red5-1.0~svn4374.orig/0000755000175000017500000000000011760512600014311 5ustar drazzibdrazzibred5-1.0~svn4374.orig/red5-debug.sh0000644000175000017500000000033411175435213016574 0ustar drazzibdrazzib#!/bin/bash if [ -z "$RED5_HOME" ]; then export RED5_HOME=.; fi # Debug options export JAVA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n $JAVA_OPTS" # Start Red5 exec $RED5_HOME/red5.sh red5-1.0~svn4374.orig/Makefile0000644000175000017500000000063111250751767015766 0ustar drazzibdrazzib PREFIX=/usr DESTINATION=$(PREFIX)/lib/red5 all: red5 .PHONY: all install clean red5: ant dist install: mkdir -p $(DESTINATION) install dist/boot.jar $(DESTINATION) install dist/red5.jar $(DESTINATION) install -m 755 dist/red5.sh $(DESTINATION) cp -r dist/conf $(DESTINATION) cp -r dist/lib $(DESTINATION) cp -r dist/webapps $(DESTINATION) installerdist: ant dist-installer clean: rm -rf dist red5-1.0~svn4374.orig/build.xml0000644000175000017500000013140511756524411016146 0ustar drazzibdrazzib ${documentation.title}]]> Copyright © ${red5.age} ${red5.name}]]> Making dist for testing Libraries checked: ${library.installed} Verifying Keystore ${keystore.storepass} Export Server Certificate Import Server Certificate into TrustStore Verifying Truststore red5-1.0~svn4374.orig/ivy.xml0000644000175000017500000001142411756460764015666 0ustar drazzibdrazzib red5-1.0~svn4374.orig/lib/0000755000175000017500000000000011760512600015057 5ustar drazzibdrazzibred5-1.0~svn4374.orig/red5-shutdown.sh0000644000175000017500000000053011140217220017343 0ustar drazzibdrazzib#!/bin/bash if [ -z "$RED5_HOME" ]; then export RED5_HOME=`pwd`; fi # JMX options export JAVA_OPTS="-Djavax.net.ssl.keyStore=$RED5_HOME/conf/keystore.jmx -Djavax.net.ssl.keyStorePassword=password" # port, username, password export RED5_OPTS="9999 red5user changeme" export RED5_MAINCLASS=org.red5.server.Shutdown exec $RED5_HOME/red5.sh red5-1.0~svn4374.orig/red5-highperf.sh0000644000175000017500000000064111352676023017306 0ustar drazzibdrazzib#!/bin/bash if [ -z "$RED5_HOME" ]; then export RED5_HOME=.; fi # Previous option set export JAVA_OPTS="-Xrs -Xms512M -Xmx1024M -Xss128K -XX:NewSize=256m -XX:SurvivorRatio=16 -XX:MinHeapFreeRatio=20 -XX:+ExplicitGCInvokesConcurrent -XX:+UseConcMarkSweepGC -Djava.net.preferIPv4Stack=true -Xverify:none" # start Red5 echo "Setting Hi Performance Options" exec $RED5_HOME/red5.sh >> $RED5_HOME/log/jvm.stdout 2>&1 & red5-1.0~svn4374.orig/ivysettings.xml0000644000175000017500000000323311706601272017430 0ustar drazzibdrazzib red5-1.0~svn4374.orig/.classpath0000644000175000017500000000205511745262602016305 0ustar drazzibdrazzib red5-1.0~svn4374.orig/.project0000644000175000017500000000067211745262602015774 0ustar drazzibdrazzib red5_server org.eclipse.jdt.core.javabuilder org.eclipse.jdt.core.javanature org.apache.ivyde.eclipse.ivynature red5-1.0~svn4374.orig/license.txt0000644000175000017500000000240411706617130016500 0ustar drazzibdrazzibRED5 Open Source Flash Server - http://code.google.com/p/red5/ Copyright 2006-2012 by respective authors (see below). All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. The Red5 Project (red5@osflash.org) Luke Hubbard (luke@codegent.com) Dominick Accattato (daccattato@gmail.com) Chris Allen (mrchrisallen@gmail.com) Joachim Bauch (jojo@struktur.de) Mick Herres (mickherres@hotmail.com) John Grden (johng@acmewebworks.com) Grant Davies (grant@bluetube.com) Steven Elliott (steven.s.elliott@gmail.com) Jokul Tian (tianxuefeng@gmail.com) Steven Gong (steven.gong@gmail.com) Paul Gregoire (mondain@gmail.com) Michael Klishin (michael.s.klishin@gmail.com) Thijs Triemstra (info@collab.nl) Dan Rossi (electroteque@gmail.com) Anton Lebedevich (mabrek@gmail.com) Art Clarke (aclarke@xuggle.com) red5-1.0~svn4374.orig/build.properties0000644000175000017500000000351711756524411017544 0ustar drazzibdrazzib# # Base build properties # # General red5.name=The Red5 Project red5.email=red5@osflash.org red5.url=http://red5.org red5.age=2006-2012 red5.version=1.0.0 red5.fullname=${red5.name} - ${red5.email} # Documentation documentation.title=Red5 Server Documentation # Release red5.filename=red5 # Ivy ivy.version=ivy-2.3.0-rc1 # javac options # http://ant.apache.org/manual/CoreTasks/javac.html # # sun javac build.compiler=modern # jikes #build.compiler=jikes # generic compiler options build.verbose=false build.fork=false build.deprecation=false build.nowarn=true # optimize only works with a few compilers build.optimize=false # Change this var to build to a different Java version # Defaults to current version. Valid options are 1.6 or later. Note that 1.4 & 1.5 are not supported. java.target_version=${java.specification.version} # If your system has less than a megabyte you may need to change this value memory.maximum=768m memory.minimum=128m # jikes options build.compiler.emacs=false build.compiler.fulldepend=false build.compiler.pedantic=false # Svn url from which to checkout the source svn.url=http://red5.googlecode.com/svn/ svn.login= svn.password= # Items to exclude when building the server war server.war.excludes=**/*.jsp,org/slf4j/**,org/red5/classloading/**,org/red5/server/script/**,org/red5/server/jetty/**,org/red5/server/tomcat/**,org/red5/server/midi/**,org/red5/server/net/rtmpt/*Loader.java,org/red5/server/net/rtmps/*Loader.java,org/red5/server/net/servlet/RTMPTServlet.java,org/red5/server/net/servlet/StatisticsServlet.java,org/red5/server/net/servlet/ZAMFGatewayServlet.java,org/red5/server/ContextLoader.java,org/red5/server/DebugPooledByteBufferAllocator.java,org/red5/server/Bootstrap.java,org/red5/logging/ContextLoggingListener.java,org/red5/logging/Derby*.java,org/red5/logging/Log*.java,org/red5/logging/W3CAppender.java red5-1.0~svn4374.orig/webapps/0000755000175000017500000000000011760512577015767 5ustar drazzibdrazzibred5-1.0~svn4374.orig/webapps/root/0000755000175000017500000000000011760512575016750 5ustar drazzibdrazzibred5-1.0~svn4374.orig/webapps/root/flvdemo.html0000644000175000017500000000150710752615171021271 0ustar drazzibdrazzib FLV demos

You need the Adobe Flash Player for this demo, download it by clicking the image below.

Get Adobe Flash player

red5-1.0~svn4374.orig/webapps/root/WEB-INF/0000755000175000017500000000000011760512575017777 5ustar drazzibdrazzibred5-1.0~svn4374.orig/webapps/root/WEB-INF/web.xml0000644000175000017500000000425511122246642021273 0ustar drazzibdrazzib root gateway org.red5.server.net.servlet.AMFGatewayServlet 1 rtmpt org.red5.server.net.rtmpt.RTMPTServlet 2 gateway /gateway rtmpt /open/* rtmpt /idle/* rtmpt /send/* rtmpt /close/* rtmpt /fcs/* index.jsp index.html index.htm Forbidden /WEB-INF/* Forbidden /persistence/* Forbidden /streams/* red5-1.0~svn4374.orig/webapps/root/WEB-INF/red5-web.properties0000644000175000017500000000005511214777324023526 0ustar drazzibdrazzibwebapp.contextPath=/ webapp.virtualHosts=* red5-1.0~svn4374.orig/webapps/root/WEB-INF/red5-web.xml0000644000175000017500000000224711747114732022136 0ustar drazzibdrazzib red5-1.0~svn4374.orig/webapps/root/index.html0000644000175000017500000000635311615271423020745 0ustar drazzibdrazzib Red5 - The open source media server
Red5

This page is used to test the proper operation of the Red5 server after it has been installed. If you can read this page it means that the Red5 server installed at this site is working properly.

If you would like to watch an instructional video on Red5 and have access to YouTube, click here



If you prefer to jump right in, follow these steps:


Further information about Red5 can be found at any of these links: homepage | wiki

Be sure to subscribe the mailing list to get help or to be notified about new versions. You can also use the mailing list to ask questions about Red5.


red5-1.0~svn4374.orig/webapps/root/crossdomain.xml0000644000175000017500000000040011611573042021774 0ustar drazzibdrazzib red5-1.0~svn4374.orig/webapps/root/gc.jsp0000644000175000017500000000112211337104465020046 0ustar drazzibdrazzib<%@page %> Requesting garbage collection... <% Runtime rt = Runtime.getRuntime(); long total = rt.totalMemory(); long free = rt.freeMemory(); long diff = (total - free); out.print("
Memory - total: " + total + " free: " + free + " dif: " + diff); out.flush(); System.gc(); try { out.print("
Sleep for a couple ticks..."); Thread.sleep(2000); } catch(Exception ex) { } total = rt.totalMemory(); free = rt.freeMemory(); diff = (total - free); out.print("
Memory - total: " + total + " free: " + free + " dif: " + diff); %> red5-1.0~svn4374.orig/webapps/root/logo.png0000644000175000017500000001201011274132063020376 0ustar drazzibdrazzib‰PNG  IHDR47CìiEsBIT|dˆ¿IDAThíZypUUšÿ{ßš÷ Y^–AÂ&D¡ SØvw)ØX]*j3S ¶ã†­==]bO‹ÚX.HZ[@ÊÆAh% !’&„„M² lä-w9¿ùã¾wI¤©šš¯êÖ}¹9ç;çw¾å|ßwŽ I|ODBH)Š¢Øß¾/ß' ÿ R¾Oæ±µ:þ<:;;¿Ï¡lrü£’„išR¢»»^¯kÖ¬A{{;yähšÇ!TU…¢üc×ô;úª-èº)%œN'‹­Ëå$%%AUUx<x<ž^|4MI8NÜÕØÙwÔs@]×N§`qîÜ9œ={ªª¢¬¬ ]]]:t(LÓDBBü~?ÒÓÓoó ‡Ãp¹\W%µ+v 10¦iÂ0 ¸Ýn@uu5>Œ ªª ÇGSSΟ?ß{@!––†`Ô¨Q¸îºëpýõ×#77‰‰‰€H$bó½biñ;P$±ïß¿ŸO=õóóó à¢ÇçóÑétRA¿ßO!ÄEm2228kÖ,¾óÎ;úè£\¸p!wìØÁÒÒR¶¶¶Úü>þøcÞÿý0`€Í+99™‹-bWWIR×õË–Ô·J(¶21½^µjž~úi455ÆŒƒ‡~sæÌiš())Auu5ÚÚÚ`š&rrrPVV†ŽŽÜrË-hjj‚išp:èß¿?nºé&L˜0•••X²d 6nÜhïY?ýéO±dÉdeeA×u8Îo—Ô•HféÒ¥ôx<@EQ8wî\677“$ŸyæΜ9“=þ8×””°lÏV×ÔPÓu._±‚/ÿá4L“õ b$j#ï¾û.GŽÉÖÖV ·Ûm·Q¯h[J ǃ®®.lß¾$1pà@Ì™3~ø!âââP\\ )%TU½°ñ* $ …TRסôK€˜Q¤¥B˜€èµ‡ V°JiBd¶~“p»Ý…B6lîºë.¼ôÒKX·nf̘eË–aÛ¶m¨ªªÂÔ©Saš¦®ôÚX¥”ŒD"”Rò³Ï>ãСC €?ûÙÏH’sæÌáÊ•+{‰Zš–Û5~ûÔÝI4âR©÷M§?Üñ”5Ç,•4M^Nx)¥¤üÊ\Ž=ÊýèG,//çŽ;˜˜˜H\¼x1MÓ¤®ë½ìÈV¹Øê!P[[‹cÇŽAUU¢µµÁ`×_½Ý&jVßž+/ (*ÑÀÓ­@T‚¥´Õ1Öƒ`˜€a@aór:ÐuC‡ÅèÑ£±iÓ&L:×^{- ¼¼gΜÃá€iš«I8DMM 33'Nć~ˆþýûcøðáö`B S)!bUJ§"¹ Õ5@]=ØÔ F+@Âç  T‡^Ä"5Ã0àr¹——‡Í›7ƒ$rssQVV†Ã‡£­­ @ · ÅVÜ4M!ÐÑѺº:@jj*Œµk×bàÀ¶n»Ýn˜¦ J A‚ªŒ$@‚+_||÷Ïàù³Q«‰Ùá‚: âÎ; þù %ÙžGLkLÓDFF‚Á Î;‡#FêêêìØ0 8!àèÙ9æaΜ9cKÈáp@×u 8Š¢Àápر·Ó„"¤a@q»æ/aÎ[lû ôI²$JZoE¤„hh„ü÷_C©ªºv5”+¦dgg£_¿~¨­­Å!C‡`0ˆP(UUár¹ìE°%‡‡ízøý~´··£½½º®£³³]]]–»ŽÙð¶·Ã--·,HKRÝÝ^/D`0 –ªjºe7 ªBħÿ‚Ⱥ?£ëÖ€®CD“:0M.— Ÿþ9âããáóù ÑÔÔ„sçÎA×u¤¤¤X tèÐ!lÚ´ Á`ÐÎ@:„¥K—b×®]8sæ êêêÐÚÚjç% !TS÷DaŸ¾Ð  ÐÖv4ð€ ¬2`Bíx<€”RB„ÃPââPÿìoñæá (’½ÐÎ;qêÔ)øý~;Ã-))ÁñãÇaž|òIøýþ *0eÊttt`Ïž=hnnFÿþý1nÜ8>|#GŽÄ˜1cÐÝÝm9…¨#Q <Ù³íTLQK#ó!n¿ "¹Ÿ%!)3­~¨­ƒpXŽ€ª h$žmÇä±c¡¸ÝB€”P>|8âãã±qãF„B!Lœ8'ND$±«N6 ììldgg£»»›6mByy9RRRPTT„ýû÷cüøñ˜>}:.I‰)0 „" K|>ˆºg{-FC²!Ÿ|ì<áP¦Hp¹P|ã rÑ»wïÆ­·Þ MÓìo3fÌÀ¤I“zµ³UNÓ4H)ÑÕÕ¯× 8qât]‡¦i8~ü8&OžŒp8 ¯×kM.jCêøàÃ¥Á†Ã°L $àP!nž‘’ yæ·Ð @(ÐÃaûþå‡ÓAºaÀåtâØ±c¨­­…×ëÅþýûÑÞÞEQ‰D‰D iü~o/Û[RSS‘••hkkCWWZZZàñx.] G¬xì+$\NÐãAÏ € ÝnСB€ £û™P¯ÛDkrBÓàv¹ì 4''o¿ý6 ==©©©p»ÝPUÕör½f‰D ( rrrX¾þÀÈÏÏlj'P__EQ GIÄ64Âïƒðû€oº\¶]õª û»Œþ ;v‰ÖÈàØ±cHLL„ÓéDEE`ذaðù|-¢íôcIbÈ!HJJÂÙ³gñé§ŸâÙgŸE0DUU233¡ë:Q#äé3÷Íu€°Ü­HOƒxüa`èPPÕ ;zwˆN–´TW€¢€ñ iJxÜntttààÁƒ¸ñÆñÅ_àÈ‘#€¼¼<¤§§CJÙKcz…>1Ñeggcܸqزe JKK¡( Fމ¿þõ¯(,,„ÇãMPË­~ºìê´¢X±¥‘’ñâó¶ªÙ*÷Ñv ¡ÉÚ§LˆºfEU­>Q›öÆyQQQºº:,Y²+W®Dmm-`„ p»ÝˆD"ö¡ÀERUš¦!##“'OÆ–-[°gϬ[·O<ñŠŠŠpðàAŒ;áP¯Lê1jpøˆ%)-›rÅ[`õ1ˆü M ¡ È£ÇÀOvC„# jE PTk1ÒR!dÁÔt¸<.„B!¬]»7Þx#ü~?6mÚ)%rss1räH{ŸêU§ûj«ôìÚµ‹ƒ ²ËHRJ>÷Üsœ={6;;;iš&µˆU0æ?JÍ•DÝ æI¦îI¶R‰hÚmøÔ}ëíN²ž¸TêÞêÞþ5o ç“$ƒ±‚Éúõ?~<#‘—/_NUU €‹-¢aÔ4ÍJ9z¤¥à±\Ä4M.X°ÀN{_|ñEš¦É›o¾™/¼ðIR‹Dh˜&YQiMÞ›bMÚŸF# Àè“fM>.•F\ªžÛ ýiÔÜI4ú¤SîÿŒÁh®UUUűcDz´´”õõõ¼á†€YYY,++#ÙûÐà’€bK®öïßÏ!C†ôbÔÝÝÍáÇóÝwß%IêšfÕÊ–¼B=.@ÝLÍ‘hŒK¥¸î P÷GßÞždjŽ®$ê}3¨ÿz1CQí8uê ø»ßýޤUeBPÁgŸ}¶—&}c‘¤gƒXVºtéR*ŠB! ØÐÐÀ£Grذa\½zõUhÔÖo¤QðCê‰Y–Úy“iz,º'™†'…º?@£ß×P¿©ˆ‘õ©GÇýâ‹/8iÒ$>õÔS$É—^zÉ.£°®®î’™ê7J(¦z±Òë=÷Üc3½ýöÛùå—_²¾¾žcÇŽå3ÏIòµ×^£Ó餪ªôx<\³f¥ _£jß (F1ÑÖÔÔØeYÌÏÏçÎ;I’o½õo¾ùf>¼ðaþeóf?~œ¡înJÍZÿõïü‰¯/}åSÓä—ÍÍ,//端½Æ[‹‹yï½÷2 ±³³“‹-¢Ãá ¢(ôù|öÁÀåœ>|ãù£~>–â666âÁÄ|ÀJ9.\ˆ_üâèÛ·/–-[†]»vA’ÈÉÉAj €áÆaó «³wÍš…––477£®¶§OŸFVf&æÎ‹k¯½»wïÆóÏ?Í›7’““±dÉÜsÏ=v06§¯£Ë>ð2Mªª¢­­ ?þ8JJJ‡Ó¦MÃ}÷݇ââbÄÇÇ£¶¶¥¥¥8qâ4MáC‡‡1nÜ8D Àu×]‡üà€ ¤¤ï½÷ž}6jÔ(<ÿüó(..¾l0—ÜX/E1÷<ÆX±bóòòzKNš4‰=ö·lÙ††[EÞ{ï=¾ñÆ6¿îîn–——sùòå¼ûî»™••eóèÓ§ï¼óNÖÔÔä7:€+V¹KI °.K¸\.TWWãÍ7ßÄG}„êêj»­×ëÅ!C0xð`:t‘H£GF[[NŸ>S§N¡¡¡ÁîãóùPPP€9sæà®»î²ã9—ËuEGûWtO¡'ãžµí}ûöaëÖ­Ø·o***ÐØØxYüœN'rss1fÌL›6 3fÌ@RRt]‡¢(P£ú•ÜS¸ªÛX†aÀ4Mû’DSSª««qòäIœÏ ®ƒ-Vs.€OŸBv˜AO§sUvEÈ€wÐÓU1ÍŒ\ät !d/3l6HlŒò£=¯ÞG”/>iÒ€ øBC)°HiÝ ;\A ÓÊ[éú9é[¼N„²C”HoÍ£ëUw:Ð×ïå JÞéÚBä‹ !Ä:&‘ ¿1Ó½#§ ÝÏT¶p”‘‚Š!Äq"¤Ø_µ&‹S”XÝ€bE±€T¤‚4Ÿ0]hë¡la¨b¢eEÉLR‘ 7>M¦àò†xÀ: |¨ÐGtÃìcº7«}«<¤»ÿIÓýêZBHb²4R÷hfÕò ˆé É-8‘ÚGZ¼ò·5[‡BÄØx“î^ërè@[¶­ŒØû,"µM0¦kûÖ¢úBEJ†Mëéºñ·ˆ’§Øë5q!(RñزžfÐÖI^a©–-ÁÎózdæ¨ì BÈ:Э¦™q<àÀ-€1€/Ù«ôºÐ3£GÑCô‹ƒ cŸ|X¥>€á*¥e =¡îoÙªE9ThIEcý7Aö@>tdÜú^Ùp·Ýc ñÙï_Ùç#¼Ý„(R»Œíz|D:qê Ü™ÑgXq¤ÛÔG¶çé‹åzR„”Ï ÚÝ’‡³öÐéÝWóÕ¾ŸìÓÁÚeçV (t·þ¶OW)Lx¡Dñ 'Ç™®>“,ˆxíÞLë&B» !„–ÔŠ,áåÐn³$ÖÇû¯ýýª>IÜqÁ¾£õè"Þz –èHâŽë Û4QüK@‘tƒšÖ½v¹k¯ Ýp›ú•fг´¼mÒˆÔ6q㣂Ï¥\ ýµd8BÈÐt‘Ê"PÒÆzŸ8}„½e.lˆÔ6Áø¨ízß'<Î$¢ !$–¦‹Tz€Ìõ¸·Å)˜%<­Åd"‘ è"z®ÂÀÕ)a±¿$ÝØ: BHýh²H¥y»ŸAfõŒ`nÐóšï{ÈÆ;Q¨!±4M¤¢„d_z@üùEYO3?ƒBY"h!Þ~–$}IïpØÏ!$#M©’ TœÐ °Ù÷T”k/Š2E*`[tfˆ·$ó¸/„¡)"Շ݆°ƒh7W™gD Ø ŽÌË—F¨Šr£BJ¤ "uä¡ÏûúT¢"Ôª&]‘ ˜ ™õ“t†Š;P¨9x]¤Ò„<ö”·=;úCLþ"©šH›î?ɲaa“¤I.µ&„T†C©¤^œ@m÷?U©o¤Š"ìºòâDÝæ=#„ÔœC©íÆ1.í xب{TK €êа{ýâ„%j*&SÊíeKuR>3æR]è¥,΄ù§0¯ÛÁæ ½sèsN²|ÅþñëþR©K(u¶ôý3•mõ_À§å³ÿ­ZÞÿ¨¶—µ<)íu­ž¿J–'¹€¾ŽÁ=¼$Çö5cào¼b¸|9¿ñ•zU €TÏØ\q ³ëï ÀÛeaÙíG‘"„ئ ÝXIx„nM¢ó›å Ùª»?w^NÎgJ©ë¤û(¿aW¨LâòÉVJžÆæHEŠb›÷»ù†0‹Îë·ø@Ì ¼œ¹PÊI³ï³-T.ÌBõú¾J¸„Å?ÒôIuQ¤¯µ\¶;¢;°Ð¹ZaæÈÐ]"Ul“"mÐëÀäî¡)€? ÿ`Ó»FÊÀç“óuÈ¿Û,üݦ]B?‡S˜ûûþ}o{‚rÇÐýŒ_²V0ioávdÈ!s àŸ[Ûîpø"å ^B5A2WÄ¡â Ñ}÷5bôo)êYÛngÞC7‰ñϺ‹ÖO^š}ëD{¹tÔ¿ÒÞÿ6ƒ#nüÝ÷ë ‹8¦0ÈIâîk’@M±+P¶@úü\Ôgš Tµx¹—eóËÐëvæ) ­Wã´û6ˆ 8âqõ÷[˜ÝuŸ!ïoÂB…T¤š$PQ¡°7hNcX¡¢@U‹ä×f«ïë—A;€J½Ãø í= x³Àü}o$Hû±ŒHDªƒdãêÌ»?Š6o^¸„…‡+G(PÕã-dmÄ#Ì¿§þÖÿöEýŲ8>J:MtpÄ4ô÷4:ùïÏŽcHMœH%q\g<ìöÇôa9œ²F Q͉#)PÕdœ _”ð/Ãá|©"ùþC+ó,Mäë>§`pnŸ ½NÆY*´O¤š$PQc5. ¿ ‡ÊÕ* T5@Ö5Çn_oÀu¨Œ9lÌZà7& Ù&OØ´fÇ0»ý®±îÇÚǬ)“H5I €Ý‚Áù7ÁÅÇå UzPç°äzhÆÂ|&7ßöàßa†º¬á¸¨´|Âæý0¹þ¿ìùß6ãØ¢Dªi5*Ž!ʪà~°¡š\AfE¹0KL·¾gsó¼ÇÚJr`ž6)œoC¤ ÆÚ©¦ Ô5v'Vœ¢9矄!Šª¦=ud(Ì75lïc=Çß¾  R,Oؼ·ã=ù¤Ý"ÃØl‹Ô-šÓ L=Šoìf†(n TõéBö{ñ`^búþõH~èüý´µlúí…å¥z ‹ÔÙ×´© Qc¡`Ÿ‡„1ò_…“U¤/tcÃö°åÁòÄ ãÐw“È|, º‡ ƒ{“.\çt‡]ßè õª[ :Ð÷¨ìó«[꧹ؑܧ‡=ûÏBù¬?O/§o|kéä|f»~5BrŸ. {No’¼…f…õzØ uj\­*SØoXhAÕ‡.d÷iºggõ݃ÙHÊgløæ3dsú%îNi¡95ª Fòeah¹¼`6fR}’ÌtÅX‡TƒOØì›2YíSAY=$tù5i=)»¡æ· @’‰HÍNÞÙÚŸžŒê3 }7õMM Û·IdM¥YOj›Gȧn/‹)v,.ì¼µ»Ê( §ì ä€ùä—U!X˧.t {v¦†íáyþ¦`D_=<ƒ¾ìÞ· =N„Þ"AŒ ‘šøÕB9Eži9+u;÷0~ÙÈ)ê%6C½^¤o¦ñ3áý§ÙªB dе5DôW‘º„îj-ˆØ$w_ö{’ÉïgŽèF(ìêóP…‰ŒièûÐG:°WÜ7U¤H5aƒUA×°=ü–Ýô œëF8‚ïÑÓ=AÖýãHJ‘"„$¡Ù[°I€AR]ÜÐw“[Or_é)R„$HÝ4¦·é a{-ç:2 }w y$–”ØÝg#p‚ÒAž9¢#ö.°Žê;x+ÊõæíåÙ²Õr¤û´–KW{ñÔGQ`AÁ|†~Á8ƒùYp…eõ!xQ¡HB’Ðäq ÛÃoÏU¶’?wÇGo}…Kõ ½€¤ÎªE+Èÿ^Nß¾ïúÀüèEMÕóת,aâB[Ä=DGéýRqÖR‘¢»’„ž I€œÐw7kEªÀËé/W/'o>.N_=¢¥¦J©k(‹++å(¥®¯0×óžO^N¹²V~:ÜÐw“I^Bz’ƒQ¤!Ipy<ÃöpƒV« /§¿\=Ÿžßí[¨"—÷QC }û|z~W¢X…È$Rž Gr0Š!DJW˜Ïä 47{Uâñá[w)úø¹óròæ#оUP¥·ÔÇnß¾œœÏüã3é}±Eøþ:†<® œžä`)Bˆ”ž i)ñpCZH”òEËš‹ñ_÷'¯æÅZN1(å,Z¯æ%XUÁ=ìþ/¹ö¦}7 HB¤Hæ4 P/ôÝË\ª“!QY‹V˵Úßd u´o_ŽÏóZã- oõÙ3ü_êμEŠT ¯ì #÷–'Ø·˜È>« U§Mü®}üÛè["|MîFOPNì3E‘"UÃ+»$ža{Ø ³ê†#uùrr4.èpá{Ø3äñlˆ"E‘Ò³TN­#ûªŒRêÚ?~mZ”Ð&¶¬á^\Š!DJOÇ3lw¬Õ‚ìe¡Ô¸àC:†íž`ß^\Š!Ä&^Æÿ“¬(åíçYÊ EŠR$^Ùh~Ë´Ä»- ›W"E!‡†RN ƒ|s"E€ü=É”ãÆìëÄÃfj4ï^þí¡˜ë;6ü,¨¦iß }ä,èÙ•]B,0„l°.© WíÿÂÿ¾|/»YyK‘Êθì b·ˆ·”†ˆÆš"ºß)Ø×ÃæÂyy2.è8•¤ßþ È÷e»ˆž«ÏAü3eÚ7À£HB=ihÜÚ>d"UN°¯à÷õʸ ãTÿøµ«~ü•× ÈãÕ§ ó=ubÊØ·/.zHª‡ Ž©!•Æ„¹n[¾?ÇÅ\á!j%âÝ=_÷—­–³ôý3¥0ÔóîåÇR©K¬2)BˆMâ]§ˆJä†Û¶ÿ|vi÷•UˆÆ?'çï|…q^bµ´7KÈ6’Y-¬œ£û!R\Až,+µV›¥?<úþõïi*Šö÷?ÿ‰%rÓ¤d“gÅto%Çvã2P¤!Ež´¨™º-âO~üù!’u¹~N“îª^>å7a0Ý}„›H\<…ô“}ûªò>†-|S¥r°¨ò[bDb%ÑÝG)OGâîãx¬-”Zºe×!!á{˜ÅÝçÅe HB¤xö »„Šè'©íå"·>;ÿÕ›‹Š ßCQd£Øþ=Š!DФïÁ1l7½Ì590lcìÐ^æa¹öVŸ®áÿ’è?Q_EŠ"EºXaÔĦOX7J´¤êMk‘2 Mϰ=ŒÈz¤HB’à òô ÛƒF‰"…ï»eWAHøþ™„¦'(Ç“Œ"Eª†WvÈ^ÎêsŽèȾ.,Šófg\vJÄ+»¤p¤–T»áÅ_ Ÿ™ôÒ ¤~\…¾›žGPÎ#„KÐS¤²SÔ²„Ti„ß%¢!zm)@7xd¯)'ôýÖGâÊ £»’WÇd)Ý ò›,Z6çÖ ß3WÇ„iß(R„¤¸‚<Ž`_ŠT_å3]”zþ*µ~ã¸Àº¯éÑýQá<ûp¥¥»’W§Ý`m7OÐ Ü[èù߬»ü^Nßø6Ëø¾{ôýÏ_­—BAU=â1<®ÉÕçËO0LKŠ’”OMi34lŸ†¾×ÚRÊɳxÿø,j–Žª¾W&‘ Ê1í EŠ’WÇ$@.Ö"7DMÖ—z9ýå*>W:­v>V”½Y,XÏ|nrõuai¡Ã0)BH$oÃ=h—ß6Ë/Àî:JyM/ä·‡¹” hUÝ¢†¾O y¤ç@KŠÔšÜÃ#V64CÃö÷¡ïרƒ5¥ð6e/|üÜANnO?A¨÷úX÷5y0÷!eÍ!@‘"„¤aÛ21D´}ÆÚís›´Êoùâ•ïÚªÅÉ«) r‰ìkÙp?6|Ó‡ÌÕ7MzpŠ!$-‘Ú'@cÃ÷L((ÏVY¥Ÿ-^ùîâäü]Ö’^N¹z99ŸAå<Òòý¬–Ô¶õÁo(,/‘« HBÒ#mpƆퟰ¶¦z27üà#¿Un5êÌWêýËÉ›ûç“óÿøµhFwÿø¬ë¿î/Nߌ^NÎg@û6ï¨AüÈ|-ƆïaºÈÉÕpœ!$=OÐî›aL¾ttXÔ[øk¡¯Ê˲9ÚËÅ|Ñjg)B†BOA]/”º~9}›}±±¯Ê­Z>ü¹ÂC–k9€ÌŠ Ë{ŸeZR„,L…ùƆퟰ¶ÈÎöä£~<~ÏÉU¶ ‰ìZQHáê(R„l|‚|µ^“[ìzë{öÀU›Unsd™JVŒ±žÞÈ…¾¨TVEŠ’•±0ßÔ°ýËV¦| ÈÔ@þãÑ·¥nªÝ‡(ºß{i¾(R„¬|€Üšþ÷>TÆ%€›,Ò ´osöﺑV¤;Ø|Ixóò,ca™S¤˜ HBl0æ{èqSOØtevûù¾ ‹¬ž´—þ4å®ï±vóyþaÈׇÜÕ7NY)RM¼²+@ó²IgÏ`Žòú„Í·ø[d˜‰âÈNMV{|ßU?þJ3s˛³oüÖTXæ-2XQEŠT¯ì THEa³•tuTZú§ÔÇ/@j‹¢¶´}œb· ìNUeró½ƒlÍ( eØyŠ!Ä¿Cþ‚aê3 Ü~Uöú§Úß^®Õ7•Ίê@ßð,çÿ4äíB.OS_É^^NÏ'€Æf¬#KxôãOÓ€[Û×ö-ÌÏPòÅ çþ–°.Fèî#e%PP êÎÈû-ΰ¿ñ RyS…¦}ûó7uhÖ”ï»íåÒÉ(P€¾Î&ê"™›Ïê"–M©æt¤V—(A>ö‚T›÷Ï·oðîôsª9RöQµ¿}ý½½\:õúó•ï_}ÿóׄhOÅ0´mó´GÀfPESX¶è›êî ¢Yœ’ëÑT<è†),PX™§‘û¯qÒßå–îÁ6) Êü‰úa$u‘5u(@¿Å{÷kHÑ6­´9´…nÕ¢ôϺ‹VûR¡}éû¸ü3@õ Ä3.˜Ë†?W>}`ÞRêÑÇbÞ~n{êùkªèE}lö)å!P.rÖ?cšåY¹ ûµ`ŠNØÈºXm/»nuLwÈ0§]Iô‘ý™ÙfbŸ¼ ê2*¹@ºë³½ä>åþ,fýÁÌò®`°á´Ÿ(PvÓõe€äç;ˆ)3êYz‡òD<¨Ã¨¤ã:düÉŸ› ’Ý›Â^ ²þhfET²@Ø€ÚK(»i‚ú3AòóÄ”Ù(÷åXUÁñG%Ð'Q¢G÷ÅY8³¢*Z ]쾉0%KQŒÑ(»nuL‘üü‚rG[û<¬¶iUÇxL@·YÛ×õæhÉ0$¿á³FÖϬÈÊÔl‰e/ pX¤}$×á"¢ì{ÈkÇt¼´`l[OÈÄy‚ä÷abõ dýÍŠ®ptî­¯éi»1¡@Ù»–‡BÚgâ²Æw„݆{†ü'Ž5Êù8€~6î±yŽ÷cúz$½þ«g $ëhV|• g‚ò«º¤AÄõ£@Ù»–‡D»¬$Ý­ö•”õ’9C~×68Æ(§òËiûº%qmFY›’4³x‰ÈúC*­â3BùVÕSÔRzÕ-U!”º(Òz+’\£>¢å{èßu×Ω¡²GËô¹NtôòsDì/I¶ÏGŒ²ppæÏªWà Ý&æþØÚv=À’$ã)—£¨1¤›ùåzà©dPóÕ*¿ñ¿ÛU9®°,þêsŒì30t¡ëzèvg =‘¯äYé¬òSÔcˆæ´ñ„b$­Õ-uÿta¶J -“´c­²ZÝÕ¾³ˆº…­¿$u3Y’’4Hy„r¤ª$‹î@7ÂûðûUÞA7öqâD¤ºÐÖÝñ.ÏH¡xSnåJ•]BÙ"­ëÐnç!’»K/ ]kCÄ»ôWÇ >ÃŒWŸ.vs<[•|Æq»J.’ÏIxíÞë%Ü/`ºø!ÄHÙf&ùˆôƒx;Ðü ŠLA[Uý”õ´Øf6Ó¤ BÉÄÒ…¨‡\鸪8úÐ˜ÌRÖé~µïdUÖìˆBÙ\{Hv-Ô…BCÚA§y‰UÁ1G ˆž·0Mº)¨¾„rŒ`Ç¥6A¾î¬¢Dª{³á r®+!„4‚¬î¿pºƒnœm»·ò©.¢g› {B*BÙû^¢k[‚e[¤.VeÙàÈÛÒ#„FÓ‡=‹"œî±h(k0ïZˆó8¿½G!…`Z¦ÂfºÃ:¯ø>‰Hõ±9˜7Q ‹ï@P§ÊÁÁ¼„ºÓ…žßîºÀcF äÖóz«…cØžÐsü‘mNBB!éƒë¿…Ó Œ „Ê‘uÖ…º§Pœ!¤òtažíüÐR°è!ʼnBj†i5ÛCH3Ô4 ‚BÈ.]?q¬ít‡ôë]B© y ”ÍÓbêær%* CÐ !D[%ô:OŠ ßæz ©ùêóS‰u)Š!„Ds-Z=l.Vxf©|o+ÍW)é‡ EŠB’sh±rWŸÓUŠÂ…ˆBH }H£²+r(´Ê®!„b‚"E!¤²P¤!„TŠ!„ÊB‘"„RY(R„B* EŠBHe¡HB!„Ò‚Å/ʮȡðÿý Ä)¡"IEND®B`‚red5-1.0~svn4374.orig/webapps/root/favicon.png0000644000175000017500000000133511274132063021073 0ustar drazzibdrazzib‰PNG  IHDR[Í»“ pHYs  šœIDATxœm’_HSqÇÏïîÞ…‹‘é–[rï]ÚX%Ñ6lB1Y0¬^–^u½DaГÑHbîÁ@Fô–>H"¤Œ…Y)óaÃ?!êîætÓ‹àîïþN“¥Öy8p8ßçá|"Â?¥i‚ðïŠ?> "¥4—Ë-,,hšæõzEQ4„j†T/0Æ’Éäðð°Á`ày9Ž+•J¡Pˆã¸"ŽŽŽÆãñîînQµr™1vÖlÎnmMNN¶´´ ò< âÔÔT$éëë»w³íÂüß;;Ȱ¾¾NuÈŸJ¿&&&ÚÛÛûûû9ŽDTU5 F£ÑÂö6}ú\«±Rë%ÚÐDšè‹!u?‹\.‡ˆ<".--‰¢(˲Åj…½=4 ÜÇ÷`2ÀÃE{Éär¹Z[[ggg{{{9DL§Ó¢(666RJ"P=yÆî?Ðï†ØË×´\v86›-•JéºÎ«ªšN§+½X,º Äv­™ø¼ àÈ;úvä«Ï³FP%ŸÏ Þl6ûýþD"!˲Ïçãn¸R8_KÁ/ó†¹o·¯\]¶X·h·Ûív;Gq»Ý+++›››€ÈÂõëm8ôŠÅ?àÏu0 P{nyy9“Éøý~B¢(J’´ººúyfæNÏCH$1òÀ`€G=ß××766<!äèqÅb±«««³³S–¤[N][Ó5j¾Ü<—W¶%‹9οìîî†Ãa‹ÅâñxxA`Œ8.“ɤR©h4ZIŸp §§§ÇÇdzÙ,cÌf³utt„B!“ÉTõœÒ»bŠ¢(º®K’D9®ê€*§¢•ú“nQ6£«@IEND®B`‚red5-1.0~svn4374.orig/webapps/root/favicon.ico0000644000175000017500000000157610451604133021066 0ustar drazzibdrazzibh( GGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýùùùììììììúúúþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûæææ¿¿¿‰‰‰iiiqqq›››ÒÒÒñññýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿööö¿¿¿___UUUtttyyyyyylllNNN{{{ÓÓÓûûûÿÿÿÿÿÿÿÿÿøøø¬¬¬JJJ‰‰ŠÇÆÒÊÈ굲ݻ¸áÌÊ鹸Âhhi]]]ÎÎÎüüüÿÿÿýýýÌÌÌGGG–––ÐÏ᜗ö[Rþ@6ûD;ûd\þ©¥ðÉÈÓjjjjjjéééÿÿÿ÷÷÷qqqnnnÚÚÚÏÌÿLBý;1ü\TþTLþ(üVMýÑÎøÄÄÄIII¸¸¸üüüíííFFF®®®ôôôäãÿ¡œþ´°þçæþÉÇþNEý4*ýÈÆÿäääyyy{{{÷÷÷ÃÃÃ@@@´´´ãããÑÐ袞ùœ—þ­¨þ”Žý=3ü4*÷µ²è××׈ˆˆYYYÜÜÜ»»»???²²²àà൲æ;1÷*ü?5ý1'ü* ýmf÷ÉÈæÒÒÒ‡‡‡UUUÙÙÙæææDDD³³³óóóÊÇý<1üKBý—‘þ–‘þ¤ þÖÔþøøýâââqqqõõõöööccc|||ßßßÍÊÿ?5ý1&ü_Wþd]þf^ý¿»þôôùËËËPPP¬¬¬ûûûüüü¾¾¾CCC¨¨¨ÓÑé“üWOýJBöNE÷WNþ¯«öÙØÞ}}}[[[âââþþþÿÿÿôôô———GGGŸŸ¢ÏÏáÓÒôÃÁæÉÇëÕÓöÇÇÕ€OOOÃÃÃûûûÿÿÿÿÿÿþþþîî¤OOOdddŠŠŠ‚‚‚UUUaaaÄÄÄùùùÿÿÿÿÿÿÿÿÿÿÿÿþþþøøøÙÙÙŸŸŸnnnWWW\\\|||¶¶¶åååûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþúúúöööççççççøøøüüüþþþÿÿÿÿÿÿÿÿÿÿÿÿred5-1.0~svn4374.orig/webapps/installer/0000755000175000017500000000000011760512600017747 5ustar drazzibdrazzibred5-1.0~svn4374.orig/webapps/vod/0000755000175000017500000000000011760512577016557 5ustar drazzibdrazzibred5-1.0~svn4374.orig/webapps/vod/streams/0000755000175000017500000000000011760512577020235 5ustar drazzibdrazzibred5-1.0~svn4374.orig/webapps/vod/swfobject.js0000644000175000017500000006174611377357437021127 0ustar drazzibdrazzib/*! SWFObject v2.2 is released under the MIT License */ var swfobject = function() { var UNDEF = "undefined", OBJECT = "object", SHOCKWAVE_FLASH = "Shockwave Flash", SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash", FLASH_MIME_TYPE = "application/x-shockwave-flash", EXPRESS_INSTALL_ID = "SWFObjectExprInst", ON_READY_STATE_CHANGE = "onreadystatechange", win = window, doc = document, nav = navigator, plugin = false, domLoadFnArr = [main], regObjArr = [], objIdArr = [], listenersArr = [], storedAltContent, storedAltContentId, storedCallbackFn, storedCallbackObj, isDomLoaded = false, isExpressInstallActive = false, dynamicStylesheet, dynamicStylesheetMedia, autoHideShow = true, /* Centralized function for browser feature detection - User agent string detection is only used when no good alternative is possible - Is executed directly for optimal performance */ ua = function() { var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF, u = nav.userAgent.toLowerCase(), p = nav.platform.toLowerCase(), windows = p ? /win/.test(p) : /win/.test(u), mac = p ? /mac/.test(p) : /mac/.test(u), webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit ie = !+"\v1", // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html playerVersion = [0,0,0], d = null; if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) { d = nav.plugins[SHOCKWAVE_FLASH].description; if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+ plugin = true; ie = false; // cascaded feature detection for Internet Explorer d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1"); playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10); playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10); playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0; } } else if (typeof win.ActiveXObject != UNDEF) { try { var a = new ActiveXObject(SHOCKWAVE_FLASH_AX); if (a) { // a will return null when ActiveX is disabled d = a.GetVariable("$version"); if (d) { ie = true; // cascaded feature detection for Internet Explorer d = d.split(" ")[1].split(","); playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; } } } catch(e) {} } return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac }; }(), /* Cross-browser onDomLoad - Will fire an event as soon as the DOM of a web page is loaded - Internet Explorer workaround based on Diego Perini's solution: http://javascript.nwbox.com/IEContentLoaded/ - Regular onload serves as fallback */ onDomLoad = function() { if (!ua.w3) { return; } if ((typeof doc.readyState != UNDEF && doc.readyState == "complete") || (typeof doc.readyState == UNDEF && (doc.getElementsByTagName("body")[0] || doc.body))) { // function is fired after onload, e.g. when script is inserted dynamically callDomLoadFunctions(); } if (!isDomLoaded) { if (typeof doc.addEventListener != UNDEF) { doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false); } if (ua.ie && ua.win) { doc.attachEvent(ON_READY_STATE_CHANGE, function() { if (doc.readyState == "complete") { doc.detachEvent(ON_READY_STATE_CHANGE, arguments.callee); callDomLoadFunctions(); } }); if (win == top) { // if not inside an iframe (function(){ if (isDomLoaded) { return; } try { doc.documentElement.doScroll("left"); } catch(e) { setTimeout(arguments.callee, 0); return; } callDomLoadFunctions(); })(); } } if (ua.wk) { (function(){ if (isDomLoaded) { return; } if (!/loaded|complete/.test(doc.readyState)) { setTimeout(arguments.callee, 0); return; } callDomLoadFunctions(); })(); } addLoadEvent(callDomLoadFunctions); } }(); function callDomLoadFunctions() { if (isDomLoaded) { return; } try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early var t = doc.getElementsByTagName("body")[0].appendChild(createElement("span")); t.parentNode.removeChild(t); } catch (e) { return; } isDomLoaded = true; var dl = domLoadFnArr.length; for (var i = 0; i < dl; i++) { domLoadFnArr[i](); } } function addDomLoadEvent(fn) { if (isDomLoaded) { fn(); } else { domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+ } } /* Cross-browser onload - Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/ - Will fire an event as soon as a web page including all of its assets are loaded */ function addLoadEvent(fn) { if (typeof win.addEventListener != UNDEF) { win.addEventListener("load", fn, false); } else if (typeof doc.addEventListener != UNDEF) { doc.addEventListener("load", fn, false); } else if (typeof win.attachEvent != UNDEF) { addListener(win, "onload", fn); } else if (typeof win.onload == "function") { var fnOld = win.onload; win.onload = function() { fnOld(); fn(); }; } else { win.onload = fn; } } /* Main function - Will preferably execute onDomLoad, otherwise onload (as a fallback) */ function main() { if (plugin) { testPlayerVersion(); } else { matchVersions(); } } /* Detect the Flash Player version for non-Internet Explorer browsers - Detecting the plug-in version via the object element is more precise than using the plugins collection item's description: a. Both release and build numbers can be detected b. Avoid wrong descriptions by corrupt installers provided by Adobe c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports - Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available */ function testPlayerVersion() { var b = doc.getElementsByTagName("body")[0]; var o = createElement(OBJECT); o.setAttribute("type", FLASH_MIME_TYPE); var t = b.appendChild(o); if (t) { var counter = 0; (function(){ if (typeof t.GetVariable != UNDEF) { var d = t.GetVariable("$version"); if (d) { d = d.split(" ")[1].split(","); ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; } } else if (counter < 10) { counter++; setTimeout(arguments.callee, 10); return; } b.removeChild(o); t = null; matchVersions(); })(); } else { matchVersions(); } } /* Perform Flash Player and SWF version matching; static publishing only */ function matchVersions() { var rl = regObjArr.length; if (rl > 0) { for (var i = 0; i < rl; i++) { // for each registered object element var id = regObjArr[i].id; var cb = regObjArr[i].callbackFn; var cbObj = {success:false, id:id}; if (ua.pv[0] > 0) { var obj = getElementById(id); if (obj) { if (hasPlayerVersion(regObjArr[i].swfVersion) && !(ua.wk && ua.wk < 312)) { // Flash Player version >= published SWF version: Houston, we have a match! setVisibility(id, true); if (cb) { cbObj.success = true; cbObj.ref = getObjectById(id); cb(cbObj); } } else if (regObjArr[i].expressInstall && canExpressInstall()) { // show the Adobe Express Install dialog if set by the web page author and if supported var att = {}; att.data = regObjArr[i].expressInstall; att.width = obj.getAttribute("width") || "0"; att.height = obj.getAttribute("height") || "0"; if (obj.getAttribute("class")) { att.styleclass = obj.getAttribute("class"); } if (obj.getAttribute("align")) { att.align = obj.getAttribute("align"); } // parse HTML object param element's name-value pairs var par = {}; var p = obj.getElementsByTagName("param"); var pl = p.length; for (var j = 0; j < pl; j++) { if (p[j].getAttribute("name").toLowerCase() != "movie") { par[p[j].getAttribute("name")] = p[j].getAttribute("value"); } } showExpressInstall(att, par, id, cb); } else { // Flash Player and SWF version mismatch or an older Webkit engine that ignores the HTML object element's nested param elements: display alternative content instead of SWF displayAltContent(obj); if (cb) { cb(cbObj); } } } } else { // if no Flash Player is installed or the fp version cannot be detected we let the HTML object element do its job (either show a SWF or alternative content) setVisibility(id, true); if (cb) { var o = getObjectById(id); // test whether there is an HTML object element or not if (o && typeof o.SetVariable != UNDEF) { cbObj.success = true; cbObj.ref = o; } cb(cbObj); } } } } } function getObjectById(objectIdStr) { var r = null; var o = getElementById(objectIdStr); if (o && o.nodeName == "OBJECT") { if (typeof o.SetVariable != UNDEF) { r = o; } else { var n = o.getElementsByTagName(OBJECT)[0]; if (n) { r = n; } } } return r; } /* Requirements for Adobe Express Install - only one instance can be active at a time - fp 6.0.65 or higher - Win/Mac OS only - no Webkit engines older than version 312 */ function canExpressInstall() { return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312); } /* Show the Adobe Express Install dialog - Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75 */ function showExpressInstall(att, par, replaceElemIdStr, callbackFn) { isExpressInstallActive = true; storedCallbackFn = callbackFn || null; storedCallbackObj = {success:false, id:replaceElemIdStr}; var obj = getElementById(replaceElemIdStr); if (obj) { if (obj.nodeName == "OBJECT") { // static publishing storedAltContent = abstractAltContent(obj); storedAltContentId = null; } else { // dynamic publishing storedAltContent = obj; storedAltContentId = replaceElemIdStr; } att.id = EXPRESS_INSTALL_ID; if (typeof att.width == UNDEF || (!/%$/.test(att.width) && parseInt(att.width, 10) < 310)) { att.width = "310"; } if (typeof att.height == UNDEF || (!/%$/.test(att.height) && parseInt(att.height, 10) < 137)) { att.height = "137"; } doc.title = doc.title.slice(0, 47) + " - Flash Player Installation"; var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn", fv = "MMredirectURL=" + encodeURI(window.location).toString().replace(/&/g,"%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title; if (typeof par.flashvars != UNDEF) { par.flashvars += "&" + fv; } else { par.flashvars = fv; } // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it, // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work if (ua.ie && ua.win && obj.readyState != 4) { var newObj = createElement("div"); replaceElemIdStr += "SWFObjectNew"; newObj.setAttribute("id", replaceElemIdStr); obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf obj.style.display = "none"; (function(){ if (obj.readyState == 4) { obj.parentNode.removeChild(obj); } else { setTimeout(arguments.callee, 10); } })(); } createSWF(att, par, replaceElemIdStr); } } /* Functions to abstract and display alternative content */ function displayAltContent(obj) { if (ua.ie && ua.win && obj.readyState != 4) { // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it, // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work var el = createElement("div"); obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content el.parentNode.replaceChild(abstractAltContent(obj), el); obj.style.display = "none"; (function(){ if (obj.readyState == 4) { obj.parentNode.removeChild(obj); } else { setTimeout(arguments.callee, 10); } })(); } else { obj.parentNode.replaceChild(abstractAltContent(obj), obj); } } function abstractAltContent(obj) { var ac = createElement("div"); if (ua.win && ua.ie) { ac.innerHTML = obj.innerHTML; } else { var nestedObj = obj.getElementsByTagName(OBJECT)[0]; if (nestedObj) { var c = nestedObj.childNodes; if (c) { var cl = c.length; for (var i = 0; i < cl; i++) { if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) { ac.appendChild(c[i].cloneNode(true)); } } } } } return ac; } /* Cross-browser dynamic SWF creation */ function createSWF(attObj, parObj, id) { var r, el = getElementById(id); if (ua.wk && ua.wk < 312) { return r; } if (el) { if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content attObj.id = id; } if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML var att = ""; for (var i in attObj) { if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries if (i.toLowerCase() == "data") { parObj.movie = attObj[i]; } else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword att += ' class="' + attObj[i] + '"'; } else if (i.toLowerCase() != "classid") { att += ' ' + i + '="' + attObj[i] + '"'; } } } var par = ""; for (var j in parObj) { if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries par += ''; } } el.outerHTML = '' + par + ''; objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only) r = getElementById(attObj.id); } else { // well-behaving browsers var o = createElement(OBJECT); o.setAttribute("type", FLASH_MIME_TYPE); for (var m in attObj) { if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword o.setAttribute("class", attObj[m]); } else if (m.toLowerCase() != "classid") { // filter out IE specific attribute o.setAttribute(m, attObj[m]); } } } for (var n in parObj) { if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element createObjParam(o, n, parObj[n]); } } el.parentNode.replaceChild(o, el); r = o; } } return r; } function createObjParam(el, pName, pValue) { var p = createElement("param"); p.setAttribute("name", pName); p.setAttribute("value", pValue); el.appendChild(p); } /* Cross-browser SWF removal - Especially needed to safely and completely remove a SWF in Internet Explorer */ function removeSWF(id) { var obj = getElementById(id); if (obj && obj.nodeName == "OBJECT") { if (ua.ie && ua.win) { obj.style.display = "none"; (function(){ if (obj.readyState == 4) { removeObjectInIE(id); } else { setTimeout(arguments.callee, 10); } })(); } else { obj.parentNode.removeChild(obj); } } } function removeObjectInIE(id) { var obj = getElementById(id); if (obj) { for (var i in obj) { if (typeof obj[i] == "function") { obj[i] = null; } } obj.parentNode.removeChild(obj); } } /* Functions to optimize JavaScript compression */ function getElementById(id) { var el = null; try { el = doc.getElementById(id); } catch (e) {} return el; } function createElement(el) { return doc.createElement(el); } /* Updated attachEvent function for Internet Explorer - Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks */ function addListener(target, eventType, fn) { target.attachEvent(eventType, fn); listenersArr[listenersArr.length] = [target, eventType, fn]; } /* Flash Player and SWF content version matching */ function hasPlayerVersion(rv) { var pv = ua.pv, v = rv.split("."); v[0] = parseInt(v[0], 10); v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0" v[2] = parseInt(v[2], 10) || 0; return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false; } /* Cross-browser dynamic CSS creation - Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php */ function createCSS(sel, decl, media, newStyle) { if (ua.ie && ua.mac) { return; } var h = doc.getElementsByTagName("head")[0]; if (!h) { return; } // to also support badly authored HTML pages that lack a head element var m = (media && typeof media == "string") ? media : "screen"; if (newStyle) { dynamicStylesheet = null; dynamicStylesheetMedia = null; } if (!dynamicStylesheet || dynamicStylesheetMedia != m) { // create dynamic stylesheet + get a global reference to it var s = createElement("style"); s.setAttribute("type", "text/css"); s.setAttribute("media", m); dynamicStylesheet = h.appendChild(s); if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) { dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1]; } dynamicStylesheetMedia = m; } // add style rule if (ua.ie && ua.win) { if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) { dynamicStylesheet.addRule(sel, decl); } } else { if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) { dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}")); } } } function setVisibility(id, isVisible) { if (!autoHideShow) { return; } var v = isVisible ? "visible" : "hidden"; if (isDomLoaded && getElementById(id)) { getElementById(id).style.visibility = v; } else { createCSS("#" + id, "visibility:" + v); } } /* Filter to avoid XSS attacks */ function urlEncodeIfNecessary(s) { var regex = /[\\\"<>\.;]/; var hasBadChars = regex.exec(s) != null; return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s; } /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only) */ var cleanup = function() { if (ua.ie && ua.win) { window.attachEvent("onunload", function() { // remove listeners to avoid memory leaks var ll = listenersArr.length; for (var i = 0; i < ll; i++) { listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]); } // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect var il = objIdArr.length; for (var j = 0; j < il; j++) { removeSWF(objIdArr[j]); } // cleanup library's main closures to avoid memory leaks for (var k in ua) { ua[k] = null; } ua = null; for (var l in swfobject) { swfobject[l] = null; } swfobject = null; }); } }(); return { /* Public API - Reference: http://code.google.com/p/swfobject/wiki/documentation */ registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) { if (ua.w3 && objectIdStr && swfVersionStr) { var regObj = {}; regObj.id = objectIdStr; regObj.swfVersion = swfVersionStr; regObj.expressInstall = xiSwfUrlStr; regObj.callbackFn = callbackFn; regObjArr[regObjArr.length] = regObj; setVisibility(objectIdStr, false); } else if (callbackFn) { callbackFn({success:false, id:objectIdStr}); } }, getObjectById: function(objectIdStr) { if (ua.w3) { return getObjectById(objectIdStr); } }, embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) { var callbackObj = {success:false, id:replaceElemIdStr}; if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) { setVisibility(replaceElemIdStr, false); addDomLoadEvent(function() { widthStr += ""; // auto-convert to string heightStr += ""; var att = {}; if (attObj && typeof attObj === OBJECT) { for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs att[i] = attObj[i]; } } att.data = swfUrlStr; att.width = widthStr; att.height = heightStr; var par = {}; if (parObj && typeof parObj === OBJECT) { for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs par[j] = parObj[j]; } } if (flashvarsObj && typeof flashvarsObj === OBJECT) { for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs if (typeof par.flashvars != UNDEF) { par.flashvars += "&" + k + "=" + flashvarsObj[k]; } else { par.flashvars = k + "=" + flashvarsObj[k]; } } } if (hasPlayerVersion(swfVersionStr)) { // create SWF var obj = createSWF(att, par, replaceElemIdStr); if (att.id == replaceElemIdStr) { setVisibility(replaceElemIdStr, true); } callbackObj.success = true; callbackObj.ref = obj; } else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install att.data = xiSwfUrlStr; showExpressInstall(att, par, replaceElemIdStr, callbackFn); return; } else { // show alternative content setVisibility(replaceElemIdStr, true); } if (callbackFn) { callbackFn(callbackObj); } }); } else if (callbackFn) { callbackFn(callbackObj); } }, switchOffAutoHideShow: function() { autoHideShow = false; }, ua: ua, getFlashPlayerVersion: function() { return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] }; }, hasFlashPlayerVersion: hasPlayerVersion, createSWF: function(attObj, parObj, replaceElemIdStr) { if (ua.w3) { return createSWF(attObj, parObj, replaceElemIdStr); } else { return undefined; } }, showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) { if (ua.w3 && canExpressInstall()) { showExpressInstall(att, par, replaceElemIdStr, callbackFn); } }, removeSWF: function(objElemIdStr) { if (ua.w3) { removeSWF(objElemIdStr); } }, createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) { if (ua.w3) { createCSS(selStr, declStr, mediaStr, newStyleBoolean); } }, addDomLoadEvent: addDomLoadEvent, addLoadEvent: addLoadEvent, getQueryParamValue: function(param) { var q = doc.location.search || doc.location.hash; if (q) { if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark if (param == null) { return urlEncodeIfNecessary(q); } var pairs = q.split("&"); for (var i = 0; i < pairs.length; i++) { if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) { return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1))); } } } return ""; }, // For internal usage only expressInstallCallback: function() { if (isExpressInstallActive) { var obj = getElementById(EXPRESS_INSTALL_ID); if (obj && storedAltContent) { obj.parentNode.replaceChild(storedAltContent, obj); if (storedAltContentId) { setVisibility(storedAltContentId, true); if (ua.ie && ua.win) { storedAltContent.style.display = "block"; } } if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); } } isExpressInstallActive = false; } } }; }(); red5-1.0~svn4374.orig/webapps/vod/WEB-INF/0000755000175000017500000000000011760512576017605 5ustar drazzibdrazzibred5-1.0~svn4374.orig/webapps/vod/WEB-INF/web.xml0000644000175000017500000000274611332146107021101 0ustar drazzibdrazzib vod webAppRootKey /vod rtmpt org.red5.server.net.rtmpt.RTMPTServlet 1 rtmpt /fcs/* rtmpt /open/* rtmpt /close/* rtmpt /send/* rtmpt /idle/* Forbidden /streams/* red5-1.0~svn4374.orig/webapps/vod/WEB-INF/red5-web.properties0000644000175000017500000000006011332146107023315 0ustar drazzibdrazzibwebapp.contextPath=/vod webapp.virtualHosts=* red5-1.0~svn4374.orig/webapps/vod/WEB-INF/red5-web.xml0000644000175000017500000000241411747114732021737 0ustar drazzibdrazzib red5-1.0~svn4374.orig/webapps/vod/index.html0000644000175000017500000001237211332146107020544 0ustar drazzibdrazzib

To view this page ensure that Adobe Flash Player version 0.0.0 or greater is installed.

red5-1.0~svn4374.orig/webapps/vod/spark_4.5.1.21328.swf0000644000175000017500000267011411747635016021635 0ustar drazzibdrazzibCWS îÔxÚì½yx$ËU'*õ¢^îî öµûîkk)íêE*©¤îê–Zº’ZÝ}Ýv9UªJ:+³œ‘¥ÅóÍãò x³|0lð6†Çn˜Ý›mÀ¶Ï/ÏØØ0Æ3Œ¹/¶ÌŒ¬Ê%"2³ß÷æ£ÿhUeß/NžØ·söûŽ|²¯ïîïë{É¡¾Ê}ßÐ××÷Í/ü½þ¾¾³Ž¾3³^Y:µß2-8ƒ¾{¬éºí™¡¡½½½Á½ÑAÛi LOO —†J¥ÓHâ4<°\mÿ´zìÜ÷öþ#;ŽÝê{û¡#®Ý÷ÖCGúûîÑ¡‹ä‘¢‡Pj8¾·õ· kK3;€¼úªíÓ¯³Ïá¯:ØÑ:¦H|ÿž¡»Íp¥\¹—€õo£ÑtåÐ ïëë»ÿPŸÖ‡Š ú{/zé¾Ãèo_ßs}O’ïÏõÝßÿÜsèOß.Yèïð᾿;Ô÷šþûûû¾t¸ï¥}ã}ô_ ÉÏÿn_ß“(ƒõ½ãæÜœ‡;ÔcÏû¼çì¹÷÷©>¬Çœ¯ÇSH)¦áDÏñGO¿R?Ö?À?ÿâÿˆl{”+N'úÂM)åéÔÆtA &”+Ÿ*¢\=M V‚S{†ÛL.a]%ˆ/ès¿Ÿ¿±%ñ-‰ÈŒ$;±Yû±YP³²ïý÷ }?tÿý~?Íöûc£’¿sìï)ö—ü^:Ö÷·¸:ÆpÇû¾tý=ŒþÃßOô}i?AïGÏOàç‡ú¾týÅÙÙÏggßsýIÙy¨;;/#à „²×íulŒÍƒƒ9þ¹}ˆoúP½·sÿ´¯ByyŒ+P¤4\mg,Mö?¥è¢„‹Ö·5¸(òÚ® :ÜG²Ò+*ÿ?/bz­ã=#še°“µÉ2Å?3ùbæµd¬˜ÍýïPÌ^p7ù÷ÕjÛŽ} XU\úÞû¢ó¿õr<èîÛqP9AˆÁ¾ïïC“…çïùž+ý§œDŸŽá¯ÇþþðsÏýã±Cú‹Ž~¥ÿÔÀôÿ–ùËß?òÚöð‡ß=ðòÃ?ôèã<öÀƒ?xá‡. ¿¥ÿ¹Óß5üÜÜæ~~î/æž{Íó_;üÜ;?ÿžÃÏýÒáçß{øký»ý=òÙc¾ç—¾þ¹#ÏõûæÿúÇï8ü©<üÆ:üë_ýÂÑ·þ‡:òSúSGà'ïÈ÷¼ùWŽ|ô]Ÿø½óÓ?öë_9ò«ÿó GŸÿÈWþìgÿ|à;¾÷mG>ûá·þ__úëcý‡o>öÆ7ýâ‘ÿëÞvôsö³‡?þË_ø§¯}õØûÓŸ>ö}?¾üÖ÷kÿO|èßöÿúWþ¾ÿw¿ç­‡>ño?öß?öóÇ>ú¿?ðÃïþÌ‘çŸ?ü¾Ÿ?ü‘Ÿÿ‹ÏìÝÇÞòÆÏ|ð‡Ñkÿñ¿þÐþÅÏ´ÿg>úÎþ¾ó‡~ì×ößö›ßÑÿîÏ|°ÿýßú‡Þ÷Ü·ú«ßÿÁc_ûÊ—ÿéOýé¡?ü±_?ô7þžcð¦÷ |æÞtìù?<ú©ß~ãáù…ÿvä׿ú?޾ÿÛÞ0ðóÿå¾ë¿rô¿óú£Ÿý£·û‹÷>?ðú7þÈ‘ßùî7üû¿ú½£oøÁŸ;òñ_ú»C_ùòçŽýí'>pì“¿õ†c{÷_¼ï[þÕÀþ…Ï üÖ~pà½ÿôý¿ùß{èÓ¿û½‡¿ú?þæðÛ~ëÿ<úÜ?þÀëßxè õþÃß÷:ò®OýöÑýè¯üñ;Ðþì'üØùÑÃß÷¦Ÿ;òÎüÆÑóÛŽüÊþ|àÇßñþ#_xãÛþл>yä¿÷ýý¿ÿ?{è7¿óû~í3?ÓÿÅ÷üꚥ‘ÿðÍ}}‰òí‹eúýÞ9ú÷/géß¿eûú~ä‡ñ¿ÑïÏ-ÍM¾ÖyïÂ3ÿ÷ìÖݧÿý~ñ‹LîÈÜ¿üð»o|ù—ÿa–ÊÿWöüaÆ{œýí›ûéŸÂÿ†ç~éåßö¹g~é7fŸ¸ùÝïÿòãœ}þúò?eßñÿÎ웞zëëßô­ç˜~ï¥ü¿<»Cþ}zv”üûÜì¿xÑÏ]øÄë¾uöóÏ`æwÍ>ø]×¾ô®wÎÒtþŸÙ/ÿùG¾.}ëì7ÿíÇÿúNù><û?ùw¼²½6;d½½ÿ׎®Ï~âu˜è ³ø“§À7|ò ³'?òöö¹“ï™=½ð²Ï}râî“ìïgÙû~bö>ˆÿ}žýý8ÓëS³ÿæÏýìƒ÷ÿ»æ§¾ãþáÓçéó?a¸ÿÈøgö"IøË³øío~÷WfÉã|jö'WþíÇ¿¸öýÌ>ÅÞó?±t>Íôx€ÙóÇØ÷—ÏýJõÎCO}ûëg_óW~ðÏÿ×oÐçùÅ2MÿKÌÎËìøg³˜õE?÷‡LïÌ.=Ò9ô#ÇßÄ~ÿ ³ã‡fÛßÑ?úßøãÙùûÉÙsä>ÉìûïïÇgÿæ®ßþá'?>ûÆ¿ù…·üÏß~çù7¿­¿ïÈ®mèÇZûƒuÛ/¨ânkÅÖ;&XÒê®í,ÔP÷èܪÁ[†Ùç ôÙÒ¶M°f·¯¶lËÕ 8øñ5Í­7ÑGàvÚW]Ã2,Ã}ià_fäÏXÝþ&ÔC_êXuܯ-;ŽvPɨÄŸÎGlm˜†NAU ¡L ÂáH›}]´,TgUFΪ§I,q? ²ÁÐLÙBÃ$ ±¿wÔjåÑZmpÔ¶.t_ jDåÎÉÿYÓÜæ#Ñœ-_5€+ …4¼ ½–«Yu@^âEáÄ «1P]Ô p^Íðo8½ÄßQJ/ s– œ¶m’—»«Zõ¿ÚΣÑL'‚Cél¸z‹Ç£¥Ðš;šÚ®AiÅñ±yÛ6f= Ð ˆ«Ì²v`w\L,$‡xŸŠ–C eòèkŽÝŽk«¬ v5ËÝpL@JÃIÔÊ1©{ª‹äC•åüÓÑhî’Ôfp•ô„KiÂx%ý€ ‰7íMÍAIF9“Wš®/¢I‡»l@ šôDÜë´ì]’<ß?€wз!¿ŽÆig좿3~e"Â5K7qÙŒ®'û5R’,Íœ©km·ãòV°”.Ol°áj –K ²hé­Ó¦£YïC u?˜N‘'ì MÍB3´5ºA¡TD¢bz”,Z_ÓÍ4y>…ÈË”æêž…*¤¤Ùw:Nö2€W o£VÅD}ЙÔT½rIEH¦°ŒŸJÁÆ–€ã´¥­œ$ÛCƒ `·–_¿n·Ú“X²ZW`]3Áõ’ [PÙà‰·é.ŸÓ²X¿ ŠÛ¿·]KÁF6x#) Þ–ïøep@¦ ã‚FE="JËC \é´¶å jÕ‚ÎzT4UˆŒcP³Á‹+—m¿Vú¿æB£lƒqálâÛúiñ*}Á´·5“©M£NR$VßS½àhí¦Q_¤{¯à§™®Ÿüå€ Òt )–Øhj¸¿ÿ¦¢Ó Œ¬þJÆëÀ­¢©°mj¸ƒ=+’VÜ<gÐ5o ¥ü>ƒ8ÚÞ:x-j_P‘Äå7wNÔ­,ÎÜÔÁîͱÁñÁ‘›¤®ïÙÎ-xUŒ7 éMèÔi+wÓŸ‰¢ÔàXš†‘jñ -ìµm'ü.ÞCÔo ÖÅr¯áeMl‘3ÒЋdQc—ıMÛ1^‡sÖܨ;¶i¢!€AIäDƒòa^1¯Õo5Я–~Y¤©Á¬ž· HV³sã⇷"¥Ä›>×5kã–Ñ^ì8d#‘åÁÌ OøfU€Ü$N1sêx\qý]òÓÕH¿Êrfî½æ•ò…,zc¦Š…ÝjܬÿŒ I‹ ¥wðl±¢¹Ž±¿¨BÑiwsE¾)DÝ|½c¢OË–aá®þ`¸.êeá„Dÿˆ×çX!;ºf£<Ÿ7ÈjÓ¦½l#eNlƒ†a-¦)Á`bä¦M—­$ZÄ´ùÚ½¾(š–>\¾(Å0»»Ê†¤t^´¤V¥ Èðh’e fý¥tجÓ1½:!0êêZ(Ë+Ôz/p,g¤Ö7泤NidFz>7uFëÞü:'38èÙ» ØÆvkqI‘'B¥»B…k`Û•tÇ®wàšf‘ª¡„ƒþ—Îê´½ B(Å ©ªë­W¸OÃÎɵ †ãrë"2/¨Wµt°¼AWná´\%Ó Ëk>î µ%‰2£Á[XY”Ê Ù=ý{7ÄÈîáòóH´0¹a£v›Œ0^S@Š;J÷(éo_Y@2„¥pdÙ°@–üˆÿÞà}6\|ƒ~§P›Ñ4ð{áë E¼æEüÅf}©V/J÷RѺ§ûhѺ£;nE ·ûx­>0ßq][½GhÚÐ]ðƸo͉)Ø4¡‡XsÞ³oÂÿHÏ,w?¹¬D£‘EHr T+W´Y³ßTâ -ÀX;¶SG]¨inkõ[Årçñb \VJýà®¶ñª&z‚;ø<­eVM6ù÷?§DˆoÁàµV54d貚;¬³•Ùtaþší ZÐðîš­çP(ð@œ¼å†ÝAÅãFfJ4Èjk <ÒÓ QÖqžÉÌŒO©pœÙaã…ìÅ–L .)ñxÍ19gåªj§ÉÍ}¯Ì—w5Ã$÷㹦 ž•e⿼ÝÚåÁÇ=UYfÿäȈÕU¦±þ¹ò¡<~•ôm©PÒ7ÃIŸá“Ôà’¬¶ÑÝÆYš˜¦÷²,OB«{^–Ëh ®,°r˜޲í¢"¼©9ÈÄÀñW8ò! ÎyÈU ­î er32@ÿ¸ž,ÉeÍÒ¼3>Y) ¿þ#K±Ad ·‚¤Ê€wàd¬N 8F#5Ç€ô°K,H—g²Ô½È.~R–±Nòv@Äq൨M‚—U[ÞÖjP½]={yÏ*ÿ]æ§î ]‡»Û;ÅKì–â°^z»!qΕN/¤¡µSGywéK#£¥©§âdƒƒWe•DÌ+,y¨„Éz¯ã³ JF*ñLEwe½“/Br‘GiÂrþ¹1ÁÈóIaAvêED,ɆL,8?$(y‹I:öÞ‚Ý¡“ÖáX!oÃjEÛ_W@!€aI¦ÀP §S<½„4Œ:/1Ø2JÒs5¶xd»ÎsJH#î§ã¤w Ò“U ߬N¬ÝxôÕ%û`¼¬wÃ0¶ÎtŸ(*Þô=GÆGÒËà†®çÅ'ÂAñ@ºlk¸fÄ:æ»·[ª¡Â¤€™VI‡8“{œ¿q9SA3=š€p(ôíT‚`ÝD–MÝí"þØ´º7CÝVRÖ½v:&>Ñ €¬}!ü­ð÷$[Ï.ÍR¶`s¦–…¦wAÒûÉßXxuAülGæn¼¿ 9TªP7 J-œ J÷.ïó¢å:ÂŒÈ%‚R½-锊Í4D¯DÚ3+òFoÇ;œc·ãF‹}‡ñZýEáªI7þ¬ÛÒ ø›Œ·¥ZŽÞ¦tP¹ÈÔQõlåÈør ÍxgVðH*¼©îP÷ƒo$Ë¡ûƒ.Øg~ä½0YwWlkÇhtèÂÜÕ¥ÍÅM$µdSÇ÷[G&§føgøƒïlE³Ð˜ÆJØPb û([:*mø÷rd|Jµö©C©.5îä¿?¥ãÅÍ•å‹Àl#m‚/ëµfݶX$…»ª˜¤ÚÂ-àL¦z¥²é¶LCœù¥àê&ªˆ¾Á¼Óƒi(\’ ÀO°Ø}mÁñ§Å}šôK"Ê _¾xÉ´÷ØéSrˉŒ3EßÎ4¬[ ¦Q¿ÅÆóO¦àð(2ùºtÃe^9ñÓ“t;¨ ÐT)…×Û!#¦+~”¹Wîà²A‡Óƒ‰bhº„ÔFŽEЇözˆü:@s6‡¡HLÃAÐu¯Hœ$$žÝÓ‰02U„FJ#ã¥d ñó`¢õ⿼"R¢éψG¹öPäïaÇ=©2Ø/Y¤Ìž·ðžô3ž‰Gþ¬™{ÚÜhÚ{¨M­{×Å…ñ’S´°åeÓР·."†ïF‹u\6ÇD)±ßö[ãx‹s2x!E† “Èòœ Œ++Û6¾Ó_–Øïxñ,áw_›t¡Ø\Û&Ët´ŸÚŠ7S]s]‘‰ÏYT›u4˜ך† DÅðÙöH1Ê&¨·äl» h<+=PZ†k¨D°žÀÚ#[Ð@kèK¶wŸ,M&6[Ž¡/®WÒ…b«O“uHñÕÇ—ˆ-¤&°´¥‰fhiûx HÄZIвw1Þr¾ÌV|f‘û×PGizž%D‘vF‹¢ReàÆd2E$6/¬N OEìä`_^FÝÀW¬ºbÆd†­4†­„.Žôب ]\ ÛIA¯·™Çg·ýfçÉdáEK÷E£3 ¢ÂØF9EDâßÒ”%¼e ƒxî”qYýLø5¶dºdšÿ4‘Ø7Á"ÁB<¿×#ÒDƒåd³"ñæ`­^¯xï"òWT£×z“ÌËL£½mk´e—Ž­¾¸é¿æÐmΉØìÒ 'k¥‰Äv;6ujÍÊMºP|ÓNŽÇÄ?Øï8ôGâÐ{…_ÑTIã‘Áˆ•³@8:a4VGsˆø™L_ËÓœy<ÆÒÀ°¹%™*ê¤}< IZˆ²Kü{ð}:²„w­(G‡ × bùqê<ÿc©‚«;˜ûÁ$¹eÒ ßƒŸã¯+÷ð¡$“9ºƒ&’¯îìÄvL?ˆ}ß&TËØ´‚¡Ùã1ÝjÕe’ÿ§’ñƒbzן«<'¨[ÊÈö×:Øözwíï‰Ôɰ‹:ë%Sk<ž>mDðÑ”9/*áX,¹.2®M›lx,e!À{¡Çå¸×NÖ‘¯ñ<ÁÓž\´!“.%·t_vßôjLV­ážÐÄg½/X«D…="ÍÄ#ž+`¿È½Ý–¾(GZcÄÇÿ]ÔWmwP“ùâê"ž"ët–¼ŽFþhÊs0é¿«ÕÈ "0ä$L .üõ©`-ï$šª°yâCqÂÜLúëBþü%ï¸tȯˆ‘ðÆq'üîòOÅùk‚/‹ØOþ‘IwýˆWáh³ êv,,œ„4>t–*íã”ä—b%I7šVÆŠ®îY´><•*ºæçèÓ©²ÜREº0sš¤E”Ÿ¹¸rSÇÛžYãJ¶n×;ž¶T™„BJã4TWCÓŸH!]D$¡Ìx7éƒi­ $ŒÏ„ÈÛùO¥ ûÓæTbÞ×ÀSéÂ>ñã)²’‚ Yò|š.㓤gÌ×è)Ñ$Ý‚0¾X-ß}šHBË`Xu³££yYpêYTÆçša5¾X`5‚øo²üª}¬w&L-µ'ˆ%ÔšÀ)ÞRL4$$wEDJS‹¯IÅ ùå7Nqæ½\ØžN‘ Õ5qá„,æ„}}…e*Š'ë“ÆZ“¥‡â…R[ƒð±EaÁ„ŒFÓwì3Iÿ@1 Æ ÙV5¢.Ɉ'غ œzÈc·˜ ¾!,èÛ\H»Œ­¢6žý½`Ý1ÚÈòÄRò8è ’'«Óðî*± ;¿RŠSrBI¹Hä¼Eº¾‚„Z”+s]Ðb Å™òBIùLèÜQAy8öfôRx÷hÛ¶ÍM£-"ãGÁî$Þ¬}7iÌ!¸Çb¤éYÏçʰpç‰×…H+iPBÕ­£ÅYƒ[¯+ŵ%ñ wÕùu„Rû¸‘ LË:«Î ߬–d´|<o6FE¼Ä!Ýyµ±Ù«/öÒØ–x$äPàÉõñéf AiòûÉSXvŸú¡¤jÏd⊠·Ö8‘2LñDýÀ¯4ÉÃñ¯ˆ¿Ð^ á=É<ú‘ØRÆ;Ï}:UŠs]õTªpP·cçùNǪãW¶— ÷XZýé;…ªÏLаZ° ­àMâu/ì߀5·µPºq%×Þ³à©øßhóž,Іeñ€ïîäWšSpSÀ‰ŸNjéÊt¾Ž§©äÌá]H:˜ÃßW-k d…(Ž®%ÒÕÊšæ¸Ç½¥¦)Ø5Ãmb¿†ÃÇ­Œ}²T×MòT|å D™SÍ{ëØý²q¨/ŒŠõp\OÝiõ 'uk°iïU­sÑŽæÔ›j |‡0u™fSÛSAe§r¶ ÒŸ¾ Ú}…ª4ÚsØz±7qržz/âÎÕ}uÛì´Ð€ûIåÃIJð_†Sd{öO¤‚ÎwÍ ÝŒ0¾Çáäè,³M%•‡àçŸÖx†‘𑤔Éh$ÓyŒåA2žÉD$“yLÕŒzåô¼×–w¹ïÅøÑBwë±¢DI…Jô9E6ªáY%4½\hÌ+ù[hF—TÕ§>‹Õ÷ï7§‡%3§ÆÈÐH¥#øáYåò³·’õzOÐA|–ÝH:AâŠ`‡ýeeM ™.#C)3Ãhf†±Ì ãYêa)¯‚\R­Ðl´É )ÍšIð8[@ÉÃùЭŒ ·…X†ð- iÑÙvG¡äÜu¤IŠpúw%aú(JÒœ†äaØtä(’]_0êäÂaCý ðIãÛpwÈEŽ—!²R@ý⽎,D |qÍvBF“…tb!¸%çè$˱ÍbåšÄ” ½R ”- ¤W߀PÙêBäEHåx7DäMphr©ZÒ…¨é¾Kƽ†”<ô]ÆÄÊC6|áÜˤË7•ãe½C¥!û( PZÇ=™áTóvÝΖ@ßï!Y³¨†Ã² Åÿ4£w‡îYχÅñ¶ê󦄾çcYJºj:¹µ¬Æ„Ëqè£p˜ŸKŠj±8JxùnÍ»†ÝKÙ©®€}÷%]ÁÝl5þÐ&ÀE5ŽÞµðùlDx¾š‚[ýy2©ëû3=óÞ…ÂLåÀÒZø¤,*v-Tz· Øxk(ö—UÆmÃuØ™¼Ì¨pi_¯Ar7ùäÎÄ&ø|•×’GÞt4QággÈf’ײû‘Bð!¥Ø_Eb¹ÓmAóÝûèºKèºú¹‚ovˆ‚khÎU'‹áÅ#ãÝ‹!Þ¹ª°b8îÁ%…”‚5Y̆7#ÈRðW«¾ÌZx‹ÞDšWRÉ¿tÝPI¾Óh7KÑñš.(pF]Ëdq]facƒ:] $AÈÜT17q¢j*;¸ R\¹kBQ¥ã8ü'Åwi‘MèYôr¶ì …”]ÉP’ý^‰ÐŽ|%›f]!i+™ØØY¸+™HzvtfUª-w”ᬻ "5>[½Ä: üäµ°K „Ü©æB&½4×ÕêM,’­¥ß1,2¥!­}Æ:‚ïÏù\Ù^OÞë]ÉØeÒÂHN;aÉ¥Lj!,@{13 L»•C³ÄFXØìžÇíl´ô`ír&Z«Óâ8á Í4éY¡•¬U”£-»™+¼W†½ÞýN¾-º–•}¾kì°d;8±zá;h:äTËÕ,#&¼Hßq²ƒB«X5½÷æâz>ZÒt|‡“§Tfz1kÏeÀ–•]\ Û¹lð²«BŠ¡«Ô×ò±s³â{½Mw3àíCäÿ1Ù–¶o´:-n©Tlslkq}£ºzEiX²i1D°Àœ†@Ó‘¶çuK,þ¦Av½›wRòˆBP%KkçЈ“QA€¹?ä=/JÀ.j£a šná¶hY6}ž€Ünœ’eÀg˜1pR HÏyÄüÁ*£i8â+”Ķð?‹c¸ê¦€ÂËÝžàeh‚ú§€ 6EP»_¹®ºAÙà×Ei Jç¬8¦·ŒÍ©€Ûد sqqFœ § ^PI”óˆoÎøeU_'Å¢ ÖAG›Šï Oõœu¸HACÞßXè9ÚQRj§P‘ãðaa kQD¡7J>$âÅ8ñãƒM Ê›¶†: ²L²HOv+"Q'p÷¨ŒúíA¦ˆÞkNÊ®Ïjf½câ‘J/JÄYtüuIZÈ<®HÓàiÍrØ$³J$kþ»œ—´ íÆpCEŠùyùäùBÈ,ɶbm&†3ßòļÅÏQൠ4þ‹–NO-Ò½|ä¢ß;X‰Q1¾—´ö9ª™ª/5C2ñ?Ý[% ~…EiÎV¦·ñwº‰k…MÇh0W$×s¤õÖ'3ΫZ4Ì{·wáeÞzøîÿ… ‰˜ì¥¹ÓOÙx`6o—2«>>ÒçNÞz÷v[/Ÿ"Ô厛‡)S²œX`¶rèÕ-¤Íåì44Ši#G® Ú¹—Ü=çdþ‡µË™éøb&„ÄQAî˜.?²ÎÔ›=ÙtÝöÌÐÐÞÞÞ ¦ÛÛ÷­C¥áቡì£iî7ͽškáãYs]÷Zr6H6'mñúõZ.Ô\šIF5'ˆo Ücçc†·žGÄÚÏä«Û\9Ì…‘Îi™†›9 ~PA`#–YyŒÕh)óæ¡,sõ®Ð€íÞîZ¿‘Cš^Å÷üÔÜÛ]!ŸÉgÊ™ê5¹dA‚ç£Ô1Ã47FÃÑsijk*U‹™86½ae³XQ°ë,ID"§]µt°cX ˜|çG^³ã«”‹j 7Ùj`—j—iÙnÙÂg|ðJŒ§UNLªƒ+A¦e¥@ZÜÈ: ¦gGºþ ¶®fžPx‹—IɯVð%ìû–ÖË ›ÕÕ+ååZ¥z¡º¹ñLÖt |D÷#=ÊZNŒË#¬e'lãã‘p˜m›àJ¨˜Ã“Ã#¥Ñ±ñ‰É©é­¼’ '± TÒü@9™µK©Í¬„x+•­(xkïp9Ó›zƳéÐ$sÙd«/T_q„$˜¹VùÞ,Ø|,émæÅºÄÆfÄÓp^¤UlU<@@ÜÀ¹)Kåèøãz¾¤¬ îÁF¾Äd“{¬›s†E¯ø4C=O¦@ZO{Ë]™IDÖÙ“êÆêóé£C=Ò #’Æ%¨‚™” ¥Nå 3¼_‚ ôЂi·É•LÕ´cÐ(ík‘VǨB£FAÂöŠIRjm9)-’(Ds?v“jZ Ío“ °SS©#¿Q¯Eó~™ÒÜ‹bê·¼aëÃà1‡nμÐíá1.Ý(Kë[§l¡Ñn¡×{Û-†îW£9œ…ÖvÿÒ$!ÆzºyŒôÁÇÄ…$þ$ v5§AÙËB‚û_é[†C:?¸š:únàÓÁÄùC¾€c\ŇºežfƒBèÑšŠ(]»ÀÇÎÖLêg™wÔ³%Jâ;¾™.ÅÒ ]:í.¾µZÒ쪴f#Ã#ÃSc“1¬2ŠÕM£j(uÞCyXèÀ¬Á"²@±?hã÷ O<Ïo¬Ð?šN ;v;ä~RÜÔ(ÿÔñŽpJ=—òÆD‘€Z„S±ûÄË©3T,Y¿:%÷¶´_ÉNBµ¡UêR&:­AóN®øó×­üáPÕBÓŸšXÁyYˆ/CWx²uUÊò©ÛíPâçdä¨×¦M:›¬#f˜Ç„ XH¸ÐŘ³yQøë¼$š‹wçýr¢ºe€=Œ¹¬NÆf]4޾B´)ÉZ€Ð,úkЙ˜!oâYH½Ž…R.*¾sn³FN,Áî¸ ‹w¢’F/=¯N´d¸$`cÇ5L8³Šz‰–fé]wkT_w7£í†ŒvAÅ3 {^ÛlB¶hÒ)ל$¬gæÕSggªØ½uw"ñç}!Ý·3Ÿ Ÿ«ÈàDüLˆwPƒ—²)†;[LÈ‹*ªäÉQ™Ú6˜ž Ìüj4Œ]êÊ‹*Ê­ƒ$§‡;`“žBú6”ìhÓ a"žÍˆ!£¼zŠAu‡TF

Q ®&ÉBÄSá[5YHpú: ç…|RÎ:¼²,®§ÇÛeðŽnðΜðùLlwÝâ`×DÀÎî›}‡ 3Uß¡Ç&Û œŠRµB°Û¯.ÑÒµé×A•¬"S b¦…Sè~¼RÍ/w ñ_ØÔ•ÄÙî½{Ž0þz ÂÀnÝ»éhľVwvPÅõV Ó¶mÈægÝLÜQí<Ø‚ ­Âlü _œA†”} • Ô^xc?qýüzïí¸úz^U¤r»^Ô D›Ž)IVÍl75.X$0RI÷´¸Ð‹Rå@†4;#Iæ z°"ÊØ Vˆ4–l•å0QWãÅ9S{ƒâ`Ûuí·7(‹„ò…ÏÞc>Ô€(Å;* ‹„Ÿ=/I¢Pîê—\ÁÞ4ð™J6‡B¦•%Á`¿muÃ¥k:\œZU†`ÉRšaEÛÔÈN¢Pe9²^ÃE;SçÈbÃÊÁ">I‹Vv‹xÁa i_‰lÁ‘Ea‚h†Ü‘Ei¨B³Ðô³_©çÁNÂÀã&•<ïá"£ sÐx¾ (”Ö¤$Ê;ÄÊJ8…ôZ¼¥’Á) ‚0λV­ŒU(Kf§eXxtP%g0TÊR”漏Óh«ôs] P¾£nñý›:X)÷ƒþL«`u¶£«.ºzA¹ç¨ä;#¸®”ï>8CÊ7²¤|C)e~ä¢V)ëÜHE«PÎÚÀ©“34Þ[g#Ž&ËøoŸ ¯0}s¼7W*”2Ǧ.Æ•jVÎò,)ßÈ’ò³YR~V¥fy`•šåcÆÀ,†MC©šæ å4o(§ù¬ršÏr­„‘®Ýæ®ÛIÁPj'üeOÙ‚è/wª”â¬0"å.ûÚß½`›¶ã•m¹±!Õõd­Ý6ÂT‹ªKÓ°\]™÷VÑm…ëçU-]vð ÃEUøõä½F–ªÎ©²\ç.*ª aôLißÈ”ö³™Ò~VeäîH V22(Œ'ö¼ŒP!E´ÕR¤Ààœ€0pŸ;' RHé@%¥•”^§’ÒëTÖävƒƒ~ªP…‘¾Þ½½U•n£¹À,¡ý­ye&!æ:w“M‘‚4sÊM Ò_ûtƒuEsc_E-ê›T­àžgVŠÀÇZVo45|ÖÛQËKáÕhw^1àGsÊJœ –0°·ý½&›‘&ò,é²cA“^ê¢VemPïÝa^U.û:ìÙú^”Kâ²ô“ì DÇ,× ·¹æ€]ÃîÀÙ WÀ~Ëà†Åê±ÌÉyÃmimoe9Ã‰ŽºÖÆg8²5oɲ¢8vÆg+–Ö†M[þìŠÿÚ8&ˆS G=ßÊð¦:;Gýš²’A®D´O Ê-B¼øœ2¾ãñÊÞŒN;H$dKï £ G"=ðð\òØ{eEh`[õ‘Gwˆé3Šº`«^V×µ1·Œö ]jn>ÿ¥ë,[­ÆêÀ9e}˼¢1¸bq%KE·¯vH½¤üJ=g[W-ì5?WCq\emOjûô¾"i¤jdºVÎÀC—ÌU41,N“rªÂ’<êw€ƒú{N‘ ™i.ò÷þex(üz™´–ÊøÊxvãj‘c!^i ÑÅA3bM¹öú«8D™%›ÝÑz&;!+±£úœ¯í=¢"*ˆþÚåfvNf?ŽtI~@Ígˆws> .Þ34ñÐóOЉè4ù¼jQSƒÃ0\¶ £©>­¨g1 Å÷Hæ²Ù@žvd:]N×ï[í*Ä~‰½œ—¡ *T¿Ã&°Ô}4 } ,îã;Ôð¾ÊâRùêòfm¥z¥v­ZÙ¼xYqp@¸…­§ü©.žs—¡ð×cUú}Z’’¯B»hÑH'³ë.ò%I¦„Ñ×qf@8¯Ì¹ †UAsêsÊxF>§Œh….*øå6¦ÕìD¬@_Uf¢™_k‡æÖ¬ §Î– Ó HCߎVñ× 9T›L¡mÙ˜ÈfOQ²fUXÑX“Åû­ˆëÝ„3Øi¿b³Ž‹~HÊ”a5æíý¡”£éF’°ãJ”‡u°óÑHüßSÑ?Ñ;Ø×Ó:Q€¬Ô ËBaÙ¼7¸ûÉѲđ§°¸°ó f¢óÑÂN hŠDÇT¢ÇãÑ®ÝîÊh1AAÆ¢ŒDÇ'b»3WPR”ó†0'Ñóá¸ÊÈ÷X“iB1³¥)a\פèÑh`÷<9MìFšXhÖ+&v#ƶó”©ä†® á[}ç‰qÀ#¬º$âÚ.Øïñ7Òp Ýkù«З-¢¹?ð’“dzC|é©ç‡yÙ„{E]×\ ËáhãUËB£\L8<ó|^œ!î=®ËP0?©1µ ÇïÁGŠFjÆ}=Äwò¸3âé¢\NÅ®w¼Y˜26¸%‚uì½y­~«AŽ#áAy5îzT’ ›%$3øó|uAx‘Úêú^J’Õ:®]­Û çèI‚4z( ÒÐÈé½TˆwÛÈ#ì*ìt’xÓ†dÆI*JHw¹¼è‘6ÐÛÇÒkšŽ‡SËìÒ<(¸M$Z÷Ž&+ º¼˜¤¢6é‘JiLpzS 3ïßÐU¥¥¿Sôx º&`Ë)ü¾oV4õêÔ]\ôqä8#ÓLrÙv˜¨³^3µ:íD߈¸ M0î ÈÕª{O¥Ù“Íç¹Ávº,Ù^e_6Á¾7ä¿3\*âÂÁôo ½Êïà°B4æùq†–­wL°¤aw'$õ£Äʘ8CpøcNTÇ-6‚,î×Í4P!â\J‰ðûÄ,}r@ÝÛ×ZT¡êYíÙaa=yŒ@TbÔ‰¯çȉÇsˆr;GÊeÚsÏ“ð¦;YV©Õ_™«%(ù¢å:Hý¸Kù[QÞ,ÌÚEÚy´@;åoçÑ"í\*ÐÎãrOÈ=Y«ç‡cEæáh¶˜*°®Lçk”p[:œ&Žß½ êXœIFŠ´wÌDñö-ÒÞ…’I>^$ùD‘ä´Ý“ÅÃB3sªHòéüí=U¼½‹,ߥá›ÙjÃ’Å‚<çc„1_ç,\¤¬Y«çŸ›cÅææh¡™*´öLçmšží³ü³süvtA¨Ši˜‘bí^H'4q;ì>Z¬Ý ¦+–~¼Xú‰bé iÛ'oG¡,8[§Š¥Ÿ.ÂîS·ÃîÅ–w¼ÅV$}ÊV˜‚‰ØÛ5 VÑB‚§Å…ð¢iþõx‰ÂŤq©(Éb[yW*¨L” ²0Ýr+†¸ ‹*Åtã­€¼-¨LŒ¤ïXAúޤïTAúN¤ïtAú’¸Õœx½­¸\ù$—¯ƒÝ8TtÜèX”·' ‚—ÕÙë&Bð„“û‡®V¿ô%ÛiÅîmÞÓ%xä!S ©=ϳáxÔ]ö¢!¨AÕͪƒ¡®ïËR`ØmdÜàf5Ê:€Å‚?iÀ |9tE“TªeãýÇ5ÍmB®)P{ô‚` AÚ©À‚ó‚0âó«m›šKï¢g@ÁŸÑ >šÚ®ASÏ„|â‹fçò o¯ƒ]à@ ËÛ£›@Ó7σ:8$ŠÖ:ŒÈU×nJšvZÞýZa 1ç°\1¶ô)ÉwÑw‘ÈŽH[}^á÷?ÄåñçË’^ œ-ì½—Pܳ Ýqê€ú`p”w ‹Ü Z­*¾=²BnÇk¨nPAÔ–‘âÓ<ØΜ³jXêñW¼Nš†E%Kú$ &ЬN{ZM…EKŸQµšÝ®*©nÙvÛϳ°CDQ%t¸!ă`gN²Ê·ì]"³*ÅlÒê|I-÷tìlUP@|ÉojNp>T’оM/ÛE6`iÛ&j×Åœx`E‰¨®¡¡[À²˜ ¬fix¼¡Y˜Ug"mà’";?í8Øw¿ïÞ û>Á,Ô[•P^/¦ÝãðÓI"ÜÕÍ*àøÚ¸¨’nO¦¼,RpPƒOŽ,gJ¢+ßV³êÛUÇÓ¦«£¡àã¬jýg¢¹ç,š;§+„wmÛܤA¢ïjÙhPèͧ%H°?(ÚyrÎle‘PNqæGö}=XLKÆÅB­»t.l®"A0s"àç·hWì=뢒·ÀÁ¶­9hÒ‹¦¼ôMò! Îz g@j ¤ò’’Ê´ˆÓ8!¾zqæ¦voŽ ŽŽÜÜq´س[ð&2Ž¢i^ß„N.ÛÞ Ò¾NûLwÚh&~EAß„áV5]¸¹^ÏÀ34γP`ª• P¨ˆ>ÞM4ƒÔÛ8Ä}N¤ë‚:·#;@m¤¾„û2œUá«›“‰h¾#çtª–H¸å{91òË£‰DxÖx-Cö>®3÷ÝO¦Ë_ÑèNœ¨ha Îf\Æ'뻋—ŸÒ_‹Šgsb­R†'áݺ)A\Ï-ÚqA`¸ö‰•)]ߤ…jLHžÎj–»E@O ‰\¸+,ŒãßÁý6-4 ÷t‘VÍ;ù^O8ýͦEXŽ ¢B­Ñ ªK&Øæ-%ñËu?8áÚ+ éà¬S’´ÕiqÏ wR/ åUò-¯ KcvC¢¶Æ+%…lÅ…6È:t(xVvû‰t¿ˆi±ÆvZ†*»·ô>•Ž Wy8#—$tîÙrZ<Í:”úÈsâÈmhºÛ\ÅGLñ¨Yóãü ½kðCMÃËh¬^WÔ(¶”FIê=ûG¼‡ã³~Þ‡§dz q¨çO©V?/ÞÂìºfÒýß‘Zý‰ø¶~‘‹`•&‰ª\R5Ûn,±3êRi\þÉz)˜\M©Tp¸\X6ˆU)«{ùÌM©Ra8ÈE ,£É ÊEv¾Q\1?– Y±Æ¤Br)šö„Ä޾÷°µª,p6TܨûÁ˜¦§‡8- z‡é´v¼"ÄÁên÷/¬­_ÉDÒãf%]—›<ÙP—Ý^ˆäR&¾·ÈAŸÑüôÉÅ>cùéƒ^M¤&ÆË¡º»“玿ê0$'>ƒź}S±É8öž¿\u»’*Þxøî~£Û‘ ,Üpº£5ì,ÅíJ ½•QlRÜi£Û”z§F±)ùGxnK:Å—<~ßæv%…ÞÊ,8©¦½4Æÿö%†ï_áßQ_ÕiYÍbÓ­“Dð Þž„Ð˵nGB~oŠM……-8Ý€u͉8K•œJÏ“ˆ9#¬lÛóö>½ð_†Sd{f)O¤‚ÊPŠd÷ŠÔtŠ|ünMÚ ó'Õf„SéY¿ºcÍn_m—­zÓvRiØ•ZãFjFÎ9%oÅçÅxÌÌÒ15§‚̹An1¯(qFRE¯* ²!ðE%pÄBžº¥š1ŸQ‹è•HŠ`¯¬DÀ/ïU”Â˰õ%%’žå¾óJ4t¥¯vâp­U«ÝqÕÌâÃ×é†ð꣄´@c¬B JŠpú«‘‚’Á®\Šd°*)%½:’­NŠ G¯¥†…QSTa@aY˜žÏºßĉ” NZ€uk–wCJ:z 8\pï³!(`a~µVXV L¸^)0> ãý”6¸éYû‘@îf®h»FƒÞÎEc !†œX+_X¬UV¯]y<þѸÑaõ±¨ rþGbžŸgèéòÏ™ˆÀcFÇ¢·1§Å àÊÓB^G¦­¯ËP±>&FÀ[)uŽ”½CœúõBè£Ã[g2EtpPeJ‘€ËÊä­óá.åoçÑ¢ÊDκb_0È´wãcšéY%Ï"f.²ˆŒXDÆ"ݹÆq é˜(VYYa¬¥Bt%ÉÖs`åÚLrj,gÊܵ,å¯e)fÃ<ŽRs:€–ÆD; LÄà ÔHŒ£@ bŠ%ÕK1‘³â€=ƒYe,J÷)µO-48Úp7ÒCø¿—Gÿ„ge9Øýs÷¹TùÚM£Î<Ë%±¡wx úç=ÃÒÙÆTŠDp„¤[‚órGÝÛÅÊù7¸€;Žwú-¥Ž¦ × ·IGh Ò7S‚Îà5xûûðÈôù¼ØŠO'«„×åðJ+õ«t‚½‡~}:ÆŸ Å«ÐP /3”f+d*I‘iò: «æfqï¥éúŠ]Æ?Óä6mšàdZ‚®£YpÇvZ× Ým.Ù]›šÆ]øNº<-XÊÊîšð<-íK]»‘&Fucœbb7¦’߆Å7={=¥bì!`ß­ÄbODúÒÁïùDZælƒ†aUmïá4I ¥Vx`é˜ì|š\po;T‚7šÄ/Òùd³ÔM4{YÀž‚ôÈvãlZêÔ¯j­M·Cè>;Æ|*ƶþÊÜ4×¢Ìp- \À 5ôX}ôã§^3þ´€¬_¨G$„©±îd} ÄÒ“Bp >ÀãD,á×[FûZ5=m­Æ$Hñ+Ö6pŠñÖ~Yœ .½Æý¶Íƒ b›´_åä3MÇõ²¾fc—UC]ßCjã™·GÇ}~YœLÚü jw‰1µCª¬`ÿ L„ûü²8¬J¨ -t¶ú‘.Í^÷ž®œ˜NAr%® yµÄ´ª Fæ|Ï0¦Ä£?&€ì1^¼BLŸ1iÎÜl÷WãïÎl:°×P³ œr½^mµMvŸ*t•pS=WÌ!,CF¾dµñ‘­jequm¹|cq½våêJ­¼°°¸±Q_^¬-¬®¬­^Y¼²¹1-˜tï£A$×çapÓ¦T9• ,ÛuòZ‚|%ûáªVÊŽ£”Äa5$´n›à8¬;m4£•Ã’ë×gä0°£uL·LZô“kåõÍZ¹RY¬H&MîO‹µb‡–LܼOÞãš’.7¸cCSšYa m­ ›6+ÇØMÆsj— {fÐÐMqC_Ô |!üuJª³¯Ü¹a1 w w^Ð@Núð^ð²R@ß3´7XìaSTÆ?Ëé’"…Âv‡ÁÎË3¬s'Ÿ'dàÁ¶—TÁéXPÊú|ï¢<Ž?À¤¿^Te¢ýT@t_Ï™²KŠE„4vU‹§º¢Bµ§AøÏAã8Ü›kõ[{š£K9â)xÏ Ü¸ØÖ)¨íOò¢‰ÒÄ,s9'U¢,½'…yåœÁ÷xMüóéø4µ[o.Pl½3*<èðµ†·Ç k*Lø¨}Tµ°ßü™d0M%ó4¨ÿžçäÊêÕ ºO_V¡D†ŸÐ&iE±¨cE°Ãî@ó`ƒ†VzEæL0²FzC…GÓuêlû? iÑ"KoÔ“õ‚R©"_W÷,¸€½ZÝY½ZõW¡Ïg$T,¼ wïà /þ×gT(ÔFÛèiQ–L­_èµ²D¬ª)Usö¸Ö²ºF|—¡“ ŽÖ2¥à9Cåiœ ò¤eV²º§øŠç¯‹ñ^ÎΖàÚL†«bwpÞq®×”tÓšMη٢ÀŽéðÇXgk¦Öå¶ïB*€[ÆSÍÀöÕ²–‰T¿ÐÂèª:au¥¸R¯ˆFoY„;oï¯Û¶[ku~æýa‡8á†3d{uEscŸúåêyòd¢E¾pŽŸRE±·ìôMOôÎyÃmim*õH ñt:ìkÜä0³â >>. MhÏ †œ›Ô5\dãÍ»1ˆn0·ìGIzÓqˆ ¯èp¸îÂHâõ ûkâ¦!R0”_‡¯hWÆä ›67•AiÐüBJó\X5n7{°…ê£ÆªØ e;-”Í+ßy.ÞØ]Râè9ù’ZX¿N1«ÄÌ/+á£QV”¸ºÎS^U"I;ZYVdõœ$q4eH©Z wˆXc«–q»xŒ¸Ð^jxèMQ|ì—Ýl7µM{3Ow±fwp^+iÏiÍWåJß}^³@öRÍÈßÞ¥¨¨öùÙÛ?,\ ]F µúXVG*?›+ièütþúާo©VÏ_ßñâô-B߉âô+BßÉâô/Bß©Zý5éë·pWsnƒè/_[Гïõ¢òn¢}KÅé;™·¾¸óCö-¾G-Ú£ŽÚ£NÊ^Hž–nGžŽš§S…Z}:ïa{x\=\D¦ŽÞŽL‹º†—ŸaFе{©XúÑ"²uìvdëx±Ù:V¬ÝÇ‹¥G ü ×n[)¡Z­§×ÆPü õ¯øô·¾sM-‰ÄwÀ«,…ðÂBxKé[*HßÑ‚ô-Hß±‚ôÃúnæÂÛu0R¨ºî¸­9#µõuK†Ï–~)cú¥ŒéfL4Sú¥Œö/e´)£ýKí_ÊhÿRFûf´ÿhFûf´ÿhFûf´ÿhFûe´ÿXFûe´ÿXFûe´ÿµ¿Ú¦¨ëhmð:ÛÐIdæÈ®G)=H~,fØ‡Û [ŸX“X.÷÷œáINhµ]éžëÞyÐD;æçăƒ‰r={æÉ´Áøh¢\ôV÷¹DLÚnô” ºÇdMÍz7Tç¥=›¦eiŠîÑŒ ¥ÈX%ï_Êþþ¥Ìï?šùýÇTß4ûûf~ÿñÌ ™&ku5 Že·àXfí§2— i•×è^†U4áx¤gU)úûlY_b$»”£‰¼ìPÊn‡ÑìcÙ)ƳSLd§Pn&óÊÐrc*;Å´ª¦ò²Cö"UÎ\ÁK¨˜–!Ï$"k‰KÎÊX4ä=«ˆ% «ƒ3¤\Ê’rœ¿*p)ƒ­KÞ¸4œá8CÊYr¹4’ÁÖ£l=š!ݱ éŽeHw*CºSÒÎîtú”9pó-$“ۉ‡Ø-ø=Ž‘j¦‰½cqwMREa¤ûå(ÑÀ¹ ðN0q'ê‰ÔOq)ö’{)Æñ;'nÚ{¾É%SËôœ É!¾‡{bïn& ÞÚýO'ñ' AÞ÷^çKGǬ4(L½%# EDìŽ%¨ñ('#HÑ&^ó²-W3ýW“|­§ˆ_ÐxÿûÂ)†C²žŸ›4kð¢)¬mMÇÎ|–ÁNjvð¢'û$Ñu¯ Ë3IvÓns3M2%ǘä¼*`+-ÇÂÂ0*j{ ì€×vt‹Jå—yiLИ'cÖí=?9@ÐxEì=¿²É¥óùŠ>ž,GCŠ ¦äö.‹â¿Ž¸pJMò„Y½ †‘¢&mªSê*•ä8’ç?`01ó±ßø˜@¿áÏû»åés‰†öœ× Hðýµ!†”rý5)ÆÙódD ÇùÈ:á›i^ ›ä lF*ùçª#RfJ ßë÷jDèy!+I©JîúŽ Cx¿e“²feβä$.ËÎ*å «½îº|3ãÑ)ý ¸7,J:ýø¢"›Ns5ˆp“jptiËAš7Ãiž‰NsPƒ›ŠÚ†r¡ã8x ‰’líñ9Á‘ ã"°ž½Ø B(¾-£Ú.Ѐ}~ &!¥½Ã¡k¶iÔTaÐwC˜ Ó:®Ìd!‘ãðˆé§ #9öŠ´|Ëd¦Æ˜ûª¨(ô*š b?N3’,\Ö )`uZÌ;;Œ—E`ð± Š)»ßÐû;vÒY*MŽÊQ—l'ƒ ²6YPø°œx9b6`£Š•F”ÝqqLÙ4½œJ †M'd¸§µ½DJ²€²·„™ áBw’a‘çiRŒ„ݲ®}ZGW‰!©’^µcµè¼Rc‘éÖ0ZeæDŒZ‰Hݹzé3£/î“Apˆ¥x¹¼Æ\oƒ²•¬dÌÊŒnLÈØ]½Š<(X£-xk  ÝK°(lر$m†»%}ý“é@£·ö-9kêõ#‹ ËBàž$WM§e !ÛFœ‘`ƒúž0Æ1Ï'ÅtÃaÞÖÑëÞ¹iÛæ¦Ñ&•dLœÄ´±£ Ì0.bNk£ Æ¢zœ4U² ±½åA02Ø^2È÷“Z’È@å ,Χ,D.Ïu¯Dñh¢6Ѫ(è™EPN¯'[)Xt˜£8о¡ ”{?ÈœaJ¾Ÿ“KMw´FƒÅRE‡ÃŠm{¼v]½M‡é™J4²-ôÐ0Q*Ymp„VI㣹»~Í¡+Ž2‡:0AI¦tPˆLâbÊ+´ùô4ñšÃÆ‹8ºDÓà…›¹bïȤ Ðï`D¦G…uÍÑ%Šãž·¡%Ñ5ýup‰„tЦ›lÒ¹NOÐhXËØç|LlZ$ôW¹„2ʆ,ö‘]iugq@n¹,#‘\2àhE²k5Ù,D®8Þ^‹4¥#Q\º'‰«Ûþ†ž<únïņÞ6îñ×ÊyÍW‚GŸƒŠm½ØfR¶:X®GÙÖÐ8÷] 5”šÑ DüÞ  ‡ZÇù, tÏðŒÅŠaqÉŸUÃ*%¬í«'ìaiÂ3RàP=( ¬w^ ʇ«#o<« WyéP¬?uè²Ô¸‰‡zæÏ)3`£O+¨NÝO+¤K‘9ÕÄ‘($íÏ(ëDHWVÿp¥¹8¼@÷) EuÉû±ð\„Óƒ kšììú‚ gijk*<üyŠÆÈˆuÍv‘Þž>çÏ(_^dË{x›¬žRï—UÒA?¹«m@[_|f¥C#V³êÜ`I3Ím­~‹+@r|:¨-ÍÜÀM¯FÂëåEýøz’DFÃpáæAp!ú”)‚i§š7ÚÎ&^xmdf€Š&Ýq42^ÓÌ y!å¼é! N2ɑڀ*ÃyD"¹ðÕxBÅ7'¦`°-YÛQKˆžŽÍùfQ瀾9 4HŒøÀ9K4A¿,Gƒ¦Px냼äúå,,ª9„ÚÍ ,»•sˆçÀ'ͨ é5×Döõ¬­{smÚ=ÄÏæDLÏQÖ8êû[ûƒd¶gÊú.îu:2ñq¦;áî”HS¹‹rïè/“ÃÕ >¬ ‡S¡]ß'S¨ECS>n!ç•gþy$#8Ú§V4Kk ƒ§2õvïz<–JAzQ”N¦‚I xZLŒ>|árïf"€ *wØ(…µ³j0*$¦&uà8’hØhpß÷G“üšW»½A/ãE>k8œ wöS€}gJÁ¸ÏDrjPX «a)µ Šˆ*™( ØÓJèF0!ÆH¤ãšx€â¥12é8 é8òél+¼Ï¶Âûl+¼Ï6÷>úuœë2%$S¸!›Â nJ” Hpž–/TŒ°¨7ÂÀñN6ÃM{ à“+³ò[4rÅOÊàÉ2.ÅMË༖|¯¹ßÈr?…KäL8ÔBÎÈèþ:%å¯Aª£ë&>|U Ó»÷*ÌîEªÀ‚3&2š²‘(Í9$»>µÎßXÍF#hV(uu°tÊÚ~†”y0”¬(1,„pF2Å…ÀÙÀŒdštZ6U`šTßiÙDÕ,Mº•<¦€¼®ºq~Žò抭ƒó*=æ±{£ìªÂq{W(‰ÔXg$kš®Œ¥%Šb§å&»he÷$ÄQÍÉ—³*F3à*n@3dX Íb†| XÎ*Y’å³ÜÜàæÈbi—o´É..ý…LTYETƒùÃ:ÂmT7~N=}úsê P‚eém÷;À²¥S.8!?ºFY®BS-År Òë‘Ò RKp\Ú\8½)iKNªkñÞnRēגeûœR[êgÙU"²³ìÞ±cìV ïA¯cÒó>äZTUjxª¹Úšcïbß;²_‘cÃ’gTÞ•‘Õv hlûWânL&1ºö†ëV#Òý™d'{5yF'åÓdT„±ëûœ&É#Éó¡A–Ø%ä±û”a yâÌaJrq2!ìõŒ2*˜ï²dH0)ϗʘŒ«&2–[²ëxZP+šÂ¸\ÉaNWfÊ«‚ ú£;|‚ Tëøš?R Pÿ%óZš¢-a°T='LõpLÍÕ¨qY©VçdQ¡Jò’Ö~”IÏ ÓFŠ´¸%;ÓÜ@¹¬ô§³H‰ÓDþËEEŽž‹|eE¢ ÇMEÿÈÿ´FPL¿‘š±•+9Í$D{5WZ/Ôs¬ÁÕåXiD‘ÔØ—r¤=ÑF^•³%B‡D‹d/ÄÞ°åH¹ ~éaËJÝh!ey¬ÛŽgÛBÊÂX±u¯Thí-”™¦ˆæ>2~-žnmîD¦2êj/)R˜¶¦}ÏúÊhl†µÉ‹J Z¬ÉMíèžB9°»QÒ,n³ÓÚæv£ ²hà°ãÈÙǽǪC¼ž8oùE;}¸ÒiÇ@ÃmÐn ë}4!„ëšÐtCBè`:0Ü¢6-@ܬ$KÝnµÈe±6¾ª àˆž÷'qI0EÖJöþ ó¢BÍîJf*|¼jµ;8Þ”›PIÆSÕÀ[¨Š K1Ån`ôÝÿ öŒÂNÆÄÜýO¡”UÑž¦EœÂça¾÷µ ê0}ltÞûÓy)'6 ð …y•.›ÄÊÔðo¹;ûó€À"(Ôê3RIèžrœ7gi(2÷×E ÊebOÌtwŽA9îˣɢžË21”ðÑþtY¼o®Ð‘$ùeh»CïÜNûªk˜"1uã¸ø/9²¬+…ˆ‚Z‚« ÜÓZäyCTÛ6sOeDjF*@ª:Û ö"žå«ð¶aá{<”Î ŠÔÄM×ËåÂ'ŽçNÅ×Pò^Uˆ2Ô° FOF†È#‹]·r¼¼Ä§ÿe^ iuZìûê69÷ÊÅB¤@€EÙ=jà–ùL,ì 윅¦ë!Š9)4ÝøŽ"ÔëB7º¬ët?ÿàÛódA’€Û°ò{×EuŽ+÷ðWs‚œ•&C¦%[–GëøÿyEvæS”3*Rv+lKv_q•%Aec1.jÐV ]7AO”öˆ_Îɰô &dÐAÏ¿,K›ŒÏËE¯ lÉé ,!ânæLËŒ"t.Õê¯É™¶g稖sÝF å/c÷Ñ¢í^*Øî£óÌ?µ3‘=_ÇjF±ùZ´Ý' ®O“óO“¯ã5c§Ð|¥áI‹n-§ó/žáÖx¸˜ærâö˜¿€Þ°+2wÑ þ£E'0Vtµü“·§ˆnÿ‰¢˜,Æþ¨á¿ö/¼xNÝD£>àZÞ†bkŽ7dx…Æóµ‚˜Ñ„öÙB˜‡±ÒEQ¦õTqZO§õtqZOc­ ){¥ÂJu©0' Óy¢0' Óy²0§ Ó™”ç­œ˜¹Å)é%5AZée:ž¶iâ`NÎ¥b|T‹¢³¤]Ê”v)äPÀ3U¶9@0F?Ÿq™G5 >6¨à™Ägx®A ÎÊ&oÀM§cÕ½‰Çáù/—Ò6X°PWÄÝ`1:tfD˜ÊûpNáÅŒð|âG†6ŒE³ËÑÞ%â@]Ö\ò÷…ˆKŸç¼8‡¶Ï2 èxð ¹ÓJp(ÇáĘÒÈÖìoxFîU?IDTPFÂÜì8à¬øÛõÆX¨(¤ÛãÃi\\îpãE¥bI¯±-¶Ú.ipQ#  xCE‰îãú$‹Š$&ª=˼Z‚øñê.pDMD[Õ4Ú—•ø\sk਽K6 ʾï^‘.!]?kuRFØ¥FùrK[o›–ÑôƧ]7êMÒ¥¾ Jú`¼¬÷!AÄk‚ÓDP†=ÝtÝöÌÐvœ¦ÛÛ “YxÏÒC¥áá©GâùX bœª€LÔ­¥Ar]àÑdÏ¡¸ˆXd0{_Ìì´ Mª©Ì>^ÛQD|Á¤}±¸p²p>-™ôÀ“ˆŒ (͸Cû %—:®úCJýÑYÖñ‹èÑÓÉN$duB+}wÐÏm·(’*"ía7™á–»ÅÜë{G4±zG7ID‰iAÝ{ûöÓéiq=Êxº4;h¥µ4¿»ƒ~#ŽE¦Ò¼"UÓy’é¤Ûã‰×ù7ÄRwù'Å8{žÌ‹á’¼p”Ä(ø ý3RÐmþ)1h¯¯ŒIÙ7e^#Î*Yˆ’3QàM»Ñð–ŠÉUQ¬TAÖ(âÙ¨(–ó¹2€º%×wo# %Åä!æ.Û0‰¯ìy³ã,‘ÏCÁÇce|?ºi"0MäF: ñŽûp¬Èk;~cn©#A1½ºÚ3öæqÏT,­…od¡:ŽN-CöÊ%ü6¯ÎŠoÙp—¦•)P‰ndñ€Ì§v&!µA ^RW•­’“ºÜåìÌT$W”0öTUO’‡˜rc²2á~Ô™¼ÙJ>DÁåöøYiÕôâ– Ü\0ÔûhIź£í­ƒ×vdË«yРwº³ew X$¿¾“èþ­êEE\Ô ÜGBx†ÞÝ3ˆêzqÉPïv·'d=£èDüf À¬ñBCÞ®dÝ´â’a0 LA7`]sôW—ÔvÁY)ú†4?Ž6üuBT7˜/þ˜_VÇd°Þ}Zy‡õ.×ÒMËé쫺²ˆ‘“2H£Vl(ã„Ü×ó¸®ðÆê`Yãòm•¥8.ÜÅ1;pr ¨ ®‹`Ñ¡-‹†µwÃ2ܾœ—KÄ[WðVõ¾¾Š/Ü}sO”–®my¤>Ë­êϨw‹8p$uOë-%âT·¼Ù^ÝÄQ®+y$rI…„ ½®¶+öžµbïzKze*Ž$½nø^R‡BßF%€ ÖÊIc„B…TÄ!pvÇ’•‡í¸ƒ†Ì†V >òtA<zŸ–Õp›bmnÜë%ÔÁxÊ€ýµ{çJdò^3‰«wX’Ã`¿ÜcÒ —MsL*‡ð=MH€ê´YHÃI5‘z1ìä\¡é8N†¼¨$­T±.çqë I*Š%9bȸ´ 1jJ^7úR‹R­›ReÂ_[—”X°!šy5Ò…oÑ“d(°›‡œÇÄëiË·¬ÎSáüñS2#;${ P`S]R`>BµN{…à÷y%…paS¤èÕ‘!r%+…Q:¦#C‚íz!3­JK™xP•¢4U*ÛÛà«v¢2mŒ(Ñ|v¢Å ë~+§X¹ƒ7ôd Œe£k¨´Ñ„ÈN³ dM2 GeáWrSï×rc[;hXܼ¨þz” léëhxí®æ¨.YóYìN)ò4VÛÔêàJŽ„¹šì*=þ&5Š*£R™{¸P±WÏ>Úá#Š‹y¨‚+Í¥<ˆh‘ZÌøZ”år> ‘úW͇ Ÿ{ jðቑ±ÚL×Ý!ïÓÉbü}6Å'õɘ¢¢€ïñtbLˆs I÷9ª èh·@ LiÞŠ®+q ÒXÏØ÷üLn”žëÓœKµúZnŒÌiÓVn„!·ŽùêY*FÏÜí9ZŒž£yë9VŒžˆ6ç?š{ËÛ–ãéîQÅ {܇ÝÈñíÃAg bνNMgßRaV-Œ9÷ò;YL[€ªEÞ]t©fœW ä‚ždCÿÀ“<"ØI4þr#Í r’‘!س—bðƒ›¨ƒUSö‚š¨ƒQÊ*3‚/ïÙIDN×4eK¯¢»ÛÕûhF¥¡ñÎó¥¡Ð¿-!­(¤f kxݤ6|u8¤­éøÔø2؉9J,G®·ÇS¬ã›µBWäÓ8‚†H…cÓns ‘*TËVÆ0o£Î¥¥Z6Â$P­N° í*é÷\—{•ÊKø ëþÕpâ·_œC’ûjv$`4ØCÏAvÏŠ ØÅšÝ¾ÚöÍ Å<&0àjX‘nb1=~!0ÅV†#ügbRÔàia­l¤Ä °tÝÄõ…ÅC¿:¾øˆeÉM¤e šéÃè®·&T£«‘Μ‚N¸Ã\Óê0¿÷^+99¿fÏò¾Äã?õô@'‚¸Ï‰‚ZǵY½X2è.áby U†ŠÖIüˆŽsŸHeXc1$%ýS©’ë`ϰÈa*aÙÈ+мìö à2º¦áMÛÕÌèëÒ¼l–ËMƒÚ<ÙzÇѼ#S$Jš6í¤¢Ü£„¤ÈpŽ~&U'ú¾vÑa+DÄPúÃÉÅ_ë@p­ ¬‹†®ÓvOÓê .±¨ëÃÌO& ºfúǃEEQò%‹Ò 2 A¹¨Æa»rm=™fXšanø‰¨ƒQÊwì æ§I‡øG .¹|ã½5›FÃHÁ]¼•„å¢þu5œ)^£fáȰ I¹eìáã‚POìÅÚÕZ¤#Ž’DÂt‡LŸ„t{Nx0½š=Z±’% ·R$\»=*d;j.o¦)ƒ©°†uBÐP;xRKí-|8½wB"±… ÉŸ®Šx Kºz¼ãÛi Ú°µ3H¯ïŸÀlÄýÁ%ùbÆõA ¼ç˜¸ÃS%åzÌéKWººæÐ'³*ŸL+’¥¥På¼.v!Ñ…N:m¢§÷ï÷e@ãÈ­}õŽSÁ£U¼^WQ¡äøE¯‹Ê’¤Þ³!aW Ϫ`q¿k×;ð.ßp# ãššìä#cªá8ÖØ\ËDèÅ®‘ës \ŸöÊ,¼µèßÙ¡C+‚;®­VD Þã¢Þ çU©%Øn,¦ízW•áëlÁ <õjd ¼Î§_L#œ›d³Î\ÄÇñr°Ùµ§P×ÌzÇDŸÖ€SÇCaâ3ö®6ÿmJ âPüîDI¸ƒÊ ¹·RvOX`¦zNJ•]OFw?˜K‘y¢Å{qJóÌC7—cŠËÊX¶e,"8LJЬÞånƧg1Žðê#ÓéÚ²•G ‰‰û[±Ròˆÿ´˜<Ûb•––Ó¤ƒ­S9@°M p<A+ÚþB8³U¡R©–rªa(ô=b¤C»’T Wâ[¤\óâAÜXñ]Í1ðÞB8Xà½"¶ƒwÑH“Yµ¶ °ÇyâŒÅ nHÒôç*j… u. 9”j9 ü¿¼½i{ãÆ•6|Í5IƱcÇY&yf&3I¼·Û-J$µ÷Fm-º¥–,±»ÝN?á@$$! lIóõùï}ëT€* œ*ü`·Hžû®}?ËfYpYo:f>ºÎG>9eÀâ3P/¯?œG_íZäX6׋o¶²‹ÛŸÓSNYb—¾EÏ>'—ñR ¥{\Z'ñ…-ZäX€_C>6]ÈYÖûèÔÓ…†…ää’U7ì̾7f¢k†HõÇ4lhVV6?€4õ‘3qJW°¤äÉÑa»® c;¦žîž/Ú~E‹-,›ø”é4 ¼c¦zƒÝêqM3Ûr—‘ö|qtôê~ Àf•AŸ½àdùKÕª^îùx,ÛŠÉa6ŠÆê ë½sEöÈzäL£ö­ö>^ê†è7O´ÚFÐoâUóÐ;lÆDÞw.æ¡M‡MYʤÕG¦S®ÕµžY⚆KÚÂûÆX „ÍP=ëŠÍh{¶Zó!±B+ó$g‚Û:”¦è׾ݽv\r|»ôZ¿uòø¤ ³%}*Õ­ŒÕâX™o¾×ç|Ks·šTü·óFQ‘– ó‘ïÌ"¯!Ï*Ò½àJP¿cjÒo”T’kõãŠi&L0ƒÕÈFÊñ¼"Û9Ù;†£y(èp©"o=Ò§±“¾óX=±n㽸Ò3`)œÌ“Y¨v4…›•;´.bÿ€UàÅjünçS‘ÁlhÙÓ N‰ÄçS¶ZxÌZÄ;!|aØ"1\é± 9ЏOMƒQ(xÖ¬€6Ãääæc˜ÁÍR÷mØå]hãáÊ íR8óáõ›jÑ»½ƒÀï¥Ù¼ÛtD–‘íy¶C²Owa¯Î5Akã˜R(f/>ñ™B!R Ñ‚‘£ hÐoňIûUò’¯C©Ë™'UxÊ [&}…=êTÉŠœÌ}J3¬ANq;“"9"l>œi@º|4[³™=¥Q¡™ŽCjcºmŠî¹î¡ÁB!›Ùð°[/ªAÜz‹ÐŸÒX\/*çK¢{V9w§t›ù¬r¶O¿r~¢ÈgýÊ9Š˜Žªç)ÙUÏVBv\9gôtÒŸÒ Îq嬉lß›ÌmIˆ6~ħ3ÿQ-T|úÿ¾Êœ{ Óm?Ršy^™êdi>žT(£7]ƒæ hõp¾ã:ø^Î8Û«Šl}è$ìYCT÷¬Iú$š.Ä¿9÷.ÃçöÝ…gùLuýµ9 pÑ+ÿÂóý¶–9Œ·Œ’íy=ä’*êoi [²›£wÚ´n^Ö˜LR3gõ°ÚÐ_8åõPÒ··]º±åÄ÷÷ù¡€=³½6§7½¦ÛdõËѾŸñ̰Ån™íØ9\üa¹D6£^úCñ÷á!û´cÊܽ²DËt«DòÂ&ý*>Lí8áÄšíZ³pîG¦3¹P²{T?|çu§„Côá’”õ•XÖ+²I5·VB‘¼ÄÇ(A#A –DÓÍ…EoòRZú D]  ƒ)¯"z€ vù'hÊ÷ûBp”“°¾FÈlAH•Gÿ_ÕÅɼ¢ï~I¬a¸³_üƒOn…“éë5,l£“WQ˜*M,­¦m$)~ÐçSš!~Ç ¨º˜ÃæÓü Z*G4ynܰº@)¯ߡ +ƒ)apª ?EÕÂ.º¿Ês SÜL=2Ãò º×Yc¶«î ³Ì\ÛKØUQFuû•¡›ÊQªç†òê‘ö2+¥ÞZH¡èf(úã¡zdÜD£ÓSP,S¹˜‘ås}7u€²ü´È°8plwlŒCy’qÂìf E1TZ¨Z«Äì gãÆ1…¢Ü¡EÐÔå˹ȴ©Ÿ>W"QÞ«ÊrNˆðMFŽþ’J¦^ƒgÐ*DpºÔ¹Ä®UúÕåHƒCT䊖4ºrº»‡Š¸Ç†à<ù­" ‹Æ ë}†ŽÏOLÚ¤õÛ]SüµwãL¯va^?4R½/¿!$çKfF’_ }›'Åÿ~f¯tsñÛh,ƒQç9‘í®¸ñøXÇÉgÆÕw˜E]b%,!:ÅuÀ¢|SI6ôF1ìf<:—"¬—woå¥Ûj9NqûYN"íâ’AsdòóN«BýòCn¨“â/Ë:ÙþdVP¥«åÔàÿNPÚð0Š  ÷‹óß“¤E:ò”wÛœ!Ëv*`zpH ±©«ó¿æ,8ã1ÈÀ“õVY¶gwâ›ÜYR(™tV1cƒÝÇ çÒŠ¥€ãäXô¨ltÀÜCÕg9 Ê#m%TrñA£døJó°é…Qø¯ÊA]Ò^‚Á}δ9s9ïNEõÊ}Aã´…œ¼×“ß¿OKºO‘Æ4*)(=Vú*ôÑ×Nxý²¿÷1SL8¶¦Ö•Êp:µ‚ÿ}°t²ÏiaÖo˜ÛŸ€ö·|LÝÍÝ+ŸÊÁÎsûî;œäy蓵lYGøÈóf¥ãL¾Ø×,fo:¦ãë%Oœ›”¯ÎA¬M=m<(HÇôR-èÈ‘i|ÓŸþâ¹6CþYà—§½gûÃóþOûúùJŸ\žê3ȇ‰=#‚ÔéÁ$Ò‘á‰6¬´cˆÞ~‰p'ò¤oÿ Í*Îyi6èˆ53bBÕe ú*ŠÚõ“6‡8}Uׇ£‹Øãó´æPSÔ$×gê2ç ö¼eú ·W+>ÞT$áç¹hÖÅßW®¦x>üpOÔ§•ºŠâ˜óH›œOG_>ÖFÓppñتÖñ™g3˜£¸)ÎëJ|ü-%²?‰Fi€jµ>ãçWÁãá^%B¾ÅV™'ª§UæÕa¨_PÞPU\)ûÍ¿UjŠìzSìœ]‡ˆÔѤ~ªu…Ò1‰}CTPG†„Eßà ù•ö¨ÙK™È™w–a%_„ngÌâ¦æC¨hö¤¦ VË‹¢ÿŒaû"_,q)U.Tœ è™#–øèU‰©ñïç‹gÔ¦ïå˦ŒJv ê»ÕêÕôã{°ÛéOgóáAˆœéÅÑz9†î‚Лˆ7N]\é3d¼õf/gÌ÷oKøûI¡à þfn/éí 7€ØWÐ0f.û¹¯î­Xùâ½}rêÙ•øUvéY<õ(ÁcÏñÐÊç{Í‹L¿â±a¤•×–™œ©¯³bÊëÁŒX|=è‰+½ûHâù›û•B ßÑÃ7±žþ#dRIÜG1³«%èÈòd|ÂfèÏ(SüêMÇgÑJl¥krJò'Â%-.MzË(Wжˆöxà‡VA€óüRŽÈnH÷²›„=ªƒäŒe­üVÎ÷?ââvŽ€t.m㉽9i…=rØ›ð½1–ô€o¤ˆ5!×½kÑÿw"l2¦Ý^Þ€–û’] ¶2ß´Ë1è¶±o¨%ÄÏ»™½‚Áy3ö¸!tªãÄÚÙ-á»'x¸û×¥‘3¥ ‡ÇϧU‚‹3Ï ‡iÏ-<h œI¬¿øÄ,ñXÿó)Ïxƒkß»ye“®x 2%ÆjDòF£ÈäÝfg~q1™uÿ4v'kGa¥ØêÿëTo[.O ü—'_f*nËÝ¿e³ùswî¿·[9ßobñ™Tö¦>¢Š]€~•/òÞ±o`>P/õY1å…h,–B¯8ªSŽˆM„YÊÇõ)’"g;çÝ1_\©GgÑäÆ"«?¹ó±ÄÞ.e¤4Xiƒ™Þk2Ò|}Z^y0Z¹c‚Çå©Ã£ú+VxÍõ“¢A·Z'[ÒÑ;ÙãÀœL_JjˆÂG]s8ã~$Õ”vöÕ)’¼¢l•çÓóòƒ•Qž¹—Î'¼Qƒ’ñ™„¨ì…?{o»?ÞÃÈÒÇîgBKl‹³V~ŠàÖ¥øF¨§0!‹Å¸§C&y)×S(¤${®Õuk ×]Aq‚k~ƒëMÙ ‰°óû$úinÌL¢mŸÊqß™3§Ó5/ÞÔljÌì21bäÄ>½N€MͧçÌÉŒõ œ‹ô®çöí݈²²»/šl’Êo‡g'¯‡çûƒÁÑþpÐ?Þo—3 ›/äÑÂ×ÎØNÖ ÔÆòõJá¹i Ãl…¡Eö8¤«¡ÄÉù‘‹?Àˆ(päHóÇrT­Èz ˆÆ‚wºñ}}mÛ®|¦,*íy’wòdž ¹ÏìÙœO­F#¯¨X²õz¨°IÞCæ;Ž´=äz(¢Ùb¤Õ?WpÓYíá¦N˜NŠ8dW“ûÓqy ÒÊz¨ß¦Iz}ÍY€=2ŠLÎwq9·ã‰éÐ<ôxÈUƒNejŠ’ºššaQŸj¤xÎ]E­é+'Ä*–sßô1¼²aFì\]%šG:È5Â+$Ù³-9/qMÇ Ï¤É¥wI~%û½ ôÉo¼÷%šfY:õµë"êÔEÔ:'ß‘~¾_‘–PêzhÄ•ïvŒÀ’ÂÛ##ŠH¬ºmЦ.HÚfÃä_YãaR!¤?ïOÈ~ÎŒƒBW*UéÝ€–l‹Ÿšõ$Ž6îMÎtU:…¯—P¨*QØ;èám„\œ¬¨!X)]D¤$"¿\ß™ NL~iµÒJ:Ö¢%ŸØ4åÊÛ¾ïùY±O£VI”0×¶;ã„E䞉Ê5¤A¤ãD^g4j)ƒAl’¨!¯&´,¢¹‚™¦IòAìß-WÞ'«¢à®X.°[­ÿ™ƒƒv^:âAù¼‰¥jÅ1Ê"©²}-&(^ qó‘Ñ0¥áRU¦©>„³Ï™}ENòüÌ~O¥T¯$ºh¡çöVö«oÊ ÑâË2Á‘KŠÄGЕë]Äv[ç½F%MéÂài¥>[eÖÂiõù8÷~Ô*VNœaïÄ«RoJ ÏoQ`øÓJœ;ÑYè6<¶§ó·• ÝK)´@þMñv‰dÆûUÿ%ù?½©œªäåB`þuÜÞП­p\oJÔºP°Íd‰\Ö]œKe2v½Éô§L'5•ʯh[Žx[c’ìáH ÿh”t•ÃÊ ñëÍ“ÎpT)Ämÿïª"zÝtHGò©5AÿòÐzo3_»•Èc³#5Ûµ¦@ÇúdBU àÕÁöyz}¸ÿbxp²ûò|¯©$#©ºF†2•SR®+ßš]³Tþ»ÖTØežI{\w1¢¾ îøèrÔ3÷Æš<½‹Àsç¡MŸœˆè}Áë&RÚŸŽO*óÊJ8§õð%:Õ3(?'×ÁëWþP½—¥ÞP«W`êè¬úVÈ®’F§¯ÍüQ¬z±íéX$¬o‰áµçÞľ¹¶ã÷»‹z}át癓ÅÒÄ;OaérîÂ;•mO·â?™Ÿv]¯øò´"gæZ¿_‘0¹öWdJnÉ¿ò‹ÛÑ´ÑDŽHûZþ3ßƒÒ InÒhrQBûÓп[: L­=tšo¯ö×^‘=ü"[­³ÐÔºÃQó­FŠ4k4‘¬ƒ‘Ýp²‡æëŽ4Ð?Tw+‹è «‹+O{åY[\y:‹(Ïúâʳ¹gcqåY]Dy6Wžµ¦gQº[^\ÖR •Åhc!j/®@› )™Hß-jM]^H‰º ,ÑÊBJ´ºÀµR¢µ–¨³­/°DÝ…”hc%Z]H‰6X¢…lÚË ,ÑBv í•–h![†v{%ZÈž¡½À=C{!{†ö÷ Ðï*¦…¹ðí›…¤,$ö‚ÊCõ7«¾-$¿ŸßM.˜ŠWíœà©"gF]«^B0,Ǿ}v{Ç¢¡†[Ò§¾)KæAæ—“Û¥Œ‚SÎäMæÿšRÄs…ôõPð µ2t^×ÌÝÓ¾ª™—¿}̨.7´ýàSˆiqN=oÐo.jN5ÍOrð¶æ$¤Ûà&j­Ýdž ùEcäñÓÂ5'Á‘ fˆÛC§î?ž‡vœë=SòÈï>LÂÕI?±Sf\ÈK4A]Ñ Ò½Sz¯ÈP%áõ|rQ)Œ¡R|kô®Z(,ñ÷ÆËjfßPS{Ì׉m©/XéÓŽ66ž§ŽÑcc!pèÚ¹;%£{`Ö‹Þ}tf©…ú¼Ôœfeå(Ɔ‚XÎÇ î¨ûj)ßokãf$ò«êä‡)¯!ÑÀ—Ò±«§óJò¢Lå…i/¦û«¡¶¶pÝÝ·Ù?á‹Zãaf^\˜ 3ÅÝ7¥cû›Œ\²>«ÈrÚ³ĉ¯²s<î2:µ„¬Àµv¡õfñ:{lÆA[-ëÝé¨[fø¾2YÜ;ŸW¡‚_NÞÇeü¾2Wlò`X]|¦òõ¼:Yœ1ãá'¹Fʺ9|•8[Jþ|X$–ñAgŒÞt|Ê7ÞßÅ]é'ñAWžvq¢ñÉ#sÿÀ£ûá¤m”å¶yY¯5eØè ó H<³UéàÈ¥)ŸL†-d­E;Óó"yÃ…õ‘.§´;ú^¿_)ìzây›fƳ%²E¥Q·$YsS/¸‚·Vú‹Ï‹Å©é÷}é:|+zcb—Õ-ùãW…²„˜Å8ˆÁEı^ß+”;<¦Sâ%¤L2 º#Iþò¤ 'ÄÁ*s!¦‚Ò²H*ñp‘#• o¼Ïòð… ß©%9‰>s£g‰Vö«ŸÓh_•"i7*=ŠÅ»’åƒß‹ÔçǺøxÏD--?a3ròû¡1Ù=ªoöÄ}fÏl+4dzèøÎS5d‘iIxU|wR1ó´yX/yÖ¼¨F¿“(~Œ Ý“Ș™½k0±´‘ÙÂÒj¦Û©=ù k§øEqa5ØY`Z]­ÇX£Öê=QƒI(Þ~GÖSVh²ÖÀÿ=)ÆõBjm¥ÙƒIÏ€·rh7_¢öbKÔY@Ÿ^À¼Ý]TŸn7?«­.ª,æ{sg±½¹Û|‰º‹-‘ž•€*9ÄNœ H%X@*í…”…jÌWìð9Ñ•­‘äí¨"ù.ÉZ}d$g¿xWW.ÿ½ây0£“S+_€P‹uB´gÏÂë–øáœyÒ¬ð¿Å¬ §àöÊ’ÜÌ/"•ß8üçòë´3v8ªþ1Gøÿû§š«—nPsîø«ôéa+ÂÅ,ÍýªgÀâÍ"õoA»Í”á ¡£``* ‚#½ê$Wvù}‘‚DÔ¿¬„W…ÞFàà„Ô&JJŽÞÆ€cÏæcë!"õñ½‘3šp |犴Np\ŠÅÙžWËØ®ëvÄõ¢rÎ$º¿U sv ‰Ð&a£í‰áX¾®Ò" <ûÔ€mU}oRUâ3R2 eÕ>ÞÔÇzT¬ÄÕCôÿ­Ò yþè°† ¦E-­À.EË'ÚŒKì‚v„W?{¬.Aî³ô¼÷·Óû©Vn_|ïý©BRdY|œÝ1¢¦OvÜõeÏœâ9sv¹Uâ»û¹3·Ô_—y\¦6[Ñ£{KúôWÙ•yoLƒ©ø¯y èO¿´Ç‰íÿ™ÜF¢ü_^ä_ŸJo“QxÍ,­àæ4ùyÿÅÞþ+eÀ®)౜7è×y愹?eÏÇÁÏ-«¶”ϽËÃÞ>B},‰wËÁW\"ڱ墌)là1"òI¬Bðr&œ‘”ßnbÑ™¼6™¼Õ=ÆBFpú³·#w@X꜀jx@Ϭà¶?¶…å8¹aØ ~´ª¼Àñ‹"åÏÑ»âO5Ñ)^;µS¯ :‹ßVYã™ÑežP_×Dœ~.m„·]o½všhûóÈž±œºÚþŒÔ¤å6Ýö†Ú¾;t~Àò¢ú(Ìv5353¶kÏ#½Ò}Q‘Q˜è ƒuÒÕš»v½¹k 1QËé,ß÷n„¸®XIcM ¡¾h;˜ÀŒRk›¥ÖîšËa™[oC$Ió3i«¸d[3½Ú‚ ½#»ÅþùK‘ùd÷÷·ÞŽí÷o»K«K+o/}kbßxþ»à-Ùý0Ìèmà˜Jô[Îõ–qm3®%+à:¦.l ×f±[ÉŸßæÊ$¡€ŸY3!$Y©h¢æ©ÂÿrNœ`!ãˆÆ°Ü%……A ô!29ZŽw+!S»‰y—ÊyÏ ÅB­ÈŠ«X bÝ`u©˜"¶ B\(V˜¿™5sÙ#û2,Ο(˜D-Ì<‹²ˆ”Lb¶åK¼™³­X.(#\nÇ#³Ç¤x8É¢„õ;ÄÈë¹Î=ôã… ó¿˜+Šè›1'N°lÄÅt©ÂÜ‘ú!¹]Ÿà“Ø— Áy`¿rüpEeéåüBÓ@Û¢ü®5º¶÷ò{ ßÖŽ"Ž®é%Spàù½pÐ ~;Ó)%azÚ2h•bèº?ðÎÿgnùöv¹¼åŽæ.ù‹Í¨½i<§­”bÿ1BçònçŽ, `ƒ´ŠGì»öD j Y¼àw€mâ‹–B®á‘gvkãa)ñ ¡5¯Ñjܤ bMMl0:èêÕ&ûm½7É`mÆoAynï•â\²Tì¯ìoK%}X@ô›RÑЛàýRÁ :aƒìn©¬3}ΠõØ}(+±`³¶QÀ[ )ìµÆÉNÈqîô8ÅXï+:³í‘=‡3¥Rû¤üJÍD‰¿W”oMØ¦ŽƒŸ¼>ßE5 „]ÁÉe1rÏ€ƒnD’’ÞDªD±c»ÞMB‘¿ŒÙ Eü¾.“â.&Ö5†·ïÍ ö)mîŸÿ㇫ˆÒHp }b€ba€Y}´•g¤}úÏ„ïƒuWþÈU>¨žLOfa¤¸Ý*‚€y‚åÇ^»´åI‡øhLßyé÷ßaÇv0b.Ô=ƒRQ’ÂE¢S~a_.”èä‘¥ÑwF‚H±œè^%7‡‡‹Ýyz“Ýl5æú¸8, ¸Ð7…B‚§ÄB¶Ð#'c’á‡EBÉm$ŸÙSû¼ì“ÙÙìß1™+×»ˆuü RP[WékE<‰§]_€@­b`öæZsçôý …AMÉ&Šö_<6¸Ú8í,ŠJJO+:õ@KÄíÄÕIÀ¥oc¼¥\,îFu¹BáïŸÓúó|ÙØUe©Lqg)ʈþ)1b‰š•JìÚ¹ºvᵸçή-AÍ !Œd¦jXf&d\oŠÂ mg)‰áŒ³Š”L4cU’‘Î2‘d£¡/>Cùᘞ)fžK§’­~?þyÂJn%¿EÑÚêæ±íP#ìc›³¯ãÙ¥O¿eŸiUVœF÷á/Á=MhõÄ…æûHÈȆ6 ¯G]`ÜŸô¹Scöh¯Î¾½Å8cо-ùã—ù‚#öQÐ},’ ßà*)fN×JLUb‚ßVÐ÷±Éœ¬—ƒ˜ƒ‚îQ>Nº`? G²1ùC=´ãQuþcÎûñs-RF2LTºØõBÓ)ÁÁµ¼OüS›lþ§áÉåo÷­ ìŽ5ýžj;¶ÿ§úÿ¼BгVÐÏHãÏ‹yŸÛÓ¾KJè¶)Ý’ä•ZžÅÈ=°oC¸, >æÍÉÔÀÚ%õÆ®k%H«:eV`»$±ókç2¼W.ÿœd• ÇoË%ðƒˆ® DïfÞ•oÍ®É1Œäg UÒ¸š¶õÄ©?òa‡šÞ­aš…UìdÞE$em1öì`—µæ0Nx¿úä„Îóù)»;s‘C³´CrùÀ[eÕA~˜“¥F”ëz7öàt‚ù *_·|ŒXÈüÍ3ˆMøõ¾í‚=^¶õ2îC¶z3¨v5/yHñ.I×½»ð,/hÊÙNdþî Æ}ŽáL³ Ø— AԋîGV“øÊI@FÎïUk—°PW*;–¿›lZu!‰Yl)$Ñ7×Døl½rç‚ÝVèBJS]úàš=Ïõ'Ö"•,$°“±±’¿÷NûÒ-/Fžðß/”'ƒ<@qîRöÔ÷Þ;cæDOÄWG9g,¼éå,¶HÌ`ÄcSÊ{…Ò¡uAç=Á-OÒóÜ3®òÚ%˜‘Ñy pÅ2‹Íwóê¼ ¦^Ⱥ~.ŒxS˜xe¯„Í}·¼m D» }yv¤+ĆsçÔÄÛLtž#»Tn=&›è|]ÜÏâýÞ>nÉ ¦…t#H¶2é“®K66¯̃gÑŠKÍW‘õÅ6,ôU›T×:•ŠñŠÅ¥•ü—‘¸8HV[­5¢8®Ïâ¾ ¿»°Ã—SºöÙDµi¥“Ö ª{Œí‹ùÕÀ½#½‡€1À=¹]4‚.÷·á±=¯£A,ÞX´yŠ,Âìºï“x‘;Ú{¶%S¢(¦ÔòFøe8N½ÐÎ 3*²û6ؼžÃ´ 5‘Pcäó g–œ>Dr‚œÓ %ê3ƒW4&.ö®^¼T[ã1½â‹®—KÖ1¨@ ð—!rؘƒ‰)Ü%Ù‘¶íw‘•!ÝŽüÛ9€¸ÞVKü9Ä,]ùÎ82È¡ãg;éÓòõ›2’•MÓSvX:¿f¥üµLhg: ^ßV".ù½W-×`»\K¹“Š„éà“?›Ú7ožW"•°ÕRb˜¦óÙy-dÖèæŽo³§» _Oa÷§ãïëª6oöª¦fMö´ußÔ×[HcÀ¶áØšQ RI“ˆÞd°g2¡<úùÏj‰ø¯Rïü09ŸÙäèâ“¡.~ØÕBZóÐe­kôîʇ9›ªCVåÀxL—8D›Sæ1½>1•ÕÆ_“EÆ·i5T¥•PÐAØqôÊJRÝÖ‚’™ó&Ø%ç*zEcŒÅÄ”±toÁªÚ©æØ·®®¸v›!2P¸ ‘.½Ê¼2ƒaâ0H° ~;1N´Ïµ;r2aF?Ò”)]rŠ—èžÒ¥«š}H8çéå@<¼¥yïoš%‰NL„Œ¹N õ±G-Ù=8cÓ¶d}pÕpNõz¸ÒMú‹oJä­H ' #u1œ ‚q)7á“+Ð\AQ -›Ü9æÊ^;cûäÞYCQ TMS L0¹Ù˯.PÐzÞþ\‚vêT þÐ3£ `[¼OAß›1$!2¨Sºµûtæ!{D8‡›•7G¹§™cÈ雾ýþ.a?óØÍÞ›]³ÈøØ£/aVx]9“t6ü{zQŒ¶º-C:eX5ÒÉi§" 9‘œW«v¯ÿ¾kô}bÊ™s&y^•/q(|Ð ÷Ô°,õ¹SŽÈ¸Îø®“ܾ?*NŠ’qeµƒAsëÑÔ܆sXBrõ¾[(І{TãwôȦ¡•á¨r†ÚC§j·‡£³ 9.HžW*™ìd¤6.RÔªµÕŽŽj«­:ËÖ©‘«[½žE=ö]Ã(é Ocç­lô½¨@šæªc$w‡b¢Í™–Zêˆ)Xtk,¡/â#Óß2ëƒ÷­… +Oä‚v  Žá’pÍcZ~A1 b›¨2S[‰2@ñ }*ôfq":â`h(üˆØMdìäµ1ÉÙLÄ0Çð<àfKú´R&Ùá|[†Hö7e¢ñÀ•¾Ò O’l ê éÔCÓVnuP4{VhE[‹JOxç†ì¹„d-íã(kÂi#(qåK_:>ÙªÆ1PµäÕãS–'#Ð눫gÌTïwÆã(„qÎŒY )ü2þ¹t¤eF¿&"P¨KfÞ\I§°ýVü×C$ ¹« «Ú`ª¨”-ÎXŽÜnå|ÿwö7Ñ=?}œû^w˜G‘©èH•¤‚ ]*øYØiíÞÞ<2·<0¥.L"›I(ü¸ªÁÝ ^x! \#}íÉ“™½3±VÿyâL+µQ:ofliíºg‹«úà±.š)dGµò›LpÏ]³ìHx Ë‘\Buœš”%J4rõ'¿¬àÃâ­öv’ö’<7èîŠaN5—~+ücGÁôL7C¡õN5ñhwèäRP¤ÑÞð\ú¶DЫJì™ub¦^¹êùÀçt;†#”téˆë\—bì#ËÃ/Gÿ’_ÜòÞ½cRMršJ,—álA&›DƒxǘãÜ[rR%ûUæÐ˜E;#N@3Á]TÂÁfWŸ‚."G߬01GÍN¦j6Mvd>²d‡úg"°Í–ð‰áj|0±né!ËpÆ8³—˜Í„ž\bþ ·«ž¯Ï26b»±»U>ÅhwE5[o<>ª‡‰YÂë²È{"?Ž>ì?¯+CäÄYSá^Òý!zNf1ªƒL£õÌöÌÂR£]¿– ¾x%Ž'&K‹€ZhWSÿ(vªo… )„Lœõ*S|¯?\ø¶~#Ź-øõwªÉ%Ð}0[¡u/‘@Áœ¬;ìn¡«‚} ­ë$EóÈp«z‰Ñ3@/ÜÐNW4k¤~xÛÛšà ~D ‹æ¦ƒ´ÁÇßì±ýï ø¡`û`+vp'ï¡3¢—±è£{Á8m” J'Ë/ÖW6(X2n4ÓZE?nirMí›È˜âXð”Úßi[y?lIï ‰ŠTNl¤Š ñ¾½-ñ“úx¦Ÿ©1»Ý매ÖHšc©å«ð$A•uxlþAªlbmg-8íÉcAWÚ-Z©ãÑTe?É@UŠ@°ÆS\ÇZ—çÒ]³dn\ø†§s#w˜’'¼Yï$')²eNݪÀÍJ?™»¡E0,}‚7+½oC¸ ¦×_†x8sÍ Õ£ <ˆÎæÔ•d‰_‰m:"ÃDd3¨ÜØáaE¸xÒÃÃßs«µìœQ™Ù˜a/fï ŽõñÌBXrÝ«±âÏfdS>2í4ßÛ¦èžën™`ÃXI¾Ê…JŸ²îCÓšpYãkå•·ð?Dΰ˜ëøè=dŸƒŒNìßûÞm†#Ï{7ŸµË)Ò_ Ê rÚñ &l$~C㙉…î"ðÜ{t¢—ÒÁƒb•“•rŒpŸÏlË‚é i¯¯m4&΢âAYâü. ǂݹ0gËa#×™õ¦c¶…bów*cÆÕ>×O4ŽÚhL¬Jô¸R´½«P5”¿L˜ƒÔˆ¢¸hHª8iåʨífªpDÒW9UÊŸ(Fº/<Ö(*áJïØ9ó]ÿx9‰\ÓQÒŸR¿ñF\¯q&vT~ i\™¥£Œ–<®—ˆGq\ˆ–<.÷âQCG\e:¦X¤£„@¼X(( ZèÌÑ`[}…²ãk˜16B†æcC¾kÊÖÿ¸wú·Kð™ßêÁÜk‘Žâÿ$w£OÜû颫 Úá‚Ù¥zà2yqÜÆ)d RÑFWÛ6Qµ›þ4žt!Âa¤jÖϘ‘É:íˆÙaF¿ó§½˜áN_HÁ úC¦måk3±•;:p®|ùH“QÀ\ÅŒ`>’Øc ¨ß!ò™ Ÿ´„ÄðFû•1zª¼ØùÖ •ÝAsv¥{¶ZOQ¯”›KJðbå/ ÂÉ¥bdH×°ó7•¾•î¹nUI,ôÔÉ%¥ÿ§ÛÈ6@IK¤'çC½ù= •&z‚߯òˆ l\òýEoÁ:‚{Ö¨W'àËsk5vÛ|^ï`¬ÿæô¨×1ìÿ8œœ÷ëx.˜Öb¶Çx8£9Dÿ„òÛ° žÀ_ ËÏSü¡¸ÇßÕ ˆ»,áàËŸGCúd(Ë·u;Õ~rÚÂc¯©ñR?žTþ”Ý%Á FmÄ‚OÈé1´O¢Ïu“‘áðp :üÀ£è¡SÑ tZœ éúÍyA ‡}-ëOñyÏ€Oæ¡YÒïì»=ï&Jú±xâÍ[€hÜ~Ò+1^kCJôrÆizZóÄjI½8ÔiÀ̃2¶SHFtµ³ýÿÃ"ì9¢; â >ÕÖ8Êòò¼Ud[“¤"ª’±UŸ“}«„Ò*xY•Û–4éx"¿…‰/žhB?VLèRdܱ¯œ¨¿¾ª“xExý[´©ÞñÐh™ó8H´v†Ss¦pÂí3Evžâš¿QxÇuE,áWÎØöN]°Ê‚üë”mÀ£Ù0H…FeXÜ.qhÁ’KF‘VÒñ’+nùãsP¿Ú¡1(j°ÕAR»\ž^?êbà’ ‰‰nU"å•ް`e¬ƒž68}ÎÆ–5:"öEù1w;”`"GD©¦V}ýLŸF€¨éŸ$;NqP5À¬×—},ÖvÇŠ‚ß4™Ã I˜¯>M oèQ3Eì‡` ô>YŒ•ÖôÐcÞ&°@ƃ›˜ÀôS‹La7õ`BCdø‹ô¹þ¯øDš¼-b¡räs°~yÅØ'¦PýTÅè'¦Pµ_—"hÿÄ—¨ó`qÇnÛšxñ JsÈEšµ ¯º¯ÉÏdÛ!½’ZÓíE ¦Ûù„»\ÃE‡»nóíKÛ'“\FiN3ÑÆå…w³ª›°o´5QÜþT³ûÞDj(š áu¬ò¢™àØž1ý#œþÂ;¶çjÊ<^^UB'ʄ膌#pÄÁN./ O (Ö@¦? ³g°Ä»öeh Óï*~¤=d„S{¬.œ½<Õe(ýñsá…¡71Ør` t¯Y¼í‰Þ•XPZ‰î3zVäOSIªè¯b‘£Áö"†’T÷µÀx1a7„ôyà * »Ê¢MsìL…l<5ÇgÀº­–Ï2ðX›€¡ìч&Søßц‹¯Ú´v+Q˜V‚Èñc5ø›}í½^©{•XÎÕá{PÅ8¶Bß¹}d˜>Ck¶âµˆh¶&?©”ÿÎÞ“J%èìiÖ@íFzÔ7HO÷øIï9>»Æ‡ÒTdb‹?ôf(¾d<’¹ži·½_£G–={äZüUó¡n~èucè‘#Œ3Õ½¡¢~7 š“’o_A´òHy€:ÖÓ<ÒÎ DO÷Y̽`Çàü'4€ÁV'C‘œÐY‡ ¶v¬À¥3€OPŸ´Z@€LBv tzÿ¹¼°^<4c`³ûr9xbÝ 8ðœ°?ý2 üý4_J|§}/z]`Ú /g÷ äÛòG°'_Ý\ÝbîWø3ýµ¥ø*ãjuÇ 'Ö¬¯ÀÂKˆo¼$~S(/ü}¿Pð‚þ½3|W,{ÚÁ‘gYŸ»_.<ðÈ9¥œ˜Î—'S ÖNÝyÂL€fšE6â—š&°DÑÔ|Qâ„ý^¡ø¥ãº‘ñR2Q^Ï‘LN“=×¹㸠ÉUznÏuÚe,õ9Ø.“³™}-ÿ.cÇ„†$úÓåØòI¡ô•,".µV4P¹‰–D'žÇRGÉ•–‹É‘¾þY!¨¦µ6âª4/Ôò-—ØÕÊ%Ýã;„tÜÌÅ4ôçàäó<Îq±xt-%ñä¥| ½‘t­#Wô;úÇ7Hñ¼°-¥À©mŽK¢dw‘h¸‹×³bä"á²FþHXë Ï;{§}†cëhV8E`§Eè£a² ®¢9\²4ìß²±ÍÍÚ/wYÏ÷­»5-.Яh°†î/t‰Š”—pSývÎä?rˆ¤ªãdï.\ô•€£pÒö{‡l¦¸>ß Jw°š’鈻x`Òs¶Q G€'ï>·5 ™ÆâûV4ŒöÉ'Z}€+- ºh¿êŸìû¾Çö¡¸VâDŽG‘Êß¹=šûdHØžê°"œs~Læª+²ç (ݶÝŒ##&)w¸ÅŽð È–™¡B£ù±FéeáŸe´øÀŽÍ­è•|›ù££a¶ÿ°›T!®mw¶›˜:#%“ð*Éø™¿T&ˆ£Y¨dÀ ·ÃõO0bA|fQ‰àÓ{:²¢Ü¡e•¨±¬ÊcC7_<­^Ç€’(ñ ëHC«<ÀàˆHH»[ +ÍŽ°ãN‘¼d¹tº-LjDïA$ÇNõ‡IwÜA`„8»C;Éi¤ ¼‚É1Ük’š râÓ¾:wÁuéàz>¹ 1‚Ò_t˜ŒÎÊ(1¤ÜEH—ÅñÛCqððcé_x»Ñ INøãJ¤éð5²µkeë GÕÛ ÝDÔ[În­l«uÔ©úï+‘ˆÁ kÈO·‰VìÔZïkµ²­G/j,p½Ã|cèÔȶ9tªwÕzë«]•Nžd—•=éVêÍ)ì!‚®´Ô¤¼"õê.Ñ†à’µO=ùÙ¬)?›BœÅBžLXG}Ié d³÷Ñ­c²nÁÿ¾T|ï“£×{kÊTiéñ…ÜÑÏö8Ù÷ÿU!Èö¸‘#â{ yI–û‡—‚j´2ß´~çdÑ8O‰§ó–â»?ôÆï!mîeù€ä|NÎå½&Ñßša ÍÝ—ÄZ›X(½„FŸ“š””S  ñe&÷÷ ªvt‘ Ñí!¼%ßG‚à@¶„•e7ºëèÒÈ¡êKk¡Pí¶:ˆGN.Úrg×–0ÄJÅkAQ_-+ºé+‘ï¾+øöt½$á…áò&O8Ö‡EJŠ^œr$/7´™· ¬("§×ñkR2(¯ª‰3Í<"!„1ÌÖ­s,Œè?*}bmŒèû)ãLGî|LÖ›$2.1nc³œ`òê™+éÊ£äß—e…¢w)DÛ¹sÒ‰`Üßõ§ðˆi» Fô VŠÙu™ä ‡=àåuZéRêJ ú+_El¢ÝvrYÖm¼›)"8AñZ7·#J†-:âˆÞ;±‚w˜ÞKå«È îf¨U,–E´¾ì÷J ú‡,ÄÏöZòˆ™'¶rÁ Æ/J©}j¹‚éÃt‡aú_ ÓÿbzÙÆJhYÄJÉþˆY)a æ7:Ìot˜Òaþ ³Ë¡Š@?bv9\ËùÍùÍùšó'éY/G’ÛaÄk`ÖâIØé¾gÑ–0;ÝH13ÝDSN³ 8ÓxEË¢V—[1o–5‚ ò…”µجý¨)hH¿Ñâ~£Åý“÷O˜#’ˆF±èsOU9f2e{Dk<¦å{H¹^鸔4èÆTç €«°M ´ÊÕë]XîÀ;òÈœ\& Q5‰ì3Šù¶´FcµûÈA¦î¤¸—®*°‰d™EF¤ñ¬¹¥‹LvÜøKIêkÈo—yPllÂì†Fò*V¶OÛ7jÊ¿éèÉÓºìêa$Ëž"l.»¢À'!™¯hXkå• ôº6,ZPKq’‰/ZžÛô>7¸>¥®¿Ý›Ž䲪ɱ…mëÁ Ý%lÿcOKØp/J{Ö²å!òE±¬—õÎÞ²^æ;{KØU—™²®bÅO=²¬ <ÖúOÑý&Æ3WžÏrÛÓ'`#"fXÖya:¶‚w|éçÆs\lÿ–*˜QYKùí7àÈõ¦öW¢!èÔQ¶L8¨íС”q;b\²‚SEaG©öGýó×Ü¡µ:?™@Z_äˆîFÌo%h(üÂ Éøý§R6úCaÕ¹àƒÞþtʃ½®´r¾ßÁ3pB™`Ðסàz 9‚2Q¤ç<ÅÓÀ%m…žà¸nŽ/ µ­<Ò1lÏÍ£ÉÅ«VDˆcŽ0ë]kÇô5?ÿ§ßÂÿhü øµ]‹:´ü+;ÏiN9Žå_†ìo½"%“Ò…çmÿu¼=<4äÉØñì‘¿ €9Ñ$áG[P÷`JùÒ•=tª—ýñòW:A‰À횣ýð/Ø,š >1ð®®\{g†ä &~X-ÍÑÎFbò;–ϩϫ¥Ëu½›=;öÆ,¸QÒA)£5¥Q²;D-yeœ¬´¼è~PC:P(d¤¹­3RR©ÜŸ–$«û$öJ©#®Œƒ”í%°¢Ê¸liQa¶ _œ‘.`öxC)õi…jyŒLOÞy?<Ôàȼ!®j€“cÿŽ*§äK2d@s°ø”ÌEdçÓŸÎæa+þk»@(˜_]Ù`òJ&Czû·#w€µÁN‚Z~L*i2‹ì5î Òá¤Ð²Ê1™È*¬ZÚ(q©Qï ¾›·Ž<ì'ùãç’ÑlS*3AÌe†ÎHQ¸(/- Þi„ƒWíœèâ%—rkž–ca¾ö|ë& =–®F:òp±[ ëÖÝKõ¦ãkôîŠJ¿(jÌ(ÒToN—SœOXý’Ád_†l& »¢œï·ñ ™é³‹Ç&³çSÑi°Ot‡ÎK<7²Ã<ÙkÐk»‘¼¶!¯g5° “$½2­™²ö\¶ëÏe[ÐDÀPZ¾Ï¢ÝjcÔ¾œ 1pû¸’ãË4L±mšb;ç¦4˜±X2Æ’tÿ+s:¤–ï-öO7ïçØ-F¼ýOôÁÿœº²f¥¿‹Ê°éßYÔ–]²ï–U¹3™cJGi•ï"9Q+Gî,£Z(¨ôX! RªmbÊ -Yl'k´Q,¨‚ÛsIp•AÏÿÇÖí®\ïÚ\:ÎT?£ ОƤÑ”÷ÎX…%§¼bårï-ßaO¯–¼ÒÏ —W8üCËõÆŒï3¤¤¨5—–¼tü ¤÷¤ýé+Ǿ)̬ked?˗͘¤¤EÈ¡/§‘s¦ûù=¬î$Ù•²ùÓ·£xZüCñNDýqQt¿QÄ­ë pé/º ÆÉH”\ ì!¤ãÍqú—è}Z‰Dqd®ž+µñ» Æ÷€Âa‰)[»ŽúR;Ë0jÅZÚ¯[_~j©ŸÕúòCªz¿bë“jEéqB³TkõŽ’v­ýºS+[·Ž^°®táb\_EÎL˹Z+ÛZµ¶Qߨ©<-\8Sø; kóÏÏ@=³Êb¼P”€’÷ãDå /Ó ‚èA>ÞËu&àKž…ß°È~ÕµfýÏ?}…€±?çŠÙ· öñ€…-†  í™+-~øVÒm£ÑSA‹€)µÉ¿( =V®¿ Q%¹”Skl·à÷ß«}lüI’\ ˜Ÿ~îcãÒëG«0=p ne¡êTUèB>ãäv:¦°v*Kcÿÿ”Ó5iÿÚ“ {<œÜNÜa/•øaps9/`*šRÁawe½Û]^[Ùl™ŸEÓ=ì+Ãéæ|ß3áš’£áé;tïýЄ!z6C¸/°øôZ€äàЄ@¤"’£Ç&DÉ‰å‰ \ˆ.iÔžQ@N#p–ó JΓéæiPzV…@Ð04jÈ$àΉѸΙ³cÚ¯’àAF}\ h×HŒâslØQÕA•NMØÝyÏsÎìüÚ»á!üþŒÝ?€'+ø—È?|V 7÷]áö'W„  ß²EÓß ònE”ÂÔC©£S²ÍÝ ŠŒéIJRÚ±Ù³T&Ñ SÊÄŠ…åB‰zRh̃¸ÇÝ]êžl,\µæ—št( Û)Α)4¥_åŸüþ(ê\ói"÷ûG ”“›Èí|y*»_Eé©Auf[ã;m”ØÕ×Ш—´r8LñDûb>±}gtÚ3²œ §–ÂT©Ä¾ kf@þ"‡×Ác²d3ð½ \­Ý´kB•Òs˜p”i„ÿ1 ±ïÔRqLûXPòÍ­Žl'ØòÊT÷pˆ×¾¥ò÷Õò¤ó\{>3¥‰Ýù e•æ$‚ì™w“âóeÏkŒ)A¥¿¡D0Ut¬¨Ò@* Ž’Ë/÷5Ù¿ø˜r§óËMqåΈ旛Š"Ê-˾¿æÔM•έ%Jß8ò`‹/8²§Wáõƒ2q¦‡Ä1_©¥a¶"sú{™§¶nÌŠ…bgvàØî¸„-SZ§Ibói¼©GJæçÐIéGaÄòsÈïFFý) —¤ }5N<]\‰òj›ËL 2®‹k0ZËD‚ÜÉuF6=¶ÿÞ–r‰–Í¢­*u±=¨Ž8†Ý™j± âùu‹‹ÔhÙ wY-°ÅÕD j&•€ŽxþâŽ/w¬hkàüobZ²¦Dó߻ّY(¹@åz-’K¼À—Ê(-¥ÙžH8·´ã0ÌW¹œÒt…ËŸM™ûIÒÞ¶tN,˯cQ,(¨cY®œ¯l1—åòg{AαR²¼©sÓ+œ¢Ä‘JNiË-È‘ñ&mÝðÂeuI„Ù^¦4¯Q`[¬\A_{7{l¿Õ¸(&†”Å»ÅG͇ r×m!Þm"íBrVŒÈÀ™8Ÿ e•¡6{®ûEÎ~†jîGU^Ö#@EØr¦aLŸCxŽ%< ªÜ‘ž‹ã9GÌ%±{y+ܼJ’Ÿe“çí>²(0ƒ­hÈžÙWä›/KK²_–¤¾Á” '¦$oŸÀ·{ÎÄžR]ÚåòûƒD¸p³È—9ê*gàµa›û6d©¼b»rÖ¸xgì(M÷ L4î¸ ýy®4¤ÏBKü:6°`ýü³\Ìx­È—ù´4u&õy­¡^Þìv% À^øE‰uPòçÂÂöÂßK§b^Ú¿‚‚žÂ©‘(ðcñÏo¾ÎýY²ÌÛb9tXñ–}XºÅêO–Og¶xÓ'åg1'(Àï–ãéœ[@|Q¶®HAÉó„ÞÜá›sx“‰&—Â+e€ÌûÏ¢ÞTY;ðüÒâBÛ®"ê•^YK§ñû¥W1t@Ó±ñÁÙÉÑÑðäå‘î W)ÐG»¥Iñî)vèí²z†™u8ñæ½çÝL÷|ëêeÊVƒ=&š£6ð¨32EŸÌ£·ÓXžEù^˜Y­9£wôr8háQð¸XžÇ,€Í élb³±©mSÎO˜ ‰Jø&Só„#¸”ðNI I Á“߈ÃSðëÌ<ôr–K^ ¨å6jd½°o3‹´}û…=õí÷éƒYüZq“ð}ˆ\j¯ba´‡D¨5ä ÝA'ï( gÌ0GÊŽç—[ŠïÖqÈŒVÀŸ† ±HWlGZh¹¥ÄäiŸÖ@%iA½ª•0¶ù ’C¶@&â€.¹6ã®4¨¢ÏŽð÷8ùã_‹D©× >¸¬D‰q.× ï¶ÎœÑõþØ á¬ NAz£Q2sÉÆ¾é‰²otðÙ5[âú´É”"u˜s¾?ÔáH4V_ÍyÐV{:DñÉ~ÞÛñí•! •b’ "?$’TÅÈxVŸNneÔN…Z•!] X#¬‰­˜-c¬ƒëùä‚EšÊ~·ŽCffËe.™p€2àï±4|îRüÍ«¯j RLƒ§µÒ®(=B¹­ôî¥M•Qp>¯4m¡Y;g{èÔUºÛ¸Æ¼u‡£Ÿjoã¸k×Þ*Zº[_m®ÖÝÒúFóZÝyëÖ—·õºó¦öú§"DÌ.4Xq}lAlíZóÖ®5oZóÖ©5oÝZóF­¿¯À–Š}PU ã© ÊèÞá‚8šPP1@áˆ]hÛä2.ÙuÄ“·ü¼Ëáð‰{±pxAC:Ñž*–æ!в¥u Æ #žøÖÊë†9jk(´d%6×áĄt!ÉUTþ NT°¢¥yW*LèB­¼ˆ*Bñ4¡ˆƒÐÁÎ\n½3rYo:Þ§qlEãñw»%8rÀyåøá<úŠ^Ëp0gë{®.NâÒ·è}ÕÉe¼¸@y–ÔAQŠgÉßžš-k,»È”ÓÅì]€æÍìîMivl×»IhþU.YÁ+ívUÀ„š.ö«š ÖçÑ(2J‚wl[ …[|'LøÌ¶Ü%€=q½*Þج4’ì}Œ$3´wtr͇Eñ®…Ën• ˜Ö{çŠ^áí‘ÙÒ™Z\ŸÎ¾ÕÜ[Š ¾fýñ‘FSó¼>¶ÌÐÐp]mL¤}çbÚ¬ƒ÷œLBÏP‰*yÔÀöœ¾óžMäøŽ«wÏ÷fLAÆÉt+Ù,ñDŸÃºb³Êží†ÖÔ{úçÊÙfK£,êdz?½ôZù?­¨¹ &R•GÎÄ [Ò§T•xþ$¯¯ ÚIÁù|r moÇÙN!\)Í@2;²`ð-Õ¸ýZ’Nyšçµ mŸç²&æË„´ÇÂâþϤ©—såà2€MOc±:—r„‘oñ¿äŠó¹ïÛ\ÌØÔîd§ÌrñÏÁ|ò¨íMÉÜa9S~˱)õ„/Vºë[ìg¹¿+¾+u°ÚŸ–9XUHì›°f ›°hxVUÁ =«ª¨t=«ª8*{V-&Õ÷¬ªæSzóSˆâ=«VLëYµb2&žU+&©ïYµr“izV­3½öbº Ƴj­í†÷¬ZgmvÜzÝÅ´ƳjmãYµbbXϪµ• ãYU•˜öìònYOJÁ‚Rj/¬Lí…•©³°2uV¦îÂÊ„ó¬jœÚ³jµ0žUU)à=«æ£1¾EsÑhϪŠϪ*´gÕ\°iéõ<«3`<«*´=«–³À›øB‡”†ÿ=pB×~íLÇÞ €^§#Ãé×)!Û€G²aJÝÏVÕ õm‹Ö‹øa¹D6sš¾WHΫ%’ê3r«E#îÄçáÍù|{­'h¤úм…ÆgÎÇÝR¨xE|Ê^^7´@,v$uoVÖ‚$ˆØx­DöÒÍz7#µÚCdÞ†â·ÑñúМ=4;æ¹ [׊¹¨”~§zúíá詽·}ã–H+Ÿ«ý="ˆŽ lA?(AË.5¤óWâø)‰áô|îb )”σL’u}̼)É«ÕòÓ³×d >%õ‰VKþ´Ãû ÕR.‹¨íàÚ³½#R2єɕ É¡.tÄ ûÑeu˜Ù÷蔎?ÎÀÑMƒ$~Â×1Õ”ØÀÕ··úü'U-÷—-ˆ¯öM>Pþ¸EÙÝ x\Ø\Û¢ӳΠÈüñ——®\/Míð×gG<Ÿ¿È'ûanÏ2ùãB6ElKüp/OˆÙnÁß 0"z¾)–ý4©%i.9)VTô¶•Î'q-:ÌKσ<Ù‰uËŒ¬xÝêJåƒH§ó–ËêÛÛ©Ž•[ÌGHÏuŬS,d.·d£—H=έ1ÁО^zþÈ>¶n‰ÜøŸåÁÉÚKöÝ!™ –1)üt<Þê(©a0M£¶¼ã*zP(¢®K²‹§e¸C!¨þÝÜfýw­ Zè–Ä¥SÌpÄwùÜênK2\ìßBœÚ鈛…ª¿¾‡R‹Rʼnâ<$»{=ŸÓIÿFqêÛÄAß­ã»>N°Ç ŽM«8V2÷}ú>Ú+Øtù–Tñã0úÀÇÕ&Ú¤»ÑS<„';ß&hÛÍЪ-²*Оy7+ pªmæ´9ùYõ´*éÌø¼ÂèÜTW»®è™¾Ž(kR‘X[k*l"¡¶|uêémÎnº\ìã *+ç6V—…ÌÑÛÑmÜÝó Œ }Ѩ+¨«]c¾Ú‚Êz—|Q¢Â/óɵ‰_~ñKæM² ’ÒšˆöTHË¦Ž«¡‚]ÛîŒJ‘XÝár©L¡øTH_W¸91…â[Ï…LHѦ¾RÁ|²iɹÊ×boë±·k©ò}29‘ï}(µveê(Õ:Uàj+We'FX¹–ãHzϲ¸=ûÒš»!{ºÕµòz¬Å“9{}1Ì—Žw]ëZi¾ÛàÀodé*Þ± ÊñH‹9=yW@“Rý19Jˆ*üÝåðÉÏ ýTÖ¾Nc³:Øa°g‡¶?q¦6ÕÀþÈŽ .½^2¥ÙR.Ãĺ„wñˆZ%¨ôÝùQêÜË·(kvX;,aAÅ"²¶ÕDbXðU‰äDi–Ë WÐjÑýˆË ؃8Æ3Ö›Žc“AVÇ䨆²^,¹"»¶Gï^¶d¹¯Að^ž3c{,ìP,ä«7ØÐƒÆ¶­vÓèƒÉ¯ÁÀ‹æ$w)䙬;‘ ¤îÀç–Ì 5µ&ÚÔ¨Þ¢> U€¤æ’ì·±³7|$=nKr^CL#ÚíבP"ØB‹}¸çP“[+¾gÇQdæý`Û\`G,\¢Á¥ónÎò²¥\^ZÊoÏó8„[0Ú3ÒF<¿ÞÏš%·Ÿ-ùãR¡lfzûWå”Ñ-$ɱÒj‚”–Z¸ÞÍÉ ‚C‘2·eömÿÄ]Bf¾ú² B/ò;Šg[ïêʵí´ô]&³|€%;»M„4Úr)ƒ,Ó—z¬Å‘é8{(x¤V’ú%º¾}Q‰$c4s\‰.mS#[{èT¯¯v½õÕ®µ¾:µÖW·ŽúêÔ[_ZëkµV¶µZÙÖ‡£êµß­·ö»µ–p£ÖÞºYµ¨ò̳\Gõ¯*ŸyŒ«?¶l«³ +õÖ[-“ìZõÖ®·Þ:õÒuë¥[­—n­^ºZæ¶õ&:IÍ­ºQ/Ýfõ¶ÑD½ÕÛ}Û˵NJm2ÇíW+2W&x†`)kD8:ÔÂCŽ:‡5ðÐ ÕCTSŽÚuå¨ó<¡KÔ®©ÍÚ5ÕP{¹¦"D5娮^Ô^©©Í:5µY§¦ütkÊO·¦ülÔ”Ÿšò³YS~6±W@‰ІtŽ GZ:²TEËæŸ¤e%;T=€ZY XјÀÔ*,Y˜;önàÎÎ59*,% ƒ”Ú&)µó Ò ×»‰›HKÙoS éDAž¼Uÿ´“1fÓ'…µ¦£È*&ú¸¡½¦;wBtM``x†)`¢5ÞÀÅ9+¢Î(=V@#\2½àpp¿|¬Hûa‹£¸2ZEtÞăºYça‘˜üÎÆÍ;àÉÖº¢‘,¿)¿wì(ÔÅÇÑúÒ.N3º|ŸyΔôüháVÇd wöK8,É&MêA‘øˆV.•Û¹ƒjèàÈ­©3¡FÔWÎô Ÿøh!kËò™ŸÕ—Eòò«7k“ÃØ?ú¹Â‡onÔÁVÖ_9º¯‹æ«´»Hù(ìr¢ ù&6Iøòõµm»<‰M̸.†$²3ÀúqJš+ïQ‹­&#‡’k·ò~x¨Á‘y½[Õ'¯x;¨œ’ëä:|Ïœèðí´G#Dƒ¾UìÕ›ôÂ=¢ÜdÈ~rÔ{³Öñl¸×?¼ù¢€ ù«@è l×™ÚÑX“l/ò©(÷XQRÖ_%žR{ŠX¿Š‚Ûá€QH.e7Ф{ ’L<,f ŠŠpžbÚɦÊ«òüeÚè7i°Y9­0pˆ@²t†ó”ÏR|â¸_@䈪Êí9²AìÀ¾Tö`>EÝPCÒùm_l·“2özÈf÷9è%{j·]ûŠü+¸ý1eŠ«J µ[V­’lIµFíÎlK“øç›hLÏuÅÚTìääxô¶ô f«>fŸ-¾:¹CcXN-2ÝøEsÙN\Ûóþõlà ƒXÖÐ@©¬«…°<':]Ü´ör&¦u¯Ä˸äärì½ð!BzbMÉÞQj"2-òMìÓù„ÏkpQÔâH¹·w´ÀÉ+v® Õ #yîZ>9§—Ä+CçÇFRZŽÆµ+\Ýý½ÁD«œv³ù&ôoj§¬Ðê¯æŸ{ÔdtšÊw»Ù|w›Êw§Ù|¯GzùFH˜›!š!n7•cú4ù÷ˆÏ“‡Ù&éµ×æÑìD?ÔeŒ€‚æŽ8Q•ÃãMcl²K.ÇÚ<̶°KÖãR¬TTâ…¥umCÈMÑÒÖšxþÁBÁ…·àùG ¦²G̓9ƒùÊ£S*'ž±µJ%Àt&ƒ´…´¤øÔ(¿j*[ô<)JLÚ©ò†‡¤Îm„g],Bgn™8ÌI¾Ö܃´R²n RŠ@‰"l9(2PïûÂÌY®3‡úàˆ%JÔ¥3ƒkïf­,ÖH”€AìEo¿C<xÐ ¶ÛÚëY "¹}¢âÛNqìVÂë¬qÌ©I0²é±CkKAIª¿‰ ñÁç—ñ«×ªm¼‹C¯Iïrjum#L ±=‹íè©›vvîèÌñÜ7ê†÷à5=T´žìjŸŒÀÞ1qGKôÅñ±v Å–èðãoú0&-뜹7_7á|Ì^6ã¿þ”#@Ÿ>³–þý‘7=#bêÓGúÄ'yè¸Á¼SSq¢ ‘“ŽædÙ÷;wçv‚’Ó'nüÕ®ë̾ÅñÀ/KxÑÁÝÌVç0ãÒ-›ÃÿT£?ø5Á¥ãÂYf 0Èî‚~j‰¾, è$¿`ß#„¥S¹Ù¿ ™:]ñämG)z3‰-›(@(e]û2”ˆñ‰_I¥°>%j é’\Ï|{ä€à¡ÃnìñÂÉ‹€R˜z—Î|ïöÚ80$BÆ«›ÌµDÂ’ !Ô~˜Ûsñjl ŒRÚD|›,drc?FÈ.éÀEÌ¡åÿeÈÆ]Ñ šz¡syÇ>pWS)§“lÑȱÆc:Gn-¾)– ("%%‘ˆ¹VÄ¿*¿q\w@†Î•í&»Õdþܶ˜Rp‹ý³T$B>Ùýé]ͤ٠%Núý¯á«“y˜|We“'$œ?Å`Š÷–1âcݪ^ŠüjË Ÿü‰ït“έݹO”£;é¾²÷Þr\h%xsíþ$  Á™o6 ÒWÁQ”–pMTˆñoúç'»ü"Ë–œŸQ°ÄjÖÄá QSðZG¶Ëò/Bð`42íõBišv:¹7(Dσ˜1NÖ’÷Àì¼òšÌ~d^‹Þ²î!HØÿçÅþ³Þ ÿj¸ûòìlÿÅî›áÁÉÙqo°¦€}ýk'¼–ËÒέËÈ¿rqíC@ÐOቈÌÍ£hcñƒŒ¼·‘}5œÒè¤\챫¿Ð!ß=Q>0“ÌÆ,à% ļÖB±«Ãœóý¡GѲ¡CÄêÚHW  YçkŠZÙ#ÝÖD9…«A9ŘúüƒÑÖèIð*‡¥í»‡½Ïöu` ô‡,ðýé,rË+Yƒ¦@Z (×J‘úAŠôDý BQ}Ÿ2o‘BѤ<ÓÛÑÉ[}Š·çÊ&Zu—PoŸºúî hu}wiö«]$²hxvâùe`OÙùö‘YxKœdÔ#—&öرø½éÒ–Nwë`î‚«}Ûž žNT_UàË(HïW KT§¨À¢Vªþ¾cÊoßß*P•inÿw%n® ­ú5r)òÆÈxopK*MzA)µ‡N³íC˜-¨}b/ ª»ÎÂZ©Ût+‘¢\6–€äš²ÙrtSŽöpÔl9VSŽNÓåX[L9ºM—c}1åXmºÑ»€rÄ3±ÕàüÈÜ—5[_›ÃÑ"Ú}­ÉšŠ¼¿,¢ dœ4\•Åd£ñi/¦ ›„,"W‹Ø;,7Þ·º *ÉJã%Y]PIÚ÷®µ•¤ÓxIÖT’nã½kcA%Ym¼$› *Iã |{yA%Yo¼$+ *ÉFÓ½«Ý^PI6/É‚ÖxèÅ —dAk|{¥ñ’,h'½¸éÞµ 5žôâ¦K² 5zqÃ%Yн¸á’,h'½¸áÞÕYÐOz±3ªæO#h<öÊÑ^@9: (Ggåè. ](ÇמF*^P³ Tyr¿Œ¿L4kåSF 2çÛ¡–1Göe‡©i’¾ÑÜ·›Í=m†µÓŸ1N\ùò7›ÿvÃù§õ?¨‘?®ôúIÈi»‰œ6R§&rJ×È¿ÕH:ðfÒ´×wsùn7˜oÚ3ÞÖË-OuÍ‘7˜óv“9§u^EA/ã\±>20:;<ß¡FØ3ϵB/RÚŽŒÂœø'pR—’…ÌD¶Û:¸*i&¿Ú¿°§cò³VÒ±ñ´7¹p¦‘¡6iîÇS ûý,cœ¶Y=ß¶ZÑ[ù"ÁüêÊB{L›¡1eõÈö»ÿù2_„üëI%¦Ö*©kú~ êj`j].›øíÏ+ÆË¢ `ć¨*1êr¦Ó}Ñ'^©¨ÊuL"*¸ ô&'L¬… r€c>n}ûÃMDÂÞxl 2MŠÄ,pN.Ï€ù#Øðª)€)Ø×¢Ô¡ëÀ£r+˜|Ôñi…—LcɤºEþ™_ìXþÝÒy,óM%¶ŒôϦÖÄ>¨B™hBÿ½ M|‰•ù)?€w=ôR$ÂaC‰pµ¦QSuÓ ¡ÿGãu«€5Y’öâJÒn¶$Å•¤Ó\IxLôæG`»Ù2´‡Îuƒ-™\56“È#’NÃíÒYDßjp|0ƒˆ”¡;-¦·Ô±: Jga·¨­.(µáèÇ*éäÍİ1n†8¨¸ãÎ\CÔÈFòv^êHNŠŒ#š&[íèçç¹gvdÎ2pÉm6ë‘¥¿èëÁ \îíè1]Xí’±xJ½o0OAz#îcܘxÑÆ®Å×ôÐcÀÉèü›©IjÓO-rô¾©»öÞ“« QîC%¤ïÝÄ-h E9á” à!6ص|;Ä9XÏë—7 NX%›BõSûÖÕÚI«š„ßÁB©shHÒGÒû òKõØ€@Yž¨à§eÁåstF?R‡¦|éë¾)Ñ|ÎUyÁQ˪.“ nƒ5QŸÎòÇYß[Üé e÷÷¹¿<ÒaÉÜÝ­é “½Ã3XÁòÜÓʼuË[ÊÇ×å’ÕÇž•Éd댢' è$ƶigÓ¬ûÜ®¾¡•sáÖýï&?ÌÒqÂûäÊÐy]3=õMx_ÕÌË=LüwÝÙM_ kN íM¢Qþv3õÞnºÞÛ ×{§ázï6Sï¦ë½Óp½¯6Ì¿Ö0ÿúpÔD»v›n×nÃõ²ÑðxÚ¬¿‚äyx¹™†U: ©³aã·¼f«g¥éúoh¡Z[Lý·›®ÿNÓ t›N`µéÖšN ¡¹}1]´ñ´Ñt›ÃÑ/©Æ5§s©v¼®½ÌN#¼dÊ|£Ã‹®h8W7ÄLÎÜ?5ÂL3Ýuc¹n7—kúˆÖH+¶ëÍå¹ÓXž;å¹ÛXž»åy£±}Lè¶r¾ßÆ3džÊ~IÃ÷̬‘Ýų$OfI{óÐö÷¼Ñ|µ‡Œ±0é²{±!ó¿Eðkx’³ýs;œÏhàCÈòP¤)¿ªËÀ_˳‰Ï'f×›†9rú­ÔçN)"¬\‘þ5ðõF£ öœÅÐÏÉd¯‰P… Î rLG³ëá¹ë¹Ôw–[7ŠZ‚F«¿ÞBã3®ƒ†&£ì‰O¹êß#‹‘WµJ6"ok£…03çt¢fQúùµ‘¼2^84Ôq@;Ù&š6­Ébˆ$½ê#Aß93S²)4 %(ŒäW ÙŠþͬÚú²¿EšÛyΣÝHbió•¤Ò^H*ÕÂPWÛ·Ùö‹©¯îBRYm²UH“_4B^²Ý¨+ÿÝEöªÎBÚ{m!©¬£}¼Wª¸ÅLCg©læ:òêbÚ£ÝT2iugɬ,¦4ø˜:Šd•¥áTÏ0¼ã1“64™ñ7›ÿ͆óOßAÌk¾º¨‚øjïÊõ.âsÀÖ‘„'3Û§ŸÀTbÈF|Á¾ï{þïg/_ìöû{ÃÝÃÞÙðàäå‹=4¡â»žäªg«7u&d€|kÊÌáàžAPðíÀ›û#ûØšZW¶¨_Æóý6 WöTÄ'6 ;ؼ F)ôô|à{“å'öOx 8¾E>þ(ƒ_;3»ÿ»§ø^Íð˱ãÛ4Üëeïú¨Wªû竼ŸíÉìÚ ÈÙt¬vû“S::âbTçŸÆ‘'Rí<©¨3Ĥç ,¢¼+ÈܼJƒjëxÚœ ù³ÆLæÜÚLèäì=òz¥á˜ä²l¡\gôŽ›Ý>5ÀKM°&ûê²è€ ¤ý··5Ç_nãa¾ýÿóö¦ëqÛJèwflkßeÙŽ}9Yín²W9›6GJ¬XÇ’í8sæp¨nJâ Õì!»ekÞàþºOrßñ¢° ’ ‰ö÷%V¨*v PË¥{eé[L’W·³#ûÒòh#(йÃ@=8ÛE ªçcò«ôpìøÖ7ù8Á¯åƒà'YšùÈfãQ9¬p‚g6‹c^_Xfš„›IÒ(~ç; Åö5ÒläÃ{ÖÐ2GÛÖ…yee…âHáN>ÒŽ;&[wAŒó»•VÄ@eÔò1Ðvã…EC8—êÃÞuϱØ0Ñ%áŸxfÝKLËôÉY@V~”?·®,ÏìÒ(¾Ô Œ"]ìÿðÊtЬKÖ ÿËå±å÷Å0ƒTŒÜ‘Gî™No ¾$ñ¹i¯è -<ˆ¬ÿs‰Îô.´/¸‰b¾ëćEZÒú«PÃÆÃÞ÷e³Ønâ‘ñõw‰"ͱoµ‹írAê2«;üRf]òѱ¦Vd”ÀBö¨ãhYh´ ËLï/ðýé]âK—è]»žûÖó1ïLßæã„J?äg˜ónË`3=Ñ fʺ_D$ónB/™.üN"Lï½ öö]™Ͱg!å©yíŽGU9¤‚Ú§ ¡È+¼Ä¸KiàõYìðð‘…ªÛpÇI¹)xzΔäóD0õ(ÁE+úÅQ,‹NA¢ ør…\‰•.!+Œ*B Qz‰ÖÀ+tCÝs{è[èß¿§„ aß3ßlJÀ@Œs†xyŠSd"=.‚º0¸_¥â‚¾# @ÿ­Ñ1ZÚ% _K@’b)eiÈ×2êHÆZ¶Ý·ß¦ÂûQÊÇ¡^cñÒ kM«ßÍÅ=³#¸#,¯¼²ˆðÞ[˜+1ÙßC<ºÞˆ‰=vLÇÙÂ7 &i{”Lj%3æ³ ×¶é= ~}“^´Ž<÷ŠhýX£Ï¨ê|Áûy2`~Ê È‰f-4Ù‡‰ç*yœÏŸ8ýÀkvò„}Lý"Q¶L´L:BÙÔý¨ õ¹ÂÆGäÏ×Â<¡œøïBPÏr¬+Þ™¯ˆöœXr»ô|ïéÞË­ßOŒã“×O÷Ž qù¶í™ÃÑØ#)_ Ìöòû jD%ÓÚr˜‰siM/<›>‘CÈÓlúU– {Lff(f&%pI}¤”,"¨ªÊšÑ;Q@*¡p¬€hÜ¥Œršè­ªuÕ}¬·†ÑûSyC[y¯èè醺Ölªîi]Ýln©æ­¡Ž·¶jÞPGÊ”X]ÄÞtKSóRÓ”ò¦)åMWÊ›®”·†RÞbeyjÜÒ.Vö(G*ôšG*q¹.…'6ƒåðxs V:`t¯J™\ÀèBe‰,S&Rt+ˆ-íHOñ ¤ÿKžBèS ZžË“/ïùGOú™ W¿Ÿû›'¶c=ól6Ýž›¢éwbÂÂ’±<ËÇ*´<ʧùú.LËPþs×±ZÒÐÔ5yóè¶$.V|<¡!“¸>}'Þ”ºÐ=‰6þ|G3ï:µ)EƒÌ¢¬Hü¸Ãí¨Ç4äÓ>s{×-@‚ :ìSç##»©üP˜»×CÓð9"2ö,Ô´ -ÎÝ…'+Bõ8¯D$q9<¬D.þ6¬š&Ô4-Ø^šÚöÒ”¶—®”ZC)5t¿©ÞúºÚÖWÛ^-¥£µ­”ZGEë7 ûDaë'…õìV ¿Õš„1·*I,dM¡æD)®”ðÓRÇOå…Æ©ò^ÓTŒ%mSmB*'M]íDUÞ«Vej™ñ‹•êËÒ2˜¡Ç$ó‰Ûû%øÕÊ‚ E€d½²Xg·åÐ’C]ýá7y3ÁƒÓåZ ö­çcÈÁÇqB¡v'X,Ó–¨‹}yê:`Žæ§D¤ˆcä Á»ù$ÎX'äŠà“…Ó P,#°nŸ¢Ö’{hQu£÷¼•9Ðo•*•+£%¾~m0tÅ~ª¬ÁT6•®°©†½]‘•‰H“ˆhH)è6]ý8×v^Sa絪uU?TÓyj措;OWØym…´:F¯êÌÓ„]Jtž^}ÐÕ÷\Cakw«-æ‰HÞꈉýàÈ7•”JL¾FàÌ¢€Š¯€Š¦„M /º^t%¼4”ðÒPÂKS /M%¼´”ðÒJ‰s(A%ÃU’,¶/u]ÉÚ%o<™$_å“è»ø"+ )V{@2M ÅNšâÐñØREQÄ2¼8ŠŒÇ¤lTÎÏ™^jŽ­QÌIM"¥SÀ8(áUDôÞ?s¡I*ŠzÂUÊâ3—à¿Æ<Ö˜WÖ1¸%ÄthhÃÐÍqî¡ÙD¨kOÝm÷-hs‚Tb¯o\OqC ûÿüMI *ˆüª„ì&S Þ¹°z!t<-øZlBõUB(Šjæ@ŠåPs°bB¨ŸrÀó$P­üñÓ¹ÅÒ%Ÿž¾/…Mo”OK!§H˜öJÖ#*[R@E«Ò*šÑ{¢ UÔ´‡®¤=UÚC|ã”@ލ0•/1¯n”jJz¥©¤WZUZ¥Y½WP[”/¿U½|½Jùíêå7ª”ß©^~³Jù]•³BW2+ÚJfE§ì¬ Ê U{ ìrû1ïä"²v?™CH&¾_ _«X¾V±|½bùzÅòËoT,¿Y±üfÅò[ËoU,¿]±üvÅò;Ëï¤ø•ÊÄg©Rx~(K/¦êV•üeÞ > 9@±rQð%3ùS1±ºO!.*èO³Ü<Î"¨bá@ããÛ}ËeÌpr”ç46ÚííÁùo…½â„E<æ‹xhúº4Ç=Ó±úà¤ú†éû_g#ò9õ4Ç#öû‰íù£'P!nBÃCíz ‚e8£¯óÑè ‘ õo²@Ÿ[olâ__8ܦŸ^,ÿ©kö-ÒúÄ™¼”7 ¸GS³C9­Ñ“(‡â¨xPÇ%Ê2`°x0ì®úÁò Â"æõï9(,N\É$u>@4˜WÖ`ßî÷­§*%‹ ÍR1€]ßdCú0%ݾU6\øSañbÃ-ü9€á[Njûrfë#p±80mç8(¦v¨+™·†!ÈÓ(zÎÄWòî³SXT%Z# W(ºeKg=Lè^^Ú£Ð}Æ#YÄKËôÇӭˇO¨B~*1¾?ÉÑ9 *däËu5î7²R ­úö•µ%‡K Ü_€‡}æáËV½À@#ãëk9 -ë]IâîØéo[ɰ~¹Ãa bºH>zð$ãÀ¶³5è®ä¡çX怵‚dÕLðþw⢵=ˆ®ðƒ& ‰Ö‡˜h<ö÷Òå¾´™ òÖÀò|y¦÷°'~€ùS¦%_?^ø²3„K¢Yôi“=•Cï[¾}>x “ÂÀSƒ®L×9±1„Ĉ'”~”‘_%ÇÊG{÷~\´ùæDã•¶ÍìÖ¸o»8>ß^áõà ‹u¤^»Å©àF„ȳDb ½×ŠéA`4íѳJi·ã~ÉÂàú)ErïÆ» êÑc´M@ø˜m´‚=)ÎZÍ0žƒHÁ•Ú)NÐSûµSáé;Bê—â¤ØÑM`!‚œç‚wåK®°/º˜ÅÉ0_âR`}&ðfèXr3à0”\xdKõ¡^¯éíz£Þ"(›CI¨dD]š}‹ˆòG[pvüV ô99,6rσ]01ð™Ý2~0·2¨FÂp%/Š'@é•=è»oq¿Ì,шtÇ%#篚dIA«khÛoJ¢zàãLT þ“$ñžãúYôžc÷þ¢ûåÏ’øPÖº,—.:œìºo•¢/JàÇR^ )z#^\༌~P¤–Rߊ¡uäÊê÷·¢x¾4büJøXlš„êI¶ŒpŽR±„uE¦³;|1ÄÇÅGáÏ÷Ó@Ј´Ê¸b‹Uޣžõ| {Ò8NöY.,ÖãÛÎGÌÓÍû¡‰Äaò{ì@|}ú!ÅåJC6bX×­«cÇôvÑùøÂD9â@ÈÒ432£¡ Õ- ÕMéZšDÄ$±r}ôêõÑTÕGâ%ÅŸ_q^ÇhU9j¨j]Áè+JÓx ’ôwÉ«ÌP³z7«ÕIƺ@rÆËÑR°ì´„6%Û)Ëľ\ u…´B-ï’UÕ2ÖTH«¥V»úÊÛVµÎ5ª-+L'±òÒÔ»W”¥A®I*i+ ÑQ@£[} ê úK ’fõÛºb¨´ª\*: iu«M)|h­©\SõjÄd ÞK«‹ý»gÔªBÒô*³æý´ç>¾*ïåÊi¡kæ¢T|T4%¼h)–ÕT2,«e±SüËŰAÿà!%¹b~ ï ‡ÀM‹#É GˆÇ1NÄ.,¶¤‡þñŠ¢È‰N±KÃàñ© *£YãÐô±Fq ,ÉžÇX€ðœjmG’k9N~,Ùr<†Üè‘g¤ {Š¢øâ×>1JšÅm*¸\ï‡OLA5J`É­,ý@Ä&¹²prmÅdî’m€§xôŒNwí«4žBX¹UjtÊÖAy`¹öîà “%Ù¸ÜøÇïjÙÞ$2Q$ëàƒ¡Y\²œ-}EQäV#„Â/z1Ps\¾ÄC‚ŒŽlXÏ©›ŒD?q½K0è ¡÷†yÂ(J¡ |³(}ìsAàáxhCx13˜û ™x®ù2>|ªidŠŸi~ÌFÊ{¢éȢǵ™¿ÎFôqjò<ý}^,´d˜J/Ê#k†]ÏFBèe ²0ü\Œ ¸Ÿtq TÆÍÏz‰ ^•“TÍ9¸4Ï­GøßÏS2O±+]PäÛP¨¨-ÌçY`L1PUöž €œ,˜Ð„‚‚‘ÃfΫxˆÃãM6 Þ¨Þw1T§)àœ™‘äÂø"!s\õ·û| ¶%ƒ õ™èгûÒ˜Þõ~àØYX¨•~e÷Gb ¬XD÷³؈]N>PR6 t麤¬ˆó ˆÀÌ&™Iñaó‘ 4fÚØycíÇvFðоÑãI0cŒJ©‰@SÕÆâÀ¥¥´IÅolµTÂT-wô?Æ&ès‰UÍ¢hoíZÝœ—ˆ—òc6ì6sÐmø¢çhÃv÷<ÏõRUp2PQÜ{–ï§* eࢋSÿš">ÌmøˆÖÎIü!ç@kgí€bÿ`ß VIªZ™‘·SšèÈôðjî\EKsl!Š‚×?,M{ì[/mo4fV¨¾Bj SšÞ5#ôvLt`þ£4A®»{žë8L‡—΢ŸK¦†r¿–o¸¸ÎÑAiR‘ ' úÖÛ­ÑÓ*”‚!F‰íWgk„¤þY;ôre>Î(ó¡é?­Îïs Ìù,okôªÂÀ£ TpÅ‚; £|R™.±;|iûh¦ì‘ Ît©`…ø¤Ý_V.Ët·/íye²gž%YS2©Xˆ‚èÅóq|øÊd(=UÄ ÞÉþG1ý…,q¡N¬t¼2&FœÈþ{bôA!;yÜáЂ+÷û‹L@ìdD|nN‚ ¯‚<˜à»)‰ 8›~—Ï'€-í‹,“ÅlENnI9ÃïãK˳{Ç#kˆNµ'ÖÛÑÁ`8Æux”‘÷S1J a[§~¸3ìC”ÆeÁ·þÀêïÅÐód{eÉ%ŽE¥D…r@Lùl¤Z´“ªfØÿ3ÑLw}Ò¼kFoÝûÜî]€ûd°‡±”8«˜¨6Cyäâ Îé9{Õ+‡X¢Ä@Û¡¢_xY‹kATA/^_?xK.‡(ÖÅÉB¡/n¿­€-v¥—…ùW£,8øÀ•0ê%Ztä4öÒ‚]÷Q2é·¢$B÷DI-À¸Èˆò´kpN$™eQQ#l•­Â}Š©ì¥Ð·Î̱3:4ÿv-t°àBÑV âW bp §•<‘Kž… ØaàˆBØ‘¨F Tí¡·ÞÚ~¹ÚØ~l±ö³³3ðàx®€Fè>QžÆ¹9äÜ à ýtÀ³Âɳ0´°Þ*™Ð…Iù©VQd´x[Þ¨0ñ/tsÛq{ýRv ³ýðÜve:; Þ)Mg€ùØq‡×»eiô2ãf¯4¨£òKùÍ Ú–‘ñË7/îÚ€NéÍò Ý;/ŽÈ%Ò¿YxŒB¤½(*³]|@÷­·ÏÎ*´Æ? >*J§O»ö¥5À—õn‰…Hr§]§cÛnl< ;E±F.ñ +°HçÜÜ¥Z¤Ï_qˆêù4bßz>†Œyz'»lç—PaŠ“Kk~(RvB&r,ƒMo³±Œ"æÒ43,̋ћzª›ØÂ\šDÄÂ|žw¡õkª<í¤+ Ñ0ì*U:qÏÏ+Е{œOÊ0 úGà›úQÁ’ß—Æ}6Un‡fõ1§ Ͱ¥IȘa¨S®v9Z 榮jnн%â¥!4,ÙgY&áåZ[WØsê=×4z¿+é¹@*^yÞ¶ª±$04¬ÚH-a(1ùFêycð«W¯Þ]m¡Ñ«üàN·#/FCS@C¯Þ£÷K•Ýût%=Ó”Ù«®ÛáZ%°ÐÞ¶[é,-ödÙgcÇAãϲÑ­ù‡òȈÿªýÖÚ—^u4¡-±4¹<[âDÃdoÍ)ö»E©ø ¨hJxÑ”ð¢+áEWÂKC /”w *p%’¼.¦aW)[¯T¶^©ìf¥²›)¡’r±ñ2åeV•¼_9qF ‰J‰-’ Ç­~–õp&Šø½4ú¯æ.Ë!Š­|㈹V¾b›åu¤ÍU¨Vè<9 +¾ÙBaeÐäj»uKÖ,Ž%¶ÅaYزç:~Š-~’Ø‚7ŽäÓ“vŠo*¸Øä.>Â#„Ÿ^ŠÉ]†Ü\åE«’sõ*@Ed —@a'Òƒ¾tx°ær%d¹2ÂÙ8¨Ì_Rw£Ö“¼a­ ëÇBtbèv!ôP"½SO,Yþ¾XDôÃBÈyÒñý’Ôòî× Eír0Äú唩 º¯œpR†Ò;U^HBiN é£Ê — Mª“á‹ ·ÐÑn#}â½Ð˜T/ Öÿ5Á©†Ú^=ß4tõ$ùFƒó¿ ‘—Ÿ±°OLŒ¶?1ÚÚùÖ&È·>A¾õ òݘ ßX¢r¬6óe§œ¦øN—AÓô¹ñ¡œßŒ»F…F@-l:ïf|èè^úªuÙ1 ‹èDèú¡«Mˆ_|/:QB—[B9= ‰N€Smœj)¯)©DƒEq$TR·(\ p•Ä,[¦VºL-å­83qº/ìNX(Ss`_âÔ&¼tBÜÑGñã[µ\0î˜ú*ýHF:»ºÚ–DbÚaÔ» v#8îÝý ¿›’ä‰[ŽÀyw.ŒêoO¹¨$¼.ñâR•ó¤`ã³£¶\jX씢Ý7’Š;i¤8j8MsQ/"N•¸iZ•ùXÓ½‚WáHUKãè(ê‚éØ3«¾Ý£Ž´ìž…/V*È„J5¹dl?BÆì]6b#¾-I.îglS/îUl³h‘¡O®VQTb<µ«4õ÷TzNqzça×]Ï<B©>©@Œ èzPÌs´ë<³…a»%>¾í~9}wŒ†ÚNf \¹ ðb·Yt±´FT$2 â·Ã®|"'l W{”–ñ}2B TäL µT¬÷HE¸FÛ­åíº½ñeú¹FUùYù᥅îÔàða¨‘´(XŸxfï/b ˜Hú½½DüR‰\ØGÿS‰N¨lœÈc²®O¬€„˜ÇžXQ1‘Ï»*I‰ UööîúG{g­¦¿³’“î]äJU5jËSâJ©’\¨œâ÷p—xLíÞÀÁº SwKJ¬½ŸB@üAø›ºaÿP¢œpQþ¾öXÖs»^ d_pŸ’@zp(µ—@…« ÛüVªXæt·;<–ƒS†ÿ®@+¿c*A}DÑ9'SåðÅÂ¥mìõ tˆM›Å§¤ý(‡ÉÅ-Á>zw.l§ïYƒvQtêbz«(^B}²%G!=¬ jà¥d½+`)<‘Ñ„‹×çîh–GÜoMéÌö|>f’ J*ˆêçÃQ‰P •ÎUà­¬-3_î„®†Kቂ¡¤âIÏ6/Uº§¤š~£ è*Ô,ˆ´m¹^Ò½nÆ8ô7¥¡Ï= ³÷¸*a²]ˆÉßÑÖòGOOövK•âcÆ÷*)ÚÎñ!?‰§&½ üïnßÒ âl9N«à£S°U°$Š&? 8$ùY€]Q¬ %uQ´´åyæõNà“»V€FÍn”+ ñˆÿèÊ£õ¢Òè’˜¡B¡ ¦ç¾ ,ƒ#É ±Î ë»u……tÇT…ex"_eb¯Ï¢oXè@„ÈoîÁ†j÷Ñ¿g¡Oë×Âû%öOBì1%†ö ž9¹7¾DŠVâšôP+¼ôlÊ€‹uÅvePó4½~*F$qL}"‡½h$-oŽ*’IHÅžU$WwRJO3lí¦©n7Mq»éŠÛ­¡¦ÝtÕí¦+n·¦bz-ÅôÚBŸ9…û¡¡ºŠëÙQ<~»Õ+]—jj:¢iØ/•vD ’«¶ºuÕí§h!nM¦ý4Õí§«&ØPM°©š`K5AEk_{2CFywTìªi¿ÎdÚOõ€ÖjŠ—, ­¿T­8õw C'·CSâ9•¡„®O¿*¡„™REJWš:®°ú«’V×”õŸ¦¬¥´š²–B¤”q¥nTiueý§+ë?]O e<5”ñÔQÆSGO]eÐ&ÑjëÙPJ­©¢ÕPÓÿZ‰HÄpµ:?Iô¢®´Ý[J©µ…¡KWXí4ï¶Bj]î>@šjÛK«J.®ùh«$WW˦b†¶Ô­š0†k‚Tn£§D·*AH÷¥(!ü¨¯„Ž~ºŠøér§é‚tbž « õDâàâH¡xÎp)ñ>peû(5g«<ÍsUW¤àW¢@-Ê+O!ñdÛˆ˜pEíî‰!— í‹\$ü.Š8øU$^‚"ŸZ.|ââòM.Jxmi犫¶rñò.;Û˜›’Hz¶* ­: ½:‰†a7rIô£õÓÉe#ù2Hö DIq$TÒ×¹H#X瀾,¨UJ×dAS‚ÓEAËwQ”bÞ¹Ç#‹Óω~þZšNb©Ø)M*\BöJÓœµ ZÇ•©`w5¨Á/mæ)°|íHÐ?èçÊ4|Qè¢uƒ-¢Yœ¸T¦eDÓ™ÜèT9a‰¸kU‹È»¦´aÜ5í.DnÿŒ¸kJÛHŸx Qü2½€Xï+',Äñzí“ú±*ekA‹C]»Ô'ÑŸÀ·6Y¾µIð “¶þ®Vmâsµ9ñ5¹5‰QõÎÖäɯ˜í‰÷BgR½ ¿«^hL¼º†}:áPmRÝÐxWÝМÄI4a&?é"´*Î0{úm  ÀIPþ«| ™Ì‹ƒ\*¢íOŒ¶6A¾µj—åSrêÕ®“”Fu>4|ToMA{h ÚCSК‚ö䇮 =tí¡+h†‚öh(h†‚öh)öèÅDIÇ8 ¥Ø&¶%¡å·,¥„DT)ÄÕß…ÞïŽÜ7 ø6,R <…Wõ•‡I>4ý2 Äÿ~“¾ˆ€ÿ¾ƒÁ·Ò°ÏÆ¢—]t)µ¢ý(%}[žuÞ Y/ml:{–îÿQ„ó¯!ˆ¬=–'œèQWü†œ†ë[Ô gzˆÙU'‚8ù(†ÆR~Dÿ~“ `:Žûæ%H¿_yäAVVäÜ=€¼àY[½žåûö©íØ£ëo%PÄh«ß·ú%Ÿcÿ¬ý–8¬Ë$>´3¨e[_§¢‘c¸êÛ×Ç#k¸+UñÈ»–qŠÿ@Œ$úÄ C$ö —$R— ò—u]ã |è0 M# ´ôXÅ¿öGÖ% Óô겊[“Áåcú$‡Çïh–zvºjˆð¢Ÿ<ðS´lBÀÀ‘«pZÄ.Í·öåø{|õÚ·y¸¨†Çh†pªÃéÀÖ¬1÷8g™lí\˜ž_ Ø83ã73¢výd<豆*…'òâ+ÄC}î[|qeÐ|‰î´/­C·oIu=ƒ)£ÄasÆMy =ü`yä¹(yd[¾.,­Íb8t…ý2wDÓ8í–#Mѹ¤É#£òðò\ÏCI,åíüBÈi„´6X“ †ãdT”T<Óé0ưû–OØÜ–E6‡C皪EçLG¾q¢«y· b¸¨ÿ,Ë5Ä¡LX¤DÕ‹ˆ1Ñ.0(øMâIôÄÓð"ãz‹ž¯¨i˜(ñûâd`¢ïaøŽ¿²Wžu‚Tv«3²ÅT[Ê6 ÁÎÙ[%è ñõk™âƒf^Y8FžÕ[9·ØL`'ŒO ì_{e($4sÞ7"Æ‘;|1Üô.à¾äýX¦Œp³úµ ºX𤠩<ÝÀ×åˆÆ£š%ΞeïX!eöœÿ\!Mªæó/…$wѩ廎"Nž$ò‹h¨n Mä>©<É„®Ó)Qû¹‰ÑÖÔŽêˉBò°z¢Š^Eˆ†òNÄíÏe÷ÑTƒû?ösR‰€˜ÛÜ¡‚:pû¥I„¿ 6°;$Ü*`—-;ÐW®€]ºl¦Õ\ •ÁNHúPA¼|=´™û6³®±ˆþûñE.$6­èF½’»GËpÍ!õC(L½ñÆ3‡ßÉ › …Ë[þK@û’Ðø€%M›@‡Êëyдåÿà”×¥Q —òºx)¯9bÙ(—æpÛ]QwA ·DÆ‘k"^*äBW°9T2%:ÿÌöÁ¿ÉœPU ¼õ×Ũ¿ææ{Îp€‰,°¤Òヨ<ž¸ MÍú±Ä¬]=ÓDžøZõ}!>~Ï{3Œ|X9ï2¶_’Z¬îuABÌ3e*L†ÚsUÊÔ?g_9aÁ™øTy!–Õ›>ÏòBi Ú¤:¾˜pûgX^(m#}â½Ð˜T/ Öÿ5Á©&LT%O,#&Ê7œÿUˆ¼üŒ+K*¢íOŒ¶6A¾µ ò­Oo}‚|7&Èwƒóh „6€_å4}aàø š¦ç÷ûeÐ|±¯à4¦TU(!•Ų(U¸†‘èeQýÀa£,j\ðQ=¬3uqbë•=è»o¶Áí¹O¼Dˆ“¿’AÅ—§häàÍckD^¾¿¾Nƒð,Ǻ2áÀríX>'‰H‚‚ œhõCÝ…‡iÐÑ+{ƒ[ XJ†o?`E|û±„†Nß~’”o¿º‚o?ŽFÌUËa7¿W"RÄA—¹^ýŠRËö%Ù^Z¦( "²å$ùÑÕñ£¤}êøAU“™†E| ¥ ‰CCìÒÇ 2`屄†ŽÌ"‘@  ¶h,ˆ@Pó£N†@å7)t¦‡ˉ=Œ+¤åíU¢Å„:/*QnÎÇŽé…ÏÔu¡ã¿‚TS¢ìÊIŠ€p…®Š¿*âª.ô†W„öƒúšò„ˆ=O+QÂOStn‹7ÒÄ^Âq§Çü‡ÕÅ[åÉ/ÃÕæ ÕS—  ÒSCri ó€–¥Dé+-¹wè0Ä]aœ”0pqœ>ÜiaàÒP d8¥Bð¾Ü˜è «ì(â0${#œ¨0Žd]Ðfª7ÄH ÿ˜˜»°K¦…Kö´OW\Ùžàýy>Wæ $sŒËAJ>õM„+} L¤|•‡<ÎKB".¾Ìƒ<µM|T“ô%Êî9æåPŠK)E“©HB†Öé}ûÊö UiØÐC_:ì¥9òì·œ‡¾\Pn èRÜ2Xyº¯ Ð}-5º‡žå[Þ•µÅÆlA TÆçùãÍ6Ù'LHl€„íJ:ž§oÌQïý¶Fãá‹‘í¤óÍ"‘‘÷S1J‰+Y§~x;+X…ŒK×,ºšˆMÙÿ%ÊÞ~ÒŒ::WÞxbö­?'P ÐEGÅÉV@3z“â]›4ïúäx×'Í{cr¼7Ä’UI³;Þ$ئWöI4yäÊ<±vAc}nÛôí¹nš(‡#VI4Õ©=€ð–>ÞW¾/V@ô²Z¹øþ^aË!/±wá¹Äñl9Ä”7®,D"“ n¢UÐQéwR€ îü‰;F%|¡Öõæ‰yJ•“C µGÂÔ®,vâÄ¢Éb†g•ŸdQR¬$gChi¾^5JbŠ[ú%êÇQEgÍŸ¤±ÅÉ›Òø2!âSPþ:’ÆáœÀ‹òÙßKe#ÏWÿTFV`ôõeÄ™ S]+D6ž®4Y‰˜Ø2˜=šƒ“œ‰ùXU,þŠGœŽ}ëù‰Ùóm>N8m~Èθ‚=•Á¦Ã"оáý-8íü^Úsü‘‡vï>¾¾JršZrºZr á£a rÏñÃÜvZôŒ¿_Dä,¿S[Âjù4¢Ûbr3.<ÀÊûR¬ÐsßqHW AüÈG¸°œ!%_:4cɂƋ4%^\| ‚s›GQqœ“8Ї¦MJœ!¨ÜNà[ÿ;¶=‹6NA ñ)*ÑWñÃ}a?ûB"Œ$oJãËSPÃoW'cã;*@$~)JE^*#Y?ÿ¡Œ,“ ½RF1*ëhKÓ.Ö¥ð pé.Œã Ï«)8ñûILTæjN~’%Ö„²¨aåÏ÷4ÐÃÜ<yh-9q]‡0»2mhñáàýoò0¹ßsÜïŸòð²¢×‡Òrø¡vz:>Z¼Æ¦ÃוÅéh)qïçáe½ß*‚+Œ€žÛI#÷)8QÝ1}Øàq `®Êž{hM£^„v,Çynƒ:sø³-‹ÒÃGæ´ Œ„ödðüÂxاR‰ò^..0‚ÊG*XRP­âHáá6iä’òUæÕ›—C=ʆL$ðR‹˜Žšýe6±ðhÑÈÿ˜”§ÎþH†çÜ΃OJqâíñ} j]ydt Ï —ubó*y¡‹ë4ÈÀ׈œ=æ?D Ñ›¢©9ض Á£r$ý:÷¼±Hú,!¿¨F2%ýY5ª‰¹¿_^8ýßT#ž—Å©šÔgï \tBw&\LDL~>á˜phÒ•ŠH½¯VX\š¡’\¨Å”C®âìKˆÓ•Ò«>›ý@‹V !ñ p?PË›Ó%ÒÚr˜‰­&‡®\OäòÎ"¿Ê’ ™™¯o…I <|)%[O1Ü*QeM5oš:ÞtÕ¼éêxk¨æ­¡Ž·¦jÞšB1™ˆ`â4X /Œ†AÍ!’±p~}˜W9(øAJ>V‰MCf¾ÿïoF½¯÷-í¬Ó«ŸuV«Ñ7uô_Cë6ê]ýT¯jz¯®¶ºVÛ:ëÕZí†Ù­w:]­†pêmã ­ÇFŸú¿>FM.M“!{>!nq¬]÷Ò„-æùñSw’å |«‡.Š\yO ÜO=ô7¿aD!l)†nV8çUüNÛÆ<ñÿþMiEtUñãïÇQ;üWöÐ2àŸøðNÏ ÄÉÿHHGbÞ´@6gö˜@ÐÚµ`sv½GiOKSdëÓ…{eyž×ꈅwÏ ÄpÜ“s8SþT“ ½µ– éÃpõKe®l¬yŽªÓ\¡ó,й0ðäÝá©ýTb.ð¦=‡r¯Gh¾™è0Äy#¤ýVžZ☲[žV–54±–ÃAy‚1Ÿê–§”÷~ñ¯*¤ééGÉŽk"Ÿp'x>¡‚â®ÆßI9šÈ³³º~Aäï¤_‚7¨wÒjú;êÆd{GyþWC>ršdï¢òÃJÕ¡ù.ê O¶­wQ‡ÆdëÐ~uhN¶Ãþ÷Ä묶ÆÄVA"™TK‘ ½É÷vkru€ Õá]õö×@¨‰öîj¢OxÜNøLÕ5zïæ¬«½£ÓTó¦Z靖ö;*§óŽÊé¶1É»[í] h}rE/oµÉ]G£ÕßUAÚ»*HW5Da¤¤ ’(Ä).ÁŸp ÚÄë M¼úÄë O¼‰×)ú—â8!T`’äýJBÐ!|cIhEq*O ñt¤„¼¢Ö ܆j *æPSÍ¡¦šC]5‡ºjª9l¨æ°©šÃ¦Z5Õ3ES=S4Õ3ES=S4Õ3ES=S4Õ3ES=S4Õ3E#3e¿A”nsjù–ÀQY BL¡H1ÄY…§ß„ú2Zˆ¯O£ªë;¦ãÐrÜÏTqœ¹Ÿ²Ãp숓7¥ñ¯âbH&U×¥IgºMÁ¿‰w¤ñcOàÒˆ%‚áåR’q†”JD3'ùPþ§2‚‰§ñ×ÊHÇÃ'DYË rU°}µÉµ¯6±öÕ'Ö¾ Õí«O®}õ‰µosb”[£ÜšWVè¹Æäz®1±VèLlftU6G\ú¬¸ëšÂ¸Jº.xIžTcÔ'×ÎÊ7Ö¤ÛY›\;ë“#ݘéæäH·&GZùÚÜžôÀ›àèèLŽtWu;w&ÝΓ›*Zmb ©VW½vU6C´'·bhÚäZXWÙÂDyJ!¯Ï«¦ÃÝ#'Õ Éµ0:#K“–[~@¡œ¦oNÓÄŒª':NµIpŠEïŠûI›@ßkhQ­6ED'Àé$F©6‰QªMb”jé}}œê˜OúæÓ$ølL€ÏÆøìL€ÏÎøìN€ÏnJxŒš¦ç—‡EQ|¡_±,üœžâ,¯\yZÉò4‰Èèm^'?2:‡sF_! b„¾é%0.ìó ý_Ë ùÂðyh䆘[RÙ,HCvú(Ñ'¾”XR¨¥KÕÊ—ŠÇgSÕqß]Z«Ð\½¨Æ)Ö’±*¤P}¡Û‘}Î_ö~¦sùýlçòû…œËïË:—ß/ã\~¿šsùý‚Îå÷EÎÝ÷ 9—Ï%‘å\^Yì\~_Ú¹ü¾´sù}Içòû’Îå÷%Ëï Ëï§:—ß/è\~?˹¼ÀÏÚg tðKÏ‚âüzxnÏòým{tiÛr8 ¥…[§v¥ƒÝù›/-od÷Lg -zƒG‘¯Àï‹gmR:ÏNÿ¨_˜à«ôÐí[Ò2¾Ž»›ˆ,Ku-TäUæËlÔ —Ñ< ê¯iæÊã»lŒÑõ4S¸Ëôiw ˆK{t„2¡‰-¿.‹øƒy$‹A—¦ï³á#qrðXyʹGoÊñrŸª`áýÀß<Ä‘?ß óRQÇ)f†½}j;öèzó÷ñ¥åÙ½ã‘as¶z½´f?²pX¦-ò•‘ÇÛ…¸ >q‰hœŸK“¡®`  võsÀ|åÔ£jp0í­>Yv­¡;z”LÉÀ;!—˜[‚vO‹O^ö¹Csèky$¨kL.ý÷ˆwf¶vš×–Gò÷Þ¢Á‰Óæ<½9ì z“[twŽO¬·#âQÜ¢™£ÐS;¸B+‰ÕâFO]÷¯ñ°]õ74îÑr­åà Ò¶§NtÖѰ­G)éÿ’§ ýÅ"#øÇòäJãúAˆ±„ÿãçøÂ&rÏÙŒ š48GÛàþÏ'ÞœÈP'%ƒŠG™à:ë:¬ñƒ>ÚàÀád"å'¬ŒÈßÞ~=|ìÃêÑãGì[z”5SFYs[žÂгP¾Y/ml:{dåÿ£‰ÌÚŒz`ùYž0v41ÓÊ®FÀ/0Л&I39I'Xtv>u·Ý·Ü}5™Ô’ÂKÜFïI(¦ÛóHŠdx'},/¾š6¤pcšÏ{RHy×ÚŸ RILÝ}It¤48õÏ+Jh8ÿ£2ɸf³bŠš0>x‰öÓÔ·Ÿ¦¼ýtåÊ)6žšÑÕ÷ˆúök)Ñmå;ªz¤aØ(î‘àT©¸Î]ƒ'áåBM36'ÕŒhÁQ]éºz’àRWO²¡ž¤²•±5©4vl©'ÙVÕŽíIµãOGý‚ÖU± QíÈê¼%´"W4zU“DÿMŠd~gˆMnKÒ)—£U)—%¦³ŽJÎ:*9ëªä¬+6ì.ELS8Ê4…|µòÕRÈW[!_m…|uò…Ç×C)ZnWp±®Gx ÓU§x9Z‰r𨗓l…:\…àýï¤à™îVh±&Ÿ:¢³UÅz#ÈB uµÊ!ŠõÑDˆq­2h¥JÓÊ•¦¥èó Ðx¬‚ò5Šën”A… $ÜÁé |ɘ{Ö¿–Àð£ËCîcÛù³Ç®7zb[ŽèÁ?NíÌôø©ÄðøŸ¤ã±?ä“eÞüÜ}³D¢’kø.Ö0Í#‹æ\±žc™^°E×$x„(¯¦=ðqkÅ ç2»btÌ  P³ß€~—uDÃî<ôßóØF™|õ 3šáŸ[ç(å+©ø¯¤ ¿•mÎ!¯?J°™ÏœMTgîb×–GÇšÛÌÜIòÄIÎ(¿ð÷ûå74®sž œko_Ó³¸–ß„l öçy‘…„üÑö·½ ¨›ŒÔ{䞟;áÈ–À°ÞŽ3FWJ€Þð¬d¸¿›Wö9ÖƒF‡ç‘=À?_<=98zºgìì=}zü]V¯ƒŒ¨ÿ¥Â޵%3'Ìþ¿Ç~Èý rò½„0Úµ¨Å 'ÏHude|#vey2ÇÔ$bÒ]ïÒûÖ‹!ÅëÃãNá‹„ûËáKêN$â¹<.:UŒÑÍÖ^Š»#!³ÌðDÂ+ËߦqŒNêy[n»€bßã!æÐè9vï/JBrýG@`’è‰Rèžy.Sûô`üüP 96Ú¿/ y©¡Û§I¶‹Ì/ÖtðúÖ s,øs\ÏßÓ8ÿ%ýÌ<-Bë¬ó"ÀÙòšÄàË‘¿$ᳯþ˜uSÎ%)MÛ¢/\³€F´3çøŸ|ì~‹Zlåô[ 8û*çñO¹9W¹(löÅÓQ)×Y² Ù¢2¿Ó“<ÑÈ€e¿_gÆHËCÈÓ ´'ÃÎ…ÕûkÛ}ûˆýØLñÇççXžE` ŠZ–=NGÍìÕep#u9ˆØ¸>ÄgÛ¡ëàãÍæáØÙ/a?=ÒQ£‰“-AÉ"¬HbJ)?p!SˆTÄü.DG'xॠrߢÈ÷YW:tÐú›p%xÿ|’ýŽV}þ)]5ÕÇ) gøÄr 2hŒöÿŽ­,‚ݤ@€W §åû4ÿÓ´|N¤œFcäÀëɇ©5%·Ç´fRu•-ÒçöA ¨g¡uÞ·ÒúnµÔRèM _jp¥Ý±×³¾ËA€e#¼X.~£Mò0—\{wÈÈɸ¤ þm¸ãöÌ w¦·Q3ÃóÎMlþ¾ÈZ•dßêá?«66/më Å›ƒ¥ýæîÓLð>MßÐû7ÏLÇ·n_¾Åžbq<»bßÐñµ? çBBl¡ç¢ÊèdžP&Ål Æ—`Hàå3Ö˜s6B¡¿çðÅB?ÈÙ†Þý½ˆ7~«O?—<ª7B¿WàµÐß /Fý¥@úM¿ûèÀ~Ž/ý¾‰ü‘7¶6p -ˆœeyÇ#üþ +§×#Ëê¢S%²Ò#·Ôû’Â,öÇ1?&Mqü³Ú/øxØÑ¯¯zT/ªè±ËéEY¨®õ“0sÜ%ðþ™cúûäZö0â§h~è_ á+4†h`±Vë[~õkØ*s3`q@ü¤ÐÏe´ðmþÝTˆK&¼0°^½°œá?,PÑÁE¿×}x¹ôˆ/VüÈzËîšD*ÑŒÛ$ãytÜŽžèY)85=DÒÔ;85YÜ"ÕE£Ÿk¼òæ1½+Ê‹¦X)q]ÆhäüÉš<Ð`ùã$M»—<¸…M̽Ê3ü»:ë.îéšµ~â 9˜”ÁÄïÏÁéžÑè%Zn@ùvºÃÚ {V…ž©˜1ijÀí |—еå I= ÇÌJ¨ESîó}ëŸu¼ôÄçߨýÑcìÒ¼Š|›oùï{¥|àïŪö3›ÔLí€ÎøÞ‰ž3Xm!k7>5¯ˆ`Žõ£Ãù°b†Ø£)V á‚ÑãÃcź^˜ˆË`NÎ_ŽÃs#Xþ#NB6ð¢œèëO(wÇ|AT:ÎF G}#¦„AA~4ðFh`ýeúv'¬ýw„W2"'¾è^"«¢ÜñðÅÈvnúð«+ ò2t`úë¨Åñ§¶6wÖ­=|@¹õpC3WMümõCgK†‡fÚ•9 G,­œ/ˆ£1ìödæKºìóü9î÷-Ã2}Ë»‰ÿ]0lî¸;Ï@CËm[æ•íz7×.FÓ ´@SF ‘¯Û脸•`}1Êù<ÒqÕk| ?qOLX#ïJX`Éê†ÖchT¡=ÎóÖBÏŽÐù £û˘Ô1¼F„Eœ°7èÓ|Ú¸'ž9ðaö lû ûΈý"]u<>íA—Þ10]2œü#×§¾œ6ÄÉkæxäîXÐÌéÙ€ôáÏ×áÏ?ï vxöÜI¡C“‰Nláa‘ü$-?,üA* ´ê|š–Éɗ׈ӲșæCžyA>:j ÃÞ›çL5p‡I@óôÔŠ—sv„%;ÝÝ‹À9Ó1¶°Ê+ê42šüD³MAÙµœ‘ùx)DÅÙ=Çn ú{x™#¨} ëíб{öhËA õMþ]ŽûˆÜ A®ÌT·nG“ éþ”AüQ­Ð¿aOÝ% ýÇ<ÿ0žÁõäß"ù·Q›SË2ñZð‰Ñn6êF½¦¥µéÇF½V¯u­V»%nÞOÅͳG뇖k´h±˜‘£ÏÙðk΀9Nxš6àˆ‡ž¢Wè_ÃÅg«ß_¦5ŸEtNyîõ3’7gàÍkƒO Üc¸›½OÄú´_¡]…ÌrØÞ£»$šä¹u†òÐú€õTda-Â(…«Ú­qo»ÊJ"eµg‚ÏðxÆ„ét[ør³Øƒ‘òÇkv<ù,ú6³ñY VDAp9îësŠzä\d¸‡&º¼]I¨ËÝGÖƒéé² «¡Aòï/œãÅêÄ} ×Þ|ù=qÉ ¶lût• ï” ?‘—àI”û^¿ÉÜ^  š+Ÿ¡u5²›­&ØâfÉëÇ‘9°f‚_k0«mož¶FKàÇŠÉÚÐéh©G_ìiâMãÒôÿšƒhÃ߀ß38ùäzhÝ€Á¾Ä¾ØYÍtu5C”þĆGšÁ ¹´àvwxÏI4);•ÆA—8äTòFBDŠß/ ,«ïGÙ-ß·ÏP§y|q¦Îpáè]Íý»F|Í¢9wRÒg Ô¯ƒ>»“w9ødw œ@= ’¤™fõòí¥½{¢ÃW˜¶ˆºèðçìÓ|.û0› ï5wƒ„ct 3Ïц\ŒfqFr–˜mw4r/‚ï§Ö*}aˆóÁç‰;\¦ù1K[N0»êËfS8Ñæùɺî{0ákM0oïÐÙáìú8ò Xëžuƒˆá|ŠW{ G'“çØâ ®ø‹¶¿up¸ÍÚyfé°ùðçÖhÎò½ùÚ­ï-‡Í¦,?eæý7æe.ò[£ÕpQzJÝ<•B`õÍEúAµ3ï!¾Hì|Õ¾Ùç­£¬gzÑ3ÅmXWá¨=‰$I’þ L‡õuÏ’Hž[xâÞ Im¡ ί÷Q-bÀ\ÏN£\Ìö,û±5š#Œ¿¸ß¨s`ùƒŸaS³a°Èl–Ø)jŽ3-}ÿ`Ÿ™üOÝ;ä°–Ð9'†ÜÌ„¼j¡uM q3qÎ ¸Æ}_©úã!–mÁ=Àò7hí,ùŠt'åuh980Ñ;ÿ —@6„ŠV¸2s lA‰·ùVRñÍs/-üº=Ãü'bùIÌ“âç ‘WñÇ :O·Mï|ÇÙ¤ŸÉ‡X¨Iãá*Îfoဈñ6Gç)ÞºÑ΂.Ã;K¢­ 5œå‘S3Iܵ͞‡zþ"IøÍ˜pä\ ŸÇxyòWØ;fÚ¾;˜¢ï§·ÐÞa:þë6 âbdÝI4_â)¾Èî€äÆöŸçæpé"ê+yáŠÝ07$›<œ´æéo|Κ¥蔵@’ÓÙ´G ×E¶ë"ÓÅ™@¿’‹/ŸÙžOŽ.ä¹m F÷½^©HH(.ÑÙ›Ÿ"Ùæ{Që4D¾¥Ì£+Öù¹åáå@#›Œd«–·QÆÂÝ"‰/sv—³±wvËl&p¹Åœ%‰ó nŸ ²îp?ÒŽ8¸Í‡ÑÒùˆ.¯AVd³JÃÕóp3Êmäáêé¸hÅÿ:·í‚Í0·ut Äîò! Wx¬ ëÐg‚5k3´öäd^oðÑCÓÿ¬Þî|ħá§&€€ øÞû6<Ì€ïs0Gª}óÌ1Ïýz½"•œ2.ð¸f:oÌkÿø‚3 ^€e­Ï¦ûÅ –ÁÁÝôÆ2;fOƒY6Âßxˆß"þ—æ ò§Íq¿NñbNúð%pûh÷µ^]Ø#kÕè‡(¸®˜ÙA ¹DmùGh{ƒ(ÏZ—§$Ê„_6ŸØ#àþ–ƒ ¶¦/MxìòüYôƒ»þ|¹‚%y¯P«;Tœ7s JL ߘF;$~Ž›ö@h÷FSD@¹Oÿ¾œ%Oµ€·¼ÚnÃåo$+AÚÞ€\Ýf È‘ôoÐ7àŸÒ“ÐR8‘lP³ÜOœŒ{w†û….À©uTƒçvïÏ 4 °ýæ44Í+tMž5ú¶G¸øOg„zæ,>sÜï)ƒeþÃÜ"¿f´9šªÎœ|ß³æpˆ.yPÚÊ9Vfðp´ÃZþMÁµÝ¹ö`//O`·%ðür÷w€…öåaWù´gg€±@“ˆÞ"ý:´ G|–ùìì M¡9ú¼­×G¤(‚»@çIkž…R/°¶‚œ9š¿çy ˜ Ü %CØù±0Z:ˆ`} ̆Ñß¼*À¯EšrââwŸÙPb°Fmøé¹LÒöƒEé6ż…K/sCrŽ®.°DP‚¼±o0ë…mÔ­-špü ò°äà‡ˆ:ªÐâÀ1…¬þš ò™0«…ìÌ*‚!ÇîˆYÃ=~¹Â«ÚsËwtþû.oˆ@Ïኻà‘DÚþôë…ŸáPÊ'‡qx4eTPþïÖXÕWÁ(nÐØ9£.[|qÀÏÏ7£És‡{Çäø5w.˜Hp¨…ƒà}m«Ç6´w«º}pâºÎ‰=¤[I?xqÐ^íÜ®¿kXŸ,c÷ì´W›e^ÝØn†—%tæõƃžIGó2ƒlò†ùZ4ÈéˆÜ<"_Óõ%4Eÿ.ö çŒûhµ"÷ž¥Ø÷ @·†y©_Ž'Ì¡P¦?Çý¾eûpt˜²}¬A1sÉdU‹ô±¦O¯6ì3”wq)¤Ž,l— pšéÉ,FH³Fà'b&øµn @W)Êýš í¶A£Z}æÂõüuQâ<Ïì|E¦;îßàׂ.u—d÷§å¹'ÁÖ8mŒÈ ›¢WGoÐ…^ùƒKû{yÇbB®#¢ óç^jÎ{°0Ò¡ñÌ;äð¾0‹nվ޸¦™ XcéŒÇkÕ XÏÈŒc*Vg¦ @^àØŽEZv¿‚¡‰¾®a5ØÜ?qÑèþ(²¦Fè÷aù9mV£ÇçÞ·‰· æéMü/›@ó·nÙÚÀ{çõ™¶0ñÍvƒF­ fóÁ.h­~+N~e.žS•ðjwèz‡^å˜ Ëo'áeæ’©÷@­î`fìÛèRíõ.®o‡Ëωy:vL¬òùAvP¡ÅPò…«‘¨u­ÝntkµF;ÛFê¶Q×u­ÞmÔjZx¢^A©Ýz·Û©×§çà8R:º^kÔrª¾0Ív§]oÔH ¹%Þ5š5­ÕîÖºZTÅòp5ô½ÕHX<Ý34½­7´v«³WzϨ7›ÍšÞÒ;ZÌÜhÞÐëÄ—§ï?V­V×Û¢è·%tϨ״v³£5Û­¨~ *¢ÕAÈínW#9ÿØ{·Ÿv˜Þù"/Ã>‹-I^g×ТGžue»c™Oüíñ øˆws÷z`^Â5 ‹Ž{ç/í¾åÂsä4êµhLÑ¿pÝ 8v͆?ïáók‰ài‘JÚO¦‚n`¡9ŒoŒ3Ðhì]߀½Ða^ U-Êœ ìýnbÊ7à¸zÃ@~e¸DAvޱØ|Ú‚ûjðU+4ˆ`ªÏ\ÒÒ%ž>à ”;ŽóœiülHÑÊ\öÖàúy=|cñõ™€ð0¥5N…‹¥Íš£ºâ·Þˆ“­Eâˆ}Îö-·D޲A¤í™À;Öçùj¥OÆÆÆ*#÷è€ ÓÙÛÓ="yä,¡Ã—ì/£jqß[#¨'c’© Á‰z;¦:„ÄòtŸµˆ¢§Ñut÷Jˆ îÎú Ùˆ¤º>sÇÞþçy)X]fÚ@w,ûr|9Kd†ØjË@“†¤VX3h¢XC„.± š}ß"èÉšhü.þÀâw”»Æ°ÁÜM¹ÌyrÐà&úG  Ç'àràš€¬Òñïíkœ<ƒß ¾Êk’ò&M¿x_ JÏ·°>Ôëù!Hí¨hk1„y‰Ì‡ÀqÁöý@$u·Éh…1ÂÉ8ÖpQTO“b­à<švŸ¤E/o4ï.¹1¡`—fl¤¸‰ÏIòÈ÷.¢oj¬\ÁÈ⨢±GÓoóéwˆ RxQËñ„¢ØÇî¥õ´Iiö,1€Nø:Wo&Ý8ÀK 91Œ)jų€Í{˜¥ÎÒï¨òLˆ†¾§‰U€ë1ã(ªLÂ&ìRLV‚yÊ¥ý?cû¿…ë—®–œ*+ºbÙ.,ƒç ÆîÝÄÿÎÁ7½rߎØ1ËšešŠ6¿ž Ë÷‚1$ð¸¼yþc޳Z Š«äk…Ø%Ñ/Ø£6ÛbïÁ†Zh1è3ƒä·XúòN ë´Ô‰¹‡‰úlœGŸÁ°¸›Ø0÷I·}‘½‡³‡¼%ÃÁfD¹oÐ_Œ~®ʹ[hIÇ:…0gž†@¾iØj²ŸK¤q  ¸©–>ݑЉ-6ÐÞ‹h¼d`0ð6sP7ÓQg‚Ï¢ rBÇ—¨^S”ž1úsšý˜ 6Žiö´à"Ž)ƒ|Þ"füñ)±ä6è+üý»`ðÏòk³Äàxs}/™æè(j­&³¦ÙÞÒgV ¶xm,–:gûÏ-ÓÁ½øÞé0ïó}—¶Ì2Ÿ[>ÄXAEÐvc»')!š¸BEq!™eÆ$½,Ž"kd•ˆt™ž×ÛœEÃt÷Íï B¶¯¬Û‘/Öˆ ‘Ôå>šú—¦Ïgûö¹=”SFß½4íÁ"ùÃÜ@ÃÚ¹EÒ–Ïèzn:»onCe1‚ Åý7ò2ûÁ(M³„8Pú#„¡ ‹Ê2Q°¹cPÎñ:õQð€ø@œÌÈmˆ³7ŒxEpòûÂTFë¶0wÝ8Ç'>ï žCó-N¼/HcdÖy+Ì)¼Ðá”»ñ†¾œ€d¸d±Ç¯³8ãÔtFéNJþŠáÀÛ°‡Žú¸ˆxBÀL<ã6}ö|.Šè¤m‘Yû@”Èh¬‹2 Öý„lä+Ú‘Ôu#:bHGÒ‚Žä­w´5€“ ,Zt/‘¬$ræ 4 |ÂÏjø“!̆I÷„ºs;è&Œ® õ½›<áâ—_<ü–i ¨âÔßC8úØo:Äý©Ÿ¿Áò£éS¶OéÅ2Öa?¤Géçt€JÄ¥+]þŽÑ=Ì…·,ÿvðÜF×|ã[g©Oè,‚›J ¨?ªþóç©»ÑDʬ=º^‹fà½y…Ü {×ÁŠùI|…ÝL€lôh i€`¢°äƒãg;n?X«–bé‹Qô 6¾X9¤C|ø‹'¯6n/2|iÁðä=0ÄeâÌO3òÑû0 1ç„xF^@<&Ø3YÞml{Á†2J>ZÏÁEÑÖHØ<÷Ô±.7âØ´©ãɤ©î<ìZ—h/Ƈ’]ª–ˆvrC©1yq\Ž'ÜÁƒH¾öo\ñIôqÛêß3Ò,þîb;¿;†ØÐï¶AÝPÃB"%[%.}tp „l ‘¯Û~¤8fEï.ØûhºÓÄš$ðŽÂ.‡æ^XsÅ¿}Ní+"©ë=[[=%–läÞûQ4XŸ…Ä?Ž`µVâÃ8ÄÖ)8ýMÏß¶Ð(š/°G=q)Òç9ùD7ì)(òï'i°[ƒk ¾lÀMˆáûŸ€¡ù<Ž?¿‰G\ì]2~DÙÌw)Ì<ZàË#ø¦7VT¦y½Ê'ÊÝ0iMq?hÁõ Ôt¡Ó¡¢ØEÍ.? W.Z$e5‚‰܃x$ýy—ËŒ4Ñ7¼Ç¢Å½|;Þå3gCи¢F2æJ ¨ˆ›ª)Hl ‚ΜsA‡£;(U‘…#´ÀÜ0@MZ1è1çú¶0u=fýç\¯ Òf.üSlS÷Gðëõ,úE_ÔWÐOvC!ÏíS(å ÚÓg®Ä«ñ*@\¾ ñþÔÁû q#?8à<ÌÎs¦™¢›ØÇ4sS4z0Z£áÜxŸ Þ‹“Pwí˜.÷.Þ3Ð1ö %ãFf€½[fkÎÙ™13cþ‹´‚¢_F}¼R‘̓@BÃÅ ‹Ë¸Ow8ÏKS–‚çØ÷ÅRLCÅ‘Ä*=1\ù ‰¥Hxý˜é³Ù†á_ =ûoÜqR‹ÑG›¹0"¥Ï-‘'f`m`¯@-ãvô“YúB ¿‰Ú®òºaLj¡‘uW¤¶Ê&«v€‘4ÅÔVc´ü‡qýžÀa¦úpeîóJ‰{Y=tŒb¸´ ´ëoØ_Á’A:ß›Oô=S™ƒ¨ï$_²î¥æÌæÄÍoÄÀ”ATƒçѽl(ñãæ÷{Ú8#6Ô‹ô/ó°ƒ hòö©…õÍ]áN2ÄaÇr<á? »ÿvÿ¦Š®³F aµdDU¬ˆÕlðùGøóõLðkÖ4¬°Ü€ªX¡þîí ìgÞ2°~íŒçŽðÿ#øõ:øõç4ûEDïÞ0Ð$ûOôÿ¬ôéLð ´WƒN_aŠCAÊñ¬I[ ·ð íFð}D„üDUo)8’V\Œ~Þì[ÃÑÅß®ÿöÓõ.´Ž&¼ cÃÍ)š‰½ß„ã,¬"ç&L­?ð¿¯7.LŸˆûß’‘N´¤îi¯­ËÔcÆ.S^Š}ß‹˜&ó9«IãùÕä,_¡þrˆ¥+ˆ˜á¨©ïÂû Z‹GëØÊÞ8Šò@5Môn2j,ÂÓ þþc ×(Lx&¢pñ„×ë±\âíX"å/Ø]½ÌÝ Àï ×áÈ ×ÓûAÁáóîøÑÒÙáy-–ŽŸNɘ^ò£ßà3„ÿÖwoؾ¾»CC)~<…zQ"NŒúwË8¦+žLrÛK‚ÆDCùëd)î‹„]•æl¸›Qð)ƒDd¾EþÌ`Krtv}sæÖÚàc)à„4Ð-~!^5+8*ŸôMØSœðÏ{ð¸„Ûqš›p [¥\Á[æØÿc%‘’zz½FðM‘!&“`¯“`¯§ ÀOÑ¿,á5Mx½;Çäbô3–ý:šýz²y¾–bßq€×1€×ïÅÆ0$­þÝ3;’u0Âæ½WÖ*Ž´ñi—påþ;6dö‘ ø»hª‚Öm"ã¯Å9šû*[Û“ƒüبkv£^oµµˆKHmx—jÎq¨Q…·TsËÛ¥ÚíbZKØ/Aü~ÂgA˜·N[À¦å2T7^à T­i5 Ö¯»iÀÏÔZWðXŠíu‰YÀJ'/j@l5™tÃ87‡‹FÄF}è×ôz»Ñ¨Õº@˜îDwŒz½Ó¨5õšÞá"Þ6FŽBáuQâF²ÛÂÔõð‰;\¤ÝIä qò*J%ÚIÐXfÛØ`© àÂ=âq7xíãš„tÛ¶éˆ<ìCÁ8LÔ Ð»mhõn»m¤ÀÄlm5C«wšÝz[Ó$18]¶ޱ–Ž”Ò”dL«…(’Œiuޱ¦ŽÎ¡4äPJM¥¢´ºr(ݯ ½ƒÚ·]«w20@T¶z­¡Ã¦·f´:u­^k×jLgÔ½km­Ó­µ[A"Ó,¯7ÚZ£Ûдö…~EÉî\ç2:|†¶fÔ;õz³ŽÍqß`ZËF·¦7Û]½Uó/L<ßs½¼…Àñqÿ†ýQ*U+Noç£ê¯$DzaKBjy\"€¯%¹”çO—毑ǟ.ÏŸ&Í_S²% ÙËû¬š4äk¢K—Ú‘nénVñÑÑUË«J³èÐÖÀµ€äÊ.ÏgîànåS—ç³hC´)Ú’Í›í¢ U JyÐnŸ¢|Ê·§V“x¶óHeÎ\âï’•þRvbÈj’%k_ʶŒ,`]²d]®! ב„ë~˜³§Ï猥؉c!r̈|iÓì@q‹#¾8é·ŸŽÈ;ÏÝ€#¬¥²ôuƉ;ªV³Ý¬5ê܉;“X“êͦ®·êµNG‡GêÊ"i!s²iA9uyœ‡$˽s²8z€¢Õ$Q!JC¥¢4%QºßZ­Õi7;Ͷ–…ý“<€È ¡ÇÛz:DÊùökÙQY‹³û0—Sñ,§xÔåyläò¨àQ“ç±)Ú’Eljœê4 TG—/¸#ßäÝLçÝœú4 vÔIÒå× ðš?Ü[…yÕ ðZ¶Q¶Y¶U6¬¶ ·W‘zu Àvsyíæµ@»Â XÙŒ=„¿”­úWÒsER“-\ûJº¤!ë²…ë²€ YÀŽ,`÷£¼CÀ <Õ‚–hvyîÛd ÌøÓVckFðªFš(TÏÈìýea­zÑ!y‰Fqa*ß‹$n ûü6ª,c)†;¨ý€z’õh .Ó nÑ<~yÇ«¦3í:Ôm úAžX7h€œþ–¼›6jŠCsxßû`>˜Eo{pŽý X¢¹4òöç¤à>þ q`çæÐûÖ Ð©»åYþøÒš¢ þ'">‡5ñH Ü´Å3ððš‰8þË]Ë(d,´ j¾ãXæ`<\¸œa3CÔlÿ‚2"ÄÁÝ~û'œß¥V¹‰Œ•^Øû¨±,o|{’pM,g-™ä/aTaÂrìÛ_Å•:&¾z†xü.…†ÌÄÔƒ•¸ˆv=QËa@“-Q”ùS¬[Así Ù¬ò­%£Ï\­>Å¿Ì7>Ùű}ü"ï/‘ªiX{u=0Õ$öì\â‹á®å‡‰÷itîW68PãŒêu÷éH=$6ÄA:ö­/õFBžfßÓ,RÆý;mРŠSôïŒñ—ea¿²ÓìÇ2JºÆ~<ìti)ö½HlN©kvðÎ}­þÈîýuÍ[ð¯&“6ÀŸñØtûÔl\sËö9.² ]õ M>Àݳ톰ƒÖñÄ‹e¯aãÌhÚGô!ócu` ð! eäB”mi A>Æ·Y‹§8õ9‚@C±ÿ@h^ÌìñÂ03lèq~BD\`Å,„ÅAÁ˜f´Ϥé_‰7ˆS%ñBÈ/ø7\ÃöO˜#º¨öÈò‰{~îXá,ÍõsGX3êõn]³ëšÎ4\$Ôx¹ð¥«{h¼¹ÎaK$b|³ì… Ä—5´þEUkñcùMüï,ùû¦yü‹=žÉÏá„ Ó `º‰¿Á?¸ñ€¿à¹cÝö96Y¬'ÐÛ»°ý³ªDŸé!êç<Ǿ¿ ܺ葯Y#ðo2ü ŽÂÖhÕ'ØùI…/Di8pø1eŸ>wÝÑÔ)ù»vê¡=utñŒxžÅïrìع$ïñÔ½ËJ ãः#Ez§Ùìêµn·Õ+P»À3$!f]«E,Iî -îÞi%Ì¡â•÷Ô¤¡8¼ŽŠðØ­P˜:ÚSwÛ(9…A b+9/#žÖëFo&¨ù2—8|þ$Ùrq{F<…ùòþ4™“×|’„‰{òÎÑÀ+“”óa2'âÆ;SÏÁL/³‘ƒ‰(?ÌW;âOÜ7à2Ç…Y¢jHS4`Íü0 E ÌñÙ«FC×kõF[oö©/ùu£[kuÛfC‡¤c,_åz½^«k.:“iµdÔk-4-šº†Ã # Z³Sk¶š6x Ä&‹ÃˆVÐÿ*OÓ÷‚ṔâÒHª`¶ ð°ó«<<£yáÌ}/šÃÏÞ÷£YÑ%ªHnb߉æ“KxÂú e͆ý}wèLØ‹¡)Ü‹=ºÇ¹­ŠæÜ!uC·PK™*G)u£©wZ -#$!rcM9 í!ãZ§Uë4k©\†àu pmÑ€ ¤ÖÑš¦ç¹on rÔíj-$€Þ]Km©ÚG©ôé"ú­„þ ™ÊÁ»{V¡$ (•Èõ¨:ÈõUº\=3éÀ?vz=a½2âõÔ¥ëÙ€Gf¹¶“„Ó>“é~ í&¡³áè jIefh͵sbåÃGàÍÊ:ÇÜ6 ñ˜~@rÞ›çq¦7Ä àÄ:yÖïOÑï™@•t¡Ç¢9ù!÷ïòID d<à3ˆÒ½é™—$ó}>“ªÝ‡¹ |×w3Œ0ªñ<;ê"^Qîп̔€Ý‡x¾6ºÅ=…Ö#i'.Z *JLæ°QIùˆÄˆÀü ËÿÚ{Dïv6ÅÍ 3’6Eêä/Fk³ÎâþétJ÷Ž\±ƒ6+êD­ëCsáxhö,è"rº“ÂÆ,ø!&-tŸùÇØìƒ~v[ùÓ ¢@£³>e’-Ÿ%h4Ac :MÐYBƒ&4æ`¢ÅFØáÒçÀ—†K_ÝŸÚ½mëÿleâ¤xÐdöMãFþ «ÃÁ¯×ì—¤i¯Áî%Výà;B÷a‹E@ÖȤ4ùÈv«ØU#öÔämõzà•ŠþýB¾™_$a‡N\r‘šCðÌŠr‰Y¼ìnyžy ¿Êî:èfK~c±Ì:ý f«[tæ“D|±^…\W˜O|ç)|GœÂ6ú—Ö2 HrâRæ-NøñMæùšiÑïaW Ë}w|нí÷þ"¡sw´¦a¡Ê J§ý{ ~!–£ë ÿºƒ£>¡ã:·úÌDgž¥Ã"»ÁQ>Ù3˜»àv©p+`™*õ*ý‘o2{~¹ø €£O«1Í~¬V¢€ÕdÒm»™H±ÁÆÒWÁ$xºI%×tž2»”¬&“VˆsÕð¢²HRžƒ‡l;9„îéWhl僠8¸"LØ`þÏ|9ï½C&Úü‡8š'Hìß ›Ð–¼…Žat»ƒu„™HœíAÝH[cöl;$ ƒ%ä݆®H ?€Kk%ÅÀoÜA–ã€ïÊxÚ* ¾IëÜCU€Tæ“ìW‰`e†Å¹´s>D{yzÀƒðŠì÷°…·_Ô«í³7ÂÙðféÁ‹ƒÀ”âý´Ãþwl,çô©ṭლ‰†9·u÷ΙØËÂ;Ñœ@y?Hç¦ÉÏR&øì[ ½ =ðmº1Ï‘k4˜2£,šõ·÷ Lűµ¸O2Ñu7ãsÞ¥äýE›(®ŽW𱊜OÈ;Ä,ˆ"ÉOjrNÍŽ7 SÆ%þºEþ|’f\è'C£‹Äý:ÏX> BüûœfîàR-ôIŽÔó7…¸äïöõâá8¿£ãcC.iéK£­ÕÐ=®Ž.ZÑœ„ž%Ô2µPÏÔCÀF&`ãv<ßÌ„©š0U¦Šé6…©-ajû °—h6-­Öp'~ ¥u´v­qj¢ Ÿ¢ãKÑpŠÎRêíÀh!XaàK©ã”«ÖîŒb¡”:NѸ”NaXínG˜F€)5œ¢…)õ.NÑ× ]o4jN§=BVëÿ\»_[A¢v4»íf[k]Á Lý}Ý€ýhçÑžN×)ƒ@Ý" &öbpâÞ"ÅÒå²8ÜV36ˆˆEC®‘™eÒìô<)àé£/«‘‰¥7mÐÊRîÌ?MÉÚ}W'š•ÜLaÉà(’CQ6t³fº¬Í,ÃO6ùôÓÖhrœ‡*k‹V>æNë©—@v˄߻h†½Jæâ!õ¯N£¯ /åôyƒA:¿S ¾ÇT0ž0Ÿñù|6€=pt?´ë.¦4ÏÑdùÅ©æ<þªõ9³¢§½:ÉDne _*­øZs§5…¥_­Gl¤ò ¡]¼ìRó߉FW$B‰-üeg³ŒŸ ÅHaœ§†8k}ªÓjúÔ>9Þ¡Üd¾K8ÓW¿u¸ƒ0ædý:aßJØEß'S–Ë;0?(ûœ!0ÔV+[äGYB¶ÐKŒuÓ\Ç¿L¢~1ÁW+&¿¡…˜Ä×FظœeÛ¡¤q|ÿ.1¼Ù»øwp-ñ oE<¬’Řã­ˆJš Ò\΄ÔY*u&¤ÄÕºžÿyÿ²À_ø«üzÖ‹ Ñ¡Þ2Øp”µä÷ì¹N”ow²„Çz­ÍÑÔïà@›QÜuIrÛŽÎX¼ŽBa3T²y5ø|’¥î€K.ç\Ôˆ²®X2],±Ÿ5Σ«éS[|Ži…8De–Ðá„çÊ*Ð^Sš¨º¬ÂR`r%Ð@„F™<ÓÚÕ-Äyl–^á¡?ÅÃ_k zóã_‡hËç›ô‘g-íWÞ †Z˜åÎÂu&Œ“øábe”üuõkó”%«Í3”Vš'°´ñƒ‡UkÉ0¿ã'ü…*r;92ßPè¢ÿÊf–¶©Ë±È›‰È,v²ñ“à ÿX&kô3@—M´’I=²&kÌzì‘3V1I ×˜9#¯éuE–Ið¬j2+úÎdò‡‹ûpˆK¿‚GÌ*7â\»¬?'9Æ}νú•Å”û¼„±¬¬„¿0­—32Âí<„!IzÏγé*åp±™Þ~Tâ~kJß$VV^\ÁKEORßiÌzÚñ}ÔE÷,·†ÒÝ^× þXw”¶EÜnäzAØó™ô—F§ëùTÞGÇ]§ÛõÐéßQs”v¼Û:]zJΓѿ±FæÆ¤ujNõ ›˜n‰_Æ6ç‰74ªf}o*¼g®“oLß+Iß\"¿¢Üòjzåläž³Ùºu“õ«ã?—_ΦA?¬cÄ>™®Ì„_80% ³c娾¸`a†°èØK?$oFÃáX9ú¡ì)+뇎ʰëö=Ç4+•Ó¾ºNÔ<ß±ÓM#u#ëH‘ŒÔ³ŽÔWêØÆr•HŽm¤P‰ÔµÔ“‘\ë–Pár’ø©úa÷»¾tK_€2ŽŸT$Iú·v)iøÆ´\¸ZR,’[ü`Ý4’ŠNP]Nï6åtoQNï²þ-d¸±XÑwÈȾN·)gx‹¶ïÝB6ª®S@F®uÒ30ëôË›,g¬QUÜðöÅ­1Ù¼[ß*eï6Âþm„-znïöÍv«ò†·îU——vÜÛ–÷VMݦ[öå £±0|Ñöu‚ßÛ{ÑÈ^´o]T×Z2´–ìYKö¿¶ûjî(·\øzö3ë Å·•p4h–Ø+¼R ý,Y%ohQ¿$Ò£tž‡žt¦I ÚO|àŽŸxˆëÉ' JtÍÔ…ÔÛI|Âsk‘³ňî+fñ]ü[S5´(G2Ø #¯u<Ä"·s”:ˆãqÀÛhÖÎQ6ØqÙË«ÙâFHu%&Zd‹WìÕtއ­lg*¨o¹ ,¶SÝL©Ø(ŒØâÄ4Å€gˆ‡ÏHí9SI uÚô™¿Ð¾¼:‹áïÕ”Y~^l]kNŽÄý†<ºÆèüRkÀ]Ÿ_ÙE:pÕç“\¾`g“{TöòóÏØEpú3çlˆ2òSLèPmÚB´g¾\ ø YCó1\%ЫñôSSár`ßÏõ¡ëJŠ­f)nXˆ´ÉP%·%ÀJÙáxNjC…gá´oL1 rkÏÆ×svGbW¿C!+俯è.Œÿv~OÏ ØöÅhœ¸UžèóQ^ÜLW ú íxE7Õxyî=F÷sS„ªxZó.:>¹ê„ß•bgžZ\ Ѹ MÖÕgÎ×öÿLnÖdЭš¶ò䃩`W„îÀ5©†N«>’²utE™^%“"ß™ßGu6úMfªeÑc‘ÛÊr·ìÐôÓ®t ð $+„ï+‹˜ªž×ÏcáG6ÙÔ8p33tü•ç1›Ðk%ªGç=©=ç¹ÞÅkN2›ÇI<ÿ(pÚy ™3·£)¥%QwØ]Üf&ÜàÁnàëÆ î¯kô•Á%’eú‡«l°ŽÇëç¬a“÷èU#}N–ØáÒ\H›~ZM–=I…!áŽ` ·Ìœ–iðËO:ð‚g1ÁÎò;VË»1„4Zs”°ãî¦NgàÕð3Ö{œøB9é`œÎœ½NÞ ùxŸRáë5ÍKÒp]ºq§#²©„FtÒª¥ýÚA °ê¥ý›V’Q¶Ð±êd@ë§4CJ=díÅ¨Í µ#ÂïÓÖÜü &“°ó·=óYM¥v‰“–†öÍb0j N‹ÞÇ´ß^nñTX–Ó—z¯(”µ™fÌÂ… ]ÑA·8æ¡p3wŽEëÉóf}…†·rBPå••´£Æf¤]ƒ(6ŶA‹|ß4‹<³ÈÝQB åÚݪS DÊKÌÇ+‘©½’Ôi:ÜÞÐNN®Øb§†ˆo‘.˜-¥îÜ5Ÿcu-T#3éÀ«.è¡k]„N¦³†xfN¶·— ì2ïör“¶(s+Ë'ß[Î!2Qú Z;O9ßrðqÊN¦Há&{Ët þvO–ØÏ*®Âáé\*¾‹é$puž­ÞÄÊ“\Š‹¦Ù")÷;ÜÞnÉòºµäa[=­]¥7Ö«”=7p™fdtk’4!øN²×²ã@ ¯Ùâ–ç°Ên'Ð÷¾ ÃoÊÉÒ.ðQüy ‹WiI0á]Æ“×t?Oî!bë w5šanžO¡n_Á]Ö B¥9Ô% …¬ŸÝ,âä7<†]Ãç“éb@¿g²QVDÙ[8ŽX«!PÁ]h–as¦g¾ ¹ ^¤ÅÛN£1[´­cÙ¹Åjý‰qç [åIµðÀ¸m0–[<ø‚×£Í#Ê*6™ïuxß8ï¥å£´…v·Y—RR“ú^“Ê6¡&ªWO4»&òXa½H7%X“wó,¾€«ë)áhr1Ý—|ú¾bÞyñŽøýl¿'*(æ/Åð”ae¶xUi[¦§qî@Í Ùï*OcìÈa¦Ñïe†£Æ¼/G4Á^¬µòN:æ#fÌŸ7 ´6¹€Ï'nYŽèž)þîÍ3yQurÔY; ÂjEŠï\p8â·|Å$èô]i+)iÈ ©Ù3eß>Íèüz ÈμÅéZŽûI6€ô£þ†i<×¹æó}<¯²ïào¿68õt4_\ÆÛi’ZNí,ù¯Ý묣sžÂVŽ6Á¤v>:£S'ÖåàµVaÀjáÆÓºò²½±œþÓ²Æ*ë«¢Ðg;]×"¼X]³á_¾MÐú>]Á Uµc}EÄè µ€åÆ;ë£$…z©Dú˜Ã÷ìÌèÌ:[äV…[Šm’¤njj?j¼«_ÄtÊÍpõ£1`¢Þ%I&ü €Î;ì-~L‡Çâüz±Äê´Jƒ3+âaCS­Äh'U½€EÊÇX@û(t/SPš„ÊHÁK_£;†ë9¶)7ÅÓ &‹f‡kIj C‹õô£ S'Â*Þb5ñÖ—B)ܶ®¨ØN´ eì÷G°¦›'ào^ ·”·‹¤£ø%˜-ìFY„  IMÑ6P×Jâjó~2½Xü“c2 OôDÉNjÄ´5Ξ*¢­)r™ð®ÊS…¨Œ<¨HMzÀôªì{ÄwþßíEr:Naï't¢Ðíy½PLÎ)ó€¨éÓ”A¿¬†ÄÚ¹ò—ÅŽÔ‹Ax-l´µ'SÜÓóýˆàS¼cÖlð6Òņ2öU%ð«ë S¼ò…XÆÂßÚ¸2ÁÁÎA®é²úêXÑËÞÓo!ú~ª‹ÙÃHiÝË3/[,¹ÁœŽIm¸¢)…GC¸LÚ7¸›„#vœC,œ#¶†SÚŸþu9ÇÉ@XO'«L€n jäÕ(äãÛ´Møœµ&y … ÔµÐNV‰Ìão:ÁÚ0m,^¢†‡ÿu ËŽ,¿ m³AƒÍñv’¦.QãQº®…`ÒrÛ$àtŽ”×S'ª½©Æ¡á½Ëa7‹õô!!ÜÂÀåôRC)7F $€ ¡•¦È‚Y?ßV?O«Þ<Ç1-Ãl i¡9ò"vf6Ñ©ko®Œ‡_Ñ=ÕDi7¥G½šÎßNbTtüPØÙìƒBbCÍRÌöO%µoŒ8ŸÒ=¹˜óf¦µ›<“UTìÔ ê$ç•âKµ`kš”ëš½þO¶îZPz“]@Äñ–~8÷Ô-«ÆhB‡hú©Í˜k|Ïk¨ƒÄ¡µŸ>åàjʪ3yή©&¿´ ºë›fç#*¨Ñ„eÔtϱŸIõ lÖ Ø3¬_@dv2³>KEþTžÿZ•¼÷bS/9#þãó³›»ŸaÿÏ'ÓÜÐÐ †nhèhè0ô?'Ó¾Á‡Õkvm¾UÊ5Ǭ+«­\ëÂw¦‘Âý!Œ« ²# 2áž6ÝÁÞiÂ×:»YÎñåW8;YÆóÅ|Lé[óÑù¥€™„E–zóÒ€ºCpà¿»³ô}¤)m›É5ÀþÀWßëÊs ÐâœÐÌ„!æt&c¦Ï-õ«§d»¦¯2®²Åáí™I¡£K€TW¿IÃi²¡Á¦î\]÷9(&"¶ ëp8G¬Qíƒ×ÓP Y šânº—Ì”¦£ê¾êçÌ söµ쌢‘Ï€ ¶ÔñØdP÷Χ³õc³;2icnɉWYP?dƒSs¥Ä#aÙW™µ6/âúd“õjÄërŒ}ÌiÔðËÏéÄC] €cýÇÑ‹MvúÊ ?Ô]]íìkðËŽ÷òñ·étöUæL÷¿ø.ÿ ƒTz+h’t¨àPë׉µb¥+¡l„ŽÐ¢qM0~S!g:û„¶,*s«¬½BN tr"•:‰P‡k9_Iûü!¾wÊ©õ†¸å ¨läˬê÷áÙ|ñÐ '6M –öRBÉ×aFXxgèh‚óÖÁàÔ.ƶiC«E .¦skÆQtÓdNÐ7º¼¢Ó7ž;±/ñ&[$Óo/e â¾&œ—X«`&Çv¼âK¯CÓ½`– SÔÙOj¡S ´Mñ ,´fÌÕ FÆEú¸¨Žó-t™—ÝÈ4ðs,çós¦ªÏÀÚnêÁ×ñxÆw²˜#ÃË=š¨c…!tNf[¼“áˆ7HÑTì­ìcõfñ ºÁèsWOß)|˜æ7͇€s /ê:¾¦rªs`v ¼M´HBý$C6ø1Åt;ª(fA¯,Ž VÍ™8™¯%©löÓoꇸ\Ð·Š³³‡D‰Œ4µ#=(gß'²)÷ʘu€@-+ÕÔÀKµÁ~IJgy1¡y…FÝäÃhé.Aj×ß©²pËï-ß"ƒ›’ « ¤µ‡ô1¿MR}èNfz;±__›G&,³äפ€¡_¢|¢!å6šãéùßwð;YÁ¿Ç×WµÂáz²h Åèâ]·Û>5&#²ùöqFâiN‚Ž §³VºŠ§t[±«´Ë’»,Ò¯ô‹Bû™P$ƒeøÕŽ*à, ˆñx1øÓDü«£áD»KW¶f»UÝÞ=¹µ>Î)“¾ºã†eôMK2ÙfnK 2[qxšòÝQrôö¸Åo"7^›à,E*X¼­L\ã12~²¾LôäL²+†Ÿ[*=]ùÊÎ|r9Ÿ~:é;-nä¡Ô+ðÕ -$X¿5â³ë³3¨ •ïè ïªA›Ryë;ïR0~ù™Í;ôñùõücüM¶§È-“Ï8g.‘Ø3­‚KXȯ·DŠûY%ðÑ„.´>€êcW×KFŽŽÆ°ò‡™e{Ãnâ¾ }fÌŒÔÛ‹loÞ¼LfÌL@©òæGq]I²ŽÏØÒ§Çï”Ðëãw1ô>F?8oŸÁ)®¾cC®tuønÇt0úo6ÑÑÄïñÍVJ“Giã›_=ýŽ{éÑùß› !}§Û—£aœêËSÌߚɴ$ô¦AWi¬lÑä$ãÎõ+¶ó‡¨bïCwiÇÊ!GNkq‰…ÝÜ ™áéMek:ªâ$CeŸX4À„öLîçÓÅ ;´½§6Š$³•ë*ùH70Q®ˆ‡&‰§<ÜNÇfJœ  ºË¦·ZþØùøšnAÓÖM”³·Ííù@#‹>“²ïѶt} ÜSó¡¾þ…õÞö¥–¼å‡)|±hÔw€ŽZÓBî*`„Yõ¤°Y„ïV#á#˜»ÇæmŠ=É0êô]}fc# fcP-÷æ%d3€Âž~Že´†ÖÏ“mø³‰ô_—q<»E£Çb¹_ØK&ƒ?«Ôp†°’Ÿ2›>Qæšá=SÕl¬Ó†eÌÒ÷”i…°å¡bÄ1§ýli¥Ü7æaKÿ¤âz1e‘¸úë^­Çöi÷?Qù§i“ìbU+ëuq,ɺ§Gù†âÜcoÛÌ<À7cæ}QV?¡!0œØ¦æ‚&_; 37UäEÖõË/\ ¤õ%v®gŒ¶{žËxBßV^ y?ýcuP¤€Ow&´îÀ¼ºN&×WüB“-šé·Š¯òó«V€ŠƒMÈño$t|;†8ý ïF]Œ R„&U#^Ð ƒÈ£ãÇÙ‚œ\?ð}'ƒ%º³¤"A æ‚«mFUUWMy†'úõ*‹@ŠÐòXçË;¬±B¿T­”ð*%|2zP$ñžã·hl®`8Щ-Æ»yÙÍ‘ÚM¦õrø6¦hùÔŽàRŸcÎÄ϶zÝø­Ç|ý4k½MSÖk²·²w™w×V¶“¶²=sEtÇ;РוηiêrRÝv$ÕꎌXG»´«}®–b¾òžæùwh•‡Üªâƒz“ðéñ¿ˆp< 5úÿªôÏYEPjLÁ¯4 ]¬Æ“kþ1N9.BñE^Z@Sy€‚FÞ>œ^NpÒŒ3¬6¿çKK$î6$Ì|hî+¾%hu/^>²CYvvÈb¿ñ+²»Xê«+\þÀçW g* QÑ,Üv¢QÆØfQiò;ŠIœ3ðKÖs0:‹?Œ&ª9t“næÔðßMO¯âO—qúÝÚKwŸYÎæ«Œ: ÿ×\Êý0 öz¾×szÄ$¹Å¯ÈGòî¡_ϧßß‘Ea®)î›àà5ߘ¹9¬™¯mŠ ^¿-J f…erÉùO6eR,WgéÙ‰!–|aÉ<ð8läœ =(ÊNø/ÌÆoEÙ8¥ ,RpKS-RðJSèY¤PÞÜ‘E Ai }‹ÂÂW…¤k‘D¯< Ç"‰¨< ×"‰~yôm}YÙ«ºåiø6i8åi6i¸åi„6ixåiôlÒðËÓˆlÒÊÓèÛ¤QÞIÝ®Må½ÔulÒ(瑩k“Fy?umú©[ÞO]›~ZRaý›f#ä¶²Ýú©¸ÇÒ=ûÕƒo“ô"Ïóºý¨'o“5‰Ó #º_týÙtv=»O´8D9%ÃCI+1ju:_<É%&ƒî@§HºHô2Ÿ¬[ÇÍçiøšîfDR4T3€u†ôFcÝņ«§ $+«FMz•0÷¬Óy-¤Uºc€MÉšü1[%ÇÕŽ5Œ²»gìö$ûQ,%¶5FzRÄ›9¦œk/a'ÛÌ)vÐs‡Q› 9Ía‹! Å¢jS¡¦F¢ŒÙ-•œ 䯧½m7UVÁÁÊádøŽ¿ôvN½ÛBkÅ]Ç}mœå®Lb†å¾2åpª 1«±Á¾==u Àh÷tP=Â^ÑL–p“—, À?k²†ÌóQœ,óß»dq3‹ܺæ%#óƬïˆ\~‹y葹R ™ŽfXöKÕðÎÈ×qH¥¶Ã dM/?Ð-¦xnÌãÝo‹àÆ;ýF0L=ÿÛ~ò7Äþ ¡È½Ðñ\b`g>VRÚ©–v÷2¸ÕÙ&NÔu= ñZ4û¬m'÷N¯æ†Q旅Û33·¿üÊ¢vpµºV0÷•Q«Ë“~w,òó¬¤Ð×]ak“Ñ·F¦áKx¿ /öU7çÁýØ>©ÈÃ)*#÷MkWF·,×6¯´¦¥ïد®©[ö6‚êø^Y=Û:úe©ø¶©àf¿zìXȸëÊH_“ûß/B¨ðJˆrUøwƒQ¿:÷•£AÔ”Xú»¶¶ÀÒv?’G P×Ѧ–«ä&AkTÔ‘¶.G pq8²óâU" k;é'¬%_À%Úíí¹ W4p2} ¹$fp¥’À(ë9Øè 7ÊÒhF û*Aê©)3æÃªÓQ­“™¡Ç=YÙü j_afV({YVºJy"$±nFDŽZ«æŒÞMleÍÕ5°Óµí+ï³í{ G˜«‹Û‡†ÄÔÅR“¯?^qcZ±ù'3ÊÝΟüSž+€L]³º{`6cìÕ'sõGÐ7Çü²0Bhÿ ©½` JÓôbC“«RŒ„›°ðdj+]gþ1“óÂ7E7a3r]âô½¨ÛuºGŒ9è4‚oÁýüi8n/rûòÊ÷K G•Âlù¾2…ô“üeuÉàx²8;ü*šÙ¹uÒ7VíLFVrny¹<›º•¤ÁÖ£¢ºå¼ãY•Ù³¬›«E›¶²’rŸT¿äjw LÎc³-5ãíê )'©KÕ­øól<:)í_³Ѽ¨n¡Sé#µF‡©‰]òž;RK㨰$‚–ú-[kìql:F7ñQHÐ1>Õˆb='ÀIƒn0•Äk4(ý¡¥<æ –ñð¹EŸõÊR‚R±‡³LkÖ‡m$p%R:`ö!€ã¸÷…ç‹*’Q^NøåhUâO-ô׸§{¸²uˆcp^“3Û²+Œ¤÷pæ'Óãÿ¾Ìci½Ê¡'²Ò¼qŸÝÐÂ>3%ðz‘ßp0è$@•eÆVÊ”A•p+y9arE’¥È 0Mƒ÷†VÖQ·†ã'>q<©•q|±x9ü¯ÎáýÀØ´ÃïÚ¢ÉÀ£4÷…å Xò0ÍÄK#âªÀE· ™&sØx*„e…ŸföÉ$þ€¾hTw‘ˆ`û¸ëº ˆ÷ %Â`q64<¶Vë–Z¹"|©-Cn.Ñ‚ùZ¤“j@O¸ æ¢ÿø7Ñi䟉y¾K?Ý^@òìì§þ'pÌæ‡ôƒìû•â‘"]xÿÀ$¿Ü?˜xûû/«ëa#äÚ!ÔgA±Ý[Û*3ßF(()‘–]ž¦.(Œíߢ>žMQC¡¨b*sµz£U õÁÀª «²¸R9ß)RŽUZx”\ã“êªé7Žg#ØÎslø'F×ìšÈVν.4ØA ;äóÉt‰Ü°ç›“éÚ³Ñâj€ºmñ€àŸJrªY` xámN„Ü@ðíäíŒÆ~<ʼnȄ×É0 :0£[“+°Ì·{Ëü÷€\÷ˆ] }®§±_Ìz4Jݼט4í“oZ +µF¢×'tç1¼DhÇmNŠë—·´ôqi¹+ñõÛy`0Z…»Á@àíŸtPÒ2®'ásø«†Í6ESH:þh”á4N¸­#:ôx5ZÔÜÙ „ï‹ÀK¾ý‚ÙïÙ<ü Ü(Ê5 $t¸§Ÿ˜†•©ÃQ…=îµÙÀáŽWuõA#÷)ó÷ngPŒÞQÍý™ éžØ*Ò ,¿éšXnÿZç¸ç’žÅë€ùÑ!¶g{ü·z×n g¯át4b:mÒõðyŠf)P¸hÂàú÷íÙ­³(lçÉ£³KX£ä8{¿!n'7“óËùtB ÅËëpdÍ`¥Ÿ¿9j*¶¼ †wýØm»&>ŸÎùMù½s¦‡~| T­™á´eX@J [ÿ+"üfÔ*^z󜌔ÆëÏ7Ó§ç´:Wì‚ù&i¤ ”ë9¼„¤l2"è°1܆=^rÉÁô|K¥ Ðí*õ ýr]¥Hò‘Šx¿yñ×h—2}ìÈÇ÷:‰ß‰ †¼Øp®ÉÇm®ðÍ\ÈÛ2Rïëùøô_ƒÈ÷ùÇûßêZèQ÷ÄIöö—‚¨`ûqÞBxÜöû6\Ü™`áÿZ …õÈa|výádtþ7Ljðùçk˜ Gªåx¬KŠyö‹ n9•ñI—'éïò#–°oŒz¼/ê†xŽÇ9ñº6æ¶®xÏgŠo1³ús§0Ù\Ãfï÷±P™Þ"Ì-|·YGõ¹XY¸}¢u@ãÂ'Ð0>TA²F ¢‰í‡™Úû?làŠ"¯CÙÁm«UþL×g¸ÀD öx2m$0§ŸÓÁÑbA9ä—aír°åiRc¶°ª+@ü<žP‘ËébÞÊäzÖœ#^ “HVñ[¤à_±•oJ­©èf•‡vªð¦€Ã/5`)Ì7OpTKpº·ø¬¼W%›‘ ‚>æƒOÏR·gØÂšßvCïŒk²®ˆö°Ä8¤´M{¿õ¢¨Û÷Ðq·hü®y½îó3ê6 ? z}?¸R\_> Z’gîl»r1Û+g» ¨ÒÙ/Z¨îZ1¢¥!Cë®+µ[“Uª©ùºòSŽì @d\k÷Ç×tL»%ÐÍ4”&ÃQ·Qî1’Å<ó}Û€XU–’ }¼*¥Š4<›4\8á.H#lõ°@T܉­½Lâ1Wá=2iùTú€ý2—† Ø·PrÆ98T#·ç8n—‹][/ÿʶջ9…!g,ƒQÔØÁ ŸŸa*HÆÏéjúôMÇ¥ã d¹§'Šï§Ÿ8Æä&§°Ó=NÜÓK}KF—Ë¢4 ô¹›8²ÚÑÒ•t!¬®ã’}‘­ÐE‰¡JŒÒ¸ ;®yçÈìñdʧJÛSN_u³íí Vç­¡wZÄ(YMŸöűa¾€+ïI§‡ºæ8pƒ†ToG8L•Xä"•ûZú\]JT],š àÁîÒDDVfNºno0d`ÁÜ`qµ"+  Ç#bºr><„«½†ª£gÛÌÛY þ65×¶T«ä¼M•ÐÎ’MVöåú¶oZ A‚ïsº„W!hG¼Wð u u=%,šo8­“wRZÚ•·Ôw“REWN­R¼Ó´—«¾)ùÀºŸ-:wådHò@)V–yO¶Pž¹ËvÐù›¼×B ÍÑþ|{q‘Ä ø‹økyM×ès‰ôÊ3åˆÒŒÈ[Š9âI©©ê›Wóד—6NÔWȯ‰+” >×iMx‰J¸• 'm¶›PHüøà$Eè};GÚMx?"íé×Ñu6å3ìŽ$j“é*÷²y¸XãOÉá¢Aû>\Ô™çRžÂ6á¸3|ûµ%t–K¶ŒÔ{„µ¼31Jxmù±žÝûµxê¹ù9'þ´L|ospüHÕiºú-¯!žG¿Y årÁÑY†óc£m5™£c4®¤ûödJK«þÕë zW§Yð•Ì øü°4@çMËìÀlqëF®çd_é›ûaÆÄd(4pÌà¦9špGCoâÅåt˜ºyxñ#€WXŸ“Påm£OÓ9¤3ÿ¾gNKáí$5ý<ƒ Ó¥Íjj¶Ú¢ËŠéü%KE?ƒ?ï­Kfk”î_Dh\ÁÉÈy:`˶¡â¼øLý×Q)é–>Ñu„•­¦X?Šƒø²ªïäþùx4£Ç^uz—Œ‹?¼,½«5¼ÿ±ävÖ°# +“w¼mws”]W¸ÛYe36È¥êôfS ñ˜u¸FqÌrH´-y´]RàÖGeh~}¶‰Ñ±Ïú§Ëx¡9¤K Ö­E·Ð»{ñ££xâ‚5¢ÐZj0êä“â¤gC ˆø*­…˜!×qÝ ”Êa_z’ÏN(ª™óù ž~c”ðNøjô969ÂJÁˆSHٔЋ4q:êæ0W¦DÕá´æÒ¼qÿ˜ÊÀj1GªG)TÈ&#Ðî´ˆSØpÝš¨J¶) _¯ 05çNÔYŽ8^Û/¦‡§±¢¯ë³OŒòÃÁ•TŸ›EØÌ*n?šEŒŽ~6Ê^Ðî’6Ç3?áâ?V‹KX4§Z8SÿÀc4É7\ð¡»ÖQ»j‹i‚àìîOþxZñ’k:šn¼ùSýÜ}}õùg® L~Ӫؙébí#8g×VÏG #?K×UÝé”IÃ^cE<,ŸÈÚ~ó§Ð7¨©¸j±†\@Í¥%Ä~ã9üqÄ΃ãñ0+¼®ð~Ê«+Jbîé¶ÄÏÉèœï`%†+4ô¾z† ³¶ô ,E‚~ÐÑ|Ë ÷[£àÓ¼àÚx_š?.`n#ÏŽIð²EðãǶ«`*ÚEnÊ z®ËðÉtÖfg4èꊭ„ù±4;÷©?§Ž\”® W/lúª™÷]6©4 „¶4L1ïµo÷v–ÊSJ0knް)½ŒÀ;‘…]“5Õûoà"æí‚ëÊó6Ñ EP¿G ¸e¤6táM-Ä V׈«äb`¾Ãø.ÖeE—ÎñÐÖä¯uW•¸íí8‹¦ïu2˜ßðENž¢ 1G”YÂI>/ÓõVL'‹e’\M§‹Ë%öÓæAZ½ÿK7£ÅÍ2‡ƒne5öXæë,ÀlÈbŽž´Xï¨k¡%¦çk‹SÕ'Ö³–!é+[gN0ÂXIsð¼ï—Ÿ™%v*8J„£Cf€†×lþݸ‚e%ýw¨`ÊŠ3Ö³xÿc+Ûß´>ÙDš,Ó6Sžq¡Ôi[)©äÔr™Ub›Ægm–¶8Y7Y:àÔL Ài¤Â Í8”±ðqÂ&ƒc5Æ>{1D…qÕ8z¹c4?‚‰q“p½ÖKiW”lh5¢€Ü­+Ï«„ûm‚G5Ë®®…Ä G&¹­PT4H¶T{-sxt®@ëÅJ|½[§Ì/Rjuù$ÿQÈŠü@|ÇïõB·ï,/kûù=é¡8~Э¤hU²ý½¼7Øþ.Ï)8{RUöj·Ză3$ca]ëÂZdãW‹…%¡e|˜çhÆÙ1}ë:xÕ «E¬"?‹÷Á‘lEƒó\c‹2¸F™œ!v¥Œc‘Ž‹Æõy=ªj‘*þ¸[ÛÉûekk÷Vásúsµñ*¾ÁŽn4-ݸFfôŠúÉ ¹7A3K§6PöÁ˜Á¡óûB7 [žŠ·=Ù»$è'áhØû‹›Ô€aTâ‡Ã ãú3‰¹²xά(Á‘Ï|ôys2`BL”;D5¾¡;,,€B¸Á€ËL›ãZØÿÝÀ®—¹v{{ÑV“ா•Ø‚æËÔXc9ÂÁøkçð?lÌÎEÛU­b-ÀB÷‰v ˆ7âËÏøý>ç /ð­õø¦ºÄÄ‚#XÇúÖ¹GÜ^×÷='ðÎ5õ4ŸÏ:¦sÑN>þ~ªaKŽé ‰ý˜/a±ð£ÔΦs:\þÅVàü¾7cí#`ºÑMÖ ÔM=™)Ñ»ùôóÖšBÀ½\,fOùåÓ§O?†Ó³Ô/n·þ®¤1CË_.Àlò—¤³žÈ{Ü÷ón"§>ˆCõ¦ôª‰rÒ6ó.H·4bè¶²„]íÜ_y?ßW˜;(¢ûùR E꺲1¦[ùW'/SÖ¾Âzª³ÖŽÒÇ=¼Ê48é¡^hƒI(óŒò‰]áoe ; }†oüp2T ÎÒ[º°s”÷t¿+¹ô®Kv ¸zú^@ $ò×ÞYß.‚û3ñðë{]WÅP>öRܵw ñÙ©(ø«%$£òL]íÆ}F ·XøÎ²ÝÉÈRÒ­*ŸgWÏÒtøuøâzæ.Ä[–Þ³®§¯]ž/m;K9÷K›×o#äæÝä¾fðâ—3$Ã~µD|ÿ éî’,%µAÌ1x§ÿ*Ï1ôö‚ø¸zÌq «\C±²˜r·° ¸'(©CqéýŠ˜Åy1i™ö‹^,׉†éV·”W-âV¬£¯¢ ʾ´<› Z$,,ITÑÄæ—§Aý×ÄI¬ùv³ AÁ8ÈaÛ Á.#9,»‹Ÿ"6`žS}VX™½Ç«Á0^EP@Pw-ãÓÉ4²c¡I|uÉÕç«19¤[EB’O„3hhv…øNÏ÷»¡Ó_g;ü?S¿‘ì]Œ˜tö^™š¿ Îæ‘ØUà ;)ï,¦ÓñÉh~ít%¿‹›‰¤Æ6L麯±žª¬%F\£ãìõ#Æ?š\LQ¯ø^€}´ÕÛ7SP*Öpú3ƒIjfÙ¨“f©Õ®'2°Å²z§ëî:ŒŠ½M'½Ã¡ác¤?09Bú;»ŸŠ8€-ÅÍWä7ÂË¿ÛÊ8ÿ‹xÝ0ê…tÕE*…3s°Œëß6®+ãz·ëɸîmãúDNè{ve†ù÷[ Iü®l§ë†^¯ï÷ÂÁ]¿Ç?XçK»œ¨hh!jø,ÛÔ:÷5¾õ+¢å»u×¾úTôé­ë‘6Áí;Ü¿Qß¾64ùî­^&¢nUGàËèÛ¥M›Ö¹õÛ¾u ÷Ö1¼[Çð¿³x«é`U `™ÊDP0 šñi>¢ y!hr mà•Âo¤Re¨+f!W ÑÊâêð%)¯¾D‹íUÆ.ËÛ¯ŒMÓ¤¸ƒmÓ‹wGLÅNÛøù¤v‡³¸¾ð\¬"äF`'í 4p__y©¬mÀXæHU Xàjº^:(YKí§yAÏñÝ@Y=Ñ…Ñq»®ß÷»‘à™9?áºG¿=ú]s‚È'~©–¯Cä2vRæ²–d(¶”³¡¦+–¦ÁÏ·[63õ¬©•kçj´Œ÷£½[ïÛÞ æbû?¥‹íÿ.¶ÿóÙÍO¥Zø#±ÀäzÞ<È0;Ãø"žÏãajÉ“´Q±ªú§ßH&Y-àÄ·¾…¥{ÙÖf’ó¥~²ö!5Gm MPù3¨)2@›:eí_çfTÓÎñ›0[rnK«[íoK{Ú*U¿a ×BƳñUŽÝÎ\GÊ‡Üø>''S~Ý$8Ì,e²Ô?[tž_ÌGg×â&ɾ†Š 4ÅwWÏ Ñ×}Zá s¼+|8"(V– J™ôæ¹¶N0XB‹[] ð5,ü¿)\u7ƒ-̃’{çâbÙ;†q¦ÆjË2`‰ýÞckuû*'õÔ •QÂMn¯„7Äùâ€Ê¸Û£36©”Îtp%²ÛȮٻmdO‰ìÞ6²ïðmÐí÷óšxsd“&Þ$‰“òÖIæõ´E‰”î&Q ¥»)Z¥Ò½º'äÕÔÕÀ¾ú¥{u= •îÕ½ëߨo_ƒÒ½üe”î¦J÷ò´ J÷ê·}ëî­cx·Ž‘Sº<Ó57„fü×h2œ~2]sÃãyp?„@3ù‰Ve·ÒKÛ\ɵùQ½‡"Ômâ–'ÜÀ»ž[DME üÇ:Õ`•iˆ‡hBñÌ1¼’h[¢óøÍ|ù Ð4Ûº„@¤Yc@‰`¬œw®(y*ÊïÑsõ®Ó8¢îpîiáóÙøŒâw¸ÉLç…¿c¼ÆÁÇùO3þïu|-ƒ¦ºÄÚõ|ÌOñ×þ8ØÍjj¼ýä~mHì[£˜DR`«Tæ>ÈBеÄ]d¹ Ý¡8VR¸6Iñéõ‰¹åÔÙò¾QDLc%\·ˆ+Öæ÷C1,I¤0 qîV×+ª½f˜vP’ùãÊ>Z)á‚÷!w_Ò§›0ªvÏ¡P¸%ß=k½úž0Ë8èãÙ`’‚›ÃᇮOt B5<;a°â ¤Ð™èáRðN¨èÃ0/uÈy¦S'u®¥eWÚ9~S‰ð5pËÄ„:'Çb—9îƒâ·§È\%p0¡îJël·Ï6éÉ¿p“¢“žLy}2*}‹œyÝ÷² Ü7x‰x18’˜ÌR¦²Î%¡˜üù-4¹€Ø¦o/‰•Âí !õ|”Ò™Šû¹þ~ʾn¦6ðŸæâû΅b@¿<èI„ÖÓ™xn0GH"Ø:ã"%ð.FÔ윃Þ3t v‚½ìÀ“‡Ù½yvê!’eyeJÃfÖ4AQ5KcÝËkKääßç4 u=9]ÑIÔ  ­NE°¥Þ‰)¸üšùž„aöºžë“,/³ûøôü°„~T‰*²a•¬+‹àUȺ"ÙÀ©*‚Û•²UEpY·BÖ“¢N…¨ŸŠ:½ ÑHŠV¶¿—àŸÔ/òƒ•}Åë€oSEs‰± ®EÜê2xÕeð ËàY”Á«.CP-V‹ôpg*¦oQL¿:ƒ¨º©úÆœ²—°ŠÊÀý™Šr¦ŸÊ|‹²w¯Ðº,®EY< ßB&° -dŠûJϺÞ6uŠ,dú…e‰¬ËbÑvn·º?Ðiv´oÈ‘ïUUåqeŸ¬”p«2qWV´R©ÊÄ«ð«¢*~ƒ©Vâ¥Èÿºì*ä£;Œd£-q§û_œzN}-dW9Úݳ›ñ°ÆЫçžLWÒ†÷ìf™ÿ®â/ 2ÖÉt™ÿî)¾991·íÌë½ä)ÞÖer–w‰]tص¿ì毧Hã ‚@_à#h<øì0ÿHr3*쥩‡b¿µÅ}Y«ÐºÓù>3b2%³C+§¹%åªÑísüý#ÃýŠ-JIA,aóCLؾ;Dàˆq«Êx Î@ãm3™k¢$évª;Òz9j)7;šœŽâO¼”6@ƒÎ|ë€ç1ù š7V4Êûc¦ ®%´¿áp±w…÷”¸íÛ"3ÀnÒ­‚„AÞþÈIÁ.FL]„¸6q¶>ª­úð> nê(›–¸>Jèô{sH•oÿÙA¿ÚËØ¸ }#¹ÔhÜœ½RÓ¡í »PQÖ„ñç-,Ì÷î †Ú•­“©bz¶C™ª¹”€FÚgoÌÄj0àÁËú§j+Af…ÝT(СIМÏã÷Ѓû©}åôà9x–3›A}Q,ìºm‹zaä†>)SÕSJÏ.ŠÇqƒ k…¯¬ÚÄñÂ0ô{nÏ;?×8-Òë;ADw8ág¸ÄàHB€·CœÐéa?ò»Ÿo®Î¦ãÒªÁÇg:]Υ߶^+D×}¿Üª6¸‚°jc‹Ü]ëÔÐ@‰¤Ð –fÉÎúÎ-³ô,Rs­Só-Ró¬S À§¼Ýk°”sºU7Xb=y‰õ_öã.ó®j¸gnØ%›žß ƒnßí“”È__;K‰˜cnþïI_&Ù =Çéy^2ÕF€[½n·ëû~¤ÁÂw—&Õzn7ì3™‹ž ìy®y]P–4éXï:Nö‚ÅÙ‹Ñlj"Çíwû}gq†×ŽH/ð#7è»Þâì5X2Æ;ĉúžõº}_õü°MéNØ »Q(|®@Δì{=§v]‡ÒÓÂl ý:<ŸÎé” ¸ ´ÛÈV)ç¹¶4ÐèêdÒÂ[)’¤žçâ{ùønQ|:0²²èÊÅ$+r21ü¢Ô=CíÐÃ@O#§9ÐÒЯuò MÂÆ¿(ic[”¢WÂóó¹õŠšÑ×[EìÊr-h=-Ê·hÞ’LyùröAcRÞ*nI̓^¨×»~싲+˨W‹ ­¯w|ƒï!µ‰´c¤ÜŒ¨ºt‚‰h]™å𙝡Ïs+bv»‹sÚ›ÉVÄüUSg§ueJJ½¢Âz?‡¥²øQ _~Ö'à~’;6Lp#IëZ¨ùü2>ÿûÙô37þþÂd(ž‘éÀÜ8eŸ(NúÚh_žë¼ùó$ã3ä{aþ=Rã¬h 0âÏéç‘îÎX«gµº aèÇ2Lyã‚ï»îeÎᲄèz?øfïÅvæÒ#'¯ÑOÁ8þ·ÏìñdÊhIÚ_‚öŸ’öŸ'Ó†Ü3CïzTf1{Ds_ZxÑÈq 9^!‡ÎáMq°¬/ddêWƒ¿ÑM Z­œÇãñøqFŒð KH L.¦ËˆGwôbý2F²`É»I7œt'^ßÈ_KÉvJVÀ*…ƒíLzœ¼–,÷5æ²ÌvèF¯Ì²»@«é­£ÁØ,ûÍ|šñçv&óøó#^=xñï&øžÀx;ª€BïpúÛëÅÛ 1_C´yaJXb=pÓÔ-W±‡1x:™²ßg7+Ørmë‡h‚\í¤Š•n9aþ“jä\¹Ÿ˜h"×HêJu5}j§7 ѧݖ>ÉФì®ñ¦oeEÖÈ…x<¸(Ž·šòš„u¯öœ‡á4pM>®£ †y½Y“©æ(&bS•²A¿BÖ}H¢0 /3 ¼¬(¦%ù®‰¯ÄwL|ïâô¼(ìw?W–“é,m )tKäÜoHJ9^àG1ÙR®W&çÞ/éœ`}XÜ=ÁüÑb´Ø‰ù¥y¡´ª×•¦Pž~PÊ K¹=‹²õ@g\Uþ®c#äÛ6B‘jŠûI@Ci¸ny¡M^y=›4Ðuvq‘MAy}›4ÂÒºx]›4Š{>Bm„üÇ•ÝàaÅ\_ÁwUMëUî–q7RͲ޽²)ºŒéÞ/K¹nÆ>bŽ~fÓ1c>}}üì(%Lç+xdK‰+ô6ü2݆œÑEêž%®íÜÏû"Î…gÙƒ¬'B…÷¿*VU²Zä}}¦Þ^~BzA¯õ\Ú[sLvfµo`0?f :ÃÊ*ê]@¾5§àÙ¥à™S`j£/ ×4ñ_„²ùJÆsUf®EBž…Œo“™MB…L:å‚þ©RÍ¢ê;áb7ÛŸ,ЗÜïq<Œ‡u2†Ã~ÄõCáeHíµ¦üðé*1pû~¯K?s…R9K¾¨öœžxÖq”H®u$W)^Ï6–)´ä)‘ÛH¾ɱ)‘º¶‘úèJÖ éæ,Œø.ôõ)fÕ]8^äøQ_í ¨Ã¾‡æÐ¾vÝDÃm¥4Ú–æhuÚ9¿œO¯bœ@ø ù}I=TßÁhP,*N¼ž”Èð5ùeÉdg§¬;Y˺ÕåtoSN÷åônQN¿ºœÞmÊéÝ¢œÁ-dÃ[È"¼IyüÛÔÉ¿EÞÑ-Ú¾_^ˆœÝxU¥èvŵ®Tzpm_ç6åµáíËëÞ¦¼Þm„ýÛ·o#lÑw{·o¶[µDtaÜ© ¿æö-ç_”¦(ÌÁ*dÐͶdßÛ÷k{Q×:{IÏZÒ·–Œ¬%û›¦C;·NèäWn»|k·]þ/” U4 Qað6…ž•R—ÐM¢[\Ô s¶Å†Á·¦ssô]—Ñ{HÌt 0]À×l²~(’’Ö`ìx†Ê>*’«žÂ,5”Ý\qç|·ÆÙÛ~Îûa<=cx¶áþmÈ«‘ÌãöÎádt`§àJo貪¯ôcç©;ÿͲ>´Sà^lùˆý®“øjv9€ÛÃ5ùØIñ¨ì ¾Ím¤Ôú?}s½à&”Kä Üò=Ö,7ÔýP<-“áô8Žÿ^#£œ‡Ó—°FIïãñ<‰ëd4­zÚM`ON 3˜/âsuÓðT;gÛ5k‘4›“ÁüC¼hfÂuãN¡1•4_°ÔžÅƒÚ5¬+Ï‚ñò[WŸ *IðyMy$XPL=}j0¢8Ö«ë!,¯ôpm8EMÌÇÁ¸™Ðù†™û3pf§‡¤Fzk«ÀÌÍÁ Kñd{0žLsd°À¼ž©Ú %VË»X©Ç¥Èп“¨çG~7Œº$Ãâ¦Ýï2䚪}?Ç>_ý‚¬ÀÖ&Ë@A×T‰¶æ€¢5ËÖ¦Œ¢jç<¡¿G³$î<ŒÇ‡™m)½½”—¯]p;™ûÅ.ïá]‰çfÈ×%v+*kׂÄS+œQƒÔÏ„n¢× ûON+ñ ZÜUÄÃjqOïU‹û?€Õ´ëû¡ß7F=-=µ=­=-=µ=µ=µ=-=­=-=½ Øè©Øè©ØèiØèi5ØèiØèi5ØèiØèi5Øè©Øè©Øè©Øè©ØhEGPgá[£|†RZSe]—|kdV<³c‘âŒÜêønY|¯:¾W߯Žï—ŪãS‘uîÏ] «ff ½g·.Nµó"'åä¤ì-íÄø Z}>Ÿ‚ês(¹â –Ò×ÁZˆÛî<4™ø(ü:_X³ ÅqÑÍx¥'iïÕNÒ vxžõÏ+ò½ì™Z«y2Çoç0 ±8÷uÓÓ ·~2€†å ðØh¥J´X¨³%#ò= ›D‘ZI†—™~¤ßê^ä÷û°p¨í*Â^•°šre)\Yb§BVŠhJ©h(Eà ў­j†þפït=7ò¢¼¤2“¥bý21X[uûNßqž_&È»›"T‹»Û¤ßõ/ò£S)°“õ âô{¾znŸ‘O¦³û$€KsðO¸I‚¿v$×Ésé²Ìëƒ'ó~è帧M†2õLd´Ãñ5³‚ vaôuÈ•¸¥vìåk,‘m²²My/D¨”ò·Ð#¦2¸ep«ËàU‹øÕ"¢s˜ŠéYÓ¢ auSõªE¢Âbúxi·¼˜Êš¢bÀëœ=§0½XÜû•Ÿ,ì=,' c†1ÍÉ®Ìna]ëæg8:_‹öwÃ%—#W"<®|}•N¥€¸”þ*°J W%п_ÚUJ¹îÝÔBÆ­©_ŠÕôû°aø*hn'ÿX}5=¿N Ü㥼æ³ßþxOÞüñÛÉѻߎ^¾oþöîõ¡Bh*íP –O,#±G2µAþ÷µÐëõ½ —Êɤ¢a¹¨«ˆ增"ê—‹ªeõÊEEÔ- Óov?è÷zž)Ð¥mçèˆ ð ]‚t{^è{ýnNB髤߃Þpºè'ò=· 7ÜiŽ8ö ò°ë‚w†ûÌ,¯à›ð¸âœRþ*K ‚ßñò‚TÁ«,^M7½ÔŽ7<^ë.(ºgÛ†ne‚Ê „¦ pAYÊÚÞ¨b› x•èUJàÍrÓ@õuq¼¢7çÙ–Þ¯,[ßÔ Æå"¨ÕψvVD®à»|¯‚ïWðƒ ~¸S0ÇÜ+ë{ÿ Ô2Ÿ¤~.= 8Žúù@#|d§ex0ô‚ Ë#¢XAqAJXC²«˜9÷âNz{•M'æ€îê¢~—î9UFæ½I9¿["ç*rN‰œ§È¹%r¾"ç•ÈŠœ_"*rA‰\O‘ K䢇tWL·Å]Ç¡[ûŒô› ˆû)Í7Ð-4ÐzZd õ¿ ý¤:¡eª®|¤ï‡n¯uÏAb—Ð ?@Ýø>#¼¡ºù¶©²à‹"—-ªÿ5jÁ÷÷AYÿƒÉ³¤Ûs¦ß£‡e9Wäé•çéóDÏEkŒáÃÆ«²}Üò²åe 9%e¥ùb„%1ž^Ïé*( c'ÙLƒŠ#ùMÒ<Ñ#n)=à}œÐN’Ð6;`Za½ƒÕЩ”ZÇdXìfr9½¦uŒ¹qQƒA•BŒëÚç°BCíÁ¥Öûr"¢ƒ¥Ž|•K Ù dþÖRÚ3ø1Hs,Òl„ÝÙ>ÂmA¾ÆÉèÃQB¾«@FÐLF¶b­ßpê—0h?y™ï‰´†¼ •6%ÑLNKúÊG 2ýÆ–£;œ&éYK¾šÎy·}’‹N*tÉØïh}Àd ,rÀCú#5}¯ÈScÝW’,÷K-º0šÐcUhxÍl5‰{Eçp0îùLR_tÈ£0R‹!^×*¨ß79¯Á9«Øu|WºIQ%Wi.dzË¢M>² ®6šrŒ¬íÜ,ð`Kkø—wÄ»@ C¯çøNˆá{ùÛŠÓüF¥=8Yb>³–§t$ÿÉÿZG#8† ´~.a"Wè—N» QC³Ú9¬ Gq:¾£s¤q /æÝtöÇ Íÿ–hÍ®F&½Œ§ºï‰ãÂ%?𬻼ŠQˆå¢îcö#ºqsÏ lÇLïoÏqÃ~¿ºJûuˆÓõû½Ð‹BÑßå(„Ü+(B!ÁM©ã¦ ËÐtZ)zE)ºå)º Û1Åó20°Eç=æØ~y®^aËà•¦,'‡0Y9(*N`JÕ ª,ïžxSÚ+‹òqÆ+Í_ÑÙ–æáUJ°“ÑÒÌÜÊD‚J‰°R¢WÔ·zå½Ã7½`iIk|õ!žœe8 pž1R¯rúEï8‚ÍXq¥‚¢Æèƒ.Ú¦oT¿´¨R¢ojZÑYÕk<“ˆA×Z.‚†Uæù²kšs ‹‚|;kFÑ+JPÁw ¾Žé‹ê6.«´\?žÀf x÷ ¶ì’»M”€ì¶&2còkÜM¬1[P.úõÞ¬Ž·=º’ˆü 6Yr5..ÿïõËÍ™pNëñ‰Œ¦/çóé\¬ù4Þl>ý@—N‰XbhL, çD–¨ƒìƶ9{åu‡[„ý>Ïa« ¦`q×màùó½FÚæË;ýUnä Q €àÓ²ëÑHk¦Bl¶‘†¥ç…M¶3ƒmmIî9‚;SÐh[tÝ>=ÏRÛà¾@—ãîèôŠpï|€Ä¨Ô‡ŠxÌ[À½"6,ÿòëTèÒPIÚ“tÅ`wy4¡»-è?Uysפ¿$%L±ôé– Õ©¼x¥j•žgŸ¯Ë+dpEü‹f4™ÝŰ阉Ó¶Akg´Ký})4f1G …wžˆ ÝõÐáž,“q<ù°¸\¥;‹ßð©MøÝÁ7ƒÿ¢MJ·œ­,AŠŒ&AX#Wâq5}ª1©©*©~%«éSKßâÞ§™ ×è¸KKUK”ÀÒë·ÄTM€qeÊœçàÒc}4y ô|:»©Ó?‚‹ZyzÛ‰ÅAðT‰¦á‹ñurùŽ5(w³Œ o/šü…'4-ô’œ"9&w1'Ã6IQàðmR× ¯ø]’áå·I\Ôë—‹ºŠhT.ê)¢½rQÿ qznèºQ/4•68ŠˆcñÏ,<¦eò·ô}?'‚“ƶ‘ìšÉž™Üÿ‰fÓ£[Ï| f%rÓÎ6øC½^Ðõ馛ë!ö> ‚1i¯)êþ!Ü#½^ÀE5W¨Q8ç€8aèxý^ÏWöØÇ~ŽâÂУo¯‹oP1Ö¡ùô£¨ç̰¬Ï9¨v‡xý°:}?J¸õú6MÅ £¾YwEBo3;´À®v{}Ÿ©­x6‰ë¸‘çti5?Š+¥ß[μ6¾Ëb/¶ ů/ÞfÙª.½8K¯ãƒ«´,Gõ†‰’ÌË `½uDß—™óözQ_PTy„`È2 [Öò©¶¬å3DQþ^yã£ÞÀÏÇk0¥åV¶ºåSReéý¢Ò#&_åH.ì¡)ºÑ›€)óo¿d3çƒÑ)*2ú5Ì5\ºë5rÜBŽW”Mîºs£F sôIAÒQ/úõfŽF{ô~.™t„ÐqÊDRE,š¢¹Ä}X—U½KÆË‹éá|>¸ù®´1ÁI×»)ëCÁQ§Á)žÆZqŸ*²p¢å—PïÑù=£ãÎló7'§£/ A–¥Ì$t}׬_’cfæÑŸ@¡æõÝÀ鹕ª´W)íÊr„UÂnš²Û­,‡ÛU¤+Ëá:²A•°'eý*Y_Êv«d£T–îí*dûû ¾©úÒÀ2 ¢W½³déQTצ®E9<‹røÅåðlÊáY”#° -dz`>`.«oSVß"È¢ÍúæÌræE… `ÍVUØtµ]•cSž’ڗǵ)g#äÛ6B¡PIßéÙWߪf‘P¿¸<‘}ylÑíZtï~2Mñª*ô¤º›V‹¸•ù¸Oªë[-âTæãUJø•Q¥DCŸÑe͘)8g4y‰mù‘›k@Úß–‚f*‚ß3=5iJO9~(’¤kÐd1§«P¾U`Û[;Y÷²x_¸Rö=?>,ä_÷¯ŠøšÖâQ‘” »/—îDS?†èó¶çí½âþsnQ”§…Qþq½8_C” tñ¹:{ö¸ ¦Dc^Y\Žˆ¹Fûf¯¦Oè•Ó§m$Bäw˜Í„¥ÙÌP¹_Õ?Nž×Áþ‚n8.aU€UÔ¿âøïáàÃëóxqM™ Îã5öŒåaG›\‚ SJ\O'à‘°@B¨ZšîÇÏÑ¢…ÛlWúbôa´`-²Æ tøæÝ›¼cÉ\ãµÓFxû1žÓÝE|rj§Í È;™z z[¸ŽL“\_•´=–Ø4Þâ­Ñâ(ÏÒEP!fu*ò#qúAõ¼^·G²Ììrâ{âÉ{?t£ ÙHŠö+Dûß~໎E~^TQÍìå¹\uø]žSˆRTQÇj·Ză³Tca]ëÂZdãW‹…%ñà*oIs;…1}ë:xÕ «Ez°d®ÈÏâ½E`ÑPÑ™¿rC‹2¸F™ÂU¥Œc‘Ž[øvŠ÷ŠZâªR>ªjË*þýÒ2ôsê—Œ©aá¬GšFWw1\ðÓ*w÷§w÷§…îîO ÝÝŸº»?-pwÙk %ž<$±Cô°˜ôŒtŒ’2ôìÔT.à¤ìáF†®Íß’ãÓ?”¶È`ôËM»ï¾›~ŠçûF¥²VâϬ[@ˆö¬!D{‰Ûu}'ÂÀgˆXˆÂ5ãpúëÑž¾"Û6ÇÎûLàç‹MæÖŸ‚ä_óÁ¬¡&Úù#9ÃåªÜãa\!ñ0—·ní»I>Bvlõ œ»ïhü"ᆵÁÒ@çÕ‚¶—'ñ:yNƒ®kÞL‡â²b“]ÛK ‘7SÿÑÉ"a-ûèµ\\„ÖÊsÊjaÜ/ìvÄ-Ufz¬£Á8¥÷2M1¸w<û¨±gZ#Ú¾kpSœÝóõnég"¢ó°‡줔¿èÄêŸñÍÜ$¿+Òü¶XSžc?{3˜±­ÝúæÏ(³.uþ\“ ù¯5å‘\ fìæùª|â»)Ý:­ˆ‡»äŠö•;ðg™$´oÄòß¿„‘ÐÑäFBá|äõzQЇõB±¼‘ˆXÇr•X¡u,O‰Õ³ŽåÿH܈þ®WI³2‰è6Bʼn(V)Eɨ6B&™2!“|±Põ+T,nªßœEÝT¡ê²æm„ª;ÂmJì[”Xµ*ªI2k#Tžšj#TýžìE]{QÏ^TÚwým冻š…kÏ/´Å©Y¦ÆðEø½úœ\²çÕÉ,ƒéžÒÓý½89.Ùß ¹KÈz ø"Ï)ÙS™«-D´JÖ‘ÀÃ<§`šu!P³8O¿"&M¹× `™È!­œyD²‚P‡“óK®Ð+˜ïçÄ,û}žU|ùÁ(ŠzÇÇhnŒï‚^³$>yßÀÇx(=ÈsU8ŽÇyvk㋼DîVþA^F±Ïñ„*µý|:ëralmóP_ÿäøwÉÙhÜ?Kä|<¸šÝÅ¿+d8ú8J¦óeþ»BW8‹ùèóŸËüWþâ„¿,nâùGûQ×B†+ŽPrÄ”ÁÞ£aZÄ-T!¿˜^  ×¼?þm €°p~=Ư¤uð(W q~2š!'‹ ³ nt üùcÆ|í¢Ø—y_»y¡¨êˆ ˜á _Ä Ä”ç«‹¸ÉÁcð°œþy‚ŠXæ­(?Íó á wþ8YÐñ\&ñ%wV›” }ÉTÈÔ“›g©>~Ex?Ý7zÕ&Y°;ÄìúµCrŽ]QÍ;ë7å~‰Suqßn.}§ßG”€ éZÞë;£dI¥Ý~µ´¿o”ÁÖ)f¹Å¬’ƒbVXÌê³¢ïH¹}ÏõB£Œæ.Æñ¼¨çz^/BÍ㛫³)XQÑÊí縮äFÝ×S¸NŽë+\7Ç ×÷¼l¾®,•ïùÝ×U¸NŽë)\7Çõ®—ã{x?¶ÒÆ@\ ɼWÜYþ¹°»À«ºãZI!6`ÅË.+‹_Æ Ê˜auÎø5+ìÈÕñƒ²øQuü°¬ü}X=™˜9 ‹×X½¬ÐJªg%YIõA VØI»vMà‰åÌHlÄ;1×N̳Óˆê!g!ã?ªnü„š'¹y’—'ùyRÐÉÏŒy’›'yy’Ÿ' }Š[“¾Îw3^]SƶªÆ”mòm¹ŠZ ÒrèBÓïÓÏ1‹ä:‡Óëöè„ìõ]»jÇ2¥\¾UWfÚ• n¥QìÊå*U »–å’Q‚¾]O©}`EZÅðe ß®&‘î¹ú‹Äøwú»"~îàé[»~†ÙVMœ=ÀÈ/,ËæÚ–Í³-›_Q6ϺlžmÙ[ÁÐV°çj%•ð­+áÛfÙ6p¿$ïÜ}©ÒZ`Î`U‹T‹b™³c]ƪ®Þ²Œ®u=kIßZ2°– ­%i_¼U Ø×+²–ìWô¤è–oɺEᦕ¥¤SÑ“ú%yêe´~‹®k]:¯¤t©ùIQé³H–yúÖ¥ `-lÕ¾±œ,å\»lÝo,{‹¥œeñ\Û|=»jXŠùvb‘Xÿ~¡Y ;Æxm>Æxm:ÆXEàê§»)¯.Œ–á@GÒx»ÜøõíÙÑ!z|9€Ã0°ýBèçñÓ"™¼ï'µ=öÆp@Áã¾ü<ÎG‹†‹Ë}‡Co&£ÿ‰ãų›“›”Ž—hf×ãx“«1B%ý¤)þ…ï*€¾cü—ŸÑëÐ9C|Yš"qãùñ1>3õ-³k~ ¼5»À>´6€,0oMG>{©*rmþ7*ÿ¬œn÷œ¶÷ ó\à4ÀC–ä4&ñ'%؆®Ý2µ³_¹úÌjÚzPïƒ+0k>/@ÊÈÅnÊ$8€îëƒ+Ã-hðÀºÁƒ{Äu¯ß ºá% Å[]62Gù˜á¨TÎZ_üæ„@%…Q×”ã<;óuù™Pa/ º}鮂jñH÷«ÅûJÑ«Å]E:ª”é~¥tOJ÷œJéþI$=ï7ðr»ß/«[l&*Û})šËâZ•ŵ)‹g#äÛ`ÄWP`ϪÀVe m¯g#•ØèÊ+•« rªáÂ"·(*ã+ss¬¤ìÒò¬¤|+©L±,kj—oh%Õ+é½[´¾]-#«Ñ/è|eL!·ƒªÎvžRœ%U–ù ‹Žn!YÈô«‹ãV‹„Õ"½j‘þ^~…Î Ü-ËkX¼ ®ÞGÑ÷žö¢ÐŸO?[ÆsXFH¯¦ù½ÊÛÆñ|@Ì£á[º¢F;°¤6]Ò=¬‹•”›f’ + }`±G‹Æ7mø};y!¹uîÿ…ùýèÐZ h"ˆüÌH-’Lç f¼†’ÍLxKƒ(»Œ5vÿïܶ”¸aiÉ0Û¦ÔnŒŽ+Ð3î8ŽaJx5Ÿ^ÑZœMóážlDñ¸œ}v15a¡»q=tƒ±pE+0äöÓË£Ü:/y;ß0”Ç" 9î™`o÷°Ã,ñjÌ»]‡æ|vóÅXùj‡Éú(a×è6®¹@_imštCƒßOÞIâE`±°¦´<¬Ê'ÓßG˜‡‰8YŒ&øx0ü¯ëDFýƒvo)¸?œÆ|‡À]禂›Ÿ9çÝ¿® ILon!-ëp’£oBÉ4·¡ŒŽ×UŸãû·n‘.»›â–˜Kìg$À g5“Íçü’Ö¶øÑ ðè ®T±Ýë,ÀÚì϶ÊÂ.»6¡MÍÂMùˆ,î_IÕ04iïâx¹êçXóÁÒ™a¥˜ž{’‘iöÝ G¶ýv%7M(;— ?ÕÛo®Ç‹ÞõÅ!4›ŽáR\`¥,0S5GÙ$1‘*qÃ@»ý=õ\&üP%O|÷þ.“ «øo|‰–Éõdôß×ñûYœI˜6f|*Í]ÌÌÝ…"û%PœƒËìÚâæ¶Þ{í.S‹³Âа›Ÿ”‰BqY¨oÃü×õR[/÷ÍzCo¶ ½AéÏQzdɾ'õ™Ý0çíþöô§"MŸ—R2ö2Ç$É®`›–Ccá()/ð¨ÄÒB ÝÄ5ZÑ[^vfÙ‚•!A1ì›:ûYÞ2ÚzµWo–õ&|EEëêM£v”3¯ãú-"ýnßfY?Ô:•v¯T¯Ô›½Z¥£'|°œŒµºÕƒz…ÉÓÔVl×z&GU>u Ò+`Ë« %£ñMÌ8ªÕ›z¯¤µôm>Öšôs³wb”ÛÇ.Z©i´R+- ´šÖkwzR¸%­l­S…/+A“ª ­i´êµ§ÐÓÚ×þhŒç½Û4ÊdÇ(PªÔ[ú hm­ÓØ(×Ojõzsü lC£)éÍOPŠÒœ' Œé×ÛÆIÝŸ¡…ãvµ"3m …¢%püÒ™ŒeÑNWbCdúCœ3Îh }'ÄFÇsqÓ¦DŠ”{±í+ ¡gáxC+—a<{ý°“‘v½‘á¦qtÜNÊØA½Ý®WZ¥Ò«5ýP×Ë­ dÐÂÔaEƒ ZéÃQ³Þ©•c§™³IáR½VÖk-½wr “*M0½zÓê°^k·’¨Âô0°nŽž@ùÞISk$(ÚÖOaòèí,Ű£è±›‹·zF f QÞ"øTq ó@B¿ã·Óê4>êKm{J©”QkëP—ïQSoµrüb­Õk•šuè†&T°ý!*ÖÚF½ÖÃ\­§Üá8øä\ @'+}Ûy¶”Ò™â™;‚]l˜q“ ó„7æ°E¥cئʼÇYapã <•V!¼e 1Ьh[íÊ!´ªögYê)Z-=1º›:ÖqÄ%ì¹3_L}Ÿ9¦i“øôÐ<[\\ÀŒeKÃöVÏœœ™8¯a #~çìMn0ª6;&<2ÏÒWK‚ÍA­r¢u[ÁþøªcÇNŽõZO£!‹^]šSPºDU;í•›00M®˜<ð¡¿ÉÔ0/Jëhó‘&aäê'½š~¤a™²^2ªZælZ»ÞŒ•#£Ý¢-#‹»Ë@%§dI±lÁ6r 7åÔ] >.ušM½Vê.ÁÓK¥[1J§Ý¬•khmØÐj°4kG0H£j´SžöZírRƹ™Yõ¢VC+é˜ëÑNNaW+ÕË:Ö˜^¦Ü¢Ô–'zËà¥!ëͪÖ^o•Û¹cÇÓÊz!<…\¬%{6Í:⪎ýø,Øá‘è&¦2Í¥ë„@ ˜ÏÌ$ƒ®æKÒ:½ýÞîÆq½ª¯ëµòîaÚ¯B íHïuúEx”B”˜Ù.BÛ5d“d—Bu\pЬ?µ9üü£QÖë :÷zøÓÐ:-ý Û`-çMƒí sp 5¿÷¹ëÚm£ª—·½ÉÕN[Tµå¬Wà0‚º^x¡‡J^¢ë5.²i’‘æ½€Ùž¬Ä½žjvÏîz§-‘.íQ¹UÀ8v˜ÜMïvƒ£A†“|ÈhZ­1q¡Oz³žl75ÜÖ9ÖŠC'ödM‰v‘=šÚ¶‹ù¶ZbEñäÛf#äb7´Û{·Üd0}¸„Îpö¤x\Š<ŠS—¿P[ÞšUbÛ”Pw'>D" },ãK¹sîÆòá¿ —gyLk• ƒ×i”ÃÔOµzï ©k8åI§fÐ’­kU±ª«ZóÃodBµ^;ªW ­ÓæD÷ì\›2‡Ø ÚZ³ñÃ`ѼšÖlâNX÷¼Ý} LßN^Ü>Öáa”pÂOeœ¨âŒå”d ~3¾ºÕ‹a~õZ°PêGxÖ6xþDÄ.TnÜKåž­NÃbI™$vÊ‘]Z„@ÇZ°˜›#PXGX|dŸ\Ž€vD“•xn¤m™Ö¶:íýâ£Å%–wïÐh¶ÚЭªûÕcÊFy|p^›MýĨ•ý)ÙJ›ô¤=c^^ª}·’¥ò¹V½Ó,-eÌñæâþ@›Z×c£ ˆ?ýûö1,Â,àÞª:ã=›4”3Ý éHöP[.4æÉ±­,I5Ø“43~2Hf3"¢ßØÁò hmØJýoþìvÀÇZ«EØ¢/Ç6ÌܶvPYjòwË“‰‘E!دWtòc<Ûèl^˜”¯@Û@S´—Q¯Òx»QÏ9ñGœ÷l!î˜47ó¿–@‡8Õ}ðg€ZÐ ½]ä·¾zÅg<…XµÑ^Qì9 ,‚ðÆ½Ñ N«È ͤVŽó Ø:®×¡a  pé§z ÞûÄÍãOÈ6àˆ‡î¯µ°“šHIDq÷ì5ê¤2·9˜´–Ê #3œ÷/ˆOÚ¾M§°q}/¨!9hs”Ê!´ÚM P;Ò³K˜n—a‰|8¨4cöícZqÙ[Ð ùѰYœ aYEx JÆihÄ»‚Œ/$Ë0ˆ0Ë0èÐýÑÃ:Œ¬Þš¾QÕZÖÈr«z€œ§J€E4Ý/ ¥×ƒ> ҿѦ^…þÄ`X$µ(PÒ+•0fÂ@LäÂpJ¦ÂÄ<‚Ú$úg@¼`TOg&œïÁ ‰Þ #ƃQð@D²U €v‰1ÞîKÇF¥%*¥ËÑx­hAß!\3jë€ja–ÁOt6š˜Î dn†h«!OXLv hCFQ˜x¾i°¦Ò.s³b!ËqEd¦ý™}i9'#ç²Ñâ‡V™›f,L9—¦4¡·Qª€VikQ8Œ"ýÝèx.ºa±Ülà!jê8eõÔÙš¸Žì<é>á<0AÍõ§*!=7™¿-©´’‘¿ú\œ õó'¸ïÃôlØ¿7ÆÜ2nm¡[=Û:wäµÀy ˆ¾5ÏòYk!éaÃ=_I¬’<ý»o'yPÉgßΕ&33Îp·˜ÄUÜxZÆ'=-#zÀ¡7‘‰PÓOø<‚¹ ÛBÐF .óé@Í•oç0:&Ë{­Jáó49é_#Ë»mâýÇ6L×+T…¤ž€dÊ"S+R¾ãÑ©"ËùäÒ4Çr;`:sÓÐì]Ѭú ­Â1piʼn lMëÊŽ‰\¸ø¢Èÿ›x’y0bÇd¿ÀÚ :P“Ì+YRˆl2Séf0V3)5èÏœ¢ôl¿pÒ-f 1½SüŒÐиtœÙû?üaj¿ì­3™àp”p׊»»o_¸;WìKâ÷/\¾ÝíĬ[“ÄûÈ.Œé¥9áöÉ<;=¢2.—"áN«• IåXyákÛ¶¦ð­v”05â…D´ç‹ƒc`ùWQ‚6ÐyX‚ÁMèY­¥Ç)¡ ý [ùÖ2ŠF“퉂z&¶ÝZLÒ°rÎÆG{çÂR‰G4á­zF:° á¬ÖË‘ÅÔ™Ãv`ã G€QÍ¥*÷p˜R <îI™ÆŸ–üh eŸ*'‘sM#ÉJm¬UoÊã'ŠI|µ”pÁP6®Ð\þðŧçVæÐHã°Ûëà´íi3én:XõQ–óç\o&^‰Q‘&áUO{âvÀµ…,èÇ'ßNè;}âß¡^Vˆ‹†cWx´Ã”Ž•2NÜ’žظã* YXQ|ËtpÚ ‚Wûö—öÍÌô\¨JÅz´;ÒÍp4é{¶ù«aÛBúªw¢5kx3°°‰°fƒø'ý9¢%[œW2„DÖMÊ*œ^ˆœ1 ^¡7µÚê40V€Î$½˜ ÛæDr³ÜµDØujjõ“ZÚÄ„’54;Ó/SØ×#­Õ­µqÆ"p¾²Cƒ›©Ó¿¦ºWaŠ:ˆ,Á³q)ëÖæÚüF£'Ä‹(÷¶Q©èG€¶jÍ£oä˜97Í‹þX›_,p=PÞ­ƒÎá!Ìa Â×)ëæÙ0º9Ê9àü=âŒïA“Å Š<ä5Ç™j yŒKµMùè\Ybû½CäÊËÚ`¾ÏÈ ¯é‚žr¦Ÿâ¤êÕ{X¬%ºb„Ô̰ú¹0”ˆ¯Ù¬M§«Ö0`B°ñÄÁëQmÓœhŒ›·ëôZj1…M vfsض¾˜Ómìö Ž#Ì8؇Fü–Ì-Ãé+/|³àQæÉ”½òà [n•<ìæÕPÖW1Ïåú<0È–FTw¨ÐÖ8oâÄÐúÊn7Ò,v I#¿víúÎ3C´Q!nþ0ÑöA°¤‡3[•ËðI­âš“Z‚Áà¹{ÅmÍȆq^¶¦f`¶ÛfÚÃÓ⻃©¥{°ÛÝù1zgÞVæJs ü Mo –€h ¸„ì…Z+z¡<ð†Ù:_ÃA,”–Apé‰^[fºT°[ªôb#ÿÔBí%Ð3ÁUYÑžç"iUS^ˆst%SæÅGDsK«[–‰Q÷k¢°þ>nÁcã°-ÀHšmúÏ;¾iõw„Ä{– ÁÉo =Ígw9 D/Ĉ€{rxò‡ánàoS°½‰Ù!üýËÎþvà³e*uUé…$OtýCYëúbë±?Ú£´ƒƒ'Kpn$Ä«ÐÅǼ娲Û>¨*™¥ÝZº¬aO=ô±­v·¢G©‘ÌÔ×hw#Å´ß5 æŠô'VG¢ºEœbzÀˆ~wásÒÐÂ{‹]"ká—Ë?ûváï¾]Rû¨?]]°ÿÕüá›åJZ ˆˆç+K–®gŸ g#‘ýÔÀÔøEï·Ôª„›‘@•ŠHˆ§pÔ-–òÖ xiÂMҧõ¶ZGN*J$°uU)æãKìÜ“ z“ÚiÄTZg¥ ÒK"lÊm4ø’!`¹ÞAú—ÒR˜æ‘äKR¼ ÑBÆž4ÀUÒÂÉ©ËOK³J–H57忣·'Uzù¶›ìmcNåò4ôö+¡ë–_ ý—]Î×i¤ý¹:3Oùunñ‰›Ëy w2þLÐEÁªQ.WôØðRòÈñ¤¸±f^ÆMøè'$ÛsÐöà/-@·`ÕÕþèNZow¦^‘,åóåJc.Ÿ.|ärøJ_ž(ÑhаæL äM7n %*Ä6¡ÝðuŸõËú²˜¥ìƒIø&óìÚÇ´Sf°¬”;gêD:ÖUþ¾0â•DõÆÈÐWâVI­Öí1ª‰çtšyi. E\4O\V#ŒŸé+l§ý‚ÉÒe“iäSm·gi]vñ?WT¹Ú²çêÚ^—ô÷Ÿ‡æ×Ïû/_½,|&_WÖü‹ýy6·pìÏTég{>ø™CB†îgÆâL¨'y©4pk‰Z…áìÇÖš”tËä ¯ö3“k¥öÅÎ/^q:©ãE|äpÓSìvB±, ó¦¡kmë4ðì  << ³°Dü3<› ­Î Î̳ÿ¥‰òʨMÚu¦ì ]ˆÄ…De˜™&Ì.sw\¡·So¤ë|Úv¥Þ®MfX2ÍÂØæ°¼˜‹ÖÈî“ñÈNàw±¹D ãÃÁ ÞÉHOç ’b“²ŠÆ\ûr¶Ålðž¾%µ4_2òîÌ”íøÓ¯ž¯¨8û³q4ïÏ.GÁ,Tû3Ì–“;Ô(Å•?û VþL’×H»B½úëÐ#9Þ …™Î÷l¦sæ3éóGö¢?­z"9¬’úUæ¡8ž-,šRŸ‘ë3˜™ÓŤ$:1NÛ‰™Ÿv‹)9lj””1憇óþŠ@…á !1õIÿúÝIÀF0…Ï1ÄÅBætH2spT;›$åÉxâ BÞýTºOáÛ/x0ì—¶KÔ›vÎå "7iû g9ëph^'}8E4›9ì¹ñŠBÉœvú Z³O×ìî£Yrê¿ v÷¢ŠQÆñÿæ âiì´# w +¤™'Ǻ^‰¶­Åà’λX»Þ)÷ô#£á0`îQaýˆWr"µ&9(±È”7Š áx[kÄLO'z×ö‘Þjwš@…Ô{@xéMÌó˜¸íÚtØîϼٷdvbÌ÷´Zso© Ò›7¦òjµ¤ 7ëm8›2Ú:1z\Æ>ÕëÕ°9fÎ}BÊ‚ou:„ô0Fp…Ç+ VYøLÊlŽÍëæ)±f„afÙ4ŒáM"Òpû½WîôÉ}„ñüNÍÃj›Ñ Bä@†ÄóÖP¬ìuÐwâ²ùbñ•ëÍÊ~1¹žÈe]³ªâž‰F;F•óTM“BwÙ^fVŠè­–ãJþPÌíã…È™öðÒÐê;b›e[Ö¹SqY‹QxâË"<ƒ×D”TãúåŒڪŽÞhޱtdŽæƒí ò|nû¬GäÄ•˜Áý‹¸q”Mx m)lÒöƒz Ôq„×å møÏŠ!åê *{ý…¿5Âû>Oâ¶7Ñ?ës=Üc¶ {2ÒVçKµÄ¶áX€ަ›Ä߲ʨmC«ŸôrNÍœ ×A‘ÀK 7ÆwßrNÁfJûV´Iæ ð‹S.7›€ ÓþÅ ?ZHQu-èus|®Ù¢6þ°úèPÚ¶)'C,ucJà‚ ƒÔ†ÿ7s2KÁ[ªT±›ê]¸¶Ø&Çw.Ìâ×’"’˜÷ë@†è0/׃Lâ!á› ÀõHÁƒîèÒg–ãX°ùÅ49ûHªaŒ¥,©ibÎò¬aJ/ærÀ Ü Ix¬›dØõµ&f»©8pÔÉ8–³÷¯Wfï_söÒû®…aÑ仡8Æ2ÚN{3勯÷·o© Q¾íÕšDäŸþ»@A*GÏ€^à`ŠºHœ#Ø¿Uçòd½¸Û· ¨×ž÷g¶çý³t3 \ð¾Äƒ+6¹îIÑèˆ%|Ûa‰…þ¹º³¿SÜ©À³° ?…‚úÝß]ùƒyÞ‰gž¯Å!¯ÄsêágqçÓ_ªÛ§”w\‰øÙ§Zø‰¹ßŠg‘ž~#ž{ô&~r}û;ŸÎ~uúaÜB÷½‰íß2øViMÓŠæó‡ÏÂT¸¨½‰›¡ùÕkH‰ò-ï“UÕæ ¯Þ„D#ê2IJXêðŠK>Ò{ëÖÙßÐ^ΘôÆ(WˆÃöf ÅIÀ.doöæô÷V‚¨™²I¤ ~‹Qž}ÈmJ‰"D‘pÏŒËB Wµv o›B(ç€xè}P¼·J²%ž¦Ù¢ óû¼2cÒ¿ Q4áe5—lïø×s;ˆ…õ³4‚Eˆ+T:[œÁR°£búã²ø÷Ü\—À¿<ÜÚw];¸ë_z¯ õß¼ß2ù¹Š½#!ç4?ÁÒGµ ±®ý©øí&JÞÔ çÝr„ƒ˜n|oœ½Rbñ%–Ž2·YÙÐ+eÖÌc• Ô¦‘òPÿDüú¥+õ’Ùϸ¹¾7¼zq6ÿ«:¯Û°ô¶–öHñ2­ëðÉg¹©¶…m~aÔ1ßSª @1u$W;†÷Féˆ4u­Ü«×*Ýä9} *¹¡eé3ó9¿j&$MDçT4Åüc…ù¡,TIœ;ì-’´>pÂn\ÎÍóXe4ý¢ÜQRƒÃAšâï#ŽÊ ÿ±g¼üYÙë•ÒdÉ’ê>Û‰¡¼9ÞfvúÿB_ËZ6æöØYû<}t‘Añ9!¢ÉÛ`Å:(9×j'°2%ÁëÔøBÄÐËkö$׺ŒuRíOa˜‹u[D;á‹YÊ+F·¬< ›oQÇ«ÔxåŠ-lœCoB0$ÎïÉœ@í‚& ˜ç˜µ;€È³_ ‚Ï`Å™Nè _t$ sba§Ö‚ÆÚ발և¶“õ˜Í0ä‘8bpl’dÁ9u¤gÝ¡- y8¡ Pýðuñ³þªÏLL¡ *š›ä¯9¡ ã †ÊÝšV5J£Öè´¿óˆº8à“yoâMæ2™¢ƒšÁ|4£}àкWlqRrÆÙR:< –õFIž«ä0gˆa‘†E\Ÿ ÑJ·;wATã ½~ã Žç*NUФ—x(ø¿^?öä‰àÀÌÍþ—`]í°~Ú€ÆíèX‰£;—Îc3ur Ô’~Û§mxdÑ/¡B¨"ÄÁ*›@ä2…š¤îøh‹àª¢ä ˜†*FAnIÀœX×Qõòn’¤S§NÕ„u`?[A_ ÙË0¦‚¾N¨*°mÔpƒä?vÊúÿûþ?‘³ÑpD[^eÿŸ³X-†í˜çÕÔxžÏO&ýëŠë> þª¸7!ŽªÝRÌ9€‘nÒ¹D]¶s ½æ°R¥Áæxü-\Àvƒ˜@wµ €Š$Q&ŽGå‰ )j¬:æXNÌ HË÷59}.×ê!ª‚/l3é—ãOÕÙVßE3X|n¨ü™™U;vûöVè;¥@¼þƒHÑ·­ e²bcø:šæ01 »‹ÏñCE$ŠÙ¸|œs *2q8‚ŸLb•ë_Ì›è$ªöãüη3sÂë|ǹ4wÐÄé ö’ºË²_fU¦©5ý=nè/ómȇÛ4^cí/ggdïÀ™‹•"ªýòÑ?þî:µœb¥á±OÙw¼[úË×ÞØÜ¡"âرY`wÇÃ`DZv~;šÎÎo_¾€L†[­ÿœˆNh2à4‰q¦È²¡6úŽ3º¨œ«Ã›´Úo%²åTæts¡ŸÓ–xLìKhZ>§ƒý÷Jრb18ÔO†3)?ëðsB¸ÿžÅ%לóœîØ*<ßð7AÄïÜÖ¶2èUz} /&±œñ9Þ7qžkΣXÛ½‰KŸ5´ðð¿ŽPO®ùʪcø§oGZ¤¹àXÓïåÆñÞÐWh‚$’ÖRcÇkž ,”Sf˜„¤[í­[oËÞ½ZwÆ“˜åbk' ãyªÐw¦ÿ±Ü­Gmi[jS3¤Æêc ë„u‘=]Oü‘µ¶y«ŠŸ˜²ß²àœ¾P‰„§],?#†€&Ÿ¹¡©Eè,î²ý½7|è_€z&<°f7¨í„y½ðx™»,rGpO®ôÑ ÞsˆIÈny4çS}½Ù®dhãñîæ.ÓtÕp=Cs/¶m F( í+HUiSg;MßF,ŒN䟎Œ'è4…I7ÃíŒbjs‹O¨Uò#½æ\'„¤¿ܤ\¼–¶²X­ÞîilGÝ9G+ʪ!8ðTFÖæóþT†_ƒï¶ÎÏ㈥Œ¦ý1Ö€•‰ŽúP‹(.Ž=^²¼úµû´?{äÍš»É¿ÚOŠÛW2D‹K¹fÖ–ˆÎд šäQë|‡M„£PQÒ[u~ñ¶2Ê|íw@\aášó½±Ì|(æ\¥œgÌN pþym §ÂµgX˜"±·–m’Ð"Kœ‘Í“#{Ããó/mwRÔ-×x…€ÚÁ+ÂO‚6,ß¹¹1":u¦x•Ä|O*eLŠæL’tT–Xø›[FÇ^2¤%ÅÚvn縤°Ôí8~ë|Ø®NïÃi «sÅC‡ž‚ŠÿúÀò>Ö¡¶¸·ï¢n×6î1k~f“̓5z0¨OVSÜçvÁJ^œxŽ÷ÃÐ0b݆G¶E$È<:Ä'HFtä$Œ’¢Š »&>o“âÇ}[¾*HÜ0ZhÄ4†(x3¡_ö:¿º„™å5ÃÇ¢˜ÚYÏÉ,n®ü Î-ð¤”æ‹ÿõK{¶þ՞Ņ´õàS§øèâãÇ–w%àp¢¢îŒ é+І%<+ÄÈî,ŸnB×áDü£H[‘¶0ˆ8–L³<G¤°Y3ع&HWqùÛ\^¯ oâ+CFÕúðz ÿóõá „oÎâCؾ+B ~ µ¨¬N÷¿CRø}@# æ˜éIæÁ`Ì"ç*º°-t< ³RÝÅÅP¯¹5ƒЙEä·žªP7"; ‡žŸn„Œƒ¢èn[Í7ÙÈD¤o c¦AF™c: EÛ2¾)’/ì„‘~~HüRX»7´}{ë$_(¾Z\­ .£Ì2Bì&¡ˆÌ¹´ÏÖì›(*ãÅÐüØ:€ùk 9nD&RF\…ŽCHÁAZày‹ƒ²¯Û€þ=ÁÇqìëȼÂFÃÄÍ(å;¹9ÞvÇ•?¦aA†›¸7’“ÃìJK°<Du@¡°„“´‰ûõ“ˆœ¤Å´Ã’5 ¾èvñãåâǪø±¿8tÁÆÀâ9'2p%9Fê2„ÌIèývÿ š"@yˆäWR ·%€¼Ô¯¾h€¾ ÈC“¯âqœ­#†Më~l:×¶ˆ¤4P¾ŽÌº1EáÄšŒð\¡Ó²Äj qº1þ¥{ÊÊqŠåoÚR„×k*Œò'„Þ#3ªb“k¥wT†æˆù„Ô•J>í”°I’¿ Ÿò^pj^UÌi‘^é­[ÍÎöß=£•UºàdeYÎŽW>¨?§‰ÇJ«ÃÔØ¯a·ï.Å?‰3†5í¼‘®7ò ŽOÜL÷Ê1aùc Ox¯,òs4é@4Uõ2 U$&˜ØG@ =‚¤$oêÆ“(sêFc$w*.-=ÊŠ©%mÁìmí• ŠäæœÒ³KÏObÒ|JÐA&ù!v˜šM§§;ÓȹøŠ>vK\1 ?,ip,§¯WÚÍÈÜts$$ù£¸ÒLçM,l6¯OÛex0FöëÀɵ‡—(!NK“Ñv$/EÄ·Xö ­ÙL釯*"»ÒŒç=²âx³2ƒZ™Í€˜À«…Åå;°™¡÷õ¤¤EsÔyÃÒvF™P d}ùY8Åù6É ß˜`9byW¾+aÕ2žAîô"$ÂBÕ¼ÿÝèUßK}siü±Þ›â–R¨÷Ð9W:uƒ]‹>=õG»a©ä(Ý (zжyðî1ÊÓʰ÷Ê!…äΈȴWNK%PùõI? ; ék¢ Ù‡Ü<ÙU×ÐÝ…¶„r¿Jtœ¡üÍAö˜±éQ”ËHÌ@1ZŠÈaýó6õù¼íÜÄU²ÔÊ _ðE1IxâôµëlTé-ûç:´àé7l´çw·Èê¬VÛôÀ£€‚£O²Ì.ìÆæôKlÒØ™›{m~º6ïÆÅ)aߎ´!å‘*›×Å„ SŠÂæ0€K£@Ïbd6bæ[!|.üáÂ.#ßæ\@}†ºÂåѹûJ_RFð—ûàùl¬CÈã­¥OQ:6çA…šÖcB›·¯O÷û¨R¸þËðž­E. IV[Ò½bÉÕôç(²åy¶üEY`ÞRU9ƒ‡‹)s¡µ!ÑX6§“—Q±¡ëˆ*F×f„üÚQ¡Ë4;Šˆ*“ònœ£€ÑhÒ–9žÃf¹%€£)¬Ò“?…õzâ›JÙ×…I-^žQkƒy€¸å{+$áý©9þ¦|¡ðéaºÄ5—ú½÷€ä)rMq˜ð¾0½ëhþ2[·`«¶gŒ&6¸^œ8–öÊOV,þmB4DGtecÃRÒº£œpÆH àÝ*kN_˜Ÿ|[Û øéÎDÃRgh~ƒ(NÏ9‰‰c£p”Ó®SmÄ È³¤Úؾ].ÿ¦PxzË\‡2Ê‹ÄJÂgç":±°Ñd m»¦ˆs:_ØiÒ5‹ÄT؆7‚&y‘ŠºÉ1ÆÃ˜%½é0I”4;—¯^Ì£#[bú9;Xú‘!oˆùÝ8õ‡%«Yh¨³ˆX½UüõÇâÐgâžË頻ïhÏGB;ãƒç‹…7€7 oxã¼€Œ±‡¶e„^\ ‹8¤¿qÉKZ{6Ùì _ö9uP•,;$ÙÌ ¼øÍMFЋIY?@Fm$HϪÔä'h ИÐý•Cù}Ö¿ ^…“œ›3³Ï^ØŒy¶¼?Þçö‹{ ¯#°hC‰BQ—Y~7ëÏ™/¾zû¬¿p,òîIãÓ ‰GËå“—rÃ’Á02# ò /ùkç“„Ož"‹|/(ÁÂWÄK׿gAû ¯ÍëÔR£j{,ÿî­ðûØ!'v¸Šç¬C̳<@šhn\•<: õ™Š j¦_ƒƒ” ¥3 ö™gF?¼× „{û=•¼U K~ݧÏŠ{-±’î'ó&]ê¶fkA¬ whbd†f¬|žA†9*ý[W‚Û~t7I+¿Ã"ø„û¡mÌtü7%ôá«;{/_í¼y‰º¤»ðܥЩè–I\ó4±e†¤ùÝ2/@…pLLÉ– UÂ@Å\@÷%™Ø’â±ë¶y½ìÏY£!:AñÄ R#dB_ªò|l§„¦xGh„7~Žü¶ÇPé8^²Aä•‚a›we  E.Ê?Ý5gw ±UíÝvÈðé1„‰FžgI*âšz" ½@ƒÄ9…à×gÎ.üЂƒ#ˆVèëÛ£™kÒÇr%aÂË=)ÉŽFÎ`²±: †É ` gJš…ÍÑø?ÓªIª Ñ/ìË›צâ›n~k!\ZǸm¬pÀa¡Iaã+„+I¾¯šİ¢3Ý>PC<‘7Ñáv„¯f€uÀ‘$y $lļ&T'#.;ÌËSèæäx‹zX­ÈY‰±‹ñÍ4á3i8>[@àà+ ’æ<¾  -.áü€ó ’¸w¤{Lª"ÈšwQòÃp8¶úÎÚuaí¦°v]\»)F{¢…S7ØUÁ¢ -v7þ£áØh UH^ðÀüÏ‘)?×Ì"üïÁÿ>ü¿‚ÿ×ðÿþß®Í k³âÚ ¸ÖÐÖk×»k7»¿^Œ¥ïõöóGØq­1pÑÜ9ÐØ°§<÷åQº´í¤›õ º©k‘“­¦ÇÙã߄ى‡QÛÏØ©ð1ÂÇd(“ÈrÞÔ´Ææ¦·V¡£¹í{S§uÌÈTÖ nUÐ/'jv%ÔX Cå„…IÀO0QåìÔ´šQA{ñÛ¾úçnƒõr°M—dÍ':PøFz²P¨»F€÷Ö3s|8î_dZz…Sjtª-0…+гøýWw,hXÃÆÏþžd|òn-¯ÇüÞXhÚ7žïµoî3ÏK¤\“xÅ£?x[PEñeo ž{[RƦ[ô·ž´C¥ìì+´Íþ|p™È“Ô¡ÅIøZú„õ«–42<¯„p¡k;-ëËIšØý¾þÕyìKBï\‡¿rúä„îCáÊ9In#ëñ$¿÷æm``YóaBºg¦‰ôÛoJ+Y×6 ¬·“/áz—H9à¬Ñ²Nþ2¡Ûr®…UWz3ÂKm¥b9Žqä„¢˜Ð]X@Eš’õ˜¢‹ôÜQ'®äSQF~¤kž7îý€a´ÈzMàèû…´ V|$éÑaE…¨¯·µƒ à â;A]Ö)SÒÕ|H¹¢7ƒl €˜MòÖ#‚v†‡a”º¿êχaòç ‡955Å…Ú´®"øÙtv y/Ê¢äá‡=‡Ó,n¢ª’ÇtÛÔ¢Ðôðð‘ÃöC\ß²*ß{·WÀòoŠÃ7Óâî~ [NK™4fT;æÆY^ÀG{øØÇ‡7't,l¯¨&¿ÿj2ý¦Š&ZöȺÊ.ÙbÙ§ç;¶Ý²·óéÀÎ)ºGI»;¯èù– ïvî`Hô6_Qµêø^Ú£±)‰ÚÖ=ÑWœÚ=å"|G XÄ–PŽÅ‚$Ð<Œl!„|ÛËý{‘²ÅYh¼UMùlò@‘LÐm›ˆ³F=rÒIeð¦ îÌ,tά†´â² ‰³ô9«(øŸîÓÿ×Êfª'ç+ª¥*ŸëˆØuU¡’/ì`ä JƒìÕ§€à Qg÷ N°h‘˜˜ÜTa2‰X`dÉ—Š»}êJÃ/]<•¶·KM²Hؽ¸1‚ FG1Ô¼¶r}üÝ­†‰õ+èœu­R9yÉœLŠD»^¯Ý@g'½×[”Féò{ ÃåD§Jâ~ÿí6å‹…½ò6ز{6sãÂØ¨{ÍnÝÆ= ¸ƒÔ%¦€0;¬PÆŸã>îº4 Ëæ`Ügx÷Úû÷O¾¡ZÄkʪ9¿Ö =C‹)éˆ<ójjªdÎR]KÚ¡|éW¿ÝtÁ –TV"Ø)½ÜÌ$Õ*µ”íÔùó´¶È˜aÕ¶UêïP¡ÄµtxhÍ=r¨ô!d;Ø–!{ý³ýϵ‘!yªŽ{«ÎIÛTmË­?ák[H®~¨ |ìÓ)¤ä× ¹+iïo¹+!uÁI1e4o …³IÜ;Á~ƒ=¥¤tµˆ¯Cüõ¿ÿøãçá?ÿË¿ýôOðóÓ¿}~ùoŸ‡ÿ”ÿßÿýÏ¿ÿç¿@ðŸðgSÿËÿVø?$0ÿoÿþû?ïüåß~üóîïß}~ù/ù矠ˆ'†‰¿Ðç—²aôóOù ä.m8¦í&xeõlõ—å o^±2¬JAqk ?ƒ€]®ƒöâ~Ö±ø­hÒKnËKo#0o­Ýc(–û‘®Û |á]!Èž¸(¦n³ç&ÞAŹB.r¬Ãѵ9Œƒ…Ço¾íÑ^¶F+©?f† nIa½ƒÆ–µ‹éCuý«9’Í6ª‚3«-`máœ, |Å¡õvw}n]mL Gs’‡!Na Õå0©KÖ-1M‡(@„ÂPœ¶½@û‰? køš!]æ/¦N’Ãm´¤qÔŸ…pb™ Î,ÉÝÝdý\*Uvþ(gi§¥¨n mBrz.jwó¡kÅt;þ>=`$2~‡ÍÁy%&.øð…I:ÁÕ«ñŽr };ê«@<àXðÜB7JŸØWvXºE ÐM>*"déNȃáéòzsodBMý°©·ŽðÐÛAVi`£¢•ôÐlÀ6©>nþŸî‰@"±æG} ­ŠÑj#O ÷ØÜrÞ'ÅF(iÅ,|?Ó¨~xØÔD¯ùÁFMø'}ì»®Ÿ·VÀõò ”\iºEâì7e‡îºÂcñIqdwÉ»­ÜíÍ¿ÞösP¤+Ý÷ìS%„àŸ§‡8ÌÖô3ÔÈÞµ^‘>—9<ÿ»šÔSÄLû^ÇlZpÐZމjÄ÷¸¦ò]ÃH¹%>g%Tù‡û ¸^­R•[ý‘ß'ƒ ¨lн—ßÍŒûgæXpÉlܧ¼L—îJ‘ˆíYŠç_¿Þ}Á¾j\›ÉÞ<ŸLr`8Ô,6¡¤ž¬æßì¿ù½+¤!~E5ï9»_p#ŽÖ(ìË&ݦÿùa$|ª£áp¼Ì.øøŠèhÆJè7{ÂùâîÛ´’žÒhzX±ƒs˜A¹WŸ«dd9^¬ÏcÒ‚.΢Ž5›ˆ8i2ÑXêÅœ=x­9g)i+ÎþH¸j˜¤\ÑÓŒ´2õQ‚Ìø£1"œÏ)b͹Ʃâ¢=Ôþ„ˆpSSÛ‘((ÕO0,m„ Ó_G÷ºù ÈbJSÎÙ¬¤kN Ä=%•à9sYmm~ašxojÚ[,:#í¶0SVFÐPgY«jGz­0‰™ÿã*딄fÎÜ|kg³8Î(©pžÂ*¨7MEvƹñôs“h¨‹pº±MJ“¡Œ¶è ñž2º€ "˺ÓèÜó|³£.&Ä+¢$€HdWLø3ÆÈÓÕ¹ó…ׇwfÖŒsÅ¥kMíÀ(1'+| ‘Cp=t ×Ž ¼Q:֪ѲþQ«iGZÓØÒOÛh=³Üó‹v*6ë>êü=žhV;ŽÐ­VÓÊZøƒÖÕŽÇ |8®êÍõŠVVô¼ P1ªHU«@ŽŠVTëµ£zÅÐj¡jW«Uµf\ü¢‡²Z¬¦ŸôÚšÑC»jµõp½Ò+Œ@½itµP½UÕj]-ÚÒ:M­uÜnj‘V§VÖð»m­jT‚m½Ò9ê¬ÔŒ¿þ½TÞ‘geÓÔAýß§+Óòû¯_¯ÃbùëƒZv p±†¼èӃ˷¨ë¤»ººUóÖ-H¾¸¿z¸ó†2OznÁf=á–’=Ì3i8XNóç$Ìž] 3_—5ôO²ý 3†ÆQjü ¶/ ŽX»TP(: Þ˜j‡Ptò¢;SHvÚU€c1¾b,1f¢]eÌ$„|Ò‹èKÔ¦ðZhBØ“ŠD&VX dˆð²@×èCuÌÑ3T©™2\š .7PK0!=®9Éféd&ûýR 4†cȨÅ(¾iÆ+Èð%—P–Á†Ä©ÏÄÅV #žöŸýÝìá+„ç!×cÑ\ ðËYÕb%Û¨«³ ¤-éY؆cÖŠ¤ píN³—jÜ$ðG¡ÖÊ.Ç‚;åŸnk;¥g70±†ýqœ¬•H³N€¹P\†ÂTŽdwcĸ¾ÿ†‹C›,ˆA£´{Énz$ Èn8Ï06÷°å÷¦õžI®ÊØ(ƒl Ÿy¶¬¿º|±ð6]Å2xÒ&|^0B®Ð@mîSê’aó ÛÖ[ìZʡͣd[˜UYÆ ^µ6ß]›ÖG×»ð/\íÊÒ»8MÈôÆ>ˆNãT·4‹°ð5#[( ¡{Íô92myó§ê¶Du®š>ZçcóBŠ¥Décf{¹ŒP1—…8švKIzMú¦gfkòL8è*³2 +C%qÎŒ? 5ÆU]ÍFh6rƒeK¥ë¿ìR2ËÞä6m-eà·Hì1¢¢QÊJšq0±H`*o òg¸$Qއ 0t)2µa4â• f¼ Ž" ±!ìÓ¨9™97l âòŽ—ú³>ÑÁp¦®õÊÎúð‚öhŒÄÐ5n¶]r0waûºÄ-äqeRhë¶½V^“… /°rÃH -aYÙ¬YWY9dè)¿þÔ‰Z!¤(HÿCù ŠPÛq2¥ÚF­Û+ë•¶FеAòDVàŸb¦„Täþ—PÕHô]Ùj­þ·¹ám®·±wûs}j-..cÐÙæUÛ²å­ß*ì@J—ëÐ_Oo¹µ—¼Œ-Kž¶Ö’+#_E+NU¨¥¡ÅœºÁîúغòAk3,3#ƒKîfÈ”áÔUSCS®];:x3ÆÙ2Ⱥ†e9n%îLKЬR)0*Œ®AFÜ÷‰R§ùQï5Гr½¶íy±«of'ÝÛC*C5_—¦n1‰?™Žº¨~xˆ™8k¬lïVSm„òŠQ;&ol¯ähé!¡ô¸Äðr@è:Bí,i_ HƵ¯³ðWç†/E€íÉ]$8E H;ð—ø¤™eÓÏG{–VD¬ŒÒ±ÞJú3c‚)Ôìú$LNéÙeíQÂùñ]và)áÀ >Ñ”(ÌXüù›ECÄÒV0R–¦ô†÷v®%ÐV«R?éñÎæ9/´ÕÐõòÖ¡ÖjßÎç…Òš ÒV~Ê?Ýøá_Ϥ´m‘wøøÂ Më µÑ~¹?šûú-)éJ™<Æ”×þegí§ tÈÚù×ßïüþìÜ“‰Dâõ®û¯[|a7éæwÙa‚0ʦ| QtSF5»goÚ#›=o}=â1îõÎÙdØR"9v-ÈÄü‰R.O¥§FŠ"%¬"G-5üÀDz=Kðˆ#ïmež+®n—ÞC_ØPOz@P šðF_…`k(4H¿»,s€)žà«¸R$¸7Rˆ+LíÑ,ÜÍŒ^šcİÞߨ`aw{E'_^¯ß<_ fS"Õ»:s÷‰çHîÂ¥NÛbBðO÷tÞ²æŽßúô!O-1½\pq„Ãu×x蚵䳤ÂåSÎŒu¦CK”{"„7¡ˆõÞð$䢡 Ì¡…£AÒ–¡6J˜&áÔOÄçP{“›ó“¦ÑÖƒFí£Þl?^LEnΤ‚S•ÏUôv¥ÛpÚÑ퉜`ªà™ŒÝ.CE~ñ…»+½–s½_ÕÇÿp»V÷ÞÐÝJ·)¶®HrÂ*¶€'÷|ïbg Õ(QjÓÕeÙ @sÖF“è@ÅRÂ×;Ç4g[y|a _Ácûñ[M\~cæÄ93²RÊ×°ˆ«^àx’ï®”'*î[UØí«kÖ,d/èN/©ÞÉ×h^ïa܈Dÿ̶Æ@Öq“1@{¿·—Ú[÷½%§¡ílnžJ‰ -ÎIÃØc·Óì*9GŠ‹ëUŠ„á]Öc¼i1òÝÂ/Ú4HZÎÇü ³]Ãc³žèFi·‘’á”–Fþt½ÅâVðÛü:1¯¶ÕÂÌxÓ(Ŧ·ÏÇ ûROwgTzyDÃK¶7Pùɵ½‘&Œ¡3CÿÌW—@f @$húwÑŽY6Ç¢Žë‹¿Ëë”eõžð—)аþüàÎ4Ü»§Ü2 _|]Ëh- ¶ÑM‰Ð]wЧVŒr‚ºFZ+!ù#lÈxhN­ š«…í’äbÚÒéW”H3Bj3˜vŸm${Iå©/B& ű“T»“a¿gµî’CµnŒdÍ.LnçLŒø<9ß°ic–Béc?Üõ˜÷°jå!ÿÇ; Ê¡]F¨D Ëã=š ™hÝM(WÌi„è$ ÑÂÄÒ'è™@ä¿ÙºUU¾°¿ÿ½Ç3Î¥>*Ü,%Šë(|I‰÷‹µ³ùš3¯Ýû P}B6- #A<“¿<àj¹ícòwYü(âI²K[ͳêN¬œØäÉÛ7ÙÝùôŠgu_»)›32 ÓYq—êmyùU=¯òyÁúꯇË÷DÅ¡•Ðüë×{I²Ì ¨Â„¬¥®‡¦B†<´z8UxáÅ•{3»%ª•éw¿—j{(Méä ¯ Aö£˜›ù<”Ø$ú‘ìû´ýNÆšfg¶Ú–¦kAÓµªùFÙÒ„XÆ«fHw‡w4E»;JÄ4CÖ«£é¢‚YAµy@ÒjwI8Çc¹´BDªš¬¨`ÅØP1­ žpqãò¨?ÛøŠ(UÀG{PtCûÚgî&<âõŽ+¡¨äIÇ3ÚΟ­ç÷‹…æ]·pÔm@;?®ÛS‰…ÿ¾¨>ãÂr'lÜרl„‡°«oé7þÙ0jÂL¨Í«ÖÜö¶$¨Õ PR:6r/|Ñ“œþ<± _ç o éøÞFÑ™4Ú$ñÊ¿ú[¨~ø3{ÂXÅã™0hú¯2Cg“é9 ÇYex92’b¯ÎkÎ&˜i¥¤7ɬ>ëÿÇFEjbÇ…,4eN[K©YéÓ‘oBñ |ßÇÆ]¥•Fœ9²¨„H|Yo•ôZÙ¨…jªÞ4Jio:œæ¯Ö›YêÏl!`‡oƒÿ´Ùl ̯Ð;º ˶Hºˆ(ÞÁi.Ä;º»®/Š(+ÌþäΛ!_NZcáÕÎPQÚ­>?P½¼.U•^%f˜ýJ,`Ñô§SË)Iµ öˆŽzJަ°ªÈí(E‡¦7zG«è%©¯³—dƒöeYÞrÓ;·²=Á€uAa£ÞÓ›Íz3ÜhÖÐI²¥—:M£Ýexê¸Ýn WhÁÞ¦c'm²N+Áõ³Aòí=OŒ½ÀèX½jëV ó¯÷ßfn5)5@Wlq¦†ùßÙÙ‰dį&FvÃÕ†¥ˆT‚‘>ÓîÖÛè˜yá-í0äÉV2ÌËþ×ͪ{ ©b·àX ¯AGb´,zë¸j_ÄD–|qÿ™**г¦0àQ(B€Ñ D0R°HAö² )Ùáf(Ð$æ¼Ì²gm8Q€g¶Í8iˆ²p|ñÑïÖÆg vu» FpÞ›\ÌMÒ•HHͨÚÈKxc±V§¡7[¥¦ÑhGZel´Çª ,÷šö@H¾(…¶Ó=’*NÉqÚ@DÜ S°A[âüÅÏNµýñÍ’Öhõ´Z¹×ªj•J£Q7˜mW—J<®ÔOôfIké½vÝS*K5ù@V*±y‹æblf}² ÃÁù#ke°sþèÍ 5  ¦ŽfúÓÄla_S “mëË"‹o2j¥J·^Ekµa\¥ÂPŒTÊ.ç(„JXÂΊpo?ºpx‡¨,.¦X0D\L1¾2Ô„q–¤ÌûŒOÈzŒ&)è"M¨QÃnÍÌÁ¨?Fw¿§øè’ùÀ›.~÷ †DZ'‡bÏÛÆOúb:ü-J„eÓ“A¾U¿ÆM0n[“TUÑpÚ¡&‘Ú¼º¥ïr¯g…έŠCQ×Tšü¼8Ýú…ÄmaÅÄÔÈ뺺(AVd’råS1þ—*J¦lPwÃSzÇ/DëÅr {Ì$ã3ö&v Ɉ #>úšM׊úB¼´_æ×ÇžÊ#ða¬¤ÿÐ1MF¸ý|*à'Öœöúó›úUËŠN™8öDÄÚ²y’ìÝF©*×ö‹lijåüîçÜKÞ¯ŠFÊOî¶WJBžùݬ?W¾øjÿ¡ynÚ_kö²FjÖžl™é2d«ï†ËBƒÍšGÐô>¯\U"9O«•µ©ô»{îµÃ¾ä ~{a›¤¼" Ö¢_q¼ó"Ûh^Üï’#Û¯¬ '~¬ÌÈ—7ºXR|41Ë #ƒëÅÎ é:Ç&ö¿öGcDòÃŒÿåÈ}m ú33Œdå¼?r²;XeŒ«²g¤N­¤uŽŽÛŒ×l.nå°7—…ÇPgœlZ\Iïuš•¨û(ýož-. b¶©Ææè½ÅÁϸ3ªn£§¢0¯Î[‚n0gžÃ¦†îãê+Ò¢hƒ¥3B(†i/„Ñâ¹… »%ý´$_ñÉÔœ¡ \5~1àëý«ÉoübE® Ùð¹XØñó_Q$L·RÐ1aB¿jN)Rå=ãéK軃PÆ”Ý'žy" NÚ“Ÿ=TTõZ§g¸vcØä¬ ëO`ïáŠ'“¢)ئx¥9­Z@y›ëW£éú¤?XO¯£l¡ QÀP™`–ŒP&†sʦlYÙl[0e‚½3˜©_~þ{û­œ…ûzt»eÆCUþí…ï]‰4PêóJe/;¨Çæ`Û ŸMŽá<1çÑ3"䑸oÿuUù7û{è{÷Ǩñ$hCÝQÔpa× ´Ô¹æXá™°«XÌDxÙ¶SL«ñ½µY¿ƒŸXfXV+´7’µûî!ïp–Mc“4”ç“J!è¶îÒº²I,w‰ÂŸKÀMÞÎü°[6®_¿ªÜ™º/+‡_ŠÄü=沂<³â‡_Hƒ³óÄ•WEk*ºë¹’’åc§¯€)¶ˆ®*MÍ”§O6J»q¶wÁ+uÜOm4³W–îÉQC¬XF¹†0ß ŸvÃH bÖ¤*CR±Áɬ “¥²ù Å¤G_b*^müé^·5ÜÀ[tõÌÝíÛ«bî‚ëc×ñvIa“æ4OÄÃÝm…¥Ú=Ù¸ä×eâ¢Í] æü~ êPKf>¼kÁ•…7½0'g&Nq´¼Ødõ”ý~ìün(I“¤2úEÑ « –£ã-FôÒž >Jô« ¢š7ùâU6²Ð rߣ ´?|d dtÂSƒŒ«TQƒŒož)ɹ5ºD‘4J-ÉL\Þöö­[%ª(7*¯´àj¦ ýöŒ…·¤IVtÿ(·‰$ÛßP¯{>+¾˜¢Ð CFÇðP ÂÄ ï“[µêœeûVµøù-°²§´"­$_c£ÙlW6ËšdΉy4õQIß=!PÅó˜O4 J77äëöM+ز8¼IÜôXð–öß6ÑÞC›m±È“'©|¶i"máxŠ C1”ÎBú¨ûŠÇWN:N¦½@xOFƒãÂ︾ Bà¨?KHótL‚JËàK-ï>&ñ"ÿ§¡škÎ…s)z2{ÏS;¥>KØe¾TŸLjP‡°ª5“æ€(ç·Ñ"ô†ð’X x/-B²NU¨›!¦­Çž¥B¦”ð#›I™‰_øØmƒ®jµ½WÆÂOƉÞÈxzƒ!I¾”Ö^·Ý ºçò={ LB^úXX€‚AL†ÊQËpÔ3ƒÐ&€DIS™ZÀq¥8¿Ý±Kðý´ˆáFäï´º·–5ÏMÙ>4Xƒt4š±Mq¥òTIZª«`1)¿sûªéY’¢æ7•߸œ!¢X>éÑRÍq–úä9¾· ×€|šVjÓµnHD=qߥ;w²÷Ò!)w>òBµ ‹+”'!¬9ò{7GÞÕ ½Z³¸§ímq9k–Æ#º-àì ?§A°8¥$¬È´ùÕÕ.“°mžläHŽsÓæAlJÁ¥½ ¿4Å‘”`kY„ï^ )e¶/EE6¿Þ^æi¡@qÄ6‰­yF\Ú:ÈLÊœTîôîTõûZWö áãÝé X¾¸û ›¶-–α ¯ás)”;D zC¶ô#£–]êµòã%,O“ _,øúée‰ix~Ú;1je(/eƒ·½@W[+£•ËÂ_ýêMÜh4ŸÜ7A|¢ß $ýÛÒ‰d åºíËþÌ´…$@dd—û¨3\3'I¶Pˆ+é9›®P‹TpL”{e¡k;ŒœÔ 9:ÉJ~Ñt‚5üâëœOzc•"íþx¸$* Ë'ͨéÍHCkjt})k¨f©7Ÿ¤,ƒ«o šõÏ·yÕ¬Nb¿'> ãÌéƒe«ãíâô‹)„ ËøQu‹©1b×ÀÒ1È©¬½­ ¼zŒ)ó}iC8ðÙ¥£½Ú1RÁ`FLxd9‹( ’+pkGg}ìml3] Áàôg1FCí`ɯ_7ªz’ÅÕm‰Þ¨äƒ„:µµúI-<›ý¹6gæP¾Þx…è–Mìmɵ´ù\_BAÜp 7.î-†4Éxß{Ž ¥áèÇTÑ™˜T`ö§DÔ¤¨ÉžAy|¿Ážö¼¶Ã@ÆBïÔg0ˆcxwnH"üª¡15ª ~‹‰š ‘õeΗß“u›î…ŸSà#ß–ÌWÆßî»7¸¨ß¾½}÷kèÁÉõg¡bF.’¬ž.15¶nAòÅ7o³#›®’ÓE%)Äu“$á Ga,ǬUý×;6Oz6u›èuêiØýü&x\u­¨û·¿œœ/¼{­<ªz²nI$PÐßEàÄ{¯€¿à¿l7á+~tg OØ^F%u— kþrëH^Â0¹Ñ§gnÞšÈÌïQ?tÉ,›ÐWþÝ€v⣫¬uö¯yQ»q±¨€+’5ÂSþéß‘“H–ˆY-Vº}6tž`“GBê Ú*²®¦¨/Ü™I{Lб$–¨´P³99Öõ Ûo3jG¼ ¹«¤GŠŒ\"YèV'ÂF PÊ eãdéX¤­ ÃÃÙˆÂëýÙ,ë¯%_xý*…GâBE[•é îc¥iÂÄËœ…%¨hØ_sê»q’Ü2‡(vêt#˜‰XcHlå#l‹†×ŸN'hR°‘!Á¦ÞеvÜî#+`HïØæ,-i[˜¼é97ÇÆÑqxD~Ü›ÔÞº• _-Þyш¤#›ÆŠq)2ê™õÁßÌH3Lã›ßsGœÉŒ éç„(¿N$¯Æ6›F°×a’(Ž#ïÔò»¡‘M‰z«-6ãNÓH|‚:),ƒõƒÇÄ †q ghžkx³,ôiÔ“RÏ“Yú@U9¨Ÿ>aa žd©ˆ© ›dÌÓ¼=º¯ì îdhÑÏÎ÷ß®Oì‹æ½6ÔlgÎ/Íù?ïeóU—Äo¾ðvÿóßÅÞ•5á+w“uâéå£P ç\¸dIøÌâ g_áÙm!ø‰Á8÷-ÏVWÇÍ^è|Bü$tÍ8™I~ùÚdomà¬Ífþ[C=È´bèš‘ÌÐø=‘ }R {p³d¥Œ|}J³Ã ÅÖÇ-·qWùbñ9ÄJ%·˜Bº8Žžnpå“K# Û@7é‘íòb‘·&$˜é …%y$ˆúé^sX¡/bŸ`‹4›ûvîÛ0¿÷6Œ;%ùr\c›gÞâÜÿw<ðÊ‚s‡kö`4² ޼̔=^3J}ÀSgþ)Oé|ao‰jªö= ÆUs}“aô„á!ueWϾ—1¯œ;‰à{êrm†Êê¶nß“äß’âf\° îçžZÞmÀÛŽï†Ó+ÜÅÊŠ¶nAòÅW¯»£]„b·õ‹P—µˆX¿h•¦¤ÞË”ê±ôâ}¿ƒ„”,Ac3òž¬„æ‹…ìrB~÷w½e¢(¼œyLnÞqAJ-o&:ÇÌ‚l[?m÷*Z·Þi÷ëͪÖÞ\*›ÆÛç&ÐQ;Ö›F;8w,fIþ u‚Wºáý˜óôèb ÎÉ%œ,D&qpÓÌü«|ÅôÉÔþï¿]ûíÿˆýë$Â2ø‡ÿ‡½¿&ešP$GÚŸV+½v·¡÷Q$ÚPníw?ýût(ÇÏûxñ uL)~Û âá7¨Ë03³­y\f@fMϧ¦0NMÉQžqòý·+…ùZDJyɇ:)f ×ËO'¤¼0:„‚R®¤¬“Þkà ºÕifvŽï{Ø­2 ùÌû³¤¸ÑMdÝ-‘š¿@ƒ<>­••õÀ²Øa£mYcxï¯ßV'Öp1Fšž~Yz ]Š_þ…‘a ¥·;I¡;5ôÙ‚>·E¹÷Ä£-$¸R±NSpz9p†˜÷ °x.ïÙMë/ÁUÜ(‚ÞÀ û¨7[È¢Ýïín.µ/_Ü{\LCqSh†‡D³ ûè —=›\8/-IÇáƒô)Z–K{üÿõ•Hwé¿BÏ"…ö}¡…^ùB»êpCœZð…¸–¢/ä¾ þ/ÜÁ“«%†¢à÷/ì@ Få†P‰b‰?¤ÖšDs,(U ÿÔ%¸H¯ðz—~‹ûü»Wܽ»Ë¾MR:È›Kñ|áÕÞ‡û¡ª³‹éÈÝUBc>0Y‡7!Á$/ÝÏÈ+Ù$OºÁ|q·x/5 Üèü¿°ßEÕ}#sÁˆ‚þ„+\ÆÉ4rc»E\ît´uÛÏÈÆ.{ q§„3OÚ‡gùB„XÈüÝ@™€”7Æ,.ã¨â›òÙÎ3ž8Þùå ªrlI¾«{Õ”7rfí[=…UN×g‚Òá].0>¸´È–ÝÿŠÕdsH¾™¡¸ÁVœëì×[ ©¯Þ |ó:Ng=ÙV=íÆ(‚CtÚM MÛ"R#Á f¤«>sGlœ›xј–.¼Â/>ÞN´g›2£§ek3*Oò2;5‚Lq°ûQ¼ÁâHëÚQ>ëSèB¦]*çÎhíLˆH´§{OÙ§åKÉoø"GTÓï/êµJw{É‹v½M>Ã;÷£}ágñüñÎìi9}‡:åú¹âÛgÁ?î®nvá¿ \Uu•sªnR†¤ÜˆðB…ÎdX¸"Ó;Jf$n•/¥8Ƥ㤯„@‰ëJöæçº êz\uÂße²ãìNH´Å]<ÂmMTå6HŲ>·ATSÖë#Hxýš_ 7=ݸGÂÇÎz#|ƒ˜êcÇŽœ &Ÿ-²¸TœЇs9w)’NX˜|5œßÊøxeK_X AõƒÿÎq$Õw‹ßy¿]x…r/Ïóo%ä û[+Òò»ÿ°JQxÉ*ÛõY}…°âûÝýv¿[Y4ú‹©7¿ý¥TÖDþÇ•Y`² ¡›ÂKBËþË|EÎ÷ù^½/\«³§—kq}ýÛÿ"=ÿúíÝýBºwµê¼t ƶœyN`òJ¦mÍ Z)áeÔÎ+¯¿,Ué¿øe×s,èl›€…`…”"tJU’PÛçâr+6G€¸èr¬‡â,"Æå~Q–°®dû#X‹šÎYpá‹Y48"§“1wjâ9¨ÂRš’ÎÚ³±P•NyºqÃÈÈTC<#¶èHd‘&åH”qŒ h2“G('ñâ…¤Ž#r`´áK/BbŽ‘mõBîËéÑÉOD,"ë ßþD„Æè…TìÔ’8–Pû™vvj¹Þ&YT°Š¤±v½¸´n‘rçiâPÉwGåjUSúÎF‚}"8r¯½#Ú{s¡öÓîC)éð¡èQ¿ÙºÉ¿Ùß ^‘øüÆ•>/9|‰Ê¸÷âÔ{­C®¼Bٻ׉ré‡HýÈ–Ügúôü #·B¼õý{™3<4Í’ÚioUùbq?BÚX,9¹ñî°ÒM§XæØiF6ñÐy4n¶õg¬Ò&nñ|7­Û öGi1OV¤»;677´õYÿúÊŠÕ@BÏœKÔ”F´7Q\wIŒWxÍ-r½Û¶dNñ•7] 5¼rÁ1x•tÂ#™–&Øî‡ÄºWDËò‰kŽ?á©pÒ~»ÈsOÊr©çò‚€ÞïO{f_õgòöÀŸô›´\çýŽ`ö[B?çKËóÿ^œ}o¹öÅó5âäâù† ü|‹X¶x¾#? „ÄË„½OÌûF<ß‘J~RÖwòa?o ÆÏ7Êvå[jÏ;ñ|ÅYÅÏ>ÁøÉÖ.ù¹Oïåç+j?÷©üÜ£/àç>}?_í|"bæ›övª«ºaOþ¼ƒtnöV5´zëÓ—»åÓÿ÷HŽÍ}ù¾x¾QcóÊ%Ú^ýÅ}÷N<_ó[^»÷N<_‹®ºí/xP rd_ËŸwj8ß0è­ú)ˆï(x¾G¥z˽UÓƒë{%žÿ?mßE’¶ÿ«jªgбœ z'›¾»Û3ïz÷Ý}gÚ]ÙPa]TTpEÝ;sÎLˆsÎ"(bÀ„YPÌ9bƬÿçíž‚è~ñûÁó¼o½U]SÝ]]õvwuUá1ü¹lÏsÕ¯áuÜ­xг^g‡Å³†Ë¯…_!Z«´uÄ”Xÿà˜oì1®Úøí¡‰+­ý µv1—Üê[ÕüC™æ Šq¼1l^ÆGghz¤†Q= ™U.úȬÑMý¨ÍÿV±Ø325¢IcÑ¢›šW9 ¬ÏñBÃ"¢´öé-åñkи©¯V'z8øž¯5cÑ鎗¥ …J¼xt"\\xHä^)¨Ím®~íïÛ¬‰OSŸïkÑßÿ‡:Mƒú2 |ݳVÍ>ÐsHÇPÖZc³Zx–d±ZãûS oŸš4hÜÄÏaµ¿ìåêsìJþM~úî'Z³ÁM´ÁúM}}èÓ3û …Q¿jƒmLÔ÷³ê{kTLl±O¥Œd±}XMÛ¶‚U]ɶ å5C{XÝJgC÷YMÝߪé#ÂzÒ ~zµ¬­²k/]ƒÆ…«l7ú5¡iæß´7 hâS˜Þh[СicƒmjØŽoL÷+´ï¨WiÒ²‰O@[߆^´b‘# üüÇ¥ÇhexKd«¦?4õ±ØFóØ_¨Ó³qÛò µÞX_¶È8¿¯—¶ ÎXWM5„‡ÑÙ GÞQ|tŸÕªè˜d¨)}£y”ú1úí#t1µt=ã–ñ’ 1#ͳæ·õ¿÷Ýî÷Ôë˸x÷c#µšIÍFT»Î5MDZ…$µ–MµÝ3â‡ô¡Öö4ººV ÍYÖƒn`ÂÔQÚè7zÓÀ¿‘›æj‰p¶Ú'Úð¬áN·àꓺ U£®ýwŧeVk[ùÂÙÕ°Q›ç!4¶“:7m¬“ͱ¯Pl§<ë#izvuŽ:C{ÓïìºÐFÙ„9ÇFDÛ?ÁTH§Â(ôß{ŠUûrÝêãKø©†Ê4GvStÍìë)¾×*Ó¶7ãèÆmËÑ=ëÔ®­POgæ‡÷žíB›Ä1Ó…{‰°ç·5YÛòš‘>Ã5Hß¡Åuèѳ™zbºéÛ~íi ³Ï²ïb¯ô>×Ù>÷It\¬G‰Lèe¤Ñ»A€_ÓÀZµlZíÀÚ6­N`§˜ŽíBzÆ÷úÕÉÝ]ÄÄuó£¯~ÂÂÛ«K´Aª ¯ÇP](kOcŸŽ¯°§)W|ñèÿÿ¾±°ÿ½‘:Ƚ}¼£:SOVšÑ³fýêØ/[\áw{Mý}i=b¥½-Fß¿1ó,ëÍ’Ë î~Åâ­wC߆¾Åßj6 lÖÀ§q“ÆÅßj¢Sþ©A3ÿ&Ëì2Úæ°(,“‹z›Ý´±:|¥7ãÑh´E Ëê!¹™-ÌÞ£X_ØÈ¯ öÚ¤ÞëjËI; Ôy6høS“Šmô“o#õ{Sm\TÅbq›øøùuþàCuÞºTLКböÿ†%æ—U´) ¾oh€?QÞ¶ÔØ($7¨ñ?8!öƒ:eMøk¢¡©úl™¦ Ô£°oMc£‰IM¥Ó¤Y”ü‰~_ÖÑÄôb …ïò2­¶}9Šâ/éƒ?¤{Pr’¥Xm8 Ö¡›òÌ>R°Ø—Æÿ¶[ü§!.‚Ú=Çœ ~.ê ·Ú>&v,ïkËEÐãQÈ?ñë´1Åß²Ôª_¯”צv'ÿ­ïLkÖ(ÛØô¨ÛÔ¾êsó÷z–]ü>GýžÆq =J~z¯»¼Â±Çt½ÓGL±×®Ž´`õZ”ñSÐÒ‡ ~°\‹7—6c›g-C{íƒú™ÌOQQ]â¢õqí;~ðÞÌáq+Õû¯UÕ(&Š&¼QKy—ñƒn¸ ï,š–µ+tܰ(—>v —^sÙý4ñ½&’ïGô=QCÍy÷ÓÄ÷ä”û}Ïi4‰ŸÊšÞðÇ2­ŽUdª`”Ì·¬7{¡TKÞò& Yƒï›àF®©€G)vƒÿ¯pYË8žA-@‰›3§hõ©™Us_uÞÕôÕ~šÞÕš–qÑïöqVÛdzåÔgÈ »âôÑ8@“Úh+ «1ETuyçPuXµ¾•­³+òƱÓÕhEÁzØÉZø«½9½å«U­&…:UûKýォբ×QG]y­nµºªE j©¶æjœšÆ_Ö^ݾº7ì5lÖZªÆx6W¿Ä$­Nµ­?TÇ䯎Ä*Þ븪Ÿ}Ùa‘¥%AÇô­ˆÐ¾³/M†Ô.öµ}èï¶›¨Âî¨m‘»Â¶ög$ÅŸ´—>2õ›²Lµ¿ásœË½«ÕÿºpMm@nÝjõ¾®«¾:þºf]u4®:þÖ®ÖùºÒ« HÖ"«¶-§(kd8Œô„ÛÑ^(æjƒª ç_Ô¦Ãp5X>*¦ã×”Ë×ZCbT¿‰¡*ïô³¯¯·ððkÐè‡rŽdêÓWg_ïï´çêÖr¶÷ÃcCé>™«]NÛ'¥> ¼›ø7kШ‰3}¸fKbjO‹fª+g5¿]®]“žô œ}¸›#h¦§fkØNªmvîö¡ÝÔŒ)Ȇ$9£åš¡ 4úQ›!¾‚7mcû¼šÎx¥¸n¶Ú¦ÆÑƒW«1Ò®ª‹ØG„x4¶O\^˜IuDZúš>‰ú:¬G ¡=nî*¿™FS£Ò›vë¯*D–(#3’ 㛆™´7tónÒ¸iƒ¶þMnbûе%½ñ³‡\¹w •ã»…FÒÐñ˜pÈnýl³T,¡þb ¿Ÿì \Ôݱ½‘¨h_gUÍ讕©¨É¥h ¼Õž·öáš>Ì£Ç/@Fx¨sFÙ]kõ=k}£ãDð–´¼‹Û‡É¥e‘2YŠîç×1±‘ÑŽßûÄ/À»YÉô · ÆvŽ‹éjßKÛ*ÜE‹í¦ì èño[+Cw4Úªêöuª¨_pjß‚q ³Wøòª^ø ÕÔ€6GK£ÐhÛEß5jàÓÖ¿I“m§´é´ÎŠtú‡ÇÉÿßVF[uˆVZzæt¹Ž¶ªÕ‡jê¿+ò]4}@K“¸k_“ÇFi PÛ?åR‚‹6?·ð(±1ÚÿZíCëÆeZ­•F†Ð]¸]ñ¬U·V™ÿ(òxœ^zÖú¦¦.¼–.¼¦6­z¢i•1Uiò¾ïèÔ5gß8Ê[†ªÞf—fô¬ý­[ »g Wûòãê8³=T|Žñª%¿)1Êç-ñßÚã?.=¾¾:ª§n)OQoU±úõËöÔÓ¶|£ãД©FÚ§Ñrq̧U«f=š@P ÛË™GÝÃÕñŸöy#èý ßkOšÕÃS¸é7µjèÛwêèRd²b«¹½mFZÛ·öig#C{ÚÓÚ¿ SW4±%¦N™aýÉñÅU9Ç<¹Ú¬\Ž` ÐfÒt°Ú§úFzÛ;yÛ¸xRÕ<õÖÈ_=Û6èЮ>]ûJ¸mº`i¯Î ïiŸoÖT8°¢®úN+¿Ò„ÁÝÂh~-¬.”æUÖ‰©èøâ°ã¨†|Ào»Þœ™>äƒ-ÍÑ-<4F« -ÃÛk·¯UJµzÖ®]Ÿ¦ÍÕ†ôRkL_c«‹šÚk+ «ª‰Ãh¯]lŸthƒ#l=!¶«]WÏ€¢náÓ^ ³j‹/¹BQ7²ÅÇ´×ÌP ÍÆPû0"ÅnWìÛ‘¢~ä@Qš‹¶#,Z£ýl\¤:¬[˜ýÛ—8ZñW{i´ç®öms‰ÛŠäÆiq5uÇÌj*G¨|;ÛªT~áê÷Z¶//ÔoíGÇZΡ©Š=?Åž•[7µ~9˜DÑPû0u†yuþoµ åšm†gGX;©ŠZš4]Uи¨ý+¤e–y$-ªìñfÝèm›TôÆjÁêvÖ°^­chô?ܫٗ÷¡èðü£Bµhí„iX Út¦Øø·²uY%fÕº¬ÒŒžu긕°{Ö°-¥¶œVb³h6×®EÚVQo‹‰Öž‚k!C4݃„¹hB³ÛÅÑÚá4 ΡÙ¶](j=Tð(ÒRXŠ•¥A·°ÂwÕ ßjiÛD)m…-–Ü]-s1SE[Ñ‹=´¢³™å.f¶+p±¨Jö•EŠY?-9Al[š€ÌÑç—]ßý×R£áÆu )\•Æñ8_QÊøÆÅš¨VµÕmKØiƒ{”:oëá¼m®“ïÞ{$Ò÷]‹¬¸ó}¾Æ£îÕ>úîç3q—Ú[¿9s×7Ž™»j›¯«p/Äú|€wit?ÖU[½: ¬“w¼á4ÑÚ*o‹ð¬U§†»ê€±yh“MØ=­èT4E©ß.Õú¿^°¼ØƒþvjhE©£UÕŸøäíQ¸ ªàÝ€&…oð- úC…r¥‹ÚM{?N”¨ëñuˆ¥ Üí«*ЪNe[¢¨øˆÛ“^S;Õ¬~ Y8»«³ÍJ «h×QuÀË·s,$®†më›QòÊ%¢ì³ÍÛué¨Í²¥jê£bNë9Äònáù9ÑóVNÏ[«é]µ\}+à|©w;>Àj¯¾BNsÓt"ÁÕøWÕþòÏjúИ˜VêœÒ¡·7ˆtl‚cl3•üÃÕ6ýzï(è 7 -ü€ÂÿC|ß\¢ r¦÷Ý´‡Á¾ïßðÆ 7¥–¼Ø²æêE¶íöÁQèOßçY«–ÁŸ>}7xG‘qáVH% S\ŒªøÓü­PôH§G"=Rè[…‡é‘Bÿ]L„ ˜? `­ØwÂ+´[\(zÊïÂÛŽCcÚwÒ{‡Æ;yÅu u74ˆëg5¢5‹¥–1ÂÝ+¤âWŽ :;UÑ#?=òB1úÑ£ ÈC,ôØ^-õØJ Ê4^´1QA›_th¨«Ý¨^ªN?ùú|o ¤-¼¹ÿ¾~4霯®Œª]Ïíµu$Ýì›úØcÜÕMÚ6hØÐ¯I˦êD7ʱ˜Å•ÚØ 8ÆM­>¡>¢h9uk„PìÑôø¶E@#œ Ü k:ý`9MýΖJQgtC…âi3{¤Ñ¾Y¼A·åùCN»«-ÿˆnqä"¤šé§l6[ ÿpìp˜aSõb¬´²•ÖþVGCèxëšy»ØÊ îŽ›U 8®Õ½c¡Å6ÌÙÝú†‰2qlã÷!Æ”+ßñ®¿èèŽ g«r<,ñÐæo±¯›¤½{ЦËQ¿¯wû•,êŠ$¶e¯]BáZÚuu‡{Ú1Üþ A½ŸÓæØVcý´yÌ}Êò!Za×joM›}  ŽcÝéÿÄ3)dåø¡J¥Ø¡JoäåY«^í¶î ýÂiùŠäÚçô#´pݲÆá±ö÷Oå##ÂÂhRœ5œº‚rêWOŽ W™/Ð2 ñ}Û—åøàÞ=þV:•ùÁ²cØ®cзú%‚:óæ~°î»Da2ou Ê:ŽÉ(k—˜‚²pZÊzÅ´šŽGÇ…Ú›ܦ– (ÛHRíUŽö|±i™ç›µ?µoþ~3QÚÆ h“:øw ±­×ˆË´PJÑM·Eê7íô}\Ã2γÿ^˼»\üF«p ³÷û»Ì8páaÚAlE»lˆ Æ Iyk‘8ÜOÈÒÒzÖ®['ø}û û>ô LËöi:ßs=¨Fþþ%Ef–7ç<³À®Ø'¨t{#Kl×m틚YJÏÙ³Þ·uÿëí«™–Üâ½ošÔÙ·µÛ¥"ãêʘ²7elú\¢iþ¾ìÓç©ß+¶AÖòEŒžµj}ëb‹P8¦Ch«¿Âù1¬kêoŸbCñ´ 5ª¡.%ØÔ¾@®}%ÖÀŒ¦#¢CD¸ºêeáШJö¹âÉìøÆ²BÇÂDêO;)GñÙók—˜.¿v‰òë½1C~íâ3ä×-1-~mwk± h~Ä ½sûªéaŸJ¾È”ñ®´ôŠÍIênrL=b¥YéG©biÇFx9RЧþ„mùcÇjZf´†Çôp¬ÚèL_¯ØœÎrímÓÛk×RÅ¢‹‰ÛÓT*aÔ’zYdÜž²bq›–Öo·¿sª ‘Â%€ËGXé. }VtÆStžýŽíMê“YuP ÅÚ§äv§Âô¸..Æj›Çµ˜Éµ½*lŸWjT4ÔL›§9ÞRìƒñbIŒÚ0¸Øæ(Teº¶ìßà2úå}Ĥ.*¢^‡%¾eB©cãbºi=ÌÇoMæùm]s(Í5aõ‰ŠõíФ{\hWmPÑûŒ~tTÜ¿S}¥OmÒ³fÝz´,©v=Õ¨¨N9¤>ÉÄÉÝ¢ÔËË•Òá68L­Eå)äg››ŸçŒëÖ¥<oíjD¬:…ùhêרáèm¾Ã6:¨WÄwô©jW¢ÚuV§Œ5áÆ*òµí#ûòÁ¾æi¾r†/Ÿá+Wúò•¾2Í—§ùÊl_yÀWö•G}ùQ_yÙ—_ñ•×|åM_~ÓW>õåOÕŒm&O5ã§šÉôæ<½¹òº¹ìÇûÉ‘~2÷#žû‘\íÇWûÉ~|§ŸÌóãy~ò±Ÿ|âÇŸø™_ûÉ~þ¼Ÿ¿œéÏgú›óÿ(¯øó+þæ5Õeb žXC. à ”Ô¹-€o PöÈÃæã²_Þ¯‚ÜÛBmÁ¶¹-xn ån ù ÐB>mÁŸ¶ã[òñ-å™–ò\K~®¥LnÅ“[ÉY­Ì×ÿ,ç¶âs[É]­äîV|w+YЊ´’OZñ'­äÐ@>4PN äSåü@>?PY(7ò òp <ÈÊ»ün ÄÉ1Ar\œ$“‚drO’óƒÌ ‚Ì ÿ*ñÅArcß$ïñûAòQ|$_ñWAòüÏüüÏ2)˜'ËÁrQ0_,—óeÁr[0ß,wóÁ2/˜ç›ÏËóÁü|°ùF°¼ÌoË{Áü^°Øšl-³Zó¬Örk™Ýšg·–W[ó«­å½Öü^kù¨5ÔZ´æ­å‹ÖüEk98„‘£Bø¨egˆÌ áY!òJ¿b¾" Bä“ù,„? ‘¯Bdß6¼o9¼ ÞFÑFŽnÃG·‘“Úpü'¶‘ÇÛÈÜ6<·|(ùC)o´á7 ·áÛÈUm冶rc[¾±­ÜÙ–ïl+o´•·ÚÊ»mùݶrÆ/|Æ/ÊÜ_äü_øü_ä’_ø’_äÉ_øÉ_ä_ä­_ø­_dÁ/²o¨ìÊû…ʵ¡|m¨Ì 噡òl¨<ÊχÊ[¡2?TÞ U‡Êg¡üY¨¼ó‰|Ê_…ÊIíø¤v2±]å>­LjÇ“ÚÉõíøúv2µOm'‡¶çCÛËÑíùèör]{¹¡½ÜÔ^¦¶ç©í•I•åáöüp{9&Œ “Éa<9L¦…ñ´0™&w†ñaò`XåL“¹a<7L¾ “¯Âäë0þ:LN —ÓÃåŒp>#\Î çóÂåæp™ÎÓÂå­p™ÎóÃåÃpù(\>çÃeB™Ø'vIäŒ|F¹¢_ÑAÙØA¦uàidzžÞAîê ww{;È}ø¾òx~¼ƒ¼Ð_èP™ÉäŽrVG9·#ŸÛQ®î(×väk;Ê´Ž<­£ÜÖ‘oë(uä‡:ÊÛùíŽòiGù¼#ÞQ¾êÈ_u”C;ñ¡äèN|t'9±ÇÿùNòb'år'y½¿ÞI®ë#øú¹%BfFð̹=‚o;#ø®¹;Bî‹àû"äØÎ|lg™Ô™'u–›;ËôÎ2£3Ïè,v–Ç;ËÜÎ<·³<Ý™Ÿî,/uV.w–W;ËëùõÎòvg~»³Ìïl¾ÓYÞëÌïu–O:ó'åè.|t9¶ ÛE.î"—t‘+»Èu]ä†.|Csj™Ö…§u1oébÎì"÷uáûºÈë]øõ.òaù¬ ÖE¾ìÂ_v‘#º*cºÊ±]ùØ®òNW~§«¼ßU>ì*ŸtåOºÊ„Hž)“"åŒH™Éñ?/RΔ #ùÂH™)wDò‘òH¤r4’”'"e^¤<ÉÏFÊç‘òE$)ºñ„nrr7>¹›\ÝMné&·vã[»ÉmÝäŽn|G7Ù/Š÷‹’ã¢ø¸(91ŠOŒ’“¢ø¤(™ÅÓ£äÉ(~2J&Góäh9/ZΖ £ùÂh¹"Znˆæ¢ez4O–Ñ<#Z‹–'£e^4Ï‹–/¢å«hÙ·»ìß÷ï.§wçÓ»ËäîrVw>«»\Ð].êÎu—KºË¥ÝùÒî2¿;Ïï.ïwç÷»ËGÝù£îrp #‡Åða1ro ß#÷ÅÈý1|Œ<ÃÆÈã12'†çÄÈÜy2FžŠ‘§cøéy!†_ˆ‘—bø¥9ÐÊZå+c•ã¬r‚•O°Ê«œlå“­r½•¯·ÊíV¹ÃÊwXån«Ük•û­2Ûʳ­ò •´Ê#VyÌ*s¬<Ç*“byR¬œËgÅÊc±üX¬Ì‰•'bù‰X™gžgžÇãdvÏŽ“Gâø‘8™Çsâä©8~*N^‹“7âø89·‡LéÁSzÈ…=øÂru¾º‡Üуïè!wõà»zÈ=øòn~·‡Lû•§ý*s广ʓ¿ÊS¿òS¿Vö~•啃zòA=åàž|pO9¢'ÑSŽíÉÇö”ù x~9·'ŸÛS¦ô”‹zÊ%=ù’žòZOy£'ÇÿƒžòQOþ¨§ÏGÇËÉñ|r¼ÜÏ7ÅËÔx™ÏÓâå¶x¾-^îç{ãev<ÏŽ—‡ãùáx™Ïsâå¥x~)^^‹ç×âå­xy7žß—¯âù«x9¥—Lê%“{ñä^rq/¾¸—LíÅS{ɬ^<«—<Ó‹Ÿé%Ïöâg{É+½ø•^ò^/~¯—,èÅ zɧ½øÓ^òY/þ¬—|Ù‹¿ì%öæ{˱½å¸Þrbo™Ð[&ö扽åÌÞ|fo9¯7Ÿ×[¦ôæ)½å•ÞòZo~­·\Ú‡/í#Wö‘«ûȵ}äº>|]™ÚG¦÷áé}*ßÿƒÜÚ‡oí#wô‘Y}äž>|O¹¿Ìîc>ÜGí#÷‘¹}xnyº?ÝGŽÿÿMîÿMøøMùãÿ±ìÇŸ¢Ç á«Úò¿ð‚_øÝPžÔÁ‚†gsg~µ3ÏïÌwá#ºZp]®ˆæÇ¢yßîüx ?ÃOÅð+ßnå»­üÁ¯üV<_Ù‡§öáY}øþßø*o>¤?Sê,ÐÖxóaý™b4Äzoˈ±ý™„TVõg|5Âp¬æ1ËFfIúزæcËJRÛòàËB¦œEڤ͑|ÖÆ `•ï2ËZå¡P¶`J° 8ä¹À„¯xÁfÁ^öÈ*ßó±¼öQôæý:>Ái¾–¾–ÌŠ|Ú@fg–íËçCËöUÖdÊ!¤Ð[žú*[1 ü°‰ƒ™åT3eê`¦$ó€…ÀòÁ¬2ÜЃ™yìö{±<¶l¤º;˜ñ‡æ~¤@6„Yà¶-ƒÈó³ìôSV Á1ÂxÎVùµŸ¥Ÿ¿r[(—axŒ$pÞ¦ e•óÿh¹â¯,Êø™¡Ì’XòÞÈÏCƒ—4ŒYàÁ-Æ*°ô« ,†ã ΔaÃYå•:>{8³†‘ËÆ åueþH¦,€ñQ?4’Y r!PõÎ#UÖ÷¸mÓ<,Ë‚-‹‚•×H;`Ô(fÙ¬L€ºz«|6Ø7-Ú` ü´½ˆ†‹6x4³dµ®œhæc¡´¶À+› Y"ÄàËäÑŒO§T!ÊF¨OBø.„ž„X Bø5h¨ý·!F·±L‚#6%Ã,ð·CÀáÚ ±±måG: |­åc™nÖV¸W»!–ü¢œËxT8Y— ~±ÀËêʯ!q¢_¨’<Žñ5ã˜%3Ô—ëV(OGb+.º]¯B•<¤JlÇÏ!”ØÎ’ÔΧêôxêöü2Äèöʈ LNžÀ”)Àì Œïž€3Æ/O`•U³ì ³\á*"^…ñ{P!@À…z1#ÜÜw"ã©™žSü¦‡á<Ä~øLç&²Êéu-3:˜o"ñI¬²ŸÎÒ®|ø$f˜wiÄñÊñI¨¬P/tPRß–À,ð˜VwäûXå̯,ÐŽÀçé8ĶŽ¸B;Yð+‘ñüDf¹ÞI5™ñµG ÚíÅð4–BÀÉØ/cœ•ïƒq‚< \*ýf  ±<'–‚–k5ƒ™ÇËf0¾ &x inAð‚pr)a? §á<\†¹=ø5h7!à4äCÀkšÌ,p¶BÀW¸—à|‚›pÆÌD=-zZÐË_E=úˆœx zò{ÐЉ¿„@ÇÀc˜^"¯-èBûÎÆÎþ6CÇ>e:fb¬û„}Ä>f`î¬*sbXæÂ8û/f`õؽ8a`' Sõy†ïNÄi;£¾?kpnêÅÎÏ1ä~8o¸`¸hpE_ÜÄ»üä5ÇÀ~¼bhœg¸j°Yõ®¥XõŒUhή\oéò ^Í®nnnnò wh#W7æåžgxhxdð+0”Œwg¬Þ}“Á‹½Ö2oÙW”²} ë'ú‹.’óç¢ü á’,Œ_þ÷L1KÜÕ˯ëÏ>Š™#JßV}îïÅzÖOêá˜/Š'¨Ð›õÊ3,¤ÈE¢d¤Ç¼˜ëbAÛý{‰X*ÞLQñwSè1¶B `+±Ù*Û1b˜ëæÅò ƒÙZ5v°Ç•Žˆõb(Û€M†±E¢L£ɼœSE6~r³HÌÙy ’»¦«…Ͷ²ºgÌk«¨>9ÔÇ2Jʔȼ~|›˜Ä2Åv*Ð$TÉjÉŒíѶz˱þ´ÑG3Ø^±OìÙêvâ€`Õ“=—n ;l;ÒìH)'D옚|!;.œ— ˜‹YŽXÄrñ›'ÄI*É"æœ'Ø)›q);-´·åØÑe쌖ÿÙ7O×jÄ»ŸpM®bçÅñfÓZJsQM³†]¢£Á¼“mcW„tMežÎÙÈy? ×Ä^v]Ü7Å-a<ãmQ5¹`w„éðbNÅžg8 ½±„Á´-Fp¢ðQöX<FXŠ>?ΘËÑä©ã,•r’ޱgo»$š¸Ÿ¥cð\=gØ ñò£Tá"ÎK_E­X?¥øérM­¸”+l r• RlUú +w1úÁÊu6DÉ3Ü`C{¤+Å”Á®3åcÃõå³áбxPï|Oý¹»l„Bv¤B–íeì‹Ï^°/ا£”ÑÊ;Ú†çlŒ2Vyó8_16NQ«ÒK6^AÕ(iлôÕy± ŠV_³‰Ê$E­‡ƒt^®,A¡”u‰J‰ ¾Â;£]¦(´7SÕ}®›¦LW÷GI3°$Ek%Féf(îu^UY²BGa‚nf)å7%è¼uL=N“t³½±„%ê<ÐûÍQÜéD{%éæ*¥k·™ØÉyZ¢d]ŠR2þ³¹èAóÅ|¥ê;òÝ¥´B:§ óŠZˆ4O·HQ¬ŠìOn‹ttÓÑ^¨[òÆoº/GüR­LËtË”7Kí±)–kgk…n…RZšŠ«‘Æu•z"VéV+¥§*¿åEíÉ×ëÖ*ëG'-Ö+lƒBÕÝF¥Ò&×&…©…Ú¨K}KvúŠÿ«dætóJÓ¥iû˜®lQÞ–²²–Rÿ¿Hê¼Ua¶êºM·MÑšM—R­úrØïLm¿·ë¶îµÛ~‡m¼vëv–¨ÀöèÞkÌRv+Ì™z§ýº=Š^)VéØryêö*zQ4䦩îÇt GuûÞ¬Z¼þ­ oÌѱýZÓq\—_/þ섎\‰JõwTå\ÝA¥´vóó²l¬gµ+^Fm¼¥ÓS\ó —tǕҼ-Ñ;Ó¸Ü@š¥f..ªëºÊI%«‰íÄ)…V+ì=ÝÅô@Ç\½Îªõÿ¾î9?Ʀçµs^ » Ðùv~A—è%…®ÑçºËê5Zî5lWÍy¥»ªz Ê5…]WÔÚWCq¬gú›ŠÚMÒßR´N’}k¦g·•†ùÈt¨þŽ¢¶ô McõÌË4FO¹ûH/ËÆúϧ;±}Æß¹3›æ´ÿ-›Ë 'öOm—“œ²m-Û6öO—ùNLÐÖ¶¤8²µ-Î0¿iýb±SõÿW÷9ykÝw[êļŽj'q‰Ó1ãÏ)~'^ÿùJõ çA]á”c,ý^¨üTÁ\­ np:Q´ ºlvòÂMÆ¿ÐÇŠT§“Fí¶ÃÕaÕ5È’î”æ”gj¤¦—Û‹ìOiÙoq:]ØÌ˜¶!øÓùâ¬1Ãéœ~Ó>$½ µ.;œ.M»œØ%£ÚÇ×ïtºŒ–¦Ü>l¤¿bÔî¡ö:]5:n®(¦ÔˆNäg_3ÒÍF¶Óuã [?;ådd.·‹V¨dQòÌå9åï”ra‰»FvO½RÎ:Ý7~vÑIm—¼«]ºàô°ôz™m`ìíS­½q»éÄkgý†Óc)wñw°_OêMq¾Ó3£ÞXÂðÙ=µ^<g½¸ëô¢ôÆò¥‘½²Uö‡N¯Ú]ŸËAœ¡¾&µ¬ú™lÏÇp/6À¤%Íš´Äb‰ 6Ñ!ˇ˜ÜÈ]?ÂD{44•ð¨Õè·ÅºLålŒí¼¦ð±&›PºYï1™3©oo*Õ‡šÁ½ÜYŸ þäDSé©>ŸÅéN2½ëÎä ¦Ò¯-‘hb“ÕC0›O1¹¥ XSµbÍãÓLo8S 8›nR=u¯ù<ɤµP¥Ë8ËÖÍ09ç–òd“^)þ|…Zè™ï,ôr>ë-…f¸G*÷šmÒü‡M|Ž©”Æø‹4^}®éwÚ½Í|žémíÞgœ¥h;öö ¶òù¦Òî©?ÏæL¿Àô;}Á~¾ÐTêi9Äõì.“ƒ|‘Épˆ;tWÍ|„S3âu˜/6Ùžð–nþìg.KL_ŒRÞñ*/-µ—¨Æ£WåËP—›V˜J¹Í¹‚4+m5ü2_e»²>{¬žàÕï<Á|M©¿ûÅS^}íï¸'|ÝÛOÜs®6vëMïøõg|ƒ©´Æîó—8qïĽà›J-»k?´?úTSíÍøí¾†4ûé!óÖφš°OŸŠôw•s°aK©å[M,C½rG¶™”y†LS›½¹†í&6Ç`Ì1°]&Õ-šoÈ2í6¹¯Aöj÷jÃ>S)k~7…^Yo`†ƒ¦C(ñ:Ãa“i£1©7 GM´SçZ ¦:'ÁÁÐÑš„Þ]8UüÄÀ„àU„áÁª V]ˆ¯û³PjQ_ÿG85E wÁ~&Á„®3•…³U¸ü*Œÿ®ƒ˜(7” ãL&tó™(¿Hg¢Â*p[«îëu¢ÂFè©iïÔ!gáqZ'*À>W/ÜR€zQiƒ^è6ë…y‹^TÞ¡rpXá$ªìv–ÃN¢Òqàô<'¡;í$Ê_t-àâã¥\è¶¹\|rŠ‹O¯CÀ…ûKà50Ä Ü‡DÕQ Â´Í tG Byl.s…pY*„²BÝv!œ²>îQíâ*âáqW®á<Ã(”d£0-7Š?^6 Ý£0f˜„q‡I”9ÃYç8 ·¥Î¢ü*ÈM΢ú5gázßYTèï"Lƒ\„ûZ`½+ʬ.'Ü·—º=·Ê‰ªÉå…ûÒò¢ÂJÈÍÀÑòÂífyá9¼Ž_OQ>¥‚ðÜXAT½PAèVåž/*ˆÏFº 娛øüµ›¨xÄ]è=D¹%‚­öM¨(ªÏ¬(<¶Òi¯(ª©9‚ eA%ñùÕJÂý90È,¾˜lFÄD奕ÅçÇ*CŸˆ³û¢²øC_)ªŽ–0Lf râËUÄWiÀ £Špɪ"Ê®"þë äÍ*âO ,âÏ»,ÂeÈG¢Üˆ„iÌGÂ} 0í#¡[ÛÕNû®…ëí…ûîOà&~*œ2>å.}**¾þTü¥Uñ—!U…ûX`°ªª¨º®ªø:½ªøkFUQ#ØUUÔ\\M|ž^M('« ÷­µnþAÔÞW]nV¦ûÕE¹çÕE•OQeާ¨˜þ™pßÿ™pÍ<ÿÊÐGÔ9ñ…p}ü…¨;äKQyL’¾õR¾߬øR( _‰o·%êïþJ¸Ž¹¸dN~%tÓÿKümõŸ„ëÖ?‰êç OüY°³¸–6{eÒ_DÕÀŒ¯EÕó_‹êÓÿ*þ¾À‚ßÅþ<ª!LOkˆÿ~UC”]CücuMñϼšˆ[Cy-õ jŠº}k ÷¡µQaêˆÿÙ[GüëqÑ`b]ÑpK]Q~7p¬®0Ìü•óá¾ø[Qýö·Âi}}Qñj}áþ°¾ø(ëo¢Ñ¿ CþßD…³îgþ[|5ýâ«YÀ¼à¨ÿîÇþ)œsþ¥2ÿ%Ü/6ÿÕ¿!êFCÁ†6I„ûäïÄ?Ö|'¯ûNTÜöŽäw¢úQàôñß Äï…û¦ïE“ÉfüvSlÿ£¨: 8 <ÿQ”õ“`«¼×9CÅôl·h¼Ö[ˆuÞ¢é`#° HEÜfÈ4ÈtÈ-[!3 3!·Cîv»¼ÅYÀnè B°=ˆßë-¼öûlüÆÈCÞâ§ÃHs8 Ž9°çBžð?ž„žœ‚Žü~:íÎ@žÎÁ†ßùé¼·ð¾\.W¼…骷ð¹îm쬾7½…ï-à6Üî÷¼ËzÑü>~êðÐ[4Yà*š@ž®Œ¢UÍÃþx <ƒý9ä Hä×ü%$òlþ x ýd_Áúùˆæý!“<„×ÈC€¡°Mû\4}ô‘>ÂkôÑc|D³±°¥à÷Ç!<˜L„}$“)Øf*Ò>2 ?Èéöaÿ¼’7aìódè¾ Ç¡ùLØf!¿ÙÀØç"<‹¾èE-ü.ôùÀÄ-DšEÐC_,–#¼r%° újÈ5Ùu/*ëŒÛ zãUo½ð_ç#ü×·ýsÁF…ÿFè›`KÒ€t„·@n2 Ÿ+'¼¶A϶;`Û ì²€ÝÀØ÷û|„ŽÛ™@¿"Œã‡‘îpú1à8ä'€“@p 8}=œÎç Øö"p ¸ \®×ÕŒ¡Ê1T9†êÇ®ÃvƒŽ7p ¸ äÓù@ú»×½EÀ}Ñâ!ðØì$\ |Œ÷}à ¢åSÈgÀsàð6Ô‡€W>¢U__ØÏW°þÀ` ¯h…}m2È×8ÄW'~ Û0`¸¯á+~ ŒFc€±À8`<0˜L€D`20ÛOõÁÓ}ÅGI¾"$ÙWxÍf³7¶yÐS Ï‡\¹X}1°X Œ¯'¼–AÞTDÈrä·ÂW´]œRDÛÕH¿X ¬Ö€À& é6ûŠÐtè[€­@° ȶ;€À. HGÛ ¹Ø ìÃöû!³ƒÀx7ázÈW|qÄWtÀqêp 8ä¹À à$œNg€³À9àÃyózî+"_/WÀk`„³`}›¡-i&"ûCA y¼ª`C …> ¤WlD3á5ú(`40  läx`0˜$‰Àd` 0˜L’€Ê™ 9˜…ügCΜ 9H¡ßûurÊ´rv}¹r ÂK!—C®VB_¬ÖkuÀz`°Ø¤›4Ú/` °ȶá·3íÈo°ØàzŠÌ‚Ü ìöû€ý@6Ò€<‚~¸™èt¤™ñ„QÇèx9@.€¼Ø‰f"êd3¡Ëkf<Å ÆÓÍtÆ3ÀYà\3a<ßL1^h¦Ý/pÑýb3Ñýò¼ Içÿ äûUÈkÀuàââÜ„~‹ŽŸÒBæ#|ò.gà>ðx< ÿ˜ŽQ9ÔèOg?‡|ùòäkȾÍQWš‹îý!@„9räPÈaÀpà$®•#QÀh` 0éÆã¡O€œ9 xZ×Ð_E÷è‰ÀdÄMœ L¦7G9HFÜLÈYÀl`0˜¤óÎW÷…‹€ÅÀ`)¶Ý„cº r9Â+ WB®‚\ ¬¾X¬6M@*å ¤57ni΄uksaͶ™Àv`°Ød»=À^`°È´1hGcÐÆZ!|8ŽÇ 8œò€SÀià p8œ.KÀeà p¸\n7[8ž·|àp6j—ïaÿÀMÔ©GÀcà +àðx¼^5±}ýDl? ?0 p.bчƢÿŒEßÙcˆÜK?Ñcäp?á>ÂOÄÆø ¯±~¢ç8èã7r"ä$Ø '“ž ÿ)ž|©©ˆC?Òøˆžð[zâXzMG^IH;ödÈ™³€ÙÀ`.âçA¦ó‘ßÈ…À"`1°X ,CÜr`°8ú“ˆ_yØ z¯ñ½×"ïKEïuÐ×C/¨&zo€¾ú&ÈT`3pnð,‹è=Ø‚ø­~¢ÊÜ;r Ûv?áºòÜÚ]~â·,èðÆwû‰>ˆî³ÀîôA±û Ø}öûìòoû!³± šŸß@$¶ÃÀà(p 8ä .8‡Ûõ¤Ÿñ”ŸÅOü猟hpòp¸\.øÿ\®ø‰úW!¯»PÔë(æ è7ýÄ¿oA¿ 7ãß(ç¿Qîç#îp¸܇ eúÏH”é?!Q®? ”ïß(W_¶‡(›(Ÿ6v¿wNˆþì)ÏüD?†_éÏž“–Mô‚è%Ù^‘†m°¾þÆþþF1 ð ôƒšºAl¿`ƒ)4ÊP ç'†Q"4±ƒØp˜FPh$%…ÐhRÆ%Óx`%š¤€&ªQQ"Ñd¢)”~*Ñ4¢éDID3ˆÐ `Éþbƒãf›å/³ÙÈ|0˜GÑ)dÐB`°˜¬KȺ¡eZN¡­V‘e5YÖ ´–Bë(´¡ ÚH¡M¥Rh3…ÒJ§Ð mE(ƒBÛ(”‰Ðv í ÐN„vQ(‹B»ÚC¡½Ú‡Ð~ eSèB)tˆB‡:â/¼ŽÇ€ã@ œ T'¡ä§(pÊà,p8\.—üÅPvÙ_ gW‰®!ãëÀ à&p‹Œ·‰òºCÊ]¢{Ý'åÑC„ù‹at‡Ñùbd~Lô„è)Ñ31‚=÷£XæŸÐј¡¼@Ò—À+”ä5Åô á¾mëGÚ+Òú“6 >)ƒ  ÐX1º‘ÀMÃMÁH6Æ¡À°†Cw‹6E–ÑDcˆÆC‚ñH0¡L¢” D‰D“ašL¦Ó$`¶Kf³hÛÙDsˆæÒvóˆRˆæ- ½ß¶(´˜h ÑR䵌”åPV²’hÑj¢5Dk‰Ö­'Ú@´‘hS€q»Ð‰±ls((h ÑÖQ=#À¸ÞÕ$ƳÌáº=Ê3¼rRv¢è›IÙ[±åÈ‚²•¬»¡l!eä<Ž¡GÇ{ðñlo€˜Àöe :HtŽÇÄ$– \V8ýõÆùLgÌ Ð‰Dv"t’(èŠw‡à p€¯–ÀÎQ <±DvY]€ù"Y.]&ºBt•èÑu¤ºAÊM(ÿ ‰;ØD–F”Nt‹ân#nÒÇPà²$²|„îŽ_"{F¿õ‚è.ÙîÝGŠøixû‰ì!ÈZå1)O PÞ ‰-!ZF´’hÑ¢§È¥ÀD?C>'z­GV€òÊ+²¼&êÛÔ¨?Ñ€‚}‹z1 †RÜ0(ÃIe$)£ Œ&e ÝT…eÆC™ÐBxÑ]ËDè“€ŠHlÃ=™´ùp¦2qðFØ4Š›N”D4C-»d¤€¯’ÈfB™ÌúÓ&s À{að^Ø 2ÌÅΣ S(‹ù- e!Ñ""ôá l,¥ÅD-óZBÊ2-EvË€åÀ `%° X ¬Öë€õÀ`#m¹‰(•h3QìéÀü6=€Ø =ØdÛˆÛ ì¢ ²¨¸»[ úîi¢÷·“©@“Y6iˆ"Ê":Lé´SØ1lpœ”l"$›ÊrZˆéìì'IɃrŠ”ÓPÎrÊ9RÎC¹@ÊE(—H¹ å )W¡\#å:”¤Ü„r«…˜Få™F{=öz:»M”ßBT½ÓB$±{-Dõû-ŒwZ8‹dvó3ÐClk2{¥xÜBj+±„mu¥6ŸhÑ&oœê%l!-FKHIõ‹ÙRÒÒ(Ù¢ oøH°X¬V«5ÀZ`]+lwŠRŸ%ZOÁ °£oWûrtêKØFÐÅS_b J?´Yý5¢t¢-j¹‰2ˆ¶QN™*ù¶“míëNlŸÕJ,%ûR²/¥dËÙ¢½Dûˆöeh%¼’rˆè06?BÊQ(ÇH9ÞJ,c9¤å"å RN’)´S¤&í ÒŸ¥î«–QC´Œî{–±ùDÉD¯¿G²s”ö<Ñ¢‹D—ˆ.]!ºJtè:Ñ Êô&Ñ>ÊåîÁ–³[d»M”OéîÝ%ºGtŸèÑCJBw‘Z‰•ä{­d[‰T¨”ñ *ò ¤0>m¥¯gØËç­Äjö‚è%vë)¯‰ú¢[„‚ûæU´Ù*ÚÓUtÁ­¢¬V³þ;€h Ñ ¢ÁDC‘äm†¢¬eÃAëʆ“†›=6‚”‘ø…Q¤Œ†2(¼Ò¾^ãÈ8­Í L ÐD¢ID D‰D“Åz–Ñ´(“h;ÑTŠ˜Ft€‚h,ÖQc±ŽÊ¾žM§ˆ$¢DÉD3‰fÍ&šC4—ˆÄÌ ÕSÅFÊhe´‘- àB¢ED‹‰–-%ZF´œhÑJ"d´‰Ûlb“+‚V‚ào¢ê¶‰üæMä&o"§y{U´†’¬%Z‡¬›ig7ÓÎn¦ÝL;»™vv3ÛH´‰(•h3ÑŠM# åÞÌÒIÛB„Ö2•Îe*Íl«š3Ñ6¢L¢íD;ˆví"Ê"ÚM´‡h/Ñ>¢ýDt úyáÂÆyù .rȃÂte?(¶°cDljrˆr‰N$Ê#B9Óéøna§(xšè ÑY¢sDç‰.]$ºDt™è ÑU¢kDTœë( à&p ¸ äwE»Gt?Px>@={HÜÑd°GˆL¡'b+ùì)Ÿ='zAô’èÑk¢¾A«_6€ ·•ÜÖ ÖŸ‚›(˜JÁA Û¤å“-›´”ä-$Û ²ÁýËdC‚@Cƒ•„ ƒN†D#‰F†9°±ã ÀD`$“)AÂs*0˜$v³™0Îfs€¹dœ‡Ø” ±—- ûØ¢ ±Ÿ-AÜR`°X¬V«5ÀZJ¸.Hd³õ¤mÙ&¢T¢ÍDiDéD[ˆ¶e]©ÚFZ&rÚNÊ(;IÙE”…ÐnRö@Ù ìöÙ8怃yˆè0¬G€£°#Ãq¢¢\¢D'‰òˆN&:Ct–èÑy¢ D‰.]V Kt•èÑu¢D7‰nÝ&Ê'º$jÞ îoüÍUfP´‡@Š÷˜Î+ð x¼M^‰ãì5QߟAýˆúÿŒ; ` 0 †Ã(Áp¢D#‰F&C4–hÑx¢ D‰&%%M&šB„Kð]‚ÇÙT N#šŽK"eQ2ÑL¢YD³‰æÍ%šG”B4ŸhÑB¢ED‹‰–-%ZF´œhÑJ¢UDIn Õ¤­!ZK´Žh=Ñ¢D›ˆR‰6¥¥m!ÚJ”A´(“h;Ñ¢D»ˆ²ˆvíÁžîU½SD`? ‡€ÃÀà(p 8ä¹À à$œNg€³?‹êç~¹ìÑE¢KD—‰®]%ºFtèÑM"´ô¹äç’KœK.q.¹Ä¹äç’KœK.q.¹:s9ÔªçR#ŸËnQ·‰ò‰îÝ%ºGtŸèÑC¢GDD‰ž=%zFôœèÑK¢WD¯‰úƒúõ'@4hÑ`¢!DC‰† 'A4’hÑh¢1Dc‰Æ£=&I@L¦SiÁÂ}z°8Éf Ìf³9À\`B‰öû¢m›,ò¨YË£&+Z+×…ÁÆÅÁŠ8Í– åÒ`q þ’qy°Nœe+‚A+‰V ¯Õ¤¬A¢µ¤dø€Ö‘¶žhìƒÅòÊÏCx†B¶‰âR·™”4¢t¢-0m¥äð‘Ü3‚™ø½ótƒÌ¶CÙ ÎQNç(¾úŽ`ã… ÎÆ¬¿ q‘í eí&ÚC´—hÑ~¢ld'‚|ˆ‹Ô±]d`YM!ø¸äs\déXV¤¬(+¢=D»ˆQ.‡‰ŽÐî¢ ‚ÂŽB?r(2ʉ`Qýd°¸LùeêÈ/Ó“ËìÙN Wع`qž§_c°ÑEàp¸\Åѽ\×ÙY?ãĺåÄMºEaû€[HqȆñÑ]¢Í¾â69n+ËC¹ºT‚¡<„òˆ”(Iyå))Ï <'å”—¤¼‚ò𔾭áÅ´†ÒÊ€Öâ]LwØ Ö¢êàÖP† %F4œhÑH¢QD£‰Æ%G4¹M e"”I¤$@I&S` ”©¤Lƒ2HfÉÀ“ÏQ«!g³9À\J<(¡ùÀ`!°ˆŒ‹‰–-…i°X¬V«5ÀZ`°Øl6©Àf H¶[)à ¢meÛ)°ÊÎÖ¸°vµwUa7,{(€ ì.]`÷Ø^J°¯µ¸OÁ‡ì@kÐA¢CD‡‰Ž¡{Ȳ$è('Ê!Ê%:At’(èÑi¢3Dg‰Î'º@t‘èÑe"´íÕ¯´ìÑu¢DøíGÔ€—\Àn¶F^r»E±·‰ò‰¨o8Òn$‹¨~·µxB^øÊá »OÁDHèþ°µxFàW¾/èáÖ º8^P“ý‚Ò¿`[ƒž=%zFô¼µxÅ^½Â¼ú† bý!¸÷"j B`¦äÐÑW7Œh8ÑuÐM¢D#BDõ‘!¢¿n4Ñ¢±DãˆÆM šH4 ¹%‰˜L„n6JÜO‡cÔ_7…"¦M#šN”D4ƒ(™h¦º-Ñl¢9Ds‰æ¥Í'Z@´hÑb¢%DK‰–-'ZA´’hÑj¢5Dk‰Ö­'Ú@´‘hQ*ÑfìPl¶À6 Øì1ÞåÅÝÌf ]!ÆA.z1P‡[_¯Ý!Âk°Øì²!bî Ñ!¢Ã!¢üRæ{ƒŽ"Ï]HtŒ,ÇÈ!%Ê X“›!oÜ` ÔÑKò“°äQô)¢ÓDg`: œÎ€‹ÀR$¿D –7]Ctù¾ «ˆ»F¡ë!b¨î&i·ˆ^ÿá/뎶‚v›l‹|@Kˆ–­$ZE´†(Ÿ’ÜA9ïøb+ow7ÊŠ»Gqûšî“ö€èa®îG!b˜—ÿ0Ý:¢ tñ8DÔ|"FêЮŽÔõ'zŽl_„ˆìeˆøüuˆ£ë×Õº ”P’2Ê`R†@ÖFŒÓÝõãu¸;¯C¯6^‡nm¼}×xÝZÒÖl#ªŽjcœõ£³˜¨Cÿ7Q‡Ën¢®osÐäóúG(ÉžŠ^©'è&ø#4¶ hÑx¢ DÛˆ]B‘¨›ÜæË­„à²M%šF4Y&‘2ÊÓ $C™I–YPæsy¤ãv8r>°X,K€¥À2`9°X ¬¢ŒV­!ZK´Žh=Ñ¢D›ÚˆIºT¢ÍDiDéD[(v+QÑ6¢L¢íD;ˆví"Ê"ÚM´‡h/Ñ>¢ýDÙDˆ":Lt„è(Ñ19§˜ªCË>UwèÑa¢#Dh9¦PË1U‡æ}ªî(ÙŽ'Ê!:E”GtŽè,Ñ Êô6ºÓFxÝ…¼Üo#’tÉ~ˆy@¸þ?pCU<žc« Æü?’î<.ë3¿÷ÿã^¯Ü™ÎÒÌ’&¦I§vfÚ33¦ýu–¶§ýM뜶L¢&щi’1fÑD“É6É$™Ä(‹ì²É*";‚ì È¦² ²Š‚ ¬ ˆ€€Èy¿îóÇçy®å{}¯ïrTÔç=ÅùoèYDŸ+ŠÕßšDë}Xƒ}ÛuÉWx*¼Þ Å…¯¢úi]õõé¯P*‚¶`}ÜnŽrá:ÊtŽZõ0šh Ù.BiÈ Ž¯uUáAý}ºÒ‘TEA4Ä@,ÄÁaˆ‡#G!’ R Ò 2àdB‡lÈ\ȃ|&¥½¸¡@›T¤(VœØn’¬ O› '·kÉvóDü¿˜Tkõ3¢l»(m©Ö õ®¤tÎÀY¨‚j¨QZEÝv“n­ßn¾Ò@r^{ ‰DgFºUpéÖfŠ:5Ò95Ò95Ò95Ò­-Zº•Æ6%HÚá"t¨êI'tÁeè†5^ÙnÒ¬¾[Tê%;¸E„Pì£ÇU¸ý0ƒ0ÃîÁu…1ÐÉšfMf¨HÝb~8¾Ýüø†Ö7¡˜RÜÚn¾:½ÝdYg`怿á4úC%w(é¡(Ë:¯î ŠEÅ]j—àžJËŠÅ*÷•¬)ö½¢sVá©ðRx¿b29Ó2939ñ29#3­>j< ð}Åxø)üŠ@E"XQò3ãqPŸ!ŠPEØ+ZS8D0lã4?«â!ê"aòyE 1 qpâY–wª#¯˜lëQH2ÙÖ$²Èu‚§¼dM0å“cMƒôW\~ÿð É³êY/ÏzLm™Š,…š-鯘\62—Ìe_=®9ç(r_1Ö<ȇ˜åßb¨­HQ¬8AåI(Ñ`§HJ•”‘èS`-W§ E¥â´âŒâ¬zTé³ZQCÏZUè>åQGaå9“Ï5 ŸP`=÷Š2M0Ÿ æ[ë)6hÁóŠFEÍЭЦú ŒÕ¡.ÑØ ]/“u›ÝóŠ)²öB\…kКâ É’amY!ó,dˆBÖ^ÈŒ‹¬#d PO¿ë0 cÔuBÅq¸A‘?s°.€&RÌ ÅîëÇÄ+æ¤uJ+¼¥˜VÜVÌ(fsŠ;¯˜î‹Ê¼ ‹Š»Š%Å=ŲbE±ª¸¯X{Å”ÐÙ²o‡ñðTx)¼>РߦÌê·C—f’%$AJ‚I* ! UFpHU‘#JŸÑ;L)QÊþ(åà•r\J9.eÖZ›)Æ’Õ“5ÐÐö˜ˆc°ÃÕ©õý(%KÔ*’ÉÔ¤P“ zø)³¦‘¥»»nÑ“‹z£&²à8múº•Z³)æ@'SÐ!±äRÒôÈÓ–ä+ ¨˜gþ…dEÀ¹R¼ÃTXžÿeÊ­'µžªNi™ÒªÑÖ—³õål}9§n9r6ÜR¦îåêY¡¨Tœf DålH9ë+çáqFmg©©bìj2­ü´µv‡¨ƒsP¯áHÎC£JM$ÍТR+I\€v¸aO‹²KЩÕuí0•L¾’ÉW2ùJ&_ɤ*­—Õ£›º Vr!«dž•̯’ƒ{ÚÚÃ@W —º>²«dœÎ×v˜õ;L•µêQ 5P C4èõ²Š x—µ*ëémæ,9ËØY䫬Ãôë0 c07à&L€®†Y–¾Ğ©fôöÅŒbV1§¸£˜W,ì0µ|/ê¬wwÇÒ×#ß0õÖeµÜаêÎYW`U­µa(5Pj´®Á¾WÅ~ð/ð~U=$”ø’ø)ñ' €@•‚_5çÙ&ËA’ªC!ìUãNí›E®û‡^5ÍV½„7[£^5­Öˆ…¸WM›5^&¼jÚ­G!’ R FŸidéñª^WrŒR&dÁq–­ˆ¡-‡š\ȃ|¸Ã8d…PÅZàs9ùª¹Èþé°žzU”B™6ªBQ©8­8óªé´ž…*¨†¨…:8õÐ硚 Z Uõ‘\€v¸ª¿DÒ ] Ûf'·ÍNëeM¶›ª¸½ªê#¹ªäš¢ŸÂ  ÃÈ«æ§ÿ%NÿNëuêFµ¶1’q¸7a&a n±häF‘Äò©0ÏpÓô»í^ìy1C6 sЭ Ã’y­pdDr–aVá¾×û^3û_S…'èÌêäÌê´zQôõ8@âûš¦£/íeë­Çu⾦‹é·õ¼®ÏÀ×T¤dæq%Á¯™õuÿjz¬!¯ }±{øb÷XC)æ¿(ÂÈÂ!A$xÿFD‘EC èkßíþNÄRŠƒÃG ŽB"$A2¤@*¤A:dÀ1È„,à 鸦Ÿ­ÈQä*òùŠE¡¢HQüšÙpâ5óµå¥lîSæšµùeQó¨é·V¼f®Z+á4œ³P¥¾Õ =ª«ög­¢NqNQ¯hPœMФ®:•ø›üÝþÞ„¥›²êoðg†úl¥c\xÍü ý53hí€KÐ ÚoƒÖ.²ËÐ =pz¡®Â5臄!†¸£0ãpnÂLÂÜ‚i¸ 30 spæaá.,Á=X†X…û°û^ûÁ¼À|àø‚øCpˆ_×k¥"øu󃃯›aké6JzÅæ˜}7l §.A$DA4Ä@,ÄÁaˆw×iMG^7_MxÝ\·&ÂÀ³"‰,R ZhH#K‡ !2^7#ÖŽQ—©ùf‘L<«úIêuºn=N]uºŽð 1ÂEc„‹ÆˆµºtÊdÓM×&œ×õô®ÈSä+ XMÝ ÉŠà2Åb²,v›•ÍÀ,œ¤®NA)”A9T°˜.cÖÓ¯›Qkã³¢j ˜ºtž_HÔíkgµ]ÕŠš×Í“µ¯›ÿ¨Óœê Šó¯››ÖÙÅ4ª[UÍЭZªíu3imW[Ôw¥CŸ—Š.Þ˯›ik\QM/I\Ýië5²~€A‚aë0 c07à&LÀ$LÁ-˜†Û0³0w``8QîjvKŠ{Še4+ú¼ÿº™³î{CìÏ7ôJâ ·~+|ȨޗÄü!!‚ßÐ[§"„B(„©®ˆPRL?o<"iˆÒ`ÑŠ˜7Ì×bß0~Ãl8ò†Y´…DHRsòfç¢k Ùù§ÍúÔ7Ì’52àdBÏ6qz?Qà™mÉšEëqȆÈ…<ȇ(„"(†pØq%šÍ)E©¢ì ã(ìXOÃ8 Uö’hß.Bɪ©«‹ÔÕ’ÕÁÈoÅu…1¸L—n¨§Kœ‡&h†h…6¸íîá¡.A'tÁe膸½ÐWáôà  »g ×aÆ`n¸³ßše~³Ìa–ù!̲5¶¨õæÊ’)¦l1މ7ŒŸeê ³f†ÛÚ—3o˜ûÖ˜çDäz.¦úîsæ+so˜,¼a¼lwa —m™lVá>¬Á¾b?x‚xƒ_ð€@‚`8! aÀ)¾ÓX"‡vš&KäNãmË~Aœ„S/˜¶˜"âàðNãc Ý(¢¡u«hÛj~¿Óåùë?5þ¶óßIùèN%‰:‰$YI ‰ÿ6c©ü™’TÕ¤Q“®$CqŒB&dAö&qÜAåz‘C– y›Ì“y;M M—¸@ÛhŒBªŠ”“œPr’¤DÉ)]ý‚le;E9TìtýùCæ “¶¨Ö¢JKÅNj;³Ó„Ø.=¯ì¬ªª¨ª†šzîPÔ)Ω¥~§y°a§±7î4‘¶U¶ª²Âh‡‹;Í!›î-‘¶Š— “:]£mã/‹û›DÃfqy§è†¸Í4´@/Å>¸ × `p§‰µé#Ö6L6×aÆ`nÀM˜€I˜ÒÜo‘LÃíæogHfµ9s$w”Ì+‹Š»Š%Å=ŲbE±ª¸¯XSìÛe,ûwiAO%^ o…â€Bï¾úô£ƒ¿’€]Æ#PŸAT+9¸ËÄØ²¶ªBU(„Q§Gü[è«cÓí0Æ–ÚÁá&‚®‡ ¢ ô0kóб‡7žì$PÔ¡‰³ÝežHÔd’wém7e—I°¥Aºª2Ç™Š¬]æˆí8-Ùd9»Ì÷r)åQÒ;Á–O±€bíóÔ=o~^¸Ë|µx—I²Õl'ÉJ4ûS$¥´Œ¤íE“h+Ú¦¬ëye—ŸWvŽþ p¡~‹ZËw‰ àŸBØš¶˜Û(è’b» pZ£ŸÙ¥ä¬’ËëµiUJjv™T[í.ãªÛeÒlç à<4jzMLñi=DSÑÿ´¸ªÒ5’ªZ¡Í=Ôó¢O·¶ »L†í"tÀ%ÐûK†­“¬ týK·éå$Ãv™b7ôÀè…>¸ × `†`Fà:ŒÂŒƒû/€j;o*&“»L¦-n›¸E6 ·A“É´ÍÍÂÜy`˜-¾¨¸»Ë¬¿·ËdÛ&¾'VTZÝermzW˵UC ÔÂБúqó%¡uäÚNoi¿19¯›îê9ì„\Û0×jß›b?x‚xƒ€Xþ“ï›ÆÃÿM“o xÓü(ðM“ÇE<‹¸G%]È¿ü¦±„¼i m¡JÂH•D¼i ¸’["ß4Ŷ(ˆ†ôXˆƒÃËψ;°G¨K€£I )ZMꛦȦh‘- Bè[lK£Û"#¥“eÀ1È„,(a>Çɲ!r5pI>¨THRÅpNº‡SP ePP §á œ…*÷P¿e(¨¦XµPç à<4B“» ‹5B3ŲVh¡Ø mpÚá"tÀ%è„.mÕeE·¢GqEÑ«è£ñª’k$ýJÞ4'lCJn¼l,#ošÛòvqp³ØÿŠèø†¥aêi1FNkÄÀa𤳬1À-:Óùu…tñ%Kùs‘öŒëæ›VWÈ:›ñ˜xÓ”Ú&a nAàsbìe1Mñ6ÌÀ,Ìé¼½£hzÂx,ès‘Ê»°÷`VÔè½YÉ*¥û°ûÞûß2OÏ-‹Ìë¯EÂFzPçíîFæC¦ûºæÈ¤Pô?ˆyZø“@ "á×kŒ±¾æ"˜ªv²ƒd! a‡à(^{JD¾e¯è~–I² ÈŽÓ'r ò   Š X³;ñ–ùéÉ·\§Þú¦«ô­oš [Ù[¢\-ŠÊ·Ìc}ÏšrîfåläÏN«öì[f}Õ[ÆZý–9c«Q4Àyh„&h†h…Àïˆ62ÝÏØ.¸ÛÂbÐõÐNÃEè€îM•mõIóóº·L­AkoT4)bþÆœ³µ¼%Z¡ .@;\„¸Ð—¡zà ôBŸÆ¼Jr Î1z¿ª( *"†•®¿eêl£JÆÝƒn7É&T5I2¥äÉ4̨4K2§dž„߈° Â"…»J–Üc eÆÖήãdªãdª³¥l+:ø«ŠûŠ5žݪܿ[‹x‚xƒßÝÆÃOáO!!‚á „¨GØn½`ì6 ¶XyJ¯$:( ¶H²(uˆÞmê™Z=põ<ÑÕóD×`‹¡!–nqp˜"P¿Û4Úà($‚î¨ç¹…6Ú’(&C ¤B¤CƒLÈ‚ã 9 yPEP 'à$”§´%¥Š²ÝfCùnÓdÓ þ•»ÍƒgvëYí‹êݦÕVµPç p«¨'Ù"v›ÛyŠmEÆ3BǬŖþ°²QºŒÁ”ÓeŠì6ÜÛ,Ö6‰Fh‚;4x2ÊêKâ.Å(`Ùb£µ™Îd·hͤ!r!o£ñØ¿Õxx2Y/ð‡pˆ†VøÑÂ@­ Œ›ž0Zyæh±…‘ù1Z0ÿZš‰J.hç´S¸îÞü…¾ö-¶ †½ÈÞÐ{@‹­ Ê©ëÐn^´˜Ÿwî6ë/ï6m= ‡°‹¶+jêUußnÓa»÷ßæë×v›K¶šªÔO•ÎûÛuƒ»Íχv›@ËðnÓeÝm.sn=4¾ÛôØnj” ]Lzxàîá”í¶MÎÛ>²«¶Û»]³»­¦ß6·[è"ÕÏůßvGÃÎ+v›kîaw›AÛ܃eXžmâ ô‚V2ÀÉ=h[¥õ>¬Á¾=b?x‚xƒ_ðàT Øc,Š Eð3l –Mf}¬M†{ÌuÖxÝN‡ ¢ b âà0ÄÃH€£I ) ip 2݃n2?ÏÒÜr¹Šë ŠóŠFE“¢YÑ¢huïÙ7™–J(µÃEmA‡âÒÛf…»û ÇÙ£S5]4ëÏãKÂeªº¡®@¯ºö±ðU¸ý0@ã Á0ŒÀuuôŠÓò㊊›ÔNÀ$L½mÖßzÛ¬q _ã$\³EÿDܦnæm½PϽmöÛù· óÚ¨ z…Þo× õúÅ·—} îÁ2¬À*h0O»¾R^öû×`ß;b?x‚xƒ_ð€@‚`8! |%ÂÞÑã•"BqHùŽñ±×oû#B_ÑÔ]¦®F~+®Ã(ŒN/{1èôò±×A5ÅN–肞íÆÛ®wu{/™Þä½íaûh½ 1¬h€l† –º8¸NqSÿ­Hf”HÝbþ9þãoOÔV$)’)¤@ê;&ÀžþŽYìlÏ‚ã 9«þy$ººÛuu ¶ëêl? :A »N¿`{uùt.€B(‚b8'¡NA)”A9T@%pNkÕggUŠjEæZûŽ µëªj¯†¨…¡¢,õ7âæKBS µŸc‰ÓÛDý;&Ä®/LÓaÚ¡öak Ëyh„&h†h…6¸íÀ?8¹øŽ ·w¾c"ì—ßÑÓN7ÙM³Oqõóàµw\³ëm&Ê>ðޤÏÙ0ŒÀõwL´}LÝÇIn(¹©˜ 0©dŠä–’i…Vd¹­˜QÌ*æÞÑ ¾>çõ¹ XT~WŸKŠ{,¨wKÓ÷ÍúûëMœ}õqÖ@;0Žg}Mä¿(ÂÉ"àxÿFD‘íûˆ&‹þz9û.ξŸOðoðà ~àA !BÁýÅû¾xŠšߙõ‘¿3ñÌ/žõÆÛ/=i¾ý;“`ýnD3eqCDqFà:tÑ:J6Úš|¾zùìÆû8uúþØoÝ„ ˜„)¸Ópf`æàÌÃ,Â]X‚{° +° ÷a ö½'öƒ'x7øÀð?ð‡„ †ƒ¡áÀ.xO—iE¤"J­ˆQÄ*â‡ýÿ G}yÏ|-AŸ‰Š¤÷L‘=YIÊ{z&L…ô÷Ì ÿíØ{¦Äž¥¶ãŠì÷ÌI{ä¾g6䩦@Q¨(R+N(N¾gNÙõ¦²¾ä=SfIÜ€‹Ð:.¥—2{)]Ê *ÀýG=•ï™ržLË™E9¥ö3ZCÅÃzÑg¢VQ§8÷ž©´×CƒJçŠ&E³¢EѪh£Ã%íï™Óö‹J:´%—ôÙ¥¸¬è~ÏœaößêyÏTÛÿVOç$Wß3×Hú!y—± è §Ú>H6¤e‡Iò¨ò{KŒP¼®úQ’1WéɾgÄM•&(éJSÍE¦Ú^úŠü =¶Š…ŤºMÑí–’i½ÝxÜ&™QÍ,Éœ’;$óJ‹¢ã®JKŠœ7UÐ+aµýžþ²jÒÖ™‡Vß3?_{Ï<™»Ëübÿû¦Þî7þQx¿¯Ã¾K‰’Tû*ñ#ñW@¨$ˆ$XÉÁ÷M—-B!Œúpˆ€C©nQ$ÑJb±Š¸÷ãðûæ¼}y‡8¢š;ÿ¨s á}ÓÈ9ÐÈ9ÐÈ9pÃ’ø¾i¶Ÿÿ–{NŒC²H¡>UII:T¸íÁû¦…1Zìî™™ù¾i¥ØJ±ÍžòSÕß\ îu¿jÍ\´wÀ%È}_äiÜ|E¢PQ¤(VœPœ¤C tÒÿY)”A9T@%œ†3pª ôhçqÑ^Cñ2CuCÔR×KVGvê¡Îíd£dMdãdÍd7Én@? ÀL´Ðošì6ÌÀ,ÌA+­ódmd‹dwa îÁ2\ u•¬llßëb?x‚\¤Õ‡¬ƒÌ—Ìü!.¹÷)t¹w tC\qï胫p ú«á€ΠbH1¬Q\WŒ*ÆãŠЛРŤbê}sÉ>ý¾^n“¥þLÌèT¶ÏÁ÷M'·öN;:y¼øÏ&Óm_x_ð7íA !Ba‘.wa îA á°LqVá>DÒp¢! ÖhØ÷ØžàÞÀFû|`ž(þksÅîûЗýн¿#ÚȺžÈ¶ˆóÐõà÷é±—ïÚÎn›}ö€D A0„…0=÷ñ@ÜÇqÄ}<÷Ù#hM!K…CµÏú˜dŸ½ëeI]Ôºq‘ÄÀþM¦÷ÿÍ"–b†x8â^#…DH‚d÷Ê Ò 2àdB‡lÈ\ȃ|(€B(‚b8'¡NA)”A9T@%œÖQœUT)ª5ŠZE✢^Ñ 8ÿYßø¹ÆCì5v¥ù3ho…¶Ì€û)7æ13Ìá0½†é5loÿ@\„¸˜šGxh±ß-ÿ«…7̨ý.,Á=àá\FíËW`îÃìÛ)öƒ'x7øÀð?ð‡„ †ƒ¡üO#mß2z>0ãv~ÞÍýwCïæ†×µ¬fÂÞ¯½3ð’ÁÌM6cÊ>üˆÿ3i¿õ¼PÝ´}q‹¸þ…1‡ôWŹ]âÅ›À߆› ™ÔàS$·”L“T=-n«4CiVÉÉ%ó$ JIî*Y"©d‰{*å>¯d™ªX…û°û>aÛÅþG}g™¸'õ^šõå_53vŸ…ž‹gø¹À ¿3ö°×„ŽÓm¾3ötñ?ð‡„ ® ?4³ö¶­¢ Ê·š9»ÿ bŠìÖV½«…~¨W}ÅÈ¿˜û¡…ß?™yvê†ÈÍ¢ûy.úC³d…88 ñpø!7§Ð’=âQH„$H†H…4H‡ 8™Ç!r ò ß=mQ¦Z¨(R+NhÏüÐ,3‹{ÌbÙ~Šb)”A9T@%œ†3pª øS™šͯ:6™ûŒ¶Êh÷íЗ¡zà ôB\…kÐpîCQƒ‡`´® ê¤ñC³¡ùC³ß¡ÝìåÐg}Û‡ÆÇ¡ï·£ýCó­‹tº¤mìúÐø;º¡®@/ôÁU¸ý0ƒ0Ã0×AWjÇQH„¥a ÆA›ïçÐæû;Òh½AÝM˜€ÉÕªsÑß1EñLÃm˜Y˜ƒ;0 °wa îÁ2¬À*܇5Ø÷{±<Á ¼Á€/ø?@àïÅ÷ŸõxªÏ`ÅAEˆ"T¦WD()"QŠhEŒ"V§8ü{³>þ÷&БGoý»…6;À1°Û¬OT§äß›`G ¤B¤CƒLuË"9ÙºŒ³›ƒØÍÁŽ\êò   Š NÀI(SP ePP §á œ…*¨†¨…:8õÐç¡ø®5iîÍŠE«¢MqAÑ®¸¨èP\ú½®!×~eBåÏŠ¸û‚9èèRãeíÄîß›pÇè…>¸ × `†´Ð°bDq]1ªSŒ+nÐá&LÀ$h/†³ÃØ‹áŽ)ênÁ4܆˜…9¸ó°‹p–à,à ¬Â}Xƒ}‰ýà ^à >p|Áü!Üÿ¨è#ŽŠ`ÅAEˆ"T¦WD()"Q˜Ì!Gœ’ÙHÇ% ÔýÈD9! ’!R! Ò!ŽA&dÁqȆÈ…<˜~K¬Á¾OÄ~ðüD­CtöúĬ÷þÄTò¦SɆUp1ùÁøs†ÒÇM² ˜„)¸¾ŸÐüá6uÓ Mz"àSå~ ˆ#˜¬ã—zäÒêB>15ÜkµÛEÅðOLµ#r£ˆ5ŒSçˆøD]gêþüÓOôh¦ˆVÄЯ2ˆU!Nq˜Šx8¢RÉQHT)I‘¬HùÄÔ;®¾'.¼h¾–¦š űOŒ#SÓ;þ‰irä@.äA>@!A1œ€“ ëmçtçtotMŽ$H†HíFÎF6²‰“½ÉQ§ Ê * NÃ8 UPí^/ÔBœƒzh€óÐMÐ -Ð mpÚá"tÀ%è„.¸ ÝÐW ú´ß®*®)úŠAÅbX1¢¸®ýÄ<9¦}{ãÓÊ=ª•{T«#ô5º©µ:¢È¢A;©…ýÓê˜`‰I˜‚[0 ·afA'K›ãÎ'¦Ý±‹p–àG~“’e%+Ô¬*¹O²¦dߧƲ_á©ðúT•ÞàÀüÀ ‚ øSsÃrä?L÷ÃGȧ" Â! 7‰¾ÄЋâÖ©ˆ¢­b“Yý©étÄB†xÐŽ¸ÄÙÒé8B1ŽB"$A2¤@*¤A:dÀ1È„,8Ù¹ùP…PÅpÂ=5þeM¸DqJQú©¹Ì{}ŧæ bWx»â¸ ‰÷0ñ+ŽÓt9g¡ 4ÞV_0}Ž5Ø÷?"‚à „@„Ã!ˆ„XàÇÖŽ8²Ã Pó©H$K‚d¨¥.•¬ŽìÔC!uGþT‘5Pw‚, Jà”BT@%”Ãi¨‚j8gáÔ»'äžÁÿËyF×v;?5×e¯êþSsÕ±²C¬îÐÛÆ§f€‹ð€£ì‚örû§fÈÑ¡äÒ§f÷šAùyjä¹oÐÑICÌSl‚f¸º8®=k¾ÙOrJ¡y‡hîOEÖp…¤úTºJ²ï–þÔ ³æa«‡Yý0«vø¼"j­ŸÎ0Hç&Z›i8üŠ¢Nɲ jF×aT«#ñYÜØ(&à&¾l®ó3‹_|ÝŒ;J·‰P²0Ðù5Îù5Î0Æù5î§áÞAv"! ¢áƧâ&L@,uqpâ3|êSãqëSóäô§f‚§ƒ ž&3šî,UsJîÌ+Y YTr—dIÉ=’eXùÔ¬_ýÔL9Ö`ßgb?x‚×gÆâM¢‡Š)…¦¸mLqÛ˜b³&Ù¬I®~Sܦ>t>¾àþÁpB  Ü=A«>¤ˆTD)¢?3_‹ÑgœâðgfCügfš€®OøÌÌ0—ÛÌeÆ‘H1 ’!R! Ò!ŽA&ð«®³>3s\ìç¸ØÏqƒœã…dŽŸÌqdçxΞãÚ?ç('«€6ºhݳì‚9G6£ä@.äA>@!A1œ€“P§ 4Ÿ'Ë>3óÖyG…¶·’Òi%gHt çgUª¢4÷‚¨V©†R­’:’sJê?3ëú6+mT4)š?3‹lç"Û¹èh¡¨Ç›E6bXt´R× .B\‚Nè‚ËÐ =pzCاõ_ýÌ,q©Xb wÝ/_5ËìÇeª—©^v |&a†aDK_ÿ̬2ÝU¦»Ê=x•{ðª#4È*7âUnÄ«Œ´Â&¬:ÆXlnÀM˜€I˜‚[0 þÛŸ™5Ö³ÆzÖØ#k wŸáÖ³´ÎÁ˜þ*ú?Í~§n—ûº]Zµ{ï~f¼œa/ =²y9CÉôÜæãl{I\„ÐØÞÎ@à÷E8³ÿS,&V@cÿªî»Æ×© ôuj/ù:SÉ´”¯óþgb öýQìÏ?šõ^4þôðc\§Åàën€@‚`8!àþ{œ4–pE„âÐ͆È?šçêC¢åyÑ mЗ¡®ò±ÑwˆR,ÙÚŠŠƒGÝaˆ‡#0EÃ4LÂ,ÌA‚6êèM˜SÇ%ÌY :.alc¨SÇ%Ì™Dk2¤@*h"œÿeÂ'w(þ@Yë³¢ŽB:dÿ¶³Šne‘¾]Uü‘çå×M¤³®@ÆÅ1íŒLE–â¸"[‘£ÈUäÑ!úè_@VEP 'à$”À)(…2¸ÊbådÚ¸CÀHgÅ~`*©&;MvF)ž%«‚ŠÕdsd5dµPç Æh‡Ð@ÝÙ$LÁ-˜†ó´6B4C ´B\€v¸p :¡ 8·.kwu+zW½Š>ÅUÅ5E¿b@1¨R +Ft^ÿ£‰rrµû£‰qÞ€›0“0·`nà ÌÂÜÝÉbœW t¥qêžã< ‰É©À‹90Ñœz1Î4êæoá.,Á=X†X…û°û>ûÁ¼À|àø‚øCBÃAPsúß"œ,A$DA4Ä@,ÄÁaˆ‡#G!ÑÝh~®×EŠ"U‘¦HWd(Ž)2YŠãŠìÏM—º8.uq\êâØq±ì¸X.uqÎÑÿ¹ôË.¾ùŸ›ÃÎÝB»ö[…Ÿ›‹?7GO‰²SP m;L‚SOw |‰1o줭ìsWÅçß2‰”š,•Ÿ›$gö âÔ &٩Ǽç™ÏMš3ÂCTi¦ÕŠE­âœÖXÿ¹Yþs“ÉÕ6ÓÙô¹ÙЬ–6ŵ´n²Ÿ›÷ ;Usùs“ïì-ï¼¢Ž½ªîûÜ:¯A? À Á0ŒÀuàÇKœ‰…œ‰…œ‰…œ‰…œ‰…œ‰…œ‰…œ‰…œ‰…ìËBN½vh“)tŽ2Ԍà ¸ 0 Sp ¦á6ÌÀ,ÌÁ˜‡X„»°÷`V`îC®‡X#Û÷…ØžàÞàÀüÀÜÿèò c T)‚!ŠPEئØgŸupê¡ÎC ¢_+Y\€Hê¢ b ö ã§8¬ˆWT¾Å/Òçmá¥ì#Zw}ýh+xÛ9 iÛǘ7ß3E¿5üú çQõLT$i d–HÔ/´DäF±± 7bg z÷)r¦Ó/ƒbò³ÊŽ‘¥Ó™³à8dÓ9rµž<­/ŸBBà 8ÉB%d§ÈJ¡ Ø”r² ¨¤Ëi8ãÞÉPÕPµPGçsP p¡ šÿÅ’M>Aælý”8ÏK\Ќۿ0ÿ~ñ ×¥/þÔ”R[êLÚ$wŠ èüBt©çe’n%=Š+Š^E•Ù,q•ìôà BžÎ&½d{øóßC_˜§†aÿdžÑçuŨbŒxË<å»Õ<å÷²yj\åЛРŤöïÔæ¹[Šf‹)sNa¶ÝVÌ(fsÄn³íÎfû¼bA±¨¸«XRÜÓ\—+ŠUÅ}Åšbß^³ÇSQc3ßñÒ§·ÂGq`¯yÇWá§ðßk<(?cÞ T¤VT„¨>t¯¾ú WD()"QŠhEŒ"V§8¬eâõyD‘ 8ª˜Üdþì¸Ý¼“¨Ñqàó¿e/¿EÇåUG!ûzÁP$©pÉ–ìV7àK¶¥u|z½Î9µýç¨ë§8ÈŽ´éÀ_·é̬w¦j‘z§n­õÎtwšáö˜ÛÌÿר•g±Þãî•‹YF™e”E›¶ ÁéF›±jË¡O.äC¡ð±»Õ%ÄÇž º„øÛO¨Òß~Òm‰ ¶kÐ`» % µ_‚|Ð&XN1\©8ï,#­€Ó"ή I°³ëì¡nÙõi ’i×6‡ûYUæØÿ^T)Í£=Õ°º†²T3r­hd»ÝWºTØÏ©²‰Ê&÷1«§ãyhÕöfNØwÚJm´SÙáf·ñ¸¤¤Ù·‘|³W4‚nÓÍvݦ/²–‹Lé’]ß³.¶»‹É{t²|ÙÓg×CWŸ}fA‡}Ã̼…Ãléb­—¡z¡®Á ÁŒÂ8Ü„Iˆý…¾â$30ó¬A´:õ5låAµÍ¹¨r›ó®Û%·÷Ü.»]q»êö¾œ`šS0m_SyÚ¾o?îßoùs§åþê¶»¬Kä´}¼Üeo·>n¸õuëçÖ_zˆvÀÃ_à]àµ;ÕÒî r«ëM»S×K°»8ò²¹è<¨ô¢3Dz9¸²uý¥n­*ù;t$Ú»Ž0•¿wùÊøz:ÂU¦=ØqtÂ)†S §åÐ74ÊÁܸªyè¢æÁ5-ÞÁ• ’X"Éq 4ñTЇX ¢ b âÜuºÁ&‰w׫t„$ŽB¢Hg Y͸٬&ÛÁóZ’Z-É¢Õšâ6ÕmšÌ§k>“)$+dk,éj(¡XB±Ã™þª8Æ ìóJVaiÖÓZ¦JMôkwd±wÙnsÝæ¹Íw[è¶Èm±ÛnOº-q{Êm©Û2ÖU.:n+Ýžv{†Æ³P µpN\a&CLnÆ)^rêÄš"›roY¡ZÅ»h‘=°ÄbËd>N-áëä²p~átA7\>¸0#0 ãpSDðdÐH§¦CCGÖéädëtr¢u:9Ñ,“0·à6ÌÀÌ‹£ Ùåþê/R·$.;—Ý®P±* ¾;×T.vîÿµ€}žî²[O·«›ûF·{T/ÕY¼ÁG<~ÀÓ²îÛ.?OË·×}‡ïËÃë6½Î¤OÄäÇf„GZÂY ÿÆõПK$yò÷]ßyØ•àiyØåõáÃÆ’èiq]øÉî¥Gv?¯Š¨?u­n~ص¬8ñô#Æ#G‹™\1â¼¢a ”]wf|gÝ£èQ×ÄæG5ΣZôQW’§åQW2¤@„m}Ô5´E})$~ïQ×1’Lw»JY$©éPûýG]Á®G]O?êêR\~úQ­»Bóü÷G]çŸ}Ôå§1½>ŠŠÐ­thÔÄzz4p=´ÎõÐcëþÜXü¾«'(]Q.³ Ýl~Fi{ú‘u›ÛÎC[Ç•Cªœyúq×-ÅÔÓ›gÖVõ;À%ê€Ön³ºÆ6ýÈÕ±ùG®››~d¬Õò_5ߥKºÎ‘0’A»¾™QÆu{ó]3›¬ïB Õ±ÂÚ¿ÙD›ô‡E˜.¯¼§é…mÝaÚãEŒ9üŒy,Q™G’ˆ5áîL9ƒ>ÇDœñyfÝ]Y,?6ÖljsÄa“OÚÇ5ù$Ù)ñg¥de"ÐRAZ U8¯«Ý Õh»N<ócWïf«‰7ºOþ­ùE‹ZRMÑÓ_ŸzÆ¥ ãß~ý–.Omª|ü‹·‹xsÑm‡Ûί‰K´]†ÄMæñn’¸âž–V3þ•Ÿ¸:þ;W೚_Ü<À­d’¶)˜ifæ€eÝ“æ˜yÓ·éIÄZ,é“']a›ŸÔ%üäVQ¢O¤.gø„î4¾l‰Ÿ¯eÝß«ÏßëžâË=Å×âêù‘šC(…B˜°FòeÅMÏjßFºSþ§(Z¢!F<K‡!Ž@…DHTHƒtÈ€c©iÔ=«iŒê{—£9þƒÉ5u[´â5ç™:ŠéxÂ]œàöËïG.QñoOÑpR#<ôÿ¹®h@K5çUsç¿Ô~8³Õ5öí¿3ßõ|nÝ?š"Óñ ñœö9Ýæ´ƒ&?þGÛ*˜^·IŠoR_wÅ„:vF·½3ç¾Ü ¨©ØŒ2ÊL?àšôµü£ÎèÆ§]ûžû©ºÜVý¢sN~÷]æ5©ŒM?sÛô3]rTHW!K…^§—ŸÅuô¹Ÿºn<÷s×MEꦟ«ëϵ¯üt¡,Ýc¬Ç•xt?fÊLŽ7ëSäRä:?¶¡ÅÝpZu=¯@/ôÁU­"æý_¸>ü'3ÿ¬5âî~Vݯ+³Þu ¶h«¾`«›Å²®³^þ|¯ýõ½~\)ŸoV¼¿eÝ¿¸ª¶üÄ•àÒûùõD·dHƒ ñ—UcîúÖýoSgÂÿTå‡GuùP…PÅpN 8E±Êà4œ³Pç¡YX[Å9“¤º@ÝÍÍÆ£‡ä ô2\Ù(¾l<ÆHÊõXv›ä.,Á=X†XÕæ_Þò¯zp °˜zSî‰|cëMÐvóuï®éjÜú¯¦Á¨Ô`ŠŸwu¨h V鼩ý¾v‰(Ê¥žxÐÝâvh«Pw9Ìm¸Ûˆ®L‡XK$DX\…Ö[÷ÿ»f·þDY›\w·Ú5Cÿû=JÔ#ì7?Y÷K~éêÿ3+,ëþ]=5ãj¨Õ~:C÷³< i’·šäœ³ŽÖª­*¦xˆX²¡-®„çŸX÷Œøz ù{qƒ¾ø\L[4„G«V;±yƒËB]¢k£èÜèšØ¸A'ú½lÐÈ= mÐûÀ½l0ÝÆï9בonp%?ÿ+×Ü–ÿ³îÿ¸Î);÷ÒêÁ܆a nÀM˜„)­lö+O¸æ5«ÿrÍXþËÌ;/éÛùÀ"ÍwaI}·ý—yl%€ 窊µ_{pÝë´äkÜ÷…ëÞó*ùò,™±ÑUôµ]ñ?ù‰+}ÛO\íÛlºÒZ\*<ä¡§Á@ž ù6Å’¥r¤»M ´¬ûµN`êO@)4@#4i˜‡žZ÷4ë¤|Æ`\-•ÖsÍmÛè øÆFWÜ ]ñŠE©Êé/èxW=Ç̾ošfK¤^L–X𞻎_¹LqÅ]¬xX¬R^ƒ}AÜ×Á3ˆfoR8¾0Ãå`eÝ&M.ÎÝí°üQp(˜Ó,Rþ"ŠÆØ`ž6‹8wÚ£Å4îÎÛtsÞ¦µ'©Á#Uuu/þÄuåÅŸh€|÷0n 5þ º=èÀü¶.0zxñ\½¸î%Õ¾¤¯´Ízî%u=«¾YËzëT×ÿìËzTRðõ[÷[×CüŸã´MÃmñÀ Ù,ÌÁ˜‡-5ø·_ÑIGiîÃì;ÈIž-ëøïÃZ\õ/ñ?-S RóK;\1ßyÕuç¥Mðz~zG¦×”ó€ü@‡[ÝdƒÐ’kô?_]÷ºë¡7\>–'tAÙéÒkûN]svêR²ÓuSøòNWâwvj‡jtï—å zYßÑ]ëÞÔÓA‚.kÇ´æG2Y}‡láQ þó?Ó¬è oGÅnOÐ|Jà”ˆy€¡re~Ö *OÃðyXçÉYhÞìŠxB7À~Y}N;á-ó½%íìóth„&wWhVhƒ С.A'tÁe膸½ÐWáôà  ÃÔkÖ-ŠëšÞn×êË?u­½üw®«[žX·ÇübF“¿}вçk•?Û£k?¾GçÏâgú6ÏäQ'öY] WþÞüÛ¯¸z{Ý;º‚†XÌÿ¥ë;àê8¯|ç»Ãå2Ìh„Ðp1\dGN¢(û6Ùxó¼Éf½v^ìXnqzâ’ØŽíÍFŽcÇÉÚûF!$º(¢‰*D !„zõ†*ª¨¢ŠPGBõÿù披MóãÎÿœóÕùfæ›z¿œš…5LP‚¹ÞeOz–Ðʾ¦k…¿þOZã?¦ãHîëÚÑ_ÇÑt¡•€*ŠÙüâhJʶç¨ója®4iÒµ$úŸLÿk_œèÉs7Â5\ÓÈ4þÓé?íµ‰ZÉY?ŸHÓ D,´Rl bÞÀ§ß`i,ξ‰4µ\Eî5Y‚|kI[ËZi¬uRèðuˆ_Ø(yC«~~¢–ÿúD:ŒM¤ÃØD­küDm0j¢6핉4H'jû&L¤±9Qëø×P­í(O?N>Â@ÿˆt ô~>èÇl²_ž Ðé uÑ`Át›]ã æ¿îû#‰§iœ˜¦×=ãʳ1§ÎÚÊÇ?Öξñ'­.úOžËjÌ €¹€FÀ<Š:øÄ'ZæËŸÐþ‘þ_ùD›Az!ý—Ð2Ù*HîýÉ'Ú¥—>Ñî½ñ í4 éBÀâlÌú§¼©¥¿ÿ‰fSp ÉKoÄÑ.ñSmÅŸj^øT«óSÚ)~ª5\ÿËOµ)ÞPÏ—7RÉ×_ü3 ül¬æ?ûþ¬Í}“6¸}”£«› d?Á‚5oú>£=¦ýGÈ`ô Ø£\ìÀ«Ú$9N9´üK¨váÍ(-ü/¾¿bîñW-ü¿h€à‹€~À%ÀåláûœFíU"7‚o0Þf¼Ãx—q€ñ>ãÂ;;± áÉPSÓr„V:ásÚÉ‚efry€™œ¢j «4SµYàeËC*(‹Êñ9õêvë¯ZFìç´F>×Ú‡…j­oÅù¾ÐÂÿÛóÍ%ýÍ¥¼gx¨ÖóV”ïÿjá¶ÐG=«]|‹Z?IhƒoÑDµY¯¬§àÎÑaZ8¦_]°ìÎ>\Û“ƒ#J‡w“¶!$ó‚4ÀšKAh%žG%å½M»ÍdᣃH÷w¿­…ó9ðqŠxþe6çÖ§ˆ…ô!ÑE@?`2ý4ƒö¿ïÑÉÅηS…s£ ²„ó”þ%€¥€e€ý€€C65˜f[oÓ¤¬ Ns(:æNÐ}t¸¡Í†fû/"ëLhgŸÖý&ŠŽ¸¹B[ü›'µ­‰ØHwÒ„mSœgüô\áÙ’ž‹«¤€l‚]!k~ãÙRLê|cüoÒþ¾"‡‚JÂ=!Sßô|}.Rîä“2¼q ö°ùØ«Þc¼Oó€`©gR ®¤ìR&Ó(x©^$(z½W.“ °ï™R€= A¹g*ÔTÀ4NÕðºÇHÍ`š‚Êdr¢lXsØ:j.Á?çQ!OPþZ .TÁQR€Ã ~¶œ´˜ª\Cx?¤¶g @QhÌ4ó 5š x¶Ž<‘Zà©Áa®M¤³Ÿ§—mÛã¡ZÅ{ºo7?7âv*p#ëᵨ!)•ÑsPM‚k?"ØÄÞê÷žõÕa]Õal´¼W*|õBk}/ÎóøÜѾÊa.¶URÚ_'X(ЀY!¸÷E¢ûÝ€Î'PAâNüˆ Ú@ àßèÓ«©`˃*“ac5c-cÅãu¬Ö3–ÁÐÀêlÆÆ9ŒÙÈoÍ{ÏjǾ2^ËÖµÛï×î½7žÚ8álÿ™6õwoiáTõ›Â7Ö€´ä™b®mLe5ƒ1“1‹1è´‡º÷ò<ìpÑn+¦û³yt\:Îþ\Ï…™Â×D;ÃqºvâwͼyÎçÍs>¦ˆ¾¸ ¸ÜÜ$}L Ç·ÁTì´ïÁv`bÇ=©Všziá „rž\ˆœ£S 1~Ói€t‚,­†dÑ™àY€ŠLÏÐlh&h ÇÑÄǪB#RÞ¤’fqyÕ£h?U† òBì²* Vâ¸WÅU©†¡°¹ÌÔâØÕ[ Á7A[ h'ˆXÂÁ´Wß4*Ô×ÂûºìëZ„o¡ðüÓ\:³[‰U€Õ×öþH_+o ­§kÞïqm,Ä|uý?EÿÓ1£Í!¸ñ#‚VÐE¯kkŸûØ3YÛü>A­—`?%š¬m/¤CÇaÊ~Ýû¥´¥¼¿çFÓ0Ëh£^%ðŒ¸‚\%qÚ Àà ~w­PøÚ Óˆ8ò~ž)"H.Â¥´´×Òß#˜Â<98…?Æ0µû<#î|‡VY6ò6lä{҆خÐHK2¾«…/¾vÚ>ãh6óͧ–mÅt²<“އKq¥ó±ºWn.eiõŒÕŒ¸Gô|Ó{J<¨Ó< ßûõJ÷´é,(ÂLw±K=g¼O°„Õv®È.d]†ç¾ª¦Ä±‹Š°ãlC®8ù[\$–á B5^&´Õñ¡ÚÙBµs)¸3Þ¨åZ´Ö9ù¹_i}ÔÄå4u\ÿË´3õ”½ª]þ`%?ï[ÅÓ6Â"•ê·•j¾ZøÖÐ8ߎ‚vv“uO‘X#´ŒE¡c{‘ˆYKû©?|’vlB›;¡3‘áëÀT…`òÇ­?!¸ö"´ÇÓž·ñ‚9‘žo@4éöuâBõi¬ù³GÔö`Ï·Îö.ñ¸íĸåÈ~².Ñ^&¸Âju£ëj&#µ¯h‹?\‡†Ì7 –iƒPoî\RïC}°‹…o=Böþž ©*~tå‡Wz1Ža€L@M™:Ÿ,ÅlöæÐ^‚SI‚ðü‚ðô¿ çHPI *^ÚŒ‰~Î>ª¨¬Í8ØZ­?%¨Œ&À&u#xN1°–±ÂKPãÓz¿»YhùÉ‚pMÁûÿc¼¶+жºÍÈ~ `+•q“Ì®µÒßo¡]}ôáÛJÕØ&|Ûyß@¸ë÷¡¾¸*Ë@‡xgHS»«!ÉŒ½¸ç2¥Dh=¿WµîßwÑÊœñ=éÛÉ#e'†T„ï¾ÝXá{„o/ÚZ‚5IðümÚãîÐÖQÜÌÿüX;ôûèø? Ä~¬¥ùžÔ»…o?Zÿð¬VâãQ{@h¹ï;ˆ#'Aø!ÚLq(!èaµ÷»¹ûÌPmÅæZF­n•©Ì²‰Ô3P›VÒì‰oѾ¡#j*á󩥨¶w‡yB¦aV:¶4Š ?‚óR®Nì!v³bçÀ5oö`]"Q ºíï¾\Y%hý)êà«4PÀ¦Ÿ‘íy\#ÉüŒBfL„sR€·ÞèÁlãv‰ ém0,´–°ÿm{?öôhxJAðÍþR\—¸IÐÁê͉4á8)<ǵ¾_PGžÄ¸ J”×µ;ŸÔîM õ¢µ0‘¢zÑÓË’D/nªõò¡µ—æù(»á=¥<óéÅT§—·– `ΡÓ8ö(Úy pp‚R•|æYñ‘~ZøÎPÿ½Fpp±TœÁ9Ç\ìÿAÅG´]CÚ뀔AíGoùÎânBîÂzpðŒÓ†6œ7/æçm@Óé|âÆ×C=1Ç_ö\ÐÊ^ñˆB2÷i/{ž/&_ëXÝw; ‚ôס}APa×6ÿq¼ïá#yàQÔw©/]¡Úƒ_×Âû…ïj†JµSÁ=†ï2çxã³sæu—q«N‚®`öCk@ËþøYíøã¡¾«Øe”% ™×Ú>O;´ /kSßô;\ÛAÖ]ÓäæÊè£ ÷QŒ¸MJéŸÆ{’Bí2ỆuJ°6EÞü+Á´—®a¿™\FýO*†ô<û¬ï:·þºð¤†f–aÿÈ&˜:£ Ö\òù€@  0 P(Tä¹+¡Îfµj`. 0`zh3ãü2<ùÚþ:….€o! •“.âJ´SÃoßLËà]¨&È]I˜º†µœ¦j'`W¾ås‚½x‹¶ On„¶ °°°µ wÔ.ýÈ#¶n§2o|7TÛóÜxßMŒ››Xý71e%¸˜ Zý´ ôÿýOɹ‰çù£ÂoÑ®÷“géj§PƒÈ‹`ñ7BÉtì¶ð‘\óP­ï×Oúîð€¹ƒÓ[ÆsZ¥wy5ÝÅàØû÷h88 XýA´~@úW¡¥½F0m Bn@˦ÉOø}á{@›Á÷hÿðoDm—o’‹†äŸhßø¶/É…j$¹<ÿ²£µèfÜÏx \hy¯SÄò?×ü™öò$¯þy²K OviܼWŸâÒ’?O;šÍ¢ ðHXÝË>"âe2â*å‘õ]: j)¿ÔµÌÇt­æ³'='Cê?ó<~æ3-|*å—êòŒ\\í °°”`äJh««€.~r¢³¸Žq=ãÆŒ›7Wß44v Ó­ŒÛ·3î`ìbÜYA+qºË—FUïF9û‡È?ó/ãµÁ°'}é..›ÿ¦m#ÛÞïÐ.äbvœ.íND(íB2]´ .ÎÒ~Epò/Ïj™¿ý±öC»G) ÿú¤Vö×ñžÇ—þÕ—Åë"‹Ê€“*ñ@" ¹R «³]Ú‘¿Ž÷åpá0šÖΠÎËuùò\Z[D=7Þ3ˆ+Üù“ï"†k܃|{׸q[[ÿcínØ“tŽRŽ*••ÂWàÂ$Ìÿ¯(­óGqÚÊÑ_×Îü×xíâSãµùŸ×Z>ÿXký\Õ Ÿ õÍti«>/¤âIkz²~öWžu¡Ë(¯õ¡+*Åp:ñò¹´ ¾‰’ný ¦ÑC›nŽÀý<ÐÄ'r·üåäðå£.û•{Õ9ÂONqzÙgœfrF’³LÎIržÉIú˜\”¤ŸÉ%&â2u½©ëW\¶Ëå2týª³ĵ€º‰ëD¾r“À¼…Äæ Ë¾M5»¢ß•ä“ûL¬ –­2™¤‚$I2™I²$S˜¤01§ª”*,æ4i™Î$M’t&2a&'Ìbbd«|œ‘a3K.,Qy°8{ð|Õ¿¿íò/¼/P±ç:<Îä\†æN…ª]D9«þéS þŤè†]Êe„†bªBѳԀ\HÊQ?W…Êù’2¦Û†Šw)£Ç/QåŒÊE¯¥ª½L]¦Ê©Ö×W¨4ÿa5è•7˵ªÝ¡v¨Bü¯õÐhw·Aµ7ÿÇ-àŠ¾ÕÉ[lCªí(>z‡ZV—jïTÅ7¾±[µ÷¨.RöÊÜeý[ݼ÷s>¾ ¾ƒL¬Cì9ÌÄ8Âk¸GwD?&Éq&'dØI;ÅÄÛ â=-=gØsVzαç<óÆKq‘cúÙüK ߸,S_aÏUI®1¹.‹¿ÁÅHr“É-™ï ò½ÍcöŽ´Ü…åJºÏY<ùÙA “‚8&)ˆ¶õɰèÉÒ2ÄL‘d*“T&Æ4N8]zÒ(¡™N`eÀle²ù³@þ1›‰žÃùÎ`âÍñæ1±ò‘°0“SÊEœ XWÂÅ•J2‹I™ +ç° &®JW•ôT³g¶,¤ùÏaK-,ÂgÖÙõA.š%5ÙsƒæÑa©Lóšš ‘lfùMsAݾ¹n¶a8šæ"Nú Ól Ju¹T—º‡*m1JC€Þă¯CÅp‰$4:Ms©“BzE¼¾,È^$ ïŠ Ú8¨£Vr…w¤KxÕ25m%Ô,±Ðè¬ â-g½Œ ¦Öè¦in-ò/2ÿ™ÍÍÚ©MÂÚÂåè4µ–ºQ݈ o·TDo—µ‰ÞÁ=Ë{ªìbÛ·ÔÝAöž wöÑ–,ÄSÝ2XÝÏYþóSO ² ‚ ‚\ßþ¶~8ÈnWÛîÇ”ÿÝCÕWŽò 8dÂÆ©<}Š×\¯4zOKiqäY²ÎQrõ<"Õ lÑû8ÙE&î~r?} p™À¸¸Šaq ãþ:ßàÄoÜDÀ-kƒ²€Û\µ;’ÜEÒ{€û€Û€InŒN=™‰‘ bLa¢§€èS¥'•=Ó˜¨ÓAÔ4éIgO†$™nªM[²ÙbåÅšÈäqÙùÒWÀd¦$…pŠ \%ð¹JÙgÎ1Ëdéå\z…LUÉYTIRÍd¶¬J ×b“©§,ÕN8—-ßiùN³L8ŸÜúno [Ü AÜ­2«EœUo ‹ÝrS8„En6pbÁ€\âÆ€\ê^Jé–¡EË+Ü4â c¥GS„*bÙ¿»Æ-!2¨R¥¹N§[΢Ö9ñôz·r¸jb£§6ߨŒJz·HóV˜·¶“ÙÐwpºÜ´Aì”Dïrän–Fü·ÝåVžÞ‹lžÞ';©Û­¨ÿJÇín»ÔEÑ'ÔïqÛ=n—ú=÷Q(=náV¹±GøžyÜmŸp+î“T¾y #¢—;ð´\gÜ'çÿvÞm_pSK…­HT”>7M3\áPD?E»/.£9Wdg]…“ÜÏ\'ã37€›€[€AÀmÀÀ]‚¿Oð,®™DD8™àß“ ŸBðD Ás©ߟNðLÁÿÉd²9€È )òÜù.¦=33õN(I(b’X ’X"=¥ì™Åä‰2'Ê™,8çq&ù»€rœÉ¤„d‘#‹¥³„¥Žq$J*óØŸ~Jù—sþ¨Wxx-T"‚bH­’*­Îj™üÅGÎál¨æµ2Du(&º^ú£9בRNhrd³”/-px‹·Ðá­Ž\äØÛ¸-êbOÀ™e;úa AÐR”´Ìc/§ö®àö®d"VÉ6­[Žî\ük¥¿þ—c×9~ÕZï±7ÿ•M2î•Í2n 2°Uc·I9a»”¯vI½SÊ×v;r·—3Q÷Ô^馒i5ì÷Ø<(÷ƒ²&‡<ö~Ï~ >|Míá†õØÇxå‡rÌCëà„Ç>I¾Sìï…™äi–ºuÆc¿ ¨g‡rn÷9nªªŸ÷$]ð\ 0½Ïc_¤˜~úÿÑe÷&XÈҸ汯SnxxzÅD¿éá&¯ß¡Xõ.»ï±åG÷A~ô@ÆÚ!ˆÂ$‰Éd×UcJHªË0BCSBRÈ15„j˜ ˜FÌP§‡Øi!ŠšNÄ­f„P­ÅÝ™!6b³–¢ —˜RBÄOÔ¼;?„VE ÀI9—ú°# )‘Z„*¨Å!vIˆ¢—†àú  f£\š+¸š•L¼U Þjé™Íž&æ³VzêØSÏÄjá+È’42™'Ú¨0½™cçKË&-’,dÒ*É"&m’,fÒ.É&K%YÆd¹$+˜¬”d“Õ’¬a²V’& Ô„u,us}ˆ½!D5éœccH*õÒŒ,lØbKFGÍ!öÈ­RšÛ¾R;°öô. $5wúÓÎ 2tÝmì‚O.d0u÷î!ƒ Ã?'æÖ÷1Kwï{„uûÙÐjÞ.>8È­<b¦&aÒÃÄ{”Wê1IŽ39!ÃNrØ)Iz™œ–ä “³LÄ9•çCì ¤ôÑ@t«úE° ²Îý!ö¥,ÔÀŸºõ+~z nÝ}ÕÏU㧺ûšŸ 5â:é?@‰?»I£8„Ngx„2·1fïXwytÝc³uŸÉ™ÀÖø—7™I|2Hü&"Eã£÷T°ë ©Ðp1Mú§Kšô«¦é5Ò5;Câø2)+Ÿ™¥ÙÙšðEæ@º|‘¾PÈdÄåjö@ˆðùòdˆ/ß‘ŽœÉÒòj6ã-‚ˆ5‹5{¥pÇÒ™®e•h©Aòvš^)ü‹'ÖçÃÝ?«TKuëúßÈ H4KK 6Œÿ_˜øù/*4;]#¥R6ºŠM…Wˆ ßÏgsËbnÕ f+…bÌÑhMÕ¢'_­“‰ê)Q¬e5ÈìdOZì¸nçQÊçš(eì/çk4ïPŒd1Z y¥µjv…P¬EšBƒÜ2Ú4¦kX£C–È¥NȲÀ±\®³ˆ©º*o®DRs•f¯¦|Öp>k™èï¤g{ÖK²ÉF&Ê&-àÀ´™ˆµ…@ÝŠu›f3·s!;˜è]œïN&Æ.Îj·${˜ì•d“n&b?zö€lÂA˜¶Ðš‰>Ä·çH¯Öpwæ•#RôHqTŠcì‰@r’ȯN£Ì_Ñì^RÎj|zNKŹªÞ«õ¢Ìóì´. Òêcb\äªö3Q/qÃ/˰+”«~•|Mº¯³û“§@ž¾Éä׃ ¿¾-=w@ž¿+s¹Ç…Ý—ä;”ɤP¾.Éd&É’La’"ÉT&©LÜÓ@ÜÓ¥'=éLÔ 5“‰ž¢gKO{f0‰Ï‰Ï“aùVÀĘ bJRĤX–SÂå”J2‹I™$åL*$©dR%I5“Ù’Ô0™#I-“:Iê™4H2—I£$ó˜4É&4sæKÏö´H²I«$‹˜´I²˜I»$K˜,•d“å’¬`²R–³ŠËYÍäµ ot€ì”òÍõ.ñ¦± ™ }c¨½)4DŒÆæÐTð'‡_à¢"v‹L:lå:l“ÚÎd‡$]LvÊÚíâÚí–ž=ìÙ+É>&Ý’ìgr@’ƒLIr˜É¹Š{x•Ãâ‹ã2ìD(íN†â& —OËöëgäÐ9KýŸólBi“Sõ>§[bc/†Ú™¡J|?ò¸ŠSæËè(:U¾âÈ«JüµP%è-Ãkøn„¦éº+X× c T.*<7CSUéFœ¢UèŠ2ø°#Åm*KÜÜÜÜ<Ø,&’ŒÉ€dÐ)€ÀTwS©º-3œ¦Ó)1]ÇÞ8M'5}HÍR3‡Ô¬!5ÛQU:b9Ióf(8w(]Þš?¤æ6óæV`P¬"—u·^ŒvùGJ ül…ÓÚ·ËÑú· ‡•è¡*‚ß̆ç7F¿_æP¿¼mÔêv.|F=gØ ã$7l)ño›(Xü¶Y·çë(n”ùüÎBh$[¹RñµQ¼ÏX¬Ë“YZ×íl˜éÒß]†Lß]®ÛtâûÎ )V²ˆ^EÂαVë8Œù,+áí5zÒZ].ŠÒ~êDNÖ:Ýnq)Öz&$ÙÈd“$›™l‘d+“m’lg²C’.&;%ÙÅd·${˜ì•d“nªø~H^¸ÕT[fa‡a‡ýŒÆÆG·Œ©ñz>Êz‹ oC1Ìh^óöqÝÞ¥cyØWâû¦y‚ûŠŽ©zÀö”.½ºÝŒEIlƒ¶-×Î-·„ÉRI–1Y.É &+%YÅdµ$k˜¬•¤ƒI§$똬—d“’lb²™É˜- c¶2IØ’°]’Lº$ÙÉd—$»™ì‘d/“}’t3Ù/É&%9Ää0“¡ÛøG »‡øQÃÿ þehDçqBŽˆ“§àí•#â´DœAgŸEgŸCïž\€­+ù"h?àl—a»zp pŽp €ÞÜ Âq9ß½ ¸Û}Ø€âiÎq“I€É€d‚„)_K H…mlÓAÓéf@ˆ•“5Œ×T6“If0É•$I¾$LfJRȤH’b&%’”2™%I“rI*˜T2S2¦šIÂl„Iæ0©•¤ŽI½$ LæJÒÈdž$MLš%™Ïd$-L ŠÒŠ`‘ÇÙ6 Òþã?~¿d_€ 6K‡ÙË(pù0ÿ°Yƒ x@uå0{ºUÃìÕÔ5(1d-ˆZµNC×1 ]¢o`¢o161±6㣠±ellìtvv!ô•Ý\Œ¡îfïFg`œs·,û•ýŽ<àȃ2ßCœò°c<"å«=Îó2G‡ùŸ—Y=Ì¿ðó2džáŸ4(â8êqp’Ë=%óï†û]§‡áôvœ–´z®xžC§èçeŸ]à$C]ÙÇ©.ÂÔ?Œ/ü^f_vI®pý* CëòéÖu.æÆ0{€:á&÷è-&ê ˆz[zî°ç.Îï Ñr`\÷Ùõ.ÊÉ6¯O2ñäžÉÁ²ÅHf2…‰H11w4¹š©0 p#§IUѧ#XO“ÁéÎd"×,hÙœ[Ž ˜K. (Ì"ôÅ"“ë÷Z±#K¤|©TÊèYRN(sx¹”¯V8²Ò‘U&nš²ZýPžÍQkÌ€9ÀT¶–ëYgÚõ¦¢7 :slžÇfµ)0U3RÍ'p/ Ð[þ³Õ¤9Ï.2í6Êd1wM;.ƒ°Q] £ºŒ‰XŽV˜¼ë] Œ«ÑjxÖpÙkM¬AΣïXgÚëɽ!¯m”yoªžP&n1gÊ·r6ÛL{‹©˜Û)FÝÁ•èbËv‚üaÎrvCÙbŠ?˜{L{/5cû»a&¹_ÆýÁ8ÀuA(O=8ĬøøC¦ýç?Sg–‰¢pI{®9ºŽšö1RŽ£ON"ä”ì^8ÉýÌi2&œ!xâ,´s‰ç ž»@ðÑE‚gú ¾r ÞËÈ8á gœx$ñ“„ëì¹Áä‰'n2ùèÈGƒLž¹ òÌ&ÏÝyî“ßßùý&bGC& ç§Ü’†ãéW‚„d‚¯N!—˜ [*Aâ4hÓ¡¥AK‡–A06ÍøDÛ÷³ÉcæÀcÎn3rAŒY¸•È=aš¸$q “„µìé`òD'Èë˜|´ä£ LÆl³‰ÉŸ6ƒüi “±[¹Ï·1ùx;ÈÇ;˜<×òÜN&Ÿìùd7“O÷‚|ºoxàÜËðv·÷SeöÖAî­CÃíäAoõŽ¢WŽ¡eÇÑ'Ð 'AOaÌôb¸œœí,¼ç¾tžàÏ}p\ô.¡„q—¹„qW˜\e’xûéº$7˜ 0ùÒM/Ý’i9ÍmIî0¹Ëdì=îšûL¶è¯h;Ìž¦èIa|L’ä0EñM Õ†0E¥sÑ·§†Ù©aXÜÆgŸO ³ÓÃü Gdø#_fŽaŠ&>C09}ÙÈø.òbCv4ÿú¯ÿ*¯4̦Ê˧[-«!,•öÕBU”`™ð³¹ö˜Û‡n÷5úóÇ,>3È;ïÑP¹v›ÂæÍ“ùü¿›ù‚¿—yËßfŽ<þMž­¬Xü·(,5Áþ…6~˜°íïVfñß«Lû£¡â¿>[f/ã²B„,ˈ]þ·c-ˆ+²",5(° þ ¬|4¿°U·^«ë5ôTÀŒ’Ö†ÙaBy¡#ýŽlŠw=ëH÷z7†Ù›ÂHnf©{·„Ù[Ãï6$önçĺwŒ.Šê‚M;a–º+ÌÞMÃ(z\NúRÉøÕiã¦ÒÂ1Ë…-4[6l9 3¹€<8òá( (ÁQLðµÐRÀ,ØÊ`+­TªÕ€Ù©AÈÐZ@lõ°5€Î4|8Z9®™9n>“’´0Y(I+“E’´1Y,I;“%’,e²L’åLVH²’É*IV3Y.'µá<©•¤“É:IÖ3Ù ÉF&›$ÙÌd‹$[™l“d;“’t1Ùx‘Hì¢fO{õ½ðëûÂù£n²˜ûa1°E?ÈîCÒ}˜=G¤§‡=G™XÇÂùuHIN09)É)&½’œfrFæv–s;'Éy&dÖ}œõEééG.±û²t_a÷U龯žë BDÝz3j üÿófÔÍðGÞŒºðf”"‘á ·9Cå…;á6ŽÈwÃí{áŠû>ùtïƒp›öÝÂ;i$Çx“FÚ0OIfÅ<d %LI qÈXˆ’:RQ&N£H1qúH;m¤¢§ 8‹È€Ç•9Òʘ,rèÙ0è903 ¹Ð£ò GåÄw‹dQ—Y4ï‘´KF 3²t¤=k¤ˆŒ,Ç»£åPJ`ªàH³’#¼7ZÌðÖèl©˜f EÌÉ…j¥YW뤹žªi4ŒÄõÔiŠ˜Çµ™"š¸Í0Ž™]]ØÔ")¢î±~½»ºh'·º$0ÁRö.i/‰˜¥4V:|¤òÇÕúã&æZäÑ‹ÚÉcwáz&ß߀šodË&™`3ˆ¹EÆneÏ6I¶3Ù!I“Lô]\­Ý²®=Nµö:ÕÚçðn–о¤|Cà8GälÄ!ôàaÎøˆ“¦GJë¨#q¤uAÖ &¿> òëSL~Õ ò«Ó²’gÐø³ÜøslQÏ3¹ I“‹’ô3¹$Ée&W$¹Êäš$×™ÜàêXÆÀHœ#m‡zsH½5¤©·‡Ô;ŽÊgiw‚… ÷ |(݃!Õ¶ª“•ÏÚ’˜ _—KÃäƒòv²Å÷„§XÜõŠ‘b)Êo¦Z|;8U‡}˜fýÏGd6C‹¢O·øZ¨Å+0rsgX.Ed²9Ë’k1/|çXÎ*wÏàSE§Š|¦Çy%ïPδìB ‹òç" wß%€R‹oGÀ¯Œ+cRÎ$UT‚¥Š*¦oëº^m¥ºf[¢Æ|OtyÕZ«u–]o)zƒ…W” ôF®ÿ<6{›@¼Í2f>{01[@Ì…ÒÓÊžE’´1YÌÄh·ø¡0éYÊžeÒ³œ=+$YÉdˆ˜&ô5–½×?Õ×Zv‡5ôJq'éÊ:Tr=wWn£eo"e3ýëêËÞÊ9l³ì4:éÓ·[ö6t9†0СРطì&bí±ø®¶eﳫ›É~&ænêAé9ĞÒaÒ#ÉQ&Ç$9Îä„$'™œ’¤—ÉiIÎ09 €²ohÕ‰éœ.Î[¶‚§N¢A*?œÁ³¬Æˆ€·æá:/4EÈIQs®UÌÀDgA„­Ò<§%ÂÞLr!KÝÛ ³ð.â¼Üm¸Ä±˜“µS¾Þ%h¼×»ÔéÝ»Œã£—s ª¹"Â^1Tü*.~µSüšž“­°‘G„î팰×Q{¢×G<2ÑÚ€”®|³‰²|f3ÁØ-c¶¶$l'øê‚q]€°í"HÜ=€½°íƒ­Ú~¤8€àƒ€CÈô0²?‚ŸéáÇsL’ãLN0{dì)Iz™œf’)΂eŠsÜ×=Ï ¹a÷‘r‘Jr÷£ƒ..ç_aߨ«¨Ê5‚O®C»ÁyHßM&·˜|2òÉm&Yâ.X–¸Çôa©÷¹Ô|§Ãö*ÊG“¾’m²×Û“½ðe‹°l1ÕûÈÛù©^\ñòU¯æ x…0Ý‹ycà„^¼A˜éż/‹Bÿ”MC8ƒàÃ\w´|äøa"sDHŽ(ûS ÈŸJ¡?¬Ä,Jb–‘#Þ,÷Ú^aÅWzíA+>Þªò¦ U­ð’5>¾Þ€;¶³½¨œRa*s¼v-ÕPQê¼v½·žÕ©ªxvy®ÔÉa*J#‚k©ÌyÞ€ãKjçjöòhœ¢ M-hçB´³Ú"‚¯¶yñt  ¶%°-]XXÇJ8V®¬¬…£ƒàk ëëaÛÛFÐM€Í€-€­€mÙŽ ]€°í‚m7èÀ^¬‚}кўqû¹=ã09(É!&‡%9¤G’£LŽIrœÉ IN29%I/“ÓLÏ€$že’p$á¼$˜ôy·ý"Œz¿×¾äUŒËXWÖ‚¸ rÍ‹{ë4nxùkLn21oyùs Òs›=w˜èw9ó{LÄ}¯|"ñ3LgK;ÒySNŸÉ{U+)2Uˆ`¤™©ñ3ÿÉ‘ö”H¹às)’B:¤¦FÊÏ,+b>61C¤EÊ:¢ÒeUžé?¸2%«0IdG>r¦›C™)3ô\Äéy‘v~¤¢€¨3A„ˆ/d£^ÄÅLŒ’H¾·(É,&eLž*yª‚‰¨De«8a5,è˜ÙPò¹e5NËæDΉO©µ‘vÅÖGòóÓÜ[\¹2³FØsE³‡Mh†õ…ù‘òÀ° ˜–HFÚó#q Š”"ѽmL£?ÚíœÍ'›¥‘|>¿,Ò^I9­ˆ´—>,RU,Ë\™ªªÁjpß°Vq•WGÚ/(ÖÖ×B7; ›Ðm±.R ¸u¸>ÒÞIr£#79r3K]ßIó^—×ëÝio‹ÜFi·G¾:KDíâõ´3ÒÞ©˜»¹¬=LòÅ>°|ÑÍTßÏ«à“¡•¤‡xÝŽ´ y~ÐCúÂóÇc‘61ó8YÌ\ÂI¶ˆSˆïE§Q¯3•;‹ôç8ýyîfóªÛÇսȖô#é% ½Ë\¹+lþü*Èç×dªë\à &ê§¾ÉDÜBéƒÈâ6àùŒq/Ò¾O¦@<ã}¦˜ô+’9ù±GæÉ)Ê÷§<†7±S³Ãc*t#•õi¬O‡n¦=†Á=ƃƒ¡Hd‘¥Xd9€ä4ÌÜÇìô`a‹<©˜ùŽ,päLHÜÓ(„"Õ"©øbF±$~_ÉPXé:k(…×[6”B1ÊQ— ®K%슷Š,ÞêÇøÍlª5ds8¬Ö_å:ÕêëÓðh}æ:>’KU…DK8ýIÛ¼Gl˜¨6=†õ¤ÞìèŠo>:3C, Þ„l!‰€…€¤°µ:¾EŽlsäb'¶= v‰ã[êÈeŽ\îÈNš•iV9¾ÕŽoM€o­ãëÀÚÆ3:³ù† ºbÓ™GÓz4ɵá1{#)›¨‡Ý›ÑÍ[žÙJ0vÁ˜í€ ]‰;¡í‚¶Úh{¡íƒÖàý€°$øê!‚q‡G`ëí(è1ÀqØN íIy …÷¢bÏœæŠ92æ¬$瘜g2öÈØ>I.2ég’).=Æ3ÒËLî4¯n^}ŒO³¯?¦è7x`bÝ|Œw–dÉmIî0¹+É=&÷™ˆñ};Šø¤(¼Ú°s™…W¢øIµ(;%Ê%ž6¦FáznJ˜¡¤F¥ºBC\ѧ!4z:B5- §‘–ü29¿¬(;;жg&3$Ée’ÇÄÊÂÇ„3…HZÄÅ —ÀRÊ–Y2}“rI*È­W¢W±E­QgKRÃd“Q"¢ø5]6‰F$ŸÅW_›`ÊŽÂA½*l󥿔èµÀBNß*Ó/‚¥ °˜˜nµGÙKHYJß2–Š•ˆb–X-•2±V*¥¢C*ÑRNX'å«ëû)ËÅ&'`³#·8r«#·I9IlwRîðºÃN)+Än¿²Çñìuä>ÙcÝQ7XÕýQò«û™ÝÑ¢a‡¢ìÃQoªG~Ĥ'Ê>õè)ȱ(œ‚‡C'(Z=Ékå[*ŰJqVœCÖçaª}œ™˜p‘] ýäJ¼DðéeÔæ èÕ(~2M\â'Ó˜|:òéM&þ™YqÖ­({0j0Ê#â,&™Öí(ûVTàâ6-óg¦y'ʾå_TXîù-4EE+p+ìhJ¯˜“ð\3I’ÉL’™XS¢ù5=I¦2I•d“é’¤1I—dp™’d1É–$‡É ™&—Óä11ò£ù663šö#…zQ4O2Ù¬—0)á‹#ÑÜvL5Ù/Ê£ñboE´]-,³*šºJÕÑJÚï› »\„ÏWÃQ>ßH•º³ZÔG;}IÔ¨ ~*ÜÆÜh;#_슦Nâgóà#Ù$¥ÙìÈùŽ}¬PK´Â//Œvú^¥UhµFó:”l‘ŸÑ–-1Z¾ÏÓî·c÷·DÖ…6Íh~Éw™ÌPø~¾õÇK¾+¢í•Ñ+£å`YíŒêÕÑ{Ê5ÜÇk£íŽh¼8ëÈuÊl±ÞÙb“cÞÌfk §Ù*É6^cÛ™è;xmt11wòŠÝ%=»Ù³‡‰±—3Ø'I7“ý’À >ȱ‡d.‡9—#2—ö•±Ç8áqvÃã$RŸâ˜^™à4“3LÄY&ç@°'<Eª¤ªè}謋Ñxi¯?Ú¾„F_vE¦3Í«N°¸†üÔë²np? ÈborI·˜<5òÔmé¹Ãž»2Í=Ns_Öîж}xÈy’‹|1IÊ “¥ŒN–ò¥)>N‘‚à‘êx§9rº”sDºcÈpd&'«ÙHW+r˜ª3|Ã!.WžÏÎ'¥À‡Ÿ êD1a½(eœ…ÀzQÆ‘u¢´NT0}®ì¹*&þ©®Vûlþh¬:Ûg×ø°(ÊœÀÂkQTÒõ>u*Eƒ÷¤s™6ˆy  ¢‰iP3XÐ|&Q @¢Z˜¨ AÔV*x‘Ïþ-ܬóÅ’@m—ªsGx‰ÏGXcá;ÂK}˜AHƒòÑ2”ñÑrYàŠÀv¬ôátOÖ|µßQk k-¹ô¿¤Î– u܈õLŒ ÜøLÌM æfU˜†±Å‡)‹®ã‹äW¶Â¯lƒŸÎGí\;v;8Ÿ.ÎGìÄJØÅ™í–ÁººÇÇ6€ºWªÜAû¤N5ÖÕnŸ½ß‡§·øcMã Ïù‚yȇ/æa–Â:Âí4Œ.q$óW‰>¬}Lv„y\Vê*u•Š>%-½LN˰¹â¬_9'• 祌¾Àáj_`_”Ýï³UE¿ÄÝ{zÐîÝ«>œÎ×`×¹œ¤£Ž\G•ì7}¸~Ëgr«oSÝqïJ®ßcI}u ¹"ÕÐhÛá·ïbPÖ\‘äÈÉ,'$³0§°x-EŠ©$55& %Óbpé†@M‹ œ¶¤Ç8ÏëgÄ`*ÃSÑ›Îd‡e“ˆÌq"Ý3(Òƒ/Åç±-?†¢ £…kfŒ]HqE1þW|Šað/O‹q‰¥1ö¬š¯2)A·WHk%[«$©f2[’&s$©eRǤXÔƒ‹P•Ø#‡ù¬,J£hDH£˜Ç)D*ÕÃóÛù0¡æY³…ó¡¯b±0ÆnÁBy.ŠÁ¨l¥ämHi‹eJ¨í3Y"+¯–KÊÃ9 þ—Q°a.G¦x €+c®¤*jU ®Ðéñj¸Õbl­kbìµ1X„øE¢]t¢Üã\ðûÅ:Î`âz”0OldÖ(6NØ,3a‹”Ñ[¹åϱ=ÆÞ£ÄwQOÄïDŠ_ì’¿ØíÈ=R¾´×áûXªjwŒ½?£ò€tÌŽ;ÄU¤ŠŽÁÁ=b˜G¸¹†ÞÃíÂW<ÆØ¸ ^á¥á{L¦}í8KC=(š ŽçS¼¶{cìÓH¥Iô#y“¸ÄÔ¸ïÐ2±®b \\—£áì§c H•Ä”Â0nñêD‹nÇØƒd»ÃÕº+KSî‘_QNsûïsû‘Ú-ø»-b†¾Û³\(+{e…-~ç2!IÊ×&Kùb²”UbŠT&‰¿eªß’ EQ§ è²é£°ÏJe§R‚2Fñ¼™‰™5 ùŒâ‡|`ÁçlÙ£çŽÂ÷Ô86_zÔ)­™! Gá×ô¢Qv&ÅÂï J³R)…nH…,G*©VøUÓ¨…ΣöW²«©€×fË‚^«qäY`í(Ì¢êdЋõÒùbƒ”Ub®_i”Š9ωhrd³”sÄ|¿²ÀŸ¤…K0¢;Z¹;±Em ìÇŤa®%£øÕRò¸—–£õ++GñE…Uˆ@ÌjÎw 'p¯…[%OtB[G¸Úh šÅf·À¸u?fÇI·ƒ$î`’ÐÅžLžØòÄn&îùp¯ ÛÇaÝLšÅ~°fq€é'Á>94*àíôÂ[ƒG[Ü3*ðøqt”sT8†f…£Â ¶ÑÑ{ØÉQvèÃ`Ë:5 7Æz3°NSp¾³xf?ƒ0Ê>7ŠBÏÂOtX¤è5tGÒ\”iÈÑ?ʾ„ðËCu¼2Š¿,=ʾF«ó:“’ 0¹)É-‰ƒL&Þæs‡‰~W®µ{`ÄÅ}Ê<öJ°cñÑ‹X%?eòv¬/)–Cü RM–&L¬¡‘œ9T½Ê#q*Á{©ø!˜÷¦ÅÚ©±jl@=—‹—3£Ócí ÎŒU𦈕k1BÙH—ƒ\&Ì@„¯æJÇ)bóÉkP¼0¢gÆÚ…Ä‹b¾wQ‹5lY%±òb£¢”’ó—³å/Ëd¡å(¤"?<Ëߤa³QËÇbY\d dˆôÆœØT+ézF¬\TËcYµTDx¸"êbùùçz™ð‡ R¾8בNýçq)fS,æOͱöüXaF.ˆµ[bEdäBpL‹8$Òlƒ¤“ÛX~’°¹dÄâYÂ%~Õ4—J•¿Ôªùb¸°*–OzW£˜–Ø ku¶–+¼€¾Æ²:bíÎØ¡·“Ö¡cѵë‘Ë´Pß({o,›cùX²Å_]Ý*UÚ±m“ ž°]Ê—v8²K¦ß‰ô»xïv"÷@b¨íõg2|ŸßÔí7½´_F?é|Iý`,^/q©ø÷¯r…F!¯qú¿Ç‘G¥¬ÇüÊq¿rBÖð$Òµˆ^fõât,ŸÃaZ'ÎÆò9Ü9¦êùØ€/æ{Í ~Š·1Þ‹±v?«KD,ór¬}…ºÖ´®ÒÆ{WÛuôÇò“&7¤ÞÏŽI Þ”ª¢ßŠ ¼Ü6û7—ÛnÇârÛX¾šv7Vnñ`GqöfÜÅÑLY(ì8Ei““§0¦.©qø&Aât‚Óéc2¾’ -‹ Mä@A°XäZbèßçRÆÄá¢øÌ8¾JWÇßf’XÇßfÒ*JÁZÅ,¦cÊ8U9“Å¢l±¨tB«dhµ Í¡5LÚİ6Që„ÖÉÐz¦6€}8—É"ѶHÌsB›dh³ Ï¡ ˜´‹…`í¢5.àŠ"uSÜÃõáÆ;èKÄâ¸Ô ùÓÎË&ŠÞNQÑKâ¹ 1Íbü²¸¡YXgçÇäÇ(KÅ*ŠZ&Ö.Œë×S]Vˆebcœ½)ךâì-$ŸÚ ©ˆmqŠÛøÖ·¾ešÛeVrq‘aGœÝ×§|kgœ¾Kr|ÑÜíVžÚC^Ž{ãì}qûâ vK•veûea/òµƒŽ<$å„ÃRFqd¬ÔÑ8¼ð„NŒ>îxN°gè mpºNÅñ£½}§ ¾z†`ÜYÀ9ØÎ|íhà"lýO\Â0¼ zƒö*´kЮC»mÚMh·  B» í´»ÐîA»í4{4i““ M†– m ´hS¡¥B›m:´4héÐ2 eBË‚– -Ú h¹Ðò åC+€6Z!´"hÅ£ñpêh<ºQ:šŸã˜Å¤ŒÉ˜r1LÆV‚Œ­ýÈcNÕ0ºf¶kH™C¹}\K0¦%Ô¬(gx´f‚'æŒ]h!H ‘¦• [ÄY%‰¶Ñü~Ëb¦·ƒ}¼„ÉØ¥\‘e’,g²‚É*± l•XÍtè->Ò_Y —Õ1Úî-9r½#7@*ÖFÚ$Éf&[˜ür+È/·ágm›££åB¦£í. ÚI…é»FóÁk7Â;Góu©âW­d‘öIÝ-¥±4öžPx@šV‹CRùáaGqd#:ysò:îÈŽý$$öÒ§ü5±¬^M^9-£^9ÃMgÑÄèsNÒóNVÞçÈ‹Žìwä%N¬^°º‚οÊ=vm´}}4¾M|c´=0z€l7¹[oÁŽïr«¯sÍnÃÆÖ;­ºz×oýá=™fµ¸/•>R·ãYN˜©¨Iñî7Msr¼Ümâ÷än3:y(HUÜn÷”xLÁüûU+%ž?¿o§Æ+Ö4&Ó™¸Ó@ÜéLô þ5ÂL&" $:›‰“µNFÊœÚoêFN|ª®»bä)AêŒxûŸC¶È˜ÏåÅóî›VT~¼]Or¦# YäÈbÈ€KEñübap³V:zI¸:ãíudXï¿~¶ÿðé{äõ»Mñ6)¿Û ò-L¾³$~“øíñø‘-«‹WþN6‹]Èi7``olÙéø€MðLàRÏÆ;'税k…Úo_ŒwYªÚoGF ·û\¦Ü‡]‰·¯Æãw[®ÅÓœOþ8åuØä2TÄ ^ñüí„›äpß "ä6F¬õ»÷@ïcð=À °ðå¨ü:D~‚àKÉžG `* 5ãcZú`:“4&‰é ‰’d2Ébò¥l/åÈ438M®$yLò™Œ-;3á‘o'&àÄ®(Á.N:z”n•"Üš•ÀßÜ/cRÎĬ ·Y ‹Y%-Õ°ÌfKL0‡ÔJRǤ^’&s%id2O’&&Í’Ìg²€‰Þ¢/”¤•É"IÚ˜,–¤ÉI–2Y– `9Å ´re‚¼ÜÓ|Œhu‚]— <.i®‘NrãdÎ\›0ô:† BÄuÊÜ×!÷õ€ è üüü&™ÔÍRu‹8”¹Å_:›Ùš ßPØæÈíŽÜ‘ÀÏ”u!ã€] ò>îî»4 š³Gæ&|æÞ{_‚ðùº¹ß‘y¥0ɾ1Cºh}$ÁîIèIÀÉíQ™µðýü¢>Ó–øE`"úIï)ô¶·7Á&¦Ÿæ®?ÃDœMÀg¾Ï%ØçI¹ÀŸùî;ŸÀßñ¾˜`÷'`yäó‘—lþÌ¢zŠ[½’`_¥ˆk ó|]¹ž€s´èu@á®› <í½…-nàk·±uÝÜ܃ã>@íDlž‰Ø<±yBK&øÚ8RS ¾š m`:BÒ`KÍd²Ù‰üU·DùU7&¹’ä1Ég2¶ ‘7ÉÄG^}-„ñ…¢Dù¨gq"ž-IÄ£¥‰öž`Å=+ï*”%ò;å‰òu†ŠDûS•Â[•(&­f=;ñ‘Ç kñs`‰¼…&Úu‰ŠUϤA’¹L%™Ç¤‰‰ÑœˆŸ„å°laÿóo}a¾…‰©t¤Ç[k¢\þ]oWU–çyÞsd¦ñ^¾®¬¦‰J£&3|`°îîb¨Ý™5ÕÝÙS•Õ™µÄTÙ3=U5KöÔQweqÁ]wPwEqAAqPÜEæÿûýß“Gd ïÃïü¿ÿ³ÜsÏÝ·s\¿þŸxŠ#u¨¿ë“>¿ñî¥ëû®}‘øYÖþÈ 3·ÇU‰3”À°~ÞRŠÉ‡ŒtI…Gòc,‚ûh$o›\Ç®šì$ZÌ]©Ÿ4ž‚óP$zÓŒg˜¶œ`*d"'Ì9ÌSU¤\¶¹\ç#êÈêH˜ºÍ‹Ýæ¥nó²šrœìžœ…ËOO‰®D¦{pJôWè÷ŒüNŠ®F~ç¤È «eÛ×áª)ìíë´ëi߀~vø-úoÓ‡þúa»ï²aîÁvÌý 6vÉñðA$¶4Ûår5Á‚Ñ Ã²v§´NšG Ç‘šéI¤Ó‰’·)ÀlW³»»ˆ2™}ϳH³¯^Õvß¡²ÿè£{¸Àî;«/GÊíëÄYa h/„¾vøbú—п¶g+»œv6íØŽÉí|e“×KgE_ 𳲯³ªoˆù·æYÝÖ~ôQ~_ýÙæûakú⎠È2k1›ë ëQöÏ7ôuòûJ¸¡e6õÅ\nî‹÷ó-ô}X0È`oíË«ê¾<{ÞŽØÞ÷¸ú¢;=‘Ø]°v÷Åçb" E"ñŽðí‰Û,€¯D¶C"åæÌ£c˜nÔqN7â â$!² yŠušÉÎ(”** g ¦ TaÎ÷íqM]Í™»Ð—ç‹e²ã/A.CjD~{E¤ÒÔ¬CÚß^cÚñ×ãënn*Ü"Ü&œ5  ³¦±oÛˆwѾ÷ ÷û_ÄöE‡’}ÑÏw_öóÝ×i ZXÙÇ}ù(ùI_ aiC’vÈS]:Ïúú%wp½~Î ¡/ÐÜ/1…W°^£áßÀz ë]_4x !b& "•à›ðÍ&LOLO×ds˜,ç’çúø(yñ3Aÿ˜å þÓ̇s꟞ù.ôáÌw‘g¹‹}øÒɾÄç,õY?[†„½—ûzœÕfû0Ð'bÂr}NžO.a +rg£Ïòl"l&˜->¼Ñ[às¦ÊeÔV 5ئÁv ,³Ã‡ódÅ.dEæÝâLÞ#Ædw‘Ï)ô™o¼Å>'ßg\Þ½>gŸÏüÞ»ßç”øxýy@s!_©_ð… ¸ìóëÏ9ì;ì 5“±W:ˆc¼\iU‡ñüþ˜Ï9îÃAý„Ï9é;é³ïõ–a:%4O©*S÷º<§}Ø?»ÝÝ…óû3(˘s¦Æ÷ÿ¤ÀLþ“\“kB¼>|Q^é þýàC<Óœõ9=ã+}.RœC½ð 1Lí­êž‡ï™?ùPÂùàYÃÌ}ì­VÌ ÝæEC{.a!^Ær›\"¯h$Þžó^ínÛZŸúñäxë|Î5_à'Y¯ë\O®÷‡74Ì47Æ­€qÞ ózïʆ¿! 1`Ü¥ñq¹‡©Á¸OÃóñ4‡1Ò¤I?nF(KK÷aÏ¥ûñ'-ê5#úQp4çð±O’õÏf®yâÃ×`­²F~âõ¶É:*몷«¬÷©¸äæ_?Äìð›Ù²Þ=÷9/|/|!9ì—ð¥ÏyåÓÖž×þÉãõ¾Ñåi¹Þ¢ùßq³éäfËõäñï}ü6©+hû[oœh¾å=#ÚI‰¶<3AžT…Y„Ù i„t…9„ BØÜh¾êOpgFóæ4Á;?š¯úkž…̳H“-f²%³”1Ë4Ïòh¼êÉaî\H'²ÀWýa¤DK«`I¸:•¯Q–YoK£ñÄ(:è:a}4/6D;£7F‡¸Ý^¯{S´³9Z–µ%ŸÕ°N[£ÂhÜó‡ÛÊU8+³ÓïÜ¥ÎÝÑúŠÙŠè +FA{!û˜a¿ºK®R€ë qˆ¹+!%¸±½ŽkÌ y’¥”iô)FŸV8C('x+؈•šñ,‹<§Éª˜ì¼ÆT3æ‚æ¹ˆÖ¿$â¾Ì45šá á*¡Ê\“øa×áV¯ñ7Sgò«w›`îF6°½úôiŒv.ÿÈ2wÑ^÷°ŒîGs?ýñ…ÑüXº)c€ÈßÌ’ja-¬ê#þ‹QÂ' »UŠ» !V‡v-•ïî«i™gÒð#úy½Ñ8Çvú<?—áõ¾ˆÖM×?ñóæêøZÄ~ƒ*¿•Ú~ö.}ÑѸ¦|íŒc™.,'FdFŒe†¹Rbœ™b¤Æà:Æ3+†W Ѩ`µIaM{ωáleÄàˆ:W_Îó‡™þY–†_Í÷‡ ü™jøÉ" /˜%j,6Ký)–ixÑd«qÉ䌼€±BËf•}V³NÝ×üù1Ι«µ1kþup~ÝgëÅ®1›0+5fsŒ#ìÞ‚ø‚nNô˜Bx¶Åwz pÅì víŽáç§(Æú¦ðÍ^‚wŸ$sí‡ÇUBçK/%$”hÏ!zk†#ïQM{Œ1ÇNN*”Nܧ9ù3™ÿr =º+ý|–¡å>£7¶ªÀLqžÅ˜jÌê|ÑŸç’†a—ýa S†]‰áØ8„_Õ~UGøËk€¿¼®•¬ÇÌßàÌߤÇu‹p[á¡A¡‘pWáá¾ÂB“B3á!«æi‰Á–wæ£nóq·ù¤Ûlí6Ûü&»æj÷~t< rHâgÝù:ºÍçÝæ‹@iؼ$ ]‹Ôñ*Èaýæu ûêz£M/Û§´Ð_¿‹a_]êìî«ë}ÌwûêÒbº–»‹‹ÞéÇ8£Ÿœ§ôCŸ ýàNí§KqBlÔ³ûùyhs¤™ô~ì«kñÃ÷ü?ÍèçÌí'á<„¡ÚÅpf?gþ,“Õ=]÷è…ý¸K\ÔÏÉè—ѯ{KìmœÅýBÌÔ%ýR÷ÓŸ:–össÕ|µ¼Ÿ“-9súùï9HŠÜ~zñtÇÁõë_‡‡çõÓáVHÚ_¯ [Y:åcnÞ9þL–EF,Kï3—áO~2/Ö‰” SŒí’ËeŠ®€´ü±2ù…(wÚ"ÍÚ{1Ã0Ï’X¾5æÃPÝæ²nsy·™Ýmæt›¹Ýf^·¹¢Û\é7yö°ÊøÑ±:Èa™üXí`iMlÐðp¬ rX¿YËó„õ:£–gƒÌ g£È_oŠåÉÂfé>YØûÝ“…¹ßùqLÓÍç“rëw+[Ø£²Ûb{¾'ö±w{làõÚï‰íèNd»Ý¡;c±ÏÚ»+Övß2C‹bØÆœ1űÎ^I»/6øc—Xí´$6Ð)¨ï€ÄûJ±,}áµ¾>øúplPߟ–uD’Ý6ÇuÛuNÄÊef,wze±)'b…Í)Äö>ÍÈî÷›È²ÊcŠØŠ e,ÆU®Ü94zU,{ÈÅ0EžjÂ…‹„K×e€«†à½ð^%¸k¹º×Ì5LäzðDêcùÙ†¾‹MA’›HrK䎹ƒ¬wLóv¿©‹ÑîXê½Xç¾Ì÷n^MŽÜCü®‡ÁjA¹XÍDZΚޖý`·ÂÚXF;¡Æ<åUÑ3¢§ƒsú á ø’‘®WÁyÍ"ßÄò•§·¨è;H'fò},Ž´XºNœngÄáý ‘¸™q8ÒBfÁ7±i"Ñé"ÿ<¹yq8”fÆñ¥,Â|Bä@äB…E„Å„è%€è¥šgó,WÈ&äbr1yqÁ¯<™qxʰ2]î!Þ»:޽9åÇáã•8~¼BOØ:Âz… „ ››5ã–R °•P¨°°]óì`žÏ®8>%¸÷ÜE Å„½ZÀ>Ôr?ÏÔ¸,ÆÍ'xÄã²(õ­3‹ãõz/=^âÍ$¾g–iñ÷Ìò€‘0rF.Kì>ŽçK½ñÎJ1VÅc´H>’¬‰çb-"%:j8#Ö‹ø6ˆÄmŒÇ ͈Ø€[!…ðm‰Ü.½ÖNDìÂãwsŠñ{E Å„½ ûû Q%€¨„èR@ôABä!@äaBÄ@ÄQ…c„ㄘ€˜“„ó^Æy?Ï~§q•.ÇÌU ª•³ðCõ«`‡U 묋"1—Xúåøào7]a5ñ|»æJ|ð6p5ÞáR+vÜ7uñì+ëÿµxçjüÕxl×ã?¼-[¯^ü‚ú2bÝoÆó:î–.¨Ûñþ9î f "ß(Ò`:ßg£<`¶È&¶]3áïþ¾Eáá1¡Á<‰çž£•¸×´Åó›¥öøž—dOsö +PG<.ÉžÓ‡Ëᾈw:ºëÿÅKòÅ«xçµ8ßÄmÕoî›N®þïãù%º»+žŸå; Øàg$R3 &5=ˆÌÒ¸ÙŒKSH'Ìñ'ÌЄs5nã2²ó kÌ‚ö=±¾(ÁßbêYÊ÷2{9!$’ãŸV®N+Ï+W˜ÕÀ&ŸøÅÐk´—…~Ù©ÕÚÀjmTØDج°…P °•P¨°°]KÛÁÒv*ì"ìöWiV©ˆVœÀW†Øèaûüiökšb¶9à?Ë6¥ )âÊ1®sˆ.ïá€Ç{„Ž\s4àÉ5Çèrx\'è(4'žBSFW9¥?­³uF¸ËÙà:;•œ³×9€«Š`ÎKZO5£/hÚ‹ð\J@LJ—œšôìpE ïUXëëâÑÛ5j^WS_j®WÄÝèNv³Û¼Õ#<üvw«É4$`4,§1àÅcŒ» ú€‚]Täš{ x²x?O$8M M æo3, "Ä#Å–~ð ó‘š&Ìû8Á™—À§ŒOœÖ„ÖÿSƶg~‚þйz;’Í£ùÔoþÞë}–à$p:üuBñº×ûê-ÇR,²W×7 ܽMð÷½á~— ýOx;Õ%ëý{Éö·+Áqú—wFÇá$Sús’è©¿ö“‘êgùÃÙCÌW?ñzÓúû;òXù§¡æ+·xÒ»=Hœiæh®L“0æŒy#3`d©á™ÏÐë]Ðߥ½Þ…ýù ¹gQí@£¯øM9ðöÚs-í}ò²þÎr1²û㫸þø*NÄ—'ÒlV"E³YÅ$A¯ŒyV÷ï~‹³w~P¡f ²L]Û_ßÛX×ïm¬—Þ ýÑWí¦þÎRŸ ßÜßÙÒ_NM úëÊ[áï®_!ë·­?ÛQ¨äNÔojº¸G$®¨?^-‚ì…ob÷Ã*I8€ˆRÈAø!ö0¬#°ŽÂ:ë8’œèÏQÕûë¨ê„S § gÊ „ÈJ@äYBÌ9@LUÿ Ã ºÇ;ßß©î_ÝÿC÷xú;çûÿüÝã]ìï\êø±{¼ËejЈWúóù-o-¡Žà¾ÖŸ=–)ÔnÂnÂn)Ü&ÜQh 4*Ü%ÜÓ¢ï³è M„f…‡„Íóˆyyƒ]à=4ï͇òšÎʤޣ½Œùe|:‰ ½3üaІ¿œ™ÈФ&ê³ýÍ̾ïf'rqU+¥È2é‰xE0Q?MÈø±™›È:Xf^";ÈÔÍ'ÿ%+Qêžðæ': $êz±0Ñ¿¢/Jì>å Ë0‹%‰æÇ?]šˆáDZÌ/—%:Ë%Iv¢´í/sÜD+Ãä2Ì ¢Y™ÈÙ*Pn¢ø[ÌêD'?cq„µ˜5êÏõOymbÐn`]"?bMä)õ‰ ÝÙ„´›µØ-‰þSê‚DŒ«—ˆ¯àDâ¶%b@2ÈDìIØÜ Ù_‘Hd±Hô^Xû±?‘_ÁqŠñ¥  ‡Ž¢Ž¢Ž¢¢O"O"˧9™ÂB9!¦S™tJ-³}6Ñ9'UªJ Gàôf éB"Gƒ¾ˆö¹¹Œ$5+ÚRWuHhS›ÈC@Œ—ÄŒ¡×Ñ"õh¾°n¢EnÁº ëŽÈ¤†D¼y×(:ý.bîqî3äÎj!¢™1 ¾€ïaúcÀô'„I­€Imš§yžv˜g‰| ¯ƒøÈ¼>2/{ ýª{]±Ë þ›Dí­EÎ|»c\Æår¿óÇõ<1­Æí$9~‡ef$a÷$¾…›„±ÁRiÏ‚í-‘Þ48¼étÌ¡!6';7 …w%v%ʤæ%9™…$®ùH"ÎIÚk!œîEIèäUX¬U0K’0˜;d§»<)CŽŠÕ;;©ûÃ÷ôV¨+')=4p/4ÐÙ€Õ;7)¸ˆ¼¤?è#bELb«’¸N¬NúÐGD~RPk’Ð#ÄZê:êú$ô±ºQ4b“Häf‘é[ "Q[Eb amKBÛaîHêÙ;D`ñ…îL²­¨]˜á¨Ý¬U›)µ™b?îUÜGŒØŠ(!DD–&i“Ø…Ã!bÔa–yÄwTãŽiÜqÆHÒN#N&ñ¬Œ8ýhúé$í%âL{‰(÷c…b¥¿Ô³Zê9ÍYŜ瓴ӈê$vq!©G§áµ/%9—Ũáúq…uÍTËŠÕÑóáyx»©Orn$Á¸ ƒ_õ…ÝJrê“ôgY·åÿ©¹ƒÜOMC’ó#ë™i=3w…d·|Ns_—øÁh ÍIú¥úàyˆí %‰»ïGÌaKˆ'?}‚’%ô›VØÜƒ{Úè†Ùž„·}ÖôÖ$Oá‡û™ß-G†ÌÛsÔä§æ%È)¯®¸$Kü¡¯7. ¼¯“Ò?ê~®¸-f»~ô?m®7IÁW¾:³ï’œÎ¤Î$™ð{§.8‚F‰õxž›p—ÒíöoJ½S…3 -uOôfILèl“6€å§ðß&˜#θŒ¸W ™7}@À—œYßBøC–@–"b"–³!9\Dä‰$¬®„¬‚o5|ùÀ5µuõ H²I67C¶ÀWßV`!d›Èôí°v`&ãwr&ãwv+ì!)ö*ì#ìW(!P(%T8D8¬p„pTáá8!âľ5¯PF8¥pšpF¡œP¡PI8«pŽP¥pžP­ppq@Ï[,—8¡lG(àl ·Â®®*Ôê®®L=–ÿàuä&<·æ/npî @§ œ[àkdÞ»ðã…„ØÉJYyîÃGïƒ^·«)àÖ¬yŽš‡jLkÑÐýHïûÃ'-WkpÚžî´àÓ§âp=€§;øtçù€ §;¸h}1Ày9à¥$y%ÿa¯‘á ’ºÞpÞÉ„~Ú‰Ð2ï «®x cœ¸ë?c cR½g Lê@½‘D ™ I#¼0s@/Lq™;÷æ 䄼™Z\Ö@tŠ; ³` \¼/hÙ»<‹¢±Ðµe”º/h±·Ñ¥È„iÙòz]Þåõ@›=¯ÌŠxr‘5²²² ²z 7í|Íá<¢¯ëå¬yí@ÝSú»Ãö~¼n H¬È/ʵΑÝåݤÙan˜}¼[âZd™Llë@ßPˆ$¶ õn ¤ õnWSN_¼Þ™AÄNÍúôÙ5ÐÙ=PÂ=ñ»]ÅåÝË(1ö}¨EŸýÓë-Q3¨‡"TÈ.Èçh¥Š¡‡ ‡E¾="qTÄwl .I'`‰*‰>< ë ¬rX°*!gQxä9YE8OðU|—ß^|[£y®0ÏU…ZB!ê ê:!¦sc`Ðó4ôR?й5ð;½Ôd/õˆ°Lf´Kå®®÷à¿%I"<÷Õ´¾}€Ym‚4cöb¶Z€€O`µ¢™Ú`µÃ÷Iž‰ÄvÀzŽˆ"q/âE!ÈkøÞˆ$¼¾ƒtÂ÷t‰LwIÞÈÌAøü[$r¬Ù" iƒÐ;d|"qsó ™È–5狆./„¦[4±±„¹¹Lc–3&›àËør Qy,`…ÂJÂ*ͳšyò5f cÖ*¬#¬WØ@ØHøvàÛÍZÀP °•P¨°°0}`úN-mKÛ­°‡P¤yŠ™g/á¥ÙziJˆÁ§Ø¹&4ôÀ ÇbZ*ä>(ÒûР »I‡‘}ê‘Az7éè ~æ~lã2îðãƒðü‡¤'˜ô¤?iÙ ŽŠtªGë4ÅÖ¶|³íûÖ+sôÕ9ºÔ£·ûv~ÿ!A5–ä…AxHpqP »ÊKƒœóƒºK¿Œ¢ìšA¼F¼‚ W[+S¹¹©‡Ü@ú˜›Ls‹p[á¡A¡‘p—°ÅÜÄÎòî ¾H38óMþ™oF»†>„Æjäü“±K€Çƒœì0cŸ âH‡­ƒÐ{@’‡·Bƒ=E TølŽüÚ1ˆýT³h÷kóŠ Ü.ïëA|©Ã^8H6æ©áo5“îõ¾“ þŒNÆã}?Èéd¹œÁÁ—f ö·oЏCgFû¦Ò·)\xÖ`úÁìÎ+G¾´Á–Ëër}“>Ø?êìpæ ö?²MÎìÌl%ÏÌ&o–äwχǽ€÷BÂ"³ôÆ,#†,…d<9ƒ9rŠ?až&\A,0+ó¼JË\Í2óÖÖú®Ó„ëý¸Aq£No§·Ya ¡€¶u0_XUØFØ®°ƒ°S븋uÜ­°‡PD°ŠÖ^Ù'Ï~F—èÄpb¥}1‡øìÝè@NÿŠe½5GÛ–ç3G†·+4ä91Ø™ýýÉ©ÅI„e ŒëÔ`ÝVæôÌ™î…êÅŽA.( .EäŒâ¿U Nÿ!.Âq>€/”õ}Qv÷øá¯weÐêaí†ÓGÊ=7Ø©¬?9><¯ʸ>ÕÝ‘íõx. vl[.'{¬­—k—uy°S3Øê4W$Þ{•ëX-]Þ:Â5…ë„z…„›÷-®·RüÁ_[jÓÓ88U®L­»ƒk’òÞ`>õ¿ÿ!ú2xÝî¦ÁNóàfIñp0zÎjø>üÑàÀ[!È¡?ãéýåû B¾%Ò:Ï Ümœà‡nUÂÂÚãSbƒ%žrm{6ØéUï9á@ã/;¯ K?˜ÃÒöK?û£wƒ±?ê¬}”¼¬# v þp³Ÿ3ý5ˆ¸S 3‡ðM÷!Nk¤åžE˜MO„§+Ì!d¼øu†eÝdóÜ"„Ý–”ßÜç›z¼âqÝe³ß£Çsày@Hn’hO3=5C ÀûHÓ>fÌ…VB›B;á)ÁýŒuè t™ .óRã^¡ò¯‡òrñÍP~BŽÎ?t.<ït&‹£“‹ãýPÞKìb©Î0€wÆ0$F(03‡ñÜ+ˆ‡1ÙÃx·/¿1åøôarQ8g®ó†á:o®ó ™ðeÁ7¸²¾Eð-.,…,CÄrDds ¹|k€k!ë ë! ‘d’lnˆ8vá0<€l‡sÇ0Þv¦· »öŠŠ {öö+”(”*"Öf:”qlßeS8A8©PF8¥pšpF¡œPAˆªÆÎ:4æcªÎª5Ù&»8¬Go—à´/sjĸ"mðõUx¾®¥§ûÑ_Ý0§ÉmY׆ý]‡#ð z‡[2ýÝ ñw7‡9Bs ð7· ®; 5 ûî[µÃpûãî0Üĺ‡¥vŽ@ÃÐ;pÖ­æa¸XƒÕ‚r§?BÒöÀ »uXðààmÃ,ÜølæÔ}¿îû–y*lþÃOž sÚ‡µKe:†÷¡Ã†xÁÖ1/1ë¯0ý×XkÞ`Ýx yéDÄ{Dtáèo8^áŽ.ð`¥Gxˆ˜ IŽ.ð`Íd É\øæ3!YùÃÙÞpí°Xa aépío8»À|ÙãÎîäH!¹Ãƒú&ÊŽóñÃýW+‡óÅÜUÃÑŽùáêáÁý„Y®üáy× wÖzô=]| gÃqóÒµq8–Ó&ñ»6MÐÚ‚”L¹u¸#V8œÝUŒùj;®ÃV†ŸïÎOë¼»4üùn ±¡eŠP“âáVˆæv¹öOù(¨^+ÅÞI¤Ø%Lv€,%xJ^÷!x܇ýS9ÂïQ&;¦yŽN(œ”<ë0¬#°ŽÂ:ë8¬°NŠÄ”q§FwƒôÙé¶+l–f—p*FàgÛ³l»r„svÄYÉu.x!V±>çµ>ըϑ¨‹˜Î%´èe´E ä |W1íZXu°®Áº«Ö ÌÆMX·ÐÞ·‘í¤µmdmïŽè9þÏ=ÿñáºô>’M}0B¯K›°â}¸¹àšm·Œøðxè#®?G} ›f·bþÚFèEDûçÉüxñ4@¸rx¦³CÍ ã fä…È×/1‰¯_èÑÖë &4oXß·þú¾ÁÎ#\‚¿átþqw¾.¶¶ó×äŸá&¦ˆ™ùwP©Ÿñ<æ,5ñ…þgNÚg–I×$s>ó?ØÎø '–ŸáÄ’ùN,á›\YY„ˆÅˆX\ YYŽˆl‘„`.$O$z…ˆo%bW}†­V>¬5"}×"vÒ­GÞ È¶²IdúfX[>ÃQÀ™ŒßJ(TØFØ®°ƒ°Saa·ÂB‘B1a¯Â>Â~Bd ò€B)á Áwà;¬p„p”Ð÷ ïqBô @ôÉÏô,ó3že*œ&œQ('T(TÎ*œ#T)œ'TkÑXôÅÏzže~†GÛº k>ã›GW> Ú¯"“]ûߪ«ÃÚq r«H=¬"Q7EÒíÛhý;hîH#w±œïïC`15aÑ53ú!ò´ æä1–ìD·2º Ñíˆy y†Üˆ~ëb_"âä5ä –ù[Xï¸`:Yõø÷„.g$oZŒ$¤f*¤f)Ì&¤¢ÒQs‘#yÓ‚=©1YŒ™O˜¾0}!á¿/ü÷Å#ƒ_ܳ\KFbW²qÖ²‘|i`ùHv5=’¨ÈÙCÓäŽ î(?o¤³B+GÎúWÁøu/¿Õ#ÙÛ §jÖHDèZÈ:$YkƒHÔÆ‘¸ ‰Ë°‘ØZ ðm‰+nƒl‡oÇH|SkrìFÄH|ÅˆÝ k¬ý°J`€U ë ¬CÈ{ÙŽ@ŽŠDCìq‘é'à;Éö/Ó…qŠpZá ¡\¡‚P©p–pN¡Šp^¡špAá"á’.ÚË\´5º¯p^ÕE[ËE[§1×s]m=í ÂûhŽ};xáâ;ã;#qiÙ02ô'C«q¤swdàgY÷äßs$oCŒtšFZžfÂC…Â#BØcIöÒ iCÖv&xÊîgðtÐó\ó¿ ¼Tx%Ñî×#ù‘<=®·×;…NÂ{‚é’´yÆ…n—FñùQôÏIŽÅ,¸àœ g“¥k²9âñdÀ=2’ _²z<óY f!²ö^>‰×"– f)ddù(Ž–­‰¦åøçjâ<ÄfØ+Õ›a¯Rc•Y0òÕ˜k¯Õë8ÍõêgoTc…Ù063]÷uÒÛ£xܪ P8J{¿Ý6 ½in¿Cä·;‘ø·»˜8ÓÞÊ´‹Fõ|©¨xN^÷bæö þØ^"zCKG9ÿ`ýø ì‚í9<Š„ÃvÅî&`›ã£¸ß8!ð0N°ÜeLr I\§ƒ§tÓ.Å'F9Ù#n% 5Ϫi¹ÏéìV)ËEâyXVûà ö¾è/ùÃËåŠm}Åï¼J§«vTϯö=VÝ(ýj¿»ÇÙÞ×Fß“¸>êÞɨ…Kª£øNÆM4Ú-ÌÔm­ñQÞÉhå'£q®® ÷Fá&Æ(ÜÄ6›aµˆøÁz ß$i‰mƒÕŽˆ§"qÏDâ; Ïá{1 G$à+Èk$yë-ä¤éޣЮQxOãs¼§!“k&$2ës¼§ñ9>3‡•.’0çsÜ£€Ì…ožH\&0 2Ù|Ž76~Ž~Fá\ü9ötK>GÅ/%,#D-De"r¹„È<@ä YɘUßj€/_ XÃÖ*¬#¬×<˜g#!f f³&ÛÂd [ … ÛÛ ßî|»Scv1f·½‡E)ö*ì#ì'L/L? ”²€ƒ ‡‡5Ïæ9JȲƒ²ìŸ½åAi>wʤ)O}þaP8¿  ÙíòÏyÝR%P‰Ø³sˆsW1.æ<w5äÛæ¢º/.æÛW@óí«Ÿ_HYµ’ë×u"a× ×E<õHé¹ñ¹Óñ‘Ufn~Î>¤nÝ·9Ý; „F…»„{„°û€° M„fMöÉZ8Ñéy,“u=AŒ«Uó´¡6í¨ÍS÷3æê@dž¡æ 5-÷K&y¥»_3©!ß|î¼ýüíçèõéÆÕ›N5z¿ç´\]ŸíÅœÑøšdÆh'e´å™9šm̬ђb6$m´¾ Êh|Ó2g´3kô,šjšO¼sG;óF›ß{3G;ÿ"á7ž¬Ñ¸)Lø¡oÓù£4Ò0/B¡ø8m4îÉt'.‘I&/OV—æ+{Ë5M¦É9#—uíþ.\l÷ är¯ípä¬UþÌr¯–˜ÈGÌ?¬åZ;:øã—Ñüøe4ƒn_ ›Pôfû-£õ“Žˆqú¶ŠDŽÆ¨n°¶ÃÚ1ßlìïBy»Y^ä@d!¢˜1{ ¾}ß~)aÌÑúQFéh~”qø‡@ÿxxtÐ36c…¾¼-ëÏÊ4Ã!MøñÑÎßHpB+ìähvÉIûíÓ´ÏÐ.§]A»vøYqŽþ*úÏÓ®¦}E‡…_í\m›ð°Ë˜VNòŠ.ÏÛë­íœ_¨„§IåCp^#àyÚu-!×Ô‹a£·ÜðȱH&~ S’ð6CoØÑÎ)„ ¥?mDjû“ðOîŽÆ‰â½Ñ÷$ß}¬FúšF;Í£{úŽÆ¡¯–y„åüKü‰.ìVø%æÛ¶Ñ8\Ažb¹>ÃrîYh¿€ó%ä•È1ómôåNÉ|ù–G½C¦N‘¸÷"ñ]g º ƒaÍIHƒŽQ ³áKñ¥‹D̓ÃQœsE²Ì<˜™"Ó³ ó! à[(rÄ,ƒZ,£µX‚ЊYJç2¿s9Ù˜FÎÿ=ÑÜ1¶Ÿ7†c 2>~%a•ÂjB¾ÂÂZBÔº1!òÁ~:FˆhæBy¨ÐBxDˆyÌ~2&èzìV`°ƒÖ1é?p SÓc”ƒ°¶1ìch †5x ;ülOÇ^Yáð/Æí|_Ã+6ðë1|)ú Úö-ä¸mô Ú…æqÆbC‰K‹¾ü ©ðÍ‹‘CE¢ÓDþ9s ¹cÑRóƲo LB!r> rÂBÂ"Bôb@ôͳ”y–),'dbr1¹cƒ;òæÉD½+D¬•cƒftÒºWuòÇZfÍX>‡^Kübè‹õ¹ZÛ@§w#œÞMþ ›5Ã+`ÜVB®)Ë ¶1¿Ç»}¬³c,Õ;Çò…<˜»Ô”£ôî±èééïž±N‘Lí«bêW{ýá>¸ß– á×ë`êÏ|ã-ëH5>ÌßÁ±¯"åW‡Åá:2_E˯"ŽíÑçÕqxícyþw ² ÷ÚiÈøÊá«VBÎÂw ¼J$æ<—@õØ'}XðűÎ%1.£5cùI˜z®¢¦µ"ž:‘GæõúX~YÏ4ݘÀ¾ ¹5VŸ@uvÙ»l+êÒG5­Åö]Ðbû±û6¸dœkP›¨ÍÔ‡¢a-c1¢õXŽh=Öy2ÖÌ5ÞÖ±NÛX[¬¹¦¾'~xª€$ϘDŒ¹¦fž+ É‹î$/ƒ“¼ò'‘4¯S|d "Ö"bp=dd#"6í@àH|[á+nƒl‡ì€ì„ìB’ÝH²X)†o/|û€û!%"ÓÀ*Çw0Æé;„à GGŽŽ+œ œT(#œR8M8£PN¨P¨$œU8G¨§wÇÇñî¸ÂÂE…K„Ë 5„+ W µ u„k × õ 77ÇÝóé1ˆì­qÿÚ ²0^šcn¯,w¸^4èzѨkÃ]ÿÚ°Ç܇ooïSP›Æá Üf,†‡ãðn ÿð1ë÷„%E¶"ÛE¦}?V}êÇgŠÄéÏAÓ_ŠÍËqüÌõ•?ékMú†¸Ô~\jwŽëùÄûqN—TÁÃÇŒñNÊxË=“ª0k<:î¢' ã^fÏïdИ ÃîçvÏŸngŽ7YãÍüñóéYÐÃc¹J’cQ ë‱$`, ËÆrïφ_xN .†¾Þ›7ßH‹,·W¡¢ËíÕZ÷|Ô}ˆg-¬uœ‹õ·°Qaa³ÂBÁ³à)$˜m˜×öÀLïøƒ™ÞÙs¦½»PÃÝãƒVš=(Ï.Ï•¦Ñ{Çãî¼HÂþñØ$! ¥ˆ8ˆˆCÀÃ#ð‰<ë8bO â$¤l<p°NCÎ I9|ÀJÈYÈ9DT¡”óÀêñ¼Ï:Å_$\R¸L¨!D^Ï{ñ„˜Z@LÝøK^“Ò¼×Çóõôñ°ôÆxn7Ç;:Wз:ááßܯŸÃ‡~/ô{ÝŸÃßn¯;l¯†ñ¼”nn,Ñh÷DbîC@š ͇¬W ÓÇ<"oOïW€âW*¬"¬VÈ'¬QXKX§°ž°Aa#a“ÂfÂ…ÂV…BÂ6…í„„¨€¨]„³{G¦ß3!¸kº°¢ ì z‚³w>Ø7!ÝùžGù²FíŸàH\XÉ„àÙLЮaK'º†<(3ÿõ¡ ì ^+ò òè„à®aÍ1Iæ9>DOÀ{^æäÞ¿/› '¹bžRÓrŸfº3p7ŠcI–OÐ1%+4ü³J ¿<ëÏiøU‹vŸ´‚W „]àœ^œà\š€þ¢Zžš è–g»å¡'¤R§ppடÀnyææœPjýoÃuiÌ;jZ¦aFØnœàÜÅÔîéT=÷9?4LÀÝ3IÖ„¢šQø—5Ý—-ö~äs¢®'‚_âià°óõ |åÁjŸ Ÿ¢< Ÿr‰ùLM®i:&øÇ:¶eó{>Áù§’ å½ n©Wx-'iÅx;—q¨]§ÈïÞÃêÂÆäLÄeÜD¼™2¯‚S'¢Oö‰¸!I›ˆ""1s ")f®hÔ¼‰X-3'b)&k"WËùÄß-ýn!!f f±ÂÂR³l"¯ü—?ôoæreOLwá“#ÝÕýqÎÄ3×ËúõOÂ储–;1½’àó˜ïÉ_ÞD#hÔ¿9èØD'ƒôÂW+äÖ(¬%¬#üz=à×?ÙøÉ&‚{óDŽd@+`Ñ[ ÛŽÙ>1hQì@”½s"w»$&t7dˆ)šÈ]~ñDÿ}‹½XûÐâû±J°@Jqp"ŽoÀÃ#ðÅr;&}Ö DœœÈ§Ïõé3á´ÂB¹B¡’u– ó!º }žY ˆ¼@ˆ¸8‘-+\&Ôb®p¹^´Wâ…Ä'ŸÔNüƒ ‰º‰ÁÀµ‰þ·Ø®£aêQÐoLtnNìnÄ[lÄÛyz ˜ûF´Ò]Ìó=È}ø š`5Ãz«Ö#¬¿YÍ'{\¥¶²ô¶‰<ÑhG%žê‚y6QOQ×I>ÇZÿBäÛ—(ô–ÓkXoPü[‘IïD~Û)2þ½Hl&éL’sדð.ï$4ØÌILvÐÏU2_ÅJv\–ç1í'°Ý­XÿÚ¹òò Òyyy y•Ìñà%#†ƒgðïß2øÅ»d½auú-ÏWï“® j9“13&s»K™Ìínædÿv—:]{LƵÝd|06ïŒ GÄæˆÌ˜Ìw'ë!p2„T;k2¿˜?¹Çv¾@ŠØn"n»Y4ÙY<Ùò,ŸgédŽ.IOØrñ˜lxÜ9ð`¨ZƸó&óz`hñd˜+Õ´Ì*¤ÿr5Ó™|·F3¯5kÆ:5z¯×p†ÙÀô®“ƒ–õ&6ÊæÉ|ܲEbB [Q«B´Á6‘¸í“q³²¾]“ñÞ"p¤¾b4à^Xû`í‡Uë¬RXa‚uÖßQ4ù±É8sDĉɸ>e°NÁ:$g£u©À$+!g!ç UóHR$€!— —!5+«˜åøZÎr|ášÂuB½Â ÂMBä-.üÛ„¨;\ø š¬‘Éî*Ü#ÜWx@hRh&| € !‹ ‹±KË Ë!ÙˆÈIÈæAVÀ·¾UÀÕ|ÈÈZÈ:$Y$€!›àÛ ß`d+|…˜î6àvÈ‘è"ÿ¼ ¸²RôÚ¸˜¿—°Oa?¡Dá¡Tá áÂaÂ…£„c Ç 'NÊNN+œ!”+T* ÑgÑç4¦Š1çª ¿àu’ÂeBÂÂU…ZBÂ5Âu…z …›„[ · w1 €˜FB÷hæ_ð˜ñ…s_ŒXšÛ y(2¾E$æä1ð Òoeú˜6–Ø®ð”ðŒ°Î~Zg¿ v?C†ýJ×Ñ×_8o¾xùö‹ =Þ»`è{/âîú‚ßOqfL‘Ë÷„–™9…»àTxÖœ$Ïž’.y…]iS‚ÊJpÍ ò˜ $Ÿ:wŠ~E2o zcÈ„¯wÖí¾aþ”½1,é¹\®…Sœ3ýÎôCoª®ESœÅSðCߦKz\Úöñ.òã5-›tže/Ÿâ0Ìö‡9Sœ ŠçNAOß"_¯@å¾^9¥Ç‡1«¦Xß¹–^=宥óƒ[bÍcгnʺ)Aƒ±'Ú0EoýmœòáÖߦ)èæuˆÜ2…£B°B[§ôªp ;ŸâlcÇôn Ù…)íÖIïA¤DG‰3®x z‡ì‰Ø_ ð¤r‡qxrr ǧà®=ð$¤ ¾Sðž”C* •³HrIª€ç!Õð]€ï"ðä²HtÈ?_^…ÔBê¦ðÀÄ™Œ¿N¨W¸A¸©p‹p[á¡A¡‘pWáá¾ÂB!ºýPcZóHá1á !¢ѦÐNxªðŒÐ¡ðœðBá%á•ÂkÂ…·„w„˜N@Ì{‡K—ËíêâZj…z\OÄ™ê̘ø¹ÖÛîPÏÌ©NêTü,kÖT¼¬8§öiSËö¸­tÍ [õœ©N¹­5fÞT~å˜I÷7Þ¬©Ní'–wþT¼r¸@ã2©w‘øÜ‹§rhpzB–B–<ËžlM›#i½¹"ž<‘fò®dÞULQ`VOåKùÄ öÚ©èÀj:×k‘XäF…M„ÍZþ–©6Ca+¡Paa»ÂÂN…]„ÝZÚ–VD+žÊA3î}¬å~MV‚Y8)e†ƒê>D8Lp¸ŽÌ1¤=Îèê9ÉÉ–i³{Où›ÿ´?<£‰Ê§rS­+§â&÷Y,5|q¬‰ÿ¬JÃÞç5S5–ó¿Ñ¾öÏ—µ˜5þÒ²Í$J6Ìm®NMoŽ© òæ˜:z½×‚œÞëôåšú g®¹A¯ëfÓu‹¾Bs;ÈYhîh™ SùÞD£¿>ž»h¤{˜Eï}΢'×T>¥Ûœ©¦,ÄðÔiάi¨æìièÜ55ž?K›Æª¹KLº?©ù—9Ó¸8þ%ÃÎõ‡ó4Ülg©1ÃÌW£÷¸ÐŸr‘?\ì—øÃ¥þp™?\®á—ÙÓtÏ™ÆÍ9×yŠ+ˆW‚&®òÇ­Ö¸|?®Q\KL^J^ïÛ qý¸Iq³·('mM*ôÇmÓ¸íD׎iA‡àÓpØœ†Ã¦ˆkÏ´ “†Š¦éýðŠQÀG{§9åaüüvß4§%?œªìW€Y¢fÐÃ=)/¤¹CNsj~h…„&xŽ6M‡4;qŸ`2÷ÉiV¨7Ôåö„”M˰qÒáŸñ¸OMc¯¸§eåaotòoBÏLK‘\¦|Τ<Ó°ÎUN«œ†>CÏržtnZ†’eªtÖ¿>?ÍTO»0MKõ"õõò4F×L»2Í\V+}uZæOj§Õ1úõ:µžzƒz“ZC½E½M½Cm 6RïRïQïS@›¦5ë$›é{Hm¡>¢>¦>¡¶RÛ¨íÔ§ÔgÝÕí ã¹ÎÍ ÂKê+êkê~KxGí¤¾§vQ/¡3¨)ÔšèLÚ©ÔYÔVúgÓN£¦SçP‹ÆB›˜&ƒž¹ÔyÔLju>uu!uu1u u)uu95›šCÍ¥æQWPWRWQWSó©k¨k©ë¨ë©¨©›¨›©[¨Ô­ÔÂ/?4ú¶€Ù,&â¶SwPwRwQ+§•º¶Ø®^“Lm›­råà*Lü>ñÛìív¯É–ûOwØ8;òìÔ/zk·?°öضðåzà‡E½¬bao±ð¿Ù+,Ñ>qüÑ>qüh¿8ÜÇ¿4%âùãñüÛâñ|ôQ©8ÂJÅñïÚ}¬ðCv„õña±þäˆÈŠô>&òÉq©ÔŸžë:)ò“2‘Ÿž²·Ù½¦Z?>­eÑ \ŠŒ,—"£*ÔQ)A˜u–zŽZ%¥õ=/eøªE¢QnÌñõ»(ò)¦‹)Ä]‰GÅP±þ—%6±F$éŠÈ€«2¡µ;¨Npð¹trMÌa×E†×‹Œ¸!òÙM[¢ÆÚ·$ýè[R±1a…šÛöWÝÏ„‘‰"“%.ù®X“ïŠõÅ=É;å>.ëˆoÚñ}ùË©½þƒi²ñ×͘‘Ðï=´#­?k‘ÊýÏ0³n÷cqüùµ[Åþm"ÿ©]?¶žŠº<žgÚ,<—²ÿós)û—/dRÿå¥=Îú_d3Ç_¼û/e3ûWo5õ;IýWïÄñ_;Õñ^¦ýë÷2ßtéD—mýµì'­¿™!WŠj¥ÿíL—±þ.UäëY"ÿël‰qÏùʤIÜß§IÚHw1ó ¼V†¸§gˆû¿Í•ÔÿÛ<§”)Žÿ=S¢þ{–«õÌùí‘oŠün‘¤üv±È?.ü§¥"ÿ¼Läÿ\.òe‹üß9ûÿäŠõû<‘ÿ±Bäÿ])¾Yå³ìÕ¢3L¾ _+¸Ö¸ÆY)ƘµâœiÖ©s½8SŹAœ³ÌFÑÙ«hšÁ:šn6‰gŽÙ,ša¶H–ŸY®k®)pEZóÌV©z¦)”Ø,³Mt¾Ù.ºÀì]hvJú>Ö.̪µ[r-2»%×b³Mµí+SĘbÑPk¯Ôc‰Ôc¯´ÈR³O›g?”ÈD–™‰XnhD©¸²M©¸rÌkYr¹æ¥hž‰úe¯_¸º¹»V™??¢‰Jn\Ç4ÀеZ–R¤•o°ŒåzFìµæ¸è:sBt½Á¸Áœ” [e2©¦L&µÉœBÅ~eN³^g¨å2c›M¹äÛb*t‚•œ£³’¥Àœ“–ØjªD Íy®–àë‚äØf.JéÛE]ÖsIì¢.k—¹,önQ—µÇÔˆ]$겊Í)h¯¹ªÕÊÒÞgêD÷›k¢%æºèS/Zjnˆ47E™[¢‡ÍmÑ#²Ì"¬£²ÌúXÇÌ)î¸i=aEOš»¢eæžè)s_ô´y zF–k«Ü4‰]ašE+ÍCѳ¦EüçÌ#±«ÌcÑóæ‰hµi½`ÚD/šv™Kæ©Ø—Í3ÑÓ!zÅ<½j^ˆÖš—¢uæ•è5óZôºy#ZoÞJù7Ì;Ñ›¦Sô–y/zÛt‰Þ1NH«ÁÌm4Ò wMJ›ffˆmÝ33C\Ö}“"Kã‘qÍ 1V³™-úФ‰¶˜ô¨^ÿÑÌ i5½2$C›™+îv3Oô©É”RŸ™¬«ÃÌ}nˆ¾0 E_šEûÊ,IéõŸ¬·æKtºK5X&¥½3ËE;M¶è{“#黤ü>–cÏaç†,éõK“’j‡­Ðl+C"­Yö*‰žm¯M³ó¥*éöÑ9öZÑ {è\{½è<{ƒh¦½Q4ËÞ$:ßÞ,ºÀÞ"ºÐ.]do]lŠ.±·Édb¬í!㬥²_Ü.­³ÌÞ²3¤×_X9vØ®îJwk°'7ŠBð:é¿7Å’'×6ö^­è>™§<{Ÿ°ÂÞ/Q+%ªDÂUН¶KEómì™ÖØCðøïè:û°èzûˆèû¨èFû˜è&û¸èfûDÈŽ^¿² íOÊ„>µÊd:Ûì2™Îvûªâñ‡üÆÚ!“Ù/áNNö7Ö. OËäw3”mÆ>#T$tF¨Ø.Ú+T.´Ï®Ú/T!TbW ª*µÏ :+tH*.›}.d¬uD|U•ð¼Tõ˜=!ª×µNÚ?«–*–ÙDO‰º¬ÓöE±Ïˆº¬rû’Ø¢.«Ò¾,öYQ—±kÄ®uYçí+bW‹º¬ öU±/Šº¬Kv­ÔEϦN|5vø®Ø×ľ*ê²jíëb׉º¬kv½Ø×E]V½}Cì¢.ë¦}SʸeË5·„·%|.{¶;6vð 6vðöm™›»öW¯ßÈ©R“ž:5ÛkMï^m=²íiöÞV£´ÄcûnˆËý7V›lZXïÿVÖÝgö¿»ß½îvpÝ}n?2_ØM¢/íæyо¶[Bpä}$úÖ~,úÎ~"Úi·Š¾·ÛD»ìvQÇõTt†ë™hŠ«Ct¦ë¹hªëŇ5]¬Á³]/CN„ôúÚ’ãì«*Óëï­yÿ]ï\×ÓÞ÷{ÏmçvÜÞ/H¾²¤ÄžÑL2“ŒF¼ú)‘'yåŒìX™$JäDÉDŠlÉŽl9Š­É z/Dïè½7DQIô^½$:äûìáËwò‡ÿùì>ÏîÙ³gwŸmgï¹¼äùˆåoñTÁÅóú;\ö[ܽ؂¾Áùϸð?çÁIÜPÎB‚àü'Zm°\Ê%ð/ä0">LâCÁd> |ɇƒ)|˜ÊÿV ð/$‘ò\>X%§YX4x+ãbäl¬‰…3 㤠ߎ7§&Ÿ§)FOãO!/÷!¸ˆ§a¨˜O@J@ž{Å'Â_ ò\ŸDù|ñ‡’dèÊùdè*ø—ðW‚]ÌVTõ Q9þF> lâ³ÁfÇhœƒ¨ÿ)— M+Ÿ MŸ;Ès|>ü Ïuñðwƒ<÷š/„¿ä¹^¾þ7|1Øò\?_ÿÿ äKÁ!×Á?Â`ørøßòàÈc­„ä¹I¾ þ)ç¦ùjøß<÷ž¯†¯gù:p„¹ðõð/€0¾ÊN"i„j‰o„j™o‚„ÕðÍr6jjo…6ë|;¸òÜ&ßÿÈsÛ|'ü@žÛá»àÿb¼á»éF(y Ý.ÿº=¾:)× Í>ß Íÿ†bÕü¡¤ºC¾º#¾þc~<áÑÀNù!ðŒ?ó#à9? ~áß‚_ù1ð‚/ù ðŠŸ¯ù)ð†Ÿoùwàÿ¼çgÀoü,øÀÏü<ø\¶ÉÁ`ÙøB¶ †ÈVÀPÙ*&[Ãeë`„lŒ”m‚Q²-0Z¶ ÆÈ>€±²0NöŒ—}d»r^ø+Éž4ƒ²|h†dbyB5,+„jDVÿ¨¬| bø“•À?.{NÈJÁIY8šeåð¿aͲ øgd•ବ œ“U+È|rðTó²tú ²[µ×"xQV‹Ë–du,_õÐ,Ëê¡Y‘5À¿ òÜš¬þuç6dMâC5Cµ)k†jKÖÿ¶¬•%ÑÿYô;²vvíð’uÀ¿+ëdÕÜÿž¬ ú}Y7ü ÏÊ^‹EÑÕ‘¬ªcÙ¬ü w"{žÂBžpg²\šfÊz°gÙð‹¬ü*ë/dà¥l¼’­b”»–uÐè)ë¤ÑS6ý,ú{Ù0üßd#àƒl|”½UÐ`OË>y,ƒæ…| ‘O€¡òI0L>†Ë§Áù;Öøß#Ï‘ò÷Ès”|úhù,#Ÿcåó ÈÀxù"˜ _åË`’|×&ËWÁ— –pò5øSå†9î_K×Y²lùÿ¼Ûü· >å¶ÀgÜ6óÿ·ÃB?‚ÿ%÷‰ùw÷ÀÈí3ÿã!økÜó3ž€¿Ï2ÿ™âÇ|$GNó‘\y*¦ìyòt0_þY)©ü,”AÞ‹ä_ÁbùX"¿_ɯÀRù5X&¿Ëå·`…ü¬”߃Uòo`µü¬‘?‚µòçJ W'ëåÁ`ƒüØ(›ä¡`³< l‘‡ƒ­ò°M ¶Ë£Ày4Ø)»ä±`·<|-WÒ‚21QÉz Ædð¿â^*âz¨+U†å/å?qoHˆÒ'OAX?u°§!ŒÆš ÉSF#K*ÂFäihlIƒôVž‰F—tHãò H4¾d@š”gB¢&Ò´< 1YÞ˳!Ñ(“ iVž‰Æ™Hóò\H4ÒäBZ”çA¢±&Ò²<6ùVåh¼)€´./„D#N!¤M9ÍýhÌ¡¹ß¶ÜÊvÎäš"%ìT^ ~ynW^‚¢Û“¿÷å¥à¼ <”—ƒGò ðX^ žÈ«ÀSùK /ü ÷E® ¿0Bg_ƒ´¾ÊkÖ…¼VI6_Í¥¼š+y½’×ü߆ŸMÉ/„¿å¾É»âÄýI£’µ¿&D~7!ò£¼þçŠü‚kÅÓ)$²6Ü4XÑŽ Ú“Qt(Ÿr¡ ÚÛ St*i뤋’⺕ϸpÅkåý¯EòÇÆX¤¢Wù£Î0ZчTcýðÇ*À8Å ¯ …X‚bˆ¥:ÌR>Q1ŠøIŠ·`²b |©S`ªbLSLéŠi0CñÌT¼g­oþ,Å,˜­˜só`®bÌS,‚ùŠ%°@± *VÀ"-è‹´ /QЂþ•‚ô¥ ZЗ)hA_® }…bU,È5ÑYmɦDøw\µÂ½¡dÓæMQ¿…‚¬Ql¡¸kÛb~CvR§ØQÒÐð‘Bdü'1d! Š]„4*öÄköEç@ŒpˆºjRH䇈Ҭ8/>ÃNDçi´(N¡Uq†"mS|&ƒVœ“A+¾A+¾’A+.”Ûáï¸ÅÏ.•?Ç"F¢¸úî^³jÙBõ÷â žqoÛ§\øŒëWÜ€Š[pPq¨üSnˆeè7¬¸ÃýF÷H}÷x½U|Çà¸âœ`?©x®zÂM)‚ÀiE0øNñBÅq>.D%A· Î(ÂÀYE88§ˆç‘à‚" \TDƒKŠpY ®(âÀUE<¸¦H׉ª§Ü†"Iu¡þ_I²j[ñë/U?ç*$œD™‚Û¥ª¸48ÿX«Mg7ÏÿËTÑ$%KÅJ3›ä0æ‚y*­6_õ½‚i (€ ã UR …*ÃE4z-_¬bW‚OŠ„ì*^©˜‘”ây÷eྂý¢þC4ë'C*ócE%x¢¨OÕà™¢ü¬¨EÌsEü_õðU4À¡h„ÿRÑ^)šÁkE x£hE Ü*ФI*á9†f…¬ êE;ø¨èŸ+;%H')’ A“•Ú.”‘­ û»ûšH$TÙƒ SöâÂpåÜ9BÙ¤²þ(å­c”CH6V9¬ª• !Ɉ*Yù"‰—Ê·`ŠrLõc™ª¤ydšr\EF<àtåî“¡œTQ/7M¦r š,å´xÙ;ͤ߫~B¿.QͰ g-G9‹h¹Ê9Lóà?å ÏS.@Ÿ¯\¤çþ@²‰[r=v¡r‰Ýd™qq‹”+ˆ[¬\Åc”(×ÀWÊu°T¹–)7ÁråX¡Ü+•À*åX­üÖ(?µÊ]°N¹Ö+÷ÁåjX%„aÜUþñ¡ŠíjáŽ-Ê#ܱUI;Hè…ÙR;ÜczXî„ñÏÚÝ)bv*Ï uA:ƒÔ­ü é5¤Ïz”çìI¾Ëþ[ÉW„õ"ì+ÂÞ(/ ¡G–^@êW^B€t iPyŪùšñ!C¹AȰò–éîï2‚{„Œ*¿AB_-}`÷|d|.`¤†î¹€‘Z$.˜ñBÐK_ dRÂt¡ŒaA¯. CÈ´2œé"#‚>^‰÷Ê(¦‹fŒAz|i Bf•±LÇôÿÒx„Ì+˜.‘1 ! ¤IYT&3ÝKÆ„`l¦ dY™ÊtiŒéÁH!MGȪ2ƒé2³²†,„¬+³™.‡1!ÉEȦ2O 3Í·•àe!¸£,?*‹ÁOÊpWù ÜS–‚ûÊ2ð@Y*+À#e%x¬¬O”Õੲ6ÙB"B&"=WgiÄ aAêl«sÞ u!í'ª³éЈ:š0uâ„«óáP€‘êB0J]}´ºþu «~Æ©KÁxu˜ ¦=ÊD5íZ&©Ë¡IVÓÞåK5ío¦¨—àOUW@Ÿ¦^?]] †º ÌTWƒYê5è³Õ5ðç¨kÁ\u˜§®×P¿ß¨ÁBuX¤n‹Õ-`‰º|¥nKÕí`™º,Ww‚ê.°RÝ V©_ƒÕê°FÝ Öªß€uê>°^Ý6¨ÀFõ ؤ³7«‡Áõ4­êQ°MýlWêq°S=v©'5 j!üZ=…’ÿß¹iTb¯Z"™FÑ¿Q¿Ó<áúÔïµ_=¨gÁAõ8¤žGè°zþõ¢fR#d`8W+–ÐÿÁ-#¡q$´Œ„&Ô+ˆ:©^§Ôk¸`ZýtQ#daå¯þuj¨Üò<¯Þ@ìõ&ÓlA³¨Þ‚fI½Í4 YV€fE½Ã4É”ÔɔԟÄ¿ ÕºzWC}垨ڇjS½Õ–ú€]wͶúPCåÓC³£>†æ£ú„iN¡ù¤>…fW}Æ4Ÿ¡ÙS†f_}Žg9PÕ_Á#Ôêîµú„;A­>áNQ«ÆQWÆÕxêsõ%øE}¥A‡¥–\CºTßhž ¹É­æV­ºÃ}þŒ»×ÐVõ7„Þ©À{õ#JóÆÑGÜûAý\ûº ÷\ËsÏ5AÚd™Ñü½`-3±ZÖS‡ˆR(œŸqaZê µlå%Dj¥\Ès¡ú=¬ÅÄÓ©‚0 *×DCõçl×3BS}¤&šÿ“‹ÿ‚‹£ ”|<ÒˆÒÄ#hM‚¨J„*F“U¬&‰TZ>ª8M2Tñš—¢*ªM T‰šTí.ICGÉš4-ìP“¦h2ÀTM&ž6,qÓ5y˜e0KÃÌL“¥ Ò …I–,GógÙHùp9Œ¹ŒyŒùŒŒ…ŒEŒÅŒ%Œ¯X!•jéí@c9cc%cc5c c­öÇή†vþó4´óŸ¯©ÃhêÁBMƒøÀx˜"MX¬iK4-à+M+XªiË4í`¹¦¬Ðt‚•š.°JÓ Vk^ƒ5š°VÓ ÖiÞ€õš>°AÓ6jÀ&Í Ø¬[4Ã`«flÓŒ‚íš·`‡f ìÔŒƒ]š °[3 ¾ÖL=ši°Wó|£yöifÀ~Í,8 ™5óàfÖ,‚#š%pT³Œ £g6¦YD]Î ¤ Í*¤IH«¦4k¦!­Az§Y‡D}Í:¤Í$êm6 Íi6!ÍÓøiA³i‘ÆIHKšmHË4^BZÑ|€´Jã&¤5ͤuH;64ô:bS#¾ŽØÒPµMù¤n@ó1w }DÌšO>AúiW³ iÒ.¤}ͤH{5ûŽ íC:Ö@:téTs¨å…b‰¤BúEÃN¹|ÕQƒ-¡{¥ù³cÖôNOÏ?3ž3~aüÊxÁxÉxÅì5k†7Œ·ŒwŒ÷ŒßŸë~4ØkÖ`oXƒ½Õéžpwš`ð^óBÇlˆN‚>(|Єé¨ï ×QŸi#Á`møB †hcÀPm,¦õñ`„6ŒÔ&‚QÚ$0Z› Æh_‚±Ú0N› ÆkÓÀm:˜¨Í“´™`²6 |©ÍS´9`ª6LÓæéÚ|0C[ £¢ÌÒÙÚb0G[æj_yÚR0_[hËÁBmX¤­Ôý„Îæ¦Ãì[[除Rm5¤22?HåÚHd†*µµªÈ!Ukë ÕYBªÕÖCª#ó„T¯m€Ô@f ©QÛ‰:‚FHÍÚ&HÔ4AjÕ6C¢Î R»–,uÔ`;µÔ`©C Û­¥K]5Ø-5Xê¨Á¾ÑRƒ¥nl¿–,u Ô`µÔ`©k ;¬¥K5ØQm‹îgB)–ãZ¾MaBÛ†ò™Ô¶ƒSÚ/”ScFO@yVÛ©ëÒ •I·nAû;¯Ñjþ1×££a¦W'. ©µq}Œý:¶a0 £ÝA 熇Ù#ºgÜ¢vT÷Ë#ñKìLü²ö­îû wJcL'ž‡™kéœüªv5G§ãרAùu턎mdA³¡¥ƒò›ÚI$½¥Ò=E1ÿí4žmGûü¨}~Ò΀»ÚYpO;îkçÁížüP»i—Àcí2x¢]Oµ«à™v ü¬]ϵàí&øU»^héäÛ¥–N¾]i·‘æµöô7ÚðVû‘=ü'øï´»à½v¬N»OV§= «Ó’ÕéŽÈêtÇduº]§N¨†µé§H 3'¤¦£ôÃug`„î3©;£t¾)j$’dU¬î§/b~ Û[º+ѹÃnD'Sûs úEžúçö%ìÕaœîV ìR<ãâuw¬†ïuÑu÷h·‰ºo::Ëù€¶ ‹W?@—¬{/y®Çb[÷\Ŷ.H/žŽÑæu/D!áiº„§ërÕ¿Ç¡#PÓÞJ¦.TŒ†Yº0DÈÖ…‹ª¨rtPåê"õ†uQ`¾.,ÐÅ€…ºX°HG“Œb]nX¢‹_éÀR]"X¦KËuÉ`…:„=u©zêÒôdøéz2ø =z¦ž < )7è²ÁF]ؤËÕ“ç-º|°UW¶é Áv]Ø¡+;u%`—îØ­+Õ?å^ëÊô.ÔaØÕ©Êéá°t€)£Ú+ðtýºJ¤? «uÕàŽ6‘†u5¸vD÷/ËôBƒDR«ÓyêôÌàêáü•V{†Z×µ+Ÿrº”Ö¤®‘¸&ø§tMH{Z׬'Ói‹´ït­x[<ãftmzj«ô†rV'ÕHé圮y˜×u€ ºNpQ×.éºñD˺×àŠ®\Õõ‚kº7ຮÜÐõ#æ¦n9ßÒýU£Zh’HZÔ;:ç Ë}Âê_qÃzÚÑÿx™ôQG/“>éFõ?q°í[–«1H{:©N:† ïëÆ¡ü—Ü”¤œ€òPG+È#Ý$n}¬›ÂÓè¦á?Õ½ÏtïÁϺð\7«§õìã<4_t àWÝ"x¡Û—`¾ÝBCøµî7–ô4¬.ëi¾Âü«z:[²þ_ܺžÎ‡lèé¬È¦þÇÐ{££¡÷VGCïŽN‰Üë¶PßtÛàƒîîó¨ÛŸë?‚AúO`°~|¡ßCôû`¨þ Ó‚áú#Üà/9:¡OcDêé4F”^<­§Ñ$F/Ž&±z:A†@§1âõÇ(,2…c”U¢~^€åB¢]ðd=Ž s Ó)z:AA+ƒ4ý‰¥ÑF¥‘©8ýÕ3féé³õgx¢ýgÄÏÕŸƒyú/`¾þ+¥§¿ õ—`‘þ ,Ö_“iêoÈ4õ·dšú;ý/Oà–}¿k¹þï¾ïýöê-÷¨Ê*ý7°ä¹ýüµ ÏÕéá¯y®AÿÜ åA­>þfG{†¿ä¹6ý øÛAžëЇÀß ò\—>þn}˜3d}8Ø£0àÁ;éÁûõ¿i ª2P3ˆfþ5ƒX5ƒ8ÍÕâÁÃ%èiÁÍ%¨a$ƒý4ü(ºVtƒúRq©Œi6¢R[Ò§°ðÖSW6¢Ï€TŸ‰,½Õgcúlp\ŸNèsÁI}8¥Ï§õà;}!ø^_Îè‹ÁY} 8§ÎëKÁ}nùoY{ZüÞž–X{ZþÞžVX{ZýÞžÖX{ZÿÞž6X{ÚüÞž¶ôåLµ©sEa~ÐW@¢Ö]飾µïJH»ú*HÔ« í³–wð½åê«vD]1ÂŽY;<ùÞ"Nõ5^Ó SÕsµT1¯©b.õÿq&ËõŒ ¬z›À_çš™¾…±õWpÅ*àZOöy£O£ ²¾ å|§oGÉÜë;ÀoúNðAß>ê»Áç†×`¡ 6ô‚/ oÀCjèà `¸aŒ0 ±¶0Œ§Š„<Œ§Š2Œ@І4)Æ0 )Ò(¤8Ã[HñTÓ c©Æ!%Æ!%SÍCzi˜€”B-RªJ*Í –Tºá×5B/¦É†ßœ4°nu δ{çßqï lKƒJ¶!ÃnŽa†4—ÿ½diåfay†9¤–o˜G™ ôë¢EðO¹%j¦Ü2ã ã*ãâÖÁ"ÃXlØÄµ%†-ÃSî•ašRÃhÊ ;`¹á£Zí¨ThG¥Ê@;*ÕÚQ©1|Bh­a¬3ÐîJ½aW5öYNào4‚M†#°ÙpŒ˜-†ø[ Óšg\›aÚÀ }… êS\óÿpô¤†3výgÄî2œƒÝ†/dð†¯6”^ˆÎ%™¿á ì5ü-/ `ql‡‰çucÄ §kö³$ 7à áßó U±êÖ@¯ñîï¿1>0>2>7ƒƒ+ ±pü¿E¢OPã7à¸á†aà …MB À¼ B(®ý÷\˜‘å&\t"D'Òø=‹OP×”Ú KmÖeD`ˆFo%¨NùÿÿjŠ¿Äb.³«V 1ÆX£0%¹AgÄnˆ7>á¶ àC"¸cH?’ÁO†—à®!Ü3¤‚û†4ðÀ2pó#C&üdžR)/LaL6üv–‘MH³Ôæ0æé×!yFv"ØH¿—+0Ò\³ÐÈÚr‹TÌXb¤ÃНŒRTi–RÊJÙeeÐ|1”yî«¡÷½0T™íWÂ)ÁhÂ’­F¬KC xe¨¯ tˆöÆP‡+n õࡼ74‚ß Màƒ¡|4´€Ï­`± 6¶ƒ/Œ`ˆ± 5vaÆn0ÜøŒ0ö€‘Æ^0ÊøŒ6ö1Æ~0Ö8ÆÁxã˜`#`’qL6¾_ÇÀã8˜jœÓŒ“`ºq Ì0Nƒ™Æw`–ñ½qÆ(¼“Hf¹FÙœ‘©Á£æçTºðÀF%/ÌÀbŠ)vü£•~–Ì- ²™£%ÆE¤õʸ–ë%Ja¶kT,#¡Jã2ª2®À_ bt6®Â_ bt6®ÑUÏQWÝh|.Y7R?¼Á¸É¸Å¸mdgvw?2~bÜeÜcÜ7Rß~À®:d" Ûø<‹1ì1ƒ½ÆàcØg ûaà€14F€CÆHpØŽ£ÁQc øÖ ŽãÀqc<8aL'‰à”1 œ6&ƒïŒ/Á÷ÆpƘ ÎÓÀ9c:8oÌŒ™à¢1 \2fƒËÆpŘ ®óÀ5c>¸n,7Œ…঱Ü2ƒÛÆðƒñ¸c,?ËÀOÆrp×Xî+Á}cx`¬5ô±p®6£¼‘\ŒòÆ:H'ê ë!Aª‡ôÙØéR¤/ÆFH_!5Bº06Aº„ÔéÊØ éR3¤c ¤[H-¨¶Z!}3¶Az€ÔéÑØ‰ªªRP@$ª¬H/:!QuuB è‚DÖ)< UY7¤È€×¨Ò^CŠèDÕÖ)6 U\/¤ø€7¨êÞ@J èƒD•×)9€Fqª>ÅSú‚´Â™NzÀÿ6@íuqˆq˜q„q”ñ-ãã8ããdYÎã4ã;Æ÷Œ3Œ³ŒsŒó?l #€l 3€l +`!óý€E0'`)€m!.#»¹+`^À*˜°¬ƒ…`QÀ&X°–lƒ¯>€¥;`YÀG°<àX° VìUû`uÀGÀa5–£j$ÇÔ8N¨QœPc8  Fð9€*ÿ<€*ýKUöתä V¹—¬R¯Xe^³J¼a•wË*íŽUÖ=«¤o¬rX¥<’•<7ýÄ À÷ÜÄ£‚ A ‚4 iR0¤Ñ€ÞBzi, Ò8¤H¡&!…Bš ƒ4 ) Ò»€pHï!…Cš ˆ€4 )Ò\@$¤yH‘hB¾ NÈ—h»j€¶ Wh»ê€¶ ×h»j¶ 7h»ê¶ ·h»j‚¶ ?Ðv!Õm~  íBª Ú.Ü ˆ2ýLX‚ðkÑ&)w0Ü€Xä õ ‰ƒ{Ê\ž;  Ÿª~ ŸªžÄ#u!‰GÈ×€\{òÜeýpõ*€~¸z@?\½  ®ÞÐWï臫÷ôÃÕoôÃÕ‡€D\ûò¨ú‘j‰~¤lJ‚þÈ£”éÇ­¡&‰dnsa¨&ú¹l„‰~.iJF~¢’ŒøÑ&úájŒ‰¶ïbM´}gziÂØkJ1aÚ³‚qÖ¤¦INŠ)Õô”K5Ñ$'ÍDÓ›tM„2L4ÉÉ4Ñt(Ë”f‚m˜h:”cJ‡?×”aÚ”«I¦©À$Ë2Ñ^G6r[hÊÆÝ‹L9ˆTlÊ“f˜„u‰4×ÔÅ—š~3ÏDƒP¾‰&1de¸–4…¸°ÜTdb†Y ¡ÂTŒT*Mô‰*}G¢ÚDŸ¨¨1Ñ7*jM%&ê_‰ÐgêL¥B`q¢®—×›èc &úØB£‰>³Ðd¢Ÿì7›è'û-&úÉ~«‰~²ßf¢Ÿì·›èÇú&ú±~§‰~¬ßeªÀct›*Áצ*°ÇTBì5ÕÐm)÷ÆTMŸ©ì75€¦FTÄ IªÀmynÈÔ„65£4„M‰¤ÅôÖ¤jÅõa­¶ 1ÇL}"Ž›ÚMßObýÄM˜$:‹5iêÀm§LHcÚÔe:“ Ûi·éµiÆôÏ_ËŸq³¦>pÎD¿‚˜7õˆßk¢EËÆ>›Xö‹!&vªwù\0 Aøk­v™X4IŒÃÈÄ’iµlãÑÙ±“xvl3"þšI0†øë&š™n˜ÆÅ  mš$¦ m™&MìàÖ”Û&‰y ʦiÓ÷Ce0K“ÄBÇÊ>šÞ™¾+ƒuš$VÚÜ5½7}?X†µIb££eûxìetð½ŒMÔ˜ŽL³bü2”DZ‰~’xbšU]NM²ÿ•;3IìôKûÏ&Ú~87Í£ ¾˜†O¸¯¦ø/L( îÒD¿b¼2Ñï¯MtèäÆD‡NnMtÔêÎDG­îMt`웉Œ=˜èÈ£‰N.=7ÓÉ¥ 3Î 6Óéœf:Cb¦34¡f:Ðf¦]áf: a¦ÓP‘f:ûe¦³/Ñf:3c¦3c±f:xg¦ƒñf:‘`¦‰f:¨‘d¦ƒÉf:ñÒL2RÌt#ÕL‡0ÒÌt8#ÝL‡32Ìtð"ÓL/²Ìtä"ÛLG.rÌtä"×L‡-òÌtØ"ßLgw Ìt„¥ÐLGXŠÌt„¥Ø¼„’)1/ƒ¯Ìh\©yFRfÞËÍ«ÐT˜×Pàá˜Z¡Uš×QáUæ Ó¯ ;t> Ö¬Û4±i1ã6!aÇêÌpu½ ‚k0Í´!Ðd7šÍ´!Ðb7ZÍtœ Í,'h72ÕÊ„]ŒwfÏ®éÇ¡õ×f:´Þc¦Cë½fñÐú3Iÿ‰ë3‹GÓûÍt4}À,M4ïQãB#ÃÝ>f:’>b¤šh „t@c ™¨›ÅêæC!Òh¦£çÓ¾!ìùˆÆ@HG4ši „tLc ùÏ;o>%“4Ÿ™>™„‰ä³iŬ97ÑË&:,½ŠÈ_Èì˜ ³3Óáä óWÓïr›”9¸[”¸Ûp¯Øó5¸c¾?šÿÍ/„# ‰æÀ[$zgBó¥ÃŠ)Vfú|Ëù©TŠ Í¸Ë‘ùÑĶ ž›¥Ü±ù¹™çNÌAfÄâÁPšƒ¡:3¿0³%vTŸÍ!P›CEUT_ÌaP}5‡‹ª¨.ÌP]š#EUTWæ(¨®ÍѤRð1Pݘc º5ÇŠª8¨îÌqPÝ›ãÍO¸oæ= /œ`bùƒDI4Ã8.Š ‚%ûÒLy©Õ¦ˆbêw1ͬ H颓Á™fÖKf™Ùó.bT µ,ÒÇ,Ù¢*¥n‰E©DXrÄs‘¡HK.2eÉUùPE[ò¡Š±ˆ)Bk)„*ÎRD*3¿&~¢X¼¦â-%ˆ`yÅ —/…*ÑR U’¥ í<ÙR¾´T€)–J0ÕR¦YªÁtK ˜a©3-u`–¥̶4€9–F0×B¶”gió-dI–V°ÐBvTdi‹-`‰¥|eéK-Ý`™å5Xné+,°%®ÒKâª,°#®ÚÒÖX`E\­e¬³Àz¸zË0Ø`íp–Q°ÉËáš-c`‹võZ&À6 ¬†k·LØ ×iyvY`1\·eÆŒËY‹~Öü”ë·Ì¡ö,4{´ÐœdÈB³—a Í^F,4cµÐæ­e1Ç,´u3n¡íš Ë4“–Epʲ„ä§-Ëæ³pŽE¤EFIγ$X’‹–D\²$J"dÂZ¬¬Z~cÕL/EÖÌ4sYgÜ0Ó>è&ã–ùÇòbÍBË‹u ’Û°|7-;à–å#¸mù~°ì‚;–=ð£eüd9w-‡àžåÜ·ƒ–ðÐr YÎÀcËgðÄržZ¾€g–¯àgË…™þÁ›{‰.èÜB.Ö—–nH_-t<ëKK¤K ™ÇúÒr©ÄúÒ¥ëKˤ[HWî,´n»·ˆë¶o–Ks²L¸ ¢xnu\±G¾f¼1Ók€Û_=~•?ØJ««Ö;dˆõž‚a¹ÄhB­4 ‡Y‘ípësÜ%ÂFZƒ-µ†sZ+¹­!b¬dñ­¡â …BŠ·R6¬b6­aÔØeó¥Un¡·–YKaYKµFâViÖ(0ÝàÚïÿ‰Ë°Šûþ™,Ѭï‰f[c,?n0ßWçYùXË/ÏÖç[ÅùQ5Îcî$’uE©Õÿ&Ž Ãµ…Þ$ý*e,åÖdÜ»Âú¬´¦€UÖT°ÚšFnýýŒ™‘ÕZÅCduV ë­âhØ`¥N£U\á4Y=já ͪ¤[S'‰ú )×fÍÂ]Ú­Ù`‡5ì´æR“°æYò-Â#VVu…Íá -tô¼ÈBãc1âôZKÀ7ÖW`Ÿµì·–ÖrpÐJ/ô‡¬,òƒ¤¨…QëTZhÔ¯b¬f¬a¬e¬c¬gl`l´Ðr½‰±ÙB›X-ÌßÊØö«²|ËÊrÌÚn™³æ6aí@.&­à”µ œ¶vƒï¬¯Á÷ÖpÆÚ ÎZ߀sÖ>pÞÚ.XÀEë ¸d—­ÃàŠu\µŽ‚kÖ·àºu Ü°Žƒ›Ö pË: n[§ÀÖipÇúüh}~²Î€»ÖYpÏ:î[çÁëxh]¬Kà±u<±®€§ÖUð̺~¶®£ÍŸ£v×Ñæ¿X7 }µRï“¶nBº´R/“¶nAº¶Ro“¶nCºµR¯“¶~€to¥Þ&mÝô`¥^ˆç­!=·Qo„Y¬í¤`õJ˜ÇÚhb×Ù¡6Zg‡ÙÄuv¸í/8¹d×kã÷д¢l{d°¶}øcl’_!RÉ%Ñö÷QI ¶# ½©8Ûâ‰X•§¢sfa#ñg -^οXØHúUŒpçÒÂ~â’d»u‰šg\²íZnpÓ—6êÀRlw6zßC•j»GžÒlßÄXP¥Û Ê°=Z~|é&ÓF_ºÉ²=·bÅk£·39¶ øsmÔSåÙ‚QPù¶`-,´…‚E¶0°Ø–Ø"ÀW¶H°ÔFW™-,·Q×Ua‹+mÔqUÙâÁj[«äQ"„I¹zÛo&XéSK‰VöÙ¡$+}Ä#|iEŸÅÞ¦ZYæÓ¬ß3ü”k°ÑR§Ñ–n¥ž!C ÐI¹&¶eZÅOÀ~lYVñgÙÖ_þl¢ÕF?›h³åˆæZù³‰výl¢Ã–gýñ³‰Nýl¢Ë–o¥/Aˆ…V)×m+´òÜk[ ªÇV ö²âzc+¿Åò„ë·½ÂÃØJÁA#ú[üörpÄVŽÚ*­ë#¥Ü¤MQe}ÊMÙh0ž¶Ñ`üÎFãû{[5.±Õ€³¶Zk¥Uˆ’rK6)M –Yô[uÆ(DK%³Æu›ºÞÊ&¬4£Ü°ÑŒrÓÖ ªhF¹e£å¶­*½ŒoÂÓ|°5áivlôv࣭ÙÊ ±RîÄÆµÀ‡)®MÛÊʺ qÏmmˆûÅÖN—£•r_mÐ\Ø:¡I¡ÎTÊ]Úº º²uSéGü‰ä5t×¶×ÐÝØ:ÕB‚Tòš¿·ñ=ÖŸâûf£Oñ=ØJ¤œ\F'’Uçò(»Ð‹KƒìoÀ`6iïƒ?ÄÞ†‚˜±ÚP’áöA0Â>FÚ‡­?’¥’k¬Ý7Š›ü57ŒélœVüñvZñ'ØßZ¿¯ø1õ´Óx–d§WOÉvú®ÎKû˜õÇ—nRìô¥›Tû8T‡¾VÊ¥Ù'pçtû$+…)¤—a§Õ~¦}ÊúËC7Yv‰†ÎÜdÛi…c§Õv®}šF1û;2*û{2*û •}–ŒÊ>GFeŸ'£²ïb²Ÿ"åÊì¿¿€4—¬è–)éÖ`W­ôÉÚŠ(·Ów5*ìkVÖ¬#w•öuä®Ê¾!ï&TÕöM¨jì[VÖ=lCUkÿ@Xø'’HuöD¨·ĽìŸÀFû.Ødß›íû`‹ýlµ‚mö#°Ý~ vØOÀNû)Øe?»íŸÁ×vê¹{ì_À^;õÛoì`Ÿzí~ûÙ‡úìAû 8d§{Ø~Göa§þzÔþ |k§ÞzÌþŽÛ©¯ž°“vê©§ì/Ài;õÓïì¡à{;õÒ3vš_ÏÚÃ៳G€óöHpÁ.Ú£Á%{ ¸lWìqàª=\³'€ëvš›oØáß´'[ödpÛþü`Owì©4vØÓh̰/ZÝBº”Û³KÓmb,ïÛ ¥˜CfдàÈþ[6šNgÚh"Řm£ùdc®íÇ0l§aþÄNü©=Ïö„;³çã6Ÿí๽üb/¿Ú‹Á { xi^ÙKÁk{xc/oíོ·WßìÕàƒ½|´×‚Ïu`£ v4€/`ˆ£ u4ƒaŽ0ÜÑ F8ÚÀHG»íÇô;Ê!N¿£4ýŽqˆÓïXM¿ãâô;ÞAÓï‡8ýNtÐô;É!N¿“쵉ãûkG‡Í)daàr8:q?:cb7¨ýá _?d:^C¥ùo$=6)—åè±Áî½6¶Þ¤ÍémNç:Þˆ*Ú£ÎsÐu¾£OTÑVuƒ¶ª ý¢Šv¬‹´c]ì ²–8臬¯xèRÇ XæÈ–æI…ØœC=„«†mèÙÅ_6ŠÎ[ä§Ê1†¸ÕŽq°Æ1Ö:&QuŽ)øëÓ6ŒjŽ$é¦DÈ“r-Žÿîíç\¢”“8ÞÛÄ3œ3pÿî,Ü` ¸º¡Ùq½/ìqüXè|tÑBç“«*½…#†ô‰N¿ƒõ›fnƒ¨›]—T'DZ{®!”Ⱦk˜åa„q(Â("ºÞ"‘kÌñã7Ç.úÄ͉kåwêšÏ\“ˆôÙ5ÿ¹kü‚’~Â}E©?á.\ïhÎëzOs]× xíšo\sà­k¼s-€÷®Eð›k |p-ƒ®ð¹{ r¯Áîuð…{ qo‚¡î-0̽ †»? Ò"Ü;Ž‡Ð å¢ÝO?ŠOÿI|€]ÑÙs°/B †bÜûTò,9kåë>ģǹXÉCï>†&Á}ÂâlZŸq‰îS<[’û Lv_ºÏÁ÷²s÷WøÓÜô]µt÷ünêS2ÝT.YîK²s÷Ù¹ûšìÜ}Cvî¾%;wß‘»ïÉÎÝß )r?€ÅîG<[‰;Vºãš¤’dU™[úÜù„+w9Ÿrî`çThÆÐëÖŒ¢Ö¸_8Ù£‡81öºCœ{Ý¡NñÇIbH¸“Š!‚1Ò)¾¤h¤[ïŽq;…V)×äÖŲHqŒñŒ Œ‰ŒIŒÉŒ/SiÊÕì¦éW‹›þƒ¥ÕŠ„ÛÜiN^h“J*¤]nö#½n÷_¢ÂÚé¡zÝÿ$ÝÉ>ƒçdí5ÓI¿oÉóídGlst¸‚›ÄOé=+Pþ‘D‘ç|ƽq O¹>ð×ï¦zpç‹I 4Ý(!w¡¨*‚jØ]Õˆ»XT•@5ê.ê­û•¨*…jÌ] Õ¸» ªLt®¢SÁòSéü‰›pÃn*eÒ]…¹Ù”»ÊiRVCùÎ]ƒ§ï®gÜu଻œs7€óîF\²àn‚ÑÝ ÿ’»þew+¸ânƒfÕi·æ^F{ØtÏ€[¬]m»1ßá>¸;ÁwøÑÝ ~r¿wÝ=àž»Üw¿Ü}à¡»÷,BäY‚?س ¾ð¬ !‡xV)tJ¹pϯ—Ä^¥-çk¿¬Ãg\„‡ª5ÒS”§Œö”‚1žNÇ3.ÖÓ ÆyÖô§ÙÜê.Þ³:Hð`ŠÄ%z¶œ¬/Þ†*ɳ U²ç²óÒ³¦x>‚©žO`šgL÷ì*òLÏ>2›å9³=‡`ŽçÌõƒyž9ÄÌ÷œ€žS°Ðsy>ƒÅžsÄ)ñ|_y¾‚¥ž °Ìs‰G/÷üÛU§Ð-•œË«<¿]‡þú&k^×b†o˜pëdÃwpdZí=9˜õˆ{Âx¢jÏž¨Æóèßë»ÄјàÔzh²Tç r± ØÅ>ˆGGS³zMÍyª ÙõTƒ{žpßS xêÀCO=xäi=à‰§ÉÅ~’…éÄ©GüéÓ™‡–ŒŸ=â’ñÜC'-¿xÄ“–_=ôÓ§ øÓ§KÏĢ®<4ñç¹k½O¼ñˆïo=4[¼óˆï\ï=4ûæ'pžfW§Nè“rA^[msl±Í±µ6û…o°·Å…Õu?&Õ^L 1( H¹¯ºÍECB;cc'cc·ë—F¤—Œ(/ ÑÞ×(¬¯@ëc¯¤ÏïíE• I%o\É^E]&Sô»¤ÜKo¿ ëdï"¥zÁ4ï˜îvõº„)—啎 ¹lï(˜ãý׿F±fözߺؠ7&:ãb}NˆÎ¤èL‰Î4îPàÆÝ ½ïDÕ{¨Š¼ï¡*öΈªY¨J¼³P½òιèÐd•á÷¸R¯ägU)Wæ'óŠùSÉâ•{1åä*¼‹ÈR¥w ù­ò.ƒÕÞš3{WÁZïXç]ë½`ƒ3H®Ñ»åz*ŒI¹¯lÛEßdùm«—œò~?8åMòš )×ååw\ì0ÌGñ9?¹¨ÞvQ˜ÓR®ÇëÙc5P ¤ùü¾‹†à½‡ÌÄBOO]â‡hÏćþÌ”çà¦~ì.6@^2s¸ã]#‹½Þð÷ìóÞýÞ{pÀûLßû@¦ï}‡½ÏÝXh{ƒÀQo0øÖûó†¸Q©ï1Û÷ÊBÝXg{ÃÜ”pÆÆßÇêw–V¿]ü´÷¯"ÝìþQ¢M1E 9jE,œ]æ|l~ØVc¨`Bc2]Љžø—FLHeLU颓!^™É‚²D]¶›u¸9núÑN®›l%ÏÍÞwæ‹N¯ÐM¯L‹D¡ØÍe%n¶({çâJÝ?qï¼’_+uóÜ{oŠbÆ[Îz+XB|¥[ÊÍy+<ï­ïZ Õ‚·ªEo â.ykÁeo¸â­W½ àš·\÷6¡<7¼Íষš-/±ÝöÒÛ^:c»ã¥3¶½tÆö“—ÎØîzéŒíž—ÎØî{éŒí—ÎØzéŒí‘·é{Û“o;ü§ÞðÌÛ ~öbÈ{»Á/Þ×àWoxáíE.½ÔI^yßÀíío¼ýà­w¼ó‚÷Þ!Äÿæ¼#à£w|î{ ùÆÀ`ß8øÂ7†ø&ÁPßæ›Ã}ïÀß{±ègÜlKsÖÍFÐ97›‹Î‹Ò‚(-"~¤o Œò-ƒÑ¾0Æ· ÆúÖÀ8ß:ïÛ|›`¢o LòmƒÉ>Z5¿ôI9-›S|´lN%‘ÖÍi¾î§\º/ZÂkæÑuù¦è”¦wì€ÇG7›|]7zÃ9ûn2ìu¶ï•žã;Äír}t–,ÏGgÉò}t‚«ÀGg´ }tj«ÈG縊}t«ÄwäŽ ‹Rö•¾xì¦6'nôNÝ4$žM4;¤€s°•¦‡L÷•é.Àš 2Ý•›FÍk°™¦ˆLwËtwîƒg•Ïjß=ê³Æ÷ ¬õ= ãu¾G°Þ÷CPƒ/lôƒM¾`³/lñ…‚­¾0°Í¶û"À_$Øé‹»|Ñ`·/|í‹{|q`¿ï?´ÿïá¸6Tç'nÀG.Ï úh¼ò‰ãí°ÆÛŸ8ÞŽúó-¤DÄóÑñqŸ„Ÿð%!lR¦|ɦ!%Czç{ é=¥ iÆ—i–Ò„4çK…4)Ò‚Î-úÄ3AK¾4„-CJCØŠ/Ò*¤tHk¾ Hë2 møh ßô‰cø–/ÓƒzYÊíø0u +Rn×'Ëö°/ƒí˜0™Ÿp{>ú{«}_¿¤_&¬J¹#7%™”kRîÔçÏõ°šËó°Iý±Ô™/ßó„ûì+Ï}…à_øÕW ^øJÀKß+ðÊW ^ûÊPü7¾rðÖWÞù*Á{_øÍW >øjÀG_-øÜ_ùëqm°¿|áoCüM`¨¿ ó·€áþV0ÂßFúÛÁ(®öw‚1þ.Ú÷&MõâýÿE·‡Î!½fìñPãíõüh” ~j”‰þ7¸.Éß&ûûi¶å Y–æSþ!šcù‡Átÿ˜á3ýoÁ,ÿ˜ísü`®ÌóOùþi°Àÿ,ô¿‹ü3`±,ñϯüó`©,ó/‚åþ%°Â¿ VúWÀ*ÿ*Xí_£yš¬õo€uþM°Þ¿EÆãß&ãñ ãñïñø?’ñø?‘ñøwÉxü{d<þ}2ÿÿŒÇDÆã?&ãñŸñøiÖÙë?ßøiÎÙç?'sòÓŒsÀÿôÓ|sÈé¡·¼Wh‘Ã~ôh‘#þkH£®!½õß@ƒtiÜO­uÂ/¶ÖIÿ-ÕÖ6ÕÖ;à«¡{ûÞ7} à¥þÈøÜû£êÞ³ª›ña&4ëçü/Ày¸àýaà’?\öG€+þHpÕ®ù£Áu í¡ÏüÄmøÅÏlúgm?q[fm<·íõþÄ}€ëå¹?½éýèßô~òÓ›Þ]¿ø¦w=Ûþ÷g;ðÇy/”ÂŽ”;öÿÎ ‹ø·!ßÝx/ûS€/†L¢—½ cLf|ɘâ¥ÉY*ó§yÙ˜•ÎTÞïÿòðŒ;õÓ¿'œùOÁÏþL/¬ÓŸåeeÎþ^\¸ÇòþÕŸëeÓˆ<¨.üyP]úó½âÌCÊ]ùiÞqí/@¹Üø Á[¼óƒ÷þð›ÿøà§QûÑ_ ÿóÀ20(°ñƒ+À•`H`X †Ö€áµ`D`âGÖÃØF6BØl`3ØÆ¶‚ 4ÛM l“;ÀäÀNðe`˜Ø ¦¾Ó{ÀôÀ^ïS.#°Lç>a˜ 4¼:'°ÔýŒË ìíòûÁüÀ°Ç2>p, ¤”(‚¿™}½£<áJñO¸²@zèòÀa¤V8‚›TŽz]ÂVãü[/ àcŒÔ³ÖŽ{'¼Â¾”k ˜ôÒè3Å8ÍøŽ*BÎÓAýÆ@:¨ßøÞûãT~s Êo œaqgÑüZ%’YÔW[àtš…gúW¶ö@úW¶ŽÀyd©3pì \ôŽ{…C:8Õ(¡óO½K^^8–Jºuýêe/í'¬0®2®1®‹z¬;>!5HŸ ¤OK Òg¦F7¼°Õ²Õ±À°ùÿÑõ¦Qq,Yž§Þ{ñž²NVVVVfv•DìûAADÐõzfº«k¦—YzºgïÓÓs:Ïôœ93sú;û¾ˆE «Ø›Ø»„ !ЂÄ"ľ Ä2ÿk†PÏÔÉ/?÷kîáánn×üšÙµkÅæ0¾ÿ+6=ú¯H{çç¿©êã RÕ‘ ÜÞ“ Ep4è#ø4h  úŽ-ƒA+¤ÎA«¤ÎAk¤ÎAë¤ÎA¤ÎA›¤ÎA[¤ÎAÛ¤ÎA;¤ÎA»¤ÎA{¤ÎAûàÛ ÏàlÐø.è|ôüt΃óA'àBÐ)¸~IzÈ–üYøD[±° éSÙ–ba9( ÒJÙ˜ba5(ÒZÙšba=ˆÔ~#ˆ«ýfPÌ%ñOÂN¬O±d“ºB?±®Ðƒ Û¢¦%[ÂQ2îéuü% qIGŽƒªÑ€< J@Š_ Õ·Nƒh%®piâ%æd™t‰ZlTAEH+qj¤4ùÒ¹GF”4åkk¤^bElÍhin/Fz¶A¬4Œ“f€ñÒL0Aš&J©Ã+IzûÉRêöJ‘fc?Uz L“æm$½NvôY8Ò\²l¤ydÑHóÉ’‘Þ$ FZ@¶Š´liÙ&ÒbdÄ4š…½Ý¡Úuév€dMléO·.Qéþ»ÞÉ…¿aƒú%Ò2\¥TZÞ’V\‚6J+ÁriX!­+¥5—2%Ÿ©LÖHõµ—˜O2cÝ%²eë.Q¨•F–ÞÄxçÒyù¬•Rù¼-¥:)M£¯—6ãÚ Òüs£´•¬H=ú =öCz©R¯tR¤HýR µ2 å¡V¥4³jHÊgV KifÕ#)ŸYõXʾ¯Ò³ï«tEðúSƤ"ê<—F‰~'ù‚f¤ôß]bW‡ù†æÂNJù\ØÒG<ñ1ßмÔ))Ÿ—:-¹tîXð‰O.ð¿’Òÿké(O¢ ¯opÆS.Ò¼Ø)Í‹}+ã¥uü¬ÐÒ¤C)Ÿ¡ûN:ÁŸñ Í–}/å³e?HŸ_:÷_˜“’ÿ¼tòÒ¹ÿ‚”ü¥/.û/|”’ÿÂ’têÒ¹ÿÂ')ù/,K§‘ôSÿ¿eN+Rr"X•¾Y Ø/+d·ÀAY8$+‡eà#Y%øXVŽÈªÁ'²šËTÅÔ"?FeÔ` Oe·!ɨá Æeu&dÔ€ ÏdTU<—ñªbRV9å—’h46e?6\– ¯e4—êŒ&cÍÈh2Ö[ùfÏÊhZù;9t¿—‘C÷Y#2zNÖÎË”O~’ÄÀ–ýòÎeV8S ,ÉR“XÖ̓Ҵ,KCÒŠ¬…'¥#iU–ޤ5Y+OÊ@Òº,I²6\{SÖnÉ:ÀmY'¸#»‹×'eÂQ} $^,êº|, ê¾Ló.ï]¦÷zÿ2>«²žËdà<Àþ©ìž>\þ^%3? r‘ªi‘ò>V¢ú‘%©û‘-¸Ìƒ"-F.Ò "-V>Ä~;Œ«ÅÉiñïx9MIN“‰˜(§v’œš<Éò Š1+ŒóâEá©ò'8&¯ÈŸ‚éò10C>fÊ'À,ù3ðªüùe؉bs9òßL^>·¯ËÉf¼!qùÜfÌ•“͘'Ÿbg}7Ê—OãfoÊ_^f+$¿BRü’ å¯ùYoT$ƒ¤bùÌe6cá-’Jäo‘T*Ÿ½üÍÖ¼%'[³LN&e¹üG|¹kåbj#UÉ߃Õrj!ÕÈ{EbIŠX4w¹A8Ï^ÂÒåÔFj’ïÈWÉJ ­òŸ–X>~b9L3Úä4ã¡]¾ÌÒWp/òUÒ&ùi“|´I¾AÚ$ß$m’o¡¤‹ac=”3«W¾j$C, ÈÑàÿ”‰/¤\ˆ&§Ö,±0"ÿi—kðÞe²>öñOäŸq¥QùøT~ŽÉ¿ p˰?!?¦† ü|.?…bLÊÿ÷S‘$ß9ù¯Ãƒh~GD[óšfM¼aE`FNó%ÞÊ#aÎÊ£Àwòhð½<ü çäqà¼<\ÓlŠEyö?ÊÁ%yøIž .ËSÀy*¸*O×äÃ"‘7àð©¼ûáŠ&0„ö*î°gz÷£LˆR4~‡·®hc䀫 H±qŠfœ¯haߊýEìv‰Šv\(IÑÁþ¹)ÉŠ»l¿ û)Š.MUtá§ ÊÿŠ,!]qÌPô€™Š8š¥x^Uô‚ÙŠ>ðš¢ÌQ €×Ì_D1ˆý\اÆoóÀ›ŠÇ`b,T<‹£`±â)X¢Kãà-ÅX¦x–+žƒ òyªTÏS•b)ÕŠA2¡F1$–䊅:ZP_D’<±Ð¨½dö*¨ó’|´7öšeàÆð_£-Eœ§©1E¹ö<¦Ö˶9læƒØà`«bÿئXĵ+^!¥CAÍ©NÅxWñ)]ŠY°[ñ çÜS,ƒ÷+¸·˜¼ 4¬’-)‹²P(Ö‚ØBHë¼nðÍ&ÿ×-¾ÙÆ[Tlã­ )vø »HVì"é‘b'í#é±bI#ŠÏA|ñ¤Ÿ…' ‘––OUœ­•tt¾VÒSµS¯•4® Š/Açk%=SP@‹çŠ£ ó€“ Ðâ…‚†Ó§ÇxðiÅ øRqЇ}Å^ýkEøF3}FÑ-B%_L•ü;ÅŸEHYÅL˽WвD‘ÒózNAõþ¼"JÊêjšÔ¿  Iý‹Šhéù§à£‚>KŠ)w’ÂäUÄJaò*âxR<’VñHZUP…¾¦H¢”´U\Žþüˆ~üñÌ«è»%òK&a“ ;K©Rþ—R¹"eÞDŒ,%“±˜¯ZœáO…a_›"_o)®"_¶ÙàŽâ¸«È÷×Á}µÏ¬x°"u¨¸ô/Š\©T8RäÇŠ|)¬¸2²â•ú›Rê’@ã“Fý¥lÔŸ¥3–0–J¿ÍzV²YÏÊ[¸R”² ׎V–ƒ1Ê 0VY Æ)«Àxe5˜ ¬•µ`’ò6˜¬¬S”õ`ª²LS6‚W”M`ºò˜¡l3•-`–²¼ªlÃM SKòg![I[±pMÙ)GI-K±p]٠醒Z˜b!WI£yJ> ‘¯, úY¸ ©%½@yg*© ƒYI¦^±’›z%Êw4¾‚²§Lù]RrÊì–Ò$ž{Œ÷{¾eI9Ë’ åÜf¥’Ú¨UÊ^°ZI-Ôe?X«Àóù×·•|þur·Qi·Ñ ‚ÔiR“rÒHÚÙ-¶œÝb«ò)$Ub¡CpªÒ©Lï*I•’j±pOøXJCâÔν¯¤!ñ% |"Í ”ÔÒ³õ)£ì¥?e/}ŒíKÉÕcBJTÏXÊs)å˜üö¸ýìq”/( _|"P& *ÉãcH9¢1¬| >R¾+_Sû[ÉVžU’ÇǨ _á©rS¾Ç•há Êwà3%Z´ÂsåpR9¾PÎK¿z|L)Ï‚Ý*Y°[åY°[% v«< v«dÁn•gÁn•äñ1«äï”äññ^É=>>(ÉãcNÉ=>æY6/œeó¢rA £¿v¸òûEÜ@ÚËZËh#Ë„U%ÙûkÊe<áºrw¹¡\Åþ¦rMª4ˆ…¥d×WL¹7Q­ì*7ñ6÷”[,e)ûÊm¤|V’»ìr8T.ˆ~'iÂG\ùïwqÞG(·”yìóÍg¾9à›Cl~‹Ö,ñˆñ¡æ¬ üÅÅ‹§|.c›ÙwÂßC‹–îP“–mbd<¢ ßa¸Šèª8¯eB¤*^&¢TÔfVQs6F• “ ±ªD0N•Æ«’ÁU ˜¨¢Fp’Šš¿ÉªT´¦RTi¸Nªê öÓTéàU˜®Ê3TY`¦ê*˜¥Ê¯ª®ñûË­º^SÝsT¹àuUxC•æªn‚y*4ˆ…|šÃÂMUX BX(T•€EªR°Xu ,Q•¥*4…[ª °LU –«ªd”Õ2–Á5|S‹#ªÛ`¥ª¬RÕƒÕª°FÕHMJU5Uwx6óM 5(U­`½ª lPÑ<ÅFU;ö›TàU'جº ¶¨ºÀVÍDlSu󜿇¤vÕ}°CÕvª€wUÁ.U/Ø­êï©úÁûª°G5>P U@¥WERúT"¥_E!RTeP5Œs†TÀaÕcð‘j|¬z"cFó(^؈ê)¿—1OTc(£ªqÙ?´ÀP‰s¿§ù©2ªŸá½«ÊEÂѧ_ï«dÏñ‹çªçøÅ¤jû/@±0¥zýiP,¼TMaÿˆfƒjûo@±0£z‰ý· X˜U½Âþ;6–ê5ö?€baNõûó XXPÍ`D [õûK ZÖªYì/«Þ+ª÷à*ˆ¶´êö×A4¢UsxæMÕ<¸¥Z·U‹àŽê#¸«Z÷Tu¢¿•´‰/Ь’O²˲cU…hEÆ&ûËØbÁ쥷Î72ê±ýg¢M³H¶dÌ‹b[ÆÌ³ž¡»|³Ç7ûô‹Ý'úŒm'tœŸÊ'Êrá ?óˆÎŽùðÍ)?.g›9KŒä›(Ú ÁΖׂùu¢Šá§Ñ\•SU6ìÿpu¡¦‘jj#D©©­Ž•1ê8þƒxùùb­±jZ¬5NÀþC\*þYˆW‹D‰\,‚˜1‰‹Éüw´l"RiÉÒ$u ?–ÊѪ°É8F‹š¦¨ÓäÌ@’ŸOùOUS8MΓ2ø†æË\QÓ|™tu¦œåQ?B³g2Ô4{&S}Š…«jr‰ÌVgóŒ¹ÆÏÍÁñkêÏQ_—ŸO¿®&ŸÉê8œ Š…Vwƒ#ê{àõ}pTÝ>U?ÇÔÁqu/8¡îŸ©ûÁçêpR=¾PSêapZý|©~ ¾R€¯ÕOÀ7êQpFý|«gÕãà;õø^ý ü ~Ω'Áyõ pA=%K:¨g據õÌ,«§å«A’NqÀKù+ùšúÇ×ìµ¼ŸãúòŸ…uµH2ƒœßP¿Eâ¬\ Ù[›j²·Ôïära[ýÙ½Ã2wWýA>-—tÁ´P‹æðëüz^¾ —t‹YxÅ#õ¿[äeá#«–?ñ׼̬ÈYý¿Š>V¯Éσ)ž¨y0ÅS5…V׬Ëσ)Fhx° H͆ü<˜b”†SŒÖPƒͦü<˜b¬†SŒÓlÉσ)Ækx0ÅͶü<˜b¢†SLÒìÈσ)&kx0ÅÍ®ü<˜bª†SLÓìÉÏÛžW4¼í™®!6C³/?¦˜©¡#YšÏòó`ŠW5L1[Ã)^ÓP©ÍÑ #®k(˜â …wÈÕP¨‡< SÌ×P0Å› ¦X ¡`Š… ¦X¤¡`ŠÅ ¦X¢¡`Š¥ ¦xKCÁË4L±\CÁ+4L±RCÁ«4L±ZCÁk4L±VCÁok(˜b†‚)Ök(˜bƒ†‚)6j(˜b“†‚)ÞÑP0Åf SlÑP0ÅV SlÓP0Åv SìÐP0ÅN S¼«¡`Š] ¦Ø­¡`Š÷4Lñ¾†‚)öh(˜â S|¨¡`н ¦Ø§¡`Šý ¦8 ¡`Šƒ ¦8¤¡`ŠÃ ¦øHCÁk(˜âˆ†‚)>ÑP0ÅQ S|ª9”ŸSÓP0ÅqMnÀï$÷ahG`Nk¾ÒiȈ|¥!#òµæŠó†»F8–ÿ^Ò £]#>‘S÷õ)c¸‚ø‡Æ%}hækþe„‚ v$cc4cŒ‚ô+VAqŒñ VÕ%ðM¢‚”“ô Jf¿HaLe¿Kc¼¢ þŸtE€ðI“Áöá7°44™\˜ƒ°¢ÉR0¥ºŠÓV5W°;4Ù ¶¾=RÖ5ײ¡ÉAJŠ»î ØÔÜÀ-M.ºøQÒ¶5yHÛÑäSÚÒØØÜ®†Ææö47h h øâäÏšBœ| )âIÅH:Ô#鋦„~¿ñÍÁ?ÒÐücM©‚+N8ÑÜÂɧš2:mç¢r¤…kË‘¡­`Bö#µ|Â~”¶G¢µU`Œ¶š?l „Xm-]àðl¼0NKã…ñÚÛ¸Ïmm=˜¤m“µ ™¢mÂÑTí0MÛ ^Ѷ€éÚV0CÛfjÛqí,mö¯j;Álí]ðš¶ ÌÑvƒ×µ÷ÀÚû`®¶ÌÓ>óµÁ›Ú^°@ÛjûÁ"mõ@9µõu!­ëÉ·YÉ;q3Îä<”VTàK­é†XÑæ™÷‰eZ‘þ2¬\ûXq^ûThyíS©ág>EViE†§ÈÀjí~æ(~^£GñóZ-i·µO‘9uÚ1°^;6h'ÀFí3Üv“ö9xG; 6k_€-Ú)dc«vZfþ5ó;´ê— ›{Åøšñâ¼5ß©¥Öü]í ®Ú¥}‹ktkgÁ{Úwà}í{°Gû| jçÁ^íا]ûµÁí8¨ýi—Áaí øH» >Ö®#Úuð‰vÕn‚Oµ[à˜v×î€Ú]ð™vOÁç#ϵԯ…Öƒö3¤>CšÒ@š†t饖¼áþZ{¨èGGŸæëºb%Õô bFL&ÜÐQ0±\]‰’+U²YÍ,×ZФÉÓ‰DT,_W¦üº–ùM­e^ +W~]˼PGk™é*”_×2/ÖѾDûL(åÂ-]òO2¡ ” åºìW€r¡Rw„·SÊ…jÝök@¹P«;ÄþmP.Ôé¾`¿” ºƒïeB#«Pwˆý; \hÖãœP.´ê*•_×;oÓ‘yÑ®«R~]•¼CGÆD§®š¿·tÜÊ]EëÒÕð÷]«<[¯\&tëÈâ¹§»ÍÐêî÷u´º{®Ž'Ñót´ÀüC]=OjPŠ…^]#š ôéî(ù§-/²_‡,ÐEàŸA¹0¤k¦ÞO]‹2@x¤£EÖëh‘õ-²þDG‹¬êh‘õ§:Zd}Lת<_œ|\GÆÈ„ŽŒ‘gº/0ßžëŽÀI].úB×Nér‘2­Ë_êhù¹Wº¤¿Öuâ/ßèî‚3º.¤¼Õuƒ³:2‘ÞéÈDz¯#Ó郎L§9™Wó:2¯tdv-êÈìú¨#slIGæØ'™]Ë:2»Vt÷¨Б‘µ¦##k]GFÖ†ŽŒ¬MY[:2·udjíèÈÔÚÕ‘©µ§£5ç÷u÷q…Ï:ê×=Ð=u1¢ßKFñ!׉™Ó˜ðPInÈmãD׫KžBQõBŸR&‹ŠÓÿЯ¤ÎÞ%õS”êxý ®” RÂÚÖ£ÇKJÒSÿq²ž÷§è‡•+™€êx„ß=V #ØÌâ\ tQ?$.êŸ ß2õ£J©¥JZ¨£žXý¸rBùÃshœ^ô oè{D"yEÒ‹ž+eÂMý¤²G$™¢®"ý¯^ð¢8…«ë§p/%úiåù T©ž·ô4ÔT¦'s¿\O =o€Tê_*ù`¬i= eUë_)Ï>ÈÐ'ýMÒ'ýkÜÈmýü{~F9©”¼ úïßâÌwxãÊoëÉèÙz2úw8µ…eJëY¦´éÿÃì_H^C{ôßÑŽwõMþÐ¥0Ps¹[OÍå{ú÷ø§ûúøy~Nù$3bѼ²Wÿ§ ¬ÆXT~ ·Úwöýúûhß €baP¿b>¤§.“aýGåy›ð‘ž· ë—ø­~Bnè?!·žè—‘ë£zjd?Õ¯àÇô«J˜³d<Óë×”l¹Æ %l2n)Ép›¥ï0î~ˆç,&õÔßÿBOþ€Sú=<Ù´~ÿöRÿ|¥? -Ò‚oô_Àýi‘þ˜´H¾ÓŸ‚ïõá*h‘>œÓG‚óú(pA­¢ÏŒêgaÙ£ õ±– ÅBú¤ƒ´ )ÒŠ>Ò*¤xHkzò\×sÀ =ùnê¹?à–žü·õÜpGOfîž› {úð…ä=lf}P‚ Ö²ž}ÑSÀ #=9ôëE"r®;Ñ“sÝ©ž¼ê äUa wºH¹ÓEÈ.Ú@~t1 k @qŠüo È? òL4G`’‚ý$È¿/Å@Q~R å'Í@öýÙ÷鲡3 dCg(ìO–AÄâý\Å–² 4º}Í@£Û9†DäâuC’*>P2'Í|W`'«h(/Euþ. ô.‹ ©8·Ø–®€¥†tð–!,3d‚å†,°Âp¬4dƒU†k`µ!¬1\k 7ÀÛ†\°ÎÖòÁÃM°ÑP6 Á;†"°ÙP ¶JÀVC)Øf¸vþؤ¤2Üú{[i²ÓpUÅP®Kð™1¿—,Bo ßU¨Hó+««ÉóhÀ@Uâ áF@m€ä£Xxdø¾FÅ|+o«¤ÂcY‚#†:ì?1ôaÔPý§†U£J²„ïŠAhRm\|_Hûñ•üŽê¥¼ûW“†ß7óÌmá›:|á_ZU_5{ÊÀ5{ÚІ´I®Á/ \ƒ_ÚUç­á×j ¿aïgÆ@o äH5k îˆw†i4¢ß^ѤDÚ”h &ö¼× jt/¨¹ýÑ@ í%5Æ?:»Ë†N•B²*µüjÍð÷îâ/»TB7¿ß{ØÜW =*úp‹3R}o|‰ûJ0¾¯Ul¡¤7¸$ã ˜l| ¦gÁTã;0Íø¼bü¦çÀ ã<˜i\³Œ‹àUãG0Û¸^3~sŒË¬Š[AÅuÝ£× ã*¤\H«òŒkò!­Aºi\‡TiR¡qR¤ HÅFªðJŒ¼Â+5nâØ-#f@iŒ´ÌP¹‘/3Ta¤e†*|™¡*#éRµ‘ëRq‹2x›2¸Îø§Ûß2©žeRƒqYÒhÜ%E6î‘"÷I‘ŸI‘¤ÈÆCRdã°ÝxDêl<;'à]ã©êëZ±]gÿÚmœ‰%»bá10\MªÁÉ¥FëÓ­&·xXŒÆ ¤™ýÆ${±?hŒUK…!c8lŒW£¾ûL0büË5[óUÍÖ|ÿ $3¦¨Y5’ª>¾'ìùFi¸ÈSã\|̘Ž3À c&øÌ˜>7^U³à+Ùj6Ë“¤'|@ú…‘¤§Œ|@zÚxM í†tM í6æ@z )ÒãuH3®CzËÞÂìY~¼3ÞPGþNr(挿ø»aþn(\511_ýµ5;o¤œZ0RkvÑxöÑX \@öŽjçª1 @ , p+ƨ‰E…ê cŸ¨HýP¬JÔ¬O·”çÒ-¾)ã›rütÓXüØ2V‚ÛÆ*5©æÇkðt;F‘¹ß5Öòc·‘¸gYn#qßX‡Ä*Z¬‚óEÖk˜ßX¯f}À |ÓȯքE¶&üð‹ñ?ÖÌ7-8vdÙ[pìØØzvÑ\ôÄ(rࢧÆ6~j;N 7‰œí85ÂÔÁ;‘iw"1ÊtWM! /^ìâ܃Ñ&‘«cL÷𠱦û`œ©çìÄjïêg!ÞÄãs%˜ªYÅÙ‹'šDî^ü8ÉÔ§fñJú‘˜l…ô#1Å4pv»ƒüïFþüg!Õ$òPh¯4ÓÐÙÁë:Õ$ ½N¡SMÃH]¤Ø¦G¸J¦é1’þæâŲ_Â$0‰¼e¿ WM8ÛDa¯™FèQ¿OÃ~È1M£ˆ]7=áOÿI7L/‘”kUŸÏBÈ3Ñ,„|ÓSõy¸Â›&2Z LcêóÙ …&²]ŠL…«ØDQ¸JLãjf²Oà1KM"ßnð–éÙÙ“}•ßn±ŒÝb¹¹ ר0Wãæ*Í5`•¹¬6ßkÌu`­¹¼mnëÌ`½¹ l0ßÍÍ`“¹¼cn›Ím`‹¹l5w€mæN°Ý|ì0wæn }ýïi wfe ]æûºÍ4Ú„F²¹Ò}3:‰…óHÌ4ú3?„Ôk¦Q((›™¾™ýfþÍ0ë'‰ž˜ÿ¦WÂÀöiÎ¾Žš©ýöÔܯ9Ÿu5f‰pGãæAÍy Ô 3µ³ž™‡4ߥ>7S{kÒ<¬9ŸWõÂLM¿)ó#Íù¼ªi3µ_škÎçU½2SCðµyDs>¯ê™Úƒ3æ'ü>¨:~k¦êxÖ<ª9¯Žß™©:~o~ª9¯Ž?˜©:ž3±Rÿ)ófª(ÌãVݾAÒ¢™j‘æ Íy\Ø%3îXsöÄçxèe3|]1“ ת™\¸ÖÌðuÝ<‰b±a~s6ÍSØß2OƒÛæ—HÙ1¿wͯÁ=óÒ9ó 霙f-˜iÖÒ¡ù-霙FëŽÌ4ïéØÓ­£`†õ)˜i³¬ãàUë˜m}^³Vãó›·Þø‘žŸëýsí×Îò\ë¤Èë,P‘õo^hIÛ§À ”¾yÉŠà+VL_kYPŸ7ì´.¼e¬–µß±²û^ËB}à›9~Þ<;´ð­ [© —XQ2K­ è–õ#UÖ%ª ¬Ÿ¨2°.Se`]¡ÊÀºJ•u*ë:UÖ ª ¬›TX·¨2°nSe`Ý­»`“u¼cÝ;¬¬»í³–Å:@-Ði¥­X¸k=„ÔéR·õ ¤{¾@ºo¥2ßcåeþ•ÊüC+/ó½VŠÔgåñú­ä™?`åžùƒVŠ4d冭葕Gzl¥ˆ@#V艕bZy  §VŠ4få1€Æ­G¸— HG¸—gVŠôÜÊ#MZ)"Ð +4e%]™¶r]yi=Ö®Ir…7ÖNØk;ýö:fØëxk½ñã¿f­¢ÿ,\‡×ÉîþýÙݰFè~'É–¬ÒH Dé.^Œ>ÛÆœmc±Ã6^G¦‹t¤F/&b»…²­c.&ºá“5Yµ·¦ eEœHÃk¬Zé·f¥¯Ùº•¾fÖ+¸£Mk:¸eÍ·­ä7³cÍÄþ®5 ܳ^÷­Ùàgë5ðÀšZ¯ƒ_¬7À#k.xlÍO¬ùà©õ&nÛÄ'· Pˆ´ý’‚?üHŸÜÏŒ§ŒãŒ tTg213–0–êHÕn1–1–3V0Vêð-. ¢mgßâ&Q„NR(ÄÙ«ÎrŽž9ÞF_ö}ÙmePç’@!ÅPsvEL‡Sm5ºˆ‹’Rú¨¤ÛþM­Ž>`¬c¬gl`ldlb¼ÃØÌØÂتc‹±1¶3v0v2Þeìbìf¼§;/<6*<™6úúdÙîë`‚ØzÀlÛûâ?D_³õ‚9¶>𺭼asmƒ`žmÌ· ƒ7mÀÛc°Ð6Ùž€Å¶Q°Äö,µ·lã`™m,·=+lÏÁJÛ$Xe{VÛ¦ÀÛ4Xk{ Þ¶½ël¯ÁzÛ°Á66ÚÞ‚M¶YðŽíØl{¶Ø>€­¶9°Í6¶ÛÀÛ"ØiûÞµ-éP_Øhõ…í¤{6 E}a[†Ôc£QQÔ¶Hm4:Šú¶ ©ÏF£¤¨/lkl4ZŠú¶iÈF£¦¨/lÙhôõ…mÒˆFQQ_ض BÚ‚ôÔFßÝ1ÿîŽÛÈf™°q›å™l–ç6n³LÚhõõ6¾úú”V…›¶ñUá^ÚhU¸W6¾*Ük­¾þÆÆW_Ÿ±Ñú­¡gmÛºÎ_HÊ…¶_ïP±v÷÷?SI âs¶Üä¼í¥|aYÏFOSôߺÙí¬›ÝžŠSãìÔ Ž·óq‚ýÿúW’š@QéoSìÿ4MÏzÈó)Õ~EϺSÒù&ƒ_,›Ë/R€û4;u­\±gá&ÒíWÁ {6˜i¿fÙsø/hlìªý:’²í7Àkö\=õôytœ-ï•c§>·ëö|=¹RPýv ªŸk¿‰”=h²7Ï^€ìÍ·êÙº'Eú¯]7í¼ë¯À^ŒËÚKÀ";…Ý/¶—b¿Ä~ ,µ—·ìåÈÖ2{¿·J$•Û)6…½ û•öj°Ê^-– Õö=}’kõ4ýäâÅÛgÛ:þÓzv°§×ØÁZ{ cÚï€uvêy©·7ã¿ì-`£½)MöZòÓ¶ß›íË`‹F±[ím`›½l·w€öN°Ó~¼kï»ìÝ`·ýxÏ~¼oï{ìÀö‡àC;9ZôÚÉÑ¢ÏN>áýöpÀ~ ÚÃQ†ìà°½W³ÿ63ûíÆ>=YRýŒz2øõT›éiYÑa–þˆñ±ž>Ñ#ßJÖV²FíÌÆ·SëjÌþ÷2n'ìOÁgö1ð¹}œ´O€/ìÏÀ)ûspÚ> ¾´¿_Ù§À×öiðý%8c¥§FÔk=TÛNÃÚPmûHïì4¼Æº}Ò; s£n iÞNÃÝh£Û«ÐlZ„T…fÓGû,Ž-Ùi\,|²¿ƒ´l§ÁpØáö÷Ví4(.Öìd¤¬Û¹‘²aÿ@¹UÏmÒ=ûÿ3ÇražqåÔ"Ël‰åà'vt™q…¥¯²ý5ÆuÆ –¿›ìèã6㎞ìÒ]vÎã>Kÿü-ß÷Y¾fù~`?@;´‚_ì_kGö#V/cÿØ~žØO©²°‡`V8"ÀG$鈣Ñ`´#ŒqÄ‚±Ž80ÎÆ;ÀG"˜èH“É`²#Lq¤‚©Ž40Íq¼âHÓ`†#ÌtdYŽ«àUG6˜í¸^sä€9ŽëàuÇ ð†#ÌuäyŽ|0ßq¼é( …`¡£,rƒÅްÄQ –:n·e`™ãÙÕåAاÑôŸ…rmÅB…ƒlçJ·«•8Ví ±v±Pã ïV­ƒ·n;¨½XçàíÅzGÎlpÐx¼XhtTCjrи¼X¸ã¨Ôì ñy±Ðâ «µÕÁ­Ö6G-޵;hÔ^,t8hnl§ƒÏ½ë "ÛåàE¶ÛqgÞsÐÈ>¾ÙŽ:H=áÇ7ÛQ顃FúñÍv4@êsЈ?¾Ùša;àà3l86ä ?|³Mѽ@zì`1™g1™w ¿—4 cŽïš lâ]‹r°•±Í Œ;hÂA–Þ3G»¡úÏ%w…iGu“¾tPä•WŽC»AÒ(Ì:D©ðÎq×0-—´ sŽïº T¢»q©yG7î`Áq÷³èIîãÅ}tô€KކÈßIÚ…Ç T–{ûû _ÝV4è¶æ A·uÇþwÃ1l€æ¶S=·íøí#U%GŸ0ŽÎõjÇAzµë ½Ús<Å5öc¸¡ÏŽqðÀ1:ž_Ï ,J2­!}äàkH;h é_CúÔAñÃ<c„“â1F:y<Æ('å{´“ç{ŒsÒ0ñg’Î@!Ñù'/ 2!ÉIn’”©)NÊÔT'…³IsRÈ›+N y“Ç3œS¸ËL'­?žå¤ɯ:§‘’í|Iæ|Eæ<@C¢ ínçï¨Û'×ù÷þ·Â…¸(û¥ ü¢üΈSÄ·l–ñã{^$>ðÍK›§Ì?2.±£ŸÅî$.“f;WH³«¤ÙÎ5Òl纡?@r/P(v~¿Á^é&ãÖùë-qÒë-uÒë½åÜÆ#–9w âŸî •NáÿnúQÒ(Üvþ‹]üâ^¼¸‡«Ö9s‘åõNÑ?Ü7°žØÏHlpB¢t``c…‡¬l!åuŠþæ )¯óÈp>ŒØìäÈ-Îc$Â8áåå¿huŠþñ)~Ñæ 7ž1¶;ùc‡3ÂÈçÂNétŠþ–¦ÂÝuFùe¢Œì2ÑFè»SôŸG¡ïÎ#˧q0§è¿È§q0g¬‘Zpq8³Ç)ú'q8ó3Þx>Kî¡“fÉõ:Î~œˆûœ¢šˆûIg©4Â9àä#œƒÎd~¿å¿EÍàý32¸†)<± ‰œ¢NËþwŠþE'W‰Fõ^8ù¨Þ”3ÛÁyŸžƒÓ_:EÿmNå¼N7+Ü@Úk§è_Þ@Úg.ÿ³<$Î8Eÿ*‰oùÆáƒó¦ñÌ·ögaÎ)úïÒaýÎ;É£cÁIÖ⢳ûäÕ±ä,?9ɧcÙYjü'’‡Âš3ð–‘¾ #.ÿ^Èûñk8Íug™QüSo °åÊbI_ pà*Œ•Æúžýrñ×GNEûiµ‘…'©12/†ZÜݱ³wwâ¼mdÃôuNu8\ϓ܀¤ÈàFžÔ„¤¨à&$EßáIÍHŠ nFRlp •Œ” jEZ\p+ÒâƒÛŒR!!˜?ƒÛ±ŸÜ&wâS‚ï‚©Áä’Ü ^ ¾¦SüŒàû¸^ÓÂ}Ô™Á=äoü€ü,‚{’ü¼,‚{ñ䃢žßßþ¾ÏÈ=Ù äÓâyÁýÃ³ß ~vOQ… ‚_àIÓða/{ž¾à)ùŒo¾®FNëÓ.rZé 0ÐDûW.šhÿÚE“â߸hRüŒ‹æŒ¿uÑœñY9¶¿s‘cû{טI*|pQ·Ðœkûó.š§½à¢yÚ‹.šÅýÑ5a‚»ž™â%/¨XqÉž›˜s¦éÛú×.¶þµëi‘kŠ´È5MZäzIZäzEZäzMZäzCZäš!-r½%-rÍ’¹Þ‘¹Þ“¹>¹æH‹\ó¤E®Ò"×"i‘ë#i‘{‰´Èý‰´È½LZä^!-r¯’¹×H‹Üë¤Eî Vò6ñfâÝä½"ÜôfÝüÍ$¹·L Ét ¨ëWWÜÚmÓ·x\?þ¸Cºä¦^­ ÷®é|u¦›O£ÎrÓ4ê«î=Óù4êl7w¾æÞ7M£rÜ4‰úº›&Qßp6M¢Æ'ÎMS¨óܦó)Ôùn>…ú¦ûÐt>…ºÀͧPº¿˜Î§P¹ùêb÷‘é| u‰›O¡.u›Î½xo¹¹o™ûÄD1Á.^¤ñ˜r·è¿§ñ˜ ÷)©¨;Ü,ªÜ`µ›&I׸i’t­;^´e’¼¢—_ïþ÷‘fªð££ccããÍY$ÉL•2c c*cã3}ÒÙ~c&KÉ2[ÒÓÍ–ôt_5£íéÎÆ? ¡ÁtÇ-úŽÐ`jv_3³ÎÁ3 ^7£Rp‹þÇëfT nZܸÍ}ƒ_.—oòðœín*üî|\µÓ}¼ë.»Ü…`·»ˆœ]ÜÅääâ.!çw)9µ¸o‘3‹» ìu—ƒ}î °ß] ¸«ÀAw58䮇ݵà#÷mð±»q׃OÜ à¨»|ênÇÜwÀqw38ánŸ¹[Áçî6pÒݾpw€SîNpÚMî8/Ý]à+79ã¼vß߸ÉgÆÝ¾u“#άû!räŠüCäÈ{w/¤z!͹û ÍCꃴà©ÒG÷¤%H>¹!-C„´â‚´ iÒš{Ò:¤aHîG6!=‚´å¦>ûm7ï³ßqSŸý®›÷Ù﹩Ï~ßÍûì?»©ÏþÀÍûìÝÔgÿÅÍûìÜqÍcHqÍ7õàŸºy~xõàG„ðüÈœigF‡<1Ç‹$o…¸ïFÍ4iêé·’B%+!„º¶Cx×vRȘY,yKÞi!ÌÛáJH&…Úœ 2C¾ǯÿ7¡Ò d…PGÏÕ ¤ü¯B6Ô;;„ºw®…<3Ë„œçæä_KÞŠf¾»ò«I3õͽ#„©owPÀî 0dï©(ä%Xò , y –†¼o…ü±N)Òä²>²ZΞ¢âì)*CŠ2~Ì 5!3(îµ!oÁÛ!³`]È;Üa}È{3 ¼yRî¦õ¦²sŒóŒ ßnó»ÍæEüº%ä#nª5d l ù¶‡,ƒ!+¤J!«¤J!k¤J!ë¤J!¤J!›¤J![¤J!Û¤J!;¤J!»¤J!{¤J!û¤J!ŸI•BH•BI•B¾*…‘*…“*…œ*…œš¿F~£†Ptà§!<:ðXEáÑ'B¨îÂëþç!áñO‹Âtˆa¡y%°ƒC¾ÿÿLjŸ…ˆ¤^„™H ìã(p6$Úa‘, Bº/ ¾u‹b>¢ùw’O¢XËbÈwq{Çò³ð1Dô?Å[ÄÂRHÛwráSH‚æhH¢vqH¤H#Y ÖC~Hâ?XúÍÏÂFˆè^úXØ I¶Ð¢qâ“_þ,l…ˆ.œüR,l‡¤à¿vBRñûÝ.þi-P8 ñ¦YØ·ä ¿J:ßdðM&ßdYXøT.d3áš…­Ê”c¡&Òu =mS€ ü ÜÀ~dÀÅ‹¹4/Crq÷áž<ö“Q˜žQ˜‘ž|ò,ü†V&ß´P—C{@€íi 1ž «° ñëXO!ÎóYX«®Iñžb$%xJxR)’=¥HJò´â~¼xñ?R†´dO9û÷ ì§x*±/šñW©žfüUš§Ê‚âàèO5®”î©!O(O-˜é¹Mž=ž:òèñÔ“ïŽçÙ/` {°Ÿã™Äþuy\Ýð4¹ò·Êó°ÁÓ6zÀfÏ«ñÑ ]‹ÚƒŒhõPWu›‡wU·{ÈÍ£ÃÃÝ<:=ÔÉ|×Ã;™»<´ðS·‡/ütÏCsßÃ5¦Ç0õ“d+Pèõü4Œ{îó<û=ÁOëORaÐÓyÚÁaOøÈ3‚»}ì¡pB#ž'ØâG=O-…¿–ì ãñ+5ãz ð<ÍýV²(ÊüaÒóà”/šû¿ }Ý>Ûù×´ªê Ï.8åyþ[©0íyF.mžçPŒWžIÒëý@aÆóãx=<¢åòÌBLJbÙœ èø[‹+àygzçyHqfËžàŠ‡<ÌV=óàš‡üËÖ=‹à†‡¼Ë6=Kà–‡|˶=ËàŽ‡<Ëv=«àž‡üÊö=ëàgy•x6ÁCù”}ñl[¨rÜA18 ÜA18öìB:´ éÔ³)<W‚º)Ò>¤¨ÐÏ¢!}†JÅ 6”ƒ¸ÐÊCÊÄÐ_~{â¤PzâäÐ/xâ”Ð#ò^ =&¯ÅÐòV =%/ÅÐp+ Whù…F’ÏPhù …FƒÙ¡1äK^@¡qÖ¯®Ÿý÷Ðx«Xr(† VÜÅ1ÝEIèo­çwQÊîâVh’U*”…&ãJå¡)`Eh*XšV…^«CÓÁšÐ °64“¼‹B³ÀºÐ«`}h6Øz l Í!ß¡ÐëàÐ`sh.Øš¶†æŸßiÛÙ¶‡Þ´âûp(Ü  ¬& ¿ ô„ …VɈ Bo¨xý‚ÀJ]_hî¶?4.@,‰¼€†âph 5 …ãúC©i8JMÃ'¡%V¥$ú‚0Xj%ƒæÎ¥¯ÿD(ÿú? -³Šн ¼Ê­/ÿLwAxÀ‚߇ROÑLh…5â¢$þ2ï]è*­T€««kko3Ö1Ö36X©¨726YiÜòc3¨Z¬ÔFlµ2ÆvÆÆNÆ»Œ]ìÌîo¯î={uB©'g.ô²d>ô>ÿú;1ù¨-„>CÉCích/¸Ú‡“>…öc9”¼ÓVBÁÕPòM[ ×CÉ3m#ô1¸J~i[¡OÀíPòJÛ } OÚ^è8¸JiŸCŸ‘ÿ\(ù£†N’¿\(y£…NÇ¡ä‹vú< }†{_ƒÞ7`¤wŒò¾£½³`Œ÷ë%´8ï0Þ;&xç­°=½°‡­°=½ ’!-@Jñ.BJ…´)ÍûÒH!¥{— e@Z‚”éý) Ò'HW½Ë²!-Cºæ]”iÒuï*¤V!åz× åAZƒ”ï]‡tÒ:¤ï¤BHм›Š½ä·&J¼[J½ä¿&nyÉÂ/ór ¿ÜK~…—[ø•^²ð«¼Ü¯ö’Ý^ãåv{­wW¹í%ÿ7±PçÝTiRƒwR£—üá`x÷¬ÃJIâ¡Å{aßúð럾ûL›‹ßXeB«÷… Íûl÷QµL%û®÷£ðÄ'¬Øž2†ÛˆŒ‘ŒQŒÑ6úFÇØ¨HÆÚ¨hDZýx¶Ÿ`£ow¢í¼¨vy©¨v{©¨ÞóR§ã}o’M*ôxÉù7ÙãÖ›özSÁ>oØï½xÓÁAo8ä͇½Yà#ïUð±7ñ^ŸxsÀQïuð©÷8æÍǽyà„7|æ½ >÷€“ÞBð…·œòƒÓÞò—ò–‚¯¼·À×Þ2ð·œñV€o½•x°ÿS¨²ý,ÌzÉÛ V¯·Ò{/y‰…ÞHs^ò> óÞZH ^òB ‹ÞÛ>zÉ ö­·Ò'/y¥‰…eo=¤/y§‰…Uo¤5/y©‰…uo#¤ /y«ÁÌõ6AÚò’×ì[/µmv¼¼m³ë¥šuÏËkÖ}ï,‡Ô ¡÷‡ÑÈrh¶ÑÐ2Ú`_¼Ë°i޼dE{[ðp'ÞVðÔÛ†—îk·‰%W. qíc»_‡ å%ÊK¼ï_t²¢p—±‹±›ñã}ÆÆŒY¡éµQmÖÇØÏ8À8È8Ä8Ìøˆ¦Ç¬`°ý'¬`~+X >*X‰>*XI>*Xɾ§¸÷¬T9Ã¥ùÆÁ+>r…K÷=3|ä—雳|äwÕ7fûÈ îšï%˜ã#¸ë¾×à 9ÀåúfÀ<¹¿åûfÁ›¾w`ï=XèûùæÀbß¾e°Ò·VùVÁjßXã[Çã%xõ>Ô(x÷}›ê|äß&ê}[ mAjômCj‚´ éŽoR3¤H-¾]H­v!µùö µCÚƒÔáÛ‡Ô iÒ]ßgH]>Cêö@ºéÒ}ß!¤H‡ø¾@zé ¤^•½>/{ý>*{>^ö}é+ɼ ŒøþåêØ&œ`sjÂíhÛÛ…H;{‘QvNŠK1|Ë7q|Ï7 ´““Sì|)¾Iã×›ýM€ðÄ7‹Vá¨ï Oz‡¤§¾wHó½Çþ8ˆ¦®ïšÏ|¿ûývžûD¿›Çv o;/°ó—‹8}Ê·ˆÓ§}‘øgQËó•OôWÔò|íKçÿñ '¾ñ}BÒŒo'¼Å‰8ôSý`Ñèf}î/ÓNí,vÿlî½›ûà»ÊŽdÛI[®ÙiB÷*~7ç[Åïæ}9v||kHYôQ+÷#n€Z¹K¾ëv|Ý}7Àe_.¸â£öتZkk¾½ßà[å£VÙ†/רôåƒ[¾›à¶¯ÜñÚ„]_ö÷|Åྯüì+|·ÀC_øÅWù*Àc_%xâ«"wG_5î¯#üµ`¤ÿ6寣ýõ`Œ¿Œõ7‚qþ&0ÞLð7ƒ‰þ0Éß &ûóÐV¼FÕMšÿmvŠSßnÿ¶~«Ÿ­ßêïÀ³fø;ñ‹Lÿ]0Ëß^õwãÔ”>ÛÏãÑ_óSÍñózÝÏÞù Éõ Bžÿûû¼ðô°ò€ñ?›Aud¾ÿ=xÓ¿O¡ôr/Eþ_?´ÿÇ« 4x=ê/öÓš(%~Z¥ÔOk¢ÜòÓš(e~Z¥ÜOk¢Tø{í¬ó¹ý_¿ýg¡÷6` UþAp…±˜h\¯ âw‰•Æàøÿñ`ÎàÍÕÆ77WBÊ5ÆGÀµFžX®3*z9³\o|Œ"Ú`ìd5Îe5N5NóÏᾺkŽÜ #íOæðèÐ#íOçÈó³Ïõ;ÍÈúndýÞdäÓ²ÆçH+Óø¸ÙØ I³Œ}À-Æ~àV#o:Í6¾n3ò–ÓíÆàãÂð·µäµ¾h§‘׉wµuâÝFî‹rZ_´ÇÈ}Ñ^£Öí3ò_pyFí/¸|#sÝoÔŽ¹0rs9hÔšK1ï=5do(6~®qábQ¸vFbñsI¸ü#>\‡ŒKÃåá’l~Ú˜ÍOCÂ1t—…kO5Á×aãòpU1®ÐX‰`5&‚u̘¤±’Á:nLë„q¥ÆZV¹qX'«µDÖ€uʸ¬ÓƵš¯u`1®ë¬q}¸|8–¯'8gäë Î7@” ãFàc °Ò˜ ¼hL^2¦/7«ŒÀjc&°Æ¸XkÌÖ·ëüGDƒq+ìÆl`“q°ÙØ5 ëq;ì-Æšw0¼w„CYò´YÆmã?å„Ë;#$î’¸[bn87³=÷JÜÎ ”'1_â~‰ÂY½J?á1x­X¶Y»Vl›ùhDà±ífí±æcc>!‡Ðl§™~q‚í2—G žØmÖÎäšOF.ZÛcÖ.ZÛk>!jœFø}fúåi„Ï3ŸAÔùfžbí7ó뀙'WÍ<Ñ*0ŸÕâ9§ç5£B3. d¡¹Xd¾,6_2_–˜«€¥æj`™¹&¢aFðá qÔ<¤6BžG­û½Fj–Ô\Fjæ?¼Nšµ?¼N™"tÁGY»ÎšG7†9'Ü77q 57s 5_ájnáj¾Ê-Ô|[¨ù:·Pó n¡æ›ÜBÍ·¸…šoG¼ýs¯îMmÕ›[#ξ| –%ð¹Ì’Bjð™ ‘h?W;$¤ˆ$Ë9d9Ù²t®v`H+-¼r• ¹Ú’0w|𹠱΢.›ËÃíò¹ü§/Û¬·¬˜«Ÿ¢ãS,ÄG R-‰sc‡W°*m²ü2i.wBÉWJ\%qµÄ5×J\'q½Ä 7ΕwáHL•˜&1]â&‰3%nžР kP¦…»ºÍ–¬¹SD–e p‹eë\9e£0¶Z¶³-ÛÛ,;€Û-9À–ÀË.àN ï¹ÞeÉî¶ðŽë\Ë^à ï·ÞkÉã=ÊÞmgÙÌ·ð^ëý–ƒÀÞi}ÐR,°ð>ëBK1°È»¬‹-%ÀCÞc]b)–Zx‡u™åð°…÷W±ã}ÜÞ]}Ìr‚wj[xoõ ËIÞ™máÕ'-§y'¶…÷UŸ¶œå×ÞU}Ör~.>³-_çb®m©UªÔËP• .€ºh©u T%¨Ë–‹ ª@]Um¹ªÔ%Pµ–Ë ê@]Uo©Õª T£¥T¨jPÍ–PW,¼;ã¬E>TiyóP¥…ÇÒëm,½aá±ô¦EKoYøÏÛíÏV oi¼cѶ4Þµð–Æ{mKc›…ÿ ½oÑþ m·ðT‡Eû‚z`©[91¸’ÇàÇâ¡´ÓR7}ÃEÖËnËôz©1 så-¹så½4MšÑ<—'æWæÊ+kZ4ÞÕAÍz"5«Çr ÚôÔrýÌrƒ·å[nòv|Ë-Þ\o¹ ì³´û-w€/-w¹[î!¢õŠüJ|mѾ,ü•¸Ðª}%ÆZùÒ˜8«viÌ"+_³Øª]³ÄÊß¿ñVí•¥V¾ &Áª]³ÌÊ—¿,·j—¿¬°rï•hÕz¯$kÛ\5¤ SfëÄûså)AÙ€;$>ø¸óI<–؉Š[c휫ˆµV¿ät³ÎÚÎzk·ä<}ƒõ ø­=c¸µùLµ>¦YŸÓ­Ï›¬/€Ö^`¦µ¸ÙÚ̲¾n±¾âæh}ÍÍÑ:ÀÍѺpš£5v^ž.¸&ˆºÆì´NŒ›ÇìCVý3-~c.™' ÅÃh›;|øR˜•áÃæ)b—5aæÛV>¨”k%åÌ=0KøàÌ.¨è>ib|F.Ì"çf¿uG+ÚùÌ"xíè ¢,Ì¢—L¡uù<í•ãyfQæ $Ul•ç–¬òÜxOçšD)Ìg0Ë`&Î3‰Ã0“¹#Öäy˜ÑÕ±B·ÎZ9OvŽWK\3•sí¼€ê°²ê•[×Í›"NZ×ódëÞzlÝÈ[Ž­)¼ÕØšÊ[Œ­i¼µØšÎ[Š­›x+±5ƒ7ÿZ3­›—¬YÀËÖ-À*ëV`µ5XcݬµnÖYwë­9ÀëN`£u°ÉºØlÍåmÉÖ=Àë^àUë¾y<Öç¡L®AûòP&×­ù n€ÊuÓºÔ-PûAݶÕ ê¨;Rkï¾ÑÚ{Ö 4.¸!H´[ƒΓ§íxé ÃÊK¬¼lõÐÊËV¬¿Ü$üVvâõ,ðïßœ{åAªËZÀ%ÝÌ%Ýc}¿PŠX$±Xâ!‰%ƒ%ýT–ô3+Ï­¥(ïÖ2ä¯×zØg=ì·¾´C°ÚyäWVm½óµ•×;¬ÚzçBŸG޵iç‘ãl|y‘M;¼ØÆY^bÓ²o;>}T ºÌæ;!Õ \âI‰§$ž–xFâY‰ç$ž—X!ñÂ<žýTfi¹³´ÂvB'Ú.“l—ç½Ù«ˆdÿa¸ÒV‡U¶jàj[ p­¸ÖV\g«®·57ØmMÀ[30Õv˜fk¦Û®7Ù®3l×™¶ÀͶ›À,o¦ßb» Üjã­ôÙ¶;Àm6ÞH¿Ýv¸ÃÆÛèsl÷;m¼‰~—­¸ÛÆ[èsm{l¼~¯í1ŸF±ñöù<›˜oëBÆâ@†âëÙÆ&¾žmù ‚ÊU`+UªT‘­T1¨BP‡lÅ J@ƒ*µUê¨Ã¶RPG@•‚:j+u T¨ã¶# N€:ªÜvÔIPGA²•ƒ: ªÔYëgßÔú9[÷¼ãワ‰‹¶ '\%¢×[ÚD¥í)´ï’íð²íù¼©Á7‚¨/¤Æ6ôÅ<Þ¼Ö+; ~ȤÖÖÇ-ÖÆóúz›6¯o°õ£}5‚êG\M¶•Êm ¾Dk‡¶ØBÕþý[üÆ|©)Ë+¤}Õö þ¯Ù^#Õë¶à ÛÂÈ)â¦-xËÆ—åܶÅE’hµñQ;¶Åàßµ-Þ³ÅÛlKÁ¿oKˆœ*Úm+i¥Ü¤ð²mŸ,AŠÿ(èýe‘B,”³>²­ˆ”ÉßÂlÿ±-Q#Ú@tÚøáR¿-)RöÉš ?CÚeãgH»m+#ùDò*v«#1ß¶­ŽTEm䯕üuà?µ­ÿ™m}¤16h1ñIîç6>Éý¶’÷ÚR€}¶T`¿- øÒÆŸ¯lé°¿¶mÈXhÏ@cí™À8ûfà"{\Û·—Ø·‚oÏ.µoC9$Ø·Gf ¾$V؇íˆäŠÎ‰ä?@wÂ{¢}<&Ùw“í¹À•ö=ÀUö½ÀÕvþ³y}|®µçE¢;kã^bƒ}F~$·ôý‘RãÀøq0’û³‰…‘.`£»€;÷j©ö"D•f/FäéöCÀMö`†½˜i/ãcöÃÀ,ûàûQàVû1`¶ý8p›ýp»½¸Ã~˜c?Üi?)W3wñš—MŒÁö:^óUÇk^ö¤‰f±TÒDUì³sÿ˜g×úÇ|;÷ûíZÿxÀ.¿ío¿ícÔàö Ql×ó”îý\ý;#‹ò¬ÄB…7µ_-7rGÖŽîà9`™ýƒó‘òC×aÛy戽"R~ñ:ÌQ;¯Ã³_ˆ”K3•ЖãöJhË ûEu ¬rû%°NÚ/Gòé†*pNÙ«À9m¯g’¨猽œ³öZV²tÕwÎ^Þy{½&CïETØ{‘½ öÕV¥½¬‹vÎÚ%{#×ñC®ãj{xS$÷éͯHl‘xUÖýµHžË^äoÜ‘ÜÜ”œ[o*@T€Z©uv^ª··B ìw€ö»‘òÛèj±ÉÞl¶ß^±·[ìÀ«öÀkö‡ÀëöGÀöÇÀ›öNà-»xÛÞÅ=ƒ½›{ûà]{TƧ‘˜¿£2Ÿ¢8ÚìÏ@ÝçjÕnªƒ«Ôû PA½õÈÞ ê1¨^Pv^!òÛµ¢.;¯ÒuÛµUº'vþ²è±k_OíüeñÌ®}Y<—ªôâ*õÚû"Ç?/íj$o†x)‘ç ¯ì¯"÷)ÁAb¡#HÛ ÇŠ&ä}±Þoçx[äàZòs-Å;BFJz©ƒK:Á5E,sÄE‘XîX\áX Lt,&9âÉŽ¥À•Žà*Ç2àjÇr>>àX\ëHŒz»x²Î¡‰¾Þ‘…T»9ÕÇÜä(y0Šë}•´¯Žâ¿$ÖDñÞ˜µQò4`ÿ%±>Š¿l6È7FqG‘Åw˦Ê*åNsðaéŽ4H¿É‘92›€™Ž àfG&0˱¸Å‘ÜêØÌvlnsd·;¶w8¶s;€;9À]ŽÀÝŽ]H2EûÊuhßA{ü´×¡}ísðcžCûbÌwð¿eûÚ¿e¼ç CÛ¿SààŽ¦Ð¡u4E^j/vhKí‡üÅTâо˜J¹p+• ·ÃŽ=|å¨=|僯=æÐ®=îà?ñ¦ÀË»£Ð“ôpOrÚñAnT`E÷Œƒ{’³Ž=Q²ïB[wìB[wì‹ÒÞŽ«Â‘ÖG~T`Ý·ÒÁýÍEÇ~-®ðuÉq¾.;FÉS˜“U90'«vh±ÂS£žjE«¬:G1XõŽCZ‚%`58JÀjtpOÒä(œò™ö—×uǧeð—†NP3ŽhÆQÍ8&õç¸Ô¥RsÊ%žÔRCn:NA7n9N£6o;Î[gwç€wç÷À6Çà}G%°ÝqØá¸|ภ|è¨>rT;j€ŽÿÓŸ<µb“¦3þ7:Ó%u¦ûÎD]¦:A¨4çc`º³¸Ééç–ïìâ–ïìæ–ï|Â-ßÙÃ-ßù”[¾óYT`E#Û©ÕÊ6'×Êv§V+;œ¼¢‘ãÔV4v:yEc—S[ÑØíÜ*ÔP{œœó½or¾ÏÉëyNm}#ßÉëûÚúƧœ8ßL œÏ¹T^s©;Ǿ¥Ò+K¥Oªoÿ`–É,—8_"Ë¥ÎWÈB™“ôv8ù8ÏQgl´›µL{“©ã2S'ÞdªÜÉÊuÒ©)×))Îé7âœqÆEçé‚êE…3xbÊRÄâhLè‹£1¡wòjÄE§¶qÉ©­F\†ÉKUÎ%Ñ&Q *f »’§õÎK£ùƒ6i Ú·3 ©6:¢ß®à69y·Ù¹,Z»HJWœM¥Å¹<úíšîU'¯é^sòšîug¦‚1d±ž°8ß]Í'Í£ydH’˜=x¨DY«S*q®ŒÆDß¹ xϹ…Õæ\¼ï\ lw®C°-(¸¡˹à†b,wòôî¡S›Þ=ròôî±S›ÞuÊ‚ó¿)¸.çúh4®x=×s绢Yy7·*"%šG°ÔA©^H©ziH·Ï™ìwn¾tf_93¯ÿ¯Mlà¢-tÉîzÓÂ]¼¸È¥-$.vmŽF9%p9-uÉL?Á%Ï>»¶ $–»¶"µ®l`¢k0ɵ˜ìÚ\éÊ®rí®ví®qí®uå×¹ö×»öF¿ç7¸´âØèú!&x¹^¤¹†jk¿¿ºÁ×!¤»oFú79sÙäâ[â2\û¢'¯Ð‹,—’‡È·¸ò[]û£ÕàD=íVv¸ä°×èÌ÷‚“ôb·K¤ ;8,8Y/öº&Œæ[Ê ¸ …šQ=x·CHH±F‚Vïs‚Vç¹J4V)Xù®R°ö»Ê¢Í†ŠÔºŽ \G…®cÀ"×q`±ëð«Xâ: ,u–¹N»Î¸Îr«tswUO¸.D£Ý¯âÊ9å[Ííþb´<-7K V×iY]g\U¨®³®j„>窞wñ¡¯ Wð‚«>Zýäv_éÒÚýE·ûK.­Ý_vq»¯rií¾ÚÅõUó¦¾j]Çh‹¼F/\ãêÂŒü=Fú]£Œb ÌD½D#ʧÑÕˆòirݧˆfWStàÈòýooqñ'ñUW3„½æâÍb×]W`¿ájÞt]Þr]Þvñ§i«ë:ìw\íã0öº:€÷\ÝÀ6× n›®›Ü6]·€®ÛÑSÅW+kõ:.¸Ç®¿»-wÚJ¼'±Mâ}Y íoO”×Iû‰%>’øXb§,z¿,ú.C·Ä'{$>•øLâs‰/$öJì“Ø/cx)c{5X…² ý.\üõÒíz|?q g=®…|ÚÉ |æŠ>w-¾p-öº–û\ñÀ~×RàKWð•kðµ‹O ¸VºùüX¬; çæÓc‹Ü+‹Ý|vl‰{50ÞÍ'Ç–º×Ü|nl™{=p¹›O­po&ºùÌX’;˜ìæc+ÝéÀUn>/¶Ú\ãæÓbkÝ›ëÜ|Vl½{ pƒ›OŠmtgSÜ|N,Õ½˜ææSbéîà&7ŸËpïúZî-Šd™n6ѹ¹ã@eеŽûk³Ø j÷תÈvç‚Ú*Ôv÷P;@í•ã^„p;A-B¸]î½pÛ j/ÜrÝû@íµÔ^w¨} ò@å¹óAåƒÊµß½ÔPûAtUê¨B÷APE ‚*v€:ªT‰»T)¨BPeî"P‡A:â^ ÉŽ‚Z ÉŽ¹‹ávT1ÜN¸¹–»µFxÒ}èk|»mЋ3î‹.ù ß]ú5ô~#ë}…ûß˾–‡•$‘xTâ1‰Ç%žX.ñ¤ÄSOK<#ñì×üå}NÚÏK¬øZV’X)ñ¢ÄK/K¬’X-±æë€–_p³–WºYË/ºYË/¹k!ûew°Ê]ÿµüFo@åW»5î&`­»X羬w·ÜWîkÀ&÷u`³û2tóµ÷-àU7P»æn^wóñ´î»À›n>œvËÝ¼íæ£i­îvà7L»ë~ÀÝ|,­ÍýˆTºùPZ»»“PºùHÚw™tó´Gî'|DÒÍÇÑ:ÝOùH¤›£u¹ŸóH÷ >Âèî壋î>nÄî~nÄî—܈ݯ¸»_s#vp#v/äƒFîXàKwð•{Ñ|<Ï7‹×¬#óU1à^j¡‡O¨©"Ö*T<¨Ež¥ ƒZ j‰'T<¨PK=Ë@%€Zj™g9¨å –ƒZáY*Ô PIžDPÉ A­ô$Z* ÔjO2¨5 ’A­õ¬µÎÃçÎðùîáõ‹ mýb£‡w¸¤x´.©Þá’æÑv¸¤{øx“GûÎððÚF¦G[ÛØìáµ,¶¶±ÅÃÿšnõhÿšf{ø_Ómí_Óíþ×t‡Gû×4ÇÃÿšîôhÿšîòðdg·G›ìäz¸%íñh-i¯'–§ˆ©ÜXò=ﮚÏSÄÕ² ×H\;ðŠ!¼bÈÃJ{гnþQàY,ôl@ýy6‹=)ÀCžTËÖ¦ˆ%mŠXêá)b™G›"öðñˆG›"•B{#ÔqOÚüŠÁézqÒ£¤#…SžMÀÓžŒùjÈ&½8ç™°eèÅHQ®Ž ÎÔ‹KžQ›‡i§p6k2gÍçµÂ-·2K®A_ödÏ—ýïáãÛã#¼gçûÓDg©õlÖyvë=ÆM žœùSE£gçüÍJp–žvÍ¿â¡Ý`µxrçç¼E/nzÔ=`ÜòìE¨Ûž}(‚VOÞ|5x›^ÜóåÏ—;´÷kƸ¶yøÜÞ}O°Ý3q|ð½xèyó¼y!üM‘3½Gž¢ùQÁ9zÑíÅógïÔ‹§Ý¡ùüŸ€<ÎçáIís6©}á)™Þn½è÷ˆ4>8W/^{Ô²ù¼äuxþÛ…¯Ï‘ùGçïÕ‹8/ƒÀ‹¼ÇQšûô"Þ+NÌŸœ§§¾eÞ¡åóyl>9ÿí#ê˽§æ ïin^§¹}xY‚d¯&ÁJï™ù¼íµi÷WgçË¿­$ž—X!ñ‚ÄJ‰%^’xy>w±UÒ^-±f>wœµë$ÖKlØ(±Ibó ž®õ²ž®ó^™/—OX]×{¹ÝàmAv7z¯S¼×™Tïu`š÷0Ý{¸É{ ˜á½ Ìô¶òùFï`–÷.p‹÷p«· ˜í½Üæmn÷vwxs¼;½€»¼»½À\¯¸ÇÛÜëíæ³’Þ'ÀŸ§ŠÓÞ¥ Îxùœž*Îz@óòy=Uœ÷.Uáås{ª¸à]ªÒËç÷0‹ör§wÉ«uz—½ÜéUyµN¯ÚË^Wëôj½ÜéÕyµN¯ÞË^ƒWëô½Üé5yµN¯ÙËÞ¯Öéµx¹Ó»êÕ:½k^îô®{µN;½›^­Ó»ååå¶WëQZ½®Ô1Áõò¿©vï)Z±@~â$.W¢%iF2 ›X©«4c5 ‡X£k5cf¬_Àëª4b#J½Ã›²@¾0›º@>Œ Öo:ð¡w8cÃÔ aï©™ ¤²n†‘£ˆ,>£èÝ|ìå‡Y;½Úì~ïVðº¼Ù Ñíå÷žxµ÷z¼ÛÀ{êå+”Ÿyµ+”Ÿ{ùzä^ízä^ïv-ôr}^¾¹ß»o´"^z󀯼üwÛkïŽüèêðá9ˆnÀ»sAàÖã…>þ¯,Ö·kÁà­Çq>íÖãE¾\D±ØÇw/ñiwÇûø]Ö¥>~—5Áǧ.óñéË}üÎß ¿ó—èãÇU“|ü¸j²_ \éãWWùøyÀÕ>~pßd]ëã7Y×ùøµÕõ>íµÕ >~Ju£O{J5Åǯ–¦ú´WKÓ|»QRé¾\à&_rœáÓ.9ÎôíÑjz/ôt³þz/ô4ËÇ/˜nñi/˜nõíC°l¿YºÍ§½YºÝ—·€?óÈÿÎ÷kÆSÄ¿}žãë~ošØéëîòuwûÂ5×WÜããïµ½¾BØ÷ùøË.ÏW„(¾>¼¬|ß!$¸ßW<à+ç ¯ ößaØ }G€E>~¶Ø÷æ9Ø?[ê{óìa?{Ä÷æ9Øc>~ö¸ïÍs°å>~ö¤ïÍs°§}üìß›ç`Ïùøá×óLò3¥>ù:«O¾Îꓯ³úäë¬>ù:«O¾Îꓯ³úäë¬>ù:«O¾Îꓯ³úäë¬>ù:«O¾Îê;Šì4ûޝøøÔßqدúN¯ùÊ×}'7|…£1õoùNsÛwØê;¼ã; ¼ë;¼ç;lóUïû.Û}üîk‡¯’›™ï"73ß%nJ¾ËÜ”|UÀN_5Ðï«á†ä«vûê€O|õÀ_ÃùwsãyseÓy¸Y3®h̺ ÿO}×€Ï|×Ï}7€/|7½¾[À>ßm`¿oæ5/}Ê÷b&6¯|ü ôk&ùè_ o‹Qô"…÷Åðf常ònåE1i 3™rI ß°ÏžÓA.áÇŸØ•_^ï/g’Ÿ^ï '2ÉÏ 'Åð?É–ÿêXÃoÿ®bW~üwuLë‚©bMÌ2eçÈàB½X£òM©bî@õ6ÆÜ…cJ̽jp‘žî|˜3¤moʺ&ÚÑWlŠiG;ʈáÛw2cøÞÍ1|ïNVLÇ‚|]ð!==XóÁCìÑþ[íñþŸ¾säÐ7´Ù Rò eA¸\åä`\÷Y^mÊE}ËÛ‘vG[9Ò®ï¨SQ³Ùéê(ÚÆNÿ‚¶³Sìï¨[ j ²Ô A_ˆdq§AìB9!v#G_ˆ\ä¬ê”=#EÝkÕ¥ªûफ़g JSó õº¡`@nð}™Q€¼À(DV`ôC‹ âA&J úaa¢Ô  eýð0qØ &Žô#ÃÄQƒ~T˜8fÐÇ úÐ0q &Ê úwÂÄIƒ~l˜8eп&NôaaâŒA¼wÖ ÎÄûâ¼AŒ‹1þ‚ATBõéêECèMê%CèÐ õ²AL)Vë¨ e€L7ämaT£¨FŽRkPR#õj-J DÔ¡¯zTj´h0ŒQÓu)AºF„Mð$š 﨩AW³¸ƒ$zƒto£l‘¥ÿ;º*kûwtk{íoèeP  öèÖ£ú€¾]G±bJ¥Ät ¸‰xÆŽWoA6U¼ô~[z_4„ZQ7è|†ÂÝAÅ­r·zÈ=ÔØš!CF¾ulcñ²¿¥û,Þ¶o©ÅÛþ-u°2îþ–°2æ~KY|KP…#uêcTáÈáj'ê0DøQ‡!¢ u8rˆÚJ Ù6–ž C. ¥'C¥ÛÃiý=å&3A}ÆIµKÏ9©Žoé'õà[êå¤~KICÅɡԇÀcƒôuCÅ­¡âéPñj¨X¬e?¢«ª/¹PTõ멯Y÷H@MG‡ ·bÐZ3Ø×,4†ªuÞ½ÃD\ˆØB±F®Û®ÙʺCž…Pœä\´È(” ¢z¸ôR3¼a¸X¹ÖŒÒo»‚ÒïkAé?»j ò0ìš1tè£0˜è ߉ï .gÐÚöžxð]—Ÿñ}±û}ºaäž½àýÑo½Ü” {K*ìmÎ’hå‰;œ!q—ó#îqvDçFÜç̈v΋è0Šáñ|ºYŒ.Ǩ…ï£bFêÄ#£¥Šï õ±‘'>Fž|½~_ÄŽ“7Î/+>}\@åºéM㺑éŒqOéÌq=Èôæqׯ‰ãÄíqcÞz|*å~&å~.å~!åî•r÷I¹û¥Ü/¥Ü¯¤Ü¯¥Ü\b¡‰§ ±&ž*Ä™xª°È„âש‹M"t¸XbøÞÍ/ŽŽ'Çf^ñ&Nw©‰ÓM0qºËLœîr§»ÂÄé&šÄPU´ JB ‘ŠšŒP#Ǫ+Œï16‰ ‘sÔÕÈ÷Wˆ!:±F\>á:ûµ&îìsþ½N²÷LT÷ÁAëM\àL\à¥äS6áØưQÆÿÁŒ")`c “jâþ+÷\Ò‰4΄H—Aš>ÔØJîHæ>ÇŽÖïAñÕé÷¢â&‰}(Œúy&<<$$ߤ†ÙÈ~“Á o’È™$µvç¤&ÖÚÖIâÞ¤€ð‘FH—— HHÅô`R ZOÉŠªÅÃ¥Vh⯓"ä5X£œƒÅ!¨ƒ*Ò'F‹{'*§”“¨ñR'qé:ŒŒ„<ñÒþÉâèdQ>YTLO&Añ G¹xæªÇ¸xæ©Ç9Ó‘ê δª>›,5âùäþÉ"}J œÊ9ì‰t’8ù·tŠØõ6ñDî;:câÁæ;:‹Â Ùó3a°ÉûŽÎ›0ØäG(°ýßÑ&s¾£Ì)úJróºÈQßþ.qÔí¿¡Ëuâ/X]‚ .<­€m™èЫ¤2T³÷{?P {÷O¡Z–¤ýªcIü@õ,IVåNQ¤š5J5«š"ê¦Ê?mªÚÄe¢S›¹LH½Âe¢ÓgL ”u‹I wO ”öU>™¦^3…êöL½n Ú;5*Ýàì<ù ¦Š¦©?2š§òqejÛÔ@ºÏ#»‰ÈžO½…È^L½Èz§¾ô·qšØ5MäMSZ¡W§HÜçüiEÓĉi²šÊ§™ˆé.Kº7†îqÉ<ñQ—Lßt~šrŸ…+÷Q;{9ø¨ru˜¸»oš˜P=@ÜÍÓ¢p#Ä#h>nCý:MÂýë2‰n“ÐëÄ“-zLctW¦=…¼-ÓüÓUóLvÏeøBv½Ëƙƨ]Óúƒ*öMû§‹‚éBz‰4*^ÁKáôòé’ßõ~¨zrú™éâætáŸ>ä5ð*š…*bÍB*âÌ"(T,2 }¨XlCBÅÀt±}†(™!ŽÎ§f¨KÌ\ýñf®þ¥fîeÚgü¨‚:fp=˜ñdF à_Îä)Á,çËÌòt¹yŒújÆ s¨îõŒD3ZÎOÔ$3ZN”Zõ‘¨ûHô~òã3Ùªö}´R ½ c²"c²2!ÖBfLBÖ™å×ëzÄÜÿÑshÐËî,+¹ýãG‹ç‹þuÍrv˜b–³ÃT³œ¦™åì°î“€&¤#ÍúO6!ª†O2Uã'×3áxó“Íp¼õIorçÑöÉà·>òû ±¾î’ýi 6²ÍÜç”|*®ðºÍÌ-q»™»å»Ÿí€t!‹þ˜r ^ÈÖïh'ä I]H´ †¤Ã²E² –ûŸ*¹œUÝcÖ¾±~ˆu/Ï„§}> –…3ÒçA®Ø™ù>næ~H¿hfüL±rÐý€V[!Ó÷¢Å=A¤Ì›fòQ(ó‘5“ŠÌÜöϤbi)àT•3g'C–ʵ3•2©P‡¥¯3:“>K›f1ó ptV@Žr޶##Ç458næÅfžƒ–›åô$´àSq ¹;6ë´ùOtÇgÑÐ3æ? :ó¬9T_>ëô¬€$‡¹£{¯˜%jf‰úY Z}¦œ“rž—rîûLÿ,àxê³@\²+ùq³@\Ðx²^;>ƒ¾/"2•¸Y÷y È/qîò»Ë\_ûa©âú>KÊç?jh©ŸsCKû|Ûçâü篙®ø¼UzáóZTiåçuÈðÅÏf‹å³EÒlµ’g7ÀÃÊÙð°jvêl±i¶Ò$ó×,ówv¶l+çfWÎÖ]‘üÉ¿*ü53O+žÎV®³Š.‹¡,sÛoèÅlñr¶x=[,ü‚n²[¤Ný" õ-öw¼Ûœ·c°d|!k9ó‹VYËW¿à¬ï@Â{_Ü…„m_܃„÷¿ˆý’¯WŽÿR$~ˆ¬Œ« £s)wЭW}ImRÔÛ_j¦óË@Yß—ú÷µK]ñ•Úߘ…>€Pøæ}ˆD¿ªüJy$#y,óÛý•®S’~óÛÅ£'_u™yñ¨jN@’nÎÖIäæ gë4, s~ü™3G~æÌ¹öcöuɾ1§uŽx0èÒ#Õå©T—î9ôL¦¿4<  ÏáÞË×q…ª áÁ²ðÔp±%<Á A¯Œ`g8OE(dùO©¥<áúYÊ XrÃZó’Å+„ÙÍ,ŒQ÷„ ü÷†?Œw¡~ª.ÖÂ%K×`G¸6ÖÀó U›gè0Ïài§Ý3è1Ϊ> _d Õ= _l z¾ÄªÞ.R#Ä–ˆ•ÐÖÎ`vÄîˆÀ*RîÁ\‘4/à²ÙMž· Ù]9/ožnµE®G¯±Èõèµ¹½ÎÂëÑñ‘")R6»äÈ5‘´ÞÂjš)ÛGzä ·ÜÈÁÕ ëóHÑ9ö-/…Ë&ûJå²iB¥qá\%K§ö[ÚdÁ|î7< &t7`É´`ny –ÍL.[aɲ`vy–-L/Û`ÙjÑi‡%Û¢ò–mýÈG°l·èG…<†e‡E?:ÄKŽEÒ ËN‹~LHXý;!g¿¥Ý(‹¦È–H%™ù©Øc£^¼9t/Èx¾@B(Í|ƒ„Pãù ¡kæ;$DP<_"!ôÍ|‹„Ï×Hˆ¡ î –F¡,Ç‘T$‹íydàïˆb”ÉØPý!Ä:–ô%ˆµÔ"Êëæ¡Ã‡F´Áâb G)œŽYDpß0ª¾ˆíäí¼[©”.¥Kž‡.I²Ü˜Ó]FE¡ë¬B¥NÕV¡›$Îzôogn5œí¾ßðKå9V-gú zjÎs'$«ç<MµU¶¬FÓKÕ3X.zÅßlå¨yqE2®y~<=õÈé©ç®G<tiáˆ_ ¾«q,ƒŽ×ÐtüžëÖP]—§Ç#ú<╇n |B^Ãc¬wP¼Ao:›K¾£‡œÍõ¿¥G,؆ßÒUG»‰`Úƒ&Ó^Ä£DÐê|rë„ÎL×A}CÿY'ô›ˆþ£N i#š®C-ÖéDp/rsXzA˜!JÓéhø.|”ƒQ®ÐI˜#ï*dÕѨ pýX¡­¤¡] Ýó˜¥*Ýÿå*=‡96U§›­ï½€Û»mßïƒ-lcùAŒk ¢ÿ¢㻂è]˜ð"ˆÖ!®úƒhÿ˜˜«§› 'ÑÓm˜ÞÔÓSð'÷ëiÍP˜7„²‘­©ÉC(îÓ¡³àOïB0g$¥ü`}T>”ÆéÄǵ áí“›CéouâÓž¡´~˜NüäåPŠC,3†ÒÒ‰YG†Ñ°?;?Œ.…èÄU£&˜Ÿ÷ £©:1ûÅ0zò‹Øê…ùezÅ׉¯ü!”sÎÓz0\GáÃé!航áT4B'æÖ§Ò:š·h•Ž\1‚ÃŒ:6‚~­ÑçGÐΑ:ñõíô?tbþ³ôßubAÊHj‡Ä†Ý#é1\'FÒ¿é„É?’FéÈÜ3’öÒ Kê(ʃi½:jèÇ:a«‚Ýþ[pÄÖ ×"€{1Àó¯:á\‹÷ñ(J­#ߦєƒœÇlM5 ¿Ù9šP¼¼4íGª²!”®ÁûŸÞ¥“¡:úvÕZ>FG¶y ­‡ùÓíc(uŒNüù¹1´Ñü‡ê1Tþ_ì}‡ƒÿKß¡0ÿSÓ;tæ_Þ{‡ü0ÿóëwèéÄÏŽŽ¥ûHæ»ê±TûŽNü?WÆÒ˜ß¿K«ÁÿùšwéÙ;:úEÆ»?VG¿Üú.%ŽÕ‰¿*|—’aþõ‘wéøÕÙwi3Èÿ’F»aþ:9ŒþF'~³/ŒËßT„Q1ÌÿZF¹Ð±¿½Fyïêè¿Ý £|˜ÿ½3Œ Áÿ}aTó„QªÿïV¼GÛ‘©¿ßñÿ:ÞSÚÏÿjñÞ§­pü§]ïSi˜Nü¿ß§M ûü}ZóŸ_½O)ïéè_Ž£Œ÷tâ_ÓÆÑfÐÿvkœz‘ü{ ˜¿Ë†í‡}ãé&ˆ…td<¥¾¯£X*OÏàGWÆÓ*XѲ ´ï}XL;&ÐX–PîJâÿüéÀŠƒj/¥’ ”8NG ttm„e-ù€þ›N,§ÝÐUxYAÐ?éD"]ù€2ÆëD |@™ãuh:‹&R!8+)~"Á²Š’&R1œVÓꉬk(u"‡ËZÊœHgaYGétb=•N¤[`l #iÿ³D©“T»N¤QØ)´x‚N¤ÒŽI´™I§Û“èám¢»“( õ—A“(–Lz4‰NÂÏfJú.Ã’E—?¤Ãèh =øú`ÙJi“)y¢NdӞɴ~¶Qþd:Îv:2™*aÙA'&SÓDåÐùÉÔ ÎNêžL7ÀÙEO'Ó’I:±›ú&Sü$åRÚÚ‡xöPÆÚ §½”5…²aÙG»§Ð6XòèòÚK>ÕN¡sµŸR§Ò"„:@›¦Rü‡:qvM¥¥ꨀò¦ÒJp éàT:?EÔ8•VÁ©˜îM¥|8¢§Si†N”PÿT: F)m˜Fýð[F;§Q=ü¦}Ójx„ §Ñ)¸¥ãÓè,Çèô4ꆗãtn=AètaõÀRNÓh1ªà$uN£ÿª§hïtª@ Ó”?š&ë ÐÁéÔ¦Vp®Pí'tœºö ¥#oWéÞ'ÊKp®Ñ+àuÚú)ýF'nСOé"»I×>¥f l·èΧÔ7]‡¡£íSz N+õÿ„^Ár‡~BKàù.-™I§P÷(y&†¥6Τ XîSúLª™¡C¼y&€çÊŸI pz@%3é:,©|&ý£N<¢š™tŒÇô|&=‚¥“ÒfÑBŒÆ~:2‹V|¤]tjåÀÒMçgÑNää UÏ¢4øé¡ºY´NOéá,:Ë3ŠûŒÊ>ÒÑsÚû]‚åûŒºa饓Ÿ¡ t¢.|F‹?ÖAqnF °¼¤öÏ( –Wôø3Ú$^Ó²ÏÉ¡´ösÚø úeã甅бJöç”ñ‰Cß¹Ï)N‹”ÄÙêLt3J;¨%J|Å+鳕Eq©Òù‰NIPÎÌ&?-S.̦µŸêh¹Ò3›ÖÁ²By>›ò?Eÿ¢ôϦÓ›¤¤|¡ƒ³J9LV €+•M_ ÑéÄj¥å j@À5Ê/è,k•%_ª±?A×¢tÁÃzeì”_ÒA••_ÒXR”[_ÒžŸè(Uyü%=Ÿ4%ö+4mt.Êò¯h²°I¹ðýú¥ë+:F¦ryµÎÔaœªŸC³Ð·(WçP ,[”Ûs¨tú¥c†%[éšCå°lSâé–íJV¸ÒË¥—tJŽ’N w*»Ã©‘ìR†Óߣ_Qüá´í3|#)OÂi,{”¾pÊe¯’A;?ÓÑ>%+‚N“§ìŠ sàä+G#¨œýÊÙj€å€ÒAÍp:¨ÜŠ k°(—æÒMX •†¹ô­³Hé˜K‘íb%qÕý‘Ž)ûæQ÷¡cQ–Db(@Ç¢$FÒ¥Ïѱ(«#©úst,Jj$Š=‹²;’êátTÙI[À9¦4DÒmø9®\‰¤…˜µPnER,,åÊÝHZ<[G'•G‘õ8¥<‹¤8îY”ì(ú8£”GÑ!ø8«TEQTæœREU|^¹E•ð[¡´FQü\P¢© N•Jz4õÂrQÙM _ cQJ£iÙ:º¬‰¦LXª”òhÚ Kµr6š²`©Q.GC#u¢V©¦l„ªSš¢i,õÊhÊŸ¥àkÚ N£Rú5=ƒ¥Iyñ5½„S³;Ÿ ¾Ô‰+Jü|*ùRG-ÊùùT ËU%i­FÌ×”´”Ëueó:ö:eÿ4Gt0Ê©” §[ʹtÃÿm¥À@­_é¨U)1PáÝQ* TË]å ,uOI2ÒÅ9è`”FZà÷•B#uÂO»rÍHy˜t(GL´#\G”û&zŽFé6QZ„Ž)OM”FI3ÓfX:•Íf*ƒÅ¯6“ ŒrÚL5`t+ fj@ 'J«™ZaéQ™©NO•åZIÖ3e…R ×seƒ…æêÄ %ÍB+梃QZ(–>Åo¡ZXú•d+ÕÁòR9jUbçéèµÒ6W§¼RÚ¬”<Ý‹òØŠÑBG Õn+ý½‹ºÔFð§ž·ÑqX©U6ê†ßÅj³žÃ²Dí°ÑJžÅ¨Ëì´²,U×Ùi{¤N$¨…vʃe™Zb'L—«—ít.ÝŒÚg§F¸$ª¯íÔK’ºØA¯à”¬npÐ8+Õ“JŠÒÑ*µÙA»aY­ö9¨–5ê"'ÕGa£®sR3,ëÔB'݆Ózõ¬“žÃ²A­uR\´Ž6ª7œTÂ]ŽÚí¤LHšª.qÑúht9jŠ‹6ÃOºšé¢Ðã¨Ù.ÚF†ºÓEûaÉTs]t~7«å.JÁXž¥Ö¹èœ¶¨]t oUO¹©œlõœ›}.GÝç¡Ò¯1QOx(iîPÏx(m¾Nä¨ç=”ËNµÒC™°ìR›<”?»Õ«Ú9ÓõއraÙ£vx(~öª=„9Ð>õ‰‡ŠÀÈS{=T K¾úIÁ²_]è¥<›Q{é8Õ¥^:KºÊK'`)Tïxé ,EêÚr¡ÓQSc0 `2£n‰¡{ Ð騇b¨–R5Ï'ˆTZ5Û!)Šª^5ûûÒ¨*³øy³<…H¤¯š]å Ôaz]­jö/‚¦‹Ÿ=¶Îºú/³ª½ý”~¡›.~Õi…Aš¡h† ãÏu5îÇVÝÏÁ’¾ª¿ñ[ ‘é·:ºjö_‹ïÕÙß«!&þz—~РDú·5J4äG ‰fJtúÏfµ$ê²þ9i‰wi‰w!ñn™xð$N½‡¦Rþ“ªÙ´dˆõÝBì>å× tûßi }køÙÙñŸëÜgÇÓÏcYšEљݵ<ŽüÿÄ¡rÂÄ?IêU}køuâÿmUµ‹üÿòÝë÷e#~ýÄêÿW„N¤*}¢ïõSÕ¯(N!Fp„H‡ÃÄ1n/“ÿ(UUÿú€â?ÆÂ ÜÊï"p5¸ãmàò?äÀä=x…‚ÀIJÕ¯Š8pè`à5Ê›Àkÿ:‹ÿz.ž1ƒó9ð>Äß \ü6p±â/áÀ‡);¸†×!p)~w0póÛÀÍŠ¿…—*þ«8LÕë‡$襧6xú¸þã†é¢qòÂ!¿ÔùÛSžzSþ°TÆT*˜Ù­ˆ#ñHé¤Ä8¢Ç0ëG*~Åß©Tý,È$~§øý â}Dp'%őڭø»•Ÿ á(jÕcµ!ÿÿ/t¿º<ô›§V] ò÷+Õû_*£ÿ'Bûª5øcÕÑ¿db‰ÊÞg½úcû3+MÃG áËãüK5ªêóßó‘ð–'},SG¿Çq­Ð¸ý¿Wâ[žô™¤Q½ã~ÏGò[žô±R}>—§Z6~4+ÆÿBùEÐx=_2z™³æù{ß2hôoÁxúgþ¾·eô¯ÀYþSÿ«·uôŸ³þÿë·Ýh38kêxË =œSù«o8úÑ“ÀI ö/Ë2z8´’mCG+ŒCƒ&üt``höëí—ÿöwäõ@ðÀÜPoåj-×Ò¯²ƒÞ5½ð¯Q«Ç@@ÿ:-ãÙîß+Œõoy²06hÔ©~ÏÇÆ·<é#åS}©?ª¾tµF¦–¡q×ÿô÷|f¾åIŸ›5*)ø÷|d½åI[þ7¼õ÷+xt089jÕŸKÝ-ÐhÞSUýtÒÚ"ºË颡Áò•PÔŸ¿@•mᯄ`ÝÇHà/R¡ûoÊÍD¿ÎWüÅ*Br5iM€JT‰ª5ê·M Á_*c­®êü¼ÇŠ@åTý¶üO HIe¹ô ß×éôCR­C”26¢‹ü­8§vÒj¤U©ú+Ôªê˜ç(‡Jõge#ªíe#haÙˆÿ%µæûQ¿za­úU¹òÍqEñW#Òýh®#C‘Ttít­ƒk¡2&nõj Û^¨øÁ-Ö¸MÌ-V~ŽNéŠú³>ë÷Y³í}V3 n-ˆ-köϳfû¯±¯åç%Šÿ:[Ë”Ÿ—)þ›Z9ºµrTZUÿm„è·~?ä[°tPñ·ªÜLänáŽZýG  iÕ .±Võ÷4¶*|OE¯6½Zð·²|ªoƇ(œ„o‰-ã6Ö¡gz¨ú;Õšê‚1BàçjuM-ÇÚ«ŽþÿX{óø¨Ž#q|úsi$„ð8"‘ÁÆrB¼ß=’WÇó Šƒ¼Éâ%ÉŽvføe¢Í^ù®cv³»¡„¸/8„â÷-qƒ÷fÄ}ß—Z˜ûÒ¯ªú½™¶7ùãËÍ{]]]]]]]]}¾T›Mïûs[ŸÁjŸ¾oÿ ëáTùs¹ëû¿~úÁ³l¯ÙvÇ¿P% æ0öu[‰ÒÆFü”ᣢˆIøœYàs: J^¦èð™„>J ©¶K*/W zÆ+ÀÂhEï3Ø5²}°#d9‚+%§Ãiçc(V7Œµ(Ö$+ÓI"ÓIf¦“>UÑ!‡’Ì+IOCÒ n¬† s$­:>IwǾâkDº†HëÚj^«øß1òßa|¢õP ØfëPPóÛáÏÑÆf@§°˜¨ýÃçL`Ÿ³@«áYبð5Äœo‡$ªÐlRtm³d‹…}ÒºØloñÍ&Üj¾+† Vù`zHŸt"CÒÿÕæ†Cݦ öØ·+|›6x¾úÉ`;ß® W^ 5§I‰fÖ÷IsB²(DgÙ ðf²Cz9@›ÂÏ?0óIG;±K1ὃ­&G*£ë*P¯}-ðuì6‹E ŒZ!C%³P¬ YD€­9 ‹ˆÂ›±ÌvBs:¥é{ßÒâ[>«ð3Šl·ò³ÈµâCF£ö%å¼ÂÏ+Š8DÚü‚.ôA—/á¾%}°½½~d´:ýe(Äex{7XäãW3e1Bå#Ôβi…K| @¢(¯þ8¥‚%z!­Ò³˜Ï>âå*óCìõá-Pê Žðñ± ¿L¸ãTK6ÔЋ¸(Ü) À'‰UtæèÉ‹=ùˆO‹q4Ãäh¤W&ü²Úš㨪G±Ú*QEm­‡Î|¾ µ• º ž8UWÈ_æCG½ÁÝ7°L¿AR= – ÍNüžÝÁ»|,™®{Z‚ë~a(û}~QNöÜ"–=þæÃ_ÉÀìÒÙ#f¿Ÿ½ï'Ùe³°þÂ_-üU¿‘½uð7ûìÅðýàÿ€Ã~89Ùß:ñ»‹ “‰ß•Ʋüâœ/¢}ìÂÅ¡ò –_’ãßùNîÎwlÁ€]ª4²üÒÿ]Ö+÷.cÁR^ªîbù#âÀ¼2ÔÞÌòGæø—¿—»ü=[p$ÂþÑq’å—åøÓrÓlÁ2€Œè<ÅòG™Q)ó»N³ürR«CÝgYþh2 ׆&cùcLÈ€\ê9ÏòÇš±¹14ù"ËgBÆäæÐ”K,¼ ƒ¡¯K’Ãùv{=ÔH53{³jFáyŒFAóƒFõÄaÐ|ƒ1‡3P qLPžö^t²VwŠ(±Æ%c‚½‰c‚7$Ùáü¥HL½çhÃEÐaÞøˆ˼HÎ,ô6ób90ÊW¸Ljñ¾Vv$tÝ徆t¹Ü^ìNGÉ~oDó2Ä.‡î[ ƒI;ÆcŒlC½À•q6K¹e&£Ù€"Î9ÖÂc9t&‹à¹:“:™/4t0jÀØç*”›Á3™á‹€»äV^'ëÚ!ÉVè…Nf±R2»`X/û“ù902'¤Úª÷$ Ü"À^*GÓ¾‡vùb²\æËÁyò–²N`HIï ‰Wb:ø…¾{•l„Ô¼†÷dÞîv/vëd=šwTbàÓeB¹zË ÄO¨X»e³CÝ-ŠÀÈè¶Fû?`1Ú®ZD°yr:(GÀ]3Âc|á±¾¼ÕïIü°(Í1¿ç{‹ër`D'€ÞÏ›ŠÛá<ªRÞ'H¤ò`ìYТÚ1àÈ,LìÌ,ôv }B7>±ãÆçjõ9í²r^¦žö‚Œõb¿(ó3²F\8³/oÇË0;ß+2fæí/Z\CI…ÇùÂã}˜1¿.±3NÁÎø† 9¬N؉ÃÌ5EÌqOæ\9_k¨è“.Ù[Ð-OðUĜԶvÙ{”Ùøç0x 3»‰7)œA”¿/ëЗ+š!I(þª3<Ù‡fµOZ22ò!S!2• dŸŸ™eê¬ðñ`œq9¼PÉÌ›æ“ùp°¹°'ûx‘“œâãÅfhlRpªý½ð>iHŸ4¨½¥‡[áýê·ÀტN÷eÖ§'ãÀB~®ßœîã“ͨ.çPeÏÿ­s*:}Ã*¯ÜWø‘;8Ã^»ƒ•>põ(ðÄœ }‹‰æÎòñ™&š#Xåã³Dà™;8ÛÇg£W5'QsR©FÈܸ„æ+ ªÖðÇ™É*ñ9$¡Z”Âx’Ðø–"ªöñ:3šëmj‚® ܯÏ:ø2mÆ[h3öH¤à[Tð´Ö7+oš†c‹BÚËð J$kØbÞ/¥Ï@­ÅÞ QëÀ#Ý£ðJ$³4 ¾ئN• À(à@èáz i4S¢ްóùY<²#?“‚c’øQy0y #JÁ±Iü„yöIÅá\á%y^^½þœh+\½»3ÁWO€’ñ'MH*þxñ' Òñ§ þdàO×Þƒ_Ê,ü²01WLŸÅŸHøXq]AÓ¢Ü&gXmSÀ댒ÆßTÀÖÞÃô[ Ø9Àýmá/ƒ4ÛЬٽt71{;ÐÙv㎂šà¼ MEÌuOáwA%í1Cäâ÷( 4}œ,ÉCÅûŠÃÆ+¢ïàO¾Ó›Ü3%rfÈ•þV‡â¯õ!—V듆¥BÕ‹l?Qšœ!gÈÑõ3èáJÔ;}·tnKsPI-“FÂskó”Ás[KÏíE,¥žE,u.<›Š˜w=ºPQÐWN2å9Q%y–Ðgo{i²Ê'C4 Tà—CžÕ}Òû¡Y™!$nv˜G4Œœ‘ûŠ˜è3šÐJ5ä ½ŒÕ”LúŠtœØ˜¥†R2Á‚ã|À‰YO¿…zªVõ+ä1;…T>W%Åæó虎3©7¯¡g¾ž¼–ž]y ªÎëÑÇ¥„ù°¥U˜l.1¡u KMèbM¯—«p:H må+T “! ¹²ßG£‚m~e».޽J¥ð§Øj{ßO¬@C}q}µJa ½l ¡ƒ]Xƒè$ƒõ&§õøß`B—t‚n4¡KÍRMƒ,6«Q9‰$(ã-*…­ŒKZÅÚG_GߦRØB/hk{}i½Q¥°…>"V¬&D§ªÜ¥Êsk²sÝm†¦øè34Õ‡iöb¡]•±‘bÂÆ$}6VÀÒG'ûÕ Rù:}«÷ûLí s°3eê9aÞ¦ëŒV;eD(º…½%pk¨ò%”ˆ…](¡¸ ‡!M‚®A Œ6E6#.²£*…?õÊ8oMUq,ŽXG<®R8†œˆ#ÎŒ#žT)C>N!"µœ3j`¬™dV<ÉY•Â" #&ÎÅ«âˆçU lj qÄÙqÄ‹*…cˆÀÄ%D¤f{E ŒÁzžC:pÕ U“\3CsInŒÇ$è@:êûM Sß²À–&LN¸z©wFx»ƒ:quâóD¸K:ñ sNT›‘ÓYFuΕP[(B'žtæ€PžZ(B':0HÖ¬ÈüÀOjÈJçÅvTþ®¡ŒP—¼e>/±cÙ mf›ÒdÙCj× ;øH;˜è·ä¼K~Ã;r°§Ÿ`=ý;Ÿl×H¯¼ˆ$ó)vkl*¦ÌƔߣ”³c)g›)gÛù|{`¹†]5˜°7ÑXh·&!wTÕáÜ&ÜÀvs`¼ÂNÓ¼ø˜ûš„œæ]açëì³/qË&ºœHáë!j>íU2^]dç ¦t`,bÄ@³+â!âý|ßO¬›^6Ð"¼B ò¬‰ç¹¢&DÕÒ;ÑØ QÕoÄbÅmƒ˜ºFg¿aÅl‡˜Åqvô[cxc]õé Èr§½ß‹BŒ†”Û$…ïG9~' „÷wÄÈ ;xà~+oEø1{ á}Åá, øYûýŸÙ΂ @Õá³9E:oççí8wÿÍÝÛ(z»¿¿/ÎN(ËÉ[š¸:oo’£èÖu=òu»¡UœÈß·0ž­–Å„„#>錋”NxqaÛ mìñÏ>žüLÂÇÓŸÉøø üürPd´‰5‡·páƒQÑ{ш m‡"ú-t9G:@Fs?máå¿ÃÈ¥K•v„TÿJ_x•/þS–%½ÏúdÙüéP’Üt)Øà듞߸ü$ÏM—lõò‰.ÜêÍb8L‹(S)}¡9‹=ÍA³ØÓ|ÂÍ‘ôtMcJþÒAðk+¼ø îó‰…T'Ÿéê°ò8ìÌxI‚ì¬rð*$à+(s:`µz‰rzóŽ@Sªr4¹ÀûA Š¿Ä?×Ѳ6g½‹;:¼é¸TæÈoPpZ)hxñ¡RE-v@E½+KçTOkæäÒ_ç0 }ÒÍ>ÒŸahÌôh¶=!@=¨22—T€’ý Òú¢µê¼™7’Ä>0—Ýš¼ÉklobávbœJv؉^a– üB)Ë–¡â(ÎÑ«? 71Cˆ¶+N?íqô†lþêu87Û)Ÿ(åÓc;Žx\oâÈÇ18 DŸôÁÉ´È¥šbÍð8ƒËš¹‡AÑŽÁS/bj©³0 ™ ÏT\•“·8@+>må­#<ÖG³ÇþQ= mTOV8ª'¨×)N¤¿†=—†ÔÐgg`7v ±áÿUÃpê< µ|r<cœ¿îøØ†Œó ˜ïRP÷m¿å¹"0‚jƒ‹g`Ðoƒ*4¦HI¼Í¾z«7½ÖÔ¡¤voGòxÿ¨5ÃÀåsÿtœ0CLÎP<ü>¶©P2´qjf8Ö|à%C±ƒ»¿Ã: @¾]Ð`BP5F¶;š<àž'™Z8*è‰#°Ú¿QþTpeÅN¶D[ã“@œ7MRĬ×HÖáеc’íS“9Q /£~ ‡Æ!ŠrçMë)A$ƒV©Î@ªhHRhÑ©hp*MiB‡˜ò Ð>Ò©‡·H!»¹’Œi¶µÉ=¡7´£ G8ßMMI;ÐÑáLu¦ðQ‚¤AR¯$’*Çt“béFQºÓfºq9ÏN–z¼³Ÿá^ÁyÐ:qö8| ÀøT§Ž*ãœÒ“W ‚û%>Ó ý†Z³œù(í‚}y•ÄSè;1Û m8Ûî 1`«Äx5â…ˆ7cCNŒž$AúhÆPÌÁË/ñ…Àıè[‹±%9hÅ9¡Ýÿ©j-:âuNœ)÷™k@Ë$œ”ý´mpÒtîF'ßòù´™otZÈ­XC[œF$ Ú1[b.y5ja Îà8i}¨ÑÉ·;ý很Vîc˜otÒ*Ñ0Òͺ—”N¾Ã ¯õAãç£ÜùNOŽïw9½AœÅAö×}Çïqþu¾ª­ó±ðzd•Ï÷9q „²+åòKðSÝw^5?@uÔ—‚“««‘ÛF'-±@¦¨LŸ‚2rÆ&»79#i=¤;qâêÏ$Æìïè}IRÿîßÐiñe)ý ’{à Ìn!ÍîŸÛ˜,ã¤þ{Zê©CLwÿ9sRK«4eá¼8é€ó þ5ÿVÀP NK„òSUDÉC”4@ ò^þ«Ræ {ÁßsD|Ę;IìûÕîNвöS™kôe¬P¨Ê“P•eÞ6¶(‰•ÃãÔÎh/ÕÎ8//÷bæo$‹%£"õöãã ãƒZúª%°*Ê/Ÿà )Ÿ V½±î'yQÚ}áM>x™,Þ¸ÑÇ+0<9 ¯^¬Ý^/z@XÅn5Ëöò|ü8/VO¤k¼ÏòBÙ~"±$O*ÚA\9,é?„Q•”Ò޻सòSIJò|“Î[ë$ç%~Q p)çô.Iº¡^—øe\9¹&ñ+˜êo Ý—RÝCÒ$ÿfŸ¶ÙgK£é%)PêëÏKä@Ù·õÀ9P¥h‡~ ƒ^ Œç6A6s› óI²•Ûdr»%á>£à&88ÏÿqF¯Ã[|zø¾”×>OÀžHéà|ðbEÏnÿ1¢„ŸJYÁ‰T@\í¥½ñb[¼êHoŒÒ™n“°;Rú/Qýè5¼gƒ_Åu¡‰ŠaB‚O%>YDo‹EO1£·ù‚$^!¢·Ç¢§™ÑÛ}ÁŸ¡è™Èa•¢ç—m|6<'Às®Ãÿ\Rb›°‡£]€º¨Å½FàÑ…¶ðEJ$=d³Q×Ä—Æ·x,S¼? md\§à¦¤ÖìÛ?æõJÔÜÎ~dö­ó%&€Å¶˜I´ÅLrÊÝvttH+::à?¼ñÈØ/°Áý ñÕ|ñB®I4¿N’ õç{¨èCú¤{Ñ%Ü› ˆ%„»ßõ燔,(Æß£b $ÂÍŠ©Í oôSiª›Tdçí;’D=aÌ)z5‚Û}4o{ÔàÖ ¡kœë»Èõý8××€ëǸ~’P»&×Ï,P>\%®óã\—©&×e*/Wc\Q××ãÔ×TÁõ6ÁõU‡ 2¹®Àåý@®?"â‹€8_¬Æ¸^¢šZÞŸ/S¹^®ÆUÖäz¥êÏרè'é_ÝÍÓ›U¾UÕ{<‘ø¶8ó&óOó;âÌï2™ß*˜ß§bË3™?¨ >„…¢%ø:ev q>“ІfvC}Ó•çRa7`+„&ð{„yÉbë’ʯPs™Ð¨ êªÚ_CvŸIüº –î¹Äo`nƒãvgsËìz¸íÎÿ‡ÄPÄ8»I|œg: ^˜‰0tÅIŽ‚¿Ý Ï}º]e†]4ÎJ»¿Ñ—×è³ñY8šý¥ Ùýœ¨®ÁìÖ¹árÚ_AÊ vÝß=·»­`¸Ì78Ð#|â=\,“™ÙdÁN¬DÀ¶Ùýìyì xŠ¾Ã ðý'”Ã^»iöÚa¬^ãš÷ŒðÜŒ@“¯‘Õs³Xõ€§²Ä s¿Â"—’F¬¤;oI<“?j7Sf± \„?cà8R(Àâ½GpröËæ÷ å@ØE;˜6(÷%$òñ*Á?/‚qÑ,Ú¯Q …ðJ­f©ë/ª¤ ¯£)XñVøÌû4€‚1ù_ë“·ÃÖÚ6Bæ“¢¢*¢¢¦áöŸâY¯Ã¬7©2ÌúŸQ49±ÍÊz›¥"PÖMõN$^&óÝnŒLÝð“þ^¤ÿ/ª;ÉsC"vÄvKYËóÖÒ›˜ÖX ÎŽ,×?êàGˆ— k±xŒ,4»²mM,1dXlÿÔ ‘¾OÁG=úbt­½ ¢[púøÜÃt‹azDÌ]b' ƒSŽÀn_^ÍŸÚøi|{8ÌÛÂ< ”ï¡)qO÷¤ð×tÜÅpñt°í:XJ#’·×§x/ op |Æ‹PªëEL¾Ïà^†çü\õоof¶ÂÇ«} ݹ2ŽA´}>ö Œ™/›=¼ !½ƒÿ“¼Ì©íW0T¦ù“Ÿè Ãq°|Í7p° DBJÈ>7ªí÷IŸÀðèÔùøM,nÄ 9C.,Ð 9¢ÕŸ ÆÙµk trW!;BprTéZˆû¨IX É·cÿ+ªÎ·¨Ê‡;MÕîäÅN¬NR‘§ž7T¤†ecdPB²‹«âh')pbƒ*þ|oŠ˜ŒÎxíÖã$Jo2’¾Ï|¶!€þãï,DŸíÔ ÞðWÁç !³#Õ R- ¡Ò.B¤»¯C¤O£7 i"­‚Œ eìEøj§hLkœBÙ×!þo¿«h3ˆßhæÜ„‘ŸÆ#÷cägfŽ1r²#|Ûy "‚<Ï8QÇpË?ëÔý3¥Ü™’­àžÄÏaªÿÀTß¡T—1ÕUHuRÝp¢Á1·VXæËVO¢¿ —B¶·À¢s¼WøPw€Â›Ío¶ð»NìÑ µhvŸKCÒ«Q9´Îû02m‡ÖùÀÉï;±Ñ5óNl]-üd~2âÔ{£˜Ÿ™¼V—ºt臡­yˆâÈXݽ ¹òëÀÔÙy±+¾.²ó2WB÷A×õ-ÈΨ¯ÓÄe¤¾‚ 4Ê%j`´ ô; T" 4Áehr­ŒŸcQî@Q¦BùŠRáâS]Y JR>Ý9eÙºxpå 4ɜѕ.ÈÕ„Ïtဦà-¼ÊÆ<ÚÚ9.}€B¨FfþKv$y&Ù…’¹pTy)3fý2 ß`{» ¬Ô+W€|.ý•Tëâu‰,£¾Õ»„´—¸„´—»pm Y®Ô•rú©Á¢_)óÕZ!§@k] Ï«e¾ž@á{Z@7A¨·×ËÒ×ÃÛ¿ŸW•!ñ-@ú„eæÿ@âM€³^NïÊl|'Ò]Fžˆj¤PE6ÈÏ¿¾òýú8ò8é¦NËÓ£¨ïƒÕÛç´²ßÅ÷»â(hĸhBãçè™´âB Œx—2ú¤¿ŽÛ!—ÿRfbœv)“…—¾0| ä‚èR¢”¹á"§ë€ GÃ`¸fƒ™jvEMõRÿ9®ºü†!šácº6C¶|‡ŸˆÓÄ!7?Ia<éæç°ZN? . |@È—„ÜèŠËÏ¥ïgàüuŠëŒúøM—nÒ)X#ó[ñ± hz'b[,ååïg¼Š¾¡¦¼ãÊúzD}Þ_AÄ]W¼ 2>Fa?,bêc¿OñÀJÁc1s Ÿw¸BöXa‹Ü á=äJÒ+u#èÇ Z»4ÍǸ¡ `ǺÑÆLX ±mËM¾p$ï¨Kâ(@ð‰ü$À'»¡iü7v? –QéÆ.âñïl³Ü|–'¾«}ƒL˳Ý8lŸ4ó9Û$`Õ“6דLÿƒãÀ2ÑäkÖ›­mì4ªZ7´s;[ìæunÝP ¾Üb·‘i.Ù•S?¤…/q8zΩ´ÁNGðõéÖÀ^ZææË܉ûV¾Âm-§ÐÀ~¥[âÀ¾Ë6TR“<‚¡õÈPË›­™…¯†¡écàk½›ot'Á>édÐŽø2Á ýó|¦`+pÿòÞÏg¸ƒËÍ·º)ÜìƒÖ¿^[|ÀÉv|ÍbÁfo4_[|¼Éíoõ嵂%Ú …÷Í”2À÷ Fq÷â[Q÷ÅP€®÷ç‡Í Úa %iùbIZÜüè.ÉI³$§Ì’œwó“ñ’œŠ—ät¼$gâ%9cï<26Ë,É¥XI.ÇJr%†zJrËL%ù}|îèéÛsàÿ™›w¸±EÛ…OC«’™µ‚© YΣß84Þ#Î#yßÁ¾gƒ‡Î!’ûX‘FÉx)ˆÃ¾Ñ½èXÙåý‰6Éc€ýœë _Ùœ+º ýä<„·`ÌØ|„°`’w+À 줓½‹Vƒ°SLñVl!ÂN[0Õ ÊÇkvƂٽÿ °E;kÁÞŸ¬aç,˜Ó«l1ÂÎ[0—÷]€Õ{|á‹ÐííÀ%¼d“¼N.%àe èñ~’YFÀ+0Ù‹ýár^µ€)Þ}¸³‹€×,`ªw5N^·€^< ÄWð†Ló–£oã Üô…oYÀt\%æ«=Û¾p›ìâ p'À}áv ˜“||-ïXÀ®Þ?Ã=ìüܾäí‰S»¼k_ŽMú½B“~¯8íÝ=ëxÅxÖñÿä?Ðâ›q9¢Œ)ö$ÏJ¡Ô;,¥Þ!”z‡©Ô;<|·Ç:ï&T÷’‡Î¹’û˜Ý@uU§bªîetÙ–êîÕUøASu•Õ=dª®’ º‡MÕUTW7UWIP]ÃT]%Au#¦ê* ª5UWIPÝ#¦ê* ªÛlª®’ º-¦ê* ªÛj©®’ ºG-ÕUT÷˜¥ºJ‚ê·TWIPÝ–ê* ª{ÒR]%AuOYª«$¨îiKu•Õ=c©®’ ºg-ÕUT÷œ¥ºJ‚êž·TWIPÝ –ê* ª{ÑR]å+TWù®ºWQuG1;¨nÒÜ6KsÛ„æ¶™šÛfšã6Ó·yø=0Ç÷Ðóûžu<ô,gŠbu¼Ï-‚ÏÁç&Áç^”;úYœ ÉF'tl•ÉбÍJÖÃuرa8“öO3/ÙìØæ%óÉFú_€ä&ã€ÈÀÑÐ61Z”ldÙpÿY½ŒIâ‹“Ìàs‰/\ êd\hç+’Å@ªNΛÁxC²ž Q| r3–¸I¥¦è*+º*Åû§h=æ¦:m™—Ò«?_b„ïù/7ÐZQMŠÿe k/³Â—›½ˆU›Ò»?Ÿ“b¤ájÇâœ*Ÿ” ôÆ\ïHÁÁÄL¦ŒM1ûRL¡ïKáÁxõ}<ûCïæ¹@sˆª/¡ùóÃ)Ö •dI±¯y4úbäIãþ€««dÞŠ‹ÇS˜› ÌŒOÅ103•˜ù Š™šj235•O#ƒ"ÍH…,d^™*Í3SEU©@º"ôv$Ý)×!éi,>-¿×"½7•ï'1M{ µ?ˆä×Éü’‡áôa“¼Žä§'¿…äÛ õF$?#ü=‹ü½Tþ€Ìõ@ ÿÉo”ù“üS“ü3$_Éìà…}G“…rKÄxõëà½ÁÇ’žm|¨5½Ãpç¸ø—X"†vß§à"å:בgÆ)<èDáá)ÜúR ³˜Ä˜û{ºX1Þ,ùÄ6ôìxÊú¾×7Ù7ð<«oàGð£‡ù¯àg”MCÃI¯ž(†ÛCm7XþÄœ,[ÁÄœ6öc7Yþ¤œ,V0 ÏΉz’»´Ï*fü$^pršáÊ÷Ü0Z™'y'£H<2ˆ¡ _†¡cU1´‰I‡¾ð#þ>öy°'-–tå†ÔŸ—vZå!V¹Ë$=¼K†fÂGKFfƇb× ce wå¼Ks²•}¥ñ/élº¸È?AІŸøèö$)Šé'Kt¾n¬Ô$7\/wÝMm†dÐHºR2ÂO}Fø™¯º?Ÿ%²ÙªAC<ÉB…Y`-ß/øBI×Zd-q-–Ä(­´™/ŵü‘2_†køsÁ=÷$Ji¬´ R›öf½Ä×CÁÚe)ã%,¸ˆ´ r–myœ~C½]6§â6KzÞи­R Û4îo Œ•‡ÐŒi£jY¬ð&I€s¿;1÷yÄù7)÷}Vîû$~)ÍÏÌd1û±Ðx0Ù|Jö!%‹ZÉ¢o†dIF—7ðHЗñpÜ$vÂäá4m’ù$º èE‹èEÜò8åD¯~Ñ&Ñ›&Ñ6$ºCæ‰ÖÑÕBц[«ùáÒu庹¬V"÷£›]vËÙ›dü@Êeƒ$L;³ØÒ>¸7ø-LAg?œVwÀfãÙhL3A}b³¦D‚¥4c6Vž÷ÈxÃ ÕØxÙZÕ¢­×qëp¿šPšP,ܤ°¸Ü‰F©–Êõg³Ä*ÖÐ)Ù@Œ×°XË¡X+q/ÆN™¯’­UÁ$¼(ðI$|šŠ„ëHçI¢ð8g©Ø±qQÆ3—ˆE2»įŸ¾n–çŽl ÿgÇ0çÝ`å€)š ˆslºòÜèð… 5œV~Åø”­mÊ!îNÈÃ5SÙŸ Ñyébƒ+È^i Þ‘Ay‚§v^f”`´<î•ù$%b»— +”Þ Y˜NOŒ¹NUD…ÍÀ5ûÅT ß#Qm°vl k&­2Œ-ÀAÞ!™Ñ^¡Fä`¿ŒÇ‚2ß…Dê©*Þ "ûqåÿ3H}@NÇiîƒôªi¶þü°‚îɦªžäJQ='éðœ¸@éeœ‚ìOÒÑ6vZá(1$õƒ€¥è‹»‰( ÷6~Ò"¶e\QtEÂÅZ$ï–,J¤±%’e{嘿À0Z1Y)Tqª%³PÅ"Ü™t)6¯™hSx›Eü“VÎ4¾ÓøÊw~G±òA–ù}<ÊyÏgÎ Ó»L¾Ž{9ÿÓ%Zv]1Ë^\ÌBÊÇL+Õäܧ0¯~)‘¼›À*WÀTG»V£OQ¢K©Z„I`-ÓOPù$ÕÈìÒWìc0Âî‚f™OÅ׈» "ó |½à.ˆÊ|¾>t‘q»/Ÿ©êÐÉ ú,ñØUâ g‹·#2¯ÆõýeTŸ½(÷¸`•ª‡u™:z ïqŸö[6Ûrffÿ…Ð×[Ì®WùFBMC·h“ªû»vìn7¥@—ùÕ0ÉuéM§–0dÁômLJeÞ¨Z ´IõOÉÙ‰L®H`ò2Ùg²U09ÂÞÏä“+˜B&ŸÄ™|*˜lI>7™lH`r¸µb¸ÛcL‚oû¥Lް&9b²Ì.˜„ži”]0YÛv0Ún19÷¬N`–ðj{ŒÉ¹ô“Ô˜“k˜\h1¹ÐÎÅ™¬û &ëM&Ç$“KM&ad´ÌdryŒÉ1&W!“kÁió$¢\W#“kítJ7*›'hcÎ:lî\/€G:7`D¡Xë(a aº]0² k­0Zn÷Ë鸧¸Å®÷F+Øj'“ƒÖ‘C.דSø{"rÚN›ðÉ-ìÚŠ{;r—ìÂùIù)Ú›‰Ù®ÐvÕίØÑ[û¤™_µ£ÍÉ&›ó€I×íüº]8|®#‘Ø {T,ÅÚ£y‹àUØÁ~t¤ ùØ@öc¸JŒÜÅÒ܇ì§Böìù›Ý½ 6»ù#Èmœþ”Ùø,ô}¥˃øK:Ðaö^±žŒÕÓÙÐ2‡.zõ¹Ø˜T.…èF»Gt¤„ 'ÂÍ'B{åôR†ÛG Û½²w šïYÝ?BË¡ÙÔ‘¯rˆìæ´LË-Ðyﺠ£´ÜQZëðþ9BëZ®å– 臷'BWt´–;Z@W:¼I]Ð1Zî]ëðÞC6t¬–;V@79¼gº  ã´ÜqºÝ:.ïNܸDòjξ÷ ^é0n°k±Ï1! ·ñf¯FÿÇ„HÞ_d @êLˆŒ;.²×d™ Q¼ßÈãßó n°[‡6Ö„ˆìÖd‹ ùâ v¬Ûßut8kéʺèóŽkÏ;:žwtíèx»£ãûÇ÷;›Ýéx^å3‡P‘ƒKEt(ß6±[!‚uµMÆ#yŸã˜¢Ë鸺xÌ!ÆtØ4 0:8‰[962 ºû1Â}=çˆw÷]±»ßc¥s~Ía6ŠE£€~˜NEÝtðj-ü¦G}Ëlòm¿íУ±F=q›#¤Ðú‡—¼zh7Mr4Òõ”ó®C7œ€†z¹ÚÄdðIL=¦ÍI¸sè±¹s豃?uà8 ¶Yà”7  ÿÜñ%üp§pà‹œÂáĵõ“гÄM›™d÷$ß.Ïg'dž¦ÿA œ|›Ýb_Q…³_àÔ!I3n:2ë0eVK{þ¥ENÜŠ"d¶È‰2;jÉl±“/vv–Y½3¤Ð(t‰Ó[ÓéoòeÙ2~J{T ´À˜ý^øè]2qÂÛiåYï4zÏÀX1æ;§¥‘ÄÕV§an·2Âg¤!TÛ'o‰Ã楋ë63e—“ïê”p°J‡ Lq‡TJ‹–d¯™–Ž59PkŸlŸ8­½PNjdU¨a¸A:Èb—hlÃQ”[Š™<ÂÅG¸é»Ð>O¨íÛpë×HW ÉRæ‚–à˜­Ì•àn-F_T¾h¹ zlü…•vaÊǸ°ÓDÈ\>Ö…}%‚çB_®2]Ó1Ñ¥gÂ;Ÿ‚{U¶2ÙíI®âžE›U&h¸KEÆÓa5¼óWÕg¹¨Ù3|‚»=ÏEg!æ»pç t°Cú¤ÑU5b§^µ«Ÿç"mnåóÅVŸXgWj\¸)&¤>OÐFR~|¡ ÷K,‚#o’ÆøbÞ&5™«wùK¥ª•J̈äMÖ$ +®üªMZî LÑ2»øQ¼;Š™ºÒÅWb¶N váÌ9þs¾ŽÅjc;‹™½ÁÅ\!;_í L&°¤|­+ä +×Ë`b¥ë]—3m;˜c—ÓÉ7£È¶1ÙåI¾ D¶“Dö²yIÌ. äN’ÛO’’¸ø—ª–7´k¿Ëlé¸ ¦Õ;Ú|6ÃDÅ(ÂaWH! |[ I@A „+4~ʦ…§ktά%gäÍИ÷OÐÂcêJ­!½®Z¸ü•`Tj,Ú ÃásÐŒ%d†€ÝÄTpü E/7ÅBŸâncû@Õñ¹ÌÌ47ŸæCZÜ÷’E×•ÆÆ± á•î|>Ó Ž{•ÛȲ-퓦 1.OïA»YüUšÕ‚?+f†9 ¬Ò ÏÁ½#;ˆïRÁÉ·5•çæ Ýú%ÖùçZ®.¶æ) tG¬¨Eµ>!jm<ª¢Ö³Ø˜{¿°P/†˜Ç¿§Í”¼ÞÝ«?_âÆ¹ýÔÑ~Ÿ¸Yç6—Ö¹Q¦ƒ1£—ddIUÐ2ãQ¦bË dއCEWÕ5½")’ÕA·=¬LJ¨7=¦âU]±ºŸ$ñCÊh«•ÑV‘ÑÖ$Þ„[=P;“„#4ß·+©߃Ü_‚¨½IX Y|²~€)@ñÛb:˜(`x£@2í7šÄ›“ÌÊ€qüæ]‡”-˜ò3¦€o7UØð³Iäe€‹Bò³ü$Ç'“¸ '·'á¾QY,^¯$‘”Lšôy-‰_KŠàþÆëIˆçFRH…@û RynCyxB]·òö¤N3SwEÕã*ãý$=jô†º—qMH‰ˆ÷§"©Ï:iÅpÙÀCM.ò˜Š¥`©'F|¤(õ›@±Ì£G#âµ[’Õ}‡¤3ÕVw¤Û.&æPSŸîÑ“r ¶Ë|†GLKVbªCÌB] P²:YÃuªa|´€8ë<¸õäžyVß"yÇ\0„òäÁvqÒF=›?Œ@µÖ 6™ú«5C«†þk®–x’ØñQ¥dvéJû<¬hçj8=‹[:&Ù´ƒÏÓp“Nwlˆ§ 8&Â3u›<3QꋹVw»9–ž€lFÞ ÏǤdh?ÂÓþtgP“Ç?ÒÌÌÈ>öÚ;c0äyÆ÷@ê® 4SºOìîh”'š›;isßïÑgdÞmP¾Bø¸„ñ輓¯tÔ£û{ZO–w_fxÃ3?iA"’øYO¯õæç=þ¦w¥,¼ô}ZÆ{6øßñ—2ÜT@1½{‘ÜR¦Òѹ+ÀáÐ13n†³p¦-ÔØºÂäªÇðgš;œ±¼Z0·7<þñ2m™¿é±æ†n¡¶f‡'y¹h‚-my,´å±©-ø<漢?…¬{Ž,ì Mä¹Éa²Éÿ²8ÿÓMþ‹’EL'þK’_àQÿ¥Éÿ‹âü—%æxŽê§eË“¡nT¨›ÉƒíxeÖÝ©òÑÉ¢nÚ@ê¸-clrH"&ÁaÔTb×ëÉߟ ÎMJ­gr²%£)É–Œ*’­F2-™Éqh$ÓqN=ÏtÑ¥VÑVº—lUɼ&Ù€±ä衜5¬§ØB`.ïdº(ÙÐóêÐâ@è\b'¹<HýÇ^䉭„¸ šˆ[<šNÐX&¹Ä«Ít¨Âkbé2{‘W¾94¨SNÛ&‹ÁMÉ|òÀ‡íÉF&ñЈèZú1'Z“MMhMnc'ÁKæÇ¨`…=[øñäHÕIîÇO''”Ѽ,˜ŸIŽIc…žKÖ#$è‹BÐÞo`ŸŸá«8-ÙZŠh§¡Ø8½•l®ä!WQ²¿ ¦à6ŽçÉçyJɽûó‘)4ív³+øR=iƒ&á¬C _˜„Õ‚5„%­‡.ñå!ü¬)¸‡¢BÄNʱûÄ’+1;7@l››bͶVâÞ*ÚÑÌÇM¶·&%¯4înã¸äåÁÎ7ñ¨Õ)èájSÚØiì"xžA“ ϳÐÈÃótc+RpÛ¾º&…îjY›ÂëRz·òÅ)8Žã+Spá—Æí«Rt$Îפ;ÞþÚ:ˆ´™45ÝëSøú=ä0G4N¾Ñ*}—ßÑ¥žÅ̹9…oN 9Áø:ØÅ·¤„`”ÑåèPÒkJ\ÀJ123@|:-ð2ÞË…ãM)Fˆ>¨Áw¤x?°Ù¼8ÎÙ“y³…ïM‰˜˜ûR¼tp˜Â›2í®,ãÛ¨,kSÌû`¾þÑ1ȶ N œHéÕÊO¥~fäMÈaütŠuìQà×ÐÇ:Ÿ¢!tã™qºg,r§ñÎ~à­ ž×¸Šä® yÞª¢z+%bRmK z'E¼Hµ-‘ê³”hoꕟ§è Xì•‹R…ãÒ ]&͘”ŠšAX]Q-zÂ(¿t°£7^‚ÙõãèǤÔ6vôŸ Ò¤T^‘ Æ·¦Ñ§§êhˆ£}¶·èé&¼2•Œã/ñ²–K I³RiR•JmXÏË0è®Nå³Rý] ­+£y¬ªÔˆ˜ÒRùœTšYBŽxu*M`c|^jH-m›êk‘ƒ™³7Ø/jµ°NøÎOEPÑ:À¦¿‹—Rñ~ ²-dà‹EÁ`ëÁ¾’!/ÞO¸$5¢×[Ë‚º „½ê²N˜ÿŒê{¥˜9VCÑ â\ŸÊW§†bÖT}}jÈŽ2åRCÎ 1 ¹*hÂu#ÐÒj6Šß–rÑFí©zÈ…r¥NºÉ̯…øÜ q ÖyÞ=pÒv§â}¦­4AyLØÍC©¦Ý<$dÍ ÙK‡ˆA9 «P%GRy4U˜S¨€#© Zå-©ÑR/zº{±[SûñãÈÇi³Ÿ8‘ x·,æéÔ(Å¡“q㢱¨ó©Ñ"ÑùEÉ"Ǫ_ ¬*ŠÌÝ_KhÔO]LÕ£d³/¡ò¥áãHQĶT³+iK%'[ „í©¼=õK'ÓZù( äžñu ý9h.ŒWº€où§Ât¥É79:÷ÒcÅÜë„ሀ'‡ï#CǨk{ø)ñš"/ñòx%ˆƒdÊ2Ò ²@HLå^Ñ&G㎨ãŒ•×‰Ê ‹Ê /ŸéµL;]áq‚кÚb m±—/Z“€ÖrD:™€´ÅBÚâå۽¹hD¤SL¤>„´ÛkŠq·—ïõ&Ì-^K˜[´ÙN' ®YIyIò‡¼\OLy½SÊ3 ™µX)[¼ühb’’œMHrÚkŽ’O{ùÙÄ$7;%9—Àße+—Ë‚¿Ë^~51å­N)ÏSJ±mê6¥¼ Vï6$mƒvsÛËybZÞ)í…„´÷)-Žï{Řñ¾—?LLÛÞ)íÅ„íZ^sާÃˇ§r±»¥(­/IÓ µÆjibybDTॄ3Õià)ÌKÓÃEøŽËDUÔÿ¢4“ê¢4¾È)¼“_Á-xI­÷%4ùkÿÛ¼ŸÁÿAαmxY” ½ö«Ìº‚ç’”2€äˆ{Õ?JÉä*(Qí696¯|ÉçÚ†²`?4žŒ%§d´i 4ð™‡Ûô>‚HN‘þ=”5w ´3Å‘œ²R&迊ëÞUìÆìmlù0ÛoÚØ]¨!m옄ÿ¡ééaü7z¸\ÁkÛÿ¯‘ÝAveÿD_-\1Báz-p–5ÐÔßúÏ2¦e,¼Á ‡€çá >¸–îýù´…ÿwþäœmÁÉ9üÀ5F3Ü.ú†Ç°±%Œgø•ŠzM_Më4EÌ{÷0]€á?}Û£ŒAgô£†t<œYΓs° ühdx‰¬×øhŠ™e .Ѽ58¤@@O?>†ßsdøº„ø(ñ¯K´Û| gþG”ø#è‰+¯ öºv>…ìñî©Î0©ÚÁx™T+…UüâÁìÎRbs @ìRW3ðl†‰›ˆøó¾aGu‡ÉPuE¢êV³/ÔÝZ&*o3µ·…Qõmc|-³*p3Òp}`K¬7ô‹7²/­¸ÍìKkn ƒ ÛÆ¨ÆŽÙ¬ÛÅxSçÛÁp…›ïz±Æv›5†9ïÕC€x¬¤áxƒ‹YIˆò™¨‘ H0ï¿5ëå'V½èØ*ãõbtª$•H‡8­ŽÁ Žblc¢2Á=<Å@U3QSÏP]|Nm+™ªâŠù.‘ä”<‚Þax~šße8‚Bþ&2ùÍØ<6Îy  Ç)xœY—*à&Dþýùc¦+ãÐ8ÝK [*Ý‘R'ºO€î(‰’èŽGºåR'º£% ;VÒ•ñH÷~Ýé‚negºOî,‰ÏJ¤;éVu¦;éVÝ H÷AÝzAwigºÏ€îr‰/O¤;é®èLw%Òmº‘îC°‡É)}ˆî¼2kSç}Æèùl‘tß8ÙÖŸï”pD÷í«çÓ6þ¥Ù²Øð’5ÈÝ#nµËJŠûãSþ?B{̇Ú^ÏŸ’óÆg¬` Øãö¡ìkùSsÞyµ`*„î •2ó+pgu„>*=ZŽ?°§!à×ʯ¡©Uÿ h>MJIõ¶?‡<¾ Eúšï÷ â)Ex(â‡ñ#4ßÏ€ÀŸ!ðyð—ü;˜âII=®ô7æÕ!¿ÅûB~KƒX¼´Ò$I, ÿF¬ ÿ†ÖÙÀþŸ&ÿÞÿN f¤ÚÖ Æ§‡§)ô)®ÿ¦9sÓŸ8¯N°°„Ù‡ò¡xÜ^ñ¸/dÉëstóæp¦ãíwË5øO.^Q ä®Ðøï›ä(¥-=#ÁtMNJѽ\b‘\dJKÁE%Ì1¸,.aÎ1 Ì=f_deïäcP,8<Ç¡¿D†&@þªÅPÙú8 äD†&'B\Á•¤G‘‡®›p{9щ í|&š“©9õ±ËW¦*±ÓÞS”!éŠ#¼åÃ\5ŒW±À´œý–å­Y”å]˜’37¸JÃÞÁŠpB„SD4`7aE,"Ðjì/€nfÆç±Àð$×j¼„WÂsóZr[³nXˆÛÕ(é´œð*mf»Ø 7@r«·Â«! Y-%Ñ…Èä—•0÷rÆ—ƒ|ܦ|PŸøJJ‚¼^ÁQÊ*x+n.¡5`h•»!½;ÎzQA’Â+5ä{-D…×iÈùzÌ%ŒŒvÞÄÀ‰›ª€IÆ §a±ím¡$K)©Séø.úÚt|¶=Œïaºo´bÒ ]GBåKñ¨ßœN"f¦áÍŠÍ\RA#ÈÃ,FN¯àŒ/Nê !aùÓs¨§ç@‡âßD€o)y›‰a½š¡;Áµ­áÄÝ¿s§bÌaÐ…è¾1ÄÜ9´úé9dïðR§ ,0#‡fÝ.Z„!)Ó±†ËÌ‚ØÍ;‘ÎøÌë*2…fnP¾E˜¼ä\0y˜swÿ†?Âä•)ø7(©G‚᛬tD‹%´0â¶ÇÉÅR½•¬}8h¯Ñ7€µÂMš³&^ôàf bt­Z±éÚ<ü©WlËŸÉzöÉÔ‚-ZþVÍ¿MËÞòçÌ]Â>¶ ”r·iÌö%À†A_S¡+[5à±T’¤Tow`ÒP«="䀋ö-²UÊ(5…V¹îžÆïÿùå\ÙV°R¡#e€E9œ5ËrŽ>y € ²h/Q$µ’ •Ú“¸¹†§ÑnȸxüZàµðÆïç¾ÆhÉø&[#UÊ%Ìâ{ð=\áÃÁN-ÿ[EQ3kP :W¢ôã#ð¼U}™k¹"2xd}¢‰þÔ¿/æì¬PðoP2Ú§å E£+³˜TðŸ¿`¡À;ÊÞϯÌÉ^WP ÁûC¥äÏÌÉ^“W0‚†ÊäÏÊÉ^›W0 ‚‡*¾üªœìuyU|4TÕògçd¯Ï+˜ ÁÇCíýòçädoÈ+˜ƒ¶¯ž þWíg%¼M¯´r¯Pñ»L}´ê[á[ͼA5ðŒQø~A!°_ $ý”eÏ*aáÚû€ÇÇ$ü g’™JÖ®!Ï6•apÎfn·Â+ÑŒ-•ð‹o`ìr´b«ÀöíTh3TóoQHK×H/“Ä·>{=‘®×3ô¼‚ ߌ$—ƒìÎ_!ÒQ$ f3¼K¡åõô^ë X Cžé3n–?ÃòAaÀÓès 5|]ˆˆi*–<]`j¡æ÷ó{,òC›÷Dä·^)¥ë¼Ÿ²Àj¥Ï:‹é˜¤ L9ž,V2q™xè©Ãù*F-Á¨e’›X¥*s´m n³kK¾+­#¬+%Þ ù·›ˆFÞvEæ«ÑÐ­Ž“;äNYäfZäÖÄɵÈÁûy‹ÜL“Ü$·6N® Q¹l’›e‘['7Ö:3:VÆÃ§ÛMDAn6µõqr«‘ÜZ‹\•EnCœÜ‹Üº„{»‰(ÈmFrãä̧&¹Ù¹Mqrç,rç l¹Ù&92›ãäÊñÐäÅ$7Ç"·%Nn¼u6s¼Â'*&¹9&¹Ih¶J {D-¡ éÍQ¾DqÓÉ\UpžWÁùxKö.…/PòW)™«^6g‘X§ÐBíb°6‡¡¥Ô›xK v¹¢óŠ¿ÐÕû•Ü>ƬTPÕ`XIß _¥˜ Ê(·Y?¨¯ ïƯÁŒ0óZ«ø·R o«½4ÐÞhæ·ÉÌo‹°ÚFN˜l£l'Ð *AŠ`›„ßH*#\#͆| ¿£]Â5üT"µúZ"¾í ˆšßV¾¢¹rÊ©=AVwj®÷”ÄæÊ(Ï4þBÅ„jÚ! "o'ŽFGU‹£‰ªàh"~Ë/ÆÑÕäèrT¡~GÓUäh†ç¨R%ŽªÔNÍQ‘£j5‘£,Ú€F)Ôj11µC…¦v©|·Š58¬…u »‘H¼Ìo±@"­H$š@d‰Ed ø$&‘V…/G"Gˆ4!‘‚ÈQ$Ҝي‘ÇDä1ŒlIÈጕÃèÌŽ)ÐýA­ Dî"‘û‚Èq$r4ÈS‹ÈS  ‚Èq† ¸‹ ÈDì•&ËDä9ž@d†Õ!Í@/^9¡ðYØH ‚W1ŸDN"‘“ DV[DVËЛ "'¾‰œJ ²‰DN!‘Ó D ‹ˆ!ó¨Iäúæ@äL‘KHäŠ r‰œMˆ|„‘ODäŒ<%®‹`äh«·­ð±‰gð–tZ½49e=òQÌK¢f(tI>ð’(|â­SøÄ[§f(âë¶sÓ;N+¤á8¥Z¡‚èá³ Ý2?7áË3c°=;ú!ô˱Ëþðè¦ñ!~+Úþ_†°Ó—!futÌ_†€Nšî4o¹Z€=Þò%§,%¨³JP'JPg– NÁŽÛºñ˜_Ñ™ù• ÌãÕò«˜_Ì+Èü2%vÝ›Éür%vÙÛ‹Ì+/0¿¹½˜ k­ïm¬Uøúø56 Þ%4öž÷M»üÁ3+“5(5a*æJˆ}Àe $+bÒö d/+½o`t/ý}[ðöW†Í4… Ák’õ¾ø5ÿí²+󠤽²’e GµY$÷öJ0ªC„¹¯e7wBÈŒ# ÀÈ;¢1óÓÀ#¯YC[w‹){­i'y·GÁ9,ÿ ˆPÔ¾fÇ•ž0<{:”ýuþÜœì;ùs!øl¨”Ÿ?/'»=¿`æ&¨ƒjÿNû¢\§Êð»6V¾<—0 zžü;Š:ñCz¨Rp^á¿Ç­’ÊT{OŠŸ‹F|>óÏcj E ´jzø¼’;a{»Ü+=¡’÷5ÿQê’_ƒÿƒÒ  æ1‚c´¦¬Pqžµ½“??'ÀçÿCÙwòäd7 *XÁÂa’/¿&'{ø°‚,§ºñPÝ´×µ°¤Ö? EùÓ„ðÒ{\T†yÞ!S!êýsÉÅRR'°ö%ùÊWNÖ¿¢ëÚÅö1û£§è¿t6þKçí¿bŠþ.hdJ*NÑ ÖÄýåØýeÔ†{´î0E_²Cª¦Æ)5N¶_pãùC<8ì ßÎà^Å)ò›øs8þÜ¢ª_6cþ€–lg÷Mò6"oû"ùk/Ná>$o‰ìÜl[avŒÄσO1Áudà0 ôÀH8çûNî;¶ÂwòÄå sÎ÷ñÿŠ›~òÇ—€‰Iè[/–ài,'kºCÖ÷³ÿ='—’Xѵ¶szþÇåÔñÕ9=üòœÚ_Ì©Pþ£r.ENT¦ʯƒòëõÿù‹ë&E²UÿßÌý¦­ð›/Öÿ]¬ÿ{ õ_,ÿ¯õßÕd­äG{ÉD+•±ÅÐÒÀ}4U#d»œ’ú®'. ÜÿƒK#e4$ßÿã—Ê”A]W.)È#.šÉ4)ó…}lxù%D9]¯µ/…Âü|þ.M?;×Y"Žo›‘ߎscvÐß  ‘ë…ðÐŽa¨va ÇÈ8þöM2Ÿó*r“ms^mcË ƒ˜ó*Ÿû*ô?”ø¼WñîI™nÄ­%Üå0H¬ä€\û*¯{µ.`ÉØ¿öÂø¢a¶ ÝÚØ™M…GÉ0©¥Ãä9ð1LYÐ ˆŽ‡ TÔžHtI7Lt3϶¤_Ú Ç^˺éFÁp¿sôÚŠ:\BÔÏ»á>¯ï6g×Z Í/l÷€æ*àã~7þ¬›~¢ú†›r´•¥੊nºœ4¼À ´»ÿ¸–{\³aR>¢»ÿ»‘ð -÷» Èñ‘ÝìÓÙÁ“/ëoX㣺ç×åðòîSüŸÖ"ÚM ltw Ù;xVããð­?í½šÔ=°8'íoqTÞ)Ÿó©„|6”0Ìh¦™Ñ¬îù‹sxÕ‹l6Ò¤Œæâ.ÔÉè|%±ú ¾¤»îPhOØrzí•wNƒÑ½ç×l|Uwà$YVuºŒéÖuGao„\×½mÂ¥xîóK—ºóÝu=\ãô§ŠvAcϾ H Wé^úíÝõÌ‚B•7è¹B'fvtïÇwQ.ÖÃ¥*¹¼{Æ÷vaá‹ß×k&|YÄ öÒ袑öDÉ}¨°‚…¢H#xIã‡é5¼¬qƒ^W´ðU-xMãQ ëágJðºÆ›Íd±] œa#ƒ74ÞjŸ+yµÝ?I‰}kç¹¾©U¤ãgO³~üîÕp5÷ŠÊ‚75~Fˆðˆð¬x½ ¯Äk¼^¢WC=wkåW¨€Õ¾h¸IÆêשüj¸Cרü‰×uj°\å7±†&S ý7VP{wTñv­•|âv¨œÝPI÷ºó{Ýýw4#ü¹¦ÝÑXø®VÚÂïwdïƒ }\5ãÏpMg?¸v»ó‡ÝýíZ ] ßÓrÛ5†ôø£îÑH–]»¯±`ƒÊ#QòµŸ"SdZä*†L ïZr—#zðâz¸PÍ̇{Ð{ÙŒ> 5ª‡žÍ@ðN>¾éÄ·ð&ˆ…9i¸÷uRü…9¦Z?Ð@«YpaŸÜCÃR°Šz>­G~}N¬h½>‡Ïè¡û“…”ì‘~¬iO4IK¬yq†KÀdMþYŸßÃñÍïÁkz€®òZb¯s塉úE“‰U^×/f• ôOHhY\8knc\èÁW‹2â-kz˜ ¥PµÊ±®G V”c}üÚ„bc9jsø¦PŒÚ/¯|•0úM45Ìö›üe9þ»,÷.³—/<òoX1Ë_–`„F“JXþJ­„Иaò–¿*'K*XÁ±Ã”‰,¿ƒ 7LÄòWcp5dzOfùk0¸‚†9*YþÚœÀºœì(x¥GJØûRÁZˆ™4Ì9—å¯ÏÉ­ª)XÉÃ\óXþ€ô©)Ø€)ÃÜóYþFD‘j 6dê°¤,Bäš‚M©æ©aù›¢ÔlÈ´aÉ Yþ„¨5[2}XÊR–¿!öš‚­™1,uË߆GMÁ6€Tó.gùÛâ¬)Ø™ÃÒV°üF„¸j 2kXú:–ß„wMA@ª†uYÏòw $©¦`@fËØÀòw"ÄSS° s†umdù»rÛs9u»r°zé0Ëßãß““ûÿ3ö&ðqÇð¼™w î  [†˜”d-'¶å$Ž!Éæ¼ R+JpgÀxç‹w¿/2¹Ù|-OðoàM‚7Áû¾oòÍ â}ßD󾉭õ{3‘Êæ÷Ãà½×]UÝ]Ý]]}Uí)uwSXãçÇjTŸwû‚3?ãŒÒgiùÒ^b?AÌû¼pQvü¹.ƒöó è¿ ,+…#=ñ Sü²ÏÞÒòôú+¸·T| ŽJ–|xî ½ðõêøÀ|éŸöÙgí+Ø—Ôúµ†îÔÄßã iXÞ¤¿GŠA´ ãÔZC¢o`¹LøL T™¡&Í;«Íªf«øÇp6Œ®ý&( 2KKY,ÿ>kbŸÿL¬;52ñßp ÁãÖ½Iÿ/ùŒOZ“tšÙÝõY‡r†„S?‚UwѯØÕ&úãt`Iiu_Mn&kê[„ þ5x·®ì„æÿs»[ôÿ#MÍ:ÛÙÉÿW„w±þ½KËŸÃP°Çíñ&™Hø/ÎêåzÄ'¹•'Šx¢ÀËDk¿6ñT‰|Gm 7Ë£…‘be~ì ŠgJd,E?W`/`ª'èÍd!WÍ‹ig‰_Õî夯 ƒ¼ßµîp¨Ö ‡êèW•#êès0½¡ßPS ¦Ï Eáо¤ph˜)†ÐçpŠA¿zS ¥Ï‘f¯ï¥U}¯M wG¡Qfp”)Fàu´mŠz¼Ž1ƒcL1¯cÍàXSŒÂë838ÎcÜÈë4.û&¶'r^oQ^'R^oS^'ºÙ€ï0³(‚l °‡™AÊÐ47Ò”ÁÓãhäRÈà&6ƒƒM1ËlÉàÙñ<Îu£è2x‚«rH³ ˜32x!‚kÍ`­)Á¼¼Áõfx±Ô ¦Éàeb‡˜b…Å/ÊÁÖ¼ª1ñÝÜðm±Š™'Va¤iеÌb¼ÁÃÍàpç4ˆw2xcœ‘›Ý¨ ¼Á#ÌàSls£Be0läÑG°Î;ÝຠÞ¯‚=nT° Þ‹à}Ið`»ß& ƒ x¨¤&qˆ›„ >Œà EÁ EâÖe§{·Ü=*o¹Å5wŸñfÊñ¦¸áîÓ@o ¦¸ë¶»KCÓµÊiš¸ï.ßê¦^:Á´B—¤2õIÌ ½0)ùÛH¢ «¡ó㑆¥Ï"áYq¶ÜFÂ÷¿Ì–6[à y$Ø2;ΖNâ/<¢Jý*¶ PM1ë¥#%[b'4FjØË[†©1¶ŒP%[걚3‡ÛÅ›Hk.viçcyÚ*©úÈwQSìu鹜ŸßcuÄYÉ^¢bÑöÐy4ÿJJNèNÛÍ&vç{"ƒÐƒƒ¤eóaÆÈDÜ9`ÀÆîpa!M“’W²Äî©c5ùš*nªaÉ?\އÁqK†Ô¿ ¹-C é!#ß—–ó:”{$Àî`7Õ*¹OªÇ |47)´wÕò龈´Íól+ÙúØúl£‰ç’­/âlí´ÙZ…ýÁf®ô\ä½vVGiV`-7a~rãjpL¿6hb"캎“IMÒL¶‘»¶4\v\s³EÜm²q5j2&¤³8ν¤³šÔÁñàÞnÀ?FDWw¿aHïJ”Æ6Š3^;ãôwÛô÷€þÒx9ZA¿àÖ9åXÆå ò”“Æ)MœAdg)óŒ#Ëq)žÎ5zÝ\ØRº€;!„Öu L娛v.n!Ë㥬‚ñÐjÝ MD)WÄK9Ø1ý:XCa×u¢ÌÁ0F=8ø¨Áñ¯“ú]Ò ó¤+ã`èÏÓ¹eMlÙ-q˜õ€Ù(a6ç%À¬Šsë`Qzën­fn}‘Q'¯QöÌK0’;ìw )[J}ª—"}šæ;T :k¹_°׺N·¨2Ä@#œkØ5̧–< †}óWvî5Ê'™‘^“LjØÃŒòÃ¥aÐ-;\ê# šWÐØê0kc ¿_¨Ò±îº8À±n³Á¨OäÒú¸¨XîøØ]nˆ•¯ÝgÖvÛiX ³62Dä~‡Î~C„¯ÞFY±‡ Saɼ¨]‚£ñ´ÆKpÜàþú…ë¯' ÙN¡l›ârK 3w È­Íq¹õØÉÅcC<ÆæÆŸrÓƒ§ÒQ^)Åa(s˜†Ã ðêZþTµz=U•ÊaÔ¿9Æ ­Ð|µ\È­•jrK¸éÞxUN÷ŠÙÞpQn¬.çzÅ\¯¬ËFGHÍóÆër¹×¢_`{)ü¹Ú-ŽyÒÏ̪®™YÃ1á Í_×Ú¯ÏU±ÁK<\Ac©}³ì˜Æn_©Š­^bß±Íã߯äß^Ø¶ÜÆücNµLjæJMZ®Ûo77wËËaLbcØo7÷»÷¼âÁk@wÆÉ †Ù¼¡I 36fWf`fH˜q‰0»ãU¾0«’p7mO¼Ê7$ÙÙ$6ÁbßÞx‹=Œp’Øè´Ø}ñîÝî ¶'‰ã cwoÙÏÉr÷¾ "דd»¹Ó˜8#Ïú dНMæ¬OLÌúÁ8·†;õ†'‹ú׀Гk¹YfR"Ìá8¹¹É¢ù5 Gâä6ƒÜV 39ÆŠ“ÛíÛ,ö¾4¯ƒ wŠmôEâupÁ!p!Y\‚9Áh<€ñDRšHõhf8œÖ§0Ì´D˜VN9033;EZo‹§½Ðq¸0E,‚iµvÆ)FÜ&àÀ5!Iš4¦…hU,5È?Æ æÂ/˜ ¡Ý)âpJ¬GIéÒ#Ã.«£¾ÕšÂÒª-%ÖÛŽ¥ÈÞv9Nóû¤ä@û&2;k+´¢fç>Û0­?ŸÍzbáÃ7XsV—–<èá›lºÑ¿3Nd°ªfô2%.‚^¦ˆ©‰"h`ª˜ú%4(5.‚êa½«KãR!8X†4¤Bœˆ ©,C&¦ÆJ59U–j vNp÷êÆÍ–Ù–¤–çc|¢IŸ/]ì$öÿ«Sm–®NkSiPh‘ƒÂºTš¥+Œ‰â–T9&lM ÛRccÂŽÔ˜º±ËÎÈndä×3gä82r"UvÑS„º \;¸€{6ÀX€3ñÖ5–†¥ÉÖu6ÞºF;>»F§‰±°ÊtŽq²¹§gVZ`ŠšjÚyòk¸–¤ÅkiAš¬œæ46yÅà1uw© ™F!lªsyšTsG¼eWߊ´¸š»ÊfS•kôé …à‚[›FÝ'"íò®GN/Äû×!äôH÷¯y‰ýëb\´:%mMí¯½«—AîjšØäˆÕËqEà¶CçvšiTçeßI3Å=Æ‘böQš¬ôÇi±J’«ôiܵ^¦ÅaUº¬û¸N|%®jÂÖ”˜—n…6¡J¯rÌá:Xœ¯ƒÅébiz¸dáGŽWpɳAJâcy:LK1ïgþ‰ÃûôÞ§‡‘—euº »RáÊMšØ˜.˱)=VŽÍé±rlOçrìH•c—]ŽÝ(ǵx9.¢— s ÊqÚ“e‡ãÁìfº¸ƒLl‘™¸K™¸Ll!&ÊdžÄ“yf'óÉ܈'3.¾ÆgX¡mHæf|;Åñð5%CLË€“™žaŠFxøÚ¦‰Ù²¬s2be›+ë ÎDsF,‹3d&–ÀrÍ-n@?â1™ØD˜›5T ŸÞœQžËrd¸éËUú±ß˜-NØÃù‘8xÝßÝW{»¯þv_£¨êMüuߤ·û&¿Ý7E,̱»ìUÜ,Ö•š)d‡H¿‹sL±ŒÃ¸¢Vä Þx™j¥Ç%.È‘Òs,ÕýezŽ«Q–—ô ¿Çó^;ÙñŠÓyĆ$q&ÏÞMøŒäïY„¥ˆóyŽ•©à Ñep¦ZIÁs[’z-‚€Vò GEŠïáOÝŸõMWò*R‹;s14\Í«HFе¼Šö‰‹‡’äf¶q‘kx¢ƒß+R*R}}îª!ò,úÑÔKÜÉ«H«Hwó *øÎjúg”ã‡ypÊÔˆ×ÇH%OOó@?ï#¸UÍc­O Ê·¢eçIž×æ[Äh(<Ôº:ƒóá3 jÈL1ïc95³‘ÁIùf* *1<'µUoRRrãòùØ- ãò¹ý(x·ÜxRKñàI3iË}B ÷ƒ‡À^%tÄì¥çh~E2t¶|È%qŒh~Ö7]œÈ‡jܯo¦8™E¸_ß,q1¿{ßlq€9™Dc´FÉ©-ùè i³X«Qrïä‹;T;™ýú扻ˆuåB½—_Aý‡CÐk±+=ò!‘¤ LLCQp¢vQô8?1ØÏ(ÛyMÈù Y8‰Ð¬&”«º "E3I ,°ËLµ$©»¥æ¹\åÓMÈóé¦BñuÔ*0Æ,Ó& k¯ÂÍDÔTäfŠCÉ–}œvãO1¼ Š˜Q1‚À*2*R¾£Wd¢Aœr‹cëý£ ¢bLB¼/bj2ö#œMŽÓ…½ØI’îd¢%ºS bTÕ8UÌ fÕÆX¬/jª'fT¤õŽ7Åœ‚ŠœŠ´ÐQ“¤TŽXXÀMsAEz…N¡é™˜-Ƨa ŸFŠ@ŒXFd¸»ˆåÛSÅ*¤”'ºëñ–ÇÄ œ‘z *ÿx’·£ Cù¢FÉßWÀÚxÁþ±“ ” #» ^;ðp7d‘¼§Àv8Lì+(˜Ûëa®‹û¨Ø_PQbU¾›8PPÁÿòC­¦8Èx¤Âñ㺛ôm8DÅ.h3ËÚI4¦ïŠŒÐZM£ e)({æQDÔnpÆ Ž”?óTdpDkAù‘Òwú¾:RºµoaÅ…4:y ½oˆ›ùÄ`5ïîóNqŒyØkn¼rq‚‡ý3¶äI}›‡|.gˆ1—hÈ¿LÏ3$\®Ðó, —ëô ¨KbÞ}§ BcZŠ)÷]|ðæý):’Ä“(VÔ-Ÿ`ŒÏü#ÅV¬Rž`¡7µª›x^ WbiL/Å’HzYàŒŸ©Xu]ÕÓA´ª}Òœa,SÒÄÀnÑþïàý·+ÒÂ˺û’DÓ©ùfþ-nîtƒ¥Ó¬ÜV—ròí—Úš·"­‰1±úW×­Be3܃cñFEñAÄp™Crh×#ºYôÐq‹XHÙÍÕÊÁ…£~´$8<«#èqO ¶§š’œ·ûe§Û צT·–”<—‡ÿlµü2µ­4€]¡ Ï{ƒwS·E4u«i‡÷‡¤’«4LÏïi,¹V£4¶‹ÝØñ0/Eðu^Ö-s/‚oPðjÂkºe®AÀM ظ[ ·©[f#‚oSðvÀíè–9×¹‡B5è†ëÜ÷a¹«[ì>7 Qì4‹EÝbº{RPXé¹3aõ¼ƒ‚Ö;A°—b«¤Æn‚k¬Fh^õÍÁÚ7;;ØÙYÖÙèìü$ötƒézžQóÒê!fצ÷\‡º‰#Ý,¤ÆöÌ ªØÇåÐÝì‹ã'º‰SÝä®Ôip~SúCÞñp`.vWºñ^ÖÕn±eàë6Ö `V“úG€Ÿÿ¹kó}¬ÒRåK–×(%7è9Ÿž‚~+éw‡~+j”_ª•®íQc—Ùò ¹;e®ƒoàý/\âðV¸òš&Žà.ÝX—ÙšåÑJ½KâÚÔ¨QÜxCÜx£¨êOÛ„x#øÂ\™ýÿcSÞ(ý¤Ü{Ê”<¨Q|š›À2Da÷)ú„)ã þEu,†eRüISºÚx„øÇ1|ñôpè”Y”Ügˆ›‹€F'þå8ˆ>NU5U{Ì™\È7ðà>9\Ø¡<¡œãù”DåÐB.‰gX¡Zˆ"ÔU}a¶‹úÂhv¥1ª0Z«ó ‰1…V%‡o;¹¾jæ¿ÃúMa4p×·2»/ÎqFJž‘¾°€ðÜÉ;ÃBì$xaLÀËôâ©ÐIXŸ€ªÚ8&¯MqBĜ µ(‡„t…Z©ÂõGÏjÜ/¢V§j¼Q¾¨µ6 Vq-*K qgˆ#ùhA GÎËwµŠÕˆ› R›Ò¸Qoà¸jBÜ@LX«( ŦB‹ÈOTÕdU«ãöÍjÇ÷kô¥ÃLu ¼A„‡gM­â>R(ŽZ¡kZöwqÇÂ*Œåü Vg©x"…"RµQø«ÍUlµÕ¨¼ÚZE=Z(Žºôi“Í熋X l/Œ­¼/ X¥ "·Õëjíd¡8 ¦ŠS…aš&iÁÓfæ,XKü*÷/€ðàWúùBq¾°<¥Bó¥(ð¿s¡°Åà¯Â(vùΘJÉZEŽ Ã%CkŠPpU­1X•ãÀeV«`;Ói"®RráÚîVay*ÑOåë»â65½efè,®X°§D!VpJø€r¬rމEðÆ{þ¥ôÆû´÷†'©nEñþ«õ.j¤gù9óµW~‹>-°ïö2Üä7ÊÏÇ+ø}š‡ØÇ¬h¬x£ü‚)-tûzåÏ™½Y~ÑËÿzåS†ëD»™¬bOü/_c—oÁçÊ¥O¸´X« ÓçÂÏÝ¥O¤´X­ŒÐgóçžóJ‡²èsõŠÒçhiàQ \ü¹ö§¨8¼ôƒ;#j¾ü"¹­¥Yµî>­¥åCú—Ì’‘ÔG.~ øþL ¶–Š¡€ÂÝUW’Sî(Œ{ž’Ç‚ ÊË&a¸*_j¢%É’®x+gèpi,ÓÅ4¾ù0Û¸bv~+´ôÃàUš€º­E£iéBwŸkfÊk¦hv÷Y¬õ¨\¬‰Eî>×)ì:M@Ý£¥¼#µÔÝg‚Ö½r‚&–»ÑÒ¬7ùIŸ(îÖi%cj•’šÑâ†u—`´T¬±ïL¬ÿÀ ÒùÎÄZ•Œ­U¬Ða²É d±Ù<¢÷(vu/»ajÒêç4ðÉ)Å\àfçb@³G,ÆuƒXÉéQ9@Kqí`:×J>­u ×˜\+ÿ4àoôÔ´â’Dh³¡Ku¦–’¶yL±‹âköš|`¹VÔÌ>žv{úL׃=ͽH|¦&ãÆsMX„óTcs©aU¶Gw‰ò3CU¨Þ¾ÅÙéÀ=ˆ{8PçËô¬úFiKDo¸¹¯`è®w œÌP)ó5*2ßàd~¥“ùZÕ„iÊ0jt(Œ¶QƆ«±Œá2Æ7 š8©¯sRœÛ Tà —í×1P3ê=†šå@Í‚a:Je;_žUëL}QßKÔ¨TUºXüY ø«üUªXƒû5ºX :¤ ®‹ÓYoÓÙüÙ̾ßgü­¸'±S²ÃæXj­ŽS(s6‹aÏöÁÖádÀ\ÒI’S¾Á1Wœ\\Qq¿"ø ®²NבÚ<¦ðC†{ UTßCd¶ð«_àæé`'Ôù5tÓôSÅÔàøÏ|.îטÀ0çnÀ0MŒÀ}ƒ!º¨Ç±þœJšˆÛ“ã$§H’·˜ä4íX˜P®E€_B@”«9!fb¶PÌ Ä,Jˆ9Œ‹bt¸Å“)¹„˜sZ`t ®N¨n59å¨ì9Bƒ¦ñýV>î5ž†Í»Z‡Ò@ÃßSznÿš{ .pZìZ塆s~â™pnø8N·{âNwàg /H¯—Z‰Pÿ~åXM Ô+µ¥¹] ң̎Ý*™P˪N/?¨ÑxuPS(_b(A$ñ=[‚Ð#ElÔ¸^'¢Ð­»Ã¡&fKI¦'§äqáæá~Á=pÛ´|&_éH`×VÄn×­Ðh0ryBîuî/ìÕÅ~Ü­­‹¸»°‚‰0Ð@?©ÃV<†cž äËË VhÈ·0ùïrL•sÖ¾ÊÕFŸw¸²Ã-”Ð8]ÞjøUŒ×â þªš“qvªa…ƃæêy9Ó¡9Ó³Ai¼.æVwÈ˹ ³&¡9l™Í†<³¹6!¢ívĺ„ˆËˆ¸jG¬Oˆx„ˆ'vĆ„¬ÖÛ—BÕ YmpÀ7xqg \9A“¼”U’%“qØ~“Igàù ³ÐË·HLNÉåàee^±8[’Þœƒ”ô$$½•“–‚9â E¼â(’ž¤ã<s»ú'Ðy:‰ÎÐÙžÐ@^:t^zEUÑ™¢‹8ý¾#}<Ž¿OH²BÓ€¾Su{’Sþžcpf¿¨J˜ò„å´$1ƒ¡Â9﹤R©ÌJM ;M³’Ðý‚”|³“"<ɘ›)»c’4¦ç]z.Dò»’ßäwò $¿;!÷œóû’Ä!¤B*Äa ïI@¿ôK„Þô½ è7ôIâЛtqèû¸wÈ zô'„þœFUœÖÙŸP©u8Ù>„ÏÂH¨Ô‘Îaø‘Éb4ÃdœlŽœœ¦äÀÏB÷pdøPBÔ2D­@Ô}DælȼnCÔŽd9îJ¬Ö‘Rˆ‰#ŒŸÁ@GÔ–\ìòcŒ‰ç礓Ÿ“Éâ4òN@º ¤Û)’€tßAºŸ,ò‰þ„ì ÂiöÚ™Á)µZ ÌÙ9š@y€&¥0åÖ„ðù_(ÃÛjj;Âw¦X¡Å¨©ö„šÚÏ󯕻ö§ˆƒ)TS‹uqì% ŸúB_ôãŒ^Æ1לsý×R„H +K“ñKôpsï ÝÙ%º¸ŸB¨U6Õ§àT~÷Êg| s9#Å/R3åcS­Ð2¤x"!Óœcï“RÅ”T¢LúìTY?™ r}Qª9§X¿ÂÁ^‘*Z€u:k;°vÚXg°ö;XûSÅA`MÈêY`§¬¶ «ç²zÕA»š*®#«-º¸ôó\ßÝèÐ_¤˜Ô¿UßCƒ.$ЃáãÒ¬ÐпÈô.E½s|rš˜ÊÒ:ù´4SÌH£ôÖè8GO¢×Þf¥Åø?;Í*™ü1‹´…8Î~‰%O¹T”qº¾êßIðL£±~}šXÏ$ª¾ÙŠóYIÊtú7¥‰Mð¶]G€bsZ„Õ¢-i‘Ð#Ó/¶¥…%‚ØÎ:ÐÙ)v¦A:_Nd©“÷ýiâ²p… frä©4vÎu& úl‰’û6dÞչΧÁë³£œO£¾Ú¯U\H³‡ý‹ia¿¸‚PVO`áséáÙ m ¯©*öOdosÎJïP.•*µé¢6p¤‘Ôáü÷] I<6­H¸ì‰éCqäûz‚ šˆ£å“ÓQ¾ åkt7¦‹™À¹™Ÿ5ÀYGélF~n%4™-Ú–t± éoÖÅv ßVUÒÈ>b CéöáËCéòð%ž8|y(]DÓi’€£é¦hKg#“G5ø"­ß—̬Uã÷'@¸ƒ ÿ„ ßNwŽ‚Þ–7|©tlàè“~éÚÑ¡ÌÆ²PÎчƒ£SÄfdéÓSêÎùuzè©iŸ™â`re—šó٠ǰÅÅ q>Cʺ‹奖/ª»z•*U¥­âîLSƒÓTq%#\ni>Ks•=7I¸f„£µàhM\§·&-ؤ‰ô¶L .ÓÄMz[§×iâvF¸{ð…):(DžÆô&O¢ÜÍ`‚\LYÉ/2ì³í/2ølû‹ 1 Ó Õ’nN\I%¦YØ@ žá°A™Vkë5ð6û8ÖH>ǾºZqÌädÊÈL16“T}Il«¤©áøLÒø%­¢UI3õ  õ„¹U'¹Õ”éxñhÊÄqýÐj=ôÒ ‡:Íìïâ iÔ¥bæC›ó2ËkÜRðUÏ®Hªý™Xj&Àåg¿Æq¿Çåzª*§/nŽågs&ŸïÝ ¿»ðǹþ­œP1éc.v›ÎÂh$“æÛ4-Šfâ0ê>ÝDkf8Pã^É'+ÚÁ—:»¬?NáM~ÂÇ|ç ½Sö@çR}ΩþµÔ¯bY»‘)neÊÁ´#³û¬ÜBÐS­d!ÁÞÍD)[ä²uf¹‡ËìQ¬Ð½¬ÊOc1ˆ¿P½$î«Lîk{´U}¯­¨ÊÝ—µ˜ÜA¦Ôd™b(}VaµdžºdƒÜ¢ºGý¨€áY¾ŠÕôX‡õ`O¢ ê³bý‘Yr¢?–‚t!ÞÐ…øBìÓšã@¼AǺÏdÂ{¦eÿE3 [S³ÄT¦Þ¿UL#°’¦_bi60Àªö7WVëbºŒ~'‹mXôç\̰s1KRûë·Ô{•Yb.ˆÌüѨƒÍÃçÒø“zÙ‚,Ë·OwÁÒ̬H¨ÖÌþr²¤Vq/Ê‹³m¥b GDBƒé7ÄK‘ùi*K‚î¾~¬nÉŠÊ=€ÕY}¶jÑÊ­šX“Õ§Që^Ù(ÔnÄ—U2’S¦@±)+ШñZëf €$añù¯­(YVÉòZEr gmweõ­ÅB+IÆìÎêÓD!+ì’5{²ú,£•vÉœ½Y}ÖQH‹B²ç@7l‹ëP–¡‘†ºDVŸé4éž®‰h–'ÆÆÇ‰¶,«k;žO5q Œ_ªêu#¤8“ý£‚Ú_E›8'›ÈŸ›«¨^/d‰ h")¡¶L‚³`òr_\Ê cˆZ_c°Æ/.g¤„ƒm™Ø"#ÉDÒüz–¸žU^Ñ«ÂÂ7²"€ìͬH`xJ°Ö/n+BX¢Ùê䡱Yv y²¼*»Ci¡ñ¬šž×ilœ” ßëõ=ªÿVQMü©aþQ“)øYnw,ÈeìýUx2¯ó‡êßg'!xù~MM¯#„–¿a惿Œ02ŽP1$;¡¡¡Ùa«d–L´ä ¥ö„†ec•'û±ØG¯/4R1Cƒý¹¨«z <ø{ ¬Êaq3Š‚Ÿ—ã±AÖ3Žz6d‡CüVÉ;•9¹¾¡~7LMä: [Cñ½Ð[ýÍ044‰˜r]z'¬n˲£%{ÛKAÑ’ÍØq@ƒ]žÝ½º–¬Å ‚¸ÿ›Ä@à ÏÊì„ß’ŽâÈæ*¤tÅvz8Ò«Q„É,PŠ]Ut«d{™Ü“¢5@¸a#Œ5ÅÚ×!ìpF˜bfÛe«3Åz|¯µËvŒjЏÚò˜ºb6›tÕ ¦¿'•\¾sòàW®ýÙ¸ø®|¡‰CÙRZÎf-¬l©„q e€_™:‘Ûà6Ôi¾¤’{±×íØˆ¨ÅÕ¨ˆ}„ÐAš®'§<•] VŠj°ëTSÀ—V¶R¿›Ã#¸{n¯„ù¾Â°œ@´´¦UŒÎ‘y›EœÜø¼;5\UÙîé×.¦åDJ纭=U~§ qiv5ºU­xsD#a½ÓW#½Bój”¾hʉЯØ%fæÀ,£9+š¥Íô ó+eÃýnì™&‰¹9°â]Üé£`Î˱*Ôp#ÔýÙ9ÒÉ+æœÉ é/ÍÚMSŽ…9Ýýbqj´¸‚½.ÇÞ‡^—ƒ«&¼,¾—hjèh—´+GÈá ¶(u·žkXë?œ:M%œÞrÝÈÁ‰äˆ£9_ÚiÍqvAÚ‰\'‘Ë‘Ið²àÉA·Hpþ–³"—ï2Ùù®»9â~NØÂâ-¾06WNs­PØÞG;û!{ahBé'æÚÓ‹‰¹br.5Ȱ.¦àè÷0nZïË¥'œƒqjQsÌÜ45ðã•ì·1·üÇãÿð×JQ•ö[Ïo=ò¡YŸ¸*Gø?ʰ~éªÍÿǯ7>ÿkÅòÕ.Iæ<Ýr/J‹rIsÿµR>Æ_rð_|cü èÿZùgí¶’ÉGÙ‹} |Ûë&PëýÉÚûSItþÙ]6Ö¯Ù©óË—/}†ÆùìïW‚NXyCWXç3ÔX7Ã6ømFÿmå"Ý*þëÊfݲ|Ïu—ån¸>q³ý›y•›|VÙ= -»ðï!þ=Â¿Çø÷ÿžâß3Ý·¸3ï«íè— ¥—P\¹÷ó’¦Â憎tû&ø•OÛ¾¾»r3ñ´Øõ»ßª™¤Ý$•OôÛ‚|p²µŒ —$¸¦„Ù£46eYîR}Œ•e9—Åÿ•õÁE¢ÿ+uLÛ©n,_µAÅôUÅ[Á¹øa‚¯pIÐò 4¤‡‹’§ÛŘ.sô”r4=–£•<*tOðnãÇìŸD Îô‡KNÔ*ÁY~€·pzhP¾^>W•/Ío†{g¼«—ÊÀ¼7äF¦›d^^| qêäe•¦ñ "nö2]Uf¼0µDëP½Ôƒñoþ Å¿a†í¦äÑë’š"“zDIM‰%µÚ ¿Ü»¶¸³©wh õ /¿«Ê«­SÄÝßx¥2Ö~üé×ïû*ø3¯‡_««/Á·ôø†¯_õZð_ÕS¾R<ŒpšXÓS&ÈžR÷X‡×›b=¥kãÆEH ²‚î}Œ¡ÓAÚ¬y éë]¨–­”$éC#Îu•œ¥yãã{MôkÁÑ~¢„X11ç(æI,†(mÑb^×Ïða-æuýŒžèZåŒþŠk•;wq­²-Nê,Ÿgˆ“:Û…ÔÙWIÕ|Ô…ÔŽ8©s|¶!Nê\Rç^%u·k®vÅIçs qRç»:ÿ*©º®¹Ú'uÏ,ÄI]èBꫤîuÍÕ¾8©‹ µ?NêbR_%u¿+©qR—@ê`œÔ¥.¤.½Jê†Ö…Ô¡8©Ë u8NêrR—_%õ k®ŽÄI])+NêJRW^%õ°+©pœÔUŠÄI]íBêꫤu%“ºRG㤮u!uíUR»’j“ºRmqR×»ºþ*©']IµÇIÝ©cqR7ººñ*©§]I“º R_ÄIÝìBêæ«¤žu%u"NêHŒ“ºÕ…Ô­WI=ïJêTœÔm:'u» ©Û¯’zѕԙ8©:'ÕÑ…TÇ«¤^v%u.Nj¬#qRcDRcÿ›W© X I÷‘ŸíÿϹ•Ë¿O ¿žè[ê!ÂáWQ£©ª†·; ìΡiéyîß-oI.úôÍÊ</wµ¸+Ä{<ëeÜ9 ‹÷ijù!Nhÿé8<áåþ_­Ðbõ†›.þµ½Öókñ8¿cˆJìCÇÉ}ŽÃ«ŠZ ¼GŒ÷&Âk§¯X†?õ¥†‚,?F–=oR– êÝò9~y0þk_¯§ Ç5žhð XúŠï¬eÅçÊ÷úœ(-Yùyå úlùÜ]ÚçdiɪÏ+OÒ§õ Ï_ô9UZ2ö7•§°äóTKp(xròsl°jŽCA„•ϵs@ ^npŸžóšåkÝw½ ¨”ÔoܹH C©˜ü2ŒÑP¬î•§ Q’¾¤ÔSR³8z|+Î#>­Ÿ:‰O)©?昅£*b‘[ï[¬˜ða®\aˆå »Ò+”òzÙÞì)* ¤3™ÍH`«‚u·z<Ý㆟úÕH·Z÷ÄÒ½à¤{A—îjƒÏ÷\¦t¯"ÝÕ†¸¦È-¶£éì°]GºÒņxÁéÒU –싌ñîò=}{ºøìnƒ›ÏîÎt× ì𦩾Ã?Á¦—͈+€Øâ¶|û ,GÖêàÔGµÕq‹»Õ ½aM¸Å·U¶ßp‰=ô-Ïjo1úÃ`Aí–[ì…nvB;ÜbÖê˜ðaÂÇÂÇÜâ Þdˆ“nbùFîm–ŸÚà´kÚ5·¸á7/#ßJåTºÍ†¸ ´! hO´'nñ,†öh”å@Ûbˆ—@Êh=mŸÒ¿T«¸†xÄ03(Ül{ ßä cí~3RÂ;Î{êéãÁmN§Ác•m'†MÀáºGMIÝ©0ÂTû|i+ªª…EŽË”R£G4zz´Š™4ìϰír­\™íéP®Ô*î91ۃ嚫r¹†ÅBO„—› å”ÑÐÊËKêš EäÅ2O´ÿ;Ù|±u¹§|ž?ê›çWè‰tð ×ã-¸nqÊkßtCÄãeóýìÞ‚¾ÃÁM>¸3îþÞFA%õcDõQ=Ž(j@')j¥‘‚2zm1J6öÎ}&~ÆÊ¸Ùÿ VxùÕ FtÒ Å\þjÁ-K±P+ç>‰óRÁ%~±ˆ9ZïþëöwÞýƒß*_÷zÄ2}­$xï S«98ð—¡M=­Ðq)*pv½–àýü)aò ¤4.½I³ÊpL"Í­š©ÌQV)•ç?]êw÷R÷Ë&wH“òó%´ÊÈ^ .<úkšl‰°VìjC`u;n˜'E#o\”á¡Eþî,ÝZᤄJš…\µ%æêI­NÌÕq2ûÏqF*»$¢v„‹Cxå­b4qþ¢ª[ÙÀî,ÀTfnÊÙyÜYÿÜÙéõxÝâ"®@5èšž’z@–é®,e¿ØÕ.îË’-´KöPaJå¢õÕ2:nͨtíläüš}ªÅrÁî-ŸÇ26Ü™|Jl~ŠR¥³½$÷>U¾VCù¬M Ð#c?kg—ið²BxQ_›á.;JÙ G·µG‹]ÝÎwvŠZŠ,jð¡ö™íCmö™&°pÿ .Ó$Üò™¢wm ¦qXÎtÝ*;Dõ=C— ½°Q·Š¸©6âDV J6áÖ:N+®.m2bÛôô?ŽðTv„þÙÿ>¥·ÁÈ  øÏ¨¿-ÖÅbPÏc’¦U,ÕÃ,i–QéHÒl •–Ñ`o…D‡há/)PVñ»-PÄjä}7~.%„Ë&; ÅÚBÅÙm(Õ$ÝM úc.Ô)¾R5ÿ_]§¨^æý«‚‡õ—î º¸ —~/0ø½Ð¨ŸöüžR5ø½vqQ†ƒCß—ôh$8ä=qY'EXzѼÊ“(?s(?“”ŸIÊ 1À°)ŽS®6$冤<ȈQ®Á5©)¬’M’5KU߬ngê3 ©{ÉëUÔÚHxµ‰¹FªvÏ7Ä|#VÝ.š +1Øjä"Ã*÷ôò¸*#†XÂÁ@Ï‚Ì[*?˵^š \^‹Ž–-ó+¢…’ŠrßZmDýb{m™ÊYìÍ9”Îc({û .</H5´ qÈ€=RêŠQ huUZ»Ñh„ý™*eËzºE%ŸÆÊîûLö¬Cö¬!Î3vÇ ˆ$ÔŸ] ^ˆ-÷ûÅ%ƒ0Lç!ÜdBB ‹Pð4ó:z`Ç“½ýüâ—w†®SÆÊå Â¯^Rûæ#¼á[=èÉɱU]õV&LÕ{˧xYþV8ð:ß ¿‹Ÿ+ý.Û µoŠG©z »Â\ü9•)±T¦xÅ4Nã­=›j`xº×Ro¸ý¢ÑKÂ¥ÝPBÃS¡ç=q™§IW‰ eZâ8¾±þҵċ‹kzƒÑf:iT[ûkáÐo ¥®¦M¬äè˺`¯6áP‹¿(÷¿ÀÀ—׊8rt-}sWò:ú,F ›âßbó—0·Ä0Ñ´vàÞÛL.þÛœå½^ûtÍ^/îÒAŒ±¦tÐ+µýÃ@˜¥+„ð5Fˆ:Q¯hõÊ©A€fó”à:çµÏלóŠ Þ„éÚ@ŒFnÛöófÞwå ÏA¹æåÖsÍ+n$b^ï‚97!±;毸—ˆr£ ʼ”'^ûèίx–ˆr³ Êü„ü H²SÄù$&%`Þꂹ€1ÿXÎ&óö@šMjÇ@E’$†%âŠ.¸ pG3n”pGîQÂ$Æ&âÞé‚ÛLÊœ’ü#{¡ä_ËWý‡k`?ûô­Ø‚×YÙ„qûck„ÎzLvâzÌbÒ!SÓrïTÕ)âg” ž?ÇjLoŠ\‘øßi¨üÿ¬Ð,…,¥ö–šöÿ=!ÿèFt.œüSüOšŠŸ1Ä¿‘®Irè9ª&ü³/c²YŒ>K “+t„—3ásÌ4geš"f`å¼\ÛiTL1k,ç 1 k; 1'¶¶3k,+ØŽvR—ÀÊ„ö8 ìQÄ>$pI&°Ÿ8ˆ.‘F— q$–€…Z8ßg2Hà%pÝË%× û"ËUYVq’¥ û‚“?Hq½PD'Ò¼!Ó¬r›bV/®°;ѽòº!ÆVOøìÊê„B-ÀBO³Û ÝD¡Öp ÿÂ1Kœ’%n,u¯¼mˆwœÐ*7|…ÆlmáNÄz·U¬TÞ4Ä7M‚ol›x 2CaÛAã–µ"fÄ®X¦v#Sk©¦¦-ssÚa7_‹º­Þ; D(iP8g¤Cc?FŸg v.tÜm¡©P òçøgˆFwù(OÙ(üJáí „ƒðR"|„w$^å^åk@ø¢$¼–¯á‹Ùá ¼“ÑÂè‡ôCnqèO$ºEèGÝø¤ZÆ„²5F£TŸ$«±»Ÿ@«ër=Ñz*iÝ$ZÂO›Ö­{ õÔ 9I´v'xVTzHG÷p*ïqŒ\¦ÇðÈËôa€p2éÏÔÃ–Ï CŒô8)ŒBƒÞËø=¼ÓåÆ{Äï¶81? ðûtÅ“–þ †_ç±/\®óð…Ëu0@„®…Sº‡àÊn›Çé(Û°žäåÀ…·Ì»Ò}Ji‡DøšØ^l,ÉÙÿÙ‡ô0'dú‡Á U A%7ó`O çvqÔ€Ó?£0àI=;éá™âIÖÃÑޘœõPç{hä1Pzðj7塲)_ae¡M~+4L†]”a[•Ðf ¬“—d I-8X^æÀîÁÁé™?‡aj$öÈÈýæÅðÀó4³¤'vA?)¾/«6Ï¿TP„½ørAøòË¥ÀÌïC Seé0ý„ LÌ0ª_*1yáü0—bŠ,…\9Ÿü1/œßÕ•áX7eé»ÞY³•°NŒkÎ.à ÏIeÿ”^Ç«¯²¦sÔWXÊh'¾&çSÉ#¤­¥¥Ÿó8Sµ§}3U19ÙîWÄ5°N÷íð»ùÜ®ái±Øiˆ=ד×ÞGر3b±ô¶×Ú燧oŠæn<këò·Â¡ýþpè€Ë3Sp2ø£¹e=Ö¬òo†Cû’|ßT*Ó\ ÖÓ¨êg¸9¥—¼QÕ»­¨ê­vNñ¥&ªt‡&½qŠt™"XR‹¥7™â@Žf–ÔÑëcIb±^c_|½W¾ƒëuß.?âåÆwįôÏîÛDúÀ½C™I¶aº¢FeI ÓËߊ„,$öó²f»®—OñĈD㋘í¢Ëäå½éIy>Þ3jóEBí¾(µE1RÂäC(B´¢ô;ê£ôH¨•^Ûè·Ûß«w ×ÑX,á£Æa¡ý ‹NÝz7p—dÎBOõÛÊðF¥¼ýÿªŸçß§E 稌­üœnýŸ¼F+ßh(+’ðŸ»Ý}Ζ¿Uy–uu}ž+-9Eʺ£°{‚ç °Ÿ§Ì¥güÞ…ö’ ¿ìd…}·ÒçœQœ\Ijô>FÅJÏÈbˆPž7;ZùÅ„˜[ˆéÀ¥/Å\Òq£íkóÀÑe¸1YW6yi²N„/' /‚j¶„ô„Ù@¿Âè?à˜GÉlñˆÕ˜ÒÎö²Žº†tÔµ˜Íö’béèœë¡â\åÂugôv>î Œñ†Î”ÊË«_àË*;SJ} à×h¨LÏøƒŸu¢³R!:ëŽGåK [$@úV…/{è­Gð˜?K:W(‚Ô˜dVØè âh_ç’|À´o3mlŠßöÐä‘°ÙáûxëÜc6Foá²½†Â—IŸ@ÑÝ‹ PºÁ”¾Å”ªsÕª¤JÔB-xæLo2oÓz86¥G"ô)ãNµHÕçÿÊ5‹t‚fêS³T©wÜÖÝô;Y-ªdU0ôÏ:ì@‡UÅþdoÙ¯"ZÕW‚6õµ·4ïè¸Éù·L3f0s‚·,œæ¨8ÐæxíA‰S¸ôš.¿>…+Há®®ƒOº9‰»ÌáŸIMå® ‡Rëà M{WÚäxHúÏ©ÿ„{¥tŸ¨VàujÀT¯xNTÆy«K®¡¹üñJ“ŸþÙ' G—RUÔ`Ò³ü£ò¨ARÂ5ßGJå$/ÛøœäµÄ­k}Í^%xÂÏV>'y?«£¬‹ZMšÙ¬Epv€4«H÷àl%ý¡“$ÅL¸ì©­£º·‘wêµ~8H#ÆÑs›îâ#.h0z‹þǰ!™'&|O¡WNôBíâ܆&zËzIùưu4–ôŒ9’Ëæóá‹•r ѽð›|‚‚TJ4—æW5^NZJhÙ+™µ1çws½ý³ÿή/÷:M¬’5ƒ8•±.^íb½Í.dí+ÊìݤE£àm4ÆØ­_b×v°ë>é±é- ³k£OìÑHi Øú©Mâ f^£ÏUNóâFhº7 ^NŽPÕÍð~ëª8[:«ØÕk†×]9ÝËæV§{:MŠû {á‡ÃBgüŒØ†¬Mó–-#>µÛÚÚ †(kú¾KœÖ¬•^f×yÍêNïòèÄ޽8ó×Ì_×ÄMÂmôrsëH }×&ýÀ¦—"OF tó— ùeË3ɺMs ó«˜Y1´"¯}Cõ8ùPIVò¡-Ò2z‡}½Nn´KbŒÞ•Ð…X™ 65è §Ç"ۦà î†Í \˜‰:7nO“ôWÅÏT5œýì½êåGѹÀG7fè_î•gýòŒ:þ,¤Ë";*Í#Ý£§gLÕ˜ ˈ oK­o™.×eÖëRñß@ÏÕuŠg‹ŽCáÞç°¯óœ‹ÏA­ÒM±Fÿ*ɶV—’m½n/ñlÑËÏûÃÝ}çýîßõU3ÿIq%‰Ýº#‰®Mñ9Á^=…©Øž Mñfá¼ÅAýµ³C:µ˜)^qD§©8g½†s]Îz¢zf#’=žlc<ÙN²§âÉžy}²gídÏ;É^xM²—ìd/ë™ßF²7ô>7ŒÀE£ò†!nêg™ëÖkPoÛ¨zæmÕ¹T¬[÷A÷ákpÙ¸õÌð±ƾõ µ¯&vè þÐìÒ ÍvÄѳ.¬ßT2è´8Ëtgâw;Žt =|¶öwÕLÆ»8 Ôb^:töÒ¡{µ7+;;uÏËNúû7þ»ó²³¤³“BÅ3´ÒǬÀ…eW­6ì®Zmd–‚à Ôû^®7^;*4H P 6$7Æ™ÿÜø7X|£ÑᢟÆ8C²#bs¦£ê ÉˆÍ ÌK’›è­C É‹ˆÍ §€*PõºßßÙ©þª³3öGßb<š<ѽÉé[U.Út*ÚÛp_|üëðNeœnt(ë¨ΡçzæÒóL?ÏÃì4íçöÌo¶R~ù?5;}`à÷é7¯úŒñ2 ¾‰BSÔôŒ’×\†á£ó_ž‹žç;*:./åÞÙDDþ…2´‰9ÐL´.¦è-#s€Â¡UнP¥ð›©Ù×Ðs ?pþ P‹mnï¨)6°µ¬J±Ë/j”€¬jŵ Eú6¤ }ãÁm¹N¡XXYÂ41\¡ÎŠÎ¬– ¿ÛºªgdFdVFpV(Q×™ e,=·Rfè¹23‰žÛëu2 ˜/g p”bŠ1¯d£UŒe³M4(‘bW:éÖ€((2+<3¡/NR¸·E‹ZÔÙT˜A N;ˆÄ8úõ9tÌ©d_›ì‡“’[Ÿâ*Û–âÓøzŽ‘ìÍÈÜïæ²ÍT gà4ÞGõ"¢jðTq¦"§Šxî ¢ÎFË ¾YWõÍv1W‰:sŒ‡Fÿì'è‘;‰‹xña1=w×)V*öÔ)ú*Ü!ŠBìPžs–Ö¥¸*T‡ŽHY¢¦¦H{…¹P©–*йB‰FaÆñN†‚¬ŠUJàŠÿ™bµBºŽX£ÔÙîkñÜáë”@MO±^)’UZDN%|WýŠ*¶( i/[UñU#ŠÛ¦`ïºÂ ¶bïB·;A$Ø4ûùy¼œ}Ö€hÊØË‘4² l®Ú­µu¼çH3ÞÝgÓ`0G0“``s&˜s`3 ’(æL¼ûÝúÿÆÎÈçù¼C¢ë¯tëÖ­[U·Ò½ßºw˜rÿ1­oÿ]íOûÏ£hŸŸg‰(Q%áž›—Éþ•ý["¶;3ÃMUÍÍû#¯ô.ôT*Ôu`YîÌTcÀ…ž–©x;3£@’*SÓróÒ çŸ¢¸{-SÞk™B²¬‚½–%XÃ)´ÈÚfâl–‚O¢‘T»5[){É!Å/¥ç€6ie‚¤I©:¥ìŽþ€bï¨ÄÎ.¹?¢Ø¼Ý‚) bY|f/–€·w^"¸€—2àíÀõ™Ê­@åªMÍÌÍ«••[ëì~„úÌ:rRŸYOî1êä°¡o”ÃEpIÌ<P' ž¿Þ¨›oPÜ>ž²13<ûGÃàJòðSùQé­UœAö‘¾ì78û Ê~ï÷Њœ½U6ðÙo#û(S3róÚ$ÕïyT¿GTMÕ’›$ª?"7ET¬@¶þTaŒ8ùqßâ;(Eo-øu³xÄaEÈ üºEWR½ÒUJ¾T`Át‘³ÆÄ+ ëu²JI×qª:Êœ‹[YíÇ2Ab°J3†¤>D•9¢ºLB†©¸ßÏ)‡Ó't¼qÅðrÃË /9?¦á„èQÖú^æ«øûôwÞî4ÆŒ‘TÅ3×±Þ0½;Yþ;ãLÕ4Ìʽ&Üwâ–Û%˜;~<–…ÍÔ˜ƒ º‚ã¢VSÝ„Jm[PlBéC³ØL s‹ØÆ¯rÎêÕ7Cß;‚4Çî””ß.©b¸bg‰Œ­h0v·äs(ØmSNQ'Ú»)¶¸­$€ÒÅž ø[‚å?މ¶ƒ²7˜Š¥~ PQzTOw™D¢öÁ öÇ›Á N©\’¬¾ÿ“÷[¨ºgˆ}Ž™Pö£_©ü¥õs% eh©_ªmÊYªß1“Õ"3E‚R@WÔ£‰¤ô¨™»U¿ÔIû¹TõEõýePœ4¡ ì—Fî~,UNÉHÍÕøePµé?ÃúÂDD^öÈÌÜ‘x{“Æë›:?¿×ÌŸ«ÿ¨”OëÓð~>›ì¼Î±{%½Î‘à|Ÿø¹½¾Š0ÅM%n™®,ÔJ´Ê‚Í^ÔZ½ÎSõo£8U>}¡ ‹;$Àÿ€‚,¾'Ë0÷¸ímKçZü£± ÚÊ |A\—ß#Â>f¬K”ÿ5GY¤¼üÁƒëaI@ÑJj(ð˜U—=) èÁÀÓ’@0;ð¬$`dž—Ì^”¬P`‚©ë†9B2×K^Û}AIÓEymJ}ïÃ,ñÚ, 4cYe‹ÁV£*ÚÍd¯ƒps_MÜ$\†Y`2¼h1‘¨ÊJïn•R¥‹_–¨é‚”j„•N­æÙ`¤•L¥‹”:V¸ ÀÔõGY•xñeŠi}Â(UáðmjBÕ³:–´ð¸òÇx“%jøXe a) ¢ 4èuÓÊô¯$JÏÓ8<ãÙ$êh¦õÇ s Fée”±ÙâH=–Ðt“ˆ¥-~ȵ’?Ë?©*«ùeódš¡M«”óïæáðÆ= ò¬`Eì£ G¥ìý˜´ZèxåC£9ƒÅ; ¾ ›æ(qDv•ZnL+á^^7)õÈS¸ÄoI*xpÆÉøKÜGµ¦ú²ÏÆYQвaÙŽ³÷â˜EÞYÑ"fØJ¿ ª,Å™ÑQK,#ÿò×ãìhºÜ€;DàŽÜ 6'-ÔaÞŒÈz/Ñûˆeº_C©SÎü 6{æÓÓÄNüS'ð}8æ´þ´.ÎÌ ·Nøm¼¸ '+Ùúôz†šú‰‹:®ðWÆO[âK”´ÐÔtÓ+›jÏH?na #hî¹DrÁ¼°Læ¡ &Š¿´Z“|VyÑR2דÖçRÁ:E¤Š¯Yj Ï3êtÜï(û1Ï+}¬t13˜ªõöì¸Ùf3¦ê‚°(»ˆ;÷[Œ—kgŒ¬3Vü¬%.a×y±©Mk­Äüc®5µ)—iÈ{D¨_!ÔËYô©œEŸùÿ°…yôi0%çÑgríîMy:O#Mâe0Y>…¤Ýñ„9X¶K¥_®„h–MQ’ÅS%öª„wæˆlPüë1Äx3þ™;ΠQ³ÛpKü¸×~ܧ÷iã>Ã`Ügxèâ>ÃpqŸità>ÛèÀ}ŽÑû\£l·J¿÷ypÃVúŽ_àâ¾ð+ñ3Ü—÷¥Ìà²a6xÍ6b“‘”&™–‘”jZëeåöü8“ûvà€!èþ™#›ã–|òu„ƒá§*”ˆãì­õ§ÂÉAÂȰò ô ƒy¹I¤ ’rThz³€ZÎÚÒ‘õ&e=åe=íËzÎÀ¬PoªÔ#JûG^ýQ3´YÊs„úÌO )=Ã#Ðë–Rñ“ñܵ)÷ÂH¥y:xe@XZnMÓÚ%…¥ &w±fjð¨Õ¦Ü[Ø 1¹Ó(“LQkb¦Ë]¼A6¹½–=¨YL7SÉí%l³­É’éùmõ8ìtÞ&~Ž Òç›à àSÌ&Q†f1è_‘|¸ØDٹÉ(‹Q(Í^fFu~ԹܤµRwJ(u£ç]Ä «½¢g„óÇ€Ó`¦uE2~)¼ÞL–ý„~{Š f&²ïOT¦Òìîöv~,±j ;r™!£Yì6AÉ´,3­ß•„„µIÄ2‡,˜ “ùcl"vÃ"aAµx+¶Ò—ðĬŽ<³;ç¡õ1ò¬2Uêžÿ,ÇpKމx™ ËÁÜ’#\ŒpK-Qoa$ƒVnGm…%Vàß% Ït±ÊJDõâˆ?¼Ô VšÌ¬«›¬ÌØ·ÕÂØ·Ú ÒüùkÙ¬ŽésŸ%Xjóÿ%Ý!$Yâ•äÛe¡$lôb§¼ì±Ê®õ¦¡¸7<'¬³I!¤—¤E­‘²zôRzÝ%©,vÖêû½D4³=¼5¦’‘ .y/ð.Y⊕(=GÔUPh­/Ñ-/Ñ-Kܶ¤|v‰°Î2¾çJ}¿.ñÖY«õï—¯â¿O‹xùtÀâ48'ZÇ"ã]åk.ïl¤ôë½w¯ùýâ×É»uúIÿ½{-è¿«=ƒ´õ¿Ù»×Â~ñ›ä=`é?î«w¯eýâ·È»}Pð'ý[{÷ªïo%ïŽAƧýo÷îµ¶_ü6yw2ÖÿNï"%~‡|»YÛÿnï"5~—|»ÙeýÛz÷j«RÊCß™ðƒïõþÞ‡ÅC#Z]¼b9×_ô.Ð»× «®×=Z¤–·õ®‹ ŠÛ3(4°ÿ½ÞENüùö ÿ·þ÷ ÝÂø}òî”õý)×+þkÃõfPµì?¿wŸèð/D3¸ƒ ÁN‚;vÍï‡|Ã"êûMñ»VÒ"|-1LI”WFbÃ#ñû–¨„¹äËîÁ0æBO­Üjå9¼«S¶]/Ý®Ë=ViH·ì·9ùR&ücŒ–*¢“ñVNtý]Nµ@!ß¶xüÞÏŸ±ª[›”òu:äÿÍœ§ó¤‘§I&¬ŽàõGæq¤«p(»„¶2B¿Ç1ždZ¡âZ’êMK|r©æ•jÙn½t·ÈxBB}ݲ¿ÉÙæAÔ] –íÔË×êå7zïÔa¾t;ÉO–ýN²Øƒ¼X%ѹl—›2YºK×H†ÆëÀÃxÔxÓ¸Ó°³í¼édiz—¯ÊÐ$^0~UÞÍp*ŽìÉ¡ƒ5ÈÛÉøª«–ä±´JËpÃSJZ­a&£–çkâ#Hš&V¨‰xúñXA2‡kg´V6»¸ïìâ€]BI°Ì$Í£âdˆÊ¾J/ƒ¨¼\s+}Ë«ô_¥Wy¸®Ò ôg—›RVz-îõ<€I`«pŸàIàIM4{[]€-¸ßGÅÇøWøAÅ>ÆyíÁy Ȱ·aá:X2þÄCu¯Êà ôÄm/Hî±çxÈp‰'o/Ñ!¾'ã/XlOÆŸÓpŸ¸ûª|én•o{U>â+ó.’*ó5Ê<ÊÄøÇ<ðÊ| /<µ[îw\r"Ÿk¹ù ­(ž•vK¼À€¤’ÿY…î±Ëú~Röm‰Wt_Ýc>\fAØžC‚ò`Ê }¸Ìó,Ï Š”`ˆíá²}..‹‚}Ä,bã*—ú ‡Ë&—Á¶XôpY¹þ„—ÃÀå( —ãòß9&åá’ Š“” 2ƒKû\\š —SÀ¥Òg:p)`$.Ï«‰Ì0[œË sÈ$}È<2¸ûRdR> ñÄÄ!†F‚fu™Jöyæµ>¢êw«m\‚ñf¤á!³Ã%L•+¹..£!x§}¸,‡~•|p9éÃe‡ËC4P‚‘\Ö±ÏÅŽf’Œ´ÅæÎ¸lÉà²ÛÅe„-¶fpÙ\š|¸œ.g øhàÒìk¤ . ÜíˆÉàò%û\\..W€Ë[\3:5Òõ ./¼Fm‹dn™2¸Ó †‘9Èœò¦Ê3e\eŠJ0>ƒÌö¹ÈŒ4ûˆÑ°t<ÞÆm?aÆ™2\ÂŒ³ÅxÓÃeÎŽOûpY\pê>¸œñá²ÁÃeƒÉë“2¸lfŸ‹ËÂeÛo¶qÀîÇeg—Ã..m±+ƒËnàrÖ‡ËÀ6kË9.W<\®˜°Ç›’Áå:û\\n.·€Ë[ÜîŒË .Ç\\jmq7ƒKp9ïÃ%cÃyp¹àc˜‰žä‰ ôÓ3¸Ô²ÏÅeŠÕGšxžn‹éV'†™ay¸¼ôfš-fZ2³ ˜~áCfÙDÐg™‹>ÂìðÙa‰]”`V™Ýìs‘i$dö™Y¶Øou"Ì 2i—03mq0ƒË!àò%­–-û€œ÷¯s‘¯Høºn‰›V²üNïBÜš&**D~_‘ˆß¶`çˆdídùÝÞ…°ãv‡âïZeG¿×÷è÷/„1+Âþ}(èõšhÇ|bÕÉÅî#NQ¾Q0"“Ôäéµê¯ÊôÒ‘´ zj¹òœxf•W|?6óÏ p+è…ÕªÉn[ñµºxi•í`OéÖºD† ˜k¾Ä3æ/eKÛ^}¨k³Y\ü?q¡Õæªa{j"‡ŠIv¹È¯Š­×%å&ËÐZ»üè÷8´$D3íþët1ËJKÿÛ¿RŸí²>pÖýDÝ.ëÓH#À›õÙÍH4ÊúüS¦>ûÜúì·Å>}ö¿YŸõ9È IܱÇ~˜*³›V·G:Uñ(W±QÆáŠÈ[5T­ã²ZWMͲ쳚ôl6-”U:I( «V”ÓäVV+êY©³ä 'ŒÏ‘[EW9mJuµbT;¢ÙNâ V´Ø=KÄi»g³8c÷lgm슉 ÄB¯ˆ…UˆM™‹væÜp&Äѹ¿‡½Šk6­Õ¨ö_ôáƒÊë6’Gƒ…Ø×¿IÄ-;7ó (- ËÀRX› ü±~ÏîÑÂÀù€?é ü©ä.ðç”A¼À½ |°ƒýQ4bºVjÓ„™= š•ÄG~¿,QH Gí‡9=JD•CùQWIVí4Ë9ŒÌwùjŸ“ì@e”ƒýÖÔÔÎ\8ÚiDrà­¡.Ç‹qNší‚NtRy8jìDÍ"%Ék©H¶ø7a*‡ÍsØøú5SÕ-{¸äÝ…¹E¶ñBmª¬pÄbG¶ÝÊ!–9™ ºÕÚ çT¿ÏLK, ®rÄ*'™âZ´ˆÕ¨rÚ—gÌÓ¨¦¸© ŒÏubÈèla;ê5„ËGlsÊ×wIŸúPaJn€]ÀåžµZõü]d׭仑 ‘aÞà:þ Ã<è¯âAYÅŽ8ìVñªxLV‘µd˜\¹ïf*—tD5òª—r’iN–©©Z.‹¥Š517MUÉfåÅæá¬x…-¾Àg¥n‹‹øœnÇgØâK|VÛñ[\ÂçH;>Ê—ñ9ÆŽµÅ|N²ã“mqŸSìøTê(øbLJÚâ:>gÙñÙ$‡ás‚Ÿ`‹›°IË -{‰Ä§ÕÁ |àBIœVIáˆ;.qîRErÿÞ—Ôû”`Dµ¢=pÄ}45†¥ñÀI$ÓܪrXÒÅC‡F–öBì54Ĉ‡…ÄÐÆfQ"fJŸ&fú)–é!œˆbL­aD C[̈®r¬5ÄHd ó å€è2ŠPÀùÕ_ñù¬¢Q“¿ÆóWýQ–ƒ\xV19”žˆRjC¸ß’ƒR¦úK™æ–rÚ-eºô§|¥ÌÌ”2_b^›­·M#dÙ 9To•¤ Òp3l÷Zô‡ÑΑäÚJIä‚Ûf©pFQCÂMÃ÷ž³yð``’Ä5K2ZGÈS­ØgBbWHrÆîñýÞPTg´÷…’›1îýʽrÀ ¢8 ´s—9†¬'Br—ÛÄÍk[$‰(¦$Š%R!𿬍u$CÙ"ŠÚnî“!b–¦P"j3ÿ€ÇšClv¹%D™lžûN…¢æncOH—@»M%¶:Cþ_ tÄYÂØ uÀá‡/ü8\ü —ìÜð½YþçùPisE– ô®†h¬¾Æ±ÊÄ[¡tÙODk¨Gª×Øj%«±ûþDçõÛ¨ÈyJŽBº "ìDLÇ4Ë^¤sËŽ ãc§F• :*ܦŒ£…K «Âm³48KBúŒ°– 5!LÔžöÎf…S4 7âRòxjð9anð%aÙàËÃ,xX+ÂbN¸(€kWsÃÜŽ…¸ÿ=?Õ©6 Â=ÒoÖfa˜j³$œòQU,ûº"ì4ète˜€WKÀk¾ðZ^FÆoþð0/œˆ=´ä®ƒÚ,Am¨ 5#j+Ê݉¦ÞíǬñ+˜íéÀlŸ·ÿk0;Ì…3M8LM$5ƃnÇÂ.ž¬‡ýx8÷clí¶,ÉEЬ*R”ARUÏIYX [ÖO4Sê¡™âZPÜÎ0óK°ËŸ¿œ ƒ_îšAÚ†ÈAòYX m(Á4’Yž1W(p&¯<ãF×*²Ä+—I^ƒI*²X ©÷&=}H–’åL†f¥=¹¤°GÄ2ÁÊ,fcx–¨Ì ç móˆ¬FFX5EU‰#²WgQy5Ym2éFd‘œ=2ËTA±QY¼Œ%ȳÊà1Y|B36‹–‚ùÇD‹‰Y˜rÛLðìK’õY~¶>‹Ïá ¿À¥ cm–¬jC–X•%i± ×fÉ£‹õYIªQ × «ðOp’Lä{UJÚmKVŠšmk5Û¤jElËJÄFeÚm;aÆÒç®N a(uxÞìcHûiw?q  ƒHÍBcÑÃËqNÂ-ÙŸ:Ô)jƒâ%DQܱ?Éi›6Ý/›IÚŒ¤§t¾›ô '=‹¤k)éÔLÒsHz! |'Lƒd¬Ÿ2©Ÿd±"óI_å “[}’%^ Žah§|M¸·É'FÙgÓ°X ¼'gJ’M%Tf£„{ܚפÀ2+EL¡"feË"àRpVöÓæ’³¦Ÿ>/[ÌÍ.ƒùX«¸Õ‡ÍcïKé ŠùÙeÏ@lÌê²pÀZÄãðçÿšP[èO _òÓÐÃÏn3ÖK€õT`=6ƒõR`½<»”—S_Å9WrÎUÈ9 9‡gr®Fήï}œÈ™èž.EÊFåD¿O¿#o5Þ²8!nN?`Yó¾æTnÿ e`ÿ‡½{HÞƒƒÔÿÖÿQï"-þˆ|‡i?ïÿ¸w¯›ýâÉ{xëÿ¤w¯[ýâOÈ;ö‚ßÿiï^­ýâOÉ{dñ‹þÏz÷ºÝ/þ GbME±n÷¦Ë7àö>Öó± 8‘zD8yñI ¥•²:»ünïâ:šŠsüO9~0N[†ªå·->Õ†¯Ø˜H‰®–7èåƒ?Zî]hÐß]ίͫUl6Ô¨› #Tl6ˆÑjùZy'¦ªÚÎ8…‹çÿŒS¡”+¶Öμ*^ëíMTûÀ`f2¾ÖS<þž†¯ä€1~û5K•×mf«™£š:ɈÏÅ’ŠyÀÈMeäfÎÂá¤é©¯î‡P÷#™º庥ºÿMuOpÝ“¾º§dÝ›¸îcQ÷gþº¿al#¶¦£îk¼ºŸ¥ºŸGÝ×(”©û—²îceݯºu¿ÖQ÷™ºß”u·:×ýN¦îl—㹩QݿɈ]ÂùÐïÀé©wúòÂÔ ùp’ëÞAÑuMÜÔ›<ì¹µjE9É0p¹­•MëÓwZÂ¥Í;zêžG±¢¨—¾òÖà(§Á;íyæ•÷ÊWÞïLgƒ.6é^y[ô"]–·UÏ”·CwË{æ–·Ç5¯¹_ä1°s(ï `ÿ²‹ùÇ|éó¥Žçø±M™ýË+ìs[åªÞª‡’ñM´Šë|tt+stÔæî_n´Ekæèè6p©°:p‚’a$÷n.ƒ­\ª¼ãš*hJĶvl¾³ÏÛ|ö£q\³ÕÆe³N›ï™ãšû..[l1>sZ3§5C|¸,.K øvà2Ô‡Ë*—UA±†ìÈಖ}.. „Ëzà²ÃÆUm?.›2¸÷!Ë·ûŒh¥>¾ ¦ÒÅûlMî!ùq”‚-o¦€8aðšáQ¾Rñ)-#N’7¶‰‡½^øŸù=q‚þ¢Á¨•-´¦ßkë=Yü= hç¹ @.ÝO|a”wdÅ([iG-hL¯tñ¸Š˜ë„œEûÝÀ¼e”ÍåÍßâ¹¶ŠEÌm*¹\Ðâ7DZè½k”ÕÛô Š6#ê€z[R÷<6ÊVeÊ[å‚~‚˜g®=U33TKf¨4yÇÁÝ]¨4™ßá@¶†K²õHh'ÏW܃äwc"Þ L2yš?)z0Iôiz¢÷hÓmý1oÒBtím(LàKmb"¥Áâb’™¬¤F˜lb›¡àXÌ#¾šbŠ)&«¦‹#¦Òr›’c·…>£ÁllùΠOjxÖW3‹€LÐ9f”VQ«åmEhl]É×iêpÖil¡2ç›=‰Ü ÌDl½]¤®”B¥X(ýz½ë_$ýAÏ¿Xú-Ï¿DúmÏ¿TúÞ™ôg{þzéÏ©çmýfÂaI ^þÊÂò²;™fÔ*—›0¢Áý–{Ó¿Å÷þ åo0IÊŸOmºÑ,¯È°à&“ÄÒ-fÙ2b‰tŠ˜h™Ë+۱ļZc¶í ‘±Wr„»ÚÚkr?Wö2g¨{%gh{™3ôCä, µ# ,Ĩ`òÂÔL™âPæöã³l,^`ãóo£6GÍŽÕ ŒÙR4Ϭ¨ê?'~8ÞÁ%¼ÌÎËCÎmÈ„~Nm›"ZõiP¬®ü±U‡\u⤉tuhÖ³l¹ã«x¹­ñúü´‰.{ÆìÕ± ΚåÛç@˜ °Ý@¼¶Çí?xµ'qÍý¦V(ø>¸È› rQ5ž³$b›30[‘ýNòâ®ûíeœý^&ûýNÙ û#bbÆþ §}Êi[û±Ý…m™¤Ï‘ô5%%ÖÑ™Û?çL/Ô,dºÝO ¡ bg&ÓP k5 ¼0Â2h¼*ÅÍÑ|P >mÉÙ.ñÁhKŒ³ÊVØÉtªx…K¢ñ2ÑBµ¨-ˆ½Ãh±I2à1r0Ù*[dsÝaïç]>hnS-Ai±<Í*ïXýNPÜ%]ç:[t#®óË@ç¹@çû.ÐE\Ý‘–aÚÎJUŠ,\]b÷À*·º«duá,&¶ßFî w“»”ø~Ÿ%¬dlB„ °Ž ŠmìÇœ·ÝŠêQ<«šˆ”ïŒý°û ;(”~Š`Ç)9ž ¼×Ù˜Á-â× ?/q÷XØ—AšŽ\A\]%jâ@j¿…:ƒ7r°0ø!MG.š‘Vw5’b缞å’#¨Ã &]¤/&-?/¦,lÐŒ"qE±þÈ],þøç¯[áÞâ¿O{¸÷VÛœËÜÑlKJóšcè;häÞ[FqýIð)ÇÂs^øqDGà¡=®hÆBÎg©jÐøOSí=ð©fƒ’”@¾þ©ô£”DéQ›-K&ãmiYr¼¬»œMÄìK#°ÿƒcN{`O+lò° ö½àZvœñOžbƒ‹œâsyœ˜”6F¾t ¿ŒÂÛâ ¥9dóíÀ«üÉu¯¥‰ŒRü(½æ‡WšÍ¡•X[V©`ÙÉ>üg!x^ÿZYz+Å…ªX ýÿÇmù(†V‡Ëøå‘ ¥g ÃåXÍMñÝ °{l`§úÀòÀRi©›D {”ÀØ„û™ 6°Ó|`¯ì5›Øé–¦sÌmìmµM99LQî«´ÆL"%ƒo#ð÷>e‹û*ˆWñÓfñ@•j¾ª‰T¬QKÅöh¥çlUx<•h•–8oÓRÌÛµTéXjÿXÙÎòép½Hé›PàlfÉ G]óJ¼FËuNÁïo2ðØ)]Ȫç“ñ&›ÕÎS¢_€‚üÙsÀøÉw¤/¯|'¶ã¿”Î*TÙÈ!LŒ4ðæÄ­|R$69R61‚ð≥GimD…Bf¤û¶|ƒþT+û6Ç[é9àÅGâ9¿ó14TöÉëšu–BÔëΡgxÙ¼·GàŒN⤭œÑi'_–B.ä4uרËc] ÒB¹¢[++X¶|Ää·qnÒNóH Q“I&’§Ò@ô_²æ±!ø:X¾2º‘tWÃDÍÁG{JFuʪƒTKï¾±½]ßÞ¾¬½¾EVP¿`Ìk ¯YðþŠH¢àá‘Hi@…˜ÛLÓŒÓP/U¹`žn¼["fIЬY̤'P{5Ë(ëŽ3kÙD>ê3‹­ 4nHbm2\6ÙdÈ^ºE¾øÚAÎôïkXÖ®¡¦ÙOîZšÑÛ@’ìArב${È`%`²ïn5RRt.;ŒîW-b§AÒìŠ÷ÑúßM¦W3¶»¢ÑH%1‚T|›¨¹‡fÛZ©ä›„‚ÉZíEºýPŒ²¶$^8€ï†>±;ˆï)‘ÔÂ÷T|[â0Õ DZÈX²ÆK¬ 4ɧø¡ÛO[ %EÇO?TŸ'J EÎz"û)C4I¶ÅÒLЊï¿_,qÊ€Å-Wâ9#•?\ v¿•jÄÍÉÝH$û’ÜMD²+n ºÝà¢QöN’-u¹fºXÌ—JUI¢24H ãUj¦«‘éš‘¦5¯§Ÿéê˜QÏD¢Ðp¬éG…ÇÖN(K¹ú­²ú÷eõ¿Rõûäl¦ªß—$PŸâ‘K‚ÇIð´ƒ-⥑Îì’@{-I W˜²êÃLñÚ­:Õ²Â,{‡~¸úP$]'›L¨s©ój=ÌÄá›Wëá&”adª]mú«íMjŒÕH³s¥—YZ(hÌV¹Òùvéôï°(—O5¹©3M9Í‚>.Â¯Ö¶â¼Ød¾7æšÌ÷& ä5ð"žùÞ^`Ò¼£züZ‹ÕÅTÓëÓÌ”›$ÕÑQ±ÆŸi¦ÐQ©Ò‡ïf›)V­¤Õ8*ÅgÒ’X`ðy’TŸñ:<)Ù‹ñ¤äz‡ÖÝX¸Gƒuîé1ù캨¾Ê=€]L±ØVŠZQ§.½  YÌøÏL¦ƒL¦ÁR5•)‡Mq˜ÈÚ·{ ¢{3-Ti ¹ìLpÙ¡%*xêˆcü(n9ƒùÁÜõÀÜ•`„Ië· ˜{ÈúÔ”ûò³H© òuŸ©– hªÅ€¦[´àÉšaQîv§Ý3å÷€”C«!€YéÃg‡f‡³ 7i3`v#kÊ”Fù |дŠGËYC‚e3V±Äó ›77Ľ¡Õ±äl#fšNîvb¦äŽü$8“œ)UбFÐ<Öe§Àb´ MWcíDñ›Ðiãì4GŒçˆÉ6ô[óþ¨Ã›¥àø¹Újž°j9Ét!i¢#ëÄšA9.;㈑`-ÔóíDºø’-µ--°sÏ p/»õvî>®´£AšçÖàæ¤-ÖxîrlÙIâº96f¶1F-ŸzÁ:œàJõ‚‹8p¬(Õ .æÀ‰^ T/¸Âv§P˧^pµíN¡ÖoP/huØÞnün{;ýÿÿÿ¨½ýoÛÛ)Tl´£“oÓf‹Ëfî!Ôo— ­OQš ZŽ“FŽL±ÛÎý-¨qÜç¦yê0A‘FÚ:2Å~;÷5À±;âž°£fQ ‹×ä¿SBÚ–W2NÙ ~ž³gázÍ…ß\øE;w04þ f¸=¶¿Ù rcgÒ+LåIe*Ÿ|³=ÞÔqhuŸØÞ®ŸxÝþàu{W&1ùÅUFQg½dQÓ3°„Ç¢þn²ÜéÔM–;²›¬t¸›¬ud7ÙîÈn²Ãán²Ó‘Ýä¼#V:^7YåÈn²ÚAs®u2ݤÁ‘ÝdGlr ÿÝ×MöP7Yàv“Íœd»ƒ4uoî&;(G»¯›ìw¨G\q{ÄGv“c¼êwd7I:ÜMN:ÜMZ¯›ìrÐ,è:¿w§n²‡Çuî&‡8pAïNÝä0ŽïÜMÎ×t“´óÿ£›œqÜnr–isÞñu“ËŽäÂv¦Ð\Ð2ÃÄWÙMn¸iRiÂøØ^HÓ ¬^rª,/Uv&U–L•ýp~ÝA0ÞÛCѬ¨^GQ¹è<á ýø†Ãàp4;œ‹œCÃRrÎaá(qå´9ge8CYÎ9< G¡ÕÎ5áLýWËFÈÔ%k'Á—,m6[<2œ©üJ/±KœÕ¼õ3*,©?¶êÊ7 ®f¨ã|PÇw@]ýÔ• u‚ ur8•¿דÃXS‚Fm•|«’®ekRÓÃ)¯XVî6£Ãʲ‚à™æ¢eŸ¸mêkp—IiT"ÿž7€Ï§„.šÙ¾ Ã6`à )ÌE= Àuø¹–…ËÞ‰ÚQ‡VLÔ‰×YM¼Õrq·:Œñ‚Vs«Ã²ßÂE¿…‹~ ý.ú-\ô[¸ÔßÍÍa±9 :<~Xb+Q gæÛÂЧó¥­BbÞNˆaÍŠaŒ'bW˜ å°²ÞÒ‚A£Jbt•1J¸ŠË˜Ÿ(7È9ù‰z“œÃ„Ïݰ¸A ]åôů¨€wšÅÍ0[º°ø±­þªEÜ §Ý+•­aê¨wÃeÓ÷oC3y¡°Ê‚>RÖ8â}¤¬¦õ}B,j•KÁ*Ü–Ä–#¨ÊjSŽ¡Ægai ®È5YØ®ãͪY}Ę¬ÌÆàø¬¢@³˜@·ì|´ÞDþŒM°3#2ïWÍbrV"A?IQ›•*~j«ñV[L¡t­v>f™éYTÛUNü¶-ff%ŠŸÙ6£^—•(}nÄ\*q!¥¾oËGÌY}x³kE¿¤è¸¼ømÓ"VfɵU”eM–·åøgX‹?Q´†,Ñ•Ùyä-–u4@¦Ä„Éê×sÀp¶S:3¢æâQÜf…t5±ÅõíÑìÑÄV×7Ü€Õm®oTTw²¯è´ ú7Zª4~—i~" ÏíÝ:¤8!ïó§;h{y6ñèosž;Y®êà;Y¬:øN–YîvT:ðVgWyÄÁW&ÑšÕÙbD6Ô‡l±‚¹Ac±œÚdâдvœZî ꋲ!‘j˲Q’¾*%W““ µÿZr“Ô'ÈMÑ\¶ƒÜ4Íe{È=IÂ^r›hBØGn3MûÉm¡ á ¹§ª•ìCÙbQ¶·ñ³8;Í;èÌÃKG±,Û›uQŸíÞXŽ˜UÙÉØÇÕ¼ZzF…°!°6›õVßáö)Rç{rOƒ ¿Ë-• ·Äz‚‹Áˬã[åa÷, c•9—r0?n@" 0uQÃKdPÆ¥¹+xvÜ´6gãÖ»ÆÕ-Ùeïô}‡DÇ­2ºw‰Ôw9(œù wfGí"m>wáSÁ|"vÓ'”z·Ùó±{ö¼¢?œÏIöH|Ça˜Û+ч uÓ‘äwF‹çÔý2h®ÆÕáiõ`6†ølqˆÝq$;J‚-. d*NcxÔ\‘³7dz‹”ްù<ŸÈŽâŸ=o|‰l9ÏúH7‘rÿ+eKeG³|@™–A mòMš “@›;méÊÄÈg²£!Dƒ«=7jI4Ïb& sÄ…ìhýcˆ9â †˜ã¡™Ãh~™ wB“ZÓ` @óŠDÓ “@¯vz­(£™#nr‹îY„¿k̸Å1,„£919â6UœWe|ŠšCŸÌNwÀNw‰…ˆ,9rÛÊÃ…<ºxDýU<ÉÆ *uymã³*yö‘9<cøœÓG ËùpRß9–¿e‹JNàšëxa³þ³áÆvIFå$Þ-}a+bt ñZ ;å„51ÇÕ#41ó–2'GÔæ$p*1Û–ñ'ª˜‚ g2hT¨.þLÓsøÐ&\æä”ýŒ~Ê›u~ÛŽ5‹¹ò«¥XÌ“_³#b¾üš äW]D,”_é±H~,‹åWSIߟÙ?kKsR072`nD,s}‰’‰Qïú’%’%b¹ëK• H•ˆÎ!;U:/¢ˆ•¨ÿ&o)WU_läí‰}I4˜@ÙüM¡—m ôÞ—æ´piÆÛ ¸;-V2{$]÷ç¸ãùþÏá`>Hnë_i‡Èù‚“Ã9‘ƒÇsÄÁoì<”õÞ¿Eåᜨ^öN2Õa« (ŽäðeÌcù˜™ŽÊQ!LNs1;Ïñ[CœÈ‰P’%’^FÞR®CΔ—“7˜ëõdkïÝeÄ$’ø>Ú½BkN%¿A«‹Dr@ÒNôJþEqã÷Ž&Êÿ"Ñëî_¦’Å?ÒqöÍ•?rìî€ð¤„_…pçk!4âVþÛ°@A—Íç‹ólü}Úóí·ãßàÜ ØÃý)4?:(ðûýŸC«Ôs\gßk)ŠaæÞ»XíS'þÁž1­M ó#Žø¡wõ—â/ËÙåÕzUEµÞ$>Nº:ízM/M®Ãñj™–,֔؂HyqUE1"ïV½ö[Ðû¿Ú§€v*ø”„Nš}Ö¦\¦–ÿ[ñ³dìKWým2v »áe©ÌMÐ4¾ò¾!×s)¹œƒâ(xÓìe ¢Ù;E÷1„ˆ¿+_I¥“Å‹"âÅȸ¦9ŒÂ¯©¦Ÿ'bƒ ?Èáy>× F+‰ØPÄbüÇLç×Hj˜©ˆ™J¢¸ÝÄêÞªóv“˜¥xtHÆÆ‡>‡9d®nZᬋ¼Ë‹† ,aÕ°¨ÿ*)÷¸+EÜ˾˔>b¹’J%ßo!™(mifb…’ä1{•’бIjÔ{5”¢W:ž™b …?÷Â×"|¸3๙ûô››‡Õ^oTðÅ+±ÉÍÃá›þÜŒwÄ*œèÙBùQú3¨Ö‡Mf  órÝŽpÝ^ýuàÕí\T9.«¨ž ÷:Iô E“U­(nÇ•d¬¾;5ñ úષÀÌx¬ÊÁ%ƒ"å3¼rÆŸaS.‰…m*èâ !æé×ó¶ÉQK5 sޤîyü˜·½sçóŠ}Ì• ´@E«vb ’ª.r¨%} ”ð3е3­Q%Ám%LÖHŒ´ÍªhPÁŒo01—¾^…ùy[Å Ô h£ Ú h³êg5]lQÁ@ë;1Ð:É@IKÛ0;Œh‚}g`Á{ ߨå½]{ìöÞÀ·Þø÷~³çÀîLÇ”¤c39¢j 9· ùÓäÞ!DϨŒpð¹wiUsžÜ6ZÕ\•´ZÉ´ªÁÍ¢{´ª¹£b¨UjmÊ}ZÔ,$÷-j‘û5õä>ªVr–“û¸ZÉ]!/÷ä­‡j¹L«¥Uy‘ä$ñc³×‚-ô±¢;Ñ2ϳäÝa¯»þóqZM¡ ÏÀ Šsª;`ÐŒ}^íI‹œ ôk‰/Ôtþ¸@kU[\Vi*§¦é½i5÷²6 „Ñ¢™fpêYq]íAùn¨¹?ÅÖð'¸­ª&{=©æâ~K\RË—DbûD¿å»Èq•×x_½Èñ­îëÛÛÕ!ííµííô%Z=þÄ•tÂÔwè7$îúñ½¯Fm‰¯#¸ø>Bðµ_G<&|Câ‰ß6Â÷Yß{_‡ïÃÿ(¾ÏaŸÀÄqI¢¸Ú A²Ô¶ÑòBêQGFöGéPÿ[ܽâoi6\‹†ó÷*Q­¥ógc—ôyµ’?‚øáEµR0ŠÜ—ÕJáhr_U+]ÆûºZé:–Üöj¥Ûdr+j”·jÉ\£|c ¹Cj”oNÕÄ- W8î Ä(*¦x)θ Åh-ZÀËâ.b ‚ù¼««ag²«ûBB´kùóÞuÑ.«>ØMŒÓ¢PW'oûz e‚•nx7©x<­&£]QÓ\ˆ5¹‡_eÓZQ½Û³Õ‘…i2¨,*o‰Z`ˆµú7Äóáü7ÅTÆð›~ ¿É|ƒ0ì.¦iч¡ã%xK&ð0ì.1œ®Q³}ÍÄÎ$/0|‹Ú ÚGÞÀ0È–§êP5¦$#=pmnò…ZªH‡Eô"÷+[ÔSÊÿµªâ_i!·\‹æ­hN¬>òY.aT^ù ¹¹bEGÌrLžXÅ•ÎÍl¯Öhá˜[‡BÖrT^&ªA£•`¯†×kå|_$_lТù|ŒR¼"¢ Xfˆn@b“ÅK ±Ù Èæ€%†4/œ²‚ïf«økrLíGߨb¾%'ƒÃšœ à¾úkõ¨†áPKhrØOj·\ça/EÊŸG#Ù|‘“¦ibÔ»K|ĘBëILxOë10ŸUhA×~ø`º:{Ä«ñDË]ˆðç¨5Œ™¾¤´yиµ¢Yè}«‘ü5ùƒMރϑ·BªåCõDO$·ÊáÑú¾–ÎÌ.oÃZ´­ßöÖÏ4w´~û7ŒÖow_H£õ_··ÿ¢½¾D•Þ“ÆÂj½ÇÀBYð(*1Ô£áŽrÄ]Vf¼îVf"¥-“ôDÔŽfËÊPòÉä72•J•¡¼SÜÊLG%(Ñ ¸£dejôtfêy[ŒÔ¿¦2ãôÿ`eæLßì¿2Rˆs©ŠùbžžHÇjºƒÆ ( :PÓ±Ýg½ÞÁ)Љ±\Oºâ=…Ÿã¨"jò¤U7(0§ Áæ o£¯Ô‰£ˆ¡Vë @kô”+æ1 ü  ê¯Êf@ 4”‚ï6Š]ÄfúíÊæ±IÛ*Ç{a’ç>ìÌp?JÚ¦'=Þø6qOômëmúú|`|þ7 ^m<½ž×°ùPȻÃ7´^W†G”Û§w®ŸÜù}ƒx÷pWDÇ9O£zf_É7†|H”{  '¥ÐÜyнcÈË'"Çe?'\š}5z´ gXŠpóñÝ·Ï@±Î9¾'°¯r\œaO@|A³1gý2S,g½ä‚GÖ+^ÖQŽG>¼ºÖ¹°ënah½›nî¿ÁCÓ¯PÆ«6¡–³Þq³¢WÝÕ;­•仆6 ]<¤jg¸’#¹ãÅcª˜ŸU8ò‰Ûÿ^¾Áç¯þ£|Þîòùà`g>üòù° äóê *0R=‚>°ýËçG#á1£&ΎĘ ¯ê£˜=F×(ÝÆÑâj xãƒb\P.… òÚ- ½!WÛ%’ŸAdš”Ò ¯¢¢ß€ü}«´1¤ŠIA<íIEßšË&§H(\ØX’§QaãHzœÓ‚.Ä®é§,ÌîbŒeY*¬»˜+Âßä«$š¢ÝQ6‹b’ÑoÎ-’öç”×v‘ºâýüïºÍ­¯íèüŽ%Esê;:}~9°_£t_ EÅ$Õðƒ†¥D´òŸVAàË‚ÑoáßÈüVì‘:ÄëÚðÄŽØŸ³%‡zJÆyWàQök¢Ä_Ûü„su0Q X‹’©ÒEšŠ7ã@{…Á‰ï³Ôó[e«2{…ß ÿŸ¾Ç/Žäzû…'­€ b³ç"2ªù”q—-~§¬Öy÷ÓïÆÿ‘}i)Š’Ï’.Yš ÿѽ 5°)™ø>6½"ls•Mu}§:J|Š=î±)ŽkAi©ÃûðËPÊe*%þÏœ[JØ4ŠÍqÜ{ eÛ>*ÞöQ@v‹ãJBoUKxßhŽÃæÞÉiUa"ï a ç1˜ûóMÃVÞUKSCá>óÜÛNyÎñi4­+e߃±ÖÕÞyíÆÞ:l¸®Ždl¸V` 㚯¤ñx¨3QMÄf ¤ë–ªz”˜æ=Ô™¦Šx 3ÃáÇ.3i!<tf8bŽêY!¬à>ÀØ™à=‡Y|“Ä1›=À›U±€gIÀÛðžåˆF”au{ø©4Å^”sËWÎ5”sƒÒÔ¡œV_îzåÜU…@9u²œ{TΔSG#[¦ü’è¶p%^çT‘ 6€ï0à?ä˜ÑÞãœÑ-Ø’HQÏK.:Ï4è$Èìw}@3Ï“híÅ1õÐz"I¤`lW’$¼€8b À æÖ¿áLÛn‡–øøØG˜i"BåAa]£–(û‡¾ÿˆÏqÄ­ì…ƒës\¡)b¯röR @ß}šŸ¾PÄ=.âç\ÄQqœŠ8AE$µþË †DÃR‘Q§¥LJë¿X†Ñ¨TäÔÅi5sRë¿T†5Èt´ iÒú/‘aëd:ZÓ4£´û–á„Â÷u.7É¿fë Ö»T\£µÌYZF\§µ Üæo«X•ŒþXâdR¢cQ2¹F N¤EEmbÔêx\•L}œúHµòý•.ü?$Ó÷ ÅÄ &)¤¶!´¢¸¦¡gǶþiù=¶ w½;Š¡ÇEêø¿NKÌ_·ä6áõ/%žï°„p“M‘€(znzùa-ì]XÈŠOnj&ÝŒ¦Óh­…µÒtZkµ±J3C¦AµIÜÚ,^ݧò`ƒ\—«*‚<½Ù?V*‚ ÉåQ϶}TÚ®YÅ&zžh匨Uº&¢˜…Jf‡,ˆ­¸5ÙNK d"Qš&Fw#R.ºKõ*IL˜ëä­HU¤ø*]:¶X%Qž‚_ÿ}=915±ôàGz.Þ”B(ÅH®G¶Àû4¤S$dlŠ8òäúd‘1—&é|è/ùÅû\Â6EæÖµzªH^¡œ’I¿®#ýÚ æfÒ›XP8®óð\8ƒ½EZQç™xföÀR¨¾Ã¬·XwKëb©îuáeHö‰óg4‘ ᥬ!òïY¸üá§ïgìXNv8æœG41i¦Œ—<1¼Ù÷VÙö¬w?ýÝøU„`“šÆ M—SÓk~=›{o%û>uÄ?ÀÄô‡ÑÚ·¢z”­c„´O{½ÿB¶J¹ÿîkTL¤üSÿ½¿3îãø ò¤~Öÿ%{_’wYHûú¿êMÓñ+ò¤Vú¿†÷5yƒ‚“Šú·÷æWÚq7ØÆ Ý»÷ê¨ÜQP+…66O;°>HHE½‡p sÜ šãv:ïBïè»eà5:eP2cãß¿pò»ÞÄwWBI¾ËJ#ï)‰Ò=Nç2Û»˜üz^w¶Þçð ï#Nh$¡µs†'_Í€éý)pÆ8ÿˆ‘ÀaN/€sFgšO¡«ì‚Ò÷‚ˆït`Q…b±]΀õ1ÔõívlˆÀÊ ûF„lŒˆJÌ8•6ž™þ/†>‚'¬ù5J`„Ú¦,¨Q”ª­&Yt£&J—„˜°¹t Kø»Ç€M¨ÀŠM•Ïþ³Xó ê×RzØFÞ©ô}ÄÐ4._¤Î$ÿÒôbÃm\?úc01˜×#0OÅÑDé^¢íB$ª²å³U$Úƒw•·sXµ­êAcŽÊQG¼)÷U`ÞPEI»¨FQ¯«âçfÙ˜×CŸ7KëˆûÑLMrÎoÁtÝäÄ6Gæ}Ö$NSÄ1§×¶ ã¸E¢&¡qG*k+RH”íÂ2ë‡ÏY-Ï£§.]@†zib8‰`_†Ur¬—V0q.ª‰ñãž0'ãqJ¯•o‰TUl‰´¨‘æd7ÕtÏ[#¢§LsBÌŽ·Ý6º Øådº °ÆG¡˜T+ñ8$Áâïð*²C»8$þnªÁ žtÄ^]ÀN`°ßá̧ö åJËr+>À¬Žf¨øÖb¹(Ù·Ï{E×aÂ2O;â"@NòaŠwØâ)< L'Ûeß'iþÚËÿZA¤`!h0öZZC£â¢POh51Z¾N:¢R&Ã;¼s2˜ŸÝ¥i5žà$¸,B£¾¹ÓË£ÐýÎgè5n¢nòv*v[äs™”‚ãcCP~Æ=o$Üq!1*(›d4Ö‘µ¶¼˜…ÚÌ…â­ù„T³SþA,É2©†Êº®ôÔ‚­ b]šŒ7;ÐlV:‹ša¬çùØQÜ@ŸÛy±1XÖáÅ}iJ:«*b4¥É¸Íþ¸s·jÑdÜVÜyŠÛL§úš¤˜ž¢-h’iŒ¦œ.xX^Š‹œ@2Ï—Á>â öK’|*EWƒ êzñµ†¸Žê´8â&U ñ[AÉ]­(wº-õPð\Äõž…ìÚr¡]%x…¾ …03Ó—kœ\‹k–/×xÏpÍx˜¥Y„\³}¹æs®zäšã˵À˵¹ê‘«Î—kçZŽ\s}¹6z¹ØÏräšç£gÖuR´9zÎ÷Ñó”—ñ”!ÎpIϳFqÁèDÏ/ ¦gƒÃ;Éø)G\6$=¯’žWQî.· CŸ ƒ1ÓÌDì´S<ªƒÝB—Ê&k=‡íX~‚ƒ|Â`Û˜Tæ²ò%Ov—Õ(žìÖÓrgɳAp)æÂô´˜Ç`±ÅÚ˜x¿:ð«<±EwIúIà_d¦;.3ê¸ÌˆŠ.6ûˆelËú?a}9CMŶGÊ?©jb… ²öð•ôQžÎeaéXˆ =.3ÕTší-¬1yŠÂ-_¸!°Á„Òdw’ZgÊñrƒ ñ,M/\æÿ@™[Ì$8\mÈï˺«’~¶{ì茬Sî¤RÏ:eÃUÎQ<\UŠwDlaoöp4ǹê²ߨÞÆ4˜4\œqðj˜‡‹C°°³ÈÇ4—ÑxW Ây0Íb[§¹è§sÛ³ösÛä©è‰GÃÉx­!§—bA¶<±($GþÅ!ÉÓKPì&_±;Pì.Yìm_±·Ýb_p±›}Åî÷ŠÝCH)‹=DÅA±·qÌ-ö¸[ì »Å?f¡Ø«”ûˆ¸Õ×Á[=ð­!qàî8â.²oóe†îÙp"vÙ·û²»ÙG„aí ¿ëˆÑØoØáË>ÙçSö6dßé˾Ô˾4,ꑽÍË‘}—/û.do¤ì÷}·/ûA/ûÁ°8Œì÷qÙ}$ÿÙ/‡™ä|$à’ü5“|ä7=°7â5Œ”’ä·Ã}Ä]óϲ$Éï…%Éï£Ø½¾b«ñ:hDûÐWìC·ØW\ì>_±ã²<×Yüë¡[ìĬ>x•Œ?tðæŠ‹š%‹†Fû}ÄZ…bñpêˆu€Áÿ¥”…<ð³ø9Ô#ü¿-«“H³=‹Eš·v¢ÜGŽØí–׈òúÊ;…òθÇ|ÓØWÞE¯¼‹Yâ'å]¦ò®v.ïš,oª!n ¼Çޏå–׊òûÊŒ‡C³±'(ïˆo8¨ÉvË«É#9,oTv1&¦I16[‚—M`rkÉõÓB€]œÙ* |†íÞ ÚAK³¡zã'œz…WÔŠl¹oÈ«(ó3·ÈÕTäÚl¹Õí®Ñ×eË-§Ý±>;ÁëôúÚÒ½ ¯À減ÀæÐ×cÓÈØœðasÜÃæ¸‹ÍI<òIÄž{Ã,a“v±9éaÓäbÓͱi6 6W€Íµ¯Çfc“ôasÛÃæ¶‹Íýlq—2¿p±i#lî¹ØÜ÷°yàb³'"vÆæ°Iù°‚§ÃrþlÒþñ)ÇŸrð<&áÈ×1'} gd¤Òr/ƒlòUp‘rQެàò±„2?3e—æôõ9²‚ËsÜ ®È‘Ü+s:Up°iöa³ Ø4~=6û›6=lºØÏ‡)ós›#„Í1›ã6'\löED¢36I`sʇÍ%`såë±ÙÏØœöasËÃæ–‹È·)ó+·ñï6m.6ÂÃæž‹Íþˆ¸ß›À振÷×ä6#s±×èýg}½|®·ªÌ9,qRnQ›K ÿšÏ\Ùû§æØs¶|ɉÌËve.6÷øøªÜDÙ–Hß-´dRÄŽ¡Ïó*팔A7z%nÌmSþTÙBΆEÝJîƒÕ¶åòv§¾#W.ÐçŠ-¹×ã›s?Çö&>Š/늨|c­ˆ6‹­¾t"nºN7P¦X1°ElËMBrMÆ6W”ËðòŠr¨ÉMº›”´NÚ™Kë$ܪÜM±ƒÞ~kÌ}%íEÐ!´‚èA"×úp®·r;ÊõçÛöÇseã%rSï€T©\4^jÀáH.¶€Næ¦å~t3‡§‰ˆ³¹ <§v50R[#Ÿ— ©â—!;öû뱡-Æsdlp ØPœ‹#ÀÉy$ ovDmžà§äu¬!¦æÉ5ÄŒ<܇ànU)«Z—ç’¤.OÌËKöjŠÍtÖè?Ÿ¼ëØkòÕ÷õQ (j“/jCGÔBŠÚÈ^fð^~æî³ŠEóüßä[ÊÅy=JÄ’<(½d[YAc£ìt òí×߈îסÀ©ú‘ §±FÑàî¡Nwo„»¯F1à.¨QL¸Ô2Ör÷×(öNrÔ(Î.rÖ(¡Ýyb{žäð²åðØ7G»õ¼ßÝ%="¸þ¹[zÜøldO2•³óIãð)öä%¢¶äñ¨E\®Š½yQÇX€.³//Ñk~ßLoìÏ‹†Ür8ÍJ3ùG™0Ns0/v‹ç4‡(Mí2aœæ0Úó² ›²=¿È“…¡( F |A¯.SàÜþWõ‹6ÿk†#*f°«ÌðÊ­¹|—ß'ç‹)”éˆ*ç‘©ù}Äô|É3òå„uD3ó=yìš•Û4¾bW ØU__ìQ.öº¯Øõ^±ëóÅFÊtÔ-v»Å-v«[ìQUlóŠÝŽboøŠ=†bO|}±Ç¸Ø›¾ùºÉ+¶)_Î×góE e>把?ã6߯Ϲx£<¿Ó|}ØÜòÍ×ÍcJ_é³Õ7_¿ôJ~™/^sYb;•8¸vÜCbHœ¯‡à>Žì¬(@.Àé)îãðÜ?K9¾ÀS€\À[pË Äb@£¥ÅRN/KYVÐG,gÿg$›!ÁˆX]€zñ–âÚYÅÑP Ï>7$zííánÐm-{,Û€Ù]ù³£_Kþ‘!¿‰PÆ©S¶©q² ™ $Œ^¡×R É~ÊEedHœ.à3ŠJ¼g Ê~ñ•ÒVÂål×Ï'Á8õäRî§6'^ƒîr:°ZÏBÜ=¦áçô<¬I>)O(÷pƒhõ´ %)øŒP|!a²ðÒEs}„™_ƒ¦»QQˆÁÍ¥ÚàB—k‡â®ʼn…„âäBŠ»}(n`øPœQè¢8£QœU(fQîQhÎÙ….Šs ûˆ¹…(Î+”(n(.($w;ba!ÆVÅEŠ‹âC_ËnŠ[ ¿¶eŒà#['á×Rˆ÷Ü%Ü[(E‚…¢‘`Œvùp¡¸—ý„øþBÙâ ]™á ‹p""&Ò¾Žv¸c½‹ó úØ×=Ú€ê½Bœ„ÁŒ3Ü@Žyâ¡õ¤Pç&•ûõI`ØÔ¥.›ânîåqgºpK{¦½+"õµ<>œí’àÙˆñʾDœç X¿ò•p%ˆ7K¸Ç%<úwKxÜ%ÁÓ›,aTˆJxÊATÂKßÒ¥ª+•PÓU‚B«õ„ýÖò…Îz8RœŒ(P6ñÊ×2ógå™ h¯}[P˺º-³¬«XÎ d“¬èÚG¬éJäœk»ÊQy]WŒ«!±¾+î 1 ¤ÑÒØUìíJ£Ú49ªí# º&AˆS?€q6âp°+x<²ë*îxWÙp ”4-$’(©Âé¨ÈYTä<€M,§cóI0ÇHÂyÔUܧ3BòšÐþ&êwå )Z"¤"MâqW÷h,©Ì¥Þ]>¸$v2RIP‡8¾IË«ÙË®â5rûÕlp7܃¥~ÑMž íFÈu4uE° ÒM®€ÕØnmÊ­¿R¦tc»uBd\7ùÆt|·>bJ7àÃ"o¦P%àé1µ—O êkiRžÞ'/ŠJqË7Q0ß ÿ<¿··™ÝMÌì&0bV79ÞÌîæŽ7sºÉµ\SDÔuë4ÞÌCe†9¸vñ;r4ìJlÈl¢Š<ùDÙÔMlé–H øÒ[‘¶ÒᡟåÄÏqu“R'iµt©›ø¢Ö(™SZ® 3jù°åb·²wd÷b—8iRªOnWß<(»Þ-•┓C,Þ€ݦVj¹híe·ÃŽ;i»áVC·DÙV§ïV'P:‰VºÏ>%¬â¦ä)ìØ· )—5·)7>ŒKŒ+;ì y?¯LøÙ{討+o¼ë-Ý­^„À²Ã&BÇ‘c’L'³ØIL#u”LÂ’E¤ÕÄ%¶“Ì$æËùæ$±‰MìûŽØÅ&vûúºIìûŽA˜}ÑÿÞ[ï½~@&ãüçÌœ3Ôェ[¿{ëV½[ë»ÕD ËD+­é¶Å……@Š#›ã¦csˆþU‰Ø»T^†Tv}µïËèДæ¦A(2 ÂÖ¬t†¯ŠÇØötÀv=€œn®ÏX’“œÑ–§ªôJUÖ\oÅD˜Ó ªÎ*죟W4¦9%S >¶¹¾±ª¬O5ßüy–Œ|hOêÏØÄæ|bss?_ ŸÔ< ÐZv»ï9 oÆñû{ËÓcW,»|rs ¾ ⸧‡qOCÈýˆ7­y7§Ñ{ìó=ͱB®éËl šóEÍÃÔŠ2£@vAS¨ßÂKAíàâæ3ù’æZ˜jËÒætzÁµ‹¤ÍuÿtëšóM€¶ÌU[¹ˆâ ±ΠØÓœïÆg2»bCMq£¥äŠmë9Ò \sZ/¤m=k\ùíĶž‘Ð:âö-—Ý­Úï*Â>yGtÞ®·=5?µ·ÝÕ:Sós{'¤æñ¼¯ØžGÍëX^B¼È$¼VÀîQsþ„ÊÈ|)¡¸v¸Ëšy$(ÅVç·¨cÇú2µ®µ0¬.…ë!V‡ëñß:ÇÂ¥²%LhÁó[tÄ#‡[èï¸7¾ù.köº^lÑhú·yémçÅ-â^Ë-4} Ç•[`w—–`1AvM£“Êá~öÁ-DÏ|\õ´ENjοSÂg¡»]|U™6_*Cåðá-¢tJÒˆ9­4_¥Û¦ùÖàÏZüYçF—ëù­ˆÉH2èðÝhÂò[‘ÁÑ-ÈË"m'Ô·[WɆ+¨²©™|l‹œ\üÉðË]q_E÷áˆ?WÁrá@lð'¶ÐçlB5IùÁ$ZunAíøHwª¯6K¹ÁÞ.>¥EÐE“;NŸsžÒça]ŸóbúÄèù-´ Šc@gâW|i -‰úf¹ÑÍ—£‰jß%*àºXϱ’­k!*^±’­UFÞ€UªÒF¸žÈÔMp= U© ®§ *m…ëé̹®g²„Ýp=;¹öÀõÜ@æ> ê˜ç\ÏdÞK-ø†§‹˜ŠWá[èÍJþ?@=ÛTþTÄØy•(NE'Ô„­"@Õœ|‡YƼ+Õn#RÉbæâ{@+:›0uç;ŠÇh{¸§óðst×yM <€ªsm‹`¬nª‚­Þ±A(àÐŒäÜÉü¸)”zÂwÚ raçø\‹œ ?hƒÚãåç[½A:£ƒßz—¨4— ¢Âã~ªd£j&òË-‚‰A{ЛššÚª’bHƒR^Râ-7s‰_Ó݈ÏeГ},K¢ }ËÌ'>’%~Ç”4%½ qç§K²«ö 1ã÷¤î‚}µ6g³Ú”ÿ¤EÒ:æ|t?ÆúµäýZ†CË3͇ºû@‡¨Ë\^B½h©EpÌ2°¥³”´ËÁ-“vÐ%¨¡¥-yiËœd„ò%3œgþQ-Þ2Š-ÝK~lÉfC.kÉG¶Ô¢8;ª¥ØaXÖÒ2 oLË BŸ¸…Ú<¾¥>¿ª3žÔ2)Ý`ඦ|þ€³·š1ý#^Ø2¨êß ·µÙ2æàV#¨áÈj«õõÒã'õ¾úz¸ãS[âùY.;t9@º[Ò’zÁÐñZÒ’FZx™ÖRZÒ’W´ÌÙòºáŸ we.o™³ùõÀ»|EKz¹u/]|b–ºbëÚ[“omI±L·µ´ìZ<"1¾S §bn«SÔ¶¤ý‘4©Ô² ?Œª[çâGc@ÇZ>µmò8°Õ!Ж´™nÐ-Zïâ·c@wZ>µÇò.$ Ÿ‹5ÄV¸†ØJ M¶Sg»¨U> ¦1‡ÁPy— úv¦¤UïB€¼ ˾ÑÚœ¸›2¤îžµÈ:YLnE›;i2XLm²npñ™­LYgµzjÏçlíB×u_3Þ´B¤@‡Å«Z‰šøêVtF¤™Å²Ë²_ƒiËHˆîbÓîj…š§|î!ö´Ò²çCUÜÛJëˆ%p€¢Í>ÈúØíý^ R,a„CÕ«Æ%6´Â.òš,è#_›½½"¬®¿Þªc5¿ÙÊhói¼§ÃŽ„^Õ,ÅÆ?…ØÊXgk•«iûÊUéâw[a“”t¯Uür;ã“~7þ`Rxë[Å- å·ŽW²6«Œ¾*(høfç^‘x?xÚ×I²ñþ­o¿‹—´6>:ø>î'€§+’åx`å´z¡Š>î.™ö3Ãò)ì ìp´Ö·žãW¶|”.Í>R g≒ñÉËÀ§ÀÃW³I ê ŠtÀ•´7H–QNŸ¿¿Ï–[ìã Z'ýÙ/|þ"bië¤_aÄ 1Ðç("V¶NòaÄQâ󗈈µ­“^Lj"bÏ?HDlj”Œ[EÄ`Ÿ°ˆØÖ:é!JµKD ñù‡ˆˆÝ­“Î`Ä~1Ôç*"´&ßüI[±;B:®Í¸ý >¯uT·ÁVôe|‘Â’þ„,‡ =DJ‚ž$®<ñÕzˆœôY !ëõ%é»òà?ø=@Mê«€d‡bGg2¸bÅ÷ê!ÓÚ:ÉÚ:r«õõÎaOêç>©ßü¤þ9Ç÷Ô×±¾þŸêë!ŽWCŽÄW#üV®Ëìغøè£.ZÙåÇôÂ?êÊ=æâ'áé|<ÆlÒ㼋ŸmCÆf«ñóÂÖú^æqoRëœTêx¤2 ¦þÂõÖ9¯ãZ‰ì¾ß—8oCˆ¦ïã‡Q¢^¦Võ¿K_HÒšáAt'¹‚ºœw[çÜI&²;ÉÐÚèµãNŇV9Ö9ê[ãÞG·?öMÑB—];ˆv7ruÙÅ‹S@P> EÈz¶â~¾ìÂï+|_Œ×H¾k˜ö¢‹¥´Ã¤å¥)È5»ß÷U^–‚騯?&EhÛœ£Ùæaî>IÌf#?ÏãR:ÀÑW¹ø$ /u7û:Zp ‚ÎÃŒKj|{géÃÜœ¦–禈AHyŠ[ÆS«³ôœð)á>d_õn°¯KRp»?óÅÄÉšl¿¯€iÝ”Â×¥ u&;¾>¥ ߀â@÷)Eó-pÛ`œ»%%lŽb'ÛËš}[ç”ϲîÛS„uߘ{RÄÔÞ^”dœ+6Ëx4Ç¡)´™m¬]wøä~+µP™ÁÓ]xbÝiÑs;KÒÏëa;ŸRÇæ÷`àr?ƒë'Гº”Âσðݶªù¸Ûw5ü"ˆÌ]Ðõº77]èÖé D–»mhoùUq!ÈxMH3T±¸ŸÒBøIòPe!Í_OÑð?L悸´!q©²˜ˆo q)ßÄÃâ‰ñÃæa:ò§HÜmŸ½Ø-ñ»1Ù…ÙSÄ‚o[rˆ }äÑmÅwå£Ûò±mñ8Kbô¦Ø"Ö·ˆµÕ+lÌ4»ÍÓÚÆœ+lÌ4+LG€©.ü:NL˜.#6×AÏËÚòåm5ü0?© ûÖÓ0zš…v£I»±-ßl¥Ý@´Ó-´{MÚ½mù~¤]`ÇÏg ÜÚÃ&íá¶ü¨•VàÎ$Ú¯ˆOrMÚ mù¥¶þaÕå—ÛRåWÚ,fY’Ý6“ÝnËïB²»z²{z²ûm n³]§jß!lE¿Tý`Ð~©t0(^EÂkßïÈýSiÔ¯õn SGÀupÐ>!•÷OÕ¢¾½nFç‹ña<aÀ? 5¨6Å*80•Ü¡ã{5U‹5ƒRÍý§8¡185 $[dtq94ÕpÍKQÃRqsB•Œ/G¤feÁo8TùÈT4…hüø¨T‘ÇÑ©"e©†fù˜T£ð|dzÜtÚßØÔ ½)öÇ¥â<· çÚù ã.|çE˜ƒOD¶ÖcƒŽìY Ÿ”ª»Á§<Ùls¬ k(t®Pè\]¡s…Bçë -׺R(tc*ŸoUh¹U¡ ….L%Çí(ãTM¬M-ŽWè‹B—Å+´Â¢Ð•¤Ð•B¡«b ]­+´RW蚘B×6Tè:C¡ëŸ¡ÐÏPè¦ç(t³È(ód³ÍuáÆ™ÁÂPîM5_4ÐÕ¾nì€P¡&ÕÉÕ©ü@ªFÕA¡@æÂøDº«å‘Ô(m,Œ¦F¬Õ°ºp ¯I¥I?a²¢A…$«M{fPªyV©Î˜RR×¥º(¤ºšÊÏRÕ£T-R]Ò¥ºŒRÅÊòê3¤úäYR]KwPªù;sÏê^*j`Ã`”[h‹Ú´Eíxq; ­° \¸¨{ÑÚéuzj;ªÓxÁ:=µŸÙ.jÎÿŒ&ú†œÕk׬váŸÝÎX“%ãN†j>¯]XTt¨¦Sáy~;\%XhaWe°«ìªtvUíøŽg°ÛIìv"»]qìhWÂÞv]°«áûÚÑyŽÔˆ¿&úXí°ÕÎÒÇjF}ÓùvýرvÜe°Ø’ä*&¹ÖÎÒ IæIÊ(É—âRíË…a¸G¹º…ù¹ Ãõ{z¾ðz úeàúé@¦<„ëm° ázg ³?ëÝÌ‘Ÿý¸tgAÐòTéfØG{ˆ÷kð^åÛÑvxýž´£]xÔYZОT¦¡£Å‚´ #2•NhJà}ӂΠ½Ü8'7!è+G¼(MlÞÀoÇ‹é>èDO Ä}úQ’fø=H"¿;iZЉOFÀMnïEè´dtí´C?(¸? , yQ̘4Ú_ç&P̸4ÑŸ­øR—ǡڇ‰EÁYi8ãÄsf[™çÌB™•FU/¨J¼Â[(/OãóÒ ËXfºz'kXÖŒæû~G)Oãåi¦ÕUù´8cº(-Tucº8-Θ.IË©ÓiñuÇ–+ÓôŠˆ"óUiA¥)×Si2Àþ*_“fôÂךð±.Mï”'ÑB6›Òø¦4¬è›ÒÀjƒÍL3­öëD*¾5Í´ÚÛÒXíPhR|W™bà¾;ì1°Ã¢ÜOÉ!ø@b@£iZ8’]½¸ƒX0Ë\xÒaCÁ¼Zû*ÎCqÅq8M£]_±uÍã®T¯bÌϼÒñ4šÈ'Òøq"„alj4ú4ôu*Ml ;¦Eðͳ¤M ŸO37ˆ]HÓ:v¤—ÓÂÑ—pöæJm(W¡Œr¯ôI~ãT"~]¯dóRáÂ]ÈïŠïÚÒð …êc+lÏóÛÇ60´7ÌÊYÅ–É ÛëóúÕ¼oû0îêÂmS4£ß¯=³å´û@ì˜Ö^ߺ0¬½ð'‚WÜ0¢=Þ^lÑ^ß0º}lIØw2K¢)̲ö]øØö"ß»³ø¸öÆå~|{ÈÇ Z¼LŸl·Gÿi”@|Ž x§²h ˜•Ò¥HZOºÃm’®¢£«ø‚®½¡ííùV‹v¶ íìѵ³½}Noo[~ïj¾#¦t[öé,™ï$ý¬¶è'jè'ªë'ªë§¦=¯ÖõScèç°©Ÿ= Ÿ3º~Ž€~ŽéúÙ“Å?¥Ÿ¨ŸJ{¦ø\{2&0ømsär‘î;¢#—+í-ó§ÆÈ~¤»Œ¸]n×ôtÆïjÚëZ£—êF{sÊÏfáÒ™TÜíöü¶ >'·@„»&¯Z1«q¿}8Ý–[”ÉÐMÿLþÈÀ çÖ$%á÷­…é–Dxf¿t$Ar;/20n`º˜&ÙäÂØýi³ ÷i IÇI7ßÕ5‹ã î”IçÃÓÃq–Í«×4kúgøU#%‡’ÏI7zsÒù¼ô@ý[B¦ùú-°,×o·È|~[%ó…x‹góX[1 “®;ƒZ“Î×¥k¸Ù#Qæõ.<»¤½îç(sÞtUáêùzJJÞ21SNŸDRËÝLwÁÔÄtÁ„gʸðìŽäõ@ú Ãë·ÐUÒ›ø-¤Kø?…÷¤»:€»U6»ðl…¹Œ"~‰U©Â%ÜÅü²Žå—0Ö ×|¤_ñ_a‚ü_×ò\¼ÉŠ‘’#4iÝ;Âx7´¾3O ÕºÉ=ÒoÀðpó߯ÑÿNпáú‰½#ý!gŽ;c_·(Ò“qûÃgÖŸræ¹iNéÏøY¦K‰ß'û1cÜ݉q7^ñÈùÁè¹?0í›ìM&ˆJ?uჅ‡¶wί]JE³#n¨2x…›R¼97ÃÑgS•Ë.Û&ž³èŒV5â˜YPO˜ÒÜâx¹ÐØ<†¾}Õn:C{>‹F»eîì `Sˉ6Éi#¡kœ}1K.xY˜ü›-cð®¼FÎÒ*ùV“쎗‰y3NŸ©b|;Æn£ØŠš±QÆ«½¢Õ"ÕvhìŽ^Duœ¨@RÛI:¤£¯û Õü ã¦ûÛãOãã9][¬àgðq°;pSì•?‹Urz¢XçÏ14†;\v»Ý±^!>W˜ñþ\B9ÒŸ±‡pü+©Hªc¡c3 ®`üX*qNziŠS¤7™ù¦Ýbæ›ö)3ß´ÛÌ|Óîàm&H©C—² }Ä"é¶dzBt “Ôë·$_‚Û7š#|~ ð…It9«¨–÷—¢ú–hàJVhö÷ÊÅq•á2:|l¦ˆ ø@qØ%tWú†2áÅž€Ã`Áa˜¸ïÀ~A©xàÀ~î(‰ð |É’›-üò#;cÐÄtèÈ á'EË;¿¡@¬2bš>uºïjƒx>Áe¢)Ê$º{£9I2Ù|A¦ I#pÞIgýNòßãœDðˆ4ÓDšeë`³­`sD®æ  |Tnʳ@¤U§“Y´Š´ÈˆÑ  eQ¸Ó%Áë–/ŒÒI·œ$¾Ép¯™ô:™Z2 à C'àGV|³„ká5Pãx•Ñ—Rl¶ŒÁ¿â[õ€† áR«-õõÒ’úzøw|:ÙÚ…¦Y}U·¦é9Ÿ˜¦yýõü úäÛï¦h´Ï»!ÝѬ‹<<*L°Ã™|£¨„N—¢«yÂÔ^ŠlB=Á>ÿZ´ÏûÀ>;œSE„}h1>XÇú—0©7b‚üP àÆ½­å¡(ÙÛßDyž°·`Ž ûü>ºRq£¶Ðÿ^Ðÿ!Êÿ(èÿ…èÑ>ÿ ísM·Ò“}þ³aŸ?ÂO]ªêp®‚ Y‹EX¤"x÷‹Á:Bl ³˜?ÜŒ9ˆ4ú4Ì’4„ñ!,§Ú-L(Zç¨Å„Câp4bÚͺÝVàˆ»Ù3 „ÉeŒ—±œV")X10U´ 7Wi{Ñ× '7Mäh­Î ’†iHgÐñTˆ‹C¥y"]öõ,&|õj`}Î6”hÓ+ê ÆW1C7«‘,ŒÕÈþº^è_Ì©‹«FûÝø×ó òïxÈM4X—"Êá|f]ŠºdÕé̬c[ܶ äâ‡áåfš„—Kÿ _Ro ˜Kª9³£+iÃdzÂ/“;i%ªŸ¾}Ðå´;]WJU«jz¼Ö[ƃK˜R«¾Ç $?t½Ç^ýÐ?ž÷XøCö‹|(½Ç¢Êï± ò¡5Õª4jÂKY“ðŠƒØZ•_˜·£®|åÃâr žßc°tiÆGªü´x”èÑÎÏŠG9tÑýч~Îx¼Œ;2q†žôõ„üÑG:ù A–ðkŒ¥ˆ« ðêwå>tó›–X'Å^ÃX;Æzø-ˆ….9` ÇrUàÏåãYvT¿Ó€G…ÇÝ=cadú+¿‚ŒÎZ­4­”øjdtE0ZƒŒ®¸ù:“Ñz“Ñ“Ñ&dtÎÂè 2B_§Ÿ £óF‡ F‡%~}"GFŸ¸ùI“Ñ)“Ñi“ÑYrínatáÁ®×‘ÑE £G£G‚Œê£|t÷yzײÁ¨¯éʼŸl0êN@/YGGe-Ä‘Ñe £)†oÑ)2Ÿ†¾L¹`4q7Ÿe2šm2šc2š‡Œ®¸’gÂ2‰ð*ïÕšWkE[_)óu²pæäÖçZÍí uF}o´^l@vV„4ëfCÿéÇYð¶ö@øfÈ×E· zUN4B¼JF´äLý$Üžv“+õ³p{Þý$« ž‰ÆwPòtÛK=°›3:T»ä:6zM»e¾‹"aD°[Öb %…‰©|l%kùžx‘ðP«(üe×gÙÉÿÂøxò²FÝ]u© »\R]¬/làÁNÐàãg­kd~DÆIdt0Ö5ŽÊ9ùoÃo8¢ñcr@L@æ¿Ë{Uó“r8§ÆÅq(.¤@¡bátÞàt^p:¯s:/óË 9]!NWˆÓU+§*s]Ž˜œªˆÓ5—ÇáL˜)êÃ}ƒÕ}Áê¾Î ¯}¿#?”Å‚ç#YÌc+ü¡làQÇò‘œ³Ç[í|,Õ¦8kûDÖ—iÉ._‰››/Pb }•¸¹ù~Jl¡³XÁ)ób…:(±ö@™Tr6ºiʼDÉÙä¦IóAJ`=PnG§é³íË„ù%h§Ý‚C胑±ÈYªˆ|¸ Œ-ljA•Ô'Ö ¯[µ5Qѵ5Q!máµ…WÐÖdEhkŠ"´5_á“•8mMQâ´5Uѵ5MÑ׆i)qF¼¶fZ´5;^[s,ÚšOÚš/´Unhk©­…¦¶ÚZü´¶–ÚZÚ@[BD¾üÙÚë™u.»ìLxŸ”µF1fCÖ(´ÈºNáëPaªŒ´Ú»^ [«s:»(X¥7(âuÔøFÅR­©BmÆSšD q Ï&Ï‚ç.…ïŠñ¤µÜÝ yîž{ˆç“ç^+O*–ýÈSäó†K±;.0ѵ⠨õZ×10,;¢W‹³ :G¢]·ÀXòˆoxÉÌUža{)ñ¶—+Vó«ï{:¡[in„:©èf±¬®Ì@ÒN¸ÓJ~6¾*žÃªˆqç!î"ŠT³oƒœ—ÐÃñM—šàL8$S~¯)†{;)ó×D毉ÌJ×Ä+Q—Uí•[ ¯Ãbè`¾ ÜR©oXjñ-El¤wËtž÷Kß[l¿ èÆó&Ç–0õ>0WÂì~_Aßh&?\1x.î[§S¥ã*tT7ÓáÅ´‹*_¬Wò5è°ÐãöÚò ÓC«"è ‰ÞÁ‹TÂ'MöAul| s«¼X±›C𾏷“TƒNœªÇÓ•ì¨:Úg00§‡¶hÉ †HJ­$£t>V ª´š1NÍ©r‹3Íñs\¤½Õ0\¼Ü´,8ßry¼Î„Ib8p?ŽpËr“$.QºÃtdº\š¿æ•~TÒº‘i2 4ÐC}R<­$TèÁ.0¿°“ø9 hÚú qT5?ý=ádìp_´Žy…š†¿„¢ô­‚ù©Eߨm?Oâó ð¹A(Í#Ÿ‡?dw$5|‚éc„œíUNoÍ$<°'ËF¹N³Pmý… šT ÉL“jެ…»Ž—áEaF¹f…L¬$af–0ÛJb1J¿RîÂ×Êáfp,÷Иjƒ¬åüÖÿ[[ÞxWäiúCýD¸tº-¯ÈC“EüK·½V“{ÏqJ¹0’Ü¡p3m£ðœ5¯ø×¼b˽-ñ:áxOöY™Ç¹ ~Ë9gé‰"öÑÑrÐ ½„ÝÎ/Ð)]_`¡Û‘¢¼ —àùnDR:ÒŠ$ñmqd/¢S}EËX^Ä|U>–WìI‚®{(ïæ7œã=ä‰7ÕÆÄ<¨‡éÑ$,„~1Ûq^HtÇ0ñˆè¤ü”/í©!ý\%ë7ÂzÉ.ü/+ÙÿµÄÿYK¼¼Ä´Ä¦”ÿ×Nþw°“Ýy|ø1´[’’šâñÁ¢kV'AG±§³ÙºÀàt1öm§@g<©©ú­]'+6ü¶™<”¦“Ö)Pð6~Ä =द­(ðZ'þ­^£”y£þ¦Öu“ÏÆ¿çï¹eè/–ˆèŸŒ=àÿTÇVÀØ.+K˜ô6@³ºãè£Zþ=-´Ì}i PÞÑ¢yË<†W<š[çæ>óá¬ýòq1™æÄdi¡Ëf¿ù1?ÐBç͘w͈ù¡º`Æt5 &[ Q˜™ó-tÑCƒÃnxgÐt7€¦§º$h~ŽwÍ/̠饅Û:w§HüW ¸n;”Ó¿hhðžŸ^-Ê ?Î8ë §×Ãàëé7â k¾å8xX?ëðg3þTÃXBÍÝ+‡á¥È=í ‡FØñ4ܰ–;O/<'&rkAØsæDîL·œó€sš?Í–Ÿögq¶grNE§'çVÁ¯ùÂß³nh…Ç–«ÁMÆñîÙÓí´iF0<ÞËÐ`8 ªIM_†_ñÅ–ÿ“áÏsaÆVbNVá¨(÷` &˜M~ ¼îÝ–ÿºEÂü—Âo´Î½‚¼Ž^û€×“לƓ¦ˆ¤ÇER ’7“Î¥¤¿l¨Fz‘H/éE"½Äé¢tquQÓM×Å71©é†µÖ`2ÏÔE†?ÖŸñ´.Ö .ÖZt1ÿ9¢¹úð­D†N‰ E!C§Ì •?/©Ïšô´Hz’ž6“.ø\ºXoèâ˜Q/. &Ǻã{j0YHL¾Ò@_* el@elÄŸM Y×È"²péÏ+b{n±?üFÈ/nœ¸-§êÄK'n‡Äp/ˆ—~.m1TtÈPÑy¡¢CÝÑ`*ZFL^nu©BålÅŸm UPª7ŸWg„†’EñŸl«í“íòÆÚZÎ €8k¬xŽ&u€xM®ü\šÜa¡Ã†&/‰wGoH´Š^¼¯<ǫ陶U¹Ëòú­&Ù2žàuTðÚ¼Žš¼*Ÿ—È'‰@¢cf¢5ŸK { -1´pQ09B •Ád-µ:ÿøZØ‹Z؇?ûñçþhÔÒ¥¬kü=IÃrµ Ï|âö:ñ†Æ‰Sˆ8]'Þø"Ä_Ô‰7}–Õ@â:ñæç•…De!SYÈTròˆeqÔ(‹K¢,ŽvÇQ[^¨FFQù-5²ªñŒtŒSþÖÉõ«:ñ¶çåZt åšQ®YÃ\×¹.þ‘žë1*庘ºSF®·¿P®k1ׇ,¹ÞÑx»þ%a‹N=‡AÏ'L=ïl<ék"éI‘4IOšIwQÒÿIß÷¿oËßòN>JF€“$ò@Ђ‹täzú-Å9ûŒË¿Í^«HáŒÍÙôÛí‰Ow×zMq…ó¦¸HŠí‰).CˆÝÔ7§Õò‰8e¾Çm—)?øl2ŸØpÊ|_÷¸Õò½1¨Iµ/5)jRC¨ýñPûcP“ê@ jrÔä†Pâ¡´Ô„ Ç ¦ÄAMi¥ÅCEbPS*ƒš5µ!T8ê` jBUÇ ¦ÅAMk‰‡ª‰AMG¨ÚÔô8¨é ¡¢ñP‡bP3êp jFÔŒ†P㡎Ġf"ÔÑÔÌ8¨™ ¡ªã¡ŽÅ f!ÔñÔ¬8¨Y ¡jâ¡NÄ f#ÔÉÔì8¨Ù ¡jã¡NÅ æ ÔéÔœ8¨9 ¡Šu&5¡ÎÆ æÆAÍ}Fãw¬œ‹AÍC¨ó1¨yqPóBŠÏà…Ô|„ºƒš5¿!Ôáx¨K1¨r„ºƒ*ƒ*ou$êJ jB]A-ˆƒZÐêh<Ô'1¨…u-µ0jaC¨cñP×cP‹ª.µ(jQC¨ãñPW›¼ ­Â€¿b­±Àƒ=ÿ.%nÁq͹è OVÄ–¤›ÐjËŠGë8ûeí{¶ÜÃø¡á- PT;­5âaFn‡]Qs´NA5Ý–sýŒ‰±;tcA%ÝèïÎ"þëï(¹ý@À ,FÀž&Àáì?Cbã7ÇaVå$­Ó{6Ì©Üó)yWqéNÜêhF¯B}u´WGï«£•Õêh?/4úó½ WGÇxãVG'xãVG§{_xutR¿áêh£`–I»q=›†ߣ±iÈ =›hœØhì¨FcG÷øÜ«£+àé9ÞU×ÈÍ«ìÑØœ|Y£iËz46'o-¦ï7ZLï4ZLÍ-¦†±cz46ã;¶Çç_}!ÍÿMVGÿ–5âòë–Üèë–ü7¨ÿ™ÕÑÿþ¥3®Gc+œÖ²ëüœØç¥ý/5¤Ÿ«dÿ3«£ÿk‰ÿ;Xâ_ý_;ù_l'ÕÑ{æêh¥eu4ßk¬Žæ{ñS§WGè«£˜æ«Ð+/ÄÕчúê(~SëÄß4VG¿-VGÑ—Ì#cu‰Þ2VGß«£o‰ÕÑïòïÆ­Ž~_ õõŠÕÑÎZ4¯¯×XíëͽJ ¢úÃIsATÄd™'ÍQóó᤹ *b~h>œ4DEL¶ùpÒ\1?6 æ§æê¨¾ *hz˜@ó3suT_4¿4€æW±ÕÑ(îqƒÕÑJ1ñVoY£Œ[-ÂÁÃ@ü‚?#ðg¶×XÔã«£+¼4Ù6 „]á5fÛž4X­ükVG¯Ò„èIœíï}¡ÕÑú«£•qK<Ř“ÞØTh¾çéùÌÊg¬Ž–‹Ì„Ì•›™+h<©¾:ºH$-ƒ¤‹Ì¤…ž§'‡+­SâìË]”x_hu´¯çéÕÑx] B] ¶è¢ßs2¿:ºTdhdh©™¡¢ç%[]&’އ¤Ë̤ý?—.†z_hu´Øóôêheüêè0TF)þ ÷ÆÖþxžžñ¯|þêèÀƉãWGK'Ž_Óô¹T4ÒûB«£ƒ=O¯ŽÆW—Q¨œÑøSfÑÐÏÓ‹›•Ï]­Å?Š¿Â,þ¡Ä­Ž.`¹ 0ì9š|æêhéçÒäXï ­Ž÷<½*SùŒU™q¨Êñ–×o„çé…ÎʸÕÑ"÷£ ÷ ÌÜ|^"}ut¡H4-4ú\Z˜è}¡ÕÑÑž§WGŸ¥…I¨…Éø3¦âÏ4olu´¬ñ÷$~utÌ‹«£c'Ž_÷"ÄÆêèøÏ²ÖÕÑ Ï+ Ù²R¿:j)‹ÞZøB5r&*–¥FNj<#ñ«£“_$ׯêè”çåšY:ñ«£–\Ïñ¾ÐêèÔÊõ\Ìõªþ3WGw{ŒÕÑAýêè7ãWG?¡9ôØ  o‹ÎÖëXäc¶‚¶¶@¼‰É7ֈ麾‰®p—ú>=Ñ›x\¥Ðwðãû/ ÷˜z{ЛŒ·Ž­-a¶Ì:6«'{·Ž ë)õ¬c'?’YÇN}¤äÔ±‚®j¯:¶®„Ùß«cëK˜#âû1çoÑ‘LÂï¸OëzH¶ñÌ@Äø°8ÿÃjž&Gþ.üÝpèZbþ¿ÔðF(¨kþÏ ÈÕvþÓ^[äHh‹œ·EæÝzUÁ}•œW%óžáPy‹üñ¬–ÿ,JI~Þ…ÿ2¼Ô䤓‡š^‘Ð $·ó_íä&8Wœº$AqêP½Á¯ûó·ëíày{;ùo£¡êŸz'ðߥÛz»’æ‘#š»Ìõ‡:6¢©{(ãˆDƒ®Ð¿oÌPIüA·q”‹;ðAEz¯åÿ’ô>³ñ?Ý¡¡~:ÉîÏü/ Ëüü9ò±çÿòƒØaþfèëãœVüãtÛkü?‚1Yè ïÆf1áØËû¢×Rø zy?ˆó•úm¼ˆ¾á~ ’ÐÙ¦AÔj/£$% O³öË29ó“¿©"bœ?wœŸÏ€‡¹Ã]|6Ë9+Å÷ö¿Ûâ º‚ /g?©çóYÐI>Ñ…};èÈìç hOôg½‰¿¡Z¾†ÜqÜe¶5Œ¯c¾o“?·õ¬Wß·sZù[Ùrû¾Í7`xØ·,“|¼oO™äæ}“x“EžÞ7‹§±Yäì} >áž/âð&.`Äp7yšžÏjëØž¶ÝŒ^*†×Í%L Ãu^@ŽÀeÛO•(\¶”0õ(ã Íiž¯@Ͳpèhf¾ U÷ *©tÊJ5Üý:¨~—!4?Ä¢x²"? ©ö½LAGYÔ·0Ókç' J`—‘Ÿd©™ü‹íáP©+¨fÏo.ó  Rkh <ïè6"=gü ˜©ôžß²˜¥•^JŠû žضˆÇض±º“¹m#ê‰Û¶qЃÛ6JYl߯øl˾ æ¶Œ æ¾qÿœ1öŸ­©1 ¶vȘòCccÇS˜"œ=‘6và=íï˜àÏžD!’ ’U{žÚêñfJÞœ¯ñàÉ."‹µE»ã«7¶BößÅ 6çÛ»<¨åÈ~Ù–·ÑËÿ¯Æÿ-p¡‹ïÜwmy[½¼«†·=7®yðt„dJ9Öp3–ñ‰Èû°ÏÄhJ‘sÐà z±Ùå…Â:B ;RL¹‘¬œñ¥D@Gˆ.Cg3»¼âˆ†£DßšèOô'?…D{¼ü4mW³°;ì.ÚdwÜ’ü–‘üã·1ù^/¿K[Ô,ÉbòÇ|/&?iIÞÀ}Í>/Œ®`NY’—¢o™’Ú‡ÉOSòïSÌD#ùD‰O†äê~/Ÿ*ÅNNÙàíCç‘N“ð>{y'<6¸löò™ä—¸t ¬ÕÈe Šóx6xC¼º'ÒM^Ø®’¨G†N}ñ!w•ÄË|kl‰?FÏå ¾¦IG¥ŒE©AGPÁ"Ýþmr™›‚^1•^^ ,ï ©,±+:Ky^€-xà V˜—×Ô×Ãû´EŽê¯ØËóÕó‰J˜N²Ãåì )g)Íù—2–}ûÆ'+ŠœbFI0#§)ZΩÿÇ MØt­š–;¡Ÿ!n!In…Äg)hÉbΦˆ¹åøFäy.=¦vÊ æNtMÒ?ÒØ¹ºÙGª|¤šÓ,hÇJåkưèø(ì¶¡6V·Œ„‚šµB£€®TQQ~Fd¸š<áF„Ž¥i‹t35’Û#élªE›zÔ$k”^Í:áûnpàSUkâ8j]Ͻ€~ºÎvd¹©Ùqš©êíYœfqgÇ`‡ Â)nÐE5.QI!BƒðŠ«—+aD{‘¬›ñÊ}óq=¯PqnÿºG…|%£×d“Š/Ýx!6©uLƒŽÍ¸†alY¥ò-z‘‡qa ú %Yè±–oU#$ékX¹¿Õïñ4:¾M¤.Ð_Î(ÝQ¸Ýô£óêÕ)Ý5…F­ê.U·ªáH¬ªLVuú.®óH*ôÙ„üx”OjQM›ÕÃV«òãj­D'U­cö5/žÃ£e_öÚðhG~FÅÆ¬Ù[4Ÿ™=§òsðÎÕbh!¼ïЇL*Ñ6E5ü¼ªE²/Aúsê×¹é…úz§â„á® Rh/êa0§WP$îÁ½z’DwÈ›r!Ò•ßSµpv-àÜÞUhx_CîÚ»ì‰ÊŸ¨9MMB÷ßñ7a†×«-wpgžoÏÙüzçþx¡¿c ÿD †Ú±È|¨`Jí¼ÔN0÷ ˜áv3"3anRçùïf4Àð1vÒÀfײ/B†Æ‹ ¬dìZRá$L|‹Æšé”xž!Ã<;/‡„' ḞëB$þ”ˆÅ˜­Ò ®´óµ:ñ:$ºm!Ú`7ŽA³óM:Òf$ºCVýC"ÚADCÚØv@Öûÿ„ᥠ ¼Ž^8^Ç2e‡ï±kð•'¨ð½ö Úu“¤ò}ö0i;fï·k¯õ¶C‘lê ïnБ[åu:œv~¹Þõ(v»ã'b(ep­\«u®Õv~ÈNÞ7K2?lÅ>‚Ø `oî­¢ÏgÄV ?ŠØ÷hÈõª(c)\´›£”KõsõËv­+ªà &¸ïQvG½L)îCŠv…Õí kÚÖ¶+ÄqJÃö­oh{ÚµŽy[¼ü‘ÞÕf;˜-ãêxÆDËÅ;w¡þ²f ÐzÞû¾Ð „W¡Ÿƒ÷uè=³«?ÂW¼š÷Ó­PËÐf iªcÇAÅ^ìƒ-àˆù@GhAˆîr?RVh´Zƒá@«Ð]{úv©hö%aèËòPЏt>ý0C†©¯ Kš,5Äag>\À5û5ŠR íóHh9e,ì+cŒ4ÂGC‡O·JÔc=Ó¿¨ö ËÀ„ó1¨—ÀŠsƒŠ/‘eÏòKIس‘"&{¶Ÿ%ýyÔ”0u’ƒOr ìÅBÙ“0°‡¶t^D¦{ Ô)Ähg¢?’ú43&û¡Ìø|b™«Ç+¼Ü‘³Ì…#Øe.–½Ão•C뀺Ä[&=2˜îÂômtX*ß }’-^㨃©þ>Í–Ù¨ð·7(ü>ÍÆØôÂß©þ.ßùtáïzºðwÇþ^ßK…¿ ?¾æÀəʞZˈ^Pèw6j®Ý)>Fž´«hWBö±Æ|>ôÈ`îBb¾ÉoßúoÙN8è¸S~ òzÞ«·J§Ø µÀ1ÏÌrrfz³ŽÀˆ%‰<ùŠÇì¹~‰_É7Åÿ%~Ù=¢¥@ާÞ/^GôÍŽaÆ»Ún€o²›ð[ÒMº—Ñ­åOü†CËèê»àe Š›pÿ&Ý×ð[p_Òjù§ð0º5=îmxºýÓlxâwàvd7º½ ·ÿ@w÷ÐÔœ÷òû­‚ÎåzCÑï±<3ÿˆ2ŒÓÝ0‡Zh›7wžŸ?tD-dTKÍ4ci‰4Û½¹óýü ªâ1Õ°¢†8Qµ¤ýg«…šÒ׉¥ õsò¾NÒ6g„&_ú;QÇÔ9HBôôì+÷cÖ:-½è@Kß—œ¨^wvêãNÈõ GqÌ9 8àÛQJˆ¢ÎX¬Øh Çò‹£™"º 3ó(gwžz$°³DÙŽ ½Ú[}¤ïjçÄ’裸œà¤’œèäãœX’—¨$Ç;±$/QINpRI^¢’œè¤’¼$Jr’“Š{ “T¨x;ʼn%‰wSŸU‚X¹VBÓ5Ýɧc6B ü¸Ú4éáÃ<Þ6/Ÿ‰И,ðóÙÎÏ,`‚\UÈÔ¹N>— úéÌ9ߟ·ÝËç¤=w¡Ÿ/p¢yCqxÖˆò¯tâ9‰5ðú‚’¯tÒ©ˆulÀOl•N¾Êg£à]Öä|ô¦Œgç1b“y›LšŽXbØÞ† 1$êßnÐÜÂNgÒwl6­S¤ÓÏm¯Õ¾ÖéË2¾Û™óèÀVoÆá–qýÜ<Þ“>`Ýe_‘Oö?z‡É)Ð;;àìÂz~ôÿ½³8“-òÛ˜Û–ïESÒUthJ@üZªÄ¬ÖÉ8¡wvŠè(I‚µ·)šcÎ8óqÂ3'QO^œÙ}‹`/°üŠw5†‡îãÝÈä×Í×7{±c'FÛ ç(˜å‡ ßÕ±ÇNþØ™ZXƒfü‰³¡Gàüñ´oBDŸÈΘôRd9õ'ú%D¹‹ý¼(ò{Ó^·ÒQ KÌ5šu^üëùm\‡Yë¥h\‡éçÅžŠX¤(òâù¡_¸qL83£EŠNük´ñutËOñߢøÆø[?µuãÝPº¥þ|µšwǃӼÔïÈ]êç=Å”éÏ }1”ÙGé­§ÿ Í8äñßÄPòpê!§|~Ž„–ù3­Ïa~e/é,ñÉúäÁ`(Œ#Ÿh}=ÿWƒáŸE· Ot@ Ó‰áÇz ~Lõâc<êp¡ü—ùyùñ§Üµ&â¦SÃý`A‚à^^/ž–šLDeQ§ òg¤bt›œŠ8寥¿žß¡•°ë^¢ÁìU™ÛÓ©Á©ulƒm—êØýÖÒv©W¿·3J»wÌØžØ±›”Û¿âŵý/Ý8Žg™IÀoI¸vIêuMê˜wMÂÉû졉ä±Þfê•!E+"<Ž3ë'åœCrÁý…bß!V×a^Yòx; 7«ã2N[†Õuvœ£ ƒ]Ï{àå·q~½*ÇÛ”èG*€9¤qUf8(Ôãý6ÅL0f~&€)UÂH‘Œ.Û'+]øTE ç=ôℚæžhË™Èøtœ;aÁމػû1b$)»PLü¬`=öòjáË›ŒºÕB“]¹—’y­㥜–ÇÞõ·d4l:„œFY8áqH¼RÕ#§Ñ”‹¿£˜Û§Û ¿‹¹¨¹¸¹x€œë½ü¡¢e…?BØ2x÷=Þ÷(ñP‡Wô´ …á÷ °¶CU^ Æ‚Ä0 W»ð‘0’Ì+Hä£Õ-Ñ•©Ð5¼ååc‰Ž²3NÍÙíÈÞ 5ÅI‚ù3Æ’‰¥*ÞˆŸ›$âXK&*U=•*_«†‘‚ø¯þßD¾Q‡Ý„°ã(qkJ|ÖH|V呸‰—_B¢ñT¿(ˆ¼ë€÷oêK^\+{âõ-÷ÛŠðìÞ ¬d,’öÇñÑ¡¤‰Ù;BcvÙPÿ†‘BhÊšÂQŠù(»tŒ=L Ï¥‰8ÖEoã6Ë‘ÍJ`SŒl&[²Î`µ{²)l6›ÍȦ8‘oÑÙT!ìÊk:%Þ°š=:ùVêK.ôÍZöÉ· ñTª©!âZ;.?Á8RëZå°ÁPQ }êmÖ[ñSÐ&·óãvzúTóSyË~ {ØgìaœGâgq°ŸSÀ,´Âï/`¢ŸG!¡–\€+½<—qˆø©—_E¦ôx‹™x£)¯sÿbãÐ?šóÆíü&p»j‰jà«’üMœk´ãmÆ<5ng'f_í"ñv|ÿ°3ŽUñ¡Ýòf%¥BÈcDïIÆa^½oc'oätÂ0]_’@âÝíïÐåéï yú;` ‰ò„Až‡çì7:Ly†8Hž Ê­„†w²ÚrÌö* Ç÷EEF9;•v_U¦qè¨Ó;@™3£Ž;;3C»21ްN Ö Öyĺh&¸dÅÂY—+fÔU+žÐó bÍ¥âÿ5aÝ@¬[Tü¸Ìô©£c&¼Ðvâó]G‡Lki¡~âù>?rP)?£ì@Ù#Ùc$«,›mž¥Í…áK'·€…†W­Ôi\2Ü©h¬à6d¯¤µs uÿæ3Ûèþƒ6(çK˜4ž%¡G^}hîÓ§‡&¡Û^hlq0‰’Qšä죎­šMujÙ£EC0îGƒš<Ë©ÊüˆxÎE)çèkŠ“–¢YÞm//'d¬u·þ•jÝ„,`˜¾<=]ÖB £êE¼€²ŸJÀ¼Bà^ƒ•NËö*$\èU$#×ë)×ÀÀmtòNäzAÐõQ5ßì §ÛÿrPE2†ÅzyÞ/ß ØwP UPg ¶Q D¹Þ¹ž ¹Þƒ<‘p_}.BÄ4L9(Ò¡œÕ('À×bšÅ$ç¿Qš$ç%ó”“Ÿ‚÷½Æap m«Ø ÷Sîsqrßõòóô®!÷,!÷ 3å†1Dö,ì•¡ K,rß@¹o1É}[¤C¹ï ÜÓ,¥–ÍKiŠ Í@ìý/£VMXÖQ úlë¨>. ÊÖLÆ'& \¡qàË]oèdf!µ›“ ÉèŸÈ§àµ_"ŸŠx„—Gx³ ¼Y |ŒsÎeÎf†VûqLú*¸¹ OÔEYåbÉÞ ®Äå_¬Äóºðò<ï)‘/Hg{!2\Nfu¼h«–—%ðåÏâ¸âÅ9®Ž«À.˜û€úÁË ƒ ¾6AËE±NÏøúlc»’Môw ìF]ÆM(ã RJ‰¸ÇqO?@c(‚@ù‰<ªk´­ôÊ`¦)”겑êr Á \MàW®Åù]k’~Á`äs#!ªÉ4…íŸ(²q²q øŸ"þ=è…'$-Ç$¨lûÄ•m²O0Å=/Õ¼B—®Ÿ+écL5Èömˤ–‘v%ýŽÙx©KË ×aØ•r5P35âËtóÝ€˜Ù鮤Ž;ÏíJÐ’†ž.!ðB¾ƒ¦€w„€8ÇSéª[££¬…ç±€Œ«}ëñÈáDš}ÚèEµÉ%4[åJZƒÃĽ.4ø(Ò>W8{ßF›^¸´œ®aáTèi®. Iƒq˜5iZ˯'PmiÇW< §©î%P*‚XRgܨà¢&TII_ƒ Y.j DLxîvQuA Z‹$¼S±¿›®:åVýëëÕNOê{?©÷¤ž?©Ï©¯‡ uEhСúU킪² †˜o²èn»ôšrÖÅÏcäjËyň¼ââ×u}c%©sA%q=ïEÿTWÞ½g–RÜ×Kã2¬¤7ò7İÞ`Xïân2ükýP¥Üñ ¶ÌýÜFs]ØLlaЬ„3„aìï6[˜b<r ñÆp°[ç7ØÍ‡ºŸÙõ†iÖZ(£Œ4£Ü¼Ì-ªÓ$ZGDoÑDƒh¢›Ov‹J5Õ-ô2ºç¥ú6Ë-Þ°ÙnñÎÌEœõ4¤mëBg¡»ŽíÈaËÜ|1$ॗu‰» _æ¦Ã¢.'Cs¾Ò­EÄ6B:>ŠFC©E8¦^…ÀȤCÿ<Ð÷oÄÉ÷÷ôaýj)g]£ÛmO1üëù÷±Í¶¢’à Ã&¯ ÈÏ™aÈg4ÃÏzYgŠp†a3ÈàMl{c^"Ç·xÁp~a ëußÛ!ï¾WL|lñâ7I¿ ÷uV2-4‡YUPšÞÄw1b£±+t#Fª­[X¾w‰Í6+äµ™f!ogFj} BR½† äv¸Ípa/›W3­óD[&¯7u% wÞ"oâßa’ã˜ä$Óºb¡Ÿf¦-Ë›áâg‰yË@ËКïsçèsâ÷EL\‡‰o°ÀÜDîáìÜM|ã½[H½Ãk—½‰o’cIWœ/ÁÄ_€lü©å`.€§]²;I™XаìÂzàù¾Ðþ¿æ¬ÿÌZÿ{þƒe×õÜDLŠa7Toâ÷ž]fBEˆ~,=d½úë>éú¿UC†bkÕ(ƪ±ÄJl’vƒë§^ÒÍJª똖q£„å­‚Æ”¾0!Ò¯ÅeTà'LSôú5=ôP€K#®oÒSšjt´êÅG“(m>îC-”ýQ-û ôŠ 7±-i¡U‰X༊Ü$yDñNrWã„#tî*¤÷Xjþï?q¥À;ÅU°"1“WÒµé}lwË´«3ô%NÒ~Þ÷XÎï!)††6ø}¿g·UJú1Nm‡qj»FLmïB¡~}xÁwëÏe˜²-Tî%<¾/.JMqJ\“p6¼©—Úˆ4ç@éû#óëŒê)iººÛr7úy®…–%"Dîv*`à÷TG¤ÔLç‹¿LÔbëŠÔ÷ goH¤}ÂaDû®Âè-O H,JBª+ ºã‘Ÿ+ù}óÈÏRN©œ]*ÛøCœ¯ Sé7%¦Óq¾r¦¬…V a‰8¿¢˜ùÆ,å|™/¤3)iÇ”™áE2˜aYHµ\F÷%`¥pß1H·F¬3\/lÀÙÍ(ñé@|v|vÈ|Ά‚ÑØm’ïAòƒ/ À—@àÕ(p5XÂÄ&?§˜ëÐu™6‰®Öõw$½…®Nä·åÀ —Ùÿ[UÜtpGÆû†ò.2¯¡W"Xâf?%ðsZª„™ê3“µD,^ÛÁH,aR½Ø/ÙWåõLÔðz%0?3›¿–ç«Qê-¨Ñ¹Ûý¼¯šÎz+؆AÍ“¦©¼¿A%•i¾ý‰ 9ñbÕ<[ ª¾Í‰¬M‰ Tø_Œ—à)ÜT>ƒ€2» ^ÉÁj@;Ý–$¾2:Î¥*îAH•V CôÔ!0Ð 4“EW#µü¦ŠS3ß2†¬¿Ä±…Íx˳âW£ùv ú¶1hÅIªb ö¶1jÅÉú¡v1ŸòüaëŸaØz÷I}r}ýWëë»Ö׿__A|<.+œ¦¦»©ÅØ;ƒÝTïôŽ`ËÙñ"Õ¹‰ø×ó­ß.ÿ°»z0µYƒî*~;•Fµw¼Q0ˆqŠ•‰¶¹Œž«˜ÖÝ–·#‘ϧîh9öAÏ{ñ[¼¦o~¹¶æ 0žSí?£˜kÆå£eé; {ü@'ÚgC•›8TÙ™Èï0\¥~ Kî.Ó"øÒå£MððªžMÝCÞ‰w2q(Á>ì`è3íH ÍPý%È£jïL‘‹0r ~Ô–ˆ[;ø2º…&'õ%l–+ŒÇ|™v,,Ï“a”‘ =ØTô>î•UÕ¾Sèa½$LœBYZ/Õ±«¶W¢šöIøYZ8o7 º¤pj2N˜ì´ÔŽðI|'täöJ˜‹?Õ@¿?Aú­aÕä~•ÕšÝÓ B…ËÅçP<ŒÏ“]árÚÒŽÙQ=ðȯFzæ ïDûÄöI[ähäåá <úx튥à ~\{±à®BéڿB1…FªPÆ“Î@”Xô¨@Jdk ö’>þ‹jïJɦÉzÍ™&×±»?eÓdüà,’·-‘Ï‚TÔ_™-çü1 íü?ÒFÅ9ðØê móQXîöDq@ù5ªoìZ‚úŠm­ ýÉpºm‰ØF.l¦ŸIU ÚéÏä›d,ºë0DUí€=Mìb†¶%¦Ò‡H»e-p½ËÿÇÙ{€Çq‰Â;y6`g°%Ë:éèLÐ2déü~~öédZ––ÐB$+˜Öÿƒ,îöpé9P¢uç3 ‘˜ 0“Ì ÅI¤À$æ ÀDJÌD3'ûWUÏ&€”ì÷}ÀöLuuuwuwuuOwUлÝ'`ávQc§Ê¬çí½²÷¡m]\ŽJl¿"M"ØÏ·[ò|éˆÆzÚÝù;|èÑ{t/ìÑÇ(& ¥ íôA õiê²½ŽAË|wîÜ|ý{R âKÉN7;-…`ÍÛ'“N¹¢ ZÜ9 ”§env^ Ñø¸(ñïïGãßß/!ûuÜk¼"×ñ–Þѳz/Téº:nȳ?•Ž€ùê6¿›wGb·¥ìvv‡®É¢> ÓšÔ%±.)©Þ—Âäf~(^’aÒœP´ÔM{~Ãá=”ù:ÝIB^í^up^C}o—›ª3^†Î»ËÍ&Ê¡ÞXZ™Wg2^rG¬c)SðZÓt9²±JD@ü+0¬^æù7ÈÝkß„Úãeªý¼öóéZ ÝO¤.=‚r¨ò|™´ãX×nMw1”&óg6~ãg74ȳ𼌲‹`u²Ü*u dWÈ=¶8Ì7¥ç5ñ®í}*³OdùìS~C&»ÄZ`×d2±" HƒFBãz=Í€ŒJJ¤Wª»Y~à§û@WÒ$YQ«y]wÈÖHÙaUCh@q—ÌvÁ:‚7`Û-£ò€£"X9Pups6H5¥3R¡D¥AãŽ`¥÷¨‚Xõ?سþì0êjšdWÔr™ ÕI…: «šN(ÍH(†Õ‚xÂÊjAºaU5ª¸Buµ ”CXS-¨Žª´J…]–IOz¦mÐÜð ºá59 ™Žóqƒ׏ì6t½ß´Pï€öÿ›÷7‚¥s•ìs³ûr8ÅèpRt›› S€)ûÜ ùAÁ` ÍÝLÔA'êeJ/Ï‚ˆ/È ¡†¶DDS|tP1éèñØp·X•U…b ´stPÉ#~9³/ìÞ‡g½ùå¬ÂG[h´RP'DðôoÁ£!w·OT¬™t°S)x>â}^y½‚@6^ñË a¤»!ô4"ŽÑMìvµ@âžœŠÎ&ƒ¢ìW—ðO¶~ͯ/¡šOÕH.(ù¹ØŠÔýœ¦dEsA±…3ñuqi–„ÊyÛÝ"ÈÕk$Wó¨;4ÇTÈf…ú¦°Xa‹Ün/üÍÈÒß´ƒ>¦óàË€“q‚›àËñ~ ®ôV ^z=‰æ'1šŸX4×p½;Ns­Es=Ñ´8ÒÜ€4C¸|Eš7Pë’Ÿ­ ©Ž öĵ®Ç€@›ú?ƒÚÔÍ4¶ŸYž'žXÑ/çÞ›9eoäŒ|ã]©¤¢èÝC„gVZàwÅ’J€-"öXÕ/çÊ›ï %U¸ów+Í)æTáòh üØCT<Ìú-:©È¹Ð«¦² ÷”Ûô~…?gÜ6È]U@ÜgÞ`þI·-á‚âB/4ýü®-Å©ëGƒÐ3ºo¹ €B“¹âÛ0&š+æ…äæŠ»c抻ñ¨=¨†™d®ønúæèCi~ˆ~[ o½¸ý2þÞyÙ…]å'…•ýrÙó…¨òvQz¡¿ zpïÇ è¯Æ¬¿Æ­¿ùÜOSeÃ<Í9øVl å-¾ƒò{?›´•Óg“>™¨Ñÿ MÝõ)GS'*ÉÿYÂÓEaGD— ¼e…Q ‹N:Ђpƒ–%5?n¾t N6Ò؃ŽíëèüѱæêèèLåô]§4ƒÇ@í¼ÐEçDöO¸ „V‰xä8M†æø»às¿ðýÂVú‹6Þ,!öß…“úÍÌ…Çœïߊfå‚ÚÐn'suåoƒnbÙ«+u#7’Ìr³/ô~éþ³L%ÂhV³¯­´Oœ0 „Du%ºú&Ö2nÕ÷a¥ìò-è=í¶L³–ÅJ3‘—¦ì äÜ’o¼4Oùž²•>#³ ZËKsJS/ÍJ€D^Ÿ×VêíÁ›h‡ÂT¦æÇCÙE³ƒ‚…‚Í{<£þ¦žxv÷ÞÄ·LÙ¡¥ªßù~g+ý],» ÷ÐÚÝ ÎÃÃu1”3gÀˆ^tÑ9Й/ºã¶ÝÖíÞGê…ÂZt²íKH}éû¾ïÛJ¿ŸTÑÊé Ì–CYJÑAÚ[«pã%ë\P]®t«’aþ¿'›9ÐóÛLYª©¶ª©ƒHª:Aê` ©ƒ=I]y3…TM‚Ô!$5*AêP ©Cîo2 7:Aê0’“ u8…Ôឤ®¦–jl‚Ô$5.AêH ©#=IÍBj|‚ÔQ$5!Aêh ©£=I•¿Bjb‚Ô1$U› u,…Ô±ž¤î¥V°.Aê’š” u!…Ô…ž¤¦æ§šì†i×ݺáÞ¿ÀTÛyÀÏR¬´¥Oغq/…Ÿê¶C1g —Ç@ÏþÖC§×oÁŒz'Óëøsnô*'<@uwêÔmFmðàÐ!Ÿ{cPȃæØi±k•”ϱñ9¶çØéînsì 7Ÿ1M6Ìß‹ÍOóùñûèŠÝ-Yò%&\)‡˜\©‡)y±è4YŒ=ëÄ±ß KNïKÜöFaKfh‰èß$Ù¼æDƒÞ«È¼kî„UØzªÙ“I¦]­ü¹i×ï[¦-«šešÐžÍ±¬à6RöÞžu’©Nò¬àÆëôÞè^›&Êû[IÓ„•w̨R~?í™_²­gÙš¬ˆc·ºç1çayäZyÌ}X’ïtÏcÞCòˆ[ñžŸµwqÔ.HŒÚ»)£öî7ŽÚ…ñQüËFm¿”Q{ÉeÄS–n› (ø´)‹0ÆBés >óôðó’ÿ&µ»ÕÚÈáÛÒ!¶gV[ºt5êÒ›ÜéPýÅâåqîÛì߆Á>×€^:ψ9y#͙ܸM5‚i†¯Ì'¢£·îzt’›½\é½9Ûòò‘ê¹íòÀd§+ã«…œµ¯Çý£ôNòŽRûa¯(IÄûXÄÅ¿DƒO"$R3©œ)X5èÙ=œo\ôL4b¢g¢H[º‹ž­n®¯ãê}a5êëÛ¨å-ðãàs}ÛÐÉAÉÆþ4,#þv±1س·J&T ¶X?Tw[ó­C¬?Çxë5DÖ÷^´ !´ËÌ^¢óÝ1ì—)ns¶×‚pì\ÄÞÃ~…â6%aû,Ç~±·Ä°_£¸-Iد[ŽÌ.©5Ø/A—5èÌßÛ¨3X¹vÖH¿Mô;›~çÐï\úG¿óéwkîÃK6B¨Ró „­S@“ñòŸÀ«¶NX“À™¶Ný`³Îްu OÍxeÃÖ) üÞ0WàÕå0…NÍxp˜J'ˆæ ¼ 8L‹Ÿ Ò颮‹ÿ"Õ3¢ÑǢѿŽF¿~ŸŽý8ýûhâl¶«n4óFK_â×GØü×°7IOÀAO„|Ü´ö/ž(ùÈ .­¯»%XZ÷µ¾hõXÛ/çâXZ×B£"<7°®_Î¥9`Í\‡ sÃý}±t¹î—ÛŸ ž¸6àO«ñ—ì­ñm´¤%íÙ ¯ ¯ôð¿ynÀ×ù ½0 §Ãqé[yIIÎ'ôõ ˜\˜¼‡Ä>ÌprQ_}HìÃÒ>¨"ꟳÓx3¾Ü¯KZ/÷WãrÿV÷åþmk¹ižå~-.÷ï$À:òHjíI"ð§ÁçØó±=É¿ç{’/ )Ú'ÈOÒxëzêßî¢EjêÎdzQ³ úà§–.î]ctÛ»ßkŒ©ßœî3¯ÑÂW¡£z±…ö:׋·s½è<èEÛãzQ´Çþ\Ý7héŸu/^©Ñ}×´ÎÒu×á°Xo$vM‡XÄd‡Xu Õ=îr/èY(è¶xA‡=,i~rÒÏyÒsôóxÒáÆ7Ô1±£ªò}ÎÝë8"ž{7ÞêÉž¼vðÜ/@î;â¹—±¥@¶/ÛVšÔ+ŽQ¨t†r&U ES‘»›bk ‹¬5ÐNNô"Ý'ZNUB_fðýÁVú‡8ј/³°ˆmFþoIâÿȇ0ÑÚµþ¯Æ.žã%ÈqW<ÇŠ¯OšÆ“îæI;!éîxÒJ#®B,E¢Êˆ«KSTˆ¥=Uˆ³©ÚHu‚Ô2$U“ µ,…Ô²ž¤Î¥’• µINZžBjyORçSIIjARc¤ZRHµô$u!•Ô¸©Hj|‚ÔŠR+z’º˜JjB‚ÔJ$51Aje ©•=I]J%U› µ IÕ%H­J!µª'©ÎTR“¤¶"©É R[SHmýF}rŠÛ¬üe›õ/¥(”K ìÊøY èiz–u–8=éêÛÑ!Âmqà¤~Oúž´MB=aš¡ºýï.W˜x†ƒAÁ‚ÿ*Üç+t¿%¼hÇL|ðý—X2Ø\=H®aJÎìU¶Mb§0Ê.`ðÉ0AÜ$²-PÎí•ÒEíðzÀ‘ÍfÙ&ÀA#ÜìAe{‡©‹mþï7êÈVÀ." 2ÐïÏnëí°~öÐ[. Š~¢ “ ³®ý…ÄH`D.B h‡Üæ#p›ÀP™>x;‡·û¨|xÛƒípwøš=?@ãVñEe¹õX¬Žx±"rAÙö[e;"FÐr;†ç·Oʶ’ýz‚ éËréê=—çÒ­þSxdpN£ø?`°3b0\rÐ`0ñ؇Æ€iì‚ñ3¤’¯þavr5‚7R°`ÃL +ÃJè7„âkœV|yRüa‰`im¶&CSu{!¶j)mžZ-ØJ¥NaZµ `x®B1<]!HB;Ë¥«Â¡>4[8©_þmCe•Kø[/D°¦ÐÆä$DØÔ !L0DPÙL O¦â((œóJÄzEˆ[ÁÙ ÿ¼ì$<?¨\õ+¬kœ~µ‘5òüÚÄs(÷P¦±ÙR„,{Αüölïü¯^é@ç 3…#Þ+†Dè‹t–þc±Î>’üz]r1Tròâ×rÙ © Ýémwbýíl%ÀüöÀ-ü„ùû}"Þð„$©ŽÒÿ,v°O€Rà€/g^µÐ³Ûï ;ñ‹‰ègDt£ébÓÅN¶Y*\ñr– úÐÄÅ.¶E¢dƒŠÓØVàf±›}.¡g9“m§0í@°ÇìE^æW žƒÐd ª…Œ¨„G­íÔ‰3C I~w–m JM¿Ãïž8ä+ý‡ô4ìk,,ý½0 bðkÄ{ÔPè›]D2ŸB«R«›í2þ´ÅÜüº…]8Ül©K²Š50Ñ~É)ØØAÉBžÍIþ Äö<ƒ0±Dx‡ÍƒÎ[2È-žÉŽã#úÅKg'1ÃS’ù¿¹§ <¡ùi´¥I£e|ž·%_/p"~Ó2Ê‚þS”?½™¾yuJ~Ï bƒ®}\‰åmðãæ7¡ò@ÕèQù[¼ò·¥Vƒ]—üFråxå×@å»(–*O2«È鉅„#/d"vú«t ˆwÚ$l„ìÏ`e„•Ë~)û¬D «”ý*«’#¬Zökù_v6èø%8©ðZ! ¿1hP1^Ý0OÝ‹²ñ€‹G, fÒo¡Ü™‚w?§ÉÁÂV©p“ÔÛ{Äðˆ¨-º=až”g9al¢ƒÂ ÓšËà)Ö½ñP…¡8» b*òïQúd±£o±à üÉÄf «¹Ïf¼á¢jAÄ’„áÁrAÆäš‚!È5C{†gž×1Ø6R°o‡p1ȳ~òl„Kª×^—V i—U ntʱ$Úi[@¢1™íA愱§¨aìZ£_÷öI8EaÑÙN†vG'Û…Ø]l¯L*`¤± e£‰w¿îO#‘‰ÇºÙ>9îcź)¶Cö§q¿–4p[^

‘T©°¡ ÑøÆü0x´ª2B‘CVíýfcƒßÓDàr¥àItâä1éP¶Æz?Nôõx¯××8 eåEÍ`•˜²òA)ÐyHÏ” ¸mY͆±Ì/ÐÎUB¹lž áb05á¨D6‹cÙ,æÙ,¶²Yle³LaËR³iy@6+”p.[™”Í&Ìf¡áÒuû.‘dˆÂeˆF™­ã™­ã™ˆÿ©„¾E"ÏÊ{!èzL *lƒÒ›t“Vô"oMhÎi³w˜¹ŠÝ¢p5¥áƒ6öyÜwH:*Û; ¬d¨ygj’] W\>hg{•‚õNïz'9w *œÞ øÃ_‰xþÛ¾³RPÛÖ†M¿!Ö®„Y‡aû•ÂÉ*; Ö©ì ‚üÌ3ì°R¸H-lVÙ¥p®Z8GõyʼnugÇ¿Fw2N ?”F ûQ©¤Í|…‰~ZXŒóJO_\œ7Sã @¦Þˆ5Þ ÎÏVãݰïúIi¼ÛV} mýOæÆé†qo„åê0´{²(‘ÁÕÊ`„J`€`ˆ€,+WS2©&2€¾šA“2XLÌa”JªrG_¼©¤m£8iaŒÊÆ é'MÞJ’»Ý¿aÀÒ,Öª4¹HÐÔBæY†ëމ*V(˜p·ƒÕ©®árŸº…UÎ$eÄ"–º+“Ï“r¤ç—ësÑï Dq„©—«á±î£¤šÍê^³YVÍTÖR³¦‡ÔlžÊ—%óU6G-¼«Ù\9 Ã:Q³ùP³MI5;âèV³#Žˆ¥§Ëè•Ò=^³æÔšÕ8Ãj³%†b×íWiy¼LåcYÁ•Fuv±Nýdï'ËxUE W?%µ¨¬…\ xOƒ†þ$”a•JBÄòîJuöÃ}ÿxÞ@Ç“«ù 2¥J@+WŸ@aË^ŽRÐð.ZúT¶^%ûpû$˜q•h ¿Ð2º°J­° /Ä‘URâÈ›¤0Gn%d•má”éê:Ýóá¥Gu”nj• íUÑ/¶H`dí{UœšµXiœS™p¾¦ÌÑòo MM © 4J¼3aÕ¯“G†PD>’“§6HG/h¢bå@2Ê …À1ÿ-2\°ÉÉ×a¸ËßääN–O!œ‹/„±/ñžþRÕ¦Û§ÈØøy·.¶÷E}Љ¬qQÓ_äMÑjz #ÏJ—Uæò¦A^…pz• ^Sñ¦¨vWe—g$|e´"ÌE¯Â®ª8[ÂŒJû+IJ•]K¢ÌÔØ 5ÖÈtÅMz"ßRc=‰à·9\cwU¼†hþ/ò ¶¦ZУP”µ°š SÓg }ÓHà;k44?̳;B K;ªÅ3³¬zÒ"ÙN³Ï eÓâ¹&€°‰œè<ÛAêÚcÖª!N BmW¦ƒîË*Ñ픿z¬V•¨“¿i¬Fé0Ø(ˆ`£µºÆ9i¬†sÒ8ÍšÛØxÍšØØÍš&j)³“ =á¸ÈÝgföA;Øðn96Ÿ‚ܳyt§7ëß­z}z?ʦixõ|™!gèöE­24ôŸ¡õ-ÖûÛ±ƒ8±Ã¸ú§õ-vã£Ñ·Øì[œË ê9 õ prÁ'—E©k4RÖB°®ZP?ƒp}5¬ ÜÍ·^#?ð͉7ÎàTQ2˜.áÏÓÈ S«Sbóµþl‘–2o-Ö``àX¢Ñ–ÿ•!¡7Ö¢¡PæÇS“–HuDse‚æ*À]£%©kµ$U¢U{¨˜A8žrlÖØf$Wà÷ùm–8s²-ÐÚ4`·i8`8`Ö€eŸCž»4.sZ%Ìt·õ¶IÂ\÷hÁ* Šà µ ]ïøµüo ûõüǾdgÜÒo¥±–_íÀÙVX~í‡p,¿ îË/ôf³–_×Ð×-,¿®k¬]#¥·5P\l¿†[iì…nv0^rßtGAºŒìøˆz8>t墄eS ÅÍŽ=œ‹C‹Û`rBc'4‹´4²/4‹’`=ì’ó{,zt¿×ã·/¶œ¥`ÒÐGñ˜>¢†øJó{_§5¿‚¬=£{Qó§=ûÜb‹éº~'µ0‡ZŒA‹]Õp[‰ó‹ïXìšFùÁº% ,ë®k”'PrÀJíf‚ƒxLùÔÑlÀ&¿“àFÜ…ª¦7`ëïÓü¨¨O£ÉP* ¬_©$Q´{½ÜP@C_Dz™nmZrã9e:)!BµÎ÷Hkt®ŒŒ‚p$LÊctÜ}WÆê虇ë!í¬F§î!¢îÑ*…¹VÕÁFAü¦îñÀÙ¸n2F/x²°ÖYXçäë&b?Ž|È‘ÆztßSÓ^Øȳ‰:á{…*«Õa˜z~ˆýa(Ì4“t4™í=NÛœ›ª£[Æüc°~›†ˆ!z=ýŠÄMÐê¡ü1^´„]xÐI#¼ ŸB •ü‹¯Hl6Nn1TÐò×–r®µ÷åzrn©Î–cyƒ³¸:mŽ :©q"„6ã[°ôl•âh›8d@<Ï£ŒÑù—•U:Â.î ¬æ/uNÜ@ø˜¿´JEÀ‹OøË&©h“DÞwöž1ÈŒí¸Ac5æz«17èl]¢õÖCëmø¦ÖÛ¨ÓG%­ô „ Þœ©W -tgcm¶ê!Œ ÷Q0Õ ì3òOø$¶ Y¼‚>ö|9ÒcöœB:k·¨C†^?ìØ~Ä^I;\…ØgÑøõy‹eôàëóaÊ»ˆH«HWéÚÂî0Ð<6} ¸H« QÒíKIïÒ­ ö]:»ùu8Ô±ì¬Ìο¬´,pæ/€*ìæ`ˆ1‡;„z(°WoÏ9X.°¡öØ«Ÿ£+`Ãì±VÏ`nµ€þx¬ãUO¤ #ì±ÃU±ÃP2†’uññ™Ñ¨<"ÿ¡%³*´ý1qì),øX»õ­n¬·CJÐÉ&XEžˆ¸Ÿ‚ Éü®à§†ÞKV*Ó1á*;væÿl‡®œþ¯œ}c³v_š³q[𝲳Õöà+Ыva¯B¿°^Ya9ö*÷T òF÷V J+„[a ½ Âm•‚¶ÙN_$ô-vú"aߊ¡Ï± ‚ÚwœŸC„ig;„!˜vv`ì¯Ý;!˜ýkca˜tvÛÙÇöÍŸÚƒ…_ø ?į©%[cïÏÖÙã ¨߯-÷ÖjÏ¢ùx…0ãR¨³-ÚÙV l·=+ Bw¯=)¹n° =˜e+¹f˜Qšð4ÿ†!°{0p͈ð½q»yV…™Í >]œ`½™þ fÑ5CÏÔ3¼5¯8FŽÙýrÖsK­iBÎúéâ§ÓÉõáqŒø~³ehBÎz&æõáFü ™¾ž´ûI;e·rÙ˜’‰ùNPˆÿóDï~D[NÛ¡MM4qŠÿõ}À8kï“etúé(‡uÚq^×BÞ›†„s4£wÝzw³Ë)ñ»’o¢ñ¤x'ÚOŠw±ëöpÁ˜ììþ4¿›Ý°û ¿ÉnÚýN¿Ë7ÂTÉÄÐ-xŦºm÷»°©îØ³Š± »`´)Ð¥ŽÔ<†:Róæ 7‰äpS$’Üä'9&“¬ÿÈD©öïÐgÄWé‹Ö(G=òâ׌Ñz–Xï÷X>ØGwë'}…Õf ÙàoÁ²lÃL¿Ýïð ƒ—¾,± ŽV«sàÇŠt6‰²·³É”½ƒMq˜ód¨ÉŒn5™Ù­&³ &ÃxM†Y5©·jÒ`Õ¤Ñ5€’79Ì·‘ä¼n$ç;ü:’ZГÔB‹T³Ej‘#«I-v˜v$µÌá×Äòn¥jéIj…Ej¥Ej•#k0’Zí0×I@j#µ[­u¤v«Ïº•z]·,×C–Õ&öʶڔ)Û V¶­l[Y¿£Áî0ûc¶Ÿ;üjÖû±¦fý®ÙÓ›,¯ûqQ•ÖPeÙ Â-~|sÓ’x/U<‰wnéVº}ÝJ×öàÒµ[¥ë°J·ß‘õ>–î Ã\ BéŽbé%JWÌKwœ—Îà¥;ÁKg&J÷¥Uº¯¬Òu¤ÉsŽÔ!y¾[é/t+ýE É‹’—8$SÆc§UfÕã²#kÖãªÃ<¶ o:üv$|Ëáw ÁÛ=ûÇ‹Ä]‹D—#ë¿Ä}‡9I s¦JôáÎþf~0ÁUœÁ.‚ðgXóê3¿dÏú…Ì¿Ð[AÖXÑt jÏzÍHær<õï@6Ï`º#ëU  ˜ûÉFV‰PÍm¸ïæÈÊµš¹ —ŠÐ­-€nÎAk펬w-€ÝœHN ²~gæpœ«YoZ§ù{´p ½À¸ðCÛêÈzÛ¤á×^vøkÜ&ê:âÈzË&à¸ì³& øެ÷,@z\‡ðáÑ3¯¿õ|ïNþvÓߤ»øwŽþ~Ô…¥ôw“þjïá_Á}üƒ”,d7ïÜŠ²jg˜¾b{~M£œ=EãXçÃDã8'ˆÆ‰Î`[º–lñxž› Íu‚¦6çN<̱ÖP!âeŒX« ‚´I·šsÙg°àñ,ÛÓYÂÓ° (a[ï áÖZø¾cÚlŸª[V©ñ»¨ù|X¬á HÇ'K÷¡ ŠÝNÚ À·¶0Äã{ü¸FÐÉk„œôe^8騆¶ÏIç1ô6'mQt8Ù^gmB›‡Îo8pr~Ë6â µ‚u8iùþ÷t>`_µà8àdÁÀ±ƒN?.ñc‚_~(XYv Xu Ñ cÖoï…_¾9ý:~ÕFÕÌy‰ª™ë ';áŒÈá3¥íä_$Îá$Ài줳àq¿ËŸæ{\¤¬¾¢Àùu†æ•m\˶8¯û;…kl]ÛªrAÀðãrAìâ|–º8Ÿe §^Yåâü®vŸµòYs¾+Ô»è¸ ÇpªƒU¸BáH~G‘Õ¸â<ÓÙ(ðÌnþ-êôc\~•¸0–0üvÎ4•ƒrŽb3ÿ–j«Õ]Xïµ ø4o¬7DEVê©B3]Áçú¶w [Þ¶Ít™R{€V,4ºX£+„ #©‚í¬ÉÎêÝly…f³á-'þ6ÞÒâosáÍ›oX¢Ö¹Àe~ ù¹‚Owå Å2•AtB_ïÂÜ‚ëF¯ÿ„’.&?†lÈÊLú®¿Ä…Vqû´uÛ‡U † ß1hƒNþ „í Ì a0}‹ª£®ƒp?tò­eþ „A™“†ßôcÓØ W0BjòÊx9HS^å*,{9—}BÐA0>ufÊÖÀ¯ÊÖ¹"qAc¬wùµ„R¬RìUÛèU•µB­‹Ó¨Únœ­°Þn=muò®›`³îL¥·éŵo ´oÒ÷=ÕD{©!DøA³… gE›ÉcbÄ*¬ŽgY» O˜°ýÉ{‚ïÿ |? (·‚޹‚„u;ÎypŠr#_ð_ƈmL%vÆÊÙÎÎ#òË ^üS³çŽÏCÕ‚óLÜ) ‹—Æ…«ƒ+© ¹Ú“ÁXšk!vË*Ëô"w僚߃»´\šFìžö`š·ìjvLóÀ…|¯H³jOŸ1ªÒ‚~;²oLŽG;?åË@‡›Vð¥Ïïð~éPù—†[{NÚˆGÖOL‹³¾6X?)FkrÙT÷;Ãõ$º@5µ1i‰Üjˆ’¬ÐÞ­i¸´¾ð†m+tóo [ÓØçix\w{Z0TR®²i0‘Õ8ÙÎ44Íaš¬ü”v×ܘ„[™»SØâÃÍ‚ˆ! 7 Q¸aX]¬”¹Y¿Ùlª¬üIL&ÕŶÉ<‰0™'1Ä s ›Jy²›MsûÑ2ðC„¼†©çÅRÏsãé@a'"ÎãD¤yœˆŒá™ç•yn¶À Z¨ w›ò'¨V3–iko¶Ñ\íÁö{`J>èAnò -ŠâhÛ 4\ø7ˆv˜ Òä³vã¤"v³£î`(üŠÈŽ!õ†¢)ê/µ3Æ´N‹iÓ:-¦uZLëäLë„©;.ÄZõ‘B:„QŸ¿äþ$½ÓÐœŠº‰fü.7ÿˆ©Sº,–vY,í²XÚe±ã ý¢ƒ)§Ô #KÚHƒô«€ðH¿JƒÝwÎyŠn„ü#~!aF,êöëÖ§¬Rù¬F¨wÌçwˆNž‘Ù†2?váy#üW¼G}J.‰Àšá'èÆØ\k0¿()ß ÃÊ×Î*cù:X5ÒÂß/CvEú ƒYMÀ`Ýéójö噄GÄðŒvêYx÷kwRoÝ“è­; «·î0¨·î0Ø.ƒ÷Öݘlo¢·7¬ÞzÜà½Cì­Ç97¤ãœ2†Ð[ì £goE-å$’&•(dHÍ?a6óMÌæ ˜±ç›ÂI´ê á©jAÄðK˜²1lòÉÔ¾£Ì7Ùb“>Ï@™—˜(¦L¶Ô15ÒdËÌ`¤ˆ. ¹¤Òd-&ä64]Q7Ð8nÕjt:¯†X+ ±Vb­0„Zað´íØt66=èW½U¦PúG´Õš Ïï«Âü…×cî&ÇÜÅäå“Ùž¶+£+9í½ä˜{)i'ò´÷“1î'§&ÇDSÒÖò´¥f¼$ÒMŽj&§­KGß/†Úm:›¨O·I=çœPÏ9'bˆÂC6õœ…JS:kJ†,ªlN:ŽØ9é4_á0I ;$1››îW-V«œËl‚îZ b/›ŸÎõZïiŸôs…-¤öÄlFP—"γEºgˆålqwzKˆÞ’ž˜KtßQk°eŠZ j¶¼;½DoEOÌ•âͤòb«4ÔQÓ°ÕÝé}œNÓä>Þ®¨Ítvs¬•6§“(ÛÌKÜÌKÚÌKÆDÙf«»oK'‘¦mO'‘¦ï€ð,L;19¬ÆvAxµÝ^¨\{ ¼X-¤í…ðRµàBØY-¡t¶-ÑæÛžþ)u¶“ÆF\¤1>ÜbÒBÙB¼G¼û DÛe!vÅ»„èd»-Ä{qÄ{Bt±=âý8âý!¦±½b4Ž}¢›-Dê „Èl7Dƒ…,Ä¡qÄ¡B4Y$=ìÑkK/¬6ùlBó‡Ÿìø„‹éHqدæOî§³Žt:¿ƒ²hÍF{p!¿-ˆw£ÿ¦O§-èœEŒÎ‘‡Ñ„;ƒÝè¤ñsÃtÆ—Žý&èœ|ïãÊ£XÄ\Âk 6Æ{hRÕj=4©êuVá ÊLÚÔª¤Ç\Ví)xò›…>}1og5€ :¨è`£ ”›ÁÀH“U—Ùh‚U¬ÒŒ}iç)|Ò/‡³¤,¹ÉûÕ_óãtã¨D’«õDPýD•*ËlÂÜ:€P£"ˆMö þèû£­¤ÌdÓ¨1ê:*ºc°™18(¹‰ˆ.ƒÍ¢.V@Bê[}÷l)ÒâšbÄ@ÙK»o°Ù<É}à ˆ]s›Ó=‰Ñm·ù1bTu‹V©Éš-8%¸+ij2Åß5Ø¢¤BXÐ{[œœÊÊ­Ô´â£[Jñ‘¢¡ ˆñ&·ÙÚ“´¿C²ËÊYRµe`W»êß¡ŒNáô5 am"bk CX“ÈšDÁpø ƒ3Ïk‡2؉ ¿æÉH³e;ß/7“ýý/3üº_ ³¿Âg5Œì5EOGðáQç1JæQHŠe«bÛ&jŒØ•$bW“ˆ=†'õ(.Bq·(–óÈû»è"Î@w¿À×fÄÞÚ ®ðbØä1¨}GªÍ`S2Ðð>è·Ó2¸~;=ƒë·3ÖC%ì‘V{†¥Í¶gpmCÔf1DmCÔf1m¶=ƒíÏ…qø–‡cˆt¿îZ;j|0³ƒ†ÄÂMj«ò̘XÈ$]Ô%0D]CÔ%0]\UdòeQe&ézU&«Èü¿^UbR¬@¤‘Jßm~ÓYUæƒÖOqí &³`r?~<•¦>@BÆäâ¨L`À!é*ê`¬ÿ¤Xý'ñŠ “xÅÅI¼â†¨ñNÊdS±ðûg(·Ó2câŒË¹„Rãæ0^úÖvüÎõÿ.8¿ú½þ÷8Ÿ+ÜOÿ^æ·»³m¶½à¬eÆûDIРSÎiç,Xÿ'J>DÐwÁy}^ÔÃè+ÅJ£àBîøp‚—™ð<€ øOÁ%‹tî%DÐMOAgõU@­&Ô3¸“rÄ@O|€ÏÕãC„*qà”~YBÉ”~0܇ˆcÄSûe‰%Sáõ‹!ÒDqà´~YRÉ4x=9Dž"œÞ/K.™¯§†(3Å3úe)%3àõË!j“8pf¿,µd&¼n2µùâÀYø: ï³¥2üÕå›Õ[7¶7Š…ãÑTᱟûÛ„—¨èOéoi']¢¾ç±íÙ1„ŸB/ EÌÇ‚ˆzÜdUÛ%îIÂ]û¨í¤Ø)Ü(tBpo xG¤Ø/!å+è2tàe_á_યä²1±`¼òŽ…ÀþGJç»ÛÙe1ìAÓCWÅ0¹g ¦šä…çZõÊ£Y¶%Ü×».†ñ=ÚL[„7ÄpVÑ•GÑ“h pø‘ÒõB»+F<ïá]@1’šÃ} ×|qHôÁy–J‘¤<‡J‘nyŽâ€.“ºê…„Ê“-’(rG&û¯LÄE8ñª¯NFL"^“ ïF|ú`:a¨‚ª½HÍ6=PÍ’‚òuäÝœÕK…¯nøXƒT8]Üô±F©°âDZ/±&z÷Ò»Šw˜W@op†¤‹wº»Ýú[[‹Ô)Lþ@X)±•X–Â[>,Béx±Ýüw¤×Haèt7t-=#ÙÃríl#¼àQ­ô˜ˆÚïaõ9=&¢vÃûaµ‡Qz·œ1âc`ÁÏ×òE8ƒô2'à÷K)ÔÁ>‘ §ô‹¹æÃÁë¥Â©ýb~ùðcð©pZÜ)~ Þ ŒŒ{äÃÁ!©pF¿˜;>üÜ!δJüc°JƒU]z|X4ªî¹={?*“­ŸF£ÿ”Á= Ã^Õ¥F°¼ÑÜöÎêç½íÃV:E­t—ã±Vº­t&ê[»%á½ã{¿Ýü~Û¿/^†•Ìõø>BN4#4}0(“Í&Xi”˘ô.b”Íqˆ]“Œ}€c’Í{4aw!öÙ,Fì‰ÉØaŽ]+›ý»Ž°ï!ö$ÙübOOÆ>̱gÈæc€=3Q’Y²©!öì`Ï‘ÍóxP Q’y²y»å¢dìÇ^,›Ÿ¡oáí%²ÙŒ§ç¢'ì]R–-Öð´À09ÞAê Ur¼ƒˆÔAÆËñ"Q™*Ç;ˆL¤QŽw~l¡ï j¼ƒhÔA4è ¿Fµ×ïGÞÖÜ~z?zæ~ô‘hô¥h"Ð+šZeMÕËÔ ZÉ÷ØûíÔZeP|ja³Œ.ºÄ-2Ž^i«Ì¶ÈAïDÓö~Û*§ŒcXœl—Ã÷}!ï}Ÿ°¸²Ý­1‘>¡í–ÃÈ­¨#ö@æ,„±‡©{:ý[´>£_3¿UÁÂ<&pü±:¶û’Ó¶aÚýrøÙl™î8€øû‘Òãøz0IÄñHî.ø‡9 ñS1^£StÐãe˜OvD¦žì„…dÓ’’…1Ù³s,ó:(S$yF5È3*½s糖c…8i¦'QKbÄôx!¾°‘(ûIÙbTÏd þJNö#„|‰®“’EâÌú*C)OËIn\‘óg“99‰êš‘Fˆ)²4#/Ë¡H&B¯pèP‚^§^ö‰š >! U,Qƒ’ƒj9\ÉØp¥¬Ý¬$?©JO±R¥˜›m¶œŠt \+eÅ\¸ã”žCy¼‚Vs*kÐ0àNTÌ Ä¬ôÈSóß-Ü©ˆ;MA«ˆvóW(ÊÆ#•$¹ŽcpŒ”Á:%>Åø”h J0WF£ÒßF£Ñhe4 /l–‚9mˆ’ªý‚²2ùÛ"‡šð‘Â))#«}¤€úÜŽ^}CÞay6ïÏ!,'Zg ÐÜ´ZÎݵt[÷õŽÞ¥C<Ö|^«ÐÄ‹Wu«jqƒÂÖ¥’og­ ¼A£{vÐ%]køÐ™…- ÎŃéDÛ6¥àuÒ|¯ ûœâ"äIp,ÝÕµ:/¥Ü¥Ð$ë釟º«k)¨°=£)öì#uEga!Årx͇®©Ø,Lh~2eþ/¼)§X½”(·+8 &Åf·2 ¸÷î‡7³Ï2t¾ÉŸcï+Δ3軘rNagº1:å9¥¬ƒ]P,±@Y_TPÉLŽ.ÑsàLfY‡ùCòÓk BÕÒ*{ðÒóe¥À‰7b°Ò絬lôVç ^§´¯*hÀsÔ€_ñ좎ªl] –T袒Š÷v?µ„¬T áPž—™%ØÌiØËa1ˆZ™©§Gò#]ZN}£t€ÇަGŠ£š§0íDæ±µôH±uª¹c§%b§'bg¨æ|ŒmP„Ç6Ñ#ÅÎVÑò†Ý,ÃP CËŽP¡oùekD½mCÈÀ^ "˜/âV¡YOÛ³)*0Ö‚HxÚžÕ«Ð,HOçÅò㣸óâ^Ñèÿ¾þ&›—"Ï’®jëÄïux+²Ì*ëTê Øž)¶B°îmi3cjy „cke«Ê6¨ÝZøU著ÛJß逎³E-+F©¶BÕ| °îRÃó’¹›ËL<¿Gä,.䌴Wõ–yŲ2¼z„¬Šªæ»@|¨f Μº¡ž Ó^ë‘ÊpÍü!R©ÐÂ|¯öYT*5ú«Ñ,(2ë=*Hð|´FE£Y<§ñ¢O‚¢×b<¯Õºó|’ö žOÖÆóéZwžÏÒ,QÚ“í š™C~.¡Ûçiæó /à‰,¶/Œ½q¶7[eŸ e_¤ÅÙ¾X3¤¶\ ÇæÎͼ„$£¶2öÆ©­²¨Mj«Ô>ÖÌ áªM kl‡šeók–TøîI£œÐ,©@mƒä„fI”wUÐD,ˆD’£\CÉ¡YRy<[CÉ¡YJ3JŽ¥Jí!Z³öø¿‚ÖünW´¦+ú«{Ñ9÷¢çïEa•õWÑ(ºò] Mû)4›ùœ²]£ù{„`ۮѾ‚c#q·Ævj4oïÖ œ!.ò÷Kî ô–åA/p£4jPÓÚÉDs"·›I‘ * ‘oá‘]É)Û5¨?Dâ¹"ï%GÀŠCäcti3’s#‰Ÿ'# \G5T .²]Õ&:¨6—4T æ»AƒXSqïÒÑš ()†zy_µ]ÒhfÂk¤wŠ74Üò‘nB°Ý”oApc r[cW´‚ò¼P~yžÀ®iAtoÊÕóJ¶¨V82où²l¬Tlj¬"/¿2ObCuˆÊ¯Êƒ9C7?Ä #‚¿·|´ø`„_Íñ+ãøUº™+ã±ÍúA£³1:šÓäÒpi1Þ¦Çß&À¨4£×Ùš&/}ëy8Ïù¹‡g}¯¦`\%Àtìå€kR°à;!ïw„ìü 0`oHÖСk)7co}Šfä±;TÚ2¹/ÅEF”p¨Œ_JYJ*#ˆ¬t‡ÇF~Ú¨LæoF­Xö.i6Y%†‹LV…!˜}XªSVÎkÔ~õdt¡€×æÊ¼7÷v±¥°­^F),`°´FçB8çqið¬iŒ%&[+G@¥A‹e競ʬ UÏoØ&Ù¯‘ÂÍ4LߎÓ·± ³»²ßž—çû‹ì>BâC!QŽÃ‡*ÉÖóýeVªÀpõÛa¼ö¡ñ:BI¯e±·l¯J|V)ɰZy¨­$K¸1JB"ÆQacS0Æ) ˜C™ ôƒX£‰NÀpj¨ÅÍï{¤q}Æ…öTú6И×Þ»ô;°¼ÿÙ ÁPÅ1n›ª°™±ZZ–…­·ÂFPáL¨WH˜Š Þ4¥FV‚hhRX½’H03b J¨ð;#!;ÖH9ØPИ…€{Æó•p¤¨)-PÂÙÞÙ -8æB%‚%÷¨i5Cúç[,µk‘Rð|Èû¼ñîÍ“°þHÁë„Kú`ŠöMÓ]dÔ4‚y™(V0’I·Ú ùX‰ æ«VOœVúoqoG!+ø…,è]aÚ{~…Ýîcwë¶žhª¼ä­VÉ7q ÛœZƒ-”j•ÉNß™lSü*¢ìP½‘Â.È”îííQ :EHoÚ¤ ø $N~ù€f¼K Y™ P3„fd‡Õ3MÏá*‡a±E}:v•û¸R𽯠¶ÜÁdìõ ¥O.~±ÐqPú£ôáO)x‹Ðß§rѱ×Ü8©3Iq1RçÔ%% Š*+Q‘ wÌÊ´ÝShÁàþ£b…JZ¼4Â5ÐYêT6íJz×›"úxdÃÔì\4Z M‚߆æ¾ÄÊàu‹ÉÊÕìÂyyùy¤U¨˜`ªÔˆe*>gY¶­FŠ£Õ‚!lŒEo¬šÝÇ7D-Sfã@—DKf‰%¼<…úäx•4»ñ(ÐA'@TUÐ:/¾NRqòè“™IŸ(P~mù5UEk,¸4“êã—½ ™ü4ñø }" ÂJ) ë¦Ð;"ªÆsTKG ­Ê&;¡ô.jÉF«Ÿ4U-äÜYhÕ¦™¸C*Ïb•.C”šhhÏR;¬'û¯ë`uµ^eÕ–Mj05è ›‘5Ÿ«Aï'¦ }7™¨æþŒÒ… ‹¨$c3é«C0ÿc­Só—™63ƒ>: À%Íã0³cø]e˜‰«Ûÿ—/)hrÛ9•WIÇ_Àuü6vQ %)ö—ð­Ù lì…œí´â¸nϨÎ!Rí/cÃM\žžã#áe²2©Ö(3a¢ÆîQáãÞ;púx‚> š¬Tã%ª³ñ}˜¹œ¦Bêˆ#µl´ÜÈ‘«5,K©ÔÆj´ ÷SX»áNÌód¬Eb&©Õ¨Žó_²úX;›¬…CV§hak1†«ãbm§"¯*NǰΣªÎ°(Ï‚ÂÙl#¨]AU^@›Í ÊÍkÖ²ÛØb*;Õq =z·ö² ncË´5Ñr«Â+5òYeÊ0X§pþmÖ¬ÁºY£ÁŠÁFPú0l…ѺíÂhݦ±­ZÁ“¡pìú6-.ÄwjÁ„1Òˆw­ÉÍÄîÖ,s¥{4>b(Þ•¦ˆca/ Äl²*ué+@6†4êÆå&ÎY“¹<9¡ÑMwþU*ê ^ÔVQ1\¾Ò(ò4<£±¯´v€¬(íôxYý´ÔÆÎháAí¼èçÐ,âŸäsZØ/×ÂOXP€,ÛÒ§qƇRYM€÷¼ÈÛM?Î ›a^¸Š»ÜT²¬kÉ‹A”« –ñWµWÑP š ÎG8 Nü:GlCÛ½ì¦Ö;—ÝÖ‚aïg¦P—þK`ÎÝX ³/¯5¿M *'[g+ØÊu”´B…Î*tKt…â"²UêÖv‰uêUéᤷjxçŒîÀL ˆó]© ºÕA&èÄØ :«%:Þ…/بØuôò~™-䢹>Œk†8Ô™&ó¸°÷|¶˜Ë¦ê8YTRÑõÙ1ê³ú½³u6W“ȧ|¸5G6OÇ£ÃÉíƒ\[ ÃP^DÙTQÍûÐj²ô÷|ô!û’¥òÜl«!ã­ñj}¢‡i#çS=„{ŽŸø‚ݤHѧ·µ)P”¹ëtÔL‡&op;´æ ²PZã@ÊkÄBeƒ5;,ž7AÙ>rôäÒ€/sp.µ8,.­pX\ú˜Óø¢W–!“Á®þl#ŒBv­#‚³ù:ÎÇGAªnpøÕaü°¨Ÿ”׿ºaqÇoR½‰¯Ô~ðìW›=7P_v >`œ'k_Öœ ²¸X˜G~â>G°éy™£“ƒY¨¹6óI-Ò)¯n2H‡ä{7¡¸m”8?”j66ô4“tà(÷+0Àý2, f™ì¯èÌÇÌM: º¤ãí„@mÿìfÚå9éàŠ–_Á®MÅN;‚³ø¼?ý…,Á7K1“3”oá/Ga¸îà»gyY~dcV§cØÒH¬¿N }3ÖÐ7ìnJvAmî?  £êäM8Ü :5 ˜h(l"‘ýÿˆlµÓ"[ídcœ©EÃYl¬“óf<ÄM7Óq@OtòMܶ8Lz’“ÊɘI-­Gød73–ÉL'ktöØ`Âýs)Ãg¾31|:ã¢tR®£If"×¢—;“æÑåNö±3çâç¼D#|êdŸ ›B×8ñÎFS(ÌkýÙJJ¬Û¯›z7™¶¥t{RAwaé&Q½ûRáöÅê½ÏÉ:œ¨Ä´Ðª`?¶Æ “À“if8LJóq'jÜñ‰á¸“tr‰ÿ=< %lÎÃýO|ͱ5Ö s0•äh?uõè*îw±µ®„.ð™«?[ãVÂûQž€4ÙW©à÷Óô>$q]ÖØGh‹Œ4ÀçA £·7W áŒ7µ¿‡–Âp5ÒùÇø¾ iüötúwñ}³ _“H-îAjØ`Ï/q«j¿-D¶ÕøÛ©ñaÔØØNWÿy3±].«UØnjŒ8?C?Ã?Û‘Si°ñM—C.k°r¡É°äAz•¤'1Ý4’€ÖBüL,á;çâ*1õ0•¹,™ðm¬ôå$¡CU‡YþPØj…”8þüP»Z®»Iå*M‹K¹¡hk:h¶‚ôDð9*ãÏ –äñ›¯?Q2÷¬È S•_wžiöUííË{!ûkÛ ìÕ {5KȲ=ý4ü³×¯'óññÝÌ’6“õã/†zgà¦íKÐÛM†ŽàgAFªfñBгýÁ@~Ó­NªÚ{ÿ'ëÀÂ?±atNû—P¡ÒBcúß‚ð82¡£ûÿ*tò/$¿ òóyx>su®€¥ø}Áúgò×?ccïCÖ &Þ¥úe1 UŒ –æa¾¥yx™ªY¥d«åY~F¯®FLügDÂ&Å"ÓšÌä3"žä3"³©CýàrPó¡â-[>½½,Ü,à!ã’Õ"{¹ô&pg¯Î~ ÉæÐx®ócd8Ȥa‚íS<'R€® tŸ&”jmlÌY-<<Òaö~̇¬Í-¬Ø:!T¸,¯Ðƒ6\‹:L¶Z¦fg„`‡1I8°<o-ÏŒV‘€&¥W¬ŒZÜkškJЬü;•(H%êè]êÁ£Ö#ÿÁpÁ,„ÌVŒè ™S™—Cëã¶a‚Ô&°6Šˆ@~˜˜üxIeëOBMEÛ~Â"B« ÷Ú¹Å3&óLÅ!+×$Êõ²€þLTÌÕrjÒ)„kÛežùu" ­ËÄNaôHA*iõ>RÄs+'m^zç²ë‰Â±B8Klæß$š%@ÑÛ~’%4{JûjåŽÀî‰Ø•"-DBÞõß>  Ÿ.!D†Aï Ø0 š ˜6Ä<¯ÑÉ–XÂóš÷Ä_K¹l¸Xpç¥Ö¶ŸÍ<üª8‚|ìšV‘'`ìÖŸäï‡!^&fÙ>è@ÎIÔK%tÿ%f ÅŠÙã¼Z)²JBƒ5±^cUb(²Ôš¬ý䏨3€úM ÕïÚk}”Èj­â# dcb”oÀà=øu^s<­¬€6'ðtÌjíB¬‚cE"å'Ø*(nj„{½ ->‘ žÀë]n>‰¬¿‚qˆÍÿw-–Èzã‰@8øЊŒqb{o`C¿ÞE xSz¡©+Š.wæ‹ÖØ{±S¸ók~ïþZ„ß®_K/2/¾þ|ðåì0 –½XAC&K|QVàɲ…}±¨åå§³öJ]]ùeŸGP Œ*_¸÷"ËwX„žþEw^D•Å'~GëÕp!PÏ|KháêO$öêAg¨¯6ô£ÔùP“‚¯^ð}õ‚ êÃÞ¸Z„(( šM¼þÕí· Â~_H=`¥Å¹E võ¯)ú}KоÏÇBEÐ ÿd›y‚ðF¢(¬§Ðêi1j™x¼/aUÇN‘U lT*2QÃvIÙìÒnd£¨_šDvyŒìr­èNö°ÉV"ÙeØäï@À$Y«¨?hð7àMÈËxSc§Xn‚Ûxi.bë;°±_α÷ÞJûu G†Ï lê—s作£ïå„ÞË ¿—y/gß{9mïå´¿—Óñ^Îþ÷r¼—sð½œCïå~ï]wIv¨³—f˜ ´Ë —ǃÏA·)üÔ[ºÆ[°ÖË‚Ek½ô–¦Û‚Þñø31Ýö®T²K æ6J>ósÖÀè_œŽë´‚2_00âÿçí=ࣺ®üñymŠ£™!±Mœ[q•Öé›üâ2ȶœx!ĶXI$³Jq6Yov7ë¿ ÑDï`½ˆÞÁôÞ™‚$zïM—ÞÑï|Ï}oæ ìäóÿÿý1zóî=ç{Ï=÷¾sû=™¹å¹Jiyn ¿v³^kùµ‡õZǯ½¬×:¿÷Ž¿üÞ7þîl¿ýÿ2±¡ä Å‘=é+Ù[ßCrWßÏóÄK­Úh÷Ån³Å¾Ó(v;Ç^~‹b¿ío»ã‘±a[¬Oƶu%©`n»ûTPìü;tPlü=ÄúßAûµû‹Gj÷—¦œI:èE‰üÿPâ%¡·QY MJÑV/YŽ^æ<²ƒM¼hAä71>Óá›^Ÿâp´¢þÿM\³8Ÿº¢M¼nú ß¥;ࢆÒ˜ç¥p‹Â±-ÉZ-´þ€Ç!pY¤&Þfø²s?m?P¦d .~~{eÐ!`6“1lâ}—iÞ$š·¨9Ÿ¡›Ç|L×trÏÛ±äžW¼ÌýžÝ‘:ùVög›aïÀk çïŸû—æ¨ã—â_¾ …6¸Ü³Ó„9? ©Ú‡Cwa”—zuOïL•#ŠL£\T¯ì¥1bI½²:X¿#ÚKÑ~_¯è¥è¨WRéõÊ¡^ŠóOìOðßE‡ðÔ'¿i%BÔ¸ÞõŠ’ph^f84Ÿþ-Èl«•µâwÔS ×Eôo1Չ߇CKèõsú·”ƒ¨›ð‡ph½/§+d˜!þ(ï›i«Ó›SüI:’ùwö*X„îí_¨W“ŽUïÿóU£ ó²ù ^Õ‹í¨Qä·Ÿªj‚øãñ ÇcUø+ Ú²ô±ˆeNf5Ü?8ÑCH=—ÿ&….óªz﫬·¿ñMIÔ5ý[½rù-åoÜ+þT|J}flcñˆR%#ðhÑ¢<ñ)uyá§é BêŒvn¹W§R}'Ü¢à©Ü§¥OÕÈÚÉRŠŽ¦àï þÛÀ£)‘p°S¦£hOj$LŸHþX'v"ñVåà=:âÍ“£¡¿‚ZÜ&Þç8;7ÛQš~¯è`:£ÅêB-–Z´óI0¬dI²‰á¥Ü—¥/Y /¹‹JqÅÓÌLNe+¥23ÓJeÕØޕL³$Ó6bšgZýw繜òFžË¬<•y.#à£ñ<¯á<¿LÀ/ç¾ì(}Ù<6'žó®Èy…-çk–‰‘™˜-3±ÒšÏĺ‡1µ‘Ls$ÓbšgZÿåsžZ´F#a»[¥]nåü˜Ìy9‹ç|¿BÀOç>í(}:©ð"ßþ§¢3`+e ëܸL¿H¦›d,SOK¦®–LÇ¥L] øx\¦Ml°¾ÞH¦,Ëä"™@¶ùÑé«Ó¯´Ò¯°Ò?!Ó¯ ôOÄÓßòèô}fú[¿\þ£üw5Òïc¥ßÍJÿ¤L¿¥2žþ¶/—þö‡§ãÁé÷³Òïn¥J¦ßÒ?OÇ—K?ÌM°qúp°–âH‘õ˜,‹æ—Ù’.©>FpÏä>ã(}&^Û"U"ˆz]Dð{"ÈÊÍr”fÙÒ;Èit'¸à |¤CðgþŒÂŸqø3™>\gÑV-B½ü¢Ã)‘P'Fû‘pQ'ibµ¬âI«ãU<ÆYü'JòÙÜg¥ÏZIf_kW´³I$ûh/¥h8LÃ`S³ñÜì|Øwõ+Öa3ù]­”‰î§DWÆ­ù‚DY‰½?ÑÚG'ú‚Lt•Lô%º*žh'ú]býV߲)·ß㑬´¢þô×[ÔÕIé¿¿èvqº/56Ÿ¦áýÄŸÏ0Ò1­ç÷Âv,íãE¹$í2)íž÷к[Òîy믙õɺ\²î}‹uïÃXß3 ³®¬ûÞC_ÂbÝ÷0©¬£ÖQ†ÔÑèûu´ÿ tTõŒÁŸ±6øR:Z"¥­{½"KÚƒ_JGŸKÖ]ï¡3e±úR:Z*Yw¿‡>˜Åzøa:ÒXGÖQšÔÑøûutä t4Ꙉ?“l::ú¥t´PJ»ó=t&-i})-’¬5ï¡j±ÿR:Z,YkßC×Õb=ñ0¬#ë(EêhÊý::ù:š õTãÏ4›ŽN})Í“ÒFÞCÜ’öô—ÒÑ|É}]w‹õÌ—ÒÑÉ{=~‹õ¬W!Ö3XÍý¶ÙÙ*–Ç>ú8nŸÆúšœ )õqZý߇J}VZcÍú¤dí"Yk—8ëØ‡iá!sÔ–ZZ¨mcjaOª;¶A¹Zðã¾@ ‡ …Ã6-ŒHVÌ ^s"ª«ÌÊPÊJ×xV&<Œ5hg­¬Ãˆµ"Î:ñÔÂQK û¬ºpZÖ…}mQ¡-øI ÿr#-|«·*Õp j8Ž?'l£àÉüg=¬X4|ûëæôæ”Gƒ‰››ÄSMüMÓoI\ý*甥œ]–rŽKåìj‹ÜRÎ4†é¡Uä4ÔrÎÚt3¹~ø°z"uEÞMùp*ònñ"Ÿñh€oغK€Ð=0ó!:4’u8ëÔáykAh·¥ÃR‡»ÛÂZ²ÌæÏ̾ dס\ /@‰õ¶mK•ýà,PZd¾P¾;Åó=÷aLAÉÔY2 $¦Îq¦yÿ`þ/Zùßcåÿ¤Ìÿž¶°öüüL'ÁÿŸ/Èÿ%äÿ2þ\ÁŸ«øsÔa˜êXðè¯â)”¥¬YX;ÿ2ÄO›Ä‹Mü$g™Ä‹¿ ñ·Lâ%_d#@üŒIüùÃJA5— nÄ¢T{)ܰJa¯U §d)ìm‹æÕ*…¥_ªÞ„ÚoÙjá²GgáÙ$µ/ÿ2ù}Î$^Áù-nœß‡-ù¼ÁK>,ùXy¿cå½â3ïC ¹÷z&VÞW~©¼ßEÞïÙò¾êÑ-÷óÒþ”ÉOj0}ReñOjõ£YÍÕ“rÉ:„XËã¬k˜õoÄú‡Ü?8Jÿ`ûï¬* TY)¬©”ûkFö¼r%ûôïò?×ÕHöªüì[æÏõ÷¯Uµ)ÂR¬Ï(b ±–û¢`F&ª6µ Pu ¨mIPÛCH†Ú•€Ú¨Ý ¨íIPÛCU¼“µ'µP{P;’ v4†ªm“µ/ÔþT8 *ÜjWÛ$¨ ¨ & "IP‘ÆP»“¡% ¢€:œ€Š&AECíI†:’€Šêh*–k µ7êXj' Ž' v&Aíl µ/êDªP'P5IP5¡ö'C¤a“¼p‹Ä‰Ž/ž3씆íÞ}2iâpM&š8$ Ì´t_#Ÿ`u†¢Ò3¾yñµï‡[ð³{ÍÛ‡ º(¹]‡qUÿŠ;왲)S…[ˆ_xU vQpåi =ÃDZÔ‰Oáž¾P/øØ:O-|zÆ78ªÌÚB]¦ˆ® h"E½|¢‚—Â"Àtñ!{$„*Ro‹œ…È92²7{ñ²¥°ÈJa_VÊ)ôö‰Ï‘ÂEÈ6€ì Qܰ}ÉRcÔ(¢Î‰êb@.Û@Îä¼éI®Ø@.[ —>Í>>qï%µtÃ}‘=Té k6¾ª ÒWýU Ò×'àÒÉë6 ™$Av";7l Ó-骘i‚ìÔÅ,€Ü´¬ÈZ R[6ÍÈfUl5Ajt± ·m rX‚ÔäŽ ä¤rR§MZ]œÈ]Ȁܓ u¹g¯DšU‰4ÑU“ uº¨À‘ 6a¸™r„úA±¥¾È dŒ&Æ™ ý|b<@:ù ²H‚ì…$m Ë-åšXi‚ìÕÅ*€t±ÄR#AúC’2È^ d¯&ö› ý}â@Êm rY‚ì‚$]m‘:F蹑¶úèf }tÑO—)ìÓE\ÒØÍ2 %H Ým Ó,iº˜a‚Ät1 =l ðéÄ·Èäµ§ d³²Y^S>± ½|:ѽÀtû,:ó€^pçõ² ßë?±LÁ¥þ¹w^W4‡£Òçt¦gü‘YÎ0Kå×gôz¥ë» ƒ;+*žC:+žC;+ú]œÓ#d…¸Áà‚^°ú¥ 2¸¬—2…C}¼ù¢ŽÈ-¼oã2¼K³·O×Ó3Úq¢×­D¯ËD¯›‰^çk‰õm\5z+‘ÞäôîÚÒÃÉó$ÐǦ0é»(ÜÚÑÉ]Œ‚U/É›©ÊpG[_5i¯™VûÍ/Ó`dµû[ÑCÚkFéçÃY6ý}Ò›ãÉÄÅÐ…ýÝ8#½9ò±—>éÍDËÓ›ã2ç÷Ä*Åò渚WØ({N×ËL* íÒ¯’¡åw2¶p߸[1Ý7Þa÷{À6Ès%Ý)Åæ8 wEŸê¥(gï?cãòE%î%í’âý]ã %yt]áËpÄmE:—»£xÛ9¤c˜sJ¤N\P²Ëÿn÷¨W²4ËýÒ×øt^–úpïKS´. ôÿà†z  öiŠÓõ –&¶\¿š›mÍ×’·UMG†CX7¯0Ý8Õô4N%óNã·ê0{>’¥UãD;‘š¨æÙÇ­0C}šætý/³Î²Xg©õÊRÍUÌQ ú»ùâu·RÚß]+æJLÓwP?áë׿©Ñhè¬+:éStV:%˜¯"M;%êî‚eNU-„Æø6K±Ê’b•*Ö„Ê×/¯µÉºæÊëÁ7ܧ“ô¥²t#c„Ä?_¡(5ªˆ€#'wRvE嬫c­¨ƒOÎxÐ1×±ËNsØ•;.ë7c‰k*]%™’H#|8yûäŠê„Zp37K3ŽôÁ]…Êñ—,A/©ðߣ\¡ÇÙ^Šz~DãþyjÅ5µ`RŸ”£dŸë¥T×Á ˜GÜR£°jì+”êRöynúʽ:ý¾Ð‹-]ŽG4HªìzŠ-ÕÌÀ.šd-Ó$« ÈrM²^´X³©w¡åx ¾ÔH2Jj–÷…ïb÷Ô,5î G”;kYZÜÒýõ[o6ƒê÷[ 54tkh ‡ã3‹ý ëcˆfû,‡hÒŸß0M רð¸ôGh–»¾k½¸­m¤&eâ‚Ï4éû>ËQ¾›Q>ƒÀgÉj1]3mátMÌÖ,WÞ 4¹Pƒ7Š…štî±H“Ž*žÉïž§‹Åš÷w YªIïY›+eš·5<`Õ\ jé«󵨩¥¯“B/Qꟛ!J\+*kEu«ÍV74¨&44Ð/±-÷hŸu‰?DÖøÿ6°Àƒ| \E ©i–δ[à1Ô¼RÿýbO¿È%@z´Fý-ŠËQûê꿇C#ÐæŽ£Ï0-½9‚;š-iGñŸáHÉŸøkáçyÍ‹–æ‰ÿÂÙoæÿ:»Ã¶÷T …Š#9Ùçšr]êU†Z?¹Im)ÿaÁ²Gîg8¤à_»¶‰†fËŽ\N$C˜–žÓÈUYðO•ƒjû -q,BÉ„–õÊéOÕcjû‰ò„’‰pókLj™½òýgÛ(E“°ïa’Ò毒¯ÐçÈ?Fiá6Ž’*êl«PÔuX˜Éܪ¾ÀñÓ¸&uÏwLÓÄ ×ZÅ­p3ûZ/%yœÈâØ. ›ž1TaôõÐÉËŸåƒSØph®/^$ÖÒÏ1¾Ì\ø …yoxÉ߈>ÁǼmf ¼mÕpÝyó’ >±CÅ­°\ M5š-»aáð>G†Ç8<Çëb?­Hë>œ©|Pp¦NýÄÁžT±r{MÞ]^¡ÍøÂnk…+òB³[QØ]çã‹?îqèÄW)´Tç%"jÎÓ3ÞaÜ®V_¬«.ºéIø*{S ?S2Îwª&(NqQ¿2ü,‚音Ì%ŠÁèÛLcs˜z‘-¾Ù¹WmSnXÙü3TªåÔ+‹wÌ×ù‚í*_he. Ô;½ñ5ÏàÓ‹àöµé>CEo €Ë,I—éb……[Å?#E¥:§…«òð ЯTˆ5zá„–ÏWçiT]øÂóõ)Z™'6@âÜ·ý'N`7ú¶{%2šÀ}RÜ«jéã° b¿vM^éãXP²‰vÔí¨.Ž'D;iŠF Æ))Ú©¸h§õ‰ɢ3E[“GýVm+³ˆèm˜ ô–×:S8¡ÝÏ lÕ¼O±«JT"ŽÀ?9…6È€+ŸbDšû0Ô ÂèÃÐÕœÍ)}—SZh¥´Ð‹ ê»Nòp×Ç£œAFJ&ùÄ2ƒªÀdŸXæ9æèÌÛq•p˜’ë UkX}bä'9r/#W}ű×û™&œ¦Áþ̳QfªëŠã´!ΚT3˜j>S}‹©®YT× qÃÌÊM“ú(S/ SzÆKL]æ4©ËœìP«Ì)º:%S…“™¢ÁcnÂ\hK£¿ÅÕß)šäƒ$yð8§±ÈF]å4sWåcMêq&õ ¦^l³e3p-î,“l6“åŸÔbî¤]¢K[·Ôb©}©™m…)zþ)M+Áø93¾ÂŒ›™1ÒEql&ÎhEÙì[MÖmëibÝÖ¥6Ö]Ì#Ö]ĺ“Xw9Å“u¯Åz†X÷uWYz瑯zgøíU.xà“æô¨–ûtÌÝÖ˜¬”oaý¸®9ŽVâËzeò_¥®zeÒ_•R—èìÂÖ°Ke¸év®/° ·Ý¢Î×Tß®;Ñç[@µ²› Õ¼¹¿®¸ÝKÑz¸øÊa.у£‚Û4Ÿß̯bˆËfx1&ÆáT[?ê`x¿ÂŽ)9$Ë‘OÅFÑÅÆªîmûêjýG¹ N±Ž^Y±ì•Cè¸w‚rb}…¸ŒqÉ„Æa“[Ãx—l¦ºy1Íe?2{?‡ÛÇMj„A›é‚јéŠÁËœiɈq®Ë4Dãüãš<˜›̸€º,;CŒK\áÎ¥L/–¹îk–Ëð®ûZ§U¬ßq‡ÔãZ;+ô¸N†¯¿_¿‘gŠØâ¢J°‚º×é»T®5ìN“•€+@¬5.QÇ B`·Y¾nU€#Dt‡JúœKì•âî»_–ý2üÀý²qµqP‚â´cbRkpmžÊ×ùwÅÌ íÃI;ÕÄÕ)“êª S}ÆTé9N3^Ý.pµ.$Ö?á‰LáJô .±¾ŠuÔ‹+RwWï/Žk2üúýÅq‹ÓjÖÛæO*ó»ÐðJnÚÿÜ/dÕjpính²/ó]öHGŸ1™n\­;É'}éÞë¥8†¹Å0 ®Ës€g¸[ÞmDiŒÏ Ÿé.Xõ’é]w}¼ëòlÅh\»Š@&§[MéŠé„6¹^Ífï;31óYšÁòÒ±ph¼Oö9ªó]j Üáüéd4u­W·ÂmŽV¸Å*w$´æ[a8¯XëŽO›¬ËZË‹eƒ[lb–æ`Ùš`Ù–u,{³ôÔ0­?‚¯÷9É$þH¾Û§ùGûMó¯´-1NÀ˜Lbá$ìÜÛÈ3:9f/6¢løÂŽö0þµû•mZg´üzÐÝÞÄ=جFÓ:èK+™í'[]éÉèJo&a2š.vªTįI<ßGÿùŠÜ‘™ˆûUD%.‚¶R…Êhò2Ç °æ¼(b‚cOT‘TŠ'²¶Î}BÖ‡¡˜ÏÙf\ÀŸ€Ûm€+,À Ï#•,ö‰5&à¡8àZî`¶ÿe¶ˆ»5¢F)”µgv«@tœ•Â2gáÆ¼¹>¸MS:W*ŽÝ˜n*ؘGÁyJhSñíQÚ÷EÄ^¼›óªÑ9•?ËÙwÈ>Åì0—Œ÷‰ÃJøí©T!ð*g %:%A‰¦ç™Ú|ãÑstVyŽVñ¯];ûbÎ|# P£„™’úc(æÌ§Žn?¥e–Q2…ÆGg?U~Ò~*Þ¦ÒÛ¹OÕŸ¶¯n™¥—TÓÛùOµŸ·ŸÖ2K+™†²ŽQÅHM{ïb9aN"eñ) J»Zi?À(ÚŠ²W2ÀÓ”öUÎÂ!ÁÐÐ` õ\¦+íg[¯³b¦R°R-<¦„¶ä^z9Ô÷56?³xÝ–Ê#5­9#/´Šq¡‚rÎû#9&XÂá*‹p•BåΞùŽ$ä®õéDø:n²7)b‡±nß×­y¬01Þ•þ\}c ¡Z1„*¢«ãT_¾XQÉ—»ñ,n¡(¶¦g¹Ü+ZĪf¿Áº/•ojZfû+ÕÚÿ‡Ö£Òî&«’šö/µd+åËÛˆ Â=ä.J+QŽJ¼Þ‡Õ¯ìíóɲÈÕ¯=Œû4óÂç0„å•ëq³¼²~¿ö2m&ÓšW…C› Å>ꤥ¦pÌKŠJ½Ò­RQ–ñêJi“4ŸCšM¾ì½­Å2¥¼V,W(ÿQÎ?.!_¡H{›ò•u¿-ý:¤¿›`7#ý6-´Ò?¨à!™.}&âÒÝìÇI G¤Nù #‹ù¯ùšÔBº©¸4“©V8'j“£'¦ê*Õph+ä8l“c€µæ4@ƒ˜@Ê1Xm%†bKÍVä¨áì£RŽá˜,8bCž ä¹Ä¸ÈGmÈ‹-äÅ*û„Ûn"/%äå@ÞN=%B>&‘Wù˜]w@ÞMŒa ·ëÎB>¨òZZØÒ!r˜tGȓߒºò ò] 7cÈ'mÈåÖjS¹tD ‘»i­à.Rñ¡‰Ë>!eî…yS6ä*LƒŒ%Æ(OÛ'[È“51• $r5!Orԇɖì“y&ÏØ×[Žäb@>ËÈ?ã˜íòv§Gb&r„c@ŽùÄNº +|˜¡†SØ…Îù #5ícÆ9 råµõÊéÇaM5g~àêm­ÏÇÞì¬(§4qJËrÔ!´sÝÛŒúüÅzìëô}œÖÈô…£ˆ‰†¶æ‘Uí+º–¹·¡Á­»ÙÛ[ó’µ>q‰ŸçLdqâ7¬LÜÐà}-bL6Äm½Ó'î€ø—‰»YÓÝtøT{¶d5•ŠNLs ÑK—9åÙ—Õ˜}A[fKi¤Å/‹/Ó¥/ÏeºX…ø^ú5:4I£DR¡—Êm`H¾"t£.Ðr5ô¸I¦-Úš'¶@øK,ü3œF8žþ(Éñöp‘ÅLíùeŸ¡§¦-Õ˜~?;¡+®«WzP˃äêIvñŽ.R*+||¡ï!½ÏÐÔøøXvÎÚàëlú­Ào2CŸp&NÀ忇öëP3Ü‘íDϕՖ}²mOv¯J¥š)œ}Ì—]Y©°Wö†êÁ¨dp n½~{ƒÓ!nè·^/êäÁzS/\dNiYU8•þE~VÕõR܂㠢ËÒ)Ί ÎCëØ±‹28rW/\`VÕ4ú.‰¼Ç ƒcE„Ú±c­(5 Ç´,ž « Ù¶vÆ,ÏJŸèb„£%«|˜¯WwVÔ CT…RCÛòHËpZG±PYÎØX¨.w\pAŽÆî½/b•Oô2¨ÎïóOh=‹Rì‹)¤+<9þmÙ:b GHVû,ÁÊœòºÙ¡F+ø˯¥ÞØð]õ)TYš2_5Ïõ¡‚¯6ÄtÄ^ãªôcŽ•³Z})–§µPŒ¸]_,!1PFŸ¨´ATØË€q1~Ä[­™±­&º"ÆjMì ¾5¾L´¦£ýPg¤d¨SD ³†ᆠa¿…°ß€—­ˆ±F‡GŒöƒ a°S5Ž᦭OrÚ9gdÁÍÒ-Î}€Ã/YÈ— qL·™)ƒ#o‚é¶eÄ;6žNN“§“StÁÍ]O7Läôp‚çž§¯ÅÓ×)úƒ§ÁÆ3<ÜðÞQêOO@ð$†êäO@M· ¦S?“Ý=Ùxægót±ñ,µxx ç„m9…½€†E¸¡¼ƒ!Bz§÷Ç|™÷¸JųØ#ãrm'‰Ê…$–xŠSŠÁ§2Òçô5_k `µ³ØYl4]†í5F›P©¤¬òˆUžH,U¬ö§úà†j-ý°£®£÷ê Få›+çîOû*g8tÀÇÝØ­üŒ3óÊú6RC©†‰®žö³%-îë3­Œí"a, ŸN“üZ¼åÜ籆%û<â€'ŒUkž€:ÊÉlždÊcL¹¸‹â8æ'<áü=ÔÆžÕ¶g’ê\©•sqTSý‰þíe¦šHßÀe¸ŠØjbt]šB¦sJ8´­÷4[ãÒ-Åk¦À·S¤d?5á‰g:™6%å§æäàH¥`σg£[´(þµûu|ºr©™ph}IáöHw 3 Ò“ò‹“(î;$ÐwÂo:ÂÙCz*%ÃSÂáàQŸ£düÃÌò«NOJ¦û‰éØþ'ìë'ì‹þ®ýµöÓzåêûú«â§‘ÐDoé›T#V¬gâ>×–­Ä«Åzvio€ø˜*èkáÐÖ&ÅFQ©_¼m3¾µm*9O Nzýgî:Jÿ³FJ—8éÍʼn^Nôúlg-ý:±Ùk™lò¸ÖËò¸ÖÖ&|PêB;$?qùhÖtɺM²Ö·ƒ¸ñs—¤LOмä 9ßïÔ ïI—<5^‚¸Ð.é¤Á‚Ôa@-L@N‚:ܪ>jQê ' Ž$Ai u-ùËT:7Nï×¶9ôo{j‹Â]ôïYú¿Ý{f-;èƒæ°®íǦ½aÊ:>ÿTy£ýô–Ùãß-™Þ²^Yú©l?£eö„wKfÐë·ÖªýÌ–ÙSß-™I¯>ÕsÚÏj™}ìý’YôºìSãÍö³[fW¿[2›^ë?uæ¶ŸÓ2ûøû%sèuù§®¼ös[fÏy·d.½ŠOÝ­ÛÏk™}âý’yôzñSÏ[íç·Ì>ù~É|̸/õ«§+¦^œŒ¹MÃÖ’Õ+S製bÔ+S©áÂsJ@Å£šÚ­›ôœV©è·é9½R1îâ–ÖcZÒ…?£Z‡fZ†¸kd)œ¢Ô‰Â»î}yØÔÙ‰qÈ+¤ÜYØ='Ü×/Ýœsš£Øˆ÷ç)Ÿø: ¹8õg'ßšÜÓIc¾H±<`6[=””»ä<¢ÒÉmÓAL±/•ÞNöJÜÓ™h à¬£¯EGIösf5¨ƒœ‘ÁÒ \±Î)ÆÌ‹Lm×9‚†Í¦£”lÅ”{„³  ”bçX9¥ èrX·Á³=3pre9G>ÍÿCFçá“>¤%>-X¦ç/Ó˜±§0œ0%Ãèr?É´]¸:Í£²é§U"%'Í£*+ñE¦ú ÓÔ£‰ÿœ›»Uü3t(¯œ”1Já<½'C©ŠºÜ~晞™Lؼ+ ~âžà¸íˆ ++ôÂ9záô–Á:ö¬!›ár‹IbÖÌz ;¨ Vš”‘ü•º&j!àZàU^·gX€ël€·,À[ЏcÎ0ïò‰LÎq&SWary¬‚Æ6°Æ¾Ï1¬ië *F9eNÔNV[‰©|ÌØ'¦©«èc'¥OǬõF›¤Û¼C5%iIºÉ&iÔJ!ªŠª)éLSÒn¶NÅ”ò4Íœen±δ¦egò¦Ò•&¥œƒyÙ­6Àcàl p› °Ö¬ÕÄ. p¶ ¸€Ûm€3±£l¶nαwØçYÓ¹ó¨Ç¥›€sLÀ…˜ã Ûk¸ËœkFl€{-À½ºØoÎ50jœ…¹¡9† 8ÏŒÙç[sKó©#h˜€óLÀE˜lÚiÄ./±ßœoÖØY€‡ qÄœo`­_7\îY “Ot²«Ÿç°I¦t"Û*eŠSLq“Ð_¸¹„FÕNQÍÝÁê¼ïpènŠ6Ý)¦; ´3È`ƂׂTu…[̤îß5wpAK­#ÙY΂[¯ë˜Keß'³Ý•b=Ë¥ÑbÁÆVÕÅ¢_JömŠsµåNgWz›B2cD‡!a_Oq¹Çi,9œ¦7/í®tÐÑÀU¯Gfa…“;²ÚÉf_]CÏùÔÔÐs5µô\HÍö_-¢ñÅA§X̓ŠÅf+P+Öe®ìö}³3ÊÆÕW$­ºk+kʽ ¿¨­FÝ-¶Á¨{¤Qßá$Óí±õ°4êÛœÔ÷7zÔ¢£tbdÔëD3 ^ð)œ?QÇ‚d9hÈp8:f™¨±ÚÍ|ÁŠ Æv2Ö7|óÊ?yžfŸç÷,ÇtÓaMVCõ ™ì l/ H’,ÇL³ýrÊ7^­Øï,h‡h§äˆƒa奨(g—@ÎòrjÊ'[ìÊm‡J¹ ½çKf‹òã‚£ñ>É,½EáLþ×î}ð1 èw³©ÿæ:#—?U~Ñ~aËì­’…èìaãÙòâ47\釗)ŽrCt5 {ü(Xõ3GéóÔ,´†‘ÒçáºðX^aê»JöÈ2%t<ïU¢À’0%éö<Ç@ý±žÔ¡ý‘çJ.ùÄ@^àÄ'…™áC¦[‚b©RH-V5–ã—X¡¡ùzŽX­ÎÕ±ø#½òÑKóiì]j­ÒžŒÒ:¥°´EhÊk%ô{½Bt9b":¡UlAåßOvÀíy‚Sík?À²ö -;pÀ¯knÏŸ˜d°j.Ø‘)¬Š¡* –ùJx¸š¥GÒ^A-¾\¦(#Uñ}³—|Ùý»*ÙåŠE¯—}mqB+¯£Õ‚QÁh¢‰qV³±Ð4(ãÑldÉî(œîLˆ6[}@®_ÀÚ˜Š\ÏS¹ž¯¶§–¼„´¶@m?Go^2GÇq±D-\¨óÂR5œ“ÆvËâ”Ë)~ÞÄjµ Ç>·ÇĬA6©Ö”Ý â%t"O¬ãôF¾V=˜g6 !ŠBRÕ‚åø¿\WÄ&ÂÝj¦¶-žÚµÐ*¯Ep¢Œ9Œó°Z8äW ·gŽÊZ¨ÀriiÕ5/‡eÅ„²Fh²J½4Ñ;Êq§‡Ö±²bV‘‡tYjõº8å‹rÜåD9õ0Qΰ(gm¢œ“¢Ô#í>ûEÐÄK» /1ýˆ×¸,å-ï'{޲¶ž”–À°DígˆFÁ·¸ Û¯RŽ~!Õ)LC¡Õ”Ÿ¡†'¦F¦V 7¢Ô¸ –>Ë¢Ô  æÃrb„Ãj9â3# ‡ã¸¿)}ïÿ´“葌5胢q OÚÄãYf¯©¤ÑÒ»b’Qx&/t6Æ‘4œ¢! Hhä—]_¡5Õ`:þ¾˜fÍY>Í9:šsŒä „ŽÌ ´0®WL‹Ýªà\£æ„ÿÚ} ‡¼ÂÇ„hfNú±Ì:1”a?1tŠg¥›]¬ ˆÿCÐôøYûzõÙ’zU:»ü9n0'Ò)²„òÿûpèúógxjèEÿÙTøŸÅ 2â÷²'šHÉŸèXÐWËï«9ØEÛY†ò‚§mIÚÜØ9û'D ²ÆƒÞÛt—ðØ``u×'†+âH´Oçð»&æK /$ —XKv+Ù`B.dƒÛ—LÈU€¬O@Æw-uâë ÷oZêä—GÙÉ/ŽÅ!y¿ÒÅä=@–R³Ó—]­!KWgý)^Böà;üü¢§jAVÂ_N@Æõ—òJòþýå&äl¾!ȳž&ä<@^M@šC¬p¨×5dŠ}I/!wó{~”4!÷ñÝ HœºÂA«Pw@ÞH@Þ± ï¨|–¿» YŠ-;Ýý¢“fAvÁ°èfr8†Y#qÔ·c­ÁÕXj¶9^BNdO?| r o' WǶ*y'¹Ñ‚ܨñI­Jr+ +ýb[r ïúZjÚZ¬;5ëâÌš¼9s§† H‘èÛÑ7Tì®#Â÷8âºåË„Uܧ… nûroû%·pȨfEýâ ùv×WtÏ'™o >ÌT6ßzú‹zùÅó­Ò_ÔÛLüv®QÄq~cO]ülM[6Ñuñw,*óóž'“¨¼1Q9uõ‹“ ¢ŠÆDDÔÍ/N%ˆº7&êND=üâ ‘:²/D¢ùçó qÚ¼ÇSÌ?’&êÅ‚ Üîœ×® >¿ü10SÜà·ûµM:¸^0R4}·rñB¾5ipåªW6P+ój½Ò»)ln¤Ž=6Q¿âõzå`™¢¿Q¯l¦aU+ ‹œ9õJe¹âz›ÇŽî|ñ:©ŸñFÌ\öFTlT3D+íyÅú€:¸°·Æ#ZGŠ]D÷¥õyEõyëZÕÁUìŠ>vˆ†MoGUõºò1üïDÁúU°þ‚˜bÅžVvð˜¼ï¬vaê¬éaâ„‹ÍNíé}8‹ÅвWÌÙ+æ ©Å¨ÛZ1gRÿÌ]ˆs÷;ñ›ˆ™ßr6bœ‹•‹ßœ‹Ç Êï!Š-¿‹g¢ü±`IËÆÂùKZêâClÕh.Mÿ#äú«%×_!ŠòWH§þ•¥ÓþÊÖÿ›åþ&þ»XÏjÐøe@ ŠëUAÄ¿ÅH&odùßH±3 !þf.!>Å•U×ô7¨¼hf}šeJ½²øKO©|ïL$š†MÜJ´ccùnJ$–5îJ¬cèÉ΄Ëš¢ï 7ÎàIã§‚~þÜ~~GI_?Z´BÁnQ_u”ô÷c&0ñ>Ä/FÙ߇úÑŽQÓ;íFy@CX`nF»±•šš0L]ºªADD­¦(ªˆðŸ<ÂÏ“i5J+jºø= Â‰ßÆäo÷«bZª~±éT$Ò¹€t¥3ét ”ΟqÍJçšoÀù[ý´c‘’‘d¢Él÷÷GP/:ÓÏ¡ògú9Dþ,£Ÿ}éç™f¢‚kˆ·›JµlÔÑÊr =®ÝÑltOÈ3ÍFmŸAžø þ1"ÆY͆¼÷œï‰4°™ ¹>ó‹j5ܼd _LÃs°_N%öL€¯ø* ð^ ð ø•FJ0øf9jŠ”Œö£ydð° x%ƒ?ŒÓ?KàÃý˜k‡†ùMk7Æß‘’ëͺý¤­ä.ªâ2’#“»BÉQ“YðyK ï‡&úƒŸ·ÔJÆøÅu †1ÃÆ´d¸_Ü2å¹mÊsòôId§™±³–€°1‡kÐÏ1ÏjÚæibÆ)qê µVb1š·ñ~±DÃV<$‡hlûƒŸÃ8÷K$± IìÐ 'vî$’¨±’¨AË'±‹’؃$&úÑúÅ“ |n–IìCº®“Ø~]äáfO¥®^ÙJÖâ¢Æ»P®hâ ¥;ÖOcŒkôc¿î{cÂmdºù 3׿àÝï+`7µ˜¯ŸsŽ…N4Ër4Áö~éX‹Ó{â.½GŒ‡>ã… ;ÇÇ.™4ì¦r‰†CHÞI\.±õ>в0Hà,p_aAÖ¾:ËŠä„»u *o( ·ƒôd1‡è1¶oÓc÷§Ut¢™÷Û¸ Ádú=É2šX°‡³ê,b,æmTM7Bn& 7«—â˜IR- ¾ÉlÞß[þå»{é³&[N/óÃ6(kηŒ[”ˆƒºSÜ8”Äç<†Ð(¹g‘Üúxrëul"RÖëØÆ‹TØTo‚xCÈ>ëÆ›\o⺫љO©1•W§‹ºû´µ›²ƒ½GE‚Óü4TݧËQÜЀîÔr'ã'MÈ“\,êI‰¬£çÔ_éçuq:Q:g¨tÎ%¥Gíûyk\ìÇ-Ö›àmS$•GOd_‚cxª@Dy…~~"Gžh ƒÓýê'¾Ñ\#Æ~s+5‘ïðáÓyÂulþàgœbcLUÉ?î ¾ep‚åXÙX‘Q€‚‡ —õ9U–:* ©<Ç媕¶‡i½ ”“Þ×€Ž x÷0"˜YÍÄŽgúwé³äîÚh<”*]¥o¦^EO£yލ4¨«œéW;Öa».ýžE¿I}p48Õ¯@/4¸'ã·cûf|›R±3·.˜Ð Ý(€¼£âòŽ2å%å­2Ð;ÐÆ4Ng_òcéAúçÞÕx#.Ö‘V8T寪âèÕTѦè]M2b¸Ò% S*—X-s(™çL3ÇLhkD]MíTOÖXÑ  2øÜJò<ʧŒ«yoμ¥o”¿jlŽXµÐyXŒ]·ØLe•‰{s–aæ½ö}˜íxãRL°£äÖf0z–ë êGð®7PÆë°#Hl@p>ÿ¤NÐ#28Û¯¦s6Ûƒç Xlå¼ èÝXÉ_È^CZØN¹ì ì¥Lï¨T<»} âoe?=ÃÔc<@ÏuÒóZwÅyˆžÑJÅu'ô£òk9`ÄPЇðpyç¢XŽ\k#,œ0¼“p*a§šqúâ UR/¦8#L:ýLÓ<=>;|3}Ïãn.d :Çõ:¾ Í‹[axßBk* ™uÌP_½ŸšâŽ7ãßÌxâ!óuCfâ(ad¾NUæ–AªˆÊë6ý0Ѝ€î16-²&°&{9k²—SjOÒ$Ðdo§ÔdzÆH“}R“ýœR“ý¢·ÓÔd'k²Ÿ“5YMvÚ49ÄéÝ„VëçøøÙÏïp§i!Fø¤¡æŒ hÎ*b?CìISë£÷i}¦]ëÓyv{œSFIEŽw&+’1'8½¯å'³Ù¨§>ˆºÚ)u=Íiéz É”ùéz¦ÓÔõ,§©ë9NÖõ¨€Av}#±ËH×ÏÕJ/sÂ$(ëüÁnÀå¤âôÜ”¯orŠ•Î$6Â/­Õ*'Y«5NôEé+~»øŸG¬õI¯uPà…²0Kb½3L0lØjÅù2‹­ÜF'>³‘þˆ Ë_d{ª¢c`ö69-SgˆÍ)oŽ“–n4 Fu£JCŽêx½²{Üd¶êð$CtËqÔâljGèQKUç(=ë¨ê£ç®JÅyœ³ï:!³ï>廑ï4du²ºÏÉœG9û!Ô\?/}!pÀGµâ–|ÀGuâˆ3*;IᨙcL“™E~ŽrdÀŒ$ U§ìU%h qL&5#ÆãTÂYŽŒt¬¨ @ › t‰NØ}TޱUÅ.ªnqÊ ØqÚËrÌ’‹z”Ô,îq†©…žc¬ãb”ìñ¾‰-« o‚ÛØÎ9ÃYŽPáDÑyØœVöˆÚF&••‘»Ø¹dIUqÝÛÄuïŽS¶èØÜ‘u¯œwW«]é±›ê^=÷Pus‰†äÊ7Ò¬|¥.*‘ή‡V¾.®¤ÊWî"#fåë*_då«pQIr«ªãZ þà9Nþ䢉A¡tw%W¾1Ü͞Ϧk߬QÇ;ŇÉâxT}Eå#\¤§44f#]Y 9ØÙÿÀv­ÛXÜ»`~éã¨*í#üÓq7fVÈ·MrÉ\ÏôÉ‹µL‚©.t‡¸½œæŠ·—4ܙ޷÷µ—Ô9ší¼~Dú5¾‰gŽË¤ý¨Îû}¬Ñ¹˜†›ÌyÌ0Ѐà"¿ö‘l2؃#X,zPޱÜKáÉŒ¼I~PÇ ¬¼‚z­xÎû•¶Ê%V¹¢1išu±Öcñé«óÃ2¯#³mZfê»"Q³Î“ÅÎue“뙱Ņ}îãFªnôaƒ±›R}Ž·¤pâ»]²©ÙÍB¨»¥Ú^7Öú>.Oc¿K¶40íÕ]q¤ç^²‡p/†Ùâìsq3F­¹‹í8>ã.4?â+‚/é,·ç®p16ë¬pnÔ]Þ=ô8íŠ7ê†8ë*6øßy¾k7Z nä<—]⢠̀[\– h5>ê"®¹ŠS²” ŒÍ®SëQœ2 ©•w‹Û.¤=]žðÆ–ƒY>Q¼ë*vÒ¸² @ryÆJ¢6§¿©°EºçâîSgl?3¨TÆ ž{]ÜqÁuQæŽgþ‰—™FmS…mÕÃnôÃUD¯‡»§NÆŒtݸÍ3Ô‚ÁnåT.˜¡nY0xRÁà‚îæ¶_áæ‚éæ.ó37kÈÊ÷h7§Ê-†»Íá6 hdBÆÏÜ\@£ðp‹*7•SŠ7GÁvRvÊl·˜@2§$•×D·÷Û µÙЄÙu öÚmv¬ ZíFóÍÔ-f¸ã]C̤X̹¤ÈÌW°>éf6ÙúÔ!U,$+Zœš(;Vu–B}rªEÏÇçn.ôÇRæÔ_ðˆ•T¨ŒÍâN)öLçâ^í¶Š›bw³ÆíÍEo2b²}“›7nv{¿CoÛ)¹:¤QÖŠÓÜiÐ`8‘C]D K?3gÞk;­JPcU‚:Y &4j$bÜHsóä²þ\°8Ž¹Ùªâ±ˆLà 7_NºÅ *©:qÚÍ×®¼ý¨¦‹¢Ÿu‹³n •)}u“²/¸±÷Åàq÷71ötcL¾èÆmCÜ#¼äöâÎk64ú×ÝcœóˆsÔl*#L“pÉ(y\[‰i.L8œ÷ GÊUà‚¬‚«€3^.šUÀ).“.œÈÏÏj¤·Ú0áÍ* Sö;áÜzn7 ½D¸Åz˜Ш¯õ_<“bUŠYº§pè‘"º§<°È{¤p¦{¥XE^™b/ò>)<7<–熹©í›’(èþ)|ìw*Ow7ãI–`^;ǨQ•bMìá‚Gžº{4ÕMu /ÐT§ˆé’”gîfà(È´äb‹|qŠø<…×$ätž‹Å`½E´^bâqé)u3=ŽPÙoIá;ض¦ˆSÚ,󾅃̕¶­)\ìßAeÝ.3?T–3k†)Ô,Äá8¹^GŒ(¿b½é:*²HJ8V4Ì/¢ÈË ^×ù!Ä܇C1Rx½bÖ+ò—´TÅA04p(%L?Kà0f&tw™óygnRxEK¹œ"®¦à^ƒm~U\ù¬€aX“rSAŒè;§Jz<·ýV-£ÇqÒLyª(Kåï N”óhôP‘*Ǹ,,›É§Ý»¥¶=SyV2š¿Ž’ëJ­–mú¥,n)'_‘‡Å-uÑ_ ± ACmA±¤:;‘¿ªT+U¦¼U©bl*ò‡µ¦q ŸÃ½ãeœ¿™ñüÍ4égÊüÍ6ó7'U̶ò7Gæo ò7/)³8ó)‹RaÃÓÑ7Y’Jc¡’JŸøœÂWZùÞ@b¬±ò½>Uf:ÖªØ*³Ë/SeFùeKª\PÙš*T¶!s*Uß]œ]©æôŽ!3¿ËÌ žèíï§ç ÊÍzž$~0Uì13`agpö’¤û¥¤ÁÒÈÉì©Y¤‡Scæý$D¦ó¨GRcÒüÖá¦@8‘“ý¯“ñqŠ‹ü²(⣸MGdn¤ ÎÌáy3‡ÃyƒÊµ’sx3^P7ͼÝL·S `‘‹;”‹{–¾7‘¾KÓ_ au¯SZâ›1ƒ:§%ÖÍ ò4)V×4)V¶1Íçy5i7ú§YójõÊ)®Z½ršì&žXÍÆsóoµô8Cz’Æåa MÓ‘X*ei/4]CÒ¢˜74ÄÐ4¬ûëi8¹¸‹]OËÙ°áiÅæ –QU´ÃG¤¯¸]|‘‹Ûퟥ…1„¦ïX£ ç‚€“ û –sJÔw–$œB"œ# §˜NIÕi÷«ñé#ýò#ž–ÖJÌH“Êåo¡Äf¥,b½E¹2Ç‚TeóµÔÄl1CìsdÄPD µGÌ…Ü *Ù»ñT‰-Vpjù§š:ÄJ³å;–fÿ4¨ÔjÓ’;ôQà˯K³uJö¦Å|ÿ…y- ôý˜~D ;c;¸¼O €iXø´üf1>¦Aòï|ŸìzÚ+.gæ>*_—Ûéý6A&XKf=žf~c]ð1ãÉ(ÎPÂL„ûÒ=â|53×D¹] ×ø é,½dî¡ïñbZí<‘ìÒÅSëWM­_ƒŽs÷i9ëø®í+€Žïš:Æsé¸AêVë’ÎfH/Kg3d”§‹†4l9è©`Ï} u¢4ý>åcš¡Sz,GtI¿Oûeél™ Q‘þÀbè–ž(,QzD¯t© §¨L§ÎŸFîm£}8 Š©ê!a=l±1=sqCƒTã@Š”Ì1Pã ;Jza5Mç©®èlp‘.Õ82]ªñ³tt¿–t2r·Y“ÓÍÛ'§{' ‘éáHèb^$t)úùkÉ–ÍL÷¾I#g1/9j=EÍO÷¾Œ¨%ˆºœgÞLßéçéÞ&ˆ^™.÷L¬J÷6 ‘õæû†t¹bcº÷$w_Ò½ñŒ%§´‘RÚ™î]‹KèW–§¦GB#¿V+¦¥^É MZ÷Зa–‹Ã&­›èÿLa‹8ìj^Ô¼³ÿ,L»i†9ã·Ý»x:ÌåV›ýº¡Áµø^ÃÎ{ õ÷2¾ÞÐðý††Ÿ64P„¨KÇqLî 6ðÉátTæÖµYŽ:tä¹<§{¿ÕLVú0§Ò½«u>9 Íü…tï$D]n\°›WÒ½Ý}+=\0F‰„6y‚c%Ô7}†ÛéÞ?ðÉu²Õ2ê•ôuÉà‘yY†è’$ŒœLD9ùç ^JY׈¢ëÊd</l]A™Q³JGC;ÜÙÃÚTóBy·Œp4?âWˆìŸËï‘!+BŸŒ¤¬¡Eí›áÝŠ °[M¹À™5 Ø0«@L}›UÀ T¼1ˆ1뀨z 1`V3PóæaÈbÖ3PçÉÒ{f50 /Ó•²˜+‚ÑìTZÞkxÿ^Ã'÷ñÿsî¡.P„C¯<ZÏmæð T„ÿ¨å2p 'Ýßûª22ƒÏs–!F’nwº ÿ£‚HÄgQÜxX'FeDÍKžp؇[ŽÑ­Ä˜Œp,KaÕM"Ò~©ÜL¡PôdWRðTó÷jú]] ¡Õ`ʦQ,ò«ý*_É< €æœ-‚qŽ BTbò³Œ·Ä%84“ûŒú1îZN ­¢5“[Åž.¸Å›µvíŸ,9Å €™_x¨Ÿ•õØÅ›• Ü<ˆÖ…3o™NvÞÆ ºøØy’ Úš.vÚŠ_GÄ{–÷‰juXžgª?™ÞuþÄofß:ÿaºÖ¹×:áÝœÓH\œyÅ•Ò9MöåÖq×4kðóÑ–©†*¦ß“¡J½r›¾¨‘pÙ†up ©G(áÈ5XqI¿‚u~Ü,ù™m^mÞÒÍVªãW´u©9ŽÇ®c±_døIü$ÜIÁœNo\Ìý˜À/PÞǸ7_,=TfZ$]Õ= C¼‹é~d Î7%œŽˆ¥Ì‡™éª¯¨Ë‰ê.5¥«±\‰ ø¸N¬VžÅ:¼B½ ¬BmP¢HðnžØÈ>„îåM™òq­÷_±CX)¼‘[øá\n·Iº†<Š;”‚ÁßˌǔX0ö˜ÜY‘$¥­ASb šÐƒ×üwJŠNaçC»Í$äUÈ‚þC%4æñOqIψûØÓÐÖ㳬’“–O*â4ÿ3Jóœì.½qź‘*•ÓÕ‚é¯ZôWqÕ„Ð7l™‰ (Z÷˜¸‰­…›8¡|fìÄÛÜκ]TÑEµåkÂW}pòR–F6™7wŠr•Ll¨€‡ˆé`gs€*¹«€qû[þuú«õJYoE¨r© Re© VÅ@téŒÇjÅ •‹q°ŠbªR1"¥ap4‹„»ýHeK@§T+œÌDN¦¼·â˜LÀƒŠ”)ðããRg¨Ü>ÌTÅdU^3…ŸµbªúÐrÁôeµ‡U?žO[ˆ¦SpBëC„˜¡Fù<ª˜©rCÃÛmg«ØNK MçÖYJUQçÖ+l·Ç.È·rü3ç`…júX¥ŠUjRÅú¸†/9f¡aŠÚÇrMÐ6Öõïb+CTö¢.½ +[¥ÎÕí¬s-¬Šíɺ®a5:àã8G†Qú,yÍI)Ëx:7…1•FQ¨5|Àl;5N×qЧ¬Ò=e–îyYºõª8£š›j²qVÍçï/åzYÊWÕ÷n±ëŠ :';Ë'ù®ß ø¨šðÕXp@žœòJ~—|…4¦Ã"î™à„[ÕW”^S+5Ñ3áh¨%Ó_+Øôd$¸éI%´ùIúêjXdÆró`úEÚ­CØÑø"Љ¡ìЍKkv64\óvȨû@F[¬UÌZ%YÇh6?Ec5ïÛè!`ù»7û)ê ÃQQ_-îÏ žŠ.·#µ¸C§û=éÍV64¨-ÊV⦠ìÁ s=ú9ëc–fÖ£Y8ün«Gç3ø ßÜä0éžĊ¼8d°|ë•‚²Ö÷ù<úWlÝù9šo²àÚŽ¶†1ŽúÚÅnd¨Æ Q§{LŒ·¼ÎMà+¦Ùx=ÅDÓ-¯sÓá!4Wuf«8‡/™à¤íËLºÎò:·Ná÷ ÒëÜFËë\yk4›øÊif{‘Éê,óX‡+ÃÔ,ÝÎÅWUGuÜåî!±¥§ºº¸£º.쨎Œ°­I:Ƕö]³Iº ˆ dhÉ"Ô?°Òèwe£ñAÍÈ%[3"®p³°‹óñ,‹Ô`壖Ûj:“…d—re8…»;`P¦Ë<Àc]–£–?¾lr­O¢ OÇ÷¤ow¸*†«ÇX”clÝ>ª#UTç‘0–¨àâ3ru3ýrRáu˃«$"oïòÃ㺣ÞWørfTñ:Ôð¡ªåŽÏªÎ WgÅ­5[ÛР”54ÐÛÃŽ=¨Î—©BîîJAERŒùñ¯]!!Ùãg"Ôý\Ã/¯(ÚHU2šŒR.ö¢ÈÇÃ-Âo: —K?, ÊᢥAŠÉÊ(©v†³~R2͉«‹üŽpðþœÃŸ+~G[½d«Î>×´dY0œÄïh¿Ë¨-¿t[¨õ÷«êÜ£UÕÌTÕù‡U(…ÓS8=…ÓSd…ºxJ¾ B]B†/Û*T=‹öXãšòDôÒà L‚‹\Àÿö c‘(àŒ¢ÕZ$Ë/f¶+Üù²´»]´פŨMe}-n1.±Åã«Èöá¬Êå€SËhòŠ|·_E¶Ïߨû/“®"»’€Ú¨« ¨ýIPûCr%A]K@ÔõÔ$¨¡Ž&CÝH@ÔÍÔÁ$¨ƒ¡v'CÝJ@ÔíÔ¡$¨C¡6$ëêNê* î& ®&A]m 5ª%ey7äжeúº}QJÑÆ)ý­pû32¥ØëL©‹L)†Óäñ”ºsJ(¥Ž¹¥m)ÅûY¾DªœTg¥°þ»2­5O<0­r™Öš'P¸VZ=¸2³e¹ËÒ³©“Jõùn·,×[–ØëI–¥Wê *P7’ n4†ªÿ ªwê& ú$ n&AÝl µæ‰$¨¾ ¨Î\œž€ê°Cu|‘éìO߸’ ·ø2¾àa9ð¿vÅOÚÍç5?Ч3›&†E›ºÈ”†.ö¦‚þêCÍäWÉ4v'ƒ¨ü½Ñ µ ß ¦ÖèF&( _·€eøºˆhpÓûF7CšZ¿äþÅQú—Éý]2ú[ŽY€£è*ÕÎ íб<ŸÁusB»pè|†U7‡²”Ô¾¼˜û¢£ôE+½ìúNÔcOºÃ𯯠”îð¦ñ†±"©t+—î„ä[VG$ zjdªgTÏ/¬(Ÿ¡¢¤ÿüËWjb;ØëHײŠ[Ú )-ýn«G7•~_ûNZQIâù&ŽÀçÂÝ5G6áÀ?Qsôçp¨™Óî Î៘g‹?Å]ñß«_‚oÁYoræ0#õ? ƒ³ÞŒ»©únfGÓ^7þ^A÷/Ñ›Èj÷[&{IÙ1C0ŽÅ•[:w¼€ÛÛ›Â` 5¯½‘¢eèKL@kݤi½2¤Lq¼ÀÝ {´Ž„z¶Æ®ZŽuƒ\L‡žyN•„ñ‹Þ{/îy×>Ôä÷u”ôqáo_[÷ã¿ý]þ«„ƒC¸^±.‚§ À.kÙ<ð´Ãñ[¥ NöÀÿÁåîÀÿ­òGã…Úìáï‘\Ñæ?Wžw«Dn9¡iˉMqk;.jÏc˜© Ì‘?î{ ”WÆ÷j­Yaƒ“i­×Ð`ЪL;8ÇÔ@Öc‰.VÖ’^©dM 5›­ßRsûñ‡:ï*šcʧ“ìÁ¡9Jþ°^û}ü[åÅuün)ÜÑÐÐÊaT¶v(†£wk‡j8z´vhšãÿ²÷àq$ÇÁèöÌl޸ݤÓxŽhP:%ûdK¸äÀA–|§ó“-@k½²lËÒéhÿÏú €`3 0“`ΙÀÌ ÀœsB3ÜWU=³; ´ôù½ÿ}ÿ÷Þ÷;3ÝUÕÕÝÕÕÕ==UÕùÅko0ʆý®JUïŒë±¨wvÖ;‹HïüèßçýÞPö{±ÈéÎ’K½†««çéážÅ¸"Jš!uórÎÉ_ t®9Äöˇ¡À5‡¦tê=/ZöH=ŸL:ä›àî´\ìyÑŠ³‡¶âÌQWœK¨Z5 à~÷kCÙ¯up§i™9 oF*ÐH‰#Õhu˹ú+1á7æÆ’ù¾,¡?«QÕ,OèÏê$ýYÝUîJIÒŸ+¤F#©• R£“HvÿW¯W%HAR«¤Æ$‘Ó•ÔÉ“H­ñh+§1„®éÆÿ~©WëUnuå´Öƒ/ºÅÔ¿î&×íqа=AUu8f¬§Œ·(ã=Èè Lv‹ˆ…“݉CèÜc”Œ¦"‚ô«¯ü¼áÔ×ûáø{œ°Š½<½…`œîS=Xæ,ÌröfaáÖ1o:zsü%Bƒ´ BÝè1ÊFÓTÊï±”²Ÿ~OïsúÃ\‚ph¬ÜÊÿ=’s#õÿèD}BU2õÿ3˜äŽê›.í«l@Œ?G8ooõ¼ô Ó6¾yývM•c`¾×ðzúkzDg2< `<”úïäÒÑkøwþ? (Dá«”û ¦.þÀ? ûkØ*Zô(ªaa_ c9y}ø@Ô ^,LÍ–žpTˆè h¡— EDÁM>Š4‘ÂyyÌe%'EáHáÄ|ƇãHÝ®#6R#6RÉx•ŽXµŽØLŸ 6‰MÊG™E¿á|uU@ÄÆkÄÆ bã…xg ½‚&¾Óž˜ -œ›'QxÜÉ ³NΗø¤º“Xük¢:M£:MPÆ@œ9ô=;3AÎw õáu@Ê7%ßÜîò˜¡¹ï+Dψ€ì†Þou@pCY IÒE˜º¼þé?Ã`é0ÈjóußòÍq³nõ=0¤é—Ñí:¦vŠÔštù6¢9¼ðg'þÅŸ“`"›hé}"–ÞEy¡À^w^E+«Èk¡ÇƒÚc+=¶hm‰uú‰TÚ¢¬ÌË«ÌM>œ…s gÝr`U“s&%ghQ+gHQNMчì£~ÛR%0ðÓœúá,gñpÈøSIi;£ó½9[ŠØýŸçÔ}¶ç÷?;å6êrÐ%·©(±·úZ—Üí¯ÌÝñÊÜ­]s?4 몿ê#ªþ’T?ú_V?ùšj§®1,]XÞY¤ßh–_ÑÌ?|e3ÿè•ÍœþÊfîš»M—ûÙ.¹ ºÜ×Õf¶%53îa;/ýïˆY— x)©ŒeÃEËá”#ý?ÚŸÿû÷+‡‰ûÿ†¾·'õËJµ_ÿoÛ/[uÌb¯ìµ^/É}îÿRÕ÷ßêSg²ÚTûtÉÿ’>ýÿ¶î\=<®;ãºMþÿuÛÿ»ºíC‹x÷±–•®4܃f¡Øƒ\߃\{û<Œ¹Òt{ûÁÐt¥½N8ïÀÚèëÚûÝoˆ÷»ß˜„ä ˜o‡ÞñoÅÃ=2§ßO¤b“wcôº„á oSçýÄCH|]·Ÿ'û‰oˆ€v—Äë½E¡À¥øë½ÐËJé©–-K ý©•„zªe+šÆÛ܉S-‘8»Ú¡ “z]°{J°»Ø=g7ú2TŸõœ@mÔsqÔÃrM;×´…JÿJ—š¾]%‰ª6aU·ãÏÜ-WëÛJ•Õ…iµ{L%CòÂ_}SÝôm{5ðç ¸› |äÕÀo!0Ü à£Äýÿ„Ø¥6(lhÙU¢ek eWÅ[öîùRhÆÙ?{t­rœ°Þ}™ˆVq‹=/Šm‚bÏÇ‹=ñjŸ×¸ ¾ÚâN¾¤õTÉ­wêOn½}Ðz!l½‰Zë­\L.Vǹ8Mr‰Bõ•¼¯ʾ’Üz@lV ¶›ï€n!~r^Ì<”uQ”µʺ/ëìË|é´@Ú H§ãHçþäšÒj~ìCµæ—Å›”c†—ãoRÎ{L@ø»ÿEÍCXó0þDð'Š?‡¡!ŒjC\xõøöŸ&<¡ùÇQ¾ôjà78K¾üÇ¿­_ù¯4wW¯¾¬ý%j‰Ú_¢ö—Dû·jí\kÿ+¢ýCû_‰·ÿµ?JòÚ°Áè$ïú«™ÏNjðLM¿¤ß$†|¯ž õçzÑÁE·˜©µN·ü£êwëwBW¿ö—Ì1*Ë_åŒ*Û`¨œ‰þjÔõ¬@mÔ³qÔÛ„úÝ»¾ø({êN~ãg£Ö°uî÷—½ñëúB¯x¦M÷JÏŸx£w‡ zV/ÃîzL2ÕŸõ/Ã껾 ÛR”|z3Aj1’ºŸ µ8‰Ô⮤¶&“z µI=LZ’DjIWRÛ’I=JZФ'H-M"µ´+©†dRO¤–!©Ž©eI¤–u%Õ˜Lêi‚Ôr$õ,Ajy©å]I5%“zž µIŤV$‘ZÑ•ÔödReÞ8©•Hj 7Nje©•]IíH&5(Aj ’œ µ&‰Ôš®¤v&“*OZ‹¤*¤Ö&‘ZÛ•Ô±ä÷µ• RëÔ©uI¤Öu%u<™ÔP¯ÄXj>ŒÞùüѯüÿ(øFÒù¯E´Ñ¼¦(tÜ ÉKé°$i÷òÏ]swûèWÁ¢ îj/F¡zóÁë?e¿ig›ÍÒ'xÊÍ‹©¾x{ªxWÆ?õÇXàô÷º½†ï‹ÀC¨ðô÷/ÃÒÆxM’ÝÑÌx4ÆÞÀ›u,DŽRý½0˜ãëJð†C=a¤Â™Ú»Ô›îvFÞ$Š‚øž×°â›Rvð¦Ä'iË>háS˜[nZ&½D-Þ–¦¸|:¾®”J¶åòZVÔ á©¢m}BjOaƒ$ñ¹,Œ¯P?ØøýP Ê“eè^x½·‘/θó¸ Áûn¾ˆuÈ¡À}wa‡Ìx=Ë£Êû©=bˆT´¹—os/ºƒáC%Šr\%…7ÝäÄÍïw«Ñ±ëwá } «å-#€§,C 6?0Ò®9Ù çŸF_¡‚ê´ØuÆÔÇØù ÖÝ|^<šÓ|ülj<ñç%´£ÈßI©È Fœèpó…r¨p°ÇÀëå¢j¹°ZÆ ~Z…—â7“tÅ4c1{ ˜gXÌdª«(æVÌ!#ÿ†ƒÏÜüˆ¬V*þ’ï™»ÿ *H‘~§èй‹Å܇bbXÌT]m:´b:dþ kµ‰a‘17¨ˆÚ R´Ú V´ÚT Ûÿi^£Ñî,µaz3T+ílNcãá:£ ÃR´³™ULž¡ðÑ ¹R»ë&Äý]·ðœ7ÉôÉ'-|¼‚«›x·òcx„#è] nü5&ºõ ñHýÛø”8?3zmyÈØÐ-'úVœ¥/¬F¼ˆóÏ7•*ŸÃl¥7_ „Þ?ÔËÀ)Å‹L…GD!¸ÈÄë•b„Î7a\‹¨ú/W´AÁêƒ÷Ü|6Æt¯ñL(MÔ;º6‰x¹5ŒIx…&’O)|› G¢ï7Ùe¾WA.EÈê}ÀÕAj„ËAlƒœ‘£e‚ŒˆR´¿—o/U )-XGhjOLl…ÄS˜ÖÕ:ì_dÒœ à÷£5ý¡yN+¥"Å@¹,ÜÓd Á…—¨KuMÁŠÓîºüþ”|’oÿÁ»n~+.›a†×h³;nÈÔ ÷-PÙ}E*Ãk-ÈÄs ì SÐ1¡RfDÆpiý¼i+\fU1ó6¸.g–f#F¦P£›=W²ÛxLÁ¯ìËŒ;ÝÈ“»=,VC•KÃøœ¼#F`ü&_¹Gé/ܦ»·ÑçŸÃ‘Rãkè¯q”1·¾ DÕGíÇ yªž`ìêv(¡Ôä«Tqg .¾i¯5&÷k½ðuÄëŒNΟù\"ºØ(,AV AÖù ¨Â-7¬$õ.2Gzd¾•è¶~éêgæÛèZQ? o4–šý{}+°T9í0’¯dÞlÄ9#°«WÙ/ûYùnc©•BÇí›"o©Ùçe¥–Âfhø½"¨íî¥ð}¸†Î~Œ&9“ÔJwêô6£öÍC›‘5ªŸ77 erÁk½ ÀÝ~™ÀGY —üfÖѤà¡ÌvŒyÛ“wó;˜;Ë+9ìŽËBç<ÄÀýÌðoÉîg…‹-="£Ä=4 ‰{H¢%áåFüPD)3Qô‘q&^f"%qÛ63ÐUÃ*Ýv“«ùA¦0ÅP<*5ëÛ¦r@…‡¹®§+˜eˆ‰—›¨½¿Í+èyµPbÀj*µä¼_ßýF~™çÁ׋±YjÎYôcÈÊÀ¬á˜µúgª`@VG9«ïý2ÒTjÅe eêÞ‡LßqÇ݉bh•ë;nrA:ÁBþÚ»Èuc¡u":‘¯b¶I&>‘¸k,ÌÙø$S©-gøõýìÒÁN¥LÅRf˜È¸W’펈ÐksLØYЬ†9&lO6Çě‘e=ÐiÉ—ùŠ)Œ4rO‘ెœa,EªËä©•ˆ—«sªX}zoüÜ_ÀÄèñÕˆµQÅ‚‚ÞÀ‚6A¡Kz¤¥á=΋¤Ž¤^µ‘¶SMçŠq3¯Š½f¤  Ý1ÔÖmÕíwTµý&MWapòël¿‰‡MÉܹßFµ«—˜þš_ýÛî°Zôa¤ä…EŬãTô\*ú[Tô9“:[œ#±dç0¤h×Ûn~ÉŠï¸ùS(»ð‰›ñk„=Ï++vÇ'„}›b‚¼ÕFŽPîŠôMü®Ö*·ð{ø±Í"÷M½ùCSxÜÇ­®ô }e“›øc‚Ž€a”x‡©èÄ{èèèÄ{€G[#Y†ÌC±f‚þ™ï•`ª›,D¢Ò,ŠïVÖ%CÍÄÃH3F ˆó0̬ñ0ÜÜ›4gZÑ3”ÊBà\ÿ±\mæUf='Õæh Üäï;©óÑæR…Žk1õÅ __-<úzMR$ìY† ÌÀâb1*XœL,îfÈß|0P0îÀu3›I|Jµf>ÍFgÆ|:•]6–µð™fŠØÊkÓ6ôv%8•g™ù,s8 üùw³!D•ÏF¾ (Ö@©˜•ïŸxÞ%œtA"uN>H Ñ[i¬dV>_OÝJææó¥f¨w©R8/ŸAÉMr4â©€:­ÄÆÃ¸w«°r ½F“Ý•ÛH‘–@µ6B}–V1†×e0Çn…ër˜cwÃu_‘r&ò!ULÙëm|§9úÕ/|õ …Gò$¾ÛŒ³fÙëèùÙ¢ðcŒLžƒ˜t’ÎcÒ1éÆA§^ah\á"6L^¦Â…Ü£$¸Â=²aò²þ c[Í¥Ft!LåfQ³‹Ôm¯÷¦‚á¢YÄÃëºALºhæWÌáôA WsÍ̯™ýÏ%ªÂuì‘]Ä”Tšø-q7ÒÎÛá.RÒ$s7Ñ’í°øÅh>¢q"Qj ñÀ\ü\ëï9Œ3LAín<ËCCµ»ñPï@ˆnðÔÊþû§žú§^Ԣ‚µZºU ‹¨lô_¹øÇ†!–v6 läa>Ì‚ªbš:[´òá–ˆvïÀÜÞ¯õê+gÒH€>_ÎäQp]ûgJ•…$¤…*REϳÅsÀÖCª(q‘š¸öÏê¡¡G[ŠæçSˆŽî¾ùù 0ÆÇYèl¾W…ô+ây¦Eu`ˆ‘ö¸Y…×YâËØV>ۋ׈¶xcѯó-BK¿†Ë°…u1d‰/†,ñÅši  oR‰k´×Xø ¹=Ûr#‚-Å=ÛwÔÕøß-Èu°ÖŠo(ÄDànÁ22*¾Óås¡vöðSÆYqCnvICn;{ô©ôˆµ³'ŸÊƒ¤vöôSeº|úÔ8‰Ë½2™Ën¯Äµ ®WçJþ†Üt-Jd½ä¿ÜÛ¿ãíÀ²”\éÍ—iËP²0Ÿ¯¦Çc¾À¢üš’ú|¾V*nÌ-jÊÍkÊ5”4æòõRñöÜ¢¹y;ày{.ß(ïÌå›$ÿIüú|§}¬’¶HÅ»rùV]Æ#È€¤ êÑêÁ‘Ý^üDªqné&*áöD‹TÔœ[ØœkÀ˜Ë9,¸ÊÈ ÊJ¯(ÿ@ópá¸DöÇÜÝÜèýg¬!'{Òß$w‰¹Å.,÷æ'°8Z°ž”a”Öx0º1'z0^qv°Îƒ‘гƒ“=~¸p!ÈäU9Ô ¿†×I~Cùsƒã<ü–\4ØCrÛ.kŸÓòørþv|9×Ù«aíp¦Q¶ÂZ‡7`?Ôm Õm¹Z7E«ØÍ Ô·)jÄÅTX c{Òôçø¸¾Z¨ðÝ À-?ÃS &PÇ㊨Ù)EÔ謭Р[áœ"êv–ÎÛ©N—­N—­NWâ˶«ñEô5\À­ÃÄáT…ü‘Æù#PÂK‡1öLÁ(€ÊJY¬V;€×gôLSt+,ÌBaãJ™6FÔ£¯‘À¶÷B‹)”F…1B“¹8r]i,êsx¤°æð!F„>ƒåÂp´ù§xø¼NóÀrLc¼Ê¨±[ëuº.¸Š«…ë`NÅ.XO]ð×”sÛ¨ÅC5ò» ø¿gìÍ1p­TÔ£xQ±€ º¦ƒ©Åg‚©4 ØH|“ræšÔæšø|,{kÚrÓ=¼ÞÌð€ÁŒ®Jud÷ Ù}€5ÉnÖ‘ kdÃ&°;@= d[éû$Fõ"²GìPQçJÑ{`åSÌ8Ó )¶ Y·×ÜÂÔÑašgšCþ¹0¸|ç}4®ëÌ4®Å§54¾5'n8Îçe¸øÇ±À’|>ž‰Ë…”XšOê¢^{â‹ÍE§YÑ(o”Çà;ÍXɲ|¾ŒrÑ¥~̬1«5_cG3›Íê˜Ù&dƒ9ŒˆÔð¼Ã,FÂ.3´ ðÕŒs6Œ0lrÚ qìì7‹±sÀ,´AȬ™°Yè¨Y3-fmÌ´š5yh3kcæˆY£8áoóš Õ7ËÄùlõKæÐûau|*WãIÿàñ®Z6gÔ(F_îÇÀ:LKÅMH¼Ÿ­¥‘ïÇûûáAœ­G¢ tÂü Ю£ÎáÏ̤ (üXÌLz7™Z’õô ‹¨8Ø$¯è×Q0‹ö s¼Ú*ZûÝPÞÚï²àhŸh!4ܢJ·XrÍÇgÐ\TQB…Yp;ÅC~RçXü+eÕÁ3ÜÁØõg)ê!6®ç[üó{ÂC·ÂÁ?”ЈÈF=°ÃyÒq{r)ðeH 2Ž5…ƒ~¨ðca5€Oó¤ãrm-¯ë *,ÿ¡Mló›ÐÐh ùò êİGx“%ôþ”( HT¿¡IJß'¨ým«c¿…´¨[ü°E¡‹&B­qc¨-n A²M^Ôn!‘=iÑ–¢'-bã$ñÁ¾;úÍÌ<‚ÈàúÿJ¼¬ëÜ)è‘ø ¤»Ý«(çY‰?D[´¢Öš-´Ö|háO-Úv!ôC,Üý£±n· tYàñ“#Ò¸5È ckˆŠÕÃ-Ìë*õìëj¼ £=ï"`aó±Ö¢ažÂaÀà8kÑpOáp¸›` ·ëT«_Û mÆÇøIÍk¸L˜fí¼=@6ñFXÝ̰òVÝ"Œ`ŠË£U„àÊ[Ý[Ñ kQ («‹áuV?¾ÕÀõÕl•¥Ö¢¡žÂ¡h¾Z‹o¹‹FxÂß¼åæK­ÅÜ;R+­ >Ð k¬ÝÑS-ua½Ð_V4ûßm…%æÏ §½m·òÖ°ÿ]ñ‘V3Þ×ï0d<W¥£[ä}Ö¢wóÞ5@ßoÐVR9U±ä„°FpHÉò|~Ðñ쉮¯¡ÙÀŠvÁ: X2DjÑø+:èÛé•Aœ ù8CL¯Èoig[`ÅÕnåçMsà Œó@–¬Ìç\tm•Þ±­ÈÏ[‘o@L~*òÔ]²*Ÿß³†ù}+¾oÛ–[²:Ÿ?$á’5ùü™5¤ÎÁ±”›rW¥=ÚÀíWŠ~0Þ“–Y›ÏËñ&P`¬‡fë>^!x ×å3 ÓƒÑoÚ ösüj͆ªIu–­ÎCýI팰iÓÒH›ž*ÌIÕ6зJiXbAig+¾áÆÂ|ÜgÀ·‚ãmEO(!ðØM»50Ë.Ò…\L·©ÛÓm¼ÎoÜŶø@Zb‹¤¥xëo’Éßc“1„Ck™ ­Ô^¢_Vã}7lâµx—ð×éq½¾Áød°™ìFüm#þ*+˜a›7"ƒar¯ß„€»Éº¦ÉnŒa³Ÿš°ÛkØœé.êpÈFs@#ÌaDÞC¥|Jȧmêrï´_¸ uÏPŽB1aá_´õæWlúåÅu›6kß°‰Y›Û´éñ®MSƒOlš¢}jÓí3dc/.'í?T—CçYÑúW®'c ÿ?úuâ5õ:Ñ‘¸ªÜç}©Wíý”õúíFõ£]>†ùƒ|¬æFt¾ž=àEÇÚ_ ˜©šÑ©ôa"Ÿw#Z‹ ½è,õ+ºJs#ºŠÑóáFtæF´#݈®G´C^t±ý&íF.ö ÛMU,çLÂÇvÈ‹>¶{ØIÍKçIÕkèiè.½×гäØ3ìeÀP&¡ÜÔPn2òäÙŽ4#Dóð˜¡^ùi+=f¼ÝK¸„ŸK¢°gŒ?cE?õÿ40±oÞO€òç,â?ß'°>¯äBC„½®(܆|n¤ƒ,Åá*p=%&|ÄÄdÍíïdXÒoý[6UâS¥¢ : ²À : —^ê,<ëtØ«¹-¢ÙKª /–øò„kÒŸâw‹kÑ)PÎ2Ç£äJw&ïk€¥¾ëcÛ’6R€mƒm“\ùè{·ÄW’cÒVì9¾ZÒ‚3¼ŒÉ盤ÈK<ïJ¯7ÅbÒïc±©±Üñ&l•¯æ/ëñïE;ûËýg”óze£œ·z_ú5s›WøËÝQ…ßü‚„fþ)(íBÐéóÞ#^á/¦h‚>”!úŒ¸ ÏDУ^ü¶ùóºRtXÏàój!èkîØ5fËj‘±å«¢µ[™Q8¼Ý£º‡ßÇ„³ôÀõŒþâ3\ñ3×7¸"¸ ŠCŒdP{ˆMù¸wˆ%À×õa@‡X$§ùÓ¢)µ …fÛh2³h l΄.y£Y¼­­­h¥æ³P–=ÓÍV=ǽøeòïˆù‹Ú蹨¸ËèA]7à®°¤ò &oÅk‹7JWYçš‘ÏÞkzŸ½7¨èØù¦è|,¼¿pÄ£õ}½ÿ?úRtË<‚pÒ‹„[†S^I1™ÿâönÈû ²>ðï ¿ÎÿOÝ<-’~Ë[LÃ*läkü÷¡H°ê5þI(\íáýÑ,Ð2™ÓJ ¨ÇÀ \ž!%÷uÊËÔõßXü"<Œ¯á–k È@p…¿ÿÞÖ³p[Oü舞Õ]ŽDAv+‘è9Ñ5Ñ5¨.ÃAD7 Ñ•tدÝŒDÏ눞@¢§€è*$zAGô¬Fô,N'a„ ¢‘è*¿'z‰^ô*@´¡>@¢XјðF¾ TÁÿjOÞ–|OáÒ(͆ŽBП&<&EÑ£°ë£Å>Zî¡\ì£ËÞ/2Yi_°ÇùüSöåâݹYÝ‚»sÛYìS©GñžÜ¬w‚{à©l€ügÅ{sß®eÁ½ð8p€’S¼/÷í²žÁ}ð8h€±gñþÜ·«Þ î‡ÇÁL_)>¹¹ÁðX>ÀüÕ⃹oÈ „ÇŠ–wŠå¾½,7x+X¿VÊ}ûtn0Cؾ^\0 CØ¿QÉíùÕ`ž† p|³8šÛó`ž†p~«øpnϯÃÓˆ)^Ü’ÛóëÁx9 õ/Š[s{~#Ø O£¸Þ-nË-2ú÷äú¯õ lÍÇßmôÛ@¿ôÛD¿×ûâïvºßA¿;éwý6ÓïnúÝC¿{éwýî§ßô{~Ñoˆ~Ãô¡ß(ý¦ßúm¥ß6ú=B¿Gé÷ý§ßùyÆ·‚møyöXHÈÊÏn_‚žý-½pcü·ôRícþ1¾8Ãwwü“°¿-78™¿\x㬵"ÖUÿî}øÇM0?¶å¢¢} ÿÿß^é••/ý¡L+`(:vû£¹Ë…­ÌGÀÓáÜ¥x`Z‡05Ž0•¸¿%Ž€Z á:!¬g„±9ޱ™¢]øwçÖ«®ý{sÕÈä| gYëé j#×·x w¹¶ã{0W„Ú‰yÍw1©ØÝðʨ{1{?$„ãÙà)¢fÂì0$ì‹gGài¿š}³Û¶Ñ ¯b”•ý¢" EÙPf¸ :zÝ`ôêð\6bòŠs‘¦E¹@Çêâåá-tÈ‚5¬œ³¢ã¹á¨oä{Ìw<—QÔ½ÛÌœ2ø]ºzçwºê‹ŒCW,ï ö#Â.U’Ð'Ð;NyÀJ•Æ~ ¾èÊÄx|1ŽÂ«õ=ð¡{õ›^jõ)Uj4Ù/¡R£Á >”1¼^…™£^œ„j—øX CðñR¸ç/ôSø©TQ]æð|lÍ]Fì`Ћ߷¹0ðý4¸íé¯Ë²ÍäéR4òv̼€ H,ë–½ü8ÉññBNÔÛQáÉo€Âä7‹Nå‹@6¿y#¸ÆCi¨æ8àÊŠ˜ŠnÔÛ‘ þ#Ф>œwzCúJOÁô¤Cu¨µïz1šh&ÿ«ª³ÿ£Ó×yøoñè6¡¹0Ý£ðJP÷ñ¾W„!…Œ‘š¶''€»ÁÖN «qBMˆü0¼PC^ˆ4y“‡/¦ãÙ äfDƒ&°‘'iÈ`¨„y‹„d{µø?õÍ¢Ój³ýÛÁµLÂVë€,VÑjOÞjûÂíkТŸ‡ÂÞÂfû‚v^õ‹ÅípÓ.ñ,}hV[*ÒÇ}¡À6dë9°eµeRú»*[ïò¿¦¶yø_¡\äÉò à AÞ(:óâEV·~«®ª6Ùy-ËÐŽÿŽÈÀã¿n rkíötûèwÁ¹ÌÐ{LÕ¥£2„À€õ3ÀÆëGXË¿Ã3ÅÂà á­ =4íÁ:Ug c½LJÿƒZ§?ðO¡N{<|%ÖQ.ÍéÝéè=“2Ó(sfÎ̽HwlzìK9‹´>\„^€ô^º‹ÀøìÈéO>n–£_½5-p6¿äºYD•uw¦xˆf–ÖÄŠÞóGL¾÷p™2žxI¡ÜØÛÊpj‚ŽÅ‡˜ ˲À>d±&C2:Sþ“rb´VO‡9€Ñ£³å’Fª0æN8¸ÏÃË%½ *cé´Q \ô«#‘ðñb9Š!:üãû!R|(ÄÁÓUÃá&\2¡/à‘¦k-U…£¢Ž;õÝj(°¹›Dó9ʩ׎×K| r²Ñ'ëз#úN@?ˆèStèû4ô}?€è=ü ¢OÕ¡ßFô»€~ѧQ÷åSÎcBŸPÎ %Þ!­wÝü¾Ùz†´yxL*jê™sR™G#p ,ΟÌ׎—ã‹Ãé2WHD§¨ÇC…QÃ-’ÿýÀÙ^¡@‹Ø=™©&O$ÕªI' ©U$Õ!ÝD×'š é.•ñ8yœnÈ/S“Ž'’VªI*9LZ…äff­Î”‡2ÑÛ"£`œgýŒÝ*0Bä-˜Ð›d0ä~ʶÃeçßJ;àÒ^Åäpå¨ì’ù69ä { 456ÈÙ}x“ŒV&·ðí²*ذ*Ú÷Sler[ã;å ˜]2ÆO-:—õËgóùHõëñ@ªÈß-GJ ù¾‹ù7:åÜ+Ãó%zFûdò µKÆøª;Ôøª‡äR%§›û³ôö8ì·¯¢“?9ŒXÀ—« ú7nkµwżn“‹¼aŸ—!ÔT<Î…P9u RÔ ¹(%ìK!( ’w ¡úÔ€r ¨³r‘;ìs¾›;P_tÿåX•öm\˜Þ©bÆË2¿,؃vçWäRžã×àÆw9ßs5_–w/“ñNv™ŒÛ.kñ£PáÅ5tæ6 ¹pÉÙ|~|ž CE@á•|ÏŠCja³ , UF-é™×¨ÿËñw¥ ù"Ô2u2(Œ2G+(¨4²a4c5 )‰ «„ý™¶j" û&2¸šßŸÌ®q FÌÉ…2QA…ò+M¡LVødì¦kù éó)`ÝZ)‚EzbÓØLªA zP«„Šj°†1ä^Ô›…RCc@ ÍW°Ê³¨Zm¢Z+“ªµRTk£¨Ö&…¯~iµÐ[ ¥ªi…‡ahoÔj¸)¹†[¾E_í¯¨!¾¦m º"‘oWkK¹;uu%²)QÃ=ø‚6éÃoSýŽÒûý{0’*ü¸Îa%Wóù ¨j|SRŠxï°÷f…cûÒYqƒaN ÙDá’¢î‚]Rø¨`›^]UÂ…Í}Ô#s3Ù™òÏ5x­Ø<„±Ç îFa,7½ìíìë“÷¦ä›*³²7[ù% TšJB}xÞŽ´—„ûð§N˜´ê3(o ð÷Ë›—¡yàÅ{]ÿ£<ð~¬û©YL­hfÌb²ò½¯Ñ=ëö}ý%”†×†ü7òýG<ôUP›‡ÿ#šA<´—&^Å­Ë8Ã,Ê@ïs”Óż<¡š—õ:ôyˆ¾ÐO"úâ Ðw3ÊZªá/¥}€V°Þ¸ožôà.H·à1îz@>¨ :¦·ž.xüO³óP/^M£F5m!¤Q”5r¶v΃Ÿ¡ÿü­:,òl¹ m–©fÐ,!ß%!˸™QР@×ç5tjþE5?p(]U ÓÕƒ_ñ£PÊi¬ëRjªïQÎi­ª§iDUÏAU/`UOãÞ ¦“D®°Ã£nÂ,ËMŠñ²h³±"ÌŒÉneG<ý`pâ!½0(&J|¢òÝ÷ú·àþqà,TÜ1óÃ*Ʀ £hn$cÜê³Xë„m±ø›A–ÑÇ4Ì×gr-€?‚i±æo‹BÝ©D^'…ñ5n©Ø.Œ{†t?Mò¬14òl0›“¼dSÌÁï³ÎzJµP¢+…Ÿ©)uÈà aY ¿ˆxFŸ³º&mFûfäœÇœ°R7FESÒì£C£}s^=“$õ.A“W?!…(’÷IÉ5·¨«pҔ­¼UÂÑùàk£´?ˆè|ð‘„XEt>øŽRÚ¢Dt>øŽQÚ¼D^âƒOz½<3þs,¦ÿƒ$~šÎ³e(ÅxETî–DçI[Ѱhg¡9ôÈž"ö.ïKá÷]ùFbüœò.“ÜÆ‰s ô$Ùz2káw@"¨&Í] TÑH¨ô€2(Eçm·aÀÀ#,ßÁfŒ"6ìø‹Á ƒéY1þ¬é™¦côã~fü>Ä æc¨ÔTjö=ñHôbºLMb˜”7‰Iôî™Ôd.5—*èU(6™ðK:÷\N_2¯‚éK1Î5/‹cðzÃd™*;UÆ JÓd¬ BÜ¢!n¯Å±IIt}ë°Sw"¹r ×Lä6¹Ÿ¹¹ bL;ˆgÜzV2¯z´ƒÔ=Lì×CÐ XF…M,cÉÔw©Œ­ŒhÙ]…¬CÁÓŠ ½¢Åž#2#vºúäUø #RÙœ!•o•)F•Ê#Z6ÅH_xE|1µÝ§Ñä¤$ÑÃ[2ŒvÅx\"ôµø‘ªy+(Z+áeW¡„—ÚŸËxYEÁ¯Þ&|΂˻¦°‘·›£F¾ ˆ‚aWæU¨ØXìf#$ÍÂFIÁ´-˜¶Í¨MB u¥F5ÔbfîÂgæþP ©cÙ ë(‚§©˜øä{ŒáR+ êå¢É#ðpÞ¦î2ó½Æp´R"¶¥êaþ}ÆH©‚IlKûð惖ãaJ寣Æðǰ|ûŽøˆb(³¶y‹1òq?I3~2Ë:›¯]mÐ#Èh‹±ÉVj+5{N‚¾ˆ›,bòl†‡ÔE[3ŒŠbüµñ=­‹î‰–ÅËó*&=1ÒñÎDW=DÊOŒ¡ˆï!HTï0FéEÙS„Êb=Hžq“r›Žþ“J‚‰èãéOÅÏ©f¼[&™ ˆ©¦xÓLâc¾éƒô&¤ß@"öK!#ýµ‚þZ_oÒó½‰n2©ƒ‚vŠ Úë£b3Ân¥Ò* ´¶Vc†Ñ¦cb^8Åe÷³R‰gD‰xYÄ È"^b ‹WàZVÍŒWá:°š™®ÓçEæ&~ÞÔI/`©—LBe^1EPö®š@äMüº aJ ̰¸~L’-hi7ñvô>5ˆ7•ZéHãS~ÄDFÀC(¬ÝT8ºç± úÄTjÉbµXÎ I‡Ù»÷¼aJÌ2¤ ]TfÖã 2cC4‘úsj‡*:dúäF›ùh3*°Š>ÆŽ[ÁxŽ ~PèÛuè“4ô)f:fKèSôÂ8ú4‘°ˆÐwДñ%BŸMè«?2Ì6󹿢ߑ]¼5;LAƒÇcìx>‹ÊëEõ„PÞ×°ÜÌ—˜¼Æ*æKÍY†>|¹Y%PV3õ s˜/F÷Õ^Þ¥£¶Ž¨mù…a³™oÐQÛHÔ6›U3¨my!µæ Ù¬Ÿ ™ÚaVÕœ‰Äj‡™Ä / Ô$ü©Ö+ï¡O®”½fúÜHè¨6¾ÇœKi¯-o×5ƒÙ¸ßŒGv¬Ô¨ª&~›dCÄ_@”šÔQ@&þAs):¯BM ä¢žµ ø¡‘ú!aÔ Úf¦÷! 5®wQõí\À1Q@MçÂqAAPoê§H¤vS§ÎípÚ!»EØ×@àÍ8fi„ÜDìv3™5Yõý)Ç !8BÜ3“=FQ˜…5âÆ¥øCê˜ï/g³þ-ôEñc3Ù¢´Ô¡Á¢!÷T…íá»™-Á3£Á²ֲбñ9O¸³ÍGІ[Ô5Ì‹XŽÄó£{Ib~D(ã,j…q^˜Ç=ÄõDKw°-b¤~Ò<ŦÀÜ ¬€5^‚ÑÏ3$°|*ECͶ¨¦Ï jf˜más-:3ïïEPbVoá %-Ä’ê-š%”•°„–X"Ȧ+*o¹øäÔ’hET“h9YeA+p?­}„ ÞlQUðf Iîf ß–(¹‘š,ÔÚZ·w­£š³¹Ñ&Oêa¬ý †K“¨ýª}?#ª2*ö€(/ ‡ñzø€…‡,:w6 ÈJ«… ]c›…G\F.[-Âp½Øf60ˆõ•Y<`¥;zwÔ‚“¹q©Êø1•qÅS‡VçÇ-4Û`z?E-w0C‚Éñ7T•Ë5Ô4Ôâ2±Ï.[øU}w~Oå[j·ð ~o"¿í*¿mœëxLðŽÔF¡Ü»Tî¡ ,Ü—ˆ6|¢uÙÑvODÛ=m‡Ð"Ê3 n):â¡éª{Þº‘—YÅ\5Ð*4­Q[ChOá0¨€ôSñí‘Jk×í‘!VÝö-؆YµÝ°¶£1Š±Î‰í~bÖ°ª\O¢5 à pàz’Ð}ÊT+~îÊõ =·µVZ÷#ǸÀë°¬0•õŸTÖ|«PÊ¢sæ‹ç[ùB«j¬¦¨v Toå‹E`Ìh¶ñ%T^”Š[a; ©ømÁJk¨G?žúñsÂ’³‹Ñ¢ðÕÈC„x,ºic­|³ÆDú[­|[œ‰ì8 :&vè™Ø©1јÌD³U¨°=ÈL”´Nµ`&¬2ƒ[º{Š Q«ØÊ9l¥­œ+Z‹^Ï{–¸-ü°5±™ÓbÅÍœ¿Žoæ´ÕjMÞÄ9b¥=r­sÔêB³ò¸ßÙßÊgH®ÅJû2hÁž²’gNR?çÅ2áŽUݽcå÷ðxýqë8C=f*뛫«Æ_(³AÂ0Hhs}*1a8$ ±¹,˜0FBÂ(›ë!Ò‹ U0Îæº„ “0¡&Û\-˜0FCÂL›kîèlÃéÇLû\+dõßë˜ëÓ6uÊqéDi÷ûj›:ÿiå6L{ÐWÛÔÁÍŸá”¶À§mêàæÏhJ{ÜWÛÔÁÍŸJ{¨¦Éî›FiÔ4S|óÇL›?f‹ôúßÅbæsÏcwŸÇ”XÌ‹uÅþ"ë‹AŸm eC3ò9xî·…&é¯R[/ÒŽ/²ñÅPñÀí¾áÀ¾ÐÓ…CÁb^b[…K¯5ÃdUŒ E'­²‰ð;$AFÍÜ93˜VÁÊ®¼š1¼VT3i¯±¡È\‹žj&¯³ñu6ÄvmÕÄHÙ`ãl4¢UŽŒ|› ŒÖÀH»gõF[©±G?3<Žén©¥d¤ßcÑ«¥í±9‚8€†€¡¾ÓÆwÙ`ÁoÌÈ­4ñfA…ëàÒ$óÝø8É«éß ¢È: ³ä×ì\–ýZ:nãÇláÀݾ0´ŽÛ°@ÿŸ´…"…£@ÏÚ¢‘´EÏÙ¢mxB< Ãð0¸Áp„,’7ˆúuúu¿‰< n!ÔQÚd‰ˆAÿÀ†ƒ¾=_ìñN"G€ôÀÆC]yÒ'`û ƒîë°ñ`‡çûÛó‡ jÃ7ivšÉÔw;ŸõOÿ%ÂC5b6³iûÙ˜{'ŸAEÊìº]qÔƒìPƒA^æú"Ža¨´óJ{b œ˜âCì8ûv§¬Ä‡Ù{ój»˜¤FÛ…HޱãÙWå÷ÄlbW[`’O±«¶%í’MSQ§™Z{’êu*ÅYHñx†lQŒc…Ï·ë…¼U}6ßÞΪ¡}ðŠâ½ÐÎÚQ¼£qñ®·óz;‰÷¢¸x/µó¥öNâ½Ò.dÍâ½ÚŽâm‚Çqý̸щâm¶˜\%øM…Ôl,’â%é>ÈZoW¥qƒJ`»¬Ø.#¾2 5K¼Þ¬r¡ÆsÚbw‘UgoRøb{Bš}  í$ÍÙp»ÛæDƒÖvSÓìÑZ{ÀÌ“:alÑ2[ì¼Í® ã„:¥#qJƒ:eçg1ó4Í{DÛßÓrïÙù»˜JQ??E‚c€à3»Ë…:~ÆAÂ`‡+†C1a<$ s¸naBµCèúñ˜QB×OÆ„‰0Å‘ÐõìB×?±wÕõeŽ®º¾Ò¡×ëB×tèõºÐõ£z.týX‡~žº~¢C¯ÿ_¦ëŸ>9c±7c±¯Ò_B×Ïp]?ßÙ¡"^Íu¨-:×Á8ÄÖ=¾ÒXèèÍëIÃb, ‹Å1,– ³zÝ¿Òñ2Ý¿Ò!t?^qp¬vðÕŽdÝ¿ÖÁ×::éþõ¾ÞÑiplu„Ig“îopÝ_iÒt¥)®û›TÈ„îßáà;¨ûw:hØàÀw9hÀÏ#˜x³£“îß㺿ÒT‡_íw¼H÷p¨£m­£³î_íˆëþ06Ù9ÒýbIuDkú#Ð0KÍNÁeù¯¥Ó~\×' #N9Ô¹à´C Î:`.˜€:ߡΗ8\q€& éW±´óÔÑG¥µk¥µ;øý»@ÿ¾C]g“f|èšñät$‹À§ª<Ã.è5ã gWÍ8È)4#^±ó˼ܙ¬+¼ÒÙI3sòaÎN?Ê©v)v~µS(¶J“¦Ø ó5Í8F…ÔiÆGªfçTûj¼J )®›„fœà$;@ÕŒIšq’“4ãT'hÆ!ÎdÍXîŒkÆN<Ê®S~sÚ0sòùNU¿,@¨K¤ü¾IPË4¨eN¾Ò™è£UÎÞ|SôÊZ§hþuˆ|9#òJ†Ñd4‰­ˆNuuÀ)–ÍN±lvŠe3\ÚŠ•Nr†"`‚GßSxØ*5'yy _Íe£©;;LÄFCgÄ1Й‡¼ÕYt¨O$ì;Ôwô¯á‘å/Ô—ü9EwÕC–¿#¨¾EÞí,ºG‰¯ÃßGŸ¼ñFðˆ‡26aq×3d–’š¡†ãz»øTnNóOrŽš?”‚§ðÈ÷ ;KuÍ`·ÇV3þÙ—Fäúl(+…bÕ~ãr…|u^CÈ7 ãÏz¯áC%;TXë5üqq°_—ˆ%ÇǾ ]žê‚Q#b†W‹1à @·20²¸.FD;%8§Gèÿ)ŒÿÀ30BÙë”øÕÐ;ükZàˆ¯‹ÀßÀ¾ðý¯Bïý0²¶ˆbÃü»þ U2£Üæ<ø ô+™Ù'Ž·ˆ¸µ? Æ[⾉F©.<½ ñçÚvt¨MAã?ðûšð"Ýü“.1ã¡ÚÁ‡f*ªŠzhÖŠºKEý=••—e(ËÒUIñ¾Q)S!Ù%30ô÷lè0V² =c~AôÙ-¢>gÌ¡À–x}îe¡Ÿu-ÄLõ1½8ØxÈ7%dþ,ÀŸE(+X´¾L¤tjªK/B¥ÿR·÷s½âE< )ÉÔÅå$z– ;p<Meø^^FœzÖ?”¬2áýÙÛ5îõO’œŸLš‚¤F%HMI"5¥+©3æ$RU RS‘Tu‚ÔÔ$RS»’:ŸLjt‚Ô4$5&AjZ©i]IM&56Aj:’— 5=‰Ôô®¤š“Ûj|‚Ô$5!AjC© ]IM)L"U“ ¶XJo™û‚ÏùqÊGý“ÜÍÏ’PÔð˃ÌÄÇ­“2ñ“O×íq „_£äx|CXM¦ŒTÊ(Œ~0%c=¦dâ— =)ýWêá¹_ñ_cnØ-ƒ•óϽù¿âTîå¿ îðø¿áç™âËRÄŠÝŠô¦½oRN§Ã  N8×| žpÜêÅïd‰*9˜®#»@ Th@²3td—kd—Ó'Ö È®²èK ØàåkU²ëìLÙýHö `5"ÙZÙÃÙÃŒ·€ Ûd"ÙF/?¦’=Ždëtd9’½XMHv–Žì#ì#ÆŸ€êz È>C²M^þ\%C²³udÇãQÇ)ØŽdçèÈNÓN:N“ø dgJ½Ñƒ}8¸ÝËgI‚ìl,¼¿ÊE/8R¤ÖªµXë½R©è(ô¾?}a¸OŠàÀÂÜýRÔ¿ºW©¥Ôˆþà¡]ðtIL"µ•‡¥(ÕbËE¤R‹FÑ((F¥¨ ØÆ[¥0àFÐixÉ"o£Ç(=Î7 ÷ˆó2-n“¹ÕJ2pdàK¸DŽš$ÕQ“Db!%±/’X(—ಭÐxEH‡éš3Òa¹ ×ÉÕÌzWH‰í¾;žKRÍx2uj5s>ë´j–Ò×éÕ,õ)\gT3×3¸Ž ¦Åà2&˜^&óÓ:j:b•øY!]müœ%é:ÒuQ'] +—tâBqýòu#Y¾Ìx––ä‹¿B¾,ø%ÕKåËJŸX½XTú÷³ñûR©M`v2; ÏK*ÓÁbnl<’üÕŸGˆÀƒ|ßÉﳓ?‘Ðùy ï k*JWF×4Ã³Ï Þ:l£ºOú¥ó29‚T‡­ ¯ñAr©9ÝÊ ¼\.µjBeW#2lñêÇQ¥\jÏ2¤à&çPƒ€„¦—ZëJMu¥vŒ®že@iÅŠ ÇüH©S±2#e€´× à,iv(pX©EÆ«äD'ѹûÑriJ©•†dÑž€WŸ€)öZHÂzN–ãPj­ §àМ&–4»Ô ?ˆÅ§É¥¯•ZD©M(i|:&90‰Ï)µÔ ©®†}£Ëñ†˜#}FÍ“©5ŸO X 6K¼£X¥z¹ÔEÍF 5xk©"Kâí°åûî¿ÂËäÒTbRPBV—ËÀ%q‹¼òriÀ8jEc¥¹zÚ9)^åµH/­Ô‚Ð@†(l”ã2"Ôz›ä¶žE´^?ÑKÏÁWxt[j/u^ë#Ñp›¼XÛT.x“Š7…ÓÞ“øN™F ¢5Ó-ô¢…ÐvÓ#B»4´´8Ú9ʪ²…j °ì'ÿˆR3#Bi:ô™…ód =© ó3Ñ©Ï_’z»Dš—3Ù_‘ÕIêª,&©kro~C“ƒ¥›pE÷J·Ä‚Lô¸3ˆ‡tþüóè-ÅðXæå,C‹ëÚ½þ Ö!ó$ÆoEŒ?•#5Â3@$ÐÑ«}¸ñg2}7“#þZE'Ë”P$¸ÉëÂ#_ƒð~³(7±0 ÔËžZܪÄ¡hìz‡˜y«è!™‹ÍÖwüŸ¿þ­À^ÊÄ­ÞE™øñ¤—\ú}Î0ŸÎÍiøyö¬ä4nÑÕƒ]‘’š~»ò3|:Z+3)ÐygZLY.ÌjÁ¬6°Sö Å±,Ž”Ô·1ãŒfÇœA7!øU±—_`E{Í…{Íè,=g*rJêD†àÉÂXù7† ÕgV36PâƒAaîõ’k‡rPã•R¨[p——m_1QŸÝÞ4ürx4ÆÛÙíåã$ÿ£|<ú8_æ“0J,i¥N‘üëÌä)r*ÞaØ¡'ù¡À!/~êÂÏu§C…‡¼ l$ül&Ó ~Šü5W?1 i³óoYƒDöÂ^/‰Çv`o—*jöú›½ºïeg‡#yÍ^#²»G e#{ãlì³qà%lÒØ‘fjÕ\dã8±1é? ç$˜âB½¦§*Z`’#N2ðX*,oxêq›À~(…{¬:~:ò%ü{ŽÜQ4!QÉYPI¨¢Œ‹ü¦ È vy…Û*YtV¹Œ=Rø4Ÿñ tJ T)GL݂ЃCq­$a2…ÞñŸÆmÒU(Äξ ÄÀä(Vôì•kž309ýÿL ÿ?úý‚gš„$PÒWg~†ÙÂ!V§àYã°ÁJñ™Ü,–e˜<“ Ëi¨R|RzÌ ž…„ äQJñ9‘æÏAJÍe¬R|Sä¹Áó2q€q¢R|S”¹Á 2i€išR|SŒsƒ!eòsR| SLsƒ— eÊË<¥ø2¦˜ç/CÊÔÖz¥ø ¦Xæ¯@Ê´¶åJñUL±Î ^…”éì›1ÔÐG£‚q¿œgÁ)g•⛹9гs:àÿê÷ºç<†ëøÿÏà+;ç)\ïÃÿèÏdç<)ÎþÀQrGûšL…BgÍ«þ›ùnÅ=7 ß°ìUНçv/¹žË÷+þ†îçù9 ê€â‹å3rQzH)¾–[T jWR|eÌWÉXɵ\~Xñ_Ãþ]›‰n ºQA·¡ º©7…>0Ozù]•Ì=Ôfë2Ñ^Ê€x¼5¨…6…a/Y²­t8ãíÓÎ6|ÆpÌÄAÊIo``7…1ŒÑ`èNC ?~Òïp~DÏiŽ†Ï™øAô+øÎnÃ%g¼ü²)äoì‹ ê÷áWLþ3¹Ý}M}e`”œ—Ü ¼pÉÀ~ oÐq\f2Ç9.§ÛÀY•ã¡"^p<9fîÊñFÇ£5Á£Í|¬9Îñx³àø¬Ý#ÇÌÇ5fÿÙdާ˜ǃ ø4tä»IÇñR•ãå ŽW ŽÏ©¯5óµ‚ãÁÈñºp¼YÇñVã­fÞà¸Iåøœ—oos¼Ãì?—Ìñn•ãÁ|/r¼%ýH¿MœBÏÃgìžìž÷öáçñP·Á°Uý¡' Ÿè ýT@oÓAÁãÂã,qèñt¸Ð5‚nÐA×#ô’ôR}  — èF]Ko·ˆ–Þ™@h—Õ–Þgáû,ÔÒåØÒû-ZKgÇ[ºI×ÒQ‹ÚÒQ o±Ä[ºÍ"Zú²—±PK±h-}Ôâ?ŸÜÒ'-¢¥Ë øiò¤Kõû2pë÷ ÁîCÁî¨ßc‹¿¢ PY€‡ýuueu¬¶Æ‘ÆÐmàªZÇ Vtˆ‹u‚u¬±v­ãNªc9#ŠÓ­j%§[ùLk¼’uVQÉ«^>ËJ•œeÕ*9Û꿘\ÉùVQÉ!|ÜžœÕÓ-ÑX ·‡E꺥ԥx®rUïçÄLƒZ½&€9í¥ÓøxPó4È®Dw‹_Sk¼ßÊ÷‹ÅxA›©Æ¿¡2k>lå­¢4X1hº×…®Ž%Úá„Ú×¼ü¤h‡“ñv8eõ_In‡sj; -à°n»©³³¨ÜûP.9¯UkñHÔâ:Ôí‰%È#àj›hˆ1¶8ü8º ÜPk=ÑÆ'Ú¨Öð֓lTk w°üÕ<1öê¤y¦M­÷Lt¯àl›¨à /Ÿc£ αiœkó_H®àB›¨à°^çãöÏ}…bRynHðÜ$x>l<ïÂc…Äópä¹9Îs7áu"\†ëöë˜>¨1}ÐÆC ¦#*Ó‡-<*˜ŽÆ™>ló_JfúˆÊôð~ ™> cúºÊôÍÓí‚é›jCßµñ»‚éÈô½3}PÇt‡Æt‡?K0S™¾éÅ“}È4ðL´û¯&3]aL(àCð|×!(M¶ƒ(MµÇ9žF·[ J3ìÝЫN”VÚE W'à× øç.QÃv¾‘J ŒÄn²k5ÌbB”06g˜*ø¯D²É®V°ÉÎwØãÜe|îâÍ¢‚Íñ î¶û/'Wp¿ZÁ‘ü=®3Bv¡3®›y«!»¦;{«}Êî+QèU?O"öêRÅó ü¢]5ê/ÛùeQã§_lú+°ìoÚý\Âgðà¿e‡$3è»ÛöpÎÒjVۇߵÓëL³âpvÕÇt¬ñ÷mílÁÛÛÙüÿ`í¼ÃŽ{e!³ÄŸÙ#X–ÛªàáÎj&pðïŸÆóB§´"áeJœÎ£ Bg"q HœÁUø\$rhèÕ‰ƒã‰£ ü=)­’ÒrÚóµ„!"á¬;Ê2(e„ƒ\±r¨ãºú3è{¨š ÕDX£؃£Qì¾1mP¡7‡j_i¸5 ÜAh3M$܉w’C³—wªC4 wzwdŠÎ Â!pg:4±ÜYÕJÒpç$p å3—pç ÜyÍêÜ…uÞ×pë¸å8—/&ÜÅw‰C›Çw¹CÕ³îÊî°Ôœ«w•À]íд&à®s¨s±†»!;¤'Á„»QànrhS+ànu¨³š†ÛÀZ€SR#á6 Ü&‡6îN‡jµk¸Í Üh‰ï&ÜÝwC³Âw¿CUwîÁîˆÔ_‡÷À 94ݸ‡îÄ]\£ÆÊl‰cE"yühs„rýÏö ã=gÄ/øQ ,§òü˜Fè9xÇËO`6 ×!øjpã»b4œw„¢¸Ò¹è UòtÕA·ª¦C…r%‘pÕ‹MÝAV ߤ[ ÄðV"A߆„£Â&¹ã>ô‚ ’""é>$=ñÒ¡ÀÀq‘ô’y ®^XÅP ­^7îN™ª>‰gГ¢z”PX3EšZn•(÷6š¨XîQ/~ÍÆg úØìsœ¢sæ;1×_ˇ~ ŒÄÄC8^$Ö‹DQê‘¶L¤A©AÈjDâòxâ~H+X  B@V¢¢ÉW;ñVmòrƒ!¦×"LÄëÆí¤õ v78Iphwr‚÷ºñ°- ­N$Þ€G[21ÒB¥0ÞÃÚAȰ“Gá*`šGzw/­"ƒ†ägÐóK›S gJ,|àeü¨+pQ~a«Ì_g¨¿“ÎNc}ÅB~Z3e˜G[ˆŸóNÜ©•ÅäxÞI“ãy'¿èÄÉ1 “ãe§˜?ÔÉñ¶“ßÅ¡»°ÛÎ €Îï:A¿¨¦L<¾}%ò}ÏU J4æè¡Î& ªPg½¸"¬‡ºœ€z¢B‚ òTu.õL…:çŵrLu>U–Uš¸Î”¢ƒº€¬BÝð¢ý\¡‡º˜€ªT¡`DÀrj¨êJj˜ uÍ‹‹z¨3 ¨‘*Ô/î¦Té¡®& ªU¨›^´6Ç©O½%c øxõ麷dl¯I¡® ƒdLJ wJJ'Ó%cjJ'Ó§¥t2m0qzJ'Óg¤$›6ä˜0EgÚ`¬½i)®JPFsRŠv^J²¢E˜R€Y’P´‹R’-Âü5À,NI(Ú¥)ÉŠa> 0ËSŠveJ²¢E˜¨ R„¢Ew¶k? Š@aT)Bƒâ+¤)É*«º)¥“ DÄI¨$R„ DÕ»-¥“¾C̆”NúS’õ¦5¥tÒw˜¸=¥“¾Ãrñ5áΡï0XsJ²¾CÄ=)øý™îßë¸0ÝC)¡÷·› ¼%…VݨåÚRBÙÁÓ^~$%„Ëü Ø4Ç÷­v2 ÷&â¶ É äq8ªx†e©q¥50¿nÊÑH *ÕäÍÿa¨Jå£ .Ljo ×Qš€¼65.äup"ÕìwB, ñýGjo^ÕjÀ‡P`LF -‡–¤b뉹p)Ý«»W8!.K$À@ƒ‰puª¶BW@/_Ö$¡l³¸0&øÚTuwMý@Vä¿…³Ié¼W­Ò˜@|#Öè$ÕH´Í6¬Pc*Î;З¼¾Ç^VrÅÍ›ðT¦lr8ï«“MªE.æœ!ŒµÂ5<„Imp aò¸^ùŽr,•NÅ7ˆ¾=½Ø'-¼•Þý¹Ù¾}XVæœß·ò6JËúŽHúआñ¦Ÿ’Ãø±ÔŠ~F~<5’e eÞ‰ÔHNt«…ÄS©¥ÆþÚè¶%ô¾ç4¤å¢µU È.tupÒ£ñ$~>µTɲ9Ph/¨¥Š€ÆB.A<#ä•TŠ#{Z×N·°x*NáÐNãítÛéL¦ÑèH]"ÚéIªp—%&Â5ÕÌð4•?M¥°°þºÞñø;¡€Ķðç©þ¹é¿ÆùÁÕÎÖW3†× ø ˆ ’6gc5 Ôäì)‚_tšUî”ÐR›(£T‰|ŸY”,fÃì9ÄÕ`[ø06EèÿÃ=Þù³aoX^å ÷aßË&³§?zö#ÃY,½ˆý).Õ¦˜ââÓ\q›wºK˜U3]q›·Ö%lÞY®¢ÆžÂâlŒ2rލ}¨-Ш-pñE jõ*µ% Ô¥ˆzžPÿ“PWi¨«\|K{Ë·.Ad½Jd£+nsor SiK‚Ë­*— .Ôâ4á5Òm'µÙ6¾3ÁÃ.äá‚®1öi<ìsñ‰’ª%‡%‡Õ’£ j‡‘ÚE¢ö/Dí¨Fí¨‹wÑB-â“.½E|Ê¥·ˆÏºh‰‚`ç]zãü‚Koœ_N”zK½”™w–‰Š-O™Ýö%ü訆áGGÀEy¯LÃ]´shŽmÑ™Öζ€èÕÀuk5“¦ñaiþ &ßÄñ‰Íð´Þ|dZÈ×!Ü·U¥…ºfð1iZÿÔÅk^tX”ʹþc¼ÊM9³óøt¸«4åLø€Ï€»‘öœg?æ3án’)§ãǼîjL9¡¯ò:¸[eÊyü> îVšr†ý Ÿ wsLX‚ƒ2øÜ4˜3`¢˜ŸæŸcJûŸ8‰§ùËM五¼Ý6T3eq_œVTà ]˜R¥ù 2(£ÔòÈc%“ øÒ4x(œéc’y%eFÈwü=Ê_…„CJt]¾qõïðvúüo ÉîæŸ®>Î7ò-iEMöH I޶ËÝ ›ì2oJ ù›ä’I&¾î¶Ë%5&¾#­¨Ñ {a#@ìNSwìÒ{á«@*XM L.(™RÀ÷%¥M-(™VÀ÷kXÙ%“ øí ÔÿÔJ ‘ Áþ <éíŸÉÓÁ¦"Ö.-ZòŒH.™YÀÛÒÀ‚ƒv<š†aÞ ·1Ìžä:ž†N;ÜÝQ4¡Œ6(nŒŸN#Žò3tÛ½ðÚg˜k6n{‚¿¶À1ݧ…ŠfZðC°¼™)88ƒ_hºøX—Ç/ÃcEFv–¡;ðeä×H¼¶÷1¨¾¤+»×uÉ'É7tÉçÉíñd ýO¾M%Ö}ËàÂuÏ] ôa2]E™Î«½;¢NG>ÒÑYôXº-Ü”gàãÒãÜ}¿ KdžÓuE¢'$\D NNOjÁ©ÈÅUZNPˆ:ºt>7=¨+Á¥ÓÁVIáø žòòÅéb-Ã+Œáåé]m¹ÿ‹²7*9òëU½ºï⨒è¶q· ¸×=žíï|ã1x!ÓS-{ÆöôŒ?É¥b\«mÿöû¦ÝììFˆû”@ îFÄ%@Ü÷)÷Q’¸ïûLNqkãù^U©Áß7ûû²^¾ÌÈÈÈÌÈÈx«o ²×Þ d¯ ¼1@È^xc€½A’à&I H]›tè¤þnÏP°h—csÈm·K{šFx»ÝÚÓü0V\“öTƪۣ=-—¬¶ˆ½ÚÓÂpÉ*‹8ÐÖÏ é’Ž_ÍÐtT¸]vD/ ½Á¢;Ú!oV+/à‡Ea¸AÍôÕŒãòÅâ0ó& ÿ =G"2-\¸$lôážá©7ÞÔ‡âbb1ûk½ VK¢òÕ€ôèD ñV@g¾·z¸º;=\Ý]L›!…¦GOžõÙñ0 ° Âß‘xˆ³ô܆ò·¸ü;\þ¥^þe@¼¦BÁÛQèvV¡a´BÃ:‰â<Ž#;ÁÔWW_¹<ôBã: )º%—TE'Ê7±&v’XTwÊÞ¢§Ò]†ôCš¥CšÕI|Õ)Ž­öÅRÚç è½ ~Œ¢óõ¢ó;‰°abÃå>D…¨Ì¥´.Be‘Uy™^yY'ÑÐ {/—¾Ñ•+¯Ð*Ë–W¢ò}®,irP¯|°“8܉FobPA¡\èÏäGf½Pª“hF¡Š h‘´€\ÒFœÀ«Ê 8…ú³êŸ×ëŸï$.v¢•Lõ/QýÊ ×¿¢Ñó*^Qýë¨ÿˆë¿/OWzý;Ä=ôçˆÁÇ#²³:ôX/û¸“h@êÐSzÂg(\6ºƒË(m!=8"j=1- ÿÏnW>û3wŒ&¹&.= !2ÜÿúF|Ž{Ê¥ÿP~T|·OïÇ¿þ•Rr·Ï=eâŸ\|O˸‡ë7ÏB×ãþ>ö@,ìjø‚Ÿ¾äpƒŠ~Y›[úðcñÿ  µeµõäÿNâþâ±™A×Ùn0Dîö)3cŠ"ïWJÎ/¸üw¸|Úþ"SãÞ›5^†±í—\c"_å[ø/†‰Ê=e? _SQ¥ÄŸn3*bŠR´67‘¿6W)[›Û"ª:pO–LŠ©ø9#X2ƒ6üœ,™”áË^…ô l€ÿa&Ö×r㇑eüÿ³eO r|2{e·ÒÎF6F•Ü||'þaÑ2À4P_ñÿ³”ÙA*4$1/ø£ú¹ÃG”Sž×ðŽø‡ÿø¹’(ˆ¡”åõv¹§L¦>º€Úþ(²<œˆ5à†Ã0~kCq™1<Çbòú›²`üÿû ™À¢£ÔG¿Uè\õ;“LÌñ_J+¬ø[iÅ]§‰üw’õí†Ï¿UâùõAC™ùwÊo•_!5RÀEDŸîß7~«M*èÝúûüI àÿVùÜüAKïÿ@x%»÷U¾c3RÑxŸ¡9}†åÐK‚ó¹±°ªÀ¬µ6¹@þøÚclr ç¯+%z^QuDzúc¬e\¶º@£@<QÖ¶A‡¨÷y†ßÿNõ½g0Ø‹¦hˆ¨„dþ´¥pzÿ[廿Sñ%`´½½¿Á¼2lP̆UaƒÑlX6˜L†ÕaƒÚÕ°&l0› #rp/ÆÙ²miœ=/¨gÏèÌÁõÂ,ãìQ9ò^+ê  ¥ð×ñز`lÆy ¿ú¥úä—âïP"Q²?$>£úc¸¾— ý7ªÿÏ$ðaX—c¢ÊÆùÿ¢) þEü+ÞJ˨ë/þ#ž(ARD:H ÂíŒËɼœrc°FÇ)ñO[6…ZŒÌUbs-cgÞÈ1ˆJ¬¨ñŒUˆkW£ötY`m¿3Øâ.ÇBèýˆ ÌQ4ö8‡ë£ÿw<#x¡þ¤ÉP 3ÒÛ"@©` å1”e:”eˆÑZ´6Yà‹­ó® #t%,órT*ü³,ÛJ§ŒU奴m%Û·Æó¥=eïÝ¿E%Qkimwÿ&[Ôm'2àÞYV–0›€R¥)ÒòÁÏã±)iCÈI\©U4`¡lP¶ëìÝô›·X/“­7ý†i©ªÊ± žñ±0›yšØqv\éÞ½÷á ¥÷Öß ˜V`.i£üd6¬ÁD™B<Ããý|Î6¬ ¾a øàçM3 jjjTmPµo‚Úý› ¦e@ͨéPs;€šû&¨¦Ž f€ûº?Žgññ?nŸ¸· þöïÙ7uç™|63çÆž•£ªfKäþ*;’'ß­ßF*×ɳãhEŒV"ßÄß5ý±uáï¿379 >DûË_6 Î_þ†°!ÿt_Ó—­´ÊRÉePˆ¦ø IWHfç˜ìfËN…[ªÐ[ª-!ÙYhDr´B1!ÝÝCErì7f$µ¿¶ y™cŒXž`=ÐFë1™ý£XêcÝOî ™qìãz–-g)Q•ʱr´FA`wBÜa‘$j•¢û}Éüû}Œ6_‰ZXjªSQ³´˜àЫ éÙªYPð‚ý*ÇN]¹*»2–ï Î`kƒ–‚äØ0ň4N}Aš¨PT¤5]Íã)iS,(IV(Ö ›oƒ×Áš<ã<øØœ`KE-Ò–a UTØ¢ÖüUà7Ñ–ˆÚVHK§<çOý©¡&YÄ“lQK¨bXì‚w²-¯½@LA%HÕ¶¢‡}Ø$Ì7Ô¨¥Šm7ö1ˆiÚ;¼±°Ë7ØÎÐ_¼5æä-fËxÙ_¸\íNÈ™¥aÇ<Ç”D’ªPŒHoYMupÅšˆÕ›àÒÿ‡l«Ñ¦¨‹àˆ•.{g‹m¬Íµ²-]ìE?é ·Þ–,€/ÖTÍ-bæL”ÝyFÕeþÕíí¢]3jr ¾ÇXm  Å?6±EÅV¥ø®=ÏPz×.¶±™hŽ´çD‰«àä׉'¯À›#í9ñæ®n^q—I©€´ç¼¯ôan±"()ñÂÖ Aë/»`—eݰ°¥Ú°Ë³ÀÔÁ4‰Ã\@‚=B`ã»!(Ø$À6d½°÷©ÖF€]Á`ûð›6l¬œP@‚}N`_ìÆ x ['¾§ÖŽ_|Ú/ÃÍþ•YM̆­ÁÛ6£‰UYMÔ©ZuªXÈd‹Ôþb‰Š`’A±TÕ›X¦êM,G«³š8€&„­hbMVI½‰¤*ŽqÙD35ÑŠ&¶ʼnt'ÓMœBkP˜=â¸YßlOTâÜñض snè ÚT<ÜSf|hx®Šçjä˜%_¨'‘më 󈬱+7kè•›Å03ÀHô†›û‹‘fØÃÅ(³»Ñf˜Ldõzßÿ¨Övôzƒý~³\»Ü,V˜(ѳX˜Ûƒbµs `nÌ‚Ì$ÁÜ ˜›²Þ¼y@oñfsÖ›‰\¤·Äc»ðfKÌå$Ѧë6Ó-lD¬ÔXÄLK%¹›³,ýÅWÂvE… òZD­%É_1æZ’¬4šË­YíD{‡©½Ýho[‚wkÛAÊ‚QúûVyUÞœè¸E4£ÍݲÍjó8WÞ"N ñÝAqÚ’ÄNݜ޺ÏXZoÝç,L/lÝÒúâh†È—-)FøŠ%Å_ÂÛsLD†ÿÊX=a2£#ãD ãõ‹xj‘õrÇY“õ¬}F¾^;ƒâ¥%ž,m ŠWyžH¥Ï¯ÑÈîûÿÍŒ¶fu}´õžÒ‚o(V1ÖJ§¦—F1Î%Uêóxk2²ãG±#}5íüTѧ>Àƒ°PA[½Uë\¥Uvn¢Uv® &;y¯ëÂí"d¬Nº—.Š™xÛÈ3`¿­±jÖk¬ [©³Š¹ÖÈA;¢í"^@¢ß9»R€hO-æÿ½‚)°À «Iì² öne§Ù´¯¶”ñØò Œx·ÐÚ½@,¶"#‘ß‹(~»rT—Å:Dåö›¬0i7÷h”àdTš4TöRÚJRB‚Òã$%)]9JQÏP:}¨b>Ké㱊å!¥gÇ*ÖG”ž¨Pl)=Y¡ØŸXÅ^«6i÷Y“ÀLì·~ŸŸƒÖ¯ãÍRÑ!~yÄyiäÂG­yÔõaVý¢U$éÇ9îþ›­©¼v-¢4œýÓO!'RË4ªDÕ†ØÂOX©)•Ð)dØç@êÀŸj–3˃ÜìE®tI#ZíG lä/kÕx´ÀÏ%ø™ãºU\‡)$9Å kÔY-;u²E+ Þdˆ·èÍâ6~“D#é‡Öd¬ÍW ¬Q+>OÕ@‚|lša4ÿÄÊvÝ_tˆ6ütxò)ãÿ VÝ}»#j[Îí=ç—/¬Òô×ñP:I°CЬ¥‚öÚy0Wɱt²XO[¤,&ýÓ#ÔÂ2Ø0!ì½:z „Wݽzz ôâ§üÝ˺ HÑrË’J#%ÄöÛxr˜Zm<9ÔãRÀ6_‘¶åª þ÷?=e'ÙǦ™o·ISã¶þ¢‘Ò*’†vA¨t±+ [<¯=¯½°)h{¨Ì~[ÑY{þY»¡¬[«8`Kñ9á‚$¹Ìa*ÓjKÅ.9ð©ì8ýzêø~¯ZÐÿ„ Ü€z* êiªqÎFsb~C ¥.d•ºH¥®¡›þÁíýò`TÍŸû‘‚3ÁMùl–ÏV¶ ½ ‘®j þ úÄu”¿Çï̳­â!òÚ;ÇD;EgÇ4#lEúP™<%ÿQÖmâ‰-JÒu§ ¦¥÷”¨{†–Þ3P½Bq<·‰§8ShóÓ.žÙhðtˆçøÍsÐ)^Ð4‰š—É@3ôÓYƒ%Æö’ššCh¢>CÑTj¨âjCíÀ'™×.Ñq‰aö¨‹Ðù Ê$†*®t’8W¡¸GRº-×3Ê.FØQ—†[Œ´GÝ…ߌWŒ¶G=lí)Ô‰†Ò;0Ù¡ô.õ`¥÷¨ã)Ôƒ J›‡*–JJÏ S¬óñì±Õ9Äšø_¶ˆ±HZÅ8$Ô¹ñœš©NdVóÏöUÊÌ4u':¢ÖبÄ6‡{߯PêYe\å(êL™ÊÌï¬èÉŽ$#€ñOsPÄôŽZÅlQ2ųÎâçHTjPMÌwH¯àïuˆ`÷©“±/¤N< ¾^O飰³’‡Šk•C,D-âç’¿9Ä"GÔ¡ "Ž´kÅß(mèelK8Òy$xÿR Câ°#[Æ”pŠ”zÙNYV9¢®¨³ŽtÖ8ˆ`£]ë€LáN±?—V±Þ‘ü˜Ä#bø›±ÇŠg3¥Oˆ?osˆM=÷¯ßì ¦î®«ßæˆzáÖe;#áÈÖøí@ šL\Ò'¹=/m´ì@F%â4Úá,¥Ë…×íˆx`aì÷9RI8w:àHA»ö+XüäÃÆðK8´ Dm4™„ßSšL)‡8æˆÇ&h÷€4óÃ-l pÜ‘ žs‚²6é=B.Ÿ.xNB¶âˆñØýíiùv ½]ËoÏ:’0–ÌQCk•ѸãŠ9¦Ì;õع×À.½ví50(½ŒÝ!ÌÖ¿¯Ü£äÍráÀª5ݧ¤Ò®>p0ú懔Îÿµå%Ï!"Pºÿ×¶6JöýÚþ”’ŠŸ;ž¡ÊÏÏÌ©\/eÝCœ˜Pžr'V…w(%/hÿ_=<Ûw&hƒ–³Þ+F8£^}Ö{yÖc"rF-; §ÑNß?㦽3åÇÚ¬$˜4’…‡‚&1ÑÉNt’±³A9¿ìbg9“±sAÝgQµ“äi Îz¦qmw²ð ÕžîŒ:P•¥ôΨ •jЭ™ÎF!Üè‹ú¢æ.aÚ§j²»2O+?NÖ‹P/R/ƒ°\5L—fcºìML—¿‰éªlôVkèѪ³ÕÎe$×hH¦³\b­3êÓÙèL¾ÄJ¾þÍ4!Æü²Ó'"TvÞJÉ« ¥Ë6§ØìŒ÷È?‡ì$¶8£˜»}9°³ØŠ…ºˆmx0òCW±ƒÑìíR#w»Ø©åtÕrœ¢É‰žÞhÿu…Òu¯“-SjÔV5÷ËA±ú•„ÞO}ˆJ2ÃBú«f•}8¦Çx2Çc@¥IBr[ ܺÅé7‰o5ðø– ßNä/²ˆ$ýv!±E¤ð±ýpŽÉl±—Ûç'“q'S®Î3Dˆvâ7œâœ“Ž˜œñ¢†`¤!òñ€† ‚ÿ~×µdÜGâªüÝ¿dÌGâ†íqÓ™ üz[V©oÜ!•ŠéŽSÜv&Y1Ö*îÐ/fœª¸ë”g @»Ç¿Svß™à˲8 KáÝòhW’Pg‚ŸŽ©%“?ÑÃ#YŠÀçNMñÜ)^:3Q¹:ž…±¶ç•l¦pÚGŠxÍÏY€†º4@C]b¸ë 6°4Ä ’xŽêµX¯Hi`ª ¿`é5ÐÚ½ì¿ã@:C‘!UYWAÒŒ©”–W*ÊtJ‡g¸˜™™f¹˜™©³]bº‹ùS‹˜á"Ák¯UÌreM•[ÓSÆ,æ¸Ry7FµÖ•HDÕºifDÝ67&Î\䙑·HæÑÄšçê/ ÎF<¨ˆ….0±mÜÄ’Ç+æzÂeÂÏ-k7¢R±np‰z:)OZêJ$_xØ~Å¥=‡6¸äÓX®‘?«ò¹ e«ØàJDþûHFltEm>+–Ó1p³ \ݾÅ%6S~þüï˜tb R¸£öò߄ң]øý/¢¶Mqls‰m.VèÊŒí´ç³ÅåNW”Õô®ú#¥m7RÉ 4C•-®xÜþ¥íí6Í-öºQ+è´ß…Cl'ŒõîI~ó̾?ÓV·óˆK!B+*‘ªÂT›íÙï¨+‘Â0¾ÛT¹d] ¦Ð„¢f^Ï)ŠØ –í1¼Ó·¥Î8 5KrV¢0ËÙ‰ØBË—Xî-˜n‰ÍÛj¹Ä_»XAØ,'U™[”¹5½Ä·ÔK”»û‹anÚêyÕ¤ÜE³M ä>ù³MЦo C.VŒWLÓ¬ÑÎâúÛF/¯Ó²Ã¼JÅ9ıHÇÏ»£-"°<7[—ñ)ä蛨B¬ç–J¡µtûpa÷ª;jÞIgˆFQs×z’Bn¸}ÇøT1²R± ¢Ì¨JÅqß-„[*Yâ¾;êø‚¸ÀjÝ©QSý¡;ê¬Â‹'LÄÄr} œË˜.mô¨¯„»4¢‹3M‡¤K»N—ªtyš¡Ë0F—KYta>3Ê£ -,'ìb¬'›2ã<Ù”yJ”i`ÊTxØ‚ _Êù3:(SéñA­7ÉÓh£=Pv]Nd™âñmåhy;îwÆn*ð-…æN?Zî–³>êÒB%!,Ïz·œêZ¦â‹à왕z¦Ñ÷ ب[Î-ÓäûßpŠç̉z¦Ê×î¸%}´Ls:6’…W˜ÅæêVÔÞn9ü²ýåËöÞ¯ð/ÿ5þQ®˜áÉ,4y7¦H*ÇjµXKv7×Úþ*7×sOM;(Ò1´ƒ"}–cZà <8ïc\èÁMåÓÙŸsL3»ºØ#{¢*_0Á¦¹Ä£9œäë%º2@:ìe<èì7ì¢Á“,°‹•]ÇÀÇÈ»¯Ć™¢JºÜ#yyԢѴYá‘—F´L%M#ÓÆh³tÛÔÞnœÛÞ¾¨½~‰Õ:YÀ7 tÓd÷7{ ¦Pß7S_g U”ÍZß7{`ßm;€Z*Yû}•ïβzÔPÜ*QTÅvÆ&I”ÉBq'gní«e¾‰¢Ê(Ö´·¯’(îö°‹¬æó;ë.cø€HJ?ßÔ‡½†z Ìé50·ûðÝäNõÈ#ÅŸÇrO(K2d¥ã*õ)¥·Âæç”Œ¯T,/(ÐÅ:ÌËçAÛJ' ˜äå:Ž*/“Ã9™ÒÛa×/SÅ]íÅŽá™ê…hçFÉ“±Šo:¥ã‡+þzJ+*•À.J++•N½â‘GÛ<{4Ñ뉜–‰Ø.$­ZˆZµšò  µñ¡þ)ͧ„\ífX‹Jqj˜û8××´è<¥XÃnýЂw†§¾Q^)å² ¥IKÇÔZ( F{ù ;ÔeJ9¬bŒ—¤•Dl¾‰Ý¢Žõö¼|µ‹ oú, cTœEé\èÍ>ü:D•,퓽QG 3kÁ4±C*GäÅbZX¬™òŸ*G›³7KÃB‡Å©Ü9èø›”WLóbïò‰é^ŽmX‰;ãÃÎ54ëÊ•.µ”®/WºÎ¥tÊ/ƒ ¼¢Æ‹ó2ñºˆZoÔŽ£Ù\o<Ú%õä'ƒ&œ²æy£]¢]£A¾F5Ÿ¤j¾«¨Ãïiø ¼Q?U‹Ò!2?Ä…ÄBTôFCì¤v‘DØíR8ÿ#£Xì¥7]yøØ«îl/‹½¬èÇõ%—ùÿ’VC½7ê£& ¼Pb±ŠXúÜõÕ-¼:¥ˆP«¾F¨ÕéÚÙ·¾Z7IYuà_Ùh—©§v±Þ›Q#t¾Fè“@£È¦,*l~ ¶È øD )±ÖË€@×IÔ¿Æ?>IwyµEŸÁǰHšµEBÇìÝÞ¨%ÚɵÜwb¥ÚCƒºk”’³×Ë_³s÷yŸB¶¨±× ÅJ®ØçåÛ»‰ýÞh7ùi›ã€dªåäç±õïÀ\ü]Ö ‘ìÉë¨7š( o47ÏàÁ6–Òׄkî@¸ô;Wö¼†’Õî~Jïþ!êþqt#·Ý=M„öEmµ…kh‘Ÿ¡[4ÀN.ü±ÅzQ5&| Öä‹ÎâVq´3¯áË0ômÉ1Ób='™é ¯T·©$$‚•Bë$ªqÓ^»õøN¯ïJ–zKò3å¶W²Ô;^\4Ýó²*Y’)š{y,c|÷”I$`ާ´ŠÌ*+íì“)LbÕlsdçW>æÈ®9>0S÷|sQO¥7Ëïh¸ËßBJ§T*þE”VW]ìÓí´Ñ'ny5¦zûN“qÇûÇù¬ðêzºÇÞàIz¥ÃÝŽïáW›7òÒHrT÷¬U“üXw ÿ4]ckßúÀW˜‹ÍžÎϽâ¹´EôHbAS+•.e>ñ’¥‹6;TñÊUu휚ÖI¿ö²p4ÄÇò…®†åw¹¯è~Ÿ¨š’w>»òõÎa>’A–H^4ÂÇ“ºbÈub!LiõEÍ]~O³mŒ/žÄ%Í,e«ïËãû™|™®qˆÀ ß÷ùö)¼?Tú2}äU0Ñ—§ V•O*1'û²Ô¡´LñGÿ–Ô™uêS}ñžšv,(¦ù¢AM;f³ Âïi¯øÊ'w<—˜ã‹º’5`cóa'¬‚Õù$G÷ŠZžO,Ôòüb‘/¯¸ãb$ÄR>-4H!›F®:ð!†\îË}rõ‡Dƒ/ÒV?„â• ˜¯h~ä}øL¸Z+I,ݵ\2je?ó ÿ}›ùì@Ì'´ƒfçnbB;1k™»Ë'6ûÑÎéAßâ{Û oõù¾P`èÍR*8«\Ç9b§–5MÏÊ»A]Žþ Bé¶Ç‡oïò‰=ZÿŒñŽØËèôgŒ}>ƒòî̗휚¨‹†î›xwÖGÌØ@Ç)¿|çÖo¸x¢®úŽÝç}Q'c0.7%™|ü¢/Úùƒßøb`§è7l”øÈ|™r)K\e õMØØ9Ú™Ç^Ó)ÐGg;f¾7éW Ú‰™ï]_‚þsïÒ¼WÜ“]Kó\f´ǰÖ[Àb]ifF;„ ØOZ{¥¯p;Ћ;â†!~¾@Žäh…bD:DÕá”N'Qu¥3ˆ±Ž¤t&1ÖQ~¾D>ÚökCÉÅQŠ}¼ŸÙ°c¥³ˆ­VøÁ]“ýb¸?r„_~Êé‡}1„ñ~ÖÆYY±6’ׄO0h’'øõonNQáÇùÕ%&û¡,ó ìrÕxu§¯QLõGíú¤¶§¿3L÷G];©æ ¿o-Ü0ø1!íú·\]ù¹#8(ðhMütêÄ[ukýE§‚N L;1×Û:%gHã_T¬dkXÌç|.9ÐOÔɧmô´¶ŸXèçk?V _õþ¢}èoÔÿ/ªXêO‘˜Šæ£ŽÂ}¬0¨çåo×W_-h7ÙßèŽÒ ¾‹xç*êPžâÁ7­ÕT:ê’*:.¸ŽÐ¬Å¢üŠÎ[übƒ?²=Lb#•›è½ØL8îðËðT_ÔRNÂê?AéúÞç.ßSj+Ï¿Øág¦Ù?ê©ÁÊû‚ØàN?ÍbÎóÖò4ÞÅÝÛEˆ Êîö§¢^ÑäÏêã`íe|·úà÷ùǵ·Ûü6ŸØO/èÀu<ǬZ¬'ä‘ð(”#¶ËQ¿Œí‚·S~‘ðëVR~íêß1¿ °Òìï/Zý)èÎ õékyÚ¯$ÔY¿„9±?žgà¥vÒŸ¹JtJ«×™ØúSôŸç¦¦˜æ•wFfiÊéôÚ;KÍ^ðCéb»þxá± 4̽L¿›ƒ°ï‡÷á/éúõOü0±—ÂD›_ª7ŸÀç~áá…_^fy 'Y ¹Ç$ÍNò‹öž)FÀû$ ט/PÓXJçÒ²žDéþ±]gäe{‘{$¸:Àê®6Åq8 Š‚”›O¢‘L hÑ}¬QgObÄ< ø¹)¬I£V‘HÕµÖf$-»H¥ë"—Vu¥†Q­);·–&­¦ÂC­æ€”¢%PÔ ×Aaí„\Ãéq³yXO³ýFô4 Ë‘QŠ‚têHÅx. Έ™õ{j7–}£U\¤ ˆ‹_—)v&'‡ùlìŽÝlk,oÁ§À9Ê5©²Äy.ýõØ(ùï4cŸ/‹v†;„cùX¾í—Ì÷V ¨‘ßžâÿg W§‚òf} hWX_üné4±v9Û©ÆmXj\ç¶¿‡MzÛMªØ3œÛA±_w0 îÀÝÈ`ܬ×jVEk6ÆÇ 㓌OuÀøŒ†ñ¾°8«5q>ÝÄ4q3¾ÕrÑÄM`|[-:ndžwŽGæ·Â¨àVŽtBEžèX ÄŸdoÓeÏ2ˆ?—ˆ·â¯$âøë·àicÄ#6L 3Ì*Fðj À§è(«D¼õ=X,ñ1ÖÌÜiëˆõ«Äú`XL²êX³ÒÓÌà/€Ò"*ùƒÿŒ—×ÿ;¬úòj´òòÚgåÐ4YËk·U.¯&k"6‹–×>ë[—×!^^û­¼¼HPí>œ×ÂZ<çµõïhï¨Þã£V¹”V6îÉZJ) ÿ8UY¥™[‹•VÕ,‹h•Ô8žEg©qZ£Æ¡°8Ÿ¦ÆPãEŽtˆÍɪá3«xlMáþ;ý^È¡>Æ>—~ä—= âp “Ä2=ìL™M”ÛÒƒ8Ì&ñô{b¸ ;3–AûyG´ÇØ$Ú‡Ãb‚MG»ñg^eЮµih/´Á¦[G{>ÿŒ%´2˜Ø ½È–è0`äuíå:ÚËmbEíUÚgß«%Úk²Ð~Ùí ÚGÂbKí­@»=³bNéh_°qt í³ís„ö‰öQ }ÑöæŠ)ËMc}]Çúºl4¬okXŸ{OÜ‘XßÍÂúUG¬hX ‹'i¬Û€õ\¬˜÷ÐЄ™jç\˜â„ëù÷ôË-Cy¦è:Ýб腬¢Cs±Ü>GѤ]_nÇì¼ÜNÚà&{¹µØårkµ'bmÁnó–åçåvÊÎËzYiùqfÍ ËÅšÆûÙ{ö~vÁ..I˜­ïgWì⊽Ã"¼f—+ïºV^[PÜÁtnÚ3 ô–=òº#aïÙ%aãañЮö̆ç¦gq…C›Ó.G›“øgìzç1ÍÁ=L`:Lw賸·’žÅ#x>Lä¾e‡É™çHOˆ:‡œ×;‹2âÌBGfB´gðþ_…g¼¡›K”ã¼Ù[)/I„ŠΧöK’a±2ý ‹µ½{ëiO§0e™ ‘ù·À¬‘0»Ò‡2âèÜ òùr:c‰;½ø'D¿’æ÷ÄAíé~°äâ{â¨C oltwDF~R8æçôÄÎÜŒÖFå‹à#&ÄI&ijrÅpÒ!N;â‰Og˜qÖ‘¨–&¬âœ#Ñ{ÆÏë5‹ËÞ“F*õ5¸±ê€Cz„ÃÈŽ‚ØòŸÖëzÊ ÁêÀq¯ÈQ´Ã¨9Ùb×;—‘E#…±uĽR¾¸ê ÙáBÐ÷¦Ï×aï,È‚=ˆÚ7E;³`ÃÏà-dÑ_ û¶„wÐû A!Ðûѹªêr/5¢÷Ya^p~á¿(¢Í¡‡yyæHÆcW‚ÿs~E¥b|á/[å%Á¿Œc‡ûhWίµLL¡v‡ ÿSÔ5…é3´¯>£ÜOá44Ad†wî<®ÞñÂ1!\1GVÏ’ïá–9ý¤$’Tb«ûЉô\*¼Õß(ªä«*gdÛÜWL¦ç)òUµ|Uͯ6õSéy²|5]¾šî„³ïÄ z®–¯fÉW³øÕæ1›ž§ÊWspOwL.LcªÍwfùÿŸ/ƒãÌwŠ…NÝÿÿb­_0 ¡~¥~­” ¬Ô;³JvfÈO³ˆ^­Ñ;³Vv¯ÖËWëõÎlÁ«MòÕ&½3›egðj«|µUïÌ6Ù¼Úé”úS}@w9Å.§ŒGÐäÄx59±â¯2³Úã¤QcúPdïs¦Ä~'ªÃ)9µq< ÍÅQ§…WU1ŒŽ9#K Ê?€ßËïЯüú%ñüæ°R_]^®ù£ÍQ»S–v ½©Hà ðsz»Ú "Cç6Ó¨\»YoÕÁÐÏÞ«è|ÞVqüRz'â*Tÿ‘k²kЃ8M5Ρ€½owñ©2z±Ïq¹&ÚÖqÿ®ò 8 4÷l·˜Ø8ª¿C?/å íZÚ­ÓÜXGÅ'®œ÷(½šsÝ´eñÄ™(—¸‘œØ½¼ºE´9“¸â"ž:Á=ê”Xk8›$¹Äsn¬ðÆ{tüÓŠ½r‚dŠÁ{=¶ÄXÒŠÃÝñ¼™ôú£]š—ÀÑ.17‡w&åm<Ñï8уº;‹ÿÅgÉ{é?3Ìr‰¯*ç¸ú‹Z~L^yOó]:w¯C{ :€—X™°Š¬Ñ\%ëÓ6@%ü'¼)0€ ·]´ I]bwRAÚ+!% ¯½gÒ ÔD;XÓìBÌáLÕãTõ¤$Õu"Õ™tų¨8‰å™<è—\ÙòÀ%Gá¡‘ÿ©.\sq4ž,yà†+€ƒá[.’^»Åmoªw\™MõqfSý¶ ºÃÂmm.}ë¤Mõ©+k}™Fò¬bIéÿŽån]RæfIiŒ›#èdIJ#ÜRRéNĦ½_ Ƹß*)`Ii¬›%%¼Þ/s쟜%&Mtg“e¢[T¹;ŠISÜbŠ»Y¦º¥˜4ÍMd™ö¾˜îf²ÌpgĤ™îÈÓŽb"ä€2'Âbž[ïÿ|ÜõžÂûù¿™z·&&­s‹en°*>Ó6 ¢ ýÍp¶n³9ù´ÆÕ Ä*w÷±NVí@ÞÖʺÔý–#B5 W¿cÕ”[“­¶ºÅö ;ù'ËV²¿»²ðÙíÖ÷Gb¨>yïà³Òý=èNÇFϧfF>‘ù”ùÓ2XNÖÈ7k#ßB#?·KÂÞ¼mäS<ògäÈsÀBºK–ýú9G~‘\F^FÀé0ò×ÜâZÇ‘¿¡üMŒüÜ.â–¤Äí¬‘¿ãŽ”õí°&îk#Ÿ óÅéôšhsg š/Ò4z™¦Ñ+ÐhznúØ>Ì£Óh„‡i4Î#Fx:Ðh”GÒh´'{Hçˆqž·Òè$Óh¼ç-ÇöYk£Ê“M¡*˜âéH¡©1ÕÓBÓ=’B3šÚ¼¿{¥á"Ó³ŠÌðGœù¢E¹$ÿ,‘nÈ!s¸Öœ¬Z5>šîoÙ\Ôyä™ëÔeÕYà£ÙýfE¨Óð>v³¥>9å—á¶à>Q•bÆoÐcìlð‰M¾Dl¿=ÎWqwúâìµ¹Ñ×_ìñÑ96m8ü(¨™ýÑ|kÇöúèg’=ÄþtÜ¡ƒÔÞ§Š8„krë—zƒ ŸHi ª|ͳ¿hIW?Žê» ÎHs3ä|`Ö«_õ‰ë>: _ â%àD^*#K/ÅŸ¦$ˆó½á»>y`¾ïÓbjˆ¾È§± ýⱊPÚ¯ôÃôÛG¾È¾‚Øþ‚¯¹¹Z,IÂã…ŽÇ Ÿáçæ¿µúì,ß):ZPô-ääKÉ?Z ¹¾‹ 2Ò]"âùßÅÓ(zº”'f Öw˜x¬tåÈAiÝìXú>Á/œ2ˆ Ü ›—›þL;EÄ2ÅÏeš_LówÐDè ë[®ÍÖ›@™„¶ {tyLgù#µý»—¼èøBÜä\49?W¥óo M.¢&Å?+*ØbL*#–ù3ô-Üi4‰åéW þ,âò»ODƒ¸) Ó*¼;Fq š«ËEÈŒnhn£ÞÃ~±ÙŸ(ÜKж Ìž[ßàÓ½^¦Ñ/šü™0U(¶‹õâ)¨KøE‹_üq"Sá$*,bê²Îü‚^áQw3Q÷²_\ö'ò/©†²Üq5“\ó¦?™ßT``Áó–†åm@[œÁò¡í!.¦mC±%™båz‘ò€HK7õ¬†pó6ÁYö5väšk!Œ(Ÿ³g_{Óyö®ÜŒ;[€°Ërõ¸Ãûƒk.âRüDÞ<JÑéÿLXŠ2%ãQû|5¡YhÈ…ŸoyOiE®Iñúþäþ–JE¼Ï·•Þ{€ÞÄóg‡ ñü¯BÒ‰?\¶u¼>¸Ú—u¥«ýY!ÝÕþ¬ZEMy}Y®öWÓ‰Úëû ×ùSÐt+íï‰âýƪ†AÍâ¿DöôË3îí§ˆ¿àŸDM‘]¦Â}ýTñ#Ê)<ØÏ ~ 'êkh>z}ßfPýtPýEÿx¿q jJ×}dÒksU4ÿ°h‘2`‘b([¤4KÌ“”è=/òoïµ!öö>/Õ†toïëÒ +¨Å_5÷m j$¨¹ª& j=Ó‡]®Ï@¸ 4k¼¾ÈçìY3#ôƬ™éàr}cÔL€Ú”5³¨™o‚š×Ôæ ¨9µ%jNPsÞ5£°¨­˜¶žŸþçÁR?ŒTñÿφ(ïf»ƒŸb@·å“ °ÛØ…fà6z÷^ÑüP÷ÏÊ•Ò'2øÊ.Ö\W*Ú]¸@Ö]¸ëPZ”â}å]¸}ï)«O)Å#ûò]¸‘”±z°é¼R<ª¯¼ 7ŠrÖ V¯(Å£ûÊ»p£)çÆÌ7•â1}å]¸1”³v°åžR<¶¯¼ 7–¯“Y)g\ßÞuŸõü¥R2WÉvÞnO÷ûÛ ëvxþÆÅFÜ![CøY9î5å"I¿ßkŒø­òf±ßGdlEøg¬ÌTÀʱ#Fq„r„bgðµð¨ñÍÇ{hõ¹=Ÿ1ÀÝv‹Q—@qçú$ÿL””™Ä)#ÒO1PDK?mŒŒÐŽè B|D?Çï%gÂâ<0Þ›‹€*Ê <…¿ìç2dðݺ`Y­âƒÍK‰íÙ0eÀ£#÷O’,:ríF1Ä”Fn¨I"WÃLŒ%rÃM‘‘‘e’È ‹Ñ&é÷AÚ.ûáÞŸ…î x¶žeJ£;›Æw)["ÑýŠÁÅÎ…)ƒÐ=EËùú ¿ù&± ƒî" ÝÃ]à¿è.N£»ÄÕÝeºçÂÒ›÷AFîO¸m@n‡„ 3ý¹…¡2•­À%nçÃe¸÷z( µ}:jûLâ@µCj CðÔ§Q;bŠŒîˆZBCí|Xz?œ…Úe v5ƒÚ5‰ÚccY£v]¢v!\–C¨ÉBí®ŽÚ]“Ôh¨=6âæ$P{˜Fí‘)2¦#jmjÂâ)P;š….EŠ1jµ±ü3¶ˆx£6NeÔ.†Ëà-ž…Ú$ýÎÞ$ULVÓ¨U«µE!1UeÔ¦ª:jÓÔÈØŽ¨ÍT%jÃbnò%x9‡Xà Ôu3¬QÅ:5Ñ=7Ž×«$Æ„ ½÷þAlÀ@&sMªÛ3Dá*G¹ÊÁ†£ê=eË/$M¿0UER¥MfÎ'¢YMD>_ÍÎXZÔ¢ÏùŸ+É’J‡8!óì±\æÇSù‹CJÉ$‡8C/¶ZóY‘ZZÍÕϪE?KäÿLI•œ*ç€|*W%T¦¨Œ n=¦¿0ßTù[éMUÜVõ/ÌwÕ$(Õù<üýì¬TŒTñ@å/ÌTm>@ï{³'LT-£Þ¦ò¹VM¬OU}Ä©î UãozÝW™ºgÂàY¯¹îkY·]Õù>O›5n£×…ÿt­îÙ0XÊp3ê7sÝfPÝÑfméëuÇfêž c}ãºãdÝñf}mSÝJ³¶4õº“2uχ±«¸n•¬;Ù¬/>ª;Õ¬MP½îôLÝ‹aLÃ\w†¬;Ó¬OAªû•9žÂ~R+«”Ìù®X`.jü^¤^‰]ø ïÙ0o^įÅb³ÌG„r|’\ª½˜)º\m0Ë|½è*\®<Æ3µÌÄÓc½9ëSúz3Oõf±Ñ¬Jßl–Óã}zì6‹­ú¶,DpËa»ÌÞ‘Õ(²w›å×í=fŽ ÏK&JZc°×œÒØ8ÃþìR#2¥h¥ÊLØÁe—™)uX+UÄVr4»Ô¨L©¸Vêppðdv©Ñ™R)­Ô˜isv©±™R-Z©E!0ãÚHždRtÇT=¥ý¤ÕrZûIã{#Ñœk±¸=ó%ϸÆ÷YÇÃpFaÄß*HªË#Ò©åŠ é´rE½f71:ì"òS²™r ÒwTîxñ4x"G¤ík3湬pñÍ /e…W_›7íÀ¶…Ùʉí(‹†í( c‹ØŽ²ˆ1`÷)©,oà «£ÒÒa~ÃÂTìÆ«,§ÕTËÛ°å%fé0óÈL d–¥ã$œƒû°­¼áx¸ÕFÈÈu™“Ììöüïò9[f®{Sf®û,ëü8ÂàÆp€'!íº~ª‰‹û•¢ËÿÓàôþ64K–.­”-@B>•k¦F*o±Y7XY¡ï›×^:ž¤Øõƒë”â }ó^—N Ç ƒM[”â ¼­ ÇƒÕJqeß¼W%•ô¸i°y¯R<±oïÆJ¥w²L齋Òx™òKcéDz½ÅjiVX0nVŠ'é‚ñ$Ƨù`¼¿›¼Á?®qHœëøÏäš,ïHç×Ádj•*{íi¢Ãßã=¥ñe!%{ˆ©¬5Š¹Æ¢-ýò·ô3°iÛ<#߈ÆH]°{}³X(T`w_uÁXå'y†úA-$'éþ|?Áw­½•Š©Þ(êIŽH)VÅwÔZ…±Kñ¢+á"Ó“áWÊ€+a¥”ê2cÑ^ Ç6^aŒÜñèžÅhm³u$ë&Vãê-cX‹0œ¥$ÏÀ¶µ&èl‰ù—™ÀìÖS@d½¬ÐûQXl2¦Öà2G¯ßLœÕXÔj- ¦òƒJ~«U‰s¦bWÙ¢–¯áoåšß;²û÷}Æ«ŠwãÝ o$àÝÔWˆ%MÆxTEgö¦;sÀÈAæÏæ"‚Ü?óxœ×EöóFq„å{,—ð+2^‰] Çcåm¥+ÆxÒ5!qéú¸EmCËv›N,é’¬í»Õß,îã 35~Ϩ8iœËEعrÓÏô¦Ÿ锑HëÏÚI—íÆD’ƒvñ ˆe¶Àyžl~° 2l"÷`é^Èz“–n7âÍEnô¿ð›ÛºôzÛD’l%d¸%S» AŽíQº)DÒkúú'ÔKYЧB@N2Ì@¿œ}Ž.€ÎQE-‰wT‚¡ÏW}Kv5 }AÚ4e!Ä´+YÐ÷úA›ô« ½?¿IèЪHú6 ý˜ÚŸ$G„‘¡ÝFMô`ov§ÑÒö ŠzK,^#~äñö”ôƒ=E±ù¡È„¾@óüT€2±Ýhÿz.‚!~ƒËoÐÍ,6˜Å&Úwzî A*€ù ïp±}z±}´ÀÿZArö>3íÜ„uS¨3|D5§xîÆÍqä6‡ÚûÓî*ïRµ E(=áKW„D+öÔ]!ì­‰Ò!q"mjrXÜäÎVq0ï˜@[ÀÞä0ô®‚Ÿ Ê&ÖJ_qk E*ûÊE}g•˜láìñ}5çÌqØåà A+ H2kÀ1…ñ;¿ê¥éaQ”E¿Ùº‘Çl mB ß¢_ vÛ¹&“Çû÷\l‰^l‰…é·Ä"–:ûC‰\Œö2KÑ`‘4Zay“F« ¶Ú«Ó kОbyÜÂaæ¨%ò˜oÜP‚5Çß™bCÐ8ÜåYׇ ŸÒÑ9eA¼¬Ožug óhë`H\`XPz_į–í%´zG¤º‹V…%²œ¤ïwÖ}<Å ÏýXP\䚬oÊÌåÛ8ÊÏþw›ó ­yø¬ÛÃðŒhr¨RQž[ÄsKÏ„ÎáÛɯ‰BkBÿF0ʬñž`TC£jÅÀäV¤/ÖñÓ¥>ä2V ³òdìQ˜}ïÃ=&U>ß…OW#¬ñ<Í:©¥ ‡v¹ÆR‘í!VàG“´è*¸–lBTZõ¹¤ßª­|ër’UßĘsWk !ÞŽ6{£øž€bÌrg[ã<Ýö†òüµ”@ú9”;¾/êÕZµùm“®Byíõ.2Mu™Žî •î ‰…”9¤¦Ì«Î ¯ÞÏo h_]Aù;Cü¡zz¸“f—5É2ÖZ+T4Cy»uÀEêi6RÆP ˆJlFÆØB5­¼Q'q’h·K>”® ‰&kÑþw#ûßmé;`ÿ» ^ì±Ò|›i.9ø®Ø«ý<ð®ØgM«òQ;›BYà#VìÃc°©nù…1i-VšŠ´9Î7ÁÃ稙 ãlù@ vM{Ô5¿ÿE«8i§ +:nýÅì¿ÒÞn³ØÌp‚Ï1ÏYl‡åØ÷Ÿ'P­>/|k\Ô+ž·6šH ïr³½]\C߉Ý߀ùÎ}^ã˵Àö;[~a¸k…r@¹o÷—CðD>Yöy‹x`M²þã¡5OÆNèGÿGö€UKV÷Œ¡Ñ©í™•OmϬâ…§¶z"ñ+k’wŽaeذÀõYპœé§Øa"&û›Ìàx(Ä0›Æã±sòìpÎa“â5Íx™= v(¿bFo¼MCq( ½ñ6QazK ½‰6Fzš*†79»ÈëS8»:»dOC3è âñÖ%µiª–Ù6Vµ iú…q6Ûõ(]õD€•¡´¤±*Ä^†Dƒ-¹Ó}5{?Ya+ºÓ=‘§»Ò³ä~wõ󅞯k³J®K—ì’dÉ•óøxÐJc?Þž. Pag‡ bwV᦬«¸ðÞŽxÊÂãpG<’6>s- ™D³¦u»¤zœ«õ àšMÓc]³‰¶Èíî´¶6‡â±­!šdЪ=ÉUhøþ.\f×\a—Ùï)Û¡”!þM<¶:ÄRíH{¼ðT!m¨¶¬j3ôj3åÊ »¨ÉT«¥jg¨Ú|T{ÊÛM.W[­W[mkí,.ÔÃà/«H“^¤É.öÚ™- ÈsžrurIÀL©§¼ê–„—’1íýE«=ŽçžLËvÄz !v åìô_±ÚÓ.s‘£¨@À”ìê¢øn𝮠±[p—ö í#Ä//ÙãÉ´L°®£LPº!$® Ó/rUÚëÆÊ½î]îu8¡3Ñ;;<æø&Gá “Ò8¼aÚ± ªˆs’¨TÌcâ1P²ù*Íh ž*íሧµÙøÕs;6í8üžy¹ÿ¥ŸÇ÷u98Þ‰¾—¼æü¤ƒÖNýB^™CnovJöÞ6Ä¡ímÙ§³ž©CqÚ\a˜£gƒ !@ë€ø5´mØÜ·gÚLLD/a‘[Á$þ½#„½ ÊA{AÔœO›Ÿ#Î:âxÕ“—ÔÔt{ÓÐÞlG­ÖûG}Z#ûÄÜZ˜ ‘T·ÁñÖ}v³lž’¶:¾¾ümøFÛ¹¹îÈj  ¶N$Rïuô€Qh®‘ÖÐÏxN^es¬Æ4\uÜS’´®:Äu‡.! Ç7,†óõ~mo wÒöewaéôŠåàdÀ/Úú}á`C¥õ!ŽˆØîèRVâ#Âp' _‰F8ã‰ÂÖâëÆ‘0˜/¸½ƒ%ˆ<¥¯Å˜¿¼æÆ¶HN0K 0Ë)¾rvëÑö n|޳¿˜'Ávþ-“›þšÄØqFã"éBÄè”Á-¤Ð¶Ì©uœåÄÈf9‘e´ÕôØÎý€ƒ¾µ²AfÕFÙ*îÅfô¢=×”–Øwˆg—‹R Mô»¢/ϵ=(\ÖÍL…ûqá£ÒâGnuÒŸÞFK5w³™ºÙ ó—•!ØÖl´DrcÃûÇc§éä>‹î$ÒÚn  Ôä\uê×…œâº“¯éèu ¯‡â¦“f(»…ŠåYh<ÏœØÁ¾ŽÆsBã%ÐXE¬À•AãláPu ÍBc¬KCc¬KŒwe¡qV¢Qá"4\%*놭ào¹b­^±ÖÅ¢Ö<—˜Gõ›¿Slu®$[ž,põ‹\Éȧ±óýâ± ÒØl1gœËd,ìáY°×ê°×JØë]b}öF ö&‚½%6›…eÃFÆ6ÀÑÍkñx+¤8³›m\>ç³O÷²ùßÃÞ@MívAÙªìq‰=ÔÔ&óð±×™Ø7»¦ßû\EßK²¢²ÛXû'Æ.ˆC¦C”¤*5騦øk–3[Å!„pPÅaWеØG\©X¥1´qÂŒ» •¢ppdþr“‚]$é*šÿ=ú›ìÙq bñÄ,ˆ% D3%ÉÑBIª@´Rr¬@E Ä JZ ÄIJöˆS®¨*N»h5EUìâŒ+5`þ÷<ÜOqÖ•aPçA˜‘LôI’0w˜0ãq“èqÇ%î¹ ‚Z¸Ã¡M‰SÝw‰û®¢ñJ"¼¢ ¤xèJÆf½yôI¬.¿3¤êÇ.ªïRxœÖ"Üܵ¥ ,’žiNPÉøž.ÐöIç>°±té¼€=Q–¹3«³Ü­¯NĹn©:©ÛEøþ ×ÓÜ:À'Ÿð…ÁqîxáÉÁ+¥ é—Ï>Ñ}–V¤óROp b Œ*FuÃÉçIÐ8îfT÷§šö+¥èæJã\©àÿgòop”.1ŒÀ˜nàFhZgo–Öy‹Uù7h†ÿV\¥+†« K˜x}}ï7ã#Ãø1†Ãã”âêþ=K«û‹ñJñÍþ=Joö”â[᥷¢B)j&ÙŠ¹[%TÈãºYŒ^ßR…!ì×#¦ïWÄAŠÊÛáÕ^„ù‰wÈxì©\WG8ïN˜¶Ýt^BIpÄEIÑït´úòå¦ë¤s[©Ô<¡ÕÇYü¤RÜ*º¦Vòo‡•ØÝpiÉ’Àz|7\Èñ3ÒOþ9‰ó7 U›Ð ·°þ’ß”éjÐ2š7ÆJ°œ:ÔØ_ Gtó!1:×›4ÒÚÔQP†Vd5°÷6ã±Ûh 2«½£X‰nËVQkÐÀíX«5°.ÝÀz40‘ÁüˆÁ4é`šŒb¯19ß…¡ì#( ¡=ßE”»!q( å0 LâyЃ¡œš§‘Ë%Ð,’d‰›Ä& Î q,Úþ› Ê`I ôc&â~ f~ÍD‹’*‡8nÒflún:”•'L¾“(¹'Î õ¿alΛt çMâ¢)íHá’Is¤À¶Î½/׳ÚášIrëéo·Lš†Û=³›J=ý3}ߤ)[î›XÙ‚¤éÆû&ÜûI¤ ŸPG™ÒªˆÇ¨?«›jöÊŒ’ïécÊT¨"$—Š#TQ®&"¥«Yvªö#Tx`¸T  Ã[ÅH5Ž¥•&òKz“*ܬùžÐíP÷N½2^¹û×ñdþíÂ%&´I*8,¤yŽŽ[ÅlÓÞP®q1YMFL«ñQLÕ*p/ܽΗ32€õ z&þJ…*0þá?>¨~ðáw§¼kSżLÂSß‚”%J‹rFyùñ« ³yöŒ’³g±*E>öZiX®2iPE½J+‘ ²”ÚY®¦¹Iƒ nòc›¬TÅJ5ÍMäôZ¥¦´…’Š*Ú½Õj<…'¥•9Ëfâ,kñ‰è+椿e„v¨ÿÝA¸œ†­·*ÕÛb[«‘¦P²¶Ó&•¶Ã$¶À=jQ Ã[hïUßzxÝÖæpke²ÿGô推¼L“ªˆ«4ÏáÛª Ö)5@Ôàf2ô ’¡_Hù¼…2ο/µb­jÑù÷“ùçßWz–ˆ°8N¯Z¾-µk'³o'ó[¾­èÌõ0©aLúË…£#r^"rYÈyBär‘+„¦âÕlD `\¼ZÙM²gwT-^'$V›“rO•ºÇªª”ÇW³–þ>n{Ñ3qHâ-üè¡ú5A¼E<Ù¿hO¨y:¶bz>U©KÒ-¡Z´'Ý|öt±:ÊIò³jÖ¸&̨rª¾šyÏ0|t»Â2_Ôæv³R¶È>Œå{SG*†±fVG)•”Nü™q¢—§xOax3i5-ãÍu‚¹¿¨4SÆð[§MÛVÜZâ[&“ÍÄìè}¢&U“šÏ3BÏTsöš~©*ôð;̧™“”Ùé]¾]…Ù¥ë>zöÄ‹ûß•§‡èÅ<Þ»6›äNhÖ× ÅêÀº‘вÊ,j͉ØýpäA8ö0Ì’Í\Â}¾+´Ókºƒ (H½AZd.zþqüX|^¼ßØ£t¿QüŽê-§.Øì~.9=«ÄÕýˆoÖõfÞÔÒ±q(®a¯à¶Þá7óôSð0 íÚ„ˆÕ±V˜Šë¼È;Ÿ"vèÕÌw衦J;õGæÿÍ~¬+ïÔó]P‰CëQ=[ï•e‹u£TDªÓ€ ¿óô!x^Qã3x^ýës=ÔM`¿ž|-Ûȵ°²ª4v-¼U ö‚Øýy,|¡,¯‚©BÑ—tc•Ot+¡Ið›à.îÖK<ŒÁQ%TA ð«Á ÆËϦ@ØTøMáG°=ŽwƒÊƒmf¶ó_A›Áâ¼?…”Ød*Ýø{¿Fí¶åµn‚Æv³Ñ÷é½ ªÒ Ùa¬è~Cù±®ì8öÚÍ^tôm¤£sxÞÉk2Jò›Ê›A\Jnþ$÷/ò¿x'ï]†.ÞC‡½Ç"E7"•=†.~2 ;ÛV$Ô¢”2¼ÿ)Ë)Ÿî†˜m^KJþËWõ:ë ¥Ó òÇþbPþ³Ÿ ¢!ÔP6›ßv¯ãn-»u°¡ôrߨž $Qõ/vó'‰ßmnÞbÀ1¶•¸ƒÞflÏ ='ÿ:Ú|}ï0RŸAwçË %cYBôrƒ¯bóe¬|žTutv…Žë”Ðçna-ŽêÛÒ,ÿ‚hItí¼Ïw£åZ¨É$9Ñk¸ B¢,Ü¥®TaÒ/ÐÀ픤H-ÐpwÒlŠáRŽç)ã&ß]"Ùù;­™—–ѵ²jsû6»ˆfhÆßíâ›; Ÿå6w®/Sþ7¯Ð:å­ÐÔ·”¼âi µO’Åò^N²»(îDC¹5€ªGá=Dq>ÅlÒˆÙ„¦ða„ ñc+ÛÑH­Ñ ±J@wÑt͈nŸÏVNu}UÃw%0‚¾€ï+Ä×ìF±‚ɔ喌5õëгaJh«{P`ÑÛ¡ÅoC…ûÔ˜ç³=1Æ9˜ŒÁÑOY,"~ †©)(ì’¾?ôÙhÃ5ר„ éê®E3k1òV4 [óÚtLH®`rtj¼“¢’ß%?¦¥?fä'ÐÌl¡(ùFÝßB7?M)]ÿˆž_Œ¢|}@íÁ~%?«ÆTø•ÐgýbΩ1sßRB‡úÅœWcFAšÃý¸õS\1 Ψyg®¨aj.vU SñSØ55LÅLa7-Ÿ%°e&ú6žmRB‹é°5ö¢ïkΆ›Lh¼T¼Ô­ç Ðè0©—Ï÷Vjp+Md3ˆ´¹\iâ«MØÂí¯§ü×6Ö˜ÐÇ-øáªk¯T?ùZöü ín ÄÞ „Xg ÃèWéÇ8zi¯éÂÌͦ(­+l1¡Ú¦sn3 å]¦©´;M¥+²/X*î6 ëå=P0¿è&Û}¦þcÚ~“è´L¥;³Èöó`Ì)ò!dƒâ• ®˜HÉÎÕEÃjÝ5¿fBlÄV±”uóTF:Ç%†æWÝIznB‹,QbÐT9™uѯ·Lá(™q´»£P`ܪ*«ôD—!I?"ù] {%c²ó”¨ÇDmÜ¡©UÌc]jΞšøSS¬ˆ³X|£R¤¯0#E†J3¯0c ¶\‰dKhQdÁ¥EiŒm±Z3ÃA IºýëðªÌ07õ¥b5T›#¹º×ƒrñŠ!^Ká´G=ÑÜ?ãIfZ¨4wIA)š>J3ŬDïSÍ‚ïÓbî…§£Q„–òs©”Ífhµ ÌILÇÝíVøRúBŽRLÀí¼Ì,–Î;ÌJh‰› nך•âÕnôÌǑHOß/˜¸R ¬::° ×™ÿ›n‹0ÛbæÛÈxìp–žï0GpžI«GîuÔ0ýZ^Ž™ï4cT`¾'¡f\C|TÃÔEă樺ö ,~+´rèÒi´ž~ˆ! XSüœÒ=PÓ´sØ”T‹¹ KŠ‹@ŠH °A‰ÒF°HÝ ù˜Y]>fæ'  yÅG 3`= `g5°³f~ÞŒ}Á. ØQÒD`×4®kf„føØàÖ_3óf퀄ºÂ¿Bí𪅞sñÌÉÎÉaº‡œ†1ÜH&H&a‚tÏLËSì±™ÖzôOày dÇIзN`Òd ˆöeÐH›»²Fôð'æÀÚ¬Gù33MËJ¨ÓíígØžÆX€;îi‚sñI[ÜLÔ=šÉcѪ,±y7òj ÞÙ&ƼŒ×XЄð·Ä¤àš^­¥t{–ÚäF“X>ÉØ™… “-Ê !=Yl$t’é– ŒÚ:ŸaAƒ K€¬A’på¾SCÝ&Óè׿†8ºb¤¯öÅ-j ²À¢¯v»È”hè[lIú–ZÂÚŽ„<ÒÕŠelÎ3.·ð]?ÄÝ7ËKæ@&Þi š"h­³^Âh÷ÂM´šµÖÃ(Ùm°¼ÚÉÁÕ…-–—¬L|+`%k£mˆ^µJ@¿ËBçCŽS7¼b Æñ™%6–õ²;Ð.Cýß…v¡Xhè [Ä-Y ?ܯþº¹bé?ÜÁ:[¬Jk/6„yh™K,ÆAªí¸á7pF˼ÅnŒ£1˜î}±cw=‰·Â‰Pª•ãa{{F²/)‘ŠìlÙy‹h›‹_DvÇ‘#ÃU~9N>îÇók”–”Œ’n$´HÍ•x›› ~_D¡ÌþÈBÓ®. ï<¡¤ï)Ñ—†ô=·(a¤aPñZèöOU".B‰F[ã9`WYØ5ÖŠ2C€C$y„d¬U 9H&XûO°Ñ:ëÉAªðÉšuÖd+í`áã`ž~º•Oµj;XÓ­hkDgžÂê‘'žª¢O3­Qm·l¶UÝ«Ã]¬¹˜Õ Y5kY5[i±YdµÐŠfuêâÂ?šÕâxVKbYM±ò¥˜ÕIT_§¬6PV÷ ýn°òMÖ’=Yêñ•ÍSqÏ-˜ä”W2%;[Å ´'–fvfÃÇ—#ôø¸#á>x>¨cÒ!x>¬cògV¾Ï#3*e¿5(ÑäëP~>ðFa\ oÂëÀ>àNôHOW'F â;hŒ65–=Ò£ïtö@”#ö@ÏÃHîi¯9#´C‚á`[a`ŒŸL¤XKÖ»UþâõP¾‡ ñcýâð'â8º¦ÓùÂQaëƒ8FÙJ6 Ž@µ?Pã/Þà6ðJ´ôú˜ëtm×SºSÀ©¿{½¸õ ¸uÊúèS²ß°™êÃhÀþ“ñŸ£¤MâaFìë³È]Ìâî«$m;.@‡xGºöâN  ߀$Ÿ¿,q9œÿ¡ž_… Ä¡[½6¢!@ï›o`#]“¹âo…@…Œødrí»¿%~S|´ÊúPæ½"HÒ*ëC#¿A?:íÅ¢úðû ~›é{LœŸÒDLkÊÇÙÿ „Æ'ÍU~#KÒ}ê7ê3uãüFCšn¼ß(¥éªýF9MWã7ÓtcüF“¤ë7š%ÝYu[3¨ÓŒël¼Á†SlÌ:¹Ý "I&è ½ÝV'³i…|ªM ‰fáºÑ9ë›E5ζ%ˆ\³~¦›mëe·èO}®MÝ^` ŒíÏúžºDSIPûk2Ø"›Á–¡öþb×b[¿Òв¬ÍÖOÔ¢k –Ø"š£·hå+´öþ©ÐÚ²¿€¶²€Ï4Ô::lýE2Zw_!ò «Ú¥ÊWËr+_HÈ;±ÉŸ§ÕðÿE¬Ò 2±* MaÒuÐ.À.ŠS'ÃP\È÷Ørñ¢¡ Tß#4ŸÛTÉŸÛ¸b «•Vñ L¶ «GmtÇEJ.DðZò6~RÔL<=ÚÄ_òÊ–dçF!çÝ´áT>\4Ü<C’£î&TØâjP†à¹°šéñ *‡Ç¨j&ݲñ[¶~’™ÌïØ")Ëtü¾ äèô*ÿò .™¡ãôØŠLÊiÜ„´Å˸¢I% ·Ó™Ö>naâ•™vGøh;®¹½#¥f F9?%çîµL®µóZû ¼"×NªÒPœ'Ùq~&)œ†¬¬³ç 7’u]}BT*¶”-5”2™`G½H•"Ò—¢vdSp²™)àÃ7›ˆÁJoJ nŽ/N n£àv$}ôGÆvºEt¥¯°Ç9•†GñúµžØõ—&¾ÒÆKBWÙñÊD;nº¯¶ã}¡’ÖŠÌ ábn«© AsÆbð ü&–$…-ý`!JÚ1œÀ³ÎBi·ÛI¼ìµ’ÿJM¨[3xíº¿¨aì„Í<Éa[܃{É2V´Œé*–ìó…]‰wÁüsÒ¨õÃ…Ÿ²Gøi{˜Ÿ±+¾ C •ÆÏâ¿sö7$ôíjuOðü€‹¹WÈg Pz(ÿ“•Lw ¨ÏØ5;¿aGš€Ð«4–“÷Ò'XYÏØ8‡P°ëÔºëüYáÏptÎÞ :J Y†T9¡Ʒ€f´¶TL ÃöP¤Pi§4ÕŽ¡ä±½]HyãqÉ*Öij%Ç ÅÇ :4ÝTBÛÜÅŠ`ÌvD„^_ïˆNƪpcULv€vo¢ŸA¤Z¹º¬3PdêyL> . ßÿÔÝËÆÔ3ÝB(U”r‘ƒ/r”ŒeØá»#.ëVŒ;"x»;_âˆ@?þ§nÞîãÅ Ø —:J2þLFi:¸¤qÝk0&;g vn%—æP㺭ÓÖt¶ cë™~·`«a±UÚëàÛ GïtçW׳âI~=ßåÈÕõðÝ£Žò=ލ*´îuàúÞÖnáû`¦;”I¨¢pté¢KÆ# é'‡áHþÖôâ:Àúòã†W†Ÿ-HŒ‰@“®Çë?ì¨Zã§DŸvð‡FÔŽå«-Ô“¦rÔ¡.áÈùcV±¸u‹¡VÙ)‡ºsÚAã |ÆÕ_†QW†N;Äb . }éˆà½|^#H¼çÅ|Ç·¹ã ;§ðœ\ŸÄ:â-ò´®gŽD»çŽWØ…T$½dR™„‚@Ê Õuz´P“©vgEÚ¿v´þ%jѲµô´WÂLnŸ“-Kà虤ä•Ïv£‹uÌ®|®›OÁ×îÂò9ÂÔ̤˜í‰o oL'ß¾~òÀ­ŠfoK _ËÂI~p’%‚qèÛâ6ˆŽ·Ê1Û]–¯JÒúàê$òqZ2-ÖÑ\½h€ÞWïgå3Ü|ˆ ¼V]>ËÍ×uå3Ýär½Å-nMyù ˜ù!‰IêkD³Få“„eßö$ÕygÀ:9D ívǼ¢î$JÕeÑèH:ɳ;®:ú܇ߓ€ ýƒ&DíCë7©Ó6 yî rùþk<>0@==€ÞÖ÷Â\ÿ%<ÇC£;ŸÄO 3pØ¥ú§öw:i(ÿ2©·*ôð³I1Ϭß·!ì|R®|”_L¢ ¾g¸CcøÑÕÐÑŽ×SÜ8r^ŠÅÖÚ"ðSc]ÿŒaô†+@Pm=“®'ñ+I%¿¦Í‰¢_3¤ž_M‚i¸lÞ[ü:T7 ðÍÆ|A ù* =ß@^eJ!¿)>jmeáBÞ ye=…üN®o“~j¹xêBȪ^¯ ƒi¯`Õã$q^Xô8‰ü­ÏÖDiœüÓ\=ämý¥¦šV%¸õŸÌÇ' ´³ÜÐϾŮMƯÀ:_w&$—üC|?`jƒ#ÿ¶ F×%GhOgJ2ö^ö«iÉŠ‚ƒ¢š¿¹îXG;C>+úF‹n…-§%ž¶õkÓâbV{rBæ+“•AØÏ:“•ØVãúÁšd%·;ºä—0íd¬O~©5Rø†ä—[0ElDwáœ$Øâûduš>Ì%«ÕóBÝ"¨ ±CƒêNF§ád’•D‚îü·pžñMö³id¸|à@¥—ÕÁ¤Û—Ìû’ÕI·þ…I·Â)ܱŒrâ¤ûZ7íŒMºcœ “nµ“<'ôXx§ß;dl;UÐ=›|%#¹sbç¢ÕIËo |®SŒÈç9ô¼9ß lhƈˆ±ÕYÒMÄw›p‚Xèĵ¢ïà$¶Ø.éÁ¨¨¯Ç¤'­©ÝYrCÂÅGLz¾Ô)îwuÒ†Ç!˜Õ:ˆ¼»$•µ òvi®œw9é¶n¶ßÉ÷8ãsÙ^çP¾ß©„}ûܬâW=ü0{rBçRЧ€¼£8•âý F¥{Myå{Müˆ³dŸ)¯xŸ‰ñ£‡C<ù«€þ8Õ_å4‰×{oWO'°´‘â»FI§1 Æ/ü1E‰JÁ="z ú®Fô]•èGN~?è@ô£¢Ñ…x66Fáó8…£Rþk ǤÄ(DEçSü,¾gi7ð "<Rù D^—Ò¿ èÜø>uŠ·‰þVÍ rk _”§{qÊPÞý<Ž»#†{UŠR|˜Ý‰8ÎïŠM ç–¾=Eíý;RÄpЕ"†‡)b¸Ø…©z¥$ºbÂI! Ó:°Â0܆“ªc1ñ¤&_…ç‘_èo¦4i¸ÏÞ Lº›‚R¥|?…vÉŒOá9µž™¦¸zÙ´zfžçâ§ŠxŠx6VÄsji.Æ‹z)VÔ«)ñ¼–"Nä]‡ä7S"¡Vénýÿ¨¹;)8Ò€>“ÑÝ” DcÎt?S¥Æja6ºŸ’Û:èØšŽc’¸;Œc¦HªÆÏOSTiô¹g)q½Aìï>OÑd–*ª$ê¦ëJPIÄꯆ°yoFòkÚII²Œwñq® )&»Ž‡T"?n à h‘5jG-{¢+ºã(Ÿä£x"œôHfÝ1Ü´‚þ±U_W¿%3Ÿî ÕýÆ® 946Ò²ùlÄD&Ès\JÉ}ѽÝPÍ‹?Õß>ÜÂç»°¥¨»š­^k³‹7»@ÔG °ùðWÐB;/ \JÐæS 1xQj‹­Å3@X„DG;ÑatÌwuõA¼¯.}6[€Å,ø»J>96½šÙÖC+›YÏì\|Råpþ 2j³KsœµÅm Kè»dAÉÃηº‚v˜„2qíÈH®®]l²ÁW­ }„¡³ m.ç_£ü‡Éq~ '`ZÀÝ¡>ÒSZéÝè :^ß>Ü‘kMÿм ]Š?¢Ak„Xðq©›~'€äY0õœtñ“®À!_Ø7Óüéá§]‘À,'ÍZ_ºJfù#¾YÐìfû}süº²¹~ºÅéœ 8ëïü¦zYMŒ¾Á*à!5ç|hSçSÂù{ÂÙ˜ª®Š6ÎfàRk*oN^ŽÀÑš*Ü›„E…öðE©:BØ–[jh5µ$5¶$Ñ*j)æùÌk°$;os*m” Fi{Îpã`uumsª8ƒ†O˜°·Â£¥ž¶ÁsȻۑÄâáõ4͘h0n‡œ©fºë€|b:ãðX ºó­4²„0ÜNã_¥AkÐÜDj)I!¹™6¨ßM‹õ`­' Ç9t0v? WǤ‰T 5½K‰¦µ@³ŸN{£²QUß&Tõ…éꌱYuݙΧ«‡l–¤‹Š…Ó¯—ì´§å+ÒiµÇwÂÍ(l%„u¦¿¼ÕÃ7¤ã! q@£]L÷|czDsµ¸ Eí®C3¸ô˜ú½#]ÁžÐoi …ýß“.zc»X7ktšcO:¤“®êç¸Im uÿs š-‹ IÇ‚¢@ûXžö·}ÝP\m;¥Æ†¸KW|êør:úçÈ–`Æâ´ã)0’¦+°@ì)ËDs—™ØûØû¼´[x¶C}×dð¾t<Âä;WÈþ¥‡Wf–'# |S~ÄÄiÍŒ¡¼&ÅšÙr$°&ËwÊ‚§½&dD¡iÒq0¨ËÄMÉP·+Å}»Ý…‰ëi®6¦&¦¦eˆirzΞòŒ >-Cñmtë°aOÏxa¦œ™”¢Üæ˜ o h‹-‘¹b›Ã(¶k2ºŒAc4ã"LxéY³ J;" úB”qÇp„ÎBÛ‰E0J‰ÆÅJ»Žs>ºØÎPkðkÖ2CX¥ŽWdàdoZ•ÁWdÐØkâ+3Jº³¢d5´*ã¥a×Ì;3‚æ ‰l‚àMv×dà°k6A%8lÊ€FÝ{³Á·f /•l”"+Œ·3ÔS»ž9?g{3øÞŒ’Ê·}•oëPÚÚ— ìýa§Ð0"¡&~E L‡)yØü÷C½ÍsWŠ5‚ïÚV-? 5ûópçqL¶vHi:j¨ÊÖ)‘ ·¡¤Åÿß<¥4®ÿ)¥ 9MɶANo¿âÈfÛÉzÙ¥l}½¾tFA®\6ƒ.÷0ÀçÌ2ºGãûÖ÷å*”_›“÷®\6 ð«³ñ<Ò·n-­‡ÉÏ0áK7a:Ê”’å¬h9Ó•Ÿqócx  &›é)iÔ¨¹IhÔó…x–áÓl=Dþ-Evj‘zôÜš)\z®ÕåëU‡¹ÐËÁ)7ßó¡° ±ŒKÈ¢¿'t´‘Ö"ÃzÅÈÚ„ÈSZä)=?ƒ‘ˆ»¦E^ÓóúÀ¦¬0õÙ¯€¸^$nSç*q·bÄÝF,°<Ó°"šJà¢Å>Fð§Åßrôs@xÊMV’2k`”¤_wÓ1{nZ¶ÁàLùJX#©.kÄ55ÞÈŽøWà¶&ž‰oONÃ÷%*7²i½ªüÛìØ–sÖ~Æ-.œ¬B †NÅ̧S楔ù,-óY"óYŸ#²A¡zžš;ÝCMÁ±¾šD^ܬòVq¹’a63ˆËß¡lÚñÊ2 ψšÅÍòè¬G }é¦ ço•¢Yþt¨‚™0x:Sþ\ôa¢-d;%’ÿ؉¯l†¬)²‡¯UyºNBõyÕ½‡Rn•Tµt«„ëCçÜa)gMYAšŽùÅWÝxÄÝ&Ž¢iŽ«#tç$~àÂÅ×`Œ¿ˆ€s©«§à \"ñ ‰÷Ò¹þlƒäLY(zÑ}Is‘…XBÔ}ò¯«¯ùc©d­©ˆOгô97Á¦ð¹¤à‡pÕ¡Aî «†Œ(þ â*ä'²£|” O®•x¶ÓÒ¤7Z„ä6ÏqGiN£³çó³&gÊlAï8YåÝ8˜^Ã>·Õ0=>ÏU1>/T1 Ÿ òË 2Ÿ$k*<Ïœ“Ê/ 7ó)2îù.[䊠ÝL“ƒFºu†·µ3j+3å£Ç”dé #9¬$=ÏòÔm¤l¿×ëøXôKî*ÓëȨTcä5FÍ3(ÈãQqï—öÛÙ2ææü9:¨7Bf Ï "ÏÔFÔÞÚUã—Éð%”Xúœ‚Ÿ¨ÆÚÈ-zPþè(y‚œá“Ô‚,>Óè\€˜ç%bžoÄî§¡jì¹IÃŒûqÍF\Á·FZÛÔ­*ê…Fç[ˆº]MO¤,5RÁÐÿêê!>£ )WG}R.SS.7:“1egbÊÕF¦nDÉ1Á5ÁZ£ó4*›¾Y ÝbtîÃÐ.*>ß©ï2:Wâ9ÿ¥èŠÆñe’š:T0ªÇüG ¶K ´@F^Ú(°îGj ž¼,¬¤Àz-Ð@^6P`­(‘—…í8A ”cþŒdAf4½ÿÐ×gÌ~Þ7òy_øyŸ­¯ï}}?ïëƒP¾ßˆ>7`X<Ü:Êa8HÆU˜Ï ­aWûÜÓ/¨®¨>ŠGÚ˜ö#êx'j—=iä§%džÅïs=6Lô–3F1}5`ü¬Q½¬ö"j%D? D½¢^#¿EÇôÈœV ÝÜm£6 Ü1jWßÞE$ É;„䑆䑑?¡yq$häü”äêhöznÄUÐf&ÄÇ¢fu´‘."¤ÿ7!oÒ„¿÷Ç¿à#ᤛ¡-V{¶rû ù57é.2¼a†UéKg Çÿº‚òY¤{é!hvüгò¾Ð¿@÷Bì]cÙlÔ¿–fK,Åõç·Vb @·H÷ºÃÍÿ;4ým%TçA³¿ËJ;²òÊ;²ø=ÔÅ–Á¼‘âú_”ò¤¦‹œÔóÓèùî©8S ª?‹žïžºù9Tiž¹ùù˜JsUšåÀ»W ¡A'tè}’£{†„ *5i¾ÒÚ dÐ'2}†W£tßçFpyå¼ÌPÍ€.1\‘Á$Óë ˜2X™scðÖ¿JĬ¢¬¿C1-ëˆÁ¬*=¼³íá=±¬ŽbV ÷¿½(ãÑî?!Ç]åc<è¶+¯¼Êš…††‹Õ t=Aºž09ÞÒ -+Å•E1P‚$•3)¡eɾc&´ÁXKäÀlí÷l‰ÏÅCÞ»³@¦‡œºAž‡|ÖðßðR x©Ä—KáÀbẰCÊWbÚÅY(ç•õðÕ±‹NÈ‹Õú„,·jX„à–a´Ø¡fÙ…À² rŠë˜ž ?“Äq8áòÏ šÃ¯aŽ.íS³ 0a·ô²X·œ–{€ºc?Ô)ç³TN7ø)¡'î©èÖø Ms(Ö÷ÄMˆdÊwJŠ×x&ž‘ÔãBsQ(ì¡ð‰Ö–+e±¶Ðm3Š•mF¾ƒèÂÑ4¥ÿ[#ŒÞ»|7)jIb|~ÅмÇmˆ,Ké*Іé}F¾Ï˜8Lï7Ɔ鯄aú`<Äw¤~g6ƒFšAÄwµÓn#ñ¨¼ï¢1r0EŸÕäæ³F~Ð=p£ÿP~ŠU\ïaü"âÛàš–àš‘ß düø•–à&&ØCcælÁ¾;ZŠ;F~µîÆ«Ÿ¶Ö´w÷4êt¡éŽó蜴 ƒ[úvÚ´Ïý ÍëF™ S‰ ·’dÜÜŸE·èt’Z„·=ÅúïØ¸^ƒÂóÞl  %dôÏ1ÉhÚ¯JP1ªÇP­!?eÕeO†òɘ~qåÏD·4©û-3Lt§Ó²d2ÒœmÂ3èx¯%ǵÀý”ªŒRµh¢‹‰·š€3] µQrÕ]ØiïfŽŽ]ék™,ÜÃ.3•¬F!—Ó‹× cxµ‚•Hߪ„ ¢ÖjY­5ñ &`uJ±¸¹Iäõ=Ìk3ñ3vhKnÚU#(¾Å¤†ÅÙ ÃŽn[MTa|Ç«¯ŠÚ‰E»lß…d$|Ÿ¨Ú¯QµßÄ"Ôm€:Œ7F=r«ëbÝqwÖTDpˆÍ¡[CÐmâGÁ]@pBUÆ´“*i§1åg”ò/(åy“ºÜxÞÄ/šÐþƒN]2)ù Nr5ö¯‚ºÚésJšMIïj™Þ5ñûè½ä›? ‡- @O5 §&þ«€úÈ }ƒ€Æ˜5Ó(3kÖdÃòÇn^Î ÂÙ[E Öj°µæ^¶óÿauf>]x@uיáö×+î±>Ù ,òw SÿH`±_øJjŽÉn¸(5ݬ„»ÕìRÑYÁLå!é³ÍØ<ðtÆþ êøX÷íÒ9ùU?ÍßéÉ¿ô§ùÕ?}O*Ÿ:ÿ‘Y~éÜxÌ{†ò¹¼âcýKçäßþÙ{¬|D?6ìe¥ó BæÓÕ²ÙéúdgTk3d˜I$6ú*6ùJ6ûÄ‹R¶Ù1ù7ÒË÷Å·Ô£S|Ëñß ü·Ê£*@F€-¾’*˜ß;=EUE¬¢ª¨»t«¯d›/Ë_Alþø1ì=Ý»ú¢m>¦ÖŽaùíãXþòqì=†ñ%œq¦Ã¸;Ãò›|–·òß‚F’–øûãàåJèb¦ëO ïßá[8Wß_q—MÏ!¼x‡Mïœ ÿ„ä B¢þÉ£·ÿ÷%òt,¿^"ï‚ÿ ‘‡‹#‰¼ö¯D˜ŽãÿŸšfBN~úSddYE*ÿO-¨G0·ìšžŒ‚ïLIÏ?йŽ8¶ˆŠÔ7w÷²Éã™n¨I É¢=’j6”×Ò!š®bÄ3¢›O Xõ;œŠ“ÕD-(L'óë(Á.-A½ˆÝ• A  ¦P‚Z‚©"vgB‚iZH0ƒìÖ̱»ÌÒ‚D‚9 FEš Ešß¿HÛ¯HMZHßÒ¿H Dlb‘Zµ ‘`Qÿ"-±‰EjÓ‚D‚öþEZ*b‹´L  –ãÒêE2!ú€j±“i7 t2r±—”ÃÓú»†XÇT·ð¶aò—/¼îˆK61k —ofÚôº3»D‡ƒ2;™æãÈq9[‚–ôSåÍ’o}CWñn1vnÍÿ?¤ÿ}ô?b +¾e]™b +07qÑwºh,Äoì^ÅM…\ǹBˆóq^Qž®"/†˜•5B¢i&JtçgØÖµDW¿ŽFÔ0¢†5LPÓÔœ@jª4j¦jª~ŠYC|-FÍ7‹¾©«ø¦†øÏÌÐß ÑTAÍm fjŒšëÿ5} 4í45+5jN½§RsÍNˆO½‡ކøM^¢X\‘~ÃýÁ¾¢üCÖÁŠ:˜®¢ƒÅ q1åkÙ’¿£8ÿñ?`; Ã4VvÖ5QC +e èúT+¤j§»™FÕMÊîWÝï‹~¯«ø}BqŸ¦…•õêáßWøož±_—þôY\̤,.ý)6{-‹^jƒ ª+¡ù¸ÎͳÐþB|Wz"a7ÂJ¸l¾GÉ¿C—næ¥ÞÁ „}÷‡ÐÁS<ÍGÕˆ¨nÇQ5öCÕø2ªÛ?ë‡êNU¢ºGÕÔUÓ˨ªûSu/ŽªQÝ£jùeTwúSõ ŽªQ=Œ£j釪åeT—þ´ªGqT Õã8ªýP-xÕ©÷ú¡zGÕŠ¨žÆQµöCÕú2ªž~¨žÅQ­FTÏã¨V÷CµúeT³Šû¡ê#cÈ¡š×à¯Ó~ùf^j¤7“é÷þÄþ&ó<Øäñò¿ÆŒ&áîxTŽ^o2gÞÚa˜ºì0 *ôZýS´Î11“y·ž@]A)433poh¨¦0 oÕ‹FŠ3ïðjú.he™¡v?¹g¢;†+ý"ÊgfâÊ C•Üp`˜ï†ƒA ÊF³4ÌïÀ?Ìé¸\ð;DqÄñîTúE”ϸÿ©îY™ü_J;õ%+‡„–úÑv.û1{=WWbB"+ë‚þ±G:õ¹:@£BºR/ ]èbff‘K°¯ç2>²Ä¸”‹°²£Nþouzrõöï¥ëôj½ïB®|Ê@þ‡Žÿ'šÕæ@U¿B4òó›%ËbZßfÇ›Mô{Õ[ùÑ…Pc²QÔXÕ^ÌõXÄ(çÀ¸¶œp‡f1/ï×!žòµ(—WS5þè՞ч•6äÿ8ÿÏóÛ*Yþ¼o©¾ÏeÂ÷ùÏK› ÞÓ•5¡ŠU“#ü×oÊ>PÛËô¢6óÛ¸_órͯù? Ykz©wä%Ü¡½ÂM8EKˆ¸‰œ1b|Žrʧˆ'LÍê ãÏú5ïðÇýš?g1¿æµ9²d¶T3J5Fók>Fõk>Võk^­çccþÉ¡Ìhêÿãª^M¡hÎ7ï[dηÿçUGù§ªËòM0¡l†ßù §º,_Aà·Q×j®ò'Å,V º=Qô£W»&ߣ¿^õf¿ÎC€XéstÌ`À[Hôi€dµšžï7°r G7S 9qçå“¡v$9çV€ýYþåèþŠ÷Âÿf­þ?ñî³Tá“ ê—Àñ_+¡.¢¦Rê, /Q—7JøßCÂ. ÉgŽläßÀ @¤–éþ£—Ýý.ûOþŸ¹ îô4èá£GÏr͵ØNæåêüP(¶Å·ÛÚ ù(Já•L„7EZ|{ ¦/Ëa@På7iNg Tã|;#!zy,z9^ú€Ñ3s´E T²B]”˜ÌrÊ·{(ù7‹¸!ø78 3o털ï©üûð[ö_£ieŽñƒ(~˜–! —¹,°zH~¡•þæ\}‹o•Ÿ¡‹¡¹Ð†ec.Á ÁÀC/@wú±íÎCz¥\ w'Ñ»šèÝîÁßûS }”ïõPR=?GfV™OlúD÷QisZkü4´d´^Cˆ]øÔ«Oƒú”èYÖŒº1ÇÀlö¿¼µÿDÌoq‘Κ>T ktå"¤­P })B°g7ÏlöïQâZí–‰ZFŠ×a0¶žzM=Þ:qØÃ'³’:Cq(ðS°m7ûmöJ>ûÿlJühI@Ü¡!î`|%„UÄ«ñjDöðµ1Äëñ‚Ä›ñVJˆ[ ±(nTC%ƒýPTE܈!⨇gJñ¼»í„ОA´g) ]•m³ÿ=Å<ÖÐ>fü)t«hŸÚ>DÛíá£ô¨ó ÃÆJ}IC|u>¦”5½ 㮀{òï½Sä‹ßU8¤,N `ÚšÔ"  -c‹5c–Åz¾zT ÚõCù2”Ý{<|¹^ãX"^’€x%"î¤txcJŽÁ`³ÿ9ÅlÓkK%Ûôb­d›/ž@œCô¼ ߊO{ð ´Ì¡¦å¥”Gg^ t; sa–å˜ì6û ]ÔÓ2#º° ¬ð·ö²ýõLw2»ûKvê™þ:<Ö3‡ç¡z&Ý‚çgõLÆ+?¯gÆM†^v¸ž™6ø½ê]=^\ÕZßR¾£oé+‚=üº¾d@Ñ]Å€£ü+}„¶YnꣅœëK¼E^d/ñ[À…¥Éת+^CWvz¡£ž ê2À¿~W‰¥âS#¬¬õ»2s.ZúõéƒR(b…0øŸD»À†@ˀС(#epÞG¨Ñ€ê#¨>«öšê3‚ª28„ªF¨óu^@ÕÔ¤!Ô§ç„P ê¡È±– &Ôƒs š~‚ÛaTŒá6þ\/2 ÚTkC´!¬TéTÙŽUQ©z²!§R¡b6„ÙJf›·®¯Ozø¼o@_ßOúú~××WG÷RSÿézY¸ž™§@Eê™eªO1¨µ2ܧ´š°òi~A#qžOW™?à Z‚Vâþ,rß ÜÿyÑdZãÜ7‰›*‘ -çEhE€ã`¡XdpîB€6ˆñ–€vƒ³–!@ŒÝ°\tœ•Èé?àÞ |n4¼‚Ï ^ÅçůâóÒÿšÏ À社¾7úú~Ú×÷Ï}}ðÍ;‰Ï)td%hÁ¦¾h¦¦½Ñ½!Ð\€þß‹×ù%¾É_¹†Ðz?6ÛL_}™ùŽ~%» Ñh¨Ö&B(²)hni,«µ9ÿŒ.ÇLlûèÙj—HŒ š ßÓ¯q#ö½<Ö(B(²)hìc„}_¿v4” !4A®slQ…¡ÊB2^Ç@» ˆ‘G b\Øà×G}'‹p>^ž#ÁÐ5UOÃÒi´`ûÒ „>óÐJÝYÃP~Þ€Ã@V/À÷%CÉkâ{…ÆÆÎ±ñŒtáúñCàá;  *~ôŽ_¥ô?tÒ!›k†’?Pê?Àè¿Ñwiæ•òðêíN Ýçži®ÿ…•A)y›R¼ÍB3Œå<¼71hš±ü ‡sC,„|SÜB´Ÿ“Õ^|¦ƒ÷_ _µ,Aú‰#ö JñI˜£}_ˆ+6û7‰;}ÈQ’Z¼â§ï0^‰g†€|:+´"G¶Ùìõ‹ÃBÝ0¦ãi¡¾2†Š wiÀGŒèøÜ_"ãxãBxÖM‹á±î›æ6ɹ{ßD Ï_bN‚·Àî!Ø”ê$ç÷ÐX»!9Þ¢u7Erz0n„Dê0nº€‚¸’ó9"…¨v ÁÈÙ±È9’ó,FΑ‘&Üb¾È7Jß×(97 \‹·é/…aôš ©½ßš`Ó]/©½ßš`Ó=UR{¿5Á¦{¦¤ö~k‚M÷\ ü\K.lº›(ð°ø²M·•lº÷>ï»ð¼O××—Ý×÷×}}e¦{¡ŸíL|1z9/áPlæmô‘  g=S;wÐì;ý–DÃô û£kµóVÞ.>jme}V¾?,cö2ñ10p/Ǧ±2Ç`³%5ÈÔ4ð°Ôàá¦ÁÃÍ+6ù‡[„œ§PÎÀç†J¦_Ïc0÷†çqh)xAæ ˜ûoÒÁªÐ!ÑC×JCùz¤XQ§1çå›%µC¹ÊÑܾ"2ÎØ&źJˆ%#Ëñ0%tÀS6ÃÈwB E¤Ø@‰(ÅžÄ=eÓŒxî½—­­dÆØz+™é DWA¾P-áhIB›ý#pÜ=(r€¸HP²EËzœü«„ kzô•~S ¬ýVh»¿"sq¯„S`Ù¢øP¶ÆÇoÃtíÃoñ»ýðek}üž4”uéWÖèÚÝU$YçR#­ÐŽUȼO#}æÁ[¦HEƒö‘<”€?Õ€?¥¥p¾À+ã…Ñ–FØZYŒ°ÑðNB|«Q1´þCÄø«’ÔTàí÷§ÆÖýÊ?¢$¸š°†ÖY„š»Z¬î[»Ç‚¼:ÌE4—Wßy®üª—ërðB;w¾€[ ¨]¯ÏÁûèh}óªrŒ‹õ/Äwâúæ¹—×7ï¿Ûo}s#–ÏüȬ+V²UðûÜöfàü¾ïOÓîm;ëAZ𦶄…Í ˜Kré­3PZРùkJ`'éÂŽÌPåOò~¬/¿àáßTÄgù%ºÐ ây¨éÊÕuãYN ¬„.xª!e»ü|P øôó00~ÍdcK ˜ÑŸ”ìV—¦³œò:="¯·æ˜€2ÚRÞü‰nTFiKA®\ÞRÐ˶|ª3J¼á(_Ÿ[?ÑOÈ(m-ȵ–·ÂçÚ S2Jä(_ŸÛ>‘fg”.*ì¡¢|ËÞøË7¾›«O*`å‹Pqß*§$ÿý­UøB:¤ÿìgº…èmе$C ìê}-¿­NÛB+àáK!0æ´ü˜•ßöðe"(I ºçá #6™ø ô°=G2Hò†-ÏDF¿p~¹<“¯ÌT{ý¾}~]ù-ïÌ üÂÞ7Ú(“ë¥vùκ>ޱ5™| ‚T¾.S Ý÷uІL%"\–]óðM™JÉ€Hè@a$t=‰–_õð­™Jñ´ £Dä}iç‹`×=|×+’îËTruåw=üæ"¢Tš‹{ xu?TÒ©yêÊÏ ]Òu(.f¢U)-¥!Žøq è). `dWŽd•dh{‘84`¸±—Í®fº‹™½lN5cøüêßõøØYà W๫†IWáyf¯¯2éÔ ñf&¿’VBW=èýV\ÍŒÐg­n¸ ¸ëŠZ€î½{áë¶&äý~âÉ­ø7T½ ž„ÃøLú@8G#2Kà™:òÓ pÕt0üí÷óÊ,%tσnáx°.£Jè–§é#§C§S'¶*Ky}¸Hªn šƒ–²»³ÅlæÕYA#ÞØG]ówȘ‰YdC?žéê²x]:ÍÅU󆬰ê/ô™j<™BÐShŸ2BT¡}b jš†&¯ø€ŸñéYxÿ_<Ë9±,çeñy/fÙÔ/K4Ømî—%†´ôËÍÍZ54ƒ(Ë…˜åîÙ)Éó-˜çÈsÐÑAè9_XQ<Ü8¥7nA'vðÞw ž4xx2õ¥5Y½ìb=cë²øú,t¤{ Pkah°ZPënÌ¢¾“Œ‡O/Õ3ýfH}„¢­ð¼BѶ,¾9kÐQ¾5 áÛà¿Ì»áë½#5³Lú UZG¢°ÁwfåìBí(™ïÏ¢›­Ð5Ìèèü =ô*¡+žtXù@VÞQ~0+('Á¬ßèΊº ñêUè ÿˆûÝð¼^ÏL²x$«¤8PÚR˜—WTl@~òhÞôÔd*‹ò#ð8èò—}æçÝYJÐè«ô²‘Ð7ŽeM蟑.þ =Üd)Å Ë~™5”_h×ihÍübVЬ¡½ïq´—­¹Ðò«Y0ãß÷ð[¢üÚ¥M‡q€ëáën¿‹W‘'0%¡èx®te÷²‚dCòdLÇë™åøV=³>„çízf{Ï;õÌ>ÊÍŸeETÜÎG¹1YÐÒ‚GšG wð1î =è(>UÄxµ…+»*o}:G"Ä­†Ûø87Œø_4­ µ‘w«m+hk£¨s=ZθƒyR«wcIˆ\tAÕ€Ôäب¦V“¢ê>å¦þ ¿B«wP¦3Í3ÝÈœöYý’R*Ê$ûœWƒ4©3@«›&ˆ$\X‚Ö±ÜMmR‡›/rScŽxÉŽµ¾Š{a®tåËÝ¢Ë]WÞ$Þáïº:ö&ó•¤×“‚.ƒ:Šùæo]1´äêŠæ›õå½¾š ?†„ÏŵŽÂBg S°À›Ü fî? ñÍDM0)˜\ü™WÏ·¹E“ÝéøB$øî%<ÅMß…îå‘{èzΰ[ &•ßðð¼$—åáQwlN¾éáGÜÐd¹‡Å‹f÷ÐØø8Nr«²é)7GÿÜCrέðóðyãò¢‘_€Ï¯<*# ¾ozˆä‹D²€üÊCd_Qɾ®Ò‡†´·Ùa‡ŽßEöæÈvIÞaD»É¬M¸Ò†šû÷lHgwaH[ ÏÅ6Ã:žõ’6ÃcB“·xÄ<ÙÏ{0BtÃó>t¼cð|é ê3sµÒG*Ë1dãÏ0Ç(1çпë¢ÀœêÆ¢Ù¼;[ÉÕ½Åx (¯ñò£ÙJ¤|¬—ƒpö:zr‚éf¬ï¯oc¡¾©¥¼ÚËc.Ÿçõ²ñMÄüE¶f”òE6?å©ö’)K. cêæxòf`Âá™ÙìëØ+¬È¶¾2”..øÖ>V¾¸ú;†Ò¶‚o“ÊÛà{Ç'†'†Ò%¹†ò%ðÙõ‰T)•¶äêËÛásç'rTº´à ©|)&þÄ8I*]V 5Þòe¸ûÓ ©tyL»ËásÏ'æ;ÆÒŽ‚¼²øÚû‰åóÔÒ¸Ž¶‚܆XáseA~s`P~K`лú²•¸\¦ä˜Ý1‡ZÜ|I!4I¸VÖ,•Îwç•Ïwó©ôXá rqà=¯ì²ž?6–䈛Ø"’‹/ôü ÅÞ m¢„:½ä½ý*éYtDç9½"HÙ"/»m&|Õ"Fá¡Æ#DQQ4ÏÒV ÊK¯¶ÚDØ1´†^)ôSÓ‹ÔãM‘ãMø>©¯5%R_|Ñ@vûÑ>ê-=Ÿ„”tÇ«b)²—`Uôäè¡*þF¬6©U±ÚÄ×âéÜ%¢*Ö™†ò xUý/ßhRŠ×yñˆ,ÞÊP¿ˆô4 ]ŠHÅ‘^Ð^0ñKˆt©Z¿€ô*"]êå×T¤×éqJ›iŸSÚL÷ÜÄ+Ì0¾tÀø2 Ï žÈ‘¬Ðþe„o‹”&´±Á•)J2o¯a Ÿ;j˜ŸŸ60>Ç50©žO†É³Ì¼ÁÖLb¦ÀkºØš™j.IûÒYèÞ-vº9(O{ï8þvÉá ,c,Ì óP>Ë<°Â 3Ý3UÁ/;i˜žk.ù%~û~ ˜ôàÌ¥#¤4_/Ì7—Ìר|½Ç›`‚q­fâªã23o…Du¸–%N<×yCsß^“Q é_‹ÍJñ~àå2Hn²¯Z ÈÞaš\!³e¿Ðy=‰¸5v^ÏWŃ/`0î]Ðó5æHŠißÀLë€gµ «¬7óuˆÞ÷¥…!Ïùz3Š3¾øW¥û_›Ì%Uú°¯JÏò!o§!ÄVsЂŽþøv³–—M.,MIê±ÖE^-p¾‰Öl`§¡"#ÙhGø<A4¦á»ÍZñÌhp¡âÞ£ÁR”™pïÕ`]„ûa ÷> ž‚ ÓðCfZ-3«wûÐæá33îöAªÆ ¶Ò/rd³ÝQEÝÿ$³=TÉt'Í´6€ LO˜· gà9æexNj`òxÖ50ãU3?cŽD[PH¿l~ãM”ʯ˜KÒÂAÉwÜÉ|i å««"„§–ÆX°‰_3£¬Ò”[ WžÌ‘vGu.:MØ£L‚3®^€äÜËêA¸Ù7À ýž“̧ðœýç9<§™•Ðͦ™c,ü>0jžW'"~ô—òÀ¬Ä¾ËçyùSÁåsÔÈCSŠ:¨s<{!´iš*CSmù¹ˆ;+â&«)ú^§îTZ”Ðdìt.4|Õ{£Ë„çy%Ô¢ø²‘À¼1"¢#1¢c$ðp¬{‘æÓYí`øéK£¯§Ð©q¤ëèGã,az^h°ÄúÞd‹ÚN£I8–O¡Ï(¶È©­EJdÈ6¾ƒ¶Â'(v­`œg!Ö4žÓ¡—5Ãshmxß|-³.µðy¡>̧§™7SÞ¡ÃìZ -%úùãŸ0Ú]d²M]Ê@Ù|)®ÛÛЇ` úÅr _Ž·´D§>h Eýh‚æ[á5 D¿Ò’:lÎÿj ä«,A;PB¾ðVÓ»pwÙ‚65Þ¿0 Ãõ%¯|Š—oˆ³i³E š@Ì®Cí߉BÉ6ˆœí%±wOîópß <Üç!?hÁs½$U|›·bQ¥pÅÂ#áAŽGá{•˜»-JñJ,{0ùéƒÁîh¥Þú…–þ ‹³÷SÏZÄuÎòò=xh±uYdrYËäŠÈe‡k´z±8}èéÊ&öä_ÆÏX"ªõLzÛÆ¿TXÌÊEOV.z³Þ»³¯O_Ñ×ðÆo ¹g@é°;ÞCjo[°3gŠÌÛ~×¢:Íx@TÅdˆ9 Cü ¶¶Yo²GþÈXRèk/Ô2«éþ HÞs¡³"ú/iÎEô£¬*3FYùh«ê¯pŒUˆÀUx•úÙø|?NgåµÖ—™… ¦Î*ØÞ€iÏ‘AóýHËZ‘f—àÝý p>G† Šh½UõP±ÞÊ7ZÕò ²:aܵ‰B ùkÉ\_`Œ/¿m4Ë?4š…ßc¾*Ÿ¡h®Á qP¾…([U9ã°•‡­ ®ˆO;mE`t,äG¬%óbg5h}óãÅ 0~1ž×0ž·ò‹‰‰f7` }‘Hq)G‚:$éý¶–â¶KÇn[ùݯOx9žU¥MMXiãcl_›âJ–@Ô|>Úí|‰:º:ÿ„|ݾË7aÜ•lññ3ºoµÖ‹¯-èɶÝyeŠÈפQbåÛÉš´­n£¢×a'g±ä^º¯Ô@i¸Ó-äkì*< ëìA©o´Ó@v;Ç`´;þË¿ƒ.ê>4ŽévØq…’ᣦD­Ã øhAk§ï´—¸"Ñ"—¾ÂòË.;z÷+[r®=:ê Êäéo—wîä˜ÓìŽ &Ìàs;Ú ¾b=tðð”ÁÃ]ƒ‡§‚ 1†é>‡œšïŸ‹üñѼÆç Ÿ­ éá¨5†a¦(<‚œrÄÎÃö’•,\´’±Š•xÃQÄ4ºéÜáxâi0<[µ„b˜ù»OŽcí¤áÖÔv`ê2q…M4(w¸þÍ“)ÐE®‰IØ Ê(ž³ƒ ´Ú £%·¿Ÿ« ,)(ºý}½o³W¬¸BË/Û:çêaöæ3M\iÄÔG,l™k6¶E p݃‚-n`ÖGv~ïU¹ã'5þØ ´´47á¶4®‡>µ+ð#â4ògö MØžH /@ÐZ²×óÆ7Šöz˜;Ê‘‹{Z•Ž uÄQçqRAX«qô²¶fÇ+Ý—40G£ƒ×8‚F”ÔÆ;^`Þ0¼oÀÓ_)è¯lâSm pŒ¶Ý§:´¾€ëŸ|±£J3Ýt 3shD¸h’µíZy“x³#˜D9Óâmf}9ÙÞÀ’–KXò x¶9ñÊô©ï¦ìqð%"Ñ‹ŒMæ+A»ºpLŽ6“¢M-M™ŠÕ;\]ãPà‡ì :ƒÉ|­£dŒ@‚Π½¥hŒ7Æä ”…‚Ž 4Î& ’“ЩÕfGPÎe¸o·ÛAIG Oá{¹äCJ®3lÎ5Sš›r #†»ø^GÐU‡45#t^RÕË–50WÔÁ£Ž7¾7bx*?Äu âìÁÔæÆ`ÿ?¼½x\×u.:ûÌ™$Á”c‚3mˆTd¨ÄqÜâX„c‚,cbË–éÈÀ†ÒdœÄy¹–¥ä»/WÁÞ H°“Ø öÞ«ØÛÌ€ÄÞER‰ÍÞ‰»þµÏ™‚B2¹yïû€9çìò¯µ×îm­:“¿ö±ÌÕ«<¾Þ6ü†=í·OåqŠ…kínGû¶íq>ÇVÓq‡(Ñœ¥©êœŠW£ÙÅ¥ZÒsíTKŠ'U]í&=S•¾CÏ%T¥Ðs)Ué‡ô\Fs̱Éòb;ŒÏSù€ïrªÝ×ÚÉKí‚‹´¼Eš%0:]^æE)þ:jû©^è »ñ’×ÞDy­]lMÇò:ð% µºÙ. çlH‡‚í[ì^SüÅKòN;´|¶$šÞ{í‚Ýeéò>žåéòA;µÇö¨޾¥ái» :Òi˜qê§=êÈâÁ"á)¥éì·é±’*qIrƒ8ÖµM_z¬¢šÓ?Y>mgÌ# íhÒdL&yædXuà³ÊìÊõ½$Ù˜w¢†—&+ûmÔæ„‰†!»¯ v>ÔÙ˜¶r@ræK!lÚøÚÖälJ·s®Éɾv.Vû`¹»7ßCÈ 9~`µÓ­]?@‡& Òš{^uÐò–Ìsض<´Ëñ$½x’ôÆ$“ǧ˱ÉjæX– )ŽI‡ú&RìoJqÉ`Ñ®œäu;#y=VSžHÏ¡¿pN¢Çš±"uj²,O6æih&$›R×¢Çåq垘lÌ÷Q‰'RtÆHñ‚!E§/Å”bªœFR¼þó°RàKHÑ%§'û\,Å HÑÅR¬$7ÊÕDŠYÅRl橤Hò˜™ŒU_*Kq–!ÅÙx’ôæ'³Î_â c5‘λ÷ “»åÊ¥É\3¨Ñ°ùàÅz;R?½B“Ë“»R½¾ã¶Ó€õ}6²úš±Í(–=Ér3Ÿ”žêCõ[K5wG²Üš©~“Òå6`T¿ª~ÛÙíåÛVÜ‘lÔ£¨/κõsÜ—¥ÙŠ~—(ÉÏ8püìI~ÏRb«•{“±)æÓæ>›±?9„o–é¡d,IGBUFCªR…ªEA›œ.ë™LÈ[×NÈÏamþ®ÛNœìóÉò¬-,—¨ÅIæosP7¬–ŠŠö‰A%ûD­ü*9džèù×e”›Yäï˜Õïïª]Cpi(™F»ô[4[øëóeÑ=•ÞMÊ䢹?óžá¯MÞà@7Ì@7)Ðéô®òV\ Ûè6:š/ïP 3„t7.Ð=t/¹h¹ðŸþ©¼OΩ\xˆTÞsëzÛvÇøÔlc2´!×+-Aɬ%¨_Šì›bèê—BSÌx}AR &ˆSœuMޱ=ˆ)¡¬ôÉÓÚÁ)j bXLXš[Wó–∔æSmìö¢Hë(Ò˜”ÙT²*K \êÌ»ÔQFPCÀ><–^´8»Š¯3\îÈK;“(úzŠ>#†æÆ±DóŸPPéM«L‘•L›>@»´^V¥Ôt]¨Ëjº-tÁ’ã¬ÞáÀZ÷l~ÍZ1HP›ØV°š¥9)¼/ÿ¹üÚÄA ,nónÊO!â%)4‹Y–ÌßOhyŠ9+X*ò– KñM®HQ{E+SÈ‹¦"ç(}»T†­Øû1ÀÖlcŠÚkÚËÌæøè˜ðl!²‡ˆìVÀ<ä ÍA.Ý;SŒ|Ÿ÷ï–)¬¢Hi/=7Q¼/EîNaÃLMîm"·}qrû„úÂ)a+ Õ‡Rb÷§øtW°q:¿O5ˆ[ñgi¸ S›»5UgÆ­oIÔG‘¬G¼Æ‹K§R ­Ã§T’N¥È3œ„%áœÁ !žO1·®xú¢A«x_¤Döº.þ1Ï‚jxáƒð_Q¦F±zED6Sûw7EÞN1L[ÞMç%¿«“÷RÂÍ [ÞOé)§Vü`¾]ŸkcJK-× ÛB™Ò×)û:a»©ZçågXÙ*ÉùB4*ètfá†Ý`å>Ëtât¦Á}˜rÝÝpît>æ«|Ê}Œé>Êé¼÷1Ê}¸é>Öé<÷qÊ}„é>Þé\‰Ã%¸»ì„¢_¬Z;¡íwæ[>[Ì»Aì8ËtTwãèºs7‚ǘŽêÎÝhvn:ª;weì8Âtl~çΖîol´×=m¼þ´ÑÞˆ›ÐßmlÌol$W9ÁI RQÀ&9Ãa,åòVÒd§2™2ÝÙR¯ó·87½•ªH…SVp®ôÖ¿…˜g9¯GÞNÂËl%®‘Ýs.’¸XUüå4J9a/`®Ó¹‘ç7‰¼ .$G®ŽÃCä…NçHD^É0øÇ§ócx,‹ä˜á±Üéüi±rOÓŸ %©²1ŽéQÝ#LìÎL—¤"‹ ¦©AH,M•¥©`šëZ’ì— ¦“"LHU!‰ ÂÀÔ(ÓƒRã˜.IÝžH³rÅôÐT• ÃSaR›÷/ÞBy™˜jì_LL•ÓSCþpnÛ©œœ!4aJU{)CÓ?áQY…SœFÞÚË£Ày&мT¹@)“©<{xÐÑâL4xI¥)Æ„t¹ωére*£+ÓåêÔ 1± ŒL—kŒ¯ Z`TºÜ”ÚÒ ˜UŽeHºÜšÚÒì!¶!ÄÐt¹3Õ\ßÞ“Š{$ì¤è±‚Kcúƒ‚÷î©{ÑB£nS—É××&ª£¯°o|W"H…æª+²VÖV~åzµ²vòš+²V–,¯¼&·°V–ìkgòš"¥Ëç0x½ÁÜ8¢¼:ä-òõ¥0¯·ÙÚRbyuÈ{.Õ|A»ÅhÀR‚+ÔQh»¼oú:|í”oНáë™gŸíç#õî@£÷ez€GP]x´7´—ÚýãÒyä4°}O9¸}dmmH{(…ô`"ú7|ç–cay{d{µ¼=²½Ýžª5cÛcqysºÆ§(ËÚs;]•ã€2ˆëá÷€2Ť=¥½œÖž»å4˜J™ êgµz·õÙø¦Nh.âæø?âKãfüÅíå2"3Yñ¾œx_…(Ôù®Æ“ºØõíÍ.v@†x4šô~# r|¨°¡¤))x†¨Nã¦:g êt{ùyûæK;ÐrsŒ’\N—ÇÛÃÅuéòDû`Mq}º<Ù>èÓ‹¤ËSôb+®M—g@~¨›À| û"‘——ˆùšôÔ¢à¶7/.Íž™7#Aj¨czð].y•>«õ“kì×÷€<ÌY—¹ ä»ìïBS}_Eƒü@á=0ð*<,¨4MöOËl['¤e¦ÑD>-ÓJ­Í ´Lµ)CÒ"µÑ.‡¦Eš‡žfnåNíѴ¢cùEÛ­áÊdLsF§ù5|a¬áAÍŸQ*KÃP˜½ÆB}zf#†Œ8]†{çõéKØžk9û!Ô$„Ûb•f P¹A›GŸŽ±œÎˆì\‘Œºô¶€¨LÃ+œg§™[Ì`unZÑñü¢&«óÓ|ö¾vQmx˜¬.LÃÍyöZLµ±¬Úñ­X]Â~µŠÕ•@å†x5 V×0";¯KÆÅêú4¼Ây3§€…ÜÓŸ-iFË@­ÄVŽÂ¹Á~ÛÒŒ„ZíiÐ:êÁˆº;JÃA³4L“‡Óš× ^ KS c²Æ@ùýjU^Cª3êÒäç­m „‚z @£H û·[ù’KOwàÃUM¤Qš§¥›+Þ8¥…÷.%=NCÀ F:Ì á"ˆ|Â@4ò&'LAõíôW¥gðÎD¿A`y§ Ü`l×ýÚÐrh@ð¾·:òˆûkK>©—ÃTxÔ”{—¤[åðT«ÒåèAÌH—cðºÝ¨H—eH£=8xÆg±¦t0Ó*õÓ:Èi¢©žÑ¡ÅTcRÙ„43]Îä˜hû¼À„\ÐA.êôžÅ®C°h@ð²D½+K;¨yÒ2ÄËê þjŠ/×uhi„ˆâº¾Cd„¸©ƒ!nB™§ÁXÿÈn“ƒÝäÞ<Ùç&~_‡žò@5Û;D03ÕíÛ`‡`È¿ño ´x¢4…)d-¼ºu#Ñê²tÆypô¨ß²³boœ—ïÁÖÐ÷Õwœ¢ïôf*gªŠ¢*gø€=n”Ga×1ìlÀNˆÂÎŽƒÝvfK°¦~–A‘ñ$³hóGuÝ䔵àäs-ýœ½&GuwrñV‡‚S†¶™‰Â¸ÔŽ¡N§cµÄN‚–ØþéðÚN&{¢*r¦Ð˜@·½}ãÄX!_C^ÝðX^kÓÄkò Üù‹`8pØ%¿ ®¤Ë¿ aµ3¡ŸˆÀ…tùÝ¢ËT¥/PÓç]ß]“߃6\Ò# Ä¿¥òC3“+à4¦ô'vÿÛîä« ?“?‡Z“ô4šûÉüžòï*ži“¿dwui®6YüJþŠ*?ªƒ6ïDùk„ g6ŸÍ—¿Ú®…C®46bDþ6è½J…ñwŠçbj:tÛÇLüLßÐÒÜü†Åß NQUû‡qšºÂ?Hf# Áÿo —ö¶9©KÄ!¡oÒü÷áP2NÃüc¡¾mÓSÏ56&Øtù‡ ÿbz¨º¼^þK ºÿØH—ÿZCIŸá å¿fêŸç?•%"”iY¤v§B æŸi[Êqû ª˜¹P~ YøÏæF‹ïŸc”0@F ÈPŒl²D… §ÙØ^I·\9N9†!¡‰" Ùs<§)‡d\@Ÿ!(—‰Û Ñ5vArH|D³ÒÍÎo0ÍeLóÂaYFDO÷b xù¢|ð®ë®Ë•¬½×c×uÛ9ÞfŽw•âm¦x_b³Š¯mr«?Ì 59K{h޵ݭr`f2ùï1ÌþùýùýB‘â SÔå!¡²þ0ëúe‘}›ã‹Ä?fÄ?&ä ƒw/‘•'¨§u¶7ûf Ž{ãK…å ‘EåjåeÊš’ôvUd+* ÊŠ¬³ôVA¾WghÖˆêûKh7Ig…¾Wáu9Ô²EúkuŽ"ÖJ¶fç7I.©7áRl„[‘wX¥õ© Üv,8g´S¨E¦’€ó‚s©b¶KæÃا¿nqCg0•ËvÉIÁ7?øg*^ŽËpóÉ)%¥ƒ:Ìæ¾q⺋Fç†üçQ°o‚+‡jÏ׬)©UÀà›¿yµj€i^áþPd”Xÿ`U„à{–À(~G;‚¿¶ÆðïXGËÆ¸>¤"8²“¥Äöñ¡Àþú4r\Ñò쌴oZ,Š‚±¹Y³>É›+€ÿ¡øç„Wë²&ÿ=ñÎÈž QÐ`÷ùžî <äI8ÿ¬yËrmµq¹ê¥É§\.ç\ÈŦ[Ay|XóÓ_ް‡-Ï5$Ìyšn ÜÑè¥'K0g ~ág0~†v²¼g‹š£TÀ˜ØðN†1±?è†Ë°ˆ‹Ípq±7µ8c׋Ò[6íUÝ»3aÍ ”ýçàžg)Ì sj"sil‹dìÏ%܆àäaü¿ÿZågîKYK{ƒòô_WYâ×VæÊÇUý;ÌÔå±ÿÅ´¿(SM„qelDæL[ûÿ’v«/Š/ÇF2¨5žþÿΤ÷ìÍTG2-úƒÃI£­Ä‚‰¹F]vP=Ï™˜+¼“r-øó§Å·þàÀ+BàÆÌáÆÆž–„ɹa³Lɵh6Ëè\‹Õj¹˜oÑäY¾È·Øèq)ßb§ÇÔ\‹ã%Ë´\K‚Õ²Z¹äØ´SuZÙ´{”nÚ´{‹¨5MN‰±i·ØcÕ“Sî Žôº2ç«4•¾®•Òã: 2þF~»àáOÙÒYgL”xÝ G¡¿ãM°Ïæü ÀÓûì3EÃÃXÚM§ª‘ci?.Ú”ƒZV­67ñõ%N—à(þ[Û G[¬¨;BÔ¿cžA‘ü„oße#¬Œ„•5!<¾Ó'<¥íךâ# 2‡NY5ù6tÿR›œò-@>%©ȧq°òi`GAŸ¤kò¦zy˜ä[Js…ä¬y+„¥d…¨UbÁtÁåü¢•â]‘©³í‚`Ncº²S@ýCI'ÄA0§¯ñj æ”òkñðWÍè«DIJK0§Ÿòõ*ºÍeH›H¯y+‰ôJQ f­è 3VfÖ&vb›N+zý;™6–·uY|ÔruE-D]ÁQ¿ÕHpæÅ+ì³°·aHkŒXHc"+à-¼¼GÏÂb¡L!,&„²Â*FèN«DÞ*BXAȺ5VH+Ë´Üš €–ЄÐjŠ5f$¤UCj:½é²5 kºL?ÓtÙZŽô1¶¼Œ4ÝË6òîŒe«aYwÇ*‹a÷TZ³fYçû eØkeï {MR©_I©ŸIýºÖèÝ7è=xz»’[ 7#‰éíJúg$™ôÖ3½#z™y™–’̽‡½G=“ŽA7˜3¤Žq…²Ó¬@Q}8PtUo[ßoþ Óßú~пÂeÒßàD¿-ÑÿVÞ·,%ߪ…ãFfªG3¦Ø`Ú{–âÖõ-­DZM"é&F£ÙaÁj‘·šJæjS¦†´ e=¡4m´‡¨×hs¼Â\Ú퓉¹™1ÿ£¹Øžbkl%›P6­þ–’²ì«êýÎû¯} Þ–´ÄÄ8ÅÄbb\„‰-ÌÄšH¬yk(ekÄ‹2B3ÜÇiÏdçCõ¶¨%vÆ*v;c#ìl¥CJÊŸ1#EÑ 4êÓo¥µ"S‡mÔ»¥¤$ÇÞ†œ·{¬äœÎΣp³ h|'ÿ+ügYù ŲÃãÐRR Õ\À½£Ç¦nœºï`÷­žŒ¬’2‘71W/>ŸÏ‚=¶‘Gßx=¶“GiœõéWòѯƽ0뾆E†»•f|Ç®Ò\k¾JSÝ;Nßð®(Ôu@íŽB]ƒºžþ<;}{¢P €Ú…jˆƒjHž¾}Q( ¨ýQ(%›C-ŒOà(Ô @ŒB݈ƒºÑjëûqP‡¢P7u8 u3êfs¨Eñ\£P·ŠBÝŠƒºÕjq u7êns¨eñPŸG¡îêhê^Ô½æP»’ã ŽE¡îêxê~ÔýæPËã¹:…z¨“Q¨qPšC­ˆ‡:…z¨ÓQ¨‡qP›C­Œ‡:…Õ æ¢£P£:ÅBêôâ×…+²³n¼X‘Ý ööÑJEáÊì¬}}+±²sÉ£Û¡:ª_™sxEk„Ç2G4ˆùý…ÀsA¡á¹®·ïès‡^(hè^ó¶æÔ|z`j'ÞòÙÓ:É¥HÔeO%ê {Šã¯Š‚«ùYkzgðdz!g-²Öõ&îdƒÈ¹šËYW¾ÑXÏ®Ž\­Vz¢å„<Ÿä³/UWOhjÉ 5‹eønLÊ´,5Æ)lŸ¾˜5—NAÿôN¼:I]ÏÏ(~ªÁZv·ÀôNÎt^½&ׂô¬må¥ëð®€=èéä|,ôvÈâ ;·T#hÑmPÉ­w"•l_¢ë-l0ÔuNZ ƒr¾DL³wä<•n_›¢¾=¾îf›r/ùÚä¼$·á0÷fM< r-`ý»z”|Ø;I®¾$ï쿲Èõx•ëÔ¾$¶Í±»‡&7Ò³êÝÓC—›f‹Ü©¤B~ƒJžÝñç\`³Zœ[ ùí,–Œ’õ‚Ï·ô¨èd¡w܃æ=8Ö¹y]›bÜÿF*t'Ÿâ¯™Ÿ'óiJö ¨SÞEÉþ£=‹oäËs¦ n={Tbÿ•Ñ.s;1aˆ°|IåhD™_ ^ÌžÑ)kd™ºkQ+¯‰¢+9E—rü7󫹨\8„ˆûÚ ûÇuò¶(Ø(°\)Š{øûæÈ»”3a¼ßÊÏÛ( þ6µÐvÇ™ðc&<¦LXžá±D¸/[ôá2òo4i—jÌù½¯É~ZÑ2‡ÿä[íÁAÍä`€¦8¬ƒ!Z(l00T ½a'ÒhXî0é˜ôh¶d7ŽHÕÄx"=^“c™LV9ù—iéòé Lúø[*õ#´'´§2íiQÚÓchßõhD»;ӞŴ÷w¶Ì"Òˆô\MÎ¥YrÛù¢d“¨“Õ°8JD~£øN¾\­…»ßÍ—k5\W¿çÑ4»ãeÚÌ@g٬ɭ0=:§“;´ w^'‹ü æõîÇ„ÞË¡¼–½šÜÐs)ô!#ôa„~ÀÍØXÁÁa±/£ä^~mFÉýü:yB3²ÿrŽyºWždÙà žÕ®wYùÉô %l%ìœ&Ïh×rr®QËCPò¼Vð ?çA¾Å¿øLKÎCJ0À/já ï£|!/i!˜#{œ¯É+ZÁõïuªXWÁÛC­ÝQ¯1o7™·ïóõ6Ð{Û fÙ›Dv‘Åsv™ÐðœS&¬xÎ¥6ϯí =æ• {£¿c€•ºGjEGÓsA™Hg•5ŸžÙh¬šùlôʺ i]så-˜³˜jå÷qôÚZð$F|¶¼'ùÖ’'ùÔn °úìþ§ùE›Ä ÊNj8Z} ®_ñÍç2‘4˜È,.m†Xå`kQs–tÒ &yˆñ¹ŸmaÍ/ÁߘïkS­¶åé«Äëk[ÍšŒ‡[}Ž®Å}½rŒµ Ô ƒzjoòJ½zI©—½qV_bN?¯åj«Æ[}I|}iqæíï¥Ò ¿ã@ïSÈ— Ö#9ØóTæÏ²BÀ½½õŒ’AÞÞ6–£e–•å(ðlðjÕV9Ïb1©ÞÀÒ|kF®¬¶Rª—‹¬5$X¨h› ër«\a-è­ …óz­LF®â@Ô÷ öŠÜ±Š²k£Un² B¸œ!ŒÈ-VÐP/6.{lT\¢ ·Õ(Üû­Y²Êý& µò0p¨h…üüeX YÃ9Ãê‰G·Ù¿W+C!½ÇŒôSé=« ­¬òTKé>tŸ¦ûbæuyÉJ ÁŸzlÉvÇ85V¥ =¨mFIXôn× Y¤•9Rq¢IæÄzßÊEI¨Š’í=× D[¹d;JuU¢‡èªDÖåk8ÂqÉñ]k·\Xv3ʳ.ZƒáUmòpa¤’®Ó`D¿ “Vò=*äýt”| ‡}*û:XOƒt_Ë¡zÁH¯/!”7Ò«•ŒD‰­GKäJähˆuT#&›ë©FL¡ç†2Ñvº«m:—Ôñ0?e”Ô 0à„³S•r¢òÏ´U ÖL58iãkcÖÁ¶r†^ô[þÙ²BïÖÍ×6/,t–­¬Òù9aÎÒ V}‘½«¾Ií°Î•¡‘›k£%\¢£2PÃÌl™.—éF+†¢µV/å-:$ü£½í±À¿^/ãõŽñZø„ôFâ“Ê>+ŠES¿Y—›ÙÉhêä=l,½‡ýwóÕ5á­zØ;–0ÛÎÁ½e”þ:–uJ:ƒ·×™µýºYV÷몬î×åA=n‹6âú‡­ÃQ´¾1ÑŽD¢1¢ÑeEKF´úØh¥Ñƒ¨ÊyÝ8çs^—u´ù!ïžo ˜ñ å/£Þä2t˜ö‹‰qÍŒqM— FŒ½ãb,§7£?³öǸÇÂ~Wi溧ËF¬}ë‘Îg‹R¿iŽMOtùD/x7 9ï Š%ŸêÁpþ nÔÃ| '§Jlê R),j `b½˜Ø [ ±A69ÄO` wÅn#+‰À[”ÀHƒÀh“þñ¦ °ñ69Á¦R²ŸR2ÉFé_E(“c³4Âhz™§q^ÅÔ,›œkc“Dý㽬tž­§\€ø«)þr[óny…-¾[~Ãè–Å*›\e+ç5zäœq^Brµ-ìÝa·È56³Ë]¶sBþ‚¹Úa&d‡Mî2šô3fh71´ ­!†ö!æÎV«þœc)¦ Û‚ùki˜QìVxLÓ:ë;ñ¡Ã#MýʽAÿåW Ô¡1¨Çz’P×ê©VPqñt+¨ð;ÔaœÊÎj$l¦ò²M~i+˜à y'x…¼ŠpÃcÂ]3Ã]³É[ÁD 7‘ÂI„Ñ3ü?§9%B¾]0ÉkÎ) ü÷ªàyþa•Ûlì½3Žl¨™ä¨Î)"9e‰vc'y~W Z89A>Áœm8j°?{ñ³¿“å=œH lʉ8‘‚=Þ÷,qçú~Ê¿Ñ ÚaÀùÎûY•_ó« Úßá1¾ÿ`lßjq€+z=0ðLÀß·ˆ 1ˆÍöµó ”æÍ98cÙÙÜÎU’SÛ¹[;™Û¹[±®2¦s“íܱ­ë‡1{[›&0¼·Å+õôÛÈ¿¼Ë²ÝØÛÊÀΚã2†x… ²ò²,%Yˆ¿/~Œ;9ŸQæhÅG܈0®³¹­øZÞk–’×̯ýæõÞøVñ—Ø1»§Vô‡}ôß‹¬èo-ê?ÆF½¯¢§¨÷#QËÿÓ)ÝE) ƦtCÀVßëy¯[J^¨Ê¤w7Ò»'&½9g<Í™fs‚o¸ˆi›ôì`ÝŒ`“™‰œæéhe72³kñv¬ýYñ+1·¯iš¦D¨vÍëj)é¡úOLõûÕ©_¢`«DÌþR„ìiÞ¼B¨9öCø â'ŒŸ#ø©ÃÏçø9†Ÿø9…Ÿ3ø9‡Ÿ øù?—ñó%~¾ÂÏuüHüÜÄÏmmÞqñA ;ATæ ÌÉüi­e¾)4ˆ«# *U ê`Ób>õg±V!M%¢­Ñ°1 +Ó°qöXU;Ü”FE$3âiE A©²5Jg¸¢g3 4§&Ô”RU+”(5±”f¶FÉÎ4tN“)é*M5M)Íz6¥× J³[£ä0RJ¦dS”j›RšÓšôþ9ŽÒÜg—•OV. †ôê›Rš÷ì4½jPšÿlJZsJG›RZðìaRªn½DDË·`Jš¢t¼)¥…/FiQëiºß²ôN6¥´øÅ¤·äÙ”ZÞ馔–¾Xš–µ.½û-KïlSJË_ŒÒŠç•ˆ0ÿƤé|SJ+_Lz«žW"‘4”.6¥´úÅ(­y^} 7ͧKM)­}1é­{všDLšŒ|ºÒ”Òú£´áye¯Y>]mJiã‹IoÓóÊ^³|ºÖ”Òæ£´åy5·Y>54¥´õŤ·íÙij!Ÿn4¥´ýÅ(íhRRL‰HŠí o5¥ôÙ‹QÚùlJ–æ”î4¥´ëÅúÜÝ#[º›°S²§sdKwSÜ–î¦æ[ºÃ>ˆÛÒÝ…Ú ¨}Q¨ÍqP››C ‡Ú…Ú¨Q¨-qP[šCˆ‡:…º ¨CQ¨»qPwŸ»g}¸ó~Ϻ2nÏzc'äNhÄLBCS(§J´»(ƒ¾Öê$ôk4 æ¶¼'¢GÝù{_·qˆ½¶ÙöèpO‡øhJ×͘ÿÅŸX¿QØähr¨é¹äŽÇ vý¿šUZÕ¬2™U*Q¨Ye‰ÛœU–à‚EMÓY垦ù¨¤”÷‘¥ä£Z»Õ9JÖ™>Åõ©Î”º-Å SB”ŒFö#Ü<²ŸF#ûnsd_Û'ký1󃔚öü uQÍQ‚9ýܸª€Ÿ!øJY§óD¢o^ äæ§0¹¾”¡óSLruÜ ôˆiš¤¬1&}üíCf›âÒö˜j>uàóf“’;ÊRýQæ÷o[ç·ÙÙÕA“9ƒÝM¦ŠÇZ!öÚ bÇ›Í%c¹áÙ9‚àÒñ; öJÞ+–’Wb‚æé„ê£\\(äO‹ê¾«NþíþeÓlB‰ ÜSÇdwÿ2è¿9&{òÙDÚpéhƒÒÁDr‹FwVDŽ:Z$rW9ê F*BäùG"R*òJ)ÿJÅóÜ­øó\E2¿hë÷É{…-’<ò“¼WôyÉ$y:Úx>Bãy&Úx>Šk<5o<ûæÅ5žg£Pu. õ8êqs¨{…qPç£POu! õ$êIs¨iñ½ÃÅ(ÔS@}…zõ´9ÔQGÔ¥(T# .G¡ã ›CíþeÔ•(Ôp7ÎèD¡†»c¡†»Ÿ×g]ý/ôYUq}ÖÃN(d8ãÓ9‘ú¬ÿiÿI‰9&uá‹Z­pUvÁg¯å}öš¥xUvƒØßG«Ó WÃí¯“«(^M®úXëµÂ5Ù»;fZ P¼x [‘ÓÉumvVÃﺑ,º‘h»eÕü´Û¯õâµ8fu‘œòÍ{¨°ßÔ=àåœ,ðäy,‰nyWàZí=py›…"2Ÿ÷à7–Åš¬Ö‚þQnÞ@Xȯ¹rAü"ï–À(·\¬uý«ÝyGݢ䨻V.ÑBAÿwñI·\ÊBÅSÞ”ËT\‹¥ }W1¥FÄnkò.EÓ/8x­þžÖS>Ш»àµ‚}ï>öµq*)&z?«½ŸU Ñœ~VEhí‰Mëí¬C±šÑ‡Za¨€£grô‰fô‰V9Árš•úË©n9orà—9ðl3ðl«œKÓÝr>=ó9„\€Ð·¸ô¥rèÝ»½þ)HòmÆÉeŸÃ&Îa« Ï‚yÏG€;Å-k &ê­ûíÞýv‹üÜj^T9 RwbHÝ©ûDj:HÝÏS“ÔS«,ÑCÁ¤úê=e©®’ÐO7ûcë^ ð€Ò@¢À÷¹Z Øk¹n /×åJ W(äU„¼†c°E¾uüjX­[àfÓ<ë•ÛVáßœôW+Ç ìÈÆï6ƒ± ·Ü…ÙÞÆwv4…ãgìÈw!5:'Ø’SF+žCÌó ÿa é âÑo›®áqçÖŽíFÿh7«¨å×Ô/×ñk ×ó+îòLñB!³q•G~®C3seÇ¢«Ž043ãZÏ Måà>½xÖ›ò˜Â†âšãàìag\Ð*fÆ®3ck¾i¹N¬ô$„¤gé ¡ÝÖ¥Ô‹×É:Œ)`3ü¦Ê•·uè Ï„rŸpÕÇõòj k+ÜÖN±3Zó1Lt¶RŽ~Ÿ)=BŽ>уù’ªC#±4Õ킎œ¾¶`1§Ê-PþJmÁn(ý±Sô˜‘n 0ûYÃlEgEí¨IÈÚG®Ãm¹r¤-Øã‰ƒ)tÆÍ«ÕGg3”ÌŽ³±’Ùq6YnÃå«§MN´…ƒþ~ii…ÄÂd^é;K«òäú^ææ]µ©Êkª­(ߦ‡œFŸ›•Ïtå3>§{Èô¹EùT°O×âÇíœs ½ ”ú+J³lx¥‡Aiv”Òå5Ç 47Jižò™gP𥴀}˜Òß ‰´…‹î9Ò Ås±ÞðË`K(ÜFe){,5°–‘Ç&å±ò~Êò«Pò[kÊo­’ßZ›\Ïòk$ùm4ä÷.*Ql6SµE¥ û‡[•×Vƒ‘m*UðÙ®|¶œìP©"çT‚Üií]Þ<åôï6á÷Dá÷*¯½ü¾(ü~å³ß€?…‡¤E%d „’Âì6j”¤¶™;­ÜÖ}‡uŒÅÜÇlò„ÍÐÈ}ÒÊÚ_&Òpî”ÍléN#rI†N5ð’j.˜;¥HÌOJ…¸BÏñý…ö¥M~X¿Ü%[Oy_ž_nÈ¿?×P¡Vâ©ÃNìcG˜í1wÃs˜/Óûð6•9UÓ«¶‚›ŽªÒ97ùûš­&èŸán7Ø`ü´BUÿ¡ŸäUeUÚpr…RdÓµ#¡Þ´k¼“ÝBÞâ(‹:ú×gSY»÷= ˜á–l!ïÁ\‹|Œ÷ͰF:ø¾vSQ—]ö³Çè¶PÉ£¦ ŒU—³â¾ö ¾˜æ@{3šrÍÄòG$9æZK3t*À3•d§Ù¡á¢A §ÁÄ4{ƒ¸FíÛ »¬°‡\8.[iÇś殠f…5Ž)kÇ3c¼*©¹aUhur³{@ødŒ9ö œ®e§pѪlo¥Û ëkr=f®«[àz˜í—¡³‡³ëL±¬³;߆ZÍ”0ïBŠ¿ÅípXD;ìJ·ô.8,&‡Ývg8ìƒÃrØow~ „ÿËeöˆy¸MvÓ<Ü[Ê<Ü6»iîur¸ös¹ÓpÐØ€ÜõŸË½†ƒ5¢œPgå„z‚–^ÙØ¨46þKccŸÆÆÑô-"aý3pC.ÓuÄL×»¬ƒç€Ï¦ç »<Ï1žLO¶â‹C 1ž_™ž_ÙåuxŽñ¼mzÞ¶Ë»ð’5€îìÙhz6Úe©#è]ë¦ñ‡ƒ ÑP*DÁ¢»ÍëX`¼[„!Ù¡6ʲ/U9Õa Mu4ˆ ~1Ó!+¨È”¹SY‘=Óòì`ÿ´ê:9‡ýË_u} ÇPæ:†ÙO*kT½šÚîóáò¨ûÇW/(ÊQ_fð@n^_£’V;`WÂ-:ŠÔ¼åûÏö‹ˆØr·²Ùµ8â»ÄažÿX®Zþ•l xR—›ÇºË]ý1€rÜv„½·iˆ¹ÑSî‰ã×Àä&f^)CšáVܧÁc3sñûlpÕ¤ÿ0Û»?ëøØI­ù},w8Xkç4wfÒÌ¢K\Õ¼«ÜšÜéè)wCæÃ¸NïSÕäsSæŸ;ä1f<¢=w¬û×`ÑüéyŠÊë¬#ìöj]`Œ;œ ƺå9ŒÃ¸Ðwó 奖£_V¡åÕˆ@¯âþÊ7 “]‹ø^7º¤ix†Í‘œrÖÆizâ0´Õ¿ÒÛöJo;'ï ©ƒ8s û&I;Ò„žr`‚JÝ„`K½fV#BþÚ\ןøð åF%4ˆõƒ„ut‚•@Åè葳¡%Æ8êèX¯1^½u9&!èŸèÆ?u.5™ÚÌÊâv96ê:¼Ogçám`åø±ÃkxrT'Ë‚8¶í^(wˉŠË“àrà ¡O%.• Û´95åmƒê`®fZõ]a³ïêm—ÓbJ$T›ñ…‰ >[¦¥º0Æ%+Ôp±®®¿Ãh,¡ÅJ4+!Hÿ>›œ Zþ0+5bϬ’s|ö¢5ܺÃ2r×À8·ÓEï AŸ›ù… Í›ùÅ”aËZ¦¸"J&ÝrUõoånï|‚XàIn¹>Á,=ô–ï?ÑCn Q¯7ªòƈïÆUò6‘ïÃwsÄ—Þ¸äÉ-ìÍuö‡'¸S¡zo_4BŒ·þ)fмT!&¸å~D¥Uñ}®ã謴¶†}£ñЧ¼-°[¦(®xSÖñ;kr¬‡ÁâÜdþBµÚl°˜7–¯(·| ¾J× AHÊ‚ 1½)¦(-œaʃ› !£ƒ•·€<2ÃnON9¤†!l¯4±·&QK †TQã–Ãa¬–š@´#i¶Ó^Íc¬¬EšêÆÈľä¨Ä8ÖjfV¡ŽŒMôé/î–ŒIMYbÁg¯½|ÛêÓgbl±Æ¢ñ‰E«³ñ%''}zÈg‹Ê‘Ò¥Ë)0“:ŠGK]9Y3YOÑìßXfÂo0äŸô&ÍöüS½\ææ"øè ¬1.UbXj†_š(—S¯3I­ž¬H$!SÉZجÉD)ÞHm=|¸¹ß³ºîL &›{Êí‰Aª~ܘ«È´w$6/ï°¬;N5Ÿ{[l>÷%ªÜ>ÎÇd`z÷mf¼†‡í\¢ìŸö&Ÿñ­cÂnï¢v,12A>ލc3l‰É)[tŽ{>F Ñv ùÕÜDÕ„^¦gÊÀz^|ËZ‘$/'¶ÖB]጖Òòzؽ¥ê {8|4_¿›(ï&횦{‰hsxâ>Éêa¢9¢ /yÕåF#ô(±¦üÕT,¼S#?È ª•rÿlj=Ù²ÂÓÄ0ÅM†SIROÙ/)v°ùôCÔ<Njá2aBÏš2áš$'ŶYh‡%1Ô?ÁHG÷­–öÐ22© Ê1§¹gæ$‹ørΨ$Ÿý£z;äè$h8ImO«–c’Ðm÷N€Ò9Y–Dø>NhUßÁÝ “FƉ«üUÔ½-"'™'3ãQ¬J¥t˜º€¤ /NÞ•4˜Fò¨IT´ª¤h‹9+ aÌ ¯þŠ73E5ß—›—d6TFÅEK5Ÿ©lSKU SÁe˜òþœËÑš$eÀœ‹Ïš$¹.‰+Ыýnš¸Ú¦ÅèÃTt4,Ã}BLô23zjÚpsi¶œcŒèåm¸] Sô ˆ>1&út3úô6²¢åè•*z¢W!ú¤ ¬B9æZ(Çœœ€|cõü„(˜æ}žvÌsôÇÿ^3ãöFºÇ©§d$•7[¸<ý “H-\×Ò¢þ:,êO%öRœ_»q¤ ê0ˆ-¼Œæ…ü1XÈŸ–aÕSœÔ#Ã}ß]\2XX¦¨ƒS«ƒ×*„œ"Š”ºäZ97j‹š©.‡Csy¬ààç°lQ%š+×…ÅŽ9¢ð‚#<:pÁ!çŠÂ³Žj”©ç …+ŒõÈÀY‡óeŒØ0Ó‚€ Í€”)!ž‘Ô„+P.…ÓÜáÀ4·ºÙ=‰ç|•®Mœ®Ú2aÙD ª£f‹ÀµU]ÙrÙ*Â!žr‡»2±ž%†Á¯ÝjÕy—PÖŒ '^ÌÁmnºÜ/B®Pœƒ"èÝF•ë(¼JsÈ ZàªC¡h,¬;…2Ðl8aË32tÊŠeŽO2Ç3ó,'Œ¥ <Ê휧 ÷ËÕ¥'jÅÊÙºðÃäç9`&`L*Iúç5×$±öN ÕÌ4úÁªR5W(…Ê”Š [›çJSÆ5x؈ Vµ·Mä$,×q»¾«ºGµB]z+ѸŸÖKé¹m°õ£g=õtýéù9.!Òóà ‘0P“W›r yEò¾nòLëfó’bÜʦÂô‰ëghÕog$Þòîs‹`ï$y_°iÕlHSX_’ê­êPö’!ÿ§˜4¤J4”%ê®Jµø!ìniÊpæ~&ÈZ¦áJ¥%ùa6BóÙRÿÍ“†.ršÛ§ÓOÅÌPUH)ÆO”ÃÙç®Ã_m÷%ªn3‘¯Ö0‘kÃ9ÜmÌãå8­h†;\ò%VÒд ž‚z5#zªñŒë©&K¬ˆšƒòŒÆÅ¥VYj5xèg aàøL6¨p÷·C5ù™ °ö”ƒ¬ØÀ×`lΊÄ|kTó­ â8 ¢Ú*ZMA,·]BµYa-¼ä0˜Xi"ÞþTD—r5ö?1[Yc5±ax®³¹Ñ.b>¶X½Œ-VÞËØb•Û¬a*lq‡•Þ²†þº¨oït¯&?ãïñÌïü]ñßà žM Þ Bs¸Ì¼Æ„‚V£ÏZe˜9Cá®±R®z<4âGkn† X]9Öq3Öq«<ɱ0i;eUÀiŸG“Âg/þ…ü «¼ÌÁaqáKkóžc¹¯ŒÎnZ©ÇS}©jÚ*ÑÛÝù‰«€ [‡é0¤û¬ìrÞ|‚¾ÎHÎzäE5æ0Ø\‡ÁæB 6“iŒêþ£`Æ 5GºñßkVìxÓ˜§†Kp.Ê€¶žîÆ€Ó3à¬ü®x»p}vVøÀúlêßûhÿT¸!;ëPŸÀú<ÜÇ:BnÌκõN`# ‹3”òž“8#`*ïY`(ïY`(ïÁsÇV<¶ /z‰©¼g+ïÙï–ËYyÏ>·\ñÒ’ (áù‡=å!DÁ^7ýF”ðÈ‹"èßïú÷¹óöº¡²bi†©‡±<ÞˆžÙÐó×ÍÀ² (9R‡G—gèm û´§ÊX|FÉkíþÀò³±÷A¿{>Ð~&ÿj¢¹åÇxvËÿ…gæŽ/5îqºLXÑ ÎÐ¨é— âl™°½Û ÎјéW â< ™~ ñ ¿‘^ŒÐtTxÂì—Ãùs¦7Ùß Ã1ëh—¿ªcM¬£CþZ¥¶³YjëGÔ¥þ†ëù¹t_(‰¿•¿5n¨Ñ°éï)l"+Wß—D½¾¿Ò Í­¿ƒ- v.ð%…•ó—š,„{vþ¾¤å<(Oût_›„þ ›ÛKè0–JúÈÈ#nù!ÉtÉבÊ"-GöM¤Ì áðÈJj ßfŸ)Âèѧ9 úÄCîö.¥÷=¹ižQ°å5ï–×h6†2±*t%@Wh «c@×™ ë„ÜаÝа[nŽ€nèšЈ–š€®¥Ø‘ðûœ3AÏ ¬Z‰ ¬~•ØêPC”ÿòÍê0ýŽPøÖÅPèO#_ýµ °>†í!æèfˆF£ÌB0Û#pA²Ö-Gj&èh +6dØ ›tŽ;]cÃ(¸hÚ°òöJo¹q™&Fs56U0ŸWZµF#J£,WjFa®ÒŒÒJÎE“½y³¼ÐOº t|› oô©)¿üßk®¡´ís7„·gD¢ìÈ€½÷kê¦}ƒ(ïbùºìˆÎ$’|Ì-qeü3•É¡<ÆîƒGfýÇݬ©Kv †¼ÇiÊò ¼3&p¦8Sv úO»Qà“ø¨" üªøU™ôŸ0¿FOPà×)ðî˜Àoß”ßúOÿ’Ÿ¢ÀßfÒ˜Àß5ºÆ@Qàâ’L†iWÁS f{•]‰yÂ8ª¤ÉíˈÞÙŸñuœpܸþ\%_à¦Á—ø¹î¶¼gê'à›"2rS„?uMµ<ëˆROüƒV,ôý”Þ/lÁðÁs¡bn–ܦ~„-èGˆW¼¿¢³±è¿‘À3Ùø}‹l<ËÄ óñ#K†*KéÙÐæ6Â/ƒ±xË ¼…ÿU¼ÿÎl4xYôßÌË%/WÚ—0emý¯òÓZž¾— nBÈ0oB]ѯq1rê"nBÌhrêPFÓkƒ×Ÿ£uâRÓKB‡3šê׸§_ã2—+‰`FS%×[ЯÑ×÷Kîô÷õ˜·KB­EÓ¯Qª¢> ¨¥‘¨áÿtJ¯6½`T“ÑT¿Æõôk|…ô^‹I¦Š3®·¤_£öÙÁLýuæÅ¡&éx!ý Fš¨€šÿÏ©[kÇIXç"·Öê3šÞ”ºÞ’ÖÏ™—÷c.·]UºaQJ7n@ ·ðs] ßh{ÔÒºþ*ß+ý#ùv”…þD£[^7KI7“FÖÝ^ÅGRBY e¢x2ä~³iÁ<–Ñô>ëõ–nÎŒ—ó^¶”¼“«#Y¿Ã(úmW<†ßÇ~(ÝnZ0N´".ãbYšAé$SúNsJ–âvüŽaJLãnS§^ŒÆi>kXôœ,¹ÜxˆŸÇøy¹iø°¥|é§òå!åK¿H¾œi­>ÅÞ4Lâë|i;˜ó i}± :×%½5JšR:ÿb”.´žA( V. mЇC„OšfÐÅ óúa“:ó/ÆõÃ/ZC×c šÞØýÒóÐ/gDn€ÁdûJF䨙¸`gšß»ÅíË(ÔY@]Bƒ:ÛêA<ÔWQ¨ó€º…:u¾9ÔÃx¨ëQ¨ |›* u!êBs¨GñP2 Uâ²ß(T‰'ªÄó¼Ûr73þó·åæÇ팟v#+q‹Š ¬úÏyVÚÇ’Y¸);ÓØ”Ý B}Äë…›³_¾ìl¦Ïpíû…[²_¦¶ÐgMëO ·f¿¼ök­ôy¤þNá¶ì—Gç¶aÍòv A¶åIÀ ‰ùnQEæpéX0ǘS, 9Å;bNq7f6v  U'œ¢ñü‰¥ø(”xßgðˆòô»n£é%\ÿiÖÎ_e§ë¯¨ýs½ï‰pÞõŸêÅs½@!ïýc|ÎÀ*§GÀg³ð#ö¹l²pY©™áQG ® ׄ’cXá‘7„’äM°4°‹•àà %Xúë¯!ÁÐí-ªe©Q^‘‚ÁöAì©®Õýå>ã™ÆÛÏì+1Aÿv—ð23(¿ ø¢ø“šáOnŠ¿ÍÀŸÚǦp¬ÂטÀ˜GA×Ù]Oq~o\ 5ôæûÖdÅ뢨ûž\ÿäŸE<G=:òí½éžÈºà’X°³6U JJWÄú ¿) oe!(N4Ʋþü¾»ùh}­Ý¨¥ÆæKœöá¸Á;Òìêïr6‚‡w±RCTÄÞå¼|»LXÊ­¸³ìß÷RjwÔlkÐ;–©¸-<Ü#§[¹€vßüÚ5Tî-MÖd¥›U¢¨Jø«ÞÊ«2ŽÿÍ¡]tÊ„þ*–²>í*¨¾ò±e©U.gj®"÷N™k­r¥5Ø ÔV)jØŸ]݈ͯ–k­¡Ê·ºu%RVÀÉõÖßÇÙ` óÖç&pf.¶P*Ê(ÛÀÍȘö÷¹Á~ÈŠ}ðUþäôå×ø9‚¤òàÂ4ÉÎ"ë2ª‹N bÓ&Èi+t^SÅÌ´ð†ü9ÉqÐE«Ñž¦:QUõ/¬8™ÏÔ™ü‘y‰ÂôýÒ¿†ZÒI*Üevã“_‚øhθ_3ñ›&ñ›Vy›ÃEªÉHúlÏÚ­‡ïYƒ ô° C¨2€>†Ñ¿Ïè}M¥Å}ulï7‹Ð_W`u%›AØnËun´j¼FêF#‘ºC ƒ<œ£e:e2ÉuœÞSNÐQ~Ë_MÍGõ™È_¸Üñ>'éêbÕü³~MÖºñ*?—SôHí(è‚À9]jIyé'®~8𤫠ü/Fž¡Ë:*ð/P+õH¦¨Dãu`Véqu¸c³:La#Õ}öLJÇ =¦ϤZ *Ü›µ´0°—>OöIü´p_vÖ²ÂÀ>ú<Õ'i°(ÜŸµ¼0°ŸlwÁô­š}ÞCϵ»˜ÓO8u*¨6¦Ÿ‹hÖWåaG¤w:§—'t§ûX¾Qx ;ëLŸÀ¢s¶È*<˜u®Oà }žï£}·ðPvÖ•ßÑç…>Öî…‡³³†û‡‘úOõ¼Â‘ݳò#»Sâ?µýªpT÷¬ïFuÇAå.1ÓãûD¸9VDøƒËŸ,4ø[LüÍô°#ø«äéÈ›Y·"†þ·øya0;ëêßeU¼ôžV$6.öÑþ¾0”õEŸ@ˆ>/õ±ú ÃÙY²K LŸ—ûè,¬¡$ô ÔÐç—}lŸ!€>#ôy­‹}¨(¬Í&´@-äZÕÊο{ã.s ÑãTÁßÓijö¶3Dá/eZ_¼$+Dá­ŸÍH Üú©¬DÌì‚ó@NþóÀG¢(ˆSX³º@ÓýoØ£¯fàöUç)úi²0_Fÿ4€F‚³©ÛYäõ/ö†xd10â”K!¹Ï™í1l@Ó¤.jt»PMw”)FG1ñÿnEÑ O9Lhcèyc˜°ŽÕä-Ê™ã%ÛE=ìÿ„Þº§áÆÃ+ú'.\*,×jü•å_âõéꙌYö-SäʉMýÚ*Û@™¹4!Ì„þŽ9,Ô÷˜·*æmF©°Tir–JMâ!AÿRo‰­VÎÕBŸ§¹—y?AkÕAô˜í¡™" |çz¼ûòæ‚¡ó<05—eûk†_¡dûï–”Ô'”ô5š\…õ÷~J#I­`FZ(gFš(™‘FCH²*­¸*MnÀkeZqeÍÈèufZñÌ4¹ sŠyÔÙŸ2úv3ç¶úàw!«¶S“;µ¹·´žfna*LiÙh£´×·ù¸FMQ¹XÁzQöjå¢&§\Ьàkƒræ‰R¾B¸O« å¬ðÒ¤·ŸäVš‹éY(Üc¥vGçw¡Q–£¯Êà#&GxTvÔðW*¬G4š)…©’T«k15E}{T»0À?Îlr¿z’_™±Ž8• Æàbòæ‘#œ|iˆ†¼«¼B^€Dt1ýƒ—î«#mëb ÿ½–°¢ÿYöG…®î1¯ðÅ‘O-¯Öeg]ëõžÔ¡¥ûT¼YXŸu½WVC¯÷´@=ªáÂ.íEŠs‘õÆS,£µºÑÞ1ÌYí±sÖág~¶xþ¯¬¬ù0ºùøv³­Éµ1¾?iæ»þÃèfbûÈÆå3m¬‹ÌkËÌÏZñer™â™¬¾ÓŠokq[Jˆ½%m’¦4M[‹ºàÈ4öJU¾©½Ò•s¯t%VwÁùÔ˜½Ò%ìЖã¼|³¨ æÒÇ¿"Çz8.£’—âLgÇRëú£Âqz×À8]þM0kŽEþÇ0»àDµ7fWƒy‰ßÇK.^hßÍK-®¶‡‚9k‘Â}íçØ(P[•8—HSÅg¬mo#X¾²í½Kíù¬û0èßÙóYÅ<ÿ°9Ï­î¡®oÊÞj†øFÌn±‚æl@µØè‰î›®ac7{ Õ¦MºÚìýL1º†ý,ÂèÚÖ¢zc£îTQ×RÔ‘¨ëž—ÆHê2íj·isÓ4®Po"ÛènQß­¨¯'ê»#Ô7pÔwbv;#¥"bÆ «ÑÜòÜjP¦VÊØÍݯ”‚^ëôï(ÝÈI¾õ¿åý›¥äß" ¼cÄäØ6È{Œü7µ"DcÇñ‡*ÅëDñ@„âægGm§¢TQ(êÁHÔ-\¡xof¦·v±[ ß±{3‹šïͬù0nof[j1 ¶G¡ÇA-nµ6jGj  >‹B-‰ƒZÒj]<ÔÎ(ÔR@íŠB-ƒZÚj}<Ôî(Ô2@í‰B-‹ƒZÖêZ¯xUÌQ¨å€Ú…Zµ¼9Ôõx¨ýQ¨€:…Zµ¢9TC<ÔÁ(Ô@ŠB툃Úñܺà $çÂô»÷ÅvêÊø¿×Òø{ =(ËPÈÜ%º9âYDÊÉß@Ï _ÇÆÔPOÜŦé6Üߨ"<\XÞ’=ŠÖÂÖ]¦x5gWÇÁžo¤SDÝæØ2šmìḛáeÓMéÖòh>íFßqBþ+àùG°ð _³g*;ŽÁP¿LÐì¬çáîØg’¹å3‰©‡{=4¯!$oýL=Õ1õ}œ õ>ñXÔLâóxE—þàÆÀo3á· ¹0û=ò3ÀPð; ~7Üx°cÅð{Ù@v |dÃê àÇø À^¶“ÁçD áæ1ó¦@meÖzb6 ò`'‰Ú"Í'áñ<žŒ_ xœÓ> øS1>µð©Ç nøœŽ!|Ò$|R“§9€"|†ŸÁ +ÿ¡ÀaŸ>á‹ |&¾?–ÇZƒþ0àÏÆÀ7\·bý<yä(èÔ +޶Rúà¦ôYü8¬£ž‹_ø•ðçcà×›ðë­r#`j§MxcmºÖÎ9‚½ØZ–¦ö À~û°O(V`/ÅÀö3usöÓåì@½§ åšu9DW°C±Üu9v4Dbѵ°Wb`çš°su9Ÿ(Ø»°õ¹È€] Ø/c`wv'Åú°Wc`÷›°lì!‚ ös4w2l°_ÅÀBs¦”ë(`¯ÅÀÞ5aïêò>P°ö`zäcö `¯ÇÀN‚–K( <؆ØJ›[i“39€‚eë å‘¡À1´F2ì<,êÉØ’Ø£ë8Ÿ¶ˆ- &ìi›<ËŒ’@°{œJ‚û`oÆÀ޳l¹=è?Ø[1°SíìT»œÎì {OY‰#M'<²Ê®`gBEÛíØ €ÝD±NöNfí=Ufš°;ìr'P°»v`Ozä^{0X4 Ç«u‹¨øºàb<¦´”î2›¿a¼#&k§+ÚŸ¨àê î(ÁÙö'ÊSö_á?cf6.yäY~¹ì‘çèŸBÍ¿|I‚þ=zÙŒ/‘’›CµÄP(A€¡[x¿‹’|AãUÔÇÊYŽ‚í¯ñ¥îH5aaq§Àjä>ëj9à€ yGé8¡¢g¿qÂz˜žýÇ ½Ö!9Ðêê•ÔHêPpºqêð]¯óÿ°#è½M…«Ö̹ãáÛtuu9Ä{Ýc•GÁÈ^:îcxÝïA'{ÒQðð§!¾ñ9ÙÂ{‰ÐD¬AZ‘΄ŽxçÎàb³ÿ‡³÷€‹óHŧ¿4™²×a ¬dkñÚ›Ãí­Ÿ=`|ö°·{½·7ºáãv–}—ŸÏÚî­Q@BE‚²( ¡œ,É (Ë’5A圭œ5¯ªúû†A’÷öÿ~?˜þº»ººº:V‡*0ܱzÿ?Tø@M.ÀÚšŒ2·†¦ü |ïM]3´>¾Dî0pè[F Kêu”艟dÓ^X•HHÿ#‘ŸHÀ¿€„ƈÐIJº);]Áª@S@J¡XÜêí‡מ„@Ra¶ºžB*ªÌƒ¤^±†nä?NêU ¼ÿæAj¿Dbœ õ®5/+ŒCÿ ú"àË(CËÔרŒÐÌo‡ã•ùM<·FP•£÷Œô…iQEPW°6ðöFÕLO< ë— ÔJvï%ÚÙ*Fí¬ŠžUÖ1K•­“ ®c Ý!ÐÒЭ‚–†îPhiÃÀVÇÔfúÅD576ão¯¶ÅLv667‘#Ô=©¼ÄO0ÜÖUÝSh|¤ Ÿp¶öI÷’õn]34cÄte>*n~Éš©YwÚ© l¨]ËPNø2é×z¹Ìþr™Ã4-ÿnøOƒü{á?þ3¨ƒM°QC:”4µûE`íSÖ¸«÷°õ@ÎM±%k.½[ÍùQ…MxI…U“-Ò­pù6ÍHMÓ“¢2½wŽ #§Íìp âx¸«9´ôÁÍåWÌvÞ/£‡O›`èö¬Æ Ù©+ͨ¦c >*´6ç)ºÖ¬Ûš›ð•üVD¢Ûýß¡Gó;lº&4Ñà£áÆ< @§Ê~PaË—¶dŸu˜\BkØ»“áqÝ™ì¿hN>’ãJ‰qòX*®d¸›ÇSR¸SR¤ñ=)1iÓRÓ´§Ä8¦uQæá)1ž”4^¾/%Æ›ãáºcKƤóƒ)1é)1üPJLF·4GlÝ£{u—îô_ÎR2ð¢Ë1›îAî·é^äÅ)€I×3ô4Ý„9cÓÓ±Ôgmz–ñÀŽ$ Ï\Â0ìì—møäš(>7¾ ž4 ½nìÍw¨7ïÎÊD-Êw»Z~'¼Ô¡™ß#È]ò~7ÈÝYÝFæ82?xIÓ4ëL12"E‰µ02²C ‡‘Ýu ©dtë¡ÛÔØy•=‡®èÆ£ã¡öxn'ý8Ä!NÔ⎷É(ü(ÔÈ\<ÈŸ‰÷PÇÚu%-@–!™Ñ˜Ðˆc(ÌçSìQ]57éjí4ÔfO3ÉxAï¬$½³ zg zgô¢ÛôÎt«-v>éÆî×b‡ñXã­BW!žÕÌJ>.Ó¼¸øZ˜Z]M)ŒÆ—Ø¡“‰Â,µÇŠøj Q«’øè%EѬ͂ÄDâ„×-„åÛ îŠLÚfç›íI­!áûo í[ì…|«=êŸó*VÚ_s᫃o·Gè&ã)q“QèâtËbŠ<£e½x: 7ãJ€§³ø¨22ñ’ ëò…b¹±ãý£½¨v2Žfáj~Ƴp²×NxcYÆ í6ŸKï!tÖaëR dŸ]¬K!«ýP¨ÃöHh=p5‹ñcöHølV^¢%©ùù2¾‹wŽŸ±œ€eÁ|¼5´ØQ™eh;ð¢Uf„ᄽ ÷iÎe=s–8ç쩬Áÿ¼… â‚=•u‘¢€¨Ë©å!ÅsWâSTîN{JÑ(’cäiâÄUä\EŽb׬—eâÜR´êC=ÅM¿± vt²í6œÝULB­”G1y˜¬•á~¯+£û]hüW ÆöñXYáˆPõ)³Bu«ÍŠ˜úShœBO‹P@:Àñg è(äƒaéòÉ^>ÄA½†:€ß¿îàÃñp‹Œú]j¨ZâLŽ‹Õ;‘^é…^5ÒÁG:âºêŸ'3dåе¡ýFרicGãˆmá3YÊp"³•žÉ²ÙlV^ëðâ ßJ)ÝÄ‹ª0¡kag f»5h¦ÔKRœ‰]€æ@í@`› ë7¥gǤ'ÐNFE»ónÊh§P¬;+QcÿÉ¿)ÄSЧé× G$p-ËBÿgÁ÷uÜtÀ4r$³¶Ša¡C4…‡e™hl95iƒ/và~&‹ž\/qàg_&êc/_îˆb}´£^ÎÖÆg”?®2`×@ýtLBÕ#¯uðµŽhܨ…¯sèŠY; Õž­¯ÇÚQ©v4\übíh6°µÉñXÏEÀÊ"‹e`ŽêÖ¬uBlÜï0ÍŠu0*>ÿäJ¸“À,û¡|gaøÛotŠÃàÅä#~ЉƗ²$~ØluG’­î(*6Ý£àŽÂ1ülWpOá¸;ñÙ,~e-n<œ">üo#Èü*¦œqšEõ,¸ãê˜vÜñuÌzÜ uÌv܉uÌ~ ÜIuÌqÜɰ´»âàg óÛÉ·8Oœï]‰Ä[\Ÿs$e \£w$Å \¢]tMx¤Æš²±óK]QšnK‰rðËR÷¾+«–Fͤ;ÄJ늈ß-âµX£™~‡X£qGŠ÷3Tilq ÂfdÒuG„&³ZÝEaº³S"×n ¬%±xÀY/*ͺvÌŽRßM¦vR˜îJ¦¾‡€°"E^5b=Äæ>(G¶iÖ+†°çÍÝ*šA•S4t§€è3 Ü©ÐF«Ô,”Z'vµN¨&…  ƒ”‘žË¢ȉ å4”Z'5¨:g§ìÍÖ®Mtò'jØ=›µPØ @Ϲ¬ùtómœLãã^Ôµ6щÝèV>É©[±gðÉN/ÎgSÀzv‰¸Äí >«[ýϲޥãŠ!ã6 *Ry¦zFê)­¤^±JÝœôœÞf–…P¢FX™ Û%F·JŒî‘1LA·~(S—ƒÛ0”i+À u;¸Ó¡¡î@±=†`8Ž8ùrg¨òml‰+㕝‚BÅ”ü-¿¥UÌj§®@´¯­q¢þì=ÚªÀGŸ;©21¬ùµ›QÑã ·Î)–€z`Œ'1¶ ¸Q`\Þ…q“S4ZëÂh%Œ[œbù4nG¨¨í{]Úm|‡[ aª©Áq§[õžPDU¦l´KD®‘Ðòº"­<⌢¦À…"‰Çœ1v¼?ǵC»Z¸õ}ÇÒÔˆ2P‡Óû¯qÀ¼ ¨<‰ºAtâ»·ÕÔsË\ù?â{ºË؊ɲXòÏÿžï3CžÜ‡q½°!‘'S øâGœñOÊœÞÚÓr‚ FýãIN~ÒéýwŒ8‚›×E““ŸuzßGšÞÁÝ,ª ©þE~¼;Q÷~ÏOý)¢ÖQƒ‰É‰|ñ‹À3‡î LzGâ—° ÎQa=ø—Ô„¯Q^ú‘åš“ßpFó,t7í¦õ ÞvÒ`–²!ƒÕ@ã0mañ–G&–GN^á2±ôw!–.Ôn¸Ýn’»míIJhˆ1ÑU¥5Ì…èÆeZ†¹xMÝpB7Òeenð¢Ú ËТL, .>.‰e†%K‡ 7¨ºAER¡vTßïB° ?@®Ê’«ñC.¡ öˆ+–gIC‹UÇ\Búé¶Å‡.&?á2æÔ§Æ«ü´+n 9ë²QWUï4Á4~ÞeL½O·ò‹.<ø€uØe6Wܧ…À6ÜoÄa»¢º¢ÛKçjü*|«ø=Gã×\8hÙKgiü:|ã¦MélßÀ*ž£z5k4ªô® …3¡Í?»â…'w;ÙB¨ë».RÉÐ]’ÐÙ1ÉÀ‚pµ»“ÍÄ%;¸³`¶îl˜m¦ƒ;f›n~+¼AìÁa7h‘óX+©@~àÂk©\"´§äþîh^"óoP†pÇ„vDZ[I¾?Š/¹ãxÇÄkˆË`>½øHÇŒ†¸±#V»Sv#qG×\@)Qsäÿx/íÖÕŒ· Y$ž‘g”n+AÔf4¢æ4ÖëÝÑ">ÖE¨i¸çŽââ`xFsÓÇ0eáÏÉ€cŸ’‚cDF$<² ÇÄш8ö)ÓPõ_à°¢qh|º[×Pÿß ·n…UŸ·S†a}[·#Jq-X5ô­ë°T^€Þø"·n¡ˆ/¦Ôb:”ˆ–ºã&èW$o!¡{9Ñ\‹Ù®èÂ@"d¼šßj·Ûy›vŠÌNÈE+m\mÂödç›Ým6ïÛ8Îö'S‹ºÞ.Rïp“~OzYàn³ó/ÝÞ‘È‹½n"ÜÄÐÐU@Á‹ƒä}ÉB/tñâ+’ ^J2€8f0ù¸Û«!!çÜ&Ù)ÈR )xqi¿(Ê‚¼¸ÜÅ‹?™Zð¢Sð‚wñâ:0•ßp{J¸`íÿ¾ý>ô8wðˆÝÄnÁn͸u-¬ºƒ/äYúˆùQLHÅ/(“À&¿wKæ‚ìÒú~ È.Òx²/á£]£õÓžJŒ¸Xj,/P‚”3ñvó4XŸh­o5Ý5ŸÜ*FnâbxXZž¤;AhÂo£Í J4¿+Q+%•¦»ÌDc0‘ äJ´éŸWÇ\cþÖ:æ—ÆÇ4žt${žA¿›3âî¤Æýi|B7ú'§éÐýLú­zš  cÏ@R‘w³žÖ„!Hÿ J4¿+‘ fšžf&š‰Òšu7&â-iÞÏqÑÖš†ZTß>l—‹¼óðÄ+óð·u±:ûo¨¸Å0g2o'T·8@Éû.IºÅðhÊô¦ç¶[ÒTèDðŽ[¨¥6Õä¢O£±V³y^&Ú§÷¶‰ê‰Ì‡‰±ô‡»#‹ÒÌ1•³nKŽ«8¥DB“jËMqvY4Á¿Ã1&Íè ™hhlmLt-f¯Ô­ h¥².FC¾1 ÂÄF)š›Ò0vSšè™[ ŒÆ0 k¾L3ºᎥâÑ@àŽ§‰·R#î}„߼/M ' ŒÒ0ñÂêmDŽÖS³6Yij=‘†;]Çx8³¢ÌÚíàþ{öDšaÑÅ­ŒSàΉî2¸ `޽‚S1̱WÁ]sì5pÃ{Ü%0ÇÞwi³ßwtß{i¸ééᡵ—kµ‡Ö^î5~*ÍØ9§µ×™´B~.Í”‚ϧáJ@\ °Ûv9->OMWàë4ÝÅSH˜–²K€üL¤ÑÊ †† Oʦ†Æû{„þ±äèIÙä°“8ÄCë5H[å볡©8l|Xj+¯&(;á!±¾Ìå-e†Èž6ÊC"²gª‡Ddo£‡Däô&‰ÈÍ>ÊCÂG{°Èùø$Ö×]¸!LáuÝcÊéõÓ= §÷9úí8‚gÀNXsÿËCû_(ðOôxw ïZ¬AŠÅ3¦FòªÂ›Î›D¬P L÷6áÙQ³€2§Cp>Ý#Žð`¨GàN–Êgy`¨5bõÌöà‘8‰ðèŽõ}>.Ĩg»­ª¯ùž”úBÕ ‘¥ &^„‰í˜Ø‹/—yhq‰1Ë=¸îD¬#ìá{‰ìížHôí£vVÄ÷y‚¿†.åÿ5«øu;ßï‰ÊÏAl5´µÇ`i»–z<ÙEüHj%à¬|ÌEMI司„e Bf}N£7ø;øñ9×Èç<Á"qÿÝ,T²í¿ŸÅ÷dÁlCѨ<.*è<(ößrʱ=È88ž•®y8$Å/À ¡_ÃzˆÂYkÜÁ1jKL†üº'&²+=éà7Ès/ _Að›žd8š2üWqmÑÌð¾Èð¡È0áá»2Lˆ ï8òX#åôô|+¼)ùö÷¦ä;À‹ùŽ¡|/¶½F¾U^Êw˜—êMªñòaÞdÆ5^Ê8%¥ÛEF»3sN™GK>‚<²ðI9ÖRŽÿF9Ö›9Ö‹Ç9Ž÷ò±]9Ž9ÆDQwbQŸ–ñ„ÔŒ'¦f<‰2®#ÉþEqJ@C[möòé^qçnÞmªOškÍõòyP+5ä(NÍz_ˆõ«¼8Q›ì²^³ÊKÖkÐY^Ǥ5஀¹ès/Ö£²VR]îJ˜ŠÚÀý ¦¢à®‚©h³3µŸ÷ò5^q£ë“þ¹7fìv+|­·Û-c½¥òu^c ìÆ˜6{S…6;ßâÕí…bO|[Ћ62qŠØéÅcÕÆî£‹ˆ´¡q^} 3õž§¥¦š3Pðo\·¦aÏÞçmSù~/šä?àmÓø/Žà»²ôI7wwg- 1ê˜WLv?îS¦ÊO!1N§q‘ ò3H9륳å Xx ‚ @ãrTf½.–_ÓÍV]ñ,]¢z¹Ìý2nhì@;YéX46YMšBE“§¦SVšDÙÔætd‡¶4Ùa]ÎhÞËÁ9ŠÙW¤ãµ+Çêt¼vå\“Î'‹áÁ95NÁ“v>%=&xÒÁ§Â'3ØÓ”Þ}+¢Ù,­Æ§™¥É@«[sÒã‚[J£®¥áaâÜtQýµÞ„óÞž]H|ÆåÅE¸ w#`_j·‡ÛdÜ^CßáÛÅ×bnƒ§]³F1׆t¾>¯íÈrÙ-äv™8rð ébÍ"zîhÂÀætê>0ñ¡ÖWD·˜?^è6·¤ën꫘h[ºî@R¶§cÏBBv¦S7E4˜’®™²ó®t\@$klDÐÝH?®Ò¨3§Ÿ/,Ó°Òy,”ä¯îäñtÝÞÛ¿ö=:äâ{È·ê=&vû¼¨"q„IÜ&‡UMK´ØÜhòÉÍe„aÝ ¦wÛòk§m;ïûÈÑÏA=–ÎGwÝÙ£ÇRSCÓø©.Ndšœx ?O§ëi46aš³éX/X sÄY¿ØU-ödµ ½”Žgp; †:ù•T†òî ½J¬4u¿Ö¡×»3ÔÅouk#IVÞjŸ])|Üâ÷ºñyºŒ0Àg[Ÿmüazð<í׺K,xÆçà èÞÆ“ ¾ÁÕôòi«ýõÐsð÷Ñbzÿ

ÄSÉf³¿ô×ÿÈúö=X¿3³ü "œ¹ØÏ^]g¼V¢‰düoYœLfü||)´í¡Ëoøíøú¾1G†øç)þÆßaÁuJh±:Xà_§ààß”£HvÇ[rß|±tŸ¡qµK6Zj'Xžu‘ÝG)8¾°x|¡EFkë DÑÀzEæÉ Ñ›NȦá3!TPåƒl¦Q6¿§˜Ùæ3¡ÙŸ C}ýú œù œê‹ K­R!¾BŠ–õáC¤( æÑJºÁ¶D ÅlùíCXþÕßú+ýRey•/•‚”À¤e:ñF”}Ò²Q NEÞ¦ÚQ“š«Ê‘»ãrÈ$êÔÉ:mì8—‡0é¤Ä :ƒ6†#øIa1,èŒú¬·@òYe?%ÅȆÆau6. jÊ"¶ZñŸ–bEü, Ëö÷!ïg‰}(ÿ+H"—"ï¶Á¤-gÙ³ìhµ,‚,)æãבäY9šËPšzTàU‰ö[††Ô *ø h0¬ÖÏÁ˜ðÚŸ+‡*^Ïù«– 4…7’Å[å^±ü­¿äóåÐ{ñ¯2 ²€P.•CËz‚Ø|èç3Ú%Ó­h¤†ƒUr°Õ޶1bþV»LT¬¦$ë0¯ÏB¬âëe:ß½•Áp¸Ý¾ðJ‰˜øW™xn¿MŽèV¼ö3Â'°ì ,_ Òv#iñ_òˆš’$-Jírp¾Íëhþùq@Ž„¯gäInœ±Å!nó?ÀU­“L6‚n½E»©§å`‹Ÿ@݉ÈZì !;GÈ®ÈÁF. Œ\:)âªL  Ù9šÕî8/Q+© ÇQP×– E4 t;m:³ò@pj¡a ·¦Š©QÁÙ*‚¬„ø|üÚC·lXÓC•à<;8©þyv™ ÿV+qàK|YÅøp%44ɘJï">1„ÚðRÞs¤DI‰Ååµâ˜ÑÒ@Øê [b›ØÆBÍ$±Cl•ÞÐÐ&)K¤X¬¬ÿ ÷X”à\{4ÇK[À5ìyM˜h†œnú§ÛY¿>hsñ>SÉÜ´åO´AgMC]Wj)äêæñ"f.³3“· .2ŸIÌ<Ä;_A¥Fspì·ýУѥw¡òzhüoµ½º@ÿ-5^×–ñ4NCsi2ŸºöH}êÚ’£*²òÚÕ6}`\²¼Bö<_!sž¯ðo¢…Ç•Qœq‚Dëb9¤û5¥û¡1ºý´Cû)-èÎ e.¡‹‹? fF¡WñŸFCÎ!•íü/cÔ®~ª|»ˆÿä‘¢_£Q7ÿ[Ôx‘ƒê’ž#àÿ#ü· y³Hø‘»x C*—ä˜ÍæÅà†.‹fËQÖFHÔÒœ.s'Ër¼,ͳOºº"¿ö•ZX¾‰øë}–ˆþLÁŸFü™å³|¨þ¿«b© wi0ù×'t”Ô¥ÄþÛ±cÂ]úM,ž*–ÔìúþÉìþýÿ!»¯P˜²<Ç4.!X,¦ÔùL…)u>4-–ó˜q‰•9¨ðÜŸ¢JƒRGó‘*G¤Jã) y„ 5^û‹Ò³Nü=šM|©@ÿ,­ |7Åü‚ÎTcÑ\ÉÆb•ŽÃŸñ>´6 tY¬Êyܸ‚‘–RÀ¯P¿úÏ[ó'Á^û©öùW•?AåOPùTþ•ÿ/©ü)Ê?ññò¯ÍyÜüÄÓÊ? ‹>Ù×¥ÆcÝŸ&ög±ëÿ4Ø؆¯*ÓW™Ÿ°b™à—Ê4Õ÷˜ª”¶S­½©*E {õ¿jí7R~'ò{”ÿÃïúMЯPÊ‚ùi"¿&ƒ‡þég¼éÏbf32sZ 37ÿy dËŸf¦i¬akÎã¦SR‰ˆøg`ö3S²ßF] ÿ ¼¤Yăù>Ò¨RŽ„çûL*Û¿*‘_$Z ÕA¢ÉD;¾ªž¿BÕOžL|—ßg?Îî/ˆ†W¿²¤s°¤sñ§%¥×îü/ŠÛ*(”·&)ßõ¼Úw’Uô埶;'i*`4 o‘œ¤©€Ñ¾T $£}Oh î¦$Ú…j ¢Šu¡Ó Õ˜'QÕvGïBU‹¨öt¡ªí†ªöITuÝQííB5Qµw¡š× Õ<ߥb¥#çÿ¿-„Ýl!Œòa- Z‘œTm'ÞÔ%à~Šzñê!ÿ¿Î'³ÐH‰Oa¡£o”}ƒO%½!9¨$5‡€„Fý‡¨Q.‹ò‰¾ÉJy1Ÿ‡ sðAþ·t®yֲޑƒP¥¸‘õ½ZºVn ”_-æ›0Ù! Ïl’ÑÎ"ÊÍb²wû!óðã¦ÃaÂýM:M¸ÛþÍršñ³,Š×h@ ]-özûýâÿ@ý"„øJs_gÁ»Åy’ÿn1¢<šƒZ' ú™81¼Ya烤Ðâ";*G⧤ă2!dDjÈ@ÁwмBжóRž%fÜÈ'Åüy,f\›À=õ)OŠ7&Ì+2]ymÒ + ¹&‘¨K$f&àácH ,¸5ëqA¦0ØùíDê©“ ¬a¬Qò–#ÉÓ¥à£â¨ÿQ1ûv>CòÎÂÀÙ©Ôr ­s¢iw`R¢ÀæJÞ ›ÿ°]` %ï¯ñ&/–´IŠvðiPÒxJIgBIã)%%EIe*é‰ÄK$F‹’.‘ðêxŽP<%]+²ÍeB%Ó©Ç)»ˆ·¥ÒzÑêß@“'(q/Jü¥™øK‰G$j!nªxa]Ÿ?´kÿdjy¬“þ€ X:D™C?Ô=—OÚ½¥tº;£èÊÔÉ”°^4f~JòþBŸ ô…”°Þ}Qòú‘»¤–¸{,ÉM qól’›OÞ–_Ø–HHÿ”HLH$à‹wv§;Ö_ÅÇlH_£°þ í:¬.*îo¨t¿îTŽ }#DÌ"Ì"w²í™l¨Ì‡Ê¡3…þS–ŠÚù0f®L|©P-Çòç dùÛên ñˆ’(j¸µÝˆÊG%õ¨Ì&G…Œ&‰Ö=ÎTv>Næ“äààw£Áï2¼ÃfçÍrhÈ»ø{§8ÏÂ§ÉØ4‡¿Û+0ô]…O§¸éFÜ Š«2âfÊøfÂîý^¦’£áUj;o”‰fO59ʈ£ zb,‘`c pøÒšCÛ¿}`ÕŽddÁM$O‡Ay¸ÿ?ZI;À }€bÕY|ž:îžËAû¦WgçòJp~‚›¯Qç)* Ã@ É/¼§’ 9hï÷{Ü×¹ûòPc{à- ´Å²ÔÇË‚#eº²ýÁQ2]³F³,»pþoÀù"áeˆóáü hnÑd¼).ó‘6!¨Hj™W1ñPfb®Æ¡û2¡ö"ÃÊi$¼‘_éB>ÛD>›&  äd‚e¹·&‘ÏO"_ˆÈ;»oFä[ù Dλï2‘ïb|7"_!Gù %‘Ç“È÷"ò«„Ü8p:áçZT¸–£@è¿`è ½ÅúÎÕèɈç"á‘Ï5¡Þ…ò¹¿ÍúΣ!bŒ1KãwX_îHIAÏŽ¸ƒße}¯9RPø5¿GöŠrì²Õ¶™a¾ †×à7ÚÅåüëd_Ô1Ö_‚É%qf bíRps<0I_À™ªÞâŽÆPƒ3tÍÑÈ+%<Ýh“"|îÜ»AÿÆñ š‘Éêž°8Kòo Hþ͆ðj)F{§5R4¸èíðÖ@h[à—,½ÉúÀ4WºäíÀö#e#PánÌ‰ŠˆQPtiÛ *ÎxÉ|f0†Ö#ÕŒM÷h5“&ƒ{¬šÉ8‹¯fÊT‰O’€ ©ñ“v>&ÖøIÌzF8Šn M5#¡Tt©Y2>ßäðüÌçIÑp4tJ0CÑîb`_¡„ty Ä€£æaTc`D£NØÝµoоÙ+¸#©æn1üéÄÿ>f‹¿ dá©ÛV[·þ~;GuÊÊ}éjƆ· E¾ou²Zà8Ñ:&½…÷;ä·ðÈWyO|ÕâNöÙ¦½Ûɪ‚Ö÷:ÙŠ\Ûû,VÇì¥ühø‹»8ÞIöß Íx­Ždû?{_ªÐˬü½`VlTlÔiEV™¿ü}]åIÍ< kâ£D·ò_è6ÿ‘w³ótÒÍ` ÖðvDé`hÕ8)¨ÆÉ…‡c2ŠBGö½#ñ¿ÕZ4üƸ—µôwxYÀK¾kÐ(ïKoÔu;fÒú+m“ùß›A m”yi°íŇ!VBÊzñȳ—*¥eÖÁ]¨W€éÖ8Yæþ]4üe ¼Ü_ÂcÏìŠPàŽGæ¿×еïä¨VYY-*¡¿©è»?t¯=ؽ˜¨tír%š”*ƒÁÙ[ÇÔ18.>ÆbèA,x¢ øRÔÿÓÿ‰ J­Â Ëîñ2V틎ëwšÃ( Æ G QMmhk×Ð÷F‹>‚Q0Ýè§UŒ0oód°9fä¢f&8§56JxD]‰šÂ¥„Ðô29¨ñ:¦kI*q:®­gOåáXFGwsT‡¬l“‰‰ ]ê°w²ö:fY 8ÇÐ…†-¡{ïy18Ë3e9¸+3u¸uLû Ü}u̺MnAM/†|¡ÄRåøÞ(¾“Ô*|)‹Q[Æ‚z±n©ÐÛùr WaGX_ƒ‹°'¬D>ŽÂÛ ðCåÿ ÐE2¾:dÑפÒh€¯†GcP4‰Ž âMºo"ðµ,ª[fÀð6öÚÏó,½ý±€ µkšqjÕØDÕôI7ÿ71jñxfg\¸‡ª Ÿ£7côµêV#l †ÅÔÄ[Qß!„FWãÔr¶‹§®a4@\ °ð/ ª¨“ªc¶=(?Åó,™¸˜qàÕ}äáÇx‰¹ÝïÀ6 ŸÚ+®¿î夘ÀZ=„Òýä~6½Ücìg¯b_/_ã£@ó|µlù¤–ÐÕú‚zÛç?´`åO 3tf„%˜ 0¦pþ%3Ö“åk}¨÷VCŸã ¾ÙÕ‰•oô¡@/ßêãëjkð•oðA¡Ñ9Zö¸ÎRN‘\ g0£GÂ;|ýÄ£ ²¾¶Å—m<‘áÁ»Á Ç}fÈ%#$êïy®0|òÃ*—á1¼É‡Bf4¤†÷æìå× h›¯—¡÷G$øZL˜v„¹Îpß#‘#â!}³ðÿö_›’À~D>0ù5D~ÒnFäƒù·(æ!¿hµÜ“øITÑCá$ÂGˆ°2áXT59^Ž„·"ÂÁ)ÔN55XN•yj§¡öJ¨ïé²@~7‰|&®È‡¤ _‰ÈWAÚ툼*Ä Ñ ¶ö»˜e‹Ì·ÉÑü%hRoìo¯RXÿÒ­ó…ú¿=¯AÜBoö¼º§¿“"ñˆ6Ôæ§Ó¦ÝøõoôCÒ¨ÚäoöÓÜ3ˆ±2i錽¿ZAsQD=• ùy9Øã3LB ËÂíáäÑ+¢©PøE@ T`6Af|j¢¬ÎEá£'W£‚ËáJh§?âõ@Ñ·&WÖ4û]™¢§(¸Þ”Û³+;²+ñ†ò8X«MQHç_ú— -Q[ÏÄbNW"ØÐ¡uz—@Ô ŠêMQ3³gzÇᕤ¦çÙ\Àw¯x*tƹÙG(QüïƒA¹/Rð¨:òúßZú”©}^ÿæ?³¯Û`@WbÙ™x-ñ3%ŠPk”X}‡wJ‚ë•®@ñ¾Ê h£ 5HK¨"6ct”Èø_ë,Îä Z12SíRbþý ”–ï63g©™ÇÒ6A· ”üu¬…Ô©ìA» E‡â]Š´ìÇ 8P¼Mt8É!~DñŽ@Ùs(eŠ—©ù'qk V¡†äù+‹%Ëò63„dÝüSuh?É’¼ß ÓtÐ ’Ñfþšá0X›AJRˆUIˆUmê C µãQâ£DY"Ñþ ˆŸP ¥?T²öà­ëE·Ùi¨ôà­Ëpj3ÏQ£¸„mæ d“¯¡|“wb«AÝö#‚¨Q#¯¿4`/Ù3ÚéKÿ1rzA‰e´ÊG©‘À—>4oæì‡N`µj$¸‘od–ò>^G‰ 6À†?–¼Ð0G %”Á|ÔtºP…Þýòk8B/RÍž*®½‹ŽJf—¨FOÄ—Ë O$p0ƒê:•«85ÇE…0¯R©ÅwÀ™‚?*4|;éT³¬RI§C·éyi 8ïËŸÃ𻬆©ëÁ= +˜³àžƒÌ9•¯WñæÀFkñ².–-&‘Í*> Ý®RÓ/&ƒE]M›ŸÚÕöFósð½j¬ HåjWí:¬êJ¶qHWüŽP~ÇŒ(˜´Ù'Ʋãj”ò<©"øã±§ÔevÒÖÃJé@Õ£rU·b«5/ÚÈC6Ÿ.«½P㣚ìõëñFÂoùÏã­Š ¿3¾…·„1öQ#B¥þŠ;C7ÍM5Ùkÿ'>C4§R³=ef{àï«fÇ#ízD¼ð õ4þ#O§"Ce^¡!²þZ²ËÒt®<Ö"teƒO‚åÕõAÌ6 VðZ$¼Ö—¾Žå_À¡UÃEҸ£%Câ5ZðP@· 0Yª`#Yu²l)[M_–Ñ8ô:>“Ó8-òúË/ã ‹moœ&Úº—QÅ"¸W꘵p›S0ÄR0ÄžÀÜúÔ~aðð{¡ßa¹úMcsEk©€kDÛ±€æT‰…k7 ×nnŸQ¸ã?˜Êwãn_}š|‡Ê~ø©;Õ-u¬+u,55êÌS u/eû°T»(Õëý=æ_Ʋ)¢Tu¹ ”ê˜(ÕíÇKuÛ(ºPª»à‚¼(°ò&]°ŽŠÒ<ŠªÚ’EÂ(Ó£§–©ÒÚ•6–Lë–J4Äú´U[Å2÷÷†[¡Ê‚§‹ãþÓÅ \(&|P 壭ÝKn4ØZ6A”¼ž¦±¤‚7’þàñ°äi¶¢êf˜“Þ3Öt+Î/Âbô k!Ÿe…õè:ŸcÅÉŠ6ò[¬Æ4†4“Í·ÒbµÛ6ûTZÜkn c®“Yðh õ*×Bå£Õ´|_Ô Wci…+îåŒË•ÜV[Œ]½Šë?rnÿÆRrÔõß0t–†%t‡etV†t–‡Utúÿ†ÎÀ¿³¢s©–ÙÐ}´£3<ËÎÖZæ¬`¸áûYÙŽ–èÁ‡¡èõ(ƒW£èuÐÇkð1Xù~jùQZùa Öòš||ØÊGô@ º½|Z€GùÒžh.Aw–¯R¡¡É ^Üø\܉M§¢µà¦k+ˆVí¸˜‹û¼ß¡˜…æFïBÜ0ˆ"ªä@SÝÑòvî ¬{5°îU H›x“:iÒpw"”‚ô‰Ýã”v;h÷Ø@º‡Œí¥ EËÞ$TîC¤SR^6‘^f¼‘îH¯"Ò}>M¤7è¶u Ò¤õ…ˆ´1é0S¦&áv,BRÜx-?ü—L¤£QôjJAš´¾}‘6§ m1‘¶ ¥í(BÒˆô/L"]ŒH§¥ ݈H7Ò#ˆtz Òm&ÒmȨQ„ ¤;éX|'‘î¦ÛÒ)H/!R4·| ‘ÎLAzÕDzUâ×é1ô&"=æã·’HïÐ}æ\7 -g庹¿ ÍŸÎÍ[ŸZrðž`.î%ç\½.ö‹¹?t²€ö¾ ûž,ˆ¼i)=YÀ‹ dåâ•Bæè÷#üæ^Êi_—ý”Źš¢¨ó–šTJ;Ù:ÆÀ¹ ƒ|)ÿm4ÏBwñ"þ»¨q²<^Ä e.;VÁ{o‰Ui:6,Òþ·x÷ø¸Oæ­ÿ†àHø´/ÿ0–«ŽÅâJ¸h*~ð“ù? tQ‘JxššñÉûžµýõê˜åìýþ?ÅRH$@ð¥Þ‡À1~ŒowQ/,ÃÛ”$Mhˆ+×ÜéÂDÙÁãÆN×ZöõòM‚[XGËsq›L Æ+r5UÕþîê=\R.§o©ftYûÀJt7„åj†Cä;¸i+noŽÂ¡ô¼FG¥ü¢FÇhþõO#á«>2+±Pådg%d¨jé”ÉrkVÂXsûÅg¹hã5ŸbÖšcÍZ†c+ wáM‹ò >ÞþËà߈èVåâNÝ(Q;¢ÛGè’¶¤/øB'KHØ1}Eü Ad·4àm¾\ ò\È(ýY:¡:ØK[lO"„²àC`üEÆ/²à‰ÆøO¥¹Ì¢0=Žz/îE^/©ü `á“Ê»Baô báSІW“²ðénW!ðL |¶[àu,øš\¼¾2IP~'Iù½§Rþo&åðåR('»Ã‰Tª)¤BꢘúK]ÔRÀ©‹Rab¬Ï©NFD [žÍ½,#Ñf§0}ÁGï¸k¥H/l4u¸á¥ÕE½$j},¢YKhÞ$4“L4“$>¥ *5m”Ð:QN—œt©#‰r¢Z‹^U[)ø6WB¾u²öìŠsZ%"ËTÂ?ÏÏ"áó¾ŒJÔG,a6Ñð#wf?äæ zÆ–J¬²žIËÀ­ù¼œÁõLY!¡ñÎÞØ–JÁNVÜÉ,˜ _&ÏŠÏ,˜_NÃç¸2\!Å”9_)Å{•^ ðϤXð Ó•â+ŒÅÛ^‘ø,Áú\Ó 0á߃—R ¯ÃKЗEép¨ÞÛe‚ª ¸(+.´Kø ¶ûq?{# 퓃wS®]SÔƒ@WólÁ+oåOäGÿº×@Gž¾GçC)V|å-¥Ô<;Âÿ›üqó¸ì.8 ­ÿMŸEÀ1áH.§ •üâ{ÝÀ?d)ød¨ÿ ¿ºž ö8„!.u¡`0­8¿ÆDñD&*B,,{ E ™ ·ç7Q<‘‰ ¢+f|#ËÀ tRˆ%%Ö"b¥î±XÔ'B¬O„°®5§*b5#íËÑÜnÞ“?Z“Â5¼ ½…&è7žb¯øö§¬wßÓù­ï—Ÿ.€‰êSéÛ}Ïä_¯ü xï~*ÿ´ïÙ‚ü{Ÿ–ŸÅ[ÿ[sSŒ¨g )oKNIò|SÒÈýº±Én'èÁßýO-y}Ïä·½W~ryð){½ïù‚ü%¿*?¹ìHÍe$$ÿ.Ú–Kæ‚!ϯ¹´A.7|ˆßÎ\™¹ÓzÒŽó‹–û^(€–ÙûVz1ïÊUXš'tu@ ³J‹ÕbÕR~ËÇ?Áy¯_p½„÷‹xQ$|ׇã²Ìÿ`„=‚°{FØW+ù÷³Þ$Fýô=cøþ}™‹w+Ó)£É8M…üN‡»se%Í3‚QÔ<:’ì ;Dó`  £Ï||ÅHçßRñn;_ÄbýÄN,ü¹5Ÿµdü5Tc`€ZÂø˜¨ý}¨0a)‹ç%zÐŽ"eÏc…oKxÖ]8¾#ÆüÏ Ê7}| î°vX-| µ#ºF º6¦Ðµ‘Ñ)ÛÆøf&¬²“uV’J ;X,ã'&e;ßÙEÙ®$e_v£,Ò²¸AÙž$etõ%š«¨iž-‚²C4%N`b7” sÉ¿s±üª`ü‰¶#/R tñôéy"á>2ùÜÙUžõPžëFyn$ËsËËU´4Ïh‰Ês‰ãŒÞ4M¡Ž|”z';SÉØCœØ#oOΰTîÅ«6᛾ŒV$ºíEiÌKµõLHFº•Jœ½az‚ H½:ò(áT)‘*ñ7p¯ˆÔ»ƒWIº’ÏzàéÐ0ü>œ5Üpø¾ ßöéjøZ |=à—A‹kHPÝ7F¢U雷Lõñãi'—úáº$ÿÈÆÇH@h½Ô÷s+¬?·Òü±‚ôÁyûj¢3“ŒÇ$“èÎu²ÕžEúwQø¼í‹‰ ÍTÉÂ6ÈJû„‘vQí¨:3´XöæªÐ6׈¾vÅ4â}PO¾£ûp“8¸§2ù*¸À÷kçÀßAZÅO;@öV¼¬½&…nBi¿doZ×*¿!Åñ<›”X ~Ý’pžÃ¾„š!½½æÖ7ľƒ…ÌJqÂùªKär‘™š [Cú&(ÅYWñ&;¾°ø ]@™³§÷{0u`©Êƒ·þ¤Ðc0>ãõÐT ÿ?ÚØíšú Ñ4q>ÛX®·Ÿò€ý᧬8ÓüGi8>•§‚SQÁ”éàö¯`*¶ÓÖ?jë¥àÅ‚ÀÅ\ í‡yËéú§«uyü.Î÷YßKÁÿÀRz©€?d}/¿x£ø‹7,¥— `$è{¥ ØYPÜY`)½R¿//^-(¾ ~^™@ï]*XJŠöI}¯€Ã÷¥×  Cã]y˜®ïc¦¸  0t½ ýEÚýè{½ øÐìB§ óGf  3ÿ_°Òë<‚Ph‡3WU.U ù!ê«âlÀx>~ÑŠ·’IôðϰKæëÊÓè\’ñkÈf;¥³?+‰ gìüœ3ÄBaH!¯õß °üæz˜ùzcŠÉ£˜|AÂkÉ™ þCôÝ€d<ž0ï¦Åš‹ Aâ›M‹å´—»'Ù–¿è”qª„çÔ‡¡]î1tn¼Ì’#ïOïiá³åHvyÿlq›ö,°]îo Ðü䑸|™/”3ìEôb„> â¶Ë=CBðM²aîm“L֨Й2‚I‡Á×™o¥óô!=%<ã÷ÏNwÑCëHÄ? Û‚HcrèRfž¯ÕÄÏ'ž×_ÊŒâE¬½øÃkXûåàО¡@þ98¬g`XO|QA¬þ!Ù¬_?#W)ùgËñ”‡õ³rh‰Jýˆ4Ñ.QÅÐ<À4ù99ô }øžOøcÑ8„@Ïš­6Ѓ‹H?L‡Ã²eÞ)G#³-üš¬ê¨‚ìoÊ}¯d«{FcþêžRù•L~GîË3{—óL~OŽCýÁÍ垤!»FàÙ~å^Ø*q&Œ£ÇB“ Sa3¸RTÁ+Áá=ýÃ{ZÊ+²y³l.,n.´T4¶óé –pÇO¨„{ù %šMFf*±h齟Mñ“*™0JQQŒÍ_ó~&*—Y¬DÂÙt6»D M+ O/¬ôb ^J¾…••{½ß@¥°JTD''+²H<]eBîÅ›ÑÒ™…|å<'™óz“´ 0«o$€¹I€M&Àf˜[È·À´$À6`;´ò/`z½ °ÓØ…÷<ª·²â­ ·n…‰p'x°tA!o'_ü½‘¾ÃL¿O‰GKø‘b†È¡zá!% Ìfü„ˆºùŠ©èÁO®™IbN›ÈÎ ²‡~Žf%ΛàQ€_"€ÙI€ËP…Û¨¢®>‡øò…ßVB‰@¸¢ îP*q’mü®¢+Ù=ÞAؘ«î+ü>„øÏþµŸñ?Pt5dqë-F×âÒ±¥?ÄÐÖd(Ui‚²èY TÀ%|°•Î/äU*0a0a˜Jy')®V"Õ`Š%|„šBÜ^>ÒŒ…ñm*ƒ˜*S~ †{ÉqX»Ü 4¨L¢û_–Q‡°L‚~²&ç)àBUJSU>…rY(ÈÐΧªÑð‚ÂO:x“ * W–@A]XÐf0¸¤%crh%“§«|†J=ï5ͤÏhxsa4Û¿¥P¦ŒñŒÏVa± Ýøs&ÞòlQ£|ž ª!%ñæÒªÞªFÁ7} ñ:_ ‹d˜²„@ª ^¨´B Þ,ˆÅý7 $(Ä5i¯p®Fc£0Ýf¼0qVD.w5ÍE;Ȳ,pfpä Ævª|'q<ȼŸsJåßøýóx…ô´ZX^TÁ^<ù?£ÆzQÄYŠ8Fx’Nõ~Ǽó±#øE5–ÝÙqIŠcÏÒ1…ü2u’†¶%DÔ5•Œ]×€®•Pc7À 5v“.oÈ·E*w`©D䮬O’{“fWüލRhÁ÷ˆKºŠlÂ9ð>ò ¸É¨È×Òšþã]€‰Ç+4\RÈû£‘ØS¹’âr·ñƒ5ƒ£ƒ5“Y•Æ«4¤è3£©·ó¡ðÚ°¾0R‹òQZhxIxDIéÈ>Zóþw ¯×¢8Š4o'jÑú'ih‚îGTk±>\ . )1_eã–"…Õ–|õë¢EÂú¤Díé4bYNç*N—{‚e™CGÇe6¼Cÿ*×(WóÙ­ùÛ`1YZ[È/AW€ ¿_Ž\ÑBÜí¤O¥´¡„_%(ŽPü¦¡2d¢Ë_•W’Ïäj?v¹'>CKK+vóžÙÛXÙsôûBï²,úxdÈo¿\öò|7fà²ïÑ0þýìŠ[™e?È®ømÙ¡}U2Ë@k'ÛdèlJè4ÿX®çl¹RÎ"h‹Ã1Úâp7¬#Ái ØF³1` Φ€cŒ•Ú¯³ÖJí×UîÊJæ®wC ­œU•Ì3ÜÕ•Ì;³­géÁý¢’eLµÒ€Ôc.ú™-àî¬g=W»«ž=³ÚŠ«üg×`p%ûÚç\Éž[ îàJöü:p÷(/lçËzöâ&pw׳¯o÷h%ËBCŸÇ*™-{¯dÙ{À=QÉ^B‹ž'+YÎApOU²ÜCà®­byGÁ]Wžq ÜH=ëuܳƒXïSàFëÙËgl¨—ð•³àÄêYŸóàÆëÙ7/»§žå_÷Âöêp÷Ö³oqtÓ^»aãUVX,Ç`µÌxµ5¥7£5$kêzYåÃɿȆ¡·Ž í¢·öƒÞ:’6кÙF‘¿ÍðÛùhòo4ü>†ü› ¿“×Z» .^gí6@¸y=¬4Òxl¿‡³Æñõ„½‰”æyùxðoD}º üé|"ZVÖ½tÜY–Á'Yõ Ò~3Ùš©a‚©Vè5ÙèvÖÐ6Þ]ø ´¼Éª{?ù¤¬Ÿ¤Ò—Dðtú”Q`k 3¬qT@>™I žÌ²ö.âs­ÐÿÃÛ iòÊä󬺆ò!Þm›o fêIr=ÉJóBŒ9ñ¯„œøúb+ ß^bå‹!*<¶äã²oó¥,è„„N¾ôo×úoù…8ø¾ÌªÄA=³PòTìžIkƒ+­¯Q«¬¨9û¾šÜgùp˾Æ×’÷y¾Á<Êpä?ÊXÅQVö"ßdí]öuï\²0¯dßÙmå»­¡H¡? +"ìàÞ´¶ê/’ÒÊ=ðÁ÷Z£†åí¢¿ ÷øPö+‘iÌ u¥¬AѱþkFÏ8†Øpu±´FÃñÂ(?e%ͦÿ ¼åm¶ùt -ŸCÏ´é?ÄŸï‡Ç—ðY<\Ñ~.H‘~™Ï†Xh¤ßO(¡‡|sÀO%Aø ¯Å& —‰ØZ[+bÛ[Èç?Žm‰­½°-LÁAˆm ò÷û2³ýˆï²z|• ë™l×®±ÅqO²ûéçðíD“9ÐU×Ú «n²Á¸@ò§M‡…­hO‡êBØe·z|åóB¸±°‡–/¨½Âr—ï$oºð¦óÝ6Ý•?ðchDÂ0"Îþ}ÒŸÅÁ¨¥¿j1ÌÉ)ù÷1ãÉbÜûÆÓC, ú•ùx¿Ïÿ¾¥,›ïMâî†àLÒžDžš/áîÀ¨²—ø[<|ÒA*ßsøA›žã›4 |¹üùà3¨„Cw‚çh¢8=…0ºöBsŽ Ý'e½ù øÔ¿Ñˆ¡'mzoúìÍOa¢g›ô¯ÕÐËü¬ ™>ü‚Q.ÃÖÉ×ûõ+û&¿dƒÑ¶,Ÿ_†4Ÿ”½Ê¯ð·8‡:ÄQúS- %@Ap3<þmŒ!5Ð3½Ìbéݯì5~µY¿îýŒWü–`_7@E×¼oÓ¿ÙÏàÏ뀧%c ÚŸ·é°F}E…UØ!.YaýÑgTØü6Ènâ~²Â*í&ò'*l0F‰ j×}4C ³C+Ï)¬‘¹Áj»žMSP çR@ýÔχÛõ—èíàŒÏ£xzµ6ÊnŒq颌×ú‘†ê1N•ýF±¼uh “Üû=©pnHÆ÷¦øÿ@«_ÿ"ÅOHÆ÷¢xÔM1 ãa­‹¯Ä›ìzýu‘¸f»þ €žZØ8€´}N³ë¯@­ê/7¡Øhf Î>8~΄/ZfòV2«œ`ƒ5aò/ŸÏ§°WͶ 㶈y•/ ˜o4±Â°’þ-h3m¯c[è¹Åö8 ´Ÿ–À÷«°œÀl—Â÷·p¹ãàË໫3àPsðvýëPº³¹Šärp¼ž®Ž ·[ÖÛy›–¦ °É‹êPåÛ8m¶Óþ&ŒE[í]+ÑL3í2î@Áçr›Ë}ŠÄÔ¨‰8jÇMW†¬<%t×`2º°‚Fg ¬ /»VЗí¼Ý'‰v÷ ±ìDR´¹œ ¢®, Ç¬à°],2qoý8¾ãˆ‘¾Î.å±ù¢  9Gq¹L%Ãɽи%;tB,AÖ¦ôE_¶ÃâßNŠQÕÊ;íº5:¸x>WëérWZ±´÷ ´½Qíé†Z½_(³÷.spá|YX,ñ6­·°°òrYúËe/—õx¹,“6¤ïÙiCú±Dºgpè¸ê™ò܃õL}d§5»Vãàì¡™¨ ó!ä£òG²w…#NœÀ^8€lÌVgKdëxˆ#ÓM6™óî Íñ¢´¤Fw¤£ ÷*CãĨÔÝó'óC VO¡üp=³5‚{ÄØfŸì@‰sÝϱ™Lu„&–„^¢ƒ%,;ot§(4a¼ÉŽfƒáÚ ŸæÐm|: ë(­õƒ÷L‡h>-´‹Ì'£b󈈅Æèëè—ñ/HÎÑzæXd«gÎÅà¯g®Õ¾È4½v¯;'_SCxR _Šîä’&Tû¼Ü¨¾Â’†n#Qc5P¸Æ!Ô´À¡»t«x¶üq™‡n;ß yžªgnt¡)§EÀ=]Ï<'‚6LÿnM‘Ä·8€;( lw$Ï v8’ç_8Ìó‚ó¼àKdªž†<5QG7ɶHqŽ;bQ¾Ç¡{ø^‡®Äq矜샺Sù~™ì:âÐݰ¦ÀUßQ‡ÃLêFë.§ÅidµÛ?Û‚›Ÿuè^ÝM°ç´P¼àðf$œ;t5}.ö7¼7(Цßt @›qËmÛ~ÍamÜp¤JZéü¦#UÒÊà·©’V~Û‘*ieò»]Œº×Ũûø‰ÆdhQô€|™z:-‹*œÁ{™½÷2ï—M.äªN—ûŠŒÝQá…jFÑAì.aëtPoCS¼ÐÛÐ.rR—Ç8Q€V& ƒ¼“œ|¤³«™v¦6ó>ÆùX+Wx3ÿØÊëq4É«Ð9Î)ZøD§èox¼= íjÞï“A 3Ð¥§8ù§Ùö@ÀB´óf§nÅ™À dc4Í‚àúhfáä30jO!šÛO'ág¡ÎÚÏAçäsœÐ dJ‰nóŸ*–pCj®S·‹†iç-X8ÝŽekíV6è”  $ ¨$ :ô/³(KŒ¢,…PQaI@÷w—A@ž—>@¬ñ…ÏÏ@s“+ÍX* Öðg)!B«Ã*Qz#…‘ÕN2»0 VÁú|Œ@ž}­› +ÄjÏ|ÖûÅ\Yu¹?§Ig›Yï M=Ûœ4’2t/@U]Ϩ†Z¼ ãaØ…³À—Îx8Í©!w>™°¥KÛ'r»S ñ”ñEáÀœœ¢nì=ûÙœñ üfðµ@ö1gLÌbôÀ/>Ÿ,0wÆŒ“NwÅŠh#`ƒ«ñM®¨h@ŒÛ q|ÛS²ç;\Þ?B¿tÅc‚ç ¹ðÅ4Á‹=¢äW訤˜Ní©à+™åˆ‹ÖD쨋qA7 Q8÷ò£äÙ‰žv~Ü¥#ßSý.0OâUˆN¼`á,§ë—XpzÉŸº`‘`øÿѦ®‹åÿˆ ÏU™;í_Ÿr©b`c'Xß[y,Ï2£üVA';ÿGé,ë{BúÌ(¿ ƒ*˜|‰õ½ƒ0ÒŒò;TYÁ”N©ïÝ‚ìÒ»x¡ñEuˆ§ï}º˜3Üû©ô>^ ¼š«Èi=:ÙÕ›õ í®½þ«>{ñ}´‰!žß²ì ùŸ:'Ù?Kè®öÿ³Ì‡zB€·Vj5~ñÑ+ó†g”äß©gþ™Ðh!-¯…˜bÿ ¯Cyàï·,x’aPþÝzžU’ÿI¨LÌ„ˆ—ü³K,"» (FЉð/Cà¯ç”àyÓÝ>Éã}_ Eñ[;=AãS>£¿n“ÈVøôdŸE³²l-{ðÖ÷ä¹%&[ZJ,ÒIf™Wb‘Wû-×èºäÿ ¦  zñcÉÿA¯Xys6êrª{'ØZ‚:œNæW4ˆ‹"­%¬´þ>cÃõïô*_«$ÁÚ$ŠžHéf?¯–ð2Æp©ï!­Wù! ¯“vÁˆ? /¨\‡†•æéMùÆûUrè3d¾¡øX8$¼ ¤ˆWËy¨)à^ŒJÿÁÏD»?ÛËçʰÎÄ,s1´ÈQÃÎi4|¯°mΓñ;Ü”]Äç˸÷éâ$°/•³‹˜û/ß:̾e¹™+Éiž¿¡lV™ú V‰lØZ™¯9µóurl€!UÇ}òÛ¿°Ä"ò]/cD´´)›oÀÛ#·èêÒ7 õ@|Õ^©DÂÓ²©ß ¦Oÿ.ÙRÄ«à»9;¼¨J};W“Ò<¿¥4#ƒœ %’¢áÍ1ô-Ý)óZ%Úð.:€ ôÌ^§„n ÞÛ»2T*5•±-]TÂÇ+æõÅ øªþQømÊm.R8OdƒsP+}†oJÏÑ‘Ì|Aåâ’ŠçPO® t~D)™t.RøÏ^—tÞ”ørAçò$+”Ðí‚^©D®2ˆ\\ÂW#i÷ˆ´×(ƒ’¶G`Æíν‚´ÑÎ~”´]P¶¤¤vŸëGéö›„íWøÁ.„vò#‚°#IÂŽ*¡;ÑTÂN„-)Ák÷N+¡Vº u¿HËÛY$ûµòç)û hÐ~üKK,ù‰0 @áÃ\TÊû ™ª™H4Þ”-U›ñ¼óAÿ† GYéN ž3Ü{+^˜M›w4»Š:+¯³š(þ2Ãë›ÖH4õå6_œýIùÂl>Ί8PML.ƒ<2))Vƒ¢)V> ŸVäaEˆÈeÉWXCËJüËKðöbÿ¼®âv`äþ$•¿Å×…ü¨‰ü¨•ŸBä)}EµAúj[D9î0—5¶ˆhZÄS>ÜZQ^YÒx?’|ŸÁ˜1†’¡¾˜PÄjW¤ø Ͱk]l®_lrE ¶S^òÌxl.É“æ&6»JwP öºžtï(QÅTÍø\ÍéËlÓ¸jöºWñqfOúøåsù{]rBÜïÂF„œ¸h*›bÈ«˜Üa¨‘€ì?b¹yq°¢ʼnïE;KaM¢Ÿ£0þŠý ž6®ºDÔ O dAˆ¹"¥_(E_(¶Ê‰ÑBÕЬUN ˆVzÚ¡UNˆ£.Á£Û_Ü&θ"‘ðŒ@eM@œuEó)'Œ|06Bo5æ›ûzþ¿¶¶¨íùµ5еÿ}qü.÷¨íŒ˜Å–_>AÜŽ3Nå„ù)"§¦F“¯,\"!lç‚ʼnnû‰×ðÎØ‹û, ØE‡ÿE8­v•Õ÷ LAx7µX]`ÎûèôTÞ÷‘êj[‰÷]¥'5¸ ,>©©â‘‹†¢ 1À]ºÇ(ÞCCÑ@¬o'äÂúz ·ï(·iã––ÌcÜ‘ð©PŒ§Çš@.ËNtGí™m ÅÛª¨qGº!‹) <1×0|™¤šÝàæ“8æQÏø+¶7ZWAXˆ-‡HxR jÖq$<9“55ßÝK,äHnVÄ ]»•‡ãK¯Ñò%bYâ5V¾«ÄÏ·'g­¢ g’5¹Åª/Ó$™hrGc¿?k™5áÎ<ñÅŒÎëÜ1ZGÐä»AÆÙ·QR¢èMn’[Q “r¡¯í‘µ°›÷´l$ô^œmÝe÷HIïÔöФÕ-»#ô_6O ·õGˆÞá@žˆ¸Ë¼>Ú[ÞJ”QŽõ1B9B(ñ4”V·œE›;myÒ"޹£¦÷±¨¹éÏxÜ]Úä²@M.Eœp—=žúf$‘£Î)hr®AƒúY ³T qž ³ƒtž‹îH²ÃWN ˆO$@vøÊéq‰Xè/DÂÓý³ñ™û áÁ.Å–BØ¥ˆÓ°ukYXâ 7tDFÂñ@â"ò 7Ism€ÏÞbl6¶t' »xÀª¸ ¡¬ ˆ‡„5Eª®îHq ŠUŠ¢Ù¹ËÑš\,€¾+W…´XÃ=‘Þ{iº剄gàÄIŒáDzAl/zV Û‹.ßW"ƱUŒ\]÷eÞ–U3ÙÃÖÐÛÚ•…¿³M¦%÷‚ß)“=¢Öƒ#àÙª˜ê‰AÍìÜŒ¶¯«QÔ1Ã$b–ÇTøËô|º;4PM ûzÔÒzO\4xH£gM™Îó˜:¸•pA2áªhÚ 9áBJ¸Èc©Ø”p‰ÇT‘­„Ë’ ›J  /ç„Ë)á ©ÀVÂ&O$ŽÅáTÀ”\Ü+k•°Õ#MYql•°Õ#¶s,¡ ØaV@½U{R½µ¡|SYO˜#Ë÷1o¨LùwÛ98ç)*Æ­ü«O°þ5jŽüžçôÙ=° x¼@Ô ùè'³'Õ×O=Ñüú¥®…Çý«–P˜s©¸fµ™Ä¾na‹ܯšÆÌþœy½ã±®2Üñˆ{ó*ÃO´FöÅhþ´>¦Y¬hþ8Ãi‰jè^ØG'6Ò˶†—½ÑXS.T1À K&¬¡É%û¯eÄ+Æx-mwœ—òÚK=z<ðg¤àO³ð§yŬ~ð÷~=ðg²&,WK¿Åg[á+¼°|¹(³rq=ê}FYë…Äí/i•êÛZ¯Xçeu'»"6§FQ6zÅo¿Å…¥ oFŠÞT*ŠMÞÒý%Ñü¹Ô›”(ûi˜$b³7Æß>¶xc¤C•(|q›·lqañ!š‘ûì\]KÌq{‘ý`Ê|abûÐ+zË—:á4Ð/†¥J«ŽxK(X=P”²öÞe”¡åí½EÔÛK|è-Ý mPlU”Ñ⡼Z½Ñp¤$¯è$K÷\ÖÓ4=òöµâ<_»²Žô¨ù>1Ï'õ?Ш—jh›˜ïKÑÙn›/NŠicÂd%é¦òÔàbÔS=ÎÚi£ÏÒJ—û mò]¶•>šŸIo_å‹*æZ¼®²ÎZ+n³ÏTZ7ûÄV«Þ—XÌÏ æqx;WWu³YÕ;A ¼û+ l=Öj²1øî¯_£ù‚ý öƒÁ9<нÆüÅ-þâ>qÔޏlÇQQòû½Ä éWGhÌ;…¤s9©Ü׺`%½àŸpÅÞï…btæÙ!AàÒÍËÕk¸¿IéÄmYbL>w¥@Aº/…ä¾%$XHŠÒz¯ƒ£XØ i «ÊŒ ‹Õ™”Å|Ž{së2MÖÖeŠ™ÜbÐÕ7eöÛ2¡hñ*¼9S*Z» 43ÀÃéžL¹O\|Œ¶} »€'ª—™lÄ"ɱÌÒã%¥× x°Ÿ‘¿¡F)>NLÅ‘j!½—äÂô8%ëÞÒÆÞµ4Ç]Î$Y­V”+™â“$kŸk×2¡€f/Ä‘ÈLè¦M¬›ò‘Ÿ™¥A mAîÁ[üø¶x33÷MF® 'e°£s+ú%ŽÕt;“^S7äþrÎû-âç0N^º€Úy?“RFÁyœñÆ$I‚àXN‹ÒZíÇj®E öCafÖ‡ú‘nU’õáþDî´leÖGû™ÏUë« 1&’¬h¬Ÿ^S3ë­bç0>ÉÙD?|mÖ[ÅdF›D¨‘c%ë­Ìú4?–¤­b¦?ʽ^*1˜ïÙþļï·|aÌñSO‹Æ¸WÍó[~1æûa³ŠW”r®oô›Ž(ýíÊŸ(jªamµ¢!œR­è~±Œ²çíË=ñz£?ïß,÷ÝþÍ þTõ½7S+‘ûbžåävÔZ+÷µ2÷µfîkýb'í½]ÕÄú¯ËxÃWf ³‘S#ò»Àf¿5ºùÅV?ìàlYÁX*¶ù£Å{ ihCš%¹Ö5èû¸¯»4× {›ŸqZ”Ò%ÿ…{лÒîAï—ã,àe¹IS4ËsS,wl¬QÄ?Â:òÕž¢|É´Œ“ìVž­<€+ÑܤáÀUT¡g×›jØ<[aÏg#ìùlƒ=_|Uù†ÆFš@Ùø6Qþ7KO–¤)¼¯àÿ=ÒÎÙ±#±Ñ\˜íý†ù‘Ñ—ò‘qøO”¸e„¼›kàÆôUñnÙƒ×ùÌôßõ{ðºi­¬üÁë¢Á©b׿Âò[.£ϼ2ÿ=~ûkv"öƒ~û½y•û½ìýƒ\‡×á¬qsü.¶þÐ¥ÊÖE¤.t·öÐUåÖ9 ÇH¶yHiW¶’þt˜Âm4óak‘ðé@ ±òd@ìÃ˼œ P #¢¦Úœ¸Êꊪ­åE«Boáúÿ‘¿½F Ÿ*akâÙ޳éXvSâ—k{±è9µøL‰–ᓲ†$êMBN´éb«ôáJ[þq Œ[š°³%hÀ–ªýšT¸2:WRæHx2*uäï«QŠJySÏÊ&¸*kRisªÄDÍ&TU¢fƒ©l•0_Ì…Ó†Ò첋Oæ*TÞæÇNå*+çÕ°¯g&#çKØÔéDïhÖ0“¿­”_(ÁÆæêô„k /&î°ºU"!ÛGû8Í—·U+ÎuªXû*n€«+<¸šò„Üϱ•óúg26ÀÊ bC vª‘Þ­^›Ø…#ëru»ÃµKáñù’+oå!ý€ÊÎu”#î§Á7¢ŠCj´l•«I5‰–ý¡) SùaµôÁʾÎÖ#Èõ·´!û¤Ž»£jôm[ù'%¢E’È–/JW¹¢«\J|¸Ìuk”7_=>ª–múVé¢Py¿Žq\MÚ,ÖÍ“ º8£Fã ü±+T~Õ ,RøÌÂú\Ms8ûr±.³a—a?±]VÙíÁe¶L©·ò´kj/ÑžhËOKb²Ýzv$|>ð¶)¸°ÁÑ%ò¹ZÛ@úºÃÙ“©ßbêó~f»¥Š;p´uÂË~8,ú÷‰þÃ$1z :±¨±'Ž4ÿ:œo35Ój"õ0­—¡!5˜@’QZ¢³Öm =ž’бš5ȉq8c±‰«¢‚É×òñÏj›ª±ùœiš˜ªI–°ý0Mƒ)î8Ø5ƒ4P’50Ý9[:ç‹™v¬fó‰BnVcQXÔ9ÒÑ!Ø'ífÖ ºr^ 5³bjb±)þ§aCä UÐp¶%{¥…½RM&öj`DØk€½•±ó{‹f6éM4ËÚÂi±Z PìÒИQbÞžiÁæpvæDG¬DG4Åí … Ñß.½”P¨6y_-ÛÈÿïì• Õ‰#aÿ¿97Õ—Xvª_¹š]3Æ«7îë\¢.¶×Û•ue ýn(S_?ŠK=㿌¾®ŠB6ƒ ‰oH£0…âÍhÙ9¥)>‹©.—\)±åÚØ5J ð£ïWtœ#-Óšøða)#8a¿D²¤ùîd? 'Øø•ÅÆÿŠåã³:Ξá»=ñ{¯ç hòùŠøM¡øÇhài”埢WKl…â·&e5…rþž?Šþ…Zaůqðjˆ2Cià#X•[Ê~²íLÕ£Qsÿó~¹–<@ž)½V"é}¤H_ 0ÚínJëõIuzoüÅÃ×úQÎZUÐß)âŠMq)•×" _°ðH¸*È ž_Á¶Ÿù¹š`—¦å>Ãçú}¼ yƒc6Zf]7*ðƒDQ6Ä»Eé3¯ÑÊÏ0ïJp¶C¾Sé7PÏ«¨Cÿí=‘–r{`mJ^0ó&NS’/×Îë-Ž9oåu^!Õ0 ŒN/c)|¾@C,~°±­ëÏe~Wù]3óÈï`J~ KÖ·ß¡”üF[¦œG«¤EÁù‡)ç[Rxd~ÕD~“U+?Ò8¿©Õ§ä·ùa¦½ƒüŽäÊó:ˆYoå·žV~ÈïN€ërš[ç¦0+¯æD^;̼v›Þî%íAî‘”ÜaØ‹ÆóHø.rriûpÌ-+w»£ÀàÜïRî÷‘ûÝÜ(q‰&¹èHpQ¥I.ª1œÄRòLxTº‡<ã)5œîQ) ®aö¨tt-Mæ7OKä·@³ò[hæ×ˆü>LÉo+òÛNIî#¿ÎïUŽÙcå·Gûßý@'lW@~÷p¢ÄùÉÖ’AòS"ù$Û¸Ñ~&+Ô"y]$Èj»A“Õç û nSÂÙ.þÈt‡…Ãð÷LQ%ì>r>š‹CiÿÌôGð¡´#´«‹Qz馞›zÚªÿl—Ü0­Gô+j¡«—Nç,ƒ 1N/}ŽŸ‡ŒrÃoæ M)˜®)Uϵˆ :ôaŽ»¢Â,õ1>OtCå¬7ã]³ ÏsY6ZßÊßüÓ‚Ö·ämz;ôBø1 Ïq%vIobÃÔk¢7P$>Î#Ñ‹ØM ö¦'¨w¥$ˆÔ¤$ ± ·_ šš€^ÄAJpXÿV,+†°¢ºÉ­U¸¦w’…kzGÄçC‹W gkJlý©h!œ6‹= §ígIœ¶Ÿ‰£„s\GÄÕ'a~'þ±^¶¹€ªþ8Ø=¹æ¯¡æÛáÔH$¿ßô¯qƒòj—{˜Ÿé½ÄºÓoêÖæÙ-,<ÁÔ~ÈÔÀ?Ñ;'ÃõñaöÒ‡]"6Ð/~ØEÃí´r$â#µÑöHïãÔ·ÆÀ˜ÍÉ\œy­0±‰lbgZÛD{»ò™¡L¶‹ÉìM(ùå°+ü$ÉŠSíè¹T3=åÏü¨8}¸bÝfæWóýO5%5¢& OFÕÒ33íÖ 0Ë.:0z*×pú2·èÌè<»ü⨲ãnƒ†£IØn²ËíàÕ¶~KÝHÁèÞÜ'QVúf»hd–ÙÛR¢>î~í½à¸i¨V¶â…ð™aêd±!Ùììùþû-bõ—b˜±»(¶U¬µ'î&®Æä¹'´ãD~½½lwÏâyÿƒ†{{-W7³Ùb‰ 9Ñ‚u«Ý”UytHn§ð9b{Èþ/mþƒø¬a‡¬òfj3§¯•é)z)TB˜ñ pôNŽž’ˆfPS‡+ö=TÓ†+Æ^»ØË8Ó‡[&/b¿=äÈbÀ¤,¼(< ­²ÃBDÈñ¶ReG}‹C´>6•… Ó@ ‚FìekQ¼ò EÄ'žáb„¹áë%ÄìLµw£ 8‰ ‰‡tô•\å}X$ȵ½_¼‡”îÓvtîlÌ+WI)kñØU| ð+ú+ztblbñÞž:_ÿ½Àu<¶†žÌöb4†HXu¢ˆ=Iw€æñý§,F7íæŽëM»¸ ON×Ô+oÄómã_–×Ãs¿ßXy3 î¦çðv@ܳS¥÷Aü ïž‘3RïÒöÿp+öo_-£‡QñÿÎþ´Øk¦Å}ÔsUùF¹ñ!Eö7ý¯ôg÷+ô{ó]ÏoiýámEïg+öþìkÅèW+úm{ÞÙŸ­dP°õW®þâЫLg+Lg+ÕðPÕ >¹Cz%­$±³•QÄ`v¶2¦“ÂÎVæÃ]KÈ ×*ÃØÙʰ \·„\p­2‚­ J?Ýgs¥— pŸpÔ= Hä¹\ée1ó,Upž"@d/‹À†Xœð\²DϧmÑD´D/¤ÝcÝC“ˆVK¢¸ÜAq0Aô0ˆ^L!úˆž%¢Aô“¢,¢àŽ &z DIYµˆ^ÑOSˆ>QXþ¢—RˆV[ºZ5¬òGÁD‡@O$uÖ": à墳 Ö‘þ6D¯¤c£Â50˜è DƒèÕ¢[At; ¢×Rˆî´ˆîTI=ƒ‰îÑ¡A±/Aôˆ^ÏõÑqÒ£ z\-%ô›t‡REáeµŒ¤ì„*Ý °’¨“jÙ´âHxH°H”¸‰ö\Ë È¥+”rE»Ev¾‡”Û‰úÒfn¶!UŠíý~^ϯ¯Vòèýê›?¸oþ¾ù=ò÷ý8Xßü¹œGÿóéý×uÍ_HÁ"úŸÕ5qµòvvù#Zò~òk¥Né×ñziVQ–­¼ƒ CûªõJ¿ªRÕ©µ¥ß2€ ŸþAŸ«ô«6!Õ¹ôû}³+Çá,©T+Òl•‚b¥õ<1(^çÏ'(Èg¼#ÔËq =棃ü™ñÌlb{¼w‹—Ö%좞7¤~Ä †Yâ7L#ØmŠã—¨éø…”iÞìɦiëh` ܉|‘«çY“™Ú­¿µÁÆïÒ!Þü­Š`òï´ÉÒ÷TULQc±ðîïÆëÊw—V€l…{8Û»S£!{øF E!óaL1ÖΫ4ñáæIé•o2©¥@ÍUêrm1GÆÅ/ZOšõÀXÅf4>° f/bö¼y¯êwtˆÍ*Í8ä³…ÝÉç.‡s¦‹‘V¸Ù4y ÊQaЃ£;,dc{¶Ö$*òÑEAx¬FQcªˆÁÐxÓÙ%8íÒâÓZ(vCµ¢ÃNõÁjÅÞÆ6‚ ¶WMx|OÙ!ŽÁ,õ˜ gT‘ã5Šã„J] X=ÌiD=ê¸A™!N«¥JÒ©Þ  ˜gd=³!éTR*Úü\¯É'ª&˜¦ j:ÕÀ1¨ˆƒT'Õf·KŸ˜ Ï£*Mqc‚â¼ÌóßAóâWäù ò9âŒÒç>ø2%yxøWÕýsQ‹qM²mÒX\Ô)‰lÉÉnʼ]Ík£5:7ßy‹«?ttøŸa³ÙýšÔ²Ïø«@>Ü6y½«Æ³~«2 ßq„@òóøéPlDSj„Öí’%®˜GiÜìeÃÚTè(‹È-ÙZC5®™¿çK¿-ÕŠs„&†k×ÐMÖ¿YÕ) â#Fj0É•A ð¡\y¥õ»ø$Ž$\|RF¬é©V^|’²2ë`"±3†¯Êa§Þy@e1Ä·ý‚-ª_´ªFIãŽôÇZz:;¼Rb›¢‰)¼»ûy áŠiZ4ÐÉŽ¸$¾34iݼžÂ“5ж@3µhÙ›MÙr»·ôÍ(,â¯íZõ ?¶gkÑðwÕ/(GQ§EbáQE•#ƒ¢^+,´ Ñ ñµ«¡Osݼ­Ç{ùЧá+‘Ã’‘ó9ìéòaOc‡8<äélXAlÔJŸ£b¼[Á%J®:G,‘o7ùô(-ÛüZ¦a¹?üéHxÄÓ&\,rH/¸U¢ðû -¥WZÿ—ß.«´X¼|T‘X‹J½MË<‡s¨ê6§T*6T¨*«ïÁO÷—'©Z·kb»Y­eÁ¡¨Ù¨ÙïÙ̚ݥ‰ÝÉšÜóXMîM©É}Ä‘A0t ÝÉu<ápF¼ÌP‹ÆÇ)»µu3¤Ár<‚É…nøRî€ ”ì w *£ÂƒWo· a±¼gÑCv»rš†­6M3=ª‰6çì×Êꊲo*6qÂÝI~⬮èì߀ïRCžÜ /Øá‰ÁÉ±é‰›çŽ šÄþ2ü¢&? &àÙÿ;–Z,gŽ,ò˜üÑxî%-mÇ0cZKàËô:/ùz…^çóë3ü‘;•z"ÿÆÞ»¾®Ec±rsÎi¯uî”õ½Žggg'qC‹‚„Éä€:m€RÝC«¡aüsªŸ¨|!û…~SŸk4¬¡aevSãAe6wý½4žßÖÄm rH9â„-Ó;œD0—wi€Î`âÞëº6òú v5¹Î4ØF‚Ç QÅž­¥É‡:¥¨¯N¸É­Æ;é$ÒÍî  æÁzœI Ñý8›zSÃ@&Ç«'úÒÀ1\÷7M¼èýùÛøkÿ¨¦Ñ:æ¬÷äœeŒÕyÎrŒƒ_ðÅ9AãõHñ´ ¼Q;)Bò‡/Ôîå ? n!¢6¹q¶Fɨ¡ñäCŒ$ª¢V†\TWÿëFÉ bªÊèo À4áfq}¼b‚’ &hn4ÓA\²§c”ÒÙwEµ5D»êá+h8vÊqØ-tZ}…¯8 &•ì³ÛôÇòŸ—’7Ú=äæTfEÔ•_qðÇÊÆ´ˆQnDÍΓóEcü5ÆD½Ùr˜­sìQ‡X^;EÑÙ~¯&:[»r®Fq¯ÕYmðì£ð|âݯÃ{“ŠÃbþåùð=äÉZÍ~Ìe0k/7Å]~0¿QRm‚¬wb®Çø†×V=œ4ŒŸƒ¸m©qéh˜ÜúóǦæÿ)¼FÅ(ÅŸwë¥;_.Úù² ±O/uÄŠxîôŠý: aâ€Ëß5ܼ7Øù&úè…Åw˜jãb’×ÅaÇŒÎ$‰¬³Ñ³ÅäˆÎƒÃIvD”àØþ$5^ÄôÁ0G½ûý¥U—Åߢ‹–T¿”Ô,Ѫ‡²¨õC™+‘÷új%똯ï^T{öOŠæ’õPÊÛüâ(fûƒP9N¤-›QBÙÐ Îé6ô¶czs6Á½¦PDI(NQ?öÁ=úo\oö‡ü¦„”³3ø/ †ÓÎQwøìËÇÉãt>îHœv%+¹øBžò5ªø%¸ødñQ¿".q‘½¬å¬Ò1\þ߇r¸¼¢Ëó?|bo£Z“ G×YZ#á Al§”Ù¡]/=î÷*„:çÌaWèò¤Á ìÎÞ5?öbb»­›{oÃ`}¤x 0÷tóÛù}¾ÛÎØ/3ö»‰=À.b³–V?ƒì‘â©”j°Ýü <ûL÷sí´nú7N5;Àcíè”Y¹ls>RšE¿˜¸ï”ˆñüp·¿÷Jв´ÊIAØ£ïW³_ƒ©;N‰Øû%¤sÀ¨ÎäèƒF¹E ƒrmå£Ýb 8xÀZÚƒY˜Ã¦ë³HCËjãÏsìþy|Vª,³‹ev^¼†Xn—ãì °E¿ +VÚcâ‡%šXeBȱË*šì8âS(V¬Á„­±ãœO¡XK°9&ì‚&Ø:»,Ûm½úu‹]l±òlÃî*ç¹óÜ&óÜnÄ9Ïf¢5פµÃç|ÔAxâ:ËÃ\g†Ã)¤²ÛžÒYèN,³°Ï—Œ,|ÉØ?‚ô{»²´Ø6ÓêÎvT+Úçî„ÖFá.RÏnQ¸»Z1àe Åç¸o÷í¬ü—…$ëcƒþœR{“šáÓßf¿_ŠŒhxê«éØ4œcÅ+¥W¼ô›Š?è+ð‹¯xUbJ9¾ÿ+ïøFIã ÔãaFZÓ£\[ä6ñuá†|/܇ô7CI‘ð¸ 1¯‰þ€ ã Â(£ŒˆÄª£å˃’ÊñA1Æ]~¼ÁK±±Aê ©ÛAðið‰ ø Ïž‹/ÿFYÇë鄸äfaBÞÇz‡rÏïAUð>ÆÐÚÔ$“I¦&ä}\2C’}?æ44ÈNMM3(™fšaBi†õå44OG ¬³œw”¤–hv^•VÒº|€YÒ90Oj”UõH'Ä,Ì1L—یӃ —tnj’ª$×ó b&l&QÓÔ$’I&ÄL2ÄLBå\ˆ$è-¢Ñ(H<$™x‰aBÞçqk©ÁÀ”`sYj²¡ÉdË "“­ d V2buej²aÉd« "“5Q²9V2bw5’aîYk˜Ãj§ÃªM¬KTúð´ÆXŸ€HƒoHÀGš4gFŒ²ê鄘§Í† a9‰`”LKjšÉ4[ bVy]×DÑ·¥&™L²Ý0!f6 SÊÝŒ4ÊÄ®ë£ÒŠ´;ß“€I)ê>£lPtBÌÃ~Ę<,J)êÔ4£“i&Ä,ê¬dQ¥&“LrØ0!f6‹SŠzi0`‹X‚õ±iEŠ'àãÒà&àãÍ¢.Æ)Q£l`tBÌC›aBLæ¦õhjšqÉ4Ç b¦™—"ÑÇSÓŒO¦9a˜3Íü”²žDLS|÷##Žgq²M¿Ð§b!]œ7â!L*OèãØdQâä!¦¾—K'öùŠ“‡åwšáAFÂwšŽ”ÃnU]³T_fƒzãSŠüŸ+ÛPPµ± tS|ˆ”o* ˜HÁü -R°0h{[­<¨Eò¯>Q¹¹ tpQ$¼8X4¸H©\ÔÒoKAéÖ‚üÍß¡Øü‘ƒ”·m}Õ¢­Š 5H´T(EB±òù[ùõϼ¢÷U j •·•4ìK5{HQÑ"Ò.F(ÑüÅ#”üK¿Ê¯%Bùò‡•æOþ]_ý+Ò^þ¯¤ýZ~TIóm½rKÕÕ€®ll‡ª[VVÔ>S„ç³›­W$¯rnª»âì““jvb`y©+.V¿Áiºc r±Z±u§%#éÝÅK‘ðÆ ¾Á·~Ëò–oÆ$<†½Œ»þ§5U|›(êÊ–F"¯–æåتrZ$?QZ@œsá÷ÿvðoÌ,ÚÊ»£‘üË¿*n0ðqC°¬®ï‘ð†`q}!Ÿ»Ì„ó‰ðóEÏÛªž·¿ì$¾(ÑF™èʯÀ¡•h' S¢Ü¢\[UîŸæfqsS¥‡H˜”òƒZ”Ú¥ücW4<ÁÀÜh¤|‚AÙ­—Ù]¢ìÖ'²Êð-Ê—lU/¥dÕ£ù»ÿ¾<¦oXWœ+û*¶–øm4ˆƒFÈôrü4ág 1¤3CW¿Š¡M’¡«ÄЦCûâÈÃÿüÏ´†"Ë¿„ʡ֠-@b“ ~\úí¢oÛª¾ ñóòœ¬¡’-‡ËÐÿÊ?|ÉFrUP§-}¹èe[ÕËiÍ„Q_‡P`"Œþ:Þæ]aÞæ]•¼¯0%)Áû&A‚]š_”o«ÊOç=R°\¯Jázì×1õžÉÔ¸¯Cøa!‘Sº¼Sb™ÓD–í_ýDz­$Û6]¸ÖJ9Ï¿þ Yš`Yº†e K–&1CFùíSŠö)¶ª}J"KWù‡:~[è×QÞÊ¿m ‰²ÀOf^ü8¯¿,o2ð»ÊHã/Û»_ÁVS6³µíÝH¸)Ûb«†Ç4iáY8¦PÛÕ !í5ù^¥µÆ¢OÓ‚!-ŸŒäGÿ†íze ìoÐ{cÑ‚[=uœÑ„e“$©Ù 55Ijv©Ù“ºœNjZ’THMO’ªK#U÷8©+é¤f$IÕƒÔÌ$©ú4Rõ“Úön©YIR 5;Iª!TÃã¤n†ÓHÕ%IÍ©ú$©9i¤æ«óoõôUÊgR§Û+ç•[4¯ìMÌ+‹¿ŽF²‘/=NcŸ¤q›hìKÐhü:ß-;Ýõqû%;Dc‚ƦQL4þ¹èŸmUÿlÑHW"»Í±nÞ;_1¨\ó1ÝyïDÂ×|Ý¥\³]ˆî¥èu”ésL[–ÛÍÛåI±Ýœ&¶›Ûy契íŠ$©- µ2IjK©-“º•Þ™V%Im©¦$©­i¤¶>Nêv:©ÕIRÛ@jM’Ô¶4RÛ'u'ÔÚ$©= õA’Ôž4R{þd_Ç]ü‡Ô4“úü§ûøá´>þ1wd¢µ¾+\IË>¾èz}ÏÞ¸J­üç‘WÅ_àläwûÝTKŸ.zÚVySÿÙH0¼¾0{ ¿ÝÇÖKô‚Ê^C«zµˆÂ¤%â¹Ýúã ¬x£—x3Ê1ÿ&ÊvÞ•µB?6 ýTü4I¨ïã„Þî%Þ‘„þ6Êf~N„6£>´‰DºU¶ùØáNÒ…“ô¢$oô›¤çUNÒEQ¤÷¶›x×Ⱥz¦ÿŒlãkU\"WÅ%âÇXþ¶ áåo^ç¡”ÍO#áZ{ìçõ„/{øéíH˜¿¯%þs•ÛH ;5 ï˜aBR×ÅÏ"áÁñÏhw,0MJžÊ†…ÄŸã‰V:õ1ú/nv«â]@½x»[Åž¿(Ýy9Øà§ÐclØþ#6*lØRÙø%³#af#Æ üа1â7‘°ôZ9¼ÄÚ+ø Ô:$±Wð;ìLÕUñoTчh­”éߤqEÿÆ}Ú•‰#Û ‡Ò‰ ¾<@é%†()ž`ZpìœbÍ÷h'¶þk¢Å‰ü%Å5L‹)cw¦$ed‚1JŠo™1VÆîHI0ÎÉ”g5-b¢ŒÝ•’`’’ `ì÷ÂS\¤Z*ÒÔô"MãØ´"M·@2ýÌô"Í’±©Ešmd‚úô"5ÈØÔ"ͱ@2Á¼ô"Í—±©EZ`d‚…XwUµLÿ/¹—*– Â¥ ß#Z®ˆåJšÂþ­8,¯5)¸;äå(jxËa1Á`ê´këÔ:dv„Ç/g[+eC1DH Ìô§n:ñ€ólóœ6·9ò‡–˜›NµvÖ‡– Yz`” ç§Ìp&aLm”¨ÆÁ‰>ïQ·žޛÇ7.ÌM—¬-°Á7“$7ƒKÐg-Âñ7Ö–€$lmM–Ü|FÜLNpóáŸâ¦#…§qsÖâæÔÛ&7—=LøÔÛW,Â-<º?÷7rƒâ•lìkZ+ç߇Ж+EËI•^®X˜p4V>íyl,醻£4|…’>¸33°ãô(‹6¦üs¢ü›¢ßت~“R²£ÝÊÛUú¹†ŸYF4{qþ½_Cj£4ãEžâ,.¾ ·²8ÊâÆËh,ÇHcÉô¿&ßS5–#k,ƒKÒ4–ãIR:‘$I#yœÔg}ÒHL’Š‚Ô©$©h©è㤆¦su:I*Rg’¤bi¤b“ú<«’¤â õq’TPø}½Â·=6*ýn•}VžÒ§òF‘Ø„d×H7¯1îÿ‹‹JD¿YDAÙ6%¼¥P|¢” ûNxÜħü0þGok0(oGÄ©áx‘“Þç›ÿÉvŸ88JQâzU飢hÁ£"å_ZE‡Ã!f2ÈI&¨f’ ª˜¤–ÞVÊîÜV”ðî?ƒËNÒH Ç Éÿì‰vµtØw¢þ£„‡'Æî7o¨‘˜Y5Ÿ©1®/Tÿ*P¹û5Tî=N…oK|Dê‡j$jªÿˆŠÿW8†HU¼Á^a-ª¸Ý<ÂKfWU)|&PÁ©Gq[•‚hÕÄé OiN{—yÚºGOwtü¢£c_²ÀM'ôu;-U¹iÞ+Æ=þu÷Ñ~ü¿CŸ®¼(å«ðÏ)…Çkuæ¬ÔÎüïR¼rã3y ”Ãßa§âß"¥ÓÕ¢éªÍ~S¿ïgÝZ®ª‰?àïff1~#:ijaÁ¹Å¯qL“u«±I!, ¾Ö÷n5 ’UÅ2฽øv Ñ(ˆÆaDï¤=f=¦ˆ ú™$zŠíˆÅéÑAô.Íê^ß‹œô²•ô²/d~dÙ@ž?(iƒÉf»ÇI~ÍI¬Û•½kˆà•¿vL\F©Vû-2ú-6|±¥r±u*•‹ 1PbÞHbRû-4úá\Ê `.`Ì…†Œ U÷›.Èó—ÿ™ÝæÜwâ©{.׃œÍý€è›Í™b½ph•¢LPú ëÑ­|nV)êD¥ßpzN¯#«íTV¿Q=ºVý rFU)úé¬~£  WŽÆr÷aWM3Ü¿ºÑœGë ËÚç4¢MåË{Ã{dÁrìLÐÌ#š¢™Áïר!ì÷+ÐXC9ÓèKJéÎÈæZ|Á™ÖB¥{*Ý¿_ÀÖnuÕìvãÿ"Û|²ugží€½]yô”‚à mQx³FÑÛÅ!{,¼Äx¿M¦‡ù¬ºEp³>Îmá“§$W÷ŒÆ¥ÁTCdHO_ˆslÈ2¸Úb‡æÖÑU£¦N4½Š° R6½O™ï'´Èè¡TÞ Š^i€ÛAÑ; p'(ŠÓwƒ´Öà)p/HKþTÀý ­üS‚´¶à÷&àaÑ¥]ŠºØ*äˆÿm>VçˆM8=˜#þ_âePŽ8îÀ[½*•µ9â®'-‡Å90öžÊfcޏŸY’“>4LlR"¥Ÿ*EŸá›A±®*·Ì½¨ 8:O‹’ŸNy Í„=aõ uZ#à~ÄÝ@ ØDšC‰æa¢} w9Ñ-µ»ê^ FöÑöQ0º¾Ÿ‚Q}ì4±FKÈÞZ­—XO¯Ñöz¹A+Õ§`VMÖ›´Hñd·0vø„þûØÌíè\Šï.6ø***.|TGc6KÌcznG§'Ø "›&ePÈÁ­Uì”HÇ„;´»HÇõ˜ÙA÷2UŽÏ.ØÜI! dÃb[è„oeÓSŒBÂw <®KLCD8CÊ$^°ô ¥|±!¢„ú6@ K€ì "½3ž "³EÖT7”ÿð0ÅÑÆ·YeEùÊüQÂ8’žÝ'ä,®ë£ˆãh´QyOŽ‹h´3h´6L#0?íé^áí^áë.ïÌÒ?_™í^Ñ©{EgzzB~ß8£Éç‡Ôó¦.í:ƒk½ÂSCûM OQŒ[ž¢8nS¸º¿ókúgÜ¥`u’M|œlþ³Ôüd¡`Aù“Dó·±í5*I}Ÿ²=Ÿzp‰ñòú>0Á–˜©-Úq™ô)9Uš4Lì®¼Ç ° BÃíRÞlÆUü¥Ù–Ͷ›Z$Ÿø/—£TR{Ý¢÷Ó‰wl¹åŸI¼;aÐ-uó•VžôºÆzu‰*P¿*¸Õ ¶Ÿüò6+¯I`êÕCô;û•Úqù Å=†t‚ƒ® ^yË;ƒ‚«oùfR0¬VÉœ£cªô/¦`x­’µZ‡CX {ÐB‡ãñvúçgEX¦þ;Ö„Ü5!^Üh%%äÁ9á òÙ‹ó¿ù9ZÞ¬‰Iü+ß¡‰=ò„¼Ñâš ^bCü+žšc3tî8rjƒ„¾_á3ÀM0SÌââ‡|¡Ìâùš*æè‰>ëÇåS/f ¾nÊŒ-Åý³veD­’=_óõ˜EŒÄ»®¡ÂÏ@¨Shè4YÔÎâ$Ñ,¾Ÿ'uÔQ(‹¯ø-Ö›³BY!ÿhí½œê ?•–n!C¬Ð¡OFÂw‚rFYSÐc@…_MN|¯"®i#쟖ÒÔ9B.ñ½3™faN(›R9 ç¯òz‰<Èp^û€îå„°(‡ú9i °U©nÓ#Ÿw‘ˆ˜Ÿ@Xzî÷aéaÓÇ»©-Œâµ¤‡îýÖ£¬}„å(^NX¾„õE ÖAÂr@X‡¿„u+ëa9‹×åàNiÈÍþbz¤xLŽt¯;6‡ŸÕ¹/÷GެU:'™U«t>¡ÃžÙ·+:³³]ž¶Í¹±á½Š'ÄI<Ô¹¼¡»à¥Þ?§O¨s¼žG²Ó2·¤wJzFBçõ =Áïãúäè<Ýc8šy’º¢c¿ë÷IE©[…£às׈Áñ4c]§pB­¢¶Sx OûB‡E>*Ž[\×#Kslýq×3R°ŒžÚÄ =fjñšË|м°¼¨®pû_Ql4Y‡\Ï#wô`ý–ÅÐ~›‚‰µŠq—ÂIµŠã…“kç}]ÜÒCzø¡ãÕm<΄þrÕ™ýi0º‡Çôè÷ñX•‰Ûçô;j¬²‡ô(IÖ…nJyu¦€×ðÚn!{cùÀLQͯùµ*Óë%ƒìñì7p…^&¤™æJ7I‡&“JûsÑpõ¦3,IÇŠ[ÏqU™b$iP̬u=KŒ²“þžÑvGÀ:)2­1D/¯xH¦BøšÛ•µçQ‡Óít‰q¸%7†ÙhÊé¸Ó:7Ëz ʼnÜ'yK¦7y?ÇÁŽnž%Íôa‰¸KRºš½8Þ³—j$±š^ÐÈÕF9ƒo'v­ b°Á¹¼r” îY¼“²j„ œ“ÎÓ|†c!/©&¨ÁO¸äpu‡U‘ߪÈï+¼¼G5Ùà©ZAXKÂÕýµZ &WêÓ)¨{×>ƒ‚)Ô³gúwŽYÀyÇY‡‹):ƒ.¦!õŸ©F/1ÝÀÌÅ9‹FÈN?Ó€š/XÞIEf!¦®VuFœÖþ7ù.õé JÆ\ʧa’âšg ‰Ý pýŽ:sFÁvh .1O¾mÅ›÷éèE6–G,äJóÀÜ¿µ½¹Øàwà6rÊ»x['U,cT·iÔÒ-j…\Òª%;;çYaà¶e0‘2 Ê+“©øzf“Q:²GÈ[°è [ÈS0²‡Š|V§æ³ÖHÐåƒ%ë B_ü† EY/]ÅÍ„¸‰ª1ä-¾@‚´™òôòÆÌ6#”g£íÛ( FîºX}ýû-ì¢~AÜ!g]=Î<¬”dL 5‘ÆÐz0_.ÏÕ…h ½Âz K³&=ê»puiRžF‹ðY,1M‰i¥åOw¤ùm…«ç÷Xv¯îo;Ì¡ÄX8Ô8 …ö!sßÕ[(˜Z«Ø[YFŒ£®•%d¤E1¢,!’˜%!­"nÄ mâCz€8è¢Å0*˜5Z±€+`lŽä×–ˆ8ŽKqž`É8EÁ4ÒÆ…!Ž1ê3,)Nq‚_XP2Ä)ªS‡)(.qιÂãÝì“õÐrmÜZÍg4È'†ÿlbÉ´d ¾Þ®ü²× ”Á‰„¼Ã4%‹KbK¡ß0 ‡°!6õ%‰sJ‰«–çþÜŸ3§Râ<â #‘ŠM—Þb‰ó°Ä¹¤ÄeˆÛ)\Ü5d³ÑîSçÏÉÅë ññ°¸U9H1fq«v4£ºaÜ$¾4k,ÉÉ ø­Ÿœ§û Ç2;äd¼ƒ­ª´Ö‚Œ`µÅc‰m¼ƒÕ~áÎ<ÁäJm¢â¢Orð@cŸèß³<´8ê(œNÊB=…3j•ŒäÇ5—‚™µŠ{»CLtXã‰.&a2Í’1ÙñÄ ™ªqôÓ(&“› †˜îˆÄ£4&O"=6Ò@´‚]RihŒåAÈ)êqÔ]µ÷¿HÌu„Œ÷HÓiâ…õïz·ò¼‹b!¥¤Nϒ䋨ºÜ¦$ùD£Õí3Å#vK–’’œ«Ôè2!Ÿl)¯k¿•Æ­&¦L½‘Zd õïÑëøµÔš¤ixë¢ÔÝixÄÇu€yCŽ:@Ä|÷x·ìñn1Ï~nuyw²Ë»I³^¢…ÂGTZü1e©ùèÂFªr+Uåv–$4(Í‘ ØaVÌP¬Cö¤~_záû²ÿ½ï€CU¶¸¯™:B™’¬u(ú¡/U8œZGda3¹øb×— »Óñå&†:eEÖϨ°1Èm or.à=ë‹(,ž²]¤fEJ2ÂK¥ê§Ì®U´Kñ©ƒd¨þe…&ú6qÉÁʇ.®8ÊFô0-¨ÄË~Ø” ëN׈¡Úœxxf‰txÏÂV”p”ÆxÙ^úÃxÁ•¢˜ÔtqC¦éå3ûˆ›„ŽY=¤S$vÂãâNOžñmÃqÓ†ï˜ cOåØ ¥Õe…ý®æ§»W<Ó½¢K÷ŠoâíÙîÏu¯ølE˜wZzUäÐÿóôŸKÿ]»Wäu¯èÖ½¢;½¼@ÿ/ªºT¼Ä£û‡ÔîÈ^¬Þá^¬!¡#˜ÒÙþ™4‚GÜ·UNl\9PPO·šÂ‰çHAuÞAΩU<Ã(œ[«x‡;¹ÏûFP8¯Vɉ]¶ZÅ?ÖÉc@Ö8'š'{< h±UOáBZl5PX7Iyb.r™¤<9ÂEµÊSó)\\«|ã²SÜsÈÙå>‰o•Ó/œb€3ää5t†¨Æ#†—ˆÇY FƒðˆÁÁ#†Ñc,.G¯.ßx[Õ'FÀü“¦m8hY`½¯À»_ŒušŸ zت¦)Yb­Þ§eöDêÁ4òøû™CÊÓSœ¢ÖI+w/ã§€ŽCö‘gÄTzy¹÷Os†²C™¡gx²¯ÈæÞ?°gBôþl1ÙÉÂ!;„CL¢Ødïw$û EK³ª¨CÔ§3ÙY48ͯu8¤ÐŠu®3”ù~Å“bž3ä¿â)1ß²¿_ñ ± Kê*›žÙWü̪úÆZ¥Ë^§Xì u¦‘¥Y‚Ò Qš.b)¤5?”U]ñ²¿†^å?ÿLÈûær"pl´òìf —Ô*ÏmsŠåÎî 眡o„ü¡.uqô…op_¸ë¥|6¡o$¥ßHJ?iÏK³ vˆË\{r3ãe7«þ0†Š«ÄõÓÅu¤þ\s†ž–ÞÇé!¯x(-â/3·GLn?§Ê“öÔLÛðY¦møZ4ÞðZ¥ûMªé¦Zå…[®®U^¼í7QãßL^·PéY À‹â6jé…Ћø¢‰YÜuâ;l(›÷ä³›÷åóKá!ý4ku4Ab—ó妟÷×—ïÐXÛ¨ÊH|Óœ =óCè¡3 ¥‡,–{¡yF†á¸Íóå¤ s?):™‚à@žZ“Á’¥-Ì`ÉÒe°dÙS¸†¦†F ×’f·&CÔdDh>‰Ý&j3âÈàÍ>d¾05OÓ G9Ê¿•Ë ϶5ƒÏslÏ`uaW†Øž ʬúm«hΈYn`à ¾XÂ;2ºŠ]‘X4|¢Ð‹ÚÄîŒx$<('J-Ά™§å©†á˜ÉU}ЪꃲªP§VãÜ©µ3Щõ£âpv­}l7!éâHFnG¡ˆst”»3-ª2€“›VVñäâDÇ);$lå„GÁÜ» éuP°e„ì¸Î›§‘õKpyÒâò¤äò$s¥žf¹ÐÎfˆÓÜÞ3rðøŒ™L ÅÑíˆ4;›e ÅÙ ÀârlÑŹŒN™ÍàÌj¹N.Y¹]’¹]’¹]‘¹µgˆ+)¹]ýÚÜ®!·öôÜ„| @»E9›~"°+›£HÛšw¨_è<&Ü…’Á™yºÃpç=ªj—)Õ.ð© XýŽŠ€f, áÔ¾:‚[yö.1Ì Ùqd„‹¤_NY†é Ùºb£]ÑXùCŸChFù L1ÖÒåÞÔ8W$fÎxº˜€xâtÑ7”ò™b²‹wsÙ¿X­‹wžbÖ†éù^Û-Æ;SÍ÷x¯Êô¿‹«.ÞÎ.Æé(3}ÜÚ6•B@Z³âצnq¦7;…^JôzDWeŠâT/?Q(æº>ßÏÇ:癩æûËg¿)àmKN o˜.ráê6­éÎÇL¬*nt‰¥.©ã-sõ+\‘(/WW"Áì<•¤¦/Ãuñöxk»òA­bkr!±²Æ%ÖÐ §-Z]Á¦©)ã4𷊵T¯ÜÄk\¯éZÖãu§&>àËsìb¨×åÙ}Ö'â}.>öŠ8-?°¡ö6Ô.•ÚöQ^g* ÂuÔu®'1@¸†I„i˜DØ2V1n¢aò,…›i|Îñθà1WLör¥œ}*m.x.žKãâ1W4Ð(ÇÓQN»Ì1ÐQO(Tq¨:ñ™+ä•Bþ9•šƒos!/zè]WŒ–„ÐÒî$=è!uš_ÒâÐýºú•¤ÙE¸Î'þ;)¹UîPîèç92 Ç n´nÙh8GâÁ æãFè–††p~ž†`J¥Ž€"v†Ò̆šÐšÎ9ÝÍM—1æsÍu‹‘nÙt£Üií2Φ+ ¦c×5ÜØ†@ýMtcO5n³IkÓ“Nw³sâ^̰bB܆.QçŽÐ<äõnœû nnüù9†˜ ùtûGpûn£vO\n§ÕØ7Ú×»Ä-æí›Û×#¸±¹È/^±ÄMêæÆ¢ÕÏRwÈx[—+݉6ò‰UŒò¡Ö¸c!·Ñá6Zï9I‹$OÈûºöñÓì&ìŒ'þµÒ&JJ­ÔÀ£é,îw»ÑsŸÂ§%j˜ÝfÃì6f·[pÇ-Å |á3$'ÎGSèfó>PÀš©Çr‹C(¼=^Mk–çÐßýyÐGˆO·¼"nŒïC¹_3ìYG©óN»ˆ¹ã²Eâî¼BÑêî3 yšÓplb>¯¹å¢¼’ê½w´b»FLί(w³©‹kúô/Üâ æÇÿnŒêŠý–[ÜrÇcÔ?gö‘ýÆ·Ýò=¤'61Gÿ7”kÚ«Æ]·¸ëŽ2²÷¨ÁXœ¸ñY%yˆxžÕ¾p'|$Œ¤ú€Ã·só4¿á˜+û„GÖ¶ÛêØU ÿLY¢Zû×R¿ pú…»©jî¡Á á^ô ÷QÏFá~ê#)lþ¥s”ÏC‹jO±:ÒÒy1ã£[†ãáѧƒ+dÚ«®q”béoÜ“)XöOGŒóDyèb¼'ätÆmð ÿnØ*ôÄÍÉ#j<‰QÊëÆ—ÿÆ;(­øoºGL£ÌCïÓ=XðK¦˜éxvþ+è Zm{;Ó“'†­{Ôâ|O7â~Çÿ]›ÍÏÞyÍN–xüÏ›ÐåL‡¡«“L&VN\ÊÇ/–ùhÄ40ç)u˜ãVøBºyœ…‘¤]ÓÄ9/+b9'^)ïàÄ;4±<,k|Ñ8kÆk}q©S¥ØlËó4¿ÿ=Oï>HZz«%n»%®™)ÚŸØî3×Ù﵊fŸ¹È¦‰~‡|ží_˜vú"˜qùƒä²)ÇŽ›»|0»Ä¹äikO"»=2»}>þ¨£î—ùð‰}>sÙOùí÷™k~Êï€Ï¬\™ßA+¿+¿Ž ˆúðžðµ34§†Wý1ãuS+YäOòfJ‹/Mä[ˆ•«´1ƒê ®í¤û~Ê'Ú|æBÕ­â¨/Ƴú1_/q /÷«'éa™#ù)zšægwÎúpãÅ”`Á ÿ²÷*»„ëÖ{•TUQ¡*º‡™îõ?c{{ÆÛnÜ”Ô4Z½íñˆ)JvYžµwgǦgþ™ÿ÷ ‘„È D‰›œ3 @"çœtÈ"ˆÚsÎ}¯Tàžù÷çCuß»÷¤›Î ïÜs³)Bö2ç¸ÚQž‰¡nr­£<s½#ΪùNäÈávÇ·wÑHÞe¼¥x¹ýßGøüZ¥µF[¯ÃCdƒ;1x,‘?ÓúÁÓŽð”:6kmCØ Ï¥`Åíü¥|ÕÚØ«Ž–ššYã–VšFn²Ødk—ò¨4í.ÐQiò² iáHÁFR i‹Àˆ©± #¦¥9žò…oiŽûÖRÂL¨Ksœ£ˆE±#§ÑÕ­6X–Æ» Žít3MZ$4;£ Æ¥ZàjgNGОãkqÂñ¤08îɧQíÄéß‘M?Ç=ÕâZžÇqÏ´8ÕA»^ 8®U‹3ñÅ!÷\‹3'N°ZØ€Úb5vÿy…GûÃàt ï1Õô:Ör#Xõ¾5J®l¢0¼Ð…Ó+„‘ÂSX½¯Òxß - ^¥E˜™ mi¼ƒð>×PM'S< âir7€&g¥Ž Ö>MSËlø«¡rmKã[U¾¯ÜAîéø°cwž€;´F=Öãá‚#6œ"ÌÞîha‰«¤—•&¹åñÿЖbT9ZÄÞ‹j ZÇ ã O£à3,ølÌp´÷…™mCžò1ÛÁùÉùØT&L5˜ë(Hàr7d ·"G¨!P³cƒîc®s@“ÂvN¡ü kzGТß)m É6ÒÑ Xà MÚÛ]¨áð¾Hc—™vÏÓ°@f;¨tbé¿ÇçÊø×}T•£9ã+õÒYépü€ÔÛz­ˆ68Azߢ½ouèGa?’Ÿ(:°ÝÁûEÛ©×:’U•!¡–«%jiI<.fÄãÀ.i#‹ô’(ÂÝ*2D°˜Ÿ qÜ1G¸Oɶl8îˆø—å+J;7Á kÑe¸ÉAn!6ñW­áœ±ó\£›™ÔyoøˆK¸èç­Kˆ=œ?SiÛ¥]šà²#êú>u¿gÂxÕWQÿâBÍà®9¢<)§KšàºDþ‡9…ïÀ GŒ¿ÀÜtà$ðŽ#¡á…ÙÌÂL`asžž ÃcÉ#^bp5Ý0'vÌv°X+C› ÕIÛ¯µ´‘öÛ>Éò¿H–•#„­ y_ÅIÃkêd>{©«E\›.R‡¹ Íùæù²x-EÙB¢Ø¡ÔE{rÁ”vQRa˜Œ3ÕÐÇ$Q:ÀpW0uh3Œp;Skiï®ÂÕÞRF¹ôJM×&îdCÅATø•.­+]¼<£Wƒ\ÇAv² &»"göŠÒgvÌßöCÚ£æ’ V$ÛjW`:‘ÝÅþ Èê¿å/÷n ¸ÌÍÀà2s„›—™ånánçƒ3˜rw;%šÄŒt¿½äÝwV>ŒrU \¤ ¨ÄôP5Ål™ÂjŠ›'6æŸ ÔiŽ šfap»ÍlÐRã†inΪg3hI;…1,OcXÎVÕî )f¹ÉDâP¶±´Z`Çš¯±ê7zœ渃fÔž¼8µT1î\Æ­qÓÍÐ.œü;>â)ØÚ/­õn¨§è.:±Ñ¦A ³ŒS{å™ÇÓùnþüaA¸NgÈòÐÍ÷gZ\§µ4Ùr³i Îé°p®sá¬sË!±˜íL ë¸*7q<ÜàæÓ)›ÝlZ¡îp“AŽi§›Móa7%–#nÒwÖãnØàN2;úÚ-g!Ý8 Ùì~ãÜÊwPåùÃVªºˆ¦YY˜`§;MØhìAyÉä†Ïtš³duï%œT“ìLä Ev“£I·@´ÀwÐÂs3ž¯Zá·œ²CÞ8€ÐŠ=‚8ÖH4h’ç…Ž»Ûû.ýmp´ɺ&bÑLàAY€ÙÈÜ‹NØÉ ›=’téçiwÐÊC÷Y|Àò>Â;ÿŠû†[ë¥7dAßpÃ-w„5[9Gõ6}Û«»2…¯RM˜ÉÅ_n{ÏMJ× Ž(y~Óî@e¦uÌlO8t”¨mOh¤„e˜¦„c}RQMŒã‰Òî¥Éë<‚à}˜õž<øÚqýœ*Öî;aº€Mêê}'âûf~ïÎï•ø¾Å“Ø ï;ß·&Á_Â÷míï?1•͆žp¤$œ »<¨HÃ(®j’î¢#}ȃÜ_’€ç<šCësžÀóÀO8š›ÿ‰€‹D`–.aLI,.¡hÕj2ïçì]õP£76e•Ó4ð}DB2£ Ä ý‹ñ&·QåßñÀu,žX6Ò-)NÀ |›…Ks‘á–'Jû¥Ñ¢Eùÿ¢|á_ZˆmØAQG(tžíŽÄž—ÏDw=8b|HÃ!]|ß÷ép<®ŠÊŠ-Ž®4±µÍ™(´xb´|Ä…Ù²Â!Ë ð;³óNp-V§=´‘ëCN¿>”~‡Þ+ZÎ>¿öÛÞtÅÿ_—¿8»'=E+8õGøÿ˘Rͦ„o¨`Ž÷1“‰ä´E#–̓²èZt';ëË&Q²Hyâ~ÞG)öÁâþ¯El±ˆí VƯ”Áûå ™Ø—§TF¨-âÅÕñ¼ú£i*m4ÏÂ`|©°Ô©ƒ§ö lø°ol„è{|„èg,™Jî¤^ôQÍdñà6(Ö;Wûñ!‰J]µ}#/°§whE¿!7óà¼þº²ß%á ½ÂU%pÚjX5¤q \WOî7”À9?þ=óû/øÅŒº£&÷ë3ä¢î)ƒ§ôƒûI ­‚Q@ùéƒù¡þÃË>&SŠ}Ž”m©Ê߆sév”¥täÞ"–ª°R±R^,‰Mñ¯,}릉Fé£aN¥P6©°‰Èù ˜¼ªÐˆdi–µYűç—õѺ|º_¸¼?6ŒW8¥I±ç±”ûøŽØ °þ{AÁÚŸ)hÁ¾O…ƒj„¾j>õá«Ãj$FÛUƒôÚú˜…=u…‘ žUÉ×6ù1…‹ºã’yâÿÝÕ’»Ùt¸ú\T‹&ô+˜ÐÏWÔp_Q²Æ·ÔpØÿµ×P²Ð wÕ¢Æ@·Ð’üpèoÁ£ã Sž¨ˆ­.„§t[&µÊ¤çj`Š-ˆªHÆ¿”ñ¯T¤tdNßeôkWQZó”šÂ¡¨L*3qÒpS †I…tûm(&“Fʤ NZ[£ðý¸L#“ÆrÒºB‡ï'dÒ™4Ñ8.BWýt9n¨I&M¢3ǯ±?ÙS3¸¸"fr^gn÷¯ÝϦÒãìÌžšÏ@—ÍšÚ½l†«æHX#«Ýkæ<¸aGL`„›fÇʽt8NóZ|Ç\T©°%í]:ZXšC?`‚Ot‚OÌðŒT™á¹9ŒVò:^™u·xm ¯‰Ä°$D…F[DµÆZ˜D[6L°è$&Zt•t¨,G`Þ;2‰€,dÑ3<‰òBòB:ç…”W›¡Á¢ ·,Ayy‚ò ¢<"‰Ä×:‰¯-°‰H¬1Ö„pÛ$v$Hì$å,œSêî¸%zÜ™\Z%¥<¡”g˜Rá%TÌö¿pJ\g·À0k„ ¸žÊ¬y0ÂJ.ǼPnÅz…mʪ×Ó(+²•Ä`‰4ZáÑÄ`tRÊ7”r SÆPʘ¤””òSÆRÊXêÇœòܪ õÜ ¯¬¸"ðÉ0²Ži³úÈNœD+E-µåA™ E‹=†¢ŽC‘mº¨cÈ${\ÛFMláÐxb;>‰í›>U°ÁzÛl7ؘíF[„ð˜í&d»…ØŽ÷ÂVb;Á Ûl÷Û Il'¦3Ù”p¨.êç(Èv‰Ô¿ÓS4¾ÓS`6ÙeÒ6ÅÜMßÌKÉ#3X\–I¾õø¾ ùNôÂÂä[é…E|âg% )ᜒ^2{Í)Yâ…å)ᬒù^XAáb/¬JÑ%\¢7©5)z“Z—R´óÏ‹†‰À0Úœ?`˜ä‚Ö“keRf”™(ff•á$.Ã/8夞—“)pš¤ž$¥>ƒRŸ#©'yÉÆ´OÉd/\LÈr)!Ëå„,Wˆéä$¦£íÈt¬=šBL§ä´+›Ivé$;L±G‚™NµçA•™NñÂt;2ê…véL»ÎjÍ ¦æŠû©lÎÄj²*÷~%—EáÐÔöÇyÞ¯øŒæ {¸`——msH‘­¦y¬¡pžÖÛI«†nùéR¯EMÔø¶T|6¨™¥ÞboÉG”¶éåM°Ãp6vb6vsBdÈ-?ì·G7ü¡›~š=³ÌL¬õÊé4[¡‡jøÍõW4ä>¡ï²düHü÷üb ߨcp”ñºàÕ #Ù3"DÁ}¿¢T"UI…‰JäŠ]Ó-Ó“RjS1¥>5ª¢j©æjù;YŠ©Zµ,I…ÆÔAp~–¦æÁòTrí2«e:¶ËT][®IÕ+hmªÞ*Ö¥êUµž¬f$±?Nì›ý b?“ÙËqê¬Îþl*œ'v3¼pÐgqMwf û„©4˜Ý(¡ÁŒŽpçÌæô§:‘§©ÐšZ´™À¤;ÿçDjN’$•d¬1¹N«I’¹I’TwЈTw€™hFï…Yd±1/ ýkBß„è³ ½& }‡Ž¾£ì"ôÙ^ØMèµIè§ ý,¢Ï!ôº$ôË:úåp•Ðçxá¡×'¡êˆèc:†Cs }~Rçªì¨¡Wv„Éô‘x®¬Å)óÈœ#R2× U±±ÁWwÔënFG½ÆfÒwúI¬v+2;¨!V “RîP }û®¥”EI)5i˜R—†Ú“R'‰·8Moq4¤E‚ÅkL˃ei(^*Á4¯Þ +ÓtñV¥éâ­¦lKrTdõ39,«Vd5ß›åù€ŒcÓH÷f¹é«c[Z8Loþ^Aê´Ôàìz˜#Zì <÷‡^øý/ýÆ€½‚”îQ!£5nQ«eçŸàÐ$žà€)Ž[¥ö0ÕQ~æ"d÷­ù¼Q~µ ‡Ö˜"ò\õÚ –¯w„–ôþB‡Ô÷‹(Ä¡Á!õ}#…8R,sèY_îÐ{Õ ‡^«ߪ÷WÓç£Æ¤jØ…¢Ã© ºO,Ç„¹ Ë\MrbRµ“ÊÝäÎtÊR#{ØÙÎ7KmŽ“…bË×Zg/TNþ+~N­wbæ(+HaA»Ò­l\‚ú÷²¥u’$IJ`Q†€b“óî DŽX†•R9­@Ài^©5Ýô©yc 2„Õ΄Ö[ÇâÓfÉÃóf§V_›y_Ï»œÚð¼Û™ûœBäv·ß:±š0'‡´œFà–ª¦£N9<sÊjŠ:åð“%'œz559õjjvêÕtÊù­ÕtšöÞ—'wfÚŠã ‡)3+’†g¹1L™·€ BvfvfJ݈#¥ ¥nÀ‘Ò•)]º,³\º,³ioxeÓsÄô2]FLW%×t¦×\pƒ˜.“Lo"ÓÛÄt™îÓå^¸çÒ§¼- ö`ÿ Áþ!±_ÍŠ¼3i#öqW`…]ø0Ë͇Ýø.¸ð¡€an²ÆÈ1£L›e­Žäí«¶2aé†Qî@C¾‹:ûz¢_,âõ…0ÖÍãñúŒ‚aŸa'ŽãÄ …0^&n‰•îpdÐ>³€ÉLŒ¾‡Mu‡ öy ŽQp6š]tº=ùwçóRúºvUCû½}|†>¸ä2‘³6˜ç–KËéyáÐ^¹«£L¬å‚ýçaçaI'Ã"74º#¡|G,uGòa9¿‡=´x_¢õoSpñ¾Šc#~z1Öå¨{j›™‰mà½å>CSVy3MNÈ¢)·Ø ÝáAGûhë³`#Nw¶»ß˜Í{cŽÄ£n91Úí–£=n91Úë–£#nêÚ®_"(mUÎ÷ö?^$¶Ò6cŸäè‘ô- šÜoëŠfw²pðýÜZÔ|oÁBŒúœlEܤ3Ø"ðâ›ß!NnR.´=WÝo*ªko@ÃM·ì¥wÜoh¦%o()׿’B,j†–ü}fõþPò î»Ã>CÉÃlxˆ„æ™ØÞñ‘[NŠŸ¹õÐêÖ§D/ÜRk¼tK%ÿÊ-µG›[ï¯ÝzÇî ‡&{]§iæ÷|º0”{ZÄ œ\Žô]VUëýý é¡Á÷÷M0ÚÃü@À/qšXéñž0 :¤”*=Ñù0 ažeSyÒFÊÆBcy3LñP¹Ä¸€©Ì«=ÉesX®zà–›ÏãlÚ¦ 4˜K†yá.>-2—”yá¾'<èößGÙ_xÂþÍ^ƒËcÄÉÆê5 ü¨³kž@µ™5xɇ.ŒJ§âÛ:gã“úΘtÙ9eç\ê…ñˆ½ÔË…sÛ?䶟͹*Ó±m`â¤tdŒ£ÌTrÑÍpÓÓ“ú9{°ôÁ“úíùá€=?4 ™ÔfQJ8t7{Èê0‡1BËÒ§˜§¿AMzÑ?ÝAˆ!+Ba%ÇÝñÃ|I©ÙKXa!Åø^÷ŽßÓÌ1=P)ÅX–>¸²_Ѯ؅bTöƒ”¢‹±Z¾4z‡à,`|‘9]?ÖÒû[¬×I˜fb‹ê–Þ4¶°)}pƒ™üò“œeŸˆ’3lN¼HÆí–q‹ÌävlÑ‹Õfö%……ŠC4=ÝN¾FýÛ½ÒÑ(‘ÙCd¼ª¼Jß+ÁwèàÈá:9`]6AˆCé-bùa<œÑtl[ØFާóµmÙš¹Dª4—ÐÑšœP+¼Òˆb+Y $#’ÇC8“N¯C›AV}éIÙ¡qó\:娉íµ/¼™¥&¸’Žú·x•ÛÍô7øwµ3'#¼[é|ƒÅ"oèš ÄÁÆ{ßRÞwåMÑËûñIá_¿ëª7rÝ"¡ª4Æt¤õQ2"çúq:½m¦c"ð$=©V(×OÓ©bš4b·¦sµ m†—é4 Ä0ÇFÊq[BòÖ]ò×$y å…Hún(ïÄ=›ïhÓ‰ˆè¥6®ÓŸÒßéOr“:µK袦7…#&jæ2l0‡*#–ÉéÓ˜¨îtô6è$uWÊ Ä 3¥ 0¯S8TêÕ «Ûä}çO섬¶õ0Ÿ”tþŒ*v >?ÍÖN,@¾ ó¢lÔ7CʼȺ‘ «—2ZA Ž%+‰íÓlXE!jεÈ|/GQ쩯ä‚ôë,7v’îž7v‚-°3<Ɇݤ2=¬KMg×á¾ðF«·áÞH£&×7è“òV¯Qž`8Fl‘N¸SÄ(iP´¿Î05'-QÎu’;>×üpž£C®ûá:>¾2"»NDó'„&ÀÍN£"TY ù¤¸-ó9©›•.`¢w ÷jµÂŸ^Ÿu’bjöOЪe¡ŠŒÉá…ÎA’çã/9Îÿ|Õ®Ïà1Hô²¥ÐA*ó•LÛZhà»HÚ´jz·à¹j„ÒΉÒ/ëŒóþá^Þ9-á…òβ8Fv&‹ÅÕdO½)'ê“;kw¢LîL¶A‚‚û£…‘Â9„òug˜CDpž4¯3®´Ë®@]gR0rÿ¬¾s,ìœÔ¢Æœ°–væ1–—ØËð}Eç¤nI‘+1òëÎún°fM¡öU¥Ùh‘C´¯pβ±³v r¢lëÓü}j~%=£aôNÊ7NîvwÖ§n{)Ç›x ðŸ8ÃÇ0Ãé4?ݱÎ< ¼Ÿ ÇåSK64uÆ&x/š s3¯šdY]ê¬ß(y©3\é¬]y«s$«1éRIv,~G#r·³Ü¹—`t_gäøŸt0¿s¤ï„)BsŒðuJûëC|­ÂWnÒ%)­£Z5ò/àòý²J]ˆC4²hK0}ÈÝð.úºoDºú™Kæçr¸ –Le—ö)$Uw„I]ôŽ0¹K¢#P/šÚ%±ÐŸÖ%1¬î´›v©ˆÃÖ#öù/™ÃÜ.4µÚ;  ÛØHa˜ÛjºDÈNçÇc„XÐtÁÕAÀÂ.QÍëGÔߘo7J·Ç‹ºäAC,úÄ`[Ž‚Ë¬ù sØÞ…]ÈamïÒ"vb'†[F ã~ ·ŽÊ ãÓ…z¸ ììxj¿ vu‰RÑÁî.>C>ìÇœÔ*QTßµ8Bè ]I©¤O¨‡»P+Ÿ_Î7ÈâäÖQFö5að:Xh2”޳§ý ©’MÐòmëBÔˆjšdg XÐĶhÒÔ…‘ÈêÑ0êEÅ(†€0âl— ŠÁ….1ü½L²òQŽoºDpj|¬K`yZhƒfÍty(éáȉz¤pèë8GNÖ#ŽOétGNÑ#ØÎpä8=RåËÇÎsäx=Ò”°‘6³´Ùjî^›ï¾Ž§Åã߉ÇûÇã?Ç‹âqŒ5¶ç(f{ê9ÖR”ké%–pœkÉñ·T)¥]Y3ÆýÛ Öpù*´×‘]µÂÞ(ìÑ]eaïÖ {\W.ì‰]©°'wÕ » Ûq.ƒúWµQa—u¥Èù&®j£Â.çÈÊ&®j£ÂÅ‘“ôHYØc»j…mJ*ì ]µÂ6ý;…mâÂöÄãÞo)쬽zpY/ïJe]ó¹ayWXÙ5)Øí°ª+Y6òv\¦Ü‚Ô¡vu…=ÕÁŒ°—Àvñàý—R‰2ØÂ)Âp¬k‹X4Eˆc]!Úµè”Rp •4#Äæ:Dn"äÝ9&¬ö3RÞìJj mPsViTÐÑb\“š$¹›¹›]án‚Üý®í:Éó9i‹MS„tó¡<ê ºµ ¢o‘耶A ‘†Ç]‹¢µÏûOºæäÄD…Ê,áYWr.õ Ç÷ØÝ¡¾ì /»&/“MÐÖ5hҖɥ݂¦‚í…XËÝz®¢ˆU%ñlÕ®uÏQŸñ§tCe:­.ÌC§ò ^w6BíÍQöÔg&†Z‡PYåÅfü³d•~|ù~|Ö|¬x˪…a]7.A!–‹‘»¿P6b°´R¨»ºñ&›i†Ã«…y/†#ª…å†åÕÂzÑÕÂvÃSDÊ] çOö{VT‹ÔûÝ`c·¢|`(ý€ÌíºéE¾«[àƒÐŽB¶´;Ô-§Ø ‡ñ×Gð7Žv‹8J¾‚»vìlêøÎ ˆt#'ASYq߈L vÌ,§ÓKÝ"Ú±ãH·ï¤ut^‰Ç­iÖŽp¼[:¹„¿¨ñ7ÅQIë&!*¿×¨x‰ÊÙnd¸·–üjÁ¹nŽŸÑò¥¥ í* í.Ä"„KÝ‚–ÀžÂÐÞBÞ™»LôytEKØ'®Kˆ½¦%ì/ôn¹NR $åpMJèMØÝ‘Y)ß ý°ïö4Á£n¼ÛÓ O»­læûœ[ˆ¿1Ã@5 ¯ºm<Ç9J»Gcþ¥FªiÞ=˜Â‰#»KÃJlàÄ0¶{¢ V'Äøîí1¡»£ŠÖýÝß,ˆÉÝõ‚ÐOÙÚ¿âÀSºÓqrb‹ÀCv:¾¤a¼»^::tª„ž&¡SÐt{hUw½Ètè_‘ǘ.¡;èИ*ǵrœÙ=tíË1§ÚS×ÈñúxwRø ØD?Ô¬øg£†n8Þ]¶ ©ýSˆ Y¹Ð²z±;7dÓ¥îÜ!Ì7ºs‡°Üê§»ëùFw½1[à•iJÐB&œ5È °Z¹ÿXïw‡;Ý#A+ÊO·ÀPßíîXKëÔîtN/`@÷ Mkiô­ä!æ—™º·w§ÇTVIŽ ï·4xixû$^+Öã=Oà™àUf¡|¥áa;¥½Úר/žÀ3CiyÃHàa^évƒnqy»AyÆ·4㊠­ÊКñø nˆˆ–)¨ÂÄŒh¬`I† *3P{íçùb:×Ý´ TqÓ3ŠŽ‰ð€c‚v¼°¬•Z~%× µ{Ù|·ž ­ÿAxÀúˆ!·ý° W%8‹]œÁ §ûÙšßíÄRªEƸúÒ.{F8ìßä5”LN‡URÆÕoímÎlÃUã6L¯—;Ò;´àjî]Äçâ{(#y@j”¢Î`3ÏYåÍ9Åj FK?7|“Ñ"f—ãЖÇ2hæ7[ÎüÊ› œ Ôç…ä¹ù.,œ‚£}e„Pb®ÿ3õxDi‰†Ô 1~¯—ï}¶ÛÈqŽlÐ"×ÿY#ùTÏ(Z4OÌ÷ñ/¨¢`p*ƒ.’<Ä¥¿C }‘Ê÷j†¶-Ƥ\Ë«æzlè`!ÜÌ* .t³¹pFŸ|¸—A»‘YqŸ"d|ûFÏ2oò&ÌÃŒ76¨\ߥÈGoìÖ$P«Þ@}œ‘¼ËC–å9*ÙkH%ЖA³‰e„¡-ƒ·Å…‹Œ«z@YvÑ’WÙrê+-¢*f‚¾Âw~Œê‘´¦”g}–š—ñ·€1=ðqè ˜Êh•o MK a;¤ÅTõˆšWH¯ =ð1çöHlÌë‘Ø” Õ™Euyêò ¥uy'`v&µ‚ChÚhNf4ËMísnf$:äEÔd&kž&¨Õê`QÌÏ|SŸ- f–fFûNªnú̸<3°§7¬Èäz@íº2S«ÿÊ~FDZMÄæÁºÌ$†ñëun !6f&)>ؤl&€ey°5³h¿°_J÷‹fØ–‹ YžÛ3cI}ÈŠ<Ø™YtøÃ‡?4”þuç®Ì r0vãCßÉÕ‚¾ìÍ,úî€ïJ¿‹Št_& aC^w€™ICEé:ks83hæïžßàEÐP,/h‚c™Y½oZ~jôW®p•±!EÓ)ÞË3r,Ï -¡yy´¿r‚Ÿkòxÿ(‡—£¼X#5õ™LíbÐøta8‡•:¥Zˆ ™p.3y?á\ÉLjeü¥÷jfR;¦ŽåK‘‘ßä g®g8ß·™Ô.6†;™ÑH] Üå¸ÝGÄÇxßïŒìÀ¥LY¥Š´Lo3½gÐ{ÕÌŒž‘è” ZG,ç÷æ>¯' Ña®xm^± 'Í+¾5âg†(OKXÔ–ôŒ¾¿†¤7Òc‚8è8ì2|3­¡Vô,úþ€ï0VöŒ’kGÈ~pÖ«zF°bÈʰºggªé û¸Ö·cmø¬¯ë§‚6êH°¥'>ð>APîô$Í^…kÏ==aOO¹ê.?ûzÀè¢ã·z’ (/urúÃAå'´x¨'Ù¯ñ(w˜SŽ"æÑžáHÉ4/ëI§kxà×ʧ‰y½! MX8ÕØö(lÀyþížpº§>?Û3J—1Á…žüñ‡Ä’Z/\¤·ZoI×ÁWÄôÔ¬4ߥ©n¤É{†×{æÁž…å½òÄm1Æ8Éøêã¶ '¹ýƒÜµë¥Uغ^°±È,­tÛfv‚`köW¬·ÑÙ§QüD›¹ì¤§>ÄeO¯oÕ:{{aUžb–Ó¤ª<¢ó<Ò Žöj/{7Õâ±^yë ]Í\Émà!¿á'¸¸^ò”Äe〗“½"û±UBôs½È²š/ruÐLcÙÚ,ïJþütA¾ˆÀ7I¼ÓÜ„åñš{ºt÷zAK/ì—/³áI/½Õ>íºÔè"Ò#^2ÂS •HœI"Ѧ“hëñ^¨İlDY¶$1<[’ v?"Iœå¡ë]&1&[#1çáÙ²ãó}Ù¸+8ƒUPI(çe˜,× Œs°È°!¶dkÖdáÐÃl}ŸÝ–M6 tº¦­3vd'­IæOrÚ·+;ÂN@G{S©ÂwgGèY¿Ú὎ñÒ2êXvX£O¶Zaå<›Ž”½µY¿9»EÌÇqå,† p\9‡áB\\ÀpQµP[0\\-L g³‰úÐ&8—M\‡6ÃÅìö…$*öä’ÅâÏH3¯oʨÝ5ÎÎÞðîrÎW±ÜNïeÓ.ùQ/j’líŠD@6#“9Öãì )Ê6ÈOÒT2Æ /³É ëÎgð*;4±5V<;hŽ1Ô0o8h.í…‘^‚ºûTxI³Ôh/–Ç®šK²j*½ZyTza28g qÚÉæ´Þ<˜†cø“lɪðu¾>–>~fyF´˜°Â«åL6j­zdËAp%B¬õþG憵¡6yi¨fµ´Ù+­Š·z¥½â6oXÿbOfy;¼‰j~ û½ú ñ`B®C”Õ‹9ª9aѳñ’ˆaЀ5ÜKfpÊ% ±â/{!æ%›9¬ð^ÝÊ®𽱍›öØÎxÃ1:¨uΫÙ÷Fc\¼—¼dGÓ×+Þ„A ®yi…ä¦ÙÕ-/Uáx/Üñj6uw½ì ƒÐï“È—øÛÝQ)òc]äÇ(ÜRša¸ enõò¬Gyá…ÉBëƒg^m—±Õ«í2¾Àú:n’å&?n«|Ñùä=¤Áäo0)yµ}vkÎÖú¤z^çÃå4’¸Ä…k‚í>r(?RÒÜl¾ã”Â…µ¿'Ïd»|4õÜüemMµ0ïAáÖV Ë^ìñiAÐ\K—Xíõ%…ïóÑŽx !w¤oû}äÜ‚^ƒ–ZÿÕ,ä!Ï+ÿ–Ù>ºö§£Æ+M#)À™$‹a)WûTó¸ž½Ž¤y›$FcÄ¡Ù㉢šJÉœÎHd¶§E).øèR·5&GI]ª¹\¸†ç!W¤xìK+À¾°Pn»0£w0%:¤ñ]˜Ù{F0…»Ã<ŒôïÍ7ðœ¯FãQ׉]áÉÈwåɳÞZ×_ÒVö¦6Ï%E³·U(XP”?Œ]l« ý*oþR~õ¦¶P41½a÷·eà;ZÄÞÞ°OÏÀ&=M°¿w”ØPP¢œCÄì"3³˜.k¬74¡¬W × C× =ÔdO÷&ã-êÎôÖõô…Þºž¾HÄ®sÆ}Lì:Y. ×{ÃÍÞ=½#¢¢`U?·øFŽQˆ”ÿ¢|_¡Ý`w kRÞôz?ðJ¼ø›÷Yï^ûÞ|Šÿ¿l&ï ü¯d…Ô«tîífŽŠ*}YÜÂÌ(jjøýÀ¿ ÷3 9õ!FÞÎ!gæðûáO øz'ÇbVM¿ ¿OŽÃŠîÜwÓ?÷ ìóA=2t³ð§":àþÇê›Øï}Foë;~šH†Èj‡)¸U(´gB àv!9¸KyTœá÷e ¼)_ž=JNÒøp¥ê˜&žPiŽ®¶T øWQ~:ïŸ7ød~NÉÉ|ȧæ‰ÐiŽ4†øïñáÐ9:Û˜á4G/ŽÿJ;ÚòüK8RrÎ ÿª[/ýRxÀ<¾Ës}máЯf6Ô·æsz[Ë“‚ZNÁ¨ÐÂ|¨YÈè!ÖlšcŽ`ü‚åݰ AÏ{]ÿBíoÄaX‡~Qt·bCQ³ÿ.vq‚[/"®ÿJwÔ‰@mJ$03ůPÐ(D—_ÀF¨—±÷e¬‹b7‰°ú,‹£[(š¿Ám8a>‹ó ¡gn—¢¸›ÊûQŽ¢¤9þKy@“²‰Kå¶w)ì4aEç*lDE”=LƒëS¢šX%õ)pBD5i¾:'E8bz–§ˆïc.žù²xÎ'Šç²äø½x® ¸úmÅsM žÂ‘Ç\œmÔ”ÌN[ˆ|–*ˆœMG¾rýg2•8ŽcöïŠÁíåXR›÷HÖH’¬÷Q|ÊËd¨?cdghÅg‡Óñ`'¦}ˆ²}Dœ˜Ó€`Ñ®?øwý¹¼y®˜&mÝ"ºÉÙÚ/ÉW–eŠ=Ñþ‹ì_áû¤6â¨6HŠ/šÞ(PF4¼ÒTu8Ö~96¢’û¸á¾—Üê‚Pi.Ñõ2þ4j@ÓQž1ºï%Z¼‰G^ÃÖÉ°Ë v%¶e¹Š’b/â”õºëE‹5^ˆ­•Ji6¢4›Išoß3±û—7Á6ùrþI5lrÖMLXw¬Ã“ø7ÿSHˆÿˆÜöR¸ ó¿ àH¾—‘ïUâ ^ì¥á¾—e)\'ÊåL¹7ã?&ÊOe)tÐJa–¥4Oz´Ì#'IrŒ5"ôx#®­Ø F’SŒšSŒ0¤UÆ<¨6¢¼0Ãî{EÊ1“ºå¨$Ê«ˆòD|ÈÞ/’(oÔ)o4Âf”· åmDù¡¶#å«’ò¢<&¹ìˆò)D|Ä>2’ËN§|Á—@+;¤|•(?²CÊ‹?“eG”Ç%Qn#ÊqD|Ìn0’(—+år*”G)y0FAʽ0V ÷½.eGþ„&$Q®!WGuˆø„(OL¢¼X§¼X”‘ò2¢üÄ Ë‘ò IyQ®L¢¼(@ħìv‚)È)GuÊG3€¤AÊ1¢üçë Žb7¼ÐŒ.J'‰Ãä\ò…ô¦sIá/¡ìØö’WÕ4G…ëHò®×5€Õ• qS›ŠÏÐL±äʵ»t嚉ýã–˜îG)%zPX°Y%XrêzFsêzGÁUù]/Ü#æS8>fÞªg¢UÄy± ^’ÐÏ¼ðŠ€§2ð_2ð(U¥Â¨ÛX+*ù1Á8Uæt<…?A¥ûד8ÍÖ‘g«0—¶˜`·z¡†€«øs^ªêFåKUX¥æ¨Î?£ƒw*åñ+y÷=F0»aý—Vñje­ªÇåÃdÑ_úV˜ž«¢úùÞš ¼UmÓF þQa'1ài»U*ÉH”Š.J‚ýL’Ѝá"e€b r<(9E‡<(„Ã$|5 ߇y„<Â*DUÍ">¦ÐqŸ‘kRSì[†?§Ò4"ØÜ"ÆŒ†V”k,êÅW¸BC.7¼¼Ë~Q̓køÚê­*ûJ?é±ßU¦ß‰Ï¨†¤ÅÙu5¬½‡Î©TÌwñ™·J+¶¤ Òéô]‚úÆ‘;j÷e48oQÃöãä Um7`ÔçjàkS`z¿š@5þE>¬Ê>Ó_¨µý·ÅÙOOò¯ë¯ z^©IG|ˆH›Xo Ì@¨™ø%"ä÷õ5©2cŠžÀ¦ãC› Ô¨Í«’ÓWüU²Ì„}î&y¨ GKny~ê9Ë„±ÂD®©†ÙCß|Š¥LÞ©èÐQ,4"¿.jPï_Ÿ/q4'DßJ¸å…q&¥Ã$ÈiUÕb%y¨š™kD=ñžM4:šÂ¡Û^]°fi_mʃ™¦pÁs¯fÞ¬\%ñMÔX&bÅ7š`¥Îæ¦ôלºS+1uƒ 6š¨y·mŠAu´ÙDM‚£¶PVöV¢1‡iüg¦qĤu¼#&8Šed¢]WÄ»ã¥é7DLƒ«Í‘’j3DMZ % s“(œÓ)œ3Á¢°[‹í.›W!…*3\Ñ(\# órÛç$·©tîš|t®´†sïáø‡:å‡&xLHµŒÔ‘ŸÒK­Jê’p†é^¹†™a8ùÛªOÂEŽÂƘ g~N¥ŽSi†É„³ g:áÌ0“ƒ­…IÑ (z“Z”Dj™Nj™V©ÅI8k g=ã,IÂÙ¢ãl1Ã6ÂiHÂÙM8{§1 ç°ŽsØ ßÎÒ$œ(ágœeI8§uœÓf8K8Ë“p.ÎÆY‘„sKǹe†;„³2 ç!ã¬JÂiÕqZÍð‚pV'áÄ g˜…pÖ$á¼é ¼ pb/NœÀ‰÷G à TZd_™d ‡nÒ¨». rzrº…\£1äL„¼E벋œ$ k,Pg ,5Ó¡æ$€Å €Åh° àë$€• €•Xm ,$€I_'؃Z`lÊ5¢n—vX4‹°¶£€’í°À.K`¤Õc-ù–OB9 £(4”8d Œ³£:$”-Ü?³ä€“#l¨%°KÑU2nM<™ž¶Ÿè[ô;ü^MïÎ_ÇãðŒù拞-êEäÓ¶•è§a7Ä>5M†ãŸ” a8’kJM±Ï3ÉU•¦o&ýKˆBB*Dq ÿÚ[Ä,½‡ÙZÄlœÔ-°±%¾q†sÆ eüžªëmt‰iƒ âÖÁ/M}J^š`˜Šë ·¾6»¶Ñ68=*Ä>e8Ê)ªã¯ÀUð“oÈa˜\Ãe8ÁF³Ù‚X~my0‰ÓìkÈ<¸EÌ/ÌS‘ïÈQÂ2ÍS9qÇ}kÆ‹~Âÿ°PP–`]íc%c{L·±µÿƒÂУB6=ª¶E° ±`†žTC•ɇZ¦Ù4ïÙõ¦ôX° l:ù)Ý‘²È†“£@¹±¢´ÜØ ‹m1ûå¨/¬ 6h°ÅBU~*Hh´)¡j¿‡æ8KmQŠæËJW&è!Ü:[ØÊ…åU¬Âz›ö5ÆÄ.‹ÍŽ¿fGàõã…m£ 6Úè<ŠÊ•›øª@ÄþÔÈ”6ã{T{mB|ñŠ)}+æ`»¤ö#¦¶`¼HÙiƒ¶H‚˜vÙ‚vÞQÜCG(’¨îÅ÷vªÛ™*ß ºé¶ ®1‡Cç]<=b£Ç²ƒŽ[|ƒÅPª”Ô˜á˜mð* K «¦#p¡"*Y…³9òùM®’9ÏÚôeÉYyç=.œØ«Ü‚<Ê:¡C^eÈÅ᪠®Û§]¸APÇXŸI¨» zwm -îÚà>A…“æ·j!öG6xB©‘¤Õu)9u,K ‡^ÐèM\FéNG¥ÐÍó‘’¸Ö$÷Œ1TmÂö7ÚÞÚO‹¿½7¹ÿÃ÷O ß\÷Òß—gô ¿’k^F!ÏUÇ‘ˆÉìÒÜ1;î˜ÉÔ ‹ÌdþòÁA]À›EwþÞ°@À"A¦á¡ŸiöÏÿm]/ì g$ô´Ðî#¡Ù’w¦´%‰´gíi˜Ë¦$KuKiÏŒ¬ƒÁŠ‘Ö?a°2‘öü ͹ªÙd.Ìá>ïÙL™* ÷-âÖo‡ª…‘ÂÃÕB¡pT‘zßH/ÊöÞ´Œ©D|FZÑ2¨®6F)˜ãtj”c•H cÇ+ ãPiŸ¤D‚*ÆOÃÐD³“¹ä2½3K³óË»mŠî¡ÝµSœÞ‘£ÑîZDЈz:WÅè¿äès}AÛXï\E¯>\Ï£+Pú¾ü¬ï‘já/÷¼úX(p‰hžÉ5u2[fØû:oÓ÷ü“+Ar‹;æ§å;r‹¹Å®Übwn±'·8½E% ÷M;ÄÁÿ>Ä ²Py„ÁÄBõ1FÓSAzÛü 8"\ðÒËûöƒšm¸'m¥??÷E„ð-"ŸW¯)h†GÐ(Mð”¾*|¥¶à{Íþ_…Í¿·•f㦋®»Ø­D†wƒ=JB]±1ñ^%Øïrêû”„ªâ¤ý”Ô“*ÔH»Ñ㽌:Ÿ ŸuRixà¥â/öªmŸà°R4§_$h#m‹Q«ó þ9ý¤ßŽb.ÿFùT5Màá¡C-Ëå(C;Ûs´dºèv\ãJthqw8¡$´‹Ý¤»;ÖRR³’ÐDœt’’Ò8é4ç¨;ý8ßÎQ:œá¡}9:K9Šâbµ.F­IΑ›st^ùT6åè¢EÎ,W:\ghËEÞinò»‹5&}N¸¥%Uõm”u=¸ ùJ]仌™ž tŸßÝ J-Z¨­€Fiƒ¤äF´¥txŒAO0¯òzBhÓIw‚§ô\MÏ¡U¶².ð\>t…WJû(JÛûmÄ$ìTë3Öm5²@»8>¡Mû¤¦Ç'±%1ÌõJÕö¶GÌa*ÑàÖ×…í·†«²)ó‘jûxG<+TÖ¿™gŠÆ³«ãŸi%¬¶z´ø­ò WÔ©uí#_W–pŒÚÞ”ØhLÅA ÓHÂqj{[" ǫđ[SW–p¢*›•Êd|v våÛЦ©r éì”Cª8Îìì\£_נ𸢦‡_Äa–KŒ J| çlúHtŽV:¦\mÆ0W\áüH(’SqI)èp„ÿ• S—H(† ÇñïD>Ták>îËÐ,ì¥Í¢ ª¼’K‡Øâ9¯$Q®æ¶_ºu-רšÌsâBëÐo 9_b!ç˸P@ž¼öB£ §r^Úˆ•”ú`™Sq~B›duI Aý>*"׳hÄÒÖðœèQòÊË‘µ¢¨œc»áÿ/ÏÓeUm2…Ä ÞöðýɶÎ¥~.¾ƒkû CjÉ”éf®%Õdž«>8G¦n|ÝŹßÎÛqöž àUW#ç«…r à ز®bx±Z˜`x©Z˜Úù¢@Ë3;_hmÅð2N ŸÛiw;%n‡Kv…/Ù£t¦¤.Ûctp¤^Ÿ›_µGJ‡ .½nª>Ñq ¤ö¢!øáãupËáSu}|†CT†¾cÒO¤(HªÏð.ÜÅp@PÍÊÊêSКf†ûvº-ðý=•ïîÄÔ¡8‹M%-ñÄN3ÿz¾ÅS>úDúuÚ¶kþ;ƒ–:ÿØ|Awz¶Ú5©‰8>Âò‚ˆVûà¥1ܧd†^%ˆ¿&â’ˆ'L¡fñÇI¿i !–x)+ÍBm£$nŠ"ËŸ'IDÑCDŸ2ÑïrJ³N´YSDtŽ­ Nã¢ñ,žãƒs Âç‰ð3n0?`ô+DøìøAhÂ¥Ã)…œÙÝHDO”Ñ7ŸÈÇÉò{ä1©5I¼á*R)Wáy$Þó¤<Õ­ŽÆª8›‹çy¢Š¢ÍóA¥ª[¸O¦)׋$¢ Dt)­%¢/“ˆ®Ö‰®Va-­•D×ÑZ]N§ÝHD_%=IDO#Ñz"Ú–Tu¢U¸LDëeA^‘–?‘’z\Wõ‚¼A„_'ÉôRG©B¡Ï—2Å u¾JM:jÙYÄ“dª ;‹Ñ&BA™Jßi'Z§›gÔ™`¾ ‰.”D’©ÍB,J]BD‡½ÓNt9]IW¼Ѳ¤”›”rSSÊðwdWÂ) ³<$v‹}nêu­¦pÁfŸ^šè™¯`ŸO@‰°Ø¯Éäd‚âd˜3󙏨m˜™ídû¶ Ô-eÙZdD’(SÈTaš9M¢”'¥,¤”Ř2ŠRF&¥ì ”]˜ÒH)I)W(å¦,£”Qï´×íÝ^âŽî™é6 Y·÷Íydb)Y惉Kä’˜£ßiï$ψðs&˜óƒÐθ7¼0S'y™ˆÞ*£_™©“¼6s'Ãâõ`*éB¶I–pÁv,Êɖ𠻦Ð÷ö±ïÐ%ïQ3ƒÍA°r‘KŸ®T Ãßñ¹>&Ï¥ö”=ÊG¡[/âÊ ÍK,Ÿà’h0Gê h)ÑÛ"³Ã'è^;C èjI®Ò‡ƒ%¯‘ñ}·BD×&ˆ®ƒè†7ˆ£ ˆëÕ¸s~=¤ÕƺÓÛ-Ô³îûúŠFýdäDßWUͰã#;Hz¨¼~a(Ícvj±‹’bM°Û"ýª“IòÊD3éÞv…’ä֫ʾÕ÷Z¤ouÒdÉ(&eŸ…’$Љü«ÃKÁØ>ÍreóVhÏ‹èÙõ9–ãQK²ƒ×›NÇ5>:c Õ2Ž]dG¸ìª©0ë‘Z• @r1K²ÿ!×›žÛurÇhM¹&®˜*ªz$YGþÓWÓ¾Nä¿+Ý©dé´ îR(ƒDú KºKI–”&žKÂúw%=Ÿ,©Fz7“¦¯¶YêÝJ’Ôp…úÖ¸w,™fKe:÷­{º ¾}W7§Ø™…Ó®7öu³J»w¦Ÿ.>ƒ¾¹‹Orƒ÷žEnðrˆ-ô!†7qþÃã#„ºÁÚ"ná|†·q¾Ã;Õ²ûÕºÃ{8߆áýj‘²Öjaßa%KHtÐ »Z¢ô}Ê¡–û”[Žë,õ‰H0•ìopõÓá¹Z-‘h=mv>·P¦Ž[O;/,í;, H#Y‚ƒ:ÒY›%ìX¯9œ[¢ÁŽìˆŒ°;;ºI'´ê£t…5 ~PM覛õö*ÙÅñ)µ¦Êõ!6è‰VV[ïããT+Íž£¿]èÇ~Ȫ8-¨ÒQòéü£#ä3ù‘þpî]ÜcÈHs°‡µÇqv˜k•Ò)KHb×>jtÕSAßù¬c ÕØgiuV¨±¶§ó‘ÉZ+•·®h+¹îmzºAŒCŒ¿R-°FƒŽŽ´=¶e’Ÿ\ja‘5ì_î3ð‚äZbÓ®A‡ÃˆZ2LòÏÕáFša…–³W²GXiåKm#ÑÝÕÒîòHD÷!¯°Kxƒµ( ‹ÓŸ%Bûú—þ ÕßF+.?&ú °Éšƒ‹°ÍV\pѵ…C+lµÒוiv¹{gƒmü^¥½§Àv+-Úpea -NuL ¥Ò^®FÞÂÚoíƒDZÙ£%‘ ä稕ΠóÁ‹¼cÖ˜6DÔÛˆ•ŽºÚà¸Ä »ó&+¯~4$¹'l‡fŠÕQed*œ²’GK›ã×äk¥¸ì±R!ù"ØCÛú!‡­²ýh‘‚]Ǭ²8µHcb¿GáýÅÚ£û‚x\ɈÇÿ*ÿu<Ž/p>©1ê·¥À+#|ZáÈ‹2rØ‘—ddÙ‘—eäpéÚM'¶U ÇU²G+œ71¼0Ô\ê~`…«Vš?êÊòš•&~±_„Æ}ѨÅ]Oó«b'Ü´äPµ¨®".‡d·Yµ¨‡ÁßlXµÈF÷¹7N¼0Êüþ8ñÍé rZBÄ¡Søn:lýšiõe·å ®ªl9“S£Ç³*d¹–¿hVGØZ³U´Ùϯˆ97æn_sUü¹¿ü›±Øü*8®éæ§ožŠ7ãEbÑð&çs,厴ÅY”à{±øEèhé,ÇÞ¿!—Còî…´ngÌõcÅ‹+”lßKiI86X“PÞÕ[þB`xIùKôS6©;DùL×lQÏêY6¢D®O(ÿèkcCÌõé›bu ÷Âo`D茡‡^·â•šþ4Ùw¦úÀ’)ä2ÄI.Cœpi)ž:…{ñöv}zWì ÏFZÃk7ú3C%Ô+€Äz•4å¾ÇìáV|‰(Ö;~ñè1Ù–(zÇ=ô‚Íè!Ù2œŠTTg+ÙÀj^aªµa T¥›ˆ‡ c²óZAÍ5 GÜz¡–î æ.ðEª‡´$¼˜1@ï:ZQ^KÁœF×–ŠÙñzÅ€ly#A­Ûo%„Ù°Ë$_™-ïœáÙò=±P£ ñJk´Ù ÌÂÔOjAý,¢Ï¿»óY•Hì`”_ç¨a…bFÆŒ:‚Ôà°\;-qWÛ9#!mQÖœüvKV°¿ÀB—磑71†‰µ®¡ç#b­ëåèD,õ‚z“—æE-LYÕ&†ðQåYž-à7!‘í‰ôÉ–Õ[ßl˜ÔÆ[¿l9Y½õΖõ‰]ˆç¦¾GfËéêmT6llçT4PgMôÍvzgÓú|N,ó±‡É:($†¼k¨\1ý‰7f°Çㄱ$&¶û‹°§¿œ1¹4±ÜžoyËszio`íKñœ¦Òްÿ*!€7_EÙñ® >|ò rØôX‡|UÞ•ÙBn$2µ¨ßŒ×**Ç´?âê}íu)ŸOÑ%ðù 1òùöÒ ¾îÂk»Ü“ØÈ3†¹”n låžþS jXÕz(±1ª›.›”‰l¢ë`¢ÒÕ–†m”c‰òd"”úá}ã' °oFQe„>›è“Y ¼#»ÛäÅg¦Íwµ>'¨Ë‰¾2€{ôP¡Y~‘iäÓ‘Æ@og`…Ç{'U—WP¦²•ðÂzÆ_B!Jbï3‰h_š_wÑ®›_Ñn˜_‘D´‰{\»,@y߬݇‰¡H¹á]š­ÉGl =W£žXÆ-¸Ÿ“’-­"X+lýœj{¦?={× ­Ê)û;ÛögúýƒàŒ,ã;СoÐhÆgßNÿòw<+Þ8âg¸ÑÓ· îŒÈµqIãuÕYœ8;l¦~ß§Vˆ‘Î߈¬Jf¯œf[ÅGž½8RÌ ^9øh±U ~Ï6Ò)Ç8ù¬Ð¹bÞr,}©ï*’ãèÓ¿ñHÝ›Ϩá]¢õ„ï ê²3J ÒŽBâ‘C±ÙžÅ¹!ë‘€øâÏX*zº3ÄŸ’½«¨9ÃiŽrªL™3ä]O,øJ6¦þákÅ­ÂÆ¹‹àpÑ[|ÑkãìÀ¬:E4—¼ˆ»LÅ•«œô‡œ9e—½ru4CèIØ]ã4?«¨,Ð\}W£9.¾Jóªà2’kŽŠîŸ|`º3W“ëi/ã CWZÔ†Nß¶ìßhÿ,¼Û²Å·âu¹ÅY Æi_jwµãâz¡cL‰Mè¶š›æ´-±éW„m\‰Í LÕ–Øì”•º›ãª°ÌÕ©ZkÕP¾#V­ý©Zw8Û*l‡Sîj_.4 µ/–ÝQUf¹ì5Ë%ä4/mŒ|ycIÖ'ùöº"Ô‚<{])Àä|c`D6@Ò"ä Z¡7$ÉYI¥uNÿ¤Ÿšß¬¨sÊÙIÑ‘»!É—Uœeer^’o´“úòh§ó“B‘ÀÄ’ŠAÙrAÖ”ƒ²½÷ukôs2\‚W5.OzÆ,·"f¤~eÌHýº¤PL“ž5[¦ab[ÝèøŸ&…0vs‘ìÀÉðhfÔÁÜ>ا?„ÿ¤’Àä’†§_4HŒÉ54G\½jM͈r( ™‰ÝH”èçø$ã}E éÒÑX!K2Ãq1<¤b8N5…²9"Ëâ;™¤8‹&*×Û<ò³$ÿ4'Q8“dÙYðÎøsð“Sry«ÁC‡j'„^¡Tg£‘˜†ÿN{áà9íT3Ÿ %ÈkIí]½û:Ùäõ¤´Sif“©3SÈ»”ÖJë(§Îp?©@tË/b™c¹XÕ!@0w’ySû+•ôZ™Íú0û³+ŸÄV% ñF“q«<×AÑ«2ŠøÃ“ASF-”·ñ+=h†þK9Š>7e³BÕú»­|G'ûˆÀ¯Cߛۼk”wM²ÿ˜œõʱô½µÍ{œò—ì?*ç¼²–¾·´y×)ïºdÿyoà‚WŽOöoîóÒksu"}¢"}*HŸ®H¯Ä”Š?Ó$}“îBCÅlå3;Jö&›½æ*¯¹Q’˜dö𧼿EÉÏä²×åµ JêBÊ>‹AfWÐLåjP¹–ÂÍŽi;¬ÍV»Òë“CÞeTÉ’aD—ºžµÙr3@ÆóÀºWåuort`BëÞd̈§½˜1y€…²ÒdJVSF`W‚ÿ ͼžlº¦–˜cZ[4˜ra(٘̃ï™N|¾)9„ƒo°’ÍÉ<,cÞ“‡“Ÿu&?1êžH¦áI0OýY²bØO'ˆÜj1Z`4Ö¦ÑhüMÛtŒO{møXëœÕ ÉXœ¨¶ Éòr2”ÔÖØYO ZõÀ+…ÑÉæø{-™8ÜaÄ¡Ü&2Ö÷ÕW ëv²¼Ûóa4æ#3æcÄœd9\ë—ÂzrÀ ¥Èþ)´Ž8Ó eQ…׳ÀWJ‰á NÁÕô\E/âèÃS¢ O‘#Ðw”¸ž³)JéÒ%¸VX|T 06Å$h\Š"¨ˆõLЫê>Å?ªO‘SAÄ®>²œ–¢ÚÐtD˜ÂçžÉ椘rOsRdCJØ´áÈL3xÝy)á6&-w>¦æB:0×”·˜-|3J¢¡–ð_Ï“,øìqpZ®S$§ü¯gHÿÜ}I¤—NËwoúu÷ö”.îe½º¸çÓßÂ^]Þ·—Mƒ4ÐtêÏ)©Å׆ֲ2~Î!ÿÌeêªbG¶ü/È|üηÖpßë/ºðݲßãëÁHóë¥Ç]*Ž9d 3r¡-¡–Ad±u;pv:“}^eóJ±Ç/ñÔáWÏ>ÝV(Òû.D˜EÅŸ’ú]Žp$ªáçˆÇ Xµ+ˆr*vÓ¬Ó&v̶Pp éÜ!À½œCÕ“’ú·ìó( øˆq ”¢—ÞZ¤QÂ{³e%¹ONäÅO~ &%–]Ì”Uš:…>;…‰¹–”§Cd&ÅÚ‡”8+Á>ó¢â óh ƒ8È>un¼R^Œ”÷³ ùvÇywÇÙäRϳïðnÞàùœ¥2ö ECÄq•¥Fnðþl²j_â,â×Pà@6²tØÌÒ£X–ŽÆÄQކÜV^ä”.ƒ†+šïŽ%ý«<‡â°ÆXHÍ7%Uµ£»s_ õØJ¹xHiíÎæåÊc-äm¦Ôi°¥Úëé‘EñÿpÄ*H ÔCP|ÆŸó•4¿Ô°ˆr>Z‚p;-Ø™­TfÂý¹Õ Ý-oËázal(ŽEÒOÈ1©æ‰H48ȱ鋎²V‡*„\COI]!˜†z€™ý_¶zúð‰zÒ7áH† MN×#Èvf_£°´ ¶ú=¾µ/±ï,ÝRÄi`šfÃwäK|œ3Gy›hÑòœËÀ}ôK™™Jt‡Ûõ|KŠÍá.Ô#þ¥ ºX§7÷¸’P %[i˜^Š"\ÂôÿŠÉ_%•"•.×0ùóˆü fRÍ7êxõ^ ^sS[ ›Û¥Ô[ÂÒ\R˜¢Jh_néÞÔ*FŒ¶|õDDXiR»á#B«ðf¾¬+ê¾yz—8üÝ«(ªlÖì ÷¬s‹©,c„ñ¼{Ñ·hƒÎ—uOêÑnñ™*;yZWÍö~¬Ùž©Ë˜Ô>ŠÔ«\Ãi.‘ŠÌkº›f/½²I^cêrAÝu=L€¿AoÕÕ¢¾IÞ„ìÓÎìH`VI=‡&ZÌVÔqÑsGGeò¼x—_ÃèJ÷ôÒõqáŠõqò>hYÎm;‡I BR¨Áã^ Çãã]Ù^]öƒüÏŠ\A=ú%>Ì0'a†a„¼³M‘¦•< 8B¯ù§åC¿¦ä_š#øßûf—|• ½SäP›ñš²†¿ž§¬Êó*V©2ÃÔ²:·MÉåšÜ4‘švH»6‚<¿Á²±þ5žàZoG½„ÊÖyÈ'ä9™m yÎâç"~.áçZ¶í{Å^=ä>–Z±ÞSºÁãÛèq¯ÿ}º÷ØÞ׊7z„éØûpôIQ,…Í=«“{õ?Áùæ¯ÝS¾Ùí_Þ×=c ­¾k,¾ÿú”ï*ö½þKòͶ)ßôvÉ-íùÉ•~erÿöÿ HÖ<`TlðÀþr.”¾Du¨ŠúÂBãÙÂf+ á8ô7¯Ë…ªÅx*ÿ“ èC]Ÿ Å /rœ.Ô¶rKG9£ Ù5Ôc“Ç&ó`68ê-=¡×|¯¿b ¾Ò¤Rg?*;“ˆßÇü{‡#‰áïý¸ì‚¿Ÿ;Ã!Ï©l[Yˆ^²¼Sì¾l¤5bjÚ î»Åßµ¿ƒû»²!ʦR´ÏPí§ñs†ê^/;ø-ÄÝÄ™|™âv+îf v‹Åµ•;à÷'±ùëÛò•Á¾÷†lëóòÿ˜óÿ˜óÿ˜óÿ˜óÿÎÿOTþÏ=™ÿm ÷Ý?‘ÿóÈúʺffýÓ¯&ö¯Mb·u°ŸšÁve³#«ˆÏ…g¶™³ï¶¿/mÈw ïQÑ@IíÿƒøMé<þœ‡”>Ï…šÎׯPÌ(¥žHéW!ï`—Mþ.ªäBÍ\ÁFð@ ­ F 9JøNˆâ´²³œÝ"ßæN€Ü[Ðõqš/‹\Ü"ï¨K,!zGC,q±pù=јmCá!—Ó”„¹` óûlË ëëí*7,žùm4DÕ#8Ô{[ ÁöécU5¬~+¨…¼•TD}4¸•Û‘í¾êÝl÷ÓTVñ-ª\MOtþŠk§Z3•Vk¬°Z“Ã4…›ÉZZh ÓßAc`(b‡…4©š¡î0–_#èãÌX¶$^#ÑÙOõÑzÍ4Y5U“S5ßµTZI¦Šà‹Mršµ®Ù¶pàN"®V]Ør3Ý"Ê­·KÎѸ ç©‚f£ÄZÕÖ0OyŽjóœÏÞ.4‘|Á+:*jp·,+øF ‚4j¬¤\×Ö ±Š/š¡‚›ä*ë±Y®ÑÔ¨³û{AWƒ)xwCMÆXømƒåÝ~BMûv!¶iþ‡ÙK»BGGn#¤ÐâX˜¡Ÿ#«)Ü®A”ƒE­wk*ªÜB ³Ó7<~,÷+î4ßÃìFÏÃláB µ&Â6ºxOÐfû’Ç7gî¶ë>7ëè—´¬  .³k`KbÐG=ôz.´ WEr-ºåxM“×µp:cœÙÔ²”=½fûºEÉâËo·£Ÿò,®ùy(°ÆÅ׵¼îµs?ç%$H";7r¡¦ÿeÕ8±‰8B÷¥Ð@ërµ©žAi”›< U½é6V—µ:‡;¬…N!Ür«vɉäÖ¤¶€'a3¨)1°ºh*nË@¯ö%/å w¹×õÈüoø…ùoõg‹ù]1ªRi uÅSøC4ð!À=äüV è±ïÒYˆ§Ao³Mñ¬ñ*«1*þ|♯â÷F|¹$u©ÝÀ[¹Jò¸ e±‡èæ¢ìßÎUº¿áŽæ>¬C»9P;ÆõÙ ¸a.ÜäÃ*Îïä*õ¿ˆ|°—tVÿ{×’\%ö¸ª Wäîqr÷4U+ÑûlÕ††ûlÃ]œÞp£@ŽÄ¶á.Yc„Ý7ÍCÈ8£´Êãëï)îï±UTyÒ¾'h ï¥}ûO`ÿžâÊ?•ü'‘ÿ2Ó¿žýzŠ*ÿV\Z"ÿå¦ÿtöä)¤ü`û–üW˜þ³Ù°§x°ò_ˆáƒüïýQíÓ²÷Oñå=R\ä½ÒŒ¾ˆý«=ÅÕÊ:–ÿ*ÓûõUþïðmÃ0Ú¶„WQ^Ò,í†>Ìv³Úh«wÖ›¸Ö°4$ôºPÆNb3v ï[j§µs˜ G vXÃÉhåœ4ägÀ4@•s•3Â…;‹ÜÎöa®² €È7{›bt1Á3hg‘oãXb7ŠåŽDgH5„‡ÛdζµdÿR”ìCj3ÅcÈ|¤hA;tYè½éQW+Œáv¨:J©’_¡²Yö·ŠÒe9€óKüS\9Ð^nðP8ˆ^üi å{”Í‚l¿©qŒ™œu®qƒ´k[ó;¥ï”]žæøŠŽ3DÇYÐ1†šŸIÇyÐÑ—éèÊ‘oŽ;ŠŽš6:îÚñY(ïÙýó°ÚëgI/½¾tÈ>„3-§8 d?\߬qÉJ‡J¯?.oVvm+æ ¸¼9‰bE1÷·ÀNÂNwà¾)P°³v`Ǻä\¶°UØÍ€ÝJ±Æv€vWv—JÄ)€‚ÝK°û;Î%˜°!¾jj= Øó«°ƒº‚‡ûgöù" û…C^ÅÖZ5 ·ì5ÀÖºä—?¸5ý¸÷ ÏeÊÊ$½Ñ7¼±”oÌ]GØ®ÍÊ1òs[n¼&o€œÁráÎê¸P ä ±ärdTøÈ89š¨\މ+€ŽðpEKŽ‹S¹¬ÅE¼j ì|ÀâÚèxÀíªÔŽ2ã…]'Wf¼K®Bôa–èûýEŸ€èÃ-Ñ›¢Ñ›âd ¢OpÉCˆ>·e+EŸˆè#-ÑoF£ßŒ“·}¢KÞAôQ–è#¡”Ð&!úhî·9ìSǺœ?÷Ùêâq¿,öN¦ž:%ž€&¹äTèqÓU§ES‹âh²æâo÷²gë=X4…uÛB\ ô <.Çi‹ã1ÂêKâåâøp`Ë[ÿÑ"—ÄgÛziX îœNÆ2¨œ—žIXrE|¹Ý_ïYŠû½­bB­°¯Š—«â}õžr»§Þ#8-Üýr¦x¢—'øYjÀG®%ßHÙô9Ë |CÉ\oŽùÞ œ7D„3·$~‹Qn4vü7ê¶!ƒ5\RÙjCI¦’ª7gšzWð *~ð° b)ûcQEØÇâq£*\Qï’'8ÎRö7x›§ ìk»:(ú|U˜£ñÆËÇ‚›y0¯î9iµÞÕ…Hû@þ}ŠKöc?–á©l ¢T›4»¬JqlßÉwf*ÕÈXíú|å3Pg¸5¸bxv]Ñ'*(9ÛG8å@þ×Y2TÁÿ ”øTdh<—Ç?²ÏÔ„èÝÿ9„_€Æ¢™üÛT˜ê‚ôÞ ÈK¥åE˜fgðpòWj0‹&Ö”([±£;D‰¡Ä°+ãDð¨™â1¤8Ó’â9¤xÁšâg[Š+8ÅY–¯DS¼’([¯R””â—‰!&S¼n¦x)ζ¤ø)>¶¦XmI1Ä)ÎáýµZ8£†§œ²Ê‰­6Óð”³@r¶m} vª¥iµSí÷ uª•g¨Hwª=‰NEÓH'ä{,4§4äD§…¦‰m4meš¸~Z”¦iN9ÉM/EÓL¢i¶™þã\gÈ?£(ìYP"ìÙÀö<“¼­ErIÞB“¼E ož…¼m o»•¼»ò63yó¹ÈÞãð{£äíuÊýNlj*òyaK‘EÌ"k4iÙ\$š´4™´4ƒ–Z.–/¬´Ü³Ð²…iYh¡åË(-_:å 'vU-7‰–ÛZÜ5iÙR$ï™´Ü7iyZYza%D…«’Pþù±LÕIѵi’–D½îA¢Žýç%œµÌ©EôIIІ8Þs‹edgd©¥NBNO’3“x/Yñ‚IÄ &µedn’Êȼ$Õæ'© m£ŠN2+:ɬhP´ÌBÑjP´áÙ}Ê-·P´-JѶ$¹=‰·´™¢DÑ. E»MŠöší3)ú´Hî7):`RE+,Õ}M²T÷CKuogšVZhú,JÓgIòL¶ÖUuŸ%šÎ[hº`Òô¹IÓ%“¦íEgš¾0iºšVYª½/¤€!›=ƒïjËà;89ªK(YVs•úÐäÈe‡+æ¸äˆds€”ê ìlÀB„y.`×Z`Ea%Ë%@Á.%Øå€ë’+LØ•€]gÝØ}ɘàaëÅÒ5£°ÉW4¸dK2¶¥b BS"15¼ (¹K“<’2F˜àQJý8E×p©n°N§HõJ2„ò°,¯GS½ž,o%«ôÛÉí—Ž÷’±Ëª’¹OÉ"üˆXúÔèt4Ðéy–Ðâ¶[*L‚ò/)ýe¨°\ao°Ïhô;)ò0+†|¸e.Ù;µ}öI…‰™®ØBí¦zF*Ì\¦†ý¨‚M–ò­) ¯)Þå.!G°„CxýqËÜQM²¥6QKÏIµB«£çäZ¡§g}­0&Ðsæ@aŸ”*kSÃæ´`y³¬£·EÁ^-r<½­ðý½ 9^‡‡`!2)5ì_ST\SDëɩ厌(Ï —ÀÎ"6a055 HÓá´K9Í '‚œJ«'P>75’Å:¯RCè§Ëñ~êÔø>Í¼ÔÆ,Ö$2?5Ô¨¼v95¹0g`åFÙ \¤ÞíeCŠåb”Úî®8%øÎþŠhöWPöÖb5=× ÚúT¹š Ì$¿Y®IðùZ¢¦lW‚\ËZ‹Ü˜Êª…ä¦ÔÆü¶éýˆDz{,`'ji7SËÌp>SÛf[Û(¼GCÚgY®F龚*%EÚ£©&s-•¸´Ô¶Qøzª…o¤ªÑw&o¦ªÑ÷Vªjò·Aã~ %#Ó°¸M{&%{™’JêÒLJêÒäдפdbZœ”ÖFÉä4EI}š¢d/­ŠÓ%SÓ%ÓÒ`¸ÄBÉP²éÙ”ìcJÂJ¶G)Ùž&wR¤}&%»ˆ’ÝJö˜”ì5)Ù§É}&%ûMJ€’c«1õ3ÆÞ7PØÎ§É3q¥+«ÀÎò{¡<Ÿs:j‘¢&y!-Œñ=h,ª„õïÂÀÁ¢JÈÙX¦+Q‚¯¤ÉVÆ1Ym"øË4jA+]ò:Q4ÑIŠò^Ð"ÕsÅH ¦·ŠKïˆé2˜n¥¢wº²{Ñ'½@H1±}!Î@ƒiŽRLçÄ)@CÍ'Írp:Ÿ®’W„‹º‰œ¡ú$òI_«ÓÛÊrhº*Ëaéê|°‰xñt“OWe9 Æ^š8Û¯1á“ÒAøœN¶IérZ:õñUÔÇgÐKÜÁ›—Õä2'êÍ]a·X-AF#.¤ ×w Óå’hüeé˜~ krE`´XÖÓ¢Òåæô°ÿ÷êªô–tßïÞߋwa 5#òU¤6Èv¤ûFW?ªHdke‹Jx+d'ù×yÔVÈ®t_'ì©óÀq‰Ü¼âÕ9ÝhŠÒeD¥ˆ€ƒfŠÞ%%Ä#Òᮚ=ѹMUíQŠõjó«-YÁ—±Û~¯°M—ÇÓ-sl´qpW“ÑÛ<÷iôþŒJæA¡Ng#Wú…tùYºªÄ·>n–§Õ{ó[·È3émçgÓÛÎÏ¥+Y„ TŽo×h—¢õû–¼Ì¯ú…ôjz¹Q(¿4#@²Êš›»Oçænº¼ÿ5róØÌM0Cå¦2C>¶ä&˜Ñ–›Þm¹é“Ñ–›¾ŠÄÊ "n‚™›±Ü ̈åftHr3ÜŒ@¹9ÊÝî;œ™Y¬Ú{EŠmÑtûoĬ 9'#)û,QÎÍ€I‰®"Æ,ä°Ssl 3äâ Õ+– ÐqãÞâ@Ë2pë&ÃrîÍ ÍÊ |ÊUáöYÏB¹&gÕDÞ Úz m̰”sœMø,”›3,‚ ì³%Ÿ…rk» í$WyÞº‹àº4ã–{èmÛ® V¦­LöÈ2Âe…1u9 ®OhìeDÀÀòئ‚ïÉHëÏ/ÒÄÚœ!›3|™ˆêÉØ@›JÕ×’Ñ2.iíPF¨{j‡3Ò¼P㥂{(­ñ½ ÷Ôå>ªS‡ÓŸÙlîY…<u1eM+kÒâ7>~¬y?ðø1½Éc¨€SÜEÿL í¦ÔþgòLF‡8ÇåY„û¬+¬ þ‡šr3¢¦¯f(VIÒsH¹v#CÊŒ0ŽûCž.[°\)Ý*[s-#ÂÅüe6N 匨æ˜àË-òf ×@ÕÌV=Òè=QdÈ[i³¶¤Ý»C4íÞTÚ};pÚUdßÏI»_•veìâʪÖ´tx:íÒf;ÓbªÅŽ¥=ºƒ¬éŠÆ {6¹pç¬%ì”XØ)ä4kØÍöœ%ì‚XØä"„ÅÌ G÷¼%ìÚXصäzkX…{Ávg,ìÎr7Â΃¦ÐîEKئXئ²ÅVá~n {:ötya׺p2Žd Û ÛÚA^³†U¸—»Ú‰Î*ÕÉt0Ík>èÀÂRxÀ¼æUÕú#®j£O¦|Ô¡ñYUM#ÚãåWv0S5´>™m•M|xßL®mEE¹Qnçúî—YnWí +AÃ2M‚†e2Ax€ ó2ÃÞk´2 ç—ô\IújW#>ÑY¯ò¹Šq¯Át,åèKâþW™9Åóú@¡¯¡çÂXKÏ©µÂ¾žžÓj…cC¦\“I ŽÕN᯵x_ƒw»\Ÿ ÛkíÚ)·OR´M™PüòŠÃ;ܜɪåŽzRy\=ï¬n¥­]“¨F†«ø½ÑÙ«jd¯Iç^³FBôœN‹´ã™2ôÜ*‰ JþÜG&¬ÜEeÙdS&¯Ò›dsfÔø»·dòÁo³<œ sìXu¡r=Žš£ßp¤Ü'21MÉ“™˜_ä)F’ŸqDy~y&=JžÍD§•ç2Ño=Ç‹œÜ .R…§ƒÓú<3ÖI›¯ºœâöÉm‚Óÿ%#y¾ë©N’3q’œir]Óù@„W´>ÍjÈèm“Û¸ÕÊŽŠ[ÜÑ”oÄŠ±0 ™ÞÑŒFmïZWFÞOU#™ÐÑdÒ'tT&cñœ夎jo«žñ˜#œ…¦²çÝ4E ´Èi&)¸77“Ó —5§±r”yÕZdw‘œßQq Ë:R97Æ€—?Øs²Hcµ9+;È5Í5jGÅ{¯ë¹1^¾¢ÖHaˆV‘›d®¤N}’&l6ü»n Úˆ MíƒîpÆ‚ÞèÚ&v AO[ úŒYÐÑ{TAÛl7™›ÿoUuÑ‚½eì­ŽònGSZ6ÇÕ 8vØsºHû„syrùÀ’ÒC3¥`'s[${wRØ·“*Œ~TaTv‚¤UWgb¢óˆ9Ðu"ö¦WûÖ‰ýâQõ¾†Œýâ c¿xÂØ/ž0ö‹'Œýâ9³VÄ×u’ã;•dz-ö‰pàÿI¯9©µq.9¥“i ý†äÔNa9­SDNïÔ(gt¢4³S¹]ÎêTî³;•ÇÉ9œ 9—•.og¢œ×IÉå¢ ,0s¶ÄÌÑr$‰Ö»¢S¨<)­DowuPû}SØàq{;ÁȤÀã‹ßk{;ÉS"ªÂDU„¨j$ªrzÞ*§]6ìNWƒøÁ2µ`í„Ãêrpñ4]éÄc‹®t’×:5f¼æcÒõNòz's‚‰ÅN¦pÍÍN8)·YE:õnxîtÂJí®%¥­)èÌ)á”Ft–c:[RÛYŽíÜ–Ò¸ÎfJµ­) qÒP6¡3l†Üëê ¶;F5‚©¡£s(°XguØ3;S¥-Öå¬Î8FÍø>ÿ:«³Í†Îæa+›CZÐ9Ä­Xµ.êìŸÕ _YÞ¾¿Ðär 8ÝŪ–VŽâ®Vpˆ¸&§¨¡Àjb‘Öê!o¿_ØåºÎë 󪯇Ôr¹»oÙóï…<Êîy6f\õ¡:rÇnú‚0ìQ=,w@&…((Ÿïžóó[Åä Ð*Jä»ëÉaóv…ñÒw¯Í&°>,w_ý²­ u,1þxÎí'4-ìÑ„gm Ÿ(þNQR(ÿwØ?µ °®„~‘à?Ð=ãÞÑ9œÏ —ö ›CšZš¢á<ëJT(­/3 `K OÓtã×()¾Ô¿RØ*ä?…3~Aáÿ¿p`êÛþiobï‰UÒþKÔmúÛÄA€ùßÂ*HÙԷ决Êf¼-?ö‡ ÂÞ™o ù[˜Èç2ùC ý_ˆ{åáv îã’C®o½y9å¼øVÅ6ÜÐ>úçá^‘º"]•‡{*¯}Ú_È¢–øO yvºl!CÈÓ ‰=Ùÿ?“ÛïÚþÚZý.ë©Ñï¶_é·Š›¿6þ[~ÌL QE}BL1]D¨üïrý VÀâûRµýŸP`$öƒ˜ây†–øƒÐk¾œâ[0§I‘îö _¥Ã]J(Îpñe½£ÿ„ÈÑËzƒ( ‰|ûl;Öìƒó:CáÛzûl»ë©ÛgGÛ_dÒµPÕmP;ÚAíxêÖûí †¢ âq9tC;5(û¯ùÑß+ô¿çs´ªøÔ…üBª+ƒq÷§:-qÜ4Tý¬tI~—²%4N]ÿ½öóÒ¥ù>ÿ÷òñ/[+öeKÉcZPè¿(]–ϺJË–aN¹r&e^[HCjx¾ƒëEïBŒ=SÙñ_©æÿ=ØÇR`yÍ™ô&»lò&ËßBŇKþ_ ¬ŒcíÕ¿3?äï âkc¡ü}(n“ú¤Å,‰ ÀH7Hdc/itžÃž”>ÇÁ5zŠZ(©EÄPÖè)*ƒB¿.ÐÞ—|ñ£x<¾ýQB›™0¥ƒ¾F(ô5BÖBK/{êDœ@Á|er"»òò{¿+[›Z/')—­1—¨^Åt9‘ X1Xþ‘!§*ô*t9Iêõ‘f¸{ñ€EÐ’=KüÆâÄafG²ÊvÁ€¾¶ÇñëüèW—²N¹(yeœ¿ŸQìg|'CS-¬›)ÎSiØ>ùÈ!—áËÁ7*–³‡·Ê°ÉUx5²ÊBšOb_ý åz|éHÃ¿Ï 5x†÷Nª&7 È}‡^k„B¦^†ÒÈ´•Âú™µüQxòÞŽryŸÄ¨ðcˆ“[t~lÕYËúGñi z'‡R~‡8ý\þ]–r7SFñÙ6ïÆí[ñ†Ü×–õѬ÷WYµe=Ü–õæv…ÛýÊAáþeùôEAy,£…¥o@aü1ÁÎL´ä}oÕ¡*ÿ“†ØKó½+<š-B¾½®â½4>îqÉ3Âw_‡s?ç9˜úÛïÞ>Ñ ì à²Ùòsò†pöÏêX<þJ´ÙÀ-§U˜^JQ Nj·´‡ÚqñðÍ„M%6‘iÛ\bÓ2m[Jlz™mk‰Í(·m+±Ù{Ù>-±9’lÛKlqý ÛŽ[ü‹¶%¶„oÛÆp_Læ.w}ñ6Æš‡£‡S”³#.• g‰ÞŠè×(úQDŸÏÑÊ>·£Ño yuÔÕò}@uɇÂ?9‘OØá þPñdXyнò=ÆŒësÕšZbìøâ«†7†j¸$Þc^ .ER¼…Læ 4ÌEh˜)ï†T}ßþº s³À_ÏËíoí7»­s1µÎÔ´hë|½t¥µu®Dë\B¤¤¥']»LÓþëÌþBÏ”žžR®þ¹™etçey†žÞ¡H)BdöÁŒMƒ¬¬æ”+ª¬æÛ'2Ò‰ùK²ü+Å%ZÙ‰ 8ÿli^ÙABM4új¶åLƒE§Í v@ù¬Dù¬äOf(O¢úVC™–þõme(OþI†r5Š:•ø7_óÿ¤›]øëùE»‚þVÅ  "aTÎIÉ?6Ç­ Ë¸ÕøqR”®Êwoýæ¢bU>*B#—Õùîóy]È5±5±–r™œÒùÚ&ª»ý0¸ˆ—\ #uìŸÆÎgÑœÏ ÿ*Ïzê_É)ße[ÑÖ|K@ë]ؾ—…Uïzë]€·ñ29Ú\4ÞyšoÀ7<¾]µÔC’SþŒ=—D¯x.Ñä2Í7ðaïÀoà2,ä¹òt=9å8Ü&ÍÔ9¶Icc›4\K¥éàngMnÓ"þÊÌÌñVzëRvü¹oî!Õ¢ìè+r>ü MeËû5ßBAž…‚¸Ü²qß‘!¤·™‰FËX¬oAu&š…µNøZþd­žêŒ¿žW,UYñ1GG‡ÙÚnJ{rZc­µ5¨µmæ´Ù\l¶. >ÍSZû6·qì¡À4áíyPO6K°×pòúvŸf.ãáÄ…?è'ÄH!Gcºà¸¨vlÇñk`RbŸæ´¿bîxY`åz¿C7ï Ÿß§ °¾&³¿çP‰­O³œ*"4y¿–dš(]jT,CÞ¦dxQQL%ÿL´–œ•¦w9²²RdAmPt•©ì¯¶½õB™ÝÅq^aO´hjÍT£à;é8òJÔf´åA=â«´9ŠÓ,ä!Ž2ã-\väyØ{,E{Ø÷¹h ÅP/±OïhÓí­)Ž]²ÚÑ>KôÑhü¸˜þ9¢ï·DŸ>A““ýs—œŒè¸ú–¨ê[É¡jßç á}©îÖkr­ ™MýE˜5d®×|k 7ùaáþq³Ü¬…Óqëb«=1UÓFøçî%!KœŠó.¹ƒ1ɘ|eãõ»ÕöóêôLõÞh(¸râû46D@@{ˆ3øS&ý(“~µ¿°Õäq.>D:©ùN}ÇßÏá9õÊÁá!OÑvêFÀ#œN8Æ]­AWŒ0wÕÝìoøŽ|­žø1ýïyµsuÖÅèyÐ8ɽqál¯–®Íw_éIÃèZFÿA¼Vº.ß}µ§»µçZÅ:ôƃyh¾›¯_ÛJß|®’ºo†BžÛ.[Ès?ð̱}`ü¿ë§ôa›J¸¢§T ¶øæ?å[ýaLaÜ÷:|=ýtC,€ÅOZ‰éþ_¥ŸN|%©o?Ç÷yqŸ•Ç×Ñ|×”Õ|§êMi¾»c&nº(PsÞšïZØ!‰ãt£f¸ÍðÅñÏÉqç)yp$&G¾Õ‘÷¥#Üø‘¼'õ›1-íõ©¥—Ís´×ª–RÖà‡µ•¢î‹E½SNv³äż˜r²«íXð«O³àƒ>lÇ‚ÞÕ ¨KmP­í ZŸ†Üêr”ÔmP²”|jH{¨+mP×uµ êZ;¨kOCU·‡jmƒúP² êËvP_> u¥g;¨kmP×õeÔõvPן†ºÚêzÔ @ÝhƒºÑêÆÓP­í¡n¶AõËáð6¨~9V¨~9JSÝí¼¨¦º£ÿ3Mu­í×¼W\hË8[&À¤ägž×Ý%¯ä”o_û”ýû4×àù·`Õ{†|»Dñ.a³ßÔä¯`/œCv俦ùÂGþþ›šg—À~û}^ƒd°ï'äû_¡ÀÀœ@†™ð²é[ìõ“wüƒ „—… Ù4>4W^5¼k Tg@K†Ås<”çAà?6—eð\e“ (ûârRºÛ@¶d§iHowÈþ(È~^k2H“¡œ}, grN4¤¯ärä²àW€4ò*@úY@‚`´¡eŠ@ZRiåµ°¦=i1ä`°šý- “R¯@Öt†­n ÈÌ(ÈLMÎ6AÖt–s2À² ëÈ:€ ´€l‚lÕä§&ȺÎÄÈ È!€Q #Puƒ- §¢ §4yÚ‘A,4È, ×rS Hµä~侯 Ô24C>ÈP Èp(â©3È&dg˜d\TÅÏ8]Öé dSg9Ú|†[@æd¡‰ vFX@–GA–ër¥ 1ä*€Œ´€ìÈ^ÒQH$¢Ëƒ&H£!›2Úr È €Œ±xÞƒçåyž5nƒRèÊžC¢l†r¨á{𦿟Ç=§¯pϤeT¥G+~ð¦ 5çX·#.9e•à8u†)ŽPg´Šþï ¨3 W>AÖ°ˆA-¥³ ÎH(0(‡QM5ÒºCÄØÃê‰Â½îÆ·å$£ÜaÊ¿l³Ñ˜('G]ž/v¼¸õñcmÂãÇô+t½€Àé|΀æqnÞœ2]å`n4sUæš9˜kÈy·ÇfMWÄ/nOü ñмµÔBü|"Þñ ˜p´Iü"ã+d£Û¿ÔÖZÁʨFó•†\mÄ x¬A¸:7¶sÞ4Çæ7Û4X>JÈî)­;9A£bñ8ž ë8ù‚ rG˜ŒDZ ¦–·žÏÈ)5µ#Õt?aëtm;Åíä^+¡¦5‰}ã\9LvÇé©é75¡M¿³–ââTSW–Óôì0î9,¿ÃãBïÛ*Fðïȸg/H#Bž´8°ã@ ˆ`W&8ÿúü¬ÌïÀ\Œod¡{¿×3²PçZ]›ÝuGtE²~.rã5 úÙD÷Ï&¹±ËöbFÚÍÔFª—'>£ Øs¼D”EÝ|5íÃF?5…lÆ ak ÍÈN¨hp„²³+æ9hM=ÌêpüŒÆO ~Æá§ŽX­®#²mÿù‘߸B“Pƒ2áW(¼µ…°‹cŒøÏ߈<Ÿc+jºö<~\`³×Ú„Ý6¾Ð¦Ùmà mºn›Ph3:Ù&Ú캭ÞÍ;7ÔzmjY]EVçà4Æ] Ë*rªö3¬+ Žýk¨a9OèŸÆ [—x ¢ÛoÍ%žÒ`<ýy)iœ’Æ)iœ’¦R‘óÄfCXWk&„¹Z‰ÂeY-ÌŒ‘eùMÒþ«i³žì¿Û›ý§r£¢lÁ*lÌ“9˜K)º 3!Ô$ÃLiîóSºóì”Æ>™RÃ×KiÞóRÒ-yÒÍVÀ+ËÚ'SšÿõRZ@UJ*qž¾ìâl[0;ìïË–`a<*o2~¦å@õö^=ìñaÙg°ºé€BÀp¨l$T2 QkÔ´F[£.ü·® OæcÑŸh]AÛ$KëZü¼fß®Ù,y^0O»`KÿÇ9¨²'.‹å ªL¾}¦ S-9Xþ•9øžÛ$mÅW3Ì`+Ÿ?–<§ÕN²V}u[ú…™ÒjÆRS“Ù³À¿À\†îÜ5î8-5Ý­æ%s&aƒdÙ6mC?[íÎrïªÅã ²c%ð õóT×ò¸Èkº™XÓ­s;ô”Ô¨oëšnæŸ\Ó­Ç,žüeáÄ×\Ó 0z^k·<8‡sö2Ž©ÜÀ|û'2ÓƒBü¨tC¾{FPTlÈoUïj¿(ݘߥl#}Ì ½°UÌ ã—­bv¥!ç…ão t£ÛˆÓAúµÝ”Ê?Bâõ¦¬àOsV%䃿øµíãV±¤ŸŸ´Š=¸¹.ÔmÁñB~èߘƒ´òŸ äø/ø·¹ óË.ÈßûŽxŠxlÀ‘ð½ õ¿.Zþ1ì>á.;æ¡¥`$\vÔCëÀÒMùþãÙGÐoàdIÄsÒ£•mÊ—}…S~NÙ)$¬€ƒE;Ä!"ì^ÝO³ÚÄ*J73æ°v˜›óåpá߬0G‰Ò-f´ÆsÇCM1_Žk—X­(Ýšï?eZñ)Ûš/ëþ¨EާÖÔËî=°éÝ>½i¯ÒT^î(·¿L%'' âSŸ•øO—Δ°£I¿5¿\/~à°§ïü8Þo‡LØF¢jc¾œŠf³É­'èŽE×ID@ŒÞ‘<# "+Bu°ŒªÏ0ÕI =Ç¿¥FH­0 Ù$|Ûò½Ûò!½ê-ò3;¾§©¨š Ï­7Eöã¿…Šrî§v<ÎŽŽÏ¹øÏˆÀÙ’Oz9äE¼w);["?¾3"ì9#“!/Á§Ü¯/Dyœç\‰€3!.u•¾‘b«€è/EZªiP²W¼iQ2^ÞåôK»›øÌÊ¿!¿ÞÝ\+ê¡è¹ÞÝ‚õž¨È#¡æÒÀ’«Ñ‚ßOSŠš©ƒß~¿—–ÑåöFÏ(¤ê»Û¥ÜìÖtc€*¬¬˜7²ˆ{ƒd1½;TY®ÐTYâI…§Ôäj-Zxëµ°™µà \.ý5–øø8& Ò$jm…Ó¤µNs´pZhaÞ梱ٶ¸u‡nÌ\"RcAëVÑêµI+_ÜÖ¸gk÷4hÆÓ‡°}(£Z—_ÆÊã¶æ§rG ûïzŸ—xî{õ*¢¦YÑ©uC5(@µŽŽc¹9 îåvê •-´<4.E;¤œGË?]*É¥8[ìåör£ãnZ+Óq“`«¢ÈÉJdOÄúx›;ª*N]}—Miä/Å·*få°#=Ÿº!¤ÿíg"ø£x§tÝÏÝ×ß®X÷sèqñvÇ?^;F1g®§äñ§Äñé1ÿC~|hÐïÂíô»èCÇï8N¿¨\~–ËŸ#«X.NŽºËssä@z‰«hÈ¡¡ GÈîDawü9ǾŠý$)|—{¸«ßvW¿ì¦tÝ”¨ûøpážÿ¡{Á‡î…º}(oÏå 8ivÇSì¿àØæF’o6NuÛäüûi¡ÀìœP€H€á¾¹ôÚS<[ÃÔ¸ËùÀŸù¾hù¿‘ÿÙ{  w»!B§ÄéöÐtÿʵãäWd‡(’ÝÙÅÛ°A±ñ‡°AñK º×­éqñÅ´Z˜&!ªiŒ9Q+ÄA£r(Ücƒ»¾? {6þP7þ°™†äH(0/§l^ Êô:?§l~ŽƒÛçNqñ¯3dAâl­ö}÷åwÜõÜßqßÇ]õ¾{Z±{ÌûS¡ï¹ï¾ '‹RqœíÖ¸øµ‚1f° A çbQ6à=1»ŒÂ3´xxYÆÑïÃºÖ dƒ®”ôi‘ D£¿÷[ó¢ŠÉéš©Ý =äBѸLiýn \- ³²¹HPèB¹˜bÕˆ¥¬ q‰ðÕˆFOÀ†eF÷‹B÷`Ÿ\F|Ê¿\P×m-…rÚ×[˼”ƒP/Ž‹Ÿ¤s&v hnºJZj÷²·ŠÚ>¶‹²3¹ ‘f‘ŸjšÜ'üS‹?Qöãßdô„éèËqÚÁê/C°BFçm‘!Áê/¿'p§|V'#‚)(Ls™, \+A2,|¶È[nç‰Ä¶¨kF)ú²„ŠŽ^PF5]aú5—&$Óóz{Ïlx6?ó‰°¸{ÈI´XÖ¾ÿD‡,IX=9‰ÃOÆ|"lC [·?*Êím>שP^@•OxôQ†ú”Ý(¡BSZ:w?z,O¡½†Üv{\|“jlç„Ù_Ω–†Ç”ojxŒ&VêöŠ#”ÕSòÛ ®žåÒè¡æó¸ÿNÔƒf+jÞ1»/D=$yT½ó˜V{ó¾©>[^£0=LÕê÷_ÆB j‹7楖ػ. JÅÛn=6j†ï c qtƒmVÊßOž6°2_ëyƒùØŠ:Ã`8‰¸qR 'nˆ ;¢rv˜Cj7ŸÏ)/ÉÁ_Ï›m¢¿‹±‘ÑäÆeÉgt4ÓBÓ™ä»vJ ò3€ƒŽŠÒK]*.È,eïR1Ë.?,­st©¨sÈ|4¡Ÿ=ÝC5j'ó_J륋ò_ýc=qž®M‹0Ô]ïÿ†ãwI…Œ>i_XïP}£¡†ø¿;ZcÆG¸OLõ†[ÃEb” ±&TMh¼®Z”’´™† ÙØ­¯N{ë¨Ùͤ„½'uMÎzšø gR½Î…¼†MÃ>,¡5õ£’æ.-rLýRÿX¯£Ñd”b"¾Díp#±Û:‹Íô¸LU°_—ußÃX#{X"€"·èáÀ†.ìº3ƒj¨r›^ºÔÎn“!½¸]ÇháT¢LŸìÐK×ÙÃÏãQ±ÎŽõ˜Üe:߃“ÜóDRãó {õÒÙÔ:gÛå~J÷Dªêz„^r2¡S1¤ç´È0;ta‡ˆN9lÔ3þK’4 ÿ o•Ý¿E_ØÇœ¨š)âö.}ú˜3N`¿³W ¥¯O”N‡0ü>aq¼ÃD¸#`O}7¢ÝÁÖ_ŽÃ5+úu:ö…P8î@Á\ŒúÈK¨©3Ü£\\QwùDnu_a»«Ëû¨$®è!/úßC„>ËÃVG5lÁÄÃ`CùÁÍ9B¿Í¾5F´gÕrœ Áò‡µyÞ-tgÒ·8ä´XÈi§.¦r&B]pÛ“œI“íl‰VdïG¬Yämê.ä6£@ng?çÒŒÃø:¹Z8vá n€ˆÛmÈ]ì¹ò§îújZ*{z¿'%¹Û@®”ÕŠ½Fy\y<µë@Ÿ÷2`ëyŸ¦aÁ==SîzÕ{ú¾ÇÔPÌ-ñX1ãXd3­uêÍò¨Õ%•ZU°Rk‘ÇŒF\9kS«Eü Cž05¤7BžÃ0‰aÈKÄìñR×./ƒzunÓªEÂC^!ïrz'*I^5ÊË(vw‘Zé;b~6ÀVúlÔùºBû£Í¨‰7 yÓÇÀœò–QîÌÀÌq‡^¬¨wé» õ:£‚¥ï¸”pƒvâ`0Œ±âµÞv¼Æ"C‡žìc/OêàhúÙ‰Õá°Ló"'2¢À8à”ýíTDÄÉ*˜ž¸èÆM/ÕœGØ£h„ÆB¼G2hÀE¨Ï9”ê<“8ÔLj³“ì²¾—܆ž”>JÍKsíÑÓÄVçÚqŽX%>Òå3VÙ$Ïjá¬LÜ<§ù7v,. · DâÖ¾w{‘]gæ“«:йîÆ%žwWF+PjòKâš9dfge3-§bk,¦™ ¼÷ù€Öp~̲ÿD„ºuÄ~ÃÒhfCvf.í64š›nuo>‹¢¢9‹t¹v¿¶åÈeºº7t2voh9³`3~ ÀÛÀcQÀcº<ÀOsä)ðT ð36)fü€WuÔÔ·¸!‡÷-ö¹Ÿ[Ä WlÈ‘·uU‹wÿ';Up°~`¨T¡Àô UJ™ïsæ©qg÷¥oaJìCñƒ¸ßÎî¸è°³»ìêN«‰s‘C ÄÜÝ-î©×J沆f½ULÏ£ ÐY£,áD“›™ßPÃ-m 1Jói&k„zÒaË zXÜv{rJPgZ×2ƒ³)GNCþÁ¶–÷©»âù€¸áÓ†Ü`„•NXXóBãßl¨VµÆœ~0"; îCøÜMŸû îßø Ñg£ÑÖq†µuœ&#äþ <#ÀçÀB˜ÙeÏzy€µªCÆÃO pæ2Û?Ñècjl’ç ÿ·wßÂïÈ÷)†fÖ0¡_0äƒBz–½cs“C`Ô{\–ò¢áÛ”SnoÊ }™“nÌŠP`ïè÷ ùjâ[§¶µVµš{àl±è‘ajêcçòìPüJs¼Ã`Ž—ýíÏ/«ìÏ/ØŸ1^bGïÛŸ1t±«ñr(椇¦`òPkír¼=&X5áYÂM‰†›b—3ÚÂÍdCbîx#9e*”;ºRsVðœPÚ:ìÄ}„@S æ=ϼwmþÎU(—m(‹ì\†ØXb÷Qex†Ö”ÿŽj»Ž#'šŸûÖ m•ìI?»_pWÖ ¹ÒEF…ö¯C…~©=½²™Øß9!WÛUauéBÌK8p¦S8p¶“\k„cß+>'â@ª\r™œ ÈT°2ß…ó´5šù­v¶i¶36Íbäï`ófÝÚ ko4ü^Z ¶…;€p}ºAZí-sžž ¾ž¸Úm«¸ÚÚŽ ¾ /¡¥¤ºÌ»N9¥;Í»N;Õ]§ï–îÊw_øvAn­_·L-5í‘~­ŠJîϽèôPÈs2ŸCæ¡íz“¯²8¸S\Y,‚•ÅMÿÓÛN§-—„þÏS×€ÎX|ÿïS¾g-—„òžò=gñ}Ó¼Bd<ë.TÿââþÅ6÷œA"ìž;H¸ÏèÛO¸O¥¸øÜòÛî*ŸûЈ÷íO$`%ýw_IúïŸC:ûfÛ¾2co='cÏ‹kÉvÔ÷ƒ¸¯ssª²[ôæ”jJæípLæí0¶Šûw{âæTU7uI qòB¯ùwâ’Ô‹ãÉqvS7§àø—4F¾½9õcusê ÈDwÓÔ´^æçh¿Ð&ós¥L†+ íò`f|À{-ò­PàXNc(})5VË‘…¡À'\ËÎ8eQ(p.)úñ6Nsj‰Á!Ûàn¸ÂRn‘¡â|·ÝÒz»«eûÿI{ø*+oøÎí÷ê6 „Œ)*h¹7 Ö»Þ’Íþb³¶ 8Žâ°öko"G\eõ‘7ÉnÖŽyw¿ÝlDï šQ,ÑAôÞ‹èýÀô^L0½Ý÷üÏ<ϽN²ß÷ûæ¹SÎ9sfæÌ™™3g”Ð)tÿólòƒªK/3¨’Ê êÒ/#e2iP5œQýÒ`Ìó‡QågÀ¤'?#1˜,á6ØiÍ@©ðŒ~'¨þíNЗiŒ³þT\Ç9¢ã‹—ÅÎ.‹ìøâ¥-4ÍÌé,ê|Î`æ4ª£~»L·_Òàþ·º]v]1à1àz’ßTè÷ªÐ Uè<º‘,4š }Ø”kº9eÂ`Ts'9uAãZA= þè‡è :ø1õKSº—±æŠA‘‹¨ÿ%CýÇv|ñæ“Ve¿õmuó馪ЪÐÍd…Æýá¢o«¢·TÑ‹TôV²èx.ú£oâ…¹/Ø´ðŠÞMb¿Ô¸pXŽàÃIÀ•Én¢‰%»&hj£‰Mèøâµµd¶ÔµµÁUÚµµkÚµµ‰_¼F×·v‰ì¶"û2‘};Iö¤ŽÉ{C‡ ÞWuLÞ:ÔÈÆìPS³sïXMNŠÔ”¨H#P‘¦ Î755* PÓR ¢@E›‚ºÐÔ)P1€ªNŠ5k êbcP5)Pq€šžo*ÞԥƠf¤@¨™)PG:ÒþÝG›•UP³S êªo êrcªæ¤@5Ôܨ†F š‚ªoìÔc^ ÔQ€šŸu´¨£MAý°¨Ú¨¯jA ÔW@}õGÍ B=ôutþSôBÃͶ‡o¶lg3a¡©Î‘wt™_ˆÛCªþØ=÷{…ðç þ<ûÝsWÊÖKÕÁ"¿A?Y’ÔO¥J?ù:©Ÿ| ýdé‹úÉ2Më@™ ißÒµŽ×”Öñmø¨á™àáÊt»m‹61§nj›{^NÃß«ôצ¬oï¿h}»‚æ&V4RøÌ{h´NÊ`}^Ðð›’S [s¶ü&Ù 3ÌŒugûaF_Ø´NV®“õÅ»Æ:E 7±%fܯDµ†»+pʸ㋷ª5|FKe«6q3Çž¾ˆcÝ7áè¦áXÿM8Œ÷ê í)|þ"Ž ß€ƒ (&oLÚFí¦Ô¨M4µ‰?:j7ÿµÚ;íA#¬Z;ýǦ·{·v4[­¶cæÛC«à3†r «¦QÐCüXþ8RV$Ú ØÎÿPû%ÿW¬R·`êQ]šûpÒÇM’þ)RÖ—“~¸(ÅzÖOšdý™žµ¤IROw80P~®gýç&YËtÿO“¤^:”_zâŠÙO)®G´A~P2±GÙ¤qí†ÙëýSDUiQ/rÈRDMÖ¢ÌÉ[g¾ufqZZ-I$,§ž'ò‰ÿHÐùKØRRC «Í£l)Áf®l먛R"æÕâ)=”)åcѦ×QÁ‘Xoïh6{{­åüSÊó¿…Ÿìí¢ìðH ìÅŠ|uR»£óí *þ‘fùôÿú'¶üÉ'—Zä›z]j! »ÁY »Ábbv„¹¡³ö‚ר’½Xyíêh¶Ø?àèßÞø7ýæ–x2VˆßÈßFËjÞ(›Ú#¦Ž¡?ÏÝdïÆ $üŸüD7ùùpë´»£…€þ ý={­¡¥Úï•åÜïe_e³Ú~pƒ6 X´·;û‘£å×v³Y²gÕ=´Ö³;þ“ Ó ¼†)/Q‹y¤#E´lZ¾ r›6Ç "ÎO=Ö ñÐA n ØÇrñhá=èÇncE¾©o7˜%­÷v´ÛìŽy‚‰˜¬1Y1YY™MÖ¬Ì&Ã9²2c+ÀxïŒ_â…8&0§ùÏè{¦FÐ_¾¡A%+Þ¡˜°•)g'SÊfv/Üû޹hVw3w͹"EιZÎy"^V݃³Ôô0ËEì­¨£î4ÿmc˱Eæž°#ÄþANFçÛß{âj²?б™Åçßn¾=F›ìK–¶ï5>øæüŠ MVc‚ú–ÏØ*¡ïùŒ ê{>üs¬þ³>¥Pî—ÌïãT¬aß%†}—œ&».ƒ¥ïºPh„0þ¥p+›Àþájš‡¾›’܃±~`6æþЦ4’ƒõ[‚c ÉÈ ®‘Œ ¿SÇn F:ÂáÓpÁ…¾¥or|Kmr|Kv,~ü668ê³±ÁÁÏ] Ãmì¶³úšÆgæò/ñ‹«¾¡¾¦Ùå_EÊÆ;R0àÒù¯õ¨é#ùX‰f;ù ÇS³ü;$vÄ2ãsÌ™[GµEÞ€i‹¼q6^© ø(ÑWj1ÜÞ0ãjÌê5ÞÁÙï¼ÚôìqÎN“fñ/ºÿÂTþ‹&t¼¸+C­©¡Ÿdxƒ)›Ôáfx%ïœè~N˜ÊÏ HZµªl‡ù?ê9…–°W šF†µÇ¡W´Ã_½¸ÃÄORˆ†¢IIDGÑ?4!œ*ìyØÙ[¤Ã è Ö ‚5! «¾còÕ8Ël蘼A5$hTB†›(!~ÔH 9š5 Ž¥@ mjhSPwÞoê˨au<jX#PÚ‚ô«F N¤@ ¨“)PÃÞÔàÆ N¥@¨Ó)P#ÑÔÆ Î¤@UÔÙ¨ÊF *ƒL÷;)ííò§ë~ƒ­=mtompFV´@sºº¾Ä‘-)|²¯K‡.öü¸Ãà:Ìë+:Lû³ó)ØÞ¾ÃׇΞûºÜ£¿cþ§OöwùÐÔs?´‹ $µ\=ºç¯´ïWüë_X»ø×Oú·lß«Kù›Oö˜Û÷Úc–ÿöÉ.úØe–ŸÂN«#\²¸À,XÌ1—쇖qɰ ‹Í%ûp™Ôv—»'¬3k×™aº¹Ü\2½G‰7Ãz-‡o»HôCfܶ¹ÒÑfs¹7 .¥ÜhÌùwÓ6ó-q±Bˆ0´¬æ0´¬–]p¯Q²ÇŒÓR°º\‡.êá ’bI ÆÀÜœ85 AîJæ%^qôàpçl¹øˆ9)[ÿj¤lýßøjѳžñŽ˜ã‘²5µ–þ¯SÑû&‰?9)›Bÿ§9þ|Û k)äAœò_EOpþ5M¨I·¦–Þ;éß–øÿÑ3Ýý|Uscú¾ÖÑ$¬Vt„›€dnNu”ùÅÕÁœž‹^³ÍœíVÇ áñŽ/¹Ü¸°\ úä@—7ß+n‘OZЬ¢à þñ÷ R)Éèyž¼ÏÑfÎtWý°ðçꇕÜW?lü£ßè‡i}~àìu=Nv„'̱âö$ªÓDjKþ¸)"%3z”X¹ñk‚²Ê ë”ÉæO/‰î—„©×=³œj.yÚŽþF`¼Q6 ‹eÕMëb•ÓÍ08ÿaÙÙw"eƒClo>C‹:AQUÔL-ê4E RQ³Øp££™‚€$ÍwiÉ=sÉ%1N’:Âà/8qY»Ú´ÆLÝX÷}Á¾4׳É«QÝaÍeßà²[õ²[ÍpÔ¨—ÅÙævÍ%šSü”SîêæwÍò>gˆÖ¾–Î/W< Ÿ2Kžæ—Íé¢Ç=LÆÍí¢Žú+Câh¯ùAX·ïU”å–â}ö¢}v“ìK_ù{EsƒBöc{ Q3aD1Û)[¢0Qß町½Æ‹\ÄÔñ‹-]åRØo, Êå…kE×*ÂÕGáZͦ\QàŠ¨ÅÀõˆquá”c:®cyœ3(\'ÛŠ,ÊÓùîûE òúì«°½Èc’~8¸@Ãy ÚÕAùˆ ?QHÓg…ä ”wJ!uœ {k éÓ)…DÙ’›œÁ’™¶®r¶¬ ºQGRKŸ’|Šn@²HŒu@ÒÏ€$®#‰ÛäΠÔ’£@².(O¤œ¤Ï[ªÁNI’'@ò Æ@2 \]3«ÞdÇÕ2Ü+û÷e?ÅuYÂÙ‚ÉUB ¥pJ•0OµËv”W4 ´w•Cùwy¨—Ã챌ŸÃÚ¡º…e¤]ްÇJFˆ²ËïEÊ*BlÁ1ÒÎwÍþŠÍ]§V k…]VØ‹?Å«Rcß…Ÿ  —£ía[NÑýBŽ¡¯üDÑCúiÇ•«XYÅ»™[ Y‰ÓË A9UGß §Ùã=‰ªj{<…—ßùª«MÖqÏ'l3ìráŽqÛåL{Øaܳ`¦keÜ5Œ;®ãžg§þº‘ÚÖ öš”µv½ß. ²£,&¹B\èXlt¨š|‰çÑ5¬šPVÚѰýß5­¶ËÕT‹M¨Å¹Æ®½v]ñîo•—àßÂÕW'«Óë¥k³ÖS–†œò™=´&»%fµ2m¥Vú‚Zk‡]n%€s_)·‘uöh%LŠl55+ ßiÚ7áÈ7-æ9ažÍÊ7(¶ÃžÃmº“ÈÃmJÍ¿Ç.wÛ‹/¾×ýâ{&NÝc/Ù_íP=Zt¨->4ÎêaÆ=î½Ô?E©Á=,ûír?xo—ÍîÑ·ÔxŸa{;&× ¬íò µE÷OMÜÙq3¸lNžO:Ȉ=¶Íí!Ìë{úÖDÂépÚå;ö¹ú·$¾È;T‘­èßC:Ù­^ßj5?´k£è!ñhñè…3©Jò1—P=ú õègÌ ®ßsêјõ©®ê[ƒr CËÜ 9âlB5ØOeNö¿¡ê4uA9Ì¡w–áÕYF8Tgå 5̸³T8`]`¨Ú,TWµ UÆòá{œ²Ð¡Õl¡C.æ ª&K]å2¹¦/ à Â0HuÇ•À0Ü€a/0ì';€a„CLÇsÈÜAa8B€aGPÕ0# ƒ†/a¤±y€áØ £ÃǪut ©58ƒÖ„á0ì¢éüÛMÓ½Sç_§â__§ÂÝßIK$…{€.ÞŒBÜ !íîцÚÕ8u!î”38ƒ&Ä$Äx4*(çhæ†o1†yÀ0¦”±ÃY «ÀÞ`:¶W;#‘Â'AS¯½A¹–£qψ[«IRG\ç”Ûˆ2îÔqºêq*¾ÅÇsñ¿æ”³zñ³Nyž3(º/Ý—nP^&z¯¨Éà WvIåñ '¨à¾`Ù©Lœ™wRÆ_HàÒßÐpÉA.ä‰ö<•)»à€Í@ÞL´*ÊpäMb©´*—\Ä4­ÊEZ• ÎVƒr™K5àr€­2€=°Q*u`'À6è`\ògP`¿$°'ö`PžÔÀžØ)°ö •:°S `û¸uoénÙÏ lwW9ÐM`å ·;ØVŒcÓ±I¥"û…ìBìB·\Ì´±I`—l„ƦvÀVÀØ•Šll½¶Þ-rö=°QR 4°'vº¡Ýoì×nn÷3h÷ ùuÅ!ò#·|âVí~&S>só«Øò¹;B+)Ö3€;Ó@nUÁ’)‹ÜY†ž:=M:=MÎL‹FÊâA&wVZW9'ÈåÜ´H‡¡jìÎÃq³ 7òf‚|˜_b1ŒÝ:äirgPŒØM÷òá Ü—¦Æî~Â0La8 s nÃ-P ó:¥÷t ÷ÒäΠ0<$ ¡>(Ÿ¤‘djʧiºdzN¸†+\ àšoàF±¿Gô¤ òt•C< âPO²ü0¬–k ´~áÁX*x ´.0pcŽyŽGÎã ò|‚¼åBâÆ"Â0BaX Îw•¼g8~e:쑇=è…3Må“H99âÁ#X}GóMeóz”O+EžˆME,Âç{‹\ñ”ÌÀ5Øk—Ôò¾ŽtÕS|#H©Wt#hfëò¯<Å‚E‚&yä,îd±øÔÜ}Ü£Þ]!‡&îã¸Òƒ›@úËN­p˜ý5˜Ž{äIº´ƒö¢w(ã3>-K|ök³<õbêîTªEžó”L·§ãQ‰K”ïÍE]­ÿ‰5A~û wÑny´Ææ×(¾öàòŽª.î`àjQ²¾w=‘äu#ÔVí÷©PÛ‡T[ë‚&1Q˜æ÷°›}¦Úv‹Ï´°‡Éj5-ávÏdü“½ÔîS½zsÀ˜ä+âÔU^«½ù¦#%‹zô­ä¢õÉâ±h»ž‹{È5Þâ›Á’Å=ˆø»;£èfÐLÙ_7‹ôzÒ©ÌN!×zaƒÐÉjóæ*]s†Wgþ\bþ />I€ýhô—4À ¯œC¹°W2Qô Fê"¸€œëe¶¿‹I46àWßRåZôŸ©×í ¬E>sñD~>ˆå`wF÷‰ÂÌœŸï}ÝjIßK[¹Ä«7Ø *÷æÒTƒ­ó6j°õ^½Á¾[^Åÿ-%fP’÷%[½‘Æ40Ƕ0þÃþm^­' Ó¢&3‹{˜,Ôœª —óÀú;¦è’—K­¦+^yE5å%YU4²®z1²òM¾4}li½¶¤fø|JB{KÐPj†·Þ{‹/égÑå àQô4Ù ž¡!Wv2Ó(¬FÑ­dCΧ†¼åU gN5Ü-¯ü:ÉÌ`æ 0Suƒç:3U$’Ìü3œšúØÓZ‚ŸUîïãG‘˜&ôô>ÅéÁ¾®&3ÅÛl5­2tîE>êÜK|:G`ÒÉlõùÞSš’º4V•¦>¹Ý§×qE×£§7ˆ®x¬ÝgGäN_ñ•`´è ¶¾×-æô‹ÔP§Yî"ü¦5,ÔµO*ެòé©%ެò#UZ×¶þš=v;ö*Ÿ\çÓd‡_Ɏ¾…h½€ÏdB÷iݽJ0¹É§³³Ž ¾¹ì´0êÝ>fçŸÎοÇXc}†¾Ù"Ù7?ûµUb&[¹š}èg´þõiý± ýÑn®âŽh!YBÝÑgZkP#îûÐ'67=ôɇDÐŽWˆ|ÑüDsÜ}ìc76O}‘há³ äû:*L‡ËŒò3Œáþ’YYü\æW9 ¿¨CÞù X~À‚/Ñ~­ÑP#Æú©ßFÑCä8?Þbi¿TµJ_¿Þ* ¨Uúú“ýT‰{½5úúå@¿ÎÞ¡”ëÍu©Þ:Þߨ·VúuöâÂ`•+6¦y2Ñ<Õ×3geq{‚nøÓüJ€³·/üܰ¼5~–Lú "ÝN[´=Ÿ%÷†N»×7BUf—Ÿ=öÜ ©öøo‰[#„8à͇ür‘RÛ’Çÿ^¿ÿÌú}~fý?z•;Îå h5zÈ-ŒhßR¾~ê¹<øøc¨@Kw®ï!ÿë6kúIê6§UÆüX'oìd¡ñôs¦ê‚?‡–ø¼epÍ//%›ð2±ãªÞRòš?9¼Zªá…}¯ü4¾¨@¼âþwÍavRf×Ñ ›x˜ÝW<8šlÐEÔ G¹A‡ÜÆÙQ¿<áÉ8[gmœ- HžIv„ èSã솿Ñ8»™ìPæ;©Žð5ÕüžjgyßovÙ©)ˆ”ü­¯X“õ¿ïÇøkÐÆß#¿6þ¨ñ·@KiüYL› šÜØ ½ñHÙ hr[ {~“š&79 §r¥ÉM t•ÕÒäNeM ©‹O§Ï‘J™›€y•AÝ_$¬îŸƒº_gH<ŽÄ“*ñ·1¿áÄó:çòb;ñŠˆKDÄ•€Z\È”WUR3$]£¤ëHѸIÞ ø3™¸¬'oRÔxŠ’)’ïÐç(Eò× y»/ÃÒñž`z¤ì$ø²£Î% ÇÒ5’ƦËñœA‘T™ÞUNL'¾œ ÊIéJíJWW.+ÞÓ9&§ÃæÈ€h­!8§h—A•Þ¤#Ú”.·p…h+!ÚD§i­NˆÎRÙ•é0ZUe70ìæM5[†ãéx–déúúàdº¶BÕh=r{Œ;µ(÷ŒŸe{ ’~eý2ä€ ZL´ª­ØŒ®rpQv.(‡dÂó´ŒÈHn5eD:ŒQ4ŽÈ€U3õŸU]âӑ´#CÖe”lp+OšCŸ`Qå÷ÍrGOΗ3M½i’͈ò³Å»3TÃîÉH6ìÞŒnY®ïV4+­ Øìgl¿fl'“Ø.dȳIlçc» °]al [Kˆ§–+°\×ȸ‘¡ºÞ-Æz “z‘X‡4Ó¦º!Íä°fÜw ¯fbN;ȹÚr®iœ ¢zZ3Y­e»ÆÙuÂ5óÞœmƒlC3®‰ØÖLni¦×dk³F5Ù¦ù*Sô®—Û›Å2^Ãg¸E²*(w5‹ä'z-Ê=ÍRlÖˆƒÍ ½#ôWtôW4ô·šÉëIô7£¿¥¡¿Î襆þކþký½úûÐ?bôQúñÍ5ôã›+ôSšËIÍuôUÍ¡ŸÒ\¡¿Áè§6Wè¿h®ÐW7×ÐOožD?£¹ýìæ@£¹Ëë룦“:áßY$êæ=ÍåÎ$»“±G‘+¼™iîÝ ÷6g`¶ØOtĪǂ”:)‡R¤D‘o‡½sâÏÔNŠNÉíæxÄ^Ün.¿ÖÝÊ„½ÞáN¸ó¬VÕã2µÜã297‚EfÕ?±ŒË”2Q–‚hLNÌı„ÌÄ+G¸ö¿SkÈ:*¿5SnÊÔ+¿9³Qå·fj4ÝæÊ×eÆ3¾…ƒÜLÕ;2#1T|Wf²â»3ß—‰Š×¨¸¡SqCQqC£ân¦¼¤âNc*îêTÜa*îiT<Шx¨Qñ8EÅ“FTyd.y„|ÃÓª{=2Ë©Ya[ï×ðtø·8À”ê,®ÛñNÖ4¯o³Zê¯ÎÂX•(usK¬Îâ–@Ðÿ]óZ ¦þβSU̺KU̶;‹+l?¡*æ8Eá²*á<%×fi§q rCV\7çÎO,Tî©b8\¢¹®Ú˜…°2uº­HŽjÇk”-Ù6eQùZåŽr)k†ÍY]e–ÀGrù‰Â1!ßémQj'V¾†ºoi'•e£ÓÔûÊÛ ÂÎ,Ð7¼»TvbÒî¬(Ùåþ¬Háî<¯-¬h ÷èìõë@Vñ.;{¶ŠoáKF³H÷—‡³Âöô×qŒWÙËUŸ%ë,f´lÈ »ÕŽÁ » [&ZúÈŠ†­ÓcÕŸ•:ä)êNy:«}©+ `F!+vÐêÅ^x'héMi—³ ÇTj~ÜlªnW¨n7²Â.=Ú©¢oR´LR|‡`»ä]h‡ÿ„¨¶iBã†~Å´_…òÌ•é ùHÇ\D˜åã,Øö¶!†¿Bƒdä+èÞ¨(,ý ©óZ«R÷pê)Ãl°õMl}…{ßÖWä6ÎKÒfQ3̧ Iƒž»áyLe+\Þ šÆC®ëœkÅG¦ë¯È›Z®•œë¬ó~åzFwÓ€–·ÄøÄ€–rPK ó*Æ|Î{šž{šÊ=­¥¬Ös¯ãÜç;™)÷9÷ò–Ë[²¿º•-åÊ–‘háÓ (ÿ´^®jë­œ€à5ײ: €+±ŠŸcS*Rv›¨žßLà±Û BêuBê!õ-åQ½y ä"OŸ£õÜRåF°ª¯0#\ÝWXdKyG+ º/Sç%º¯jø*·ÏÀWåàW™¸Xáb®÷eCî)zî)*÷”Wå4=÷Î}Å{›ž{›Ê½íU¹ãU­*û¹*W ¹Oè¹O¨Ü'^•§ôÜ8÷µNxØI+&8÷ÍÑ”xUöiEëÏ»Á’]¢4Üæõº”}[á9@n²?Wºn+½ÀV·Är’åÃZÉa­´2¿­—Ã[Fln¬òj¥—C%å¸V‘|àœümNžä¹Txf0®Âæ·Šü«˜ÚV‘³³xq±enr™¿RVh(³N•aÿ—”·ßŠîQÞT‹ŸM5ú‡\| Šßêd¥‰é ]ð´‚d¯G‚õ9åÖ¹›@jOGÊ‚½3>…Ï—Vø†g-¹¯š ç*=§7“ûµ_'­=OZåÁVšœI–ÖL^cDZѤ<:$d´•Z¢ÅZ©%ÚJÀ!O=BZ[}I v§ÊŸ¡òØ’=Ñ*Ҟ˟D¾ÝAy¾æš^ã|³©HF6dû…V\êµôtN˜ûJ’¬:‚õwº“i%r©•¼Ô*ir™Ú¿pKÐÔkSP^A_ØÌ©­„ ÊUõ+J¿6åWÀNKί[18Ê9­«4ŽŒ7€duG­ä£VÚ‰ ééù;ˆ“¿'üYD 1ù”?cˆ-o X<Á÷i­¼!ˆ„˜ŒÔ<Ðs­Q[£n9)wTƒ•r`kÅé®H n­±m(e_ä]ƒa­ÕªnEÕª¨‘­Õ¯‚Ê–b4BªîX„µ¤;·Æ´«Ü­$åeRk9©5ö̰ „m³t}Û }©ªuüçoQKLjí²‹ÚvÙäÖÈLÄÏ ]ƒ©ÉØs€Ö0é­{K€s­•8ß:).ÈN·×·Fmáõi£évp•hã/X9X‚öiÃÁ´ß™¶‘ýÚ$÷ôú·é*¶Ñô°Ïä 6ºRæGò`JÚ&¢d.F1#Ú”lr÷VÚ\ÉF·ò(;’*ÚDÙõ¹R©a0ÚÇ´Qb»¨*ϰ“‡\~v†9¡—¥’ÈZE*ç„6²² k]\9¡ <`†­}I!ú ôHWØÙÎ%')xaÊ)/Ò‚­á©mø¤gB›×]ÎômÔg]Ng`0¬ÞÚYþÿVÚšm:¡^]%ì3ÚÈém’Z›]ÎP¨í@ýv µCÎnvÄýÀ0§ |sÊyLKØÁ•“ ^FËBEË ¦e™¢E.icbÃÊc5 ÜÒ¦ø²è~Y@kºË“Õ?râþ6š~±¿ ”uq°<ØFwõòP›XNÒpÔ¤©ßÑ$vHÛ&§›Œµ‰E1.J>… ô=ÞUí<·Ñ&Ú£|ãÏÄ—mä—m’¶]Çð@žÈSH¼ðÊ+ηվ¹ï‚êvž¼g¾ÔF^j£a—_¢EÃå6q^]¬kmâÔǦò¼þ “ÝåõUªŽ=¼-:v[š×Ú6ä”_Ák%øÅ—˜†·½%Ö\IáZ’c£(ßËRAÁîáÂ:šÂ=Ã…m …먑ǵ•#Û·–íí-Û×­{[3•£ÚO¶Ä '[;V´Åpe4rt[3*/ÐÑõÆãÖ!ÎøÊú¤¶%¿/Ûð6‘&«Úæ!j¢6rÔm•ˆš¨õ5³-Ãè’³Úâ1Œ¾!9»- –YA9§mà¸ûsøˆ#r×ÙH÷ŸÐ– ßÃNí,úÞ”¶l¯Å dËÄ×ãš^„u¶š›HX>H$z%ÿ™HÐYÛ6¥^ÍúþÐM.hv0å|&µRUÚU.‹KÙ$v¡feÙ¤}¸m6km³Uk›:Õ6Û´¶Ù®µÍ޶rkÓ6©kÔ&Û m²ý%m²£i›È]möHY"ˆ7° Û#eå¡ÚJVƒö´E/Ó•+Èò›!Àƒâ^ª/Õ~ëÛqdB3e_[˜Øb~v08Îõn¿Ê¿åípÓ&‚ò 7myHFÀ¶Gli©]˜8e`3ìT[yæ›èú'ˆ+póœÆÍóm幦l;߈m^^‘‹m±…GÄ]â"î ˆ{ÌmZ¯ˆ»ÿò6½¯µiy¶¢¢O6·ißlÕ¦ý²U›öÏ–©&³XÕ‘OÛÒäH½úYÛ®²<» Í}²4÷ÍN5u¿ì¦MÝ?»iSÌæzn44À lcŸœ ¿Š\¿óª~•ÙP_ ¦J¢y=U áÄæf+>² Ø@3ÒD 7V [U¶œ˜MlìÒ¶ ä¤l\êªÅ^KUvñ´÷ §½oúœÈ©Î.ßµ·¾FO-û"eýB¼ìSÛ²&}²_¨&RÖ?´ˆ•Ī&›ßÆÚŒ+23;R2à^ýHJdw•ó²iÁÞ šŽÊ¸)•qA6zå[„Ê>픞áõMTty6ó¿JÁRWαŸŠÒ´`©'Xê –ú‚¥8- (n,ÏÆu±\1żœ™bYÎL±"xže[™Qû* ï:Vgó‹@Î5Ùü$k-R ÷: gië)œ3Hx6P8wðnDþA·‰Â ƒ„s6zV`k¶\I•ƒÂ@ì¢Ñ£VÎJƒû”-ÎWÇ“éVµ'5¼r ÉÓÕÄ+|4£²rMv´¬¾°w©K®¥¯úrËuôëÆ ëé;Þ­w©Gn ¯Ãôå•éë}ùä&”¦/¿ÜL_;»}V[³‹/ë²c¤ ¸å¶l½ÊíÙá´°'ì ûÂþp@îÈa;ürwÿ} ü÷¥érgvñÖŽátåB-ôŒ÷åf«ÕÛál¾U`ƒõ7t¶P©“¹ÃÄ MÔAë)¼9B˜(|8BXŽR¸™ºè±lYŸ Eû³zÙ@¤Þ†w”>á‡.¹µ§Rkà’ yèTv,î‡ô:Aa-[5¶NÏd†˜)Ïyä â¸2ݬڃåÈWÙ«‚8c–7Tá°µådvà}3n ÈÂv7[Þ%"¾~#ôñ̾D)ì1ܨ^ÈÆô÷UùxØ^ØfüÀü4;à@Ø''R6#È‹¾9J·ŸdãÍÆÞÀÈåfƒs v Ά›Ÿ(ú:hü+„çšÿ+rHÏ#)¼ð¶sRެÈ)yd†Z7&Gß)›˜S²â¡Â ÍL… ¿/>§¾4 ‘agÉ6K iò+ß¡2.Y•óÉ#35²ËG3BØõ9:cØñ96e§ä Áæé© Ìø¦ ÌIU`ž^ù*‚)l޾rÂM¥0d_ JòMÀ¼"'°ºÃ.¼ÚC 0¥5uû“Ù%wß-›UvkÊÃPì®sä\=R>ÇiGÞ{W‹4J`á‘ôH ^€–O8ò¡É7Fäs޼¯GÚ8ýü"‘ôH{R%qp Nw«÷ Çož%Æ=Kì–ð=Ç¿Ï Ï” ×äà:S'+­uîڔʑ£ÆKNùÔ€ÁݧR;¨m·BíÈQÃ¥.G —m9rk–˜4Lêr´a²-盇ÉF¼@A=ÙÚ@êh8—ã’»shH çïAs,§ž_†½9Ð_ ×÷娃êGrôUì‹-·\¢˜«°ç\€Õ£FM͉…mÉÑcKŽžcªÍs5LÅ—9Cèt's»^ÈѯÎK^¼˜Œ›ß¥6c)FÆŸýr޼œ>&@I½Êl ;Êæõ(ùÁ ðX^Ë ã…>e°—rv˜ôAmÆ?£øó,ÇõyÒË;im–7rÂÎJµf;ËF§©uÐÍvÞ")±lwhç§înçDÚ yGOX ¾FÂ8J¸œSç fÍìIÝáANà ¨|¢{šóÉôþfùÌÐûwäpïwÉ]9Zïwzÿþ­÷» ½¿>Gëý.Cï?‘£õ~—¡÷ŸÎÑz¿ËÐûåh½ßeèýõÞïú†ÞïâÞ?ïYb÷³Dóç‰>O|ø<ñFÿÐûèý‰NxÌ}R¸æjgæÞÛ¨¯ÎU}}H®œ)[>>$Wõq˜r¹ä˜\ê˜Ø"›ËÛ%_þ°äø¡TõZ”ãrW‘kâË'å¦X:,—Yj•#r5–Z ,™«±Ôj`é¨\{VK+r5îY ,«1ßj`ie®ÆR«¥r5–Z¿¥Vf©/‘0þûKþ–NÎÅÕÅ+-€g)–N×Y:=7ðC°¢–ø¸62Û4â é½ÖåÂÜÀYä]ú²Äe¹í`Ûfì‰1Ûêålk1iý±‹ 1-¦ñì7ð£ñ,¦± Žæi,‹iƒ…Þ|c1aX.ÖÓøµr‰Æ¯Ø7°ËÜêcbW ‘0þû.ÿ£¹ìêS€]±)Š]kuv­¥ž·zà¶\¹!Wmà¾xiî;DÀ¦ÜÔvìæ\ãvì–\µ-:[ÛÝô¶è¶\m=P/·ó'¿~²“?£E‡š‘6¥A`„=ZåÞ\lÈðÒcª|ry/ÑùSEG¸xoýI€õ¼úbwTÑÜH´hÉ—#¹j‹»>WmqÍUss3ä:†\Ã(×qp©ovä6:™Kgr¡wZU5[ÙÔl…­%fß™\>,:— ýÚ|>—¼+ÏëƒwÍlø-oä öÄ“—0ëåÍܘº‚y‹†7_À”¹uùUn\cdæj¾;¹–¨e{û ëã\ù(—tÌ-À'D4>nÇú-ÐxŸ½ïs]èžäÒ Ô"N˜úä³x‹Ày·ÄèÙåÉy˜NPy9(¦ <ãƒóøžéï€dh”BšnÊ–õ(ùtyžáyÅŸ¦b5Ì#òbêÂëȼ˜vßµ"Yv9—…Â:ÆPv¹^vlžÆ­qyùƒóp]5ìÈüO"~B^àfÍ)ykkˆ¾ŃyMy0SR“WgIò;J€fçæñ#‘§û Ç‚<¹ OW.hb\¤jÝ`—XžhA§v©^ÁeÉ .RT:3÷ѸdzÖ¼„žµ:=눹*/IÒA"ic^ êTÇuâþ´ý%0vèÚ©«3Vn7^_ÉKÍ—rµ öJîK&Ø{¹æR5ôÏk4—ªÙ *¯Ñ\ªfƒ/òÍ¥j6˜—×hÒV³Á–¼?i‚Ýø4a}–ø—g‰o?OüÅóÄoŸ'j6ØŸÇr‚á@ž’+ ‡ò’b$’§Ä¢cyI1ÏSbÑGò Îh2¡>dÂp’ Gó —µ)ár YFBlä)ár"O —“yðôÎÂö¿XŠ\˃¬ÝQ%L×ò°Û"næÉëLPÑ~éTyIy+/†£*y;/ÊÏKÜÉ‹mkf’w)ÜOáj^ZB(A»Õ(hIj>Ï+žmÉ7½V4Ûb– Ñ¿Àl÷úV¨ “!íÔùb½v‹ºº…iH;Þ‰Ùf#æQíXxn'‡µ‹æ'<°ŽÞ~åF¶KîSjSgÞIÔ${FS~Q •û;|çüy–ul;9¶vÙ]©”69®o¦°Jic•(Æ· [»õÌèf<‘ÜŽï‚ (0“ÆT¥¨ŸÁÔŠ],"|†"|Slž×NÎJQ8»]¬Ò°×ÍúºœÃõ˜×.:–DòßjDZjÛÉÚv±xŠF«\@Ôè4Z™Flo/lGéøÖ†x¾é\Œ_¢hX{Ï÷•m;4óNjæUíäšvÑtÈÀµí"ÚQ—šT_ºþ[”(_ᘩׂ ÜØîÛ ë’ëÚÉíä dZYîÖ!Ãöààê?r„Ù:×|DÆÚ×u,™k.Ûð{@é•Á.By¸<Ò®x®Y¥uŸkœ¿¾]4R¶2Øsn{ـϥÁžóÚË£ø\ì9¿½<†Ï%Ážµíå—í’*œC ôGøðL¯èñ§¼ª0¾ª Î=pƒnhó*7zà ðàÇÛ·Gòwßè2÷w‘|K¯vü­å¿³ùï,;qª*dúPôÚ$ÙQð"§À)/r“Bº¹I!Ê4¢ç?/r#¹áþÁà¯Kÿm“CÊ_[á”òžtŠ:Š)0:EU°:~_s¼ZÁ² ¾äµ 墑3ùÑL%;К‚‹õ;‰§×Õo£­‰¡&´î7vÄ<–ïï åÊ?©ÕÊ͆V›¸ù]€7ÌßyÉæ‹Ê…øÞ'»tX\.zìrK,)æŸ|r¨K‡¥qˆ"–• Ëÿù$Ò¥ÃrŠˆÀÑø«ÕfÿóÛ»«ôg¹G´åg¹ñÒ9BBpúhýMó1 £²À*lö6œ2/Ç~!Š«Eò¹ñîÕ‚ ãúÃâÈתxUäÃâ}¨z½ªhôƉ”ÕféÓ_“8©õí=8®‘¢d1Þ /9ý½ž§¿'+@Pu›=3Mäª<Ë0M„̨œB¤w=ew"þÑ à´g]ÂY7d™–þ½L°Ë°â“ÛÝKît/[Ý£×íîr%ŠM!2ìEƱKD¬÷º—¼Z¶î­q‡S9Ó«œé2=Å‹EÉÃî…‹…(»—ê†,Úkµ†,÷‘å ¦0WQÄ‘ê~cZf–+Œ9—ÃȱºžPÅ9·ê9·šo‰~Ãim¾™žw>ï.~[ÏL©âw³Ò±«¹ÃC=×ô˜÷[83dø‚oñÊ]*ÃZÎ°Û këš!ý#m0k ¢³Ë´R‹%bi"A¼‡RÓ 1©Sq[¯úm3én_ã$uFîV~«Ü”]¥7"€ÿõÅøê55ÄÉè3 R>Ägdà¤åö?ú„LmÈ)\„?Ëðgþ¬ÁŸuø³Ä¢ãOv)Þä1™Ñ¿N½¹ÒG4yeŒ!¹oÓäñ¿NyülÞ$uì¯ÿÐc3ã ©ßÓ^]±½ì±™—ûý?Hk¿ÿ?´füAZ _Jë7x`Ÿ] {`?`x!f^r¦š‡™jNÁ Øç(ìþ€öyðì]d˜ÍŸ·0i>ÄS¤øz.°ão­&´Ú„V¸0ô‚»ïùL±qâRp;öoØ•:°§ `è^hXå +2(°ƒ­]åPx¡=‚·^;~gOÀ΃sÛZ*u`Ï0Ø79e©v©U.ç ì » `†ä+µ!_ï[‹/Þ‹_g (€/Šs§u§­ò,gP(Ί @q($/%Q\N¢¸ç (Àç,ÞŽÅŠºcÛ69Š3hãÍÖUŽcÛHH޳é(ÆÛt•pk{‘©®½ØÆïˆ\jcsÄ(›#ò…‘e6üìvKTu6­´É•¶’Ã.ä\e‹j´p>Émåesâ%cOÓÉÛh“›ŒÖÓˆ¼: áM]ÕÓ@ÒeC­Ï¡Ö¨T µ¾b{M{Í&¯Û¢ÈÁ`oØ[ I©½ °W `+ààtŒ=RØk†”åHYI)‡‘òU»ù)§ì`ϧ‡G Ó;M£Ø=ì.†­ÕÝÂÅÔ•ÔÝö®r/\ëÆCrŸ=ëu8$÷Û•'xòñòðe{½Àlµ;þ•‘e´7(.„gL…ÇíòKe{j–ÇÏ: ^ž°ÇJ¦þ}Y ø×Æ·jáNBÍÓ§h®µ³üi§íq–?gìq–?ç€÷O+™Œ÷2ª}ÕÉéµ=$¯!õ&˼ޜz‹«^ÝÂtËΰÅ]»¼m/ÙçÂ]8оsÚ%ºÉ»öâ cáÇBïž=Vù’;µ–%ú5ªí¡Jž ïÛsºÁ³,ED oû±Cx«Àê±;Zÿ8šŠC¥¶P©r“2N©#¢’šk(Ã^ì ~güý^ê£í2.´Ü¡8Wó†øœ´ÚÏJü´ÃÃÖ½Æ!×8hŽUJIš\ë§é&Xi¤”T2²u q=¥)µÌ&7à›Õ2»Ü戕="¥Ò!·“²+Ûf©†æ¶ƒôhm;aWØNQn¹ Ÿn?@îfú÷ ±DÝ^ »ÃÎEŒo/'îs°ùdØ u Ÿ”Z[ etÕÌ€-K½™ÝqÒÎýa˜“Íû’¶è®P©;TšF?=øé •úB¥~|ð'=§¼Ui†RåF9¡»‰±Ô æ*'÷Ë\'÷ë<'+¸¶UNVpí«r„3òÃã.“åäuDV8£|Õi´³«ë„8–”šqNRâ•2™bœgå™ëŒ—%ÜŸS§™G_1wA¨üŸï„IŸP .¤KœÔ'zë1šk™!×rʵ¹2òѸNä [ §¿! ‹¯W¿mê·w¨äf'©È0]Z«ñ‡º ê1òoá4[ãhê NÜvh>íø(áØé”;Ň»Pž|Qx¸‹† »œaÒf›• Ó Zì!îÆiüíuòBÁ½Ï)÷8I‡×ú§Kî%­_õA·Ü‡oîƒir?u“°m¡:3§Ï´j !H·„dÆhQCôôªx?‘vØ)3=±ü„"Ç#8Üh?ái 2W ïQ T ß1§l r<9^yÔö*r|ò¾™¿üÒö¥Èñ…ýIrŽ °ç4ó40%üg ÃÙQ"pŽÂ>?L?ï”gðåÒPä9ü>¬ÿN—çS§4C^q†•JŠ„Óéƒï \u†3¨ó„ ‘DK"¯!2æ§#’þÅÕK˜´ëÎ(ÏÒ:w•Ûpl|»Àæ²;Ιy˜=wb2jUj–:‚°HÂàyîäu¬ƒV–ç<¦¬å.YîRë!›ìëŠÄ wf‰|ᇫÈA.µÔìÂ(Áµ¿!®âVù¦×^‹”Õ[»·²v“C]±°ÍUÜ0NŠ„mc ij¡ZвΘËë¬-ƒ…­Â%+€„²€N9žÄOFpº¾JØ'P®Z‹NtÉ .ÃX<Ã>•8e¥?©ˆ"bî%½©½&R^Ñ$©IáEp¸0‰dZo­1œ½Y&W¹°@¢Uv¤Ë¸®³-LÿZ×Msåà‘‘i3í˜Õ3ÙsŸšfºàš¤ f’üD´°!„ ø_ò.Ðó*М÷´5_èyï˜vÇdµŠ]É™ÓJbÆÎ®|׌à"Í–k(¼D‹øõ^&™·Á%׸°R8ïûšq»U®wv¨Çá¼XoÜkÙà Û°ÙÃ%Ö½§Jð£{]aëç˜26¹h%ÞóT–ÜLöž§³ä¸“¾ÇDÎSDîÔ‰ÜId­b§¢’¢r…W‰Êý^#*¸äÐãgÒtüó5ŠP)öºbŸƒöýŠöUŠv"ù€‘äÕF’ê$ÒIŽè$GAò}V§~f z"šôÁ"ëQ}Ì%¿¤¶8NíÖ g‚ÇùÇgõ.&8ÑŽRw8MQǬšÛÑ3.¾IpÌc+»zy–R¿ÔSÏ©Ô/)u%§^páTñA•&Bic2¾v©= šê2x5júšhYÝNÜãÖ6ß§ ÂeyàbB­)ÜÔÞöˆ‚/i|<¦pÏOO)Øýç3 F½ïzŽ"ﻪ%Òú¸¹nžn4w£ß7˜‚'$˶Pø”dÙV·¼ç*¾&º_¦òk¢^Þ§šÄ¬ÚVƒ| É«|HL†lx¤xCÜ~ìÂ4.ŸR]â‡.ùœC·Lp˜&û¸yoÌ#ûºùî44Ox?aEä@7®Ñ4敃IX”úÓÙrÐ û5Iê“ÃÜaŸ®óøXçÁ<<‚æ“­DÓH7®UÊ1nR?¼žô9ŽÀúžXÑñEŽ'¥%Vv*‹UžJwØ+;ÅÊÎwCNAÞx¬èKÊ:Õ %Æ…Üh<ÔgG¥¡ŒŠJ#:ëüaØšù!É„éÆÌR$”cÓÎÍK-"~Ÿñk¨FªjT…½aGÍt¦m‘F[2Ê-—ˆ[Ö”¸åM‰[á{1{­%Rò…¯OîU"}½[®‡«tkØ1vúç4m ÂŒx#!æO·ÜBy“qÄJ?r«2œ~¦Ëmnlê¥W÷œc—ÛéÛT÷œo—;èÛø¹v¹“¾Ó?–Yp’þ°Àl³;bJdDÜ´$hÁb Ý>B1AK²ãns³zÜžuØ)^œÕ}q– Ëš£œßµçð7ä1õÝ¢çÐ7äqÅaZS¹cßE=Ë+hùDûTËi·<åŽA~Në(úÂJ—:ò†°³n¥VØyw”½g\à8ôzø?¸È¿ÀµžQ«¼¤ýª·ö÷†¼Œº=â•í?pÕ®»µÕÖu·¼ÉYõgGpsß|yœ4?Þ ¾¥0M|CH X °îé°î¹åƒ?ë¡kÒpaK‘V¿ÝqQ-Ƥ)µ;„û4ÿµ»J”bôºyY*õ¨ÆB+´¾´nFa?båð4––‘i,-¬£Òä°4õrxMßèõ rdš¡ËXå¨4C—±ÉÑiñ|“ƒrlZ”ÖF¯•z©g„½N/:Î8ÄÙ7WÅQÇŸÖUNL‹D‹N…„œ”©‘‘…K;{FÛT¢eØûöÙô¯ŽùirjZ~‚ÄÑ´´8xP6ÃæÃû›ÕiÚ/ˆªš4ÕæÔ¢³ÕçØÂÃ^¡ÑèóÓ¢%ÿ6¬‘µiagkÄ}IÙ]˜±éZ”&R|áÌo³š¾±^ñ†]}K}îð"à {Û}Vʲֽ$M.IãE‘¾d[šNËÈ#ª–§…y‘Gi´Ê«îE 5êLÊ¢´×}Þô‰„ÓçôʵiѰ?•=l­å÷-j=`;µXèQÖ»6¹ÈØÄÖÿhÀ­ Z¬Ε¹Âû&4hVz°€sÉUž­÷xåà¸Õž°‹¸ä:úŒ.ÔDôÞELßzŠ}˰‚õЄ¢{»;kyÄlóO³€ oN³mAEjJbqÒß§- ¹9¯æ5ƒûú瘨4µ„ xå@èóªDZK ò±òãT{æ~9؇™' ‡øÀ>Z¢–ó&SUçæ£|ì 1³ÂÇ[ŒöÁ}bÖxŸ勆ðìP¸ÐbA7’¾H83öž Y>/m!Gû®ÏK³ä_83Ü"œÅ¦céGá¬"ZÈqøæÄ,9ÞNp>_áÙéY‰‚¯„ýES¾o–ÑpfÑÌ7Ìr"¼IdqƒU£#|uŠÁ^$D|8[˜þêÿU¾p€æˆ 9˜U©¶±t•Í[[™1j®Oç1«æfMO¶ÉÈ7›ý¿Ð·e˳ÁMEÍ”s^àÀ\Us®$×~ž¡öó_RãZUãLìYr­g¢ZpF‹1T—¥¾oì‚Ë|ÚØfá8tC5J›Éå¾°=Ü̳‹7a«Ä++©·-WùøˆíÕÕ>¹Òn¶¨–r•{¯ÊÕ>>m+m%×øÂ­Ôy[s¼L¸Ž9Ô2ß<⋲àhƒ–iã[Í¡'mò…[Ê_øÕ|“ï]~¾D1Nݰkĸ¨wfá²n¦ð«ªöÕ\ý:½úû©ú»PW«QÝ}Äè@ØYS´‹†ð~úA‹pÞǨÖC?®æÅ”ŠÍeÔ÷ c4F„4×Fh¯»ôél{Õî˜éR‡ý>µÇ„+ªÍB¥ÍI8¦ä¥’’Ç}jŠ;¡D•ù$äÛÏ,§}|ÇÑzFÉ9ÛE3ßþ˜ÂúQÂñŒÂ³$&øY¨ºúY¨ºùY¦ ÷C.zFPp­¯ðޤð«¾Â7ŠÂsUÂ_Aáù*í‡ÜL¯ñËã>M.žð}“8¬—'¿±Ÿ4È3>}ïú¢/._JvýÃ8iíˆmõ˾’§fRmrx©Ôƒoé®$KŒz³6cšr qÍ'¯ùÀ@Üé&¹r¡J4“>y8ßLëVyöê»SVÞb§>ÖlnûXEÐí¼à1䎯8Ú%lÕ ½š³M×]‚Á›Ôà÷UƒãOs´µ v¢¤®õu[æo©K=öEb°Èº€ñêÏ|jî¹/U5~½%á+`“38÷,÷§êÈ]½?ŸÝ  ðç›~KR| _M9n9ÈvÇ«!³‡û•hõÈ~0’f¤G²T‹óË ?­Ãr4‚t9ΦÅÕbÍaÞSseÆG`)Ùæ•~YéW4SNð‡3µ -sƒã“Dm Þ@k~«Få¤QŠ•ãTÎvT³äƒ«£Œ@1+ãۋ̹~–-æùYè×úå 4œ‘l²™þ—5Ù, S2êg5ÒN µrž5QÊ’µþ0©Êá5açt–€ ýagµ9v&qöW”yE.&l$½,–qš~·¨Ö%õrŽó‡½á,-Î/WøÁ6íHh%ÒÒôÓ*d »‰¹ìHuÍ&ù&ZA¤«´4ýØÚ‹ÅVškü¼C ¯õ‡¤°0ô‡3^+mùYiz¸¥³%ĺĊ¥(¹‰©Ñg)°¸.#œAoòó„Üê§…K°:?ÄY:K°þ(ýçÚ%˜Ü¥ª–\,­v㑜¾évǵ#ŽGrrʯjŠ3TJÊ_)„}{ÓQ?Œ/‚C¤‹"œX!,'(¼HªÜI «*„í…“I—; qó3Ç .‘:ïgaæº@áZž]d©“v ìÄ \ôçóyù)ÿ‡&¾Ë~ÞÏ[NÞ=Áàd%å„•ºÎ¿ZÏcwѯxx,¨Ô˜ ®#=yé”7üF§)úîõ-8m+•”þÀJ~r©Ÿxè‡Ã'­½3~ó4R8•uÀþâ«¡îWC&æ˜|è‡Kªž'³ä#þ¢l=7¾'ó–ôÜûŽ|¢~­¡_+ß‘Ïü|€xïmM$Ù'PëBÃNÞ’}qÒÔ€žÚ9ÖÅ!û”]¦S5àÝ5‡F;ÓIi0éTùÂÇ„”›¸¼Å‡¶Œ•Ó*„gl@Ž ”l~þÆä(Ê++(]Ž„íE[޳ʱ4‰WŽ à@Î:ÿm6Ò“Úq•o‰š á,,Êu {«1Þ>£á41€-tÄùj¸óVqõªy2KÕpr€´9%`¨ãTPíczÇ^øÓ‡'΀Ó/«)¯’w¶YíŽcj­4; {PdÒ¬jžsð {Ôe–óš)Om Îû_ ]å¢@›D¦”kÏZÝǾ©6O3- DòM<À–RVË´rÍ;a/1§ÿÜ7µÝWo+T”¶›q+ íš¶Ý0)¬ DŠÎ…L<à×Ó÷ù |ìôïŒ[gßáîãâìø@@hSôÁ€ÚÇ;D£¨òPÇÒq€Ðûm;-Ê–5 Ž¢aâÁûÌ3º›NØù)]g<@-ç(œ^!¬W)œAãù…ý>³EÁŠÿå¸À|ì¼guŽžcn`Oíbäx›ìRÛdW%ÍËŽuÅP¹àíá¯j³Ê÷™xsÆ)oRø¬ÔÅÎ^n‰Ø»$!™I2âqO5…]Ú¦ˆ[Þ„Ý¿òN °³5ý.K¸c‹tçM{d-u…*‘v? ï#Ëð4ú³ÍBSY5&ÐXØãa§bŸaé«vǺÉÇh3õ7Æ€k Wuò‰SØ)ÀŒü‹›/>§OÔ2P›Çö÷Í@û¹m‘…Í™t6ú ™CH§NÆ[DÃÓb »&D9q™½³ÍcwlPí9"í™…Ò½¤@ŽH§òbT:7¡¹"ç–Ñ̦–œ@áÆqÂ61rÜ^9î¨IG/pÎMG/pÍO—£Ò£eKÜ´®H×äjƒÙÁ#1m»P¹]ŒÅkÙb|z>æLHÇÚ—+mMíwÛäDN·ËIDRãÿ*Dz,ey€m?[Íç¨dSÒ#1Ýb!l­F<»|L§ˆ: þÖX09§4S(^5é°¡rÊéé%õ®’¬å¼ô@¸g¦Ë™éÅY[˜%À29‹¡±ÁTZ17(>W¿§éxN97]iV.9?]©€$ökRº[.”ü„FØL ’Eµ2ÁRPÜrazq+Øq±§ÂV]ƒ:[Hv½­l%ùq/´ßrj„ƒƒ…@8a0¯JÇ›`ÑØ;]fxí\“g¯kÓãù¦žír]:ÞÜY«MÝ%Bß6»—/‘2ôCxËk(ÅZ¬Úí{ÎýbŽáqõcÍ*þóâõ|³d—«sIKú÷Q¾¿úmN¬K/ÞÀ©'²ðÿ£¸\}5Äi»Ò‹7ršå£æ6½®)á¼Ft†y¨¢adgls…oë,¿ƒÊ_©¦ï"ÐY|ï–¸JZÅ›ìåâ-ùÝhNsØ!ü=ÄÈ÷¨ÕË7ñ0!õÉ·ØÃ <¨ËˆEImÜÔ£š’ßR.*®ÐØ*ÄAÿ¨Î0 ý7 ú±nZÕÙôc¸Jÿ(ÿ1§¼e½ü0ZrF,Ç#L·ÄØ›?’ŸÑÂ3B”­v”|<òícÅûŠ—Ý3S™Žµ~-ùx9T~Rüq´ðc¡ÒdO`®èl¶³m¡þ/þÔ:ï´«â_@ˆù_I=ª–ß ÂÖOå/£üZû¯J6÷(ÉÆK‹Ýä¿h›S¿IÆ•¿­ŸòáÀwÁ€ßFÃ6¥ß4ÈÏã¤Ó° Mïtø/®ï/¬ï"J–SQ…ÿ ñûƒŸÖÙ¶XæFâÕñ”:šÚÈáÌŸ¡{8ß7©+ïc¨6çA®Ídê´¬Ï75èKZ›z÷óihÏŠ®rº ¾»g ®¹y–@Õ-³Wz®³DRÔÌ\­÷Q­ùˆÖkF5®¼:`Ñ¿@°¿ÆE‚ªG+ª¿TĸšX’,ãïA9E×iÞž+P×x&ü0¯‘¨mK®fO ͇³+ªµ[è'e{·Š8(ä^¡Í´ûD”½hï9ÝäAQÜÐ%ZØ@X¿õ2"H†ÝÁâv\g³ÙálxõúýzR¨qäZHÎñ­‡ó6óòBé éuÁç¼æ^§®!)¼Ašõm oÒúÿß<ùaƒË$¯èÄ]J ¸F,¿Þ˜¶¢ä°µ§Á RŠHÙµPN-;weŠË‡Š€›|×BôIÿˆÍ·EñðôHgýö®ˆ@êÇŠn†,ò^ãT»|$¢,ù€$«8;"nž]>aWi~pî1£êåfµ%?¬9åË<±Bƒ+7+ ®\] ù¿ì½ xUÇ•.zjOgÔˆ0¶ñ€cБK¢Óqn'é˜DzM›öMZ´tèœV:1¯oÛææ»Ý˜!@ƒf³˜çÙŒæ H1ƒ™ *1ŠQw­U{Ÿ}Žƒ“wßýÞýÞû>PíS»ê¯U«jW­ÚUû_ÒPI<##$Rˆ2F"©c%üŠF·ì†JºR, Ën˜Ô›@A]h÷JTäÛFnÛÇÖ_åc%CcP»ñ’G~…Æc/nF~s”ç—Ö©~~õöh5…t3IÂKdÒw"£ ÇëXÃfÆañS.ñr û«U‡S­y…³ƒJýt’”ét$ìK×isð©êZE]ãl4M Âd¥Uaž!3r~Sž®9­¶bUZ'TÚHêTº`}¨Ð@‰–:¡D¶N¢ÊHë%’MÞa (w£ÄWKºïW|ŠÖH8ì$‰¡hù øF‰^ «| VÜî/à ÒHx;íF%Ë~ð6<`A‰H9‰ô«0¬dèYaFÁUÔ…5(A&¡"5Ä)ÓaOˆ…ÖrØìüñUT¤k‰VÛ0›ã"5‡hŠë ÷¹W0\R7wǃÖx²š4d¹š6ޱ‹¢§KõF¹aÍ@¥‚› HáÒ1Lk‘hmÅo§`m»á­Jf¿ áíJæ¸á´{%`]÷$~Y Õá“qžŒkÔɬ\Dk4“Ï37‰Ë¹èüh~^—h=nã7¥Ú4·$q ì6….~uuø•ÐT]þšÔê­ÓèÛL| &ù=1"v¡ˆ}‘öbõ¸Pì¿âP¡°#Qý…²Çé'`z6X†Å.Â’5?TÎmîžÝ ýµË‹ex¦bòk’ø0¼Âd¸.~,Ôp >Bü˜£á|¤ŒHÒœN³É‡(««{OÚ«X­ã«Ðìe<0;M_@ÇTÊ|²Œ èÉr€—ÁM^¢ñ @¤t¥œLž«d¤÷ØŠ$ĈI‚'þu·™Ëb§Ë|ºL§Êh±\-^XÅñ²'VÄÅá:–×È~ø]“ä‰CµÌBqâHÌ*93!>á è ¶x>? ›fV’uè¶ß$ü¦ jÐôÓ~¦Ä|_P—è†_*üûx8}5\0„Æì:Y$Ðm¿hû5wÇ;Ëk*`ÅÆ}§´%´tí¸gÚÕû±‚Ã=›Ùñ?²ï÷?Ò3íÂï â2MKO’ââÉ-­Ï$>iCêÑ)–~’Éo’[œíóŽLÉ.Îf…ÅÙõ.Ýɦ0ŽÿEó±9ìî¿GÝÝòT:“­awßÖ)B”ÇÑ™ ËΖmI›?ŠùÓŒbiÛ>I+ÊÒNŦÈM㯥 ÏM;ܯûHmW@¸èÿñTÑÿó ¢ÓÝdËS+Öë {RÞ°jwûY¿ 3Êôtƒ¥5Œå~ˆå>2£ÌHoÇŒRM.Ê“êKÏ;ÜÙ‚Â"{@䌜™.8T0òM0kÿ‹Á¡ò7‚CåÇ€6 Vdqñ(Í[Æ»¤·„!ÁªQLú9ÿyî:%mv¿¬u kª—Ïû¨{°î¦÷ö uç}|Þ&'Ææ7;ù;>/'?ÞE;eŠ"ñ_"ùO:r_x|é¹ÉÙÉ–ÂäzQo“}¬-ŒƒŒ; S ûc÷Ïß/û¡ŸäŸvø½¥Z¤~_~)~"WšB\Û>ñyKS ®ŒÙTÔïÂx%ž^Tr"²K$Ç#KI²’CáƒSt‚˜¢A9‘Öð’N@™MN*³á#¬¸QæœtƒˆÂ e~ï—¬1sÓÛ3º´F0º Á:M1ÙFæQ]ÒÂ(CZMÊfœPÀ&PÀ¸æ§·'ti$t/rm†\ãC¹P®~Ñjc#­aô¤ªaºªà±Õ5tÎEð‡ûao0àkÓÛÓ­´>†ne8*`D˜>C%¢*[ *%¡ª,JoO´ÒN´ò=A´2AdÝ Y'„².¦¬ï?I R„ˆÖf”ÑC–|¢×ÿ¶`pYÀ·M–ôöT%­áT%/ëT%K©üw!Y·ìn–ÂnaÉNR‡éô§Ý­dù•Ø_Æe_ýX/{_•}õcŸw_œQö²ôöD;eÇ}´t¥¬~çó¶t í¤‡8Œ?/<Ñú}Á—öMÇ‚=2ÁspB˜‡àŸ…05(dCÝ^üsø›Ž1‡Ñ«“sñ(Ö…[Æ!ó,V2áØGrX¾å%ìq¦k—(Ãõá†á axÉ+JÚ—üg`=QJIHi˜”_…LJ¡]aRNK1LÊiØÂÛ›”>2»Rž‚¡øã¼Ö^Þ»½ðï½^ĵüÓ¼£=ûð·òšÐ®ôëÆ&&φ¾| #„‘G‘9€ñï½&ÙÂûú¼ÓSÈKãG0”äÌNa¼Ÿ¯[ÁôÓÓŒz‹ü+_Î)þkˆŸ‘Âs}Þj‘åaxÍ¡,yp«:…{ØE·j± †‚~kXµÿ"¬ÚßAšCéXµßˆ>ö¯†Yû¯Â¬ýWþohÏÖchÐvMš%}æó–«]ó'8ùç>ïe] òy'©áÿ“™»¬ž M†°UÛ0»€ÿwŸ·8)üÿÓ“ÿ £N胖ÿ¼³¢&ÿs¶9%þïÙs¶:¥øxd†¡|ÝPªÁø.ÓE—E,JBËÓŠ¨LtqPL—þ‰‰Tà0V"¿Ê¬¨£‘À@à£Cq Bo`/àËrݼ‡cJ=™weÒúDæKï^ßÌ&Žf–)ŒOf¨zCYÆzó*†PÛrhIQä±pWÿí§wUÓŒ(Îz(`eØad¨ww„e¨1¢D†Y”a»‘á qw{X†ÙF”È0—2ì42Ìww†e˜oD‰ µ¤4±UZY¥%t7¢JK(‘yd•êÄÝð*­0¢D†U‘UZ-î†Wi%2¬‹¬Òzq7¼JŒ(‘a#6cCº sg)£f܆{ŠͬòË6ÖÌ.¾Ëv3¾ÃlÍPõ½XŽQ‹ø>ºG¿ô!ë~ ¾2•vrÂsE§4s"g=ÊÖ˜.l„lM´‡pžì&ìºÆŽ1~ŒùËÄÁ#Z嵃ÈÊÿ^¥Ìø)$Ñü0eÝ~›á9üêå ƒ¡F¤³,wŸ–³O³ðs”6†ÒBO|Ã0u1”ørðÖœð´ß`Z·®†Ò6c-ÓC•x•È;Ž#葨eáO!çžk,»†¿¯›þå*ÙïÃßÇñ°ߛBë'caªã‚ 2•Y)Óð72}’4ÆR°?£/k¾±)6¤™$¤)~Ç&øXHc!"€ÕÜd!ÍufrHšãÏ’&jIVkHsÜX’^KÒãýp5€OD-ÉBJg<zŸ•e)ÌŠj›öïX~mg·üEøgÆ È2 òÌíì‡9ý1ï0jDBkBu>Ee¾e.aÙK˜¥p ëȯxÝŸ—¿äu?˜VA,N"Äí/â³g ž!þ.ûw–ÂßpÝò›%øsÿL×ü`Ï=ñ\'B<ŸŠÏ¤xÆ´»'£Ý}Ö´»'GØÝ“£íîâ÷#ìî¯M¨2„:gB•E@•EC]ÿ ê¼ UŽPL¨ò¨òh¨á‘R]4¡*ê’ UU u#RªË&Ô„ºbBM‰€š u>5ꪡ®šP•P•ÑP#¥ºfBU!T³ UU uªdrÂâ)L JÜ/ùó®±:|>s¯1Ö5Ƽë»ïº~ô®ÛÈ þÚ” w{_,DáõŒwˆƒñW¬y§zÖ´o[RÊ…âCT›$ìžÚ9‰7I¹Í,»¦I™ŸÀýóË9æ½è-ù%?‰æRº%[ºæl‘T~J¿}JÊkbÞ³9ütäý3úý3RÞQæ=—ÃÏFÞ?§× mèót=”„þ6±ŠyÎáÙPKˆ!ÍñKTDCþA‰oâj[%³6KüŠä Ra9ûS$Þ¡ nEÛèôR \tËÿæU~KʽÊ|”#û*“¨3Ô»M,šïI>Ü«äL‘ãéhWñdfk“x›”{1'ûbŽ…šw•í]ó¯äà~2:¶çìN‘âßÅ Æ2ûh™—¡$øëmp&g8!w…ß¼ %+¢äÑ2vo’5åŒz#b9;ú2>^ö`Ç“cÊ?cïš!ëÓ ™º «‘©ËH3eÜà}zWià3eTP@(¨‘Ï’ƒH!Cþ𡼱4ÈtÇò#/èR9|˜Y&‡3Ëqw ø9fØd¸Ip‹L*‘¶Ê|˳Ü)à6ÏÌí ­‰c§Hò/Ûû¦ð/±ôñ²ªjsÈ(þL÷!!…Ô ¤eÞ ?ó‰j”#Ÿ¨#²G¡ãaMz{‘ ÇäÜå)Á@öòI$;NÙü%{_~ÂHŠ yR£Å)”·$C’U­Šä½(ãh±<¥¾ Öþ²ŒãL²%†N\Ƚãÿ‘Ž5ƒà–f]\æÍ„œµ³¯%oyÊpÌ̹ìG¯X-ü®EÆšAŒY9 ©Ù„–¯‡©ðª¬°Xt§ñmmü& 9†ÂT”qñ¨žù­e„"_7¥ãk _}9>Ç"gji†¢©Ú 3MV°b+Rð4ÇdELˆ6G¹ÂË•Ü)þ@0{EŠŒé>EA·v)Ióñi:7„)Ó>]ñy7¤xïþuÞ ¨2ÂÆ'â©‘Å£z/tÅòjˆ@n› |¾Ð¹H÷£?V¥ nmÂ.¨ä,H—ˆ_¨ÏVBw’#`•„_˜çÜÿk‰ŽuÌ3£@v„Z=*gÈE, ‹@B[ÒÊ ÔÊÄ ŽZjî ºVêq&hÀ ¢‘o‚œEìLYd8ýÚBgo– ëè[¾… ÉÚ-/*\Ï·*þÄl}œb;„–¥] ß¡˜ãUß©h´Ú¥øñYÇb¿T‚~ïÊ”\|/Éà'á Ð“¨ùÿ€21dæÇ_ל` 1ëÂHœØKo ËiA°Þ@õâksäÙ…R æìƒŒç üPkÕó3Š?á4Æe%ÜX¹‚L¦!e'i­E— Q”vj9¸Š±› ¿!Jm •Êo*:Ráú”~"˜b‰›ž£¢*&=PøÅ`ü!sÑæ‘4úº•-TZ 9ƒÕ@ts^ÑÖ&>õ¡"šb$åðÓ?LÅcg ‡¡r£ÑD,Ë€ÚÄŒ£G£ ŒË¿w7À35jQ¦þ†aå>‘ÃüŸ0hÀ*f)SyÄSÇ©ô)~#–[w~Ã~/Q&>Uÿeêõ‰OƒÈßËF‡×ßé@”ˆÏT“Põæ¨0ûS†+Ö¬fÆr<^Eb_z ýWw£;=õö²MNn‹ÿŽËÜéS„Gyñ°§Ø=ŠM$ËkITè£3<Ž–ó Œ)(˜”ð&\.Q{Kål>[ʼýðíIlÛÅ,ù˾ær8v÷µH+R,{úZdÊA}ªvŒÔ·‰¨’a²„n0³«e 0àïoÁx§Ê·¨~ï;N¹…g°ó«8²þ5ÓLèý*út"ë¦Ö(XõñCû½jÜâîWƒ]Ñ`ðACNý0=—T_GÙS=ÉØªH)¼‹åíbÞ“o²w1 Mô-V£€'ëH÷#@dÕ’Ïù£PžÚ>&Péñ8¥êC}vÙn HÖùŒŠÜÌ0àö¡a9(ü¬* j€ê…&WÎVIâ!‚$ Å\‚%s;iE:CÃóü æŸåî 9Ѝs|\‚‡¶V§àÛjî>q+ÿ<o-§[åZîþð[ãñÖ ºÅ±„)´¶ù+ÝiD‡0çp`õ÷NÿÓ=Ó6ÂRç4,72é÷ýÏôLÛ gpíS™¡XU-¿exÃåð7B÷7B÷‡á¾®2ÕÏ)ìü;u£Lã q%x6¹ >]ÆyÔ‚š$\ y´‚JŸHþ×2¬ טé+\†øXn-ƒ¿!÷qÜg=4OM’Ï[éÈ®eøÍÔ Ã›æ|%÷€éMnj¢VÈ Ïiè·ÈO¾`y4e Ç?‡/ýŸ~Ïüùg±Æ3 *.®c3+Ê,¯´Œ@м’>~ïW}ѳݵarQ“ñœ—0Ã*â Sð£`²L ¿¥ÖÇï&Â8”uTõ$ð@ç'D!\ÞÙž]’^·X~ÃrKû¤}éÍ*íÞqÍÝVù++Ðå-–b“ ©ïg32~VÃ9û¨zi“úˆ‹v?½“ú`⬃}Y¾—[™Öøé-ô¥-ë£kÀ—u¦”[\\ÃÍOŽZðÏuüsÿÜN±ôÓÌ Q¨ n‰Þ2¶D?QþÚ=1\ä»P½£ 5Qèlß„aÛš“ÿð‘‚@>(!ìÝÒ7ý(*o°~ü.‹3æn(¸Ÿ°IÆ.§^nã»TìÅ?»Øvò_* Õ›À¤? ìY[²z!—KCJú ùöŠº®(蛲„÷©>ï}:Ù$üwÁÏ{ôó7,ÙòÙ'*Î…öÜŠ>z—V¡»gUôa9SúXðç„Ï~ÃR?Áÿ3<~°­­·E«ìcaª¥ªER-%},²lñõµ(ÅÙ–©},ês–i},šl™ wlîF‹Î,v£Ï‡v£Ïãnô¬ t ¶ýX›±q­Œ2½3¥Ü(6p߸\+eÒOyÜ{oӖ䫸gDgçq;ù¸Ý€;¤ñø¹ÝðmèþÜQ0Óã¶æßQ3Ç…v5ÿ6ocömA#Š)ïg˜¶¹”Ò‚Xô-Î[˜¢ñ]ýöªAĤÝÓòPZþv0D¶=ù¥AäN! /ƒù‡lüÜI=!K<=#fÈrl\*) Ç×–RfÉif×KÁ²á`Ò‡%þan‰L_¼â‹°9*èúß|é¹u,»ŽY ëX½P»?wY/¯¿oÞ Ö—%Ë=™;ÆŒK)–üº^îd/ë—’/ë ]æqyVbIÏó™çªH8ÞM'3(–­`Ù+ è¬ÞïK«€/FÓT¼D=°n€Ï[ñ’±0²¾‘U—:ùŸòë4€Y8@ß¿™ À„À|øÑã¾»›åÏA„ÅÂD°&†º [ɲWÂÊBÚR–¿ßË ˆr± ÊCµ¡ZDA@-–£ “êĉÃIð >8\HáÛ[zî'ný5»Í¶E¾Ù&€ŸºÙ¶˜2ýsØ6‘®Ž›¥´Ý–v«”¶ÚÒÆTÑÖ_Ú¡¦´YÅ,íìP†Ûµþ´³‰4E¨o¨oJH}KžTÞ=½¼±Uߢ¼]±)o†ƒÊÛëóÎp„ÜRy ;‡Ü®¼ûzýÆUÑÆbÚx½\üÝ!ëhÿ”ù ”u¥ßÆºŠ«-¿~Œu‰âˆê¯}ÞºÄÐ‘Ì r¸@ŽÔìTKaj=¶$ázE G;sý,tzÂÀÇqWt¬ бî†:V¡ýÐV±ìUÐ3W±°¾…çHB]7h~˜Zƒ9Y4×Ò8N˜+ó?¢Õ÷HW_›®¾vjK[͵*Uh ›î›ŽâúÖ¯¿÷OâjÉㄘ$„XBL ±ìÔ¸¸ç©èñ,¯.Ñ;Lÿ5ru²RÞaZ‰‹‹ K0Ɖ§D3dˆîLÑ%è¸-oòKÞí2ÞÿBÖÉøÖ„eÈò+ÞV<úøèuV).ìq2VuóçR˜`abõýleF—´’*–]ÑGÉÿª/Ý`tcܘyC¢«áFiä ™n¬#o(tc-ܘqæçKï὞æWÚJkÄ‚ šL£5þßJkŒÞJ›00b+m£ u¡6™P‡# GC•FBm6¡Ž ÔêHÔ‘h¨‰‘P[M¨&„ÚfB5E@5=sz» u¡v˜PG# Ž>sz§ u ¡v™PÇ" ŽEC-õ¥ u¡v›PÇ# ŽGCmùuÔêBí5¡ND@ˆ†Z)Õ>ê$Bí7¡NF@Œ†Z uÀ„:…P_™P§" NEC-„:hBF(Ÿ u:êt4Ô®Ø(¿ u¡&Ô™¨3ÑPË#¥ šPgê u6êl4Ô¤ÈÞ^oB}P &Ô×P_GCÕEJÕhBC¨Ã&Ô¹¨sÑP+"¡Ž˜P­ÕdBµF@µ>s¿þ(¾ˆéùí÷ëG(—†ïÕ4¤à PÇ2LoãÇqàÏh™ £÷KO~IˆìaójúàÙ×{oC±3™?±s™ß£Ôà‘¤ …iÖ¾Thf¾¼CúzÏÒµ§T0ÊÍ[˜/WΖ-£Ý|D÷W†îuó…’~œÏP¼ƒGCñÌR#/oˆ'‘¼À;Ê5¦’â^ÉP¬šõ!£ÛÃèÔÀ &¼Ï “ÈKV‰øt[š€Ÿdar)„C™2‘>ÑV'K|¤äï’„î¥FKÑR‘L©ÇJ½y }¢O@ý(~®­ PLT(Pùdü[Ã}o;/—Ы·¿ÇnäRÐçÝcÏ¿öŸ"yÔ ÷´Ã£å×÷…,Û4舙S%|­ %OCŠ,v,ÐÚ¿F2|Τ+\yg'¾ SRÈÕèXCIW34›f&Óí-¤¤•¬±K1ч Ç£ ¨½ìˤ}º¢öëŠ: 哸vCQ;Ó|»ÂšïKPÔ^CQûuEÝ@ESÔWEERƒ‚anIÛLULk”x ¤@˜MŠP`=Tw˜Û£å5èÝïÈ:ñÃèF=ò'3ø5æ‡%ôx$ø­i-ãYmY¢êt™ òÎ÷Îúú-KÚý_¦M]5IX"ö“²Š³dAZàÓ[ëŽSkAõOPkAÝO…ZëL¨µÎ†Zë¶Öµ dÆ/:íÉš¯ªY 5ˆt]âW%A˜rú¼ ß¹)áèÜ»×mŠ@Íü¨“›ŒÌÁŽç@®»Ôþ"Ã=3Êe¸gfx„‚5g Ó€B‚•Юú­'ŽQÄ‚d)“er =EF+©RFo;r•Œ¾w”©²àÀó•Ѐ3e¬ˆu–ÌKe_N©Û‚.b‰?e²¬ó§”É‚?¥\îͧÈÄ3Dí7Ò7ûÈm5U¼„Ób*@ÔȾ¬ ·NZ1~TŠV>[& I@ ò -<6ä(š-#ÉÇ×:ÉǑޕ~¡Äô"<ý2ÙçÑðüM¹[æËà K ϼB†.k# Ë)û=ûjÈnM¶t£ìkÂʎȾNF¦+bY‘}£ì󻋳ô—c™m39¾Íªµ·ó­2‘gØ“-м:Wì6Œ "š×È·Ë‚üÝž,‘È" Ž-{²ŠUù—2²É ï»égÐp=±‡~zÃñÄ^ñ[5ÜN€›-öÚ0<‰·ò¨k5ÊÆ1²x¡Š!2ΓÑ9/u•&Ù`˜9&ë 3ÇeÁ0s:˼3Á-ñ¯éª®ÎaA-Š]³.‘¨¤69ä‹kÓ‹kÓ‹¬νb¹2•a 1õª#bêÕF*ø‚••¬謂`õ@×TÖ Œ™¦¢w‰ØÜ}!®‚ªr?Âùå,a„Á –8[%§›æ@è¯`Is! T°Žó0Ïž›(•¬Ó/gÂe Ÿ†—³à2–Ï=lÄñj¸ZõKtE6[%ê§|ޏHâsÅEG>O\<Çç«ÉDÉ¿€ÂçùB _à‹T?2º/¦Ÿù5ðù€—øRúù2_­zô=àZí â ·°]¼ÊשžW½Ã4DÙ¨zœ‰Èº¹ÙH7ÛL·E¤ƒ?ÛÿE¾]õ¸ŒÅÔsÜ Ð…ïR=]¼cœ(ÌÕC¨ûŒtsÍtûE:øCÞ^âUO¬ðIºq`?´×œ*öZ@å~TÞ<÷ç^ã&hý½† ÐqyPà¾m ¹IžïˆI3 ™%_æG á7}>Õ¤z^Æ”‹nžP‰ŸØðÜÈO¶—쬊c싞j‹P¿@Yìú"­³X¤Á( ¿‰*!ÈA‰ÈH}‘ ^ò¼¬C$¢yÂ/ë±X~•€ãh]6©”Õ…Âr®zÂdh¡[ZèÖu¼¥Ñ­›„›@ôÔo¼43™è8gŠ2:ð[xþÑk [9ßÓŒ^Aœ—²Î÷TkÇø7ÐÆ)@™8„*µŒ6Fï ‰¨äü%É_¨…CBÖ<‰k VµH éˆn Á[6ºULô ‰ø'¾½üI|Þ…¿Ad|æÃ5?€t Aœ8MùŸ#ùGš„Éo3å-$¢’“øJÞ„z}SÑïŽ! µIi ÍÉYNëÈó§#d Ñ”và”/)„SI¿Ÿ áT éñÉž*pV œç S'‰ÏЂžž$òSQyÈME>.+¥þlÍì!x*sŽæyÁ£B¿í„ V>W3{ v¹ytd­ÆÓ¡S ( DÃãà²H uk¢ó_¬y^öØ«ƒÞ½ ùóx›/ kQúUót&®ú穼ea­Šå-× Ûj]b»­!粋?ÐpU´H'Û‡΢Äïâ× ªXì#  ŵiä (¾ÐÚÌÖ{[ù#‘ f¶6ÍGœËÖOñô¸GûÙZ!½"µQ¤ò)rñ6#‘™¡S˜!‡=e¨•^ ´Ã¬º´#¬žøOèn¸FYi¶ŠÑ§*•µÒÃà­k=ÎêqQL Ö¬ìkïá¾0HÇêCªséé§A=.¬-¾)E1ð(âD+úÕˆR|²Uø -³’ç4&Æ“X A˜ô;0ÀªˆÕ°†ÜÙøt—’YÒB|Å&„ÕBÂ~ñdYÿ;>ÉÈè§ ÔB†K…yÖܯ{²¾îÉèTû|«ðº`§±(”j¡®Š9Zèq^¤§¤È½"Ù«_1ÇÒ¯¾oüpléÚ*–¸švaë°ÂEU,逕¯¶¯ÓzÒ{²| ÅÄR>|Uô¡õ l¨áØPÛ7ÔæÈ†Âs¤[ECm“‘ôšo³Æ#[ü#[\§ízŠÖp¦ÝmEG"ÄÉ»ÇêIòÄÐåz+qZŸûoÐD ñ`vä_Y=“-±ÑìX\Å:ú¬Ü‡Evœ…CsÀJDŒŸ`!®YÑ8I…-ôœ¡øÆhÅ~Œâ›¬FîpíC‘$hÇŽ£AÐVtÄš¡%iÖU*‰ßXõ1Q!^íR8ßM>%f÷ñ`ê7³ åhµ%°ÊÃpi“(ÃäkV²„•f—ÁÈ­D€©]·¦õ„Ë«˜í&„uUÌ~ËJ˜ŽÛV4¨÷¬œ[鈮1Ö ÇVâÕ±[Z‰ÝÒÊoZ8ݲ ·É·­‚åòž•üIü˜<š¬¨b®€|ícB°+/´é#„"u—®u…0´6:>Š— 5Te1^ÎË8dŠå#mdºt«På£l ùå”k4^ÖR®1x9sññ6l²j¯ôXió{\KQB|š±!Ó„F+µ!Á¥K”>ÑæqzbhD-³åÎwgÏw[¨x9.á]ȤYW1H£9¯b‘C³¯â@³Ê†Mˆ@s†Ícø5¨Ñ{VòM¡uÜð¨Ï¶áà;A'ÐŒ[hãsmH 9×àóà&Ÿâð€Hš mØ ñ|zMÄ×Uâ³ðuUOâë$%ºëŽ_jãKmÄèŽ\™ñÕ†å»Ì†>ž0.¡†ü(×®lÈŸ™€šXdË옰´­ÍÖÁ–È×ÚÐùo†«Y—‹þ{Þ†‹Q…º°ÖÝôÂÌ)ÞKœ‡’WAåŽû@ºg#âòû6š¸•6ê¿êC”&ìG®©bÖ6M÷¶B;ç¶n ¼Å†Ë;¤Yà7lâíÆM[×~ǦwØdK ÞlµáÀ¥“ñÞ³Ñ ÊF\ >²uƒNÜm¼Ð®'ö¨=™x97”¼€+ñ?‚~̇Ùõe“è¨a‡q;b”Ò"ÆöQv|g-^QÂAPÖh»Çö¸ƒ@‚±v¥S¼¾Ž3º>Pôž©E0½â8ŽSW %I¶Ð¸ŽsšŽ¢»Ÿa§YUÄì“ì|’â±ÿ–E–…#X9º~÷8D¤NÅ?EO6ÐU†’ƒO5Äô8ŒAn(DLåá·C7C'ž ú+rû]¤…\Ê Jü)Šx<Ã1ÛÎg£/[&,‚A¹öÙëuêA|®ÝÅ8sÊÜ$ÌŒq%œ„Ncsñ…(¦__°¨œÅ˜Å¯¿ûµÈýB]¼>[ B÷±Xî“=ºÁI}÷+»Øgy¦=z#Ê­¬b–¯ìdbö¨ÏN¯Œd¿] Ç×Âp|ÂuнëíÂm€Ðöèa÷üÚ~Ä.ìÑ&×W1çQ»°Gã휘vî³æ¨ßn Ë0r²“9Zo'sô°îÒþ „9zÂ.ÌÑ3v²'ÛLsôk;Ú“mž<—5ž<—sBæèE;™£WDö€iŽ^¥ì‘ý\ÎÙ›árnÈm±ëÞm°ßØ%×Oí­ÑQøî~­Nü^„èøß×E§aó!\Îr'â›ë6¸œ‡¢ó"‡Çž›dn*™o ì¼Øzk0 ’Ñ[M òvªó(Õyœ#dAwëg²ãñô˜àÊdAW8„=ÅAt¥ƒ—; ºÂñ8 zŠã1t¥#Ú‚žêÐ-èiŽ=á+¸ÆfAÏrÐ\š+ç8„õRfZÐsdƒ• z¾#ÚþZþx ºÖ¡[Ð ¦½Ø!,è%² Ašöô G¸½Ú² × aµ°Ÿ, ²›· ·:rÏ}N· ·9Bôê0 z§®ŠÙæø¶Ëar³C†ÜnÇc-è`Aû i7í‡p3XÐçÜç0öY{Òjîw´³ ƒz:ä³ Ú7ÔáȆB ºI4ÔvaAu}܈ YÐ'Ÿ¢5´ O;BôGÈ‚>ä³ Ï;Bô‡iAo ú’ƒ_r„,è+Ó‚¾ê0,hª@³ãI4V|ËcÃñX úŠ#Ì‚¾ã@6‹ -F³Þ› ƒ`4Šq¼;²Àôá  Ë`0DFÀ†9Ñð†;Å=Â)Fè‘N2<ÔQN2<´ÑN×­cœ|ˆSiuÛb¨3̶æ¤=ÐF|c?ÊÙ ÆÑN´0Ɖ=а-l¼³4Æ÷@Ó¢”òCj›ä|rë}ŽLhNôrmlG‘e¡ñr'MªQ9Ðê˜âQµBÛè‚»Òé±uÃoD8°LÅ®†îIœñSì «‹˜­ÚÉ«ãéÌÈ’°]g9‰£]DRóÃ<ïŒjþ9¡dFóÛù<]HÝhùgpÂçAÒqØ‹AqCC6…fØÖMa_æäË@Ó(a<dS¸L9SÀ¦XæÌt9ɦpÙœ|³½Ma6Å:ÌâÂA@°!f¨`Cì´QïÛåDÐm¸‡iï6ÀÑìˆv+8Ú¬Aצ†±£«e·“œîqâþ¼´×‰ûóò>§phºŸú¬ú•“v’µE.¾ûP=ß#zß^êQ|ŸSì6íwâÎ3™*ÿÊI“DOÙBŠÕçD Åæ‡`+,[!Ü&Ç]'÷Q61c¸ªHÖ´Ç!¼žá…èî«Ýe‰8¾çlŒ7]Nz·s؉ïÖb¯@pa<‹ãNÞ€yqÆÅñ÷`bxuW»w·1¢¯ãºè¤Z Z±ñŸáÀž>¡]ú· ÁY3á'R×ç8œ|íôĆҋÛEt;¦ˆJ@3à¢ÓcÏ+îÿ²î@ƒÐˆoôâø7NÑb=qb©ç-Îܯ{zlô®Æ‰ŽËðÍçÈ:À¯;=qŸãꦓvôcq‘%öó[Q5ašœé†'ÕÁïbü,wØ÷‡Ñ£ƒ£šG}ÿЉ{s øqb›“LÇ….4“ª!¸<žuœíâE.ƒ†ú¡.@Ä]®^Œ—¸Ë•ÈGÀ#@æÃHŒÃí®|4­‡ÚµE¢Ù%.OLäèõu®4\æ‹ttÐ:É…j­5ýM>5ZY8pB;`l´ 3Ax£%|Žo¿§¸§í8—8r‘ruªÀs„§ˆ`E³êA_äÒGõd¥kOIœfYìBKû9²Æ!k F1’@1â–bœÄËex){¼®ƒkNehNÄѯu.á£÷ŽiJ³v)6ŽõlpÑÐÀ¶¸hÁ±‚‡Ã˜¼ÝE{Ó;0Öª~é¢ÉMÛí¢£aÖ=.¾Á¥äÙèy6¹zó-.ôœÊÙîʽɺfßd¬ð&¾‘ùÒZdh|Ë8 fã{]hTwIÂá{Ÿ+â\-MÐ}˜Bf©ü ‹6¿ÇçÄl‡\ÜOÀ´ÉMãÊàQóƿ걆 ;¤Ç›GÂì¼Ø8fׄ¥á‘Wô‘°Ft|6µÝ¡°ƒ.ÜU÷h vD“ðGhÇs…¹;î êvo0töã„‹æÈS.ÌE9Ó`öhr ÷`[ê¬Ë :ÒͿƞÛ2\ÏiÖËbÇãÚ&Ý(ÝÑ6ѺSsÚ°Iá¿þ;á¿ þÇàÆ}¬˜+º€ºñO' lnË7РÓ2 Þ“šáï›2wá¡´¸pŒP¯Cðcí† ÷ï­­.Ü¿·Ýuáþ½ýž ÷ï÷]¸ï|Á¡ÌõÈE§c cp–ˆ-‹Á~7#†Ž&ñ{o€-‚rñ¢|SmƒÙ¼íbãÅ"é3é°PRèLÃÍ´v>R¤m5ÓŽ2Óª|´™ÖÁÇŠ´wÍ´ãÌ´o¦uò "í†_†Ò–ši­|¢™ÖÅËbr[üõóò˜ ¾­@V#^ƒîmø”t]ãqe·0'N‡q¼2&à÷Äa§¬ŽAǸÂ4°C‰GwÆ51äí^ Úú‘!>3Æã*KLAö18»&àôìz`Zh™PPìæséž'ŽLñÚzO$À%¾ŒƒË+ñ‹ EªËYÂâ¾(&ô"+/Áw&„»,·ÈÍë螎»p@²Õ;Ú c?<{йøZX¢u!n×u1ž¸ÜXncYþn¾~z¿€§Ø…O׿˜°Gk;žLÀ~xHÆS[crôõÄdé O×®ÊÚ-ʲeí •µ/¬¬Ùnþ–5Û(Ë×¾,?šeÂË:>Yê®A‰Í¨¸Š¤Ä¦~,m@ÒÑñ uó“tO×ÑiÀ"¹ÏBì8·Ç!äîÀÏÅx:¹Ï ¹; ÜsÜüÊ=ÇûJ¸Ü»ð™@Sî«ár·ÄÀ<ŒeÝe9²n…ʺVÖ\7¿‹eÍ5ʺ߾¬h–õ0¼¬Á±Wâ 4ŒÇŽf&ÄÒÚ'©4–‰¥²]FÙűFÙÃbͲç¹ùHøég”=:¶]Ùc ³ì±±aeO9?…™¹46´JêÈ'ÅÒÈždŒìh¸óòX|“€ï*b}ÆÒ©#žYáæ•tדDž‚Gˆ¼~09Œ¹uz,R fJL³þ„†ÜY±¾t>;Öן†9B‹ÏÅžºysóùú aä®E”Á™&Q¦” ¨cÅ Åm±x: Æàm Å÷þ}S¿£>’1˜ü’‚ÁUü»b †ÁÊV V ´a°z ƒ5¬èÄ`Ý@ëÆ`°a`,Æm‹å_Åâáz¬Ï_p¼?ë œuðúX_° ÕÁbñDs›ƒ7Æâ‰æ€ƒŽEZý~.¬3Üü\Ø ªÝü8\Ø jÜü\8 fB÷‡ gÁ,7? ®xêÏÀEL<’gá"¶úø×pWð\Ä@o8*’i2@Í ó¦Šj‡žÒ‹3ÑWê¯|âŠËmŠô•:‰|¥vÓÝÕ±¹GuZËÉÒË-â,Þ¨¸Ücá.TËQd¾È1‹–i:Kž‰N9ã[¾„›ß‡†GaxÜ‘)+V[Ýø‘q”õGâDÜÄÉÒŸð¿É-uÓAÖŸèGGL[“ÿmoÞ3w‚[?¼ú¶Ï»€¼WîD7þ C•½sKÜú¡Ö>H¶˜)܃bï$ïçV¸ñ4Ò-f¢ÛËïÓ­õƒ†ó_Cã.póÜpÌ4¡ç!Û"ªRû¨òKbY9®ÊÁnüÿq¹ð?VÇ( Úc2‘z&]§žI£ž9ð'öAÿõo¥}õ§‚õo-ý·þëÞJ ¼[°î-ôA›‰ÜCoµìÆgÛ £ÓÎŒÑig0Ü>PÃ(Y‰A4SJD3µnA+3.S…žñ%ل߃la¹sLNŸ·Ö=‡¡OÕñ™‘ ¦MÉ=aÉT`³Ïå`½J2‘Ñ?I÷8áî¡gÚ®Ø~¬àÈLÈì¢Ä'LíØ²Rw~â‡[}É jø·Vóù²¶»-¾¬/ñÏ>üãÃ?_㟋nƒ,Åt¦Vï6¼GÐÏ#ÆÏúyÊøÙØÞÕÚ³=8˜nÌÚyƒüGbYøíA<Ö#Úƒ¦Ï³·¢<“= »Û3êî£&wI‡¨»mO½{ç©w[£ïö³F°¢Ô}LÕ_ô˜êŸY}3màÏPÕí0eØ¢D¾=0ʉ[ØÝ»OÍ{w`8 Œü”&úùS›èí§6QâS›(úî½°»/Fݽv·³ÞD®ˆ&Šfú ºè3Èq–Œe,…ÿËFE“ãü¯í ÿç>bIO}Ä’þ´½3ÒÛÞ. ÿm—aÏ3{j«õzÂÝ'åýß:lþßjÓ˜È!WoÓEÿ[ÚôÿwÿÒqwÅ(“•Ìåÿ·=íÇõÿÏ—z›õ³ ¿[¥°ˆO@Ža¦ Ž€Ínƒ#`³itaŸÆ0‰"\”ç _zÞt3¬áø„ÎùW`aÿµáßê‡Â¿Õ›ÈÅ K ø„=ŒýÄXýD¬~"ܶþ-ÿÛ·­où¼ÛÜÁPÿ9,6·¹qõsÙ…±ùœèÕ}¸Š`È_ Ýé-ºŠ}бŒñã>ïy¾wÇЈ|×ç½ G^EþÒ罨G^ EæÞ£ÞGwî™ h0Üõ(iÒŸÜFmDQÐFmºëÑ èzt‡û[ùy©È”>Ü몯{]݉kƒ]nÓéè’'ܨžA8†yIøË¼ä¦²n…¹²*Ÿžõe‘õ‘õ.dý&”µêIZx‚×C »ÝßÊEíÔghajao˜¦=¡*ºÕ΢*Í¢* *Í¡ªLRÖ¬ð¬\d}Yy(댿P û -3úÂ%ÑŽõÃmÀWü÷£´ðÝq’PÃTÃWøç èBÖuQCÏxò“šUËžíãÝaÐ̧'~•wÑÏzzâ×01\‹Ä_ü…ÊñÊyºÞÙÿ½'v‘ª%ˆ…éfåzóIýDè&I÷1+šü4yK¨Éç>àÕp€ë  ®‡æ=A‡:@¤çÿ…:lpë·Ž:d½ʺ²þGÿeèi|dxýfÄ×ä M9¢øšV³´K¿$Š[sÒîýöIœ˜ýg8ÂX1óLRÌd‹Ó"7rûej2Õ‡ó8-rGñ8ÝnÇígB-F¨-&Ôâ¨ÅÑPwÚqû™PKj› µ$jI4Tk$Ôvj)Bí0¡–F@-†º µÓ„Z†P»L¨ePË¢¡îEB}iB-G¨Ý&Ôò¨åÑP÷#¡ö˜Puµ×„ª‹€ª‹†z µÏ„ZPûM¨P+¢¡FB0¡V"ÔW&Ôʨ•ÑP"¡šP«ÊgB­Š€Z Õ å7¡V#TÀ„ZµÚý,Aj B2¡ÖD@­q?Ë!z½ µ¡L¨µPkÝÏrˆÞhB­C¨Ã&Ôº¨uÑPG"¡Ž˜PëªÉ„Zµ>ª)ê¨ µ¡Ž™P" 6DC„:nBmD¨&ÔÆ¨ÑPÇ"¡NšP›ê” µ)j“ûY.Oã®WÜ»ž³ÁÁ.üÿñ”»— ºqÐ3´žµï·ÎÒþcç–½0adb‚¹ÏY2é×_ùüï0þ¤Õ£íË8Šý_:ÿ½ÏÛŠÕ<s¤ÕÖâÿMß»ü7þÌR­nþ¹/tj¶à¦›B=ÂI ô¸÷WÉ|ÞûˆtÒèNµá#¯šñ™èï¾›Ïb‘h_gÍ0¸5·à"Ü¥0¸-ÜòEì/xèæÛÃán¹ùbª ƒ;p®0YêÂà®p×çW˜JÔxáp×ÉÃf¦MµÚNÉ” ™ï^+ª­¨áµ¢Æ×Š(¼ùrŠR-|°Ô¿NB®ô“}ó¬!ªô\kÚŽ®ÙV&ØÒy‘cí"¢ NâC¤¼:)Ùâ=ÕWÏšhfML¶ø¼mîìDIÏ=TÊMÌ;ÿœÏ;8Õç}7dd^oŒçńžŒr/ e˜òÀíóÞ C%åUgr'ªHu¿^*K<‰KöW1Ë©™¨bl,„_U1i„«˜<^âc0“·æPM(¾¨ž¥ˆC1zDg¤kLjF>ÞH!"@‡%’?op¯…úÑÙ\×– 9üÚ2ršV*å6Ť½—ÓÃå®ß¤ëÉRPÏJN²=/íó(‰1Ë)è(Gý˜üý˜*ùÞkˆ±ðiH»v5S†–hÔÒ³ÉgâÃ÷-s¡²÷ßgó$$Ä‘æKHˆ#/ø\¬>ýzm¾µ‰W bp¯"Ðļv îG&hàóÛ%𽑠‘/h—àî  @sK%è°ØKè$íºAÄ Nä¢Ä#Nç"?hä3zQMA››¯ Ï”x“Ia™ŠôS™| „¿ú᯵M­7Ã+xg]ä°‚þ›^À$ëCmîÐÙ2…xø¡×Æ'ÜÃS©›%_ׂÛnäOÄg–>GÚ!ùÂËÃhTÅžð:„«¢-L{QmnLVcÀA‘éž©Q¿ˆys7 &€0≪)¸çæ‡Â3‘F¤°L!6FhôpÄ£®Ñ#‘wž¨F›¤@¤Ö¦F=ájôjôŽc`Œ&ž i”ÊÀhTÅÅð:„«â^˜*.¡*î‘*ªqÌÿ†¸éœ ,ÃèáJÎ=òÇ´!&=o=ýÿ¸Rt¹á¦DNdBÌ´³Ø8ã K|ØA—»/±„þ{¦5ÿC·´/?ì–vÄÚ--øv·”ü‹xX„g"m§Ÿ8Á’N¥DgJÇWZ2e%.þ+FñU4,Á,ÓX3;ɦC°¢”I3ŸÆòævöžÅï¦#û*þš˜~®ùùç 0Ñáõiü à ôhŸV:œÜ~äméã]üNžÇúm ”|måóYÿÓÖ`²% / úsü0øyÁik<0-„ÉL¸ØHˆ®?Ç ¨Á„|9ë?íå@Á´—y¹KÎT司å¢^ÂÝmýDfÙ j˜È؆¾n•¹ ÿ¡ïd?Ñœíb½ùn Ö§½,÷ž÷L/Ÿ÷Ë—s¿#ñ},w«¤GLíš³U’Ñ”_Û™û˜ŸNû`“`õ¿bõƒ¶ ®Xy#ó‡ºåÍý…wÞ/r®ôVøQ–»%p GÙod*Ð&ÿJ¢_$Ñge[.‚ä“?b”3é*ã—YÞm+tzš§îXËp°çWX²¥¿Ê "k½Ó)0¨f¸Æò¾FÕ¡Ç[pVÞi+ü®™Y$˜ŠÐCÀÍLÕ¿B¥’oBÉÝðc³Wècw˜‡3Ë](mWv‚ëß‘@°i8“Gã¤0‘)81nÎTœ· gÚx· gV$½=0œÙ&Hüv{©Qñw@ñw ™¡‡=Œî2µú„<·ó Ä_à„|:Ó>XsãY}q€¬ úŒh¨”·¢W²jîqÔˆ¯UÐ!&àþH n¦FKØ©`V+¡P1£ÛÂ2äK”£b …6>Aòãç\¥~¨û/ø­ˆäQzà·!X\Þ´—a2žörõ,ÿL¿ññW9ݹmõ.Ôÿ{•/3^/AŸ /C xåÏ?+Á¼ƒôˆ™ÈLþ'Ñí%ìöÍl tö›ÐmÀhq[âw(ï ïC šzË# T<ÿm’ŸZmqœwâÏ>£Þ—¥?û,ëœÄ²Võa8. –AŽù G‘lÈ1D6­¡Hz‡ü?#eüšžù¡Ì2Rnf þ‰”ùhÊš…ý¿i"“ÆÊ|¬¬Ë0Nöç]±Æ>U èÜãAŠà{+^–x‰Üypýú5h SÄJÙTÄJà((b5ÅŠØ$ç]ÀÇf³Üÿ‚Ub‹RÄxS‚qaЏ`åÛP7­ ©_uEì@ŒÞ܉rÜÍ”AŽþ$Ç^"g÷Ë^bîØ^™ï—ÐúIß· —+\¥½“zÎô‰¤Ÿo?}ôóÖß¿ƒTÝÙPÝCXÌ=ê1ߣbš¨ß»–& ^A.ìÚÇeÈÅćCù Ìu?“A®®”뜑ëœÌ/P.üJü¢,¦K˜ü,¶ââ?¦äÍFòf™·PrtKyCŽž ñ#£[&¿u»/ÃÄ'¦T1°Õà¤÷ x˜)²r©€!ÄíYùeˆ´Æ†+¼XÁî/3>\ñëûøÓ*?¨žÐ?¶õcñµD0Z1ª~€±ã•óQ¦ìˆ‹/’©˜2I¢? u`펟lA•Ê ÄM¥ŒU@¸l†–ÃÜ0Âm¥L™á£"¦Î‡pøßi ØQʬ‹^%âDSñç|ÙÇÂgAÊ9Jл«IÌSC0ôÄÏ`4_¤à°ízl…ÚñÅ‚7÷Wôi×–Rf[ K %£tg —)&çÒEÔ)ô½—JW'W*<Þ[xF_¥äòÞ,Þ›å”þÂøD‹«vœÞÖÆ×)+¢ë±&¹/æ½è]÷Vö‹ _¤ðzu6a[´Q‹ÿŠšb—¢w©]ºþw+|·¡Ð=OV(©q/(g? ¯Ë¶ðJÀŸ37‹ñ¯°ˆÂh7j¾ô¼‹xcptDð¡n?þ1÷Lß§½Ì9gàÿ-kzÞ¸—ñÿÇU‘ æ à Ï:õP¡¤°w_²ü¼ÿ¥ži%ýº¥íŠíö‘” mØ!=Ä¡+eŒÿœÎ;ã‰|(!!Ö'bóª\ùgÑé[qENèðŽpÆKÎwõl舎 ŒM5Ž Œ……߉DœÂ|¹Á»ä­Ò²ƒJù'1úgC{äú°·…Õha’eXv'U†S*è*hDг1øŠedг1©áoÌÆ¤FoD¾ó…ºŽ{Ï—žûõ3µ\ž7/6=o+\6|ÿ<µÝ;³Ñ©¨h\{ke±(àÁZ¿"õA­Éü|Ñû —qõ°¯ã¡\1 úÈpÌP‚mQ}ÂÓ›î 3 ƒaØ}˜Àÿ"> #¥Þ|,Øü ©›TP’Šº”¦ò1Rî>-gŸfA— Ë„’dÔ{<áÝa–ñØ‚èQ/ŒÁ¼[MkñÊŸÈV!ž‰"Ajå,£œûºZ¦ Çl†Ä+H¢.d3UJ¾.9“RaU¢MǵdIj·¬Ù©Ra§z°s_óg½Æ _kàÕR€èbffA†9°ˆ}ï>ŒúsA(|õU’š3?UCÑŒæKƒÑHIùk1ïCÈ»…žØCQ\1K„ЫÉ[ƒÜ€Žx-«AðÙÙ «!m”À"ômŒ•\:ÎîÔ¥Ö€ël?þð–üb)šð`.vé!Æù³&þ‚¡óúP$ÔvjÄ7¹¯¡r$ÿÉôHö­R0$û6”=’}{(ʽS B³Oê!ƒà3„à_àÝ@ìõ£˜%†6Œ÷FA?è+HòÖ°z°ýº¯y?ÈŒ^šû¡½¬b숦#êåÆÒ$åÎíƒÊÍšÛ‡¥‚‚ŽJµ ü¸H|A¼RÀ›îÆ´ú*æ=×7ø–Å&c¾S’/gr*úd@·è=d蛄 ×Œz ÔÚˆ„bç(má ¼Eòh¥zD¾ … Ìm)лØ)Võù¼•©äýùž“;yÁÆê8iÜßg÷ÃÿÚ2šÞïƒ S@†èÔá–†­?ñ¯åVöy'¦’–‹d?^:}<Ì'PöñbÙo¶ ކHoˆç,> ˜Pz[˜•JÞºT¤òI²ñó탾eqr(Tè:v° ÃBκT‰Aä5=dͳE"‰F«hÖ'[ºàx2VEIˆß†ª>NíÍK nQªþ\à¥î} õ(%vV¡òRäKS0IVQ–%Y{³YÑ5>éVTòú§õ|¢ CçL:KÕLUI8×ÖfSm ŸL¥–€2¸^¬_WÀõR,râ§ ñid\®bR¥Ê+éNÖ¼,¤µF^õÌ{m8 kj`kC Ùòü¶6ò³[mÔlâ§õø&ÃÎk AªUÿÖz¨ž¿–åª>/ÏQqfBs^åì·Ã,€W4€Ô¢&gRßK!E®U±óÌîlY«òõª¿Ë HŵAõgïké“öåùFÏêõPì®˜Í e9¥bo¨d] ;#Sâ˜×ˆpNƒ–`%Z9,F0ËEÐðôÿd—Ðï= ¸8*ï³¢/ÊÏ’öp2´ÙãcÁ@¿@ŒSɰü+Y~Nű›^EœWÃnöAâòGRaçz~IÕ§ OøÕŸø.~<}t~Ähªbò57ŒbJ³Ší¯¶¨üªEÌVüššÛ9»³«Å›Õ¼ÁNï˜lªo¡Æ_¤†¬L×n¨ü†êƒE²,tB.QÕc5œlXÉøÆž|K_Jå77œèËnuPb¶ &GæÃa¿/®Æ8ù¸òX»e•¿Ãò·Éü¡þ³~n—ù#5oö;“U’mñ¨9²åx$ï.Ò(ryB"~Õõ!Ä¡âWù;,¿*ààÐü°P*ÍfdɌԂ¾!oQ…»¡èXc´`Ÿøwð™9ZŬ%/Ñt¥¨mð=“?^ªÁb2çŸë ñæÀLÔˆkè‹ <Ä»ÄC¼”ø³;A?Z€|±Åè2zâR­™ƒYC|f–k|FCF\¶ŽbòoÐ|þ¬¹Ï3ÊÌ·@Åè•üV ½Ãô±nükhEhè*NßbË{­ŽX¶kÂc>~_jÁ2ÃEõŽƒˆúo·†×: ßG)@Ôþ0¨ƒ”Öaƒ²¶cŠ_ã!DB('ZA-ohVÚü!,í¸ðH ˆÇ ÀúÐUÌo|“®ò-÷ÁÛU°ÑКÝCQ]1“dÒç9M Óø *øèY[±«³¡V~A£ÈE¼Übõæ×410GŽËh:4ë©Z´èG7njøÈâŽKá·´°1â,€VëÐ=S=Ô Þ@€ÁVã©­çC­¡±®AŒuÅV_€Æº¡VýÏ_†®4ŠΥòéQ„‰f”ç#y´•ضgw ƒ³‘&¸€1=A'cÕ;É8«Ï£‚hrÒP©QÎD«/ÈY sÎë6) ËÓq"[aHÂ=ÂM±úBå‰<˜Çßñ ¤®Dfä9=ho‹It¬ù™ “R‚èoæeMê ÄÆQÛêë†vÄ| ÁZn5VuVc<_eõåÌ•®†p„ë­˜wÏȺNð›¬ýïJýïHÉw}ÁÉocw%¾Õڙܵ`™ÌwY}ïM–‘Ú矚w¥ç¼D|×¶×ÝÚø@ì³êF‰ ÜZ(×™KSŦ – fOÐ*¬Þz¬ÿ\ZWˆEàu«¾Bç Ç0ØùwÒu¤a4>·¬½ù]+Ø'óÀв¢ä‡&šõ¼Œ4ËÝ0vÒõÎ#Ëd°PêX›Ž:ÖF¨êX/±ù}ù3~Á'Úüy¿¯£ÏÝ'ÙrïÏú= ä—8x¹ˆÇ×az¼/˜5ÿy–_êàUpó}ãI.,£ìSm¹ïûÁR æíç¡(óÉ$ QæÙh4Ã'¬‹y ÈIÄ0<5„IB/]Á™!L©µñ6¿Äô¡ðZdˆ^ß ycÙ<ð uð¢+ºŒ%·¶€÷bß.I¨ëå¶ÁpÞʿؗ×Ñ=’s©/‹Çiu5D\Ö¯ O|¹/_K÷Db¾ÁìÃ7Ûàa$ø^›,ñ-¶`2ÃÅö‚ŠË3LÌù»ôʳ,ü·S­,{õZîƒð8Ôò„'†0¹ÉFC·r ïaêqç9µĘl=iã»m>½ß•Ï+ŸÊ÷ègõi€Á÷Ùº¤F—$\5°EwȞ‚³´ñƒ(ŒGôjÖÉðjöé;÷AµìÖ‚Tù³zHˆŽÍN Çf¤¤CTò„Æë#Ò²m³#›j­LòRoáó¼‰tWø<4Øq$ž°ùÈ—•Ÿ¶»tè‹&­+ÜøÚ–÷_ƒ9% ƒ²-HäSV~ÞFo»bmA F&T)¿¥«ÐþÏÝ>«§V8o£·†ÖŽà*tŽ.rqP&pNÊâס hG,ävQÊ-QJ7,åŽ ýÂÅ´FsË(ÆÅ<€‰»õ™Gzë\Ö[§Ð½–#¯Swg‡±¬ÄŽÃŸ`ZC8¼"CÄBZ&v&¦]os‹hH}1€gòéaž&ž Ýv2êéù©·óývlWd&âì¾¥V°(™ŽÁÒ¦[Ão-Nå‡ì¦^o‡™‚:G#Y'ÁZò ”ÂO–N½=S–ÈÛžl“x£Ý4æ›ì¾œrÈŽbÝ÷°Ù\1ųð ‰ÙÐM̳HlvË©*f¹…”Éð4Üð .åÞLe™ nïÍoÙ}YËR-ƒêù¢$ÆE¬ñW°÷Z=ÚëŸ6 )?¢ùM)rð{$W ëöÛ,¹­ƒ•xƒã7`CÙÛOqm"æ_ÎõMáE½a±q¢‘ô¹÷Anr‰9Äï'ž"¦ ï×%¾.ˆ…•nù÷{ñátQ‘ÍG:p=Ùß‘¯u4ÜIÄAj¬×’µ,¯–yÏôìÖ̓NÁ²k™FëÊq_îk`œéopîØ3­Z‚Toµi¼ÜÑ­‘W8„>‘>›úà•Žö­‚B ƒ[ÛúµÁr6ÕÿS¢†¸‰ÿ“·÷êºÇç¾23Æ;qKäDǼq¼ ’7Énlƒdɱœ0æÇÆ;’ã±6kÇ8vØì÷m¼B ‰&zG€èB¢‹Þ;ˆ:I€é½ëŠÞçιïͼ‘„q~åÿ}Ò¼÷î½§ÜsÛ¹íœÌT (9q"Å(ü¢4“äNmC÷ Ýn™üm[ϧ9œ8èŽs —ѹœå‘r4Û!À ´Þº€ÖvºSÝXàÀñèT†Eš^.vðE}*uo±uÒ”«)8˜‚šòb)çɸ0‹:¸Ñ/¤v'ÚÒZ@Ï×CŠíQaãþ÷P§Úˆ Q£K«˜°ÆÑ¼ïD¨Qµwô€ÞƒÐ‹)_tÈaÜ® 9Äõʃ×:rÉÙƒ }} x±)tÀའ=?äšßnŃ~æ±L‰N8„:xÒc:$>Ä«iFúK"~ˆCpÏÁñÚ®6ê+Œ¤~‰Æ‡Ž” v x±¤ƒÝ–¸K¨Âããý¯µC“ƒòGVB6>¾ïË>'ÀHEÏ×äÉñ|büwYÑ,‹z“ã zTËã)W¿Á‰æiífÆcƒUgÅóiñX‰¢ÁÒFßtBÎÌøvhÈ:Þ´< ½zE|žòT_ôw/úcåb¡¡U㙕¹ñÆê±0€Úb£œO/÷»àxÆÇãÔ”ÖZ!Mu|[ ·Lðž§`}[o4ÅìÕ õ®„ôJ&¨ã{}lü6@îùN5íÛo÷Îù ΢°’¶Ù•¿‘øžøÈA+!=Ãyó²Ó¹7žÔmtåÏSIS ÄG;‹ÔY‘Îb?@àuª?§2½¯¯Ã_ŠçWâ¢Âu ¥ŠNÆ\O gp.rŠÂÇ›=h¯†Û€ß77Ð>æÌÁñí^¼±vOb-ï ASøg铠ׯ> ´ìÕ7÷Mˆ,{}ZRðiï— ló%¨Zãž×ŠÌÌæŠ‘mX‚±\ÅG$Ä.ULèÊG'4oP¿Ð—©Æ&ð± ©–zÑ+*4/ÊSB8Kð²—CùŒMøGE~ê,tRŠ]vv@È30•%ð²„Ȥ…O4µX¼q|²9)a Ÿ¾Ï4äz%5¢Cb~¾˜¸þˆ?bÇL³óÅ 4¥ÄNÎ÷&ð%È=óR| fŒc|y Y‹Ÿ ´âÓy<;‘Ék…µÏu |m‚>ÄMÜuœå?Ñ$ÆTuCß@ òT<Úòܘg ¶Bƒx›ôˆ<+h®X½× ˘ ™³ÜJ"¦ZR²v‘yM‚˜†îL0¦¡» ö‚@ŒÍ‰}@ˆü ´<„– ¡ÑÏP0@[ÁQy(Á¨Â|ÄFêpNª>BêÊxU{\Bb•è¨.“|á]ÏØI΄œñQ9–IýØœg䡉üRDÜ—…¸¸Z^ìœr>}ÚÑy«7HÞÖ› üzBjú…Q±[ùM» ݨ ±Ûn'ðÛBº6»ßIȳ©K»›gû ×2îa(jü¾ž<Ï>‹âfÂ&ò7õô\(Ї 0Ÿ “m¾Gz™¥2²Äû%ã;–@q¢^kƒI8ù,‘zÒ‰ºÜ&z†YèƒC‘©[( OÝJsÞÁÔ-§nC±< ^ÂÓØ‰ ¹à0?<z@RKF&ŠB•hÚèD(´Õ´puF4ç ‰Ø)ÌyÆ2!‘ ç¡1”Ás-L&ÁsãP¦LNäe‰_?+.GLJôö‘éäLÙ7¡®,ceŸœ©@¾Š”M]ò”©_¢éëòÄŸTòi‰þ@ž:’´öé‰]ù,ÈÄÕ47Ÿ˜óEÈý do†='QïÝ*zë‡e+ŲU‚XÀ*!EG_å©‚Ü^‚<Î#ôï=ìó1»k:X¡×üÊm5ä–/MÄZ·ZF¯ÞRæ;÷k¿o]ûvèŸúRW•/Gȵ´ñë"È5¹N@>Mö7c!éÐå„Z×A~gP°÷&’‚Rð.Ú VhÞIF{¿F“óõÀ­ïZVÀט•½ZåDç ?j ßáǧ1üœ)|„ŸOtîÆð«"<Õõ#¾ëYÙ¡m7$:«0ÁÍD±}r+Ql›ÜN4Š;‰Î˜â‘ž"¬§(H2RôIr~B.¤@ ,Mâý“ü¾Šö¤tHÂlðÒ$Ôÿ@mmÓ& MâC“jïÖóaI¡ä7Å0 HÂáG™D(g~/äÛow_{—aý™„í4X}¢7 Í(ÂI¨§*MBíãRÖ0h‡c“œ»¬s;Ù) øÊ^€¶LôÞÈòÍtçYŸCo'ú0ù†ïfé̉üOR`…‘Rrz…ÝP¼i¤”Y¸‡I·Œ@…¦ ÷)ð¶¨Ò2m¿$ ¼cZÑ3Z´NµQ;åûù߄ö¸Gá—…þ(ü›Gá?? z^ï¸Þ†æ×Ój¨O,·‘‘ˆRf™¢»ZÊ>‡¿/MM"·MÓ’øT6ù8ž–„õL¬êÍH‚–€¢ æ)å´ª7-i“Ò|ú™“äÏ^Å]‰ä6¹ÿŠ„ÜÜAn‘ ·8‰/2È-N „rÃã q|I =ÜíZœ”§lüˆŽ-}ÿÐ\©Ó\…47Ò„ùM±š¤ïݬ×Iâ“—2i}ßhC„nSú*ÇŒlÖmAD›ˆùÑ¢C«‰p_££ªÜïÜïNâ» îwëÜÿ¹ßkpï»ÍÀnSAæü†"—» ¶Mò[‹ìm&Åï9âî\’ÞÝžKâ¼ ôÓx—•VW…f×`$iHâIhC[_A¿`röm±l¥Ó¢[»m€ÜN¢Nüv¿k†¼¹ÍD,l@†“xŸV&K1 ÛM %­t5²¤`¹²ÃÄßÐV:•¡­ˆ¿¡­øp3ä•È‚ì 6Ø òj_f   0ëÛŠ7Ã^Ýi‚B°!€°ûvJ+>Õ Û» O2Å¿åGe&±œ+Ýžpð_{LŠž_Êÿ‚àP-Ú GR«—uƒ˜/÷¼ÒI;øyw–¥S;ò5{­çÕNZýçÚÏ»KùWñÓžO±VÎÙr# Ï>ÖHæ³~¿{o{4k‚?AüÙßÞÒ]‰šÃljá²»¥©ÕJ4D5´·G3ÓH¦ØÚÏ£±]›ÅîÿüÛŒ{íÿ¼¹Ñ%%†™êÿ™ }Vc ZÆ2ƒÖMÜ4³{¨[ÿY“½¨½ð,.Ú‹%&ìEí‰ÖÛÓï;Ó©DÓ)­äýîj~è2û¿f®ž<&H1Çž•\x7ZWR+‡ÿµ?|ʹ¨êÜ€ §óé6¶³<Ûx[›wXFÀ×€+ß7)ÖŽÉEÀ­ÏÈÎä«Hˆåk«[öc–R ~Æð!&‹‡ Ž ¥ßa6ÿ–üáô;ÂÖ²Fõ1ó»gi])&A¢ó6vJióc‹åc–3"C;ÚÝ="ƒ!þÙ§¶Wê´ ¿ö‚)o±ŸÚ%HêóF‡7ovÀSûð/eÌPuj£2ÄK“Oߨ LìæÝX®–3&6­ñéƒi%J;&Côoù5²¿]~ƒäÿI_F¦ÓÿG˜Nˆ£Æ#5$Ò !áZÈ(™B/ÔtSèŸ)zȸHˆÕ/?Ý‚îø5$=õ…1 êí‰Í­OCnT4TªëÕÌTé†[0k ŒlPÖ+b¡=Ö6õÅÿÿ9x¬ldÝÚ(j³TËWŸYкãrÆeèuÆ õÉ=.ƒeϰàçð¯>fí?³â+¦ÀåŽ}ápW‹mB†…©–‰Iµ ˰Ȳ¥±›E)Ê´\ëfQáQ–a±>c™”a±É–Û-õ†IK½ÑRï –z§©–z·šóoK0Ðñ×½wºøîvÁß{]psâç^Þ)ƒÿ³·UÕ{”üyJÞ ’¿mØ;í"좺|¿ƒÕÚÊyP¡DYÆŽ\–ØËöNßÀ ¨äþk¼_V[,.d¶ù+ÐËFÓ`mñ6æû~ß(ÕüŸÊ^ùH4Oµ«øv'ò¦7Цøoü¾yšùÿ;‘¿´n;¤Û½]Ë“éþ¯ft¿ÐïPG ŒD@ê¿1ÛÓ»Öµ»J¸pãÿ†ßÐÞªz¤ð\¿ïAûPë¯ûü¡üíùLjCsûµæ¾ÈGqkþ ~ä)hÒƒ"^Öû·æù‰ØšÿÑï÷UkyJöýöÿ?ŠHÿøÔ’Ñ?@K›«‘ÅX|Ñ¿ðûÆØ03Þ§¼´æ6‚êD‰ƒ¾Æ¿ôûæhöC#ÙWFд!‘d½ û³ÿ‰;ˆ{…XÃþ[·¤óß ìÞDÆþ› <_Šçÿ#Þây ›åïX<ïÓRø©x^ˆ#ãÃfó²BGmCó²68/ûÙÏiJ—Efÿ§ó²GT ÿ©iîp#v^ÖÄŸßÆÁ HƒŸü Yº+4™Ù«¢ÙËï«Ð ¢aÊsNs¢Æ$*lšJѠˆJYKT *e@eq„JAǦSµO˜röÑô©Ú¤^úT­Z žÔ k¨¸OǦ~±0&ZØñïÍ_ßHþÆ´”¿*ÁÆ`£*ÂFß¿;ýŒü5ò7W Û ›”¸ß“òWô$ÊÍ*M±öŒ4w4&lÆÌ>"8šÍ±Ðõß`7€JÇÍc¥ÝßC‘ÁÍ(ÁMâþ›NoDgr4GoT/ìI  ô/û&†TýîÀÍM ^a{«¡ñI¬ ãZª óÍq½°÷7h¤û!ÐlŸÙÞRÐÞT% mû87¨`ºA±±{šñæwFÒÃðgþŒ‰4êËŸ´ÀÄš—ˆ‰ËÐݯyÉ`bðw¯zÆKb˜`TÇ"w w "¹+íˆr³‰j±nxr.E#Ű¿»Š7ªøD#7 En&BnFr3œrc¶CjÎa‡tæi¤)O#"m² Çè |b–F}—,Ñ¢•‘¥ÑF7²4_diº¥f^)8 r®Œp>žÐòwŒÕTþ”kÆšßá–ÖüΈ•°Ã c‰¬„M ªúæwkÑPm~ÖÇ¿{¢ÖdIlâãQ?ʈÒ/žT5M9›¤·¶Iß©]MFYL1µ«ÉkWŸë¬My\·ž üq¼›;|ÉÜïMm*Ÿ©Oèá¦!×ÓM\O{\ch´¸éK1ÈH1ã»Ô&³Åï˜JŒAµ2Šê*¢ZEu5ÕÕæ¨ÆÅrµ:ŠªQ­‰¢jˆAÕÐÕM_ ªµQTQ­‹¢â1¨øWâ×GQ5"ª QT1¨›£›ÁQT×Õ¦(ªk1¨®µ°æ‹jsÕuDµ%Šêz ªëÍQMŒEµ5Šê¢ÚEu#Õæ¨ŽuˆµEuQ툢ºƒêfsT—?‰µEu Q팢ºƒêVsTe±ÜEuQ펢ºƒêvsT“bQ퉢š­¡5ð(ªÙšÕlíI»û:â®E׿ÏÔòH¥Ç”ØM‹SíqdÁÍõŽè]5M7:ÙÆdtrScÿÚóZ'ms˿֩m)@w©=¯wÒ¶BÈuÜ–tTlªµŒ5>„aªÒð±Z©ûX­Ô}¬â³¼—Œé½|Lí¥V  E†ÇÕjô¸Šg5ó㸂—T&°ü¥_±*`ÌS)V7XÔüå_qVŠ³ÆÆ-Óø Ìc°#:ö}ŠèE¬Æ,Ç‚u´AŒF1ƒ%ˆ"å\zO›ÜK+ýYЀ}íÈ0¦•÷âÃ%÷¥÷¬¸5O@?# I4EÊY¢ñr)â–OK5¿oü/Ó2—hWÛÑð ‹/å\ú†-Gß°Kx¦®ãcm_×SÔ if¦„yH¼?ó{#÷Ø|æø([VÛ(Ñp*–‡É–áŒb>$Þ‰åòLN&ƒv¾|1éJºæ{–9Œ¾«™ÓžÇz6fz¯eúntËoÌäóìPGI¶Ù³(Ù&ÛÔ˲ жï`ÝòfΣ̀ûQ&ûªŽoc9IÞ;™îŠ$æ›î ¹ÛYQÞì6Ô° n…+ÿ@8k œµŒ×7·[,ZŸ2ªZaž;ÜѰ¸Š°ŸåÜ"Ñ^€–Qê|Í[õ4þ÷˜*,®®Ô(Šù€Ùì-Šù(E=ߨ·,*æÏ›HùXG4±ý#Jó)‡¬Ùã^¥¤f)ãwS)ߎJùDGÙn;+Ò¡˜Í§ñS >ÿÈ‘ûÚ×ÙVx4dÒ6Æ·²œÏQbŸ3ßdG•€ñ½$©àOõ þPrýhi À]²);õSw¡Â‰tøNòÕ$á)ä]Œ.øÿ‚Žª>Ȭ{ßÃBÐàö&1dƒïey6 ð^§õ3:ˆ'S̉…½‹¡!€<õéuá0ßÏ‚Úö¯ó”r­¨Œ•ç©ååÀ`Õ€“XŽ6è)߉>Î\Œ+5üï1Môfù«4JˆeyŠúXáDûtG4Ôål,†87”]Z§zwí)¢Ex!"Ïï[‹ýÀÙŽè8e$£ˆ|ÝšJ>ÿcã[ÿ'äàS|£ÒÂ7þ'ï{¾oºàzýLñô¢à^|° ®ØoÁ_ÂTÂ¿Š€÷¦t½ø8×ù+ÿU€ÿcðãù€Žè¯ ñ†ÕŒdÞ£?öÞa%xXf Î§Æ Î…zÿ»Â } {^–-óÞéé}A«ûN7æ»Û­·Øa¾{Ý„™¸™¬+øò­×ðß·û™1¹»Ÿº ßÞûÝ|ºAgïàÀªËçBmŸÇt ¨¶mùÖ6ûa7_HG:2ôHü-3ø[Æøj¿5dÆ˽•Ê“¥—±mp›×¼W ðàñ¿Çô&&ÑÖh„ kÆ¥ŽqÌ—Ñ‚ñScï÷¼ÑIë÷VôVü6»ºúŸhðØÒV+ënϽ#ßð_Hô¼Ù©;LqÔ» 9ÎñVã` ð‰¾iò }ý;µä?öì÷lÛü~Ïòÿèyýmò¯¿Í?íY#µÍ¯‘øg=·ÃËv‰ÿ OF@}Œs8 ¶‡’BÉ{·¯š"úcÄ@É{# ¦Æ94Š-éÄGK|,šä÷>"{ü,hnœätÙ'a÷È;*jœc #¨Éê¯d“ìÌ0ÆÊáyv“¦ÂóÜ0&O“p,«‘¨Ÿ‰àp "‚F:•‚mðYþ -ú ¨žO‹$®ÐPm†”S‹6CÚ¢e×J2Ÿ‰A!¿o+mA³0(Oñû¶CØVÖ\= Õ Mg5bå°¿•Ùï­ó¥×¼óàü>‹ÿ=fèÕ “–ÿµŽ*Kjõbä\Æ­NÚößjmZèm­á÷Ý•ü[X¨×;âaÒÉRã{᱇I_ð§þ˜Ž ´Ç¸lÄŸþì׌ƒ¥t€àÿêá€#¿5µéà&ä bDZ횟ù|#CÎ#~ß4Ò8ñÙ]g8ot4vÇ… Äîø>ÍØß§¡™ÞŽMvÇouÇ5}~Þº|»£ØÇÀÇùü¼C+8>ÿk9/g¾l)x¹V ¤:i§­à¤£Ç¬v¹2àçb×€v¡ú}ï”_ŠeÓí¿mº|ƒlçßû,Û ú|dŸå.‘ó4#×ù¯½Ó_ÈÚZD~K ?hƒyGù=Bþ»æy¡Õ¨&$<Þ+?$Bo·H¢oqtóm¿¯oƒÄýÇ“¸ÓŒÄ‡Þ)é‚DÃï[$ÑOhø½ß×/BâAt2³ Ç·ÑÉÌ®˜É̮擙ÐÛ1“™GQT»U8Šjw ªÝÍQ5ü>UAZÕDÕ'-‚jO ª=ÍQ´Å *Œ¢Ú‹¨úFQíAµ·9ªí¿AÕ/ŠªQEQÕÆ ª}âį8íoâ73vâ·SöMÓpñ\ Þ¶ÁÄov¼ý)ÉóC¡ íÇA¨Nò¾ƒ^„|Ó H“d«íuJs\Òuàã0’4ŒaìœÄÏI¨ÔiuèPá€ûæ[ð« *Æ~`êü?'ø’®?èû‘DÃi?Ù{»™z(’{Þî”s—eÞe–ÜÛx1šØ”fM]p0mù“ýÊþÖððN|ÁWý–÷×¾[™Þ¯}³ßæãexV¼ ?sÞîŽI§¡ÿ%ÁWÈú¬£B數GÔ¯kÍ•½™|ò:n » 4³ùøå;§Ú|ÌrúÖµC·ÅÈ)|%9¯ÑÃÅ2êöánh]Þdá¶_šl³ÙO)D|»ŒWÖ¢¿]3©xÞû/©Ã˘|žãÚ(ý!Ñ’ê…×ȦiÖNä¸ê•äð|Ë.9çÔøIÞ9YøšÅÜ…Y–*š~¡ymà¢ON¿öÈ9Iw(ù‰*ÙÛf YmSnr$ƒØEð & é" ×bH‘ãOÑ€3ÎÖû•äçÉmG4_v$»¿éÈÈXòôàé!ñtDò£$©‚,~L/k?.ëló"òÝ9c+2øy<…>Êiiƒx.˜óv9& §ŸÍ…Ë!ïƒT߬N­Ûá]5&°ë”ð¬FŒÝÔ¾‹1÷)挖ÜÖ‚F>þ^ö%óG²ž³Kí¤Þ)t9¶¢§*TD*÷™v ÏõSÄš/R‚zn€B=μ(^ΨÊd@w’†°Á:jßDÞvïù‘D†bK“,‡*8¹BM-êÚE¯è4Ipw2Q?ѯ6’LR2ødˆê2Ò‰Ídhš þcŒÀg+Â`ᘭð9ŠYÊ•J´9Ãbz[¡™F•Ò•ÏSôŠò%6#ù¼_eaƒ.ΑYÌWàéü+š´öbÕ ¯V¼}Ñõó%ß1jnÑM(ÓMþÅ“ºqzðÄH0Tð?KÂuƒ j^<üˆTe"•6 Šd¢šÄY¹;ž¹'t•ʶ ˜Ð¶]ž_Ž™˜DVÝ•BxÜþZdå—õƤÆpE¯é½›÷¬WÕ®üŽ}Zdï®*º¹¯j/ÅQ=²‚FûÆçÔ¯jùC5'Áˆu'°Þõüä“…ÍÉúXÁIá…VcpRy_«ipêg%ÓEVQï@E)Æ@%O;ÞN⃭ÁX›öhÑŠf!ˆá¡”*û\;±p8ܺÒNrÚ% )‹àè(àx^g^À} Ú,€eQÀIð‚8ÅlÀ18ժ˥¿å’\ˆÌŒ2fTö©m1<&|j¯Fë(п,±òéD1AÀ˜–ŒcÚ #¸D‹e7kW>ËJº Ô>Ûšg#[ˆ•¾À*Ê=ÏF¿ÐúØ‚_©G ÆÎ«#Ç—ÆrCÊè2kÛNô ´<–)Š]a…JŠËFˆõçÙÜ#„vPð.1ýÝf!?´ùµÆ·ZÉgOž‚î„ø6úRòìSÑ tMÙA˜ï ›:L¼3&ñ.úŠƒÆ†_»›‚ò=}ao§ðz«¨›!6t%Ưƒú‡š[ÝŽ²¢Ùõ4UµÙ'‹ùÄi+™•HµÔãð:tÑf9k% ­¸.]²Ò-xù²•ŸµÒA ~Î3¼ž·ÆŽØ¬Ð‰^Õ+2mäFŠoÚ!ÞõÉ7Àóe=¿fEƒhӆ߲‚yJÐ7ÐãäýÊ4~Ûª ö”ó;VÑc•£M›Þ$COo ‡¸¤÷РRõ,Qy¡&*t;¿ÐfP‰Å¸CGVb£Ãkij’ÍqÚArk£ ù‰/Eº%­”‚b†&ž³`à/ú(þ)8 ÐÀ/LºÓŽ›jãm9ÅYìâ,P%m1"œl‹Škï[Wg¦ìÎÂ>Û–“”S!ÜóU¶Í€W˜ƒª0•Ðl+!"HºCÒ{¨Z˜«œO¡‰©¹6oI–³N¬Ãƒ²²dÉΞ06'+¤TK4 _`sþZÁYÐ9WCÆfÃl5²‘VWb¥í‘ #Û"*Hí—åècGU"¾ÐÎûØcô¶x^hˆ õ£¾ö<´œj(D到ØnÖ;JìE€þö<)@·óå3ÇåŽöðAv(ÜìY0µS;A6i`CìÎËd3ÜS¦£ð“¶GÊ´i޵ÇÖSÃŽsN@cIPâ«Ôù ›·Bò­y+/Q·ióŽ–6±2¤2'v»m´P¤‡I¸×É÷ÛhÝH“Ñr+f§5¤ŸÒ"’£DŒÕ¨d¬Fµ'>ÿ×pXíp?¼ó~8ña8ãa¸}8üW4Scï* ±NåáÁÛß®±±ž¦7ËØ4E±ÙG‰ùõL²¶ûA=-ÆYfÚ©¬Ùl,ëÙö¢:^aÀhñ`rA#ã–äö ÂÉ *ν¤J´2™ˆÔó*{ˆæ ôYFŸkâ,"໨áæÚBü<¡á;$˜oǵƒqi’Íf,¸[B6—agYBõ‹-!‹eÒ2xlùWy¹랲Žó0uµ/³ÐþÕr»Qd ‚šŽ&kEmTùJ{žJÃé*; §«á+±‹¸ªŭŸuð@½ §1&+bÏw¼+jkbð0ÈOÙq×÷4šiž˜¦ØµOEÞ´G-C¢±3Zq¼i§aë&‘––Å᪛¼ èú¹‡54Ì=¢ñ»v¿XÄÌŸåä÷ìþ”ü“¿ÏS`÷‹–,¡Ž¸f¹}âH…dÊÚ7NXÖ¥D¾aYù¥É¼OÚ‚ìGv×:`k(ŽÓS€âeÈ $Úÿ-í ˆCsŽãÈPc¿84¯æ÷•&?½ªW)èQhxžó{Çzt«¸ÀÛ0A š[ F 4XŒ‚øS|ó¹ÊaQhOolœãSÄ0.#„Ý2EAùÇ4´pÊËâü©Ìã$z9¦ñ)‚òÌï‘O¼©q~ýeq@áÓ0à¤y:$> è˜O Ì'æÙ„ *è儯+é卯«è可çÒËiÏ‹ó·Ë?£ñùø<«ñø<§ñ…ø<¯ñE”FŽÅô²#™WÓËE/¡— _ ªÕrÁ?-h&¡=±00<¾7ç\òƒ&7’®Æ¼”&#Kkðõ˜Ló› V7¬nhO?SÈmq~¾=.OÁ•É9Œ¡w‡RÙ© ó²íŠé‰vë!2º×€8­ù}ǵrü=PVÉuBC§a<9L­FL.­z]zâüA÷%£SÑCqþ¶ø P £¼Ó HðH\j¸Þ‰«|ÇâB©–tirSªSq~W9Bœ6 ÎzÚ='ØDÁ^€ê¼¤ ¥žî”Á0áE|€£§~0‚¥v ópQò½Ž¯4,Ýq˜jYX¨¸X» 'ÕzMëMváoŠúˆÉ}ã=ˆæVœŸz[ì)ì©(ìmÑJ09ÂÝ;hHº,MVµPt¤ ÉÒí¾^–…޶·ÃǦ^Òb_ìÀÂÂC4õ¼Ï¥'àÄl‰æ.42-uhpÙz™#¨G/§hìV:B*Î`9` “ý«!±­qä<r?ƒÝç¤4EVÔß+»ˆ•qm,»Ô¥ïrð=?ßëÐ$úbþ "ã7™Vý’ïsèý€°\è=Y©þÒ}‰'§I’¢þžH|ãÐWA¿qð#Ž˜5¿£Ž¶d#X,S ;Í~ó"ßqLqÂÀ:™„'1à”£^_HSmŠºLì¢4: ²n››œ7°Å0^=€ÌUÃHúžçÿYêÏoÑóÚ˜Wpm(îKŽ˜Æ쀄ùß»hnøI½·‘x‡9ñŽdlî"ñ}Lü@dg¢Í½ãGxœ±–?Œ„ÔPHDÔ{ çâA¿¾ X MÑÄë & “ÄûŒ$¯OE|ð[æ±” äSù$Ä> °?¯ JR>TÊqkÕÚÙÿU •Rì±³Pküï1Kœ¬ÓÄŠ¾]$’{Ì–^Ì¿+š36™š¦2›ý—-6Êêy§3Šž/RrïˆóEÙ=ïâù¢»xeZüYã2À™«ñÉ¥¯hCôÑcE§‰|7T {œ“R®Äƒb«™÷.´˜aŠ@?é|3Ì|0bfš ”4ŠØËtR{÷3J)’ t¨q`ü%V"3ò€ y.gŠG”þ(ý"áª4`_ÕK¿•©ôwáÏz>蔓¥Ìx–ÿˆïâÿ`s ì•Æ•€æk<ŸÌ¼;=…CZÖóa§œÎÞSé™YîÃN¼£ÐoBš *í)F0öy*öw÷šJ]}ÝÖÀ¥1|<úž„iŸÈ£àq¶—2«¡áŽ…ç˜Wc| ®‹„—ùÁäe~ ༂e©,ƒgAúÁÐÎö(òÝ×´mÜË3’ç£!¤Ÿ‹˜àcY(§¤@œâRа%³PÐ`ãδiÓd"!œDI0™è•3ò&1*Õúåu Õ¸µ8ù™"¡Ýš{tFþ,€G(°£Ï:ú¼¯ñUtÝš–j}÷0ý ç†®G}75á6ÏϺò TÅü›1¿6ê×ÙÓÐ 9Â/LGÉþ8¶¤“<.2aæfÎø5Hp[Ç|0ßDÌ·5~ 0˜o#æÅ&Ìýð°E±„€€¹Ú³cAÌ]ŒYÍWµNrXn8•\ŽN:1… ºJꊞ8ùw5¾N ¤Ðù]hÎWÉÏf Q8—Àͨ-\/VLƒºÅêŽ_|—äÏžî‚ 3Иh#M}½¶Íþ2HRòkcD¾üxÀc©‰{ô»ÎoAâÈý2’د)æÁü }@Á|˜GŸêù4ÞW&‚º“Jx%ãÌŲ_+ôÈAårÂúa%c»î®Åƒ¾G8J _Km½“߯ÑlÔ£J<ëá÷=Ô¼ÃÝ%”ºJ6Üi|åL^5†2:—è²§zŸ‡v„Á4‚`ñ:Tšµt®(e:é:ÊÕ2ô©ŽÉD®VÊ]ùjBáè¡Ö;ù—ÈÑPOÖÊ|­™£:¾NFGŸrð©sD ­',ÁìiÀº\Ϩ¡/Ì¶ÈØÖ¨¼¶Eåµä5VÈ‹\a®4•Ï<>óÒ¸ðN–©|ú.&û)¼XÁ"'%JW>]K¸ø %Bo°¡7Dñký½¡¸½¾ÚDon_WAÚ>Ho©-2è-Âm~L è-zË^_˜Ç Ì+óZSÉ×*FÉ×t_WË%Pá!ºÐ)ùCÊcJþ%Zò‡(ù¾.t› °xOŒJ~©(ù3йäÏ(ü%üŸþ/*1%_è2•üe…_6sTǯ(-—üU%Zò(‘B¿†Î=±›¢$ÐÄmE´Ö;J´‰ÞÁ‚{€‚[o*’1*ž Rý¾"ÌØS˜¬êE2Y%§”Ez–¦ª]ùt(ráf²Qf©‘*P¡úµ ‚Þt?¹SÕú„u-Ò[i‹])­É~L±«wÄý0´ƒ2÷µ"\UÓP÷ØD ý n5ÚªòíÈ@±‹×DØe`700Q0°ØlÊð)d½KöÇ o!ü/PÌ%ÿ%t øû»p‡ÕbÙjfðV¿o‚o3UáqV|è§”@Èk¢µ+Ÿ„7ˆ¸ø«_+Œ•ãvÕvÂ,Mˆy r‘A xT21Ëšhóíy¾ð²‘ìN ; ’;­|7A ’{€ä>$9ÈÅVQ!‚ÖH÷²FëF-p4@pT‡Õ˜òú9*-~0æu§‰p±Íð¸mãý) <ÀÖ½ðò»x©Mb‹j‹nók“áè:n—‰ðôœ·W ðná-á-6ôh áí@¸ —ºø.ðî(á=&Âû€ðd}ÀBÂ{L„Ï!á xÞK„ß ˜ƒpƒ7RAø¾„‡¸ø-p»_›"(ârä>…I¸T9Åî÷ E ~Ð{PÌL»Na¦Ï¦‚B…½+¹ŽËêâsí‚Âb;e TÓkªå•ìY²Ä—érAz’˜HïCÒH> IM¤ë Òõv~Ò‡€ôa$=Ì…žÏˆôé(é31¤Ïé©‚ôy$2÷2è W‡#éý¦V39Îèeâx9%Ð{™¸®¸ Èîâ3âüÚ4y&®©Ôš0¯CÌp$b®3aÞf`Þ‡ŽÆ À\˜w!æ‘.ô8¦M×; Ä\oÂ|1_Àшù€©gl407Æá:$þæoæ[ˆy´‹ß‰‹tLwã"Ó} 7LÞAê;Ö>èÁ©¯Ãï;ÚÎÛ§Ësßí>²Ô]ÀÑv½*à šŸ51;§ðXdö“f;tfg;øJ ÄPéèÊç:Ðh‘‹Ïwøµ‚­èé° óaÄ|Ç#æ#&̧ ̧ü,%˜Ïæ ˆy¼‹_Ì3æËˆù¨ stÎ3¦öó1æañ:æab¡a¢Žyd|W>:=€»øØx¿6K`‡>|ŽÃœÁjMm`‡ ™%ßÀJ1ˆ'|Áø`.èîqwÉ@ì„9ñQ=ñQ‘øX|N¸“HO¦©8M$>«'>+Ÿ‹÷îvç@/„ÉK]¼õW÷^7®ˆ‚vfµO—„ÎoØæÜêÈòx4Çùgaœó>ûLæ+ãѰ&„ðUøæ»§Ñ°ŸI|s<š·L~İ^s¦dL±°mñð Ѳû` Ã4÷PŠýoìÄ”÷)(ó>c"õ"«|¦ð½ñXj)­äécöæñ4 Ç“Äî!A£bô ýŠ}2G}ü•ºRtíé,¦>I©)åeD$£yÈÜM?äWŒ/æ+sånù!¿JeºÇÊþl™á±J –™‹|ŸYfy,Šb9mª7E x=3ÁõæLšª¨ÖõB+M@]ìݺ”‚RVO5¨4¥¤¢ K芙ù“]|tBÓ¶®]ïäQ5Û ªÙØ„¶­ŒIãÐ]ÓÿñŒÁ<§dø¸„œR&Ü›d–‚|*Ÿž-rË^àBè߃¶UÊt"¡ìÙnh² ~m¶® àZÂÙ4Å¡ÚG‰Š22‚'0ŠpÇjæó–yÀÎv` Ÿ«¼>Îö’ñ±t8S–&ð :‹µ0Áû S_œJiM^dBøß’2øÒ<ØÁWÌŽ2¦â³¦ŒYW&@P€v…VâiN{°ð£8áZ3.Ïþcœ¹¯JÀ‰ºo¶GOõqvr­g·ó5G^í¤³ 7DxÜbm‚qÁ;Ïê®ð°"ôõ¯s<–"äc}BtoÝ®ïŽÛùæ„<5]æ©Exã2S”Á¼çY{ðv¥Çr.M…~¢-Ié|‚îã|¿¥Š Æï[û}¿¯Ÿ ð¾dšªªÖQúÒA¢ž~HbÛÂϽPÆÃṯŒÉ#ù°D¿o[;¾(Î8]Ã¥]ù¶´ºê–vEb¿ âὨžH aT¨;+Pq‹y*PiµdúÜQ‚~_XÓ¹»@ BØe07 =?yYE"¯HD'šHsNb0¥5È2HE‰z¡ QJáEÌ;ˆ%ƒDýZþ‚D¾(1g“+@×LÈ,yRz.ù#×IÕè‰ç5­W vúïY•HC×3èž^É=ÒÚÄÈ(¶Á.ã ™òcÿkøAN•ÇX¯«vô¨Äûí¦¬ÚWh˜KkáîɾÆþس ³æ/`ùX €ICYÏ>µ „ôé ÐWÓZYm‹X£'†Ñ­ºÑ­ºÑ|N/a2>g”0Ÿ3K˜ŠÏY%ÌŠÏÙ%̆ϊf'ø‡Ï±%ÌÏ5žx{>á¬Ä­‚hˆŒà)Alyxt‘ÿN<ÞZÏKÈ/sð:xIÌŸéÂÒ¼¤ü=Oód¾:­•dµå’Q´ä€~ŒÄÇH93\ð5!0Vòú3¼ o0ƒ“¼¡ ïþ om†·.û-ƒ—ü¾2ôîéÂBÏœáJ*˜áªå%¨óÁŒ\€™DV—8–ŠÚJIþKÎ\nsà=øëQ…K§ù3\‰ÓH §ï¶P0þÿaí{®}KýBþÚ·Xý×RZÏ!ojïåy³øZ~£çÐ7µÊú&.¹*ïD–\ñþ¥yA5”~×-# ªòlÎ<}Au®ôbþ,"C7ˆ¡äf áÃ4Å.+£¥ÆP¹€Àkñ)gRp¯§ê= ŒÏ ßcð[ýž¿{Ódø½UÈ”i`ó>QEþˆßà?èþ ƒÞë?ô{«J?3ðvPßU…k¢ü]ùzúØ}“œÓeãfzg ÎS}ó=Þ3)Õúå›·sΤDÂÝgR˜ož‹wñºTS3ê‰#~y†Õç·6©üM¨R¶§g‡ÃüÝUÆ¥5±€{­‹ ¬Òð-ô¢©Øt¬—ŸŠ mVÊHœUÊ´ˆðØ¿-ºîEK0{Kâ‹u§†­Oö#Êd‡@] £‚•#gÊPó+]´œƒ¹ =|]C%¢¿$¢ ¢€èéfd\œG¢Ø)m¦WdŸA÷bèâ[Çàtæ.#EƒÚi Ù)“û¯}ðXVÊ$¿Ìw©p»0ôuÐXíùï‘Ûeð}r@;PÆÜÕöe÷ËÁTKè‹TKнÄ#ÑŠjõÓ LsIÄçq•Ë7Á¡†ŒO¼«š®sÿF¼ÂÝ¢Z~XäŠÔûw³•ùQ™<®Wº ëiÊ þÒ—Q%D¢>*£ÛõcºÛõS²?…z…0$]‰W­ëd"tƒÁÀ^$¦>)K=â îw:ˆê Q²ø8ÃÚ]x..Å»²ü–L¡:vêØ]Ù»ü í›2Ö‰,£žß“!÷Ñ,±qùHÎS õuvôC‡5I_¡zÕê1ɇ0‹ËKhüX(jx†ÉR!<”1[?…(:$Nfú( jt˜Ãütuªût¦„{ …¨3bÈÈT&Âl¸·"¤ ÃüBe)yv¼L€%o/Qx‰âϳûVrà^ç’ðZG%/.5ÜšNú^úsÜ@…ß%Zc¢˜o`U3U M8|zjÕÙÁ8Ï‘{ÉÆK•®|”Áw™G¨)£Í¡ÁÜå'úƒ ¡ã?…87 vg…¹+<|î* MWâTëYI´_…ÊQ‰”%fS÷u‹­Z¡²cÓ*;iºÂ§*ïŒnÕ8ò|+=…Ta kù4Å\Žu|ººWy ëùl%¤Š QIôNž¥—›<Pïõ¯RœZ% Î:/¯†ôrSx¥(·Õž<…Êm ´(Î*([ ‰”›•Ï‹”›ª—›ÏWòlÉÿ(ÊͶPá ¡ÜlXnVQnv¾å† ßbH 兵ГÛY-”Á s¨o9È—­Œ ]A½Þ0jŸ»Eç±IѧE›Dv>ËŸ‘¶(|‹‚ZÆ6ïZo§ê•§ð$#ß.ÖGvˆ€ žªdÜÞ­@âüKÍúe=yç{•œ6¬ã#ÝǺ2w¼…á¶X´S8ERÄ9°z¾¤nùÕN—1ˆeúâj#qgšÅPPËž.ÃØ’B™Òo»úsžó†œ¾UoÓÖ XÝFÐh1@dŸÓÜ™”Z:›rMá×I`ÉÀC}ôŠÃ©#·|Õgí Ó客Üå.~[•t¥®–ßQHÈ]àâwÀs¹ø=…ÆÝÜj¿¯ÐX™»ÔÅ‘EבéV«jíB UõÁ{¨ÅÝ>ÆÂܯ§2™®§Bõªòªß·Á¥O0³7H*‰»N£(ƒ/¶qªnHiœÊ'ˆänÚ©6¥*7h–«|šžj¥CuEh&Fª ÁY…ÎY^öÔ9ÉÞ(ɼ ¹k¿Ѐ\¨òÅ:þÍ„\:.¤úÅà]ÌÄá9.üï1*\…ºèøtÓ)ît †ÀŸ6ÞIãï ò /ZÞi`7ÒØ;<µÑ,Ð6?Çßõó·»h"915Ù$„ȇêñG¿o+jeéxðð{ü©®w|ÊÿÐ[]üs›D`NŒˆZâ`з!àd|#†Ç8†0˜Aì6ÐPPÇœ’®ªŠz”a"Ð’_{¹þe¼NÌ,sñ€ ´·Å td¿oósd‘A¬‡nwát‡è…,Á³Tö %‘¦O¥XxNÿK¯f NÀc,KX 8>§Oƒø ¾”R¦žšôkòí CÞr z¾ŒÉ+̌詩ç+Xß§ÿz6˜F¤23¹©bF‘§LEÌåÓ2`b )¦áÁ8,Fmý@Fž³QŸK,€¹Ä†áBûÔt\ÌiqŠ>¢^h¼@•Cæ ãq%Ý‚È@æôt\«ú%aXÑÁ`àc"VôÆbÒP6VÛ«”´Ò°¢WÉè{®°¢7ß°¢÷0­èÑdeoT^{ y=y¡a£ü½.^ ò*Ä7ÞWňȫD6Ék€ÌÊ1ò‚9µoIT^ƒå¨¼†Ê†¼†É$¯m˜^ÇÈk”lÈk4N¼ƒªe{Ž23U­áJÎz`½ý;»×+¸yYMîEIF)ÑüŽRøx uÆ¡ =OLJS[æ%ÿÔÈÀ…OT"()2.¡•)9“ÝÁÌÉnà»\ÉÙ  doP`ºÚÝoº¨ó6Ààm©‰·K&Þ.)hæDç­ÁÌ›bæ­QÁãSÍy»nâí¶ÁÛ·;ÈÛ²t<]ýÆCRt:ʺÄòt<ÈN1ÓÓDÓU:&å×w g©]Q äû] oBºÖ ÊtH"øUˆyÚBmÅ-àu*ÖÖõj´¶nP{^¶§äC­Ú¨ö\¬¤ä/Vø& µUõ.Whj±]õg׺,|G$e ÄïÆ/¾GÍÙäô™›< cöª A¨ÌOãÌ`~øvx¸Ÿè•u†á ¿‘D!©ýª_t+ùA¯UsÖaDö:…ñz[-¿DDü*j=ÿ†b°îó£*v1”è8%:Aü¤íPø`÷¼ž‰ ‘L\R½F%oƒs¥+$š«Äêx Gá®L—U{\îU+Î6yêqŽJ¥tÕ ÊE)c×­œ[)mPkkÄ«þ×­0é¹èi7­9÷Þºï½Í’ÿ¬Øš±ï¸oüþКνi§y[òRhC^ʉ—~6ï…ä ^bCجŒkaþ;ÀªLZÛø@ŒADÈl ñR[Ðï ¸Ü7’%œ±E P4N¬¯ña¶o…â®ìÌz£Þ ‘Eh”3O)Êà#méíFcclÑú3V06ÁÓe”Ù´Øë\W(ŽŸTÇòI¶ –wÇ}!‹•ãéQjŽ+EßxЦ·Ç«xêÒ†7²Ÿú™ÑòŽÚø1[L·v܈ôi'lÑ>í´Íð9|ãçm$á ø¤AÊüòãrx•rØ`Ê!·Q~=6‡7m¸…檂,¬N—! óEªIØSÊ,ÕöÖ*þF;_jG†p¹ ßî–ÁWØÃÃ*;ò°ÚåaxXoáa£Ýpïw±‚u|3Fa=ó]²QUÕƒ-„bbgÚBpE¸.뮡nçEbû±½Ø>eçgí9 ÉwC2ªkÓŸÇÞEäîž»d‡ö«UvãWì©í܇üª½vúCms)ÓfvãÜ廔¥Íè¦Íh£UuÓf¶ÑwÓJ¨hü]îÆoâó̇ü–½­vöC~p\è¦ñ2jÖˆ¥ýƒDì"ØýŒÄC;õ x2ý‘ê~á€UG݆÷‰£ð}.øûÆa‡²X¡¥(.FxÅxjꨶº.—•³+²½PyÍ»þÏ&ãEúí‘Ý.J‰êêút³ñõ˜ ͆ta|ýš®)‚Rè=ü,(…ú„fùkHÆ×¯é×phB³’6àk#šu˜tSº0¾ŽIÆ„&Àè;$&4µÆ„f·'4uäÆ!M€½HÉÎ"çš<Ô{j×zv—ô)Í–t´@ö Juߘ„Ügü!CÆϣ¬YN}ëœÃÏâTäð³Ì·õûx¼¾5Ôá0K[ÓÑè[¥`¨HÒqIbZT"ñ42<‰“¢¢MÇ d’ çñgI/,Ñ$i&IdggˆØKh;jX,ÔSx3a„™3ÿû:ÿûÌ7Q¥Ë #%“±¼Q¾?ÊB³Öþméªb³ÊÄó,I˜2¡éÒ,Éy‡,˜—?ÃæK ¹š§JýÅTi¾#Àº@ ¦ZZᵦE€¿w2ƒh™f±d²e°DrÆ1˜€­h ëʘ@b•ä¬Ç)Ûº&ÿ±ÐqÔ‰`@Ï%{YmFqÉ9á¶7³Ñ5 g_ŒÃíŸ÷´f|äü3Ìèpß³‚æ{õPKx¥Ò§{oÀóZO¾L`x!D ¾ ªwH7„9×®¿ *uH·‚`Ìš!*vùùáá°2ÿQ8>þ—pø/á0|‹ËÛ±ZÍ c4ËÙçiájÝbýj‹RaÜ‘n6ÌÓkÒ…aþ[¦Kn½q¦&ZàZl;Ó…aþ[‘"з2¾Z`M¤î$/ÔÇ¿GI-ðÌÔý=ØYFÁÇDC<Ërzܽ™o^«üϱ Uìó0ûηê-¿ï°‹L¶_@´»Óè\ÿàï"—Еz<ÈÊÀ¼ý_÷ {#¾ »»¬·Ú=éx%ï5‚j´¸¡Ìá©,1ž…?ÕÒ¥[é((æ‘ôj±ì%À· p²8my`M±-ï–Ó@l«ˆl:!îd3 Ùp²ö¸ÄR"°ØÀ¶Xoø+$¾±&!†e61¬ d¢;XuíªÉL=Àí·‚j‚ y£d2ÔYC|&Ñþ¥Þ5ÐòÊnjÕ~ÊÝ+ÄO½ÁO½Ä’XÈP¢ÚÙabFX¬ ÈËrÆ{šÀºƒv4!õ{£LØ¢ ¦+Ð à6¨+×%˜ùù» s’5¨[­xèfy®ßÃoÓA›¹%ØBÚ¹+ÆÒOÆ›J]жW-/’sz£zSŸˆÖØŠÑ^ëÚá\_ ¯¹_eàyJ˜ø}»øðŽ\ïÈ ”éŽÜ~Êí;ÄÀhÃŒíh™•¢'cé Å‚/£¬ñ¦ø„(WóZeð2å7”äWK\.aœIÑfÝL™,eÌ”ùlzÁ$DRPÁ‘ïuJ´w:#æ‹É&ì½É^Le„`öf+LtpæY—.¥ÿE”–¼/B[ÿ­À«SHAï:¾yOÄNr•Ä!+\EˆWÃ×¼V¸œ†ZiÐWó}Px×È8ŒÕ§Ãˆ·ÅF‚t3ë/u êz4˧àJDP¦v¿_v"ËCw˘tXF«µÍ»ôÃQÁÁ0QÏÈ!}˜8‰Éñ÷N&Øà§dS§Fv¾Ž‘.Ê-Œ—ŒB‡GU òÃ)Dƒ¹ÀH„²ó´$†5ù•Žr÷>sj^ ¸k^d¾/B.ù]9Ov ¯hÂ8¼/‹Ñå,Fbá!E=¤(†Æl£Q…Š©뛣¸ã¹PØ·Ë‹F“AyhÉ•÷SüÞÉÌSy‘bÊmũ߼TiÂéPEG# I&wG*‘|Œ"ä£tä£aM‹UÐê_/St‘âvîSÍR¡Þ¼ø$%FÒo Y2s¯¨Mö…Yø s ^uxô=‰ÏTôÂd¦ìU(Î_#óÌ8rÌWrú¿p÷ù¼lƒFA*A4y‹ã^}3†’jÅé ¢)Š•ÍQ¬«uk ô?²NqnG…`³‚ ‹9WBÚ:™Ì#YQ8 çYu]àPÌøy#ˆ9?ƒÿ #DrþNèƒ=DFkt¨BL0B´2ë1Âéªó%+1ÚéÖˆ.a#]Âf·>ß=¶ |>û üó‡áƇá÷…ý­ÃaˆàÛp½åuÓ?¥Æ¼KÑ—Âw)|bnRz¥Ý‹#³„™Êš_ð¯sáj}6pÐE)Q9ôøÙÀ7úlà$-ÃA~2ó‘øC)GMàpº¢XmÝ)Q…¡‹T0a Ï~ È—Ñ©0´“~ÄU“ˆ ûòK–‚”z^Í K!‘¡€Gè™ÌXË_Šèè3D¿ÃÐ_v0úÞ)—ÝÆ â:m‰ìA°£4ƒhKÉPíA%G¹ø?μ÷~î[ò¶7èñM}#2•8–ŽÞž^§ä7©ÄM}wä6Þ`6íŽÜû!!Y˦ýãé*Àïl 4¶/Jèt+ðÞ•—˜3— ‘Ö ¿ç^JE5Ñì÷­wTdc´„55ŽO ÔôÔ)u­žº,’z’äü îx¼KsÚñÀMÊ¥±ç§ÓÇI"ÏA½æ5S¢š)Ù¥ç׆ÃRn8<4†7P«Ð?Sºáw 3VФb} ÿ{,êí%Â:u2=ÎκG’¶=vÖJÿÐåìÜÀŽ|Í^í9¨³vî íüÚ…/´‹_h—¾Ð.¡]ùB;õ…vú íÌÚÙ/ºÇçÂ]SéOÛZ9Ël“î±~KžóûÝ÷]¿»ôUô$ýª¥»LnJ·Ê_ëÎ)Êôû®̢LVP”YKŸ}_Õ?ëè³Èø¬§Ïãó#…¾D¾Uúù¶F} nEþKŠ33‹3-Úœ,¨Ud)ÚØ~L;ž¤õÏÑøKZI޶ð‹îì•<“DÓž”¶»ã-¥Ï×ÿ/‰™\¦ ú’»ù¡6õ9W×fU›bßo{ü‹¨—ÖÍbO|kìISl²î«Å#‚êMDgý;d§þ=‰•¿#qèSº¿ùVéþV—µE;ÿëA3×=²î5G^sN§^sD3^sîº ¯9w]è,½‰×œ³éÂk´÷¿æØúÒs¦Àt„çÓ…+ ü%tçÿb¸Òù•p¥ƒÃÕ…ô¦¾Ñ‰—X'ÎÌìÄùK÷¾ð Ý7úy„Yø…ßwÆex„¹˜ÞÔµ³ŽXwíüûG®¨kçKĉfrÜ,\öÜ‚Öhã¢2è~ßí *—ÔMÝ@ƒèNèÊßç‚Wu÷‹Œ<Ÿy^y>ÉóÕHž WÜÄä„»v³…¯FóÜð8ö=‚ýµ¯•ã@eí«þ8 Ð:t€ÖE€¿{žãÑ¥¹ßÝïU½œy>'ò¼Ÿ‹äù!þG“‹sS±~ö¹t:x½àé$€®ðtýI<…MœOÅOÕOçOÕ€ø|„§Ô°~ÐŒ'ávýg6ôÖÉn~;}©9ýþý%ý ‚þ !BÿÖ·ÓOÖéßþnùÒï&¤?Р¿Ô QÐ_ ô/Fèßùnôï>žþ–é6è/3è_ô—ýKú÷¾ýûÔ\ÜÍé›±[ˆ qѹHý¾(‹!z›Œ8“n8¬o›ÙÖRÐ6R»ëŽß¦¬b&Ïï‚LjÈÀ熭tþŒÂŸ1ø3&àOþLÆŸrü™†?3ðgþTàO%þÌÅŸùø³ãÏüY†?+ðgôÏäî– èµàLþ®è»J¡ïºé»‘Ì~ñx™¡´Z“œ’„œ†ëe‘S8"§f¥#Ê¥àõÇÐLíB¢Ò‘Dÿ8²)>¯cÕr5ï3ÑImÂ9¨7["Báã‹Jh75ÈÑM ÷}½å̉îïJ<ކLØeÊœL4d‘¹±Mi=ކG§Qü8 ÑPˆ†B4Ac|S%`©.À­B€çA€[#ìÿ8Â*V‰°J„UAxbSÂGxˆNx› |o‹øú·VK¦K«¥^r“šô¤’üí4ŒîiH‚Æ”¦4JŸDcÈëß¡yÅäcjSC_7†ç&4>òÛ.äwä·="¿aßE~1y›Þ”îð'ÐÝ!è^º;"tG<žî–ËmfSº#Ÿ$ÓQßN£…r›Ý”Æè'Ñóí4Z(·9MiŒ}‚üj„ü.ƒüj"ò÷]ä“·ª¦tÇ?îNA÷ ÐÝ¡;áÛëK˜ú˘üÎkJwâ“dZö¤¶lš·MiLzÉß…FL>5¥1å òÛ äw ä·!"¿ò'µ·fy«nJwêèntO£ÛçÝiß^_Z(·¥MéN’Lg<©-4ËÛò¦4f>‰Æ¬ïB#&+›Ò˜ýùmò;òÛ‘_Å“Ú[³¼­nJwÎèntÏÝͺ•¯G|vžÀC|U¯G|vžp™}vžp5óÙ9è1>;çFQDTó¢¨NÆ :ÙÕàXTó£¨N!ªQT§bPjŽêø1¨FQþÿØ{è(Žkxªg•BÈx‹[q²ñ€'ÏF‰ Œd%¶ì0±3ÊŒˆ'ÊKòðËf[›± $v»Ø÷}_fFHb³oF%v0 ïÞ[ÝÓÝ$pÞ÷½sþÿóPOw-¿{ëÖ^uëB-T¡Në N‡C}¥‡Z¤B]F¨ ê²êr8ÔI=Ôbêk„Z¢B}­ƒú:j°^VKU¨+¤†©B]ÑA] ‡:¥çj¹ U‹P+T¨ZTm8Ôi=ÔJŠ#Ô*Šë x8Ô=Ôjª¡Ö¨Pu:¨ºp¨³z¨µ*ÔU„Z§B]ÕA] ‡:§‡Z¯B]C¨ *Ô5Ôµp¨óz¨*Ôu„Ú¤B]×A]‡º ‡Ú¬BÝ@¨-*Ô Ôp¨‹z¨­*ÔM„Ú¦BÝÔAÝ ‡º¤‡Ú®BÝB¨*Ô-Ô­p¨Ëz¨*Ôm„Ú¥BÝÖA݇úZµ[…ZÝuQT¨ÕíµP«Û?êºâ½¯ÿ{×/Ñ_W|¢6Ùh3ïu<$F†Ön~ah .þ×Ñ4È‹u¹Ð¤÷ð;øžB'šîàf:ý?3x ü7à†š ¯&sW úBä•0õ¬o coðŸá¹gÀs#Õ7 fvö{v·¸ª»²ì]íy— ÆË…^AòÚÓž§¢ÖÈë¦&óX¡âw¼ÔÓöÞ€‰§Á>©e×G2?7F2 ~úö2þ½–-~ßôZ–_Â̹¬–õ/a–<ø-(aÖ¾ð; „ÙúáÆ` ‹È‡ße}Y$ÚmT¢Šáwi_Öl w.aÍ'1Þõ;P“üÓ`ÿoÔëÀ¿U¦ñ¿û}»ÚçìnßÓÄÿá÷í¡W3ÿ,ËÔ-ƒ~ q?t=Å05"ØYæ–xD=‡‘g¥ÆÓÌsY–ÉWÓµcfYfzµò~øzËèZÖ§gÏG‡ƒèp"yæ¾Û9˂ʫòžøMʬŸ’îl‹7ôéi‹y—ŒzdY³,ÏÆ¿dtMÞúÖz1‹~•¬{Åh´]4^[Ÿ—JÜ«CVñmåÃU‘Œ8C{ÉàÅ‹ñÆG³¬HrjÆÇª,Gã OÏæ1/“iê»ä7£_s²R—5HsÜ÷ÝÝ>«9Ý¢t¨«±wÏh^ʲ¢Q9èuS„Éß)0¹û=ãêG '4 ƒ»ÏƒMxü(@ò¤µ8¾Ò€”#È\“{À3®rRR¡€T˜ø“{ € ¥rêu€ä3 ˆ§äñŽçwn?mà[Q»¼}l;ºÒÙï+³Òé“ôj¿5€¹WšðǵÒÄ2V™$¾­@ïkÏ÷@¿ˆ·Oçñîˆxw4ñÏßžW";§_—ŒÍ£û vßwò˜á€©–]µ°C&4H§\íe÷^ù§ÕhŠ:ðÎ8#ãGÑ44ªý‚pVNúaÇÑ4°uÂäÞeÉØe1ð“š`w”`§1pq&ìòszÊæÑC?—‰Ÿ™3\6á9z4N}hß¹ó´Ä¹)èÉoEúš·LðÖÆ{ôEÔ´à÷Т]™µUT0')$x¤áÍÑðê+}†”õú)_0›«µò|ñY&<û+_Âs×9ûºÉÔ<úÄ—8ýž7†ƘkÙôŒáïŒLcæÌÀŒg>« +ÃJðŠãIf÷|®®ù Å‚•®¥?ÀêŽ@ß%Š@/h(—1ËeÌr3ŸÂÄ®u9•/ÒBV dƲùbdõ<ÉðuB]K¨gX+àØZ3߀p…²6ãW ˜qúE‰oÁø¨œ[üϬù±jö–ÜV ‘܇»65¢:'žÆ¿Ë4c©ìË"O±=»DÄû˯G³èGXÝpð|¦Qõ‘gü~W ndÄÇy½úHC ib¨»öùŸ su7{Ùwü®‹í òÆ={˜òB#±¾n$–¼Ý¯p l¿ ­Ct Ü~ÉÛïÕí•í÷êöhWÄÝB³ý^ mnt í ÅVV¬Þþ\(ŒÂwZ8Ðp‚aíêŠ aWWê^·B€·4ûTr âú]‡PÞGðq 'ðqg!,¸£¤ÝJ¢]ZâúG€Ø:½µ!§uÑäò,nù…g¤@?Üpcíñû¼fcMËo¢IÞ6ºÞ8áD£èY\ùø]GÒ¸Ñ4 eËðæãЈ4Ž7¤qëñhÜ& XBz‚!'A f¿Ùû¿EÀ>¸óŽÃ½“¯fìGeìÝ×M µQè! ô)e£5ÿy£µN,KåÓùвÔ7ĪVÉB&(+YœÆBqF£pp/Ä¡¢; "„öî7àC9ÀƒGH'”„saûŽ!ñë¥#k <¡ì>vDíÃ+Xsª`OˆJu!lDZãÃÑ…ìC{›y›–Ø%”ØeÄúvlD >eC±±¿—ä?‚ä$Y«!Ù¿1ĿɈpÊtÄV‹æìU8gØÑbŒnñªøÖÎÙ«ÂçìùŸèæìƒT(ŽP_ªP\Å9ý/ì™wú?ÀÔc¹vꟽ¿=¦ T³æ±aw*¡©°Ž’¹Yóy¬®¨Õz1È®6†2ö€ÙÔø]÷'iüý¥q&ãSXÀs¤kAΑ®Õ|* R<¥¢µFßýèøzÅGÀׯ…l _]Åí Ÿ~Z· ï¨03 ù²¤Jqª¡œí£J˜÷hWºãjøTPŒ§pù\Œ_˜‘¡i¬Ž‘QÍšW‰o< ”€f0ý¿ #¶ßcÛ&DÚ?Å%̸'‚%ÌT¿0óaø½ø®åZ¸M‡ˆµlT7‡Ÿm,â*ãÛ =«-9¿ªæ;^}ìùWAοjøNVIiÞiÞ#<>+Èù ´ø%¯}àUÅÜÏñjVéZ”†Ö+]ð{~G¿…+]cÞ¢ûÓžƒ æaVé»í{ Á—…é0‰ã(C£¤®c0ÅPÇqI`“‘.©EãÚðµ¿È  y `*ßòä¦ùòÒÊaÎx–+Aò•¾Ãi®ÒvÌ{¼+?Ç<·Sƒ'º2^ ³s<[é‘ôíÊ(ë…+ÚßBL—õBC[‰FûeD?èÛQ†¦nÐ~ÚUæ9—O÷÷³L®ï£™˜£ÞJå×Bò Có›0ÈëÂo±8~›¹ŸGK¿éÏK®óiÖœç{F¢¦sV$^9 „2üJâw1{‡u4Âøê Ê]Tv¦—Bšä ‘`´q­=*e^x:!ûÂÓ|¸ä^/yN3ß®Ÿ{®¶÷ s’æ?Y–Þç|?¤è %ÙÖÒB‰WH:+΋%½ç%·¨£â~Lq×RÜ}Å̰Iâë%÷ê.®Õ] ÅbVá÷MŠEtƒä7]’Òø&É=ވξ~´©ñ<½÷·ÐOa `‚‘‰»÷ªøV)ŽäwIƒß#:Š)g‘:…õûn`{2²#ÎÑ^'Ÿ³Êö¬„ǰ €0‡pAJEã’ìíùeÉoÿê×Û3þ5¦i!ÿ€âƒÈ÷!â¶X\•Á_¼Éš”µëq—XÃÅœ¶Žƒ$ÝD.FwÄá¹›|J•9k©±– ÌØ #ŸL7SŒ©xô)}³½ýð/ø <>ÓÒ’ôcé°J?—Ós™ÿlœñŽÑÐÇé5€¼…ôÇR®ŠÒ±]¡¿ÝÈw¢!Æ[í‰î. »éÞjÏ÷Ý÷Ÿó»ê¡ëðÕÅeÜNâûÂ8¢ÐZÈYLÌIÍeiŒ·æ¤â‘²¸œTÜÖðs C߀з‘Ÿ ~¾QøùO0ñóøÉÁK†n·ç¹¦0~òpêX¢¡0'ÖhêãR˜¨É÷2en^fâS(€ôTS*ŸŽî´ç3L~ûi‘ï3y’y"o€ˆw¹”xO'Ÿm ò6ÍÚïÊÈ;y7"ߏzï{ØÌ·‰Ø>$V¦!¦œó}ƒÄ&kˆ]Qˆ]1¡±9 ˆÕ±kHì›öüz8±@ì¬HÙM$6ECløSß{Hlª†Ø0ÅtÈ0aîžLlÌG¡é{íy±9ŒØh³ß~NƒóÊibsØ<ÀºÄ¦S½K>‹b‹Í|)Ä–±Hì~{¾ÊŒõ,¬¦W æ­0ãt×~B\‡$ghHÖ Éƒü’œ©)Ç’ÇÍdçãLò$<$´Çš”l:‹È³`TÐ<ºV‹‰FA5-R¾˜Ù]ý¶}MWWõÛìS4Àï¼Ø’†w2ù¦D†®ÞÚ+ß›ŠÁ+1ÚBüàc!Âx}„²HM±&|ð a"DØûðmøà“ B™¥A¨ 6|ðÉjªEæVI\E5q=ø43CáU ³N#€u]ùL3[aO S󾦿}^aæZÐãò“èAî—ŸäóÀ½Â‚g)gSç–"*#Ê}ƒÅÿÎ!£oèkíéÐßKXaÜjñ'`Ç·/•*§&ø5ÂØCwVÍc†=–Zv.±=¼¬Ê³ÑèÙd|ç˜Qâ‹{¨ÓŸ1ÔÉx£ÏéÈ ìz€ßc…v)åj{ŠŒK)ó©ÒžÿÌð÷ÌáÎÖ»Yöpg-«ûŒý#³ÈÙîÙì"øºú™ôÏÌÎxCöøºö™ñ³Ì‘N·'ÝcðŽÄuáŸ6E·˜f©›1˜ñ4º óü“Ùs,ø,·øý®I‰0Ÿ˜‚ø˜ƒõ‰†îfZœ¹üdö—?£\3&&è`ÎÂDÝ)Ÿ%‰ºS>«•ÏuMçò“ P4r(â@÷ÐIýšLÍûß@³ê³éõ„ÇOÃÎlÖøþ,ÌwË'MŸÙÚ¤ïú&}7„û>êìMå#ýÈ#*Ð:laŒ®S7„ùnl2îÆO´ÇZŒMdŒ³ÉŒéÜdÆÄ6™1ÊÁ¦Hy=Ï(ÖóvTÖóD}ëy#•õ¼‘‰¨œÒ±Áz^ÍÎHqò”{Cò‡|ÒŽ§ó™~<ÝŸÔS¬%Å„&aºé+NDEâå·ä3C±:ƒñYhų8Q\®s4P™]œ3Aôh~`¾¼÷ZñÌ=ÔHת,dîaFºL¡‚ùí³ÞΕˆ V q@tðêZº³vt¢¸ptbè˜]‰â˜eÄ×Qø*…¯*º²‚‹öðuùS9¿oLbì‹4}ƒ^"1Á;šTzEŸŒ3F²…—=&‘Ÿ ±y Øœ-Ø_òäFÁ§w© øà¨uLbw‰ì¿/–hÁ†'LòUs0;«¢M+%¾”`F:}‹\ÃeÊw|áåÊ÷bø²+%º æ·dmh@?f^-ñÕÚsöwf­•²,@ð´=°Þ=߯&÷a‚_‹"+ÈDÈFβøNuÅl/ß鮘†3]ÈFs–™Ø}²¸¾¯hn“=>/hNÀµW½ºÜD˜/b®ì(£[dRî—”Æýí4VK¼Z ë7HòFã!IÝA„Ì;ˆGä‚{4Tp#™UqÝ;Åïp;Ó†g•h¢üUÏñXïÄ4xµßìæïƼ“Ò áÙ•HkÝÛ>Á†KYë^MðôÎÓÿhÈù£ÏðÜN£‡†´¥6Þ­öÅùÌÞ·n¸ìSàýT?&>6dØïþA¼nnx'ÚãìI‘ÄÒÖhlVdŽÖGÝ5+Õ2Cõ²¶Pé­)öJÞs¸ÁRš(/îí®œâjFèG»û}›)ðkÃÖexyݸ v“ÕuãuÄÏ«šea9‚Øßø®8Š·IwwSH¸ë›Žú=u«ˆº¢n EÝ@Qß —B#âwMUÒ_ÝMNÿ¡(®îæ÷ŠR€7>"ýÓ0ýÓ5éßÔH"ä †çD"¶‰Dl‚Dl %bscQ]Ú¨ÛEÔÍu{(ê–oþ™Jú(ùAäÿÈÿ ¡üßJÀíÃÒßzˆ$0 0å £,…mÔÅÇ7–•oAz ñyy;d{Ó_ ÀqràMþ>m´ìüÖb™«ˆå€"–3B,@,gBbÙEÀí-óP óñ±@#•Ý«cceCH¥•Èæ"›·@6ïeóž¦^Ðì[`g`o#Ò“ôÒÛ÷­¥·(Q>¢|P‘ÞY!½ƒ ½³!éùC»kÊe­ô”ƒÊ(¾Åšª ~ìg󉯇o¥8ØX$—|„MDÚ‘¶„"U~ë”/UR~HIù9‘òCòs¡”ïïhà?"åË0åËñ±+ñ± 'ϲ ªš®/bþ‰Ò„šdøràš¦ÇË$ÿÃUòÖ¢À×iJÞ‘¦™OÐ üèã¤ô%9ð1bè}œ#¥çH†œ)ÞJ‰µÊ'%ë•ó’ЃL+x+MÀìdv#1û‹ã$É75Z2øï¼–€}û'9ó»[T‰íŸÐdF–Ü z# Gäûއáì8;>Á‘»‚󕺕›‡“Ô“êVn^¢v+7/1l+w~Wø” Õ¡N«P}uP}áÖë¡Î¨Pýê¬ ÕOÕ/jƒêœ •PçU¨|T~8ÔF=Ôª?B]T¡úë ú‡CmÒC]R¡ ê² U ƒ*‡Ú¬‡úZ…€PWT¨:¨áP[ôPµ*Ô@„â*Ô@ÔÀp¨­z¨:jB]U¡é …CmÓC]S¡¾D¨ë*Ô—:¨/᪻é n¨P…uS…*ÔA†C讃º¥B F¨Û*Ô`Ôàp¨ƒz¨;*Ô„º«B ÑA ‡:¤‡úF…ŠP÷T¨¡:¨¡áP‡õP÷U¨aõ@…¦ƒµ]Ÿƒõ*Ôp„ÊI A ×A ‡:¢ç*7)U„Py*T‘ª(ꨪ¯ 5¡ú©P#tP#¡v蘟„Z,NhÏ>Æ.ÁÕöø×c¥Neðú[Bé² ÉÈZÄÄÕméÏøxÖØj?„‡3Q?]*:ý¡…N?.tLj`7hPRèÏ>Á—I¡s<ût"Ø.‚›úªUˆ"ˆNœ{L `ø×c•þ ÏÞDLªó$©·= äMQ~‡ç÷x`ç êô M‹™,$Ô¥H²ZLf·ß‘eŽ7¸¯t¶ß~8nÓÑ]{ç»vgÁô+MÞó]!ÃwÔ¬aŒȸЕa`å5-0•Æ–Šº’±Çjé{Ù”mQnw=EË%ß5œb™£œöõ&tcÞQ¸o3‚rõ‰º’†+¡~†n‰9‹ #“Ä’1úõEu…|Éï b~ŒJ±˛ävßh0Qßh0-â-³Ò’ñ|£Å–‘¸ØR¬!±I,•Hb´†Är…Är¼p%€!ˆÄ* ±IT&¢¹^™Äú‰ Hb ‘@mäQ¨<–ªÄ;P"ù s_|¤6òØX‡g’„=ÖèêÆ‰@pm\nÓñ®ãÏ~‰÷z%áq$ЭJ x‹Qذ6´x²–îÇ ¿¬›qé–ð]ÂËXJÈ׆Á…ÃD,õ-ÏI" ßñ~Û*4Ë[q?bq9Æ?ÅÙßÝ=ÔŠÏaV7CöpzY^-?b~×ÑDCŽùÏì#Ö%pB8O±3®Õ †˜»(Ížãu¥1ÄÿˆýÉܶÚ>îà+÷Sö²M‚ þ7'$½Y’ž€ó')cDšY¦62M¼4øôLÃÀ®Ë]™WqsëÃ*Ÿ¾b +QØâ4YñÏà®aüK´ƒx,»0ÊïwÄqí×fïyÄzÿÙC„{LšÌš ØvIccÓ ø9¼÷Gì•?›ðCàòã¾úúTƒy\š™ ãÓ ’Ù0,Í`4&¤LOJÒ f£aR’²g#¸MÙPSv«[iRƒ=›²$¹wÑÌQ(¶:/ÔÎiŽrH^[p†TáÌÍÑÉI 5GCh8i°ËSò),‚­eék™!g- …üÀû 6Ð.“4MÞlgoSóY|TcË—~Íâ%ªe(³iI6à¯ßŵ ¸‚Ìõ‹ÆÅÙ‹†0û–®écÒÌÞK]éĿڃVc[2CíA«uÝGõCƋѺîc¦ UƒP³T¨TÍ#{¢Ù¡ÎøëÇè‰ [á_µº§* IVFËa'ºî|—µÌí´ýe‚}ü´âÙ­ÑØüÌ¡^µU]È­cü탭=Þp>7ÉhnÓ‘k_Ún›’nèKº™ Ö0ij¤0ã@Æó™ç¦U¾¹×sËJ÷½ñþPÿÒ𒼯¬žÓV¼Ào O×ê(„ÆŸ2¼Éo_ìÿðDj–)X–ešR99OØÏC¼yI&K‹˜ý‚›aÄ Ð5Œ|0” à~>ÞP)kæ<i)Az¾~–,*ú £úô4ãIÊ›V¤³È-î’evíèÂ26DI¤îü¤H¤N¢ÔM£ã”¦—pê9¼XöyÔ¥=ùKÃ4HT9$7ðgàölÀóý‚œï×ðY /Š¥DÞ´~kÄ=§É%̈g+·0Ó|øÝZÀÌ‹…V­eÞ÷­Œ¢}[!ƒJß&#)”b®Ìgž Q² +m,`AÔ µø6Kûàý¢hÙ\ú`³ÊJH¶«®#ÕÙe¤ŽºL–š\aá+Åæ+ñw“¯:ÈïÂW³8¾µQÍY&UÕÊ70D„x®Mi†,«ª¤ ~›X% Ò ä]_¦1o ߬8F‘SaßJæ!¨˜c‡?;ü…4ü¥\Þ½î+ìïOÂß «ÃSdÿëôÁ2‘mØé/Ò ‰+’b€ê©nÊ#ÍØžÇ.ëk|Ôáã>^þ­I#|ªºÂ_ÂFj|ÿæ[ä S±P¬6v”IK.³Irÿä9µ8I1A:Ec‚ôl¨ÿ=‹ýï’†S‰¥I°(Æ‘¿¬m+ ‹¾a–%54î7EXjy@=ÞêëP¿÷{¼Ä܃çì¦/$68»³< ­¶üP³z8EcNTY=¼ˆÙ~ —5kÿ+’s„ʪà9ÂКûÊÇ ¶ªÉ`‰ä`«K¿²9X¯Ù"Äôÿ˜Òÿc‘þ+ Ó¿†àÚ?"ýµ˜t®Y=]Û4³?‘™]×t°7ä`ëKSc{¯VL<)MWÙÙÔÐÊ€k÷‰|Œe#ÑË£—HvôÉ‚^"YÓK$;zñ¢gô®Ë2tÝjHxÓc ó ó¦F˜›¯€liZ˜­ä`[“È¢3{ÉßÑß–ÔÐîëÜy/Ð(o„Ïï›÷‚2ÊÛÞX$yf¾ˆ4"ÍEÚÑX>7²c^”»QÈý›†âÞ™¤˜|xJïaJïãã¦ÖîzDrç ΋€ó¹!Îw7"{±ÉÊ¢=l¯ºdr ªûÔ%“Sºê©ðj‘O7Põ«P§* BÖA‡¡‡ ªPgªR…:£ƒ:5Rµ_…ªG¨*ª^UŸø¨Ã]ÕIÿžm—õú‘ÀÉDÌ ´¯„–\®JŽWç0ö“Ì1NOmW¼ÞmŒ®9Lz7s,9uf§ƒ9ÌèÉGNãœÙãÀép3õÉONãÙãÁéH3÷g™Èm‚3{¸Ëa–1,³„ÜJœÙ%àv"‡Y+XæDr›èÌžn's˜m=ËœDn“œÙ“Àít‹8À2KÉ­Ô™] ngsXäY–YFneÎì2p;ŸÃ¢°ÌÉä6Ù™=Ü.æ°f…Rær›âÌžn—sXó±RæTr›êÌž nc“¢§K™ÓÈiš3{8Õæ°‹¥Ìéä6Ý™=•sXÌ)s¹ÍpfÏ@%ãÖò°”9“Üf:³g‚Û{IÊœå´oûUö,2H‘$¦ÖM-7ØÖ²†;RLÞ°cLH‹ˆyo´”Õü¾äãTîLÀëÙHž±Nå¼ú¦^òŒ“¤Ð F:”c´IÏ-©¯7ί¯ÿáƒçÛà¦%-ù5§A1ÒÏ·¢59¨¸äô7—oß }/;G8â ò0D¶X#‘ó¿‚^¹‘„÷r´­›A&â¢\)ó”;[¢ngË,wÊ—:{Ë| úànb^£‘@Qrh¾4ã)C©‰âýXæµÎžÃqÙ×:ÃÌ ïÏHÂû3ž¥ð¸¶gßPÌìc»Ù/½ËIÝѶÀñ$³ÍyG¢ Ãðnào NQÌ„=Lªe~Åð§j$“ÆÃïÎb˜‰Áï·©~Ö3ó2< Dð'¢hõÏvYœ!¥ñb)à«ëª(lù®v-¦‹åGã%Xc¥*‰I\ÀóYEK<“8Nrßëì™ã´Ä컊é~Ûô{™‘O¬k]In¢ènð^ëŠ7„‘ÚÏñlŽä^p-Šdmâ ®©QFH Ÿ!¹Ÿ‹7´­D¥¹J˜¥(S=ÙaSÈA>+ˆ«J|.DJÎ@§çIžÕ/¸? ¸>cYæ6®¯~J° ¥˜Ðì8>0´íimëxåÏì{6+_&¹éF©Î-—²,ö»oUz¯wå+ð}‡;ËŒ«¤@– ™_®il)›/-•޲û '’ðÃÉŒ2c“(æ3l)Ï(al›Ä· ªÛZ‰ñí’ûp\Àu8ŽåŽ«Æ«Èü¾cqÞcq|¾óã{$¿ïD\K´ä—‚qÞqtåMP òJòòdxW.ß/¹2tqd,ç ÃzÅ«$ú‰8|BL^¸_Åy¿Šã5t§H’r§2ÛË}#4áš'9Â,·o }?s¡Ó³òÇÞ…ð}ZЙ‹œî…Îô…f¸Ý‡ôƒÌ §géw¼ðýZÏ3;ÝÎô ³˜.)IÂÛÑž©› ÌþK®]ÿâŸËu í $á `œQˆLΠ,¦¶CCX&Èt‘3Ä5”ŬB·á䶘܊XÌ tInóÈm‹n£Ém¹atsLÌ?ð’JÈ–µæj>˜yJ¾ãú¦Ò®¥‘-)tò¦Ò´ýˆÖ@ÐmÊJë†wÆ“ÛTÙ-üfDé¹Qõõ¦.õõ¿®¯ÿs}}n}=|óq¨ñÜ×û9¸'ŽÙm…~˜’þŽÚ¥*¹ëÀ¿›ä«‰ú‰€˜åg“̬Yó—®&’W±–8íú'Ø·F't“¼K0Î% ëC³`8^t/#hÇb$òr>I×BgùnE¿¯À"¹„ÇÑ\ä³AQ&ßu •Ü ´°™¥ò­¨L^ààÛ˜?c ÃÀ· ]z{ùÛŠ6ý$t‘÷3 ®Z«füîp-·ðÃŒ¬Þˆö+ª"¶=)¥£~ê3¤'\àuÃöÙ%Ìu³+Ã[àp‰å˜LømÇ×'2—ˆÌù_¾FsÏr âBm¤·‚|Ì1;˯B5ôå–b¡í*‡zUÖ9/pÐWI$[ œÆàEÚ×eײ4fg®#?g˜†›ÈÁå$Å–Ëìf¾ÆÌnÖE–üî[\LɆÿ=6kO½Dq±ë»ùß<úYyoªSæRm†/Å ¯¥–˜º9£äçO0«q—“G òø<Ü~ß—˜Ïu´ÜÞ‰Ü{ÊùÒ“„¾VМs_*φ,þÒÁÿ νzr™ïzzèðëøU øgþ…ßWˆà×ÜIîùJ®ç3^À0€8‘0 Ñ ,D…¨¢*‰Ui!…(Øë„õ&afò…R£‹•«4š6Ký¾ Og_xŠ—°‡ò:‘tBû[K1‡nÒ*s:ä"wpß~œz þ÷Ø¢[jÎc€Ùt Æ FÓfÁ –ÕCÃü^æ2gëóÖøNS²—Aû™“ˤ/Yær§'¿‹w98äæ2#4€+œž;]ý¿b?3xW€k^.3 e™«œqÞU8ýÌŒ‹»'?³Lc™kœîmßI4¥oûó®Ͼ¹Ì:e®UÖ‚k¿\f›É2×9Ý×Yúufð®Ãs;ÉãÁõRÝ<ù”k¼¡º–M{ºÞ6|Rž8/¯BQžNT´@Õõ; Þà»ÛÝÚ¡Û]ÕÍ·ÏfßÜêu+ôøFï18¢<ö]¡qÏêMü¾É³Â Ë@Æ‚.FþÀ„3µ¡^oŠgÕ1ÏÒàÔì‡Ær…3?eAá»Q ‚nI©¯y†,M„ È7Ã{ ãFgeeæ£Íºè0‚:bsnì_Q —¬l¼…!M0ó±Äv<YH|¼YìUÍ'˜½jb’é”Áüfœhæe©T’TŸdÎ2µíiö ulèiA» ›Å†¦²6+ƒO®‡>i²Ù½Ù™±ÙiàS÷»´1ÿ"±>“NçB ˜iæ³Íî Î elp¢É,TMI2EM{E™kF[fL£ÂÄ!Ô̹–0ÔšoƤI‹(iÆ 2­µÜÙ§š/eé‚|@a.RRYÃ+ õ4żMÉ\XÂL«ÌÈyµ™¯2·äj9ÍY&%ѾÒIæ×¢!Š9C1\gÎ2Ó0y½y£‰/¹È…e*–¿þÎA̲ ð•0ën3ßEÐkTL ÚÊw›=ëœYVp@#†ûÌY6Qšáí”~3ø”;èzÛ¼gìonˆì啸±ÌaÀCZ¼ÊŒƒ\4ýµÖI•èé<È„s cÚÚ@¹Þ£Iñ¯I¬_Á´Ÿ²B¹SN+ ¾ã åÊi&¨<&g¬¡„ŸÅx«Ò üœUn/ø+j‘&Æ÷‰BMÎŽ€¤p(B©‡ñ6õIV³É\-ŠòÇX ~kø˜&0“…Séc²pjü˜BÌg~¼]̲²Ç8`ôî÷\Áwþ§Ù¼Ðä÷¬qfÏrð^ØõFõå§xŸ`š_Á»8+ãæÈóš,¼Æ~ ý·ß½°‹ïNWõW,žýŒµ7¸­Át+óVtÉ®øßüJ["‡‹…p’‹[N±„lÏøßݱ0KßÞšþOTd¢ hKbþŽ{.@4»¬œdI2™¿K>—”.ë’8µ–=ÎÁ¯òR²ÑŸ¢@ýQ cL&8ü¾©ÜŒËK6Æóä=HQÅï>l“±Èz¨·”¬21QJe82ÑOã³}vƒÏDôÉ×°·WÞ+Á¬ØY¸¿&ÐE%ÐE Ík²'9„m +HƒIHc€&z±b¢ØˆV5Ùe>'ë5ÑÇ¡y‰ F¿¯ £ÒD¯P¢WùŒ>ÅÁ—bô/5Ñ—aô} F/ÔøœGŸ‹à3 }k|êÑ'×ä÷Í@Ÿ!Ÿ‰h¡|f¡ÏPb&•|¦)&¦™ø S€®]Ÿeò¬ ³M™«îÍíÒ7·3xW;ñ:ÓÕΜˆ*>­;@á‡ö†i(mEJh9r6RN™Þ|ö(”ö˜ÈDäp]d€×ŽÀ89¯DԾߣ–³OaËDÙ¨AŸ"‡ dφJŠt‹’M“y¸™àOA£ûR ¶‘q9“l¸¾PQ gàw1´¸gÍüŒ9¡ŠŸ5'Tóóf¤þ©rÜn˜ãÓX—½MÿßJ—Ìü¶Å~_±wž/›ýô5ÒQ–= ‰¹k1wJ—@_Sgæuæx ú—«fÁòdGi¼!O­]ƒ–UÔ€³O•…<Ñ_‡Ð¥2d£*ŽŸóbŸf~ÓŒáâ ­pÑá¶ÙO§fOsð;23 •lè_ïšñ˜ü^VHض\øi+líï™ý(Ôb”å}s›jœ+ò\ &5m×öµTbˆ ñdé4â”n3Ï·P O|æÈ˜Sµ‹?c.L+XÒb~ôRèˆFXøP5ü0Møárø"‹{£ÓŸ±zËYP .$Ê*>:d]ø}K4¼.4º(FRؘ³ËÑh´y‚_!å%2]ÈšRHÒŸ ¿D|ªˆ°@1B1ÌQû3ˆ<"—;Š…à±uÂîg43[è§ø,K›ª$3–ûóÊTGÆB‡Xß«°©g[lñ{ZønwΘä–Èi]Nªð#¨1ŒUíCl·`[J}ñzõgÌ‹„† ­1ŒL†a†¹X ªÈXÀÁÌPeá5"ÖM˜QÿG{‡ä¨³!êaKÌ1t;*»Í·c–˜èvBv+·¯,1KÑí”ì6ÜN[b&£Û9 +ç-1CpY` žˆ¶ªùA ¤î›®Ê’@<íˆNÕï(+hÜô8:Ýëª,à,ñ¤…Ä¢¬¼€]1:Ý‘L¡%3-˜mÒsëëÍ­ëë“êëß®¯÷Ö×÷©¯'a­bT²ä³@ȧÎ"ÆûÿÖPg¡ò5 ¿añÓÒXöX¿I¥*ÐX,8æ#Lì]pëÀ.2(FÛü V2ÖqÏò¨‰ÃñKÖÆ ƒ7?@Äþkñ h)ÇYI–ã­|œâÙ«Š'N^FNJ¬0º"²­°rL¢Oy4^jÁîb<2!Æ`Oî¦ÒÞíú2Ÿ†ìŒ¦î`ªÈÈ‚¾Ø**á|ýn¾22,µò¥ÀF.@EðåV? ­°`­TI¬BŽ”ùÁjÁÑRëF9Úmb£-±ön·ú©|SíÝa¥ö˜Í³lOíï—·Åœ{™¼¤©ØNàâÊN«¿ ¶¬{!N.Á¨ É|²)ï·R«D­PÀ*š…ýD­ú¢V1KDcpÀJmL 7­Êôã0Jk uo…´.‘´°[[ ™uÉJcsv~OôeÒMÊ<ã-+¿bU&tܪŒ^ë¬aº«Ö†ºkVeBwÃ*FòR˜\Ý´Æ××ð[Vš|ˆ9Ö*hóïXù]”<ˆ–æXZ !ÿÆÌ27C‹H÷­Y&˜µ<°Æ`Óz˺ÑÓ ‘+!rm•ñ†¨”ggøðã—†û¡‹Ÿ¦§ù6ÌÝ ðþ6ÉØd Á7I$E6¥<ÇåцU% ê1Dæ“lî»+E½ßšDVR›pƒi÷Ö¤˜|´”h …‚n¾ÑéYÆ6>Cõ@=¨™øÙGÝq0ʦéû,pb8Ï29ζaoÛ»¡2^ÍŠ÷’•ÏÃH Úpþÿ V‡ b<¨á§T‹m•¢8û0á¡^V*µr‚m#®WЦââƒz¾ŒäCË ËC‚¡| F¢Úà‡!þJ–{ª «l¢*¬±…ê°èl¡ƒ%+"kmj׉ÖC–ÀôoÀÜ—Œ\3Qnî‡ÜL ñó—zB»*lóß7ì‡] …}¿8ÊÚö´Á(Ëf³etðcÈÆ0?aÃ]ÈŽB9 ì 8°[S¤“6~’¼?­á§lº%‹Ó¶ ¾ÇÃ8ì¬Mi#0ÑF/ÚÈÂ%øY[ÂÌ×mü¢u—ldï€òåk,ÄYfj.q ¤V|Ë­·Qµ¸dCÛrµØ¢½f µf×mä¦ ¯¸) ¶Z·lYÔ½‘ûmøˆ74›„¥šË=¿k£!âTG Œš÷lñõ0[¿/X³#kõ6¨Š¢êšEÕm†e&7"ËÜ ‚æEo÷µ¼mÞò#² hv7úG`d«¶ÒˆUÚ˜ˆ,ÖÚA©t[°95U|x6~8úâE¢4Œˆxh¶Žï9à=*Ÿ€Ù[‘ÊÇETÒÝ%šÖ{"¬€€¥Ç™"ãL•q¦ál~b²ˆÓ3B§g¶:ýoNO~sFò·?=Sÿ-NÏÔ‹Ó3B~×zžwˆ³2²y=à çmvȆóþljh9¯îñ±ÖÀ2¤Aƒoö!½4&ßFý­›©ñ …`6I𠥉ã<æÇyÌ GÍq³8ÎC‡”tÇy,áÇyrºLùéxªÇL§z,FìdåT’Ð*^ëP´Š×¢r÷ìä§zÊavÝâoÇ¡ØtËQþ#h¿ÑNTõ h&Іv8°~ÍïiNðŠé_ÉøÕ¾x Ll¬jxoμ“â4y™šò^”øh ÍI¾‰g9’š> ö›0=±Á¡˜éW6}0Ò,Ìô¿‹œ(Z‰s“CŠ¢«VTGY)ÒÕ÷C%Ò¼d£|W@çôΆœÎ!n"‰›Hâ&’¸‰Ül¢¸Åш9‚ùÄ„KcE@Æ#sÝ tù^9>´ÃAì éå÷íp(ì- ¸lÍé&N¹ãú¶æ¦k<ÑtãÃv‰3J³ó™}é+â}nχ,7ŸÏí Vèæó…D°g#üÃs^ú°räàÞíÏÚ ÷Š”·õ>„VE¬°\ò!ŒVbZ‹¨?´úJé}%CN_)DΊ& ðZKj#[“óžy&ßk^UÀ“Û¥ÇKqù¸§ãŽ ¸¢X>„^ Mw‹Ñú7~_n·x[Ú L¶J-Zv ªÜöa}dâ8Ö›Éqö-%,}LšÉû +y0òX [uP1/¼ƒ•sirèxÕ \u^–:^µÂ¡Uê\áSêÒKÓ¥ µ¡V¨P+uP+áòßÕßt©B­B¨U*Ô*Ôªp¨«ïéoºT¡V#Ôjµju8Ôúõ7]ªPkj µFµ&jnOýM—*Ôv„Ú Bm×Amwʵ>ŠôØæX<å>œy¦[<Ó,®£oEå<óç"–eiKjmîçE ôç%ò%XDå¶ioeY€SüF‰_ý·™Ä‰©1vøVñ‰ë86‹ë8@€øƒÄ_áY„SeÎÃë9t"œªá4E„Ó‘¿zaaˆp¦^„³4"œ­a¹F„óH„ó„ç+"\áÂ)"¬h(ÂÅŠ—„‰p™`Oñ=¶15ÃÎd«Ññ/’àZ’ Ḛ̀„´§[Ïøz”Q€Šì©HHL½µ¥ÿu`g ¦ž@ª/>5ï|3ÓT*‹[YÐ/çã. »CLìLìe|¯ÊD=2ág"Lˆ‰@ãLµLPnîG&„$vS͘8¬”¥Ã¢,…G:ÌøQ$‚zBr-¯D0<ö‘l2Û"2)ú)%ú)ý”\O ã9Üõ×6?÷¡àÒÐE£ÆÊw6Fù%–ʯàg–)c¯ÃÈkéšÛdS„-"h$:×ÉÚíóò!ÔT}¢×Ñë2Ï×Eù¿‰»þÀt—ñ›(Í6¡bKS‚okŠì]âĵÏap3¿Õ¡Xì(@ý¤B_kÆÕ»1ƒ˜9Gªec1K_ ­Ïzò»„€,¨½ÅÁÊû ˤOáB•U*¨•®=#°˜OËŸ% ÒZCñt)'7ƒ"ð@ lå…Ù„Û¾ÖOcQ?‘ĬC$>DRIMV&Ïïiãä,­‡@˜xÒ§”é÷BF­ 2^Â'¡Ù\T+•Ü›¢è¢º&cS”D3üÉè.ê0º‰»8÷%7kn‹g¢¼-' þçzF¼Ô3ò¥žQ˜ f”½åe/þ`öâoe¢q.üÜ{Ö4~ÆCÌ‡ß  PÝ?ÚºLâs%?¶4¸`>^×ã«MÔBƒaÊ2WºŽ½eij ãzG<"må‹$%ÛqÛ†WH‡x±¤ä?¹/î¨@oèi‹y¶v”0ÛJ`eâ ±~' b‘k$jˆ£¶¡¿ ¹ˆIæ«UbVRéÇí@VS¼âwJU „›(@šYÜ%+ïòM|v®l×\¢dʼ ’ûy$ Íhß 9™™h»u-| deV”ø²òm(xfYøvðà;¤J¾S‚Vœï’°!ß-) ùIiÈ÷JrC¾OÒ5äÍx@Êj†ê¾<(Å´!ý¬f$z¯ÂWq&}9”¶ë{ÚZ³'W>¨ç$¼ ÁŸ¬hoc!yYÄ-‚¿½QÏúë±]ÖÞ :GT $ã)•Ø0ím<ö•Œ§Qž«Û A_•Õå_¥¯‘Êü@˜Êd<Òð¹faÙ4ÁðÉÿNusÿ½ßtàH¨–í*a†?ð?xvDø}‡¯o7 öŸú:2úu“h¿ÿ¿À¡mµ$øSÃË6‰âžð‹Œ ¿0ð^xz,Y9”€ôžwçwSºº9L[á_âP‚ÓX•ÁZÄ8®¡“¹ÍiŸÖ#Á~ë÷ ö›ðwû÷mº™¼ÛpͪèÅ´Œ¯Ûƒ:S¨©Ž/…¤©>„eÎxÆïÛïÈžñ ŒuðüX²EŠiù £×&÷L{:Ówß<ƒ™ïÜÛ~_¥##÷-‰aº©õ( ¨> ž?÷Íüy›ŒK©xm•?`žö´Ð%?,cZögDå µôƒY5­džÁþA*b½(ôýûÀøæÌ®ÁŒaHè?‚¾ ßõ\ÿ¹oš«¼mKR˜½r›é*Å-wÎ<_G_WñÍwCjãÝÁ¯É øq ù9e$¦å+ÄÎ%Ñ4ðøzR¥Î•R©u§êÆûa‹v(Y2Å´"Ò0˜TÁ¶t5 ¦F‰ •H5s„ćBõz:àºú Ö«Zß`¼¡ÕóÔüÂôæûÂÞüöï‡ìÍïÄ×4´L4íiß°ŸèUÃGJÁJŠ2 ¢ì£ì‹2ZÂW´ Ó“˜–¨ƒ½ u°`aCkÄçßÜý»=މ¡að;ï‡ç4ýõØ©;lø½ìÝ"ÕX*&GAÍûà!¥òÔg,=s»Ó¾¹}p„ýþ»öoÞµûíwžµ¿cïhÔÍ>ê»Ý#½Ûµlx²ô^æ§ê.Âu·xw`ù=F5¸MÝ^ ù;¹ÿ޾|Tƒ³ñ<Ùµ¶xžìx?2Àj‹¡ÇPñólGQœÐxœEó̳=¾‚âhµdäsE90sFûJ»Ê  É'š®2÷µ¶×µ¶,çZÛj¤@Sí÷Õ·¥1n`ÝÀAW}[o}[‹ gî+!Ï[è™ûŠ7÷¼ =¨1ï çƒ¶ÞmaxBžwUÏoÐón[ïݶüžð¼§zÞGÏ{m½÷ÚBá%Ï;ªg=zÞië½ÓJ3mJ6Y­¶õ"­$¡Õä1Ã(¸ãòÃßñÐãïÖ})T,ƒ•]6IF:Ý6D Æ~"´«Mtò.Ú<\ÂñÚPÇ]‚áØKZb\¸ã0BªŒ“•Ô*…jmÛ–8ÎÒ] ½”ÅWÐÍ7 ›ëfgoX@ ”Å’ìžàØ °6Âx&Ëüä"<ó^k§¨m%“òãðÃ>s¥»D+Z-Âà*ÿédÕNÆ™äXhQ뼯÷®žÂÇ9|\ÀÇ×ø¨ÅGÃÐÝúï[ÌXØK5R‘ˬT,Òxç…{/饮\· ó­Ðø¾æ»Xãû†lÃÜ´½ -³o5Ékßÿ ¯±Mòêz(¯ë8›¬ëh.,>ZV?†eá\rcç“…±Ž@Æ:.$74´P.O=:ê/Ö¿%:ðícÁg9®¹~å -œt48ù‘8~Asã®Àm×ÑA{²´á.%7´Ð_K{™LgPX$d[·É-†ŸnÈË×É í-t×°žÁ pÖ¡Ú[¸’¬˜-PŒÈLå3±l]¬‹/ìå÷]­‹×6«¿놈µbÝÅâ“>£lãb#^€{¾aúêˆð«È0±­0M~[P_Ôo‡¨_ýÖÒ½èhxGtrC“Zé*&5.¡Œ/kd|=ÄtiÙäòALßLWÓ7CLßh2*]'Œw%Ѝ‹!ê­PÔ›M§× I/× _i(í[ÉŠ ½´Þ%Ý%ån Õž†$(ñ†”î<¥»§©!%9MWRúæñ(ÝK8ˆ Ý÷“CF#꺆/t/Ôï/õAÃZ:4E©¥JŸ*pÛ½­ëR‡¥4ìRå`©r—:<¥aƒÔ6‚Zó>Lt99°R”Ò°ÁjŒ4¹ÁÑ%©1Jy )lš’Ò4z%Õp‘ÜÜökH©øñ(~©eþ9Õ39&–Ÿì;“]›\ ˆñÿβÄ=‹¯Ãé ÷nÿGÀ>+Ÿ)þÿTüÿEþ3RùçûÕÿ ôO's YûêwZýˆÎÅ»÷9•®}N SŲ,3M:1Ï”TßÔÔ|R¤ÿ’¾¦¥æ#Ð`F¦§òaŒT1 Ã’ÀðE"ÈìT>’‘ÉY%ȨPbdn*ÃÜÛXú6fÈÙÆzZùX–eÍ2yç¥òqðF¦i1¶w~*ŸÀÜ»ÞHßõ†!g×=m¼„eÙ²¬Þ©|"¼ÙGÃø¸ÂÌK™ûµô× 9¯õŒàe,+"Ëæ}МOÅ„ý˜–ÑL‘ÓŸÎÜx}¼ë8c”|ËŠâ3!¼¯25+‚Ïbq­Ï[»K®1ï)›cpOnø£»«2U"W>㥬HߤÔÒx©´jÒÎgîè 9ÉŠ§+š¥ñ…L pRŠ-Òhª‘°@­ 5?© ”9¡§%¡§5.ç'=mq9ŸõŒ…jÃòÄðgλÒ*ø\5®a| Ód°‰¯‰Šlz¢z²3­‡Ð§ú1óø]úŠe#üT•0ëfÜòÓ”3ß æ^jVyµQÍ]ûÒWÊ!k¶0qœ+YÐó“ :嵕¹tý„!×1NpØÆÐ8PlG䡺„Ùv uaÅw¢ »a\DÝ~äþ¾[©Ã÷2Ï'ßÇðX9”`–­«ošÄă¬RÞ‘©šZŽ›¼šÑû «Ä ¼Sðe3aú „|›š2l»ŒØQƒKk÷ànBõq¯ô½ìÐ ñ&kÆ!Sh2ŒÕÕ<Òxh!Œ9ØÿÞ˜cjhÌQ£1º9¨ƒ2æÔu6Ž9¦ËcŽš&Æ3R¬€ü¡FGªFXÚ÷ÙXÂ5Øã˜k8>Fàc>Fãc,ÈÄò0=²™a=_M“F ý®! {¾Y) §â5:ƒ€C‘aÔiâl’Ø³š¹žˆÐn(“G3å…¦„˜Óß3jH=vQC¾ç†õØ5ZËŽJ=¯iJRøxgdCJóÒ‚Æ)Ý~8¥â†”>¥Eß:×Çth°DP6p•³¨»nຸ1JܪèwkHiI¨|)‹úò5Ë×MùZšÒÐdÆdHËšÖ\¶\±•àˆm…:b+ÑØJ9b[™òïYUܧ° 쀜âEœ)¨–€¶!¹ÌðZ¦ßé)yÚëwÖ²¡0b{=3àtûé~§ÁÀ-‹Õ)h£ëźN§¼eáä]h»"mhȆÖÏ!èše×ÿ°Q›U~y×sb ˆkÙkS´»ž:%µuäõ\ÝAZ‚{“˜çÏh»ïøÞãoÀ5ï »-Ö)Ì,Úõ¸k˜Å ¿ð¹Ìøóòtèë!è†Ü‚y‚ “U«Ÿ6l`ô½I˜õÛLx)ÊÖæA²K$Rsd?8Æá©|ÿzÄ¢ü¤ûŸMº„´ÐiÛ¥àÞÌêAÐ÷eI¾_Ë®cì}rü5Qÿ÷€®4Ç= ýÁìÚæü7¨—‚;>ÑîsBô)hB–0;‘s²ÝS£„áyŒ "›ib»gtêWšä\i^ £Á ßWÛÜ Ðd4i[вý€0o†‚Âä¿„[¸/Æ®sŒÉ|K"ŸwiOǤìëà8TW€¿ø‹„¿(økVË‚…0… “#ì]29"ÁÏ‘fìQËŽ–0Ó¯kÙ±fþ –/a–kÙ Dý¦–}Ã7Œ´JXD& ´JXäoa¬V¢<µìt köÇZv¦„5ÿÔýgÞÚ6ÚDíLãݡŢ÷+Ӹ׳¸K<Ç!àZÒEÂ#$}ªx–û© ë)Ö. ï)†1^Où{8à ŠaÜö;ဗÃí#÷S•jp+÷Éßrpÿ½p à<GÚe½`ûI›á-Šÿ'Œ˜-ðÖŒÿè‘É¥½{6ç‚‘X½Gó?ج½·àÿ•Õ<>fZVt¼mÚ¬¬³PÁ*ÅØÜdÞ$2àSºÑ%ÝEÝe}k$3| ó¤Æàg•O‚çYõßkÙ9õ?`¾¢þ'IÕò/’ªõ3’ªís’jÄ$ÕÈ/HªQ_ð¿BòùG@Í?²Tþ ä³ *‹Ïƒ²rXe,\óPþhk)x`ç¼/9š³lªcïGŽ–¬Õ±YL'šOÉeñÌFD¨ „Ü¢pz%BnÍ .eE¢0£H˜ÍP˜{pºkN$YN6Az“ ~Þ†¢:‰Ô!ÝO GE1hãšÜ­„îÕÄ[Ї·Üx‹_ª— ÇÛ—¢GŘßq‘ÇÈ•0F.YŠU×O‰$ Š-âYºI ÿáã- ‰§u0dû1tz€M¯-ÂÚýDí¶í‡aö6…ºïÊÔ*¦Îo*v~û¡ó³E¼*¾µßԺܣŠz”—ôÐn UhZÃÿûå®dJù©jѡȪ_4ÄgV:í;?Ê®„Þmôní3÷;íý~ž½{¶í$ãšuC}Ž/‡É¬ Nï@ŽØÌLÑ*Uë´t‘×wë.¢Íèæ,á¢Ã"ór‡¡Ã²Ú^¤@Ó•k:v^>;Ôa•“ÙZ{ ºVé°Ö2ú^/:¬ ,³.Ýs5Ý7¼[v]:LüP›¢½BÁümã_ ~ó¯€|nßS—Þ/0bQ·Þx¦ÈiŠsT‰s”Áô Û=´u‚Å¥Ù¿ï“ ÙRöü„…1òÒG¢¿Õr6Íè@!Q‚'h2Ó ‰ÌÿÜÐ>³Êiß s°*Ìš¯R^”bZ–=YwÕŠ¹=ï’n-zo0ò»¶â¨n'>öáã>áã>Žáã>NÃÀ/BíÑQ­ýä£ZU 'š3Y<§9ŽÅ¿o/pÛtïκ™r, æ„僘}Î ðø¶Pšýâ‚u+ú§a»ÉC{«¾? óÖ[Ýk~"Ìwx“¾EMú†ûv·v3êçɘü¹¡ä?AtD ÚÛï»Þ÷VƒöQ‚~Š>TAÿ5SL1-×)]Ÿaº`fø ’„'7;J90£ÔnŽú.Û<’ÇÌýíöZò¥ØZÈøÊjžƒ‡Ö µ¹,ÑÔ‡Žsz6ñH?†”ßšŒ‡RòÅG:|XíxZ&V™e-ӫ̲”5dlŒ¶A"*ÃÓ;VaH' ñàŠ÷ P%›)ÊçLš™.Ä ³žæ\i²OëŽæúTÁŒ!Oü MÜ 1Þõø¦ˆ oŽ<'ô1Ït Z) Ï ­+Eui£^Q‡B+p!µ–¢þæß’‹ßµK‘Å‘î²,.4#"GºcYiç‘öa²h=DÂØÂØƒ½ÔÌê¨ÜƇ%KÞZ³x Ò‰ÏË›FW›üŽ“_k:ð÷1pè³ëÿ#ùPDtFˆè@w¬!m\"Ò®Ñâ@áñQ©‘ÐMŠÕ±±2#$ÔJdÿE‘ýà û/†²ÿVÓ/h. €áp)p»IÊzIÞùI²JÞ¦´T$yVHò`wl@ŽîRÅÓjRk%©hRW£(k4ÕïâÍþð„­Ë"õEúË¡Ôßk,’|;àY©" EºO‘ºA¤„ôCN£¤àˆ•äï-'ÿ†@ßÇ úƒPŽ*ëÍ!tHx¨êPŽÖ €QP¨'€·–I¡½}™¥ÃJÙ«°tM ŽíC1§“Ò<)[ä ê11óµˆ:¢~ŠšÛ©f¤0fŽ*ÌŒS˜¹.ÇѰGAÌ{,f®ˆ¨#!ê•PÔ¾5¢¶NomÈi­‰vaúq%·F+ÜÔ ÈÑY‚ì×é1rK>zÀ@1ð@~§F S#z²°¾RØ£°wU éÃ[½§Ç©K'±.ÒÔ¥‚Nïäô¼,ÒsNP Ï…(h:ª,Šó"êˆz>u Eý—Æ¢RH–÷Zéoך€’duÖ&n¿>sR¤æZxz+ü N85¡í›Y¸}óe'‹‘ÒƒßÚí›YáÛ7)ºí›Bj6B V¡fë f‡CöÖA Q¡Êj¨ U®ƒ*‡¬‡¦BÍA¨á*ÔÔœp¨!z¨"j.BP¡æê æ†C ÕCT¡æ!Ô(jžj^8Ô0=T± 5¡F«PóuPóá†ë¡Æ¨P j¬ µ@µ ªH5N…ZˆPãU¨…:¨…áP#ôPT¨EU¢B-ÒA- ‡©‡š¨BU Ô$ªBU5JUªB-F¨2j±jq8T±j² µ¡¦¨PKtPK¡F롦ªPKjš µTµ4jŒjº µ ¡f¨PËtPË¡ªõ»3U¨å5K…Z®ƒZu »j¶ µ¡ÊU¨:¨áPõPsT¨•5W…Z©ƒZuD5O…Z…PóU¨U:¨UáPcõb_ B­F¨…*ÔjÔê‡(“é¡©PkªB…Z£ƒZ5^µ¸žÆúªßâ$An3üëQÓàþÌØÓáEó"YT³rœàÚg¬sfµÓíIüþ‹—Ò=&o5¹Ïe’+³Æé>àl7‚%>onoŒg mÒ8mÞ1%‡Ó2:éŽQïAp)Êe¦·29Ýϧ?c.Ür^ ¢iÖ¼UÝ aîŒ~»£VZ7[‰mÖ¼9fùüwž¤fÿ¼Ø ‹ÈšdÏÆµåË`XÞÉhlÖü'«·²Ð[˜³ìÍ?EÓûZKüo†V¤ÿž¹Ãˆx7K!{‡‘ÿˆ¯èd–š5çŒp¾êyÌsÐ ÿã m«¼…Qóö· ¢ ¸îjíÛh„É>ª¸ˆÏMxú„÷g€ì[c%ýo´á/>í ¿›‹o4™ˆ„?%£8˜§Æ‰®·;0z!£ …Šûí;Bn5N¿ïN¿ïV‡ÉÀØ'±Â'øP%ÂÁï»Ýa2šÞοáñòØ=„ #»™xé>b‹rʹÑÞ=ªÉ’¶³5þõ8 –­ì›(&ê¬êddÑ-’d}ƒ„Ìèo`¯ìÝ]Ê> %âèç,1óˆÓ¾¿ww–}*?—ºd••Ž’&d§ç-bªšÕ}Ï¢Ö~zU#š Ï¢Nù«0¨œùªbVU5({UQ5 Ï)Êgõ£OÛëµ Ô…ê=½›ÚØÛäŽÀ¾ÿ‡½7‹ãºÒ†ûVWo¬ Z[N"'DØI<gâD%’Ɖ‰ã´F3 ¤i’2_ò36š-“ í;  !´€öÕÖ¾ïK/$kß…6.’Ð.ñŸsnUW ²<Ïüóýÿó|Ï]U÷žóÞsÏÝ·sŸ;çï{®o =–Ýp@'–= ú€nAÐæ{ð¹¼ub½æ«WVßç*«_ʾSXÚÞ¥¬u¹:¾`¡¿c›¾í-Þ¯hgƒ@€ìû? []šûIhu©ÍJÔó©Ûlø¢æÿöðÿ?šóm/°Èú?£•ÿ[´¾`ö4AŠ®Y·†èϺøc\ÜÔK=$ÚåLPÏЙ ž¸O¾W›3A[ÈA´II¾·Ü'p!q«Î1O¢ã¶^âô:B3Ȥ®.ö«‹½qÓ»Ž1O!ãŽ^x¤è#Ý‘"ç#p&"š–¢ÅÒÂXló&âO)þ”ãÏ ü™ÕS9LkÇóòž4áÿÆ•=Õ™ˆ½ðGox„”9B2ŽBa«GAZuBÄQ£žmŽ‚ìêÕÖ.…a˜BNè©ÍíîÕÖ¸D(Ö8“*¦qj„Ü@îšÜ{žÏš&XkëA`­ ±î}N”§²C§‹}é“z¶9ѳ¯WÛÓUú(ûÒ'cd§è"»¿‰+7‹…ć@âÅ!‰tÄjX¹Y"Xë’ëAóMÝÌŸ`Mz2‹åNGAËÚÆìP¯¶g• ‚vV¦é¿€ÛÌQûÒ§¶Í9G^(çLCeN×)ÓGIj_™ ‹¥BG@KCºðwĤÌÃ/L>`Zb ôj{PJТË*½Å™m …ÛŽB!Ü"Ü„»"îQbú°]õštT óÉŠz¡~T&lŸŠ9й€ý44Z÷BJŸJŸ£Sz}¯¶³ en€’1žO¦žß:FüiXÎ ™¶‡Ø%=Usé\E©0šPb¶Rh-1[ÒÚñ^mÍóÂN%e•`= ¬«B¬Ÿ?_ÉóL•gžªéUža´@‡…@Ohb˜¦}éÕ¨Ýùø³ §¶Tw²Ý)eï¯Ýz>™š§_ í Y ›cœ×­˜u&’$lšh2|èÇ/0îÓM…û¼Ú\øÙ^¡s|Ïp¾ä\¯Ð9¾g†ù’gáó%Œó%ç5¨V„º Aµ Zá¡.jP…=qßUØSUØ3 êê²U„PW4¨"TQ8Ôa#ÔU jB5jPC PC¡Ž¡®iPCêº5Ô54Êg„º¡A#ÔM ªØUå7BÝÒ †#T“5Ü5<*`„âT B5kP%¨’p¨ ê¶5¡îhP# P#¡Ž¡îjP#ªEƒi€µ;ÆuOƒZ„P÷5¨E¨E=¿èìƒ^ÿµ°Ç`ŸüÖ€÷°W‡võv[E™Nh¾C_?¢s6¸ï1Ñüˆ\ó}o½6¤®‰Ý,a¦àpŽŽÍæf—¹ÒË\¦!uüñ:—ñàGþ þ±Ï»µñ„0^&ŒÅpà_ù¿C5´¦'ÿ3^ÂÞËÌlöJF$x°ÍÝ’ß1Ìç½nÔÅŠ±”9™ƒãñfäqàqğޣѫßÄûÞßÀ©7ø®|}¼å.á©|Ô–‘ù† Ìgpοnã“Õ0^F+ØS˜ýÐ)kmO‰—1Õp9Yðê%Ûmöqfu>YÃ0£m o+ñ¡i>C´ C*˜´ž{‡0ó"FÑ–kpCWbž|B#5,ìh}ߟ´³G­¸¹ÐŸ4ÖQÿ¡ -ðÜ‘«ÄŒe in)KŸê"C›xÍî*Áƒæ$’|ßsšáñðe]Íð–/EeHŸæ’0ç´q1´‚Y>chÈÃ#§¯ëÉP|¾y¬î¨U¨F¾ Ø!Tq# ¤Ow™’ZK¿·íHÛ¤ê‚:ßÁæÊOM0%+ ­ è4 gd–u㻩†ïÆ Y÷œôUdãzMÏÎp‘×>ænà±¥ßÍt1RÈ!´²Ï±šlvFr´‰[îrâ<´OuÈšå’¸Ó¥•2Y %ËIÚj7DK²~“¹gÏÉžÁÏÑkz… §® {›%[D*1_Áì×H¹«{'(µxË=~ ®2xC|hˆ§Ž ñ|ÕŽ&ï!ód°.ßxƒ ðõVÏR#Þ·²g·g&úsqÂxuO"Â)Û!½ñ„±8¦8´·$™å(“Î~ ÇòZÜOðYé||ëm³Ê–·|oajgßê—´é7Iü§=\ ¹“wŽk dÞê'çÎq!8ø³*]dX å3Ç©UŒyÐ é«ùŸáx»¤·~Ö¸GÎiš5.-(埳ÆßÍ9Ó7©¬` Ë?#fûåœUfÏâ¬ñˆÞ¯ÙbóœÍÃ+ÈÚófÑ"š»]·Ú™5¾aœ5>š5¦Ï³êg}žW?ódú¾ú¶Ð÷åзõ9ÇÝÄ„Èä‚°)Ž Ÿ|ùo/¦ß—]ð¼i½qÏ›Ö_ð¼èt¾?}±)k-ë ÄBGnùräò—"~)Ž.xÞ´Þè‚çM Žy.çM êS²ïsS2|JpÊs¥šXð¼½û“ Â÷îG¿ð™º/‘[_ðTÝŠŽNîµJc{éý"ÅQúòG¿þ;Ãÿ?V‚­_jêýËÅûÿúÿ_ú˜/µðÿZ‘x¡E€‘½ÕEÑ]‹GB‹G°S2ªw›E€Ñ½Å´=ò|ºH§qÚ~ŒÎADZ½Å":vtÄhœŽñ]`<‹Œã{[@°?êHÀv’j~ž;w;°'S?ŸãÏUèÓÈ´0¹ ù—bŠjrÏû 4E5¡wÛ N%Ô§ÿƒm'q'ön;Ÿ¨@梄uºùÄI½ÛNk‡â«›þçBèÑ 4 =ùù¬Êô³`¬Í!Ö)ŷùÿ†¶º¥½ÛÎýëãëK?†1=®‹iYâçþo qÇ‚¸·Câ–wÄj˜û¿#XÇëëTbýyÇ1} ›À¦©ëê,ëuVs§¾ð‰Ï»3<­wÛYVCt”“ëéaˆuú‹Ë¤hÿ”:ÓzQ•i—¾2í Ïx¡ß‹ß¡™ìEÓ˜ékb{1|ìë,ÝÃSÝ—¤Ã8ªÐÕÀïÃ@yDóÒ‡¥£e¼ƒ½åˆˆÈfÄ(‘” Y_ϳ½Ž×±Žù©o +g Ÿ‹Ê™„ϑ̌ÏQLÆçÕ^–±’ó)Îå®`Ö)à4¦‚Ù¦J^*x™¬Âk(§I¹àM´ðF ¯ø²(_Áð·ó™’ß=×å­rÕ¾‰÷Ä¿FЗ¼÷.Ì~³¡ó['ò+¥ì¯ñ¹L•ðØ«”;…/áíÆèU#=ö¹¼V ª× /“œ‡ðƲÕè½8×j~ŸJÎè· ý6Þ¢X¥ß.9‹€Þùgn¼äÏsð‰’ˆ„ÇñŠïötâÔ$IH¯82ç÷q͆ç©”’ó5p\OŽó¢8šQ&“ßd§„¿vG·É­­rí³VøÐÚš×Ú ßxá§·õ6³È¨,LÌzHL|“p³þ É—5+ÙÄÏHÙ[%÷+Þò>ï¼ä¬­’ÄÏ*N‹2|ÞjátIrW»Üçúæ^À/ã•r‡¡xDF9oŽ Ãã¹0øŸŒ[ Õ =ÊÊ­Š e^#C»9>™×ÊhUQcö#s˜' ³º?‘Qo£Çq•ù¸ÌO€ÿ¹®~2!zRÀO#Ø„d~^ö%&fU&Kü¶r?DØÇÀö¤§÷|WܽCb} ýž©ÈÏd^hAîù®¼È‚×tje€˜JþÞ Q§ù-A¿eÂï"úÕk~»Ðoð»„~ šß)ô;#ü.£ß1ͯýî ¿+èwœDþ.ú=µ("?µðV ¹¢(£Ð:€±Š(\éʇZѪ¢9Í 3Èß»áG¸‘…üz ßRô[ ~£“éŽáUð:29ƒ¯ä(ÁI’ ?’o°*l°òM@Ò¨H°$Ø&PðŽðØ=™Ìw‚óE°Æ®|/ vJKõëøM🈩~šRý×Ti©ÁܱòòÁܼˆ=1™?"wZ’}bõe͇LüžK’Mxi./²ù²‚[‰Íç™c„ oˆÔÔR µ:¯²Q<¯c<Ïj’íD¿Ýà7 %;×[’#£®KèsІuá|W=ÉwÐÆÕ E GlœÄjâ¨Í'Škþ¤d^gsAÇá8Ï…ŽÇlÎõèø¹pœý t€7¢¥Éü¶&Ç]EŽƒAŽ© Çc õ24æ‘Q¢9 Ø¡Ÿ÷f×øéx ¼–%Ça{1ÂáËþ}æïMùåÉ|$8—'ãén>œqš1¿,™sd?6#CÖc3ã㉷Gî‰O Wäɺ>S>üN?’ÁâpE¼ÔÀWNà(BîQ;ŸêPišCI$ç»À3‹ ãSñJpb Ô­¤×îÈ8W „ŽU9²ŸŠ@žB óB° hT‰tðª`ª`‹ƒ2ÓäH÷ V pU+»Aô¯þÏ0³7jµä ‡’8'  É3§HœÓŽü¬CTFÏœüy­·ÙÕHj¿|‰u‰õü–Ã÷þáþ&Îl# %iXò`±µÂç-I_ˆY¾¼‚™:šØÔ Æ9x‹ƒjþБXÇ9è±Â/¯u—ª<çâä²:þŒ^×ó¡Kû%†Áëðdfòá=êøÈŸ?@õ×è_bþ°d>Ÿ%É|7 ³]Ü.>{ìÞ­.R4•ý©Ëcñ.·ÁÏR[æ§ êž?ŒòØçº–©=°9ÉeC·­E‹*qI´èâÁdY´?þ ö!¢¡gàóŽMÆ®AܫಖˆÐ)w¯‹¯S¾Æ%çîsñõÑ~mèÒ½³GŒn£ùÆèìù®Ìù.¾)ÚC­5c6û{¿Ëè—„®~pyÿ87 ó­ð•ðÛÜUV¾M¼­´òíj žˆ¬ƒ.‰ïŠöv°,ù±p•Q%µ'š²¹ÝLè‹VûÌhÜ‚N;oP¿7ªþS¨ÄQ0>ŒÖWA+D-r9Z¨9îD‡:œw£¡=UÚÇû^‡¯§èÕýUú.Œï¡1Xßßë-AzÕ÷ób°õÄŽñ¼Ñ1žÃkb0Éâ#²¡és]sÏuå«b¡ze¨ÖO>)ú ^#ÚËÏbBMúú­IߣoÒ7ƨMºs|îA}~‹ð®C§+îµ­ µcúà0í‹ùï!%¢€‡cü´U¼>¦£»!ÆÐ™9ÓQ‹}ñ6.™×D Õ˜õ(Ö#k‰uBëD,?…²ƒXg5±ÎÅŠY² ð\ÏFá…3E×c}¤ˆ½. ï†òµÏ…aÞ$©ZQÂ[ê;Èw©®uµ÷]”åqo+È2œdyL²\ÊLOcùÓX_áKuÎß`ËYäô»‹˜×IR“œ˜`ê‘u}€…®£ë0§ßtÅCqæ%ôš´h$ã#œ>o­ Ú*Yøhðiéï~©‚àÏbýqÓ qëyž<¿Bq¦8UqÊœ¼ÌIâ`÷‘Osú“Š~ïó.ÖBî4SF¹Ó·¨À0žö–!Œÿ ú0Æ|'Ÿ/ˆa,2D9«è]3¯1Ä—œ‹ÈâšÅR-²ËDd!ïšùJ½ @й Åj”âIáB)Ö‡¤Øèä…ßE)¶hÑ¢ð¶¶ùÞ®Gßèû}'¢·Òˆé[ˆ~À©d±N~È 9X2?ìTfºø¤.LEêdZ~P©ëüÀ±'Í-èŒÝÈÏÞ!ÞSÈ[” é¢Ê{ÑÉ/#uI2¿¢¾ŠÔCˆz å·›¡hßqòf¤/Næ·ñ9<™ßjA=7cjf™h$øÒô¥9ÆwïÆw¡ÃAyî‘ÊÀä%slªÄXD/±|‘e×?×LØ{ƒN…v äO¤n>Î5ŒKe,:F6ŸÉbbÿÒ|¤‚ñotxûØ7|¾ô Éê½Ñ7ºî¾Ñ¥ãÛ ŸcÑIÜ-‰«%&@½‹›Á… b3øgÉêfðÏ’hb*^x­Û >)Õl‹‰Îˆéû8iò^žUÌã~_XŸ‡Ç‡ôƒ&V=ÐüÎ È?ä?ðyoÆxkÍ7ðw|Þ¥ªI}œ(ø!Þ¿éL†–¥‰MËÒ‹÷BZ%}±™¹ß+AxÞÛc¥sŒ©+pzdÜfƸÝâ±»ì†6àǘýi³Ä2NN•!fƒ|oeÿ)óO¦Â?Õ‰úiXé§!¥ß—¾1Ù”Û"ÁË&x9ÔÅŸT=¨mk7chÛZõ ”*´‘šT× 8À20Sá £5×/ÓNiÈŠ1±hÿ of_Sa_•€ÿÂ]÷ÃÜŠ xMºçò¹Xîlº×°Œ4-lVâZyªÕ+lV&lV&‡í©d4«ªAmF¨iÔfÔæä/Ú†33t_ˆEà Úa!:­ßƒ“?K˜Ö Ëje`f*íÞìüµrú¯!oÐ9èœýÑ=ò÷G“Í Y©6«Í~(–(ÿä{+±!1ON̳41?Œ›?nb 4wø1tÃzÔá KzÔó÷œÌøEVS V0é?›ØÑ fÂø?‡Tp€ó¯âü2”ï1HF;‰ÿ¦w, + ÷9¼Ç]ÿï¡Õdÿq´ÙÈþ½£nøžÓ\‚c1Œ|¿†Ý¨"£€ÞkË7 õEá}ýçm‹>‚‘ÞŠ×0„ñ¼X×_nÔã†#<÷+>1âw(heðÏG0ZßÑyèàÁy¼²ôp4ˆð8R¸Œ†gü'à0–Q}½¸)é%qp¨±—`*À5ò@Aþâ|z­Š®º ô%:tòÉ=íâËTŒÒ¶²/7øhè+TôRƒì«tèä“{ÆÅרïkà8AÆ×ê=º/~3žÖfÖ©ÐÂUX(øLŒî¹g]|ƒÊþƒ6¸õ!ÜM*ît¸[t¸èž{ÎÅ·©ì£tÚ ˆíDî$Nû+гÐÅ.4yäžwáEŸ¯¶ÁÞkð aï )úUö½žÑ#÷‚‹R|ßk“Ñë2:yê3ú]FyŠ`üº`È+÷¢‹Õ`¾Ü&˜£º`ÈSL.˜§¦A yå^rñã z7Û“ùçªm ­Ç„;ÁŒ58V8'™R‰çoMæ§X*¿Óˆ³-­@…ý“sÌ—`‚êÊù=\’1T…ˆ|E«æ®%Ôƒ×à…)5\Õpo"8ÐýÜUÿ0±P«…µå]U³Pƒ„>÷TŸz~Ÿ.âóªP)z¨IðH­Cù3–³JÊ^Ñß{Ùå¶}ÈØOØ› ¦l( ÓÆrWõÏ_%ñVæ^%%˜@# eÁ„ñÌŒ—€øÍÆ ¥ìx÷å®X' ÇÜ'" #Cq+dE*^cüjÕGI0ˆ ¾ç£qû§Ï»=™z{$ÐçÝšŒâN÷mÉ¢öG÷D”| BÍNUÍ? Ø·³¯Ì?l ÿAg„ù‡-ÉD„=ò9©6è‘ÿ¯vlA-dÌÏr.ôM` ¦êü }›Xã_¤z–s\ެοÅ…Ì|‚å\B©:ÿ8m´ÉWð íW-WXÎå¾I[•˜ÔâML:“œè2ç^Fk •©hïá»Í Ã}ãK¹äƒÄïábù;’!pŸéS–Ó$%æ7I6h¯ØºõQTV½”}Ìæó®Hr¿T’~̆&5ª¨Ï÷m4AaUÝiས2›2øxß‘ì½êÂA©Vè¢þŽx†˜•}@C̼ØL¬ØÅN¯þ܃f^bö¹·½‡pw-á#Ìî }ýÝkËÒ·¿gá˜G“·?÷ª‹5gï·eí·AÀ ±¨& ÿŠB«€Ðø Wo‹Tø2n¨ãs ÅÛè*|O¥Z°?Oœ U9šyø.NU+r¶H|‰sIHÎ¥f÷ž=ôB®P„ltñ•(Úí{À>í€@Æ5‹ƒB´‰‘ƒ‰õìšk0!"Á_P,hæuš` Š`0Æ=&;ì¸Ù}©¯_/ØIE°k.~:¤½3f÷:åü³øF1çPìE$vÿ Å.„ÜNìñ×Ðåmò®nÝ.ó¸ xg2%cî¡qøhzõyw'ç^íÌÇàžàZ(Q1±=DîÄMÁÓd÷}æ=“Ö½ 9¿|YgÒŸä‹Se9&¶T"zÜØœ`ú¤¡‰-üÓ:öÿÂæÈ¸ÕÙx¿6^âóäH“˜óõa;ƒËBô­êÞy;®#Î)cR­ÌkeäKd%çbEý:îH‘Tqĺ\Fý.—ƒ|… Y“’WËJfR×jŒ.Ì2ëˆq0~*«y7ÈJZ«Œ›4Æk.LÒÍĸ·È–*ãvÙÄÒ¼Õ³$Õ ê©g¤žÃ2Y0ê9,ÔsXæ>RÏbPO@Q@¥ª€z™×Ë.ððcš’y ~é;ß“(‹—ƒjÇrwBOvQÅÐ.ð RÊ0ãŸÖS]Ò¨Î(T#1žSbrbÞµ|Qy½]Æø-¥n•ˆ§Ì6õßM·e~[vs‰Ì%Ýèâ„NP «ãwˆ?þ'¸!hÔ»b£~/\¼ÁTîËþ¤Ê26§Îù&|=V3…2%ÇŸ¨i&¨ŸªÔ¼Ð‚£ìe4~‡Â» Cá=áCáÏuçd(rŸÛ}9:«ï-÷e<¹¾‚Èï+uùN–}ý¹ãä³à0-þ-÷l ÿ5Œ”ï‹`°uZIsD½Â̈a3虑XΕ¾I õMMÒù‚D—%÷ 67«Rñ8ÎKÍÇ+„™%zi¤æ]²ŠÇõ{ófl3¶JîqR¨œoÃ/QηcC»š‹XçJFô{$”íéfÚ#ñ}’»&ƒÖÁàþ1ïÚøAhmN&g½+ñCäsˆ|Ö}ÀƒÏ)áã—|þ÷w[¡ %¬ÿë ÜÓÉ&gìIîϬ´Éå¾¥ïÈ€®Á|úÏ{6¹‡²ŽåÄÑ÷ÝÉŒ3bŽ^¬M5›cŸè×It(×%*×%~SÂò·/YâM”¿`rgœjl–ðÕý¾÷DŸ÷¸˜šÆ%Ô;HH¦]-¾&æËà÷èÈù1ø |þ{ ü©øSøSèZQàû!ð"³84ȆÀqý·›EàØ¡f6†ˆÓ¯Ã±eø4ÄnI5ÁŒÛÊêød3”ÇÁŠ]·yÖЂÃÉeñ%XÝ@±-5'íŸÌx©èËÍn(§˜ÓÌPÝmŠ)™#›®óÑ—Òfµ”b½9Û $Þ.e•Z~ü¾©”ÑJ•–Ï3û3ø³¯ÿd”­ÏR­ÖXçt‹%Ô¾Veš–˜›X©‹ácú¿IËà1ãßÌ«áq¢‚ÉkÌ|™9»›Ï;Üêóމto‡Ì™ÝäÂn ØêƒžwY%¾º}’<™¯5g?z~ÝÞñ®êÇ×™ƒ9óÑ;–ÂGïäYøgæìmßñXh*y=jz=iúÛ$¢Ï¬L9ûÌ<€„Ù_º¿ôV¦e~)V”‚ȳ!U†üP#âuS§ðµz±TgæWÚ¤Rü`ÒŽfì–™_‡(x÷g¸‡[+ó$óøy Ã=&²2ß—Ìo™•òpœ›¼Ù yã$äÏ“±ˆ˜ùmp¼ƒŽçÀñ„âx[Ìî½Þ}è*2.bõÈÚÿ>ãPæ©V[¬s‹™dF­*$Çé_}˜ŒéÁȘÒBxœ¬`æ%Ôçðú“ãNc4NA‘±Ï‘Ý "áÖ©?ߟÌÇʨý±2jE?>NNì¼Ý5ý—5ýO”=–ô]¦ø¡Š†,Sd>Eé ÏÊËdº0:-à2ðTt&ëÔ€®ÓÑu†¬Ó§Yˆ—Hz˜-Ó.Ðûñ*¯”}ÝQò¹ò¾@‹Ta·z¾œá7CÒù¼G’+Ó÷õg¼F8'ŸâT+2ìRRÇRRÇÊ~ÐßI쪺¡£ƒº æ‰¯’=2ê"{ÓÐá íqÆì¾Vög‚Zs6×›R#äXçe‘ù¶+ Ù@I¸]m§ =]VÚ-øž¶JÜ ŽûÚêp?8h«ÂCš ý”â³0ÁNW0é¨Ìë(’uÉÕý ¯“˜ˆ4¼!\›JÔ±#1RÄ+ p2”8§B‰sã»9­ˆFÐ+2o”aô~8™_“Õ~öu$ߢ#ç*9ÇÎŒ/Éï„Èï"ùÖT+4¡ïù#ì*?‘±™ƒ_Ñ>•± mƒxF¾Ïd¥l•± ùbÿbU(?&ÄáE€á>Ââ÷Âp¸3oeÉÞ¦kåPÉ£-´æxZ¬9ŽE¤í©dpÊT¤2 Ÿj!,©i8óÞruÆCÓ-jÛ oÔ¶òj^)agZ¨A漃úغ‚] ØŠùPé_ìcÙM/ܺÏðÐ9ã¡Ýq!a?h`˖ר¯ñ¦>9sÓ’šsòçB?èɰ¼œÊ´¤Û9ù•xŠwwªlµX4Ÿο ýد™þÒÄ3šb&Á£±À ¿»~)ÿ…1h ‚ïšù´Ì™>™…Kþô^Lg™!e-ÖoÞj´Q¹–eïéê^oq×§»Ò}ÞóÉ>ïôˆÌ=]-xÒu t€ô/gsRÁ+ð7èì¿úGÁЈÿÐÝØ7ƒ÷v_ÅVΟ*lÛ!y_ ï¯Ú¶K¶íàaz°4ÊDôSõN¾ŸŠãmðX;ŠIÙM ’ÊœÃßÇëüêÄx=:ÿ „÷sŸ·ÜBÛa``;Å¢ÿO`oæYr‹Ý‚oBo­ô–{!‚ÿÂç]’¤ÿ&'.ÚÄpigØß„…kúâp……ûL¿òykbQSF‹{þ ôlü;C øoÜ›Ò1w×¾GƒF7~7jß¹ø …¿—¹ó|Þ”`§¿à¥‰¾`~a ÿ{ ]s‹;ñüÐÇðNü÷øá‘q{::©Ë̹#:ñèÀkT'þŸÏ»* ºÛ­0Pÿ£U¦|üojJùø“Ï»8 G¹>|Q?öyËl¹‘?Wï4üDuª9o,,ðy%‘Û×U²ÁªÓÜq!²Áaì4Yâÿ Y.˜*ÁXò7”ãþ¢l¤€.ΣÐíá…ÌO‘¾ ÝñÚ  ,†g"¡ÿÓŽû…HÑ:JÉÁ¾·²?ÉüÄTøI(kþ„ιc:áï¸Nþc¦¾"s‡tBã[ÏâTYø‚ª±75±â2ŸA˜¡{[RÑ@ät"•à;¸ÆÛ—>›í‘ø3Ʀ¨ö!«·èê ´ ô½:E ´žâœh‡ö‹!F¡Ìü¨PV&Q(3?òyW&©¡4¤¶µ‹Ö&javц¥(VÁf}¤X[%€g}„yT>FÕâWtVÁBÀÂ"Ûñ/¿’PüÊÚ‹_­£ Ĩ ‰ñù—Žß5~åjü àò°P…n˜ù¢øü¢Ã2ͨÅâ\ÉÏ•Ë-r ÕÍjȧRUÓ‰ê­ô!ÅÍͦ21Ýù ¹Êtº#i:ÔöUÃTi¦i†ýkøLjÛK–°jÈq‘PÞ”°. Ý=CLÿ«ã´³F9.EÙ/7ËS%vˆ)'Lm/',aNýÛ5Ìs”`_‡0¿ùmSá·uéá—ýI»— ­sçSñJ¸œ0Ù|é0è)ø3*ðg6þÌIQ/€»ñ÷툳ñ5ç4 _SŹðâÙCQÁD5A¦«s™ˆçtˆç²Pòªxº… ¶§¡œ/½ 3öÒPÝ\Ú^Ý\# ²IM(îü߉Ö< j>þÔPAÂðnµ—*W„¦n¦®„4uŸj‰>/VùB ‰òíK¯Nic‘úAǽQo 2"÷¨Œ¿u2ïzúm ±Mhš§Û}oále‘=5ÃGÌ{Y÷îIg0è®gNͰä6»@\ôå£$ð¹RÁ £«úRqZÈøåE܃3,-düò¢a«ÁÅ𭕃 »î‡kP—ªDƒºd€º5×5BƒºŒP#5¨Ë¨ËáPUF¨QÔU„­A]5@] ‡ösÔ ª¡ÆjP¨Æp¨) ÆiP×j¼uÍu-ªÄ(Õ ê:BMÔ ® ®‡CÝùÀ5IƒºP“5¨¨áP¥ÆNÑ n"T©uÓu3ªÌU¦AÝ¢3&Ô-Ô­p¨r#ÔT ª‰Î˜hPM¨¦p¨óF´Ó5(ŽP34(n€âáP[e€š©A5#Ô, ªÙÕ5ÕÁ ê6BÍÖ n n‡Cµx Ps4¨;U©AÝ1@Ý ‡:l<Ú3Wƒº‹PUÔ]ÔÝp¨ FµÏÓ ZªZƒj1@µ„CM3êj¾u¡hP÷ P÷Ú9pd„Z¨AÝG¨EÔ}Ôýp¨F¨ êBÕjP P¡Î$ kPj‰õÐõ0êÆß –jPj™õÈõ(j¦1‚Ë5¨ÇµBƒzl€z5˵RƒZ‘P«4¨)z¨)_tdluÚÍróã"ð…dl…qÛYšvOßÚ4õž¾ÝB÷ô­K3ÜÓ÷išÃ*[nJÚE}["«õµ¸àÁÄC‚Ç@³¸¶¯¯í“üúÏ äYwÀŒ¥®¤Ñ¥LP°¶6¤¸¡AHm Te&Q!± Åò¼6:1­H0Ö‘4V… 1ýY÷\LyǸÁ#ë¾ÞÅæb saš‹E‡i¾VÅ Á§µ¹åð¢ôÕü5)¸E* ·¯¿¤,x¿‘s½oR°_RÓ¯Jù×qézCZ$ä½ñ¬¹z]Ý:<ÛÍ—ð®È&Dáê¬/}v\7×eÿ{OÈnLSו„dÊ Ù”Ð YŒÝ¦´6ëJ›ÓÄGÈC÷u\=Ú’&V•Ŧ·ÕÕ£ï‹Õ£¿Æ½$iØSÏ#šT45ÉûøÞÿÜlâ?ñy7¤Ä÷ÇM3kG1S?ÞO·PRÇûû¼Åiïn:¾‡ŸÈðy‡ ÷ | ¹gâ.“4\6ø%…•…)óp3e5±ÛVöÿÀ_¦ÞŒ:ýƒÚÁõüCŸÿýéfÆ]ÁªGõÀZÚ¹ÿ7 ‡ )|jWâïpãI¨ÿ¯Ž¸Iíízâˆ81÷Ú1ìöºÞ£î¦_‡º!ò‹;Sÿ¿é×Sµÿ¿ãÅ „‡÷÷ý·ExÁ~í†7T„ì‡TÃÛ©U–밲ܥU–ë •åºðÊ2ØÏPYîÖ >E¨=Ô§¨Oáš~m€Ú«AmA¨}ÔÔ–/¬Â÷ÿ«ðKÆ*|m &nNI³°È¨Õ´õuJ3]—rn(§knômb¥EŒÝrnŠã57Á¥¬ˆI7¥œ[Êñš[àT^ÄÌ·¤œ&t2Wç7ÓÔ"&7I9äê|NÓŠ˜…K9Íèd©Îo§éEÌÚ,åÜF'kuþmÄúOÛm)çºØªóï€ËŒ"f¿#åÜE'{uþ]pšYÄw¥œtrTç· úF´H9÷Ð%¢:ÿ¸Ì*b‘÷¤œûèYœ*ŠXÔ})ç:EUç?§ÙE,ú”ó¢«ó‚Óœ"óPÊy„N1Õùúâ–îXpyÜ7iÄz$üC¢KÊ}ŒõãÁ4‹Š~«ùdê‘xÌc¾O ñæIc~ã®ø…wö/’þ¾‡Ëœ¿#à¼kâcpÏæ!ÈQÑß"ÆKÈxÅìóNMÄÃUøôNL(ÌÅu¾î…¹_ë¨ï#õCA¥P_èZ€»øÝÃú ÉzõHÜø†çHtÔ Ô>¢~“¨g õ,AÛÌ+èÕ[šû*½;R¼p‡’?Í"EE"–ùê–ù2ÈGN<[SC¯þÜÒ^+ÓÙšZÀ³5‹e÷ õÐO ­YF~ÐÛsñådù^'Ó”i›&Óv!Óti§é!ÊÔÉ´_•i¿Ìj2VdšžÀ™Ž„dòÉî›F™‚ŠL]ü(ÊtT'Ó”é’&Óe!S9ÈtUÈôeªÓÉtK•é–Œ›U™n+2•'àá ”éNH¦»²û–Q¦ûŠL\üÊT¯“i$ÚÛm É4†^½3A¦q’é1ÊÔ “iŠj†Šw!ª2Mµ™f&ði’išE•iºÅÝd”i–EÈôØ%v ÓÉ´ eZ¡É´RÈ3øj!Ó”éxšdú±¬WeZoá'vÛ¬Èù!Ó–L[-îÛºÃnB¬ŠXO\|'Šõ¹N¬:«Aë˜k¨ês!ÖSë„NUgU±ÎZøyMU±æ$ðKB¬K!±.[ÜÍFU5*2=uñk(ÓILQ¦§šLÏ„LsA¦B+Éô e:¥“i¸z¹Àp+a É4Ê*dš›ÀG[I¦ÑVU¦1V77Ê4Þ*dzæâðVƒÓ:™*ñZƒ*kH¦yôê½Ñ5ƒÏ2µ¢Lgt2-VeZlÅ+T™–+2ÝèÊW™V„dZiuß1Ê´F‘©ÕÅ×¢LguìUØkåûµ*T'ðC"€C¡[Ýwø• òpNéŒôq-ÒŸ‹HWCBœ‘.ˆ ¡:–Fd¹®±Ü,Gíü–`)B– ”Íg3ây¨Æã¡•?¶¢ýPaÜý‰ufõ%æoMá­øÜžÂ mðܖ‡ØB塨&â{Ô·Ù(¾ðPâ;Üæ¾VFÚD”‹òÑ6uŸô[Û›Æâ)n=HΙxD…-·Ùôê]ꨴA‚K¤:òH¾J#_-Èk€|­B~Y§¹ÝH¾W#ß'ÈùØ;5wEÇr YÎh,gKê”ó‚e(²\ÕÕ)WmŠ®¯Úø5M‡7e~SèðfH‡·lîGa:lVt8t ¿zjL³ÊQÑ—mÈS›îtåS›8Adã­6Üä³I¼ÈÀð:ÿÖ ƒ…LeçCíèäþœy/dù¼ûRB†ÿŠ…ÇIæ½û5a£ˆy/àóÐ<† W„aås‰p>Á¼—²ôî#„ûå,ïƒû(;ècWš{õ|å8¢W±YoG·ù»Úžãd»Ò&«Œ¥ãC¶½eÄXŒåvµÑÆév¥áTgjŒ\Ø@Î"ÆYÀXaW[F`¬´+­›ÊX¥1>va+6çcµ]m¾€q¡]©ëUÆñ© ëôZb¬ÆÅvµ2Æev¥BVWhŒÏ\Xñ®$Æ•À¸Ê®Ö¸À¸Ö®T *ã§cá@¬¼>#ÆÏ€q½]­µ€q“]©FTÆ-cÑ@¬¶ãV`Üf‡â¯2îŒÅ!ÆÝcñÀÜ |1îƽvwKˆñ€]©àUÆCc« +òÃÄxØÕv¥ªŒG5Æ¡±°Õc0ÖÛ¡”©ŒÇíJ@e<¡1>qaË’Oã);4ù*ãY;„MáWˆ>kK‚Éù3lm±¼MKìüc´x^[SТÎÕMKÔì.OMÿU¬ìèîS:ÔJO9}oŠ”{ÝÆoáÝ&×ÒÌPÞ·Z¨¼ß±ëŽ ß±Sy¿cç-v,ï~(ï÷•ò>ZRÊ{¡¯J1”w:ò¨MY'ÇÇmÊ99>1”qrzj,ßÂä­±l“[¡CTâ‡w±–ƒb:[<ÔTúúØ ¦§º©Q W¨¦'`¿x„žê–F5R¡*OÀžêh=U“F5F¡š™€}Çqzªfj¼B5'»MõT\£š¤PÍMÀŽÌ=Õ=ªT¡:jÇf°\OuW£šªPU'`ÿ`ºžªE£š¡P-HÈ-Ègé©îhT ծؙ™£§z¨QU*T‹r‡ äUzªGÕ<…*(c4_Ou[£Z PdìúÖ:ðƒn°Yâ¥d^s=M‚ÖqšèЬ¦{fnV0ÓZ_ëÀ ,øÀ¬ÁuüS@Øž‚vO’ʦ3þ™#ƒ¯w¸¹g§ÆùpÙˆ¶@R”;Güd':i Po¿Í$·¥¸þµÒ·-E—ùGFÒdxnsà¶Ÿ4³9*úÏ$á‡:¶ÇAaû|Ÿšgã\Ø~‡2vгa6ò‚¨ÔÒYÖõÛãwh“e-¿¯Å©¼ˆ#Þò{Œwþž^‡zº©ëEœW¯ã9ïà¡^Äe‡èE@UzÅA½x(½ˆ«È2m{×¢Ùæ†q‹j•w)Œf £ø7¦fˆç°ß0|T¾"Ýqð;<’¨JøíÜô%ïâ&컎ìGý‚êý2Н é›(uJˆ…ˆxº„™ #ø4¯“‚×ôP³8BUÉðˆìíßñ{×[hî Å,‰f÷¥ð4@stl„rdmlÝÞ³5%5êSøq¦èGʽ4Élµ2 æÏJüskª`¬·•û-P ™ßÝ¿¤°=Âñïãñs¦\¤u8…g>ïá”ì—3_ÆÝ¼„ð›îΩ’IᣀìˆF6ÉŽ²±8Sx? mF£ “ðÐ݆Fó¤1Éjë„®Ó™"á™ÈñToµ %Ùç"Ë<—’`Ê­²ðjx*ïóáý¨ò¾Þ)Y3?0ñ…L¯’EL¯­ŠåÔZzͺb6ñÅr]B¯äº…yDŠü-ʲнn1­aMlûÆ62¾Èϧö¯ãk™ŸnºYÇðϘïýßÈüÞgÞÄ¡û )ôiï²229µ™ùéη-Øã4Ùaµ=¡˜ïTCÛ ¡Ýÿ€íÁ@³¤ÃðØ‘e>Y²»²,~xŒûÀ„ÇèlGa€k¼]H)PÏ÷1\ K;ËÈðð~ô óeKZŽù“¶g)ç4ŽÀÇñ‘'s|íT¾,Ü_»”/+Ú÷ZÝ?è‘çPå’gãGÑÁçõ§x,sÊYÄ x>{)ò&ÒŠºE)=N‰/aŠÄN0EœáQü^ÜdxÌúx¼ùuX9ëT Ïå¬s<×”³.åð¼]ÁºN…ç öÒtxÞ­`_™Ï9]_®’ø%!¡»ª$$¤Èy,S-@Ф¼Iy‰yäô}ß0NÇËW.ÓaMH¢+”Í  q®RÞ†W;odAï4ªÊÁo±„Ö¼h~›_ÃÒ5$ïΡx‘Ð7<¯}•Ïï2O„·8ÕÏ[˜' [FO”woüÇtGbëÇÀŸy¢ZkËÞÄÙè7<Otú½~Lsá˜Çê‰ö– ì.šÑ·'"·d m_ODÖÙÆ[!¸Y%± „êù×â>nmµÃþ þá’÷(‰Û9$.d>Bòy" i¸„üçþQ’VaŒ“‚jŽÏ‹áãáKÍò±||©YÞÉ'—šåãødÀ¸”BùŽO‘<ñ¤Šxï„÷„*Lçu⥒GötJŸü:û8¯3/“<΂¼.¼\ xœ•ž¸Ê‚¼®|ªôÞ—üs ò^âÓ!*y_á3èù2¯Â¨½âì-¡Ý– öÊNÈËËY·]ð\YÎ^Ý-ñjÉóŠÇâ­²Da7d¾ú~T áÄþÜB” :}JÍk$HÓÑy•wZNwËÕJÎS ª<ˆÐN~¹ÿ©„’x…¤¤%þJúêÉÄWIžˆ¸â²ecöW×H|¹`壯ñµ’çkqhëeÄMuü’âkégR˜ûÏ%„¶žÒº¥Ù¨ñD€@Q=²N¦Èx•p„·ê ²V³UòØ€[’OçÚ¼nx¡¯œ`q—u’<1 ¾WùnךN>_å{%O7êší“ܨ`Ï«•žØJô9螯zºf]ËøAüxÕÓ%kæ»? ÊL0uÆúøˆäyÓÂOÏWç`r$¼çæTJYÖðX4×Fž—bldÖÆ‰WT—<õ²½neñA Ý«`_; v¿‚}ý¼„7 {¨Ê¡')'B&E-œ’<‘=r§fòÓð‚ñ·SüÏH;P`üÏGú¢w!w|ŸW%ëÎ/€³çëJŒ.âGw%FUÒöWœ[ž¶ò«TÏÞJ3Í7KüZ´Iñ|ÅS‰gö®‹ÏØ7ó^ƒ˜z^³¿–û ‚ß®] ·æ¶F )üìêqÎñÄÍÁKñîHAºïäëÍãÑ(ÎÓ4s¤Õ6KÂz{2tv^Ç ³¯ãµZU™¦ÉÂÈ > .5S%\fÆjR.7cMj™ Ì:ËŒõ«­ÂÌKÍjõWfUåfµZø4³®*T^,e8HàÓÍ ­|¦Y+æV>Ëì‡V ª 3d[‚)}}'éc¨çš=öSÔ ºëgöy ¬ÌQmæóÌAÐ_T”ÕfÈQAïvóµ²€|Áç›!Ÿ:–+pC–]Bùo†`ŠAÔv^AàöÝ4s´Õ6ÖŒjÚ§ªIèhŸÐÑ>¡£BG…Ž H7Ö <V0Û13Õöãð|TÁ'àù¸‚Eœ„ç“ yÊL–ï„j:<¤Óᑎuè# : B¼P‹ªîl¼ÐÚê‰ájDNhÅú§b~œ¾Cʨ]ž0S9¶a9F%ž4Cy„Áb ÉOA OÅx²ª¤3 ¼2aHÓ”Q•Ëts–©³”¦B?oö8Bô‘zúH¢Ga/€XüŠl2µ¦YœV[ %˲àÊ‘Õ ¼zé¥ {D©"=¦T1ÊØÀËE2v ,ÃeL#ë({¶Ñ2öìcdì8ÆÊ”RãeªË#'ÈÔˆš(S=I¦>AÌd™?RR¬ž?VR¬?5”Þ[°Œn |fîžAæE2ʼHöÈÔÉúÆÈ‡BjYb‘¥X–á@æ×*{+/‘=VïÄHºÖjRŒ’¡ä¶ñÑ𥶌v>¾Ô–ÑÁÇ—Ú2ÂNö=‘À‘|‚L0ù©š¶ÍÁœ({ÐM’ƒ~QYÇðÉrÀ»RªÒQ‰ o©ì‰$êe2µ5H:½‰§ÊÙÝ/8æ¢HàØK"—EÂÆ] Uæ+e5WÉj¯‘µ~3N¹­u %õZL•õ²Ò“ù9¨uô6B¹òcOëcHËM– ­Æ`-ÖZÁ:m‘±#Ùy+4­ìh®ú#[eTŠóïý]¶Ë|;øzº~j¦»ò²§ë1ïééêš9ç^ìâ«8V½†> 该µ˜2{h<:w©hmå»Qö¡lj㡈B Ê9Õ¿”âx郟.oÚùÙcWó¦)è0Ké¸!GQ‡ã(d#Õ±NVÚYµÃÑ€q݈àá‡V5bD=Ž3º¼ÉÏêòz?§ËëÑü¼.¯Çð‹˜×m¡ú,–_Ò²{äì5^†> ö¯ˆ,] Mnô¯†²'~MöÄRv¿®ewè!FU¢çMÚÓÉOû-üpzâ¨qç"F— FÍð’ˆ]‡;ð‚5ú˜mVÛLA¶R‰è–õô0µbfÄZ)[Kø˜æ2·RyGÉοµŒ²ðb‹ß##Þ0‹?˜[ˇÃÓ[òÜ¢X>Â"r-dºQ¨Ìç; ß…<7Úâ±â!s>x­¹³ßãã,þø–X›[ËÇ‹¯m߯Í}Ã'à ö>fT§¢3i…¼1Û4d(œÍØl ¯°øzäŸJá³!c/É0Ñõ@õ|_Ÿðc?´ÒÀ“}̲ÕVL‘­±`d_j ¬À:YÎØ _lñ%"Öà®KñCŸV™J))üJ=_j ˆëÛ÷•3i¹…/·Ò~`¾Â€Þ5ô £”Àý%ßà«,Aʱ«-Á ¾Îâó§ŸNA{½Å$ÍÇ(ÌŠÔ}fÚbAyØ6!´Ã·Q,PÈ®õ´ß .%€Ÿ_ià;-Á¸n¸Úb Í÷ óAĘï³ýÔi<`ñSÂD…ëcްÚNP×ë¤E ™¡íñ±sakb“ÿ`:iÁz†Ç“—¥s”+Ì-ü´E)œõüŒ'ZÈd@òö'ÂdÀ'8\:X ü"BÚÅ Ñáü Žº;!'íû•|Fž‡Ö`_Õ¯ Ô¶â j(êø+‰ç÷nN„DÃ-YØU¡ô[f ø¼S:á!QÜ)q1…l„¯¤W÷Xæ½ò3Ÿ÷r Ùè\mõò/¦ðµݺ¶t×H|=9â9£>8¶ˆòØv«2źÝêü¯Ûgõù³®ÀH`¿ÕÉ8A‡«àà³:9RÔ¡C#8Ô[gÐá”ÕÙ€Ï ¤£î¹»¾Ï/Z;ÁɹM⃖f¾ZÏ÷XÝwßóV§^±bftccAn 7æügâÉ­å=á&9Ã2r{¨¸™´1Ý(n2^yÇÏ’Û=ÅÍBV9Ï‘Û}ÅÍŠF¬øf£ž•Í.uûÛÖV[dkë«­­ßimM¥¿tú~s̨>²Ýj«£„½E Û¿ú(2)ï$Œq+eé.<‡Œgæx/gò=xŽëb¹oÅŒo}håtrû=¼·ž7[ ¦h,%·­ø]«ÚÉo±½»¾Oð{V(zx{¯…ßÖæ÷°ðÐ ¥Çæ|uÿØŠ=f(3kl'ÚF‚ߊ[`ׇÖí6p"+>ü™F“˜R­½Ñ}ÌQVÛ|ÊÃmúèaù„‡0ugÑaÑcÑkÑg£hއGÝxfÏåÌ6ц}û$aÓ¢=Ò¦F{”mcS£=Ö¦E{œ-íñ65Úlk`W&Ú°v¡Úèí| ^ £!y‘t•1 "¾ù1ô%Ê`\ç±F¡Eær¼±Ø5/]¾:}l±8Õ2|<¶Jª–§ØzFFÄ­‡Ê,ÒÁgØ‚;êk&nüÓÇúª¢!FU[}E®ª]U+ºZ¤èªFÑU-<‹f3ËbtŸÍ¬Kà9t6³-…gñlf_FJs,G]ÆD¬´ñjîæ‡t·t·(¤»îj5Ý-Ö;¤»%ô&´·TѨ/£7tuð•¨ÂHç ÌT«1EÒdT_ ãaUGxlKâQŸ öÄ<ÖJÊgëmÎÿû4éfèÜœµYm«c ^sÁw VD gñ2ì=Äõ&mj»ÆhŒû ŒèJÛöHp²t™ûMÉ܇1±ÆBmÏ,ßò½…©õÝì´ü³Çñ–ûeøtzò¥ 'ÝÖo°ëJ믚Ʋœ'}“vÇ$ºXîÜð;¾..uj6WE íG6›ÇÓEò‹#¿è·™ù¼×±ÆØÇ,EEÿ ùìTWIvŠÙýë)bã×6€ïc>þõ~ÜgGÐzîAzõy+"Ðü!&6l mØ:LGûàZiágŠããŒö$‡Þ2S÷ ÂEÙcÄ:ä3ˆ3™bðu¹ˆ1¸ÌÂí„ã%[DCt•ŒÎsb4KûXAŒwÄ·á|gø¶öÝ1: ÞˆCf¯Ëú¨kwOpí®¼ºv‡CYöÈY»»ª[»+•ˆSvj™ÅĦ)g]zä<%Ž;^AËŽæü§Â²ã9ÏçRþ3p[þ©WNkߤÛ dù­˜¦õ‰e±ÎK¬y8wíðLLWŸ/ý!žƒyŒ?Oñ§ }©1h=né¨6VÛ9£·:·rkmõ„/‰’ÒI›é}Ô“6"¾â¤Í½ÐI›{xÒfFŸ6'mföÜ绑’Ã,¸½í~Ö7ƒÿÀýzVq0É ©ßŠŽ}ÄÁtLŒ õ`λâ`–™ÝÇ*Ç:wHD”¥šuËëDYüƒ!·Áì‡!Cn¿„\Eo®vLº5ä"‚v3<(ÏV|â\ë@ŸwXgýÿsÉÿ¡þ]Ȍۯ0Tzûu;ÝžjvX¨Ï%w‡Û5ËmÇ®Yžj°ì·x¶O[C'”äÏ14ñèÅŒ2Uöik”I~žQ¦¹IÓ¡¤'/f”©ªO[£LX5ÊT*¤¹ Ò”†¤™÷EÒèMDí0ƒ4ÏTiN T¤¹EÀ§bP«û´5R:‰WŒÀ̧ðK¡²Í^Æ2—1Sá2¦’&Ër§†‘ -ªGo f{V‚Y¼íÌJ°Š·¡·]!߯´cça˜8wµãÌ„j,ôÑŠcS°°vPÜÐð”/2@°HƒjF¨ ªÙÕuÛxÔ¿VƒºP‹5¨Û¨Û)_d€`‰u¡–jPw PwR¾ÈÁ2 ê.B-× î î†Ch€Z¡Aµ ÔJ ªÅÕµãÔ* ªðm€Z­A¾­‡*|û‹Î¨­éó_;£Öh<£Ö”‚ùžY¦Ú½²ˆ™~”SØ/Á”_د‰Í-b,#§¨_Ë/‚Ϫ"&ý«‹˜ü‹œâ~ ÿ™_ÜO'C™’-o5—@)rÓ6©Á&7´îQݤY‚)ñ'R~ÑÛ܃}<¨*ó'½Må§}ðXs<1@ËôÏîËÒ/þ˜.FèƒV±{×hìBA/Ñ;ìí„ÖZa¿±äíOœ|öö'@¾J¿lù‘OV{†xËóeÍyÛÄË ë–5âmÆËQú˜-²¥†ùl&6œCF¡#g3ÓlèñšÍØbì•ù1¬¨>8Ù2z6“æßØaÌ\Íø<æwí7ÿ“¼Œpuÿ {H¿¹ð?Ò÷÷—&ãݯó!`œ5ëm 7ÞøóKÞ¦Í5%o»‹ûý?ì½wX]ǵ7|fï} !@rŠÛÕMˆeËÇ‘S(ÉÍ%8:Â86‰oLtCàÈ9!qî÷ÞĶì¼7q@ª †zõ‚:¨÷fuéªVï…A½ó®µfW`;ß}òä?œ½÷”ß*SöšÙ3kæ$Ú:Ð’31¯ÄÞ¿––Û%QÀ£|º]¬»YKºŠ'–7¡B¶@ÊAXÃÖ‘ìOSÌNMö ­ß`Á $0}qË®)ûqÌ~²ÁìLÙÏkÙÏÓ)*Á‚!I Üæ¼–¨ÏQé+Ѻ–`µ4 W«Ò&Ò IE$ñ!Øi—&ñü(ºÙÄÈ,Dš#üÑ-¦ì µì %¾³KâK0ûVSöm˜};dÙ·™²ïÕ²ï•ø~Ì>"‰0û'¦ìg0û9È^†Ù·›²_Ѳ_‘ø5Ì^–Äë1ûSö"Ü@ØW†—fßi–];'kŒ{áM˜$v+îê*+Šý/”¨¿tÖáàÔV!׳¨o3d<Œêë «Õ/ÿìÂáR-Ÿ)‡R°N}Rš-óÙr龃 V#HñAŸ#ëë©… JÒV2ÆÑÚY­.»»*QŠý¼D\¬%V‡µ23¼`5ß"X’·Âµ´œ)Ûá:Îgß—³¯8vÊ|½ÊèFxEÃ𸞇¾IÎyè øû'¹¼îZμÅ^)ó¡‡É^äjSÙJ‚……PÐ>¶É>%þYœâ9Ã¥Ìá’­s/WþlŸËåɶË$éû0 ß9@òÂÁ â;eŸÃgGÀH|—ìs†h¸[îÁ÷ÈúŒgž(°?†*þsO–åŸ{’ïOgŸ„&vöɸIÖOLÄù3-}"«À´>çTÌ’@GŸi(ˆ@ø¥¹óÙCÀ??„¥¾§«JýŽèmp“j¢­6Ñ&Šþ¬Ì/€à}“híÛEU©—!¨_RÂ{4Ã; E©gàTêe~¢@ãeïÕòzzøïÕñ9V;àJ¢›""<Ľ„§&B\ìÓx:"Eˆ óûÆ}RoT©÷UÔ¶§ƒý^VO6ï‚â$<2Äãž‚ õî4gTÐ/‰N@Ñp™î‡àöʽ]PÀtQãF+ŒVø8JO ¯&)F­š¬´T«ÊÒÜ55Mƒþ{8¨i:ÆQªš¦Óƒª¦™J0\FJš#‚u%̓˜6¨¤!XhÜ“’ªTW(ñ>ê ál(†•½‡ÊZEIYkÌÊê›Äךð×™î7 ²öuUŠý}ÑÁÑfWh‡¶môÝ’áåx?&áu4Ïí >¾ˆT…Âw(tà8º%ç»lJÈg¯ùéˆyüV³[y.Ò‰óÅëp®Gé„[ž»ÊqŠý²LÔëˆúH ^dÊ ƒÂë(P0^Gù:ÁŽ‚×1åÌ~?—3ǸŽ+gΣp]ãwÃokå, ¿O(gÑø™xb9‹ÁïÄ“ÊYüP<¹œµ= ×)åøÁ˜Ž•ÐÀ(>Nœø”÷âè‚”½‡ónG1Q&ŇÔp?¦†'2m)^?®k'šŸPÂø¹ ,Äç‚Á ãbøIws÷jÃO‰›¶ü´‚KÐðû&è´]Ü Ôéü(Çw^Äé3'õ>mñÛe´ÏEmð[e[_›¯ÿq*6ԯ৳Å×n@á—Š/–¾nÆòÛ”¬­Öó;Êf‘æ¦i[i _[ìZã¼tÍ@6*8áZÂBnÂÕŽ ú7ùêÏ dûÚƒAìµb©ê‡Oçžôµ£>­¿•º:Ú)ö‰v*ôR;YCø¥ìý^ŽŽØû:ñ·³õŠ¢çhœÙ„ÿ6ðß¶S¯X*k[©Êžá«(^¡NÈÃìôÁsÔËávèë±Ûi‡6Xñ^ /³‡ð¦6.––ö•Ûf<ä«€º4ÁNuÏ1®S¡.Më´ræ*·SŒª€ët¨LÓá:*S%\gBešoçãíâmz˜`Wß:ë¥(‰^$Ÿb‰d.^·”,оªB2—š,šÏ®icÓL;t‹`àùSñ7j*yïõŠ¡µš³¡³ÄÕ»_CaÄð9˜ÁVÓñJDÂJìx/. /¾˜©Ð½B­mÃçkqQ".JkËÛ}ÑÚNŸs ÞÆÑ9Òv±X0Æ;!I›¯ªìê TˆX­Êìsb•Y ׄw!ÕjÈèôµ™³&&Ùùzˆ‚jruÈÄît4Çv¾¹j‹K[}1YI}à&»ʾ²7ÔHè@b{‹Õa_L%µŠ-*ÑŽHs;~?'Ábú`[óÅ ïƒ%¿Ãj&¼?ç‚äÐO±‡¡_xÔÈwc% vu8ûCñ Ù5“ýý^ ÕIúZÏú¾g A=¨þ Ùã6ÑçP´fêìdÅÈíÔ›*‡à:êØ1;¯³k–ÉA­ª@ïc7)v~ÌŽ®LÅ©ÿO©P¡ (Y?Í.?¦²û¨D|¿œ(¨†87ž Z}vL„’'¥_ÂEBéØ1\6Òóz\:€z:mç+ÉÐŒP !²Ý‰7é=Ò}+Aññƒƒ«žÍ¶xä› mñ\çüý@5• ±Cô×ýéš}€ƒ?°ŧ‡öŒFÐvzdïÁ Á¬’l/rÐ{˜ÞNýÐ¥x‡pÐ÷f†á`Ù&¼Î‡v:ÄAÀ„JÊà4-@öé#GKöi#¥þ –:µN¦[©÷&U 芜}¼¯“úKEín\¼ŸÓçJÀe/ÅμˆàÝí‚n‡oÓ**>¨Ãϯœ!è7DP(r⊵ð³¡ð9­½×`'vlcé%8Ä mqêûP…JœÐeý†ÎÄô¹†:ñ±]µ‘¢ø0Áæ‰Íߌ‰á¤yÍG:Ch­D›G›}p^TÈÎ0bÇç|b}c#-¿ã aŸ“¸ë þ‚ =ŒsâÒ¥Ú®2ŒŸ_ â¬tªƒÒJ'_à%²Ðz§&1ø“Ä*ÐKW ªç+”c=å¸ó+ÛzúÜË69ùF5ã&Ì8=‰AÚŒL@©¡q؈Æaè=äT –øNF¬Š©þ@„«±B¤Qƒ Û1`xn–ŧp¿X,v ÂжB,à>á„—[_ÏÌ:~Ò‡'Þvb$S1#€C\?T„î'Þ‚ŠxÎNl¬ ¨›‰w†3ø%äp¨¨{ΫÔ*]לüªSÙ»ø5¬‚Qq?Õª wrN Ô*Ø€…9:©åjˆ|]‡Š‹ ÷†3 r nŽòEÜeOÌo;qÖ®¢,Kü>ïú0iŽ‹ÏÆMïÞq¯Ú²ÆB?7ÇÜ„p—CÈ;öUÚÔñù.1:/M Ó¸¼4‰/Pƒ†'…¼«_·Qðð¤8Zº¿¢“—ºÐ³BPy©@ž‡ÈãTd<V‡ö)ö ö ›¯Â}ü‡iu­j“¹ÔF-ìÌax©†N÷ \—AK9äB¤•WÏ7âµ.Ú߉ÛºDÃþ@ø/š„üÖ•„Gu…’ßßÁ¹B¢/È/‰áŸºBaÜqÜödþf9Oz<­§€äg($=KI í9̳Yæ\Øó¡™æn$Ä5‚_w‰÷× —xÝt©¯ Ûpc+˜nçwèfh¿K7 {¨£4IZ%ôñ ÜËË™{<†ägb¿KNi¶ðqyIz¦`ÑW)°-ú5êÅbÛuQ¿þ?Ÿ[ìq_|Å}?×½3Î}+×½æC÷Ã\÷£\÷íÜlWA±Ïsd!ßñ®æóûãgƒ]Mç9~½aPø:ç8ÏœìjœçH§ºþ@ŽKxØ]$ÔÎsÜ–È×ñ G:Ñt¬£ë‹ëx)©Ùcû{LÇ:.ûz¬£ë7ì.q¬ãÐlíXÇþž@×]»žìúÅu–ýùuÄ´c2TE¼›“lÙŒÖC”M`ÆÑÁ¤¦G7^ÐCìjÈ&=Äa,£Zã°jï–òVŽ\öaÄzË?lí̽‘îõn>ƒ3t4%ýÑ[Šù>•ÙQ&f·þ³3;ÚÄì¶vf‡üšxý¤œøýçæu{¹¡ØÿìÌî41»ëŸÙÝ&f÷ü³3kZëõOXg[\*f=v¯ªqèzÝût!†ggϦ¼}–úu‘Ùt”êÊ©yaµE´*bßh-2µµÈÁo5 ¯ÿV¨ŠØ7Z‹Lm-²%ªË Y¿¥kо—‹Ñ‡ŸÃèv5ZU!Dß§è‹ýQ‘| Ë;þLÂ’si×B¬(Å#b—šòþ¾…Ø–òV™òºZˆy"b«[Í[mÊÛ)"v•)ï»-ÄŠ¼©êÛÏPç:–7‚E$¹•Éš»æÃÖb¶š÷‘¹,kYÞý§#’Ü6'9ÊòÖªI²Ÿ¶4¼€Úð¶~Ùð¾lx_6¼\à ª oÛ— ïˆ÷eÃûÇ5¼Úð>ù²á}Ùð¾lxÿ¸†VÞŽ/Þ— ïˆ÷kxÔ†·ëˆ÷eÃû²áýã^Úðö|Ùð¾lx_6¼\ë-7¾‰ ¯…O_6È/ä— ò»A>£º‚ˆ+Xïý K´½ÿ_NÚ“3.C](âôÍöŽË`Yã3lø8âýß°ÿˉ·˜WÔíolìasMȰ1»mb†M²Û†gØdÙ6"Û¦gÚFfÛìp)˶9à2)ÃæüŠmr†Í%ÛNëž'Ä‚áyb}’æyb}žUÕÔóÄYÕkæéx™Góñ]á5â{æeŠ¥4è»ÿ‡yÅÝP)ߊTŠ3³¬y÷ÑåïÛ åÏ…ÔCYæPjôlïäW9‚îªì9Ña·¶–åM“Äãθf;¯C¢óÚðÒ;¯~-1åjŽ©bb ËõÝÌwm…ïÖÁÀlJL³ª B‚à-è-C:Áþ‘f@hÚSÂò«ìA°I›é½n‹Ò^¥}[/í‘Üóy[áó¦öct¤œåO‰ray'^2ÉqÎ,Çyõávór„…·Aް.G©‰Éc“Ç,r m%‰*ǰn_ô½vQíÜ´>~‰¨r _¢W¹áÝ4K®™^ Œè¦°8•¹ßçUwO´Ñšw+É¿Ežªz…ÙÍ)Å%¸Å‚}um=y`ãŸ@×Ý:º–³ÌqJþÐlŒ€!ÎÅ7p˜SÖM÷¥4]—Œê¦ûRšmñ¥4;Ò—Ò’-¾”FPsjŒ5Ç5'j©j¬5¡ÆPs-Ps#¡ª¬Pã ¨y5Á€šgš Um…šh@U"Ô$ªÒU µÌ 5Ù€šPS ¨ù¨ù‘PË­PåÔ„ª0 X DB­°BM5 "Ô4j¡ja$ÔJ+Ôtj)BÍ0 –Z –FB­²BÍ4 ªj–UeªŠ„Zm…šm@U#ÔªÚU u+×êûÍ€Z†Pó ¨e¨e‘PûzZ}¿PËj¾µÜµ<ê¡•«Ô „Zh@­°@­ˆ„ºm…Zd@­D¨ÅÔJ ÔÊH¨ûV¨%Ô*„Zj@­²@­Š„ºg…ª2 V“ï7jµju$ÔÎ8«ï7j B-7 ÖX ÖDB­±Ö«ÔZ„Zi@­µ@­„ºøŠj•µ¡VPë,Pë"¡YuµÆ€ºŒPk ¨Ë¨ËŸé'o]·¿ÏOÞe«Ÿ¼YIøC_i€Ûî[º‡Û÷ÕžÙ¬`€§žû˜};w Ç}þ]ˆÛØ6tëïÈÇrÃ1x~­E?¶_ ¼ý“Á¶™ CÚ­u´]Á:/mÞ¬nê1vam׌û٢ͳ÷³¿â™¦4ÿoÄ|jØû?±Z!®1ÅzÔ‰LÅÂLUÏ&Û+‚´U¢6r«ÄÁl}«Dó¬ÿ¥UÖÿÚëÛ̬½Y°î-ÖR^“ØZl¶3¡°©d4¿»iÓ¬¢"ˆiÖ>ÉÚ4kŸdH´©[“iÖÍÝ„Ç^Ìóbàå¼8ºÅø=ˆ[»‰ ÙcÚd«6!ûobBöG€¶­›¬´‹û+¥é¦Í¼v3¯pY>˜Ié<'_gf«g[vø‹“ÃíÿÍfã=á‚âdžðŽÁÐüÓ1üUýáx ‡šz¶óšþ1oh¸Yèd¯[ÓTÒH+“§°a”`àÚæÆDã“É@­…1ÑødÍ@ÝN¤þh²|['•˜@8K þCØ;0YXÄÞAÉêôGí[ªi|8FP~ u¡QÞÑM›þÐLcAù¥×iš¦&Ð/`·¦3C*ƒê¬Å`”|H²1k±«[Ó ÷cÕ«®PCÔ0ZWÃî–2ýMd#2…!Ó=ÓÊôv¤îšsÅ‹º³è«TÕ´mUMg…[ÞƒÙX14"{»5»1Ë/ÔðE- 3iañöÝHÄäÒ‹ù—ÈI²ëˆ5VkëY="ë8‘µ²ŽÓ³"ÆQH‘ΉGh•e‹6#þHŒ£¶ð#}ìÖt®L¯¦ÈÓ3ê\Yˆèÿ’uÊìd+ìdJ&f“ÁÈzà–?«N™FûjO•önñ=ãjÏ€·þ=#¬ë£YÚm…>ž£¬çß øžÓ²0ÞÑwñ]c¼£ïZÞÑw#ßÑ!«Rk@ÝC¨:êžê^$TØ uЀºP‡ ¨û¨û‘P¬P‡ ¨uÄ€z`z Uc…:j@=D¨cÔC ÔÃH¨Z+Ô§Ôc„:n@=¶@=Ž„ºjµÞOPuÒ€j´@5FB×uÊ€*L¨ÓTa²Å±qr¤€oY ÎPEuÖ€*²@EB´zn>g@B¨óÔ( Ô¨äÏ2#/™ etö²#¯XíÈ;IØÂðb7<é[œr~©›åt b ŸBãû+¾šoýÊö×zvãu¿EoKðÛ÷m~¯”1.sìð[÷Mün/cοò>tDF?tË[ØO&\’ðTòpAI{>€|JÁÐö| ÜØ ¦gá¡ä>GAõø Æç,ø¯èHÙç*˜ÅK½ËÀžÓOáé|: ø'¢¯@wåt}—bfi.g1>½!OLn>üæ!“y%˜E/emx O Ы&Ð º @'!è5¨õðŽ ¦ Ð:)™ïÔAw#h½ ô‚žÐÉÊM g5гèÈ8ˆ)”ONæ—tÐ+ÚÐ- @»PÖ»zŸåL‡ÊÜ>à¿$å•´ÏÚ>ozV^õÿÀÍ›•y0+½ŽÕÄñØy˜ó-cÌŽ{9oï3øßó*Õˆ‚ É”OÍ¸Ñ }o9¬ûØ–˜;´«û‚¡]¡l Œ(î§¹w²‚ûiõlV“Rsyܳ‹XÁ aÜì†^‡ÛÐТá8âö·ºiþ:0äÉœ1ª¿ŽkÒ3S’)éÞî&ÃXæyÝ_Ç`u,3XŒe^Îâq_ëé®ï c’!HìN·öРÈ '¶ÅáÌ“0œ™‹oíùø³–&kÇrÐÀ拎d®™ þW#ÌòzSlZDlƒÉào¯írsc# 7fFš™y­…X1F`­²ú“b[ÊÛœ ŽÏ3ú¸«>D¹‰ÑÇl}ô1G÷šŽ>î« Ì5:o04˜“ p>TGøCh,?ÒFÿ.F?ÆóŽÉÖË2™OÄ‹u:W6˜'£cq‘CÀ;O3À+U»Fÿñ8ÂÔ¸MLíÆnMÏ£P“½!ŒàUÂäã`™­ÒM¾Â´¦ŸîTž[ü<¹ ){EiMM|B5ñbãXd2nû¤5µPUF……ú”°ÈVv¯»+tvû¶”5Ëœu¥ÈZYWêYû}~I¸]ÒTÒâ´¦¦¤…ñ΂újA½¨¯Ö©÷OkjÚêuÃ0mO–«¦mÕç3m¤iƒ‹3?´~hÕ<X&€U£þ—™ô?°%ªñ…{Åk@qNqPëYUcz¯ÈZY÷êY§é–J¾º†¤é–J…ÅR©ˆ´T®Y Äj*B•PS-PS#¡ê­PC ¨i5Ì€šfš Å­Pà ¨é5€šnš Õ`…i@Í@¨2j†jFògYÀ£ ¨™5Ú€šišÙŒÚ­Pc ¨Y5Ö€šešÕŒÚ­Pã ¨å5Þ€ZnZþ™fë„4ÍlûÅÌÖz«ÙZžŒu¿$¥¡©ÒM†Y>[§ÜObc~ Ø sŠ{>·KÑT˜”&CÂ×N©‡S½œImmÐ3àw!WΔŸy§üÌYù÷0— rñïç•z2x2<«Ñg*F¤`„Í69M’d%•0ˆÎ\køò03zf¯gëK™íÇüÇ9C=Þ¡Û{5üõ6ƒwSÒÐXŠ#€ÎÀÔ‹h4»ñSTšf0aÔ39ãTƒ‰ƒÁ´&™Ñ`ª€dmÚ& ôÅN[\ná+îûRAá+ø*ÍÎÚÆ.f §!íA N 7éyã5ïî[“ùa )•roI9{¿Ÿ¹÷û¶‚[?&åÝ’p !?)å=ü&üø) :³d~Z\ÎÐ%kJšÂÏI9¥¼7üG»Cß“Œ_•ùy5è8íAÔ C´O]TƒCÐ~t Ï­˜eÛØï¿·èp‹ÒgmÀÕ)góKAª]è±ø®DÇâµCñîaÞé Ð¶±ñ”·ϼ&üë°Ò΀²jÛbFkg^Œ–ùXJ Žã'÷àð ŒuÉ|¢œ3\Î.Ûø$0«»e­Mf|2‘0ÓD£i,ˆõHcq¾Bè|­Fd-@)‘ @d=÷îŒ~ _À[ÿDg⠊²ú˜÷ÿ:P̆ä¬M ˜­ÈÕúd:x¢ùŒÛ#3¢FwÊP”Y{¢l|—œ3L¦ópwë¢íÑ.|›DÛ‡¢Í&¾Oü‡eõó}Xæ5rпßå¾úz£ÔʹP‚þê oVpGâu˜yŽI/õrXÚˆz™kÒý]M-we:Ôa£ª– –G(åÆdþXg°\ø:1XˆÌ3Ñ¥1`8nF•Dã-Š™¤¨4&)| žÎ°9™h”+=øThlNæÓM13M13îlº.AwÒo¢» énº[î“l;5º;:5}‹*Û »énIæûu Q,h‘ÆB¢ñ!Cbk²·ÏZ”&Émcs(öšFçšÝÞÆÞ Ñib“N`xâ­ÞÒáþjù †áÐêoé<Ü î ‹Iš%*ƒéìêž¶Áv^bGVè¤úÄÆÊ1ÀÏ’4øy‘RÎ¥”Ó3msíõlô[l®WÚ¡? {÷~ŸCÞƒßÇÕKMyöhyöˆ<{ì|Ÿ5Ï!ÊSE}“òœ×8:oç͉½GèïjSÚ‡ZÚ‡vþØ’ö0¥]–fj{S¦Ä³È'ó³µðOG+u,FíP÷gÁe%(x\Ï–3i.\Ï• /Ü;K˜R ×Õ„îꞎƒÏqä<ôïÊúwgd>+(ŸëÈ™(‡¼eðè;ìïïH´¡€è–{¾Ã§$6¢v-´õžv„p Ï«ÿ®äÄÆöÑP®óoöãAp·ÖS ÌòjGÜ#L·Êšî=Ý:‘n5¹¨Þ”Ì×8âö`†D½=ž¼ºÙé¶y0ÙNÐìJæ[)ýÎd¾MÍ÷žÑŠ)×PÊ])w;p*Rî¡ ±Ï÷;<úȱÈô¯¶÷rñ%zWø\ê‰Ðß§£«!ì¤ÆèçõvD “ôœeRŒìr=5§±Q¾ò¸±Ccc÷ÆFxà!!ŠzzÖµÓáaG ès„}ά@²Â GîåivGÛØ •þÕ&¥O%U-ùzµä¹Zò jÉ_wðúȢ斢nhZÔ7Z/j~ âþÉ턇j8ðÂãoï‚  óíž0’ ÷„¸ñÂÕ7Æîð„} Å=rø Ån@èÚ{»T褤›h»*rúì*P»€ìWìÄÂÜžŒGDCØ‘Œ»!dU'<ÂÙf[‘fWÚÆÎ¯¼ N¡HRà§Pà$§Pàd'ŸäŒPØd§YaåNUd|£U8›ŠLcªÓ$Í´Hif8±BÇ3é8žC7Àñ\äx%ýÁñjg3E¿Zå|­Êù:§(zô×E¿ÁÉ×FJ²Î"Ézg“¢ßèl½è7S|å˜Îè»ýlÄ>¥’vß"dÜ¢nÜ‹âxe»9ùÎdŸ½’_oÉ×ëEø J½Ê,õÁæ¤>¨J}X•úˆ*õQUêcN~8Rê#©6•úÓÏúD‹RŸblµH}ªE©O‹ät©Ï Ô«ÓâãÛÆÖ‹f~‘¤þS/{ÇBO‹ùK/g§^®NxPÌCÖ+ºS¯˜N½Út¢Sbðøœzvy0³]t¢ùÉðr”‚×êž2^U¹ —™OÙ¯À¥ñ5úŸÛ9¯Áu^?æªÇØ,ŠÃuÖÝ×ÙXÌu¸ÎÀÚÜÀôXÛ›p;€ÅÞrb9´»ãä—±­yƒÉ ¹åWœÄ0¿J¡ð¦CÎù5gÐ_ëí =j=ÜÕÁ]çpÊ ix܇3z÷Šá×áîܵá7à®îÚò›˜;E¹wŸd¼×«¿ãÌù¿‹^ü}QüžË+ì/‰á÷ñ@î__[_¬¯àLlÄ/|Ÿ3óoq…ëÇ:Á÷Å‘þ¿&M‚na°¨n]ê«x «žÝù —~¯IC]|° F£qx ^Áx-ìývÇÂ…=jùrHŽÉ„üë;!—ì%®Ž|¨  §²:>ÌL´iÞßÃþá¯-Hhg³…ƒÞ²×XÞŸþIàý íà˜ªMwu$´GÊ™ð9† ‰=L#ς^ë`|Õ.îëê™áßÉæqÏîDdžKùÃpĹ칸ø6 —Ç0þš›Æ8ÀD||l@„æ]i“?ÅnLSäøö¯âºÓÚ—ÂÿÅÔl¸Ä”fGè³£’þOâAÌ@NøÍŽyË™á7¥üO0¸ë†´üoö°±š7mL²m"ÌK8(ÛF‹7葆öa´f·ÂÐ>.þ»âÙ<´Gío[¿“mCõ¶{†ö“>óÀî‚—óæÄ¾œ· nk¿…ÿ=¯[Æ÷Ï„’Q¸>ƒ¬bñ]j{úóžÀ.~æê¥ƒ8vN$Û²åÏ=Ó/¦Þ›þoæ¨îfæ¶w¤¡ïpœÛ¾hZYS§—^Îmï¡bÛ™Še ¼bÛýÄ4ßyQ|÷–i¾Snº(:QÊ?OË.¯—‰¼‡šÎ€î&Ðo˜æzhÀ{sÄ4˸‡¸~Ö4UxÑüÝýEõ›ÿÞ’©sªÚ¹Åûˆ°7R…¤QšÎS›¥ x5•c‹r|Šr7Éh]mŸO°õdš!"üÃH9Z\ª~²)ïa¢dÞ^¨C¨*P <…-°Z`l»ïŠgs <õ™“kµØÛ¦}þ¥…•ž7Ìí® 6Ù¨:S«;˜†_åÜ —€ñçZltÏA£;Ÿ,|»C¦Cz3ÙD38«7ƒ³Ø 7mG( òЇ›€ÿB²¿Êz9JeñE¥a¯;º³¥q¦vÄáNÐ;9ÛVŒ¶…w«ÐöÜciö˜Øv'ÊöSqZœ«cáSøÒOKYRÂl?¯g[ždoáK\Ê®g[³ä¬žmÎRÂe[–}\¶d93þfàºÿyÞöœiÙŸ·#Á»°½TøT (¼w(œ #íì}ð‘7Ÿ€‹¾ ØÈ›ƒOÀD1-©Js´mw,†äL­×=ßËù<¾0d|aLËîý|¯˜ç{µy¾WێŽbŸïÕîù^qÏ÷Šk—3±x¯Ç/ …Ë ;ާøx²A/¤“X" ¨¦0,÷aêÚÊÅSªxªOƒßSÅãè§Åã >ß¡£šH!ù˜¸~xŠ12ÐN,Ȃ؎þ:\ï§Ž… žÚþÌ ½ÝBb{ÐO…ÌNèÌð¹V(åœDdúqÙñnê®ðÙE¢à ZÕ ¦[Fdržó9Ã>Wæs2Ðã«›sÝÄæƒÍ¹n0Ýâ¾É€›ðJÜ€kÂî-Q:Xø&æ‹Jø9¾ ¯Ë-Œ¶¿œì?“7-» s¦e«!ÞiÙ êL\4fNƒWæ´lªD|ƒ!uTþÿîÈA$R"ß®M*‚.I|'QñE#ƒ}úÝr½v¯œÅìc|¯PпýÄð}Ì€Gü˜q®/*(H jÃÃCŠÄ9·BaßÄñ~æ7%¤G_|Ô`èTD(?Â|Šû~9¾8¢ŠØñ5Ÿ½wÂ4TäƒrÖæðY?™µý·„úÃ?èÕÖÍø§PÝcù H´-oŸpbô‚„ë(ÞÑ>,ö4d ôaíÎÀ55î,ã§!m—W§}Ы?ƒ·™pÇϲ`xê½âùyæ‹u?,‡˜Š „¾€Ïà9­ªðµÓ.{coL¦ØÇå¬r¹áJ‘—0ò:DÆûSMá—µLñ¾¸©j¾x_»©ä+z"¬’WŸTæ®2ìZ}¸v%îÛxÎ2f*¬`w]¥r™hß ´”›ß¦û0vG½-‰Áup CW8í¨{‚Flþ„h~ŸîsžK´%². ¢%Äa?¦7.eát’÷‘´÷ˆÏѹW Ì| ®¥ñ~îžø^9ý%“cœç:”Ú@Èv59;ìAR çABæƒ[ÁÕd>„"º8±2—Ð=9Âá¥â‡]|¨¸·ç÷iχѽùŸiEV·GVðn ~ןîòûµç#$ìZ‡ym|$AÀTÚ`(ëêkv> ?_${£-õòYhe\B«ãY?Ïf«ãR¤Õ±ñW†ÕA0ã÷²aÇ4кT±Á‚ØÐú@Î@¼JæÌk0†Â —r¦gîaÝ-‹Us1™pÚêp)+ª©§Õíx7±G\­É)<ÃAAügÿu¨Á΃`_Àƒ¯Á`ð÷ÔàêÒîƒæp?¦ÂÜ4"Ê0b4DÜĈ[FšÀdóÞLjÛixxf.F,Ô–ÍâÛbe)c˘¶˜N|i]ÂzÀËLÍûÉÔù_O.ÂjñÐë(¾’… 8Ÿ‚@Èþ)  7¦±Þ¸˜4 ³3¤`ê•vbEL:É ÏDÜŽ~ ôjX ‡—ž faRÁõdì+1¾àF2îäïÜKéFô²ã”iþÍd—Ý¥ðƒB¸C>è-LaÄ˧,Ô[Ìc†üû‚Â?ÎBü$3Ó€ÄuІâqxV g=L–ðE½` Îz,áJâpÁ­dè´ÂèY%M²+öÿFÙîl{K™íŽŠÝaÐY€r.<E(ÚÉ?ÿÀð®#÷üpßH¦3ÞSxS7²`“IÎu$§ö)(¦â’¡ÁeœáRI#\* Â¥0x’€à…§m8Ü"Ú CahÅ!Ð*EáDp´$Æ6K˜ZÏý4Šs·„”gHd®‚ÑC…:È÷òóàZÓ—I•pí[Áäùp½ð#eÄgK¨VÁð9RG^IX­±\¦â€sÔŠ¬³E~+9á»Xõè“tÀ7ìRzÌàÕzðT0P—It˜åò 4ÇVI0ø´µA"kÈ:JÚG­ ϼÇ÷i8¸€¦ 6H!0|¿w¡ÆÔÞÆd‰X¡÷ôf-ô±Šœm:Á6˜ëŠ¿Ñ$×. ½näâ{%Ÿ L¾OÂ}P‹‚Ëm©4?FÖIj©“¨P^¡©H‡H‹òa‰’BT[ u)qÏc;<&…IK8ö?.…)†ŸèãÞ)ˆ£¶YÇHaM˜|aüh¨g@\àk°qYcã²ÊÆe•«‚k¿ª²qÍÂFƒ‰7·!î‚`£ÞÊÆbbã®`ãU±»TÅÊZ_Ô€£²¨fCeQÍ†É¢š —©šùõ>Ætø.}ã¡2ŒÕ*V&ëUl´l©bcdQÅÆÉæ*6^6U±I²¥ÞN‘© á¹M[üª҈› Óeª¨Ž™”KD †çÙògU̹²V1çÉjì“bªbóµÐ¢SÅ\(ks±¬VLK®jY­˜Z.¾BVëã*™êãã4IQ+Â&Y­›dQðŠ ¦-2Õ€¸`Á"‡©_‹¡USxnt²°ƒ‚QU±8Ÿ¶S¦š°[Ö+äVÙRÄ/…š°WÆÞµ‘Øø²Q£±Q£²Q£²Q'ó:•6ÈÆaY¯c­È‹âòQB.LGäþôR:/kýçy™_¤2JÀ—Ðe™t‡ýá9ØûÇ«K½é5\T/£z9й»ÊºP;JÙ%Åáaè70 d½©f½…éá=v[ÍwG$²‚›ÉüÎë¥ã»ø‡TãUÒŠt°Â+ðF{”,ÞhC”u"%J ”Õ/…ñRϰíC"M!‘Æ)šHã>Aý>'(»~´&'S”öf*WÄ› V` OáË N£(í2C2ÍT„Œ³ª…Ôzæ(ŽX“æ)B/e†^x%®…ꛎgí¾„l.ÃåX+ C>(f%^A1«”® ˜ÕHk0W¿tYQ•=$Ünhèx?ÆöMI׃¡Ùª@S% ü·“©n|ëFX ƒÉº­½Ä(zý *áøSP1j‘L±Aæ¤Næ¤Jæ¤Jæ¬ÂO«d¦"™³MÈ\ 2ÛÌEƒÌ9•Ìe$Ó?þ5’¹Ed.™[Êû– 'Ýää; ¿£Q€^öI$q_&Éîö2÷‚ tEwá!þÐy„t8Ô€Ú5qÚ…8xEqÛqMšE‚R;J°$j×%b ·òÀtYVí1„ cJÛ8ÈÆÛÝý*ÀÚ¶×ðñt-6‹(^nº'ºÐ«pÏìPòŸ}ªÂ]\ñ^a×mȉöPü~ 6 Òã É5|†VßS5 Wáþ̶@%¼ÐN'³/²óöœQRæ(ÉV8Jªá u&ø";¼Kâž Å_vrF6ãÕÙ%@ö4]NħãzaüÜäžÎ™©.¾-=S0¢=†¡í?$×J7»Z¸„šõ·€6R0Á¸¶üfÏR(ì46€a@ ÿXdýSø¿C¶Òt1‚À$ÙÐDzüýS€¡é’¤Ø¿FṪŞ £† fÌG'P¦ŒïCÆÞÿÌ8Ü”ñ/jÆ¿ðá¿AÆÔ(¿E pŽÎ=°‚ÑÌ=Ó (€G‚8ªÝ9¥ëçDC²É™¥êåèe£@TL~GU̺bêÙž8ö\îp{Ö›Ã=õln“ܹ#<îÙoŒÀoü£Ò‡ÝÑ£a°¦·ÒgQos¡Ö¦Ð* .s>’áwöGJ ¥û  Ã¯ÊüǸ jp _iƒRxWôü”î`vG'J× ôò›œ)ü7y«íyµÞ¼:/÷üƒSþA)™Sðý7T¾bޝåÌ&Ÿ„¿žwaX0PD!Ǧ#¿qªú‡¦ÑZø.Xº>>ÝêÃÉn¨„Ùºò´¼9ÙAœ9èì]•…vÏRëS@>+&Ûåž÷@©CR0ÉMLÇ=XÔ½|îÜ‘÷'±Ù¬`$-ÆOÿº¿ÚÙ0˜{ºÅoŠOŸ(˜ïÀßJG àžb xgãO%þ,ÆŸ­ø³#Å–íhâ¦dYŠæ¦„Wiµô¸Q{¬kº  ©‹Ž­8Ñfî­Û¿€i7ÝéŒxã"7Û1EŒ>ûQÄ^»OùV#KŒ›9'1nV—ŒiùK½<[ uA¨‹B«¼üjè|®öòž>{"Ë_æå¿D‘üE1>{þr/ÿ1‹6òÛx§‡çjÞp~{oÒ(ÔlÓŠ*\Í9l#­xi¤/ÆÊ€wFŠºò˜æ`å’p°r,•¬}ëž.¼y÷© ¯î>‰ù¬c=Ï âǼ…QÍ ê<-¶0îL´> øw¦h´f¶žõuã¤Èz²îѳÎjI -ì³Õ´0'åsyã™ýZ˜‹Z˜gÒÂâç{¢¼4‘™wÒYöë²Ìm)ï$KÞ€È{òô¼óþN=Ì×ôpT« Em8š Kƒ¯$øoGèá[C%¡ˆ¨ˆ…ø³(]Æ m̧Ž'±¥‚uäÈ vyV]^µ õÄÿB‰;ª‰¶žø_1±¾pkÑß©œ%šrZ÷E´˜à_j±’,EµTáOµI7K(Wjdi»Lºé Š<(Šü,yP/ò¥­ü‹ $Î@H¨jA‡*€U‡Õ§—§¨þœi:<'tx(û6—eÔÐÌþœÌ:Ôü9­@%®45·åºê›ˆ0™‰Íù»„àŸ‚à»tÁW´”kŠšk·ÈuríÖs­ü;5°ZÓÀaMç…gã{Gƒ_•îøÿ ¬A ¬ÅŸuø³6€BìªBV·Þ.¾¥)ê$^óySM¼¶õÄäkªK¢šxÝçIü-5ñúÏê%0ñsjâ -•‚¤úÒº«{Ô’Ì¥°I+…#Z)\¥p$_ôZ)lü\õp3ª}‹©nj]„Nµoþ<ò>¯&ÞBòú"åmaakbwòD×AõDG²oÓdðSUö±v’}ÀOÑFÒdßú¹dÿeßn’}[ëoïTߢI„&µWoRŸ´žUuü°Od=Y÷éY·SÖ¿˜ ë­ñaÍýC÷‰Ñ¤©è¦5—è¹/þN,…۔徯Þ~ÛtU\nyt° <š¸ø$6¯+Ôœ£Ä5_ÄÏrQüïy¿Éf¤’|àŠœtôí&æP¯¥+m\Q XC)¼"úÑšŠ;¿²õÃEŸ¿bxÙþŽ„—ïÈxÙñŽ‚—¢·íxéû¶/Wʘ¯s\x)}6Š2–±è~ —¨‡qÕÈ«2®Côi‹ÏCø0ò–WÒž'oyCÛóä-oz 7QèH¯ n¢ VÛq]¨/é&÷tém˜+êÇĵêH/gn6üæõiŸ÷8!oß3ygòö?Ãg0³[¹<šÉбÜÜìœCAõ:¡dè瑎åöÐÏB•áJˆ3à éÆÂêëé1,¶] k ‘Oµ8üT àý4}“ÀÍi´ΦhŽ©¯.E 2- ý¡¶×mÝN·ã*u°^ªXf³V±!A0gIwÿ¼ì¼jö,QNcqßpUÝ;'²€÷„z+¼'é6¿¤³–gæajžS"vXg:â)w ¡UÍ2«^5«{°ªÚƒšê Æ=-N.ê½ðÓúAO”5Õ’UeUœ pÏ讀•#À|¡ÜkžöB+í2‘u!d-Ó³Þ×i/c™Ë ë23í¥H{©F{¬X cu€`ö¼«ænq[ØmÌ_¬ÙÊ£„­\üS,q ø!›Â `í ­ÑNÊtýgXôC (Ó/M6«Èä¾?’ÆîÆ‘4Štß)§Ã+Zª‘&iÀdü†Eú8]_ÚXƒÝrcº¾E£ÆÒ-×DvËÅÖwt¡G‡ªE¨"Ukª„ºþ3 Tª¡úPu¨ºH¨ù½,Pý ¨ƒUl@´@Œ„Zh…êo@B¨Ô! Ô¡H¨Ob-P ¨Ã5È€:l: µÔÊÕ`êB 1 ŽX ŽDBUY¡J ¨sUj@³@Kù¬ ‹C=_|ÃâCËÊÖ)XÛñƒ²ÇÎdåŠûÝyEÌ6Ù•[æqW±‚2O=›_ÄØWî({„Œ‚…EL*wåŽ!£!dQ“+\¹cÝ•;Îãœ^0ªŠ˜c†+w<Œ‡€ê"æœéÊ€àyYsÍvåNô`_Z™]©“ºR÷ð &z_÷õNrTïdwcÝ(î25Èîî“N7÷( *˜øË‹XÔÀ[Hp9 …Mã ñUËÏ©M#djÔ¦25KjÓµÐ4¤§æBÓ(ilÛØ8­±ø5°Í6Å,Eƒ.EC¿!¤¨6KqS“â"<$)àí#UŠGš·I“µün3RÜoFЇ_\ŠÂh•°ÍVNíú$DßhMˆ¾Ñ¼8:à¿’ðw÷ñ1ÑОˆAc5v´4ãtŽ& ŒuVŒIc¥ c²Æª–fŠÁíTÜæ³Suf§FóéÑâwùÍ@•®Ï¶½²mÞÇ)RqÁ1x“\p9…Ï)/§ Ü”JÕ4Õi¤ÐÉ< ó|­ 4/ºž…06?š/Úé„Ëù6_m¥‰ØK!ls¶íƒZôgÁ—c²ÑV0ÙJÛ‚ÉøÁLx«„¼Ðu’ÖF¼M§ÎëçÂH „€± ÀX: ¼¨`Ò¦h¾)Z@×ñ-06o3ãý¾5:ˆm ø>v‰mÞ‡ O`lŒôÂ>ƒ*CßIàc2ÛÎh¾¿þ´‰‚æs`ëCÝë“ôÆS3©ý½NùöéŲ˜ €¶Ñ< ´E~K@K`« E|R‡¢C‰mÚ š ᤶÛÃ,ÌÎLêŸaóVî4ûñGÓÀ>\CœìÜé÷à ¦Ãózàü"w†Ç]øç‚ð¼†7¿ÌéÉ#åuÏ#±‚™hÂ͆&æpv%F/9yB?f»âäWyc%oÅ+¶ÂjÐÇîO¾€3ò¶’ýéžÔù·e§A \¤ƒ9§KRSpbq> ð,ï\ï™n¶‚>©¸}Œ·©tæ£'RŸ£ÄaLŒ;Œ¤Æã¶:–³NÉZ§Øø! Ä…(<9ãJ~T¸Ç(e¶£Ð?ãÄè€T~‚N$ (Õ=}ù¦’LJtë_¦dðÇ,¯J̾Åà¡ãü„¯£kD)·ZáEš sÓ à¾ê*ƒc†ŽÃP›@ߤóIŠ…Ù!Á ¤ të_©“{–IR^µRŒ RˆIaÒÎÁ<ó(aG4wRœh˸¯‰_x¸®žn½ŸdÛ2øu© n’·LÜ܃ÜýSáýƒ W -;]ûE[~d:×’ÁôPâ!]¿Tu3 Þ+qŸo”zðBÜÒ/•÷‘‰©§!¸Ýþ¾©YÛ³%^,:§Ò›büΤ wª‡ÅwÁ=Ý7ú16Dæ%¥Oª{d澉{BR²™·Ø+×òR9gŠ7”9ÅËd>BF†©èFÒm0¿!…—Éæ‚àcäœMJÖ&¨)cqoÊb“ú֣Ⲯ¾MtëÝêÛ"· ¾mÏ?‘ õm—I}»ˆÿ TßRß¡¾½²¡¾½2ßéŠ õkê È=xÕWœŠ~•‘)Ügu@¨/kg6‹û5Ö|9ÿ]MW‡d~ØÐÕ-¨sGpS¡®£rÎø¡Ìñ=@]Ç uPÕu#…Ÿ´ªëŒ®®³¨®¥qP Ê{ypóŽ6·*jnÉSªù.Uø0J vÚWzð‘èÓxP*¥hÀ£q3Gµ©ö#pPÑË!D·Þ]X”Ê¡VÁr¨SŒr8¨P9Q¨ê±–Q9„D9|ªåð©ÂO(X%õrè«•ÃI`ú2Ý7•ŸQôj|Žn©ºS5>¯ˆjìÇñŸ¢Wc½h®*è‚ÙTy½‚f‘^4\1jò E/š›Š(šú~K±Í]]ƒ÷PƒËME3ÁœdøcѬ ¢g¹]-šr;Ÿj©§òév hî~Yé±Ð41,]„HKìÍ(í¨*;*½Ún(}™Ô00•/·ç.U:,Uø {¾Úž·BIè9ÖÚY¥©6¾NM·b7Ù9c%¾© BQù™c%ã·ØQÍP*_A›|«]í ù6»œUŽIøîɳcË¡Nt‡]Lq*¶¾Áäe—=g==d­Wß ´÷©üìWù Ú©¶À/dªî€VÏ æ56>=âëPW«<²ât]º*EŸÀÅu¢æ;èíÍF:ø0G°#9Yîè˜ÁG:‚yc¤*bµŒîŽ‘p¯2¼eƒøŽ…Gø«å£¡¼™ž¸Ur¬ƒêîÞžH·;b¥£ å,ƒ rVAe0 ’\LÈà3E®^ê¹ÒlG';ƒÐŠ yo‚q‡;;çj ¬ÌJBÍ·Ç"/„w³CU¾w^:ë»ô09O gðEŽf*É“¸É™\ê0*I•Êàr‡¥B¯4˜C—ÔýÍÌ­Ö€9\]æ‘¡!‰†|É¡ >/9Äàó’4£ðø½ìÝCÞ[)RçŽzëÄç Ÿ7ԃܱ²yXQál¶5fVæ95Væ9+óœ|Sge¡Seå6²²ØÙ+KÈJ•Ó`¥ÚI¬¬pZXYåTY¹M¬¬¥Nô·â-œðýN½ Э·$:ÑPKtÝÝZA÷•îg"ú—_Gô>FÒ{ì äœOÉ<Ÿb+€ÖRèÂÖLr¹Q|ÄWr_6qŠè§FôMÅ®¿‹š1F P#ŠSñ­4Èe¡?'ÖÖã—Gzàe¢Ÿi|X¬¼œ·ˆþ{>甉9—±.mßÑ#陂ó)b´†Xè…ø¾¼ÑÏÚÅMŽV|–ÇÐÑ©¶€wþLÁŸ ü™?óS-›‹¾èQa+þlìù?[8Všbÿ;"vùŸ[ÛÒ²êÏ‘;s”Ö33“Û*3ü»˜yG±f¹iÁcê&v˜($ñµ½,UûÚ^–Š~k=MNÛâg|ažNP]_ÐöŒt{F^„4[=xä’Ù)Q&>¦µéícú\û?‰vù7\Ú¿ä‡tLªXà¨ûòÜæÁó”¾gZʨÂY–2ŽÅ:3Ƨ ³?ñhÇ‚i‹Õ¼´(Q_½ýó%ÛÑj².?R“ílI~m7G£iOÊÿï$ÿ¿ ù'6•—§éñ¸ÍÉ? EŸœj,åÜÝ:³?V™ÝÓz²W4´-ÉÔÒÒU'ù–u ™ÊS›øgÝGTÍþYÜKBª¸8ÑÓôœ8‘  ù²íB¾lá·‘~CtÒszSUzg4%ø\Êœ†ÊœnRfðóUPëÊì & {šžgf"à‰äg™Èð4=»YU—ºBaq*-Xñç€qª¶| ¦¥L^‘i‰È´2-Ñ3Õ¶TÎ--Œ·è}NSu×/µ(é\”tþTšZíÁÏw‘à|9p¾HçüP º; ô":üù’ñ4= Oe\1|­˜y^ÐTö£ž¦g Z¥X*¤XR,Õ¥8æÑý†O=ú¡_ÃR-ë}S#>ó/ÿ³å3ÿqj8B0 †[ †GB­°B4 F Ô)j„jD$ÔJ+Ôij$B1 FZ FFB­²B5 "Ô9j¡jaêg-‰8ïÑHÛýÅHk´64 Wg ÝÑì¦ÿ‹<ò·CÃ1Ú”þ2]ŒSty‰"ÛQàÛð~Í ø«P¶ËIv83)üuüùN=;Ãâwq{zUj°ƒ 6ßo{ðßAݪJåïæíŒ*üÏZþ‡ƒÿ_ˆÎZú?!:€è¸TÓ£D9œs%Â,bxJÿôrÕ³ý™­˜Õ³~£C̲$t­¹õ9¹KF)¥ŒDØÉÃf¬c8ã}Yàº(/fD´†÷gÁxù`=ø –h«%WÀAåƒ:^ôRx)]í| ú+eô<Bz9ãòm¶¨zvù×ΑŒdAŸÓ;_fÈ/c>טÎñ8»àsùtƒ |#‡*c˜Oñ¹¼s_µU üX¶YâãX^uwŸ‚ç½jó.ë.!Áál³Óçô9žÛØÈ'±P"‹ÅáÑdÈ•M£Üå@WÉŸçàpcχaÍŸ^õ(í΀ƒTV©©Œ<“& †l•¤!V)Ô¶€‘6åÅpý´‚)ËTÅ-Úu¬`$çJÒ£kÆV°¨0\OT°èp=YÁbÂõTksˆáÁMmëá2z‹åp=]ÁÚ5ÀuÊpwñšŽ2\ x0Jâ‹E‰€HK@>*“¥P&ËTå/‡@Uû+˜Ï.šWa)ÐGÆ(¾u¥ëm„þq¾žùœ› ãFÎO71R¸(;ÀmŽòE¶¶·AÒDù~ÚÎÐïQç¬Y²ÄwG{z,¡Çý úáX´d³Ž‡±¦†}βiS?èͰ öÃæ{½ÚòÃÌhk3²ÅZ3mÂüžªÔŽ_şƹk‹L'š­S'- =Í„$ôJ@ç— ¾6mq8~Žùb| Dý<óµÝÔ/0ÊôTi‡¢+¬}‰6_Œ¨y1¼ž´Ë9Ë+îŽ5ÄM¿N1ñü†à÷$*ÿ–•ÑÛÍ2z‡Å-‚Ë=ž;(¡áòHh‡*0_‘ M´ ¸óµþ~ì@V©>:'mGÎI1}1:OóµóÅWxwvgÈm ýo¢3NäyäsùâBY—2$>ïcmY“^•x©ä‹ ¥±P*Pîá’*î MM_5D·q×°¶?§v‡Å s{ÔËy_‡¿ž…2v®»Eâbæzºùψm,bìÜY÷¦"V0ËSÏ61©”åÎö¸·@ÈlÙZÄä,wŽÇ½ Bæ@È'EL9ÁrçzÜÛ!d.~ áÅiwä7œÁÎQ;±HNFðŠ^Fð:®ƒŒ—êž ^Õ^$Q¦’êpd°„Gö' 7NŸ½`Gºâô9 ¶£N\˜íqJvÇ(ÓN¢œÄl»%¾[Êù~ 7${$t¸‚®Vþí ™; ?®áûÈØ¸ŽúSþô‡0/åì1<’ò >¦p:eÜc‡qú3ª‡Î¹ó@è7݇œî°Ç]ÿ6ŒçÑyâ4‚Ÿ"5œý,W!íÈUÈ7…«5hÊ­ÅŸuø³>U;îûq¹¸šzWY«©Mcd bÇ¿±"Ð 5D†ãš¬»i¤6¶Î–Å(ú–>Š>krǰJE¯ÂQôí¦£è;q|6æéx9o®À¸«­1ðûðêOÖ†Ö)bhH÷Ȧôƒò|æó¶ÂçkÙ`b¤íÈ$OFƒ´SþÁ ø¹Ô#è¾ØŸqoÞ½—Å–¸ío6]ŒlÜ‹œ·¿ðßÑ9ß'r? ×üõ¼ƒ*ø!g³à·ø!gÀ[@࿌”…†‘MHüVÎAey²Å¾ïIèï‚ØËÕàÏ!ü9¢÷w4gpFY<Ï„ýì ÌÊÁÌ=0ôsMf÷üÒ˜ãóGôQ{M±¿U;)é-Ù:‰Ð >º Uèß5 ]6b/lŠÝLçmηh°È·þ—@^IÕˆ9ÍR5Í|sšÿMµ¨ø >þߣ›êÁºnt9åÏ££l—x· î®í‡Q¼[öèï–=øFÒ½É~¨’îxnÐPžà5òR€¼Ä_ü Ú‹`eƹð«„<Žû àqÿ6>ä1ÿšŒ€UUx'©a73õ0l¥ÄÑwû»ê9Åß…—Uë’pϱَr ¼þýØ ë®DŶ+—(£lÁ";RÂØkõìh “~RÏŽ•0ùuC•0å $•0{Œ‘J˜ãg8rr¾É½AÄ£püUôÊ’Ê_ ø«ã¡ŽÏ– íµü'Ð÷ÁãJz¬C/B«áq =Âøè€<¯Ïvž¢m€Ù <9øÏÐ>wò7ÁõE狆Ì5…–×ÞþXúˆö¸\ïoA»u¾S¨t+ŸÆ&5³“X®§4Íljc}ƒ'Êšžã„¢^Ëúà8Æ)ZÁbåkú¨Ä¬@»÷<Ò¡pP”#Mo,w"å®%å® ÏÝßÜÍ»³˜»sšÜÍlVîVò„V€#º¢í«‘ܽògž»U<Òþp #Ín,wFÊ] ÊÝc=Ô*j B­V¡¶è ¶øCUê¡Ö¨P[j­ µUµÕªZµN…Ú†PëU¨m:¨mþPûõPT¨íµQ…Ú®ƒÚîuPµI…ÚP›U¨:¨þP‡ôPe*ÔN„Ú¢BíÔAíô‡:¦‡ÚªBÕ"Ô6ªVUp˾=öѯ÷Ñn×3ÖwÅÞ –bñB ß­ï„w³¥MíÒæ€lX®cBwÁlm¶ü¥mE"¬ñ½×»²$ˆ¶;V4š-ÿþ¤*ûBCZ°ëkfÇ ,ÝSžq£+ë…š“`ì3[:`Ø/eýÌ_²¯\¥±h «}¥EÇö¨e¶D`¨¡‚l¨Àr…pbÞB9t!J"ÄÊ:¤!‚5u/Ø®ÿSúâ‘íµ®èÓ è{!‹Á-xvË!Z‹–íkËú l+JÛoEñ~Ç~·«!ã †®ˆ--Z~L!¸A[=È ÎØvþ”¦ˆø³ù÷Ærø¹ù¡©J`å‚×=3$3öA2ŸhŸǪÐÞØ˜’®T3šÖqßëÚËŒŠ1ö“Î%Èt‹–¯jED©}Ù!Ü ÝïÊcô£Öm"(Ð9Œ~AtåŠîcov|Å¢/â—'騛xëåbÆÖm¦ žèì¯ LDêÙ52Aæ Ù ±@Ûý‚l¶à+¥²[ô ?xr°ÄÉnÃw¶îWDúýÖ!ÑÈ£B€>íÚ!툯ð^áG¨ÇoiD/`Ù(EœûJkŽQJkŽ‘Òšcd˜V/¤u°‘§õy 5ÔH j”ð‡)D1¯O 7òT=#Ý~€¤Œƒ¢9˜>”Fú'¨jž'úSðÒC¡ÑÅD<±^~‚î‹W‡NREeóBE ’#fY >èö{ VlÄ{ÛÁ(Gz)Èu"¨˜®)Ì5¦Á×é ŒKA!¯¡Y£7_ uZ 5ŸB P-$“.Ýo ôQ"}°RLó)*³J 7ÛK$4×2,GÈ\‹Ç})è‹*VfôD$a´­F UþxÙiIÝðJêÓÖòDçÓö¶1Ok0=2¦GÂ,7²rsŸÑÓ‰0«TÌj?Ìýˆy&ÖhjÝf¯H ÇeÐãè#;iôÚ˺[pÊÇÎHDB¾ÇÃË2¥+FoÒV‡]5†Gr¶nJuÆ­èqO-iv_ò{` )F¿l“R¾¬‰ûõ5…äÒÕmï ‡À™Bþi0„ôFK`F¯û´£š]0ºN9ÜÓß”ïæ¢ò¦Zr›ö¦|7ooÞ!·!oUH75‘ãšiB·¡’›Q¹½i¢Û›¦`ã3ýêëMÏÔ×ÿ¼¾þÝúú?Ô×Ã7fR 6×ä[°yx¿á, Ö­Ût¥ro’Êu¼‰MÄ|l„|L6¹VXì› ‹SL®îwŽ-: ‘ À9 À `†‰ÍB€ÍP¤ÌÑl2îr>ÖÍåSXaâ÷b…‰­2Q†:QÔ~t_AXcbkL©×‚ S^÷‡ë\ÐÔxد‰ÐœÖšR¯•']‡Ú\Ç3ëzÚ½òm9»ë¥šÚˆD/P_µxº¸Š‘ÏvGùÇâ¥áö¬êmRäç88œ¤ÿ”þšÕHF.oŸÈR½~Þ7&€‘&€1m®2X7=ñ¾1}.N—!9mÚv¬½€ÒÕ8 àË8šÆ‹žð–'‚زKHŸ"ÿ]8œïS÷yÜýÚÙ÷áXs•(Â)“'>pGd ¶±ë0€›í¢Õh÷5JûYè$Cl8¨zÍç‚Øì‘ŒHÿ’OÂÑn Þ¸j§˜Ãí׿HΨÀ(}º«_p°©Æ4aH‹ÈPŠŽ4Cmȶ¦T¼A>ÛåTl7²h[i¨®<킾oq µáM¯ˆŒa6æ5¦î´$í´`€Až¶†À $Pr‘À "ð*ùÜ— Ü7²‡˜kcõ8Ü]NÌÂ&sSˆ [¸{ÖiçÉ—´æ™Ø¼ß4ÂÆšPvÚÆ)€‹ð–°«p4ÞÖ‘˜Ø1mÃKUù6vB<‰€w¨J"(Ú¬1¹rergøÅ'÷Z ~—‚ï(|†¿mòtgAv2Øö%¿ÇàqQ_‡Û¾ ‹ÄKœ&¬R}²Í€6é˜<°9=Ä_h)™f J“Q¶Ù“4Ť¼ T€×H]GNI“lŒ~P@ÃÀo˜ /%±áf"ž>ÝÌò0Ôñ(pÍçò¥£mé-l €‡×‡îÅ¢ú·y§qŸÙäC+•"]Š‹éËz±@HŸcfsé †-û¦$Cz‰/€iËo&û>%;‘R½TNõRžê¥f¶œRiÙJ)ÕÏð›_˜´Õrª×ðTã¢d‚> ÖÏgºom1» ãÂ’éJ¼I=Ƹœô{ql—Yî¹Ã:’š³Úw¿äŠad‡c/ðî½W’tþè|Hõ!5àDµš²2ëICµ™0{¥°xɶžBñözŒBÁ o8ff' «Ýq?%5žÓšiWƒ_4Ë˦‹fvBM‚PWÍÒÒ¦ƒgÙM¦6mOˆ¾¿…O,— CKp¹@Xhõ ´°¨›/ªÙ`‹Ç=ÊÖñqäÇ µx(­%fû(›+ œšó À@[ÇvÈÄañ¤²¹Ê“Ýû»;Ù„ŒÐ@É_ŽWñèš}gw{J.¿³{šYjðVœŸ Å‹z4ØX9¼U(FÇWQ9-†¥Þ `œí ‚K!Ú|-iag¼­ 8ÊIõFØ[üF̔定“&B7›Œ¹¬(æ&žË+ŠóI#Á ΕYç÷9³>]NµxÃp<"=ŽžañŸUgYPÿÕÌß©¤屫P΋,l‘–PRñ®Ú ùcÝÂ,Aï/èVv)z~ñE%[bñ”^oË ò 2Ps¹ÅãµçÙwE²ƒ­´x%Ô5gÇþŸH,8‘HÑpØLEéÁr†ÈÐñBpÜÙbñé[1}íxÂÈçÚr‹´)·°}@º{?(¾*KêzÑõ[÷˜W_iTûi"–#¶°£±?D<妉ˆ+Ÿ±¿]í%äˆ,ì’¥8.^ÆP9šP×åP×-즪C °ãd‚ 𹏠hǃ•îÒÒᶺ¯Y š\ÿSrtG,¹| ÅUÍ €µ5(Â<ØŽ×aŸ©eœ›K=¾}½Ag'dی´'פœ|ÀþŠi6äYšCí„x‚BK³èIñt¯»2™ÙEcPp4ù’ij׈ÏEO 3·×•/”àµJöß©ù‚מ›¤™NYÏìÞò¤ªdýÔiP>•P>%”OÙŸU”¿¨(Sìåo€R (ÿƒÌW;ÞQ%”Ï%”Ï ås2(÷9û’caÏù‡‚U‘4Ã)ÒFìk4Æ·?Yd½‘ýJi²Ú·Ú·„ö-û'ÇÁÉô{ǾÛ)8X–à-·HÆ•Þh…AÁÕA  3žkÐ ¡q¶ˆJ<~ê^Õ¶‚«À†ÂÑy‚^Ý…¿°Ù„Ž8¸„âà2‚;ïkÍ¿¬d£מ֡¸G+xÑÜ(ÝnÜÞ_i>€w ƒ nœà‘à'©Ø&’àìÁãž+‰°Ö²² ™6®x¤Ih>y– " {Ò\›‘ ©“&&ØT> U yŸÃ÷¾fCvxx«ôìÇ‘Eø0ŒXãvß[Jrø­¿BJï;§×OÅïZ)‘ö 6†åT»ï%; KbX®ÃB]oS–Ó”ÔÉ\G3,‘÷ÝX€ßJf(d± ŸüͤÖùŸyT%À1ºKWO7'±]¢D꺮E4*´Û¾1¡ÝYMiE-­¶4"âr|­QáÝö ïÎ&"(’-8³¡-d *‹Äm‰¤Ûu$„“¼•Ö É}OÉ[i÷¾'“ZvEzt!nœçØéÑ…6íAÿB›ßA–SwÐ_¬B-B¨¹*Ô"Ô"¨[i:¨y*Ôb„š¯B-ÖA-ö‡šô±j U‚P U¨T‰-Ðî"ª¡«P¥:¨R[ ¡Ýª ¡JU¨2T™-p‰]¾ewèÑnÙ ÔKí.°aSC…-v4­ÑÀÁÛéï„!m~LêæWœ›_1¤ÏÇ z™U–ÅÖÞ—¤W¾6|€ç-<ïÿ^ü€|–âh~LÆ«ñ–ê)dzß4h–[l°N­È8Â\¨äÅŽ*à¢)--+¡ü™ý95ÌãÞbÃiûpˆ3̘VÉþ{á%b:€þÞ¶ÚÒ·Ú`…‰¦¢°LŒ`~Dœ·RK¶r;d„‘®>VÚ‘ÉÉ9€«ìbKKÐ(¡ö&x~…„ë¾6|U#ÜþZ€çµ¯ExÞøÚÏ_›à±ý=3<ï~mù ™}A_¡È`ðW쟘·LÔãå±áí¿òŒrË {»lxŸ¯—)c ,ô2gÜ býÈôÁÝ ÖŸLì³±2}ù8®?{µÈ¸(²X%«íx1”W€+·©°ÜŽ gUž½N>3é k®ï¼‚®‹0AÛml¬6^IZ÷Šv¨§BºA7è]§-“Aˈ‰!t;‚î°± è.]¯=‡ t'‚nЀ^–A/ ì*‚îä  AwÚX­zA7j@‡à!í0ÑãÞ ›4 yòélžÈFŠ^ A £Éº’å‹2èX<«Ý¬ƒ sñ"‚–i@È  D¶A÷rÐ2Rhc¥ èRÝ¢ÅkGl'€zt«t ºGdõrÐr2egc h%‚nÓ€Ö"èu­@ÐíÐ:´Nd·´‚ƒÞEÐ »§€>@ÐÐ\<ÝE-e•ºS:J>Ýedùx|\ÉAÇâIo¥3Ê ðÈx—t‚.Ð*Ý­],ƒ.6²R­â K´ÊÆ–) +t¶á­A·;¢döq3,EÈã½ÕŽŠ”Át½m›¼±»{ìxZû¢´ÙˆH[c½’†15‘ ¯¦-Œ±žû8,ÄaÍkosñCcm]@m+gqÑsÍ&ñPÍ63›l¶ùQ­Œì­ Â÷ö“¥ñýÆÏwtouÿð?ß|oLSŠV|ÌìZÇônžacmÒ¿m2éß5’tòm@-‹6c±d¬±¸šl˾>–ŸÑèR®lµê4]N*[­“¸ÕªðÝjí“¶ZuÜ~Šknµ*5Ž?Ç…èX%í¿Ðv,RÞEñýW7”ưMmC¾£0oËÖXÞæÖXÞææ‚ßaïè,ÇzÜglG¡ì>L?glhŸ±¥×`éãÙF£ÀÜ'Aù¸„ö%{º(ܳ_ÙÊÛ¬:½¶¿}Ï9ì—i7€[¬1½ØbݱѪtLoûŽMQ;A¤þ¦Ù²4M*<ŒÖß!’M¿šVø¼„;˜óÒÆ~ÁÖ,{¶í²& y·Á)¿ò.i² ñtÔdᷪөจ9¿¤Ù¶ûjߨÓ魸ɋa$ÃM¥ŽØeE>‘úKb@u<Ö(ˆU§Ä:ªlU| OÐhÙ…ô¹HM]‘ ,€I×cv_•/u ¨|¹ŠÅP£)†ãŠáÏÐhÈÐ-%C'(Òë Gò¾ö ¿ªp›G͇¨·•¨')êo+ QW$Ö_+·“¾½¥üáÀ}øˆ|Ji'ò®»N«”¦ƒ$·~šè'jã•`а¿õÎxI:þºLûJŠD{'?€¸’K$åâŒR ÒnÍË£6‚¢žû“Ç]!G=«î;öã´|NÝwì×í;öûï;FöÖ›JS¡ Ôê€ê€?Ô(=ÔEê B]R¡ê úCÖC]V¡!Ôêê?T¾êª u¡jT¨Ã:¨ÃþPcôPL…:ŠPµ*ÔQÔQ¨+):¨k*Ô1„º®BÓAó‡:÷'Ô ê8BÝT¡Žë ŽÛÙ¬S¡N Ô-ê„ê„-ÁÛ*Ô „º£BÝÐAݸ5¾«l<ÚÖxˆ~k\mÆ|q;jHH‘¶Æk¶ÆÛ²!&mQŒu{–±V”;²ñ£´Å1Öà°ve Æ,!­$ƺ\JÀeO–`š"¤•ÆX÷‚K)®:ïÛM³¥Gí-Ôÿ-H Ö \Aþ¢‚üßÛˆ?z›Ö z“ iF(£mæ=ÛBÛÌû6ض!ÛnÍî‹v(n"rÅÔ»6E ‚Ç}v×÷mλ6ä >´Ër´þ¹Ô£ªæƒ¡(F{×F¸¬®·k•ò„j9Z™q¸èïR{‚¾+q´Þ¥¯$âhý&íì“ᆌ³O²i×c\¥¯g\aï!ç9—üSи‹ »È½ÁĦÉÖøA¿qª_Ÿ8®Ðý¦PñÍúÊ0ÊéÁHA˜FF½ÝoÅlºZúº×^úºYúz›)”#FúÞ`Ø8—ã)Cú¥ 6›ÌiÅÉÛ µ©ÛŒù"þ§ £mÆycyô‹SU6ökmyŠP{'à&";¦Êþø€A‘ºKÏö|ÉÞঢau¾«Üœ8y•{G³ÊÍŒ”W¹™‘È!óYåŒãk×;Mè-g”f@y¾ã¯ãÎHó°Q5G Ï ­ð ÍÉ}"}ÍÇù.¿îè–_}±ûEªëŽ!q¾ Êîh§ÌŸHÓõP îLZiP0˜_¹áéaq¾ZÝîøku3I:Í|ræ±çøæ)7Î÷_¢'sóÕž&ÑÓö6I+*·¾4ò£áhŒhŒF£¼‚Á¾4F6BCÑ7*Nà‡DâuÒ8e€©à‡DàóãäþØ£ ð¹ú¾Þ†‰DÆZž´Ã‘cá? ¯¤-‰±^ë‘,d,ÁÁyl²"‡‹µw!CíÍ 7ÏÂ8;RgדŽ&DzÜ#›ÁÜ›ò©ÿ—ð#Ç)Ã/>|ŒS†q8|Œ÷>&Äñýð]~ñݵ„LæÄY`¯{’ò/åÍî/ùf÷—¬+îr+ûÓ݉NíP©y$ZhGÛ°c†7´?ʺ¡%Ê0”ï~ß´ÿá†ÎÕÐr+‚ð{[ú­Ç_háì-»0ˆ$kÞÆ7h³ÅÏ„ôBYM…ŠßÈ®iœB%ފЕ…J"Q€ L‰î9mIÖá7ø†ù5˜GZïyÜÅma{¯nò‘×Ã~çqç‘™’d|Cß¿‘¬ö”ªú+FV/ïè?@Æin$þ[Ã×¥êkœ¯{’øºéåÈÜÉ™»{SØÖÏå—½°q™«rNãZ½T‰¹;·­?swŽò6Æ,¿å+ ßQŠÛhÅ­Py»Ò†³ƒ§Ä™%ý:ò9Ï•Ç>{å|âcZä£3 ¨È¾ðÏŸ2?WŠL˦}…Ø´A*›VÑhÚàé…uOC%8‡“ß“‚­A&_统mºÆ<ö‚Hi?Ÿ#›kÃ͵æü² <5NÞ˜Ëç0îä!R>çW^ïmJ¹ìÜXjU05²YÆc§ÇùjùäÀM'«q²;í†L»_Ùø{§ô)í½Ô÷P§-$lÖ3^ëƒ TE!'÷ öV™ÜÌ8ykÿ7çß ™S›Ù ÀÚý¼Ì„—›¢×:£¡ú½Ò†@g@ý^i£°™å4õç;†ÌwdP”:Ý2}2>ͦ@X:?qþÄùMF½&¯µ& Û„9;hBö÷1z)¹ŸiØM·=N×Ênœ½<¤ƒ{FüŒbÞ^‡tÀ‘JÎÏ¢úµÆ ¯ÒBî·øW¨³`*ž£TðS‘ÖL t°'Ð9Ɇ$ëÝ?ð44ßÞo±ºÚ†«¹êjc˜nµ1,2½ßy*T.BÍW¡ruP¹‘ìý.P¡†#ÔBj¸j¸?TŽ>U‹T¨<„Z¬Båé òü¡®ëSU¢B@¨Rj„j„?Ô ý1Åj$B-U¡Fê FF’+X¦BB¨å*Ô(Ô(¨=úT­P¡F#ÔJj´jtd ƒÆ«T¨|„Z­Båë òý¡†tÐßÂV¡Æ ÔZjŒjŒ?Ô^}שPcj½ 5V5Öê¾1lP¡Šj£ U¤ƒ* ¸Lß÷ÃôŠ ×¯Ò‡Fâè¬Û8•q_'1îïÉ›z£0jYož7~/ÂsCo#<×ô6Ásko3<×õ¶|JœûO‰sÿ)›)z’ %‘ìïÈÂÿõ!D²/=åË"Ù?<U!ì+cevøXGvxq$1D'";¼8’MRØáS0ûÛ4 %º@ç"èv èrt¹ÀV"è\ºAçF²5 è:ºý­­DP¼•<Awj@Ê Ñx™CèQÉŽ) 't—ô:‚ÞÐ…º[z[½-°»ºƒÞGÐ…‘ìZ {4 £ð$+_ô¸!è^ è8™>Nd¾ˆƒNÂEÇ¢H6Ya‡ ;Ü£]‚ Ë´A½Е2èJ‘­FкA¡ñ¬S@7 h¹´A÷h)‚Vh@«eÐj‘@ÐRJ׎K#Ùaô(‚îÓ€Ö h-€.EÐJ è ô†Èêt)½ K#Ùô‚Vi@óÇŽWs—#hµ4_fÜçÙXdÜ/ç ã‘q¿<’MP÷“q¿?®%€¾MQç è\cêñdxzÜK`×¶ þ«B8]Ç“[ ?P9„C¬D?^Â͉$o<„;‡·ÉTè±ö†§ðZxÞnééòñ§‚7})îçã:ªí5ì• OÕÞÇc ×p‡×}Eåo0çGãBmCטx@O—ž+þaÄýDè˜iþLÀãgFþcÆ%7ŸÃƒ<ï2òè9"¨ácƒO½<ÒÀa’ñW'„s-éØî? †O„Ôëâwí#â"|jî\eÿ$¯¼ãÛÂËÁ"õ¼u8î­#qà 8ŸŠI#f‰Ú(ñùtr``ûÉd!]vKÍׇ•?ÝùV¤°ù© <ö2ÜMmÅÇv|줳ËSÉà³;R'’ý/ÕU;-—«Ì,ôWÁx¸·¯vZ]‰Y…?$2—~"„>ÿÌDFfSÇ:¤’6A-ØÇ:„¤q~æ}þ‰ð“ÏLøŠ!PSÜÞúú8ƒy¼Ã ˜ Ñlî0†‰ƒéIÃ$‡Ál4‹“ÕÞ×ÄnRNR6áIÊñ8õ„'âðâÛWç%ùÌä%~fò³¦Þ¡c€çñ€Låâ­³WqÇ…Ç%t¹àuü¢cŸá¦J ' ?—¦SN~…' G"©Ð=IÉF–ä8Ñ9N4dŽ+y¼XOé§“½Påég’½ég“ak´¶F…tŒz*Ž.ÿ@Ôñ¢sF¸¯“6hðá Eúïfgžs-ø,F_^iË¿þÃr_FôÖ ‡0™ÞÕ8T±ÕèM †&ˆ•è^ îótÁÉ ÀXã¡´Ø;v´öƒñëpoçX‡9ýD2lÑ“9Á£¿ÞC$îà‘£÷0’Ç{à1@ç*âõDëp P§¨'Z§[ù¯ ¸e¾¦B­G¨ë*ÔzÔú€[æ*Ô„º©BmÐAmð‡:¬gÇשPê– µQµÑjý‡znµ UPwT¨ TEÀ]ÒݸGWå4BwÏpe$¶äSÇ™aïF ÛîKý£ä#{ì³Ê]Ù†£.ÒGÍçQAÔ|%ê$ŠÚUUÊpøÇé%°’µÎýHZZçq€¹§Ln˜ö|=í‘<ê|ˆ:R‰:E¡½Dp.¨K´´#íÅ2í1`1ŒQ ¾û)v£û…ÍÛ/:|÷ ¸ÉýÂTŠôf呬·GÔZ?‚¡ÖºÄ ¥_@›?NS‡£S8MW‡£SºáèTÀù ê4BÍT¡Në N\ÏR¡Î ÔlêŒêŒ?ÔÜtPE*ÔY„š£BÕAõ‡š¯‡*V¡Î¿O…:§ƒ:çµH5O…:Oü>ê¼ê|À e uø}*ÔÔ¨ÅúT-R¡.¿O…º¨ƒºèU¢‡*Q¡êˆß§BÕé ên^–8}ó2Z7ˌĎƒ÷O5³Ü2šåúµ¹…(àäVÿrr[®Ln<5|r»§Ln÷pr[á;¹­”&7Œóåln•ßpIÉob¸|ؼárµßpÉ›.×8|WšNþx%3êQWÖ:>^Y§¶ýÛÄ)UÛþm]Û¿pLÝ BÝ!N© uGu'à˜ºI…º‹P›U¨»:¨»O&ÊT¨¬(ÔW­BeEi¡²¢uî­? sçë:÷­H¬fä]:´útÒâÛÈiz³v8´‡3ľæs";/º:Û Þ4d¾\É`§ƒú`½™/‡„ ®+É®V¿¬û î«É¿†hÚ2ÜŽp>‡ÎŠ¿_"W÷¨Øš<#Èq8r$G wŸ(TÿÅF ©kLIkLhöQáµõ-u àãˆM96âãΚíÅ&a¦vC¦‚‚3(Ô]ñûF‘„ßrzu/19ØJÁUbreÅÎåºá£ãܰöÄ’M+5±5‚+³‹»è x_+@8Û€è:]1›lʹï¡\ü„îC‚Uœ š ­æ—›ú‘Z°ý‚«ÔÔ™£”ÈÇ)ÎiŒs–vD=r‡üväy =o4”ÖçP51¥õ–&­·OÇŒ¾QìŽÇî ®e¦0T«÷P—tV/ÊãXÑ“Z ¤³@б/*2Žú²3ª%|™õ¥ °þ"L|§8? ÙŒÄÔµ&ôKZkØ@@"JDÆ‘¡"'2 Yš^ªº¿S–fSsòÀÀ;[dÅ„J”èÊwß(¯½_”à`óÅFªg!Ra‹D5Ë‹Eªž%¢.ËD¯ý\¢M–khïRhïñæ·L{¯D»?Òö6F»‚hïÓЮä´÷ëiÚÝ‘vvVË+RÃÿ…ÚeBÇ\@ÿ)c¸&¦ì( ƒ Ó}TúР^²J‡h6™ãkGJzÉÆ¶3tCç<·$‰ð,øÐØüßÄ~ö6tAQìמòŒQ,ÆS‘10ŠÅ¢ôDNÉ´ÊšæÛRŒ4hl.;{[5›Éü¹»%V³›eDür”5¿…ˆÿô¸`ÄñYrï+K@gé½ÒCÅ)r(¾Lú´bôCšè…rtxŸ†Ñ!íÓ1úaMt”­€îìqÂèG4Ñ×ËÑ× ¨O bF?êÀ«C¼”ö@ ë€Ò$ïÞV`X  Òë(ðöâÇ~Sut!¾ çS„¼u‰uk|êa:¦ÖHz-Æ;d¬È+ó¸5úýHºéþRÚ É),dVà‰ä XUµ &ÐYJS¶øÂ[á¡›Ç>" ÖV#£tk+OR^”á_»À:éÅÈyÂøkX”¼À… ·>bä§\Œã@³w­À³ã3~5aÎc?—¯¦ü‚_Mù%jnvÐÕ …µ!G0üÚ­».Ⱦ²•á‹Jö¾Ó÷ŠV†pCÒ†V"4èîùF’W½¼äƒy8ç@‰Ç('åÅËz¸D¦OvU¤÷=ï éSP®vT0­Y޼ «`…áG×ÈjrŒF×H?ÆÕlžÉD©,²ùG×Õ6*:zº1EG²Lx´5êŽTzsoTçÑÓé<ºèPÄÌcgºäPÄÌë–)ƒý—)GôJu.«PCêŠ 5D5$*ªŸ«*ÔP„ªQ¡†ê †FRõÃT¨QU«BÒA ¸»æ¯»°G»î2N/H7Y”¯ëøo —Má_ŒŽò¦¯ÄÑ⦖ñFíˆ\½áªMöº¯!»¢Nâ_@pîp‹ø—EPæ_ŒeÓÿ[þÅä¨ù+µü‹‡ûó/®)ü‹•1ž·n:Þªûü‹ëÀ¿¸Îù¼tü‹£CZÁ€:Ô ø˜£ª± &Ƶæ11n$#ãf221j“‘‰Q—ŒLŒ[ÉÈĸ­ì\y’¤û9ÊÀ:Ö;¾;×»´UûXs×bK K¡±› G’ا]ä Ž${Ü…÷¾F%brL&FùÜ<»ïÇ&Q ´l’þl%Ü¿ÛãaƒlL¢CÏö¸FlzuŸ—ãKf¼²ÏË×/ùQN©²â¨1•­BÑA‰ ÈpU¡Æ"T_j¬jlúþBx¿x™ƒr»ù”ñºíçè(,?äÅÆ«—ssâñrît¡vlÀ³¥©ØSgàc>ŠðQ ×üÿÞ ÝñòÚh¬æð©@éÂØ…Æû¬ÅóeÆiì†îàx\%izÞXùDF{ £ö¿6t"Ó†ŸÈL‹’¬L÷íŽCâ}U©p\U*Cã}ï‹JÁä{¯Ãâ}ï¤Jékè–Ý{é›”\¢ñ¼?†“44 o)QKj¶/©¼¤^Hhš”¨Þš‚÷HjŽ/©‘Í$5ªqR·}H9©¹¾¤F7“T~¼²Ø™‡Ý~L¼²Ø™§ëöó.vÆÆÿ°Kôk)Q˜Td2Æ£ž‚¡bz =Y‚àN[cõf «bj„ò,AÌÒVÇX+Àe5¸ìˌ˅´51ÖJpY.UY‚é„¶6ÆZ .kÁe–`$¦­‹±—uàr0K°”ˆiëc¬‡Àe=¸Î‚‹ib¬GÀe¸Í‚ûÓ6ÆXËFp9ž%´˜cLÛc=.›Àåd–ÐÒkLÛc=.›Áåt–Ðê®1­,Æz\ÊÀål–ðØ4SÚ–ë9pÙ.糄Ö;Li[c¬Àe+¸\ÌÚÔšÒ¶ÅX/Ë6\Ý,ÔT-ÔŽƒ -2K*'ŠÌ\åþ¢Ê ü–#ñwzŽ`Âß9‚gæü•#áïì!˜âç-ðwLŽÐǶk…?¥)áÏõ&gÚàO}BÛ"3%a•Ùÿ^n'š­6÷²ô êÜ«E¯–½ZÅ·bkÍž^eì cëà¥uƶ0¶^Údl cà¥mÆŒWØFx ÉØýÛ„V &Äã±âß¼ißÅ0ÔÂr,÷Ö0:£@¯î A6ÈâÚÞÂW‚:±Ù`KjjºŽl(yÌs2gŠ•l˜Å+©ñöº§tú’Pr-øN(yÔP71>(ƳE”½Ã [cIýž­µ(Ê7Ø:‹Ëãpyl½ÅUîpU8\û®J‡«ÊáÚâ@¥üî½ax>€Éô¸g¼âqï~Âù}Hæ÷•l ÂîrGz¹ƒ•Yˆµ'¬=ˆêN j_(X'੃¥(X' ÖIà°<ŽëŒv@»À:Ü<–~$ŽüDbíy-xú0{¤ùE˜‚û©wd¥ Ýá/e"ÉàO~x1%^µ¯Wæä,²œY! H-Z¶…MÆÝd÷½äŽÞ¤¾ïã‘ÝT­û}Õ}îÔèPÐ1e’l?n>NƒÓœÑÄIÏ€ê7šÌaí<¿6¤À#­™ñx–£¤gV|ÅdîâéÒË «­«1°À²JŒx_èe 7¸$' åΫ1¦ôɼI“qL™ 3†Ê 3¦L6vÈX„I(ŠW¯(͉ÇË µb*Æ0–ÖS€|Lþþ§L¡2\ŒsãUkŒóâÑìbxí4(Z;¶£a;sàYZe/‰b ž¤µQ–çåP ¬èGY†ƒñ‚ù9ùL‘Ï©¦à‘—C] ©B›ŽçVË¢PŸhÒ@‰Y]¨UŽ¿V ì"‚!ýñ—Cì&€-CØQ¨—†`· ÞP´ °¾×Ã÷N$³˜F黈d.þou”®Þ_\§Mîéo:ØU ¾OŒÛ‘9’(ëˆâ~¹Ö;Üż†‚Ï€àµô6íMHm è@ê‘@–èq¯Œ’z3–Ã—È 7B¨S¨xÉf°èo¹c¶Í%²Ÿ@AQ)‰7‡¢\ÝÝÇc=î²(²r3Jv;¦º–Ý©nù²Û ÕmŒìv@uËÝ’ÜK0&p·q˜œ¥ñh/óCJÍTšë&ô0LÙtŠà^aÉ|£’ͽa¯CͽdV¬H”(n‰âV9Š%¹¢k›Ã½Ý>Dc>ÒX¦¡±D¦±LäW¦d+$«$¨ÕZhÀc­ä±NK­îÐÕ©åDãS¢±•hœ$¶‹¨U«¾HÓa%Û)º´ š–Ù-zR§ÃRÆ9%XÌ(¢ÓöÒ(×{îePJÛxö’[Rá/ d¢Bô$m‹’­® ¶ñ"z«ò0&ó Gy>?¾ân‡¢x íF+£˜×Rƒ†÷K©Cäiä{•ˆ½¸jÙïs†¸5žK¿`œWeé—W¹ôË«ìõ†¥_~®“~éªH¿Øü¥_"~‰–¥_ð@{[¼¯ô %¿ é—ò¨fI¿l÷•~áÀMJ¿ì HÑH¿H©iI©iI©iI©iÉS³O’x¹Û_ÌVÜ!¿5_ f'UÞ3@·èì#2ûˆ é Ô‚²ê‘Ý.\×íVìvéöIÄìQ¡v#Ô^j·jwT ‰ µ¡¼*ÔÔž¨@1å*T%BU¨P•:¨Ê€‡ûâ]"¦Pw$¹3 ËÙëñÈŒîêŒÒ¶ÇX¼×ɺþu²f9;Yo¥uzßœ¾÷ëU°Þ ýyí¬B®7€GSå(’:_pÎ ÕQhøi½HkUû8_N¨êx¼QJ‘`äC°Ž®Â²Ø3GHèD¼NÈ«ø;E!¼´Š? «ø³¸Š¯‚¹’Ü]S÷Ô7=îkí‰ÈűqÊ—ÈûhÎ'ÔEsŸƒ•<!¡Î~•¼ñ3½¸-¬ÙQÛy0É£¨mzQ[X£-qJ8%RY¼WsA›lzuïxÒÁúŠP•³&³p‘4 Bì'~?eö#ò™&_”Ÿ&²€çu¦‡b#ÞŒýQ° NnLn4Àú—ÒôЫ7ý“l‘¨¼áT .&sãÐRBBŸ"Z0›¸Ù}OJfÄ›,!¡—xÉ{!ÄKÕ5ºÁP%Öks¡~«G âA‘8ÔÆ3ð»¤`:+ÂêÕU”ß»ÿË®[A|…¶R^%§}u+øãO!¬?«E× 4È\øE.aÝž }‚ËaY=Ë5#½Ë§y§~bĵÌ_Tãòƒ½_T³3ˆšú\¸¡ÂùœhŸh2ŸûÈÄÎb"Ü}-½Lö FÁ=¤Õ™Qf«.ÈÅ™ã®ÒØ^fûöX˜äÈŠ:L !¡¢<_¥¸óÂUÈÙ5‹PK‹_o÷ñF´wàíXÌ…b¼Öñ=Š¿¬b×Åò/e—œOŠÉÆâMÞÚI¶Ó«}šÛm2Åc`HèψæC¹Ö’to÷¢`–ÉJåö1òÊ}Âú’etjK?¥¸Q•Á`´LŽË"œFCž€Q‚7>2V^›†¥s1*¯¦œNçÕ›'UÏãFÕóŒ¨hf«ÙÁh½‰¶{è1R~ÚpS ð*÷ñ”0ÞÐ<MàŽ—‚0½é«šfH LFࢶÅòR¾:Jµ*\­t°©˜Ï“”Ú¾<µ³äÔÎâ©%ûê<íÉÀºORÐä{$ÙT/Gàv¯b/‘"´â pîˆÙXÌ“DÎ%’3¤a)F}ì%ɶ:•úO(1k±Ô×ÃýB{Û`tõ°Ÿ~Û´Õb`žî›,¸[@iªå—)Î6y¼ÍÈvoRÁsÛ…5ž5¾›,£ÞC •c”Çg ²#¸B¾0\1Â~€C^l/0†ÏihgË ÉlëkJÝ”´#ÈÀú£Ym/9dº[c„c„‰RbŒWcL »Û£Ř*ǘjÂÕ1T9-Ãgá↥Ùþ"…Â/Ã/0±E&V ÄÁ dNùR¼|ýr;ŠÐ\Æ9®m ,ø0nŽšÕ³90ouqîâ*ñ?eªÏÝÉu¼máø -zíŠAŽ1Ö{[ï~ +Û²MŽ1ÖÓßX~c=ôõð7Ö#ßX~c=öõø7ÖßXO~c=õMr«Œ83^¶EÛºÚÙ¤š<öz\Cçuó·Ø1²›l±ƒ>ÇËŸUôÙGþ¬¦Ïùó#}T¾Íô=Xù¶Ð÷På;ˆ¾s•ï`_õŽ~¶7|£ØÞPÃö25¸¨¡ÀÂ&}¹•¨1cî YcÆ¿C5j;n¬š‰ó3rGãû?ßêoÔýÏã~¾û›ô= ñ “ô…ë””¤PÉÍûß–\ð#”\¯ G ly”ÀæX)=š¬”÷«,FŸM*–ÝüËVç·g6é¿`OüBø_}2Pþ³kkºXJèÜ»„þ£KÅ7ï_Q|ÿ?ì䥃”N®ôã¿]l¬³'ó²EBg¶Fzùr@öȘ¯„Nm<—^Æ8h)j.½®i Ž;Ññº$˃ŽQ°L–eyÞà²<ÈØ¼ï«‘w6—ÞmT#of7é´«èé´ë| }ãqŸ’nÆûjÜ—€%ûYÝ`E•ÝMÕ¸_ïké‡GDzž#*·?ö¸³ž“©Üj,Òoy¤léDÊV"Ý~ä<÷í&éDž#çùÏóÈó%Ïwâ}m)ÀSJÎûaÎûkr~·±LüŽgbN7¢U ´ætSÄ‹ô>TÌ#í‡HÅJ¤ûÍÏy+.®4@®íCK9?É­0‚"=©Xa~ïkaHSyÞ×~Ê- Íåi:iš«¤éa 4ùY\$§©X®‹¼6Šø¢Rõñ¾—f˂阦 I)ÓÙ$ý,> ‘éÏ•é_âôçýK ý,g“ôÃ$úÙÎf応ž$l5L¦?O¦™ÓŸô/+ôû4~߯éßn˜þp™þ|™þN>п¢Ðï×<úý¾ÖÇf7}wé~Š×Źg.Ór•§e¤åª’–§¯Mh©}&K2ƒ(jÎÙ•T(v·<öQØuóñ1ú¯‘Ô–ÝkÈTy_>î܃NÒWw:qxø©Æ¶§a­KIß×Ök­)™õÝÍGšn³‘îõ7*Êμ{-ãÝë4ä|™Ò½;eY¾/2_ÔTï°öx–ŸK¶¢óè}D{ >¦› ï!N_¹L]E¶“µÉ¥ŸûS2¤÷·È4Zsã|i kš†,o™K‘ š&` Mí&+–»ÛP õá5tj¨RCþ‚>mQeÁlj¾U•çD{ô¿jtÞ›„i›Œ)ø(ÀG!$Õ,M#(‡6ÿq½PPêÚûZûô'db¯ñƒPãó”I]ýþ¬xÌç‡`¾0ª±$LÕ&á'aG8  „Ñ%á3 €•,äG`¡ßX¦i’M˜q„£€°HAÓXUš«Êi¾U96@UNǺ›™ø˜…Ùšª÷(U¹˜gâdb±’‰ñP•%à8”(¥*K9 @(U&>BU.á'`‰0éQªr)G8K„ÉNEFø4rc¦8áÓ:6Üi6Üm½q÷ê BªPgtPgü¡î衦ªPgjš uVuÖªúÔtêBÍP¡Îé ÎùCí×CÍT¡jj– U£ƒªiàJ›j¶ ŪH…b:(æuW_VsT¨Z„*V¡juPµþPõ©š«B]C¨y*Ô5Ô5¨Cz¨ù*ÔuwT¡®ë ®ûCÖC-T¡nˆ£ uCu£Û+z¨Å*ÔM„*Q¡nê núCÕC•ªPuµD…ªÓAÕùCÓC-U¡n!Ô2ê–ê–?Ôq=Ôrê6B­P¡në nûCÐC­T¡î Ô*êŽêŽ?ÔI=Ôjê.B­Q¡îê îúCÒC­U¡î!Ô:êžêž?Ô=}ÇY¯BÝG¨ *Ô}Ô}¨ÓúTmT¡ŠºÔ&ª¨›Îº×%ƒõ 9,úV=|Ûï¸pŽÆ÷×~¾Åß6uT;·Iß©MúNó÷õ±Ïïð>:Ôd:àùeƒT¨)‚`¿„~ëgÊ^ã;½É¸Ó¿Õc›¨˜wš¬˜˜&+&¬ÉŠñ÷¡ñ}ÚÏw¦Æ÷?ßYMÆí7¹MƒR? /ÈW3w:åƒ_ÞÓùÁoy7ùà·¼šBqúüîvò3^ŒcõtqíÂ3Þ=GØz»v£ã^'?øEGXx³(ùà·?øF19§›íúµ,hùk.h ?K b ‹QÍ~Q– +»U<Ž¿žŠŒÊnhÇðâcèš~®ƒ±ã`+ù#Áã¾ ø$¢%xùã]4#'üVË¡ þÊŽ=`Ý+9žS߃qKr<¯8þN¶Nø>*ðQä-¯7¼ž¶|õt’TO¿zÕ¾ªÇ^-Ÿg‘-Ø7xá¼Üé{¢-ÁKÛÁý8ÜМëV8}ÍÐKø™Æ³üÔ¦o4Ñ*üÖãî-ÓÚ×tÔL©òM<¯Èås W8ÙHJú2<õËð‚|`}@.ó¼ $ã¨Ø*qú²’´eÈJûE,ÄKšÎvÆéËÒdhõãùž ùî§äûlc‘ì®iNà.4Ý+è:oY¨X¨9ÿC |©éÀ(p¸ørs¿(¾hŒÀÀRà«Õ‚ÖÄ·Ö<¦T 7äZ8$×Ây^ ‡’qz•k¡¦Y­ð&{¦²¦³ÐIWìµÍÉïKRàk”ß^þùmŒYKÌ¢vtÎ+åýv·f¸½Þ¬¼ßÁ¼ßÕäýFÓ3÷Ë|üÀ»Ô èR”.u³é¨—g :¢T¢ÖùvKQÃcâÝ÷=í¾`b€9}¨ÉéífåtOî,Hî %¹wš•ÓÁ<êlˆ:X‰z×)[Ñ•™hRT‹T÷høun¡ÄIËŒ–f¬+)R]ïäVg¯¤xÜ;«³÷”ºþ‡ó†ÌøÕu¹E¢Qd!Z-ûMgãUž]œâU ¸K¡ø é¨­yÔÝqybà/Üй2}H+o°ÞßÂÜè¸óEw^¸{# <±ÿV6¡I² ×Þ×öÖ[“YYÂxé á½1(iÔû&öGäÛ&˜Lµþ/"ü™…ðÎBø û 5 ìïqì <§ßû¢È¾,øƒ´UCÚ*‚˜¶Þ踽…”°o¤/žªo‘ ŒØê©$^JíÛd5îxÿSf©•—1>šb"Wvkê­OÇÔîûÞž¶ámë ÷36¼]#\†º{5­<Æz÷åP1žïÅ®ikÞ¶Ž~6c x_zŠI«ˆ±nù$£¼¯f ¦÷ÒöÅXk²„Œ}àÀ²sjZeŒµ[F%Öâ¶TÈõ͵ó|:2…d…ìèòtj¿ž\Ølc‡ŒIÑ䈩ÜA©ü%¦²6K0¼Vc½tª€ÎuJguŒõ8TƒÃÍ,A´¥í±ÖÃ~$½SKzªáG†’B]žJí/‘.Ò“£É±²™Z !¡]hÜwžÂÒÄXûÿ®“õA²j‘ÒÉ:¤C*xß’~‰ïâ¡a?ª]€™×lR:Ð{Ï^˜fCÞ!缓¿D  îSZº~”#Ýq÷F(…Ùa ÷4¼0Ù…†½A>ÇeµÇv’ð«ø§„8vÕL‹FõS¢Ù9!u§%i§ÅÀΓj‚‰ ˜aòÝîa"Ûnóì§Xž˜škLÊ… k^¯€² ãY™„—ò§ˆžî§ÛX¡ &U1ÓDO'¤4]ô$]jO  †} FchØ;±X”®G‹t=ºXdóDìgÚ‹lXŽEÐíV,yš‹ršK«&Þа{­ °E…‚a•ÈV‰T|õBNf½P‰š²¾ìŒË_vÍ~ªcq~Ø7ºÂLE“›€ª{¬%£ šmÆ×|KFa4+CªS£Ù6Ñëê›>Ö¶ó·| Ú¤(È–Àv‹®QñîÑñ®eAIùñ"óˆ^¯{Ž»®_gY°ßîã¥ò&Ы½ÙR‚0 Ù’Ž(JÙ9 Š  !âka4BÂ……²Þ„j´P v¡aŸSœ¥2˜—'΢Ñ,ƒ°ß¡*&HwVl;¼Ú|Itm*›tiAAð4 ' *tºÂ îrG¯kÕS®5OÙ‹ž2¦Ÿo‚·ÝkÈÏãf?V‹Ä«©Yâ…ç¸ZÚ= …Æ)5NÍ xßy\X×pøÿT×g]\‡ÛãÊý•çcEBl, ·´nÞpw M;c]ÿa'XÄ®w0–´«] ‘¬Å$5ï]ðàW‚{à¯ÊIEÂ]¡þ)©ìž ¤ö>8ß(Áì ¤¹^YŠØ}E?ì~¢vŽXÿ{€Hبbo 89ö ‘°Ñyˆòbç¡ö’ç…D€¸.p%g7¥òµœu$+¼hd5g²¶2‘´•‰ÁÆgJëëÅûëSêëáÂ^w ÖÖrO%SD{]9 £pVîà„¤ F6cœÆ¶myÚv MB¼q_€–=4¤‹káóøŸ2—Û´)ަ@ØzÏ$¨j@ÏB-›ÌÖÚRðû)*Âö¤Þ"œ7!ca4{MýZ ;%èb?C}PÑ&ó{)«ù†P]#,A:%ׄhö¦·ããVÔûÒBA|›ý`<î…Ñ^÷€žv@Ã슎ãØSQÎfGݰçLf“y®@Ø¿ãØ™8øïŸ_‰¿c=D¦DÂø{ö{Ÿ"°z™BŸðÿÊ~wM¥@½Léz²ÿêeBº¡?ƒPé÷"ŠŠ3\/ú  j0aÓ·$\(Àènˆ^/¨|Vˆ&sOõ_u%òWJô_Ùÿ@rÿ$—ÈçìsMr«Ù´‚ü2Žýƒ #ìmøúº¢üz¾ÌzëÈDšß(‰1´~‚~GhúŸäE¯ÙØ/*Ë!LÛ¤”–Có`9´ š±M\J@3= ‹¤úŸ†ð´aoY»g {«F8õ=ìÑ÷¼m½ð‡Œ=o×ûÿ)vMË}ËÚ5#÷­€G È·LÔlà7±žh$Qž±6ÓÙÁXiÆ*…k}49bš$ªzÔB”-y/.À^\ õâÍЋb/”(ZZ´ü˜BÑu«‡¡H@íûþ”¦ˆø³ù÷Æbø¹ù¡ilda…73$3*g®ë Üsσ=÷T¤0v }õ´¦ ²è^fLNjBåªP›tP›Béí`fÆù BûáÿøKY"7š òH”—¨¿p\ºpœ_ øiÚ õZÀ l #Ÿ0µ )´Ô–ºð8] øg>AæÃ |œÅÇ]|<ŒÖ™ !qÿKѺË5ѺËuÑÿn—}×Ôe€aß5u ÷»¦ú‡7é›×¤ïàïþm.h è& (¦É k²€ü}‡|×”`ýÐïüëƒÿÕ‚õ#eNX™F°þ€Â ;€3ù¨DNØèDÎ +ã*‡]Çñx$_ãˆUN ã˜DÎ+kB£ÊØD“¹mÈt‘Åȧâ1üT<† ÖÛ™]'Xïð¸FW<þwóTdŒFñy”¥§ÿèΙÒkZõ2›ÒO‘0=JÖ㿯׻\ÎþL^ݹÔ=þûzõ |´Áû—Â?Û@üß’L>ú—Ê?×@ ÷IF%s)ýó J‘eöFv}µO”5)Fê±n–œúøD_q¶28Û1k„¹&$úJd•5 §Þç ¢56–}ÞPîH7U'§žÃ£ƒ¨9JÔIœÿ“ÑÍ’PŸœè+¡^¦—P?…pg¢U)ì)‰¾Ò˜eK¨4X/¡^Øt`½tõÔG.–sÑÍ’MŸ–è+›®oç±@.à㢦T¦'úŠ–—5*›>€Ws.Tó¥šg4  “MȆÀ@`f#¥× lú¬D_•*M—D<× ŸP>ört³$Ôg'úÊÇ–5 {‹òª¦›%ú ›—é$ÔñÜçAî)¹ŸÓX$IB½/4"õU"ÿ¯JE7KN}n¢¯œzC¥P‹¥p ×ñq7£U9õyM÷ ½œúüæ–åÔ4X/§¾°9e9õEF ­œúâÆê¢19u]]ÜŠn–´zI³Zäm,ü;šYÚtFôÒêKš“kYZ}ic¹nL %ŒDžàªîE7KN}Y³r}sý@“ëåÌYzéí~¼c ŽÕOéX+šŽ*Io÷çQ‡BÔþJÔ•‰¾ÒÛeMHo×7Oz{U¢¯ôvYÒÛ™o@ d½¡–À꦳єôöš¦£6%½½6Q•Å èºDUrT·Ýê¿ô^9€ µ ¡6¨PÛtPÛü¡ë¡6ªPÛj“ µ]µÝjˆj³ µ¡ÊT¨:¨þPCõP[T¨µU…Ú©ƒÚé5LµM…Ú…PÛU¨]:¨]þP¹z¨*Ôn„Ú©BíÖAíö‡®‡Ú¥BíA¨Ý*ÔÔ¨<=Ôj/BíU¡öê öF’Hö¨P¹P¡<:(Ot ‰ärÊ‹P*”Wå$‘¼O…*G¨Jª\UH"¹J…ª@¨jªBUH"y¿ µ¡¨PûtPû¢I$T¡*ê U©ƒªŒ$‘|X…ªB¨#*T•ª*:DòQª¡Ž©PÕ:¨êè@ÉÇU¨ýuB…Ú¯ƒÚH"ù¤ •ýÞÆT¡²ßÐBe¿H:ðt¢,8þѤ—ꥷDã$€\äÄ µ^nlÀnìê ¡—f âdKÚÉkmëÖ›=¬·{Xïõ°.ÿÔz¿‡õaäàŒ“15BV‚qXpÚ©kß„Ô'Ã…pà û“‚uÍáGgz¯ç"}¬ #}Lÿ>Lô±5‰>Ìô±XèÃC`áAô±ûÓǺOé£}ÌqÑGKúØÁƒµ¢ù<Øcô±´¦¥ü£ ~¼ß6ãdhP‚iqpÚiÌPGÈGGHGIo^ooCImÞß¶%Éné ’+½mOrõ‹…Dv‚´u„$u‚”t„tR§‘û¬¹òù´ó1Ö[=¸´Z-ü×ÁÿCø¿ÿË!êMø½ÿ—Ì ø;½ß*ý<ž¸žM-µv×nA#¨ÁXû †=Á5BA’€?cú "þn-Œø[ø´©"˜y‚½hâŒyƒ½î =¬"øÿ©ìKà›<®}¿OÒ'É›,ËllÙ–qCI›¤iÒ¼EY..`»mÚ¨÷ÞŸƒ-]÷5ÜæRÚÞûë»¶YCØ Æ¶Ù±Í¾f5«–Øf û¾yÌÀ`½sÎ|’>é{¯)þF3sþçÌ™}æÌŒåÅûVï’ ËÞï#. yâ‹.©Ò“t±q‘ø] ñ»Âù]‘ù]!>ê+œ­¿­µ¢tSÏ®é . Âp%Ç¥A—¦¯„6Púìv¸r ´ì6H7_Éé\š¢yNÖ¥wi\Ú¾½ñ9½Ïçžï,¼0£ÏY^4ßIÚÝ‹ð_Þh)óSÆó¤ñÍs¾D›¹ÝzŸŒÝ£ïF ÃTúظuc‡ªJ£Ù“(T]éàvö4ÊWÉ_!ò¹·gWš°t÷DAé.FÒZ±ƒ•á¨Y¶Rô»§m4ÅàÉë¨*~6¡ô3l4¬¥Ÿ¡µÂ0RùSb?#Ù*TD³ŠhGkc³¢©=òÎ(²¯ðX³BwËŽ­Œö@S,ëî鎣6G˺kŽfk(×=Á¿ï #e¬‹Fk…4»ˆnÛpaO4ÛÒ,I"iö¾Hš iN 4§xÕ'²4ß+¤9”æ|4»H‘ÂÒ\‚ßxÖ\Fi*P!j7Dh¢>R –ÅȨe1lL F £Ž…ß9ê8Ü)}< Ÿ_L ºE@Ç–Ä@âpôÑ=Lˆ)RD¬a10 \bg«ü ‘gQ¤o|'/´«rºWsØî[Ï+b·cìcáØÇyì&ˆ}’Çî¡ØŠ}c³|Ð,@zàmAz—ÆzÜKí hÿRëñ8º³…’¥vVNÞhKNââX X !Ë1¤,7œÄ†X9‰ ±lU,$q¹5áÎs¹‚|’·ù $CäoRÈÑ ùÑXæ¥ÜjÛ;˜}‹p+ì¬=Ö3p>×}"%dO "³Ø:ºÈé®uÜÅv{\n8û'ÅAäÉqiÈÙ?>7œý3ãdQfƱY)œý³á÷\„J4Ä@" àQWÆaÕ¦¸õätŸ¶ä°Fp.³£S&Rªß"’µAVkãØzN U›m §·è´Åˆ@›ˆ²ÍÈô ÓƒÈôp˜éÎô,0õp¦g‘é$Óö Óö8v,Ìô¸Ìô,gzRfzÖÂN!Ó/ú»L¨b{Y“IV }ÄÇR$o>è=B˜) ˜/ 3Å࡜ 3USaa* l6Eâ0•€™¦€YŽ0+!ƾ|fº¦9Ól`k(‡Y‹030{fÄØ„™©€9„9l`G)‡ñ L…æ<Â\„ž`ó9Ks=sÝÀnR$s af+`Jã¦<Þa¦RQD'ÆË0ãÙ$Š.¢_ÂïI¼ˆNŽÔ9 Ôˆº"´ÓX¥@]D]Ï–Q¤0êrø=™£®@Ô¹Š2¸QwćÊàNrº/BÜOeð"–ÁjbµšûZƒ¼ZãÙAˆtÑÂëû¡øÁìH|¨Pç…ò"/”Þx^(/ZØ·‚§ 4š‡=uáeqm¹ü¦0kƒs`”ôS ìˆ/¸,Ê‘—EÑ[øÄæ^úÿÇaÜcñž‚ò¡Žò¡B}ÑÄ vR;§ö¦vU>ª9G’?þ›p!ž] Éǵ±‹ñ„¸ì½ú Qtš~-_ó¯ ½¤½ÏnioqÚ´+‰v"ïÊŒ å1FLoä¼ûJ‘w_e}~ad_R¤pÞM†ßÓyj¦!5 -ò2D]aô¸°E®Q´ÈMAÄ&#[Mx­1fëŒøpƒ­äÕy"×*ämEäƒae¡,oB^oÝkd~Š–÷[ø=ƒ£¶!ê"’7“èÎ ê9c¨¬'gþ¹l³cÜÅ `܇v XÚ—($è JÐcd¥ ),AüžÉ%(OÀع8~žÊ‹îÊ2A…ñpSkHðäíÔ lU‚§`è¡BIt{ w“ݶgm¬9ÁK¦g«`7`@þ4‡š­!·ÇÝl÷¸WÛÉþlmBAû/‘,¿ý—0|"„þE׳õä,¼“Tt'‰mý:ÙF”k™¢lµ'›õv,Á㕚´ìD) »ö“ µnÅ2´Ë‰ö5¢½@´5½„ ìÒ¯ËÄ‹Ôq…œ^”à*’®P² [–Àî éõ$v7LzO&ßûHºRAú4Hú4´3‰•šB¤e&N ¾å& ­§¬åÝýdí¦Â_ºÏ¼mMÄYæ$øáÉ?ó6t+¹!W‚øžc3M8ÉÑÁ­.fš¸ÙÅL›eB³ƒ=:èUˆ4jMší^hðeΗ0‹|õ•¦ahl ¹®ª6±*ÞQogsM_Éj;«6…r¼ƒÍ3ù)Çç›ü¡_@îˆ_ˆb6*ŠöbLÓRS¨h/#Ð||“r9Æ]EªË¦¸&ùÚÛFk2y1b½,®÷ýc¹âhÜåËUKq†'j"X*×Ó\˜WÿZXo¢GR7›ØF“üHêfÓs¤nåÒi¶™ð½Ôh<¡µAëuÔ8ÅÑ&øã$a»ONš"µ³þŒÁÜÎDS*|ìs¯I9¥Úg M©:Ípp²[ozb6yòçØaLC`¡§â©ço5É? ÏÖŸ‹‚S´6Î}ÛM¡‰ÛqpÖêLÇ1S›&Šª³ UEõe;kÂ)÷£‰4å×ÁΙ¼øËŒÏž'2üéÇãÙÆ×p­ÀäÃ>ÚÆ—üè@ù —ÿÒ½zpC%Ív/FR±ËÄá{™C±†]ðÓŒÆèWydøéÒŸƒç5ÎC¢ tÅ𵌠—\Üy†ÝÄRÓœ«™ü ‰JA7•~ʨR¼¢B—%²§¤­J9{r„Ñôpi0+K„ÒµÁN©“è±–l°³±‰Þü}9—8˜}‘è)H÷º[£é¢c½]¤•‹I05Ñ뾘Sx!Ç]ë”õºý9£éyÝ鉞ü͵3d¤™@P•ˆ¢Ü1HÀnÍM¤ Þmàq“—XuÐËã^loðSôœ—èqÔÛPŒÎçqÖr²¸`±Y 4‹ìͦÿ,LDm¯ã°ÂÓ±ÃÚD×qA#~0ÓZGñ0-5,AW†R¶iˆù3Q` ‰˜2.34'zBâGÇ~èS`¿™È×K(°hU6[öX›]ÔÍÖqe“r#@¶å˜ðáÝ-ÏA¶$žÚ*\ÇzÒT ñVFÐÈJ»`ú\m i(Tqv'Ö¥ºw¿;ŽVèöЯ=ïŽ×Îö'zXk¢ïŽÛíjÊØƒüÃ2×ϱ†ôV²-ªü‡k!¾+d¾>â´_æë§_­Ä·øvü ßãÀ÷¤\V΀ûdRþ!èÊ.&â]Ô­ÿŠŠøÍDù,ØÍDÖ™ø\¹ˆ„=Sjù›×wù¾\2 ðš\-4ÏŸóºÀ¬'”¢•XFã+òƒE*3{X¹ÓÖò.c¦–I’{úP\…$K2á ë83 h°8Œº¡$|aÆ»8r5Ð…}Â{03VÜ6:(\if³Ìž¼C0ê¨ìöÂóƒÊ;ŒÐ`Fù}™0ž¬2{ 7êÖñæ\^÷<çhj‡æš=^Ù#ÿkœJ™_S«özµ^Åæ!Óu¤Ê¡Ä´†6T¿"Ô˜YÙK±È<˜-1{=E ³ÙR³×Ýüʪ&m6AË „ÿÄs_Í¿aËs}®g¨Šâ=¦¤TM=‘µTS,C ÿt”¶F3‚n4³&3vÍèšW›©T˜*h«ÖŠª­fZŽTo‡¯§VÔœ4³õfœ`´¢y:¶ÁÌkÖ2{ÑÁl¶‘ÿ*Zjd[͸^ ÜÙ×fñÕŠ6áw".ÒnEëýåÅQÆ—q19Ê¥Oņy‡Ù¥ÁxfÜgFžÇý-÷9I…þÖŽJM’•š‰9ÎN™]ÒÇHð®øDDõ‘Õ÷I ,’Ø9sxÈzÉŒçìBÉB;»lƵü¯4Ð/bÙ˜¥£SÝ×eÍß$YL÷p ƒçêÌtr;"Cº0¤†‡Ü‰Èœ{²‡ÜȨï1dŽÎìÆŽˆL{jÆÕ}~*ø\Ç'YÆZ”Ëúã1¤ŽK9Á¢,2_bH•Î< B¦XBãÿ©–°2§[Ð …`;‚S\¸A¿ýàw–ûÍ úí¿sܯ"è·ü¾ã~³‚~-àwšûÍúí¿3ܯ E«Õ™'Ê£.i¡…F]ÚE¶Ð¢ukYÅ¥ t´ZKp8åÒÒ@g‘%b<¥c‹-.]VA»Ä$éˆv™/ÊÕèã »´|%ÓâyÅ&|N-|qW Z¦ µL ¶Ê‚-“Z¦f o™¶Š/´L{,¼eÚoaë,ØþX±9ZO¹`Ŷhƒì„¶h‹EY‰ðàôV‹²¡Ï×–ˆêO~Û,õžü¶["*<ù}c‰¨éä·ÃòLGÏ–gª8zî±`Kéžïü¼ƒíµ„w³ö[p×­ðâ Üw{[ÞwK¥Y…šâvÀRxaµŽxÚç Å%ù—»$:¾xˆ@]h?qBŽ[‚û-¸Å¶QÞbóÊêî“PWý²*ç·²jc›ì„ê×.;¡ôŸ°„Fû'ÉIº>m¡…a”á,9ó›;gá,´'—x-iÆ™®…7H5,Áu o-ÐûFXš[ÞT ÷í°dÌÂÛ‰W±m KyÏR°SÑH –ïË^r#^劘Âéê–[ô~ÖR@®ìcpÔÑ+”Þò^‘ÇôЬàè7¶WdG¿q½"+8úïYÁÑoB¯È N7ô‚Ê´‘æéïQ]šß M_õ ÍË’Ó}";‡Õ‚ód¶{‘„CtÚ(3¥U¢QƒÛYU¸^³ ¦¼C_yµ¥A®îå-\õAщl¶¹m†ùÁXÇ'úË€s@;ŒZüµ0³é5BD ‘*üjFªGˆÞ‘"­8,ëÅVp©pGq%9GˆŸˆkü5\Rü÷T‘Ó}ÔDŸý¦!U¢J!'q`M@ñΦ\d×öQ=v PçßóoUÝð V‰Âª´*ø4~ ¨5ÂZø ÑìEmíçrP) ª“Ù¥sE#½p°Ìî¸dà'š7*5ÓÆ5ÓÁ5s2›CÍ|«ÍÌæš9ÒÌ· ™#¤™¹/ÒÌ‘^ÌÖŒ7¬™“ÙF´ø6¨ûâ×Qî@‘¸2æŠÊÚP[ÃÊ8©Œ“AeÌåʘTÆ6*:ïðÝpTFW¸èÜáEgOïvœõ} èØ驾¾…ˆ{_Û•ê)M"Àò$oaÃE{z³1Ix—©§„oÕ†´ÓÚyÜ‹kEÖÊã^ìIX+OÃZÙÓÛ˜†½w$x;&XE€c“ä«(Áã¡ lÀ„ª4ÂE®W%á½'I¹^ß§´:œë—!׫1×w*“µŒ'kEåz}¶“Õ¢Ìõš¤`ºÚ!]5I˜®êåzM«K ¥oQR(}õ}(×—&½ ׫å\¯ ”-C%ì çz}RD®7&ɹ^Ís½:˜ë»(×? š¨Œ]I¡\ßMNw+äúÞ$œE…fì{zÛ„&:í£ôÁ-ñRµQ„²÷KÕ ±ÝJù¹ÆÚxAhíÍÚQc{ápHa °ÃIÏ„ÃIìhXQž°¢ZyAð£v‡ BGdA8,j¹ ìÍU«ã ¢¸7è–ÉÎ)0ýO‚’hï$±[aUÜæªhì“ÃXš›¨Ñܤ´Alcw’`hì…·®ÜMòb}ðáì9ÞIjÁK¤¨ºXNì~ZïSꥼ7/´½©$5öaãz£u,饜—¤îbŽbºI1 /*IÝIìiXA=a5ö1b‡XÖ›—$*AˆÀÊÁç}áb3¾wD±™Ø[.6 ¼Ø4‹M+Õ¡—ˆfno(6ózG»¤¨ó–QF=¯Aè†D eóåò†Þ¨ì*³ÐÐ4ĆÞl§G¦&rz}ùÕ0ÌCm¤ÕW'ÑnÚl˜Œ?™* _÷fÛ9/wÓqÅ"Œn3fbùíM5˜<ØžÞ^ZÙÛÛÇ[ùµ0oírHÿ­¿½7;Æ?Áñ/fñOsü«„FÆ?ð>7®¹LûÞì^8Ñ÷y¢—²Åö={×,Øð!ê7x;Ú‡.Ø‚ê[Þ‡í"ׇ“_Fò }8ùu"? E)ÎPÈ—2€<»ØÏìCigõa•}Be¦Jƹ’-Žn7¢%Î|ì†|Ø‚>>JåW}”©¬íƒ×uxŒÂŒdF«ú°æ0£52£«!FdF7‰ÑF™Ñ¦F[‰‘WÁho˜Ñ^™Ñþ>ì@˜Ñ!™Ñµ#Ìè1òÊŒ|ŒÚˆ‘/W­‰3ü›5!£btíÍÏr~ªó}ØEÎǸ—9?Ÿãz¶jt^®s†>Çm x±}üÄñfÇÎ>~4ǦZbç›d}ä’ÒÓ‡jIOVÚ7ØS±²¾2ŸÙª6¦¯Ì¢Ó¢Â׊r%)Îð{nBÖW†™Ú—`ð³7_…ŸšUOíËfpP\® '›Õ5Ž›ÙšVEÐl®ìÇ,h£Ö¦ÐÌ’¾!Í,á,ðƒšYÖ—­èÒL}Pâ[!Í4Åî"Í4÷åšYÝW©™u}Q3í Žß„9~Ã9~#sÜÙ—í sÜäx;ı5Èñq< s<ÁñqìPp<æxœs<.s<Ù—}æx&ȱ3ÄñBã]âxQæx)‚ãUâx,WÒÆ&òVÿ.²Ä 0ð¼ËyÞåYw—gÝ].æA_öK€×H=æYØÌ®lÍèb ÖX€gdi2¹gÁV–ì’H òd¥@ãÀ­çsµ1q†ë|r¾-%ÒYKç¥ëéoT§x¼V¶%ÓíøY÷{~öæ«ñSó¯üt “ÂçÌLQ{)™íI&+K4·Û› “‘CÉ›EÉ% Ù,jJ7‹ÅZæIöx]ZÇa»Š"z“ûç°¶ä‚–— 祸׽K‰ïàRÆÎ™¢®#™K.˜—y0;žœÝŸHˆ!óR$˜}—\°óe—Þ±óe‘0OscöÛ×I"÷Ál5sÅ:v#ÙxL„ÎpÈMÂ’Û1ä~8äyl\Œ!Ý¡Ð2Vy{’lœˆae)Á0?•y*O1ŽÄ  Š ;•öóºšÐ³fT+§_£Š5Æw±ïj'’*¤‚rù‹~PÓñö¹)ýB 2BØØ~-6¦ŸKã·¬‡Â1³æÂiê‰ù £ªŸÜ…Võ£v¸ª«æìpÚ1¯_¸'~Òô wÍ/ÒÚê«Çr­- rZÄ9áZ|ü@‹¿¨[Îùâ¦æJr²ú~¡Îài›¶¡Ÿ,ø×Í$[Ý/Ô…c®é'ËÂc ÂYJ6ª sŒ s¬;Ñó°¿8INH×z# @¾ë‡ö­ç¨„ñ©uQoŸ, ]ýØ]N‡åÿ§sl0ÂPõ‘W=2èW°Lå²L…Ø ¹ºø8ÃBÞ-O•Ï,@7´n vCàŽ²–6kŠ£éo ùÇ‚¾>–§vЧ ÎàwÛpÕJüùwõ*ø|W+jÖÁwѧÒ&øœ®µ·SÙÊTœÌv›PÚ9¬ƒÕ§ú©4¤B!Y•êw×9K9‹5¬)Õ¥áuÖ¢ÅN#ÚË­I-¸nrÝ.ðHëR¡Ó¸—8}޽vu©}íúT—Dˆq!"~!b©Ä­É%ˆ¬eÛR}¦%¸ó•êÒ³pÐÌ Cw§b+µn ûî{Ô²üg°/Ü›Êö¥¬y0ÛŸ ­Tkª—vd²n –´ÇޤFö‰GQ0_ªKï^?°´f·þT/|‹°a ¥åX0-Ç1ä, 9e8 -åùTv>Õ&ǹ´åÅãG¸TmpÅÑ2ì˜/F]LeS]Q…Íš ”wìRª+º’á¹¢Ý-Ú¡õ€KrE; ig·/§b£Ï®¤ÔýÖ_÷[¸½fˆK¨ ô}»ÍyKÈ{¨’·®SÝáùô?äÞ$¦4•¥a>•¥ñ`Vžù4&ÍËÆ¦ám…ÁLŠeãÒ0“b©Ãø"-´Æ>‰œÞ¢=o°)iØd]ÌÕÄÅó™|Uî¤KÖÒÏøov°²dGSí¨Jë/@íÀïÅZQUEgÔ_¥ae×Ô¤±yi^Zç£s?óñÜÏWiÒ K †Õà oyq¬ñ}d¸b]1™£p¼ÚÍU9À¤Æ#!£ÉH`æSÄÂ.¶)-»ƒm…è”_ƒÃ½ÌY ¸;ïH}É?šªíNdºàeÎafmtÑü—Ùnˆ®eN¶' ¤ˆ¢õ–š´×bcV÷ô±ú¶B Â%jË'«ì~Zhý *ßÃ4nn‚Ð# s¯"CÖ­ü©Øü”Ãár®zŸ2yåÔJ†jÔæµR›ŸÍŪñðYY!ªç[ÙD+ç–‡EÐ.÷/­|l8®Ãøc4~µ†­3Ì>Å*»tIñ4«l ÓatÂÏ™V2h1áˆp–5Ü©ôl+"ÊЕְ1AϱÊö,z®U6vé` ¬?m·«Gc±µBÛ0µV×—ÿ]ÅYIÏWrµÑq†½òú©•f_¸áÿt¸Ÿÿ ñZü‰PʨýDÄÏâ9¢j5|/ÕŠê5\GšµV¶ R²Ï.P5Y!‹V[ ×½/kÞë8ð¾ 0k"üÖƒˆ·^©2ìå7Z=l“•®Ùf«ß`[@^­M¬± hÍ‚ó»X ­aK#3L¾Ò²Š½¶žW Æß‹ý‰R…´-¼7_Ú ‰Lµ{à[6MÔí³âÈCßje»ƒ\GAÝ’½&@˜¨­û#<)AzÖjué]:NÅ‚H‡¬|\Ï[ý.;b…* 'ªkØtÉŒ—Âûê[9CY›Õ볉dvÜ óWÌÏ¡üR¹bj‹©Ø‰ô‚}Úü}Z~&Yg”)8L£ÛÑóϦçBdz.¦‡“B)k¢ô\V¦ç*¥‚ÝH7žS¡’¯Áðå{PòõZ1öQ:»óŒ4w#”|/ÝX¯ØCð$ï e¹`±²`q¬'Ýkšd¹JµÄÁŸFZ_+ËalªZhl†Ï‹ÚŸáŠm/Çž'#RËSè7èwr ªrjFP•33"…¯ÈxFÎYrjâ…ÝNÆ3RÏÉPJ]•ñB©«Ÿ—z>ÉÊf§à Íâ ›ÐΖdðÏçĶU¾± udi†±#×g@qCdt˜T(£¯Î•¡ÅjLõšPª×fÈÞr KÄ×?C(þ¦ ãeœdo˰æOa÷œî-6°ÊôÂUñî©ï¸ ò¢®Õç´ §HëC+ÉsÑÛ²§ŠÖ‡V“çâ §šÖ‡6‘çô ¹†Ö‡n‘猠§DëCuè99è©¥õ¡ä9%è© ­éI/z½!ù¿ÁèýçÝëÌïléœè¼ý4PÑØÑ€0¶3£ JôùÑÒ¡Vì[Ê'ć2¨ 9”ÁŽd„ö`ŽfÈûVw³UÌ“G¿éÀiÞÏ Ó&n~<ƒrñ,|oÀØû|­åª¯e°S˜4rvÌz‡OʾËÀVFÁù¯ã|Žøy;;Ÿáñ9ÚÑü¡ƒ]ÈàÓÔ‹íJ7Ô½–‘ ­ù ²dÆ,Ããw5ùÝûMhà m½gÝÉ ói\üŽýÙ[v+ü@_PüÆd–eâÄãf®g¸¢á<3yO‹ Ó2q HÄÏMHåÔLZü™žI3Œ™4☙‰Ý•¶"“MÏôñ6\ûMØ Í×1 9*À5ütF V‚êL´dÚa+;ؼLãEô«Í /ü€w]¦ñ0z/ï³E.QÑqý ‚ÑÐy¯Ì4ÎCŠæLÐïNÂ^ÉWn7"%ÌYZì*ðÝ”iü }·ËUø&ÓøÏ°›óÄ}Ã= JRêÞ"ä»/Ó˜‰T‡3=ìH&†À˜HçØe×äÑL£¿ÍìßÁÚ2Ã+·³3½Ð´ÍÉ”WnõŠ•Û™òÊ­^±r»$S^¹Õ+Vn3å•[½båv]¦¼r«W¬ÜnÍ”WnõŠ•Û–LyåV¯X¹=)¯Üê+·¾LyåVÿ+·zZ¹ýqOàížÀ‡=‰´r s¡=!èÇWngâ°é­3MâëZ¦lu~-“ÝÈ$Ss²(¿™9˜±L¯»=G^vóº}9¨ùúJ²àïÊôd—|igw3y»÷¥‡‡"ÈÛТ­ÙìÞ3ûC›³ÙƒLoþa¨lßgâ $Ó0¾u©'“•ÚÂ"•Ù³16Þ¶#úØ ÀÆÛ<ýQœ 6:ц+(7Ϙf“A§ÙØ èLeCpZI˜˜ ä0Gþµß„<ªdՈͨušË§~ m|r±uŠ·jEq± k«j© k«z™Õ*˜ÖÓÅ6~¡-µ‘Ú`gó=£'¬Îõ6˜¶ÈÇJ|ò-. xT@­²Q3„/E¬¶áË xtƒŒÞ×@è:J„GÐëm¼îÀÚøÏ8=²Q ‡o5l±ÉG_åãLØ'oUz¯|¯žzämœI«Ìd»m0Í÷7µtûPE]Š3~‡ƒê?lcGm¸ªC¦œ´ªƒ´[ÁΗ½´HãEÚ; ÚŽ m‡'ZZôÑžÓžDÚ»Dû?ùÆsö¬]°á’Ïh~p–6-nå:@ÛE(m¡#V—å^.ÞÁÏ _¢\·±[¶ÐÒm[èX'’ܧ=Ïÿà‡^³d’²,謒Ä1Y¸l¤šÅÆdyÝûL¥Ÿµ³±Y…L%ߢáq7Úå¥ðÅU/óãã²³ Yh9cø@ü[÷ÅwÑv©ƒ}™åñ÷Ïß:Ÿœ…¯Xäjtq†R> Ÿ‘¥XÅ"afpa*àsº”¦,*ÍY¬"$Ô,Y¨Ð‘5ösrÍ’åš rÍÉò iI‡U¡Ó“SrÌÎæfyxÕï°cŸ¹2Q,9ng5YVi÷@ çÇ–å¸ËsêñÌW§ØY+jê²X]–’rÐ-P¾ðUrÂÎgyä3øGã/Å’“v#Ú-,ÏòX1Î ˆ3î}ðeMY2Ô³æ,ЊƘ'àxœÕŠÒš,¶& û¶àšÚÚ,—Ö=#F^¡ág‹šÄ&»ˆu.w~ÀzkÎjÑàH=4³0'¾ÏUCNç ÄVȉÉy°”Þ-ÄøNÿµj'|NôW·ÀÇÿSÍ®,¶$å5 ô»# uêq³×þ¹íD RJH‹¸ÔjþÌ7È÷Ïî`-<±KµøàÄ®,RÓq»¯U„/N´Bø »é3TøHÿÁ,vŸx!ð  Š9ÌÁNÚ}µæÒÆ¡œG@Σ‘lüà1ã4¨©6Œè’üü© ‰µ#gP$0MÀ¿ƒ‡ƒÏá8¥Æ%Ñ{zY¼}?‰*~HýǼ¢ëÛÙ,v>¬Á À%, P h ¿PÑ% 1ô˜&üâ·4Dœª¼àë£×‘z.ª$.Wæ7N,hü¿ª¤ä•Âåü÷ûMÏ~¡" ÔKu^øÇyy*•Fz·«Âèù>ïß…×™ÝÃÞ.¼<Øqñ]¡äнç)Ü-Ò«vösLô^k".$¾‰+ØÙ/i~>ÆOHyÐ_yÜW±œ, ?!ÿßÉ÷[üŽ9=üÈß{K£à”F# |òâ«OjEõßÐ@\S*²¿øÜ«œ~ø—ˆf'-xÃ+öÇ'‰{ óçP y2HT³ÿðJké$à~( 8->ü—;Ï&§ }X©ˆã\ÜÛŠbe".`¢Àéeå¢Ï%¹›~úë8—¦.jvA‹ä’PËA±ikaž$i¤É<-sD~Þ·Sü~–(Ìbøƒ_H†j®ˆéP׈¬Zôœ'¢„$àBÑ’°ƒÕˆ4äLGkE˜&‘|u"94;}Žói*«FÄQ¤Åj±‹8_¯QJµ1Bª Å#j£,Õf.Õ‘m KµU!Õ7RíPHµ3$UKHª \ª‘Rí&©jó‚Ïw¡XY«åç»6«û•\¶“'ÞWÑ$íû/¸=vL¹(~+~tcÐÀ‰•Ü€:=¶\T?º9hàì¿–Üqå¢úªøÑ­A+ÿZr «÷¢<|u÷Õ®}Áꨘl’*X nÚÙQ•çC¡¤ËΞPÅŠvq¾’—EëðÉë *»ÓŽ›_÷m{©WS<îÇàÂëvòðáÞûëà{Ú_«Øv¼ý¶}£ò •µ¾²¤ÓÎvà#­K‰A‘œEçʵ,O­ÑêæŠtUÅMpÚmB¿ÊQÅèzufg7‚rß$RS>ŽÏ×hÄÛ*ÌUU§Šuª€Œó.UÁbŠæw¯q:«DewÀ«Ëîs/àg(:U-j?FÂ3­x†BE×W<8,xå~¹Bø©Ðà°éjû. ¿Z|çC*Õ²&*Õ¬J 2ß…‰žïÆ¡Hcy S¬G墰XÍ–ª½›~E÷Ü,Š÷aHœÃVø-{aÙû •Á31·ìÖ¾°´’sXƒº°ÅAå·]^|%2‡5© w;Ü{´Ù,ÿð:Ö:!l ñ¥Œ<µZ«³“0;BÂìPwгÇ´KÍZÔxÏÐîæâáXxz0Û§öä÷àxLT%ª?ÁœÁœV³³r¬sjùþ™ó½‘Ц…¢_CÞPrx¾D4ÃZ•§Õëb« üDGRеYV'JOÔü,Š?ÒH|ÆÔ€º92†ÜÆböÈò0¡3‘œftZÈÙ‹þ&ÑY–¢·øñh‹K3R¥‘?ótP:Wñûøo*ü”׉jüÖº5OÔl¼O¸$àÖùDpzÜ7í¯ÍŽ©ƒj¦Á6$c“4§ò!¢~È©|h 'ß´Â¥ð©ø[câK§ü\›~’Õ<[„É!·¤a’Ùl ›öuÙ §ÉTç@4] 6œýG&°®cÖ…„Ô…GnLP @S¬ñŒ¦¸b«¡;*ô€P*o#Ù2:Ï+.í+ÿ" (Ö xåÇ#E¶BCší§×±z„H$Ft&$à>MJ}Œ}4§±§R£VVGje=ã"#ÖDœG³-Ä#ì¢vR°•j)&êÓŽâ1?1Éj°¤`cKñ¸r1[ö*Åbì eËþHŽh<˜/6ÒžÿÈ.2×FxÂÅ`Â!ÁFÜ9Ε%Q¦|G‚F±Óôfg¸ÖcØYîˆeçxtÌõŠQ#ãØy ^õH»€QÄ‘ñÆ65äÐeøÓyˆ ÿâjä7.GÖþÅ€ˆD|ƒûéèÑ­›˜tíÇrÐÿ]õ(ºÈùVdлªQ£€£9Þá1$Ö]1=Pñ‰6ŽPÁÇô#ŠukŒkñwLBÖƒ©B0³2 #[Œ[éÑq)$²9(ò8I!òxéEž =/r/6‘S÷² õ#-ì ŒcÙ:Þå…NùR&äGÒ™²ÑNHâòOæ´báË5t ·M,¯AýNE0óN,UfV.ÉpZ‡–ZJäæ„4(lÓ%c-n–Ì’B‰CTÊ¿ÑÀæ(uRýÌSêdþëdÁ t’ľâÔI\' ÿ±Nâ¸NjeÔý NjQ'‹I';¸Nªþ±NâV‘N–JÆ)˜Î’¢â‡Š·R V¼zIYñÐb“}T]¬c4…7¹tòî6$O5…7ƒ>¢-BfJ…·‚>ªÐÎŽšÚNµ^—<6Pç= |ô4ðiO~°U’ñ/(Óje¾Ä²5n5EÿW¢P€x Kc „øãÁ}M±ï‡Ý¨dÿ÷ÕÀ}Õ“À®'ê@~°‹VV,W–ñI€­—d=Ê*ÕT¢‹m”°ØŠñ6ÁKGqIj´D÷¨Õ U¹ú õ“AO]×tkÊ¥SùëœIë‚( œ‚J-lt êa“SÐÄFGov ’&6v‹SÐj„­NA' _;}Œ°Í)DÅ ÛBt¬ðSˆ1;œB¬AØéâ B‹S0¨…]N!Þ ìv ÆaSHˆö:“AØçc…ýNÁlZ‚%V8àz„ƒN!É 4å©`÷åì“ø8q?öItìõ€ÄZ%VŽ.êß±Wš@‘ýsØ Oº¾EkÎk4ªC;$a¸+ à°Ã’†m^ù";¿ûs4Yh•ˆšÃÞ¡~a+d‚OBÛïf§’DßI¸Ú߯άé-<¶„s;¬ÛŒ)Xb.H4j¼c÷Ê£ÆüÃNÉÀüÍD?è—%ß>±W–<±³+^T•§Qët¶NñŒJµâ„/E±TKŒËµ-i^_!³;ZÒðèòŒuTM¡]RðümE(vI¡ƒÉ0°QóNCÃ>õ-Zî§ã½|>G/]»‹EH„Æ †—/uˆ«h1ó¾4˜=$í›Æ£í0D%Jµï¬ÎC–l‚Öã¾g7ý5hC­–ªPrq: Q¡(l’Ë­ÜÛNÖ**ýl¨ôS´¼Ò«ÙT-¯ôj^éqá$ëÝ9hæµÌI[«U:Üâ®Cﹺ‰UàoA¾ <¾‚Ô/ÐѺ͆3EâŠi”ÓÈÓ¨cM Šn{Î"Vë<ùa¶·Vç)è‡t‹BI·­TLqÀÙzéã“(}p{p‘C0zÒeM[ÈkTþÁ4‘}­ÃsW0×ÐDâso¤P®²_A•ÝA÷gZ¶SÇ+®–*n?½Äö 20¶;ЫFA#¶O‡Í7M’[uÔj6!äbjrĹâr±I<•ÿtö¤ou8E},ÔdµûTkƒpÚ©…b ]#l¤žæ¤á:œ Ï+ §tì”õ€ûò6vZ‡•ØÛÛã3ºÁ씣’[vvž’O[§‚ºÁ˜¤›K:Z“(ìëÞònpUâ2>þ± —˜¤ò2O‹Xp&´ªÚ¬Á¿ß‚K§%×ù\—LßNüQt‚ZõiÑgüɨ?þáßGý„»9²èßF|Çéññð‘ùÉðwGñù¨á£þâ>|¸ë³?ýqÄ¿SÄ᯿úæë¯¿òÆ«o l„Û=¢øóQ?qþáÓÃñÏ ?ýåß?()úxÄgÿôIѨQ‚ö‡"þæÿVò¹2¦ôLÌúìO£F9 |xÈ¥Œ®û!àß}ªŒ¦ÿ¡hÃF¸#Ø ÂðW?þÙÇ#^sÿ¢øU÷/^ñÆëý þÿúko½þê[?sýì×k?+~õ5×oýâ7G¸‹_yãÍ׋Þzõ¿xëµW€æÕ7‡»©døÇõé'EþÁ§Ÿýáó¿DÃhô éWô¿[ÆþúÈ•wà?Aø?ØÊred5-1.0~svn4374.orig/webapps/vod/textLayout_2.0.0.232.swf0000644000175000017500000114256611747635016022522 0ustar drazzibdrazzibCWS ò¤ xÚĽKŒIš&Æ.Ö“¬gwuMwOk§fºgº» 2If2#É$##_AF>˜IVu³;Ç3Ü"Â+=Ü£Ý=2™½;ØZ@'a! «•€…ö0Ð Z`oÚÛŽô€.:íM«ÌI =ìA@Ë~3swsws{xp ¨d¸»}Ÿ½Í~3ûíÿ_^yý¯¯\yÿ/¯\ùÁkW6?úá•+Wþþ÷þçï\¹r?°‡Í£ÍíO_N\/lâ§?GÑ´Ùh\\\ܸ¸}ÃF[«««›K¥¥/qˆ/ÃK/²^~é…?ùÙ:!ØDá p¦‘ã{ŸÂ³uêÏ¢?ûcµ ét¸„Ò4‹&È‹ÂÆ­·0‘=hý`bEëÖtê: è/¿ ÇþàìÂ:G_]+ßo¤9‘‹Ö[¶Š>ÝvÑËOï|ÚJñ$4 í4¡ë\6-@ßø“Æ4ðíÙ§iˆ©˜‡Åtvê:áë3ïÌó/hé[3ùÙñ;øîZÞhfÐúÖ>ù–<“4ZZlyŸ.ÝúâÓ¥›·nÑdÀÛû\i³7¸ׯl~ø7Wï_i¿öûßÿþ_}üÓëWpõ^Öݺòá•W–¯à/¿ÿÿÿÖ¿½j¿ö~û¿þ'ÿüêÕ×}ûík¿øì~ûÚøíkoýàÓ7>þöÛo?Äÿ¿ýí·ÿþÛ7ÿæ­oÿêê?ø««ù¿üã7~ÿû«ÿ⟼ö?þÓ×þóòÚ·ÿúµô¿¿öüŸ¯ýÿ×kÿÃÿûÚúï^ûoþÁÕÿþ?¸úÿGWÿ«tõßþWÿ꿼úÿòê¿þ¯¯þÕ¿|íÛqõ÷ÿíÕoÿåÕßÿ««W®]!ÿý?é¿ÿîï_¹òW8Qÿ[‹½ÿý?þÏà¿ƾÿ›ÿîJòß¿ÁáþoîoþO›W^?÷û]Ò.n shLolÁ?gäÕËzu­KÜo Û‰šŽ¡À@Ù‘€»–g»(h(†oÂWöû½'èòÔ·›ðóºÜÄmŠ=º¯ ºã){¸¶íf!ù<{ñ’ØÚcÜ7{ûNÃI°é¢ã‡€o:‹_¼ÝÙÛ"~·è˜ êEVµýÉÔøÎ>ýÅ¢£ýa·æþ|ŽÇPo×þž? Ñ«)ý DÅ5óWáž·4ï•D˜ô¬‹WT x–Bm<7ž½Òr=8G{Ὶ“n»ðz Õñ^UöHtiöŸEG¸[üvÑñÙ(cðJJ43Ë|Øö=€ï!oF‚.<×X žõ°8<ˆ^U9“nò|ŒËÞìªÆXöáG"&è¿ Ó÷¶ë_ü¦,2Z˜qÏò°<\ž¯|@2_uc„¢EÒ‡(ú¦Ý|ñ ¹îlòâ4°¼Á…/Η^,ݸùÂFç/0 ^øSäõüY0@/Rúa0X£‘òo!ÒµB¤7¬ðªãEƒúsc†¾;‹¨œ%f-.Ž-φ~] !yq=÷W‹bo¹®½€²ÁÆ™tųˆH` E|$omø¾‹,oýcl…É»ÓúéTsòþ1òý$nÙZ@ÏÁ¥¸ð8Â| (Ð Ž“÷¿\H6È n=ŸÌÙˆŒ+ (› dzý ²þAÅIˆm²íäÖå`x†ÌE‘ÿ°ÈA7¿ÂûÉ+œ¬ŽI?ùf! /H'¾‡E%˜õQ@#]dT‡8¦Q`MÇ‹ D>Ëñâ\½Ù‹¼ò]À´¯1óžo“¶å.¬sÚÒ«‹ ÷}¯þÈf^yÞ^et8w“Ìq±™{…±á¼ÐLÜY8>Dž›þÁ/àc8¬?"ÏœáeÇ Q›øs„šÒÑÞ\gОÞíã¿ìÃó2Î-üw^ª¹0ÍYÊ 5ýQ'?ª÷êŠ NU.)'ZÐ †‹/^jKù ­l`~^kit‘5¤¼×úí¯·è2õ°Ö(0ïõ®ã1ò§õ¦0ÍÎ’×a™Êb«­´d„±v6kæíE—.Ú·&èY½¼ýË)¡ýU]´6OöqD :©—û0@çŽO6¤(ÿ³úÓþÜì_.&Ù@}T/5Œ‡w< g;ÐÊk†oœ~ƒëÚ*×!“F&¦Ú¸'¾M¦%Žû¨ÞtC1×E韣à"phῨuÈÊÉôõ’ç¤ø ˜:û>k~/0»xŒüä˜Ø‹Ú†pê:QÂþ!L;?›²xúµÆÃH¯m:çuÏDab<»†qDGõ²s¿¾!àµÇŽkã…þz³Ó¤øâ?©7…hÞ¦;½~][ö³(!­­±N­ŽA„¶¶Â9E#Ç‹×Q²ùu]üxSdÿqé'+¡÷ &Akœm?áìÖ¹`©,@¶­SÆ1!´tX°ÕÍy„“üU"Žuy<å®–‹!+¶I•§B·ÔM`Gvº’¯Ü‰­) œ‹ÚæÜ)™–ë‚Äø®‹‚ð¦ 9ÿð‡EÀ @¾—ˆ"i oîÏ&§(([_v#¦9oðX‡uñ÷Žg£—tËòµ£n[•Óõ¬¬…QÛwgï#ªF7‡GHDÎkñ=©)ÉÀõÆv°„`]¾·Iÿ¥²|K9ž1œaÙ‰± û-¨<‘>–eŠÜá‰'ٞ劓­(?ÂoÝœú˜2ݾ»'˱* ,KI# ‡MïÀ á‘3Gwd9øÃ?鼿ô¤cãOúÕA8¿+² Ü^½tÖòH·eܹֆ,¦üèhC1ZÁV°)NŦ,EÕv»9 œôH7Íò½qcœŽ=­±)Ì‘¾ l]M¶|‹!„vÀ÷õR×÷8‚XkèÑ1]uÌO âFÙ«ÖiéÌ-ìÈ‘ô#õ!C‰þk{„~Д%(jzÈC úÒƒzA¿gEÉ´vnÉ—,Ó–¹­† sÀ¦jˆÛYkÅw•eØwÙPEYv:´ôÆÖ…›ZçH¤ç–¼âÆ–Ù`BíŽî ².z™þ(‘¼Š·SÕ~ª•ö1§*íxŒJËJII”¸ÕÛR´;–1`ãwõ‡Š¥—×çV+DN/{E ˜( /+ ‰žôŠ,nEiðLµˆ¥G΂þ±ôxÆíµÜV0Y<UmÀ]4ŒZAà_<ÐÃO ú‘š,fò¡ÿ›$ן 'èò¾Or¬™ôCüîxŠñ-}”.Ž—úT›¿:{[=†ÐsUÑähã“ñï¡^ü ^¦ s¢ç]‰àñ(5tp|Îïp›QAÙ~‡%õ-v¯«!ÙÐâý×ÛR-&{0¦Œ Ë÷kE¹ XsV™QKp‚´¢a,~‹L-?w3@‡å{JÙ5ÑÄþ3ɱ]¦sçµ2´pl¬@ G¶K’s·ß¿¥Úum4´fn”gÃŽç{pˆ†×èS"PÊÌ1YȲƒ£}ù¡eS{-Ðd¡o-KµÑ‚§Ì(ÄiÊçô—dÙSEöYHn‘$Ë­VÔ QŸ\Q+‰D3Rf,áG¼ï¦Ë︪e:nVóìsÙLöÛ_¿‡çÉt´þBºïì=<§P™ÊÏéåËC•û[ÒX›^f*Ѱ“‘È„ÊsÔ…ÙŽŠtu ô^Ï™L]DãD‚³Ù!@ýà²+ÃlÓç +DÙ8§±Œm߀a–®k@‡‹5KöñIÌ–OÃÕ5ŽP¸qQÅA6›ˆ®¥ØUƒgN¦3D×;½çÛÌ„É}5ÒðbÈ€<}p(¾·LÔOÚÝ1b*–~”ÇkÔ`‘#®¤ª8œå„jì(VàØœßÁ\êâ)¯}×\ÖG jDX¬ŠœA1=uÐàÔè6ðAQ•’õö6.|²_©MŒ—ŧÖàì¹ãáë3<–=Ñ¥´}²AÏ&Önœèï„\A ô]â1ÒñÈòT7*¶BH{S¬*ò^‡zMf4ºÈâÙL¦¦]ÙÅ¢U ö#Ì;G&ÓnàÃ*uWä(€°í»~vª)!S9êFÉû–:-¸¤M}x2Ì̽ÁSuÊD{$KoÆi1Vv„ꌙz‰âÁ1Ýf±T)ôuöˆ(ë7æ|'׌I`éçóHâek7öV î÷Û1îg¸é,¿ï‘¾Ñ ë²)cmb½ÃÂLŒ³Š­6>ѺPÑó°EÞ¤ ´Ø(­4ò/î©Á‡‰¢dK 8ˆ7ÙRUˇj x%àW5ðèeÿn|1 !¥[ \6rð¯~"{ Cª°}3 Aá©‹,HîÊ  :…¨ªÍŠi!*cp<@O‚mè– ÇÐ Â@Uº%çM’D¡À1,K§)ÙÞxt`¡d Cò2‘i dËŽWýWT¨ýg»_vw«Jw6Û·²»iÒ¸AVסdÙUÄ•)K¨s{€Š1g‹Jª>ø‡UζJ3½Ø¿æ¯ßé!ápéKéϹÊT¬¢rÏ×lg8Dòè®$C…@dÕª^#DµÜ騒ÒçQ.òìøpK6>r•I9•¥œJ‚Úpïìˆ]nPDrùûR‰~;³Üðî ä‚Äó°t§°™*ìy¥ŸÚêø§ /kÒÏÃÚíó°$¬¥qܰ†TRÓŸÛÚYky—GˆõðMø¦[R¶­èu¿X“B±KQô Ya‘ qx¥î…Í–ÆÎÂ’kLl*[á,@];!Ï;—œ(K“ì"P¶-‡DÕàG–»‰¦4æ%)ŒeÛýöa¦­üteùŽdêãUe€ÄKE–qèÛ'Šqaà‡Ò ¢¾Ÿ»%ÅÅY ûЉfò4Ýñ’«ËÝ{V€ã”¯RX%vœ\•Nýi ‘«ÁZš¶;Òi;J·eÇaHGÔñBÇ&çyM(ú¾lŒ"°\ÔŽY2+ŠG2Ö¼¾jû~`«¢¾&¨;Š(2ö¨FEÇšÏåÆŒ6ô>“ ‹Wg¿ ê‰Ïöçõ‰×{îl$=»À0€ë'ÞlB?‰4^à¡k K”Ì)ÛæmÆû½±Â(]Þù÷3yØ–J x,ò'_íu© ÓøµxXÊù Ãwœ @ÿÂã´åázþ4ž0v‘;êÈ—‚rÏ›Pf{~¢wÕIįUµýÈI€ˆIНª04jj¢ä4© _Þ|VÕˆø4R,…b}¬¨Ú]ðqzâ²ôzfËu«CáM˳a 3D×™8dŒ©‹ŠÓ×TÉåÁ£FQ€Fµx˵žQï+«JÁÜV¤ úû¶JÃÊ]“JÓ-º#G3AÁ=š‹†3ßl—ʼQ%(>™à²x÷„;0Z×dcçS&pœ”Ž"ÜÇ t‡X¿àí6ABjbÓU2A'¬dÛþô2 ŸyZVJCYØlî ’  yãV6<·”ÏN°d$Z·‰E—›¯Ë—œN_C*Ñé FâðÓ-9f_Ž€™•m4F®ŠÛOJ[áw¹°sxëîê;d†ß´"ëÝXÖÝä"ɪ¾$T×N† Àâ}](Þ•Ž™>ÌgcOŽO¤ÞDW^;BÇ]w$S—Ù—x$›¥D‰‡”Nº?ÑR%(C¬Ê1„ô–&¯›·£Q~¢£‚-Õ<¥:r«qÛbm«–b3£Ï®?ˆÍöß•c`ïâ&þÎI,Ú=QKeŸcÙõ}öÌZñ(±¥Æ•–HFKø¹~ ç{ð¦ŸÌ&쌢ïOÛª=‘©/Ó¶CÓöD³åB‚ÚÐ p)A·.Õà©ìFôM¬W·£‰ÏðVnÉ x pzå‘[g¸Ö”šQïòP¸®7ÊÄŠ«ªp2V( ýIÏöÌ S­¨¢±Ô®•^Ò>©\PÓRÍÔNwG¤Ý?N°dͶè.5”Ýv DXîÜѤ¡—ßRž'ÚÝ«èÐá¾&ÉÚ†âo¹ƒ™K•›­òRPä˜e‹+Š5¸§“S°žc£kz_ | ¼g‡D^iy6-ÝÁsŸ Êø!=vOo+ÇŸäYp[ƽ Â#yØROŠç„ãøæN”b½Ðû€8,)Ö¶FINr´Æº~„”9l?³Á¦5 #LƒœskõTZ˜”f_LJ²ŽÀlõ#ÝŠeŵÙcæŒ>(×J"ÜA/¡E¢œºTص˜•{_³Û§ù`+í÷±î“Öø®ú #J‚ÇÒ8ò?&¦(¶È6’7¸¤ 6’ ¤ìõ´}ƒ¡îеdÎISØQ®ƒE¹^¬”Þ’#â~ÿYqéÝLV¹äײ X¡Ê…7w°ü@þÅ-Pf³âÝtÕS9èñÁ yüǶ¦àŒ¦–ÇÇ‚ ©%™àòÅÿ†2Caõ¿,I‘[ôn+Ç,\³?R/‚ìÂmS™@0](“TOVê…#œï)Ó°õÏ®n©æ×O³€ýÖ®* 1±²¹Ç«Ð÷`#0¹¢x[’8¬¼çÓ!ׂ¶ÈåŒ ¾˜(ÒF8\Lùöú*¢ÁUùÛÅDSÑ_qŒ8ïw2K£Ñb0È,¿pF_I28˜OïÌó/â=ë~”É0b8À¥®p¾¸mF¶ƒ"r6ø™óž›K|ƒIj¼cÌkÙ6iÈO™ˆN2—ÀC³ô½£án%¡€Œh祧‡ªD8k‘ fA>\UÅÓÕÌáÎÖ=-d¿ýµ^”à½aK¹k—®@ôYˆ¯JÄl’j³ì‚w³¤„`Ïç,fy¨Å²éœ³!bC ŸÑ/W¦(¾ÚW¥¨Þ0ª“.œ·.-ò^Ût¥\þR‘.hŒð´†xÓ®TUnVBñó‘ nWŒàdçc[*/ÅþÁÜ(xß×£/¸¶ŠÓ¨iäb¹{ÚÒ£€‚qüµyœ³$Š[V\ïš¹O¥ú·¶ þX*30ÎOÀÊdl¹YìèQ® KŸ“åßËl9>UådOO*"¿uzP™EŽîèv¡x`iþþ 5”ÝB{®_üôQˆm·ò´·Çy¾KÏz…o75ˆ êæ$sõ(Ä$ºà’±®ÁÀ ¯hÀáü\7ë»óqÉ€’«Åâû-²¢Q GØ`©‰ãf§‡g´Sÿeo6…æÚPK=9íwÞ¶5f-*&bÿ6g¼¨xˆ«áãiÏŸ ‹1 Ð7 h‹¤ITk*Qåžÿ¼\݃;šb†‚–ÃX‹Š``>[T §Y÷)%¿õÄó1ì$ÏFÄ6-ZT<¹}ÇŒP¿‚’Kâ²×7õžó;bìÅY\†x;Z8¦ñÂ* +gŽ7‚ ¬ ÍRÑQ¬²:\dÛNM5» «#Ø¢> £Ú /3.ÚlgäDmæ´n¸ÐXSÙ +9ÛŸ8žåE±}8ˆl°¨È° –,Ú¶]gdÁlßEçÔþídQ1Yñu&¾ìN–/`¹h¡Cwt9õGta¸ðæ C÷¶5q\ÒW¿Y䜷‰~º »Ð=O†:´Ð9¤+ˆÅ[T, DÔƒW,ÿ¸Ö4\ì`Qœ³ù…ÕÒ`8ÜÅ 6 -´1tÉ]­ÅJ øÅÛZh~ 5½ÑLMâ7ˆ\ªH#ôá–g¿ÒüA×Ú@8$*¹¶ˆ[È$[ðŒÙ.T~cƒ ]›A z!ër¡²Ä7ü¥¯£Ù‚G÷LlÉd²@9¾<²ÈªºðÐh°¡}a‹ÎÈ:íEþ4\èÀîRc0º ­›¹ˆ¿cMZ7S˶¹…ípÁñôýÅN»,šdùì,8¢ ?ŠüÉBkˆ¶â;àÄ“¬k6ñ÷ñÂì`8 Ñbkêðò èÞìáâ/1WÅ*x·¡[ñ©-_e ‡ˆŒ¹yfψzDmh“0G¾¯>ðö³Ì«1[Sv¼s\jvÝt¸é^§ÆÔˆå®‡ê}#Á–Ì’}«Ô+l5 ™bÕ^a%IÒ£F³Ä|Í&iÚ¯ƒ-Mœrç c Ž$—pä}_9Eœ;¦朕§ú‰Êí'Àý‹Ó¼zbÖ´Qt”òm«r‹ì4Å~¸F¦#ûÌc¶›l" !oD[ÄS#VÎŒab‚¨fF±"]5cÁ¯ÐºN+K iß´5¤e~๗ë£ë˜5Š©MŒjÓªr+ 7-P_·Í²C…vfðجí%uzäŒÑ¬€&°oɘëJ#+'–˜‰{†}Ã.âº=˜<ãtÊ)ûó;xïR¹ìÐwÁ%ïÒÒ”*4í4ä¶,¥¬0ã_Eïdå³XQXvX©¬Ò½›úÈpÊžk¯†¨+˜ÝîǦE—æ·.*%O.·Ï„ÌÊÂ6“ÖW<]³öO©â“†'u±ã„¯ ¹H¡õ@‹ÇfÞ£‚á~‰¬Kôet‰è»g:éf*wG·ÍÑ)‹«´µõôÛ.û–®¬ã¶Ò¯‘39:ª‘”µÃã)Ó“%å•_HHú>ñÞ¾«›¦Ð˜§ÿr‘v±p>8³fËüp%Kã õ¥Yž³-2ÜüÃߘm0‘M¥>.­pjDç0V³Æ}b׉žÑWNLxëÖê$سÈ:iJ™A—ð™aUOüs$ Õn‰6Êäú±~‹ž·µxdV€6½ó|ŒPÂy\CáY÷kj6l—z¿†DrtOÔk$kiŸã:0›éêLPlžHy÷ËšE>Ï;Ã}NɬàòCÇ¡=Q9cOWñÈvhº?K|ùqK»SBÐãøÖ5¤PšãMäF–²Knfœ'ÕhÚ­~;sD»+ÇúP/Y³ˆá[ZxÒ³ƒ^Álú^ýñ®k%ëxÊàf­¶@÷2|O´%48ħ;1ñ4¤\g…û•Ê­&woò‘fá&—7´2÷Ÿé–èØ‰¼½KbzáåMÉ@‘i§ŒUÏÓzZǸ£ÙÃfxäk»ÎàLw"ɯ۶ýÁ,ìÕv—†y­¿¡Ü"†*“êvyBщGŒ^-ãÐv†ó¡V’Òá¹__šRRåD ]GwΰQŽA¹¦ÎÐ%7¶ß×€'#ñ–x»ÐÖéƒt¼iR Ê«ÑÐFOÐ%µ{M‹ÓñFŒMyEåËõJžž”êJXæÍLPkʳ‹íhcC3ÙqОc‰Ïå PÃÂ%Úž¡tõaäO³d׈8OÔ:ºi<F~YðØ …ˆæ–ÈïXv7vìÀº ‹ ÚpK:0]”&Läp&4›R9 *aܯ-…ää¨g¼¿Š„YÎ7HJWAé®áë›òmÅJ:‡©ÿqݤÔÛsݬ}ú¬nNº[j¼øíûœÕ'%ú´NBRšu2â’<ª“–â'›N8u­Kjê3á0NyÚ÷‰®Ü×úgÅž«ÖqÀ‡L:¡L<ökÐKà5…Èø÷¤Rf0,ü˜¨˜sQ€ÝmÝyndmܼúDP{rgn[‰¶@Ç#\Oõ¹`ß°åÙGhp‰ë+ö¯öõÛT¼õs‘Á.ž¾Ü2h¨¶óíê³ÐìÆD]£ääæ¡ÓTÕÇ—™Í%QÓô)Ÿ%1c¤¯Òt±B"E¤f:HQÜ#`<<ÔObØ(á­jè²RSMšH±/Á9»mECQÆ!R×ÃÌ‘2‡§ÁãRh³:HR`ÌÓq_};'5G¥ÖQÜ,ب2d5îÍä­W™è”BÁ¬•!C¨¡›5xe5ôéEv°ÌItƃŒ‘,´NdMg™Àuê@dQËœ$,óuY¹—™˜ÛÒÆêô .C†PãRˆÐ8W ,8-MåÜ$¦»t¡:³¢Àš—1‡NoÌZú2‡7gŠÀL)tËà¹þ¬ÀÁuÆâŒÉ0t©iý ´ØX4:#SÁΘ!ƒN[ÈZ 3ë¶ÄÔ0™ \KFÌÙ+3#5/(¥†¾Là¡Æ•ˆ2ûfõéôO±´:hÌÊ'k­"œ¢3¢Ä€Z-<úëlfcÆ­µ¾Ê›]3dÐÙçÈd3ÂëÈ•BCm5°èô]±·:hôV|œ•7´N«ÈÙ~3Âëìüð6áôÁ:3jÞPœA¨e€³ g€Ö©÷œ]9#¼Ž4‘µ7gשû¼:3¡`ŸÎA§ ä,×áõãO¶›Œð:J‰¥»ZxtÚDÁž!ƒÖ>¨À¦Œ9‰Îè˜1 g€Öۇ˙Õ3dБ—„÷j`ÑÙ˜ã3æÐ1²¦úŒð:m2cÂÏ­Ó3E†ýÌItS’·úgN¢×. &9ôJ¤h.МDG®š…( ý=Ô’«8¸Ö 4ö¦Vу“r×…âü~—]ˆéÂ]ßµQp¨«u8xm⢼È{:—ë PŒ•ûŽãŠ}îC »§aG‹À›ZC.nè˜'›Ep/#®Û§5þÁlm+XtÛLÇ A‰‡©ß˜Z*jëá¹cµAcMäC× DÍ­K!àœ™öÊ}cë1éúui‡2N³öf“TÞØ1¾¼ T­èˆ­£¼Ñ›ƒšècQïÍ=+ œ—;¦•Íh›W -ÊVthj±¦‰¨’á~„ÑA@HÐáŒk)ìN‰±RwÑh‰ˆ’´âfg›7ª)®™3/ø›ºù³˜ú%­eb½a…£º3b›r­¼?»îx¨ªfËuÓvž.&’¾ŸÆñÕ*žÜó{^71{k-ˆ·ïÇãâ`a1¤Å^{Í≈k8ÐB]wd^£8Y({KäC×pÀKŒ•,¨ò´ê#ØÅ‰ÌQ{E°»åq&NÊOfÔIÝQÀ„‹#{F‹ˆ DÉ\<§‹Š'â}]p³ì× ¨*á‹ W‰D_{²C°¿^ÌHζ8ë—™.†ÌÒ¢éC¡ÏÃR/3uöëÅH1ÔJ°ØH™¹ÀwW–6ó´WŽâƒÁaЈ%|è=ßfÕôÖ€þ»¦ÀšqGëÆ=R”Œ<Ž¢i³Ñ°lÿAøF«w»±tóærãt渑ã­(Ðò„ Ž·Æ¾¡€+ó7(ÒkW©+‡rëÊsIˆáñ˜‚,8YÀ{ t™®rK¹øQj0ƒõ ³ñ†X=.p FdDeƒ°YÜ(¼¹£Çó#X†x3€›xvS»?›œ¢ DF®€òË› %dÁ˜®œKµÈÁØZ‹ê)!é ‰ÞüI>P"ð½ãd8tQ$²Ë?´À_Ðes›þËì9%-HüzO™§jØø‚-æ½ðFºžO©1Ö÷÷¶”£Èdžw¥¶ ËÈ¥›wbæêæùA®p49Ë>| Ú‰|Í^îˆ^’(–Všý=Ñ1²ðícužH€ KÔ©* ¼ÿÊ„mŽ ±ç™Î¬¢üc¡åœ#“4‹ñô “*T84$-8 0%,¸ xfR’対vŒUjîë± OÖà×¾a’r&ºžš§¬NF¡Ù¯¾y‹¤=ÃdЬt=3O¨ˆ¶UE{„&ÖtÊLíS§ÚÅW«Š œ[nEdÁøEÇì,`_í„GÈÅâMÍUv<‹íWÒ;—ªåF8ÀWÚȯÉé‡j º¾‡*‚Ølë“-årc>ÇRÈV­·)2šåâò§ÉÙÎÆaàO­ÙS^×àáàÕcQ›H °œŠW&R5Ê?=Ód—ü:n]—v@®ó™ÀCÌ—Ì¥_ŽôøªV×¹Ù´Ò\·(ê†M[%~?tF³ÔÆL_™)›Æno,Ögˆ¿[l—XQ ?*¯õä¥û-ÓYÄ^ÆäŒôû½ì¢ä¢:ª%*JÍ(PÖ©ÌJmq¡!ÂS Þ÷ÌøB¢#š¸Vß7lÜÎÛ\óùtcæ^&áÛRæ½\WfÉ8o*ÓÝÖGÊPpDÀ™2#À£Ý=e‚uI}õ¯¿ýgoéY‚yµ~¨ ûa”^I1‡:­gî³'w§k`™gGcKj»±šyËÊzDv6ié4¬ŒÛÕûºMÆ÷ûºÀO4V™“íÚ¸púÔçú2¿Ø51…s\íJæ/½d]#[¨Söå>¬kã u®¬§¿ó#ˆú –q„«žž¬Ž^k¸!nCx}>9ËÔÁÕçpâmdÆma‘®|bÙóe-¹£A€²Q¨ÉÄ/·ª^Ól«%xõù)uJ|ìÙ>{ûÄ€&Ùý¢‚@xl ìǜ±þS Öìv~’NàÝÎÝØCטž#û1!»A¶,Â&Y£ÁjÔŠc|_¸U·­]h•¦Nǧ ‡”¡¼Ú«áBä›A4³Ü}Æyh¸N*\Ý×.à©?¹‰N£ûʘ.u)’!¾§)p"õ•K¬êÂ^¿0+rvþyœ%%§x!­¿Ù`Ù‰ï;vs5ñ„Ý5ntÜ!ÏsƒYè©•$rÏ$ç±°¦²@¨>ÏÛl(#ÙüX$Æöké¼¹ôX_,ð=Heß3ÿ+ÓM˜Ø8ˆ·Ÿi'Å~Æ6v«Ö{gYêšPŸjl…´šá@Ø,UYªPg½˜ôt§½X¦ξÁ„>bʈÈÎÉ6Çf¤p`œc}fÆzì …‰í˜Ò&Ò¡¹pij÷µvØdüØ ÁY7²tð‰ÙmtÑ‘¬úª!ïIVC\/uþª.Uº¥UÏ\Þ9¼&ç=û¡CRÏ»ºyÈ»ß~fzÁ9º?8OüÀj–ÇðH“a¦ß³ž·ë)™œ›ëGz©2!ȹ¹ÞÐ8=ÌQ´õ2‘bÔ“Qp鼡×Džre\™+VrÒr6ôö\Hj[Sp(óHgÓ…'hé0=‚.Æ(@mýA.áøÊxùS¢˜Ö1#æÓ»¦-€WN;4NVN™¬WGêê媨=«#EÚc㤊ôɾª#±"bÚñ ï ,Î49Q¦Es:‹Ù}o”~ Ô¶é¦e³ÓÍ›¬T‹—„3ÈÀbv—ÝGÔñ°\ßàtÙ)ñ˜ÁÎ!¦Áⲕı°:²èµô$¢ÓEEΆCçeÉÝÚò( ovÊÑycœù{µá p¦ñIÛS]4™F—… ˜qIÑ ·~;³Üw+Ö÷ÀLµ*ù¹n^ÈñÒžo;CÙû¾çxx uð •Úx}s÷ëÃÝ­ý–=wĽ~sã ß?Ø[S Ê¿PIDÞJ+ÍMK·”b­ú ±qUÑ=T9†ÔÊj¸ªR{½*ȬỠÈÔÈï¶iym\‚5í-ªO@ Ñåm•,0´ &n% ¥ê™^ÞR ï ¬è¾2¢Cûõç^ÞT[Ó©{©Òh¨œ²áŽ7RG¶€‘w”rÈœK«ƒÄ°KA‡Ö&p±¿ÌRxε.T¬WÞ-yçÕz@íRNâ5‡BëC¥pÞQµNì#©"¹9÷Ôú`±Üò Ê9¥ÖÆ*æ¸àŠZªMiYÔšH±bUy ÜNáûoÆÙ´P±”³.¦5‘Š¥,r,m„Çñ/+à9wÒ:0ÅTp"­ûÖ*D®£ÍB5á2u­Rœ‰n¢MàŠý(ëZV.·…“vÖ%´Z#¿ÏµFç¬è{ª³vìR(ö>U ;}6dP? ®žõÁŠuœuð¬‰ÔhW©[gM¤ªl•sæ¬UÌkÖ…³&Rì§©|Å]â¸Ù˜C±g‰Ý52h—EÖI³1‡X}]’#qÍlJ¡µvd®õ€ªk‹¼f}°âê<ç|Yª( ].›(ö:±£eCå5ç^Y¨XÛ9§ÊºPŽ Þ•²NqË;PÖÆ*ÖgÆm²P±>sÎ’u¡Š³uÖE²&R±N󎑵±Š#sÁ²>X±nsNu¡Z±&Û ºPÅy¿Äá±)…b]ÜëƒUwÛJâFxÅ‘+ãÒX¨¼”sd¬V”=„î‹Í÷gN‹Màª=<ëªXªØÂ2Šõ€Š}Jä–Ø¯Þ±^¹•\›À•s_t%9 Ÿb1ÎÑð)¤5|J±†È`8µ @o+2ûñþŒè¥@â‚‘œì#…ÍC+ŒÐAüÜÈ>®¨@m?ùýX—ÜX†2>L¶SQ§áÏ`;Q³“·ÈpS%ΙgûJ€Ùþª áÚ°Êö,d¸}U‰lA‘1 wX›€ÜšU~Ý1 ŽØ›Wàê<8£oÇÛ„\|h@­£b"{^‰ÎòeæBDšMmä¦~œÔ¢a‰Ã9EÜjÞ“óì¶>×E¼õdÌåiœ雓ˆ­éÉ’øDDK¬é©²˜¥…ëÐëú,П…ÞƒÁì_5;ìÖûÈJ\h–¦·ì…òÏܲË:uEâ[ýßWŠ)÷\Ý‚;^0ð·´†ïÚÊ$©%¨Ø)åª2G…3C¤Ø,à¤À=J"Ï$öTkbš;.‰˜c LhñÛ)æ$â3SÉZµýM’»Ž60}Çc›>mƒ´tØ®Æ}õ:J‡´»Ê`ÉÔQ ¼ªg6³y3AÁ½IïW¬Ó˜MØõhp¿*G“žîA"î¾e2°”z KIFë 4‹wt)r#mÕî8Ì?ܨpÄÔu¼3Úñ“_Öæ¶Ø¹ß‚N6eûÍc'Ý d×êÔÜøW{]jf;~-Þï¯dŠü„¥¥õ/¼4îö Î6ï*–*¹çÏ Èf6ðÛ… ôšA+„Ž÷‹ê ÜÅ)/>nÛì¸~|x¸utÒíìuúwe8˜]B  µñ!˜åña•ÆŒ¨/ËÐ죋 ßÇ Ë‹_]›M§àFmâDw%h*.¨ Q|e®Jb¶¼Ù$Û=I$ž€«F ÉÌ"e‹…:¤‹ßl*¡‚C„×Pù¨×õHâOkŠp>êIlŸi鍯ɔ‰HËß?”3w\¤ŠÏoò)å9õ1°¢]äâ·wpaËu)jI…à¾u‘Š1¯ãµñˆ1Â#Ã;ût¤é5dðáØr‰Ã‘©\pá;Þ¶ãFBÓ¥•¸}?Š¡d ©5À xa£~»¾?mH—)ÅHhäÓÒ²þõþŽëŸb ¶'ú@~§Î†ÀÆàa<|!ƒŽHöØ^à…fIeD±4Y%îqS*û¬-–X(8ôJ¶T½Z¶Í¦×ðƒ¼(!ƒ÷Î,ü—R ±þ/5æ<(ö¦<–䛸BxNÌ“êóë%ë IÑÃ9^wS§°^&€u¹"žLñ²€Z.ŽßŠþ´j­Ü].ݾ}÷öòÍ•ÕáàÎ{Ëö²5X]²nÞ¼k-ß¾mÝ]¾»bß=½wÛ²W†Ö`iéÎòÒê½Ó[«·èn׉MÝô¦Ðy‹¡-(µd°Þô'Ø £ Üï5™ð™­ t{õu £ÏeÆô÷3O|ª\Dpv¬ŸÎ,;°¼¨jÁÙ +1aÒÈ<­HÃ&¤®XCtCǬ…]òXÂUiмT´$L„‚GÒÉà®"EÝ‘Fq2‚<ˆ)Tm<çPœà¾œ¼ÇÖŽ¥&Žºü"3¿È‰|#•3å_ÜU'•½¢‚âÊðꋟ¾¨>Û‘dë¥Ô”M}¾ r؈"’ùp1DãÀ¿8ðȆ׫Š׿o Xu)µ²ìyìš,)¿Wc©W;qŒ™§^%._p*1ƒÈÚ>nþ±Höþ ²Ò'bø–N”´åƒ1¦Ròæá¯úd½©åÁÇëÔuÝŒî±YÖv6e)ùa¢¦EG@<õ±/=ýHJ9 ò 5½aïDhb«Ä`i>WÉŠ]GhÕ¨øuS?5('³î—u0qÝð—f|!ëƒG/„÷k*¡?7£#xEv\¿®£J{ÒnìÐ)ºuAïª%Ï¥ýì¡AߣÖëHÝüý•U%f‡ý±©h–Lz¦¹™½¢±VÉY> €7Ýk§–CÉ<ØÔ£ãëU=è¦s®iïpgK3Ò~ûë UdñÕ3U ¹ñª§O[:V}¥Ê)¸cD;,Ѹ¶÷+#bZôà£æîžèDa~9Ðçö·j +ªþ”ÕѼ{¨LB6@÷@Á§ä<Kû×ÒÇŽ2•ž*œ4“øÊÏ<&Y…-x¾Â–5_aK„**l}×)¸Â¼F–žDü~ùÝ\Z±Sªk^xsSLÕ—L™©äf×\®æë'(Éç]м)¹ó4%¶kQžÜ$…%§2ÈP8¶'Ú`Üh%~Š ôxI’“û- I÷íw“á$Áéj†Dí ¬®Dè¹Æºç¡ByTÖ¤ø-ITj|K§Vê±~ê²$ Ù›=N2º£9§æ€[™dÛ§šñNzÖ/ ¶šò†dxæ˜þ;×>âÞ’‹Ø7e‹+œºNÔŠb‹ ZÅuêx6XÝç’U Ø ü|2côýÃ;þ,ì qîBïê/ìæ) ÑÑ! p¼zÉ2Év'Ø«§E»§Ù ñ·ëZÄÿ"˜Þ{Z+ÁÈ+ä;òFôÒRK3ý„e]©$3É.qâ©PºûZ)ÙòˆNPW'P€Þ…‘P/¬±×XM²CzHD†À¶nÁp_ÊΨ¤Bãxn˦»ë©Œ 5‡4vÚçâÞÖáq&xœNv‚ê¢ …*A%Bs€ ›ØÎt¡bó BhÎÉ‚,ê –Žy‰“uVi&ñéBúïLA#>`+IbΉ‚PlŽQ\ 9ç Z8…œ&èÄü¬³ ”؈¸N´± ý/ãA¤PšY§(…Ò9CÐÆ†HzýË9AP…(ô„‚ó= xÇL:=Їò‹æÔÙ"Baf89Ð…*ô‡¬s TÉ–TÙ„™uj ‰TÌßsåÑ3ëÈàŽÊŒ[^V‰]DAbçh…~_pZ TÙèÊ8+Ð@)¶—ÔIJEvÉ9'ÐÂ)ä-ë”@%6ßV¶†:#0Â+ô±´V޳Όðbc™øÄé€ \y-Å «ƒTdñ¼“= Âª4ç\@¦ ï èƒzØ™€Zi-À9P)ÔfÎy€LeŸ‹s ŒQ˜Uòδp õ•q R¨¯œs˜Âl™u  R¨³¼3-œÂÈYp T¨»œñ˜rlÉ2_¦0ß–û7+ÔeÁÈ¿Pe—H`Ü_«0ÒdŒú«ƒ”ö6rÆüõ€ s½Ðˆ¿>XaßA`¼_ªÒC³Fûu` -'c¬_¤Ð7DFúµ±Šñæókc•ZOÁ(¿.T)·EcüÚX…}Àa›""Ô<@¾œT/òjTZÇò4-TÍËÖÒ¹ ]‚ª<ú M ÎKÛ ÝGZ•ž¥‰];­z-Õ ÛoS¢|ÙjéEY±6¦F'­[+¨mkª$*UÏ}hÓ²ÑÆz\·T^‚x¤¥ú« V2GZå;"/> í¯MäZ—È>žÚV„ö4)ÝKFÃP¶'šU±5"2Œ¦+ŽnM\DÄ\^ìÕDEW·A¡ù=Ñ®³¢-ìùÎÖ: ±”Q uyû™Q(ZRÓ„W·å!É%«e% qã« 0¦’×sNñ¬<º+Ü[òuO…G‚ Un¼¯lã±$ë7£í™G¶Œú~<¬|ØaŽ Â)øU@Á†n/š=‡˜GÔ¡[!È8¢¦´35$0#cÙ ¹ZÒÅS¾P{äñ.®(oªoà9šúZp!ÑŸƒÞ¤U7¯ßÑrÙסøíÌœµáÂA^pèê3¨3ÏB˜ÌA(ññœ>¯ÄÁžL‰:+àÎÁÎP¼§ðnŸ;0zh’tcaBX†ŒŽøngsë`ç¨u¸ÛiŸ´·öû[G×·qÅí!,! Â=Ý¡÷÷zÔû†ÿ’FÖT`Ë=wµ³.P<ÞÓ¯-òñ–[ÜÝÉÆJŒ‰×8áûYÒƒ‚ßàÈ· x¸áL»øEcã3]²j±2Ó”7úýƒ½Û*11‹I»&%Æw°§ºD¥Šá׉5ŒÒˆrìdDì$—npZ{p{aYI𪩋Ex}_ š•B´ÛuvNi)¦!YÌ&#d·Î1ùYqa½oÒrã•B7QE¼Ö%ZQÇ‘ãîÔ4 tëHá6Su}b@7˜7@97<ð Ç?*—´£¡²Bgo«eûQf w͸R¢wOP:ž>ј€ò„¬865¸ðÚ2µu~„+I»!âö6˜¹ä¾CàœÅºá‡ÆtǠ˔شEµ‰ ×$»ÕTª#ã̦Y Ñ˨ڊÑn¯+éy…ÚtÀXB84:¢¢a¼ðþê#ť嶛/ž!×M^œ–‡WZá‹ó¥K7n¾°Ñù ̌ǡ>žš)Å‹4Êa0`;½üÛ4!k™„ܰÂÉbr87Á9ƒìKn<…±… ^¾º¼ñ±Í7ꕉ-óTíYˆ[ˆu¼¡ßÈ=7•À`…øM(9ï•ÆÇR+Jð©„T­kU ‡bKùKivÉ&³Ø÷_ñsÇ„:sZWnPoc»&|ºH hÖCª88q¶#™ð€ ùöЋËUÜŠŸ»&Ô8èàšD}d¸ôßå_ì˜0kU…€§Ä¢Ç ÞübŽY}×\6øA“RW*Mj›H¢˜ƒ9Xá‹äH9"Ï÷§C&}|D†]¶ÅF†ß–*í _X[ª ·ºÙK­]¬«R€=§t±g‹Às25"Wâ"SCìy«š#bG3i2L)ÄÒË|ŠM# `‰cõꆜhþu Ûs<±aŽrF²§óý`æQâ}#¦ˆò ;6`~d8"¥ ëx6h9ûÁž.%œ &tñNÔÃvnuxD|Â…·âCD`s"K7Wš‰ª¶…×Qìã—ˆS4êØÄ„›BhÜÞÆ XÄ‘qy-— ™d!ÏVÈ ÊÀ¡§³pœ¼";á˨0ƒ „ŸKÀHÕ¯ŠR=ðÄ7²‹P|õ´)ì ÉžFÇ ¥¡‰"욣PQ Š„rØIN LJ§4½‚ÏŒ-M9,©Ù<Á–˜s`¹.$ì‰$cîcjÇ”àð!çS0\‘£*¼9,ßãË<=¤|q#ØÔ!¤sQJö=An´RÊT8àC?½mÛ e†–„Ù 3éø°¿ùNr¥£•m¼¬ˆ¼:®¾ß&zì-Ådánp üŠ’Åi¸¡“ð9•VÀ‘fa§ ÝüèphLIºdˆ{bLØK$áž1W¢ö³7 ­ž§¸ä’ Œ›š Ë<ÑLIš»t¸1/õ”ëõ¡ã¢Û’„üú٨µ¬ÞŶ]k¤ QØuÎáñ#„É)\ÿyÉ>…‚>ñÑLz¥ÒJ‹E†NJ°¥Cå“¡ÕÂ!ð.W,Z$é9!ÉÖË()­‰`l…;tjâU5™Òž¦Ý`¼Â´^'•ø6Ÿ˜*©gHÀ’¨—jËæó²ö’Ö¸lD—¥¦ÓçEt©Q™'s‰1ÿ«¯[žM‹\vd£)q‘­ØA¢XXr¨Râ­¥™ÇT«ñ–$Ã8iƒ²:P–ó"l”@dK1{sñŽìü‹*%Wâüð ØÚ£e˜ÓäV*­[JEZ·”mpaÖÄ]XbÁa·Ž9»>¢j½©™»Är¡6f‰FIS]êÂ2“c;B×îBè9 _b¶Cˆ™yÌðÝjLò·a& ÔA!¶Ø+!¤ ³ Ù²»™ÕȆÓv`ȶ‡%òÉl’Œ(µò…šÃDbpL{ IĦ;$V*ᦚ8öC­]ر¢M¼M -½„ûg1ýFV!µ†šlª’µ"9Zš’pʰª2ÏFªØÚ«¤)Bgñ¾Ó’ü8C6Ôš14>ÆÑš”=z¨¿—×´¦·ÃЯ öSeÆ íÝu©a•®EaËq¬IÖîõh[~Ù(g°l»ï³`-㈶ëÎ!uˆ1ØÙ)™`wíýì9Éõ†zjfš-,¾_~x’;«éê4±¢iBV¦þª²9LûçšµpäO,/ᢋ1¼*{[þ°Ab™hlaO¬3”= ïiP便Ž7Ø/![ÌlÏ›©ÇhɶcðzM““—>Ñ¡_¤üz$Êø9¦x¾¯·pa4Ï×%ã{ˆŸ©0?P¬Áôâ‡ÛŠh‹4¾­äöͶl`™{Uy¸hEþZc´C|b–hÞÅ+ÞE)?¶ì£‹­`D˜&µŸŒÇ‰XË'â†>2Mó›.YÉÞWáÉ¿¸£ŽÝ©ÜV1Ñä­QMl¹Œ«ŽýrO›JdC©'/'.ñ )ƒ?å` ã)°7›ð¯*VÁ’í³edk®)ƒòB箊Ñ; o p[ÂãȾ %¬Ôƒ|9ztS”dzížb‘nƒ1ˆ}Eæ/÷@¹ù‹s‡Úå^r ÿZºI÷D›;@ÿñWõ¹/IJϵ«Í…W“<Ñ»|Hý‘(s'¹’€úý/h7…Çx!¨ßc–wpáq7”Fª€ºG+¥ngdYÔŠVÔÒ Ž W5q­H©ë3adôXÓÊ:+¯ÙìÕWàhÖå¹ aŽî*‘©Ôµ5ïBî|q^iüXÔÛ×Jwé—*i·ÔÛuƒ× /Ùl•`)ɺæ|Ó 6£qhN&o2¤œ°ôËgñʄ覭6wý0cLƒ³8'K‚oÐßÍyîz☓¸9šñEEÁÄ\‰êͦLàâ°G4Ýf p7dH¸NûD&|nÞgÎmÏõöœ,kp :B:u*•Pí(S±MÅ\î¶ur·S ÚÖÉY‘æ® MáVNSUô^lc4æGPuøäuNáÈøºÍñ©–Ü,ÒÉXåƒ3H­¸ËR²J2Ͼ{l޽~N#ÚZp^ï2Ëéa…~]œíƽ½‘yÚEq×±ÈÆž-ȅѯ­NÁL¦oŸœC®uí¨“åKtH[‘åaoã¢ý8U®MÜpUç—%ÊöŸñ¾& þjd× z÷¯V-—J6«êdxò¶;²Èˆ ïË‚À° 9¢Þµ<›i(냫µËË[£ii4núfŸiñ¬KVf–º°¦¤5; »0œ‰ý†¥Óo°„f¹´ ¦Z­ ³þÜò.Ða1ϲ–OâOo­Þk>{Ì6Sâ?©FtÕç† ç†¹”à!ºÿ?¯“ª¦ÿ¢: §‘>‡2Õ94·º§Õ`Ñœ3`@žß@ôúl.,ùõåÜ |¯ÿ³ùécÍù¤yËœ®åxðùD ê„ ²Q‚dA˜Œ¼ªÍ_qa'Ù3ÝgÜ*`ýWðã[©×û'qm?P¡-¼ùQ'÷Š^±fR mõv³ST}Š» *‚ˆKÄúýß}±1} =ÇÆ“Aú5|q“Mß¾—©Üßý-¤ ïН²àiU§_ÿÞ+Œ›ùŽL?¿º2/DýD=jõDqcDƒûý¥Lø¤[ÞV }0„cEÃ)QÅ&Ö•paŠ[“Á•t}l¾õJ•M®Ó550¬£ÞWHj¡ÅÉÇ[€–6°£n å~)>i2k2¡U+O€•®<+[y˜y•'Hª|åâ-@&0ªDW÷ÍÞl8t^6è?’CºñåRÑKŠ.^à´E—MæëµëLœè½Œ×dßžjRpöýÉW{]j9Š[:nh2F~ÂÖѤð/¼4-í1œé2%zî@BLüð$ä·‚Àº<„3ò@dFQ*<À²þ\"ñ’­Ú-ü‹ªÂ0ùø´~­ÅZnù_ÌMÐ7~"¯>70 аó‰É&}¢Ã1'0ÛÓg{móBý³@Ϻ¾G0>ld­ÌÅeZÃ~¼‰|k~µYç¨= bA|6‘üú9_?½µ|§ “1Kuƒû}§p3Ée¼ðæg 0ð).@¶K"í&xó}ºn. b >â•a{g+ÆáêõXûÐ Îî©‚ãϤ%ïW¤ À`+õ8Eì½Iã ØåCCáÿi!4 •+‚‡sB±&¡^Cf÷Á’Æ/¥b‰Óy6Àû> òY5’ø“ê P6s‚@ü´ä1®r)ýB&Pœ[Õã»B±†$îð?¯Dp¿ÿ¸2 ä¸:d¸X­dÈÍåèŽDЛŸI€ÄÃE1¤÷óB¸½tÏ%xY&lñÕÏe`f©€è…€G™é'—îû’Á…o?—CdÃB– a‰Ó-Ø‘Œƒå_|Zœ³f‘ã†Íþ…3 ±ÔöAÿyç°wr¸utrØùj«û§Õrl×÷ÿ¤:Ô0ð's‚ ãþd‹ëûÁO$Ò3' ùûËrA¿Ó·N{‘?eG¿²›±WÕßÔO=å ÔOŸ1pV?¿Î$³/{F¯­HÇ•}Ü,Çea9í¦p8Ó¸ ßÏr>ÑâD“it™ýŽ©²\N¸õÛ™å~]ly`ýLñÒbU–…©m¥ñß”EÆmVûð}÷„+Í;²h¾«ƒÄ¦·Ä L“Ö@‰-p”Ió6dPÉoæé YÜb»!lF¯ªïxc8Ñç^~)] °5³,š.÷@é ÷E˜ãØ Bé#§ÒŲ́‰üù¢ãXP&˜sOúv´Ð8À¤4ýr¶˜xÀ>û¿àQ6åš qåž‹=¼™êi=£þp Oì=ìß]º½ôéÏWî®Þ¼³ú‹;2t6xŽÃØik†E¿Îæ]Páè¨ûœd™^Î'º• î÷gRr½]銤 ªc´S$¢—Ôið»a:µ™„»ùó&j`ÑKË {H3-y±‚öܱeµíÇËðê$œ»›eu4¬™4`°,Ûžï\'½|¤N£Ò¢çÌmEBå-Å¢—å-Å2·E‹s¤Ø¢…$Ò-Zˆžß¢…0hÑK¯ø ˜çÌ>ViNƒÑ¤x»Ÿû½+ ™ëñZ6nîÞIˆøÍŽNÊ—h²<Ì]ŒRx\)ŸœDÖé!\Yû®v–uC’†i—¯HÏ[ÑÂ…Õž~KKwl…É.vÇg8Œ':t%·Àe[3¥·!ÝÒè°ÁAãñcK+¶ ’–…Vw£Ë¡,ѲlwË^íßЉ?{ãyO‡b‚‚êû±U•Î'ˆèm?®dÃKo ®Ð@ŸGA:| ß­A%—ÈjÁ„9fâ\ö_ÝW¥àUM×UÁéWS8 >«„Cõs‰;Hò°¦ ææç;ªX˜f•A0¥¯¨‚–wŒ#SnCŦ¹[¡þpˆШÎk>ˆ_¿ƒ§`¢(®«Sâ(ñyª·^&ð–:œ(tý °üÚ!š ÇÓ)cØTg(*¿<(Ø2ºÈG35 on”(+pçð î÷M‰à0ð%æeøáF*{¾v’ ïU6Ú#ÄõÀFæI˜|(±/Ä£Ô;ÉÓ­ŠmFÐ]§ze î÷¯+Ú19€&ì&*T™s†—D(Mt¹øýªvªÛÆÑ†K‹"¾ý›…–GøD™¾\î¾zRSí·¶2¸Øõ›Ê‰6Ú¶2TøöfÕ¥Hë4uÒŸ÷åâe×¶xÞª«*ïxºDx<"6hÔÞù4ItuÐeÊTΈÅÖì‘â²DÐÔž)tïì:÷ý®EîR°ï¡?™ÚR&&›п9‹n7$X¸ßKÁ]\Ü¢X‚+ý5wé–Lî—\<ŠÍ/d‚MnÉÉ… ņ@ã«Z¤ØA¥1×ç@-¬Ø~"~(A²«–rÇËãï Þmªp‹™X® £xÕ…¼¸D¯s–I[*„ñª9ŒP+ÂÃýé,BB㸥 Vº?—£¼-C@íC&×è>Æ(Ùéx¤>—!›Øýö××¹ýˆ/dq0b|)˜Žæ†|h ÿqovšäŠ·`›’-åK m]ô‰AÌÊ ¼îö¦2šØdñìGÒQOÂì4œM°¾Ï2³¯›ªa–·£^ºxÚ!¬]ºCüSô†VvàÞxÚ`”)˜:(õС¡=¶ï]ªËP=+fHA£>“”YTßÏà¾kãÑ ¶ãð¢ƒUÌ-y*†¸«9CÝ”Añ_UÚ®3=õ­À¦öÿˆl–Ý Ù dùsS•ø ;4L¦~@ÇÒ·Àv–YϤXÂùù!Î-så½LróP·,ðÀø#]ükçmÖ0ÊMÝ }‘ø{SŠ„¿7‰FŽG®ú¼ÅÓæ=U’-PÌVÖñˆvžžû'A+tî×ÃOv롃£áýú¨:štꡃõZ=LI·®­Ì¼³š2Ùo]S¢z‡;[_×DÅ&°‘°®Dâñ¢¦>EŒb×ĵWµÕ¨uZS5€D’HNÍŽkî”þ°¾ÊeF·ë!ÜÆKº$ëëã¬i^e]ã—õwºxŒ¯¸×šQéidžªŒQÁõé¼…àÝ=E bßuž¡XÔ#©ZŒq»Œê*1xÞ û¦Mú³_¥ð\q6Û¨úøµ.éÜÝ‘_ÖÂ̶°²Ô½Z¨§ ì3Cu×Â9ʹʬ'¥°(€+{NøA=U6¶ÂYep̃Z˜«ï½Ÿ]¿. ý±}Éç5µ¿üe=¼ÅÀ~]ÕÊ“þ¦R°RM΋ˆ†‚kA³! Ã;ºô¹ÃzºIv ¢žMn¯í“ƒÿÑ dësõ@¢~A´´(^Í”U€†ÊáC±†©0Vì#eÄ?„<4f‰ÍyŽ˜xw¥÷*:¯nêÓ†d-™3'Á-æ{©{“äs[ŸøÂ±£qIÿVã2˜º55'™k­±’ÄŸ&v¢j` …禲,XdÈ|á¦Vƒ´qrĺ> ˆp.ªîmó^eÌð:ðõƳ¶ÏX¸·ú­þÖÉÍMUfÑ˧ª$sOü»º¦û5Y² U²¢^ôoŒrÈ‚>‡îÿ܉Æ{V€e¦°åÙ‡– jÉ'uÐï’N-ä_SåÑÇ_qrU{4ûÒ3ÊÞ4µ€¹“&k¯¶©™mŽ LÅê$÷7j¤ßÒ¬¦ #+š…óŒqV¶…ÁV´qs |«ª\É ¬‰_­FN׈줡š¤N Ý2ið¸vlȬ¹$ŽW+¹àdˆq¼Ùż(Ø×¥Âò»øDŒ4|ª/Oö¦€Q}RMV»ºPÜžõfb¥Š‘Æš]D|>6¢-;2ý³ VÉ{ƒ¢kù=çw(l™t‘?5[Öð×ï@‹Õ«.âÓûþɈ«ŒÝ¿œúŒ±tÖbyÆv¯GÃmø/?8ÉÎI‡54µÎÞVËöºR¬0eS^8qMÛê Y´·hVB‚=Æ_™:f |`¹ƒ™ 4Qàœ¡þ8ðg£ñq=œ`}3H=^¬W_ƒéÒµg_Õ̽XSƒ`oš\} ïüWa Oâæ`p­—œÃV™‘'9+÷'µiÁ…6zúÂýþL @ŽknIå­Ùß—BØäwë4ôÝY„[ÖwÀ]äèêèNÙÆz×Ç- ‘mõoòw¶ßtÉÇ»ªXr%ª!r¹Ûì·%ÂÛ¹»ê¥ßˆ“ÙÛËïÓ7X•¥P&ÛœˆEß^?s•ôw[ `£ˆ†QJ-!oW@C ÆIÆ¿”@ ²"lf‹°‘}\ž¾ÐŒ ýéÀðp±¢£ o¤‰Mä¹8¾ÉMd5èìÌEä›9éöê(×W²î—kŒBaů[ÄCuïXå,¡ðö¡4 w4òЀÎFVXÝïnsâh.{_U¹’`†óZ6dŒ¨x8.Ä v]Ç8ö5a츷•S¬f|^Ì!e|^ ¾U•kéò¦Qþ©«q¨ôBëc2±¯s¯i®`Lš½±ôÔ˜/½í—ÆŒ¥7;>/1Úx^ùÁe#þñ¨Rþ-*ÇÞt *5…ë#ÃÝqºH5k‘–õ–bêÅJé5°ˆ5x+Y¨Õ‚Õ¸“[Æ¡þ?>>±‹•Òª¼`@ÍTO懺\ñ?±CÍgº„ÉeÚ}„ì°C¥ýÔ¦‡1-u K½’}§:¹M¦Ü³Àis;i^±®ZáM¹Êå1Óf Ûêt…*x·¤D@ßkjß‹À4•˜´±aÕ}–_ük"CT©ÊM»ó|yi[™CøvSÂð/´©¼mçÌ»5e’Ôº³66ž}ÏÁºø)U¢1‡ó4ïDx]À Nì¾2·Ò¹« †õ: T¾š•3U:†MÅìcìµ"oD>»xÙà~Zfβ[®ûG¥¨WÂR08 Ï¥SZM0 Çðü|Á¢ýà¬*-àØí+3!*S ªR[M€S n–€ÄØ…íÃL‘(D«póÿq ô#´¥¥Òij0nëQ’;ª}¿{÷þ“ªÐ°ÅsgY3&Ä“v¸OÐe™u&Uõ I­’Ym׉úxMê‘äÎ4­ Š 7ôá\4¦Ø×£àö3fžšÑ GÕPh]ñ"Ú{‘¡ÌØÑè›etL‹·.ò™If¤äök´änÿ³Z™`Éüóª$.L!âÐ,Ýääf“¯­Zz"ùoÏ‚ÐÊ<‰õK] 0£„ʆèåOD¢ѱhöÜÙ¨¾,ß"éìmÅ{iñ¯ÝJ,&Äæ•R!EøöQª c€†;‡'œÃ· mªŽg£—%ŠÏJ¡— ÝTðš©àT馂§…š¯*IµÔÂÎóm^“®V4à éàNÍÄ3üùyU€)3t(—Яë·F…ãYƒx°œö–è†ÎhFóXe¼¯“ ÙI=—Ú‹`žQ¾o2Qq¸¸H¶`Yd4¸ÉpŸøÐw‰ælÑ Ï:uQk0@°‰ï¸NDâòÛ«.ûd—0Ý„ðß.gÝ¢³×bú…¯&¾ì†0Ä7YD|ñæÛ*^på ýÞ윤ÑMÝÌ+p!µ‡'>ÒHñ_8€íÞÍÀÕ@ˆg¼Øx—È%çkîâ":Äcñ! @#֢ƣƒÅEFÖÏǹ{¸ã9Sס[ïÎB:QX¥JÚäHbaM±Ä‹Ä7[LÓ甎Pè»08ϼA, Ý“5ûX±¾"6Ì\gä5’_'óUd`0ç”tÔÂßSå-Nê±lø1 Ïîûð9v`ÔTeK SêBCá]œj¨(é%—z4ˆæ.¸Däœ"ã¤~M•BÚ%¥;ß%¥‹’/« þ{ˆ˜¾h$¿¤ö É&J¼“ÝQÎ}ÚÔ¡Ëo:¾í²;:l‚=Ǫå +ig«UÛp’A'FWùuË€XVåPŠe®Êa5‹´Êa5 4öíò4b«·Ø#4¸À9n”{±EÖ1vÉ2 .”œ”|l*ðƒ¶CÔö–T D"…î«ä*sÛ¬$žÌñî%k tù§ˆµÑélÔ½‰@\þéé,ŒüIî~ƒèåŠ: ¹“q_ Çîe´ÔÁ¹»Ÿ•ìã€f ñâNíÁC™þÑœ ÍyTñö¸ØÔé°Z8St\›l¬ÍMSJðù¼ Ô.ñ›ôÁ(v°q 'ÜË²é ±äLì%ûë²0þŽëŸ’ êô¶ÆbÁ%ÄÌ:ÎŒ€¬¤g7›Î òFvŽîjö°À1Ï»Ì] «Mƒä ]ʵâ®ïŸÍ¦|YÔÂVð@áQ7>1æ$aµ}ŽD¤{$$þCÇ;·\ÇæÄ{ÜÞÃ(˜ *íÄTEÎNÃȉf:Ôd ‚݃ë[§½ÈŸ†óÔyÕ Ãê­aöqkŽ~l…‘¯#by´6uXfÐmMI\0Ì‘´tHl4p&¸LC×€9&þ% ˜jù¾~ñîÏð”ê à"[±ÜiÕÂO1jPF§ÈáfPU6:‡30+`$:$£Ù7pmÀŒ"˜ÌÎÆŽAaœYžgÙ–ÃÖq£]×aˆÆ–cŸöŒÂôÛ(ÈŽ7ðîtl™öcS2¢Ô’’.nbÆcGòX¿Œûä¤5Í”Õ7g[x}2v/7Èá?¥êhRí"ëyîe/BÊôH‡ DÐuwõ ÈDoÁÅAí!aìà%œ(ÅŽ E'ðãšÚÐZ"ëÌ,)1—ýž° tfÚ8’’$:μJ'žÂ}*=±'ï:ïû–;ò¼Ô8ƒÄ n¨Õ&p1ž.Êì”IO´¦;Îг ÚEè[ט-z\YߟîÕDµáG‘?Ñj/‰ï0z 6PkâéMqÕdk NH/µÑë|K’Üï•êƒÎM4ðÙÆzöñ}‚#°Îý0ݲÄG6¹¸·• Øìtö¶Ú®CMþ•|IÌü&œÛ:,8Ñ &|ÒthFtÇŒZbßÓKH’²)˜(;>1dÛòì„ë±:p–›º°K¯1+R…±þI K~¤ËŒôà„ì¡>i  ãŠ_Õ¡6I^¾Àñ¬¥ñÀå–òä¥?«õážOz–yRf¼@éC¹µ«˜¦ñ®eâÅ…÷‰‹xËù›˜åvÍèÓ;šõáÒ}óýÐoXå³Rƒ4‹Íˆyg¿ÞŠKnUhzÅ.A/Ë£‰®~í~MúÃÖà ¾ì†Ks±…õÔí¹ââé®&]iZxvô-_/fpqÂý,ÏÍ…e–e×F œë;Ë'3»»§å×^+sâ…Öª|ÓÎ-„TÙõØ’H2$þB"0Ƴ°![alu-UzRmÿm'&ùò÷n™îNßgG + \TáªïƒŒð}ø´í ×Þ&nl ê–µ õQbd*Öëz¯Ã?-+0‚¬›!‰“¥H¢³l¦ÕŠÞI~ßÑ!XUQ…Û8â dbóÕñX¼¤Á¯hF®XÂqŠ?*˜û~ÚDá p¦‘ðzø|æÞŠÞ$#óH¥X½Ó5 KF¹RdæIlØšª5ÛX`›°©Ÿû½"‹߉ÛEñ&Y"~Uáv¬i¹Én ´!Éc«DÃS€™´÷ðÂ,ü/tq½ PÏñF.¢˜¶-ÛX¦ßÃ^õ¢tIÞDáCÞ•çä·eäQ°šV+ç{òÁqÿ±ð²¹Mç]=`XÒ,©¶3Ì"ÔÔ8±Ù”}¬²‚—½‡”©VÖ);a+ê"+Œ>ˆüÙ`ÜSPõh‰¢^Û·§ì¾,M•yZ“†Íï襞L‹“YIoúâ†4Y†¬JÏ_×Dâvó~”9=YS$â/‰kcClñÖ¸6vŽ®a[qµÛœD/%Å[Ñæ$bsw󳓻~nÌ¡[7ù{éæ$s<åÆƒ²ä¦JõR~ÑÛ˜#¬VHÈrT]9¯E©TÜF7'_Ê)!ÜSׇBëEsÁéÍuôÇ–"tñ2»!ÃýuCÙ÷ZxÄ~Êú˜è¼ <¬¾‘…—F1#Pê“×òÍIæ¸×Ìwì9öë¢[§þ^’kVÄÏ‹î:£qoþ‹§ŸPËçc'B½©5@§ßà1èŽ,Y׿H¸6å@ÉÉž0æ%Ù˜ 0àm9Hæ©9Ç{ß3Ë¡]⥹‘{~ -.šêè¸ñêBÃjI>…Û)ZfåζöRU¿÷{­\7kÃõg‡¸™t»¼‘ñ³ò…ê¡…‡u·Aÿù|n¸´ªÞ;áw±7æ"3«66~´¼Ë#4D8¦çG~Jtö  >›6ˆ½·6æÍ<¿)öU’-ôùé:ΩRXÜX®Ÿ¤ [–HyìûüѱLÜr°Œ'®4êŸr~þèE¸´º$ª5Õ +üR¦¸ÃŽGÿÅÜÐìò<ØÜüÅÜÀgî„3‰H÷šŸ°ð7æwÂðÏD¹ÝïÃæòèÙpÙ¶K™Vò'I ýtõfÏ/^þü{Å×°:t­).£¯PüŠ~;³Ü0˶eãq þü¨øúœ:áBüañ“eÛ@ùãâZ:ðñï?z³ |!BÜ?ã·{ÖK¼`€@?-~/Í£ Ûÿ¯àí¨øª©F0q<2I”La•Pëe} %€»ä& X×A“+,€V,²¢¿I·=‰m„›5Eþ¬ïkï½kU“0ȈŸb ^ô÷˜9YEžôÍÔvà³;7Ë¥F²’¦î3²MYX˜Õð(Ád  ‘]NÑ—²x²s[©YÖþ:ÖLîÈJî±E â¾ø†Ê¶F"TZ4Y'`] †R']m 2 ¯a§TkaIé$(ŒM… œ¥Ñ•!“´à™ä‘F¢©ØÎ´“žè4ÊØÍq⻚ê½<”m˜¼uüáÈÈ0ô¸´ÿqŠ?Y×;eVÔ©H§ÞÖÀåxª½9ÈÓ”ìrÉӤޅká)ÙåšÃÃ+ÊšÀqì¿ÉhÅÄ3ˆS·oÝj‚wÎŽ""G£~w;oiN€=3úœÁ¤ë6Ó’€4cN/ˆ´õ¬’ ÞQ{N ä#ªúØÑ§Íå|£’‰|̹;/¼z¨J‘KÂr%,$HþaU–‹°;W‹¥@[2Ïc¡ìûÂð4¢˜ZA˜ÜïûqêÛ0Ö3L…ãûºìÐÖtÁ›Îy[K4ãJ"9Ž ß¾ÜÓ§ÛT[Ú1Lö:Ø,½¯_UÞÙ±iSÂ!@Øë90ŽÂº0?ÊU¼|\ãW8Æ¢ lž?«Gàá†"™t4h)Sêâ—fsS› ä%Fò£Ddb÷+¸ÝD#~ÇX×Oá°Œ’·µI±$ÅøÞënõû[G½ÃV»³¿£_ ½Ã-FùÉÉ4 Z¸ ìÍtYs`Ô(}ïìÚr- k ‰ÅEë±4·¸JÐ/ –HxžešÑñÂKï;Ql¿_¿ô­SÆvh>³‚l•Ïߎ¬Ñ¡—=#æ1Ùu?öÎ<ÿ"5Íñ´>N6 ?1žHP‡'f5 °kJ”!6Œ¸"WícsŠØœò±•í£¬$ûÖ¨íú!beß5bc©žMnz€h÷¨L{dß:wFd×0£¶B¬lZô&¹ÙÕT$°ýއ{d¤¥²méVäOv‘;ž •0¤Èø übìŒIÌ+’èǪšâç~`ÇX•8yÜ‘$Npu…îd ;x.±ìÏeÃC}J˜é‹„ªí]Þº°›VHKƒ.Ö¦ wŠ7Ѧº§XŸ °¡X™·5NëÿçíM¸Û8’tÑ#’Ø÷…‹V«Ûìn»Ýc“T{Ÿ;ó@’Ð&Zâ´{ê@‘„…­Q DÎ{μs×ûï7¼Ør©Â"y®9:GDedVVVV.‘_üW¾’8ágêÝü’V¢åÄ/m%ÞóKž†ª¿ôxÏÞÞKcãuð7Pf¾åÏ¿ä•q÷ÇýW¿ì9궯Ùmšyÿò—´Ñ°ü¿pnuz?_{ÈbPvÛÅiöí/¬FÀOž÷g±ËÁíä bÊÿ‡MÁ)ÿý/m…Sf››Ã_x/¨ŽGðëlëõÍ/¬¢ïIÛ¿ÿÅ7¶È¦ Š?ôÃû“‰Ú1°3̦-uù&n§cNïÅò#¹r~ãÞV€{”d’§IlB‚|ÊùÀT¨Ù9ÃJ$„ý!ïFÖQ–d=öÆAû| ƒŒT¼ª,P²sÞz:08«jtƒ¶å†kò8ëwßøîÃo!„ tÓäRQSÏÉPÒdg:Ü4õØ\Ï PòsýƒÙ~ÍÖš¢Mä…’òµ$,8•„åÜãëÒ`öc×$¯:ž¶¿Èö=*­ 9ÔÁûÌ9r^’ºS×»ÒԨ ˆˆ—Iò]Ô‹öp«{=Å3ý€Ãǹۇìa‡Æ0fE Þ¡œfåpÇ 4¯ÝZìè²³Ìf{‰?ÊÖÅàÚ»: ˜ÉÚ´8Ïú·5 ÏÒ˜VçàãesÅÂDI¥¤´·k¢eˆ~äv.8åÀå³XGÅíÊtiˆëT«HšàGQJsZÙ“|¡nó-ÛL; ²%iS9ˆ‡ñ Ô…á¸GolÑâ&t)·í,ì÷eÓ`ÇY22,$Vû˜®!æô=žáq^aÐ 2ΕàeÒ±pÖu¡9OiКî"êÝÇh™´íè%X7ª_³èù›HíÚ¶—)‹~ŸìPå¤u5'ض4jšñyåë©7ž‡Ü²ê ÑøÌ£q«^¯:×ã fƒÐEÐðYÝ}×ò=÷+\èÑÔhÞªJä;³C˜hb)2^†Ë#¨oi:¿K‰ÂfB©,§¦—R7D»øËñÐ…=4É)Ø; !E‘>@:gÒx;PÒL+jiÎÅ>z>…EGö¦‘# wvßT8·ç0¡ÇÓ[ŒK±(b$ç~· tÞ±lžØ -M.Ú¾- H{z=êBK{Û¬ ýÇMbÀ|,{˜oj¿›šwf|#êÍ'¼‚:JÃ,¡ Ç{wAæž7³Ü\{²—'I·(ëqëö¹'&¬æo-n}aA›6á]çÐÇxü©:Î+ þO¤Žkõf÷åóµõ“—ç‰ôÜò^|¨ð§a_+áàw)¨ ùµlO¦cô0DqèrŠoVÆSo»-ö`ï·¿úK/¸##*sõ:Û´Â÷gªÇTEeéÎÒ¬–ÂO0^¶€H6ñÎÐ$6&ÀÚ%,Â?¬Ô±az²NwПøÁYi§/šWr!M;î•ÌJ§|…S¾²iÇÇÜÇ‹þÔCx‹˜ùt•a¢fgÒ”£“1}KTÝ‘ößò•ÏtýŒr—6;¾%}ƒ+åw5½¾üþ}¬ˆìûη>nrMÁ-2|}8€uÙö3 RŽ®¥]ër: |qÆJÜT7µ§ý•ÇMÝqSuÚ_SÚÿ 0;Ãì¾Ï‡O™aâWÜÉì*á€|%kp@T6ÞÎmÊñȶ‰o+8"q’fiÚOÛ–Ìë÷ô'l•°©$œìü|tÈ-Žu°æôg:h¯W\ä˜—à€ŒØ®Y~¾ùùj C¨7+ö #§¢ŸÆ.WqÓ)`’Ú:¢ ›6ÆOzW‘kÅöØtgÒâÅÝŒVéðº7¯ŸÆi|¤“©ÉxbR «k2X°iÒð©'Vr³k úzÊ-¢}ÞL¨Í¯ËcØW-Â2†@]hàî wf¸z‡:3`È6Pšò}Ÿ„å°½èã ó³K†¤¯$´ŠècèhŠIùyß&=øÖáx ƒdðëÙ_á´øŽ<át¹S$ éVT2_:íÃaR¾ÔŽo²8¯(±Þ°ã1‹€c‚ÏBÎL‘n™ÆÑ‰ë¾Á‹|S&ÀGÇ‹Ý7aYü¥²DÀqâJY¼øÃr§Ý…K¡3ç}™–—¦ü²I(U·®ú³uûÊeš/4&&l7£ž•DCwÆE©œÚ²?¼k®ø¶üÍeŸä![´µ˜œ*'·úæ?®F䲋æt`Åê|¶*Ny ìï–¯ÖµÖ«çÂÉ¥«$•ÀÞ•i¸â~«TB–u||Ü\fqù½íÞ9‹Ð¸¸€ï’A ÙÕ†J g ’t{S8Ý%0 9gÄMf ¥²Aª! OÞrŒù2ž¤—;ÓißíYܶEÍ9çtàSf¯nŠ éoÑè&cù9ãrœ¶Òíñ$k%i ÎYŽâ²©ÄÙ[ª73Ä„Š*Àþ ØÄet^L9ïÆÓ7ðîå•m2S¹¢¼¢ší¬ HÖ¾¹ã§ÉãàwœN·{=$ŸÞqÔ^e|LEõÈ‚~‹Ë5Aý•’÷ÕŽ³»xƒñX©É2l¾0Y²ŽÇºu-“(‚*AÓé¡õi~ì“g‹E¯Û¯–æµ_}´,¶½ö«§Ëò¹ÃÛ¯€ïEèÄÚÑ ¹Ûãqú Ø`xÑ`•Ÿ˜,ªEOê"ƒ âN Fû;­¹^Âéà Meâ2ߺ2¯øR8oæoà{FÕ”ƒŠ¬sL˜R²ÿK'gµåœ,9ù4†’ v»Á_À@×"ÉdÍ!Øõ•g¿ˆF;½·àæÚc¹‹Z­>ܶ©×'Î¨jÁ÷iá&ñjekRâ­ÛKÆ™j˜ð¶%­å < ÝnP Ó<2 µO—”®‘`Ÿ(í—#cÔô1úôä“G` ¤|j;^¥á[°Ô‹ÃhG$`%f£°®­À})‰™ÕÞ†þP¿®¥—F'%ª*j¯>Jr'>ÐD¬ŽfCU¸mdi~·€³|Ñ™¤‘׃e@’ùî$&cÈ~’\³ú ué¨Ì3ðŠ¯¶žÌ;öøÐ…oæå.`xW2ލïtðqzŽGXYd¡ ¾Ðû8úĤÆÑ‚¸vꮞÉO¨æ¹;qãf’UMQc/KÌ™¥/èq_'û¬4Ë âËŽœ¥õžê—-/^g#mZùA´ñ“>õuô Ú¬SGë’÷—I 0Æ‹ Þ#‹y@÷§ý/¿ýŽÞê™5£35Ðj€$f$§Ö‰›=wwÁä;›†oLûž09Žõór›•Áš?úxAmÁ2¿_Î)™ ø@µvÒ™}û3i³5¡ðöçJßÃëöUß“¯é "üzC×AÉÕpÍlóƈÌ>©â…u+øQ •ç<-Kñåá-•ùó RÚ¿@ö/ú¬ÃÞ»¹wî[é1{U´ÂjÞvÿ½,wðŽ,=3RG;çl† X‡’Èw—„—ÐYûÓî]>'+1+—–@Žˆ¼JÜB: r;RSÛ;¡Rp Š®m»hQ‹és4¶¥‰¾pNÛ%\ôq¦¦ÿyeÿ,¹)B‚I­vFî»Z%VéOYùx¹Ü Ë¤4ü5ù?®h¾¢ÇNÇS/åÌ®¦ãwQ“;8tËJÛWÄÛ sé¤]º“F.^o/¹ou‹|ØóI#僣(ÔL`U|ïý5ûox°ÜŸåÙʺ8¢u°ºugäåµôiƒÞˆÃ-ßÒY¾9­­?rÝ8¥ôÔ•¢K(ÚÝQîŒÐ±ë]6è ’ò¹r$ÙŠ¦µð>cã eîMÚàC”qÿbÿ‰œCO:#eQÏÒ°ù Y› }²Aûô›˜ã«Ê±÷cM±#l©ÜÜœþƒ`³Í%,ãíâ"ëð­Åfèi³:ÔFãè —×á$~D夰µØq%Úéõ¨±ÙiÀ«!?ïèŸ^_¼×hÚ_þ¡³|xÿVüá%Q‡o–i3²A¯‘'K¬°|üòÚáâÁr߆߈KªqÉ0-aÞ¶j½@gz+wþÁ '±x®Üf˲±ÐKíÁÊõyá-Ñž‹š¡H¶¼³àc£ê,&k¶Ü7—Û-ŸÁÇîKnÊÔZðáÎÇ7­ë ~ëÏVAðÊò1.ð±l†NL:+¶d­ñÐ}wåNݼ¶6Ó¤ ,kë4¿BV¨‹§™sÿ]ƒø¨Š‡ ž‘˜R”Ž^À µp7?·‡I4o$pJ%HæÈžã*Ô —¾fà6Öë_ögèϧ+ÖW÷ÆCàðA˜”j#0‚P±œ ¡:ÍÎu[¯Êef·“ñ%aªø¼3ìnéòñ¡1j6¾|þÆÉ,£AãÄsA—TQpÅ»/ûŒþ’*8"Ž8i~R\䞟Ÿw@+úõ`Œ]SðK¥E{¡ ”Às‚·¹Ÿmްy /à£Ð;%Þ§¸ÒvQ£0뜷f㉗XJ»˜ŽZ+®ÜŸèXÉɉƒ95±'¬H +ÚFØAõX ™zk‹_Ù j/5PZU4(Ë ‚:Ö RJ׳±D^c6ŸA<›´ì €ÏNÛ83ðÕgUéAyþìœÄ‘o¿Ìžx×nollf>[^ö»`Yu¦Âüë«CrÌÕš6œIøÖ|2¤KÜX äÙt‰ž'çI§k|älãúR>s ÌR¢ƒb90­Rœ™ÔJR$ •€Q’R×rW×Öen:°©YFÜðœcIî4]¢Î ·E[¾Øt†(¸±ÝŒ¾}oílæ¨;[>ÍecŠ/:#z Ö¤ù¬˜Òý{[Üòêz‰ŽÃ”™/îÁ†4e/L»ª·ƒ>¤Iˆ”øyNÕ¯ÆÈ_£¿%ã<{ñ2Ë[5Cv¼n§çªÝ‘ÌÀäôvv¥>Ž\:驞”s(TÜ?AÇt]+áåå8Ç"Å0~!ñ]qühxU¢6Ë¥ÚŽãs’I)Kâ(Í ’ ~_’Õ¶´YcJtÑóÛÁ 8ýšma[èWS²-4ó‚º96kVDnÎͱ4Å’'àý­ó­õŸJf|©Ò,kö&僄Ҭ(³ÂçI’¹´Ot¹ƒMš:é1öY€fºŸzTŸÛz^Ñ )¦×fQx7þÈ¿Ž.S6£è…¹G³v//ÕÄ›H|vÑ0ó÷EgÁÇ QVÆoPcî+k{JѸ #ÐÝH,ÚÊ>õ°8ûÌ`ÐPÈÑ}€ò€¯fGä“Ñúá4KbhÅ ØG›/ŸLÕae`ȇ´²hÚ´ÇhNqx¢@üLoFy½È-YX¼yyŽ^4‹fqæìO+°jç ³mj±Çq}ÃaÏv~ØÿIû ¡J¬ /{›Ä½·Ä,®WàQNèÓñdñìxtª÷thØãôJß› :·êÓì-·n_|ÃãÅdT0ìýyG;=^ó«•·}·ì¶}‰ËÊ]ˆtÓÁ×ßµpI)§®³R´8[pÿNo|ºpSù|ÕÓ`¬!€HÏ(OÂAÌÆéï ˆÇîC _@¶MÌlÕF‰f4pao‚ê^óÏYV|ÜpÆQeyÙÆýQЙ¨‡fx%ô rix¾Óa/å¯VöMùx‰w†3ë×áÿ}(³ø«|ùžšß•¡÷@bg#pɱšh“=!Dú£$ý•)ÆO-u3´†¿{²—?r<:·’Æè£'ÊL: 9¯Þ­I:æÍY±€*b“Žå:›qúçngÈÌpËåKcÕ¢õ„¤ý€”¯þ¨,ƽ¤3rÝŒœº‰ÍAܼWB²ðež¹ÎË ÏÐv°ú-‚²ìješFO+“Ü4b¬e4üÀP Þ#“U›“Aå¸*èo)’í°æÛ`ÓŽ Â×*ug×A]6ÈÍÉx"+V¹Gê6áoὈçb‡!•yrí]É ©j Oì«0£xo„OdÝ;õ“•¦å!¬ÊÊÁ^¼ýµ|,úG–cÓÊ‘Š“O„Yrk]´Ñ‹· _z2¹¨Ž-mäkhNÐXÛcm7GAîUM[‘Ík‡z¸?Áj–bô[TÂ2.•÷/ÅÃ}Îqö±” ]g"ç½Äß6}ésü„Ö Z6>ùÓðÖg{¤Ç‰²ðåöbò‚noÕùRð¤&-YÝÓjV¡)uN§Ê{¥Ã¬%ÂÞõÅEÿæËŸ”;" &)Ôš‚¨ÎÒJZ‰)œŒ)IÄKQ„|+éêðÏò&©Žú7ºãÉ-KïvЯj#XQñ0¸ ‘•YZy˜ÂàN’xÉ?®6+·; W¤£ãçÔ„" Yö…‡ZèbAéô zžëÊÏVžjúËÆiŸ ‡õ´ƒ‚ô¬WêõÜ^ÑaOþ€Ñ¾ß†4®õ^NèÆ%»X2Þø–ùλÛ–8 t@ßôÝñÌÝš"o\EŽ93¹Ê¿š;üÓò¯7_8c†&}‰O–~®@ÁGÇóкµß®|ÑUwFd£Ž“ÍùÑ%+G£Î˜ýK£ãA¯†ô0LzàÐCï°hDr35?ãŸV[ôø ‡§®‡ìUw}oå;-ðºÞ”aç÷þØÀû‹‹r¢½1ûgƒ#ðw+œe ZÿÆŸYË¢z¥¯W¾ÿòûÎ÷¶=¦e"äL½Á,i»Rü~Å:aÞ¢é½âî IHJ” cÅ›[¥ §ý¹ØKŸ¯p¯ZP<pÿýt•Ç‘¯dn®d¢Œšó¸Þã¹Üï¬Ü$;¸–<<¯h±jmÈÁ¤*g°8p¡´²»½„ƒîÁ—ãi¤xò³$×·ªxÐ*U2®ŒçìYf½ýf}5¦9ã |jRJƒ-*O»›Ç&€wQzîê>”FznbKœ$Ó9‘ ŸR¾Î ;7ƒ—–öGv:ªÂ==3Œªù»Âq¿í|ýåÁÅÁ³g_>ûjïëo/ºþó7_õ¾êt¿=èìŸï}ÙùêٳΗ_}ùuïËóožuz_Çwpð篾ýæ|ÿÛ}Æôvz,Õ8¬½Í2vÂxØAƺÙ:Ú!NÿîõÔµ2x¸uìP¶ ²!ïvÑX«À,Ž/ÿ¡/ð-–¢‰²l_ôÝûUwÊ'òÊéŽf!Qº@œæxà&åšg¡$p“QÔ±I×B¶2p#l¾@0‹HØ'DŒ{0]»äÓ¿½€+ñ²+¨7C“—tYeÖfƒµÙtí|°v²"rëÎÍpݹ†ñ;x»ÈÆù/×`c#‡c5T>Y1ç|h—SwูÌÐy+•Ĥ—y‹]dŒ(³m±fQõ|¶âÁ²`᪦w˜’_bmªn’3T»s™à:Úè›ãkË oÇ“ðM«G¡ô"ûߚσJâ\ ޵´¹D[Í\e“n{×£Û?LšB"Œ¬‘¢ÐGë€z+wáƒ@]ëü‹}¨£*ÿPäWz~B«ú'ÜÖ┼ ?¿š7¨ÌsŸ Æ`!(Ÿ´#.\W§Ÿ‚>#VëËYè`Ѩ#û)J˜æŸ8YS‘ˆÃ§NEùõÅK}p/ªb¹å´ ¢U3´X듯@ié¹ñ”^+¢Í€”¾“ÛhÏu'x‘[{­S=‡mEùð÷—†]+. O·©•¸6õþÒPi—æà®TXÐ![ú9ç/ZõðX²„³ñ”Åiµâš0ÊÔAÏŸN‹Å¯j|¼ÖÄÍdxŒ.–¬rÜÿ„ŒUÈ«APÖYÜ'>RHRˆs¢ÊÂq›ŠÌ‹IÆA`á&oâ´úx|™ôI¢Òå-óa7…RÐ:)a`31ÖÐf™C“=XÇiØÞO,b‚õ3$éÓQï¨; #£Jt7Ýõ؃éÚÁ€¦;w´­É1ðG§Zÿ?ýã{Â[#Vˆrý`—_5‘ÙR6Yz_}`-=hÞ¾›œyèÊöhÌópAâûûu‘û-H²éMÈw ìë3azKN<`ÀôaýØ…áÓõŠ ÕÖ®ßwv~¤ÝŸèФÕbQíp|S´‹=KÚ‚l|ÈÙ ·Ÿwsí¸ªãöyJÅ­ ;ABCêÈùžQÇ´¥=Ï|±hv4Y—a;ÎÏW’ul0ô3‹ˆnŠw£CvÜÕC´C7Mû7YB£Æt¨G*2Õ0L‡’¢Þ³ÛE ‚„þX-ÐZc½ âÙÔ1†Ž¾DÆŽö9}…´Óù)_É0ŒªrOlm…Þôþöýk:æï;ÚR6NLÄvÆÐž¹uákƒF|ü/´aþÞ4=XÓSøpJÚ(VŸ¬:Õ° ~±üdyÅÀ¹Ìº3»‘wÈAÞ+ãˆ*‹Úñ92űŒèOgþ³ÞØ€d¥|@Ri?®Ô±•4Åa& ¡ö˜¬æ¡¶~k;KóÙÝ×åˆ#ÉQëÝD‰~Ü s*£úZ3ž/éåÍÙ'Žœ®¿_ôØùbE#Þ¢ÆÂÝ8¹¡aµ¶wÏÏs¦Vù,¿[ýl)•wælÃSÎÐÒ›æ¹g%í|VæÏ®p-µÛµæÜ¬9·çÊe (»!ÙtóúäœÓB‹OíWiI5`@cÓ*Œ*.ÏtÂF‰øÒ‹8ìωZºHŠÿ kë³ ó5ãGlÙHGš\…9KOá!ØsxRä’£W}¾GûU”ÛÒ~•šÙdrwPˆ IÓ"Ið³Û¯r°uû ЪÙ|Íü|ãâ¦æõ›ö«õ[è?¨øõp”¢£„aËSÒX9¤|¨qÓ ´¢óÙ;$<ãj÷´‡E6øê ë}Ѫ„wNTÇÿˆ'týÙmô­\¯GâsÁӜ~Ø\øe¶— sÄ´ KðÉl¦‹“ÝØ:a?šTZ™o1»“D!µÜ©óMb¬k%k$D,#“vëúLÅ ûãÑ=îH²mlJ4XRÌÕpón¶ú$Α+Ðõ9ô_ã¹™G>Ë=2ó õŒÌ- ßaÖ.zÑÍÀ(ßø'Ä/;#Mç‘CF»ûkWô°óÆõ/‰^ itù@޶°ñlællG¯P÷ÃÅôýBô›e>ÐOÕfOõ üª`@„iËØßðÔho²Í®ÌU-‰Àv#/Þ§(#tiV‘ÏÞÃhÛ>™ §‹*Ò¯$#Ž•Ûá@pÆIÖÀr³œÅ³.q3À35J¦YÜ!Ë.miD•¤2“ÄRbJæn§ýòiɣרT®š4‡ÕˆÎu;£Æ»‘Å¥e$ ~#}z–kÈæ”u]š)'vjøŸWôjrÚ¨YVÝ´T7“V m~ßf_jKîÚüùßów}½“éx6ƃ,sZ\^œõñªhßò¸‚3oo*-]IÁ’Æ 1I•H çeç&þ\îÒn¶2cêìd__¤œŸ¡€6èwx÷áØ$ú£\©§£¥ßf®ˆ˜ù`”ÖC©<:}ù‹~Lµ7îh¨¬¯š˜£ê‰;ZöÝrÖ¹êAÌŒÔFŸòmôq“.Ÿ1VøÔGR¨Ôb 2\ª ÔÝwdl8Ašgš¿›+“í®Ä´?)]Ãg©U–UÞî…zè/Y,[Ái> ÓkÑ)\Pà"‰/)Í'’Mˆèø@ûï×ø˜öÃ?|ò~œa.øûßµýÇÓ/Ðv§‚@AÖR¨RB!ãwL©¢^l,âvkãi¢—'¬lÐÂ[òó±{¾xñ\¬ÇdÇÍe̵¥¤l¿C{ñ1ܘå,@E€é„-Üc;Œ£ñ;TÖÓ§Àüs:÷— É Ë๲Kƒ°È2 ÛkDXÿhOˆaϳ2e¥YDì„}ö›N&›!áý~·ÚÜXJm ”¸Bíå®Ü{?ö¸ÿ†ß­À;çÊFOáà•I~·?ݳUÆxKîYwú=¨x£•A³®:±IXô¸!'ˆ{Ìî QDÊ})RY|½÷ÄGÔæ‘Õ!ïNŸ-ºç»Õ÷äË ëC'Û\ù¬Óë¿å-—-°HЧÐ05a] @ÇTÑe>û‘êT’ø@.Õòƒk›΄ò³b„¡ I‘)‘Rº^J=rGtÀ¤+$.Ĕ$ÎWÛ÷´¬hôt‹–BOIwb…6&ulgz[ÄŒºDVD_i ó3WÚ&fT³ä|è¶ë#;£Àƒzlgέ0O–æ’âààÃã\+k¦´eBC&ÆI ¾Ò]§­´Fo¤P»|&ÄÖÉ‹ê}¹´àÚÔ‘øJb°E ¹&ð>Ucç\ªY€Ë¶h@™Ê%2š˜¤Ù±âã†&±b”+ù|£µXsdc8ýáô±\¡ Œí/01^P<Ìa]V-¥f®~½j?"ç)% µ”siQÐÿµëö0´IÒ¦'É2«îŽ,ï•ÄIR:‹¦¤žÁ$Sd ¦ëïßcÅ­—ëi_°$EàáTœVuö¶ÓW9ãRÿ†?ø®k¤¨Jƒzµ8êÅéîêR‘shP;fi¢j¼ùVEU“"ùšVG}˜Aá|ysÞ¬ï£â¤ÒÑÚXÁ—·“+XóÏí ܵ”ÿž/»Lšƒß3"s¿]¯Úëš}'%Ø0Ée¹’„ÜüÀàsÅãttEgþtÉÁ´“¢Æ¥„xî#ÓÃ-—ãÖß…è/njðµñYÇ(Æ÷ó•]7W<éX€Èi­ aH4_ê³Ñ¿‚1Ð ³y;Šû hbµ»1_ı%8KoÏ8þûi¸/wB°rÿ°Ê=qµh¼pÇCw6½ÅpÈ»ËDt»Ð£Ú|ÈÔôZu'š‡ÙFŒãô/V‰ä ÊGÕ‘NÁ!®äj<è¹S)“R“çîŒß¨s}¾KåÂÎ;JS3:)Žc­hüPIëoìÇ¢y© §Ã€æ·¾¦,,‚k¥¼G~þÕ’ö#R¾Ú DW ²ÑqÊ÷.‰y`ð{ÑËÖJˆ:0íïÖ$7MðÜÙ”Äjœ‚GcK«=òêxN¦0ÔNãTá£lA׊?> àµä7©Ž”¼ ôâ'Ô¡ ™ÂêÀ{í#¿×ZÜéâtF^%Á&ïÑáX…Râ“.xuvâ·Ëæ9jà.Îò§æ’ÔzϾ’Lå™wæ@@ Î< hʱ?sNQõqiATä_â[¹ìVÖ<³õzúµíGd]áO9_x“ØRWíÁ o ¸L†T×ÎÌÓ‹–+ž_þÂEŽïzö_`2£eqüúí ×<)òùÊ<Ç/=p–rGgž—J+æ*ÿ¸’+õE£Éu3?•«ÛzAïæ'ú”·ŽX b­û%GF\5×–+ë÷“ÝõãE€2?4 ÍÉ?-¸ orü‚Q·ð†BYC`ëɱ÷Z ß 9ê\¿ž) ˆƒ,.EB0ô4ìÞG&'múW´Ï> ú€*›° ¶íÀx=†!É)–靈(2^z‡B•7U¹…3lG©Ñ|ÄÍ˨–R4Çp¯Ÿb@òl:øÁ½M9]¾ q&C¸'¦z‰:fp¯êÕ¦ó²T¯U[NõÇj½o¿¬µü¤m"ÕZíj½åÿìÃB·RÙ'+¬20¶Ö;X#¼Ä/£fóª»"ø†.³y¬ì¼`È| ÈüÂ[’h¤;CuMM+Áæ½ÖÑ`ÂÊÌ >\v¼ 3üÓU›/FErHÓ¢Ý9ǡÉ*ŽaL"Ü5ŠaÚ¡_˜Ï v[<øÙ[ÝBͶ‹ÛèÚ†î_í7•ݼ¬ó"X1iÖ|r¥ÊšôIÿÆxE&`(x9¸€«L4`¨ÇðÀ>:zMû¤}’'NQ1ZêãÕ ~*“'Æ_ðÕÊóåÎÕÔ½àý`ÓqÑö·×Æco””×f­‚‰éà·¯RžI™g²n<¤Ò´I¸„ã…Öj ßÈX5Üü%ÛgŒ£_Æ1®¼5«Œ”HhúÇÕf+vÑ";æû¹÷ýÕÜ‚;¢*¦àoêž{~}«à_/³¤ÄwºÄª.•èVÂËÿþ=\–òYÒÚ<掰- ÑÑ$Ú¥§ûbvÏL™VÜî˜ûû“ÕSÁŒ×` -Ã,Íî`ƒLNne5O®4Ó¡EJ©C ±ë¶ YµµCÁ¢ŠÉM^áiMeZªªH¥–ò|Z}è+ú´¼8pŠ.ð?>€W[~wÎñ&—®Í¸%‰"Ÿô!Zß, vßcŸKïq: }6k] Ö¿õÒ¦û‘ØK¿oÊ«³—™iéÁÁ¨oroÞ‘Sòµ:Ž$–£Žx uÄû;ˆ­ÇDÞÎ{¨BvKž`ڻĻIÅÂÞ™ Ýêx•ñÈí¥ÅÀ?¾÷0HýÃêÏ<Í ‰Êµ,+@ÚM c¯*äã´ã‹®‘t¬€)ÇÑçH¥|ÊOËñƒÊ& GƦ¼èL|%hùWþH¬>r¬hqG‡ c@xW—õE•纗 ½4Hþ½tZÖ%Îô’åk³ÐºzFY%#ŽØ·’Õ°Ë0ïq‡c5 &Ÿ¬n]YÐ6Ë7캔~*ãøªŒã稊ΖjÇYÂSù2|Ü“³˜Û²nð³U&^™¯Ê:Æ*ç9«MgkõÐYÎ[å;|‰×Oœ•üŒ¿áðš`×ʘl(Ó×|””6œA×ï–)Ä|¥ÞçMNÆ+/Iý ˆÑÐe1a]§ p%=_2aª/WòY…²ÁÐ+PÞ‚EŸ.º#9à¹4G#ÎEVݪ°-ÊsÈÁˆI¾‰L‡÷6ª½K7ìPôN2ìa•ù9­.!"‡¹>4P¼¬œ“-4qjI(‚øì§œ±×NÉ`)„c%'§ëAgšW‡ýÅNÍÛÀãæœÝ:²æÚ¸öñOç&ãj£39~‹Œ*#]œ˜D_¬%.xèp‰àÏøë¥(ì×Ís¶uÈ׿Œžþa…§ö! W‹nЇLë­•ð?,·÷ó•ËX(÷´{ø“+m…ô¹q¡Ó|âü/æå3®jÇbË|j¯ý¥ ^v‡/¶ƒ”Û‰ð,“›+òÈgs¡ú‡Â³ýý§¨Æ,UoÝöÑs?ïþ?VÝýÝûîNÞ¦†}{„u°„€¼™¿ì·+Ÿ´êÎ/VÞiÌ8tŒM4ÂP‰OWÞl—ü–-ê–”ƒ³J¡O y‰…I1¢oÏÌ“U äWà0¶=‰š!úQŠþ*ËÌÞØåX²íÎ%ìžâˆ3ì\Dê]ÒõÎÛ>c1ãðûe;…¿ØS4GM"#¬@Kò'vë°Ê¹ž°0—Ü„‚fNÙs³ÛÛ\X:…kBŽº¸K¬;³.ì··nO|ØÕ.ŠÌŸçíq´æòçdØOËA·ø)ˆ÷*§aσ;´Dû”^e³÷È…¥à —^;/«µ/Û1¼|U«´_æ?ÕD‘O1p¤ÄwXÄñ´çRá~Ø¢JSØe!®·'ë³ñ$|\«TŽªá!yõDþrÚjמŸEøÐêv£Þ¨W7FÀlUŸ·CMlU¨Õ.5Û!R€®Wë•uèƒDëô¤Úl•›µ“v»†¥š¥b­ÓC¦Æ¼ës¦…kõV­R 3hA¤qÚÆd† ¦3üitdl1ÂÓie„§ i¾‚’®/Ržñm׆ëéD ý¨Ý\̦ëÍöÑút6Ø:®6_TvéW_·FÝ9)µÚÕ¼À5á.Úk²3º6…£ØgzçÂ’îÍWU'e’¢dèȇˆÈÙ=F“—£ÂØ–Œ*…ûœ§<Ò*Eéø^.O_^_¡ra[‣n*.Õ{13%0'uˆë)ŸPŽÙï©ëœd5QS-“ÿRéÈÊO|h›ºÊç8« wæô—þR´ø~î$\ú¤ßÊgªßFo6õ•ÍþªÍû5Õbü7uÇÛ\?G6myJûÎ"£±çÞ‘¬ú#(°ìߧꬿO”ø‰6·¤ÄÓ÷@­.*µ¼Z3ýëŸú1¶W@4¢1èÒP1}زեý62ߨ{ä‹Z ±ìyI}¸"oÛ‚o‚×Þ·ïiÙer²r4Ý X Áì±…{¯Ì Úh³b¬Õ8m–«N«Ý¬Õ_d$Õ†eáùQãU¦Ü8>i´ªÎóR¹ÝhžeUZ~›9>Žj¶œz£]ªTª•”E©WM~¹Y-µkzFS ÊÚÕ‚N7N[ÕW/«Õ£m0"ìoÿ¶“¢P±ê%¶!c½`…ŽU´œ!»àn=«BÊ*¦/´¬¢í³º¨/Ô¬¢æK‘v‚Qhu;u4Z}·‰J«ïÚR¨ŒŒD©ÕíñE«UÔûsQkUNšÙtr;ÌV7ɵU¤­™Oqë+ùÊ÷ê9ûVQÌÇÀÕ/à‹…«k51q}âØ¸æ Y1ru¹in{–?Ê£EaqUæÃáqc úÒ|;p®V]ý ælhtoÌ›ÒXƒCÖ]µjWàYx´hâ躴®M×eiþtwE¡®ÍÖ ê÷)u–r/@óç‡ B÷êš}!|Íü ¨4ôk ÔI•5,ÃoÝÿs€NzЂþš†„jý4 m¦ ì˰7_ëy¾ý׺Á¿ë©æ¸ÃÉì6h:½¹šäÂl é{UDöŒ)®ÉKÉþˆ Ͻïöê㑆£æû·¬x$Ö3¨mÝÄ[Pm}âËÒÑôÔóe‹¤hÝît—Tµé è Än N;Ѓ^õ8àƒ¾Ç /,ælkq$ùøËF³ö¯z»t¿ÒÑX£?V›íZ¹tUã6Zn•NZÕhW·èI³ [çÀ¾‰¬éJ…YºQ:m760 f¤VYmÖÚùÑfã¸TwNO"SÄ:äA¦h¼h–N^ÖÊÀΟ@VÄ µhô=lÚeÊÕz»Ú„b«XãMO'Å`m•Æ«zÞ_Z¸l/¨‹nÎÕ‰¥s¥–q*Uþ==É0ÊW…ñÆN'[¥““fãuí¸ÔfÖÃy^«UŠ OÇ7À,ó˜#ÕÁúaãõúùøf§Mèeú;t…³'ÌìD˜O¡â ªa7·ªɰŸ=··qØh¿Ü8Ï®íf©Þ:)5¡A +jk’,í•ý”LŽªESáoÄ|WAÅüÀ„ +Ê4HGçe_ÊÚINÕ*ä¾…ÄM”ÃñVeú˜‰ÁùçÏ ŽSÐ5©M¯^uDA´ Ç2@±Ñô‹u4ž5¦¶ÿ˦òS±2¿ÿÁSMiLEÝï¿åÁ|½(ZYö- qµ±ì"ˆôµêe’Jâ­žÓPÍÕ-·ÑјªõÀÃ@?ª×ÚñöM—ŽŽ˜Ø*¹SáçÔR ²/SÒ„®¬“9mk#egY° –k£çýÁŒŽ¢ÕÇ3E&UfGÅÇþg’]‹ÍA Ë97s§Ö.¤¿ïópæ¢he®‘š ­6ÎÆÖY«]=V¾y\:ÚôÑ€Ÿ¯4êGg[>j­þc­U;<ªnÁЦ©X¤VÆ©µÉHØ&‹5§qø—j¹íÔKÇÕ2H/ª;>ú¥£SÉØ”wöyõ{è“DiB1ßt`méL(xŸ‡z;¢æ„J¬Q2„ÛhJ$Oç=0y'Ƽž²¶¸X¼¸ƒO„rVa¦äÅøõñ‘2wMÿ8 vŽ5Vo¶ p»}@Ÿ¶¼ï +į̈?ªÕjõª£Viü§ „QÞ÷¡Ù¨ãѾ,di¥ádÑjÍÄG¤ìà´úh1Ÿ ÇV^@*ã¡bú,‚16o6j1S×ÏŸ¯/.Öõµñ¨ œ/èfíœ'åìb¤Í ÉL¢ 9M|¢O5j¤Æ3ê6 øí7%DÁ ÕZ¥Ö>sŽK­2xQ?Æ‘ÜzY{ÞN›4e×O«MúT˜.È÷ªUu™„#È“Ã@V`ô6LVŸÃµÌ‚¦‚¯hŠ>²Ðç¼ äCT¤ÀÄCð³N¤  ‘“ÇUZÍB+­Çb俺Ó1A¦(Ù1@af:8²Ói:·Ó­B×Y“: ré|Ù5?"ì¶/Óøš~䣟ÌÁÆf=6üÖȱÙËaÛ³k°"<_.¦3p¡œsizÉf6%㌠ã_|:3aÈê ô¼Ölµ7ŽJð—Ø"-!zƒc]k±l”éuGƒÒ$,¤90Õ¸ìt”PWFðYT)—ÙŒ™ÔĘW¸’däW™ÜŸAà ‡Tü£uF0pÛ¯j'¤Ä§E:v\«óÕ0°ÔíñÆ0¬]·?@§žñ4Dôì$ {åôèV”Ç qY4; ¢½äçI™òi9=˜ÅV­QOȯsàìéë}ßõ~òð´vTqx~†],¿\?ø|/Z:…ÉíÔ*¹,õÆçníäéüûó7_ýŽbá2Ìœo‚¦7vß,É:ÅzÞaMÜㄯÂ`pJ­Z©ƒ%kVòúQXØr5DûK¼RCÞái»ïõ=åR]#îüU£Y‰‘7ºÂo;]¿ÄÅØ_B?ØQt/pòŒ¥w<+ª û˜q«;}‚jÍ@ûH8"ŸÇ6…¾å[èÊÛ}àuXxS§@$àùh¤>¦Zy‹Ê?[^þÙo|ö5Pî~úžÆ{ ÂIYÏó³-óÙ[•q€B6fÓ›©ÐlÒ·©àd`I1§"ˆ‘-Ëh!‰ n»|Å_Âؓ峸+ü&Ëw!}BÇÀ¼¥#Æ\Ÿ{×C½˜çÂ…KaƘšƒ|ìvFìý)Å“ çDNmèY±%KNb˜ ;_ÁRø¬JÓRLSgĦ„:µ áò¨tÖ8޵ùÃéIBÅóD,>f¦žKx]˜3¤§¸ ¼=¦žJT¹ÁœP&ò Ò`ªÁDðL“F?Yµ%(öcâf•^F‰8¹È:[Ù™´ÂU¬@Å_¢Ê¢ ¬VßÛ¼öÜÓ‰Pô˜§aÒ¹¼áRø¾”‰Ó%7Fw DjXKJG'/Kñkã!ŹÈEL&¹ˆÉ\š4\š0“¥4“©4‘7`õ*oÀºÕ —kÍòQ5ÜíO»7Üú—SÒÃL™©*¿¬–Ñ6©ÔJÇz%Òëw†ãQ/|E¾eÉR³t o­^©•00Îû]ò­ŽVë/€ûŠœ»£KèªH¥Z®P‘¦(içäšZý…ó¯Õf#/™ÒaÈÒÄ+ÕKõÒ‹R³ï¹oñ¦3íG_œþžÜ®E/¯F‡6¤4Ox‰”éðúÍU?òC©^/UJ‘7ѨÓëDð0ÖsÜvq5ßh¿,Õ6f0Ü7N›•Óëiï:_þËNµÔl¿<:sxÊv~SíLgWƒÛÃ)Úàæ°ÌËj ä%(„‚Uмtaw n[3wF¶ÿô(|E¶RN9åFÄ‚z;Íd‚¶íŒfÑ—µ&¼^½½êü‚L+ŠSk6^–RŠ^›Ž¯:ÑJíÒXüMgÖyƒÅEŠ+:—ïÿ¢Y­þÀßÿÅÔuß(ázP†ÅôáH—¦AÄ¥™Ì¥‰L¥óoŽ;7x.z¢q2€ÔùIÛ°ÿ -ºL—Xìd:k‘lúÑIÓd“c(ÿ:ÈEaïaÄ¡8‘^5kíj i¯Pwš b 8úr;ŽTæ©‹x¼æ4à5èTÌ9¬¾¨Õó6-ù@¹j½² áYÜQµ]ÝôÝ­ ¥ât¬Fú¹˜öQ‹2ñô$B¤Ó‰”:†·äRè~Em$ú`DQ;éÀ¢!Êõ,T>ªáDD@ŽB½á‡SnœEª‚QŽ:Õ££ÚI«Ö¸C/û—W<8`ã0…{l¡¤Ð]µz­]+µ«•:lóÑ.ºwÃK×fµ\…oTI¢ã6ˆnÿ-dÑ}ª+’¶Ÿw² <\ÅÁÕJƒ½õõ7 ‹Î ì¢dHIl@Ö†$ë§ðÎ"%P«"òr¨ïwº;W¾S-s ú`8r2YÛäÐ>Oß™b´A£Q]]Ïðûȣ•ÒqéE5ã |Ø6½²pocÀüsbgn`º#[K¼L_¸ ±knXŸ—NÚÙQ¶i–K-²i£r«\:iiNvjÜ‚qPîL¼˜.ÓÙy,í¿7Ó…²öm4{é6š»x[’>|]\zøõN8ŠZ3€AA…Öþµª zxNËC8ÏÎB8ÃnCÕf³ÑŒÀŠL0¦9„X%ŒÖfLûÇÊ/¡`¹4eõ»>•ÈÄEÚ¥ÃV»qjµÏŽª!úuzRA—nékŸo‚ÓöÙI5Î'ø¸­F_-r3 !ò¼Q>E õi]®¢µ:/@Ѿڎ׎á9G%Èõ‡.{%‘U:Hd N’×éÍÒ«„ žÝì¼Ëë xy<Ÿ¨Vr*[ùô²õFÛ±kHÆL€*Ùòå늊V)]l¥ð1¨žÁ<>N‹„¹|­d¥Oâf˜Â]:*Øy^k‡fãçýY´úúV˜Z#Á"ÓŸE Ï)ÕÏÒøËG Ø>S}9GèÁ&úØ™ܳÊXF«d(ßÛf =7u¯=¼Â<ÒádpFõ)Tpò܌ĞPé-’1›ÁÛò&0u Ü!i¥ áYAÒµm)ýt…µÔ¢È,²´ˆ"ÔzÍ"q9âôqHrX.@Ú"£.=PÉ‹ñŠða"^ã ] «Æ¥Ê³"ÆYµÝÊ69›Ta°~ŒžjÁl®ÎŸÍÕm ÿ¤ÓAÿ1šjj›ÿ‚3OK²sD‹¢”¦;u_²*‹uÓgiÖæ o­ÛyÛYL,ËisanE©YÛ–4-À¶o.¤nã¢Dr‹ŸÉw…uÓB§—§Â šŽ¨§ÊÑG.a%¯aËÉèÐ$%ßðç”o’‚&Ü1§h£;íw9:©ÌY|¸Ü*\¸ÄU5Œ´©ÑözV l–vTë8±È[lßëÚ†1ì ‰¨²ÙÎÒ…å=ÃæâèaƒB9{ô"ÏC~/›JýMáaÔ‰tL»×°)¸YõTeƒ^‚Âg°rtÙ@ÜÞ5M$Úõ+J*ˆ"×Ýw¶‰òªs¯ý›÷Þö[Ác·Ñ=2n€JH¥í‘TƦ1ŒÃÌæ ²_û¸'zcmh–ŸXxÄ|]´Iê„2=xb.“UI•¯o“E¤R6á K” NpQ5EÅ$¯óˆ³ñ|r>3'‹ÿ»Î´ÇÈS¸³N÷!¥Fäç$"EN5JS¢ªEI»½ _q<© .?º &ˆŠ>¾šŠ‰ÆmâÀ4äSÃ×)¢VÆÝkòÀ’•ÎJZ‹i*®“ÛÚ­•T¼—âÆòÉb°öB’A‰Äá‰Öñ¬ˆŽ±¾'Åaca[Ü–’³Á…£0Èõ5ý½üÝO?ºƒÁõð§sâæ\ï§·?|¾÷0µ?Á¾ýõjªZ$ üd‚Ÿ¼iW¢ÚÚT4×ÿ¾faAÙ IŸw¼þÝ<±Z€'…IíôšÎÜ—¡…²d¯‹CåÇ>I­OB}¯Ý>„}Z*4ÛGQh“òxŒ£M¹»Á¸IãÀ0á$söèá°&¤ßR)tžCKƒð”Â:ƧÚl!†ÓTæ:"¢/ê.:st¦·Q¬ g`R] ¹B˜ƒ¤RüÐiebØïéë>¼t3¥¬2âýщ4–9×˪Ãü­`€ÒC±‡bx=2íZ¸K¡ÕñH£˜{kï†á.uN¸{ ‹ù Bós<ˆŠ«‹·qÜ™]­MfdIU7(ãÕ+*b(Û]´Ç ùRçéÀˆh™qIYí1éU‰¶e7ŸU­„ɉàUˆ^‹´ÔTéN0K¨æ\w÷"oyè„ZpÏݘzƒYZûõPó ˆTFûª=BÎúìb°¯žž¹ö”-˜è¬e˜*´ŽgºêŠÞïu }–˜ºˆ(’Q×5¦&oÑW˜s22¥øN'Ù½#«Íkù=KZxm'΢ Í!4â æM½S{:ç:0m C`\3tǶPÊò°ÏÐËòåâ'¡T-8£ ö­BË0B”&¯û#ðà5"‡™³q „ñ2=KT¦7ö²q8:ú|¶ÚO-‘—TÔC/šÜÛл!ðû¡Úaµt?¿žÍÆ#Ô|'ÈÌ‘bÖöŠ4©uÛxiÖoš'ЪŒ!Ó¦‰(W|‡ÇÂ$!¿p”&Á®ÒsI7¦,ˆžÝoÖÆ“$#‘e°·YƒapÙ¸n$gû* Zÿr ó…Ÿ}<¡>Â_¼m£Ü89‹3×Ž"‚î °‡"oÜ[”‰¢pM'Çk§'x޳ñ„²ØIéëDèêô$Š Þ®¶Ê¥“êì¡×ïÖƒ±¦OŸÓ]u…~•Þz÷z–â¹ôÍl<‰é¢Y 9ЄHmâ_§i"8&,±84A£üîÄD­Í.60v„Bª4.¨íºÛ 6œÝƒ½/{w³½U Ak¨²úX,3&¬H[ +žXˆtäëíÒa\}ÞÒŒOß(ï¯ÝƒƒoÒöÞ?Ȱe»&…qB7&óíÕÎI¹\fjvŸ…<ü8Éng‚‚:͈,»Vsµ›ü?o–Ž«™®å í]Ÿô÷Rb?†pW»¡Ù• ³ˆ¢?y× G@<Î݃$Âwª,…æçÇyÚ݋㒀.iÖFYãï Ë€Ÿ›nÉÒÆ RÕA÷ê Í?¥s†ÀåîLóú,Úó­´<@¥7°Ê¨Šè”³¾^{Œg§)ò£WQI²X›Ý¢Fž7ttGR”Ä!„fÜѶ"@3<$2äd–}àÂ#07PŠüõ'¥Uù>¨Ï…f¸w´…ZˆjêãâVÇåµ(¯çâNñ}ÍD(⋼܇ð £1eR˜½Uc°Â2 É–YâÚãš¶¶@ÏJ<Ž D¹xH9%ŧã±òÕÔ,´]ɶq#ßÓÒ‚~+WB5<¤€÷Æi4½&Qaõ 6¶æ‘(˜fQRµgÃ\_F‡²"%µOñQ»9øÕûY¡[}„¶êx¨Øœ§ï~»†þ†¦Ç´—ww 8ÅY탵Π]tžûäß~òþ(ø2Ÿüä}öÿüSï³OÿçÞŸöÿd즭l¼º»ÆŠ16Ö44"¾¿0Öß½¨”xºB3¾4Þé7¾ç…ÙY$†›/ Õ¨ {ÌÂtR=ý×_sb[Àíw¢ÍÔ»ï´ÇáI;{9…ßé»Ú𤄅j:ùÕŸj01¿W{º½îòèàh?lxg}:ç[O»¼ƒš6„ïkuæNŸƒ#EøqxÎZ§ë( ©”²âØ<*Åx qã0êŽa½ˆÓ1±’“nZ¯wꨀ uñFàm£vøà||ƒì9•†AEp2 Éöx‰ $1‚Ó)æ8Ý^ÅÀ³†›¢ ^ùâ}¤I-¤ÕÃ¥0‘QüˆC:^&å—C¸Ò½¼=Æ…+E°ü o˜$Áö—© L™QRI{\FM&"WÉiT‚%Kn—j>»ÐŸNxÛN]`Ò]h=Ñ¥š,äd´üÃý§4_‹“ÒÈ"ÔųAcƒ%éԻܙNûn/‚'ësoK}^‰&>ÄŸ­öBr¬Jˆ`õòY”;hìÅ/P„£¥-iƒ`§|Σêt%iw„X1ŒðΈ¾ÐöÛôb]9[î¥Ø VauKOÓƒ¸»cÜÐq9æqLÌ«×s”³ØÅLp¨bä˃/·cb Ê—¬œý4Ñ,š€hãñª`C}¯Ù>ŠÐÄq{EõY¬”FsÜí]º%ÊȘ™C½P0éãÎ i2g±¾'@i)gešd26q2˜Kªæ¾/Ñï™GXÔ!hµ8Èe÷=øJ„ø·Üô@v³ÕÖè*ä%¢¡î,_!Wо«è!rØÀ¤dc=x¹;h|ʔ䉰‰©€ÇÉéd‹æÈEu6ô«5îªê v~TQwOhBfu¿;›ö»èäãâ†CŽŸky>ÃÀ‡zIÀ£I“Jë·¤ï–R+¥Š–P •)q ÓQM*IµÁj‚2 ¬K®s¶xA”È Ÿ?¦|˜è{ϵÎD!Óe¨òXùŽVq!Ô†—1žµp•è¯k¬Ô|5:“Àû2JŠ‘ +Ö^òÔÄ@Í*H®5î©ã×.F‘ÙUM€bð\\š@ž]OG)ÎÜðÛŸ [ÀÆ&$õÛo7@ yÎ6`Ý‹7ß”üŠÚYRz¼$iµ’ê2+æ¦OQO©cÝRN¤ßÑ–’ï¯ º‡Sdits—²9g°—Å‹þèbütU‰Ýƒ/÷’æY÷Ê»kN/]tï&ún<%sŠ·wÙ Šh"í¨Uì–¸wÆ êát'Ì­54’¿¨.‹AÂîþŸ¿ºÓÔlÀh”ÿúo±xêéßB…Ÿ¿%ÙTÔÊbFí«%¬7w‡ë=oÆ:[B¿F÷¨Ç‡6œkãï»íŠÉ•G}uŒÎ§ñ*:Œð9í®G ðõñ‘ #|Úú¬s™qŒúع²ð‰ª0dQ\Ñp‹áh¥«ÈÈ#X‚´òÜÄ‘¾{#ÖÒÆöÉsôÆåÖìîE=q¹yûÃÂDä貆zÜk5^–3":*gp‹Ð')xŸ¬ A«Š?ÈÔucðËß4†º¢jPcÂ`Õ[±ôU_0ÝSW´ŒÍ–|hG{'•œ;U‚:F}à^DF (`'åÜŒ§œr¶‘ê¢3.™cá†1÷Üú£Þúìf"“ª ÄJO_ÞŒL$´„zxrV²´ËòÆ?N¾ø'„/ ‹®Ýg¿ËÑ¿pp® úë³îí½Îz¯ÿv¶º¤ŒB؉@–Œ0Æsôu·Ý¯f³Éw_|1ò>ï âèažýÅÁÞÞ7Qq*˜Fñ£b'dTé û‹'ÍÁÞ7™aŸF›R¯ÇÔ\ôâÆn1úÉû… —>ß í¾Oá:=ò®'üuš Š_ˆ^^ãGkðxÍ`Ȫ.EßÄí±%wXÀþðz.]ƒœÒ¶ ˜ÚèvûùKËMåj<Å"‹¢w÷®’ºX,¦Sì°)©E=lÉ…ªŒ`tCeœfXuŒí€2¸·ed¨s˜Ï×bœ™ÐÀjK½^œ+SØJ¾äãE¾†Hr»Æ_IŸ_' Ÿ’2?þºýÊ—>k¿*Øiâ¸Û¯Š6Yôö«KKt¨—AÛ ëôO2$³`‰ÌÍ8Hhœ€m$ô¸ gŽ\éŠHs¡áQh†!ú8t4²èº(Gœ‚°”GóËFs¾¾R)³ó&öƒeP@½GV{jº&AHÓŠŸ$Hh:‘6TºÈ$ÛãIƤHzÏš4ëŸ6$5X4b½ysÃoÞø!«4!аq“)m@b±Åh Y>KÂ@ÖçÃIÍ:¡ãæÞM¼£ÍÿbøÁHÞ‹ŠK4Ì”K¾ÑóK¹ëç—7ðÿ6Æ‚j0ˆö¦wø”U°IAÓµá¨(ˆ£ä\êÔêâäM˜‰ãîµ²÷ô4ÆE§íd¥qzˆŽèà%gÔR»šç;¹;dÑ¿Ó&ÄÅâä´“¶ã•ªª£ÀžªJ\£ï™8®ÖOÅ"Á7´Œë6Ü¢¸3˜ØíÚqµ&÷ô×üs&¦<«ãC.ïÊ•ÁKõ¤>ß{Ój8aáW!!5±¶Ö@HŠ—}½œ5£dP’/Š˜‚ÒBr(äScìæpJ{¼Ë7Ú±×1ÓÈݽ }(CAc¿ç~Rìy˜>ÿ9E£aö¶3ˆ÷åâ¸êaܧ˜¶W Ã,ê[úLÕ·pçȰSG•ög»#IJ5Øœ§ÃmY6PƒAê1˜^æ,·5A ÔÂjÝCd’Ða :OH†fª0­p%äáÄz‚%”ÛAF±ðg<tú5§£<¤Ü^G Zx¨;Y B;_œ«½›MÏÎe{ÈS™ë‰l+{•@Ý•PP>ay ¨õ‹‹ö˜Öª;kÁS´ÔÅ 0E…r__SÓ‰c‘G+içÉ"†ÍÂç訑óQï ‹ÞÕøzÐ{`Ñ%³bµâhVá.|-¿g þåCk¾æ ¦Ø_=êÊ©{ˆú7o<¡´×¿ aÆIʶE;DJ¼=Ø!„(Û!ÄE"7 7@߸…?ÿ‡ÇÀ?-e¬~ òUµQX«8ã“DW ã1kÁâ³@¬1ñƒ7bJ¡áS*ïƒÂ'RÎÆÁçB>|"e >¥7ƒð÷Ü}Ï7à{¾)ˆzOÔ¤@Þó£}x÷DÚš»'r‚5øÅ0÷ütƒqOé‚àÞ”ye^+­¡í)¹=kÏ­ôÚsMÑÞÔÌèÒË–M>—0@ö”¾ïçA¬œm£á ƒwÜ{à±ôÞ1Сò¥m¸{dÖ=÷ÿÐ=7jå^Ù…¹: ߞǣ·çn±‘íù~ kÏ÷[˜öÜmОk°Ñìù¥|Pö\‹…coÌØ\tˆÂµùàëeð°ë¹á¸^d ?Ž{r²žGo¯^hÀê¹zTÏmÂÔªíI§à¨WEý¢>OFÔƒbžŠ]ÓÞ«bŒ¬‘`I»E9nÔ#Çð”ãÓãèi áêëF»VÞd(AÈ-ÕÛÎa©UEÃã5w*MûAü¹fˆ7¡… LÃXÂêõvé¨VN5mæw½üüyþ ï›±`Ç2n€˜Â•êµr•±ü*Aw6z`ÿ›=uyðõ^L.¿ÝËÿeŽÉ|xÒ¬Á3Ú"wÄÊ ‰¨™“ÓÖKXajõVã‡Ó¥êQ3ð™~÷§§_âŸ}ø;¸³´`°¬Mö×&ÑÉ>;ND'|±yIb´<žh)d$ö0ljöG]ž.Ã÷ßv¡ñü]¸£{¿ã˜Û4Úb¥„‹\ñgOÊ/Õ#Ìüêko÷×Þ¤X:—7‘ê’%F¸¾ID[ˆh  ÃyTƨN*Ð5.Óç2í×gÂ|j!ÚïK]„uÃÅõ}‚¶¹œ!†§‡$ð‡©wãGl€ðr¾í«T>Rßõ¶K‹é>ä«Dû"8§] Ãiw/å×%y 1x Ÿß™ŠB®ãN§xz|9ED RýúõzÖxß¿ìÃöéÍJ „’[! ^ˆD„è߯;=xØ,ç/µûÕ7¡ñ;Þ#½Zà÷Á:#½[IßR:©*@ÖòÞìÞù½AG.&ÃG¶Üã5á9ª+ø@?ßݼ$ukÒ…†„ËývŸ×ßÐïBvƒew÷¿ü&ÒéõZî°"¬ü4ŠvŒãá°³öýÓµ?=½÷] 01ô_ˆ.8Ù¹ñkâ¡Î6.?þä¯^«[v«½ÊßþùÓOþúoÿñôoŸ}úÉüõßžþíŸþó'Oÿc÷ÓŸàßÚO?­ÿÿùŸðÿÿÞ]Ï£,âìy« ~#r ³c±›„¢Ú3i{Á}»Ïö¾¹×½×»÷ù½Ÿ6<à69 _ÏÔií§§÷þã*ŠŸÿïþïë»| ß Úzrq>àîÞúÍp€šü.%¬y¼´†Ýƒo÷³b¡Í¦—Ð"@ÕeAÚ “OòÝvüŸ”›” õ®‡ÃÛµþM„Ü?fÓ´¿’è?R/þ)Û#¶Ó s¿dÑ–¡¾X’>h"zS±][<@Mx¾ÿN ¹´†mw.Ó¦¿pî%a i£æXWA'­}ñOIŒÁ¦rÖºWQ:D†zCÿx>ýâŸÒ8²å›´!qŽ_ƒ˜h^M« –hŒÂ„ùvï¯÷b÷þößdnl}¸A—Þ_üQŸíï…ÿÞâ‹ÊõGÝÁuÏ=UGgøF@ÁŠ«ÆC€‘~—X7>iÃTŒù蔄šÉpëHHлÝ*ýÞÀÐ*¨1Ü™rÇŠ^©Dú«»“ ,«mtæCKîÚÍÀÑæ)ÅžÊãü–;“"œÖ7¡HñT|±¶ŸŒÆB9YtÓúàíÕ¶»æU Ÿí ~fr<ƒ¤¹‚ÐU!GÉ`K`žÉ¹¤ÕQÑóþ¨‡5 î™ú“þ~:C’œUâ!† ¬5ã‰? eba›G3ÑÓ†í͆—‚7µ\â”Ì£=0 êiÀiׄ ŒÇÉŽ©ÆÈ‰Ì[S*ÌŸbZÖÝÈ)£)›œl¶Ç³Î í?áIt€ *}DÖ©‚ËLáÚ¬Ó¿‚ sqŒvø¦õ- 8êÔ¡òñ¡]+xÐÞâó´³²ªj%àXr¤L„Ѷ m¯PÔ¾ÛA}dü˜‘÷'Áµ‹^ÜWÈ´ý†2ŠõRªW¬`/q+îËs?ˆtâœDñš|!.bÇM/Mpå:™ó®êŸJ²‰EÖ¢´Ðž'ƒxV´NSvdÈ5…Ü!úÏ^u¢NØ`Û^%`dt_e”‚vD)׎U…±M;!zz¢£ò¼¤Ú&]r€‡¶’Xs/b¸;óÜJlU/D6~ÌaûŽ×Ò°oCÿ¿Ñï%…@rJTÕk_ê,!)O¯­ë³¸yÌ/î³èõ€/6çÇÅîþAlÖ•À|i¸*õÆS© ‹Æa§GÆŸ4£Qö¹¾¼NëHœ“• Yß¾,-sa Q8SÑqT-ic †hÇ[KÏØ¢MWáöu´Ì¼âl&=eí߯B7赆rÇý^Úy‡¬~Š>-8·ñ•ZöcøM Þ<-q9)’=žÉMV\ΓD—™rp™'º70Т“MÆu9íÛü\,ðr–ã.³ŒÛs¶m‰ƒ!LqóMè#µÚ†0¹K׎mëPwr’`ƒa™í9?xÜÿúï:5ÑŒšÍüü·=][]ÙOÿùíl§xÔßïÌ^ƒ‡ô<®\˜mæPìö“Êi–ݾ»ÿÍWIRH‰ãÊ}X©Û qSªBz@ZüY¤*4ư¨\I²kß7±]Õð¯§vnà'{Òhµj‡G"‹¼2ƒÈ‰¸º+„20ôŒ|0÷î^–r-ÃÏ„ò‡++ÎL(*·]ÁŠˆ€šr$NŽxÛ@©¿9N©Âmc£;ìyPÏ슠¼‚Z¡O:Èà ‡`[0” ÓnD™¬Ýð•yÕ§mÑz£Na6É‘3âWÚµ"þÖ\š…?íMÜ.¡êR_l ;Þ›.q¯éï™l"äu5p…É(ë5ÿœ…Îa¯º¡¿·ô÷ý½B7È.cg'ñÃ)t΄¨\®þâÂ@æTÇsɽ»£è5þ9[?¿ÒÄ}¡O$Ü1·r-È Àd8Ð=£ßìî¡(ÜK2Bn›ØÚ’#kÅ” —„ý¬¢ì2; ¬ô1ôê9hÁ…hö=7MÖ¨MU"­AP(™SÞorZÍÕåé<’X*šÒIÿ£ÐJ5»Ðæp€-"HKcÚå3lOœœiÊg8·êWÓMJªškâ‹9y¼ ®iA‰b^|H‡¬l÷Ù½UÊ‰ÎŒÚ ÝI‰†Žâ±–Ð6»½Ÿã}OAÈÄÏuÝ1’E\ˆ®„AEï4ãòåBç«úlÕ<QÇ8ru˜eÔWؤD_…œO³l˜¥§ïMš SÐá´Éægà§«A彈õ—2"¡Mm1"¿I0‘b;’tu*{íÓõìî…û¤ÈÅò*‡·µÊîÞŽ!x‡·šqÝÝKÍÄðˆ=D|Å”MÒîÚnhjžk6Uõ¿<:™öÇx‰´^¹ظ.Ü)F^‡ñš .Þ^EßþÌîÈ™’•™Ã¼·oŠgÈf{€RÛB}©åH¦çLôÑx ö1‹ë—n ·Lz…󻸥P hZ†*Ùü¾Ã«¾zr*áB±ÌÚÅ u1Š ¬cx‘¡ÅHxx©¾w¢ìØv÷Ò’’Ï4¼3QRõ¸Øs’®<çó¬Á&Æ=½MÆ ˜WTáxÅ€óf§žÄâ¢ñ51ŒÂúØ(|â{y(ä1PGIÞ¾ŠL.™*±m'NGâáäöГ`ª Ù «PœÚD;Bw ‘ðêüά,86➨§¾°:zBü«ŸzŸýîsDÎý¯>ý®þÿ?åä?Ó´{swçâdFóæ0éñd†hR*- :ÉX’üíêºv¾ùúÞŸRPÅÆ a·6úä*…§Ñ…ÊöD–ë}uq@~SŒ9ÁW´â¥öŸå}9%vþÌOÆt,`ôKFÆV/N ÅA£²Ÿb¾€¼‘Rx3ÁUmŒÃ k˜ÀAŠç Ç‘ëØ®!%QŒ*ŽÅv·P™1²ƒE÷øÉ>8lâˆÌQ€8ÁZ¬S×°£]”¤ i]­7´‹¾êA4@V‰Lä¦Vo•ÝHéuyå%UqWŽoºëã;ⳡ⣄¿€l:ÞÅ•T„£ãó¨vò¨¤ LÉ ‹Ú“Õó™ìÜ‘­Gû]‚FO÷îÀ¼ÂÀ°1€¶÷. »û_Üjrðiá·d‡')b,Ûħ»àݬSeAt"»•ÎÏãiÖ”ñ4Ìçcÿ æôðä;Å$dÛHêR[¯YìŒnëA Þ0lù@ s4«Ádà—T²{°ÿuˆ='î\I;ÿô‡KèЪ¯~¾sqÖ_ÝíIyK`Æx˜ð^4ĪÁß4#'·Ä6ÉI>™-€è׺"– ñÀÉb²ˆ4ø¤ÓŸbNŒñéQ/…m`—nÿ“w÷¿Œ  Ó¾™‘… ünªsâÿŸ·÷€âHö©™iJ= €Ñ!FŒ‚M6¶1‹ ³Übã³±½{ë[/62Ë.›`{ïöþGÎ9ç$rÎ"çœsÎ9ç¿çíìÝ»ïÿû}ZÁóVÕÛUÕÕ•ºzººê“¼ßámžûU¶.6ôLz謟g“¡¯d?oæM”ýðY('-Î#®×þÂ×þM‡ÞÊ3KÞ‰3†ü¼ù]¡Üggå û†–÷Ýa®‡ê-ÃB+è~ãnÑø«yö¯ÓÂÙ´µ~Fsy‹Ù²Yóâ¡·Ç/oÒ2?‹=ãëÆ šäì#š[²à 7ïïówõxçuÓK¯A^ù»Ú@…råÃdl!t3gÁê0{€Ô°Þwù¸áÄGÎÙ_ Ú/†[H×åüp)þËÏeÈ¿rB@Æ>ù½wÀÇy¶>Ë×IûõsW¹Ïxä)&ô!¶/R^Úä‹Tytyíô#:_|’žã;Çw‹eÙÿÙ“Ä™X&-1Çÿ[ÿ×þžœRÿkâòý&ý_œ$ü¹‰*þ‡¿wÂ×þ%µy¾o¸š˜“gÏ•PâJþ#Œl+ýüãÊWUjXöEek‘}Ðõj¢Jl”¿ô9kæ:}q«|üÌ${Ïž_vpùÔÃäÙlT&õ~÷My¨àjR>,ûÅm¸|JŸýõØËÞËUÊÈ¿_ßì_—qp&gY9¹_×ijhœm%rÝÅm9Oä!mTŽ6´Þdè©]¦†5löܯò¬ÙEl¹›qã5ìEDxt–黲~¼ír¶|IåìÙ`?Ý:G_z áìi«>Ì´0/ïdŇý\oÏ Îû Åë|V'«ÊuúO'Còξ†Ù“–g •ßp~°W¿µmrY…æ>Ž‹;ªñKã2ƈËã-'_ çQ:+L†Þð:免?Å•W2ß6h˜Q¿æïôwN~ËÛ´ÐÔAîÑ_†V6[5M‹ÿò Ýk/lû´G=Õkñ]#û»yû~ZáÙSACo˜Q9ëÛ9?k´úʆz•a-B {‰~{ îo¾Ê0sÞ^È[ÐVÙ¤Ütâ&J×7ÎŒìO>ª]« „}¿V!ï†ìW!9S:ð™= ³Þ7¸Šä=ä¤Ô‰ÙNJxã†Îéì­Vä$ï×’‹ãb7¥ÎgDÎzD ‰ª‰\¹£qÞÑ‹ÎY"QÞ×½n ¯âDó~-ÑØÕŠ^[ã,zGI6 ½z ]n†?E4núIƒoC¿åD0òÍýu+Ô ÊÛ®oò¯µç,¦(‹ü„Vt”ò ”“· ö´Òl‘¡E¦[5•i$öC½¦9G½ söóË]ôV&PižÛì½|Zä=Êþµ,'´a×áHg|è ‘¡¡‹Ì¿Ìhásªm¢“”zMþ|å{Øßʳ§¶~à,FýV&šþ3•ó~Òþ9Ý.'y?™ë*œ›g2äy'#'Û—77x„]¹³»†ïõ¾±g–t>á*ÖØ©î-›åy–}¶ü}ưQ}¯ñy‡šÎ;sgÆÈ»½à’ü.aÿL)¾bù6ÿnò9>÷V‘=qG>ÚÊY§2Tw\¾.úÜ#góáòË„½uL‹ìßíßxž‰g×ÜÛ½üSûUn输½=®ôiÙö(ûëþœw7ѵˆ±z‹Æ 𿍠çô4¡TÄü\šd+?^H¨"ß6ø‹m‘gûb‘º¡C95Ñ2¹Î‡5ë~ú^kY·ú'õ#DUãÓú¶#üÓeå:ïשõ^T‹—’É.(ô;¾¼qüà¥ümÍK¿ù‹¦ÞKï"sWÂ#Æœ-wþ-£y³èŒ_ä€=Ä^%Â^¤,´ÔŸ»e‹FKù:J7jÐü«2ÂóLƒ°7ì³kZËüþŒåýÆMþºå·Mò|­â mÕ\¿A£ð–ÍìüdV¸a´cT­ñqÙj²Bö[ú’ÿ(ž@…·Êyþ„NWýuýê–­æ©Qï½ßy¾jÖ𯺪XËV õñöÇ>õðaTýžýÂØÖ×­S¶šúÈž»•}J÷{u>Ó2¡žªÕ‰ù××z¿`ýê×®U¿à—_5iÐô/«r‡ç7è ]õ“ªX¶Z¤ýñkö;çâ¿y¯ñ7ö{c»wê¢Gâõˆÿ‚Uë|P»l5÷'×4ì-8 þºVÚ¿®oT¯[§ö‡9›TØÓørFᑹ øËWVòe ½G¼X>kÐ$²ª,§ìl¨^¶š·n­÷ë@²ë|þ±ÄíØ Öùð½ZÖ×ukU—:•½8bh8R¿zOê×ûè“ 4§%E9]öžªŸrñU눨Q¶š®ú~½9¡çýê5ky>©óoµÜÍ}¥Ê5ëÕ­÷±þM­eõ!U¾qþoË'ÙŸ¿_ÄË'3¿|J‘£¿³o#ùø4ö^ãr»è¿æãÏq­rAyå¡•ÿ—ãò•³ß–Ùù8ûTeœ7Uê„ÖÔ¡ólI¢›Ë:ÙŸ6oìÔ>ù…³~ž]ÊCÛL8¿ØSKÿ*Ÿ*9]HÝ"yfž:ƘΩšf´t}ýM¸ý¡‡ÓZ å™/îWšÛ[ØeÏòÍ3|É^âÐÙôÌžÏr¸¿mÔÜûéÇu?Îø¾·Å‚öUQ­ÌŒ¦_sÇúôã:‘Mü ceÔo†¿üúm ZË"_$ ½±‘!RÎ`%ûÅM>þhâüzùË–õ]¾¿h¡+Ï;*û.?s4û‡Íœ5çógY¹ì}Üs6^¯g'Õ"_Ä ™» Fã|\X2ÏM1_VqqÞr×ÎÍë›ÿõS\2vº {ªj‹ˆÐ&…ö(=úg>o¼ùŸù¿ÌÑ?\ø©˜ó ìø’/ä7«BÙ«÷Õª[KÖ«s•K+ï¬Ñ’ü}>¾Óþ;Ë«Ëó­3ßÏþx©ÙwæÍ~h,ë}Õè%ŸQ/,漜~Yù]ÞÍ=²U ½ñˆýi¯Z9¿3CÛÙ¹Õ™+ƒÒùô¢N={©Ý JÒ2š{C>*ZнnŽÆ›kõÔû¨Ö‡a5ë}ðQÝZõk…Õ©÷e­?®÷q¬ý(ôžìj3ÓY²2PN•õHäÅ_Z|>û½¿ù-PòÑÔû]ã¯[:7÷×M䣕fAÿù˜L~£úçìH]7{3˜üý¢kûÙyœ5ëG=n%öR`Ù‹üíŸ5‡¸éßÛèõõP¡âëMòõ똺ζ4²-‚óXõK] |ù×ÿß÷ 3¾jÕèm£5ÏŸ¹Üy‡ö’e¿x^Œýzž#Ë7ȧùB2›Ã™_ú<æCgRnDÎdYùþK^$q7ª‘ÑÈ™Z`O0 }T#Ój¿<¿ÅþF¦y«¦/ÿfc:e·O§mK H{-€ì4ᡪ K{˪Uöäh̼“lBjÇŘ XHñÒÜœ‚ 3šÈ‰B²›GÎú|öÚ{9Weïm“sÖ¢Xê4­ù’.L´”uiì7Sö·€yò-Pá× ¾[K¼˜-h>_ÿ ŸÚùÊåW*XÈ^ã®VÎâáÍCàʲaöLpgz„óñ’3†÷Ê»iÇOÔW²/M’Û*4§Ì‰­HË&ß|ú’¦ÐwÙÓ£BKÉÕÚŸ9Ÿ²srÓù›¶÷Bjø“ùu³æÎ»ãÈæ-šäÎ»Š }“š9bO4¨÷(th—SÆ£ÎBö„9–=Çë¬í`_†}«ÍÙKÉlöÕŸ_çSK~O$ ’MñÐÖáÎóŠü2%1ù>l–àL˜O >&4©þ³ÜU¬ÞRfµÌh˜à|Åßêë– Í¾IMsOÈs»HhÑê+û-o Nè À·ÔÍæ -9ÁËËÉ•©Ñ aB¨÷—å­­œ@ô< %Ä·?}Û${èR¹^+Û›]gìì/¿ø2¿ùËߨW¤g'¯i3;†ΩZþ©AË™Ÿðuƒ¦ _e$8/“ññŠXbw¾³ÚŸ¼–úŸ.Ì.gK®*; -r¿VxW„dp³¦Mþš kŒ9ii‘ýq6n.ò~¨'‚Š9çÎþÔ ONå Ó<÷«„äì0v[Ú§ÿåIKg?¶ÚÙo •ðŸåÿ+¬i–'ÓSê4‘Õ¤›$4pj„œWVzmÕÒ)·œ»kàÓ¦Ù›Àç°xø±1ÙÝTNOj­<žšf¯ß)ÞŠ~Úô/M›ýØ4oдœo툤<¾“äƒxɲ¯åÿ+â[²–æŸÑ°~ƒFE>Èv$´lÐHÂÊ9ìÌ5*–ëã[[!žŠÑ²§ÊUÚËc—¯•ÜfM3xrJR?Ã(I"šÿ!ÄÏw= …ð…¾Ý²¯’ìoÕ´…³#{FâyìÙåûRÁ½ì?GjµEA2ì Õ"ôÅŽDžx½9m£E±_ø ¼UÙÓ y£®/þÓõŹO·ë>=h‚ûôÀÑ0Æ}zx?Üݧ۴+R7w­"çÖ¢ê¨ÏÔoU]US½§>P?¨oþ”¿¿“åžÝÃ(´t\èµµ¬‘äX=².‰aOÇ5ì•f£ZØ_OËx¶9ÅÅ¿Î^P#o«×þœ¯?¹{’’üÿÎÿ¡~ñÛiÞ±²Lƒªž½ƒ˜³Ëh²w³5òù‡ƒìŸ òiMçk6iú¤‰›`«ö6¤ß¼´ž)ƒ&ç³µìÙØ„ËÉ©Ÿï?â¬a‘£‘©Ýƒ…(ç ŸØk¹0Ì{ö@…7+Ë* 0ÈÈ \¢ñ·yw>ûŠîˆŽ¨¡› Ù›cÊoI‘ÎOJõ­0‹8®¹ë1æNÊ y)š£p|ÙkÈ Â¾6Éï)hÎoÎÓA7³*âµèÏ*¿Ñ8—½«iï^˜]Å 9›æ¬ñVäåÃÊoÍþÎ/Ï~¯Ñöò*/,š³âŠ]hö Íb/뜗‚‘öмÙ[ØÎu9E•«Ò)”ëÌÝÕÚ¾¹ÍFå¤Ãyšã¬Ýà»Ücö•Îsy<ç—ç–žŸ>’]¯Eðò[¿ó9¿ñy¸<…×úK¾öP­Zæ÷ú‡¹›º¾—³ýª¼°ÿùo^ò•+þ9_— zétá¡–"sÃcB[À5þ YTø=ç-s ÙAW~ÞqnKÞ÷ê¼ÿ~­k}X³V„ýuLC¢lüM£FùôR5çƒÐÐ{Õ¢?WÞª”ÏKÛon}ó8_Ì/Uòo•Ï·w×yÖÆÎ—ï s¾ñþYo#ƒšŸ¾•é¿mðSáÜA°ÓuE†V2qgDÈe7ñâò¢á'y»Ò¸eÎï‘4òˆë¯4ø©`3{o[OFÃFÆO2¿Ù-£Ãü{óVçï~4k/¹‘/ËØæÜ}r–<ÊóûTá<û­Ëà°E˜(Ä“ý…VçWW¤·q¾­Ã3\½ô,èL /øÓ72Ù×Ýâ»FìÅïì‘©ó…³=1_>¡ }=$S÷ ׯù»¼#ðò-ò+Ñynh?gûϛÞ§­ÐFÎv™õs7¶*Ö$Û–gqrO úTÃ^]ÙUç½wª–zíµ2iï¼öZµ¿Uýâ”Dì‰ "ƒûýª%ÿ==5C¥þÁW‹FïUMù¢ì;©)_ü˜žš’òN•/Z¤cµ-i¿’¥‘Þ©òRØ/~ü¢ aSßIMKµWN"p5léN ¹áþ~(WUu‚µ=2ÑÞ#S½½¹ÓÌÕ§ª†úÄõi]W½º®ºuŒšu«òIq™æZ“.÷CŸÂö¯?yv³‹lÜ0+ª…½ AöÂçQ-ü`¯wZ_³FÝz5ãL]w–uÖW#è›öxöO:ò#_󳟜øåŽ&»95¶'°7p”r>úpÇÛ/&ý¯qÊÙT;Ž¢Íí/à2dÖUöÒÛ‘!³ C¸³ÿ ÝœL{©Xû§@±9¿ŠÍù¥Ør~_Γ&»Ë”/"YÒ0o"¼ s¦„_¶ÈhòMXö$7ï_œzeÿ/©€²#˜”ñkû"=5ŠÄ|˜»¢×^]Ñvé–Í~ûAÝ@9iñö¸ÒvÄ"ïî– ¶7§õKe…ÔÆÍ£PÈG]!'㶦²!·<˜¡…4W¿ ËŽH‰DVÄÙÆ‹Ë©åŒ÷>ýàƒß©j®ªe#Bßçµ°Wÿøé[{]æ?åÓ0ãCgÖ6m54¬È]M•ëÉ^rJ¾à”ÎòófÍC_sþÔ2djiÏYÏ^°LXÍ»€YTãׯ›3n-›jÿÔ ™ýò¦Pè«Ò·|ácÂée¸o:ëËÉ ±öbº9.;®Âö¢ñµs#³×†_­¥å›´l u–KèÂ?;×o£rÙϹN;Mó\RQçcû@ö㽞î˪8™.Û¬‘¬¸—»ÔaÎÍöÇ_Ù1jI#ÊÂrš¼¹W°=ÃÓÎïÐZÒ…i¸Ä÷91É3ÍË |È€/ùxIa?˜:[p¼Ÿ½†Ÿ7¯,ŠQ¬¡¸BÚu§'FŸcbÊÆ¼ó/1ÿÓEÅôR1}UÌbWÌWÌV—ÑÕSâœ'¦“ƒ\`ļ0bö4fyEb&ÅëKÄz%lAɰka§KZãŒÎqa­½Öì8cv\‰²Öæ8csœu:Î8v!κg\Œ³®ÆW㬇.ã¡+ìyœõ"ÎxgõŠ7zÅ[ÝÖŠxkU¼±*>lm¼µ3ÞÚoí·Ö3ֳLJã­ãñÖÉø°SñÖÙxãl¼µËoô[ÇüÖq¿uÆvÑo]÷×ýV›£M‚Õ!Áê”`tJë•Ö/Á` H°%‹¬u ƺkkBØö„°= F÷RVÏRVïRFïRaó­­‰ÆÖDko¢±7Ñ:h]M4®%Z7­›‰ÆÍDën¢q7Ñzžh`m „m X;ÆŽ€u,` 'ÖÙ€q–P%Œ %¬~ÉF¿dkrrØÜdkA²± ÙZ™l¬L¶Ö'ë“­ÍÉÖ–dcK²u0Ù8˜lL¶Î'ç“­«ÉÆÕdkIicIikGikgicWikOicOikiciëiiƒÿmƒVû Ñ>hu ƒV· Ñ=Ö3h ƒÖˆ 1"h Zc‚VfÐÈ Z“‚Æä 55hMÓƒÖ‚ ± h- ˂֊ ±"h­ ë‚Ö¦ ±)hmÛƒÖÞ µ?v h‡ƒaǃ1ä̹ u1h] W‚ÖÍ q3hÝZw‚Æ õ(h= O‚Vë£uŠÕ)ÅêœbõH1z¤X½S¬¾)V¿k@Šu½˜q½˜õ¨˜5<Å‘bJ±Æ¤cR¬ )Æ„kqе=ÅÚ™bìL±v§X{RŒ=)Ö‘ãHŠu>%ìbŠu5ŸšbÝN1n§X÷RŒ{)Ö‹ãEŠÕ.Õh—juKµº§Z=S­Þ©FïT«_ªÑ/ÕZšj,MµV¤+R­Õ©ÖšTcMªµ)ÕØ”jmMµ¶§ÛS­Ý©ÖžTk_ªµ?ÕØŸjNµN¦Z§SÓ©ÖÙTë|ªq>Õº–jÝH5n¤ZwR;©V4«gšÕ'Íê—fôK³†¤CÒ†¦YSÒ¬iiÆ´4kvš5'ÍšŸfe¥YiÖ¢4kIš±$ÍjûJ̲4kEšµ2ÍZ•f­O Û˜fíJ3v¥Y{ÒŒ=iÖ4ã@šu8Í8œfK3Ž¥YÓ¬KiÆ¥4ëyšñœÒ­véF»tk`º5(Ý”nH·F¥[£Ó þO·æ¥[ Ó…éÖªtcUºµ:ÝZ›n¬M·6¤Ò­-éÿw¦[»ÓÝéÖ¾tkºu0Ý:”nJ·Î¦û6ÇùhãÇý¾ ¾éƒÿ[Ʊ€A-ê›b<*fPv«SEiFÛWŒ•iƪ4ãbš10ÝXî#’³éa+̘Ñc²*k*ú:ÇùÄl®h®è£{êS©½Û„J>:§iî‹]>z ncs¥ –½•|ôC_÷÷güÆý×}Èç¯ûèNºT66UöÑ‹«\â?}ë|‡ã}kŠ•è¢|t›M}Çã7}ô§o•HðaÞHôñ¿}’ï¢×˜ùV‰·|ô[#|ô7ÞòÑIÜ}ËGÇðì-½B—€ÑµŠ9°Š¯w Ä䀱±J‰…íþHíþV9Ñúmí~üÛ>²äp”æÞ®ªæ>½ªoK²<ëW¾%¥}ûKûv–öí(mt úø?0è£]©æË ú–}SƒÆæj>ÚÖÁj>ÚÓ‘j>ÚÓùj>ÓÓj>ZRÿw|dvæ;>ZÌÂw|ŠùÈõ%Å}4”ÅXÞõ!¾ëÛ“öø]£uõ˜6Õ}4”ž©Æê>äÊê>ªÿêê¾¥©>Êêpª±£ºy z‰ñQÇX%&Åø¨Êkø²Ò|ôÝkø(Ñn5|TÓq5|íé>J÷Z Ü«¦º8¬¦’YÓGu\PÓG-\^ÓGÁ¯¬é”î£Î¯éÛîÛþ“ò¨‚*\Q† S.µI©W”Û¯2݉~OÜ÷D÷$wx)åñgº§¸¦Ú oÀ¯"“¦¹§»3Ý=p«ÈðÒ‘~%Žéîîä™â§B¸_•ŸåžŸ9¸Í¹n5Ï=gÅ&Ú[Ye9Š×ºm•öÖŒRáþ=ÑÍETx/7ÑÔ^dG³ØÝS"^âöZêVE2Ý¿^&©ûH^î.R(Óí¯·BÜõIH!ÿJw‘Oz»E¡ E|VÄ_H­"ŠOW»eÄo•ö¯q¯E÷ù:÷z÷‰Y}ñåÂüÑm’p_x¿"ªÍîðÙnƒ-uCåß*ÎL÷×ÛÜ¢ñnwg¨n÷NTþ](ÂT£ÝØÿ´Ç-.Õ(\…ù‹/Q~·×½OTÅÃ[©ýn〄hyMaïÏ?ú uÈ-Š»m/á¿P©ÿÁ%dºp=º„ˆÖJsk¹,ÿÏV¶Sø»sì†=°öÁ~8á†#pŽÁq8'áTIswÛ’×àLI]ò,œƒóp.Â%¸ Wà*\ƒ.]rŒO—¼ŽýÜ„[pîÀ]¸÷á<„Gðž@_Â?Å|Ïá´ŽÓ%Û@[hí¡tŒÓžNq:¾ t…nÐzÂPŽï…ÙúÄ鸾Ðúã§y£ÈE^)òJ‘ŸŠ|Pä"Ÿy¤ÈEž(òÄ?0NûÁ`Â!<ù7“¯«Нŧޢ;F'âuõÓñ:üL¼®qŽpç1yt ˜á\†+ñºæU¸†ý:Ü€›p nø ÷ðsÀCx„î1<§ð žÃ hí×5Ú@[hí¡t„Nиžš]0)û]1»Awè=¡ô†>ÐúAa_׌9Dâ‚a0FÀH£ýÔ̱øÍÄ>sÌýpÁa8â×QGýæ&åO™×>á×µOÂ)8 äEmò¢6ùP›k­M:jsþÚ¤¥6×W›k¯MšksÝþ‹í?‹y–úv›‘×9â?üºÎ%¸ Wà*<Ðúš_ÿæÜ„[pîÀ]¸÷á<„GÄóžÀS¿þ—gð^øµn ?h íèÉ m´OÐE:&è:C芾tOÐ~îŒþØ{&èí èÿý¿Š»áú&˜}ýqÿ] JП †!0”p„QøûddžcŽ€‘0 ýhÌ1˜c!ÆÁx˜aL†)0¦ÁtÒ4ƒp3ă9Ä=ý<˜ Ðe‘¶… fßþl1áHß§œó³%Ø—Â2X+`%¬‚Õ°&Aëµ ú·ë1¯ÆèßnÀ¾6ql3º- :l[‚þ·°vÁîýû½°öÃ8‡à0£pLì~ýûã˜'à$œ‚ÓpÎÂêú÷ç0ÏÃNŸþýÌ‹p .ø ×ä<ÄuóÜ„[@½ýýmÌ;pîAï"ú÷÷1ÀCxá <…gð^@ëRú÷m -d…ëß·Ãl #t‚ÎкB·Rú‹<üô‚¡‘憹-¡ þ²O)ý%]Í—t•_öÅÞú—ÒØT\9û@ƒa …a0FÀHÜÈ¿äFþåhìc`,d¸RÚ?&`Ÿ“`r)]t 瘊}L‡0³0g‹.Z9“æáŸ‹~Éž¹3 Â~/·t‹a  ûrÌåQ –°¯ÄÞ'ZûWa_ kp¯Å\ëaçØˆ¹ 6sì¸W¹s+úmè¶ÃØ »`700ùrÇ÷Â>ØsóÆÏÜG±ƒãpN¢?§á œ…sèÏÃìá\†+äÏUÌkÄsã7°ß„[¸ocÞ»pc÷ÑQÍÕ\QÍÕüË{(iePüó1<ÁïSxωÿfëDý‡6‰ÚßXûXûÛao #t‚ÎкB7è=õ—=1{GoÌû…µ¿f_ôý ? àØ@˜æÕ„9†ÀPÃaaFbŽJ¤+'ý4MEÓT4MEÓT4MEÓT4MEÓT4KE³T4KE³T4KE³Tg¥k(A÷Œy^òƒÁ-ÍRÑ,ÍRÑ,ÍRÑ,ÍRÑ$MRÑ$MRÑÍQÑÕ=é‹0pƤ9*š£¢9*š£¢9*š£¢9*š£¢9*š£¢9ª¶R?Ãé®1iŽŠæ¨hŽŠæ¨hŽŠæ¨hŽŠæ¨Fs½c`,ù”‰I×ä‡9&@ÛnÉä ·Ü/'aN†)0¦Át˜3Å̆90æ%ê?ÒþH[øãì< ü1 “úðÇ…˜‹`1,¥â–à X «`5¬µ°ÖÃqçFLç¤.ÿqö͉:|K¢þj[¢nÀ0¦ÁvLÌïà:§§HGƒ° ;aaq+âV» ¿'Ñ<ÊíÚOÔp_¢n¸=çQ€ëðäºa'ÍŠ4+ÒÜð°Ò­H·"ÝŠt+Ò­¸^EúR'¿>BØ£pLê¶W7§0÷³DÝôöÖIºx›$íÇîj—¤¿§¿þž>ú{úèï;àî 3túêï鳿§¯þž>û{úéïé§¿§l¾çöÿ}WütƒîÐzB/èÍ9ú@_臻?P®ßHâÁ`Ca0$üžáÒ÷ñ€‘0 FvL’þn,dbGœãaö‰0 &ÃüNE? ût˜}&æ,˜ s8>Ý<ìó1`roø> “{É÷³ä¾À9ÁbXKAúÑÒf¼ÚOyø)?åá§<ü”‡¸ô}RˆE’n± Vàt‹µ˜ë’t« °6qî­Ü_6cn;ºm„Ý;`'ì‚ݰ'ÉÜaè÷a'^E¼Š8q+âUÄ[b’Ö“ô†#pŽAŸ8ýÇ9vûIüf×úT’þÛ8‹û^„6Îþ~.%éÖꊈ«"®‰¸.ↈ›øžK/‡ÉUÝNÒEî$é6Š'Â6êžØî'évê¡FTªƒX8;%ãÓG{,š'"žŠXÍ£Ù˜"ºÐó$óN’GwT­ˆ6-QJŒ¡Ñ6 ÝíÚèÐÑ1»twÕO½º—ê#¢¯ˆ~"ú‹ b ÞtO58÷¶úµŒ Ca5 s8Œ€‘0 FÃ97d–©˜ãaL„IÝGM è¾jZ@÷S3DÈOT396 fØ+æa™ + û«E=P-±TÄ2ËE¬±RÄ*«Üoɲ5âXËu¬ èÁjÑl èAj“¸6£ÞÐCÕv Ô‡Ê~(Cws2Côኆ9\í ©‹¯aj—ˆÝ"öˆØ+â¾Ø'¶ý"p’ƒb9Ð…‹å–£=BÂŒ0þãpB»Ep|”bЃç”ä‹ ~¨Ú¤ ÚŠh—BRì¥hÿ¾bT8Ü]¡[ŠÖÝSôSÕÇ¡bÚè•¢£û¤èrÊèþ)º­k ˆA"ãg MÑžaÐÓ¥;¸FÃèÝÙ5V…ÚÙEÑÙ•)ÎqøŸ¢»º&Š˜ÄÉ'Ø ÓÄí×]\ryÓqÌÀûL˜³aÌ…yz>@,„E)ºÈ8Z7£/ÿ¹,LÆZþ¥Ø—ÁrX+a¬†5°ÖÁzØal†-°•lÚF.ìHÑ=]»8{Û¢º—$±k¯œöñ‚Ã)ºŸë¨ˆc"ާè¾Be\B4'ñtJ,§±œ‘Ô•$u°VÃJ8Kžžãª.¤è®K".§èWRô ×5×EÜ E7áVŠâj#¢­)ä;ÅÝ=Ìu_Ä;bÅöHÄc *‡¹žˆM ô)<ã4ÏSôWëTD›Tú†”m1ÛC蘪G¹:‰è,¢K*Ï ]Sõ¹ÊþªGªÖ½Rõ8'ã\4Äq®«"®‰¸.⦈>DÔ7UO\ýÅ6@Ä@ƒDL-,¶!"è('¸†Šm˜ˆá"F¤rë…Qâe Œ…LQŒããa‚8&Š˜$b²ˆ)öð9M,3JPçpÌÀ÷L˜³åÀsEÌ1_ÄY"ŠXD¸Å°$U—˜äZ–ŠxX!Y+ ]byªžâ¢ÛœâÚžˆXIô«RÉ«¬Âzºkm*bˆõ"6SõLi93]›Sµ±%UGoKÕs\;·3U»w¥êyr*co*cOŸy!Å£³\RñBEQÔ˜®C$ëHª^h·©£8ŽÁq)®©ºÄ©T½ÄÅPl‰¤,ú §=—ª—».ˆ é.w]´m"¤é^&æ+œïjª.x=ÕüK¯rõ·7S·8ºŽʰ 6ÃVØÛ`;ì€õñx¾ª×¸ú•BÜÛ=÷E<ñPÄ#E<ñTÄ3ÏE¼àl­Ó´jmÓûa¶OãC€5®2 WGDtÆS±tÅÒ-M{º¢Wš6z§iÝ7Mo”j¸ÑÅc£‹¡ÓFWÑ !o¡â{ NÓ›]ܶ¸VyÃÒÃEŒ1RÄ(£EŒ1VD¦ˆc%ÇEœ1NtãEL1QÄÙÂ:Á-®I$m2I›š¦·»¦‹à.·Ý5Cl4ÙíÒ«SŒñfâq×4xtÏ#Ђ4½GjÏ©=á Ót¡Åiz¿TFÏÒ4}е#•íŒë Ø‰ Ÿ’‡¼s®>qˆ#dr_ž`Ž’¢U^sCš©/¸Ž§!²â'ÄvRõö‚ë¾G‰þ´¨Îˆ8+âz.Aqê¼(–R†\‰âBס¸ E²‹\HÓ—]—E܉G\ÛU×D\qCÄÀRˆA"nŠó–ˆÛv0wEÜq_ÄE<â4¹’'ð”\z–¦¯º^ˆ8ÊÃ{ëtÞ&Ýdxõ WûtDEtÑÅèlÛDtÑMDw[':ÝDô]O½DôÑGD_$ª~é<Õ¤ó&]ß—2ºïâ1ï¾k¬83EŒK×\Ä6QÄ$¸1JD“ 8¦Šr–é0fÂ,˜ s$‚¹XæÃÈJ×]‹D,N{[õ,ʸõRXËaEºŽ^™®ŸÊ-ò©Ü"ŸÊ-²ÐŸ~最‘ K¬I×/\ëð½>]·vKÓØ˜®Û¸7qU›Óu;÷VÛDÈl†íxÜ‘®Û»w¥ëŽî\ÁqíѶ$â@º9'ÙÃh ]ws/N@ÛQÂÍãéy~²îêæ´]Ý#åeI:–,ñ´BT+EÝ,±Í1FÄ ÑqJÄét ãLºŽ?çá\¤”/q–Ëé:p®â>íÒ=Ü+D\ÃunÀM¸…ÏÛéúµ;éºÂ]¸÷Ñ?™ð0]W~ñ÷D²5œæ hó*ƒPh tnÐzAo®ÙçU]³/ô{U÷t÷Ñ“Œðªî列A0†½ªë€‘0êUÝÛ=å3™G)ޱ8®ãÈÄãa‚˜øªþlŽÉ0ûT˜Ó¡MAýÙŒWu¡Ç†þl&îY0æÀ\üσù°²`!,‚Ű–¾ª¿\ö*4̰Ý*ÌÕèÖ¼ª®…u¯êï×iðoÀÜ›`3lA·¶ÁvØ;aì†=°öÁ~ü þƒpÃ8 Çà8œ€“p NÃ8 çà<\€‹p .ø ×$óàÜ„[pîÀ]Ø/-îa¿à!<‚ÇðžJiÀsx­_£@[hí¡t„Nк@WèÝ¡ô„^Ðú@_è÷šnŀɿ%V·êÿu÷@ôƒ0cA7sæp#aŒ†102aÜkúÇñ@|ja&Âd˜ Óa&̆¹0²`,e°VÁCw€¹‘x7cn…í°vÁnô{`/ìƒýpÂ!ކ#pî’žc˜ÇᜄSpÎÀÙ×t/uËy¸ ‰ˆ¤ %á˜W0¯Â5¸7à&Ü’@·9Û9ÜÅtBÜM÷q?ñPÄ#E<ñTij×t_7cÄ~îç¯!^ˆh]ÑFD[íD´ÑADGÊhç2Z~™V]0y–®ºbé÷i¢ûäÈïÜÝËèþî"&ñÁ#—âQLñX¦xS+äæ_FgªÞ"úˆèKìý ? €0ˆˆÃPì‡]z–¢­ÍRÃË Fˆ)b”ˆÑøSFg©±"2EŒ1^ÄEL1¿SÄ2Ë4˜.ŽXfŠe–ˆÙ"战‹~̇ a,†%°´Œüü&by½R­@E§¦V’ô ô¥«$³`M½[­1‹:±ÍzñËèîMX6ÃØZFQÛÊècöDÐíhÎdæNØ%¥{`/ìƒýp¡2ú¢¢\T‡IÊqIk:Ê¡cpNpà$œÂ~óæy¸€ýb}G]qYĬbˆÒ«püÜ€[eô@÷wEÜq_ÄE<"ªÇby"â)®gbyŽå…XZ—Õþ6eu[W[,í }Y=Èý¤¢ƒØ:Šù«ÊÒ«@è ÝðÛð¸Ü³'ô‚ÞÐúB?üõ‡0¡Œ9s(æ0Ìá0F¨²z°{´ˆ1euWר²ÚÌ,˰¢k \ãD5^ļN„I]‚öOÆœ4¿¼¾™JÔÓ`Ì‚90ÀBX KÅävºs¬u°6ÁØ;`ì}pÁ8'àœsp.ÁÒs ®Ã ¸ ·Ð߆»pÂcxÏà´)G-¢ãkÙ:CèZާÝn"º‹è)¢·ˆ¾"ú‹(bp9í7 ²s˜(‡Áˆrzˆ{¤ˆQ"6•@ŒÛcEdâmL€I0¦Á ˜s`,€,XK`¬€•åx¾S‚v†c-¬‡° 6ÃVØ;a7ì•‹…ƒpŽÂq8 §Êé¡î3"ð¤uV,çPŸ‡ \×Årz˜ûŽËb¹"⪈k"®£¿7á܆;pîÁ}xáQ9=Üý˱<ÅòL,ϱ¼Këòˆ‘¯ÐJÊk[q´ÃÒ:@Çòz„»Syê(ƒˆÎâè‚¶«Xºaé=`á{bö‚ÞÐúB?è` ‚Á0†Â0#`$Œ‚Ñ0ÆB&Œƒñ0&Â$˜ S`*Lƒé0fÂ,˜ ÛHÓ̹0¯<·cÈ‚E°Ý2XŽ}¬„U0ÍGá–×#Ýkp¬…u°6ÀFØL ­9l— ‡èwÁîòz”{ˆûD³Í>8‡à…ãpNAÅY´í>‡ã<\$ºËp®Â5¸7à¦\¥p óE¬ö߯¼wá܇ð‚úa>†'ðžÁs ËyZW %BÛ <´«@yãè¡t†.е‚ãî&¢»ˆxí é{aÒau÷®€è#¢/!ú‰¥?–0áo0 ‘CE C;FÀHÅÑјc`,dÂ8`"L‚É0E"˜*bšˆé"fˆ˜)b–ˆÙôe5§‚>èšK€ Wžò<±û.Ø]Agº÷`Ù ‡à0ÌRÚ<ŽyNÂ)8]A›Cy8}Hou÷Y8*hïEÌKt¢Ì?|†ýy]¬uE²®¢.Ö³3ô†¾Ðà'«‚çSQͬ¨GÁ8ÏÁ¹Œ'`N„I0¦ÑTÌi0fÀL˜³aÌ—ˆ+êñî…XÁbq,Á²–Uä:/Ç!V‰muÅXîOŠ˜â¨tëð°6TÔ“Ý[°l?Û±ì€âØe쇢8X16B'*f®ˆ‹0‹@u’+8ý]:ñ4æY…y.Âe²è2æYØWášÄÕ¾’ÙÝG::W¢@Oè½+ÅR\}± ¡0¬’¹).JOww­„¸êBŒ©[ˆ\ªdžâ@¦{F%sQQeÎõyÌû.e¾¡b)´E]]ÉávÇáê*™»"£ÍåñѱE ±¿’y #Ãx:R ÅÑJæÊøh³wQÃÜo˜{àoÅÌCñÅÌcp"žaçuüÞ€‡•b‹S ¸ú¾®Í~¯3€Ž¥µ¹s2§^й F&æ]Iæ™x·ÙÍcõǘk<1±%Ì-%¹‡ÜyÝÜáqÇZæ,Ãc^ó3['3Û'fgã³c‚‡Àí*ÇúÌ®•}æ“">sHÀgvÇÞv%ùt¡±º\hpe¼­LVÁpqŒ¨L©Ž¬¬ ²¬Ð˜Êº@)s|e{T6'Ål…ú¾¢ ݪdŽ6b‰¾$Ñ—Œ-IÖ”,« Tá¬%uæÂ¹*)Î\K·$£ˆ9Ѹ O^ÑÝ—ü±ñ܉(ºÑoÐlaL„É0¦Ât˜3ă90æÁy¢[€™‹S)Ã7Ì¥å{ÜKÞà4½*"®T@,ç2Ë9ØñUs£)?‹‚&¹Ñ=_Ä7¢giê4~v¾¡‹íÆ<à\~ƒüØ‘dÎLŽ7§$Çko·7y¦xåJfWUÐìQÊ›@qA¢›[é›±¥Ì>Ñ´ùçx|ñ¦¹¯¤Ìé|KÏv/JDtÛâ ˆ6bãGt‰˜íð†ˆ6÷$ºcÍþo$š]ßJ4÷%$šÓ“͉‰f/ÜW*%š—ü‰æeXåM4ï˜ÞØ$Ž$™W£Ìë‰<õœ"ŸNWŽM6;z š—¼¥Í™0Ú$•6¿bRƒ‚Úœû¹ óßÒæÌ,Xˆ}æbXKaºå°ûJX«a ¬E¿s#æ&Ì͘[0·bnÃÜŽ¹s'ì‚ݰö¢ß‡¹ÀÁ·bSÌý )æ!xá <…gð^@›R)fVxŠÙ³ìCwÂa8Gá˜Øý)æqÌpNÁi8gau‰óæyØéK1/`^„Kp®ÀU¸&ç ®ë˜7à&Ü‚%SÌÛ˜wà.܃ÞERÌû˜à!´&m¡´‡Ðº@WèU¤I§Æ¦™;# sRzì«fë¸WÍ6p0©˜y Î%æ…¤tÚökæ%ÜGc˘C#˘­Ê˜s㊙cŠæó¤X³mÀ0Û¼fGÌ•ËRO{W1;¢Í®z¨þUP–‹-G»•qn"Gòf–M0Å,˜]…p DdáZ‹ªè¾j±ˆå¸VÀJXUEŸ§Å™S¨¬ÍMU*ÆV4÷U©h. T2·Ä¾ûº¹.M<7ªhóf•ØÊfï*•Í“+›í*K/t_ÒSÙÜ‚õ¢Š¹$þØ7t¡çUt¡{Iîð¶9Äõ†Ùíí7ÌGIo˜ý1½- räÛæ(# {TlÔóˆ7£n%½5#öͨ™©oFÅù&žßŒ}“àošG±æÕ˜bæ™@º¹àí·bß2½ý–.ºômós/·õ·¹­ÃÉ·µy ó4œ³p.ÀE¸—á*Ü|;–8E#ïT•›t®Ð ºWÕÞ˜½ªrÅøRÕ\U±ŠùÜå5oh·yÞk®H.f®ƒMÉcß6çz£hUiþ—eðq H¬ØŠX$bb©Øº•B,Ûg°\,åà ±­±JÄ®d‰KÄDé^&‰¸RIù•N|[Üæ*¶fì{±µÌ®A·Ùµh˜9<fŽ æhÜ«½O{ß„9Tz?ö}sl0ÚìûJmsbP™S‚¿6§Á˜Ka9¬…° ö+‘_ubÿÅ|i˜§¢½æÙàoÌ Áôغæ‘äºæQ8T­.wͺæå`1t ûÝè>0OÐ`o öl5’ó!cÕ¸½ÃÝjæ}×|ôÆÖ3{»ê™³á*<&š$³cŠa®aìÒ=¥˜Ù ûžJ™ë’>"–¸˜b?2û¤D›[ ¯Ùófà_ͫŔÙêãØÍa)J'Îcl6¬¸N¼MÎ?xG'fbô÷ñOtïÄ"[¿«ïr„‘@"£€Ä6¸ÛB;`døœXÚ¿µ·ð'fOO#SꛣILgãÓØÏ¨A¢[y—’ýL›ÃßÕæû.tãaâ»äÿgäÿg”ÇgÔtÓ`Ì”2þÌü³Wz›wÍÅï~Nƒýœ!Íçè?ýœQÇç¤öó¨-ï~µ•£³9ò(éó¨ý¸ÀA8„¾úq ð¶‘I;ÈŠ¦^’ø[³Sq¯éçŠýíéR¦YKêf}¯y.E™WRÒÍAôw¹¤çØ·¹¢Ìuäæÿ¿Ñ§ý›Ù#µ’Ù+•ÍpÂŽ®®½cªk3{&ñ©Ú5 ûLô³0gØ ªS‡É¿îµo#Ö‰`<¶SZÓNw–.b¡ˆ;r`‘ØtiuzßÓcüÞü£7ö sYüæ4†€ËSÓcÿÝÌ*\ÉÜPâæÆTÆZ©†¹-5ÚÜ•ê5[xͽ8ç{*}inâ"N¥¦›g8|¯WS=±4¯§ºbð„ÉYNTçp¡ M4`4~}£¿MUis“¨Ÿx¼÷á<¬nNŽI7»§)sÛmöN3̾iÅÌóJ™“±OÅ> s`rº9/Íû•¹ ­Xì׿Â4wlCsqZ,Å”AÁf˜G+epæÙj4Ü0™c‡p/,•a¶Ê0—r’åißÄ627FJaþ)¶1U¾1Wט&ÐØüÎk®ã\;9çnxÛk–S±æ>Ö·&Wög®ìÏæ¢¸¿Ä61[51/¤yb¿5Ï,h>Ão›twlS†›•ÍU0—Ô47XÞØfæ€ôJ±ß™mL¯9<=Ý™.÷åïc››™\ëÜôæX™.w´½5Í ¾XsMzzlKóc¯¹ÿYï¶Šmû•÷®ñªîTÝÐÿÀuÿ  µg°=ÞÐ…TÓ…^ÔÔ…Ú¼§ ÍB׳´‡y¸»¼Çﺨh „{”ÄcÝ86ö=so¬ÇÜ•þ£¹Ú–üÑ<€y&½ÒÝ’ ¨J¹ŒÖJ)·¶e˜HW¤! ;©‚Q"]…Dê"¶Œ¶eQ[³eq[ÆØaKØÒ²C½bKŸ­‰gûŒo­ ðóÛ˜‰¤ÃLj(à-] €7XÀ¥¼Þ”Ö@•Š; Ò  Ê(Qßð­*¼Úסr‘oPQ…ªvVIX~•m©f[ ~/Õ YƒÀ‘5ÅöžØj‰í}‰°¶}ê_Ë© ÔÉM`‘º<*:::âC‰©Žó£l§KEGü«ãp øD¬¿ù§XáÂáŸvvGDx½Ÿñg¨Âűÿ¶³[¹]n'p½òwOùo/)¹ðßÛ§ÁòE¶åß³-ȶ|i[Œ˜üE|ÕÙÁŸKþ e«¾vTõœ¤ŽhJ:ÖŒlktÄ7¹ÖFŽÕPÅ£IÓŸ^J“eDãPN(+â/býÀõÊ+ߊ­lY·ï•èˆf’ òW®\9w,Šï³}ôQAõŠ×ûŠ7¢yv~kIü´ÌöÓªU+ñ£þW¶ŸÔ_)Ÿÿ øâÿ«5®ÿ×ãò·Q­É[Œáí¤š‡··íl{G±«NRºUN1sgM(Uª»jÝC9ÿ /îÂ…{æjzÐ8ÌÄR¥úäªTxRÕvžÍ%J•˜×sèAõ`DÄ9sÄPÕz˜*>Mø©ú#Em޲ՅG‹zŒˆ±ˆÈL99Î>9ÞvLpmÇ$Ç1¿…§ˆ¦ðTÑ(˜.¦Q"¹T©ð™ª3uz–ÊþW@ͶýαC{çÚ;OÄ| *KÙí`¡ø¦<Êôz£)ÉsqË¿j±x\"b©ˆe$<|¹êì çOüáöùWØç ²ÿѬt’©W‰éR:|µs&TklU¸å]«Z‡|¯ ù^278¦gcÈÜ䘮Í!s‹cÆoUmm÷6ÛáÞ®ZÏsGÈÜ2w…ÌÝ!sOÈÜ2÷Ù¦rïwâu™Cç?ä˜ÆaÇ,x$”Ž£!óXÈßqÇ ;ºŽ“v¨SJz­ÓvöÎUXÏäZφ¬n)‚sN&¦ô)ÁÒìóz/9G²+²*P䲞ëÿÐvæqd÷¯ª«»« ˜¢¡i4c5c'ÒD“±cÅÞQˆí‰“8NìÄ;Ç:׿Ú$Î8εÙd³%@â@€„:щ$@' „îû¾O$tºè@ûýý^7Ý8Ù?wjôy¿ïïõêÕ«WÕÝÔJ™Ú+Ý>jJ¿ õ‡Ñð‘ =Uè{¢BãiÔÿ,šï¹ ½ ù‚ª$ ^Rï½’ù”æ½×œö½÷ÞÈüahó-ç±]μ)š*0_ã‚ 4d/ì©=M¹‹È]LžÏ”hùä)e1…3")©L+±ÈÌLš©ÑÞVh4éT²]¥Ui<ïÌÒbsHµFÏ=³Gœs4ÚbóÏ\ÎÛ'ãOC5#Éçi´ÑyM ³6nÖÅÌ$kæ–SÂ…ñØEñØÅKÓí’‘I-Qѹ»^S3õ2-¶EgðåшxKÕiŨ=P¾•£|4¯J¨5´z”jˆ·AÍök´ØtŸÐ-4ç¯M(sò:–ÍÏMñ"q9lfµ^[¯©+â-vIܨ©-z±ÛôŸTÚüÿŽÚòŸDa£1´UãYi›¦f%މ]ÔzRüt ¬Ÿn×ÜMŒë„GìÆï!÷ø½ì¿Å~$ñÁ!?s”ÄÏcaGFçyœ“ìqN±8ÍbìMèrB$rŽ$mºmMt.hîE6ͲìKM•´šøð åµ®Rb¯0‘/¹¦¹"ú_ìªuvp‚yCËïÖº52oj.™\Õ-ewc Nè!;žñ6íêÂ]MÄ'óêòó4·W¹ý÷ð(žÊ#œqãœÇÑÆ8Oh·ŸãžžÇê?‹Yë…æj´Iù³CšÖKÞ³Wl¿fû Ù½%û#W'{ŠNv>Ù™dg²=•íid›Ed›ÅdJt!¥„é@Ê B¡3õx—É YIžª¸Û'&Fü™¥ût]z«1¤TàÑc>q6ÌÈÀ™ L¬!90Ÿ|µh\§»³ô‘Ú¾°ù…Eº»Î%±ž/ZËtw¹.¬ðØ+ ««©°$ˆDÖèîZëtŒšñc­F*6)Ç6‘í‘bÄ4ÇÜ‹uM޵×+)"¨ÚÈF’7qõ‘ÍìÜu¶DíÑp›JÔJµßNµ#Ü Û¢a;·Êî Æî$t_Ü¥ Ãþ9ŒP{·îîÑc›‡}{㮑qÊݧ»ûQÐÔæ„êî!Q‡u—RÑihÕÆ¥8ƾã‰>ëù¬“ÔŒS\ÎiÝ=CåœUåœã<±ã~é¬ ÔÖEw ö%8>s™p…¼Ÿ¹J^yŠ»NÞ„nŽºÉQ·hz¨ ·”¸“(î&Š{‰Í5ïSsÌU§CqBÊJDZw{Ü=ÚÄ{=€Ëɰ÷Åœ´¡köGûïaqÐx“yb'æáØ:≎°£ #,:¸¾|œZñå÷$†Î)5§Iðx8C‡NSÃæ,yÕFþœ’Ô#ç•9²ûâ)ՆݻH>´÷…4Z.{Ü+ž+8 WÕ(¹æq¯{®£É7O’n´Î¸ nzÜ[µÉ¯8w<î]ø{·›ô}Ò#¹"h7"½·Ï#"ý,*ñ©" O¨š§‰ç`<Ï<Å­w¨‡°³¬çwÀC›¾ ‚‚ƒäÀ¤àáIA‰W,^³¾ádÃ$¾eg´u8–åñJpm›bÐJ&ßp a˜,¦‰óD‚ø¸Â.¥ ötÃ-‚1ƒs—±°Ë9f& QÏ(ÍP¥iöã*Ê?‹SUî {6ÛsÈž\Cöäyd‹ù µN¨¥ˆ u†»Þ… Å:Î"—Ýü…¼ÐRƒN¡zƒ6]þB^x™á.7hÓäG­P‚#VÆ"X­¥VR £Ôš‘C¡_\g¸F£¡‰¯~m½ÁC~ƒAû¹Ñȯ7ÄäM¼/›)‡&¿Úª²"~›áÖ#tZ)4ó¶+·ƒBñÕ6ä³óÚ ·ùòrwª|š™gvŽìŸÌÌÛe¸]†ü$o·áæÉ_ÊÛk¸=™·Ïp÷òy wX“¿œwØpS9á#ªÌ}Ô  ËR;ƒV}âC9TÉñ‘J0¼‘öëXB|'ãÝê8§¢ûõ•¼Ó†ÛbÈqyg ÷¬!2Ï“{ð¼‘ßat`Ÿ.Pd^¤ä#Çõk—ȾlîÝ+t$icuu”º6J]¥nŒRÝ£ÔÍQêÖ(ÕS¸ä£îð »K^Ž{†{ûÌË}À] ’Rõ²¾oÜ7dV^ŸáöÓñxh¸ 9&ï±á>1dZÞSÃ}fÈô¼ç†;@Çé…á2#oÈp_8P¯ ·™ÔkÃ}ÃÃiØpo7 ù+y®×âE˜Oa¬¯4‘.ðÒ0 zÑÎðT¯;V„§!]$J¼‰K€R¤Çšbº×-õÆ—J3È.£2´r/?Äé¥g¶‰yJ®«Š|³Õ„Ù„9„¹„Â<Â|B-¡Ž°€°°ˆ°˜°„°”POXFXNXAXIXEXMh ¬!¬%¬#4šÍ„õ„ „„M„Í„-„ÂVÂ6B+a;a¡ÐNè ì$tvº» {{ ûû  ‡‡ GG ÇÇã=i Ƕ#‘ÏÑ ê o±iÛ–¥y5/}ê?ÿ/tC§Tnn O{Ý3^Úįž‡;pp‘Ž]à’×u„}™Žÿ¯ÐÅ7q é-Ö ÝÐùÒ}IG87èýn/î;oRò[”ßî¡ü¿vŽoÞ"÷÷)þ¡×‹ÕU$ÒGE³®o=¢|ßzLù>ûë)áy­çäµÈñ‚ƒp B@«¸—\ŽýŠÆÞk¯ðJg,îrìa¯ºwø?L*ö[N-]]œ||qò¡|Y@ŽBvL%GdÙ‘"ØîOŠ}Ü["RÂîÒ¨{zÔ=~²GÊå>º ›I"RAžJ®óÔåU>7ÚŒÈ,2E¤šâgææúx]ZC‘žñtçùÜ^µã­IXAÍ{N ;j‘OÖQ£ì>ê—Ï.äýYDþÅ„%„¥„zÂ2Âr ÂJàWWQ~mµ/Ÿ;´ª—Ö¯¯õ¹ë|bR#RLj¢½²ši¯¤ô­çš|T°Q›T°Y[TТ‚­Ü¦mTa+a;W¸ƒ#µ6 l_;”äëP9vª “3îBò±ïwùòwû¤ôìá(Ï^ìSÁ~PETÁ!ôÃ*8¢’åÀ8¦’çÀ{‚ÿIå<åSCë4õ„&ß·Îðá’g©Ù¿qžY2™ìEu`]&[Ö%¸öPâ÷¯ðν;'¾}ò B7á&ᡇp›p‡pY¿cß÷áB‹s†:¬—ÐG%Zý(Ñk;Tïo>â>ãÿ~ëI´ÑO¹­Ö3K9Ös>˜2g€ýí*äà;C*x‰@—ßyßzÅM×`¾æBrßPµÃ€xKu ×Ã!¦øÉÎg»€íB¶§²=í"¶‹Ù.a»”íélÏ`»Œír¶g²]Áv%ÛUlÏb»šíÙlÏa{.Û5lÏc{>Ûµl×±½€í…l/b{1ÛKØ^Êv=ÛËØ^Îö ¶W²½ŠíÕl7°½†íµl¯c»‘í&¶›Ù^Ïö¶7²½‰íÍloa»…í­loc»•íílï`»ív¶;ØÞÉv'Û»Øîb{7Û{ØÞËö>¶÷³}€íƒlbû0ÛGØ>Êö1¶³}‚í“lŸbû4ÛgØ>Ëö9¶Ï³}í‹l_bû2ÛWؾÊö5¶¯³}ƒín¶o²}‹í¶o³}‡í»lßcû>ÛØîe»í~¶²ýˆíÇl?aû)ÛÏØ~ÎöÛ/Ød{ˆí—d‡^‘zÍö?®™Ã@à-y® ïwóMZĘô¨È)D€ù\L5ù4s¦Q’@‘‰<Ŧðå84‰OÊ)1ÝV-qÓÇOÊ_jF§r9>g:Ù8OgP¹e&éåd[3aÿ¦Uaº•&Â* mi½OÀD¬ïT›jòQÿ!Ûl80Ì11}#œK¡øíyfü¦ç[ó©üoÕšn)¬ˆ±Âc[‹Ìb©{Çb±›ôL¹ÎD { G.U‘°ê•%¬eTÎØåTnÿ­dÔ™p­$ mYÅUÈÕø7Öj0݇^i]cºóMzn½–ë˜o*µ.®&Yv#«&³É”“¬fÓmBK×s;6˜XžÚÑê6QýlV•}v‹j‡eµ¨vè0­ÊF+ĶxÈ>h5ÝípìÀ¿Ü6”3Éj7ÝÔ²³°v²‹°Ûä+óÓ}ì{ìã‚÷*û±MÚgºûyp«šy±ê0;ЪIÖa•A|p„[}”äH{ä7™îqS‹8cO˜ôLIœ¤Ãr I­±§M·DŠoá£v–Ò yŽšužZyÂEÎŽ^¾DÆq­ºlºtÁ{…<ô¡€ÊyÆuÓ½Jã•MMïæÆ–HÔ$oRÝ·¸·{øXïöј¸ÍI¸tùÙ;ª´»œêU%ìûÈ÷åÔž/÷r{° 룊®zÉì7K5M×tÒÂ~H•<â죕À|5Å÷ž%ŒXñ܆ÌùhüÄÈ€é¾0c=ÏT)' ‘%EÎKœ•i~;yOŒ“ë5Ç˱o(Œ—=Œƒ‹Ö½5]×r-aOÁÊù{ùVôÀL*°ÜBˆ©VÂó,¿_d©O2¾_Œ˜_-±èé §f¿]FV9a&`UX|I®´Ü"«ÈB{ªÈÂåxV4¬VáwfGÃ9ò•y®ÊSdÑŹF uïæ³çYtTh‘? Õë¨5 €ÈBÂ"@[L9–PÄR²ê ËËc{¶Ƈ+ﯲ°çß_M©»¶ï7`o©—ÖXîZk-{ÅäuH6yr£å6Yâw6@üîäM–»ÆÚáÂVÂ6ìºøæäVK}¼,¾¹Ú±pÚ¨*§wÙq:b§%;±ûÎ.®>ÐE »YDöˆìUb‹ý,&@aãæ!r›‡Ùíáâ*qŒÅq•ûç>©Ä)§¹ëŒåžµè„?íêÎSü8ñ­èCÇKVì¡#ŽæeŠÔr~+÷Šå^µ®²yM™â³×©Çnº 7©8û9”øÙèßK½c¹w-ñû÷!r¬”UX½Ô}}”§Ÿò¼ÿP÷qSäcêÇ'ý”ðŒ†âs²/ƒHfkC–ûùìW*ßknÀn?õÌ0¥|K…¹6ànÓÎàþ2ßF¾—–H.À~&¦©Ó€_-¢´Z±ÍMÒK¢a© =ÓUhÌP¡·L…Z¹ }3£aE4¬Œ†UÑpV4¬Ž†³£åΉ†s£aM´ÜyÑp~Ô_«B]4ÿ‚¨¡Í]°È¦[$Þƒ%ÑœK9ƪ·ùD]fÇNÔå*þÛ+¢áJ~gU4\mÇNÔ;áD]cœ¨jÚ {Òµ¶;ú³Øu4€ M„fÂzÂÂF;ž4´ "°­³-¶Ûb·Ø"°•v!´Ív[m™Ún»;l)m¶:Õd;ò„:hBöNJÔŠôäÜEè"ì¶y³GEkòëboÌtÄ>ebµ³ß¦y¸*8 EÃÃÑðH4‰æ  l_dûÛ—Ù¾ÂíºJYpV±¸®Ä Ý$p~ߌ†·¢aO4¼ ïDû*óȧÛI"áÑó»÷¹NûÙ›äö%‰¤þ$ú|x÷¹ß}ÌîÑŸ4=IõIÓSJèLÖ‚‘È£d÷qòãd]†œñOÈI[|r¡ƒ=îi´ƒÄ¸gh€zžÌóã@2ïü‹X/ ÆŒ¡Xw¼LæYÝñ*ÙÅiâ¼NŽSI‹üá'»]F—áázÞªj¨7…Nm'4%ÅÍOÉ2ú†ø¸0…¾Á“Â_¥M¡§+El“-JR>Ï+MÉw-íþ8X†È±™÷ÉŸL˜™âV¤¨ 1ŸTR ŒpUÔøïÕ1cv̘5¾57j˜5dèâ«y_›G­åæÍOqËSÊSdžYK ý£`µèO uyÎBåZ‚Å*X¢‚¥*¨G É?Ê]¦(¾ºûZß!Tœ±2Å]•²ŠZž¾zÄÌj1Ǭ1ÓÖ*+üû“FnGSŠ;#Å“ Ù¹Í)˜cÕ¦ý‘Z¯R£!È¡)‰Ó}’½)E}ZNÇÉÞÌ}¾%ÅmII[I$mca·"[ÒvÂŽšÊÛRÜö‘Ãè¥ËYÐùÓ)Å]ÑÔ7Ž£ŸûiHÜE…»RÜÝ)ÂÙCÂÙËâO÷‘øÓý,b]’H9‚Ë(.¤â` M'Ρ÷pÊa´äõßQÊ:F>:Nžì9IiOQçÛÁÓÔùAË:“¢.ÔgSΦ>— u\Èó)ꋸRäÅÚdк”âžE}—¹O®pUöUjã5Âu |#…¿¥Õ­ÚFæÍh3­[”ÍêálÖmw”¸‹œßº—B×»û)êÙíƒh.§—{¦:ý,*ñˆÎÇ)¼ÔgxÊâ™ÏY (ñ‚Å C,^*ñŠÅk%Þ°Vâ- ÷SÞ᥾, •˜ÊbšE,Š•(aQªÄt3”(cQ®ÄLJT²¨Rb‹j%f³˜£Ä\5JÌc1_‰ZuJ,`±P‰E,+±„ÅR%êY,Sb9‹J¬d±J‰Õ,”XÃb­ëX4*ÑÄ¢Y‰õ,6(±‘Å&%6³Ø¢D ‹­JlcѪÄv;”hcÑ®D‹Jt²Ø¥D‹ÝJìa±W‰},ö+q€ÅA%±8¬ÄG•8Æâ¸'XœTâ‹ÓJœaqV‰s,Î+qÅE%.±¸¬ÄW•¸Æâº7Xt+q“Å-%zXÜVâ‹»JÜcq_‰,z•ècÑÏ"ðDà‹ï>&a?y‡VÐòé;Bžž)ý"ósðþˆeèuš¾|‡OSœ”¯Èòò—ømûõ;ê#~Š‹mš47*¹.MÛV6*¼EUúÐ'2…ïÐÄUà¸\p¡ÃsÄT8­à4‹ a!Yf1<Áq%ÍIÁRx‚Óáq¬Ž‹ÙʲÊ(­´'”;¸<ýYØ•T²UE%ÒÇö,'Ú9ÖªvÜáz¼8Û‰Î]'Îq¢»œË­±Í*,6);ÌyŽ;ß™ïèÈü Îq8´yÆþ"'s‘C· ôþ€XìУ^ÂRjK=ð—Ë?[Ar¥#¨‡V9îjgµ#œ8ÿ|óéZåÔåGÖÿhTöjG~nâV’Ù3k=5‰Z¿!ZÖ_l¤²69ô˜ q¶8n éäd~°ÕQ¿=ifdêÌÍqZw»³uæ8ÎŽXš•ã´9n»ÓÎã;b†Ìù‹ñ¶½Ó¡g§ÊÅ-Žä8ÑIµÑæÁ*ü/rvÅd‹ëH[$|tÖå¸"ñ¿ØwwÓ±›°Çq÷b=»„½_‰,²‡œ„«ù¸ «âÆqhµ L8F8Oæ¥[WaY'œÄ{WᜤbSŽ{š>fuøìfaŸƒ#é¼#~âæ÷¨œ‹œÿ’ã^F–+”媓p¿u-AL¾ñ»7€Ünü7÷–#&÷@ˆÉ·ùØÒ× ï°;p—Òî)qŸÅ%zYô±pú¹I ç9ù>&­K¬OžEnÔi wž)61'òÜqœ'ÞÞ°­A>†÷%zì‹×$¤ÿ†¹Ã”å­ûqI$ษ#ÏV5Œ‡)©înm·&œüTj^A*e ’Leñ½i©tkžª~bSL>Úb¿œ)I ¥©ª™óÌÈôXBjÎûÂ÷‘©ùe©jóDr>²¬rÕÚ¼ï{"•93Õ­Ho>iŽOþÊx™j3$û«ý2'gVª[–*œêT·K“‘œÙT… äÌIu‡qNæÌ%¿&s"5*#’Ì£$p}o~Ôõ½œÚT·.Õ+r2qX R‹=RW›Ú[¯äˆœ…©ÅF,&))±utÖ/Š7qââTwIª°–¢“¬zÂ2Âr ÂJªTú© ¡ˆ¬¡ãYËÇ!²Ž<ìibÕLžõ”o»7’[§/RmŠõˆ°6#~ìJÔ’*èÓÏ­*s eo%l'ì2Û(a;•fu¨Jv²èTmØE »»¹Æ=ʽžñûxígs€Ò$ℇUÂ#,Ž*qŒÅq•áç>ÉÂ>ECî4{Îǰù[gSÝs©± ·¼tìÏ'{a_ ¾»ä\Böûr*Íe©"ç ö>ç·r®ÒØ(KÅå2çZìè;×éè£À¬œœ‰êøºc#”+p3¦p–Ý¢´ÞñHóA §'µ”'ï!'¾Iû£ÛÔhã¯,kÒ$çnª{/5¶yeN.–ö¹÷GjŸüvòû”úÁOŽv-wÒ¤ÞTwÐt|¹9èÇÉíS:¾ùÇSÌxDõ§º‰M¡ ³ŠýP;RÍ£ÿxR%[ïOšô8ÑoŒ'—ý$±HÃOùŸ¦ª/X277â8ÏFe³¸™Ï£It;ÇrbQX/Rã·ÍCƒ(љ܈]×SBYSYž1O9&眹¹Ïîœc_°S¢ŸgäD†´fˆ¼¤¼‘WyÍâÃHyKpÓâSÄ»ïLIsóÓ¤0 ÒÔgf!¢ßšÆOåÒÜÏc¥¹ÿ$ìâ´‘äú"Ñß%•¤¹¥i‰›ÓUéžÈÇâ"Ç%´œ””?œ™æV üÍJ±Ö ¿A‰³béu UMñ´ 1;-ú½˜±sÈ©JŸ›Xúk¸ôÈçQ¨ÉFæ«ì¨ VEEê¢ XmÀB ¹âE£*^¯˜ë\¯sé¨=ª¼,ZðòhÁ+F ^9ªàU‰««ÓÆRCZ‡T޳&?¤Z›FOQ×¥©Ÿ‹6Â)mÑ”æ6㸉õiñ‡±úçͰµ!ÍݘF©ð¦˜ò|Þ †­Í1slå[VË(N§­qnkÃÛšýý–NÑÛc±BìH‹ýv´-Ú&] E{šZÍvPôN Ü" Zö®´èóbóÓÝdÂûé§á=ÑLá½”vaÿH®°ePñÒLs[Òô°ùiî¡4÷pm¨öÓÜ#ÑŽR¶cñ¼aû¸ŠÁÎ|ú鉨Îà.4|R ƒZ`}þTZl~šrŸI‹Þ Q¯Ùg£‘´ŸZçbIÏS¢ £R^ŒÆù¨ÔO­O­KiñÛ¿Ë”ôÊHzt¿}5M­°¬Ük#©¯S²iñŽíŽFEOe+r3ͽ•†°‡Ãˆu;ÍýçÜUÁ=BÜOKü î—ÔK¾>B?áaÂÀ =‚øÑ“4¡Ù?úÑÓ4÷YÚ³4ñ£çi”y M=)y‘æ¦ "ÝP?}$)Ä+¯•xÃb˜„?z›½äýÈM'üÑ”h˜ ¢aa4œšÎÅľ¼hNã¿è*¢ *Nw§¥k"䔤Ó'cš¥éîØ±˜’Ò>J˜8#Ý-KN99g¦'Üââ†Ñ‰T¤{ÔólÍ}˜]™žø“Æ@ P•>ò1m`V:]@ªÓݪt˜ÍbŽsYÔ°Hš‡2ìù@R-¡î'‹\PäBθ(Ý]€R³X¢ÄRõ,’–Q‘Ë©´„•é óȪD±B6¤óRfMºZSh¦øu„F*×iJw›Óy1¸>ý'ƒ"w%ÉÝHI„½‰Óoæôt¡ßBm¬Zb «ªzŒ Õšîj´4Ú®b…½#±m´3í ÇIävD»ÄÜ wn'׿+ÝíJ—ò½Ý {íø^Â>Ê¿?>¦8î®×>uwœƒ(éP:9Dä0FŽP꣄cé”ðxzÂOïʼnô„I8häHëí…y:Ý=“oä{g)ò½sÔ¸÷Χ»ÒãÅ\LuÎ¥tš½çr4¼ ¯R(ìké4Å_OWSütþ‹Ý\óÍÄ~ºEî¡cv;±³Ä•ã.縗°v p?ÝýÊW4;=ýòïþ®/ÝíO—|È¡<Š ¾Ç´éOÒݧ(ቴçJ /”ˆvm&æ Átw(6þ(ÍËt÷U:mZ8|î¾I“N¿Ü%7%½%ð`Mô®íÝ)Aµé6J˺AÚ RŽSÓ´qŠ©1«i£Òÿx\ñ¨ôtvIp¤Bš\KãzÉ<Óã.Ú\t+ƒÚç3í*2`þm¦=+èV«á ‡gǼáðåbn0q€Ô])Þ‡âß0?èÖéǨuAw^p^PÊwóUÜBåÒÞuœE”¬6(ßuó‘Áy×YBÝNËÍ3—Ýú`}ÌeÊÄK¬ÂÁÄÕAõŒ”¯¸«‚ôkÌÕAzh XÃ"k-²Ù뀤FBS0áÛÍAÚ‰õA·9ˆµù† ‹SpcnZ›ßÚBh!¹øëmAº§ûËÖ »=¸=ˆù€bÚ”³=æì€ÓÙä¯Áw Ù)w‘þä“.•ÓÂn²xæÚ™¹šƒ´‰Ì½("s²YÖþ { Hß”çбqs-ëpÔ„B!"GàXÕ¬u"Ú ç$5èá4áL¼´¼ s6ÈŸcòÎÝóÁóA™ç\ §–—º¨b…¸äÏ™/Ý+Á+Hb^å$2œwMåÒdvÞõ˜ù¼13+¯;ffæÝŒ™éy·bfZ^OÌ“w[™ùã¼<ûNîÅH«èOòîÆRfäÝ‹™¿”w?fþrÞeêyyŽèUmçÉì‹îf(ôI¿ÚNó0ž&x¤I%Öc¥†óž(3>§= &NûÏ‚˜ÂBσä&ÌËö êðAJ<”0òÄK*êá50ñ ­aàÏÞÒpu3øS‡)n~F~†øë‚ `…J“95eOËàÏ"ŠbQ–UœQ¨Ì‰Kb©J30.~<=ÑñQF¡°Ë3PÕÌŒ„VU@L¬ÌћܪŒØM؆›Üê w6Bg…|“;7ƒnrc œŠö<”æÌ'ÔfÐ¥·.Õ!œ,*±(ƒ¯ð‹3Ô~IÆd\Ч>íÉe( °œó¬ <WR¨É¿÷5¡Ì5qsmÜ\7ãf“2…ÝL=°^uöå”¶¹‘›?Ò)›zÈÙÌ Ù’á¶ ûVö6¢5!Ù{Û)æ½n[†ø‡vÿÐÁÂÚ™ÁOQIð·Þ³þaWFìÛôà8öm„®Œ„é.qvgÄ×{ÙKßGØŸA d¸ôsÚƒ„/ Ú‡3ø~ì7öh†{,C¤§l'€¤“„S mž¦„Á3îÙ á;GÂwž¯5ƒ¾ ´Ö´íø7'´‹‰Mu¬À%Œ›ËR‹îs…;íj†{ Çó‰ÀuÖ în#~3qHÞ¢–öÐ ºwËÜwîdЯåïfüä·ïe$|ñ>záöfˆP‹~%²x¤ÄcOXd<¥ ŸQ¯<' $Ô*ß‘áÂ1D­}IxE£ó5Ž7„aàý·TÜûnˆ’~sJˆ>: Ñ3öD YLeáL#*b!ŠIˆ•¬”2Nì@¨Œd9'˜©RW°¨dª ÑŸ T“Û™­ÒÌ QÛç†0"5TÂ<*p>Yµœ½ŽÒáâ» .Tá?.ކKTñK¹™õ$øSâe¡üÁ Úpº,¹+½ÿl{U("²:Dh6„Ü5!ÉYK¡ú`s]H]´Cjã2›¨\ÚèƒÌæ[ª Ѭ°>¤f…Úko@«!>Y7©üAæf*6õAæ–˜\ŠŸãB-ÔbÜVrn£m ñ÷6·‡Ü­¡­¡QßÂÚiG(~NÆ>èZÒ™í€ÕAØJ\ u†Ü]!„]Ñpw4ÜÃá?9ûCîtËAüû'ç „‡Ù)ŽÄJ:J;yŒáñ»?$œ,N*qŠÅi%ΰ8Ë"á#Ï€e %~ä8O Bî? û"Ò&] %œa—Ä„+”tÂÕ{-y=Ä ôÜw݉™n&Š[4¨z¨å·‰wHÞ%ÜKLu?Q< è^ªÌî ¹ýØ›‡¼7HÐ2ãqÈí õ¢ÿÌ'!÷i(~A}Fõ<~0@e¼ñ³ëÁ;IëC!šNb x™Xá«Ðè›fsìëPì¦yd"{ƒDc‡©!cß†Ü Ât3éŽ}JfâŸù™Ô™£—£…™ ËÑ©”/<-“—£E$Å,²K2é·o@ÒtŒ̄6–%ŠòLú-¥®>SI¨¢’>3+Ó­ÎölJ0‡Üs 57ã¬ù$¬Z²Ž. ,ÌL¸IüNî"Úùë¾Å™î¸”2Ùõ™n—æ•‘ñômY&]Ø»´ø&är*iE&=>±WŽÄ“ZEY»4ÝUå®V‚6Ì+ ¤¤ÔרÐ^«Bß: qú3Ý>­Šñ5©œHÕœIË¿®„¿©¸>±‹6$Š™‰_à?6º)3ö*¼™È–L·½³•{g›­,¶³ïàdm*¦c:XØ;éhuve&þ¼.4‘&k7§Þ“éîÍiÔ?ï§ãw€p0“¾åKÖa p„p”p øÁq²NÉ' §§ÈÂYÂ9Ây`Ü*å"0á5årb/\ÉL|Fã8öÕh8ר}ÎõL÷F¦pºYÜdaßâãÞÃ"ý6~‡öó.á^bá÷÷<ø%Gн™±…b_flã…a?列ó0SüÄ„õ(sÔ„õ˜Ï˜'™4a=¥fæÁ,õzyÉ&þùuüQDzÜãHz‚ÅIΩ,¾_`8Ãcæ,‹œ#ñƒó*æÇ\Tâ‹ËJ\aq•Eò5Éו¸Á¢[‰›,n±ˆôˆÜVâ‹»JÜcq_‰,zYŒë#1®_íÂCÞ…GJBèÌþÏ!좽í¢Y»³q[iía{/Ùæ>²ÍýÙñÛM]Œ Ù²£:ƒÖ­³ÝCÙ‡²1ZGûˆoÉvUôQó‹ùöŸˆùOÆýBž¢CûòÂg²Ý³Ù´±:7J¥.ŒRcJæå]Êv/+“w5Û½¦¼×Gå¼1JuR7G©[£TÏ(u{”ºSR»ÙùJžÍö’#%`ßË.Åe*æå&ÊÌû”Mˆø7¡—È„>öØý|^>Tâ‹Ç$0 Ÿd»Oæ=£PÈçÈ›9MŸw¼È¦OG³ó³Ý¡lù¼—˜Z²eVÞël÷M¶“7œí¾¥ZÝ1TRzÞ”1nþù‰S0Æ=ž-3ò ǸSÇÈ_Λ6Æ- Ê@^Ñ·x }ÊV2ÆU{êä…KÇŒì)ýµØéch–Ù%;oÆd™ç”É¿Laùi;3ɯÁQ1†û&>§¾S‰v¤Ñ—À&Tq'L˜à±LÜÍb{‚5™Ê;;îC&scFM̘3æ“¡ÛïØj©ÚXÕÅ”µ` Ý9ÆÔÂQjÑ(µxDôÕZû×—¨æL È¥£’ÖRËF©å£ÔŠQjå(µj”Z=J5ŒRkFzt-íž&ß±ÖqÇ4Ž«I¹>´š£.Ë\Æk˜>6¨Î s£2…Ø4FÍcD¿üm,Q‚ô!§ÐÏÀó½ðÆTÀ; ðþbÀ,¬RZO’fÉe@J9ðÎLú•lZ ª€´Y@úgq›_-îÝÙR™³1•…çÀÊš d× Á˜yÀ»ó!ß«>S9vYä,Þ_ |v ð¹¥HòSõÀO/Æ-‡oü àƒ•ÀϬ‚oÂj`âjTôa¬Ï7ÀÊ]ëg×Àúh-Ò}aðÅßCÃåŸ|Є¸Ÿo†çËë¯lþËFú­î&`òfà¶y-À/n¾º øZ+ðõíÀ';€_j¾Ñürð+;_í¾¹ øµ.à[»_ßüÆ^àÛû€ïì~óð[ïþëaà·ß; |ÿð;Çß=üÞIà÷Oÿí4þƒÓØ©?8ëÏÀú£³ˆøãs2d¾‹}ûëß;Oo©˜™—ès¨²wåez"®Ð®ÄUð§Ä5æuúÖ®¸ÿª›’ànI·TЃ þæ6ðÃ;ÀßÞ>½‡Ô?º‡êÿî>¬?þ¾øÜˆìGÄ?õÃú燰þçCXÿòÖÿzë_ÿö¥üï§À¿?þÏsú‰¦§ÈˆÏ—ƒ` åKpª|E¿Ï”¯Á"ù†~ž)‡éÓù–~)]MŠér 8Cæƒe²,—…àL9¬ÓÀJYVÉbp–,«e)8[NçÈà\YÖÈrpžœ Η`­¬ëd¸@ÎÊjp‘œ .–sÀ%r.¸TÖ€õr¸LΗËZp…¬WÊà*¹\- r1¸F.×Ê¥à:Y6Êe`“\6Ëàz¹Ü Wåjp“lЄÈk`o–kÁ-rØ"ÿõœ4ÇÊF­UþF’4k‚¾3ô±A㻑ÛÞľÍ`ªØ¶hb+ňm¸©Þ.[QÔìxD´a"¢»Ø…ˆØ‰îˆNìHDìB§EDº+"vc§"b|.#b¯ÜŽöÉà~Ùí(ß’z”p’;y:a–÷äûâˆÜ…ꂺ8&»à?.wƒ'äð¤Ü‹ØS .N£w"âŒÜÿY¹<'€çåAð‚¼/sp&‚}I/Ë#ày¼*×äqðº<Þ'Ány ¼)Oƒ·ä°GžoËsày¼+/€÷äEð¾¼>—Á^yì“WÁ~y |(¯ƒä ð±ìŸÈ›àSy |&{Àçò68 ï€/ä]pPÞ‡ä}ð¥|ÀýÓ û•ì_c”GÄÙ¯…Ì÷E¡6†^ 4žß 4^ Ö2M›è¥ZX¯ýmÈ'Ëõ•šA¯Êð®Ò*uM¬Öèð7htà×hÿ2?šŸÞ&äˆYÌjpœ˜ÍœƒMÚ\°Y«Ñé´˜nÐ~6dN‡´lzw%j™uàGbs!˜)1éåA¦  ªEÂä¶U£ij¨‹Vm ÊÛêb‡¶v¨‹v­v¨‹Ú2Ø .vi4¡vi4£î֖ÿG[îÕV‚û4:ñ÷ktâÐèÄ?¨}s\ÓV¡Žj«ÁcZrÈü¼8¥½Ó@/«kèµEb-ïú:ö4²§‰=Íl¯Gá§µ àm#xVÛžÓ6ƒçµ-à­¼¨mE —´/„̟׵‰ÛûCÑÊel§7åˆ|8Ú¸ÃÚéõC¢ƒílwrÊ]Ì.ænε‡¹eßÐöÝÚ~ÔvS;ÞÒ‚=Ú!ð¶v¼£Aš»ÚQðžv ¼¯h'À^í$اBÊ~í4ì‡}Íð‘vžÇÚ9ØO´óàSíøL»>×.!v@» û…vÔ®‚CÚ5ð¥v|¥Ý_kÝàí&Òk·`¿Õz@WÿƒùQ¬{n#¦P¿ßTý.8M¿é÷õ?0¿(0ŒïbˆO×@þœ˜©{{¹‡ú«B¿­çˆJäˆ*’ÍBÞ†l*ór=¥ŸNý!’Ö€º˜§?‚g¾þ¬ÕŸÐi¤?¥ÓH.ÔŸƒ‹ôp±þ\¢ÒY¤ÑY¤¿—é¯ôýób•.^Ãø2—70¾BÃä½ù_ä°¾^wÞò}(½¢h¢˜Â¤W™‚†ë†ëF®Œ›t:ý6ë\}t: [ôB.$úTp›N³r«Nóñv}ÒìЋÀ6½Øóž9£Ä*¡—‰RuÉt&Y:Y»t:³ºt:³vë3PàPÇÀ9€)pŸ^æ)ö˜yâ î¡ Ê!4%"sÜ4("Žêåžý‹â„ŽYÏ3Qùi½Â2¿&*=WIo>U(ø²>ËC'z57a6sއN÷¹Z%Õ°gèH9ŸÞ#j•¨c±€¹¹ˆ¹˜¢Åzõ‘XÊžzæ2æræ æJæ*æjfs s-s³‘[ÑÄv3s=ss#ss3s ³nÃV»ÛÀo‰V.g»‡® ;Ønc¶3;˜;™œwÛ]ÌÝìÙþœØë¡³s¿‡Îøœæ §9Nâ· åÐ+…Ä7ÄQtÿýxU?Ž^¿¦Óp]?Ï ý$Ø­Ÿoê§Á[ú°G? ÞÖÏwôóÈuW¿ûž~¼¯_è—Á^ý ا_ûõkàCý:øH¿>Ö»Á'úMð©~ |¦÷€ÏõÛà€~|¡ßõ{à~|©?_é½àk½|£÷ƒÃúCð­þt=Á)ž'`¾ç)XàyzžƒS=à4Ï °È3{†ÀÏK°Ôó œîy ÎðиÌóv¹gœéy Vx¾2?³<>× bPæt„ e…lOeNcþ|Èü% cÞë‘z± JTPj„ÌoÈéÆ\œaàÊìùr…ÇüeŒ=§Ì ÃWΜI¯þá—Ù¢Ò !^eÐ?å¡!>Ë !^ .ñÌ—zæ4Äç4Äk âó âó âµ ñ¯…Ì_ÁˆöÕ¡ÔXÀ\È\„†¬ó,=KÀ&ÏR°ÙóCœ¸­_½¡a|×:Æ÷2Ø›Aã{9ìÏ p«g%¸Í³ÊÀ¤ðM èôÕ¼ Ì5̵ÌuÌFƒÁM¯˜šU°Þàõé 4}#ZÐîÙ„b;@\¹=›aw‚˜›<[`w˜›<-H¹Ç³ÜëÙîó´« ó[8¼Ûùí`¶!Ï!Oòæ9눇欣žv#dÿ†8á84ß—<ÖN¤ÿ8)©Sµk— ºý´g7xÔÅYÏTvγ<ïÙÿP=ÿ†n»íñïGÄUÏD\󯃺¸á9»ÔÅMÏaØ·@]ôxޏS>j<ðhÇà½ç9ï}Ï/tæwáôüÔq4ä«âó$ø5q œœ”tÚ ‹Äå!ÏÔúÒs%¼q¡ñœƒçç<8ì¹¾õ\]ã8ŸŒ”ùÆØÆU°Ð¸N5®ƒÓè%;¢Èè‹›`‰q ,5zÀéÆmp†q,3î‚åÆ=p&½íc÷Xiô‚UF8Ë談hmfRÒ#ˆÙÆcpŽñœk<¥óÁxfü‚ùÛò¹±Â Ы†Ä ´p¥ñû²ÊÄ>®6†°íÄ4m¼„½­Å4m¼¢l¼¦l¼¡Œöcš6†ao@û1M£ý˜¦·ðl6\/.œÆ°ÅÈ÷bè~_´VWˆB¯˜ŠàSA/ ú¼ ·… Æí ÆF±ËKƒ†Q»AèàKßN£Ä›ï5Wt²§ên£Ô‹ÁpÈðLG%ûŒà~£ <`”ƒ¢Ë¼y3!Ž(ô˜Q 7ªÀÆ,ð¤Q ž2fƒ§9àc.xÖ¨ÏóÀóÆ|ð‚Q ^4êÀKÆð²±¼b,¯‹ÁkÆðº±¼aÔƒÝÆ2𦱼e¬{Œ•àmcxÇX Þ5À{Æð¾±|`¬{F°Ïhûfð¡±|dlÁ'Æ&ð©±|flŸ-à€±|alVpÈØ¾4v€¯Œ6ðµÑ¾1:Àac'øÖè]ï.pŠ· Ì÷î ¼{ÀBï^pªw8Í»,ò‹½Áï!°Ô{œî=ÎðõúÌôü1/VƒÞã`•wlÈü½ZžðžôÖz/jôš!Sœ¦ûˆ3ôÞq–yŽÞ$èmC/èuC)â"økâ’—§úË*¸BïW™×È%®3o0»™7¹¼[Ì/ÍV·™w8–_:$è­C˜‡î«à zUЇ}™çíWâ!‚o‹GàcoRÒ®˜Þ?”+žqÏÙ`¾@ÆùÞA¶‡Àô$ñ ²Îû± ¼o`/ôÃ^ä} .u±Äëú4±Ô;¬÷æƒË¼àro!¸Â;\éæÃÍ¢—V®«½Eð4x‹áYã-½Ö[ ®óNA]4yiÚìÏzoRn𖃽3ÁMÞ p³·Üâ­[¼³À­Þjp›w6Øê¥{åí^ºWÞáO›—î˜Û½tÇÜá‹’w‚ºèôÖ v—w<] .%ÞùðìñÒ}ù^o-üû¼uà~ïøxÂ>è]ò.†ç°w xÄ»ž£Þzð˜wxÜ»<á]ؓޕà)ï*ð´w5xÆÛžõ®ññ “¹ŽÙÈlBì9o3xÞ»¼àÝ^ôn/y7—½›Á+Þ-àUo xÍ»¼îÝÞð¶‚ÝÞíàMïð–· ìñ¶ƒ·½àïNð®—žÁÝóv¾ï¥'q¼ôä«×KÏïú¼»àï÷Ò“»‡Þ.Øè…S{À'Þ½àSï>ð™w?øÜ{ðÒS¿Þƒ°½ô¤oÈ{öKïað•—ž²½öÒó¾7Þ#ð {é©ß[ïQØ®žýMñѳ¿|=¹+ðÑ“»B=¹›ê£'wÓ|ôÌ®ÈGÏïŠ}ô´®ÄGÏK}ôŒrºï˜F½8î£A|…ÎðË|§Àrßip¦ï Xá; VúÎU¾óà,ß°Úwœí»Îñ]çú®€5¾«à<ß5p¾ï:Xë»ÖùºÁ>z÷Ñ7Å-Ø }=8ü‹|·a/öÝ—øî‚K}÷Àzß}p™ï¸Ü× ®ðõ+}ýtªø‚«}Àz‡Xã{®õ=×ùž¾ç(¿É7»Ù÷‚NP|ƒ°7‚X¨ù†`o±Pó½„Ýêb«ïìm .Z}¯aoqªøÞÀnuÑî†ÝbÕå{ »ĪËWB«.§ŠÏõãŽÄ¡o ì} .öûòauqÐWûˆ—¯öPG}Sau§i°O€º8é+‚} ÔÅi_1ì3 Z¾Øç@]œ÷•¾b¡å›û¨‹Ë¾°¯€º¸ê+ƒ} ÔÅu_9ì .º}3aßu§ Ø= .nû*aßuq×7Ö^ Ö^¾*ø€ºèõÍ‚Ýê¢ßW û!¨‹G¾Ù°ƒºxâ+@Þ§ .žùæÀÿÔÅ€o.ì .}5°‡@]¼ô̓ý Ä*Í7öPþZØoA]¸þ:ØS@]äûÀ.uQè_{*¨‹iþE°‹@]ûÃ.uQê_{:¨‹þ¥°Ë@]”ûëaÏuQá_»ÔE•9ìY .ªý+`Ïu1Ç¿ö\P5þU°çº˜ï_ »ÔE¿öP ýk`/u±Ø¿öPKýë`׃ºXæo„½ÔÅ ì• VxþfØ«A]4ø×Ã^êb­ìu .ýa7ù7Í~zª¸Äø÷oöãRáßâ§÷Sµ€›ý[ýô~ªm`‹¿é·ú·ƒÛü;üô~ª6p»¿ÝOï§êÛü;Ûîï„Ýáß{§¿ v§·ŸÞOµìòïõÓû©ö{üûýô~ªà>ÿ‡XÊÝñ¿{ÙúÁuÈöaÿØGüGýôjªcà1ÿq?½šêxÂÒO¯¦:ECßÚO¯¦:žñŸõÓ«©Îçüçýôjª àÿE?½šêxÉÙO¯¦º^ñ_õÓ«©®ÑÐ÷_÷Ó«©nÐÐ÷wƒÝ n7ü7ýôjª[`¿ÇO¯¦ºí™,øÓîøi p×Ïšü´L¸ï§Ö½×ß‹Ä}þ>Øý~º˜?ô÷Ã~äÿcÿ#?½ê1øÔÿÄOo§¢ õsÿS?½êøÂÿÜOo§¢›ì!?=æ~é@åæ—/üoýŸôÓÚjˆÛðÒO –W(ß5_#דùæØæ0Xh¾§š®‰Už9ÅÄÁ̋ͰÄ,KÍ©àts8Ã,ËÌb°Ü,gš4;W˜ôáF¥Y O•I‡Í2§Ã®6g€³Í _DÌ1Ë`Ï5ËÁs&8Ϭ盕&.×oD­9 ¬3«Áælp¡9\dÎ›ß ™&êM ²ü ÀÀœ.7kÁôŠ)±Ò\®2‚«ÍE`ƒ¹Øð›.Ö™z…‰õ¹lB™Ñl.5¿gþ¥ØhÊZÈ æï5ÿ‡ØbêQÅ÷Q« íÜo•ƒ¬™àA«¡ûôéÎ9˜Á;‘A#{wm_¯½¶ÖìxÃuº¶×¾žõ¬dãµ½¶×;Þõøóµ-rF€ÈQ"#!$’‘3 ¢„ÈHr û¼%XÏÜßw¿ß÷‡žz»ê­ÐoU½õT÷QוD9ðjb!ðZb°3A‹|W‚–ýë Zêo$#þfb ðV‚öî-õ¹ÄRÄÜN,ÞI,ÞM¬ÞKTï'*D“&ˆ&?JM~œ šü$A4¹'A4ùi‚hò³Ñäç ¢É½ ¢ÉÅ Ñä! Ñä¡ Ñäa Ñäá Ñä Ñä‘ ÑäQ ÑäÑ Ñä1 Ñä± Ñäq Ñäñ Ñä Ñä‰ Ñä…hò$…hòd…hò…hr©B4yªB4yšB4yºB4y†B4y¦B4y–B4y¶B4yŽB4y®B4yžB4y¾B4yB4¹L!š\®M^¨M^¤M^¬M^¢M^ªM^¦M^®M^¡M®Pˆ&W*D“W*D“«¢É«¢ÉÕ Ñä…hòj…hò…hòZ…hò:…hòz…hr­B4yƒB4y£B4y“B4¹N!š¼Y!š¼E!š¼U!š¼M!š¼]!š¼C!š¼S!š¼K!š¼[!š¼G!š¼W!š¼O!š¼_!š|@!š\¯M>¨M>¤M>¬MnPˆ&Qˆ&Uˆ&7*D“›¢ÉÍ Ñä…hò1…hòq…hr«B4ù„B4ù¤B4ù”B4ù´B4ùŒB4ù¬B4¹M!šÜ®M>§MîPˆ&ŸWˆ&_Pˆ&_Tˆ&_Rˆ&_Vˆ&_Qˆ&_Uˆ&_Sˆ&w*D“»¢É×¢É7¢É7¢É·¢ÉÝ ÑäœB4ù¶B4ùŽòçZüg|eâ‰bWaÜ÷(±Ô?UVa>bd+Õ{Ùj ä!@Œlu5äa@Œlu ä@Œlu-äQ@Œlui¢£.ŽU—Ç©+€ãÕ àµ8Q]—ð”ÏèØ¥õ‰ÑRü_ÙTU¥³ó^aâð<¦ãó†Ëpsäùë´òÒÙy[Œž¦NS·&èP&z¦:C¥gª3ÕmhÁ, Æ»º=±<ÿ76O•wÐY{ð~„» 1_Ý*•R&ò—«»Ñ–g‹U¸ÄPü?Ø2•ÿX®î¥¦ý'«Tõ}Âíx@`½@:wÏM>ŒâWª‡Q|•Úy0̪Õ#k€a¶Z= y 0ÌÖŠ&¬MX¯6&°-ج†›tS3´6©- :©&„F ¥Ó—Ìc z{\XFU[Å=¦9 Õíê)dÛ ³êiÈ»€a¶[¥*ì†Ù^õL‚e: ܯ¶‘·ͨÍ8(,yH¥gÒ‡ÕvXe8œ¼ÊÎ%¼øÎ;-j伨•óÓUõ" 8¦^BUÇÕË[Õ+È4ŠÓKW!ƾC…«ö”1œNTêL|?>» U¼T¿ ÒKõ‹*½T¿¤vAküº GîÅ'€Î¨üʼ®xñ‰àIÿ¦¨û–86¢[¬ 9à¯1q £Óï&xŸ|œ|œ˜| ,I>NJö àÉɧÀ)Iú%@iòä©ÉçÀiÉ^[IúµÀŒd±b3“C€³’C³“Às’Çäå[ñI ðÉÐH\—%GË“ðíJ¼¼=©ŒUè Ó8…Üx$.MNPú±eɉÀåÉàŠä$`Er2R+“SPøÊd)°*9¸*9MñâÓÀ’Êt:LQÕ/™/ÂY/ÂÙ ý¾hŽBlt®Ày@GUç£è5ÉÀµÉ2àºd¹RŸB‘L,TèG7‹PÕÆäb¤m‚ÍÞ`uIúÃfX[X[X[€$uÙöähîH.UÊ•ø,0‰dˆÔ÷ŠÄ}ÉÇP>š”—A§>¹%L®¿&+ 7á_“?؉Ïá¼R9›ÔW*ô®ŠNü q,àobåÀŽ5YlO®žK®AÞŽäZÈç“뀒듵ÀKÉ ÀËÉÀ+ÉMÀ«É:è_Knv&·(?ˆÏHÊ[•7Øä6˜ýnr;ôî%wï'w"æArR&‡Ó‹žùœ=IªtTà@,$â¥:ðŸ°`"ªê~”Û“Ü;yš¤ùö,Ióíy’fTo’fT±F3jˆF3j¨v@ ÅËÀˆµD=u Öχ€ÉÈãŒÔ£ÄQ@xQ­ò øvò8 øæxñ… i’v„UèS£BOä›zµÐ¬_ÔÒÃ}MÖŽ#÷8R©FF¦jÄš¦iÄ—¦k­Ð™¡ÎÔNgi§€³µÓÀ9m,æjg ÏÓ΢œù@øO­Æ»ÖNã];\¨u u‘vòbíp‰FÏç—jôd~™v©ËµKˆ_¡]†\¡]¡¯]®Ô®«´Nð@8M|uF¾zµÖ…ø5ÚuàZ 8ƒFO¨Ï×ëTOY…UDgz+¯Æú »›é«›l‹J?îÛ üØ/õþv•ž¨Ñ³«åúØ·B߉R+˜D:ý*· ˆI¤ïB|5“H§°Z'Z¼F§Ÿ5¯Õw#ï:}p½¾šµú>ÑÆýˆÙ nÔÿÖSVcé‰zUüÒè`_pAžªF®-úa”¿Uo€¼ fÛõ#È»C?Š˜z#ä]z“êÅ×bNérEŒêh]ºS%ÚÞ"j=&bè(¼?ƒþÓø:Ì]9!ÒN ½S"œÍ~œÍý4j¨b!ÒC>¤ŸAm‡õ³à úð°#úW=¥–ó6õ¼þ·íbLØ¡Šßœï .ôû‚K¤!‡/S _pU¥ß ^yé SЊ.•~It]´û†À›o ì˜x[à‘™hèý.ÍSýð’~-¿¬?^ѯê€×ôÇÀNý °Kï^ןoèÏ€7õçÀ[À0ëÖ{!çôùÀÛ@,SzqË”¾1÷ô!ïCÆ2¥MbžêÃóH|¬Ï…Î}â{tÚ£=ÕG"þ™> ø\ ìÕÇ‹ ú¹Ác,4‡Dj†Dj†ã:ÂiLŽb™2&Bc”@¬1 8ΘŒ˜ñÆà£8f%ÆTÈ“€a6Ù˜y “˘y*“˘¦33ŒYÀ™½—šĕ<Û˜œcÌ…þ\cäyÆ|à|cpQ,3ÊåÆBàBcp‘±¸ØX\b,.3–—Ë+ŒÀ £XiTW+UFp•± XmTkŒàjc5p±¸ÖX \g¬®7ÖkZ´mƒ8ñXŠŒþ’´¥ß˜$¼))|Ãýn5:À€·“£Ø_S€;Œ:dÜ ;36CÞmlA{Œ­À½Æ6à>c;p¿±xÀØ ¬7v»‡ rì‡'ÀcbŽ{G}ÀFc?°É8l6ê-ÆAà1ãð¸qØj4OG€'£ÀSÆ”vÚ ÅâŒqòYƒš6£(ˆ×a_bðS´6ß)ŠoÆšcHô‹˜Kâ¾.(áŠÈ{ÕhJzñ­œÝ2"ÍIá ’ÄßiÅ¿nЊÃ8í›Fü;ñíœOæŒßhMÒ„Oû3:ôkŒÎýcF‡‚bZžé Î"؇ÀΉ±aç$f¾Àó(õ¶A¼c\ Éb\DÌ=ãð¾q1Œ+4YŒ«ÀG¹ÛÇýç 0ÌzŒçòì)0Ìž× óÜè›]À!æuà0óp„y8ʼ•|ƒ6»°¯c>G½cͺ$6Åf7RÇ›É~l‚I{¢™–˜·“Ì;ÀÉf/½t3ïB.5ï§š÷ÓÌIzGö¦†ùˆ¦†ù˜¦†ùíŸeöÐÔ0ŸÒÔ0ŸçšÏ¡ß”dôndžIïFæ›7Ñ”f/ͳX‘3‡h˜!æPà"sbÃl‰91KÍ·&Iñ˜¦7B£ùŽÔh 8Z¦§3C•Db¬F¾{œF¾o¼†Ý½9XiN®4é×¹Uf äUæ$`µ9XcÒÓÕæVçRÔ¾Æ,EíkÍ©H]gN®7§£%µæ ÈÌ}ðòÍ™šßCn¾ÎŒÏÒègdzE½ä7›ä·˜ä ·šä·™äã¶›äãv˜äõvš¯xñ}˜P¦›FOiÙ3±qü~¼ óÁŒn}¹U =µz`ÒSއ&=µzdnC MzúñÄÜŽrZ0ê-l,½øqŒ|‹ï&Ý¥íÐâ­œO ±»5úÅèaå½÷‰!´_È„\/dú¿±ýÇÆ8ë Äxët’ šdE‹‚¡“A±í$–ÔÕÉež"2—ZM”í4e›iIÍ¢†‘”f ¥ÙÖ1R:KJ ,ù¸HnxB4æ¤FOA(C™ÈPn¢ í”a±9-TÏÕ³tøªP]"T—Zm¤ÚAª+¬X»P='T;„|^à~ë"s¥u‰2_ Ì«,ù²hý¡zU¨^ûy†j‘¡ÆêÔviñK”a…®§\‘³Ø1^wYÒutÙ6댴ݺ ÜaÝî´þ‹_å¼[k² :÷”aãKxG m©ê-ÚL´îBýëä 6þÖ}ÈGØø[ô²©Ù¢—M-½l:fÑ˦ã½ljµèeÓ ëGhÏ9+ò€F¿õF¿õˆF¿õ˜F¿õ„F¿Õƒ¡t\ÉâOi¼[Ï´=‰ø j+ü\LžÙ‚UÒã£kV¯6ZŠßÄȶôb:`’ÎT8,E–.p„À‘)*kd*ÌnZDžoYDž»-ú'·0Ìn[£R˜ö»=˺gm¿om¡gãÝX,}´(~ŒÀ±ljâÇ œð󪋪žˆªzDUOEUÏDUÏ­‰¨ªWTUl‹Çf6U5Ô.IyÊmÌ+›}#?~‡³Ñ¶IÛ¿16­acíI©7Ø8›V—ñö©Äl‚MT¢M|¢Ä&1É&1ÙžŒFL±iÍ.µ§ ²©v)pš=8ÝžœaÓê>Ó¦z–Ýy¶==õø=ð*›Óõ|{FêÕø}Œ;1SÜZ'ƒ-´g¡ìE@ìþíÙ(i‰M7²TÜÂ2q;Ëmú‡§6= ¬°ç¤¾NeÇæ¦Ä£ZóSÔ™ôœy•MÏ™«í(«Æ.®¶É嬱ËaŽÇ`W6ûG/þ[[Z˜[FÑœÅhÈ&{ 2ÔÙKÑÔìüíð2¤½Ê–#m›½Ün¯@1ϰA±Yšòûw["ÿVo“;(*;d“g;lszJé…—·C•0v“0v³½ùŠCì„"ÝãB·Õþ'->$Ä›äv;^•¢©³ hÓ‘µÌb5hÀ9» è°WC> ³ 6=ù»hÓ“¿Köš”n³µ†Ãí9l¤‘`Í[ŸÂ¸ç$kSä6ÿmãn0ÍêRôš„GNq:Pd©C¤jªC¤jš³ÕNw¨sf8Ô93êœYŽ_¤Œ ±Î[ýè\ÚvÂŒeÎv`¹³¸ÐÙ \äì.vöƒ¹,qö—:û€Ë—˽W8»aª ‡LUéDÌJgrU9{«b@ÕÑgõ®³¸Æ9\ëÔ×9Ä^×;!×:‡€œÃÀ=–ØäÔ£Ì:‡Fêf§ñ[œ#À­ÎQà6§¸ÝiJmÄÇ…x¥²Ïqéqú~§ œ`½s xÐ9<ä´;'€ ÎIàçð¨sØèœ69gÍN°ÅisÎ;ÀVç<ð„sxÒ¹<å\žv.Ï8W€g«uã1v £gBˆ]pÂ)z•Ö…~¹èˆwANú;J v€Nè:lxUØðšó“ > þÊqn@ÿï¾ð$è¦CO‚n97QF·s ˜sèIÐm‡žÝqˆ ßÝuOt×}ÑED§=tè©Ð#ÑE…9Ÿ8Ý(¡ÇÉ¡ÅO…™Ÿ9·!?wî‡rìŸ(SB äCÝ~wÅ|½'ð¾À›hñ0—¸ëp—¸ë—¸ëH—¸ë(—¸ëh÷tƸtWc݇¨j0ÌÆ»Ø)LÂ{¹_â’‡›ä’ß™ì>FåSÜ'ˆ/u7cLu{È{¹OÉ{¹ÏÈ{¹Ï3Ý^à,·XǪîÎq‡纷Sð3îà|—L²À†Û-s‡éž2îËeÃuÁ`©p¥zˆ-uGèa¶Ì y90ÌV¸£ôP|zˆ­u£ur)c€ÿÌèlà„p/U.¹—Uî8䩆Y;òj`˜­qi¡ZçÞM|?>»B7>Ž#f–è/½ßF—¼ß&—¼_KÞo³KCc‹; w²Õ¬Ã ÌÆÚí¦¦ˆªKN8Màt3ÎÔ‰»Ì¢C€ÙlÑ4i§;MÚåÎ…¼Û%°Ç%°×%°Ï‡[‹åÝΧ£Ù~¾Víz· 9ºåÁÄqßó”ù!ÖäÆ"©Ù]ˆ¤wäcÀ0;î.†Ü ³îq¿t6±É–õYP÷âe!vÚe¿ —[bmnh…þk£åœ[žZ¢¯ªW’…Ø×Z©‹WåU:M£U«Ö\­÷ý×Ñ;ê«.½£¾æÒ;êN—ÞQw¹´¸îÒ;ê.½£¾éÒ;ê[îZ4·[Ø&'ls[ØæŽëæ+K°Qt­u¬×ééf­N?¥Û úr£ÀM"µN~3X˶Ü*R· Ü.bh?tw w¹äß»;!?qw{Ü9ØÀ½MkòèmZ³×­/ÄW…ØqOΉIs[ùȤգÕý„G#õ¤G#õ”w­© Ñ7Ñïê߯ƴñ"÷èdjv­=çÝG÷uxäVÎ{Ä].xc-æ”Dz?¡o¯tz‘‡°l—°ìu|û ¯xÓ#Ÿ|Ë{„ ëCì¶ÇëXikCü‰~Ï‹õˆÿT ›g¨ë¾÷ u=ðžC~ ³G­Æ½^äÞ ï(1lýh1Ô–‡o°g¢ÒçÞPkŽ7 XìÓê4Äy¨?Âðâ›Bl¤ÏF¡x]ˆñ££èX`6Ú þ¢>ëÓ“Îq@,/>õן> 0Ñc|?¾É_>˜ì5àN¶b ûÉqѪñѪ ™y"0ÃJŒ—´jºO´j†?ɱ™À0›åO†<Û'óÏñÉüs}róü)†§l±2Ÿ•¢Á;B|ª±È7§DU§ œA÷ ÏÄ]-öé#KüY—ú³Ëü9Àåþ\à °ÂŸ¬ôWúeÀ*¿•¯†YµOÁŸ6‚«ý…H]ãêÅwa\û¯Ð Í¿Çèˆfú¹Òì¨êÒ¾€NjV}g5'tZsTU+ú®* ™<èJ ¢á* äð*C8ZBU­AEµþj4c0Ì6úk³É_ ¬ó×7ûë[üZàVp›Oü`»¿òp§_Üåoîö·÷ø[{ým°âL,Ÿ}Ù‹ïŬñåñ±ŽV ñññ¬ýˆ·SËÙdÛbG|¶“úw?¦’oÑqÏ£óžlÀ½"fŸ÷‹~'ïÔì“wjñஎ±zùô¶ˆ©æ×#þ$0ÌNù!Ÿ†Ù1Ί1Ð&Æ@»ÿ%/^®ï‡‰*hÿ|Á§ýóEÿkØ?ñíøË+~J¹ê^ó;ýF`—ß¼î7oø-À›þ1à-ÿ8°ÛoæüÀÛþIàÿð®xÏ?¼ïŸ>ðÛ€ývà#ÿð±ßÑÅÏ“B¬8H]0hÞ^xIØñ²AüáŠA"lC"lC"lÃ"lë(p‹Mp ò¨€ 1: CŒ ÈcƒNTw“0sÝ7bq ¤.C¬Ï×i²;`›“ƒ{À)Á h7aJì¦Ç׌ÉÈ·ÄŒì6^:¾Y9¾Ù¢²9¢²¹A3íXˆ-ØmHÇÉõ¯¤;ÈóQßo¶*òô•yú•Á](±]»éTˆí Ø}H§ÑïË|'~>$­<€S*N“S’&R<4]ídž¥Ï‡§ÏG¤Û€#ÓíÀQé‡èÓÑéGÀ1éÇÀ±é'¸¡³ØÅ¥Y}O”Ÿ'J‹Ï¥Åç‰Òj*~ ‹i:6U´yšI#°Ô]JOG«¶ÃlGzä@0ØôLTº;½!äů„ø,s_ÚŸ\ÿÆæK 6W´ožÀù&- D¡eȶ?]<^¬O/L/J/N/6¤—¤—¦WÓ¨¾)] lN¯¶¤é§kÇÒôÓµãiú/ËÖ4ý«Ì‰tôO¦W™^ü&vš}Û‹wb>§ƒjш:Ó™­¸ÆI¸Nàzµ7Ü(rÑÓ –"f³·y«¸ÉmBÞ.p‡)>^fÒoãèg7ÒôC›iú)É­ô.4®;½˜KïÞN率s®#ÝgÒR÷›‚^ÓX¸/ÆÂ1¦à¶Ãìqº·w5ÍþÅ‹ß ñƒæÌ׉¦Ø nðˆ lÝÛ$°Y` ðcvLÈÇMú>`«ÀOŠÛ9%ð´À3ÏšDéÚèàfÖŽ[š¡C£¿Æ: ËÐüá™óhê œSæäQÀ0¹y 0ÌÆf.AUÈ\†<ª¹¹f“2W!O†Ù”Ì5È¥@pà }PpZ†¾-8=CŸœ‘¡¯ ÎÌÐGgeèû‚³3П ³¹™.Èó€a6?sò æmæär`˜-ÌÜ„¼f‹3· /†ÙÒL7äeÀ0[žÉA^ ³ŠÌmÓSr˜vö‡Züvˆ­ËÈwÄȸ C¬Ï܃j-0Ì6dî#fcæpSæ!²Ý…ͰGîa‚eØ/yñûpˆ™×>ÿ¾E¶oy},,ÿDÌ¥1䞊>}&Nºî5s`ˆEºôÍO… ³0Q3ôE=™á‰˜z 6˜™iq¬õ@0äÌ(ämȌɌÍЗ®3c!7eÆ›3ã-™ Àc™‰–„å:黋ÑŽI'CãD†¾v2Ó‹¡ûËw&6E¤•§Zlšq&3Šg33€m™™ˆiÏÌ‚|NTÑ‘™m}?Þ^‰Í±Ä÷Øγ^nã/eh9CÛø+ÚÆ_Íß¼–™o.? чL2‘–ø> }“äF†^7ÞÌÐ7IneÊPKw¦Ü ÅŸc]ÏH -òÙ‹ÐŽ»™E0н ±Üûë'J18u&A»ÈÇ™ÅÖìI†Vªž qö§bëÏ2ôüãy†÷ôfè}lqv *’] š]†j††Ùˆlb¹¸é@ì>2=2[‰ŠG1s²+!bædÉÛË’·Ÿ­²¾f%Ùð*Ñã—°y¶5LÎÖ mT˜•f9ÅNÍ®ÆõhL™¾ëÙ5¸2Ýw=;ûŸ¿æk­šl¿u¢kÖ[4Ék-ÁJ7ôôÝ“ÕYúîÉšìF4j-KMväõ@,5Ù: Þ3»¸1KßÙ”Íë²ô=”ÍYúâÉ–,}ñdk–¾“²-»ÍÝžÝ ýÙmwf¯!uWv; ßìeÈ{²; ïÍî„ξì.àþlâdwC®ÏîAêÁì^à¡ì>àáì~¾Ù–§Œ³;ôõ[}•ýe¤Þ2ÂuÐ2¤Á‡,#òׇ-CþaƒeDÿfçG,úú{¢—ÇBúk´Xè-Öd±ð[¬ÙbR‚µX,’ÇŽ¡ŒâÐq2$ÔŠR††N ˜a¡Ùð&XÓC¬ î : µõ¡SP« êPµ…"§-™÷‹‡ÏXrÁY”ý‹¬ Ší¡v(ž£O%žÃå°ðX8Ãp¨ê…ì<´ Á¿Ø²°t1úÓ÷øEÄé+Þã—,9¬?_¶dI/~ŸW„#WHeèûü*©t'ù5R©xw’ÊÈ÷y—%GôÑïóªpè:©Ž}Ÿß Õñïóš0}®¯[ápè&¥M|Ÿß¢´IïslN„£Ý–>ÎÁ@_a·ÑäSá;0Áéð]ëËìnèËì>Ìq&—`ãmYB0Á–#· 6Ñ–åV&©¡‰È®/ÀKP€^1€—ªô#ÖEjh%¬À'Sª|©Ê§PTÍ^¡² *ýpóˆ.¥¸5øTR[7€_!×Wج²“j|¥ÖàÓ)uã> Ôëð™h¢¾eŸ…FêÛðÙh¦¾µ;r”J›ãÈ1}×>בãúžüŒ*Í£¢öàó©¨ýø*ª~/£¢ àíªüÿ× —Sm øy•]UùB*øèÞ¥²[껋Æßg‹a机f¾­.E…c ¶ õ]K±å¨neŠ­@Ã;ÁPRW˜U¢Ùwu¶­FP…~¹£®r ù®Z ;ßSkÐ}÷ÕÕŽ ®qŒÄCu­c(ÔuŽ¡>V×;Fò‰ZëZºÁ1ROÕŽ¡?S7áæ«s 㹺Ù1Ì^u‹#'ôkøVGVô®|›#«zu’owä¤~Èæ;Ã*Nît {Hr—c8C“»Ã–<¥ÞðäÇðG$÷:F02¹Ï1Ò£’ûYóØÇÈŒNÖ;FvLò ÃRï³CŽñÊØäü$[”Œ†yðp¬0@ $ÃGa…Z¸V 7Á ôp3¬0À·Àv‹“5IV›d»’‰c¸Ü<îÐÒêÐr¡%ä$Š(d§PB!; Ùä/dg©ëYu<;dMI¥%4'Ï¡3Z’°í±äyØöxò‚(ó",Üš¼ ŸH^†…O&¯À§’WaáÓÉk°ð™äõd´ýê±.Ñ€ë(ðFò ¼™¼‰o%o¡Àîd7ŠÊ%'ÙpçhT”|À'j‘Û$ˆð;4òî«ü.¼ÞþüžÃ$ÝGa%Ú™Tø„³©‡(µ-õ¥¶§ž¥X±NoÐ&éôrªL—^ΖÇTÔ¬ø*jμGLÙEzô)šù/}ëÂbý™ÃBªªÏQä½×aá½QÏ sÿˆ wÑWfx„‹¾J„Gºè++<ÊE_ÙáÑ.úJ qåhëʱ<6¹›ôñ.‹·ªl‚ 3ëQË1½µ×'¹0°>Ù…õ)®œø.+ueå»lª+«ßeÓ\˜\ŸîÂäú &×gº0¹>Ë5’gõÙ®¡µés\#Õ®Ïu ýœ>Ï5Œ}“šZ댨n³qΠÇq]ë6B£±Ôþ +sYh@4¼Ü¤'»ÍP¹ÛÇI"×ó°ÉAh0±Óƶù’ɰ|iÛ+4ûán›ÒbäB)`l¡rx ÙC /%{8aì—¹4€–»‚ט±†VosZôܬ€zÍJ ØZ  ±šCFl¨U…Ûf­Âí·FZl´Å&X¡j´e¢UƒŒ%ÖT+L—Ó¬Õ¸œN‘‘Öœ¾È¹Bgžµ‘ó­…§ÈEÖ²>a¹µ²O¨²V[l•X‹æõ‹Èëо„^Ö'Âr-ZŸå Ð[omDqµÖ&·ÁªC[7Z›ÑÖMÖtVµÕb{¬ÄV—Ö‡m.­Û]Zv¸Lê[‚öZ;]ù1ÛåšÒ>‹ŸýÖn—É!ŸÖ) L8¶‡¬è…÷Ò¨òÂûÈŠ~x?Y1À¨Ò'ؼÃJ¿ð?ˆq¥_ú€Bû.XW,Öe±‡nÿ|¡8Œbôë¯ñ”£Ÿy²#G¨sw$øQÑ.¹‡&—ÜC³Kîa®ÍÊlN´Îµîø1*æÖ|ƒ ê~:N ¹x+%Üù€ï±S'Dÿž¥ž¥ž¥ž¥žuÉé´¹ätÚÑܽö9L‡BÖáÊqì`Ú}öŒw¸x¿} £¾]†™ØGm° 6 Ÿ¶¯@ùŒ=Ó4"gí«Ph³¯ØÞ5”yÕîDÒ5» %tÚבÔeß@]·o¢‹nØ·0œnÚÝN·ìfO·}³'gßÁì¹mßÅì¹cßÃì¹kßÇì¹g?Àì¹o?t óýÈ5¬‡öc×°ÙO\Ãyl÷¸†ûÄ~ê^ýÌ5ü§ösמÙÅN¢—¬3s /öŒðPgˆgHÜ¡žá ó y¤3Ü3¢£œžíŒôŒøg”g$Æ:£=CçLpØ$‡aQã1>LÂÃL‡'x’nx"ʜ딠ÌyÎ$”9ßÙéÈ“=¢øS´Ë)EÒngªGý0 {œé¨t¯Óî¼9ÃC»ªò™HÔ«òY(R_=Ïö°d¯H“9B“yއñµ~ Ÿëa|mÈçyX%6 ü9A˜ïaeÜX…‡¸á:²Øè~|3YlL?¾…,6¶ï!…â<¾—†æñ}ÔÃòø~}1" ¾•ÇÝP=²ÐÿÎP޳.?åbVaêðCè÷ îe—Ýs“‡©XÖ@*òø*´$¥B'£*´47Q¡Óòx3uðŒ<ÞⱘŽy´ã8îÑŽ£Õ£Ç v'Qþ}wµÇ6zü•ð Ü-˜Í?RéÈìÎùY…Fo¡ Üû¬˜!íôæÅŒÈ.oXÌÀͶaÈïñÚ1ä÷zç0ä÷yòû½zÕ²3^ä<¼$_ ¦/Ëã©é+òø%jze¿LM¯Êãí»ìE®vu¿JÚ«óø5Ò^›Ç;I{}ï"íÜÛˆg9O¾NÚóø Ò®Ëã7I{K¿EÚÛòx7i/Èsd–yü®ÇoãætöÔc#|6Úçw¨„Ýy|’ϦúlºK{óø=*r_è³u>Ûï‡ïSBk–?]ð HuÊã}ÖàGQjCL©GóøJmÊã=Ô’–<þ”Zr{êËD¼ûvˆöU"Þ}\"ÞKeœÉ£G&2=2éõÙø Tì#W[â#×¹<^°©Ah(ÅV¾Ç‡Qì…<>#`óƒØpÄ*tç!…ôÍð‚`¤oIeÁ(Ÿ…?‚9ŒHy0Æ7ä…ÁX߈. –lU`Š^Œó ©&ÀúYŒ‡Îš`tÖ}#¶.(ñøú`’o$jƒÉ¾¡l¦ø†º1Hn J}C« ¦úFjs0Í7ô-Átß0¶3|ÃÜÌô k{0Ë7ìÁlßpv{¶?0ç …‚9ha}0×§ Å<ߌ æù–|(˜Ow¡( |3z8Xà[±†  ·ñ>+÷Íø‘ Ü·Gôžô>[äË-F³ƒ%hVS°ÔgØß'–ùf²9Xæ[ZKÐä/'£ëÇWÀh«ðåp¥ÏVúFø|PåËÒ¯±U°Á… Åý«µ.«a‰KÁXâr°–¸¬ƒ%®ëa‰kA-ªì 6 Ê®`£o$¯›`‰A,q3Ø KÜ ¶ÀÝÁVX"lƒ%nÛa‰;ÁXân°Ó7Ü{Á.ßðî»}YþŒíñ ÿA°×—£Ÿ±}¾< öûrì3vÀ7Ò‚z_ŽÆúFæqpÈ—Ÿ±Ã¾‘}4ø²ò;â¯ôG}YýŒ5úÆ«Oƒ&_N~Æš}ãµgA‹/kŸ±c¾ñúóà¸/§>c­¾Ñ¯78á˺ÇNú²á±S¾lzì´/[›½Ü+ž¡aVû!Ÿ”fóÒlašU¥Ù–4Û›f§ÓÆY2ëÆy)Õ}ÈÛ}š¥òsèœ< #|&}}6½¾›^L_…M/¥¯Á¦—Ó°é•t—o¦®¦»Òìnšõ¤CשÒúù ªôЇüy:r5õ¦o‰9Ðh…åÐ…ÝöM©8³2¹…ªÌ]tòªÌ=Ÿv:÷ÑÉÕ™hPMfm†mÎÄR¹­òGTîÉùcº™Óò' úÞ~¼ƒCoûc>Ëú¹ù3t”¾¯ŽNÒ/|È·eB½TÄÅyq€".}ÈwfØñ ;•a2¬+ÇÄ·ngøP:šøê‡üa† ÏòatÕù!Ÿ˜eS²lZ–Í̲9ټሆ3 hÄŽ ä°ÇF2ˆéè€Æü˜@–=66 §~ã9ÒÈqt]@Oý&LYc1x µÊb“–ež0 WS–ª±XiÀt\M ˜`ZÀLÓf!€O±Ì ˜£±Ys5: ÛÓTuNÀüßbs0šìŒ&K7çg熼 ;?0¢eÙ+Ï–F|av†m$eËCYœbê’,=T\š]Ú²ì¢ÀH-Ï. }EvI`Ù¥aVf—†µ2»<0ìªìŠÀpVe+íÎVrPÈVrºUr¦NLβ£Ù7ªÑ¤ÆlM`HMÙÕiήA“Z²kѤcÙuhÒñìz4©5[‰Ù hÒÉìÆÀPOe7Fòt¶M:“ÝŒ&ÍnA“Ú²[Ѥöì64é\v;šÔ‘Ý&ÏîD“.dw¡I³»û”ÝþåìÞÀ®d÷Fújv`d®eF¶3[¯teƫ׳‡ãµÙÃñúÍlC`ô»•=otgÆ›¹lc`ô¿=Â]þGc_áý%Æ‹øŸI,´‘ó\báçœÿ›Ä¤Y!~+$±HYˆ KL^â%]âÿ ±ØÚÿ‰Å‡ø‡K4…økSΆxRbê0ÿE‰%Ç„ù÷%¦Mó.äOM óëõ¥anHÌXæ=¸4W†ùS„Vu˜?Cho óW%æóÑ’ÄÜ£a>¡×æú­aþ®Ä‚Y’4 —é¯H,36"±W~YbÙ ‰ÿŠÄ^]-ñß’Øk›%þ÷{ý€Ä—C¡ßQ‰×!|£YâÛ¾yVâÛö¿*ñÿ%±_¸!ñ\~iV„ÿºÄÞÚá÷pùöÎ*Kì½>ệ#|,Â÷&ÊÜ”Øûb¡×%öÁD ¸ãHl`OŒ_‰I,¯<Î ü°2ÎÿXbùë⡲¸Ä~q!à—š‘?‘دüO‰}y ®¿ò=‰}u„_>–àÿ*±_mKð%ößî*\“د•¨üÏ%öµ)*_—دÏQùz„¿±PåÛ~}‰Êw#üÍ*߃ð·jU¾aÁ•7"üFƒÊkпݨòv\jRyS 3öZì„ÊÏ!æ›§U~áGm*¿Šðw:T~ á·®¨¼á·;UÞ…ð;7U~=!ñïÎKò‰ý÷…I>B‘øïV'ùhEb¿·>ɧ!üýI^Žðö'ùR„ؘäÿ.±ÿÑ•ä?Ø=Jò-ˆýãa³ýÉÀõ÷N§¸ó ö§œ=Mñ|‰ýYoŠÿ¾Äþçh/Q%öç%:ÿU‰}küë1Àÿs ðom€ÿu ðï[,Þ…ð?w[üÇ+æ'-þÂ;,þ#‰ Uã=HÆ;-þ ÂpþÀâ½Fða6ß‚ÉGÚ¼$%±Q|ŽÍ¿!±Ñ|ͧ#b ¯´ù cùZ›Ï0Ž×Ú¼Âx¾Ùæÿ(± |‡Í—"b"ßmóJø›W@˜Ä[lþM‰Mæ'm¾Søe›ÿ“ÄJy¯Í× b*/qBk!Lãë€Óùl‡¯‡0ƒïp¸/±™¼ÍáMˆ˜Å;~Âl~Ùá× Ìá]OKl./vùO$6—»Ü–Ø|¾ØåÃt‰-à•.¡Œ¯wù(å|›Ëïâ†òý.ŸŒ˜Eü¨ËçAXÌOºü=‰-ág\¾\—øRÞáòß–Ø2~ÉåÐXÎﺼ l ¹+± lñø×%V‰]¿Œ„•Øê„º TñŸIl?íñn\Uó6ßPƒý¿ a5¶ü„5Øð¬ÄÖbÀ!bÈ: a=îóA«å£|>Âø^âó‘ðxy©ÏÇ@ØÄçû|,„:^îó)6óµ>/…°…ïóù§ÛÊë}¾ ÛøaŸYbÛùQŸï@Ä0¾ÂN~Éç_’Ø.°þ5‰íKàHØÃÇü<„½|bÀ;!ì㥩°ŸOø Äàó~B=_ð„ƒ|YÀ›î/ ª~1‡øî€ß…p˜ï ø= üxÀïC8ÂǧyFbGyIš?AD#Ÿ›æ=šxyš„klæ+Ó|4„¾9ÍÑíÇøž4GŽóSi¾©•w¦ù*hœàwÒüÛ;ÉŸ¤ù^DœâÏÒ¼Âi^™áÿ"±3|M†&²³¼.ÃÿPbm|k†?DD;ß‘á œãç3á_’XŸhIì<ïEÜÞ™á³qy‘ç2|>„KüA†—C¸Ì‡e9Â+|B–/ƒp•ÉFþSb7x®®ñ`'_ ìâk€×ùÝ,?á&§cïy8̿ɘâ Ui~ŸÊoÈ¥FÎÕÈ…™þ½°§éPr_ Ja¦J”¡úgE¯æVË…¯þì]ºi”P˜‚½©IÂÂbH˜Ÿ’¥×ÀŒé ±A. DÿoÑÐó…æÎ"“ê÷cÏ{s[äB ;€î6¹P£ìÛû¢ÐÌÜXã£Üž¾î¼è~+·W.´¾„náè;wHn)´ÏWËz"wX.”p±ER®E~«ÈÉG!En®U.L˜: =!Cãx€¡çêÛp} ¥Qç[˜eÀ1ÉAOcL“z:§ûòôçš‚Ûb¨œ øw2áÑüWÏb°6æ¿Ö&çÎ~¾8TòZ®2·ƒkƒO…¯ :pø\»\øúû»#6•îÿV>%ž—¿„Û¸ðB…iñ*t¹+r¡‹8â ÝA§Œ1=ÉØÇïôgï¾ÛŸ}ë©øt—»†aü Êë’[ú3å®ËýÙOOè¿ñ¬èÁŠ€†D™ö5DÝ’ a±î/ÜÒG¹œü9UTN:·?‡2©¢è Ô„ù•{H5Iú@~Dä¡“GPׯ#îÉ˺zþºžÊŸSE]4ªž}>Ž:zHôãCVS¡ 74è%}Zäç†E }8 ÕBÿS1_hrúcƒ¥DXš)‘·%oÿNQŒ>hc?62J®œS°!?DÁñü0“ ‰‚ÖüÈhJë'æFG±ȹ±Ñ¦ÁÅÑâoEõ áËNäGK t2?6)š+‰F åA»Lšý±Ü$q‰)ó"&ž›-Œ5· :„„;)êŸÂL‹Æ_Ä’]fDwɹ™Qý{œé_GòÜh¡Ôç­íB$/ˆ¶ÆààÎÞÃìl)Œ‹ óU\|r&@Úp«¥|ÐÙ€Ó%ö]­U–Eu†2FûòiÔc‹©Â%Qý*¦òQ\WD #´<´D…UÑfÚò²Âfdlùb…#¬æÏUØ4®ÂUQ½Au´/Ÿ"«©Â5Qýg¨ž)·QÔ0ªþ¯èâs5¼,³¯†—õõÕ°)ª@°9Ú—OÜÒVªa[T·!ï#yB”FÅàE±Rç›pFq‰ò×R2,­i€4`€ ‹U±Ø7Di¹å b„„Ä S°+_jŽÒº9¥]>…àL~ô,‚³ù±N«²ñI±n>‡'¦ hËWæÆrG£Íƒ{ß|u-¹ä\c”|]sôã¯Rì ¯’«‹äZ`õÁ““Ÿ´ƒ¯ûÂ'zÇÿ¶æNF_,¾/—o9w ·ò¬ÕÑÜÙèÇßýÖwYñw1 Û0èZ~0_͵C(”~°@Í]#ƒj‡!…Na~Ìè¦Ú sAèS Õ”ðÍSÉ)¼, ÷óîFEŽþ ƒÂ 5BÆb!VKÜéÈd5­¹{PêÏ(ãý¨(ûsêÓÿK}Ô õ}ê(ýñš÷äÿ­yÅ1ѼÙÈ7,ö¢yÃc/›7"öùFÆš±„›äOF i/ÒÆÄ eã}¤Œ‰Jšñ—¤¥.BŠÜ«ÂǤ¿ Ýñ1Ñ–füýéæ&¡ñ>G R5%öXTi ‹ÓG!ÓcÂhz߀tƒûB0øb€¥6M^·R˜ ß—€ïÊ_V]¤èX²s³b-ˆ›O /róDU—Þ?´¸?³ˆÍ*&&%\ÐÀXŸ|2›þ:¹ƒÏé\ùœÎå>ÜâîæÅ2©–aÆü0,Iñ±œf̲XcÞŸ¼Ûš×ͯäóe±¿âMÏ…c]ËUÆô_f,ž«Bôøà«!_{ë£\5¢Dd‡Rüæßó\PùäZ°Ö$Õ±/}„ìglííÍ­‹ÑM7æ5çý{÷Ä»yï!Ëzè¼ çjQío~üÏï “ýMä•°T"ø}]Œ<þw‹¢Dòã¯ûE‰×‹_/Rh’“$ÐÞ.J½]¤¿]d Ú¤‹ûí"çí"÷í"ïí"ÿí—áê0©g'9%ýBÔæ‡)Ø/QЕÙŠàz¾¼ ÁüèîXnkL,»1b¹=±æOÞXk~‹èÄÍüؾXn_ìã7š½Á…‹E­ÍíÇð6ß"•[ùñúX®×躉ÜAŒ AãôKCØëPìK(ô8F¤™ÅekŒÖǾò0€"}‹¤¬ÿ¹Ähÿ’8…F 1•Ó±Üij”ªÿ£e¬;_=Ë ú¥:ú åÚbàžC¢Í/©0]´TŠUê’Èœ¹Ž˜Nüûtlx¹ û-1§=w‘ÆÖtcSAN °ÜÕh28òÇߥæ}뻡Ó4𻆡‡ÔÂè‹ÍuÆà·ç«´øw‘¸b$w#öq=x€"î±¾ï? ãsùɸÇÛùÚCwòSÜÍ×#¸—oôÄrb¢çscŸô¼Þý)ø~ÙÂÔãa²Åý|óYŒv)Öp\=È·G x˜ïŒDð(ßàq¾7Á“|‚žü  ÁÓütm<÷,öbÓgC+Wÿø°’3$úÉ›£¶¸A‹Ö¸>=ÄrÃã…Ö G!Fc.7"þñõšC£ƒ®œüÏE‰ÓÔ†RááÜÈÊÃ>¯|^(ù/åa¤ìæFÇÿoFƒѸ/}|œHœ—› B?W‚v~(›ƒhí¡.ùß ¾[”…za6–-'O<¥OeÁ©,èSñûTࢧÅEýYÍ»´y§¯DgÕ»äŽÞÉM‹üŸOFiî*“|õL´FtᬾB =pÃTnv_žBWznN\¦³@ÜA+a:·ðe½êGD}â/W[ò²F5…„¥ñC-­Ó´Zö¢h—èwnùË«rJA”éECíÛ¸Zùòªœ ®úBÁ«¾Xpõ ®ùBÁt«k~ž™&ÝÚ¾«I”Júë?¯Ÿ«…ÁBìÓ Ëhƒ¸!^˜)4’ÄŽ6A¤‘^÷Òt›¿`º-_0]Olöm/çr×ÓÞÜÎx¡fZØkÐ¤Ó SØ+Ó¤ÓCŒõï¥' {ã…Ø»¦h³±/Nb)Åï ¢õ·œK]qÞ˜—ÅwpÄÿ]ñߦøU8ÕøÇ쇡\5oü˜ƒ7¾þÃ6ž[ÍU†ØÛynÍKùÏ­¥ôž[ÇßúáYž«£Ç@?Š È·¨È}Täþ±Ú8¸ ¶óÁwµÆÁçú‚óü[ª„ü}$$EÞ#õcPïæ½ùìϵòƦÁ¼iðCü=ÂßtówŸq)w‚jøj´GY.P _–M»j”ø”<€’oQr÷ç“ߥ‰úÎÛ"2ýøçzN™ŠCÔfÄÿSÍûOŠ¢æÓÙÐPn¸Hn²>±G ™ØTnT¨ñw—À«ŒAøœž€„šŒÿMÙ—ÀGq\ywuuÏ=Ò ÁÆ’–m`Ç’MöÎ1¶•]klÖÉ‘Ñ(™Õî·Îf×±³Ù+ƒ¸ïû2— â2—¹ ˆc`$q›Ë˜[%î[ßû¿î™‘ÀÙï·¿Ÿ4ÕýªÞQ׫WU¯ªÑLFê‰ÈåÂØø'Êo ¡Fë‰$Ju,#’ âe‘މØPg‚¬Ôà8ŽKTuª :eù_!^ĘEb¨:=Ò?ÛÔ…| ¹} 1õˆYLˆGDdc§Ø­.œ±_e ëCÄ¯ÍÆßèROÑo#úÛˆÞŽèÙè›]x}e7ZÄ«jO;º±—Š"öSx%õJ*JG¸¤;µ#º:†Ìêx;¾Œÿ)•Q?*«ÈÞ¯‘½o÷3Hñ9%>(`”"ŒûO㉠9`…±&3ÖÔ‰àdpÇýÄü߲̯e˜_ÓÕ 0?$ÔÍGsuËf~Ì“eþÌÛ(ñ!›ù¡ßÁ¼¹óÏ2.mæÃ¥)‰ùa¡FÉGJn´´˜‘Äü?²Ì'®šL‰ÛÌÿæ;0ÿÏlÃÓ™ÁÿK7 3Æ-FÂó7Ñ3¥Ú,©êdé‚§¦TÌ•-¢©>Oª¹Dà2qnRï!G„šgCšÕ|™N…×HcD-°³±Ùøo]æ_‚ÛR.‚¥ÚR"9°T| Õ2iƒãÍ¢I-—©‚ç{¥L¤bG´Æ*<žÕg„ZÇVQ~•ºÉÐý­Ãe˜ÓuÞÉ„G?«í”l" É!š"Tj 8ò‚¹Ÿ‚£/8R},Qllýî‘ůªOd"ü¹Ðx¸Wö Kf¿´ÕÔeBÚJk¶)Y±7ôTË{±ÎêTi¥yagP<ŠÍ“b'×)ÝðLœêŒš\N‡)=H•˜wîI ã2²‹ Gá‘Ü¡>Í‚œá5L!Ä‚Ôc`uZB¡žç%Ô2Ÿ¤ªŽ Im  …Ô‚6ÐjåÙ ü«òu‹_i0Á¢ngÞ¤W{”ïwéêŽLX“Ëý.ʽŸ@›î ’ ”ûRm€¡‘–Âd¥*Tƒ JU#Ðø‚H5‚R©Q†]”$Tÿ\ÜdÄM5ì’¥¸ZçeÄÍFÜ\££FÆ"E¦R0#ÊÔ ¡Ì¡.êÒGPó~7ê .¦§º¨‰-â!´ü¾ÐÕFäh°0¨!ÿÒìá|ïÿ’¶Ç ¦U$öj¯aé÷¤‘´y`Yê;•K ºS!§)aœ6 (R4xIu 5=lÐpyZ¨£à8DèÃLòŒî8³¼W¨7ÀYgÎ:‚·%~‡•ç u°ÓFŠgô&–¡è –›úÌ(ikRgé·Y7ìVY¢åùm»€Í +À‰‹¦AÜ;/©¨™;ù Ù«o5)e¤m@+Í꺑ˆûop¤*¯å©›\Åi<ÞFÖ† ƒ üUäì> ü¡Á}¯à%"7­¢ìgZ%UcrI•´•´qY 0­²hZe5Ø$‚ÃŒ…\VCM¬5ªáf¦uHdGYd56N¶ÆšÐd4â~&î8z»CIïŠzËèEdl•,ÑP«Ï Éø\’IíÒ,ç40Æ[ÄðRm¢©&š$KàyL¹§dJöÜ܈YP2dÊ›œRM2“v˜w{hª6¹.$µ½DæfræšZĪgµZSÕ2É‚L>tÄ¿b _‰¥Qՙɂ¯X¢ˆ9¦šC¢4aKÀ­æ™ÉTÏÍM¢¼ÙIÖ¶™J‚åib¹,Gp'},—KµÒ´j¶îj»f>¤°Œ™µ@)$ã?¡ÑDcQª5š-bd©h4Õa3ÅvÐÓ² ™Éw¬¦Å–vYÔqÊ«¢.©£¹TaGêD‰ðgB‹û¬œùÊê‚Fy›[¨OÁw”p8 s*×ü·=ìqó@€€4  Á¨Rs¯[íu'’Ø5£yêuaÆ}¤l÷‘Q\Ì|¿»Ç«*I¯dh¶ëÒù¼FF 2×­»PêFw‚Sr+&w÷WÕA"¢i£…¤ÆY ÏZ–jgÝê±OÆZ Ëéº:寮Œázþ1¶f¶’¸cKÅ5·ºæFùØ{…Mêº;e-5aHÞp³!yµ É›dæ_+äµ»[Ä¥;³¸ c…“Fÿ8×½ {ÄcB©@0±T@Se7—ý;ͪÐcûi‘pD^œŒ]/LÆn¦©ò$”Û;áþºÉ~ýÄ/3ôobMÊAN–j|Är ¦–ê+(x·T®¤`Z©±Ù£ê­œò¨ºÈóŠZî± ·°ò‹øSMj…'…¥:â½ÊÓQù±¦¸Ú“'Òu7]ûV•x+ðíc>¶cÔzOÔHc¹– Ç ôÚ@௧nñd3ð”ÀôRs; =£Ô±Ã£¶{ÚiCKHjþ;šƒ¥x ßX¨°ˆ82Ú@ obUö‹‘ÇåR~d#OÈÖ –ïú€ÁÓr±»)k‡Ó™4ÇÎÈÅî°ÉÍÊ6êªÎ—¢!of»"š›)¢¹VÍó©y¹"šÿx•cA5'Q}ŽÁ.[¢E9‰çbwÚ-Í4 §_\⫾¸ÐV?^âk/ñ _ŒüÑã%¾©C‰«-\D³ÚÑöLm·Šh§OíÌÑî/nE{¾8O{¿X¬}‹•èØ§_ŒÜøx4w,´¢c¹:;þx}š«³×Ù©u¦ÎpÕ¶+¢Ï3Eô¹UDç}ê|®ˆ.~q+º’“¨åñv­rµ>Þ®¯uh×ÜŠn}q‰ßùâB»ûx‰ß¼Äãþ/Dîç¬ÄûûÛ—¸ìGÕq±51Ìo—Ð0?—пáÏ–ÐH›OA†Ï$æ3ÊÿXUŒÉ¶Ÿ±ÌgvŽÏ„ Ÿ ŸI~5)Çgòó™â¬€ßͶŸiÌgóéÓРŸ™ŸZ¿ªÍñ©Ëao%ìÙŒ=7‡ý^û= {¾_ÍÏa¿ŸÃÞBØ û=aÙ?ƒíôEôEú¿Zâ/êR?8÷0ú¬ô'’áqº@Ä*àïÁ>l¼[ãü `ë›`ÁÖûØG€M´`ý^€ml’k𺶰Él›? ÛØT ¶Óh,»›bÁ>öŽ`ôkÂŽ:ÕH¼¨Y­ðGúÅ>¦íáo 4ÃjŠÒöø7[E ;g§Ó¿„®cX; üZal˜À~Ú†]°qÍ@ˆ`Û6ÐNç`¿ƒ] dÜÙq×Åã®Ë%Ÿþ^[›ë½‡mk¶í}ØvòaÛ‡mî¶¶®mm_kk£8µ×Ÿ*bb°ßŸ,_ï&mægËFÜ!IÍŒäö³?¹?¯E¬(I V–êÇóT2WC^­I¥ó¼tK1f4æ¥bC‹ºWÎó¨&~LÄ.ìÈmìR_9¬H5?LøÏböÊ=€xØ~¤äGìÇ„OÏ‹ /Š(Š'…ñ)sµÖg­µÇ,ÁžXŸLGVäÇÚž ,4€ù2ª(6ºˆ!èqê¤-꘢öO۬ƩÏì˜{BE±,ÍÙÅL©\ÌS—·Œ× }ˆ»NqꀰºžËS‡x>0j‚Z<¿El$3<ž8ú |U“Ÿœdù1[½“Œú翪æG¾Æ«ãp0H² —‰Nz°Aw3 z Êø×ȤÏO…çéZ<¯Y ÍOQ |íë3«Œ')ÛX–ŸÆKùP#òÓÔµ– ƒ²WÉS匰SóÕ´/o:Ä›ù¿/<_׈ӊ§…N óÕ¢/â´œ–þï9½ÏœVr ŒãXˬ6•jkó±&}A_›¯Öçc”WÕ7äÿú¸Ìçü/ÖÇÙµt^ža­¼)ßZzÙœo-½4ä[Ë-[ò©u¬b ÀÛðûY´Í¥Z2_%ó+º—´•uñî*E¼êÉò±EB¥ó“”£Õ¼ÿÂûÑM¬¦|¸L‰ƒùê •><®H¼Õ¤å§JÚ‚Xª>ÌðTªDÔ–/ÒÕð¡¦a.çÂ9›-ÐîUF‹Xú‚v6çD‚=R¿¯Îåc)CÅùüWÔ…ü­9PÍ~Y›Kå¥|u‰é§cŠ@C]ÎTÉü?®›>ŠÀ‘ªMú¨9&yʆ¼Uy-­®«¹TØ(¹¿E¦A=6±è‰4®Þ€ìk„.„|:ñ„ÿEŤ¢H——"]Þ]«›9?XLYË;aPHz‘Âë»/Ø£r|¼ÖQÑ›Žž­ÛJÕÇìSqYh 5Û„sÇf]}ÂÎ{E"Y½JWûàR±ž:¸éåSø?œ¤ú^¥S…l`ZO#âl†ÖY¡ÎÙÈçü Ȧã@¢KÂV—„º"xæ1¸E¼¢Z éõ±º¼‰ñ÷¦ˆÜÒ¨ãàâq¯0¢Ç&u†¹zGjK„ÏèZyMµuO$ŠËS40Ý–ÁñÍ%7|5(q8ÞE+ÿŒ¢ûéVtø9†uøh\ÖÄuÁ,2£úËX›hJvPÇšD@S‹2czfl•<¶J[µµÉï¶µÑßȶ6zQàG°Q¸ý¦ã¡Å0\Gƒ 7‘ÅÚ\<°Ê(Ž¿ŒõæÂ*~àË77ý{ðr‘ ×[Ä®R1’‚Ý¥ú(]Ñ+>_lÓŒÕ_QãõDl¥Î BôDù6ê‚“t*âiT Stž[¦î8CÇ4 Ó8cÆj½8sø„M¢· ùå7õì~RËéÊçhY(âùzä×%ž¾ü”nûÐDÞ-ŠM+ê½·4<½ˆÆ(Ë…ø}½ï)Ñ#üh' ´Ð®z=°’R³)–PŠÝ”b©b™‡Ë™7‹±"+†ZI©›)õ*;õj«ÒîÀO)Ù²WùÔ{zÉ¿G}í*w‘^ò xþ@‡©3£È>^¹¾§SåÛÚ*ÚÚ~ÛÖF/jž1‘fuFG_—“p}N $á’ð#[ÂÍ:¯ÒW`I”,ùiç¿Ä }²TîÖán“!²#Gd· ¼°X„g j5êc=²/È{cQ£ü0õ§õxˆjxÅ'à2Èöæ*†O«J1/+—á~À.¹F;=Š¡¹}– AÙ¶­š:Þ>( DiJtÒN4ŠÎ&ª-â³EŸé¤ˆHêI¤‹ÔY;åϤ¸£Så^ MDâ¢]H—ôÀ«’àWôÈyvnÙשà9A…t»«¡t¥ŽÜáÍ~¤Zõ¨ ‡oxE$<˜ú—º¦§h,Õíñ4"RV@ö«¯ëè†ê'³¦Ä­4%ž‡õ[+%0‚ØåŠð¦Âü±õþñõƒ%=ÞCö†¯Y=ÐÓ¼ýóú^\&*:¥)ƒXb¡Z;°àµe X6 |™ðÈDª|/Uá YqÙ£Ö/ï)–ýt¬¡bø€KQù'Tb#¤Ub#)Üà†Q %:VÚ%··SÁ0êâãe®È:”Ô‰"À>Þ£¢$õ|˜Nf38YZœ"_QïJn¾(¨YÒÎPäé=± ++œmû-õ’§Í:öËq̦à@©s“zºàXÔXê~Oª÷™ T Z!]¨J»Äߪr©z ½¨ÉGÊð­*Zb•yÔuG]QgÔ“-ÕA„‡Â³Rª•2…ªVÉvBvF7[À«Ö¥a*|TTQ/;×Û¿Ø’*óq²at&7Ð$:"5“D$€þ…Ê2¿#s“]S 2ðOPQyeFE切´À×1cd`]QU5F8ûRUúà~Ûîûmòa½¨­ðÝÙÄCö ŽwH{8Þ!Õ.ù;G“ÝTá{$ ÓIþ½2Ûß±&RWDcÅ— ü3M‹êy8Úg7ÒäÙL ÓÑ â¤3⤥jl×pÓd[3p8_Îá Îa©ŽÊìˆwLZ#Þqˆ=€Äþx[ØùGà’¶¡ž’ꌌœþ åƒRqVª³ÔÀyJ´ð¶&ÏÉTIq>æÖç¹®ál\ËîÌ ê÷¢¤!Œ§±—Àr+‹ú]°lɈÚ"á„•|}$%¿*¡Ý킊´f|/-?Ïk2«ú¯ƒØ6&ö2ˆÝÊ»%á¡•|}4v]dvÔ¸—C½ÔíBêë@mË ¶I5ÈöYj${*Í-ê„U—áF¢âC=Qö¡.ªWëðÞêQ½FW#9èVÎ-R£áijƒ%ú ÈŽc÷¤UÏj 5Á ÚC–P‰8¤L4@¡†²l mÔØG“àzR"–b檦p’ò¤Þ5*®ŠÜÆ&+½FâuÄ͇;Y‚¿… 2,2T½‘(†ì‹þIÉG˜ƒú*P_ ê»ÈŒ6_õऴÂHtGQ¬¤D—`p Ñî\¢‘h-E^¦Èuv¹­G¢…t8¼G¸ß}bdv7”ŠO {[óPgíC% »AXSÖ5ºÕRF¶>›ì:;l$z6Ç6ꛫŒtԨܨ» —TGˆ\‚7,tÁ[›Ç X;7%?5*6ê=« Bo¨2áþ|Ó÷1lVòNå)›ACg P·½É˜Sù&j{gWÄkÿòo8ìó^6÷§ÓtÌÈð9ïä|²x»4Ç»Áäí“wp ÊÁºçhòu´T\6ÔÊéE=ëø|sŸmiÁ·Ð9ÇêÊPŠ“Øqã©ÕUÕj¤cóŠ$ogžIÑëü¢ÈäüÁà«n)tZuÛH%ËßÍ6Œñ’ÓpC9½l¦—ʉEê NίµñcXID‚/]ä´xc‹8V*û™ðQC‚V©Eº FÖT ¨ufüx©1ÈTƒè=läY 6£¦µsȈåWÉNA°x·F5ÆL†ûîXŽN–_“B3ûž&»ø´P-¤ë„4ÅL”o§v𮉦щ¼æ–šÓM5Ýl·é›ÌíŠÓà:ÃĨfmÿÖÂwêá2Þ&ªi©™i—Ÿ–Š¥&6¸Þ¤ú.Ñ~õ¦Á›ÎÜüRS­ 4(5ª†·Þ¤^A¯=Þ”j%N'®3Û¥G™ÏnÔj=D¢Ë¡kƒ‰Gžb ä#³øUµÉä p#³Y¿ÙäÍúA+zvÂñ~›—¿‚½ÌÿßÖý6ÓÚº7ÕǦÚO/Ð wý”E•`Êôï(ÑʺJ™È·r^‡°$á1ºöåô€É»îÏc„B6ÊøÉ\αƒO8ŽÙÅŰLñ¦SGbšòåïæÓ 72"kión¯Šëb¢œ.Iû8-7†EšîÑiÒ —Ãri0¥ÕiŽßÓiN¶—ÇŽ¯£éÇöù¸CÕ8,Ûß‘µ'8,{b #‘4Ï“mî ®³/·,2œÐÕHJ¿Ë"ûsË"£3tG;ÔXB®^®«q@N°ÝÃi&pšó/kj²Íh Ò$yЮç1cºÃòhi Wk ‡SJ³ù1¢Ç“úÛJÊÁ¯«9ÿVêjžÃø ~ˆ ¸ýR¾×Esn‡mðü4Ç™Rm±C-¶SDn‹ð—x«Q-qÉ ÷v\ ~Öê /ô­p$º÷(¯ÑuµB§„ƒ„îÇB¯w@ï7ª¸hpÑ…ÚÄÒv*×øÈ£ÖàP 6a²¶øX^£Úâ`§UµJ,ÖωŒl·ò AvtÌoѽüªßdÛà»üöA”t®‚’¨ 4!®@à b£³1SAÕìH²SþA»Œ¡ÂVèê0ˆ5re¼ œcœ­ez£úÔ‘x)Oå¥zÁkÈÔgdQ:Ô)†p¢Ó¨‹¥º:C ô‚§‰ÃY~ä,Dê¬û©>ÐÕybÊ>4Áµ‰³ðûlò! ÷Yï#k´ÑãZ wâ±ü ýœD ™õû8³g‚KÅ'´à èwÖó¬}Ðó¬á?/Õ8Õ §¥ðxl#?؉®8ÉÚO`¤óPŸd°b¦0ÄùŠædu´'±)qÅ $+T ˜™é|tD0Úùm™j”ÓÒN&k§Ñàg²nb‡Î{Fa\Oü&Zš48Ј0Øb2 h³“ŒHùè0ÅÙ~„ÑÕ4Îfl ­“‚ÈÜLbVçÌx}ÍuªùNÛ/k'&È4z,tVœe½_~VUïd#ÆÈ"~d±o“ØKkõœÝÄVYňnû¡óQ­ntô3Õš…¶Ö.’ÇUº™sÛàÌ:Œ}ä´Æ69-‹b‹MM'¥\~Ï/Ô6gÆÄP;rÂØ.e«ogIv;_ûõárT³c †ÏhdêÝl³¥Eš1¨Ú$ ½Œt³O;˜kòÔ`Õag¶Éqf›ü1g¶É·šü]jòŸ¢Éâ&ßÄ&Í©l“?_*N9í¦®#œ—߮ɷ3m¨áŸrªÏ:4|šrå¾ìÐð?§¶qÞ*¤‡QHóò¹ŽæÑðVêÒc ßìà°x9Sê\rWœ—¿ì\`•nyŸ´fZ“äÖt•x_wfÝÉl1¼Á}‡;ÁÍG;þàV®'q–ïr–³3w‚Ä,î²:¡ú»Ô@ëÂÞmw‚!®ö`¨+Û †¹²b£ïŽr=Þ Æ¸²À@'˜àÊv‚I®G;ÉÀÈàdWûœâúÿzMê]\e`p'˜ÆRÍpY Î¦&I p'˜ãÊ ˜p+zÏeÙ¹±’Œ¹y.Û˜ƒŽŸï²âzdÈ\àÊö§z×£ý©c«XÔ!SK\¯ˆ“ú 9—M«?Ù›d÷HîVƯ´Š4s^¾ÝŸ–³­s˜{UúÄõªu.k³˜FÃ#Â0þ:â¶e¯¸X*¶qEw·ºK÷¬ÿíîRmîEàyà^,!õ:þ"µú¸Ã»T{‘”­ÞØm}­}HÜbÀ~—å¶ãϵˆ— KÚÏÙ A ‚ÔÀ;éÜ_vG —AIÐRÒ®ŠE–‚]DCçûMò[£Ë¶Çõص¼ÊÛB5e€[âiªíö¶Ž ±DQG³Õý4_¨@YúLXJðêeÝ+'¨ÓüøªþjÄ ¡ioLS)+¨r|>ßJÒvݵUdˆv׎òúÓ_£œ¯¸`vPI^qa2%®»”r%’á=ðjT­®$ŸJ¼ê¢éÏuWÅPG²l¨CÄkMê†+‘bá¦+âˆ<5˜êð˜T‰Ò÷˜ô»~íž Ä=æ ÇqûA"eqhR])æÐqwE#•,«qèÄ¢Yõs'ÒÌ¢Æ&Dÿ8µÓQ úƒøÈȸB W.¼-ð»»TGp¨³áVCÙâÒ¬†ºÓÌe˜›¸ŒpW¬ÊO'Se«òe|U>Í”Gº±_F£¨2cëó‰Ó§9Nã2œÆ1§q§q§)n5¡§‰6§Ià4Å]1¬8 ë$ãÃ:§©YNï‚ÓØNÄé„pºLÇ¿ƒÓLæ´äim¦ ÓÁƒÎ:‚É=%‚)= ;z™3™¿c®[ÕâÄ%M­ëÜQ/Ïv¿¢æº+:EöÙ",EÇ:U9Õ{„âd9æá(ÎÉ\fd2»€3»ÀÊì+³Kݪ¾]fÙ™]ŒÌ.uW )@f‡ÈøÊì²lf?@fGPfO “Ì×?§ n»ímp«Mî\£ÛìN²ü $ÿVw¢b€#™ìQ6À!™Ô6È{Z8©™Íbã~ŸVðGS‰ÖÌäö‘¬WJE“[%ÚQMÚTSDµÙ x,tþC˜Ê-¥ú!·:äŽì Úû+ õ·šÕa7˜ó <Ó¾ ;D?¾Ñî˜;'€ê¸Ûî' è᢮¶Š½ÉïP• åV—Ú xÙœd-\g.¨·ö1ð >Â9~òW( ‡¡HÐF«µº3.mì!pRÜpÓȲ[™½#*òìl»Ä&ɲ<ä‡ÇÇ›V9§rå| â&LéÇ‹gwÝ|(‰Ï"e¶†[Äž/iw)h-÷)¸Š#[-âZ©|ˆûbJ¸GÝwƒ«µ9Ö¤¸Sáë^-þT³zèN[| ÷ð”5ždÔ¨K#§ùOða-«F’\Ufàjëz©9ÔÓ"n”:†Qp³Ô9œ‚[¥®‘5” à¨ò0OšúįÀù¡á ïR#~²[ùôïåf8ÇÃýdG½çÉ5Ãy«ŸÌ÷¼¢z²ýäïw–ê‹ô²\âŽ0–Rp§ÔüÀ£{Úµ-B-ñ¤­Š¦ê]J¹±vµLõ‡¤RË=”÷ŠNŽSöÌ%j 1؇\qrÊÞ¹³.xS«€^‘9öhâ‚.3³¹‡sòzºÝuTÅnÁ{}Ž 8çw~DÁÝR×Foòmò¨‹VÁxìz{˜–µoÈÕ »~;=%‚šÄ®l"¤Ú}åÐÞù ü©uÖÌÈ ï·žyÏЃfíi$¿˜N7·£qÐàPV&—:ìi—{ì8õ`Ç1¥^É{޹Ço£»Ü+õœð¨™æ‰*ZŽêU'=Yõõ"¢Ì'³ÚMòXŠ,€µŽÏ9)Å Ž;gÇ© 8Dö9+¹ñ¬ä®{l%wŠû~©¸ëQ7Ûµ®[vëºM­ë®ÇRa-vÏÓA…= mžÿ… ‹{UaýàtN¤Â޳ àef©­^V[ƒ¼¬¶{Ym ñB¿c¼Ð/æX/ô‹cJã½j·½.ìÍê²!Þ¬.æ%Ô¹‡Uô®8—Ñ Ë­kéFz­2w'q5‚ãµ”–©ÆzÓT­¬‡j^ÆgTØxoÊj¢ZÃa+¾ëÖd}IÀÆ*ƒ7«pX©LeŠ8iJä§Q£!ý÷8¶‡Ï°àp¬›Ùé¬G¨Õ¶Ã ü³v ~ ¥ÑžìûY\ç¹ =|¡‡“J}v‹rÔxýk±7êj¨rÁÊV+ÚSXm ™4µQ—u¿Äyá ¦†g ^¨C_3®ð2HC=¯5P>, ^µÝ›*Îzb.¥©,ÎLïðâÿ±Cždmå!O`*,ŸÝ^¬Ê”WíöfÌÖfõ±×rBØã}E%¨á-ÓÓɲeºŽõµ”·ã:"nžõZ;<õÖn#IPc=EšÌÎ#uú~Κì,{‰Ön¼ÞÇ`M®ÉÛ~¹®Ã‚ã!û„Û´ù Â$óèg¼åÅÇå¨αÒF•ê—½ê‚7g…_ô¦8;—(;—½Ù F³º‚¶›îÎ'’Z8Ÿ©dš2ju0vñ»(NÓñk0»ïµÍ×ûè[Ï }:‚«ÏËû,àPg³Æ‡Sx¸{ŽíVSµQ³`k2î#k²ÆWQˆšl¸–ÕÌx=¶úûÈÒeÖ|QGlÜÑ/ §ÃtDx•Ûgóícþˆ?â€øö©±¾öŒÇùˆ1r?Þ÷ŠšèKTl÷do÷˜ÌmNô]æöC0ªeF-=´Z¢ùCßû]õZf k}j610l†šã‹Ì`.1˜O pFš”mðXæñû %G~y†ür&¿Ü"¿Ü"¿Ü§Vv ¿*C~5‘_KäÛò,òmyùu ß"LRÒÝyrÍätÕ¶1E±Í§vøÉââTù1ÝP;‘\qò<Åɨ¥¬Ô)Ÿ:àK'íÔHÝš#~‚Sß練’Ÿð©S”¼8i%?äW¹Ê~Ê®˜œüî3Ú%¦ø½÷ŒŽàþ3ò’Uc—|êJ‡kÉÔ˜¢_¥·d›JKÀª±kàsûA7Í ŸûÌç>SÖïS#ôåæ3m>«WÇý¯¨¢â2OÞ.w²Z{œ5¸. "9‚ǺÑ~{¬íom¥b ñ>Õ¯ÆúsCÞ8¿5‡ï§f=ÑŸ1îùf‡I€MñGº&óŸñ®Mjªß2õiöñ.I°½€Ø^À>>jš×Qd:äþÔ«jQд òÿ„²Î$õ ñ™$*ÿE8“”ëéKýVO_FY\N Vyh¾½Êc1XÞÌMá72­û/j-ZuÖ·ùq)K²ÁoMá· 3ÛücDrl@ 4«í~{ ¿ÃŸŽMG½%Lªü\‚)fpôi-E”kBÁɧô³“)fgñãüM»ßè§ŽMàxÞØ~„™ è!@ø+Nv²ºÁÉNFüd'j6G‰ŠÕ:ŽùɆ:‡É÷mnŠo³ªdaú›Ú9?ZŠ@@mµÅs,“qί.øÛ·Å‹~»-^¢½âÏ\îzײbZØJżΌš|ASÙ:Óá*Êú;'ü'¸?°¸‡´÷÷÷wo›ýóT[ây¶ ýò^Qýó*òÊò´xéËy4÷¯\ìRó¬N’Š:Ú÷>"s·ͳ…ÇB ! @óÔØ¼ 4Ã~<±ŸHœ6y2¹Ý”Q `tàš¯ÏÃ=8ÐÌ'äa:!6à`5Ž-̓_¶ÕÕ²<¸„_ÔÕy“óË&çkñÉùjE^{}UžZ•—[×î‘Ĉ›YÀlV«a8¦yñr]^ÒZI¶÷Ö×ç%,”Í]P6äUt)ë¢Å»4©òRÉÊùEjc^ d+ç©M,`Š·ã7#w÷9ws8w{r¹W¨á¼Î¡Î"•‡“<_èí’dbáÕEÄ­Q¥ò’±ùEñnÖ‘žvylÌSy¹Õ穎ylÊåñ`^*Õq+ûP™ìð9 aI ã[õLž}EΙ<¾"çLž:›—ÝêøœËk 4u>/‘L½Ž Ö ñîÿFqâ%ùmŇìþß,ðÿ†Ñµkõ¡J£7¸\ì¥}¯ïþ`EYY™V¹?Ø".õe-â”®ÿy‹ØDVE‹¸ÜËø+BŠë@*iR?H¼¤~I‹;Ãü»¾‰`E²Ze"¨Þ 0uâ~º®KãkHü>jð²ÖWõ$ƒñê§}“ÁŠÁð V™ ªá·G9j“Ùü˜ƒBÚÏÕßSBF¢jBNíH¦þ8ï`ä#ñh\Â7VÔºqS˜Ž³4ßüm¿ƒƒ ¿NTGöËŠEõ ]ý["Qˆ¬óÅî=»å DÏÆêkzÒ%ª¯êê7Dz nÝG$jp´a€HÄZ°E*Š<7˜ŠÅTû(ë±6I?‹jS¸4i¢n¸ óËy”åÒŽ’HBÁÄ~…‚I!yŸ‚É!£‚)!³FªOõdC#\úÓÁH*˜áÒ þnÕª'ÓÄi™í8Œç4˜.fwý«zàϰÈj%òõb~¢S‘ ö¬rÆRÁ†žUpývU¦‚.—Ë™#®ñµžê®˜ÚÖ¦îSžó4Í¢¾©¨.{å¡Úh>5ꛋxÂ[#1ûý¬¬œZ¬ éò†"M ’|qî$ݺÆ-w+—µî²Z7ŽßMfð}ÄMvMNj’ì› f«hDê¸l)ñRÛ‡Uö’6\»Ç0jªÌÜ¢é2yÑPÿ"Å=ÊÏùuõ¦U?d¦Œ'#ãÔ¸6þ™lØ/IÞ_l Z»‡ë¨Yýë+úïï5Mûú*4Mn-Â÷x·iº_y•=´º3ßt\p!¯o%^êÑÜ<ù.®¿/ÀI¯ç2×ßâúû—«ò8çoqÎéwݳúÛøv•üu‹˜2~Ó"æ„ÌÏÇy¡Þ®¸X¡¡d¯WŽ¿Ó¬~Ê|SÊP¿©è/Ãý¥ÿ 5êÿˆš‘»zå)—ú/zjÓ˸„úïYEê·)®äþ¢o«Þ£ºUWƒ%±ãwŸ§|S§1Ð{l«`|½óÄÀY¢‘‡úÀʇºò;¢PôFÑ{J©îå-~¡Fé^žpij¬ ¬w¬hý$½Äæp‡¦!ý¤œTð]&YÈ9A¨ñ±;dœ pwÿ$Q1ÀÆ(  ÇÔ‘J´üf,K¿r½Ke5åyw­€~òÌPZÞ¹B½+*¾[ö] 5AÃuÔ ³•‡=?d „÷CޏúœRш¹Õ%Àˆ >žr€Ÿ¤óµ~µ¾ÊZôXçã»D‡PDlg*ë|d f>aà ¶¨†é™O8¸Àh`n‘›æã&7ôfø"÷eìl°s_«NjNÄó‡aÆdèZVÚØ MËJ»Œº}‹‰°'ž!¥>fÙ,þ¢O¡gdnŸAv<,Õák1ÏÒpHIþ´b‡Wtü¿á 9Ù ‰ Šuz泊ïé™ï*. ©'*FÉâ7œÕ_åDóôÜGçë¸yá‰ÖúzÖñŸUÏaü|×l° ýb_@ì¢ö‚ê‘äñêÅDl¬´ÎÏ·nè8^Œ¤½hþ½Dl´äåþ¯`š?Zª—!Ëe!eÖ0ÿ KÑb¾ÚDi}TŸjñ—Õב®àû˜/ ‰oªßÇ{ùn2‹¾Y¢5㥦ÊÀÇÜQ#ý<¡«o%SáRcQ¾ù²!;&£‡Iþ ‹úǘÖ3ç¿ç?kÇù;Ìè»ê;ÿïþ.ß#.#m.ßmÏ% Ú‹Øb)¢â&êOW|l[,®®Õ¿ž¸]±/aQ¾Óº4¤º `ßÖº´ˆÖ®‚~¯vÕéWu•]ÔS¨‡Bjã¤*ÂÇã¥z:‘ª&CïK‰tõD©ºâò 6„ò@‹¦íT±q(çe9pO÷JÄÆüAü5›ðòøe—&b^‘ÍEäWì±³åîZý߀ [+Ûek•n8¥±D¶. ©ƒºÝž¢ÃI øäK:‚ /Ëú:¬'¾­Å¿F=þˆžJóçÆŽñü ճʬ¼+`>UÞÁõýQ#ɋء«¬ƒ‘ÏÓˆ:‰}ºÊ9RÔ+q69(Ô©Ld%¤§­—9²r® 8C¦Ò>èó “ù‹ô&vü%›~!¨â軂fr¿fCîZâr3žÙP^kËç®ÀW0ê{v dÞ9ï…ó|ïV–Èø •;æê®˜mæJÕ_fHÍeRüÀœâ«ÝR4¥Ø\å€ÕMò».ó ÃB¢¬† YIfÝzÀÕº.¥±T ÞFó•ý/7ñz õÛ‰dÇ×1;lÐvȧCb²T“9&I¥åã­Ó)|Î7ŸÏù’ÌI;3õå<ÝÀÑÖÈ¿®°Ý\­·Áá«ùpB…GMC€òX*¸ˆ=)§Ëd ÕP Íø¡ÝlIî?¤fûljػh¶kXouøOíÕˆ?UߦŽô®TßÁý9´?'´×±i@[—CûKí/Õ_Ú4©þ7UäÐ~Bh}±é@ÛC‹Øh%´éRUᎊÚ?Ú/±@Û˜Cû¥öKõ¯„6Cª·p–6‡öŸ„ö߉ØL m¶×5Ï,µÄÖ—’Õ3©@ù7Øë”fVTF‘!3 È[rÈc2Èc„äY’l^*Í!O2Ö“j¼-‡\›A®j6k%Y§8 ªãúäß Í6aÏ`®5Ïj;ŽOŠ]0ó@‘L6‘—Âå/¸gEß#Ô‘Âí3ìóÚL¶^º¤-ˆkdì¥38ö‹$L&|/^ÀdA/$å{ÖLøÇ‰ÙÄRÜÎ\ÜEÄ]¡¸:;n—ŽëÅÿq8w·Kµ6yyHÄuÕÆ)ã/7ª¸^‘Îey"ž×è z€žLP?e“r Žg=’ ôiÀ¬§€P^ï$ úÃôÈw"y‘¼ØÎ©Èí@ìr—á­O˜‘<¸Zîf1†sWœÆ*ôÊËd °3u”›øSdtƒ?¹V9æZrÌÖÙ,™££p’Vÿ%UaÝÄܨæ¶j 5ï¡.¶êcÝAÃÕqjµnŸƒ]CBMÕÅ,u×7±ˆr³®ÖèÙÚmTkuk›l^üªÚñìºmRé)û[¹I§–+¸Ym¦¼¥3y«â¦nµUߢ«m:_#Ï9Ün]帣âNèo;[ªAO7øQÔâö¢'0‹þ8—MØáØ¥öùÜÃí×x‰^äutÌ'Ù1p†öOì1ÐÓµúk€` Ü›5»’Y³kEHu®xHf—·úN”j7P¦uÝe˜¿h]RßáÜn0C†tô;´›N¿ÃºIúÞÍ ß‘ÝLúÑÍñõ]˜ߣ· 2ê¥z…LER½a±Te‰¨Y½Dªï'¢Žê¥’\ÔY½Lª¿ ¶l•BlHÍÿDl!:vcü÷þ‡D¬à¦øW¼[p³­VZ š'¶sc1ž"– âP.b"fQÄ2DÎEÔ#b1E,EÄV5b6po\Ò6šTBˆdl…´½(±MÒ&c˳ÍÙJÆ>ÈBXÂdle²…EKÆVe![™u2öa²¥LÆVËz^éÜ.º¿ªvÜ·4Û$H¾Âнv“ðu­ö‚Ú>Æ;l5_ÇöÈáà﹫[Ä^"Ü÷ÞŽÐÛÍ^úk”ú8oX„ZkQ_ÖVÇëêõÈÑ &ÝÄKù.²—J㥪¼ïÑ`qåÑ úKØžŸê’È?ò{Rûú!awîFr¿A‰“‘ÒÁHÿ#›¤ú1=”ïšú q?Á¶{~Jµ¡6–(Ѫ?Bë?Éq,YÅý·Û|-†[ÊÅDJºÙ8ÇKº%ˆ˜’^§`ý(ÉÚêu²•øÁjÔ ?!¡>v±åSeâVµ¨Û戜ïë÷T}õ6©ö1(ûÉàêíR%ßG¡ã–Ñe6 •øV8VÝpìø·šy:Ô„.§Âß–jVÍ"…Ïmòºáa‘¨(NF|ÃÅ¢?ö<¨$픞Q߬{P6InœØ|½Ï#ËsHÛˆ´Í¹´žvi—QÒX50¤‡y“¼¸©El ‘íƒo/RÂQ‹´‹ñÉE€1é„nV§ôdÁ‹èÛBâ3]¡TH†N‚1ë3=;¦6±?ì9ÝÌ.è0|æjó2D½ÂÉ)¢M÷: s@¢z¼ Ib¨§‘ùí¹`]í¥î®ªœIëà]öJôžV¢#é"ŠœÃênÇuW=ІX<¬E÷‚‹K6çÈ«8`ç<¯ku_@óa2·y<\bùýOZ÷Úk±D¼‹*LF¼+øXVQòUõ¥dï}¡zûžþÞûCÖMc]úªzÆr„Ä&´- ÃúHˆbEµ¹Á+^ì{:Ø{A¯êÓôú —þµ¾g‚½öª>C¯m½ä·ú~ìï]ý*ùýö üxHýöZdÆ=â8سxA×ê{ ð_Èü_çYWo­°ïÙ`ïšÞÕg‰CÿÞâ龟{·ø«?§×½õ®}Ï{/ìU}Ž^ö–Ïö=ì=¨wõyzÜÛx¡ï…`ï!½«/@œúöâ|J5…Kѳâ| qŽÛâ»Vß—ñæ‹Ã{hoí¹¾ƒ½‡õ®¾H†÷½ú^ öÑ»ú8,iÏáDH}[Y(ªøÔæÐ¹kõ 8,k§Ì>˜w~©õ2–A¬]ˆïÓÄú5MýõC½N‰–Kk6I‰þÎZ ©ÁZø Æ}àÙ³°©3v;lF±ÿ@Hÿ:mUö_û-´Ùj†ùäQèeæ öBÒ®‘Ö0FÐÅ€Òì+‡(kskAS™X?D¬cȰVGN’ma­Žœ·¿×{ŸtŽüxpüÇÖ-F?Žÿ¸“˜â Œ†‘L”§„ Ù ÖµsävdÈÙË´ÿ#¹Ýr{@.Mäö‚Ü,G˜=A.ÁäÆèZ‚¬ît‘*…¹KÜ 9G"UÝÏ –ÈYÁwÊF9ÔY;#h€òÙ˜ÕçýµŠví?ѵº ¨üMíôùfVH¡ÖS!õ Û“ÿê›üMïׄúŸN«f¨?HàdõpCý!I4Ôà®Õ`«LBS‰¿’ˆ CoašOüªÝ(^U¯Ú04Š­9¤¿&¤¿IĆi[é6ÒÔßbSHÛsH}yÑ%6H;© ÀQ)ª~f øsÜHÈhÿ BûeÅ?ö/6þ®¬£/TœäÂêFoÙzš÷¹Ä¾¢^J$©¸¾FÑ{HÙ9œ_EtbùÈ#v[à÷–àoÒý~dE~¤+pÜ—f«o¢µB,N?ðþˆðþ„toú‚~Ï‚îc¨Ð2xp¡_íGVÌ(+}¾âT&+C ü¿Ñ¥+eh¤Hd(‘Ó0#{kÅ}/{ê]}™4ÌèÞ¤p¯{é]}&Ù^ܱl†TVÃ੊Óv{ªkõ( pHgõ~SVïF£GÅp³øÂêžœ¨™Õc{kßkz‹íXE1ô@=ÈñÖ³!Eƒƒú³È03ÖoçCÖô÷†-ýu²¥/¿¬…Õ«ÄÝsXeªŒ^)R}?•¬Œ›êÏûª`q¥ ª¿H½ªÊ+¾ž,û:Ʋà Š=@í¯ Ëç!í¯Ôß$‹+û™êæßf˜?$±ŽHé–Æ( „Ù>š{W¹ZĹ6Û×"·‚ !ÁÅDp)dp\Á僓¼ìœ‹/|%cýÍȉN±¶.ÿ7ƒù"ß Suê“Âþrî˜]à‹±3E3íI î˜dlY÷v•+ðUþöW*É“ŸŒRW‹uœº¨³6]W ”Z ìá‚e8Ÿ vîk}ìqÎËþ'ÎøÒèòßÍ9Ëî'Ö·Â:RÇrë‡PÏ‘†ïÑÚÿ)Sí²£Öû¢Ø•:jRT-ÿ‡šËO±±è.Çì䬽Éu”åqÛ„&è1a¯ê8ÚݧöXBq'qŠ”ûz:!1ßû ">CÄçX/oÀ»¸z’¡Î#œlÀ+»¸z³âê±<²‹«×ê2ÂõVdŠ«Wªá'†R÷ªÜOJl -ÒÁå.‹¶.¤ÝµVsîòZ—~—׺ä]¡†ê‘kA윫az¢¢OY­z;ûb¨‘z‚¢èMÒû^£v-ˆEŽDxŸ¡A¦q<¯œi`•Ã^‹muT׸œ>U¢-+ *‘#…‰Øj#6™âE-ëSÝ x«z¡¦èX Ãáó©:ÍtÔt…Žs/DaiyRpÍ!>ó ,{ÐÃûn­§‡†ª#1¯^f`$òYQõ–?°æj¨÷t,Ën1Ô<¢ºÃà»8çó£u7èLp÷ÖÊÇ)iäæNJmO°ŸhîQe¼Xå¤îùb•ûEøu>Uå}ná*‹PX¡à 5¤/±Ü-–êXê3VPp5d®×Õ v²R+õT"6æ²Ú . Z-:ª 7øÙQùC=5Ãù  Öè©tì´·ö­&µ¾z}•#ðK‹¢×BމÑõs7B®O(¸rïÕ±™é9­ã~ú½­:vìb»‘sžØÙ`ïI¾òn·.ªßeØÑ¨š]§­o°…‡åÛU>¾À~¬õ•Ó¸¢vr1Ï2Ô>ìAfüìpú>¡§ÃÇœÚÛUN•¤Çãxt©=Å£[¥éñ=|évsæÕ©f¹Ô¡ ·:œ¡âáµÁY~@Â[…_\å4ÀQÅ‘9ìNÄfKq]<–?†!u,øIj)G £î-|¶HGNëéÈSƒQ»êŒõòÕ„gõDÔ› 6tÞvø\ïñj`:n¦´O¯à$_¤S˜ŠT8eèïà‹!º}¬î ’¿‰SJ^ûi¶ò]ÕÕUh¯&¤®é ŠŒ6xý1Z7H?¢neˆÞѧ¬¥v‰9îŽÄeÔƒ|æ!ãý$gÜ“ËxäŒ{r(íÒl”¸¥Þ.M6Õ™âÍ\jxC%®…ØÈ®tÉØzÿbëjëŒ%™…ªqFø„Ô&uúÇmj¸„ErZšÃl6С&JëkÌÅñoàTM&JÖGÖ‡ô‰pp!»‹TÚ q[øqÜ9ŽëË#¿Ž]yêê õ®L°îxè€nœÒ‰Ó%ÚáDCÍ@ôZ#¼Å¯A§ÎbøÒ’ºù.¸ÄSüR,méò¤AZA&Ê› -²‰ØîAÀ]Ðx¾NêñºÁ@÷«§¥Òz]W¥%Ö-ë‰ðC›Tpû2í£óp§ÅJà×ê †Zõ8ÃÕ~øõ6EJqÝ«!Ug(³u’Õ€{ñÝüHÂÚØ(ÕGYÒøðQ—€«çFÑ(xÜ%P j“LDÍîá™$ ! Tw¨4°¼µË`oέü€S~;\—ÌS&²J¨¼`»r9Ûm¨­* ô‡ v‰p«}’ÇIi}m>A"—ß5„JJ¬oà¦x° hkSÀk”ï§è&i|%=‰ØvÃÏa™eŽJé }ž5ö§VóÀ)Ö[²Ê÷"Tô݆-â^Hœ¢à~H¿BÁƒlÅ¢_ȸJA[È|HA¼#nÞîãì‡M©—]ïêä#…؈»æ ’´Š°I}&ST:±-.ÎÚyŠüØà=Ð ’zãeI“.”¯HH\¢uÆ™Tá(¸ªàмÅ_ÆU/J&ø®—ðÞ|­zª[å¹…ì1²÷ÁP^•Ö/&®QíQ3ò $¢JÔÂi>ÐbHuý‹Ë »±@Ô[(é=F¶òïZï±~ è÷¬·ò«T%GL÷•´ñ%1%š5„3ì-¤i³j-vZ¢“ÅñÅu§êgຠ@1jñsnšPõ7¬6ÐHØÍÊn4CÌ;|’=j)­‚3š8h{%{F‘ ’IuÚ.É^5ÚˆzI Ž˜î˃›Ê#°—!&ãCŒÃ8ì*葵ME³¸à7è05}¼ã©®û÷ñQ[Ù NÂ_Ôxr0‘BkËŽmD$ê 74^¤¦Ç-ôø6éñ‰,!ÏõÑÏb2è㧨¿6+ÉçÁúòaAC0¶8ñU‹'Š©ÍOÍä ‚q/ëglqE]QÇ[¶©i(,»É£¬ffå‰ò7jf(|®Y>ùk™ä,k}þú_ŠÀƒœj¦«fãfû:²• «­sW¶T†[Í7Qw²¼ÑÐÕ:ý3iz s‚‰.·Œo‚ÿL$'^4Â=I˜Í¬yY[Fe; @Pÿ‚¾Ü€j’+ µœšF3nÖOdûRq¸ÉÐaº­3¸ ½-4þÄg‹x·»±ÓÀ‰?“2¿Ñh×û¨;l†£åt_:ß«-ÖË[dã¶Á¸Í° ÆíFÎN܉tãýoSÚe$Ø>OýˆGDÂÙ‡èI~Lk¨¾¬ˆ |“Ø*Øo£¼ŸAy߬Ac:r¤HÐ}œ†J­AꪭA2Qig°¸·aNx€_‰KeS5‚áP¿µ¯ìRM—ˆvbRø‚¡W4U³¾hˆÊ¦:2®Ø"Gå S2øð—36?Ìںʈí4øø¾á; u”a4æcÃ~ƒ±E$SOŽØX‹Ïr §²%|†j‰D™àïY妬FÝ.7 é3Љ~”ççÜ´b»$_Ê•ÇÆkè mi\Ï·oµ¸éëBNôwVϳ&—P]p³®zTÜ-s_¾ìŒ+ã®äðkœÕ¤ª[±ÊsVÔ:?á‰ÏuB3_¡¾ˆæYlݺ†1ÂÖ¨]ç¦%®ꦑŒÝ÷¸p¾hr©~›"õ‘w(ÜǸKÁ>æ=þŽû íã|`¨ÛįYÝa)ÓY=}îÆ–ªN…ßóK4¶{í5‰Û…3}Qš~‰ÂòÊ Ž¥É+¶£ïelÄQÛy`¤Ù—W=¤j#%Y¢åýˆÔã÷mõ袊®¡ZO‡·±bt«þfÔÍ]hÂàsDݤŠ0ÿâ­nŠ$-W"jßj†SCMø©¸™Žºž¨'4‚fü¯ªÑ&ͧàCÃsÖ?F¡Ž3iÎ:Á´;UÏÄÌó\šõÙÏcP“³/óȤÃ× ÎåæÄÓ@fº™ˆ}ˆ9ñy‰½ˆDÌ21[ÖG›eò¼j–©êÌD2UNV®š *$Ü.qÏ5¡€þÚÖ><›ká!˜ ëË(ÞG.7Õ<¢‚ùõ|“†ä)†zŸÞ©Qaª½ÄÌiØDlŠQ?©z›¡–™‰ðQC{§Y-7ñ)ÀUØ{4:%ø»^/kMÖIëLµÖL†7çk|Àx½ÉŠ! ¾/çV™|p…/WÛhÒlI±†B$áÙŠuÑ;઺›øTY;::Ûpˆ…ø¨òvzä£Ê;̈êDÀ!OÑdÌä~ÏcKdWæbgâîæAwtZHìö˜ÉòMùšJRâƒFV–I¼Ý–¢È-yÀÄ75/J8ÿ ½™«hL¡Öl¢§ˆC&ßiw˜4Y¢5©ÃT[pT­‡½ÜꘙG7Ó–—n³:b¦kló>yrEýi¯Š'Óá'E,È Ü6 'Llp^’F¾a®çe˜3\óÏ5YN+1ê7á`¡Ÿ7áü /P0¢q‰‚‘}Ì»¦:kvoT—( è«—©H&¹wÅi ¶Øñ6YkÖóÇÛUFC»ž4«Ù„ðm1¡ Ó<[½ÍÏQƒg«wM46ØO÷3 pŠQ>e,›¨N2ÂG œX|ßDÕÇ1Û•AçJ F÷q­r`ôqï¡`\wÏQ Æôñão;6¼}ü݃j #à7©Ç;åÇÉNIŒÿGÙ{ÀIy\ù¢ýåŽ3†8–5’0Hì<ÿ´Ýhm¯eËR áµç­wí•ðM³ê{­g{eqßÞ½wï00D‘ÑÌ’ÈHˆ$‘Dê3" ‘ƒ"ˆ8ïüO}_wƒeïïé'¦¾®\§ªNsêÔ9ürè Š:NQ£ÌÂvHš?h=ÍóuÜExjfêbÌýUCÕãÍàR*?ÑLÇ/è.š1ÉÌV0å9éSÍà8]z8 úÞ5ëñlÙLZ8äNFʘ…ÙÕ?ÇsL¦P^#Òj®™ $Þ+IÍioëDÈŸsÛ7ó[÷euKQpyÄóþ¹Ã³U>Gëù½‹+ëÑøB38u3…§e%fð'ðóõ#T©çýJD³‰ô³‘d‰íå "ÏEyΉTò½T~œ®ºKÊiY«¿hkÑÖ†¾ÜLôÌ‚|Ç*+̤»Îö½Ø3éŽ7´W£ôÔÅHs}­+ÖÖ¡¹øç™HsBý«Mæ—ÿgf+ÇFS§;‡‰÷¢Œ3 ¤Dm5ȇ3Åm]ˆHƒëMÚSbƒi@fW])v³iC‰ ³Ó´Ï›Ý&>ÌHÒÇ+ö˜IoDOš>’(žCÔ‘& œ  Ô§5fâ”7õV;éËYžÇ óÐ7 TÄIä åéúëI}j&}ði+™p¼5¥Jðæè¯Q>¢Ô‰T“²ÓZ©à âUøJí¸i‹²N˜yjz·— œ2ÓY„ŒŸ×5ÐGŠ‘çÌš;•e/¹ûì|©3¡%³èNñ‰•mJü”ålçĹΩÏmï€ûíþ¢&+øñÉa«¢—8jaŽÐ©LŽy…ƒZ±ë;óIG_ë:Ó L÷™â„Å/æ.2ú#í ÜHœ³°]›uñ9, }Çï¿`¥mv¤f‘..â×8²kêâ’Å7‹u!à[â’æf“CT랊Üî+–¸fåòFêäp,FÿÖç/üL|­Ûªhn Ž V‹–(¨ã¦SÇMKܶ.1jÖm>QܱcçSì;_w-‡ M§ÞÑ6t€Œ0–¸¨s§Qbºó÷ƒÜ…{Œz·äá»í‹!îêÏ©ÊÅ:ìGp%CQÉb<ö07TJ‰æÖÜón»ç#Üb”Û¡#ñÐ~´ó+Ãdäú¹HgˆnÓ"€sZ_èÙ„BϘ­›èNwoI}¨ohÍæú~¨» ìb’µ¤S uû¢A #&»‹çk :zEƒ¡¼cÞrƒìk ò›Q×[îKJCTi¢`bTãªÍw‹énL Åg¸»õMîn-bŽ»À}5·Š¹n¹L¶kt¤vÀ”·Ý9Ûu£ÃXÖ[”V µáþ„AVÿš:{~ %ì0}Á—öšÝIZéânRT_è 9 â$C,rc mÔÙ˜Ó¸õ  hçì ÖWeƒŠXìîÚBU'y^亓zh&a·¥nÂ_ðÔ½ÃS·ÒÍ®¤ˆð†Õj¸ƒ@åÐ×Zã~ h&òþ÷¶è¶ÿ½_£s;4׸~ âÁ¿cN’¨ùm Eu»[lã² D¹oçuuìRïp§‰jÒ-~ZWyuí”™±·¸7)»­vó¨Ó{0‹W53¤Ÿ±¨6Ë}–Æ´1› ×Á’Cb‹ß%¼³Ô“ÉQå 7ü½ªW)˜Õ®Q05ª_§à­¨q“‚iQsŠGìsgRç;7ÈËŸ4­µ.®E,‡mqwí%öÿ0 ³?=jtÃSÅÛiã1h"Ĺmù«sÜ%ÝŸ LmÔ}Ä-ޏü¯õóo1EÏ1øhˆz»ÁšûN¹ÅQÎG<·¬õÃ’h­¼”Ñ+Ž­Î2ŠjšÎÂÌs¼¨èl?ý³I†¾F ¢Ì`ôlìçÁ]ZÇ{÷Úħ?ÐY¤y‘Aн_) Õ/˜,Mi­¸ƒîRq [ô 7jZhWÝR$Þ ×÷W×Ý|‘z“X=3¸ûí®ücx¶Ün6·hsK.+IÔÂʇtȦz~?5ÀÓ•ê©6õÈUS¤6؃Þ2a7ÄÂn‹OǦ ƒ=Ù ÿ†ë¿.®RdáÙdáÃm”',éÊ{TÁ{õÐ@,#Y_wø9‡­áí—ôÐ\i¸kg nq›–WÜ¥ŠÃ?‚ñ¬ßð¶Ñô΋úê½—”w¿áŸâš¼åm4¢)茨õ&}X»g#e`[xÿTÜÁ]Š;è“å#>Ü+‰Ýfœ/ƒ"Lí?ÂŽ^(â¨ñ§vy9•ˆû7ìÔwŠ ©?ÒŽ^‚è,Þ®Y¢û±Ï¢fêóÍŒûÓfvš_ÜL}¾™ ÅÍLwš ^¨”l×ùÁäDÊÃ5‚¹˜bÃì´„Åç4ikŠ>[´º¤Õˆcö-ï_<‡KÄ4//”€Ý×’&ûÃÝèÔ/¯½Öj¤>SAâÛ?_+ОoVˆ&¯]>`£!‡œ`1>šãMâ%Ë—šfèÆV¦·ç±# Â=ó¼@: ‚ßPÌ‹jÍ^Ñì­~¢÷.~йÀ› ƒôË›t.eƒMØXM¼§øi<™älá¼\ⵯ+%¨åÎ|.åÄ»öØ"vM¼_›°›^‡¥§¥°OÕã‰à2þÞì»Û¬eo&÷·³ZÖ5½ÐÎÁ|;k¼E]ævq;›Ñõù=gP²—³üv/ч÷‹ú°¶Ð±ÎËÌëM¾±he€nôÚœÖFáü¨ò[žR7SðÎSÚV ¶=¥LÁÞ‡^ñ‘×AzÎåWs‹ØìͤöuÿZ«Øê}à”.–t4Ã8(õ€p #F Û½¹­âco&ý<ŠÉÙ3ãû;áE­!vx‹®êÀþïôr^yÜáYžäWr^gӻГå“÷vâ{¬Ý´( .Íp‹¸ˆ·/<ÂR2zÛYoÒ,jÝk7T—¯³® •îõfØrç>/[î¼¥Á|ì.ð'^i>ÖÄ Š®Oܨ‚@ôPxqG«¤ åaý°W p Ôvj½9y «‹Ãp“‡9ŽúÜóãìùô¾\Ž£©,ŸžÝ~^ö&rÌ ÉJjÙˆ"'¨µ»~Û(b._ó)˜ß-¦#veÊ*÷°qÊ ¿yÚ+Ny3|sÌ·7§½‰žIÓ–[â ÜðôLZÐlERövÑ *Ò#÷Ÿµê¬IWǽ¹D#†ÁV!¼¹„gYCh#_—©4ž1òºÝ /Sm°:7mÖ« Oå:ÃS½Ç@k7á©F³EÜðfž­â&µãœÍ Zs L K]Ü.Îò ÄµØ=lh I]ÔúŠ ™ý Ôë|€¤1Ð'ê|yHb gØ4Å qé­„¤.!9Ü—Ô€dhƒ!™ ¨ãÞŒðe’-â _6É‘>Æw41¿C¼€äXh<(“Ê[*Ià=Þ¯”ÑÂXàLÁÞ‡µñ>^«oúb£Á=ps¢ºÖŸï³% wÓ™øY]±Ÿ£žèÌ }ÓçˆiÔ >GvHcžèëÂdÍÛ¾\x(è‰ =Ü‹|P7÷,¦ 9ê]â“~g }ð}˜Ð;€ÇÚ |9ûrË|Ū)ŠK¬ô± «Xæ³=|«}bµ{EÁû>F§»¼Ð-7ˆÁl‚žçZ_ÎV)?‰ü î'òmä>ôtQg1Éô¼Ž¾¯÷ÙXo¶q²zƒ0T°©8ÚƒhñQqål5;ô¤~«/ð;+>öel$íô9v¶pKS¸ Cuu·/[}-’ðp¡ŸÅGÒ¿±P4Í-dQÑ=¿Èùª¯DrUW"ŠØKä}¬5Qàm†¡ä¦Ïòӻm  R˧‚å³ÿ,G}öqu?XNGK°œz,g°ÐÙv–Á2C‚å¼ –~$]üK`Å`™qX¨è,3,× `¹Î`whßð|Ùu7¼Ü Kî¾ã¢Í—'ÓÜVËšOˆQûNˆþ\ˆE6 ¢þA~1ÈýÚ äÁ¥hTCR-ÖªO´Ñ|@Ôû‹yÊRûbjä"¯}öÏéüÙû³á‰@= £¡Dùú‹ñGˆ°嵋H嬣¸5ƒ"@ø óãÖ*,‘1ˆ˞Aõ‹¢%#ýb$†H”X«TŒò'K“î&|Ž¥Oéªîy¬d)ó9oúó¤1`Lß]\R• Àv(å‰Ü£<á@Oº÷ á› ºƒ}ß ˆ©þ<ñ±]o.âû¤Ð¹?†*ˆÈLK‘9ô»ˆ6žî‡:Á݃Šõþô“b“*îiñû‡Y_x‹ß&”¶ø/)‹£Ê~ £"XÕ¶ù™ëÝåÛüŒÎfùè¶ËN;Ò{&r«êªØåw&yD ˆy QŧýĪT ]¿¼üÛ¬'ù¦ Í´Ä%˶R‡RòžPâ|(5°csnéí{B[뮩.¼?nH ±®± Ah¦~ÿº‹ŸÐŒð³¸[ñ'Εðvyã«ÚKJÙ8óØ’z³d£[ó]Ýïî_íw.IášÅ‰¸ç@‘ÖàHÝŸJ>q vØárS8æŽú¥Œê˜ßæA½v ¸ ìÏ‚ãþn½Ä‰<„º¸þì¸ ó?UÕÉ^*K’òæx.ú@MSËØMï”$KÙtûBÄ¿Åñ2/-ê*âPéê’\õ#Ioükmm –…}„9sD[×ɇÑັ®D®“nö: ‰õ%É\'KX'RR2䬓Í%r„œu²¥$©s2¯“Ý%I½˜ø£}”ò¼\†O|Ε³adŸ»ù3ÊL–Ø[òÕÊLn±¯hóÊLnVfb>ö£h¨µD´–`½Y’ð}½_X|ò@©¥dx _%òwKŠ6+ÎæC%LL´-«êÏç2Žb9Nwªº§T7Y8&Ž•HKú×ÊJÿд„VuñûHÉÒ^R6G]ÇøW?,:FO–°òÿ©ðµúé°˜ÆÙædÏ•€Ó´>/aöó| ¸\Ï…ð¼Þ‹l‰ú.•ˆËÅ£˜Mè‹(xBÛª®_I°–(¹dI2ðz%®•ÐÙ9À€â |Ö¸+ýŸƒ ð<·Jˆ­iJúš²‹u‰™¥ºSâ°”^É—˜â^¡1O0 ][šMµi‰žCX}~@)ΠÜêJAmƒ%Xš•ƒK©l!ipè°IÔA«`H)?Ós§SË¥>Èr] +Í«¶Šá¥¹<ë•+f½`íÒ±^IC¯‘ã[‰8GÍ÷ÍÑgŽÊ9"þtÏ}¼ûgçhi~ŽVÈ9ZAtEñ­øKs´ê¾9šqßQ³«9’ òÚR|e™?$èÀÐ_&çhC™.6>0G›8× 9Gr.êâôÒ¢9[Ka—J‡-7V®Ú^Êtz¸¶—Š¥é"Tf»ÏSt[²4$ðzÍ4]ì*eìYóaJ™½fª.ö Ö:\`vF­®ukÔ•)½¤l‹*™R±Yéùô­¥¶©ÏÖRqiõ:n!–2/xØI<,Ë#hüºz¦•jÃâH)xÐüm%+š+%~áL©}9HçÈÙÒ?áá¾â²Ìò¹R>“pø|^ “ŒÐØb„Û*.•¡!8¾\š¶±6Êû× ž’/JÓRŒÓ±G®–¦svŽFš xÀ›v¡úH® •ܺ¯’ÛùT”¿ST¥¬BÔ±Áò<ÞV‡ÇƒK­AÁ4$"U—uEÔ«¯D.Õ2 n”¿¡·3<ˆç #‚Eãû6ŒaJ•ˆÑŠÂ5&Oaþ•5Áïùù>AŒ ví§³ŠÄ¸ ̱þÿ(:EÅÄ`:©g«¾ .wz0©º ݆ ý¢«)h¿èš´MÌ žvÍ ‚Á¬»ºqŒ×óƒànp0ñ š¼¤Üëª Øó¨Š`{TC°õQÁÇQÁލ‰`d«9×lîìŒzR°+ê]d õý hæˆÇ:ݹöUB ‚¬Ð8^FxÄ’b`âÞÒ`ÒšÍØmèu|úøŽyRfqÊj¤Ìblø~01£„}òòó+>«½Å È‹ö]©Þªf&ú]¢p¡á·¡¸aˆã6!y™Î­RmÄÂúq+tîaY^Ž Õ¶"~¹Îýá¼´ì¶!n©Îã¼´L?Âm¢nZº1‰ßî ÚVD·mˆÀw¨vG•ÝA±;˜Ÿt<šjz­E¤ƒÙ.®HžoU¨9Êz»BÛKÁ }w+Œ– ÈÙf(m¾½A¶× ¢f_­‰‚¹k ²)O úÖâqCmy?EÌÒmGéùGÎ ÛC¼|f鬷û)FG)üàì(åš"€Åqþ‘Ô¹Ì .3[g"õÊ © OŸÎbB2©:‹ïr¡#és°jæèAP¢ŸL~\¹ÿ™4šJ@_¤Õ._³q ¢¸q¿æBb‡×r 2^Üë޾YÜë[޾s_¯ïqº¸ü¸Ú¯ ÉÖÆ” T]¥ìžÔ‡Š{2$ÄcXëÐPqß0Öa!D uDþgÒ”c}#”ÎØ/ÿШâÄØP#COÑ.¾›Œˆ¦ªFK–™ÊÏÕ½‹ 1¢!”ÉV²1…·ë}GXbRˆVèPV²,î™b»™ô쉺¦„.)騂 U§QjÓCbZ(á¥|jzÀ­à¡œíU°UL±¿AùJ’_“VëlÈ÷5[ ”hߨÞM¡ê $æl«½h[Ì A­<ßóYü“û>;Ä~)o*ü²~NþTèæ†6ibFˆpAûémmbÆ6L‡!Ã8†ö M,¥¹%¸‹ŠÚA–RŽÍ?ÑT¥I\~¿(įíi.±Õ סXúºËC8tWõp-XÊJ–º*$V†Ø>M<ÆÆÂ™Ôw‚YR±Š XŠôÌŸ$¶Š5¡l¤> oD<Vàû¡,~óh׆¤=›B¶~ñºPAÝy3÷ "ÒØ*”Îfâ×t5 5¾í! ),?NòCŒ¶°Av„€Ô°œX ¾3ÄHëyW¨k‹Ëì1ªÄþØ‚ÄÊã2é#L¬Ð}¡l.ò¿!‘¥åëêFÕ ‚é´)q(d/Š.J ”Ž>Ũ½¦÷u)?bÛ ¹ª/u•u;R5üKåÂPZ8E °áP:g[8CŸU·©­ ´‰ðäþbèþ7â—Bé®P ¼…º¸L•Á@ÓȘç†ùVHTÞ ³â ÌÕB¦ÚNv—sÐy–ŠÒEܦ“Voõ¯ùX×±†FèôŸ±·ÛíM¸ÝÁÒªr‚½Qµ-$î…@€êN<’ZÑÞ¦*ë¬×_om!Ø‚&t? œfyp¾ÃÄÜæ²M¯c/æ^¯n¯Ô| ‹:ÎÓͳNÃé|í^ªý5¼¿â<„ŸWµW^«Y¯‹AÈTÿU™Ú™6è¢>L#zC‡•‰U|Ä K…Êû$¤,&¾5ª h‰ª>$Ú4 <ú Z£Æ\}ÚIÁ'Qkû£îÑa1<Œšˆö Û*pµ K¼–ʘt¬ 'M©kf‰Qøïg´Ña\ßz‚Wp1!œ´ì™%ÝC!~–4¥VˆŒ /$–¬ÊC“/ÅD=“ÂbGIEä)ᤷðü²;´ïîŸqÖ*Æ›ÖDdYžK‹iá¤'éEŸü7¡r–?À°5!É]z ŒƒQïì°˜E1H™Mmâ¶~š äœpÒ—øÔ›ߎ‡Ï Cœi ½ÉŒt+È3y.tN]î\6õŠúšÃ¢™¦1éË&½¹ø]Ý`á‚p7Áy‡™_üP'…åö÷ââä¡EÉò{1« .¢z –'–„mÑ!FïÊC¾C ò-'ý˜¾`zu8êÿ ,>ÈOR@¬ 'ÝÉ@Ïa6„“ÌÛGaVË1Y¼›t/ä“-Ièm¨!¶Ê/jlWØ™CLýnª5iØOL1.̈#<Ó(- ¿Û&ÒaV?É|V¬ß½lºöÓ¨«%,ZÂŒ¡Ž¹k»ï­á NŒLmw«¤™¼Úîp­Ã;ðG¼ŸriZìØOå ¯yÁ¨v—¾ŽàPÔ8LÁ‘¨y„‚Ï¢ÖѰ8®~¦÷3.•)Ž„¥Ô*>Ö¯ðeuع³ )ŸlfRm~ÜZV'ÂY{Öqï}*œ40uâ,`aÒœ@ÖÔEÕHðbJú¢LšOiL¯„YUh´c™ÿˆÁ\£Á<Þé”ëZX|ÎØOqt¿ÉØأQåVXÜ 'zfÀbžºÆé™­Ú¯)â.ŘBåm…ÊÛ¢.òßW>("E •ÃH*?@•ű:ž@uL?É·£JÞR̬²}âqzÁ"ëx]úŽ¢¬#˜³ O¹&FÄ$Û\q-ÒO(Êÿ¦^ä‰6ëPaƒ\|Œîšés)’~ÎUs i¹@)ò¾M9Ä<Ô §ÆÌ¶K‚„K‹ºÞ‰\RŽG'¢*‚“QíˆÈF’ü Fä"ÄâįtV{‰½ø¬¢OÑ‚f&ë°ù39èïTaÛ‰ìüPÍ&R"ÕWí¸ò‡jbˆš©¾fG=ôPÍpÆÚû#Õ×í¸¯=Tó 2@õSx¬YÞPéú\ëÒ…JV—ž‚Î=åzA¼¸©ý›}"žáǽú\Tô½/ez‰Hh]½Åå*P® åNE]Uâï3ìšå'”?ƒüpj6M‡!Ð 2²O ÄÓñÃÔ0]‡%ÒNHø¥mLð—¢:ñt¦êSbÔûÀq%Vóyäèk›ÙíË&´ú²­¾â_ðÔs¤!^é³Cgâ‰ýÆŒ2DMº[ÍhCü@_Èé°JÝHUfZAm¯òsƒ­¾Ê5¾Ê6_e¯Š?ôYK´ûN7hÏui“$'žÖÿ(þ˜I¬ÕÙÃX¯ÛƯŠÿ‡tkÑÏ2ñˆÿ™46Rú€Îuîµ`’Žhbûéæ~¢hÿOŸ÷u;*‰÷y¯Èë¯c‘H)û–¡Î$ò†´†Á©)$Ù?†=¯á0~ؤðõ¯1°‘ì䣕 JŒTØ0ÄH®c2Ùï'kœ’¯‡Y™bõSêEL :Òx­ˆÄŸÃD¹wßÐÊjº´±*Aƒ’£ØÔw»C0ÞƒgênŸaÐÐäT醭•èØA2ØG+ "<=ÙÏËÒ°© K³¦*bš’©ëŽK•'ÛôºÂþ(Ý)Vˆm4„Ž“{TWu•?Õ1CI0êºQÉI ÁUôL¸¿%àŒ”ýJ>ùÒg—AY6Éé‰:n_烡äм½¾­9aåøyJ·}pŒ¹ÄL.‘Š¥™þ!¸úZ dœ;]ÎQõ‹ÐèÐJs±"˜‰ z‚hTi]Èb÷5£Oû#ßÇQk™Ù‹{¹ñŒg…"–)€›XŽÀ#Vp×ÝCRŸ»F±’GB\ïì‡&[w£ŒÔΩ/;Ç·¡·XCf7»U5z_IC¢â•ãoÑžªÂó*Þ+›àÕd¤ÝÃF›gén¿AãÀoU¤2¤÷ &pámï^We+w\E°=ª!Øú¨Žà㨱•Çf"È=líTÄvvÈëˆv~|]·ÄNŒÓ›Imp×õó¿ ¨¾¤÷1´…û÷nEìV’î¼ðÚ#öÃ{u#lö5ÑâÜ©<å󆶵µ¹}n¯8ˆŽÏÖµþà=:I•Ž9 ©(ˆÛú·dJŽZƒ@·Óe›n¥É¾§lòbߌ4Ú½w¯MÌR³<åÀéAIOgKõ&ÐÐ]Ö ³Õ>Kõ,ä…sT ¼B?dÓßzby¡`7Wí³\Oê:¾­æ¬?—XvýóÔ>Ëôä™óaÄucÿj¬vé¾&÷0Ü×,RÓ™ÃÂ5c„Àe¼«ÚØ$þ‘FÕ57,µV_Ѷé»å*.4øáòHƒ.¯@+su¢sÌ •UªýDb•´»JkTT×ÅåoÇ®Ó÷#>œÐk©;Ùè*Äoë–—Nb•mP%fÑ ºÖÝøzõ’r)êÚ¦bÙ*ÛÑPTÝÁ«Wƒµ×ÜÃú)UlSíV“ô¦×ö±×š‘†<¬ÂìCy"°dmO)–é S†;T¨svdo².â üìvl ±=œ:ß±¹«Ø£&v9v;è <©ÝfsøM,ÅËQ#£ÂÐ+e*㪦\ÝûyØÜ‘Çí© CKmŸZ¤Å®Ã  žC˜ûU±_M<ðâvÝÊNíQJ‚9–¤ÅÊ-cY©™•[ƲJs|d{ V«ïÁŠÃ=šÅÏTJMHµÄL=Q¬¯VuB3ı|w‰ÿOäµÏ²ÐÃkºoj·VqR%º*.)›QYA:=Á |^‰Z7Tq¹¯Ð¼sUø»>ÔŸj¨¬vþ¶ôﮪÁM웘ï+2ÅGFð<_ú`¹ˆÿûà¢ÿ!5¢ø™üí¿0$¨àñÛ÷;jE¯àO!ÙÕªoê¬Þ7@KH•¾.j¹îå ÎgÄ`­º mƒM­¢—8§Ò.i¹¡å®Sl1JKØ&%y¤£µê‹P(hHêñ‹ºÆÕ‘>åÆj:Îé Ä&5ó&5œEhf ªÍ¯Cˆ­ÄTDUM ¸`ó5W3Æ3ŠJÎÔøÃ<&˜ÌÕlSs56µ ÷°º@ÍèIuÏŠŠÞ=Uôg†­yXWq‡»HËñé³XËuí{³3‹èÞÍw}™]ÖùLÑÛ¼5µ¾`Þã¢WÀ¹‰.zTßbîcŒŽ/ø’¿A< Ø7qa ˜ÅëvùjþßÅ×Ò?uÕ¼eˆ‡N3Ä×N7DW°|ÝàåC×MݨUPà¯1¾É]\M4û7úûÁ7Tú»îý½ÕŸOW ÔFïoiµß¢Éé‘á‘õL§Þ2ˆêî{»³ø›,Û’ùN:5 rçE~ýÝŒó„¨?kö<›NM—é$ƒmZÄìOGtäE»#/Š—¸êÔm˜[\ÈÀòoDa Ù–2üÒÎ@ìzbgxWwÜRP–NÕwl~îá‡jžC `¹Tw<¼¯;.è”ù°¿â劚W9ÓZ½à‰á¬ëéË_FÅwmO ß½¤ÜzX¡¿·VéïŠï±o†ï§¾ªe†&ž§²ë¸ìL…yÌ·v½ˆbÊ‹(¦bü™¾Ë Ñ;ë»Ò F1Ûw…!~þ DÌaÓïµVñO™ÄóË$á\ý|&þ¼’[j±f³ã¥%•—sl®Oü"æg§ÙÆîýôšwˆóqë5 Ñ«ïÙ¦'4Ë„…sŽëi#˜Ö¿¢«ÿЦS+^€»~ †@ùø5œKœUjÛíƒkÑùÆk-Lz^RZW+~›It‚'B¯ærh‚›g[åÒ¤8ÊnlÉvquØA¸àw0r³A'VÖú¿ÑÞl¯@‹ÊÅk|kkãXÛ®EÚÈ{=ݽ•ZÝÐOÇ«’ù†[wkâüœ¦] ‚вO¨æþð¢ÃoEçᾋ­¾I‡Or$ r¼yRÄ`x?y×CØÓv¡0¼qà wj) T(<Á)LÌ` /5ˆ „ÿ¢+LkO·äñÚI N#:søã ˜±_SÁÌ¥SË Àe†"_·ÀiwªÙȲÇ.ÄfÃDÅ4ÅúØ,û¸È5úK.0—i–Føæ*é®5K xÅäFz@yEß)*º@Ée"‰-â:¸àb\lˆ%J=Y®f‘A ¦g‹®©ð0BCyO±—î{Šø@‘K‹V|Ûð\³™¦fC¬ ¶‚è±>VQp³Ö-XK ¸ñ¤J6)b3Üøùá‹!Ñ"Z¾Ê6УÌ&ÝŠ²£ÍË=´í qT8ž¯ ÀUõ®ƒM–íæ„,®­h±É…(­JgàDS®@:ï³øUµ;çšÕ2ñNpy¹ƒ~î!ñý@hŒKçë⌭pAl„ÔÊ™2¾¨ÿ‹MÚu5ôi>Š+9¢äì†Ú híCjí¨¬“s4ì)|.4ÓÓ€é6ÝñºB@}´úî^WוyÙ /aÛ ðû[—oG cKäõF^ôw ¡~¸Hûp‘þBo¹šµ¡n8·K/錶wPu–»U¼D¢w:µûa'íËÝÑ?´½“ÁŸS†j€÷mNý6R«ìÅó÷âï«WñU† ‹í'pþã«yßÿX½ÚÈT­6ñ³ êî{Ö'þ »¹Ž§QÇ/í:ªEuQ}(ÿûœ?Q½†êXCu$¥ïš=€˜Ù F¥¿Q}¯bó ü{ùч¶÷ ä`g5zÞYÍD8«¹©œTYs#BU¥òDŸ/#•S*k¾dg5z‘³š;QQ g5ºã¬†":T·Ù'ÏcÕ¬3ÅÎj¸O­týuŸ›‘Ê·*kn¢Ê½ºô)r7*bägÒ© ò¾B4»ëI§6"º…ÏÁˆ~ÎFEωç ö ñÞ0B:<÷ü4ìmüVãz)?e–äq×OÅ?¡Z¾ |¹ú™ÞT4:A¨L®ý2¨-OÿAyÎ…J~…„ ®«¦úö:Ø—Zê—NmB:øŠÝÁWèTÉÔl2D \ÛC2Á1õ¡<)¢cõ€r Á.Õ¬7żó‡÷éüáÝ_«ÞmT¼üšÿÅ™ÎP&]g_¾œ)B™ˆ2jW}2u­Ùep® |+·ò´JW¬Ï-øò«I_~·hÖ§W*Ë•>·=ËÑ·)zF¥ºRésÑìÜw0ƒ²_¿Ltã˺˜k•B¸3“¸©üЈוƒ‘»Ä·ç#Û‡œmPÌõ!¡¸9†‚`\'õCàÇL¶"~Ä@ÁÂòCÝNݲÀnYA}LK+ð#œf(µ eøG‰_6TöS°««N*ḤNHšš-ô«úùÞÏ»C}¸]æ;Šo£ÍÜæà˜ëµòE¹r@‡¨¦TƒÖ·A#ÜGŸ›¼}7y çÑçYvãÔqE׺1KG%gø,|¶Ÿ)°>¡Ø r¾)' èŒÐ9 CbÚ9 †Æôó|×qÃ;JÃ{¾|Ý5‘XTîªMÀ«’4âõå.Öíe~ _\Q^× 4ó%º~þàBÅÔŸô=†.]RFÄÌ Ü ›ñÁå.6ÏÂ_©!åõ¸E®`³ž7•¤UQõÛ˜¸«@4>´ÜÕw¿WÜË7dÓ^Ÿô°ØÏ0ÃãÕêÚ²¤›2Õ–©b îNéz•J»¹4üC@ŠT¹®KÙOQÓ¨˜{¸*†«ðí|Œ@@àƒÉ~ˆ}ð R]é(TãájpÕ5VÍ$®…*GÇ’ÖÏ”xSGµj‹¡°_äñh`LL606æyî‡ÑÀIj€¦F4¨I/70‰ðÚ LFÞ|o}eH™ñU)4Où}¡ÿ¼×æö»}¢‰ó"ÿÖÊ;ª½ÈßQyM  5ÁAL[ Š*­ ],T󳼈sE/¡¢ÕNE«eE«eEÆÆ´÷Tñ*’CÕÅûª}Ï´¶Pã¨ñ×X…×;5®—5®—5"Ó6‘0Õxœj,§7©ùý‡z?Róûo ê½^Ø×Ûœz·Éz·Ézl{ZûX£ÞToœêݡ޷¯wêÝ£ïë4ýªîØ»£Ü×Y´yC‡æ_¡ÍqÌëNˆ¹ÆihZAðfL¢w©`æãM-›:áí%&r(-3NÒ2½ˆÕÎfzŸ*µZ‰ÇÎ!µjX¹"ÞbV÷KB†ùy†/Íb®g.)+:+ψ¿Sú-:Ò†øv:[“5Äw¨[7 MæÃ(AqR?Þl¸ˆ•ª¨ÉtÀUÔ\2Ä(ß-×¾Y 2âþ§î-8«cÊ‹¯(™W K,*g†² ¥˜øHÊ„ÿ.ýŠò[%þ‰¡ô?~E©¨õ¼ªŠªW”ÄR³ÚÕV¾ª‰Ÿ$~Nµ}gµÿðŠ’ÏÎ S½é'³OþÂÕ½µû“õª"þ©z‹ñŠJyh×b=?DŒÈÏ? bªø}¨½”ÿæ÷<ÛI^îR:¸F”»Tër—V麭Kƒ4†¦ÁöM§r81ïèÒÇ Eÿ‹}bþ‹H¨r†øWû]&vCúo~Õpý¹ˆ3û-u(ñZ!sÚÉ ö*å¿§Ãyì÷‘ÿwÈO°ùø\ÀòûÄOW3ñ ß¸¼–I<+ãÿ˜®~6V‰@üëxpÛ6p’¡þ_Ô'Ç”ÿ0Ÿ}U/ÿ¿ˆß"À>I(¹Ao ‚ ºg»õUN>F—‹zÊSý, ÜûY@»Òñ“³K^ðq”BQS‡{2äó<áÏJYöaT'À]5¦\)§%ë:³ôŠœDc IÔÄHE;†g†QJbly÷ÖÊ1:;rÈö}å ªj´‚ ì¥F^ír=õÛß»\:æ.èGs×Á5žæÎãšPîÒŸuÕ-ŸôùtœsMTÀðeä‰tЀ»¿†¦Á‡1e›ÁÙfÅ\3ø,Sf*Äìe~þf9ç¯}¶EÌR²|Ó1[©¾!ë^DíEìà_gÈË`ªgãŠ4%3ÐÀ’x“'f/£9†k/!Ù1¥E-j&Þ@ñýöž1B0ÕtîÁ‘ ¨·ªX9„ çƲñ‰å®"}~¢Ž¨´G3;ß:ŽrYîäŸ/w åΪ ßšß0çkèÞyY§½­ `ŠÝ ZsŸÏSŸßŽ)ÅÔ‹Ì‹i×U!àÍ­ëçAi´`C%Ⲛ«Êxá5ë);t¢­Ííq»Åj&¤³ÈôEq‹fâ“Ê](TœâÏ‚ }'¦ÃÉxs̸IÁ‚˜yK…8UwN}ÄOÚáÔMqKí Ï!å®ÊGø-cLâ.Œ±¥àZ-¸Øå‚yLøÎJí5·KR›Û/ìþ&l†Ô(ë­Šfû¹–Qy»èûNÑ÷ÝŠfGšúÏP¨Õpë–Å%_·ü%†?DËá:0žóª¼hàyËÃ5–<Ök¸ÝÛcßîÔ’téÅ(V•^Ò¨:O§ÅuÞ©{xc ¬7ZQ嘱ٚ½ fÓÁ°(¦ÌÖÄÛû7Zýe|T;yÞÑÄBNRH\â$.ÑÄ2NÊûæQ$®tWjb5õ¬¢êSêÑ­ú…Þ/@ÏaX¡žµNÖµšXÏõ /$nr7ib3'Ž(4²ÍIܦÁã”ÝÈ­úÅÞ/¢‘7xƒvAÖ¬“5«áèU²šØ ¯$—š‘†á5Ì1*rÒ$9{ß">$K"XS,‰i.÷Ð?Õħš\ƒä‚œä*,HC|F+$>™ÖÖ=…ŸfƒË­ülesUç =ø vž“ñæc’j[3NSËbæYMœFª½fÏjX³ç´lâï–±Ðü¼–4·"ñ·:+]Úp]r K¢\¡¥³iZNg …ÉžO5,Œ>ö®º¦AQŽÅ3\(ƒëZºêŠÿPð“nà¼ÿ&s‹Áxó1×-êÓò˜rGw4›ömw‰l`"Yƒ}ÚÑ…µ6@·¡ŸZ´ÖèbŽÉcè¦aŽf 7D·eÆCt&’‘„`qLCp-ª¿Án¢²ñƨ`¸þ¢xCO§²F&ÞH§dÚ#õ¤Â¯ÑzRÇî“êÂĉ\çL¬Ñqë^õ¹!½‡©ú½ØOä\ÈŒ5p(>ƒ~58ýjýjýjÐÅ$ÝF“+b™"9Œ3 ýS¨`*W°2æšÊ˜I™ª‹iNÉU±lægj¾èto€Rx EÀ5êðÐÄÔ«£…ÿvž›çwŽ“wƒJy[‡ß¦ŠÔ~«EÌÓ³lÀ(µÐ_û¸¼ÁzžØ Mg{ªj9U%Vêéij•«cÏ)à8)CFä;Æ“µA¡ÐJ ®‰©$‰ðŠ’}• [×OÁ D#ë8¾ý–1©¶YçeÄ}ÖV¤(XpOCE›zzÉÁ’Øn=Ž Ã¢pgB’¤qé'~Ôv"2mŸ ׈-œ‹éÊÆL¼/JÖác6ýd4H?]ÒyGt›ÐcЦwëõ®ŽºöRf)K•5Šël'u Ñ\S‰Fhçšh€Œý+Œÿ4 t–;Íj›ŸÃõò ªé¼.)Ú‹˜ÌIŒË"(#x‚.>E¿¸‚´É†s=D©OT¿Å‘õþ½Üí¡‡j¾‹xˆ2¦j¸…I€y•®§éd«T~ÛgxYõ÷%‰’ÔͲÞßSk†—ÑQW©¾ÚgDYõoå6£÷¯R3‚bVjÿOŸ78öšŸcߠئþ»>#˪/‡z_¹jFRÔ¢Jã}F•%†—%F”%Þ(KŒ,û™^3ŠRnæpµÏè²ÊCå‰ПŠnñEíôÊ)ú9%`ÿü©Z3š2/®´F©}Æ {½£¹sc(zI¥{´ÚglYbÌý-5c)õÝJÏ"µÏ¸²Ê{þDûÔÞ•—£p_‡ÊEhqQ¾ÅÅOÐÏÅO8?¿4(WK‡Ÿ5㨒¥•ÞjŸñ²åqÜòxŠ^Vé[©ö™P–ÿ`ËÊ ïgßÙÚå÷bĽ<)þ61¤,4Jq‰gû )«~®÷s®¾CÊÄ÷)¶ò‘„'ñÝÔ½H¢oêL»ª†.žCôº.‰(¾®ŒâÈø þª‘èHñmÈBÆ?øå±Äó?ùÊø?&–x‘âÕGü-QNñƒRÆ¿ˆø÷c‰8Å×#þ”Œï…ø}Zâk‰«FêͲÄZ_ê¢Ly )kc‰R8å’Lé”b‰2¤Lä”ó2å‡<ºX¢3RÞâ” 2åï²>–h”iœò¹Ly™Re©÷:T iRYÇþ\ƾ/c'Û±¿±keì;öWˆ-OÍëȱSíØ¦XhYò6Œ`²þ•&ë×4G˜Ÿß@±’p”aþigx»lˆ¹ÎH¦ûŒdºˆÚ9UœSÓ¯¸2ßW²ñÛ„¿Fœ÷ç÷sÞ œ÷¥û8o¡KÔ®€óž^hø¶ÓðmÙðmÙ0‚1í®J„¦Óðj8B ß»¿áZ-ßpVÜ0QšE ×ãtžQhx´f7Ž•$êéÄ6‹F¥ú°‘cBr«&ÄÍbæ:Ç̵ËõŽ¡»M«VE¯æB@]íæÖ¨k®F#ØSìŒi 1OÉU”á–d¾’UVûd«hVª?y¾b! 7Õ Ñùo3ÔDÉÚõ"%©óÍÊ»J&©Cd¾\¡ó%uÂËZ+”Œü•ä|¥B'“¸Šßp7yÅj…Î$$Â+‰2äý=\/[aÊøº~Vðëà+¬¤ùuð°ïS›†LKºªÕn•J„ü¬Ulp3yànQr½Ä6%S¹+o,W£Yß0¦}¬ˆ)va,ÕTEãŒÊݱ2e;•>Ÿ\³×ÀsH± É{b?¬W¦cÍLÀívòná¼GdœyÏÄìŠ(쬓ÿ#Î_Ê—ÅUˆý´|JøN·Ú“Ƚ= †uXIç2U7i2?SªO™oÆãJ®ên€x/šþª+>EœV æ\@Ü£i1Ò8§Ø¤5n,>Œ)qA©îÜ»³«¶s‹¸¤¤³²ÖË Ÿ……‚W‚Wù G¹®ˆë oõÚŽ-âF¾à—\pQ¡àm§ ôXEå®"î*Õ_ëý5Wí× €élã‚‹ ë9Q7Ê ÜATGzG\µ‘Q¯:«(¸ÄЩàoQp’Sp’ŠãB™¢Š)juYï2WmY‹˜Š‚‰±eTVƒ†è^§•¬š•¿ˆ(¤%ˆ¥|£TÌÈÇN رiSÌäFß-ôvŽÓèj4SÞVÅÛjžŸœŸïm3\j@e£ÿ+ê[¹0$þ¹˜Âÿêö½Û»jÛ·@¹’z§*,Ô‘µ†Ng÷בçöµÃ/įÒÕ¿ËtqõþZSoò5ÿ|ö— Û+TU*‚‡rë Ã2­3âͪ>]\­t ÙZ~…ÛÕ)׿‰cm§NûÄ«‰›Jâ–âÿ?ØhûcÊï/)bêÄï%¨?Hý§×ZÅkéêAèoïA¦R3ÐL§šUcT—èO•dÙ¶EL?ýG&ÑqŸÿ3qV¡,qP¨M¼[ÿ«_8ˆÿÓ•ÁJ†_˜›¬xôïËèö,3ñãUÐöâåÀÁ˜JåPL¦ñB ÐÈë‡GEÔ„Tsó¦áJ:±¾„’ñ8i—ªÕ 6ÅŸùòZK¥š!¦¥Š‰ø2ç)ÞQLê]wýb*h2&5—…S á¿àFm#¸]Ö#0>Gdåó™Ä0s™TfË$–¨ò&í…ꉥéÌÏÔÞK•^"qæfÃQJ¢+«ç¢ÎÄ¿—»³RÒ090’-†£ð²ÓptYŽÄDyuÖ¬xù¯j†›œkW>×(ÓQ‹ù,&:Vg(WeMXÀXÒh³€FƘ>Ÿiýúò>SÜ{C[Vîº÷è%åhLAp,¦"Xù”†`ÕS:‚ã1Á¼§M󟶌yÚ`üÓž{ŠÚÇŠß*áµTÒû’W x SSRŠë£yøXb~9Ád\!~âëíøñ&t¥ž`Þ¦ÒõEû>MeÕeñÆ2Wߦ2¢@*•Æ}f•±c‰¾³ ¥™`꺦?…š,—5X—”1ÁɘÚ`‰IVâ`'˜JÌâ] ?blÓTUM#ü23æ#Õ/õ~ÉUûÒ>1*éÚ÷r1:I ëܵoÚ/ÆØŸs½b¬ý9¼³gŽé,ÆÛŸ·1!•ÊnæÐÌÙöhæLÌõy{ñyûê’Þ%®Ú’}â|û ^¸Oh×w–[\Èÿ˜îó?f»Å¥ü¹n!Ú£î‰&TÄŽ;uH4A2‰ÛìŒøú¶ž^}1¸4C „œÑ”.·)Ë$lÁÉ´‘ϽO)$¬@ÂJJ¸‚„©&”æ£HhaJtõ#®Â’-^ÁšGÔ‰­ .ü?á'lU·Mènjï-Ó¢cúç8è?(‹”Å* Æ35­&ž£UÔÜ2‰$‡Rp‹)Ž*xÁJe+éêVTÀ¦fï5LV¡ì nÍ“U›O›¬K)ãŽÉ¸£&Qð¨ë¸)>§µšÐÚ'Š=®&Þó§n·KÝðÆƒ Êœ’eNšâ"´c¯˜âŠ___šâ þøÂ×Ü ¶T"ÞÓõâòn` Ó~Ý1Î[€ßjm¯)mƒïeÚÒê*[ѨÇ_SÓ ï†M­ !ú>‚ÏÙ˜«V}…X½W1PM§n™ÍŽcl  ®¿c(¥ÕL5—÷Çq+¨¾¢Ø©÷¯QÑájÚŽ@ßP¡Y~2¡w‹”yVûÜ2”e²Ïñ•—biP|Žç´aVjž’L­ëÐ\×wQ¹¸.(ldÜÝŠ;Ú}y˜UÛEnä.\ˆ§§SÇÀE…„z$ ¦„HX\ØáÃt{‡ÓÅp†};|‰ %¸É úi:¿Ã‡å-m*ÌÔal@™¥‹Tá>³K[„ÿè%f—±OÀðM‹˜­gÃßu,bê\]ÌÕ³i6½Õ*ÞÖ‰=‹|ƒŸÆ´ùº˜¯gsãaBm‰wô${Q“. ÷‰…èuh±ŽƒõÝÂàÖbpðòÛ‚Á-å¾ïà¾oÔ¡ðÍ–Bÿ¯Ä\uñ!gÎDåífs»E·ŸmΨêØ^wåc/:åpvÐpØ뀰ºK»ìáðÜò“r-­‹4 æœád0Ô˺)Ybç(²K[_êê^íÆPû»õKåÜí–´µ‰ý¸s\fÂ/ä]Ô!T7Ï7%?Çc:DC[ÿˆrTG)²EÓyÁ¬DG'FÕ”¼âí$îI´ÀŽOêù“¿õŒ´ñPÊøˆ–dÛhÍÝ5ž§õ\ƒcàà”‰Sù&쟇ðòTœÑsyë'ó‰’5ú"¦ŸÓÅ9¨|ÙyÙðñe0'xÙ‰Hxÿzf¥j$¡˜:¡C‚Ê=€a9ÃÐÒUjð‹€§]ƒWcÊ C 1Ò˜Öl# ÷ S£UòŸT@L2Z¿5Æ?sãŠ|%c°¯!×täšeоßoŠÙ†ÄwsPÕ*Ó LO S32-4Ò‰áÔÝŽ´lPYÕxK‹ì’‹Qbµi¹uã·(±”{{-æZjð[*×c*‚1 Á—1Á͘`ýÓærC,7ŒYëég‰FÒbð+éž n*¹FIÖWÝ ÐaŒFטînœÓÐêË¿'<Ú/xIû´k U>§«‚àòcêZôƯ}€öŸÒסý§ŒõÜŠ™(¸³6Rp'æÞDÁݘçC ɻـ}MßÇìkúwx­ØcˆµN]inö¨i[Ç>hÂmçÎ]™tÌI:$ÝG­32¶‘0vÈrÚÌ5ÙNK_]ë©ð~‘¿ÁHœ+!V~u{6B±‘šò§[lÂÏ[ëçr¢.zÅfCîá~>ñ±‘ô|Òª€_ì°ó¢/cb‘ô¿Ö¯$XÏ»úv’ »b-Ýgˆ H–Ø&JEÖH–Be…ík•Â9†4.rFð9¼˜6Ò‡ó¢œpAŽ-F2“â#˪û©¢L2Èö P¿0éuì16•Àürû×%ÆB¿©Ô\%2sþž©yuc&ÏùQã>;ž¶'5šùS˜ë˜" qÜÀ8»¸ÊÀ)Ÿ0^§ …ú}â 7É&hù¥îYêwת DB gŠ<†Í~Ù(Úäcˆ+FVèß"®Ò¨,Hkh©]—Kí†\j_Ê¥vÓ×ÿü’¹ñ–Ì—†½N ˜_w ÛJ¼ª0Ù{½ô$f¶¢Í€¶Æe¯çòÊ^pÆ6€xcu&[RdfaûV ÏlÁ ƒÁ‡ÈßlìæžÛ ¨e-·Õ²†›45GLÊ[s„¸Vüṳ́œ5Ÿ™b ŽÖ÷ çÖ,“ÐÈp„ÈqÛ¿"ámØbX"^/)m1e¾)æ›’BæLü¬¦&‚Cê[D³™E Æ^h¦$Žh‘Y˜¾[lâd›h‰%¦$Q–¢#˜*“‡ùHYA >¾ïñ–n­ÝpHÖö$lG'\Oe5u=Õ5¦Xgö,¸Áä Û'6ÒGõz‹Ødb*û·²gÁ-&OÚ>±•>"y›‰éìß*vš@õ2J’ZvÞŒ  Ÿ¼q²4´U–‹ÉÔ½ô½’†ù †¹®ï€÷)k"³¼Ï8ð>#á}Îçòð>U ïÏïSÞïSÄš…UÏð¾Äðžl aÃû :²¡Ð‘;莡ÓèÈFæÚGòD ` ÉÙ‡]hÓꩌ  ¾§ú†%Z8 X{nõ¢lM2”M‡Zh”ëa”:ÂbÔÙ"Þ°hÇ'Y°~=ÊÊe#@6c¬tWâäÄX+C‰qV:±Ü›Õ.—mªj¢Í>Á‚°Î„éÕÕÌMuº5•ú3¸§2•QŠ:‚!=µéÜI}†%¦YŒHZÅtú˜aa£Î°¤Ëà& wÐ\ìÌôašéžÉZ9{U½ ‹ Võô² ¶27ò^ÒãÓËØÿÝ|+›g©›’VaœËØ€ö:„. 1cX ²ª£fc înYé|ò,¶$=@ÿ@ìTeÝŠXò§]àüv'p—+–åá"k“ÓÍ•›0ø°0㛀â# x o–‹f|+ƒöÜî­rƳrÆs–Ø^˜ñiNwZEË 3¾›gü 1G”šåºiÆs<ãSxÆ÷93ÞjÏø'˜q*±_ÎøèüŒÄŒo6Mšñ‹Ü­ÃN·Ë?,»u„‚¡=µÏxþõ£–8b±S Ï¨ùé<ßG倷LžñCfI, ÚûÌd„È M¤­âó¯˜V/O«Ã¿þöæ•:‘‡ŠjØäë%‹q,RÄWÌæå¿ÔðU WÆ[˜²{Ãì¦yê®~BN- Íà¡õ~ÏW·ft4rŽu#%l+’Õ!aŠ…)a»‰w…Ï1iéf,ÓÓ5Ý}IÞSi¢`DOu¦[4¹mÚüˆá™îl hšEœíÎäfRU3•ú·Œ¯ÑÆ*· ­î!IsçÙ}ùþ|µ¸—XãNã#>Í­»£PËǨeçW×ÒÖÑ®e—‹¿—ØZŽ:µìäÃãïQK–‡µûW–ƳçAöAæ-ë{ݴ莚bŸ;„´O´¸i"étlu¥sñwºªÐä~èîì2-X”BrÕcB®ƒn8Q¬xDýÔ-ó!. êÎó0­âˆ;—““¿›&ÿ¨ÛTœà<‰¼©qíâ_¶Î{’#«ï–ÈønÝ2ÙÞwKŒª6"΢/»™Oþ7te2¼»ïcþwªG¼åI§îªyâGz{»çD°8b\¥ïà 1ÃSUyå2Ñ™éP¹­×é lò€¯ÝÃm>Š6g{l+†s=b.Õ1“ 5RÖyœ5ÍYÄI¡{ =bÑ߽Ų{¬C¹'[Të2®5SèÀJ§«=b5åšmá(GÞã¬YÓ«mñbòؼF·~ÁnýB„4:»>&²yÏ×oôT³Œì©å üpׂðå_AAúBÎ0þDTºš½°!© ¸ÕCE0º§†`RO}!u‹¼Àêæb¯Xä•´ÑeÞ‚\Êb?ò¬[NnI³^K½½Äro.©—â…×ÃZé£ç^CÁäžž÷(˜ÒÓ»–‚©=}RðVOÿG^±Ò›´r6ëy7L¦q«QçŠqì`yà;Þ¼á"ž/>ð&Vè¯À¬ ŽÖ{Åz¯#®Éàæh¸·®hn ’z“žÔ¾N:|äá>Ëî·Rœ&Å7tf¡Ä6/ÄàïXˆ×£d§ø³t—b¯àn¯Øåýÿ({ð8Žì\´»§'4â 0 $$Z2½+SÚ¡ýÖ~ëqik±Á«]¯/dp¸;¦ýV÷}¶,®}}mƒ`Î9ç@Ì9‚9ˆœ@Ì9's&ÞùOu£g(i¿ûô‰¨éª:åpªN§èŸS‡8’ã_>¼¢0D”Â>‰“-biáìpFó8ýt^™YÌ,±W&A4øÂ¾°7o[k«h¦Î‘ÁÇ®pzùb·“^§ …3s‘×°QÎLŽR^_Ävà½S‘ßúN¾³”Ñ•rÎ¥‰3iɪ ÌÒ†ŠAÏ&µFŽ8Kúù™+Λõ\]è/³¬±çÀ®Ò±Bq ¹àÃs#­Í^°ë×db×sØ›†ÒusfFÏD¡¸%í£sÁôÉiÞf´˜½œ˜¿A¥%õµp_ÒZ¸:Z¸/épf÷Òă´XY+Ûx˜–ˆ•Ÿ(DÙ]âIZØÒwÿ#Le”þ?§ˆ³NH¨rŒóé”<Ò_ÑŽIÃS¼0£ÙâlOÚ õ„ωÃCá3˵r¿ÚèrÑf¯Ÿ—¦ã ¯+`‡sP:.á0Þ¬KÏu8¬8åÂÔT±+Ç)C„¡‰÷Æ„ @˜”ÎË8»žœnݱ]Ã&W™Š5F*zãK#1Í.—AlŸNÕ¦£ª{4ñ UgË]‹:+¨Ô¦‹å@tµéºíj;¸âHeÍ j}º¨OÇ©áˆéñ<ùX•ËÁ ¢5éñÈŠ¢Šh0§ÿª®´¯—§w­W~-oûµŒõ®u{ÿÐs‚Ú¦ôunб™œ1†¾•œyAç6ræ]ÛÓŦôo<«‚Eôo:«Úšž´EøêyÛÒ¥ÕØ¯~ºØF:Ž·ÜbW:ÖéZ7¸ Ssü2þbcÑÈr;ˆ:úÊùg\qØ•²/=!ù+)ËËd°5u€£”)ïU¬,ÒÄAþÂ*ôUEº8$!VÁh:­ÿTkâ(ýpS-ÂPz‚êUÄұïs‹&´ûq¾¿[ÀCìD:?‚ *'ÒÅ©ôò+N§ËÛ¶3éò.ílºd`üü¸+gpù§¸”Ž‹²€u3‘zkÖs¥žÝÛôÿ£;·›Èî ¾*˜ÏÙ½®þ{ãDûœJžYæo‚éÁTñ8˜ë.ñ”Ë©ÄpçŸUzdMQ4ò¥»â~¦&^H?wd-ùí”~¯ÒMþ&Ð¥Œ€•I) °®¿¤¹¾ÑеT?2(·']PkóHÞ^³¹íeAeX†–-?àQªÖ(Ff˜ îÊFd‚£2ÌŒ­'à#Òo´oCQ,2Te¿1ÒO‹l$¿QÒo¬E»‰üÆH¿q–ßfÛo¼ôsF¶_é7ÁJc+ù —~3ä1Ý$+­m6Z†Me¿.kƒ±Èé3]ÖÐö"¾™a}Uy";ˆl¬Œ4Ó‚zY‹TK¿Y–ß+Ûo¶å7©}›ßËoŠí7×ò›lûÍCõŸâêÅտЪþÅb±]ýKߨþ‡D[ûFõÃoÙÕ¿åoT?üêÞ¨~øÕ¿Qýð[ñFõÃoåÕ¿U|b*V¿Qý[—RýðÙRý¿Zýˆ´éê‡ßæ7ª~[Þ¨~øm}£úá·íê‡ßÊönÊöN4Ãi³yÌî†-ú½³9ÿ@yÜÏÄ0º,f¤GàÊHŽÙÒ<$¬øBæ(%³š’‰’»‘ÜxFô©‰ŒhçÞ7]¢ .úãf5ž@~ÎðáÊÏù–Ù9Ë€¿{ ÁRzÐzQæüÀeÂÝ@¸WÈ]IàŸåò øw2°JúlbÝ,ÏÎ"î‚‘q²» @ߦ) ôçlúG Âô|ÍñìkèQ'ÏQN¢ úó\>h}u&ˆ¢å›ÜJÏíEáGð³¸[&ÄÝ8B@^äC²\ÎEàüÌÊYþòY~’^re8—t–:Ê´Ô™lª‹3¡ÏäãϤœ•n(7 Tßs}æ4•œŒú@Yœ)j)1!L—e~$ê3Í:ÆÍœ×®òÈ4Þ´ š÷Ï(d êY7õ NXûLk2ùͳ{uîòÖq* ´®çŸU?Œì¢>´Yö¡9rU¹;Ÿ½wÓŠº)3è-\ÞÿM{•-ŽÛl°í_¶#3ZþÊ¥ä@õNùÛ†E„öm‚Ýi®9ùôµ—©üØZGöY¿öõøXC}Š}™R Ï­ËÏÓžû3¥–­|«[ýü3‡8€Ì:äžÁe.Ÿ}rÖR†!…#(çžüο.%óWçÎßéqÄ•††‡9UáâæGeþE4¸PûR1XUE<Ó[ð¦~Ÿc™xôýÿKÍñLÅI °š›¸:ÍüH»ç ×ÿõFá]ÇB})uç¾"EÕ”ýEŠö±r Hq¤)‹Ý­*Rœ÷\Êe—ÃÍ6)©sÞ¤ÎÙ:¾àŠ™iØTnf¶¨›ƒ*œ[]µ~Yláüc¨ÜëRÃq—bm'f‚œAçƒLq73ù I-_!fÓs"“-e¤îMá ˜HŸh¶]ÂòÁ×} 2a°×m¶Hù¨Lɯ<$ª\f=ÎŒq¬p…Ô^‹þ¹u|Tø„HcñŠ-nÍ CŒ/2c˜°bâc€óe[LÑ7 ‡s<k²>ý²*?ŽÅ¹ç5‹þYÈFBö¹f1 +š¨ Þ&Âlõ—Ë¡;Ïs]ÏÂʺ3¨Œ‡½ó :=KLÏ‚xË̬Xëú÷œ2% Ó×,˜Ÿ"Ïªšœ‘“¾Ù8]™U¦²>\1פ˜Š °°óÞ¤àó˜ùYe­MbÅÆ^b^þbÄž”‚ÄfüZ“bnþ²7)øˆe9r$VfÅ“G”pMdx«³¢•÷\Å _{.£cMVÊÔйLy‡æv§X›%§,Xë³R§‡¶H²¢{hÙÄ ‡iªÙš…‡FWy®îÂrRTÑ¢"<Åå?Œág™©+Š|YÔ¦0ˆ®ñ ÂÒÜ»A´§¨@™Ÿã¾JzÝ¥géÎ¥.ÐÏ’fkðJò÷ q°´NCÒqœ”™°¾¡ÏÂÑz’œ]Aíì0@¾;¨ÃÖø†®Î;lœÜ5%C˽€œ=AÏ¢lq2«í©IœÎŠGÎyÊ?Þœœ¡.Ô]\¢úÚæVªƒÍârV§¸Â×(`;h ÞÍŠQûߟÝ4f ‘g¡4)"Bã'+ܦ3=M<ʲ/aüocèd…ÓØœ5XrÙ]5>uyšvíìå‚3ñ< ݆âÌ”çX‘^˜‘¤—}Á´êl¶P~Øóy¯tÑ7;ŽŸo_wÏæ£Ü~Nç2öÏFQ^@l6Š>®^òˆbžç.÷-¦ùp l$s D•gÄÄúgS¹3þ šZ²ã‰¤òŽÌN*!®ùG³uë2m6†VÎÐÆd7H‰Ëqlœ<³ Œ$Š“…ðñ.&"Ù2…Óä£q§˜’;Í“·˜švózüLÍ@¦q¦ÃwL&äRåþíòôƒô™Ôè£ 3fe‹™Ù(Sš'pbVv8C>"é•)fg›½"Ì'záL¬÷\}sR’_<#{Äâì°‡ÏjQ3ËÙTË„¸qÈô´ì[ßÔ€|Vý,å-˘ætõ’2cÎʰhf™|"Ì4+˜f Ñ(Ê ¾Œá ÛN6¤M;Ù°ŽeXî*cå› e"KAìfÿXÅ0ZC÷àqÉM¦g¹ýýþlq0[²’‡²y¯' ƒà–àq‹à8¦oHð”™àp¢? úÛ.ØðØÉ;òëÀuœjK¶¸™Íļ,ÝÊþˆ-r·Õs“ÙqÞcÝÏ–÷®oˆ `«ü0›§ÕXäu–5QžöÍåÙøQv¬b³¡° Û§Ù¸µE¥¶!œ5ØB÷”7xö!Ä+åWÅùõ‰×,É0¯áýjUv”WVÅ ªŠ±ü»|ºª0ç>έ8DÕ=F—ïò×kh²Çao51öd¯˜Jt·\¾¿AÇ>@ëWL÷ò´NqÄ oœ»à,oœ÷\ÑÈA{–ŸÍž˜úwÙžs½rê_à%àm¬½fs#K™.ã÷Y”ß*ãz¯ØÈù«Â¢75_møÍfi‡ÒV »§í°vxa»šÙµ]VÒ Ø ‚{¼’ðò>"¸ì\ÂÃ^k-“¥”Ì™7yÛ%=ü^‚?ê%.…Jò}ÎÊŸð 2gå`P9ë…¡hd¡j¨kPõPW£8çY¯ì¢æe÷y/ ñc€y`ÃÜ´`îxaú9æîWaZf¸ F ¡ú”aÞÌS«bžzaÙ9P±‹v=/ðc3ýx‰Ø\0÷È$¡ Íæìª³y¸¾n0È4¡¸ zØ’8ÆÖ6ï-A3|i¦{Â'*U|Hl¼Ö'–û¾:Úð~aååA¡ik!+?àV'2ß¼¶©×±Èzƒ7¢«|²£‚­XƒZ|ê’ÖþÐå­„ÖûÄFŸÙAq">³Çÿ~+â~Ìíø?l&4”èúRÆÔ'ǰÏyÛõû€m„Ùçã>‹mÃá ë NÏuEâ$h^`ÊH;.%s|w|(¨žñIýV2whSý¹¡D9ã|P*lˆK>0^Ø›wÙ' ¼ßCÐUúÏNOrĨ]ó£6³ÊOy®³Ow&þcǯÕßGŠ¿Á? Òêk¨1oJ( Þ"®í‚yÝÿ¢ ;>¯÷ ¦LZ‹/Ð]ý`‹ºK%ŽL?JœØ[J”8±o)1æÄâĉ”—,Gó3~•c6FuN‹z8ÈV{¿ jÃr`à·ò-îèo©å‡Ý*¬Yƒ©à%Eò³YŒÉIĹ0ãsäT?j;^¹ X» ]Xèó öHP]˜#æ€çXœƒ6͈¥9²©GPS/ËI9Pf×Ë¥ß5²Îñy“¨Ï‰Æ+ŽÑ_´^sGŸÅm¹ÚJluŽX›#×äõ9|ãˆ$̃˜¾ò gƒåÌô¯‘þsÚÎ¥?é¿)G„·Š‹‚>9Ðþ¼™ ºÄ‚2ú@}KŽÙÿQ¨­Èh+÷ÿ,Üaåó`Ž8,ëwHGÌz‰.ŸåB/E¡QZÖzω–)\ö «Ý(û$.{“…Ù”#N|M™1½Ÿüš2ÃÿÔ×”þ§¿©Ìg¾RfD?k•8‡ öu£Ìü4ðŽ•¿;9¢E– Ÿ0Ë<ŠHî¤Æ&ym‘¼ÎÕ¹m$}s%Éh"©Nú~î¶MÖÈ\“dd®ûõ›¬1&}_ì,@ßߦŸcÑÏÉó¾~¾I_Cô @?ÀÎòJ‹~e®XmgyIÒHÖ‚d ä.‹dW®Øó Iî5éûý>в“ç‹&/Ž¡§æ%pÁÓòaçœ/šÅ¬¼°+²¢(Yã¨XYDÌ´ü®L‹—§©•i ú‹wJ|“™ÏAnãh›2åa3žÈëóäû8—Ø×v¡½MÔRÜy3UßçM^TÍòtg#Õ­”êj w¢ìÌ »?oæ( äéÊ@”]å@6€qy˜ã)Ÿ¬Ë-ìù«51¿Ãya)PxΓ ¨/ó̯q=ÚÖÒD4/ìÁæ•=ãä!J›qJ<}Ì“Am&ZDñy¯ ïR>ÙºÌ8•'óÂV ¹¹&ZßÀsŠæ¼p:þ¤Å0)ŠãTé¸ÑáÃüúöA⟋T||Ó¾×ñšáò›c%>çžYŸé§CœÎ ;9Ÿgò™\‚D^CF8#l´û!mdÏS'LC'ô.ÃÚp)˜y9O\N®Û,q-/œe–Fîé{'ùßUÁOÇðNÌÿ8 ¡À2%ת¬¯©ÂÛ6ž];Y_[;w’’À+Áf—pͤƒf,¯«¿Â˜yÀ“Çå ò$O<Ê‹VÄiÿù$/Ú¹ü2í–Ô(žæÅl·ìy´å°Æ¼yÑXÅ}*|:X‡Wy1ÓšÖKŠ݈ùPöÿšz[u;hEvk.Ýy›§ª~¬\ãÞ‡J¿vHTÜÃOEΕ c49Wƒú˜vbp»è;2Mbh»x€ß© o÷‘ÕŽ'ˆùjuf³-?poGÎTOo‘õŽžIDV;@·Ý˜¯µÖñ…ŒµÊÁï Ƕ‹Gš‹Âz. 8®Mw=›‹Äòv²ïDòubI˜L¾¬¾SÚÑÖþMGÓÚÅc¬r:J=žW –ššez–,ôœvbN;«†›Ä\” òüv»‹…„R~²öx‘ûK B,£‚´¸p×#êÚEyðõnq‰úvÐ`ìªh¡<¬â(Ph´Úí ÝÑ:"›]ÐN2.Ç|™òK™_@U‰MÕª]’jë7QmeªÉ6ÕPí•T[¾‰j SM±©öƒê€¤ÚöMTÛ˜jª½ðÕ—í¢å§Ü¬µC¾?æÂw /àJÍl¨D±IŽ‚$J$§ß 9J2Ý&‰ƒ$A$gÞ 9“J2Ã&iI‘œ}ƒäl*ÉLw›ðþ)©t&¨œj'δ‹Á:8GrÉðƒÍº@íÝ£G¥÷%·¸Èþ{/—ÌŸ'ŠÄUþI¨³Ü¸bÏä"¨›–íP³y[<áÈ|¶RÜÈÆ•Çæ‹ÑùàÐFR÷›Ol.®ojšÁ¨‰ø[OŒÏ§ñ~—û:4ßÕÖV6¥<)_^áÆä|û5ÆúýX¾É›Ê?¥÷4úýHzOçŸÒ{f>4˺=¹º3žÆo"eö Xì•e?^Æœ4S~+¨ÔæÓ¶&¨Ö‘s'¨­$çnб™œ– ¾•tn#ç^еœûAwc>ÞT{FÐJûž1¦÷Iiã pŸ”>¾@, ,µÊÛÊEù‰Ú|–¸kËò“ÞMLL>HÆFvy>ìv^wuÆs+¼?ªË7ŸÝÕç'=À˜˜|„ ºLwèhðàÚÊüp,A¾¸|ÌÖ§Y¬Í—&l×%Uð¦ühÅš§7³_õû0Ì–ßv+¸EÙ–ØÇ-öRœ‡üܽÞ×ùqo}Î8~”ÌØŸ—Ü™ò±éÉ:HÎÃ`ö¡|±?‘º"´…8_ gFZåA,àYâ`¾\cy\ùóô¡üp6LFóÓæÃÜ?ÂÞò±íù¥ö—ùaÚŒeCôüh~ƒ[DóÃÎ067N/?”–n¤X´5ñŽàÁ£ ÷åèqÐw9_œÈ‡E/™#Ÿ8™öqòñƒÅ?›ßàçòˆ)Èoðˆ ù^Xi»,³á“ÙÈWòÃ9e­¼Å½ž ûÂÎ÷vôrVÜ¡½åM¢õ"‚<ᜊ[äyâc¯ÔœvqåùMËÛcÄ0o:9Ú3.]‡^ÊÝh«WÔÒ|'úÀU~²H…z¢×vS²¼rMG¢~v+÷/€(%ÅT€ATÓ¦Xá±|ž]O>дû.Æ’ú¨-”ûÍ`€?tU\§á;´ Ú¹w«KŒ(ˆV<¦þ3ª±ÕmæÆüùÊ>´ÃW`^–Òžh|u?š!&TÍóC²’ÕåÇy¤³'É .hל,?.º }sJËtÂIŠ•#侫-]Ësåb*ˆÃ†˜VNOÚౄl£ës1½ œaÎÀÆ.»qIÁ3 h¯¶ÊG q럡p¼›Ÿ_Ào•-Qã³2a± ÀÈ\T6"ÕYÌë.‘¿£³ U,/€’‹,Œ%Ã~OÖ‡_žÖð8Î…¬ú "JzZ&Ÿ["46§í‘ÙÊêÕWãÌChÜŽ¿–âT ôEîçó6Ö„ ²>éÛ¹3mÙ{ ôÉØ›  «Éíî¤;g³²m˜[Ô¨þ1¸¤·˜KÊ'Ÿ^{Òïö˜e‹0éÓWD騢> *Ûh¦\ü¡ºƒœ§A­œE:ö“Sÿ®~ 3ˆó`tA¸‘ó,è>LÎó çKr^9/ƒiÇ ðj4ýTdœ.€B€Ì3Àìšut]³Ï‘Sýïr^} 0£ç\BÌ`î3rZƒþ—ä,/ÍV( >Q îù`[ït‰Cm½Ó-„]Üc\vyæÆ#¾,»ÍK\”Ü@šŒ ™.09‰žå s†KǨ31YÈÒ¾–,]4àáUz›§¼UOMÒ?l¼Ínól¶"óÓ-Ë÷T| “!N|ƒÌ9MËg ¾Iè1¯Ð[F¿&ÂN´D™’¼.Æ7×amJ^Ukl.k_W(ê ÃU¥ƒ0eˆúÂpQÎyãX´²P¬¤o몱W±XU.¦ÍMF[v‹¥fNŠý¡Ñ²Bn‚ˆþ|zÀ|•LRêãVAmÎ!™CŽâõ…bm!P ˜c´X¬ÇLÖÁû6ºÊ†B^‹;PQN)CábÖ¾´±–Ë(jC‡psÏ;B}dSaÛwF¶hbêêIûGÜ¢Û©E¹u›DCa8'œgWþy–ò¯­y/Ç\M)°o ±t½:yäx-?#Øzž“Ášr÷Æ#ûÚówÏ9œ×ý…qÚÌÌøÇ¬ q/Q‰ASz¸0Îï‚t¼ B¬/á1 ³ÈƒbGÑØ±BKñBoWUÇ 9N9üÚ‹ÆÂpûpN½¼Q Èwÿêº&Ô¡¹P4Ëø9´_B¦±6ˆã…áŽ8À®öT!k1dЇnÍû%.Ô­êùJ‘Áó^@v.2sƒÊ¼lVîЮ¤T¸šTØkoöú›…½A±¥í¡Û…²(~šŽÄ]¨ çòIúæL9׿Š™ñx8—Š–[ñÀí€$©¸O#®€ªâjox!íÛåÝ}ÑêíŠÞõô+5âÏd×àyiÖˆÓ¬ñ˜jÜgø™]ßöÑfŸþíaíÂíðèÎ%̤ jŽpÌÊ ö-j¿ §Hƒ3 ä€30¤ÃYô¡ΠkH{1¤=K?¹0vdªUíU·£epXû˜y°‹'1ÃÛóÃ2Zóözg'VÈ­Œ!}iÌÏ®cÅd#Ûó3жÇ;;nE%}©)f×AM£ «8ËS‹±¹(hæ#Ø5ÖU™Z SY,fÇ"ÛW—6Ÿ7â‘…ô;n^xÄyœƒ¯sŠã–âgŠßZXfÒêåwÅ—4]­Ý¾¬âtv1ݲ«ƒØÃñpÄÇ;3Ng/â/µ/J›­øÍĉ|f‹$NòO™Ä)Ôr¬òø.“ )w;Añš‹ªÎEΙ-ã›±Z~‚ð@æ´-y6Â÷ØÌ>fÛ'À^ÆÙéÄóXG{PG1¤£‡¡)Þr7D:XfÇ[¨ÌêˆÉL…3EÓfuó;BG1Šº4u|°ÊUºÉ¢Ù$i6uÛ:b2‰ñÉìv"ä´v€®ÞݦŸeщ}1D`JÃíJ×øÝɱŽR V’ú´ßK¾Az—8€¦Ž¿SµÆÔñŽ|­†uüdGùüåv¡8Õ‘õ{¯c5"¤\ \ ©;²v´KäŒ 9.wO¤·3:ääŒ ¹^36ä~IθçUGq¡£|L=‹Uq\ì(ŸUϤ¯&q¥#³ 8߸֑u05‹ë?1û‹^:öÄíŽÌA4‹;xŸz¯#³`'t”z|œâ!ÃÒzðMgØ€<íȼÖ¸Ža'¦¾è˜¤Œ†Ob´Å´ã±êËŽÓä#xÕ"—à©Z;‚'â+´?Åx÷à§ÜòüSÞ²s…Ý+¬ó®2e…)cÖëL«—aW×wßNmõݯS[}è$ëûß0‡Ã:‰a¹]È-9¼S8&Ö3IJמZû“H£í)mZäË´DRà‘´°“f'èÉ•ïâ!<-ž=ÞÕ‘öèNÑw “zR'ó4ar'êƒ+¹–ÞEÔiØ<ãQ¸‘'(U‰ö5Ðaê–:X(j'ôò !¥“(‰–¯õ(±žOÜ¢Têƒ÷Õ6ê„úÔ§)¨klÔ [)AÑÍD}ê$Qÿz3mÔ¿"ÔSPŸ¥ ®³Q+X%gH©?6QŸ¹ÅO$êO¡BÓF ê¯RPŸ§ n°Q#@R"¢·‰úÜ-þQ¢ÂxÜFõß õ?RP_¤ nbÔ2DýO6RþSü·‰úÂ-ªU ÛjÂ7»¥^Š<jÂǪ)È/S·0rgDϺӧ†”ñª˜¨šà/Ý0JÍà“¾Õ_ ðe©à¯RÀ·Ùàu >-¤ÔÑba¿r‹•&ø*€o·Áw|O*øëð6ø>ŸRö©â€þÚ-šà‡¾Ó? ð³©à­)à 6øyŸRΫâ¢Þꆺx¿ ð]6ø#€?IâLßmƒ?cð™!å™ #L|ˆªÝüÀ÷Øà#¡ |´–^íIßkƒe-è³BÊXMŒ×Lðj˜ Ið‰°$¸Ï_ð%©à}SÀ÷Ûൠ>;¤Ôjb¹Þ×#êLðz€°Áw¼!¼&ü  ¾›Á焔ݴU°ÀkÀÏØàk¾>|x øY|#ƒ×†”ºØl÷@§9ƒoø9üÀ£©à#RÀÏÛàq_Râº8fðˆF¼ àlð6óÈIà#SÀ/Úà·¤æørKw,ð‘q×oø%¼J³kœ)à£RÀ/ÛàR»w]Héï&ø(T|38+÷¾bƒOø´TðÑ)àWmð ^Rf8Å, |´GÌ6Áçüš åݬ‹; |L øu|ƒ¯)ëœbƒ>Æ]Ü ¾ à7lðƒ?œ >0e™»iƒað•!åˆSD-ðPG-Áã¿eƒC4«{N›’óÛ6ø_R®8Å5 |¬J¡üÀïØàOþ<|\ ø]ü%ƒ¯)/âµ>Î#ZMðj¨ÈmIÚqAEîXW øøp‘´ãbý½khÇå]&øx˜dêß ð{6øb€/MŸ~ß_ÆàkCÊ2V­,Á'x U™ÁWü ÞðÝ©àýRô¡ ¾—Á×…”½.èG6×P§8`‚ø£¤ÀϦ‚OLÉù㤃¯§—K\´À'zÄ%œM=<±Áüi*ø¤ð§6øsßRž³>c >‰8=ü5ÀŸ%5(4àŽu§€ONžÔ ¬}v#5¨F£$ødjP·Ù PWû"i ðe©àSRÀ_&m¡|m¡Ýb…>Å#Všà«þÊß ð½©àSSÀ_Ûàû|sˆ¶xâ >Õ#™à‡ÞjƒCÏ®8— >-¼ÚÓ~Á·„hΗ,ðiqÙ¿ð¾{ ð'©àÓSÀklðg ¾•¶ÐnñŸî/MðWïgƒ·)ÀMŸ‘ÞßÇš\·…ò<&ø ˜è‘à“ nu€ ¾àKRÁg¦€´Ák|;m¡=b¹>“¶Ð&8[¡dƒïø®TðY)àƒmð= ¾#¤ì¡m³>Ë#ö›à>ćÎZVO›>;|¨ ~ŽÁw†”s誕à³=⢠~ àÃ’àORÁ礀OjPo õˆøjPüÀG$5¨5RÀ禀LjPV »‹Ô |.5¨a6¨Áy|1À—¦‚ÏKmƒ/cðÝ4å².[ >¦\|ÀÇ$5(Àw¥‚ÏO›Ô  ¾‡Ôû,ðùÔ &ø€³ÁOüt*ø‚ðñ6øYßRβÞV ¾ÀÍ­ ~àlð‡œ ¾0|¢ þ”Á÷…”§Ô¢Jð…Ô¸&øK€O²ÁG¦ÉMK_”>Ù›ðýÄä¦A©_D£5Ídr¡tJRƒ|i*øâð©I Êà¨AYɧ_ìšOÙ ŸfƒïxC*ø’ðé6øn?HLnšØk/¡Ñj‚ïø ü8ÀO¦‚/MŸiƒŸfðC!åtš8k/õˆs&øy€Ï²Á¡KRÜK¯MŸmƒ?`ðÃ!åAšxdÓ$öØð96ø`¨¥šž¾,|® >œUî}R†§‹‘é&ø2•.ÁGCéÝ<|&Àg§‚/OŸoƒÏeð#!enº˜o/÷ˆ>–À| ¾àRÁëRÀÚà›ühHÙ”.¶XàuèQäœoø"üÀ£©àõ)à‹mð8ƒG‰'JÇ,ðzâ‰LpV]¸Ä¿ ðë©à+RÀ—Úà7<Rn¦‹Ûø ¸c‚ßx­ þàÐý—¾2|™ ^Ãzæâ!¥&CôÏ0ÁWzÄ€ >º–{Ú,‡Íïó"<Ó_呯±Õù0æÑº³šïov‚eî¦un©²°L‚©‹;‰¥Ê”æ(‘ÕôÒ½¹°—¢':ÂîH§hœrÈ–ë—vêª;|—Z[=ºÇ!ê@Cô<;z=EÅ#uÒÔ}\0 Vàl¼ÞÎöVd{[j¶W§d{…ù "J¼&%òJOÛÍÏ D>É‘qÆîÁUÒ¿²v'ÓºÜ)*x"¤žï$ÎtŠ!?=8Ûé#qžÈ–{¨(;ÅüÈ÷UÌKcÅSâJ'Ù" ÓTq­“l’ëâ cûh7:É¡qå]íÀ8kK¸\Ýe°DµDK§håO{üTéýÌ%„•Û5œÛÏ@ðJæ6¤¼ê¡fµ& Z;UeEžùcåçŠØJœ¨@l>V>Ê¥v5ÛŒT“舛:Óã‘~Yò5_ÿäèÑXùz6ŒµÖƒ+ºZ©q `&;4Т6†Ô‘¤® ˆ‘d2V¾Î£Ö4‰QôŒBÈwŒÄ»‹±œºT{oåB6Qm4‹q„©å5AÙ铃 ñ ü¦\<ËÒq¢8 ˆSS9¯)\Óòåïb+Ï‹)³»ßVÄÒ€¬*êŒ\ôZ*m¼g]‘2ÄuÙˆqî§õÙŠ+¸»ðàÆ”m„m²P7Äf"7,~y ò”ß‘ @¦ «QÀ6£Ú4…”h@Deþs¥2ËT¾[ž¥VgÉZÉQ,­Ê‹F6S›<ÊÓ`Q,vŽŠ¹Ñ ‹¤zUNÌh$ê¦@uN3¹½tqJ¦óHyûÊ™€8“ÔÅÙ@,çS6S—ˆóX´¼5“2Ò$.â9Ž ã!íR6×â74á‹Ë„|¶r r-P™ï"Pª×4è+–Ð(¸A¿º‹;³ oò@p K\Ü H•Ë–r¹G)œ©pN†48§B8§C:œx''œD'×½€x»Ê§e*¾ó¸©„Ý>¼N{I¾–"&·xE_±°›Íh½¦(òÁΧ¸,,±„a _¶¦„ãIAŠ˜9‡þ^nÏJy*¦f:½ÎíŸoG1õöpdŽ÷cT×™{p‰\ »Ë·y cÍ#†”P¤Û¬UK -1uç—oõ88tC{ø („öDޤTŒ´²[›Ãb¦g]5}`8—¼gC}.Óºsù³_㎢$qwvW—ÂÆC[Ýt£K`òz³Ç‘®;oIý¥%¬‹Ë4ÿ.l†}ÜË !aO º.¾ßêÅ:±•…%,ÑçlH[X"—𫎸ӮþŽc)œ éµäœ9—‘s!äZ^"––DÙœ7K˜ê¢V~²AyéçËJØd4+¥[^Rùq仞,úн¢D¬àÔº¸$†½„*ªM2q0êPȳº²ÊÆš±º„å¡<)òP†XS6"»½¬¡¢WšX[NËù+HRKÄ¥.S®lû°þ.S°l#ùõ/ÄÚ7ɽ^ˆµo.IP¿dèÍb[Iƒ.êJÐ(y±Ø™ÙÂÓ_±B ÷ÿ&– ÙC9¾R÷•ˆý%±˜ÔÍ×$”°”[ÌÊÌÁr‹YY9\%n[=mÂJL“G%âI žÄX€ói Ì`ñ‚Ãkæ Š'^q‚}]bLne?˜ÆòènKss¿R–²äº&} ô+e‘—¥¬ }`©P ýKѤm5—7ˆÅßv¾E¤!r .ƒKI’[CJY“ZŒ%R‡–z±¦+mШ«ËéÛNÛ—Ç)F”2Ž7#K£¬iü!Íùw 5ˆñ*…e-¼¦ÜŽ¥ÜŠñ¥Ö[#KŽ=ËØ^=WWë^bëS4er©˜ÊXpgÉKíOØdÇ©[™Y ‘Su^©˜ÍQñèWÌ) tóJMÑé&1¿4n&˜‘%ÓŽsW•óúaÊ“‘¥;rÅÖ–ò°ËdüÚRÈÒ«p–½­Á¹ÑÉçf'Îò·pêÞvÁYñ¶ÎÊ·=pjß6àŒ-Lƒ³èÃô¥¢Næ’­¿•¢y¹ÄŠÒÊÅ|8½ÇÓi4eˆ•¥öó‘÷0YñsÓrÛ±å,Õ¸Šã…3з09¢3֖еVEôÊëdšt)Þ¸ö±í´›—PV(²ÍªØm¥b§l.¼„o(Å®Keƒ»JÛž‰±ÔÊþ–i 7ìän+ÖbpÖ‚<+Ûê|©8މÚ74«i–KQF«u"§Šbu¾3+ÅxÚkÞ²oIÀ;¥âÎÿàr¼Ç€û*☆£ê F߇ÿ?Tž/ªÊ¿*ÿßêЛ½,­¼À^ÚûUnúÿСC‡ÞGøûs”û€GQ\j_’–CHÓ Ñ­ò‰'ð‹o÷þ–£qÃÛóŽèûPGårèqïRHÌ狛͆2Öx¡¼ «He~¬<_í2í-ì!ûÀDHì½&úŒ\,Š_ñhÕï¡Ü±ê÷(÷·x2)Ø_R‘ÊaMþ£håû=ÞWz_óˆîÑ@ï›ñ¨ƒãÒg!æ_K9’k¸ã‘ˆÉûçæ(ü¹øc”n˜Î‡=‰.Œ ªk i±ÿ'…ü¿ÑÈu ÛÛ¹ï{hn£Á¿¯j©ÌÂlöÌf—ßVú©¢Ÿ É?\÷° §²ŸTÒ(¨¦|å …­Œ¨ƒT1H•sÝ5æº!ms]'tmˆ*†¨qù®Y Uíîùô‰9¿¤ÜŽPmò‘Òr¬«c”*F‘?‹}êb T&è, i ²ŽS, 9YJ°$ä5Æ—&ª± BR1{~fΞSUd²L¡A¨Ši* ÆÝðˆ™è8÷y5jPQ5sdÕ4Rïæ…~ž*æ«fÓÆ Cs‘Z z5Š&C<’µHòËÑ%—WïoP˜!ßQëT±œ½M˜qÔ° ­SÛÖ~¨FRã&PÆPÞ•œÈ*•öáC3U±º-µøNožX²<ðÀê>'ʲC–¥ùM ÔÚ!e‡Ú¢^ ©p&|¨íUñzß±œ«!ý€ i™Èiu·ú$bbåä¶å€Z•YÛ»•ƒj¼LÉŠ@ë— …f\B¯>òÕ27‹¨šH ÷³‘{ÖùyŒ£…õ÷vôÒÍHÉ‘D³š–’½ÿŠÍÕµóåòá®Óª8¥ÆGCGÄiôB6^A…»r_¦7Bž+*dmÞ„¾ègjØ5›ÐQ£©·àQ(zeìsùž_F¹ÅeN8!OxĤaˆk*-®ÙaO&£@Å&b1»z“p?ïex!rx‹bì{ÛôUÀЪ¬8ø¡E…ýú#N1XÅ0íÒÂî9|nƪµ¤‹Ã%[ËÒv/Ul¸æ ì¯Ì–©Ôµ5~"ÓW ;A™Éàͬ?ÑOãz%:®ØþZÆviƒ5˜‰ÍÄ&dˆÆOQϪÞå¯[±Ÿ7Ä(-¥"GkÔîÙØÈѸJe}òCÎq¦ÏèzÈ£Ë@sãÁu>B“Êï¸gäÍ¥b¢†Y*ìÌž¤EÃN ÎÉ`$ò¼5›ç­9šTlââµQ{§;Ä›(±:kžaé­ˆ›SFu~'ÄgšÔOlÖ;a>£*¾RáÜi/ȹr¼ÔÄ ­Li/­äÆQzGrIï†ôV \í­m¼f—ióÐ%«\z§Uú¾YúL¨„ïçˆçt w€ô ãÅêìX6”àt„Ýy  M ÌBà0ŠôWÚ¢G§M_È‘x…äÛõ¦Jë°×Ò'Í©Sg8̺›áàrÎpˆY3‹S¿Ðä²üÔãÌÔÃ= Xæ0õí|UÕÎ'–2çÒ^-jKHYF "¤Â¹ÒV3ÿ;Ž•žvW9Ä N)n²U޶yvµƒÌÚ®qØŒ#†Ê:G"Àëè„rú©C Ž÷LÍ}JÁ›msZ}Ö¿`¡ºrnwˆ­Zvb‘!™¼òÀ ¹#¬·ÅäÑ»Ý!ç+—ØáHÄí™*g”¦#êÄ‘ž»e‘¨)Ê”XX§IJ÷þ=Ö‹7©´E”½AG“gIÆŒ}%SñäDxŸ}Ìa-­)¢‰3øYã)…#a}KÄ3236àYGBîIxÐ3áMìómØKÒƒë²C\v”©0*Ø–Rn6†Ü7P ä¹å7àºÁ’rËcêÇÆ ‚a †UüGí`—螃wA4{džï“GR8¼?T/tX=q4¸ÅS‹š“zæh ÅEFÜç—ç𣾶äR4ì8 ‹žÿ#¯¬hß'ߣ<³w,µ¥–®¯´Dµž’«~v0ºñ@ÝÜB.FŸ»ü¶1˜öžBiChùÑÛõJCôøç½ÒY_'6’éÃt1L¯ rŽÓ)ÇåAÕT°!†ëá ó U8ƒ7–ŒO¾¶†ìwÉg,ùð®qrAü¶ãõp?›š@?È;Ç!zCz8=vÏÎûoª„©<×Ò§lýzÒb5S7«9òzf±Ó¤°d(êM쾟{`çx&Ϩ›tLïÑîû½fæ>6éb‹CÌÜßâ½WDίPCCêNª¡'!Ìú;õÊùþXù|¿JÔ¢_ ’Íb·Ûثǹx°_§]®9¯Ã5 muÅƯèŸ%m„i’E^€‡rEývåe“{¿Cï«<Õ™zÉ…”ÌÔ+^s>º÷4$6²àqÔP6ªb3µø•¢TúVþY58}5ûmS+§Ã§|pºZ1<Š«Æ=¯‰Ø¾¾f¦óCàm`9©M]• NÀªœb“³í ê>[­Ø±Åa6–*¹•2ït•€øÇTù?3ö7&3öÌ#~íÜû¹G|í›ñœ®,Äü”bþ}4ò­Ô×p8®žðþ$>òå_hºþ®Úç¾Ú¿±¦ß}hƒ0ØÀ9Ç¿E#O=l±Yü;kÿÍÇ@þ_ âÝ1ø®E®ÍF v<ñ¼‹Ô›þ7Àj8^¤4Ò݃T Q@?CÓœ®a*BFsÖÊh•Dˆåþ=UU«åC[ú52hEV\u+àw*^{16ñ½ŸzÄ õÓëÐÚá‘WT†äˈÞ×ÁE+Z‰bZ¥¿¡¹œ®eœ©ùÌTéõàÍÜä+%çóÌcšàYJÕuOŸœzñ‹ZK;ò—!m™*jÁ{•2X'í25éë&b‘< ëÔÊþDÅ¿Jlª°54Õ¶oé ëoQâÄ÷Ä*š©`k©óT †Æ'µ«S÷&fÏéÑ%+4ÀÐÝN×b ¹ÞÝ–ëM´K!L/å|¯JœdaŸ1 Û¾…¥dö«•Xy€ëž“ÙÇ<åi“§<ôõeæ¹íUH=©â´D#>%ªVIõêQŸ©¨¹jjûÈõ¢>9ßGÜ—!GœÖ0«b¸F j8*¶HÔˆ:¡¥•ÒDž4„h’½îé18]ÃÐûÓ,ßyŸU£‰6Œ&qNKuÞj¼sψÙàH˜™Î;J½ñŠÙC®¢Ær¯,E…µ W .ŸyëI9>d8i¨ äÊ}¡JS†” ©€›ÆÍ U¼fjYÌ ¶’GµQ&™¥¾w0ï6³²jÄ…ÄÚ*z 3‹0H“E¬É" Ѩ.s±žÒ6‚ö•ÕÝ#51ûl‚׿ÈÎÕH|FLš8©ÅxË¢Û‚};³ñcµDORÕM°¬Õq¼–(SrÑ'j‰ÍÄÐÌ;•ÈØVì4$NÈdÓŽ3±ùl8Nן :kæÜ±XããáÅž6ðø[™ì#ÌZÁr²\VñŸ2húsÕóH[ÉÜFØMY©ñ$¸V#6#VÖÊ;ù5ØÉ¯eÈM5Oë´8È®GÐúˆ©l ã”×=ØáçôÀFP™ì}ÚMlѬ‘¸U“#q›Ö6whq9ÌvÊÔ$¯I\ ¥²[ƒÒò¡†ƒÊÿ#äû¨Uþ£²ü1MÄ´¶)3®Eãåý Õ6ö˜Y/f½HØ&³FŽ£F†Í¬Ø šyBvA—€hÁ\1a®¦äîš s0à uíßÌ=¼¾x`’ð+ O™ÕÁ™ðFðD\‚V+ÝV«º!fhTèg„Ã,ôV u´ƒX‘aTŽeª8QŤ"yG¼;…óÑ©‹'h,Np”µê(ÃAóÖ Z+÷0¹¯•’+CÜ×s_kÄ€ûZë0™ûzG5¹¯ ôçFø›ûÚȱ‰ûBç¡ ý&‹ûºŒ·ØÄ}ÁdܶTî‹xWð]†ØEÕNÙýÈNð]¬Ç”Ÿ73`­ïK*ß^fÚþïýMÿ÷rÒd$fË'æü¡› ÷š¨ã,ؘÌ• ¶8î€ †H˜y8Âiú÷R"Ìü5•+<Î'S¸Â3W¸ÕÒ.úº•¶úÜ£ Ú׸~ˆ6¸êk¯7´Ã¯lñT´ g9XO-͸´a=q4ïÐ.ŸçÔ¨‰»fª‰»…gcx†õÖzÖQ>ÔÀ„:–G~?ù³t³Ã͢ɴo7u195Ý´åüê‚¶*¬2bžÞ¹»X¬W±Ñ¶ê²&±D—åR=^±L¥É†¶­±Š±†&–S2ã ¥O³¨Ó¥€z=Z1ÜPÄJ“hÍ&¢Õ:¶'ã83¿D^öë&;¼Ÿ2ѯ› §oŽvPupÄC fØCz‚&%7Ö1 #¿/á—‹]É^ÄÔ”7‹¹ÓohN³‚Ïò†8ÐÄfQÏòú¡ž×Åy%nž±ÄOŠÐ¼…Iî‚U¬ Ùè¼ñ™+¦øÌEÀNàvû À^Ñ­v£ayM×ô¯m­ëz¬âµÖ5=¹µnl"Oj}¹Mî·e’êâ¾.Qéÿr´[õý0\zLN®~¶±¡D}¦‹g:/H㬽ÎsŠ:ñdœ¤JÏ'­ÙJò¸u_è4µ¾BW;¡¸pÏ_†œàEžD¹+¢™Šá¬â“ZÔþH§Õ7G;£ˆÍ)\¾a¦ìBÔ‘û` Æj‚³ª[ùHî„SxÒk É¼ý¾úe²SL¡±ŠQöS íÏpLç8K•é´Eßü¡ çêw´¹äôïæ˜OΜNz-ž–Tá€)57|ø9Ûi×Qw1×EFª»5‹ùN¬ÎÔ¿ºt Â:+þ]èü¿Áu-uV O… òÖ:‘¨ÎÖá–;£ äVÔ‘Zµ(7Ò¯Õ„a/µ~•‹r¥wçÎôU¦„õ‹r]¬+lµ“­bO£ý+}ŒÅÜᄉf*ê€nÚç¯ÕÀËÀ„“G¸ä‡Nð3ûlzâ×jü3«hÕÆÀnê§ØCDÖ¨ýL{°%Á+î>þɃ÷3ú¸¼ma(9 U¼i!²6£™ÕϘ#( ˆÜÿ>ÿÌ%šñuª¶(dÝB»Ëgš8tµ¬ÕzÍøÊIà}¾“?• ¸–1•llÔÎ8¥ ‚ö.%b§e‘ûõgnq ÑÝrr†MÔË’ ÅÌ€ÙÈ×5g[–üÐw@è ›<‘].ªRqÛ$”zË>óˆ; ñP‘aŸ²r¡ß´±á._è' 1F-Û`½+É<2=•ÞCg´ª$r«¨÷CÊiªGKŠgHÌ E?â…ÁÉ›–Ï Ø`4Ä+'üŒ÷ØÞ‡â¿Ó³Õ%^‚Î@¹xïç‚Ú˜èû ÷è¥K“\Ÿ>÷0û9ÐeoÔÅ`—äH‡ºìŠìÕpWô²¢£ËÙ]ýï•ú˜l4n)jšæ¸S¤häÜ-R^¥¥H¡YN)΀r¯Hq¥)÷‹w@yP¤x‚ÊÃ"ÅHS¦óÉ»<j[Ú&ºÄd—=EæÛSäTW,Òêâyiš‹æ¥É.L•çÌ©r† ÀFó½¯g6¸¬•ª3ë®-k(>]žÉ;ºßGÌ—¹¸4¸Äž$Øÿ¦].Ñh’f–MsÔe.ŽG]"þ ­w6Íl{­mBŽš]•ŸôøÓÜÊ«ª—DßGØW>âSŽ«üûÅvèÐû±8ë˜kØÇó ˜iÊ¿7¤›\IôJ´²û;=º«½'CÞ|¾¡gèÎñ"¼…z͇°Ðæ2å­uh7õ-ظÔèocÀñätú;¬›óíõ‰áz·EÞÍý-0Œž÷ÅÛÑÈd#y\Tý>m}Þ »~âKEgöæ÷z¥÷|\N÷¤s”w+ó{ä+”¢[¼v'z>)¿vÇ{>-]Âî°ÞóY‘øúáìù¼H|+ÎG½<{KÚAi›8²›ÑUte9J—ò.>§uÚoÁMµUi‘§Eå/Š\Caúþ.¢‡Ý”üH¼ß`ÐëtZNá [ÁŒô(,0 aûsTÎ÷øÖ½Lùíd?T¿‡ZÐþTü©]æfñ'¬™ôûÉ%ÖQbÝ£#Ÿ%ºÜú0þ3ÉXþ9Ý0å~9+ŠøP)A<ÚÀÕ»èaô \yÏ-M‘‘6<9ºó•’Ɇ¤ øû{â`ïB,¿Í¿P¤_ŠãýO Iÿ}©IaÙ´;×”µ¨3?Téïô5ú;ãCǾþñŠèEÚ5½|^M£½/ì툄¸OüøÒ¦Úì?ãjÍ9ŽåQÝ\?G_rÿ=Çó·è3Æ/ÅÏq{Gñ#/‹MñKdÏ;Xñ?¨%Òd«¢2lPÕ±|ìKlVn}˜ö÷8ŠM¯jQGwËèÙ¢Žé–Oýàt&¥‹ªª`8½|F;Å=ÃÈZºÌZ¦£Ì޹܇ÆvËú•øóÉԲůÃÙ‘'E,ß {¤tŸ3òšz.¤¹XœëØü[á? þ³2Dïª` —¡eÊ{Ðm4º[üS<²¢ˆŸáÏ󢊕EšøØïëÄacá7qËÂB¸!+œÎDïüik«÷¿¨wý3•ÑÌÜ¿$g޳õyr¶8CÿúÕ õáÄ dȰ2ôÛß™¡kËÐ/ÒÂir¸ü’Ÿtõy}^µz|¯øOˆÞsÇí€^øßæˆùoˆn ÇþÓã¢wE öcK §Ww.s"Ú>ˆ©àStÌ”^´î¤òW¯¥­ò6˜¥RÑ{µÁ¤°Îb†ªqóúšßû伯)ÐK yáj¬ü$-ÛÍ,ÒAeŒf(báy_0#º¹L£rÿ«Š1úˆf&t”R(žWS{üxbÞr¶¡¿ïº&ªœsOâ5Ï4ULRÑ,¦GLã»yoNæ‰aÌPÅ 5y*›¥Ò\föú×f¯Ÿ£r·Ÿ«r¿Ÿ§rÇŸ¯Š9Ðgjvý¹jJߟ§¾Ñùç«Üû§[½¡*ªÉý‘Ê ¼ºXáQ¹â,>›n‰3.‘^³2dßGO[ÊRïTÔejb׿~¹ôL–×¥Næ¶:Ylô²ùªÝïÿ–úýßÁº.J˜”©5IÉ­“ÈiH.ÍJnýïNnƒÜ4Õ^þ™zõ('ßhjø<}Õ*¶¡×Öbv´§˜ºmqeßbyÏеCïOàƒ¥w/ßré]N¿]îÌ{㺠è¬êDK/T`ºîrÿ¾,ð9¾›RÂ|H ³!ʫnæÄß©º«Eb¹Õ›Egðe­e­ÄYˆßKTìu(´|2äÙ+MÿõœX:`ÿ€û6دìçƒt }X9×è1—Y¦•†}²Šïþ'b}_®:¯7ßgaá?§ßÝ´¿+Ÿ‰›«&ñ—U“x¤¦ Zy"ç}Œ:~ ~ ©œü @üUXgÃ]j쟩vÇ"Ó3ÊrÔžýŠÅñ„‚k*=ú>U Òþù­A;i¥…Gqeÿbk‹ó˜ÿýâˆÑÍ6ú'•8ôúÿ’÷\öfåGI…[G ¸Óõɽ‰ÝÄ,6Bµ¡D™•KNSál,ÑàLêæ˜• [\±xâ17Ê»çb^5í¯µÞ¯51?÷ÓWøz¥õ~¥IK\ë¹™€_DðÑÈ<ÊØ×ߥä+jsPþ‚«~£MR‡Àú\lD7™Û>ò]ßչъÅúËfC'v~‚Š u¹RÊ)r¡PLݘ+6çVMrÑ(¶äV%©äî€ûd–'ªUI;®B·æÆ*oVÕ¸ËoªPÜJ?å®b–»fanÏ­šâþ¢IìÌýô¾ Å îvPšõX ¨-æån2¾7׬„­¼µ.CÀAn«„¿§ù27úà ÔËe£¼…È1D>Ö™Ïy)îF<îBÜívížBÜÓ2îˆ4Ôî>üàTÏäšòÔgrùD÷L®8›+KP12 §¥;ùà ‘ÏY‘ÏåŠó2VŨ4 ú;Ò…\S;ß…\qÑŒ4š#í²#]²"]Ê—ÍHc8Òn;’4ˆ64ƒhWÍHc9Ò;Ò5+Òµ\6•†Hã8Ò^šCœ®.ˆt#×T£w#—ÕèÝàÂj7rÅM³°‰Šñi8ÅÛgWÍ-‹è–$º•+n[U3«fÒp ŒÔeÂ\„ÀÅ’r3S³—"°VnáÀF;p9ëdàVlJê<Í1×"â:¿\ÓôàrçÃöëÄ&å*ñ6£Ç^ÏN0Ï+[ƒuÛPc'i€¸ÜØÆ5¶Ü­ló‹íhýmàhO1¥Lý4Ev{Šy/G®~KÙëû Š¿ñÏÐ`r{~8üæŠ|ÀÏK2Z“øÅa¿µ*ñÛËòQ"ÙiD®=Çe‰¨?e•Žùå2÷'¯Óg /-N;ørfoåžúé"Õ odG>þîä¿ ùUsr#5…ò´¯ÊÙŸOváÏÖ"6 LÖÉÏýé‘'ÍT]ñFNäK[Ÿd÷^D¹_ÜEí¯}ºØ蹘¾öwÑi-êÁ.Žä|ÙEß«}Zï¯úó.§‹¥µˆÎéJ[ø»=¿|Ež»w=Qéâ¼ }ºÂ_¦ô^AŸG»¸.iŸ®ô—©½WÒg´‹ûªöé*„®¢ÏXÏuíÓÕ]MŸñ.Æ-íÓ5]CŸ‰.iw´O×"t-}ë’Þ¢}ºÎ_¦õ^†]2îiŸ®÷—9z¯§Ï¦.™´O7øËôÞ`µ¯K¿ñ?Ç'¿Ï×ccµ**§ßÇ÷¢TäÊ%þ@ù¿J%ãåJ$5þ4“ù¢ò·´–®m¯LÆ¥_7uª&¦i1–™¡Å"g|ÔÔå͹Rq¦ë.fi±ªß*ß`(DÊsÖ\­ò·=~‹O1O‹›=ïäˆùÞ\0 kß)âŠU,Õª–úùÉ[­öéRå/züBé¹Ô/–Áš ›a¤ø+¹“Pîp:µ›¼F­ZæÇ«1±Fût™_äô\æk‹ .®þ[¾O øqƸA«üÛX¿UṑcÄ{.›9g—8g¤´9Û ÄÀ³rµ kÁe{‰Ç¥"‹?&0¯Ø5Ð%ÖŽ!àª0) ×xáZ¢!dºÃÜMwP§;ÄmÞºÜ3 ÎøªqÑ]$Ë~Õ{·!fó=†˜ëˆÆq–CmGW"5UƒýÕßë§}›#Ä ´Ôù> ȧҋ­Ï‹¼È“´r¯ú^s﨑ð8z5 îÞg ±ØíÜûœp]ÔÞ{ ±û KV­ð÷Nb9ýZåï}Ìuôk¿w£!ê«ÉÀ½gU½Ÿà«¼ƒz7büƒ¤~Âà‹Î]FÕÛ«yﵞ¿Þéù¬=ßiî2ØÔ&óç"±Ëöu».÷¡.÷s8Õå Þ`}È{&Ĺö)sµÒ¢Ä£—-Í5 kg¸»ü¼Gí¥T6ê9Ÿ'âf Þâ]Â^ì/8ÌùõµÐ´nê%‡¸ä "j¬ü†C£rhW°RgäþJk ç”QµÚï‡àÁ j&TÄMG´âŽ¡Àþä+^Šh1ÃîqÊrÂaS{÷)Bÿ4E< ÷E|ŒZ¸ÍLŠàl äK­®MR]yØ•éÝ”R/aPC1ÎúÚktÃÈÝgô±ì?î7b´÷®åiu¤.FèfcÔQIå Äætm£ôx 7bX×Å=^þ0]¡4Í£ÇÝãu1^O”ïÍV 1wg{ ÚÒÊl N”Ä APŸÍ‡uQk8h1˜l­]OøVHq=îiÓ Ø¶ß`y½½h;†‡ä™¥|­ùì-e)•yf7u™.–é›D,øJ¿,.‹¸Òþ«4+Ä_0gÞ‡ÃWêï4‰Uz´âµ»S³‡ðÙèë«â¸G*<úª¸‘©@20Ðû¬ÅxæHØ [#a£nukLˆ›ô¶¾¼Y—M¸• ÅU0¢8²¶·érÌm7 Þ W>È”+_{a„ìÒ£•W¼Ò³sçöÄ’÷¸â•÷^{ùv’ß?1/šÒœììí#ê9¹Ò—¨{ÌÉÕ™¢„M?»9H¥ªøÒ­ŠC¸9½k ÖÓw”"@´ð¦ügˆê昈êÐÏë}À ÔÍAzùÌf@U6qå¡çEC4ëæèä¾yÜ,ü $+ìd/!ÙËu7’½Ç÷ÿÁ ƒ•ì\ #4”¯XåK3Q E¬¨NS… ˜;)S÷8åÊÇž=JÏ×.qßÙ¶RÆ(7ñÀò¨ü;ÀX=1ÚãïôŠcUªã ÈzsÞÊyÞw™/‘iøT»iDÇ Ñ×muÈ¥Ö¸SwþnÙ@#a;ÁPw8Äm¦3 Íévº.ñŽo8ë6¼øe¸»E½ôÎåïhp®|Ç'ÖUINS'µçHw¼ê'ƒØøÊ(7¿}ÜVµÑäÜk!¿,Æü¤½|\Õ•?>÷M3#Ê`lK Ǣؙa’6$ Dg%$$DÃHÎÎN²Y °Ù]²‘å"WÜ{•{ï6î÷)–ä‚{·±uÝ ßùž÷ÞÌȈdÿûçƒßèÝ{Î÷œ[Þ½ç¶síñJkä\Þ×;Ä«´&KÏ:•Îr¨=ü‘ËêýU<áמÆUZC8L£;º‘¬©æ×#î¬êˆ´…Y"yU«:vµÉQv2ü0Vm×}|”´P÷2Æx-£W9¹ÐKŸˆ§ÆÛõ™Èñv9ÉN½Àjv®;‡’lS×Úcë)`cC"YqÝÉ›&£FÅÎñuœa ìú8|“ÏÎ.±€3HYd‡«Ì¿¡zƒ\j‡HˆÖÈß—}]Б$6/·ËåvV°cW+1tÜÐÕçPËæ°b4ŠÛkVØŦŽ|ˆÊ,WÚ“q-Gã Êsg¹†B¨ôW“©·j³Ym#9uœ”„:- uZì²áï$á`fÜ8_zØ–9¤ ‰æ34G –®½EÓÞ ç ÐÞê°ÆÊÇî××dê£bíw ß%TÙF*‘ºÈç†z^p:ê¤=ó;»b×¾³«v½sÀÞcFáá÷@©rh(3Pº±ÿH Ó£<] ÿ‘ýÆ€i]+¾*e€ƒú¶KÔ5òþjjz|4ÈÇ:´nj»‹T1ŒÚbFì$êHqzü¤Ó$‡œì0>àQXÇ\—%¦:Em‰2~&—˜§;äT‡ž làœæHhçZÆj×¶7½Ó §cRTf:2†z˜Ÿ˜Md2ÌaÀ¢Š>vïQ\Ì›™Â®Ø÷鈓)`a‚+å´­áÚ §ë[ñ-grCÄb¥ýTSi£S–\lènKx9j‰£¼Aã¡!eׄðþWô¦d®o•#þ+¾Zæ:’ ãg•&³ô²Óq«¿$nMKâä†ÌìÛHY€kg7;±Ò¾ª©b¶[ðwoú{–áï>ô÷í8ðÍDF…æ¶ô.jžXÞ‡¢®‡¸. æê@n¦[󠂉^¦“yÚQþßñ.ÿŽb×+^i8îó½­N™…D4˜kéþo;ô=L·XؽðKªÔÿO4}ü=Gk2ôÑZê†ÌIŒ0¢®èQì1¬Š¾Ô£Nnb»9ceÜÚ)¯îNÍdîÅ2¦·:ËÞN]Íxé\X/û8àLè>’´ó@_ÃîdNáÏ û8êî4ª6ŒÔP䨣³åü*Ý¡ºí,Ôr v3x‡ŸæÌüâ§;µ/~¦!¤,NFç¬L‘&Ó0†àU¯y€XÀðœ ùOí.áEìt”ËóaÐ.a?¢Ã;™–8å2-gxCÑrÐP±àùèV3Ý”Ój>(Ö:åZgœ¯|¬—ë(ÓpÜn#Ü0’Å['7ñ[‚ã¢÷úHW¥£vp+µ— IJ¡«…º°ŠNÞÆ¼}—ªÕ·Cx‰ÖÅ_WTuY©/ªêÐÀ ËEU¯cGöw´êj/êÙÕÑ®Û;^Ãí¬©â!]—ʹ˜Ãäý3 ¨¨@¹oÒŸûú Dß‹Ï7ILÑ;G©r”š¿VÃz´Z©Æ*Ö;åúƒÇóD¬È±ôV„àñj¢¹?A¥Ü/B¾ORµ2BûT«j¶ß ')jðN6Ma94ºË)§ãωîèN§œ?w«Ñ=NøöMFö¨ÑÝN9K=[{®Š ²ô¦r4ºóÔXÆ–r¨Gµ·)µ§|JfúQ§\ /¶£T5U¸X¹ëTãcE±^Õ?´ÒÝSg¹Qå6®}3Fƒ[ ¢2"’ÛÔG;Ë*Ú}>üµS}¬³ÜMŒ·‰qJLDzU‘1ká¥ÚÄY\ÕËû8=é»´1eTGéI_¥]Ô¥WŽ6ß× j³úûUlŠ­šÉ¼üˆM x.ªj¿9EìèlV‰éˆ*ê¥ð*ê~·\qQõvÂVêS*&¨{\KýLû:yZÀÕ‹=èguв=ðÒÂ/šï hT­ú&.qÙ&аÎå4N£êÅÙ0ɬúe„U>rÅ-´ocSŸö„Ãaž•@a)°kq‰ßuC¬Á'–·ô#éÊUÞIqR¬v}b ÝÍ çÜS“lè|¡&S‡Ò¹(›Tø9Jâa87ªriκ¹RÎnݧI«ÿ"MJ‰½ÆE 4fcú¸´Ã²Wœ8,ëK–¥LŸdÊNRÎÉ×ÏÉöwiÍæØp5FÅ4äb.ÎAì¾wv‰iˆKq…—å¿S'‡¹ %ˆ>ß•aâÓé ¯ 2.¼Ñ.½¦ÍᩦåúTÓ‡ùïÎ8W±§°Ìx ;"qŠÆÿ¡&E‰|Þ:Ìaìóe%%l…¶ú³ªEÖ¸bq,™­EÙeû§#Šn <)ouA…p²MÍ6YóýUSô®S~Ì1ð®âDÑv^ Ù žÝZ¡éE»//¯“Èø}yIaÞ;8†§qR)lÇl} œ _æ”ûï+„¸¯vð¾Ä#ìp³R@ÈÑfY}ìËY ¢œx(dŠ"”Òéû É‚AwVK–^ZPã’ËX¸dÖãU›ã‰mé‚é:ÞÜsÕ%¯Ò×Yž‘_Ýïº8WѳN^s¡§¡ÉÉ%zÕ…cÇôc×8 Ä›ˆ·]òvKˆw2¡ßífˆwIÛe¬í=`OäÉ0îˆz°GmBîán7Ú‹ÁnÙË]CÚŠßÛÛ­Í÷qg®¿ôuó”.Júk,¼ƒ,|àæb8Ðö±|äù@wjy°;ÿ>u)ïÕË!îÏêuDZ_FscM}§\›ƒåæ9êY^¡žeN‰i”Û;Xo†Å8·çN÷&ºQ>ÞÑ}Lp'r+`¸é»xGhSýFÈš6Ú>>Ì‘(SÜr ÑÂÿ njW¶IÍó wœ¯ØœåNp3=ÛÙn¦Ç¸õf:§‚z©ùpC^Ë“ˆã8 9—¯[M«)—÷K¬uË¥îX¹–Z§À4þ2wæR×r7OÍ`#Æ ÷}“ê«ÝåvyÐTõ`\ÃqZ¿Ö]þb—MU/ÒÀÄ0ì«õnê½Ám, ltký› ådÇ×·²–¹”¹%¦Ür›[kŸ·»E”Ö·¶&³Ëm Öºë‹"1·ÜãÖ×öºµ&æþòÔ?–JâîûÖF2¼2¼?ÕûHÿ%¼TZïÖfc¨8x!Эp"=S¸=Œ°eâÆEAŒÃÆàQ ’u–ÇÜÈëê÷ŒÁÏv'ãÕ›~Õ `ªnÍöÅi5øGÓ|‘ôÄ},î ˆ;qçu¿“[¢ îpcëð¥Ö‘¡¾ ÙZ^tk.AËiéÛnÜ FÝ{OWð•wfu÷èÙ»{d5ù=aDÎPmn«m3/x ŠÌkzqVÜùxWõñ®.\™náÁ•é?1§2Š~íÌcè'ÞÎ2ÖƒKw­3<¸m×¶Àƒjißã‘£HÍÀ8ñµÃ0œàÁò®ÊèÁ"ß»dktÐÊÝ1Å#§xôå>>LõT:që.oâOí2Ý™^ÈÔvÉjÞAö´sÎöÈÙ)9¼åb—ó]Œ«ˆo¬ýÝwi0ÇS©VZ&Åkq /ŽºÎ÷·ï.Ô0»g`îm§.öÈÅÍ1w¦0ÇÓ%—x*]•ÖI ´3ær`pgï ¶öÀ÷ë¦/æµTÚæëZ+íóÙø_Í¥† #×z’|åî:•rOÕ /f›=ÉòñCé—ânñP“ÙS•Û<Éȧ­iüñnüXû{¢ûÝz¹]û{·ŠÄíÐ^ö¨Ðj'îRSÕ¥«CîõT:rK`ÇÓÆq‹„ö7 ~lÛOj¯špÞ©¿O'ÆVý£¶ÍLO~F5<êá¡c}ÅÍJÇFÜY-n?âf§ã® îš×€¸9é¸ê,Šë‘U>4§ËÐL¨ÍUµÈØá‰¸áYá¢Ò‰ùˆš§¦¶LÈÒ»¤ YrR–Qð,99K›š’¥­µ” V„œš¥O–Õ í‚™Ñ3³p`€Ñù3]d /Ê’K²Œ±Ø–lc‰mؤÙÖlk³äúfl ¶qĶl Ól; ¶YrW3¶ÝÛxbÛ¶Ei¶zƒ­>KîoÆvÀ`›@lÁ¶8ÍvÖ`;›%Ï7c»`°M$¶‹`[’f»m°ÝÎ’w›±Ý3Ø&Ûg`[Êcm+}lÃvÈ–½³‚úW8âËÖ ª6ók‹´´ljF«¹|±3Þe±STÙ5Ϻö²DøA6¯ðB™ƒt€²MvÁ=ÔèAê ËÆ¹…tªÆÚË–²3S5Ñ`ëIl“À¶<Í6Ó`›™-g7c›c°ÕÛ\°}˜f[j°-Í–Ë›±}h°õ!¶`[Álßç]ƒÛúl¹1;£Ñ’›²cñ²¾Ä²¹Ú õÐV2Z%ï¸1ÐödËXŠ FDÜ`#D ÄeEwWµƒ|v»![ï®®¶Fwµ?›š*ê®fk“Ÿ@Ô*Åóµ' Q'³å™”âsœÍæ½g\@ç ±ý(!±š!žâjg@ÜΖw!®žìÓf‰ýÌ`ïO쟃}M:Ç«¼:{•WV{3Ùº{u¶=pvêÅUÓi©ý ¶~^9À«m:ü û@ƒ}Iöui©£ öQ^9¦ÛXƒíb¶õi¶)Û¯œÖŒmºÁ6Øf€mCFce°-òÊ%ÍØ–l“ÑXm#ÛÍùË\ç…%÷2ÙÍumµsë¼rƒ×(¦(ûPzJlöÊÍ^c¼ôr 1È-ÞDî÷ymòie«Wnõ&"}ÚEnó&Óÿ9#*î ù±7ùXY}Ûñ;]•;ð۷܉ßAm¸ ì5BŠÆ è&Nmé;à•‡¼ql©çuþO¼/É#)u± ~Ì«µ(ǽõÿ¤ñ2•°O{3cÿ؟؟zec ïV§¯zcZÕºÞ,ko¨hsnu ÷[n®u9ÔouËÁ)“t`_öCàÖtÙ ÍüóOš†æÈá9™Fäè¶‘€‘`Û–f›h°MÌ‘µÍØ&g²MÛÇéÔ.Í¿ $^{Ú´2G®Ê¡øäuÊ59< ¤ ‘´²u9p«BD›àVšÇ-¾}¸£!g!¶óÀ…·[ïËÑÒ÷åðùŸ}9²>'cZ­Zì`-þÅôsä%]îA2ÍÐ.\ÖÞËvÓ`¤|;¹+áÃ4Õ¹úŸê\Ù#—éb8ÄBzæñ.Âó# â¹rTn׳y¹ú1 y¹rÑ5´ n9ÒvŽæ«(™ä.sàlB.¾O¼ØËrÓi˽'½”´ÕÀÞš+?ÎÐa;èöòGÉìäꆎäò!üŒV”#¹òX.N!©ÇÁãá9ççMƒç¦Æs3WÞÎM@÷wˆ‘eÝ_œÆ"Â6RÄ:õ²(ïçû69ñïµ’ÂÂè/16¯¼/GÑÿ¯}›‚Åóyåý 2ýí?…ƒ‚‹Ü å—÷ç¸ËÙËŒ¯=è×»9¿|@³S†“œø÷Ú3… ÙÀ#qê,¡¦}*$U\Ýóâ•y%ò·H㽇M¿mŸ=,è¹®½BÏõíÍ¿•¿ÃößÓàg™U¾KD—[åbÉèUþÎŽTåqÌF5•Ü#åè‡Jƒ…ÑÿDæ<êT“°Xpðë°jÜ0¿Dæ—ÏU‹^{6ZÎDGÔ¿‚—øLé~¿©KhvÔ› ,{*~¾í\jõsñO¢tÏ]•ß(øÅ?‡Vƒ²¾(|ALö=öej-¢t±Ï]M<ýÊOBkÀÓPôXKàó| ò›Z ÂýEÅ¢J¬–•.ñÙ¢k‰ú¿åÕÐ:P êÇþõ:¢>ì·þ"´Ô‹ŠÝ-a‹GbV&_OäGü¶×C@~¨èì-?2êvSSö#çìþ…%þE%áÏÍ‘‹yx~šWºÔ§F7ÈQ¿=ÚÈçeZÎÖû@J—ùÑÄxÌï‡6ñðÿžq1÷;+C›Yí‡ý‹KZâ\xœ1kçfâ<áWÚÎ#EáA4oƒ ðR áy&¯t!¡l!”“~×›¡€r´(<´ r¼UK(ç°<‡𑡈ÿ”ßýNh+ø…G|?Gà9²ÏQÿVâ?í÷üWhøaB£åTpDøR›HcïÏ™(B;¼©•ÿ£ûkž[ý\¡u>}¬;‰ã‚?·V„vãtQøª÷+ÊŠ#ð<ÅÏÓü<ÉÏ8*æŒî"°‹þ¼Ù"´`gŠü[[ª¸,x7Ñ~êÏŸ+B{@k¾›Cõ¯%Áç¡IŒ-º‡X/ù}‹Eh/XÏ…'P¯Ø+Gà9¥€Y÷ëeÿ+D(ÖsEá©_ÅÊxNÓXcÄÚèoµN„â`=_Þ¬FµXy(b°O‹fÖ8±Jÿƒ[D(Ö Eáé‘-–÷t–ÊÑÌš Ö+þÖ;D( Ö‹EᙑY-²ÎÄ÷«E3k’X¯úÛÄDhX?- Ï.ˆÌi‘•#𜫱î#Ökþ¶õ"TÖKEá­¿âC¡ˆ“­ñœW€ç|~.(иVÔØuÁQªçžãáûÚÁ‹Zk¶a#Z³ ÏqÃ]Ãm ‹Px.µÈSl2èˆþNÛ‡NŠÐ~Ð7þ=úýDÃÿði:zù÷èýMÑY:ú+þ Ñßò·;/B‡@ß³ |,'r>¯DœÍÃó?›Záy:OcÀóe5zˆ oû¿vM„>äÕ¢ÿÿŸ ×üí?¡Ã€¼Vž•© %HŽÀ³î®!‡‰õ®¿¸»:Öë-µÑ:kmv$ùžûЈ¸)=B÷üôUBGpão,,ˆ,*Às1?—¤`Ñ£ó™ÿÑ!Jè`å„×Y#·ZÌŽÀóv'á±~îl”:Ö›Eþ%-ðé½ë â8N_ø£„N€ãVQQ ô¥Rëv‚(›üÆ)¡“ ¼]>óU©£ˆá>?ðs!?ñs1?—dè¼”ŸËZ¥Ó²œŸÂbêm¤Ìèxj€9$‘=Ú…?°D.çµ”q)O‹æ|”Ä: ðôPsè w1íŠo¡äRà n®Ïg†›CWÁÓ«]øœJYùX ÍEP_AÏ ü<ËÏsü¬õil܇\%È’‰æÐ5@Ö´+j†&Óß5¢ÖšC×AÙ»]óÖS§\E”׉rpàÙ)æÐ PöùjÊD9$ðÓÌ¡› ìûÕ”7‰rhà;3Ì¡[ ì×2åj¢¼…Ž6ï¹YæÐí|E‡Wåc„¼:ŸÆ¼á5ù4  ¯Í§jx]> @Ãëói\ÞOÃðÆ|å…7QÈÃáÍù~mÉÇðé£| ‚¶æc(³-ãŽó1xØžÛG>êáù0¾wå“ÕÞ{xO>LÛ½ù°Rcù08ãù°ù0“ù°èöåÃ8«#Ý×ç“nÈ'ë'¼?Ÿlšð|²TÂóaʇÉðI>zùÃùÜaç£×=šNóX>õáãùÔ§…O䣿:™OJøT>º‰ÓùhèÏ䣩>›Æö\>šËóùhû.䣻˜vèÓ|4#—òÑ"\ÎÇÇݘZ-I‡vá+ù¨rWó©–„¯åS _Ï§Ò ßȧ’ ß̧R ßÊõ¹ŠÛTÃßm47Šï5™CŸå³ÃÈèg1*ðOK1½y”çe²¯,‘qýSsø6{zP á·~Ǿ›¯]Ð}׺›{ÞTq7_ÞC0Ü4¨‡ÙrK€~ û}^ •˜¶ØÅ'%?‡K”]ôs¤Ä¼›~Ž–Xâ6¹Õ/âù¬m¶ð½üªÜ:ù±-¡…l×Bêå[<Á.$vÂé.[<œUS•Õ wÛüWW‹ÜcÃ%ƒ^­}/·  ¿ÄØJ ž|ëuéÇ>sgÇuM6¨îj÷>]söJ[{¨,“¶J+6ÝT#K Æ¥MªÂ»,÷ÙÀ“v[ÎÇMM»Ã&lØyB5S~}é_ï…7oø Ê/l§Þì }ÁùõE¾Üâ ¿@Lqe}ŠÜ *ø’PÅlÙmûž»>VbÚá•»¼ñȲRu5Ü"°[íÝÞ¸ñ^±¬@î!Šå X—¢ØËü^±¼@ƈâCPœJQÄ™‚ß+>, ¢XŠÓ)Š$Sð{ÅŠ¹(V‚âLŠ¢Ž)ø½be¬'ŠU 8›¢h` ~¯XU ÷ÅjPœKQ` ~¯X] ÅPœOQb ~¯XS ?!е ¸¢8Ìü^±¶@!Šu ø4Eq”)ø½b]uNÊ ´ÈA̵¶ÄâeÓU!‡àäúþa^é0œ\a‰E&ª¹ORZGÁ/Ã5üYþl«ÓÝÐb¶<ü"JwúDU«èUކw‚‰ª ij*<¦<Ä @œhI¡Øq椕¶©~‚ZÕŠT=§Â×ÌS ®5È×Rö(µÜâJ„ñ´Ê­ødõ.'óvðP¯Í+­r¥5žÔ:ÒN®²VZPBÍñb*-” „”y;ø:dÃUÕæ°Xg(Hâ^=‰Úi¡žèƒ){µtÆ­¬OÂ*ã©&)…ã èŒsMŒ¥þ ü’&õPÝViAWY¡w•ÔÜXå~uK Hž<`Mòy¨ƒ¤lùÏ18Šîó U)›¦*|Qè'ÖX¥U«rÍh6ø.Úz+z×ázïz„²÷„µY‡Ý1Ýa7ÈS†<=óŒL4D3àvépga×22ìf‹vS˰ÛZ†Ý±ÊÛ© »—‘aŸkö…U~žÎ°/¾*êl™ÖͦeXµ­¥ û<#ÃzØþv†}Ñ,ÃzÙ^’}m_aým_‘aºHbḬ̂p˜ýºŠû…‡r†#ë®]u <‹æ$»gWý³sƳqÆM°¡Z+ÙÌ3Ï·É 6#ÿjm‰Üˆ––)6äŸuªMN±éùg•S¡¼£ÒZÝ•÷ñ¬ƒòÏ&gðáh| r¦-‰Ïû‹gQöØ’ÜãMµ=étäì$Õ‡œC91ŸÁôœpò¬Àƒ­ÇM—m¡M.´Á!±JI‹lñJ»&aqZÂ’`×$Ìg +u Ë97ÈôµX÷pæœÖLßúæµé4gƒ¸Ày£\´É³0zÙ¹ ©x1eÏ~JUb¶^µ.sÖXmò²-iT­F[ºjý1³j]ɨZõò*e1vó_·%¾TiÈåó\©’mдã2Ûý¤¼ïà¶NƉoäšQ£×Œ»¤ûÍ+ÚSéŠV/«ì,=¡W³DÚ’æ¹Ýì1i* 7èÐÝqÿfF¾²·”¯ƒìœ¯Ã휯#ìrˆ]Ïסö—仑¯#íé|mç|c—£í©|cÿŠ|oÏÌ× v-_'Ù[ÌW>ëVkož¯Sì÷“æ!_§Ú3òuŒ=3_§“î3í_¯³¿2_5·xÍòu¦=3_ç!_o©pl]…ƒó«YÃÈ&ô–·U³¢Mkìúä5v¹Ö#]VåÇÑ@àÆË4Ä.@ìÖ –ânb±Ç.÷2ÄêĽ4Ä@Õ 6â³4Ä1â˜]gˆ5)ˆÏÓ€Ä@|‘†¸b@\±ÃA¬MA4¥!ªp†»›ƒ!–¢Ê•‚¨vèÕÙÝãÑ•ÑÍ•‚ ˆ!ÄG€¨NC 5 †:ä0†XŸ‚螆˜ˆéÄV@ôHCÌ0 f8à € 6¤ z¦!Vb¥± ½Ò« ˆU·'ˆ)ˆš4ÄN@ìÒ >Dï4Änb·CîaˆM)ˆ>iˆ#€8ªAlDß4Ä1â˜CgˆÍ)ˆ~iˆ+€¸ªAìDÿ4Ä5âšC^gˆ-)ˆiˆ8ÞÓÉ;ñA¢—S‡èå”5N@|”‚˜† ˆQÄ.@ JCŒ6 F;q¶ ¶¦ §!fbޱCÒs ˆ¹Nb'ˆm)ˆ¡iˆµ€X§Aìİ4Äzb½Sn`ˆSÃÓ1@Ä5ˆ½€‘†H §L2ÄöÄÈ4Ä)@œÖ b€•†8c@œqʳ ±#1: q74ˆ8 Ƥ!n7òCìLAŒMCÔàü,N:DãÒ}T¢*ûª€Ø•‚ŸQ¨€¥A$1!£P ˆÑªÃ»S3 s4ˆ}€˜”Q¨Ä\§„ bO ¢6£PƒÀQˆÉ…j@¬W冨›‚˜’Q¨€ˆkõ€˜šQ¨DB•I†ˆ¥ ¦¥!Nâ”шéiˆÓÄiUžaˆx bFâ& niû13 qÛ€¸Í'g "‘‚˜•†èƒÃˆ8³J1; ÑÏ¥Côsáð*A$SsÒã1^ƒ8ˆ¹iˆ ÄŽžľļ4Ä@,Ô b~b‘±È…ÓŸQ—‚X†ØˆMÄ'€X˜†Øl@lváÄ&AÔ§ ¥!€Hj‡±8 ±Ï€Øç’u Ñ‚X’Q¨€8¥AÄÒŒB5 N»ä†ØŸ‚X–†¸ˆ›ÄQ@,OCÜ2 náL" ¤ >ÌøRq,ª·›!ŽbEÆ—ê6¾T7ŽÄÁÄÊ4ÄX@ŒÓ ŽbUb¼1Þ-'0Ä¡ÄêŒBÄB â Ödª±È-3Ä')ˆµiˆÍ€Ø¢Aœĺ4ÄGÄGn¹•!§ Ö§!±_ƒ8ˆ iˆÄ·<ÈGRÓñ©q›Ò— ˆKny™!ަ 6§!šQåaˆ3€Ø’†èf:ëæÁ¡4‚8–‚ø( 1§~†jg±5 1Ì€æ‘Ãâx b[b* ¦içñqbº1Ý#g0ĉÄö ++5ˆó€Ø‘aå«<8§E'S;Ó;±Sƒø»Ò» ˆ]¹›!N¥ vgX9ÆÉ)‚Xˆ=VŽqÌ#3ÄéÄÞ4ÄUãA¬D, qÝ€¸î‘7âL "ž†è…óT5Y ± ‰4Dï,¢w–ì“ã y"™†ˆ±Äj@ìKCŒ3 ÆeÉñ q.Q—†˜ˆùÄ@Ô§! ²äB†8Ÿ‚hHClÄF b- ö§!6›²äf†¸‚8†HbŸqÓuD]NYÄÅÄ¡4NRÉsÄ:@|’†8o@œÏ¹*^W0 §!îâ3 â" ޤ!>7 >Ï’_0Ä¥ÄÑ4ÄÀl‚”Íëq, 18[‡œ-‡dÇxí€8ž†¨Äd âS@œHCL1 ¦dË© ј‚8™†Xˆ¥Ä%@œJC,3 –ñ±'‚)ˆÓiˆ-€øHƒ¸ ˆ3iˆ­ÄÖl¹!®¤ Îf´€Ø¯AlĹŒ¶Ó€8K¼Jc@œÏ(T@œÓ 6âBF¡ç³å†¸–‚¸˜†¸ˆ»D# >MCÜ3 îeãäA\OA\JCà’ìïe ˆËiˆ^b€‡’âF ¢1 14ˆ+€iˆ‰ÄD¯œÄ7SW2:D@,Ô ®âjF‡h@,òÊÅ q+qÍelµ'—ʯé[íÿ±0š…œÑºîò”sìybÀTêé+¯öù7¶Çö쑸~ÿ–ŒÒjŸ%ÚÓ×(&ij¡^L¾©½ÿtÉWÑö"ÚÚ€òP/ü‚sû¢–±U¢†'Ìß õö•÷ðù‡ ÿ™A{mo¢°üS¨@·|5h"œ°¾ê ÂÚ‡Wfñ¦¥/QkxžÑ¶šô%ÎiÛ÷Cý8?z"™á^>JA¸Ú…{ûHp¸¨}}¯Ú*úù°‡Âžá"s|TÝ|7¼ô2׋ Àߘ~tYmëWÎê÷aÕ¹qÖ˜b܇UŸ¥Ðs\±¹-íeûòØsf—,¼Ú]Œ‰åÈL_ù¹l­€~.ºœËåÍŦ.Í¢ìžj–ðݸ7Ór:èr:°œ,§ËéÀr¾.¿~ŸÿWË)9–s‹å”CÎ7t9ß`9ß`9ß`9ß`9ߔ߼Oη¾BÎìì.³³M,åÛ,å¶Ëb±X)õ‚]lÈý"Üß—S¦­³š>òõ§BÖvìô‰Šþ>ù‰€Ž~¾ÔU©çapÆ)4¹QPq£€¨2¯J=Šh¸ vYìk¡;•ŒÕàJ£8W"v+¼¼G‘»•x¸¼¦ª¼^îQx9ø× r¯ÒÒrp\‘q¥ååà„¢/ßЖƒãJærð>ËÁw]8Êô4z]_ ~]þ*YÈ_c’Î…LßEtH__ ñ:]ˆ—ýÂ2¬/úUÄË—;’¥ËÂXó«Œ%?ÂêDWø)fœï'¢ãD‡žçK”¨Œê™‡Šß&yáïwX3œ§*|eû›±xâGHÄ0ïç‚ß…V@ûjÈþJ¢ék"E s.3_EñUBoͪ.Q$²801óÇ ­A4DÀ €é•SåNÁ 3`† 9œ`z¥`º¹S033‹azgÀT§af0³…œC0½S0ÝÓ0‹³„aj2`z¤a–0K…\F05)˜ži˜5€YË0}2`z¥aÖ0ë„\O0}R05i˜=€ÙË0}3`z§abLLÈ8ÁôMÁôq[lp¥HD'ùkàYû“‚kûY!O‹XüGØopVõýœHä>«Õm傸&I|oî­¢ wQPõHêŸÛ‘éÞêzõuÛìì—„K¡/ñõÔ—}¥¦Á5!¯Bƒ¤Áµ”×Iƒ_ê+·7…¼)xåؼßj¶n;ºØ|[ÈÛ"É‹GyG`e?¸?y r–½>½MÆN (Ø/CÁ¦ûlÒ¬Vd7…œI V§š„îJZÁžŠì©ü-kY£ öVîWðs]ÁžJ¦‚ýPzýÝf‡Õ6‡ü@I+Ø®Z_}ù@kµ+¸>(þ£Y¤äà”’CHÉßéJSä0…×3 ¤]óA¨/G²’#¬ZF*rDJבЦ"I“£^+ᵸÑJŒ S±S°¶±X_ÛÇS¿nøp®e¥'*÷åêDMáÉŠ¬…³IáÉ)…§Â¿Ñž¦Èi™¹úÜý¹:C‘3RšÎTšç©±Â6 šb†TÆù»BÏßyPõƒ UÞ¯êBMÕ%Š\ UçªKRª.ÍPu¹"—ÿMUW(rEJÕ•_V•­Ve¨º¼™ªky6Ü›³"»t}¨ü&Û}Yôÿkß),Œþ¡8A9È-ƒl„̘}àóÏ D? #fV@‡úü³Ñ>Ì»a‹êwW^(‘SØ1·%!p4ó–n\>W]ª"†ºÓ£ s+f›=påb‰|"·Óô<Ùp>ñ¼|1ŒÈ®Rå÷¹++ÅáQ•ï…î¦L·ÏRÀÖ·P°ëÂ'µ{ppAôrµ(Ï ¿…Ÿ–˜~Ö(.•ˆüQøŽßyØVøãXy[¸¿¥K›ˆ®PåOb‘j٠ń˛—«¥²pwÅ«ñœär¾©¼Ö(µ6¿._ Ÿ„SºÁ#Hž|=©Ý†CRI…Ñß^,xÓ㯨$ÊÖRy‡Â‹³5àÆK/=`y§^¾AA¸*¾ÉÂÚßD‘ µeó„"+büwôCUvEV©ï¥,8~ø—XùµÜ­Á2ò‡ê¤.n3(‹Šº¬Q-ÑÕ*uÑ‘ÕZ’~‡#ÜÔwÛ«²ìÈéA­Mh—KÄÅ»ÊÛâjùOòP3r^àþ-iõò-\GµR•o—g%"#Ìì°´A¾“ ¯·FîäËŸ*oôRŽÆ“]½æªF/eÉ»¸i™x/Y©ÒßpÏûX‹p[›}"ëò_|è]¾¯•YwJÞÿ@q¸t’å$l#„*^ŸÕ<Á•% ß©¼RÍý6Ši§ÙÔ]ÈîÞfè;uì^MöàxävAÙÄ7ÖÅ‹Mžlj’½Jž½ÊÕðŸ,®Ùz,Œ¸­T;/°¢kJ5Mš¶K õR‰i®DNá Ñp¶ÎÐfÚ‰álwÚÕkÚà´»KÚ ‰õ ]»Q¢Yõ1ª&×¢:9ZèÕ‡ÞLjT=ЧêÑXÁy ­ÆñŸ¬ÕaTÎHã·¨‹iíÖ®¼˜²… K@ÌÇjÅ•Ìxd—ŠLå˜AˆÙªVìR¹Ýܫ귗Å#I/^K› LsFð¥!C@ª…T$½Ô:â“[æÆåá!¤g4§çF‰i,Û7KÄ8ú¹U¢ŒÔöe¤ ßá8ÏU­ëåxþ+^ºÆ#Þi æ0‘L‹I±Èµl‡Ç,'é­ÿòT{F‚Ú•W6oÏ^À‡ù‘ŠHÔÑÝ&a6#¿×€OÉ#¾Û%2§ü˜ZôڋјÊTk3jò:·bÁ­·wJ¨Jj5ù9Ük'èy·½òœü×Þç5;¨A•/P=®‡9”,ÛO¶E)–¦Ü¸9·¹õioê,»Ä‹Ø¿ç(Uî:ùÏñÈ-Jòm‘?€?¢ª±O¥jL&P,²Oe¨Žl 8.Ò«ØT…®GÛ¨×Ì;÷Wèz­BoJ³ýžØþXbÛœfû£ÎöG²&XüÛpÊ“fûobûK,Ò¶8M!ø¯:Û_ÑÑ—¿ïò–@FTóõÏ\ ¶Ðõàjpû›¦TþwKDú¹W¢ôèÊßJÛl¥gUoÕ˾ˆÃÀ)ýÌaÒ·m¿öõÐ4yÕ[ TÍc‘:µ”¬™\8DµmPGh¾g4»ržæ†2üV" —éïé¶ÁÖcF‡úù8ìC“æpYdxºð™ºÍmsÚìSÌHÍxIf‘9ûvg>‰Ë|¸,àIxˆôÁçûÒ§Lã)C Uõ‰"œ• Jbf_í±#ÔG”Z!kEyVvÛ¨êíTPXk¹°rëŠªÜ ¨{¦õÅ#¶¹‘+MQì³MÔØ¦«á!UàÔ¾–c˜bõ*êTçÊ8ýUz@±ÀìG†¥7o[Ó–ž®Ûz‹[¤r5ÜCéw—HÄ‘‡»E,/ûDUäJä[Kªµ«=èk*}KPVWkÎtSïTfp¢Š›»¨ýˆŒÌÅ×sû^îSì{ìÛJBÈ„®Kéa¢ôˤH†ß"!5¥£rEň\¹O'H–MB6ðgÃûI+¼°b‘©Û¹5ð!OÃð<*be‡q³·ù;xÌð*bOñÇ^4òÌ}­¤´±Á9¡·çõrÀÆÊ Ú‡LV>b>Õ›ún+Éþ&ÐoCö]]ö½ SYƒÎøS7˜w¹Í4HèÍ_n«Ö-Ès?ÕAÑs?ZûàÆÁ³j¥¨³ì®Ä"=-ñHKÂz ¬·RTµP©—}”xx¡²„§úòß5ÞOIäZ„IP‘ƒZ%Ñ.rå¾Ïôà ¤x*´¹Eú aýM£šÁJ8E¢]sØŒfh†2M:­LsG°ÂÃ@0<DÍé˜CL9B¡–”ƒô­Q|玔`‘ê$ô £•ò^–pK‚r¥¬—EÁ%Ær„Œ¿/FNPbe-åKÛ¶&+å#³cñŸ+]Ff‹Îr*q™L»S7I‡ò÷uÜßGǽ?^tÉ{آ[0‡†úü‹Ñ¡dQ/ ˆ@h˜Ï¿4F¯ÝüÊS¡3yþjô œaíÍ4°»e <¥ l h[Þ³P3°K £GTA`œø„â šZ@ÂáUËÓ0^é”@¥™%¦d+í¢öã³ìcó<RMm+Šž@xk“…ð6Þ69δÞóWèx‰ù™VÇUöî]D–Å U¶{´³lÿq5¤’A|9å½ôd¼T=ª"Zïç|ëÇ5~YÀôDh¸Ï¿<N9õa@”„Føü+Ñôº2 ¼éó¯ DGÒëꀹ,4Êç_ˆŽ¢×µË/C£}þuèhz]°þKhŒÏ¿!ãC‘ØÞÎ(’ûÿ„Æúü›ѱôº9àè'Bã|þ-è8ŒPp.¸µ2é$Ë“¦RC!íËkôÔt.ŒžQ„ÔâÔ|—ïzÀôhh¼ÏÿQ :ždl ˆN¡ >ÿ¶@t½~P‚¡‰>ÿö@t"½î˜¿šäóï D'AO2+EMG‡Sò)  ¼·.ÿåÂèYA츌å³uÕÍo*JÕ³FÑÝO㺳yþFOô,½öð+O†Îåùg=zŽ^{úÍφÎçù{ù£ç鵯oy1t!ÏßÛ½@¯»Ö†j}þÝh-´;š©]ï bŽ¥´£€Vå}tíºFÏ©‚vÇ™O«¡'Ø„u]éCÔTÑDë|Òm1Ãa®|<ÌnÃÎè dA¼Ø[Ú·Pô¬—… Ü%es?`2ùûåC4¬°!¨¶ôP%1©g½¿P>Œ?dl¢Sn+ 7/ ÀÇ:=^Ï‹;¿e*n‚¢ƒ|4,aw“Å;ËŽñ°wInWviTüÒ_î—zEÏùIÁ’€üƒ²ýIÌÄ |Q}#YÚ¯ÐD” S âìDùÁ6ÉÒƒmÄ»| Æé6ï¾[ï}œ~3n·Dï©Ãê> ñ­òvñÒv‚(pYÖSád›Îò™ò‹­ìÜa%öl¢Ø4OãMüƒcÇü#Ç<‡dŸÖ2X+$Júó8Æ™)S€¯¼?RˆþíÔ˜WŒ‚:ËÕˆï{0{;Ùç߈NFÙŸË,ûÁAù5l­H•=

@/û.Œ^PÈ ­ÓEÆxàÊ ¯¦‘Q[žh]–h ‹÷“g~}D3—ÜÆ~ ñü‹IñÃÂèE!qÙc׃y¿A,`*Mñ…§ú*¦Ð÷• ˆÇCÓ}å}rºôÉ1E§Sо€Ò14ÃXæÓV‡£3(ª.`ö‡fúÊçfw™›mŠÎ¤ ú€å‰Ð,_ùyµËyÕEA k§Ðl_ùs— fSt6íؾšã+¿æírÍkŠÎ¡ û·CsSAs)ètÀÑ]„Vú¨¬¢+ÑyœÃDhÏ.]CïçêZëó_D×Òûk”­óùx¢ëèýbÀ=F„ÖSk‘]Oïמ‰æÐ6Ÿv &q¥Ë…Âl2]aò¯ƒ¼NÞŽÉÛÉöá9þáA¬õ&Jš~®”Ö>¨`߈›F¤–—Áó´¾Vÿ4¯Õ?ÍkõOóZýÓ¼V_"Kb¼Tÿ¼¶R$ë}¦/<Ûžáãuùgy]þ#–ñ9ñ9F|ŽŸcÄçñ{åf þ“†8pŠ|žá®§|Q‡{‘á^d¸îE†+•¥Íà^Òàf¥ì̈7ÜV»Ùò* #þ€Àˆ?`Dznÿ–åÀµþPþ0×&Ti ó…J+*Ÿ^ViÃ& Ë™-oýýF…Ñ_atzî|ÀBÏ©ÅÖW Éö $Ù&–!É!_­tè’ì¼ bLÎÏu“§hB-ò畸Fï'é5}]ú: }…¾ÎB_ç$½ÎIú¶d$é×÷%ÉÈ3‹,çTÝv[ÔCA@XfafaNU˜S†[¥¬Ìc—]i,Fb®©œŒkªbäÝo*q!è·Ýe¶tÑÅDXL„ÅDXL„ÅDX =§Ûè9¹ØAúvFe4C°*[©êésrFŽÍÆ…i]Æf+_RÆ*W ãé®Û¦š-‚.o꺼ɺ¼Éº¼Éº¼Éº¼Éº¼Éº¼Éº¼ -ÿ&ÿ-C §üc¥Zü áùï•|étº½­ ›…¿ÍÂßfáo³ð·YøÛ\‹ÞæZô'ù§fµèÝûjÑ—…¾Çµè3·Õj¶<¡Ö…þ™…þ™…þ™…þYþWùt—¶egº c Ï¹n„Àö¾Îö>³½Ïlï3ÛûÈËûÈëû\7þGþO³ºñW­n¬ÎbåVg¥êF•àÊñ7?ƒ˜žB—ÓS° ü$ü(üPkÐ[ÈÞ"¯ô¥[„>Bk椚„¾‚Û„¦4x¼¿Þ_ï¯÷×À ,5¤ƒÏMÖÀ«< µË%¿Ìà#ƒ¦Ë„3*(. ÙHód›¹sœlNhw–À,HTãÞØx5n´ö˜I½_aµ¾ÐLeßÖ´Zi£ƒ?GK”µŠ\‹•dK{-L]%öBƒ\§$°‚œ„k‹A…D†íGôíë±B\íû—üímÒdç4IÐ&ž`~>)Q6±<óvEn!\öëò‘BÇm¼Á‰oŒMÍáåÇÊcåvÞ;ÇÎ`†«>¾kÙ©ÈŠ~|×*wÑŸðÙ2¨0ÉϔۖÝö ¬Ñ÷ ìU`~v÷Xè;½ÊŠ'tÅíTrASBî?cƒ ÿ›ñ3.hIðN-ë>N‰­N‘ûœLµÉ:èêHà¨qŸŒ£ÆvÙ $+í8©9¨°(n¸÷+^\–pP©´æb’ï…â凞–<ÄV¼/›L^Ì(EÄ]Š(ÒF71ó1gºå ¥ÒV”õΓJüykpJÁµ(-CЬNÁ±å?èÇ–Ï(Ü,÷ðX¨^üI¿ÀIoEõâZ[ÓN¸Ä»2”ËŠ¼¤è>êååtyÀØŽC|²‘Š2žÔ¥]æ rL¯ RiÚÓW(°ëš0” I»NbÆÅumóÛ-j¾­È[†Ðy;½Ãí1c‡ŸÛ½‹M"ì*#ú{Ɔ7M‹Û¼‘a¯¾‘ásÞïÖ+­E7s¦Ý̬~H‹fÖ¢§Yö0§´èiþ -j̺9Т·¹™=Í™Zô5C‹®tý¨1À¬mÔŽÒ£‹ªj]¨ƒ‚¦¤ÇÄ ÀÏζÊM«f9ª8â¨f‹Ó'äquÐ2˜¨jƒÖ!Ô€˜55øTý(©½ØäP3šÉ¼÷´M$¶‘f9œB–Œè˜c‡%›ö·‡¯¼‰ .¬´ÑSGØLÔf{F˜é›‰Ô:ËQæJ;ù0)¸ÉGpŠ+‚óÓ•¶ÒM>³Æ6lͨ/êõqœŸboÅb¶T SjÍhè(jµ ¨Õ2 Ö,§˜uwQSÍám¾ªVuršYw5] ©—3Íå[ɶM–nõ™ßëˆ ±ˆk¸€ÜC£ËÛ4—%mü–i®™/çZH?“ƒÊ"³œoÆ Ù!˜iøÖY.4ëÃÂz¹ÈŒÑç; r‰™ˆ¸UŒï·N-ÝßZø§ç`¦²|Ha¢tHazH¢y­ÇÑš±OÍÇOÅx_eÖý½¯2Ë5æð_¼b(5¶æò¾.;|¸'§Ÿ~ÓâF?3CëgfhýÌ ­Ÿ™!°ÿ² Kðñè%Ëî‰èeKîÉh£*ç ,aJUαǢWT9ã­þ ¼À_„1Úb‹\‚53 ± Ë)â2">HG¬DÄ*ŠhDÄ@æš|ˆÀ476F¤Zl¢ª‚#´i¶ˆÝı¸.Ûƒm¹Ã¹9ÞÂÓã¡Ø&¦-‚oÝ&äV + ‡~*âT>¯D¯«r¶åzËøv¸éAe»ÛESö£Âè á ?©=t8µ‰²‰ô·SµñL6Q‰:UW¬SxDa¼ld!š¡Úfa£8l2¤8‰uÒ¦ÉpñGûNáG:…Ü)Ü…þ­¬ÿ‹öä½@Ü<ÿ ²âVÀôýÐ._±)º ÇM¢sh·¯ø{ÑÝôv' üsh/à‰î¡·»˜}ßë+îÝKo÷–WB1_qÇhŒÞ> X_ Å}o4NoŸl¯…¾@N4Áû‰<ŠÃb½'®,Ê\ÂÌé+g~[SLÁ¼ÐŒj%I?K‚fØÖKƒ²­ôylò˜ªž¬÷ ™Tz6ÐÏ>ÛYë”°÷‘y¢tbAÖ¿·?7ÿ×­Öý ™× }¥Í[ÎáË‚¶#Š<¤`ñÌGì+]( ›Ù~Q:¦P ò8LIÌìž ÓV:À-H`—&}¢³ÓIÝSQgo”Y<¥\¢^‚¦‰6Ô›ø~êóÐY 𳇹öbýD±âPÚÒÀP™ÓÔ´º©‰þ2™f§Åß0ÄßÐÅ÷RîßOÑÅßI‰¿—–¦‰ï£¤ôù_ˆŸC–͵ž¿™¡ôÍü¢c=é°6(†*ÿ"â|»ÕPņ>Ó•ð„BzÆ"}]Å&9C Ç}e ÍÔÚ!b¦1K '´ˆÙˆ(›Th¢&ÎK•+Ö)Ñé—¦Ž ;}ý¢:¥… ;Ëò>Cš'‘oŠÈ½Ö Ô,k)©'ÌH‡àt‡¹íž¦&ñNSýÈuÊK¢8ü¯ª-“ MB1ÍM×–ÛÜo šîÒ‡¾9(î)4šKÕ–:Ì7ÕËÏ”ø{Ú&ƒ¸^WpýšxùõcÅ;õ4Ãør^z€Y‡hfèA0e@2šFG_=ÔŒô†žïÁªÊ#€W¸Íá9‘ñ‚™+Á1§©'Ò_„[a !Æ6Kз| 7÷}\ø÷Ú©ýííBá…žôòÈ"î¸ ¯l ÊCû‚¦ËŸ ]x%/›àò§ØÇç±¹-Öývýœ‡¯õEU0xì`ÜûxWÇã] ðs<-^k[ƒÊ/ņ§ÍÿÕ(¶-Ë…ü%Ù/òWq¾œ¾œìH•Æ’.o,W¥úFQo$7t|§¡Xda)̧°ÊŸt©9‡Èjq9Tùøä·£ÐH¬¼C—¦è—ü×X¬ØÔ±«G(5:Ö%£/É?$‹E>YOò)IA]R{Hz+–ˆL-ÿÛ±XdŒ+’l Îw´—}­ šÈDdZat¼K¾÷’ü#ôX«ëñ~ ôÙLÐÿ&ò{ÁǸ0”Åi0õŒqñhÕ‚ñ©»^ÐV@øû@]££ö¢Qơֺ6ü³[-V¦L*]õ€€r5éø}ÚÏžt<éÛOLæùs\¼áB#2ÏÇ®nùHéý`¦ÞƒD*¥CÄKD­ŽèZO3]Èdš(R©D†>D•®0 ¾ï­Vx×Áhâð±®Xdœ«ô`k%wÌÙA+†Œ;ƒ¶™ô³+hŸE?»ƒŽÙØÏrÜ'[ãö]mSWÏ<âæ\ÞÝ=ñûïÐ6zõÈC ½;yˆi«´gñõÉdŸô®×¡ÿm«}™HƒÏJG¥S#!,§AB;ˆ„òq‘`ÇŸã9Üz6,å2‹%€”qH-ØõàÚ.,ø4ä‡Ô,ûWWZË&¹Ìr…¨´‚£"Ùš†­ø›¨{æUôÌÃ6î_c®6"“­A»†_ǹ*öµ¦ÞLÇ ¦uY¼Šy8L÷¯506dÛØ\Ø&®37£K^–ê,/|7w;ç6íÆ´ñÃ?{‚J½ÀWlÞ/ä^®dñÊ“§9cÔ Ê$…Žw±¥¼ÿìŒÁ'ôvS}ðï Â4õÇ‚dÝ4ˆdº¹‰ØVÃdöoxº–Ï~ G¦V wQ­:H…[ÄSµ‡ â0½’؉.,.õØ\ëV¹>µgC‹dçV¨µï‰ À϶ ‚ŸdÐ<“«fË M”u°Bh²toíÈþÊK4äyÕÄ“kƒxîOVR3^?IM¬’œF±/hªPYi£O Y:ƒì9MCžJ;s¾Æl½ŽºZ©qòoí´Bÿ°§+í¯*Ó ©J æ Òiú„ÔH¥ÒZlÊÊѶ%ʇS=ï2Ü%ˆ–Æ@p“ã1V¿)ÑO”ÏÔmúŸF‡»„æ}¹'½óáCÕK«>([ë7­yÞ¦5OÛ´æYz6-­e[meãe‹,À¾óÉ.Y„‹c¹ÊD{ꄊc‘É.Êý•4nµÚþÁj=[å¶ÿ ù¸î±Ã£¼Ë¡Ó̯˯?ÖYú E(ò ê(¾#Ú-5- ÓؾAlOdÎ[|óv«<8-ú(4xš{&f¹¥ñ ¼¨öÞ ¸tf†ã«Ùþ ÈŸÕgžå©gåwEmÐd=Gcæêzù=x4ž£M$Œ±=ôø§DgùB[60áúb¬Ü›(õŠÒi.A\¥±DéT—`_ˆSó/Ç;Ë$t5àˆÍ…_@‹2]‹2žŠ(“? ßV‹<A/ͧ"È$¨%èÿ HžnȘtXËøƒ¼ª x•¼*A¸ç}­¥yŽ¿ ._ç¹dÔ/µ©_ýÑlÇj·Ú¶³fo ÆtjÀPL›€ÆJ O¼Áó#oÈ ®%yCÑYì*]Å ù7²+ª qÊß$øúP#™ø»’rQl‘¡>ax›üŸý`Ðò;|õÖßËß52K›™þ=„zÛÃŽýCøxß·Ef&ø‰ic®zÿFUï÷›l•6€ú’d\þ;UÚ?is7ë=·Õ¶LA’þ¬5@ÖÇÐñZ} †tÑWß”júù$hîN?‡ƒ–Bþ—ž}<‹üßÚog>¦+‰g5vuQJ{ˆT[4/£-²6Š#Akž ´õdBTZØœ¬IÿÑ û»eèÄèÄ™êÄ Mû ¯á–y¬ÝÌ.Ä÷/ÊÃé½¢ÒÆ€ƒð m•Ç<8©ÒΓK“Ðv² tšãôNs8…Aw´s/íœÀÈtƒÇ–gµí4#ûÆòAíÔJŒéÍ?œô‡Jÿ\ÈV76JñɉíÅìU¦Òω y:ýœ Zf`sy z¼ÑÉ/´½Iè>j©:îQ& ú6§ˆòN]:™ª:ÕË©éŒoÓEœòN¥[È(¡¼óÀQk–×&(ó²*=íy™‘ºØ.§‚¶9ô³ø[ö¹&J—É.m]lå*eZj¼?HÙ•öê®^ïTƒ·2›âtÐ1_ Ïr. Ÿ3Au!©k±ÀžsåµâĦsg±‰Ê‰²†»ô"øÅ%>'YÝ5#(gene Ù-—ŠJ7œy«ùpí¼»ÖÕJ7UúE…?oV*f’ÁÂvÏbñdnNÎ:*®\Géü¤7;çzó:²É8¡o„OFÎOfyräMŽ,‡‡¬ Z6zŒm_õØö5‡{¨èÿ×^¡AH­ Áè¥6ypÖj›MÓªó…+ýgƒþ:óóJ´Î×(ªžsE¨Áçôàzlj}B™'B ®ÎÒ‚(¸ú ó|Úàó:õ~ îþ„e@ðf«|€‚{HÁ=Ÿ°-¡C¾¨¢à^OØ—‰Ð'¾°7P€YŸè'Xó„c¹F`!ÆœÓfn€¿åÓ U0$níS¦ÉT± ˜,¨ŽÅ#ײôOp›ÞÅd½6Úx¯X`o‹‡ºoû@k¥÷ß­¸ÿnÅýw+î¿[QßÎ=wø—­² ¼¦y,N›}«|…ÍÖùÞàÁw …ÜûÑóV‘ò¨ü/‚©ËkO]Þ£ ½Ñ},™‹ÊÓ¡|ª+™ê뾞êëüñÎÞRLƒæoÈoPGYƒ9­'+-Lø­á·éÃ+Ñ¿»ùRœ ù_iu[ž^{ލx§¾®ó›*´ñ ´Ö/àë·ÐórÐúuÙ^—/ ©æÒ‚¶ýÅJkÆß÷.&ùRù]Þ0!íÞWðÏ•¶ð¼ÂÈù¼ŠëYò‡Þí+ÓšZ!ìÇÞe{E »Àt?õÖ"ìU-l ÓýÜ;s½Ñå“å&"ó KR#íßÿ-Ù¥Ò¡OV”‘u+äôwáý.½_ Êé ®‚ñŸRþD0cÞÆ-(¦XRóVžï°:mû65YƒMMôÿšš*›šÞkj¢ ùzy;ÒD&íÆK¿,¿ØšLRL%£~*…r*…70Tª¸–%+¨Û»ž¥¥ŒÇÌ] ÅL(~‘¶ßTÚü׃7²àêAF±äÃÑÅ¢ta¡ôùoK*D!K±¶È¬ð!}sz(OE½™å“ ÿ–Òå¤ËÛI½Yù“·õMòÏÉð>_éâB¸ýØê1S}žlF}~íÆ.êºÞGŸðÿèúðªŽ+ÿÛ_•ôTM‰0Ø€ËbÖKˆ­õÓÇ)/„mâMâ”Gžñ‹RØMâàlvÿ»+BtD$:ˆÞ{ïõh¦ƒ)è]ÿó;÷>]=;û} ywæÌoúÌ™™3çÈÿÃýøÑ)ÔR™ªûÊëÄÿ&Ù…RL‹F²=ä¤,ÐòŠ U^ÝúËqÊnu$ \b}ï^]G‹§o-<†’ÇíwÈc˜ì› äq­[5Wûªà1Š<î€b´ì+G¿(%ÔrlOï¦ÓFµB6;]s·ø.^LÈf¯kîo‘çpÙìvÍý£/¾fë4÷‘d—иKhÔ%F65ißmjúeSSŸ¦¦ÿij¢o¼Î¦ ÜI¬È— ¦<ÞÌÕÒ¬òäÁ;»B7Czèx.ÍŸh4¶L‚tЉÜ.ß1Ç¢N u¼Ë£wÂz5ÀJeH¶,~nJ¶L7Ÿ…¥%Ÿ2|†`er¨ñàÿïã.`ŽXö¦%ß FÓ’&²ãB­§ýÿZòßæóƒ4=á pHWéˆÜë&è'ï|].¹€97ž¦jº{£Üø”% Í#ËgïÈ?ûPn_ÞG¡¿¥/ôQ­ãËçïH?Áåлám%ˆPèÝWŠG´ÅpG¶a¸«òEïe@VçK#~úkäV+~ÑôahTÛ×ë»L+²&?š÷ä×h_ ½KjQe[Y”€µL9Þ¿küû•?È*N<ûŸÒC~{˜it[I}AJðÕ—P¼Q ›;I7È•éòÇâ?h;¼Ìƒ1r4M£íð3Tƒø÷ÝÞÐæî¤â‡›fý×¥Aæ[/8ýü œ2¿ §¿_Jο>BFgçë zyXOÖ3ãa@ZÌÈrãñÝ@¿Aݼ‘¯8*üŽñuß9œÁ~×lý̈lÈÿˆ:þ»Ú°2ê”êBaÄê¥tVjO-Ñeˆÿë2òK,MWÑÆ|üÍ[› ßNµÌ^³©þš¸T'ÄÞC 71!±°›C€uv”«Ã:ÁÓ„;좔³dT™OŘª£´„Uë¯JÉžß…u]óÅ\Œ“!þ¤751«´™LÒ­èÆÇÒtMÓ{¢öÊVcí5ëÎ0¿²_ûåàYHAŸÍUJCõâ€<—›àâ±ÈrO,²ÂSt.W™O®ãûùIܽ¯qËæb)aËDè×v¸_¾f¢ãš|„_½%‹©‰Üb•F¾op‹ôkPFTé×e!0E6áÍ1L: <µ ˆÛÜàTÌ;2¦gó–¼] kñȆ´Ü4ÁÜã<Ösm,>Oû9¥0Ê/?—E©BùXÉÝô¸M8F±Ç(L8FÁíp<°Š OØ„³’„³LÂYŠ˜ÂÕLxÒ&Ü$„láÚòÈá&<ÅBAIQø. Uk5 ~ŠZûÔ¬µ£J‚•Oò†.®i ¡º.‹Þ =I§‘yy2¼Oð}Ûé4EÓ·JW$RÝ^êÚ öËôwU¥«øGœ®¿M”,ôˆŠÆJ{D·h¼d‘G|/o8ú÷EÛ·…hû?DÛャø‰qÚ¥íÒ%áÆK©™Þ­…ñÐèÌÈj±ÄÏä&g` |d‚m9IÃk—>@ýO u(¶Äœ”ü-ˆFy² Ú×#ø.~÷|—pëÄwâÑÈbOÑfjõžqJŽzº€¯eß ^Í%Ï«¹JÀ$/²Éˆ¥àlšªëÆo‘*?‹®L—hççñê·xG<ÌO;bÚô´Ž´†SmÄzâÝÜûÒÈü$7QÝ¥Ê_Íã»I*SR[ò¡ ¢þBŸãê ¤xwurèîôÎ3WÞþ§¸{NðK§ðØ/Ÿ‘Å$1‰8‹3Ëõ&ô9^Ñ.p1þ†ÈŠ9ü4.L…)°ˆ³Å~e¨‚cȦãÒÞ?v”êÙȆ›:\Õ`ïX ·œ°Æš&F(ñ(eݪVв]M˜4];itU²ãE;Rr0ÁÌÁ$3S1©E¦¤æ`#©–[·ÈÁôÔLá0M25œƒKvæ§ä`¾™ƒZ3‹QÛ"‹Rs°DK¾ƒ¥©9XôÅ,ç\NƒÊÀÖÈÁNÅêM;±É™S˰Æ@q1IqQáw™œ{_Q®(â²Ò¢§]QÌž6C—KßÁµz¢=«{¸ª$0¸¼Jqßg~JS°nìà)XX2«–'ñBº~οrOw”x—©þ¢­Tž{|އ¬ÔŸše¥ ð:ݯ>€´i"²-ß* íÑ-‰¾Dd{¾©¬ˆ÷‰â‰I+ñT¡­‘oEˆŸ)1P…5šz +ž#0´‚gë&%Ö¸>ï±4j¹%iÕ²WyøP–þ¸W,W1–¨”×8 9 QQöë¼£oOŒù¿ÜÁ Ýÿ?ø11sÅð›vƒ·ôÝQóûJ]{]Ëe–Å×h³ãÆ#7Îô[Šiv^ICt–_^i.m«eÜÀ´\ÓÖ›rØ”/[/'ðY¼3g‘CÍpÈ]¼+‡‘ƒn³•·Àû »xw>-ÝñHÂGô°  _ñž|±ƒW·›œ¹ òv0™·ƒ”©]oÈͼ–Åa9xy»hæ-J2X§B x2Š÷æ‹ùF ö= ߨQ¼/Ÿ¦)¤r‹O¨_F*g’©œ!øÍoa’:'7/Lç´i¯&i¯­è._…úÂæ¬@Q¯MÛ˜¤m„¬Ä[r#4¶¤m¤6„& ¢}“z@·hð½.»ÞêùžÜ>tW ÊùŽÊ«Ôí4¼|OÙ;DVºŽYöNT£q5½—\eh¢}<¡ü ñ͵è[D“ÍŒ—pê} ­Lçúú;ϯþ£Tû)›þú@üô'q„ºø ùj³1y ]ޛ͈?Çù›£—ø9ކ`”:Ä/šu}Öˆ1dÙøÚ*~ùKßúÛ+nã ˯ÂÎÌwȯ8‘õ¼‰vÐè5¯eÃŽ.Ãß‚ðöǬSí7af ÚdO÷ãrû`q¿§(é+²X©Û|?¿ÍÁ–=”^㲭Ɔùc —íqµðwR¶?Ue3T|€³ZÃ:«ík>5KÓ†£Š+ø?X¦5ÕÍûgœh/ðãi -ßÿ…Æ™Z¿†&“±uhbg þ;ʉ¬¡Ö|õ -?6¯‚GµÄ”c{Î3Rá½n™ µÌkÅ_£^Z\ýÒ"¢ N¼ŒsÝa_`tÚCÓÎÕê6#ä(q¸Û¶x4ÞŒ”ƒë<Ä5èÄ5W»Î£Ðž=b”˜…BATµ1ÆÜ $œ±æ›žûi´:ðT5žùñ7­Åp<ŸôËÉYäW&³,Sì[Öb8YŽEV:q¸(Ä-ú~´¸%<¬ÿªæ üo`ºƒ/¯ öëTß îõ4«š‹Föy¢‘ýôÿ€§ç^žLU¤›—ðKÍž_<]IOœ ﱺ0¤·b”:ô Û‘~M‘>& ¢Ù‘"V¤ˆø EÚHCíH¤HB&`ÍŽôg+ÒŸÅGé" OO^úPx~ðH~³V¼¨ž÷zà ºéxëÿ-æÍ»JçÕ^¹4K•4ƒ8ª«ü@íu;—&¦’Ûô=º«2^ëu'·KSÇ’;ô=¦«úDëu77˜Þ3]*¾‹¦™®fªÚ9Gã2¿Øë¶î_a´CoàØ+÷†/ôöâW~¥7ÈËýÒ^wƒ\W ÃYáWö“³Ò¯ g•_;ä†tý† žqÓ VÀqË ^ÀÙ@Îj¿«ÑyÞ}È#ö»;׋n\Ïqdzú‚ÛsDZ6ó=D£ù`DÛåægç6ÆküžãnqÜËgÓruo¯8᥇½E¥¹²8…¯Þâh¾8í{‡3_qÎaü îWêyÿ”¢Ešr,[§W[dáFK|C4R^Ýâ®;Ö>Û…»šµ~ï}·¸ï6mVöNÜá´¬LñÕ¼”ö¶³ÂiXºxâæÛËtÜ^ž²n/ÛÁ€é3w8=ìˆÄò©êÅswØi]´â­a©'žõ ¬ê^噌_÷÷„]4¿ñË/Wä¡»* — iAK"UxøUa,?ìdMpƒù;ì,Žå‹!žÎT’¡ôWà ‹Ó‚ö]ß|>¹ª/$®m"ÃLn<TT\z¶5/=}Ÿ@”̓Â[Æ1}¾ÉÛ[ŸMà–1×9žXsæz¨*¨õGbÙõ4W 4²ÕRµÐt.y87™(ûÒe_ö¹²¯h‘Å•œéU\vÄÛÔ‚Ö?·X˜(àv¦ÝÙ"ö..àL øŽu«{ÄÖ2ÿÈžO«G=ñ¢ÎÃã ÃHÔ{p[ܹh†[ÇéwqŠ˜å,ô¾³@G=G?º¬ö¿RÏWðZQ\ k  —èúž‰ôr RqµE:×8W8ëHG’*ÓM«çËx…‡ó>Ñ~ódeîO‚®ˆ9­5­äž‘UñS¨{N7_à=«©Yï—‚ ò^]†*Àxñ5«ÎZF@E˼©{x û½¿¾ä÷q4õ˜b·QOd¹Ó°7:X'r&¾ÒmL*ºKÛdÚªG‰ÝËk)øŠ2Ï»ÝMŸ>°P¬X0j)Ä{ÌIé00ÿ€ÌSÁ'/ò©àÓe8M™Ê'²øD&òƒZGqfHäË¡W+¾.•æÖc“NEiŸ}ëY9|Ÿ=ß—‹£q™wô“Óaq¾;x’Là‰™À<‹wlbáŸç„”ð|T‡'`´?ÁòSÒeÊÝËÜŠŠ‚‹εW•J¥‹,Fƒvª]%³™öô[Òl(‹±ÞLy1$±„5/ÏS‚#ò1^6ù1^PÄ‚c=Ø£dN(@‹ØÕR¢]6ûŸzäÎxšÎé| ÁË”¤ÁVOT±¢«)VsJÑ:`lP  «†}½ÜjðÝÒ¶ç~xf3“éæ+Mò¬‡çI%9‚i`ç×p–Sßâ—ÎRUlõËgqŽê®äˆ'/‰{¢¯Ýò [Íæ(Ü»/%£\2£\Âa /Xì„ ᇠꌞ›nª8C;2Ê6¿ôDO=˜óì˜Cpr6œúY1çÛ1Gñó€­~i”*F«“Ó\n>X%‚ˆ9“c"ÝjŠ^ËÙÿ=W%¿ÿ^w÷ ªØ FKsù¾Æ‡«ÛýòfUlVc¡ïUآƳ¾„“,5NUW•䞟óܾ]¥¹}§£0è™Ý¨Æ x_ìæó¾…œå7æÎrEéˆ*¢*áts^ˆîeÉ,· ™I¼ƒH×)§ßE¬ãÉXÇùá¸|\'©¼èDñl<´<­ò4‹ÝÏRÄ'j4ô +ò¬U´£„rqhâ,*sÝäó6êæQ6æïì®xWµ4xÝUÅ=¦‰®òZÊeá£Bc½»^i°&kÑÐm*?&†h10±rhñ‹Ò¯)–ñtôUD¦Yè´©Å0«d¿ˆ}ƒÄ£{4T„)íˆq Fix8a…±#Æi¨á\®ÖðßÉ„t‡³Ã6!ÛÌ…{Ó´¤QMÔ0!31ø«¬ujlhK@ùÜD^kê~àhÙ@«¹*˜ôEÖW ½(:˜ QüÀ!^2'ã—!5l£~™P¿’‚ú0u­Ê×UUÒÛ´Q2Q:Ä;&ªÆ5mÔïê÷SP¥ ®·QM)Ù©ˆö5&ê#1ŒŠ§)lTÚÅÓF§%êãÔ6*o|&ÐÆ§ÄB}ì¿5Q¥Ç6ª¥¸ºê“Ô͌ڤ¬Ìzb+³6QŸ8ðøƒaûa:Úb-¶DÌ+óh9ùi òVF~Ħ! I0T%[àOØ;3ø€o³Á¡î/!Z‚?Kßnƒ/fðÉÒb~9g‚?sà->ƒ/ø|Àw¥‚?Oßiƒïað)Ò¼·ÀŸ;ð8žÁ|— ~àgRÁ›RÀwÛàç|jtN’àM˜ýaðKßcƒãA?Ün>Xo ¾×ÄàÓ ¤G2Vo|0Ìè˜àÏX¬ c5X©[‚—:[‚ï·ÁÍWÒÓ ¤ÑüJÚ/uŠqŠ ^Å6Cm𹟟 Þ/ü  ^ËàÕR­‚UÜïçÄbÎàKØš¨ ¾àÛSÁËRÀÛàæå[Muùf‚—9Å |/ÛµÁOüT*xÿð¨ þ ƒÏ(>Q°Ä›àýXÛü<[ µÁoün*ø€ð¸ ~ŸÁgH÷,í&ø§xd?fÛ¤6øÐäJÞ¼<ü¨ >’× YÒH(@±ÀËXé| ´c6øl€ÏM˜^gƒÏgðÙÒ|UÔ&Á:¡E„Á¼ÞßðM©à)àÇmð- >§@Ú¢¿`W8‰I0Áwü„ ~àu©àƒRÀOÚà&/0·@2™|Sœ²ÀOü” ~àŸ¥‚N?mƒßbðyÒ-Uˆ$ø`§h´Àoü¼?Ûr-|H øÜäæHÌ/˜àCœÄ.˜àC±þžµÁ§|Z*øÐðs6x5ƒ/(ª5ZÈ-ð¡N1ÓŸðó6ø*€¯I–~Á_ÇàµÒ:MlH‚sŠø&€_´Á<š ><ü’ gð…R\G“àÃâ˜^ðË6ø§¿– >"üŠ ~Ãdµ ¤š¸™á·,ð€jƒ—ê^¦§€L¿jƒÐYž¦@ ‹º>Ò)*t|õ¢6øD€ON¯L¿nƒOeð%ÒT]LO‚W:Eµ^ð6ør€¯L•þ™ ¾šÁ—H«u±6 >Ê)ÖYàë~Óßðƒ©àS–¹[6øa_V ÖE4 >P1 <ðü<À/¦‚Nɹ°Á/3øòé².>M‚vŠ«ø5€7Úàþ8|L ømü)ƒ¯(žêây|ŒS4Yà¥lǶภp\F øØð»-8.à+‰ã2D•auŠñ†Åqüž >à RÁÇ¥€ß·Á2øªi¡!'ÁÇ9Å |)ÀØàÛ¾3¼Jƒ>´Áw3øêi·!ö&ÁûëbŸ¾àZp\?“ ^•’óÇ-8._C—!.$Á«œâ¢~ àOlðû˜ >>ü© þ˜Á×H ñ4 >Þ)žYàÏþ¬Eƒ:РŽð )àÏ[4¨àë¨A¢ÊaO uX êÀ_ à SÁ'¦€—fØ,4ƒ¯'Ú!–&Á':Å2 |9Àûe4ƒïøîTðI)àe6ø^ßP í%¶9 >É)XàÞßÿàgSÁ'§€°ÁÏ3øÆé<±ÍIðÉNqÉ¿ ðrüÀ¤‚OIhƒ?bðMÄB;Ä“$ø§xj?x… >Ò‰ÓJg øÔðA6ø'˲H4äÇ9-ð©NQå4ÁÇ;qfƒÏøüTði)àClðZßB,´S,J‚O#Ú_ð¡6ø6€ïHŸž>ÌßÅà[ ¤]Ä6'Á§;Å^ |À‡Ûà§þI*xu øü,ƒo+Î:Åù$xµS\°À/|d‹øƒTðšðÊ ÊàÛ©AâI¼†ÔðQ-Ô…u¥€ÏHÝ¢A]ßA êã\ø jP—Õ .˜b´Áç|A*øÌð±6øBßIS®K,N‚Ϥ)×_ ðq-à;RÁg¥€WµhPßE ê{’೨A-ð}oƒŸøéTðÙ)àlð3 ¾»@:ãç’೩q-ð ŸhƒßøýTð9)à“lð‡ ¾§@zè“às¨q-ð§Ÿlƒpc“ëNŸ›>Åíø^ÚäºÅX·>—F«ÛÚä ÄÔ ð©àóRÀ§µhPßG ê‹“àó¨A-ð¥ŸnƒoøöTðù)àÕ6øNßO›\·ØŸO£Õß ðü8ÀO¦‚/HŸaƒŸfðÒi·8“_àg-ðsŸiƒ7¼1¼6|– ~‡ÁHwÜâ^œ&±ûø€Ï¶Áy èéI_˜>Çæø¡i˜GŒðXà b¤Ç¯Ä‰ö\|À«SÁ¥€Ï³Ág0øái†GÌJ‚/rŠÙ>šÀç|¾ ¾àkSÁ§€/°Á×3ø‘i½GlL‚/vŠMVÎ7¼Ö? ðh*ø’ð…6xœÁ£´'òˆ£Ið%´'²Àë¾È¿ð«©àKSÀÛàײ{+YE·(¯;;É·t!¬*ŠÄò¹ÔTÐxq,ŸoçïêÉë8ˆܳvÏPñ›2š/Ùê`C 1¢1K|V!3N«uª˜èÞ[R•Á8Îý·8ÞRá<|Kƒóè-Ζ/ ÚK[ÓÛ!&aËL¢±xÖÕP£6Š¥b26[2d*m¾ã$i(M3²<ÍÓA²5×çøb•I>S¤D²Ó/ÃÙåWfb&(·qïç Ï9Ø®Î5Ð%" ëŒÉm~©Ï*¢8Oó·Û±æ'÷þ¸éÿе‰cí°cá@,2cmü¿bmäX;íXKk©kóÿk3ÇÚÅC«-bmåØí—¶8Lˆ•49Ä”}77ð?ƒæ(Ó,|C:jˆzJ`8 .AVõ¸…ý˜áNqÒÀ$šW§€°‡Ç&w¼{Œp½›ôÀà— ñÀÀuöGÇø ·Í– éGF,NÕ7Câ‚ hÞ›¡PëýŠ'ÞDîñK•–®í¸2ÆÁ[ÿ8Ä&Æ8Lðz|¬#ž`p„$Ìh‰FD¬¶*ó$F; ö¼ëˆË?ÇaÉ’Ìwˆù¾\÷­Ö‘¼'_À¿Úç\£è ±«—:\þŸa #Üê&m3sºÝ!¶9Ú—¶:&¶¯Î×x»ñP« øîvÄøuÏDƒhŸoU„Øáˆg¥Dö;P8ójSØë—ŽS ˾"Ÿtˆ“ŽdŶú'ޤ¾ç3T@q¶óaž!Ìó\Aävÿ0cöË’î;Äc^w‰NÜçï(Û=FÛþXǤéÑ\V±„™hŒù” Vìô_ù¶ÝisŠÁÎfÐ!Nˆë;[‚wÆx©Ø6¦:9Éu”«›ÁgÈŠ% Pí´D\h[;Éâá* pU2p•“¬qŠ5NšUzðâk­3nITǭ׿TŒxG)0³ü?¤‡–¦(„¥662Ü>¿´‘˜Egì×Ñ÷°:Ä2šïõ£Ø?Ç9qÛ÷|O9!ø’`0žˆn0ØŒw¤Ä¿9£è½±ê¢KYÜÂÆùh†FéV^s;a¼ÝÔŒ„×vÔÞûýÒc'¢Ëpø8wuõï¿ÁÄ«‹FКùŒ+¸´5-þÏaÍ4€Ú/Këç¢_àý\a€jø£Þº@ßÔõ6|X ¤±»Qᮤþ2빞C r…ñ¢g”årXa0r£Ô§†¹ —-QôܣШ1ËP M¿À%Å[ÌC~i”‹ßÚŽ#ç°_™ݸÔä\ú²6ÇÜò[ËãD‹|;,¡Ë*Ç$už)®(Æ9Ìé.kp‹©.Œï0¾C߃V¾ÿ½Dà{2ÇÏD.g¸š}J»B’rͽr€çØ¡¼èĪ_ œr*¨¹TÒŽMx:Áª{O8åÒö&KƒV¯ËP½š¾Xã9Ý…V«ÇKk4ô6è‡ùŸuá±|= ò¤¯H ©ðGüòB—Xj>ëo£~e9…Äüê —Xî²²­ÿ®D¼æ£Þšo™ŒFŠûµ5ä$üúZrŽú£äó;θÄZW”f“GFÄ:WØÈ< n‡¼ã5Íþ›É?kzǪέ¹ÎïÚFN½ß½Ý%¶R¨YW.± ꦌÀI§üQo·ØN¿QÈžºÄn„¹1V¹fwbs@ìNì³hÅ~9èÚî;ÍaW$á\ô:˜š×(Æ#™£UÇeÎ¥ö:âÂ[}Ë0ù›JR£®°‡‰¡P˜>ã._-¸$C|Dôú­Ã‹g’õ®DØQcvs(˜'8ÌLŠ Å)W|ÆÌsX_áAþý+ÓÖ?‚ƒ³®°³£”ÆVP\Pù).¸‚í©JÚ›™;kІӨ»èŠÓOZy.QÂô£^\vÅðã˜X墉æ…o=oW1Fêmæ‘ã¥TùÇýò —¸’ãö.`"œmd®‚CZ‹~‰•ö05%uJ׌¾½Ó}oð‰š=˜"Jg“Kq¦ OGÍLgì:"ŸÍ€†×<ôȈþyô•’^ñ <ýø%ÌgÀà@‚EÁáPŒG гÌJ¯T|!_ü&tÎô.¡QíJSÄo!`Ãømð{èC‹æ¯ø·^1¯žÿÓÁL’ ’?ÉGˆß¾"º3ðPîE„ü•Bþ†fGþ3ZtÆ#Aft€²3œË×A7â‡x.Yáe“]£ähp7ÚsW.©ð²0h¢\æD_B”‰ˆ2™,ë.ø¹ž ëOžÉÀÛþ?€tºl„L—ù dº,jä8N(´ÊiŪ¸‰“ôH¬¡y–+º˜&ù^â'LõŸ[ãUF3Õ|¢º”&Á|S,þƒÚò/„Ð㧦 J”,mÁ Ndü*tF@³(ÕŠ“,˜Õ²‡½"`ŽéZÔ*”) ? [Òùd–·ÓèW¢²8$Ǩåøù°üm•­6¨‡-$úYf¤~ºÌŸÝiÒǬ§7!77üNjø£r,IQU2>(>æb£b#¯õ\ìóTìÓÀÈzLŠlgu+hç¤çÍBŸ£¸ '8é‹rË>çË&¯Ëƒ“¹B1ÎR2WQ§×3 OysV¦Í#âõ Ìé6±ƒäÜ1U;mù²z[7åàÚ…a¯w –µ¨×6˜¸èèBæ$#'Ü%å^Ñ(˼±¢2¯,nË1ëœMw YÛzOkAÿtÚd½ÂF¨ûÇ"1FÀ}4Ã2w4À 5GÕ#äù±§ºñÈòfïú¥!ЦP©yc5\¡Õ|Æ¢Íi8ïýÌŽ3=g:Ìî$ãÌ@œ™Vœ-çf†’Œ37ùºe®Ââ°å^óD´œ²v¼µÌæº`‡~‹¸kÝxq)w½Haîz‘¦s¬VX¦àÈì5±G™ ºÊZHNš¯Th ù¥] ùîSÄ¥¹?ïTÌþ¼K±úsiä˜Ø­Ä¸ {P†}Jð¢+¹£Ý¯Äˬ·‡ØÑ&{ ~G.8?†.q@±>cÄÄLž ‡8¤ÄÀ @®*CW ß†òvM±ÆúM¶’˜L瘸¥äÒD¼ëšXÒJ?ýHÄÎ)”¾nî^<à'U<ã|ƒ;$0oª„‘ n£A¥þ¼éI^4ªÍ]⎚2Ñ>DHhq ÷ÖSÐ,ë =UE“ =ÌŠ4µª5«8”½‚Ÿ`–Òf¹‡(3×t‰ Ö£1^ ;ÔŠdè44~ÀJͬdvD®dvDS—¯VjbŒöwSA£ŒÕ¨Qª´àÃ\4x40Ò+Ň¹`~îrù[!‰“¸Ú9M:Ÿ¤2“Nn,æ©êœÆZGÜÈtNC~d8ãº+È©ê®^'ôí9÷ýúe ›}ã H¾â¸Fοóž&.hÁ·c‘&5ð¶\úv½¸¨%"ƒÓ°×§¾¸D_äv©a­ÔËZð©Áümˆ+ZØˆÒ ŒkSMï5-tª5UÓ6Z« \i£`ßz›]=ƒ¯Žúû]B ´¸‚^hQÖñç† ®‰ÛÈ»œK^Ç¥Øk¡Æ,â©h·\3'dû­äñÖPÜÓX}ŠKÜ×1h¢ã̵ÉÛQú‰R4?Í46 |?CÏÓêí‰ÆGZŽŽÒ_ØXÈ«½Ý¯öö¼ŠÇÙ¯õN#~óÕÞíK‹zûÚ—¾Ý›¸ÞYíK³{g#4çÕÞ0å—ž˜Õ çÈ›ÊæMÕgä<òkÏ5Vó]ª‹g7/ñÏšx®áIÝX¯ÂÚ^Jù@Í'©8?yì7úë ò¿c9OýÎrržù]ÉyîwWÓä÷ "§´Ð[EN¿Â´ñ䔦O çÔÛ{tÑ_ï(Sµ йX¢œ\p¨Ùu‹ v=b»^1TO„¶fFž¼`iÛå¯Ç/˜jž†ëªԓ¾-hžâ €e?Ÿ‰1úír•Žó¸ÈÅüÐk¨P1—<ÄàNôªà°&èÑp:}Ç“¼Z_bM'éqs¬dCGÍ=œ¹”™æí(W£S›=È=䮃bLÓÃ(Ötv½¾oà¼j\wß,ªÓÝ2gëb–Ž>z»(fë|zΤ^I½6ḴP§›É¸ÅÜfrs2^±PgñËEÖ9Ö:œµøuØÀz-Î œo-ãábëÚ*Öz³˜3ãKØõø£³(ÌZ©CÄ6”¸ç‘CÙèL,?KŠòÀÊæ¼eãwÎß©¼0{=•d`aÎF]¬×ÙÀ ºŸØ ‡³ÃÙT9E³³5±Q§5ó26QWòa~¥oï\±YçÐvÃ*Ö| ÈæÒlE?åšÌåªÝ–êá{ô`QÏ" _ìÓþŽ|ö°Ÿ~E–¶ ;‹–µ•ÅAë‹F'ý¨ö]ͧ½¤åé »‹®å+â°õí {‹®ÓwÔü.ZÑV1=öH“i@¥=+À̽÷´I$p×÷€§Ùu¼öÕ릆~dò¸«×yÜÕëâ´Žzˆ3ô83rªUmÒH<9ðÕÎúzB¦‘ ëó¡#tÝ™‘KmöTõ#¿rfšUõ¬.Îè̓´^œÕYS%_åœÓMÕÖÔ­‹Æ{U ƒòIVÆ—:~öu>·˜aäê†p¡W¸E8=¿‘Ÿ´O„™* <˜Y¼°—F3yú+˜x^ëí{µw櫽³^ÅœóRï.ø³àWxPàЄsœ…ÚM]\×í™ææçjÆì½VÅTÑäÓ@#4³…\ 7Æ1Õ¸ÍÓŠãO+·º¸ÓÜ q—t°;¬ó¨{ãKÛr™Äƒ–#Ü éé°Óá.ñ¤y„/ƒÆ8¢¦ºë\4Á«‰¦”Ìæ@A?(@FÈGè êbŠ(#ï„5¸¸“õ·}˜È}m a–•µ 2Á>ûØà`Nòy0'À|Ÿ(<±¸* L,îQ†¨4ì‰Å-F™§ôa·9±xD•ö¤Nžæ)Ó2e¬„–ƒë⮋IÆêbÊ߯‹©ðv%Ìùг?­¥O×EUs¾Ž×߯ŒY¬‘¡²%Üì¯f<ßaY 3·P iüf®‘y¦ó,¡Zª,ô® gTaÚJrF¦¯2p[ÜrúóŠäÑŠ=pI‹ÄJƒ¦"btjŒÀÍ|‰Æ‚Xe„Ó»Œ)dÕf´É¤…bÑbÎôrµ{yÎ,yÎÌØ`ˆ Fr²ô‰FØöRÏôñd¹9µz‡b ,ôm£\Ž-ÌÜnˆ­¿²·ŸŸd3Í[àœ‘òì¾8¡HD­ûö¥…e…`&;pf%hw6+œYMSàÑÖ\½{Zx Èæ–ÚßÜR¿CÆÆf4ÄAb£ÌùÙGjúÒÂqÈgóÑR¶8L?9 _ѿ߸1xgÛIÇ“ßVºŸÐ lªsjüJöYCœMvïÀÔ4 Ó¸`„s’ü{8‡:.oɳô¥c⪠<™_gyþ çƒøô®ÁÀé] ‡õj’¿â9­Áà#=84§Á©*TáLz[k`© ý®ÃmÆcC4ÉÉœøôÏOæl$à¶ñmq·Y†Ã÷©h²t‰-¨< ÀÇF"°Ö%±¤RbG«^Ïê`!=s4Ÿš¦§xáÐt<ú×øBÇ Î ƒ8Yt !gB¡{¨C qð>ëíPG0¹Ð;⟅=3°Bqàìª2ìžis¬#f°á°+fÀá'õƒ4Qå Îíª§UcÊOMÏ'±,;h¼¦ÃDÂd5¶<éYSS<Ý+¦8XËa7_DÕ˜1¹Ó!c1à ;äöÍ@F§¦- ŒN-L_è a’Õ:øÍÌåBG‹¬ÅÌSF+—b±#œ\¦s.— —а¬9—lå£9?]a¤9?(ÁZ³Ó¼–'•`šW¬KæRlÁZiz,vX‚{IÑD—.¶B¬ÿq†êÖ+*±ˆí–v8x5…sïÀ™V¨î"gz¡¶›œêB=NNM¡‘ gF¡£ÎåÑyÑ!váUã ³Éu±'µ!B±–’OòÃúŒJÜ’¾G>û-»TNgÕ"±çògš”ð>ìàË“<¬có‰XܼÏ;FkKmž"áà bµ•?u¨|ÔöIª$ë(µÊÔD"N¡ÞŒZSäìTŠ[Ä)3·òў׈Â<f¹»ÞHø 9è¦4éK4L {Rܲ|æÕ²ð˜ E¨ãsîø©$h$Ì€A<ß°U·ÈoµIܵ|&~ɸϱà n•¯$žð"÷Y>›Ø+uòŽO«af¶Ÿ“wzO24§n|Êìc¹Ó4¶Ë'•;¹ÑáP£ÃI¼¨²g¡VAÎÌB}ST84Ù'h®¯FãršõbˆaÎ$ƒK“áN¶ÔT“°ûxæ¾ÕͨtŠJÚÙ›xi€£ë6¯mXÓòiMËÁ¡çX©DBãRgT×)Mpâ 2V6ª“©!PLvòéôS\jí¢o¢Äï_æÒ¿~žŸ_Ò ¾¸>}–a[Û|ž¡xY¨pV!Œ©5ÈK:I/7È :Éôwa'åe˜ÝS_†Õ=þ.ê¤ÓßÅ ú»´“ƒþ.ë䤿µ\ôwtk÷Ë¢Ã;Gc%3¼â•h¼d²W¼M”LõŠ× …ކìëÐBG“Ï?@ 1]hÄ–ÔxÅÄ+–ÌôŠ®Ñ°«d–Wüc4ì.™âoFÞ’sñOxÕ|;LÎ 6Z·Ã¿È/ù!|P¼RŸ$kNù`À!›ˆwûDnpEvû~Y2ÛËTƒ}v% ñA²ò›³ )«xØÔIzµAÞÔI~ši•W)çT¦×©Ló‘ëxI-2(Yˆ<'•7—, œã Ž—Óéû'ÖW™ƒèa¶wwSƒÅx·½M“q‘Zx°½¡ÍÖ,„÷H_²ôðBð¶Uú`~É;ðA¹*}P¢h–k”Ow8œ=çНZ /¿Ú ?~Qþ*”¡(_…x´úU¨ñѾ ->úWÅרX˽â=4ÕJ¯ø¸yâï¿£‰oB1;œéü>eëÑÈrdkŒOQÎ\xYšIŠÄ¿Pu-‡°öX;ÒÏøÎ$²‘ÆÙ‘~aEú…ø%EZ‰HU>•B¿…Ð_!ôñ‹R±(®Ñkt ’oáh ©C°µd…Wü:¸V­Õea$£¿ò¬ñŒV´ß[h}DŸhÿfEZaFúcp¡­#´?›Ê&' âש⠢SðNKåótüÿ Û_æbb‹†˜DœÃùNãÜBQh5D!7ý=íS Ñj!š@CS%JÖzÅ»¼‘ ëTõ_Ë« â;T‹=£‘µ¨Å)V-’÷w­Zü®øÕâZÔâTõ#´È*÷Å[”ûGÑXd‘³dWüksþ$l¼sø)ênc|¿°0‚"Ø£ѯaúPsµ…Íj›Þ\m»sðîß©¶_qµ­ö‚ÕVísѸü)¿~Cú‡^cr»,£dL.1X]å·{=Êí2±kÉ#úœÔUùV¯Ç¹]&w-yLŸ'µG¯'¹¡otÜ=“ûJ{üFÑÿǹ¥¹Ž’'PÑXÃ#ËÃFåçŠïAç“/iÃ’<òƒ÷¬aÊ/Yï…Û‰÷Aൠ?ïï"}µ×ÓÜöÅO)Ý)]åMr¯gôõŒ¾¦uUvʽšè«‰Í½s¤wçB/´øièinæk4‘ÿŒ¢‡\‘A9àA FüœB‚õÙúl©øf–øEðW³D~Àb:ãtÎfÜbm•C”"/ÊÛxôë%/¶Ãïc|¦ð<‘ïù9DYb«I{‘;6tE9ûmR>äd#B-oë.Õªb!´Ìó™ê7ç›ï»ÑÈt¼ù>Ü€äÃû·ˆ1ª½ô[\4Oþ!+Úê•Eè’òiD5LÙ¿ó ã6Ò¿‹?Eƒ55™òâƒrÊ•粤’-^ñçhÐ…Dzºä’ ^ñQ4تg+©d£Wü%üfÏoJ%›¼¢o4²ÑÛQz=Ùä-ÚŸ¦B!ÞÓc£éñðˆ<7BMJÑQ§,þí\²Ù+þ¯j¸H\Üþ¨Ÿr0‘*Ü;,äruBX_zõ•*d1˜)bÅU*,É3ÐP¬0‹l¤Ñ@+#}i±Te!UÉbS0ÒD i–ØH°Òƶÿ6XHKm¤9Ò×¢DÁHó-¤@Zf#­Òj³t'ÜxÃHí¶†‘Jkd±Î*Þ ·X϶w}šn¤­àf;+'íÕÊgeËfÑîÒYYœ§ÏÐ-%p,[*}¥".ÉQ˜*Úá•Á£%m ½ «B›pµË^2y‘ODAçzÍÖœ‘ÀúÐU9ËŽ Lï(i#ÃV}"÷Ìâ:~Y¾7.ÌÕeËmi*moj7åo+ÝüïJÒ?þàG’¤ìh#É]¤]m$åi¥ÏáÐÓŠdꜧ"@çüúòr6tPîâ«›úœ™Ýµq -’ÝõñЏ#‡(U¦ MðFkú ÝÌ—}üq¸ûÅÀÃV`½xh6"1|; ˜{LãM1㛄EŠxʾOh# ­÷Ò”UÎÃâ¹R^ü\ÏþàgüLMr¯Få•’FªúpR²Û+Ê”hd³—x}>ú¼â´ÆBä‚rEäz¬à—µ…ﯘý§\IšÇJñ'Œ‹Ln‰sPѳ4 7«¯€zx’º(ê”ÄhÎ#ÚiŒBÜCfÃ?eã`‡¨ÆEìQÌqN˜‘ûù¡—*PAb¯B;¤&•þlÆ%¢á[Ê1:;Q!:)¸N‚{’½¤o²Ãv÷Å&ö0åkŽšõUÈø(a'îN稑¥¸;µ~/Áïj6Ø3ËÅryq¢æð…‡£oª«ÌŒFF§ñ®ó8UZ‹"„]½^¡§š©X1ê'J¯D¶¹Þ&²Å|Q T¥Ëðº€A»Ñ8é‘B­*°Ê]4}:Jp}³ËÝ%Å\Þ:ÊÍëÛe{@^åVÆÝë&t«Gg¨¦uÊ[TsK ]úÕrÄŠ¿ß­øDà¶…¼whs÷©·Sõà>𛆕`™Š#5•¥¯Ÿ˜p‡öHR¨nÔÃsÅ÷?4-—ªT}ÖÄ qRV;@Z}“&,>~ªP£]dÌ^ƒÔ”`¨Êè:–§á`IVûLidã ª»Á”¬ñAd¥š×­©ÌÈ$ò¥©jƒ<à5ÎÒBe:9Ë ÕjULG*ÁÒ¼@iž„ÖÀEOµ|žxž+•þŒŠ_Ó⊘A?âH~¦ 3OÛ¼ÅÛ¼bÿž£Ï¡)o÷o÷Š9ô»}ñEÌ…Üj¿<¬†bKQ2b>аÖó=«8§kUóa.| Œi­Š¾.ÃY^¨¬'gE¡ºAëÕŽRßz±AÅÁ,N‰Þç§ã»k[ˆfÚÛúVUlQ!B¸µŒú­˜º'ZË<ånS<»VÆv5OG‹îP}˜w1å•Ö2N˜6±lm%Cƒ0w2ÄñÔXѶ6’ØgŠf®ó%-ðPþß>`Žù–‚ÿ?ÿ3øƒm^ßb›½Yï¬ÆÇ>Q–CÍÖ?ìâHboô™z)h ‚*r¢‘}hÑM>S[) ʱ68ƒrÄਔÇg³s(b£˜ûs‹sx2æð11÷#æV&x•L0çm©2GŒ&€¦Õ˜œ(Ý’^1޽c`ØÙJI²½ÍN|ŸÈDxŠg1ì0Ór¢í2='Ú±‰2.ªùÇ~¯¨Î޵´Ó‡ºEˆ:Ÿ³5 ƒ4?§A>ßI†ë¤ÀYY¨ÎÏ ¸kQ¤N±0jc½bQí ©ƒ.ÎÁ.>áKÆ.Ÿm c7÷¾ 9›ƒ“1îy7ˆ©ËÁ$ÃYU¨œ'gu¡z!‡ë\$gìÛú¥q>'Ô!²*ºÑüZ×—:ÍÅtbq%'nÎÎ9¿’$ß÷1ÝÈAߺÜZF“ õà7sZvÌ[9¡S­Ñ7§y·Z+„ÛÚþb‰‡à¸š³]‡Ðô±Ö¹ó›š|¿HÂ?ü"üãø'Iø£­-ø§Íðšáï¥À‹Ò\³Ç—况ÄÜð[cZB–ð˜qoð¹ñ Rã×£ñ÷ú`ƃ{Þ¡dÏ;”#£™êÑóöÙ1£ˆ£˜Çs?Çì„€x2fiÙØ¦xTš›ûuXƒ|E.ŒÀþ¢É4[…øaŸâ0ßA¹'æZON&æ¢Ð2œk/*p®¿¨Â™Ò]ƒ3µ»>1WLÎÆˆ_¤úS¨KôK—ÄT áÚ÷š [ ϨϠlî/ft•~Ñ«^°Gçž=äâþy´«è*ÿ{¯y%èkVWå½Êó:ª%åô5»«ú§^ó:¶*H_sºjîU‘×±}I}ÍíªÔkP^ǯ• ¢¯y]uZ¯Áy(ùVøû0߬ü=Ü6´/+òY«Ÿè%ƒ‰x~WÇ0½×¼Ð¹ÌÈ§ÙøÛôþ^Íþ‰Z2„j»:';iIìêºéë5:/ø}ÚC÷ü¾R2šÂ–wußòõO¹£ß1仢«§Á×k,“v”á;6:0‰õUµ‘*êâ.ß®Ðtr—úÚÚBκBÎúBÎÐÚr~¢?¤¿;ÔÍ1²rþ+Î §xàˆÊ2¥Ò õ‡Žq˜¥Y4”;¨s,†Æþ…æž+Þs·¡Enf7?;~Ù¼ `RËv¸¹µXlô…:‡ô…0ÿ3GèíXØQ4)6PÎh·²YD¹Ì‹Q•ôvS‡ »ntÃþÎo‹În“{;ÜP`|ž Îp°“¸Fs :ÔII¯6B›õȃl>‡挅]•æƒúúÒ®êXäR¾Õé¤D)Eä Æ|!öX3öt3vUJlã96ÁLÄÎ8Ö9-uhžFgèQ~ ËÔ‹Ò” «9`š{ýÞ:ÎÀ µiNØ)Îéãa£Å>|¼Ù'ÎK}²àtë“ý¡Ü¡¬O |(ÇaÙ8»Æa­†–—¦9Ñò2œº|ÎÆBušSÔ8CÃòÚç@¾w¦³×°¼`·gW*–'f!(øUzèrú×ó5 <ØxÃXq11²óœ–!dî"}tQk…ÊfByÍ"‹&rÎj[QÚ¶!“W0ÇDÖz ú8ēΙä4«¸0ùSêK.ëã4}ôíãË ¦ÿ:+®X‘ütDêähÕÐU¸ù¡™ÐêI¦]õ9Bg W[w€\c}(V×;¹Þ̞؞&Q»ÄÓÃÊa©‰œ j"·ØL¾€ìãõ}‹â6“ÊöÛ‘´Ÿ‘‡̾ì€;ô©;R[ô4C;-úTÔ-L–¹`²î\Íu—&ü½¼ø ‘Ã_HóƒÁ7ð8_âT£7Õƒfªë(Õ£øéɽiIë±*"oL\â²Y^ú¤IÍDý2ˆD=‡óÛõ³É¤™ÙOçœ!|§³q›óftݲdWúBŸ qÁ‰…|3°ì}H ~ãkF;ⲓUXP¨/ò„ Š|voL˜ Ë›F‡¸Š< !CÈ1'¤Öf·Ê)ëä)I_ü$Ÿ’Å6ÊZÀnX½"½ø¤W|f} SœÝÀƒL[‘ì™ßÃò¾÷U¨¼Òß5³”ÙQB>±Ñî“%î!SYlb÷!ÿ|¥øx[ñÈúy¢­xì NAJYèÉǼESh†| ä¢S^I£|ßcLsµk~¬6`>¾Ê—\ík_Ç‘‚ë²ð|‚/ì²Vï Šã‹G­Íâ…Zu:Øß)¾xK?œrVeyö(k>GYžÍÇ4³›©ÉÓ >aŽIhÒˆyÍé&ÃçÛá‰Ö¾=ä³Ð* ?WHÅae.›S‹²Œ ¤%HÝ€3¸¸¶cWå€ì/P®ùå³(š©É“³ºÑ$4iÄææt“á[ìpJm;ÁzŸB3ÄÑ/.s¿û¶tÙ‡&ùþ¢§ñeÎs¯vÙ'>õÅâ`œ®úb pR×|ÄZA¸è:ýЋ»Å ÷)šªýY¦lÞEÕóô3-eyf¶˜™Ý‘:æ;|NÕÚ!ÑEÙ½([,ÎŽ™Änàý¼M¶4I¶4[,³ÉâØ#ž²ÉV$ÉVd‹•6Ù6¶ÉV'ÉVg‹56YdŸøUÕø¼c]’l]68{y]¶XßL/>Šmèuc’|c¶Ød£êYuk’l+¡*”·f‹m-Põœº#I¾#[ì´Qõ¼Ïá€z "3m?RÃÁöcekÎØÎ uVáø’çö[ú8¶sñ . ÿ ±ˆXÑ4ašº¸àS uOë“¶²µ4™ñäÉŒ§Lfh}„]™Ay1ÏAþB?‹îxî´k)+¼'åëP+}*ÛG¢J1mhõI¨àG å 2î²£‘ëÞøøy±ùÈöD¹ÄÇr­¹Ñ9Ê‘Bi«,¶Ë ÍÃcT>\{»­ëíëéÑÈo`M[]·Ã÷!|¿~1þ©~á‡ÍðÉð«vxá13üf2üšž@øQ3¼)~ݯCx½~+~Ã?ð“fxC2ü3çó£O,Û#TÍ»^Ùzb{Ó&8‚ DPÑ’à–Âe\1S¸í ¬ã|*Û¡pÓV÷ñW¤«¸T] Ù(¹M¬&šCøLkPD ƒa°5B5|æ…5¨Fût8 _ŒP¢‘sd·}¦É& ¨â—ÑB©J`ŸêœWLR¢•’K^1™~È%—½b ®ÏîØùÆSLQ­p¾Ï%k殌}ÁÊWä<’»gG\…€ÕfÄóɈ÷íìlâìÄ ¥M¸ä¢ìœ÷âa¥™íÉìì@vø [ä»ÜÑ’…Ø­ ² çÔ‹ÊnE쵊´O¡ÑKXû=¼â`óP“M‰=äœT0ÛzJÁÁÿ1؉\ñšzã…ÒY¶49ã…/dÛ¡ªå §å@‡ÂE ;ËaÄxšW`ëÓ#sò>â+0ú9+ï£â’céx‹.Òµ—ÏÎë!>å_—²©jÙuzUwà?E>¶ž# ‰®"à j®Ì2¾d‰º¤2•f³B¹LŽN,Ô¾ÓO¹JUrÕ+âÆã© W‰K›Q*†,Á=³&#`ŠŠUévÀœ¤m’ÏÐÔ¢ `…ŠÑýç™ÍÛ°]Eña,؈" ¦¢~¡Ô<³ù– ‘´Ù•PaQ$F30´˜Û1Ï æYµåó5„ɘçUq1iʾ¬&'É4^A ”gš:ó(Æ}@=$¨þif‹Íë$n+â*—-Ž™Ú±†à!è0-kvj¬¥-cUØÙ…X£5L€PWnx\ÒŒØ8MTi”í‹(ð`;&™ªaêƒ.òL]×ô©ÜsçkÖ eë»ÉËÈ9Z¨,'çX¡ºBµZ´s`ZšŒ‡ µ?ƒX¤ñƒŒbAN \ñ$ÏêÄròšæí[/VhÑx`FšŒù•Zò*†«4ܱU¤Å ½^ðÕ˜ÀMÕ!7<{¾†«©¡™˜Û˜iØT»A›µhhp^ oHBxÍ[ uX& y¶ù7¦Y”H0Òv2šŒÈ-p>YîKxkñ2ebtª8‘Vƒ©q„]×|CÃ!ÎLS "4$3Ø ‰F´­ì·‘«J;ò=D†^TÈ£ìÈO’‘Ÿhx^7ð‘GÛ‘ûAwj=id9M;r…nE®ÐÅ`"û0oîÆr}05‘Gé¡!T¹>BåysÌ:Çu û¸$Ô8/:‰Ü¬åò¼Ùkz"«2›W-Ø&BUb.Ì3k^µÆ37Å,ÌÕ£f(óó€1!Zõz0ÌÉ^/é òÄw䥺Xʈԛ–éñ˜õR5nŽBóYÈrýÛbô¸p%'fB-Üï™eÀQ_–6ê¼G€C{87ÞRá|ö–¶Q[uëAwd²·Qš—½ñ¥IŸ—¼qÚN-ê!vp@¢EvÉ‹ ìÌ€bÞœd$³½ž¥B²åcÎõRJa|šDÐiܾÍЦ øe(ï ¢™næbµåžÓ3U—¦Ïç]Â:üsà ¨“؉Bi£Á5·/ ËU¥œ7pÛ§^4°Ri—¸RõË.$Œ+|ëí¸JÎ'…Îk¬Æ€éJê$¹„Ö¡..ã‹«ÑÀ«7ˆÓý [ú+°3ªÔ" Ù¥¯—¾õØ\]§_ϼYƒw¦Ðõ™!>ã°äÒͲFnqÓ½ ¯P€OÃø`ô°;0Ï|5߉ÌÀàV*û‘`É·ÇÐeÜeÊË4›Çq¬ðaWçŸè‘šŠæÂèx’ÈÕ6±æ`Í MFË5NJú9´IÅŠó’þŽDçâGmÄòÅv³Â\£ÖI¿‚¢WuwfU¹<˜òªw¨C v$¹\<™Â_Q(ŒðÔ¶ÒâÚ  a‹"MŒpPñßÚÿgìKà£:޼ç]óf43Os qØÈ2VÀ&Äñb0v¬QÇQˆ×k%Ÿ³Ž³‰ˆxÊ*Êádר$»ùvWˆË\67æ0Hæ·07Ä}Ï÷ 6£æ0lÐWÿê7#ÉÉ~»¿Ÿ4ý^¿>ª«»««º»ªVçF›°ÅÛcbŒYÒËöؾ$ËÎw(‘­ÃÛ×”æ:l¿HÚž¢Y*tšÉ!lxµDêÕHM.Èß5mÃaE‚Žj]¬ì>€í{(×ÉwBÁ ›5Õ!Üâx ƒv–ôÄÓÝ5Ëdê„àT¾:‡‚ÓùZ)æ˜ï3ÏL$Ó3Oñ@‹M¢ë(wTØfò ÞwmRÅÖšb…™²1‚¥XÙ ÿ›Á ù^º á¬á×{’ô˜˜G¯€ô„K=W–zÙ„Éîe wŽº†ÁÕ\î¡#˜ÒÓXoŠõ¦”MNùq?Oì5½‰ý„£p?\¸3c]K3¨ß7•úì Û×÷’ßãódˆ¸ 1•þ˜'H˜ 3¬/Zo¿—Mƒè½l%7ò ôí™|÷aS6˜‰Pܰâˆi›|; úlœ{ŠWee°“Â)98šwÝÎæ›LØäð\d?Bˆ¬‰>ѯVÞ f‚-ÕÓœºˆAcªžnž€áõ´sBøÈ´½l8ôú"n{K‚C‹&ø5qÙLoþ_1“¶›7ÿ?5ÙªÒU3ÁÃϡꃿ'‚v =8;„}¢#¼n óB-–é’k˜<¹&O.L驤à\¾>Ê+Fz[ ]£¼PÅ3‚C¸©çóq^1ΛˆŽñ+ÐPφJ™ó„1–;X¼l҆Ϲ'»ŽA6Wçå1‘hçtcRó鯻éÓÉ^nào«ö§¾'O8æ„Ü:LS çx Ös¸] "És¼bž·øíì$ö×Óø@Ýôš&ŽzO¦4%Ëšƒ'dJµ¹Ç^Sƒ“a®É G§ÇŠýÃÿ—ÒŸ÷:(驤;áX•k¿¥Mâ#Y¨^ !NvËŽwD2 *ľl;X—d»ÒeœÃL ¡Uב€VþÀÕ\JÐ59Ç¥vwMÉqi8_Ô»º¦æ¸Œ°ß?2Çåîä÷¿›ã2sMËqy2\ï帼\Ós\Ý\3r\¾v®ª—¿ÌUã üÚ5/¤¦xýÛ<.ï+®Û^DRîPðq¾z&Œóµ/½l,éžWÜñÆyá©wiv9SáKoŒ­ú’Øå•ƒ•g¥!š¼D;VÝmc)ÔdB&q/Ûyð­É7íüÄë}͵&ƒ˜¼¯)NöRTw×T>¬#8–olÄq`¾{ŽóÍ8—ó=I¶òä=CÁ•üŒ³¸·è»˜!Öe0?ÊÌçú b>7f4¯¬n±-#ž¨‘ÁvÇ«w O¢² ’ë¡&Ž‹ ˆ(bWF*öe” ÌŽ£Pñ[¢Áû3lØT‘™e{ýq\aûåÐÊö'jØ€ÖJÖ[Ä3øþdÅDc“ég¯8D_sÛ@ý»!£ø·/üÖÅEæŠl³ïqéB§TE1?Qwzˆ÷Ýë§è!ÑwŸ_œÉpf qMg3bDš k°§äç2b0ºÉz‹>6üt|bÀöT–ZÁ,Ü\³ìÀ#èñ ,Iù‹öûJÔÝ „Î45y,O@4fØlÛYÐ_¼žÁÜè‚çkºq7Àƒ(ƒïífÒ0·"»4”[ñcXˆz ÖZž(ÅuÈ,JϦ‡¶¹¯—¶{´´==wÀ×ðó ½uD†zx1¹x{?(êúÏc™ê6õó§ù ‚c_SoóØÑnËÑr›‡‚`tÈ}—ÇŽù%Wó=÷)¸×Ã[ákTó3*)ù¾Á\Ë÷õa@†ùÄÝŒ'º’•Ç¿l1t<â~F²t¬™ÕΕ>i?j°/Õ¡~1Ôàb‡VðßÙšÕõ|ë}6+ž9½3›õ:\]†MÌ 7çÞýX_-a¾àw4Wp*úZ’]+y2<-;,ùR+»! ‹-„Wö N¥âçöMó‰I>; 5âÞMÃS¹”¡è1DÃÀöVn%á†úJ¼ç³Ãá|v#?<Ã'føŠ³ÃÄÅadƒžfÐÓ z •m ÒÏöà éè`QEõÙyL Ðgù‚ƒU¸„âFÙ7|°(^ݯ4SÌóIóú6fª÷ãkhˆêׯ4(j|’Á$Žä©vЇ_è‹Ç®J+[1?´7ó#‹©éŸå·Yê‹}1< ÚP7iõ^01þÄR† 4[´ÜGün;‹æ1½ÔW—egÙm`·ˆ¤êà&¶¸•ŸµŠŠ½Ÿ½ž‚ÏóÛn àN~»­ÜÍo¿‚/ò;l÷‰UÀ+›qÁøë}vvÙ_¿Ò¶b=–¼ÎÜøëC1æå5M>»­Ý®ìœ¯ ‰6ûìv­‰)&TO ÒV]íÅ61xm¥³çm SÄöt÷>ÜÏìÏ—ùì'Èîå?ó‰=_f{ÿ»Ù÷ÿï‘ý«Š°Ú1øm®û~~Ç„O$|öƒvGHšÊâ ÏÎ)#:ÙÞ‚EÙzù†6ñÙØò’CÌW×Ñîh?ô¯„°ë³ƒ˜d»|Tg‡¬.uÒg[| ýTºÅ–8ã‹Q–Ý^J#D kI|9ëƒð)>r ‰Bô¬¿|Ù$u»t+álORÒþ®àhÃýŠª4ÃU¢¥c &ÓüŒè6âó'ñ"É3ØÁŽÃ_ë^È÷|v®Ë:9Œö‡Å}Œp¿#-ÎuþÔ¼ŠüŠn~»SÙ¾ ûaúiÁa0e)ZÙÁì 7úÚü½çþ£ü¶‰ûŸGÚðe™"ÙÞI‘l 1ÅîG¶ý²Ø‰-‹"39ß«q‹`zëbgÈÛs ¾Áð¾?f“¼âC³¹çùm˹1`[ާÖ¦ªŒvZà °ò¯ob!e´ìGRS}¿îûÎÄ&Ê–‘à+³Œ>RëµÈš'³~@Yv^*k­¿.Ï㩬kpBP2ƒºq%Éu~ÉÓÝÏ+ ð]¦uÄßí¥ Xý°ºŽ¹ Áñ¯éNö2Tww#¨{ÖÜàÇ2æÙHÁ ¨w³MÆv?nDùvøÅJn¯x‘V£~Û“Ú’ñŠÍ„&>Š‡Í«Âyƒ8‰ Qç·3ØÔÏÿÄ¢l™ö­R»¸¤þ©YÉñô‡’Áñ-ÿn¿ØíO3BÃL´Hì!d9Û‡„†) ýLUø6±ØK¯à‚ƒMþÊÒÌà÷ÀddÚ˜ ŸˆûmŸckˆ(Áëë\´8 Š¤¿øì8Y®àøpyұçƒ^è;Ùn*µ{¦ª%–$Óc ¾â°0¤{uC0;yÊýB£K©ûQV,f]§³ ‚ÁQõ C¢ÚYb˜ü¬9t1®ý%í¸¥û2]…£Û*ìß겟ĿÕÎgÙ‚ObjÖ÷Ô¯SIC£Æ ¿¸îÓ åc“fƒXRkÒïÓ}Óü5û3|ßpâ_I—H§ëаåBä°`)¹˜Q6!«¦?1¬wü¶; ]³{4…a!F 0 ‡þØ!à#”õ'!A¢U15Ä[5¡ ø3ôú—_wϤQ;ÿëæû13€óů[Kâïµ,쪰zà<0f5•]ÀÐ.\,Äÿ )_E¹Y ˆ† ‘µF¶hh OU¸.›wÖˆµ}&g…¼¹º±‘åߺÛB, Ò¨c«¤ô¡æ8é?»KiÛ.¥íÀ“¶ïv3\úÀ£¥>ZÚñÑÒœGKb޲³õk ‚ã_Sù-_C@%‚Ñ!Á•|7‚·¢æö¸$Ï †E½;)ÍØEÁˆ¨ï #£þCŒŠ®SðvÔºÛÍÀŽ@Ê›Wì `ô%ÒkÌ®­1ïø]Òò>­â8/}{Íglñ„Ôkó‹C6ÂHC¤pEÀÀ¾à±€í–µFZxŒÛÂóí• $“u£|¢C>¯êBâRÀÙAPÐãDA¯R’ÞâzÀöç5EpzçV|Ðúc¾KZäoÎÔ×@믙âó·ÇìÌþá¿Ç ½ša5*c¢á‘ŒFFS0.Úf ã£Yc)˜Íž`‰V6OGZ‰dDúgSýˆ£mÙþ~Ä5Žá0KŒå0[L°¨¾Ò¶òŒ` •41Ú¶Ú¢';lGªPÚ4 6P¹k²Eµeg§Ïn |;1‹¿‚`':íì¶Ô70H8Ç¢äap¨¼æË,ï[`Ú¡ó);`\Àa–XhÙíÛÓTB-”äü÷e­l.kSÆ:äËêD<ð?±q·h»M–Ød¥‡öb3±[¥‘*»}Y<%…È.H$Ià%®i‹{-´XüU•[){Ç£PûÂÍA²-HÍÞƒÁ7©gûí„Ów£vXb;%m>räâywP¼Ô€y@ì´ìáõ‹ÜvSÖ{¹îµÄnd=auP챈ÿó‚xy‰½øvß:Š}òÛ ˆÝ±·- QÒÝÜŽq*éËÜœ¤%âH Íbe25ñ;9|!5‰oP„ ¾î ü68b?T+¨PE9 @§úã…ïnü‰f|Ÿ¦G˜Åéaݘʄì#‹íV3c¢ôA19ª UŒŒj†Gu•HÌEp%ßD@DéS¢ÞOdäe ¦F3>§`ZÔ÷ïEýM|Ú=°)±µv̺LqÉj&KŸX)ý§ŠÀyŒEÔ×ê M…%„Eb‰’׬$¶®[v¨_ƒ¸iIbõ™ÕL¬>·âIGÿÐ'¾° ’+ßü¢‰Ï% dºàÆb@¦íN_¸eº•l%îý;¸ÖLl£ƒ€s€A$¡X‘ \b°óêèj©ÕÖáMð—C3í@IufY2›Ý\ £<Ì\ÀšÇQˆð°>¸Ü·QA›ÖËÃ¥è UÕèö„™Eñ;ꙬY”›u[¦¤ ´ ªvÉê{i("ØTœÑ¢R‚±ª¹lQVÿ-àw–ü0#õ‹~ßÁB[— ðù1 }4N« ·WRÈØGÈ ?C…,ØŸšÿï3‹åȘávÕÊÙ+šáÿŒf¶ì¹°²*“gv†¸=ˆ]#c©=^‚\ ÈlCê Òó×jnì¦Ìf;³–ØœÙríÌ[2íÌÐ/¡Â™Èsù!Olç$RQ†øÑlóe&œ«`™ÐMØ)Sl‘)Ä.*'+v&HO{0ß%ã– ¦ùÉ×;÷f¦¿Ò²—È´ƒH°(m0éÄ,y°&ü|V¤ñEýW›¦GÂÿ,7rÙÒí±tAlñx ‹ô™ËAãÉVÑßôÎä/ùðuÑ:ÿ¹Vs­È¡U4ågT_ÎdÓKB·n¬çSšë™à¶¼Ð“} z²ã{¹®õ˜U$RofŠ›™Î~dƒ¨ Æã|9ºŸuVâ7Üa„jL„û€¤l|RÊê ú[A14ØêÜù­ xIJ ¬ca]XaDÂţ³qeð×I&“eP)ƒfÑèlSŒÀ5õ¥!O†nlåVì :ª&»‚,ž! ñ ‰gH:„û­‰Æ†`m¤™”¶Áy¸PçÒ œì6*s£‘I!1 @Œ“P´ï†ì6Ätþ ÎâCð‹Õb í ‹ü‰iˆoÓjmÍN9ÑŽ¡øæC¢Šªña¢mæW’³'¢ÙNâ9œø}$ C-Ž,±(#Àìô­f -GZÈKBv&¯€l–z%¦ÏÛµ!Z,¥CÆ!;Ô_2Üœ´$Ó5ô Z³’¾OtöðZ}—Vã3³>”(›]x’X F}cç5ÎÆzkTM o†çEÛl‰Í”w|*o–¨ ñv¸…ýpX™Þ²#ŽóÝ`Æí¸j^-2ÄmªÎΨNÒ?/¦³Ý矡 `ï÷ò}_†øÀÏÇÛqVpy«3¿û4œí8¿¨Û’¯¥uÊY¯È(°›©%»2LB:Cûk. Û¦C¸p5h(¥'Þ1NÿKåÎ63”qú_Ì­{+L-fw¢#‘ô %=Ø"é J:ÈI: IÅ;aB5’Ï;’ãÃìNbß¼ÁºŽóÂr x•EQ×¼p£²8ª hÌWT>¬!ÒTD –DÝ Ã¢†O)Ýb!vŽÌ`HÅQÆø^æÒ°XJm5»n*5%òˆÚpÚNظ„—}I?NGWÑK,6ªõø²ßùò!!^».l»syO|+E¡Öà,v5—º ÇÅa¹ö勺Â>Ôc©ÅЉ1¿Œvz«&Ì— ÃlämW^Óá¿Ãl sY\È¢tN®ý×EA(:ôWE‰zDy$ÃÏ·^Ž…45!ÎO5g=v–ÂÍ…5Ã?]2€?Ù~§þs²Ò}ŒÖ* ð_sY\È¢Öànº(ÀÿÑ_%>–ð³ôÂðš†ÿª¿¸Æ=¿ XEäfúû"':ëì½&q+ ãvÌ€]evòNع'Ì$‘#¢Ú9_„ÅaÎnq/œLDþ“êi Û†cm!µ]§·Xĺ†r±ÊUDd*ÞÔ³¾šJ^A"ˆm¹ˆá<¹2Bâsn¾!F32é° n1,B,F“³˜ÄI ¤ä‘ôÖv{‹Q”Œ&ÝÊÔ€þ…u)"N³ÇD•ÛÏ(F‡Ô11."7ÆGš7&Bå³E£¤ºgªÙ¡РDËö¤¿Sƒaάù"ÿ”¼.Fp‰>¬©Šbü2ö>ý´xvŽ4XûÏË{±f@¤xŽew,ÿ-¢æ¶)~߉*íX÷#n[›â¹9)Ã]?£¿W[¼õüq3, ­ 5;Z^ËW»\»WYó ¾—ëª.„/y¢ÇËæåHµ@å ‚qßÿ;¤¿™JSoT&«ÊM]Ü–ÙhÈÅeósØÓm¼²$k(å\‚ë³¶È™O­ŽBé²— ×Ä· ’ !ØuŸ¤"Ás YͲÒ^é'ôt=‡[ ý6…Ô4*Ë¢Zo6aõCñ|"¯‰-Ù}¿d¤Ù¯^ü øˆ:áˆO-i?´¢}ƒø!¬X8>ç¿û­ÒÙ¼[¼Iᜯš=l/’D#Ge¨â‡°Z+[Èz±©Iü—O? †{#è—Aìïþ½05íú%LM+ô{éQ•~ï<¢õmT&=©—IƯEߨ÷O{]°XZšBׯ$ºÊâÑ~‹nðÜë Êý›F¥6jþ¶QöüNü†¸àt~‹Õ˜ïü;¥ÈWnv” þž {lo²ð´W«Bå¯A&´=Õ|¹êÉæ{F%¥µxÁìµÄ"¾©óG[Or®_Ó²¨9Eèg„›eÓui6î—›?3n•-ϺþÌ‚ä_Ä¿Çâ/1ñèoç8SÿCüG,!ÛÓ þ3Ù¥ˆ“Ô© Fü˜ ƒ²ä&¹Qö(K¾¥Ä^kº`>XfŽT›9Õ·‘ REµ‚R>4·â ܘà¥t>V¶:ðŠBÑ|£wU p^WÅ022Lš š¥ -mr+ž‡E® ϸf)ÊŠ¨²TáÔ²½à<.—‡ÍR%VѾ^Ô*îñJêÉgb“ܶñ#>P’%Yµ|p=–Öb¤‹µœ)õ‡õJ¢äÅZ^w6*l¡ÅmRû^ö‰ÍÐì]À‚Gú*äùÚ®!&¸%¯×²”²UIvî» GlS Ïø/ÎJf)Ȅ儔-Xþ3æÇáÚ.EìRØ4š)vËYL@ÙCoû÷‰½ü@Pìo†1Þ câ«°% 5ƒ!çgìkƒ’Ì@.=¬×ä”|ê¶2Z|»}6ÿ_Q «Û©/Ôä(a²»Û­»ßäq{ q½%$íTRÿÀªø”;šznkHM÷´jáG³” Å¢¿\_P·}ú´r‚+O«•°Œ¼ãh 6)‰Éiê-*Õ”ÎQ¨€·‡§f=74î^ªqr×ïÆˆëw(øÓTûèܾJ] й}ãœVê_ià–¿ÕÀºlà ؤÅ7ÂŽ-Ú7~ŒßÒÿ—íÛò·Û·7¤kW4Rw\jdˆ•·uñ¶N3WN'ñŽž€„ˆ'b¸ÏY]ø¹¯…›í}!øŸÿÊÇåìzÖ5Ngîn’.&èñ_ž«pC&ê{‹I:½Žº“uÉãÅ ïúdŠ)2EŠÏ;Jm¦w¡Jö‡àË»*™Ë•Ð’=ªðQe.”ßa´9ÉâT’Å2Éb],G’ó$Y-ïµ\v¼9öCÄnÖ¡ïšé†áþO^‘RÅm£â>ë¥lÓEBwŽúê¹w¹‡Ùe¢R•çJë ñ6Íq=´'^QËWÄ =–[¾: Né±® TĦR=ië}×<ºG§õD,^vÁWtÖ§Š39É ã3ãcÝÑíùXŸ8ç­è¸$ò~|½ù±°ZÃCF[ý›Û7^:u-õ€Xyñã¨t¶…+Ô¬R\­±pÅ>·¢}ê¶Ó¸bŸ‹+ö^8D]u'2·>ª ØÕCE°!ªM†ò³ú >ŒS)ØuÇ(Ø5ãlŽzÐç=§áŒCPÀîåk ÎÅà©»Dp×/ïi1É(~»#8Àº(ñ}JáÛ‰ï›l8N°A*§açÌì™D¦JæÚãVDØ*Y’™j´JÒ¯U’~ØŸ˜nÄþžØ½ÖÃ_E€ÍüV ÚÕà­à¬s ™Xï±’Ûá²ÏÛÙ; Z4ÎÔáËØâ7ªÙó ;›ç*:CݹÀC¦ Z¶ÐÃ`‘!åìà߃U2x å)4vT±Üˆu-Í¢,›K³í,;c$Û“}zYNS>0bÈ“ç"Ê‚òV¢\fkŒÄæz1‹š•õM¢uÚËCS¶)ÙŠš²ÍHµÁª.:ïSÄv¸¨3ä ŒQæÝFñ}ܱ±Fw.ºïÓÄ^£¸ÂO‚‹Ue[E~xÆ®¦h@•¬,Í6@´!¨ÁÀ"q/j7ÄÃöóŠ~Ô®ThbÅÓ³máôl×ÃO »/8ž²ŠSFñŒlÜÔ,œ‘ Q>Cœ6ìŒp?ôÐÖhæYCœ¥÷²Ó> SqΰƒaMÛggfýŠö£{vVè!»0áÌ7¼ ݲ3zÇ-Þq3Á£ÝÜ™{0ÜÆrUÜ ÛK¬:,{{l¯…Ü·ãÝr%c('¸á…nu ø#¬n‡Ìâ0p’[NÁâ ©xŠ;Æ‚tI3XpWS‚ûê€l¦ÃT·œnï¹9µ©õœšî¦Ü4¤ÃUÒuÓ¡ôÄZàNM,*k®[r( *a¡[Ω°œR‹ÜÅM>Û]ØäS@jÅb·aÅþ%îâ\;R˜«°‹r”ô¶©ˆe»ßEµµÿvW¸™VÝnÇ·zÎIí ¦UËRm"é-8ÍÙ¬q‹5îâs^çjD±Öm·É ó)à`ðÌ›Œ4\}Á"\ÿvõ²0¾¶6R\iœîê\y•Dë8dÈaÃh}p­ë³Ûಠó›ô¶™bcTµíËS`èár».E“ºHÂ×í¡ÎšhI;çvçsnqÁÞiˆóNÃE7¬dN§3Rßu;Âå]û•»nñ%A—÷ØfD34/!ùhÓ)|´É©cá2–š ŠR—±$„aê7©·§ÅÔ›hÆEûiêO2Åa†¢Šo:P̧b÷F•Sª ;ÙBz&…e® OñóÉÂç[D‹ZYßòP‰àœ…tÓpײL=ÒÓB¦–»R‡;»Fz(xVA0 ¬¾ío{Òõ;ždóÅ^Þ¬X>ËΤ{hc=b¬'–L Óã<ŽðüÆ¡àZO’Q}2•zX5˜ìá¯,æòÒ3…"à ‘A@KüÔÖ)Üb,‹ØFuÕõb†§Y¢vÄå㾉|ÄSEP$¡ _Ýb¦§N³= /ïsÏñ»a‹©%¸ dmÒ_J\”yhe97³VÖ‡TwjϽ–‘nx¸2-†/ü†«–±¦|èx⹬ô¸ÒÃ{çº³Ú¨Šªk`*=ª­õˆ5pÛå¡rÄZORºŸëna™@ë0˜ÂwTªèE»ŸÈ¶D×Ó×Á‡Ä‡H8çHú&ØäI3\†Ø o³E×i<ÔÑñ0ÒòÎ Ž=’íÚÂö¿KœòfÎe_‰]š&¹T!p²ËƒÄìÅ/¡Ð½@ΉFÂKàæ@j`±™ÞÔØÏžRÈ÷ˆ¸›—_s€Õ’‘lÙy 5Ò¢§žK¦°zTs2”òK}³xQNÚÿmYÇŽåí Ÿ4§BÍžPNqu›¹×f‡¥ûÛ =áþvJOŽlã‰ïã\¨‡RgBp÷àø¤Ô]aó“á:ÁmXä/NÕמþ^ý5ÎÒJñuž 5{=‚+Oßµ†¨èLò]WˆwBªfz~‚¸Ç™¢ð¡Äãâ ç8¢G¬ì¾v‡x =%žBŸ¶Á‚Û _…Gmª'úž xTŽƒ>kNu©Î:©6·Ju«¹’ Hu&UQÉíæì—ðáÎ~ZVr:•ýóæTŸ"ÕU'ÕæV©î4WÒ„TÜÃ0úÙü­tŽ¥ øð¶×ña<›»œ×Ë5^“ø{<ò2oqã™W‚)ü˜Ûw‚›žñò†›õ¤¯àE¦óc _gh1vaW­1ùÊL~Œó(b6[m†i`ZC êÓ½¦:m]Ï0­íáZ¯‰©ÆÎE÷Ùï‡ Ó㽪"YtŲÜ5Å׺ê4’ãŸU#†U[¹ŠŠÇ‰ýä§xä1•Ç£ÚJs"ªïÔÄkÖ°UPZ㓟®p®‰zÄN¤ŠóE‡¿ñÝ{¸üðó 4#ž4öcª.©P㯶»ë¦R7“ø"ñ4™Q}Dâ±%™àD¹E{a‡€íú€hÅŸ‡ù1ÆŸi´ˆ‡¡nq\‹9#íÛI椆ùÜsŠ:gåÉ ø ì%-Ág·ŸÐ·Kký\Ñ’¹mù)E~B½Ù¼ÓÄU½Þ\Þ"¼¥û·´8<*à®HIöÐÎE'ƒ 6<+”Ð×)nh°ÏsˆºòdÔuCŸiü|rK+¾ëûNS¨è®iÅmÔ1 ¬ÑÐxïØ÷ez4»I+nôÅr™W¨ÀÖe%ª›z‚gžŽ,óôxÙ%_ÉÒÀ>Ërâ}—åtî †UÍë+@¢9zÊÿíé¨2G‡]œ,˜b7¸§¢®9:•Ð*Ã)ÐæÃŽÚÛ¥.Í›e9.5Ë5ˆ«ïÄÕ¯çê×ëp¾]²<¸+©Ía<¨}0×þ"Ò¬I×~&ª¬Ñ¥žTíûŸv­!&b-Ë×T*° Jò!Ër†¥–`yÂ5¤,1†%F°Ôe”¬ø+X†6ò/ ˹¨²ï+°œºöéâ@+Xb Ë4,ñ,+ZÀòV³;€ï‡°Ý]Ï›àÃ8ÖbRK±ÝGqycxX7<` AiuyÐÕ¨ì~ÖuBÇ&©‚`ϳê ÚeG¡Eù ̬óQíŒ.Î`“ë(É%p=Ýü?^ûaì—=`õ™óØ"?À»­WW• ˆ 2*Á/uh?‚‡ÿ¦W`ß5Wu$Ìsñ5ÈFKÅ^דéU¦>Ð? Û77u&-‰¢óf^ã‰./Ý÷i,^|Ž×$^Å ÞaßÇÑî{¼ï>á×=]4Q2cm@T’Œ0Нûr™›¯„uÏ‘a,®S_0ùÚ¥—D@ìïe·á7yƒòYe„ÁWEFb„“Ë¢ßY‰Ôà[ÿz1TSG¾ÊRf½8ÌÌÁ‘QF²$k(Á]$ì‘FwC‡ÁN¬ÃbŒ‘àY<·b¼“]=*¬RWwˆS Dy[å4h–ë\ØPBŸ¡›‹&½öP“39_n`¼ëâÓ®åT<£ øäiÁçOiË ±’ ŸÀ­xCŽ &dk Ùoë î·àÜd1x€àŠ]£r!ªo6ؾë±U!ê87ÞªâÕˆØb$lƒe­FÛœ"·°ÛOeâš@‹lŽÄwñDU:ε‡2ʸjdCÔþVQ"Ù\ ÑkÎû®0íæ¤8l0Å?zÄ+YtÁ£‰c”îB°ìHÛÂĬãïq#V|!(#»t¡z^¸t5yq~' âY ø›§ô¤ëœÁfÎ.â‚Q¼) Ïâp6JýJã5QxÓG2\ÜÚúFsÝPÆÕTWe¢U׌‰0nvS×þ™vòÆXí.%ý´‚àbTEðQTCð1-Ân±›VÂã#Ñ+®óÆ^¨ó*åÇb/q4‰Š® ±[ucy"1` \Ç;OºÜâˆ,’ïQ7 Íc2w!!†“›3]LvÑ->nÎtÉÝ¥7›ùD¦¼2> ž›×›©L7eknÊÖÜt‹[²èGÝvÿ@ÜI]t“§»xBsÝM§˜¦l¦ëbRÝCMY÷g\÷Ä08£^,Ó˜Î1ÝÛÒXæ-ÇLÒ3VÜû…Þ.ÌÆ±ÏíûAŽ+…“Â*ÑÙiL7&òþ^Ûz8QrUK‘3Mñ® æ7ÏÅÖÂ&›„³©²ôièÏe+s°ŽÓätÓáöÌ.‡ÄL“D}IHt>€µõ$Ñ‘z1ÛL€ŽôËSØ9fg¤î®k¡#DNp09·0ß ^w “‚…ÜÌÏžr-”"¸õ”ŠàöS‚ÏŸÒÜyÊXhŠ%¨£–IÒRY]œ9…妣Vk²$Sj:R…—!Ux<&¤™LÜ]X"LÇåŽv s·+M(I–ŠFxªÕ&‹ Ã].¹7¿‘ßE·-El2]ŠVå(b³ü }ÄΟXkÆKaiÓ9Õ3;È^OAIÔt¶Ïe¤Â¶ž?äÈ{©H7f _’§ñ­0Íc>0¯©IÑÔ$ÿæÁÒ:zr8Í['Lø² ÈN€·žÂÃî|8̨½u6ÅQ“H5ÿ2OåQö(ÒœL²“¦8m2/ëäg̸ÂE†iœá/,˜Ò÷Á§¦³Nÿ’ïø=ëj4yT»´rN¥\­*«úÂ,àç|.ÇâéÑÀh/ƽç†ë&\ì9¾a:‹ð-Àð·80ŒõP‹ÇÁr«ÃÃß°EPIÆÂ°2ÍXø)K=ga¼å$šä¡åì~Vb ”˧zbÅñÀ ñIÅ$úð—x_’ž§{ŠÇ˜¼Q3;V3!ù(&—_ÿ´k¶GÌ–0Y¦ÂƒW…%²*¬Cbާ$«d'Ž=XH«Dh^C!‹=N7,ö`º*ËDÕ•±”Šˆ•`ßy°pÛC¶¹”M1¿{?VŠW·Þãz‘þ^ýmGÞçò"É oñçÎþo:–Ç™EnBAóÂÍ×òç‡uÅpw¿v+,¾K <+î•›ûB/µ|°%¾‡ çÖC,ñ}çq¨% )ë‚°¼žJYHYÿ¾äÉÂhÕ„qÉ£=>¼<ÎÑ\/‰•</:QÄa‡(l†ûu¤xÙ¼_nTÖtRè÷rX¥ßu=´—Å+}Öéñ<$×òuºøiŸõD3Ë×ëâUb:ò\¶þR\×ÅÏceCS¾Þ©ú–%Šc]ʇY¢O¬dà®s—·Ä/©êE´¬jÛqäksÕ6*Umñ«>«I˜‘ƒ§|µ.þ¹ÏâW[å{tQkv+ÿ;T5¯Óþ~R×`œ"ì1 ÷L¥ÿ –½Ü–' ;zºþ¥QÙÙS¡ßËQõuñzÉX½ìœVÑ£A¼O[‚n•|¡•à0Ä☷,Ô[6¡CÍÄ”0Ìšþ7¼·;kýI„é©ÿ‰D—žÆŸEÿ’zÙ ªb—ÚFõâßl½¬ŽØp ËÓ_h…Ù¥î”fÜÿ/½×K&èU…;<¬áòŸÅ·ô$›nIôâ— €VuÑ-Ý”h¯Äh†È¨HìR¼6X‰Á†Ss? ÁÒ%mªa)?ZÃpÅ=.Ý, ãPt®‚£R F)â%é´®ˆ1Jɽ¤JÃê¾Gð\RÊ*äNÝøÔ%)šê…ï-bÍGX0*> ÀްØ9=:ð]°³Ä*&+Íø`Ÿc 7³ø]+N%ÁIÈ»–*½*Å×u”~]‡ .(˜ó|ȼ|/¿J)Y ¡syó<™ƒø÷©È± µŒvø0WqÎ\¾h/kQ‰+8Áß!AM 5 œpÅ_:CÕ.æ’r#—PdÑX"KËa“&ØYké\þë»4< ‰÷r×*ö¦l…§­’}z© LO¼§#GCM˜O•æ÷T×)bR2Q—ú׎ŠQƒX¯”ô¢,ô¡dµ^v–h=Ü ÑËêµ7Ù=&µ7¥ñùCbƒR|Ÿºë>¾Y¡o%Ût¸é©—LÒÓŠk Ïk3¦uJnï`w…xš“| s½§–TÄ~¥ør–íËÀïÆÐĺ  h¼AœŠ)ÁeÐáSh& É,á¨ÛÃ:¨ÐH‡ëy?Trëƒí$©.Ú§)ðµå€•§|®"‚+ø(ñ)Åwô¢;:­H^xFs…pèwâÿ“bàN*,öŸRŠ›M„ŠÓhfqT•â«z¢s¼ðª®qÚ”`/\ ¥nçtó%šKE㨛?IUÍêjWš‹ûÅí¾ß$®5ÇÝTpð¼’„*Ãý Œ‰Ï¥k´N®Ïö~rWwyTdãkæ|Û=¸×ç£!ø»Ü#|VóÕ8Q:Ût칡הâtiHÔ¨vÈÎŒLÆ4¾,U¡ÖÀõ/qê_J)Ð1ÁWøú pÑ 7ñT;`·­¦*¤^©Ú½žàW‹ïº¬•)N8)ÖÉÇd ±AµÛÈ mm 3ÑÆ9íåÈþ¡ñ4Ú7¢b´|;C;TÛͧ…Ûð¿m³K»Ð¾f–%v«%½l·´³`Êä&Þ‘õ€jûìPä'¬î`‡¤­+¿H¨¶¿Ùóù#|2#-ö,„‰¶RÊXä~³T¦?Âà߇èň'TÛk[ì ã€ÜØÁÑÖ€zY»Í²½oÂÇigÌIÝÚŒjvÿ-5oé)Îr# 'dC)>"Ϋv$ü´wQϬ‹ª¸ˆ éI©WI;‘”:o“ lÔ ;úo(÷d„©¢+òK’?4ˆOù†Ùc#Z^eªl]â@g§©×dÆg¬×U'µŠ7T~²o:%|a*¤:UÓ-5Õ-°ò1WíÞ®mèé{Mžvž¶b€–à‰[ã€_Ér-&å)KYØ«Ôú,×åËu1ú<Ï‘>$ÓSÔŠæ €iÖgÑïòº¬%¿Z~²¤¶uùC´>µz²¼–(öþW‡MZ–¿ ²6{ÿ#µØKÛ5¢¸½\Z˜ºæ¹rÙCçÛ‰ ã,1ùÖ„›Ž×†¡¤úʘÆ'Hz¸¦A]â)eš&ÞÓÀ@OÇ‘Êd GU‰ò)–¨B!ë˜ c5*Ç¡Õd‹: ú«aéf‹¾ÍJy†›¥‰Ùœ$Þw: ynhΟömGùg ÿ‡Íùç¥òÏÓÄ|'ÿ äߨœ¿ùÊüC mjþ¶ßËoCñmsXž•Ó·%ø¶”¾M/SáDïc\|£x- £uü¿ú;’Hº ~’V¼Î‘H~ß±ü] q€Ž-”[ÓY'|j7×7úTgw›Ö­¼§Ô[ÃpÏ|H½v3*^t”Qñ#ï|7*•׋ ÍÊK8òU‹•Ï¢Ú•[Qý'Êí¨ñŠx){ûõ¢(^vW~ŠÉv’þ­OLÙá[ÊV†^&éõ'¶žHBë–‹iiùGÛà}§Wb¶ñœRÑ‘äŸ:z)ÖJÌÝÏ£îŸ5*w¢æÏ•»QÏ/ÄÏlƒ ¾ús[‡ê8_Añˆ_¤¿xE±í…V£¤Œzœ[3¢1Ù\ºZídóÂB¡WØI›Ülî-±>Z)AØÚߣhµG¿²½ º(ûŸÙtWYb{‰ü²ÁGOÿÌEÿu¿ÁÅ‘m§sßõ9b¦Ò¹·˜­ÄËVx°?8‡ØÄ¢×N=£»=*¬zÇ_KG nó•dÉF£ìN¦(‰ýN¶…ÍUp8w'–òI×î°¦æ|sŒ’:‡ü2ê£à¨«Žºò\¯Y ÷ïì #iÇÑk—×8.›få5ÁD É(ðð1Õ‚šv¿×4†Œ•©üsàBÎÂp2Æi¯mþgåëð2ò{-ÏÕŽ ƒ(Çáf:Ò©²WMo—¶>Ç¥ø\r\j7ׇì!c¦±Ö¦1AöµâÎl}­cyGÄàêÌÞôo_ØjúÚµûQÑ “³Ê’jâ̾Vê{4å[ëÇð­E<_§F¥)ªtï©ÒoEF¿;:é à úéwf3ž5O7ìCy¿!¾/j¶´kÉúì‹WZñVZ WÌÏ£¨y©¨;,#÷ÈxVz}=¼âIÞЯW¶)Џ^g‹›Õ1~Ñ3ùï|*飿p¦¥¼é\Döα^ÇŸÂM_æ¼¢\Ø{©Ä¢YÄ™?Uç…ýtª$ëlSµ±§ÿiñ´íîW>É‚ÌÜo‰oÁÂìv$`‰gm«ì=¿´ Áb•TE³©¸§ëÄh™YÛ¨O ‚ÃPßwPÌL¼oi€å»Î{Ñ\KÏÿÛÀ%TÈ7Ä^ýlélèPwÄKÅ)Al |qRq½œùÀ¦&mëý&ú{«©‰^Äì (3…[ÜD¢p ×r„]Цaún1^ŽðÔ©~™¿ñI×ï鉨͈Ú,°Ä)ÑÑ0ŒT¯Sê_1¨~ ŠŸ C5´¼þ+†‘B¿ Tú­,Ðèw`ÞÃÅxCô‹Å [4Ùß7ªàƒè¤£½Àxw÷ýáCNâݲÍf¼?%½B˜ÿ&þ-A£>ÍôƒKC®ñïÒ½‘ÉfS ë‚®ª”££7 †lëYp‰óìÄè·4m¨PΠ‚7JšÁƒtNöM$œJ6XC‰¤õ’Ç oQÚÙF¼l¥Çæ½Àazî oT*ß(Çd o‘pvl„ŒVâ d®î;Û`Áf,EÐ3‘Üxäb~Žb&r1o?íšHÅ *PÞU˜Þ,°ÊšÅã¡ð¬é*|X©&ÞhK"^§Î*¯±x‹¤ÆrN¬§²qŠÆ±ðÂÎu¼Š:f¤ê˜!ë¨VØxÁß®c&×¢fµ¬`vª‚9© N‡áKôT0/…‹yŠX Ä,$ªBƒkÐà3ÍiqÚ¹=\‹±Da#‹2í ¿ÜC9Ö3tãc‡pâÁ®ò! ‚T£zh)Z oR@jŒ-Ü8÷V Þ*0·Q0¬À³[«R¯Qp%Ú©ëhEè-6R—”m9Ò᳜¸r!V[èC’Hs‹­ÿ ®ho# &3Y Ûß®ÀRªuìä:vÃÿº,×+öÒ‹‡h”Q͸/…Ésaݧ*Zç]£×Rb>7>.—ËÆ×S0¼@o `DqXþÝG)Y`C’Ïqx®×¼'‘DÓkRW ѩҳêA墾Z¢á°bð/v’XùÒ lÁxÅi%N¢J•LoÂ9p§yç6üá®Îã†UͬJ. ‰í)Zb©â#…ä5*ñcBj8©ÔeÈ”5Ú¶ìE¾ѺÀsôa å3Å¡ZŸ)x&ºu{%«,ñ9r]dʵ“GÌ]E’.Æ„ë®Âd Ñ-D¸8²@ÿ’‚w Œ{Œ$÷}…}¤¯²Ê*¹ŸWY…§Rýlˆ{Ô´xÙ,£ ¤M¸¯3ƒÏ;άPE…š dHçTâÓ4Wü+¥'-DUR‚DIuì/kaaʶ‹>âùò ô_®Üÿ°ë-ØuˆÅ1ûW[bŒH¤&çH¾šI±£8v4•ð1cï)”0:UÂhUŒ…ÛsJ8®eöñ©ìÒÙ/5OØwUgr¿«Š)jh@ªê¾³ 1kÎ'ÍißSÉýž*f¨lQU¦îUH{™'÷%îª9ª3¹ç¨<¾ÐøF@ã{‘Ê“{±Ê“{£ ÜËUžÜµ*OîÕ*‰»èóÕÔä^ bâ-RiT×ÉQ½Xµu‚¹L•S»NNíåj«¾vúŸ§v-$ïYýPÃWõé 5=½Wr-«e"ŒþµjŒ½x«¹Ö¥Qy…g÷]nòFõ¯g÷FÙú²õeë·ª<»·©<»±íD³{§Ê³{—ʳ·livïUÅfµåì^žÝuêÄÖxØÖŒ‡íªœÛ{UžÛ?ÂÜޯʹ]'çö•–\Ù¶„ÊV]½<³WÓÌfl$U>\§apH•óº^•óz¯*çõ|чÑíŸ2û#âo Š·8üí:–ϰõJñ|+÷Õ?–WñÛ¯Š·: þ¥cù<ŽúT)ÞæÄýkÇò•÷2|•%؇1–}ÕÛg\V·åß(—Eó½›òXŸ‹‘n•ÝÊ/FpG›Ù%çöú˜Ñ W±¬,ŠÈ.ÞîÔðzÇò5¢Àw_ãžE ›wuê3;›d¤ÙÙʽ¯+_ïs>’§–Ÿ4*u«=úÌÉÎÓËçз-kÑ>ïgçåïC˜¾Þ²î±â;w#]7E´/ÞáÔݯcùZ Q¨ûfX§|ÝP÷ÖÇ]_ï37»Äî6® Û!í9µ|.Õ³4¢|£Ï<ÄŽ/xN)Ÿ‡Ê>ãíæÇ®M b‘sVž«=qöyJ{Ѥó¢ë-ñ`,Q¾Áqw™OJ|È‘KÒãÃqm™Ï@~¸GœÍŒGHè6± ðÔŠãŒ%ÞmRë×wåkëãe;s w帺M) º¹›Ÿ«äËùÒ[t‰ãêûœëûê{õíéázBtÃŒ{”ÌËŽ6tPx`÷Œ÷†fŒxšáÙ›Ó ž–¯ïÊWÎôL¼·x¶$Ù*»†!b1¨¶ç~@A£2µ@ùN£2­@ýn£ò^öÐà?£7ſŒ…Zr`ü{²·øÙÇ_ðÎØC4¿¨ÉmŠ÷óüêC¯¾Ñ±cù: јc_¶`9î… ]Ó»\«ˆ¤Âª`c/m?ÛéÓH˜bªØ§&âNkaçv¿š(›™dÏðÐ-ÇIL•$ÏJýPŒ9À}”RKkŠHÁ&üõ}%Xøôý *óó¥)n½š,iWî ]4æ)Øä<ª¶T >¦&±èÚn@+ªô+Á'0—U¶´K90épxŸçâÎsZ•É9'òˆ W£#àRT-Q*»Db Amº„ñ¢-QI’g’¸\¥I³×‚âl²|ŸE":”|ö[â<”¼^[~À"aǘˆ¼F…¯ÆX"½l?¶ßÆFp5q:šK\픀«‘*ZQ \§àNGõ–*®Pòs™Ÿ’\ÝH¯ûZŒDÌ»ëj¼ðVÚÆgjœ(qœõêo© Éš4ˆÛjÚ\iœõ»j‚P- &¥ &L_¨‰$翌‹h©ÉPCàO‚ V¶×Â…òB‹É0!¢ÓdÅÍ­9Ø­ñ<@@óÍ4ÆjXâqìk¹'ÐÔZN‡qH Œ šœ4`.Æ]ñ„¼äü¡ÑÐ1Å$¾±Sgg„û9­·˜¢±+’¾ ¨ÞÓœkÏïi¢Jƒ¥1Þz¯Æ#³{CQÑ+fk¸Žšâ‰YZ¼êܱ]íÄ(× ÏTÁ¤ˆáÓ=̼ÎÓœ —[ñMyB–[±Ç*Í`\Ìãf+ó¸Ù*‚»i5Ò–âBF‚±ˆ‚ ÜK4p°æRMÔh-f#ͳ…¦ ®¨ÁåšVÔÏ•A~äEËueÙ^‘—pjì>Ìv^WxVPÑ« ¼«4±‚ðã¬Â|°ºö•Wi%{À.Ù^"z±ZKòÕŠ5ZÒ±°´V#þ5fñÄ]¯'‰áäg¯)ð&òÚ¨Õ™A˜áÙŒT/Öâ6«Øª/˦º—e+!ØCÚ®Gcëø4àOìpêÝIõz¸Þ]TœØÃÙÝœ½+ µÈîn‘}¿“ý@:{RÃ0b 5¾ wHK30Ác÷›Äa)û؈|}:,5–‡Éþ&ûo˜&FhLFâÆGÒÂ’dyÂoãªÃd.àŸPÀ1ß<„>uÔÄ -V–°Švup‰“0±‰·Êœjz“‰G(¡8¥Å‹FjøÜ]SCÑZ§yˆŒ5ç;ƒ*¦ðÇ<â9ÌÏóéù™´r17¨S[LÐi·W7æð½“jÔH$AÞ‘Áêý ˜9-0îQ°¶À}Ÿ‚uf….¾ aE²®ßÔM­HnqŸ^“Í T“œ¹ðÏDàˆ D„dáÝl…»§’Xi¾Õ8Hq"01ϽÅP6eø^DsëF1 ®;Ðב‚`mŠ`FóUú(]ŒÔ[Ï–Qz²Å»!ÞÑ‹—gc-'!e44&§1ÖPËX®e}k,¸¡@Aða:ÍAéŸ2Õ!±¥ Izš¶JÆã]9#/LqD ÍB¢YH4 Ư&£ºÐÄu9’n`$²ÄMŒ¤z zÍ´¸4Xâ–UÁÖTg®ŠÀ²Ð¢‚) óŒ×tF‚2S Ô*]LÓce‡-FÓéñÐWÖŽÐ*mW/ª øÚ`¥å1K&]³ô$M¹>ÌF;«yüuïC%wžž‡,Î}>_‚1ŠÀX€L3[ ÈY#= ×¥ºxÎ;ƶW×±+ ÁìèalÐ1Ý›uPPs‹.6è 6»ÿ¡î\ñܨy Žzƒ›õVcr‹N2só ðˆ­:Ü›ÛԣÛtç2évhÖ☬ճ#*q ½mm ÚZ m-C¤ÖJhkuñκR§ŽgöŸë¸Ïã˜q—áPî1>×îhiX\\n,.nŸ‰6%Åí]‘%ôµ££Ö6°´8˜^ZYJ€hG½4ðïGÞÃiÙÒ"]ÓV›* I× 6WXn‘íýÙ±ö®é¾lèM¾Ç1Êã3Æò.?ìg(©ˆËhú0Qñîþއa ÌsÌw3Eš@ŒªbÜo¢º_>D@²¢ØŒ¶<ía36éÍh+“ÑV¤£yÍh^ùX2Úªd´•E‡÷)ªõª¢äáã&|î5{ÎÚFN焃‘Š’ªdë[+¢Ø[*dKC^Ù³Õ"òW鄞pQ6µÄvÞ­ïhiø 8ø„gw‡ö–Á}í‚ù?¿ ^Ê7”<#í-·ø‘o±Ûù€cwGq{`5¢O¾=8¯møTÑ ’¨üm*ÁßÓü>£Ä·Ð투&,{:jk€eO‡² ðÍw‘5ñR‘Þ)°¶˜Êü Y®.¦$Á5ſл¯¥ð½Gĸ»­ ¸ ¼ùÛ¢qk…|€d©ƒk‹á‚ûÝ-€>AЧ‚—¹ ï |X}ÜÒýÃbù4¡“KÓn¼!wú}YFaÿé!1J“¯'Mxт늫ÿºKÖjq« urœ‹óåÞñîékTîXø‹¼8ý|MÙ_Öš¤uè*'kT™XøK ú2ô‚¦hTÃXø IMEÐt 'ƒ›‹tªÒý(æ§Ø9¤×S¥ÚÀɪXϵZ_,jÁ'ˆVõ¡[“Ç . x5ïFêß Žýo¶üF>…÷·ƒnntÐnBèÍÐ?â°UüQþ‰˜]÷ýíˆÒ[‹”N3Eú;åÿhXbWæ“"Øw+øŸ|~›åŸò_Q¢"Ä|§t-"±í¾­HéÆSDèäÉa"n†íŒáV &ŠáBŽQ¢â($@²#d2¼AHÎI4dJÉAì6JtE…ä,Ęw!®Òr;ü´Üæ³ÆÒãøB\œ-ä" ­8'ñ!É*NòI…e•«…Ù;Ö³w¬¥dÔîÝÏåÁKÚºûù<¹¯gòº_È“ë.Á¥ýÐ%Ýч, !w E·syÀá»–­OIˆóy@ÇPBYoÖìB03”°ïöiì'’ØOìµgb¿ª°ŸnŽýªÂþysìWö/€}Wüµ½ ì— ûͽë8ƒË8x°‹+B^ÀW}ﺄC&Z·ÂÁà5#»&l® ¬Ö(rí¥!·ë{#2ïƒá^W¦j­j둲æ]Ƙ: W{Z.Ñ2ëIc‰w3–jQB‰2¼§eÖ8¾L…S1Þ×2ëž _®Â©$+P’úŒ’lL–d£&7'K²…J²õú’À»)¬í™%Ùv}I8|{ª$;®/ ‡GS%‰¡$»S“åfÿs’è%ÚF~ ØÿžÔ$q(5IlÃ$ñi»²g{‹ÈŸy*9Ìl3Âî!:Z:>*¾»$òñÜÅ= øÚ@_ŸvÔ l,¾»ed#}ì¨?ØT|w«È&ú:ÔÑøA`s±g¨+²™>w´þ$°¥Øs¤cd }íh{&ðq±ç³Ž‘1«¡¥¡ntoÜn2žy]ÀxvTˆçI¨ÐþÜ bú òùXû–3oko¿Z'ÿkŸ¯Þëå ±»Kß~µ‡!_Œûƶ±xÎ? uú{ªƒqÉJx|‚ó‡|róµ<6$z²È&lö[€è*ã‹þ«yÁ+­‚ýn ö¿)fyÝ®æa}qŠåLØóŒ£q!µNÁ²ñ{¶¯€x5¡lÏ3£¸ŸÍmöGÒÇ<îµøDCAŸÑèÏ7muŸìÊòþ÷HÜïç”ÝHÚŸ©ÃUŸyK—? ,_Áâj°º<‚ÙmäÎÁ7ÓëP…ðã$¡NbPÍSUÌnÛuàA„Ìn3»j—bv{“+bP»xÅâ¦TÝ ™]}3f·›™]/—bv„k×§‚S ×Á2»Þ.“ÙQ£™Ìî˜  gðuìêTŠ] Vu’~§³;ÙŒ]}¡R¹.õ—ßJ}Z1»/š¥–*õÐë˜]cšÙÉfÌîœÉìú¸’ÌŽ*ÔÉÿùuÌ®3»UÙ³ëë‚tÞÉÔ¡¿#C‡þ8ÄóOŠ=Ÿ—F>!)ûDGíáÀ¶bϾÒÈ6HÙ5® )w[¨ïçJJ¹(õaJ¹ýIÊî 9öwá¤ê/ÈñdGK—ÀöbÏÚìÈvÊâTGqJv@£}†Ué¹ï ðéŽÚç"¸WŽBýÝ¥!1€O?¬À1Oö"¸ÚŒGy¸ÀïœxÃL>†eùãPÖ£âØì÷þÁŸöÍ-$Ö&»>-»W8î”ßôÍõÿ1X“[ÖíZ¤o®üQôGŸæXdµ\6‡Íþ‰†Ô?5í ÿ”Í ÿ”­ ÿŠÖ5úoHè©0ž£uL…5@B|…í·òçI'Í¿PNš•´•þdÿê'ëåo ÊçHJ3ÝiBFl!ºoÈx…o³÷¦ß²+e@­ ¿3Á’ÍIš­éìÉ–mº‡ìRhœî²7¤ß™~MŽT¤ýš„¡ê‹…s…TïÍ7£µðk)zÞã-wÊ?@}‘ŠÒ‘ì£9ÖYŠÅê#&ò£Èÿ„¬‹ <÷¼©FÄèCvß—í´ªQN]¾›íƒ¹©r@Ô—¨I^ÆMï! kØkÑNž%]dOèqã=(¶þÅî.ÀE=Bþ»«ü*šP6ía4{´o_k­†ÝqÔäÖ‚a.ƒ¸ÆÍ@0„¹Æ± ˶wÅñc\¨˜ß†»tâ¯"æhŽy¥Ô2Z°Sn Z_ã9ùhúy'ž §; ON¬tŽ8¯(ó &¶‰À6Ž»À\è–°žÚÍ=!¾’ñ¼2Ç>Ë 9ØP!Vëò}ýF>Ë–ë7ðY¶RG„ywáΠƇ?LÈ—/Ò£J Lýƒdµn^Ÿ©“kõx4|*§û©ù!^×ew_—-×ëpÎv–s²BÛ@<ûˆ¾QgOöR‡Z!ͧÓÐ%7éè~/²£± ëVŠ2íQÛ6]nߦTUnÓC6Šçkh' ÔìÔ!(Īd;MîÓI&c¹¡±€H¶_Ïì¶ð‡Á. §"œz7Ñž®åa&@.úæQ=Îìd_kÑ}O¶üLOwUšyädFÓÅB7Ó)ªnÈHT ÉÕåçD%*ºÒ<¯ÚÜBƒ–™¹ µÊFV‰ñª NÏEYŽÇY[yPdcƒ—¨0êÎÑ•t ¯êñŒ2ËyM"BÖÞ¬[3Þ¥[mö…,ô3”c(\Ð2Ø;T?ƒÝCõ3ØÙ3ÇIo`ð¯ö¼é"j!©™²^f׬‘¬fÊÂÇø`…>Š|þa¹ ß°\ue4QàF0/®Õi^«û®º´¶YóFÕ#飪J9\†Ýf北äã Ó=ö“u’;•W9Ñ ÚõÌ(vWÁ-“ 9ÙHy¤>‹îBèWb*Uýb…¶ÂSIù’dùºN¾eÀ1»º3m%-“ýDQEŸeÈYiªô€Óªê½ŠÆ;†|” ðRyåCÙ’“ó8OÖš—Ô‹¤±f£CW¨žù¾É±°­ô嬀¤ß¼=ëå*#ŽhTwmQËñ?@üµh!ÜÜéß÷íΡ±{›Åª°n4äF ¼~“/{6t$%-¥ËµåÚÆ¾;&òªñVZ¹Q[Üë?›4sÜ™þ?;€×ŒO" ¸I®´_´É.8¿jÛx¹BÞEüσUUçÀPD˜‘îÈP‡¼z.ÃjwHh]RíL?foòA0ŽmÊ«#î(~]!ºÉ‡3Úõ4+ó‹¯*´Gå£Í[³^VÐÔW«úG‚{áRS0/AÝ.¨ºbÏÂNŠ8úò‰“ÆOB‡ÉHQæ) M9Íômº¥XÞ÷㈆øƒäPýa2ºò3ù#’CâÉKU¸¢ ºN]mwÀ½]…,óŸË ë“ôÿÙ‚mG×:âNu¥u¼¦¹¬šÕö“Æ+òAÈXW;X”G˾'ä#°oç”߆Ç9iB-„¿ÔGý4ü黽%|¾]øB;¼›á£ùª]U?C“PütájÍÝÀ Ô›Ñ0=€yÉÅvÕYj£/‹*3Ã…Ñ<¤ú>¥ú!âAÓÍÉ»®2÷ «äO¢1¨Äcâ·Tw‚lŒ ‘qNùS([r’ $áÏ=.K@vO—BùF„É8X2#™+òÐÓ2Œ(Êjð wéÒYÙŽÐü h^×,/À.‚ø‹|áö]ò/p¸w+î¼Á‹U?S%Nu󵾚¥gOŠÇ7¡8o7¬x½Œý¤Y.å•p÷T»™´œº×òwÆÿh*(ʾR—²øgsÔ›4Þsú‰ŒÔ1Z ´ÿÁ–×ÛŒö§@ÛGdàíÇ–HDØ!Jy· š#Ý¢ö®'̃y7m¶K·Ym1ÜÃw;xY¹ZaÁÞê¸Ö¼N½¦Ž‹¶ê금¨4Zû¯Ô±ùfFÉ[®|)³+_Êœr¯1ÏL¬ü|;ॅmÈîkÄià±í‰Õ×ǰ(5^tØ…ÝXk¸˜Ç\ÔLÌS\,Ö³® &‰7t!³»q΄ÙGƒ5Æ…e2°L᪽ãÂ-Þªö¦ª±võÜsÞr¦ˆj‹“RÐ@[굯mqáGúMbUüÀ½Ú»l£ò³+ŒÙÆõ¹‚=“–í™= Û¯„Ù ƒ‰Z£ZÝC_"¨ T¹T$XÝ™Ñ1_ƒÂëhÙï™\šŒu.®åÛÂËE&²x÷óí`÷‹ÏéνJÐX¦f‰Q)yÐ~ ¢°YÍç9`)F±"Æwü—’|ížDÌ$2Ö 8XÉÜ V2Ï-õÇ«½² [X(¶´mA{yµ6ò&pî¶Ñà1˜ˆLrÊvôçÉNYMDÞpÊ2B5ßä„êâ·FÓÀ¤Áí |[4<à…ÌiÚL\PaßpŸ¯q§\Žð÷n,Æ¥#{(òÝÿ%òjŽü® ¦.^Fä”шÑÛ+:ËÎf5^«£¹ìóVq˜'æÅ÷}l4àþ¨oŠÓ’l”ŸÝKÉ.ú@Ô753t²s‡>È¡¡;.N5eîö_N›Œ&˜èM°Ä•²PòyGËD±ç‹Ž‘D1-á:ŠÎÅž3#;Y1s;µWÞO°÷RÛ©(õmn§m#Óœ€!‹e®ôEå÷]V'‘ƾ^Øò`%ç2,ÍE™¼™ð²¨wµZ<2ÝI ÷Œ%2Ã)Úw½â”߉†g8áT)>n­KO*Ñw'T4yg¢Ìµ‹ð}°ËêRê[”!Íëðk:¾Â¥Ù ë¯~Ó}=+½>„˪âvû]šÓ¡èü]å™j†{QÅɽ(â@ƃ­ú'’‹ÝŸÃæîÏczWº’ú)”IKÿ“6C‰6/Ò¬ÊðŒSÖXã¥*ªç;ÔÁ0ÅÐtÚ‘¦ÓYNYNW›ý¸†ËNmxª´Æ¥,çøQs’{TzU2XtY›ê£ÿ›ô¨†.1Ó 8 õaºK4@erW±GvŒì¢.ÑØQܨ+öœí©C—X—Ù%úQ/‡6fªK µÿªYíáTíÙNÀÅG.XŽ9»Yç:Z:ê±Þßû¸ˆÔS>ç;ŠNÝ h7.tÔî ìh @{ôUGýþÀ^€´—@;ö4 }ЫìhýM`?@C¼j³}?A/w´=8èPz€ W:Ú_t˜ =HÐo::þ8èp =D k³z‹ÀÀFv„`ÕåÙcDà3ÀFš©?‘6¸ –öëÆQ^ù[Ôw÷}–ßÊPpq{K÷=­ez‹UÕKý]Œ^Ã{Zc%U³K†ƒÌ( 7%Bb&}P$µO¼Kþ £}£ËÐál–²xÉÌâ%öÔò7ùjð ‰å5zSXzÆè5•‘GÈ¿ÕÔå·a!¸§ÖÔÉÅø¥ù{ð2´R‹óùôðMœíß‘­Ò/¡|û Îx0¤„TÖD*ïâúÌ‹S˜&šg?\¤ó"‚G’HPF±úÍLÛ(Á¸d Æ 9Q?3³ž„W•õdÊú³ O) O)Oߢñ žá·¸”"Ê«„†]Kˆ`³¬4]Øš&ýš:6EÔZÞóŒöÂØ»}j _kWÆN‡<ÇÂ\êãlª§Ö;µ«lóŒU±Ù50ѯÌ3Ž8$ÑàæX¸©]Yî-Þ÷Œ÷âsªg‚w*Ô8ø¼ñ¶¸gBc¼Cxëäñ®ò®˜¯º&Œ¶òltŽËú°YVš‘h5Óçfñ]é…1£x]®ä²÷*æò ‡Oöp˜ÚEî*ÖgX=z"Ö•(»MuõJ_ŸSËïÛ„÷¶Œ‡{—B'æ:D?îÉ@ôCBTÜ›ù1A~Ü—úçþcôuŒQÿâÿBý¬2·ó‰ËfµÚÆi¨<¼j”ÕÔ—Õ˜ö…f 60ÍŸ>7ksè±áV}® ™Ë484_˜ ãÔä"‘ª6r´×“¸D³_ˆ®$i¥êß–å¬êU@Ðþ„S>ç—†|(>•Cë£S9sԪƼ8^ˆ%ÓB§ïx±ÖSdȇáEβ9ÇcNWù]0»}.¨ËwCyùBÇT/Œ)s ¯|,V6'^6‡‹ô8é SøÉÛ‰'ÄÂi}xÑ9Ç4{ŽÚâôƒ„¼ŸQŽb¼œÓ¼–Ät¯x‰f²Øã¢ú¥:ùrK'û£™ìòyJ6Ï)ÿ mcWÒüÅhëïÏ#&þ?;#æ%€Yá8cípÂeÍÓwôÆ7½ØÊKoÁâOÒöWKeGæ‹:ÀîWç¹øÓ‚åû»Ø%À]ìà.ØûÒ=²<ÏËÂ~ì[^ãž1ÓkíÜ fym÷Ò*Àm¿¯A¼íuÜß f{³º4ˆw¼ÙË{RVެ²sÌ4âO%÷†¬æF¬]Þ²™ïyÒ6P–ì’iª–€¦RÊG`©Ò­ƒï&BÙæk<”5§¶gØ—üEQ½¡œÂ_c¨Ïñ榨ü¾ÿTq &¸ªNëò‡Ôy×v®7·JVQw\×Ââ– ;f-äCì .Ô¢™§VFó³t}NºŒ\ݘÃmöŒé§6¦’mÄÖÙxh=}Açy5ú;ß«?Û x_Áœõ7òÙöM„õWìºì7Ô0%ÓÖßZ(«\6Ø$š' 2ý6²‡æÌ7Ïø\maa{V21Ú[rQᬯ²Ç:«üŠ1í•ú|Þ‹YèµZäuüµA¼ëÍzIFʉôŠaO6dU›°ÏC…,ÿÌ| ø"gcP…O“cšr,ƒ.ðÌìò1_–r’‚nðrÈ|rqaG佤Kö«òUú³)¸×`ñþeOõÞîI%ŽæRkQÔVý[ì_*TþgM>§v°x÷Ë;ó v\k"FĵQ¼¨Yuú`Ö?E’¢nT¢Í”~%5vÿ{E?Û!Yãy±½ –È“* qß–$ž$ñ|‹Ì§i 0 åM±VuŒMY#ç9m„xÖǃ­›&Sˆ}ö,ô2!¼âu!_þV1_+ÛÌc‚•ßpD—V.Öeñ^ÌÆxÓ½êóbØ)©ˆ‰Ý`ŒGÝ>wé9º1…;ää¤á*x©²â¸HžiA°A¼îfwx,õjx¼çÕ§9]ÄÛ[ò`«ˆÖñ¤Q@#¢ø[´ÃÖ¨f‚—ü%v›ñ6„ÊAu-ì‹ ^Vˆ›#Ý67çP=ixµ¦#[þS 4kaÖê…V¼ Ù pþù®ðç1˜ýfö°sÆK{Ú©Õ«ÞÎ$|Ò;»ú°AýÜÆ£Ý5Úæ}Ї ›{z|ö…o’;ÁN¦$±Ìk_#HôÄ@Môî‘ ƒ¦Y¸2+[?$áÓ켘× Xî^«c.%qöÌã´5¢svVÁ†¦&G¶#+¿=‹§ ¤c› "AÉ”r96CS©”’HŠ›.k±nŒÊBCí6**sZP¹”G1zɤCi€Ã£˜[ycž¿[™®Ãc†[ÃãèM:˽Æz¬ðZ?¥ÇJ¯ VãVyí°÷u[ÇQz|àÍúLȽ"Á·÷Ñì+ˆDÚs »ùFåÖ±aG ''˜ƒ·³ùñDÅwu°«eÞìS„~µ7ç ~– ggk¼-FB#œzrÈÆ=ø5j ³pv“§çÊ/;nüÊeînj­„Œž…?CÛy(¯AÈ‘š‚œRŠ“¨[{W 1×"–e#•4[ž¥¸©œ“¿œ¾¢^’t“ÕSµ®õ:/ yIøO¢¾ÊñfKd-äejA½ Û Rœ:_~-ü_ôæ…é»ã4Y«±1IÐ"oZÕ6M—cÍ\©¿B¹©€íÄô(„ZSA{ }›¦b& ìP¯‰ê=TÀªS“`å ºj“5Eϰ±Y’Ê7´ä· ıߔ$0ɦrp¿¶GVþÇ(ï†G g²M·¢Y¦=×Ûšœ©}«ùŠä,‹L.ù¶r%=°ÍÖ(¶;ä‚LÃ×BßÑÖå?C ’·Šó(F>˜æ|zGÀ´ª}9" m¡¢” €X‹ +ax‰Yß"Õ”/º"þD5WeŸ0þÎÔŒ…o(¤˜è"Æšc2Väá¹Ú7°„¥¤3œ•°Ñ×W0h?Ð2FõqJO}Ó$×R}pÝËeËÒYxÓM™Ï„âK‰ï¸š²laÇ€b +Fix¬óê[Ù# ñ‰&·j·ÓÜð‰FÌBA¡‰±2d6³]ëÐ5%Ÿk­÷Zc”æ#¯-®±•¼´LHqe±ß"ì²Nó_,†ZN\,6̃"å4Šdº¢y6­ôˆæœ}NKàºßÕÍeAåä@D8£ûE§„7k÷¨MÕC¶fdϦþë2Én“Ãu*{¤ e¥ê8J§’(bÑyÍ#¯ Ú…DìqÊYƒ fŸ­§³A)"ítI‹‘v:üÆ%â-PØ™(ìlÝÿ„~j÷¯Ø´LãXœÄ±XáX¬p,¦˜Ä± 8V$q¸L.;5újHbI$1…$¦à±Å«ãñ±×Àãü½Ö=¶zm;éqñ!û.¨iÝëØ Ë€Þ¬ãôØæÍ>¡Ë„ÇØ©Cêod[‘v¹KGÏ’{õÔ|™%÷é‰Ló«ê Ë~}.ëÌóË–'ôä:-GžTA˜Tp¬§æëb|·ÇÉ)íEË*73vj]îTæñç LáJ»"#I érÔ+GNÌçíÂF•'‚í9äYàš]ÂXŽóǬvÛg‹ °^¼¦ûÏcĆl·ûΔ,’b/ƒáŒ.…Æ›USK¡i0¾Â?PºÑFš¯וgŒ2äÁ D­r´;jŸ”o¼‘H’¡åQê–o\@’ Á¨Ù׌f è0]àZJe·ÇZu¡Ø&gØw:ë2lº±‰WëX}ìeˆìOö`£E–u, <¶{µu†Ü`ÀÝO4› ÿ“1ß“"ÎÍ "K//6µ•zþ#y±fJõÛ ¹Õð¿ó½,‰ÜóÍìì‰×bV¹ÊS˜}w°l%ý\ŽPóvúcV2œwÂPë•·—‚ ¹Zeç\†]7–r…β­§˜×#Xx|üˆv–k£ã÷çé‘ðZ/ò¼QÆ&S/ÀT¦g¬…¸l(Ó¹ü5Z 6U¹³_1Hpý& Z`N ø:–3õO¯þsÅìD1¦Q³œƒ>ë:M^4âX8º'RKö¶bÿé¼ËÚB7öó¸~êÚCÆ[6À|å6ˆ^ËV®çïÕð˜p¿ŽÇ¯ÇÇ^+q¯mªUNåE˜]¾iå<(ü[ÖD×üƒ´Ê—ó­©Úåf«Z±O y0ò±5°‡Ìþ; K¡Åµ\íɨ´(®'ñ¤Õ§l wqaHuû!«ÁŸí£9eeÏŒ$pñŸ,îÒG(»­-YÞÔ”_*,ò"£Vþ·š¬þKÅœ‰ú—Š5ÙËÖ ‡2™ÞÇÆ_);•>ÒÖy³jl²Æ–,m¶d ecS³½©@Ii!ü"ÈáûÒIa_:óFsúG²§Úähìgªj˜Õ­÷挷Éñ” UÝ\9‘?ÍêNn^Ô\.j-rHVWNµ±•L’W˜säÈ7MýÃÏV£ž±ÞEc¿¨• wɵ&¹À†+6\F¾n|fc˦Ö6,ôìø“!=´Bwk•ô(èÆ²ðåN%…Ù”fSR=v{u<Îßkl¥Ç¯õ›Üj£™ÄšJCý÷zm1 Ù絟 Ç~¯ã¼ †³.ÙdÌkËæT£ØÞ^[šíÕ«÷ÞæÒ,9³¨þ8‡3Pú“»U<̽“þy~(Àâü [‹YOçpö©wGþÍÈú´]y".†É6šiÎ([È;IïeÉkà´”Á&Êà¼-½yÁÆwÜ Ï_ ͉)+51¡_¥Ð’Œ¥ of™ë‚ly€l³«Øä×ìòŽ8 ¶<¶z³¯ùxsªí âSon/»¼J’æÆ«íÉÕP®ìe咔Ά_Ȅ闋¯ýíÝ9IØ´<°ØÕg('lÞAhÏ¿…†ÚÐf‰<¬0†+‰f^¿{Tm½-ÆÓDF¡©Q''ð§9 &¢¸pÁ¨l·M²¯k!Ç¢:<V`˜1Lnr:ñŒaÖj>äÍ{“xÝÿ2I0<á8å[vZ›cÈ»À–gÒÏ™,^Gè‚”þYU7DŠüïPœÂ–L©hÑõP¹ƒdÂÝâj“|ÏŽ9ö+—N+šm¼-¶ÝÎ:ïÓò0Úη<4Œð8ìÕñ8â5ô8êµÖÛeÔnJƒ1;uÅ„˜µ+V¹ÓÎ3å…Á3ã®ÔgÒÒj½ûè*ºMî¶£¥¢ïI}&mïÏm¨øò ]í¼« V˜;„B挧/s¬A𣯒D«-|Íò™×vÌ.Ù“®ìò¸E¦Æg"¤XìÔŒêeà ò§ìÌေ@M¯æ;ž–§U0CMÙðK”ð¬êf)PÂZ5='T‹-PÊÜǼöóvyÞlFÈb¨LŽyÉ29TËÎcÄ_ñ%nÖ‹,i\aI£·#µÛÙÊÜílǽ–ÞÌÂ^­¯Cö%æZŸ¿”ÂI¯>Ø!;b‰ÔŽæbq³ ŸòÃr¸{šÜ’0¯NÉN{­£r´ƒÍ3'ûæGz¶‘c %Ցχšç,%ð’1ÑA¢ùNŽ(?Lu°¹ôB¬ˆ¦;0{Ògÿ8Ož3(E>¯e´¿#Á‹—p½í€…—ÐuãG Á¦Açºq¦³eŽCÎsÄÔžû¥{Ň\à0]´ÔɅޏÚ*¨“‹|…N¾K ê^]å´/»à½fÓ6Áx[±²8[eL8`õYìrÈ]ÿ_b¾£YvÉR—ÿC&Ðç^m·Cîv˜šmr#^ZÜzõ}´&w(í6Oìwăkò@Áî†|sM·$ lÀ×9RðLÄ9“©æ‡Õ¾vé´Œó£ˆÇ4©ÚǨh_z“ÒN8ä ‡ÿrqÌw¹XàbÅIGÂÜ]Œ×šú°ã‹~Ë»¶§þ«ÅÔ®k]åi¦Ä•t.g’¹œQ¹àqÆ«I‡”ÍriüÿärÖῆ\®!—sœË7.8Nùr¹ÈäþK=›2¾è`SÆx¼¥k—ò ~¼'3ÁYDÀ8H÷kNû1‚IO4ÏSó#}øFµ¦„óÔqáU¯oøû•ÄTô+ѨL¸`/¼ 7†E\µ_Èþ˜v§œ(Vh%TK¹ÿE 4dïïÖˆ=ìäJNçJ¶¥þ”ÖpÞk™.  2]+½ ç¾]ô·ØjÔü¸ï0ú_Éã¿ÁÌØ5c6ÔúCÆíÝ·Zù0æÛl|†ôŽ0íˆÏþ¶!k·¶‚ò‚Þ(t %|ŽË"q{Õä<o9r¡ ú´%ï·/‰’KD”Ìà9|‚°TøkJb¾šFû¾kà6¬FÎgÜ=V‰d·ºæ«x,¶UÝÊû‚¡Võ°©‡¬x¸_ÈÂ£Ó Ùf$â¬r=¡ z}CÛXªK^ÐåAÿƒÞ݇µ‘ùex¹‰âø½èqݼyÉÍè{†od©ÅÓÓõ [pù=ƒ~5ª´½%<ºE‘[“À×S@›ü$ Ó& ´Ëm(ÅüB‚ÛA|»¬J.·#²£0Â(F[|2áiLÄ€±`Ø7€3UP&¨·Õ$»w#¿”:ëï©·‚r'f©C)ÏöûøÈ9!:zA}S“ƒÆ ŒÂüOøLËBlÜíÁ‘mîª÷LéBEM Ü‰;|*íïôkË]õô¶½}Ž«$DÞ˜Ÿxùy'̓¢T ¢ò¸ÑF´!iÀr’úñA”Iëªýq˜>ŠFxšþ=²ÇЈηиÖÚZji@—XÆ–Z ¯e\©Å굌/µØ¼– ¥»×2±ÔâȲL*µd¹-“K-Ù,ݘìns”•hÀå±€¿«oÓŽÁÈ‚#4þ]/‹D!̤ÜýyJ$ ÔU>W⛕£óûw•ŸóÕ‘AnÏŸ`æ†õ4Õ Ëäz„¾yÙß zUZÎ +GM¥&ᆺRo„Ù6úÓ(â,´ž±²"Ö¤;ó Oè_i…ñ„1÷Û`’3šGÀÁ‘ˆ3ëøŠF¯gB˜¶ã^Ç~•¸oÚqƉ`Zv‚ˆM6!ÌâÄÒº—”*d¸AÓÒ=Œ'`?”mlô€o¬Pß;ËÃZc€æßÛ:”åÛÛšWà5¥R7˜ßû§ä$®Ã™ó gÛ²;õ‹‘Z·¥5´‚g>¬þ;Á{WZ^טàx ªÔj5&øXœs¦>VS§e|‚ÆŸÄç;¶É|¾c‡iq"ø >•½7ÿߟ¨™Ÿ¤}›à3´ÁßÔ®#ø[ZŠà³2>;Mð9×|n3‚ÏoNð_ô-‚¿›"ø4-Eðe)‚qgˆdDô5¸ä?ÔVsv£ÃÝÙî!™ üSL™m Él‹€­ÖüSM`-—0‚ÜwÚVÜH7,ÄT4®TWD¶Üky”íñÓß×4¾-ò=!ƒƒùx4yß)Ÿˆ’HKÕ$ÚÈ2§|–L¨06»h~í$«¢á÷œ¸7†'l–)CôJ#¬̘¸aÆä¨@ªŸ`ƒ!mO²¦Ôù–ŸÈŸÅ X¨>ÓJüŠ7~-<%°ÌùUTY%ûu”m’åGXTR©ûq `¤?©f@,Ã;£Fˆà+ G™Áü{!§ÅÕF7á %Ì×zÙ#ÁK{'âýŽ{ÈïCVÊ;ÿõ¦&žu#8;àyú±”oÃ]òù¨ÿŘò“÷žRo|Ý­ŒàQ]_! ½ ¿­È1n˜€qüš©ùšì —ç0V[›NôoJô¿Ñðr$ë†ÙºùvÀ{)_†é¥mB –‡VŠA0¥S© † Ë£ú0øŽ¯4 y5Þg-p‘Ó,k?6âb5}S%ß^V#ýE‡®rnwÊÁ0ˆf1Ô“Èü:ùEôƒ›‘y0þ2NÐ" T¯“ã…ÚžOnÒL€¼v4'QtŸ2×^æ¤EMJ- ™æÛ¦é¼byƒ`h ”a ÉarªX§É7–8οbaÏî‡ØG;!ÎÌX>QCÃ18‰LØ–5[~®ˆ5wÌ9O•"d-jÏ2Tf1°‰Ô¬ Å:ƒ-~,qæ%ÛßlÝ­µ%²ö7Ñ$QS·i…àC ׫¸ð.ÒÞa“9¯iž6hR­ÍÎæ^Y×7K©ò\ŽmAß#¶V7]ƒ*žÄð1‡]¨ñ'±Øå¢¦“P4ÈŸþ¿®ùhßb˜Uaó¦°¼Q*µ¯sƒ²É:P|e‹‚­ð®ž‘&Oï]äwÆìÿ¯š$Ó4÷Ìw¤­©Q¢¨žû{”ÁQKyz¥<½â4õ³ë+ËXBŸ¸±mE¨¬œ‚循«-,0îÏ5‰‹®Ÿùä“än¹zd…“$•>^ádsgØÜß8έ1lÏÂ"Öy.PÕ&ÍB’ƒ²„7ž£´AØg›Ke EùFÅ™àNZË£XßñO+mn-o,[>XêD(ØýDæÍì bz¹e œï”‹¥F`HIûN‘!% â­rí=#0´¤½+2´¶Ü6âIÆ•0ù€Ëºe¥!W%Áé¥ÁA%?Á¡%·?®uX"W’ì¹K)P­2‚KbþA%ÁCð0¤$6½Û ­ûŒRжŽfh‰wÅ>À™çd·¦Ûìƒ5ä3Û†|.•YfÛòoªÅ¶à—­Ã ­»fÉ÷øuÂMôºœ_Í߉an‹Õå+ãAÓ1’mÁãÙá îxkÀDþ0,Š6Ñ„iùÿÀṵ̈I&LÏc#acL˜‘ÿSh1¬Ö„YÙñ÷R†3a6Þ‡\ư±&ÌŽ¡ò}†7ae6Ç¡µ¹ƒä~úeþ¿—ÿWð‹å &ÊWDY$Êj<ÍeÉm·¶Ù:¨ú¯m^ÿnPÿ 7¨ÿÆÔÓ ê¿ùõßÒ¬®ªþ[›ÑDÕÿ“ÿRÿG©þôûöÿ'ø¿Å2Å ÛŨþϨûÿ7…ž‰–E>pÊ_ÂÒ‘Çîð#ø×¼w]ǽ3(ý46wÊ@ÔÿÓn?µDV9eݲÔôÐ,B2äÿ E,y7·G¼ æƒè“+[¸÷PŸü}´ê§E†aí[펾Ü3ÿ„ln©+«~ ÞôhKùõòÏÑð*'ð´|áå­ _€¨2²’ïª(¥åsTùJœ÷b‹nE”/;k“‹‡›ôàý µü{"ü»+Ê<-_Ї׶¢Äñ2ׇ¸] t&J~¬h]µ²µÆ–½W9˺/̦5¾Í¬±^#dH×™xd?â•Usà‘Ú¬7®MDÞU0ˆŒå°}ÿA"Ë)‹ÄrhÊ‡Ý 7.rÝ b KÁYÂ~‚)¢U«‰h£k7qkw\2àM’sì&!` °å¦©üz×.ÏìÒðŒÒØc–;¸s ‹n+µÃ) Ê‚B„âÍRÞs1`ˆÉ2v˜ ³ƒÏ÷¯~~d‚ ò¨J1êÕf0%ÆfÊóÝž· Ú<†Ç@¹…"®¶ÚGWÂл\.ò3ñ¸™a E-2Þƒ÷]‰ª·Ju¶|À­‘´ñ3„f‹Õ¶Žþ ùß4 Ûµ(ª\MŸÖ|s/d˜&Â`°ë@«ðç-;ToaÈu¬?“db»ã$Wy#‹võ0¢Eâ]"qã}–ÐP~Tlr³ò¹`gÞ‰Ÿ_Ìû1ª£YeßóÇ+e\â©®’Ïžá{jð‘ÝX¡ï…ì¨:^¨—{›¥Gæ4/‡ >|Q˜>åŒ5×w†$íîi€é*”&a’¯Ÿ_\€*ã d)Np)BVнhÌâ_„ KôŒ³ª˜sjax„»“ a_!ì’Ùß.#ál&Õ%&Õ7Ü;¸g<ŸÜ¬'Z}£h…5-Tª©¶5|p —‹]nÄxPôÒîÞÚÓ´¸V”ý1/­™²]x)ݼc M®>‡kþçÝLbÁM4ÕСY1Š¿ãøô)º“5Ø&4­†r²fŸ(÷ÆuyLMæ1Má…¬ªû½…%à;Lž ÀÛ07[ýÉ9 u:— žóV9®ÂæºaÐhÓk!ëë„A´òQËB kÇ–û4<ÆTêïjr©‹|D Ó÷´Xœd|¢ÏèH™ÿv‹?£ñiÆ ÙR]¨•TØðÞ6Ôk|g[«ðÕZÔø¸E”XAäZ¢öGNØ6„¡·A\}—l=—ìIâ뵕– šÜ ù×·PGp»à^$ü3VÔÓ¿³æÕÇüZ5†ðmÕ¢eÝi²Ø®ÅØtTcͯÖlÇ^ûW½N±Dpz§ˆù܇wß'ê5Y¯¥L'íÖ¢ÔèüG8ŽÜ£Åc¦Œ¿W‹3Š}pÆBDæó´Ôå?–%ÇVZŽÇUŠ#šüL•šM¬ƒ÷gJvɸ­Ôƒði.äâXÈ!ãóZüöî3KåÅTÍ‚îþ¨\þ ¬‡Õ‡1´+š¼’$F½üFKøóã¾|6ævUKÜÞ}:+< F‹½õ¸²‹ÚGÏ´‹¿Þ.jƒË›–1úëª' €5Á…ÜGk¹' ÑyïÉ`«µCt¶Z‹Ç©;´!°p››J[6Þ¾iÎ]Icš£&í‘­rö,|”õeM~†‹â âò­úh]ŽNÃõ­`ÓôulJ»aϧ«GÈZ½+{„Ž'ž:”o¸‹Ü‚¦±P¼Y¬¿:¾Ò2[‡²¬ê¤ê€x—|G7-Ie^‚ƒý—tú÷9ý\¯e…EÙu-Ò×èvÁêá Ó/æi´-ÒG9ýþ.–¨.ãzÔ·ÖIÑ7;a^wI:Ö‰d¬º<•Œµ…c-åX<¯™Œõ%µŽŠ¥óínÅ.åÜ:uðAÜ.½ 3ro¸¿¬„™¾¾°aÇöFkˆ†]e?ÃÖÎ.ç` ¿l,Œû¾j) I‚r–lÀPéfñ¦â%}enoYP%!e˜ë*Gfù?æò/Ë(ÓŒd™fP™&VŠY†|Ë`«¨¸Õ7vêºB§”r33{;](šµáR>KÎ¥5 œÿ¥c½“Y¤¤u×Ñó pȺeZ”,ÓV.Óûn[‘ݱÙ2­1”QêY¥=lwô°ßÑÃq"ß.…ŽÚà(©ý¶G.uñôË+«TÒÃIoù âJÖaR)6Â+o¥¶^b+õzzL~ÔØCÒ‚á?žã;N½ã»äzC]œûÈxZn4bê*ó Gua>9˜nrUÂòïRr˜@´>;Väú!¤wƒÄ¾p­Ãa3å#H¢Ø;¥5¼ñ±¿æ”ÖÔÔ˨Ó2ãTA¸WKö"ãÀ¹¥5õ<ÕíL}Êz"LÔiÁÈÚC¯;ðj•ûi Ns†w»øÜÌJ맆üÔðÏ*E1ú;ºÍ*Õ™dò ²:Öœí ï*žAëö|a±tè>¯T6ÔÙÉ*Œé·+mLj8³+íÇéñN¥ã„!Á'~¢#<¿¦•ÚÿnÆkPÞIäáy" _˜†gÉ“TÏØ ¾¤Éo4âZ–µ§6ŽÃü†°ã­9ì4Âj+BYøø\! Ùññ…JràC,/غ/*…î/½û‡—D}ÛœßðÑýÝÒ|¾\5¯2ë¢!/þ·“¤ ÝÞ&Z¡?ÉË I6\¹v»Ê‰¤ÁÕÖðÅ¢¤å],ÎD÷Å¥²·•%•ðz[ðRa¸©%;ˆi^pS w%z=Úª¦û’RYc¦IóìU}„—–®qá%”÷bYö’ÂVæ ²ÊÖ䯉5èúrÎ TºÞ= ógb2+ ÜŠ1Ñ Uæ¡Ô“oo1”gÎf•C¬¡Üð…ñNëÒµV¹ÖJëÒ´ú؇ÖM»Gs¦½º+ÿ1¾¼xÔØ„€G­[¬r“•CùÞ:k*n&@,®’ð&à–æ1lòckœ/aO}µNn³ªïìêŽ;̱Bçz»5šV){*üPBU€І;à!ø°K!ÊmrálO ¢l g~Èýˆ ¿nÕ“ÑÊ?îÕÞzùx\é?°ºc°{Â÷©[T—@öOT—À²™æ0{W70h¯²PØÖî•âòÔPcT{ëä”ÞgÑl)KÌP'ñ¬®,ê°¦Rû©ü)%XË êåÏ≪åÔ>?ÆU §ÆF~I |È_C9m‹[·Zm?Gö/šów¬ć•âEž^’/AQøæää+ò• 5áWiñ¯:F_Z§+\ô$:}ÌÈqø»ªýÃ[:Ì×RGÖþ)ÿE²y…ïÿþ›j°NÕ€-ü‡¾×›5ªþÑ%T™Ñ%ÎHUµd‘OE|÷õ£JµOšGæBÞ¼_ªÈÒ§Kxcº &µx{t«[·';³²`ë….u§±+»XpâJ¥ÇƒŠ£¶ƒºècÙa˜×³Á,ìèŒÂ¾ž*ìX‘ð­(µ* k†oe) j®?° úûŒ ‚‡µ·„W•"O9f>(µ„W—z6VºXnS¥u2ìÜQˆBeã£UÕMÊ©Xº Ó ÿƹ‚o%k:5ý„;àOPÑ٬糺‹e¶ªÞlU½9l³bTI̳¹Ò7ªDʹu›—ªÛü$æÀ¼–ýVÛ¿€y‰0Õ…—(ÌKæ•ôØR©¯r¥Ê`c*ƒU¬†{áßgNÕ„pBL-wœrüPøkK ‡QKñÖ‹x4óvj\ˆØ²™öz_A!”à w[¶¨BlQ…Ø!äPëc“Z1CV<]Ç¡ÁtÑÙ}M©Lسb³N;Úº¯-å¥Ô‘ðl«¤/¹„ˆWíƒ÷ 佃ó~yæ¼Wu±VyVy+*¯g»™÷ñ4†Àu[ C¾d ;*-_* _* l"Õý‹‰Ç|«Ó£{4Êy ɹt l Ùˆlbn=›S>çÌÞžÅ|àç"Îqž±J× (RÅ+­P¤JTÚà“fÄ#öo„¼À-ç–ûJ€Û ¡. µx¥}™mʨ/ÎBq>OKíN²Ø7Pâ$>@í²Ç}µè`—q”W¸•‰ e•[U{Žy£ã£JGµ&«µŒû,h`e…Ü1zk ‹0ð³ÙM„÷Ãö]Üm¥^{’GþXµ}޵¤‹öˆðxá'jr¢ÆvgªÓNÒÒv²FÜ>$¡`LIÕ!·!§jA¹C¯ÉäsÔ=“Aø>,µx.ß:‡åÞ™”`ÅaÎTokpóQã/äÎÑxˆ˜ 95N0›Ï­¿HS­óäG,‹T©/ÑàzÚëÙevÖ¥µ}*÷I6šeZïÝ×—Ê÷ º-Ût@Ô‚kJŸJ,SñrDÞ–Ýý£Røè ooy{óÈ«y{v÷ ¥r5EÞ‘üF/*BØ„%ò»o,•jßšÖsÐn8|¤%§ƒ Zæt°Y3YÙh§ö?ï…v°¬´·Ò²Cg,6ÄM™‰SÄ‘b§`Ñi7§ØWiÙ­RìÖ°ÏLãb?‹ýìö›yp%"äÈû+-)òJǧ•ÚAZ0h±‚l”2;Èm°K~†ý{HtÇ5È`õn£…ÕvÚ L JËÏ0§®Î¼W5?lPe£E- ðÙÓYàQs¿ÖHa÷ëçèñI£®å—YÇêØ„æÁZŸÿ<öÓ.j‰ð{6µÙ€í"ì1(R[ ôz²¨ÛC—´ü!ˆýõ bŸLÇ>¡b_Ñò¬MI±Ù’_Å»Ûøê‘#¿Ò”îA(§µÚܸ™w·<  ùê@{š#§Í¦&íçMM½›šèM6i4k ƒôÑáyðïƒÃ޾:ñŸt•ñÖC•`9žÃ•ˆè;äÔy*îGéæ'Óõ¿QºÃ*Ý¡JDL¥Héæ"N\!çH%@©C(ÆróTßà‹JmmÃt9L›ÆIì°a/|aûJí#u9Ræ…×»hÕJ ™ñ¸í9:×â뛣a×k”Ž‹Ë|j3š3OmÊa¹ú†ž;œSuV©ä;Þ=‡žJ˜fè°\>‡à휛S0¿©É‘ëÈ‘3Í$(î,.î±ÊPVª¸ïèÊ“ ¦k,=%νT¦Ý,ªMfö¥lXPφñŠ%]؆ÅkÚ2ú{¼RŸ'* 8JTZ?Öå2ÝìØp]Ä,s%æM›oS©%øuAx_KW‰rBT[Bcî$9âÃÈq? ¸3UÜ7o ¿uÇ]mÆ=Õ<îŠû–Š;ý¦ð w­÷tó¸õ¸²&É7ü7QÝÙ{Ífo¥1ðc= F‰0kÚäV4#n¦|¤|2‰o»Î¦Yö¤yLœ©´¥Ò×™ÇàA<&®ÃÊó˜]:•ës“ÇÔë&Ù£ƒÇìå r?Óû¨nŠõ|¢óšå¨™@ekÇ`z÷¾0YÇÃ3l1ú/G3Ÿ *x¾¨Äwí\/OfÄCqÇ$ãžBÜ/+IÆ=wŸÊ(V¥þ….¿ÐkŸO$‡I\V£÷4TÊ3DŒ©à8_ê|(ÔÞæ>ÖÔäò0¬w¨‰Üd%QÐÌëlF^ã(¯qÉrCÌ«mIÆ=Ÿ÷ ŠûâBŸæâ6VœxSø²{öö¨HlÖs¶²wÅE×6ö¹áBc"‹!Mº¹!+ÏÒ¤ó,‚ǘG´^D÷ ÷ë½ ˜¹Ø*†c¹šzÙÛ …kÂ7Ý*ª¦:õ» Ìÿ} ì²U-ÌÕòùXðÚÃÆ8dºÑ–ƒâ]F4½g+ øƒ ø<Ã$7Ê^û¹O}eÍûK¼–Ño4ëÔhc 9ÆÀê‘χÆ2^9ªã#¹b–kãK<‹Ê#ãéóÝrýÁÀ„ÏâòÈúìå1*Ç‹<½=‘ãET…rk×ÀÄÏÒòÈD }¯ÜöãÀ¤ϲòÈ$ú|¿Üþl`r‰gyyd2}®¿Û Lr{>º;2ÉÝ V”gEo”xV–GÞ ÐUåÙ L)ñ|P™BŸ+rrþ˜ZâY]™JŸkÊs«E`Z‰gmyd}XÞb€L/ñ¬+Lîò¼"0£ÄóQyd}o(wŽ7K<Ë#oÒ÷¦òü©"ðV‰gsyä-úÞR^ð¶Ì,ñ|\™Iß[Ë ŠÀ¬Ï'å‘Yô½­¼è}x»Ä³½<ò6}ï(w­Ù%žhyd6}ÇÊÝ›EàO¼<ò}'Ê‹£"0§Ä³³<2‡¾w•—ì¹%žºòÈ\ú®/oyHæ•xv—GæÑ÷žòV'E`~‰goyd>}ï+o-E`A‰gyd}(osI–x>-,¤ïƒå7UkE%žCå‘Eô}¸¼í-ðn‰çHyä]ú>ZÞn„X\âù¬<²˜¾•—ŽÓKJ<ÇË#KèûDyÙT-°´Äs²<²”¾O•ßü¶x¯Äsº<ò}^~ËB-°¬ÄóEyd6äf*ÜŸ£É¢×!wò’$AZú·˜ºõDÛÈ '`èj‡ÝisÎGܺfµÝÒx¾RºÙÖQ¥Å-‹±×U b¾ƒE"rÊ)[Âf®ND\ˆJÈvÁ'¢áSNßžì­}æ†åܼŴ=}‹l1¶ßܾ¹ÅrÌ´=M) ü§mOOĸ8éœMéºÓ&ºO¸•î¯*åÍT‚[ IrÒ­,pì¶h'Ïê.Z¬§TLE º“RŸF–öïP–hçßÚ|_ôôÿÙI¦MîÖˆ‚Ü?ç:³Ï/Ë-å÷Kn;i¼Oíq¦\ÜX^ÒÞYŽÖøÂ­Üè^ä; ²‚ò%è—$6Ûìÿô± UÀïI"ÝNv¾ôäÓÒÇúŸ/ëö¼ˆ|á”ßk¦ø}ùýL½À(½Àïeèþ(hÝ«‚s/à®ÚÐBcÉgXY3„"ü,£¿”¿@´2ÊðÌÓò—Írü•üUfŽ¿Ž³öÑ/3r|.Z†‚ú“Zxʪ!Mƒ²Óà÷±%(šh5ô£z d C[nîBÿÊ1Ð?·ÀɆQ£þ¹ÑnrE¤.»HêŸâgYMø$y#©¡×?·§2 Œ×ðéœîQÔsLú?#ê ÞkXs¯e­ê/t3xÓHù dóų„r‡ã©·E¬êh ûÙ|GźԒ•°æfÄšG±>kÁšù±ør4¹;çÓu]ŒòÁÛüÔõ‚Û0löG°ŒKÓxŸe™Rü£W¡¶\ÀQR¿m'ÌPg[ô_ñe”ÙhÖ$ïÞ,5Y2Ò5 é¯ô„¢ðiSn=ë—鱞~2›Dð“´"¤5íOœ n6K@‹HÊ¢0WÆ!· ¥Œ¶#í˜fÖ(î‚f±jÍ©PRK È¹ÅŠPâzPd7£Ušs—¸‰â\}ª±ì£r®}Dìƒ}Œz3dÿT<-‹ ²l–­<öú6¶°¤]>Ÿqöd‰àˆP#àŒ³ê#GE¬·iP0†µÍS8Xã>Æãé87åajÊÏ…r‹˜•Ψ'ŸŽ~É…gùõŒˆ"ïBÈtžugQïËÜTÏ£j¸j+µ\àk.-÷ixŒ©Ô±ïtÞj\MÒ”žÚeaê¡%|{ÛVF»"Òî/¿IÒú*h ŤkÈók·‘e³¯Õ‘i/íÆç£OÂ8ÊîÛ-½4>Ń:GMöÑ2ŽFûjß:mcöÓd?­Ù!_-}4Úh1F‡j|4:\“CµëŽF‡i××®;¡¥FGkÿõhôuíº£Ñ1ÚuG£c5lzeŽ×¾}4:IƒåF±ð›¢ñQæôæµ|SË8Ê|Kã£ÌYeæ?œ£™G™™¥Í£LûÊ\ aiËG¬LŒE˜Æ¯¤9)¼@Ëå¬4ù ߃›©†?›£¬+û”½œTÕÙ?>çÞ;ea; ìÌ‚dWi–IQÑ` ;‰#!151¾1³ÙÌdbbŒHÞ$o²4—"½#e)‚€ˆô"½ L]šô"ˆìYÀB‘ý?ßçÜ)ß¼¿ÿGÙ;÷9çyÎsOyN{JÅÝ5ìšúC Ey¬4»SÛqBÔ6q?ÊÚd]4¥¦˜l•ZU“­DÙÝ•„Åäbl.–ÄV­›4m¥Båv-„zT+÷M;pÒÃö6¯WeÁŽ#wªŒVD¾ýT»4LÂ_ÓÚÂáüØkÖ_\“{5Üìsû(Ÿ¬Ñ”o;D·+ö#ý üÍL•œD•œâ"ê3Ð €~ÆÐŠüTÐM‚ßÚ•5Ó¼0™MO^GføÞùPpب¶›ZéJoÀÑ•4ÅË¢R/]åñ ¼3ºŠÞë:hÃôÒÕß ;£«1é÷ÉÇ]maݨüô F 'š­ÊÎ6ˆLný¼‰Ù7_i»R¾·o’h[——ýòIF¸~ø:‹[ÚÖ‘<øÌ+ð8ó¸†ÇÙÇu<>yÜX'äºÞ0x½¡6±ìppw¡$:Ü-äCâ; ¶‹‰MË·íÂe@èFCÌ[ÜT1˜ÊÅEYenþÅ"+1Ÿµàó ÷¤‘Ü·_AuŒà³Š’±_w±ÐIÔv¬—Z抗¹DY^%´G뉢fòµõÚX]ŽÕÓ–58Ÿd£‡ñz2Rm÷Õw±âƒUEöù-w×£x0ŒÜ¹Ø¼}µ¢O±ím]ÎÒÑ Uªš³ÿ°ÙzQW9' Ú¼tšçBßÙ¼ÚD®œ§ÇYˆ¾«Ç»²wÕéüSš7ƒvÖ{”u:ÿ"+ÿû”_.¡¤•œD¬ÎרBÆ0k+˜µÆT#}‹m«¨Fú‹ÕjŒÀpì¿O®¦’®5Á·­Ñ½îu«ð¤yÐåü+^©š§ûkëu¹ž$8.@Ü@œ`y³QOÆ9*À&=ÙUn!¨Ǥyê-¯«Ü¦Ãû˜|˜BÍföªš£‰1/esônÛA]æ7ý;Š|£X!Ö+‹µcº<’fö¨N㔄ö1 R#ëeIŽdP­«ŸÒåI=4ÂÙ®d„SÈSz¶ Íioó¬uÊMG/vDxFç—’].þÁdš›º#ø½À‡—Äâ]^´XÄaœ´X©CQí¹¨Ë@—-þïõ*£(¶]E ÷|q•£œ·+Yãò†Sý¢äzˆç%«sàv—(Œg O‚B?âÐÏ` ý ù†aQ¨4b‰ÈåÖTdJê’ƒ;O¦:'\˜K¼¡)jCµ¡†nÄÛ3µ†5'2æHRžác| s¼Âoȉ)>Þú?ù˜joeêezŠÚtEMéö(j3S³ U/³AazՋ泿ÞXa Ó™¯èÌ7äBsGQSO/âß|èºP©øã½­ñ÷|ƒŠç±ûÅFœá+7Ôö%«ÜšÚR .Ö–r™Š†â…ÈŒŠn±Bâår#”(dq]’(Ôä*‹áÕl›š™¡Æ-×qÀñ)èF@71tj>ôÐèvÃÚ o7x7¼΃S»á\V­V;à|V¬Ní€1¹ì6Ô®w‘ÚõÆÀHU> šx’‰_ÐlICîe7ÈÓòSº1]‹P2k1ö:ýÿÂ¥ŽÆèXMÏÇA(Gž½ÔÁvWéïr‡èZ]é î-]ëñ}Þ!º–^¿è u,ýÐãû²CôC¬Æfäg…õZÌ‘^ßÎO‡ÀÚk‡M­¢}MÀPâÌ|›0 ,Hæ!»ÖŒ²/Ë—ÍC×Ì¢ªD´Ÿ©ÂþR¢agƾê`û^é:ïj‡è:âäZñãÒõßšüèzz½ÞA{¾tƒÇw£Ct›Ÿ¯‚M +–/Q‹ü&€Û§ù82kpÄr«‘¿¥a?À„ÝMéuBê‹ Ò{¤?[H–= i e,_ ƒ€ô~¾ ½EàYHÿÂaL<:X‹ó §ÝñK$H-Ãà÷êx'ljNš±3¬º» <äÝö«Þ°AüB!(ì °Û‰,Žph­÷C–Èכï$ÆîFÕ 8Ti–]/({㎲Ê;P!`ߨ­ÒÄÒxI~ê|P íã†Óèÿ¦á|°Ò­²4?s˜¹,šlê†ÿç`ÌñèS~+–ˆ59ó0“0/·jЭÌCP{+2`+óP€W櫘ʶ03o©Ìï*óªLf+ó7fV˜Wç#äe¥@î‹ÀŒx—XN‡F¶ŠG¶=!CwƃwŠžÿa™‡˜ÿ),óPó–°ÌXš¬áþS~?ó¶ÇäÙTãŠ*öÆßãj“]²ÉÆY$sõÉîÞÖ¦™(7Ug§£‘/7üa~Æ̺|h>_7¢8ÛÌ»EÚL‚W[ßÅ#WEt¤)@¿®‰è(ÓÄ⯫‚6å|Œ)L}a‚)Ÿ†6l¾rgBäE-U‹L@koȇÀåV”ËîÔ“í%ÄΠ½Bh¯Æ"¶)ßNÌ®×ïÁN÷á7Ïš¶ð$1ń뚦šr«2æ;X$É`f—MΞª¨9¦™Ý&›vbpOZRPöΡý™éàmHŠÉüMh‚¯ø j€ßÖO”n÷´©n§jèCEéïp~tê1N³…aïT7ª ÞTí÷ Òâ÷ Òbÿ{´{-•oª‚é&Iìdt†)¿C‚âm“ã™'xâ)zgbÿ±Xd¦‰] žýù¦k‡êøÉ|(¦{ïIKr<)Ÿ"ª3MÙÊXù*Ô;¥?Ctž‹Ef¡IöeÐJ-´RYFh³LY%+îkw"ýeBûC,2Û,Ûî™oÙKÙÁÈl³´¨2”zX”zð’a¶ÉzÍûóSßGatÀZ#ͤ5Ò}qØüŒ§¯ƒÙë¬ÑÅì[ëPšýƦHÌ"sL€@ãp~æ&ïã|lwLñ-Áv¯wNÛ=’¯®ú(C:ØîÑ|uÕG0Û]Û†ƒíËOÛ%x›ÐÁo ¶;ÛºØ{™ø4ëƒNä;ótã†Q7¶ðEã¤ÜÛÇ»·íxèÖxèïÓúñKîŵb\±¤Qð°ÞµV,*4~X+Žmäƒi?t]˜œ‚‡]ìê‡xÁÅêXa£4<p¦ÿ8lODŽºš@õóiü‚;^¼lc[ˆÁDØ<â+݇éCòYhehw—üüšvÏ‘ÏSݘ¿eë¦ 5x±V$ †jÅè‡sKcüáF¯É ¸¦&H7h#ªn'î”/ÂÊ0ì Îk„ËŒ†2vµ N¡©ƒ*Sþ:좹áX\aý™ŸGó2ÿ¢?Uü®€%Ëã·eŸÊÊîÌ[dPVã6Ý­üi/q ¬tE6: KÞiä¿E(¾pNŸînèä„Ýa³5šœÄòÃ'òtó@oµ‰|9Ü$œ[~¨Pþž~4 .ϱ•.”¯$-›»ßvt›î5õõ.·Ë”¯Â@©|L ùZØ…¾ƒP™\Û=¹ žßÐ Ü lÏq³^öÂ)ÜÉìaE=ñïÔ3O¥·/¸+ô±54çиšk†®|:kqt&_w8œ‘º‰Å2`-ްèô·®µFoæêô÷Rk#€u-—‚eWá& Þ qÝÏïÖÏ!¢ïb}”ˆÎ7e7Hí÷Lù# °V"i¾P-–ÎZ«*îy¥/Ä"ó!»>±Kþ¥5›ü’VSqP !Rgv>2‹,Úù ÚËÚË$Øâ(õ\ÆgÐþJh‹EíBíÚ?h‘“ÿÂ%|¾º”¥ô˜hѬ÷/2bK$¼™šõÞp Ç÷Ã,U›AdÚ½DÞ²ÌÏq9œ3t¤Lê¸Î ëûšòCY+F¶²Ua>l*àæù»ÚB8Lþ®þBqƨޣ‹L^Ǽk*m¯ºŒ™ˆãø]û,öÉ{îìÒQ{g‰ÐkÂh¾&Pæl"®¥®°Ãâ†ÍMæ±Ë°±y8à[ Êîç•Î"ÿ‚û›ê÷WË…"™¦W4¯¡µPRŵ0àp¤À[ÅŽÅWÙ”$†r¤çä|×ÅQ7àÑ>X×Ä6ö^÷°= Ï%“áe`ƒ˜e‚czr)ج`UW …§|w%\oQå\v‡¬bѳÐMÐæ±Èžñà›^gô}S®µÜ˜±ºà‡Ö UQQ2_À¢kǺ|\¿h¬ÍÜԟ׶•Clõ£m´>±j‡k¼ù>Z§(G÷Õr;ÿJ]›ï ëj'Çes°+‹ƒzæ`j߯˜©‘¶j¶Š\LÏÔ.¬Óo§vXÃ%¸üXÄJ¨%q“kñCEY¢n¹X—^N¯K ëÞБÛÖ¥ïðºt÷ZHˆ+ù IBœçëƒÁ~[¥(ýÈSf–E#G ƒS[ˆèG´òDûçÊI¬‚÷”7•GãôbÛLøÓ*ë—ËÛÜéâ)8Óbwi3EèDa·…¶Š…ûH–öËGû弫d û ô7Þå¯hMÏ*%Dz‘¾»÷ãDþ=¸É$òe' +™¼b.5Y—c…ˆ…ºuëf‹.5åJ¼ü­\¸ÄSF¸MZKBàda[Ó5qšàOÊu=•‚®gè©B³«£æŠÍ‚'Þm¼ n0m=«iC:‰¦Õ[E<*Û(u=¥Ö°¨9U˜äÔ"ž$j$C RµÀ§%¹ÖÞ.¶ír|¢ÍÛ'«…²µ¯áÐÖ|i×/Wé¸ì·êê P6÷×ø åŸ uDX'¶°ášY,NÁOVúNcŸÈ×ÃJŽÅ-’ˆX˰O,˜3m£ÜFº\¢å/håŸí'SýÿCþŸÒäe¦p*‘ý<9vÖã£Êø‚µø¢rV± bg‹¯è1§X»¦É¯èËw5ì_-¯¢]H°^S€y]K$ç¥"¿´8ïgÖå×›}+y±ˆá®BOª¯`½uZa•Üh$dúÚÖ°l[ÈlÞ¾},Iô*»mkè(©Ï²?n ûgºÑxÚjÈ z,² Ýè ¶#&ò…ä§lu9IÅy‚˜¬“ÎÃЬÌМ šóˆæÐI@VXx`ÐÛl=J›ö"a%ì4ËLxÄi÷"­iû™CNU¶Ïù²A…‡»,ÁÙZ}° JUܸ8¾{ŸüXQäåC³×Q£ïÛN鸎ìNÁ!ˆŽ)fåqz®5Ù‰+P^,p‚~B‡Ÿ©Sz,XmÚp˜ ÖÐXÁ&>t'Èñ™ý>yZƒÆ àNï*ÏêÄ,¸À;,  «â1ˆÓ…ÌéùT5Ÿ‡aHŒ3ï¢ñ9]‹®2á'+ÜAZcÔ*m'—Ýlò5óJ3­ùÍϨgFË嘮Dã#Ó†ì—täA”ïj ¯d×<Ö}¬ôYÑ-¦üÒʺÅ,ßÝ@^GÉ4%î‡å0xøASÍô›áêÒ°“m¸!GÔo°še|S¿ûÆa™– šã˜fº¥÷f·ôjÕÒÃånî¥@™D(¥»º1Êj€ÔUNa8tb˜ï»€¿]¸8ŽÄ¬ó½˜ÙG¯í1¡Ê>’EÛw‘uÉÜbÛCÎeŒxSTÒ»ôUÑÉvBÝg¡fä÷ðA£2•´…mHq1š+©;6–ŒÞdÈ-à7IšÜèefeŸ}r+ãÄy¡²Å}hÊéâvZÅ}ôµºLŒÉ0qL2Ð)‰‰±™„›H€“¦-H—½á.®™v[£q|ÖÐêgç¡UiÏê:<´æÛ†Úå@{Ö³ƒì\²lÿ_‡Ö›v ­¡vÕeyh}dÞÞÙih ³Ç6„hh°Sïx·†ÖZ‹˜ÓÑv«'Ž¶Ë±ö˜Êl ­Õ´îµÇÔX¾uh©Œ0Þn -—5´ ŠÁ5Ñ®1¸Þ²gFÌ${öˆ™š]è7Óì™q8Ýž=ÙïÒD¨«™õ9Ìú¹Ž¶9öZ±O íraJYÏÊ’Ã4¢æÛcí°ž_È„*ZWË÷챉¬íáçîXÝ/VµŠ{Iù=‘*q‰ú/Xñ¼Ü/;]¨Â ¬°ÓàÝj vüR‘饜û0n/öq¹Úžh_~¶@®µÇÔlÄ( »ž {øUnÀ÷½Å#ë[ÜýSŸ·É.·P¶Ý*ÛVd›äqèÖJf;g›_lÛNµ° Xì´ËöxäLaÅÙÂj¹Ûž(Ó"ŸÆ"ÍömlíJ.5²ËÏð@˜ àéÂÈù[¡{QÚdîÙ?EiÕ©Òªíò“&_r¥‘&¦`Š:Ã)Xš8ƒð”Ì8»€át‘Ú錳©,º"AÚ-) íðˆÔ®äUÂeªö覼b·6`\5ŸÛ¿i¨’ª<´IÊïÅz;‚(u7`îV¬×sÀ$ ŸÔZ…Oò©ðI=Uø¤0‡Oꯢ'Å >©¨âîWr¥ßˆ0%_Ñy-_O°éQÇæGµz»ì¸D´Ó¡• ïoúÐ{ûWtÙ~ôMÅ|³‡t›€Œz^;ú9ˆ~¢"À• ¸+pȹ!Ž$"ÕöÈQ7•C‘ÁQÔÔÍñƒ9ÙñR¬X0ö¨¶ vÉ/1ê»ß69Æ¡v»c)O¨g·ž6|°œäˆ!SÉ!¬dÒe†–8½•…}ç:ûöé Õ"«Ty”¥’êGNS¯9Åä[RìÓRx–£,éÉÚrŠb½dËÒûy¥_MÎWéHL'ÈEà‰`N%Ÿ VÒY •ÓRN¤Èeë‰õåŽ-œ¹[¬t@U>æˆÖÔÝ~¯ÿ¾W„\ã69;$ÅZ\ҭĆ. ?t„¶š´Dz+—×ÝT]Ü­œ¹nJ}8ôÉ_i(7¿5AlÁÖ‚©l!bj¨weÇíŒÐzqŒßw¤ŒTö”=®²ãúvÏ-Å(Qñ#÷ªž³ËÓô¼œ9”ˆ«áo·CÜâI2®'n(HfCÖí¿-uw&•ÄßA‡šT°`>ìàŒÐã:Â?•8¦j#‰¶»ì$Ù¿Â ŽF6›jÛËY13ìj@3„çy‡’ÿ8æqšèÅÑEt‹"º[½ÄD·(¢_¤‰îf¢$z¯©ï@ Ãk³¬p¦F­ðA¾¯3Vò1ÉŠ~NHüvºýi[‰^¤ó È gŒÃéAš q>%¦i—õkúŸÏ4¼Ph9¶Ï mZCÛÅB›ÞÐV[h3<6Yh³·¶ÕÚ>Û¥B›³§ír¡Í¶])´å˜¶Ï m b…¶/ m ï¶Mã –—kÃÖ.¸SŽtÆâíەȆºåÄžFíÿØ2h:¯,^Ê8'vNÕ&˜>ÞrfæÄIÎì9qŠSU2rU93“ì4gö$;'^3<ºá̽È3çlg*ŒÜªb1Û©dfE…Ûô¨m¶S¾«jv·gž’VŸ›—‡‰nŠçY ÊEN®Ë/ mr±AR‘Ñx¨!èÙ«º1ÖV*ÒqOÓ_bn®àÃŒµ8Ò]>ÐûÐ+⡼ު t NÕëäFëËÜäT½FnvfO[íºŠçJCªQsІh6­§ímžÎŠQǸuÖÐ~Ç)O8³vûXqtòfÆ{rT® ›gÙ¡‚8ïþáK”m&ÏÖ~P:Ç”úÜi;生ÞNéSúŒšÿɹP/žå1œç>¨s²CZ\=Úꜵbm±ø‚k_ÑC>ª#àï©"£/=nÜgïï’—o§…éáL·]E††‘¾.µ°ÂÕ¥¼ž‚õ¯1qñUïdëªàî&6˜›»°nÆ^¢_näD«Š†chxnpx®­"R º+lDÞp!ÔÇ´;xMšT®<í7²ý]$Pº;äWRi†9i +ìH´ÑfTQ’ù†žJ¾ØÂêZü6áŽì·Úó8æÁ`àQ¥_q•”-8’=¦qÚܾ‘¯ü6ŠÞ¨Šg{p/øwÔðd—Õ6“]¨eÇÅŽÕ­t߃³Ñ?ói¯ËÒØExæÏ;‰$Â3gkìV»â%g,ÝW¶Æî~J9ÛÈ&º²%¬ê[V¾y,5¹â±’/ y•¼ÀKÂã<"RéwÃ~ðáTluªñ£ªÆñøôQ Þé§è1çAã´KwApQ9XXfJæ Ð nÒ''äê$Px”ˆóYjâ¶í§Ô³ÎPÉÛŸ¡ô5|ÀÛôâ‹lB¦ÈTç4ŽBwZg»4'VQ7”Û"û0ŸÑãpGçE—¼à²Ž…1.>sÅSMº;ÿ™Í;#WÅ4Ö«uÅîàñ¡.‰Øc¼L±™’*=쨚†2[rìçìäÍYÉò õ–GO¨…á=©zìTÕÕ\Õ׸¡{?f»¦ª÷šªÞk\çú5¨F=Ò³Wä ²½sàmÛ9:GÞø_ëîk®ó°ñäÄ\£«¬weŒI+r”œê“i§ì“væýƒ9ïlÝÓŸÀ¨| sa/"úD{o;Ò¯ m¾Q¯Š6¶f°9„) aŠœv$#§[%#gZA2ðMv•ÃT^ë ŸFÞ–›eÚh*O9ëvÉ19aœu'óy¸ÍápŠÈ5>‡%ß{ž”- UðCײԃ:¾0—/Jó‘„{ÒEžŒRÐû8 ½§n}±lÁÃÏnkQ+v¶-dKÜŽÝA{®ã¦lKDO˜ò[P£ö(E.Â(¢áM+µãXê~࢖àÖ¬>\=iÊv„°$ƒÐ^iŸÂRJþ%À÷¡ä9ߵݭ-qô†O˜Ê¡ª;£ˆ?Ü‹u;NË"ý qιŽÀ”‰àB­üz¡|°]WÙ Bg™'¥®E…4 }mé•Ì­¢]Be,g¾9”öd¿­°ô€Ç·ã®èÜm®ð@aü'uY{‹•}¬ ècU@Ç—¡¿KïB¼íõ÷Ø}ò;Ð9cËa{ô¬Iü†ÑOLy¿¥$ؑȮô@I¼È>Dõñpèt¶>à39Kÿ>1»fñU¥—½Jý2€,О΀Dà :ÌðÏ ü<AÙ“R,¤„;B73Š…ïB±ð´ 8« { XÈ 2Åo»·ô §¨ü §VLõ‹ûJy|¢ü¼–x4_éaJ:ŒzZG}H7Ú×m*¦ï'Ä Ûwh+\,üÒ:æ‰yDE¯jù@"22}&'+'Îÿˆ|$;ÿ£‰ÈäßÉÿ„•ÿ ÎßEvÉÎÿýDd2òoÌäÊÊÿçÿ¡üavþ'heíeZêF[äÆÊÿŒüYÙAO<Ô«[/[y}¡ü9Þ"õ…PÐ¥õŸnÈþ_Vö_Ë_QM…ºvëj£Ú’¿}ìñmþnðc”³O†ãÊÏ~ùx—ì/{ïŽÈûw”OpÉ—â*ÒWùd—üµÎ)ïë’¿ú–âúËq5òþû,ô?ÄU°/ ¿W‹/ ¿ t’NúëYè=²Ðÿœ…Þ3 ý/Ô¢[<#ü,>ñoÖ'þ­VŒxLü£Vœï¨ý<¿nE[É6¬€úWËÿ¡ JPUôª‘ÿLÍÃ%<¨¨\çö‚®17ÎK ÝGX´ûnžAŠÛ-ÇìýE舧äˆ/ãe‡@”ö fè(µãQÕŽCõÅõE9TPS•Ã4ú·±èi‚”MI4ˆ¤íYpG&+\OÊ©ÉN†7.Vc‘OY…ØwÎO:—ÙßÔÖ61Ô‹Å»ê×#Gš!/Ÿ¦"Ì{"–P~ò‹úã<=s“触\ÄîV3¥,æR. ”Ý™R>H•ò*e)b_Q)G›!oº”•ßXÊS®bŸ¦™RÖp)Ÿ¡”X¦”µ©RÖªRÖ! &•r²ò¦KÙô¥|F›0vHš)e—r¥$2¥lO•²]•²SÈ(ek3äM—²çK¹hÊJIzRÁv7AY°¢H õù$ÔÏ›€M¡Þp{ö0÷òTµú>âý|·n«5³açZq­Pt†ï¹Ît£wFœ£³|,?aû ù½X2*MÙšÉèù6à§c‰Ï­ñÀèÑp‰uˆYBb%´g¡†ì‰ÚËHÿ9›˜V£XÛ/ä/BËìÁev4²þ+´Ü/YnòÅX¨1âuk,¢u&bëIN:jEÍâ×$iR©DH–%\òN!Ëã „Hz jaH¾9] È(Ç/´½,_Î*îñPãX¤Î$2@úch•¾‚Jÿ“²8ˆ*wÀ¥‘¸'Ô§(KkŽÿ^X¨ÌÛjMdÁDrˆ'’Ÿ°‡ßVTzÜã›é§Éc–_Ü[zÂã›íž ×9~íÒ“ß;þèIzë×+=åñÍóGOÑë»~ãÉÒÓß|ô4æšÃž,õÑíŬZþ±'¥>ºšÝ}­Æÿ’ ;ód ¨ŽZ“äQlJMG½ï šî˜G8ßÒ Ï—Ø´Ã6à8§Þ…Ô–µ­‘ØNÉ¥ü=áŽ<Ž«²eˆFY[YY[ÉoÅâÁ+&NrñÖ7Pž» ›ž  Ð$Ô¯(m#´ˆm„LÀY 6S¯ ü¶o•žñøú£gà0Í/Ú—žõøù£gá0ͯu,ýÄã[ì~B¯øõGKÏy|KüÑsðæ7~PzÞã“wGÏ£^Ïd×ëš8¡öš®Wä‡ú[õú>Õë&`à瓬AuΣŒ2w¦lÅXžghC@Ù( +³O39ý´ܧËû¡âš>H9*[KÍÏ2øô»èÒ=°å_-|Ì2å¿£Z>aùÎqZ¦ü)§8i[üþ–i?­² û‹ãmlM_¶Ìô¿/¿Ÿ1Ò¿£dƒ$ެ V Ó‹•·žjß•––>bÊ¥­ð¬Œð›²¶ú¿Ùàÿ„Ö§Ï¢j=©ô…¡7Šn³]¬ÕHF]Kn{6¼Yæ·yK?õø–û£ŸRs®ð‹‚Ò ßJô½®òk-J?óøVû£ŸÑë¿Þ²ô¢Ç·Ö½v~ãŽÒZoF‡h-½®óÛ[•Jo½?*Ñê²»ÂGÅl3x)Ý>BW¨´ºÂÔ¾2{—=ˆ°à{—=¶v¥už2³í|ÝËò:P¾ây`aÝE-ˆý²#¦ãbí¢×Mjo߯Ñ&›³~nOÊG+E®c|~aO?a‰Ö'` GøÐ¶Ë  é©Xä¾Ê uµºÂ$ŽÊ‚²™6ˆú´ài ð´, m¶—l¶ÛäO­`Íp€@’ “ük-Çîx_þ‹æÞîFQå¸×Û '@.¦û"–N"«3­Ô'dˆVM¥qå(¶ÆœÁŠÈWìzX†“Ö¦Õ€š$Aw6~ƒðföWåo’‘ pìEÀÖ­V,éì q¶—Õy‚Z ”*vúDpb+¼L„íUTÚ«´1É…–µCþ)ìpãñ5xÙ”=ÂâBv7‡" @RÅN«‘Iò‰Ü_¨L(KºŸ§/ÛjÏ{…ï*vþSþ3Î××.ù/Ú«~h\m\ê¾Ý²«ç ‘&Ò—×f×=)§‘Tyw†e9\™wÕD :Ö OƤæk²˜Ù]LýÇ/`§9e1³›7¾UäÃÐL£¶uå<hgV>ª†³ÓǨK•µŒÌñ²[‹PeEhŸ|<^Ô¬µR+ߣ¥TŠªe—ä'pó¶×¬?€Ag…WÓ\9?eîSWì¶n²[ Áè}Ð÷zÚŠóÀѺ÷ÉŸ ˜;ËŒ’?—µXÌ61ÏøQܽ‹*ô9µÞ^Ãpå¼²¿àÎTÃ>¬~Á.¬~A›xâ'ðôb¬¬AdI~´Â-CLmÄrZ¹,çhÚ„*»'ÛØîeoL,t^ íhÄSñòJK¦\1ý.~¼†Ã•3]CÙ/§¢zjT4û œ® ¾“ ŒE*Ü\x³ÏPäúÖ¢­à[kƒi­Wëö×bÁ>nêªG<2¾t=– h—|Ûú^|XÓ+–ˆ ,¢Ï0§´}õ¿É¿¥ÅrwCþGü”Ü…‡ÁGÞ‚ú‘Š2ÞÞȬhòÁJðHû‰°66° ÛƒýÜ@¦};Œÿ'l…¾ ¿CÛOÈ.ÖE1.ú5’¶xwËï¡A^˜0ÞB¬]Co¸³mÚݱH¥»Ûn~ö*!WV~Ï" z]^%„ ü{<èl{N¢•n(OeBÊy†f~mIî_³ià ó¦LqØÃ .JŸh,‡ðxà 8jh¸7³ðáUk¸D1-úÔ¬™Ìç5Üíž;Gz³i”¿˜ÒeÀz3³H[2ºG™£½[¥1^į.iY•ÓNã1Ääô÷ü=,ÌaŸÔ%–ˆkHõŸŒqSõ‡þ®nÑ7U+Œõâ²Ð:Ö~c°7hxÂøåœÎl¢DŽ2S+€î’þùN `•°+µ66kT`T«ÝIÜ=žýˆ_à‚@{Aþ¼ìœ€èúE,rÁ_ˆE®‰5f”Gâ›]ô9Úð¯ä‹ñ;Ó£ù«¸5Á ÇMI^®XYjâþü×4Á^Ì#ÖÏYŽŸo:› _˜õcº‡í¥£ëëMÜFà7o~ËA8ÙVeŸü],ô*ÉÙn¯jÑÁnù2\¾x•á}ëkTC¯Ç"CÐ&xqa×àV?ê!ÿ ïèG3HìÍ3 ¤·¼Ž‡s[Àÿ…ŠSUæ€4tâ®RÙzÓFvHÑC»hýÙó¡>€ú¡ÿ }=¶=àø@°KPÅ{?A-X7WE\™Õ è÷µÔÕÞ0A2ºñ¯lˆèOrW“¨±ÜÒq;ähvP5&›>¨¼‰FÞt+ƒó°#É)Ó‚»4½d¸ †°Í+® bƒ]N4 ±·±5ùŸ ÛãÔ£š@6OpˆGÍj"ðòL¾{³Úy–¸¥¡a—Åe…íMÛPÞwnaQBnác®Ø`°@^(mD.±PËn-mÑ¡nù¾@Ä"ÃÝØ‰. °Ñì:›/ÄÙG_vÉ«n-ËAì§ Z•šŒœ›opêZTGp±ûïpé.BÁnAZ–݉¦):/CÝÙ˜n-Óv"už•º‰°xJ†bÂæ¬¬/Ìæø]Éeú_«>U¹§Ù iy»¿Å¦ÿ‰… (Æg}ͧÿgã^ø{1»qkÿSÑ²Ž²ò×^ˆâÄ]“W[W¬õËÔwó£7ëáUUK¾×R« »T¢¨kÿV”+«¨ël´—"qã›I|ýITh˜AÆåYˆÊ¶¯Wb–õÑè­äëF6ÙW‹Y¦zCÝSÙO%ê–«G‡¹e?MáÇ"ÃÜ%S…•ì­r’W9¶ Ç…rˆŽJ¶j69TSçL“9KKd‰,£U–í|ž‚?yS6IØ)ºÕ&p%_u r#3ñT/¶Ìwò¹£ßvWéeo³?z™¶½[üâžÒ+ßVô –KUÙ+°}´ˆ#Ø4ojÛK€¡¡Ö¶w-ÁFºcONY˸¼k[WmíN°Ã}0ÆvïÑ1nùõs¬[v‚Û&Î]„Ü´B£%@dŒ[™SÇ"c­Ÿ¸nâŒÍ±›ºìãæï ¡WâŶÛD\ùü"“˜×˃1n 2*2¬¨¢P-p“1›©z€XFˆáP!2—¶° qN5Ç w!ý÷¨ÀÍl¿—¯ Oœ-Áÿ+™î¶ÉW¡®að/Dê¿Á~šÁ¹œèE"Žü±GG\3\êzqä¾Xÿ0;Ц­ïÁbÛQ! «3XõYÕc4>±ñÿp˜šbqR\fµ'‚N³2"Ê2­@N‰{Ø9cµa¢dT Ýn§zÞ¢Š9èB6¹1Yä>ªÏ+2Ì/N¹j,ì‡[cn5¹QnÀ0æ>ÈsK¼¦Ã°÷Öê³;0V«Z~§íjÅÇÅâä?i ÖŠ m´‚Vrñè 7|‚ýÜ]àæÙw™3²¤%º¦ú½¦¥ì›ú½Ñý•oò°þ½Ùß3ø­G’-á{FýÞÛ2y×}ow£|DQØpÿÿу–‚Xo&út·cœCk(£uÿ¶è_àNÆ"óÜ*WG»á>Z_ï²» q©W·öñU1Ž;ÎϺ³W?Û8Gâ-z|ÚQ› kU„Ã+k] ùÉ"ôt5—Ö  8¾H0•~ôÜÓÂæ~ÛÆÃ²É›Z­8[lÑäJ 5`ªÁT¦ SBÄ¥ »²«-&,Èn†ìn ßDŠl>D 7›‘Ü à“Ý=ö^7ÉawdbQ8— ZM#8›oôÃa§o{çpîÏ5Œ°‘Ú††T9›7sŸ»YïjîjF-Ó±ižûôÖÔ•?ë i—%ý·hò¶›w'i±’Å4LÖbáÑ…nX̆Æ4 7è6¦¡ˆ¾íF c92}à†ÿu¨„ðø2úõL,|fk±¢èL·œƒç,7 hÛGç¸a<˪}É·&ßå·5ÖÛ|~ÛèQo øm“õ¶ß6[oï¡ÈU\äXË,‹Y‹öRʳ*Mo«Ó´ñ¶&MokÓ´ñö!½A$¶ã·uü¶×z[¯¡êØ€çÛn¹ÑúÊMÖWn¶¾r ø[íµ“({—ùÛÆÆ£?­)ªðAœMhcÛFæ“b±Mƒ«vŠqjaH޽Ы&6Òà4ú3¯¾‹FçÁÑ}Lƒ(ŠÌkI„d\K¢ÈIÂ`ØØ(¡&°Ÿ~­äyPKÒž«}Qr©‘p€(9™Ïâøcp½†ð;ÌõÑãú¨âšÃf¸žïnÑÃâú¤âú”&O[\ŸÍæú‹ësiæÎßÊõÅtBm†ë:æš p.¥X~—Y¾–×ziú°Ÿf–ë­p œu89rt=±têǹb óÅ:;u£Ÿ.ûé© »9ÒŠ«b¯Ôéñ„cˆ.+u¨à9@WÇMœR‘ å`‚ñ¥Ú½¸Ž¸‡¶ƒÍsº7u’š^Ÿ ¡wš¨Ç%+ݼe§¹£X›¬ËÉ”K¯$l9EO²néT=–,YîrÊYÇóÙ½(gžnù©Ÿ§Ëùz,2×ÍÖ ôX@N1¤7ANæF@Î2¤A>1ÌE¨ˆw‹…+¢ÆP#6]=!b 5øÓQFÀo­ÍÄé±[ëQ7aðvÒP#Þ\¹g 5”, =]¹®\Uîïêë_߬oR_'ûÕx’iTžÇÈÛìÕ¨[æ‘'Ùa{7+r癇lÒàKëÏ y‰;sÇ‘ºLMòyÖè©–_3‘R¡r¤Tcð;’tõÊ›¹ír±ö•!¿2°Œ(ëVIEÉ«4ZØ–ÈHÆË'ÉxN.’78Ë×z£¬¶ ì³‚È”¢rY`> 2#ÐûØe{B9¯A€Î¾ô2ÐÙ+í+Mù³Q!9ûÙ-— @2èhTsÉx-™Zd“ùWý ß-é;Rªž`hšuZ°F´Šö‡[½iWëÛü¶üÒÏ=¾ê;¢ŸCj3_x|CZE¿ ×~íŽÒ/=¾þè—8Ü–}$xµXBu4}$"»˜ë?€ëprù•Ç·ËýŠØÜ ]ì«ßô*½ÆüZ§Òk_ܽF¯ ¿þ½Òë_Ò½N¯{ýÆKox|ûüÑðÁë·?WúµÇWã~M¯ûýŽ_•Þôøø£7ñÅ»½Jöz±ôОÀ‹óK0¼'ýÕ×áÂúm‹áuÄð:7`ì”6ëÖ3NK‡ówu7øÎ˜o=ƒì¡‘þ޽ÞD¿n¦Óßq÷ôwü½ö *)؇C%ÄI£º/¶µbKg1Z`•¯Íäè|ú,!GãjÒ4 ˆpƒU¢´,+‰ÎËZ.›7•à „á,±Ÿ"[Ó×TY *Õå Äîíî O¹w]w'îYÊ·¸]N—#}Ó‚ÊÛpiO8´Ï;\÷X“¿¡ 6"ø®uûó(_c~3/ÿ,Œ´š¶ùå›õ|\¼Á]QP²9òv!™L)ªÌµíáÒ³M}µ¢g鵟OïRúISßÜû¢ŸÐëAˆÏzï?Zç÷ÙŸ-=ÝÔWዞn m´lá^ÏÃUZZV Eh¶õ ›è޹{õY²²¢@³;œOÔõdë¢n ]ô‰ Œ~Ü«³:ÉÇ'`‰åfEô“nÙòñ”[ÃZ’0DÆR9 ïS üÆøV…t¢…ô¾´ -‹œZ¿ ZFû¦œÐ¨Ô0”—2hPBðÐÞÈ ýÉBû“|ЈÉÐiÊ ýC…î8´ƒÍ ÞO¤"4«n_Ã^úÙ½»ràËq¡ PŽÃO¹óþRˆvÈC„|óW²ûäWAÙ­MóP‘`ųá¢ôªP^û¯"º°®‰Q)´Ñ·¡!4,SƉÒk Myø¿†StËÿbŽýûŸv³d:áî•’—'Ü>1{ÕŠ­ßÓ¦ 9ÕrǯÐլͷÓƧJ$9žûtAE¢6_;û¶oƒÓú4—Ñ3nÞÏ¿…lI]¾Nb"c W{[T/Gl]Bežvó9ËRþÉ–Y¢aPƒrG‘{r¯±¦Be¡WÞ÷Ø=¤ú:¶]ÿUBÅÌmþwæ¶Y.HÉ"*²MhÎm²h3Ë¢ãn¤bð¼Y¾Ô= ø ¯ïc´Â[+Ž@¾·×wÔí`ÎC ²ÆgŸ€¼—`C Rã“ÍCïXãs ÏsnÀPİ‚ŒÖØðhµªëPv€7… –~ñè§nÙ!VDƒ’uË 9vÇTl)gwÞ>ÄáâhqœÃ‡8ÌáCòá˜Þð'p»óMHÎÈy÷ºî®°3ì*?ïv¹\NùÝ¢ýŠfm”‚ªýQùh,òij_ì…|ò8mOO6âÀ$Ÿº-‡8ô« #–_®Œ,°;íŽaÌè“i¯|Äè“Ìè“Ì(ûîO$‚ †]‰1;1±¾;«ó€1‡ËN+5CœbLÿ‰ c†ü1íÔÁØÓaƒÃ)•ü'ÆÃyTAJ#˜8»#4—fCþ½° vr‘ v™p Ö%}¼¾y÷EûP8î–öõúNø£}ÑÆd÷€~ùTéÒ=€ù¡yVØF=à‚01® cØ0¾@Y õdëð]+„_Oí1¶zŒ­…X/e-e¾‹n¾ÁŸP ¬…ˆÂÓ4¢¨..BîM,PÖB~Æ—ÏÈç¨kÚÏàª@§‚ç dø…2âûÍk…6¯Î˜ð¼˜¶ eY ÕBC˜JÊënY •׊£ßÕºËò[솺ceXÖ8rµ®[[WŽßê_ƒ NÝÉÈ»EeÉ8zŽ$’ô³üÝ"Ù·{­ÛǨ27ú=+z(s#bùUËÜè5ùZ¯=ØÜ¨Öm™õL›ýÅR)H™‰ûBó¿ÁÜh»²ŒøÌ,h­):unœ“Ø-õó†žíö¬Í7©54z£ý¨g|é­Kû{ËúyËûÓëi¿vi¥7Ôµ]·®¢¼}ejÖ8ê*•!ï+ëï%vª `ðÙPŸÕF>ùm¢gß~Þ^¦°ÙÚQhŒÀ–´52ó\ž,´u–!V¤ª¬Ò/*_P$Å‘ÍÐg÷%Ö¹Þ'#ÈÉÚÜÕÛ¢2JkqBéScz©Q’‰o!ÏïAäåE÷È?ÆËîªì*£uïu—&_‡] ® /(÷¢ùköwÊÿ†æIö¨ \ÿ€’IzT (´Ð;hTH7`¨çY„(´uÊÌ›@³ä"¼*Ïœ‚ÌRñe8(ÞPtnÆÛL‚ªµaQô–ó Ôš‘à´¤eaäFÉ»8àV–©x+6o% ‘EÙ†ÅØ—(Á(ý’›ºä{Eò.tÉùéO#MC‹¬OÛIŸVç l/Èb{aÑT7vÚëÞ ˆ‡ú§C]*ÿ {R€‡w´ìæ§C­Øy‡ ¿òþ èX]ýÁZ14`'i?¼Àщö½:®Ã®GÈù~­hðí¿ Y+Frÿ,ïOò¥0Ÿât,ê*Œ'”—öîvÙ)l·L,œòá°S]øºä#‰°kZî9²sØ•` üGÁ.I}/Œ‘ì ^n(ša îêHD:Bmh®¢Z¶Óƒ ´Å`}L‡ü>ƒ* º7O…íe¯ó"ãõʊ׻74Zóu“݈xCE|®˜nÌÛV=kh¹Ê®òL¯pŒ/"aÞnnÈnóÝ-‘ø´õ>Ê mÊ old›—÷8,&ÚÑLòÓpæõ™pƒcφÞ˜|a&236ùsö/Õ5ܰ¨YWÚaý’>æ•Ô„¹òÅ0\Hð±Ñ+o\í$Ф´VŒ ˜¿—¡T(ë&ò×ÐákÌή¯ºËey¦^éÓód˜¦:X€½ΣÆCgüMØAÓ¥Ò_籆sS´Ío /¯äPC!_&†ô_¶È@¬ Õ(Ô±äÂÔ§áæä#aH.!´dµŠW æVïòµpþ¢?K¹i–É¿Ð[£p£dÉÈ&ºük.øß+0èÆB úïVÜtôh»Õ½]ô/Î7lG7ôwl@£¿ãúÿÔŠñ㟵bBÀ^•‰€£74šÂÜ¥:EÀ9PÈþ"Ýe Z§‡ Uåv9úÅ`vP½Ö)ã×OUcü ü‚&Ä©ã‘JMLëÁÏɰ#×ÉêÎI&´ýç¨ò þØ‰Š‚òÌQ+&\“„œ$²ú9FËd ÎI‡8˜ âÐÅî åkÏ=Ôg¦±:VáÐq§tȨŽf®$<¨–ð˜Ðg*m’÷¡_ÆÊÔJa:ÑÆ6_¹0¦¥ÁB>6G<…#6¶F+C?E{ýD²ŠãÚ,Æ7Ãw‰@¸;­ÒÃöÄ4ôíÚô‡{az°WWŠ1ï8H\%X\!ðô^¨eÜ´^€ˆš°ÁAûÔûi_ÐRSîÚu?$C­ÂJW;ßcI±¡¼ÍCf„ðh¸B[Ncù9¸hl ¨&ò nâF£~©àC,ø5‚“`êeÉVg/¸¬ïÜ7„¼!B9™—$6¿¦‰ˆ÷ 7ÉH'®×ƒ`$[o-Ü€¤ÖâÍ¥ð½Áú ?ÀælohµâP[ÇÜ€†Ç¼€>€ïŒ!ô˜°¥Ç‚€c8”‹âjÆ4ä@Fár8r±ˆ¡Aµ»1ü-N2–úbJª¥´d‰$÷qZØžDOå L“µ8¿È)ZœóNÓØAغS7Fñ½­©0ÓêBgb#ÛÛÄð€x[“³´DÛŽÐÞѰn×hr®–(k¼˜ÇÆ<ü¬$džæk™ÀÒ 4œÆ&#¸úEä b| ×0 é „²Xî‚’PG‡Ý}ŒVŽØÏ-‚6ÈÚêÆŸÁÛjv—ÿÕ¶ÕªžW«zÆãäújfÔÀ£æ ûZèeí)¨þ>„;v4î: žÚ¸q×k¡¡^ðR2Ô«É Zh¸7v$’Áá^,ü—òu†'¨]š²§åC˜œ°äÊa~vQ™=Å.æJÛÅ\黸õ=šÜ“jh»ŒQ å-¦‰>JíCy‰`žˆt=6ï=u´'wQÀ‘ä¾âÜÏÈuD“ -nõ‡LjPSY§Ü¯%ÃvöŸu@£ÙɨB—iŒ›ƒÜ{xfƒ~P:kåÀþ‹Õ XèñàDdD“^Ü÷k yTC:ë£ÓBC¼*ízu|=+/œ¢ÞD¿åYþ8ŽÆó‰ÎQ‡BÎI”TSç»@ÌU]e­Õ± )5Ì.ˆ±¬ÀACë_¨îË\Ý¡ôó~Àv™ê`q@àñA@»¬Zü²jq<–ì_hò -iºÏþòAÇUM^¥îå°"99åu-4Ì‹©Ó*öÄÁa^;ÆÖ—T›Éæ[IT}N·¼€6ÚÆßÁG…ni 1:óñÇÒ€ŽÇ’€ÑW—}õôŽ:Z ØßÐå¬p´.­pD=ŒÖ¼¬y©|´ú:G?Þ›o"A×eÊ):˜x“™(°¬ä¸‚¾íM0ð„Àã|Gm¸.‡Cû ÒÊI5rŒžDl§ç Ñ¹, O |ËÆdÓ¤}†.'èIŽÕ”¯ItX¤f c 9‘ eÞÅiRؽ°Ã†®ae`9•ø¦¥Ë-–Pv9Egk»®qc„;S%¸âb<ÐÐVæ­äNýH9Jv6r®vpÐe|W1ânÃZJTŸY8 •ZpÞS8†ü@W+.ÑÊÞKuØ”1„-^–-è©ì l%}r…y?ì¹tŽžEHÐÅXŵÁFZ­«ì Hr╆]7F²ŒØhuƒd©žWЇ+ÚN]nÖ3Ѭªå6=WTŸ!o×Ûw•;9 Ñ”UQ%,§wéÉ"βYâé,‰6šµPLèIÅ:r%õv]Í?Y}P߯ËýzR5,¯à­Pˆu6CÃ?‰€@‰iU£6‚–M!!øM›t^Ä΃„<®§ØN«Öq•äîO­|ZÇ6w÷áÍ<³|¢+ùi‡æ«MPÒÚ÷„À£ú UýÝü;ó~±£q)ÛkpA­äÒîójõT€@‡”:D8¤aù²"Y§³åݲ"µLU¾¼H^"Íõv5”¯(’—3Ú|ŸëYÙ©aÎë‰ä%iüžû5úž/1$WóçŒäÏécXÓIƒå$ðè©ãïê€ÑÏý  ݬϲW²Ò°ÄBZ 40+qˆéÆa“VžRSáµÇ C‰{¶Ûª‚¸èñ‘‹º7¡•±¦@§©ê<ó6ΰd';{Àš;‡¹§¸§¸Äƒ¤($EñX°O0䃥èpæö«“¸7;§˜X]3 9ÉÈ–©“°“Uì§fZ‡ôžö¼0Ó q¥'á9˰&áÙ­«Õ$<ÇÀ$œcMÂï4Kåà›çÑ/þf—úft¬Éü}ó||óZžž§ðÐ[ÈßìIíékÜ»ð Þ…õ.<äƒÆ"z¬ Øß‡¶JÀ±Ø‹Œ¬ƒ÷ Õ›²÷y‹$~8ÍY\/Õ;—òº€k•!—©¾è’+‰éºá*zï4×(÷¹)áœ*ôÇéwV\Y$×AŸËÅýqƒÁz¤)\^òm4°äc—c› ³"XQöÈò"ê¯Û³yßa¤·«Ï³jTL tšV¯qߨmðéÂ"hÕz¬ v·ÁK*<·Õv«ÊÚmȸÜtä­ÀÊdÇ£FR¥W2É ‰öÁC. Ýq/•Û¦žÏ‰öOÉjNN¶ãäYc$)+’ýœIºFõ¨1_àºÚÎ~ô°ã0-R8"Þ%À¢<œ®\§üØ@¥”¯*’GéU #3 ¡\Ç vy€ÇǪƒS¨ƒu<>fq_9c¤OМ¨‡¬!rFÕÃõgÔ9£†ÈCžSÕqPU‡ýS•í"=N=à¨3ä§·ÔŠC^ kÕÊgT+o­•Út­È¬Z‘u·qša«–œWÔüÜWT-9¬ZrÉÏoh_¤Ú—™öÕ-íjz ]368ä%[£±B}­çsã6¼âàÕÛ* BEò¾(YQT–WY¾ºHö…ÒÓ>&µîÛðí|Ü·=àÛý¸oGÀwâ ß΀ïä¾¾OŸðí ø.<áÛðéìÛðMÀ ø†uòʼnf'_"à[ÒÉ— ø–uòí øö|Õ_MÀ·?àÛÑÉw€^;ù¤“ïPÀïä;ð}ð ü¼ :ƒxì{¿ýCQ:ËÛ¾|Îò·Y×G²mÌ/Û—MÂuÀv¾(ôKóæy_é$o¼|’—­Fwdð:Þ#eS€·3ƒ×ÙºFè,£J‹S¥ÉÇ¡–Á+!¼gʪ€·+ƒ÷œUÞsòç¥U„Wåe…ƒÝ<(1½T6x{2x /"£Ô"qjù;èkÀËã‘c”2¹ ØF!Úy@à±×ÔÆ9F„̲Þxäâ )ú×Èq‚VGw°N¡M§MñçE…eê¦}ŠÍô&Á™^­?_lcq>MÛ&PîÛ|×ïÇ nhgÛÛTêöÓ;kp«x2 Ïlk°fšñ¢f›Í'älÑUΉȘ®ác4aÓ ‚¸)ó/f«ç"õ^‰BäBe喇C—*å%Õ¶\ÄCaß©@Ø^å;¨òíÓ»…5lðm±²Ãª Ù«ëUþ€ÜMðA8}C„ÕYh‚$7A+À?Jii}$änô±8õ1ðpoö8¤¬ ÷¥Ç!Aš…ÖYãp7ÃÏÝ€aV<,œ®±’Ëý6é¯oðÑ9ԕ߸_ô¥ïx}}|>á[ÒÁw†EßÙ€oEß'ߦoûÎ|«:øÎÓ0ìàû4à[ÛÁw!ðsWô®¼_.JçzËÖ•ùž/u©)貿 Ë‚. º*èr¸ ËÇ]Žt9ZÐåXÁó ŠEt.¡ ¼__(Jç3šIh¾‹_mÀ'¾º€ïRÀw9à»xÞI¹çSîÁ÷7EéÂLîºïó€ï\¡/ÞÙw©³ïrg_Å#œ{!äÇýöKZéFÎÝ€r·-mGLm7/mkg‰oµ½¼J´Ý6K´»[´]|^|ûζonmgNÏç‘D¤ê~Ç5­ts†ÈûçEÛDdýëMÿB‘™¸F|û®¶‰¶_]ü}› }úýÎ>zéÖÿ±÷€ê:öÇ÷¶½«•±öîJ¶…­5.K°\p'³Êš+/±§¬²»Ø9Ï$yIpÊK¢÷"z•Ó{/¦czÙ‚$z è€MÇðŸïÜ{µ‚—üþïó‘öÞ;gΜ9åž;sΙ™†ì­Ÿh]ØÚ×úÉÖ­Z?ÕúéÖÏ´~¶µ¿uëÖßhݦõsï4¥L[)ÓÔ"G?¥t{ºÌ…Qß’¨oyÔ·2êÛõmŒú>ú¶F}Û¢¾QßΨoWÔ·;êÛeۉĴ¢ŒaJéÎ4‰aßæ°oKØ·-ìÛöí ûv‡}{þDØ— ûj¾º°ï@Øw(ì;ö ûN„}§Ã¾³aßçaßù°ï‹°ïBØw1ì»öÕ‡}W¾«aß°ïvØw7ì»ö•G|Ý"¾Šˆ¯GÄ×+âëñõøúE|ý#¾ßÀˆopÄ7$âñ ‹ø*#ïgnˆqПó-ª•AŒõ#ÌëEf”J%V¨žTØ%®*U’xºËU½ÊµÝÆÛÈÕ¦VèŬßã& þ¨nTChŽwÚ—»‰ËYE™³”Ò½i.'G|S#¾iߌˆoVÄ7;â›ñÍøF|‹#¾¥ßòˆoeÄ·:â[ñ­‹ø6D|›‰­ˆo[Ä·ƒ¸øvE|»#¾=ßÞˆ/ñÕD|û©Ôˆï(Õ*â;ñˆøNF|§#¾³ßçß¹ˆï|Ä÷µBÄw‘(âßeb7âûÒhνÄ蜢¬eJi"ÍèTÆÞËEâ2¶17癃/8=Wàsfôs¼™™ÛÁ¥çz æuWò4s¹™^ÌM@›ÌÕžËìžà:,gþ’\ÕhnÎq9¯¨ÉF¥4Õh€ë¾Eºo±î[¢û–ê¾eºo¹î[¡ûVê¾UºoµîûD÷­Ñ}kuß:Ý·^÷mÐ}›tßfÝ÷©îÛ¢û¶ê¾mºo»þŽ› HQ ŠšîTJkÒ Õ}Ãt_¥î®ûF辑ºo”î­ûÆè¾±ºoœî¯û&辉ºo’î«Ò}ÕºoŠî›ªû>Ö}ÓtßtÝ7C÷Í4 ¨¡v{šíSJëÜþ…mÂóÜþÅm ÜoËeu”´¨(û Rºßí_ß&¼„¾umÂKÝþÍm Ýþ-m‹ÜþmmÂËÜþmÂËÝþ]mÂ+Üþ=mÂ+Ýþx›ð*·?Ù&¼Úíß×&ü‰ûí̲ýDpqQósJé·n›ð:·~›ðZ·¿¶Mx³Û¿¿Mx‹Û°Mx›Û¸Mx‡Û´Mx—Û¼MxÛ²M8îöŸnNºýgÛ„÷¹ýŸ· ¯wûÏ· ׺ýÚ„7¸ßnZv€ŠXR亣”Dþ¯¾EEàw!ÿ.æßõü»‘7óïþÝÆ¿;øwÿîáß8ÿ&ùwÿÖòï~þ=È¿‡ù÷(ÿçß“ü{šÏòïçü{ž/à÷í¼²ƒ´ê<’ªëÖK^´ E¼ò.{¿%•üÒåëÄP¸rØÏh0Ú0m˜6Œ‘†ñ×ø€G&¬Ç«ÒÀª4°*«RJ$°úyñZ2Þpo¸7œñ†15¢8ÂÀa`Ž`ÌR‚#ìnÄßHo¤7’ñF²ãÃ#¨2°FX£k””äR6âo´7ÚÀÍx£Ç˜Çó Æc`Ž10Ç0æ“q7*}¬;ÖÀ˸$Â¥€w£kºã Ã&²ð²í5ÛD¼ÑAÂåàcrõ Ét=Ó)âc)•,´Ç6T‘¨G²šïs½ú5b ß¹´4KJ…g¹Ÿé¬†œ‰Â÷¦aGÕd¡J×d¡Æ¿ ðºâP«Äl)íœR蜚Π3ªÂ¿jC†934¶1žÄ¿²… ?½UÕÛdÔ1aÕ1A•»ÙAÂ6ß­òqI¤ìº öXöI¡…îDp¡›¤Ï:®V“f†Ã¤9îDx®;8Ç-w‡¤Dë¢fÀ?Üÿ#Q–©&bÏZj½ãšOÒ@CµBldˆ³ÔNÙ¾Š<§¢1?£²†¼‰Æ<ÍwîƒÔ˜çèvF0×Í>ŽR$X¥³Pžì_#0¡T=Æ(,”ni”7Ø‹QÂ×§U3Ä’ºÌ¥vk(õ '©\0u)TÕ‰ë ]ûZæá“ÄÌmê{´è)>ûÕ ÚC6´‡,zÊ ÞßÅž#Xš ‹"n´ùF[pä!³­zÓ‰è¸A§E§,úʉà¨<„·9Ãç^B ¡¿,PAæbb¢ðú(!þúöœ«Š#ñ-Š8KÚîø€ß8‹Â(¹^ºM¯£Ì üe1ŒóŽñr8;‰¦éèÇŽ5ß#h•jc°%«–B»M–1\©y&!óèy¦ÊP|>ãÆy%ΰJœ!‹™rh1ŒãYÁÅn˜ú<6ÛB› kF;›c¢K£Í³ÐæÁÔß@s™hçÓh -´…²Xd¢µ0ѾH£-±Ð–Èb©‰–k¢]H£-·Ð–Ëb…‰æ1Ñ.¦ÑVYh«àT€ÑDíRm…¶†wÏ7ÑêÓhë-´õp'p?5áQhÆú%Ð6[h›©'ïtpYý¬¼™ûUÙ*Sn•{vV³CîDV¦Ì>ŒªUØ(Ý%½¸{±Žzq)‚TÎeJì<†rRV9)Yì“Ck܉ÂH¡7¸Æ­Þ•4^­…W+‹:ïõ¼/Óx,¼²8ø ½¯Òx‡-¼Ã²8ò ½«U3ö ïÕüëÒ c`ŸææPΠNC1?#C•†·¿–hsë‰Ê¨:•&ˆq}^Mò7I 5ÉØ×ÒtÍ*ñš,®Ë¡ôŠor7r]O£ÝµÐîÊâžö©…v#ÖK1ÑzÁ•£mµÐn¦ÑYhƒ1Ø@Ûn¡ÝJ£µÐÆ*bœ¶ÓB»F›f¡MSÄtm·…v'¶ÈB[¤ˆÅÚ^ íë4ÚZ m­"Öh ínm«…¶UÛ ´”…v/·ÐâŠHh5Z¹×ðŒLh/ÄŸ/Â&¹›×ðŒL°—ãÏù?VÄ7aâ…ÿâg}ôÄ‹¶WÅw0E2çèðóéÛß/F¬Âî^]wdôdyàudºÚÖö:²Jô{­­L¿×Û*ô{£­J¿7Ûj¯‹â„½ËŒò–0#q™{=lPfͽ 7uØçz#;•ù‡:Ñ1<@O²ƒPz;YÇä£ö7+u»ø>üírþnÞ4ÆýXü0¼Ê[m7à±»nÒQü¸!R|x+1ò™æÙ`È0O5ƒV°Î l™=¼V‹]Ï1mÓßF¤½Ÿ a+"òôL—ýs³ì°!yMã²K HGnTväÿXö «ì(Ê~¯¡ì^é²e–ý¡øÉŸ4.ûפ£ø°QÙ]þEÙ°Áý·õþ Êþ]CÙ½ÓeÿÑ,û/â#$¯m\öŸ HGñ—FeÿõÿXvC½ÿeÿ½¡ì>^ÍéÈX® ðq*{ù™ú× Êó°¥êÌÎGlãT8«–péÞRÆ6MùUtÙô„º.›ŸÐ¶«b²šŒs~ô 6ŸÆ­T»à¦é#×r¶jì`ŸN¸+úLºÜëà˜¥Ò\ù±Š/Ã4ÎÛL,ˆéÆý§àCÌTã`EÌR“à&û}Ì¥sÕ¨#Í@H**ê@õ?µ÷„õwªgTÞh®š_œù„ò™Vør¬ Ôïô-T³±˜¹He?y½¹ÅjÂð³Mºw/;OÌ Žêã¬Ò*ã‰:ælN.äÔÕjø³fôÐÓ81´®Q=6©)ãõf5l0X'¶ÀÌ?UÁÞ6BëÄa3\¹~v/¿Æ› ãÓ vÞ£ºEí ûzUêÀ[,kïáäs§:¼ã8¸ãö·Çè8\îbO ý§ÆU,žj ì…gºSô]ª ’jÔŽê¢v)Üg÷†+&8€±í5û~ú~@Å6X2Ø£¹„½½Ãjx?S@ÉØãrä ½Žñžß\œþ󗢎÷¢ú×IÆZ1?½.!â%» 8Á¸Mžf³ÿ(oÓë,iÂxr“,K¹!ÍVqž×áÊG H—û9—‹sbçT‹:!BVÿB ב“ÜhRh⥆¾H#Å8JyÉhYd€“zê Îðʦˆa™Íû[Q-| ’øRå“gý¼2‘ÊG\GˆûhK£¿ “rl±¼Ü›æmlO ðZîÍ Ò*´å_¸7ßkº7Ï V§zltºùm—žÍñWøËÎæÔKK‹LÌí_VTvêÿ o#k„nñ `y­pxB[Íð¸ôH٭怱oo¯e :èr.¡Ÿñˆ—Bc\ï&¤²ÛÍm‚7mÌ5Ñks÷aç&½`CÀ9XqÁ¤«·K´%ˆ×pINXˆ9ò­x¬· ¦ œùa€¿mîá°Á²µƒõ‡×rN†¶Y–+¾›d§ä.ÀÙg¨7mþ9Å á¯]®ˆ€i\`áÄwÙîóxª¬ŸKt4Ü„¯‘ý{—蓯áœÈüˆX~+ëë2üƒ÷uý[ÿà{U‡]OÈÈõŽåœÃX`K›¶¦'(ªé;âÝDóó¦£ð; /ÅQ%Ó5 ÓQv^j8 ‘ð9©ñ)çä­³yï'1„ùÄHÖP²e©†gÖ?°‰ÐEU8™Îǵßòq³ß‰ßZ¾§ìâw8#ÑpJÿÕy¯Hüž]ÿÁôEÜýÑôEt»âv€Þx±ëñ?ÁkoMöHšP±Åõ?,ýnMÄa${3ÿŒéÅ?â h—–òòß­úÛ²¾.ñOXÊx Û}jÙ^Ø‚È~DÓ½†í>%ô±üˆö‘`¥Ÿ †ýL:çä ß½È9Ók§ÞfGÊpÉòJÎîºZ “Æ6áåŸíy…fP{y’á|²á|Šá|†$F66¦óÒ1 ¾ÉÇJ œTãžÈŽÊ'Ýç¨|ÊýŽÊ§ò¹~zJ—mø o€g;3ÿ/¶Pmpf>Ïô Í'õæ[žÌƒlÿ_‹]>|õˆ±þ.Ë#3uïŽÍÙJ`IÚá9Ÿ¸] ·Ö+ ßæ§ðåkðm—.k,ßæb„Sg0ä®—–´·oÄ87¯4ÙÒÅF)ªó™M>c­ó¡/ËN…zóNì%n2Ü:çØÞØ[úË[:Wsgƒ«t(¬»Ízâ|Éžëù çt>SoäRkš°Ü©×6¸Sß/ÅCùòme\†ÿnWÜ´9Ú¨ À9Ï.°r²q—À7·aG‘Á_7ÊÙÏðbScF ò\Ýdaº¸>Î.®§“š(¤é_ºâÉJ–é/%Ë¿ô—áW:}Å@‚{é.ñ•d¹—èb÷Ò×ÙÂy–×ðx@¯Æm¼4_3›ìá®ie<Ûk¸—&” x<ì!3 œ"ô”A¦f^Ë™°žmÀ9Å–È}\HÅ<>×›>O1Ï Ï/_¾æõ ŒlÏ?ÍYxZCžýF"ŒÊ4uqMù¡£xëÖó½ðLFþvÈÛckG“ÃËýÖ¼,·íáaáuš%»D Yxo¶93¥pËO¾O‡¹ðrã)¾«c‡*C\ìPe¨‹u§^Ä|í‚‚ÞAAݶwê¥ 3|šl²ìÏâ &VCúŽUMòC\ à:Ø"|¨+IØ8ŒT`„Ê¥£O’úUt¡×°í£Rá0  *OàE^ÃcN†¿¿åJÂp: ÿ„Bq„>éÏf¦?‹¿p¹8Ãî5|ÌRj9†¼üE¶eœÍ„ kæ­àZ%A¬RÎå^Ø%¶B?äìÏ9Qè\Ìx`[ @þ§µL°-ðXHbPC¶,|ÊôùÌÁPÉhaìÏ6]ÜÃyµ•oþ¿,nUº¸qVqã$ö6`dkj8ÝMWeÇfL«½–skNv˜"Õ>©š„ýI#QiWÕ4û+—{š‚ HIöæC0!=â‰Ââ GŽ šæÞoÀ%ÅpGæ[ëUÍÞÞ2GÚ[<ÒÞ¢‘—H~·Ò%ó¡©wãÈòS+?ÇXYgŠ_”│]>ŒÇ†£ÿÖ³ø• pëjëBƒ&AYq‚*ÇŒþ1y6z(2þ£yã¢+eL›¼eÊG*ü–ÿ™' ðu)|þ­]²0olf©î1Ø#HøÝÉíÖŒþÞ­T—0ÚîÓF“ÁêTíér¯V^ Ê¿ɪ^:ñ¢íe)éE~…xë"Ñ2ë"Á©l¼ –ýtNr•p`¯–ÒwüŒA±»v¢!^Kº^@Úéäö¢}2ï rà==žLá|ZÙD‚Ot±Åqw%;uÍ­Ê&¹è­” rag@rdeóN•Ímeã0EPR<6ÎU²J–Äà —Nb¿…JPÿÑ<`°ŠRã± ®ªùVnßbð\èA$ –LwÙ8²Ô6¯Ã®j½¸!>@ zÁöA½Ô; }À¡Ðþ«^êP>¤ÎT»Pg•MÄ,GuâÔe·Ó%Ô´SS[yS„4#ýf}󨇓XÎgc–ß"o¨>;‘·þ&}ƒªÄ]:Õgk%C¨J¿ƒÿ.¯CWµ üüÞôN,ý¾^êèwïsòÁ˜ÒOgêºtÕIâOÉ‚\iú3 ¾û0)ÑoÓÓ_’±QÎæø€ÿO26ÒÙÆ`pà)<ÝÂÄ™ ‰Ñ Äu—ò5R29Þ-o?l:ú~ ¨ú¤´ôÍyE»¤êú3ÛÕ¶’ÇãW><‰'¾“Ö±É:š¹R%Ë"i¢¸Ñ˜$%S]ª Ç+`ÿã$| n*»aiU’”U1™Å,nªZnÎ)G±«ÅFió7Ø9ܱñºœë<“'Ñ~Û< ÞÈ#xY±…í]þh ¥å…¶ùϸ¨ðšçâU¬žªõbÞj2Ûr¬—€ƒÿØqï"‹Ÿƒ[l=•ÜTlì}Åxº®Ø°?N&ä ¥¯’â&ñ’).ŽdSh+›àkQ]^­©ªQQ Üi./΂°@6l¥p(›þp5^Pþ—ÎYHoR/Ý|¶úbf[ —]Ïȸì~FÙ q$Ôµ©ƒ%ØxÉTzwÒ„=zÓsXQöˆºzÅ Ú^ºT|Ë«Ðþý"]—$bǺ‚g$MžàKì•BYf]ŒYÜ9¢Í­`šãÓŒu•|BRXJj˜`xBáÀûŒô¤ 7´@¦!Ýi,s]E}߈C4Î~Æ‹ê<¼JISÖLša$c, dæã„Î#’8,›Nq„}²ÃÝc¦Lìý dG¸„d43¶‹ÛäÙûêÍŠ-ժ̻eäS´2 Ññh“hfIµK&÷Y%“éþˆ´13šu¶MÚå+0Ûúÿi›&â²Ú˜ÔyÜ0¥‹ŒŸª‚ Ú%ƒµ gÞë­Œ: ™e¥çæhIgnÞå5fyä7s–Ü‘dqÕhæ5ÔÌ780µ—¾eÚãe·ø5¡±s‹ÚeH@º%Aº.™á‚hó§üJ}¨å¼¯34`ë-‹Þrxwÿì3h>è“~Ä’†Y_9ñÞë¶§E?íeaè7 2Òù  5x6žä2®–ß•rüI|ËFÉÆìhÙ³ce|Â8pã8&QÀŸ³‰|_²šê7 þÆéÓ[…bã^{3U»Æ¯Ó6‚{®þîI±~ïÕð^ýë”?À*ó:gзÜz³^Æ›õrç&øiZ/•cÏ”¾ß”–Èb6É Ì k® ÏM[º˜‹ÏÒ\G%›X!'’9·0\+ò*Y¬’Ùu¿õIH6xȆ¿ˆ¦[¾íye­ —#ê:º hëé2"`߀-URÀ©åc{¸nbõ¼—« M,·œ~$xÔ#¡ÎbƒùÌ‚.,³Å¼ëç(kd@ÇnꨀãSYl6R¢öàqÆuˆOMˆnB2ÄV9#e0)+šaÜM̪¦ÛI°ºÓÓjÇìC†è“‹ÎÏ;÷È0m$ÑûºGŽ:ÁÃ$ötÎ /Uì˜#×ÁÝ£™š‚CÿÌàQ‡ëÑ2PnwÐñbf Ñü|V-]ªŸoR'‹šTô§¨eŸþXf¸Ò€k;/£¯EU`%–oó±КÂ64+’cÝt\x2¸°‰ÖQ¥v(´=óL¡ µµÙ¦²Bûµâ´Œ·‡Šù}h„Ïp^n˜ p´Øk„¢Ô‹H mÔx{…÷1ý ÂÆ´@¼óT5é´›H»c¤]GZ­>WZ!í¿Ôû^f_ð5/K÷dÑMf"ÉSGŒµê˜¡ð{Œ­[ª{…å›?ŸMÒϱÙy€<|$¶,Ï|  €ÞJƒ Û%í÷ÂÏrµ!µ(Æ*¿{Ã~÷p¹ ËìÉÝl”òŒ:1F!ÝÖòÂÀwø<$`ÈW9ßxH¼ÿ4V)è(&(ÉDVÎè€2I“`pªŠ*%ApµUI%ž º¼Ôø±Rh«Ó•T"<ž-Ù ‹Ø½°š75®ZÒ¸–³ µá ¯“£:Ùâréa·EQÙaw½´²H:(—qûW•¡çÕEò9¹ô¨ÛÿIQÙQz^S¤\”K¹ß±E޹CÇÝ%ÇÝp¯sˆ´E}çò³Ï¯6àP÷‡N»ÃGÝ᯴ð'™tSrÚ­b§ž ‡Ýá†Í tƒAGÜá‰9á›Ùþ±†ÞÄ”y˜:@Qßù¡Š5y¨›lü.õʸ¬ñ)•ЍTB'ܤ—œpË壖NmÆ«‹#м#é©Ud‡&F)pæ½MÃÀ;’¦¾Ú¢¾š©ã·òU—µ>e"Ö(¡“îdð¤[*ÿ;_k_âë™øÌL±ÄSÁé™è‘£^Ù®¨%?Å&’ÿ€7®¶S̺„K¶òR‚rVg”‚ò¿Õ‰³Jè¬;<ëæE½ÏØZµY{ŒŒ«íàöþœ>æ¦ù2ÁÅy%ª}Ô`‹;Zùˆ×Q.´ÓhÅ‚•T2² ^æq‚â˜WÖ`M\õW ®`ÔhëÃ9Ÿ4P;ò U ¤ïÒßkÅ µ:1X¥É¼ÙË3ÊPU U‰™”Á‹*†‘¤üQƒMñâ߯J‚vC¼µ*Î%÷ÂôŸGÍLÕ\ÀÂîgW ¿—‘q¹òˆ‚‹xDÅåj;m¶*f«¡ôþ¡R‘v1 $ö®¤Ò«Öƒ'¼vªâ·A~­jhïk™®´–éÊk™®²VëÕÐ)7Q oïü—œrkbˆœôÂLêÙiñ¸S»Uã[kœ2àŒsÙKüƒ‰ÃKí…S^™&¶N 0ÙHpëJ)XÙÁù-ìªAÎ$µa,YàuòZj%ÂØ('ÃçÝ-àgc¿Zx‡Õ¼†í†”Iò”*Ψ¡3n«—Jθ%qåŸñ6!„|ѪÁEUÔ3£Fq8œÆX^`]·°®Óëgaá4¯6¸€ÒM£—¼»fT'ȼ,J(½7ìÃÎ5ÌE) ¥Ì¹¨Žæ¢yLsÑùFK_xí¤¹ÿôòø€á´¢¥í—õÒ„€ôKXÇÉô[ëTèweKqy¿gËæ»DêÊ—x/QƒC1ëüFÉ&—&~/ÙLb .˜«{T¨ŒÇ>Á—ïbüÿ3[ð%óKI`x4f-y-êYþ| c%³±ÆB×DÆBi6Bâ± ®ò§³ùn½+ÛGr–འI—UäÅy'l0<ª H¸P=q©(¸L¨¸L hsè25`ŸK—ú<ºL 8æÓez c!]fœ‹¡h2—ÐeV k)]Öz›,g?ÀÁº­+½&séö$nuR?SÁc¸uÀpð8n3Øð*)RNørÆÖÛÙ%Ìܯ²w%ie)n×ÜD,7ŸqàG& ‚Õ‰§C-l)Á[WóðÁµ‚Êé­CtØlŸkë†#;ù O”%0Dµ®q¢j×àé£HÌ!]56ßÕ*w1o³Ä£¤/wAùàÍz‚*Â!Y¹¢v+9[L [úi‰ËÐ[Œ§¥.(-Ób e]àÂzÉy!–œ-ì®hÓ†‚ÖöJW43¼Ê…XOÖÓjW´Éì‘«ë™}NËnÄZé—Ø$Å“e ]ε—-rÁ¦+ª—-v‰-tã([â[é&£l© ZsT-[æ‚ÆÕÊ–»ÄºiZ¶Â‹¯hfÙJ—ØM7Ye«\ÐŽ£MÊV»DZÓe¯ôøåN =3{ª†æž§êžêlª³þTgÇS3žêì|ªsæSFP3Œ&ÛAMÒ!b2tÙÙê꜀z‚.sÚ"¸1 ØÃ[G@‡>² àX 'ŒetYp.‡{@&é5\}ŽÈP+½ÁѸ¬ç%èå®®Æô2W×®ô59qJS¤,r¡#«ºo׺®Š5l!Ñk?ßtyò…'ªbÜŒÄ ‰„jM…6&Œˆ‚+\.ã\ŽÉáóMc‹ÂñÆœBU:WK™Õàåiµ”%‹=YYœâ¬l|s ØoPœ”r„9Fpº§Õ² .Ä+([ïʃƒH²-ÂëE$Â%ww*Y׌°bë]UêK¾-´‘Àe„€¼*›1o×»HùÀD†˜F¤_ñ¾âÙ™ÀMTÁQ…*Ü’))£ íyMÞØ$ÚÜ´Øhy ºÒ°5Û25¦@³ŸšïyæËFçl¾"ÉÏ®·¹¼$³l>gÓ–ôÆg¥¶â›|ÄæãP{ü½[\âUÊwÕ«HvýqäkGbÇëñP{x€Ú©‡]*ÛÊ{-[]Á!2¬®ñ³ ¨ABíÈI[9éz:é?(éMNÚÎI7¼†OtJz—’~mXsÓk„† ðÏÌ«Ÿ‰Ÿ#Àv®n5lT/Aíkب>ÀÕŸryhˆÛéÃXÛŠl¾Ò/ÜþíEe_¹£Hz¾ô‚Û¿³¨ìcÝi|ki@¼7÷ ²ãRƪ3›ú 5õv`(â®W¥"xgw‘íÕÒKîÐEw¡³P ^tËe—¨¨=ER»Òz,Lz Ë$:u²ùëÛÂWïGeõ„º·Hn_*ÜáKnBá#¢c½þmÞØþ…Ÿ>ݬÞó€½Ëååñ"ŠÝûšíÅz)þšD¿+r[Ñ–rÅø7iÁ1Ð\ìc_ ,àÕ³—CN¬‚í/:¥Äügš·'@³Mæ$ äœ³Î3Ìí©Ô‘8E7†£?uË“8:0Ay{e€÷±I*þ]‚÷Äþ;^r”äÞßßyŠª U€üGÞv©©—VlñÈÞ’øs¼UÙN—ø ÉÓ»\â¯ñð…æ±îî²Ý.ñ?”²Ç%þF—½.CMZ+…RøH^ìPA§&JY‹äeÚ `k¥nÜÚ:5ÑËj]ØÇj]eu.Qaí#ÕˆîR"|«yì;ÒÏ!zH ß=)r]Gx‘DYÜ%zK¡_tú…­üµ¢”,T#•ˆáɲ”KôOS@Tè£8¼Ed†ƒýï“bPÃCµC nx¨rˆ! “bhÃÃ4 ú̇)Øí¥†7ÂA>Q¶ß…­õÂܲ.(…z¡cJÙAöÏ xÈ…Íóð5GÙa—˜©¬{t‰×Ñ3SxsåO5û㘫9ÿû$`›÷ñàŠ ᇿ옋´‡D"B×9ŒŒ Lé²RKYµXêEDÛåRèO­:ýIB效‘ü™+ò™‹ähº=늜uÁ©@Ç>ÝÖ¸"—$±·µ®©Îëq[犉DYºÝ銜€4K·»\‘“hév·+r "-Ýî! jév/Q€4K·û]‘sgéö€+r-ÝtE¾pa?(;äŠ\€TK·‡]‘‹kéöˆ+rÄ%ö²fÏ›²'‘}H:û+ûøš(K6dšÎ¾Ù?¡ì d–ξÆÊÎVV”=ѽ2}'²C¸Ú‡ìÃÓÙw[Ù9¬*¿fVöéìG‘ý˜ŒJÙGrv?Ž[Ù#j¢€*ŸšµNËLŠøÞOSûÊXÀÄ 'j£ÓÔ®YÔØÒȤvÔhŠ»eR»jcÒÔúaiº¿‚÷Þ÷ÓÔ(&µŠ¤˜Ô† x%Í’CƒZ%–ŸÇ¥©Mµ‰ Þø½gj­‘0É¢6IÕJ¢ÐÖä&ƒMHSLrƒÜ„4¹ù ·@Á{Gä&¦É-´È-„©‘En ÈÑ´¶Ô$·ä&¥Ém¹ Þ]]N“Ûd‘ÛÄ>òLr[@ŽfÆ­&¹í W&—9„î<r“Óäj,r5Ѝk ·äh~=`’;rSÒäàŸNœS0‡¹©LŽ¿žç-rçᆎˆÐÔ|Ñ$r D>N¹"·LeDdZšÈ‹Èq/øfÞ3‰”cnzšÈ@|Ä©˜‰ÈŒ4‘ÁªId0–T‰}q‡©æP‘™i"ƒÈtó #¦‰Ì´ˆÌÄB)¡YrŽI„×EgçYb,a…›²Õ!’­þD«9yÞâ€E¶7J¿r‡®ºƒWݶÈWƒææaµðÑËkÆ™ö…|¦=Ñúù¦%lëæWóÒhL´¢8ÑúÅ´—€6?Ë™cdàñ®Äùçmßß7݂Ո$ žŒ)o&|å­ù®$áôßý`íùî?¾nÆÝ¾ ãîÇ _wãî­„¯‡q÷vÂ×Ó¸{'áëeÜý$áëmܽ›ðõ1î~šðõ5î~–ðõ3î~žðÍ7î~‘ð3îBÄA˜ï~™ðÍ0`‘„o¦q×9Q˜Á7ï% |ó~¢0“ob‰Â,¾ùU¢° ß”kß}ðUw¿ÆnAž±<»ÆZq¤¦äÇðWîDì–gæ5Zƒ%¼*öÓgÉÑy(tÔìëÈCà ½8/}oIN¯=zy]@xQΉWl^DË"må‘x¢äK—$ʼnÇ<œÔ{ h8ÓT˘âñ„ë[Zö¿( _¡­.ûÊUÑYeO¢Q5õhÏZñd< h2v¬ äšK¾çU…}«ET¼¸ï›¶çD²‘A¯¸T`ƒƒn¢·2g‚/˜9^¨—6û¤ÄKIÂñ"2ÚËLªî7™Æ¯<Í+6߯co'þ¶˜¯1F2r¬€ÃެʳNñ­CÛç¶oJïÁ)¾Œæ_ÍïÚÿ€…š"[óÒënmQÙuÒIêŠ$Wé ·QÙ z…ÞñØþY/-ðIô;¤¹L¿ÓUºaYýQµq ^ÔºãHx+P=I±üÜ;—“‹ž½¤”¹ÖI øg9=³uãöóœž=kØyro#ÏùœÜÇ9R]Ê0ký·yøHåÒQîºàHgIÆäÈXÈÖ)óL´ºEƒ)5“š$œ/çÌÁ9¸"eÿ+Ì.Ϲ¦FJ4Œbþ=ÍÏMš#ÌÌÍ‘Ÿ'#EíÉjÄÞ‹ÚÃ-cKjñú½{¼ÓF–aöNã^Ø›[ƒo &ñ—rÏ«¤-i’Äá9Gd|ôLsŽž¬Š{çØ ƒÄó´LUë£"ßtÎ÷鋤xsÇárè1—­e:Sq™þ¨6;ÒŽKÝc:£¼èÀe[ ƒôö™R<Õ‚}sd>'0 &Ns¤DŠfƒì „<] ÑcJ–X•ö.}£¦dá?ÅíI‘øMj~,¥ÚfŒ¬kΆG$ðº9RG ìv$ÏzÍSÂr#GÔ^…ü+@¸<çµ –±u Î}«m(c•ÄáܼÁÆeèHæ2j2Ö s­Õ«@j­u ÒŽX/E3x¢Ú`òਲ¸ÚdæppŽ-RÔI%çòæXENCàB~½%Œl”ÐCÿˆãBo%žðòÑ̚ݰ~ŠÇnºPJ¨ªÆ”»ƒ†²¹o— !UðšØN‰ ^wQ·ð@ƒQXÒWÿ}÷žØk>ÌÅ9©<Õ®j?Ç€H"—Ï–„¿È€„ËŽ€ŒË΀‚Ë®€ºOû$Ã'+z²üž ¯ÚžnéÞ…X…%S%#sì~ÙlÉtû­2öeì7ÊØo”±ß(ã šþ¿Ë8d–1ŠÊ8Œ2RÎù=æ¤9™>—÷°¬78‡9SeCrD7(Ñuü"·î¬y/}ÖÖ]©;ü$ã±Á9sŸi®Ç‡ä,€×ˆýéÒ ?>T:"tPé}8³ÜGFà |¨ÌˆLÈŠÎB8Åv Q’~‚í~¢9’iîØFÊ8 ú=>š(–ƒ˜ð©‚ð œKle•9b,*qÈTØ(ëx¬+àPè0˜âÎÓTXÖPBµÅgµÁgµÁgµ,¦veNhPuh§A9 ïWLÝ#$«Úï}š•}š‘}š‘—Š2C3° ¢âS‘u¢ˆƒ—D3¸BQ8Ðèlž[™+¿A¹6ªØ[¯Ì‰ð¶ØD“î"|4Ï8ÁGãðªX&›(8S”§Ð°„Ä•|²uPNQÇ­4:—=y5Â<´U>ƒžB[W+…õ/(!~Èófü'8¿X+¿³RóM3HXÖÍ‘?bs“uF"Ó@l‘Ífl‘ ì'æxžLï×$æh¯ÉQé½Ì‰”¡«ÈIY$d~óiFHr{ÌhÙošÁ ÁLØ'§h°$曣…î“l¨%j8r×ÒÍFC,Œ:N`úd8à dx@ÆQ¨,I&N 1áã$¿Ð5)tÖ„ Ø î€¡rè3x’€÷\B/l¤Ñ¢7B³·½¼7`Ä?Þù-¯^šZ(Ño·v2b!Ó0&å®l\Žx”^Äñ9â1z'äˆH6•1Êþ8õ÷ñØ8Œß3ip!ÂòÅcã>KõÐì…?E`šZ&䄱uøäS ?¯iwì³4²Ÿ[ÿ䵌ü9Wc”lVðv¾hávÒóõR{/Ï'ÂًٿþAo"xÐ+uÅär&‚N©+µû ¡/ò”§RçxP‡3E¶N¥Ý<á¨vž¿Fé —uƒªô7n³Ë «©ƒHöMDÐq þ ó â7Äs\m|b‹â¡ìD0[ VåHÍÏf»hvåx(µ'ÉÝt)Ïp+0 íH@f»º²I9"ãdR‰4û?dתڡ§Ó9j þÃz)~ħ_ߪ—Råmñ£D¸››_ðÊüV(%vÊà±ïÀR$YÑ9#û¼TQÇ…hˆG}‚öSñnÈÝÉm€ø© Ï.~™ç™¨ÊÑÖ~yò™¨#Rü"…ˆøj xçù Gójz·2oÅ¡È68¡Iø4eã¹:x®@æi|)šð×8E±R\A,bÜ|Äþžx/…x  áý¨^§Ånæø÷¼È¶B±¨)÷Á~•ºÿùŒ ‘gš¥}"tžÇÆ: ÿïžÆè˜˜ƒŒŽËü¹v¡WÎÙZ•VxüŸ•U`X\áE—ç/ײ…GÐ}™Tù¶ýžl+Óï–g•—i¬’289‡´OÃN[Ê_šã€²¾Mãàxl2ÆÁWæ’ bŽƒŸˆwiL†‰úÕ<Ø*>ŠÔ_P¦ÒPuNø¶'Ü+?Ü;:Uçà@ùµ†Oˆ†¾àÊÉô÷îT­:pTíz^:Àí<„§mvyMžá²œ  ~“ánÀ¿Mð×âoÍDˆá’i96^U¹Å™@ ¡+бz›aM{#þœÿ“¶¢#\g1Ô è÷ãϾ7Yyð¿¸TìMä®)(Ï©-(oQ'~>žù‘±,>œ9ÒÕ# þÛÄ(%Î1]jÄ…¶œßqlÛ€ô¶x›’FXœœÞDI¼“týÈfão-}XòÏH‘¶B³Ô‰Ÿ‡v4Ah©²øE2IÃÿ)¹ïÆoÅö0•‚n‚´(Æü¥eÑ|7]wèÈ¿ì^ž¢èŽ'c]wÝ«¶ßÔKë_•~#~GàÍ™2v‚Ñ|Ø .Ï—Ù§¡wú¦Wm]ÅŸâ‰7‡êØf<Äkí–¯eèŽ> ÿfFH2CŽ< ÷9¶¿ÕK7^•þ†sš2ý (ô{( þCüƒÝ›KB#hPvìPvO~Sï(ŽðW€VkÑ›-ÿ+ Ý=ߛ߲î¤}XAúìáß/v=¶Šq<ôæÃ¹稤oÔHóÍ®¡Äþ3{E=üÐâæn#ª£NÎð,zc8^%IUNïØ¸¬dp0õ ò*jN)k¡QGlŸ‡dŠ}ž¬&ôa;è)²Ï#F#µħ9~kŒ‘Ú#'Ò#GŒ“Xa#No¤NÌŠLÌÊnÅÆÑˆU7Î;¹ª˜ŠºýF¥«›´XEjÉ4ÈñùpÊöKtˆaF¸ñUÛlIÌ&É 3x6ÓVþ5ðGz©™ë%vDOw ó(Ãý.° ó‡Ozbóò…º=åéê yC:Á[aÉ8O´]läyç÷ô÷îY#r’ñV÷Èo˜°>/²½XÚÝã?WTÖVÏ|U×ìo^>Í «#OXyÂꈇB¿{žUéwï³ZGÑ k[3rèÚËfæˆÿÀd6+GüÀœÌÞ$²½òuš—žÙÿ¤×àÇ¡éç%ضÍÎ‰ÇæätšžÃ^Äò¹ï˜1…ⱘûúäsK͹¯Tü’澘ûú¦3ýŠ2•Åc3‘©_:Óf¦į)ÓLdêŸÎ„•¥?Äc³i@:ÓÍL†Eø,d˜oMŸ”î]JOŸŸaúœž8zP~Z¨œ¯:4ûéòñ€Øï4"ãhôòk¶ýNò$\NúH—“å°áüÔ#NqÐI¢Ý¼qØiE]QÅ—Ùéìce;!X=qÌÉ1Ôê lɨQ@ÈÏëöæûé «;ìâ¤3žˆªß“Å)'¼#åcEý›`êŒÓŒ›|ÆÉ“Ï8Åg„\þ©«ór »'ƒý±±÷®dÏïžqBÊ-õ 8o8ïœáÓNèþtaÄKã•üaZ¦’yx$¾dÔ&_mò¥S\%’Äî5°;œQ;õ†UÚ ƒÝNqË(ªg¸ã$Ù¡=–úý=óÅ×NÝðo2>¢#ÓôÈ49è‘ÉôȽ2 zsÈ÷|•Pr7öÍ4Yè›É,ôÍý3-f&üÇÛãpÿR”Ù³&û·Xˆ#ð \_ †ü.|>ø¤®{L þÀ* |ÊzL þUFøLûÜÇ|½@Œ"°“™$™tìk,“â0QÔŠqàݬñèF5“®qµUãj£ÆÕ™bŠY㩨ñXFý¨Ó¬ O3*<-SÌh¨ðLbêë<æõH˜eñ:›ÀŒ*œ-s†þ:—ÀÂ衚1U˜ßˆ×qù™ô^.ãÑóE¶o–öð^¸ilU.Q§ëÆ\"G×ݹo+e=<õÒERûÒžÿ©@8@?­ ‚óZ¨þ“ôx²À||[.ëI¸Šä7J{y¨cˆB].õ]÷çRÓÓµ6—Úš®›r©qéz2÷m­¬åºX¤ügioÿv‘¼g‘”ÊzSâ¥"õÒ>n”åP.Aû´¾Hûyi_ÿ0²n”¥/%Š"{¸´ŸÇ?¶ %Žm’NìG‰ ýúû¥ý=þ»Yá‡bûö_~‚®5SúSêå"LJ¥<þ/A÷K‹®ÿ4ê~:®ì½——ñûÒÿ6ÏÒÅ ¤Ä+EÎ?×K_eþµ^úª(‹Ä«EMþQ/]+jŠÎ׋šA¸Q”݃.‹üÍ{Áóu‘«<_åÀÿÁí¢ÜARéh&šwŠZ ‘Jǘ1ùºè¡aRéXOAd,=Ý-z.¨=ïžç( UêlÀÿY€T©Ù”Ú'ß³ÕQ:àÏMð~Þ»ËQ:às&x.'øóæ8Kç\ÞÖÐÇæá;6ž?8_«µX¦pxœ§y™DR*ç uèÔÁçs÷Ÿ„¿~-V‘[P2ISñ)&à–öawøŸ±{9p>÷µ°›‰¹€_¹e2ðB ü'˜ÀE ÜÖ>ìÐc3ðb €`M؆­mØ$¶œa—o² [Á°z†M1a+&6Ý„­2òvìc¶ša—oª û„aW6Í„­cØ—{-ÖìÈz†}ulîrÞž&l‹¦Qw-» cnïê6A4¯Y1r¹@l—J‡yB rÂMÃ}<äÈ‘a±C*â -°—§ÓBñˆRé Oh€=<pGì’J{BssÂÃ==æp°Gì–J‡šÀÞp¨au*M`_O+‚*‘JØ+•7¡ý Ôá—JG˜Àþp„G$¤Ò‘&p€™¤G$¥ÒQ&t :Ê#öA2›¯Ø5ûdþZ\äÕ¬<|ô{´µ]”ë¥5 —a—m/(×eQ/§Ây‹›·‚Âò±¢^–Åe9Q<¥IÈ*®Èð]RrY“ÅWrTCDÑë2}×NSz°3L2Ké.ˆ¯·(ÄïÏýŽÌÑB mì¡äkzbÅ£tÞà ÔÄ|;ñ:›yÃfíL^ç(Ì+.Ä+.=Û*ó1 SÉðÛ·@i(ù0= .QÄ%TåI«<¨‰¥Jh¦‡4 ¸] îÛaS5YÞ.ª†GÓˆ›éÑÄ Åb3Û šðKÁÏ5‰]«„f‘¨_2Ë#‰u|–)_!ûïày«‘•yÞjð¼Õàñ¢²];”TÈÛÉk no"ñiô¨Ä-ª¢®º9¢'>Éa€ØK ø×¶ltŠ$W›>¥44ë>pQ•¯[¸éjïc£Ö`£Ö`£V”DleŽ«/tHI…37/Fk­{U9¢ˆ#q/6ì&r?ûi+÷ðÂ/÷0cG0ƒ69¦Àõaâ&ã<ïH%G‰¯“JÊÿI{ð}ŠˆŽÂ[œŸ#Eæ:ÄipÆœËg8q}’ê³Uéâú¬æúœ»¯>çŒúœ3êsŽ£€ÆVä¸þaVâ’".ýß+QßP aVâÊ}•ø’*±Ž+ñÕƒ•¸ú`%®7ªÄ Tbr>–c¨{.oWÞÙùo¿¶ÒULPÁ+¶òp­˜¨&ƒ_¢Ÿû Ôäò‹r•*ª8.ÄeäÕj*øU-vµ x­€DºÛ{NVSÅÇ*Öí¦äÛ©ÍÞAq[Xl¡ÖÚ¢rkáB­…ËÆ¶Ê6øÉ¥!¶–†X.¼ÿ© /öáv©xE’^‰=865_&õá$wI¬ŽœªëÔ>m%„‚$ÎÀIn[åá÷†äzX•ÝgVÖfFJ«Q;ÂrÕh€Ô«Žª$¨ JF¶©d<¦8hx< B­8kª‡ŒöÁb®ÕP¬(ô„càÃì–”€ò1B¾^`ƒÛÙ㤮',L¯Àð8šoÏÐìGdÔõ ®k>0¨A¿0ô £Aq¹P.Óåf@½B—[ —´µ÷ÖÚ±ÑXº¬¦P±tEMŸ bä+5TM3Uµ‡ý_S£ö‚Ü8.ªr0ô9æÖdT3²9^8uÉ{·shá?ÄØÙÛ^¿­ŠÛª1æ‰sq^›G{à£èkDxT1€ïâNÃȽGwþ%<Ç”k4<ÇtÓ¢¼Ý5©†áÐC{CôÖ¬¥V]ôÑ¢ºI½/ÝÔûᎩ÷×8@ç§â:kßitbÚ6ûQç~t  ý¨s?:¨ðgõc†#ƒûÑ!*u“sG«’ÉNY ·èëT/îXD©¿!—>‘×ÓWýˆ”kèêüß]{‡º¶):XsÙ¾.°Ù3λ6½¥í^Íñ°­¼¥-ÃiëÖÒæ,¶ÍÏWIA¹É/ÄyÝp®ÈY8½ô¼í¼NšI±t‘.½ŠåKté]¬Ôë^ü õšnú(ì¬eÅÑŠ«ô‰ w1öÅu.ªfÁ¢&nè¼XwKO6ÇÖÝŒYûµž`ØôßÕá{LuâݧJöÛÓ‘h¨ä¯ð9=4öãa¿1p™ßVÙ¯‹CºqÀšÿ›ç©=ƒÂöô›|L7ßäcº8©#ˆÉŽ|UÓ›Î7‚új cX±”p@èku—_–ŸQCÐp»à@ýŽp»V‘Ayâß Î‡!A-ø)äê.²!&!ÖA$/ûq$ˆ ˆýd)†ªCe)PLj&ÔÌ’!yRƒ‚Ò¹°£üÍŸ†l¶—>üͦô#)0Û¶âhÃH |ض3_sÙõ»v~2ŒÈo8 cGмVtÉ g+xT~¸sÝ7¡ÿ¦ôß ûTÙ\ÝŠ  Ñ¥²XL—ƒ/*Cé2¼X–!zf$³=¤ãhD”nç_Ó¾UºV ÎHB§šžã¡NîÜg¨?'¶§¿w?ǙĹ9H¸ì H'œCÂN¨È L'œGÂBN˜””Nø ‹8a/ŽãíÍO›\Åóáïà…ËSŠaR/UäØü¢5Ì6ߣDìºÄ±£Ì§üý|Ãï/åmƒ¼‹:ØÚÐ\ú‚D¿S‹å6B°H%’AÑÄ8nð|ê=š$“F¸“×q¨=™§Ð?‘—L"/!£ôHÉ/!¡ò’x™>µÕ…¶\Bû&BÎÑhIUþ‡¨­£xŸâêà¶fò 'êùª¢¨ƒj“jú KDqh'‘ /ôxT{f…B}ÃD}ƒxƒxƒxC| ,Ie.ö{;…yw. \Øæ‰ï,l·X¨I³ð–I÷-fá-ñŽÁÂb‹…Ú|EWÔpiâþ’q Nä÷˜‡÷ë¥iÅê¯Hì/ÖÊD$´—h÷zŒ8KÑÐútíñHÅ{V{׉÷"ìüŠÚœƒú•awX|L7篓Fs&šÓ˜Ðº¤H:ßÑŒƒ0þ¦ü˜¿Vi5ž¯~µƒêïLÛcf/»óf¦¼æ–>j¾˜æ³ÿ樦TÕº|Õ®¨sUÿjVõ¯\Õ¿rUÿÆUý;*©þSü-]•¿7TåŸVUº! ]5{vçŠTHf§$­N1*ÒS?;™iÑKŠjœeî¿ævf_Ébw?銚nûóèÙÖŸ¤´n.©¿$J˜}¤q†Z8C œ¡’¨dœƒù*õ°4R2_´‘„Ôë —¡ß‘Gòª©26Ð>Gíû´±’-%ØÏ=Õ|Œ„wµ+á=DÏŒ—’|a‚”zâÇë2AyªŸ$q§y1ë‰5œ×€ô¥Lå°ƒ]ìc‰û’¿/Ó 1Ë -Š9Rh¹‡)/÷0™¹Rhöà  ¹}þ@±HJŽ4ä}ðÕf[7¨¸Ù‡Sk*$«n—IliMýÇ!B+Ñ‹(k¹ÉrGÔŽöŽÖÔ<×Àè¨táHê!nùÓÜòë­–_o´üz£å×-¿ÑhùMFËof_kVËojhùÍ -¿Ålù­ÿ«å·§[~ç}-¿«QËïI·ü^Œ–O˜µØ—nùZ³M5£M5Qgv…Ýè £å<DœÿWË d-7+ÇV­$á쬗óŸ0ǪqÊè—†TMœ6GÈg÷µöažôx6¿b5ö£±¯Hðå;Ÿf©ùÉõ½&…vÐãÒø!]—B+1-.ñ”¬ô(â†ôdGqK‚éÍ‘4Õž²Iµ§ÌT{"Í}TûÊ¡]ô¸Ë¤ÚO­ÕEž’UDµ¿LTÊ z4Mu”Eu”Au” —¼©Ž“ïãu¼lðºÌàu¨NbªÇÒTgYTgTgÉbÎýTçÝÏë|“×¥¯ @uS=ž¯6WÔJÈ.“92†a `o“‰Ø5Y¸kÒª3 ×Э~ÝjF± n¡gK¸T´”q™U¬à2»XÅ…ú ºÌ)¶Ãbxn±¾ >¦‹0õbF,Vʉ'ƒi~œ„íUrÒzpˆÕrÔAÚÂiT(O…KRaÖȉX&IúÏíÈFÃ)Ãæÿ+ìJc£º²t¹Þ}›]å*»\¶+qKa„:žH3Ó1[ÐÌhæG)jµÔ‘f~´º…Ò~•¶Ò£þÑjÆ-æ†`–àØ,f·Ù88–°mpÂZUB \:èà9ß¹÷•«lO7ÈõÞ;ïnçÜ{¾wîzb?à3„yi…ö ãÙp ÓY¿:Åù?GÔËU ûd:°Ÿ§ öö»Éâ£8ï:Yr,(qlÂËçØUTÿ3?ýÉO‚ì z!¯¤!›ÀöžèalçÃ|ŒófCÚßMHÏ g)œôsF±á©„rFôS ‡¨("<¼Qµw(í3ãÇ"fÕ'ÈŠùÀË—/C‹áz¦xì`ÅŸ–˼Zô\ïºâ>L†¼»ME7ÊïT¨:N þ4?l¤  \ŽŠ°SÔô‡ÊàrPÉ%ýk\Íû2ø8ë® Ý ºY^þ’.—êJå H¡XWQX~¤–)¿ záò%¨ÎmÉÈí ¼«¸¨ü:èE½°–íõÀ’—w‘TT×]TJ_|ge쬗ò¹š(R»«ºó.¶ûºüQü„N ®íx7UÊ-í-½(~ 'ý—r@ÚoÐ1`ïwA¯m~s=AsõÃdïjœg,Êÿ‘nžPðç»ô¦ºbx'‹©e»£ãS L; s)çÉL7òrº‘ŸÓu•“œi¤šÃ7í¹T…©¦¿DmêF.ø{!äzK9ÞYjFŒe(1'Dø±‚.ï%­•ty2Þ^mbœv£¡ŽOdYh<·0>в'ž%ÜR#­ýø,3²jÿ† —þw…áqWdåfaåbHr5jѧ‡ÝE9²CEße©cyºŽÖžƒ@péú™ºë¨ˆ™*^O—íÉ’ p/ô¶ó3¼Ñî•n2€‚‘ÍtÙ‘ŒvÁL² +¨w%Ë·Ðåýd¬ÛˆV¼O—ÝÉø 'UUöÓeO²ê<]ö&«/r*££}PËõ†W í!ÜÚ`ð‘ÞS Þ&ª¬a¹ašÃ¨3¹Éð¬”r¿|è4¹ÄH>òFe—¢)+“ï¬M©r¹ÅðÊS1ÙÛ™±ÆT…|×ð„>_G2m3Xáþ=:Ëá·ã¶‰Ã¿oøÊçõÝðjfŸAd¿áÅ9/à6†ë?P„™1hõAz`8޾ˆz"úa?úúla½GšbÀ^0×8—'´dsºR•ò¤áUÂEžgøÓF¦ ‡I1ÒÊÔ ©gëÉzÖy¶þ;µt‹Ãé =Ê,Úb?'Ê-&ë´Áç*”Bž7¼*®´jyÁðªé½Ÿ'äEaµöP£ž[Ê·åö%×±:Ü«|yI8PÇ€—U© ›ŽÓN‘¼2 #Wý8Ð’Ï¡9׵ȧ%*àb¡ªa‰ÝˆQº[j76¦ž‘7¨*ý¸~eƒdŸF:. ç+|¦~‰Íëo©§¥¶¼cL9˜ð*=ìEtIÒlàÝ£f !EZ¸ôãéÿI~K²†õúÐPÖëw[¯0éd—f‡º O ²f³C½ÌÑ_H“ƒF¾Qùy•0Äcø6G(|Ës‚ù7¹êT˜žJn‘ÚT´–!àCè €5·T%ýUÕ¦ªÜæ·9ì5Ø*ÜÚƒÛBÁà¶HÕ¬%¨f· 9O Ú|Au³@øV×W‹ –Ô*|Tky¨¶Pø¨¶Hø¨¶Däã˜-ÛÅ0sä2ÁEµÁœæ®@°âUV²šWS…:,܉õÔÉÒ58&Y+]ÑuÐU¶^ºÊ»é²?;"]=ÐÇj÷½ÉÊcB®PŲu£tåJj¬Åru3¼âN Øj¢úÐ’ÃЖ‚l1Ë çAW©\b©†©ˆ\+Ø j$['¼ÃT™\[ÀT¹Ü `j£`‹ á7!ÐY¿·M¾[ø0“[EL½'<‡qf»ðbœ—S;AÁÔ.z‚©Ýê‰è{üè{Uè!˜Ú¯ ¦‚Á˜†©˜<¢¥¨½ öˆQ0&. /ÎÒ­”Çia\aL•ì^+´1üTµžm€1UÇ…<. Ð!žC‡¸B‡jy‚’W1õONŠt8…€Õ>:œQO„Yt¨ dÀ ø˜Fêãò‚PpQ( ¸$rpYbÀ1>/¤É/D>\«U†XÎ6Î=Æ€çàÐ8T u2gjSñÚT%k÷=¥Ý÷¸yï³’l‹G¬äælJn5›lºÌ1Y¹æš¬\óér Yü¦ g’% èòA2ÔB—}uáVìO–¶ÑåP2rޔߢ ÂC‘=Àfªo(<»ô& <ì„S5‚Nü3ñ l YP=áÃô=‰ߪ§"è &0ÓÍ)gàõ‰žI¨cïf˜”ñL³ÀÈšeRàÙì8bm6á083G€4\Ps5ÁÉ©üü|ŠÖý7±3Aé~‹é¹ì8³áò> M_¬ãŠ‚–Þ'ÛM²syZÍÌ6L·éý9³ábÙšF²ƒa,¯ òŒ²\(.ú™1ÑNSvRÕ64 Ý-±½H§WÖ²Âuf–n©ùÊõZ¾dúÁÄÚ ‹ÒÌ…£; ?&Ë6Q5N–w™r§ÙlfuÂHªKÓcòÓ+÷bè n)L¿{DúÿA¶šžCo£1¹Ý<’;†‡“;Må35Ì>S)ùδj—ÅèÒ6êræ2ŠïŒDzLŒ÷wdVÙ0Ï> »¥TÞ¯¢Nª‘* ·óðèb8’¬è!1ü1?fÊN« 1p²H꘦WÊ^Åbø¨0ýGÉ|1œ†ÎŒCÚd ”Æv"y%†ŒÃÉábýOPVÒÆ|^?…U/•¾ÐN£ì@øSÓ‹"ÐeS!ÔzÅ#\|>-±]3‡[~aªá4[a–Ícl7†åM3$4H}Q#* ÑZ z`ò(M˜‘!tbhz`24áB†Ç#˜d<1Taz’æ  „²–[@({…„rVZÜYeq¦ÃB•tZ@¨Ð ^k¡J×[@¨È ½eɇfB (™¾òÄÌà“fŠ'ô÷É”ƒŠ`Âoý%®2KNç(Ló,>üÏ”v“…¼Ñn¦EÙ̲Ò*­¶ÙêhNs•ÀŒ-A–‹<Æn1c·˜±NŸ±NÅX§blƒbìmÅØFÅØ&G®u šÒ:‡šÒŸÙ·sÌnÎì¦|f»4³ÊöjC„w4Ï[ÏÝ9ž·çyÛèÝÑÑñ÷ÞþÉÎŽŽ nuµ´83×w¿^³½zºxt½Ùl”ŠÅÁÑAÇ]+Ÿ?¾84R@ˆoÓn÷lïàÑKXÀŒéU\«Ñ´»ž§Õ¼xô(•Z­øB-·†EV+E³fÖM»é‡‡‘ j¥´ê¸u£yÉh4jVÅqÅûÞºS¹»aÜ3Vk†·~¡Ó´š5óÒdÕY1ûæjæý¾S}“£ ÀÕ £—¸×4€=XqêņëT[”§U$ “y ˆh´Vj–·nº—Zö]ÛÙ I¡€©¸¦ÑtÂñ5Ã^kkæ¥Ù«8ÎÆy4šæ¥ZvßÈɾ‘¡áa’ ¼PŒ6 Aõw©cfÏWº.tLÞBÿ=þ'Û::Pí¢ÿþüùÑîŽi§æ¸o첺é5ŒŠÙ1WC?;ÞØuÏ´«ŽÛ °ãí÷L×C’û]Ü«~ßJ ¡ûêNÕìø`g¡£c×k­æ´ã¸ÕŽéØVõš?Ò¹Ís+,lëìxÄ5½V­Ù1TèøzGÇžŽ½]Zèx–=wîÝFž÷:¾ØÕñTÇÞîŽ/nCG::ú ï'Ðß®ŽwìíÜÚêØêè8…Â:Ñßm=€ÿFGWå!~ú{¦ƒüÇó·IøÛ(M7ÊG¸½iDD/ºËÁr?ÞÑÅòEã;Y|'<£¿HnÉ+ ¿Ý ¿—ȹ—^ý‡×‹Òé¢|œÞ“;/¢÷@á]ÎÒCòû è/Âí¹ø…Ë?Ip[ÎGËç^š~'úÛÑñ¡Ž½ÛI> |;ÉÏœ$§òCåA8ÎO7„£ütéH~öt®@óƒq[‡Ó§rP Á8ÆÛ»jÿ I>wv|q©GœÞŽ‘Gävtìàäby4_;iºè}0ngò×ù@í @ž£í`oÉ'ª'_~É.§ú»òõÉ_×CPŽßÀrG?û @õŠy;{ oÂ÷B»B¢<àwR>”ûC|;Cr `ù䯛毃{¯hþ˜œ½4…^ŠçòÝÉwwòͧ·æ‹Éé’ä«‹æ ã¢ßß.’Nç.š~‘‡¾O‚ÇïKäöÐüíâó×Ixo=þgÛ;àkõû½KF³åâ¡ Gçùf˜ª|7|©ø/îÑPËë€g¿‡ƒø,¾@âwDzÀíYzý資 ú^(|÷[Aø|AÐC ¿}=¤oEˉòúé™ñC{¤4_Ûh~ºXy@fHO„ŸY9ž¦I~ãòY~XþÄùÂï¹'à}<’¯ U¾úh¾&Dù*Ð|h¹ôtÛ˜þ–(ýè_A9Eë×7)¯ ÈçD›ëo+¡þ&äõäOœ¯Ž„òëЩ¿-IýMÐúÛ’×_®ô'DéËþ‚¦ƒ5ªñ€ÆÑËk>(í¾¦Ái>ÝÎ4 òÝSM£/ªili[¼¦Aú š~g/Õ|v|@8Œ ç§›jbT„ãüôPM¬'¬ytR a¤›æ§‡jbœæóÍFj–¯[òw‚þ%ù¤#-ÉÇÖtz©FùÚÑhX¾vÒtadÉI<Ê_/Õ|ºÉsL³ šK¡7ßK51(§ÂN:ï"ùëÚõú ,·›íTƒØNxÛv‚F‰Æ“ddÞKGòNʇrßÅ/½Tóé•hfœÆPàÞ+š?&g/ÍGa;ÅsùÞÉwOòͧ·æ‹Éé’ä«‹æ ãvÑqw7Õ´vÓô©&ÕÅ4¥TS¢ï üÝ|þ: ï­ÇÝmx>ák>;ÈŒmªåÚyg} ã›z–ÞÃøÇ t<‰¤ã;ÄŸV¤úk7)EÆA¦DùxÆrèÌ«P r¶Q}««#Ü_ ¾ž†û¥h?νDŽä=&’ßcÞcBòúï1AßcBõ ïÑ'y¾ä÷Ø‚÷蓼GŸþ{lÑ÷ØR½GŸê=bí²—ÌHQAú·×í·¶{:vî +{é÷â·o:nvqã8ž¡Ññúí¸ßyW·2¿ßy¬c¾U·lÇ³š› †wwΪ5Í4 O‘.(×òúV±À¾²Ø·4ób¬?ú`çöÎ­í¸«ú§Ûù¦Qk™H.z0.ôP5W ÔG±XÔ‹Õ‘|IÿÕIú+~§ƒÖc'«²‚ƒ¿{¤ßlu‚ÞZÁéàWpð÷Mp[‘œŸ7 ýw µ[ø)ÐoY;Û¢í Éc+.x èS´òÛÖ™R.“SàÛ%"rHº[!|— ËÏ÷„ù&í­;4ÎÍÞ¯ÔZ^¾ ¾/ã›ã\ªù}']ayTÿgýF7§ÿC¿SàVBa~°®,õJú­ÿoôo'QçÖZQÂ:ÑŒS]3ó*VXÈ7[œ¶f…{B…f%‰ùô ßèg=¬@³JÒº‰FåçË¡+¢›æWªA%çw‚æwB¨A%çw"’ß º£Ì¯TSJÎïÍï–PSJÎïV$¿lEfëÿGÑkhBÞ¡–œÕæ¼µ¶Þ̳Íd|³¿ÐŸ‰ù3)A{æ4uû$õÖ§¬7NnÖ®·H¹ùõ&(/>ÿL^¸Þ‚ðX½Qù¬|üzë…¼¢ºÅ§SÆY²ªWܯöõpåëŸ)¾ÐŒ¿=¢ñ—ññ·çŒ¿ŸÝÞѱ»:®´ò¨êˆý€ÆÜÄ1¶@ÇXnl.¤c tŒ-Ð2î‰ósÍé˜ÿÀvy °:)Øå-ÀjŸ`—‡wÀ_2Ö⻩…„]‚j—õÙÉ.!ί`—æ‡åOœ/õ.kAµËÊú¤‚d——æ«@Ëm¤ß%Ì™þ–(}é.oPNÑúÃõMÊ ¹m®¿­„ú›×_?q¾:ʯC§þ¶$õ7AëoK^¹ÒŸ¥¯Úåí¦«8…ÿÊ»¼…oîò~s—÷¿™]Þo OwGh52ØÉ¡âp{,ß\]Ð]ÿ…ÿʾ…oZø~ÓÂ÷¿ ß_xìæÊÛðɆUõpè;>ÛÙÙÕÇùø§ðg]=;ÿKáÂc?ó䶯þÉ÷ö@Tï÷_­önu~¥·ûS¯¤çSot{â­·:/nßÚ¶µýW:ÿÿ!üóñ'þEakëû¶¶¶àÿ§Þ³µµýÝóµÎú&v<´k÷Ãìyômoüɧž~æÙçöî{~ÿƒ‡9züDÿÉÁâÐðÈè©ÓgΞ;_»4¾U@ì¾­ ØíD¿Qb[Û±@$B(C8Dà0ˆC·¶½g«ðޭ·m¾}«ð[…ïÜ*üý­Âû¶ ßµUøî­Â÷lþû­Â÷nþ‡­Â÷m¾«ðþ­Âÿ¸Uø­Ân>°Uøãßýhïá½Û¾ô‰ïíúʯýH/ć?óÏ»þ¯ÿ¢û?ý‡ŸèýÜO} •N×Öß¼ÕûCŸÿÐn{ÿwýîwõþö·ÿö'»¾þ#¿üï»ßó¯¾÷;?ö=Ÿø`á—þú§>Ôýg?÷WèýÄG¿ó[?õKÿë…¯~îG¿ZøñïúõÏlûÏüâïuÿÖû¿ü¯{í>óû¿þ£ìüŽüÎÏ~æÿèk…oüöOýÁ¶øá7_ïþ/øC=ýÀ‡>Òûµÿø·uþOïý_í|ßç~÷ëŸúãþ\á_þÕ/þ³®¼þµ_éúäo|ñ/¶ýûüÓßéþÓÏÿìÿÞóÇßñ±íýê'>ðozÿS?öéž?ùòG¿ÔõÖþìûºâ#ß÷Î×øÛ>ßý‘/ªóË¿üõÂÏ}ý³ÝÿÛ—ÿEçÖ{Þ»íãïù¶ž­¿éÚÚz/*Ûoôn½•ñ{ o½ç½¿ú7ß¶í­¶þèozóíþîŸþÐú¯¿ïƒŸÜöï}ÿ'·ýò?üÀ'·}ùS¯w½þ‘/oûÜ[]¿ùV×›ouýö[]«ë—ßêú­·º:ÞÙúïÍqò÷kôï_þ=ò·Œ:À7Qu’ÀnLüðëðßoÜÖÜÁí¡á¯O|ãÃ_ÿõ…•ëãçÿÑâ?ûüûÇIøÏŽÿƒþ~ç?øöž‹£ø¿Ï°tèß7„iügö}Ǿô3£¼? ¿0þwûÉË_xíÛ þͯN~}ýKïû—ù/¡‡ÍçæË(o4?zæ?£¿[Ë_»üExþ­ï©üä{éÏ;þýýøøgŸ}ý}ó7¶þî—7ø­£_AûÎÕà þk¿ò_€?q⓽ÿƯžëÁü¿ªv€ü7ÿ²ø‡¿þ¾ó[;xoû“ŸþOÀ;|ûÈ}ãûg¯Bº}ý?·þ#àþí|æÛï.þ§¾û?ãôºÞ1¼­_îû ü}ãùÄ{þž ¼r:&ßü¡/@>Þúü“ ïÿh÷wƒ¼7¿õÔç!ý‰}ÅrÞøôŸ×ðóý͇!~ëÑÿù_šü‹c¯~ß/þùçÆIyþ!-¿Óç_¢åýiú·‡ÔßÄ>Z_¡áÛèsþýcÞMž·¾:Þx_çè/}ì×Ç×ðß/B|uÏ¿†ò{óWvœøÂäW+?u}ø/Æ?é,¼ÿ'ÿÏÆüÑÚWW>ý'ãc¿ðc·ýÁøGûþ¿ûÚK_ÇO¸ÿ×ýÚøwM¾ó÷>}à3ã+{^>ÿÓ¿òÅñ{ïcÿä™âÏïº÷Kÿjöõó ÿ÷Ì?>ôŽÑÿ0~hå…C¿öþÖxcã³öG?ýÓã—~È\ýÇo|yü|ñ?öÅÿîsãøì‘¯<4øèÇèßKÆ»ÏýéOœÿëñUüß_Žÿ¹ÓѳÔt-{í|ýþ 9‚×DeiiÃjVÖ—6ë+NmŽ…¡{®­¼Ë¬4‹:"[èÂZéîÖLw@É1W-ÛÞÔæUD:–Ü‚[ 82ˆÄ£Š‚Ña¿¢xZèOËÔøúÈ 3뺎;¬ÿ±Òb˜Hf †ÛDµ5íÔV 52ÓsZnÅœjoT#IsÕt]³zµ;œöhšþ€fT£q=œÉšÙd¤a-.:ÊÐÈZ‡–Q󠜳ºœHîv.[uÓÅ=¥F=7¬Ÿ¢Í {™ãçyœw ¤Ç6=Tà¢,b ‘‰zê&M§Ó9V«Ë.-‹ ¾4J‰ÁÏ]ãÒfèí)³¹`ØÆ–`EãAP¹ã†iðÙŸ–Q©~Ù¾gÔ¬* ÇÍ&# õÿD²}JO ž„øI§'¡”O$îúï5ólʲô¦× {ͬÎd«ƒ;L§­h¿Lˆÿë´<§‰´m³ZÔòˆ>‹½Ï>…>}GVÞ“ BYÃaöt u£ve3Ib ì­Ùd~ e‘ ïÅÊ.Ž¯Ð ‰´”ʹ$JÕ¬Xu£¶d6 ¼Ù̹NÒÊFD)žIK\v ½,4”Ú@ i€ ¶È ‘h$ûdÚuÐÈmÙk ZŒ$—’ÀÍu§å¡–ëÅê%+U§-Ä©¤n²=2‹P[žyÕ\CØ=s }l摊ƒÒ9¯ÁYŽåRËÈÔ©Cyx$‰J"OýY Á¾¬P‡ƒ&nµ½H"™kbµkBEÿ×Ó¢ØJͱÍîi4Mõžg*ÉjŸH­BÍŸMpüö ü»`4ž‰QbÌ^aT4^»bîÆ]5*&Ìžcý_þ´« ¯~ ½Ì,Fž¡¿ º Rm¨"¹êÅÁàmË`ÝLZªì+é—ü¨¸1NÜ áM—¾ÉÔ“·Å—#ΧµÌÉÎ¥c’)1Sæ+²x¨À[ ¦¦àµ\—žPp•?O'Ah›ÆK[I,¿3éOBr}Eb¶ƒÞ!1~ˆô{€.4pKD£ù€&iqH碅ÃIÖzý‰§Q û•äLÓNcT7wÉÆÉ‘ÄÁ]Kbhgr2±]V«‹°D…´³˜ü^uçžé㥬í¾î:k¨=¢Ê$— ASv"¾Y]ÂóOœÔI­oŒòvøjWï¢ùî–é5§’è¨qÆÆyÊ¥BOj}d<’&½+¿l'–?| Eî÷c"ðÎ@þ©„ôQ5Þß,Fž´HL¡KFÊ Úï(‡´à\oYÔ"]¦^~ü~Sîwž'µà´SÔÓžà¸ö{žÔ|CÜÇõëewZ‘`üYŽëå=´„Œ‰´Ñ/ðË ¥`‹ªHnGñÙR€\Zä–µðJÌ+ú&û]”E”LÛX©‘ö“ƒZÉ ég5̱@&*ðÇéÒH±1.ÞRúìÑPó ”üô·Ê //ÌV(Ñ0n¶ú¼ˆÃýޤ$Ë26Y«šœšž™»|¥ü‹ó W¯]iqiùÆÍ[/ß~ÅX©TÍÕµuë]wkuÛi¼Ûõš­{÷7_;%ÌšåªeWI`Á†˜åì '’øˆ@Y¹Aì—Ñü_{Ê8cy £YY';7’”ØŠêñZFmÙµÖ¸õ~-Û”Æ_Š´°¹&žˆA ù S£©a­/¤’„Þ£aºÍM¥$äi•ˆ`Eý€ŒE:OQfÍ Æ1Hα Q¿Öt0Ë€.Òr,M¯,³VõweÒÀUïÍu#úõÂÖ놓>=¤÷ÒoÛcU2ˆò«Mò¿¡j•}@Üfâë@ZÞ@2ÏòM£†w`öJ†4Òpû’úÌÝ‹×&¯Þ™Ÿ]^ž]\ÒxOTõ8]Üâ¤ë‘QÞ¼`LN¦êðÝ!øžèx6””>{×EÚ2‹Éɯ㪠ò½Aþk,“[˜b;l÷ ‚øœÈ׊óëBÏ©€Ñ‚ ËÙdD:®"†žÎ«“P &#*&6’1éÎ1ú¬³QFðˆí€š°M×O >®u ð·M®ôÓÀ鎿F—ÕªFôhü}N× ƒ\sƺUñJSV³n4æ¬Z o,†ƒÃ7- 1³ÄòŒ= Ë&f!ªø’ݪϲkPFãæóŠG"iØdó¥¬IJÑ4þ…¼Ùƒå6½i j²¹WÑiðµ¶JCõÐy“5ã]k_3)ÛUó~ny^X^îÊõ6Œ{Ù«í6Ù<›$Nþ¢rŽSTÆ–jNŨ™¨g#{qm“…ÊýZú¯Ü>޾ñ«ùòfTà ˜×óˆ#K¹a”Ã†Ñ yÀ;R¼´\Ùe[V¼ÀWÚ-ÐCZõ±òR>ÑlI–ëÕ£‘g°¸Ý¿ÓçN•ƒ Þ¹Ž½ ! ²;R”„/f=³êÜá n´GdÄü¡Måí Â;žù¼-è©D° l(‘ÑÀÒš5žHP s‰|­c`;çœJ‹ØµLkK´Íéu«Vål¹==týêöŒFQ>ÞQ"*{;+Nͱñœât"]¤-Ž$²b*àˆNk S¦´‹1F-Síä×)ƒã™XBt4¹Pñ Û¯S&T<§ƒi|ZD‘Z—\ jmë„NÂD¥Ò‚géAŒFQŸ„Õ$­Dˆôh¬ùÕëlñžl"T­ºgŠÉèù³Ã§Žë0°öñˆÀ¶@ïC‚%/<¡ÍñZ†ã6¯:ö›£.ÑKõõ.a³ñHóõÆ´ET[õF¸‹‚Ú6WWaª^*O®À!O¤ºã€bäy”‡RH<¨„ÏcÀ'å¼3¼Ä/.âk•ÎhJlyM§N(ìœDZ=Ô¦A«Ò»wÙ\ JåÑ2ÿžWi1#4v * •n hPWýRMGðÈÁ ºU5±Þ°Hwª2ñè- žå]¯›4-Íl i!]~]]…=Tôÿ=*Þ3l4aË‹Xèe'Óct)ÈKÍMj˜¨ßΚ¸q¦hg”€RNCÀ/“’áiw)QÓ¢,4ýÔÀáÃ:šÉÀÙþ©…hÔõ‰ ’à_f5hS§5»ZìL„M¢¼Gh8?«J-E“T5Áž‘NèQ¿&ÔhyºbÑxÓ8©û!y­:>¤¤Wºx£Pg4°«š_sÅh4[®¹„>²)é]HE\pBä3©È³69@ï=# Ñ¿‡¹(ãÏöMôñb…['IPH±7lb_DÓ{*'ÎÅ#ê÷ï°c¬è+6l{‹ÁÓ&·Õ`jB6"ú4·QæóqvH‡: ˆhDI”Ô¾8„×tTш}$-ÒWt`HÚsqX ‡È#©e$2¦_$bA™‡ôÁ‹ˆt5UÀÄc¿šK€Á˜ž ×E0VË#s¯,'®ˆõ„ 6:¶&AÄR¢cfI9‡ÇÂý‚,<îõ%!zjض昨Ãò-[mË8ÃãÝâ×{R ã˜cÖS¢†ãÓÓ¢<=.øÒíê Õ‹‘¯˜å¼Ó4Ïø€tL Š >¤@ éWwÓN°ƒª7ámxHÏ6¨ [<›\fOjÀýl+³‚¡·ì¬A·Ø8_ʪnÝ336èÕñqÕ%ë5s@!#´7„žô`±3øùÐluÍ\0›®Uñ|Ýå)Ç­ò‡&Èsiÿ¡h(ˆ'£ úwÉŸ76VsÆ7UHË£k®Å„øR-Œm_Ú-½}æÓOâ$ ïvÞ\Ò“‰FÓŒÎ&I–„ïå…/5\«iƒŸÏ b›±3 |zâpÒt¸ßO‹âñDTgŸ¹ìdçܰ¼)ƒg˜פœ×ØBx,Æ×ݱt[&èݪhôs¿(šM|ð.‘$ãv¢ŒÛ‰2^I”ñ ÈèS!@„ +Ë`>¯ŠV²o«Ù·ÕìWÔìWØD,ZÐUiáèv] ¶«`þ $DÅzìJÚç<%L cÂv¤Ž‰œ³“-9ŸQauv²zg«$os¦ËÿÁU"{_ù_0P €»ãAï®e{ƒëFÍ)Í7ñ3®±V®Ã²j4`(«ƒaMBP·“¨°¯§¥°ÈWAäXT$êuO&$ªÈþ°o´èÓq¶¶^”G…m§²ÉàwÉóŠ@ïßK#'²‰2ý Ê|èHfá}ÿv‰¢ EDŬÚ"åg.›œè>t;ÄÀu"t³IüxåŒbÃRÈ=Jm‘g±³IrÍê§Ñ”7©6HÉ›—•~î¼)t}&ƒ6hý¬ä‚rr#£–×0íj°dyË¡_Üêeîæ–|²÷Q{–vˆÉ^ ï É-ˆZðeïËÆ2RÁx¥”5ãNãBÖŒ`.f%cC™ó‡FôEdc•vÞ: Ì%bw_'""Ïq[~<'†Ì`°ª8Ãé_GåĪwDŽãÕ9˜ÐØÎ‡êX2È™ E@aµ* œzÈ’Àcê‘6–úó’`£jŽ.4b¯h@[$ŸR5j¯K£>¸d‹+C)ÐÔžQj4‘:2}@)4Cõ‘a%CHï6’ÕÊBF¦úk ýdº]Go]¨:Á |8¡„IØ>õ×ô¼"Ì}ªDœFŸªáÀÀ·_ÀŸÖ^EeWÝ+?H%ÂÈ@tNÿÇãµW6pŒèMÎ"pTõý³ëNQBü­›Wd6~%8LïxVÓŒˆ’„_K-H=hN¦–íÕsJ€Ý ®{»™ëýØÀ uì´š¤m0/ßé3y&= >­ô‰Áw*5 }EgS“È×{.ÔSù¯ùBj¶Q­bKfój®¦±nx‹°à[ÇçgÂõ=íù0ãÓ\ú¶ç[;Ô®yÖ®^J-Ʊ±eô ì]a,+%ž ¹J3j_~˜w¢yÙ5ªêͧ Ï,ò¤(liÅŒ¨ ¨3빃’"Ñ_× Îà¨Aô ­„ß·áÔp{Y0Q—Weghõ e²OqPÊ«“} ºq ÄxdKHŒá7ì4PTÓ£¼øñ ÞZIwãÄÈûl7N­doªÙ›ìîMIùqí—•@Ù^DÃö˜ë\15âg–´I­¤ªÔÁP·Xa½˜"4ÓÍ;áY»Á‰'——š®s×, ÂJþ®TZ ,á¦ß¤bÒÆ¨´AdÖJoÊ2CÁ3º¬:ê­Üy ýIõ–ï«*\õÛ/Ó¸].>ùó0£‘À ºdr,-L~VD¦…Ÿ…„{lp¯]ëÆ3·ƒ ZÅhxÒþ†ÇÈúŠ ÊP%ëoXQ…ªQIW^dȆu߬]A©s+/ZX:c—aC U˜P’!ÀµØ¡pë,ªªVÐC)îk–(ðT"kÌA±ã"tºð†éIè…wñõÓŸ(!/“±™Š6V_îíro3û5×or}‰j¹÷Ih.‘íßiÔ*­ovAÔ\¾`Z'¾ŽcvÃhFvºÏÉò®;”Ÿcy©Ê§Î7æ3©xY1³ 5â\|/ÕGÀñýìç¡§,lþ­Ï¤âù¹Õ§9ô>­Ô/Õçî ìfù¯–™ëñ‡’t¹‚óL騰cÄç—‰ãS:t§xç¥,ˆ07tŠ:‘‹}Œ ½,|‚-ŸÌZµ;<6Iñ9tpFŸ6’tD¹æ.ðÆë³9…f˜â½Q)Ý$N/S}cÞ~!œ“b;Î*•—,п±­@i•F–p ³Nj‹ôžW3˜ïcÉcqÉhF9—3[´Ù(‘ÅxPP·3FÓXDóÓåò¡%¤ôlù& L˳Ê㥡‚:(N<ôDú»é:5o.qf›[e˜¬”QÇð¢!¼×54ÃñœÚ=³È~E }!Åþ‰º±§Š>~GÎ{›Ò,ÊuÓªÑ#Ò:Wö«!×Z¼÷=±„QH¡‰fW«‘ÓBÐ’—~»‘ÀR}ž¨ÛškÙþ1©l°÷ÍÒL|¹cX.j%§ô3± E{A»NCòR‘Z¶õî–™2%J¢.´µ³gW¡Q§¨ ¶ÉDš²aÃúlj½0¨ÏðÐ?Ïáøß§"Q8þ9*Š4C-œv0‚ Ú„*ZÆêYMÝ?Æ¢Ù9ÝçÄ)“ŠÝINßhZ5á‹ jóYŽÖ›°´¡†Nˆ…Çø _µî=Gü`K.¯ñî߯–C6K§Ií(±¶CR£Ø)©Ã$9-6bÎ¥ôážqó8›U ¾‚II)¥fl§£ aNþÆK&qNJ˜>G|>­|uUÄþ4 }1Fúá&ôj(¡1qBtäH•7¨ƒ+©I’VtÜ9kÓ[Lˆ/ …¾âå͹N‚8pEk.¯hÿ})»uÁ«XêXH*ݘiCƦ6›Ä½õ@’¼ÐÓ_ûF“føKç¯#Gµœz@z3Ê n¶"ú<,ñ†'$~‘z§LÉ ë8I ËF]»û±ßãL.ù·O/-áØ³R3ˆ•㉄ÅAßÎÀ‰ÇÈ™‘Òtcô“h¥ÉGÀcºÍ‘ã°ÛÁ%\×\CS9pÛj\Ç$pË‹G4€ËæýæÞÇS YYÂö«t¿Œ¥3(MG/%¤q¯ ©§¤))H“Zéq{1 c ɪ¸ÇRŸvjŽ K0¤‰øƒò¶ïcöD»¢C$OÞ¦ð¥ó8 粌E¿ OÖ0Èåv1¸ìõø‡ðn/è ÷Ì[h álpWq*pký‚S5j$ÔcgÛ,5¯™† Ô…=QÆG騦3ógüRþüÕ*/z9¿Dr[/ô…6dÂÀL~QU“ ;(LlÝáóðõãAÐ0ðê(Ø!L ;Å0“u‘Ñ…ZÍPº4'›ÃzRÃøy45c²©™-è¨áT:ÂÔ&ôm£éHø~NMŽÇsJÚé•ï,Ïb‹Àî Dk¶Œ ùè½½xðsgðóJ¨u‡¶¾Šò¨R¥åzHÏãšîT6A¼©J^ÔÏLf}ÅoNs¨øpYQ?˜D…LrË Žp3È@ê‡ëÜ÷ýxdv ZÎ&D0ž¶Iõß“AR,%ø¶;›MøŠâ¤Ld“âU\“Ï(€Ý¦±`›ŽS[¶Br-«¤¶É\Šî„gÌ´]sï.;6é°çó¨M!éhè›Èúi-Ó¥>´›hž´3˜,]É*ºŸ9£bÎÒîh&oþ`6=›¹ìy)3™¥,vuŹB®eB·Ù¹{½ÁßqÆ‚®šš³¹÷,­ãåõ—3´ïr0˜aNÚUnÆw\!8üxˆGÆ> ¥[sP€£rws¯?¸cÕ£³qTÎ =iH¯ÒÛ€¯Bc‡M‘íõ@ Èï¼ß½éq9&¢H+^Ũ՜§jRÙ¾jn,.Í{™8hz,„#>ÀñÉ*AeÛ3‘eŠ2‘™ GFxEYÁWÄ §$ÈèEQ”…ÛU*ÊìI95®\žÖK‡ýÜe`Ñ5K VÕ„{7—àx [Ë–ÐxWF÷H`"]UQ˜q‹i}0=õ“ö-ð´±Ô ­Ò µpô¬™ÇiŠW{5íOû¯~N¯ÑØSÚ3g'ê7ÓC‘Žq@Ù…FUõhu[i¸&žNTY?§êžªÕëüL²T7ðß3É®ÑIGËéiÄy¬º«Ð@OHha±9Š¢À"óÅÌ55+˜h66Êôwš§ˆ¥3 í¤ÂŸ_Ý-ÔùøPSÆ–!ÐO›vD™Œ zx †xºoÀéË®*æ:JþU…²¢9t"‹r!ª¢íДyÂY?” !ËŽšeέê¿"%Nz9Œ;ª…šlªµz :– "“ߣÉ@ÜD¸Ðªä R^l%RQ“lÝñ!˜¬S— Š\ ¥©V¶a‡Í#ú8|¤wŸbl·W!½jŒÔ5›>×­ÞaêBvê$6MIæÓx.öd3CÖƒ&:‘Lšîxv¸©fà‡šú\¦ôcŸ@†¦Ã>ÃZÓËTó¿SÊXrLâtJш!42u—¾öGžxtµïJ«gËSÇt@°zrBHôÙ“*ht™îTòº‰‹{á%§ib":LâúÒ¥§‚Wdظ«‘+ÔùºFˆTN&ùúìÿ× MzÑ4ª›4Ç%ÙÌãÏv¤ûcEâRI®WcÇÕ©ÍUV|”¥Ùß W©èñïZ•»×VWw¿hn®8†KT´¡ä¾knÎ86Ml'nX˜«±†W÷ÁœJí–B9g“96[#ä=W–ôš=¨Ãßä0ýô=I%1iPPWiTÚDÒzîéä”ñÅØwȯÿõâJY@)¥ iRn°ÒÏi,ÂẸÓäjäªcgwó&n'¬r«ÓË¢)ÜîòÌüìòÕåÙÅ›“ó‡’¦= âÈÞ…Z¿æö'†TZ=5·ƒ¶«t¸iõ+%‡±£J¬xƒc÷~™Q1(Å·44>j¼öž²#Àµ=o~C•OËȪ[<èDƒ[¯;ž Ö3Î% ¥ ý D~ñV ®™ãñÄLŸÓ§ÁCIïÍíHA Cíç)B¦Ã BÉ,l(9épƒ/&¢+Iï&X[8žØ”X?p.9÷âOpçµK³wf®Ýº:˜ôBÔblj?'X`bF œcÆûä[çt€JœVͧϟ)é´Ä¢èrÎ4Øû–sÊ Jn1§$Ášw»EÂáé¼å6¿|)§¸¸í%\Kꫲ^©|Ý×ljêSLˆ/­ÄàÛ.3ÛU§Ac±$P©µ1—þBÛezm•éoZ´]&˜5·O&Û%i·H”Ë…¼"ýHv-¯4¬ˆm•çOçùåù{íGM6s‰ æ‹ÃI¢b!3KhBq†QF暸yS>têìPiÖuŸÁå1ÖŒ³Fl½ @v‡’}J&òtŠ´¸Ÿ)XÞº³±g¡|õέòÌò4š¾2»4.™8i:#šü{D}bZj uü£C 4Y©™Rõ;ù¬ÔL©ú]vV*=q˜ŽÊ:àŒLê-B‡êNÏh’"½fõ̦MóûÀ ,KÕa=Ú¸v²¾‰LÖØîÜ6ß_Ÿñ»Èéuש›¸ÕΤÎÜALdR&§CqähÊ—î0-.${!}FQJtDAÃÃZöZçætNaPS)_Â#F*iE@Œˆ˜L)<)‡m^Ò·€ å6R~áÅßôµázµëáLd’Y„žÈ"ôT@ú/Ò⾤\B"¯2›¡qÆ÷Kv•¯á×#ŽT²‰´¾„¸£ÓKKÓŽ]%®tù‡ç%˜»hîqPŠ÷fÅZ…mR¼rÔ'ù@+³ûß9gdÇ%¬:Þ ô8¤,›¼ë‹ÀÊ|™˜S)Ü‹Ì +~ü#§<˜¼æ9´!Žtß³Éy†^ ªQ[öiâ÷ãÚ†òê&ˆ%ƒ+*ùëNͪl²ÉP»ÄÁT2³Û8|TJ/åΞ‰º™Gb5ˆwèˆçèQµXahà’÷ªqÏZ3Àó‰.JcÈÜ-ì8:Ûª›ù~99rŽºçDZ½ÁVÓª¡~#¸€Êöš®W?8ÅÐÓÙDæ1›NtÙV•ù³IÁðÒUBÈ t6bÚyWÈÙˆ¾ßx=bÌKqv2½DM—¼É.QÓ'xÌ?´f€”RÐ|»,Þï-ç08c ,ÕL{̃‡õIF»òËëñ’z-Mðd3631çLj67<­O³‡ÜŽXM‘A²‡3Y«IËI]+‹•Ýt°?±g„ üïãå+è_ÇÝ igá¹aDQWböSY´l&âBVàÛ®_EŽ<…a÷ïã9SZÄyq鑹U§ x$"+dT—‹wç©7¾áh<èhƒ•ÜC`¡EA&pø'£¹® ‡E…éÅé!M8½Àfqúá)×ÙðLWdx‘ÜŒÙh®jª¦Þ:Ÿ–Öïžhu–ôK+J½žcr%Ìàñ„¼_ÊÁ$|#šoæµVêVó¥–én¾Öñ€†WÎ$HY!Œ‹ó±[#uGµå™d.ÝUq+»É±þU«†^ÒÛEAÎá'Эix©ÌGe¥JͱÍ#R^èéJ´ÃœönZæFQÍ Ì×ó "Yå ·W S3º±ä¹|©€_Èl;ÄÀ½exœÆçƒ_È'’.ËcQ9sÇ\Ë'¦jypÓd«éõãj>yäB§@\9Ÿ8N-šÍ'É5W]Ó[Ly>È;œÅ¾=ðkèiŸÖåöÏ±Ž—*àÅhï6Ò¶êÁUh›ÅÈó*tÉ?  ¸fͼgØÍÀé°-öã?Åß½€ð9ÕVÍ,ŠƒKšÞ©t"ˆgÀƒÿ€ï±'ž¹—Ve½ ööF…Øôê€ÄÁýo©‰·Ñü¨ èS`q—˜€y¥y¼> ÞË‹äÆZ¸™nq~gàaé°KúŒÉÏ©µš@¡ÂÇðUƒ‹æ»[–K[ogœ£IdË›‡kHwÀ­x3ĸ¶´ì\¯›0ð–GDè––Û¤~æ p㺹½Ùl”ŠE£ê¬˜èKª'—F‹#CCgŠ+-4`XvI%}ÕpÏg°INE-.õ ¥Z*^PáÖ ½`Å\wj( q&ÕR‰HÔ®fx˲œˆ¾ŠÒ —“:Ñ£rR…¨nÚFݪ D”Œ~¥¸z~>vŸüð×AiV‹Ñ€’mn°.ãéºÌ½!ŽÁ#‹åú„NøX´_\&Ã]#S1ì–œ©t\‘#è¼"<â†,…ôÿxFÚ ÅKý:QïÅJ$&"ì?ZGsóœ’Æ†¦si[sõ|9u6q#އå´U×´V7—‚ûÊ6³ûHYöhBæôpi*ÿÝS‹ÀsBrÿ‚wPÂæž”Ü[´kÊðð‰Dð½_“^n4ƒô“²»â(%¾T£ A“ýÛK,Ûå,­W¹´Æ$i¡™üå´¯# œÙ–f—Z†ÍM8ŒÎP@xK/eÕý»åSsP9>/âp¿o†–äÂ.’¹›Ú Ä)çlp×íƒ ·*çÙ+&ÂßiO^‘6„# ³¼{˜)É·´G<>º6©ÅÛí‘Ý4V¢’Û&Ù÷VÓn‘Ô6¼ "á*3ˆ¸ÖqUרÀ1ç5䉃_ tMÔRW#‚«E±è£ô¡ÜÛ&+…‡H¸¿&Í›04¸”ßð/ Cy'—þÚB)›|ž:•;ƒ}6Æ¿ê+:a^è)È,ç”íF‹«^?¨D."A*;]\ÓžZ‚]Yw\^ˆž³j5 Îà> …*ø”7ë5Xp¬-UQã3šW„§ñºqi¸äÞ—´”Ð%Íj vÏÁk™x¹s21²ÐBw&+iääü êYÉ(¾39U¿æ\ÓkºV¥™¢æ|Jèb¯‰} éIõ‚’Ć„4ðÐÝóê,­;SŽ‹”îI›³àNóB‹0Ü+`?õ>ï™ÄÅÑÑ`14?«Ü%K™áÇ}R^ò îrÇfºF½ŽzÕÊÒ]Ë.Jcø.úr>7DôËåÄBž Ý,·n4Ì¢ÿë™x[ÜÇwE!ºWŠ% 8$‡flÉ ÔŒ^Ìp 3ȋʤ7 Kô.'b¨#_ FìS5|‹÷ö,ÁrO)Ôí¬i£n¯Ø2·³‰8Ú Jpt-ެΘ^ŵìÞ²´v9˜B ¨1ýu4aGms®f¬ù—Ó¥å©K)t¹¸Ž^+«uê;L&†÷¦hiqõH2˜ù#K€qýÊ‘„æ¯%—µGØÓÊ&A÷ÞHq¬c:©À;ꃒ;œ\$¨«> G±eØS:¯åE®» C TÊË®Q…µÄõÊøšDò=xÍJ”z^‡Š~À†t˜9¬Ã„í"ŒåàS¤,® ÷ ŸHÆü"ù³?¼‚ÿ,˜ yì|Þ@jr­šáR°<*z\ ~µ_údç³Îqci qj>[æÖ Oà§ùÅlÂÐç´¢çá²âAAçGÇB†`ñ‹R0¤õžžv;ÄŒ´JM¬Î(d(:/5MzqHAVÒ)t`*:§¨C2ýÓjœG¼$;ôÆó†5xá"÷ÕÁu£æ”è)'J = ¨±nå˜ Ío ÕÐWAîXH.=É%MVÑ„.Io¡^0¼»‘{ÀãASièÄ"x›¸¼"Ð×ôŽvÝðOí…4„r]7*¸„·»’†²BA‚‘†ìzÁ…¶ ˜¶@‘…Ja´©ÐÕ ³©R„›ÌIØPÚ¢NE0Zž9”.kNc$ Á5½¹1Wr1 Í4Î¥Áƒ3;o¦kÎÜ(ÑÝxþ~9_}3WVXäÛš¸¡Ý´<49!ƒãL6Ñ,0“åçu$'oÃŽò ¦t´¯ÉøÞŽ >I—7LÓ&Ƙ3¹åÌÚÕ+Y…`7˜\nfó BÙÏRæ¤]b—²ðÉ€©,t0­Ç‰ã‹—g²vÕ&§ˆœ Ö éÑíhwWá‰d0[*Õ…¢>ûé”ý˜¾!©Åð+ ÂÊ©¨†³‹©$EGÕlºÞ”‚ £Æp* £©dÜ8•’ƒ‹s( Ý8|*]!D\ã`ÌŽ;žiÞ…R½š¹]À­f›´jþ½¹”y#_sÇqßb)•ÇæúijY¨¨”7­9£júþaH(W'ôÐêGõ ¡WJÅAï<Àmg€EßÐhÈ~ïœæl± ¬±Mjö% ŽžLNåQ%c5ÄyƒÜ7›MÆŠ¹ŠºÛ9Ë%R&ÁSŽs·n¸w§2 ¥ô`;<µˆJËe~¾‰̸”Mâ=8ãáÝOMGÃ}uÒÞÏÎÆ…|);júB6:š[›nÖ´AMë>§²Ó¯£þÞrZ^ÆìU©” ýü•û}4  ŹòâÒ2ó ¤ÀÍOØq5lúÆââìÕev-¡ zLÈ¥ïs脇ç `=:²'œªµjwþKûq0v<9\޲Erèjö°±nÖ »iUP7pêü¹3ÿf$ AÔÐ$BJÓ|!÷ÚŸ  Ÿ.gt³ÌŽ;›Û‰t4ºÜÆ¥;—2]Ô®Ö\%Àà–ó´ ‚ñ!AŒ¿ä ©NÍ4ìÃl tj)‰àDqõ‚ÍbøqVÞ]^i™¤c¼³„…¡O.9Ô.—àFi«¹y“lM8Øâ=ö€2+FvÔ¡øÞ›³‹KåkW/ê É—|'¶Y%wñøGIJ“©µ’™ZN {gÖJY¨ú©n¸Ž½F2œ6Õ•úìÕ ¾fºÞãôÓÌFD)NèùÞÉsZ.š­Òݶ iTŠ4†q|,¿¼0ügXø˜$¼t¿^#OdÎxDÆ?ö–§ZÍ&šUKO/ËA3S#"míå”’íèØ¯5ÉΗ#îÔcû„yd»1µ0ì‚áºAœ§ç”÷Þd‘—e/sGý_È"šp-–|«í…^í ñYû YRX£.2‘™¿‹¹Þ-nÊžqvqé¥l­žÑ2µR˜œ‹êïzÆúƒé±PàQ¹ÀÐÓ1Îë S‰&ÉNLøñ¤÷e8$‹]>F±àíÌøì ïN‡›þá9 Û…çÔ5ThVŒ…”VÌ5Ë>ªƒ4íê“qþ7”Ò¢Qµ‚sNÅðã ¹ ޝ;à(Æ=¶ƒ¤ G_ça¼ŽM%¡<0ÑÄ—Ïk tdÝÖ’udõ)P¸šö)¨v<¥þrà‡ŸY)¦ƒÃ4‹L;µVÝÆ­þo=MTNïÌæÂŠ¤ùj8ͱXšHÓhüm½Ô"½ýùo7Aª§IP˜N!”ÝEÓC*R1gÚWÈ»t‹® Ñ¿Ï ¢È±â¼sgßKãŸP`¼aìÄÑÅê,c¿4A†8*@°93ž’ÓiÁ¶FË[ƒY¿¾W²|D‰«šfcšõÚršuÃü#Ä;[Oñú8š,0TðóˆÀ–RØ™ëb_M](ü¤Tš ûR0ï””-ƒ#3%ß¡çl}Å„­.ðCTäö +N Ï Ä|ð¥Ä„AVVÖ8Ïp!ˆÕD_DEï¯ÖMûæèK·æ¦\«º¥pÏ E•¼U>qšJFÚÿ$ÔG*5‡,â¾…ÃßÈPÈŠ]âÑÄýk1„/â›s°ˆZÁ îÊ ±!8.h-m”F/9Ï+Í+Þ8ræŽ^’8½´„ *æÛ%my³aŽ&¾›È¨Lwä‹âàRÍ\m†]>éÓPe\ÉúA„Äѳ·)Òw™—L<ÿŠ7m^ÓiW¼¥bù’i³VœfÓ©¦ƒi‰!ŸjZÄÀ‹Å´ VKaŸjÙDø¥¶æ#ÈC>!dzÈÝ]˜•š¾ô•÷hw)z/œï±(½Àx&zà\)ßã]jñ-»RkÁ±:YË-ÁcçX´%ûÊÉÆ 9ûŠKs.¯R(ã©Å,X6—‰ìüÌ0îçËã“ \J-€°_žl‚#¬ôÛ„>•šN¸˜Î%"k!ð2^ÎG¿ò‹ðÂtÖ»Mæ’•q1ãk'I3¦OØ)kqÝðxöè ôMÛÙÃx®IÍ÷¢üí7M°"IY&M×°½UÇ­ObG5‡%ìðc ¨W±4BÁ%gƒ^⛉—G3 ÉCšé¹thøÓž”9Çöeæ¡7>ŸŽwL.!ÅŒL/u^ZcÝÈðŽ„—>=ßd&^Hu×â­GîNKôø‹´ˆ÷×hrÒ§³™!¼dòÐŒéYk Xñ÷¤k¶lŸ˜ÍÄFùè…Ó©ïYf½×µÕUιuÓû¾v£QĂ =ÂBÞ›µ„Y_KháG]³|£˜ú?ÅÒ4Hƒ7VÓ?ÿó@Òˆ\Sù¢~‰ˆiÎxjÌvÓáppËD\‚‰51]Í-5Ërvïë¼hÔç_J5L/ãÒÇ<•º|'¥ /¼þ‘ší÷²pì•ôÌL&X>æ• Š<[aá`4Éh ¾¡ÖÓ¾Lb¼˜˜³¶Í¨lÔ:ûåYŠ…¼6’,û…˜}^1 @¾“»°£§öJDEµ˜¾lùcqù¨ˆ^ΟÉ{¾ùèRkeÎ2‰õ؃L§ÐmL ^éñÓÑDÉñ s\÷Û‡G‡K fsÝ©¾Ô2[&[â‹=^æM ñ ãnú«Ó᱋sÇ+ AqED¯å5Lþš°ëÄ« jNƒ"~Gô‚'ELÙíIú`ßU¬¼1)%ÓdȨà’%ŒÜ:†>ØcþU`¶h¨‰ôLêâG…dEH-bÒ<ήTJXZwÜf…Œ¤@{fp­[¸ò©•2´äÀîv¯ëoo*bé}Uñtü5®§EÑ÷1ž$æ5)ç5àÅø»À/‡Œ %D)·“¥ÜN–òJ²”Wعšx¿—*Ñæ¦xÜîˆðJhÿDŒH’ñr¢Œ—eÜN”q[Ú&6¥m/•®¿ßªˆ•5ë`ïT-c‡´TÑJöm5û¶šýŠšýŠ´Ûà‡ÝCÁkhcõåÞN!÷vèB{ËÙ (㥥åÛµ ‰o" ˆ•5{$Ó®.8USÚì„ÇÝÀ#ªNkÛRWîrã¥.TVhf JïqÛ·|<^‚›ô¦¬fÝhHS!>D=i*,Þ“hI‘ ÷DŒ¬ CÍɯP](®ªê4p$½‡xÒcQgOZŸY04IÄÞ×…y:°M=i›zuæ÷ãºP­ÒYݾª…•éµ!,×#郥_x²› p·õË!s ê¶´ ðm H vÁÒ@ኻ2ñSFO©‹³Â#ðnbèdû!aGÀ„§wþªA²ILÜ?J’Øè=›Â—ò6Ѽ·žÅ›‡Éª|8öÕV­¶ÄsO«_»Å”g G˜Ðí½ ™:ÞöH‚ÈÔÙ*·ªð¶F²’cà™PÞžN¶«ª(ÙK‡—lËg>Üq8i§×m(T3v°}Åvù4P¹¾P°±nºV}â= ¬oµÁAD\¨6V–SüΘ•šáú…¬”é‘ ÄDŒlÄ‹ïwî—v\ÌNÂSu~œ˜ ’ U놇ûc@ñöEú`ÙLFŸ¹HF5‘ôríø8d¬D%jád‰]¦¾`Ùþé$= ô­`pâH)ôcW¾k ¤jYì®y˜¬FOv%ƒdï;¥¥’ -u®6ÕÙ7Zçk/!Í…q?! Í…q?)>BÖÂÍû0YÍÄÊZ8Lháqdb.¹2Ó&æ’/CM¤¬2¤ú; £dß!C%|‡oó/VQMVàïó§i¤¥àp¢NÖA“Ë¥g,×ôoÑÂÉŠœÛ·7Uo³СTwøûÀâ5U)_©ä÷À²—äöâ/)Øõ×ÂÉúî¨í\2HÖúxEœ'0KЉ“TDé*v+WœI´LáÃ‹íø¸Ÿ'UøxŒ¬×6 ¸)b»P‡Å{9pYµ¶ÔCÔß‘ëÔ¼=Ø€Šz^0í–°ÞWÃiûˆâd£ÖŸY¦²%¿&½žt-!ñŸn)’Éš4NÖû7@ /ʬ–g¤9°¼ëNãF#1^¶0%>š¡ •ñ:0Y§,8˜ \-Q HÉ}{óDŒ|Äó]ãO9.xjvjŽ;çWÁ„,¬±¡†.Ô#~±ãEL}yíSENŠ›çëkBü¤äC4›8 ω?U§1ãkÇ“W¹ifûµ‘“ëšÜ; ¦Oj¬ž‡Þ¾˜§V F­¶bTîzûåë3ÔeZbA r€K“ ‰ ÒÄ_˜v $Aq)0Á'µÓ;wö©mLN%-'R 9@Í9Nk’ÌIÞ*á¤:'aS½“ê$è]ptÙa Laä&úªd)‹­›ËÚÔ@8à?¡»KL2iW©ù3XLW§Á!‹ê±1üÓ™jÉóa¥»¤’ÞŒœø¤5;,UxßU}R•ö¼¢×5¯:‰J#ÃNE4±½âõ¹ZmšÛhâÇ“„Úd­6Í(ÞUVƒö3˜Ð,zÝjð>•Th9C ò {é®ÕX «5°˜|LU©tU{‡Õ’)´”Üù½«åáFî¡Áw 6çI劋ü´Ó)í5w!´b¥ §sauþ[66Ö̆46_nð¤D‚§Cˆç(˜ñ§Èa §Èa<²Œo+±ÍéDïyÅj@w‡öò*ÐW–æ‘Ðm³ÖL"Žª|rÏç—e#‚?"i=»ê#2í) ªPÌ,_-‹85Xœ€×ù¥`.Zöý hUØò:šmá%Ç •<@ïºQ^Æ·ÁÀýbÃbÓ)Ä«#Õ%ÀÁmˆ¤ÌÄË¥áóÀ%m‚?Ï»«(&VRÐÛ×Ì‹\p!R·û†Ûf58–»jÕj«· fRô°ª­9ƒú^¹ƒmêzõHéà›ØÈ®UjŽl3ÅäQäˆ9Ô¸¼u³*ÞY¶«´þ¨ e!„cÑBP2èù°ÙPNNk¨j4W¨µ2µIXp ôGÅŸƒò€ýAIgÅVáÆîA=ËP¶Äu@ 7aQxٹ˜¯Cáxå°î/C×Í¥Ä$̹3ΆMëüD"øFƒB%¬mz×Z.Ö¤2°J®D£R4À×ZMu¨*Kçê÷âu›ªêÛ@I/kø÷°OÍp9àŠQjqtsÇ«¸N­Æ´Ež0¤E†Rª^jÉ]Ÿ€ÂÙˆºÒjpÄâNx–Ô¯ÞD 3>¯®‘±öJô~\…Î gHB÷é>%9è9 …‹œðfùÔÜÃËCÃ:e›ã')À0ÖÃã4³Ða”íF«é3FõrEþÐ|—ZyúY§½â y‡õy5¡;ãê—Ë9Ø:&bN³Žëe[KRG|ê÷ˆƒº„ýyßéÜ15.˜ÉW“Lo…ßNHÌŠÞ½HJ•Jýr±õÂ[/‹×ÌøÛà÷I-„åç'ëþA—sÉÛ”ìV²&2‡še µ­ÄõCŒ¶W/¸0ÌK\»i8á'ÄÁãê™6‘{Gþ>ÇF/Ï0yÝs©!PJ[<´(=צ¥ÈÎð×aýø oÙ_iNG®"„ý˜ÖÀŒÎT–qd~B‰Á×J"õw Gä&—¾«wÙf…ïè[+[äm5›`‚“0Tâ•%ˆ@ó×*ÉÚHâ·‚Kû+nq–'\u0/ßî—ôW¢Û1NêaÉ>Ûa 8|ÓÅ‘$T‚°Ð­G’PDØ! ,t…D±Û$ŽkÕ™ Ý ¡׬䖇£Xé&L䢙 ¿Yá9±}aÄ-¶"©Ñ™¥ÜƦ…Mƒ'=Ï’–‚+Ùü_Äñ ÀÏàˆŸâ‰ŽAdÝ¥ûVÓ1øÊfÓôðoî”…úƒÑ)¢{_Š&C»÷§Å¸`3‚à X§R°|Û…#Ê,ù°Ý$œ*îGåeìcïÆùkb86@Nz Ôý{S =ièqŸ Š% ¦ƒ*Ôù[ßqغ³1Õò6Éáæ@OÊËÈ«;Ns˜TpÙLö7Âãh;‘V ” /`*±HÀF5ä+í’0‡†³jd¥4QÊtê7qðé…\¥z<›0“Vúè×\Øℼmɬ´\ð»ç篜V®¡W_qI¤“ãE\M¡UÝe]ßó9uŒ@¿>*î\qü–Ätò×+l1ü»œI’é1(mHMÃKdKë°ÆÚg‘`û€àOˆ"3Io¤Øm?™Ø·Ò®æc'‡)ðvÅí߬¹Fcݪx%°€5\f¿W ?V ëd•NBd¨À1šŠêr2ÔŠ¹fÙûÓ®¾ÄEzØÞ0Q±8«Íy˜mÏPw–‚Ø¢"¦‰&´B¯´ Î~ˆ [ðóa|¥†¦ g¸›îçZv…¨*Í–k³Kï…¡‰4¢k ñl"š[ðY7@]œ†ÌÖL%§“š¿”Új,^[yWò;™Ü—þ$›Í/.ÍÃFu‘þ},(“\ …þ¹Nûj*Pˆ‰Xô‰0¸OŽn.²]8ÜQúy…Ps ÿ°œèoµ— éw³gÜ®JjqÑmB>÷û}3¼Ò’É&›Eî÷óbÄ=v4ROgQ²xÎÍÎ 1ŒëØ®{f«êØ›õ‡Ã§üŸ3ñZésâ8¢ ª“ô‚0¬¢UÛΔãÔLÃf£!š¶›®7ØjâuÖßà£ÉäøÝªS =A•É¿29rúL‘.ÝÎXkhÜêÄËp¡x®pP«F cªæTîÖ‡÷Ê MçŠyÿ‰h,ùN²ë¤}y¥rxà…<2×\z0þœßË한 |妧¿¥½¢CÇWÛ+;˜å,; ìŒìêTIÍdäQ£œ„Aâ 5äþaD“õíÌÙ°&7h§4¡òM“ mcÚ Åõ¼)M®Bñ×!k eM>gÄŒƒrgZé1žR’å…s2–’ߤll2sé=ôY¸$×ìúP.¤”ò?˜ Ž[®»&Y£N+¦ÁˆYò©ï ï®e{ƒHãtJWÐ?þ9“bèI‰ ¹R!EnúÒP®Ò_ å¿ òÇBò oT•¼Ä `jŽ—ðš"§€éÔ=§” X>¤â1Ãy%ˆÐQ·f:!AñY³êB—vÔÊr ý Þ›vbdZü|F§ûƒ("ŒÄq¿Ÿ#0û¯2™™3§fm8*åCOÏI@U8*ºWi⿇•±7–ç¦`[ò€…!²<¬ÖZÞº,ÍŒÈDFÙt÷(¢xÖÕÑL€¾« ÎCh_xŒ×¸ð`€DÃ+´Ã'ù¾•ÙíYw Í7îoËD…|»24Ûœ2,žÖ¨_™ð°„g‡ûdŒªORp½F£ !3hjtHƒMÀ9Ó¬‚7‘ƒ2,9RL¿Î+›v¢¤ò¸ßçÃ_Û”ëÜ5íræNØ/Ί+ CÇu˜Š~¯sý_ÁuÃ……6zb·I4 $jÁº$‚Bw- 1îÅeÁ©¢Hû»‡'•Qó›Ï’€,b6ëk†vj¦³HAs GeìšÙ´ºUñWà3 ¬“Ú%±³%™¡Ì]Ï"…©”¡˜éí|ÑqØJÛå,’V “\væ\Ç_±ËÔ¬ˆé3n«Dq¦Â^È",Ò𩨅ìùªÆ3öŒ\Ú* £æ›YRŽšö³@752• tÅñ·ÉÔ¸Wj-wÙpaC8Ge­[UA½Kž"‹5¦ð.ÐbÙ‘ò£’s‰Œ”y-ÈCgU–3ö_ø‚„k-¢²][¶˜~+‹P²«”›«úáLøkmê%E[¢µ°âz^>›Å½þ:îõña„Èó%‰®Vòu5~u–Þâ{ÃFllyÜŸL÷LƃçH28zeà…SÚŠÉp4©©Ü}ÑÜô7'KJ|ï\Jª?´žÓ){oó.‡ÅÆô«•uƃ_t‡ÿ낾”;11WôÉ–·dÔÍkdÅ–3|šqÀnpgͲï[;V-‰QMʼiøœ!MŽ_O%ýwúxï²Ôjä,o;.9V”Æ” pœ×ìk ß¡íå,¢`oÆpý}жÉYäÀ"ä Il‡žS]ªL-¦«rÙÉ(åñLäVÝt­ $ž‹7æfáã{"§[^ÓÁ;È‘¦±œEdЫS—.ÁcY„ºHÕw=z€AÈ ~ˆ€Œ4¥ Bü­”â+†g–mÏÄžMî™éÀž¯}°om-‡?:-œïñ@„³CßE¹|É ÿ–%Hݤåyd f祈¤–Ý'eÒæ+¯?ó£U«Q©Ï(^DC.)ÊKN—9‘@àÁD°‡Ë‰Âûá÷ëì•vñ÷@—¿‹n‡.*cKl_È#©¶œ¨ù<¢,/xDR«»C—2ÝÌ#vñ<Ï©Xt*ˆÝ¶Šp39eów¥ Bðêý¨Z0t@nêv¥eÒëý_ÏpXÔ!N‘þ=)ˆŠ¸r ß@­F=ÎN4•¤ žÿ%‘®aÍÝàs=ž ]r+€½uú3¢š/lªÎ&S¨Æ Óuo@Ha• T;¬ÿ‡¹Xdª‹PxÐûò ¨5Ö æDðä€ þw- @/ãð!Úg$‘¦]=+‰Š~XsV­F'¤þ­«Ø)7^iyÅjL“HH1€'qÁ}ˆ©ðp /½- ~,*~ÐðÎ'd@>a?¬•u˜æ­™N½ä»ì+ú¿Æuà?ŠC+!Û7RƒèQ€ÈF¼iCŸ<#S×sÏÅÁ‰qy$ud)Œ$¾ùTшýøuTÆàBɺg® û㤆 hcéÖXkÝ7kÄSš¤šx!)É̇#±ÿîšù`ŽÏ®„N—Ù¹à©ôUEUdiÿaÇkf³ â|„Íd—‚¯ÐñwƒåB"Ï#!pË{K€¾j^÷„Š~TBÃxT­„½HIqA! ©ß‹u6ˆA‚¸ãÛ¨õT±íP18 "¸Ù‡šÂÞÀ¶µ8dX„LHŒÃ4ޱsûSô¹‡N9_Â+¦l{4ð²½3rè8¡°Þ.àéÉ ~žÐ#À*Œ’þ7¯$ ËYh@š‡Ü²ÕÄÔ<¸ÔKà Â’Y÷çÆ)Ðz9Â5ì¡u’)>XiÓšf*RVÚ´ð™Ôi–G\j³ÀÍ ó“˜Žäí):¿9œŒÇf•á+S0è¹EFè¢J}5lK|kÖ£¬îh„ì¬àÙ”dÆ+¥âáóDŒ:‘†Z¥±|÷’O€^ëôÁš­?ÊòÈ ït¬ ¿?ŸšËÊøb&u³¤;–ÍRN•gdüjÍÈDe|)-ó:É3íÖòЩ¡žîh‡õ8í´*ØÕø …N[]c#Õ—¾Tû|º”¸ðTÝqDƒ#Rõ]°òÇ{„í>=zêôPŠâºK‡Ã+E}8Ri+/§ÄßM‡ÇÎ,gÓ¶Wzh}à3AoØ}zäÌùáKÙeÿËúÙ‡ð©°v‚ _P„}!]ÑM…Ô…t]\ØÍV*n%ìl$Uy»^-âá+-=âêd,%÷¬uF¿¸›VÝ?Ä9ž&Iz"ÿÆ©ù‘WžH×Bá¶¡¸{˜t¨Oî"%rØÃ£Ùúì+ŽS/Ó‹X‹üÃ;>ÅÑÝxæyBŸï¨Ô±±³?21JÅ™µ«šoN.N#/2¥ù üͤáé6¾9%…pÐ*ìž`•z";Ÿhý)3€÷£._/WaâˆRØùÁ¹ôˆ/„Ò¯&3qc¼¸AÃËða‡ —Ò àOõ]LOçœ4œOϦ.K™üÃQ‰c‡2õœÁɨ ºL88ùDk;£çÏõ«DEžO¨°á¶v@%­ê1føŒ~ãK(“·„c*(_çI¥šä¦ãh=žÕ)y¯~'j½q: /tnPÜe,Á&4¾¨›vÑ€kúÔSzé5ÜÀæ´è}™lb¯)’uÓ¨.[ä Ïî܆8½Y©™3-m>Ã3 Ï@l<Åûúúcϲc£³iøÔº3½Ïø–LÅx«”r_ HDlƒâ…Õþšƒ{…Ò¼Cìþ‰«¶ÐÓÑ`‘œ¸àfC_1ü¸OŠÃëèÇ8»ù25—gâ¡GÎìb°W_ä~?+FD­òqd×ÿ¦vPϾ#1[~rû,sü+ëO ðþ÷Eml§ý‡›–¹q:A”?"{µ\g¥f‰\*j¦E/ Š×Ç gàB1ø)×Ë®åù¸¤G ÏÀ†™|Cã¡‘š÷¼P”ÆÐõt! ŸùóÉ–8^ÊÎ' MdáóqŽÊ„žvøžbBZiÔ_Søú‰ 8ª$ú¶,¦qwµF»Šz­ÍÝ¡LSJàô­­¤lÇ®cÖ=ß5ëßÎ}N/‹fr¯ˆèRÄú—Ë2è›ÖŽjæ h¶ö‹8v«Žx¡«ÙCYCz üÖ"¹šM8š]w,qípÊŒ0žêDðû,‹ŸfŸ»«æºS³*›EI8¿èŒ=ÊÌÖL¸vˆ-Å Âú(ü¢óé¬x}xLÚL#ÉkŽ»êzš\ÖýñÇi¤Ý5«03¿ ¾)Â*·øŠ>ðR×$\Fƒ ·Xˆ®>AÄ1”຾R°] ~`^¿ìšIA_dQÝ /‹S`æOnç 'Ê´p´óà„:ÞI1V¬é '›þý“TkàµOXúÇ»;–ÍûÄÝÜ´ïPÈb÷ôIcè"\œ]ÆÜò¬Ó/ 9È;DYpîY¨­F1ô´OŒa_ÇaíGMz`&~<.AÑ+Ñ«õû±¤oÃ.Cð宂;ÞgeQÏØÕ$×nˆâáú«J³eÔÀ–ïxìÙµÕU„ðŠÑ€}R$>°—Áþ¤E¥ Ê”„§ÿXô¦øô_­d¿¦f¿ÆNf‰£Ñ'†;¾—Ù€œÓ’v[OÚm=i¯èI{…-lˆaÁU¼‰˜d9·5äÜÖ󊆜WجKŒ û($gEû¥èøÒƒ‰X¢ŒÎÌŸ²½Á>½ïï»èÿzZ[a·òÒ<'ã eJz8‰…eO†Çú«­úŠéú.¸ˆ+ñå͆Y”ÆcvTŽø_Ô³^‡‡œl臹ÂÐСr8´ÏVÍpÁˆ üf9Eah2ÏW¢µ±žÖ^#óm¬ž\ÿ¿6–z¢KÀV-º«¿–®'½Y[4ªVËÓ”îÃ5¥»é¤»©¤¯¤ËûJº¼¯¤Ëû —÷~Ì´Ü—5[ Áê˽Bîmvœ'©Y¹Æùy1vH§¬fÝhx'ÂVS±‹­¹K-žˆ@-oÎhµx0ž= ¾e¸v<öRã"fÌ•ÖÚÃáݧ"(Xéüi{óþ¨m®oüsÝ¥lI[ ¥´e)KX2Kè6Ù`ÚÒL  ÷ý<ó8c'ñÍŒ=—å!™ë=ýÞãOçh±l˶äIÿ€Œ¥ï9’e-GÒY0ãËå•Å÷¯¿Ídó³K-)lñ"`*¥v1Ãw73‰ûiõzÞž^9à˜Ÿnà«÷EYRYíQÁgèò-'z´lìøKD|Ô@œ±Q½Süq=~;ï}>ƒ£ÿóCµ(ì‘Ù-P(6¦T#¸¨Œ(†¾›8‹7ÓšNÐéyØZ뢛€A} ÂÀeÚBéx?ºkž1â‰éÕ<2ùùe ês/£üÖ$£   úÖH=Ý*…Âˊ˵ }õsKïÖÖV–¶ZïÞv–Þ4ß¾^ùµ”.9 ó‘f¯·Á|äË·A­øjzæœ4QðSü¼²¨@¶ôŸÆ % FĨSï¥É¾¿çh7…AE]kÞnÜ0£8¡­>]ãgùKL_‰± Gq¬ÿUš!?©: ŽÆYxŰÁË +oùn™Ðå®CJ<î8ުßó\•ÑKƒòóT¸%aÆáÅ”©Û)ÑWÐÍ[{Øízžë¹?×dÀªs§|fñ‚=vBòc)Ž®®ð^·M@͸ê›1á<·éS³sËKfBg `&¯BÄ«”·^âaõ­ ;#›J%?O=é̳— ðå& T.å[ï›qhý!O 7q¯$o¥¹ Q’˜º;ÑóÒ¦b¨n ÂÍ0oDaÒ‰9ÕGš¾[Là <ùãÙlî_M)WÃè}KzƒE,:(*¦W®è“ƒéÉÖûäÜõNyáw£— ä]Ibl»% ÕÇ+²ÔnÃɳү€ò©–®~ˆ©wpÜê¹ÌÒ\uãÀE-îïENÔÝMª±õVÓû´3„ì/ªÑøŽ¹J?©&$…©=ðºþ®ßõcŒ#]ýjª•Üi;ýjMŒž6%ýL1}æùŽ€L™`Ù¸µÌó9D²Qüz¨ÏïëõÑ_aÕ)™ÓYj¶¤TûM=œN‰ïóŸJ¼Wf#Í6² «6Ä<_¨ñ*õ<צwBÅÈè¥ ãÔû Z»Gˆƒ˜tµëæÝéãÎ$Ç¢0D¡´JåQúY„>`5žì~ `.AÝ­Ä£ž8L.ª‹ ~ üþÿþÕyñlÎ{üx÷Ùã§óóž÷¼ûtçÉNwîÙãGO_<Ÿì<õž8óϼ¹/¼—s¹Ó¹ó ¬5GÏŸw;»´ˆ} -ÙsF6–±×øgØîýCµÅûqvÆÜ 6Ûká?Y„’ë#O)o%},NEv×—œÈ•àð€‡Û%y‰n]jii¤žæ @!þé `ÒL¢È ;:#*’¥ú²âèl-k!Y  jÀ»´!þ±žï›9Å„RšIåö"à÷ à•E@Þ™ÛãÁB£qp@ÅH7Üñèøí7æ=z†AèjÚü§m í# ö¸x`H€Êr&ïJ¼Ô7—3mA¯˜‡úsè ½Fêé±)•õXù_ÐNd\–Ðˉöè®îb‹­Í|åçq‹j±BÙú䀞Ùñh÷i¤L^Õ#òŸØÑ"Íc;ºÙk˜Rød¥?ˆG/Lñò”•íMÈ„È^ôƒ)(l©æ¿XP å÷yípÔH~ÞÐæ3­ûug Ü”Ah?ÎÎðõ…±<¡¸W˜OŠJêB —¬3Zˆì{ô…ž€X ù-H„t1ɳ5“¢:dw‚ŵÍ! ‰Èmá^5„0eMë¸â¼¦€|C*tVƒ¸tHQ£Ì#ÄDŸ+vž?tωðy¶ˆ·~+ÿ¨àËBT¹vRåV ôß,òöÀ^î¿È¡{Û‹´›2Þ.n,ÒJô+õ¼’=t¬øoV€@¾¹¯\,(.žÖA§0óü¢Ðþ<ã‘(ã.˜L¥LT¿üúŸ:Ï.ð w¼Iád¨‘Oš­ †}õðçN\DG˜1Ä5ã{Hey`eç”e`è¬ ùÐÉüa?0D£ÔsJÑ^„Î7½]*ÉÝJDeð¤º4&›÷pÚ·úAå7+ßý¤'Ó~K7fT\§£õ?pل錚˃Rõ˜†PbéËÁÙçr4îLÞz{އm…§{‰ë)1³'¸f·Ýså|\¯ëS1¨íÁ†:fj)¶$„m¨ËH˜Ÿñ=S åx¯ØwQ¦ž¦P®~`ÌU@¹¶E tÑGÆXîº Ήˆ¸$õõì‰ò‘( >9ŽÃ%:ìcñ²!w/]BèÂ…YweQ–ùèY ¸«Ú6;{vpR9Løx„‘(K°%!첯š$;êÅ5a Ê|tÕ,%Îþ[t¹^÷ £«VÓÊ9.àÓ›,à ÏÝ‹›Œ5Y€Au/&lŒ©EXRTMã(±Å„Ù(±\t+‚j8Ùy Ó#Õ¦Þª¢’š­R€dñÑMõFÏé¢íLC—x–÷´G§·ù$¼)|±ÏX ÃO}'úÔ(Îú­;ú-áå™§™ÛÔ<™¦ô‡ÕDŠ•Ô—/æž<›{PM“\£ß3siËÊ¥ (Ûê«* öDĨRpÙeX„šq¢ä“j¨Ë¢Á7‡qÈ®ýçªi¼ M2kP#æŠ#{›ô›D a¦y»têØ¿_”êXR¤Z¡ÁrmûÆÈf|×Ûìõî™›ñ¬q à¨ÿµž1„[ƒÐ>’þ—jz厕iX2$Ÿ5ù²‰öÈ}S¸F'Eƒåz$÷LL™ä¥Á ¿’°¤$µ)•›†Wv”©[gõh'Õ%å¹=Ü,ØÑ©79sF#%åäiÞ´S¥¨FójâšÌ bôË¥Š0˜$ü^o+òAÙú…ùHäÙ !ù™Ý~º€úr‘Àq¥Xàxi=ÛÊ_jSbO|eÞ8¨/­µ^6§eнšð`äk&L÷­€ä¥9¹hƒM¶"Zt 1϶0ù'sBð®ÙÒíý³9q2¿P»±,:ò c#9«÷»ž‚Úú¿[ÏL€ie,سúÌåŸíI»Ì ¹±§ÞQöÍäÞny«~Ääï_í98»`pá0ú—öô05ƒÑ«z”Xó…z´Péö¤T §3C2aŒ€Sæ_ê‘nDÞg?’Ufãó™=!xÀY¶'KÙÚàž~c &2Sõ'0F­ˆôôkÚ1(E€£š¹çR!Å;Äó}´›G±Œnà(c*°Œ¾èûÁo<˜•~†ÉO h¥ÓÄÏ«‰Á¾2òw†±·rG«Ã3k:|ÿÛÕdðŸt¡°þ÷ú»AiºÎ" çRnc•c‡7…÷xÍÀï;‰Rt)]>oÍ·~±¦JEeù¾…!=çŸÙ¿œLVqƒ…*¶Ÿè5»ïôB `äH—s¿‹gm¹”WUÉé3*ç¡¥ø¯½³ëžë;½h´†9Qâê%›ÓŽN„*¥_4ß.ß+†f~(†¢ÙÐéÇ…Dß#OK Âi[øÉ h×K_ü;8|\Mè}vz+‡¸„áå~5EgßÐÍVc]ïÍh°!®'–½€Ðá.k (a#K%<ððªXA´íÄ<ê×Í&´+”K—CwÏcÐN;Én”eþ‘rT¾†½-_¸tk”e.pé)q»sd¼h|;N¬ w:Öׯ¯KFóÜ#cFXÄíšÌØ)¢+âvÉ…Öåu}.àiÙƒ@%{GćÖgº%Ü•2}—7ãñM|0 #2#Ò†;²ÉކÑxßãÁ7LøŒÙB”Ï‘|3…lWë3ŠÙ3›V÷ŽŽœ”×g%”ÂDúøœðæ‘Ù6Çhvº®Òç1zw3ÆRÇè.s‡Î“–2Ê&¼³_‰¸SÀÿA±à¹²¸¾:›x drÃ;éâ^ïe³Túd ™ôAÔ`?Eø¶Ç•ŒÕ‡AcmH7^!È>A£,Súkí¤P7n¤ž'wÈKé­'ÓÝʧÍRdÑ7Š‘âzâ‡b^^/'ze-ÕÞ­Q¾ Ó1Ÿ Lö}’ñ~•âM{ã/¶Õa‰›`¢ÅcC×%çÂy<xm> ÝÐñ"„Ÿ1¹ÀÁ„-¡q¬([ó yÖo“h/+\^ÛrSF'½iÝ]I†Ããp@«bÔObºo~[›¨Ùkûšiù´ëÖŠi½ky®Û×­„ÛÇñj¨œ<äXoÕ­hÓfÝúâVnR_ÙWKÒþTc&Ä?CLj 7<äÅ4<ˆ²ž> *sΰÁzh -Ÿ%ûÕNõcëySkIÕ‚iÃÝ*b”z*úúsEåÍ-$>Ë×ì‰ÿ=¤p×÷ЀT¬Jäh™BÇ’Q+óÆž>V}%ÈÕúhÑ7Zµg¤Y²ÉµØ¬{íQYfËö¼@á„xC7”f ¿pÇ^«µêÓt?Ã9°+ûOO¦ æšöŒX°cI $éû½„?ÀÙþ`)t=© QüÏfK»žqaùÝz³õ¶ó¾Ýy·ÙYj¾m.7ç+XˆËÁê}òÏs%|æŠÏ]l-5!¿QA•M¨*Í‹<Õ8Z·©'Õvš©`‘X "óæ 9¤ÎÚ†T¿~þcš4š†Ê ¬ƒ( ö–š¬©ËÒP´R­¡Z¹qûåhLßé}»Î;¥©òf3šaTd51oL©šM$·8ï`h ’õÃíãÔ`ûYÐU HË(ÜËײǼY`<¡\Ú½2ü@zü&0…ÐÄzâ&ìÇ2q¸&½«)ŽÉ˜6õv9d)=›K¯{áŽÓ# ]⺃]°ÛÇ7!A3£ÂLº×銀M›P9ò¢·õ¹1 !p–IJ@ïúì×Móڬϋþ/ØöúNû]ÜcÖ¸œå…¼ÊÂ=g×0—rf…Γ=93VšéL¹pcò|)4ñÒ†i­¦ë‚*ÁTß' «·ý½à~)ôããR¬nQ²¤ ÓÜ)2„;R>Â*i3K“5M~×Ó´6ÊA*ZÖO&T]]Ò 2EÖ'&U-“ꆭ©¡¡å¼2¡a•̽`mÚʯÈißPóí{†_QK•·bÎPÅaH§æk—ÄxÕžˆ–ô¼b„-ùO éÔÿ7é/Tîò^GápÐ(HçÇD,Þp<õ®€ï« _:ŸO’èºþÙwYôp«Ú ×,­iK®8¹`É«¶¤?‹Ô{ü:bÝÂv¥Ý)"Ï<ßSAvàr—+-džï”@»Ÿ&•8n$]ˆÏËÃÄóP6ÂÙLY xÇ/ô+ï#ÉZ})$Ù€'%å&ßY¨êB±Ó¨ÁÛ–½;PiÇNÄTJQU²­apJFôÜÈ z#¥°yº•ÀeTMCªâ%áé&Ú…GÃ0ñ½YÂAÌ(ó¥ èãò>ÍDErU¡Úp"ðôÖkˆ3ºLmg—ZÒ™ñ›~¼S€ÊÎùF8P›ª9µçfö¢ê§g뻨ܤü°¨Ÿ{o¡ 똞IÏì¤x£ÛtHµËÃ|Óu’DÔo®z¼Œ^µ@>þ‚xÝ™2|êéAr—_IG<Ú£9˜° âÅu.QnT—qlä9™— y.pSÝ4Yª9ó²}§c*N’ípW5…È_êÊ¡îë˜is#Ÿô œ =!_âVSŽVÐL»„‰"Þéé‹~£ØÆÀu7™mlžiIÞV-†µ|¦³p~W¨™‰p¶ÚÔÇ•düpi$< >¬¤Pcì>7ᯉ²;g@Ç­ "°€ vÃWÆ$x¿€÷õ[üê¹1-9ž[Ýžby5¯ÆAö!À'~y$UŸ|¯‚*{s6€¦[‹Qx@ÀI'ž•ÝV5%ÓY8qp²™Xúñ¡64Ì3ãÁГßY_'¯¯ÁuŽ0RJ?Þ-'NQ*€‰ïQ3 ÑÿEn•C¹Éø#T3®ÀIg!Àýí¿Ÿ¸¡ó=#Bœë'2߯„Lñ%RQ3é>âž Îèe¥‘Š&æKÜí*¯7Êa;C2zZQ‚ª£3TŸ7%â^cU£ŠŠ›c‚¢ß"­ÚC3 ÔSº¨Í™Ë”B"áá!˵H~JKÒÍ6nYüµFêéŠZéÓpËÁ¨ø&÷¶*ÚÑGpu‚fÃAÄwz8?Z™äðˆåûb(dß(儾үê!>YïqEÅÑSêUUS´ÞáÉ'xVMІHjtŠRÉN¡ÉÙÀ‹O¿ß\ãš×ß&ŠÙo ÍjÅËšt¤ü/¿¿«Gð˜*,Ö î:'Õ°O ¨Ò3F#ß뉄˜/{mBv4 ¸^O~žK¢¼òCa©Ò™ÍP}ݾH>)\ ݯ XÝZ‘93…ØlÂש»Ü!ñøÿw¹dW¹Ö½“ËÕ_Ù_Ëá2jߨ.ÍÛ0F öçWåp¿ÅÏóÛ^<ÞÂL8ºfKés)/+Ü-£@?™<›„¥Ã¾‹üa𤛲 úº®GZ=rYŒNÒ­!NXßh0’gt9ÉÉ&E´xᆰCžæ²ã,Fô &ö=ºÒ,±Š_×A˜¦$Gü CàQË×VDŒ¨eï#ª¸ºY¼ºYöî›0ä5»¦ÃŠ(Up—¥}µ}‡¬{±Cßй©oãåQàôý.JhR¡7 Ï{eøÈ£cÙÐ;ePx°ñûÃÝ-Ã9 Õð)ý;£Øk*àÒÒŲIq7*j¹éí~¯ƒ$?ï¦Îœ6ù/Í ÚƒR`æY µãÜð€{©H=}W„êŠûQ¶²ÓQë÷½å–P¬HëAòwG4ÿý·Äù‰ÿÃ&ù¤™t$“ U¦[‹~ÜwË‘s·$© A«OÛ 8²J­)ާ]ëâzóïÎbkk½¹ÑYn­¯¼m·Þ½PL¥œS'ÍnèzÝ©VxŠnW‰‹a2´&Ytˆ÷ì©”N[಑‚³^ó ˜Q²ÅÀr›=Ô¦¨÷ÁNuÃ?ôz›áyVM0ˆ þˆ·nЉ‹ÇàzRM¶K×L²¯ÐLqI˜í|îsH=Í”47Ü^'v„†Hý° s‘ˆ~X!Lp,€ìãWH—å )«°5UC3 ס+Ê£J å“líÞ·–ÙÒ²}ú>—'׋bf= £—­u_ç>¡¿®æ’ãP’_ÊeÒÓŸ×séÊô»ìïùñå‚ÿÍh†mìÓI/Ñ—J?ΔbéhpÐÂ’÷:$Øetä“ K1ŽŒñ„)Ô㳪jháªÍ (ðw MDmIø!h1I±JÜMƒwù-u!—QN)É[Ø¡SµpØT‹Ánäìõ¹_ˆf]&±÷û!…5‰­Š©¸È™v>ý¹ØÒ5pãɼ¡Å%÷i]>£ e/VÃ,42Ï÷Š‘Ù˜L?”@á6ìZq>ûT·rg¯ìÈ8ý8S€âý’Ç\H4i‹‘ò~÷Û" ­Ôq¶…ú±"¯BA3íy>Tô¦s  žI}\M— þ š"‰Èýex°/YA"¬s˜Cµñ¾³`Åž§a…n¢ÑŸá‹²€â s¼3À§Bˆ?3⟋"nÐúÂîèYb»K Á¹†6u ((²xî®mÍ«ð£rõ+›âÃ<’(Õ • B†´ûÁç›z¢ÔÓœ^=8ñÑÛȥܯ$IÔü±ô7ë|#ÉúUŽ5ý\÷*‹§ÛY æ¾9”ܮĢ ðŒŒŽŒ[ÕÈp0zP‰r=Òõ× bò¯{ÕÅ{\m¡ºxȪù©÷7UHšÆÀ?U‚¥iС×å¹Â²*uzͪ۠¿²gC™çÄp`aÙʦü¾­Ëϯ··Ê`r±½¬EÑÿº.#µ¾&FõË  Í÷®×(ÌYPî;îÓçR~UÜrC_¤sºB\åî¾ ³îÑã^eVV‹½y#ó¼àõtæE-.ÞÍWw‚gÜè\1SU ó\£ý0º”Eò¿™ã?<93Ë-yЭ¢0™M娔…Ø’˜ô?ÂÆ¤ZŒ5Éè*Þz>3'Uý ^VdªÍõØŸ›ù ˆžºv‡d“ŸmTb2¦£îîæqzñîiá6-<ä>"õtß„øW¦XÕ¡—nÒ&›œ”òq;„y/©™eb6áv)Úé ö!ïWÁ;i.†u4¨ª@‘ª"»ð»ºf Æ·iŰÿ…‚ˆÞU‰#«Ô®O7ÛÑšOÿä,X˰\(Æ@uû ­ƒ¢¾iˆæç‘Åh"o!öÌ¡•-{ÚWâ² Úù® Ë¿¹Æv÷×ò†1ݹ²KV/^&F¨ÜÂQÚÐ ád+’xÑ‹a 2•¸fÀ.âoè)ÕÔ‘ÅC.º ¥Û±e¿åÀŸˆiÒîVìÐÝìßB×¢HÌ€Û¦·å±z ðSv?…C9DŒ°âX½‹QϘQ¦)Ô ¶$ޤÏ8c,av¡ìû¿i/b§…‚Ït¢Ïq¸ùzñ¤È(†RTÒÄ+y„øñM>kŸmd rhÝ®åsˆ+f‘å=‡FrౘØå¸Suµú0]ÿqþåãLÇÁ·Ì‡%zÌ'¾³â Ma0 XÇu¨X°¡ø’»6.?8£qfÏK™­K¢FæùvbÁ›åÐÈÜœÁ² ·J°IÌÂùTqpÂTD¨»é©Ò‘… ‘„Ð!u˜­ð|R„ׇ8´¤à.ØË(r1íøÁlñ[ç‚nÞ-k~µ”µ¦.–àÃr|Ƭ½Q>(rû1ízݲA’„yyøÿz³vEÛ {îÓr}pÈÙÒ&ÍTö…µ!ŸŸTMHÔ¹š‚ˆÐÊ:R6øó3Cp&Îó ƒjiÏ•–§%ùÅ ¬’ÐÊ/JK,!\1.·,Rò¯Å—Ñ?0¨… O|»´0 »S>:$nªçÁ68K Õ¹kHEÊ;`&rÙ(ÒÆ(}lK0WÖç Â"¯ÌObk’QD¹Â¿WÂ&7u:sûÿ“A ˆ’ÁH¹ˆó2¹ÜîªÖøÛ(HW®…ÚÙØx"ÂéWëïÞ·W:½YYYë´ß­¯Ð_›+Ë(s)×ËÐxù$=¢@Ã0-¼Fòó˜3ŒÃo5¡>øF5K@3nn`²îÃFY&Ü*¿×g4 Ò¬–²Ê&(M´éŽwÉ“üþVÀæ›WËÚàâô¢-û×?Ð%Î;(kâ÷_´„ªÝ×k;’l86é¹Þá ºiÇ{|Á°O~ðÖ©$kZƒ¿-²à€ª`5S¯a9¬Ö/ìX¸ž ^®WvÂJSÉ.M]sHÌ0ÀhJ.tè¿Û®4yåг޻±Ù ×P÷òg˯ìºx†ÎŸ³£f†*ƒš­‚AM—À¯wTž¸1~1¿€i¸%–¿RÖ›*M#õPˆ"ûágæ‚Õ;9¶Âós'=ž+ªqÝÚ=s(ßO@WЭ¼+ö“ü(]O± Nà‰£ô*?¢ÖÃT«=PMGÔ†h~ûV¦]-ÆLqûfCÂÏô$]·œfTÚG”¥eÝ94× ñ àÏÅÂÕeî²¾©øñ3À¿ÆÆbbås•É\¬ø 4+ƒMœì…EI)ÂÕƒ¹"ï‹?Ž(ôfÉà˜âæ‚ÕFMóù›DŸ_´ˆÑÜL%­Ø>5@òI¤¸|âÓŸÕ|Ã/ŽÄ€˜pKןh1Jå¶z‚ÓÃ’—éFgÿ¤xÉY“œXÎתâ+£)ˆx»œš¡A€6›¾Ä…’‡޶ÿbÏ Ð˜vÍ[¢Ã uê^˜4¶Ù»]Ìö\Öó„àJÕ”JL[aBõÔ‚J‘†_K-®¢sÐ7z‹gVšyA#䜒¢Í/&­UÈ{nÊUÝ…=7a¶З{;Ô¼/žöÄ·zFbáh˜kÖ“D%«»+íÝž+lÎ+ÑLu |2| &’}¹®Tƒañ0® šO¾I(ª—âϾw TK¼þ¦³mÆÛoõ4ó‰6u¸ó³ ¦ó¥"w4TI-Œ­S”‹ÕíîùMµ,ª› ÷#¬³ª„ FÄ'o”'}bJªì‚LdeÕøÃÙ½ µÄ¼÷ÓìNí¥ÉÌR8ú &6$L™ç™r4Ë£Ü'åÈDô…îblbÀþÂÄkHÏýÞ²ø¶_gP0›?~†Êú\»Ÿßu³>!‚öÀß; ºÕÇŸ§™Û—wAý–‘ìqod¶¨ÈsýAŒVÙeðÔÓí ð00z=ZWlÙ »e]® éüE³«Ú?ò¸~¬IÑŠ¾ ‰p»3ÂJÏÒD΀×þ›”Â×½Ã?%¿Ö†}?€Ã#îð+›ÐJ9c±µ^ÊRY Üù&Kl-£ÁÑp7¦YŠ;No Z¿ÛÝEœŽ9vÛG[»í¤v¿ÕcÂK©É –òkÍxüeëÑsÇ4˜¶:‹f¯Ç’ÉRí7‹GP•„Íz]6ì{+|Onïêq›z~3%üÒ«âþŒy"äHÞ·¤¤ªD‡Yˆ±Èsß/‚ý;A#Å×c³a¶‘¿YóY÷µ"Í1Ô®‚s8f$V…ŸÍ8¨­¨”ÿK]jVøscrÚrJ±/ìé¬ të(èXÏŒ ÕßMÔ±%Ûfd Æd  ¼á«Z¤¶/©Òþ]lÛ°Ç’4ÙFÈ\SfÈE€ {FÐÎKf”¥¹óÉmzb;³‰Ñ,ؽº6õ~Uß#„N¶ÂÊ¢‹7÷ÓlK#­z2V™\iqËÒ–ƒ3Ï÷ËÑ}çp-¥am„¥ŸçD†ka°WEãæü%–ëJ–`yéÒLËNrÅx{?Œ£G+ħK¢N[ÒÙu¹`؇»Äv<³[ñ&Ùp¡Ò€;6½]µE”[Ën(ɸ_ C2’ôÁTuÊúP«¬–ËY–A7µ^ !±;‰6½=?+à¯58¬®¤·(„NCa<[‹Ž¾ñi4âhÓanÕj’ȶ¹B®ÂiH(BjØ’ØÍY@"e¯ZtvÝèÿ{–JG|6tt;÷©FŸIè,?:lIìæP˜vÿ¢{UË9T’ÙIÎ`à.<[ˆ¬¨:Acèĉ|ülM‹sD3FUM+êU?"œÅ†9¸­·+VVµüŸêQ¿Û…Z<·&f'l/¬éx  ©Ô¾Ú¾xvq:oM v-%?{c»ª&{’Ÿm *¾t¹Ù·‡ÝzÞšžÙ¬|±<«ynE–¼¢ÝØÃ¸•›p±þÛÍi© ¼éw÷!œŒî„“Çea¹N8;Š_ÐnJˆ:dvë.ZÀ)®å²”Ðqf6{¥Eë’rU Ó­B8Ä]J•²Çc`wÒãï4mÃq…3ùÚ´´Ü_,h5Þ4Æ!·ë]Tna1é,{WBg·5 ¥yá19ØsQ½(ÜJ ˜sVs&–ûÒŠ„?â=g5±£ôlG‚Ê£62l4 º~.\õãëZ:õáe±ò];Ü¥ë;mT®{—}.6yÄëÔ(<5’ŸOðÜÈ]„jû#¥M£êÙ¾ŽÂá Qž½gá ¶E?Û‘ñªçñ>ÑñËñžuÈïãUŽpÁÞó¨Xem15¬òIsJ ËÖýÁ:J&izè^„+#ú¼lßêœË+Î…¶ô}³â\og¸gˆõànÙ»ëÄNïžÖvCCèW4Pþ÷ûtüQž)]×f«é²AS®h3°õôYØXú,l›o´YÐúxó)¦ZÂ;bÊ::•£z »SŒJ==-ÆQicß!"SìK?qöD\¯¢€ÈŽi¼´?×J8^zš/8%•—F8¹ÚÌšAæÍáJÍžWS¹¡¦uKz„(åmxp·ÅBîÝ,iPÂ}=¨®êãÇÍU˜±fŠÁN;Ý}±’_k¶À’ÓëÁíðÃjú!„:XŒ|wÏûF×ïþzCü~¹8<àúUUð.M“vœ…BYP<³”" u–»„LqE:Ûj9B·&/>Hõ¤‰¥\ª,a¾¯'"CGfI¼XFO¦¬‡}Ï lY•:™‰âC£÷ŽÓ^¡™£X–Ñ/v‚Sa©ÑMç~Æ:íÝÂtd*…|fö±Å̹=5"£ ¦Y”õýðY–¥ý\Ù4]p:ø.zàö9›„Õ׬; ]v-*òa%üÙˆTØH­†iêÇfïªxâ®î¬?5wƒÎß 2o0æÐš•eò¢æÍ*‡9+«xi0¥j÷÷Ü'$«~à“}¦hJCW¹]H”zº—zóº§^p‚· ¿–üLË2Ûg¶ŸR~?ÐBü ._G ìA8l©‹[S(a¡âóСïŠ8òúL©$Ÿ‰¡¡x¨TÏ&š‡•`)ÐJ´ëݰÀWWurðL%<¬À¶rÖ‰g÷Œàh­W]a’´ÝÓꯉîQU]ש¡Ùnh© l·´lðö»EÁ¤‘êKnª/‘~½#ýÀ:ð{=>uê?Å åâO1o×B¹ê0Ç­ ˜Sì} ¢‹$ܧ/áïøà«›E0ÀÔù—! -óügköÐUó&ýïA%‘ÈC™‰Iýx"Ó°6{¥4‰zb­’¤„ü.K…L~Ð1P~·KNΤKpvTÖi'Ù²Ì T:uýxɉ\©Xž ~“G$»™7_M¤Iûµš*éªF;–qeSAÁº<5pN}Bú•ÿëÉ3Ú.}b»Q]ÃB5„šøS¥„mO³™yi ¬«oW‡LŸ©„,y3{"³÷ÒÅ‚ªCFŒ>6'cí/Ë«GÈ}–W!¥‘%Ùh¢?i  Ñ £?UP˜}¥ƒ( öØM¾ÍWÊ‘™õ>$K½”=-é'›©.k ô†XµúņPxˆ€¨Ólؤ"ƼŽ£V‚85RO7‹q2€Q%†”bd¸¡JL9\ +ø0 ¿.ÀdÝBcª°ælk+ {[þ€ï¥æR.)ÓyÙ + ù¤GÜeÛû‹ÁoN@ÛâKìÊ ÉXNÎYf5EÖͧ†ÂKnùM¡|CW' Ë^Ï ùÒ œuÇYfÛæœ;Îr´oÒ†;²Úhƒ¿Æ-’€Mj-Õ:A“ŒCP :fILöݳÄs}´2¼*Ò'6³T‰3Ìš3„ã˜cÛƒ*’”ã¨y÷9ãq¬„¸ÕïƒoúØëLÉ §*d¿Z4\wßë~jí²Ù…Ïš6 Þ7ñ ªX-î©Muñ\‘^Ôêt»ª3Ø3 þnQoÐR‡Îôc[’À‡¦Ù,HÐãSÕœÁ›•eTÍ.˜f„#ž³`ùÆ+⨖Ê9–o®¾² Uե왰ç*ÃÙtQ6¯{áŽÓcÞNðmѦÛól˜`ZàGCͺ,¤ã% x ¯©Åbm²MëÞß÷¢N ÿ×àÀC–ƒMÏÈ^´lê¯v©NÖIà «)X9&|Vä”n•QNÓLÉà>}ÞÌ#©¾ÀÓ—Ññ^âÿM†8¾ß2Ï÷K âˆThhÝ)Á±xæÃø‚æ¸÷qy9â|uÏ‘–ÀÓÇB)…tÄÊŠL•EÆ‘ÓÅÈuó`¼WÃð=[ÜÁì#*v*ßbN Ï-{Tžôw<Øçb\³Ç,x³òܲ ^ý¥ÎFÙ|HÊï»"Ìy]fÑËf1u"ѹæJé{DÈúÃ=· Q!gv{ÎÞžpÊL±ñÐP¼¯-ÄC´[~aÄX£Y0SÕhðŒ·ù3Ƶ¹_Št=[Þ">I)™{ˤ¶äyªIHØÕe¡W¸IM,¾[[î´¶šk­¥Ç¥:Éwz$Ͼ¦É¥“€³Fìtýd‡—zUƒD/ÃË:a¸Ð5¤Ð¾vä/%fØR»öÕФ=*§àÞ x_ÉÄ{4 HGÚÔì&¬ ‘1?Ž(«äÀëú»~—‡,®h2”: •et(ͧæÄ¾ ÛYÑíú¸tLgšƒ§Ú´ z^\ÙÅS*Œ%·Ë „)ÃíªÀ`Ïm>`ŒÓ‚î–Ó%‘71/€­Õé«ätfÃü­0aq}¹‘+.<EŽÙŸV\ø$Ó Üw|3Ó•ã¼GˆïÎÂh[|3ü¢üŠ® X€¹Í8Žž™ÆdH”©Ñà7!ÓGzmæ<3¡ÎÏþuÈÒ‘‘‹É”•À ŸŽŒ\ŒO­ –üL§’B†Ï5W -ÐõDî„mí†øÙ¿n!’#¸/qË~¿(ÄÒf+çaVõ·?йcú'UhqODKXá:»ÏŠhRi¤·‘ŽŽnJ– ?ñÄ %(%öFé[©G ³U`?Ty¿2i±ž3ÂC‚Ì»,TÑÒIlI…c΀4Óà÷ªH½úK¹=ñ¦GZ÷ŽTÃÊà`S¦\”¡!K ÈRD¬Ã?*ÁË,ïÎ Ø…ïËñްKw˜Öœ1(¤ˆR{< c”®‡Ÿ}Qí¿V×Xsæ“Nɤ´}‘$®vËÀЭª0$÷*0{tŠâÊÆO  è/» %j›óèÝ (è^"k`»ë•@Úã?q r|V §bÜÉ'¦»¯*ÉD $ꨱŠ~RhgñúÃï~JãþòvÚή·á`hëFúqÞŽ½Ox)­RñÑ,…®'õ)–Ã>]³Ð¥8ë¿M"P¬;ä“F¯ ºFKÝ@ˆs3]â댢^ÊwG²îÍž¿´Gý°×(˼_|¬\Û¡äz(¯¯`.¿Öh(X ³¡<3hE3ÁF¹Ý-¥4Ì€ÙК`rïnˆ¬à™Ö@0DV¼yJóÀ XUË”Æ!’±!³šÆØLè,VgxS}í©·×I.g IùMtY«§îmËÚ2}g[†L?Þþ}cE8E”'/çý˜ŸèÈ_3ygÊ aCùý°™q:ýc9š¹>¹ëÆ;½ÎûMÐÒÙôÓr´êmúÍpw—¶×ÖNï¹(¨©¤+é^˜¶Äm¯™Ré¼9áŸC¦^ˆë7y6~WÕCöC3¢Í׋sÛï?4ÌÐTôèR~ù½!~wyi _ä|¾'žJz¢34:¡DÄ O;Œ þ/ð‘ionl<šµÀ/ÿ¹eþýnÕŽý›­Y+ömyÓÔyÂSvî\Ê\Úxx™ò3á²Ë±;$®ƒ·ÇBãÐŽ¸O'™}LÃøw+$Ö¿j ÷Ý£ª³»+Ž¡ÿþáÉ5[K'+,^ÖɯÊ‘òýL¡„MÌ:(C¼Û]fòB5ˆ¿IÞÛÿ³ $‰iëv²*ÛO >߃o…Ÿ¼Ó3ÍÜü£;UEs…í%»* í‘”È<ÄÕÂ,wš#ö,p[Ç™®³œuÿÐðømZÉ”ßkð)H_®Y%ö]ù{ÿVƒ‰Bgð¦§Ûõ1ä.G¡X¸Zƒ†V÷<<-p6+5ØÀíyšËë\áàý@‚ÕhV™ò(ÝIû~¨S¡ Ë—ULÎvëØ&0Îô’X“6ÛkpMÞàOði÷~6_‰ÍÎOä†÷Jëú{TœWþ©¬}‡ì á5—é“6Ýž³]éõlf_U‚0@@´ŸNDzï7×rÈAHß®Ž<š«}FYײYŸ½Èß-Ëw\(Ôgž½ž×“úbÙ„w椩¥‘[I‚úM8Œ7½çØVN÷=Ç…Û¡LnHê¸.Ž6óËcQ`Ãî ‰gÁNA™Ã™‘Ç6`ì=4§ “ïï+Ã@êñþdC/WÐ(Æ+¤WuˆÃÒþbO«^°$~ü–¨hD' v5IZ2t:®J)ÉƵ^ÿµˆøÝ¦6$Lœ³¦øppÃ:¹t9M¦ÐÇfDû~ÜŒ<§EÊaf)vðY<δÃL :ZÞºQ˜E«‹3môs¢@t{aؤ)¢´ç[Bî@Ì€PLmìàMÓÏÁÃÏÍkŠflHƒ¦#~0¤!*Í#»rš¦Q,â~pÞŒ(ö…¨]`t¶g@%JÅ3q)‹X!I»û­ª.W‰}O[%BÇç§{a÷Ó’Kñªa'‰¼Vr4!þNÏËqü½n ²öÔ(e†-;;j‹Ö 2ŸNPñ_-­ùî²_İG’Gnšñœ=ÑSãÆS\>Û¥¢.TIÇݶ$´Ãé"å°Ûš&劼º(-W‡Œktš,ÊZÝõ‰Í‡ ßv-¢¤b1LÒt©€zåÃuN‚½%vŸ°á°0McPã‰ä³ïðÀ iOúå’Lùÿ§ ‡%Âô‹”÷òºƒ£Ç®®ã10»Š_a(÷; Yòótò3Q؆Qe/RÄô™8t4 ±%:o¥ Íî´å|öĆ(öúé¹¶„”ü7¢ð³Ÿ‹òhJ”ê%D‘×u{+¢]j¸•Ðá6†UÙ†5¨R³„*9²I/LȼC¯;ŒÙ«-2+òmžPþRTÔ˜âø=pzŸø3±®iqÊïÔ5ïœ )€üXˆäÚôûžÏUžT»^X˜ÝÁsIP8­±m&Ý*íÀÕËV¸…Ì!œ¥>ü(›NâŸ=]öØ•Xê黋O°kh÷j*¢óSQænoHö‹2ÑÒûFAfÊ‹ïõ”k÷7>óDþ‚ÌV¡Q‰X Îg¯ Æ¢G Ô8‘[{ïú:Ö´³­E …×ójfÚÔéVû¯UæZ½åHñá‡Û)}°F%‚ ê» KÈÿ[Ð!ç³èÊ Ÿeó(ª*N(X}ßKåD‚qí×”÷Iôë$ºÙ8 þt? 9neËn…m'pwÂC°Íù¿GÜÀØ ûý£`ï“Ô2Ù š¬U\E áÿå'mvc\MÝ¿èâà~^]€6õqq¨wáíá`ñ¨.dE!u7<çÓ²NËAtùxÌ“'GÁäéQ0™_¬ÅÄ'›´ws©U‹…y ²&€«µ8‰ãHP–FI÷W+6ù¤?­èÕ+½‚TÖÊì#!eÎ1¿‚ŽEÏ£´Õ Û|sÒ.MƒO ÂUس ã=Eœ‘˜³È:i®7lö’¬‡¿Y±Ð8ySoÜñilÜ5þ`ì¹ §ßkqr=M¥þ“•;6¯®4óõú¦×„2ŸÕ››Á˘Â䆺ºê—×z3&ëLJIãu%…Ѹ@aµXwYÅÖ“ŸlǸ:ˮ֟*=ï/o뵺Z2<ͦ÷ï¡Gâ•Zì²~›ê}ïo7Œ¼÷lcÇYìôc8àï4VKÉ#,»µ«¡p÷ÃÞìåØnSËRÎgäÚ€Ó|½/M¿Ðáä‡\ÞŽÃE©/¯ê‡#˜àùN¨P9®ÖR¦aúßc1U¶QÞokC×é±íSúÓÿYWðýàãm4\Ç¥9nÖP|×CgwLÿã(X‚Æh!ËvÍÁDÐBžëGÂs+rºŸ(n£ÞK{q£´ñ]­Þïu?užÕc®Úã·šºp«ÜZ5w•lúC]§\GtkÀ*|ÐC Øö‡ì¬ÉYÍFí~!Vw»©R&)MÄ}ƒ§‡-æ«a/öÅ|%D’ºßNqҢѢ­x–?©{]CHÓÉÕë°)ç˜:ux«ïÈjÓîFžœOIùDg³öl+TÉTÞ%oÔf™>–n#Ûµ掣%Ï?Ç©$;2Èpܳ–Z¦¯jufÆä—º½˜‘¿´"WÐífýDÞPæ­Í$ˆÝêÑpûJ»´cîzƒ^8Âõ¼½aÀI­•©ìì»=ÖÆn99¨Px~‹§¬¥Ò È¶ÞìÆ¼^­9$FÆ(f¯Á¦ªå¾9š=TËýk¬ö¶٠ßÅtMKÍ·äM­^RqéeÕ^©“>¹äyäýM—â©,€ùxDÕÔ4eç(+¬á_oë4ˆÀ(ó®çödõ6£a®j8ûˆÚ×0ØJqª×¥<µ)ÓÂz½ÑØŽ)˜x&¦ÿ·¦\(#0㺠ûœfà*A±k‰‹rS«ÖޤŸsfgs~ÒXoy£…ŒÀG(30Ï¥ü¬÷M»$“>øÞóR«IS¼ð GŸŠ φ&í~9E*'œœÏ•cý€ÔÒ˜ÛÈ:$t}®“M/g„AKSt *RYa¢q^jK•å«H”[ÆçåpåpbÙÛ¥=†g«ŽWutÇ«ÚÚpØÝª®"œp>¯,û|Ö#yYõÅbwÄRÐà¼uËŠOy{0A? SÁ‡ÜÃJ%N5¹gðÁ¸½þ}¨QÆXî² l(¹B²”öb\Xjr%kN{&-D“–TDu+¸s?ÄèÇ•~¾‹ìhúàDLY as8kÅl…O{çÖOxòÍOp]Ú§J䂺bòäM B0BjèoWm/>Á1·ªàh¥p ÝSÒ=1ÀV1H2Ø?…; õáN!j@ç«7ž¿· ¿eŸ¿|7ÞN; `ðCD—·ÒÏprÀ³¾/¤Aê…ÙT6`Çm§±a}¿+fævª°zB8•ðIKsû {8kcÇfy7WÉi#¸+l’8ÖëNù‡¨KMGI€1Q(ëóíwkï·ZïÞv¶Þ­­l6ß.­ÜÐÅÂ.­ßþk£¥g ¦Äc)çèt§¢ ÜÔÑ€±BõÑwyÐêþ«;£Ë§­µBůñ0Œm Åð°ùç¢÷Ÿ ïÞ^Îu(òz郄z³Áb'i¹pUR†Ðrñɲ׋–K+ãÇ£sIºiyúLÛ"»>çy__ªèñƒaO}`†e£õ±ö;½î{†Ú W3,(°>3eõ!a Îÿb7½oÁú[}+£ŠÀw%yO–ïTÖ‡íøŠzÖRPyÝ 0üæ<6@.1·jœâyY´e¼ñz/ú^G—ü¼šøXhÃ~¼ˆ÷t™‰o˜…„ç€{iÎù•àL»õŒ®@6 €³®a"FwU'ªt¼Åž«µNÀµó<€(X©F®Fÿ©2ö"Ê8„.ê\ÿS/)ÿ§ŽQ2+â”"^iŠ íÿýSµ‡‹@Ú·öÿÉæ)ïK*—y½ª”į€÷O‘ò+àüs߃›ÂþcMEe1^Ä?ø[áÞÞ?ü¼÷츨‚ â߯6…hÒžëÏÀârÃC™‰ eæ é"±mÀs–ã6jÐ=Ý’»‰'†|è0’4×™ÐdÿÊx•-‚Îeß©®rõ¢ÓýÔ ¿½Vð}Iî»!:—*&¦€o ðŸ 5Ƕ%MÛcå÷7º|´-È¡ÿŸWR@h|úì¹<*dƒ»TmÎ iþ4ßérÄ6®$—þú^—»/·ŠeÙDñ$¦fG|[ówÊטQÅc»’Çv%•<>keˆ”?3- ¨- kû»°-yv)õv9õv9õÇrj|÷;ºìž3 ‡ñ²±¡,<¡Vâ¸õ®O‡á0òÜä âVLžC<Ô¡’+Œµtñ—µ<銭í)­±»:„r#!C<+‚¤.˜XÝV='¦oDž”‘‰×‘ΗؾA]qDÐ’E'Zsv¼^̺Q˜³Pâ1í;çCó|>ºìF=nÅY¯ëW/åâóz|Ò®ÿ ¼}–ðâîßßø®gàí³¬R"ùxõQäT·¡%Œ„L͹|¬Ç%ãX3ä¬?¥lÓúSàîùP*6Œ‘ \’惨ËÝ®À¬Òù'Ê‚û½!ÿ=ŽasY!T¸xm^÷Ò\)ð–š,ðûéÿ{)ŸƒÑï>””¬¸^©€ä\±ülakpt߀Aÿ¯£©kÎoÑ?—ß”â%Ô÷íÑðnÇ^°Ó'_WœÊó¥uÕïõÉÏk§7Øw„hW à¦ÐÇEZ˜%î@C‡#ÏgÒr¤’Ëv5—íR.»»4·¼.RÉe»šËvYÛFÒ;o‚°p`:Ä.ýOø<­Ä”ðQ÷•˜’wJvˆ*Û•/ÈÊêXB"×x@§t´J,Ϊæ ý/ö†‘ô]¬><2#™élÜ3#]´'fÐ0Ø:ð¼à=ªÏ>²¢Y ÜW†õQÚ‹¦³ø¹÷Ôe‹Ù1¹ÂºU ¥¹¢˜‡Å(¾[a‰­å\\³r4W¡2Aÿýgg¡BeCbQʶ})ÛI)?“€ýK)ÝK¹YÂÉãÿ1†$™bIÈÛÅåñ=¦Ý«‚5é0Çdr§ô ‡ddÈ2þ\ ÕÇ.{Oê_ͨ‡Á¦ž¾ä…ROp%½ç…ýÜÒ¤\WçR~(Æâ„^š¿Wš?ª UÐÿ§‚þ?âì­ ?užj„3ã·mÈoÛßGC~e„6=.‘‘ªAœ¶M8m›púhÂ飔‹õ Ÿ¿Ø•šMX´#ßqˆ×£PÕ¿ð‚ 7ìûü°.)qø°²Ù¾§G/íØ(!fkRJ·Ì攇`¿æÇÉåÌx @rªÇ`Ý9L*±X›‡¼>ª[ ?¿~ «ñk=GCO¿Æ+;zAó×ãOPÚ·w_íõ Ö´u{»¸lMõö±yë£ð¯2.‹Am…kZYóçv¤áAàEµéˆõÜ@å pu¼êXô\̱§—Í5¹ýÛç.2Æ¢Ë.;úNÀÍø ã3!"È“ÅL)nÑ-Ç óîÈÏßX‹•+|mz­«º­#`Äú¤e;éaÎz’«e$¿Õ›ÂjÌœîŒå ÁÐ+ëÆK4hžÙÑF!‹*e9ï°ƒNbÚÓܶ¯™ýèH;½g¶Ë9ùT—Ì^ØùÌz~ aGPÊØGÆ”JH ûrF5ÊÕøÔÉQS=š%n×-q»F‰èϲÎ;"áv ‰J½s­KJ¬'©P‹Î¾¼ƒšB£Ôàµü‰no=B{« FݪµèXôö{‹pàü{èÞ÷^§c5ö922šÅÀƒ°U"ð[}bû~/*I^PÚï¤èº¸Bñ¢6­}¹±ó´6m¯K^¾Ž|·ÖוÄöo¼× w@%ZÒö€f+|,ž[‹ßÌÔsÞšúñO¶5uÀûT°Öø°û~¼ån޽P‹-®-7("r)¢Ò»½#âd¿õÎúÕ±lÉ”Û-Ë¢÷’*ÚòXOãÄç¥íŠÙëmEþݶÿVã*$ 1Њ?8½¡÷›õ&)Ã`Ñv«ž¿'ú©. Ø©-Õ%VœDÙî8‡·á4ÀZˆ<¢¥òû]>* Oü½¾öÜÍø^”„©SU]šŸµU!9¡ˆÕ0b æðé¼B]ós//*Im?Øëyqè«¡ü>Ó’p=óãŠ&ü Í"ÿ§|­tµjU•«u§=Ÿ7¸ZþEü„9gÎ ïR¥¿/Äá§ûCF&ÄûIðº"œ"I«jsý³¯â¬WÒíW&®^±ÿ6 sVÓ*=ðN5ß§Y†[̲ª,ó‘¥j÷Œ°v7“»< œ¾ßeŸU}¸Z€ÁOßH2£ð€x;/®D|t ·S ë5Z¢M<›DߨÀ³¤6B#ÙÀ8´˜‹ªg¬óÓjÉ(ÑDÖ¹ü¶y·dZ=‚j嘵k2Óê(sžïkñ,Ô|Ö9º5æJw÷è·øÝ0ëèvc,~ë´13 Ûc|—"ž›ãòÌ¿÷ÖX³.'õ=¦l>!1•ÿÕ/þ÷QÔ4䌧dk~ðÉØäç™äçÛÐõ®êÐûžã /¹L*·î± -mì0ok?è2©8åEqs—Žƒ šükÅ4‹í²±7®è2XOÑÒ †dÿ’6#|«KdßßE ê\æÜÒr“b3ˆ+´¹o—£úÎ'`ß%’âº8kÈ_ßèrQŒ”›Õ¥($d9ì;~°Ù^a¿‘Oš/A+‚,¯4¬Åć-¢‚cÛÓ.ÂÉO½ß\[Óܧ&E¡µzì-¹›¤dgvF±GšŸi‚]Ýí`ôOa´5¢;õ¸ÙœŽÆyu²®Ã àèåˆc_¼-TeÞ/SÎ-ÕŸe²œzú®…Ýà·B·6á3«¬i ™ßžœé)/q~ >÷˜›Y<‚{øÿ¢Ûõã!^æÝÉ#]5 ÛVØŽ#:ƒÌäqt@¿Àå,œ»K"šÂ•3ï*xJv>¼ª¡•¿nÊåA\¦°YÒèî{ÝOèôâ,¼ô¥f ±Ù„oÑß9m5ðwÎ<ø4ÄSàÝÒ °±!>^Øó»#aº\â~貨؉ö˜oI®ô¡¯ËU\¾Wƒ¸»m]=Ñùt5IŽF.krÁ 7úF“ÁDÊ”]-?°VàÔS÷ÇÐ|Ò 0y Êp»‘³'ìšîV`c?f*·+€Ã¨'\b”Á uO»ÞÎp‚|zO àTb|C…aúQy΃ "Å<8¨ú"p„ÆÛãN5t šãÃòwXuÙ‡>¯I¾dúÚì,4àêcCÉZ‘÷kè¥.íÇ®Q–¹ÀÜ¢RãpÙ;.ÛGR—í#©ËÇ#©ËÇD‰d .RKüˆ8ÁIk}Ni›æ£a´w4Œ¶ªFÛGU£GU£ânb¬ï¿©: 8BnGY·í#­Ûö‘Öíã‘Ö ¿éïãrkKÝô£budµÚ>ºZm]­>]­Žæ ®K?GÅŠßØ+æ’àè˜IîZÌ„Ë7ãÖ§Å-×gÔ÷Ñû‘0á7Å5™8ò@é êrlޤ6ÛGS›í1»_70Fh 3Öƒ—²Ó%Êî¢÷>­Æºzü¨ó¨37×yñ¼#%l¡EÞ‡­Ÿ 9)ÞJsX4$†M^†Th=¨`±3¤{ï¹eÖ\“]'xO¼·X#Ê'œr¾¬O¾WA¥ìL¡{¦Ðms®Ûæ\?šsÅ…iÖ*w6p¢¸{/€§÷ è= ô¶ïm+Þ­xLÌx«š0%…Û’X—²m_ʶ})íKù(¢CV“$2®ÞŽÿ¶%ÿmKþ-ù[´O"AZáÕåËÏdAK 5E…êq¢ÛÏUëWHøÂ+W/¦e†ö8cPӲߙ.á…\„Svð7SÁ/‘5 ‘„3—!U©ÑkÎwÛ‚ï¶I¿Ê{•«¢ÈË~O¬(X?›7]Ðöl+d‘|ß¾Pžýc Õ“›îÿI ÇÞ³¦Å7Ñâu.§ÞìvñðX½™LEL=JOìéÈU2p¢O³RGžÌ§7*,˜2\ƒJ0žPؼ4bªD‚O“6ÜG|£­èrÜ/äéA½ìc ÷…Qù>‘—Š‚ð¾!!TjÎËÛ¥aAïüc!¶i·§_i›l¶Ttâÿ Á©R¼ß8]ïE%Ü¥ý=êû'*Ç.[•„²bo=Ï%íO~€f#[Þa¼èoå°ë  ]+äÄÿΗ•2˜ [!›¢ÅµfavhÎfØó*AÐÐwË@xcÙZnF‘3ºQ¤©m¢·MïòVä×ø÷ Þ ¶Á´÷Í 8¼ºpäïçMZ˜Ýöª¯Û0ý.|Ý|d€ÿQ%8µKiö°ßÅeîò†j˧è1(«9È¿Áß ‹†ûå÷½ 4~ÌeƒÇ¼˜æí Á—éŸÐh'éð#PêåšÿÕö4Ymˆ© ÌôÕ¬PAЦÞHÇ\À‚zŽò×ÍBH¢\ZŒI4´*12Ì›3dÆûåõB€«4:`šñ´ÞÅ0"`ÅE9® U€&W¿,€4{½ëùM…­ä}ZëN2S:Ô*$Å Í"€j‚Jïv™€[øfIÃJ3ƒ ! sÉ«ÜâfCü]VÇ]9d«ÜíBÔADK°ë%¥±1ú°‘˜Ž%m;[‰v™(ÀàÏ*ábÕ^V÷Ÿ–IË@Ù¤|–3!"±Á®¤û‰‘’'FDá@¥y™YÑÆX"´5ÿ­xÔÐ'ÃÑåŽqF61<Œ¢˜õ¼¾5Š2æLˆ™CiSzÁ„DyÑ}§× –„«©êÆé°E+ °ý srª'~+áÒ‚Ö¥’^6á©9iícÖœ÷ž›ÃSQ?žZÓ­îüŒ+‡Ø6]OšòÚ¢Úü9}ƒ%\ãÅüEάöŸ¼|έ:þzC)ä§Ÿg c duÊåÈ\Êãr¼&̈%aÎëL)”p#uÈ,KÛ®Wšzän9Yb0XLLïTpF—‹:Ót¦óÌ—3L®‚ü0Ÿàè=òî•S©Vƒ³&ÐÄ.ð~å &&pF¬øs³Wå_%ù ?™ÑAôKˆyC8o>¨É¯fļÅòôóUï¨5¬xÕB£Â³J pr[2«~7!ë@´s¶1T‚àð@÷ ­l­ Èàä¥BûËrõX¢ÏyQ –”ЉŸñøaawí¨ºiuwyôª8Z;*׃€¢Â‘š!R:!Ô#» !,Q9d y¸A'„–têu–†.Ÿt]5Xs‡=iÐ&_Ó#úø*ú­€æN÷2'Lˆ2œ}#õt³ F/½Ü¶$Áh›?*Ù"û+ Ðùƒ§”€@'”…n˜)y‡^öô,•Ü-A"/œ-*G,«~Dâ¿ÂȽ] Gý`žVR|úñº*H9ðK~ÔöZQ‡P1êF‚Žè+™PÐÍø1ŸtT8Þcv‰É>¬¿ã—U:ñ±¹”<.¥‚9rÕ÷z®bªp]K¡>ÜÖ"XW™Àh÷ù—wMd¡!åÇ2À›­õµbœÌxFÏ)åßf0?B‰9 Ý®A]ôèDª€²àªW}ëí¡νBD²gv6R\¶w8 •[9äWóšf <Ãrû#}²2µ¨fhªë͈3ŒC0@‹¥nÁ¤Ã¤ÌX¿ÄœkP"ÜÓ^/(a[K|IÖ!”óºG{Èo Ð`–ü¤‘㘶8æÈó†*&§iUÐ`ó¬(§îߊ>ó5jÄ5䯋 3ìÐ\þV6ËñÙsÇŠ7²¨ˆÊ½Ÿ nÇ£sày; Ñ·ê 9e-{¤ù;ÞÖhàaÿ¤ó ]léÕ„xáСÅŽ`ùæµÙî;D^ÜØ§ƒ‡¿ì"7 Ó%¾4 Ãó3X¡aÎXÚwÇÆ5(i?yd@Ù÷ƒeÏg:v\¯"àÊP«¡’Q‹Î°¼ƒ( öÖðrŪ¼Wy©¢K†GÄÝM•—VÔnÈSéjô4#…€V)Éý #R~£ËG ¨ q4 ˜gÐ]“»P³4·vÍåHŸí×t¹ûq¿Oø^ûn2¢ÄU]vÌi¯e¢Ÿ½”®§Š€µ¬¯·L§»=ˆ®¸g%yI5}Ë£o˜Àˆ¢Ü¥‡¡Ý”˜÷NÄVº[ŽÛm;S\I‚óU ?$‘5´…ëbj¿]W§'ד„³°PÔ?Ø–±µ¾R8H”¨„¥ùE=!aÐF šY-ðnRª$—³T£€Ý­@J–·Ê€6¨¢/”ŠÈW %ù{MÚp\! HÁ÷öûž8—*Í/ËšHF8RðQü`ß‹è@ ö1Í H„æ@˜òUY‰)êùò"–À.»¸Á’°ƒ¥ùE$BðZBöDmMó¨fÊ`©‘bˆ,ú|º€fÀ¢Îž †¥o5õ® ÊÇoîÌÆUôÄkÞg橨¡*ͦ ¡äƒ1¶¨Asq P|c\„’ [ ",6´ft… ·ä¹lÃ31R’6Õ‘@s(a¯‚Äâ\(jØœëYTÑÂH?èG/ !!ùP7ŠD¢râ0ìmùƒÊü"™RëÐJò¯åºüeÃÃ28ÔÕVPCðú!6¯ëg~ðCø7;6Õ¶Nä zNÏ^¿/_;fuÙÅ‘Æpö}¿/xC.¡^-ÈFÇC7 ÊR~/ëç»Ï^QÓ&¯°Ç©¨¨b˜y½x‹Ä·–× G#h¿š¦âIÙj.pRÞ)÷_/x!x`ókÑ[áö솾£¨¡;fÊ!J€Ž»åÈd¨é·Œl¿ëm…«~|RìNgÊÚ¤‹íÊOçž—!åI;ùœîe8>àÓ`'U¢¶BÎï 2Øl[’[4ÉF'XtåTçæ{…“Á¨Év‡R}O åñäF²µLw§<»n 6½ýH=Ö¼¯¯ê2e9\”ß'ö}îtí„Õ©šú>’Ò¡úP»„ ûydáÜŠ­ !xã{‘u÷G5(Ò7ÙºMý–³׈Âù©ŒÛÑbºðaQ·± }à#Ûp½Ã›ƒºkÊrÈ<ßPކâÇ#¡.¾9 bº[[Þh]+‚Ð<´Ô”ß%! VéF®‘4! Jòæ“›~\ cSx™vn¢D›z/s=íð¸A,ó\E³ y„\~K;dØïû1 z%çy å’_HehBÇ5x£ûâÎÂé93Zµ¸$pu‹A>RÚF¸õäóIìaÚÔ´ãAЖSzöã–&¯ÊÝ EGÎñô}WviWˆ†Ý4W3 a§«Y ÿï•eRÊ+Å1‡nÑ)ûÆJLν¡Ò6î 9—÷†,WãÞe$î ³9‰ÍmÀp$ʾ¯…*6?Ì/'Î]ŸÑéމUt›^ϓޥ\©ü¸ÂBðHÇ—OK™p‹ ²¢6Ý¡b4¯R:zâ.ò‘+,û!j¿?43¯¦¬[PùÇ¥àÄÚ‚€öAKß”°' Vö¬¤À%¡Ó![­YÓrè—%d¼Ùù¨[3Ñþ'ÙìÔóŽƒ!Ý®grÞ™¿­d“ÚÔ.¬Îâ&i²ñ‹øÃ„ßÙO‹“vþ<ÅBÙò§¯Ò'Î<õ¬„÷‘L©„'}‰{½ct‚÷¦…¦Ïú=¿‡h6A; [ÅGZ'…¢æE~”Ïv¼¸Ãào’+›ÐyÖühb,p8AKfµ’Κb[ALëKâ4âë.긔³üÏzŽÎ¾]v˜!º=ØŠ^Aåh/ò»Üé¼ a Ó™›ѽ G–ò þ+\òþ´O ’é~ºL÷Ó=è‚z|ÇÓN #>B§RŠ?_µü¸»ßõwÂÞªHΨ`i1“Ó&ÂÔ>Áûá F…—„W¤x ¡¿ÖÕSدP%€ùã'­à­w°Ù^#ßa*´6ít^6wjyØ\xš¦Ó0¡p¼ á3E;F¯ðžtœ-ÜçЧPî˜O%²¯…x:ï\î5ä-t.ç¬v1"™˜WÏÓR#'•4‘üf¦èK$O§úñ‹>‰óøI*)lzŽ;š ?Zt–Yïýp÷KØFDè\‹8À ~mAÆ$Ñu:²¨¼8-vò‹CØ»“ Z ØUAa_w´æûNé—9áÓvZw§A\h¯P{†}4 &¹WpÔYøÞa¥×ƒ±ï÷@ã/U:¨˜äöVTþ\Òhü á<­lÆiù4MRc>œcçýÐH<å+–’¡›Ä6tƒ‰c ø®ÍL–ØéD±d×Ô¯L‚=㈳9Ý’ƒærz`%ÇYê)™p)”é_â·œÎÇœÍjw|Wz^sŽdtG’íéârù“´ Py„ö Êo°0ˆèº8¡¤Mwºœž=~$gÒÉ_utŠšWu‰‚Ã…ÉVx%Ÿ$àçóY§;¡dyNþøS2åT'â ¡gÅ:).ub¡Ø™ªì÷údAÿµ>û+ ·­ðª.Qpº¨Ë<Û¡bœÐmÓOt)ó,¨§3é_áVŽãwÚTÁä+mîå$\¿D‹sb ÉH¹Ó-PevpíƒkìKrI§ ›d×t­ó!O'ž]6g+×8¿D×äÇ é¨Ò5Š·ø8îÐÅxŠqàƒå²Â;•q.õËÃíT …=}üd!;ËØ-ûX']„3,B®ò:_5N÷þPÂ^s‚SÀoöªÑq¾ŽÐey&R°«$ع|jm:ÞÁ)äD‡5Ññ¶Ññk$Mu¨´pJÆ9æœïLtiãE¬ IºË‚¦Ù®"yÎè°H„™«‡ìŠÉÏ‘Ä<ÏÚKׯi›Di‡Ó¥h bßL'-µú–?V4'‚NG¢öî—ˆ$*¡(¾N·Ä¢ÅˆáPBN½ ™ÌÓ-©Iw9­l—dœw­õ¿×ר.ý‚ìóIÚ„¢ðpJ’O9x¡Ã£«O³'©×{²Ã÷'§: ù¤øqª#¶t'åˆ]Ÿè°×8E†;xK9Ŭˆüï”HÀÖ™ø ; ›T3.tOäƒßóJ>INÐù¬s´›ñ×ãßà"ëkéÄó– AÇ2©>¡‚T%Ôó´#â˜p™ÑÛ9~Qh;NªªgÅç§üS"V-,‘3qªRߦ¿:•²<ùå.tòj±WòI²eòY“´“J;ó‰Ìo¡]|@ìÕNÉ_“? ùâå·\Ì•´3>š÷¥Ôªy…M2(+dBù}®#Ú­IØNñr6A}6›1ÕÁœÃ œÌ=ˆÂ'ÇÊ;üœì0±;Óå·|W%í\'«×{9› ë™Í8ÓAÝe.ì~•zTS©Ôs¬Zïål‚,.›q–Ñ®C#c¥̳\×3éÓŒpÛãõþ:ý(…³tò¶^õ{=X}¯äýDˆ,y·[pX8A(žF&áîœýnƧéæ“ÉÏf<ÅÆ1žN=5ãsÒâY0N˜â©å4I?O’g ÀgÔ‡f<Ñ ñaŸVõ<,€éý"“2‰bíSw3ßëÁy×[%ö‹\B#¾õYKЇtF*, é9<”M•6»é$vÉgqyú{ ï÷aP‘¿ð\2˜î÷qtoŸEâ¢ÓJ„!]õƒ“âå«d%Rª{e3½á6òó/žžO·,¸‹Ñ yôé¾üy&Jå^JÝŽV¼h΀†äRRHG•V®(é©F%Q7|4¥_KI ÀÙür‰ˆ8~Uò"ÐÞð6 pÃzFŸèt²£tÝïJwÚWï€]';W±:òå^é›\Gkq+ÃÓÐáXÒ%2 Â(ÎÔ†1»›ÏômrÞöéo|^1êi1Û£SR÷z²‹1[WñTì¤v–á·0Õ›ÄÇٱٜѲ‹IÚ¹Oùd£çŒ`ÛF×>Ì™?‰ó¶(¹§?“67:Á"\‘I8À€H¬p4ð•Öpi:}DΤŸÏ¸<ˆÇcÀðKŒxœ…÷£»:íï /pÏwx‚lƒ?”NÈ׳© Í Ѥük}òUä²%ó(¿äÝOw|ñÚg;pÊö!Ñã9IÛ^Ód_‡MC_!;¦Š´LÛ4€6¹˜¾b 81aÛo²Æq§Ø»µãp0ðܯ¸Êp …™Sµ»œêˆþò•Œ›ÇϾ{£¶Ÿëd»Ñ9O´Õk\* ³ºŸé¤ºÖ¹N¶G¬›íRÓtŸšˆÐmвG_ë4zlŸߒ!Ð’î§=ó cWðâ“ÉãV8x"Yòi+„Ö=ï8ëNÇúùtâ3ÓÏû×áqvCÄþlGo³?Û'#î÷úl8pèæ5ùx§I7¢•‹æì3‘S”]à‚|tJ:x=\_¾¦âÖÔ:hØ q’œÂ©|+d^Ná ÞÜNàŒL;ù¾oÑÍ2N“ü ÝÕ^J9Tæ¶´†ùTJGûˆ*S)õÀÓxh'Z‹aD7üÓR°cÏS;øgÝ£rD—\j±{#©ÂÇF"êó§{éäo5¹ Ái¨Q{.àΫç¯,é¤pú6Áž±êr#­¦õRþvQ¤9“N»¨‹òp¢Ãn/O‰Ïþ·üµ-}d=åãÙNæµ¾èÅTòN„3ÔW¡Wz¯º‹½ÞCð¥H¸Ø!Ÿèd<»ïô³ËzÈXŽœ½VŸvðïSÙ Ùìcnä\É/Äb‚9ÎÒ§3³ôéÄߨÎgì÷¤Q–?0ißäÖ(QÂi¦B<?ƒ?qâç³ø¸Òst€„i˜ŠßñÙ„N=ßi×ÁøÌ›KtŧÁß«ÇvV"¢$Ÿà+›dÅŠs¶“yÝÉ›À‘›xÀ)|¢“LçW;%óù >ŸŸ‡‚@NŠJLªžMÏ%Í!ÄÍ‚÷+\@pŽQ?óDt]uª ò ]‰\(¡jàÜ_qÚFáà‡ÆsOãå NéÉ ëé¾C0€”u0ï»EÊD˜|·©”'¹Ó‰¸Éבã‚6x$¸¬n6ÕŒã]ÐÜ%DZÂä8ÞÌ“/щÄ9t-L^’sKÙ8£‡mþ÷"ó£1{ØtfÛÝ/¢½ šô>»ãìܰ9`ªC°àäÇTþ«sø_Ñ9n›ô…hÎpÑ{…ÕåªËw&â…UyßB…G™ÎÉ{ɉÃOÞµÕxÚ)œ`:ݧ½"ZóéŸãàí9¦íÀE&¹¾æ„ŒìŒ¨{¼¢û,ëK*È1øïD‡ñè$EÑÑåz½74Ž„ÓYœ/bcôÒL¯©åég;»°`âˆêә笤¿¿£ÿƒ7eîd_?á5UïŽ/WBÇ®¥’&@uö,ßZ;œÏk~Oªšå4:äå©xØ8›µ]=—Sþ8›U9—S(9›U=™Ji„œ’öŒÓ¥Üî”TÒ9)tÎå,ÎÎf ÆNIMž“Bca*¥Ë3©*.œÏ¦L¥¬ ®Ûi|[b“q:±¿8*êç[m¸¿ö˜><~g¦j8«¥\æ)iV4©š4Lµà}ÓßTpå,>žšzõ¾˜+–rRø´¼ ,‹"íNh ®žÀ_TTÅ oš6¡Œš»àŒŠ›lAiÒ‘{.ç‰éÄ høÝoò>šxÎŬ›­6ÝÏOw™gB!£g_LJ ü$À{\SÛ =ª*Çà×… gH£{Ä4gØ_ëSøèD‡•rd  awÓÂÉwšú ¬ôñ!§[}>Õ²ÔÔ™Iœþb“É¡©¥ñaáZªCãöÔsY—p u†8Ÿ•­ús¥ÎŸÅÛ¹‰ c(E¯^¯œEa»#s©4©>\N‰ÄJƪbx—ε݅J|+ÁëÉ©̼6A¥uñ›î9":UNK½<–ü•uq±JwÚ'[<ýŽºŠýNã°ð5WYò¾Q[)Uë“â].ûDÙÒ!Í$KvéSa…B±Ú>‘š8ðüuGÛ“(ôò‡+鯲¤dïà Á)¡€MâÀ;7>#x³.<á» j4„¹êüF ~‡WÃè¿ûéÝîîÙNF ëxSÏuœ¤!±_Í& rÒaγz‹GhÇIaÚÞÊïI—Œ IÉ©ŽpNqŠÊO¬³MwÒJ¹g:)Éàt' :ÁÿOÚ›··q\ý‚-bßwn’éXŽã¼ŽÉvåÞ;H€"b€@Ð=™é&‰ø¢KÌ,Ÿ}ÎVÕU†œå‰U§ªT×rÖßYÀÔè,<¶ªdíjú©±þòN`™ïê¡ô%¤:qa žÖ@»X-¤gVÖ±Ö Èjþ‚©ðõ} ;¼ŽòN`!e™YÁ&ãG›•ÂS4báÔTæÊÍ·:r=^fh˜D+?û–yaê©¿oeŸZ›UÙøYŽêU #ÖW5“lÜeo ½¾²näo‹ûadÞ"÷šh<¬kë< \³±Z?Rm©y«âYUd¿êޱ6?Ó“ÃÑ¥†xfö ƒÍ“Ð~s%RúÍ›þ‡{~c_6ö†{öûÐVÓwP„74Õ»¾eÇþIû°øƒžúÊÆD»Ã¿YébƒhºY"\(]mUïGŽéü’,é5åïå®±ë[›böAóÍù·´Ý‘~ä“­{8bÞÝ;£%Áñcø&[²ŽcŸSçúñ]TðOz¡TF>µ1²{›Ï#£ßŸ¾ÿ_[[BÞ‘ù3ĪÐêéiÁÇrUúÃÑlÏ]Ù›Q§ý̨Ó6–½²v¯´X°LûïGÌç„¿Ökäñˆ]šþøu’lõÄåþþWº¾ð»–&›½òúkçU«1ŠêCV´[ð¢yöÙ?¦„C Q[bŸªèݳà%sPMZ`ê†o’!O¦³Ÿ!dœ ' àpŒ8o`_ÜÁÿRü1½FÖä¡xGÛ½gHé•ÖiKó±Å†‡õˆÉé^i©8B !<³Ç¾XÒšµC%+ü­=«».[…Öùè—é z†Iƒ.Øh‰ÐÚÛÁ@« eˆZb@Lñ–ƒÚÅÏÆ£xaŒ®ÑÊ`£«’úð£âÂd­Rênô®ŽòòêÅ×qEL:úž ]úp:):º'ƒ¤T=YÇRñä´•‰ëÊâÄ$¶.¡“-%t†§´™)e$JhG ´™Û(¡“>Å$ Ñ5 ìÔYqú‘\ÏUqeùßÛý´?É÷ß¿”CáЯ}V·ÅÍ žlOä…Íõ@w"Pniܺ3ºÏܳ&ƒ‚±¼¢Ôþºv—lûBao´ºáÊ=éŸ$D# %¤4ðÅÒôz¢)‘EÑ~ÿ”·¾º›®è¶µ«%p¦îò¢ß¶”Ì)Âæ‡&1t€­œ™–öSÁÜðÂjÈÚ!NiÙIN)H’%D à/›g'VŸ[º×°ÙÜfPÕ¡±*¦DSóÚ+E–A®>ŸÞùšØÓäh‚ CúšØ”w–$mƒDJ\Ã^M¥t‹µ äÈR5‡>¹¬ Sîx6â‘öªÃÅz|kxµCêqªCñ•ï7BñˆÛ÷¯6Åçî[¢ÅøJvÞFÄ€’†ðiñ– `òƒ·˜‚[iµ¥4h=µI„õ ›îYÉ{­¾ÝÞrK!PXq…DWC—$×s*î)O´1=àäK´IKãX”a1ñK‰6¡ysjͱ^Ï«µðº­yPOû•ì¬ËÅÌû’¢÷dSÝҟܬQõ›jµ:Már}·nŸ–Ðø1Áíûµ=™š/mH“.€˜å°HSæËOn¹ÕèʬǡN{h\%ÐL¥J õB*êR=Õ?üÂZS×>Ñ×~·”ÎqØÃp²6ÄN%N'e@% ¤…þɾÖO“j ÒsA1ñl&1èóñíb©èq ] Nÿ§Ûl@κ‰äna¥Ò'°Çc™g1¾ãÇŸŽ½"ÐØ @vpdjȱûDÝ4§¸_Ÿâk9÷'ÈŽ´†wýåm7D¦øùvðÌ,9JŸÏ ”V€Ý¡qkŒYU}^"ØR°ÔÆ·£{7®üòaw¡–-¡Ÿ -_iÇðZL:Ú€VqÂ,hûÎVŠbw)p'ãIÆ×S–A6éUÁi6’+d}u'65ƒ €€ÿQ…õ½^øGsÝj•„ˆJÃM•€€ÀN;EXŸƺÂÎ!jaã†ûúÙMåÀ³hK I|¾ó]U'ôeÑ¹Øæø ä kÊüeÅÁ›ÄŒ0Óüv¶¯‰Õ–œÀâG˜™ÅÛŠñ³ššu,Ç¢bgä½±Í.ÿµÕ€²Ù7ɰ¡èûî5I„yâòÛ%(´-qt*þY, ´G{mQ—$™(éF‰“ï¨Ë‰9¨ªèy} súàGç¼Þiæœ;ýÆø¬²²ú»’diˆ ¨DŸîaïG°´Ç>ÍÑröPr˜ÂëKUÜ$ql|Óò¼ãßòMŒq.L»ôi—ÃEŠpñ ¤²åF™ô[#ïðÂGå!yô0\Äq ÀWQ»ýrYÕÄC÷ 21ØOF”™¿¬AiÎ'ÅÅÜ\î‘3IÐ%ÅîGüÅX4 G#[‘ÄfkÉpXT“é‹­/¤sŠ¿µ°Ë+ Ìôéh¢ýb>Ýzo³W'#)(ÒKÊkîR¥@G¹å"bÁ¶8ñrxö/D[ѵ«€yùȼGHû~PxûiêJ¾ÄÓíÞŒDiŽâW‹Å›»ÑòMLÆÎ/pE ­ÉõùCÿr?,áÅQ{ŒãGðð4zK÷—)¿Qþ˜;žë¾yx~‹cyÜÿÆjz=E¡[uÁWå@Àg/Â[ÕÅew¦‘úöý·ò©Ü 7þ©+hhM8@¡#‹k§;ƒ#‡0+©Šqõ\c´þÈCR† X &hº¡‰´‹ÛÝÆbJ\=%˜x7üGì ךš¸³Õˆ#¢TöD f ™$¹)R1#@›\Ë/ý×bœ|¶ãít¦bSYB#œ7Ê4È%dj^-aÑ|ü@´›f 4JÜD¯r{Ï€,íV0c`Á/(Z5’ˆP¡0pã>Á« Wâß~@Ò×(ÀaÖRLÓægÞÅ™r³¤EB¦‹ªº¡Žƒ§È{FHÕ‚Öä r‚hù¿úÅ¿3‹y".´¬ö  bZ¡¹¼Â“pöŒß’Ó_.EŽ.— È}þOãÐÕºóŽû$ˆãCÝmérô)¹L´4€y¤iiU@oÁYR݉ò"bY%ËÎ3:ËÔþ4$¸ÅÑ1TöyXŠÜ'.}ìÕíå^E?g¥šò%•c¸¯^ÖNWþEÿ·(nÕÌ<¼y­9*æò Ü6ˆñçó$#¿â4y(|µ8®¬vë 'çª:÷lrålí†Ànÿ¸¡ý?µ`î> ˆÈtõ Ca% òÔÃÜ ì0H£!çüÃ].˜W¢hF»ª£mrMO±ÖëNû•Sü¹ww3®ñ‚ÞÛ*‹g„•a›²U©0˜"C‘²iã¡è&¨ã`Á[·%tˆÉ…aÂÿ!ÆêpHcÖö 2­í–´p9´´ª¦ÎÉ'GZÓY°üH‘¹ro¦ó¬í‰¹¿ÝI³ÐòUÏìGøå{ÕÝ cM€Ím}7÷²cS™í=±ç™¯ÍqÙ ’aNÐÏtêш«Èö¢Ì(¼ãc‘ñ“QÁ–}9ÙjŸ5läPÏÚ‰ÉyÙ)D°·0$Ì–&&®{OyÄÓf2ò\ _x&¤¼HÅx7Ÿšàí 6¡ŒÞTÈѬÈ;é]M-ò¦á\9k6aß¼&® I"ÑdIèRÌ™‚t=ûòïàÕé1¬­|Ê/S”¼·×LIb#k‹f&•Ã0ÀžÊA÷`( SÔ&^ܯå+rb: èLÏúuä¶²âÌ+§k5’"ä™{½Š,Q:Ž^-`!ßå}µÂ‰‹GgV©¸j…î²ÀB"÷î&¥n¯;ӹѵhRŒN£wÁNŠ"ε:(èuŒ8>á’ ÈBðï3îT ý›™Ô×AÂeͳ J;V ÐñÁ9}1«Urž]dzþ¼Q\/HÉé°©:é&ªáaæ)NÇ ×ºËýû…'wÑîÞªçíL½çÖE«‘6ܬÖÓI­Õ³Žj>!ɇ#†Iê§:b~`39SÖή” dQª„â-ïmEI®„¢!ç9—òÁÜJ…J…\IÕp<ë/þ˜ëÚ6Hë0¤êJ(*u5¬m,¸ÃÒNàûÅÄ´ S˜2çJ! t·lŒXØEð% 7ûÏ7ì¼ÛzfÇhF8s£A_êÔØO™œhÅæG<ާ+Ÿ¦!xq€ðÖö\ qÍPBbx޲^çT(.1åé[,¥§4%TÝ3¼Ô݈ôÌs›ïï둃-¸Eù4FWñ6HGÛ`p´„h€Iª  ä´®ý8Ùú‹ñEPúæù7E޶¡è&Ù>Ýìõb³×0Ï^)$驯§Sœ”Wd0)q¤lúIÝù7L+Ë ª K~h5¡ÍàD-ø´á‚)V„ê½÷„d¶b~/¬ébŽ98­(P½êM"nH»Eéá1ZÚjÀ1¸‚é·fÀ¡ðÛˆƒ¤’MÊAc;Àn¼Æÿ.Q˜aO (ˆ— ”T HšËr8A¥i:¡ wÁ»Êïµ.]Öhðµ˜wŒš·ˆäU¼Úà‚¤=çØ! IGŸ7yZÓ?ë†Ä¡£l­¹ïX$½ªI“Cµ#ëšÙ zF}_íÍcd¢,Q¼„#ïÞK;kTl0‹•2ÊQ‡’&Äž=Iýê¯ýâ¥_ü9ö”•½ò÷2êP|IÒÑAÊE*‰$'@¥ºQ¿Në+âÏÆo”QQbå›È?‡£OùöOõÒOûÇžòkøô݇O¢OÉ:ö”£mãOÅA+#+äó÷Úª]–œX!v{Vâ;.+Ço³R²}a5­±;‡C{=³ kÆD7é)ÇßëKÚ­Ú7l7IÊõ×÷îÎÞ[{>â.øhe'ÄL^`£˜aO;Æ T¤rÝSØ·0ýd ä{Uœ0ãqÑÙ°ç€ù¸à£»ŠÎFXÆ1º N0ì¬àcÕjøBlý{gòÕprÞ ¨auÂÆ3ƙ辋«c/éè0cèÒmò•%«»ÝɉA-‰«¡ÄÒ^v6¡’a€M¢b&ÊaĘß(ÿ)ª+ý'¤ Ô/e”3f<¯—w®a˜d_ë¸óu.P+öøÝ™‘ÃiÄ ï+9›¼lα™Ù}g+ŸšvŒSÔÁ¿s8Aðö»Âõ踘ë‡eÈ9@*žбW™—YaȰZú" Ëɦ¦5â<¼ZnUÚ3öNœ-jsäãæ*)† ½VÂÁÒ6ÈõršBOÞºâaÁ{~íñõòV›Ïå1—ŽE‹—ðr™ÑjgªÔRÀíÌT ?Qj•ÿµã3r2Þi¢ñTzMcÇäõüý’ô² 噕qÍæªÃþ1¶ÝÙËr§S2{Ã8jìõÜŠíe£<±u5 êr5Œ‹šù9ò•Sø ,¼(²/ÃEöܩ\Òû–oÁ)‡Ðž¥ß¸:T$×îzI¿9{Íjs5ˆTí®•ìWã¤HUÚ¶’Q~môœêµ¬k‡±y”/‹&ßùQ3~_ëëÕ 2=QÝc€—޽)”˜¶­=´½h‘£¤@ ZEÖÑiw¢ Е\Ü|ªº¾#ðæ|[îQ) |Ç ÜÉõ$jïÔ; OËpì™O”ÑÙŽO“ö\_ß–|ªµç¨Ä 0T‘•ô¨»ÛªúbŠƒÙÅ ø™¥,ZA.1´!á_Ã|çŽÙ±UM“géÒ…É÷ú²<'Ng52¹Ë„ÖXW ÷Ïšª„Îg£Ž•”aêÉ©Âý©+Dª˜“¯Užæ±ÜÜ%¥9´ù*/÷?‹VcØïîWŠA‘øÓš7½è· ÆýÅM1×m3‰FêÎÉÍcpŠÔAÖ*·6k/OŽJßW…Ц½O;¾¬~ªQv|Tæ˜ü2=nt‚—¬Q”8‹Æ:!1§áX‰A2V­ì„$)…Ð’Ž6X( ~éŒcæI›E:^{â_`WËNH¶‘R ñ“ýl#i³’±>‚ÔÔD1Êjù³“ÅÀxÏŒTeþBmó€_3/©ž2xÔΟÕÔ¸wˆÝçî)öfÃ3¨às*ˆ\FHÅ¥7Ãßšo¿$Í0¿Âßmv»]­î‘yX{fÇßlv$h*£ Ê h4²½ >W_ë÷iÈó8„éWÞ N ë.d ̨Ùí¿6»ybHßxêÓ;<‹ÌN_[kÌùuLö}û­ìÓé¶á „¹¦Šö®÷$uþãÁË”,«–U´RzŒ 'u¤¶g-CÐvÓÁ`q½jãæžép‹[Ã{®*Vs `XQ®•}Ãù+ߥEYrC;¤¯…Jþ͘6áÎ5"d¢üñ\‘k²êš—.fè(3Sgß>K þ=e1Ö~˜¦>Vr½œÉ§ˆ¬h‹^Â.§IuŒì¸; Äõ)rsr«kÆðu`NÓÀà=LrBm6Ù#ÓC¾`ñ…è o¿DiæÍ*6ȬüdÅÚŠ)uøp-+€ó–©ï)T±|t4:š~=w=YÌîPBV ŒƒKLôœÿr»„Õ±'XÚAV!&ÇÕ£»Ñ»èà¬þì»ïsÚ¥…ë¿ÝŽ8bb[¤ÍŠyÍ—¬ÕÁƒF·ÌÙh¶ð¥bÛ×ÛjK±¶‘d¬$ S´HÊfÄ’"V|¢àÑÄìZ²MåÏï¿蚪þÍ9ËN£çî[Ü¼È PYÆ´¹žRN‹”qãE®gkï6‚^+EŸ-ÆoâÎÕž¾ô¢p4­Ñaõ1£ÉR¨…RZas¨ zå8È’a¬Ä'öx…öÙ5ƒÏ%\¾ƒ¡ž›_èŽÔ'ÚvMúÞhøÐ»£ÔYHRëëè}(˜DöÓþnö; QQ7±cÔ:½Bf|¸ÙÌ?Ä5݇Q{o`Ô€Ú*¨ŸûO6/Ø÷u.ºIv³*²e›W®f륀ýÊCÑãj³ãG/iŸXÁû«Çî&ä}¾%5Áø’õ$YËIVíqŸ(ÿÒ÷ôùµ4gp<ÁCðöòÆðÕÖ÷¸mäè»ÞÒwE_Ï·/ð@ÏèñÅfÀô—°ŽnTwœæ– ð2D ÔLƒâ×t9gn+y‘ò|!Œ¸¹a? Ägmˆ½cåhìÿFÉýù5ÿ¹ŒrµÄž”§†âmR91­À0Ö äD-ˆÐ1I)VÎéD6¹©DÖˆÒF[7"“œƒyÜ|w¯]Û0Öè’êQ&'¯ÑÑ­ƒƒ™BK)2À´å£Îõltƒ ü_t拦n"¶uoƒ¢¢ -¸œžEµ²YÑîô&1­|šðU+¾`wãß·Ü^ßMçh¿zÀ×Û—Û×dX÷;I7cí´~P¡‚\M}Ò®é%ýÏ2RÛ®aÍó@2·ÌÊrÅUZjVkšÈ•#«}g©ZÅÅËQ%泓À&Þs·œRf+¦hÓ\©ÇR’# °Î›†œâ¥ÔÐ&›—4=6à ¸‹É@UÞ¸DµT݇‚Á-Ö,oy8¨-ø*ω5÷I¯Û¿î±ÙÖþö}fkèt\ø êƒ7FÕfû¢]:ÉD¤ëUÁª\.îXàfrAX*õuŽP:üOã1xÏüFuR¯mEpÈŸêB5²‡¨wóú-2þ—†¯š÷kÇäó\Q†u¾P1톑ÝjÀ¤¡oGË ó»òn*l '“ØçÔ¼xÖOé| L¨…ÂbÕTäødÄ PýPŒF0ó?OïOØšÊiKŸØiMƒÍIÆghÙ¬è=Ï$R,„»¸{¡í»bh€·Ò4ŠÈLQƒ–åçìØêj5øÐî¿©}£¢ÙÄ—Çïä. ƒCU6¢h³IŠðµÙ›±]f”ÐS={K¾B¡L^étSQN&”µ;„æ0â¶”ã_wDU“¤DI_…—ôþûˆEƒT9ô6³ïÿôéö&ßìcŸ,äšr§uÞê\tœFkÐk×/a«Ó,5º¯ÎÛÝzÃé5û'Íóaýe3/á„úʤC`L¨ìH+o'Ö|p;¥ëÐÈfX‹c "äÄU¸½›Þ­ï|W¦”º)”Ó äL0ÑØ˜Ûfœ¯´ª£8•6“ç%ý7òÔàÊ6>*&·É¢ü* ý3•©„QÊøÍIº*¡Kl0éq/º³«Ñ1úr½` kŠ5gTE†žiž‰ –Ñkúÿ’pÈŠ‘Æ1¿LmöJrd?ºBúÅË_Óÿ—;0 _ã—ö:érÆ«v™Ç¾=ÓÕÍ è\x¸<<Ç&eÚìYOà ô ¸uëÀMáíZz=CÛ„¾ÞPƒ÷¹‰NXÌ¢ï=¥ø@tŒ¸U2r B¤lQ]!âÁ°ŒŸ¼j,}êl>ly¸ˆJÞ<² ЦÕFù`äÇ£þù{à¯ížyök£3„d§š¸¨Ê¥%©êÜUÎ/’XB£’Óžxƨ„y¤“œ 8¼³â‹ö‚ÕÄùdÙ:¢´»vJc¿!ÛIFâ–úþÁihŒ *º,37¿‚’éY!ä“ ¡Éj.a¾Z‡¥âØ8+Òh–[fËFÑg^’唢*Y‘šn-§Þ¯/+³—5iª%Hq¥†LñÀe*§Måá¡yOó–*»²R¹Ñ %°¡ÈKúî0¹€¯¨«|w¹€Z¯Œj7­d;~ ¸›½­ ½Ã÷iòòôªÈö©õB„3x¢"BÀ[?…mž²ß„]bë«×„Ñ 8x=A2¼j–‹‡`ó¡4ÃäðÜ`ãž±6Zm.êÇ —Âõ!¦˜¤Þ¥J¶~…1 *Ëšy»SÞí–:œ;xÏøLa Ú\¨ïð¥äF+¡¦_±uÿüÛÍn/Bºe)ï€ÎUþÁ‘Jzqóæ‘ϤŽé{ÓR¦-A5àæ’RŽ1ð›SÀÀ]¾û“—0šwÛÃLt†õqÇVÔMÊSª!@eJÒ‘³©L×}ƒz,ɘ’d5*Þ ~Ç¥âÛ§af.Q‘C~è¶!1ëE•ã*;^ÒOu¾#ƒ¹s]›€ðõä›yx)C°L´®~AïLíâÈž*£ƒÎB² zEñ9`U1zO7:½ØìT¶ nÜ/çÇ(é;mtzèE{L™‰I5¸AÇ5ü0ˆ÷„<±ÈØ·BS.[º‰ä‰Š]•N‰ùúŽnîávJ¥$SºKã€j5€÷ÄB)ÕùÙ¶´—Hù&±Q!‡QHsš£‡d¾NÓ¬”–²|µ´h,»õÓYÝü˜}XÄo\Jòp“}ÃìwpNW-mšŽ{ú•›î”æˆaÉìp§ ˜Xè“ÚúеÝ^ú¥K-ÈŠ~/“šôA*ÆŠõ©;xbš+ë{¢ /¢é– £š,O§Ã¦&e˜ùeН÷¦¦fuɰɻb®¸ª'u’«×~ñÒ/þ,‰–~þÐùGÒ÷öÈðŽò¼‘a['¬“¶´¤×¼aô– m3J=,,¢v‚ãM•¬JDÄàï=Nl¬u¬l»Á–Ï쉱µ_ŠäGÎYUÁá$¿Ö¿,®f z|lôx±µ‡{õèO£Ð™’Z*Ç“ÅÛÄJõKsl:WbÂÚ%P4$æ+® g5òµW -i©HWª×•îu¥z©BÔAÃéëýÏ•Kª\¢Íî-¿‹ø³r…ͼGpfm–úé6(Mä6Û›_.¡ 7ÿåý˜T÷ Œ°ŒÐqÐ×½‡ù¯FÌ4Ô{«}ª­Ïf#¨oáÜÒ©ä#åz‡*_¼¦Nö*įn<À»^¯6È}ü ûámmøîIpuO÷û‚ê&ýpa¨qo{‹\t:¬ÏfËGôÚfûî¶ ÷ÁM]ëN^M·’’’¬V.ˆèe›Î·-Y õ4ßÿ©à#§Êý? éõb£Wfdöª´Œ\ú óma­9²ú±{¼F~K.™¡£¯ôʆŒ‚S9&IAR†²ëËÍÀl{>¯¿Ç ¯n]wf·ì g¾ƒk.é;1Ô¶ÜfwÛ]2–Gû½Ç"V ý3JŒDf‰R{ô“è Ï´ñƒÈ -• Ê1üŒê•ݘûŽ8ë$JÕ\L ÷ÎÄòÙ—·V²•ñSñ˜¹6dDŒì8×Ó›´v…†ÊQH‡f‡½ ›¡>Ýnµ2zýäüðý3÷›o®¿ÿæÛï¾sÝ?Ž¿½z~5~öý7_ûÿûfô­û|ôÝ÷~pÿô ¯Æßýéê{ÔÊŒ¾þãÇhÐón•¢ÏáTyrtà©5ïÚ»D@+ÿx½t†Xß“éêd´œèƒ +x}nwïé!­ï]ÕE½¡B—ýýo_|õÕÛ·°8'‹+†îî«g_ýýWì–Á®_ÑùjA×P¶ Pƒ«¶ µÀJ †á>6%V6U‘ꪊwUŽ#Hù¹T5?X#¹"eøá™Ê‰/9Ž@>dF)xÿ³­ý^XýàWqíx:÷RwÃÀuÄÒWe”Œù·eKË×[­‡0ŠUéCæ½UÉ®R1œweëEŽþ›ŽÂˆú•á%#è'IΫÝîÝCR·;£û„.圑‚ã!uÎPÓ¢°y`ÆFÚ~·U_P}FHˆ,#}1¦†%É„2fÖ¦Ò­ÀÇŒÚ+öy3gİU퇧“À¦Çïe³­´s Ñ«bÕ”‰(cQ ÎÄOïçLT »A‚F3 6 àŽk9ËT¿Ú¥T ª)®ÐgªL¥à÷BÉÁ”¾èåéGîo’ÔuÅͦšúqCŠΞ„“ÕªáÍy6uà¼ÎèËxºº> g(QïëÍŠ¶Û™Ä]G„Öýž75|´…®‡À/ë.‡0!;Sñ©Ø hŸŠ–¬3—YAÕŠUÓÓÇ¢æ0‹ÌxªÝ2ªvUÚÙä¼ãñ'R„Z ®G2@¯“ …­Ðöè’R”Ù‚Ovžž‚þ<2÷ƒ°ÏqÙnBX~ÿËÍ… úq€Ýßì™smÈ8*¹p|ìèBÉÿ*+Ì)½¢¨ë®”²q,x¯9ÇNVq0½i6t,âü§NÇy…èÔ$ˆzĪ'f•9Iž$4ñ† |ç‰?¦ßÄ> &!æP¯,Mֻ뜨}N‰‘U0¥-”"*† ²­Oɇ2õЪDݹ•ˆ|åîæ³CÓ7ÿÂ×ã+ªcLU1´('ü«.ð…ÎëN[0&£û«¡Yil©xüz‚ô-T™Ä ã#Ûk{£=1QR@ÒÛÓTx­eTé¡€·LÝ,$3}GHæ+®Ðó×é®0¥G3ß›ÊKÌq—BwÑp¹÷·ä€f=X[+TÓdd‘ûirá©–üƒ3LXÕß¿'æ%Ðõ8ÜÆbrñùý¯0Æ[.;|O&¦g}Á zUãN„‘I ï$–X›–¦s}ÅjpJxEíTNí*i#=['ýPHß: ˆ>C1 Ú2¢wãžÙ ›M¤šS*ü¼Ç¾RT%­‡¾oÛ¿4†ï»,CËI±vZágQK$cÅòÈîÒº·µ5Ž»"™eEÊ™–™¸¶‘G¹²}¾ +0”î%Ø«K7›éqJ!)s*~ ƒªYà84HZ”“âúSÛcu 13³–Pkmê…Ò?QWùm7ú<žzïiý½}#§ÅF×§êFï뤓HÑâCY(5õt9M~8Rɘ†‹¸^º [cÐ d#ÅN# 7è%É¿´·D'RX'»[¦É³*:ŠõИ%^ÂS¥"Î4CÓ§2}©Ìû›$ÍNo6É.w°Hö¬¦ ©m.Õ¤’v>õ¡·|“×F[ÊñóUü¢Xa‡Àú×fxJ+À.ö¡™Íp4ÞG>vû¡iâ£K¼m(êÎ5ì±J4Ufv5t‚<ÆnÙ”]òäKØ=-òC{²4á ÏôT©¨ÉÐêßþ0Œ¨¾O9ô uŸl¾‹ ìÂFã'ïiSw=xOŸ¾š^ööFfì&IO Í¦u¾½u÷ßloRwÜßÞ¥¢î|á!—~Ç"ÞaQ`Xc»`¦<ð[³ŒzBÓë2¤­¶‰ÜLÞçé{Ã9k»ÿ6ü~«:ß³…ýœ³ÉÐMišÅWš– °1¯™Y÷MŒ¿Å³ÞK8 Q«0VÝ”Ž¹¨ ­Ò=$*Ê(·º¿¢ic§ýóS&;º'š ?N~CÆ1G&ƒþÚsøÀv,¶Úd·7$Mzl¼™¹ÀYV̳°éÃx¥™ pKÝÕù*”ÇÄ©%£Ô'`¶ù„o·ËBÛ/z³¢‚˜ Ó±•B"ÛC;d•Ö—£Ôèïã¢ÛT‘Î4â=™îª x¬Å !;éÓEa³yß%Ž9î@ù›±JÓ? BÐŽ~,È“x2‹4L)c·î\­½‡ŒÄ±„ž þÁ@bl ~~RíIîˆ0o”ïXnû^Ĺâ;¸“‹V#¹žN”Ú¢¥Àiè·Y?ÛnªKО&[ìõ䚘@v˜HiR¸TÈâµïäm¶šú¿ùV:´;3àì¢|b>¾ž9Û¼ø/£å^ÆKDÚ80>Ìà¥¥ÐÆžéñh¾˜#Þ°ÌQyB/…,øæ ï^4,Fâ×Pñ…¿Ùþ¦ªKþ$Sàÿdò\îÕø¶ä¨ûéöÀZ¶š‘-ÊÑe™æ>ˆþGÛ¡+¸C’׈¹Ó§U hœ¦lÈŠ-½ÖâÈÌ¢ŸkLÒçbä$g6;Ý!^ôÜ-‘^ʆW ¬càaIaèEŸÝE€ŠÌ@ó¡ ¸‡7DNoFð@KI¯øð„C˜f˜/CR^Àœ»—ô‹qÇ[“6(&‹‹AsúÉ%øF'-æ“òA¯›]Õ'Ø\)‚—¹6Ür¼Ho‹/o?@HèÍ.:¸‡ PbÕ¢‘ -Ù2ˆÙßÔŒ”ÜhÌ‘ìv¼^þzâ@Oú°öL=j3´C> ª èSÖLÿƒ^ìà šÞ¹^Kq:YÄfSr©I{V†Êf(ÙîÒ*EŸl‡Ê’__ÙÞíÂwë\ÚG³Ý˜‡íb„‚Ž6Ž(BÎQ%î\µ«Zñn“‹ŒRÚ£›ÏÉ€°·AÑ‚;µ}xí`îøõrtƒZóÈjºš‘%óT(˜¸uˆÄ½+ø¼“W:ÔÁýþŸW×e´÷²o ¶ÈYûyûÛS\ç ¼üß7éÎ /EÍŒu­•òÍ9±?ˆ®Iï¦ RYöoéCLRjf~ŠAÕShçW²-—k Ê?voG¿€à] qú±k€SJBsÁ -Ê5‡€Õ ¸½„Þ$HPoiàOBh%£g+äÍžI­Bšk†ï©üæŸòV0¯¨m 0ÿ§ÝC·´ç®…±µg¡â˜-Í,EŧænízME,úeõˆÙ^‹6ùãMC±á÷ƒ§`ÆLñ¬–HâYAØ<_÷yÎú° —Ó«5â ª’·3^Ü?¤{¹ž¸+¹ÝR«ÜB@Ž1_n¨G…}çÈuPØõöhK±~¿ö96h{[YŒÝ§†š‡ê¤Æ®O©ñ¢Z|Ϥ{w|%¥ÜaK¹ÞXÛ»n uÏ—1³—c¤Ã@+êM©ãùVQeû59´üoó$è'h7çZÍwl@c<Æ4,ȉ"eÞ¢óª¥; ÷k0f¯ ȘÜj1ÒšqITíÑÃñCZ¥šFGk×Ä"jÇ\æçè£nxíY IŒiNW9|,-˜#Ô˜‘Š µß©Û¡îhݳLÿd¬'È͆1* D¹Ô”ËᢸÁ©<{ü>>æYªùŽ5ið&7êÖíržˆîôqÀ/Øný(àóD–¤±ŸzN¶wW‹+VBhZ±ÒíS6é‚1XLIÀ,çØ½•†‹ qƒj~üv»{ŒÙ-E¿½oò~04‹‡á‘Òܨ’¸j.í´bÜmv“ZBÜðh$«ñúz€Þ4'œ7óÅø ˆ¢q]pH§¿zˆÉß„’¥«BA?ÿlpLï¿ãÜ®ÝGð/åxÚ™ô‹)犼£çpJ'ýbÍ´&`h9@ý雲3æ»|±¥ó‹°Îì.ʲ ª/>{ïÅ~?N\Æõ(«~óÁK÷ÎXFÓ£»ÿ¾ßŸn³ZyU/̨äÞo·8yŸÜÿª Å*e¢Ö‘¼sÏ’•y{IGÛhÒÆOöJ*^—ì1ÁdÃI9¾°älÚxŠÎ†Õ0>õ8Cê'>iàÎþ)³çãjy\ÔB|-Ð úñ{ƒÓ±‡‘ayÀV~ht4Cü«ä›è ¯–3 ÅÉûÛð äã<Ê,ü&š\'¥°2ò8d=weTóë¹MHÈóºžA-þzÚùh‹CŸîð‡íÊ1aï`írÞþŸVh8…³>0 V‹*å³ÂA¡Ä;s…vAú“=ƒ@Úm„yl‚aÐJüỂ£q½ˆ ¸’;m^‘k×û/›Î°~ì´ÎÍ׈Y>&Ç™ø²¤3ó"d™luš•T¨-° Ü ±dÀó½!Ÿï‰[ …AÉ_«Œ+,{%Mð—Pƒ3ÉY˜×(Iãz´~G·/9›˜0‰‰{Íœ[Ö±@W*NXÆÒÁa ¤d=HèR–Sªt¦õvj^Íÿ¤6PßÖd¦ÏJ_«>ŸBy=¬ŽÔ³±z2՘⾠÷~u[ëXõ0ÔÝú±8ó3£ÉDwõÒS¼¡<¾"–pþhêƒÔ”¬{M ʺìÓQ¿&DUÅ'–B vJvGºÑã÷%x}V GãÙgÝsèt\ýkSžmœº5ÉøaDç0i´Q¯%40ˆÿº’¯acRY»Ð¨C2̆Ã2Ù;¶Ÿ(„Ž{­ÐÕ£0mEØÀäXÛ&ÂZÓðI(Vý´Ð´/ÉÀø QêdÆ ç».Û.AüÂÂïÜ.¼Uô†ì"1…cë9¡§¡~V"m5ÔRrêÑ•U#&a ]6…Ûœô2ÇW´¸C"åƒ.E¿ÿç½l›ƒ…œ¦3{dÙª¿æB›xÉDrÓb ytq1ÁéO0M¹Ø ©"“sßPàŒ|üuiö 5ß×ëÂ3è{ëy?¼å±•Ö0ô“×§vìÏ–^†ÿl0Д3+SÌylI/à‚ÎóN‹(Itþn ›¬JÚ3\S’èÿ­º©’ßMQ2hIn/æ7lW6+ÚsÚ$f±?%dƒ¶UÓÌ5ýR&S :Ö &{ç/¬×”_¾DÊø…ß/ÇCÜtæznH’d~r»ž¿)ù[µ>¨4š½=x¨"`žc×Q ˆqPn(‰lêÊÏ>•‘¸J’¾JŽaó~Œ8ûrÜW·SÔBòYâsâI. †2u³Ä€sRW'áÓðÍÎüâO?2K!LÞÁݦˆ,Ç`nD,.HøOÝëÁ:| %ò÷§’§~Ö1æâæPIMkÎ'‚}r;ZÞ“ˆDüï»"Ý$#2cI2(b‘32®àK¼Ákâø`„‰Ãì>½9™Èæ>âx‹z¯–„B¬¯ÈÿF꘥' h€§OŒ}ñš}‹&­{Wd„Ä36+µŽ ëbì©FÞ;RRÃw+2¬?Jf»Ò¶Ò‡*‰›3O Î蘖)#ˆCJ¤/ÅßM– íeU†ÏØŸŽo±êL®£å$ §šú¬× ;3½™Ãíqò±Â|1ÿÙ].†zìÑuBæ.=+î‰_^fµ\þ×ps*€¢ÿüŸ­OŠGèâÝÃÓí¬»ß)'AuÊK­Ø2YÒÏ[A9›Í r© (0O»ÁÕ-ñý !2q¯Ö7‘ëÑj4Ûy;ZÎЉû•mõ<ŽºÚ‚›±ìà%;ÏED=ñÃÒYãk§2-Ù©Lé’Ýà%*Éé¾ß`HÓöv›Å¤N(\…™B{©Sú(wRPšnFéB#£ƒ_§üŸ™o¬9áæüÊdBMâƒù±9NV¥¡f‡^ ²ã•Xe‹J>®nµ¾¡Ôµzìn¸³ÈØ—­²}ýC’‰ÛðQXû ¿=¥cß‘jÔ4Xr°ÚDëfsÉÑí%)Ò¦4yò½{ ú€sSI âoÉöÚIƒ²&áŠ)½‚ k²)¦ í0è3ÿOºw¿ï²5^³k`9ᯢë{I:ØÒ¸R‹AwÁo¬î“ßJÐiÁô5|¬]ÕÎ¥üË¹Ô iW½Í¦”3_@•ÊE¿¨®Hú¤4ôÄ'³ QV}S-ÇN¨º^µ«Úök“3ÊA£9_ñ6¤Ym«%êÐ'ŽÐÿ{†asù`jd­=ÕŽˆ 86d“ _„" ¨ÄaTL©( 8G² áG(+ž"çØIGGT¤?¤"åø1Œì']ü¨ŠŒc†U(h8-BÖjÝÝ¡—ôÊ=‚–Q/“-¤uÍo$£D5@x¬Ì†„aLï3>d:ÔR÷’Ê1žûÎ}ÎÍ&ú åü_FuD´ zñf/\†Ï¬ÉoãÐò_4ØVÕ¢ë4t»œ°d³ÍnX[)èÓ9è±4l’ŸXIŠ7`÷2c+Ñ›”ýà³­f»_ŒØ^ËßËœ:¤˜×z¨_îf€×_ ¹£á°UC7R7Û¨gŽ oq ³µ£Š't9 7^[¾Â£ìàU ñ_K3 ©@¥“;ÚÆ1® œàcù“¿qGœÕbòWëf:GA1÷8gFŒI/&Ž×˜1R}ìuºSh‚´T(yé£pÇDÝþØö‹ D$ä•Ú8SN0®T{⪔µ«qçZ\˜íx‘кû¸*ä4‰-kW“Sm@F™F™Þ¬,Ø$V HY%çÄôªáÇJ¥. ´}†Ú9~Íú|¢¶_Öê›ýd—MOÒ€é­Úžk¹#ò‰5ºá}RbNA²äVÏñj6¸lOÓ"ÃñÖHÛ'v—–œí«‡Þw)_íÚÞ!rs„‚ˆ}l:ØJ.H¯£ÉÃ#ÍfxlPæÖ‡•¨¥tfZè{!ÃVJò2…°m¾}ÐÈÇ´¯4ކ¸"Ì#¶Üh#µÎ›øÄ40l6³ ¾ZÜ'´A:u_f‚ÙU°LÒ%ýnI“§zÐuü@TÀvæb¥_˜†%¢•ŹÌJef¾Ü—dë<¬9¶ì+÷j0ºin†z»?¼¿÷ »wŒ¤UoµŒÉñ±¦~÷þà¿ãQX¾É>¾ø×pöÍK6=ia*†tJ È6ñßÿŠÍÝèšµÙœýíÐá_zM¥BaáùŸž¡/ ïFàq)£ÃãM’Ѻë­&ÎdìÌpp sæKlðj ¿ÐzÙúøv¹\²ÒÄÑSFÛž2Úò”Ñö§ŒÂžýyzóóè&zÙ8qΆ±‹Ÿèoô².Uþ{5]á}¢—¤K2ÿ½ž¬®fÎe 3t‚ÐLçî[ú œÕ‡‹G—ðïþýÔ¸ ÊgëëkøBëYA²©ú”"vP}̳Çú/Ÿ]^ü”PIE.דá_×p¢&H‡ßГ<•K¯Ë —ê½Þ×q*5þ:dÒ {ªHgø…Á÷(cËÓžO-ñ†dW¯nÆp ¹f@˙鞽-iË%k§œh”Y'ݲ°™f‘™ÇHm·l³Êà@ù¤ÐúYtV;¸¼aà .ÐNzÒæ¿²ø^äÈÈì:£p¿¿ÚzÌ™LË&Êèm R}Œ£FgA”SIñòVöÛ(N¡tµ$?kqèú|««C°gÉr]dY+…»ÊÍœÈÓ›“ú½çÞJ˜äOˆ™îª›`H.ÏñD‰Š2C°q"å\Qœ¾ÀSÞஃv®º –+ú÷²¹‹–vÞ¯óÀyªè¾d)à\Žfnß…1Å'ÿ‰B‰;l1z­ —±›’äïetI÷I Èâ æåˆ«jÌñî@ä¹òŸ”£#ÿ_åKrÔOOc¨Ò¯Gj™½èPS‚åÙ¸·5[ìžÊ“@SÀä—ûÑ[9û^†Õ÷Ýëár ?†º “ùñá>ò|o8Œy_̃DÎiÀ{B/ï&pH"Äû¢òëNû\ü!âäK „¤¸•Bñ3£<åŸýɼd0ÅH¥Õb¾lÅü‹Ÿ¤‚‚n É.Ü ðÇh§IŒ²¥ÇaX‹Š|ú¾ËU'J¼\£ù¨jĪ?ÌGwÓ1ý„CŸ,žÁFlG ÁE¿qæJûBX%Ãͳ>& ïi°Ó‹N¹)ýpǧ=5¹@iŸCˆïFh«9„è›ÚøïþéÀ~óª¤ïѺkcWú É»é|ÍEü¦&Rìˆ\G“H†Ë’Xª@Va²¡(‡dNE,²Nª‰Ñ‰ ›ØlÏZ4æðí{Ž­¥9Ë<[^«·c%…y‡¶]ZmßYQ|—dKy&+ñÞtPVÜhÐOY‹[¦»²Ýyƒþd‹ó²4mõaV¬¯‘’,Àú¨&ŒW ´=1ò•…4?¶Ó™Zk&"¿‘³·Æ#K©æÍwTzjës«ùågú‰8·îhqp>Åœywî i))˜Ü°kÖ¯ÑOŸËǤrÙA¹õÑýâ>¶žSàU„þG>Ìâw£7.Œœ4%,O– ÏcåvÐÆÕ«ñ,6›v–ÞÌ‹¯—‚Œ‚ ê=¶i* SQ«“ñMª'“¾7Ã.Èvb– ´É§ñbUÙÕw ˜akVD,ôÚ%Â3è7Ù¿Øžrq³3¥Âü QnÜå±ÍS¿P•óÝæTÈîZ§`œJR¯V3†u¹—½ÇHÖ‰Ò)çÐåýΨs³>73+D‚Ñ÷¼ZÛ-QÏ™-`#f[ò”à-ì4a1 à)Á÷[dz;ÜÖçî,mV"TI¡<§Ì?Ͼ_’‰x˸üüE „<$À)oÑšó z2DÜ#ã ¹8‘§ú‰õÊüzö÷£ì€"‘«( Ò>ŠæÅ2»»‘ÎKâuላ>Bƒ"EÈž›Êî-猭L`qåmÒ g.²;j‰³Fƪm<tb{²«‹9jßÁ8)8A‡pxõŒfR…lœqàt.a¹¿ëŒÆaE€Ÿ”DÂM©©ÛôÛ|Ò˳óAú¡¨+ìwÓR„â|H¢b_ãS}8]/ÆI"^ËßKùûsŠÿr4>—û*‰V ~¨ÿœæ:ç¥5+ª…Ä$WZÞóFônŠÂ$EV#¿§ —y±×NT*hª¦ÔöÏ‘œ]"¡Â\°./8ÁÛEù˜%22ÁìaiÇŠßmïwb¥+9ü“8l“.]~¬öQ}‹bRê“¿ÃIƒß?<άƒºÉ¤!…„ZæÝ N.Ú‰ØÍº’Êœßuôî/ü2®K €Øj)t& ÃFðvÑ@´ö°& ÜÌK2O]C)¦Ü†;BÞŽàÈöÂÞ›Z*¶­J¶€·ƒóHF.Äóv7 7**Ç2,W—„¤4˜/åPÿß„@—ºì*c æšÅ…𓌷Á>yx o1ûåŸÈ-ìÃÃ݉ä¯lz2ø¿³ØÞÿüO¶”LÃxì?Þ*âEiô?R¬i’ùVÄì•fÕ—ÆâHË-ƒËÁ×ÔñMq¬!s”rU•±QÁ”b̲bþ€>bÞ °Ì'ŒYP…MÎ) âŽsTü²ßíZÆ{«ôŸb× iy<öi*êxÕ(fû.àNKN¢½¸³=j‹†è%z?°Wš*&ˇþt,ü9ŒÑ±²³ÍYY‡ãø”VÚ¡LÅa:„ë¿gLfÑÜÊ4‰ŸL—j¾ÜßT멦²ÿ+ü0¡(Á›qÄB&õ”‚[D¦ÅŠHxÖé)jÃHúÁ™›†›¢þrü%ýèŽÝmaY¦Ò}ÐfW_MW·=•–Dâbœø%ǵ¡J(#uÝ[n¬sèPJ‰F ¯œûøº‰ƒñªÆ%?CæQž„|o£9e°»USÁì“aɺÅeF™‹,s õÒ)A^¶‰êoÚ6è¢Lì–´S…OFÃÚÁúÑv‡Jøz‹å$2ÆrÃZ”]›°Ž§Ëol<ÂÀ ¤6¢€ÑÆôfºò ºdŒ2%e†Uæ!Òòd¸#ç_¾Œõtu6ì´±[FH[‘Cÿjk£¼¬c…ÇÅ`öQózxƒ Ks¯åVÏÇžÀem࿃²Å*ŸÛǿś *hñ›È=£¢Ö8•‹ñ1d޼P(/¹óÍ{®ªœrÄ i†5؆JÚžÃíd$lÍüz±ØiŒ¦Â˜¼yœ2Šø7)9u!Yg°¼ ý¹{Ë•¤r÷;%pc"õWÅôË!†Çøãmž;ºŠ,”’ÆYˆÄ¾X :_ß‘ºªè(ÅŸ–Y"sôÝ*lФf±Q‡2¢eøÈ.i³²ƒÁØÔ£ó3'9@#‘Õ™ìXò'¤uÔêòäÙwÄ…vm¥´Û@ÍÏ$Öi•l:g«ôi|Š™„Øaß'´pðʸ“äÉYýüeÓiž7üÍù$-Dú~)&pÙÅ©>Rœˆ¨Ž9é7í7ʱBöNºçÃæùÐÙèZ3и"srÑÀܸè5p¢Àu‡_‰Box(#pËf?Bb_ŠÊÎi¿Þi–®g.û[4µÚZÚif%] ,šl¾Vs:ájlÑÓvóµóªuÃçÔO†­Ÿ ¹ˆ7}eÁñTÍ~¦êYö{ú^';g­Fs§Õh7w¦ä1q-©Q d>ýÓ©©×ï¾ÄÏ•–Ü*d˜¥ت·[?7c­óŸ ÐˆÉš‰IäH¾Ó<¿°¾6òÕþ×Nw.†Í†ŒeêÅxÌÚyý§ÖËúP-Hµ+óÑ/Ó›…ÿö=¦ì=€úù˲ÝyµùMå¼ù Øj7cþ–æ.tš±*ðÎþOÌÜ/]ßq4 møJðÝsjähŒ›Ù3Ox80×—U£Ÿ-¡Æh&}³ŸÓó…ód¹Óý© z0]“ü‡Ö›,q}‘דi}äÍvó„ç8qNC3ð8ï κ¯*ŒÉ%ŠcÕà)¦u¸>®pUQ€zØcç¤ÝêíŒgÓûÈà¤Þ†Õatäz¥úé)|VX9°0{Íþ°Õä pN.æû²P=Ï—©£ÐMY&Å—}Xf¸76Z°t0ê šÝÝ-æ|³(ȃð}cøÄÝW¡”­Ÿ_2b™Óé6šFó‡üi«?ÄÈ5ÆJåÚu‹š:ïØN»ín¿„ô² >0ZgiU5¯1¥ äTÂ%iÉâŽæ Ï`¯9ë¶…ÑÌvwö’ìªHÙ¿”šŒq^¥Ñ<­_´‡ò.VÍ¡yR„¹ÔœÕ”¹ÄR§þÚñÉÃ>|ŠB«áœãš4{õ>nKü¡Lžm>ùå^ÄßFà m5’·¬ÃȃÁI¿ÛnGs¥ §Q¿‘¹«!Dܕ۟^ž8a-°—Ö™üà1ÖÖ¯¼Å ¶b ”$\¦/é>00†¦ñh–éȧú•Ö­*cžÀ£X‡¡2f _1ûÅÝÚœšz˜%€æ^Óa®¿ƒö§ldAþuµPPcwªò¢‡þÖ“#S¯3ç'll‡ß"°¼0Ë•®'[Ã&lNpü˜˜’ûùtü& …{qyXO}ùgf”Ç»ÈGÏc&1j™?–>kÒ!08kSh#„s­~IÙî àlI7Zƒ^»~é´[ƒaÔ¡u!ð»¸R~Eh5íàâ‰É§ŽÁ®ß®Ÿ4c‚モN­ÙˆKk#.Í“”P`aÚ ªž‹ÇMØ¡›Ž±^óõSäOü¥š2ÄÃ"œnu{ó©j¨’ÅxŠi„»57ìvÛΰÕcV«™QQú4ÏÒº6ö¤4Á®žÑtäRR†ß•߂ǖjAp¥¬Õrž6šæFž0º —ªZåf}pчõªÕžío;­snªm45[/φ¡—p[A·Õ_ó]Š&…;Âè^àÎÛWGvýä¬é\œšÃein·äæ 3Ý+»!‘éûlõ<Ö¸SâM‹›‚«†´k ¥± ;T4YÀ–;ñÙbñ&y=zÃæù×~ñ21|ÕlÒi_‰)2Å$ú>I"Ò×I3YØî•oÈLöÍ `¼.;ƒØð²Ûq#ðž}÷ýo2b☬åß#ýãÙbüŽô3ÕË!©/®Üd“NVb¯\…Ñâ`ØíÉ0atoZ“‘ëRtxíŒ40W&£É–ÕÄ?IšÄ8 »H>µs1kPêBð,µ¼¹ÊÅeï/®¼(Òª€Î˜fš].$›–ëˆ]¦k;õ‹a÷p^Ñ¿^4/šè£…j’Áõ· •‚JRÐb¤5pž7rç ç´]9pXŒlö­v÷<Óè×_úr)ư*Þ>AM ˜hñ‰„®&‰D’ui$ns?”«©fì`,†>‘Pu—ÒB¦Ki—ðT®OξÇOpëGÀ÷íÀYÖÞï>Kœ¶Úm§WÙ$?Ñì1é]Á[zê¿ ;°¦¸vÿ8RÌ_Šq!í [qgFÀbÈi" Yá6—óè”1„§À_­oø-è*Á¥äJ‚€Z0T­Ù̽áGÄP4)°²U3Ķ?Ê ÍyŠ;úoU /Ûxù"qãS;Õ*ˆ/†µƒs27c|Šö&%à­´?$4_†ÝHqš'wÀ©·`㥕W½c8ùÀ5„ÞíÎ÷îc(à˜|X{ Üæïµ‡ýGýaûÑr5ÃØ”ÉW„ߥ‹) &É*éáƒI:©÷É9O"&ÖÎO­A}ç§©7ÊÇßoÔá¨{Mê|f”ÛÍ~”YàÚOQ^Â$†(›#@j£Ì&Ô”.Ïéu{À:c{ë`¨ƒPéø{ÌN¸-<1‚÷¤»y鞯5 \hݚ쾆æ{ë¸ .by¨%4Z²›ýq¿Õ@%IOêwX†Ò¹(*E|éWð²Ô£„àðÁ-@½qxHæí¼¡„GiîÓ‡½¢¶%r³ª‘ÕåÁ¯eZÏv!·zWÍW¿™8»g^Çúª{2O²!§~|£ÞVzb¹‡ÇÍ–"ªýíÉã€a= *,wzuü°îø‘q/’DÔÒ4õ€î«“àÌŒþýŒ°«ܼA§*²Îª{ÖŽ‘­áW†OÛ«Õ­f{„i0ùKàB?!õ³\uˆ® øruL÷q8h_'¹¿yîÿ–B•cF†!üª°C•Ø»ÑíÔA½d¤ÛD½QÏ©%ø>yÇ3Daç³¢&1˰oªš±jy±¥jé>œrÀët_LÜîžÔÛ¤ #içðwŸÿÿõÅŸ_üí7ÿûÿqôýòôÓÿó·¿ÿŸÿ÷ÿûÿ|õ¿}V3®S/=½è¿äªŒúE”A:/ú­^}2Á#·Äb ðup2É k—_t¾h|Qÿ¢ùÅÙùâÇ/Ú_œ1øâ¯9rþ@ -«dkÈ[0ŽH:½¥N|ŽzÝú|r®ti9­UãÞ{ð9/€É¾ÃÕ,(§ÜReu]¯ßêÔû—N¤“ 8?DÏÞ|=D“@CÓi±oœô[½¡TúÍ—p¾f¹òS½ßªŸyã¨Ædõ“p³dJY`ýäµÖRÇøæð(úë_‚tý±:¼øaHÄwràÄ’—)Hw\i<Ü Pw¾báÈ[äøS­Öõsµæ n-èlܸL¹€»íàèè r\ý¢40Í“íaJˤ·¾òVÓð ­4?L†^Ú–ÄdÓÈ-½YV6ÔLÒØC‰ )hÔ6°ö¨ õ‰$¥JÀ¾ÊTVSXÝ’_˜œ/&®”þÌx¶˜³áØ‚£Á‡ä•‹£ºõÐV7%ö>¿ã®FhŠÌpÀO‰lUw8óûd—丣ªsŠ>‡±Á°ß¹0&ŽÄ ˜e°1w_'¨m [oB¬•Fœ4Ì0;ÓŠÂÓ 5f¶ ÷þJ¨If…k#k;•æqªóµÌˆ•ä@1ie–ôÄÊ/:œâfÞ¢GÝÓÓG‹ëë»ç.æU‹ÖgRylº¢ÊiT&:гh@T©~d|ö3 #Ç5¸ ?øl QBô¨ Fep 3&@=ˆÝ{ï¼ù²üò\}àQDâCãÑ~÷y^£q ´Ü'¸×È- —¨hqIgÉv‘úœcrãÅqŽÎÇ«Eÿ屪CqµbÓ”]O],Vɬ¢&nAщ‹»OŽLΠÛi¾:kö›Ù1.‹;÷í-œJÕF÷™ò@¯òd±¾¢P£oÙP¢éžE­F ö£ùè×!ÿCé'J9`Ót/VÊ]Üë>%_±¦iQØ5óªžö»1¬\œzÍ“Öi«Ùˆp6`ÈåÕìÞ…' ŸÅKwraÄï…4°¼‡HféÜì\²HF·Ñ»nšÄÝ´pÍAæñ[òDEÑGB³+aÄgi剂:ìÄ÷¸¯îç7;ø)v0qì¼ ›É`Ã,Ü0?¼è}¸¾ÏŠƒ&ßÐûA4÷Ë)ià|äìÈ쬇U«]ðÝéèØóýü gÉCž€0â¨È„Á+ Šï ›HÙã~MóÚ[lš«|Yñ-X—Ä`b7@*LñÒhN¬Ñ`t§¼9== Ü9w3ë܃}Îüfý\S»Ë‹9ø>DE…4Z£³«¦UpØä½ú“›Ä³M~£ ø—ÓšËK)Ã,lÌȈ¥ä¯ó­ó.?w¾Î¨ò3çkç›”Q+©r½M~"H…_X UŸažÐ‡»*{áÿ3Z‰Åˆ˜V¶¿½©b_& ¯ƒ0¢øT솵¡oK9¬a?ŒÈ«çh¬NÂ;õž«aèK«MÛpä`úðlƒ/*Àuyöyó=Ø3üq±Ly ˆ1­iq—6€ÕmFͺ¥ —`^>{ÚjÃÙÝ©÷È2ZqЩÎ]ÂqÎT‰š¤•rŸÎл)F =1Ü«U†'Ò•W¯lçY¹"}18Z,NบŒb „vÏÛ—ð÷¨;Ÿ=¤Xº#ZŠ»½ªFÊv‹¨^-+à@F’¿sÑoç*‘ß*';íeÞš‡ ô|ªŒÈènEzT?¿Lò–÷÷{÷&ãLFd<ò0ãOÙ¬èt@&1«ûS¾ŸŠUÓé€,j~¢@žqÁ‡Î;_Ýê{VíªFp¶É5¿j=, ' 6½{Ý=tI»µkJÞÌæ…²&f]¡_|;š½±Ð´¼ØtN9ÛÌô,P¨¨—A,IW†³Å¨2ˆ\ Xuç›ï¿¦¿Ï¾å¿ÏŸ}]B¡úùÀé¡{[Dæ €¦n4Q»íf¿~~ÒLñ#tÈ<š~‹Ùl´dN(¿žj°e¶¢Áó À¿ªӧ΄âSí=¦H 8îîU˜bÖoÇgØLíò]r±hÔè·~1Çí7}xð½çKÉñâRÿzìþ¡(\ á<jF?õA¾;3™ûå?×Psg«Qk‚YƒW‰ë©jÒЄ;ñëÌS<ƼÂePÒ«õpK+çR&‡ü†”É|Kר”?sBþ>o¤è:^¤JPB±ó‘þÔë+„^sæÎàCEOÈ,÷[T±xä·j§Û¸.õ´~2ìö/+þ±ö%BŸ6Ë«GØrÜå[žwE9‹ö·~ë5Û³\yÞàjÞwXaBaнèŸ4 G–ŒPøÂœU{Þ(:iâRѾ$*ëw5ØÀ·Ù '?odÔ%÷Æ=Ƀ§àÌm†µH³Ó^úΨ¯;m8Ç7…O¿Q³›ÚJϼǀ™ÆY©L‡!W]œ‹çíþÆeŒ" ‹å±\gy‡ëçÉ…&¦vY– Ñ%×x¨@zž»o§©¾Gè]›ì«Ó«WKDþ z>ï«ßØêoU“_ØêÛŽÕ‡›—øÙ \ä?©j £öD-ò:Ø»xÜï¾À ùý’~øhŒ²œjcmg½]¬g“cw0aØ !ãjl*NLŒ‡Rebž$J¡„ Ò.æZà¤Ý˜z«iˆV _,‡0&ÙŒéÓVPGFÞÜæ ¬¨j)î,ÝŸúøßàüWý¹Ùï:†{ˆÎóFÝðˆ·Ò( zÝ3Ÿÿø~é~ó50ÌÏž9?üÑ ´Væ `SÈmÓ㛹Zƒ„þ¬Á» מK­ \£`%áÞÊH5èVYÒ]ÌcÈñ¡ÒÜ¢zÃòí“ÉoX‘ësøàðvÅ©§ŠÀØ[iêgU´(ƒûdøÏ™Kk3é#þ ¢Ëd“ÿ;ÈÐP=Z› ¡û¾¨ê˳ãwz’c,âàÍtN39gTÅ5ß!t8"4ólƒ¨sÏÊÔÏ‘¢³%Ce5åP„ÆLdn=~ø+¾N¹Œƒ#ZœakØn×û%“ˆ@«˜4öŠjÞ¤¾ì·z«[÷â¼Q4)|TXNàTZ”:°2Cë2^üöÚè-] ¾i¯Û»è•ƒTt5µ~”¨¢jÖc}Ф7`sÅ¥aýÖ^ý¼iÿŒ³zà¥Ykw_Z¤ãn¿Ñì—íAë^ô0¾Â8å’¼ñÒ_bX^ €j½Ì°~ÜnîZ¯×m_tÎÙ-ÖºlL-nvÏ:Z#pÒl·-:¸YzÖl÷ŽÑŽÔ=¯‡ vñf?pù`X6>\÷bÏiÖBh}Ñ=FÂÅ"`›õRÚ’X²¿N½wÖ:©‡¼¯ÿÚžH°úõ.gU³}óäÇ:r÷]¦—íOÑ9îw_Ûs~ŽO-ðÛÈþ\—8íÓþؼ´p]0‡ ކLÍ^>HˆL½»ÊõaÀ~ªS`ãe»9(i|bI¦ˆËžõ2J°ŽKDb/|E;¸x%Ã%aòôr7¤ù]"Ú9Êð}@¨F¯…¢3ü!Ä»lã¯êýFLÒ•ÄÑ qtëb °ñxjÆXÖˆñÇÓ8ôÍSFÉÁ9£tZÚÃ@÷‹ãT€¼gˆµÅ2ÚiϺ”!*Fhßr$_„¢÷"#!Mݽs”Pšsr:êfóÅß&î/ûöËï¾üæo×è쎙†¼¿‰ Ûóió–ã?ß½ûÔüٸߗ#ïâ_¿‹çôçÁÛ)úðS¾SE†»FçkÔ@Ä×ð|ªwQö…‰ŽoGËúêÇóÍ7”Éð¤øDâð«a­O¿®qšÑù9"Ë6}péßžÚDËt£Ufïé´ƒþ.)B¥—ò"ÃV§ÙO‹™‘h–ÞŒÎpÞ|x=­næ&>ZÞ3Slé®Ö˹—@ˆ­kxä$J± ^Cµ´†/¡k&‹UÄ÷J06ÁE¿B«?…²v¯?ø*6¡0//9ÑŠ*eúä0L˜ä+±>\]t„GshNÿáFLj0ë¡WÁOcĉv“œÀ#‹ã (Û…Šs›‡¡KÁÓzðÐ}tçÝšˆ>/Z6„æGVã&ôç}±¥g¡†n¢ìíÙ—Yíì72ð²ÀëÚ€ˆöëÚm!¯Û6 +å‹÷4µLØ# IÐDRÀ©~VcLÉfÇ|l7Zñ»~þ‘-30çÀh0éjdC/zf¿mËΫð̽Í\æ9ÔpNgîDÜzT]½øñ­ídÕMÓ¶"!é ª”“Õ"¥hÅÑ2Œ:îNȹb&îQáèš(G«Å.¶/úÿÁnf˜GŽ•¶­Çïi{úÍ_þ£-»eîÓ­ÿèVæ’>ý1o5Ö¢}Îçj~3„íîˆ{]‹ÚþH£+ìè_ÖWcF9;º[{«#•^úhºúò¯ÿÑ++??óÕs8•ü ãíƒ4¸àÞÚs² &œlÍÕ Urn¾ 9õT·$bŠ-—C÷î>ÅS œB¨1r ¨ÎÁúÁ×qú Ý#p¨LWµ°×}úÇï³:ïtF«ÛG0l0Y˜l€ ±)ïú;xãÈ_3†HÆð´(yQ/ãx6 õŸÿLWš¾ôiá•bWë«+X|É1ºÚÎ(iÉ¿¹*tÐÜcáþñ¼IzúÍß|r¾8¢éq¤|y`9Â7>"¶æz4v>ûð³/[ÿæÑmÈZÃCÿÇПޟ™!‘ý nõYæÿºa®{4žyÞM#è±í}°L߯¯fSïÖ¼øê«¸BcHI(z¨Ð°YÀ+ßí'Þê²S{vÐ<¹è·†—\=`ñ¶íCÀOÜ&åÌÄHÈ;¶ôpðê—ãÓ†Ò‡Ÿóˆ{kBæû$e¢þçÿúàèãåÏ-;9 пËÕ¶:¯;mfÂþ½}ÍǸü³¶ÄöKά>ýþëj2ÐÓ¯ 'ðËÐYQ¯g³#`ª`îýØÙkä¨Î ÑÁ±¶nå= r 1kÀÆMÇnr íkÙÅ.)‡­¬·¾§ÈSA]ô;v¦„Qè)iúV}–õ2K‚!Ö.EMTô:ÿѡߓ9N Ý–À½‡‘$Zk~¿^Å(ñýÕßá/;ÆÜÑ òÁÂRiÄŽû´Iž°M2­¢±1~ô ß‹‚ö‡â+ØËoð§uï9æ5ù)üþT¤÷§¼ÔOQ±My,Rò´¹w>˜|Ðøà2F£Ñ½NÓëËHâC¥˜Â_)å )Δ” 5–“<¸XŒŽÉA裉9uÜY\ó—§þÄLúÀX©ŽON]úå¢ñÚ´|?_%¤øÚãÙÐþ×§ªÂPý³ŸìJ6÷þ²…pÇpËÌÒÌ¢›1gšºò9Ñ—F?u?¿»lG×`)»´øØš]Õ燺Ö?xñÁÓÏOЧ„6qÜ®ŽW|¤®?â Ž>Ë~Fg'¿äÑgt4ì«À¸“ €r§¸sçbdä„è}zAþŠöoÏçÅFéÕ¬ñðYÁ2^bŸO¿y´¼›î3ï+óUø{ ~ïÎè>Ê¥4ÿá ¹ÊïëóüÖ¦^I ‘z êm˜¸ËX˜ÎI¨à€GjúdtÏþ»°…'f£ù;“Avõß™Œâ`þçÖÿOÛ›€GR•{ãOWwuW/Y'“ —¨­ÀÆtgw˜é¤;“ž,’ÌÆ†^*IOz³«3“Ìýî÷°(AÑADpEEÅ P@@dQE¯€¸âqaù¿ï{NUWw2ÞçßO™ÎÙêÔ©ª³¼ëï ’—šÃÌ ×ЙÙÉPõ˜}H±€ J© L`°R*PgÖù=^<Ó¸ü‹„=q­à3`ª¹o°ÀSaÞ‰ôlBóeµCÚ­îå‘ÛÂ@0®ÈØŸŽ±Óç—ä P®bDLÇ£6’M*Å Ç}z‚<ó Ò0%ákëuCùІ¡7 —‰™Ü÷<h?t3NtãŒâ ª‚cÁ™¢è¢'ú%ÀNLyb^ñÀæ ¤¥Q;Rý[çñ\Œ×ª¾£Ós¹ ôà; ךÉh@ ð0Ù±yš|ƒ¢€‚q×¢¶‚½ðõŠTɵZK)eT[‰çb…¤ Í‚aƹé/¹üìxÈï”p•øK$ñÄþg¯ÙcÙ$ôçg7$ ¶€y-p¦iÕìç±ðöÜi˜GiŒÃ•üž—òÑ¢ó‰4Up©~^´ÜCÏ'r­I_LågrÓ\Àm\äjâÎ@b <˜ç¥BS·4™Äsl­qù»úº•à ¯Žhå™Tž;3Š™næ]8Ôˆ±0|Pîßý™ñ$•aÁgYKatà6)€ë8ÄÓüY/µ'rº3NÔÛ=q]B3A©ŸÀ³¤ç¹”Ó57²ÜRG1%]‚¨z/vÆ0ø3×KòhQòZÞ3“ÊçiÒPƒÝëu»a˜r–ûl¨Èû»º»Æ«ß¯J!²’Æ–uZ ½U€Â#†lu˲ŒFê—[øCg;jëŒ÷3˜Ë-fPÝÓþÿþOøß¡ÿÜ][÷@>p{ÐJÒÝIä÷ö )NÃÄÅH SÂ:FD –ÐD„fÚax1<ÚîâFêyÐc(  |×…p*.ÝÀ-p xin ÄhSÚÉm7œ¸psI…×hI‰µ .hüû¦µŒ?‘¿ÃɱeÝh©L·vêš¶è*yDý,&ŒçsÄÏØÖ“¥NœòÂ2¾KaGFÝ*ŒÝ¾êõ…³e1·O©ˆ¹]‡À)ëÙ°†Ò¿ ›¨êH#Òú”¨NW­¦z1:ºâ押¿·ÃÉñŒê`]ÊÜ—™ÂUßÖPÁ Y5/c\ Mf: –þ@GÇH•›» m˜pì®Éòµ<`žÕ0Ô»°’_@¶Ö˳T°I¾ñè—úûú¹Y'oî‹q KºÌÞÑÑá>¬rd$q‚¾v'«m27TYNOïŠV;{£{ÆÇ8^N„ÚLDÊuoÐW}¬L 7RÎCŠ#j¨»(Ê0«;”Žb{P¤gµ™: Ð6·:>&ÎýyOÙmî?õ¥¤?Øßé„=îŠfÄdÁ ¦]°3§µXÖwžŽ†ów4¢Ó%i(†]DGFÃxòLjt#¾O‘ƒ’3é%}²íEåHŠCùn«þ©`š–ž¦©,çïìë­–S¶ê´ª¥TΜÞ=Ì窽ê&…ÁbVeå¬öi50“ÃÊ ¡%©…y/ùèVk₽„$8ß Š)ÅWf>SíË{i]+§¿£YÄiåèÓ3>Έ#ãæ‰;gœ¨ÈÛ9éÔ Ö¯ÎÊ2ü¿º²\#7©.EYór8a2¾Pt„£M,ßaÕßF ¼ÕÉt,[¦ô’Åôΰ+›ãº72 Hæ`–qKøR!ëÖ JÆ­çæŠ¤‰ñ¤—€A£·Î")b o Xùlð¶ŸMr2HZJyõÒ”c)1-Ó¯iÔýŒkh(£K»8c:êoÐ_-¯Â¶O:cŸaílgÔ¡:ˆRÀD+sÿ€ëwˆô4¡Àò¡Ÿ& i}F„- ûQ b“:k©ÈÓûqs±\$]Ü€ ·È § œ\­Ã2Ó÷›•å&–2F°»–.6`%”ËܽšV¦KðJf‰(¨Gžö).dÛSžÝ+FsÒg¾8Î܃øêÑÞÂÉQ¢|¨6¢`Ö•õá\&ã ç G>ÈgxLd± u×PF]Ÿ05EäVÈCãDˆªÐ”LAšË¸P$=ü»BIJ™ì¦$~7WüæÓ¢¿U=%gà8\Äð•h=§¢ÛŒz$ì?ù‡ÉàÉ‚U®•!w”͘!äëÑŠ©”mà¡Î‘P%a9ê;–ª9÷Ý\Ìä+LÆ[ËÛ>šM°Ü ÃNY_àæè¥¶"È,LNÕÒºÂz´±¸PÈÚ‘Ýi8ô;p³©§§2Ëœ” ð?AÅæª-]ƒÏ“¤t›¨7òºR§ô /”ñ=’Òñîïp£xŸ›ùÅшê3@>¡U)/lY^9˜*êÒB‡´”:¥….i¡[Zè‘z B„§1ÈUÊ©T2:·±*‡Šî:s<þîÎþ<'KW¹Ñâ5dÉê{j±°;êþ7¯¡ãYEÏ4 ,ïxCEÖj?Ò-pNò¸ñä•2#Lvx„–‘X:'BsŸà®Þ>ÎÛ™Ì)çúˆªÛ@IŠž†zç[0‡9 iÒíÅB{<Ý/HÙÂp R+iÓ4j[ÕÝpžÍèg¤ÚyÌC]Š ™¨ê/AÇ…–Êr0ØáC?ù!aYwO°3Ã4¯Ð§Ï\‚Фž¢5Ì5‹]=®´ò¬¿ËæÿtvòOô•9MK¢ÕÁÎ*í%f`Öœ2¸µ´ ƒT?ÃE@fcŠ[!Ï„”l<µLwA¨ì NãQ\yîÍÿâ*°£»ƒ[—ÂR{bÈŽÐ5"ÞXÒ°Û—ça³‰érêq4¨·ë™¼L·'"Õ~<žU]¾Ôm4)Ó¥núE‚¯RKy‹,Í0ÂGÆGý ½¹mø[ˆC ‚5±^âܪÏZØdÍÐ l´– ¦— hK^eHë«kY3¤»…Ö6ba'Ñó-·²oÝö§É’Õœ0˜®¡oœÈFÏ8ËK…B£µÀßÕ×#iÉú¬¡ž¦«Ú¬WË*ñ$rù¡˜/h„I~pž¤5Ä…Zô±yôB)ÌqRs釿ȃ³”h„”o#ìd¸q"í¾Ñ¢ùJ*V0~è<Ì·cx`ÄgÌÀ‹‚Dc)8vÍÊ!ò„­Ñ°ýö ›àíµûe]5 …¦#щiŒw[=ˆ™@äW×ÄÎñÈTtÈ^\É7X¯ñ÷t:£kØÇ¡QÛ9Ë~g›‚ Š™PÔCQûH¸³ÑêWhv%ÍŤ¹¸¤Ç$=^-‰¸¦Tu«G1?YÒLÃT}—ÖÙÅ¥q)v}©Âìïvk„†˜,‹ÚJ3êö êñ„ý­¢ý@;n"üãævÏIíôö!¹á¤v¸7^…È0°ÕAYÓBLñSÛè@9Rý!Î. #‚“¿c¢úÇã-2 3Ÿ‡­U¤NŸÇŒ£;´½¶¯jZñ|ÇšÆi¯B-N4L<¸¿âÞp$x(áPÖwJªé$2Þ)b ÂÕÃØEM¥ÝxÕªN¾É‹­UðÂ;jR€Ã‹,ç­vœ²Îùt.Ko\]íﺲ9ŠÎäËæ ]´`:Ÿµn+tÌT¡¡=£¹X=J¹¿³§¯e•ml²*‰CÙ]²ôª.Åž­#yf$WAhyŒàkÃ㾤VÊÔA‹°ö#ê„ëoÜE5Ñð¸× z —´D®`ó¿¸)PwÁF2ˆƒ¾ Z» Iò2ü›ºEáøÉÕª4"JÚgBƒ¨íåº_Žý­ä–¸D|¤áÑt vDCX±Ã©<ò\⚃ ˜]×ÿëyþïdüáÉvü‘)éY—hÑzºµ'V´ÛÑÿ«ÆHFËeN1eÀH\AEƒµÀßÕ!¦9¶0«štaØk–¬œ$Çîªn»Zîfö¶qU‰¿'pŒj+íom?ã ™D°µ§²« ÖvTÍ‘–«+ Îtº&wÕµ=U]»´B‰’FdT¹ /Kk¤îöÏ+ñìÖ‰i«uCŽKxÚƒ?{eü :°Œ#éJ§â…XaÅÅÈíŽöÜ\»q•IBÕ¾næÏ§[°PÈQ‘÷wuwºŠ¹a´–wc¨†ý;vE¦žÚ9ã$®iÿ³M9ŒÍžRr¯4·ÉÍõ n(íKÜQ1 9<Âú0ëaÐC¸Ÿ0%ù]ë²¹ìÄR:-تáÃ=ÖâÏ?]¡­­7™}z{êšœÉËö­×ç™Fæ>…å“´­QŸ©£‘$n° /h1ò ö1V5ànëH>´’HcN!ŸiHlD…=œõÊŽ®ŒQ†ÍËšK™¥40¸e:w„$ч¡!Ë µXœL;„ÜÂî[…t¦¢ÚMÑ!àE³Ê€'“êÆC±T‘œÔª†Jç(Æ)c9Îy’È®&×$n±eøñWgèiæQAO›ä_õ¢p.Y!Ñ%š(—gýŽÀd­ü¬5$¢L†Â§T®P/Lµ¸n°³¡DwÑ+R×¾x®mµâH ìuÛ%£…”nÝ%+òþ®®þZpdÊ‚@5ôUÅ© í`±mrwo§—Ägü)@4r >HðÒ˺܉§yE=ð€Dbr {j)% dL]J#um‘ǹ¹x/”Ï;iÑG«_¸"(ßÁQ¿´ªÄßÝåÍ}è5¯ ߈:ÌLÎNlR¤…è{V@f’Ó “æ(rzÍ\Y­”0„€:ö`e*»„öHˆQB6Jz•¦Ó)n³¤Û³­LRGÇdí#AKîX%/ù’‡;ÊÙÐ,Ø4Э'c`3ë+æòf¦C£•ÚB‚²T½ •]Û‰-sëAlšy"D]EŽü¥ìWh•"¸ŠÑÀ2ÄÅñ´Q ZÄ[@>)•7˜Ya‹gæK5ü~îÁbÞ“[*Ф“[ä4Ï#ü"Êeé§F¨L-kiÝ=Úãxz€ %ñj ßðÌåÔÙIûf÷Íž1ûgý³gξcvöøÙfÿcö?gOœÝ2ûÎÍg½eëÛÞ~ÒÀ)ǽõßOÕÏprè¸rŸÅ“QW2©,±¹»Ö 1™,Üô…ò¹ yh!Ÿ Qd>—MVËøX¥ù!}%›À!Ná£o ÙîWgÞÏ‚k®;.æè¯‡‡,C†tcekM¥:—zØSym#)êŒa¨› ÔGeö|Bsrqd°ŸPѰpÂñ”nÄÑuó¥:G|À$Ê\ð/¹¸ S]iOÓà6K'µ7µ‹KÛ fm6׎²jýíTìá»c’HÕ]VÌÖIDø¡øéÞe„~ªñm:¹GŒ¤`YÁ\_‘1§“ÒšdC²tG™ÞººS°·CF Œ g¼jê^J%xïÍKÙ:® £°áßqÚ€¶kÈ¢»íšÎR§°ÂJo\TA¿è±]Ö—¹vèm)½4 ¨éc•¬7oKãAëcú;¤Õkz eÅfˆË£å†ÌŠÅjš+ÎÌ òÝVsÓ‹-{~úÁˆÕ=0 PÅIêKZ¼VªVá2_äŒõS– ]Õ¤aTé.7ŽDbö¼¹Ô¼ö¢Lu"¥£h@‰Ý5œûj¢&€?IÂ$Œ’&EqöWm™·­ÎŒ…‡2–Êg £Ià½R82rÀ¶[DohŒ pŠƒŠþÒf¶·†ÎCD›&PBiJŽQÒLÖpÍ»™9×à¡aQ‰àI§¯—$²Â!¯:V´vÈ‚·³f©¿»»ÃYЊ0ëÆÖ2tøáš-*Èh”=Öh 2FÔ§Dm„­,•Á^7ѤlZ–LÉŠÈ”MâÂߥcfcv) ¯¨“˜(Ìë]è¿6o:ï™à~9hvm«œI2¬ò\ý |ÀñTÖ£-'4-©Ç–7f×â XE©b³©t%qð»N[7FƒÇ@”ªaApXw k ^«cJ¬äÎÌU@@h<Ó‰DC,\#íFЇS{±$ +ìé\tb½¦vƒH`¬±z®–6€­½x rz±Y ¦ mx …Dœ%þÃá‚ÏÁ„¢€ÇßÑlÉQ[w¤Ñú¸Ì‡Sš^ž‰ÀË\±'ŠV ý`[%ËXà´5TŒ¶3;¿Ô¤SLÐ¥B¹ˆVÅMFdó)mvª‡K‰¾/¡Æ–Þh(õÜ=Ò| ƈp¹xÈÃq…ëxV"ÒÈÑ BY mœéVx±€Ôè3f„‚ èc1,¬3ðý*|$þ QÌU[©ƒU(› (ðŽéõvå@«p=sÃSˆ-³‰ fra´l¤À}M¤pä&ÜÙ+aø€±±‘õŠ^ýÁ`O³õ2Ήú¬E¾9n¨/e´¤# kµn Õ¢…çP,[œÉm+乩j§Žbl¼™àl±Á4Ö´éðti¼; ]M QçXÿ4èj…S¥˜£¡d,ÏíhÖ-JQhmlÛê=,ö÷ÄÛB§Q„]§‹ æQ!—JÚ£;¦í)„& ¹3±,§œ¾`ßp"»vÝ>6±GN§²KËöÓ&öŒVK‚#øþiÙ<‰Ê8†¶5Êü=]¾ŒQžÒt™YqeaJÇæ½šiǧ×éR2ëÓå\6½Òî@«'íº=ŸÓ=¤Ð#™;…Ø…¸mÛŽ·Ã;p`_ŽL*{²#[>̧ٞlou`˜Vo1·Íé0V ë ó5»nDó4Fø¢­Ç¤œ7e9 wu.Eé«Ga»1!`‡6&¹OSÊ„ÛiµÀ6ä¨]²­Þfi¨|§dÑèzõ‡p<®÷LŽ[æÖ¬l ðAêШ ÖvÛ•þÎ®Žæ² çüµUïqd kRºÏ±G)÷w÷õÕ%ìÿ¬¦ýp*ïIšòÚq<èc4±tã8âÔÛÆÕÁnOÚUGe;§y)Ï …x®ñ`…âã­‡+ư±¬µ² ¿ù* 3¸õƲá¥*ƒÈBYÕz\úBÕÒhÍø»;»}á;Ç"ûÉQ}¼j½œ8›Âû‡>LKÒÌ•àÔµÛú=}R"ÙHG[©FoY£ùþµc$•ݼuÍŠý§­SôômdÕ­W'NµÌýÌ´uæ+–À&‚Æz„ýwÆ2ùɨ"3ÈÍ—¤l[당 j%TœNÍgõ† ä¼S´6¼Ì£“|6ºÑ%=‡N|uW3iä(‹XO¢ ^®VÑ/Õbg*DyÁÄB N8ÕЭbg6Êmž<}Q)4iTßÕe?s` eÕcûûúVÅ]ŽìjY½"»Z+ðlh¦zd4¼Ð´ÇCêÄÇ]·npR0?kà­ÿºÚßÙÑ[ÄB$¥©U2\بSEhëŽÖÜßÙ×Ùºfåñu' ´óã¿}sû>I;8Yƒ5l+KBd\R“¿ñ¨5þ®`ÏX òµA`»t­P²ì«MâaZïmØmÔˆØ ¬RN%ÆlãªW à5“ˆ:3Ò~\£™5áÛŒáØëÎbÄlëÅ”hFiÑÂ…hs;ldŽyøñÄòù1þ”ˆôàÊdÁ00ôw´Â6JÌß0ìnèqÍ[5åÍ6â2¼‹L®¨¹ò<ð¹‡oÁªo¿½Ö°, ¯†]úR¼›×ëñhØCƒ-Åy¼XJ\ÇSû¹¢ÍÍ­«átsE˜´MxYĸ 54ue%uBlƒÎ°1¦cŬC+.¤`±¸#}:+…´£¸‹9Š©xÑ1_ÐóK Ž-^€ŒAãLÖq Ë:æµ\Á±¸Ÿl2æX„éærŽLz%ãȬ@LètPXrÀù¹à(Æ2н–^Â{¤ÙEhO§t|ú):`Ëžwè+…„Ÿ—1Iӥà Rñ”ÈJ ]J–’1)¹(%5IKKóIËJ|—’æ Ò‚&¥ÒÒÂ’”Ò¥TQ:“ä¥Åœ´X²i)—²9)Ÿ– 9©°$-$}QÒß%ÅÒ’~PÒ5©¸ -¤ü¢´ÿŤ¸&ÅW$jS’V”4MJ”ÒE)U¦¤ƒYiaEŠe¤ØaI[’2‹RlN:“cÒ¼&Í夅””ÊJ]ʬH‹‹Òâaió’~HZÔ¤¥ÃR±(å¡ñ’TŒIEMZ„Æ)“•æÓöÅÜ¢^‚¤¯HɃRæ ”ÍJzAJ¬Hóð‡¥LÑþ.è!ž“ŠYiyA:¼dÏê9»ž9ÿbðO‡Y)®Kñ˜‹K±‚„QãW¤8¼Å) CÎIsìs…‚4Â0ྥx:^ZZÌH阔ŽK鬔ÎI™y)³ eÒR&'ecR6)e5)»"å2RÞ˜.½kI*d¥Â!I‡ÌIº.éE©˜’Š0B]:¨I‡rÒJÊžÈkö¤‡ûêöyý}Ò@ÉØÇ·“Íi ä]𠹬å£ÅÅ´½˜Y°ó){ñ`Ú~8ŸwQZ€ñ.xÓ1Ô”ã\ÖNÏÂÂB` ÷ÿ¿ ÔlîR&[Fî(õ¸5R V§<< –‘<ÙÔ8ÝYh⬸IŸtÝh• V°¹mu6Ÿ4ûÒìºp_º‹ ­£.?Ý4rÕ®T–ð]ºF"d±µ13<±DBËS~[õA¸Eš¾-•þžŽîpÕì<ôV II§dè×)«¡_ªÖ™sš"…ƒµj#Ú®aŒ·ÁÖ ›iÛÖhçïìï>€xÅ&³‰o®¨™™Vk¦Ô¡¡ãßd…H¬…ÅX"OŠº<&j0ñ.¡×¡¨¹J[Ó?FІ@/,å«7êäâ Ž‡°?/ô¾ûÖWÁ?¸T(‰*•<Ô {_ÕaƸ]<²—ðox‘ñ•Dü>2 AUBSYs°«»©˜ãÑê QFËá 5á·…N Sùs®/˜Šê͆¶È!ú;@aéŽìR:í"„û$ró3…ɦWK…”nûéŒvÇån‡ΔŽSÕ°ÍÃî´àƒ½ ‘ (ãBCžs!ñwÐ=a LÔÄ›ÒæqøqÆ ½S&O™2õ5d<½¿C¸5z£‡£E-X 1HÝ0‡Õ#i7½Q†+c‚ì'à**v‰˜­JF+Æ’±b¬Íjù0PZ„vxr·y+S#FÏ¢$b0s)’-Ž“ P}F‡8jk‡:E*N%x´’|J~Å.7.ÀL“ùü‡ïP.WCÿšmqß–2Ig†G ¬‘^gqB«w/æ¶Ó[\ñaÚX£ ÖÍ"Úë |²:#CÏÖP\ÉçÄŠÆÏî5¢àÄ@147ZÀH 8r¤·1"¸OCG8¾4f£–uÌ£•žJCŽ4,<öƒƒšL—:W4TN¡mO.—udcWì@:óK…|ZsµXÚ5·”XÐS1Gì]K1Êl`Ö8+±¬­é ¦ð–Lä(Þ%%ùm}\6ÄãÂyIÏÎÓ>Hš.–õ¼ÂÈz±n‰£:êì)AÒ̆<Å„0ý‘ —PÑÜK19}Ùˆ1Œ¬‹Û·D}grH5´”–xÉÔ…!f`%‚œô¨5·ØCïôz¢ ëáê#–Os,Ð2$3¶V¡¿»»³¼TÎ5‘j ¥„(ÁC8©‰Ä 5SØòŒkÙ¥š‚L•âëU§ ^ËÐêúºÝôÖ!Báãxú%Ù”¤Õµkü]ud,Ù7” dy>ˆ LYÈ×¥t‹$É<Üþ”ðCÇú ÆÕ–VõF¿½‚!ÖQ¿îÑO€NÛ^ƒ ÁŠS‹òª°¦/ÂÚ¼¶ˆ(^¥'õw¾¥lÀe•íÜÛ_NÀ»[ôap#ŠHœt3<€î7"f$Ňƒ.æYGq³M$¨4=ô©^*Î{âÓJ§íÅùü òîpò ‚ð°ß4gie&cY@ô†$¶£ÑÖLé&BääEmxG3Ö"+§IÄAK‹s€•ó;E³1Û5­³;¨ {9Yl˜HÛG#{Ýô}Â;vOÔÏ•UÖ&àÚL«ô öB‘C+RÀ£²’2¤œÃç3sιT6¥/xÈc†Î”êa¡ 4úX%»È–ʰ£ã¥ÒƤ7àÕ1GÔȃA£ú•75Tä¢}-†>¬ChzÓ.\ ï`p ³ÿÁMÁîšprÅØÞprÍ¥(Teõ³•èTÆ9ñ†£Uø;ƒÝµ¹:ó¹Zf_Ìå¦1âqõÀXâS– Û!‰ñ×—Jš>žµhúxUÓÇK¤åCÒÊ‚ ¾#¾]¬Ø$r®Uî÷Ö—ÝeOyvoCù]÷Tä÷6UcϪ’½Í«F¶guÑ^à–÷ð4&÷Šgˆí‘b{kà«gQéš8eŽ3tQSYÎßÙhøØ¦î·Aa íùì¼#:žrDá™Fê(‹xw(Ø-*T ™È'ÅÐÏ6 :ÒÒÎcTtÉÿ ²®–É™($àO£õ¼µ’º¨%ŒèºZÒLçæŠc¤ 2v†]ëF< G>ì&“ÑšÊJüݽÝÃ5)ÔÆ_%i<ÑIßh-÷w÷uÖ‚Ëw»%ÔRYàï t¹éú)8{Õòè$Å£Œ ÷™ªpù…Ç…㟫ex]S*‹g`QËåòÛ–b…dR/––d ÍeyE~è×›zˆÂys2Gñn˃Ô {W©PšAAÕ ÊöZ}AJïÖMì&ŽÝk‘Ôy-!®}HœªµÈ©S¤ü¡É8lTÏp×GfÍוB,À;n4! Du#o\úÞu†O#YXÿKÙ¬O{¸6ë4cépìu2Új.¯ß©wÜÅÝŠQó™‰Èd¤ ÍåUþ`wßôz£êàò2ÖC©ívÜÎ1k_äïÞo0/áó³ÉRÅKœÙ¶q“_&¦äljlÝRw@êJÝRw—ÔÝmë’:á¿^GOG `ïìè€ø7ÿ:á_üë–:û ¯TÞ»Kܺ‰ä€:’‹âÖÆ 0N†˜Dô–’Áf‘F7ŒÔ2U^ŠäÀ ¼ÉÜFÇŽ=Ä“PÒ ;nžR€)¢ÜÙ¥ O½=±ú­­vsõ ML‡ ¯oh¦”Yåé:´†O+”Õb¾eXs G¸;Â0¢\R|Ìš¥p1š‚¨ôpF£0¸Erç Æb£Gä4"†ÖF]bx­…|†àJg1•¤‹Íš;‰ò€~0Ù¦r¹Œ¯ÈoÁCVˆ Sn0:Q‚¥DùÞ¿â^B$¿ö®—šcªL{‚1!áåïÂPE•þ®î^/W¶ÅâXõJ¶Õ^i­k:ªu¿ýP¬¥pW\ Ø^̵c'ø×0öl?Îw\{.ÛNVžíÇÙŽó×~<Ϥxø“X¶=Z!3g/äÙaZÙÃC{áßNø·Ë±Ý8–áG-;†Ë>Þ)Ï%‹ñ´rŒÌÐOhÈÙ1èôÖ 9Mw†wîÍ8©¹9ŒœÕ=PÌLd ¼$8¢† }|vÌÍ¡î©zñ'€?=øÓ?øÓ%cEývÒo€~ƒÒá€t¸[: ‰.ép§ý0°”‡N¸¼jÍQ§S(+²(«³ü¯ž”dŒûUy2c‡’^Jòé'å3¯‘€DwRž/Óm#¶í¶QÛ˜mÂ6m;Íq¸Åäú![‚TÒ|ÓÑ«üÁΠOtDìA¨zß]ƒ¼oý¬Ï8ŠŒ5ÝeÀ“šh“¶•C„–0'õÒ¬“æpZ+Ös¸Ìâj£åžéMT³Š¼ °ÓHÂþå<~µsÔ a>T5$ºf}T->bS:+!d †PÕî2ƒäâ$™ØóZ* üÁŽ~™Ú¢qšƒ¢%zÒåµä™ë&kS=MF6dņ$®ìý}…’ ~À𠳿µþÎÞn¹˜ËO¶pØ¢™Üðx‰'ôÆKGÍ@ƒ—ÁÄù;…«^˽|·LرzxJ¡ê¡B¯]ÎW+q4Ô·Œ¨I7yÑ¢ã‚튒âúºaµˆœq­¢Io¾Ô Çâä`L2Å6ro‚Ñ|÷m*”âõyuxɧ•†h(ßÍöÇ”[.nãÃXu…ZQn¹„ ЪkŽ­¬°\dÄžN AW=õ4¦ü·g–73cS%² ­« 0õ’¨‹[}:ÆÌMSð8ö¦rK:¼E2vB–GßXÌí »/k¯z½ØG…ÃBµ'Xx2J3Ø´d¬nO] ȧ ·vŽ:$B%X‚îQl©5‹ý]]AïRÊÔŽŸV½è,ô€á´†óؾNlÏ-6Ù$¤’͈o£×Ì +!!`r!…¸œ“^%Ž&Ž‹š.½øìÈ2(Â*¶ÉRÀ/Â&C“¡yn9TQä!×µ),ðrß5Jûb… cçÂ$LMÝyþÈ©l¢°‡~÷’m –rŸW#Ço_ŠÝ`¹é1),nJ˜H½eµ*Þ 0t] ùòWˆPØx“ÆÊWR5@Á8…p2L¼w.K;W¤]ËÒ®oRƒã‘ÛËð"²Á è˜iºr¡…AÊîÁŸ½ˆ+»öJ‰e©ÿ­HËi9(­¤• »–;¤•I_–‹ËáÔA¹¸¿Òr§´Ò)-wI+]1\t¢Íð/ÿ:á_—wwlN:àçÆ=Ç’¦—ç)æø“t†¼ÒEÆ#á:Ñå.’Ôs¤©‚ðÎn0³Âz9«Oe…Û2¥-±åREl™Wˆ3 ¿·” XÒA÷œ1)¡ÞÔæ}÷”’{¥d¦ÖÁpÀ¿ƒ˜¢dÈM¦µ0˜½"oÙß1qÃZQÊ]…"òÅ” Š] LÉŠÓ"\hìî¸y,µ$Y'Y7ø²£Óêã§4—Ä¼~]J·ØëPάkÔEàcÕЈ„ÌQ ;FjaJ-þ{¤Ü5\ˆˆ‹" ðÊÝëcHº J~ýØ–rž»‚=yË¿¬…=¦g¨“[Ãuh¤fwLôTAõ<0¶Óy4•©ãšwŠä¨%ËZù{º›Š¸ø¹¤‘×5s±[H/Ùè1ˆT>^e ¸‘Ûçž²Ü^q«n×äá9\ºXé»b’r‘ë`¯Ö &zE nÝó-Þg„”]ž>­Ïƒe\bÌhÝ-‰}÷dú¢Ý}ÕhMµ\攵ús'5–\k)Ûþgøþ¿®`a“pú"%$CûR*g–c‹al„\!:”Ë€~Aã÷¹aZç5Õ:½²›öD,{\±y{„#k'‰ÑIíKHú¤WPÜËEùVuŸ½Œˆ°j÷™Çãì¸ ½~“€{Ð?‡¿xÞåLZ¨ u'òŸšæ:Dù¤‡#S (ìM)3rt¬‘×Âßá‚N(†¿²`ð¯ÛkÇ7¬)7®*ñwvöÏT:ÓÀêYÃszºê`¶å] rü0¬6„ïQú4Þnu»¦™Ã„Œ—¹¡"/·{¢êÎ…Qw¹[u¯À°§5n×%4Vçðo¢PÁ]…Âå¥ÐÛˆ^}k%Á¼‰D«‹9ö€E á àrÌúl=Ðèü…EîæÞÉp"ûÒX$D8líÑù;Nä4AÙ£ „¬¹’•–‚NGxÿƒð³Ü¢qAKç…„ž¢‘ÛhhËEÑ¢nX¼ºl{M±0—ôŽ:‹x¹\h H€J}Ÿc¥Ð+ðsŒ•²^Ó7ûC’kžbjWQΕ“æÖ*s©Ó¬9D¡·»óÑ(ܱdʙڸxdUÛVK¹¥¹LíÿêÖþ@o¤ö`͸ç׬>Ô.>M­([C…œ®sõÖÔôÎV´„Z³ÔßÙßí*èi¤Ä6ìœãJAÌq1ç`t"4µ·Õ§.èͽTHó– „ ‰zµhz`hHCN+^tc×”:9çv’Æ´¿-ÐÑhçí™”N^‚í‡RÅ…vZûi›Ú§´¤–OçVÚ‹ Z»áDH•¨áÅmb±}hÉv‹wPvA:/Ä +›6 “3á“PG-XF4Œk°0Z‹oѶÆÇ;s½NÂÎ,ˆ† “ØuDdÍžeë§wìœïÚ1>9™‰Ô!ZKIPíôÆýRH,i°§£ê€$yHÄÊqË()<¡)m¸!+mžÀ¦êµ¬¾TÐvd¹Bg–Öeê6·µ·­¢ÁÓÌkÍ6M¸±YÒL%ÿ¿ é€cVpÈ Å ‡[W7ÁbãJ”µm*£ßf­Ñ‰â7äš&ýòªйœsUKÔ¾n¯•ýžAì{¾RÒ|çÿÊ_`Srbö5ÝŒ Ó•àƒõÒ÷äéæ¹Ò+E’ô`½Áañƒ¡ÎÈ’¿±ò*wÊx›ÇdVŽÂñü›ùö&’ÇœÈÔà[‹,# 9 Þ²êuO¥ ‘dªh\ø_?He÷ ]¦±²¿(rØ(Æö,aB—Øzq)Îaê¢a|!$O\°‹r;ä ÒƒçïêzO"ÑkðXÑ<êün‚ëx:øŸ LܦwÞ¶¾t‘?ì¦ÉA£ë0gIV#‚`9 g‰Ú^[2c|Qƒ5ãïíÃÓ“¾ÄLí8™\®ˆó‚B¹SìÀÕ+^ ³SÚPòTxó¿¨ów»×Í*(œÒõ\º ò­m2Ww·+>O0K;jøüeœ±ØøJò®‰-å%­SÒº$­Û›(!ƒxÇ#;÷OGÆ"C3)ÐòL×Õ:3EŽWщÉ3^Î0ÑÖ6V{8¸Ò¤ÝV÷öÀ 7QÛäÇ}Ûª¹­~J ; 2†×™.Z÷‹&úàJXCXq:‚6®ºÀìê·4ÖæQƒZ\ئÈf±b$¨{`€¼)ü8<œÒƒh¢•LŠÛ–5%Kw­>f¹Æp(UH,¥cUÚ}‰yAŽdèt¤­áã¸HF¶3ïX(fÒ>k›&tG)sviÉÀ而ÅcÞœÌ*îãïìíÙXr…(Uz ‡Œ£]9ãK0KŠ.¡Å¬Z×›žsâ`QD~<¦/n«ZdŸ›ŸOk0µº½ŸTTä¬%MePu]­épŒÒè‚átìÌ.eàLÁ?cZ¶©¬•?ÐÓ‰ÓZÞ#"Í•9‹ý-ÿÛÿÑAQøD)à$àñHèÖo×–ó.ÑõÛÎ<~߉'Ÿq–ãg“'ž° ÿüÛ û´ÈÇï;ùÄ3¶`¡_êØ4Yû&Gž&ngõÊy«T ÷zÓ½™;6ù_OU®è’ÛmÐWK¢š©. (Qöh¸³Z“O\z†ª¿¤P¢"Ÿ±€¦N­›wÇ9pÅñQ«üÕ¨Î,“%ù2|røEGö£4ð÷u½#¿FÕ®¿°‡‡ÉYyrb×*o_,«ôö…²Hm²€±X{?¶˜á|¸UñòÍå—ú»z»[*·X¬³ÓO6Î,ͽ—÷£ '‚­]ùÅßð` øÁ|°Š ÆC#w.OácËÂ?ÜÇ0Kà9×#høºa/Ñj7`î†l‘ “«7{FOÔÍ)­ðdÔÍ¥ ª§‡¤„]‰|m¬6úƹD¨©ZÑ¢ÝÔýnbóij]ÝÜìèò›.ÄÙ\{Ò²4Û5t/o‡¥ý¸6ò Îæ²'‹È3íèÝØ~ÜIæÅB°®­î8PÞ‰—:áú–QºÍØÇ­FÔœò‡@ßIËèbŸfXQÑ¥¤<$“*,>Ñ@h#Ò¤–lç—ÃøŒ 4í)Ó%Úˆcµð$–T#IŸÅD¬Iè„°N`-(££œ7³œI Mkƒ¥‰?ÐÑéA\n HÄ7Öä,uPÄð±'¹_º[m­ ­Í­-­­­þÖ±Ö÷ÚZ/·µ~Ù&ßak}ÕÖz¡½õƒŽÖÏ8Zÿboý޳õý®Ö_ºZ¸å+=­õ´ÞèiýµG~Ð×ú³ºÖïÕ·þ¼¾õ'­?mj½¢¥õ––Ö[ÛZ_g­wyäçÕÖ;•¿ùÆÖ×ߨú7µÞõ&ùå·È¾£õÃǵ^u|ëƒ'È/œØzÁ&ù¾M­×ØÇòÇÊ vk@¾5À(Øòì©€üT€ý3À^ °×ÊÙAvQ]”/²Ë‚òeAö‰ »)(ßT>T>T¾d7l”oØÈ ÊÙkAåõ ò²M¾®“}¬“ÝÐ)ßÐÉnî”oîT¾ÜÉêTŠòCì¯ìÊ=oR>Ú¥\ßÅnìb7wÉ7wµ~µ‹}½Kþz—ò.vw—|wûI—ü“.öl—ül—òz» [¾ ›]Ú-_Ú­\Ù­\Û­ÜÖ­ÜÞ;ÞÝúnvW·rw7{ [~ ›=Ñ-?ÑÍžê–ŸêfÏt+¿ìfÏu+¿éVþØ­ü³›]Ü#_ÜÞî‘á¿_÷°g{äg{”ç{ä?ö°{ä{Ø_{ä¿ö°«{å«{•ëz•#½Ê½­?‘}ªWþT¯òå^åÛ½ìî^vO¯|Ooëz•÷*¯¶²§{Ûlìç½ì™^å¹^öB/û]/ûS¯òç^öR¯ò·^åÜ>åü>å=}Êûû”+ú”õ±›ú”Ïö±Ïõµ~¾ÝÚ'ßÚǾ٧|«ÝÝ'ßÝÇì“ìcôÉô)ÿìc¯öɯö±súåsúÙùýì½ýÊEýìê~ùê~ö¡~vm¿|m?»¡_¾¡Ÿ}³_þfëwûÙ=ýì¾~ù¾~帤N>¿Ž=Ñ/?ÑÏ~ÑÏ~ÙÏ~Õ/ÿª_y¡_ù]?{¹Ÿý½_ùg?{­_~­_9{€7À./`W ÈW °«ä«”(×(7 (ŸPîPîPPžPžP~5 ¼0 ¼8 üe@þÛûÇ{e@~e€ýåßå¿ü;»c³|ÇföÍÍì[›Ùw6ËßÙÌîÛ,ß·™=±Y~b3ûÙfùg›Ù/6³g7+Ïmf¿Ù,ÿf3ûífù·›Ù6³?nfÞ,ÿy3{}3;çTvÞ©òy§²kOe9Uþȩʭ§²¯œ*åTå®SÙý§²N•8•ýúTù×§²çOe¿=UùéìÅSåOeçnaïÞÂ.ØÂÞ³E~ÏvËù–-ì¶-òm[Øí[äÛ·(wma÷l‘ïÙÂÜ"?´…ýp‹üÃ-ìá-òÃ[Øß¶ÈÛ¢\¸•]²U¾d+»r«|åVöá­ìº­ìÈVùÈVö‰­ò'¶²OoeŸÝª|n+»m«|ÛVåž­ì­ò[[ÞÊÝ*?º•ýl+{z+ûÅVöÌVù™­­ÙÊþºµõå­ìï[Ù?·²W¶Ê¯le„Ø{Bò{Bìâ»$ÄÞbW…ØÕ!ùê»&¤\b ±#!ùHˆ]’¯±O…ØgCìÖPëBì¶ûRHþRˆ=b?É?)? ±GB2ü÷ë{.$?R^±ß…ØBì!öPëùƒìÂAöÞAvÑ {ß »lPyÿ  ¿?8¦õÃìºAþ»iÝ<È>=(zÝ2Ènd· Ê· ²¯ ²ÛåÛÙ/ٯٳƒì¹Aù¹AöÚ üÚ ;gˆ7ÄÎ’Ïb±‹†ä‹†Ø†Ø‡”«‡Ø'‡ØÍCìÓCì³CìsCʆ”ï±Ç†ØãCòãCì©!ù©!ö›!öÛ!ù·CìCìÅ!åÏCìå!ùå!å¢0»<,_fW‡Ù‡Âò‡Â캰|]˜},ÌŽ„Ù'ÃìSaùSaöù0»%̾f·…åÛÂÊ·Ãì»aö½°ü½0{,ÌˇÙaödX~2Ìž ³§ÃòÓaö|˜ý.,ÿ.Ì^ ³—ÃòËaöÏ0{-¬œaçFØyöî» ÂÞaEä‹"ì’»4"_Q®Ž°#öñûD„Ý‘oŒ°ÏDØ­v[D¾-¾aߊ°ïDØ]ù®»7"ßa÷Eäû"Êýö`D~0°'"òå'öÓˆòd„=‘ŸŽ°ŸGØ3ö«{>"?a¿°?Fä?FØ_#Ê+öZ„=ÌΖÏf ³‹†å‹†Ù%Ãò%Ãì²avù°|ù0ûа ÿ}l˜]?,_?Ìnf7 Ë7 ³;†Ù7†ÙÝÃÊw‡Ù}ÃìþaöÀ°üÀ0{l˜=>,?>Ì.Ý&_º]¹M¾rûè6vd›rý6vË6vë6vÛ6ù¶mìÎmìîmòÝÛ”{·±×¶±³Gä³G”óF” FØ%#ò%#ìÒùÒö±vdD¾~„Ý0Ân‘oa·Œ°/Œ°/ŽÈ_a÷È÷°‡Fä‡FØK#òK#ì#ò?FØk#ìì¨|v”•ϲ‹¢òEQvy”]•¯ˆ²OFåOFÙ§¢ò§¢ì«Qöõ¨üõhë÷¢ìÞ(»?ÊŒ²DÙ£ì‘({4ÊÊGÙkQvövvîvùÜíìâíòÅÛÙµÛåk·+G¶+ŸßÎnßξ¶Ý±]¾c»òíÊÝÛÙ÷·ËßßÎÞ?Ê®e•?0Ê®•¯e׌Ê׌¶^;Êne7¶Þ<ª|z”}iTþÒ(ûÚ(»cT¾c”}s”}{Tþö¨rß({`Typ”=4*?4Êž•Ÿe¿e/ŒÊ/Œ²—þM~éߨ‹£ìÏeU^e•ÿ>Êþ9*ÿs”½:Ê^m={Œ;&Ÿ;Æ.cï“ß;Æ.cWŒÉWŒ±/œ$á$öå1vû˜|ûûλkL¾kŒýjŒ={{vŒ=?&??Æ^“_S^c˳kÆåkÆÙãì¦qö©qö™qù3ãìóãìÖqùÖqöÅqù‹ãìËãì+ãòWÆÙÆÙCãòCãì‘qù‘qöø8{bœýd\þÉ8{m{zœ=3Î~;Î~?.ÿ~œ½4Î^g—ÿ6Î^—_gçLÈçL(ï›`—M°Ë'Ø•ìª ùª öÑ vdB†ÿ^ ÈU &þÑ)½[~®[þœ®ýò³›å×7Ë÷Ÿ*Ÿ»E~z«ü`Hþ]H~ï ü!ù7Cò-aù»aù±°üTX>7"Ÿ‘ß‘/‰ÈG"òÇ#ò'"ò_#òÃò‘mò-Ûä×¶É0o‘¿mšé˜WÛå¯m—o•3*ÿyTþÕ˜üƒqùññ¶ŸÕÉ/Ë—M(÷zä‡wµµª·ÔGv©îRÛ¥žß®þh—úO§üp@þÀnȧí–oÞÝv]@}* õõÝê«¶Ëm*<ÐÅA§Çw·½j“_Û­>lS zhOÛ…võ¡Nù.‡zs—zc—üúhžó÷¶ýÅ®ÙsÉÞ¶ï¼IÊç³{Ûnô¨@Õ<ºW}ª[Âæˆ«íý.^Я¡SJæ‘]­ï;½íˆ[ºåÉÓÕ«{U LÞ³O…7øP,ûTøýÒ¾¶Ï÷©·ö©ŸëS¿¼O~hŸzwŸúÍ>ùñ}*PÏïSÏéW_íS€¸|¶í§Mêùu*šUb¸nVZá³³*_ŸU¯Páhÿ¯3Û~Ò¨Âé~ç™*œè÷œ©Â‰þý3U8Ñ{@…óà–*œß> žm½ï€üð΃G¨püø€ ‡Á T8 þv@…Ãà•êW£òy‹*œ÷FåËÛ¾Uïªp<ÿÖüS‹*Ï,ª°õÿaQ…íþ¯‹*lôM«°Å-Ýö… ûûM'¨°5Ü4*_˜Qá÷‰Ô;FÕ»‡Õ‹2ò%vöË3*lè×eTØÐ?–Q_Uaù+œ~_…®2*üÞ“i;{L=wL½7#?™QaËþEF…ú¥Œ ;λ³*ìÎïɪ/޵^”•dUØ¿›U¯W¿—•o—ŸËªðû»¬ ôŸ²*ìÎΪ_Wa_¾ §>>.0§þd\½:'?3.ßSŸo½-'#§Âþûíœ ûï½9õœ õé^õ¾œüóœ ;ïŸrꑉ—l6Ù´9mn›Ïæ²ÕÙì¶ãmM¶f[›­ÅÆlo²½ÍöÛ[l›l’턆ÞYÛ]NùnçΞï:¿ç¼Çy¯ó>ç÷÷;ZãhxÀi{WõýÀY^éÞl þÐù0Týû#ÎG6r™ó1§où‘Sy¿Óks?™Á;]^ÛÎðÐp%ïwG~â´yÝ—;}¶Ÿ:Ÿ„fã÷;=“6ßåΟQvÇSÐÊcsÍì}²{~YÛŒçŒÙ_8muÏ@ɾ_BI½fû_ò¿¿¶ŒÎ6çYœµÕxÖ‰mŸƒofîü¼³ñ7Îô Tbkôäl³Ùãëü´ù=–vÿ_[Ûœ„üþ |çÚfm/â5w:ϱýÙù?t¡ò§­ù/Η ð|Û_ Ùf› ï—s¾×ö÷²·d­+¯ù‡³ñ_\ç°]ß³åý¶Ø®´½7zÕúpï·)´Ùš_£!\e{Ýéžµm¼ÞÖô7ȱí²m´}Üæ¾Ê9k{Û9®/Aágm纔ó\¶w»èe}Þv¾«îx´¯Û.p}Ív¡ëNç{\ïu]ä¢Þ¿fkø6Ôý—¨ù–íb×%®R½÷n¨¼Ëö>½•K]øF|÷AÙe¼ä^Ûû]—S)Œªí˜Gmø6±]á²c{Üæþ™Ív¥ëM€ŽŸ´]åú Ëó´Ív5/xÊö!ýÒf»ÆåÃiðŒíZ×å8¨kmîßÛfgƒ÷¥~Øõ-çG\6ÕóG¸«zäîtþÁöQ×G\ ¶×mçJ³ôçHs•M‰×mï–fmçIG\o¼n÷qWEƒ7z.‚zõNç Ðå{¥O@‡ÊÅÒI6ùFöøI—û}’í&þ/‘nv}Òå½ ®øþ¥Ò§iøÊÕNÛg\oÃ÷~¹ôY—ûÒìç\¶“?M®”nTÝ%Û­®¹/@ÁUÒ-¯V¹V²ÝƯ¼Fú’KùÓÖôe~ÕK_q¹? ÷j¿Óy»ë«®ë¤¯¹lí×K8©¿îzó®#Ò7*ŸçÍîOH¶oºÚðÜ }Ë_äfþ€ß†¼IúŽËóiêàN—ú-秤»\Pr‹¾»]O:?/}—Þ½ûZçã6Û÷\÷Àxo•îuÝçr‰äû0’Û¤û]î¯âE¸‚;o—t=êô|]²ýÀuìCpÅìפºvÙŽu.ú†ôˆË… úQ—íÛ’ï{PôŸ6ß•~$¦ç> ÖÅãôÜ÷J?†aûî‡vOðvß—~ââë×û”þ”¿ûHOò©ó°4 Ï£ù™ë‡ÒSð½O»l?ç—>*ýÂÅç«çq¼Å3t‹I¿„[(?‘l¿r½å¿¡¯'¤_»l?•<Ïл©{ÖõŒóÒsÐÆöKÉöß’ûy˜ÏIÏÓ”ø {~K _À—ø‚ô[¸§íIùˆÓö–ß¹°¿³í¿wyηÛÚ.°ã—˜}·ý8Òë`y6_iÿ£ ñEö?¹lï³{?`·]i¿Êþ"ŸWØÿìú˜ökì¶Úÿ}]mÉIÛ5v÷;<Â_é>fÙåÅæ¿Ù~Ýãop™Í¯üÝu-.˜¸þéúŒý—ïóöYÛ«ü]|Îþš±J¿`·½möuÚ'nµŸ­(ç*ç(¶ó”·ßéü²ýÝŠííîóÛŠçBåNç7ìïQÞ«x¾e·]Ä ¾iÿ/‹”#NÛÅ úNû%Šr·ý} ? î²_ªxî³ã¤ºLyÒy¯ýý N*ï0–ËÚÊï·_¡ànî½R±Õ}@Á¢íW)¼Ðý<»B]ýÀ~µ¯ûa;¾îà‡”‡?´_£< ËF±}˜ßüûGå:åQ»­î£ÔÑÇ÷ÅÖx½‚ý˜ýã mÜÛƒØÆ·"˜mÀÐàçtßôLUwçΛ¹Õu_¿y·^õ•sD!”#ÊYBAH(ÊH! I( ˆ`þ¹«æÍ›*ÿ~ëûÖ^{íµóÚ`£j5Æ[-Þ; تU¤¹Óü‘âSʘh…¨ÌÜeì4&ýF™»×¬ÔGVѼôÖ%[e™S¬¬žUêocï7¦Yé#F‹¦Ò74l̰²ŠeëLŽ|˜ee5cTOͲqX§9Vz<.ÜßvkÖ˜ge}ÆdQùV‹—ûiS„«IþVábºnµxýû˜Æ\„>¼MÅV¼ô`“²-±â›ú¢©‡K/Ã)_< —L7p@–\AÏUV‹×E¨©Úê·ëbY¸IÕü6ø«¦Z«[V·­þû7”µJ7-Ï1Yxõf›ê0Tèw¬TýoWFž©añR1Y>Sw­øð+25rÐêŸÊL–ÅWU©©‰«ý“Õ “j¶²åËM-VV¦Õ=\„x(˜î[é¬Tëo}ÖšÚx­Õ›T»Õ'¨¸cê´Ò›LªËjññÚhêF‡ú}“zÿ¡o½{¦n²T½VÜæSkÒÍ–Óo‰vÓ#Ž¢ÃôZ·i]—I=¶â4úû­póeð=áqxh°²î3)_ó ÕâË©×4ľž°÷§‹½÷›†QóÚ Iüv8L£ÿ8œÖOM–!“ZõÌŠ—Ý/»Q.‡2ó8.ˆÓ„•Õ˜©Ì¬ž[áùøÌ4ee5aâä€[7ÍXYOá$-Ÿµâñ~nšãfþ5¦×fP5oµœUÓ¦V¬|}u Vor1kziõÿžB«L³Z÷jqwçM§õe &uF_|5¾0ÕÿÇ×£Õ9]×_š.èeæW&G]½4Y©?8i‹'ÂQsÒÕô3oMgçÒEsÑ­Ü4¾&\õ/j>ºu¨¶\ùêÜ#óeÍOÇù G7þú CFrU ÔõZµ|½C³Q:/Ïv­»cÝ­ý£K—V¬›ôÿ¡ÂºG³”è ‡ñP+Õ˘X•ëêÆo¹W»©ëýšªÐŸµJ¥AmqnQ¥›´j—ø’§¨«ùíÐ iµÿ8txUÙlÕ8¢íVUõ"³¥Ø|[gϵ:]ŸÑ4uG禵z½A·º«+[Üázƒy^kÒ­Ïš[tµî·;õŒùž>!Öç͸5ïë‹·æ9óôûº£wXëb7Ìmz»Þ¡ÿãbv7«N}ñ àfîÒ­½ÌÊÓÜýÛ{¸xتwˆ2ˆÒDY‰²Ã21¾!¦·D[±f±jµ¨wÄü¡˜÷‹õ_D;§Äʸ)1¸+ÑýðM©Äœ2•Xç(yí:ÊZpuJ–¼ç ²ÄÕ Z’A¤›¬õ1÷d©³Q–z€h£X?£F1>Ó`Þ(¯_4Éëa Ê$¿»f-Û$KGM²lu­šGÁH2‹M™YŒî"Ë}A˜ˆM¾ˆV'òF/Ê9ë&+1?mVbÝm%oFèb®Õeyƒ.ZŸ.6ç¬ÅÆÅZÞ °ëKÖòû«Ö²"$XËÛ­Åxé51Ž¿†ñ.‘W@8H_"+ëÀÄ÷–ˆu+âÎ%¢½Dì¶T–{.Ík©, A™°Tl²P–/•UKåõÄ×åõäב¿.«+_—wº)pþw¢ùýNŒ'6ã`yå2YÓºLÞˆ¶‘µm ×F´YýÂF¬//­d¹XM.sÈbŽxC¬+Þ7Ÿ½!6>oÊ»þoŠô¦ØD¾)Ö±oÊ{i(«P7ñ¦(—·Ä&õ-y½ ¿%ožÿ½¬šû½Ø¸®ò~:(^!o¾-ïw¼-+ÆÞ–N¯”þ+E [)ë¢WÊò¤•bÓN¯uf•,ñ^%+òVÉúU².hµ,M]-–¯ëYðrµ,q~G–¤¾#Zí;¢FßÁvÖÈGÅk°ïkäãÓkeù¹µ¢y®cÑZÙP¶V>¹±V0ÏÃô»b˜}W–½'ëÞë¨÷qÝ­”šy_–Ô o„®›‰u¸®ÖËR¿õ²¤j½ØŒ¬—u®‰Ñ÷#ùCÝGb3ü‘|ú±¼ÿ1¶ž},ŸmÀqÙ 6åd•Ó'¸>Ïë>›ùOd]ÿä‹¡?Ⱥá?àX~*ë®}*—}*ŸÞùT¾tú\ÔàR±.ø\6Ö|.ææÏåSÿ/dIô¢U)ZÓ—b¶QìÂAÄFÜ/Å>Ä€XâAHIàH)EKݨŸSJÒ7ŠCÈD]ÊlrAÈŰð¡8"¾Š@1(¥Ø6¶ëP†ÛVض¶¶©°M…í)ŒCaå(±m…q¨ OÄá¶An ¾‰e`³8T¢¨Õ Ô‚[à6¨w0Ìz¬rw£Ø6n”­Í([6êqëßß(Û]×˶e[+Ú`Ùö6,oß(;:AêºQ>=ˆ{QöGˆ¾÷#~‚r "Bù #A9 ž!C9&O¢|¦O£œ³ˆç6ÊWÇ Œ¹÷CܺõNe”= oÉŒuÏ[ÙsœçA ’=P:'àl+º‹­¼æf+û=lñ•¼lå`,‡>(}mÅè‡Ò`Ùƒ D‰~¡Dß/¢DÿƒQb*ñ%”ؖ¶^F °ÍƒWPb» ÛUaà*ÈÄ;å$®Ü”‘ Ä`\±¶xR›äkœâ¯ãmåëÔcß¾N´I²•op‰,I¶•#—>”#©¶¢¥ÙÊÑ [Y’i«§Ù*=ÙV“o¾!DzlåX¶­|›ƒõÑöÛ\”yÈóQ€BÄ8¯Çp^¿½Ž¼o¥+B]1┥(ËQÞ7WlçŽý·•¨«B\ j@-–a,Çn¡þ6Ê:”wPÖ£l¸^Žc,'AÚ6£lAyÜGüe+Ê6ÐŽ¸e'Ê.Ðø!Ê”½ ñ#”Qöƒ'ˆP¢O££ˆŸ¡ãˆ'PN‚爧PNƒij(çÀ<â¶rûxûpû³aÁVNžÞ$'Ï€³à8.Gàœ pÝ$§Ü€;ðs9å‰Ò à¶<åÒø?à@ A0—Àe€{÷Tè&ù.l®8r“ü b@ì&‘¸Mú1³ü”°I~š6ÈO‰(“À54Çpºø)y HEŽî†¨0D…!* å§4ĪÂP†ª0T…¡* Ua˜ ÃT¦Â0†©0L…a* Sa˜?¥ƒ ²6éxÈÏ9›äç\òA(×A(%àö ù¹%.·ŸËX‚à&¨•  Œÿ^~®FYjÁ-® ê6áÛEÄR¿I~iØ$–»›äŸ7fЂº{à>xZQ׆²cÇé@‰qþÒ‰º.Äï/Ý(1æ~ˆ¸1ÆþK/ÊB£·Ea~éCŒýøåJìË/Q–ÌÒúQ><ž+ä—A”ØÇ_p[ý2„û©°Ÿ û©°Ÿÿ^€ð¼§íðh³“ÿiĨ­µ’?寔?µ“?ù-•?Cy\Ž H—?9¡t.À¸6³üé¾ü)ö]€ÒuÀxoà|Ù/ð ÄZþˆ2\Á \—íD Wì侊2ÜNþ—H…8cŽEg§‡Ú)}êu¥_An§äÏ vòçD,KBŒYaÌjv-36òçk\ï]¼=Q¦€T€ñ+ì“Â>©4¬›ŽÛùs&JŒçÏY(1&…1(l[al cûs6ȹvò—|;ù_ íäW\K¿âÚùµ1®_q­üŠóük1r\¿âšø×į¸&~Å5ñ+®÷_K°¬à¼ÿŠóþ+Îû¯8ï¿â¼ÿZËõ±¬ÜNÇ„[,7íä_*@¥Xª@µüo5(kÁ-Ôãúý—ÛÜgĸ~ÿ×ë¿Ô!¾ƒ:Œá_êA¸ AàccPƒÂ¶T9új-XvÏN–ÝGÜj'ÿ ׬¥ q;èhÛ…²<´“ÿ½y/èCŽëoÃ#”ýà `Ÿ¸'íäÿ²“ÕOíäÿFÛ”£(ÇPŽ£œ@9 ž#žF9f±îÊy”/P.ØÉ†—vò¯=kä_OÛË¿žgÁ9pÞ^6\°×_ÚéòW'{œS{ù« J,ÿ«+J´ý«ëÍòWw”Xÿ¯(Ñ—ÂúŠë{ÚË¿y#öAéËØ,ÿæg/ÿ¯¾ÿ€2‹ „ØËß.¼rÿ†×ìßn£ E~„« D€H¢A ˆq $€¤wåo‰,AÏûò·k(g¾”¿%£L© ¤ÛËò {ù/Y Û^´{ù¿0Ex;Ï^ϱWzËJk=Ãþ5}N”,ÍǾ‚ë È^,Å(Kìå¿â¹ðïeöòßn‚ P ª@5Àµ÷ßjìeE­½k½DþŽ)ÂßoÛËßGðõö¯wÐÖû{=J¬«°®Âº ëý½Üè£ e3h±—e÷ìåÿ~`/§U+‚6Ўʲ¥x-•³ªk7äŒÂ­Ë^ŒÝör^õR}Ô#ìõc{±yb/Žj¢žRÃÔˆ½8©gÔ5NMP“ÔsjŠš¦f¨YjÎ^¯Ã‘rV/ì!œGgµÀ(‚zIá9åÌ-:«WÔéÍÐ JˆÑ9 ³ogužÑÊ‘r¢œ)Ê•rÛ¬—™­ÅUaNnñØŒÀs³X¼€7¾›ÅƉ?\w–&H‚ÀE&Á>\U!²'V•0㣣sU—QcâªJYÍï‰þ÷„¢—+l† ]E›lŽÚÖŽY‰%’AḪh lƒà6kb„³&•«ŠG ‘k'a Ž›º†2¤€T.HCðŠÍÓ±ù $8¦–L”g¸4 ÁYÙ¨ÍArŽI.’<ŠP>ËuI Ï9O¹¥MŠQ‡3ÏÏóÎÓγΓÎsŽS.ÜX–´-e Ü7A¨U šãÆ:©|@ ÆYU5àÇTKa6ááÍ n±î6U‡ÕñßPϼºKU³áª‘iúscÐLµP÷¨ûXóhÅr¼p•+ÏhßZ(ÙŠ€¸¸xm¹ªvªc³¸«®ÍòY7ƒ‡X†Ç‰êAÙËŠ¾Íâ¡æ­ô'öÖ⵸÷oÞQ¼¡Þìß,Þj€¤†¨§T5LP8ˆ>êÙfñSãT´M0šÜ,¾ê968ù¥Þ¿y©¨éÍÐ 5KÍQóÔ jzI½Ú,þê´¢38ÊvÎ"à²sœG0Äà‚§ 0pB0ÌÀÉ1ú+vèJ¹9 u§<˜N~ =gOÖy±Î›ò¡|Y‡/5~ªù+?¦ø€öWµ”?Ó¶ ¤‚d¹ëZ RÁØr¸ä€„µËbê U˜ƒhW$XEP‘Tª¢ô«Ju°–ëÅ9È%ï€ûÈABU:Kf‚ µ¸½Cy'†ªW+0oá¢t,‹%Te ˆg‰ ‘Þ¡*ËA®¨f#”Ã(—Ê£ò©ªºNQŦJ©2ª½]±Æ ûRá »X[K„ªr€ª©ªmJÜ¢nSuÔªžj@ tÇÞ"Ô] š$Rµ8H¿ê£9ÌhußÂÛ$Z=`4Ǩ•QU@µãÐu8H¬êr¥Ýè¬ô‚>ðÈAâÞrË;H‚zBá3ÜzÀA¬‡x‰ðêpu£ècÌA’Õ‚I}ÌßðSX8 P—Ê/„T•&Ð,ÓË+¡9FóÔ jzI½¢No‘·Ïl‘4un‹hç·Hºr¤œ¶H†r¡\)7Êò <)/¬à½E2•ïÉRþTHaáÅ-ú™-¯ëYK­uï-J?òì_×ût¥{.}M²UÈèu™ ¥®PaÔU*œŠ "©(*šŠÙ"Ö±[põ€Ë MÚ"¹Üz®ÂlGsûTòUê=i‹’B•¾ÂåXÈ7M¡Ê`š‰uñÎ*TYd#bƒÓ…é“Âô‰*La¸ƒ*—ë¶8Ê*v%”ÇÅùTU¸C¸Îcõ®©’-P)UÆúò-º÷»JJÔÍ-PUIaS‡›–¨*ô‹¹ÑÞì\¹DUS5T-ÕøšüåÖ)Su[dÃõ[¤”ë,kØ"媑š|Mn¨¦-P3ÕBÝ£îS¨Vªj§:¨.ª›zHõ`@½`ú5\¿(Ç ”/åGùST ´U꟒«Ä‚KÏ‚-MKðB°•Ë[¥A…"¸ÂÀU"@äV=|ÉiäémTÑ[¡*–Š£â©*íñlᣅ>Xø ás„O•„å×@Ð ±$c)\)•JC–Î ‹3AÈ9Ä r¹4ʧ ¨BêúV=“èfUŒ¦%èg_Ø­fUJ•Q; $)[³*§nl•U±UÖUm•ªf«¬­Ý*­|ïµò³¦•Í×ÞÞª×ný´©º­Ð­Ò®êÑK¸ËšFª‰jùj^Œ°Þ½­Ò©P­TÕŽ•xÂ:˜tnÅl#x¸UzT£-ÔDP£T<Â:ôSO l•‡ªu#Tg+½jh«ô©aj„„²O2zFQxDö©qF‹Ùd„šdú|«,Ú*øÐ·žá¥â æ¶J¿zAáczÃÂV}n«. _xÊ—Â÷—_R¯¶Ê :³ :» 3=P„³r¥ã6yª²>‡œ¹ Ê¸÷m2¬g£if3h‰ÛTÍb`s`¼ ¨OÆN¿Dü œþJ,g¾Â!9KûJxÓŸ1à ôŒá<«ÜxÐ.|9b!Ù'”ÎXÍ…‹]Ûp±;#Ô{2ðBà |˜ø"ðþX3²}u‘‹ƒ)N§ñ˜áS†o¾øà+€o¾8±æ¼š3j‚~.Ë ŒqF‚ƒz1>LÎÂØëUn$œŠÀö#A–GsOXKÅQñT•H%Qרd*…J¥Ò¨tvÁŽ0(¼Àøþ²d"ǧ?ªÎ²ÌóvÈF€¯.KÊ\ðíeÉÇP <„ù ¶\g·EXP J¸¡Re ‘Ï„r7X{ëT0¨DPª™ÔPµhs 5xÂó¯n³Kþº•wØ¢žj`uÃfè.£Fª‰jæÒlÞgø˜8khazºO= Z©66nGŸÓ¼âÚ6ò†A–Ž+«“‹ºØ¨›zÈ´Ëz^`|ñõÅ·_^|ïñÇßw|ÝñmÇwšêãÊ9vby„ýzÌîú©'ÈÐ7ž›À ’!€—7ߨxaã6C> FØÇ(ÖxÆ` 5˜-p²À¹§ œ)p¢Ày§ œ%p’À9§œ!p‚Àùg|srpÆ0þ•¬™øJÇëÜòü+9o˜¢<6BžÔ4Ój–𣿩Ôõ’zEÞ¡ÎRçv`^ÇàÌžÎ8±Æ peâF¹#ó`à‰À‹7¾üø#`ˆ ˆÁEÁ ®ÛB!È.LàÎñ¶>Ç›ùÜâ}y™B©+;PÆè*NEP‘TMÅP±Tܼ$P‰TuJ¦R¨T*J§2¨L*‹Ê¦r¨\*£Èß! vˆ#ß·-êúYU²C\ el(gtƒÂœVÝdPAõ:ˆ‹óÞJfUØå\G5(kÁ­âf¸MÕQw¨zªa‡¸îRLñús3ðP4a¥fv²C´{;ÄÓð€jÝ!kÛvˆ·_#Þ†6ªê`]ç¢8ïâVEÔC”= —çx5.ü²îÑñ3à9ígxEá)íg8M5n–ÏžìÐý6[K€?E#…6 KšñÇ´†&ª†ò ‚¨{j³üep‡žî@ž_ëal;¥ža«c('À$èãO¤QNi0³C.f©9jžzA-ì›—;ä/§wJ({|ïìN 3œ§.ìÄ#ë:¢tÎÀ¸7à<€'{!ð>À—~”?@¢>\d¼S> Ary§D®PaÔU*œŠÀÂH¢A ‡â@¯ï쑳ƑírιjØ£½½D.±\¡þTà>É2S!Ô¥)F—©Pê F]¥Â©*’Š¢¢÷ɇ1ì.cL؇Ç6’R÷Éò´}R`L(ƒQ&•EeS9T.•GåST!u*¢Š©ª”*£Ê©ÔMª‚ª¤ª¨ê}zھפÐxΪÝÝ¢nSuÔªžj îRuó>)6ÞCp%‚ûf— x€ •‹rm¡6díû¤ÔØIuQ¶P…¤”7H)/ßR^¾¥Æn6yˆµÜßAÐìYƒI6xN=búõýû¤„k /ÖuOp`Q{c‡Ü0>E0 |׋eh›X†Â<ºOôgû¤Ò8AMRÏ©©}RÍTs ÕH5Rmœ¡fÑÓƒyê²/©W¼hö#8CݧƒóÔdŽ œ(gd.û¥ŠC®âkŒnû!wʃò¤¼(ïý²Ôg¿Ü2úQ6?VwÆ.ì—ZãÓM^©·Œh´_ö±’;ÆýÐ%ê2Z£w…ÎúVèZ¡g…ŽmC÷Kƒß6 F|ÛÔs8ë°(D‚(€þ/ߢ÷˲ÔÄí—&&«â÷K‹Ñ›4q¤[Œ‰L˜bVÐbLbz Ú&Zò~±ñ±–ÒöËŠŒýÒÆ»¶X•µ_ZaŸC٬ϡrY—GåSÁkPWÀ…Ôuªï—vc)å¿  © ªŒ Ê÷‹ÜØ/]ÆJªŠª¦j¨Zêu›ªÃÎÝõ ÜÝ/5îÇÓ¤y¿ôS Ì¢zŒ-Û¡f*v3ÔÄ“uë<Ø/Z÷Ë##&+Œ~ö²®}¿<á#뉱‹ÑíPu‡ª§¨n¬ýô€^ÐÇÖ¨ÇT?ª@‰µ¨A”CûeÈ8Œ`„Á(‚g ÆŒïËÄ~Ñ&ÁÔ~Ýs­’ãÌ~hK1áR˜o-Cüb¿ŒòâY³€Óùj¿ŒÏÛò³þ€¬›2‹üQ¬/Íé.×2ctCЋI˜1Áº†©o¯ãåͲÎý€ØzycïZÈ-}˜ùR~ÈüàR›ç¥6o `ˆú 2Ç ï…1øB]¢t™Q(u… ;€Ñ]Åè"ˆMÔ9cÊàïîÐMˆ? –ˆøH) ¤5ôò¥ _䂉Xßw ‚lf9hµEΛr@ø°(qܳe.%ÁäFµØÉ÷ƒ’dÂI’ÉÉÂI’É…‘+åF¹S”çAYçuP"•ÏAI1áS$ÅTEù¡V d„àâAI3… ¸Äà2‚PW„”tSøAÉ4Ål‚b7!D}4ˆ9(Ëcê¾òšä˜âB T"•D]£’©*•J£Ò© /€S&£é7!þRóŽSúÏ`0´ÊFv›YL‡¦+ S…YˆÂtDÕqa.bš¤0IQ˜))L”T5À\Iaª¤0SR˜()Ì“¦I ³$…I’ÂIaФ0CRåœ1LfG 3UÉÎóÐy#ƒüƒb]€¤ƒPzP´²ƒb,?(¦ ª­ª°„W<.ý55å³ì÷¥ØÔó¾XnKÝA$I›¡;Œê©ê.ÕH…ìÂeþ>&WõÉßYK™éÖ»€VІ ´ƒŽƒX؉Š.ÝÔCªU½ ”ÿ/#¿CRa  ü–BŒ‚¨à Ï=æ?¦;üÉ!QÁ \b›ËTè!Ùpå_]‡¤ÚIEQÑT KÅQñT•H%QרäC¢¥ ÛtqHn›²¨ld9 r©vnñ±³®ô|R~H¿±ö-©7ÝÄâGöú>€*A•‡¤ÁTMe®ƒjÕRƒ›!¼EL·˜Þ¦ê¨;T=Õ@Ý¥B¿„šÐ•-P#뚨fª…ºGݧ"Øä£V*’i£vªƒê¤¢¸ ‹Q7õê¡ðÕÖ`êeÔG=¢SýÔj`q¨!ê)5LP£Ô3jŒ§&¨Iê95EypÓŒ®2JÙÍ0Å×[ƒ)Àšu X7ÇhŽÑ<åÉ5^ð‚X8$Ÿ½:$M&×]«xæ°Øœ=,ͦóÔ…ÃÒbr¢œ)êþFÈ•Q2#·Ãò¾ûa=}År¹Ï‡ê}“ça¼NVQXC¡­r;¬ï·–V“÷aÈq=äºòaêK¹1õcäO¥oRAÔE ƒl53 A¿˜}£ÞžUTu õ˜|«r.»Œ$”­¯PÜHäv± ;,KÖK‡)Ë}ÖʺèÃÒeŠ¥â¨xÊw¯t›C‹?zø)¢ÄÈp–»M˜‹û“°ú5¶M>ŒÛE¥–^S¶­ô™©&*­²@öa$9rä!ÈL \g0ÂF©"¦Å¨/aPJ•!+gpƒº‰¬‚Á$›?§*™V¡¾šÃÀ­ÖË[­×Ä¿&^sXó=þ˜¯ðǦ[hu›Uu‡õ‘õÖbÁLÈRO(p4‚ ø\m:,OLÍh¼O,-(Cö¡"Ǻ‡ì³û.3xÀãÍ Ám´#¸Š·Z8ˆ`E;°©nðô€^Ð‡æ‘Øâ#ÄA?ò(¬º'ÈÀ WBð ƒ0 ž10&˲ÉÃ2h𢦩…]ÐKj†éìayj—䟤C&|I>5áKò©iþ0RoF/Ø$‰ ®Q Lùaéa-ګúßš\×Cü­o5žÅ7ÀMPª@åN‘3_˘éuþkQ8"pbàŒÀåk™0¹Q·?„ê?Äw3ª=€'ðÞ_Ë>_Ë”ièC±ø-ßõHbWBXÈEAÔE*U! .¡åe ði¹‚2 \á D‚(6ŽF¿[–Ç|-3¦ ¡8FñT… Ì™©‚P£LF×%S)T*•F¥Sw nj•±¸•…Mù9ˆ¥f£XjÙC•ÍE9TÓf(—îäuéÊš|ìR!¸Š@1(¥  ”ƒ_Ë SØY0ÝüZ^š*QUýµ,©ù7è­¯ÅfZdÉ” XpñsQM_Ë'Í_‹“vºO= Z©6ªê :©.ª›zHõP½|NZ£GÔcªŸ*ûzÂh€¤†¨§Ô05BRϨ1ªŠ«áuè¤3 &©çÔ5MÍP³Ô5O½øZ´…¯ÅöÕ×òÞ™oÄM»°Š Î}ƒ p8'à \ØÌ•rûF<4Ty2ðBàÍÀ/?þ ª·CÈ™þßÔ .¢&øYòxi—©Pê …‹ÆSë±CÆô*…óî­õ¯"¾"©ÙíPò(Ši4CÙCãÔ5IMS3ÔsjŠzFÅ.vÅ(ŽQ<¶šc]ÓD ïUo̓ ¦]e”Â`¾ê­%±É5*” ’•l-ÕúšY¥1J§2¨L*‹ÊþFÖå|#6y( pp®ƒ¢o$€ëh oAÅŒJ(¡ÎRç¨óGDÅr/0s¤œ(gÊ…r¥Ü(wª™G݃‘'åEy­`­|à{D–û‘Pma„ÏÌP­f;tö(û+(g È&˜d„ò[tDÂ4×O LC^‚H¸æó‰Dh—…b|W„!¸Ê AˆdEE‘u5ÈÒØ#¥á+?ZK8"1ZuJ¦R¨T ·W שּׂn'”ƺt*ƒÊ<"qZ66rÈ¿çqïŽH¢–`%Rרt*›Ê¡rídÍõ#ò^ñIÖJ)\¥É|(%k]›ñGwåภ*ؤòˆØT‘­†ª="i¼õÒxc¦qý4ÞÊêŽH†VO5Pw©Fª‰j¦Z¨{æAéÚ¢ûL`S­  ´Á¢]\2É6¾ö·ºn ucáC.ì¡z©6›¥ÒwA}GdÙ£#’¥õcèOŽH®¹Š¢¢)ô˜Ësµ¦X=—«çj±L{¸F/5DsÁSlt˜ÙôN(ŽÍøæV‘KêÙÉךVbR ÎÛáFÀ‡?k~À€@.òµ@Ï“Gt¯¥Jе™¢ÍÑ«¿TRªM9@˜«KkD›;"å¬)gM¹ök½:"Ú™£R©;*UÚy*øC¤X×b‡×­ãQù‹óQ©Õ\)7Êò <е×QŒð¨¼ç{Tê´¢í®ƒ: ³Ñ:^u<Áuš?Z€@.‚`.Ë \aà* D±÷h*†Š=*ëâŽJ½O%P‰h•®dRAÏRQi(ÓAÆQ¹£eRYÈ<ø÷5¶‹–sTµ<*Ÿ*  ©ëhTŠ™”•eeG¥E»Aݤ*¨JªŠjÝU3ª¡j©[ÔmªÝõ Ü ‰ ›´€{Løk`þ‰T<­ í¨XÚAè]l8à v3zˆãÑúŽŠö訬íG“0xTÚø2jÓ†x0ùWÙQ³¶ÉA6zTlžÕ=ÖXK‡6~š &©çTûAhŠ'ì‚iž53|¨EÃG.{Š=&6ñÇdEâ1éç©í× öC¸húµ‘íPØçP6뮓ÇZÞ~(Ÿ ^#’ɪÔc2¨áócP‹Ý-¾5|.,K?&OµL*‹CÂѹ²SÿµŒj¹Ç <*ÿ>[Ž"(`VH]§Š¨ÑP1£4ãO,#XSФ ]FK9Ê(”7PFbAÜ!4¼‰Êx$ $±²‚ýURUX| Õɬ®fM U‹îo–ÍHÂm¡I<în“q­ªá˜LjTÕŒ#àö–üû½c2Ãg“Ê\‡›ñþ©tßZ¹”1¦ ǽý˜hØv×1±íFÉ·±e/èÀcО€´<&KŸ“—Ú…óôR;·eŠ“µÀwøKíÓ1j+M“7&±âÔ19mÆò³æYt7æÉys£-ÔD-0}‰úW FX5JMRÏm圹u#Tg+Úéoõ°•JÍ—¶Cü‹wg¿Epî[±œg€¡9š/0ÂÅìhæo"C¿Ä¾B2ÆUÆ)þ+-Ž[äØB1›¡XÊñ[Q3lê„À‰ °9fEŽæ ¦Î칚u™Lke-v´EÔ,Žt7׿ßœ@â‚^ÆPα2—ÿ *æQñ‚‡!7vØÆAG±/÷oñÿ­8™½¾•u‘«ñÆòùV¬ý¾•Uߊ»ÇÎÝÄè"z fB]¢.S¡ßŠÍ•oeíÕoÅËŒg¦—9‚Q$5ÈtˆŠÂÚ1 –ÕqT<²î~‰Škߊ§9™JáòTFiT:•AeRYT6•Ãv¹TÎÆå¥âÿ­8€BpbPò­lÇu{)Ê2Pn`Ã7Qþ³l¯@X‰pæKÙ^…²y ¨·@¸@#h÷ÀÐÚA'è= <OÀ Ã`”§Œƒ ðLƒYž%°^3Çñð€#p.À¸Oà |€A \¡ „oóÅ ·iò¨ãâcŽ9.¾æYÅ¢*þ¸|›'—×P&ƒÔãòæ9¿¤—_2öŠŸ9ý¸ü9d—ÿ”²Ñ(ç¸ü[îqñçB•òA(E ”—sõr-TÎèêoKÆ>±¤‰Xn£ÌU zŸ¸ªŠãР•X*ѲŠI5ÖS5Tíqþû%ÔmªŽª§îRx$EðGšª‰i3Öo÷Ál± e;è@Ü º@÷q 4?¤z¨^ªzD=¦ú©'ÔV<.…ê)5ŒlŒ‚10&ÁóãR§¦¨ijU³`̃à%xNŸÀÛò„4«óÔ…dv¦’ø˜Rƒh:ž‚a0FOŠ«i Á8˜S`Ì`¼§OápJ®->HÎ#qÎÀ¸Ÿ’X“'ïS’¼ØÂ‰/ð;%9&ìmŽÉYÁàa ޝþSRlÂû³Ì‰š( bNI…)v¯¤p×RÍÁT{ Š£â©*‘JÂZ×@2H9%õ¦ÔS’Ƶ[9•ŽêL}J,¹§$ÝœGåST!u ‹à™”¾øL*Æ*% Kæð¥Ã¥åHn€› T²² A5¨aRKÝ¢øgK+ð©Qn££:pÌýž(À]КOI†¹Á=÷©T+ªÚ@;ºï@ÙyJž,îT×)5uS)Tšzå}õ2ê£a¥Ç§dÌÔJ¦L˜óL™žœ’Ló 5„…Oy2?’,ó0kFù¼ƒ' Êq0 žƒ)0 fÀì)Éæu–Íë,{ñuŽùQˆÜ'NŽ~޳ÚËËó<ë^`å/©WÈN'–3ß!9Kû׃¶  È™9QÎÈ\`.œcÆdØâÊÌ´ØKÃÜÏKãäÏý;Éåðr9¼ÜÅy†×z€æñ´}‚?üeäEyS>”/åGáŠTþØ\üNòÌAeÈ'b¹È$˜ ¡0ÇÊ3_bt™ºò ºaÅ0p„ƒ ¢@4ˆ± ă®”H%!»’™¤ Hi 2A“ìï$QÃÄ7QËäŒÕ¹ßI†Då#+øNòyòyòϾ±-øÆÎÕ qˆ´ëT…·{®6ÏéÖ+¥¬-£Ê©ÔMª‚ ¢8¨DӪ豈Ï6K5’p Ôzp4‚fp<m tà v~'…æ.$Ýà!è½ <úN:ø#ÍníñwP?•öô„Ñ5øÝQæÏb˜ QO©aj„¥ž¡·10Îd‚šÄÆŸ'=Ú‚i0fÑdåÀøA¸‚A¸ô½ŒòÚ·„~$®‚§|Ø¢AÄ÷r݉ DƒŽî-œá#Â}­Èû=ÿ׈¨ÿ^f4|mÍhøÚšÑ®0J`]"&}/%|{—˜¯!KÆR@ê÷âhNCÎë:𱮣ë–š]àúAãLr@È… ƒRPÊÁ pó{Ñ*¿—uUßósø½¶Ñ°ú÷,Ý÷ÁÐ ³I?•ƒwÑSÔàf}ceÍ!œ¨Ï± g©¨°ºû8º?èo­ÐS7*=hÅÛrÇü±Þ²Ñ Çý°r5ÿîÖz¬ÝJ¬‡–‰ é$)T¬”ªûƒÞmµjõj½÷C¥¿D_^¶ï螶ô‡ÕxÌ aëw bU‰¶U Ô€Zpë‡Õx%óÿÝqï¤îbkÒÝlßÕ¯«wu”± ÉÖ¼ú=ìßzÊïI›ùþP“Z µ/¦o@]Fˆ?Ø7§Ààº~Àî$}¨;n{OÏ´Õô…Þ×_éw0}:û#.PlýÌz³ñ}=uefß¡àW¿¯/ØêzÓ—jõúÇè›>NsÖP ‚rá3°Ó\G…o‚î »‹b]„­~s×ú]à\²×²u×>ÐÝ~ø@¬nü¨oÄ‚Šõ¸Mf=lÓ:=rÓºÕëõŒ½ëõtP»i=ViúQ¿½b½Þµi½Þ æÖëóà¸o³^¿l·^}w½î¼^ôç›DŸÑvjõ‡¸[Ñ1ÊßC?³`Ìÿ¨çÛ}„;óG1ÌžÐÓì?Ö?þçþc“Ÿô¤?ÖýÖËê úÇôj» 88ô”÷í>ÁIúdõ?éìt1ü„{ï'1¡ì·Ã³<á¯Þ~Ò/Øë¸±ì–]¡ “¿ÃE‚1Šx” ñ'½Ìþ«?Å“DÃÓô'5'ì…RÛ¥2ºiå0Ê¥pzGÍyŒò©ø-P£B WŨÙyti…KcÔ\̨„*¥Ê¨r âæO8Ú5öz…ý§zåOŸ"©â¢jª†ªàækÝúIïYú)‚8ff(r­^k¿D¿gÿÉêÏp’>Ó§ßü 'ê3½ìG°ô½Ë^­þ\lÿË8,<(»Pvƒ‡ˆ{~Zý ²ppåÐOzë¾/ô<Û/ôÙ%_è÷W~¡·ïC»§?é‰wÿæëO2c>ý”g Í.Ú÷Aõ?à>Ç ³oâ‰ü“îöþº3Xø u…pw­ÐßÚˆ“Üõg;ê×–h?ßÄm"Õµe—7²dí£Ãa÷Í@fß7™]> dâGS{ìMüI»@fwÒé¸ÌìF¼ôžŸÊ9á°Ü~Kn¥ý(íëßh*7¾‘ä6Ãÿü©<žÒLή×LLl&+Þ¨î¾MGÌÛ²ò !“ciÝæÔŽÍåÖß4§Ù¹¹¼GExúF ùDĹ-ea ó>¥“(í h_ø)±ç~*û6h)O6n)$¶’»ÍwÜw䀭äÍTᶦ¹"Ý¡}-EXGûzÚ7о‘öMŸª—“ÜLûÚ+>•ëZSœýŸÊÏ·–ë’~ôSœE@»jO}Øšú°5õkkê×ÖÔ¯xI­=õ{kê÷ÖÔï­©ßñÒZ{j‡Örç«­åÚ·Ó~#­µ\Eòíƒßn-Ï’\×Zž#9ä *Òk­i¾i-ËÚ·–‹Û·¤,¡tI_Nöed+ÚËQTÒ•ÐW¶—3>"9ã#¹ |u{9òy’#Ÿ—kÀ×¶—ë(ÞzèÚˤo¢½œöÍ´4£z4iM q*ÃnªÛ«5N²oȲzhšÖÆlOkÏöø£$+ÛËå/#äàÇr@ýÖr•e?íh?Hû!Ú·Ó¾“öô? y¿MÝ?£Eág4¨ß V *_'èш¿“ØþA¯Ïhèã ò.úŒ CÃ(^]‘dõuß{reð=—,“©f¥p™˜ è 4Ch†*LAÀTÍUÅšÓŠ4§¦Á60ƒÒžù™¬õžœâ¼'ŸÖ{O>¡ýæ/ÚÐôDA+>“Ë5•W­,ê¦÷Ý÷åÊF­Ü_Ê;9Âý•Ü×H¸¸áùY`p€NVƒ Ž·%Øöæ¿–•´¯nK²Q ÷ï©cèüxö3yºQ’û<×èC9;ðò~½½(/7Ê’ç¬,+¾”õÃÏäõFI²Ï›É'‚R5~Ñm+»6nKC¸­ìóy[yðc:÷ý\x»­ìGüÄómå’ýi_þZ[¹¶][šDÚÊAÄË^mKSA[9‚ôa´¤}4íCi/¢½SÓ¶2Ÿö[?oKc’ôÆËáqù^ŸÎ õÝOäµ×>‘·iŸ÷ù'ríƒRi²)ûœ–¼´/ùÜý”úŠŽ••ŸËò¼qS·=ÉïÐ~‹ðã/Ð)vÕ^îþ¼=ÕqÏçd)ÃáÞ£ì^»•û©a\Ù–€Î8+èt/O5n%Ï6®//4ÊËñ_6Ÿ  O~î~.'×ÿœZøsÙ¹É4G|!;5i*÷Ñ\Õµ‰p¿¤ùŸü|.»7ùXžþä·4åþÖýJޱ¿vÿQ®o/{&fÑä^_vIà ¦ͰßÐ û ÞßÐáý ÈohØ~C–|!§½öœúÚ7t²ûBÖ"Qú…,ùâ÷9‚¼;Ó>ý‹oäÈ×I’>íGßÈ»Mj»ßÒ‚š:²ì3¹è‹oååƒîwrKÝïäêW¿£ï;Z ~'7Ð~#í;¹‘ä&ÚËi?OûÀ7kË5ä¨7³ä˜7[QßS{ÌiMй®û;9lSÞ´é\ð{*õï©ô¿—ÓÞ¬ív¤!Ò‘†DGi8t¤áБ†CGiHt¤®ïHC¡# …Ž4,:ÒpèHC¡£Ÿt›ß¬A5¾òÁUÀ5ÀÚt‚ëÐnn~!w¾ùyˆö#odå›Iî?Ñ‘þ¥þeÀÌÿmà6îíøË_”f,|• 3º:½BКʖ#êýY^|+$/S ÓƒrvêDz[ÓÿM›ÊÞMãÜÿ¤9ä?eIf’û_rTÓÿ–•™ÿ#§e†ä̦mä=»¶û¿rìëA¹ iHoš%O5mãþ…J÷9¥í_°6 è,}5~C;9¥þ_äÚF‘K^ù A÷¦ƒoÇoIÙöÁПìümà:Í¿@‹ð’Žÿ˜à0Éîdÿfà:Í¿@ ¾@§ý¨^ Sþ tÊaCš,Ë ËÇM•ç³”p; ©šµùÍ„›/hMLðÐ¥Ym٭ًng–sߣ)¯³ ãŒiÑWtñ•,r“ä fMåfMÖ¹ -‚;mÝ.‚äà–›?'! å.9¼O0ò+‚Ñ_ɉͺ 9‰R˜ÒLÈiÍè˜-þJ gI•ÝMÈ…,ìiF0Å!¸ï"°;»#à`3‚²Wî‡ ög†í‰›åÐVÙWò\³$·‡Ë¿"8žBp2¼NcöZ3[ö¶n¡   ·§k^%X èÿvÀíE×Ü$z 9²1Á•l‚Þ4õn_!Ǽäö²€Rè/äÄ·k»„œüv+w 3Þ¦‚4RÞD5° w05ík¥u ¦´%è m`"ÁÜ·ÃtIº8Çå«×ñ¹¿&X—C0Úµ¦tt4¾'®mgýŠ`w{¸4!(á+_ø†~í :=!k‚ò׊„;‚µoÇË9ÄÜõ6AÑ?t‡S“QUFÐAü Áü—…Ü@§EZ‘ßz[¸#- îP•ž¾ÝJvjÞ”ÎèR±ƒ,o0JÈ»õF w†Æ„˜T;PEÉö󩨊䴫9±ùëóãW´'˜Ü  šùZ6A1lwëL{Ÿ`(¬ù¨ùüøÙõh)Ù¡úñ—ä„ú£P?‚m”v5äRmU‚Õr`åoˆ®¶0¡åÐA—&¥A>M!¨DVÔóã·  ‚³•`+û¶¶v0ýœàJ€`'èt@9`W¹•Š&7"ËC€;ñIò×ñ²kó,Ù½9NºH}Û.ÅŸÊ$¸Y—`i‚¾ÐÎw ˜ùÁ‡`2Aéß\@ÀEÀ%ÀeÀ ¯®B»¸ K±K¸˜»¿ö#‚ÃíÆÓõÓ]꼇ÜÑ4"ri®íö;†ÊRHg¿;ïP‹Ž²×7c0R zCëè (o0 G³íüø~ßôôÿFöjž$Ç6o*‹INhtÇR“«Ë“´¯H¯!ç6o#—6¯.—“ËÊæÂG=ô#‚Z´ohNGÍåÔ"Wã˾¡F+F§ƒi 7ˆ4 Ø®må¸ìL¨_Œ¢ ·£Œ`¥·ä§YrJ"Æ wzƒ`ó«}Zš4èfwZ ÏwÃÞŸÉ‘`HËHƒ Ö œXè$¶Æ¥SÇØ–MåÌ–ÂIóV‚å/ìXû}'WµL ˆówNßÑZ–ö¥´/£}9í+h_ý\ÓÒ‘[6ugS´üPæ· ºshô·ªáÎ¥ˆßÉ¢ô¹4^&8•Ipü%²ß£ (ºô$z³fPŽieºóh²Ï%¨5C…`cC‚»©3^&8ñŸôÌû¤kÒ á a‚ëp¾ ¸öAøM£€€ü{ʬ×ç•¯Ë ˆ:0P ^?"ÿü¦óP°ƒÍ*°º­ÀêyeV`uKpìõå’\Z˜½;H¸[…ônH½Û*P7á÷î6Jñ5‚©tŒü^{—®²ÆÕˆ#ñîv2­ý=]QÐ~Œöã´Ÿ ýäïÕN‘…¿Fü:í7hŸØZ®~¯¶{Œ&?Jâí§ßÃ`:NSõk7×7 Ü´ÎyýFà xÔ:!ËdÏ¢×tâ9ñüAÖº‡‹ ’ò˜¬O~ý_¢ÅåO/ÑÙ· ÕŒFäŽ6aÙõ—…ìNà’,9Ò˜`+ §ÓJîkó9êçW°À$ØÞ’``^M‚ÐŽN š¬kBp‘h@ ûC@ §}íEßÊ{ÉtØR¡ì%í^ÅBç*fÛòWiH=ÖÆ”ÚˆÀ9ÿ—R´E7ÉýN›€{MÈ©ùê^Ç@°0û:e2¿y@m)·6¸A‹e‚€¸Ø’ŽkÚÓ¾ö«-] +øÁax©÷i¸Ó>ž.Ýû¿ßT|?˽‰«¤›¸|"íè*“o"²mèp/7E`EüÑ?œœ\{M.¦h² °°ü7ì·±Á¹?Ðå%°Û¤€Áï·’£ßº·Ð»·4Áî¶%oÜ•÷-,­ ¼v §Ø[âò«†! ì´Y†)„¯h€aICØVH… +Z5Òâ’ ÓŽ—*6ìÌ.†ÕÅ6‚fÈÊ)¡?3·‹0Åß©j†ù9 óy8£*a£&%~QÕ"ü±ªeXµ‘|´Ÿ@{‰´¸:œÑOU­Z:ƒŸÅ2øyÃ|Ù0ìW(ÿW» ‹ºäF™¾¦^'¬§^7ìúþÕ¡%(rV¿(áp-ÃnDAQ‚&l åM‹±)c3`bsÆTœª¢·DÄVêªæfkEê»±êU{ŸÄ/‘ï¯Ô¯ ñ÷Ð> Íþ2þÄÿ 1ã#òlK–‘Æ'ªÙ?…=šS{Ÿ!î窽!¾€ö%´ßBû Ú×Ðþ‘4³iæ7°} Ûwо‡ö;h¿‡Ö~?ÀïÐþ Ú?“fÿ òÿWõÇhÎ ëß Ì ý¡¹Ãªª5uõ?«ÿøQ]ü§ PSÿ—úoÃø_ÏþoL7ÿ‚,”P(Í|2$uÁ ê èèN „aÛÉ5R’z‹;ìýuz3ì>äc÷¥f¶“úqJFQ•…Hƒ•#É,Ô*^ìC£ÃÈ#ÉŽ òAžÞx)”a$BF£\c Œ8P¸’há&ú W*ôfÚÉ)“„‚jØ“QÎ)€©€i\âé5ì°Ì„%< a§ÍÑ2 …ö µ_˜¦)ˆüƒâ  ¿CB¦ð#´gW"ÛcÈé8çtB(Ó0OruOA§¡‹3ЫÅH;ÇçaȾNMp¼ÄŽ—Y¿ÂúUÒQ°k†}õ¾¸ ¸¸Ѽ#Ô]®ß=¯~÷Å}ªÓÚÉøP(p2¡2"Ç|*Ô1!Ü2)„z®“©Lù$ª¬P®)ºÐ!„•“+DW“f[“ÝÈ#Ôn&ÊØÃT…ñw=Aþ®³7ˆÙ‡‰èËný´[v Ý²Û M3¢ÝŠØm¨Æ!Ãuj#8µ‘šŒb2Z“1LÆj2ŽI±&ã™LФ„ÉD&v)‘9‰ji˜“MßÌ0ÅGœ©äõœ3ÝT3LñÜs3!ÍçžsfAaÓläÌ4ì¹äï<7R5íçœù¦šjN¥~|î¹QÕqjÕ0ùr •¡p¡Å¦ZbÚÙÂJ®±Ô,°B! ÿ2So4«YËLœ^–˜Kˆ=o­  j&ÄJD^B½)VA3ìÕè°5€µ¨­X‡r=/Äz“¦š!¬nÐ*Í¥Bl4qž¡òPZä½ÉÄ€ ‡³éÏ ‘©œÃ1*"[˜U˜Ø,‡ [Ù°ÍÄfÕ$Ã6ì4±Yv±® h³ª“a–šØìPr(díåáP£ÖØÇÕ0öÇÚÉ2RƒÁ¦âó+&™ÔƒDh68dª%ë°'@ê³ÜQD¯D+ã6>Ž Û Î öóÉT¯“Ì_ ?a¿p~fÈ´Î˜ŠŠd‡Îzi ¿H„Ð=vÎ,ôz켩7ôØî±‚Ò¢»È90£Ö¿dª^°H±.C{½x¹ eq•ë`_Cѯnp/Þ¤â ò-ŽŒŽ»ýlÇÝñ:7î¼{ìC5åλÏì‰;ï!NšØ¸ó±f?î¹ÇÌž˜Ø¸çž²AYØPÑÉB ;ߢ‚v¦bÙF+Ú¼wµbÃ]t#ò£pûQ¡¥ˆEz‚Dz1y±È‹}™ˆ~ ¢?kˆ5P“A”Jd0G–PHh¨&Ø gbŽ1GêQ2šIx Hx¬.Æ8N­X»·p˜`¡®–¨eNd•C­Rx˜4†&YzÞ-° ,:¿Z8¿¦¦!µZÓ9%hÏà|grêö,4ÈìX«Pj¡9¦ÝPh.¤aγtÏZó¹Ú ,µ”Eh¼2n¼Ål‰,áR/eòâ2n¼åÚw7ÞJ&Ö*Neµ&kÐxk9â:¶„Ösé6h²‘É&&f97Þf²…C*˜„·rãmÓÅØÎ©íÐn;¹ñvYzÒ¨eîfmE ²$÷A¢÷{Hu¶ ásáÈäl…Ì£–ª´*©qAŽsvö ª¥:ée(èd,NYX‚Ø¡Ði8QtRÏhÕ¦³«ažÕ›°|^—ëǬ÷e½ëýYÝÝÝló)zaÐë ‡=4ºeó)úOÇBÿé8ö/fÿñ¤‹Ÿý¬ÄVA!êä•ڴب“7‰„?™ü¬¼)¶ºgYV$bMµ15Þ³°?ŸT~>“K9 Õ™mSGF"sÈRÊ\(†1Ïö»çûÈË Aù,¢ŒK¼ØVKlÃ^ŠeþØË‰ˆ~ËJd¼ŠÛhµ­ÖØt¼0Y§Éz&4ÙÈd“&åL6k²…I…&[™lÓd;“šìd²K“ÝLöh²—É>Mö39ÀDäÒ!‡QÚ#/%°+uƒCàêq­Òñz‚cØ'áwÊ_ãÓHã ଎~ÎVçíóýBL½¨ÕXÓ^B”Ë\´+¶"öÊ5W®3yñÈ‹7™X·x Ýf¹Ãqî2yõ>È«˜8AœGšŸÎ…éLJBJÒ%^ýñ]ˆ®ñÿ¯BDºqBÝãyØu{@Ò‰‡=5éŤ7çÕ6d×7^õ‹ïGuêþ¬4 vñ> ž—yñjP¼á q†0±Š8d¨&Ø gb`22§ðQ”ž1:>6»EÆ1ÇÂͯˆYÅg<“È.p‰&É7R ˜˜ ˜ÂSÙ¡Þtz3t:39YšÌf2G§3çæsìÚ¼É"Mʼ˜à¥%0¿´T›—±ÏrMV0Yɤþúk™„Ö„Ö3±7puœMH·<ž&rËÚÌí2&~ uhÞ–xµ™®(*|cnåvÙ¯¶S‡Št€ù=v±Çîxµ‡¬{}!ƾxÿD¹?Þ[@„ZãÕ¡ª®è¿ÃñtiaYGâc[4ìèÿOXåÿfÇ|… G®Áñê$5Î)nœÓL¬3Ü1gAâœI#û\]ïÏ Ðåz5ˆn(Ø|n.›±À×&ÎBÔYPe”æ/–xr©–æ2O.‡4Œþ˜+)f^Þª€Z0óòœ5PVÈ´šÈsÖyr½–bK'oc7£òœM5^Œ§kËŸ•Ôæ&-® _.¶1·s/ì(bæN²ÔÛK½Ýl±ö%~/³k³ŸÍ¥ÑA‚:‡~rôAý£äeŠÊ€:F‘±Ÿ ¨­DNSpÞÀYÊ©Në\@_òqh[ç9eûJxÑ7€óÌKT¹xÓid^¨++v£üAä:²¿í& y‹Àº’Zwê.e{É}&MÂçWä1[=å)[T,‘N Ô*ù h•Îl1»%Ò5/Á´Ow&Lêõ©WÈÄê ß^€ÞN„9}9ÌéK¶ `KÜÀ~ž4 é&šCP€"1” Ñ0Àp‚:# D"£8‘ÑœHý1°ŒeË8Xâl´«8¡€ÎåíH[o†5žœ­ †çT’Pø7N‚&&`:òJ}ˆ“Ð'46'CÑê­Ò°œ ¼¦iéL÷ä -ÅL–NÞ¬êPŒ×Ùºh¼ÎIPh¼ÎMPóôC¶ù ±§l ºæÂ¬[pŒ”E˱8šyÞ/³¥ž\æeºÜËtE4Ó•U™®ò2]Li5K™Øk "ëГëøâhƒv‡ºÑ‹iŠM êßia‹VÝœ€KÜ-H‚F}…Njkß1?¶žÜáɞܥå›{<¾7³?«û¸“íýHç­ƒ:¼éaÏïH•_âQÏT©e³ã:Þ ÎÿdB¡ç×ô”—Äi-Ïè}=GÎõóÎ'¨ ÆKÉ’w p9Ÿ˜^©ªôUª4Žàk ú¾žp=²^nzò']u"ª;NDÖ å»õïa ßç#íA‚z˜`Ô”€Ùãq‚zBY>MÀ#[%‰x£µ“Œé‡ Ñg¾ä“' «³äù¥‹Ô¥ë*»Jšw»IÊ‚dw-›@z%ë!q_Ù,ÔAfOrzáQ³ÓÛ‹×Ç“}£ñô*³œ"ý¥ šAjbb–|d"Š@ÄPš,†±12œãŽÐd$“QLìÑ’’#c“uã±l¼=ž *&HU"uØD’V)?ŸÄÖÈdNh “šS¹DÓ˜˜Ó¹D3˜ˆ™\¢Y T¢Ù:îŽ;W“yLæ3±H\0Ô\$ùp(ƒ½DB]¬UÃ^"i…³”Â-'m™TËårIª³B«x2¨³Ë[¥sXÒÖhcx­–o®óäzOnðÂ7zr“'˵l¾%Ö´Ü1„¨Xñˆ­dt¶!d;åcµØ)U¶!vùZUìæFØ#Õ^²îó‡ìçR¤zB#Fð¿ÏQ"Õ+a9æ3lj˜'¸­OJEJËÓ -Ï0‰œåf=§Éy&˜ˆ‹œç%r™C®hr•É5M®3¹¡ÉM&·@ðñ6”Ô*‘;^µ¤¸Ëå¹'Õ}ø9 j:ÎC:x,뮼+…c>’JØ6-HÍÇt°é'²pÄfØO(Óy*Õ]Ši:*¨ÍuÂ3ùü`ì¤m·êT‚DW†Ý AÝcáxpVTú¹ŽñN!Bz­WPõ ѪOPèš´/ ³fÍšý‚ª°P8b%ˆô@¤/Z·TEAŠ8 {%eGRïŽä¤L1*¨F«â½qȬ8è[m'œ€8Á’ "ÖfH›ÉLÞŸÄ£×iA\&LGò3(n¢™ÁhêͰf!åÙ¾ä9È|®ß2/è_ŸÏzP ÈZˆ¬k- ªØ »A·âbD[âOhiŒÄá !– l<âB¡ôµ{x¹/7¿"¨VMjºUPH %…VÕšàš ­ƒ×Õ:„Zëu¨HJÚTƒqV(‰þ6!8º™V’(ר›µ*¬¤-œˆJªªêÕ kk¯ñ8Û¼ IÝ®UÃØá¯ÍN]þ¶©¾ÛkcÏQì%bîCC™ûƒŠ˜y€ÉA& 4< B‰¡qF§/ã(8YlQÉn¡cAØ­ãQ»u‚cØ¡“nœòeù˳Hó—ç‚ê³1Žˆ(ö[ƉLà*–„ÔDªo)“IšLFð´ÉT.ø46;Ó¹f0±frÈ,Mf3™ÃÄœ bÎÁ)p>­.Ð*-ÙQkð2n’Åß^â³èÒ¨ó2Ôj9`Eceˆ¦Ç«(¤.©?ÒŸ&k4‰cY«ÙC6MKuEÈ\*DߨYÈço·Xsm ý徬³ ®SR›©ö[P¶ oõ7ò64àv‚:;Ø{gHíâfØ eu~Þh†½í½Náý°<àɃìQ•æ!”ä0·Ö‘:ÊÉUB9òÍ›ÇÐBÁã!¾ÿR'©KOq‹Ÿfbar·mÙhŸG-....®®®®S÷üÚ¬s3¤n…nQ¼Û”X¼;!u7„Ó¨NÔ¼ïÉž|¨3y„£ƒMó L\‚§XՏІ·è„ç‹"?¬À:‡ý§….a,õ¬®ašú#ÝÂ|ÿº]ÆC @! ' W؈û{êúH¤O¸À´-:ZÃÑͰû!víþaœ‘ÍZ DZ±ÜqnáÁašì {"˜E ¸yÃFÿÁš‰„‡…c+תƒuxØ7ØV;æù‘³+¬v‡wS>{Pk/ #DÛýau€ÒùØqÁ‰Øms¨ÝöKë“J] OŽA²÷ñ¨7³ϰ“QFuýıNq‘9€Û÷Þ7O‡óѾžA·žEgC/Ÿ\àÖ»¨s5/yò2KÛ¼Âíl]…ç5Ä¾î ŠáB^“Ú7Ã8þ¬[aÜ<`SÕ ¼í¡wÂÑ›!wÃÑËË;áèFz/¬î£C@r«?äJEÄ#ÄÎOÑÆížòn§q˜uJôe˜OÄ—ÛuIT]IvcišÝU~" ‘vPò)Èì :Ôáÿi/Eí„Õ;õꚨ·hê¶Ñ^˜ŸõKŒ½N©o›ôGts@¢Hi~6HËvƒ=9„¥e%ª±7­¡þR‹+ô¹)F$ª‘‰Ø c²ĘDõ0Þc™ŒÓ¤˜ÉxM&0)abOLÄky¥H©jK×0Ô“¿f“}…øb*b1-QMO4¬üþ÷L&õfÔ›ÍÄ™Cq¬¹<-_.ùr!{:  °°„¾üÕÒDµÛ_ZËyÀš†±<Ñ?¯HôVé+‘T­U‰jµ¯ÕiNüíÚD Lˆz\çk1<[¯ëd¿¶ÇÄFënJij›D~ QÙ®»ÒˆT°q«&Û˜lá$w@ÃF©îd—ªW wÁ5´;QíI4B{™ìcbìelxðw€ .¼æ6|uLôÞ€1%Òå˜ýÕQN% Ã>–ˆãôx¢:Ac(x21? ¾rN%Ò5öW§¹íÏ$ª€ïŠ/t6‘/ËÏñX<Ÿ¨.$_]D\JŒöûeX£Û3ï~_IÔ3òU˜¯®£—o$â ­eÝLT½ªúÙ·xpÕ½ëklë—î~¢z(êX¹ÃÉf<ò9‰ÇDZ$µŸàŸ!ìŸëN>Â|T§WÉéÓä8“šœD]Nq]Nëˆg8âY|Ž}Ïë¼/À÷"û^ÒÁ—9ø û*Js-×yååÝHRsªãéîM(s`ºMä9·9ÈÎsîÀñï&áð½h”ûUQxQF£<ŠFyŒÜ^z¢ÇkÞSOªä|–’5ÏOæòuN¦ã¬  k2Eû]7mîK  ÐÐ ÐÐþá¾Ú¿_2à É ¶âóÕ`hP2Î(º`ƒm (™˜d=ÛÑ1ƒÃ20’ 2 000Q"ã8‡H1,ãÙ2ëó/bb²*M&9 Ò°'#)É|;rj2· .§%ëÓåtm1ÌHÜɩš³˜ÌÖd“¹šÌc2_“Lj²ˆI™&‹™,Ñ÷4—&« IzÓ†e1CÕM“-Ë“Ÿ]ê&ûÛ ÕY¡ u¥W³ŸýlU²ZLr'×zr¤ñ«õhŽ y¹é7y£ Üë~!t³N ]µþ€­Ô†5ß²¶q_mOÞžŒÇ ;’±Ôå¬-±3YíJ&¹Ò{k/)‘Wö%«ýÉÂþñ$lþ«°s¼-I[’ð°æH²:ež¢êÿëÑdU‰„űhÝ„8îÕŽJŽþG!N%«Óɧ)é3”G‹³¨I‹s\Kœ÷JqKa_$Ð%®ëexP…u%ZA W½¡pÍ öuÂ7tô¸éÉ[œ7Uù¶çgÝáN¾Ë=þo÷9‡Þ@¦Iè¡ö¯ù§Ç¾ÿ$™®çÚÕüÓÓ*¬øÁwªÁÓg>ˆÕ¹çZ«‹'»r Ý ͺkc¨€eHô¨AF+ÍBmÿ¾'KÓéU£€’@ñzS<óû>5Ô*’ù}ß^‹†ûÕàÉ Ü_G}k€'²´òÕ@cÚ/ Öö†h.òäPOóäðºb¤ŽÐ¦åöä-?«¥;γ{r¼—õ„ù»’í$ºú5J(UØXCo¬^ŠšbR šS'×0L3IL‰ŒÖTÔõÛi\Wº˜®íthÍàfúÖ™YC¦ùzV Ü3%0ç¼40¯¾O,¨Ë……\ý:y‹¸Ze5È´&:ÿ‘Sd)½ îË¡­ øó*tÑOWsýt Y~º–-ëØòÍzo6èºZuŸoªÁ—ˆå5¼1ÿµµY«± Ã-5þúÂð¯g ¾5¢Ûþz+'ÙVƒïªè´åÜIPwW žw{C!bí©C’Óˆµ7¦î‹©ûcê˜zÐSù:úG°±á°Ï@ÎGbñŽÆÔʘz,š®£×ˆN.¨Nø FÝ“høS€Ó_ŸA­ÎÖð]hžCØy>ž.ÔPĬ‹L.1‰\F^!È» íàz ÓˆÜÜ$ú·áÿwtä»ùžŽ|i?`ËCüˆÉcMž0yÊÄT)˜(:¥pH~ ßL²»¤àëü“Ö¨v÷œlS¸czÀã\ ÜYIÁàƒjõLAZÇê•Â7vjÐÁbâ. §h÷E:ýý‘ØÀÀÜ_ N¡ùDz¬!:q¤Ù¬:eOÓò?Gx|¤–ñ£<9ZËæc¼ð±Z¦Óò¿Æ{ö ž,ñäDO–zr’''ë‚Oáv™ ‚Yvš.¡ñ³é°7ÁNU=;ƺ³Rø¶áì^˦DoÎM‰Ý6œ—â¿mhÌO1ž¹«i.Hyö®æÂÿs[3h†‚Ö¢ý¦Uô“:˧à6àb´-n‰/áXJFªÎ2„Ån퉤å)úV²ÄñË Á)j¶ˆnÔr+Á)ê*-ÓWCún-&¯IQU‘צ¨u)ÑMØÿ½Þs«Mh"£<w">ÛL‚ÜÄ–”üŠ” J£ÝVh·-…ߎ¡<·§èÔ–¹#Å÷tÌ0v¦øÞ¶HÙ•¢v§˜vJÊžµ7eoŠ5÷Ádû}~vÞN?ï ‡´8ŒbÐ@?’¿WpÔÃHªLÁ»¼c)ê80ï„'Ozò”–ÖiH —3P F"gµJ#û{YyçSTŸDúÀ#ì"ŒF“K M.3q®€8W™üÏuÿ¹Á¤ªÞ7¡ß"0oóÁ|'EÝ¥ãô“ûL>iøåxån UçqŠ^a<ñ,¶xÊ1B*•ßÑè”êÙ­|h¸Õ{˜G#µfMÑ%µ #ªH†»¦>;¤kuK}vHwOõM‰DDTÜU®Y³0U?hÄÛ1kðêHÏTµ&hÙ)5köz&ȽS±ÐGä¾ÐúùÒüßDþ2˜À’j$ØM”hú=æþ¡TÞp©˜ñ¡PÿÔg7jýa© R ‡4Ĥ<)òyt*χcRÕØÔ±©¾›sãRÕªø8»~^“:õŠ¡G7atR½›ûá ;c¢–ùbRT™ì…LñäÔhÀ´¨2=ªÌˆ*3u¦¢~^gaÍy&W ë¥4/ê>_+áž\èÉEQ‡²¨²8ª,btKS}? ²Íe©Ê÷ü²ó~ZžªN$b3 jõì`¯LÅ›hËÕ©x«vM*?Âxk­'×iÙt=$ƒ¦æ†ªdì¼.b“ftì—§ªÍÔ?M·èá /æV-¼ 2öÎvÊ3¸yw¦*bÖ.k7±DìebîKå×›´Û&™Ø‡PíÃ5¨Í#©˜Ò|ÃÚ9ŠWÉK¥)7xœs>Ý:ÉöSÐÅiÎ÷ tó,çtŽ}Îc,]`ÃEìK©üíÊåTu%õJ*Ô«1õZL½Soh5öó+]EÒ­TšÏX»ÍšEÚ:žS聆š5“ê÷R± ½ŸêߌÐ*9šõ1¬…nsðôµØQ#á†Æ;jÕª„aŒ%_Jº3 QÉŽšâø‹NåšF§!hºã@0ÃQ3at³è|3‡Mvx®'çyr¾–/,ðøBO.òìež\ìÉ%ž\êÉež\îÉž\饳ʓ«=¹Æ“k=¹Ò´³óÖC){ƒ´‘¥emrÔ<ÇÈ.ç¾ÏÞ\å·…+‡Øáì Oy[«˜ao£–±·£Ã;¼„wzr—'wCÆV65#{>Ïà¯È^‡? wð…]Íý 5€ð¢î 4l´¨;¤­”Êá¨5ÖIGþQ•Ž:Få:îà×¶N8Ê÷¶~ÞÉhˆÓŽºmâ Å,g ëžCüºç9 î"Æ×1¾¾„€â ‡ôWɹÎ5Øž»Î¦çnù:念NÇF˜¸å`áÃŒž»±!dVÉ÷~ׯvßwªÖŠâ"=D¤GÐ;øxà‰£žÆŽÆOqÓH¥ñ r üš! Ò Ñ—d}oIðb ?Í÷Ò}ç4…¢k¿uß--úž¹èžC6ô (V!,VO¶Dz¥ñǰLjö©Ù—‰ÙÄìÏD àT¦éWð鸃9îMŠ˜ eò§a”ÏŸ†Fˆ‘{”Nj4“1L¥à:ãCòMàò•°ƒ5‘I){R/&§y/ñOIÚpÆÓ`CàthÒªeFšš™63ͰgÁo6ùE"s`#9Ò°ç¥ñóÓÔ‚´iø`¡V©ê‹tmóÊt#Ÿ´%Ú^ªå›Ë<¹Ü“+¼ð•i“¬®òL«=¹FËækÓ|ÐðYÇ}^Ÿ¦6PÉ6róo!Y®›Q‘-\‘Š4õ0žäV–vÓmìQ5ónOó/ßv¤ù—o;ÓžÝhù¶+MAŠÝt~G>{1¾öùÙÿî§ M¤©ƒd=„¾:üL6GžÉæhÚ³eS™¦ Å1HCG6'PѦ'uHÓSk”Óiø ÿ ÷ñÙ4uŽá“ÝÁ µMÈDwüñæÑÞšHµ …J3K3ihL‚“ µ˜LYþ‘ìSusj&unƒ"1=½;#Ów”Ìô“Yh̦³3Õ*hÓ¹Z†çAú‚À)¼ S-Dà"Hß½ú²Lµ8Ó0—­æR,CËý¹¬ð“•DìUøYòÕUæ5™þÙ{m¦^èƺLÜ 7Œõ™jCæ†L¼)N›(¶°ŒòLµ™ZÂØÂR8™jk¦pœm™jy;Û½ø;t|ß“‰L|áìÊT»3w“¾#b¨Ø—©ö; ÙA0“çP&žïϤ@ûp&äeååÍT•™•^ºÇ2}/E¶7óÐ1Oðˆ=™©NeíOƒ´?ÃDœÍÄ#sðy¶˜˜\dÒðHÃË:ä ‡\Õ¯QÄ×aiq:¾o²4Ä­Lýðà68‡Üá8¡»™üðà^ÔnÝ×1C8Ü~˜‰ÉæQ¦:‡‘õ2ÖZOžéž§™Êwº&†Ó–ŸÅg|§sÞ;ê’¥ò³ðÞQW(ùYdêMä9Ý=Y ¥èÁÒÉ+ÌR=³ð>R¯,µ9°?DÑ;KuÉV^Ÿ,Õ5+V˜¾Y¾/FSôϪúúb…™³ø'–³Ô`R†dñ§—š e2Œ‰9œÝFh2’É(MF3£ãŒå8ã4)f2^“ LJ4™È¤T“IL&k2…ÉTM¦1™®É &35™Åd¶&s˜ÌebÏËÂmÈùY¾/Cø+€Y¾Ÿ€_˜å;Êeùnˆ›#é€X¬ûÇp–dUÍóK³ø0ÃÊnY–Zžµ<ËpVdaÞ_™Åóþ*Xàj°à&mÖ‚´Y",s}ž{Ù²ðëvïoÊò>/Ϫú°+Ko†µ™Ú–fê-Y¸bÆõ&ߊ,ïRÃÜŠDqTnÓ¥A¶kÛáìðŒŽ¹“b„Iîòän–¦³'‹Tj/•#´fá@–žz XÆ!”šå0GΑ,u4‹f‹Ê,ž[Žeu‰~u<+úT´˳ø«§Yü­Y–N1|’S¤“µ'OCZNȱÎdaU¥¿ø²SXg³b‰Q¹•¿˜jõÁŬ|2Ø_⦵C—¹½í+Yüå¤@W!³g5ãÕ¬|ÊÉ6­Ð5Xšy­m_§·©7¸Ѳ“á¦Ï`Ø·¢b¤¸•oÞÁ1t—àƒ{Ö}Àƒ,|Þòy‘|äÉÇ,mó Õz OÜÌ7;¹&†–ïzŸ¡yyuvið|ÜÅÍçzX]ÝhAªÆu¤Q$ÒÍUÝ]lÌ ¢Œ¯ƒB=¢´»kÚ"…®Ò¢EzjÕ0z¹¾C¡·Ë¼«ô Q5‹õuq·£ŸË· ]5À5"ý¹¼dìª!îª'Æh1QF‹a®î #i„«OV–éªQ®‰Ñ®ã +4œzKŒsUgÑKÃbW§èü•øÉDÉ+ENy“\5Ù5~;ä·S™XÓ@¬éL"3\^ø3#fƒstØ\›§É|& <Ç…ÚqÓêe`ÕƒXvžK ac¶4ʨË ÇýVD"¢ÉrWß.u£9¬à•®ÿêN¨UnüX›,k­[È3×:7¶y>qcE.ëÿÆÅ06ø[j£Ÿlò“r÷¯¿¦wB›Ýÿû]±…œÃ®ÿ×yHlsÕv;˜ìÔd“Ý ¢¡Øãª­.ÿ4Û^X°á »Oš¾÷³£%¸Š\ï K[òì‡=~ÄãG=^éñc.ß5{IZâ»Ô4Oºje:¥]Ó°{?ÎvÆý8Û7º¡hgùxCRtñ@U¶Ï£Þ|•op‘ˆu‰G×eW ]Á}•k~ à×]Õ?@-pÃU T¨›®ºEcò6¥Ê¿Çþ~¿ï—ﲓqÏ7(ƉðW=tù×:²ÍGîßüZÇcŸw±?u•ÊÖO.ø²ñäBç¤'骋F'?›êѯÖt!ví–÷²}«‡ñ4{d«ÂllteõÌV½²{±Ú[«†Ñ©ôÍæÿÐ![õ'e“š b2X“!LŠ4Êd˜&ÙŒÐd$“QLìÑÙ8½A1bƒp,éæ8”µ8Û¿öŸ¸'Í.ûÄgBK*&eû†É>Ûœ’Í—}Sµ˜–­øù˜ž­fdÏ Ç™þÆ™@3;7<©ûæd«¹8yÎçÒ/ÈV IYĤL“ÅL–h²”É2M–3Y¡ÉJ&«4YÍd&k™¬cb¯ç†Ùí»š½Ù›²Uy¶ig—ˆ-ÐʳÉVM”ˆì­ÙмBÛÈÓÊÞž­Žâ–á3Í´3Û»ó¸+›¿ ÍÆO•GöOh/Yj™ûØac/²z ?¿~0›¯…]ëG±gë_^?â9aíEð-þÍõJ­â½hÂ~å8Ç x¦H'½"ENùÍõO£C³Ïp¥Ïf«sºÒç¡C¥/@C¥/f«ŒÐ%®óålu¥j(‰‰B\ËV×Épƛܷ²UœaßÎÆ£Î;ÙênÌ=dÞ˦S%]–‡îg«Ù(è¡@=¢:[¡ÍÇÙêI66fO£ í¤r˜øž3ä°ççp[øÞÕ0CÁÎ9Uï%ˆ.9üÕhúì«n9¸E(ÈÁ rXÕUVõ¤ž9UÏ@^9±r–Š>`}sü·ûå(í&ú{y;È­›ˆ,º‰A9jp.ù!±-‚B*­]‡æ`í:,gX-<‡ç¨9z¹;2'ºÜ…'6Õƒ» £sÔ°,tÇ@–c„Æ¢Nãrðÿ¡bã%€‰(ħ¥È2úý·Î^oXÌLÖÏÐb䦿ðo·ä¨é8T̈*3£Ê,(†=›úƒ˜5'kÑé9d³æ¢¥æùšËósÔ‚Ã!a-Ì)ä·ߣ?:*å¨÷h9S–£S‰Bb <Pä¥9Þ«-¡Ð2m“„X™Ã¯®BýV£¼k¨ Ö$±6G­Ë²Šamðbã¿dAÒ‹sHÛÄ™àaÑ&ÃØìëgc ‘–¨xË­94UˆmÐÅvè‘9|¿Žõ]¬ïf}ë{YßÇú~Ö°~õC¬&m~„dŸÀåø¿ã6ÍÊeüÍ/XËùüx´°ëÏQ'rŒÈINý¿±p6üDô™u6çlÿDô¹h@ìMJq>G]à&¹å5¡¸”ƒÛqB\ÎéÂAί«žjÕ×rô­.ãºÿÀÝ ZxoŒÞ¤ƒ4'ºÑAåœ,œ»9ê^ŽáܧXÎ ݇|8>‚3ÉÇž|ùÌÃO‡þ¦aÅwÊÕO?±þŠ>©z?«ê…ƒ\ÿ[l¡©¢Knìðž*ºRp¨Ó=óB.~É®G®*$¥',½rýK™&úæò]ü~¹ª®0“䢿ú'áA¹Þ$<8φäâÙ@(TÄæA¹¾WŒbÑèð§%Ȱ\¥2`¸¿ü›/¾94 ŒÌŤQ¹Øèà«Æ@Ž…ÄµÝ¸\G×VŹj|®éD"r|ñÕX%¹8^udÓ™HsûD/”fÒP©×V£s±Ñ sâB¡I¹…vô»À†29S»¢`NÜ–Þ,Ó ™Ss 9Å1¹Øâ,JOó²Ÿݨ¸ÓsóÇçZp˜‚³Õì&f¢Z(œ9ëÙÂ9¡å8ÛŸ£é¤¤Ìц8g€ K~'nî3¦7 Ž¡6ïkèj rMÃX˜ûì[€áE¹Ï¾ÚZæëìHdq®ZB†¥¹ø5ÿXHüÓEÝ!êX+r ã¢%‚Á•¹±Íž!¦‹ÈLa­Ë-ägù¡PýQÝÅú\µ!72]ÔщlÌþúH08Åñoq))NŠãlÊU1›5)ÏÅ{ÎMB›sÕ–Ü-¹¶á8)¢‚RÑo DÏ”[sù G8)ÛARv0qv‚8»˜˜»AÌ=:d/‡ìcûiÇ\¼š} W¤n‡rñ+G)âp®Z¤µÁ‘Ü|²×GsÕaŠTéÝLj˜Ç9ƒ¹ê$)§¸P§59Ãä¬&瘜gb_@–æÅÜØ¯úâŠtpp•ý¯åªë¹ø¸ ßvÝôÑõÜë”Î-”æ¶¿Hwb$`yßÂÜÕ‡&ýí<ÏöçàÿG×›ÀU±¥y‚çDÄ]âîäKr©z•ÈD®€fÕë~¯2³òM½ê®¥gºúU×Ò=ýjËÌ×S595U¿ªÉ꩞žšA7D6AQ@T6AQqÁpAYDDÜ@P\qþßw.r}™ÍÕÿ÷ý¿ó%Nœ8qâĉˆ—ßÉtz¾ò÷ê;?ÿ³qœšù޵`À("Óß›¥²~òæ;ÖÊú»oÃÒŠÆŠº=óÞ+ÈcÂ+WÆÐã“«b"6bu„·ŒËŒ±ÖÄÐ+"ׯdÒ»éDâYé¿ä»¬Zd¸1ÆÊ†²‰ˆÌabäR.yù1<­Q@öìºX! í¢PyÁ)_n!×­‘¹G’m‘d{LÄ´wµ”%1ó]vx­4f~­ã›ó?i|Qc±Üqã_ˆ1ô¢:‚rUÔŠkwÌîR÷(u¡2‹äÞz÷Ô>ll(º2ÆÚ#C¡$iúù )lªRAÑÕJÊ–Ñ¡ÚõŽðº«2¦2Fº—б¦qùª±Ä,,Áh êtޱc„û“£DpÐ4ÅXÇbÞ[6‡wó*y<†‡•'b¬“1r½Æ÷g$ZbÒ~¦p:£E„~/ìÌ»0³ï9¶Æ¬•çbäÏLòüû&D¹@ è"mLвJºÚcVbѹ7/QÍ_&¸¢ªÿêBõw¾_ýB»F1¯Ç¼ßbÞïw»#Ò×{¨2ôÞëF =ç{“kéFÌ øôE–£Ÿ²¹Åmx Æ“·™ 2ÑîÄp¿£B†9dD‘»LF¹ÇdLŹÏq(òÉ#&Æãê‘Æ#jE­#ŸøÊ–<‰,ád _ÔLÅX“1“mÒý4¼çÝϸ™LÇXÏq€ÕÈ—J©•3¤Dô¯cxYÞlŒõ…™ã’½%B_g]DÆ…+©E‘/Ï ¦/âOc-²2‰à*²¬&Èdó6°–ˆg“ˆE‹ÂåÜ@Á‰Y‹"¾Ø…KšZÙ¸hþÕSÙ‹¾²deÓ"^ ¥HN$ÉUDˆ¼E_y#«–¿èçæx EÌ9Ô¡É.¢ªBQY·,âiT \¼ˆoÒ0‘Û9¤D‘R&eÊm»íTd“rE*˜ìVqöpœ½ŠìcR©È~&9ȤJ‘j&5ŠÔ2©Sä“zE˜V¤‘ÉEŽ2ibb[D×ÛÍ‹Þ[u|Qx•Ÿ~•/ô“¨w ï¡S‹Þ{MáéE4ƒ}†÷íÙE´îIk…˜÷pЏ º9·(Ó‰Ú×uû/úž Ëyn,Yç \ä"¶1‰k'סB.qÈe&Á+ç*½“ˆ~M¹]g·.åÖÍn=Dø:§—4úÑuÎEÖ…Eñâì›óï¶P/—}‹h”ÞÙèoQëàTo/²À‚ƒLî0ч¸$ÃL¢GˆDßUn£ìvÉ|ƒC ÇT?$ã,² ~Y´üjQ¦NËT ;×Ï#Žúx‘5ŽëÂq&Št—4-úóÏGc­{±÷b…1+´`(t?ÖzûAÉ¡‡±i*è¥ø8––/ëã\ ƒÎAúpƧ¢‡ä“pÂÑ¡IJψŽF/<¥’¦¶ã)•“_ÍI ©Ñú´RåôçœìP¬~ÉF¿ŠU‹›múL,ýäçŸ¿Ž¥¯CÈY*ʪ(Ï\¸Þª„CºT©žA”–éa¹RÉßÊóUa¹:,3Ãr’ñkÃr’¿¹>,7(ùYVXndù¹ž¤BF<äìÚäyX©åivMÊÜ •Ì ÒCrùA« X|w`”¢‘ââasP-v˜_[ì¥Ù½0H5T¤Ÿ®Á°%¨Öd;Ж·­¢ =„¦—Êâ úÜTÆ6¤¯mÒº†’ Í(ë¥Aþ6mÏÎ`ÚÂ\óÂÙtWΦúüÙ”×ÅG¬áw[7±Dµ‚ŒÞ´öEpoßÀ¤H%“ýLŒAz£>”ht0XÌÔ휓ú*ttµòª!¯Z‚:.ô!2Ó{f8X4#¦9>=´®²1,„åѰl Ëc$µà§5yI©ÇÔ êɵeA=¥T#øi0øÑiE g ä|v!^ë‚znA=NÍ È‚ÖÅ ú)CÛ‚AˆöàW™îŽàW™òœ<—ƒ#ÍFŒ4¯©·œ_;ÔImâ×èõ ÕZ7“&²7ÈßÀPä&“>&F†q·‚ësLµ"”?霟ҿ`Ó-"pþ­£ƒÁÈÏgÐ0¤¯ ­‘ úúØÝ ÓF‚ê'ŒQüÿ@CÀ½÷èÙìÆ‚Öý ý®ÁùÑö õÊcÞ”qE&˜Õõ-ñ´òÍí¦Ô8i¹U%þ´8>íA¹·©L=Úvb¡ähO‰"ìj,)U “eóÊÞ}'mÝ®øð —ÊWq×O8+âÕ `ƒ‡Únxo‘{hƒ·È½ñ–…qϾxžc Bw¤ây±áx^È|0ž/©DK]O/­®‰·hÕstm¼ZÃXG‘-]£[µTšVªçZÙ@JxÎõpüüœ+ù«/\lä]¬ R÷QùÊ£aÙÄÒøÓc\d£9>âë¢Ç©ü®ñÖÉx×B$îyš·ì Z¾ÁFÑWœ‹8÷6Ó·ââÓx–çb<=FM©鈷.Å‹˜ËDb®0Ñ®Æó",rC®«.éf"{8^En0¹©H“~En1Pä6“AEî0bb ÇÓY}$Þú™ÐîF”žÆ£¨]T§]WÓ÷âù#Vñü(ú}®˜L‚9äQüüèã¿úúq9A‰?„&É;4o=?~FäÇÓLôçñ|p3 ¾äD_1)‘3ñ¼Œïµ ›å°7ŠÌ1yv´ØqEQ1:ce‚àe~DéÇlÕ<ÃÅÇê~Ú#”I6È5a¹6,ש„Ö'бNEéÿx£2g“eAAn‚¯ÌKP÷ ®0ÿC¤|©€\7'ÐWø ¬¢=%Ò·$X[è‡ë‹b•÷gÛÂr{X–(é- Ë2%—ì‡ïTÒ³‹óY˜O+O ù´Šž#L°ö$¼¿PeoÂÂB•}ìT™`íO?9@=HÞUÕ ´V¶&ÁªMÀ=‡Øqᑊ„…#ãoà!3äákÈ)¬# Z´”Gè-î†hJH£ï— ß±~ãG3¹9ø¥!ÇøÛ¦¬Ÿëô ‘“ áGZZÄ»÷ˆœJ ÷ˆœNˆü q&!ò¼t–*A¶RiÏœ'¸¹¼2ŽØ^VÛž`u$t$h†K^R*íË Ö•ô%WÞ{=†ìLˆ|n@ûž~-Aõ™ê{–®ëTW®.ìá_®n&=L´^®îL*åMb•²©ìOà³6“è*ím‚A€~‡vÅo%XÃ(Ï÷GX y7A=#1Jq¶þ ©÷”J'm•ãý~|—”!íA½åaýØðˆ[‚2¼ózá6jÚxBš²Ð)R¦S:IÊtReºpõòýï£R¦Â•2?ÅD݆ëi‚†Úx–€“¤2L³á9´\=/‰Pº¯Ô¹”J5ÃE¥ç…vG<Ïñ:Ax ÝÔpÒ™3j6!Ó¶p'ôMÂÿè'ç¬7Øûo9Sk1¥Oöo¬Xl‘ô¤)ùÍt%½+•ü×áðUJþÖê0Ï Ë5$ß5—R¬[l­_Œ rmXÌß3€-k1µNqBn$Ed/Žh—›@NÊÜÅt§“ 17Ñ.áký5Ng›•©0ÂTD®[¶l[LíöÅÖk}!ù’ÅôdDidŽe‘dG$ÙIvEã²,TA9„v/¶ÆÑÓï!òã½Lô}‹ùª€Ipÿb~¾“I‰<¸˜;ð*VÍa5ŠÔ2© ;RŽõLý Äü‡‰p·ÞHý˜™g(ÂQÒÃ=sÓbÕ3'ÌÿàpŒSÍ‘[w|qøøž@µÚèÌvr1]¯¶,¶N-V׫§Óeé©Åê'Œ3Øhug[­TÀès‹­ó‹ÕUì…÷ÜíÆ¯@«ˆ.’ÃÂφ†‹m‹­éÒk§ô¤Ñ"/“+Ò¼–WI £“vî5jÑÑ×UjÂè"cwäõD_ïbúšûb~/úb«o±p÷3¹¥ÈßfË ²Üa2¤È0“&Æ]ÊiÙË ©Ý[l-[¬I-ú¾RÑä°£x¸ø½¯ ,æ—’ã‹ç_4±X½ 牒ߚ Ë©°|–Óaù<,_,Žx±ŽC¨'«åËÅ / ¥ù“W‹å»I­I¾&˜èo9Ú¸ÀÛÅ–•ˆëøD„¥%ÒªëÄ÷¾Ü•Ho×ÈHäF'Z¹hgîÕ$…‘™HË: Ö¬#XO°!‘ïG*¯dÉ&‹w[æwͿȡÜr)DÏK´rq½š’Ÿ¨¦ùrjÀ#´ðq!¹}\DnBßÂq¶29-·;-KˆÊP¨4Ñš°Ñâ2R&l0í M†¢w²ŒíJä…ù¡èrŠC±¢+”‹ÜMRDïAžgä>¤ì^V™híO”ú²‰ÖAd^Å™W«’Ô0©å¬õPyPã<¤ÒE¡z¥ ½]s¼èÆDžÞg¢Mä×G«±[³"Ç™œ`òÓ“D~Ú¢BNqÈi&ß=ƒÒÏò.jeKð“óLþîíЋ {Uœ•í`Ñ\ˆK‰XôåDú~:ÁU.N'›õkœÏuåÓź‰hÆY©÷†£—¿±6Üu3ÑâZôEä¼Aö'οäVâü»>çá×€Ü~ÔŸ8ÿö&Z,ï„åI!†#2#‰¼†)ÑMÜCÈcÔï“ö ÂQ{È›ù(Ñz eœB&"‚[å$…·Ê©Dëi"½Gë)O‘í‡Ó¤†çC]ž˜~ …ÑOè/itz©üI}Žª‡fù‘Ðk²1›ÙQ¼I¤7™ÍQqßXKè˜iKhHš¾ã •¤@þ -c‰5—8—(Å'«–¨á­m5œ [æ$Ö*×,á­XKìÃuHK_O°a‰°©‡0²–Ì4}áL!ôK?¤‘½„®6çÏirÓº”&sÂ27,óX~+B;'µ —XEKŠ–HãœÜÂAÚV%ŠÉ›°Mm‚4~°âK¨„F)7¾ŒMžJìTb—åJTÐÏË=ªNʤ¾w>EÏ>åR©Ä~%(qP‰*%ª•¨Q¢V‰:%)Q¯Dƒ‡•häܵ#Kx`:ÊòÃPÓëØz)¬ò:NÛŠÝb ¿"P†N’B¯{¢mM9…mýÁyf ÷éžåH¶r=œ£½~~‰ †wAÅúð"…èmKÐ~¾ÕN¶””Þç—–Ð.¸ÌñCW”¸ÊÉtR2×–ÃòCíú5YmÈ.UÀî%ôXjÇ=KæÛ19ØÕć½Kh"^çCQÍnòá%ª“Vobß›Kæç+Ô{>ÈÚ·D}GÒþ õÏïŸyKe? Äm%y[H»£ Cá¶5–#K"ïaÞ]yÕ3º$òÍ}÷–Ð+[Úý%¼dh‰õuùˆÉc&ß'òý &ß{Bõ4¹„RšZ¢..žRÈÃ%ô¬û¸§—ðØÏçíú Òp6|©¤|¥r™á\^3‘³Dä&¿=·„?ÀÅİ’ø\IVZd:IX™Dý@F¯þ\Ëœöýb§H—Ê_ìâ|ç²ÿçü| ¹ìÝý¦ƒ¿(mÇüVT}5TÓ?ú¨š6tÔ/¿¬Qª=œ^íûîÚG¡P]’E;ŽÔCJÕ? é¡z¥oGÃhHŠN i“¬#I"xt!Xû#MkJR5uùÇXoNjN¢+ëãÌN$H¢°“ïÂàÛ’dJ2tzµÈéwvú)Û™÷lè†Ï&YHÓÐôÖ$«ÂUá‚éܼé|Ø$µ ”*ÆA‘å—mt4¹Ûé(i——“¬+ïš¾MÕÑÕ$Zd¿pÓ:lîüÅæk_1 q=éýÕ%]Iï­. v'ñòª$«•wƒÉMEú˜ô+r‹É€"·™ *r‡É"ÃLF¹ËdT‘{LƹÏä"™šGä€sÉ7˜²Ú4ñQ>‘ ˜7sH¡"EL¶(²•I±"Û˜lg¢—„øãiLdoÎå¶“Ýv)RΤB‘ÝLö0Ñö†øQ•Z%§¶_¹`·ƒŠT1©V¤†I­"uLáÅ~õ¤ÑOÿ¢AY±í‡ç­šñëzcˆNòÄ"º…#!¾?w4DŸÖlâR Ñ{ñ´æ- ‡ø¥€áÚüۨͿ= ˆn!ïèS!kо³Æå9£ÈY&­LŒs! …Â+-.„æWZ\ ©ÒhSžíäÙAp‰ r™ÌW8X\Ü©œÅµ½è:xI—"ÝLzéerC‘›LúégrK‘&·drG‘!&ÊŒ„è›lU–{LƹÏä"C8öâôG!õªãqHЧ2‚ã!êxÔk½ÅGÜŸpcÉ9E–/Ÿ†"Þà-?Õž…¬éŸ>Ñ5þ 8j/¹Ž^…¬¤üš›Ð,“à.Çœ"o©õ[K+ÒÒ—òBæ¥äðq‘W1ÑWÑ3YÃd-“à:Џž`ÇÎRæL²ÙDÁ9€ä\2'ç)s>û(²™I!“OŠˆ|²…‰{+w1c'°]Å)¡tK—ò»ÓÊ–R+ž Í„p¸ïXjí\*‚»(¼|©z†¢Ì„HÝ­TÚƒð¥{—ÒÝ„¥|c“MÞKèYBÕWñW«\k¸¤µŠÔ19¤H=“E3iTä•ä(A›)s3“㊜`rR‘&§Tö§9û3L´³D´V&)爤œWu+ê"ÙÆ[ÔÎ$µƒHê%ç2ǹBD.[vu©U°²“eJèÚR+‡äu’ÂÞµ”ºÏnªOZ©÷p5ï\J?±¼—’Z~ƒ’š¿ŠX:AU¬~R÷ôQôÂNˆ\o½Û_ä ØAÈÛKÕà}0¼Œ;Kéõ±Ã#K#N t¾»T=˜õî}kß]p—äØÒùùÊêãü×ý¥š—å#ä§£+‘r|)ÈT°F–‰¥»rZO•ç¥gr©5µT—ž.}ÿ¼ô,"{cšÈóˆ¸Âÿb)½?à%mÌ«¥‘ßðtÍ, ßÞÒ^SèìRñÞˆÞ,xÙÐÜÒ¯¬¹’o—þÜÂ~+9¢(+’é½µiÉèÄõ/Ò“­•ÉR|‘‘Œn^ÿbSó:9âI‘™Qîï­Iž?ѯM¶Ö‘÷ú°Ü@ò½“utV²ªu/^x6&G²“yðpUæ$‡_™‹ðPà“|ÀÇTÖ7'«aBaX…å–°Ü–Åa¹MÉomË’°½4,ËÂrG8|gXî ÛËò",w‡åž°Ü–û²29røbìGÉ;åA`°ŠÕêd¡uJ(5ÉVmrm²"uŠHC¤’R?¯4§Ã¨ÐÆ0=¢èÑy·&¶¿¿pùXòÏ-\nNŽhAn8ž¼ð(¯óDòüóÆ'“­–äùŸÔ¯ÉÓÉÖ™d¡ŸEt£•v…ç¹Hã›ç•ô\ ùÕï\LþEß;i‹lEZ{2¨:`Ó/®Ë+É4a™Ì–ÉŒk”íu‚.‚n‚‚^öºA^ôù‰°ì Ë~û9y”Ñs›ïžåÓ“­;ÉR††”Ô†I 1²PFç²Ð'èV–-Óï¢Bé5™twt4ùýŸ÷’#æJ?ÿ|,ÙºŸ|¶‘uþEH>LV7%óT¾|œÌ‹ý’­oˆÐé¡'¤ÿù$é>Eºñ”¶ö¯Ó0@<'û‹^P&/“1È|E[7Cðš`6™zOù&™žT”r.yUòV­‹8r_A­ù Ët’45²2…:eååɇ®"¹pôW§Ð»73Søé&Öײ¾Žõõ)4`CV Mû7²=›M›XÏa=—õ<ÖóY/`}3ë…¬±¾…õ­¬³¾õí¬—°^JúGe¤´ƒô/w’þå.”G/'¨ ØMAú޲—£ïc½’õýý¿<˜BïjLYØÉÿùËÿ\bÕ¤Ô¤Z» Ö)ÕiÌÏJ±êSÞÿy/#6ü¼ÇÂÃs.L#9aèÀä¨"MLŽ)ÒLU}œ-'ÈB£ÒÂÆSŠœfrF‘³LZ9Çä¼"˜\T¤I»"L.)r™ÉE®r¥w2ùè×úu&_vQewôù¯zÙüW7ˆxn2Ñûx_ô«¤nqºŠÜf2ÈĸƒT>¢}2 fÐSÅ# õ§ w ŽùOð¦Ì¿ä«õÞ£š ÜK±ÆRÆR4tŽ÷S¬)R4¿æ~˜b=Jy”¢}¡¹§Xã)ã)8GNPkÖ¿x¢Ä¤SJ<%!¿x–bM§Ð÷œ”ét0/Hƒ‡d¿—)igÝW)4g1ƒŒ‹{b=cÜ,9 ÷›º<ˆ›K±Þ¦¼%»•J ÄÅ­H…Ÿi©Bº£ÓSQVZ ˜ 7:TI¾;D»¤ÌL¥7Èèô^È5©ÖÚÔµ©êºT‹^ Ð u}ªµ!uCªY©WO#Ivjäû)6¥Î¿¨fwn* 5óR­æ‘Dè-›SéJ¦0µ0•Þ¹R”j‘Šz ;ZôVR$½\°XÙrdô¶°1ZÛžj•¤J]+MµÊR¥½ƒRÆÎÔð{ w¥ÎïWŠ@?á.Oå…x”-ÄÛ­J¶e5öìK¥OhiÑ•©t 4tQº_EÑ„åA޹ð¶ÖTñþ¤êÔwkŒþ¤–’¯£üõC©V}jÄÉ®!•/¢§ò«ŠSùSt©ü"í¨’=òXjÄCŸB4‡3üÛã©´NöÄ|µŸ¤ØÑ-©–MO‘<ÍúÖÏ’n´RQÎ¥†/©Ï§Î_RóƒXѽ²W¶¥ò;T¢ÛÙ¿ƒü/\&¸Bp• “‹z N´ŸÅ ÙÍò³ÑZo*Í|vCo²øF OjÄ‹ô[\7©ÖM›Ðo3d"ÿš8Œ!¾>”ªžòzïe øûú0œ=#©gW—K»;¿7PÎÑTkçwè[Ï$>»¥É‹r,•ŽOšM¼Oµl#U˜J«Ôý‘G©ü¥:ù8•îUŒ§~å™Û‰ÔˆÇlŸD’ÉÔð3·SÑߩɊeïÞŽ»›¶dÏ2~a™Õ¥ m°’‰ÜÏ!9È¤Š‰Q½ŒÖÂÖ,‹xÂEüMí2Mˆºe<±Ìª_&‚ LAÜF6&ᄎ*c\µcœo3yœ=N0qŸD“[NôÓg–Ñú*|+Õê9Ž|žýõ äp‘ë¿M•¢KÑ¡È%Šz™à ÁU‚Nv¸Æ_'òq—J¬›ÓéQÅêåbÝP!79¤O•¾Ÿ pK… pÈmE©4wØ2¤ 0L9ŽÜ%å¼ï©°1&÷y@Á ),0ÎaÑD¢Ÿ¨Ü'9÷)ë)'ñL‘i&ÏUQ^p)^2ùÞ+ª·Žøš-ŸÌ.ã·–¨ˆs”í[ª`k9môŠå¼/Òˆ¸Ó™è+‰èDø‘UËÕ"õËègÐÃ$úêå4‚Wrƒ-“"ÐOk–#—µë–ó¬ÙúwîÂØû?f-çÙ²*©ÙJű°i¹š›É [ŒäÜ媡åqüåô™xÀ7SQã •¹ˆÌ[¶.ç·´.§#jÛrZá§ð”„e)K=T¶ÜÚ¶\$ï d’wr2Ÿì¢Èžr ‘Ú_W,·\ô¹èÝ.{–[{—Ë¿ŽÞ·œæÁÝ•È.z?@?ÀµvÓЪ–GÌCDW/§/Ô­v!@ëP 4Ž_Î÷»…¨_ùA—Hr8"=Ñ-QC8à,O;Š$š–kš±JjÇ–§5/o^®“®_ni^N'Ë­£ËáºðröÈÄ[(à7‡ÓË­3PÎ2ie"Îç™ôË‹ÄúeS£j»ƒL_\" },V…\YÎM¼ºÜê\Þ¹\‹þB»Võ[ÒݵÜê^Þ½\3~ÃÝCþg–Ó ÒÝ«ô0»1Ïhàæ¾©æúHå“kÿ¼ öé-•ñ€Ú´Þ^.ÅàrÂ;ŒCŒÃŒ#ŒwGï1Ž1Þg|ÀøñãcÆqÆ Æ'Œ“ŒSŒOŸ1N3>g|Áø’ñã©(ÂÖ_3Î2¾aœc|Ëh}—pcc:ãJÂŒï®b²š1“q ãZÆuŒë70f1ndÌfÜĘØ˘ǘÏXÀ¸™±±ˆq ãVÆbÆmß]i HÍü5 nó‰kfâÎþzçù¼CRö!œ¿ÃМÃÐÌh®»ðq<÷Þ1€ï>ÀÿxˆzøÚcyRšÿRŽËo¤L€ó à[“Èf •O¯ïÏè1\]Ÿ¦¬]®çJ¼Pâ%}] ùˆ×a6KeõxÞpô9Æ·äïv[š&¾miºø¥Ò`øå4>L‡ö++5)¾“ˆYX´› ®Ä­EM¬ƒ¿°°8 ¸°$´ Ê,Í$çRò©€e›Ë ß-üêÀ¯m|T¬=–æ'âc¹ ì“í*÷²ú÷K5Íüž,Ó~Ǿƒo´íúÄ.í3ñ»R”Ãã÷*ÿf7àÞ£•jæÄï‡ö²ë>ÆJlØ¿«Ä&~¾Ÿùƃ°þÁAXÿ}ójÆXÿ°Ö?ªe^ÇxÖ?>ëŸÔs 40†õ?†õ?6²×Æ£°þ¯GaýOMÌ16ÃúE3¬zœù Æ“°þÙIXÿ¼…S<ÅxÖ¿8 ë_ža~–±ÖµÂúãsZ¬øIàËßò˜?%ÏCÿë ¨¦OÅߊ‹šæþŸÄß‹¯ ›lÓ,éiGÄŸµ#â?v@û/—ÿ÷eÀ?]ü׫€ÿ§ðß®¡ÿßë€îüÝ€ÿÞƒD?«¤èÕª¥ù[¨7P›¸‰Ð5²O£Ï*~AÿZ¬—±ýº¥‰ˆÛšÔ¸ÙÞˆ!ä°AkÜhw€dÉàFyW™FA²å=EÆ@6ÉûŠ<É‘¹ò×ÚcèyryçË `|Ü,'…rJ£wk=n‘Ï€[å´FoˆÜ&_·Ë—Àù X*g€eò5p·½r¸KÞ¦ÿލúHx„ˆoÔ6ÍQmü®|«í‘ #ûo‹:6M§]•®kb¯LǘŸ¤m­ämÝ/i#HÚºƒ’6«JÒ¦Ts1kxƒjy#ê¸ø‡äJ]Šz™¡£¾àª©6ÊÕÄNH=ì˜ÌDÍr üŽËµrZÊu:­¸^¯£ˆÿVÛ gédòF.W¶Në¨6ÛdŽÎ‡.H»ÌE22òa¹$óa¹, øúz3,WäfX®ÊB­H§cp‹þ™èDwµ•#Ãíš,†Ûu¹M§>g;ðCQ{—,½[–R‚§~U–ÁÖÔE¯ÜÁ™ìdÜû ¹ ö›²ÛÑ'+€ýr7ð–Ü{·å>:ãJà¹8$‡åAàˆ¬Þ•ÕÀQY¼'kc²x_~g½nþ;1.㲞³n`<Œ<‘‡Q€IÙKŒ8Ë”<ËSy”}šxsÁþLƒ}Z6³ý8ã ØŸË°¿'9…X^ÊX^ÉSìsšS8ûŒ<ûky–-­Œç`Ÿ•ç`#Ïs `™“`y+/r mìÙ»¥µÃ¾Bë`û%ÆË°§i—aO×®°å*c'ì+µNØ3´kl¹ÎØû*­ öÕZ7[z{aÏÔza_£Ý`ËMÆ>Ø×j}°¯ÓúÙr‹qöõÚì´Ûz¬ÈÒµ;ÀlmH×Ü r5ìI´Ô2Í= ÷mûd³vX¨‹´{À-Úp«vX¬=nÓ·k€%Úc`©æãN®Iûæ8’Ú¥#çrmAÚànm¸G›îÕžêtFx¦Óa¸_{®ÓÙà…Ngƒ—À*í•Ng‚ý7q&ò5d-ä,däÈCsõo! -ã7q6rd#dšAgƒtƒÎ+ Íücq\3fÐw¸D†!Ð5oc}tÝ« ª‚“ž‰-Úà)m-ð´¶ŽÂþ£\o´jñ êy³ Úó³ îu6t´åh:ZŽ¡‹óZ."_Ðò€µ|`›Vl×6;´BàU­Ø©m^Ó¶¯kÅÀ.m°[ÛìÑJ êúK7´2àMm°OÛ ì×vasoasË! + oCÜyr/ää>ÈaÈJÈÈýHå®v€žgÓÒ£lZpL+‘¼[jâW¡Tùzb 6n\«NuñD«ƒ> ÔÅ”vúS .žiõЧºx®5@ÔÅKí0ôWZ#pˆcN;}ˆãL; }ˆ#Lk‚néMÐWèÇ §q$éÍÐWqôèÇ¡¯bïé'PèLý$pÞ\«Ÿ®ÓO×ëg€ô³À,½¸Q?Gëç›ô tY¨_æêmÀ<½Ib!Û-út¨ý{I‰ËÈs«~yëWÈ$®òŽïTÁ×”¸‘ º î§»Ù¡‡{o›°#‘Ö6½}û¡o×û‘n‰~ – CPiÝFH©~!eú L‹ÅXvèw`Ù©)§aƒýìÒGP®ßU£0Uè£0íÖïÁäc°ìÑïSºþd/gIý!—ó,•ú#XöëÙ2Ë}–ƒú,¸Pbð)xR‰)•ÕSøUéOáW­?ã˜Ó°ÔèÓ°ÔêÏañ:çÔétÎ9¤¿PEx §z ŽÞÿ•A½ÿ °QMǯ>KǯþÆ xL lÖ-õõ+lÔ×§OêéÀ}%ð”ža£þ}ðŒ¾xV϶êk€çôµÀóú:à}=ð¢¾ÁF½y°]ßìгmMÒüsqE×7ÙÐMx<9¶Xtà¹6êÀólÙ6ó/Ðc›ù6ÚŸÀ ØÌXÈXĸ…q+ã+#VtëÅH¥Gÿ©°iÛlmZ¶ñ/·Û4ôç%À>½ØÔÑ“—AÐwou1¨ï„~¨‹!}ôa .FôrèwºÕ+ ßêbLß ý>Pô=Ðê{ô}ÀÇ@]Œë•Ð'€8–õýÐ'8–õПq,ë¡Oq,ëUÐ_q,ëÕÐ_u1£×@ ÔŬ^ ý Pszô·@]XÆ!è+€ºH3êQéFp¥q˜a4WGà³Ú8 =Óh®1ŽÁ²ˆ³œÑ }½q¸Á8Ð,ã$p£ÑbC—œkˆS$Ñ»ž†Gq†Ø6C? ¶Å8‹¶­ð/6ÎÙ>6"СžÇÞ(3.ØÎÙÌ/‹¶6[»­Ã¶ËHºd£å2ðŠM\µE¹qÕ'*ŒNè»qbq ú^`œØg\‡^ Œû.ÞÝݰ0ºa9hô@¯Ɖj£z 0NÔ7 ×ãÄ!ã&ôz`œh0ú ƉF£ú`œ8j܂ތnjºGQ÷‘¼­k6nc뎃œóXNC¬C?iŒ[Œ»td£td÷èÈ0ÆèÈ0îÓ‘a< #Ãxh»`3ÿJ¶Ù.¶aäÖfܶ#V¬è@¬XqÉxÏËF"*wÚˆ{Œ¤;qà5 FÆô. FšÆè=@ê÷&¡ßbTiLQsêèöžB¿ÔÅ€ñŒš;Íݘ¦æDs7žSs¢¹/¨¹ÑÜ—ÔÜhîÆ+jî@4wcE|h¼>2f7Àqc8a¼>1,»“Æ à”‘|j¤ŸǨëÿ©\iiüF†.åÅ*;wT«•wË™vk Žátcçžp2®·ãÐ0¨{Ÿ16ع3§^üµA½ø¬‘Ó¯Špzcl´ã81²íóýú[ƒúu˶‰RÔ{¯°Qïf£~2ÝFýäJ[‡öÀ’aëe•-–_yHsµ-ifÚòU‘&à´Æ6§µ¶ezÓ:Û˜ÖÛ6ÛÃ=9*Û$LY¶BµS0m´MÁ”m+²ÓH‡:øM6êàsl[ìóÝy®ºó<ÛVT_¾­X`£žz³zêBõÔE6꩷ب§Þj£žºØ¶ žÛlÛÛm%À[)°ÔV,³í°“æßˆ]¶oï´Ó©d½G¡m—=|ÊŠ TEœØm+çà løÛn®–=ÀJ{Q„X±Eˆ•È6VìGAbÅ$VDbE•m/2¬¶íÖØ*µ(N¬¨³í‡~ÈvXo;lÀ&Ɗö*è¶j;ÚÉߊ&Û¢.A-cã!*¦¨G™ŽÙê±3šm °¶‹F>bÿL·Ií‚NØŽÒ#ÏO>’Mp?ik‚­Åv ¶D3,§lͰœ¶§$¥ý¦í3qQo¢Ÿµ ¨Ï?’'‘ º6í$\ÏÙZ8÷«ð<ÛUx^°b['laë„­ÍvÉ·ÛÎ`k:lg—l­À˶svÛ7lŽóï´Gš×l _·]vÙڀݶvøöØ:€½¶Köj»ù÷ò²½ßöõ+\&›¼Š2Ý¢üÀÖ¶^ƒõ6¬×`´]§RizŒw`ì‚qÈÖ­š_ŒÃ0öÀ8bë¥øÓ6yVtdÚ XGm7y«ú`C‡¦õÁ6fëG‰îÛnØì—ìæÿ%Û¼·Uõ Âu®ƒp@ÍÆ‰'¶;*TÍ$%Bç?ÛÛúa{ [?‘p¬˜F±â¹mÉ¿°ª!r†Ý=‚*™± Õ×¶»ÐgÑÚF¡Ï1¢µÝƒnÙïA_aCü4û}`ºýp¥ýSJÊVg_ún™öGÀ5@µöÇÐ×q¸ÚÇ¡oâ8µO@ßh̶O7Ù§€9ö§À\ Jû3èù@ŒQìÓÐ7uQh½¨‹-öзÚ_‹í¯€Û€ºØnŸ^ÔE©ý5ô2û,p‡ý p'P»ìsÐË:ŽÀ·Ðwé´W1®´¯€^ ĈҞæÀÅž=xоXeÏVÛWk쫵öL͵Øõ5ˆ×`_ƒx‡íkÒh_G!ÇíÚz„³¯GH³}lö,G›ÖfÛèÈvlr ùç80>û¯âŒÝ‘렙ǘŒ³Û ܾ6Cü•µ:bE«½È¡™ÿM´ÛÅ¿¥öowmA.—í[ËûVèWºè´C¿ÄÙξ åê²ovÛK€=öR`¯½ÌÞáŸåG¿ý;ŽGÔ|Et?b4ºm¶qù9UÈq„ÜvL8øšò ·IE¦Ôî| ñ‰xœvˆçKÅ ŸÝ_Bü³xüXÌ?¯UÀ¬ƒ8oê–ÅYÅ[NÛrR‹\Á˜æœÒ:Òb:V²…†½CŽ X†«œïîmŒ8èæÆ]Çjç»»£º½qÏ‘éÔĘc“¯"ׂÜw¬ubÈæXÓz§ØÓCG–“K·ä‘c#Â;²)Cþ ¦qGŽ“†#¹Ð'¹~âÈ#‹Ç“Ó¤£€ ·ú”c3‚Ÿ: ÙRË3G,ÓŽ-NªŒ­°¢­1 aù¯>6ó¤ÜŒ?.4¹0éÐ߸•±Ø¤~o›ÉÝèv%J ât½T‰2N}‡ ÛiE–¹ÓŒÍ]”¦ÔË‘c¶YŽ‚n2+ÈYì†%ÇÜ K®¹Ç¤]½–“^`-+a*0+aÚlîç²€^h¤T]z‚‹Ì*˜¶˜Õ&_HÖÀ´Õ¬©Ø¬Ån3ë€ÛÍCÀ³Þä ¤Ró0°Ìlî0wšG»Ì&`¹y Xa6w›Ç{ÌÀ½æIà>³Xižî7O˜g€ͳÀ*³XmžÖ˜çÑH plšŽ ´Mâ" Xo¶Ìv¶Ðá°ÙïF—$âˆy‰›ˆí¸©]†ß1ó26§Ù¼BÖM޳¦qÖó*¬§ÌNÄ;m^ƒåŒyZ—Ùm"“8¦4z!/˜ÒvÃÄ«XÊ z‡ù›jGõQ½øXöÃç’)íýHñ²y ÖßHñŠ9ËUó¶©NpŸ äæèÆxÿš9hª³Ègâº)té2ïðö !f·9„˜=æ0{ ý^Sš#°Ý0ï²m¶›¦tÂÖgÞcÛlý¦tÁv˼oÎ_” ˜ÒCe·Mºá6h>À6ß¡fNÒ¸ézˆGÌG°Þ5GÍqà=s8f>Þ7'Ì)àCó)ð‘ù øØü=Œ›ž™ú4³æsà”ùøÔü7šYŠËS{É[õŠ‚ìÍ2)_›3f`Ö¤“ÿ“îxÌq ~Ëž–KŠ×æ ଙ|c¦çÌ•À·f†‹°ÀUÜìÚìÊ–f…[]<-vº4sŽ—(ráÒ`/Ž—s‹‹gg]êr€ï+²Í5?c»Ó5nÅ.×vW¬(w•P÷¹´Rä²ÇUÜëÚáÒÜ•8>\ðõ˜ûq\¸ô]üÜ]9#­ ¨qU p²q‰Ý”F«KîAì³®½°WI¹ÏuÁ¥WºhÖq¿‹G2|Ñõg¨“lGŸËw5Ðáª^¢»ª¡_¢ùºj wÑl]µˆxÝUìrv»ê=®`¯ë0ð†«xÓu„J2èÒŽ"ö€ë(bßv5‘mÔ¥ƒmØÕ b0çúžº\ÇaºĘÍuúC .¹NBìjŽ»N'€˜¹N#«I×à”ë,%þÒ¥µ"ü¹«á/\¿Ó[—qŽš}SDÌ¢*Ф\©I¹ÚÅÌr´»:\—\—]W\›W]®B÷7®!‘4÷u`º» ¸¨‹ w7ôU@]¬v÷@Ïêb»úZ †PîÐ×u±Á}“ÚíÌÝGí ˆvæî‡žD÷í¾=ˆŽÛ=@íÌ}›Ú™{{ü0š™ÛvÇEÏí;Ôß‹~Î{¿Ø}—6¼Ì­"V‰û°Ô=æúózc77Ñr÷}טËl’¶6ÛU]È>píq'=Tíñ‘k~ü½×MSÊûÜ]óãïJ7O;»iàzÀM׃îq­\×D•»\×Eµ{Â¥¦þ°%5î'Ø’Z÷¤òš‚©Î=Ó!÷SØŸÁTÔEƒ{¦?ÃîBî~K£›ÆcGÜ4;ê~mir¿s¿6»g€Çݯ'ܳÀ“î7À÷ð”û-ð´Ûrc¬å^áÖÄYwôVw:ðœ{%ð¼;xÁ½ 5b6KÙnkwKšÁîp¯vãph·]w™ˆzÅéFãw¯Þé^‹H×ÜëÍßC¥/ð\EÞ›=ÀBÏ5`‘‡fŒ·xhÆx«çº»ÃmžÇøÌãìról7å,"票¾J‡³žÿ¤™Wp¸{\½¦Ç3áæõ’OTsŸToJí§§(ïyÏ3ê<ÓÀ‹žç°´yþX3;¥|áîð„^ò±ý øGhGœÆk7_fÝ4~yÃ8Çø–ÑòàdêY¼ ÔÅOšjžt`§ç,]¨yb¯1ö󬄽ۓìñ¬özVox27=‡áßç9ì÷¬å–g-pÀ³xÛ³žÁ<¼v–AÏFoX6²¿ãÉFöCžMöäG<¹À»ž<à¨'xÏSólÞ÷xŠ€=[€<ÿcßëRnõŒ{¾Qì¡Êßü}´;ªáÆRíµ2Ê­‹jk'rŸðìò|&ž Q”CNBV@NAî†| ¹9<óìN{öŸ{*/ÇZ/O"ñsUë½ û,o¬XéÛÌðeÁ•o#pµ/Cjæ)ÖúÌl/q¼×ùr8f.ôõ¾<Öó¡oð°ÏfèY>:’6úÊ©ÍäûôBØr|EÀ\ß`žo« ¨Ø»Õ§o/ômóê¢È·¹nñý6‚:]»|öm÷•K€8F|ep(óíîðíîôíòrK¼âK*‡ßn_9üöø* ïêbŸo7ôJ .öûö@?ÔÅAß^èU@ u}û ×Ñø*¡×1¸õí‡^ï;lêâ°ï ôF .Žøª ê¢ÉWÒóÕ›}µÀã¾:à ß!àI_=°Å×<å; <íkžñžõ¶úpl‰s¾cÀó¾fàßqàEß `›ï$òj÷µ@ïð^ò^ö-6팷Ãvß÷³p¹æ;‹â\÷µBïòvuÑã;½¨‹¾ ÐouÑ绽¨‹[¾6è@\ÖùÚ¡uqÇ×}¨‹aß%è#@ ¾ËÐG8 |W ù®bwˆqŸÖ öÈ׉Ǿk°imÚuï¤Oü5‚Wû?èBð3_‚§}ÝПqiçÃÑ+^úz¯|7€3@]¼öÝ„>ëë¾ñõç|8¦Å[ßÐòßFM¬ðÓü8ˆEº¸Ò? ÌðPƒöߥ‚­÷k£ˆ±Ö?ŠT×ùï‘m“_ÛèCH¶ÿ¾—ƒÛý®°æùšï,¢yûSƒ¢ÁúÇ©Áú'€[ýO€ÅþIà6ÿÿ„÷úSp-óOÁu‡ÿ)ôþgÀ]@]”û§¡Wu±ÛÿÑöø_Púµ—`ûý¯€ü105øm3ÔBý3ÔBý¯©…ÑBý³pª÷¿ñj¦¥‰#~mÎKãÒ·^ê6¾8g3WhË×íXáKóµÙÒ}t¡¸Ò—á[å[íë6792}k|Çý5ÆZ÷ >µÅÇCE²|t„odÌV¦MD2¾/s|ï®Oøéšñ¤?×÷î±ÅOˆ§üyÊDˆ§ýtxÆŸïéˆS¿ú9 N˜þÍÐ/uqÑ_½ ¨‹v‘Jb‹[•(Vb›ÇãÛ•(Q¢T‰2è*w2îb,ç`{…»UB{ Ï^ˆB·!D*º !þÝøh†ö ‡‰U>uùÄ©ÕpÝÕRˆ¡×¡ØþC Éè90\ô×c.ûØB3úWüWm?WýÒG Ä:ý×À®ù¥Ÿ–…]÷Fœ. .ºýÐ{€ºèõ~ˆëM?-üêóÓ¯~?-»å§a~Z4vÛO‹Æý´h쎟 ù;‘🦠ãĈÿ¨OÍüXÜõËÍŒúç'3,îùi23NŒùûÀîûeT“ª%Z[öÀßãC¿üÚ1e¤Efü·`|ì—Ð2³q³ïkbøxâ?}ø˜òŸPu¶Óü±xê×¾MsáÏü'}#ú[Tr§|?Ïýò§|qâ…ÿ´O-à8CÑM¶ú‚⥿á¯üç ÏãÄkÿyµsõÏĬ_~“Œxã¿€ 9ÿEnÍmp~ëoƒÅ ´Ãò¿¡ÕÄŠ@j4-p åL~ V.CÏ~ V®W®Â’è®~ Ö®A_ü@¬\‡¾øÈ tAßü@dº¡o~ r=È+7Ð Ì ÜàòÜ„ž¸‰Ü }Ð7úaÿ;tÂè]·`/ øhÄ}Û÷™ØÀB¶îøèžÊÚ\º]S˜uêb[`¹=0, Üõ½›¹) ÐÌMY`¦ÿÝ´&vî!õ1ßüÑ]º#Z¸Ï>àSx蛟¶Þ ië=G°ï ².ê ÖGõóÍÁV%Îñg¼ vÖETΆ(™pîYQm~œÓ£Ú¹pH&;ªöMQt³?'ŠnöçFÑ þ¼(ºÁŸE·ó ¢.ùcÅæ¨Ëþ(QEKŠ¢®@ßE ¶F]…^Õ‰”·Eá„&¶G]–DuK£ºeQ=ÀQtu°3ªú®¨Àò¨›ÀЍ>àî¨~àž(šüÝEÁû¢nÁREÄû£ ˆ¢•É£nC¯ŠVGÑ$rMM×FÝ¥.jx( '>QE“Î Q#ÐGÑÔsãÿÏØ{Žm{~»»iÓGœs3›ÐMhæ½;óæÍÌ{ÇUS®šr¹ÊþÇSÏž×syÊáºì²=¶«l9G‰$@H€È( H$‘³ Ȉ$ „¿kÿNŸ{Æ3ÿ|~«Wï_Ú¿÷Úk¡òc÷ƒVÁÎ Tz¬+h|DfÝAdFд˜y´ ý£ Ôz¬7è A¨ìXÐ8´ íƒöy^ùÈù š¡ à:€<tŽ¡~ccAG¸Î8ˆÜôò$ˆ¼t yDÎ:< "ßB~"×}…üDnzz1ˆæ(—‚ÎpågAßÀçAçà‹ vDÃbQ…¼Š£Š$(|”¾ Jß%ËAÉàJP ¸” ®¥ëAéàFP¸” ne‚²Áí p'(Ü Ê÷‚.ûA—ÁAùà§ ð ¨< *?ƒGAWÀ/AT½•‚'Ae?#‹]¿‚¨ÆƒÊ¡ÿt <ªcå•`œ¼ Œ—_ä±ÿš%ÊE®jüJ’×€Éò`ŠüæÏŒIkñ#U^¦ÉQ±t9j/–!o3å`–¼ Ì–7ƒ9ò0WÞ æÉÛÀKòvð²ü6˜/¿ó3嬻?óåÄ?óüÕ'.wà‰ å÷U'ÂÉ»xXTD¬XÞ ^‘÷€%ò‡`©+“÷‚Wå}`¹¼¼&+äƒ`¥ü1X%¯Ë‡ÁjùX#G¥ÂnÈÇÀ›rT&¬V>ÖÉQ•°zùxKŽŠ„5ÈgÀF9ªÖ$Ÿ›å¨DX‹|l•£ò`mò°]ŽJƒÝ–/wä¨,Ø]ùsðž•ë¿ïËQ9°Nùk°KŽJ=¿»åïÀ9*öP¾ >’¯€½òUDMŸ| ì—¯ƒò pP¾ >–oCò9,ßGäiV6*'{˜19ÙÃŒËw Ÿï‚“r”ðlJ¾NË?‚3òO¸Â¬üàg›ÑŠ–B3¢-ÿ,|Œ#üXáEùœ¶$?ŸÉOÀçòSð…ü+¼”#O½QûÉÏ(¿È¿Q~‘ŸãÜwòØ äy¸,Wä àª<\“'ëòdpCžnÊSÁ-yøAžnË3Ày&¸+G‰ÌöäÙà¾<ü(Ï ³Oò<ð@~ šCùeð³‚d(:…‡ëÂ…3]Pe)ªn„ËVˆ"º¡ÌQô «Ÿa¹ Q$­ÎS<>BÀK QÔ#¼¬èÅ•òd$W  #¹BE_êAE?X¬¯(hx‰b_ªTA&YeŠÇ¯*†ÀrÅ0xM1V(FÁJÅX¥¯+&ÀjÅ$X£˜o(¦Á›Š°V1 Ö)æÀzÅð–blP< `“blV,-Šg`«â9ئx¶+^‚·¯À;Š×à]Åðžâ-Ø¡¨úÙÊî+êÁNÅ;hºïÁŠå – ²$±h?ð¡â ˆ>R¬ùD{€hŸ‚?û4ø9 X 𔥠7+Xh ,UÌFbaè’cÇkA+KC]§øqR"ªúo3ˆF,¶¸üsü[T)¤ßå©(§{ˆêiÅ>oVñœS|Ÿ(êDbYºÊŠ !Mq ¬U1?|æ7;â—ûÂyÌyÂyÊùUøðg<è· êÍœs™>ì¢"VŽC>SăÏ ò:‘, …B’(';xÅ׊$üùF‘,¿(˳÷ŠŸRäôF©òÿç\@šÜ? ØG/+h.`EAs«Št\fMA3ë šØPd@³©È·Yr±,ía…,[N–¹[bÞóÈ‘óC®pÈ“ó~çe¹Ðå:ù¼/€K\B£ Ã_)ûªàÒGŠBð‹¢ ò3äsåeÕʪcy‹HV-È“T†S9 é|E dÕ=7êJÔo*Qô7œžª:—SiD‹=ÒT´Ø#]« PqŠ_X†Jä‹S ·¨âÜŸÅwèÑ©D1]—­JPP”'"\ŽJôw.W•ÄÏMVˆYžŠL†.©P“²Ë*Z’¯J…\ B=Ê U¨>Y‘*,Ve‚WTÿ-b¡Ju! ?ÊT¨5ÙUUX®BmÉ®©òÀ *IV©º¬øƒì&òŠv{’ÕŠY­JŸÏo]€[ש ð0õªB®)â,Vдö.—(hZ«¥z“TW9Ëù]SPŒTpVò÷®â¼Îÿ­ÆÜRÕ€ ª`£ê&ؤª›Uu`‹ªlUÝÛT `»ªQ1*’Õ‹Ù]•ä†ÂÊ ¾¯¢Ú¤SÕ¬À÷j³n•¨êU«B|±QÌzU¨QñÔ*Ô©8«D·ñzCª;ŠL‰¬YÌÆTª»x¨{ Ôª¼6¹Ï´ÆUˆƒ U×<€fRõš)U7×ôp>„~ZõúÕ#®éåìƒ~VÕýœªÏûD5ΫÁ§ªÇxÈÕ¸¨Æ—h³ç*ñÎy¡Á9/Uÿ‰XÖ&foT"![Ž*^‹eí¨TÜŽlY5¦Ën‹Ùº*tœGü˜‚‡)j\Æf¨r¹rNA™”Êœ ÕÜsS5n©ž‚T à¶jÜQ-»ªgàžê9¸¯z~T½?©^ª×à¡ê øYõ¦ü¤>QTˆebV¬¾pÊ¿ÞWÎ3|+ê3|õ7|·R5y‚*SŸ+"dHåjy¬’'š8á/”vV¡NPÚX¥:¬R'×ÕÔ «m¬FŒ07@»©N\ ÚX:¬W§áBF+po©i5nƒ:]iej+’p»Z’¡³u&تÎÛÔÙJ±¬[,ÊQÞSŸ«¤gσ¾C}IÉíÈо¯¾ÌõùÐwª ”(ŠÔ…àõ({ˆÊK}a”WEü”b΢_ ù›ƒ½ê+ÊßËzÑT_(Aˆt4•Ü.¿LÉíò¯*¹]~9n2 &»üÇêtÑïeýbQ‘lTýŸ]S Æöt¸(©Tò: JIVf×9«•´Z¯†óçMÐ(©uJÞNª·”Ôóiàls©:ç‡f%•O-œ­ÂWiíÂá¶ð$w„Ã]%7û¿§üÍìLMSãêåofÿj2ûŸTßWúÍþ§Ôdö?­îTúÍþgÔdö?«îRþfö?§&³ÿ'êJ¿Ùÿ¼º[ù›ÙÿS5™ý/¨{”¿™ý/ªÉìIý±øLý|®î_¨û貫ÿHÔ_/ÕýJ {¥n5Õkõ ToÔ!¿UïÔÃà{õ¸¬"| ?VÔcºª^yª5õTëjèÛPO"mlª§À-õ4øA=n«gÁõ¸«~î©çÁ}õSð£zü¤^ÔKà¡úøYýð³¦<Ò €_4ƒà±æ1x¢ÉãKrµ†4Î4C*4X5ÃÏAô˵#§ãµc*±lQ,WeI’µ¿›PñòpRE-Þ)•0 +f)Ú1T§©Úi•‚1M;£âY\7];‹ëfhçpÅLí0KK \²µós´OÁ\í‚jL%{.f—µß/ÒuæÿJ´Ä¿î3Îçœ/8çñ=òµ/qZöX¨}­ZPÉ^¢:ÖŠ^áÏíU®TöJÌ®jþÔÈ–s”kß"È5í;¼Úk4qµì?Â'{ƒjTkýÕ ø=O\˔ʿ»°Âï¹*¤õ5!­ ¿6xÙäÜRQsöç6玊’å.çžêW/Nú£¤€W™ûB.úˆ(jÔ~3&-9óhÖàÕZ´yR kÕRnÑ~¦Ü¢=ok¿€w´dkyWKÿ{Zr´Ñ¡%G÷µäh£S{¬:QÉޣݫQGµG{JŠ4|µhy‰e«hëjÙ‰×_‹²$£ZõÙoŸpLKsÄãÚo*šYßÿ5œö÷œÔÒ6.Ñ6ûuîö:UtÚx5ª8m‚Qm¢ú×öª8-µ¶žh“ð÷¼6?Õ¦@^ЦB^Ô¦KlÔ'ˆ2E², kÑ_LÑÐåR5Tp¤q¦sfpfj(#eñ0Ùêªåh¨?“‹Ë´âbVÖ¦ÏÓˆe9v_îd¹ö@FîïeyHÝzq>B>Ò€½úBøâ% гBQ‘æûËH²úÀb ÎWøó– ذ¾Ñ—áâ£ú«à˜¾×_'ôाœÒWÓúëàŒ¾QŒêHXïxCóÚM ÿµ¸æ¼¾|ª¯ô·ÀE}¸¤ï¡uøüã>×7BóBß¾Ô7㚥öZ/ŽåÝ- +Âw)“ˆR~z§7·òçnÓ ·¥oÓHز¾]C+ênƒÿ˜ûë]ÑÓ|ÕªžÆÂ×ô4¾®§±ð =…oêi,|KOcáô4¾­';•=Ù©ìê©ÆÞÓÓû¾ž¦Ø?êÉxâ“žÖØèi¤üPO#åŸõ4R~¤§‘ò/z)?ÖÓHù‰žL.Nõ41ÿUOógú;ø åhXŒXvM  Rîs[#øãSå^¬e~/–UHDO¿K6üÔÕ4Bp(AfIäáÂ@6.0Í@‘™nxf™†^0ËÐfúÁØk U8y†.÷½àGcøÉØO Ú8@ Ú8~6>ŒC”¸Ã”¸#”¸£”¸c”¸ã”¸à7ã$xnœcMÓ`œiŒ7ý-]Ò^2Îá‘’MOÀm!Ó<ä4ÓS0”° ÓNÉ4-RZ5-QZ5=£´jzæš^€y¦JQ ¬ý“D˜»y©¥<Š–"S•¨R$ë‘°RÓÅW<Î^ãâe¦7<{½…|ÕôŽ'ž÷ËMËZ*Èh›€k¦fú ]¬ÒtªÉGh"š,è³Ó:xôÁ/°©õ¯0¬5Ñ Ã:Ó×|Ðú«ÆzU·LÛ\³£õW9 &ªrM»\³Ç¹Û6™öͦ\ó‰óúÓô­¦C®ù¬õ{³o3‘7ûvÓ×|á6%ëIJÇ虘‹ò¥)ýk6nJ'Lià¤)œ2US\Kؼɖ¡ã«ðtþøzÊãkÁ”Å5Ù:|-òøZ2åpM.gžNÌž™òtöÜt‰k.sæCÿ”ýKS×rAÿÊTýkS1×\á,þ©ú·¦R®)ã¼ ý;ÓUèߛʹægô˦ èWL•:Ô7¦*pÍôXð=³oúî:Blš®#Ä–©¯üÁTn›n€;¦›à®©Ü3ÕéºD²1 ;0Éëy„ÞâlàlÄeM¸ÌgSä# u|1‚Ǧö05ãÖ§¦ð«)‰œšRÁo¦tðܔƚ§ì,ÎLÍÉxs+n›`nÓÕéd–l5él,Åýœ:ÞÑÄ ªÌÁëæ!°Ú<¬sÊž ÏšÅ#:Þ¶Å¥kÍcº¿•Í#7š/Žë(IOÐùèŠÓu§tþeŸ fk4Oãœ&ó .Ølž[Ìs`«™fÃÛÌOtu?ÈÅÌâ=¾È£ñä4ó<ž{õ™=Õ¨dKhÉ™Ùí(óL"^T§ýøÈl\ÔQ Okæ{ÍK“E¼ïÒg¦¾K¿™š?fjþ š©SüØL Ÿ!35˜†ÍÔØ1SÃgÔLÍ¥135|ÆÍ”Õ&ÌÏ(7™ŸSn2¿§Í/Áó+pÖüœ3ÓÖ'æ7çÍoÁ§æw:Þ{{/–yL¬?Vu<í¾5¿†O½d^ç~f^ÇiÏÍà ó&øÒ¼¾2_›·Á7æÄÄKÔHfV‹ÿê ó»:>¶'ö…ÃGþ-?qð/rÈåÏ:Á>•ò†™Ê]óÊæcpß|~4Ÿâ.o$ìÈ̾R$¿¥̉Ùð«Ïª3ß;Õ©™¼S}5Óù‡fÏÌ44ûÍ|®ã4¿û…›EA«Ibƒcõ¤£Õ'qÁ¢¿O«OâƒýËÃÐ ¦åa–§÷¯ I Ö…$Çëýk[R‚EIk[Rƒô~7ÂiÁ´¼MÂÒƒ©•œ¨G¢ B ½—°œ`q’ž"`Á%ë'/È–%ìRðw4­}98Eï·3Ìì ‚i¦0˜\é§âbÅÁiz±lÝ«`ö—]“°šàŸÓõ‚Om=÷ÿ¬§ŸÅ™Í™Ã™ËI†}7‚óp©›Á—ÀÚàË`]p>X\Þ .‚‹ÀÆàb°)ø¯Ô² ÔOÁß bWôÜ‚¼ÀJõ|’‰s[Ìí©jm ¾…ÇÛD þá*þ¼%båzt‹ƒ¯ñ‡¬€|/˜\ŸuWê¹y 4÷ƒÉõYgðuÜ´+˜Ńàjý3‘ìƒD4*}ÌjðòÛÑ ý`pÀM=Tµœu8¡?¸¾¥Ï•ÊvÑ€ hàW~`c#Áz+ ¦Òs,¸Iÿ7²= › fÍzœ=,jÁ©3Á­ú?È>JØÓ`Ö†}’°Ý`Öé@Â>³Ûú@Ù! å`ñ}ŠßÁÿŸ%ì4Xtoð5¸I$þþ)Åò»{üîЦX:ôH(–ûÐ(ø~KiÚo)ÝÒÉãí©嬅œ©eZºôþ :ËÒðƒ„e[ð0O&ÇB 3×Ò{KØ ëÑ£Ü=A¯Ý"ÈO|ÄÙ‹›^µôâ¦å–>þýœÐ_³ @_aäšÇz9]i¡rºÊ2Ä5Ü#Ý2‚ðÕ–QD`…Êï–›B×jù~ !ê,ã`½e¼e™,S”z,Ó”z,3`³el±Ì!ŠÏЋ¶°'zñÅo(K-l¯sŽV¹…ýÈä±lÐòýS½0×£L¾xƒˆ§œ%Nò¡ùØò —²<‡-ÿ“XÀÆ,Òî3þ8,zùëñ•p½×üz9h^&°)‹d–Ïb½Ñûǯ§-o‘6Äïô“?ÌYäïõd&¾ŒWzbYçA$Ë*?cçƒuè,ëÐ/Z6 )@ËqµdÙŸY>€Ï-Ûà ¹:ziÙÁ¿²ì‚¯-{àË>øÖò1’À–-쓞LŠØš…@™À6-ìP?P–À¶-²ÏjD„žZÈ_“U4„ |³IJꖄšÏ(« `©6ÉÇß&ÍÖN=²,ËöGyR3øw Ì¶Ñ”9¶qþÉ' þÁã\ çÙ&yÈ)ƒoÊK6Úœò²mškf þAå| *Øfùæ þÁãB ÙžpͼÁ?x\l£Áã+¶§\³ð[B/±QB/µ-ò+/üƒÇe6<¾j{Æ5Ï9_ &Ëm/ã®Ù^rÍ+ƒP¹ÂFƒÊ•¶×\óÆàT®²Ñ òuÛ[®ygð÷L«mÔ3­±½çšeƒðø†oÚV¸fÕà<®µÑàqmkÖ þÁãz ß²mpͦÁ?xÜ`£ÁãFÛ×|0ø›l4xÜlÛÆÇm±í€­¶]Jµì¶íû=!ìÓáw’?5¹¢)ò;6š"¿k£ôqÏö'wØ>QNª `]6é:wBãˆRûÛ!M·R{í³•ð­ÑÔ…^›áÈÀý‘IhŸM0 í·}1üq㊛°qÅ íØð›¡èc›`(:d;1üq7‹a›°›ÅˆíÔðÛn£6a7‹1ÛWÃo»YŒÛ„Ý,&lg†?îf1iv³˜²}3øw³˜¶ »YÌØÈ}Õ¬v³˜³ãužØbbYc[´±8c³BÖÀžÛ~oäSÄ4‡ûÂFs¸/m ‚Šæp_Ùh÷µ-Ñ(†Åì-É(aomÉFî‰=ªw¶¨ÞÛR|^? ªe[T+¶Û"ñÅÔÖ6Yº‘wðß–-ÿ}°erM4Û¶,hvlÙ\“Í®-š=[®‘ßÀ>ÙÄyF;°]m—ñ*wØ‘í×mù„ ùòqúµX‘öè+¤3Œ'¶P U9ê#|å,å,ã¼ÊYN/É®q¹‚³’³Šóº‘ïÅÀå#uo€Á­\Nm7ñÌ_A ;³Õò0uÐ|³ÕAsn«7ú½ ÄÚi~.Î~‹k&ÞÞ€0 öF®i‚&ÑÞM’½¯šlo&ÅÞ 9ÕÞ¦ÙÛÁtûm0Ã~Ì´ß³ì÷Àl{˜c¿æÚ;Á<{xÉþ¼lïóí=`ý!XhÙ{Áb{xÅÞ–ØÀRû Xf ^µåöaðš}¼n«íc`}¼aŸoÚ'⋬ÞÎÀšìÒ)»Óœ3œ³œTò6ÛçŒOŒ²ÎÖfç¶(íöÿ¥w‡]<ëݵ?ïÙŒ²ȰvÉ"O'Kœtþû3ܱ;€=´³çôÝ{Dq²ûÏ/Œ4„óÒHMäW<‚_sÀ?h'äíä™|Èþ÷¶“òû[È£öwà˜ý=8n_'ìä«|ÒN¾Ê§ì+ÐLÛï¡S÷(€ÍÙÅ«Fjë¬ñwJ!ƒ¾ÞѺqÞþO7èŽ?K6¼Þâ>pnù()—w9÷ŒäúuŸ?ïGÎO\ÀyÈù™ßèHÈ‘_:žÚ¿ ½,Ø¡úì„óúEû)ôKö¯ÂÏ zf?ƒê¹ý›Ñï?ã…üg¼´ŸCó—ˆ#äyû+„ym51öŸ³8²¼=΄,o‡üΞ`B n§õâËvZ/¾bO„fÕž®Ù“Áu{ ¸aO7íià–=ü`Ï·y„ïð¨ÞµgB³gÏ÷íÙàG{øÉž ØóÀCû%ð³ý2xdÏ¿Ø Àc{!xb/OíÅàWûðÌ^~³—‚çö20ÖqŒs”ƒñŽk`‚£LtPZKrTBNvT)Žë`ª£LsÔ€éŽ`†ã&˜é¨³u`¶£ÌqÜs `ž£¼äh/;šÁ|G Xàh m`‘£,vܯ8î˜Ä²þVæ¸p×Då×=ï ›è»ÓåW÷®ÜÑ ^sT © °ŽŸ»L|[º›ŸÙÃùÐDéãXAƒ×|Kj“0ÂOìÇen:ÀZÇ Xçx Ö;hUÚ-ÇäÇ0Øè1}6ȆX‹ƒšþ `íöß!G:~7†Dp×1†qÏ1¹”°ûŽ È šõŽI\åc ìvLƒ=Žð¡c|ä˜{OÀ>Ç<Øïx 8£ì…ƒ¡‰6À^;ù;¾AŸèc‰Ç e÷·Žj¨°‡üÏçœ/ð «Žx†5ÇK®yÅùúuÇkè7oø%ßr¾ƒ~Óñú-Ç{®Yæ\þƒcúmǪ ÝFǸëXÇN°Û€4 Ú49¾ÛâFã_´òïØñ¦c›¦c‡¦c—¦=aé…©ÈÿVîwäwkËùßìá^±Î=Ü+ι9D}àü9DMàü9DÉâ<€œ ¢ƒè<„œ¢ƒèü 9”°,çälç0Çy æ‚h¤:O _Ñ0užBÎÑu~…\¢ê<ƒ\ ¢Ñéü¹Äy–‚VæŒ5£¶tÆåÎxð(aÎÈ• „U9!_w&Õ ‹ÎdÈ7@4)kA4 ©ëA4i@4þœé›œ`³3l%¬Õ™¹ ”°vg6äÛ „Ýqæ@¾ "M:s!w8óÀûÎK`'ˆ4é¼ ù(aÝÎ|È= „=t˜‘&…`¯³ìsƒýÎ+à€³t–‚eàó*8ì,Gœ×ÀQg8æ¬ÇUà„ó:8鬧œ5à´óî8¢ÖsÞ„<JØg-äyPž:ë /€¶è¬‡¼JØ3ç-ÈÏA {ál€ü”°WÎFȯA {ãl‚ü”°wÎfÈïA [v¶@^q¶âVmàš³\wÞ7œwÀMç]ód³lÇÉî™QoͰ}§¤ÃÌW}Ý7SÚ‰p]f”Ç΀¸æ¡ó®ÿÙÙ ù”°/Îla,Áõ]´_qÖ™óøÍÙ ž;ûÀXW?çã]ƒtÇ…Ñcs²K6d¦&Ö°™´á)®QJui®*Ú­Þ59ÃEÇdº& g¹:©²] Mšó\Ö)œ\­aÓÂaÆÌ+ÉYá0'(Ÿ¿æ…ÃSA¹ üZKÂá™™7«AU䉗`1ý £gxÈK®×xûË.š0Ìw‘£š¹¨)t½Áã¹Þ‚Å®wà×{°ÄEÎiJ]ËË\+àU×*XîZ¯¹ÖÁ ׆™›–mâG¥kË,¾ø<€U»ØŠ®¬ÇŶÍbÙ«öÈ%¦î»hÖ€ï'¹k.Ò|ÿ:@|ÃøS¿+xÏÌÍ`öͼj¦y Of>÷@w`‡\ÿï1à:2s««/ø1èú‚—zì:6ûÝ ¹ÈòrØE¶&#.²&u‘éܘ‹,NÆ]dk2á"»“IYœL¹ÈeÚu‚7˜qÑƬ‹†0æ\dƒòÄE6(ó.²Ayê"”Ù ,ºN~Éõ|æ:Ã+¾ `Ë.öÍ<({ÀÖ\¬›Šþ÷lËqn¶±®Ø`zƸ`ÿÜô¶‹æ¦w\ñÁ´÷zB0:®„`´­\‰×pBæ*„þ›«ˆkŠƒýóÝç.šïŽu_ášÎR„s—"|¼»,ØÊÜWÁDw9˜ä¾Œ²ÀRÝ?Tÿ¶|1Í-ôUÓÝ•Á´ÔŒ:¥n¡Sšé® 枃aYÐ]Ç•³ÝÕÁx÷å­µQMðe÷_ßæ‰þf0ßù«V8Ô ‡zþh·(k¦j#g6ßÝ„K¸›¹¦šBw 4EîÖ`Þ2½Œ7-v“³¾+î6z¹¤¡JÜíUê¾ Õ5»U™ûTWÝw)”Brªr÷=¨®¹;‚ùj·ûPU¸ïCUéîN삪ÊÝÕu÷ƒ`ÊÝÐT»»¡©qÓÈù w^÷¦û!Xë~Ö¹{ÁzwxËÝ6¸ÀF÷ Øä~ 6»‡À÷0ØêÛÜ£`»{ ¼í&3¨;îqÈwÝà=÷$Øážï»§ÁN÷ Øåž¸çÀn÷°Ç=>t?¹À^7íÚç^„Üï^ÜÏ‚'.Ê6Ø;ð9ÿ‚/8_r¾â|Íù†óߗ݇àŠû3¸ê>¹{lÓýýþDÇœ'8Ë}Êå¯?¸Ï¸ü ò¶›&ÏvܱhCDýæþþœ¿W¬…gáVî zîDðÀº“ÁÏîˉJvÀŽÝìï#O°¯ngª…&ÛÒ,¼K™Î¯’a¡AL ŸsÄÏÜYälw6×,‹‘§ÝËbÄ\H¿÷"šq!‹zäæ\ ŸÌÃi !y8-1ä’…Ð$…\†&9„æSBhv05„æÓBòñ€é!4S˜R93„,x³BÈ‚7;¤šœ²ãÍ )‚œR ^¹懔€…!¥`qHx%ä*XR–†\³ü}ÙQ+ù±ÂB>+9«,ôé¯ÿúŠ6V’e±³Êê__EIȲØÎªñZ6VÚÙ <•ÝĽ­¬6äÿø½ì8€Ý ÑÕà”Y`à /Enò+ׂ‘…C½…—:·„CƒphM8›q l”´Ø´!¤/ÐÒ6…´ƒÍ!·Á–;`kÈ]°-äØÒÞ¹Þ éï†t÷B€!ݱì4€= a=–ü Ù×ÖòãC /·á³ô‡ÐŽÅ!´„j0¤ç<é‡BúÁáp$d y Ž… ã!Ȉ‰È“!£¸Çy› á÷lȸE|1VÊæCØ„õ^œ”-†°IŠ—²ç!l 'HÙ«6mARLD£,„õ"e'IÙ×ñŒg…ÃNK–¢£ò-ÄûÄB+æ9Ÿr.p.r.q>ã|Îù‚ó%Oׯ8_s¾á|ËùŽó=ç2ç ç*çš…&x×…GÙ ƒR²ÉÿÙâüÀ¹mñw ÎC¨J¨¸ÐÄF|è.˜º&†îƒI¡ÁäÐO`Jè˜z¦…~¦Œzf„~¡Œz f…ž€Ù¡§”B¿‚¹¡g”B¿Y‰d©R–ÊÎMiRVÊb­bYº”5„ÆY©ÅoåžLÀ>wxКhEª M›C“Á–а54l MÛCÓÁÛ¡àÐïŲL)ë Ê´òæƒ}“Ðl.ç@î Íårä®ÐKV¾Ëä¡ùV¿?ÕîPò§ÚZÀCâ߇¡E\.†ü(ô ?«roh©µê‚,[ÊBƒÊ¬³W9Ë­ÂîtVžÕhî`(-À}Z‡’(”ס´ w$”–ᎆÒ2ܱPZ†;JËp'B+¬(ïC+ñVS¡Uàtèup&tPÄg÷RÂbªñOBkÀyݚбz\ ­…~)´|JØóÐzÈ/@ {z ò+PÂ^‡6 ü›ÐFðmhø.´|Ú.‡¶‚+¡màjh;¸z箇Þ7BïB³zÜ í€æˆ®|è}È; „í†vâß½Ð.p?ôø1´ÿ~Ñþ í|¢Íúòˆv^è#ÈÇ Úv¡½OA´çBû Ÿ(éCû!Ÿƒ(ãà Dž ‚ñ ºõa!'‚èÖ‡ ANûïiÙGØÃø‘6f€h–…BÎ ³ÃÆÁPÂrÃ& çv)lòePÂòæðaÓ`aØ Rñ%)+ c³.KYu›ƒ”/e7Ã~x‚0µa䫨.Œ<Õ‡ñ1 °yèžZyv]°RÞ]~,ñ$ôÌJõ¿n “<§ôö‚ÒØKJÿaSäåaدðPwÂ^á¡î†½Æ?÷ÂÞ€aoÁûaïÀΰ÷`WØ2ø lì[{ÂNYŠ¥â5kÙcaÿ|gÁ +ߘvÓJµí.>¶…‹O„}€æ±ˆmC5¶ ÕTyi›#/m3aä¥m6lÇÊ—Ô‚÷ÌlÏ*˜ a¶> ã‘°Ÿ†}¢¤v@I5ì\ û > ;Ÿ‡}_„ƒ/ÃNÀWa§àë0~ö•’jØ%Õ°o”TÃÎ)©†ÅÚTÃâÀÕ°xp-,\K7Â’ÀͰdp+,ü– n‡¥;aéànX¸– î‡eòÁOa9àAX.x–~»…]¿„åƒÇaàIX!xV~ +Ï®€ßÂJÀó°R06¼ Œ ¿ Ƈ—ƒ á×ÀÄð 0)¼L¯SÂÉò15œ,Ó¯C“^ f„“ûÌðÈYá7Àìð›`Nx-˜^æ…׃—Âo—Ãld5Ô9?¼ ,o Ã[À¢ðV°8¼ ¼Þ–„ßKÃï€eáwÁ«á÷ÀòððZø}°"¼¬ ï«ÂØÄK¤¬&œuÛÐx+EñÎzl´×£T’òSÂOY’[á·6J´‚ª!ü‘Í?OÓNó4Má½6¿·êæpZMÕÞgó{«n §5Umáä‘»=¼÷¼NHï„ Hï†S«ë^8­žê§ÕS÷ÃiõTg8­žê §ÕVÂl~ÿÁÝá´.«'|ÐFë»Ûü¦{ÃÉtïQ8­Ôê §•Z}á´òª?œV^ „ÓÊ«Áð!›¿®xNuÅP8_Õ>lËÊ¥¢CõXxÀˆ{Wå·¤ƒãá´`p"| *¤l:üÇqü7ac“6ÞY˜²!…O ?fðc6|ÖÆÛ>sø1>g“°'áwi\8-ƒ{þѰ>.†?—Âð®KÙA8[´ÕédÕRv.^²YÙ—p2º=fC¶Nõ>§ôþ‚ÒgøKJŸá¯(}†¿¦ôéyCéÓó–Ò§ç¥OÏ{JŸžeJŸžJŸžUJŸžË"|í›R–ᑬ٨ØZdzfz6(az6ñ¦uRvÙölsFY½”¯vžz\lÔ7ܧ¥lFŠÞ‘‡\ó{f!_ñÛüÏäR9é/óµÂUY+”{vlþö®yÈ®¡ÂCnø+=䆿ÊCnø¯{È µ‡\õ×xÈUÿ ¹ð¿é!þµžç´IŸ‡üë×{^Ðö|r«ßày ¹ÑCNõ›<»¶?úÓnö?íYæ´zÈ&§ÍCþÛ=d™sÛC–9w<{x뻞}ðžç#Øáù„ïÑ e]v€¸hD‰í¹xH_%ˆŠÛ#õÓ¿Øø µxyŽqf¯çìóœ‚ýž¯à€ç ô|{ÎñE?Œyıv1ñÄÙ‘Ò<Ú@Y‹”MzþÄä”ç/ù@á¢çBÉ=/mêÑᥠ>î{ï!v:½`—÷>øÀK µÛK µÇÛ ÍCo² PÂz½]ˆÇûRIÞwq?Íü0èýÃ;­­&÷õ½´µÃ—¶vöÒHÛˆ—FÚF½´Ëý˜—<ù{ r›OȽ—À)o.y ÷Ò¾÷3^²ôžõÒlñœ—f‹ŸxËðï¼—|ü?õ’óú/9¯_ô.£ºZòfCóÌKû$<÷Ò> /¼´ÂK/m£ðÊ»Š0¯½YмñÒÖ(o½´5Ê;ï:ôï½´²7ÿ®xÉš|ÕK»[¬yiw‹u/m—±á¥í26½ÔÏßò’‡ù^òÖ¾í%oí;^ÚJd×KN«÷¼T6î{©lüè¥Rñ“—JÅo7²ã¡7Wþìíúu¡—¼'~ñ’1DZ·ÿž€È^òUòÕK¾JÎx*ùæ¥sÎSIl¥˜¸úêñ”"è«'FP HŠØÁÕ’#visÄ3èS#(¯§EP9”AåPF™1gFsV™=gGÙsNÄÂä‚–ñÏs D·0âä|P "ÈNaùÑ)ŠxL†€v%â …PÂJ#z¾ ”°«}H7åýൈ°"b¬Œ(AÏ»*â1äëC`uÄ0Ϊ%ìF5–oFÐH}mÔ×EP“¹>‚ÆëoE7û†òfßAS M4ÒAS -4ÕÑ-–uIÙíé w‰Äù…óøw‚ ªªˆI‘XöS„x„’|Ä(Ø1m7*©6, ”õHYÄŸØSD¼à³NöáÑ8ÂEL +<’Š&ícSvªÑ§í|ÝÌ þ ŽÎDÄ,õQ é霆­žæù :ÃÎFÄ‹¿²ùî]êiÄ? ” JÙR„ä)íÜÄ_0•~±`’ IÙ›é".ð6b‰‡xÆùÜN»½€þ]ÄKûD lDÊV"Ø+ûT6*eëÒ×vÚßõ ç[„ÛˆxnF¼·"–í²q)Û‰¯ØùÂHÜq7bï1!eŸ" kÐÎ鯵7ðý"6)•GlŸ#>€G RyÕéÇÛ¸îIÄx± ~ØÏ"öÁoÁóˆOTØGPayÆG~"ÀÄÈ/`Rä1˜y¦Dž‚©‘_©l<Ó#¿‘ç`fd¬C,›’²œÈŸãܱN¼pHpðB:Ñ$I …ò"“ _ŠLv Ÿ™æG¦‚‘´¼·02 rQd:X™^‰ÌK"³ÀÒÈl°,ò ”ÍHÙµHIŽƒïŽâð UDæ9êD²Y)»yñ’ƒˆ—¼“›ï óUV€{WG’#çšÈB\ëFdx3²¬Œ“[Y]dŒìEÞ{#;Á¾È.°?ò8Ù¿ e£‘¬Ò"Ú„‘ì!¤%)›d÷eÏÍ"å½Bô ‡~ 9 8„ ñFO#¶ù˜tlˆ¿Ö°ƒš¬ä×r1’|\.EŽ@óÏØ(Â?‹Eøç‘§è¾G’â—‘´ àU$­x9æ 9U©hÜñ>R=áà‹´&ùµ§8§ÜdMˆ¥Y®šs ý)úOø¯yüZÁ¯§ü×~­â×¢C(~akøµ„8X|nD>7#_€[‘/Á‘¯ÀíÈ×àNäp7ò-¸‰~ˆ”•F…¼Ã |Š|‡—9ˆ|ùD¦Ž\†|¢E¹ƒv¹ ž‚¨º"× Ÿ¨º"×!Ÿƒ¨º¢6 Ǩº¢6!'€¨º¢¶ '¨º¢>@NQuEmCNQuEí@ÎQuEíBÎQuEíAΑ£öÁ¼¨”£>—A Ë:€\JXaÔ!ä"PŠ£>C¾u–Dý¯bÙk©è‹ãzÔ_ ÉàXÆÓꉃÚq§jÇ}uðüÿ’}spcÛs\ª:ꩉŠu¢öÅìfTäZPÌê¢âüR øQ•€?nEQ“¬!ŠšdQÔ$kŠ¢&Ys5ÉZ¢¨IÖ•ˆm raTäÛ ²WT2ä» špQ);@4á¢R!w‚bÖ•ùˆ&\T:äýú(Úhâˆ~}5û¢2 ï¢+¢h÷ŠÁ¨L':WQYN¡?ƒ¿‡¢²q‰á¨'oçB5• ÕhTž ºÕXÔ%¨Æ£.ãô‰¨|h&£ À©(Úãb:ªú™(Úõb6ªÈY씽•²÷Q?^qR5Uâ¤IâR_Ž*sZÙJÔUp5ª\‹º®GUàQ•àfT¸uüU nGÕ8ƒØNÔ §Xö^Ê£ØM§øâ²”}‰bµÐ­HÙi«s"ã­J%‹j²Uøe®wR^¿åäeyã8ý¾ÁI%4•[±ÑTnÅE7:ýF ñÑd”MëF£i}hR4­'Mަõ¤)ÑäN#5šÜi¤EÓªÒôhÚ9#šÖ“fFÓÚÒ¬hZgšM«Js¢ÉL!7šÌò¢¹£ìè&¼Íåèf0?º,ˆn £ÛÀ¢èv°8ú6Þmù4šÝqfˆdRV}á.ì{N^jÄÿhe×¢;oÑ÷qNet 4UÑNôŸ¶¤¬&úbø?õ;XÚ/\øÕsmœþ¯xoêF4Ì7£©7UM½©ºè¸h}ô"ù¯“²Æè ÝBö8¹“õ×äà‚DðØ4#úw¼çGÓû;RÑCgK´ç‘“t÷òïãüuÆ¿ßIÖ¢N*c…„øX8 ‡aá0"F…Ã70pÜÉçè&ø'…çšBÊjž¢=-dÇÊXÑ3”±¢gÕå¯è9Ê_ÑOð‚÷¢çÁŽè§àýè°3zìŠ^D?»£Ÿƒ=Ñ/À‡Ñ/ÁGѯÀÞè×`_ô°?ú-8ýŒ~Où+zŠ^‡£WÁ‘è5p4z©uOÊf¢™^-Û—²'ÑB-¿á$#ó#úAѼa½‰ Ÿh m)ZJckÏ¢ilíyô–“;yäÜvRmµƒ‡R¶Ív!}–²Íhö?ÿCÙ‘”íFÿn¢íó4Î]‰°NÁË2w‘àôòíEÓ(ß~ôE;äü,Ä<íEõ1šö¢ú}„×8ˆþFãnÇRvÍNœ´±y4ûW^Ù‰”ÅúD§B”EˆS)KðýØ*–ZñÕÂe»ÅÂê(>©Ž &úÎÁ$_¬ 9ΦøâÁT_˜æKÓ}I`†/Ù%¾øUʲ},ÅÕ%’IYžOŸêâ×MsQ¶OwýºÃ * í/sÙ÷kc‡Z9ù¾_›<ÿïÆN†‹·oš©^ñeºü­œB•E¾[+'ËeeÅ>Z|Å—g-ñ倥¾\°Ì—çºä’KE£Òk>vÙ•+•Å^`U>Ù¿Ëò)ZmrÝGUWûòq—ßCrMwÕú¤üA Á§d%ÆÝ-h•}dNUï{NVN X“O^Ìÿ¼âòÛ75ûȾ©ÅW¯P*¼° ÊWæB†ò]å!Ë]~¥vÙ(Ýö]ãš —ß¶èŽl‹îú*ñh÷|U`‡ïº«èYÒ…ïbú£•jµë¯PTƒóþ!»ñëGµ.¾‘P‹Tõü3Þâ×o¾l£KÈÛR;ëöшjFKúš\vöÈ÷ÇÍP{}ëz;ëó5Cßïkqù·ÀðÑxƒ¾V~UÚï±vÀòÑxÃ>ÚFjÄGÛHúh©1m#5  êOúÚ\þ .§|4 2íkGlÍøn»~3>šõÑÈœïŽKØäPÌžøh`dÞG#O}40²à£‘E Œ,ù¥ðh^úhxä¹Óû¸1½ïžpéÜ畯_åµï¾WP½ñuBõÖ×åúuÇD1{磱”÷¾.ÿIJ& V|Ý®ß6×]õÑæºk¾\cÝGÃ.>vÙôѰ˖†]>øhÈcÛGƒ/;>|ÙõÑàËž_ö}|(ÄGC0Ÿ|4sà{èò—(‡>*Q>û¹~Û6ôÈGÛ†~ñõºüÓ Ç>š9ñÑhÍ©Fk¾úh´æÌG£5ß|}ÂKÑοç>Úù76†æGâbú]þyŽøšçHˆ¡ÄØIŠÀ;%Ç ºl,%Æ¿"Z1´{bZ û¤ÇаOFÌc×oûgÆÐ>ÂY1CH»Ù1Ã`N̘CcCy14*t)†F….ÇШP~ ­W(ˆEÖ.Œ¡ñ ¢*Ž!ƒ™+14iSC#J¥149SCãWcƾfÿÞŠ¡íÎbhÛ´ÆÚ6­)†¶MkŽ¡mÓZbhÛ´ÖÚ6­-†6yl¡MoÇÐjwbž¸˜T´¨îŒÏ#9uÄÌ# ïÇ$’r@%$”³„H(g‚$”Ê‘§,¡À¿zà½Õúîÿýîó¾®®®®ÔÕÕÕ èÄ•íXÆ [â‚›¨êñŒ›¨vGÆ-¯èÛÉÞ?WÀ–±>/pws/DHz*ã.’žÎðÞøV¹ ïæêê¤&‹Gžñ_Þ½7½ ïM/Ã{ÓËðÞô2î¡2îã÷bÆüvf<ìeñ;—2ã÷rÆü^ÉxŠß«Ïð{-£¿×3žã÷FÆ üÞÌx‰ß[¯’9€ $ܧìIæT¯ gXKT¸„…×(…Â)+T8dE 7†G°b…û„û°¯kLÞ"ß êKBQ«R…°@2Z aߣ´i¬‚+NÆ)!ÒÛã”PÃ÷Æ+„c «#–°JÿþD%ÔøÎ$Eöyw²"ûþ`Š"›2¤ ÈÏèÊNaù»0•„[_ƒi¨%rÁtTš2aê -.˜‰ŠB› f¡¦pÔ³î Ç]P®pœÀeP¸œrÁ\…ûÃ4˜§ð8ë‚ù „ó.X ð ¸è‚ …Ã%,T¸ W\°Há!pÍ• ….X¬ð0x”K·]°Táýà® –)<T,Wx$F¹a£Â¡È U 7Cá Ø¤ð$(uCµÂÂŒ7a³Â“áÌ¡Fá ŒsÃ…[`‚jž“ÜP§p+*ܰCáÐ<~mè[˜¸îxåSdö›U’,}Þj– ¿ýëÝ-–­Ò {IJ-qÃdH}c§©Ì á•¥"ثȆb(ñOØ/Á„UˆßߎÕ.ð¾ û³û³ån8€BwÃAE–öÀ!d°n&ø0ŽÝ†#8vÊ(kQ»Î-ÜD…›Z‹s?„é”TâïµxnSmrÚHж‹Þ¤â¹t&ÓÆÚ‘ñ,vÏfG˜§G탎á\?r’‘2‰L—Èl‰,4ªJIãr©‚Hn– ²Oo•È“/‰ ñ /ñI$Ÿn€ShL¢ÇKÑi¹m€Ó 7É¥œTsRÏÉ6NvpM£3^örÍïgÑ‚}üZ°ŸŸG·à‡99­_.jpÃEá¢&7tІ ì×4{¨CÏu¨‡“bãÀ¾Î%dÅÕeÔxF ¹‚yà-rSB‰ñf¹Ž²K7”Ãhü†ò1Æ›Jˆq,~C}Æo)!¾ãñjš`¼­„øMÄo¨ÿ$ãE˜l\8ÅX#•kbäà©Æ-1²<ÍxW‘C¦ëbäÐÆú9l¦qkŒ>ËØ#÷›mlŒ‘#ÊM1räã¶9j®q{Œ=ÏØ#÷ŸoÜ#Ç,0c+Œ»b丅ÆÝ1rü"ãž9¡Ò¸7F°Ø¸?FN\b\n$Œ¤ÉHNµ¨ìBc±àWÑ]‰¡ìk ÷ÑÅgŒÐ̳Æ3>šîú'>d´/ï«-íCá©Hö'›£X•/©÷%Û|É_rÐW›vÉ—¨¾ä±Þêë×=ÆÙáFöD$îPöT,Ô7<)±Õ Ý"%¶»á9æÚo’ ñù€¼TV¯‚翈ïg¾£Md¼‰”›4îóMd¡ÞYf"«MÐ#6O‡Ö™4µ ,#£Òa¤cäf%SpßÈ(‹¶B‹Ì6™Š,²Tm*¶È†Í¦‹ÌkL¥Ù¸Å4Ú"ûÔšÆXdß:ÓX‹lª7³È~[Mã-²ƒi‚Eh4M´ÈM¦I9h›i²EÞnÚi"{uÅšÈYé4‘ë&òÈDºMd¤)÷ÓB~ŠÐï–æû‘J?Ý?Mý2Tò 2Õ"vß}üˆ9®w.éÐ *õ'üµÎ<Zì¯miBìÅ4˜.Ü¢ºa†Wä¾–ë3-bg°YH`d³qÜ l•?©÷7öQ”£nÃÈÔm™k!Ò02϶úÏ·„H þ ,!†Fÿþd·?«Ë‚©_;+„Ô—n8è¯åæ…BŸÊ·a‘¹ñT }F†ÅŒÂÁpÇŸ.±p—ØR¤ 7°Xf!DF±dr™ ùt9’P²$@3{yY¥®À_P@H«Nr<@³j¥Ðdì`X%4?V M&†5B“Ƀa­cµl0¬³àñ=m0œ çuæë½Ëu+€Ü×9?Ò¡‘4F‡¦’™d^ YHÚÉ­@¼*dL™D¦‘Š ²*ˆ¬"X¶×…÷MÛ€J&F³¨cbV…*&ưM¨!6Õ¨`bÛŒúaScÁê¢ø[°ÅB|M¤ÖB°¤¯³¿ÏI=.V}Ð}< ·mÅÈoj°ÿ Òh!˜½›,$0ˆl³ ìl·`i¶¹È ȢѪٿÓkÿîP²/T‹£]ŸËÃnáÏ•ƒaðçêÁp(T÷½Õíµˆs­3TÛû¼Kºyà!§Ó«¡†q\†ƒÞÝ|÷^èaÜÍ÷C MB‡’W:}Y˜¾Â4ýZ¼ë­B¿éÐ&ô“Ëô´Ù.(¶ †£‚¢n0[Ãqƒ¡CDÄ6Œ”0à ¡Mó`8‰Ú„û²SbóIJÓb}âØ¤÷#5aZzVðÝ;Î ¾-?€ó‚ïœ7à‚à{p0\´ÞŒe´…ÿI.ájm »Œ[«6¬8<ÄPV.óú°ÒpÙ¸5ìJˆìÓ6:\öm »‚yª)¬Y7uw˜æÄ“I2Ûv½³7ìB¹¦yûºírØ£0R®ÍšN‡Ãuï[¦c«uhk¸È! rȶpÍ—7ÄÞv ºüÚƒuùŽp²;œì×gžÂ*ÔËö¼ŽêÔ¡«áô5e¯…Oè§Ìì§Ü~k óû‘uýHu?Mú]t:.ÌG2QÑ¢Íýûi¦ßs:Óà>â›úíèGöèÓˆi'ÃCôðÞ~-¡Ò¾~Åú åZ$#F§È¾/"Hq¤¾th–ÍÔÖeLŠØ‚ #5;Æ¢E‘ãPHeäøÙ°8rY¤oߨ/íÄÂ}Ù$ÔéøûON!†D‰OÁyË#ËpÞŠÈ©8oeä4TnUäV]æ6Ú¡KÃ*‘íŒÄŠQÚ)jÅÝ‘û"ÉÙH퀙ž‚NÅûòKáÔGƒa†pê“ÁbÄ&¼ ³¼ªC7#ɽ£FÒ™)x&³P½{‘u³g{My¥ŽŒ"%QZg¬•E±òæ6U1`sS0yûó•QZ¬Ì*¾Â¸Æ( „Š£†@E ªX4¦`ž)‹Rðä=ÖFi*TŠ™k¿£´x_,0•K¯ñC :J‹á¥bdâX&F&åBÊ´Ý+„”©C`‹®ykT˜v6¢©á2[…ËNV§ˆ °×̬M!<¬K amQëqáÚ£žûˆ£QpáŽEmĨ:U…QÕµ £êDTuŠl:µ9Eö;µ)Dö?U“"œ‰Ú’"žªM‘ƒÎEÕ¥ÈÁç£:u5®E‘ÛQd\´ø—%§EË}Øúq©[,³éÑ[QòŒè ™™Ñ(yVtJž½8Xö)î6ɾs¢˦¹ÑÛPò¼èí)²ÿüèf”¼ zJ®ˆÞ‰’FïBÉ‹¢w§ÈreôÒhÍ¥{„ãªÞ€½Âqk†ÀŠhñÏ9nŠöy-aUGïóê³?%DÚ}ýd&SB 5чÐ[âwhß] ‡SD lŒ&;¢µ•9â0Z„€ê!Ð*V¦f´‰õ¯íbeê‡ÀîhÒ­yå\4¹¨wz¢µÝpTðÚÓŽ ^Cà¸àµmŒê¯ÑëÐÔþ¬#Eœ[Cà„˜¶ápRLÛ5fô×BìFýÌþ[û³Ó‚tï8#H÷³‚ôàØÖ_ÛjçÄÈš·à¼Yõ\²W¿… #aG²[þª?íLñv—R¼…ݔ͗QdYÌ\Ô©1WqQ§Å\ÃEsuFÌì½¾Õ¡JZ#Ý@Sr×c¾øëí¶<æn\¨´"fc Üòz¿:†l‰!m1Ú ßFGcî Àã1'cÈ]“»BµDÖ•â½½¨h&ì{hN¸™ÝÇU Obçc|ÿåýç¼È4xœ?æŸù†xÿ0ˆ"¸B” Xü>Ûøâx”‚ÚÓoÃãî ‡ð”ŠÑ|þD8rf:\‹!űdZl¤v­ø+Cà™pðµ!Ð-$ÜÏ…ƒo "Pî —BB×x%$Ü=Bƒ!P`å&x4FZ¹<Á °rx6 ­<ž"+„C ØÊƒ`Úw Äʃaúw ÔÊe( £­<F …1V ECa¬•‡AÉPgåá0z(Œ·ò~0v(L°ò?&ZqwÆÎŽÕ‚s’õŸ4&[Qÿ)½ã展±ZMÁq¼l”á0Þ@¦ZñêAÙ4$Z[«M·Š6ÃÂêbgZ‰øgkˆTÛ«‘:´7f[1üýÄ’6E¹ÐcÎP˜#ô˜7梈öØyVY:{#–<ÐçÇé•»MÓÂf¾`³p(,ÀéÓâæèøýd67®«Ÿ,Í‹«Ðç-Õ¡•:´I‡¶ÄiNª@û$‘…hÚ²ÞpmÜV®I‡NÄ‘KqšE‹P…+q•hÁÕ¸ÅVÙp-n‰Uæ×ãnÆù.µâ.cl™Õ[¢-·zK´Vo‰¶Òê-HVY1”#Øj+$>l òº·yÝŽ{ç³çû‘õVQ‡o°Š:|#N¦¤ çR² ‰ÆU#ñ£¸Í(øqÜ3]ÉñdJ¼Ó5VqC(ײæœ8'¾'ίÉóâëQãùñÓͲqAüV«ìSß`•}Æ/Ž×®×ìm®o Mb· …m¨4…í¨ì ›âI£>m{¼¶2ͨÄê^§6ÇïÑ éPK<9;¬"KœˆÖÊ*Nú]¨ñÉøâþ²t*~/• §ãw£Ægâ÷XeãÙø½¨ñ¹ø}¨ñùøýVÙt!~¯Aö»À*ûwÆ´Ê—âYåÀËñ‡­rЕø#V9øj|‹U–¯Å·ZåëñmV9ôF|»U»Ô*‡ßŠ?f•ûÝŽ?n•#îÄwXåÈ»ñ'0*ÄŸY ®À½x-fN¡‚ã$rÚ*^¶…u÷ãéFŸ¾ê g…¯N…gñpMéŽoê#9/‚c »`Ï q°'¾W¦ á®ÌÈ„Ëh稄+hgaÂU´³(áÚYœP– å¾ëÈÀÜÀùrçOM¸…ó§%ÜÆùÓŽ ùŒ„;8fÂ]œ?+aN‚~GO U Ðåõøæm}UäQ“pÍJ%ÝÁ²´%áy°l¨MØš ÅÏ}ëö%Pää!fƒ†„¾²Ô˜P`’ M ¥&™oKm’ÛvêÂöëСÍ=„{F¿Qäá„¶-`ñN“Ù¥úwÈ€§‚ò~?¸š@n|©©ÈÉÏ’aÈúß„g" ߀n‰êP¸­3|ŽÈ}]…g:T:€L Ÿ`è !ðÁPx)> +õÁ Hõý¾ †Ÿ …±°Ï†B E? µH“>ã¨N>Ò†äãß…Q6$Ÿð. òž¡pB§=£C—tè¦>_«¤‹Äü‘àXÌ/wtÚ§4[KlbǼ@F&¾þ¦;*Q¼é&Š:½(±4Q;gK…jÅÃ`´`]: ÆÖc†ÁX:qÜ0gÃm¶‰Úª3& ƒ 6™O¬JÔWÍ+¸.Q¿1èÐqfÎéH<•H®%ÒÉ_Oœb“¥‰÷Å_ê<Õ5.C^oõ¾A&NµÆüüV˜5 oà©=M¨ž4V–C:’ÆÉr艤ñ²v2i‚,‡ŸJš(ËýN'KÒ ]!J°æ7Å‚˜øQÐ¥$Í«P·ËI÷tÊÕØ¿Ÿ´u}ôX§Z+¼½aô$‘;a×`u y8<HŠ“5gLJÖØ¬Ç©ë=P&'W&kþÜ øT ƒ"ª‡‰;–$îXU"j†ÁÒä­ðÆkµMÔ1›m"«×ØÄÅj‹ðDÆjmÄh u¶P¶,¹Î"-O®·Ÿ@²ÕbX‘Ü€î]™Üˆî]•Ü„î]¼Í&û®IÞn“Mk“›m²ßºä6Ù}òN›°!y—Mܘ¼Û&U%ï±ÉÁ›’÷Úd¹:yŸMÙœ\ÁåКäý69lKò›^›¼ŽËýê’Úˆ¯²ÉõɇmräÖä#69ª!¹)™4'“3ÉÚ%±6+¬mƦ £Þlaíh±9…Ř7[Ù1 y³·‰Ÿ|ƒÖ¥Û’à„˜Lä¤-„M>i •Î%Ÿ²?drÚFü™ÉtÆæ}™<‹FŸO>k å’ÏÙBŒñêÓ™|¾”|5™ÜHÖò.ïÍäREÍQ´M}Þ¨=Šˆu+Svëdt¨CN›¸GœR´ç”K6Qx^¶‰3î .Õçä*.ÕwÈ5\*ƒ—Õiå:ÔåÿYå&®Î9å®Îy冢iv¹<‰'ª.é©=W´°ºcóþtꮟÃ`žE/u¨Î¢=tyõR½!tí®·ÜG-¶Z  –‡¨E£e»>¯E‡ŽZ4Ÿ<áÚ5  y÷†Á‘±àúXÈ)‹ñ)úÁ<³‰G¶n‘És´ž‘h=#¥”pqï%FJÎê_ÚzB÷¯WÁ –þÚá…ü‰?C%¬Qüj»hY"uâ7Ôpɲ>>„_Æo¨ñŠe* ñ¹ŠßPßk–ªøÓuü†úݰTLJøßÄohÀ-KM|Hàmü†Ý±ÔƇßÅo¨Üe© QñzÏÒv¿¡á,#ír¿‡–Qv9â‘¥Ð.G>¶Œ—£žXÅËÑO-Ï-ä¥E[²"»ÈÁÃ`jŠæº)qÚ Áîý‚»¨¼JÑŠ™)£íâ}dŒ]lã±öiVÊX{¨avÊ8;á~d¼ýÈ{/O™`5ÎI™hñ™›2ÉN|üÈd;ñõ#Sì!¾óR¦ØCMóSÊìÄä'þ®ÖÏL³‡ø-H™fõ¯H™n'þ~d†ø‘™ö€…)3í¡‹RfÙå Ê”Ùv9xqJ¹]–—¤Ì±Ë!KSæÚåÐe)+S^f]•R£›´#E?-ìâg¹óíÞŸå¶§1V2ÛªM[`Ç+›užU+ü*x$…H=È"tÀ|ëúpYZ`Ý.*¬Uá2_hÝ.Y«ÃeŸJëR+­´sHŒc‹í¢h\kÅKÙn5½~ŠY—Øñ³.µË†Öev™ï².·ËÆÝÖvÙgu¥]öÝk]e—Mû¬«í²ß~ëb[#¸F³µÈ5ÑÎÖÙñLr°e6}ëèÐ~:¢C§mIZJóø´(1oÄÅĦ W3•lÂ,ýKŒX¬â‚‘\0J¶à"QR‹‹$þ¿lâÊ`Sž:cÛŠvœµ5 çlhÇy[ÚqÁ¶ í¸hÛŽvtښюK¶hÇeÛN»ìŶË.\µí¶Ë×l{pA¯Ûöâ‚Þ°íýiÛ zËvô¶í ]»c;d—ÃïÚcHwÙŽ`H«¶ é{¶V»ußÖf—£Øë¶âök×Ï2ûëÚd»(ЦØEVfŸn×¥ÀGíâ~PgçÿòàsÌ.~˜ø]±Û¥¾Ýnè{øáâá§ÁþzÔ5Ú÷ÚÉ!u\ì®Ú¡ÕNNéò:zá |ƒ:4eÇ9´„´{!è´9«ô;r£o¼±4Áqd`ˆa"~Cù$GëÀãdü†úLq´ ñ-Ão¨iªãè@ÙošãØ@Ùºãø@9`†ãÄ@9p¦ãä@9h–ãÔ@9x¶ãô@Y.wœEÏqœCÏu,pÇH3;ÙÔÁœÊ.¢õæpÖiÇ/]²ã7€]¶ãìŠ<ήڹ™²kvîkf캛Ìì†û™#ØM;÷7û°[¸“¹mçhø;Jôç;pÃh§£Ê©¹« …¦“§¶j*®ÌáÞ d‹óF[³ÑI¶;µít_¸÷ÀÇð@¬Ñ¡á¡]üþcxd?‚ÿ£¢pßOPS8ú1tðšóØ#ÿsâcÿæÄ'î2Êž:¸Û<œ=sðÁæ¬ÛÁ‡˜Áž;øPógì…ƒ3ç³—þ±ù—앃ÿØìa=žeþ+pòló¯ÙH'ÿÄü6ÊÉÿÝü9+tòŸ˜ËŠœü§æß±b'ÿÞ/Jœ<ï¥Nžkþ=íä?7ÿqò<ó°±Nþ©ùlœ“ÇM:ÞÉG ™œühæD'ÿ Íœääùhæd'ÿ%š9ÅÉ=hf™“ÿ —ª“ÿ)§9ùorº“Žq=ÃÉ‹f:ùï0®g9ùï1®g;ù0®Ëü?Ë'ÿ#Æõ\'ÿãzž“ÿ'Æõ|'ÿÆõ'ÿ3Æu…“ÿãz¡“ÿãz‘“ÿŠ­tò¿a\/vò¿c\/qò`\/uòÿƸ^æäÿĸ^îäÿƒq½ÂÉ {¥“tå*'æ/Øj'/ó²5N^æ?±µN^ æ?³uN^æ¿°õN^ 濲 N>ÌÿÅ6:ù0ÿU9ùX0ÿmròq`þ«vòñ`þo¶ÙÉ'€ùŸ¬ÆÉ'‚ùðÔá“À\¬ÖÉ'ƒy$°:'ŸæQÀê¼ Ì…À¶:ùT0kpòi`.ÖèäÓÁ\¬ÉÉg€¹Xw”Gàäeš–DÊÓ©*~êô,Ùû07K$ÚO:uhµ­M×2ÿ6'¡¿{í–·.ý`ºßv'«Q¤ÙéÍô;œÞ·ÔN" &»œÄðÁcŽ‹?¿r†°Cé{œ¡Òáô½Nbƒå 1Ißç å-éíéZÔ*´ê=W˜8WªÄï·‚ýNñ“ÛApÀ‰‡ké A¢YéÚ3ÑA§ÌÎ¥rÊÒùôµÁ²áBúa§Ì/¦qÊÆÎô§HÝ­NÙçRúÕô×K´ké¢D»ž.J´é·u]Úp#íhÔçä(p'ýZ¶Èqgˆt7ýI:í@‰OÓH²ô,ýE:éÑ•5Hƒ& ú½öMÖiçëÐÂAúï:½¿Zên_6ˆ¬¤ÿe¯T7H³þ´ë·vÆÉYx Vâ÷°ÏáˆýY,¹€~ÿœ\DCêÕd­¬W/‘\BF —ÑmÛ3ÈÎ íPº‚as\E–°%KŸ’(>ωb‹Ô=Ú…ùš <Ÿ×e}Üp"eCÜ«V—·ÄªmË‚ÛN,‰ÎËp$CÒKœymÜ3Ofê½mºóDD4¹a¾ˆˆU.è¼w¦*xï΂[Œ`9à ù™ç@"$ ‚%_ƒ;Ø¡oÂ\*û6̧‘>‚ l ŸÁrDò_Á;1þö!Îç°ß‘a1mCvýNàÇ?J"g|…Ÿ :€b&‘àm¥ØÊ;Æbr`<¶¡S(ÄI6B'vÃQ8‹ŠôÛJ!P"7('I$º?‘¥ø‰ºMaôŸÁ`Db£±ÛÎ`²A"q'LÃ6~Š¿–HÂ4 ¶cwÀ, š±MœÎÀÖ¼H‚=Ø&í•`¶[$¸…mòc ‰(‹ °¹Zj °ˆK$¥Åë±µž2Àlm· p[ûSœCÿ:J8ÌBzç&ß•Hj‡ÑF‰¤5q‡mz3‡ ØÚáÌ(AÆ!³±ÿÆ)?’È×nã%»_À¡Ûots¨Ãö›¯84aûf‘Ö!÷·–a'ö¿µÞ»°ý·F#|["ß>e„oJä;§}`6R}÷±݇íÛ¾ù^©/”bûý¾ô]‰¼;áwê|a/¶?hò…ÃØfîö…lß;à G±}¿ÓNúJðA—/”!£ùÂùa©‰vãð>”ÈGãL0Þ$×l|,÷<ÌÄîà Ì2I0d© fc;t•  ~ØZ,Âöã&¨ÄöÇ;L°Û¬=&X†mö¬Àö“3&ȑȿ_4A-vrÍõØþô¡ >•ÈÏž™`vs üà=‰äÎöƒØýù½ ‹qÎz?v#— Z‡!€ †ŽŽƒ,¢eqЊ[¯’–ÇAC”‹é‚8ØŽCKè’8ˆ †®ˆƒ½ˆXF«âàËiME`­ƒc¬¤qpU´#:XM;ã0^0ÃЧqì.kérTa}Žðz:!^ ´ tr<ìAüF:;J¢%¨¢•ñ0&“ ]÷q¨šVÅÃÛÙLâa"jè¶xXŒ$[èîxŒ5L.ô áì:z$c “ m‡u8´•E6¢`œÆ|:âaâ¨h¤ã1"1ÑЧñ° môe4"PÍÛ`/›Ù)@ †=²A[X· N PËÆØául¢¦¢6õlšn"f+«µÃ-ØV;<@ ‘í±ÃCšØA;ô °µØ“÷vvÒÿ†I†r@‰Y‚l¬›±¤aó°]¬Ù5xYÛÍ6:¡1{Øf'¤cŽaÛœô0ŠÞÇŽàw?Û儽"Ű}N8ƒÀAvØ ‡pÆ!Öî„6³'Œå ;í„b5Ã.9¡·²«N8‹$mì¶Î!ÐÎT'\Fà(› W8Ææ¥BAf¶0þ‚†­N…)ˆ8ÁÖ§Â?0ð]©PŽˆSì@*4 pšI…FΰöThBà,» Û’ðöÎî¥ÂÄœgsÓ ¯¯X{ü ëJƒ™xøt²Çi°KìY,Cà2{‘˸Âf§Ã ®²¹é°i ×Xe:T#æ:[•uÜ`Òi«È+ì~o²¶t¸ŽøÛ¬#0‰ÞagÒá&"î²+ép.v+ºPÙãtøfö<ž!â>{•Ý<`#ÁŸ1ðñƒà"±Iƒ OÜÇlÞ (M–à «Só”-SxÆV ‚&Q˰ÚAp÷ìs¶9*qè«Ï€£¼dÛ2à8¯ØŽ è@ ‡í΀H‡3à$#¥Ö èD`”t;.¡¬B©Ð&þi8êÓ’vo_–êÿ!@IrKZÌ Á¹¯’íFÏ«d ”J†ä{û³T—]˜N\¢3¸å¢miõœuXK²ç¨#5“|$ÃÿhIK(aì‚céä]p9 ð{ ‹þ³ f±,†J£°9Ï …`õŸÅj$‘’: Zó ü¿aP ‚&Ä· eñbP‹¡u8Ï|àä®–ÀpcKþyëOˆZ í9Ж x«µn! šŠâŽà@í}³ƒ\›ùp>ܾ¼§Gíï"QÖ‚ª¿•óЙGÓòè'$ÖsÎkð‘c€@ÒRtÖ=5>ç.$|ž`/E8_Ó}^”5/vA ¾Û“œD<=Ø«wÑïç(Ià)Pº`«‹½—;RI¢ž‘ØkpIåŽR’˜gö]†!¹…J’ä)Ä^“‹gå)IOö¶¹Œ?Í-V’¸§XAÑý5ùUÁ½#Yê/Q3l&±–ÏXÚ-Yäê¯ÄŠý¦¥%³”û©Áùœž þ6§Àà.0õ÷yåÑyþù-ù³¨»Æ‡ªèÅ´XZòg÷bþ˜÷Ä™„—J,’H0Å/|qLýÏœ¤[ ´äw—îÏ-9Ï é>ð<õ/-ùO!/ ÿ)ò.ïåôWroŽ ê¡îB÷ ÿ.|·§ù»úßyÏœI4ìM\»ÿÉ©}M@-N/¡ ÅÑ‘ð¥|µW~!´¸Ë(ÁHAæ‘‚ùOóRèã^ -ùÝ€2ðNHÔ±ð†A v=Ý Nx<éQ†WÂ$øRµW)(a:J(¢L~ÁBÂS” v#ëÀЦ(¹¿ÀP!ù(Å[†:Šâ®éµâÔþúÔH¢Î¢-ù#)NѧÎצΧj…˜:’ª ÅÔX15@¬S×ÒœÇ$“ß/² ‘ ow` ˜°Xí‚SYÐDÕí(¡¶¶}úÈ©6ÓœRÿ¼·ó­™¥þb%¤ NgÑTÝIsÞö|ø6 umoý´‹µQõÍëv¢† Ìhò«ñÆéêM’e„Á2‚wÁÅ,,*» 3 Îas)‹^§ê9Ú°Y°ÅÇÕ ´-!lˆÐt°N$»œ%]ÂæJ–á2U;)Ælþs'2U/Ñá’½(5ó…þ„‰ä²è^Ïêírõ v‡s\äá†Ì—NŠœ¯Óœ –¶Ì 2ƒ  ¨C½IÛC| iÿ>®Z0CÍ ÄÊ nê«Âí÷éÉûâŸ*Äõ Øn¯#nd‘nª¾>2ëCE¬o¨ˆ©¥ ‡’Äj}_ Íòý«¨.ØáÑ,L¡s˜:‡µä¥­h|íPç²vÙ#r^/Ö»Šó§”™ü,‚ÓÊ>N+½,`5SW¿Æâ¸º†µ¡¾É%ôLÄ Å8™€eGô„Ã6lnfÑLÝÎzÝK¸?O.-«;Y[kæ+'„Mv‰N„v{˜H¤Š7ìà‚÷!äDŽ%‘ã èЄ‚É0B .¡ÄWmGƒ,öÞQöžzœµ¸'ávê@ô=ÈœMBDÒ>ÁZòF*ž‡lÂÞ)숞zšŸ\.zɱIP;œAÕKØÌ¤êåÞæŠ·qߥõ*N.öN¾Æ‚+Ää[_Ê AîwXK‚™ÝÕdª* þ‹ |„„OÀKôõœ†z>E¢Q^¢nùlºç®!êL ÷xŽ¿½pЇþàÝê³¥¯œ‚~ŽüSªÞÉbË$µÂ;=!4Í_ô°_ü%ûeRÎdøp2o4¨Ë¥á8ö>½­®@8‰|ÚjPWöBmuBy©ùçS>™ª®–rê|†Kî:P×zõŒÆ6/:¿Õ¢(ê:œcÌ>Œæ^Å7üoÅ7JÁ‹ÐÇÁóPÓ#¸fsC+ËëInˆî=×òqèÃPëÃ@ðLj¹Á0~ú04øûˆyÀ0Pú0,8 1/FEF ŽCÌ|)¯HÂqà ˆ{ÏNîcèÿמþäEÏ·_öüíeOåËž½/{š^õ V­–Þƒíô.}D»ÃG¥‹ägò;ÊÄ®ª—ĮƎ0`ú丷F üFøà>á›P°F˜º ö#Ò€‘Ö•بYt»$Â5{ÃOÚ!© Rïæ®ýHä¿cjc¢+Ë‹8®n—²H_‡ºSjÃxöÁxnë æ•"˜ïeö"·ûY|Ÿ¤îÆ[j Zl¡žW î•D7¿<:³Ð‚¥W÷‰x¶?ÈÒCË·ý¸ø¯¼;cá€×¤à÷¼{àa–ñò~”åÓ"©‡¼dà ^µFø¨-Òp£øø¨­˜ÅÕ6©åûLØ®¶KíÃ}Ý…©€Ìš à åð èÌRkª½´öYð…H)8;!LFèô¿j{VjíSë\¯ZßòªÕâ{AR/H9+¿­^•ò‹RÕ‹BN©åÃÀ¼  ^BUL^UÎiª4 *פ–œûÐþá}¬0Ý\—ÐÜý(¿ƒk«vIɘG­¢pä#I¤ôÇY䑤>‘°xêSôv‘w;?“ZÜ1'u N6Nê¤bVÔWíôHj±!oµ?ÉRK b žjkàÞ¥Pu´wðY–:Æ;Øý•ÁqÞÁçYêxïà‹¯ Nô¾ÄRÓ;øê+ƒS¼ƒ=Yj™w° ûõÁiÞÁ‘Ùêtïਯ Îôf«³¼ƒE_,÷g«s¼ƒ%_œç,ÍVçÿƒÞÁÑÙêBïà˜¯ VðóÔe†÷Tôæ C¯WW°ÄBÐCG]mèMÿk èj;ç&¿9ÞBf£A¸zm:Ùlè‚#¶`36›Öc3.›5bs2]ÚnP7¼û«€Sk ­½‡ª8Q·bgl¶7¸;Ô&ìŒëí`ð5òª¢3[ͤ ÕNCËpƒºËÐÖ>\JÎ%Iž— ÁàÊ¿ËdqF¶ Üî.”@m::ÖÏ…ŠÇQEõ„¡¯°-N çë)CÎÎ÷Îü5ì7¼V¶?Çð6´ä{o.W/bwNoõÞéñ–ï—…§d0,öºâºA”AÞÈ»Ž–OȆ›õf¯åö‰Ù}eÈmƒÈ(¾"£ä•¤"òÏ!ˆ”‚Gß]ƒzO¬PßÀk'ß}ž|’}²`‚dž8ù$õ¡áË“Oê;ù$õÙëëÖÝ·nÏ ïÁú‡7¡¦¢Î~-^K¸H¨X£øb^±\ì—]°Ó%}Þ?5L‡.Øíâå‚ÿw“÷ff«C0aË+UdÌ.êǹ¥J_"þ´TQ³GôÛ€Äýñ_‘øo9“÷$…¨ÿÈ#F¿'Q&}$FGAß~¨E;Viýt¬¢–@îE-…Ö„P̃êhh-ó>UåVì³²í»\êXÈ|Îhñ§H8N¨÷}!1Jð\*ž–ƒ&s%äBßÑ…®×„®u#äN@¡uäŽWÔjMèfMh&tKÝÒ' k…Ðw9 ÍDÝH$Ú´E]IûÖËSIÕ ¢}$mÉ_,`¼ú¶ä/£º¶E´Å½D¼‰ûû€ ƒ£zqÅoÀi•âêÿÀû ü)?#h?dÞçQÄÝÖjnSõ.m±—gÛçd«]´Â³ˆb¦¼'8üº¿ ~IûìyIÕž>áâ&ÿ‘ö‰DƒrÆ¥ö¾Cb=T D ÿˆ¢ÿצwxȽ¹ÙêO‘69Âì\q‹‘`*N/Æd¿B(4X¢þ§…Ë8P'™+©: ÛÞ8™¬ÅÉÈ[Líó²íÒÕ²Þ8ñ¬ êT±Ct!›…-(dµ2TÒ¨ iu›²†ªÍºššKéê®>!«) ¦ ¹,„`\ä¯B>Ö…ÜÖ„ÜÆÛ¼²žªª.äž&ä¾&¤4U}Ð'dU !?Ö…”‰•ž†°QÉÒ…”k«]NÕ¹âY®ŠŠ§º>! hŸ Ú'äzººö ÙHÕE"t²u!»„=(¤ZùDùHàiBQõˆ²™ª­^!"'µÑœðÖÌp( ÁáØm÷ŠÂÛ¯AÝûº} î3 ÈœÖëüC}Fâ´?ðS†û‰Ç.q[[š-œmǸòoþ^Å‹„4P‘ùRülY´Úð†©ûxT2Øãš“H˜A¼Í”õ´¡=D¼žSZòwÐÌÂ^ês†¶ü—e8 ¯ï‹8WÑñ«¨}Õ[a98~y¼+ÌÛpÍߘxK<ˆàÞŸòª·D†K1S3§§¢ˆ õ¶ax`KþZôr×Áb›f¸äE”Š7Ú^Q«ß û¥±);è‘A}$Lîååå¬>6ˆ›¹¸¶Wg¯ ±àܧ^¾*ô™axP¯Ð`]èKoX"N „Å£øëò÷Õ¼³cJÿ k;)¡·4û ÷TáýåTàE—/ ¼µ¼¯Â ùò*³ßßË-SìËßõ”áe怋þÊíÙ€ýB÷€JcîFÅ^äölÄ~±;q§1·JÁ;º§ û%nóqcî&Å^êölÂþhwÒ#cnµbŸñ¦§ûcܧøänVìg~èÙŒý±îä5>¹5Š}œÛSƒýñneŸOîÅ>ÁíÙ‚ý‰nËŸÜZÅ>Éí©ÅþdwÊHßÜ:´?ÍS‡ý)nk…on½b/s{ê±?ÕmkòÍݪا¹=[±?Ým?í›Û€òÝžìÏt;º}sñ–éö4b¶Û9Û”Û¤ØËÝž&ìÏq§n1ånSìsÝžmØŸçN;fÊÝ®Øç»=Û±¿À~ϔ۬Ø+Üžfì/tšè—»×gg‡øˆ_J’;îmÆË±ŸØ;1d©_Ôdƒh¶dÓ¥~bp…_Kk[ûL]釓<–DÑ_“Ô¿œwò*"óf¤æÍLýð†»öWbׯá®EšèœYÞ™?þï#nÚwVìÙ_‹km\ß– ýrËþ|+w§òcòéN¡âo˜Ä¤oÞ«ÍV?ìý1í‡]P— z>¤þ(o§Òš?;UÂøß‰;/:/’‚ïŸQ‡ßk7Tì[sÊûn¨>±ž}T „3þ œ‘ú¿Ÿb¹Á™»[±Wº=»q»ÿ?ÊÞ>ªãÊîº[ßnIX’!1¶1²-#›(iì8Éd’Œ“™AHÆš™÷bµ¿ù䑚¸G/ÿæÍdì—™É{‹ûŽØAˆ±ïû"v0Ð ’Ø÷}S±0è;ÿS÷ömáäûÞ—ÝêªSçœ:µª:uJûþG» gWì‚tþ%ئù#ŠúW—Ø&ì÷Lrˆ:UìÕb¿õ ÃÀª­·ÀæP.÷òãÒV-/¬hÏ0}ÚØ7妭™û ˆôå[›ý¯áûüQéݾxÑä,9úy@lu¦Ð÷¾üÛЪbßP˜ZÒÿUÖ¿ctëSòï)\zXëyXó•Oè*KUåé/xOA™2Vˆ¥jޤU …Úgg¤Åzw†ˆ•š]zš¢âˆ&Çñ¶Æx”} Ð¦uYp‘PGúy•{y•9½LZÌö"AâÛb }¶”hË„\"J§†âESC¢ªI.ƒµ•?=¢õéeg÷÷ù;â…ͽ­¯00Ö ¹B$Ë:V?­õiм¬aCX®Ù ­ Qg5P–ëIJ°¹À÷07”˜…Ü(JŸCtë·œ“@Kn‹æ`'tk9Žäfà9¯õ ¾Þ±ý9ÿ£µÕ¶m¿Ü&`ê2Hè~ÓZÁ%Þ“^b®Ã=‹}ªœû…Ü'(±IîG MUB‹Ïô`¦J¸­D?(äA¯h1@âaZ(Þž—Üİ$•EÂ~ñŽeæ¬'¶,Û”Í"‘óÅ¥ã=; e ‰xù´‡•åpË$ÄÚb9¯Uf+,Ù<ÂÃrÀg ø°Œôn#á.%\BÂ(//²?-ѯ a4'¼†„H¥3ÝL‡îÍY èG@gèuà˵>UgðBÿ æ[¢·ˆ„&ðÙ^¢á󠽎ώcÛÁ˜{t¹Rç¹°9Y¥w—kôX—Š š\§Ç"FÅMnÒ“|Ö±EÅ“Å-š&·Øv¦\¸³„5q›‹í ø]zé|¤žó…¨œ3‚=zé¿÷üw_å¿SsÞ«G,¹Oóêós=Nƒ´_/Í)ˉֆzæˆÊœò³šØ‹sÉ•†'A­J¥¬6< "eM*e­áµ*¤¬K¥¬7<Ù"eC*e£áÉ) *ea åv÷Wú‰ÔŽTäá·cÑ/Uän¿|Üè ltAØ8°:Ä™Šç‡|²Éi 'T:dvÊM×ÒÒÏ9sÁè®ÏÇÄYñ¨CöXô׆jMÒfk 9ä›È¡¤}Ò¾Fuq›ðÞðªþæ©z Ç5y ß3¼eÅMàŽÓî:MàžÓî£j'¡j­ÅÜáó†aïw| ù„[zO©b_*m8{ñ½ÍîØš*=¡õÓéh¤%`ÞÙo¦Ú¾W¢˜Sɉ?R©I³»öêw~ˆ†-Eµ6L5ñi JùR=l:GZ‡MÆQ&/Êc&7„g„qÜLÄ£õ9Ç ŸhÈIO §PkµŒ>ôç]ôçú˦¼ ôWþ(ú«fÂ-¯"rÍ‹P¤®{¤n€Ôt&õ1ë3.©ÛŠÔ}SÞ…dÐ×@òÁ­Þ/Üê}èVï#ìò‹¨ßǵ§ VÇ:ß+ Ö—7zb%¾¾–¬²â±è­|£_ö‡uÀ nóÿ °Á®á¬Oˆ©Ñ–n©¾+§Å¦Š7Úò:¸c=#±Ö3g©Ñi‚•bu"x˜É<üŽ'+­ãÀ~$^"æYr†ÃǬ?ÂÇk½/{q9›», ÖâEÌo².R¬ÆßtX]â1° Ì8õVºòlÖ›sYwµ »ZP’㛓¦Rωw†#ýŽuÖH¿íøX?éÔ•ºçsEûé©þ2ž#1y¥ENàÈåm"'rd¼-ä$ŽÜ×çd?ñ4ÏÓi·Kr-´ú`=ŸÛÂK¼ñ;G={ür¸ì£ËÏ‘¹ž3?˜Fdn¦Ì•z´:ñ/í ÒΩ´óH[è¥Ý@Z‹J»ˆ´E^ÚC¤=Vi—‘¶ØK«²qfsÚU¤-ñÒF"m´J»´¥\¥‰ØÎ,4Í–Ó$^|W²Î¦ò,# ¦5“‡ã96·ª^l<ç›c³2)óø2?Ç– E±¤¶´ˆ‚½õXC-Q±÷(v©M­°·.WÙŽhr±[k»CYÜ‹²çb“Þv‘;+M·x¹¿£_ öW‡¿í¶#œÜÔ`oì¶åÛ›åP¹×Ž˜ wMCÛ—ö“úÂçÀ1ßû+ó!w†CJR°ð#mÚMÖrƒ»®Ö1Hü 8¥pŸpÚ¦)™pYV°îÁ#Ç%d¹¢à Ö\ã`ªå³ÖtÝS Ÿãn¸qªÝsÜM7.îÁµ¸qû<|<¬ô¹Ç¶3z=¶å=®ÆB€­Â¾ñûX7¾^ZïlòdtªhæöQ%J¤ì¢–ˆpf§N‡9å¶(]˜ž’E)‘°É*]ä iשâ÷ö—.N~Ž€ŸrÊÿ"&V ×ÄhpmŒ%òk¥KByáìŠ*÷‘Ö§ ¶¤ âB¾Q:LÏ çTT+¨­)¨í)¨$6‡TnÅ µC`›¿ÛWwÉ ñéG{ ‹Š=-bN±V)>Ú[P8·¸b/¶Év Ío˜ëÅ­C¤ ñÎGµŽ=ž—°ÇsTÚÙ"f¼"&ó;m*_±Ó§ 9YÀš»INU·ëšå4¾m—ý+¶ln,1¦ 9]Ä#Fti¨¬Z¯f´²NDL÷pÄŒÐ?Ë ¡æL!gRbÑ@ÝÚr¶ˆXÑÚÊ^Š6y•í>ñÓ§êûcÿ„bŸh-âp /ÅRlA}Lÿÿ¨Ô>¡µ½ú¡¥Î÷>1äj‡ó›ß~bÊ5ô#ß÷‰•½Š+7¨DôÏ¢"ÓŒk'ä‘vî“»EöhIÉ4óR¹W|¬ýF”- -ïšû5œïãˆèé –-Ç]}MîOyƒècêé"eÂû‰_T„ý…GEá±c¶?€ý‰N¥•qQú¨EÙ¼!˧†Œ]‡U+ÊðkËÇâŸXÑ?³C7’éQ湇ølŠ˜Éë{E®´W†àBzUŽªW‡à$yMÈgvð­ ù¬¾u!Ÿ¿o}Èg ßna†YÍê4[М(ñ&i×½OKœq²D»,äY[*$xA4hòœˆ6þ8A‹ -ñübä2·­Ñ¿mÎöèšHn¥µ=C%‹¾ü––|þ2AÝÉÄ>V&"‘Äéã†VÄ…´þUÔ@ö‹°bðÓ[£D_ZÖ»F]tZÅ>ðULÑe_Þ(@ŠÇD]t­»–ë)ë®ÁZ¬x¶î“C°‡¶—ÇÒïßBì[-¦|Su6ý\ÂÁ¼­6Iç-†å,{¹º‡\É7ìöñ˜ö>²ïäͺ¯øvÓªSCßj”{ ~ŒÎjÎ>-Ž0Ú6Žâ÷+¬¸5uI“8IÆ´8¡ýÜQ)C2XEGA9Øï(”p×5ºKz(¶GéòŠtÀË<»e³u¦Ì9ó7°ÀµŠY ËEz¬x>Éc1¬cÆèØH+žG¿—b#æ!Ãý-¾%Sdq“FY£Ž]¦xE.#sÂËÜ+Þ´úœ€ÌI/a>%bµ»ŠÛÝ26ibÌË Þƒ˜¤ÇyËm%­]Wl/QˆágÙOÅZC®5PçèJ§Kä:#îô£&¹Þ n”P‡›iÕ=W‡¡Œ*uLh&éØ=(žC¿wªô»°Œnôøü|ÂØc*ølòDYiº·9MXv0rZ?Ç+¦êX93Ò*(ùͲ:¬Xg’2P d‡ÙX.2Z‡.àtUà…´ \ì _䵺\ê _äG<äŽq,ZäG,‡ŠpÒE~Ò„9¼b†ã}Çꜯb›!ZZ9bÜù޼`*[¨:]^c¬þ¿tÝ™ç}IU[ú=ñØ”O[ùp]-jŽs×ú:ÏKPÎ'[±Xt†^1S—S ¡Ÿ`¤+Ëé3i½0B©1³8ˆâÇ¢Ët굚œ,'½,õȲÐ˲¨m–”e1²œ¢YÕ´æs‹ÚÌ ­‘¸.ñm¥éqå·DƒÅóâv‹çÅÌÄ£#ǔۭ„šwX<3~ˆ1l—•à)62»iÓyyîaüj•®¶é/OwrŸUÚ9^ÔYD¿Ìâeù~NÝÔy´Ti›ºÃRÓa-…¼v9Æó™tžÏ)žÏ+ž/*ž/Yò|Šç‹.Ï—Òx¾’ÆóUçëVéZ›þ*žo¤qÅz§¶8<ËgR/¥ñ|<ŸáF̵ÝÛ]¶ôö˾~ܵ¢vx–·€‡r™æøQ¦—šhŽ¿Eœ-sü²ž`Ûc˜]à-ÔùfÌ"ZöÕëâ³®9_ O*`–RB¢h‘nji«ýr¿ô%.JÏ—!—ký‰š®¹*×('×zêÊòF?î§žs7ʈ­`«ªÉ/æ— ?œÏ\5„›Ð‡8¿I¢=xé5I¯I‡z Ç>~·+‘Gý܉å1? Dq5|} g<Êx 8'ãÙ´Œü˜yÎ ÚÈoyŠpÄ ‹9CÙÅ)™âC²‘~yÛä²áÐ…ý®_Þ…`ë‚ïÝ÷Ç"FÑRrˆ=Ï#—&ùÄŸÀ•Ùê ­ ¡]€á²Õ´'ÙN]O¢¥ÙòîbŠ9P£EÞ[é—´ð‹-!Ôše­Í—¨i˜Hòt7ÆöwQ˜4¨üO¶7è/´åb5žûw|Yögb©Më:¯2`:˸*Lj©I.·K÷$ŠöàÇj[ÝLlßQ­ù:ÑŸ.…¢ð"Í „q¦Þ³“ÑCn²!ÈKÂô›Ö2V=ñÚó¥&>=¬R—*áqBó²!MÑdËöº6Øî"î ÚÜìæ©f×$Û‰xù‘Nò$š¢+¸uàÿR‰všPôÿsýŒÍî..Øìîâ¢Mkµ_úpgú²ízº¸b³§‹7Ym²ãVI7…`MuÝŽ|0rӯŝò¥!‚vµÓ;W“ì@Å]¦åŒ£ 8Kº¡9<+^@3Óœ__ñ`ƺ0cr\@iaãs•×|¯*½.Rº9}aö<-̆èHÀ2éO*Ì5ÉuáË´ª¿~ër Gàöküù àëôïªÐŽôÊÙ¢Wg åôzµ ×k½^/蕟WÙ©×oöêB”öf‹¸RâûO^^Ðß«%Ú¢}ë ¥Ñ;ì¨äÄ;f_ú\xÇê'p¥Ïߟ>×Jìô¹^DŸ%Ááô¹Y’1‚>-%™#é#K²FÓçVI»1ô¹]ò.œÜ)É®¼’œqô¹W’;ž>÷KžŸ@Ÿ%í'Ñç‹’j ÷5µ†ûú4#Àjéó°¤ãP½E<*yq}—¼4œ>_–¼LzñÐ '*«õ*v¢nÖq«µ…v韱ãïb¡-ˆ²½³¶ªW@hš½‚r°ˆ Eù–¢B[Cr¨ 5„äp‘¬ê•!Gà“)Gâ“%G‹.½ÚÉ1¢ ×sr,ýÍ–5ô7GŽ£¿¹r<ý}^N ¿íyYÉ-öër–¡/ð½_9K1y¦yŽñã[Jáë4GЊ2bc¤¬ ˹Êf¿×+rÖL‘WÔX9C4¼y!òu¾÷»P$ 1¢Ù/&ÎraíÀbÐJ²±Õ³Œ ^S+be:ÄlÓ(›MHþ\ô¿²VȵUÍ­ªðÁËrˆtŽn >)¹Cçèö­h [Kh•I¿v„~‰ËÉx1·E$–ÛEÄ_Óç‚oErkrh„¼o¸óNªÚ~á¼ô© ¿z“>ýïQCÕá×¥;…rIAËÜZט3Oî‘<¢VKµ±Á/×RìAð ÅfÑú4ŽY´knëÝ"Ò7\(êyÚ/"›D—HÆÍƒ”‹ÇM^Áü§Ð¢tXˆóÀ.˜3%U¦Cœi@˜«ñè±T&‹Í!ºPc8þ i,4¤X8©°"l™`áôWX8ë°Ðà±p^eºÀ™†åEÊt² W‰…yCP¾­it·‚îg½^¥åhäUR7Ú)ËgNaÃçÏz½F ÔÈ«5êXþ™´×i¡É¡"q%>G1ùòŽ[LŽ{Ui÷ƒ÷‰Á ”êA›Rý‚x("¯±µ×câ4c·|""ùnyý³\8hUx*5à¦eq<Úèâ‘ý´Hë:K©PÕ$D˜rŠ>èÆU d«²µ õïþ ¤ÁihÒÊ~A÷aÆÏ¤ÉAÚ¯~#hyM³U²è`Ž•VÙ‘7òž‡Yð08Yyƒ¹NAÒÛÆëÑZ‹î2E“£µÈ×¢;CŸöê"Çh‘.4Uf.Vèr,Eäkµ·O€Çi\úñZ—dá°œ@…?¬6þ˜`j]L9EÃ.§jœ#Ì4G˜첢߻l˜;ÈG "Ø}Ø‚ùnGŠ­£\4~¼ ,¢û¦œ¥E‘Žj4jÿ:6¶/sÁËаœG¼$R1Ÿ™X EÞ,ÜRRß5‡wÎÞ,®Ï…7£EúÃbmì «2²çé}‰VЫO¾ËP AªÁHÇZª¹ìÇŸ€qxØÃ8ÂÁ¸Š0fËÕ ãšÆu ãVƸ5”=â6㦀‡q$aü¿)a“†³ùYŒßÄýUô§¶¥ªAn×Òjb a"ÚÀD©é¼ cXФ ó€ÂxÐf¬0ãŒçiÓ0٨Ѻ¥IÃ$3Msú®O[å: ºOÎb£ŽÝfŽoÉ£Z$ÛKÙš–rLãÞë¤4¨” RŽkÔ.ºÔ×pO*öN9>íøLzÏ2£—5&O­ÍîŠjvÅ4±Q˺¦ÒÜÆå49y]ÃŒç ýü¦¢Ø¢aL%‰È6¹â–{bÊ¡w· ½û*íYz¾Bï¡¢÷ˆÇ¢÷¸ ½»éôžj,*‡^kz½uUÕÏÐë£?K¯ŸÎôªt ØD¯¿žN¯5Þ íïI¡Æ8>X‡Œ‡êÔ&!I¾ðñ¢¦~oU¿_’ÃÕïü.Úò}Úëe9R¼˜ÁK/ Š…¹ù¸£8£;³×X=mö’5Ln‚žßùÓ^ä$ 0êS(¬z5‘ÈÉHx õ¼Ç7UÏ…òe—à @´ö¿€{=òr¾1“J zþËz‡Â3‘ò+J©ïоûVäå7Fè3q{³H(sôüN`i¾Îm;À/E:¹Å{É-ÞU¼…º3a,ÒÓ'ŒÅ\¼e:÷‚\Epøû.’—ó} É …d¥îL¯«ô´éU®f$ët¾ßpC˜AÓ C!ߢó¥®kÕp(Õø¶ò+U¢á3:¬ï Ï˜°±“>cÃ&ìô=oíÑ¡éú÷êr‡žOUgÈü5å.þZrÎûpC1½ìì>5ªÛŸëÔ ?×;b{Ãw&v´¡8ÀC1¬êbÄöH¢;G˜ØÒ†×¯€Jè“ ÌlÖwå ™2ìÆ*bü”-ÿlXÍv¨ öÛLò5ªÐöh)‡ ¿”„-nM†„#.˜¥®!È÷ÓŽ"‡ÏËÑ&3ˆÇõ¼ò´N5tF§ªñmÜpŒäõ®ÏwSÂò¿… ¹K‚ï}»å_èMÑIi$ ‘ôÅtì£?Än Önþ*®ÃA¯ªÔâ˜ÔV "ßX؆Å0úŒ k“è3>¬Ï5äCmÃÆmΦ”#8Hx›oëuž—FqžÆ‰\Ì5F<Á-jœ‘Àv6^Æ¥EñYþ8KN¦L[â)$¶ñTÜ=Rˆ§q+ëéF’Ï0âjça¦‘tÏ"ÄI ~ˆçQ¦Ý:§Ìç Êšý5ÜC£ŸûÔIÀ"E.2h=Þ¶¨~°~ª:+û†e„=býƒ—~¥áøRæÍec}¥UFœÂ¬âç#3FêE{p~Õˆíl4K!¨³Q§°}†¸X‰]Þ[ zÚ!r‰=B5åûW‡4ß%C^1âyÏ¢œŽ‰kìõI»nÈkʱQ“¼nP†ì"¬ºn4FÇ“ik®®jÍ¥KCJ£LmOѢ떡]†¼öˆ¡]×=™è°‚Z<;(Z¥Ã-‘³ÍüÈpnÜ>vM Ë' QÅJfi>ßm¯œã°›=ÁDË¡rÞšfùßCÂ4w7{š)§sºÚ*¯3»Ë™fé|·÷gcŸ{.皥ótÞØŸ‡½é»Fh6щÀ=aè–ÿwH8az[Q'L8Ä!Eã4Ñ8«îk~Ã98oÊó¦S¢IayÁôŽ.šÞñÕg×ÀÙz]ÞHqvœÝ÷8Š-îáV,ºœ=ý§Hk9EkÁN'^±I—,WÂ-G“,ð3¥¤prXN¶”„7:›ï_xdVÌ ]ˆÈ<ô$¼É%³É’[8]•~«Õ]n³Ürì[t¹Ër˱yî‚À} ]‘<ö$ü¥åIøKK>eE£•hôö·‘p_ì&;ž–ýüž„«üž„ø]ÎÁdf›.‡ø]ΆÂxæK³Å0tYêEw€³',á_ aµ»…½Ú/×ÍN]®÷»—¬7øÛ\²Þèruá¹Éï\²Þ¡ËÍ öÔ£vÔŽú1¤µVOЧ]j§ýò,§+!œów—RŹ>vSJç*Tj)50íocd"½µ” §¦íªNµe-ƒ(Óíîr†ÝFгl9ËvŠ45,gÛž çØž çÛ.g lâlŸ.Ù.g‹aÉÑÇã, Ήì~pÖWK5åcîþñ1v,ñŠ:ŒXœ¦|Úvšò—Ÿïȳ¶jÊûuydúyd*D¦O L•Gf@À!3 ˆLœšEÀ%34àpÈL ËáE&¦«}Ìþ™… ³˜È$A¦Ú#³Ò%³2 WƒÌ!]®M‘Yç’Yï’¹óŽÜàIêr#È ðÈ™D¦ dzdιdÎäiÖ奙Ë.™+.™Ú°¼êiÒå5ä‘„ez0=2ƒ=2#‚™A9*HdŽêrLÐ%36è© :d¾#Ç™#ºÄeÌJYMdŽƒÌPÌF—ÌÆ Ü 2't¹5E¦Á%³Í%óå;r»Cæ8)† 3LÓˆÌÿ¶È$‚±÷±¹|(ïzÅj]6"¸I¯Ø¬Ë&wê»tyÁ¸^‘Ðå›õŠÃº<ŠàQ½â˜.!xH¯hÔåqOè'uyÁzÅA]žýáša8]í¶[šÛA>¹ÄÉ…öEPÞ¥2ý”O\šäÁxîW1šåàãQ±+.K¿•äõŽ¢0^¯aïQ0ÑC~üÕoàŤè@Ä9BÓ©¯oçù¿/_wœöUeðöuu†¬Ê(h”Õ¿doM3bÑ ÞÁÓ:Ò?°á98#xDD÷†°û3$£ éo½Ýƒnp G·azKHŽôX‚þ܃Þë@ôç:"Ý’ã=)#K¢£ô‰ý”Ïüp™ˆªS˜ùJCýÐs5DÇ¿p{xƒzi8¥á¢N-*ö½öQ¬ pqqEŒ¯¸ŠÂ´®Kеï~/(<ùóŠ8 §Fki ëÂòÏ)nŒæÞ0¤ˆJ÷9Vc:UœÕ‚c5מ«Nsí¹i2¯ôóP^øk'CÍÐÜ‹ˆ4÷"âzM–•1òÂ_¯hÇ@5Ï–u“FÈ|ïÖŒ0ÌïPƒßö]‡õãÛŸºw´ë¶”6ÔõÛ(« yÇŽ%*¦hò®KV<Òä= ‡›5Ïðu‹Ã×rà\pp®Ð@,›q¹%àï 0Rö1 ¿-àÿ ôâwPü΀c8ȋ߅ñd«à ¦”pOy´›‡òP ô÷²1Pöût;éßë•¿o’M”åws eù}Á¹°•>HÙÿ¥MÙ˜¥S.¥SŠÒ™€<JgA)ñ,¥s¥ó¥ ú‹@¿MS÷ ý5ý5…þ©Æ„žpÇÞìù{œ-^n‰ÜÛ5Xñ}ý«V|#_¿€•§¿ ìÿ@ãTyY¢€X#% bé+OÈ_Qõ¦ÿŸRÓ¡Ïxîà 9à 6cþwù?Q™ÿ^v /Z­áÈü?â¼ýÏX¼ ¸ÆÐäÿBÒß ±$÷eŠÿßêg¾/º?$ÿPöWÑÅTcâ!xR'wiÊ”„HÂC\3EGbù¸[ÃÿëHØézUÚ)änxUiȽ"V<ÍðÉ}@²Gó·3­É€û+ÏÞAZŸ³'6ìí¯µˆYaÏì°†Ïñ¿Òñ™6†ÑgnØ®ñ&À ·6ý#á<\·Çhr[Wõ2åp-ß÷o´È¡%PäDº ¿éxìNµåìR²ËÛ;Þ Ôðtp‚&k´D$@B[ €ÊÈþ1Cm/c’&'iÉH'gÊ)|¿íÓ®#‰z×^Y19U‹G‚‘L9M£¥ÞÃ(ß²³KCF$#bwXCK¡1ZC ˆø;TÑ„€$ºW32Lëª)ÍÓœ{qó40&ðÙþž6OIŸyac}æ‡ÍÅô¹¢YKèSöo Ï‚°½ƒ> ü¿ã o±–Ä)ß-Y¸(Œ•¤²T‹øiE×™­Ù’ù¾ˆŸ=žø * ßqý|´ýKÈZRnB¹&zå«$ÂÍZÄÆ/·P ‡Ü©% ‡±ñ^xý¯j{ä.*œR”wS§S‘o½Ðpõ8(’´| «ê¸Vú\\&4ŠJÝÊF-Ì!T6£y¸Mž£œçØ3yÎ Æœ£"+^ηÉv‘³]z&¶bsp솆kðKÂò¦–¬-\†¿¶DÚ…ø;Zé°ö‘à_úІµ,Š/8ÆÆïDùèöò¡÷;Y>¢½üR‹Eà¢z"õç–Ï·OÓ-Óúª¼î 0}t¾ŸÜ>ËÂZ•Ž^ Ñe?==„ïEoSÓ‹˜?ñÙ&æð*½ ¹pÒwy³ô|pëÕz—f9D%’EÔíùÐw¨žä½…a F"h™r8¶v>×LÛ´úq©»—"t´6Ï m4}–‡õ):Ú¥Q§Ã­9“¹³æèr´ÎŽj÷‡à¨v¬^6¬½¬Ñ“)×ÊIǵ2vhÆéIpª0Ñ® ÁL¯*¿ù¦œªc4ÚûVáàos×¢ÁMŒ‚wÔ v£“Í›¦1úUŽ£ Y§³Ë\"Ž{å³tv“ V¨åÎÑcr®1“KÎÓE£ ƒâýp.eä(ïb±dñ8CÈUzÄÃJž) !Œ­,ŒA%¾­ºÜ¦ÇÊnv”Ûõx¬h‘áËëRT×Õùáš+,믹 OXê¾-Îp_Æ¦ÛØ—£´¢+Â×§I^Ôˆ•ЈÉDùÁ¼¬—ÅB¼KuE/fðÐyXB™´F º¥çUþ^¹Ï½¥óâìŽ^¸* oãñP--Èîée‰Ï«E2Eîϱ„›ÖèòN3áúWç\R3Q˜qà .µ&˜l¿:6õ{rY™f8Ù31š•,ëÏ™¡á7£,b¿¦e‡Bl6 1üŠÈ8£¬1TÖ*k'5ÜR%qB`Ù§¹ÝÔaêÝË$y¯ uØz·ÿÄħڀQs^åCñIßà'AÏøûc‘ü„€#Æ'ê~ÿA’Íʰ8È U;ÈÀuRÎPY³Ãð¢cšnÙLqò°^Z Ko³gµ!˜– !?Oþ07éà l´åuφø€Øp_ÆEÖ¦`°-ûy R#!«Ò~ „lØÝÏÐÑ%‡Q,ü-ûào™ -‘åÇ1ЂÆä Àý>„Má œhx8•0Oaö¾`<ä ù4=#£)äÓs23›C>#73³1ä3Ûû!ŸUmø‡|þ ïHÈg}É/ðPø…|Á „0­ \Usy÷7ó‰Âs>ðÓÆ0—êa¿&ðYÖê Þ*E“§ÙÏh– Œ$ßz^ht—‹d´¿‹6<Ì-3ä2މö×yÐZŽýÔߨJc%ïTš« ¹Ryi‚QÓ*ƒš~ìÌáÖZS¥L€ñQ áA u©ßÇBð ¶ÞˆEü»xŠ«ËŽfç­Šß<ÔEƒ ÿzè-¹ƒX«2Š5šÌŒÛ…ï1”ž³­9©ÁTs1wÖC|Ѷ>ì;dð(ŠÏŽ÷´fæN?lÈfÈÐö´Î;LÁí1Ü%ZÈÆþÎÁ/~þÒ>NÁ÷p©‡"‡œ~Æp~ 5äyŽ'#F-À/¤PE8â²qî~%->Àk`ü«Ñ¯oåQ~Ç{¾{Ì©¸gÀÚ9ž(ÀŒOcc£¦‘–ò”ËØßT9áÀæLýM΄Ï:Räè³>¬¢ÏRä賑9S2Á·ì™6#F&­!f^9ÌÌ£Ù”ô9ŠM(RêHÃ*3—Ã3‹Ø¶Æ®Cý5¦e&y¼cÍx¢U]ƒVˆX}z³¿ OÁHàp —vVÄFùýìF{¢±Ë^­f’“LöÝQc¾ äìimµƒv€‡¾é ïÍ4Y[kâ¥Aˆa±éˆl±*ýb“/ «&¸å¬2cñ¢:C½÷Ñ(W+N]ÃᚺG\„ ì×=·p‡5˜=çñˆ‰Ýê8_ÈÍä« î³ ¶×`úKww¯g…}'‰É›~qÊ”'Mu*sŠ„Õ *}z0DŒä+4œ1s—Sæ;†žs‘bØ:lÃaJ®™Âi27Á†417Þ2cEµ†/m~$Ðcšfá¦.~ÉŒ4sá¾4¡í‹§ÌÖjʧ¦2mEå®ûô2Ñrx&áê.½-Ç\´Õ|Ç4r.W¦mȾlkZ–iUñ¼;Œ7”qûIÃKÚ)©i8yį êÊ7Ìj›Ãb˜2¢£Œ¨ÇZ|ov¤j•£,jYcø·²¦«¬©s…qŒqš¹9ÁBû¶¦Xhíþé¼O TPfLlÊS‘"¦Û¦'Ҁîq&YÙ[qpE¿>á—S­ˆŸ§YÙ3Ñ-f^Πxt„TÁžÆ;f[r^qÖ¬gƒ¿Œˆ¿O¯LÕø3#¯°ÙÞ\Ê ¢ñ¸ñÏ·"AÕ®mYoqãŸm½“™Á?ÓÎàÆ¿$ ÔwÜç>¨ i¿‚uÿ•tÿ±Žø¥§­rsÚ< þ jcŸÄw(‰ãCã!>õa}·%÷Xð½U´€×´€´hP€öYxJî§ßD#!>©~vWJ˜º˜*Ìø,þ[í(Ð2ã$䤙ç,y th£™ò4Éëù êùœ¯Ž!lÇáA(+ÉZçE«là‹0gZßUCüeª0âå”fÒĸy¹çòrOñrO•òž*åCfÂxJŸ-a³ÒÏ+Ú>~>Öîë—ÚJà±å ‹_‚±§^ù©GÈJ?ø$-˜UÝ>~Ǭ ‡#|þ Žðªüò˜wùŠÖtúûúãè£4ç ðsaNkõÕ_¡,cýNYÆú¹,øPY𡲌÷sY¦øå¶'úŠ›ä/;ê!§øÛ0>Í_ú1þ<ab½@lKl"¶@[ ˆ-VÄVøå’¶Ä–‚Zà2*o¹¢-­UþÒD«hõhmsimS´¶)ZÛ­ŠÖ>¿ÜÕ–Ön—Ö¦µ¯-­ýþÒ׉Öë uŽiýš§K먢uTÑ:ªhP´Îúq Ö)¿S÷§ý=äÙ¶¤Î»u_t"ä+ìÿv=n0É2^&¸$o)’·É[Šä]Eò¡_ÞkKò¾KòŸšÛö$û#fÙsÕ0÷×puãç ÔÛvõ¶™PoÖ´Þ¤ïڱⅤõ·“yÏ£ëTÛ±d¼h­D_å1e€ 3ð&ÿÆÛì¡wf…µZ“…>ÝÆ½ò能–Œ²»ã†y—ІkóÌ£,‚XC‰löT™Ó('ÙñÂma,þY÷œL©SìÒç)§Ú©€&Yk'¢'y;B§B¬†Î°cr¦ íªx´¡ËÙØc¥…ßì±^â‰ûgÜŠùÊ@F#É¡“o‘-—Ùe§C…;Â$E¾—´ÜûMPüúäJDEuþ€OöWÛ˜[/kºÍ. åFF9¬}O›ußöm´1¿ˆÍ¶Ü s~š#ÏðÙÙ#_0O© ¶Üj—ž %¢c¨"G¶/>ÒdßHDæôéå‡ÉP€¦‹&ÖwüVÎ-öý¶E˜1µ.r¦Ö](ål\£vÿ¢ô\ºUþ‹:U æàq»ô¼³MþB§Š~W(½Ý‘ «9%ÄWS{ã×S;è»ÂòµÒ%F^ø¥ŠijýA™& jtw}wXv.ýœ ^®x‡ÆééîïÓ]ù×u‹_Ýæ·Iá)P«—±7ì«-b_Xðã åuùó°6XÈÁ†¿VOŒ†õ¡w l ‡ü.Ô,†³Ë¸ì70ÊŽxòéb(‘¤?í¡ŸDCŽQ&Ã^z‚}E‡8 ·ãi½Ê&DpË•r°J3XÀX0C fŠ@c˜À¬¯ÐÀú á¾È ûf°å¿˜-äl¾z«±>²Z×ê…œKX iôR¨ =Æây"û$lVøV·JºÌ­f«YÁ.f¡p“À‘\äü¼Â?ë»æüwØ-n4¶0®W¦ÛrIx'å¤,…ivz6¶“v—y‰W¼Dvȴ£õ다¯ô(ðïzvúC§ÎxÒÒ»GÈ:–ÞD;çÿáæmêý_÷æf0D‹É¡ZÙ“W¢'¾¿‰oðƒ@ô‚láóu©ˆr´†kÄq+e— ܤ¤˜æj Ü5àÆïg>yÛÞw y-t’®ö̉Èì™ß±è(“uuM–¸{æ„|ˆÌ'2OÑq§¥=`â¸í›ÔÊ6æÇŠú|ËTóe$^ÕbÑcÀH¡~Ä¢‡Œ¢Ý…¬2â…sÿK}ùžŽ²¿‘ƒ‡PŽ¡F錗zÎx‰s ÃÎ1ã%!‡SŽ»ÝêËkr„‘} 4ÆRŽ£ôžo0ü8À…ýß-Üã´ò†Žr‚‘½°S vš[«`çÎé,§;°uFv5`çÐßœ«¯ü¢Ë/EùöŽrž‘Ý 0‹Ò`+˜?v`–ÙïfeÌ*Óûo˜ÕFöK€Ù³QÁôua6Ù0Èmƒß1Jßnd_òù²Ïñˆñ& lÕÎ+‰³|¾ÂšïËJ#á<’8†"îu“-»/EÜ…¼„óDâ¿RĤwåh'ÂÈ.§ˆGÝäd'ÂÄó—…«¿'g9Vö{ˆø¾\àDø³¿E‰°\îDØÙ("–뜈@ê‘Å Ÿmí¥PkkðÜ“Vú¯ÃSü×ýiëoŸ¶N{Úºíi+-c2Z[ BîÆÉl¯=‡¹ÝIxjC{œã5æóîs ç yÖn y ™çrŸ{0°ZÆHÜH=W–Ì‹ Û<Ìt@Î È+ 3ß#3ϵv›gÂ~¼âŠ!`É_¯+÷³™(ó5ƒ7ª¶q°œ‚=4àHs‡pŸ‹p)²@xÍ€p¡ÇÍY Äuðàf‘—ùª›ùª)¯#3 ì6k±®\ÓÌ)X}¡ð]ÇfSßYþ‡<Ï Æ%<\óØtÕ58»jÉëdñUš$oZqž9[œÈx9ÍUffK=n«a^5ÐB»L‡ÒÚ‹‡<×¼j8/¿Äh^~icàʱ~ãOÀKEg4øS’ºŠ<Ž~ä bB#˜äÖæd¾ï¬&‹æ‚I0ÁZî1‘²(»&Vx"ûŠEÙ}C®Cæ•\þÓÄ0§tßa¿T»í/Ý Ü˜¢ BÄË¿0žô—£=ÄÑ]¿Ú>¥5Hq+a½!<0hí;,Áv`r LņØ ½®Ñáßu3?޵â\ÆÝúmß8R‰Ãb2ߤզѧ)¬×ò…Z£Î¦U@œoPM¤•Ã=jöäÔudÇÝM­­,ÊëlVèŠYá»ó=s¦MjL)vE ’¤ýG¬ÜB8—´â¾obÓõ¾)çÙØl½jÔÕ|ÛõpSgCõKò[»‹l@§ër ßu^«CѺÝz›ßnÅÞŸÕ”õ6X[èÓÖ¶ÒgÁÛz}‡m6- T©6Q©î8ëßb“HšHçÏ«üv3)úÐP·Ù´|ÛA0MŸøï¢hSî¦õÌnŽ”{ìxQ?SûŒ€?Çeâ+¸wcS«Š÷¼djSÀ³c‰â/ !vÄÌý{µob[6»¦jR;ò–l„ý¼õ$›9!â‡Öv-ç]§#vBõâË¥Áu7×Své‘(Z"DÙ›ÑÆ7cÑ¡¦r&›ˆâ‡©ø3éñIŠ®âÏÙhrj ó…§++íÂÅL!¯p5¬ãžù;ÔÂ^~Ž|Å÷Ä–­6õ¢SFùMSVJµx‘& )•_ÉÞx¬¼Å”}pÊg”KSöEð¢Q~Ë”ýl1Êïš² Ai”ß3eoh(ÕÞ6ʘr,EÖs¿\ÆM{TÀá`T€¨Iî—“rL€ÊG9娀'³ÕxIãžt4ÞKšðÄO5œ>IƒÞäºt>êljÀíÀñ±D¦~;#ßät7QEMït#`Zktð^PmØÙm-À©õÏz*‘°À§1¬5r¹ôf.—q8ãÉ‚ŠÃ†\‚oÒK±DE3)*8ÜÛߣ¾€©«oˆâ"EqqP.J£´Ø£´ôJ•–’S”V€ÒV"dÂ~€Hm ¦î‚P ÁËß?òm Ê-Á8‹ ÁxqoË—]æÜ ÙÉôµ]A¹3軂¬½ëT€¾'(÷8|$S­Ï{ƒ4•À¶b€–2:ÓâíxkÐqêøg¬²¡l,ì;ÄÜ'Nå™ – ì ì,y¤Mí訓¶Ä;ØÛt¼Ðñç¼D„¥ï­ z°R0¡ŒÜ Æby]Üþ?Hm5aÈ/PgiQ¶sM”LeóH+à!«/ìdÇ?„@Ž…Å€ 9 ÃAíaP0yÏç²Å, uE‡¯–ÉHTf€ð0<&²ƒy}„Æã5‘É19%£í55ƒ8$Φ!ÃNÝÊ2­MrÌÊH{×]­Z/̲‚¯ö oVF‹8øœkøÐ8;/ƒÇÙùô96WáWØZŸ1û7dÀšÎÞ˜‘.°‰>§ÃÁ²>#žƒËç 3Ô á’ G°}–fðèó2šà²Œxé·‘ÆCOÏo uã)ÃcŽSU¯Ê@åñõj ^' +3¹&£4Y@%×2P´¡cQ²€d˧Û2øÙ¾„k9æC'àb?Ã}~}§âd 8Ù¡´4Ò2øœwOF’&;Íršoñ˽IÙÅõ’ÜJÜ:ÎHÀ.ÊÉŽÁ<;#õó ýäÑý`†s¶1 fÿd“P["AÀ^ÄÓj/bߪы•M°úR?ŠšV+±Œ† ޤ;l ít¥õgôã„'­“¼éJëKëGÉÓJZÛ}¿c/Δ‹2ÛÖÝâLbF.ÍL8ê÷²LV¿»Bº+2¬cGìö¸œ´*“Ö2¶R÷ru&?R¶,ÓѽÌÖgF¹]4ZVd&|›¾Ã<⟠¶'gÃÁúœ glË”[3“L¶² ™©fÀuDò‘Û2SmÁ‰Ë”Û3#Áä u«YîÈÄQ5ìý¾…Ÿ;éGÙkËkºæð…×]™ð²‘élg8^72øwM.üìɌѿˆ­Ø‘{=^T "÷y‘ÅCLÒ ÝÒçA ËDÿrÊWåÎámõ•ßÉLRχ³ÑçB¸]c¦L2´Sô,y(­èY\Ìv²1­è*î9Ù”ÉúJÑ›3#ÏEÚ¥Š~83Ò.­èG¸èÏ=SôvªèÎÆíÑLî˜ì¤á¸G6Å¢ê]aE{‚@Sñ)VÒ!‹[B?Xw*´XÂí‚+0óÏËtú[Ï'­ò<Î`öp¯yh¢×\ûÿÛk®©^sMõš;ª×ÜS½æ~¦”$ð˜Áçw·2»Ë;©Nt/Õ‰î«Nô·}¡:ÑCÕ‰«Nôe¦|üL'ú’;ÑÓT'jMëD½³Út¢¾Yé¨_w¢ÖôN4 ‹:ÑyAJA–Û‰†d1¾­n'–Åhxw¢YrX–׉†g}µÈúj'™•êDWÐ’¸éŒÊŠd¦5ÑYÿo½¦w·²bôÚ ¬y†ˆçEpo’åó{TÌÉYi½eŠ*àEŸÓ[¦eqo©ÍâÞ2=KNËjÓ[j³¾Ú[¦g}µ·ÔeE²¾RÆY‘çÒÊ83ëÿ»{ÌÊRÝãÇp’ð ô L²s!…gÒ¸'`óo>'r˜âJ!—¤pßíC¨ ,΂Y]·L{+ë܉,gÊIdñ”ƒÏ!Mç9¬'²dc& á˜ïI@†c]#OeÅË~½ÜaþtV¢pNçz~PólV<½Jß&Æ~‚¾M¾ éù.R¾Ã9*ßå¬x2½â|˜ð®gÅIÌ -Y8¡ä,z™Îƒ¦¼›Õ]|kŽX$uèòíÓ•¿nl­¶s Õ«ÛÉíRþºµƒ9ƒua-×ßNNôÀ¦´#—ûS¾’‚»=ì´S:. “3Ö·kÃbU;^émh'¶‹E›Ý’º[Î:]_ÜN.ndžYî:ÝXÚN.mÇ+o#µN7å2/ÊKSëôå^RÄÄ:}q;˜4¥¯ÓWµÃR‡Z^úν¨ÿ¬I®¥”ýÞâñ0ŽÔtJ}ÆÖCëÚ±²Ï{ ƒMMnhWZ.Ìu–¬›ÚÅ’ÅO !·x²jh—à¬ÛÛÅò°>ØÑŽV.û ¹ ²; »nòHxÿQz7ýˆwâÖsûÃ|PÿSnòb:®¿uë’:ç†Z-ðs ˆÅ†é.eû3pö9Ç“q]§Ÿd—p6ªv ¼²ûƒûDéþŒxÑþ Ü2ËGšr¿p÷ŸÊÞŠî|3­vç¤Çïòâ¦Çïðâc Ÿ`†_ùsÂi_焼 R2»°$dcv!ÙàoKï¥d³žÿ…_€F˜H…€é~aùß~V@-bY±øùG…ÕïxW穃º¬òF\lÔ-Íoݺ–9òû?ÊXzïr{¯×GFAE£!õÑuÃÁǘ «ÞýÀ¬ %ÐÇ„®IÂo? ƒp¾;D+kÄý¯fÒaýv?<;ŸWy6Ø$Ä埰¨Ñð}üýQ¦5Zéåöñ¢Ëí äx-‹N4Ë'šr‚“ÌòI¦œˆàx³|¼)'!8Á,Ÿ`ÊÉÖ˜å5¦œ‚à8³|œ)§"8Ö,kÊi8@> éZßÀL˜‚Üo#Ý&þ…;w‚ˆÇ˜ˆè®•ÇHõ߸–¯—î3óÂy¿V·7 ÷2åÃ5¹ ½ôjÅVS]¹LAOA]‡ÁÈçõZEƒ‚š‚šš‚ZoÈŽ¥û êõŠí¦Ä"{¥ÙœgßæÄ)¹¡kÌïÞºÆãøüý?ùh½Ÿä+¿)*Öûå_ý‘¥þ¦»x®ó7 -˜Q'nÝ Ëß¡Åä4"ø(ÄÿÂ5f³â¬)ÿ7Æ$³â´)+EYSA^{~‰ñÈ|}„ì#RÆS}E¼°%œº9ÕO|ÔTÛ)ŠS†SåM4‚†Ï”? û¯Ñ/B<êJ%< ±²Ìhõê˪WD Í¢3º€?X¸È94x4óÚÓ,3âæ§0SBLôlþ§$¹Ù†FE{à ]3Š…B.ƹ“©,Ýå2K&’Ä(ÉÌÆñÃŽ—ŸÍ—kE¬øªé“ëÁÅ‹íàbg:‰4.Î1s=.>w¹ø.ýcÑ„ÃÅAâ"žÆE\$Íçòa˜Â\ó<.0ÂÑЖÆE2‹óÌÅ|‹k.ׄ¼A¹’7‰ ™ÆÅmp‘T\Üw¸8Ÿ‹æâ!¸¨7L=˜ñ?€¶7¡F˜”ùðÛ“Œ û«UZÌ8dö€gý悼çq&6Á®M…³ÿUz‚9½O ŠYv7;ºÑú‰nk„ŒF6¾˜¢zM”í‰ò, nç岌âÁZ¬*ÏX­»§yå™@ŸyÈÌþl¨5Už ùr:cÑsf¾>‚ãÎøÞ ó}Ÿ–_Ï—uš*ñL j ½/N/ñ*}þ»%^N%n¢¯öJ¼æÿ¬ÄëÜ'Ü7q‰q‰?á-n‰·hx—“z¦*ñ6*ñŽ´ïB‰›Lv ¶¦=¦<è÷ŒWÜ3iŽ‘·<¹¸ w±×ÌŽa¦9¡¥5³æ´fv…›Ù¯™s™<§É ”«Ùaò"1y9É«`²Y5³›Nµ\É—-·ÀÅR‹{àâA:‡Ó¸¸Ê\,ó¸xârñD“­”ë°ÃE¥Þ7)S\ôÓ‰‹ÃŠ‹ºââj¾¨+.ÃÒh¹ÇEêñÑGÒ¸¸Æ\¬ð¸ïš×åDK9\L".¦¤q1 \Q\Ìp¸¸–˜‹Ùàb¥ÇE=¸X˜ÎÅѯp±Êãb¹ËÅr]®¢\G.VkÓ¸X.Ž*.6{\lq¸`««ÕûÀÅþt.Ž¥qq¹XÃ÷c€'].’:?œš1ÓÁÅFCÙ@»\ÀŠë$.+mbzßæ1Æ¥·Å 8S9iª1†èí€ÉÒI“Ÿ½¸`:Ï^löR<‚yH·x ·‘p—Î"a«á§„r$ô…ÑP•Y¶õu–…¬6ËÞŽ¶öÀ;oÓJˆ>xNáÀÃçäP´T>~ñÜô¢‡´Ü¦"Ïpä#Ùómس4: ÚYÉ©%Rløì«3eYvË®,lÌŽcg®/Ûn.Ïe×ëþZÔ³Ý/ûŠ\`–n7ãEÛMÝ¡¢Ù¦u!ƒ¥%Õ×ÐRo©™pÞ=â ª‡·$¹ÜŒ_!©­09òyÔÔ*'ÊïäãÂj*;„µ é½FpÐü,÷%Øqx ›(l¸ò*šr›É{q;MZø£Pr¶Ï)€a̬¶ ¡+d`S¬þïú´‚Þ SÂ+qžÍåô» Y¶{YNs–[aßiÊr;,HÄ3 ‡Ly޲T4Á•ί AMè%d¹â¾xÅ„ã2n*׳Ó0íl›„©”μʘÙ$ïQáPKþØQ/˜x)ÑU/šñÂ;J½Äáý#3åòŽ«\VÀc"˜oÛ¿­6‚¾ë)£•ÖGͬŒÞM)£Í²ŸÅŸ‚÷¢¿%û[±žLó3/31ð Dð¸‰n>Á&úÕ`›MÌXCú£ëŠ]&þ…ßèä¬.ö˜€æý[æ)çÙÕ¶µ ]dd¾|ëŠ!C„>oÇòƒ]‹¯›šü6–ïÐ>223‘ú•è'ùA¼`äEv§ÈŸqä~jƒ™ùˆü¥ÓjÉö—²D5Ù°j±b³ƒ:zFfgä´×¸¹~$ËcñóÁV‡a™ÿ pŸî~Ø÷I‹¨m/èoÍKÚ?Ë.{ªüN³ü—dñ—!Ÿü×ä7ˆâ'4Èü6™/¾9P? iòß’ù¾®„µ5dÈO“Å•Ý|ò3ì–@²Á¨²w*íÝíOIvÿ wéäŠ÷š‰,o<µ,½ŸZ–o–ö³ò ôÀH¿Ç^_ê’è“°ü™³ßð3üø9äÿ×Êý}‚{h࡟žHšê. j…¬eÇCŸ6Ê:û¤|_»Wá\VÀÊ ur–€µ£ëja­TKÐsÙ’þ‘¡ Ó åj,LÖŠ4Ãôdž²)§Ä"ݦœÖ=Ñ–²)oä0Û”¡àP\:ûÒP6å”û´Ëíi¼(¦lÊÏÁ>~¨%ÏClO e^I°_€Ò#B2 Hžʼ’*]å°RÃò%^1Ì’}¡o¶z™ÇCßœHšãd®4S™kÝ̵VñŠ–œÌ½ÍTæÕȼ–2Dæ>^æÍnæÍšÜŠÌ#-Òä)s_·v˜$27j<§ ²FçûŠFçjª ¤Q['› T˜]ò}}x¥@õЧ–õ3Q«“°w)×äIÊQåž•#íÓí³ÜÆõ1N)^™ë“g46?Cû‚_úPàg|z¾èùPhU$_ŠíÛ­¨o7_ —8+ûˆE§[¼Z¿¨Ð­úº Rñó}ƒ,yMSÆ¡7QÔ*ON½¡¥õ…£ È©¿'§®>6P'ï•YrT¼j/s-2×QæÑÈ<ÀË<×ÍßX¦3¸5*¯¤Ü3”›×ézö…æõ*¨Á†ª­FìG¢â”!+ÍìQ|1Õ„éj—.Åýº9¯ˆ°`O‘e]W‹ÖZÅU”6ÐÄ…€@6Î6ñhí M…•Êdž{å ›ÏWØûCùeêÊ\õ5 ËÌ÷Òký¯³õ?­Ê_ZÒÚªGZ[é¿?´¶ÒÒCqÁÌ„¥Žêe5Ð_Ç›e×_‰ïÿ†Àëâ`îï—ónÖd³ôïñ»èïE¬x]¶€ZêSìÎW)w͆zíqºév8¯»Õ™éÝ vþÏv·™fª»aïa®©zÙ|p9δHú`r˜\ÅOž²ømôA?y¾†]¼É¦¢±žo¼E¾Ž ‘:F¡ò¼¼œÄÝÀ m3ôï&H5Åf+`aÜ ‚{™¹>Ÿ©lgÔÁÏ,uþ‹ö·pWÃT|®ŠG0ûSåÈôŠjK &^uìÏr? Ç8ÏÇÍÔ8víd°%ϨÂÑ—í]IkM+â¹?VÄWœ÷ìPDøçålÌ´‚^$ O±|òø™Èþ=عvî¤ œá¸¦M‰«ãX ää` 'ðên™®¶(ôiyu7y¿M3xªrÒŠq—Œ™(x \#ÏÜX]ô‡^Ùb`¡a¼#q5TÀÉ&fãwi$2‘Òé rŒ•äXK ²ÆR…‡¬S¸Fs%LG^R2Õ?ËRòže±±œm¥É{®õ'ä=ßrä=ßÉVo¥É{‘•Þ–XiÝiu§åw¼ÔñV€¹©Ü3—2sðGÌŽˆ[5îÄ7Ñé׋P:¶Zˆ€|*Ã&%¸úÜ_aµka²%1þÜÇN‹¹sʴιÓJ¯•],5úpÿ”»­TÝcµé¢û-î¢N8r=Ö§q•ü·mp~ŒÅJcáq ˆŠCžàiÈ“¸eÈÓ„`²Ç80q3ä@Ðâ>÷ÞbÉ[FC-ëÝé«K=Ûúß±bRïPú:€†Ôû@:‡ù?ÒÇ.ÒÇ–|â5’§VŒTFÈ U…¨·V:WAzã²FéC’ï”ì–v ù&©¾¸¶øÜ‚EÐå«§l+‹ÅQ­E¬*ÖŽi)((?‚£µ™&ŽúºÞêû¡ü¡£êþ?~‹—3,8>¤À,KþŸµ½‡s~dÿP¥Î¤õò”Ê[^ÆÝ+í^±èl« êî¯Ê¤Qƺn™Ruÿšîl~jÛÍgTU¿‹EgbNœÃ 1öþ®–ÚG¤±è\‹Ïi‡p0^¼8Sp Åu¦%‡cÇý CŽ€;×Ã> ì‘Û-ó¨ãYþ7½ÑûE¬ôï¨!t³=ÿΨ˜K䈽ÁóQè|ÆÃòiD†fJÄUš#Štö£ä 6ÇxWßË= öû‘Ï{Y.¨,ˆå“Ô^œ/à`áý¾&çMe‘*˽>y YzYî# ©éï÷¦,¼,UÄ~‰,‹L¸ìý²àA_<Ûû~“ÏÊh 5›IcÒR¹p°y/›s¿ŒÜÃ{„ËC EXÐGh‰©–¦`¹k®!t‹è÷¡o¾&hñܾŽÝó"øLt®‚-ÖÔhþ;RNéÚjM.%Ú³,ØFâX þ È VpB\½|¡á.ßY«Å“ÑAX,¨áo-¶ŠS\¯’båCºQ¾T±Ÿtͼ1njºåŸÇÜî`nó*ë¬&lý™ÜŠ#ß4Ü û ˆíS<ÒèPÊÒŽ_Jìÿ¡Ø¯ñ Ã*)ßGÊê¬jÆwð™ø£—wÅ|õV¢ëç¥h¾åëó;YŠk]ðr_/›sØð’…†3êe&<Œ?b–Ϥ³|N±|­K+;Ró# ]BOïB=]^Öx¨°úCÞÒùìí£Ã¥ÏÑ×M¢¥†»¹s¸ïâ.HÉà†&ox2hù2¸¥É[Bwž‰?\ðUÔ§dp2¸ñ¬ ³ –sÓç–è.}ÞŸfñ)D1zMÖ +LAãÈóÅë‰úFér,ðó}¤Mt×u9Yqë‡#œ+̵¢·;𦲜ªcxúÃÌ4`Xåa˜éb˜©ãÝç†9m1Ìõ0Ìã#Só[þ%\‘+ôg½ñ±‚dkøAm-Ÿ:Äߟd‘Æ©;B¡¾³VG/(ecœêëuät¾U³QÇqÁ¢ °‹ zÊ¥ÛFïÛt@}nÖÙiÛ nñâa¤1lÔ?mçHèkuî5S(ȇk¸ìÁø.×›¦³Ì‹.Ì-^@ òRo­éš‡dAéðÔœµÿ…ßžM…TL\ëÌÔvÌêb_éGG BG1G­ç)­Û­AÊw©ºÿ3ÒRKvÇw™¥¦ªå–œÍSÕK~Û4ßÃ¥)Îø"2þ2ö¦ñp…U62ÑmÆ+Dn嘸QjwºŸŠ#ßá§9>m’ƒhn¡3T溊¦¡Â«ï&P¼ÃÒåP ±›œ¥¡[…Q§àk0­mf:?AÂ&—Î&Eg‹`¿k,Üv؊Ɍʰ”³íÔ¦w•›ï&âLb'HlñHœ L+ë@b«GâªKâª"q]Èë VÕDsK<ñ|~ùH­#å†HÜrI܉S]p&LÓ0Ôãw•ßèF«ò]œxæU¾‹ë!&|â\€žãn—Ìј.\èýVOŸa?ÐÀïï‡ÆB ŽwK“¬×°¿ûi3Í ØÝŕ΅v?eoºñ¼öoÁ9æšU&hGq'Ä%àCŠÜQ7jx·h••×¾?¸+]mõ\mùu=§Ä±»Q‹ö7Ée‰›\ìMµ)4ŠK¨¸Í7øÝˆÉqGTÜVLÛYpIÔ¢KïöJŽãP¹RoSr×Ê º•K¾‡éþÐë]ºë]˜6ê\óMrèþ|+lXÐlÓá­Ë<öÕ½]W2ˆ+ìƒ[±£„Štü îõ<Ï´eÐ5 ˆ60ƒû</¹ ^R ^Ñå[d“¼ê2xÝc°¥-ƒÒa0¡¼ ,8Πfå0ȯ;}ÎCÒK ù >á“ä´¡{ö¦0­u€†¨—…ò*§uVÓÛ½þÊÞ>Ž#¹žž€¸ˆ  Î‹³¤ÓÉw§p>GÛßg%àóÒ ðn ¿{|çgdû{ö{`Žb&˜Ä0ƒ9g1‘"wÀœ³D¢Áœùê_3³ JÔý~ÄÎLwuuuu¬îê*½S/6;Ö,†—*ãÙX§˜ ñ¥ìI0¢á #5g|¥9$|>­ÕcJ•kíë>uläi¬ÖUŽ×^y*hy>Is"?n’“5\„û=O/÷ºx>ר ÔZ=ígšäT­?ÁµtâMµ]zÌD*œA-ƒIµñ/Ù`…c¾·¥ð÷Lú^ŽïÚ?‹ÔØ$µmj´>k$M6³4–ö—“¸I™±ÿÃdve‡u.í—s]˜ú±. úÌ<Í£òj‰œ¾\ˆåh«‰Y#J½›è1²T߬aª4¶hض²äR"@.Ö¢õ‹l¿nþ¨ƒ¾: ¦VP<[üY©ù>cGRѱ4¥ÚÖÃÚïÅð)cØd—ÜKðY¶YsA>éeÈ-Do/îÎ,¶ŒJ€¸ÛdBzfM´Â;³vʵEƒi9|g"œ 5_zìĶᯮyõ¿@:È»†k<ÊA›öAvP¥ÔdT I þ=ÃYOßpvÇAÞïÂÉÝy$YúŒfOMç4LMáÐ:ÜÄϳÁ☬J ócZ˪iÊ_ª#‚i¼î1ÍQoLÑ+;ê¹½V¹[g¨cܧmï ÇyÕlU*ÿ}AùgZÚé‚~«ÞTñþ¦‡~û¾©ÑoŸ7½ÿ,ÿ«……]~Œ+Ϻüc¸¾òˆ.? Wh•ÄÏ oe½.ÿ-\¡W6èòß)£^Û‹ e4³ìdš>ÃLOòü爘?óaÆÖ>ò c0­Å, ?³1ˆu9Wvêƒßtƒù(õ©x&_"“ýÐjcû€ñL¢n&Q;“CT9 F™4¸™4!“¨NR)2éëfÂâè™x&®Ô:„LÎÆ3âÎÛCìy{˜*‡1~ÃU'“lÞ¦ÿ‘I7“1˜{ÎÅ3YLVA¯ ™œg²ÁÍdƒÉ&31}Js€›ÉdÒˆãf—îd²™\ˆgr ™ÜF2¹Ïä‘›É#;“'00b×S7“>žë$8 “*·$,7\Šgò9h¬ü"“ËñLZ-ù9“9¼ò'0b×\“É|drg&Èäì N&‹É¯ 1ùEàÚĸªs”M„kt©ÀcL©Jä@^õÂàÐ} :ºTÙÇ0±¥jnK='<2ì ¼Õý-¥ê­&%czùíWd¯ z9µìz¼6éåÔáõˆ^Nýà0[ Ñ1-ÇúCãüìI2¢(§îqÒïï>Þ¯T÷ÓxšD…à2½¼³+½®ÐË'øåY¼.×Ë'úå9¼nÑË·èò<^7èåtyÑS_¡•OòËË܆ÿ:&PÁ:&Ç @88 #cÀ7¼ù‰ò¯-Qþ½ç±üÀÝßPÊA>¸æ5 ÃüIˤR¨ÿò ð{~σÂïyPø= ¿çAá÷¢D\Jü’†BrÝ ¥pÌvµcO¡Þ›©Þ¡|N­ô`¹Þ—Øê°§Pï0Ë–ÑžšS½ŸÒåJߔ«„SõkÐ%IO†Yt[]t[ÖûXÏóB+oǽXûG¼´^åe Ó÷2Ò}ÇDp5oÔÐ#tÌ]לáuÍ &ù€=#bKÎ3Bžƒ8}Ì›ñ+gÉyAðVÔ1¬r.1ÂØ[wlmƒ¥¯)?æ¬?Q¼3P¼AÏÈ 7ã4‰¬¶¢ñ¸KãY¦ñVœÆñeñ•†—4Eb4ŽQ±Å„ärœêÒ8A}†Æ‰*Óxܦñs "gik"±%,‘Û^K3Ìq×ñ`qé õ=<¨ïÕ©$ƒå—Lñ+Aè/xŒVy"ؤÀ½G0¢ëõ`ƒ^ò¤Ð$±$ÊKú¢”®¾äå¶Š®RƒŸûCSýÔ_äj•º u€^ë:†\K%;­—Ló›$º@]Á«i|¨Û¬:Ý}3“%ð î¾µV#Ñ_œÐUôôj}úß°º*uÓúÐ$ñx¿°³-ŸÑVî!XÊ2Ê4í}æX>¤¡/[‡šòÓº< ¢“Þõj¦aÞVAM*©—ÖÉ]2e DÒÍ7DƒÍ·U6©QæÚÔGš&(‡xŽ©ÐÑŽÓcZ©÷=¦—ê'UyLåµÑ1/×#´øÜ– ò~að¸ r¼Èq¤ ^y Áˆ AÕ@¯õ$YÌøW#¡»©@–§ÖÎø+­“ CG :ƒ¾Ÿ ¼´A¢]”F°£ùµ^ü–L÷«òŒŠ•| …3zýÄG‹èàvý“’~¸¢ŽÒrÍ(™éWY{ø¢¥¶Céí_ÆrIY–.©¡—iÑŠ0%HE‚ ÔP0FêiŒ$þwŽûäÂy€ÿ>z_Nê€À8yßë^¨»+ªqº, Œ4r?êR9Ñ6ó9HwÍ|®Ô]õ˜šRùƒÀh‚*¬|—Véîâl} ­cþ,0Š€ü•ƒ †Úƒú"EÍÏ#ª¨r˜ µ… t·bPµ¥ò½@8!÷£V~fCm×1È¿ôÜ B={ÏÇ%Q~CþÝC£è-³Ji}g[ü >þ•O)þˆAë_Á OphÀÇô*îÿ@Ãh§nßÿ!øf ¥-"xœý?é¸ÿó?~—M€®žþs—†ûÙ¥â¡mD’¯ÿ<õ¯DŠ×¿"%‹h84Ö(kÈ'xg”3äS¼Ž7ÊDzŠïüåÕ­ÂpçÇ(Ÿ`Ⱦ¨æÝº[Í”ñ¯ãÕÜêžÏŸs51NíÑá€íywÍöêºåÑ9| Ãun©ò“fqB?­_•~G~ä¡ßy¥ÚO Éé¥ßñ/è¿”ïEòVS}?ÚMþú7ð—\K=ŠÍ,üŽ”yro}…·¶¸Ö/jÐåþž1ä©y ‘±±ìkŠgùÕùèWh5ÆÌ‚š ½¶x6%…öΗº—pƒð‡8þÀ ø3àÌ€?0þÀ ø3à?åÇ.þH øôy ø7fÀ8 øÿb ø¯ç2»)ÿ‡P%b`ìâO±`pyp'â”|°øSE¯ŸÁeß§Tö3*ÊŽ+>náaÖJ*?Ä<ˆx – Zø€ ؃Ÿ'ˆ D®±k[qBeÑ·N0+QIø f±3 Ój˜ËÄsUÒ‚9²òYެý“Ù@D‰¤àùU¦ÿ‰²ùOò©†ØDË®8w¿“~ÛŸL_¨º¬Þ¯Ãå_’íÉØ½ƒÛWºëÊBrsü¶æ7^¨œd ]÷@lÀ<{Ïé$óÖЀùfåߨ"¯Ž½ð÷¿{ùlc‰!zžÎ/ØTRy:¿Yl.Q'Šžgò ¾(©\¼Ç õÎóºnꉟ¥ öªÊnštø+õ^UmLìž)±·A½Í߉<¥w"¿û~'ò{§q@:^3ø5¯YüšÍ¿mžëω~½½½ÍbÁÊUbß’RG¿wU<––zðØù¦vU%±.•Ò:áN½†CµFÁ²Ò‚å4aªì¶7ûg”Ë~–å |ÀIl —˜á[K·õÇ "ö´ æðÏ”›9Z@6Þ9JK:E¨1] y†crç·§|¿°›ÔÛCéµcï49ÌcsÀWZÿŒ1̓ϧtªwb’|¾ô)Øð¤W GÅtYXÝ;CŽ÷ÀêWØ_¡óE}ƒ¯›Ê fê ¦!'E –É)xMcïwS=qn¬(•Ó8Ç…3ñdºçžÔz_T>ö=or ò!÷ŽÎµm•ã=}ËïÄk¨Øÿžî0!ëÔ@—3œÍÚNì`-NÄÊR¹ÊãVÉêg³ßè £Nò*wÉCÈÍÜ|° -ÜBSaÙæÆn›Q^®}L¦%÷ó3A~es&\  úK$9ñ;ÌàKGQpý·Nõ¥ ü}ÏÇ|içØ³Qï«L9êÈñ´"‘É:ãñý5ÏsÓIðõ‚EêËüaÉ+ß2|㤑u~=Ž!S63p–oÚÚ8É™.É7[“|ëûI¾ý’³å;uvžR×;KÞLM¨¸.ƒWG!ù1ul)õ¾Cÿ;-b²\ gÜP}g€¿€,s+ÚT¦”n£³ªŸÅ¼4íϨ©=ñø¦ÛV¾cIGú;ßybx2@kÅ“ÁÚwy2DkÅ“¡Ú÷òd˜ö]ž´‘ÃíÔmlž|¦ýIž$Û<©Ù<¥}Of‚'c€,s‹Í“ÚŸäIòbæÉ8 v¹,9A‹w»U¥r¢æv»IZënçë Õ pÛC šKžàéü #®X ·wgÜÁK¢*-xÖ ù®b­‘3ðéSÏß>~|üô_Ÿ<S1šïß@ÑôÖµ’$gh8µ|ÿ/Œ€T"à”'ïi,vàégR'ûøþ[žø¹/£Ü—>zºóÑÓÉOŸÂ*X¨â¬J²Y•þ詬Õ.: ÕªÙ¡Ñl £ÿ|D¦æ))”‡K5|¼ÜM=¯>TûzpÏÿ”&µ»Ú Üùþ6 üŠHTêüŠª* ýŠG(‹üŠæIHXìW¼ IIKüŠž ,õ+F¢²Ì¯˜BYîW,²Â¯$x”•~%1KYåW’²”Õ~%9KYãWRTe­_IÍRÖùŸPÖû•4²Á¯Ð"~£_Éð(›üJf–²Ù¯dy”/üJv–²Å¯´ÉR.è*-Yó’e•f/Yš`†F±=鉵š\£aùôiç4[ay¾QN|ìØM®åóµÛGS]Õõš\¯!>ŠCxä­žV(‘:;i}èNº­ ³IãÔÛ LÎç)aÕÁ ‚ìE^ý#ÚÇç‡ ò+ÆšþcG›ç &jÐæaû‚×Góˆ³>*¹—®kߨÈòC­ãVÕ•+ Ù€“žKºæÑõ!G(×5–1®kÈUj9F$œkÏ1àÏî²îõèæfŽÄYÒ‡áÔ¦TœÒì•ÊËg®ÐìeŽ—§Ý3ì‡É+^«ðQçDÓ]gˆÅ|¢yNë ëðXµöÃÙ-"÷ëÚ{—tdmúP‘þwpƪÔ`bh«¿x›_!òrМ öA«ž¾ ŠñvO÷ÈGNO÷Ø=G}¼.Â’m~áû­Xz‘|¾¢ÉAˆ÷:K¼:K]ÀËƦèŽÅK cÈñ^¦x6<Ùå·’‹ºô?gg{±Ò¡í~FÂï;ìw.áüâ\DÓ]°iNzÁª^N÷¶fƒ)g";ÓaC­÷6Ìòºl˜í}† ?‚f2ÓÉ[¶ ½­ˆrè)!"˜]K9y3»RùVgë ¹ÎÛU1í~¿Ë¯« è×ÔïwS¿W•=ÔíÑ[õ,e/õzUù’z½ª\ÑáÁ¬ŸŠšßéuM-7\5«o+;iåûU©Àã@©ºÛ˾éöxånØm’{ÙMžíâkŸ×é'šÓQ"%wÓÁØö‹ì®Ò@]å+o4}¢ìzSôöP v—öP~£_ØÆpz¼†;¤»K½õ^\+uQ3…²Þ[á µ¤Ãî×!/IÇOY*o„ Æ£Þzb"E“ð²˜sŒ¾wÐú?ÂÏSMäœöb;÷ª;è-Ü ®Ṵ́݊";ƒ{ñU/÷b³ x_[Qrˆ&ÃîÒx‰ã^²£þ“QãY‘Ž]Å6ï„}f¦›†S4øÙý'ƒ€ÚÖ±±Ð¹ß• E`š^2MWä"4¹ûÔ†œÚ]Ž&º²5spóWwí}ÄËÆgšä*½Íçë € ]>dœÏ3¬õˆ–€fâ[-‡Jå;„òN~©È÷¾eXëƒçÖ*‰Öz¬ÃpW:’ÿ7"ù¿·2¬õä]lÜ/š¾uM{‹¿~lßÌþÂ(~Ûþìo¸'A# ™¸úBîGïT.±¨8ßxŽ©¸­%â'=Ïåê•çò›Å¶µ[³xòϯi-Y¢õƱ—¡QÊ–†RùQ\¼ŸÖŽªçz^ȼ#Á½jÁ ‹#/‹âwDù…|$*Î Ãcx´û ÿ}ëF˜HÔЕÿlsÛ ¨7–ªƒ…üßž«Dð@nèÞk´¨:Lm²zLðR~Æå¢ç¥|Ûmtù¥|t›Kù@y›äQŸ›ÙB®¼5W¨¡,©ƒDm£Eðb>BÆ  RŽg4õå‡ýÔ1ê£y‚Þ|¬>úKÏd!'³Ÿ¼ú¾4·bYî°ëçÏE…|gÐMìv²ø¡î…"š©c¢ðÏ1Øĺtp`1èRÚЖ¢†ªêÑ^@Ôrwƒw¹@¾˜)ßÐV®B#Ø;Áz G°ËE°KÈ=6‚õmå^ GàÜo‚F ø,Žà‹à6‚ƶ² FÄœ‚ÓŒ`#ŒŒ#8ë"8+äyÁƶòŒbÙ€ºÑ%á¶Î¥›ÑqüŽ.ð7ÿÆŸƒ¨9¼û;ù—Êh:ñ¦¶è3c Móh]sÎ…9§Ro'ðøJUÏA-)¢õ%›Ûzäl3<ÖÉ{œdƒ=ìý}0.v3|ÉmUûr÷øxÆCƒiJ"T†‰ˆ®fB€è:ƶêM¥zI@S²¥­‹6!^žÍ.Øf(%qy¶ry&Æa¢.LÔ#Ù0ÛfR<»K.Ì%(×rvÛ)»«ÈnrÕSì©GöÑÕF5%Žj¼æÀŒ‡8Fµ“PM„TúyÕl‰&—Ù¨v1ª©qT;\˜šÜm£ÚM¨ØÙ´8ªS.‰gmT{ÕôxíÜb˜¦Rå‡KÅ-MÞÑìÚÙKµs(gÄQñ:àC¼0Ò”_2Ê™q˜E.Ì"¯\bÃìc˜šx ¶3Ì¥7”í^r¸û©»p³µ6Žê¬ëAì,ŒÍ0ª¯Õ,‘<Ú€Î÷«…2\çö…Ç”ŸªxT=xDUm¸.Ç蔞~#QZCªøX[ögÆ<Õ<Õ<]Öé633âfä£Õ)¥YŠÀ¹†{ŠF!¯Ž8§hñBåA˜ æî4²46¬3d›@+÷£ŸTî´§Çe1¨Í†{Ö¶Íh4r?úiåOè ÃU™8:mÈ_®ÐÏ*ß¶ä °~þÝ iW‰X+z6ç¿rÙ¨l¦)骩n=e~Þo+%}î.ñ|)z¶¸SA Éž+éh9R*)·û6åV½ ¹4 ~'R!—ž)PӛŚ?‡ÓÙËìÑty8=0­0R<­P h”GÓa:Ø’ß·—éû#F{³ÂøAߦf1àgžã”æi–v"]O¯¾=Øå‰t-¡³*ò‘§ fÛ‡ÞÓéÔ o4æ™—dÍ3é‘ }[ë?Ki‚u“çÓãÆ‹-g¥`?4´¾4‹˜¦!/§çvÿU'–Û¶ŒO¯•ô+”rQ;0î(5âvÍâX©ÀcþÛê’vrI»¼§Mry»H s´¸³(Žâã&¹²]<7ÍÉM“ëÚÕw/ÿù;Gý„ý$UHBâ9fâ)lÒsrNø7Jå-S^æsLÜxég¦ûÙ8#^ƒÇü¡ã~h<6Ûß'ü¡“þòS~¾\Iß§ý¡+Êuwœ™ÝÞ“qÍ ô3«ÙßÍ]ίl6  Ba,d<@P‹!Áä‹Á^“;8Â|ŽS¥ª¼|ás€Üô²sãÞB“ÛÊÇâUû+˜ºÓ%:lòÍçÁ˜Nqa?FGbÚ­ïwÉ3‚w»°æ1jW¨ÆÙa “SX.°#·dG®Âç°)’¼ßv¿/DåcuBü°¯ZÏ£Ïóv†ó9†¯Æ×!ïÓ†mŒòŽ9ík­¸ëV¸ñ¶ÎÐ!PúhlÔíŽÁÌzʯÝh$ký̪×d_Íö,Ø,îp ÚM†9#f®ë¦a3e(¶o¡3 ‡i6®Ñôl‰7ðëX­o'Æj°õV|ÃTˆ9N‹²Gèj-¥ªŽ Ž)ñ6‹s¥¢J—Uzp3?n”}tX2e_L× ˜Dû_H_:5Êi:kŽ2ùVÈoÐ>Η*3hpò 1S‡é¯âAªRp¾4tÆÿIƒœ©;Ÿë¢|Ò(kô0}D¢Å绨•£LYû .ŒŒ³Ø EÍÕ=áx‘6ÂöÀfõB2Îû®·Ílû R9Æ”»Q€CÓÝáì¸îÈöyò$!gæfnä…¾rVÇ„ Îë°\@ãÝ8.>¹(§ÿŽŠ9û¢Î¨ázº­ëzš&ËŒ)‰Xù?Á±óIDZó5ý;]ð—Èòb©Ú¬³PjG $ý·ñß°ñ×»øå3øïr,Ô“ãœߣHf®FÄÍ8§ª]¿™Õ†œ·•Õ¦œK·â‰cŽ?'"ñíxâï8þœhÚŽ?ïÄ…Ä)ñd$¾Ë‰{"¢ÁMÜ`È&#’K‚GIÉz’‘<VÓŽóKÔ+O‘Üò-/ËSÈg²éÃÎÉ9# ¼%›)Å#œKáòò¿Çù'#‰üo=ïsh„ö‡'Î4Î<0ØÖÁ ~-`(Ÿ°Ü6Ø Nn²MÚ>ˆ'›ŒdŸÇ“Mµ“õw“Mãd¶í߇­ˆdËv*xðÈ€™Çw˜¦Ë@“»Þ:S®ƒ›Æ©ÜõÖ›TÔ©&|i†C+ÌèŒÊ¦Ü/ó㸿îýfXÜOâçq‘2ˆ§ñZûÆÍôS^G3LÙ ¬UfŒk÷‘ø‘‰¡»éÑÿ ¡ƒ,ô˜÷hñ³%A¯=Ä K±h~V#Q4Å¡V`PRð½ÐæÎŃ’Dzgv6ÖCnÉáVà=Žèþž ò3«>R>¹½a†$Õ³ÞÏhxÐëkbämƒü¦[¸kÙîÊ[ÔÚ‰ž~&Jò&â—Z®ŒlÉåØU€õm+¬HðAÖ%\iêÝàFÇâØwûn'Ù×öñøFÄvâ¿qâš±Áûâ›­Øà--î¹'ið†Á9öà}ËâÁ›ðhÖ ìÁûŽû½.>xÏ1å}NŒ½Ë‘ÎÜánlB84Ïä}q áÀ|3Ü}¾)*癲šc°·ÀUø’Ô!É"Ѝ³—N‹Â%—ME.MÀ¤ÎAË • …ý‡xéö"ù¾„Xéö'péÎRéÐë"»tá.=d$á™ÒÈhÂ3S—n‘)81¬˜™±¦zy]¦ˆ%ˆfÆúÇõ§‚¯'pÿ R&D‡þÑ’@w Íö Ô?F¢Œ4åMøÁθs~ðä€D^.âXg`b¸ßQa°Ý'b§PÄr1"NÄ´D‡ˆi‰LÄŒD9#1813‘ˆXnÊx¿[ "–Ò<kü#M暟Å*FQÕAYE(ÖýPàq?IÅãp;Ç®­J”ëÝû2¿ÂµÎ @3Êô¨ ÉÜbAâÞDŒ1«Ìnr_âsvÉùÝ„™ÞîAVªŒŽ§=†´§8íjJ{æyi/¶N;ÆÔÍDßM›zbLKîR©÷táªú ÿ 57*î5»¸×ìâ^³‹{Í.îµDyú-"øA謿.~¶Lßç¾õ}Þïzp»i'I ]x$)tÑ_—þT¿÷YÁ–ô#~µ7˲OãZXJ+-,Ù?‰Æ®‚|¸þ'šJÒïD ¯(ÈÏïØ½¯ðp‰å ¨[ð‘Rù%¿ì~©å—ýrˆûå)¿BC¡û¥•_õËaî—·ük¿ž°‹iÜcPŸ%u•£’¸0«EhÒk™ÿŒø$.LvèÆ¢SRè8t/V_$O ?ÁgF’¯ãw”Ídt ¯ù½(ú\;矇Væ·fëÏCÓóëÒã–] {² è›­ÌÐ[°úÚB;`:äR›î—aR É­GÉÚ+8ì÷2ù(ÚŠ¤ðó⹫’ 4c—B•bÍ÷¤pJ³žóŒÚÛ”ÖñyæŽ+¹îWä&bù6·\³óëÜÙ#£:½ ·á“ Ìe>Ks ¹3 ‘ô°¥¹]ôùµ-Ííæ–æö‡Ñ¢Ã¡+&ªÈ#÷sÈ9 ¹ê„ü%'uõ,aÑ$šý5êCug³o+´ÇZ/ÞtéW„PZüŠš Üð+4R%ÜÄq£Çs˯xéë¶_Ñû e¬©ÑÔÍÝ¿!É’¸KâA]²!IN˜ó«uDÖlÁŒ3i‰œ|ECª“I˜ðû ìÏSÚ“vÚ“vÚ“Iò ÷˜…¯p—鎹>ü¡ç\’<—„~³ð•XÇé¥ÉóIZ}æ½DÑ].ÒK=zÊ%ô† -Ö.SÅ|“q›#$øˆÓq$|݉bëÍIv3làXK’Ýäm» ä¿b«…¼—ô<ÿPã\xJ¹÷OŽp›ÈD~“cqƒ“±¼A Š\o1Ÿ¦CüšÌÍÛÃ’i=Jå³äxs`7Õ#’ã­ìŽkl<‹jÊÚí‚;áûqÞøàÎÌíH{„¹¾I 3yšž–ÌÌ@ÇÁ¯™µ®¿,Ñšó ·=¡'Ôq±ù›qC“ÄÆ‰uøòägÆ&.æ*­ÚíúäøHõ+€mJîêÙLmý$·ö}žKžëÜÚ§k›µÞ”ñ<ÿíqûÛg({’I8+_&Ë/)ï&MÄû’aO<Ì+¾ýÉÑ­ò˜Z¼ÁTi>¯F«N É!É¡dl /÷°?u95ºòÄ ªèÇ]TÂ<#5ަÚ÷M²&ÕÖµú@©RmóLè͵,I¤ ó¨rAêo`q–™’–8ÍBøÚTÖc£2TÂ$œA$£í¦à<5·j¾èåk7J•õDùº¿éÑÜC½D›¥žËô¸Uª}CÙÃÛœŠ&®ËTT¼ÑBÛ¥ætJ~§ÔšéùDÂ,Ÿ\ï°é.6ß‚©ƒªRä†ÔO‹SqH¯4R²3_•›S!²úÇÖT qACîN Û[•ýM¹ÇþhôVö5åþÔp࿺ÿ—RyÏaJÌš—çË}³F vLC* ûáN²‘>OÙ1‡í˜ÃH³,_¡ÏãvÌQ;æhjð½Ðå1úϤ²äy–­…êçJÔç9òæÒE‡)ëþÛxÔ_/9Í=8 I^NíH-åŠ|“™÷ K[ oø)A}ãŒËe1µªæTŒ7Ôžn¤Ö;gõŽâév4Ò–‰÷©ÊnôHz*o†zSaÞßN ×Wö1}Ø]ºKìž“®/ÐI¥0y?Ÿ¡Éí‹ûuÔ~ä4Í‚›=b³W²|Heíc²é9C>JE[óuãÑàVä'h&=Rúøä«0¹À½Rd_E2~Rd__E’ìç àA£”ý}zE*Ÿ­&öwLì¦WSÇùä8_`¾ ß(ºã—ãA]µ/Ü}>­+Ñ_äÈ|äDÎ;`ÒK,Enn®œäËÏ/ñãî¦ÑÃvé>Æç”d,•d†úËW î Jô²d¯Â‚Ú_…U0 °xu»£Ã9y‚œís6pm;½-fð”ºfzå_à”ŠâSªÍ.äC@¾h1×çì3¡‰ÓU¥U¥õJ” |ÜÔë|š\è«ðÊEPkÊÅô¨1åzÌ2åRzÌ6å2ŸÛE±Ü -³>ñŠâì8ÊåÏÆ.‰Ç6Rì _®\I«ˆ[rµ¯"A®ñU$–,·’åZ¸.ŸßUÛîsfâí>¹“Þ2"%ãÓ…Üí G~…þ³× ¬¦À}>¶1Ë‹ž¿Cꈛ:âãEOÄ'ž›wc+|‡ _ôWÐáãÇZá>Á¸çÆ);çâ>ç“À‰x”a5vÉ œ@W8õ<çÝø Èç¬hš}@"Z|²…ÚSc£¼Éi£Œð6ÒLÞuð¾3ùüøÚç©‹ð©OöI³1Á‰]bPš³:”&‡¤ÅVGuqˆ‘iN‘F¦ÉÑiö ÇqÌÐ<@Lp!&¤ñÂhBšœ”ÎaM49 &jãè¦3ðýRezšœ t;Ýâ8Ä\ÝÜ49?Í^rÄq2xSš!®ôPÖ¤ÉõÀ¿4·ÕÛš&w nï—ò î0ÅÉ£i|‚3Ɍۑ˜d:IÎñ¾øòxŠ+HñµbB«Üg8Å S3Úóhšã\åQ{Wy”&Ÿ€Œ•̯¼€™îøT™ÎNUF¦ËÑéÜ7„¢t•Õô~ßàSωü)?ä•“ø5ZÞH+‚tœMFhps m÷5£uÕéy£ÒÃL„ÓÓÃQÌ3Óùê*ÍmS^s/¯Ö¦Ã¨¯Ü‡0=«Òùœ©‰Â*Vkèqµ‡º9]®Mÿ¾Ád]ú÷ &ëÓ¿;˜4Ê-éÑE?Ú†§]N‘v¥C+}u|«ó&Q$osƱ†+¤"ª2(¢o˜»CsÃø®Ñ¸ñªnlø{¦@›!ÇgD‚ï®èŒÁòUYx7Rü®À™H¥!é21!q…‰ff€ c:Ú.ӛŃRefF³˜òލ¥Ç°ÕYôü¢g6=–js3°ºñÎÏÀêF_@ÅEÆö Y› ÝÅzo½ŒNþ´IΦ— ɘˆçfÇt,¾çÇÄKlF…×qæ½ ƒyOâ‰å~¦¹0C.ÌŒéX5÷3þâ1S&eTX¡±ÉÑL6‘< ÈZ’Qð¸T.É€ó¥˜É5h½kŸbÍ_ð¤T.CûW[žQÏÃ^”+8ʪ+3*4TlÁàå*ƲYŒO®Hà;k3h½ Ãñ¿ý4m̈R»c?3›¨Æ›ôƒür3áįš×ß[2ò»Éí±@vû¾“I„Ê0Í~÷ý”4IwñðÏAøîŒúj·DÕ±ø‡þêj¸›3½ZBòPnÁ¹òÞlÈ­z½QF2¸ÿüÞo2Ø¢ã_€¸œ5ÈFúXh"ISF„ýΈä)Kªò¿FiæŠÒüľ‰ŽœψmM79y&£«ÈùŸÿÞ ” LÚX•³2ƒyßábt¦¼Çí7­ê"¶®Ghµ™þk8ÁC”H*xZšß±{’;NÎÅFY•éÀ>òDþž·wX±¢Of¸cå CöË|YC2ƒ-ù8„lº¦òùWæ·µK°Ë1<:*ƒT6àð>¸—RåŽúòU>Ö‰{5Rþå«rtfðnÛ FžÂ!ýÉ ó&W8tÄ^ž.Ùe*²&³«(êýGÖ ÚÈ’üoÀ¢Y™‹feÊ9™Ð^Q3ßÂUèÖx@å|ÎNMáýÝXäQ;“…”ÉIÊdq&\ó1öø Ξ4S.Ï ‡ž”ÛöX‘ÙU®"4÷»T>1äšÌ¸. 2XÛ:侞28Gl@›9{9âf°=SîÊäåÒ®L[ÎØÉrRï¥Ô× E~‰Ô_˜Ags »ÉÙÍbù/E4SF31BU½Û(m|™¶ Ò”É2ð¶cgÚ2È‘L–As,3&L`Éq<3œ èTf8°ÛÛ}·W©¼oÈÓ™èÕo•o0ä¹Ìpç&ÞUÒ`›mšijÔtÎg†“§ðèÑßD¥¿˜É'nº/3ŽüòZK^Éì¹ùe|Un~Y^{.ºë”?ëvå Fø 3ø9k\~÷Ÿ‹’Ç~!fb²Š‡a²zvmámâÜÕûf¡«[¹U¾&f[ß,Ù?+šÔÞÙ쌰"U G{ˆYPÜVeÉYÁ'þ ùwâ·XƒGBSÚÓ¨ô¾ TrPV˜°ÉÁYQgK>š§`q.S>åË5C²b€–UÎÄ47<‹Ï•)C-ó)Ȭzþ.¹ T9*‹ˆßÊ‹“Ž }b–SÕ³äJûÔÖŒú<+\ršX;àÛ¸aý’7¦\ðÚ,9;‹«{v–-¦ÎÉb1Õ=7‹ºÿSCÎËâž“ ŒóŒ €q»©[ ‰}ùœliVëÛ^©¸ìUU¦œ!&õ)WèÑ·Lýš«‹<÷²ä Êe¬É—(Wfu•³X L{ ·N³b*ï4¨|‘È£j[’g#yZÉSªÍmYÞû•ÉíYû—9B ó;9rÀ‡rGü°uäž,[9_î}NäA޼ÛC†9ò^Ö‘Q޼ßCÖsäƒg"8òqÙÈ‘Ož‰<Ì‘O{È#YõLžÇ8²Ï‡ò8Gö}&ò$GþPžâÈ!ÏDžÉÊÅŽÆ•,{=4 ŒgÂFùu §˜&;âT ¢ÅBàn ­®eÕ³ªÚu»ðe1Ù¹AʬH.7¼Ž{Ô£UÜM&ãa{³ä¶ÍÂ2y‡!?Ãü{5GÿÖ®5y?‹'`‹gZGVþ'Û?ƒö0 Kï£,ù0+f2þQ›Œÿ ^±Ì|UïŸ-ûgSNl<žV,1yß²+ŒÎ½Ì‚i¿ ˆ 3ü¾xÕ4 cX~­)FdƒÚ'fqf§IiXet6UÉÁáDÉ0U•ãrR§dµ 9‘ 'uŠCÎÌç–\ ñ¯6ÛxgeÃ\˜™@#ÉExWdc$y¿öŒ•ÙrU6-Ô ÓþR(ìK«Y );²åölšõ‹¹3;ð>ýÀÿK$T]Ø1êS õ-’»(¬½F:DBé/Ú¡ûûá•»³á&ŠÞ`ù®ÁCp64ÉuÙÁþE¡¯Õ;·îbÉÌaËœ0ᛈ£@PTïܽïM1è„y|ÿ‚ÎÈaƒœ0ývmæ°»í0/¶XävêU;L÷Áñå;í„| x+‡MË·ÃÌØ‹§xËôä=}j{òôûþS´Ü~ï4}Äï»,ªÛÀ¤hjêá6rr›pñM“=ïbl¾VDµÙñ•Ë-è49µ Î!‡SàÙxà4<ï&pá:d*ŸÆõ³?MG{¯iÃÇ~.æ|¾Öw‘ÇÂg¹á6þXøü6X•ÇSWz̉ Út• Ûðr¨†Ëvž•mä2æcâå°’?ùtŽÚ m*4ŽÚئ«ï·¸J¾…BHBÅýL¨ìkÛÚÈmmïVh$§†ª pQnoSáu6i+¼Å ¥šEè:gƒìjÛÕ7 ¹» k\ì%´n¦›‘)6¿zŸ ßp s<:åµpèr\uwÓrŸI±ægÞhµkÕ,ëÛTèá l[¢·ï`“GÛØb{+Lÿåá6¶Ž×¥6ØÕà›Ûî®ø û\ncï"›ºx¥½yкjÞ’øºM«Ó€oÚ´: ¸Îè?i”ÍmÿI“”ÞtðRø-Û'Ô—Úð¦Z}ɤtš-ÑÌ÷šÂÕNìßÖé;ýÛÊmÃ%—ˆöAmár€û×gÜÕÇ´EW/hãÚ>£KÛB…þ{»­(ÕmeuÛXãhÀhlÉIm#Á®öåÓ)m]#Å]EÉžê!îÇ^ú˜Ú¶«œÞÖõN=¡m$mÌ䷵͔ {ËÝé™ ²öÑâ91ý–Ág˜m]‹SÊD]Û߉NІê„Kïz[ŽE *Z][¹ˆH“·óÅ”ÝÒ¶°ÁñIoU.sÞ/c-·±Ëë°êó2—UM ;ÃQgr©TyÔùB©< òT[û¢=Tcf橵Ÿô&aʃ™ fʳm¡=…òœy•õ@Î;|3}o £bÑ'_ÍD‡½Ü |u5uÊFòƒÄðµ`‰‹>m#‘­‰Ô> ¼Ï š–­r¤L-«ã³Ó[.aòv ûXœîÄÒ}V” Ÿ÷c€¾´PÅàGØðO¾U$ù4†ÖIú´sáGeB¦è×î[ðýÛ=›Ô޵E1ø nŽ5 ! K"ÐÈê~™PËæ~©ØEî~y°‘:¢ïºÒà-GµC+m~ÒÛ’cÚ7½Lÿaª¨sSùqo½é)?æ•cÛ…fˆ˜Z 1㜠%N 48 ü…"^Qã¡Q'”ˆ›=ä„‘“ã¡N(;ì鉨éílY|F;ý¤!g¶³•õì¦\Ó.œÐYíºª¿ÆnKºX\×XÅU¤ˆ¤¤¤ÑEŠú’2¦Hñ¼¤Œ-R´—”qEŠ÷%e|‘¢ ¥ºH1^R&)æKÊÄ"ÅzIÙÏÛ«¼»¥3ni'··ƒÏ‡†ÜÑf/ã@_º@_¶“_¹@t€µ?þ@M.PS;y¤´?[ ýñÐ`ícĈ‡FPæ×›óS Ès¼»E0;¶EpXò1KÙWÚaÓž’~ctiyø›vaíºÙM^ãPZ„ãà7~›"®ÅÀïx3ßåP0ÍcyhØCûÛ´Šë÷†ò°-ËÊÄãv˜»Õ'íäãv‚HhÓËÅ¢ª QökÝR//å^[a›cÀ†´mW¡} ÀÞ¦‰ÞI0 }4øöŠtt‡AíoG‹ß”—ܾó>ÛšÒ¾žgý&9¼=öÍ£¬CËZØ“ÛÃQAû°ÖBÔÏhÿ ÚÙís» Ó׆÷)ë± •¼‹µº=«··è¯Inl2)xô{C|Aš2uK{ ˜ÜÔ>BT°‹ÍüŠÀ/Ú:GŠ; ÌLåç“ÐÙ>L¶·x{xÑ.w¶"«]í£NŠ­í£i4—ímÿ¼‹_øÌÑb"7eåé5’% sÇÚÛÏ@znÕ) P½——‹pª½%¿/y3JÞÒþ[éÐHä DÝ#P±ð}þ1?ôû¢ò>>~ŽØ¿G*š²k8ðÀŒ`û†N˜¢ò¾)»÷l6:âu‰+Ù?5qAÀ#†]Á@•î^eÙÛz×󖘜î>9]TÞ2äßSÖ'M!“‘Û?Óü÷ûŽÔ\NqXÂþh;~h†N³aiŽÉ@ÌXö€áG& ý¸ÊLÅKLÊBÜħ¸ûf¸xÚKPA8KB “rŠk9dŠSa2àcõ!Î1êƒqC˜ÖD‰I±S8Ê;…ÜÍñ‘âó0_ šLLz@¶›§3=”(ü;|+ö‰ÐŽÏ(‚&ßEê ‰IoºIØ#e“@¯G|ÂD~1œf'Š(¬KF»ÉãNvÄwÜ/6u=1éoà’pÔî/ VÇã~’ŠÇáv<Žÿ\»$àH²õÅŸ¯m|vHÉÐB¯ü\¸ Y3é ¾ã"¾c#¾c#¾#à ØU%¿ï¢)ÙTè‘€â 32(úãŠû@ÕƒÅn/›*y"DZÝÔÇ©<¨Seµjcã±VQ¾fàŸxƒïáf±¬L,„c—ÀN¨±ïŒæ¸ÓU;F¹XFJöB.Á­÷o¸Î;ÉFÉFnªø²Æj$Ô÷å’‹IpXóh\ۅ߯:]r¿*#j¬ñÎMÔþ.™ó’õHwÝ„©ÛµY3áм/Çתӕ¾Vá ò—ì2RÙ—ÖH%Í]ó^½I ù˜ûö,{ˆÌ›°€þ–¸»2?Sªò¾8˜õµÜx0CTÌh”Ôhèä‹ÐÀ3TÛ®ªƒ­NÖ¡ªC“|¢Ö§W±Uõ2O•§Y¬(ÓúydO°ªC`¶ˆÏ&L#_Ðpèç 첿'¸G„îÈžüü‚•er §¾àÈ_ÊA[Ù$ôõÑÚ)¸)æ;ú”×çuÑ÷7j÷=Bã"È¡޹b(ÔÂ0€±M›–VEíùv‘G{¸È<\äÉ9Ñó=EžâùSEžê‰yº]äx¾|N‘k¸Èµ\ä»r–SäÙv‘çüÿ*òüo¹E¾aÂ6 ;‹`xa C…N`ÀºÉmåˆ[åú"[å‘k$R~Âkâµb…ífŒxµÉ#¿@ÜíxÜ7n‡GîBÜL KÓÅþ00ó{g‹Iü÷Ñ{/¸SÆ^®¡‹j ¦È¶Úòþ •UÂΣåÞ5][+ƒ,×lËKæ&X¹}P9ÈâÙf°%hE`÷Š!–ªZ ѲªLà[µ×zPZ9È ü¬ûÏ”ªŸ5ÈÁnb7äP+R°º¬ü®_£ ¤rê<ÃùníPÆñ"pŒg7ÞRÆ[r‚…ž5Ñ¢ž5Ú’“pÇw˜¥{­„å*@ç0hýO•9V³XS&êè±¶L]ˆÇ/i’K­À(Ñ}”PªFáêÑr«B V†N½ZÞ§P® ¯ŽåµEr%¿Ì*’«øev‘\Í®iÇ[åsŠä ÷•.·—ëzta84Æ ž. Í-ªã+O­™‰Vjë]±.-+y‹ÇØÑìè<¥ gR\£×NK+>¸Ã28ö¶°Üb—¤…F0¨[nµÂ¿mï†[°çÿ®ÏŠ/KÄ6­ç­ü×ÛVÞÊoûJÔíZÏÛù¯ì•·aç3ªn+!<ÿ¨=ÐãïQ1¿=/Žò!l¦×M4qÔX°æÅUú!"¶»sòv©–â«;§{P)Ÿò »K„KÖZ ßèÛÃñŸ:ñ¶Í^Š_g)r¼UÔXr?Û£ÂX €_"ã‚•gY®Ï'ySà³›¼-ò0·Žf‚rà¡KÐCZf² K>Ò1ñÒTcŽ›HÓÁ”fl<ñ4×sÄ4x° Äs,9“€ÅoGâð^Äãã‰÷¹‰÷±+úHåä&>ä‘HL¿ ‰§r i˜+Hüµ'èç/îçW*?‡çX³ô+a±0ÙBÎ`‘´:GyJ³Ëú2ñIÊÔô˜û3ÏHzÌû™6Š˼ó豩L_¡É§ž ­¹Ö¹V¡ž ¬´¾Â¡Ùk® Ô ¹Fb'-±XsmŒ[¹I®%ùVÉFKÈÏìAa™•—0ó•ƒÃ T#´¼ £Fº‘Ñ™ŽOøae‡.±êã¡^xŽŽÊ‰–§…?êþ#¥r’ëlöû ¦wì÷É–œ¨Ö›áÐ$‹GIö×ûk²ý5Ùþ‚“á)>+´<ï ’iª°L<äÔx¤×‰ŒÚ‘4lÁÅð$ËQõ›I<¯%OˆA5Zäõa‚xEó¶Á – `Ó,ÍVð›MÏ'…Šœ«9üž§¦%vŸ–¨TMÉù¸ÃSͼ••¯Òe½f”oK‘ ¦–oÏ–‹è~"r1\#/¡ŒäR-*—iõ%ál¯\¡…‹WZÊ{r¥Vaoåg À¢cã»ÆjM®ÖƒE÷Á4E ±Èµî¼òTäùfÏËóÍ ÞΟY>¯H®‹…›nÚáó‹äz7|‡,(’m†ÜòU˜åý2Ùñð”ø'OŽn¢é–G³&q‡ÿJ³÷yG žƒ·–‰0=¶•©Qز¨Ï6ÆdX‹`o,RüµP ¶—…êŠb7‘ —DµhP Ð$ëµzGãª>O)¾ÙEhu8Û+ØAN«ÏÅ»ˆبÕ,ðr}ñËâìcïVþqoÍÒ“¬„«î~lh)úSå î¬ýTà±³L…Aú]ežfòeš¤Çž2o =.¿¡ßÐp,mÀLߌLó¶†>iݡǖîjòkæØ~£u•׵ׇ úßCÅœf­0³0 ïÔ-¤öúgâõEý¡EËù]—7´<…ê¿ yËî?-¸—ŠÖæq§«±û‘)okyÖ'½,yÇ®´¾^ ò®ÆNN«Þè•( }uU&h$z¨…+ÌÊU–|¬U$R­[ye% ‹<ò©V‘Àj­}½ yhûBö£×‚]‰ÛŒŠÄ’i~¯ìX¥3r/ÄÐngl'€!mN±¨È+‡0¥ÈSgRnêLN7”B¹û|ÆÑyJa&aðÈøT+¬±%‹‹hNà¯Î%Kè}½3’<•¿G»ßFÀXo$š‰Ivœ7ܱr (°O5ÓÒ­„KöâÌëÔù/×9_•©ó`L½Ì3ŸWÞÐxQÙÞ:/*[_äEe‹½¨ls‰•m-õÊy^ÔîH§vçó×(áÔï¯[¡^YçW(õoï÷W¨!{Q¡¦\âåîÅjÉ¥^·BärÚÈÓgÚœ(s“WÒHƵ·†^œÚ[K¯\{¨®½uví–ÂP?ë‘BíLX5`ÕìúÙ„¨ŸÍŒê'›ëç ú¬0ÆR ~¶Ø_¦][ÁðËãIH]ÊãÀn/ŽˆéÊ”Ý^¹ÏËóGüØ~ >ÒÿT¼á —U.³dØþXbU.±dÔkMˆ`ǹÑ9¤õö\f9‡÷ßàí¹ÄrŽï—X/Ð<ßôüœÐ9{»ÂJYÇÊ©L”•¬ eÜ oWÑ¥[ +×òŸúaüRžG©fQ©¬„7x¥Æ­è`™òí&[<ôÂÂØ+½KUƒ>z4T— =ViÒ[û––J‰_å%œî$®Ö›ÅÒî¢Z—“(ñBu‰}ÞÍSqÙ`Ž¥VÒNnµ3زWê3§ÿ6\Ɔɶ}(jt9G8ûÉ‘`ê OÙUÎ|=a•ŸF¹@G?PJ6YÂw.Ü>a+Òqž K‹"RLëÒ"á¤\®?o¿Å­Ûf)S×érNØq^°^×s.ýœ‰mDâÈŸj»u¹MœR»ŸRû@b»Îr‡î¬ûvÙK´Nø.=ø‹Ðê-»íðÝzà?ºÿ‡‚²Ë=z…7L Í(ìž&ÊϪr/¥ ,6õÝARñuU•ûõ®â÷ýÄPÛ¼ä\ËK‹«ÍÌ׈ξ;õ2;õ"ñ,Z¦D`²ÿmÑ-¤·ÕFzÔ—yŽÐãè_i_ÓãØ_y¯é²^l0iÕTÅä=bk„4ê[äˆ.Þl)Xþ…¸ Í¿½Ä{ÝeúqÂÓPfœÐåq={ý ~š>¾›}ò¯Ì3ºàìÍ›"ÚÌÖR;Ô¼Ô5)f2{xNlÊ#ALãkƒ“I7¥âs’>E><¢U¶Uì#"bÄ.—ãn9û©/c·º§<žY$]2`pMFÁѲDñÊ"•å,ÁYáRž%çj½¡UEp‘Éçâ¢c£œ/øå,Q¡&Ð wó³>}ê+a»­˜ ®¥”ÏôdF,#0­%WˆV¼Á¨¼ ~¼6Å5ɶŒÕÈlý_ga'¹ŸK`™?w@ñÝCM®5H¬+è_ˆM2B4c@+‰îoMä7M~€RñÖ”ÅâäÁ„ABFÄ€Y/0E¬·\ËßDMûÀjgù/Tî±ÄÇ-×wù±-äFl!7Z¹W°··X®Ãñ]1¨£–ìh ¨®•ajw j_ êx™üA`MQîGÝ*ÙPû¹‰>ÏùËW\Á¦·œ(“?¥¤ôx—l@݉£RVIMšð1´Àƒ<³ýÁÿâl,ý Üß³"¸ûöGê7Ç,ùi8tÒbe¡Ç«‚þ¿AôÙZŒc~iÿ‹2 [¶[ZÂ< ~ ±ù²ŒX¶[ZŠ˜èîLN„³Êê„%§ øÑxbx †#àÐ)$®gz ÄltSor³ÀmèHŒÁm&Æ·r¢HÆo(l;ÂNYr‡½oz*¾oº–²©*¨±¡ŒÙή¬SȽ"VÊ}Â.æ¥X1€ÔCqRqˆ)¯PŠÓ µIý7D4»”6 ÙÂñ¾ùwCt•·AQ„ÉjϦUNå%‹Ï'+O[0åíö(NØã8aUŽ_àË1Âú`›´1NXlw÷ kŠWÀwvwÏ8»»‡-øW꘵H¼Qe¾³â—ÏÏYŸ`ä•Q¿ÂÝó#\Ú2$Øæ"ݦÊ*#°8¸ œ³àŒØ-Ð^5V /ÕXö;ºç4h:Ê4å#‹  éŠMÓ…V4] šàDSIÇâ$5»$5«²EœMÒMtÁÂþ²KÒ8Iwã$ÝwHº#é!H:çñlºŽó„C—ÀãÌãÿƒˆÉîŽídüœãíÊŸêé ?¼­+†‡+Ÿ*½[»Ôj=\ÆKñö:Ëc·×9žÉó<1’ç{b$ó¡ÝÉ8«AàZŠ¿O1s~ŒˆÍ.ìN#€ (±o W,¹Ýc—ý›XÙwõišr½úûÀp‚1œÉPNxšÅ²‰yÊŽ–Ÿ…“Û0 /1ÅóË–}ÈqÆCR2•â,0‰ÓÒ̘fd*ͶìŽþ Znzìþ{ËóíNxÎb¸Ôrí1ïµß)­ü†ý’ G,„cìÊOÕ¬FÑóa~ìÊåÚ¢ò‡ù²Iô|”þ@)”/¶ iq©y§«@q‘W6:ì‡ãs{JdÉe*Ì…?±ØJò-¬VÊDÕq–pˆXuíkxUpº¬ûƒ,á‘×þ/goÕqäO¿kFóÞvâ#IJ#+ÆRœÃÞx“™ØCœcF£ˆ!™Ì&q²‰í$›d7Ì}ß7HÜ îû6`° <3‰ËÆÆÜj¹ýê[ýÞŒÀö~þŸÿç#Í{]]]]Ý]¯Ïê*Qq½-o¶œO}€ã°ŠS÷Ä?|hù×òi£ ˆ¯)ÓÊëe/‹Š9÷Ç'ÜÅK¯«n€xÂY8u—ÑvWÛBÕ’²¯æbÃ6A?7?­õ®ãùÐ€æø –ƒµòëm“éÒžAÑíz[9T«Ø{'ÜÙWü$~µ( h¯Éa8œ¾‹½$ø|WsLšž¨¥ª±çNßÛ5PWqHƒèhÀÝù·õ5w·vKqßÑn)nR{JÖR¿î²j+9)6æsˆ€¥=‚ðÖñ¦xí]®4]újP`{¾rX£ð”–T>B×s íAðT´#M;vÔº­.–’ 'ã½ƒì “:ÒøœZ’¾¼p^Kyáð¡{wªüíêâå%ûZNûï@©¯{¥¾®É&-Uú3_Ïцy˜ëe¨Ž}€—q]øåî~ü<'ª£~´-ö´ÖFé<ß­Ëáúׇ Z«ÒqþR½­³»_ñuÊ] (f|ÔÕœD#]­Éº«§bFéÚbñ2,é1/Ã̽fáldŠóøZ£r¦Rçó—ö j”K–­+‹v£q†" |nÄÌæÙzº ¯tT{ö[–£ù s9tk’XÜa, æŽvx|ÒU[Dc]õ%\Fc¹.é÷Wç¿\/—è÷W׆\Ž2š®Ïã]Í•8\L}ý×s |5c¨$«õT˜ùò^¹† Ã©t{å:=3(ʵr½žN°zÌâú5=U;›õ˜Q f©,¶˜¨ŽÛ'Ré¶ê˜!7å(Åb~wÝvõíÐåÛz ¦ã†µ‡\B« b¡3œ ©<3ÍyÁ—ÖÙ›%'ºj{èq²«¾îš’ѩҢ´OPTv¬—{HgÄÉ~½–äßµÈÁ®›Pñ;ÈCzmür­d.çäZì]º@t ±(u}_‡›çu^œõ¢Eàì˜îJâ1ǧ$òè€XôI+;ª££Ž”¨'—'Íå¹ä¥º¤ó~T¥ÁâØƒ}-ë= |µWô[¾Ú«ú-_í5š TMupLB_–Üž îýX¢½Êp*ÅêâïLô!I{©Nö5p1–P•äí¡¶d¬µ`œ(] Â'Ðÿ©Œfðõ¥Žß%T@þ4Gà´­WPw ³JGÙªù´­Ô˜µîV~ïî~ú @Bvª«o6òtW1Oy¡*ò".òtã–"Ï0n)òLã)9Ûh»·èLW9Ï n½Šz¦…ÍJ¿H•þ‹tCWc Ñ—]Í¥>k­%Fÿ:xÒÊÔ x•KÙÿÓ½>ð ÷Õ"Á‰_Ê!þå: ƬžÝí¼ÀW„ ~µ7ŽÁ÷h †Ü`ĬX¤¨ò5CÙlËÅôl“‘®¸Â\n6èûÇË]bÐëF:º®8(]W,ÞJ1—9f›ŠÉ)]_ìóbß0 ïÏ(±ƒ-ÿÑÔ°A*­jÀ–Ô€o©Vð¸Û ©ASÎ5¹î’ñþÁð†bZ¤¢¥^ b!FCÕÃëË~ª‡¦¾YvÐpG@ÂïÜE½¿‘Ì'REgiºæ5 [ä|Ï =Ðmc±|t{Í<ÃL Ü è]—ß»sPw$6DÀd„xÓǘgüâ·Œ†cÌs]õ+ôø´«q•…üÆÂa]ÇÞFg/2ráV¹x«Œ\"¹b¤h¥šWæpáÀxkÊk†k À’× 6^ô Ëù®&FÌOMI Qúv=¨E+© ‹åðä%‰ó'z–¤Q›Æ´ë†k`žË{™œG@„•ŠÜ˜Ù³{‹¼Á˜±Ü¯ö®kºæ 6å`ÀÏ݃ê±)÷רƒ 7!VöS3铌± Mƒîp3³É*ƒºÛr1–VrçÈQf,€Ñ“wþF#ðœ,Žuá$µÂÍ’¹-ÿ“D¨E WN2½C—Éò#÷ëq¦šr*Çs• éd•™Œ…¼o£^N3c!EžíéÈ‹û…ɦ[1˨bæªú >îÌÖ‡¬11Ƨc¼ÍeÞÞuy[ˆÙmŸ ff%÷›‹yjLÃøbvq-V™Ü‰¬£ï×Lõ)æ=¤eæär _ìÊáfÛr•ÝTœ*ÝTŒ½þÕfšFR_Š£×˜érÝLÑ›‹Å+õr½Y›Þ`Öv¯™¸ú±µw¡ÄÊÑ-îÖÎÓmWrÚmF_wa?m“諽•ÁÀ ·~¸ÒUÞÝZœßå™Ä …5(è­2ƽõÃÕ®ò±èE;¿K8ñ Fšü"_©ƒÊWêµ®òß(å5ìæÐ”ø?nñ•úäçÜ«ê”õ•:)¨|¥RòßQçðb3_©“ƒž¯ÔkØ]ÚvËžë0ÿ.ÔŽëØ °À1͵2®SƒÍ<å]ï*ç ´U\©·]‚|Y-ô.?k“gÕÁæN‹[5+ð´  4Þè*â:-þ O³Óâpù'FÅÈ;ŸT<Ÿozþ‹[!~-'ë±õ£wfÇÅt\‡ŸÉøÄ 2õ”J;°8Š£Ó ¦ûò^¡Œ¼£ "ßZŠ4u»öSÏŒ0…|GDGÞ‘*y‡–L‰t2>9Øm2ÖGô:!ØmBPÖâu¬Þm,Mað:1ØmbPîÅë¤`·IAZ<ÁÅ êÈjGuD;»T]‡J7ñßåYuÛ! ÔûìŒÐÕd„®2"AB÷óÄT%tóƒX9²M¿º°ï¡ò¦¶EõáD4pcÙª±zDd{œ½½MÜ}Óö_´IL ’‹x€ik‹5ˆ}aÑ¡¼²°¨gq¢²°Aìk¿+ïQXt œèQˆ£… a™ÖÓ=#²Ÿ§ßjuÕóÕÏkxœù¶ŽÇéoýP³BþuxÈŽ‰™AlÆÌÄŒ ŽÂ/ Z´Úu#Zw“ˆNÒoEÕcÚWŒmÏ;~3ƒÉøŒ`ÇéA6QHã*$%j}‹ éÐ_—稆§FA—iÝø·Ï®º†ÅÓå= ‹zEŠ^íûvÅÐÂç4„zsh…:kÝz¢Ð˃FŽnì}"p— ³Õ½q Ä:­p_„ÉeñGö4ø_ ¢WDÿSƒè1þÌÃãK<:¾"ÿ˜R Ê—*fã= ©/Ç2ä^ô°=ùWC½øöâøŽb˜jþÍã1µëx©> šZãæóß›£î,+ò1óWéÚÿ@¯ÄüÉ,÷ì3©gï)¢C K‡* »½DôíâtéÛÅ4ƒîÍ{ó+‚–_7.h(aµ` Nl}ºA¼ý„¯ZpùðѦãÔ!McÊ,)g ÷Ù"]´°‹r­½¨nß=˜†Ei|5``Äм^ð ¯>hn +…œ/REƒ"ª¨­XcVÀ¢²b¦»@¤h€5Øõ^¹ˆÏÅ[|ÞJudzíaJ¢ì[C¡ Ö…VÃ]vpœ€#Š º`½ëò~âóå} íñu„0oO¿ 3G1„tÝGz‘â’n½†ê~› •USëÖ¬ Mš`j†ÞÙvÁ–)ƒVžnl7Qÿ©ú§©©k›^Z°sèÛÄÆchD;Jaýöz"ÆqzŒ.1Oœr['é1"â?E‘‘ÀizŒŠäœJ$H3í£=e½<–u+½½¸2ŸEÌ Sž€Wt’Ï“"jv4}•&M°OÁës@žÎ€r䀂²A€S;ï¢À”dOkû*Q9ׄ¼*”ucG^n(ïQÆ9Ð9tCÈ" !o6À¬‘¼æR¨å¿ ¤Zt@!Mèr™¹ø®âÒ…;™ïÍx¢ÛöbÙGÛBó8 —[?¤Ôrkr°VËU3·rˆkA ÉJðjÉͽGxxM·a0 aÞR™à1ãžúÇr8”_Óê8åÕbEÜ៪E.—¥|oŧwÅ/·«aÃnÕZ´_aª´_¡àÚœ©EûÒo,WÎÒRr61.ç-9WƒóB“TÔhÈMp¾¶%H5·%D8çö­7šäR-ˆy‚ÙËûeZÞXÔbvËßÂΓ–ÂxHóÎuZ m™÷cfpBë%ÅŠ)ß ¼["ý›KØ®*³ÒD*fr5¼MÌñß]ÍEXÏx·Í'ÉN^éîbÓ»Hbžº­éz“Ü£A¤Wá¸=$úˆæúç=¢É£ZªhL䦞!åõZL«ƒzŽn]å®è²Æ½­Ûù™Æe­AŒ<ÆE´´2Ñ{ÒcBÄèE‰sœ.{é©ÞÄTo=ffº•lŠ–é‹ý_-÷|ˆ03]-õ+ }Ã@Æt;B¦Gß)¦š|§X 8BϪ:ÜéZ@ŽÓiŒ°äx½¶  vtÙ´¨wÇ…œZu9Q¯…ÝïɌծåm§)ºÂSšV´n\À»6Uît=óS÷!@~–îÄ¥‹dqÑ”ˆ2¹1›=h·¹:Ôöª:Èzé ŽB-Òi  BÐ ÀÑK²áb¼˜#)å§54—Òï¡5ÖóvõCëuÜfu¹QÞQqG¼®¨#ÍŸhúôš®îp«›¯›ôt|ƒ¿"¯/\y ]ÉÍšdB:û’:è <†G4Mùàm¼UXX›Êô.©wA=¨×r’çéýc7É•v·Ü'90wã¦rÏqR »ò´qY%jÔ¹Gõþ™<,y‰á/î&—_iÝ]Ñc~fùª\H-\¨Ék:­‘štl»¯ jT«y2÷nrš;ˆ VHëïa³‹µÁ†L«ë#¢Ò„¢}m«¿*{•úCŽà¯©þœîúsþȱ5¾Q¼š7Gr”‘±Æ7Ú`k|mБŒ5ØÕÚÐ{Ó¼øo›£ ×ÞÞAêFp×<Ýu×<Õ@ Ös ÞãÌ7²s Þ€òœBpIæ«’àQÑr¡¡½§Ex¬¨—‹©@C”ù@}™¡vN ¹Œµ°Ý½œ)Ãh 5æJV¸¶VÑc`ÿjè¾×ÆLÃFÒ*”']Œ¯kµÁø¹ kÕ~‹‡*èztµáZÎGA—Ø8¼-¼…˹Vºñ7s§áÙŒ°ê¹d; ¹ËHU´[ÖŠu\¹W@Ñ}SPKBÃݳP'“Fš,êeʨíéZ.®¨á!§ ãµÅÊÊ£ÜÖö1ƒš©ÁÀQÃýÒŽü¥UÛyÇÔvÞqC3ÜôãjG®5 ~w¨Üén{Š)Bm^¥žÆÒkA!}äÏboêS}ÏÞâO–´¢™ô㛂ðÏ~Юnÿ¢¹ß× yWHÒ@'ÔÍAƒjìI ö1]Ô>&£â1+¢õ3e?3U4›{râ¶¿IÉk ô*PH¥ œ*Öã'Z[š¯^‰àlN¼žY¤0Z箈:·IÌ „…ÂÖÌRìÍÌRlNDÞÌïò|b¶Zнü¢£Áí¼Û|Oã܈Œ!ú·}1~…~<™JÔåo`Ä+h˜†ù;DÍc-µ4)p²cMЯºPÀ™Ìoý¤äŒ_,4»¥‘ОÔL_ÆgkÔbsf©H¥NÇë‹»Õ^‰¡·Ì`}’Áš‘wGß!¬HbÂ:–Áú4“acPÞÝEXe‰nŒt>ƒt9CêzPæGwR4±M‘º’Áª´=R °ŒNVyâ)Fêa{ê<ãmÔˆüJt?­µ™Ø©HM°±0ÎÿìÂøÆÃ ‹N†ñ(œhÓúeã¢Ônx!œàup‚—Áô;ûÛzBlÐoÍwLú÷+p—Ãÿ…ÕðGAù',†?Ê?'cVâHP¾”ŒùåË”Ï$;@kã$óÖÆïvmü­? ÿ#ôÿa°ãûAÜÝl{kdJ|Oô@v\Akä÷ƒóîíUß´LÍ,ŽÈ;¢'¨úº%>V53Ýn¾ÉÓ|Wk†­kþà·—Däã””ßeå¤[vµ~ð9»Záì®ÖL[ãÝJþ[*çï›íjÍ[V¡¢Ý&z°ù®ÖÏè¯KŒ÷UŽÏû*L«ð³«þSañ½ò…|9¢ÛˆÂq:¬ýºÉ6¶ÔhœeËç(z<"D’ðÙ8”eIøbHœ Ê(¡Ïµqo8xÿC¼þ+?„ß [Ó9_¸·§Ô[ȾÐ÷¡”ýE2|5è“xÇIäw<Úu"µâi™Ÿ%Rí©Æ¢›ˆ#3]"³@dA–W8øäka\ ð^^”ÍÒ½jšŒŸA–‹9Ë»qÉËò’€~R*q&HK8ìÑd…ŽÎp-o@â¥Y~ÇzÊ8c59 8 A9YSüNÁáð²,‘¥ ²Þ@dy–ƒµ‘µ,"¤Ô)l@âÙÄi$ÞC‰Ï!ñÊlâ^⟊'Îå»H¼*›« y•ŸGâÕ$¼œDôðÔez`ø/Û{ëÉTE´oâ|PöÑUiúA7e­éœvH:Iw½ràäycŽ˜¤Ó<>™‚†<Ž”ùº ’¬µ5#“@’…ºë¤c¡ÎN:ðX÷Úb].ÖÛÖË¥:ä!ŧÒËuÕö+ôêYÑçT0Ík‰6$k"6êµîù®âq2\ÇåvX &´Àõ¶ 2·ðs±4â;¢Ë£ˆÛ`ë” qçà<´’NåE¾ØÇ¬3ÃׂMba¤ž qÍæA~YÄG3Ï¡†â`ÏøÓú7àTa¾0ÓHÆOÇxwld¶ ¡ì4ÛH>€œæÇîo~8>q§ó@c“-¨¦ï-œÏÐïú¶ÐdbÄwÅCnÊælAßA6|޶% <໾ÎÀ{<à)fˆ«î41~™?¼­,VïºW¸ë8{‚d¨óc’Ò¥AÑf‹ó{’4m³ ¢ý3¤é‡{@ÌŠ‘…ù¬C;Ð,YÈ·eŠ–GÜ«2ÝFÊÁT§‚„¶Œ ~ á`üPq9̬ØêÏ/=Ö}à¶eråÙ¦+l³M6<öµÔð˜}>÷Ç”-•_é«6vKßÌ&Þâ%Þ¢oQ‰·¨Ä[Lù†—¸«›ø-Û²9¿@âÃ^âÃ*ña•ø°JŒÇÀGæ.–£³<Áföxæi<Løü)#°Ø‚X¤ŸÃøqù›êG3b7¤Šð ÅjÜŸÙa{‡e$|í£Go™V â¿KwuXv<,L.vr‡öy¡·me_ⵈüQ¥Çw0‹x ÜÕ0¾”PQo("ùß ßPØÑO>‡‡ãüßåWî=‰>6PÁÈ;¶7eß›™·í´iž=ÈÎïòëD_Ån óŸ§T^O]}ÐþFã&ZPRzü9)_ªXvÔ Ãl┸ÿYt,7W&ãm¾T÷,ÔˆmØéjD#=CVÃíü8ÎÙo+?K·qK(n$æØ0ßù4"VyóŒUB®áxÏV†»¡PªôÒB™Â^+žÂy`*1SèÕ 0¯¡ðm# U «ÎûZàt†½¢†rKå+í6pHÛ#ZJÈ]¢Âµ¦½›òH‰h¥]tò[¥•6{ŽJ‹Úd|°Ýº?N,¶<¯4›Jæ‡'Ú¶±jƒmùž¨u•ojù%‹~ ¢-j•‡C~ˆc¯øÂcl‘÷}á“G8É Ä²VaW¸)k›_¤¤´'Dv{1Ç7çÈ3Zå««”F#tÏ‘»m=‹£5Îj¢ºMi^ÆÁV¥&/‹èŽÖw´æÛ”MðbnM^îmÊ ª¯¹ðë½M9^Áo¸ð&Qñåxª0¯Ô¼[–~ÞÅ¿ù–eO-fñ-ËZï–¥·,qÆ"{kµ­f;H?ò÷Õd_š• ³‹¶DŠ^È~ZmgQzU×±³×_‹^¹=Pª¢ƒ5ØChz9ÖÆÎþSb½Ø+©mËC6¬â/Ñ xN˜îê› 5ˆ­±Z—m5=Þˆè59 Åá6MQSlóaôZ2zXKyŽÇö˜‰!4¿Xg&†ÚyAáIK‚#m–âx9‡¨öó/ãýZ”ºÔÒ~~Qq!Ø­¿Ÿ&À$|ì3 Zôò—ຣ­|‚=¾¬Ô¢Oø„¨|¢ò‰:¹Z‹ v¤åsåÏêå­¶h[>vÖj4Œa¹Ž_hƹ^K׆ßö ¹QK'KÓ~Ö}Þ‰9¨þU…wù5¹™+³¶ÛƯÉ-˜)¿k›yA»…ªƒÞjaw£°»é]z¥ù›˜Ïø}»©ߌˆ$=ÞŠh{è±=¢×ÓcGÄØ§án§ù±Æ÷W?Ñøþê1 ·bغ?ø“œ«Ü AìàïŒØ#èñvÄ©C¶C÷Ê$UÜ6¡,Ù¦´è6¸Þ"¾õÞÊbX ¥E@ų²¸²¸NîÕðÕîŠà«-Ú©S/÷kèAøNÞA~Å•[*ÿ!¨£€Éw˜Þ×*à‚ëb‹êtüR‹jà| UÔè2@W2¡L[:Îöáî+ßN á7tÁÛIMÝÉ=¥©;¹%êNnHjR’èóÜ\Ù¨ÅrcÆ´d|ˆÍ—rÏ"lRx¨Í·r?åfPsÏ«w¾›{Eã+¸°Ê4Änv97G^scLÐhv;7(opz” òÐä†.·€PôУ?céÜøµÒŸ‰ÊŸu·eO=–AîÅï µ^›¹ކ(„δËÉ4Ŷ{«ÁH=ÌÀÞ,(ëÈ­rœûRÜÊ0Î&Vªß°,,mÆ‚UÈw„~K‹8r¤~K‹Ðì8¥695žƒ¸Ñ€Ô™±P͸€Ç„/w,T€ Ìs½rœkÁ6ÆÓË×)-èö)L8Úr"0K˜Ì-lø†úo|ÓX]¹ž¯-Ï =õ-1S—3tu{y¦Žâžr‡Öv{ù4zùGÔ±6W—sõ4®4+Æ^æ<þ´Æ®FÞ—Æ™Ôñb÷>óBVÅ=l+ï“ÄÁZݽŒ¹V—ø®† ·¿DÜ/n‹®îzêr«îmÛô§ä›úçÞü|‹‘/äv]õ¥;q#C°|Œó6ßä°aµR £Z¶0ôDgV«C‹Ýq9 Hýk½.ëõæÝÚ>ýóºµýúÍÝÚA=íÊex7õY‡TßßÕ“ùè óÌur¾£&,ÿ=ñ3¦>6þ»Ä={qmàóM»¹‰Ñæ¢#6LC¶j|¦ƒ¸bËbÌ€p©ôcÛÒmçœðY$MF|ÏË_$ãSm¶|üÞ:Èç!Iî‡zïÅ,οžÙ¡ö!tÑö{¬üBV‰¼'ÀʇÌÊGøèDªÀ¢¦2ªc~š‘³Yps”V#“m^‰"’®Y®Äd›ïN¶ tÞ:¡ÞÙ0×IõÎæºNñ{û†»3üóhUݶ} WE3Á7¿„ØLpû—øò¨Üù%¶ù7Ù&$>}ŸlÓë¼È{™¾\xåš*j»ç½ÕIV‹XŽûÕÿ€¾rêfy!èÖx-﫪'xۃ虾Àà¾ÀäÜ]£É(¸ÞTt½iíõ¦ŸÞh¢°¼ÄxÑýŸPÝc›è©ÿ£ûÈÿ]~“±Ù9ÉF"ôÁÇmÜøü¼>øõ5–ÿÎÆlYájŒV cÑî„q’"ð<–—©®–Øù¼!z‰ß+ƒyXíÃøïf PvŠ©Þ4MÞʳ ×iiæ¿„f@lZ—qžÎxÌ{÷*û˶°ã³lV›˜Â¯ñ³·¿²7ï^µLˆÏUQÕüª¢pÖ?Cý•YZ*i\2p4y†é?úK¼mê%ôe+êØZί©nõMú™0 «ø•¡kˆ_“žkÁoV–?ô¦`§¶Š†á5è®%gô5DÌò¶´gé¸LšJ¬±q“ôÄZê¯ØÜ-ë–™äÞâ†.+ êÛ'Z"ï›w`kv-y:¾¢F²-Â#¼sˆ‡ð"ª7#ï# ç½Ç×VàᬮhoD¾jxƒR›¬x2>¡­7. æ /ZÛÖšþŽ](ƒÖ¤Ó Ó®„þ†d¶Ç ²ŸKÉÈëŒÅ’Íp“™yOBÃËཊ´ë€Â_ù‚æ&óçAyr´Á¾£Ò_à|N»ûûMM9yMMÍÿò½¿Gšš(ZNÂñY[§xu‡û4r†‘ o²Ù¬ß9£¢þ+ì ªÊ Ÿ¦>jž‘|f’E“<$Ðz 1Ð’»²Tw+ªço÷ÁLœG5¥¨š©Ë\•ÜA׃Ô~óæÏø }Æ)͘¬»µÅ¶ºõ›pÛé»}J4™¾òàw…Ö –¿†¿ò xŠO³[â@á ½.²YW¯ÁL&£íÐ`íDéë¶HL·ópÎÐh&£_§IÅÄŠñ+‹;~Ý hy–’ Ÿn—.µµÄ4[^df±L‡–KÅ‹‘_øl±ÀÑ»¼br‘ט™d|Ý£ë&\(Í  ¾°ÚIêá½Ó¢¼'¿·ÏÃ̦¿³_æ¾>Àö+í†ãœÁŸ`ï6(êö·ÀĹbVl`%U(1Û–ƒ,—“nçŠåFû´¸Õ—á&K¡}Zœ˜cËáˆÉïöi±Í`Oí­ø‘ƒØånß0‚ÆÏçgü÷Ë+ž¢”w8ÞâÊV`ÜôÞ™K)3m9VÊ®ÚfÐò_ãqîÍÖÞê#¾¹\<öE´ùôØÑÀÚ[ÄXËGLæzKηàÖúçñ Å¥#Ú‹é¯ÔËü¼3𢠤UÉ"+U1ªå26 µÔJ…/ûä2Z£_.f½+èõJ1¥^I/W‹‘b­•Ùþ£UÌzš7«Í Kn°bÖ×G¨=,ȶsσäkäòf®ìkÅÔD¨î×)y- toµ ÆÖ­ÎÄàKë®G­·¨85/øwàl-ØiÉ·ˆ…kÅÍŽò°JÚ q1éLe^t§¼^Ì[T»,>û«åL£ùu`Z5Êìv{DäL«âˆ:S¦(‚¦0×øSìŒFxŸA~H·ÖÓÓu[*?²*FY±ãú#ÅW~¹¨÷£hê+ÏÃ;sGIjšEŒÁìçùºmš–ÿ´ý3l]‘Úö •ôPDH º‚Z#=ÞèŸÂÖ]ô1ì»ÿ-Q{}x>Pàëø˜QùXl´\K›õò¬U ;^Õhòœ•NÕ†oP‡ñ©•nG¯miS±^ùuj¿ VÌ`÷+¿ªÆGvQ…Ó¦í²•W–øp²“èÈÙù’:à3R®_œ*‘ºÒ϶ÔÁcõôKyÌéåg,ìäÑn¤Û:M <Ãõ»Ãñ~ØÈKå‡wÐz²%äT~…~ìùbdTå†ÂD6ñfÚÜÙÌðGŸÊ~Q® É™8akâ™h2\åe¸Ê/×P†›E/ø®ûÙ:Ù ¿¼ê¿u$¾îǽ‹½²ÉÏ#[{xætØÀôÙõ ¤Ò\,Ö¿ï…pCy˜Oô P[!ªŸ÷20À#¨ æ×fÔ†ÜDmèg¨ôˆŒò^ƲU¹+Œo+lÛ6ÕñAƒ7Ç¢S¬ðÚ&ÂB[/GDz? ª} ³jÙî¦a`tщ©Ù6|…ÇÌÙ6>Ü<÷=N2@cP }ÛÐ >ˆˆõ¹‘ªƒoŒl @uÓfk"[éüÖí·’éÄ|[¾Éç¹fHÆkl{¾Œ>é-nŠlÜ|ĵúHI‰¶# wÔ%œpÄhó°+P‹÷lƒív7µY:P«šªÖ{© €>“؇ó›‘Øïn"ñ®—ò=ïå"±ÐF É2ðFaÇ•-ž#šCÒ¬÷“LÜ›$µžtGõÖÐ,Oª˜S¨æÞŽNÕäåäO£=K¼•õüß%”j±ØAéëxå9žÎëGùÕè‡wåwùÏDŒ‘;_´Í2ÄQÛ,GXg“·YG໼Íòa eŒ‡ln@Ž÷^NÆ“6·Ã+x㽉¿À™…ƒÉøƒH“±‡˜TÛ#}ù5~övµ"û+ÄáœË·b¨·13”!›p¿¦Â‹ÁÇ~£ ðŽ-G³£ K“vH¾ ®jµJ¥Ç,5¿ò‚i ’ŒÌ&qu&Õ²hK6Éë*  [‘dT6Év$Ù)ÔhW6Én•Ðwd4×Ä7‘d’Ô µÔÙ—M²_%ô È,j!õNÝ©‘úœð5ŸŠŠÞ×üy¼±Ÿô‹ŠfkwË+©–4W°Ýž¤ =öŠÆ:–ßòo ¨,×”øÖj âÔ÷'¿¯á±æ:Ód–G#æ&œGŸuýpu|Ö¬|–&š¯k1‹»‡d¼VilU7³m ²- I¸á¦êVwP,BXQ¿Mðw¨ÇÊ ©{f‚hnùh¨yŠ^I\Æ9º×{ ÆY‡Õ<%E§¶ÇîIo¥½€º–(úx–°¯"É!ÏcÖ!M¾»oÊ×Ýa Mp¡µfÑõ6Í^Õe_vßÁ$J×|Cm®N äS£«ª^ 'ã»U—²PWJŒá“wÒX¤{ƒçr›”ùÒ‰àÑ^·~é¿Å—¾ËF,>âÉNsÅëæw¦8¸]gã'ÙÁýˆ; Б?âŸà2¿ƒ«ð—5@ ·ôßÈæí½á|¥GÙNéç3mlŽèGúåx5JE¡d¯Ð^-IŒ¢©£Èû26§ êl9ý&J!61꡵™7QCF³8#¢4[äíÂÖá[ØÄ™­ÃáÂÛ:Ì}ÁM[‡Ø')nÚ:ü ÷7mþBmŽÞÖ!ö §ˆ›¶áíô›¶Û¨­Ã*ámzû„Þ' ´»ÞÔxóFSó¿œ&÷âä<6àXÔHµ:š`7Í× xñã-¿Õ™ Úk˵‚,•ߨ+74¯H÷ÒO³ºûK«µÐôå+Øyl"¶—YtЊ÷.Q«Ì‘7 úöÚ¨wêÛ²TÛyÃ,ææÔ´DòR—*gF)wåÔ»DyÛk{6AóM—æç#PXíôäèm—‚†åþ›ä;é) ŒòÓœñ³yåÅ¡ö&ÙéD½_X|Ì ëo-3Ô²"—‘Ÿ— ‰àaQž´£)›Q&Ò)ÛÀ§ý¾ÀŒÓë]º½Z"?@ãVóØm{Ô¾Ž \¬>g¤€uœ¯U0Ö÷€uÆÃ:ÃCSÏ,¤þ㜨è‡jŠSg«™ðyÁ3ؽ6è\éè8¬‡¨ã JFûÜÔqì²ñßåw|Ò²Ç z.´|ïVmÅq&,ž-UXôÁ#‰Q… ¢!¬ý½|ta‘ 'FS°1¬Oåc ‹Î†cpße¦ƒû./6Àø†ºð²UY~ت,?àQó¾xôyÌÄãõk«@žˆ]lâHÃfÌLì·a«7f%öá”—_ªq@›n¿|‰g¡¿Ÿ£Eë¡R•½ý2WS·^ˆÆÌ,.ŸP˜,:ùè6¡P–—³Èß'äTLTÈO–O$ä3@žX(H`\,Ì"?KÈ¿¨˜¤Ÿ+ŸDÈ @žT(;˜_sÔ}8BîîŠ|w~í݇;fó}¸M\o-õ/"Úƒ&0ÇpˆµÙQV¼ >S ñ¢  ÷û¸Jï¢J:…»[ýÝ*ýc›ÄÏAe½Î)•1›­Žæ7­D£ŒÈ÷—÷œ1ô1ÇGÃcîwt<ÒŽÇ„ÇÌ÷ù±ÃƒèQ‡–z'iáã$k§lyÌäž°åq’{šÖ<$÷Œ-O"óm<ã¾^vpÏÄIÆOÚÉÒ+ñs;~Œô ûF„ÊW´-óXbEÛ±ã12T>¢mÑœ&FPøZX*¯*,ºNTAÀÞt`a韠<6 s¿ãÂ¥2ǤǴ±!9>„ê‚Áß œ"¦l99T[Ñ5>¢-/^§„¨DeW´å[ÊÕ¡$ ²´ó°‡4ÍEG)§SLÅÈ9!ÜäÞäK`â-bBî%ã 6ÓÁ¥Ïíì£"ú¢…hZpÖ–ï…°; Õ1TÇ4‡AoG6Ái$h%Û&mÙè&ØÜ,ÁY$Øé(‹ë”à:4òò6WíÓŸýDn„ÅãåÕ…EÓ¿Ÿ¨¦Ï¶)¬ý[ù´Â¢ã?ML£`e'ý»åÓ ‹ztJL§`ÏNÆå3 ‹zuJÌ@¥ïrtÍ­ôôÌÇ|?Bà¹$ɹ«(}É–„áÓ«¶ü“gZóšMK%Ï̦-_òÞoØ´vrß›l\'¢„ƒšfzÐÁŽ| mØšð²- ß\ém‘¯÷‰\¶ãC¨Óê¨÷ŠÝSc=qÐü×Qøƒðé ùM:Ê 'AÇ{ƒÐx¡¬r§8…ƒ¸¤XÀ¦ºƒÚæqÕ¼eÓc¾%ÔyL,¬Ô}Ù.ôU>³·PãïÙØqZ&¢ÏS/ßñyF½9ÏÛ@b#“˜÷ßFAK.ÜSÞ“es'2ÝÅlîͲ¹ÏcsMåÁQ#LWZŽxäŽGëJûÓðØý=ýlœ@Ã=›…{ã ïË–ö: M@ÝŸeµ¿æŽoý59PCŠÙÈ1^äMŽãÈƒŽ° ³="§{‘Ó5öIŒÇeGÃcß:‡ž4¦kr&›˜v¨ã7ïåúõÒ-Ré©t‹4¹„Ur³Ù¯ó–0ë4¹³ÏñS¥Ìˆ}GÃbÜäoŒøÞÑø u :¸švN‚Sñ)ÎKu²VKø(­t2^é,ò”°õ½šÜKÃè%»hÉ Eg#´ÀJ{J؆¬×¢î‹7Ü'tZ\¥â3èÈÒ¢é§V¾«%i]Uà£UZ¾Oñ“ø»¶ü€Þ¦:;cwØÑ©Ð³™Ùú1ø1ßE¥KÜC——µTEçecÚµäœ+D:UÚY ­ÓêAÅ¥vM“×2\ž£fÔˆE˜ß»kƒ=t•¶²s쥧ã'ÐM¼ïAüj€q¬ÇØ7Øì%ÕÙ8³ǧm²Ó§Ðã|Ä€ŸÞ ³ F+"VµÎ¶¦ÓãR$°O—“õôKõrŠb†œªƒ²)«õ¶l´ƒÍ tÅRi&-¯Ú±@|@ ò¦emÌŠt F8[Ïû`«–êW« oÛÁËI…T£LÐ{£1ø9Ôù ï”,¦Tœé=ï¶@ÝD¢ê–tîûÙ›ið“^»¹^®Ô ®Wéy+`)›÷W=cn¢ÑÒ£1†'®ë8õz=ï¯8ÐåÔìê—êó`¯³NÃeéhGÀŠ|ý3å:G³ßÛXaÕ-Ìz^{ZyÁhæ[.v l!lϦú…MÔ+ÜXŒ¿Ñ$wé1“+e7½Ä? ¢Q )kuˆeÅÏãS k!–ÕáOp´ÀPî¨ñöê©ÚnS¹ŸxÀ^5 ¹|"è(N¹}F´­áÕÆ*–³jK'8:¤‰7Œ1ÐÌaƒ&Ú?Èb¡¹sYGåÁðiJðYø0À§Vc›²ð€Ï øH½óÖ vpg3Ûp»"ØŠ½x\‰h³¼ǦÂ|“ýð8G— Œ¼-R ±Zläý  ¥ 4ž@ËŒ¼ßcKø¹F*¾#‡š¢Æ¨XyÕrÌp·pkd!Wx@ÁªXKXUè?«àjÜ=³©Iÿ}SÓ¿ššF45Á.Ú ¨b|ìhT¦×¸Loz5ú&æjDl7äöLÅVtí[ÙµNî4Ò-£®nËæ»t«ïÃN·Šøí€’å#>oûdƒ£+öfunt…Ïä#M¬V£ÐXI‡Ç8â.ߣ@)àL¾¯X`‚|.¡P£\Ù\ó^AΫ‚\…mUO\~oPA~†½tÓkr7¢‡™nõ(E¼j¦ÃŸÚ¬”Âynº)Ï>f3æûš.óp;Àt™ÿß{ý¼Äƒ  ñ k_¿“øféÕˆoõ™¦û9s`k¾+OK¼øeSt)˜¾:8Éaç‡Wí4• uz±%*ìG^ S£ Ì-¸ù¢zˆh{£çqÇ$‘>ÉãÁFS9ø ²ho4Y´ñ ÑÞÈyë›pϵ‹±™×"&nÎ^X[éq#âÔ›`“Ç›ñ0å¶Ð#·š©øâ/³y¿|Ãäá Ÿ-¡]vPÚ¦HÎNSî0£]yx0¨,¥]¸‘; ˜Š¯º¨3C3‘ðw쪃MVs¹f'3‘ðµ‰'ì6 D¾cB½˜íX%áx1‡:±X ª­ê(ŒîÖíÐ8&H? ÕA'G޹5rwªûÌ-†Üoæ•Ó'ö4ΓÌÏÇ®a 8lª"ÅÌ*×ö:ó£Í ¾XàºütË›»ä ªZù–‰›/Üj ÔX3cþ-·ÞhÊk‡¦?—©±v$aÍjíÓ[ŠÛ˜¥tûMMy?CêËÌÄTo»î6j8fl>#»òÖôU°{Ö€ü·Ï ùºa&11w›=fUW%®Ø² r‚…®/ ]_ë3B××b¡Ãƒ„ºþ ÝzT–™-ºA ÝKö·XèX,t-Éd5“¹!ËÜ6Ÿ+sð%I27Ö’c¬Ï‘¹±–ªj|ædÉ}V´,SÐÒ2wÏjöß  xPü¬`ÙòPV°b9<ÁU’åÀk¥ÝLvl´ÓLvìf²“‰T²sñ±•77iAÆ››) ƒ ª°ÆuÜwÜÊ’¨á«™ !Ñ^ç,6þvé&tX/[Ù“$?Ž[nkm}ÅÂ(šŒ3qP¤¡"¯ðudQ÷rÛ“:´q¼>þϯå¾þϯå~þ›$5[©íº‡P¯±P Ä¢ÚßÿÅÌðÿÌôó¯úYŠ£$Ń¡/sŠg‚;y²1Ôï.Ƈúy²ÇÜïhx\ŒèCýr¸WáîÁr“[˜-¦›5Šçð¡ˆÍ$ムæ-Ñ0£T0Ú%Õ±‹;£3ñäx¿g1c>2ÁŸ¦¦¥¥Á$ÂäÔzÔ&«`–Ú”L<ÍNóN˽(Í«|uþò™…M‰™… ¢w'qÐ_>«°àFb6†Î8ºeÙó5ÿ‚‹»”ªW™~Áÿk‘zQüZ¤_Ô~-j_Ô±Ûè»@uñj™ÀcÈcÚ?tHä¶€·‡4Í‘—üØö¹âOþZü^$&9ò¿j‰É޼áÇ[ü·^£>†MJ4ù“3 S6ÝP`¼ƒŸÅëHVÌb<ÔN¯Žeh…Ó7ÀÙ±'„E­Ô ¾Ïg¾”˜âÈ~pRIQ·ÑŒ^b\½mx‰£É!ô²ÉGbßL7•‹åaò)ø¡´ÃÑ%N>c· ˜rTà)qB\7ÄHѳ½>°Ä'žó *ñiÏø—øtÍ×àÀ¡Õ¨Ð:hí $ËŸÜO‹Ö»¨‰9´œL뛄4›·Óä À¦lHNô9$-}N$KðîYΣyLFSÝ<  ÂE§”ù/GJt.›h-q-U‰f}n¢OirlZ¼és Ç=6<#ßÍÁ´õ|6²GÐ씯y!9׋œ”ó9ò"GòþÚÚ ûÙ® Ê 8‹¸äׇ¿é÷8²w™ïhP²Õ ì ~DDäÑ *З6 IHDÕK/핟Sn)Z`Y|<QÚ+O“ù$ –ëdC0™­×TéGC”l Ò*—ç,çC—›ñ3Úvù™lËq6ç~&ØÄÏd›ù Î{äKXù­‘`jŠ*hbÿ”U65Aªífü̲?—Ÿ9¶âg.ç~®°òvâJbG®±±&¾êÔàÙÜq;Óô)ÓÛ¿ù½_4è·²ó‹Ÿí?æ;nc˜xô-ÓŽÛò”­d£ÁÎH›j´ùFýïê#ö&âè°&ª"™èQ«À:ÈÓœìEKNAF¦'çè^«·uòþ(Ž*™ƒ¨NRõˆlm`NóŠALÈSÇ2ÑÄóùÕâúXà<%®Š!úh}Ã}CJüC©ãü¹ouœ·ëúpê9é1¢ÄgßÈŸy»oT‰ÏÒ|£K|þξkÜï= Á\á°ÇU¹Šê©Úñ6R}k¹Æñj{P™\«*d¯\‡úH©šÞ€ƒ­ë´7­­-ÞIÚš”.[¹Õ¡o¥Ê‘o8iÞ½{Óžà“OÆ'µíø¤Ò!| dnð‘lyòjãžßý¹Mâ9>ðGÇ–4óñ÷R›6‰ç‘r¢ã8âçô×å¿Üàa¡èx—ÄŸÚ$x§àuV<æœ]&ôéä+(Ÿ]XQÿ@·Ù¹+C茿Ô8¤L&£³ ;Î.ôýXÈb( ‡¼3cB¸7:©¿H]^¦L—:£ =CY—½Bê s¨"©üCÑ4dY†ù,à»üóþþã¼½ÿ8Ÿ <·Ëï&ãË|öÿôïÉèb‘ì¸XˆÄrG~®VxIæ@¹2„]ÀBþ©» ÷Sù “`«0'*¥zï ;=@½TŸl‚ˆËKDF³ ÊU‚¾HðK }C†a˜"ÁoÝ¿eæËÌÿ~‘‘;¾/º,†×tùxSÉæö77ñßäß³¹ýCåÖ¹ý¹õyGå”ä+щn£¾Ò&±ÌÈ&¢BžÊ¡!ÏÞѰ2Ù&ºÖÉïò—Ä ‡fX({ü;<¤:ìáeòëÔ0_§†Ò C€V0ÚÈÆÄ\¸¨½õýjYðË.9G‡ >0üw×€ëÅoûþΆZÿ)ÿYà«OõtMéº6Zÿ7™N¥ã“JºM*‘ÿ„yÖ#®yÖ"ª%K5L,Æ„àtó Pí/\e®þ™ŠþB©|6A¥¤RSÎâ4vSõ–ˆ™®‡€´‹ÈúÉéøÈaR1ÓEÝA¤–|›Iå€ÔÔ’Þl6°7 ¹ïìP ÈæðG†F«"4Ê0f1Þ.ÊÏeƾOeòm¥«ŒRéËØà7)c½í(4TÆ{7Ó”G´èV§6XÛðVÇÈÃÊà(7-;ÔÕ¢›Y¤Â›±žÒÊ×9$ÖÑŠ¢:†-Ë?B‡¨^ÓÔ­l ²€^ƒ’Àↆô( æv‡“¥­N6‘lÖdnal§ÕsXÄW¦ÅI;ËÊÿâÈH÷šëN¶œ›öÊÿ†ã•ÆjúèÍËßW¡%Ë+[›H F…Ä‚¡Ür¨D„Àøìß%‹#GëTWi®+ª*˜ºå{§æ{¯ó÷R/'éµð¶ÈÛ«S`Ë—­ã2]¥c*FiX´ W¤§(÷°èMMyPП§G·8?dåšÖE½qbÔáoˆþmïú5ˆãÏûžå;wô{ây~—=¥?ß ö–]Äþb³Œh–Yå$­ûÙ &—*à!'†æ v—Ïã"õ‘ØBÕáÒ¥ÌÝ–«Ì¥ž¢¾)ä/Ó¥³J|ñÙ%/uÈŠ¶Ýsä¯a§¦ÆS„Ø4uu‰ßÄŒh™x ¶hj™üÏT|¯Ó±Á°¿ä‹ÔbÛ=(ÿ€b`½˜#ÿ«bG[êíÒsðQŽÚýj…fÿYþ9fE•]äK¼8ëNƒŒ!:Êâ¶Øðtzû*êHÿ>xžøß‹ÿàþÊG>UeÎÿÈÿåP¿ß’·Ä tÏæ­]`Õðhø¯˜I5Ê;„=±DÙKÄBiâlN‰ËÙm8 é-¸”}spÙ—æriÝ+g?‚þƒù ÜÞnkEšÝCÌ-ÑŠªË˜ÂEa((L+“ȾLM g £ßZ]ÀÒt;Ú& æxÎfOâì™p¡; (ŒBÑ<þ拸¿Û&“fŸZu®ç6þ¼ÒBî¡Iuë•QÇ«´z!ëûĨ“õp¹WŠÚêHÕ6kŸv®ÂÔA!ŠŠ ºÛD‡„j#C¾ ïæ1C5R½Ø¢×¦o_Nuñ!&!Il”=êúc‘êÍÚòG=BÓËh®Â„ï8J‡|q¶œC  =ŒFʹ$dPßñ#DŒñÌʰne“v`ýÒÍf¢æf3Is³™Q&'+Í©DÊQÚ—f³ª™Ü@ÙÔ"›eÙl^÷²y×|(›= ·^6oyÙl÷²9ú˜ÜáfSëÐÈ —zÙlŽ!›”M²Y‘ÍFzÙHF0ʦޕD7›ó^6¼lŽ?&/ºÙÔ9ÊùÊÆ–+ˆZ/(ÚôÖ“ÏÌÒ1àÐX³JOPÛ¯i'‘Öå6qî$ö:4¸Ðk½“ØçÈAè WÑbØòÿ „ª¼Š`ËžÓà¤üÇÚ,æS?Z¤‹J»NÎÒSø¤¢"E“žèÁ(Ùl]y^ÔF›¬å@²X1NÃ{šstZãÍÓõ{HHéÜBhR®æ>´@‰qÖ¹ä ÿ]þŽô—ˆCgº&³P^ŸY(Ï,“_Žöåwùg")kCÈÓü«¾ÙôQÎ.5BÎÅ]‰k¼¤D×úS¥ký¢r­¿Ž›<âÄÅB¼nðw£¹9¯;÷fG"y‹?Îu¢Ëÿ²Ug‘l&™Ç?~öžDÿNâGåó ‹tJÌ+l;iÝËk ‹uJÔPpp'½‡(Ÿ_X4¤Sb>…‡v2¦Šò…EÃ:%Pxx'sƒ(_XX4¢Sb!…Gv²ŠòE…E£:%aMTÏ» O4Î)ckV¼Ur^Ý«8¯îUà1õÛúyœËÞŠ«|…âÜêÁsȤfÊÆd|O´V8éd.I$ã§œŽ't¦û3Ã9¡Þ—½ñ/ªŽ“À¨Žz…ã68AŠF'¿K¥HœV›-‡Y<>çbÂê°%Ê»ž6£¤ï»ýø¼2VKÆs÷ãCÙ¡Œ+}ýøvêÇϲN\È ¹xïx Áï°¶¯H \"´WꨋO¥[c7ú׳uãÑmVÑðo¦Sám–.÷!“ÜyÑúÀ£õ€ËÅŠCíMtÊx;dR§œL™,¥G|„™ûÒ]sWEÅJ ß7=âÍWòLœ6œs^!~?f~ÿ\,! ë”K MöÒh2zÐlý Fâ¾·&{k€÷}5Ä ¥°.›Â§–˜DDDªÛA“ï¾e—Ž®¡l}uË6}ÝÑ,îU™f<òxü”yü$ËãÂ, 5¹<Êò¸Tƒ£$¯ƒ­b—ÇU7ó¸ZñxHñÈ>;>uäF江Çã&ðx,” å²ŽŒ“šÛkÀ€ððØŽðˆ4<.tÑÓLAµô˜ò‚ ãÂS_°öj2­ñ-°ƒ&çÎÊïnýÃäÊ+0R«P5C9ä¡ÔÅ”{€R‘R4½¦×Úxʬz–IayÄ ´éU¯Ààï^ÆNg±Ó„Î`_nº.¶_Ök‹ ÃñÉý¨—–?e Ä‹ÚN™ø O}J ÒËÙ˜0ŽDèõ>€}Ýz%\õˆïrJ+æ‡Y‘<8€ÿ*ê—i}(ZzƒžFé>Be§l’䨖ÂRqÒ#ñÉT,±*–YK-ù §ÛdU@áå}+¼ 8@#2,ô…[Ì£–:ëµÔYàÛ‘9œ!ï"+aý=ÛÃ.¶ðߥ‡@+Ä¢³8™éS3}ÊÞ,ˆÖ”äwé)TŸr6ÔÜÇVóKëçBPp|ª±¦L~—O÷}·Aôy\Ðï«kô»±Xÿ.¢¿~å$ˆWùd2¸æÈ¢¿¼âÈ%k—Y #\™MgJr_t¾»éÜK´I´ˆ=P}!7Bê†Óü2ù¢W<ì{ì2Ëö”÷u‡O.† å˜‡¨ˆ»a/B—˜Àãˆø"vú}¿’ñdü†)“¿I¦:‹Ä ‡·.þàOŽ—J†+CBþ&«BJa˜H¼Ë;ú^‘U¸'÷o0C›(pzñ±Áß& Ë·ôëAxo7GØ-òF¹š‡°OüZû½ˆ/*¹ÿŒ?cèjؘÈÏf3À© ðP¸ |7üK[t퇤ƒµÅSú=•Œ‹KîyèçKJ–Òãå+·OÓIJŸú®‡4Ë0W±8ôɺqͯìÞ=ûùúp?/úk¸nSÚ'ä«ì^Gƒ_:Õ­Éaÿ×y󑆼4ÞK··÷u£j¤ÆbÛE‰­6Zã-ZïŒÖ<±­§uo×ñÂwu™1Ž—C3H~S¥ËKøãµtÌ ¯ J¡¼î"qž¢Á%ö >Fj þgc8«E»wì“M!\aI f‘æ­+Äš2ß×aÎè®*—1Ú eæóº£–+4,,ïÂgµŠÁµ`+orÂ+J4ŠæÅâûÄ ú¬Ìõº)ÊòÎèJ·›z•º©î±w»Üæ{;Íçé=sq°ô@ãÚ2YÄÎ÷¡³E=œLÓlýê­†øü³W.öqr÷K*v·d|`ˆ ýj.– Àÿìöb†¡¿(‹7x­¨Ë”hõËØâ+»öSL†w|M“MUtW>qþ–LÅW•$„òpÿåïÄÈ€üçÿ7ºÿsÝíD·RD_ %ãCBáW©‡ìŽ©w.N®îã}0wë'¢ýB(UÅu§c¿Pöa”Ppj&' PlõmuBF¨E£ËnkÉ&èëD} ¼ø¬öÀН.S¢™ÞgLýR´g(Ü3„®f[r5Ë´~€¬r/9þIßBY¿Àc×—5<öh:Ãj,ä›vá!”~™ˆö =îK[Rý F>‰»+º†Å¢;ýuéMo¢_pÈFÿÜæCØíÍdc@.Îxn\_ƒç bâã¾ö´Ä¹WÐo¿{µöˆ`èßà[Kstù(%˜«îæRì3T]’ña‘AYð¯ ü›d|Àƒ³`×YÞ(€‡äªK0…JC5=C™©§1M¸\MÌÄ×4 tbXö#jcBX2¦#B8œ¬8}„"][:¢µ–R?Œ?¢¯Pm­ÇJx­ûõ¡¨· 55<×›¡ŒÉõf(°ê™D ç¾"1S­œÇæz+çI´+!ywttËü.ýDbbHîÈõ‘ŸÌ !Cl7°ö±A"‘RÄd†ØÙ ÚkÔ˜ÑW‰Ø`‘¨Uhç2Ôúµðò¬Í•_VÚ‘H(ñjáa ná;‘KÅìCXCEâcElHmDmú³^„6L$>Qh#[xv¦fÐ6£ÒzÚp‘8®Ðª2ÔæeX»‚ö&´"ñ;ƪÉ`-Êëß‚°zÖH‘¸¨ˆ-Π­ÊÜB~%ÚÐF‰Ä=ŒµºEVãcM ÌviÜR&¼=ÜÒwäÅqõqqäEùÉ‹øfŽ¿H"y#$O¼H¢Ú’'_Ä%ÿ†È */‹ô1¶È®˜Gwsìò%…÷W‰Ä’Bê§;i+íò¥……‰¥ÛIßj—/+,øRbÇu2Òvùr—Sp|'ó=»|EáýÞI¬ ð„NÖ)»|%‡WRxb'ÿ§vùªÂ¢Þÿ–XEáI=œ1¹SÎ`ÜxoCªNöùN ¢º“s¡SùÆÂ¶Ý6æ´N¡ñÏ6ˆér'<[¾‰€›8£S‹…ñ1³SÞÎxù–ÂèQñÿ{︨²oO´P€¨Uj[éC+­Ý¨mè6·¥?üI™E¥üÎÔuî›7wÞýýÚ;óf>óEÌYÌŠ`ÆœsNm¶9hÛPu€eÄv½˜=š &W¶7¡Ñˆ½ 4µò°} jjÚ–ûhZeU>GÛi.®öÏ ¥E¸±_d£%•µwÂò«žs1É­l>v^‹ZªGíOP=ªµ¬2PÆ`™¼BRã<8õŒ–ºR:ÈQgµ¨UÕÙ3ñ{Õó«µZ:ĹNiQkyFpÔÁóyšKl´¹2SÅŒ\t4г4tMhn¥­,MØëˆÝ¬"|YG”T íp3pÀ®=aÆŸhãš2ÙÆƒ™ ÏZÛCC¢*vAÂL›¾ƒ4ÓF³m~l4Çæ•C y6Uõ°5t´…Ð|›*¦pó¦p qwȤq4Ž2™ qXh´BÂ)ƒÆ) ¦uŽi`ös^G»*€VÚ#&Úû@ûÑÎÚ£v¼¾V ¥ÚR=ÚY6zàc\y&Ûxª=õd}ÙD:Yßs8!Ç¡X,X\}o†]Ç5ÃN³ìx üH‚<93ÛÞæ^ΦçÚ‡¬ïþ.ñ;ˈ“õi>â½9i‡h=õh‚ëX‚…ÚáæB8ˆæuà`C0{"ô­t1´_—ï3Ë—YEõLYD£«hh±Ï0¦ŠêzÊ Ž­¢ 9ªeWÑ„WEr|<-m&pÜ N›Tò”šòL®yJòL©‚c!‘GêÑjžèQN8Bü€¤Ùaƒ4ER† ó¦*Æ›Uh Ãì°iRl­Ò¶1¿]g~‡Îüíԙߥ3¿›¯qxø)6ù)?ÿœŸÂÏE“Ÿë?׫Р†Ù©ós“ù¹ÄÏmŸ;:?;mtWççžÎÏ}Ÿàç’ÉÏèª83­ú§üì~.›üL¨ªó3¡*Mb˜]:?“«v§)UM~¦VÕø™^Uãg—fTÕø™YUãgVUŸÙUñ¼§ðÓ$–€Ÿ¥US?Õõ\kŠÿ¾¦•€2¯ªvÙÚƒò«UÍËAUs¬TÍ«Òæ&IÕ\mp»º*”Lj¦¶®*7µËVZÏÌob¬—õ*»™Ã[«òÌgž¶éÔÐ÷VUS‹¿ö:÷Ä+ &;¶uùÆ6 #º|GuùŽéò‡|×ÌñZ…|>!Ç.fVlp[\•.1k#˜µË.1çCÿ¬â Œ ܰã·ÿ…ìÏ ”ϪJÛ|[•^0p±.èKômU½m¾ *¾÷zñ}ÐÅÓ€>êâ}ÒÅû¬‹WVÕl£Õ´6:ªÎúL®§Uc®gT âúb×YÂõ-“ë¹Õt®çV®—T£ù |QçzAµî´¤šÎun5“ë¥Õ4®óªi\g5 üj×˪i\/¯¦q½¢šÉõJëUàú¶Éõ1p}"˜k_×Âõ þ¬ÁöÙjtžÁ|:¿*óë«föðªqµói=üEÕŒtIgõŠÎêµjÿN½ZùþF5ôˆÍñf5ôˆ=â-v7h²û&»_¨žÝ˜1Þ‰3¿0f»_ÐlÎ0/Ò+^æ|ÁÕq^$-øBu}bÞ °· \6æ~¡ñ»ô í=ø¼/4/ ϺW~ÅGÀjùhÚè´æ Màu_€2ù_ÿø§ÿ¿€ “ÿbð‰q•ÀÏÊáÿ"¡Ä`¿ä ºÉéstöoƒ•9‘t_gÿ‘Àz«àÏcý':ûOuö 0¼Rx.ÜÝ7¹{!ÜÝp÷ Ü=4û¯Õ™»YÕÿÐÍ®®zöØzМêA5êJPÊ–õH†ÖËR¹ÕǶ¹Õ)¯æúP ½'=\ÃìIÔÐzÒcºHÇuÖÇ7 :ë'uÖÕY?UÃìQO×ÐzÔ3"΋€8g!N©Ù¯@œk5Ð põ× o|ߨA·jH…£Û~f?ð‹¨¸²k¿6€_× ·šþé€_˜À k2ðâšX¾ã®×A²š:𲚴¢¦êåµ½B+kâŒØUq“èuOMÝ«gÜS³TQS”=5i?çqÀFïòPY—ªÙŽpð¬MÔŸžÌ/4°£5ÒqN.Òkå Îþ+°ÙètM_tÔÄË]CÎÖ¤³5½Xµˆä,¬ZĵqVV1¯É=”_ú'¬¯Ôšª»«ßØ-ðõ×v¼ÿ¥ldBð5Ý<¸²5ÈÉsVSø'—†¥#MF®§†žÖ$ª‰¬Þ*xû9x;d£—"’{UÓ+2e}‘÷K!½A†s6zW%ÿ:PòÀÆ[SÿSjÁº±–ê9ý¿ý/ÕæÔ2ÌkÑ\Éà­’…;Àµó-¨ÅUò˜rkyã½)Æs¤K9äKÑm]½ñþ@B'\08„|NXä $ìoe$,ã„Âí5Ó vÔF«jéýi-µ›b‚Gj©a' Æ{ˆ5ªâRm=]K{>76£·n‹zªå`å\-9,,¬EgX"ë ©µTyEw ¼µÜï¾Poè‰Á»¿–»½*OèQa-œ*6—CÏӡŵ¨¸–ÏïT#”ÔÞÙ Ek¥‡É­±KüÁË~Ãà¨Ñs:¢Úɲ2º>µ#Èð‚5}2|’Jð#Þ%ñ®}€öOÚ¨¬Þ€°Ñ¨ÚÚh9º6ÊùM œÇÔÆõO)Îæ²¿T[Ç1¹6M­Íòþj£™ü£¹ô‚Ï.ˈw6š¸2sñŸÏp´¼¶ê9¥¯ÕOÙ4ë}5ì41£ްð¨Šçdß´ vÀò7£Ž®î‚Úr6»®¶¨{=ÿ¼mºŠRÂöצMnx˜Þ"ŸÚ¡íÖÚPoKÚn—h¿gOBjl ¥µY³˜µíäÔ Ud«ñ’õ¯yÊqîqVðÞÚ¸€d£ýµÅäÜJ4Z³ÐÑ:,´þh5iMŠÚ“×Ü  ²<ù Lþ×ÚéV÷¤(Ä9)JqN޲È[ 8Ó<[/ˆk‰b_rXã7“ùõÕVÓ­ÖÓ6ò£F95ã! á7æã jF¦#œKuÔîgF±>«M/$ƒ0öR>ã‹S¸Gs4’{¢¯¡Œ36z«åÂ,ð]¹\اÅ}×µUÉÒ>d÷ô)šEÛ!Û/èV>"w<ÕwÀìSÏ O©eåhtŸŸ ÌhS˜éuX˜™uÔ°ÃfŒ#0\Ì«cøI­C êp=l£…up¦l¯ðZ>à±&ðfxsÚ àã6Úàl3Ï~#Ïþ:ty~M CÈ3Î$p¼u°…{²f $ܪƒÝ%N˜`b}``}P‡Õ‘=#ú X'šÀïü¡.8¹5G}©ú’F)Ëó%÷Là_bû%6ÏqkÏ7€çI |ÁJ‹<Õ.ðº/±ÝÎÀÓLà-ð–/i€‹¬´ÀÓMà£>ÎÀù˜ßÏ0ÏÀg¾¤sί@ç<Ó¾ àÛ_ªž§Ðä,3á5ÞrB)f Z‚Öå¶„ÂÍ ´®!h]ZX—ëñ%-ª‹£aÖªÿ'òl­‹~þ¿ð´ó/–íui{]ÙlRèh‡v½»®7µãí(~ÿÞ­¸ ?£ÊÞº´·.;?â¨è¿Ѿº¾t°®Wƒ¦u½Ñû¹m©›º¢>Îð,†pö7ÙÎþb¹]—n0Å«6­nÊgº`¢>˜¸ÏLü¤]0zP×ý“×ù“âɬ߃¨Ýej…LíI]¸º˜çÀð-è¼44ð².½†®ÚèM]íDbfàDâ-t2ßThN=VèÜzªç:ºÀéku$¬DÂêz©G#TÙœa{{¡óª¥Ò‘ÿZÚlR›Ï#gÇb:]ûË9†C—[¶‘1O¡Ácƒ,gëÑÙz©ûêC€s’-ÐÜ´y®DŒÄZÇN¼¥T/p —ÚtKŽXÕS½©m²GÜ´ÉSëycpËùJ=ÕÝÔëlªÄYœ#=ÇßAò/ÊÍzt³ž¶û\ïQ<_J ¹SîÔó¥vÌ¿wëù¥»_Oõ{2"˜Ôs´`F`RûˆóµÑ¬Z×S}vzROžk*­çÓPÓ­z¾h¼Ìþ¼žÚhÄ-½éXU‹¤Ô—]×zÆ®k=úTžÀmôYÏ_V×f¥åÔ`B¬ØQv°LŠ¥I±ªçc$'§Äz£ÑiOu·I§¨ÎçgIÓ9 Jšt ÙƒfÅâöù‡9Ë™‹òŠ!÷ò`ËÂXr—ÄÊ›K cµ™ ŒhÅ–›Ù`ÑbÌj2ÚÒ’X/OPxTÌ-7ÁÉ‹¥¼X¯6Áš R”«Op–ñ‡ëŽÍÂ02˜ÁáãŠXž±±VÆÂ~À¬“˜S:ÄÂß…"—:B#£*”:wBd˜«à*ïlwyY«'be²v]$ ¹)…ÞŠ¥3±Þ8E¦êgc»“¡ ÆÍ]›· G®:úc¹@îòÄ+VuùxT{Xqà*þ%°TE¹«ÆYš ø{azDdgÆàEW9#]ÒZÉÿNkEt3Óº¿Ó­X1†K×+eØXºëK½ÍU²E>º›n•~à>xÓî†Ãz®TÙÙÍú[,ýÈ?›óCô$6=\4ý”?¼iëë2Í„n«úTœgªxÎWðàÿ•ê¹ç›ýè’¯ôººä+Zú«æžò¾Â³&ðaeà^.uL[x¿BùtÔ§uÞ¯¤Žù¿’:vá+ò•šÉõæÂW¨7ÃŒzSô}å>é—fŒÆ ×Ö_¥‡Á6]üJü¯^æ°çq8ˆ辨¯hQ©ëyn5Õ¼Œ]û óèÇáLBªÙB–ý&Äx`£[c…)FÆ×,Fæ×ªç!ÄXi&,BÂNø «Lå,ÿZWÎò¯iå׌õ7^nà‰‡ÕÒoÆ ÏNïfà™‘*¼F­‘ñGF‚{_K ”ñçÑ×ôèk4oÏŜŽýÚ«VM@ ?PÞMï¿özN%xN'HK*¢_ûbĸ]‡ø<(¤Ï_£©_@gA})î™ÛÑ¢úÂJÕ>nË’úè^”üú´¤¾ìTBß…”[ß+ãÒÒú^ViÊ×ÛdDzú>I\^ßÇÄ{ÐÊú±=äjA gêkбŒØ[_ïÁö×§ýõì`}¯æ°áFDÆ·óßâ*¡©õ†£› P ­¯w„Tˆª¸OZý}‘ç~eX«Â¹>ÃÅÀýúRÃÖ—ö¨>=¬¯Õ°GõQÃ’ö¸>=®¨a÷+g 6zR_¯cOë;`²Lö<¨«{ÿ’øÑêÖóú¨[*3r©[y\·^3¿+±UþYü§„½­Ooëã~*¢3‡G é‘éuÁy©r%Åú¾>½¯ŸÎ“èú#áô©~zøHÍ›7}æo ÂeZØäcT8óñ¶~BdDôâ²²ÈÈÈÊŠã Yj£ì8ÕµÜa¡qq°²2õ»:gkq\¬ÐïF³VoŠ3ÎÑâh <³ÑVo2Uûø€7›À à‹qtÀ/ltÀ[LàW~ÃÀ¯¼ÕþdŠ£2¿²QFÞfohÿl TÏo—‘ò?!aGã^vÚ%éÞ*‰pvÞ€½±Ñ¾ÞÔ± =cšÊæÞþ<Þþjs4Æ+MZJ––r°Bœ‚ ’à xÍòÎgÙÀ1t¬ì)Ï?@ñšAñZ*Š@3û›ªX™Þlà•Ç£o5P›1Žƒ0Azgƒ ’xþÝ@Ã\CÅ=Ó!3Ý3hä`åýÄwšzÈjÈzÈn¨z>@»D‰¢‡É e{CšÚЃÎrzCÕ+fÔ3zµgigÉ/f7ôƦ¬Osâ2†Í㘠UàuígˆEB"6[ïâ†j,g¡\X¦îêÿÁÊQÎ÷¬ì1Ëó”ÁÊ©†tø?Úè,€÷õºÐë6R=Ÿ¼OʳµT5ÒÇ5¢ ¼ÈP ÔV{6šÜÛïÛSÁ"+¨¢ñ&FœaÇk7&W; Ä;Ñ. ˰Ón4¯¸„3|Èäê®|·ÝW™váê!eÚé‘pu8Úàê16ö'òâ 1¹šÞXG<½1ÍlÌÈÆØiÌñŽ­Ì¼ŽÇøXÐÊÌÞÒ˜¶x¬¶ø¸ |Àçx€O˜À…pac*ð8;]ðI¸ÀÏx<€5ßÀoÓ;·Ó{Ÿ2—ƒ7éaàÓüW±úF^÷ mtýüâ›î´ù›rWض|#÷þæØiÛ70A·ÓŽo´Íëß0µ3AEj%Œm¨5©Ý5¨Ýý†îKºFíS{TžÚoµ¹vzj“ìTªS#P;'Ã{™85ÁÄ©‰\h›f7n‰Ñü&ö …ü›>Î M’×Dç#¯ -“|ú!P“î´² “›f§UM`ÿb’92^Ì “Œ¯ ‚=èÿfƒŒ×$sÙ s¹ ]•|™kL¦dfØéÈø„L3ÙÚmŠ­Ý¦Ú;nt‰Ó›"ø‹\˜Ñ4u[cœUøMRs›‡¾Mi¾äÕO{›v§EMa½f§ÅM™Ô“ÔY:¯‘Ê1I©MÔHy›¦nR…&©bƒTqSº$y5R—™ÔUʱÓ5*2kÄÄxœ™Æ«ž©PQ±4æžrdo™ÆÓlI×åÄw§¹ñxÒÁN ãµsÇEñZXþ!ÐíäÆãv¯I숩Œl:ˆ]2‰ÄŠâ颤kÄ.1±+ 6ÝN%:±:±[Bìc€Øm»l›§i9ßò¤ Ä®˜Ä~«[ø--–tØ’o»ÓÒoa¦h§åßjÄV|«[õ-ˆ} [ý-ÞÀ1‰]±«Œl6ˆ]3‰Ý2ˆÝú–îHºFì.»b³íô›Nì±Nì©û V b׃$ƒŸ¾œfªgˆ•±ÿ ’53$kF‹%]—¬YwÊkV®ç7“VÌ}Åòf8D¶Óêfkši\¬m.2¾7¸X× × M.|àâS™ .nš\\6¸¸ÜŒ®JºÞ¸˜‹幸©qÁ}ÈmpÁ}Ê}‹:„‹]ü.n9pî3@†ÈæÌÅn'óìÑXiNlÞ¨¡ÝàÈOkã5ì¥Ã³/Üy,^ÉÁÁßtèA³›#‡ŒH"‹rÛ”q;°ïä¼ ãN ÿIö>›cšÝ];•ÝßœJo•ŸõUÉÑæt·(ØéhsYtÏæìt¬¹OÛO4÷¹N²˜'ùΟn1G”}¶9LDLÙ°*#7Ót[êŽÆU±‰q»¹ªÆç·„ã«ÓmtWa÷ %ÑN¶³›ÛÙÍéesolUìǼj°Ô÷Í\Ëšã¡7ãE˜Þ‚ð}!,&Û“¿C¯÷êYbÇî4M—OüÁy”gOÂße?ã;yàîôa¸€›4@ö¯—Øã,ν͕ŒŠÚ’‡ƒfß3ïh®t-á™n+<fâef œ~Æ™gÇ©~ñ§s’ñ_5Äÿ•ÿ&Œ4–3?=Ó€P€®–8ËÀ{аmpòæ;zNòxØ'OLµLû»îß«žåšZfÉ'þÊ©eö÷¢–§R£ä¤{'÷h€0Êä_æÅRŽ—R“—Cßë¼úžŽ|ϼ,ç …›n$(å6@PŽJP=kìÚƒj«ìYÚ‘ÁJ{”.´D/;:Ð˂ҨhÉ7RS@é5£Øecï7œÿ¤ÕyÒj±ËNï$'†ÑºU&,œjg)kI£Z©Þ4Η٠'tÂf/™8¶BžÙ_Z¦µ*UJR”é­hZ+Õs«BV!Mç\;|îÌh哞df+oü_üÍçÙ%7þvJn.gœÕ Wc¢ZÙÄXi ƒïKY&KÛZéZÙÖŠv´‚%v‚¥±&°À~Þàìhn]$\2€/µ¢+ œ:"{Ä~;]ü8—•þ9ôËf× ùìA/ù÷€]»$Ÿžs =âzÓ §&Ÿ 2ŸZQxá¦1é‡ÂÉòé9ŸÐƒ¦þ0GM–!ó ÎqM2)­ýA§´öZÿL-ì´”&›ÀÏü’xŠhc ÞÀï ?x‘Ajó§ºSÙ*Â#Ž3ç­ï1.øÖرÓèÖZ÷6¦5ªÛ˜@uËjÃÄè°°¨Š¹²Y7¹5fÿR›Ñ¤¸T¹“b™Úš¦¶Vãï¤`TÉÕ£µ7†0¥8ø£²¦u©r7%¤ 5Íj Ê9†ÛýcvÍSÌ·˜ž·–UÃF›Ì±P¡æ2Â3Ý%ü<0¹Áæh…y!#Ú §Î´´µÚˆ£)¯µŠì2«Øh£åpü=áH¬â¨û)Òj×0ü5 @­}rR¾¶µ»‰Ïy³’ÅÙDÉh"n ×µfñX@ZßZÜÕÊ»ž•ŒoÚÐÚ¯j»u›˜7W6÷Û ©if ýÊŠ¢ÓLí JhºY¼ÞÖz y[“ÅpÆNA¶@¶@¶½ |äD‡‡êÖú{ &ö¶‘/÷¶¡ƒ&8Î&•<.dièG qÒ–øhœGc‚÷“Ô¸6¨qmÔ¤s¼9ÛFkÐçÛ”¿b¢¶)oì’¹¢¬šrfoðy³ ÝfRÝvGbœŸuÄW295r<ÕJüizžºí‰ÄÝþù&®FÎmè3pí\ ÌãÛê*ß–&¶å$ÇB¡&]jN[GN[¡–Ó–æ¶540¯-n}‹îIm\Ö}j[^Øhq+Ûârè!^˜=ªÉ+`N˜¯%¬ $<䄵œ0OKXHxÀ [Ú ‹è ã0ûfwÑš“-¶Ì‘1#pí³M²éŽæt—­m91ßÁwS[À¥võlm¤zNh&B;¸%fÜ®¶ÜÉM´ÑÞ¶:agŸ’[ª ïbQßÿ%F¢œ§–3mImë†Ùš¯­;b»ümq›‹¢ð(¶õ¦º·È쪘µÇé¼sx‰£ÛhÑWôh [%üÍMXnƒ«i6ºÊKd˜™dƒ$£\¶¥Ò¶ši…œgP[wG¯³£ây®=/ô\ÀQ’œx¾h«jÞºAëe[í|/#ÇzoÓýÊ:*÷ýÊ^çýÊŠœ–Ä,Ä]ˆ¶0Vˆ­‚nìC[#qi*;þo s‚[á 53#=jB¬~ü9H××%ÚÉŠWàb4Úb×oω©ƒ£™vxùtœÖŒmçM=µÅ0nº%GsüIÙíÜÇ¢¼ÎcQŠçx ‚í¸@œ0<Š&´ƒ¥Ì'¶Óæ¡ÐtN˜«h~{g´sÏU¼Î¹ ÀðÌ,Îqú0“3ÍV4»ÅYíܳ9Ól3Óúº”Ãzo‘Œ9,ê ›”ÄÜvîÞ^go¥!L·“:ö–´s»½N·Òе#Jq çjšì¿g]Ý‘’i;ž7±®ßp¯ÊùÇEh—$–µs‹ð:ÇE(±® ,Ñ 6Vê„bº¶G…ÐêvPœ°¶¦{¨×*0ëÞ`Æo4âop'·©, ¢CÃ*:vÈìd{;ÃUÐÃe{;¼’©àùqĵu{;ÚÙ-üD³h<:¶»¼¢ÂÈq@¸—‘Ëã)CX ƒù}f”ks‹û34 Žšx‡¸¸$GGÅ•aq¬‚Y`9´§þˆöôŸ =[íùòhÉ×Αô{ïF… áÎTâ¥$f*ŠˆJEÀ¿AiÞ*ÖBŒ'Í—@Û¥~”«\Ÿ¾SàUèJ»îÊDåºrWÁ}ý‚Eib¹` ÉT,K£qæ[E,ßÚéýF;ºçI”(§·FÚývôP«ÄhõOÚº¯%Ñ‘Ò'}ø)xXütkLt³Û3º9í1º ºyíÝ|-hÿï [Ø>xø]Ü®CDÁ²½º½>¬­oOŒb¡] ø×¶ïNëÛv& iC{¯$lä„Íí½²;¹…±;¹8ך,ž‹çÚcf ,ª`q|ÿ‹þöÁS‡B ['èdó¥è.µÇ6¬þ^µìȾ‹kT'ýtE’¦½‹£«BÁ(y ©ñÈ5]Ž$KÊ‘¼’ë£C¢¢*^ •Ý¢öXzµj޽®)Ãå©ÛØŒØáxP’×,xUýqŠåiûRåIŠRÊ?ãz…¼jOO5µµfžJ9XbÍ*¢Wí½Bùu{¯ç˜ÕW£m®¶Oýø…çÄ7YLïDdó‹ŒSp¶ŒÁ‚ìC{ó®ÊÇöÚ]•OçO›Ò€ÊÚß3Ëè ÝXÓAõ,²ƒ‰*ot¯ïc;ÐÄjê5Åþ‡ìH§„MîPª”¦X§t ÉÜ×Õy;9ˆMS:¤[=·Cÿ><œ¦us«Å„RÂgt ðØóN¨ÕЬéÆì<òhëÙë:nµ0ØQ¥‡WÛWVæøO ý,%b~šß¶&Ã#i¡FÁ©[›D.î@‹;ð:€IÈB`xZÒ!½0ëT*°¦µ^<·ƒû¨5½‚ó¨Ub 5b‘Õ6—•Ѳ0ánVV†+:ÈÒÍ,+:Ð*]S«‘g£Ùö÷s:ˆÈM²]³Jæ½WrËPËVÙóåZºÖÁ›cܨØÖª`d•tàQš;ïy¤½ÙÁý –‹ÜÙ•¼ñ/RråÒ ó;x… QúAf1þeJàîÝCdãˆÀÉxßHƒ^~ËTozº£1¶úŸ‚ãÍÒ~j‰ÕsGctG£¾?æú>¦#ÌJdæ?Z„šÆy6.¢ÙQ{å¬$§#žŸãðB[Žö † Ï¡xgP³ü+B@{§åu²eiGx5Uò:Ò’Žª« W#;ªNo¤å—BÊã/ѲŽXDÞ·†Ð=׺Žpº±UäÂÌ±Žº×¡cÅë~²:„œëH§:bòïþTÙëKüT9DLúÏuÔ £ŠÉ×kß*â{úk‡ž¸‚Úk…è&˜šwô—_'\”ˆ EÂ¥ŽÚ"áZG`“=¦ëò)˃[Ðà6™¤gÓ:ê¶Z:Ò£Ž†­ÖÓŽ^%ïYB“&a),=ïè5YÂ励ČxÙQm–Þ‰â,âó=8Ù8Y™Ü ¾M:É* •gz'ÕuÐ;10;³;Á'×H¶VÀÆNZÙÇf‹Q+mîTîá…»øN¸qɳ[•…bÊbÙÞ‰¶wJÅI™–ïœÑ\á²ÞÑ)øDÓ‘T9ªÏÃñü.-y^d y7’çErò¼HÚÓ)øÉ{‘< гì´Ý6ì¶ÑA€z“áÖËméÖH+.Ìé„뎪g…ÎêëåX':¦±ª%h¬ÑñNÁV vøgØ}y8â?©%Ï1YýÉs"9yN$ê|äÓHÎtŽÎ"PR%è¼°ºWX]¡±zÕ*«¡ÂNÚI,x}Ò:¤¸KTV1]ìÄë˵vºÔIõ(°ÓU ¼aé>¯Ý‘ÆbxyhŽæð彯N÷¸ügð@ñ°\©Ú‡€Þ›”Ð'èI'ížµfg\ÚÉ/ èÓxä®#KÎNéaQíšQ_ ^ºYdÇlKvzŸ1±»Ü÷¾ìWŒÈV؈ôqx±Mw·ùš3N`®ÞuB§Â´ ŒEÎ52¾çŒ9ãGÎø«=&+KHö«Ê:©ñoeçQ63:c/_õgæOÙ]™ñ¡”ÙYu溟ÕYõ³ÅìàšœÝ™Ùh¤„ÞéLw:«Î{vËHn6÷:§‡ÚàBûHiƒ:kk‚ß:ë¦à~WtÀ6é3Oc»õˆ9ú²ßìx`s°;:”»kŠÌ¤.¸ïݸ¸ñð°Æ°ƒÝÓÙ2¥K©ò1E™É?ç:†ÌêBSº4*¤i]d‘€¡|zoÊé¢:ïÚ-0¥¹]X¼j˜×;Wcì4_>ÆÚÛñôѧ”ÐÅŒìsJØ’.´¸‹tW¬Òk²¨K´ˆ«z„•–v)7`à_~—ô°8¥ vr–wQa³—–B+'¡q¼Üê’nÕ³ a¬=Ýš¼µ—Ðx;m좺î³þ6ëloí4Æä‹‚ÛVD­“¡z[sFܶҎ.ACJ¹Ì³ì$óÎ.2Ä óî.ACB óM+¢4Ì{ºÈ1⦕öu ÊeÎÑ1ïï"#2ü£’›J:j()J:f()J:i*锡¤<(é´¡¤<(Ie%=`%ù4®–ÊOÌ&Lvº¨Ác2Ö» (—èéRXÚý2b©®è9g˜9¯vAPËy­ Œå~‘g£=§>#ç.j9ovŠ‘Ï㓞sŽ™óNµœw»@e¿ŒXf£û]:¸ þ­Ëïù}Äïß_Šéi?•Mêƒ$‹ðŒ‘ÐË.¿ãU¯51Á ÈÓ¼–ì=|êò{é>IW¦IÇ2º2‚| AfWFÀîÊÆvý½ÐÙ]M¡Çu¡Áx X¦!˜¬‡I@0½+ÎHöHg!F%çºÂ<®+Úi–¼ò‘m'Ÿ|pÕõË×´ ]a' cëý²Uw‰!£Y[®tE³V®vEr½+]é*þ0 éjWý-„]½2ÑûŸ0ÁîZ®Òâ ¹;]¹õ{Í_1Ý늲ÑnØt•fç—©Þê=ê*S=¿LõwE£°']¥úeŽG]aÈb£]}2‹û¥Wž!X9ƒŸ9ãÕsW± |ßU©_æqEñÿ©«Làü2+늶)ñ?K;õËÌmôϪ«¬Ÿá,Ó<ÿŸù3À쟃…3Ô 1sá*ÁE¶ß„Xˆ?טc@܈²'Gç;±ëçrÒÊ£¡?cžÔç÷ ½Dzf­,ûU ¯zŠéµ¬ïÆjnØ~6ܰýŒ1BñýL¾Ÿ½\Øþò¤°(½ð³Oè,·Ng*üÆ‚>9Ü.ú¹;]‚D¾€™ÞåŸ cÁ«ÐÜ;ÝøYÛ»õ³6î݆&›R¾€”¯þ(åëŸ1û ]XÊ·‹oSÊÏ"åcHy4HÊIÝt)'u)§t£)Ý åÔnrZ7MÊ)§wƒ1¢&åŒnÝiv·rRæt3Œçvc)çÚia7Ý-P7ݾµ¼LÊÞš8Ø"ì,kcÙÒ¶uSë/Œ„àcÒÌuRr-úÎr²2r‘ä:må\ÿ]©»aCj¼RH7»É&PAN¹½°†šç†ÛÌÊgž-ßãL¯Ú3e)–ÝèA71rÌ®*HvójïÛþÖÍënŽ ’òObó´âz iNJ/ò\z‘7Ý4_±˜|лnXÝXG,²Ó‡nrØIÑ<Â~fÝOýI™â,Ufü2ÕIŸ»î?RY7¯lÚrzqYµIt-mÓöc¤çvDvD™œx1BåQÆ:Uüa+²²‘ “œš»•)N4”²5…;‚iÎrÅu¢á`¿B÷õ&î°ò¸b͇O›™NÔ¹ßgÀRä*2Ó\§Öß<³/Ei^³¶¶æ9Ãðó‘Ì]ùórÉ œˆaèENÕçw½´‡ÐbþñÌNKœÜÙ?·ÓR'ÏiØdXX©‹´/xü­„ê[8œ¨#S²\­*œTŒ,§ÌãÝRÉ2Êm)uÒ3§êŲWÌãÝ ÝõºË“‚ºÓ¤îØÙÆäî¸ `îàçw‡'Šîj|A;ç+©Œg£a'è+»ëílewZ-y¸6ñÌ×›)ﻼo–ézÍ’®Îs&΃Ày˜ó¯5pž7q5píNÇ%ÏŸâ<œª‰óp–pþ¥5tœ^çMçÍît[òü)Î;Àé3q¾ΜÁ§ßÄùÙÀù¹;eô@ž?Å9ªlöMœs{0Îùœ½³Ðۇa˜ÝƒKž?Ź8‹LœÛ€sçß`à,6qî2pîêA{$ÏŸâÜ œMœ>à¼Zë8/™8‹ œE=è¢äùSœ—€órt¸Uw&üIÀƶ´|êQªì¯ à‡Iâge½ÐO=hÔ_°9y¬™Ÿ§Ã®k¿·R¦ã|Aõq öUî_~~Uî_h™‰ŠÛ£gÚwܡ闛¯FGEGUÌ KÆDž ¯Œ—m±-‡Ûq3Ò!D¦& ü¼NÁOnÕPü†Ÿ¥ßXñs%<?™îüŒvGâçAË øÙ=4 ?9µ+ÎæŸ=C+&ÒìÄÔÍ3Z ¯Dóý9M¢åÅë°9›ŸØ%¦‡ÇÖÊóà%ü•ZqKLô­[V^Ê8^´´$R~bzRäÐW¾³!^m¢N‚Z•˜%ÖŠ«ã, Ê‰Ž¢‚D‘•Ö%¦GÆdròþHm©IoJt·Lt¶TÅñ°œJ”ÇÎdr~­·îJL·ÓîDÖ¶ûk†øZÑ”ž×`«¢«].€ïG¶ 繘Àÿ.áßeü»‚W¤|Ž&¦WОpªO0‰é•øŸC'DÙé¶ô¨t»kãņòœ–<×èÌòÀtÍËy˜¹pfŽä¥âOØïML·âBºÌé^<{ë*kÿt•“ Ò¹žÈ@VŠ Éûexe*1r§WN¯ì*³‡‹|·S|i$X=×ø_ þÝÀ¿›,_Ó t?1½"¼ápj˜H9ÌZ@m£G‰éüKt˜$Ÿ@È'ÈÌÚªÈÚâñïÒ‰>Úa |ðÿôJšûSs0çsƒ¹7Rç0d½ehyë]"/¿N¶œï)‡ç5‰ý=ɉ {jþ áß½¸§æ÷ñ¢0#’—uaG7 +:¥k=çôñzÏòNKÀß­ž²s\¥–[,(vïöüCÆ{=Ë;d¼ÈGºd{jOOzj»§ÔSm8b!/Ž!a‰i 9ý¯°t°eú_iæ_ÝGê{Gê£×¿aæYoäYÿWÚøW÷aÎsXòÜ”ã46NyNÿ•Îþ ×[fâ#ñÁ_é‘$Þ–Dñ¹6¦—~n2¶íeœ›d÷òÊÆÕ¸^±=hB/tÜG›É9×D=Ѓ&÷ò3SäÓs+¡Mëg.wädfæNҠ׋òò{ýoNfpƒb¹:‚Ç`´RH¨i·hRbÓŽ6sÀtr-B*‡h]/ã¼Æ+GHx\Œ6’·ôR%å–]¡m½pGtìÏzÂãX·e_/Ú×K3›-¤½犞ë•4çy¡‘ýáÉŠÄ|Z9Ò+6£‰›ÙG%Ióã’Ñ~ä¨ç¨X’õÂ>GÚvìf»-E½`7¬\埼V!×zÑ¥^r(7{u§«½TçX‡6˜×„1¬—ñËT2ZkWjZg´.¦’^ÞÀþç.GNLƬqîЛŒy¼;ìy/ºÙË/VªÃÃèv¯ô0©òOØâ€²ÜçÃS̃^î6éaÎ6JlÚå¹Qþ¨—»#ÇÀ¬åe8=*4‡!O8·‰µQüÈ6PÊù%®#Ç1Äó^jü7æÅž^öâ@œÈ³”ozùtæ}éÖ-ÚÊ»^~ŸX;‡r‹èS/_4LF˰‹(dT’/>Ë 7û£“8/n‰MòÉN2DÈNrÏU|† YÚÝpÏ©0ÕBAMHr‹ðÁTKMA“’ðÌÿyJ«¿ÎÁBir¹8yúaŠD×ñ,hÊË=ßÔò‘’qZ’ù@E¡žoF’¯aZ~š™Ä½ÁdÍNR]ãGÎ ’TÏd[̬i’xEÂÉ ’|1xÎzQ’¯À–qŸà>Üç'¹wqº o_”‹j(nÑ–K\÷ˆ\Q>R€WJœÉ=ò­NÂݳ舨¨Š^™¹mO2vÂÈÍh><²1¬2.Ô´lO¼PÙ—„yaÈþ$´­ÐsI¨êa¾$Ú™ä•û;»’TøQ:$6oxòP’fóÆ+blsé›-Ø8l¤<ÖR®ê)ÅâÆèx’W[„žàY„žN2¶¸o‰Òöôý”‰Þ™¤ît.IkéÜ Î'¥‡ImT9Þ—äþgiuÎV2þ™ëª?)Ý3(„ÔD·µÅ¸Õ=üÿ¼ñ0‰Š’pà…S9íüì”=^ÑìŸdƒÀ¸/ u²8ɰÖÿex8<4ÑŤ?ì\J‚ ¿‘ mï ÇLrë1tC“õP•0s02Äw3Éíæé’[áÜéá®-Q!t“ùŸ/.$="/—î'ùµ/×A^Ãÿ–‡à1ÿ³¢)îÈ'IôDb‚¦‘¿ ¯@O“ÜÍùŸ—§<ÕÞ<½‚óÓ÷Šö±ü;eiÞR*åTߟ¦ææ-Ml‚ÚA”änÂì5Q@#í²Õ»Œ—Œ\üTCÈþÊÈgáÌô6 ¦ºªÌN?$¥GòÔgœ^k.ÜB|ÔbpÊé㸖syÕ*ßcÌréÆKŒ ›) FʽŠI®š VÔ ¥‚kª O¨y0N¦‡õˆé®t« I×ÖåLŽJí®u=³\îîÌywÅu*Js•ƒÔ»QÚŠaŽË}7ŠÓïF)®{ëˆÅ6:º„®¸ï9#t‹ëÒ9!,ŒPnÊÓÜÕEªË]\GKJ,®£Hv/H.±¥]ªC>|æÚÒ.Ö!¿A½$/XG,±Q1>‹¬#ryêê¿™öC%.ÜÊEäc9°ôÉ6Ú Ñí‰/,/X©ÓÝ ~& yã¢7.¯'óû;VâH7£7†¤JRcJ¬°;ùMÌvFõNó½§ä›SfoÇkdÛÛÌTy²Í<ãz;|È3ùßE8E2ß@橽Ë‘yæïÎ2óÌîí…ãe|pù¹÷úäB⦦éaúñ2¬mÆèz¤âø£žDn1rj]¦ëÌê‘¡óá09‹ «=³¬,ìÙ粺ee]ÊÊþ¥¬ŒÃ4¯·Ÿç7Od‡ëˆLõ6õ†ng¸-›z—*3Ýʦ޴½·êuNs(âOÕ9Ýa‘f¼YY…´§·WS±“*¶ {õ¬FGŠD çÄü ‹XN±ÊN‡{«t¤·šú¹Ö–ßg”=Ø£½ÉíÞc¬ï«ít¼·X×bÕr²·ØbÈôäLo„רéloÍŽTÅ òOeÞ*û— Y.÷¦«Lº‘s¶#$¶ÇÁ¥RÃå%£;F®;½é^oL­b¦ÀaɾNÙìkÎå¸ölÐn†mМn°‹¿;Ïmí žX¹“H1úØm)?ªû#áØ.‰h<<²ÜYnËgVøl·’ÙU;d4ÿ*î#ãr²s#$ãr7lTŸØŒdü£2ƒ’s!YE4¦"´ Í+íú«AY\³•³Ív(ç¡sbLKåÕµýsbÚãª`Ÿaû7LÛߘ¦ôIöä6Ÿçv~n¦Ä`KajŸaû»íük$Ñ´>βfŠÓ®¤íkL³™ðF{L¬b¡ùòé™žÚØãç‰Ê,ÍJk‘PÔÚ'—ÔŠþEA l}–Ð åöIo˜v'Vð‡çn4J+ù»QÚ=^dð‡ë~‚…VK¶{ lc¯Ó0\¯5R³ õ1ʼn ô˜ 3Õ­ÄtÄfŽAÔ³%Œ×2¨†›ûÄY~)[(ÛÉûÃh;”'!çL†ÞHÚi¤»N†Yhot£]={l÷õѬÅ÷¬Å÷÷QcGl䆢…k¾ƒûë>^éjŽ÷ñׯŒëLŸô)ü³,!þEÐ9hâA‚ëaBy…T~”g”6Vt‚¡pw~”—˜¥ 6Ò…>þô°´åQTØÇræ%w©iË¢¨¨êÎ.kõHoärñEÄY*âh3¤+ºŸ9Ö—NôÕZþ©?êÿôôúÆ3£m2zûûâyqñxæg=/r+ø) ¹Ü— ûbŒÊѵZvDŠúÆö Ë}ᥰ¦.W%£_˼Òá] D!çáP¿>øU;ÏÓˆ}}1ÍÐ:6w ½Õ—nõÅ£Šñ‹ÝñKÜt»¯w âüŠ¡åN_÷åïÒÃ/§pkï‹}¦WÑa‘Q?Hõy%ŠÈu[^1ÏKÝ ~òÜ!oð¨;ô-ÿ,s‡éWª,w[³øg…;|l?zÃÕW¬Šém_Õ§\aô¡oðÙ@85}ìÛƒÊúª~Oq-½“a&=̈ÐóeôëAcú©~çF_ìYý8“ ç cûe À„¬MìÇ sß[8‚&õãA‡¿i G²~r´]1î”ù£4µŸŒã8]rÀ™ g0ɃP•5¬Ó™üHÍnœfggn÷DÈ.BN? €Ü|›ÛO°0TU@Í Fë ìu-èç×`hq¿ô.„×rxÊ`U?Y¸|oYÅ ^éVÖô£5ýà7¥ÈQÂnèçó²®Äp|c?ߚ i]?³W,®52Ze1¶ôCe#Öw[´'0úaTq8÷EØ@㊺‡)­r+øÙñ}Ⱦ~´¯ŸY¢úy5ƒ‚ƒýºÓÑ~~\aåìÝBí‡zvºèçw]©e¡_Y¬‹µ€šNC-•¸‘:j‚ë3ý¤²T×ÓéÖCÃY£Ñ7™ÉóýP|bA¤ö“Ê¡ U¾~ðb"Ìoæ/ýùKó—4æ¯ô£+AÌ_3˜¿ÎÌß`æÿ£Îü}ù‡ýèví;m c÷Miö9G5HòH$AJY‡ý[qMOÂ?a]\f]”‚ówR¬rñíU?}–ûJUÞp» 0Zä¨Ôúù\Ç#-ô±Ÿê k½ëç‹êÏ@ù>:„{ûѲ:¦?”ñ¸?}ÚÚ2¦?¬¯üä× Ë?k†f÷9çõ§±ý9k1e÷ÇõšÖ_õlÖJMïÏÏÌþ²ÄíjV^Wäô÷éÁ9ýyª:¯¿È_¢Àútå`ë‚þ´@ˆ"À-êÏõüj­øõ ´M^ÓƒáÒÄ)ëdƒe ç'¹ýã”áaŽ,ž†æõ—Ü^ÔÀ¤·]ãu4!še:šåýãBMF³²ÑH‘ïÏÑ„jhVëhÖô e4o°nróÿ…$LC²^G²¡\#ÙŒ¡NÓ‡÷ßÕ†UÝ¢ƒnígeÐÙN°*# `Ÿ ®îÔAwõ gP¼Æ¼Ç¤úg€ëd¶ºOÜß?.‚ë¡þ²ÿ7¯?j2Ju¹êç2:Þ߯‹êçé‰Ö{žÐªÑ¯ý±pý`:°¸Ò/õÇôn{dÙ&·A!áqÙêvfã¡ó¦hiýndizÞ¹´ÕnËÇþô™Á:¼X–ɰ-/þŒ€kÜ–ñhâ¹­ä\â€WŒ˜€çúYàJNR]{¿áú<qbÖ«‘^ éÎ¥œ eÆ„òŠqª\¢ó @ 7òbtûlßñ2^<@¼Œ_ wÒJPáÕ•ë°ÐŦ'ðKÊ{Çâò€`gà×èÎÀKÈݱlÝÊ;ìæº9@wî .èöm£ŽPîÐ7*=¢èÁÍQŒIŒ¯ÜÈÆéâÎ7N„Ÿ pÏV8ƒv)[êÒóÚl-V.e— Ð<†ÿ+w=ohžÿ¡y6¶¾@ïÀk¤æÙ¸‚£<WH„gãpx6ÿ0€> àUÑÇ\ìP} 7ëd`,ãoð1Pã›gÅ3¦GÓŒ>¡Bdôê²²È ‘‘4v <ÅàXsŒŒóÊ¥ÏÖ–y¥×ÃÏæ¡!óÒ’¨+†ï¯OÛFþ Ds9é†Íë¼TÚâ`©Dù$*»¢ùyÅNËj>œ–TcÅÌ þð‹ÿ¦UàfL ªª¸öÔïÓùÒŸ£Ý…ÌŸlú* Ÿ^¼ ó¾ÙÚ͇Â@#®]6<»k (û›%á›ÁL¹eyc Ü-KÞbp›o°\Î5ˆ¿(ƒ/Ò[á{"ô~ ´ XH…âQ ú,TÅš·l êI ±Œ˜`£ŒAÂŒ/çB™ƒàK)ÆÊÊþbu5“ÚB!2uM’¬²Ó?yPwš:(ÎR„˜Ìb<÷^Áï«ËÈ´AB×ä9gBhHôU.Rx8ž1ˆ'ÚLy&¨eÇ„ÛAyƒtyòѲAªW÷ãGË‘o\ îØ“*pfæ@]žóºœb93ˆÎ ò¦6ÙýL#y=¹•c«4@-p+¾Aä“(Ý…ºO.v^äóºVsy’*^󀋃T·µa¢U±ÒAW$ÁÛª¹:È«¦åV¦ëƒ¼âí€n òŠ›Íÿæn!wÑAÆô{­›î2¦ßÅtoϾýÚäûÄ/uH¦}c’!6‹1&™Æ&ƒ¢±?’-!hq¤´ÞñZøŸ÷$ðº2Ù ~&'ëüLMÖø¡éÉp6%]Ùt™Ûç&C]ã"Ê÷e¬çÜd4?Ü—-O–¾lE2å'k/F-OÆÍÖbZ‘,S£sZ•L«’[SÇEd vZ“œnF×ò‡W˜Ùœ¬u[¨Ø[’ÎÉ'^V$kÝÌ*îfv$kÝ̽›Ù•L»’ƒ»™èfö$Óždîfö&ÝÌþäôéL&£3ý]ÉèLŽèÉQ¨fbLhŨŠçåî´¨&D»‘‚™f˜¬¡q$‚«Ò‡W@0ªTÙÖÊ¢²ŠÖqâŸõî?ÿlp‡^½…&ÓÙär·Ô0Å:—ܰ©Ép%ý“áý\.‚]–Oý¨ŠY +ZÄFílª˜®jáMúYU•$£«p^®a‰9»d_ìZãÚz²³5”œ˜|©nëÝdº›,cÛÁodáD÷’µõfæ¿HQnq‡?H¦¯ÍæXjzâ<û7þâî1‚Þž drF`%ÇØšÕy)³†gɲaÌĵYœ¥Æè²2\3£·&€¾èz—ì5n‹ƒÜÑû'ˆ¶Õñ!™>&{SyHÔæ“h%~Lso®ób æUv_?'{ñ*ÂðHÊœ)eò¢h4‚,Y 1mÒB,ÐøÁ¦Û``›;râ`š8“¼V&–9ò¿ŠN·»+LLSs]ÕuEÓ§G 3ù#H§³ èt6B¦Nçþwu:o°ètò`Y€TÀ¤uJKÿB›…ÎoµdlS…iç¹8!ͬú\k1ô æêºòÿžœßáÁÎþ¤˜P«q zýàÀÞëËè´‘v¸CvóÏNwèÞÁ´y°Ï(Ã-ƒÝ¿ç~Á©(΃ß+¿ÉTiÛ`÷×^ç׸ìºc°q-üî¬ ç§k q÷àÔ[Õ|q Ή߄°÷jA§Y‘û«¬V¿ %ø{£;=LÃWžL-&„É%•Áî´aåý`‹:˜T&T`Ëø¥|ƒ½Ñ×aò®ªre¸98äò`*œ:¾†kϳ„ø¬æÎ]M°¿_4Øý‹ê¼m³ø pñ`¯øï!],ÙŸ'ð¨pe°?~sñx{upê‹OÉ7YÅbxsSN·³«ë’rƒS¨d°×ŸVòÝ:Fò2!~âWiÓ+ÓMÄÌ Õ^“×(¼JÈÐ\àÞÖ¯9œ6;‚î æ±þÍwtWGò&!ímÝÓCïâÇ1Ê9•é¾ó>!íC=@è…Íó1!íS=ÔCŸÒÊ葞3£EÚ¨ô›ž–Ù"mt z¬§i‘ö[=쥧ƒ%9«Eü wAÚØDz–ìiÏÐ3=4®EÚóô\o‘ö²½ÐCZ¤½j@¯Ùkn†×–ø3ncç÷ Ç\瘳Œüuz7ØëyÝ@ö]?èÐ[¤åÔ zhR‹´YU©l°êň—9^SdŽ%îØr†`p>ç¶ä )Uλ•¹Chî¸i ˆ‹Ç–‘ša‘|k=êyjCÄKè!©OøàSu­çÉÐü!p•cå¶2Kk+C[‡q–õCä)“CdëpÓÚ8Ä«½=¸iv J/sâ‹Ð­ChëÔÇu½òxà¯Måiûô0¹]!+Ö0˜RÄàe‡CÜ;"ùzCxrÃi×F©ÛjxžãÚƨå%“ex ÜM‹ÑòMáî„h`+Ë fé`+åÄ:5Nè¢'â p+nÎQÝC‡ZF¬µÑ9IŽßÚ ÆE^ 4L+²‘ˆŠoý7³ ‡¨®M<Ë.â‹Æbéâ ; ­šÐeÖ^®¸b|û¬tmˆf!X2DSF¬·I›¹=DmRìYo;8< § ëm‘a‘¡t+VR‹OFÓ†€"±XÑúïCÔé² ¬!‡ÛCp±GcRì¡^#ÃŒ˜HÖEžè"s(t±µ—%s(T¢àç`«üäÔ7”²†ú£åÚÇP÷È8KÜM‘‹)–đ֌‘Å4n¨×#æÓ<Ä ånècs MàŸëSs…&ñÿó{¼V¿‡ÅœÌŸø³ÈJSøóCƒ¸<šj|Áp–¦ ^§Å›z18Nþ7qe; …ç@q6'ŽéšrðP“"îX=!‘ bèfokm#q;˜ ²hÚªY4-ªrqv;©ÈúeñPMGðd˜;×üm”ú³b`n/6V ÕwÖW ¥5Z~Õ³Î+e_€Ì³c[Áìafv\çÄÌ75.V ¥ãCá€×A'<Ê- -M†G2†ôÈÈHäãöÉñGe¹e]ðW©'³¿´f»)Ûí÷ɺ@Ðq]ï–K2¸IHŒÄò(9ì;Ë­9̬VÀÅ8ùÃädÒt·¶mÓ[(0@3 Ÿé¦YîTî Ü^ší·”ã6Ä¡9OؾA—4×íM€Ó?Zè† Ñ˜pn°29^á6K!p¿bÒfµÅr Z-Ç 7­vÿYqlÔ‹£ÀMn£8ÖºµâX¯ñ‹âÈÖ‹c3—C¡;t‡¥¶[JźǶ~ÒM›ÝÁ…³Õí—Í©mîî´Ã-/9‡ÑNžîû¥Ý­—Œ•ö dÂíõ’‰Øç¦}Pfx d"é€;]3$?ÈØsŽíqǺyfµÝ\Ç¥èPz“=é–ƒ!^lGÈÖâé!´6Š tZ¢ä“4âÐpn°q–êÇ÷9 •Œâ6m7ßbà)¿¤8¸f¸ð‡šYä¦bÔ„b® µšpɬ —_*Ю ¤&Ü@MX"3‹aržåF“.r[^q1»•7nzÃó¥,?ˆŽY@l~|tÇö QüqeUe‹w˜OTRHc†ùÐè)k˜êYaǧsF ìÀçÆ ó†ñœ`Ù0¦½4&pãð0Ð>[Ýrx†C켘ÀEÓ+’x¡¦åÊ0äQ® £k€Ïç¹BEG‘Ì3^t+‡ýÎñ'l‡Ñãa<²ñTòH3}*y¤™L% ñž_›Ie}>L…·L×I‡‚,郦OÃ`CXÞgÆß4œ—ܦ ÎQ vÁ™)!þ7Gÿíwþ7³ÿf°t¨KãþÖ]Iñ/â”sf ‹RÉ2«…8å\Uq²ôŸSþ†–ûIKd §üM^~œÅ?ÿ/cßõqå¿óÛ¦ºÚßîâ$ޱe¼6‚¬"°ÇIÎŽÄ‚".wqÍ.«^–vÉ›»ÜårB z1MtèˆÞ{/¦š- Ñ›i6E¦×ÿû¾ßï·+0¾ÏŸÚ™ß̼7oÞ´73oÞö+SÚñxWÓŽÇ»9íä§È*¼é‡^“­h»VrD;íâI­ݎ휻ÙÎùI{¹aci±ƒMZ»³M°qíâÚÏ l‚Mh§Ù›Ò6ÁÊ2ëäÔv:dM»„>ŒÎiÇèfçˆß:¯œ×Î?;ÁceÑýlÁe“ ÚQÿ}K¿³‹«Z*© —lgI;Xòt%O >k§Ë2Ÿµ“;7=WgÄÕµ“‡7ƒg´§øT«Þ¿j'/¶‹ñãž3¹wð3|wÚivïüN;y¯]Ôß<þÚRÔ\ír (ñA¡_‘Õ÷§Ë‚ºÅøò`p½7>-®ÈWd¯ lt²PÖ’¯Aub‡åÈàc¹QeP—7G²´fóCØ ÈA¹$ , V†Gºy ¶’+ƒ|x·}ñÔª«àK)[…o~¾;/VcÅe-Mr ¥_„`E³¯åfߘ›ƒ­„÷_?¬o1Y¡ñ*™ù#óA¹ëñÌw²èÿGæq=ó¥¯}Ræ‡d>'µ®8nd~<(Oµç‡O;s¹&»ñPa¤ù2ÈæBP^áb0Ua'íÝùîãå üÁ,ãVNõAýúÆ ©%àÜźÔïbɯ‘÷;¼@t«•ljڪï¿ÞÔÔƒ™ådIÜûзE¿à¤Æ²ä4}}–ü:Sŧï ?ÞV‰ìÌ‘g9^›qÊ®DSbÛ”ÔßÜ!ëÆ;ÊÅ(Ž˜/•HI0{rxI“ÛöðuCµè`ãî®-še2ËÕyµ„GæjÈ7×J­íy3ä âjø^0xþ7sñ}7‹·oïÀ'«¢Î [8’å+ 5,_PÃò•‡/_ÏУåëz¬|²OˆÕ®–`yXëPm:qˆ> ÄåÑö±õH]Ÿ\â8MÌ]XQ'? úD+ɱ¯àRF_²÷ÈoPW©S3+Éí?@IŒñXu<¬â<6dÔ?Ë•ã«&cŽÿÖ c•U!j’KR£ÂìÞƒg‡äÜP´x õòyH³”G~ g¥‘feH®F;‘]¹É–¹`%ýKíï!,ö‹X(e=’ ú”ûB)e‡ý¡o*;Ô†RÊ$ïFÆ‹öÛë? ½ÔZ iKâ!ð9.­ž¤¯¤ióð}[Yó®‚Ï=¾ ã>&…8¾tÓÌðFgWªó©»ž aƒãQ9ìËPÓÖ¨.†´”­EçÍb§¨o‘4k>†$¨×MË]i6ýõ„²R°kÜOMe¥´îx^Àéû¼çŒß ç¬ßÒ»Tö, ®ÌãRõ*%Á·wipu^YZnô- Y¡;²Ê~¥±x"ŠÃÌ$²iÈRô©Û^æÔ.£bûk… ·ϰèVÃYŸó›jJA˜Gο2Ÿœ ?5/`z, ™ë"r–Ú–sÞoßV Q8mW©œSJóÛ ‡œWг ßJ>aJVÌ/úÖpµóô1á§üA}xai T‚ED'HÌZRêŸX+šX  Å¸ª4d÷}é÷@ÓdM)oÆ#x-‚wû=Øw_Wêϡ֖ë)BW.ËÙ/7—F£ôCk§MnÑ€fvZ"3r[i4<¡ìJ¾{”¹]ÝÌt¼T'N|¥_¸Ý/O–âv V_ Oxçb„J/O•¶–§“|ÍÃÒ‹ÒË¥ò2!½D*ÿ¤ýò !ýº!ÒÕ.Å’‘ù:?’ÜHozL}Û£ÒœK~e@{9 =èrPû HƒÛÇâE_ Vðþ´=4·Ö¸ì´2Ø®éÒ´×[öäöhWbj{´+eZ{´+óôöhW–ä {Í:³½œØ>ž¡eœÔ¾ik9¥ýZÔ~9µ}²EÕÊií“-ªNNoçe‘3Ú'¸=YåÌöè5vný¬ž;«=õYÓ>mKî*rv{ôê(6®u›œÓ>dC‹àEk]ɧù–·×XÞ^®lÏïk±•^öÆŠÆÑ"S®nuã:ô^Ð6h•ôæÅ¶ör‡‹Éj§/_¨´–»x=çȯWÖ2ðe¿©¶½<Êñ žãäx¨=¿éµ!Eç™öú{6gÚËs)¨ó:ÔD@}ÉYmt%-÷_kcüZj6¿ÎÞ¢I…¦Öò'Þ”JÜó#J\ñQò‰±Þì W¶–}>ò‚œÍœ˜_5†Ä#R‰Gj‰«)qåG@¼%µW? igP‚¥x‘sk*b"V|FÂRŸ!bÇG8 „]°TÄD¢ˆ)èˆÛ°ç#}‚:ó‘<÷QŠ=iì™Ììù¨)ž¤vY©5æ-å; Uï7Ýù¨^H¿xø.+a’n>0÷'gðO,ȹâ· Ë{ÅØ‚îýü͹yáY¯ýò!esð;rµ‡¾¢<Õ@ä-ÇaOö ûóÛäã+Â0A㋳|õ¶NöÇÚå×:ÙŸÒç9šÉ®Zk›|KY>õáhYsê5\fÃ.kºü4²âN7ÃÂþCV\Ý&¢pguxƒ€;!°ŒL‚P DûMhôo9–üÆ®­5¼á…î.\±›æ¢í ç.'†1‡Ç´4ÈŸÙ@>àªØ·â®: KøEãZ .É ;ëšZc4ûþ„fßi”†2ÙÉ+U6¹9¬Wëæ°ÜnÌÓžjÜöoÌ‹E‹7æ)r{8{›äXÿrY„ng#Æ›~áàÚt¥~ò°X<É¿)OW°ãõȾpÔr9­µÜöozÁ_Là5Q á2•ˆ2Øí²FGÿ 6?’Á1Ê ž28®eà5%“Ä‘Ánê¼qU ®„£ÅWH»†m1WRQö"ï„uÓx0-æJZD/ë@qåØ. „ŸÞ4+k}:Ds#³²_Øã®3Çô!ÀäëvC;øÿ³ÍšÊþs¿Þ/wäÈ‘b0WÒçEY ïkIßå(xZKú½(GÃ[g-éõ¢ïkIÅ‹r,¼‡¬%½_”ã:°©˜Á/µˆ²åxÖ’/ʉðî³Ât̤Ѩ¬ê ™©î€óõOdü rMý€¯¦C½¸êsÉùÚ¯,ì çR™kÁ‡î>eݵr^m­9¿C<·äk’M:Äô¸:¹¸C‚ã–tHD· ¹Ö8ärð&žoÖ‚—ë;À– 좹’ïîDÄnÎ0×.Þ!ê莶yèÅWBF9Ž€ö¹Ìi™5,œ•EtÚË"õbû¢œœk~¥'9×ýæ^äÜð[*ÈÙû'k?rnúm"²< ¯µ•½R+{’¯·§¬}ìE¾žž²¾§ägC‡ÔkûE¢á¡jwê™"FqqÓ%²³žÝ`ò„{xØÄH.EP¹4Œ‚ûÈH4Æ¥‰çº±"‰ÆÑé_*¾åTøliL$‘ëÆt76MhQ·Š³B–’ž9AóSÓñȉDØM'3}RD;‹¯Š`Jªò*¼:¢µÒɪýÜš_ä§òˆer^„[º›U&f9Â×e4ñ·q¸–'ænËK /a.йBcI­\I½'²:¢½'²6¢#Ìu£PëŒÏ`VxD^4|<‡÷dÖG4ÓF×rã¿ 5„M‘x²d›õ’mh-zJX—÷ê ’ë"ò 1>rÃ)Eb†= ÍŒeîl^faŽúû‰6ý„ l=¦óò8H5Ü/À¶3˜Å„Q;>û–Ì!id'‰C·üÎm¿r•ùe¾‘W#É¡ãëˆþxÙ+£õwÃË^){¥NÞÔ[šEÞŠhÅ¿VÖšÂ%ŸÜQ/ùäŽ\r8{ÿ¤Ôt”Ó:ê+ð¬šñú=g¬èsŸ¢Ù/™N¹×tä×É9S inG­!-ÐKxÏ)ê%\¬S»T§v™N튎‰$±+ubWØÃ®ÌìŒÌ³â‚ 6Ú8¸ß. ˜wª+àô (ƒ;ÉaPæa¢rx§˜Ñ).GvJÈÊNȯø®Ó*Gu‚á8WÒ’Á‚Nz3[ÐI.ê„çÃ1..Fªc<®±´½‘RÉÍ´†¤Û`MÓ‡·Ûé0“|œ‡ˆ ï|(wt’»:Ñ\y;oªíîÔJîé”jŒŸwÒc´“Öo§ËX'íµ M¡:ÞÉÿ!o‰(ŠïS¨:‘:B;ªÎ!ð$“Êz!WxQ6ųS×ÙK-˜¥Ë›ÐW9dä‹%½=,]ÞMŽx‘y8OqFüÀCàìÑ™»¿1ª0ú~Xïû0Æ;Ía1¥3˜Ðïw¦!ëEÿ߉!åÐΩ²묕}xçcûôÅÙúZYŽèç aÄïTvÖøó)É15kzÃHŽé¬µÊ±‰ÖÓ\¡lt!g\0-ì,wÖ5ŽòåþhÑpÕDó<ôJQ·‰Î¤ÀÖ`ë:Ë ß VÎ`gS`» °]åžoëÉ`çR` °å¡oëÅ`çS`g °3å¹o«`°/S`W °«åµoëÍ`_ñíVWzÈ`TÓÃΰT%àT”‡e.„„~£±¸,ï’x²>*ÖRÈuÑ‘ êÂÈà²A]äF6„‘}úDd}ÙÅTÆuÑ 4®‹œÐåÛ Ô t)6Ó›ÙEÖ|+X»œ[j€-í"—+Ø«Om2À6u‘[¾l ƒIfë`íí¢²ÜÛ… YîÕµ·‹ŒiHâO`Qñ Õ"ã]¨'\Ia:b°üˆÆò#¦#]ä‰ÿÓ`Ât˜®ò˜ÂWX.&y©‹aÛ[MŠ:km$êÀÖêí.©¾}§‹Ö·ËºêBäÍÖ¼a\ÑUÃ5}_ø)á¡] ÿpNŽðbwÖI¢”×R)'"eÕ£)i–7R^gšÀåH9·kЬy]5²wÕ&ËdºÁ0¬Í´0«)~¬vvM×ÜÖr­†Ã ú×Ej-77(ÊMB!ÒåUð Lÿ” Ò"¸@´6olÛ"èküq‹àgVü½W)kÿ"²ùì®þ©œ\yo¤h¹Ï6ä³p9šéRQ‡ã³MjàÁK>{äÁK¸|L+›Ì¬.Wzd3eJî@sô×$u™k_nYû²bôÌié™#‡š¡wûËð̦ÑpTeyw˜Y3¿7­Ä-h8ý"<‚¾Ð‚Fš[Å–YiÆõdª„Ì,'2aÁÍK’ᦫ¸*JM>3«"Æ[ [Ñ9‘ãcnØ©² <]•“-${ŽRåT‹ÿAK[Ó,þûl¨~ºÅ7ƒ¥ã™¿,’ú$_Ÿ¯±÷Rì»)ƒ™ à~Š€¸A@Ü"÷q¼F@-˜©Ê:‡’Np$IÀ1€¾IN€€)n€€[”A x˜Šb¥ˆ¡Öhx"ÊÜ E´DÄTDLÇë+*Þ>g³3¬þã BŠŽ+"(»<¤fÞý’½áµÖÖò‚w£-b)ýyÉd^·nœ¦àK^{Œ#sUæÛ¬0`o5€•÷4>Ñ—,³1¾˜Wˆ=l0JØ~.Š*ì¦Ö²\‹î¤ €=mþNÝI0‘6½ö[+=Äje“r§Ñdå„rSyÀ>ÛÌB“°™fš”½nSM¡ÉÜÉ4»ÐdyÆ4§Ðd­¦¹…&[sSO·™šË(n.ClFs0 ±5h.´ÖBÌ6kíÃ"‡Ûi#lOl•6n—±akÐ>Æâ½WýG-sÕN´=¡jÍr§@ÍpÕVÙ¸’¨jçQÕN¡/9Õö¤ªUä4$U¸j§³7¼Ž¸6Óöͪ­±¡zö¥ªv¡í Uk‘‹m߬ڥ `åJ­ˆô%×>RµëTm/TíúGªvCƒª‘›´ª%<Ê_ωËõ9P™¢ÔpÍZ´š¥*U:¡2ÍZeZš›z¥ŠƒT—ò°í‘bß#E…;9PõµSâþöhx†›Þn ¡?Bħv}ýÔ.‡ÙiØ\¤Êáv6'«r¤]$ÆJ;îø¦Ð.Ú%„v Ðöe´ùˆXe ]e—k€v‰*×éè&Ñ­º~ T]ø ]´óS5sTÝl©öÎçÕ03|ÈŽUx{Øîm¡±S&òÉ~y°1¾_†³cHº_ž°c·²Šúû þ!Q¿Ô`:~ƒˆŠ4úŠ4Ù' ñ1~¡¤_•d…*¤ƒF«r`š1‡ IÓÊ6(Y¶OÓ¨lS™Í#œr![…̹Êì·ˆXfd¶,M®àø˜ «Ù*U®á0¶Q³6-8ýZ•û‹WëµÏc>!7"·Á©ÜŽ!·¹¹ Ií¬‘ÛÙ4yžãµ¢}…ÜÖ¨ò"Š6F•—’E“zÑ'‹v™}Ú hé(Zz4¼™ u'ççeéFÑÒå Ž×æçUé”Ù:*Zº6?¯K7æçõéÆü¼!Ý `SºFÀ$[Òq“'EÀup“2X†3ïr ÜO—9>æF÷ï‘A¬WeÏ #ã^FÆFÆ}2´Œ?MfÜ/×bRÉ ŒÇeDÃËñHi#ˆ˜ža ´ƒ¦ér&¥«²”9+£ik97#9¶b>/ãÑ‘5¼4­µ\¡é;4È–d4åqhyÆK­Å ­~ÑÂT™ÊwS2ß!´É[RùnE¾;Íwçãù.£|w?!ߨžo¢a¾£XÞyù#NfDç]¿ LF©|SíLF´)jø\ÄC>ç<ŸEK(¾¬ùø9Ú­˜3³¶à©ÏÐÿ½B¸ðÌÞ×\×_¡¦4òg¦ëõ¢ògâF†¼Î%ÑÞ »¡ùùɰ[ì÷Š’ÃVyÛð±Ê»¼³·@Åûd÷2xo¾Š7Êpª²7Néx-¼o&(5ì|‘×'fó ×þ™„L{êl@&¡Ò;œ‰;;n³%3ëŽ‚Ò Ï„öhN¿—3<“ßËž)+3i1ö{<À3:3É©±™§Æg&95!3Å©ªLæôÁ§fbDJªÚS53Ó2£Å;T“öxùwªÔÖ€”ªÙ2Få™hEí¢¨¹ˆ¢Ž¾0(’ت [˜ Ҕřrq¦¿,Ó74 )9ÔÉ%™ ~3iYfÔß)ñ X…ŽT«ry& Ù"7$Ý™~šp($iR|e¦Uf)¬¹Àu<'nͯáÌ+S™wwáÖ̺Lÿº©aø|}f49mâœøüx3{cq¶Þ¼•Šu’е u0–G×QG3ùÆŠ0Í”Ç3c¼×{"S~NÌ6‚9 VŒUå¸ãTyîTU^ЫäÒ“š¶ø.g¶’R¯¤ÏT‘ù8Îüçȼ2‹mEL•Yrtu„tLž”SåØ,*Ðx³— ÏPyt<qeOÀ‚pù%ewDå©‹£²Â“ó¢á£ZØ¥¬¨Ž´¸–ZJ=%™ª²Åɨ¢áijñVU›Ø¯rPñ×Äÿk”p²Š–'¯£Å,RqÏEÞÖ²“ñ2Ç]É\Iß{„Ã÷“f¸gv²2a ´Ovƒª,®) Y';Y ¢A5T2ÛG‹•M=!ÜIÇdÃŽÃ(ÆÌ1)‚z‚ªl¨p"A¼Åf]‰¯qš˜§gSñ*U9+»•壙b>ËÄ,ó-Ë,ðm³|aùŠ}7-½¬¬w-(4/$9yß3¦E$(WXRÞ.LÝ6G¦#ž…¿0#póZŒÂ¸Tš[æÆm³ã|ÝìoÚíÄÜ2VAÔÒ üdRõ²è¦…ÙP#‹ÉÙô®²$Èy)9c–eä {Ùº<[®ÌŽs4!M¶?'ƪpuNœ¤¬Ëf³oà EQßÔ"œ¶ksur[6^Ê`-÷ÒlÙrG¶–vb»m!rkëŒ=Ù~w¬ˆÖ×Tn+‰ìXÑâBüê²µÁù`v”†fBHe§eƒ«‡²i“|ÏtyšUΦY{/âHv´x;M G-$2gÃk•œÈÆ%‡Ex2xJ”g8r´q6›{ÄrZrõ'”ç³CVWDÍlÿNw›nWƒ¼ ÙÅ}1…ûrvÈFFÖgíQ¢=®mWI=ü Âoü0Þ§…_ÕÿξžN ˆ:-üš~éwQúÃZøíl\ûІ«Å³ çI3u¦ìÅ5ÓLs฀m‘C>x”އߤ·ÜAô†lÚ«-£>ŽG ÷sÿ+¼¤0NháýõðŽG 2Päx´ ƒõð!H”æÈZø§zøPGð©pœò=¨ïþéáÃÁÿÏ <‡´ðzøHÇ£ íž ¯ð¥ÙÚ= 9Ʋø& Îî}H^ŽuIªç^|.|êáe…áå…E=ó„o’žp>áO°=ðC-ÐAد*ÀO´ùªåUhµ“€Þ{:˜f÷BοÃ!¦ÙÉê!ê:(»_·W;ädGðóÜðí°’;t¿µO¾žˆ>9E§~îDߘê®}÷3¦¡ôû4(G‚&ØIpP?åÇg ¿yuÉR©ä,„‡,øIÃú2”VÝô¥¢¨wž(ê“§ X5ŠEÍÉa]©ÇÀD¤œ›ÂaiµÀõ׈¥M‘*U.r ib¤’‹!»ú%¿ðNÚ ‡\êðÿ­ÍßL·Ì Ù±tßèJã¬\nr4ÔD]À…ÚŒE„ÉwáðŠB }¬]¶ÕÁ½ø–»)ÓYªë_‘×Á×ÓãŽz19‘pȸ#”N´ÄP)-a«!]Ö:Bø’uä1Rì#?[=H”ûÕPfU”œRäB¿AeÞ£˜ ‹ò-©.`îŸà¬ùBî) L“h8Ñ Óuè/PL©RCv•Øj…¹®ÌKyÉ<îðM ø¦äeÂ3ÞlØËÍ’õÿF¡¬6w ³¼æÀ8•¼ÌJÃâ«&¸^wø·ð®hÑ+Í•[­ò¦ÃX Þr´ÄQ#p?Ï4‰]÷XÎà0äªiÓ‡¾­&Ër¨$WöÊyd#­"ç‰i}rHگʾ9¼¡† úç4ØPƒ0)Í Â8^u½‡}9oŽ-æåÀ0$ òÕð9Qì±Q¡Y™ã|îñõݘœÀ5h$Át\•\YhH?ÕÉ4‡¸ÐLNn@õP6ò4åqJ|‹ÙLÒ´†á/•¬,”Ósü¾GÓù´˜Y9O”:æå«óù9F},Èi¥üïB±‚«£NìQö)ð mï¬ÊAÕs2 Õ³&ǨžéÓ¢<2oÞù-rù½¦OºZåçºÏ&c9|oÂllˆÅs¼â6âžàÊAÜ”O>éj—û´”#åþdÊÚý ‡)Óä¡låñËKGEŒè’æÀcÇ@äÐ1Â'WËã9Ñ¢=ªirѪBêNh9¥}Ò5×w§“Pоo'¨3õyÊ&ÏjPv‚’_qK£¯t¬Ç/¤¾hIŽëõFˆñÒøJÃÿkã‹\¯_¶’¸Õù’¥oqˆfæ¶á[å]£.2ä=£.2åƒT¯½MWæüÆr'KörF‹N©¦pÌê59¼”ª·“›‡ìKn—¬äjÃ3 ½ÙI-"·ÂjÑZo…5ÇÁN'=ˆ–Ôä£6×%“W¶C(íK„r8`²“k崥ؑNøýÕ‚|ØZØ\V:›6ÍõPå(€døf<dTÚT íød´Žr<£TñðÙd'×A–69äTD9\0…=Ý©349Âû¬SÀúFh&‡ÖR¨^E³“éKöYåœdº’Z+Û¶]À|0[ °B³¨¿øø% áår§³ùãc×Jg0•|•þÔ9Öø²4ZÖ1&>y¼¦ær=3GßDš"7à3SßGšÒ&ßR²á.ΖGÈÙú9Û­ÄQËçöýv,L«ièibZC«‘&¦µ´ibZWh²41­/4Y›˜6šlML Mö&¦M…¦´&¦Í…¦ô&¦-…¦Œ&¦­…¦Ì&¦m…¦,ZÉ|VhÊ6›¶š6SµÛfÎÌZÅÛcµNýÈ£N~ò˜Sp&G ƒÎVò°S_Ž:Ñ¢÷ËcN4çZy‰q%6_;Í—'Zâô‰9Pžb.io\ŸÖÙD<ŠÅu>`¡qžÃséS^`o «µ]ê"‡Æ¸Zëàè\—œ­L¦É¼SÈ'WPX¢¤úO»ÆglH—ì(”75…¡þ Pwuß™ÚÚ{àLmí=t¦úu™šê×=TB2•·cŠ€¤Ÿ®/˜ú©²ŸŠ­¼±U±_Pc¾Ù?õÀÖà@‚n-QÀ-`0eÓZU  º1-…n£[0QåF·Ð@7Ž «¿ËÐãÝ ˜«¡›Èèª5tÓݶô̬OYЍa|‹¦µ^Œ|MÀ©|MSñ†y9Ç_µÌ'güÖ%äÜzö”œè»öuªœ§q•"¤ú¤ÃØR«\¨†¬ú&VÈZtêy“öÌï"µ•\¢â©ØçÃS¾Wö -q–Í“X¹\ñ¹Ã ’¶‚‡2ãòf!x¥çàUzðh-xµšàà5zð-xNëU N÷›É jÓ¦r£²ÉM”CRYµ ©z3…ÒxxÚ‚z›ÁŒ~ŒÙ«ê öª2¦&wLª¶=·_Mî˜Öª©ÓÀ2Óm3NºŽXŽªò8¸Uô¥Ýߎï‡ûþ@ž ,'Rëâ“€žÅ4¼èsô9UJÕoã¾6^Øí¯S_!F^Sýý²´‡¹n¨Úªø0Õ0¦gùLÂÀt_•=\Éäåxés6 •™Yù¯÷qééú¸êņ 1Ø%û§’v%i(³ÕÊ!®hœhÁöÒ~UÈa®xr›‹;øp à .íŽ;¿1‚"°©…3 Jö“£­ßG¹Œõ» âæ0qmAÛL¶UˆZPfšé’5®˜>Ó5‡@>þ 1Ç%çPà½H&çºâô‡íºë>9Ó/â¹)ÄkA¼Æ%×}ñ—ÜB¼‘o4oÒc¿m Ïã“ ñƒ›;\r+ŠÞº˜{+ö`ã®(5jQ.­Eís‘ìY¸¾ÍO‡`<œª£®¤|€#c„ô¡ž÷ùN€Œù©Ê?cqÆ%ϧp}‰d 8Ù+HvÙHvÙ%¯¸¢±ð}%2G•Wá­FjTy=|À ™‡½¹åÜe&þM3Zq×%¥“ø [¢‡[–¹© ´¶êáÖ×µ²ÜcÙÓí?E’Ïe…‡íån%ûº“Yõw?Ræî'•y vød4Ó3Ô z^«…RŠf<`¨[wk›î•)ìcܼÅoˆ‰nŒxÊ$·ÇäècÈxú>®²Í‘‰î f¡Êý¤a¯NV».>ñ¼“ÝÑÜ!š sãðÀ9n¶Ôö.5qß>Zm¸cKø„a¾;Fß´`.YQ(h …¸©ºõ:Zã–ëÜlUÁª¿ë‰k9(è\Ì]k ‘£u­­nîZ;aÈýÍÍâÈj)sðs0¦qPc^Œø²$ n™pïýÔÊZwj‰ö4zv;ÞUøØùÞ½³]½4þ*'ÜòàãH À Ãn^<ÊcnMš8¡q¹Nž— x ÞF‹?¯ÈSOl §µª;mTÝ­êðØÒ9”r™ÛJ¥üœKyÅàè7jCÜ$gi@¹í–_»c¿˜ç«kÄÜ›@+Ü:$µò¶ÛÿB<ÜÓ\ô‚ø¸NÞu'´Éj&¯vî¹3ÞZÄh=â¡ÛXTöð$´ K‹(÷kÌ OTööèðæ“ìã1ðgß$(>‹÷ªfÙÏCåZî¶RC¹ÀåæÑË5Ì#Gxb¾áÙá…¾²×yÖéi%Gy ÃUæwh æ’ަ¨±4AJ#P9žNQU˜è‰úÜæÇ¦ÈUNâàðÝ’ÙøEùªÞöÍñœ¼¬6ÂØÀäíëJ´°åTUx sš‡ÏÒœy8­ætɽѬ ×xxëж³?…^ÁÛ›(ób*³\úD`ô‡åC"*dêÚÇňԫ€h¥ÛlÍtüŸh{ŒÁC©ã'6yäO4ö{Øößîá‘b»‡åÇ×ú` Øá‰çº_@¿þ¡²Ë#wyâ¾e´WÜšÞíñ+ ê2±âÝ…Bîõ¤¶ß-únƒEî÷´¹Á|ƽÊm¶e:´qõ¨F ¿:ha“ëG=lrý¨G÷àL |Á4)_¤hª“§=‰\÷KMæ³yÖ“HÒD"Û9"*dUñâ=4&|Õ€,«N-v‰¬f]º1Y«ÝŠ•†W–o0YÏÔA{ tÝ~ßt‹h˜÷=ò–Ç_ЦÀTV°_Þñ sVòè …€»žXkyßó袶V>ðĵ£/~¬¬Q B.’tÝCÿªÅµQ§_›‘•ŠF²¢‘¦ÌW'{7J¸~…ˆè»æ¾dßF«|ÁXj£DÈ¢^ÿF±ESöþÆçŒBðŸ6ŠñÒšš†"o"L£dX#<«G ×£˜,9²ô|Ö¸uÀf`ÐÄFzÿ›ØHV5 7ó« ÓiƆf4j%g5¢F·–Z¯Èø™¦a{Kñþ­j½Òÿ÷Fн##T€àÐvá°Ú^x\‹·^¬(ƒE`Kžÿ•6¯˜J¶äQÚõn!löFW–doA¹’ÛW@¯·Ÿ Ø $ Øì/"t¢ÐµX& Y%¢Á#ZU‹h̺Ö&'#õFÆõR/¥Ôr¹.³Ab!:x4>£B-l“Ûb¶ÙÿŒ´kEÒ®÷Z’Ñ_&uÿž7~"6 ¹Q „Ö›!Ž>· C¹ KIù" <ÁŠ»ˆ¨ÈUîþ­6_ŸWâ±â­6³Ü 7»Ó2mö‰vd|—ZòJ­Ú‹Ùyü^v óïùŽé„¨Cßp†½¯œò”nÉ+GãÖid§žÀûÓ+æ³”beÀrŽœýfëy!ÏŠ nHQ—A\²ÊóZ hUóÙX-ìYa’—DðÕûÁT¯É} %^°IB´:`¿GΚ@ÚrÖÒË)‘ôÅóÊT<2}UÀ˜_ÚÐ×ä¥à*߀‰à$·‘ä’ܲW#øžˆCEV;°-†üMŽSËÅß䪢½…¯L—)z|(}JQ´8&kQOÁý¯^JÈÊp@…§·âý@GßG  „Òðè4š¢?`‡¨§àm쳪 @D-öitfºÐH¸5RIYƒOY‡·jVæQ°J/wjïVJ%îþXâJV¹͉-rü·c­d‘r‚B5<ÔÔ«LÑ~‹«[Ð|¦„l^ÓýNº OG„jÅ« DX Næ$s“IÌ猧(Þ(Î à Ùç¯Àoñ$Â; ¡DAp 7 ¬É«éPn¶}R\ECTMŠd¦p6qùfFÔQÍ[x'u. à¸Z9OI–ŠAæÈí°V±2ÈB%Ć 1}–åe³ËžÈ‰åÕJР+8-uõµ¶âÉDóJ|† n£¿àøá£/Ú‚‹mÁE6¹–á6Ø‚«mÅs[ÒZ]¡~º…FN›ýûè¦ÛÝ:ÞvEîTb,9ìBš­+­/i£ÖÇ™Œ‘r ïÆØ9­"Ãâ6ž¬6s´ù?ã¡ÊmAC}ngLÏD[øc<Þº[÷dáï½1Œä,–Ï;(‘Åús}Xu¥†ÕmE›ÀÖ<ß̶‘­yõbV[%Ø–ç«iÙFŸ³Ûš{‹Àgy¾9m#ŸaÈÝé¶X­¶×¯l`ø$leϘª©—/WÀYñ®gŸb®H3MàÖ̯Ír†Àã¢kír&²]n+•æY¤¨Ã`{Pø›«¾¬,Ž*ˆ†×ÚÛ4à ¦Ý(™å9â%|ÞçâQѲÞK%‹4C0˜³‡ ÷¤›Ÿ»•4«­ó•Ù Ñ›^75«'Ý‚~7¿®Ðï–×Íô»ô‡úÝöº•~¿ø±­ZFCÖ_ YHãñyU¾B‹»/Uù£h"ò•*_Ei.¨òÇÑ-rY•¯áô°^•?¡<÷Ò¼cµý(*„þªW…}D,XºG±˜¤bÅWUᄪVÌ—T¾W<@Dá' ZÑâ+´x žEÝvBû Îhïµ4r¤ðŸSé7&"+É!"G‘CDŽ&‡h#‚÷³äXú¸¬¶9§ÚÊΩûåxÁ†¨l¶nÀ9W/«¹nèÂ̵vÿe5x^-ºLdÌÁ‹ª\ ‚_‘¼©UµE‰B…*“G®%HM (ux_!}"ñÒo&–+„¿<»¸<Û$W¢¡4eJœþ[SÙCÑPixÊ”-²ç#‘½1üís›©5ÿ•9T1ìu*r¸¢µøQŠV4ÌÏcŸl|b‰šXqŸlAÓ Ó†¥‰ˆ‰C«€z?¹4jòïû÷ó¨QJÿ߇Q㜊p µ”ÐlyÒ°QçV,ë/®l ÈBW! 1!àÜô(#"G±´9U÷PE‹Gn¨rœ AâJ} V ÜÄJëFÉ×2®ê—IT¬× 8Ë~­ÀÙ0ÃÙÕÒgØËÖä yݶSàHèoªr ÐßRѶ‘Û*Ú4 BwT i¤ŠÜU圯µ9®èz6;EJ¿ÄJNψ†oP=>T¡KÁ:×T.5M–¨Ð5_Ê\¼·×ÃB×Äé¡…ï×Ãk…®YS®…Ðà ]SF?L­çÕæÓÜ/Bv|µ…%§žÍQ «P@Iá„€’Â5]IAž+Òˆa±¾N^z›¹($-”xOï,¤Lm§ï:Úw4|“ò„Zè5Œ·7i$»4‡M  ¹c ¹#H´Œ¾¹§rS¿¥–)x‹{ a¦6k±&¸æ{¶·"û*QÿÞ–±ðù§‹ö¶‘ûªì§h¸ú+Q¯ „ `‘5HñŸ"ÆÜW‹O"Ù´%˜8[ïïÔ·Ñÿyÿl8¸M3Fj©ÁZ#u%¥¾“L=©ïPjX«¥~3¼¡¹‘z¥¾Ë©ÓYP¤ÔwU½×A¯1“Òåùëô+–ãEãÈ,.1zÌQžh¿óÍÅÙÁ–âUXp+f«í¥+Ûò-½Û¼ ñ‚~Ñ|ú+jŽ\òmJ~ÜmI·Ú†(ˆŒ°¢7Ì×Sÿˆp÷ˆpïˆpçˆp߈`˜·öòß7UîÜR¹Wü%p[ånñï;ªÖ/þ¸«jããàö<ÃäDý\¾­n~½ûM¬Yvl“ÿåÏ1" [|Ôgþ;°=OþÝïÙ›—¦ùÆ5( ¥½eJK+rˆ’íyPY’ÿÛJö„=H=ªÞ,øð§7µ]šîƒ§¾¤®Äï¢#¬?¢yÁZØ@„ BXŒúV…Èsý æãàË£‰Ž¡!ö®'h|ñ¿Ím¦ÍÛ¢ìíZgâ±ðWÉù§±Ðÿ¾Ü%ä$ 9É#aªSBÔÌët–Àß{0öt!5{ÊNY»oʇsÛŠÖy¾ª¯úG¾Ïùö¸}Çê;ý³?š#;HBìÓVùc`g"çüèèÙpçüˆ‚Èý# zGüÑÙ ùñ 7 ûö6Wvdw]2î^/†g‹îú=úswDÿCë?hèûÚ"ÿ—ÚÌj»,ÃÈG’DùveÉr”ò4‹ÃNÀœ†0‰sg¬ð@ Dhãž_c¼¸Œñtg–¼"‚«³x¡±"¸&«øˆM!Î2`Söá~ÞãeSª/E³!8ˆ:NÑàï›@Ê`ôsn³Õžõ@`¬Y¦Ž€v”±Ð¯€†ÌóåP‘‰Am&ÞUa«ìc.øXK¶jfY-yR îÈc}çC…PYÂǼ“„VðvAÔB”ŠÖ´’ûH4ˆìj¦õœ®g"–¨ïc‹R .zšÍ‡F› V훩°Ê‚B©xêf‘öÍú)„„H–Kgcl¤%ìðÑÂ* ‡Ý¾UœQk±^ÄÅAq¸°¼Àr¤Ð$h¸(4)Ât¬Ðd¦ã…&Zžw[í6ûi38µUÑmg–Zž/×ÞN`ay+óGЊé3%°&+Y“Eë(ÿ†,’&,±¢ YJy­Ü¡ÄsÝÃ`ïÉ÷”Ý1úOæÏS¶ÄZbQ‹éç’»Á°hxµŠƒ£ÕhEý]J…¶¡³Ú^A2ÒçJp'­ö( Ø²×ø*Ëä·ó¢ ÑÈo'Ä,NˆVY§Pãá]°ƒ”Gú¸äZÃB˜_e8A2žëí}]ò„Â,4†ªßIBÒײÅa2ŽéÉ¡BJÂ(ðóÙ`¬UuÔïfk*ü5ã¹Ù.?ä@Zùaœ5;­¾ÚŠN’¸ÀU£¯’ l;sÎ0TQO¤’^Pðä`¢èd¡óÁ†¢47P"¨ôöqpYä]Å¿%+K4-Þ’¥)_ÞçÒcã°ÜìßÈõR¼1KȾæÀ꬗"«³d?\ÿ’Dv›½×öpsª¶5ËÐTÓÃÍ\Ó#Ír¤™ë·ŸË¨ßJsŠ&Šº8\«ÕÉ:v‡ÛÐuÔ¬oÔ5ËãfVþGÆ'̱¢S…&_ï–³[ËSæXS¶ x1¹…B¯i[(‹³ZWòß{y÷£· ±ÊæÒ#â¾§¸™f‹Õu%Æ»p~€ÉÇGQõI±ˆB¿ãÿB‹&‘X4ˆ0yJ÷[„y#Ï1óÚš¼]y¾ùm#»òðœ’x)°;/¸È! ž.ø~þH‘_) ž)h\ðlþ(‘?ZäùcEÁs¹Ï4)x!œÈ/ò'ˆü‰"’ȯÞ‚ ^*hZWÐ,¿ZäOùSDþT‘?MäOù3DþLQмྂü‚´(hYðrþ,‘_#òg‹ü9"®ÈŸ'òç‹ü"¡È_$ò‹‚‚W ~TðjÁ ^{ç͒ݘŸ¯¸Ó_4[Æf_‰äx‘ªÔN*ý¹èÏMúkDOÑßwèï»ÐtiLžgéï9|äâçyújB/П7>LoÔ‹D@ü’ª7 ´ªûæ¶üˆÍ?׋ڀõ_Ð3lïÖ‹­ö@½¨ ¤…)ÜÞ¡^dàw0Ù±^ duª‡ÙëÅ‘€£ É œ®õbæûÎ?“ߦþ¶…]ÿN‹§÷Ü­·~èéFéßoô1ž¤{ê(}}§;Ì~÷¿ ö½ÿ®ÇOÿr|ÿðŒÎ3ÿ¨'ÿ—ÆšÀ³e$tÍxÿ¹äœ ä–“óEàùžäœ4é%ä/cámÞkå¯b^SÉ6¯l…×£¼oNíV'í}3QMîo^áM«ÊÂdý»„÷Í* këÏL´É<èü3@UÞ7§à!žai“?&1ò_ñ°Í‹e¢ät¡|ß+JíPìM—â‘Ê¡xÆ*áM«nt–&Œ€ñÂNšlÇrñlSBÉÓBöj¼Çå5O›þâC1°íëµ4:Láü%¢4]v(øI·Ò É_*J3eÇ‚Ÿv+Í’ò—‰ÒlÙ¹àgÝJ²KþrQš#»æ¯¥N›Ýmܦ2wé÷äû3½ojezZþ àûòà<#¦æ ™¨,üŸçÅBß+þxa¢ q9ôL·R/IËzVXn¯ý“)GÊÎ ãëÓ r˜–ZzÐR£Óò‡¾CÞy—Xú.yÔ½ù1=k£çî=”=•XaÅ¿7/”^´7OÀ“O•À¡™ü_–<ƒ³“Á-xç$ƒì£yÿªÛf6[^Æ5ž—g4¹ŒWØäìx…VN±¸×Z Ÿ)ô¾Y4Ì¥Ÿ-4Óò‡¦·¯ÝŠÍl©€®­?Œô0™¦+xÿLÌThmó:‹FÀf{Âx¥e½‹¡ã|@™KÉ´1ÏSXœ›¯ø¦¿+ç*$ÎS¼iH[‡šæ+4j[a!4].T”¨hG̾ÏWôw˜ð¦ä%¯j-—+¸k|%‘,>Ú×Aôõ¤ B!OûÏé2HÉ #\ƒ rÃmf3V¯÷‘\ñPò/²‘œ+÷½j¹nçd‚œ „ ‡¼»Utå«€|ѧž7½ŽŸCz+|m1_HûeÌ7ìÕhÉùBù«¨ÿµXÑk"2Þ%ߎ†Ç»|ËÑâ‹B‘­]™Çl±XW[€"€½_Û”§¹ýb@eÐ+jeûhxª«R{Æ ·ÕÇ»pQ *.àG"¿§t”FÀ|·¯Ë.‰àh’±ù7ÿh‘(-DøŒÆÇnµòÏlØä߀ì”Pw¯?¦Uát—ìƒÑ¸ü‡ÿç±¢Ÿ dPRf—ÿƒmQ%ÿ¡E…/Ú*ù–q™H¥ °—\´É^"<—½X§ÿ\v¬è\¶ŸÏÎÍro…0ÂÿùlÙ¶f,ÖŸ© ~¸X¿hÖ_ø·fÄŠ¶fˆð¶ |@2ŒÁ·eЄã"cW|˜ 2ÇPæhxº‹ ]rÆF“f,Øv1«Œþ¶Ì·¶"ü™öhD%Åèû¥’Ï4m2p¸:F/™ßÇ>QÜÓŽ¤Xп˜•ª„ß+ò‹—Š—gšùzír ð÷µÇ`¤ ·¸?MÓ€rxÆÔ€r_*^–¡Ðƒ™NÐ1[ø?ŒÁFçlX–M…/4ÂOä˜hV FÔÃ6ù{´¡åÂxÉ@м þ2<¬)+•‚U«DŒŸ–|fV< ]«¯¸Ün’뀶œÑ¾ ´› ´›qh´KSh·éh—&Ñ~ðžl û¾Ûß-hÚâ,Á°½z–¹ÌÉ(€zyÌ6‹õ€Ô1>¾òcÌYô¡é‰“—¬«±Ï­œSÌ_šbšÖâXíí¸=¼ËN’ã|̃öÒ‘­åŒàí.N²Eí"èï̘"¬¬‹Gs„5ÆwADýÍCV<…6Å¥=7sQ¼T‹]óGóØd YÆQ‡¹)â•Ú;2Ñð4ª—oQÕâ›jWÃ|%¬ð˜ík¹‚–+Z m¬äU®°’œK¥Báöúhƒg_EV(Më°Ñ–"‚Ͼ /;é%µöçMt½¤ÖTIm4O„lÜ%†'ÆÍðSøâÜî†+(´­a¡G(/Õa¯ü±üô1y0{’’x¬Ø/±²Dƒb#›É©9EÑ3œ†!»·ÇbµX+™s˜?¯cÓ’s6- gѯ•¥PGQؾ¢¾÷¥0Q³i^j‰Ls…,iò$|% \ >®90έøŸI=#ÈCmtlS¹‰¢'k»È[•àÐï„÷4Saêà3|ðѱãnÉžfr;‚õ°ðÎf%;šÉ ƒv7+ÙÕLîVüE„n%¤Žò˜áâmÐìM/Ì¥¶ .'`jd‚KÈsɯ‰.̓ÔJ‰BÜúx³Å:Œ{Ã}æOS¶¾¯È‡Ê·Î ÒfÑÃ,{˜¿1/Ôò¹§ìeŽ[-fK¸½ÍþVñ¢V¢x;Œ;ðt´¹•ìoŽkp²ÜWñ&â lGôõta}¤æíˆ“>Óh³kFvÍk};_ Ÿ/ŒÇÞi¸Òσ#‘§z¢¶69™oÁX5Ï#z #ôªiŠYN3RÅ0“NG¶RˆfQ–d”Žh` Ñ\FtðW¦¹ØWÒS1¢@4(…h-Ñ’Œü‘†hp ÑrF´ýMÓr³\i¤bD«€hH Ñ Z§'Ñ)ú4…h##ùªi£{NZ*FÄ;OC=†CiàÿR`&“3Ö…0H&Ã(QZú“Nc‡{„HÏp]¹é–„ƒœ–I^†%)ŽÊFØo£-|_½.3RêDè{D÷Áá¯@r¥G(zDPßh J¼ò5*Ñ™ ºâ F§ ºéÝä'°RDä¦g¸ñ‚ éàgTô3¼Ô1–8®·¡yØ[Ⱦ%Çyœ®ôŒˆÎ:|Yy¥Ùy¥Ž¼Òœ¼Rg^©Ê×Ó† ¾ž§> Œ"GÌ£Éè·à$èøï¬cÉä·#çJÀ>žœsJ›@ÎÕ@ú$펌)ÐZí=˜F‰¨¯> ¿<4š>$@Ýj } ôk_VœcûŽÿNû²á4Û7H³Ó":껢!)M“èëÜŸ´¸t¬¢Ù¶z« f°ò?~@+„OÁ»e?¢¥ÆTZuß+€àIj†ls$"Ûr–¥ù¾[¿PI›ïº mÅ5fÎ…>á‡Yóp6þ~ö|r¿ïX€Ãô@Î"!çâb/-_æ±›-ç³ë nVš¶½êZµ,A6kt{9üP"-i¼1CÞo³‚cX]§ùÖ6„YÍ1Ù$bPÌà†0ë8&+íLZlYX©|“žoŒÅv&_ ) ÿ$‚„²È 9ð“Ÿú)žûƒZY‡²Ø@‚íláS)@áVZ’=ê a%”ýxh6 ,¡œÇCsäv&d;h£µ›Ü!b^%dŸ\×¹Sè´íúvÚv£¡Î¶—¹ªéå9±X×Hv6$9fìlHrÜ ÙÙä„A²³!Éû2r?Ó¿Ÿé§ŒùGÖŠXÈ^§?Züêôøvú>‘·‡žÈÛÃOäí‘'òö(ÓvÔàí±Çy{Ü íÄ·ÓvRç­Óƒ3Õ:IÎ;ß$ÔqÇÈ@îÔ¤Ë5ʽÊäOhñÿ•ÑÄBjH-~˜cÃ΀M¼H‘øu—§î²H‚Ô|µaÎ_ë9gk9£ÚËüð_ jæzªfn¤ðßL‘t ·4’n?NÒÈ]ƒ¤ûJÇ“žžñ2FÒ¾¼@¢&‰“ý• f³YFÈ8ËUÎG%•hìmªÊaÓ‹äôŒ|€3@‡ñ顦€ l/b$g¹d%¤–‰œa ÆPãp|ËÉ3øØ–•Ë `&ñ´âÀTöŒ~øŒvÊýiÏ1ðÌÑdä9ŠœÈêÔ²„“ÐBa‰"—!nr*n5Ç óšV+r-â¦`ªM{E›&û/6ÔÀÿçÁó-‚_òß{StíûÈLžY1Oõ@÷ÞPu§”–´¿ Dó|ý[F¢yõbi[¥4Ëóh‰Ñç²¶æž"Ïóõk‰ãašÇf·Ù‹¯\вOW­Ñ”Dk4%Q8}^7Ùþ²NâukÄ|VÅaد­´$„‚å—¶œî± ›Ý‡TqœôïTÍô›TÅÀ0[ ’Džãj3Û[ã3À«—8B`ý— %Ò§èÿ{SùŒh¶ qàÀLyÚ}“ËÛŠßy¾m# *òʶʿöåùVµì£ÏÕmÍCD`žoMÛÈ~ú^ÛÖ²@jó|ëÚFjé{}[kLêò|ÚFêÀ¡YMöF€ú*r;ôKÓW‡¾Ò8G¾nþJ ÍeCV²æÃ\—¼~Ôx45ZJVLíÖŸ×@v®«MÔhg{ 5ZJèõ_N©ÑNƒH‚Qø9cíez6¶55 Èómj9@ØÜV¼8˜çÍ(9H_[Ú*G•À¡¼>‘C°µ­ù¸8œç}=r˜>·µµ\PGò¼oyáý¥÷WÞ·½EÞVÞÖÞ_{Ûxãý­÷wÞß{‹½m½ÿìýƒ÷_¼ÿêý£÷ï»Þ÷¼ï{?ð–xCÞRo{ïGÞ°·ƒ7âíèíäíìíâíêý7ñþ»÷¯ÞnÞ½Ÿx»{ÿÃûŸÞ¿yÿËÛÂÛÒû²·ÐûŠ÷GÞW½?ö¾æý‰÷Þ‚wÞŒ·çz,T«/\¹Eh6PÆjÞüsd•K¶†(ùëhñR—I¶ÁWÅb±þ i;b]’Y‡·€M±X]}Bv®Ø/»zM×òám½¸Pþ,ÿ /wÅÃõ…ÁÌ>x¶ý/± ËÂÜDQUK¥ ñ¡ׯ‘ §·Ûh­Ñ ªË]òc¾cân»C)w¾‡–{´Þ }¹2j™úRsxð¡èË÷48·›‘sì]Ë!û‹„×äIç]#!}\'‰øÇ$Ú ñDÕÇ$Õ}Š}Šr`œª¥¢ö0,™ >¼Ê ¯pÅB–¢U-EI=Q¢ÍKm6´ÔŽ¡¾d…+Ížfcµâ. ý¨+çj¯˜íú)4ÏD´x±“$G¯)²Â¡‘RÏv‚öA‚¾&j_ŠöU%B–¡ z¸ÀШ”øÄ·sðzñM°d‘Á’ETú-ïŠ%‚„9ý ª–¤¸x¬øJ¡ËD\;“[.¢ñâÅ´*]D =–t‹u63w‡i‡ÆÜsáÜ ˜?g[¢Ìck\,dðx·ÁãÏÁ{…¶ñ×­¬#\…C<flI®ïÓ¹ns×4ຕÚ8pL·3ÓÓh:LÓÓÒì¬Bù ¦ÛBÖ$ÓêL?f0ýxC¦Ÿx„é'aúÔ0†‚èZ×µ‡ò ÍØ”瘶ˆ7¼~žiŠTÔ!®°"Ñä5Á(´09ÿ+"Z´Àe¢&Uh½êkV5_ì1SôÇŒÝeŠÞþ{( :@¹¢Sß“=+]²—Ò JÃbôV£¦¿%쟫Èe$FÄQJ´h‰ sîR•ZPŒ+~ Ïš÷¦iØ®AözÇnôàý4U£®‚‡òr<¬)õŽ ¡³8uŒi£Ä‚Gò4ê«^e:ù8v^óL¯ešF=KJl™>ËH=_aV lþ,H"­7‡ðj  @7¨- ÊÛ+‹âpcZ¢aRØÿXšÂPïÏg6„Zž‚ZIPó].XÍ&‘"^éòZªš×RÄÓïo=àÁZJ~PK¾Î¨`ú²äòžxû=ÿU}y?–÷ó\Ãä²Üƒƒ‡vßTý¬­ Gó|ÛÛFŽÒä±£­2RŽåù¢oGŽÑ÷ζæI"p<Ï7î•ÈqúÞÕÖ2KNäùv·œ ïMÅÖ¥è¿ÏÚxowõfË+W (Ý·ëN婸h±CNåùÿÅÍÅw÷¢Ø ¢è¢äTžÜƒDxû˜‰ü€±G‹S>%øE^‘"Â_c7`5/³Å…x‰ø«‚b÷=xŒØ“žn¶” j*7¯)o˜¦’L7õ gö œ²vf8ÓÞ°À™þ†Nv685oا*r2¤_]¢–±7”V|Ç“F-ƒJ¸†z£Ùò,rÚlÜ.ÚÌ[~_äÅŠïz„܆dkSÉöq²òv¦}Š¬Õ’Ý£duH¶Ž‹äF²3è1ç¸À÷=è3ë9î)Ä]B\=âŠx°Ÿ‡ –ž‡U”æ7&…üÍMo 3¨1¬fÆ¡1lzd¯§¡*Îf}¯§g;ùCÂA°Ë–¸Uå±ZÒ3þaÿ¤ñù'Þ$ù'ìu(oÊ7ŒŽ7yŸ¡Nþ"Á› ¿LxÌUìn…Šâ´ŠùU‚—G|­šÈ[“b3aÆýÛÅæ™†Ø¼†‰ä»Yž†gj9 Jó×Á¯ôj‡í©z1¿‘é·ò÷Á"|3ï~“ÿSÉÍ<ÙV ®siv=P–ÿC2»Ý¿Ðg°§()o&ÿˆ‹_[†Ù²É ôÇx5¿Ôž[Vƒ¬ùx\¯â Ó1jXWÞpÊ~¡À)ÿ…N¯W,p*ÚYO“ӻ팂‹Ïö³Š<­Ä5{¥E[^üîy%—½Øõ+úÇe'ŠÆe‹¢‰Ùx&×./(þ‚=³Òþêoiš¼¨hXBix–ƒ.áÖešþ~îeíƒÐ…BjT ˜}“W¨ÉëOðÚù1ίm;ùªìò´-ÛaKxD 펂Ç! Ȱ4 ãö7ɸ£øó™ ΞRïÃñqº¼ ÊÒõ×|íòBÓóÝnK5¿×D‹a!{š¹Ä!ý8`©¯—™£áÚ€²û¬©¤ÕÜîúêiÀ¸,÷Óû%#¸¿Yã,BªÉ[keàÉ öY« Þ“×ñ+((눙ÄÈÁ±rÈ7@«9EµüÔœÊ`¸^4T1ÕôCÞ¬·p‚¢g0¢¥ZJ9R+¬¬47âõZÙGix-?[Ä;<1ö*h˼5;ç9S!tÿö1Êöµ’xÉv½KF¢þ×`–ôÖhv½QˆSè .ØÃë]¾[-¢áÚÅ“N°àÍhx“Йú¶‹†7k]8 lѺr@ÏW£á­ZÀ¿q@o ئü™ÒÏ´€¿pÀr Ø®ü;ìi ïÐþÊý)—Z@7XI »µ€9àÆ[Ñð-àXM)>׺sÀZ HhÿÁë(`ŸðŸ0€r‰kÃ…M+‡W hÁ0”d· .˜èÕ<Þëb³M¸5,QAÑTÄðdDoŠˆ¥"FðNO6-Zj¹þFññæË”6¯+ÞصîùŠ‚]ëíxå}×2[Ù¯Zç9†dãµöðÍBÝÅXíûVaÐ×'øãD\…béDñxÍ#õ$‡1ª¡ƒ¬ÑÊš“l>›Ÿå!w®ðïuÇ3ëe“óHF‡5/l . •GÜݣʠv¶E‚Öþ"Þf‡\$¹OðÐ/8ѧyÓ¦ØJ¶i¦¿|E óÆ_ÏWh’ð nGK.ËíBß¡÷iÂw ÿh1lwY¡É…›Ë8b^…Ͳ’µv¹ZÐl^¨Yïö¤Ù-ÖüÝÀü%8ówƒÆßMgBÊf¿[˜±–­Bn¢ü’\ÝL÷ ùùŸ:¹¥¶=‰5V’•âEçì¦ÊòîÍqtÚ,d)×_îõ7cPµÌÖå¢ïZw Zé¶*ú5‡Ń¿ÒÆí? £¤6µ°lÑøUrô»Pö²…{šƒk½ZÚ¢ù¢ä~!-¨â![¸ˆ¡ü{T•¤‹a*Q¿ä•|ñª¡FÃ÷²òG•è?U©,!FÂÖ Åê±£,ÚÇ€öˆ_7Ôr[I°œ)/)®€ÞO‘6Aã%މâŠ8ÅHÖâ› º˜ +ÑðÀl6­Ð‚÷—£áûYon!¦ªQ|†7·(˜ë ˆ=XÆö°E‡¾‹{hÉ„{ŠgÓŠW’;äFýNªì•Lîl›ÜÙLî\UÌM£ C²½ÙRC” 'φ¡†Ï±\Aí‚¶Ô04Câ—½,Ýd¾LK—hxXv4<<»ðó®dÊæU/V±Ðr%<Žf¾Ù¼wµFB&0Å5±ÙMd³ÞÎf=g³Qf³ÉÙlj–Í–fÙ°•ëæÙ¬¢l¶!›c~Xú?Èf·šÞJ=kí1ø&À^Cì±Û*k]î{Èêàõ’¤ö7UÓ`÷à!¾jêÌÉõÏæKèQ#ö%‰nª‹æ:ÝÙÔ$ö9´ª8??¡¬_ Ž Èó“9Ê“¥ë½€áÄáS>˜‘ÖàN0¥ßjœZ$esúßv<Êf¾ÅÙ¶ú¨x ;¨›‘Ò“nñ„-­÷ŠVf¬´·&ž„áx~„ +8ÊÊo.åWç ù¢H©ž‡i öë©©éË´ÆJ´KÞè€8Ušs€â'„'ëšÏ4p àQU¤Î4Älª§j7{^˜ct5F„5bب!k‚„ëZHûó(xA‚m„ê3j´.øøëš÷EÅA­/VÖn ô`ÕüEFLÔ.¦8ùK¼Ü¥;ðž¶ÔKéR©­Òœ8&à½äpä—}‹še‰¾Ô[Š.» ¨¯6¨eRß.ûVxl…¢fI}£<ðê¶k Ökm£üFðL –)ãJ4Vx&O›„ Z·eƒÖM©X]Ι¹½©)ãÏÿA@_—÷7|·ÝgìææÜcˆÝ2yí‘y½‚¼""R"Üÿ 6º0˜Ú(pYyï³óV’óÞcç½’šÛ1£“z_¥V°ÓŸóê0m¬Æ~™>óëNO ïT¥oZ'™oòAæ›<Û¼C"í'þW4­·¨iõŠBjZǼ¬Ïœ"~>•bYîý‰É“Ͱ¥Gh p4æéâÝú ½>Ù^¼g†/y±•¬‰÷ ú>AOµ]Ípƒý€ „^ î ‚føŒÔp("`7½ Bfø¬Ãx‹_Sà_‚ÈûÙ^üÎ|k±Û-ù£^ìƒÁeÁ ËW|Ûò—­Íõ`ŸŒ‚>ö"ú§`ߌ¾ñgØvatߺ¿ºÞ AëË µà>JhkJðL:€–òWÁÙ6ʸ÷­Ú‚úóY?œ\gn^àËéEŽK¸TÒI¹¬ˆK„ì‘ý¸@þ´EþŒ¢‚*eß«ÃMŠð)oh7|,Ïï•æÛògIG²û3~" ×XQ>•Q¾ (»üv’¹rTF¹NQfű´`užhþl"nÃá¯NïÂTί¸GHzC3¿>˜ïC’ûJèp À #Ob3ÏäÏ|£mù¤^zÐ+fóÃûåïÇ{y} É´«O²ž¾ª{[£wÎ)RÊùR s;føûÍ0¿!†²=+€èQ0;׆­£ îÕA:•¡vbÃY¥‡po3HuÔG W=Û¹‰@”¹§FQ_ÅÔhÇãõ˜·˜n^Oy‹OyÅl–EZGZ‰‰xý¤Uñ'­Ä$¼F[G[acNÚ„®S`ï°7< Î4§Z_;ÀŽr¥ ú¼ŠIqGåßy·xMЏKÝãˆ7ÆX“\šE¿¡¥YáêgI‚,Ó¢ÄÑ“Do/zœN½50úQÄ7ÑWËD?z˜­Dz ê h1^+eí(ª‹Áô jBª¡ôX’ÕyiVK.˜®ËùHì48ÏÑÄ…Ñšu;f~æ)c5.`¬ý„*hr¥ Í]lê‡E¢qZë7D…fzP¢Ð´X~¤3 =QKzŠ ¯Ki©:”¬Rkƒ-Y¿þˆ'íˆÁÒˆlÚ²’7L¥¶é–¤7ó™9³é±àUuŽÆš—s5n® èÑð¾-Õy] é10²˜ƒ®%HPäÞ@Ú¢Tì.,òl×Ä<Ã^±@K´ëZzP]D¨"ä•§X¨áI6A§ÕSÄ"Öh;6š×e+tb‹Gì°I½D©CÕf©ö!n/˜áãÞªRjæË´£F‰›fú¦v¾R‹°XµZë$6j¸»Ö-UlÒBOÊ¢$•E…-âÛ±OÃöCÒ2^„œ±‹%i|¼[+ñ˜¶UÒà6W‰§`›K)ǑأAÉ]ìÕJÒ6uK;èI2í2ök<¸oá^QZ=±jqQúMÔkTâ£>Ä!ÂO•QŒ¬i0+ªûa´ô¤fÊñ;+<ïÕÄ)­5¥<­e¼ìp°Ú 2ÂT;‚`¤1?z×Îæª–Á3ŸÆêà´8¢ÅZŽ#òni%é-¡ÚyOâ¨|6RÒ‚‘41’’¬P¦›90C×W°åïáîY71§Ï+¥^1H—´ ´Õc¦-„ëÍéÉ©™a£t&hŒn4XÁìª's`cŽ2‡£œÃd]ŽýS°9ÐÈ#ö×ÐÈ«í½•j]ÌÐM m… 4DÏD¼+~ÝãI+w!bž˜z±þÝ’ù›™ôîf$5:÷‡ùrW¡VgAo15é[tQ«[B”X¨'ä»Å:Z uKõüH±n™.åºu$Á­@À ]Jv+u)Ú!`5VëR¸[£³t‡=Îõ€¯×-9mƒÎ‚6!`“.?lK•ð-zhÃ#,¡oeöZü Ù§¦Ü{­ðÖûÆ^]|¬[bÁ”„X°]‹;ô¸X°S‹»ô¸X°[‹{ô¸X°W·û½S|¢Ã€i|2íO9Eôfó=8ET˵˜åQ3Ñ>~—Ñ~š“Xá¼NÇ4Ia|@õzBl`Óª‡“ÛÒ)=I"ü=x²¬Èù¹.>׃£[›G·V¸u`ë*%”Žå™a!¥ä³€k=â^‰ˆõq^‡E×ÞâuqßOz‹7xÄEzf»R|\—°Sp_wd|„ìn>Ÿ‚ý«ï¹nêâŠc˜Ç ·FqÛ·®\Z·¤7JR]©Å ñ…„:­Ð‰†¸FP+‡ëôŠÄÍf¥p‹[z‰»y)n"Kq¯²wñÚè _v¡÷¬¯JrŸ¾¬|šè•óémX-hr¢õ1â-¨¯oAýŒ(L1P¾­Ó4Ü߈·¨F¼E 4â-joQƒ Œò|7”–ž–;Ù¤fÍÕ?Ì(±"VPõ0’…ó‘†)wˆä£ 3§˜f¨1Øã¸ê‡ƒ'14ZzÏ ó¡±Ò2ŸèÅÊ4½}XÔ™áÁ¾Ò&/-è ½Ÿ îs`œ!/›¼ïX Àˆ}¸Ÿ¯‡år¶Ó9–{m17yÍ🠙kAùjpÔ#æ)¹Mo°rê~h9…ï{qÔ yÂsö‹…êé³A“ZD >¾Ö52G‰m a³âLFœÅ|½¾&üd€bؤ{)å=œRÈ„¡íï"`Ÿ­‹¼O²$"°IæXå_*ÁiÁ´ü‘:§Is‡Á ÔÃp x„ B ÛΨ[#@Þt¨zÖQ®²b°²‚žð†Ü×G *(¸'ð,ž%„§ÌÕö‰«T‹ÄU*ó)<Â$®Nª²õª$qTœÄ@=4ú P¦¤½€z£~'$jŸã„J‹Ù"N[èFÇÑ}tÃèî] ½nD‚Ò~¶¥Â~IÍ—”‚ Hmj°&Q‰£fã#¨'C§~*%í Ô£2¡{çGôûIn -~Ü,Øn@¡|t¦æ4\w5„nd¹V…íûœ¾X[ì{̱QªÝ÷óµŒÁC²Æ­†= |¤™h2T+)èc ÍÎÚ«G¬65l¬e»f÷€Œ‘XˆïS•Ý$«­-Ri$Þ›lý'¢Eðž€Ç´˜ö0/KµhŽ?…ˆ#ˆuL‹Ž­ÏXÙèd<ã2ÚÀ>×gZ44S‘&cÎ xSÁgë‹´‹ä;;Qƒ-˜pÀÏ{£–ØáJäý…V¢—['zþ†¢>‰¸ Ã--c!(¹ÐÝÕ`#Í ‘Ïb |ƒ”Ñ×¾´X7#áâ„Vb<+¨Ë?‘OB¨Q2^#È çÅmÂ~Õó}@’¥Ñ`®.?ÒEÜ·!:üÆÃi®‘¡â×e<1´©É8z¿IÜoúESÓñ‰>z'µL¦ŒU༪I¤ŽTogVc¸Ù<ÊSGçÄÔßÓW^ÚÓG'5¸±™ºÇpÑ£‚…@UºßâMZjAnOtTè°ž¨à±OU'Ò£æEm=潨O¦Çª÷©ôØTäüˆ›‹R>ÖÅT½ N/têåm±ñòl4GtÓuxl­s³éŒ‘OO4xwÑí&Õª»T£‰H†X®'*8i-ÉÈŽ/#V~ë8¿ V´ÛË'ýælÔ#œçfÑ¿ºErfQÚ±$ó|L±Æ’²“ªó«)¹ðÎ6fvë­±«Ç»Ëj˜ûAìù‰Øôî}ž,Kt´nûlŒ[zK>¶š}z¼½ÿ€õ@3èùzçLrìCºÝdÙþêÄŽtIÄæwž™Ž"hQõôÎÙgDŸêñ†ŽcLÞ†øL7±ÁQÐäUß 5Úë®s:ÉxføŽ7Ñûù[ŠørMÊ»JÁM£FC’^°N‰»sÿESÿ:XÅ-³JY¨¬à7G9Æ,÷RžDoPÃË«ÏÃhEmí†lkxl-RoÑc[‘ÖË  “Ã}6øt¤ài¥;ö'éÕj€t¯'qìaÃN_#9u4‘:šœšZBãa#Ç`ƒÆÛX‰^°½­ú†úì;]Pˆ_ŒPÆÉÒŒãÒlæÒ”ó9ÇL¥?V™Ê .[å9"•© ”EU¦ì™JJ‚ìí"Y `“‡•kz†h†è¨l3Z¶¹vÙv¢líþ½Eú)Ê Y¶ñ™:•m5— Gwñ™…ʵL–k™,× Y®8Iâ¶)P”¾Ìm%^Wé[/Ö>´L[š¥Ž&RG“SãZÕC˳Ã*$˜‚mµ7Ôoü¸+ŠòËQJ…,S—é—©îKeª“eÂã£"õ.•i' qئŠ:Q„ç,žâ€Jtô¡%:”6Om––ÊóùCËsÞ6œ¥_DÙ‚›:Ä 6uPèIµF/Ü*…x°ÜV;µgÇ„LÛä?üƒ`U\Z_¨t™mï[^„@Þž˜i‹åÕ,–ûà' Hd/-§Ë¥ô7Ò&KåìM·LŸÍ íM+>Ëjþ<÷d5î`]-ÑÞ žÍë|6Ïñ¦ÂúZ33m?,á©à4&å·ô¿K-íYÌÊü*›„³©uc¡Ò¸“–lŠÉçøvƒR×Q¡ßúŽ*ýè¨ÑïÁŽú·é{÷_" lŠOt$iªO¼LÂ~¥O¼Y¿Ê'^…¯”i>ñ3<Õ—ÃF^§áp†qß0Õ°3§ûòßÌÖ¥c|â-³Mi¹OÂÁ±O¼M ŸxÇÌm*à?]~&BS¸ûyMü þ™Ðkš~A¼ù¥)on&4iŸø÷–üø{ñD/eð‡ï u7 gûâOpf +b¹ø÷má>õv)ejƒ²»HíÉVÔ´^*jÃU¾ü>í F´SÊ`/#<Ñ×Ëò‘‡÷p…ÕÜö÷$_/´ÆpÔ™>¸£:¤êZH°ì(Ç".ËJ`k4pârúdË!«­$k(ÉF¼SÝoRMj5>¦hŽ„n;fû(Fƒzéácõçêo”pí Ïœòø\|;íI—–Û×]i[ßž ½`{#…ûY7¬¼Q‚âÂ0Û”Üq‰Ø¾Wí¤®SbÊ!îä«•¾ê@•釢¦¥-È„!®ƒ¥¦ç›RÑ3’ãë í´™áñ¾_*Lâ÷•¬ý{P ­;J™Q:ÞÇ+¦ñ¾HkTëQTkm&®¼¤§ø4CÝQFô„óOŠgTq†šV ½êÙÑS“.*,w:ì0£è¥Á13­ùáÃxCôÕ2~ªP”<¢;e%ö×PgÁíO£õi·?­ž{þ ¨Ÿ‡ÍçCUhÜ^¹Þ žl—)"Pe~´¨é*áÜçI—“–|7r%Ž|øƒXFþ#,c´ŒÅ65ŽeŠf·³Ë)Ø—çÓЩq`cX^I«âÀ©®8pZ8Ÿ€Ü¦3HƒÉU1ûAÂçþ#Âkµœ7´Ÿü­2ZYøÂOþvBYôÂbzÎRÑŠh½Ž%/8ÔTÇÌ€C£–Ü”îÐ=ŽY‡¡:eBãçïhË5X¢ÿ#¦ï~ÇrZ˜®w+xìó©+5vÌ8þX/Vi±(^ý¯JO ÚM¬Ñ8iF |¢ñpW¢ÇæK½™erD›×òõ´õ´€ŒÕ¼÷b3Ÿ)-΄fbO¿vØ‹þ]šØ…å"º©¾‚9>­~Å Ä`îIb1°ÊüXQe„Ù#¢´¨®À0$$“iÐ5«}¡:øöƒR5¡8zô²íQVû"ózQ… ÂÈèý”%½šÇïe]/ŽXaÙˆ}$sôþ€÷/˜ëS{•³ Ãa S )œPiÑN“Rµ··y<‰Í‹%ªÒ&ó|tI³ýÜÔ©—´dß6«>p\ÂyÙ‹Ê%–ìfxœÏå…Ö‰è„æÏkz–Š1’_ÜÁL{x”¡qòë ¶0i ÔÙ?Œ=PÒB™J–ó<ÇÊ;Z'õ¥·~äp¼Xv8Ôjbšc^À¡f:–fÚˆúǃó­‹N •'Kwr‰ Š,ûÊ=È噆a8Û5ÖÿCIÁ/JûEoêâ{°{Iès‡‚ƒZ'mʼéø7ÜÕRJDa¨Üç…zëÛÄ>,÷ñTÓ-ÂÚŽ?§~•ëÉy}t;¥àÞójß:MñEà h‚ÞŸcù¥‘±´üóóíƒEê¯Å¯žî×V:ËJÍob¼{üÛXÄÂ…Åôïy¨ÿϯÿ@ÃøÆ»],þô€‰…L§êtþ‚;ÂX.ØX%8Çg†H  ÕÂWÒñûE:u ¸Æ)‰acA€çæ ½â°6b’¬ôE$ŽÂJŸ*&C<]•©kN×IΩ§bKGŠ”ž æ f‡\¦úÕúµ5u€Í=ѽ…x>/üÈç•ö&®ÂÕ8ÍÂO7Ú7BááV \ãƒJF¸ýÓ&¤{']„š@)¯#àŠðŠÂNK×û c‘Þo(‘¾~¾š åRòït·°ã¤ö-]ç·Ùml":°çÈ&–ÈfŠ}Š0ޝ)›M>1Mµ³©V­l¦«V6÷;ÒšCf³Ñ'õ"÷Q%9SÚ›}XñÖL uh ]ï+ÝàËñºÉWº™:û%‰Ù™òG$Ùe° bj'eL^¿©FT\±Š¼^«ñ-¢F’·OH¢Ï‡iÖ¨ô6à¨mÛßbüamy†Ækå|W&¦Fßûq‘ècNê2U͙ҙfq:»Ÿ½ç8¬ÂZ“rL…‰æðJŸ ¬“jð‰ÐáÍm:?¡PDð£‘âƒOb;¶›#¯/Ò~ÂôJ‰íðMPŸ©KžF7Á’Ûª\áC3CËè¼Â§–.÷‘$›ÌTbETEÜžò¼¢žùÑSc~ôÖHþÆ­”:ÑG“yô#9a¹/¾Ž[åËWHe·òÕÿ¤‡,Ë}’Y+ /N^€e’Œ7ùú… ŽÉô69ùJ>Lv…WÑJU‹…Wb¹JÁš€ÒyLV _ ñ”#! ¬ÄùM,Ç¿€Fõ—ØÞE,Ç€ }‰}\sìãнÂÂ4I“õÉÛ;SÁ“$¦·ÎÉÿ¬ˆEoöu~Rg›L¼öåð™ÿ¼NÅÂìp’µQ 3m¯WÄÜwŽÃ‡høë²œ-.ó!£Í¡fû7y^Ì íÉ)¾ˆñð°µs¦ˆÆíö"`/æu¾Èû7ÿŒ ý|TåGð¿Rð[&Ô5ÖÂë°ª?Ê£ÿó|¸÷¿çxGüØ ïðå6ù!Ìü¤“ø©•"ò®R¼. Þŵúøž%|&¸>±'´ãývà ûx³=!oÒ ù)o¡|­ñ|‘xβßö>Úa¨lÃ7·ŸNðÈþŒN‰Ç‚¬‘}%ì]b¯—™Évˆ|I¹œ¢5µ;í[Š޾/X[K/¸&%´.×,({NGÊW¥ðJ¢ë~k7OouRùÚ3|•út¦ÊÖŒ(ù/‰…¿æ¤=ŸC‡ý ä¹¾)q?Üøà±úq]VÙ‡vúdþ•fg2ap¨sãEˆ¡ÒàЋâû¡þqƒC/Ñ»48ÔQBC»|–Á!œÀ½r‹Ã$}–×?£4àü¡e™å‡øø70¤PZfèJ¬ßã£6 ~ÂÚÓ{|ác­Â}¾ž¤Sº×'ÞEH²–÷@\×ùÐ…þc†÷KÀû„rÃ^0ÃõÔ•ã\¢UÕ øw\&ÀA ø€ 8$AÜ-0Ç%àCÜ+ˆÇ(b@ŽH@H’Fð£PÌ€c㘔0 ‘b—€n ¨xÙ *?cÀŠqB~΀!ÿb†¯H@˜C pU~ÁåýAxZ3ü…•Z êè—¸\5rÊ5ÕQͶ¾CË‹Vònu5.,°æ8î-ØÕƒ5ŠŒø¢#T%¦OÌ“ÁZµÄ¬8Ÿ¾Lª¿½>KhÅc|a¯u‰xDžÔQ]±3Ú®„¯æ›ás>¾¿œÓ†WqÙßÌ„äN÷osÛm+Ç|(˜ï)ý5ѤJ`ôv}!gÓÑ_k¦û;@ƒ®l5máÐøYpìÙïß¡±¯5®`¡t¸f&%CÑÚd(Gk®®Z$n¦UeśР:‘ÀŸÆ’´Y(|vb=Þi9ùK)3þýêZ‘: M0:š¾`+¾9ßJ)Xý˜BõƒÛÓÓ-r”þ±Âf|™‚ÙT„Ý>æjOk´8OçcsóV¦t E,­µÍƒÔjp¡ϲ4想^JUØÛí€c•€–!ùíDòvòšXý¥äkdò>”|­•|’ßáä|ƒ|ƒ&6kš¨d-n!6nG¢x£É)îù$ö¡ã9pÁvßÝL]³f¤}6¾}7ŽC¸}Ÿhí¡æâ0cK‹o´ÂV°5?$òÁàt‹!ufà“t.OáªÇ1÷Èš2áϯ+ºŠï‘Ybf•dÎ V@hÆ•™z|H_lI5º˜­'KÈ«FO’çÛÚâôV}©µzŒþ¬",La©þ$Âåz²Dˆø+ôd‰•„y¥Í„U &¬EÁ˲œTðÁ\ðYÝbSãcia§Žù^Ý«‹lÒd§nÍ÷»tÌ÷»õˆ=Ùþ¼5ÙïÑñùÙóñɾNìÕÒ6XÑcòÆwT÷Cšà÷éÖˆF«ÇžY [´‡À‰kǘ…|Ùñ¸ÍÍ7Ä 彸?bP·ö¥.áåEÊ.†z 7ôAÿe›½ z!è¯QÏWôH\.¹ª›Dä¯/À›ÞY˜y5xŸQ—9î³ü¤ 4Doà Gy%è×ÙD'1Ðn·DïÎÛ¥l;aF#Œs0î›÷É‚ùû•Ü GóM«4ˤ¹†ÑŽÇÝ긄½†/êsYsÚ¨1p=©%²‘{‰óïÒƒs²!&ñv×-EL5JR¬C³’”hM¹gçÓŒ[¢M«ÕFŒÇLˆÌÓaL!›%)°‘0“ÒJ™l.ã,XóT® QÃjð]±35þåœáM¨÷÷&P/±Pcä[Gleŧ™,7’!2»c³“í)–¥±¿¾5à`ß,Œc7¹Åîã‹ý~àØG̹^¤àq£H=I›EÚYCÔ‘¤Yù€Á³²8HuuD†“!Ç 9G§“FðUVÙéüªRöj½8Eô÷éÞ(îÕAœ6bÙÄýq¹ª ŸqD‹¯·Ÿók¬p!-qÎ,ôl ÐS–KUuv3âØÎÓ×CÑ]d%za-!¹lÈép7€ý²`lþq0à b€¸Îá¹Mm '?©ŠˆÒŸ£<(wå>GIH:­9j¢ÈÂ\úmDíé´æÒžN¶±ÐÛ)z;#ù“:R¥”µª}Ô–óç}> ÏP‹îçÄú,ãí‘~€~€L?È)%§Bé ÏÒ$> q÷úo$îDOØnY.N©ï)#b´ZѼYàÇê`ŒÓê`7ã,·ÇÚñªÛ°1÷r;Þ­DGO™[=‚»chÌÄÏæÆ4‘‰ø¤a¢¤a²SL•¸9SF^éd·™Óà6“¢ã$MTÅ#ÝÊ÷£M“‘ª­Hbº“ÛÍtZrs|?˜¾.·*çãÊYv`á–T‡˜Í_ùçß/¾ÔJÌÅC²ì#"¹}p«µñ·Zy²t—0l¡ ÍúªƒÞaT`Ùßx·HúÁ]ÿÏŽ—”ÃNå%€¤7\3R:6E¼fFK7·?€Æ@öJ[ F5¦b3|ƒõ¨å@_€À?³FÞŸ5(¿«„±ësÃ×½Nü"õAyò—„ó†OüÊÌ?ì¤áð–O¿¾#~þNˆ{Òø&« 0æWïcªôQw?x"ÚëD…Ðã ñ@œ¶Üô‰AŠ™¿þŸ­ †`á=:‹ê×Ù˜&)ÖAœÉ|_ÁcÔûê$8J˜á±)fxs ö5)Çd)*Žø(å;å“”Ûuž‡8ciò1œÿŠ8òÄr…æX$éÄcŸª.bÿýÓòO¶gÇ«³/¶àÀ´Ðô4#ðä+¸’§sËX¤å¨aý)ªaBûõÄøB¥Ël#_÷!Õ<Ž«9çA¯‘·•w?¼”—}»ôöÂÇ3Ÿ½ŸfRÍ´Ç£5M¶Š,©²A0XPfÓÉwP²t*ÿëg×Á8X2&VßõÁý‰uâ4É>Øš¬„¦«ùãßË¿‡“_yâtÇ'¹91 »ñ_68M®Ü[3T„°=s×WzÏ'jÙëU–æ4œS DÄ]®£Îr_­²)àûEÊvz4±#“Ê÷`ht‹𦲣½­Ê‡ÓÔœÒiªØ¡Èƒ{׋]Jˆ¸¡Ä*-!ê©{74¬ Å·{Û7DZE¾ü²å„¿z†j¼ßÄ‘”Ë5l¿}±\7M¡À²¿–:Âr@Éu×e”ãÖ‰Ä×+äÿ&»0y(‚ãÍ|JN*¹F]ÆOqm]"èÝŒ >D”zÏ>§ÏË>p“Qœ'•\g+á6rØ`+ì …]S¢¹Î› §EÆf8nR¼{ˆçÿ‹¼j¤7Áû¬ý³}O5Rbl (¹¯Ìo ÃŒÏÚß]kÛÂDï³¢W¦8ÊŽáêù$6ÔpÖ@'8Fï¤ÔPß”´’ÿº¬E'½íC:éf¥5£©Y8WÊkì¹ I.!ÇwÅ÷"òNî÷ƒït~ÇQÖv?®ø¾©ˆŽ” ’æHÃY¦ E¡Õ Å;–0ÚDþ¹ïãk)ï´ü¯ È_ûr¤øã@Æw üãäøƒC2> ¼ü¯mëF)àôõY—Š«dâ]3bôö‹.fëÒ2¿x.Û¸÷bJ>¤z àwq3è÷ œ#\Õí[­ù·ŸâÈønÁš¢ß~Š"æP[UÝ ü$‹U\´a¼C}é_ÃTVÞ}°„¸y0RM”¼Í/[ž‹¦QêÿI±{?ZýrI¿Œq,®™ òã$|A–}'€h}.¸åõçé—u˜'š|€cž¨Í²ïW-ͲV†„Äÿ‡ûsº¬WJŸ’W8³p8þä—o4(Û^V¾Û ÄÞVqª½¼š—àíâ«è7Û¹~“k°“5ß]…3»TO.÷“€/1¬¹d‰!–!q„’ŠåØÜÚ™…+Jo"ÖO©)ÑcœûK§A–¡×þÒj?&3¼É_:Ý{¦fxƒ¿t†WJÍðFéL¿xÕß·X³àÂ-¨p70Ã+06íæ†ófÚ$gªp;Aá´ìÓPõRûjŽjîó;øJ\ ‡÷°Â¥Þö< ßïg¯Hé ¿ô™¼‡‹’üQ•ý¼ÒšÈ ¯ô³m|$Û;þ7D½š‹™g/ôµ :ªŠã@ºÒ/>ÒO¥¹¤7 Å*”ÆL$¾o'¾¯ÂVD¤t•_ôĉR$‘¸ Fª©¯Fâh"ñ[§dކ3ÉHéj’Ù8–H¼‰wRâ5H¼/‘Ø´›4J"¥kü"ÆÞHŠt§ŽRé¬é¬&Î#ÒZ?l߇²ÂÑ<3|ÌÏ׉. -là¸4à•ð¦¶føS  Ø@€ÐÈ€8¡‘€«øAxV3|Z¾`ÀL|&ר;@¢`ƒpxÓ¯u(X}¢`£ì“ŠQº£Íëüb,›sO$ž‹Äó(ñz$>˜H¼ØN¼æ¨pÍØ/–±Yí,Cãmг ‰÷èÁ¹-róž™ äê{ÀYòá,'Ei…(ÇåS¥ ¢8s{`ö8‘8¯FDºŠH޶Ï,Wr¿Dˆs4©”è–C 3¼„K*¥Ý/G0N)ÝL¥D¯<žHü G(ñV$þ”?€z;q½!‘Pên㇀g«_1ÌÂO¨‹¾œìûHvɰÆýC4ñq_‘çV)ø {à¿bXÿUÿIæÞc@ÒÇIDõsŸ#Ö´ÌýYnFççÀ¼SœÍëˆ1ÎieSáÎx6œ‘üy/o/&:­‰f’ÓÎo²ÓÊoŠùNäW‹ü!¿ßäê¹OÛù}–`ÓÄØå¤lúœ ù:"N‹M§ˆ9‰7;ýb¿Sò¦ûÅgH.I!Ù $gH®ÙH®9Å Ùí·,$·ä\–FHÚ"îB2,Å ön_л½£´Ö/F¤Ð0¹ÈmÒ´U¸×¯Š‘)0ᙥkîÔ·dF Ðh阑ҠÌúš2#EÌJ1i.!±ºßš3 VS)å³9$Ê!u‰Ù~1h/déDõžtk oÞ~šv»:¥ˆ%)D„߯+½.ö·„Û‰•)˜ÒÌð\-æø bDÞ* ­ôOËýYuÁìöJ÷ý0j-Ö?oCJîϳ QÅFNUi%ÁþÓ¶”fñ»ïÛ)Î|? Ô;øÍ³ï.úZàgOÆ{RÀvÙú CÛW»…ɯù Eæ­Ô}ümm\Õu­’«ñ÷°/¸Íó÷`+‡\åo‰%ØŽÁ¦ ^3°G{"ÅŒFüŠ8 &^Ìr»Ü©—SÁÄË)X Œ€é¼0^þ„CP5 )Wè16¤^¥GyH›êjP®ôiôXÛÕØë"…ýî7(«YîvNß×)£[)|™ánÞJ¿Bý m¼yÀ;â=Š?Ç- ïƒ‡sÜ…‡‰´2—ÉŽ—JçÑüb¿×øEoWpµ ¥añ¡üª‘_ý]‘çmç⬸"ôgrˉu„r õ5 êésËjpb°Ëj`bˆ|»ó ‰BbhÒGaÓ#N1Œp‹ãÌU*íð8Z@€y„9W­#mäøG©@Ø£›s.c\òL¡<©4ã(çqä<þœ+’sžœóÄ/å<é!9O¶ržÊ £BIÔœæ :eZ~T»JðCŠLøA\›î¢îÑžº§É0Épù.¹]8¯ƒ!fºJtú Mj>ú‚˜åznµòÜå]‹`žs\¹Žgš™KΧ45HSãJÆ+æ¹’Q‹ù6=bË&©V¾ÉŠ\˜ôÁ]¤‹âHm~.Žãµù¹ÄF .µ±ãcYrË¿œÁ Ê€YI­Ó’ÛKçûÅfxš]Çk“ ²H¢×I(€û ˆÜë€:£˜Ê¸mŠwÄF+ì#–ó7É^1_öŠ­ øÅ6ÆèÆ&“ðQ4AÂÇ  $a{ IØá’ƒ‘°Ó ÛÎ$ì’$,$ìu§x:Oñ8ʦx`/ÒÅEh>4ñÖµx™SDè­žÞ¢€©Å[²DŒÞä?«­¶í–R¼+«$Å•‚·ñ·ù­x[–ØGIè'"ö7ïûuÍû~}¼ï°;I¡™eˆÃ®H®òÜ¥]Fáývš8âŠ$c±¨¨LFU¸ ƒ*Ž>4^••Góøµÿ˜ ׎³RÒÜ©[]wO»hòêæáÙë´ ã®ò9=ÎÔsô8ÐÎË÷=Æ…ŒËôr6У"”"è1!äj¤ÇÄû =&…R¯ºÄç<2r7®g\Qvê{ÎEÅ£ÿïªÐŠ=ow¸2õô I=ý2%ž ê#˜ðºS­5p½ÐkŠ2z‚^k½àîL»ø0Ú{Å‚ÈB窕ݻ¥Šk=®±ßqr.q—¤òÀpÃ¥?9.ÄÚ}¿ÝK4Üt±›PŒ·]QDe×à˜3îÏ]‰çžÄ“Ri¡ºO¨îÇQ½”‹Á¤)ªÌµbDZõvS¹4.W·U.ª¯;¹ ¿ˆpUŽîÞÍ#¸‰ú ÝIeäŽÒŸM@Çv/ƒÝq†º­²ä*œû0þöÄ¿Gï‰w¤»yÙFêQqÔ/·{…PN ›T6 [¹ Jd0Œ—TXаeç1ò˜Ïã•v-(‰‰<&K„2Aç”$h"§ªc§%3¶ºci¨o§7—iŸg‚Ü™’ÜYÉ|žM„ÎNbFæ¡5_âó¼/ñyð.xk¿Äç…„zauF;¡^”@½äA>/}ÏË‘Ár™ÁŠù¼’òXÏÃÅu¹*‘Çš‡òyíCù¼Î E„,$ì?c0©sCÂŽ¾ä¨s7(»^RêÜâ€;8¬]{åòJ¿8HÔ‚`#Jr“p¶Ðú8ìŽæ:jyƒû¨Û”‡­¥sýâ>`p¬tŽ_wËUÁ Ð¥êîÔ©¼ ¿â† ´¥× Ž+’<&‡Ô/Üâ:²©iÛ’ïˆó[ª<ÑebzÄ?#òljú7ܰywËû³È´hu÷zqÄǬøòÜÖ±€£Þå¨÷ܱÜn-ð}ßÛí Q–JJ Ò: §óÖÉ  ³*-_¦š­K—øÅ T³ð•fpª,ÕÔø²f¡_ M…/ŸÒx9‹¤c¼ÂK'^ºU¤‚ó¯;*RÅÄTȾþJÊñj"F•£*UT#ÆlŽñ/d3ójR±óS!'?S©Ì—…˜sÿ<ŸOWjS?t¯óé…Fþz±Ðcõ;`˜p‘‡zp‰Ž.ŒA¦AÙ×Õ¹„ðìïš²Ô#–xrLKùéÂõ4^×JXI…i—= 2Æ*¼,rcL È«ù³Ö=-VYf¾Å©é®§WñClñP{o§"I´$eZÕ4^¾˶ÙµîX‰+àSRòñvzqB$Þåá}Öî¸ÒÝž¾!¹îñ@·‚·:B¼3ëá+K,Õíóˆ}žÐ‘vÔ«ê<$—¹½ß’æ•q€!´´çûòuâ 'šÛÄwÙy‚O#,×-ÛN…]Çýâ¨[F·³4Ã:Y¸ë®åF]å F]õšJ»á_PÔ´üc¸F/÷Ô?Ö‹kt£bû«pIÿ6Q±ÄoÀf‰)8èW{€Nq׃íÞ§¸ïáíjÑä¡ {‹¿t›_”¥ÑºˆÖæi&rA…Q¿*úâHæN–BC›ÇÌ4‹ÊQib Âî&ª찪4Q°{<¬ü˜·vì°Ú´eJHY”–?5$¥õ­‹Ó"áŠÇ1gåÏ,KZ–fæW†¢•ùû_©Œ„'>^™_¢—IW‚ÖåÀ}Ÿë¨ŠÛúùB^ßU9™&¶¥™áµ´TJãmcñQïÃ…Úv²=û¥Ø‘Æ[ÈÙ%Cv¥ñF²ØÆ{ÉÙ+Cö¦ñ޲ø$7•‘!‘4ÞZÑ4Þ]FÈ>²/÷˜Åþ4ÞfFH½ ©OãÍfq ÷›r( Õ×÷M¤É::š&§¶O‰%ÓB`I[Íùq2-Xá7;Wø•² 8•„çy ËÝŠ8 V5ñæzpê¢Í©‹iârš4r6ØfN¿,[wºS÷q«¼—&ÅJr/ -QiJMiÍÚ](K7ÛvÓÃËü#»ÁÍ—Q¼Ìï2\ºè•Žòt‚_¢w:.ì.óB›Ä­¾é&¥Ký¢_º,ï@Nâ}=«× ê¨t187ÿ°C7,˜±Ø/†§›¡/òPöQéØÓ[æŸ&FS´å´x]ꯂ|16ÛŽ±ÜŸaÌý7æqéTºžÙ 9ƒ¸tÕé˜|n)–r:pFº˜‘/àB.à¬tÙ¯ØÃ,bª>6ÿ”5Ô9ébNzð–h´*Wé|KQSÌM…ÒÃ7Ÿ7çä_“+\ž-•Èj©¼§¨¼‹@S¯lt”AÒòt«†–§ã†ª²2]¬L¶ :Y—É©„u`:±šØ‰¹H¬ŠÞÙñ~¸ÎF±.]lDXŸl(ï ÏË~ÜóP›øßî²ÙVÝ—Ì9šÜû17Ù1+üˆ¹™ô͆ ’‡iù÷ËVÕ×cÕÖ•·=ÙŽB|¼Ã·â~„Ûíãu'Øú‰h®TÍÈ[Š˜¢Z×Á§·©±®â;-\•ÇÖåqhצô ¿¨ÆØ€l'a»œtpÒ·àÇp×øŽg€ †?¥‚, mK:µ2Úø¢UHˆ÷×pÛGsÎ~/n7ÂÂJ®£íþÒñFÄ¥”N0Ä Õ ]ÕßJ'pv…3PZadäK+ñV(E]oˆ 6¦ Æ4ÑÈx†Òÿd³\ù1%•X)ùD‹¶õ´óÿUœ,L…Vr3Ïèù$9g6ÍM¢íY§—’–ÏØãla]=×Ñ=Cƒéñî`ÅádRß±¤â3¾OÕ$Úßi6 ù ¾ CœU‘S»ì4lŸSÍvÙ`éyXÔ´¡JyCÉu¼ ½ÄP*áeyYІÞ+ñRžó‹«qÏûÅŸ"àÓ?øtÉWY z‘¡—ýâ¦,J¹, NnKT±‰Ð¥ ~˜¢M(^¹a†Ïù§LôÔ8Õ¸DªÞ§ÚÇ©„L5ÚŽã(ÕyJ%üb°fBÚhðç*û Vy„kˆ„Š$(Å)ñÕJi •Ù5ÊÓgÜŸ­Q¨$³8cdìú@é¿+c_IÄ.·cï ï ˆ íCÓŒx¸ €áïre€É瑱ãzAÄ£—š1I3Ãc V}›Â^ ˜á›þ6…š˜jÁ%Á*-ØÉö Ø4ÔÌ6œ)® ý~–}ˆ-ƒˆ‰‡™‰ˆ]UIÕ/ÖÈÄ—ý²ö“¯Câ‹VâhrâËH|Ñ/6¢@$r‡Š? Àï>|š±E“AhÕ$ŠoÕdªÝGª;: "9ü%l$âÈ·Á_¢WöJ4Ï ‰QŠ*Ñ6wË–q)©ePÄ=z9 JqM†¸)< Ï=ZÈôðñؼµ.ÞëÉÀÍçCÚ‡{=­K÷zÄæïzâïQTÑ š|S\STTÑIª¢¼º ÂÉÿàl]Iqý;Ø4'ö£ôx7£7ï&'P²mÞM+×›wÀÆëæ[“éi~H¶Nu±GG&Ó)“6um¨.jßw̆ÖkhŒ³ì›ûÅ\=â}F%†Õ†”y:-êCê|]ÌÓÛКPoS/jõH¸·‘ß?@-2tûùÇ å°H7“§ š®å ÚfJîŽÑy±Ëš1`d>ŽÉŠ9ÑàÙb‰Þº^,— HÎh¥…b|³ŒL;ùxJNCû*+VEóŒ$eTað4²­Óc|“k½Þ Þõ@K+SLø››—ÎÇn¬á¼àº_éÎâÜzYÝÖ¼ ¸Öÿ‘n&'}¬Ç˼]o]'vÉìg}-)û=ÍËÌŽìtk^(¸acúDßl^ülöó`&'A×âD Ù×éQæD=qâ $¥¯Í~ÌÙ‡,4 „ôuÍjh¶NÒ׳hU'ì‹-'tqJHÑ@)›ÆÈêjx½I¤8g§8§‹ 2Å>;…™H1œåÅß!Å Û¥Ü x»b±mž•@{´\¸ê‡ë=ÑÛ°ÂH„Ä=`ÑÇÔ°„ÑNÉü|-¥¿),ë@˃˫~©ë;r´3ŸähÊø{ÁSqéx-ýíñà¯ËKÏú«©‘Ùö5àŠlûp4K<lòçtÙª”þÇšk§_Pó«oGåû ÊÈR_mP½­ÁäÄlè‚…Äiløièz^Ë"šßûðZ^hoNøæ7hÂ8(¾–'º|x=Ï|ÍQ|=O|@шu“²a¹á5$þ\³Ü%®ñ+x Îb³ÒKp¤™‹à@C”CF8“³šá< W)¶Iöç:êðñ+Ü­û åǾ:~‹{¹Ÿv•7qº‘çý¶ôíøöMþŸâ?½®ýâ? îb¸Å ¥R˜¯)ÏŠÿܬF#™g›šÄŸM"^‘KË2ÅáýLŠÃ iú¯ íµðiîe¶ÉuÀ³!þ&¡§:8-c ¾›Rƒ Ëž–/©›íí•poÔØ”ly_Ê´דWѬÝ;“Š>5ÛÈ2œcÜ9§`§Í×-5§,­›'§ì{Ýü9etËdÞžSØ55]U<ÊŠ4E0[õ`›ej'Ñæ{gо*Ø8ð•8ûYª¾b³q-áŠ{fÂ;rðï‘hç¿«¥½2ÅpNØôÏœ0›} û(hÓÚ ÷ÊìÜGÑÁJ1R-ñ”Ë!.ñʼ^¥Rņ¥ záîEŒQKô–¿DÃZò£Ò¯ù+àÝ+x3/Rp3O‰»ªîæ§Ef‰?ÿX–ô!Ý-SLTK2_s”ýŠõ€2ض> ùä{2->ç±S,CçÓ[jÆA#ø˜ÕDCh¼²„‹4] }&¼éùàx…bŒW”Ö…SÅ Äyy ËÌâ÷þ}R@?Ûúì‹ÏÔŒ,¾8Z¢‡×sæóñº¹ÃÒQh«±¤-zë³b©ÜjD ¶Jx›º›Þþl «ý/c%¤ø8V£%:Ÿ½m4Øõ2òçCz/£Ï쮓ï®âÓ^±I Õ?M¿Á¶*¥ØÌ‰Ë2aiÈÌWËÝÒÄG*ü§ µ'¿};@ì#¼ÎIQÒiéY’%BZ^–¤Ù!…ÓÚ+bŒX’V¼Î)"j þUÕn-h}YÒ"‡½™ÆÔCö«Áv±ð€±¸gÚGD‘SÒÎ'±\R>"ê$t³= –<Â~i3ÄA¼Â/mKqÄ*W°]‰1¢Ä9‚ðZx¼âh¯…ÇËæ–ˆ7%^ÂVU|Ü Gm€´$H” Ÿz±P1°ñü™ý5°ý|Ž?ñ‡ð^^¦ZŠqÒK‹Rjm—°\}YµXëâ-`X ÑØu(l+•HWé%+Dæž!Mè㛲MÓ(žˆj‘rëHÔʾ‡÷Uì˜ÈL±7_§%f{i4;Àaá¾®\G Ì¡ù;×Q¸†™C°ªD£è1ìœlÍHqý À?¯Ø0:öMÇ_ (ÿ Aý«øK®£û~ñß¡Nˆ u⯹ŽúŒ<hæ{_ûñ? Ÿ ð˜¿GJt€ÎÂç•”쯛µX43JÂC/ö=97[÷§¸*Óg9k¤³¿mèBÃúI^7O^·´¼néyÝZÐ÷# )#¯[˼n^¼úX<-‡šMH¯0µôÜEÃcáÛ:û‚kCÎ…ôXJõ€³Y®ÅôXr/¥Ç†Pê2EŒWB7uZØBûÞ¸©‹…JðÀÓ¡á΂O+ááPl‘R’jÔ+CB¯Ä©Øb|ó»[,UJ\%îPƒ>z_ÁX®DJ\鸷¹RÁ}\JWU’ÂGÁ4®R>äÌUJ9ù yENµn Š\‡¥¢¹2@ôˆNˆßÝjcȳU[‘GUwù·)4š»§#îGÈì¼>–y!Bu%a€Ê~µÓò]CoÒf´wŒNx7…Ò>!Žl¥Çñ‰B•MsFL‘±ºÓØ¿OA…ë¨ð-¡uykè‘ô¨x%ã=¶…Z†¶~¨^G%-FǪþÕ±?üFÿCJI:ÆûÃô¤¦Bãÿ¹@¢‰Ð°~„Æxdú©B¹geWÇSâý¿Œ½|Tו?>÷µi„`Fv9ÆÀÙ%vŠmRfw-È&¶1o”ÌÎ/›l³ã_6»¿ý‰Þ{ï½÷Þ{³) Ñ;¦[W6ƒýÏ÷¼7—ÿÿÿÍ{ï–sÎ=·{ï¹ç,ÍûHŽýòyF«è<¶+##}á&ÍÑmoâ½–Ûò*ì‡ðÑdv½åkZmÞì@ñ;5\ÝáƒÁ› ¹U° 7œ]Â!%“¼‚€Ý±€ùì³ °²[— è 5åGLǘw)G”½A‚[œÍ•¤4¾ÚÏŽÑ{+@Q¿B—NiZ™·;Ⱦ©¯² E¿ôV*¸¸ÎºMŒ.¬í€+’p“ü‘T޹|]Ÿ n #”4Á$PÑGfÊê: qv >„ïp%]‚®1Iy¢“­|QSŸ tZú €'gQšd°JçÓ7Iiá&Ñ‘>xl*ëƒ\Æ€Kx®E¥ž]ió(l´Gòù™è2ÙYw²çb«[‰pRº”ù»mRf8²úËYó%ެü G60GZŠªw‰¾7dóDOñd³Â晞EÔVpÁHCß–údØ›¶³ÄLI0dfRßB«îêÄÞPÞ>ËŠå_év0ÿÔLî·èoø$Á5Ë4ÀýLl¸^ €‡²Iý¤?ò$©1‹T®¾Dš6T_2ýÀ±,J“ ئt}OÕÝ »îNfÕÝ鯩»3™º;û¥º;ùåº#Á:uktêË Û’?*h¦7öMü¢A^ƒµ(_1œ®K3Å%µÂµç L:/cØ©™¨T±8S`3ž&ƒÞ*.`µŽŽöÉûJù,ãMGt–Oh,Ø©²æ2ö¤Ú€2Tí c$aÜÚžß´!*Ih™°˜«“xƼf[ƒƒT^ƒw#Uë˜k´ ý:22å“cÕÔXÛ¼1ïÒ§eÓ ‡œ vbC–㈭S ,ÎWT§ëÿ ¬Ujª¬$°ÅÞh ˜³ ?PY µð¥ý™171Ž¿j/éçªÌ‹yªœ«ÚÑT y\ ªm'RÕ2Ï"ÿ ‘Ï·È–ä+^§ë®2V°¤å=F5_š¤Á|'½|Tá.ªlE‘jq{úuóL>Üï 9Ö}ûCb“åé UW¨rrYáI–TaE¨¯Mp <ÒÇŒ¯!2‘Çá¶• ªoWåV6˜OAnW¹Ñ7C9w¨‰LÜ®ZvϸœÕ¸mÄFMw"-÷_¹¶†ŒCÜŒœ‡U®ÌxjXtÊÃjØÉØ\2lnxtscƒÈÀº°3ìFZp$©†=‘:Vx;5AÉwºi¹çò!>PÑŸ“¾ÁèeTÅ•:dLâÿÒL+8›iç)I/JrÁæñÅÿVpÙjWTy9«\É´‚«™VPOü¹’i7@Å2¦â/ ¢.CE=QÑ[w°yÍÿ7ìw-ì÷TxRNc¿—Á~?ƒýÂ~/ƒý!°/ÏW=N×mnƒµÿmPÖR"Âíë Ûn€ã4n€ì¹¸™2Kã8[Ã~¦Ž×R p’–Ý'k™oÇÔ§irª–j€Ó´Lœ¡%2Ãì4-«ÎÒì8[Ëj€fªÎÕ¸ÎÓ¸.Ðä\-«ÎÓÒ pÆ ð)`[¤7 »ñ•n¢l1 4»ÉAb™­YMn"½/Ó¬v´B‹½Ñ‡jt%V+òUªô<ÚîàeÉÀ·;¸”âCMЂJ¼T‘O;`] ã•ï”mnǨØïŠÃà–U³Í±ŽŒñü𰔯µÜ¦ì™ª;5 jj´Ð<#k§;ݤšcç”Ö:VJ£$›ô9­¥ÆÏ³ y%gÍe’?â–²Ycº¯iºÅu&+¯£~³ªò¦£)a„OÞÖ Ûþä×i ^Å\Ô$2â<Æ¢ÅiÖ0k5ùUÝ'—ÿ.Êÿ Í÷´xÙT¢è¶†… µŠ õ^“‡ûâ‘¡FUt¸O>½«˜^îݽø^åãw½`ù’À7ýrt¢’V«lð©¿k[C·Ý^›Hš#}ð‰h5è1ËÙ«Ë@½uç\¸c–J¹#“²¥£Ò §4r”nÍßcôV´[ÞF':Zï<±>ÓÀ_÷½Ö6úPÒ°Œ|ØÉˆ|õ‚ù©®â{å÷Ûñ­èxÂ@çú|iyí«ùg»Š`ùã6ÅçºF¾ó]• ¢¼¡Mñ…®Ñú¾ØU‹òÊ@ñ¥®ÑÊ܈åçäÎÿªÿ0$¤L><°L><°L>à1îmñokx,zIÇc{©ÇÖR';J]xl+uãqé-Ï }•ý±ï7˜éÄÀ‰ÅdØö¾î•ý!mÌÏ¡•ýÏÜv–œà£ß´Å‡ÐÀö¡AíåX%tÙŠ?:òt(ñ´§„bO‡·ï2Áç…‘ðMoI|#8Oï¦,?üœþwßÏ`&øÇ.¼ÒÇ%[óS^©…d~ð^‡¢îDt¢e„k[þ7y¥Úž‡Pß©?’]ì=‡.øø{J¼‹G?ÕdŒYÐpc8W Ä e÷éàе{¡%äpQ¾9'Ýœ+z­£S}r”nÏ¡˜xéö¥w-¡¶«¬µb"òy‡÷yÿk¬ˆá#:Ù3J±Èd_¢t'”x|l(…>˶ºLðµ"¨å$‘H9‰mʱÌFNÁŒ­lG޳Eù¦œVÑM9rX³“iŸÁ´/KѾ̢}…+¾LéJB<Õ÷~ʪ{ÛU8‚‘«-rb‘)>Öö]OåyDz»AßakJD¼^€˜Y䢖Ã"¸3§lgŽƒVÿD^k·l+ÛØËÖ®ü”÷¢ô‡–UµUTõø¯ûA®üI>Ä¢Vwçg›¹Ì®Õ=¼eõúXH¶EôÜ×mñQŒZ}”}²lx䫊aü´NÄCŽ?"ÁC÷;”Žò8*ß8&ÿ9úÇÈ´6¡†œ²«^Eþ©|‹39ënqÊ?{7*ëÝÈ!ÿÆ,ò ÕpÅò—¥ø%B¢ Îú~óç”#`âyL±M·6>ûü ¾"[œ¥¿H(ß„7¾¢fÐÞéŽ×Ð[‘{$²TûZ—mi§Ê±àö¨W:D!ø50z"#ý›±H•mV< ,u®õ{ËKå,ŸàM4Ø·Ñk{óËú6â¢ü{'‡ò€öÝïàP~ãØŸ»X?DÔ_ÙÚIÈñ×:±²‹ø›üÛ“TÔÈÿN°žÝÿ‰%]þ¼ÆqÌGö>8ë'‚Ó|ÈÕešǃóáJr;£ÂÞ^¦ùjß1„·ÍÄh+d‘>6†ÆÆ;føZ:â‘ážRš¯£3||Õy¤ÀL9ÃGý ½%§˜AƤùE9M$AxYe#AX  ¾ñ4²­ËòS&ŸbÀòVAÿ»€Ði>„£ý~˜ÿMfZñI¢=Ÿ£i>íÒ[¬P|”½Åú!Ïö!€<±Åší_*fo±Ö„d{{¸kðkXõ`¹j¨ŠÐW‘äÄ;Ž_Ô‰ãïˆN²cì^‡üTEÆ6]eï~ªEÓh†VûËàØ¦ô]:¶©ˆ,mú¸Þ–¿ ÍòFjtûX¾Á:–ÿË_ŽÉNߦs˜6˜×æh Le‰ ¦Fþ]h“7”ÿP¾ÆKò¯|£|ÞÖyeYùZoK]ë•]Ë×ãm½Wþº|³7ÑR™€q½*ºÙ+ÿ±|«7n%(h«Wþ¦|‹×JÝâ•¿-ßæµ"£Û¼¹$lo›¶·MÛ;Àæ¶Àæ¶rÂfÃ!D= ‘ ‡p„G6%„È$DÙ”lóÊ 8L AT-ß ö*É‚ª½øë~È‚æúÍ ™žO¦'ÇãE–øŠºÑa‚“zB™ KVõmñ[¨(=êÄå®j9ܦqÚ6õ'B2D8ê`Ï[Á¡¢ËPáè,ìèÒ;à `(„%#2üi:ËžAÀ_Âÿõ ðùÊ_Ë{ {Ð+ ÿFa”õ\>,SG‘r°ÇöÍ5ØC…Ä`æ‰'"ÓÚ'"ÓÛ·*Ý÷¬ ‰[=r´'ŽSœŽñ_—¾*‚m˜ÚŠÒNÁ¢ûXO'9Þˆ'Ê9÷šÎgNO!œn!œî‘Õß„pná¼oD8Ÿ.ôáB¸/äkº¦ïÀ¸2…q¥…q%_¨RÖÓãþ[ê\âŠó‘úZ‚´ÞC’Uh­;$5‰ÊŸ×Ê žx°]Š@œLZgšÜè!™ ‡‡ÛËMüžÐM’Â6{Hü=mÆž–[ðšx–Ç·âõÈÓæ‘§å6¼ÆŸ6ãOËíxÜÞÜ^îð$ƒ]¹t]…yÙ#wzâI>pÛ…]Ì*ÑT‰X%:`•(f•(ì¦ÅR%zÜ&U¢ø7•(‘U¢dV‰ŽfJt,S¢šL‰j3%:ž)щ/•èdªD§P¢Kù°58œKÔ_¤õVèkÏ4Ë|°)õ:¬fBYågö®ÂPkÒ¢.6T¤õU†ñ”Ħ#k¬ô.a•a<‹ø>¢)dÌ—•MÆ~EÙdºôå|ÉS["älJ¦; ÿá=]~$Â0Òy%?§‰nH7`gùc‡_MXáæ-CÎSX9É2ߘ¥˜Dyz°õ­°n9ËQR‘aݼֈõ¾Ù˜9k («:=Ãú©ôLGÛà „\¦Ä¥+©ù¾Tᔫh‰Ô4ÀšþÁ—ÒšV½KJ_²â×Q£:EÖ)Áނ»ô‚;‡”J¸qØiö)‘õô7û–ÈO¸Rsÿ½K4E­¸§£ñÒ(ÕÀ‰Fò>…CÈÏ:ÿi} xFè!>aÖ»äc«áE½Rµ*Wø B²w꣟ÓÁ<ÔУoGÎ|¿‰ï5yŠÕ:X1ˆÍ_VSjAe{u‡¦&YÇq¤K¿a–Ãö µ–­õ¹ßa·±ao¨_ÀlðËqxí0+óå÷&©:§SXdMãÐ/"[Ç"Û}|¥iF:p6î°«ÕUâfZ'Ìa3mÕmb‘>ö\4OEíµÅ ïçýý—5(YÕ€…é"üÔ³u+ªժŪÍ÷%ôBÍ¥_‰\ª¦kwxå 5]ý¨²Ÿ«húÒ;<Ø[ #Å5E•/ÕbäÓxˆ]¯Ö‰ê·ÅFËûÓ&j"DNŸ29¯Z]UݦÊmP'éóC[„f­í*l1Òâq¢qÿD_Ú©BUË*@Øän5Á½v,ŽG¶<[Z,|PMŒ·¯Ð‡¾—54rý€ÒÚCc¥ÓÎ𡚽d)ŽVƒ/%xÔ©•GÔd駃…¶˜šŒ\r"4©ÂäëÕ|½™n$œ(ý.ýKZ› ½ Ôì»Á¬·ø<ôÛUäà§QëŠÆE•m¡ùPP‘‹¸¦Î#ñ±§ãŠ ¯q7è÷tHùJûñP'«å_Sƒâ¥DÙAƒ ÷•n¢qs¨¨‘«‰Þ©»s4jô¶íùâ=ÒÇõ>vÊñ^Ù6×€rvµ^Ù—­ë¨É6U‰ÿŸQë cÿÚ'ôØêÖ?¥Ç™q‡gCÎϰßraÛÿ|È}cË=ŸÓãBÈ{_…l’óÙØè z íÙø!{kòX•õj"òÐÅ>wî«Áv]Ú9Àù*]\ Üú[íȽ4jýÓ !WöѹöqB.Âx®Ç¾ZP çb­ÒHÛ˜Wåý5~Õé o9P 7Î{m¬×s‡jr(ÅEÎ;Ás9L 7ÅíkšX†ã•-oäV@ „DU›£aXe1ꊓÚC¨2'µ—cŸŸl…On/'hV28óAY'âÛB3 ¯–éZ{A£@ÚãwšÎÒd•|'YúŽ(½k!®¶ˆá&Í0ÄÍÌ ñ‚ÓÍÒ’iÂX‡n¶Î ç¸Ç*rUБ›c%tV“«‚žÜÜ]nœ9XtyØ–Ú"-iG,¦7—+,S¦PBq†ÝPBÒ&[›…Ü7H§pÑÀÇ)–d¥0äZí‰õ'|ÃÀÖ´,„¸²AËÒ´”µ”²%Åf¹FÊ-£¾Z°UJ”ËÒXl$w3Ù:†än ­vÚ{¨ãö:ÍñÄ|ö'q¦lüû°—-_¥‘í lGùìa¨°‡¶W1´Qg=ªÉ“ZÚpaz?o*ôuqZƒ#®L=£%òþ†(Ïiòœfu‹Zy^K6ý".†Ô‹š¼Hô½:äej„ÜÆ¯hÁ—¨ÕÒ8ÅdyUë$oG~–ênR=uÚ"Âašš1JÞÖ’™)Q¦ëY£uÓe¢IÀ*Tƒ&{éOj«U¨>ìÃ+S¨¾z"o–]¨áºì¯£¯²D°Ž_ø¶:P—uÌ6«^ËÌ6𤇵„Ù¿D†C's@‰¢gÆx”p¨ÞI׃/{$¡s!vŒÔ3Æ[ä瘲¤Sá ÔÑz2c[V4oäëyº±‚GëìJì΢Êa€&ªšÔ‰K!Ç EÅïîw<ÆöTg°_1 ¡=u=6üÀµ¾ð:º—èÍ=›t 8Þ$¼“=•'[ÕF5Ôçôà4—þQ·œ¯‡¡à€Ê Nûô–¬¥¼TE–Z:ËõX—¥>(Ì-´œíÓ»ìÓ9D®ÑIz«ïhnrÊõzXÏXÌå f==½Ñè«ËÍ:¤=ýKÒžWnÑÃÞ¶¹‘½ÎíMÃ¹á¦æ^§«©+Wn'Òòpö´COÒ_˜Dl°•pZ£'œ¢ìq›]Èèɰ‡åÒ}(MÔҫݯ£”Ö–Óê )ûå‡zØÅ-ö;QÅ:–®ôsgcu„[: "M½ÚÓÚÜò¢LRɬ;G¥@Ëâ^#Y£??T@u­1ýŸ —ↇðÓÜ×Y­1bµÆÆguy–[ãº¬ÖØDžÓÃM¸5ž§C©9^À[cs`‰¼ˆ7ÍT"/Ñ[Ò\"/s[m’Öt½B‘%@{F6"vƒ^Â[þžmÞÄGz¬¢Ÿ£ø©ÑÙ6Ñ-d!¼™äC]™d˜¾”Lë¡®)9¹‰¬OQúIšÒOSTݱ¨bùs=È’æ}zÀ‚æcb% ‹S¾—ˆôÏga±Ò :†;°>ôbË[-9²¿¡s›2È ñMk°A®Þºl½OåZJI‰A$Á7XÏÙ4‰nj ƒ{f 0ʰ 0ÚH`Œ‘bðXÃ.Ê8#S” °§z“'Þ@ÏÆ¶W_wØžÆzåóÒ¤š_ËpØ=Óˆ™½òå êmÅÎãWŽØÞùr!ÀÞÊwyuc­ ¸‹Ù›éôÅ_ ÂcjOË!u©¾®-3àL_N)=Íô˜ÔÓ¹ËÀàà:`È¥„Œ$vîÖš\f [ër9? ¹lD{]M/ÅíöªËu©ð d‡r3çsÊ­©øíˆlÇ;å.ƒ;‚KîN%Ø‹©Žà’Œ„-j¹å\A¬N1ÙêîC†<Äõ´!«SxäaZÀÄQSGè%i)‘1,i sh‰ŒãÍi+‘ ¼éæð™¤·– Gä2G”Èc\î'¸BTK1‘¡%(Öq¼+A Nàux ˜p¯#J@öââc?¡£Ñàœ‹ã • g"ì.ÛàsÊ ¨¿ÛùFcÝØ¢¡þ®rý÷±Ð]T¹ý) ë äTéUª¡ ={*W¹ÚT<&÷Ô®ruëW¹«†¬'”eëh…õ©‘È[Ý’;w¹Æ]œò®<ï]ÎÓd¤òs"¯1NyŸÞ’æX§|@/ “æû/è%Ô&’¤uÚ.k ÷ˆ‹g vù½¬Ð60ÄC·—ˆ·³z;i(Ǥñªhݪ¬?Íf}a—šhhHÇœ1ˆd²<T~ÖÑ=Û)‡ÒÔHR ï!Ð⇻í'­3#Çi‘ÏÚÉ£œÄPg³7Ñ ®„<ãr¢­ãnÇÔø!Þ;Ù)';I¿Û±u«âÑ=ã¿Ö®IŽœâDíæpíBîžFrH¬Wf:ã¡[߉\üÈÙÎàö§â‘>ù]¶?%¸rä'VÈ-m+™»ž 7r52w<%çrhØÐÝVèΧä<'qr>½ØœÜkqr¡õ G/¢(pŠëry†+2ükeño¥3ÍðÕ0ïûq¾æÑ«< lrÚÍ‹8nFN\hB›œubzOÇå²Å‰á@Ýæ”[œé._ 3Èl¿i»3ÉSág2ÝÏ5¹Ûi7¬½4hæZ-K;àDËÒkœò€óK-K—P-#$²³1š×‡ôI ‡Ú×!'{µ ¶¦7úaÎÈ#Ζ|±Èn_¥K¾Xd½1·â™¢'œ°ÜDm-I™¹9Õ¥Ó#Ïqj yï±ËíŽÆI§<ùå*tÊSÎ0þ4¶  Ý.7ªð4‡¢bݨB„Ržqò4AÄž¥·'ë𜆨¨/P×!¦Õ˜V¶Î|›æ&kàzÙ¸œ7ò¦צ×Z·N \.y‹z\·è~#KäÇÜR]é—ߊU¨0Ë‘®Ä“)Gq@V29Ö¶n±Øú¼ÅVe¼KŽw­[2l­•\IfêDñÒÚíŸ ­õYÅ©Ê.N•Uœ™.9ó‰âÌÊgΗŠMs¿\œ vqf)=QJ&—rq¶>Yœå.¹œ‹³5»8+ìâ¬Ìg5ŠóI>iþ¥ÙîlGß;]r§+ÆV‚R  ]®0»]±D ;,ØÉ&¹H‘{ëS>ÿÿ1`}‚õÃ:ä’‡¾ë0ÁÂiü‚U¶‘Ƈ@ÜÉ€8–qŒAÔº`¡÷ Çm§»ƒgâ³ ˆ‹)ÄeŒê>⊠â@l!7ân¾ÚH7â<ÍÞq¥ú ö°tüøqbïËU„U…;%F¦;.îOw]ÜŸîÁ¨m¦?Ýs¡?},¬þtß…õ§öÀ%ﻞìV\Ü­€ Û‚äæ+1tžé]Xy .ÌàÎJ7`®nù™°éEC¬ÛR«™²ÒMï¼'å’½ÝaoîaþêC¼»Ç†mIV~ÕZÊôw_ ë˜}±é?È…”ëK )·Œ?µ¦Ú¡î°;øSÊóSQ¶ŸF#Ü,yÛÛ´h»£ÜY-µZêG!÷·ãFK’˜=r,Æ44Õqn–¦¸­Nt3GØ5údë=³o SÒö¾1§»áSÕZí&ÉÿÜ¢¥Bó¢€’ÓªnÎaN6³@¾yVˆ½@È@jEíT‘ ݘ¬½´‚ÜQ‘ö†s°‚Ìqyå7×¢­ºÔÍcú=‡9ä ˜D½Ç»,3­ýcwf(¦¦³ÞÍMg³››Î·Ü覩s/Q¿ÙiC[ÜhCoÚcò6·Üæ~²ñl·8a;'ãv,É‹|®/bƒN;Q½ÚòÁ.‹Ö-n¦u6 Ý{AëçÓä+4YfžìÞÂâì<X_P ¹Ì@Ù¥Î~µt审t÷y‰Õ…ûØm»¥L•¤þ‰’ð¬ü ò=ÈW ÝXÄ\¹çÎ /âöìFXÕxߪÆny?«öpíUص÷ÐKŸÚ#·|ø¥J|äfÔu:ÀÊ7äZï5‡œYIý >.a/GõÎoŽa¬7G‘\ñÀªÊ T•}qFýEZ5ˆ¨îU’¥tªA½¸ù2ÎÅ miQz£­#óÉŸÂ|[åÞ²‚&Ø‹™„š¡éûÄÀ±dQ?(Ñõƒý{¶à18þÆ~^ƕֲ¼Ãl[ïb²€}Me l"üJÊGðÚ4!§ ;‘5Ý Š‘Ñ%ýjdµ%ü‰ÒuÁ'i³ˆÃ¾âë¡â!9[$Þ„c•ÐË9"xßֺ܇QŠù"A%dõrH² eœP°:õ˜EãØ¢4°›´Ï¶$Ø4ÖGm˜*s|å è¬_®o h÷¯#@‡|-lj(Ž•­ ¹®‰É›¬ ÕÁfY¶ÙÁ;Pǃ2¬†’€äïC¬ó-W(ñÐù¬m,Rcmˬ¤aHÛR¶)r‡ i— iL¤ÝO@¸¿†À‰áó€TÃ.4sÔ@áàG¢FÁ…±å‰LIN"׈AìŸï¯á#*­ôn[Ê©‡Ü-ljjå>JzÂÇ'àûEp¸`©r¸‘­ß¶’`Jpˆ~èшX"YÖªâ‘ó-ªÊÎRÅÈþá ¬þ'j –utÄíÏB¢VÈ"‘÷öœoéÉ¡±¿ønHžqæܦÆ[þžƒçþŽzo*ø¼õÖ™õ.S÷2,9°&IJn¥…)‚ñðbß Üe VþÊqWÈû nBAjÖ Øï§p³üÀ‡¿î ̵>Ä qN,ÈÖŸožÕ8'Ñ@b8óêï±Kk<~‚Ɖq~rTë[ ì õ²kðb»xÙÅvBvƒm" ·¶2>œš&¡–ÿº'YãûœÑ cjJØžûêu‰•e¢´|P ø”QܯÛŠ9w"¦@Ùµeýç!ÙÝVv펷YÙµGùU-tÔ½ªÉ Œ÷PAœ®&ˆŸŠ¡rº ‚âŒ\.ëŒðÙÌÁQßv̦:¼ó…œK£í£uGÅG½ñÒ£^QyÔ[#RŽŒqbƒc^Ç:±Ã±l¯*H©rÈ—ƒÓÒ“õ&ú©ã¯ûQK•ó¼iPðê'æãìÑa&Mšª6AÔ?°­&ÈŽŸÔ‰/B‚~÷üNùmÔWêÄC{Uþ ú³£ÚÅ[æÎ}®AÌOTÑ/›¼uð±f­|%•Àõµ ¨±¿j§øÚh]vL¶ÌÖZºæ,ë ` £@%Ç* ð-˜nÃJLè[Lè[Lè;Lh&4({&Z:šãä,ï,Ãô‘ó}ü¾åïUðNR#ÿ.ÃL";’&˜-þS<õ®ç¢|ÿœ°2ý)•‰²ü9•þ%n½éòß’ô–¬N̬¢4ÿÖè+¬ñ'%û°ŽoÝúÖå{0l³€’ÿǯZê›Ò¿Ïdzé]þç—¹3»@u«Ú®¾áܾ†é}= <‡”‘ôh©£` ÊÔFcì6õ±ôèmãp±ÀtŽr¤È*Û(‘]¸Ñ"]º±"‘JE Éqô•Jæ”ãEÂzuɉ"6fÒ×,"WN"„Ö'.'Â.þFæ°,‘c)«S1X ~nzΣ§‚Óí9ïÍy}cS <ç½þUÍ㻊nåÃo:Ìa:Q×Uy³|x ¥Ç€ eõò"s}È®Ú?— „N·3G¢ËÏ/€ ï Qß×”ïîüçïË¿ÆCÃ$^™—`lXÀº'÷ß¡¦í©uü Þ¡á.÷… ¸òÿRc ðfS%ͶƌeHßÔ—@³C»ÐÈËc «‚ȱÍAIr°ˆÇ)¾my×p)æuÉ»°dR 95}7:’gç_cõµà%ª›V,c!qÅÀ&¹¥oéXÂ:ÅcD'ªB”Ç^•NVBZŠLñwks_æ¥H?S,pƒáŠOFf”t@'§PŶ­Ð#—|;* Iƒ\†K§Ü¼ÀØA Œé=úU"ÍiHÎÄ5yš©4 Y*z…™/l¶Óè¸PG“~ÉW6šd«EH¹ˆË}–˽Ü.·ÁB LŸœË°yr!_YÍ\P×Y2ü!WŠÖ5$H/©}¯ù—×¥ N…Ú@…‚®\öùÏ雄.; þvá ’ÂF¶â¶ÒKkó°–LŒ²»>I a#rØË·wŠV5€©ï€ÞÒQ3ûhêÆb퀰´ôÊn¯{¼¬ªÄ!±ïòÕ¥4êQ9° ¸áEÇ=o½&ð¸ùš‚dž¨x\yGÃãúk:7^3pÆK0òû¹/zÓ¦ÕŠ¥1=Ré$G+‰wß³ kW|ìw<:N…Òn"Z烨žŒ~ì#ù<í{a¼¥XECP-T «NVàØùœ&§s*=;•ΩPÒJì¹kΰ>+zÙ'«x~¾åcsÎèmŸœ­ÀŠߢ«ÄZ6D©§ÍƒýlŸÕc*¡_ÇÊF¡@"^R`YÊ£2®†÷×µj,RåÇÒLĈ8DŸ"bYe„ˆ"’)c½IUƒÇ×O}²†ob³¸Õi>á4×_s@ìÆkâU~FIM¢ù®K˜Dò=dY‘;5eLr*±~U‰ë3øÚ.ƒÂMvaʬ›U[7 BÈž6]¢2pL.ÁUÚsZé=Ÿ€ÃñeZ<­¿ì9ñv×*˜Åõ5_Wk±DÙmûÖZØmUeÕ%´¼£÷K´ìk‚T›4b_ªm滹اXÅÍd§Ó¸E•JmQe›L¯MÇnMîÖZƒ©Nê7Ñ>¨þD®fDûH´¿Ñ~)j©D;^VNj²V£Ô±Èu_5M™Ç‰Àh½Ož¢§U¦Zèÿ ˆËS¾(?òçýšs׸<¯µ:†yœRoBù'‘>šÖ‰Á¦ö‘&?²˜¶×bMLWÁž°Îü¹¦Qs–>yËJ´ÏN¤ÉÛ¸fÖqjËЮ>ß²¹ù‰K–ݲ¹y‡¹™,›Iܼ‡+äùä} 6V¸tݨdæYŠCéëú`…¥4„R“v±5ÐXäc_gËâ§M“ àøxõ_ŽÁègäŠ/¯7J7ÄCØÌ‡2TÇÈ¥ÓåýMîpÃGn/2«äÝZ9LgÛ)¯ðU=Öbôˆ#>¬Ñ%G2F~OVãb4ZÖMŸfRšaºuEwÆè‰Î°í 'è1úcHr¢Îf™}´c+ßx©–“Ò@ˆk tâD'0¢Š¯xÏ{ËQ¥CU¬ç£à1¢»Z¥ËYz“Xú‹Œü~<¬Íj§TÏ,ó}¸ôš™€[£µ¸-ñKÀ[ÁðvþÀ±ŠF¦X«Ëµ:†oNujSÔ7Ó3^¥9q+l¯Rýl×cÖ §u$íëÆß؇ð|XGãÍC1c0´zÍ×Á( Fê²eÔøÔ7žn5ø¾Fß”ø8€®ç¥Ls½ —éªO^AäŽl…H‰ÈOô¬Nø©žÕ ï ùF&ðnFHÞË R¬>FŒ{…Âõ5@‹ýXŒR 0,úáÜ/Äž!Y‰ý28;{û® ±_#‚¯;|Ó×-<Ö3­‹}´ØjÌž­\¶<–­ƒ"t¾E©ÀÝËmé• E~+8‡ xàÃ_÷Zp߇P°ý)ØaS0Ü”Å6Åøx)ÀmÛi4\œ›æ8Ð|áC ÐìúÆýÇݺÁóÛ!ÜbÄ öGÜ^ÄÍõGòÇhŸ$ÜüåXXwé-E»Ž³°˜–?I¶ûy|f|&Ú«üY¼¥‚賿‚ˆvMé³:Òµû7mùZ¼Ý/SI;rÒ_}%i©•ô—Ýé+ÑíN²§ÀÐUí‡(ÁÛv Þæ¼Í%x›Kð¶ &ƒg[‡iŒiéHÒä}¶5-C}/õYU«@ö÷ììïqö÷8û{œý=ù¿aØN™•m žiMEiA:ÓZk§0¥# §N E%鯊qí+È2l@ÿ/ÕÀþ´hO-‚ólÑþ‰ö}CàŒ*_ù;È-ï©ú‘&öH¸Œ½]¼Žh¥?³YðOü‘æ×”æ7±È#Lûr£ÊGðÛöôü¶ìA“ó#¯Úe²½KÙþ‹~a]4îë/ëOï# Ù±E‚½«ÒÒ#ý"6¤n`Ù“âã|«{ ôò“ÈI@{[¶hœeŒß!oÂÚe0GIömŠcBeï“ÇD¬2bß ;.X >Rƒ¤È,7E׈”¦+¢Þozœf†SlÅ0QàÖtc´‚Ë,vG,Kú—­{j7„üˆï™õ(®íA¯­åUÑ:tøéÈÝ@ñ£×ØŽ]oÿxütéáäi÷ße³´ƘÊ-Á6í*ý‰Èü.ëE’ˆb ó‘ŒsQo¶¥RéÇV÷"îÊžÌ0tö¢a®/z”™òsDdK"SObØp¿|w 4aÐÚ‰’ü¦|‹34Â+IÃý¡aþÒªö"²¨v/~›²{ñ&nÆRµ®Ÿ"Ë)³“MñFÆÞŲk,Â,wᅥ…‰‹la‚ruïä–…‰Ë„]7žF`mÏàP,2Œþˆ€G9]†úU\K-HÙU˜ñaqIÚ®ÂiÔ×P?ÂÁ¡¾QF¹jË(S²¥¤)ÙRÒ5[J¢ÀNDÉëYRÒõ´ø2RÒ’lñå (åG (¸A•«jÖìw“÷Fž®ŸJÍÌnÑz£yï{T ÄÔb¨î¦kž’å—Ú5–j>!¨·¿ñˆèã1ŒÿU?Í”¿Bt¿;~U'úÿXÐoß+ô»µ½J¿c:jô;º£N¿c;¿B†ˆ±UŸ×5Y ëÑñ~ª4ZÝóËn´¸ÇþBØYéÅ= ,c¢ü샫.]â¹à2&ø[ô¿û9°b¬á ZrïÉUŸwu¼P>!zð‚9›uõõlýt–&dÇÇBÛìçôN‚”½ÅCÌÿ$»»Px6ø4Í4 x6¸ÜfÚybÚD?€ÿWè³_{dP%Ê'p` ÌI è3>±h_?Ä ëÄ`¥ÀçjÁ-d­À¡A5¬ƒIZÊ®Çv—Ar‘tö-FÑ(4sØ=ù,"&¤´ ªœ„}‹É~Œ‡­¢Sü–MÅÏ9íSHû •ö*RZ=BšûD½áꥯ£õ4œCrDDÌAÄ<-4 ç_ÀøÏ$Kx­[í­áSŒ%´Ø­2Å Öâo<Ô6)ª½ñÒj¯@*Þ¨˜âçõîj,ù7yÍM^¹¯›½æf¯\‹×­^s«W®Ã믹Å+×ãu›×Üæ•ðºÆk®ñÊx]ë5×zå&¼®óšë¼r3^×{Íõ^¹¯«¼æ*¯ÜŠ×Õ^sµWnÃëJ¯¹Ò+·ãu¼ÓïÄu©å"Qº\ÞEˆE¦ùyŸvWvø¾Løîìð=™ð=ØKyÈ|ÿ68t<µ¿s—¡Ò;6§ìVµ¡æF LjàŠ'Nn6‰î,ûD~ijÓÉ‚o2ÃÒ`ŸLU›²£ÝÎ:âãÜÊ~…F6ׇFV ‹…80úá¥Ï[V‘RX'ùñ×ý¢u^4Ý$@Ý«0¥æÑ¯0¥æ1Ó”…Á¹-Šº_ÑÅ–šGÿBxFþº¹d@¡ªxý°~–) &¦ü)†¬×Ê79C[ZÆJ+ŸÑMNùsÜÍbw¸Çlo¸B–uM¾ó»˜Hð=Þ^î7‘Ûûýº¤ãûó&Õ¥÷ÛAþçÀ øÀ ìÒ]zD¡¢zsÚS’‡£þIXjs‹¤ÀZ ŽË5‚ä§„.kQÛ#9Ë Èr³Ôww\ ,Ÿt„¼$ÊêñèQÖå5z"Z£Ë+È6 •áù©Å­·‚«¾±2ªýøë~%U!ߊÎô#k0bzú>°>èêè\>9ð\¥L²Ï]ÅëåSèÓBŸ»*5JùÔ@»œèT »c !³6©ŸS ÛC1ÄËöÐ`(Älý<Â{ÚÃaOi’ì¹Èßœ„Kî$+h]ä—¿µ.[A2ñpè^h- )×ÿ"hÿŒä8 Ï{߆ƒ¡Xd±ì?;É¿°Å~ù_6°ÿÆy¡µ6¡\½PÙ}2¸‰ ®"†§{Ãù.Yâç“ËQ¢“ß?Ô™Z1бìÚ'u NÈDP'g .HA]€“x¶ .&¨KuŽŠÔe€:%u5 ®È'>¨;RPw¹ PçZPwÔ=€:×/÷¦ îÔi¨êaLuzê‰ÔëÍXdžõ4A=¨óüÐ?²ØzPgd b9J+Nd"¨U¨wRPïÐrPç[PïÔÏu¾_ÞOA}¨Õ¨ €ÚKA&‚:3uhjå3T‘ñúZ`A¡t‚òxtÖ -¨£± š•:K*,5êì Ô9)¨s؉EZPçÔ€ºÐ¿¢_ùdN*V¤¼]¨s !°´GÄFDl¦ˆ¥þДÀ|{7z‹+[éwÀ("&#bÑxÊ9¯‹§7óÓ3Çt¢eè\SRä%Î[1*1À ó£Ký2¡$øbnRI9ø›vð{”Χ©@7’p±¦l}ŒW•išVc>Ït\PäE…Dz…þ10ÏšXf½dEÌñÛáUÏ]Sf·Tèmf*Ée+ÉܯOÒ I®XI–¤’,{ÿ˜¼JÅÂ¥¸kv±&P©ØÛåtUÒ›é’#‰¼Â-(L-©tEÁÕÙËÀ Éþ"àæ{!×Ë¿~U|ÔUü]ù´@ñã®Ñi4º5tUþ\>=P\Ù-:>{uS‡‹òâÞÝ¢3è»O7m¹(¯ ÷í­¢ï~Ýô„(¯÷ï­¦ïÝŒ;¢|f x`·èLŒŽ‹ 5á&êç›r¢b›öœ¨°iO<ÖÿNÁcÖ+*³_ÑðXðŠŽÇöR­¥NìŽ&ž¦ÎB M¸Ï™ª¦ã"À5¬—¤l~BM.r&/!àéõR^ˆ€>R,ãŸ]ú we_qLVbOá²ö—záu`{Xwê×AíaÜ©¯Ší–%…)ã „÷™àš’lã WYþꘄ´´òWÑWklP7ñJù¬@ñÒW¢³Àâe…ž<',8.´·T‰Ãï1ƒßcþ¾Ç–Sßcéï±ÝÔ÷˜·ï1kßcξÇ6Sßc“©ô»´£—~—uÌyUÓè=ÔLã÷P1M¡cî{@ÖŸ†±Ö­ÃÃM¹–=Õ×Ý0'Ή®ñc»2Ü(ºÖ ÙpÓè*?Dª/bÌp¨ºE‰-$¯„=ÑØÓP"{£ƒÛÓ´ƒ$>ŽÆ¸¼0$Í Û#ìjÚ‡¡=¸ÚO¿™jÚ/,ë¬O˜f= ,Ó¬$ÃÓb|­?DMå Í Q5®òwYíoZ¹Ú GßT9+XPmK•³[*k³*§¯À_÷k–œºÚ¨¢•…X¶ûj î&ž/Ÿ(ž%¢³©W é¦ü¨|N xh·èÔØªÂ¬åà"’Q)luaj9¸»'ëìåàuZ®ó#Œ 3Â_E8¬›x¡|n xx·è\B8¢›òãòyâ‘Ý¢óèsT7µ´|~ xl :ßÚÌùÇôf-¨»é=ËŠÇt‹.uk³©[lÊßã0+MÝbP·Þ¦îQ·Þ06\øMj^d^ý,Ø¿GĤ®8…*´ty)l,f=ØÝ†™dS!vÚ!bjj.*ätŽ7Ëeš›¶ùe5³[ý–6Çæ @ldóövÜ’ø¤ x Û-!Ù®ëÖ À´òÜ–øQ àG‚·›wØoà¼m€·p{`Ì‘ýh`Ù €;2‡¤¦ä! «7ï´ŽÀt¼ÓÉžò¿3p!.¦ »pWàÊÀ• ûëØm\ €»ýpßÍ7àî À8&)Ã^Ü“x"ð„"Oq¼ð îõÃ)<€{3ï †Õý¸/°Wj× — ÷Ïoì‡Ý†ý~Ù_µÄNÂþ @xp€ï†ÈA<8?p¾*r¼p1ôc–.Àƒ€{p?eø?È<œxX•1Ž·&ðC?t;à1ü0ð~Là¡ À;)€w,ûý‡m€Ÿàa?Œ÷3À/ðp¡‘¯é·¼È8JMÚ¤¼5µ©hÖ¦¢y› _› ?44,¸[Ý Ç›ªxÌûކÇRS‡Ñûe¦1¶ïMçz¬0] é±ÒtCAd•éÁ&ËjÓ»”kÌœeôø´C£šœ¦Å"[ý,ÍÐbeq’窠£€>¨±!ÖÐÞ›­Y6^øS—ó(ãF¿å|l£?rT·œ‚8Þ­0ä|ŠÛdÇmz"Î)PÜf;n³?R“‰sA«%²ÅŽÛòDŒæàbuÕ»¹Dà E¯^¹VÀ½U-•Yðì´ Þ^<ÖW#l"uèÒÁQÙ¡¢1Ô[ˆÊ´¾ÉfÿûyÙë¢Ùx-ñbÙd½K:£Ú±òË?‘ë´p#Ka²‰\Ïqë­8o•Ü …s¬¸\¹I 7N„j8ÜLïɰ«î·Â®ÿ¸qÙ†EnÓâH„HL³l¤b»g»˜aO7äm0s÷yͦû4¹‡IØCI÷1y{Óä5•û8nŸGäíO“G%“§U÷@USúA¥‡ž ô°§?;K¸iµ<¢!¡ŒiðÈ„ÇmÂ>É×-)Â7™y5Døf³Ùq ž ˆ¸Jz€ ¯MÞLç¸ãV~"Mxsy*‹¯§™Z½Šê Q£3ágŸ ü~$ªaÈJn^-/háfáæLøE›ð+Or„¯á[ÌæWÑÓLßuM^eâ®RÒ˜ðkiÂ}ðŒ@q×­8"üFšp¿¼õõ¿ýõe¨{¢ ’Ê ÓÌ÷UËútIüÕò-ì û¹$ŸÚ%¹guÄrêÁ÷³ö€Þ-¯–c þ#‚ÿÈâÑc®Öpn•l Î%+áÂÈU%{é@–[MœcD½u Q?{u9kY¢z Ñ`èûlJ!¢Çé©äPåUÉazØ)‡ÛˆF0¢¼j*#i#£óDã,à„f¼ži®hs Ñ$B4IG‰ÂMªädÆ%§è4Urª66©F3žFXÑtQµÎã ÍJ#š­[µDshK ÑOÚ´fgØ(ÝX¢P€ 掜‘{MÂ.ú©†‘ Ôî"Ÿ7¡ÐÏàñ#gä>RÜG€6\‘Hñ  û(¼¦Ç‚/SØQDÔè]^V¢üòºŽÖÐnèÁvawØÛÅ2…d”m*Ñd…)Ãm’hîò<,ß5†q#wKGcØ®¼cµö¸.?£7{N ç°»»v›Guy©„Y£ËûLŽ»¥!ýòŽÅµÂÊ6—¨|çï±+Bt/H÷´l 5¶ÇÀ°§ûrȾ,Œý ¶Iû)Œ `ôX7ÑÔÀÐòŒÃ ÂHÑ#°×.ÛhÃ.-6Ó7ÆàÒ¦±|Â48½À4˜Z â#aÚì— Œ-_Á4˜(z†oÁ\¶jÆt ÓÌTikôpN50ÎJcœ Œ9À8ׯ˜Œ[üržAæ+#E/n^,½l£Ñã'Á-ö²í&-Û¦³‰e[œ—mÿÕ{ ûºŠhùÂ@ÈÙZb.¤…ãØnÊ¿”/ „ÌEô9®›ú—:qãÚ—/Ám‡%6¸¥Þkœ Ô_±v˜iZhšËËåKö[si@ŽA ‰ÅIÎñ䘇 DˆP÷Eî·sV¹Âáh ½šL:ÛO¹.þdºc™tûî@*݃'ÓÕdÒáš›<‘J÷Å“éj3é®"ÝõTº‡O¦;^¨¹Tm˜‚„÷„¥ž[T9\ðU`úÓùÀì®±ÅóÖAzÞA|!pOTyÈúLjƒ_ˆxdŸŠ· ð•i„zW8Y{ÃÆ·qq¯—\k‰Òõ…Ýp÷VâÁá‚’†µÈ¶\ù+;€kœâE§ÑtOCƒËé2ä%´Ä¾C2H qm6‡öË`…ª6Ù…Ÿ+Z‚â‹R°æáÐìè¶ {寴‘ -DC˸(|Д£”Ò/T…ŠHËÒàÉï‡õ.'¿/T9–µq 5·ªU3[ª•/±nÆèi0kª9K‰çí³Y3GaÖÌe$u¾'bÚr8Oqh><%:™C.‹C®°“9´ðËZüU$ÍW^t9™C.—S.·J‹Yçä8Ã>Ñ•BëvEœJm/žÖ‘ä1IBY,}D©^ îÊ>º 2D xWÓ:7Ó:qh¢}æ/êþ±ˆ~héTÜ*Ìh>ßfºÔ'L¢r/;~ž‹\öG/ùåf•^¯ú£ù¡åciE_÷Ãýºõ~%Vü|Ò/£Põ² K ¢°Ð_>ÂÖ„k–@ÌÈTiGâú Ä›gn ÆÊNù¼M|ÂÏGøÕvuÚÏö&‚I'ü8 F2h‘O~2YÚÔTÛCÅøö©sÃiò'mÝ:´¶ òY Ë[Ö}éà ,„ªâ?ÖY<Ãßñ«IÓ1GÈ9Ð,ŽE®û{×ÂN¬;™xÑ$ÓÄyœ/â-Ì Jø¢ª4=CsL@,ÈCòfe߸a¿ó¥ëzÆwHµ̜Ï_p¬ÅCS¬r½¾/}KT¾U“û:ÔK”õ ¹Uä:´"àì¹w‘bÎSÀ^‘{…] #à¹GÙ½¤Íè#"w7}çn³lDºka´ƒ˜RÕ&ÙÂÀF[n_؄氻+LäþÌcrØ9;’ÛƒÏê6ºµ¦ævf+[c‡i¹à¹RXŒ·Âtv½xˆÃ>µÃ \‘)ƒ–NÞðsºÔ§Þjhpê ôßßÐк¡á¥††×ù?EÈ„H«D%ÁÖO ¡Ùûpõœ°„ÏW™â²„µ…K‰8*wXùRåEQÔÿì.¡ê­‘WD‚­·^µ‚ÿ¸»$ ¯‰à¢ôŽ_X5~ØwÑÓYÞ°=÷)*ŒÝè´›$‚qŸ _R°œYW=ì5=Yžß›ÄèYþγ¸ÓöÕw†ªï·ã,ðwŠŒ/êZÓ#ÔÔt—&+!cÜ)Tݺ1Š›Ô –1ܽ»ã¯ÐŸé AŒ(DòE)†Ð£ÖT†* H¦°`¸ U˜²ZË=ºÓ¢Ì•;ßÁžL°SAy›úD…Õã¯ûÛh &/bfE0ácb͈Ĺ$7V‰%¹tã8Q2¬›»KpœŒ¢("XNRÂô/a›yŠ’aÂT~O† d™¡Ø©R’xåüÞ°%¿™`Íg…ªG73k+V÷¶¼àgœÌ™Å NJÅRzÌ|C˜¦ Ç0IS[…ì—ôl<†8bÝh^–bÕ ŒŸ×ý¥ý¢ÒKÂÄJ%ÓñW®°Ö»ÂÍ¢üÉ>kñ ’fä‚'Ù¤ ŸÙ„uþLT=ëXœY¥¼èv5ÝJ…r»\Ðà À¸Ï»$Ítfõüã¦Á)bH® $“†`!lsl³£˜‡ÛíDUØ ø‰×¸sm$ VP¿Ú®Ý-T½º±¹vˆý‡×d‡ÖAÌs1óYÌ;b1/f1/a1ï(Üð˜ú)æ¡qšõ>Ò<Œ1¨¶Ä—¸˜ÌââQpÑ .z,.zÂn›‹5Ù\¬Ms±\<þe.U^ô¸™‹—›¸˜‹8ª8­$ߥը¯l^:Ï*ìƒxäd^ºHâ»R¼¼`G1//Ú‰ê° XN+;Ùl';²½NÞ+ÄåëÞ<Þ&Nã¨ÍËq[© QÇÌQ¤ÕëÙ… æ[,…$•½VÖó&NÝÂ%Œ°þ,‘ŸÂï ;‰w”D²íöZ’NÃÑA¿^yÑÐy”À%ú»,²^(TÈ DJïÔŠÞ$Ë2EoUöU1ÝÏÌé qеXE.aN` 0±2%¸¯Tqg:ñ}–|‘A°#…`!XÚ^ìPå.Fð0ƒà:Ü$Á£ ‚ú‚z>³ãJîÁcä[±Ä¡ÙjŒ` &k™ázÔd˜ùÖT;žŽ{À¦â[èø”s¼•œ§Ñ㴩ΤÇSƒ볦>[“³ N¦÷kþ¢`¦hptO”^ó+¶§kh ñ$ÂL-8 ‡e"|Ÿªk‡ôˆÔ·±BØO„FÂ9;”Ñßg»äóµ`NÓ¥‡­rF!_Ñ1Òº…¾ŠÌ‰Íå"zIššó‘XÜœ ò¹WÞëìñË4Vh8ù²dž.%hǾ‡âSÕý%†êp(1´;~ÇÁ‡®8>(1 ãÇ“‚ú¶€´5“Õ¤nMêµ\Õp qÑÇtL@Ê ]Ó¹Sòò¾FÖ艖 ÍÀûZ=ÑYžà«ï,ß?!ƒ4yROÚž’ÄÓøb¶nqJOÒŒ‚ŒÙ2Øi«U5¶Ú¼´Î-¬Ð@ÃZ¿¸Öþ zU·äUœê¼(ð8ñ²‚ÇáWÕ«:oNâoØÍ3Öʤ[“7q|Ô¿ÆÎïÖg¸ä}ÏJÚÿœ_ËêÝyI´P ݵÕZ‚¶Hhu10ˉqô¸d* 9ÚH·È1µÈq³ ±FŽ·>xô›`Äâ¥$¹a°› Ãý¦:Ù°Šü‰[œb$ÐnuÞ-'O3’àa²Ráí­’Ú_•§WÜÙ*t»·érŽ•“'(±Êy:‹ß“¸8¶Pºk9h¹a3ž¨g/ç")k ȧêZz\1µõp .Ù*”l‘2kåZ#[xÕäz<Òå&«H‰ÒOÝ lÉ¢×°é5än#™*é#ÙY8žC´‹«£¡ÿ+!ƒZÀò@-ÓOBÀiÃÚI1ä ‹T\8:i¼ICçi#赇Ó.^¶¾xÆH»lîú/»éWä4džÉ8#•q†SVggœ™•ñeœ…Œ#Z`ç‡1ÎÚ=ã8|UN÷:¾ŽÆU2ÄiÅ(Ý¥øVôŽa}d‹ÔÎΘ©›¦, *)ê^/¢÷ý¼³3¶Ÿ_|õ˜§º›øUù¦Àoæ&¨ÿk¡6Qµ3jý-Sþ#o z‹HÆÎÁO£¢ÊŸÀ}æ…bÇ?Ö‰y…ð°{ÛTÞ„ãNõwuâcS#’ëLýí:!Mã:Qo:{Ô‰OLWÍÖýGùÛàž@¼tO@Tþ¸F¾™ˆ-x¿Vþ. 3=Ô¼âܼrul.õ°yÂîñPé€ÊRêUowâÉÒ¥r¼ IçZ¹LÌ'²œ²‰$Í]2:ݲg¢ôd£éÓð$žˆl. >v¸„cÂpϧ¿awgÁ­@ ücØE«#Oît–è+ŸöüIþ‰¤re*=Râ È?3Dû†zX/Z4nUêÄÓû¯ò_aoim#9òßÂ9yϱ­~3ç?äwÂ9´šÝEt å»´¬kTz »s9áª`£¿Ê¿Æq‚A,–ÿn Èòo”¸1 Z {vT°“†‚·©ÏþÏWÉÁfXÜ»Kw,ðÙª—ŰÛ<\"‡*¸Ã1¾…ÖTÕzPÍcØ3,[Á€Ö¸¨²ñ¼¹\Õc×õ86j¥Œ·Î¨`á뮩M¨u¶k§°]{ÏtN£Çç¦k:=Ö”¸gÀÞ éÙ€”NïV˜· æ| K¸ÙMa’ˆ‡ÞPùÕódaW¹!§´8§œ&¸¢\rºh]ÁVp#ƒœDªGV‰°'¯;º½„~b¹œ#®àOžҟðË@9ñ\eéîÐkÐr¹H„¾ IqK@ð唥H%V«r¹hE¸°éµ©ÞKä&öÚ3|؉•¼ÏÆ¥6‹8•­÷`Ç­¨2Hm`•¡hŸ9mÁ¢xi‘ˆìmd9¢ÉÉ…·å(å*Öþß)‚¥ñÒR©J¥»5¢(ÚÆ³Ñ^ìÓ…s"Ë<¨¹O„Ñ‘M¾·µŸ¨âðAü{ð¨Ž+_¼ë.Ý­nIhƒ–%9a< XJÇ8NPlg& ÎÈŒßL9/±‰ÝЏJzzœxþ™ñ³gËä‰}ßAì ƒA`v³Ù0Æ,zA‹Y̾6û¦ÿùº·»ø½÷} ¾·î©:KÚNU³"%»ó‹xðÄo*>`uòÈ„°<ìßz=XÙ*$WÅäή²sþ•o»ÐŠÂqœþ Ã[ðf ûvö!ÐÇðªl¨…<*¬ŽÚu€Qìç"²:T„„M#ß`8%TÌ‘p¬§ùù@¬-ÍlyIp—"¿íTÙ Uƒªm*E ™ŠMv˹&¬¬ÎùÔ,¬,´vû˜(lcŸiò&Á¨Æ¾o1»ð¾ªX•·‘àO&øå]JëÌÞåï œ¤7®ÊëBy(ZØÖ–ó'á’'–Çøu‡Áš¬‘ª¬ÉüuOQïö–#‡hVhk‘CÕZO5œR™¨p¢GÞ·pA‹t·ìVï‘£4ª&?ó…ÍÞ¤Ud¬¡F_¯Å*Vû\,ŒIÚÃ…1Yá­Þ©Zº0¦i÷ cºvŸ0fjJÊgZ,%‹É6‹ˆˆ¹D›bqžBõ2PÍÅIT ÀÈØuÚ}8—ÜsiÎeé8çÙ8gó~j,¼ÜÇE¯×brŠGËy¿]ñ9¾`de×i}–ú䇹ÉÜÜ/CnÑÐpú,ó) Ö¤"ï+ ôˆjÛõœ°ïÞv¥ð †þL;Ä»¯úgº5㘆&jžÇ·û+ }¤ç ïÌzêò –ÞÉÒB!ô\ÔPæ3-VS6¸ŽVTò˜–/óñäñs äx3L§gÕÔÙ¼|R³›)OÖíÁr;£Åø…åvžŠâVè–4ËíuR»(¨Ø%§(·ü*©VyEK¥7µDÍ$ê až½­!¢RAž Ù»‘úˆD·Š¥:“ÒOM‰ŠIB„§ëGu˜áx÷´U¼Ê¬ËÁ:V*ñÉ‘:BXY†­ ´ªà‚݉®vÁn„æeò6 àžN ŽúÌÐcüÂb¨oajÇ?“þÌÑcr®âîj?¦³:¼­[n¥8 úôBm¶ƒ^¤c®åi„™ir‘™£Ã@ž1žÏù½ªzÏ\õÞKpG™¸¯æ½ò’Á}6ŸÊ|_®yhÖe¢³'W_RuÉP­s*ãŽn¶™œš8>îŒ7÷ Ëä#JmFr8ëÚ'çg<\¬ e 0å’ö8J3д•f•ší¦°pS‰Á¤]¢›Êä½T- ªF›ˆ²FBc"Î;‰f, _S‹pfh¦=™Ì7ZôL6©£}ELfK›†ŸèÓ`ö9c1ýÜëc¾K?#Ÿu/3å435Ê“Ì0ãÁÕ= ` o0c‰>C=r®ù¼œoÖ\üF¼bÇ·DP°G¡œ«Üô-M.AÞŠÍ…lç_jÆHlöh]Oœ,3cqÄ‚KЛG®01 !V±\eÆB?èl/ü@ë³Ü'ßã/ñDe}gMn0-7/"ßß•k|‚cnJ‡ùˆ`Þ²CÔ{Þâ^åcÂU9ÌCkz |ïù4¹ršV¤¹iŒcËÀ^¶¡>! k¯Ö^–’3á?I¿eÊXš\Zd³«ùØ·R… žøkÙbÆV•aˆ-•ûÍXY­I‰TÝ–ù—×|‹Í§ÍXå'>—ˆíÄ@Õ œð^ÿôµ¨’án[u‡»[Å¢ÀÕÆH7l4ú(7 3Æh·éN¯”Qîl0DÜh7ì+Ô‰Úç£ÍxÅÔ€èÌgëfá\â|d ²7æ%¢A!›K?m}ô…n9·–·ÝñÎ|ý¾[¹“]èNàt™2™r‘V##I\ÙFšåR>ûfÇŽYîæ9jòã whki\Ù9šyi¹ÆmÏb›å:76/g¦‘q”õu«ÛÙ©³´­¼ç’«¶^r°óÒ¹®ìu/ý |=#}†øÛÊâ[ÝrOاPl½®ËO6³;§Árõº!·»yûC7òîÊž5õb0 ôuSîpc£sAOÞw!k½x¡^¸ÔÇ=”PÓ¢qY5Âä^dðtÎÇé—2äâ½â‚p/ü Æ©\>r°Ø„üSçÿ’(âH6#¿:$[w/¹_Ñç O- ×[r§ ¨>{zä Ç pÌ-?ÇGÇþã*«ìkÑ8P±¯‡Fòâ0ß'ûƒ.øXÑïÛ$‡ yšñÑÿŒ®•Óš<ò›zȳHw3dÛ¢¢©Kí¼;§è¦‹n®@Ÿ¹C[J9×–RQŸkQw.Gb½6W_¤ún¿îÍ=\"äjéáÒt¿—þ¬ë@—!\{¸L’ô¡.w®ë³.OŽëp—·Ìu¤‡+C¸fišnüšrÃmï$ßpÃÝÙé n»cÁA–óv‡ÞÎ…œ7˜¥[ðR¤ytãM4£ÖÔE±\#»îecÜBg+ô°ê™°RºfÎÉOˆô³·Z{‡£jêKh­îÁFÀ›Ír‘'ÞEà,»lôÄzÉ%ž.‚V÷oñˆ<üec©G.õ(ïô¿„n,GÌRÌŽö ‡ñê)Ö•öÂ.WáÙþóãj¼O@ðŒZçaS츨ÌÅÜуµ¼czÞèÁdnNN¿ Îvxì¾g‡GîòÄjÎd­ÌÃÙìO=4? ÉŠUœÉö4­—ÜM˜_AM÷xBÛJiÙê§b[)}Ž"Sgu¹æápíë@r€‘Ðñ€‹2qÄ#xbu¡æœ<0ÿ¹'¹ÊÂâ©Yõð:,÷8Q|’ž¢NÙDÅÛu&ë¼¢´3«„ú"¬úo9gV)å;¡cö™Õ/Å£‘Û›þü¢ti6ýÆ*ñtõ'¥Á•ß‹|RÚ*WiÏUo/ .©Šl‡AQÚÿ¡;êz'‰þ*ô¹ð+8Æí„4 \˜¶á²ˆ épyÅ#ì7é ·‘÷A:#} °’ r0¼Æ®ÎŽU¶uÒäŽ2鎄ŸZ°Žz1\BÕb˜Ã ëHØ¡'>*& 9Y„žæGO OßÌg=ïuzKÍ-PX¸¿ó¦LÐsc,ÂÓ*Þgâ¦Í û­ÙÄm›™ö[ÌÄ Yö[ÜÄíœÙ éݤ¸ˆ¨ÇCÇmq]!q`B!®¥E©Ó´ËŠà¥Óåa–ü.‰«ÄUí߇/ÿ"œeé‰Ï£•K¦š÷H­²ùæ =Æ*F•‰ºÌ&Ü›YÍ–œ xRç'‚´EnÝt(k-üv3—7M ôÅêì~$™N8ký `èSntisDͽNIÀ{Tñˆ© æÑÚOÔÜñÚŸœŽT¨%ÔwÔ‹’éBõ¢DŠã¯£|Ê¢QÔlÌÃß;^‹éˈ@4<*ˆÊÓ›ò]0¹²ÈñgI\v `ùøÿòUìšõgþQ «¸•”=ØJÞ­/µŠeUÚï[Å´§ô?Wï.íÜg7Èjîm^¸<Ü’#ßúG\ËoÕìV!W¾M€5ó}1B+ú?.(‹|¢zG)ÞÃ;Kûì(•Ý«w©×OKûì*e`ïqÓÉB‘ÕÿokvàÖÓšTê¿Pê5»º–S; Õ2H¨)}]‘ò£Aé?%Îé§jô<üh$õ‘R¿:iëã5ÒDZ¤AŠpÆÝYú¹«KõžÒš¯ŠúìÇïÛê9Â’O°³ÐžÒö”ºþN0õ93 à/B§¸ø×éßË×!ìq¤ÅF"Ñ›¡TþCzÎð¹¹›ß j†¯CôÉš9ÝÃC´Î±Ê†ïÀðº9=}h*} pz»FŸLy L÷èöý—oØŽÜ"ãðº^ô5ÎQVÀ9Ê^ê «"{©3\U¥=]- ®®ŠDéõ½*½gu¬4¸¦*£×µUÆßWÇKƒëª"qz]_eþª:QÜPI@L[Ó{Α–ü5¥}œ=%”„NÛ¢¿I¢¯ rÙ–Ö|Âmý©Ë£,ù¤},áIùjò{±\ŒŠ=~é‚£<‹L ȧ£¿rE&ä3ð{ÁY;!ë ëø,×ÈÿŠÆ*¦0”ìÀÑ(w|/ìïØ¾Û§ Ž=¥¥Ý\êVëÑ„váhÜ“^ì/|Ãh)¼²uFDÈ›ˆ…ÏôÀÛJ‰õ.Æò-dÜêdÜJÇZb+¶ªœøWœí¡Áºsº€2µ8™Nnœ%ÐÏxK;H?,ý35ç0bÌ¥ã>¨Þ^;Ó£E~&º´!æªà›Z]ù }ž yÇ™±‚¼'e™©s\`È&XÜÑŒãrú”@ ™ìö±mÊlØ÷ºÎ ̦vÙ1,«VßÅuºYOí8Öæ.ÄXÍ>\8VCD*-6žH! ½\L@³ uÇÍ&&Óó·µXÑÐK.ÔºÀcl´È L‰Lï;™ÞרkÚ”@²t… V„¸½#Y´{øè-æœDìk?ã,-ªÁ{š-Ð~-2¦%⼈>œæÍšÜ§>Æûœé!›ÕÎN1»j×”lX°8ÆxP{ž0As¤ Wí‡Ó<7=ŠæOöУÐ#ãf1)€ÿ/ßB§QÏÃ;Y¢èë&ìã«èòDn*øù!ZÃÛÕ^¾ ïèE¼zVàã/íIÛ/[Å~>Poi¿•/Gà Hh󙘑ý:Ó#²€xò‘ùì¬TÇ­ï7Ñ8¥Êš8²e#¥¥,ÈßFÃoâáó=ê–Zd8‘ûCúöO¡¥–\œöC$úœï!Ÿ/ ĺâñ ÂGrÚT ‹–Ù§.']``•ÿÊPTdç ~ÿ+•é͇f’ÿA7S[2̘ŽÿŒñ}i Ù¾?ðˆ«NÈ:4Ý&ÙÎ`"ë›0g×[bµ­½¿ÑÆD RñQñÓœó#T6ÍÒ€vA`³vA€ÑIb0W †Ý_Í÷`Iñ² ¾y–ÛHš1†·gãö½…oÙ‡¾»é8‘¥ÔW…&‹DÅdÁh*7z5šÕpì¥1|wa—:”óÞÕü§¥hôðô.çql =@åä¨\ˆ-"öÖRD:ažbѾ#”lÕ©ZDüëàÉ¿‹u´Xk{òÄCUùÒ׫²Tª|9]•ç+UþR©ò¥UùÆ×Ðx3E#„wK©òí¨¼öPUncU>P„`u –í@MɶÅ>ÔIšÈÀšÛœÓÑÖ\m8.ù´ëìFh ;luÂVÛÅDÐ(M©-‚MÐéZ[¯Ý§µ“4ÒÚVZ«O×ät¾¤`Qº•Òº-ó¼Q9TZ£Ò60lú8(fS¶^T0 #KmÃÈ|m‹–ó×|{xÖÙF-ŠÈ»ŠHbðb–K´TÇÿ®Æq˜†ª¤NGIqWhP܃E w:ky€&‘®Õ’Xàgÿ#Úz{ š\¯Å»¸:¸iH|Cm#i¿Ñ"7°ˆÉÎá};‡,Õ9ØÃBc=Ù¨©¤×Î÷(•j*òa]¦ùп‰d,·0‡xà,}ÛqÙz'#S7dviÑ.. qŸr´;Ù8úÆgœ¥#²Ä‘¥„Kq³šÏWþ¾dmú›“€S»<â ÆÇnvZ‰U\«¨+×øVLèf§XÅÍN"|«å ™A"^Ñä½äçTg°Nh¡`¬"(â{éËi-‡-íHš±á(ÓV¨¦×¨æÍLWdY“€› þOŸRß]°'á·i>/€´¯´ÐE;ñ%.åDö¢úy»ÙGz|àãEˆÀ¼<É’ßÃ瓸¾‡zñ=$•ùÓ45XAssšªO×Ù“ã žég¢7Iñ•hxy€¸9Y·o$÷±-Œ}Øôò»Xâ/øGRƒ†×R'²>–=Ôã:<Φ Rlš†ù€üoàÚåqý·üߢÎ6––¯r;Í%ú ¤”5#­¬…RÇÒ¼/a}d¯áÕ¼:-¯0ËZlÒ ö”ªŒØTìHu…[Ù²Qþ§|&&ÞÀÆ* -Œ&@a&xH8L¯îåà׸™QŒn$3$3’Y‚­ÓkIw{qa©A¤£z· 'Âò8žÆá>m2Wå«Üá…÷~bÆ?@Ì|&f83-Ë[óËÏV øîëÛ1ÜP±Ó+êÊšÙ©ÿÿ Ë61(FÇŠ±ÅÁ²‡ÌÙÄô±Â²-ÕXCÅ.…å.ad±êE¨„¸c½‰«htÖ§^ô"£ÍtÔìQ…æs¸HìqG„J£Þà5]#jw9ʸä”q‰ÊôŒ Å‰T¤^¾_öðº×7RtÞáì­½]w„¼gãÞËtŽe:'± U·«ÏP¾Hœ»óónrE½â­< ó0Ù[ŒÕ°?žøËˆ WÖ$Gò@ NÓza¬–Îç8-Ïe¶×Ú+–Nµ®½äd ½ß¸dïC>ºlwuÚ£‘^¤¡Ïý›<7W¹ºU·”·TEZ¨ƒû¨J|¯zipù÷#ûéuk•Ö³ú@iðãªÈôwŠÕÜh†%{!®z„pW%‰uú¼/m¬} ë†Ò€µ¾–í‡õ>“ŠÝ%¦ûnöå™–¬f»Y‡ÎáRnté)@ÿ )õú-¢ÿÅ­âÜK®j6ªÑßó/iôwåóºÕ*6ô4~×*6ö4í¢­£û‰¥žžH«ØÖÓûO­âÂw2^k;zú~ß*fYþ×±›ùÏ­böKY„ù-û_q*«Ã­¢ÁÊùwz¶r“ͱò`VÝõÝü~š´ìf¿‹…7pH( oÀƒÔ?ÆÂ[éÁ##¡ÇbáO‰7k½òŸð¶S½eÈ×Bcá5ZEGg¸¿…÷øVKˆfÝB ¬Í”ÿleò™Æ,ùÇnµÙòßkvv î­l¨Í•ÿI+3cYn(ÂY¹–Ûq d§ý‰Òü©´L¤ý·åÆJQ$þlùí\^GK·Ð£ÔÏvMçZèMÇ/<ª6·û ¬ä ›šíZîËß0°6f¼|<±¬V¦Õ¡â«'ˆƒ9BXyVŽ¢£8F)£cäËè†ÃqÝÁ1–q |j1«ã2œ¯pÓ‡âkŽ®Ò3«‹à¦ªÂ¦Ù…MoWØ .l µF{ G¼rQº72dzUsìæ¶+`ðްÌ\À.R°€û|,|")% »\0†»Opí­ Ô›©îVŠ®Tyk ®%˜“ðxç ‘ÿ—lMâ‚7 à·-\^ Ç“ÀoMf†¯Ý…•ߥ-ÿ ˜]æ[ì~¿‹ Îlw«U§sÄÊRlîR>µÙÜÝŽÍ=Œ!†2EÃT{PûPÑNM¦Õ_³*ªÅ.j»¢pQŸ «ãXPsLXžš5ÂóJ‰¢l–¿*/8ÿ%[厫âN ¸–’D[ ß,ETxƒŲ7i¡Ç¬L:áÂK6Ÿ!üH³:AÊÇé‚Qí¸“•±„kç%äíòbKî º%kg' y·–’c2»W5—½*{Ù—`á 7%³Ç9{3þº\“‹ü¯#Fá3â!Zòœ†!þ<ÖŸSŠUÌ@J……ÞZƒ½ÃÈÔbCs{þêïõºœ ïœ0Ö9æ¥izHUè¢NËÁuŽézÍT=xP7ô”3ôŠ:C«Ó"ïäL¬§¥°m¶M„íC`›ÎØþ¶9ضé‹l ÈŒ ²Ý¥ÇↅüÔÁ³±§Ü­¼åE> È=@3#…FÍ—„f ÐÌL¡¹á ¹¡#¢b,òQ€£)*4w4÷4ïZ²ÍF³…–4p»1+…fÜnÌ‚'z iHÉîmà þdÀ=,²-wû¶ì4‹ õ±e×hØÈ>ê)wuÈîã€\l³SØvÛ§„m;°ÍIa‹;ØâÜÀÇ";ðñnckim¿ƒm[OyÀÁ¶= ÛܶÛÀvNÕm^ [ÓÆF Ø&‚4ä`ÓÁ6Ĥ9MˆllCMÛRK3+î1¶]9gŸßNak„…%f4¼Øæ§*l¥ƒm¥)WÛž\vÛ¶Ö´+lƒgGO¹ÞT¶; 7Í‚š#@sŒÐDæšÓšÓ&<>Ç"±|?Øh.8h.:h>í)¿°ÑDòÐ,L¡Á©a8D'€fQ Íxçäx7ü;Ä"ûìÎA¡™ì¶ÑLqÛh–Yrª[¡Iä4NnL¡Y4ð“Ð 4‹Sh6;h6»åG@Ó'ÑlsÐ|â ‰÷”Ûm4͹h–¤Ðœš³„æÐ¼›BsÉAs Ž à06š¯4W4ò)yÕFs ¯ÍÒš‰B3É še)43<6š8ˆE> à ¦fŽÇF3×c£™X$çyšCù6þ-O¡Ù4[ Í Y‘B³ÓA³Ó#?š£Ô¯$ÑìuÐD4-=eÌFs$ ã@³2­š/á¦hV¥õ@šy hŽS”Ds×AsÏAs°§l³Ñ|N=©RhfzaަUçI y/…f¾×F3ß+ßñšS¹Èë iôÚh{m4‡{Ê%^…æd@¾ 4kRhvÍnBshÖ¦Ð$4 ¯lš³Ù’D³ßAsÀAs¬§\ü´*röƒˆSÓ]vy¹…Ã*D\¬yIàgíKÚT,áì¸rìãsc1àüYvs––k¯{Eèb wì…‹½îb ‰&þ±hø‹@Ÿ/¨u‰d,¸}l0û°Ø9:Ge‡¾r‹e¾ÜŸŒ\ üm*NÕžfÞ]%ž¬>R\òlä±·Ñ½Ž–Ÿ¥×½UúO«•?9F¯Ñ*ãgÕŸ—gF>ï›ÓmÅ+-޽%i7Y‰Í²+¶Ýd€öhäRi ç£âÔ‰µ­Åšiº{]^eÉ…NhÏ‚V1úŸ}™~>­/,ïpà¥Ñxä‚_.+ˆ&"ýryœßž÷Ë83ÇF™Ž(p(·DÃüÑŠá™0wm+þ:_¼ŸãÄÕO‘O¹~û¹¦×!"J‹yÛ±|äJ¦HšC¾'¢¡e"úÂ2!"­ìm±3ZŽ{½½ÎçCîÂŽ9¿“ôaù÷ÅN€¡•3áu”@wÃÒ³=­¨S"¾ª¶Îð#)=VIïJ„튧­ ùH×Îb寴b#e˜ _Cµ«ØMÚù)s1!*›»µ(ÿ·»Å¼ˆå/ÄJ`µ%&ÐJà=K›¨aƒ¾äá\Àd~¤v߯!>Ûìw*!*¨u6Ó: ~or–ÊĤ²Î±³Îå¬I߸óÒ²·ÈZü­²\¾g¬.P½£E+º#´]úiŠ]ìlñ–Öu°»›«ð[øð)o<êíúTÃɵXäz€Ö (lr²°( Û“*ì »@…Ý@a{S…]æÂ&>꺬ɯPØ ê4¹°)É®¢°h1ä=Ê¡Ûç/‡èrÍ­+Z;9žÄcÅ8ÙP“1E§õDYSør`Ss,ÞçrÀ«y… |gÀž\À…4—¿èâÊÆ©ˆF;׿´\‹m¾õ®­ìK2\Ž¢Ü* PÔõR}aH!žb¸{šåæý©ÎnÁðsà ?{~¤ª¢“¥û‹¡ô&.=Bé‡õh׊~\v3wcY%{oa“»ÔÙ Ôi…¢Üáz”;\øÂ *×öÚÌÂWÁ彃³ŸWõد œ: ×ôÐò§/,Jèˆf†6ƒ·ù1¾Ú£üEÛ¾Ðhýb;Òb¯sý l3·nÓ}€Ii(îöy,ÀHå¨?k,­Þ£8Ó©"4ìT¯HŽ+’ŸP$ëc 9ÖH#yœ·I®5äxƒh¶ Et½£ñÖ@:®îMAwnïÙ9ìÓÑñ`Ø¢|ùô}Õ˜eðJëj N ò)¬†²LvôÖ"ç*ÿ„ 8 Ã)(VbVµw„ïr­‹@vå4¹kžÅ©À–ÅÃñnOД6(1l5ŽþkŰ4)† ùaº6¥‹asº¶²¶1W¶§–hø]Ï[|§{š þÞw:`^뛉S,pê¼ÛHز+ÈáKÒ©|XÅùÝœ-«}¶¬Øëb¤p0%®ã,®µ–ë¸!O:âºÐä)bq½ À«àU%)ü4éÚu¾Ü­ß0äu#Æ„È}…ïny‹Š´ ÒFañ®‡†òJrŒo9ãÔL16ÏÔ€eÉ[3¶/%uóŠjgÉ>Û†˜´®|@€ÿ†º˜ó3myIcÊ´˜«™í Þ­â^@ƒ“b3Ñ¥­Æ¾Qf—¶^rŒ p\P]5o4«ãºãMG€1'0n Çš[´¸et:BTOB9E3Å|H=U€žÉOÓp­Ù®-,˜n—£˜yŠY@1Q˜b“9ßL:7Äù¡b81AL‹M{‹d³XÉw©'?¡-3å²$Ò¹<…så}8WçràLt„»Š5&ûNžÔó¿øÜzKßkâî3eH@-ø´ZÔ¤™MEßL‘WiË.nâÆœÙdÊxº›˜Šœ¿?-üÁrC–Á~œö›–›€7™[Ü8 ×±…øÚm&6·$º¸ áÆä¨É3‰£¬×ó˜É &÷Ö)gLôâŠI«þ¯í²[MÙj¦5|i¦ºìËfªË¾bÆà iͳ»7ýºÉn$UÿÍP®$IJ†·ø5Dí1ÿbºíŠŸü„k°[vƒª7šä7QšýìÓnFõmu,]ŒpËîØxÒím”;¯¼ÜIPb|s3UTá¹¶6¾ü;ÞtfYÅúçÅBƒMBÚÀ¾,ýM4RZ®9¸™Ì(p'àm~¬ØÑÝEßÙWÚB.§âJRd#{<Îãf5ÊZ ûÂzULHï»kVqÛMÑKnâÜo©ý‡ÆEi"|­Ç[ØD•›ÝÉ´Šk=H¹>JºT$4'0Ðy·p­ÆÏã-ª{ŸåŠ)§•Ín™pÇj¦Š•lÅÝ玅¯÷è×$›Ý]ÚšåA7ûg;èmúŽZ¢UlúŽx³Er‡FuOÀHËN>s‡:&°Ø,<Ô¯æqwœºgŒ8é–'ÝŽª¼oÉSîXjŒ8íÝêHcĭޤ,çÝÊÁd/ñý×þåVÇ~Ý]'‹ ‰ÐÔÄÒ—`ɉ€D<}éæ}Ô/™5í:˜Ã{~˜`Ö=%ðs3SÃÏþGtü|öœqØ#OPÍњ&ºò¤çH*ן‚ëOi»£¼V§¼VU^«*¯Õ#¿â({å:/õvÈw‘.A¾{û"æ=¬ó2dÅP^ ~‘îµ î•#m Á t)4Ùšì•Sm ! ÔZldšîO @­òò!Ü÷¢CÏ Æâƒóq?\=]«¼­âKàgä«~>£¯¡Ÿ–±–~>´Ìu^¹ÆË½ é80€Sˆ±:?ŸXëcZçíZë–ØÿÀæ×:Ëýý­g£W~(ÜO9Þœ¿à#ዞönòÊMÞ˜åU]~†ÜìUu>je`|+ïv—¼˜Ùäu‡//}ÁTåX·®4WÑQò6¯åæÙþv¯…ÐHr‡·Џ„³àwp{¸˜ œlæÒq3ÕgÏ¡ÂÓù5`¿Z<²z0…œêÑÿè[ªµgðÊ^§µo²û^­Oò†>xÌò½ðÁcÔÔ{U e›PVFåùîº<â…MvÛƒ“áŸ{9HÔFï¯åeOºM÷Úä)¯=£JÝðKÑåÞ›¸ÿþ{ý¤“ï¢W~ámç‚Ý//y-¿Š—ì­^x°ƒv‰'£Ï²€¼L"óóÚöŠ×2M¥Ø¤ad%÷Hƒ2œ5ÂÒÞ®AT‘ý$ð³ÙÒeÈ!W½³H¸¨w¥ËÃ2Am!%ÏP‚2äˆ ÊP‚aÏnhÊ„nLF"O…„Q¾¬åFÁs…x¢b†Çè%ë36æLË p1@L3ÅàÎÔQ].6 ·³Ñ˜çÍÔ‚>²Dc†òT®±oÝupŸÓ˜!—dÀûE2l ^’ ¹4ÞÐK_¾"—1¬ÝÙ¿®Ëå` ~0kk;4.Á}õëš\—¡\TÄS>ßåû1ðþ¾1#4CÐ_øËfDå&â^äfÆô aôÿ6TŒè‰uå¾üF—¦¹–?éÒ…ëKØcý[x%Ñ”dy«%šË qÏ#Ÿq5ÑD’K¯™!VRM*_: ƒIŸ!¬j4«‡™è`š¾zERuJ¬Öžõ£—V#–Ÿ3[á‹~°”?–Š;­RÎûYÞYJÞxç©fY..ŽGí$‘?ð1 G œ;j'ÂîÒç¼_^ÌÀE—ö2¾Ä¡Ûöv°ø—ª¢¨ÏE¿¼âÔKœ·D_ Фßìá¿pÝ"9϶ ¿Â íþP‡ Û2œ%÷ôm²¯Ï¶ß GêO/_ÐÇÉ>Ü<ü2 sßtÌyS¸r¶p …|1ÎG3T_4ÆW7ÖVÞ¥uèh_΋81ΗŒcÂëŽñ>9ÞGHs:a^;AåJP—UÙ¿PЧ-z"Þñ$Mù'úrrQÀdŸ²µMñå¼OOC4°P“3|9çPTCZú JŸíˉ!}žJ¯¬£âßöå|ÀG( ]G®  ' wfP éS=ŽeØáÞ„ïŸ åd'ŠœØô}*F“¨åüD|*˜“¨ç”c…èS$ìDk 9×§BFÙ‰f2ž“›»·×(µµ¹—ÝkÛ~¯-£­í‘¶¶ïp0'J•>D1*vç˜î[nTä{>žæ·$W|p÷Æ‘gÃC§ÝØ£ßqÉHÿ³1¼v Vö7®÷|­âcK¬õɵ¾{òñ ]ݯr–Ç[4ªìm–ö!Abé›||Yy3ý,{ÉœLõvË=Å/?ô)·.[||CùFwXž­>M?¦ŸVÆ6Ö‰¾ý>¹Õ—)4¶©ò³_Êb‡zæ1w¯z¦?ÓõÆúZßkNøøöùˆC¹Ÿ™Ì*>äKX~*7|»‡•QÀˆÕ#ð~òÕ?Ï<æ“G°;=°î9ê‹Ùî ù؉ÇÂõ’‰.Û¨Qm˜=-¯ú¬Œà´ïY¾àÖ¿±¼¿¿Ôy™yÍç8¿¹ç³ ÙFÂ÷zô³ðÔùQGýúÙ¾¾úú™Èzz ïýüدœU ñs%>! ó'TE á~¦€Ý<ôGé…ÄŒ?qjÆ:‹c¬?Î)Lö?Êg9 ÜÏd.Á«üìüa—•5Õ/§");ç)àœFe`:“°²UUr(Ò~Ëm§ÜéaûwS¾-ÙVvÂqÂ8ÅxCr½Î¢<àhŽßv­õ 4âS+ûm¿œïo7ùè ø­ª…bòñ½Å1ãXHŒvPv~ÜݾÊö¯{Ó²­?ó3ߟ5¿Ïx¼—œF 2í„™”0³CîòæfVL‡c‹a…ÃØ|ÙŸQb P,µQ,ë b×v½›BH™¤2}ˆL›íL[T¦Í4°Ö‘÷Õ¦W§ÒÐ,«ƒ3âª_ÚÛu¡ƒüÂ.ò}L£¼n:l_v`?¦ìjU'y•æ*W:ÀûfûŠ»Ñ!Ôü&EácE/4?"tTÙ­˜…PÏßÀw:@tÔì]~ÔXB¤TÃB¶Ù°K{‰ž¯Ö²Qb U±æD³ªèÁ<”Æß¼‡¿C–˜—s?óräüÅß‚œ‡ðטӞ¿Ï“ü-Éy¿å9áoeN«s’ü½—ó ksÚó7¤üaü NãïH’¿Ã–8òGrä1›¿ÏÆß©ûø;žäïÌCø»ð0þ¾Hç¯5ÅŸ|_þ?ñ7¤D§yû|æ¯.W…O¨B ÖåÂä*úåÊþ¹Ü®pøa`®­Þo4ç¼DïƒsÑó° :47©ù8DÄ;¶ÃsåpJYëÝKŽÈeë]‹™Kì%˜196ûå˜RÔç‚…7šåäÜ4ñ!ve'MNÉ¥Nth ¶m3½ëù¨ÝÀW][råŠDŒžævë%·(ºTèÅÍwêùDÃo4Érc6¡p|ãã\ôMr[n´3—W+;s£é$…úin4ïft8p5, ËA7såEº‚n*Ù×#Ï¡@×xPu+7Ö¥­ÝÉ¥ˆRî¦Ô7ïáõÏS È:4œ5v>Ï ÆæAc›ˆ¨£–klk¬PÖX9žs¼åô¤ ¨'…¹ubV:ªÂŽY²>Ï1·NʃBÂÜÊ•6…ᨲHW§æEËšéySK<ÑgX!‡†Ÿ–‡¯Ž ±Â™‘%IƒØ™y6g¯ ªI;ÎÚ©ðü<µÒ‹¥Â Êwò’ƒ\˜G9kTF´*Þd_”‡V£#^ê’¼vÍM×m»ø»yh1½Ä±EìàLZÛö°rض‡—Ãä:¢Äp»ýWyis„eYkàÀ¥¥Éc1ºS~·'¯ëlÞ>’×*î½"ð3øUíHž<–gw yÉÂ}N$%r’$¢x:•÷¼<›”­!Ïåq®ëŠ yöºt7"Š8g>^€Sà­œÑV/‚YK•3ëñü)ÐÆ‡ex¦®ë¥µ[&|¼Ý´+IÞNÓˆ!¯Ê;¶F¸å][#ÜJ#êòUmYFÚ.‰ì—ÿ;Q“ÌÜ?ßÉ< ?=36S†ä+?ݨ—3,߉î:<eÂîÚÈ|[t9<•oÎgéOXàéJNÌ¿Ÿ]^‰“Ž©ø®õùè: TÂd~4™é)ùÏ‹]bžÖ¨}ðØ¨§Ü#ÊaŽYÎQ[G¡çÔõÑåX )ÇJ˜ÔÅ-\#¹/àã³ó±‡Õ$çæGÃ# óìþÐõv¾|;ßæˆWå|%&¹âˆ)A.ÌG\Fê˜Ýþ5l$nÌwžã–hÌ·‡šª6æçüN£…ñ²|ž÷­)„ÖdÁ̶"?ŠgNfûP8\•Ÿs ðkÒá3á$}Ýýð³!Àÿ /Òa þ±ªòÓšv&&“›ó¿¶ ”/íǶóÓ'’lãøÔ©O¹;ßÖ»h~ÎwAlB°V€u~S~Ô¦ Dþ¦Útö—xèa ÉÃêèCu á•PCAhúý{y >Ìà<·°Æ[òuŽFÇ•¸;èÆ9óò Kþ5Öµ#ó°öÿ‘Šôx­ÿñÚÌÇk³GøÓþßsýu«8i úÛP ÑßS–þ“VqÚ2z¶Š3–ù\«8k¹ ž¿åPpØ!Ìø™üI§–zâ½)Ÿ³×ÿ?‹…wyà–¡’ÃïŒàÍ¢Å=|¿h=üÿ³U,øfæ/eUèG1+£"ê? LþÂò†ÛÜoÖúåÿ¤§{ô”)_Ây¨LûF.Gsô†¯ºßÊû‰½wÍØî²7%ÜvË_ãù×ô|T3»üþéob†—°2çtùíÜ7+Æåiãó´7k³øŒÝo,oÅ@Qž%-`ñ?ˆ¥7ýÖ2-ø ‡Fæ½02ÏŲ”ÿˆ|}ÆæÉ=xÃwÜ}ÆåÉâçî>ãóäkôœ?á¿GbŸQyòu8”ä}VÞ¹ÚŸ›õ/ò_ˆŠ "[þ/Ê:ßdІxc7âoY^ùñheW¬ÿ®ÿ†Ç,ÒÕ$öq“3´ô“l!³9¦*ñ'fk¼–ÖBÞÖBgÐBÎP yGy&˜PbR ¹b …ìÐp~ÕÝ­Öóx­÷ñÚ ¢ÝÇ-&½•œ´\;4´ Ÿ –†Ÿ3–ŽÙÃHÐÏEËÜG?_Xî&¸ðcÃ5bªˆá0}9ö¤ç$ý\²¼­F4ãŠFéh1¤›ZW’ÎI’ë)-–€ZΆ«ŸÓ3[…[ÞÙo6Cså9Îæ•­Z<1^€®@侜ÿÅÍë¬å»F¦>å¿©Ék¨'Ÿ]~yS³üá±yVÆ´¥:Ýʤ÷qy™C¡nƒ‹3û鲟ÎIPÿþôH:zA“Cuƒ*ß\F\Qy}&–Ëa:+Ï#ô=ûÍ9J‡ŽuÀ¦Ò~7| w‚'åóÎ&NäD]q1I'áËÉ:¯äÀýìTEÖø¼l&ëäßdM×Ih3@V6ÈšõP²ÒÈš“FÖ<Ð’ÍdÍçÇ$Y‹ˆ¬l›¬F›¬%LÖ»:vÖøËJ ÍÚU:i5Z¾›$¿Å‡¸uP;Y«[žúÜlzZ¯“®vqѪ¶Ë=*‹^†´ob‰‘¥óXûvë¼7a>޽ ¡sö=Žc¡Ô-#\(uËøÙ—¯§ŸVK?¡ó&àIݧyJ‡NºOÓ´Ç6çW]\e•ï~G“¯&b]\•K¿£ñ¡&™Þ‡žâH—µÖ^½ßSt…¦—§5ªz²æ¬ïÉšsüÿåáš×hb!`Áó‚’,jA?åÍU®oUŸ+ N-Þ°‚7­à-+xÛ Þ±‚w­à=+Øfëjƒ}kƒ³Šéîs®´U´T‰§á­DÅšêW+{RøiÍyÄ”ZX‚Ї!õ[^OßøÐó?TŸ/õ9_*†ˆo%pEþí Ðë®Þòáxr¡ü~§Ê_Câ¯Dkš»Vœx™](_±C°êÇ­<Ù;<£¼3ŸýM4- }¨…Ì¢2§PZðT¢û s®„ÿ}²[­Ùy ÏÀ“‘œ©èúÏV1 V ãU¦6œ×œú!ÿ»fhQ¬bm™Ø$ÿw¬âpw×@ÄD‰E©_×^´Ò¯þÜ~ˆ@…1"$O% B¸¡dB7„;‰Ïö©£âÒê_ÝQÁ!!r~ËSê¹ß0FkÍÑð[ëƒ@!µž™ô3¤Ö; qtF9wŽ˜9Â8ZËîí\Xa§”.fÅÄîPñ}˜óÍg«€É€2¨™"J£Î´BÈy–àXÌoÐ0Õ °6 ŒÄk£:§o'Dà …y#0%V¯¯T`Ž"Ï.I"]ûÌ(—o‹®ìœ2£‹V ¤±ˆŠ­œYŽxmöâÀ[1ÝŽ`LkÞd\áz­YŸŠ4 ËÓ0¬ ¸_וþº.íëzà!ÔÕë‰4oþ@ÕÜ(àvq‰ži˜«XYà2˜T%5Ánƒ‡× *FÔj0MŒ¬Õ÷ÑϨZ£‰•Æ„•áÚÝ-¬;ž0T¨“¿ŸPfÑSMoÔž @ãN'iòù›]ô8¦–—â z·ÀíBÌgb"ö+ÑKîcõ þ•´—ºUuÈ-[”éÃ#¾gõϬ>³K½‡„<$b$HöݘKÅÐ"+£b}™pKy”ƒv3rTäÓ¨/ɇQç²'œÇ45‹ë•Á²‰2Ï8öxRSþ A%\öjA/6Å‚ÁãûX/©„;Op_4¾ .‚šWÒl……g¬—ÒˆüRÃUø¥%†i˜3™ákšò<À÷ ‰ékÜ.Ä MÞ ¤;à¢9§Ÿj¬¯Õnkèàô»š¼­ÅâèHPr‹¼æâ6sw‰g—êû yZDÅìržÛ´õýŠœ†‚¬ÓSHäMDØ L„-@Ëx¦Ò dª¸Dß`]ÖkŽuÏ)ïâê¢Û‡ê5çJc3žlÜƯTõ5bp/9Fçy¸<¹B¡";‡æÚ+”´BQÒÀ$mEIûðšJkî}£ÏY\Y¢ÂkN©uÂk^(}áB2¼æªÇGüEh^y2¼æHì`Í-D:P¬æ3Ê)×{%pz— ¯¹e˜DbèmΞO³çLüy;R›WH@kK\B×1»\+ ” ‹eièíov~y´Ù(M¼äëâD$ Yã¼iþæåÍÅòßjæ—×,(¯y§¼b룮> Ëå¿#n_‰Çk¸·@¼ÆÇ=¯Ñß]¿Ñéï”ÇŒ×pÜ|MþñwBþKM^Ç!„ÎvìqwÅÌo™ŒN¾¡"©w£J~ówâlj`yÿˆˆ^ùñ£Bþ'ž~Ûù'¢Tþ7>ôryçóa¯å.M¸•»tÍÕXî24×âr—©û|KÊ]núy§Üåi®wË]^Ÿ«‰&Նљ¥´Š…ðž-u„ô÷KË©ø5¨…æÇpoeE‚å&Aͨ5 [Rn%)ÏÿARTKµ.Ĥ›ø<‡¦Ûõ ?SÓñóÙsÆ"„¢#-JH8:§wv½;BrÓ, Bëœ8t«èùÇM“Ô­vÜvËi^=JPïó§^.ÏR’”2ÒXF:ËÈP22•ŒÜ$£e$*Ÿ«%ÝA6Cû“íŒRŠCËív6†ÚÙÊB¤A;¤5‚ƒíÁ¡d#Xq_#Ë`Ág¬Ý/?)ö`•x¶úRé_m‘K´n:T¥UT·–vùm¤•Þ>«Ò«ªeiWDÒÛá*£¦úri—=‘Ëôv¤ÊüCõ—¥]¦G¾Dk?\’æsoV­ü#¥IrF ]C+mÎÆg« ‘ÎŽ2eCŃ>wþL|»z\·à;?ŒëF¯?מ©>úxpÚ÷"G§~>¿* ~öýÈWDÎJãgÕ«»량¬&à;•fïê†Çƒw+# |¬Êý»ê+¥ÁÏ«"Wøx•çÕWKƒ7þ&r•^OTyÿT}­4¸[‹\/ÇÒ«©¡VÖ¡š>O2C)Å¡U63㉙÷ ‘fŽswØùþN¤U\-•Õ×Kƒ“¾¹'JpïåÍ˳kúŠý$ü™3þ™}3Òß©ß×ÿŒs÷ý]öœùgÅwÿú;^ig‘X¸YfdM!bYZîÈÚB¸¤9‚×å²\ö\°®$¸æ¥àÚ—‚‡C4[­X]î¥áT‰WÀ§$eCP)9X õN:†Œ†wfDù` Ò, ¼Ðq¨Ns/ÿM’e* ½Wžô9½|o$Cpg’ô€GN:ZLJ/ìüòD-²®P…ÕyÔ% `ã,ŸÀ®Ë¿ M*éür½y–¡&<ŠZ¸¨ÙÕŸª†“Ðö¥ÁSU‘Tñ§«´¿¯¾YÕ}˂׫"}éýF•»¨îW¼YéGï·ª2ˆêþeÁÛU‘þô~»8ë Q= ,x§*2€ÞïVe×iÕË‚~Hï÷ª:ŒÖª•'þ02ˆÞÛªr¦kՃ˂u/FÓ{ßsçkÕCÊ‚ý^Œ ¡÷þ/æ­Òª‡–¼Jï_ÌÿP«Vôbd½~±`·V=¼,8äÅÈpzúbǃZõˆ²à°##è}ø‹ÎiÕ#Ë‚#^ŒŒ,Cd’Gݺa>yn-Íb/"4šW+êtÌ]Ѹ¯¥ÿñðšrš¶ÄÃkËeúYW.ÐÏúršºÄÃÊ{«Cý£ð‚÷(¯A·ÛHƒÎ?ÔJðÓôœŽŸE oëvãX £q.”ïèhýu¹'=êf&ÐýðxPÍô7©Çp>L*Ü_a¶!“uf*”é/Cï§txtx¶@:ۉŌ§ûƒ­Ô‹âûգ˂£_ŒŒ&ÑyQûIõ˜²àØ#c ¹©fè¦û•Ë jåK¶à^b¹õ–½Yj¯Då+ñðåñðÆrùj<ü!=m*®{J†â«`q‡7—×ùTü5Ÿ¬Ž‡·ÄGåò7ñðÖòžh»Ó52Üžÿ޾Ž?ؾÊl_å?ŸÓñ³î)?73MüìÄÝ—ÇTO_üèÿéÖD<‚ûŸã…E">Y(Gqÿs¬Q ,OäH¡IäT¡‹V;ýQå´˜JY‚ŽÁbàÞÆŒÔ‡mø°>Ç™©GðaQÿÿŒ}xTǵÿÎ-»+‰²H`³²U+¶³ÞظI±§8ŽBœ—Ç 6vXeµ+íS“8·8//Ó{ïEô"z7ÅôÞ¶€Ø`ª ¸h0Mÿó;sï®Àæýß÷I{çž;3çL?3s >LJ}¨Ç‡ ôá>T¥>ôÅ,E{ÛÈi|˜œ“FžÆ‡Ñø0V Lô›júqõ$5=ü³o —x‘éõ“Ö/L¨Ä)9¶õ^Êã»-vO˜,ðßq4¯·S¸’øÔ–ûÿ¹² m/~V2ÄW *†Pwè{/­¹C}ZÅPzÖ^ÿuÉ0_^1 }cZŽ3ËtH«Ÿ–æ+.Öå§-HSúoþ`Ø“_™nÁnzþÌæ¥þÌnzþÌnzþJäqã¿à ÇìR'=æ|“ÆJØõ6·ÜïÔ‰êpÚ»Øâ§áƒ  Øžü½&ãè17Üt›µ|ðüW,²‚-DuQ®wœòMK˨²m¬ß¶ê¸å;És¸wƒC|o„Ó=¯à:é_Á¡x¡ÅÔ3ï=„úJ‹—g¼rlÆ€þÂÓ€!Ê?ÈPø™–Ãh»VßÚv§0=ž0 59ÙòŸÁÝù‘¯eZb……,×à%(ØC^¶ZR8Pgá@ÝyOφý÷ e o64Ð $L.S†œ„ë&žÿ“YÊEmÝšÊ)ìü¤iÊ';‘š*‚;AmaÞfÓd’\ìÅ ,gel¦¹œ)`€«¹2À5Ill‚ûþVC`îOaîÌïCR%‰yõ-8,‡+kn!GfÁÛ™„ñõ:UÉë-',nq²‘°¬PT¤µêATlð”´]ÑoÀr'c·ÈQYó~7»åÙ#X´f»kã8U5-SL_ º«}-r@iB„šTޏì¬NÆp)ºûÉé¯üä¼ÕOŽçY¼ÇÉb¨Yñ§­µÙ‘ÊI•ð.ËÓ”ðëd¯ú„ |FxHû…•öŒ¶N¥•H»óN,r1™ö<§½(,RUíš_…aå°ç¤{ä .wª(i©`zu&zlCcjïã£>Â×MS´¾§Y´bÄ FƒÖhškDç}ìç†R Е8²»˜L5©äp-äAÿ„Ô‘jÁôb%c4>¾`Ü#"”NCëcŒÔäÀjÖži¨&GU.A. ÞÿËZHCê› Ko6È› ð;5A‰MÏ¡•ÏuQ`z›ÊÇIo°}×°c*ü΄£ѦóI‹>O“ÓÕ $Ûff ™Ù8§š¯qJ¥ê½Þs`Å4åZ «ˆ!cÅ f«8²\KpCÀt{íPʇrlùŸµS«Ç ÌÛ2û™­·2Sh·~;Ú툹9‰6Ñ*—|˜6#Ç Ò ¡ô 晨à Uð„*øUð#š<`ü çsÄÃÈøˆ*¸<¡Ñ($äoú€æ§D÷`<´ˆ»Ó÷SwJÏuü P¥JqÑLr/»‰Rõr§Ÿ#AÝÿ§üÿÐ\§ôŒâP\âzœ™£ÜéP5öÒq¼–}t\ÊõË7Ëb:,ßZÝÏ‚!˜ÍÕÿw¾eº­¿¦N÷ökŽeº¤ægu·,s¾¯Ë÷uh›½êP7Új]®Öcqž‡kåÈM¤æž†×êTÆ$0Óg›!Ö庤›°\¯ÛÆÆ6èÌK¾¯o„»ñÊ&­PŸÙ 8çZ³åÁa‡íg§×â°ÜmyÄ9ÛZîAñ礊_â_ â†âWç(GôákÛñÎ×: UÇ*>o #Õš›6šÍÚ Íg­eWãÌM¡™ç43Œhä  ™—B3×v…3×€ÙçXÅ—­Ùä³B³È°Ð,¶à, Ë%š/ZË¥@3?…&4 BS4 RhÙhòC ‘­å‘$š£6šm4ËÂò˜…¦®µ<4 ShnM¥œšE)4=m¯4=MÙ^i.´†µc M?Û+MÛ+Í©ŸË–WšóÄ*Cüdq MÒÇÎW@³$…æ>v.µþ_}ì,'}ì|ÕZùØYšBshšË@³,…æ˜æ˜)OÍ•ÖòTÍiÍ'6šO.?µÐ\n-ÏÍòˆ«”"· @ó•©\…\6£ÑȹÖ+t˜ÍF>o ÿ W”­+ê[Ëk~ÙÞ=®#x¡uÅEê€^j]qP—7¼ÒºâëÖ²˜Vä(?„©‘Óöã1ÂÉ~<Æ(>¶1Îoõã1Öùðã1Îo+'8-?Ã}ðã±2¹ žü†1¼˜Ê3 vïçà+ç›;Ãíñü£ÚkðQ±*G§XEýŠ0œ¯ËÂà_‹ÞDÁJFø:8JGøä3 .‘ËŸ‹Ìx¢tk¡ü‘ù°|–€Û ü±õ°ü Oµð§pôÃòg<ÁÀç,à˜‡åÏ x’Ï[À±Ë_°ÿc¶% œ˜4¢³ÑY¥è –Œ£|2D ¦O†¹H^¦€Û e¹"Àˆžj#ÿS‘ `…žh#ÿ¤ÈðU<ÙFþY‘ àk Øÿ1ÙY‘ àë$:×ä4:“$Zß„_”ûÞÀvëo¬–Sq½5`h®rî¤3³.·A¿­_–íqTS'V‡íëÄ—.ñ" ¿Ç²ób£6Öø‚,Z)hÉÏíQ#;Fã±xdGaÅŽBùâã†ÞâTCÞy~PrtÃ0×äg·°(¥LôÉ~ðOÑZðá`[â袑Jo~¤‘iQ¼D#ÃÜÅsž ­å0•¢–šµaÇMŽ`Hdg!ÌMÔb™?²ì÷V»c4Ú[»cøb·áÂåíŽBä]º«¾ð]àé†Ö·ž¬Aü…ðMSd9øÜ­% 1+Í(=𣱠mL}œAýëÂ8™‰œH«¢”›’­BŸØmµÊ8j•­C«lÎiì"¥q«lÉQ{ׇ%û’¡&ù ^Ú±4Üï(ÆVÞŠgI ÿ†°Ü,‚ ù6>ß¹Ó×§{ùÖøï8'<ÂP°û…(Æ´w´,ãË/ƒ]úŽÆ=m#u,‚íL–‰™½V™&P™zzCŽ»r’—SÉÍù÷ʼÀ¾Âü޵ŠÔÝÔ–ƶÏ—Œõùǵ¯KóÈøöÚ¯JÆùüÚWŒY‰ ¼àªßÆ•Ä. B”4ØvϾ„»¦ýîšÎ½„»¦%¿ÔÿR'6‡·êÄ–°ù6û÷}ÆõwVoy·Nl §ý³Nl §§MÎöpÆ,!ÿb¼eŸ˜~!ßîvÒã8ëýgÈôïPW½´Íÿ¸my»_Ü%÷²_ÜQÞ[ýâöœ–ÅB)ö˜HÙ[¥ìƒ”;q2‹T%Sö㔃_ù§+÷‘@ )1då>Ò…“§µ¹=Ó4Jå<9ï Ë1”ó„dÎc9ç Jq‡m|MÁ±>ès4ÚÿàNPê$­V7K°¬ ìV oð ú±N¶ƒWW¨É0ìTùS8S >Hºâ±x‚O°;Ý… ó"`Þ–‹ ód–ð9óY{ÂMÞ§&ÜnºŠûÂÍVã¦+äòwTµTS¹ mF­¸Zàˆb-\þª–k|z óéÁXï-§ž£¨žm*C8ææëÂg¡f”M.‚ÂO²MšÃ¡ns¬Å:µBJî¶ Z²Ç‚IÈ^ b;˜*êbÖRü–¤Wþáyž6«;®Ð#"¸d‡TÚÃH C@)2m‘9‡E¢…èù±BEn¤wÒ2û@JcÒØésTvxóŠ+±)]¥±q+v× YÊ–mE¯Óh¬Â®e´ô­Ü¨Ö?¦žâõiP˜ÛÌâB,‚³E寿®œp×íÁhÙ£q;!nEÈ^$6"$þm¸ö³7[²Þ–ž:p[4Bæ÷‡•Û•[Šyˆ6Þò#j5MP;Ähq3dh²™N¥šé“oi¦s·4Ógª™¾H6ÓqÕLR•Ùàj©5’ wQ•òyྤ¾cÕ0›òòÿ^Âï6X%¼‚'4#€æãšó6šó†¼4#½òRÍeÍMåóòk ͯ¼ 4ÇRhFaç 7C£æx Í${ƒ=É”“±Áã•S“ìiö{º½Á~ïy9ÃÚ`öÊ™ØöžH¡Ù 4ðã3hN¦Ðì¶Ñì6å^ ï…» MÌF·Ñô|^&,4ã¼r?МJ¡94 ÍD 9BsÕFsÕÄž=V1É‹]º…¦ÁFSi{—íó¼ìjy—è•Ýà°æ>.x ¹ €“™ANu\0ÄI[šþ^œ Ep gÃì­â•Ãæ­îÅ?é­å•#ã­ë…ÓÞhd¼·b‚WŽFp’·¢Ê+Çé§ÖÉ!gŸÌS' ÔÉÁ§\Ðèä`É·Ÿ,ý¿œ,ÃÉÁ ûä`<ŸœIž Eß89˜¤×¾‚õ?›”x8ŸŒØy¯Ì ,ñæw¬Ò*¶*éµ ¼Cø¶½ÑEÚ9]߯?t¯|ÝÒz/Ã,pÎõÊÿâMÒ%ŸÁ)ΊO Þ&euŠ8·«“D42]àRŽ®;]k¾L–o#ªÃÉ|(¦ 9ƒ£fþ ´Ç¥|K4›¡ñH¼0¢µsD`uR¼ZˆüÒCÅߨÅÅ‘ç˜<‡ïJ¢qn*Ïy©<çßšç‚ÛóŒ"Ïy·ç¹•y™Ë×¥X‹ò­ÁÁ4]¡¸Óõo—¸e#¾‡ò®ö¶(ÁÖyòûXŽ^ĸÜZ~R_dJ1Š7Ï«6ÓÐí¯õ䀨ýp’:Ï›m‰B‡²^}ÊäØT!ÂjQØj/ñœ@DÄ|£Q]?ZŽ «í޾ Eâ´ F1™ã…×øçŒ½(*æx¡§ûÅ5CT>X/ù€÷¾Ê™½ŒÌê8³ OPA8³KWYœÓyX*6@ØEPC©/‰hñ5à ¯X^l :þ¢HɆk9¦Óéªæº«T‡œÂE;:*‰)¬ýƒ¨Ôˆ î72ßEU~ÖŸ©`>Ó¨ÉÞZDÔÊ>šX,ì ï¡s¼`0˜‹+,ÞŒLcÁãÌ•S-oñê< ‡`!¨)ƒ×­PMÇb?Н®çè.§ë Æ=]K ί\-à>mH®cÑu$,&k¨3mªg¢±ß^7„œ¬¦8cÅSœ¢rг†]‰Z­œ¦%‚KXhº– zÒp_…öÏ<£Ž^ôÙª´s4øµ: hŽ*Ð*¾bèý²9W#žß¹LLñ¬Á#? š‹´“^Jk –(ì7ò«•iaâW©:Þb•…÷k¿Qºß4ª nð¸QzÜËé¤fWU iù­Z\nK¡Mï/íf;º²ÜEw§>rR;ÑoÕó©žÙ‘é žqûs·8À—\ÞwTŠGÔùÓQMԢŋ¼<€>ÔJj š›¨LGìS©£Zr Cé‰/ <Ã`zá Å9Õ’é42 f3J(îmjÈêŒVrÂx°â„!Ï‚ª›9&µû"¦êK½©›~ ]†Ž#µ/U缨šë+ VSÍõ•j.e@x—˼¬Çy[s]¡Ú…€x&PY–ZlªÎ AøUÙ-NTfÙ:*ã+»>'Àû"K¤7p—ÝǤwÓ-Ò•õ^¦¿›ŽŽ*º)íø¬¯÷Ô!n^+{ê¬Âõ?ÝFoÍböÕáäù&,˜)B!1ÞOAˆV¨÷×ãlfÙ Û¦Õy´»ß`‚[Ýoc!g»¾¦F4(å¦ÀçXÏÊÜTÁÆ~KÁƪ‚U›  6Q—lâm«R›¢CˆìÖ‚MùFÁ¦ÞR°iɂ͸CÁf¥ Vm¬lb£‚ÍCÁºæj¦Óõ7”k‰].uǸ„Ë"VpY´•:v1sŸÁ›{Y©£ó?`I_¥ËUº½–pVrµ2b¥”l¥Î£`?a^ ÌÝr±ús ï z¿ì¨Ñ!úFé•ñpJKËΖÏXrÝ<ŠäïåêiN×eéOé¶· ´´ÛλêÄѰÖˆ‘ú”ë\;ÃFô³\Dã3.¢ù9=Ö¿äüB‡«×—ºüDWËæ§zdÝd²àÔDõ:ÛçvCã‚j?g²Ð©ÐÁÙÞ%™…z•˜M[<Û+Ôƒu“×õ˜)•‘yÜnÚ@®£+:«O¹Z­¥=8Œ¸Áþõ”ü,(¤tW/²#û%õV_Rá!Hö1b)°*jý`Ä= ñ"jÑzÝò’)o6о,h¡4å0ƒ«‰žFεÄáúCŽ¢eÑÚè<ì×7 fdà +=Ñ.v‹sÁ­>HL'õ€?$5xWóÇÉÌ®Îöâ3 èæÞIc½g.T« ê?Ër‹—)ÇË2ûù'°Ÿãîûù*Eî•k˜.÷ï²_HkÈ ;þ›ÍÊÿ.p¼y@þÜ`/ÇÃÚ¿¸ÇU Y ^08XÁfUé*¬ƒƒ‡n"Ùc"ó½oÖ²Œî#ò±ñ&Í"AÁ:cŠì˜4ømØ”*>tŽÔU©¬Ål#‰h!N3È}·Õ_¨û Ô`ï\[ß›Êò»@í-58Û‹ÿŽS”¾÷b/â ûäÞÉ|ß\\uäÕŸ¹W>…ÏsóOá¥ÇO˶Ô+Ÿ¡xýr¡0Ð Ÿ:û×hd9XÊþœün€ßäÜìxS¾MÉ–{Y‰e@.Lú¾Žï½…¡7q‰_Þ+z³ÙHm€hd™—}ôÑ€ù‚é¨Xæ…(cñÒƒ…rtþþÏ¿Ðê¾›¨•ƒE"Vz¨P‰xéáB9Tú4I°¼a`ÈæjNvðzFí8òi.ÈGJ&aìp…ÅEÂ,Áû‘eÞ‘Ê7{l$ÎÁd•ø¥œÂº§øÖ–å\\¿Ñ♋‰ešˆÇXm:§¿z°ð{ÿqÓhq°¡Ámº±ÿÕRT϶¨ž“¢¶ÔÊ…±ÎÇAì2»š– ¹BU Šü¶r•(d±ÈÁÂâéæÃÓZ`:_BÒ-V9ëÄé°c›*â!·Y‰Ø<¨¢8ã›D”d¬cÀî¸Hfa>ÅêÈCÑÓïPO'Üù›+œŠ{´X¾ Ëm¬'ÑH¥ª½ø’‰>ÿäöqƒ5<×ÕÊ0O4©ÿ$,ÿÆ:ªÍ¨›Ó¿‡Â-è?“ÂYÄ©½äø[¸|¯x«N|Öpgõ’þN86þÎ:©ïÖ‰ú{ÿ ‰çE×?ëÄÙ°Š/¤U ÈY¥CÂù\8£;=> 7Y§É.±‘J(,æÕܿޠ} ^L߆ƒÖwØÃÈßÙÅá»ôë”ÿ _—_ÈB ö 쟪2fž˜uÇÔ]à€ûó°ÿ‹ðsZ劬pšjb¡&ö¸g™ŸKJWòndÓqåöøé|ëäÒíïñh5»Y,<Ý ®±Ü¬ mŸß±Zùĵ–Ûÿe8õi_»j^`‰©-#Þ!!TïôüJsøg¼ÄæSÕ~žZ¶ |¾]·À¬q1˜yœej©I3y"ÂÕW&7¤C7¦#Ãv+ûÂ-©¡C-Ý-ç[Ö€>*W¥ÌÛ3j·y-–SÃV¡Lxú gA?« ¸ù[|Q/hàîá™/ž€Ò×ÿÆH†»?jw÷Ïn ÔÝ­Ú%¼ ¹v¿ T]j¸žê…ç7„à)á`‚ßL™BùVÞGec!¹J™ÀS:`¯±?ƒ¯#oš=]lRÐ#©B]ãAÙòiXÂç;ŽÝSCl^«d/ÚZàÞ vr&}5Ñõ cq$\˜tDœ\>âP±_W"½ÎT—e4Gqy~£LÚÄNÔ±…¬#ÇÕH¦…MfAQ²“ªéÚw£ÍCYUVÅU+ã/½åI¤·?½Ö «œ,¡ÚT(Ãîæuód0O]Á,ÑòY/žHnââ 7l.äJU).>ÇŸ+W©Úd5ï¿q³6CÄÊîbÈõ ᬜ!ÂMYB7Ô´xÄSHd¢{$èu8^çàܤ…šÂø³L­°Ôì×h£g¶ª#ù«О¸IèM\Æ`©FåÄ üÚ7  \žÄ*Öyqbгo†ÁišÂKþñåë&á/qî0H•‹ƒÜ<ä6h¦ÑßNרîh4²Î[q#KÎ@¼1¹¦ÛtÐq•a‰"æUV8ñl—…µ# èGÙô™qŒmž™ÇéQõ’óº!×Á)ûúÀ(™¢åWLÑä& Û¾Š%ª3ðˆ™h ¢>Hi¡Ûj´•» DËÄú£ì5ayõžä•ڹ׈áx\FoI3ÚrwÇiÝ ±„cÔÜ£–r†!µZ 5 {ŒªûF–µß9®ö;=ø¶‘?„œ¼ÀÔÈSFp¢/žÂUÁ1QŒÌüwÌ+ÆF¦Õ + Ÿ9‹wšÌ œæ~aÄ‘#›(Vào¼³@eSÙÏ¢R•Çí=SšÍ.A]¿I&_5Žø5E¼n–åÈL-‘(oXŽÆú_X–£W.Ë¡Ž^i†\±âãÌ%ŽÍµe’¨}‹Õ-AÿwœVj­ÀJ˽“q²ñ¹0sôXýÕ{å3Ü/½ŽgäbùÌÅ=û¢£­üI,˜±„™ˆŸR¨W[ùspq8&©¿GÊß³Tú¿'îÑ+~Ï'//òÁËKòEËÐK|är7Zãe˜ú9RËŽW ð’: 9AÕ(h€FWn#Y)³G“rmY)Ü8jÉJM×r*6xCI«r嵐?™ÙÉGê/…åaX+,»ÐhÙê­è æ ÷½r 6yå³Ó?¦dSraËâyÄ?Ç\|´£ã-x—Ã=wkç­ðø§¬y(ó/QÚðum¢µ•’q)Œ{©¹ºË0G ävIØN¨)ÇK*ÇK*ÇKÔ(ÇÍÞÌ?â x…®_´x`´uë'ÀuS—Êe#B ûWâȺ«†9®¸¯WC\ìT ùB¼>^;Í›ˆ%wÂ!½ûi u›¦5§åi†9T}³ùÀó‰F.¿ÔQ‹cé¯Ãb6Ÿzjs“jsmíƒy,õáY£¹`Ä[Ž@ù®†ÍÅŸø,ÑøÄg©F‹C4²Ñlò&]x.±MäºäROÚ¡7-G^Ëïfç_Ò›œóËÏçÛôñ=3õñ¶¸Ö ÿ>*b©f£ÌÆ‘œ¦ºä³^Ç÷ûÓ¹ûÝ£ºÎ÷Ǭî7ƒºßwBï›qË–¼qï›iMÙ×ÂòQÊ‚¡‡=Q²ÑëïÉ:ß“ÐCà-î*¬à:ïÀUÞküe®ðWäËVu¿Âµýw»¶;ÉN¨ë㪮VU¿È–Å";¼ì°”+‚PS4Y²Zˆ+ËŽl+#·Äiiýç-ÑÚÊWTUURU½†šškëÂR!r'¸¦¾KgbZÚîÕ5çŽ'Õ¼AýYý°lƒÏ#ŸqÀç÷³‚~—=¢Ñoõóz|~*šø•E´ŽîóÊDã{¼òi¨œîUgs­3Šúß´TþO4² ò¼\'Õóø ‰5ù•÷Ö²-ÐAÐŒšÇŠ›‹ŠÝ´æÒXÜíõß GNæg½†.{øçb´ ‘:HØÃ ¿°h…+âþe=ޏgžÓÆ 9¾Q&„ˆ6J ú§UäB‹!¸¬u¤î{´ëû¨IÙâ¼a‘uÞ0]º7FÞvÝ›ââú ¹&qÏ‚öjž“®?æ˜'ä<Øå…Î,‘ï=©*ˆà&´õ‰Föz_Øå5*wy@ÎÊÜ%A.@ܵ²L®g"«ˆ­B&Uþ®erƒ¨ŠǽŽ*ÿÉN„]˜ /á‘l›°xŠ9X3ïV&vÁ”ÜÓ8»Ô)ÁïmBÎ{D,N‘ØZÍ.>"8iD™®E¹Ñõ ø×®G™(¶ÁuŒË‘Ÿ•ÇvÆKÖºðŠ¯ öEQ\õ˜V±Ö¥tÔgõ‰êðtVK#x>½Ñ$èÖ´]·¦PÙƒšE.\5ühÕÅ$ÎD¶ÝEl+M±`§%7uâxGÑ]“ݵ@§Xq'¥ãÜ£'n÷y³ æÏIÌxã6ë¯z5EEÄ"U­‰”v½8üâ’äH¹AóS¥8"`lMà±øÚÇBñ¤lc-`ç'‰âƒ^xšüˆ<%â/BÛ\ïQ ‹O¼°èq¡C9X#–#Њ÷~=±ùÃyM UX ˆúŸÁØyõ)£ ×òÈ÷9´ÖJi‘XšvG½0~HÄ´ü>›>DW+pD­«Vâ4b BmPe›å=Wˆ-„LèS|˜ú¥±*ú$¯rÕÜÞ\×îÐ\7ì6jkµQƒ ™ÿ¶6ꪩ6R‘»iì =fN4Ø',-É–ë¥EÛñâh %´w0h—±Ê*ÚÂ1;‰±¤›“mÁºBÏÜR59QkÔ$“´X²Iª´T“@žd¼£:€– ¯Í#0.ÕR#Q³:1ÖË5nBu­‰¤Ú×Ðvü³BñVf{å¯W¬TBïk°=¨n˜ßgñЇ™ËÜ]ª¯ÖäjÆ ÜÀ1fCmê>Ðm)>_3ï£á°Qã]Ývfnÿ êŽkV>NˆV?.ð8ô´†ÇÞŸèxl»Ë8­ÉOh¡ vŠÔ?ôB'QÙ‰ØÙ3ÄÑ÷޹ăæ,½ÅJi ;Gxé(]~FDéè–òs ÌX騖Ý™í>¦Y£­²ƒúq\I_s% áR#¯iªï5û‡ÒåuÜÐä † ër@I5@‘JÕ6ÏB•:¿¾z®ð{5¶á5gë*ð{ºÕ·U}KôÐeO½qߪ‘½ôxjô÷Ö©Ź õÃ¥úN^§¿d"YÌ!9¦Ñô:1õ§b:¼:ܹér¢Þ¸é:Þ¨éj(N×í¢£™Ñ¨d3õhœ‹;K¿mÄÌÑeµ~Ûˆ™««£üQÏc¡$óu:êNjž1‹u5b–ê@ÛE;PÓ¹Ÿ×’mºmpôeìB;AƒzÌ6g4<ºvÒ¢ºÜ¡ß6£-Ì|ÄR¡Þ¥Ë]+a·nOlDéÔBÈPÕåǹøµ2¦Þb˜Uâz4ÁÅOèß6½ì×izqñôâfG44½¸Ý.ˆR¨Êêª*Ë8Hï™êòЭufÊÃI:›þH¿¥Ï;å=äLõù£ôÆ=üc ÄÐÁéèüTÉÇ!ƒ²ö·\Ë'¸–M®åSz‚jw7÷ªÎ¨Ü ¶ýǯtð—è±:¤]V3WtùW-Ÿä%çwš.³ F­–P,ž¼ª'B,“p®Õu…[â¼4_g¬{x£ñ0°öÂqe9ós_N †ìo»³Iiörš–H3 iÆPÄ“T›Õð@ºyÞB|œƒs¨ïUöúšX¼ô„×­¹i3d¨êo†SÕùÖû´±h”“óºÉ×ZÉ74Jþ"ÆRx¶#âNŽxRá9©"î²c<»ÏIK®<žÂsÉ[É74Jþ!"&8âñSƒ‡«­Ç§†6‘ÏÙ Í5•ϦÐVVÛM÷iò—ŠNÏw1Z~eRmS³T x”ž/D¤×ÜëËÅÃ(ÐkøÇI{«Ý´¾t°K‹\Á¥vN÷¼„aüR¹Î.eV<Ÿh@Éå+iVÖèLµv²Í‹·›‚ð•,½,ÿÈ/W½Žþò;£©°ŠVŒ|^-·#¡`ÔòÏÈG¥Í@¢â¯½ÊÒòk6Ê  «øFÙÓ[Í'Ä]ì¶j£Kç4…éMj„é­;azûL]¾)1u@Éî² §·šp³AþVrÙ÷Ë¿¾…æ–» ƒMýë[ÅQÄ6Û:š_,tˆ ÇW…-Ãq ^²›4¹¬Ìå^(t˜ŽúB‡Ss\)t¸Z9¾.t¸[9®:ÒZ9®:Ò[9®:2„ãF!Dn:šf8 ÍÒ•EŽæ³„ãÚ’éÆKèÇýxS=ýi|cŒ)”–Æ !Xn±fF¶²3LóÅhãi>%M>jlyåÃYƒâSìºáCþc9ôcqú˳!Õ³¯R[[Y(ûäjDÒ‘dаv‰#ËcQ&¦àÌ7·ïN¾¦Ä&›yü-?Û,AtÅAñõsDÌ2#Ä>æÑ+SÊê,gsY¬%dCÜ<ÇÓÖk tf{Ç>Q2ÃGÌ _˜Õ^ì%3a€p&½În¯%³`p½Îi¯%³a‚p6½V·7NŠ’9¾£b½Îmož%Õ¾³¢š^çµw~!Jæú œs!°õmSuãEq…+i\™ã \ÅÕ°Š6¾L¿ «hŽ7jq‰ø†Íp^±x"Òµˆ‹vU$†¼QK(3œ7QÐÏs ÝèíDþï)v‘Âv è™Î’`PjžPÆJÍ+Ó Í<±L‡–ɤ2£/ï~Mölpö‡Rsô9 lÚµiÁ¾.µ´Á}³5ñP~ ÙŸå,?†.OXcƒoe®p‚Dm×¢ânEo Ö”kK\>…HÏ'Yq¸ ô’×ó”Ípû?Ö[žÇX-Ôyý“˪Jë¼,ET¥@!7 r²œIDzÎBöjJ™{>djYÚb ¦ÍlË‹ ´P1–¸Ù]¨y>0~(¬Ž·0´Ž/%Âfúl¡œeH¡WÃ>!k:Ÿ'|Ü+ù…•ñ[ºYâ"8 øÿ$ø,€^ì,Ö! £š…k7À'c©ôÊZp6¢?#àQ A/ó-¡ä-ˆ®¥Làé*å6NYï•Ûµà¤tPÊ”rRþ)wi¡tÿ¬—ZKé,C¦hØLÍ…¾|E¸g¼”Š˜BÚËÄ.Ì„?ñ‚]Þ¸…¶»,HçúæYIhì2†=þ´šòn¶ÃF‘¨Û|HÙ|åE‡d«|kÁj€ø"åN}¢2C Â` b‡Ç­o!³´k7ö)BYíkžÁÚÒ!Ó"ª¿ÆR®V#n4ÈÏ´x»Ë^(IcVú‚ 1 `vWŽÓqÍ}Þ } \ðb÷ßÁQqÑ+ç0ä+/Î6~å]qñ%߯Ô~oÊðÉ]®±³(Ñ×­ÖCÝ7-Ïíq@~ ¤Üü-­Þ©t‘÷ЍÏyXŸ™a¯v-úŸémVïvÄâîE*/!x\×ZLohpën fÍ¢ÔÓŠ7¶aòwàõ‚z¥BìÄëWê•J°›r”^¿`—î{ôhðmÝë¼ÅË|¢‚z]ÔúlùOFê½<¹¢†cÉØ/õiH‘ЭHv ©R à¼ëG"é-^N‰¨‹D ÖåÂ$Ð <¢[÷.Žy»->Ói3„/²¾ßq=0ÏCAÛÍ#.é¤E(û>;¥Çð¦,QZôð‡Oñ¡^}8kepAeð™Î7qù&î‰ÔµÌ\åqn&ˆÖé–̰´ÒÓG̳*ÜÚl²nm.ê¨hu\–Íš1êéœö²•ö+…û*}¡YqÏãØÕË\M3Ì\ÔB¥a­Ž•†ìfDÁ_ÅðSMÑê9ÚÈ֛£M+sô6ø° Ž:G·Ú¾:ô*½HsžE+êu$lXº–¡¾éeŽÑ,×$Ƭ¬Þ˜öáünÁ†ˆvçÕäã¶r´A=]Ž1”àÅE¼ÈM ^ÔÈqFªþ  4Þˆs|ÈX´d,&1pIubF™6Ù€¼–ÕÁqŒ2ÅH(/1ìXÊH9èg‰D#’fVm USÄÏãw fÇœ˜‹ «×@Þo©Ñ¨ó üßr#êç°Ñß7T_jù3öœ\¦¯aÑ/êÒ»4ÎÖ!ƒ2Á¨Ý`஺ùF;·MÈm»•[VVÂO4ˆŒÝBIu‹fêÜ„×ã܄nj¨µš¨2&øÝ‚Ùeܘµä .äSÛ]ea{ÇE£dÏ/ü³Êü³ËüsÊüÕeþ¹eþyeþùeþeþ…eþEeþÅeþ%eþ¥eþeeþåeþeþ•eþ÷Ëü«Êü«ËükÊükËü”ùוù×—ù7”ù7–ù7•ù7—ù·”ù·–ù·•½x_Åbnµ“Ì’…>BW aF( tBZ`Ú“8 u‹¸ }APN$dMˆŒ‚¦DHA3"¥ 9Sà!r ZA™DRAUÐ’È*hE„ÜE¤ÜMÄ´&ò ¼D`A6‘XpYp/‘YC„ä©yDlA~‡üŠ…DîâöÚN³d‘Ï¿H{~;ÿ¢üuÿNwQš×ý»)ùëþ=e4ÿ^þ¶ߢŒ!ç`Á•éuÿ~0´Á©,k9X‹àADðUÀëþÃ~ÈÐüˆƒ!x„ƒGwByAþëþ‰N*/p¾î¯Bpry²CLáà^n‡½èÑS0 Ñ6½„àtg0t‚398 ÁÙ©ú›“ V§‚sSÁ/Rp^ ýüTpAyr ,Lqp1åÐáß+Ñ]Ò^Ÿç,Yìó/¡²s R“Ó¬²´œf•eå4«, =‹±`Ȇ²%B¶\Rµ<^¹~üï—Ó<„1Ë£Õ¿ Q0X¹Or/âÎÇ£Ö¿¯è-N‘t,EÒ ‹¤qI’N¤÷ò”À¡¸’nRŠUÍ ð͸{ |é®YÈ»k²§ŒqDzþĺI°^冥ZJËêE`ÀV5ƒ@$ʶª— F´èƒ‡ÓØj­Eê`-Iê-Iê0M‘*ÛØ¤Ž„LG©ópÀ±€RtÍ&R{2©oãÃ2›Òeš\Áßcì~¥öK¹ŘœteÐ?øÑ£ݲá=3VÑ5[®O¶1Eئa[-Â*“u¸ „õJv„£Ý@Xo&l×á'6eŸhò GP”%Ê>»•²ÏeDÑ— Œ(¬S•Ù-;Y™ÒªÌó)š/¦hþ*Eó‹æñIš¿Í}R4w‡¹ž´Ù4÷ešŸÆ‡þ¶¹þºˆ“‡÷²³²ÙŒQõ^¶¢«¬¿L¶Ó0œƒôËÃM÷Ïx é–Çûj]ÞWë°¼/=‘&çÂý¦uâôk>’M/У \ ‘Sÿ-ÊnÞ¥Ž–Ý<înÙêÔ‰»ÛFýö>³9 ȳÕg(ÊÈÖBÑq®¯{ñóÚÀ¥!ü”N¿Ýž2è·ëSfD}z(JùíWNù(XçÁÚÂwñq=… îDûДCi1×:•òýpª—û~ÄžÙ`–.wBO’‘Í7=&æ¨^Ù˜œFäºËýWÄOqRjgóqA]åC3ë·8d8ô´X,x–¤ä5r)g˜Ãú³·ôù•ø+ýÐô¸Y_–j¸LØâô÷z2k·Å©Ëõ qd^šár@å"}šãˆŠ:1äeÇЗµ¨ ©5¸Â×n\ìmÑðCg£@kÁCNy@cÎ`Â<àlwóQ·¬qXŽÅ,§t‰v½³u(²Òp|›È‘ǃ‹œòC\â .vÂ/õ _p½“&Ýàjg»‰m\ò((•gVœd†¼ì8É <†½¬}*`Œ+ÿŧVYX+ÏŠ«’~.#Ú$"cÚhca,­j •£¡Š39_Þg…¯”­^@öftž‘árâbܵ<6 ›……]…Ý…ÓÂ}Qƒ›— Oò UÓܬĹ’®£ú[„²ïÊý&\• ô8 ›•­ Á˜ù&k!ã&ÌiVjÜ¢a§ìƆ5hÉÌ\•Öàa³à•iެ/ÐV•8q㲺Ä5œkJÜ#é±¶$m4›÷:l~÷Œ6íͰKöU ŸlL‚‚®x ÂKG‚(¯4kÂW( ¹&<\‹ÑTòfØMëÌpÐ þ§Ä"5&þ§Tï{B¼ õvû{(mjqô AyL!Hdp›©o†Ó¡ë ¥7kÅê°¯XÙOÒ ²Ÿª…ÜPASUº)Å7”Øéù;ŠFˆZø(§õœé áP[ó¸¶ ÔÍ}4²¾—2KÊÒRТ¥ öàþeA*ò[·EV³åBŽlÈ¥wÎu$.Yh]Œ?X MU¿í&·Ñ,}Ú” ±¦ôƒß× 4”ú«8ʼd”› 2ÕÕOÁMf,åRŽSi`Ño»I”ë-N¸ƒKöREAf³‚›œo¶«j#`ìÖ&–×­MT¿—›£ªˆ2jsƒõÔ·h!#‰™`áµËÃI¶ÁRsTªJbr’ đĔ;‰6šQRܚ˽ßRû´¸¢¼ýQŠG“ÝZg»)DkL‹ƒäÊ)X;Ç`²w> %Årék´¨8Û÷òÇ%ÊKÏlDÁÜ?6ïNžÆåᶺ‡¨?—C K¾·|¢NLù­(ªG_Ò~(ŸŠå·ÔÁý·•E^7qAúôFMþ °Ê§¼ÎÀW|‹3 ò‡ìÙºK-Ò䳉 µòGˆ•HÆú”bý$oÞ”µ=ã XÛ^ó¨Ö–6ÏÑd2>Ït²O"§Ãí¶ûh‚ïP'®•‹ò%è´Ô‚ó«GfF0Øç<ŵÑè`+iäËDß–ÖÊ?ضú:±é¾r/I„Ì`ŸlêëWT¼Ò'JûÉN–¥³£Di)´Î›a…'â¸aèq@þ'ÔI&Эã˜ÎwPm7Êïx½Ÿ ÈÅ-a,Z­ü•Y)â–,–-ge²œ•éÖîÖÐ`hhhüG ‡cbžA•¹‰\¨¬H⪂Z&2†„ÄB¥/±ŒמїóŸ± fªÍ— ¾¯¥%“˺‰8¨Æ µ ê÷…ýÞ‹ï¥W ¾“~£–WÓDœ¡”Í6™¹Iݯ ™Uþn‘*ÿÈ{^X‘…;kn e„{ƒ@K$Zí…Ó!ÖÛš”…à?¢[ã\N˜ÕE÷ •gÞo…œ#i¹GL+èÄqWQ\ƒmê­¡PFíº(DËʲY edþŽíN†LxËí´$Çæ[ÓL(m>+©ÓDï|«–¦x”|—*³´û¨éÒXÚ!ª¢Ä7*d¾¶1=”r·Ê£¶ªÑÐŦä5:,¡VúSûÔ$O{ý->~)ññ}²Ã\>-ïNúçÓóp©ù`}¿ˆÚ8|L¼´Å}{¿lšßi÷ð$ñ¶ƶaFžæ4ÌWEqç“'î¼N\Ìx,ÿ•†ÇÖ]ĹkÜ?JXñŠÙr”ˆ&*fËÑìƒuP6ÔÛCfÅàl9ND *úfCߪÝlâiÀ¤Î̃wÞ.@9 ,þ-‘íhñÅ^î›Í²Ï}³YxžYûfÓ-›zT“§Ø9:Þ (â7"g=FfËåô•Íö¯FgS În7°È”«{WÏ3À½‹‹;ûŽ]Ê¢,ÛŸ®ÓBe¼Ƴ¢Œ/FÈ wÌ­æAI7°}±oòðfmá Vågy8³jo øÖUkT¦…a.ÖØ.‹h|<1 [íB[ñv²q›ª6G ¿Ìã„!áX;áX Ïhd •p"¤„“`~*Á4;Á4m²ÌB‚A”`6,HöHJrO`Õ#—Qÿæö° ]”çlâtMõ"´G±¼®¼®¼ãÑëYxœ{ÞÄã³çxŒ.<Ϻñ8û|ëÓÓ?çL/ {Çú+êa!gŸly™ÏÆÔrW|¡ÁTB(­bn&Ô¿Béc²¡ñʨ›M={óšXH¦,ãæ#-ðSúIyô=¢«[¡êCù…Nµÿôœ›PvSplö ?…ýâ%¨r“öéÈ.?0¸Èòî{ýu\ΆŠO¬´ÛèØ`Yžf@g`D™ä;ÿ¼ã©:!Ÿ‡Îê—ÏkO)Û|? ñ;9[>MÃwR¶|†Fï„lùC¨írn†äÄxÉ—¢‘ èØ+Ràÿ"ðÑÈ$€WÒJl˜‹àý˜µØž¦´´@¸±ÀqÀ¿-³JdJ6ø4 .ÿÉ?Ú¯i|f¬ÞX®a0­Ëp©¢~ø ˜¹A1jò,XR• Á’–J°ä~ £)(ìJ«êr€"5Ö÷…îçDÊ×þãp01ÛŠ7¹ˆ÷­AL¤¯Àx|ŸâOF¡Våi.êãË.T1ø¥ã~Çê5^0¶=(‚ þ>ñ` M (v­L0ÂÌ ú½'õ‚vø 9ó9ÞÔ+Ù”€·i,Ûq?'«¦òe—´ù-§44°ÐÙynʰZyõà7âÿZd¨yÒÂËåEñÌrÇßR6Ÿ¹©aŸcãTw.þõTñoXÅ¿‰â_½¥øï±|Ùjîpï¢i”g2îoSsý4bŠ DCS'êüwVߤÉAZ£¾ãkÜw†‡²3-¸úîȡﱨØ0¬uQ.Ã5ÖᤡGí¶zÔ6x¼†IÊ}~&+[HuûÙq2ªß±Ð ‡!m;¨­ªØ_Ù" o„i©¦:û-‚—Cs²Á­¼R£ å‹Ë™¶ãmk˜¶µÉyšˆË ±æé4OW3ÁìO.¯±uþƜú<ءϬ‘¤<èQŠÉ6qÖçÙ¦W ú›ÀÐ"{¿y˜ÿ;®Tž²ñH60{r÷7µç‡ä ?°ñ÷ûê‡DhBj#Ÿnä.%Ÿ)Ùè‹>ç(Ýè“?"”¾ó oõ‘@Ôר\Fãå–Ž×hêÿ…økÑ^—ͯ,j`W`&-ÓÊ*ÍZù_ x¥‚¥Iý ùz`¢›:TP’U|ÅõV`0tm Á¼ÍÍóFcɪwã-^"ØÇXþîŸ?æ¡;ïüÿE^,œÍ{"Á&I»‹€ùÀ ¦9=D‚¶ú¥ÃŠ`d&îÃâÜ›¹”û¹”EãbNÄ–&"`ÕpdD›s†0îȬdQ§‰Dæ³VYg@’;YZï-¥% S#g îà3xŒ± :—†ß¯Ù—*êB*計\de¨¡aØ× Û¿ÁÌo÷k°;yîCy<’:÷ßÁ&þ;®Rç>ÕÙˆ‚ÊÚCiÒ3¾­²öRq3šdÖÈ_S–ôø Úá·ôi¥?­ O§ùÚ×&èo,jÜFÿ@W3JF;? €6šg»LäÙ Mã"²e`dQ~Ç5ZÅ‚l޶Ÿhš›>ŽWé0§œ r{þÎQP²É6˜]Æ ÌEq˺FÜ¿óȧ*[ôSÀ•-*[D3S`¯/^¼×Ç~'xbr&"㊺Ñvù9ÌM®ó~BGSS\ÛÂ}+ ­Èñòž¨)Úó-ÁWÓ´Xñ„"±7Óµ8‡jh+JLÏÄ"¡’À}—­Ö`ó˜MÒ*?zÍ\Ìqád*'˜´1é#™ôm6éÛéxì)×âô8Y¦'4¹ã›¤ïdÒwÛ¤ïaÒ÷Ù¤G™ô8‘<©Èñ&mˆd„ÿö“\³5é Þ¹jqj\µÇóœÔM òØÖ:в?3"ð¨|N`È!F"¿¥2ÙÜìÃÉáHÞä(#°Ë+päÇÅ»x^9‘çN32–§ñx6XÓ‰‚GÌIëf:•§[©s¦•‹¡´ù t6ïëÖ¹ +Ù5Uqš}«ú&ýšÕAü$¢r]@à1;¢MbÒõILº1É3 VÖùlÚ?'‚kFôèìòôÑiüÍ5X™³ªÈÑ6Í?",%ß«èµŠÆær†`xòÕÐÊT¹J}š\¤>­iôéõ©ù™ò ËõÐúçïUþe/Uµ•›)ÍNü|ÕýsiÂ0ðÏ‹@í°ƒFó–ŽÊ’ÛTQÜ4s¡Öäz§l4¥ˆóëì”û‘žß²9›-O²GuY£2Љg¹ÎÍd-¢7ËϺC}wú@+@‹[‰ª*j-y‘œ0AŠ+Ú&älóŠÃvùÚ<ÜYÈcF€«¸Xˆ¶9n—<ÉEÉÏ®ët2ËàA’à ?1l:\:¾H~jú`[â Ï¶-qÐǶ%ÎY H3bçtù™ýf.éœ!¿PoZVÕ¥³&¥¡zŽçUèÅžGáwû,M[­x·Oê *M«ÑŽ/¢î&¿5é™P7»dÓ{¬U&.gäe|Í`ƒ¿Wì¯ó#¨êkê Î|oZ_h(p˜Õ@5R6àÿ&†ŠÏ~ß3U Äå¾âzšIJzYßý € ·1²·Éøðµýu!qýlÐ"&n°™¢á×”Îêø¢$aCÌÛ “ÃLÏ}v‹dO·sîÿÊMŒš~­)k¶6µ´}Ó ÚëfƒœeÚ22Û侓&šJgš‡†exw©aàéN˜‰L]aÖ²ÙFÈe-w0 @ëß"Ø,-€ lˆÆfhÁ[jCt6 Ð÷9ß´ ß¼®rÝónCƒé¼Þ@Y׺Þй¡@Ú =ª×êW[u{ôºs‘k¥ ¡fÓŠBsL/rh­t}F‘C7›4™Yä02š4™Uä0é1»ÈáŽ9E—pT9Üšcn‘#-Ã1¯È‘®;æ92tÇ‚"‘±°ÈÑ´•cQ‘£™æ8ÉëÃ˘*7˜ÖMÒ“o’60ÿ£m2ù&i«)7™¸9Úl&ü'Uµr«É†Išƒ‡ØN@ÚߨîÎÑz¾Óov*ÏÙR7ñl¼Çd^ià°Òñ“«¸&øiú`¸Y~åXn¸?-(j&/X{L^°ðXÑðXÑñ˜1ðX1ÑcyÄyœ‰v4áZñöÅ,nb1ÛoZ‹Ù Q­i-fM¬S‡ÍX°.—çLù¡¨Ë×åŠàùG*E–aÛtÄŒ'£E”ømQjä136"ì”ÇÍøˆ0ÍH¨)·<ÍÆ°[þEwx¾Ò¨Ò>3Û}ïÄŠ¿#߉ÓoñvŸ†Û¢ÏMÏ/°2Ô#B,ø^qú·?ž7=áãe3°ƒ> ú(zïP¯˜jæ´:±2â¾AUñ~$­ÒY'VEÒ»:å ·¸,;2†u€cÈèýÔJg eq­OCÓȮē€ ùžÆÄ¹žº;Q‹ƒ`à+#”ŽÙsˆ<‰} Mëü‚LÜ8p‚BL.qüX4z¾9Ê SÅÛ×§cœý>>&H/>.Þï3‘d%çT ªÒÍæÅH&8;}øÒ °^Å;’Þ”b¥šJAÁL˜€˜ì Ôøð¥`¢…èß)ÙTJ–•¤-k LwP¢,J“Õ«ø€Br?Åžé¤E5†•žq<[:¡  d̦š_i2‡{Ú7ï„EËf«è±&Ò|5=ÖFñV¸™\ä 5Ë„­ú%N{7¡"6•KQo¡&¡¦‰PZ²Îä2'®³ÐbË)ØV®…eáLåb“âgbƈ“ë±PsµñðÈ Î¸ýÒBntÒÖ-ä µ€€g¿Ge¿)•ý+û™¡ÌŒßÐÀ׋»a{Hóü ª“4ÂY˜bÏš¡,kŠ}NM±u6Dð„JSìW6Dã •¦Øk6䛛Ь{&Ò¦bþõ†}×>¿Þv£ÞyiÚŽˆ±‡.H#ô:§ó\éFÚ͘˜º»˜M4hü ¢wWF=Ôrž²öAœ£›Óøv>*{ eé£F€o´8F~ÍG™ÅeKŽO<ÍCïR<çÝ i—±¢³—e߯j²…ðî.b/#m/kÝ]²Ÿ‹ùÌ?¸MîO¯4ñÒvë$D ç@—âÅ0Q ¢0±vàëòýë#tS§Ë¡.ËĈKŽqâ¦r‹b>ª8áÓ©cʨØC>fÇ™¹vÊ•HèÌÏ‚ôÉû.ÅC¯q%-ɬe³O˜Ç?P€ àüyb_§—Á´¹X¯Û£)`;q÷†¸X7#EB¤M6Îær3âk° ·ª¶ÔØŽ‰!·©A§šHî@¼æVqÒQ "½f2ã‡Êb’ÍîU™¥ùï­îì‘ûì·‘êÎ-d ©Zdþ›Q˜VgN'Ã~¢½Άi”ʃ¶Ý•–Ük\8þH {Nƒ!à–ÈŸ€†øi&&0–ú"¾0V('í˜Ð>µ ½‹A­alùÛ£(DÐ:ß®SãyK¥$œï0Ä|@Jñ-ênç]*‚@Ž¥.¾¸BMö½ä9©Ñ^ÅÅsM[vÃÞDåÌ“šók»9;°—?ë«Õ˜ÅS0œ[Éë·ÕÊ}#Uÿì.[U% óõ·5ÿ$šåÿƒèéæ¾•‚÷Ô»ùûÕ»eO·EQ6˜¯Þî[(â \ö±MëØ“P+Ù×­³@­e÷-T³ Ë·g9ÍnƒÜŒq}‘åê/Øh†¸þ]‘â˜OK9‰r{zQô¡ˆ~w~Ö=ÎaÖQ'¶µ™ªð» „—,3’âPÍЇÖv#óú!Ǹ­)ÁKÑ¿'ÇâÕEUæãÝ8 ¢-•Á{f“·T9ÔŸ§ÂÃŒª’löØ'§«¢ÒÚôZ6eƒ¢Îp7*;ж³îDFõ­dÌu[ÝT™J˜ßˆш&ãµlnÖl„¬Šhõ*µl³¾·Vîpåð¯¾ÿš[ñпÖ?zÆ7ºÕá r+g̈Œ{RnC8 GŽô>áÉnJ?¨ÛìÿÇØ{ÀGu\ûã;÷Þ­’@Œ­¥Hò"c±cc#“bÇ áåY6$ì¬"-ñj_¿—'y¿¼DôÞ;#QMÇôÞ{ݽwc42½ê¾çÞ»»²“÷ù>Òν3gæ;ýΜ9sNáÖ—…ÜÀ´4¬pBf7ããéÃf¸Ûë•ȯ´œ2|`í[éˆð¥û*ÎÓΧù­ Ú!`ÊÆ¶N9øóàÅ#Ç¿ü<œuÌטJ/ðSGu[Ê©”‹)Ødî­wµ^u=~ªµ~u}Îá€gS@…³«»gzÀú„œCÛS‡|âÀÒ›·Ìë¢ÛS‡5}l—µÈ~{$Š ÕSÍTMs¾ ÈáN¬+ öH@ wò޳0Ü)ÇË#¼•îœ`¼„^Ž` Vé¬ÉÎ:6q¨ò3gnGѬU[T¹Ð«ü*ïÌ‹1Ý;=°LwrÙàPÙ¦;åLg8 ÚªÅî€:Û)g;ÃóaŽÓ¯ee€e3‡èäÅ&Jæ \èÃýZ3õÕöHÒ2FªUº2ØþlïWêÊJÑÃÅNìinàÉ3 É’c€ØÉׯ÷ÚY–9ùøe…S®pòií'TY*kœ°îÝ#-õ´ URš?õy¢Lê:XÕhër3J “‚#혙 MëÑ@e;Β܈MóK½I‚ËmÝFQl;r³“6ôXòlqê&l·±K­ºÝ atîý;‘t¿µwŒÔŽÈG†?ýy.dµ8°ï¦ÔŽ{QÇŠs9'®äœ $U9ånZÝÕÉžCî%¯@çÏ)÷éˆ.y0 üÎÞ=ò‡ÐßÐ߀a’ªÅ©@ò!§<äô'yý:žTŠ 9ý)Ylát %â”ÐVâ4õdÔIûñ=”å€ó•† Ò*èßÐÑ@V9Ùæ ·²<êô'ge¼Ïj–õŽ;å òÀ†Â'ù²ÊõYæ ½ã°•v„g9•ߢߞwúëû]<ƒ^ G$ËW( ŒqiýÉz½¾’‘ž¶èi­#ÑNmþJZjÚ³ô–æH•7X¼„ø;”jL¾©òg¤£(:«]ÑÐù-×›)Iª6BAo|àÔ%v­¬=µŸÞ«ÅO-œ¼+‚C»"8‡~­>¢e†ÓÜŒ£Ç<¡ŽÑY×0­Õ:e­“3¤ŒÏ¬½\²—K?r+ 2³·ËoÓ-¹÷q¡«”³Íêm£(¢ß qÞ†[hÎàŠfeô`#Û —ä[+Ú»‡ ÇchgÓ~èK‡ûP—‚ÄìœØPW”:ŠèÃ\~‡84¦äzÅåL[E êr8å(Ÿä|ÕÌæRµE\1\ú„`gîØsÇà, (p–T8sœM­S\rŠ‹µMuAæÉ€.úi±W>R*wÁt&›“›îòz\‰Búµm¶KÎA ºÎÔ®(¤ÓïhÊÓã\ªD;«æƒb¾Ëw ~Ã\ÎÿFåO°Ì=°ÉE.ÜhaîÁbzìÈÜ‚e.0àæ¸^q:ÒhQ‡ý‘\Ř`6­ƒ¹éËT¹ÎFÃ*ŽzÔˆº [,7ši4®å°.æ?j\m;õjÛÉ5¤ìvÉÝ„U%÷º êû\ÑŽò@¼ºž‡ds¼º J¢ó¡ T¥¾«w6µÒ%+]Ì}‹€£.ðñüW~™—W%¹¢T Hè„Ë”„¯tʪ·SG;ãõëf6úÄUq.éeЛþ’^†KzÓ_Ò›þ’Þô—ô¦¿ê’Wõ¦¿N _9#ôÏM#öÊMÿu¼é«õ¦/ÖKc»å’·‚=õÇ(Ínß;\ÿ7"¢;ò®‹YD |Ood”ïcÁžÔ-×V»ßŽ·†K¡EPo¤›ôAUµ¿ |ý“ð ÿ©¥J!àœ(“äÀ¤H˜§µ*°~œrHR$ª¿ËAIÑOuaÊ(û͉9,)ÊK‡'…A5")Ê)°xïHJ-Šktj¸:Q rQ‘}›19òÉñ5äp6*M‚K3áAŠšf‰VRÒêXIy“­¤¼CTß4£Nè"j.d7¬ŽÀlHÀÒM~P|"/ 'í~JéÓµ`¾&ÒÀÚùþ.?òÕ÷-iãíÛµ`IQP_îxA‘¿-:‘ç«'gÄq•z¢äDžüX?" c–­Ô=A;Dë4D³E‡"ÿN˜ÅOŠ<åÞJ,;å¯/änÇÊN>m|ÇŒ²o¢²/Ë„Ê~‡åTZWÆ­²³x«èdž·ªsðd}˜;+EE§ò¼Ç:OA`än3(G½æR@þÕgþ+K3ÿ•…™éwÛ+ê_ü¿Lþ©*ÿ±ú U–!o÷šY´}S8ÔxBÀbyfLÈ8¨P;-ÏÄœy?& s Ò€ÇMâän›! ³<þ¬N!A~øa3Øéû~ÍåLuW‹±=,Ëÿ 7ß-’ÑqþP¼>'°ÐÛQþ1Ü|¢’¯Oൈ¼zâa±—qÖG"(‡oC¦èÇ”øc®±FðÿùùNçŸm˜Ó¦àttG<‰U;QäûNÕ¾…ª}E&üÛ§ÜåZ·Ëmn*~Vt&¯ùæg‚g¨ÚO ÚÏæ_kRrÕ^ ŽgÒF[Í•Œ†ƒãi§4®lƒX‘o|[›1X•.°-“𓌟”ÿã@mlg°~ÅÎú78#Úªp®48‹‹¬ƒ!™ÃÌÌ7uûzó]Îó½ÉÌÁ7EÁeVfLŸ.H•釺óÀò×cå-ƒrV9 ±t}Èy"pØú mvÊëøUZ¡'÷,”Ã1ßÐcÎÕLõ†sV?=&l±ÎÑcþvYz ¬¥Aõ[¦ú­,à˜óêø-DL¹„·ai Ùà/·õPÅæyD§¶ZYÛ¹LèGêÌ;ÙnzÏ“är; V§à—,WGôü8E®f¦Eñ™¼zÙäñGæû „®£7zF2ëEL=qÊ ¤±ÑÜ‚åá˜Qr²ÜdzÊ9£äT;¹#™éï01Óßi¦Ÿ,w‰ÿé'É=ßMïwÓ?dÖ/¨’s=–Nohèw2ZÉm^eX˜gÄØ¬>mc“Q‘Ú˜wñv^H:ô9îˆÙ›8žÚTI!ˆâeò£„Ç!Uç‹´ˆp8UO-ùÊc±ÈšC…ïJ¼û Zx%OqÓ^ÂÂF›³ØQY*Ö[·Y1u.笗h­rš¶l …å m“Û&'Ÿ¥mò@‘œ|ŽöÉ䜧r«ää ´SV]®‹´U~Ãr©´)_nmÊWh«œd¹J[åË5Ú)çX®ÓF9ÇR–eshI7y¸>1Eä7ÚS.í"!WGï8 >ŽÈÐO#ÞÐÅX7ÖO%ZýKmä4bqÛ|l§: À‘õ©ý‰RŸ¢z~l“>[·¤èF‘õƒùžCöü#³ÙlÔìr¨‚£.Gïô9ZIôc”:è“ä…þâƒ~’’8è§(ßôNù™òíAïâAÿ¹’8èË•oz§¬P¾=è]†æÄA?Kùö §­¶òíAï’ó¹ë¦¥±XŸÍët6ÏR¶X|¬ÊÅJlp;0ày’Ðý\ìw ~PŒ~ÿiPŒ84ðåAÊçE¹.x¤ÿ†¯ùÌ9“íã(8—§ éåønŒ!ÚépcÁý@®Õáêe_g¾r±åz%&£“R°Õ.ГR;³*J«•ޔȾ«S+ JnCÀE¼>gàbžŠˆr{<µd3^Á6»¸‹Cü«€HîæÊ l±wиë;F¿•Ǻíeµ‰ÃÞVÞ6Þ¶Þ0™jo»ÃÎÃÛ&÷+‰Ãû€ò­áTgx‡ø¨¡£r_<¶–ÑšþŽeGn}cpEƒ;GUoÐà^L£úkÜjRÒMÜ‹„¥šwŽEÒØÎÁ,àh‹îäîâž”d©¡±a¡ñŸò†å›v–z‡µ³Ôoeé•¥°’nçXF¯&`¹ T‹í]Å%r¾ (WɹP¯+ò’ôQ!{Uñ-Jï´(ÝR¶(½J^S¢‘ÂeéB^W¢KÒ™erC—ìeOWµv¤ÿ€ïŒ´ó¦x7­ }‘¡‹ ]dôHãÉàÄ?pnµUà¬S…3¢­çZÀ gq‘ Îþ¦ö2µZÌúÀÑ‹œÛgorî\}È™ýAR_ræ5L^JÎÝ@ÊJZĩт݊¥¬-m€{©~n‹åj„z%>>ïÂŽ‡êGŸ/9l•CU_«N­@ä’ÃT쮉®$l•Ãé%ˆXK"V9‚Ÿ¡T‚~*m$ûTZK*­rœŠ'¤½K #m ˜HDY¸¾0IOY§ŸƒL’Ÿ©þ¤H ̈SéY'"ÈÏõÊ ¡McªJ+‡V ŠXy:a6‰¥˜,gªþäX!fé/z’³é¥n)æ°Obº T¿ƒÞÂÖ‘ô±Žd UèGz‹ô'Jl©ê{ƒâ¸æ×¶GŠ\¦úñ¦t4¹\ÕÍ´óçu%…ø·ÛÑÐïQO®Rýõt‘ë \OŸbOx?PoôÿÄ[q3räâ¹b9ÚB1ômÕŸ(GÛUš+¸¬O=ê˪ïRýúëéY­/w9ž\”é‚KyVÎɪެŒ»À¨Uå¡üð“?)†¦:~D"ü(ðé7ìO’‡ÕX.Rå Œ²°‘ä@ê9UžJHþ4’Oæä“cÉŸ¡zògõ'Jþ¼^¼äXÂiòï‚êO•)T.yIõ§ÉË /WàÆÊ™*¿BEÔ£ý?*ý^R ï´²:Ö5ôDúO–æRµeÃú!ëešßÞòÙ ³ ½çI@…ó4 Á© XŸ’SVj«…Q¯R{+kvôÖäSÕ·§­{­ñhÓ±_/Óü?:do¨Ÿp¦¶À滯淅ý4×N§~s§*û‘äOÓýöè­m»ÆÚsë@ ¬d~Æþ¾YÐo1HAæGjÆ-•‘”—Þ¥b4L =§Œe lꨑÖDŒÕÂXàtœæË Ów¾,Ù/㵬²¼²¼*9AcU,©åÈä-Züá²ô–Ø3h¿Ö3o…Ñ*J~®ù>Œ|(|†é·`Gª(¹ÛÎaM} +Š•gH E‹[.Ÿž‡­C|yQ,26>OÑä MÍ*Ùø¼ƒF° Ô8Ñt–*¤@zçõ 3¯“ ÖÜ•jg¾†ký²À¨:Ëí¹Ô¬’¥z•,Õ«d…^%«5¹"^+ëVÅ*3ùÕFU”¡*ÖéUÖ£ì±òî¶Óë¡pgªi~¹é;Uð,+ ÖË™‘Š,·Ç LÙI,­j±yYƒ¢þú+`«.~ˆ‚žá‚M³œät3g^CÎ…×Ô3hÎZ¡0]¦¼ a}‰õ`¯Î”—µP8ˆ¤…"Aš¯j¡h°*¯c@–~¹•â²â“5XÅÚà²põÛ€QVCâ|”UޱRb«2åXØ,<‘Pä5¬–-y©y©U.Gä5™r"‰GÞ‡È(òZD5#G­l”)¸6S·Æ4,ù"ߣÈëyx<ò3ò«¬Edªš2¦Å#·Q䉶P`="ŒGþÜfDþÜ&Ëmy}¦¬@äQY&ç¨Úû­J“à"î“à<ŒÎJªöþw>ç:‹öEWóº.•°¡Kel–Õ¡j_*h¡™ºJŒÁ¡Š¡˜héG–™¸zf#:#Û“ºÄ|¹ô*½¤_ÁWvP©ø‚ æ*su]5óØÂŽÙ’¸ ‰Ôå<Á©SøÔæ”M[,äš5m•h[üÑtÍç5 E$JóÕŸªh¯À5NƒÅ"\ð°åú,I¦ºñ[›Kñ…G›£×‰ü2lç`Oý/Ì~C Í£œŒ¢ì\jCÕÚ2£Ö"\kr¥È‚’¾,\Æ:,Pu{t=:•-ª¸sïrß·ëË3?}ºÎ{ —äQ§òW¼¨­ûpMÞ³JFD„ËÌÒªž”ØSzì©Ñ|Ù?,¢žV|ö[ •L/1¿#êyy¡Nõ,ÖïÎG=o,6$y=?Z˜»Œ@DFý©2âñ4ìIå<+r;Ê |ck|´}Í¥»Í#ƒ;ÎùÄÍPD¥½-ä]á»Aß«y"}9 9£iÜ‘¼/bWþtkD©5Š­>&¢Ê Ö†w´ÈÚKj!V§ÅG}Ô ÞC…,Šó”uIÉZá»™ç× næ‰?±¦</’½ò5Ôpq4çE¨UµY~ÛÜæµâ‹ÂGíb¦ŽøæïTÚ¾Šqñ°Ÿé(*hÔ YVMs.²¡ØSS `H©˜ª°t§b‚ªü†›Ge.0lX@`^¾eª"§”Ìø½Ð­§3‹¥£œ©o^Ã)ËÒ¡†Y áÞ½†SD ’‚ˆs˜8ËPG`ˆÓAí‡U Q”ëy0Å ÚyJB|–DRR?RpeŒ‘¢)Ë þÂ"sß<ž¡Á¡ðEõ¨Ñô—ÿô²ºÐË•„ø&ôueEŒ$–ñ¥É5ÆÛ€Žr‹þÈf¯ôEàq;üI7ØðòXh0²°ëv=B%%u˜ÍQ*uÔJ!¸!ä!ƒQð’\š¾å×¼3ó©NDó|g>ߥ ëò3Oq—*jF¬mgA+ÊÃÌ,(v-KkÆWÚ>0}XãÕC+×ÃZX–/äi&öîmOy-~ø üœÑS„¯QOyU4©D*êë\<”â$ ½#Jiû-O× q¥ôÊïHdòjBÈ5=¤w~Gù²vÙ3zJòkn·´wpÐW·•¾QLækI¯|y[Ñ/ã$Ê«ÜUŒ´˜èA;Ȯɠ™Ÿwg÷dÒ¬åjYªÓj !¥¬-&¦É¢ú½t¥Z<ýµ8‚ É¿T*um‚Uº6Á£äL*µÖSÞÕFÛ»ÝJñt] à¥hº’œ®ÈJx|^Z $nie'„þ%Ò×3,ä6$œõô‡±xø Õ+è+ÐQQ°o8Nuù$ÃÄ8¡ë$üæ˜Sà·òz£Š&ô¨WãÉg•­ ØÑòSDëRD Šë_Kë½G#¸©Ò¨6di°ª)/•ÅôÙðßÊKƒ°ÂoŠnåù~*?‚ÔÝ“_²ÔÝOEÉ­<$ šE6f EÕ2¯7k¿Zz ] nSÄÊš"lŒÙäc H¶øv^¸ðŽÒPP3'›n’Mr¦Nv× YÐ.—µg@¶‹Í•/¼ç´è&n¶&VÑl€ç¶X‘Oß`£‚vSÉ„*h{õ|¢¦¬YÚó×T”Êÿ1̪Þkgù¼ŸЬ{4“«x8– íHâòoXðÿÃc© 'h­„9OªH8’’/ÿ5~ 5~}XZ,Ž|ˆ¤3»ì[Ä©ÌLû‘γôR`û 7X™){Ñ:çd‚œ²â[‘ Í SÒ+’EáÊd l…öË£X5n¤f53J¥Ÿ"牓¸—<“)ƒjÿˆèös‹»u’÷|ÃŒßK-þ'x±j4N+ë»,ýëPv'Ï;°cðÖR³`Žå¢¨™Y ™F^¸wHmMõîÔLvìèôžyVþ;9+Þ“É9ùžìJΉ÷ä¯È9õž,éèLýœªæÇáJYP<¾aàQ sç ù׃×ãæÞ»TÕÁ+ÜÂÜ}ƒeñ x=laî¿1e¯-Ì82¿†×“æÜÜÛxwl£ÝñŸkkmÿ^[ûóÚÚkkýµµÿQ[û‡ÚZòõÎ*•ÑP>”¥©VÛ÷PØ‘<—¾cI³ðî·ÄH®ÄÅ#DàNÞ /üTÕõAŸ5ôAGÒWê߸›¸A]…AzLø  ölf(iØi¯†Ã±%èLÌZÃóc"ªûÐF0Ú)’vÙß]‚Î~M EÃë7_ ” ¯]sD™”ܬfv)+R„[.Ð%f‰¢1m_Ži+g#{‡™î„CC} B ™Å’ô“ËÝÂ7 >’D`›µ#>mÕo=’­yõõ0¢VŠb‰3éJš½’’Ýð?ɵv¯å¤€Žèp‰¬GóTÔqÜTТ§ÁcǸd¹HiÆç,Ú¼ž¨Ï: k2¡9+ä©-¼™)hoKädzT5)yý—¬%þHVÙ+±•}÷b}0)}gS ΦZbz]¯±^×71ÍÍ·¬QäÅ·ÕáËCHAž(ØêŸ‘k ®:†:BaF[Ëð£00vu%3½#Ët{ „‹)ojAö2ã¹ö¹ú¼*÷sx¤äayQ{%ÛҦ6ô’ £H'²TGRòEªÔ5\h9N{è9¥â$9_”*§È™[ªž&g^©v†œù¥Ösä,(µWäQ*ü•úÞ_Ì,ksDžd !¾²$ï_AY’(ïYIc˜ßÂRÝ»ãpà>ûm3èh7z†<²ç"ƒP··î×ÊaÃä¼õ[ÙÒÌE.Ô %c›ÂX=F5õÛÊ‹Ïe†×¯Çš|Ù[÷ðÛ*JXi3 ¯\Dº¡]°r¼´.^°Ê¯•¢sº×B«ß^.Áž}Yý#ò WxÚo1m,)µ\Sa‡ž:Ébî$ øŠ'bg_SSv° þ«9Rñ@»>¿KÕ7ÐÎí4Ð.¸à·ÌrqÛy,\°;±æ¹|žÇ÷ÊÕ^ÿ¬üoDþÿ©u\+ê¹LÄÀ—ì¯køKv£³å…¢{yÞ}¯ïåU‹¯;‹¶E÷ó¼ß<¼%ÇE^Æ&éËØ/Ke;ò»[Œdz¾‘Æšæ4ñgÂ7w.3“T¿Ïq% :mœ½^E|+Å÷â¨/HÆ·ƒ¬ÁùV&]ã,þûw· '߯ɽrƒòÅjñ¨PùAÑ´Þáo§µ Eogõ'Eò¼}ÚPqª;kï=ÌóÊÎÁ‡(ÎõÄâ,-•¿$¿¯bÅYŠïÿh£8‡¨8·3ᇻÁl¬¢Kº¦³ø…MK3›Ý[³Œe'Xpè£j1&E|¯ÿÀ·ö¥¼„…νLR£ÿp$*¯bÃf}w•ƒ¦c|竳lV›ý‘ €|,üaUVÙ“g!Õѧ­å_“…|$ŠÖ'‡ƒë“i)àÛLë÷[Z¸`s²Ò›Õ¡geŒÂßå¥J™»‘àƒLZûGŠ?@ ÒJ¡ø³vhñ_ôÈ)y”G‹| ˆÆäª34·P`žÌШ„êzïfÒZ"‚·PànfáØ|%õ3Ýœfà~fVF3Ý€&^@:ü[¤ÿÍÆ4q%§Wê}šîýÜ^­ÈÑ ¼¸ äXšÃOŸýTgðs,k7£}E40Æ‘`äoB]Pùåíå-À¬}#ì^æ Kná¸|+4ŠRBÅO3—¥½ÂçÈF‘q &Íöø…¥dL¾œ«$ÔRçbÅ·=9†× …Û“5Ö7²T)^—œVíÍø¶p£n¡=Î¥h]rnp]²ÜˆO¬Ì¢¡g_§ ì¦Oì ,À`·Â`/Í 7ûƒL³Ùi±Ã\%Ý(åƒÌOÓ²ü¶^ÐTÝŽ˜™E®„°‚úÈÊÀô‰WP¬›KÿÚce)Ÿ2œQÕS ­r«ä±Ä’ÿvLþ‹´´ÿÜð…’—†¦qHœ…éŸsº’üS t¬œ3t¬\T¢Ì¨»Ä)rR_Åk*PåHßЊ1¹p+íOï¢Ê^@•ÝSh$da$Ð" ­„Öð”•KsÕâ»:Ç|ÍYkø¿[ˆç­;™žñ"w8ÿÙ‘Ü- qº<5«Jåë”9ù˜¾*>l >ΔßWZƒ2åpf+§«¨ºÒ©{(ðߣ;qïÿ$ï?„á}—¦ §+Þ:ë£[K/⢗ ]=mÂVÙ—Æ/ø9ýøGy Qt³;5ÝØìÎ7ÝÛÆ,:leù¾Ñ¢¨ÒÊ~ló>jÃÑVÏÿó¾ñßú¤§ .üw _ŸàÃLÐòE¿:{êĺyÈ2rÍjV£R(xA3K>^Ú£†¾kÈzµ<âI< Aݨü„O2ÓÀC~Ì)<‡ ³:ÉR„‡ ö9øv_œâ Øg·ü¦D@±‹)žÒVD³fƒâÅ?Xüílw™#»Ø8ÖrZA9T¤C…®SìáäʲcD“LS?“p›N'ÚËD½âD³™hLŠe6„±t¢ýLÔ;N´Ì„[&ø,D˜¨O6rÿˆ6›D›©Eû¿!6 ¹Õ(@áAZVð‘ißx¢˜¾º»åÄ›ôDq¢ýâDÇÍD ì/™(ÄDý³ÍÏ(‘åú&ŸÑ}Fç:à‡Æmž' Ï6Ï“V7“nßÄü¬nQ%øTWÇ>"û_™‡IY±Ù›Õln¦s@.>g逗£PùL•?,e6tó¿ˆ 6´]|ü0…|UÏÑSAÕs"ð™ZÖ_@©=ôiPþGg«”òˆÁ6¸Ç5 nÄÃl÷ûx̬ÂøÏ¢ãÏW¸y?#ÿ ””7»ýfHh˜OÊ/˜œ€±ÙŠjw¶ÿ@a +­+…!‘´¦Ô2PàZ(H†Š·Æd rSL1‰e3Æe J>ƒ“ŸÉÉÏá‚)ùPâ<ÐÎæð,æåæõ¥–r&¼gŠ·ÆéY&$dt§´™2úY~ÁTÎèÄxF×Å2º¡T¬33:¾½qH’Mâ­ fF?ãŒNJÈh%'_Eýœ3:9žÑH,£K-6¼+Å[“ÌŒNáŒfrJ×9¥Âן›–o)è/@òY<Á˱7•Z. Ø›÷uñÖ3Á© %¤ t°..Ï/¨à’/y¿˜<ÙæRÑO1JN㲟"(œð å­©fÉËQò]ÍÄ´€Ù 0G˜Îåq€é1€-¥bzÀt±@2[ykZ"€ €Š„ÊÝÀ•pÁ ®ÜéñºX£˜u±µÜ‘uzŠ”·*̺˜AS…ÍþwxŸÐmÈàþ”R|§Ö€%¨ÏÔ‚™”4+¥½ÀŸkq gã`ñNìuyÜ+àÔs2k å´Gäu*÷F‘À¬|$QÎô[iÑx‡Kí­­•_³½˜™ñl VcÙªšÙ®r6f›Ù­r6ƪ”Ñ*ì䨱lŒWÍlLPlІÙÌÆl=cÕºÙøLE6fek´ŸÍl© T%&–”€¢kµØVjYªÊ屜­TÿAÞ~$:Â>°ØH9[çW6qÕÍ*í†u˜O*i#lè&Dš´މ2W‹Á/i[UÚ-­5gåŒ6ÃÑðoüÖ‰r#‚®ÔòÑ;T¨K˜m®H(ÆíÕ ^.þLà¿Ûa^‘ôv#3êœìØŽï›Î–œ¢ÇyÞ[ƒi‹t»³hUô$Ï{§sð ¶H_d'l‘¶—ò)ýÜl“‹MÏê`J·#4µvà ó²×<‰söül}ͳƒ¿ëpø‹þ^ó sËòšg¨[¾IÄ ²õÅ Qu§‰ûÃP`¨›Š»0îýòþc(0 Þ‹²õ5y÷1×<}ô5OÉ&^óô7Ö<ðáYœ­¯y(Ê(sÍ3J_óŒ8Ã4Ö3ÕM_ f²jÀLQ ˜ÛmäTU‡ùÌ-?+î@f#`Àãü0ãM´Ó„Ù©ÊÝ€™æ–{U³‰ö©>5\ šM´_5ªn/­ÇÕ‚2 Mô¹[Ú¡8Ú  Ý$´r …âh·M´Ûª¼ ´ ·¼C{Pí¡‰ö°|d¢•»åc …y þ{$:@#´Aš.~8D …cÜÁ/9ãÜÁå L‡„ÜÁUŠŽÇIîàZEŽÀãwpƒ‚+†¡ÀTwp³"Gáqš;¸M‘£ñXáîTäÜ‹d[“¬¶v ÎаèálÑÃÅ%š¡AþP¬"§¢«²‡œ}¿T÷‘sÿ%í 9Ó»Z#äÌèj‹’3³«ý4Œ˜’Šs4SRq® ìT>ÍKoú:u/k$ð¤9ú°ìcMì­}­å+«.ˆf›Â4$ZGVô8>ì£Ü`jüÉþá·…%ªÅãÎâí¢^-½CìÕ²Z<鬸‹z·ôûq°7½>í¬þwQŸ–ÞÚÎÁ>X½1V/ûKÙú¯^é«—Aúêμ†ê š!æêe¯^ú¨r8>g•Ùº‚*¢Xˆçbá[!TõQ;­àuKUlÝB¤™¾ñuË oƒ°¹¶ì%–sŒgÊf5JekJ‡œ6X‘¼Z´õ9o¿¶¿Á­Ïɶ8äÎVlVÛŸAð 0ã_Ŧ"ÔÍò‹jñ ‡øD®•î¼wø@vgmtUòÞ(¼Î…ªnÚ¯ä¯ Ï·0‘e‘߸¥Eàrٯ鹕ð(Ö ÎùåØ3DÙ*»·ÄNÄŠJ9hâ[ÄEmNÝN¢¨3ÜðGQOÖa¿$.¾Nì—»ÍÀzcöK7¼|€ÿJg¿øp„Èì—Wôgªý¿Æ8¹§§â¹Íuí—ÿÏ7·9˜*s›ƒÓQþ/.ua>ŒQõ%ý¸&^˃ã2·y¸QƒãÒÍ|–‰ @<š‰§ù-£aª0‹ó—¥?Ë:ßâ|à,ÎáÂ%ùºï Ôq ¾Ì·' @®yewŽ‹÷6’ûœ“ —Z>´NL®¢NrK)9lg@Àé3µpY>DÅpLÛ Qj?úÎíoÐf¹ÊGrÙ‰Æ$ëü"võŽçj¢,ËGK]ðò ¶‰¬KT vÇ×¾·…aL›/ú…ÂïN±áR_¸øÏÆ5®p€FÁŸgZÌO_ÉfÖè+ ¬O2 ºá  Gxn¨ãùD÷\îNô|ª{n¬CY«{nªãY¦°ç =zz{§*!ߟÞàú$ÙG ßÒËóƒ’ tbŽô7&!ƒÀùÁMIr y—³mN»c‚ ÅÆZUÚT¶¨jÑCkÑÃÚ¢‡­E{ Ün¸i·ldæï>Õ í¨øFSß›”TÁ›¢p[Kѱx °ŠúI/?}Rô­Yøñ81B0<*zBc£žïž(Åd%!rúßÙÜ\BäÞ†žD9U)kÃ[C¼}Ž7Œàþm+q2´`<«Ì)§b'PÍ€m€5zBšiœŸõœŸò:ù¡Šœ«$4—ožyÓwÊ·"±|›’à/ß Jb¾’™Ë·0±icå[T§|‹ÍòmtÖ)ß—±òq5.—o…‘Å åÛÈù)¯“ê k•¢P’/Œ‡^ “~É/n¡MôR|F+'iÁP’ܨ êªüâb@ÙqDnVÂéNœo)[q æS¶‘³£«º’'ݵl«ÏJKÔ­J8°=›z™Ü¦D÷ê÷¬’ÛÉk}Fïׯ€XÉòP²$;)`! ¹Z_î׌;À IôÃЕ{Îo]hÂÞ¤¿p:û8qÖP[,M ~Xóâ/7¸Äí½öŽ<¨„õûЇ”0½ç–¬Ì—‡_$©0’»³Ø·,}‘°`»FoÞùí Öæ‹à<·PôŲø¡žÒ†üà2ÚùsJŽ’5ùò)&È+ÙšÃî8¢`‚ìÂ+;D%Í’uæHÞ[Ѳi Jcᆖ¸– ,qÇ¿tš~è7íb¨ Îl⪔ÃÕHú~  e$læøÔQ*VíœîÖ1*m¬Š[›<€ªä(BY2£Éo5ª «£FyÙäX Xhê#È.Ç«aZ°¯Ì÷kÔáÓð!ãWsŒXÛ· D'@g‹Ñ ƒcÀ®Úè›c`²ÑÇÀ5bŽrRУn¤†®à*ÚHU4;ä«ÙªJßÕ;Ǭ^®Î9ªœ«&~g¶Ówf¾jŽVL§êã~Ü‹ªæø@ð"UðãàŪ9¼DÕÇü8øKÕìÿ^ªêý~¼L5û;‚—«z‡¯PÍþÆ|m½ÃW«ÿ²ƒc›¸ô¡ÀRwÉú|¹Aý—]´›tÚeî’ ù,üµÄ­ qRçÚ®Êíßî\;©s5c¯Ð F{í1Ûk/·× h¯ƒþÒ-Ajn­xBh kX‚Ù¼´£zÓ·)Ƴ]Oÿ’ðßí´n¨z®4Xˆ]gNù¿+xtû=ѦhÜ‹ÞÙÁq/Ò¶¤‹ò½¢¾-½½ºûÒ6¦wµcQ¿–Þ>]‚ý°ù*‘^Y*!¢Øi%$6G¤g”&Á•nøÿëlHÎþ³…àMZæ%§ 5U¥’ó7â–xy «ï¾¿vú«¥ì¯GäÛaùc_ZqZ ¼u§4Qr^ñè*ߣ‰|÷Ãô–[²%Ÿ“¾3J§3Š%¸Ú- ¬vfµ–?/N„ZÐâ2°É]¸Ê¡È_"„¾,îpáÜÖŠìê[ë€Dñd7QA“SžG>`”§Ü5n|ŸädzÜàî(?!­va%-e“S^ít“sÉW+8 –ѳÀÄ\çNMb¯ CßÚXQ×0R*b/Òr=y‹å›x€Áª¦/*nÅó¶ây;¨ÓÈåí0òv;ž·J3o•Bçíò¶VÏÛ #o‡­ò$òv‡‘R»H·XëÈ]Ns ·X™b,ÌË,|sƒkÜXãõ8l ®wc‘kzTZƒÜµÆ2hml‰)nµn€ÖÃ×ÅÇáëܨ¸á¸æ»#ðI¸‡.˜ô#ê‚”¥–¾­ÿTxp3½W<órñtþïv6&BØ$¸Êˆè§÷yÃ’ó]‰¸¥…¢SQÿ–Þá´õ-é±ð€w0žšc¥ºurÚÁü /E¼ƒ).º¢Ï|>xE“%¡š´;ê#|#jr³(îßúœqtê(‚ÿNnŸQM-;Eµ8^*ö æ­¿;Ú*ä^á›ù|¸`æó¢læó•r¿ˆ„[Ü%[ÜО lu—luSãÓã6wÉ6š1ð¸Ý]²ÝM]ê¡csýÀ·-ÿŸ·?§Ï›Ý A]<‰ï”å˜b 'Je#ßöü¬nç•àN7“õÊI}IMÚ½slVU+¨9iˆ¾ÌénÉg½òù¬p†~GtSóå÷ÂÐîAŸåHO\‹jíQ<®°_›1fzÁÌ—•é‘òžɱZaÓ™’{ßHî}Nî}Nî}Nî}ùsŠ8»òH”VÕÏżžN)"½‘Qn¤Ù7ÇfSµÁ‰þÎHôwœèï8Ñßq¢¿“ÿIyl QGü¯HGùß„À&+ÿHåŸèգ̘‘×ÃÚól“yD2DÙzFÉ×,L¬$åŸãþwÃcòz™®gJA¦ ˜’“0ÉR¾þÕf9æ${Q;ŒIöM²»Ýðc9”0s~õÝÎÛ·‹x©h@Ko¿.Á4«÷/ØÒ; Kp ½Ä$?¨¥wP—à zÜEûyÑà–Þ!]‚ƒéuhkqÑ–Þa]‚CÐíæh6«í'5§(c#ëoÌÇú³±þ†Ó~õo˜h´¿¨ÌdeõfVÖ:; ~šìúýµA96Åj{¤_ê¢D%Z&|{ÜÐz;˜ÃÄé» öN{ÜÖ²=î#r¥À!÷à“t Ì®qf×Ep€ö¸áú’PÖw?‚ûˆ_ méÑ%8ešckfµÍH«9]*{²Y„Ô¬~=ÒZôxŽœLúw“Wcr›ÐÓjq­«¥'J,è÷zW…~—ýDýkµ8ÛF£šX×Áú¿ÕâBÛ߫ůöT‹me4ÈwvpB”í«6®Þäìé„CÞiþä~äL|)¥¿À™@½¬Å¨>´›W¼˜:„œr® UøÓ§#¬4ã9gKÜ"gº¿á ÚÚÍö?3˜œs¥V*ò¯PsH‹Ò¿…ó•~´ýßp`c£Oi5ú÷p`ùØq wK#)¾œp`W#fP;e/~Ý«¿º¨ } Ã:söXoáÀ!Š–,û Ÿˆ€ëÜ#ZÆRXW@=9P¼Ð£¾)Š÷¾P<´ey¿ér´ðÛýɦäÿ¼9Ì·±ú0éy+ã„?Ýo×Y̸gÍžãáéø–çx&Ç=yÉ<‘ÓÍž™>“›…k,œ"üš¯ }Ès£Þ~9•JsªQ§&Û¤ùœ;ÊfÖésî·—ûåþd*F}ÒÑ+R;B@cØŸªëŒJ“s…?ßf(lÌ|f`†u“ &¢š0‹f–ØšêOõ×k¸„U}ùS<V©p¨°Áϰv~[’Z­'µIÍô˵”Ô…XŽ×qR›[€£Ž¶Ø,üõ¶PCl¹=ê§N¤$¶ÇSÑ£AòÙ…ì×Ã^+º²=’=:Î^#Ëûêdy?ã„Ì+!ðÎsâûl›(V“Tƒí±žßþ9\\Ð>ó„"s«wýLy¬_½ç»åIÅŸéw—cTšy™C=á‚‚/•·oë 6#4×ï¾ååþxë¼±¼¬øÓxû!(æùCËù|“k`™1lc¶‰¼ØÆ1ئòºâoB‰—û›2´T|9þþø='¿QüõÁ–·ÿs#ás'±bô.þœßµ[çž^É÷QÉ üòåûl¬ur%?Qâõ‹îÔGH­½L¥è ý²—‰Eï­"z•Ï2‡åàRC¬U&¨´"w’нódp †sh*|!³–C`/v‘#r4ÅfMñŠƒ*î—…ƒûܸbfÈŒDM™‘Ãjñd2#gÛÈ#†ÌÈ^·¬ÌÈ8 „5 ¥Ø˜Q ó3<6a«ò)`¸e™fJqôÒêHqôÖv\x×u}4CŠc?m.!P1:Ž6R³µPà ÐÆÄ µ@3Åz4¹}¹å-&Ö£™b=šQ(šÈ—iz¡ºårÀŒÃL%Á„3.sÒ„9‰£}‚ »åÙÌ9æ¼Yœä&ä–3>ÓºyûZC`&Äën°©›w°U…nÞ¨[·šu7ªKCu7Òj€më GY ž°HTÄ-GCðÄ8Ú -%´Ã@›G[m¢­¶Êµ@;â–ëchê¢m4Ñvv›L´Ãn¹h“ãhçv‘Ð*6%ŽvÝD»n•7€Vå–7chÕÖ:â^ÒD;_*k¬†¸W¥[~´Ïâh£ ¨xŒ-8 ´©ñ›d**žd“S ¨ø˜[NµÅt˜ÙLf6gOYnÓì¨[Wiüyf`vÌqÀL‹Ã0aØä!ÀœpËp &bÂDM˜¾ò°sÜ-¦<ó `nÌ)ÀTÄaš0mò1`N»åÓL­ Sf7`öw½ì:Ì)·ìm'˜éq˜iv‚© =ÖÀ̈Ã̱0sìr®* Ür¾Ý„Y`7`š0Jå"æŒ[.ÌÌ8Ì~À$˜s€™‡9l¶ËJÀœwË£1˜c&ÌqF¾"O0ç蓘Ùq˜€y„«¨€™‡éå0`z9dÁ\tË~¦¿Ã€à0`ÆeÊæ‚[r@ž83›R“_8BK€™‡YdÂ,rÈ%€¹ì–Kc0ËL˜å&LU¹Â€¹ä–+3/aL%Á\Ìü„È„9é§s•f Ì9æ¼ sœf æ Í@€Y‡éã$˜~ÎPà (Ça†8 ˜!N9ÌI0×Ýr„Ó„é4`F9 ˜Säh§sÍ-Ç8 fQÂÔ˜¥ó`ÇaV›0«r-`nÐÔƒÙ`Âl4aÎÒ¤cÀ|Es`–䀇wH ¹}À9à ½;[µÈCÎP(°Ïœ¯È¸ƒÉ0¹ƒ‹ÁcØÜÒHFñuw5’‡ñxÄÜÛHÁc Vâñ˜;x¨‘<ŠÇîàI·<†ÇÓî`¤‘<ŽÇ³îà‘FòÏ“¯*Oâñ¢;xª‘<…ÇËîàÙFò4¯ºƒÉ3x¼î^n$Ïâñ†;x­‘<‡‚}™£i6û_P®;f5Ýq‚Ù îÁ¢ìO•GNy*ëÅ*«º~ä ãLAµëñ5/Ô >vFX‘ábýŒ5jh5d]^ÅÕñ¬›ù‰3ÒQÖ:ó{Þ k ûÄKsLéÊBG]ú\Ä¡*þ»]bée\ñ¬@/'‘™šV‡™Ú¡hxKï0S‡ƒã²<ÌÔ–5KåÏ fêÏñòKf¦v3õx30S»‡rƒ—5ù$Ë9Žd{LÞ6«½…­DÂâÆ+sÀwMÍAð]Á¿ŒUÓª!{Q×("O‹âá`È®ÎѲäÑdÈ^ÕâR©¸*pGgÈ^¾ãÍÂÇ›‰²ãÍ*åuð[¥»DºisH5î’7méq¼µd¼•öˆô8ÁZ2ÁJDÈ‹£&m-©& èµxM&ðc/ëüØj. ªsmN¢0M"£u]Ž.Ls™ï_rí½Ž—|®½7 Ÿ*ÇFÅý=<{Riÿ¢‹üO(° óÓ<˜Ž‡â—¥gQÓÿ-äkŒ#¾Æ"xÛ-ÿ7¸ía(pÇ]8¸µ"ËDñÍc©ml/¡Ë)„<–¼„Þ(ä†Hðü cL]5GÇvw’ðõ±ö±Z`þâI„Åjŧ‰:°¶\ø>·~nƒ½=Úsêí‘ú<³ùçA‡{,…ßMc‘0ŽÒ³î¬“-~zwý³£´+z3ÜrƒͰ9ç_ ñoÉQœVÛhQs¥ÜNÜ{ÍÖÞù&Î ›g M…SöšÆo¯Yáô~ͧ×köÞkÖÆBövܾŒŸºqŸ5ÜZòþ~-XeÃe¿5xÌA1¿-¶¡¦ýö`Ôù¿#xĦßôØš£‹Y_ÑÙ¬¸l¸‡¹w[ýkÌj\C99ö†XžÈzVÊõ"Éàå²tÏ3)ï [$\XëVå@lCÄqŠ{;â§LˆS:Ä%_DÖ¯Rž5!Î⾚n½_3 .±¯8DLÇÏ@ìŠCÔšµ:D/EöR@ö§JÙ[1 XùÏ>šòn4!°®8Äçå/§¸±'1Ô埡0Ä,ª€ˆŒJ1Û„øÝr.Aô6!æbob ¶QÜG€Ø‡ØiBìÔ!v+,móm±Ç„؈Gnèîñö2!bâ ®PÜÇ€8‡¸nB\×!n°Œ‘}Z‰[l:D5 »!âh6÷7€8˜PQØò•Ó–ï %T”¹å›¡ê¥ÊYL†ŠRÍŠÂ^ð U”ò–Å* »ÊPb vPܧ€Ç!ö™ûtˆª<ÀdTQMÞÕÒø Äù&D‘§fµ"¥ œÒ•&– ”Ò¨îÎèîÊê{j:R'h>Ž”[ëÑ*À&/“×1ò¢u} JÿGl…O[;ä¤ÍQ¬VÛbË5œð¨î–NQÀÓ]¹KÎÕRµ·F»eßë^·”½^%ï©Qà”Üi.ïãñˆ­„†ð­½ÄFž¯­íP[[R[K¾4DüZóZ1™ÿRø­ú³U.~›þlÑŸæIå·z³æúms©÷_˱&©Zýp+uÿºxµm-[ºžØ!Ð÷8Ó T8;ºj;¹÷Ywqï³í&çâì{Èàvì%çBwç>ÜÞ {RgÃ. ýÏ@vv‘#ÁÇ&wS‹½Ú¡ßwTk¿?6m¥+ø‡¸æÞº!£)d4Bœ´ƒEÉ ô¿ýôˆ*8@®Ç’Q¥•`°qFÏ*È>ÓÖÌcéY%ÃÐßË „"¢ødëž•©ŸÐóª8¿£A+þJ…ß5ƒÂ p_G°Ž¢]í~+BË)ØÍN XœjõÛŒ`y‚FÀ÷§ÓÃIŒÐdÖ¹#"4°HëRè¾î€ïõEÓ¬¯£-^ÄLDãþE÷/ò¸Q¶Ä—ÀK“ÑÆ²­Õ‡5–/ÑR}DcÙbsüí©‡èÆça0&¸´ƒù´¯!ì¦ÏooÉ!ÙÁÁåÛœ‹G}¢v†"êÍ(/iïŸQŽÍrphcÙòkñh¿¡hP`8¢Éx´„¯EÞXþÂh±âט8÷į胸\À³å7œ¶>[ÞbéŸÖTÓZ/)V¼j™‘"g¥ >椄å)Å™H‹P`TcVš4¸µUÎ#ÿùð_öB(0:î¿ êxi÷R\•blW¥P·/kRäšßüt¹6¥x~:¥ŒoLhÝi~ºZ6?½R®K‰„óÓJæ§Éõx|¢”¤3×{z‚r½w Ÿ:×{·T® ç¹ÞûÔe€åç¹Þ‡ØÐæz•Òƒ Þ¦uG®÷1n·çzŸ@uu®w·¶³¹Þ5>ÚÍæz÷ø ÷Üû´ÒÞ½>švs½;|r9SÛËíäìóÉä¬÷Ñšë­-¥Y3×»¤ˆ¦Ê\oY¦È\o¯ Ä&¼½ƒ4ùåz7ûhâËõ.êJó^®·Oæ¼\ïgÙò9}ƒ4çåzûiÎËõöÒ„—ë„$…w`ÖA¹ÞAAšùr½ƒƒ4ëQ^Þ¤¹Žj4Hó\®wh¦¶\ï° Mk¹ÞáAÈQx•ëÝ⣉,×»ÍG+¤\ïBhÒÎõŽºšwdI¹ÞQAÚgçzGi›ë”ɤ}v®w\P^&g|P^!gBP^%g­O^#gbP^'g§O~…fõA Â;)(¿FCåMr¦e5Š”U”5ä|”ßóe‘¼Eδ ¼MNyPÞ!§"(ïRèœÜ¥ÞEí Íà]Ø^ö!gQ{Ú®çzç·§Ýz®wA{ÙŸœŠgi»žë]Ü^TÐu¦4–£õ˜cõ˜ãô˜ãõ˜ô˜õ˜“ô˜“9ægy‹~-Óƒrâ±xgåB…¾|Þ™A¹Hiõ‘wVP.VZmÞÙA¹DiµQxçå—J«MÂûEP.UZmÞ¹A¹Li5Txçår¥Õhá”+”V{åJ¥y™ð. ÊUJ«-»((W+­¶ ïâ \£´Ú&¼K‚r­Òj»ð~”ë”V£„wiP®gŸeA¹}–å6¥Õá]”Û•V;…wePîPZíÞUA¹Siµ[ü¢QpjcyZmÓòÆ0üM±µ§‡éió’·”âe™áÿ°ï€oã¸òÆì.€Eaµä(aL˜´EºÄv2åKιƒd¥Ð9%±dJð¾óÝ}g[çKrwÕ-[]Tï½Ëê½YŲ, ˆ¤ºdÛªªZ•ßû¿Ý@ËÉý~w1;óÞ›73oÞ̼y¯Ø›‡T|™ÿiôï$Œfäëñ謉‡xÕE¡È^ö¿pžI¼Õ"F?£üQ¾îTÝ)ÚTÞ­“ ÿÓŒk Ä?&¢ÝÕ¹H,È?%óŸ'™ò_qAÿ•„ÌùoKæÄfäÿÄ£³Øz,äíÄp¿CQ½RDû”Å£{Óߎ¼cm ´˜çÝ8ì¦ð“Ææ}?ŇYø0G­¾W=V†¿‰2¿“·J»ÊùjõÈ2,å¼uåK ­:[ß/æ×èN]åRËÆ{4c:]ºÜÞiX®Ê•º ]¹ «ýûišvõ34µqñ¯áÃ^»ø^•-úcs¦A]1,*ç d:Ã7.§ ‰Ó51¸`Å6ÃÌ,ZÙ?ëÌ@Wyw¸8Á¤½A®‰K*ômQáŸ5Y׉ ÉvÍ“¨ïéÌ}Þ­0ÈVÕH’t¯¾ýäßàÃú™@BÍÞ *óŒSË3ÚÚt§®™nfäçìW¨w1ªÅ³Û»ZwTy™¨#݇ZÊ\‡m³y§@çsþxÕžøa!\Œ&{p­ž¢ Ei¤†n¹ Gs" €‹SÌœ`»OÐä$»S¾É€Ø7 8ú.² .aˆ‹ìê` öKC\mC\­Á|ë8ªp1üPtEž]pÞP÷½F¹›Ì ä=®÷û¦c&÷hñòÓ¯†V¾¤Y§×ûÒ¯E¡±EJl^@B¸7¦çr{Ÿ`wÔÜ>jîu1ÇÇ6[°Xm6ÊSiEè¦Ðzyvëõk’§5#Áæ §4´ÔY«¥ÎjÜ#žmëcʧ£+4v",ò3†—ü"°s6°ÏÚ»¨¡¹£{?‚o©wàäÝÕJºÊû&J?_ÇÇkèp'GWÙÛ‰4ˆyü" â“þyaÇ 'NžHù%ÀƒzüŸî;N‚;ÄÉp³ØÄ¯FèP'ÑUgÀo«N§ë$óqŠ“cûÁεE\ù;Çg‹Øï9åLg;1€ž³†eÙ÷©‡ÊMoëÊ\§œë4à”àî“âõf9Ï™ ¶ñ:e¾ÓHÂFÁrå{ND¨•ËMÚÐÈ+,Úš;ñ©Û*g"›Žk(y:WªÚ7€> ¦A‹ØS78aM‘ùÖE©!¸¦›œðOˆWk«!¼“Öîꌊng~ôªc»“ý7â1íUe»Sîp& 6òr,EPèb•t\VÆ>aÞ4µˆñ/8>qÊ òãÒ—ðC´8eKšMR:?ZF"ÍëNtNTÆHÅØ=|‡ÛdÛ&Ò.Œ1‹s_Pf»ä,WÜ­ÄPi’³]4¢ˆÛ®;ç»Lv$vÒ—…®D¯Îy**{å—CF»ÂSŠèo")—¸¸ÿ“ˆŽ$‰y’ßâ¥Ý¦9}™ üR¬úœ®A¨:äbƒnWQ¿žntI0âé–#ÝèÉ-Õ•u9ŠÖÛEp8åNüZpÚ+[D§Š±£Ú ”Ë9Ó܉Ќ¿qÀ2}º“ÁŒ›å îYnî)Ø¡PbÄYî,¢b£Š<«,vÇKb“I²»!ÙÙJo™Û’ö+ÜIγÒ¯ZK3Ï*؉ -V½N×£N›Á©7öt•â)u Ãþ ð˜øUå=®Õ¨ÇÝ@ð=–‡'ݲÑmwçfÙìNZ>!’Ô¶AǪtÐìÜS§„­==ØAc{t]qscÿÓÞŠÇå)wÚÁóô¿é…0|ò s ¿3$ÅYj‚ü7Ž•^¢uþ‘¯“,ÿGl‘]pÃU6eEäEwÄeÑqQŸ0äcgë²Y*(ØÃFK ˆÈ…je(AQuþ)8œ[{:é·£ÓͶÜ=hùÍ1×·¼ã&6É»¼- õ=9‹‡z³^̔ޥƒaͧ§)í Jûê™”öÓ ô[l€SBê6½ØáĨ(WÁƒõ ‚ UŠàÑmmr¨q³²7Lçnw×ýŒGÏ{™æ74Àh=Á}£A7ûƘà +Vi‚žÂBl²Ž¾Q‘r—¸ä÷Ž©.ù˜®st麜¦›+eL×ÓuÃô8CGô*öqÒïÿ¨³)÷õßjst9[g 0墼|UhÃì q®V"Î"JªöU9ÏþYTRµ¿B!˜ÛÔd¢ãªÖ:¼ñŒºƒÎ l´ò[Ž ºÜ¤C;„D.yèi„ô2ó Ùª›ªÙûúƒªÙvÝTÍvöž¶{öö-HÅ4Ð̯ŒfAWy(”ôÖi?ªC”÷2}t˜R}k'Ñ‹gøcÈpBÇL>’qu®W‹.[©ô¸ WPâÚƒ ·Ù ¯#ÃM9ŠYóu€è±@ôÈ·=ñèx‹ƒaS3:z²o²GN5ó¥POóäžPo·QÏD†ÙŽ[žF½ÆiZ3E'X¨×õ˜4ê¸/îò¥P'¹ñAÔ;mÔMÈpQM£>gƒý_á]´Ø‘¨;ê›å%o 6xï’Ì­^“{: ÊsÍÌwÝkB¥‘á ' hWy›Þ ¼9“X‹žÁÂît£7 Búœãój¸åÜŸâ3òp¦:Ô×E÷Yrn„rîeõQ>–l™9Áôó48½%¦6ødƒ/n~Øoà8ÉÑL"Åc NDC7ác7ÞÄߘÌ=æû u¥ÏZ¯­ôɵ>Ãî&ë|Ô à.ÅZ7lô™lÙ‹uÃfzÇ”b'‰÷ïÈÒ ;|<Ñã1á û„¢íðɈà&™Ðî¬Ç¦Rgw¹Þlû^r\ \³Bâ’/ûÂS¼Ftt ºO ŽÐ¯¨›âm’­>+µ|ÀKÕÉ ÞU¹âKàuªWÈ«¾êiΑPˆ1‰šòº¯º±‚¯·ßð…×x~º .L+vj.×|n²6_QÝ‚üf¦¤(Iþ@ôöËÞþêò“/—o‹Éz¿]˜_ÝTñk¸“Ti­××_Ý\nã±Ð@’ýUhù¥¿_ö÷cfþú…ýõf9ÐàŠ òä ~¹§È·ýÉDÍÂ|90“ØúaÇQCýáÛÝnwªŽCƒé$™\®ïò^û$?/ÙüÕ+ª³¢Ÿ?Y}¨¢j­®È©H©ªs’¸õW®¨>RQ}´¢*©(r:@Ì(v¹\úÕ§|ðÝÓI­·=¦òý^Õux͉Çw_sá1,ðšŽç-ñšOïk>öFý{‘xMù½H¾¦þ^D´×4nþSfóŸâvWNq»«§|ò3*SÝÌáëCGò¥ÅE^ ·M-&Ðn^ÓÏvÒƒO6èÝ-oûR{Ww髼ç  W·a¤.‚Dj@2 @<2ÒÏ@Fú ˆñ½Ó°ò§€4øãÑi äx$ƒ"äë62 bÌL$á[´ ìv‹´ T_N¢¤Mî¤3Ãˬ§“D„W™ÍéU«¾âsñªwuøšà¡ÛÑXáPTŸïH…CÍóûV8´|¿ÿp…ÃÙÁ‘¬p¸¾ë8Váp{Í}XÀq¼Âáñ:V8¼·„ãP…ÃçuÌd)³„»ì?Tª=MÖ¯ñ3ëñØSÖûåz®#&¡º‘f¹ÁŸÌ ƒÎ©[ür“?¨šæ%µ†^GHnõG´ªFÅ!ß§úÃ- ·S†I Ûýí@ú“©r'¥ß6Ó?0‘q{ü¦.ø‘ßÔ÷¢ÓÍ*Æ×ß‚î¤ß:+jôËFx¥ ¿¦%›ü¥¥åëŸ)Ïý+|uþFÙìO9)8H³ynîHÇü¶œ_ž Æò0á|ìWOÑË…±±yÊL‡ÕÀ< ÓÈYn“…Àdzþj$Œ Ô\.”ŸqN#4¾äùœbnýдÚ·s×?#nøåU}T–â×ü]ä þI”·I0|îOPøFàm¿©'Þó·×±Iz?]³6ާ] ëžîñ§ô¹ð‰LëžË°îip×Î ŸÌütŸ†ñ§Æ¬ðÇÖYã%¥ 6’âük^1Ìžzðüëô/Dy—ïUb7o£»+ßî1ª¬¼¡{lNÂæg˜ûìŒÉïÂew±}ºI >eal!ŒûHCeãÀíÿ>x‰~LwñTÑeåc»ÇF—µˆqÝ•Ê eåã»Çèç„îê{Œ)+ŸØ=6†~Nê®ý¬ÇزòÉÝccéç”îΗzŒ++ŸÚ=6Ž~Îý†«¦Çø²òiÝcãAì¢b]Õœ?nÝ“½¬&ëÕ"föoÉ· ìßþ1Ž õÓ‰è™ ù§Dôl…üs"ú ýþ´BþW"ú½«xÞ çáÅšît½X“lO““LO““LO“xl ©xl ixl 9ñØrM(8Ó¾³?›íL¼–Dœ±ýDb‰€œÇv¦ñ€œÏþÇ‹uát=ƒÂw`ÄsO„W øfN]ßG U#î§ÿ út[%@ðÒâ”í˜,ŸO_ß—è «˜"ö7^œiÿœé«rY±æt{Úº;fÆÏhèáx¾E|ôwIåy|YUêÖc½»zc0ª{BÀÁOá71þôo{jŸ.{Mèš|¥‹>÷ÝÛëŸr,'¬n= Þ Šõâ²½ŸÀP[QlqÓǯ‡/dº9Àÿ—[MëádYØz±íTcm±í(|zãÅŠ¢—¯(±ÿgšzÿ…à©Ó»‹ç{L(+¿ýtlzÎz>;øqëG1ÙÃjìÜÖ=¸©éïÐï©ôwØ÷´È±¸ð;´ë¡€ü=šõ`@Fa#^ì¢6 "̵áa²9á]ôµÚÁ@·æËlLµe„/¥[í*{F UÙô—ð> à—/ønì àý¿ |òñò…ß|¶Ù™x¯9€·¤ð^°ì²5€¯Ñ>@n-δÏÎ4“ßV¬r(ž}1ù,>/éèxV~ A—ïëÕGU;Jùm¸B§ÉJsÿùZøtãð+ŽöXyJ«*[Õ`éÙªîœ@h΄›Æ7Ô/ëNwÔdWQüìw?Mj;Ÿ'üÐC~êŽ~ü!ŽdWœÂu3°ã)ÒEþ,nÄŽä/ŒÐ§nG/ÓEž:çv Øÿí?ÕÏGÏ<ž @GPå/áe½Ø<"°p7Š˜Ñ8ðØÉ t > ¶mê ÓÎüD€£ü 5ÇÜr(ûOçìdÏÙ¼â/àúȨ:$a`1] ß¶´Ú¢\³8 [=²Õ‹æ¢ºïc–§B³&®6!燼†Ê\=ÞŽ«\è¸ÉГžÇœlÅñ ÅÉyL Æ_…7T0nò³½ ‚ñL~òÅ•ãÔñò—°ËÍF…º]¡ºµŠxÜ °ð†Iv£?gd‰X ÙmF–Èäæ‘´‘Ýû†~•=0ÄlŽÆgãO³[übš<]ÿFV,žŽVxí:†£»(c9F±ØAKÖ±öûÈ×›s+±rÀ)ÉèÕ î†ìbÒN ~öxj§u%É­Í´ê´…Ö¦SøÅú¨–KÿtÌUL«¦e®ÂM5_‘ Ï»£kl`¶ä~[ ñ޼âÛ¤ÊÍj)Ü1Q‡L¢~†&ñKÿvÄm¢&;”ÑdïÛM¦[M¶ËïÈh¸llqÃîGЋ¾~ F²òŸcŸ–©²ÔžØvus”Ü)$ó#÷Çýéd¤É8€U€Äñ¬„*jxbYÄñ‡&–)p“T#ÙOvžé©bøSôË ebF.V×M*çGq×°ÙüI\£B¸Éx ÙivQâÝ6=¢':¾¿MV#ÞˆgIgÜ,y<¢5ð¬pÜx«’nE£Qý®ºÍq&:6Þm“'Õd´UÇp¬&ó–ÞmË…oÓ_ì¥?´ ’Æ£-†Øµ¢ Ækê‹qÃшµ°$!ý¸5@Ë’xx—³Û.§#6A— ¤lLÐ˧«†ÖrcéÛ U5 ¥QíN,^À÷V'rÂ4J˜a&L¢„Gוƣ³Ì„Éœ0“f› SR s Lõzª0ÊÅâѹÖï¤áõ-®Gú ¾&`„ÇqRhœÑúCè[ó…Aÿ ÒøR¹€(žgB_,ªo>–ÿ#Kwe)ßüPß#€t3TÂ{‚c% F,¼áÝ|ŒTÖ›ñçÅãôÉ …p†¦µõTö½ßhë…Ü Â;ÜÀO‹¶²ÛáÜl¤âFœ¼¼‰^Œª]nai»Ÿ?ê‰[…Ù?Úî‰ÛEzEã²V4.¹[tsÕzmÆ‹ä&k½A}!u£ñ&ÖÍ|*ô">춯î&…`ýߊ= ;÷¾ Í¿ î»ØÍ© HV¦(Š+&E²Ò¦ÈÀ~0÷ùæâm`<Äû_ ¹_^µQ^%”ÇcâºBó¿Q®6BÕ¢®:WE¨Ìêºê&yá}oúgxábh¬Áßæ×Òš¡_“wqÔL½Ç¯œÚ¦P·¿½U$Å£u ,%ï(¼€mú¨ˆ1ýTs›±¿š(AùAê‡ÓÕ™BÌSwQ#¬}fÙ–v³Txf6bw4‰¤HZį@.È£iÛr;nEò­4Ëè>|hƒüP…6b÷r/ O>ŽÂ'©pßCKþÄ.ü‰*?SÍQzŽcΧ ßFá»*8{géÂõ¶¹]½&ûÂÜ®®@öƒuÜ)6àë€<#ak6Z‹‡ú8‚®1Oó6r?nÜéßÎÂâÎ1Scýh6[Ï)s49“4¹7Ù1P«5 ÎÑ qþ€äç¼¢ÎÓ8fR+)ž7+¢ŸWànÊ| ™4ö: “fcP.º4V#7Òx[Ìvqg¸¯…@Íf®OýsŽ­Dà b§&·j¼Ré[ýØ]WÖ(ß׌<¨×Ûµ¢®r§fDO=S÷bl ¡w °Ÿt–‡?¸„fªñ M6iFÕû^šŸøÎåŠÔÈ8¤™#cH…=2Ž€Ÿ»ˆGT€9©qhìºõ^0ŠôÕ“¼À¾ð”–ÒKAƧlªŒn~†á#™Z,KK™Úë9­‹¼ ÅÃ弜.‰Ð%ÿÀ@ tÝ?ÝiÝi§üÌ/ºó&:hç¿„âKÎô¨åýµË E5§ž‘H.²”ú6‹8øµºK¹>7Okî£^ŸdSÈ*b ¯%UÛ½BÖõӥtñwàÚi¨ ÅyÔ wT|„+U|$¿–rñ¿Ì‡RwxˆÏc+Ë~ÿDZÖ%¹¸n¡K]]äZ—Ez]E£\ç2ò·Ó‡ .ÞIÌÿ—Aµ¢~§"]\:Ül§¿ÿ\<º$¾ÅL÷GÏ>öO§oµÓ?¡ô©ôÜ_¢[¸Œöp޹“3 #q—Ëh‰pb\$~ÄcÁöµ±½vâJìg%î3ÍÒå¦Öµ?3m™•1n&þmtð7ãÑ÷ÌŒFfÚR+c‚øX‚õƒË(?CzàÀ‚›¬ƒ”t–’¥“ޏ¨3\¥žéz°gŸH·ðI “ª~¹BžrAÎ_z5%çO»L9éU[ΟE'há}äÜ >·;Á}Ü¥[½¨‰4·Ùêh‘>îv­ÎGï}ÝíZœÓú¹Ûµ6§õw·ki¤åþvÜéVæƒÕÁît sÂ;îtër»îtËrÂp÷Zu#±{„û ­ŠÄ‘îö­ŠÒ£Ü_hUdínߪÈ8Æý…VEÆqnuÔNãÝŠ„‰n4ÈåtƒLr› r9Õ “aR*ÓÚÍ\·9}Ïu³›´Ð»¢ºfMñ­Ð‡õCž5Vž5n¹ÉmnCn!–ÔX­Â5F¨FD7y{YΑ·ÒÇ YËyÎÚæ6ºÊíÔ´¸|±‘Êy›I+Ùå†YÖÕ›,U]‘ûÜE]Eö¯Ã-OOWWxÞùð72þËnG£K£[6»Û}t—v•‡ ¶Ž ۸÷6¬M£ÖÐ]å1ÊÚ¡Cq¹ÊP—±ZvÒªÖI‚úILœrËSPWÞ”ûgÔô7v$DI~êNí?²~ôŸ§ïEËóÇFŸ;\d„ŠDt_V/Ë®Èþ­ؼ-pe.?fxF ~K“?åU·©z]CòÔòOÄ­îDHàÓ‹¦ý.Ó>÷Ç]7û€ÇãÓ˜rŸŸÅÔ6·¼O ïVв¬ÍÀ  êÉ`[/¹VwŒnú}í£G4JÄ<Õ×J¤œýõdD[’oÞB/fûVJXÄ m¹Ô±¬Å«u 4¢@yè»Î»Û»˜¾wÙµ¦Ê®c¤n† ×åpKã+´FÖmu·QŽÒ@üMVw§=®4è°q¥¯ Rw©/9FOÖÛÇÛ¼õpžÑÁÀ‰;ò'}0ýlMC@OÄVÝJº°“yGx”¾MIûacÜú:¬ jÛÓBN…aébÍçt­d¹5Kgc|gQ?Ó ìvÌÒÁnǹ˜2‡çcê\;~Úç᳆É=ÅÃçEsø|jŸÏtyÖ>Ÿf ŸÏxøDíás^—çSŸ@È‹z’À†ÌÝŠŒ!c]¸[K˜ä/ëñªá$œô.lÚ|%4o\™ãe5Á5k¼Œ0ÇËuŒ—[Å*⤠ÔÁ›aÖáçË/Ǻ=/ªîQ¾¾°é½ ú0Þ³{Ûc®ûj°gWÞÓYŠ˜ÎoS­Zbâm¸r4§s.:›Æ”a9ÌSÚ,‡óg3˜QkLé‘#=æÌØr”‡ÖQ›¼¬¸6à}«×ª8Mzc ,ËܱZaMò$YošKæ€a¹£îÀ¶Õœbúþö¾t> g{Œòmyñè‚×3‡~^!Íj¾ùsQU¾<ÿëp™rð%mÕæj̹Ô#yÂåÏ3p°aÒŽË$+¨ü-Ò ™åWZuˆnööêéÊEw[K9®†…fŽužˆ3ºöYÄHØè‰¸òW ʓǜ£`FÝ·]ÛøpĽ“Æ­'czŸå.︗cTïñÄá"w›û’{=é55M{¨ö™#îèwÇÝ$pcöH”ÅIP¶è&”m("ÊŠ3ÚOyÁÓE¦NU稘þ›ÔOÔKüæ¸ÃWÊÆñ¸hõ˜Sv«qIÅUŸ2ÝðÈ«–ÈÂn&e“¼æIä)M£7<<»–7ç~äÝò$‰_<ËÞöÐç;žd†*“4™mNÖwñýž'i—7=¸÷Âç4‰ yˈê6fæ»L¢¹Ã +õ¢ºõ…Í ³Þ '¢Þ+ûz¹‰¡Fôó¦4¦<Óv½”m×ÐБg«—ÂXݨ^_¸dRä^oôĵˆ[ ä rãWÜ+ã˜í¯ÐÒM}À- oÄÍýä<úÉ͘¿¬7{eºKÄmõÒ*š½à]îrn¨_õòÊCÌšÞoVðÔ{ØñœÙR4É£SöÊÿ€óÅå@õÚP}ò˜7â£nÑéÏk®öE7öÊÿ{˜ŠzÃ/RîÍ/ôæ6ßR“ºN9Þ©<å…ÅU||Fº¯7â!®õbz'·yý›¯ã .¼´®XéÍýÛûmò²[œmÅnšïwpϿ浣ð3nÅÄm¯¼á¥uÓõ€¼éµ¦N+LÒçÞ.ò6¡fS¿Д¥nµh’÷)ß…‘‰†‰è§^æåÃDô“@Cþ3Ø+ñaµÕb®¶¾¥«Ï<'myµ´¤»©Èz_ÙχÒÌl€Ï¨ºó¬C¤äÁ¾8ÒQ¢jb-@a:_DuVpu†øL±7Äǽ|ˆOó™µî3øÚÚH¦å®i+Ãq/,Zî†øXŸ¸žÈ¤f4¡ã3ªÛYžßÞM}á¶GŒPÛ#"v)_ô]èQåÓ:Uõ.r¼æºë\Tr¢6@'ûâ¦$ãÝ€)f&9Ô÷ÂÌÂ\gÍcêçU8æ™äãq+¦¬òɾöm±¨ZJiçŸz™/^5ŠÔå¨,Mµ«ˆO´ šR R 5˵>«…Ìuµ[ª¬gVÜK› m°XqXQÔŽ  ß_Ag–ÓÕÄK„ã>SLyi}àcÙäç²Ç©¾·c¦å8 ,µÕI¥õó³lêïǘu ¥GcÈ=ÒéýòLƒ •ÎúŠºÊsi]°8tÑâP«/‰õÛ_²zRY‡¡´/x®û0 yïøäu_‚ù _Ä›…æ¦/½eˆ]~|¼å#IcÙ´ ñÒåŽ*&ïúL aÚ«]ùîûä}_;™à—m¾ˆŸÄò÷öCŠŒ+ ¬Ÿ¿”DoDƒÀàçÕ'Œ×ù ¾ó¶?%¢59Ø_B¹‡iÄÑð:Ì2Š.GQ̧ ~,"rx.£:¼Èqœ˜…ÄñH”ýáÕ¢Ûjá ¾C«œÉþˆ‡å)é1¦@­ù$ §øq%´æÓ€œFoˆºÄþå>îÇsýÖV‰?w6fÅ…~S!e[¥EþŒm3i±´I……ÙÏ› ¤¥vê{a¤•Ô›³áR?‰µe°d/o ¥Ër¿ÙƒÛ¨C—±8ø2™ŸºÄ*¿½Á²Æoñœ²ÖÏ|˜ï7Â/òJêEÑáœü°ëĶn÷q?ûÃlËRD¨­ÂQ~'†C¬þœ‹y‘«™GX9>į$ÉãÑsv‚v˜S‚m5w+äQØäË€<ÎÁÞ‚8Yý{@¹`Ûù_ðó Â%¿¼äÏ0j’Wý‰h÷³oøã©O¬H~hƒ8X;£Ü}¿å/€ Þ÷ó*©.‹šHéMïÆÔú,Ù;«­Q}áÑÓðäõ¦y°Ú™ú¸&ûg±’¢›æ6¦Nøf%I‹7PrPV<\ž$ÕpšdÞõLE«+–ó¶Û;YaÌࢨæ0otÉ!YáFж¨æšKŽÊ‚Ê™? 7 «7¾=6+i¯Û:„Ðoñ»®€W³Ò듲ˆ¹urjg·¬Ç¦eYkÃéYæÂdFw€†¬m8.f)Òq,u€ÙYI{Á‚}Ò9ôÓZ°à缬x²´j&ÉÂù¸Ô0(ÛÎAÌí%Yl^!°„ø{/&ð eò½,¹,‹×9GÐ!³y»«²Rë^•ZØàçº,¨ŒSPï `¨Á 5Ï8ùˆî deÙI)FlÉ`ÄV‹ÛSÙ¨brG×­®R‘;Ó®Ää®,®%>|`~°X·;+9òõf¹ÇæàG×emS“6ë~E¬‹ƒ%oswîÆƒÂöÉÖ˜£Ñœ%f…w¸-¡ÚÞ®¡IÊJðòúp­Vív y §Až´Až4AžÊ’§ÿ È3ȳÈ ä'ùƒü:ä…,sÐeÉKYí]+±£wvàe?Ž¥Tïìì‘îǼ—ioÈÐøìÅÇW³2ÓøÈ隤w¼Þ bYÔ4ܱi¸cÒpŸ÷cJ[–¼ŸBªËÔ•7É6&¤ºó«Ù à†SÒÞ¥H$±‘Û‹Íúd›¸úf#zP»'YPÊæ`ÐîfÆ8(›Æƒ³åà침ô;Ù ÿ¶OÞDt†§>uvw•T¼ï`z{ï7Êl94û/µ@³–äžL5êHP44˜Úd—mœfË Ùf皈<ÃX˜3­ìLÓ™àÙÙlj3'›Õ…¹Ùr¦Upv6M+h;ìl4É9ÙöVP³œ›Í&8…ì„”ÓÙ'Á‚l¾ï87Û´Å9Býy±`«{&rI6%ZQéâÖ¾.o‹`(/gX k'PV˜)Ø Éå-F÷sÌ ¯5¶¶ šÃ¹3ò¹êN»–;¹–{³åÙ¨]üõ‡ “íÎî"÷XUÝ›M‚Uåýx¹È]û,/âÙñD M {J8À¿ ´š€n£ã£‹£6º£Œît¶<ÞÝ B÷±…ît{Ξ!t›½¼wüI¶Å'êy>Äxd§ 3M‹î„Ä9;]Í–Ÿg¡Þ•>ó¼EXësŒèoÑs¥U^W+ûä+¬¸€}s J¡¶+YÀät‘osêab9L[Ä¥_‹wrä;vê “ïæ$¢S;•O‰,°—+=gú—J F昫ŽQ9Å:ú–íãs,>ÏÁ霘BÞµÊÜ9%'uH×$§å°Í“¹äy¦§9¦f"_ý ÖÃ3ë¬óœyv޹h™›M¡hAC³œÇ¯<œççÄ«¦‘.»”*TÿÍê¾ßŒn{Ž*ñu˜n |ã lžñ^ó´Ïˆ—ç$y]¶’‰s;8@¯Üj1î}0ntЭ;]Kyobw+ýͤó³I6;ììfvî6Ù¹/GîËäcœIlMóѰHlýK|L™rl½Í¿1'‚óÄÓ¨~1%&=͹^Aý‡ ‹}aMüÃcÙóÊz ªUG >æE·k ,qM4]âOr„ÀúH¶‰–£ðpÊ‘(ï÷Thæ‘@ {qªâx¶_ƒðÎ|@ŠŽI‚ÏSx÷]0±®ˆN¬áÀ¡Ír*|/5wÒªÜ"xÓÛåfçnšœ¯íŽ¥ÈÍlêëØã†§À×ñu¦ç7š¦¯òýø·7Ë—ß­L–ïy6¢ýJ%m·¬·ÁY¾yþÓ1BÜžÏeãÑuæ9à\œBjæ ‡K…e§°”½¼‹¥B.µ%Ú3»3ËEPt•+R‰~$®8“XML€ “ }—–†Xâs+ †miíÆCæ]ÚéA[ÕH)\‹ï4[O¥.×"Fwq ´ùžWcº(xŒ{DÅãèµ:A]"Qí[žÇ¡öÜÃQ·(ÑÔ¹²ùÊ—o \ ÿ ƒ*“M¾#“ˊhaz»R`G{r™ö¼Æhå»`­³æ“Nr½U+󂸺R_ÁÆÌŒ SSµgA¬É;"¼™%–2}ÊR9?­,<µÌ åÐÔ254­L4PÙ™AÕ£jq®é‡\SÅò«õ¡ êCÔ‡Bî<ÚŽBmÞ­U ! Q½±Èµ– ™ÑÁ•‰Ð;•‚GYR$ókqh­ÖD†Õ:›qôWv ÖŒ>ëŽhõÔqw5ê#…08H½zö JÓò]%5ƒ*©Ä3º;ï@[›®ënÚvv…kDy‘©ùí3ŽÈ‹AÅ©j!TìsÁ~Hq~áøœcNˆÛBÞÆp3êiñãf- O¡wEiWúòŒ¦æ'š®Êû‡d³iÙ¥9Í.1œ-ïß:†+èb CþV® ÏhòrŒBëÍõ¸”É™¨_Ðs‡²1¢ïVö‹m(ã¬nl*yQ#:¤²ÎÛHö÷› p‡3Û\€[š-¶¥@NbÇ[ Ç©4F}c žÛvš:ðœ .Ät!³a¤>Wq¿™ö¹üµ+¾®Ã× j<º¾ hŸgmTám—ˆ6Qò$C3Ù¬ÆC» ¨ÕØ)ÝþÚŽÄ… Âóþ3h:ÓÅv\CÄÇ97/y ~5ªvæœ-ó™î¼Q$ϪÔOãÑ­ÜC;ãÐàq“ ûÚáÝYàè…8‘AµÉçÜ&×U«‡×:®óMBqS•·Ìš=„åê•ÚÑä_I7ù=ΓˆG?(¨Z©P>´þ «õÛT‹Ïõ°ã§¦ì«™ z£¿§!…ßñèú¿¹c ¹hÈK#Ä¥éÁøJåÛZõÊNѪÖ'ª†U:© °ï³°јsÐÇò+7·ä0˜Ã/dî=ŒÅ}‚ñšÕ’Ü—øCŽG7°»Þ8>…6³ mªiŒq. jN§ÿ(3·^êÜD 9¢VLרôÅÜgÀåƒxt[AÞbì h´H£.7?Må‚/P¹Hc»—\Î×Ò–X¿DǨÀÝ«â¥ZÜJ­ÚT`:XZa&ñoútöÍO«ºlƒ¤à$AI”Reòy'6ëe¡Tø9Æ€ø)¬ŽKØÅÖº(O #…ÃÑyº˜M1¼Ò!üŽÅ©É‚ªþðk²¸E“ÅTf&‹%¼¯ýeñ–Òüïr¿Ô:²V¾e…Å{‹£â½ÅAñÞâ˜xoqH¼·8"Þ[ï-އ÷Šõ¦É ·à“L¨"N„‰è/è¤tÀ3HÐŽKIYŸOGS¼ñ5üù6‡ûÙ]€¯ tw‰|PÒÿEG°Çô²êj¦ÃŸÆr®Ãí£jå“ÔYžŽ‡§—u›^æxAÈo"LeÐöz1 |É|xþ½|êå‡Hg7AÛÍÇΠíæcî#òáðæG‹^¾«Äþ…sí fúÆ(H_Ê÷¢øFeûylFY‹ÿ¢òH™üs&¨ü€TUûyëh¦’…ö“P$Å3ò#Ô×íx³I>ÛÎc-V:ß1¢³IÁ¶UÐñ&|Ì%2ãMÊ] õywlÈb°Ýd7#ÔÁþä°UFtÎ`ç˜`°U•U‚ûK8ãcÈ¿ló¿%^–¯ÀK\ôŠ‹/Ý gÿ¿Þl‚ö*_å·ùc¾…€ç…Û.€¯æÏÒ,‹±US=ü©§ M“üÝÔÆþ þ Ôîajg3µ¯¥¨}ÔÒo‰ÿ'ÿ1¶¦©}¿,jßâ·¤öSûŸü¹%MíMj[ljÿ«µìÿ¯0·½q£½rû‹½ýIÍþ–$*ƒIì.>)@3Ö©ïŠêel¨xùHñWx5š‘ïM#›F>–Ïú–˜G!™uòI?-äSDõL Ÿö òY­æsù¾ FJÝ‹@¾BXýu¡^÷KÇÁ<Åôù1«ÌÍ*o6Ë5"Áþ$Ö‰êæG’áÙôav™H„¶•«QÃI6ðreðfðf0s¾®l¸)i•ALÀ;ØF˜4'xާ'lÀ p¤ø€Dx˜Ã€›,ÀMŠçÒ‡¹í(>€4àã6àã&àã&Å'…<)ìòTî”ø Sl!̤øSœH¾b¾b¾bR|MÈk"<ÌcÀ×-À7MŠçÓ‡ùí(¾Í€“iÀ÷lÀ÷LÀ÷LŠÛ„lvy*W§˜€ëPl!̤¸ŸÂñ ƒY´0é£ò0Å‚<46êhTáÁy¸W=8O™†öB¼½&5~‡SßáÔY”Ú,ª¤ôWmv*òÖÂG‚YÄÅ,ÐNÛO3û8^/uöÓ&BK­)57<ÊZ#Þ£5bsÒ°:ÎK¯§tlxåçâ…óJË·UÆæ•¶ˆ)UJmm¥åS«bÛ`÷D~Ö:¦QlMG‡}M¯–}M¯–x,ë¢â±¼‹ÖW ë Ûå`öcy°@¾cÆK/ ½Ž ؼaç5÷oüÚ±Œ7Y…<¡*+E96Wû5BÇŒ*0m¹Wbc =r5''££+£ •Ü½× Ã(¼ÁP.ês5zœ×O%ëºÖÊ<¦)+›h¯¢Å÷&{ÛƒpÂø(BÐ[yT„¿FÒ~4¾ƒÓík§xIúub;ùzxleÊã},I¿†d¬5OÿÅÕù™ ®;]÷Eë¸ZD lç^rüg‚þžIù8ªþŠ˜ÝE{™ÆVç+ôõ×o寢ˆ„ÆËáGŒèÑx4§Þö ~0¹äoEùŽ0©€BôC¼ÔrD†«'_–±ì×ÝÄÛˆs oƒ¼Ñ²º$YÞø­êý=U@Ù×wVºh|U$ѺÊߊë(®E å %FPÆ×ÊZ†r¶€²g@ù'@y-§ÞgƒDÜløobç8ÞØ~‹0xUšQŠ)>á5z>-> jŠËýS|Xd{T\$äC)ïÑÓ µL˜Nßëxs3—ñjùaQ¾º u­Ð=U©Sb‡ ¨Gà²ÜÂ?`ô°Kc;bc;"Ð)ŒØñÄ,µ°lícÛº.¤ú[ØŽÈÓÀv>m|© RâÑ“Àv±ý=> µ]© U°¹kÄ>. 5ذ‘?J1úåâ ˆ4fÏÆ.¤0‡î¨J¿ØÉRšqg>f%Ь&4§æRÍFÍF…ÔCBs¦e,4Ûl4ïÛh¶t‘Û-4§ H1Äåø ÜÄþÐâ@“Pâ?Ÿ­: òÅ£G bG d#^ÄNŠG¯ÄNȃx=S;[ P -Q\î·è’MÖ%ƒA´ÀµÝ ЫZˆ¸¿_¢r°&Ò±ò¹«]WÂ<ÜÏ6Õø±À¼ßP=V5/Å\W]åMåwÿŒ -(CÔY™ÚÖ"žJok½£âÿËm¼­µ†Ç-Fxk»ÃšLÿ¸W‚®U›¥µN¨•?±‚Üÿ„'éŸðýÖî~‚éS£¿kôwR­‹þN®uÓß)µ:ýZëy±EL«õ’D˜^ëûŽ ü¿Ç¡¬¨|1Ѧ"Ðï/’š¹{úä¯à0‘u:¦LÛö'ÞÞìé—¿Ž¸"~¾õqñõˆÿMÈ‹—"n;ÝNwË—#º®§ÓuùJÄc§{Òéùûˆç©¦¿Ù3KFé­½eË?oÄñL«ZüMEÆÌ_ÙÓè‘5Þ²¦U«Ôd-Ò³‘६'þsD·À½Fo&¸1}*eXBÐþ•~dÓD$kjÖ¿Q*Pà¯n&½qYÞ 7Ò›ØÙtMe@½ðž=p’ôŸËüO&(O’þq[@þDo&?ƒn÷´$Cù/³I®[ ÎS*€ã¯ÛLúŸOP¬òàjÐÕIÕκÑ]6 «¿lÜa𠳑ÿêF^ªkx̬uâ1«Ö…ÇìZ7«Õñ˜[ëÁc^­ùµ><ÔúñXX›…Ç¢Úl<¦Öæ Žõ´Ú\ı^\›‡8ÖKjóÇziíCwáæª¶vü¦ã}z4þæá6!w³÷åÊÂì~yrNg•oöÌ—à ¯!ü´›”_Ý ?íBÏÚMªˆÎºŸÎ¨‘®KƒÓ=©ôG°öDFº7•~€ó{IH#Ý—JoâHå>ÙÌéþTúAÎï—‡8=+•~˜ãŸg‘`Gzv*ý(çÏ&!ôœTúqÉ~³gÉvùÙH:%"ù ý´ Qñ'‘‡@õYÛ6s}¹¼òSA oæúŒsùä9¢ÁÊužsùåɲr]ä\Yòa¶r]æ\Ù²EDr¬\’såÈ»”‹;iy¾òkGy©è°Ë6¤âõ+²N1"¹‘¼HŽ94{[?¿2¦Ñ[GsðÔ󇇑’‹1šÇ©ý”ˆßÂÔ_‰dY˜ ÕÄ4©&¦A %ÿT*‰þþ6~=L¿‘SÓh#èñ×ÊCKt ÉÐ.å0ÅÓ´h š¯È ±ÇÐ#ùÇW¦E2ÒÑv£LÄIHsHQ"^ þX%â³àCª ­‚¸¾tfiÎH_Ϥ÷ô!Š¿Eœùªc½Yÿõfý×›õÇcE­†Ý앵Î-ôXUë‚Ä]]ëÞ‹õT­~½ç›…Q]9 ®;ôúЀº‡hžÞFR‰OÃß§— £fgdoø¡n9è³[î&9ûÔO«&U ù!½>±[ðûÞTòWOTM¦Ôýô–ä7’½zP¯ºóXLЫ‹_!yƒ~M¦_¤_Œà B¤Wµ¨$am,’²ðÞ›{ŽÛ«ÿsÞcT¯õµ¾ã‚älÄc•?IsE^5 Pp/·Zï ü%BÛ<‹GÒBS*b+Ÿ¿’ìt…¦V‚ÍšžpqÄÿÄ;bnPŸõh›˜GíÈõ=%¶ùH'踤­-·†Å%ÃGX8ÈI~« ZþÕ ø×Û×7HH;ÍI!¹l!™O=âØæ¥Ù½c.½ß¦rUÓ+É@ìÙƒŸ`Ï}þù‘(â_½̈h¿zzÃeç Ó£9'+èOYñ]Uë¨`Í-ð˜ßQÁcì“ê`zl©Õ`Õ±µÖ9Ž“½® ìïÙ=Q!)ÊÁ¤ä;J’{Ê» t_¤ !1¤1íÃ#º3øõ-ÈLNMÙ¡í7(F²êúw°Ánæq‘4"N:AyÊõu³‰JÄùFOݼƒ>Y c¨DÜFhF¥c~¸˜š‚˜47J#g }¤Šê©g–Ö‡Sqš?]ìÖog¢qêÊÈ5º€t½¸™Ä™‘÷S"rDäLKDö&y®i‘mA‡p¹0L/>Šƒà”ý}œÏ,)z¹^œíÒ£í¤—”U’W³²óò£æ‘ôöÔ‘ô’²nKRGÒ-ÚGÒÛvVúHºŠð…H ù($¬é"¶õQÓ¯ÿŽZYlÅ (–AˆäGi͵¶PòªáQ]sºî äz vOÏ7Õ­æýÇdg£úùåææ¯Šò±³VyB–SêÊ)Ÿ@'ªïvŠŽílD§vŠÎ®”O––&¢F ÝOÿôß  T¯èšÂ<˜—~3.Ÿ ï(][X>î1¾²ÿ![S(ŸEždQIIÕÇßÐà2E~ «ýÑ‹OwÀ•² BZ½JDÇ•\Áp¿›‚û½¸üþ—ÃýA&\š•(G’kü-´áGm/¼;`(7'Ó¨´/X¼º_ÀâkÚ§þ·S}¼˜ Í­,z¹Ÿ[_ÈÙîP6MC¶¾%v¶3Åò«á…E/÷WcCÌ>ѯ$3EæŽMÿ4ß“­ÔÊçðy@WÇsøñ÷q²»ï*”ßFƒVPƒ~P(+qe°~9³‘³šzR$ý ÑK°·¶C ýu˜™6÷-âƒ9^Ç–˜ ¿Ã#Êë´ ©nè½û˜¿­¾ìïÕÿ”ÿî*,?W]¾›¦h^ˆÓðþSøðÓ­Ûá§…*ÿ~%‡ŠèõÎl?ü JžPµÞBöfûÍÜκ}D"¼ú¡òÞQRÞËë£S˾ÖmõC éòÑy•¡ßRú5Q~8V†éøÕþìªv¨H݆ …Í‚§ƒJp¹n0Wg„°¬ŽoüÚ Óá1BÈQ¢=M¿1iRÆ9†7ö`$Ç Ã$)™IQ"iÔH™±yzö=-z,¥ˆš ¢ÞÎ jnQsM¢æ" Æ—EŠÅ¢4QKþW¢µ#jY&QFš¨ jpQ›2ˆÚdµÉòü%D½/hÚOµã%êývD}IÔ­4Q‚¨w2ˆ:AÔ“¨0ür¢HU9”&êÈÿJÔ¡vDÏ$êNš¨“ êÝ ¢ÎguÞ$ê¼ ¥Ñ—Õ"hi”"ªõ%ª¥Q×2‰º&êˆRb &¢ª(wT9@í"JÿµW ‚ûŒ*—ƒ]ëíã©õªÜ¨Æ£Faƒ}òha/^lVã%1£Pn¥Ï‡ ™ÝÛÔ8¾W}Z(ä.J>RhDϺ²°®þ¹…ìM?^h ½jîWÓaóè4âK6âK*âE<ˆ¸ Ê«iÄ×3ßiø.r7Êû”œÌ@Ü'B Œø ¡YˆGÐúV‹G›Û#†ØC6ÂÓF<^K!†Í©œôÅ’ | F•MÈçùF>ûÁzûšü@ àRhÁW¡±¤ Œ¹¿ÂLh‘ÿ,6n`¯zŒz«fT}ærÀÓrôSWì&lû3°ÒŒ’šO]ðšü `¹[3òfÐp=«ñ§E_1ƒ’Ÿƒy%5o+H›Aj½Ó"u°Sv2ÄdahÞImp¦Hë4Iç4ªÎ©ã)R':Û“:Éi’:÷ËËwœ&© œüÉ&u ¼ãR‡X ç¶ã2HÝm“š€Ç^†Øô%\=–&õ„EêI"õ<‘úqšÔÓ_ õŒEªü2À2i‘zÍÉŸlR?©Ô…êàu<“ºG©ý\(9Øž(dOïº0òø6àPW¼êd¡ƒ=ë’8è–#]aù¾Zxñ\T)à/@6¸0`8ÿXÊÿ1åŸÊ?ù÷§òCzLq¡·²?‰i”ÿ埙Ê? ùã©ü¸é¶Ð¤YdѳÄD©³×^å2*’–[P×qAÛèz.cÿÚÀÙ{±yñ&Wz8-æÈ_uì¤å:Ü Ÿ(”ÛñâmÁNe‡}aÞ«t(õÂ1­.)Þfn¬öX¾×WÃè·Åf\Kµ:WtX>$×™?~":½Ç°|hnöÖN.Anñ$8ˆÖ6O<èˆ+”ïÃQæO"´¬Ò I¶‹¾|ùÀCp>´óíñ VßôÔrˆúŸðòÌåà@,×1¹I½ç6?{p9¸ 1Žß++_Þ=ö^Y‹XÇËÊÊWv-£Ÿ»^TÜãØcå¼;öX‹XÕ]ûyåe嫻ǖc£rfIFÄÖ¦ZùŸ]bï‘RB ¼ÂÚ#¤Ä."#cÓrRsþǃä¬é.ºöXQökGÍ B¿¶»òó+Ë~å¨YI¿ÖuWÙc~­¢_ë»kÕ=V#çjúµ¡»ó=ÖÐb²f ýÚØÝõZ‹x;èÆUãAý¬«ÇGeagI7§¨ù„Ï)A\ØÇZ›kÍðË›žsô’ì±Öδ¶Lþ©zm©?++åŸq;°DÑ4çQѱ¾Qߨ"æW8úÙ‡ÖúM”·¾KGO2QXß(û £+}yFUò.´µé*üèóµÔy¼ê~pÆaÕ=AT¯/ã«!EõeÖV^Íú29_¨Äü\~%–£ÄJ^SÖ¹1º¦lx“‘ êêŠ.Ìc¡é¬;uW*ëÈŒ¬ ëÂÅ©9ÿˆ¬ø†ë[3:`ÃöËAQ½¢Ì4‚;$ ùm>Y9X«0T[Q–Œ®¬Œ®ªd òî_ÕÌhޏZÕlj۪VôÌ÷I(óË¢œ¿E@ÂY>º[þ[ÇYÁ^ð¸ûwÊ!/ˆêUeï×,/ŠdÑÛMa¹XÐÀ“Üe‘ ÿIÙ"ª/F§ÒÒB”âúà•Ç«VWjò P-.Ñ|šû¤ \|ïµ.AsØÅˆ€?T¥§^T—×ÓÃ,Àuغ€ÀcË3Ê0DQë”q¨V›­È;¢zeYÂ¤éž J¸¦÷E¢|`p*n-ÉÐëªo=lêÅ´¨+N­µêŽÍØ"¶½ä@‚X çD´PŽ58µvÏ‹®ra›v Qpò¬á"ì÷Ø"û%÷p…OPÖV‚f9R‰è|Ëf”R}ñëÑSeœ:šR©VVríàÇgÍZõz‚ÃNý”ðzj˜ÐzCÈc7‡æ™L/FÍUMNÁÉœ®¤{­í¯œ£Õ¿]n¯ÖUöÊÇ©„8ô}¾"(H ­¯t”_ø5H ®Ê…JÄS~¸6¢M ÝRpp¬E¨¸Øö¤0Yà”Kp6êK)ƒÝPIYä{ rm¬üÿŒ½|Tו?þî+ST@°1I˜q2*F²±Mb)‰ãĉŒIQ²üÜ=d4$!Ç»›uL6ÙýýV0Lo‹^Dï½÷:Iôbz³®À4Ìÿ|Ï}oF`ïÿ³ŸFï½{Ï=çÜ~n9ç$¡-¡.±eTÀb–X /×ÙAÙü\#Í´ê|-o¥C‰;]™–†µãë“õê×ê¬WǤ'ôµºÜ }3A¿VSy 4¶ÂYÄÜÆ^N­8 {͵S~ífï«%wLu?r›·ß-(&˜lŽÀÕ˶L°[gË/p_ðºg¯.÷êlVÖÙh?% {¨üÂVØK6[…ŸÖ½:l¸†Ý­ROÚ­oRgY°ØPË\äš4¶ù‘ïã|–G-ú8T‚Ûi@Ë-Ý^`ÈS8ÍZ˜¼èònóà.J~æ~¦Ë› cÞàâà}ð¾.{ŒQVaïjI®ËkZó,@3øÛ> à Ï+ð8ÒMÇã@Kc´Ák³1ô˜÷Œ5Þã öÚ*'¡å¶Ë‰Êei`5©´idZWkõû÷t‚8åƒÕ¶'²÷ưÉÖ³gaW‹'4­pï£r®+<Š«û­ðX79Ÿž¯œr#rñuÒ¥F<{&œó‰ì—ù*~ØÕ¾«;²¾hhWXå÷”­/bµüµÙPÄYÂ\gÄB3ÙŠ%Ür^ÌŒ•\̹e—2³:cê·m(z¿½ƒj£J¡Ø¡P(p¹3‰$r93ôAndäÊêÒnƒVçó¬¬ç”ÍÙ°Š˜;뉖±ÿL‡ëár]ׄÉú$þ<0Y©\aªLµüwl%YÞþ«³A®“Y¾ž1ùµwFÕÞãì-¤ Ùó” ÙõUOõu5‰Î¾ l1\›ÊÆ&MãšBþö`Ó€Ð}SÙÆÖn©–qÍ¡´‹(ÝE»]škÒœ5˜ø³Ë¯‡­Š]­‰*Sö6c…¢e9,™qšžÇÐq¼›Þß”ýÍñ3pÍWÆcô G‚æŽ^¥4cÍÅØài‰æ;ÔļƒH2ÌÄ´ÇëHl5.ÃîxÚ›`k\RMýD71ÎQS?ÙMgÊŒ}ÓVã êäT4Ì›pÄö€x](äT³# Çð©avOüày «bc‘&„¶<×å6­9&.11¸ØŸ²rZ¨ÆØ1µ«¶Ä”+ÙJ\¨b1)Ze¾$ט!Èj¼NXKßëÍX(@­øq´ &ŸðÂÿOMûlv£´þÙšìß°Ÿ·nb³)7›Á@¬$ ˆºÜbÆ#g` 6)¶Ò×<BJ6 ¬‰š³'ìdpM•²æ¶ƒÈï5í3åÉù5ʳý=)ß6×嘺£Fˆ–(QÔLµj^õoé§MÞl¾nÒôȆ7˜Á·ØXÓ["2ÍÈcãÌu”ø`“ðYðÑÄÖ ›ò°É¦Ÿä-Ö&PK³xBl.Šl)RTì8!;lÂaSP&ÁüiÅŒ2yÖL°xê0Ï›ò¼ {ül0’&©‹fØò·ü™2Ãd]6åe HÀyæ­+&nü4Ç~þ§f¹kÃÞú‚o%ˆbhwA ú±WÍÒOš+³~_˜Á]1”Yé®]ÞC+]‘keQ«qsï±R£¾3!û{wõÒ/ ³t:þeà_&þ5c µ97©*å5hPïmñü0ÙâùaŠ…IÙšj±èiôè÷†»¯Kö¶‚©ïP•l,ÐIè©—XÊjVë%ÙÏJ„FX‹Ê¦zý[äD~ LzãÔÛûö¡5…Ã…Ÿt“-uî핃¬àç­Ã^öF"GXñÈÖ¢¼Vawßô޲xC¿º åI޶Âi kû<ŽA@ý7#ã (öÆäX„À;­0NLMŒG@Fd±†¥òËÏY™HY¨± «À*2ïÏý^Ú\ N‚`˜HîáF±ÊùV8Ýñn› û/¤8Ý-}¡%R¥+Á%C.¶Ãç+œaË0Ë,IùºÛ ¼»á Ñ+WáFÕpFØ ‰®±9\K®°6¹iNpµŽá›e­\v*Þ!SÂJ¼ÜeQÃJvîÙÁß™n{,¹'É_¦Ü«8ÙÀ"ÔÙn™û-eLáLf¤d[,D5“1+ÜŒ³Úlf>®Uô܉su*'°—6ÍZò ¥âœpÓ“‡T2U?Êè~óH_Wwv7rÄ¢›Z @Õ®ÒíEºšÑPC»òkíä`¾9ñ¡ˆ±–þP¶V‹O±òíäM”ÖþÑ_ÑÊÛ±oô"Úiå²üH(/Ôà´ýN;uKi‹}ß‚8ø[F÷D4r÷-¶¦"†á"Æ8îFĶ\eÙ’"Æ9:Rãp#Þ¼ÛÉ Xnç}öö€YˆÄ‹á;»¿m3^°GCkÛ–\j¯‰eChw¤Ð®qЮÑå: %¸õ@»3öˆ+€êu4:¿ëu¶YsX—G ]c»XÉÞ"-²¯ˆçÈc*ˆ>;Ê:r‡÷ª:Zdza~WL>k‡ÛÒ -j/ÙÞÞöªsJZ´:ŽÅK>o§Sª«:¸aN ÀˆZè÷u¾Äë]‡ žñ’ýE°%µ;×pY®+Ìýpæª| ^J9œµKÞ#é1,¬CÅ}xؘhÈ‘F0‘ép_’È•‰Ì:9ŠœÄÆqú…ÞŽ4æË±Dñ {/Ýàû¨OMH2REB‚ú š"ªéC¶ãÄ|y‰…ê혓 Z%ßæˆNo °Hëd!ö}32¢ l—WN¥¯XÙhCN£—DÙ˜Vr:½DË>bå„”œëÎ6XÅr×ëcÈôÃ.©­ càf ,Êð‘È7±Â°=œ¬0`„-r½]l8*NÓö1šç´ÁÚ`ÈMFÌVíÙbDKï¶Ãª9†t4Æg x'ˆêŽr¯Á&÷çšì’„ÐpÐ0h‘ f’ôÉh®Eõuƒëë<×W"«§Öά1{^ÕÚEC^lZÚ—ŒDü±Å(Õ%oÒÀDÆËöѺô«õÊKÔ° /U´> ›ò†]µ7SU{«IÕ~ñPv´+ð¾!ïÑÚyœmÞøK#8NÄJÆ ‰шYi†Þ–=Ì(w‘D¼äZ¾ÉuL‹ÙTÕ±WöX.Lì®æìO4íš›hrž'R2ã¡D¦²`6ÙŒÓO±;Ådvc4ÅáþN£åi&õ£™fpb‡xÉÄ¢ÐjõLU›Q¶“¦JÍφÒÐçãò8^‡WÁœÞª:]kgPÿ›C´æØ´æ¦hÍkBk>h-2ÑOã|jó$ò°“óðqXÛ©ò°Û”»ÍXÉÂç4œÄì1iP¤At/²žàÆæCªcœ*ö'í˜)O˜ÜfK?'äIÀÈuQ y pý-[E½?5Ž•Ï <îdèx|ÌÀãè‹fK±PÎôˆÅòC ú’ìOy(náÔòÃÀ7×Á7W᛫ð‘H¿€1ÀêÀJAâ:¥«ËÕ´Óñ½Ó’»$ìÃnH èù'–]îz€©=_ajïW™Ú÷U¦¢¨š™¢jŠ©3¹MÔ‰±ZžMž;_„VL­-}"éû^;„¡KŸc©V ßçsaœÀÅX`€é-J¬ã¤-ŸíÍÀïõÁ´î¿lG@sÿ'“—h.penmÑxµ›/°ÛÕ„³ínÆxëÍÞuÑ£÷»íÝLþߌÿ?Âá¦\éþQ$Þ5Ø&Çx>zx\zM/äÇ ïšr2½òîr£÷»–œJvó-9]EñDk³í¼ë–3½+"¬êÞïzä,ÁLxålõ’&kè¥P¼›.ÓK=ùFê‹`倠–Ьbì‡M>´Ô…ŒФ V»É•‚»ß»r• þG1Ü¿EÓÝzªGØÆ&øDß–&ø®ãHÛÁ·í+øvª¢cd¿‹ã|y•·7,Ê÷âvAö‰\zs6t«.<÷šÜ¯RM5Ó q¤áüGpÒÔÚi®©4u§9¬¸äc½w¡Ê­ª6ëŸy×)eú5+¹þ”P®_ZBj:Ñ${•¯Ë“Éìz {ŒñÏÍ6üQ Áü¿ÌÖ“q÷˜³ÙâIÖM´¹½Ð$‡ŸaÜfnGùln³pAö2§ z4²ÿ œ§³£ï+ÉÀh*ðj20– ü4O6$È^Üž®5áé& æi¼ÃM ÉR¿í¤¹Ó¤Ôov£yƒÓ O¦¹Çi²—SšûªÓì ¨Ôí ‚ ¨ÒÑŒm]3Zàd…šý£4©PœP?j»ä½u›‡ôƒ^—}tæ!ž¬ù~ºª\;qË<13é&éÌÎWjïT{ƒ™ŒÚ•ÄJew”Cm ˜8KÍi–¢,ÝÿÝ,š¥Ô[ š¥ì‘ [ŽÕ›”½r=EKsàhhs…·º)sÕQ ªvêÄY}á°u fõT¤È.¼Ýó6M}ÝQ_ÓÕ×çêk†úúB}ÍT_wÕ×,=k;ðÎÞLàoSh!(È{ r¡ž5ËßËUü—*~…úº¯¾VêYÿ èuI~׫øÊ Žß g•"~+â›!~›Šï¡â·«¯*õµC}õT_;ÕW/õµK}õV_»Õ×êkúÚ௽꫊ۧgíE‹K8Íç€þ@³¯ÕjöuªÂ³Fc[”«f½Iºª °ÕVùÀ€Šò]õK;Pdý’÷QT¿´uÜÊ¡9[õK;Ðà{ž›uÕ6ì@6íË, BÀòXßètÿ¾uûÞýß~yÿ_ÞŸùåý_Þ§ yl5§_::ÎFìïÔÇŸ¡ '³Çšô•¯Ëã*³“}å„ݺOÓ3ïÝ–òŒjåÙìÛƒ:kúêv×ÉFO‰b' 4†ã<éÅåR‹:«Œœánµ1Ù­Zhó^EpË`­ÁaM6a­o…lT¬}˜¬‡k6k7™µVò–@ZË;ŠÇæÌàh0ø…¿m3©Æóo‹÷Þ}DÞŽVÙ¿bÝ!NõH@ŸŒ˜ûê³5¥M­~WêkJ@4Ç9s|·æ1¢µ¬2˜ öö‘JÌ)û(…VÌÚCÙÿ=e#"2­%Ê`a—Á`ã2b?5˜r€ið"Yg éè 2q~j*I§É¦ñ–à4 ŠZ=|P*³-4mK`£D#+ä…¨¼Ò'ÇbG¦!•ÏE0ý¿ÄD1ð­x]îŸp0íeÌ*S®áøX«ÔE„àl£t¶Au ª|¸b0Ë(E![@ 1E ®›¨."p-×4`:Œ"•ðS~Á ŠÆ]¢ñ¥ÉŽ- TшJKVZvŽFUÈVìUH‚­[«¬Ôºµ·åpÖÚV½}²ŸåpÖ›@×SœM±ˆ³iš,qöY*ë5–õ ;L¯Øšg½$$ ,>>¹$I`)ÜHø nZhúDàf*ëw­TÖïZòKQ4ÞÓ…N•õѲ—+•õÞ®TÖûºÎú»ˆ³þ>9ÐåpÆM·Rœ- õëR g·s•™9ŠXá²³¾ÂŪXù ”¨ìƵÖe7®u?c*äz—j\}rÈÜI‘92'ˆÌ`ùy1Iæ’Cæ²CfCGyÅ&3Ø'¯‚Ì)2ýÝDf ; 2wSd†¹m2ÃÜrŽ©†ùä(·Cf´Û&3Æm“ÙÜQŽu+2C}rΡî¥È,™•DfÈ|™"³Þ!³Þ-7‚ÌHêI2[2[2Û:Êm6™>¹dî§Èœ™óDf4ÈTæ%É\uÈ\uËã“I2×2×2c+äg6™Ñ>ydzä%ÉŒfÇ8O42dªRdª=6™jœì!2ã|rªÇ!3Íc“™î±Éìì(gx™±>9ê=ó`i° ؃ÌR²4¸ÜFzøÊ—r%^ùÊã†\…×!¾ò}ЉF†ùʇS«ÃëH_ù(Ÿ\‹×1¾òƒ†\‡×q¾òñ>¹”zå)S„D)áðð°)ÂZ›"<䑵ž”)ÂCž¯5ExØó¿0ExÄï(ylS„'Ùaï<ƒzõHžÎ0“^×ÎyxCâ‚GžóäÕÊ žWx÷ü•ö_Òëk?_÷liWú`‘¼è›”/ðx <ÞñD1×ÀIÎyŽ¥Dâï_¿b)qïÙ¬eîÙwvÞÿdY£o<Ö5Ž«¿¶=•üºAìí(~ÍžJ~ˆßA´èŒöï–ÿ'/Ÿâ“¯D囚ÉWa~"OÙ À§6ñ×h¤-¯ži؈ÿfWàßÄ¡"Á&4ª}ï×ÉÄâ-¡áô_„ºÚ'ÿo´ðˆ++ê3äÃZCž:ƒ% 0kÞÈ$ ȨŠˆÑÎþíhÁÈÇ (Ø_ëä8Aø[³n˜äÃÑoáºïÙ>f3)¶vA42$§H¬pH¬P$V èðå`µCb-HLöa?¹poG›Ä’ç¢þ0ífLË m·Â´›÷·ôÝ´z‚1…ÂOžNzÜ;¡·éɨˆ'pTÅg 1¶^çlãÚÁ«Má?Ä6þÇ>Ä ê‡rÕëáªç³þŸ7ˆÃ¿Õ à õxãø ù*•Ãë¡S¸ (ßèrŠm!œ*oQ,äáìw¬èŸXW•„&|4ÑЩ¶åk|²ÚË;Ζ¥ÿLSYáÉ7Õdö/¡[ùÊ%ò–Ú¿±«õ¿È£@HSµò/ðbŽCù…Å#ŸE&žÙ¤Çc­/`ô7”ÓmUN-ØI¿Œ B rŒâù<ÒÚµJLE­§êš‹Z™§NÙ)âŒS«g„<‡Ê›ë“çQ´£ò°ÇÙ0É+ó}¡pJ?:gµ?E\Og7¸§.{ÃYWû>åó}Ðg Ç½È fó½âpÜ‹‡ý°];&Åb5®LÖ£‘…`qlŠÅ™‰™ºœ‹ }²‰Ç¥oCâ”xO%Þç$Þ§Ã*l¬|‘Oí”J| ‰¯Pâ%H<3çCÄ5'ñ5WÞc¡EŸò%4×ÁÄ«—cH˜^§¨O4l œµÇÊ—ùä$,EªS‰W"ñjJ¼‰'¥oto4äf$^á£å\ð¥Câ”xOI±~ÖI|vÐmÖWùä ˜šBiŸýv­‚i)êýù¸¿I‚:Q§=²ïô<“Ì  RO£Ô3|- ?ÃŒïв9 :Ýzù ü`EøÊŒÜ~J΂1ß_›C¯3U²y&›é“ó9’*Ù˜†PÉÓë,f1ˆõM“ÍòÉe°21Ý'—ƒÑy¸V³Ÿšöµ(-]zýJà1¡Bšò€Õ>ÛÀ¤ØÇç0A¿ÐÏ" E²žˆÅ݃|Á²H¢à„ >†Cô >Á—¢ŽÓGéFŸ€iyÒŒw·Êþ9L̆Olħâ•„á Ÿ±ŸUˆ|±)âK@¼É'ädlf“Œõ¶ìŒáìØGu…ÞÛ¢…ÁC`Åp}•é$‘ü€ÊÁ d)úƒ)¸V³šÐn5ÉØH롌& £mÄcbä`,µSˆ<±)â-;c“°¶˜•‡{C8c3œŒÍ°ä,+6JùߎEzz”°2ÛÊëHkD>õ°0“nDðÍP‹µÔŠ…Æàî.ÜÇh4FX:`eYA¼®pÉ•–&·dûw ÍιW:|m¤’žT!6[r³Šú#+1nÁk@+[é“[‘µÍ”µm‹#h;2Y“§×189¸öáÊjÔÏà1ÍÉS–HÓþ¸sL?ÜàûÊgi!u$¶Pš‹>d¦9>$.[ÑÒ­>’¼¬(ÂËçøä§À:—ç¬F._¬Ñòêñ]uyVö¡u™oqöŸ1-Ý~[ôwÉ~®hÐ+ñ‰Èç™å³}rAó€N‹¯`¬$( o¿]²(Mt¯c‹³}¬›§|ÏöA=O5•xw¶x8‹¡y>ù¡‹:jOu½$GÒ}ÞÅìl|4Üç•ìóŠÈ~/HŽQX["õ8;õxز ÔQêjW,Òè©l_K‹ÅX‹çhnœâŠú‘r*žÍwFçñиUGÖòÑ˵|ga¹K.!Ó}Êé+ZºÍ£É•.”fR:]@Ò)°a~cÍ‚‹³;ðz1x9#t9#2'¿Óå ”´tŒ¤ìJ­ƒ¯BdáHa³ ¦¢œçEL[؆ƒÄžw}ÚÀòª/»?¯\ª¾±¼¥’Ì+›baU‹r?Ÿiß žÏD@ÉùL¹é¯Q®ºÙDÇ<c¥Ð1î&pü:ÏIRv!“ÀRNwLºïVBÊéŽy¹2R.Á?r¿„럜<ê¡çúÀ ÷Çîxä´;ò‰b­}ŸÒ=n!«± ]3Y—¹Ÿ­ÅrwƒÛi6èžÝÁ0s¨Ô²=éXNGj|¶†¥nö¯®ƒA†¥ž¶ô{…“+J§é´¼Ž"°tõýncñnúZíã•Ôž&I?~Áœv/A,Uûš@|ô"‚"Æ8º«¡ÝYO0!z¨Ëèès¾‹ÍÔ!Ó ó”}Êóqnÿ@;î–Ÿ¸c¡—³|Ú|)Vò’(Ý•FÍÈ“çÜì´Pžw³—Aö6r¸å™Y–«GÝwó¡üú|\»ÛbAO÷É®ž¼®Þü®iùÐy®kF~×Ì|h‡t€rȔҪh…Ú÷×¢¯¦_õþ˜´5Ðcù›æ z¬xÓì‘==Ü\¶X‹¹8zy‚[x -Ùb‰ÈV«w-_…þÀºûHdû½ke_O ï;ž¨¡á΃âˆìN°àýbpò»Î‚=û=¨ÒìtƒFÓ)®Duj…ûczL«ðÌöÈ‘ OÄûp¦ähOØÝÝnÇcèˆÕ(/íãw«©ø¾MßÕp4 _wš‡ßŸÙvŠO‚±Í±æ²æÎœäwuØšß½«WÎõ„½Ù— ãÔøºw>åcÈÓxä|OèhX_ ^Òå"B‰[þ‹m¢zµÉff‰Íœ>‰ý4tÑÖ$ —×{&lpÐL"*Pg[S¼lØj†ÖµÍ¶“câe§'iª½ÜxïöI¾_ëÃ=üÆ"0¹'N+k,’{=MûÝ>OªkDß*Œ¿Å=c?ÃN}Î~ЬìÓ"¡•u$¯ÿÚä¿6¹<¢ZÎ\‹JŠ+&Ýí¸ª¤TeÌ̪@?BÌç(WTàÙ&YÅRðÜÃ;ÿgä,¡8»øõœ5zRãÌMOÒÊ=(¹Õ„N:ÑÉbbT™ˆ¼óÕª¯Ïj‡¶Óûùô{Ôv¦Wd|àm3*2‡yáõªÙ(¯¼çI±èÓ²ÒlÎ(i/ à¥Ã)ToœÏMª¼‰^Ù3 G‚ß#\(xíxX­ïãULõó&z†çóÞ€N ¡ÓôÂIµ!» öB8‡y킇ûáÞ° ç ®fFxîp3Ô†å vH„Mån©¹í0n^²ù;‚ÃÆ¨°‹nM…o²ÃÇzÃÍ•C·qx‹³O¯ L•0²ã«‰°¿²˜e¶<—Àâ wu<Û®öÊ5^{š›šf×z“òÇ:ojÆÝàåÑÝr3³þX4rˆ¥}(òÜ½Ý [#©Z¨“;¼qú‘æi¹“RôñeNs17ǽ˜.XzJx£¥ûH8Η0秘óã^[äûò/#|œ“3^yÖûUIê\*'ç½IIJ~Ê”ù€«Á›®©üáFügœ?7o<”UZd=‡æ©prý…W~\ÏIæú.åú®ë{*׸zÝ# Ó!gµ*-ZºŸ²Ú3 Á¼M¶…Å¡!iÈj•PY–Æ‚ÓÒlZD¥aM˯£Ò8ÍÐ!n?¥MM“ãÓ¾vÎÀ€ôPsîÄ4žsÁÊä´Ð•vÜ9×9- ¢Ìõï±(Ã+ñ4Źþ=dª„väÌ4.ÏH¥»ìZ‘œ¥¾Ê®Éš4,¯ õ@â_î\4óÒä¼4;™-÷ÌO{HîÙGrÏÂ4¶‰ÓÅi4£‘å,6.á/ÎòÒ4´f.—?µBAA¸\Ò\–gz-×y.Í;vivÅôùœv'‘à±Î«ã1³ÂÀcôÛ&ÿÀº—Æ]÷ÓP´î¾éò^ZðTÛN§Új•§ÚÒ¼|?-lñžY%ôí\e! Gº2žù¬ˆirËžÅ%ºN¯ô°‹äȰåH‘²ë­}¿Ôô%û¥£"UEà~×€tTDcª"h–˜¦‰µ0o.TÂz¥ÔŽ©ÂU hÄCÓIà»1sDzØÌÆ€;Š(Û‚áÔ,]ŽÆgô-@ð5޾beÚÊÒ£aâ)(ž(=GÃËTzUûyËópã| ÷Ô•éªÀë¨ùÖ³·2%)V§Ë5éMZY.ÎÉÒjeur}zúUŒþ»ÜÒí½‚;éònz ¾ 弄^o¥›Z± 7O S¥®Î³,ËÕ‹‹¬W†m̳W+lâÑ÷×:³+Œ¾²oF°C@k¯&2SöÏ€;F5…™rpF‚i É`#rðxÀšT³äÐŒ8Ám²á†gŸäø°Én•£ŽNOBh ¯`fR†½^œ”!§dDƒíYc½½àݩث_›§;û˜5pM†œ›AKÅ3i 7pëRH—:pK3äò‡‘®ðúÒõðú ¹± ÒM€Û'XLjàv:p;3äž n+p¡¸/C-Ÿ÷g¨ås4C-Ÿc¼|–  ÙÈhx+õ°ƒæp†<šÁ­TÌ&fé—€9ïÀœÏ3 ¨i°0%pÛ¾”Áój¦„˩إ>Vzº’¡¦¢«À¹9E÷†ƒóF†¼•¡ÚämÀlIÁÜs`îeÈû6Le&ÁlM­Ô÷ƒ7›­ ÅÑÊ^nY@·C[ó,ÓíÙ¨£‘LpÎd&è b^…˜­£Éè5º¬Fö€FU뤒aD‡fÍ0rMÖíº_Õ¨Îi ø¸OUjSàº]Óà”+s¶®|*¾_'kì2Œ«¬—s“8Ùˆ£ ²ÇAŸ]X .ŸIvi%T£A‘,ØÑtŒ¡x–¨’;æ{ <—ªÐ㾊rùWŠre²(W¡(w¡[“ˆð4Êò¥à½d·^C¿½éø½> §æß*?ì :øîÿñØ|OžN“ÌËó+ä÷ØOS±ö½±åÇ‚þ/}J§ÿ5?7¾‡èâh‚ºü Kí“?ŽÆË?ñÉçaHõ´Oþ$U~ÖÇþ öÚgS”¤ 玽¨sÁÙÔ¾™(vöITU\Ú‡?ͺ<Ç‘QmìYŒ!±+ý½>rÎ.# ƒõyУd«¯':k…r0¯‰åÓå e‡ò 4 x,Ø«Xi 0¾U~Ň0 :LíÏ0ßüêm”“Å3]NúééÊggýû]Î8æHÏà¶ŠñÃñIg³¤Ë¹‚àóž×ÊÎÁDjŽõË.çÀóÐú<’½ÍÇW8WYÎ:WYÎòU–³¸ÊrWYŽæAô1@FÀÑVZD–Ç"Ã3c‘‘™hÜÇò ÿ7]ÈpÛË«ÏÃåàý¿×þ£AŒ/ÿ *ôÿl«*Œÿ‚B½ùÿäÿ ^*ˆ…zG>(.¹T ¿×Õ’ÿ¶Z3œµô±€F ieÞ¬J{‹x^^§ÞÂè({ 'eŸdÊD2iß’ö㤹vÒɤ}“I¥’y é‡*i®J:<™´_2éˆTÒQ$­¶“ŽÃW¡°ù×´ãyÐ-EqÍàÑF‚¢Al|Cà1ë9}–³D,^r÷)ñ^½¬ ¾¾ÍvSkÕê{®Ht” Dà>á=‘G3’÷¬ÄkX½°ž¯¯Ð×°váŸß5ðÐß5ÕÃb->4 ÜøçIi¢¥ikˆ—[­ÄZù@½ïÏ4û„vê…=ß,‰}G”üY!Í@Y?‚V^‚•üL¥”·Ý ]õ•ÒJf#N¿ó«é¿ESè^žz¡l€©·¥Ð¼<ù‚UÖ¿C+Bõ/ß4CÁT檺º³§p‡]í(;4AÙºt.Ïkåf—«ðyÀZxvÞ{£U+öŸÊ9—ÇøéÉ Ûêvñ¥‚8% Há–Ÿð“ÍpÊ3 bÀã qΆ8oãhÇ“"Cô}¼U–­G*W¥gЬHM‚5&͇JfhlrzPK2ù¬ÛÕâ;4.»=.*$H§¿TRÇuñ’øí;ÿÝ Ï€bMèÚÀbMÏÒkÆŸµÁÅš©kCŠ5K×>,Ö\BZ¬¹ mX±æ1´“yʺ05’* í½hÀnð±‰éÞ$ÛÚ~ÂpK p>Ÿƒ;CЉ,_x\›Hm¤ïãÞÏèÕ,_s_î]ÏxÝ“çúŒ¦èªËõ®‡[/9Uqð4]ub ÆÁçt=Îû¶3tÕËÓ,=¥ç<—ú7Ð_¢ÛCÐ'[*Xçyk…±B‡zó…‚XÉ…Ük]¡‡N$Ðj,Vj›-°ã³ZW#!‡®a˜°YÖ¿X®#ˆx@à•mÉœÎÓ½¦µB€òNmÑYlP”YØ©XØ©XØ£XØ«C™9ÅÂÞXØGü-ؤt2ã°û˜•ÀÝ3"\Ñ¿ø šÙwDwجêêÁy›;‚íØ¬h­¾ ÑÏzÜ-ÎSÛ€ù̓:†!ö)qˆÉ1¦#¬ί 眢;§ø>§ø¾¨ø¾¤Ë‹Mù¾ôßWˆ?ªRlÒ£5T1g¹bÞö[ŽÐ±­B»£cè_è4­*-™/ }BȦä{z,x± ^r±@°Ê,Šœ°E‘JÖJ9—çnaZ÷,Àj9½ì0guõÂg&ª##¯k¦¿w×f˜j´Ú§À£ïã:§ <¶W˜x|ò¸…ÇÙ  ;­Ü# òÌ0PÞ™°¨:;_”w’£Œ°§…2¦C6O ›ª¨± 4ì¡&“õ[¶ö`f¬eãûC3ãÉ€jŒÎLØ–©'ç”&8åLƒJª%ìA½¨êHƒÚ4ugåi ¹¾Ãž×5].6Âé¼¥°Ä[(¦,6Øx¦kúrC.‡…Óæá´ª®Y8‘ó†³ÂÍÑ®2`’6#”Õ ä*ƒå°åƳYÍ[¢êÈò4—ë°wT{˜¶|"ìêŽë©r«:W+»õ´Ü†·xÙÐL¹o‰²ÑÐd »è½äœ[ÝæÚEߌ~?aªrš“;ôùS5£ªì•Yèd‡ÈÒïvÏváìcGEFÌ1#ìfWqJFÿBË##ŠýÐ_b[U4+Qû†U•à€¾©€W’ ÂèÎ*Žþ€úPpúZ#'J}ú«:uïš)ëpf‹~l³6t^5‚ÿ@ñí©È„A˜¼È’Þ£¶0™&ÏwOÁ( Õ¦U%£² z¾¬ujG_¿EЯpMù7´”½í“¿Žûƒc³áŸ•Î@3ì@vŽÂxÃèâò;>ù ‡ 5 þ…O¾Îáz3Ì›oP¸^²¦ƒ¾½ÏŠò{>ù&ñr™s™º`yß—–w0]IE`uÏËù/q5± [(â+­¥"Ž#â$EÜFDC²Ð(êñà»ÐFQ¡Ýò!Œ½¢r¡}ݦe#OŸíãÞèQ‚•ü}Ÿü%ž•~ùLÔôðËb”Üá1•YiØnÄÉ;ÑH˜ù¿Îÿ,‚{*Ãn­µžð]ÿŒè)HʘÒìCï÷}ñXÙØbåÌò³TÒ8éè—´TÒ`"•t½WúUÒÉHzƒ'óבt'­}Fƒ§çÙ­Å&Hz ‹Œ-Æši³ˆ³¹EÄ;ÊmŒ Q|Mi;¶¯G@â§$Xt$ùÙºÉÞ##Ê_À1å/ภ¡ ,*åÀãìñ¸cx’ƒ„2ƶÌO‰ÜŽÏ4-ôÃ}·’5H4rƒãìM5X)†¼ýÀ®TÓ¼“§¬¨…ˆ^ô ­Oñ¶s¸iMînSp›àx&ðykü^ƒU_?bØi+“yê«Kµ¥"ÒåjAWùUZ]謿Óåӂ‹Ë?Åòë.Ÿ©U‹ÆÚ Z¢°Oò—µ~pÆý˜À£®BïÇ‘‹DT +å}ý°ÿGMj°ˆ·hÉ«ˆÓ}^ƒ8*îSY\'‡Âlß?-Vbløf¤ˆ…jl+_£E}ʇúùž ô=J>*Öʇû©Å$øæDµ Eòp4¯t]CNA{¹gï¸/Ÿ¢Iª¢¨ç/íÛàq“spä í¦À6N¬| _ÞAâû©Ä# kŽ"‘r0Wæ'¤Û‰?Ò!^ÆÊû•úùÉÄ0uƒ=ÍÈ$®âÄm±š¿¬­Öa¿?V>ÄOBt°Ri£H§´"m/NûDÔ:{ŵ:,ÆÊ?ô“(õ—ó“O»ùPr(,¶d!æÇuBµ‰ø¡c=$Y‰½Úý%;, ©¯1 òqòÿw`¸Á;¼Jïñd£˜mz¡W‡VE˜c†D 3}¡wxC«Ô? ˆ’‘D§^)å]=¬¡•düUÑ©FèÄ0_ƪ4£ <ô„6qÑ SD.ˆos @`”F±”Ä3²Ûûë÷C[ª/g·@gtƒúYI|.¿G&·-5Î^ú®nÛFn ·ûä<8PI Aþû1ÊPB_Š ‘¡„2ä‡úK¦´ÕX ÍߺPùP²šÅÍ~—¡J«–u‘dö“ø=2±-JQƒ‡¸ ªn›]¡ŠP;dÀlXÝîÃýâ4f–>Oÿ¾FÝé®CÂCorÚªz¬Ü¼‰øw˜ä#ÙeWAK$8¦`Ÿð ½OxÚÀH4€[S8þŒU*NjŸlŽ<7SÙŒ•ìõŠîYÎ}4m`>6±–ëHÔÃtv±>zLëuêÇD_Sö4c~ÿz™y¡ «eÛÆèW²µ=ÉÒÌÕ@D1£‘3ºÓ&cüN¢æ£5?´ãF)KÄ*’K`(’WѼS7’it:£k1ükBe@Çè Š Þ*ãí¸$|0•t¢Šn™£ Ê/jKÿ£ù59ÉŒáÙ„Öd$˜®²ÛŸ¦šþ~D2®ˆšebsr·“kÜN¶˜láóñªzv ³…Šðe±þ×¾¦o‡ñ>”»2ˆÁ0ßÁ¶Kl[4qS•è„b’?ç€s™0éµ£¬MÆTÕË:3Aƒz3Ñ:\fO³ Þ_ÑÊ&ËS&^UüÄŒÛiO§ÒžAÚKvI í~Wi¯ªò ´Ÿ&Ó6¤ÒJ¤½Á¼iÚà|#Ír 4÷þÊ:ºW\=Xy¹ `GpßOظà¡"} Æ zÌÿ£9ƒí [3Ùºk–…Kî9ô¸ñ–g®½XIeº€eAVí­h¤ŸŸwŸÐäËinü9ÒrÚ{še¡èF©V"G[‰øœQ¸"/ÇZ¹„ì#+ŽLa¢šG¼t”_ê˜lÅ|u}Šõ’œêDÉ–òþËRfZ¶W¬“›Ù?eý ¶ÇÍþ–ÂJµ›J¥!—YaOá².ʇ-9–[aonéÇÅ‚ÒØÆá¯aµBÀ¾@Ö>€`ÝCÖ‚Xniu±N‰l ð²šCòaµµ†k%fq—îjæÃ(ÕGÌbuؘª=^6ŽÒ¾IY×qÁ´Å¢í ”6&ø…ZYÀMx!­Pu§i£Smc0,sŒÉ7©mÜaµ¯'Ù6NW}=NÛx¨Q­Ð ´û÷¬—D¢¯Gö÷Ø•oÊôúÂhÔÏC<ö)×Ò‡e_òg v˜ÇÂtÔÒóÖÒ¤4ìR÷·ÄÌ9Êc¡l0N½ ó ^VØõ2Γ,U]Ž÷°ÏÔOá'Êì訹fréQêº*=mÞb*¼4m ÞØ|e±24ÅcÏÁS<쓘jGù½h*§bi`º'% Ì@iËÇ튚9Ûä?ašãÁE±ZHIÑ`Ç *,„l/ñ𽋾~QdÙG$/-óÄ¡%œMœ³Ï&V€ìø|ÃÍ£‰îZ¦[oND|­²‚²–yÐ7xäê: áÊ* T V.ç*ŒM¹É“ r„Šk34ûmÏÆ1®*öõêIØrÄ$dh'¡ä› \K3ìZÚ?ÊÇFÖãѧÁâÁ¥ÅM®iŽÅFÖ}¬ ùÿ“ÑÚ‰ù¦×復7ž¯ÀF$-9þ OLÅÂ#ï{?£õ bæËq/ë}xËÀãB…Ù‡7ý¬!¼肳Ջî¡èú‹hÖÍ_6ä@lUûå ì`MòË"ÖÝqÙßß=ûw|ÆÞ¥¿ÿU­¼¿_ŽfŸ6cû´!~ä8ÁÌe}rÉxêï§"ö„]‘eÅeËŠ):ìJñ¸ßú( EÜ&g"½x Œ’ñUˆI)rSDÜ!75EnšMî 7ã+äfrˆú¶M‡âᬯNkÊ×bâk®ˆæ–OöËyØCû˜jÆí~ åu™2¿}pBojnç»+B}GK«ŸòSªNÂU7…kê[Áñݬjêƒnï?€ÿ_¨¥6p¹B;%äi’ö¦Ð|êáƒo¼w„Hµ’)Ò¹w:øÛÃÁùò< Ë4Oò™¦nŒ½ðq~ù?È]W(5mR¾Ð]î–»ãl%Þò.Ø›œÊþ(ýÁìóhÎÙ­«o•­±úƒÙOÁÓÕ·‚M¾)©ìÔì_©Ðê|ilªý!üË«_;=«pö‡é_;¢ŸÆX£/LÎ/ŸÊÙŸ¨PjÚÔTö§:›¡Sa9ž’1‘¸×qî<ÕÂ*¡=ÐxL[¨7ˆ«¸ã5Nö³þÑ|=jl‹Ë]Ø^±y„‹ÄëðŒÉ¯bÒ§ú ].ÃA-®ÐíX,KWòYtÃÕ#Îpqh•%bvã]©cÔ9i:k9ûIB“¡n Ô@ƒœ.×ëqfpƒMp“nC©A)âØÛ••Û”äV"I!T4ã;hñ†AÅÂff!j³°KÆ-ßwëÑ„Ðö4û]Ói¤cˆ÷º6“Ÿà2QsÞDjkŸÈ:#h¬ Î"€póÈŠâN³„à2’g M¸Ÿª}"6577ãM¤‹ i Âá ‡~†Mÿ7ì}Úö‹×ŒÆ_&ö4»SÑ¢Q@¡gv8ƒ‰…3;õÌÖ¹2ht g…³™\ƒCn‘»%¢ÁkÄJ§kB”ÏôËÛGØY”½£â²8n–º±²~hÀNZ§;>Ý/ïÓÈ;ÝÏÖs¢‘åªô*u„±æSO=–=MÝŠÿL+Ÿæç»@üeD¢ù¸~YégUÏzp•'ØÑP¨Yår'Êúyyæ›e}½<„Ò»UÖß e¼»ÊxyH¥wwÙ`/Ÿôî)ä…N½—ñò¸I¯Ñ²^ŒšÄÃÇyÑÈÅ7ŒBÍô—Œh«´fÅ|­üXâ—Óé±Ôkû‘e~X‹Âc?J?Õ-ØŒÊ-¯ñg}À6”£‘Y~[ͯ ëüì2˜!ÒÙ…[[²oê³ëé(@P‹ÅEŠâbEq‰"µT=–%)²¸U :Çó«ÜòÙþ,5$ò; ‰0Æ’oèÞ´7Ð]£<â,zY‹ê4vÅ ÷u‹FV«Â?@ŸûSŸµôM}Öé±Ð‹‘qTT«TÀ!šÃ<¿< óhfñ¦í qJ]nr5ˆÏ+x`«zVœ¡ÇîëgÙ‘µq=X›uUß«tÕÊ3z,RÓâ½:y–^îéïÕË \Ù|À£jÅ>`‚ÏÁ‹<¼gý˜[ÿåŸ[ 4ã [%ÃÚŠÈ9½š5èM‚n´À–¯ÔaW5ῨÛîWß¿_Xõ,®õîþqâ8ÏšÏeöCdèŽn+.ÝÑå]6.ö"Åô¼N/**_‰~^Ü×£þÒ•~!+q^¶€–Þ´\*ý Çt‰[™|§hösú@øœ~Õbà>29œ2Y'òGLÓxQ/‡ÁB/D6¶ïô‚¨|rÿ¡†Ý*?ZMMÙØ¶r¨9¬¦EYM 9Œßïée÷t9œÞãeãÛÊv cÙGmåHúND>kQvU—£ (‚*kw£ÁùB漟Î':œOTœW+Î')Χ°¹±ç“â|Šâ|}’ó©s>¹ÁœOwÞ‰óœ‹ëfÈÕ§l\[9ÓÉȬ‡22»IFjšdÇŒ5~\rÛ=ï¤âQ6#µUç°ñãlj#÷£%F4N´E²ˆ‹d=Wæj§HV«"Y§Šd½*’ †\×´HÖ?T$T‘lHÉÆ‡‹d“‡(ÍêŠc‹“ÿ­å[“üo§÷àþgb‘ mKö?#ÊædËMŠd2²8ßMÙd"#õNFê‰õ-¯‰cº«~ûJ?6Nò°A”-Ó1^‚ ¸’E~–µŽñÈÊbêD'èeU1zäiP >BÏÐ#‘x¾wÏ}ÜM‹Àf½³œ©çEœÃáa›Ã£`á è0ìÇ’þ‚êþযx¶[O‡Þz:4¢~¯O°'!ÌCëüH‡a&šÿ?]‡ŽñÐ•ÝØûùÑ¡G†¨?Æó³3Mk«‰Àðú’ òõîšÑ >xG+æ+Á?j}ÞÑŸo}ß1^ ¡èóç ¢ÿ;M£¾áúUƒ8ærÿV}Q8§¸ü䄿xSúÃß‘/ÃAl’>|3¸Ã¦?™èï÷# ôOæ75¿ß„þ¦Rñ ‰^íôbø[Í7 ê™ÆïÈŸFŸ–/†îàÐEþ¢Ëý‚à:!Kp®/߇+Y'DÙýù2Á@ƒ0_)ƒPÊßSʲPeadZŠ8Mši=†ˆ?Ù·Áÿ$»Qt¬lZY ºTÒ¿SÒÿDÒéHz–“~ =3ù$Ëôœzz%ºœ³ÇG‚…ëóc™çS&:& @ÁŒ6$&BÇ'…`9¬d3àb ÁzÁz˜‹`3ÛÈM@p)… µŒ`\N!8â 8å F0«<WR>‚»Œ`6\M!¨rnÓWé0@³Û@>M!ƒ{ôã©‚†‚jA5ötAM9d @å2F0SÖ8ÖèrB0§Rä¼–B°bŒ`.\O!¨wð,Ëæ¶Q›¥Ÿå›¦i=¨›ºm«è¦ÎÆâñ˜P¡ßÔåçœ&ž(ׯ_ ÙT²¡†l¨Á¦Øñ¨®Ð‡²¾¡J6Ÿ’ÂvÏMæ©· Ã6–Ë>Xº Pnnå»\¦õc€d°©Ïi' 6‡Ç:¯ŽÇÌ Ño›' yƦ…S÷’…m,ø?bbß–;±;Ä?C–,jƒÊÖì VbYûy¾£%C!ß îlz¹` .Dýˆa-™|ØFPÃâ]».F¾ÃÎvàeçe˜¤…® C~{h™t]z~Þ¹¼º/ó§ µ3X^dÓ2%Ú‹øGe×€Ö> V@´oÏ?Íù½Ú¢ü€_–Ge7¸è#`œ+àxÞ@Z ýÕŒòZ¿ü—¨üW 1’(RhG_þ5*ßÿÿÁQï—ÿˆÊÿ€ "§¯Èé‡ÕvN‘3Lä 9#DÎH‘3JäŒ9c­¾sÆŠœq"g²È™"r¦Šœi"gºÈ™!ä‡"g¦È™%rf‹œE"g±ÈY"r–Šœe‚Ö…9ËÅÿGÜ{‡Gy] ãsß63ÒHšiXlãX#IC°“uK.x“ „ÝXÉÆqË KC2Q2ä—ͳ»Ï~›OD½‰*tÑ{ïl¦ ‰ÞÁ` ºô*é;çÜw%û=ß?¿çAÜyÏmçžsn?÷œìµ,{Ë^ϲ·³ì,{'ËÞÅ8Ô²›eïaÙ{Yö>–½Ÿe‡Xv˜eÆdvËndÙM,ûË>ʲ±ì³,ûƒeöy–}e_dÙ—Xö×,û2˾²¿a°É̾Á²o²ì[,û6˾òï²ì{,û>ž d?`ÙÙGµ¬ôh&¾±âÓYD $d>Š‹xŒr@°A8–Ék!é,•)I•uL^!°ƒ(üò•¸þÌç0‰,¹ àþÆç¢<èb`‘ø>ˆ'³F’‚ C¡ø{>›èʆ6Då¡#_ÀP HtYàõÌõV¢,ð…ÌõÓDYà‹˜ëÓDY€Í¶ë÷‰²À—0ׂ,”³'ĶßB"žØŽ ‰xZ`‡.$âiq€-»ˆ§Å¯Ô%âiqà«t‰xZøj‡gÊLÈ Ï„µq‚p<Ï øVÁ]+R]i®—\`ª¦ÁèJqY /»raÎî›\€\߆äñÈÒdö®W€Gn×|'²3ø— lëø|YhÃFG×wýoºÞ滑ûYÐÛ»º¾»Àõ߃ã…ËõH2÷]×{u+=‘É¿e¢dØ&õLf¥g3ù͸ÏsxÇ Ÿ®nøu^Ü&ë_2Ñ~Däëb&ìç£_—ð_ôë›LTn‰|]¥;ØÈ×·™¨»ùº– +ËOÙÏøOpbèìÊRð Iû¢÷ º~“ŠŸÿèú |þÌehä]ß³àyea‘#{H§`ÇÁú6’ÑÖ_d/ º¤Úò…×3 üWBžIï“ od2þ1¾U¤y) '‘¸FØ%tãSÅæÇ<„ õª^†ã¸ÁÀ_0bÇ’Ÿ’‚¾©oynf¢=Ëþ9ªŠïs!Oå™ÒËÐë„#6†ÁÜW$ ®dÉm/—4!ëYËsp‘ûÌ: ŸÌÁº!€ÿù`æ AC¦§9S*=™‰ïùøŸæ£ 4‰˜S™|"ÆÀ>˜`ÐñÐQs:“OÁøÏ#ÎTŽ‹˜30TáŠb@ŽlRÔ k¯‘Åó"h°ß€7‡ý ƒI~©—0~ySüÊ–þ\'ó:˜Âšø,´1 ð9ä!_îÀ4Ú[³þ»¾ÕÈ|‚ŒÖž¨8·Pöª!¯âÛŸ_´õÜÆ %ûóù¢(þ…KäóÅñ¯Vr0Ÿ/•·+|™¼ËÃ'9A¯qíÀŽq¥FߺMPùvÍ«¹¬íút ”o@sÐlÅj [¹™ZÙÛ­^†­Ð©~¶‚i~iÓýò.™olùÙ%5ñ]ˆ¹bý1ß+‡ú6X?ÁŸèªõlfv[ V{l¾[<§Câöe¢`C¾J±½{åí,&î!9»¦¦gÕt$¬ÆÊBXYht»PÛq9äb³ù !›-Þ®xWZ; DžB)©ÈéfVÔÒïЯs0Ü„ÖpA&oe— ˜û©ô53üòfú•6\ñúÕ J3«ñkÓ~ Ÿ`ò«2Œ}É0œYa|ë #×;ü[ÙeÉ…A2ÆÄ|×Û®7ù5>Sô$oÁ|ôC~A6ñ^†<»~îz—7Ë0H¶ƒñî‡0gý梟q.C–Wa4ìóg)¬Ÿþ…ßaðëæú2ýf¥ÿpý–ß”a¡ó/®ÏaªüW˜È~çêýQ7<+âwEAø{rñ˜®hýTëú^µë7užõßg_4᥋Yð¸ûHÇšÍC9œÝFæ9a) ¿ :Ô=ŸðÈ ‘T“îÈÛ¥«› ß8Èwuõ†¥fo^®À§hð:`€±/Bëè3—T ­™›Ë+”ÈOŒ”ð58ákHü5UåÔhSG(ØTõM©Dš:J‰6u´mêE4¯1/$6u˜kêDÈÜõg]?èZÈ'áÏŸwýE×þÈ„Gd|*âÁ§)ô2o µ~ã …Ï@ÉúgİÊ¿˜â5;ž¨46xÔ¢Š-†.SmÖ_Y.A–Y”åÂÿM–9€2T»Ýä5¹LŽÁ€ø4øø|ÌÇ]РcŠ¢>±3¬$çÈh”fÃSÎ /V*4êc£>0êc°ò÷ÊZVý^]A_ÛÁ,¿q?³ý¦Ìñ›)|­,~kpÙ[À¢uð3}pY:Pi£(Jï™n(ý:“oR.CéåL¼\uK¯dâ}i—C¬ð>LmÛ•@á˜êv@ø0=`«ù(Sâ»ò »!lpÐ÷‹ÞF¾ŸB?@¡/OEñ_FŠ?¤ÐYâbÎ\RPáA%[¿ ïöJÀ«-“½IPÕ­L ßÔ|W3‘g^cÀw~ÎôÜÎT±¾FŒü6¹ã5|§à×=Ò„>Ö¾k"Òœi†J½É.SußÞÉÞäc °äâM"H’7)ì@wç'€íW2]†4²‚3ÏŸ|Já§}œ$>ñÓŠ×B‰XuI0“ŸOÌWÊÄç½^Ká] çE l@Pök(ùk¼Ôœ£Zµ‘Dàš´M”„A qÝÿLgô>³ò÷†kÄv†Á\¿t-_#9QøŠŠÁÒŸk7œ0·~“º¿-º@/†„ßl6Ý%WÛæ‡ ¿« É h8 TŠ×ìÕÒP·é¾âÕÆ!ì¡àX{Ê8èï“CÆ ¿O.Sñ\×2LÅÓö|+|RK¡òÇJØ›„tå-@b¯J…µ*^uÂú«Aºø !Òì©yK‚F’‡ÁjÈ…Õ«µÞäêÚ’Ý.>D yªßB*ðajQÖ:ƈytœÂ‡ ˜)Kå#¤ñQ*Jרõ—Þ”Ú®zSk«»þÊ›V[]Æj°£ŽVQ‚ ÁG˜àcHPÓUÂ9FE ‚H #?¡ÈO!’rŽS·:tðlrœimëý} |TáóÞ!9Æ4E­P‘¿SÅ£k|Ëa¿Ô£mfóý†©@¼~†A½_Â`¡_Æ`‘_Á`±_°ýÚLz}m¬†`©ßT Á2¿yËýIëT>CEk^0 ¡pj|&|ÂNNÿ6òZ|í¹“)Á`iæ³UˆLzíü††5Å€ `#g«Ô¤nŽ#Ð!P2ª!\~G0r/VéZù»T  Ö ÀQô­øq%‚" 1~RÏX…îäÎÅEtêzÆ3"¸^õ&oþJ—)¤oóM¦7Òº õ6|‘±EÅØ ¼Mئ¢W,c»îÁw©°ð2YÒ˜³ÂŸ¼¶Òo9¨ò½ª×ÔäOÃ:öAS©T“(U×#2y“£a1~{-Ðîþ•ê…EÚ;8.¬ò§ÐËÔ‘JÏxª7Rõu{ª7ÓÖµ»EV‹ð•6wh3JÅá¢k#„‰"P­ÿQ9GbJH@‘Ço¾‘Kn×*9‰„x/ï`NE qFEsxCs´öŠ:? Åñ’G|lÞ¹·Ö¹·±soSçˆï«Îq#OçÞÖνm{Û;÷NïÜ;£soGçÞí:÷þ;²:tIÈ.«ýÒ’Où•_Qq=eL±þ›„”_ãW®AüZ¿z‚u~­‚õ~#‡àj©éüæ›lô'Ý‚`“?ù6›ý–{lñ§Ü‡`«?õÛüi!Øî·¶A°Ãoª5³~{%»üéà ØíÏÁ¿c${ýíFiüš » ´R»ŒDc|í~ý)p zÚjF0ÓÁšžÚÈùSàœon XÒÁªžÚÌo>&GR·,ë`EOÌo?†Ô~5W“«qØ»O?kp´{ z^s5Žsé'@­ü±hŒ7Å›FƒX‹JEá7[mª×êM­îúYí½m¼L#ô@Jm”º¿FÂoJ=PóZ SbÍš7 & ¬n=BªÆê†jP²µ¦ë¯¡8;¯ÔºþÆJ¯âÒù0­ë^«øÊàÃ5oÕêà#ñÅ’ íø(ú ˜ÿ£‰¼çM'\ÆjD ü#®F„÷¶ófPüxØ…ß_¥…qG¹£‡É1¨¥OÑP§j$ŠW`ãÓµ8vÿ0*3ž“ÌD°I¿•‚ê§À$5¶êàÎQ)¨} LRP‡àö:83*³ž“ÌÕ¢R0O‹JÁ|-* ´¨,Ô¥`‘FEE¥`‰/KzQ)X¦Q£¢R°2&«bR°:&ë¤`}‚lH‚1)Ø“‚-1)ئ‰¢R°]#*;á£R°S#vE¥`·Ûú©š.i0ï¼篴 ÷(A:ǵžy¯1̺_äêæh€q4HÖ*sTMQOÒ¹ÆI2â°ì·†“½Ð< Á>¿tÍ}¡Ì¾ü üfŽëÛdе×BE¯ºXx¶çU6<ý\Ô`(¿œ‰P\'bÄ|\!­…·5ñËZ ··ðmø–É«–\É$«­W4±µü ÃjX,r2ðIô5-? ïÁ ]ƒå6þ"+]7EMs[Ó×ßw4}E~úŠ¡=^—ßGSÃrð*çle‹¦ßeµh¼MÃ…j°ðÑ›Œ—áËõá92¤{ Ó ÷œ®ÂÈA}%Fõ ïèÇPÌ8"ïi'G¢ëÊÑÆ@— X1\Vú5~õ¤Lãà—‡~‡_?¥_¢°*£ÞRôÌé­Ÿý59;…`XòÔè¯iÑØéÑ_3őԶ‘„bQ?Ü9-æÑVA—È>ÇÈ(~Îæ_`„ÄôÔ/Dšç3ƒ8=‹¨í,"uH½$Šâ²X†˜áB,ò¸ «¯Q9’¬¨K¯õDô#6Ãz#.÷Ùz#!èm‚òmôk3ü2Qq[Œ¶OèÇ6ˆ“)n{Ÿ”íŒ6jü’è×îhìžh޽ÑRöEc÷Gc â£s èÚÝâ2¢“Ï.‡Ò @ÐZ™~6Eë>Bôyés ésmœTGHt„HduœÁ]ZŒ’§0eCŒ’'(Yr;¤äY’1„ž‹}3I(ú\\Ñ—bE_Æ”GcE_ÂdÙ5¬Ý9Hw5Úìoce_Ç eW6•}S6ÅÊæqh߉Òön¬èû˜áXBÑwãŠ~+ú1¦<+úa<Ú­È£1Ô/+H¸à¥j…)Ð¥Apf)à²Ð¯Á¦³‡˜"mjŠ0«Ò”a¦ºÃ£9FDa#£9FÁ¯÷è×è(l ÞãŽÍA×4Â|§èK]çc¶üri8aU¦¢¯tà,n#Äñ¢xä4'=ëmãøÆ’’uÝ’ý~ŽÚ2°ó›P^,:ôLý¶­ ÿ>™Ql+mÍÄäX[UÞ7—>muÅ÷ؽ*ÜJ*Üͬ҅úi~)5³Ç¿T¼Í¬õ—ê0ÖÌÚ~IÏÙË?4î†`À‡¦ïhŒF±?LÁà“÷ ¥ì-Q`"U˜}〟w.ý´xÛ†{ž½¹uËÛ%ƒÜüŸ³Ö¤¼5o‡©ÿ©ÿ\4É]8Émà}‹‡`ôd蘲òŒþO}ÿOþ_½†ºƒ%CÝü¿{ q3Óqãþ×`Y29\øßŃÝîé»úyó<–aY2ÄÍû£–Ǫì, MŠò,R]5+†õM¥úþS̉h‹ÌÁ+Æ^áÊán¾€õ†u⦥ža¥¨2¾a­“>v—}ÈEjæÛ§A2±L]»%RëV<Æ]<ÑíÙ×5¦ÇÐ;‚ Ež`Å£½9Š*+G&9'<ÀÀ’× „é9|ÖÙk4`:ÚÍ/±^£"˜~Åô2Óéó¥Ÿ_‰`:Êͯ²`fygùÊÏn0~#’î+?¿ÉWê56B„yR„ó%]ƒ>ä $cݨB#Â2‰/“bDX.éDX!%a5=”×àûrÀˆ06‘k¤Öa" ÂØx"¬‘bDØ„}¨&NÇ¢D8!O@"Ôæ ê¾Ÿ!¢ÒsPiû =?ä—¾–ø©WС „!Òâ¶ßèÍø:9ä'>;ì5ie4PšÁ „”™àæß °ò`hé“ß“Š+Ü64õ÷ ã%ò3Z<ÍÍ[$Òó­ìªò6©h²»p2àÞ_†ñ¦#Œ7|^±Ì¢~Ñ‹‚·€•r¯JwñPwI¥›“{pw—Œpóár/è%£Ý%cÜ|„Ük¼»xœ»d¼›”{MtW¹K&ºù(,pvŽ’"+CÍÔ¿ÅÍnëµÌŠÞFý<+zfÙÌúb˜&7³€ŸM#ëèôrðÐç2^üµ}¬Ì† èWçÈ|¦¬ß:IôvÐòó=†?Bø£¦/pøÜë -’ù"9è©zÃàßÕÕãÕžâ’-z×ç5º$4zŠÖD¬½èerÑTwQ–×èÉb^Å3Õ-¡…Q¯±Ùò±qÌ×A½AÏx(eL|½(]slDã*›ä0;Ê] ˜n–Ã=øVJF^ô¶ËÅã!^4g>Fÿmæ_RÑô¢Uþ•(JuŠ2óJΤk( š÷‘§²ÅÚÇj?)€TûY¹¸Rÿ k*u¢^»Æ¯È^Íe!b}#Ãøè2Pžoé7yn>‘çæ1+ŒÛ²«=@î„´Bw© ŸÈÙòTºVJ7PILW¡ Viä~Ö t°òdî! æùDîQ á—LwI.‹°7ÁÇPAäTyl¬ÌqO•9Ëlfa¿iŠÂ§PÑ“ô¢Í|ªHnŽ%Ÿ&’ßè`®Ux-%Ÿ¬'‡­¼HžK>K$¯ümÒ…/ äSôäɼ^$OŽ%_ˆÉ­/1Råïp~o‹{Ì'øÞÕò¢†Cž5d0¸G~ÂWG ̺ £?Aóø"¡³÷„ß¡Á{‘­ÓÒÜ›_Œ@k%@ûys¢Zÿ ¨Ä§C4« ~Þ_Ñ!F+ŒÌî&?˜Ð9€ûˆŸOŒ@ÌhœÀ}ÔÏgF Ih×}ÌÏçF ɸ5ÅAÐe¡Üb²¼dik³¸·ýûã¶£ÛXKÛÇ-mÃZÚvµ´]kiËkmûß­m‹[ÛN¶¶á-òRÏ1çäHFY©¢¹j“’h¼ÞDîƒ0ülà¸_Þ¦À0³E2oS‚ž†|ƒ¯‘^±â ²ä‹YGÙI—"ê.…ïTB^¥ûâ.¼ÿÐÈ•ߣ„Ýs>®n êxUÇÀ逦"‘‰_~ss¬w^FôŽFÞúUøq%2fŸÀû¿y9qo· éÎω(=¤sQ“¾Ö kÝ6Zìœç=ª¨ÏÁgc=oœðó·1z‰Ãð6·x;óÝ댞rù{ðû#Cɽ움—9uC¸œ|? $óÿ€ö?h[\Ͱ̟‘#ÍW ?ÃBT²ùEÐ&C¾îÎ? K8ù¯¾N÷ý×¾mv²²ð†v ø: ð1ÚÞø†À'¨„ð)êß ø Àg) À¯ 0C -ähŠ¢ž!Lÿ¾Îé œ|ý/„ÏÙ_›YýçÒ(†Š“Â:, €GòKû;éY§çk£Áæ¦dú¾b4”–;ÉS`¹³xe;_]NÀWéŒÌÁhøƒü ôwBMhŒbŽÊçäà#Eľ—|Cò¾a±ˆQ¬hßKÞsßK¬lßKM|4 »¿”J6ùXÊ.ly µ Ñ üZÅt«bØ@6™ñÉOÖȧÀ"sH7,l* u,ÙdäÓ©ÐZýŒ5£ìÌQ«ç˜—ƒ.!4¼ˆÆÈøÁgÔü%Ô<Œy(®º >ú>:P †tl#ËsÐIu²Æ{ÑöÍé°#ŒeE‡ÒQÔÜ“;£•aÏ¡tVv(½‘‡J°[‚…çìpD'±Ô°¸UÔ¹{:Ò°LÈÙDœòs–‘Á.*ÃNOÔNÿ@ºÄ`³óÌZa b«õÔz5’vö[L 5á;³¤Ü¦Yрή\r°û4µn@C†µnÅQëî3RÞ‹ é}ê„|—ãñ3r´D;B«žÍ×Dr ÁâÊ|eŽ‚:mD°¡‘wtCapÊÏF¢ñ¦Ï¥ÑÌÿ\ÁðŸ*ÓÉâ‰:ƒ6/ÚL4q„Q`Ù.uç#a³$5òÑRñdòÍ÷ÜìÄÊr›ø)LfÆBšñRÑ@ˆ<–ò‡¿ù=2¹l ¾`ž€Îž|'óK†¼Î«è÷©ü’¡¯ó‰ôût~Éy;ŸD¿Ïä—;ÀVŸÍ/9ÔO¡ßçòKB`÷‡¿Ïç—¬hǧÁï¢2Ö³ŒJNÙa;ò]È÷]Ì'ÍžRÔtöLò+eíŒó`-äñ²cJ²|}$ßs)Ÿé? dJZ·t€ r–„m…•Î×ùŒLxÍÑ©<©¼*M})#•IB,…D.¤^.ñ%@Ç}/ :.-':Zï"2k$§ïr~É_+YÿïxÖK¶‰™â‹’ÝRøÉú&ÛM†³ßÎhQ…íŒï–¬¯c¢½ ‰ö£Ý™Nχ¡är>ÿR²Z0Q€uxP²> …»H¾~O o‰ÁBjB÷OüG¤°.¢G¥0¼Ç¥è`Ƈx¸]ö]Éï­@:¾ ¸¡/qÙVÙü•éKD\¶Õ¿Ë·F -Û†uã{"™–mû‘‹1}‰ˆË¶/%Š@Ôè²M£e›fR^ú¶6mpkÛôÖ¶­mWZÛRÛÚœmmåg­«£ àë÷оÑ2óÐÕŠa¸Y“°±Ç-dÖæHÐ÷þëÆi?‹ÜÔô4¼Õ̪z2øtO þÛS†ÿÇ÷TàÿÉ=UødOí-Ìð>.L~Ë‘‰Nþã@¨t‚“ÿ$.éät <ÚÉ»¼jéX'ïðj¥“ü§¯±t¸“÷D_ש¥ãüŸÐúBŽð¾E–ÂNúßp'¬îÖçu_ÿÀ°œðDø†ñÞ àð i"DŒÆˆ±ˆzŒXc1bS,b'F £œñ±9G¼¬ˆƒ4ÜË0ÀÌòšºäáp¾%–­hÔž€™·Æ"Ð&¢p#ŽÛbcð¤ÍdMƈíÄ«—€W§ñäUWóW&‘ÿ÷tÆÞQgUZìÄsU!ÌÍlu¡tŽõšáîT2ßÙìÌÚÏøù;úó¥wðã=r•ƒ™wåȪÑô'úéi<ž4ú¾áôº÷_ÉßÏŸù]†/ø¿ÏÖ„ËŸ?£Çaqmè§r_Þb¾oóIçò/¤g ˺oó}×òƒžqv 2ÿ™œÁüw¼ÑÛcL3šVªX1Ú íÖ=Æè,4t2Ë62ÔÑMÅháÆb†k¬MÅÒD´OÚNžÁæbe çüêT:·Ó–á-Tï+°4+ZþBñ(ͳüæ[üÂèÝ3T|C©.æJõM||á/À| {•âfe\-]EOcÁpJôóéè¦>yjBž±Ðˆg°^•š‹•VjV?z@`A¯ºT÷ÖŒ¦nªè}ø,ÂÔ³15À19­Ž¶…Ð0ÝW/À ¼Z´ôz†'³ðçBQ~×UC~X”Ñ0R§¾i´xëÇæ• uÍ’Vá àLÄ3_1•—ÄW1Ròóà°¸ ä%C¢â&Ýîò5ˆƒËàÕpi監éÑÀšäa9Ž<|ójå%×ó¡¬íɨ!èX,]Æp¢âáð`3ƒb£Þº§;ã jNwê¦õ–#!¾ý§dô^uÞoÙ&ì0ÌÑŠï+tѾé‰QIg;ó¦Œë íþ µ{ȧ);9 ›îME!áû˜×âMõ ×RðŠö +®Ó2éXâKÖ«NûÈPZ§A÷¨7•vV‡ô\¬ð›®¬½©€wI“‹AH2M3`ÅÆm½QiÔÐ5’I X“Mge”ÞK´ˆ«Õ`—L'µÂËdro ¡¨?ðS,Ý.ƒ<~0_Ck€‚P.¶$âEd8:Íô©8¢R*®ÕcÙü+žá¶¡Ýº{Ø¿;Bÿ†ÅV±ÍWÝÕ=øS²Z”I{Mw¥áy´K1OÛw™'•LwãÛÏénà‹ «5Lw¯ÈE‡9¸(‹º yê5C?û6r=è—ÊapÑ/VäJ¼\‚Fx¾z݆õ½(ÌÃýÄ¡K~u¤þÚ¯ –ø L ‹I‘ð¼(Ö¼ÞFXÙE@€à@UJ^£nGßkD„ªÈÑËp‰Î—FJÛ±N´'§KÞ àÏhª ˜–Ê´Ô'éM=ö 4tÄ·s¶—'U˜So¹:˜Œ3èÞÉl4Í"VÏ 3{x"Oeô …/bMù²ß0‡ ¬žˆ%-DߪèRnš“×HQ1¬%Øt',Ã:5àcšÐ\Êb):Æ.AŸ›ä—Y4»õce…„Ý\]Iøqƒî \ bWQùJ‰ÎJþ·ÞQ´Õx|ïU¼šÞMŒ°,½mZð @dè1ØóÙ_ЗiØ)¨‡l–…5N9ôØ)õî±CÂN$’ìÃn*ÂG¤Tüë›Е’8›Y$ÈŒ±¾ÊÖ¯ß%š :¡¶/–"¼¾‹‚¶§ØØ€Vê2 {A²„ÐD„@_ê°óš°É…Íù€CAdÌ™néÉÃø>Ø5M%È,a±•ÑÏuÛ©KX²ýqÎd&Ù‰_ÖñèÛ@&ñ²Í̯"4„µq¨íŠ´] — ¦ëXÓþI1šÆ1¬ê-˜“„làBa­Ó€wP]oÑ2òª RñHHÅct Ñž}]ÉÃêC”ŒLŒGRPÀcj7:¶â­R›MÖÓÛÄï€ÔcAKÔ¼ >@["ä5ì@Œ Cå(†A’þd¤O†ÑâÉÇ™–£d#GÉ0NŽá&Ô8FŽ’ž:„M²Ñ´È05ZõÌ{2ôÌñ5Kñ\­Ÿ°ÙKÝ’ösåî¼5BÇFÞFè½èõW‚F¬2p†  ñƒÔó*£OžŠ5™ ïÖ»ë¡èŒ™ÌŒTŠfh…34¼@»6923š<$3 ,§C™36t,4S‰³t;ÓIEf:uËyuâ”±–`dé¶‹ ÀŠÚhÊÂâæaq (žìWÕ‹¤hd äsdÍhº@´[AÎÛ6’ 52“‡«¶FÁÕˆ´–¡å­ ÌÓ%|­Y“4ñõJØe ËŸŠ‰MJw¾U Ãû²¾úð«lÇómQ}Vé`[,Sö(ÑeÊ^%:?ìC¨W%:ï×óë”>¨ÀŒ'Æá/á'-S¶*^e[oÔ›3´¯À7gØÚî(47ì(Îà1öݨ~ÅFø«ÕðWQ:Õ‰ip‹ÎAW¸Ê’ Ù¥ È~MÜËÏü¤^.ÝÅ(ÙÐ\“eL6‰’¥C²oü¼}Ñ}H¶P.ýWJ59÷ygäSreMVìÆU?Ç Z;e–å";: o7üì þÃÐo‚ﳞ,v¯°OÓo¦ß&î¼Ïß ?h·ÂŽßï=hôâܪ«<q’Êó§”ZœmXÑg¨RÍÿ%Z(äRfG“Q¡’^hѳ ýœR˱B‹ñH‚{£…R}Úìh2QZïg—Ö#4æ/!\V9ú¶¶q^ßæ*²¢þùæÇÞZ÷<ÏzÜ‹ý‰ÿ‘8\–ÞÀÿ„Õùv»þÒÈÿº øÜíÏAñ›"Ë,…wÞ”ù¿áGcûEª/¸Gœ¼e-ÈEÛÄÚð¾³¢ÿ•ø`Huãlµü'†2ºîôsº›ýnôÞèüõÎdHÛ=$…„,àYjG_¾õ¹ÂK9”9OG³˜hŽa:kÇ2q8ˆ-Ìe€F'ÌRÃôV×1^e®´S‹g±­„f3D{QtЃ/=Ö½%¨äéDz‹£³üŠè,­Ï,jY~©\ÚƒR­Œ¦Ú]2ÜêÄ¿Sôµ3ó“eré¡taìô¹‹í¹2 ޯܸ³¥~aþsþÏ8‘Mî\üÐT¸«“ĉǟ¹¨;fÂtŸ1¢1@vÅ^ìŽ~G€=1@쥙£=nžÀWà …ß‚uïÛ+ª€Rûr%UV`_)QŠ›~Ã#X Þò3 nû¥èƒÕ/Ty dÛÃVØTzqÙ©/SCQ@Ô¢=,èÙÃXÙÖÄâgHÿ„ü 5ì«x‹/Ö—ë^pø`6Ù#†Õ!²ÉÞüêQ;öà•*:&ÞŸ+«²öbYO êÇ>5ÔÑ Ã`þÑÅÞ"£«­‰/5‹rCž\æ ,Œ–c–{Ýr/¬|áìÕïç{­¼«á@®¦*êy‹ÿ+9wfxT|Îiø+‚Hè–‹;›Ù²ÏØH˜ù‡ŽÖYËÈãy9 ÒÅÚÖWÁÒËN>˜ÝÃ~ð­Í"×CámC‹¯JøZ˜ðmŸÃàs(¤%>‡Ãg%|Ο#àsÚgßñ9Šït·šè~ôxVv¼C#t ûÛ7¾Çb 1>y¾›âs,|K¾[âs| ö¶øŸ!ˆ½#>'Àg>ïŠÏ**þß…×¾V˜ sËVtÇÔÐzîYé'êåzê² ö)8,¬øLžÍЪpQ0=Ø3˜ÎJ¯ÁnF‰k뢆 °Æ7åEßã×Jê^Àî\X“…ý¶h/+Þ [:wϽ .È>‡áƒÎkN_Ý %dÔ^…®RëY ¸†ù†æ|åY„Þ"¦—/ }[|`gµ.+j»t)Èæ£/DW°0^Š Í ø&Ǭbá`FSt%DOe¯T«˜$ XؽøÝèç&Hè tÊd³€ HÙ" q(oJ€ mBÜu|ƒd»€ÜÈ Ù!rµæ|Ãd§€´d¸€ì2(y„€ìÁaì`.jÛô¡!Žwšø-V$|—¸©nÍ'®·ñ%¨³¿Ã0ÂwÞˆ~>aÕë7ÜcüŒì&t÷"¢`(ƒÕ(ÉÃCØF`‰XÐw²?bø ýË\Ô7臕¶ê•66³û~C+ô#)¡nÜÚôG—÷ß8­è´\z¢~6­øaý¥¸ú+¤¸úù ),¹êäCÈ\-µÙ‹ÕO¤ó¬Céh·—j½h4èæ{¾oá©Ñúò„n‚aºÄgH¤›©,N=¡Ï”‚¾S±F–¢–ygéUAKøÑkÖœXØÊ¹ØÊoÖ·HÉù‰ZÙ‰×?·ÖF¾ÛwÊÉcû´ò+]÷nh)øš8%Ø$é¦ßB‘Æ70í~Lû•„r-Ñ-W™zð€dMÕ‡Ì}Ä„½‹Ô©3½”õÐQ+B±BÎ`! Y …\zV!Wã ç&%©I—iØ­É¥CûC¿Z!?Óåoa<ø£ÿ«„9©¬ƒ¡Bnfë¾Ç0x`‘08ò‚ŒÁ‰)2¯”žNC¿\>è*YârÂÞG2W”f§ ­3”Ek¾ƒ-è¹æ;¬´V"P[ñãö¾ª\tdékËGÿ”cÉ ¥½+dFãF—I£Ëþ#<`§OßY#Œ—ç`¼™Õ±xU{ßõ«CËD9P¼šù&å=¹$KµâñÐT9ÚžYHYŠ&€oU–î]cªXŸ)c åÙP±¸:’pebÂe°F !†ÌÀëÄäV³-?3õšgEA.VÒ–>Ïø‚åöFï§Zno$ÓÛì5¢é\Hc2›Œ&Ÿkü¾T›¾õßáóäd°Eó)4øükË ŠEBÚQA}qä ~Ápþík‘’–$–&e¹eqU/ḴüéºWÊè€4ðšW£Õ‘Ä”¯†2ŠE«EÅ¢„5O•ð²ÉÈ7ǪŒø?î”PËFÛåŽ=Øpå¾Ò¦4Ã’Cë_``ÌP^`’  ²œ”4°À 8`Ý\`PákP:!=Lkåtì!Q×­1]ÃGèÈ ¹ŠI1î—1ò0é’Õwè‡E¯8,zÅaÍ-=¯Tà½Ü#¿|TæGe!ïAv˜}É^Åþ[Ž òRqGÒì„eDŸ"¡€uHN: òi]J`+=ÀãzÉèŠeÄ; ‚F3Õ ¼¢—¡Þ>Ê9§§ùC[~zƒ‰rö<¹¬L¹ ‡ Ȩ~¬)*E_ŽQ)r o0º}“(W!ó:“̯ɱ5¢ªV*ªªG«¼™˜ñ–¨ÕªÒé3ð÷A¤ó¥ .AìyáÂåYh­¿VÁ×Røz+4êD¨·`e È8i»´OB14Ò<2•æc"*¾cZƒŽSøxV‚XΓ‹Á‰¨³ÕÁ^hL¦ŸAß‚È uÈw²ƒÎø·!Á4¥hÓx¸éÊÍPŠêÝ‘\žz·d³ˆƒk„>t2^­Í*ò×Ò”‹Z$o!Žs"8Î!Uôn*ËÅÁd¡ÀïÂPÂ"½„%XÂjæ@jæšHkD3×)|ýóš¹Y4÷ÖÛbÍ|ª•8híHh%b³+®=»ulö#6GcíItËòd{qí ê%Ǝ墆ðDjÏ :„ßÃ3ËjXS3 |ŒþXN‰Â6©°RœíûÙ+“Î*üŒ‚[(ŒÛ¦F~V)ªað?®æäðsJ§N™ü<´ºâÅž5LÅÂù¥¨CvNžLhñ^T‚aßu».é^FçÊFE=DNR‚¨×~ôdžI0©N{—a°ì3iŠJÎÕfÅ e¦Ê§ªÏäEŸ8¢8ê»ÏT颼¯WjTh*ÆyUèÖÔÞa{Ç|®Ö©¼7‡±X}“¨ñY0T@Ó‚:7ùlün²‡êqÜásà«Ô¢»Z›DVcp]s"-秆-Wõ½îrj [Im‘Ö ë!ë`¯>G®ÖªºôÀÎq0.2›²A%!d•HS~‡«+5 ó -â¾6Oìsøæ¸˜Jˆi²×Ûß@Oz1x0#•lÉ„ŠÞzÞf…ÍhOFDë×!;H/0Çð_@k÷ ÙŸ“$f>lk0ÒÖ Š"ÆÂÄE©Iåaå&¬¢ÜÜÏá‡ÕNxƒtx#C téiäME¿ªGÔ0]©UáÂahü§Çª;©î¤¨î´¨î¼ÊOSu§©º‡9ü VwVTw.±ºóÑê.èÕ]ŒTw «;+´“¡:®êghÄå–Ÿqí„2pཅç÷T:“Ð]%ãO´Þè0C8„õàé á •ú–Z®é®lË5’ Òž#C4䈸†– ÎÒfÂ…åŒÖôAb4¬ µl>}’ÐÕäÜ,ÆÇaâs¹F¨´7&®¡ÄÓÞ5ÔiD¹Y¯ÓôÅyY‡>KCúÍÖ~-9|Žô›«ù<­øX²oRg>Ÿ~Lîð0&åR¶¡ØÝѦFи>ØÊím†a{kï$ݤ’“)Édæ•&ZüQNX¶ï¹‡Ibù7ÌD½M£ w„)n´ÛÎk°íü-Ò=ð±qŒ‰1á¬9Æ$ŽUùXÌšãLX¤ûèùx“^ǯ˜>iÂ`:Áä5´x“+yOÿ.¬dL¯¢*½&’ÃIh2äR® –Ìi£]cÂQC÷ y5&’¼:IÞŸezŽÍ1%Ñ<ÓìŸoJdÿBS<û™Ù¿ØÔ/3Åss(q“”—?Qø•‘‘’ãJŠHàDñÕ [ƒScÛô›Yàú®_g <ͲÂû°Úðl&} ˜$o6ñÍĤÍ&qÒÍ· “¶ &þœo3+"8b¼RøÁ q࿹ñ5­óëi|:dÒ70‚‡ˆ ,HL‘Â&Œ'z#?lzΦÑôü¡¡ H}ÔuôTdI¶ïb£Zýò ?"B´Ç„âDXá'M´­QH„Ï Ò—seMQïÒWLbi†û$BûŠ@ûª@ûš‰_MDûúóÐæ€V'B«JèÉ·L´[»mâ·Lq›²Û&Ú”•âNæ®é©MÙ?¢9VSlЛÙÌ<ˆ‹¬¤ÆÖ“KÕG:\ß­<6YqºmÒ7g£až*7Có¯ä¢¯™É6¨™æñk¨™¶œ£Ì|¸9ºôÀµýs§|”9ºÎŒC%c øxs˜Ž5Ñ!^ÅDoÓ ‰ žLìùC è„sr,>ia¬{`×j=}5¤äSÍ!š§¬Ýðt$®:p¨þ¿*£ÖR_žcorUd6‰–šq§øØ°ÈÓæg”õ‘ÖCп¼ÁŒ4PBD:5læ«I·I·Þœ‰û« f<ä#(Úñlxsä Sl£Ll?jàï‚Ï“í1b¯H5¦ Ø÷·›4šCçA`Ñ‹ø"ÁÐÁèrûdûpá‚,…ܰŠÆÖÃÒ0ÇD˜OÂ1~ÃDp؄ѿ³XwÒv¹ÑìÕíQùòD *#*^ÍŨ;¨Ÿ3뛳sf¤/¢qÖϤ«f~ÉüœAú²9Öﯘ»ó«æâ½zGÜ ƒö5s ì˜ÅlxºÆÍqÇJ0ŠÓêú†™ÆîA§Î/ê£Z½}3!ºÉNÑcaG„Ëé[æJá1Àì5ßR¯éK—f‘¶´Š¶ôO¢¶T$ñò¤ç´¥")÷ÁI:îh yhR(~,'$h8Çe~eÔ}V¿§ÓǤÈécÕ=>‰Ox^¥“’"¢hÃ5Å”$¡bU75©;Ÿ™ôÔFWcשF?Ö¸ Rã‚$Ú)/Iâ “bœYÅ,IJ"—%BQò¬€Ó-‡t«“„Ê`aðUÆ×vbǼëlΕ͊:„föíI8.uÁåeW\]vЗÛ{ ßKÚ›„æ ä}”÷QöC0 z ‰ïŒÃoÔ»'¿½IE]pLõtae]šø¾$ìGל8’â2QlA~ ©#~0©È¡©fî21Ti桤NØ/’¼JñÔ”4[7$MMA)Ì3#Å€ø[Ž£äƒOµ£Iü¤uÙ¯2LÀ&Ea0¦O~ݳ" ÑüX=± ª%A•!µ$¤òSIaØ’M}Ð? ã…ü¹$¯¦«mÐí?ÜÎà¨d¼Ä/$Å:³‰_L yMØ™/%yM‚W’„7Ò¥d\ÿ9Âs%…¬8GnG:ˆ™â¦`ý$~;é‰åFŒòw€ò÷)ÿ0&‘99éqC®‰·`sµÖ¤0aF¶¦Ê’ñ¬ŸüÏöO.þ*³SÉÃ<^ž (Þ —Š•Éq(V&Š£’ùðäç¢8"¹;•œ€âØhjÛ[:Šã“ùøä8'$ «’Š|brñÈÀùd2èÑx)ñ0©; Q¿GÝYñ¨Ï¨ÏOæsžú\@}~"ê “Ÿ¢îâd¾8õ%:êK“㨻7©¿’­ç°Ô»4Œ¢aì¢Y£Ç1ÜOe–í£ÍòÛúpöàô·É¨&.Ý„ ¢|+™›ÈØ›É(Y¸¸•LKˆÛÀ%Ž);¨r7™ßò]wÒb±-Ÿ*å÷’aH9ïãÏsfÌý(Ù«df¼®þ·$ó–ä (xaqÏ©oüÚ’½±´¿ŠãÕJ¹¥;l ïƒji;1âs­Ò‚'>Æa^i)ÚÇž}ÀKl#ùŒžY ˇ[¼Æ~úñˆ©éBŒ°àUua‹‰Yq%¿½‚îsF[ŠÞÃtä+µð¢Å€×Â| DwX!Nh,!¯‚#ÞxK¨¨C6÷(',â·k¬`’¥è¡£çC‡Aæ“Q+ð^cj,›15bL…3ËBŒ™máu–ÆÌ²D3ÛBŒ™cy’1ó,|žå)ÆÌ·D³ÀeÌ"KiÑþšné,z?0Åk´ŠG©)¸©”¢_KNMý”"<·¦{H>RÆßQV¦P­[†‹ßaºô‘ ë‹€Q)ÝùxXÐdý³,cU J–ib ¯JÉ‚åŽ.Z&>04é¢eæ“R`•Q®Ë–¹\?£ôš=²ˆ1Ö±87bñ ^8ONK A 1cÿ‚7à ÒU$¦3su ¯ÆFá‰2‰×P³k"Í®Åf×¥x“ø, ^´­sBOwæÁq#;?ÚJ+¥DErq º,¥»çŸ£´¬NA‘ü©au _—,~sE.nì`&~OwÖÎ×§½ô¼É|uæ~âš´è½ ç=滦 ÝÙ ){ðM)xïõˆ î€廬: »SøÞ”@¯k„2Éã\ͤ¨Ãiûy4%:íÆ¿úî€r‹ç™TÂÑ~<…´Ì‚✇LÁWét DœI¡“ˆ³)ü$ì$ìq?Ë F¯°NS!ž¹/Ðkë3)aýÈâl Yô¡þÁ}ÔóPÞÕßi—Søy`GX^K4~™Êðjq'®)ÑW|ί¦x51|›‚£bGÒÍ¿–‚wÉ<%Ä!älŠ~l1Í"§àr ‘.‡”£SôaâQ oIÁuÕã<^]¶ Áf¶*zÅ ¨‘Ôÿ¥ê9¥6³q)ll*’—±2UÏ825f{fTjw>65è—‚Z8|B*ì_B´{™˜U¨kÒuTd>%µ;ëñËÏ:Ê»Úhó+t¹g§FíÜ éc˜ŠÃ›Êç¦&è~á;Ÿ@¨õ*¬*`ÖuÛ1‹Sù"ˆº¦ vƧêvd*cvd–¤†ƒî¡}ªÑ’ÌÒÔpˆ k¥&U.×˨‚2V"‰ÊòbhnI@s‹@sK*ßö4š;âМ‡æÞT¾G¯bT±÷hîC4+šûu4<æA½Œ‰PÆWˆfÿ><ç;`‡·cVT$E+%“q¥d“üR—¶¶ä%-m[Ú®´´i­m¯¶¶ukm+jmë×Ú6ªµm~kÛÖÖ6HÄǦAg(ÏÜúìô4:(iÄC\ì»xø^û®¡&­™íÃjÓxMZìT¯ÏJ RFõ²¹iE]\†ÜØ6f¡û½HíÙEr‘F|žÈå;oÌø>vôŠw¥i|Aš8¸0™4ñzQbØwX û#%¼/ÆyI_’ãü/†„N¶KÓ`hPu¾,-èUhX EyT¼ÂCšF¾&-SÀ€Ùú<~tÕù1ÕʧYŸÏÖ½ZšiíÎk­q:\u›á€Í(!³d@F È\kþt¥¼y{Œ€Ïø|«®=·àc¼^”ð°' x€E <@Èb‘ëä/ K/o/ÛœYŠ”G©µ ”ÚaåëÿGJm´òMƒR[€R¨Ü±(µ#žR;(…|Û•@)„ìŠìPjŸ Â÷|„R¥~0Rùò)iýê)i=”@)„(… RjHžSÁB±G²êÊ|G­x!À0T$„à§ò)+.•V~ÒšYö§&~ÊÂó}´ƒhæç¬bÿ‰7ò¬0Ö+â|^´ oDhê(ü ü¶ápÕ*Lx~ ¤¼N¤¤§+ÍV|fGOWô—v7¬EåÌ=üÇ=Ëa—\Ž69nZ½j°¤²€ß‚¡’)ü¶¶PÂè),šÍBžÙŒÎzAâ÷­¨¶Gºß xµ§j(½êä ã2¬ÅSE™Q«Xñ*æë3l°ç*&îëûÛИFꎎ¥ tˆM§Ú’‹°‘Öó(_JyB)#lE¢zqÇ÷'Vö§F>ʆ-iam SûÆØBb³=ÎF­*œýãl”žTÙb$ˆ¸U橲š´™8:͆/¿q} Ól¿eøtëŸaK¸]iëÔƒ×Øž×-ðJdæ³lÏ{»eζá3Ï9§¡Ÿ¿cë¥?2^o‹S²Â­½xȃº „ÁBlí—Ù"ÐŒÿØ*ȳÚÔ/¢~±ÊÔÏþ>ê Ûbϲn˜Š,îñ}:uìi‘=°Þ¡G»ë±¬6Ts ¼Ä­e£¾µ”èmÃ6ŒßaC¡¤x¦Çó=@HÄ@(5±6PÂ=èV6]š¿¦HÓ ,×0½À J7 ËC'g$_ÙÄE›B‹G¡ñ¬ÏXÀF×û!úÿ@ÛxÀ†šð¾ýyÈãß` Emð]v†6¿çJ“7ÙpÑ×d‹>~Äë>X µEÖ}*?fà -¤ªÌœ°añ§ŠÅnOÚHµ­ñs¶`€Ð˜YPÜe0ìC(Åy‘‚_BAž§™uMÿWm‘õq×&<5QH_HÍ,sãJØ/Ä8,!‘Cí^m¥½ ¦œû™6Ì· ·· â`¨ðš:¾ÏL&$8nzâö²¶£‰€yÑ›˜*{ÄÀ¹ TO²óIv Ivñ⤧ì>ÙôU€©ÂÞ¹="Ž!Ú>Lµ£‡·<3ÈùYqÁfŠ.¤¶¸—L1ý±a–4^æØù;Ÿ‘~NH«l0€È ºË\{È>^Ww™y&ö‘ØñÒ_©·óùöø®°ÀÃð¡Þ^´†»XÙñ…vÀ}åg|‘=„êp‹þ8DËéYÁ{ñ&W59Ê%õÜËB“/ÃTxÞ¿ÜŽ“4Žt-VÚC:ïÖ`SGQS/PS·=³©ÛDSwØùŽ¿ÙÔÐÔ‰zSw‹¦îMÝk绚º'®©{©©{íbÉÊ÷Ù;ñývjíÑÚƒ‰­ýòÙ­=im ¡µ¡hk°µ£óðÂàôÂ.LˆEÒY;?û7Z×ÀÏÙƒv·xÏ.ØùÂú‚],«ùE`à"cyü’]W翌UŽÉS`Ͻ‡|ƒDtÙg†[v²…vßNFÛiÓÙbç·íÏÔÈhà÷Aj…X#`¹$ ®!Ú»óÇv4—Ðb§­i\™´ÙaœÃ§T‘g.œ’¸‘K÷*°-O'B¶ØÉ©¼”vÒðöyH:æ‹XLJ_X)Á OG×ktˆð[lϸtjÏ›†qéÍlR†Á´w% õ‘Ç¥óªô0jõó‰é±µt¼Ç £Ó)éh`òº“O#X°¨ÑŽ˜z6Úe\›LÇÚÆå ‡“PÛÌHm3ÓyÈA‹ZL7>­ƒ!2ÏIgóÓéÝЂt"s}:Ÿ—N·Íóøütñ޲,¹‘/H‰CõéDÌl$æ¢ô‘…‘ˆKt@î<êÓÅÖþ0qy:)@©+£ y L&ÍbEžŽÂfѧɵ€HÕç ƒÉ}$ ¦ô‘1xüº²‚a?V÷¦ã©„"”át¾xGol6¥ëçÍ[Óiñˆr°-½;ß•ôì• X ß.ÞãìIGûÕ ³øÞôx•¬}é¤ðAo ´̹9øt#Ý«Òujw™óL¬5Œ å­Céh*“¤:”;ê‡A9œNþÁÿ„ÄjHÇ @<ÛMÿ ÏRãP:ª£t,‚ÒÉH}øîàT¬>¼y¢2ô[À3éñ‡p:º÷#&Uϧ2±ÐKHøª<³EQ—᯦“–fÎàÉô¬öj:=«ÅàEÂàÈ 2'~¤\%ƨ>Ön+Œˆ¦b…¹5_¾+½¨–Áÿb‡æíô`&¿“æwgü´³g-3•ÕâÆƒôxuš‡é^SÄ`ŠÉ«'ð¡Â#€ChŽÅs‘–x‚›­ú]JRY/Ë☽IÑ[”d^žáMöjéXÐø_Pk::¡'[ËŽõØë3h{¿pqlö3Ðy`žD¶Œ(7"C¸¡'¢È ¢aDàêsX¨MÈ ‰”A;-ƒ$vz“%ÓØŒî|B’iB†Ø¶™ª2€L3Â@ ‰£òIñR:9#ª–„¾˜€88jMhv›ºÊ|ZF¼$ZÝ(‚33tañ*é¨ÛZ/>‘œÓ3bò³(Q—Ö¢Äl¤Ä$Z n§ádA'@…‚ 0ÑÁDƒšÏÕE8ÔhËVdðE‘š´ÇÇMbô^TY–A#Ñ£<¾\Äõ!Y‘A]ŠóU&ìiÂ]åš$b®®¦@…,¢AŽКõ4A¡°-“óÐHØRñ$Ò–­¢-[E[¶öòÂ^ÙKØ«û2øŽö ß™A|uìwö{¢Øï͈÷Ý—AÆ}sûtñ¬cO#K‚¬¨-!¹î"é`ˆbḐ䡾õM±UÏŠN™eSSp}Ò¥7½\4ÍÀ;šÁOfRj]mšÎÒW§’º~>C¬~³uݦ‹übFœÆÐ¥Œ i }ŽW2`wx-ƒÔ ÓÏ¡–(VÝ^œ†Õ‹güFV‘[o'¿…eÿ ßÊ෨젮ÈogOMLXó{Ðz;)ö•ÿƒò ƒ?ÈxJï?$Ľjɬ^æˆ×!,Ê…¤°@EBœUû;Dgð G\{9D{* åf J÷0GˆÔl­8pè­é€ÖŽuDÉ5Þ:¸SóлMñÂØ¡O¨“´´®uð)qJW]SÝùtÌK‹a^ªuxq7 PÀ}×lGâº{®=ÛÐYŤ]À3=Ë€'CcÅøæ ~^uéÙÅP2§€KHF‡ã øð' jÉ„>˜IKú7iA`\;>¡]ÜYœ22>m¬j(lqÂ>óWÇm "ùg¶ã5íbÃF-¦«ÉÓ Ýû¤GÑNŠ1»ŸÛ.AßÜ‚ oüÍ/àóàsü¬/ð€ ë¡ùíĹÐ,©6í'~KZ)iQ;¾¤] ¾Ï:“Ly—êy—cÞº¼ˆCÈí)ZX Œ.—_.}Ho¼QÉlVÚ| ‹ÿ¡¡c¯EîìjVºÈÝÌ&|È^ëµØÍYébø¬úPÊïµÄ½U*]‚6DgçÅYòÖ‡¿ƒf`£5 CÑ"½ÆPãÆ,„asóÐ$ͳ,ÎòªÚ 7¦÷áßÅèå?1|?^#,hut>V dA~±h1UðП¬”_~¹tSÆ„jâ÷ÔCŒª}÷ÆŒ>h¹ƒ¾âGí|rJ·fñq,ÀÇ3ý{[ïFú~Š6$)›Óÿ!ðïS¼Éð”wA΋€ª–†Q;[³¾˜ôÂE¼Jbè‘/ˆU %u”׊if£5˹yf^˼(’yãK03ൔÁÅ2ïÅÌèüm;f^ˈdÀ 3oÏâa²ZI ú;Ls3_dÅøô–§z.wÂV­Ìƒ}­VŠñ—ÉçtC3[ñkÃ5Æ¿j¶d‰§¨¬;¿Æ\†F„”7¡æ€9úNEºòxÔŽs†Æk¶d}K gYeHü=Y²mk3É0`Üb°}Ú’Åo#B«é) k,#ofP]™Ä+$ÄʆïQKX˜îž!RnñÃï.kô!RÖƒƒßgR}ëÛã§ýUò|ç,[)U¹_o „rë+ä7©/’l‹K2Š’QVç)²ª}Š(N‰ 8Ejf_½Ç¦ ™7Ä”6²ÕÒÿaí;À«:®üßm¯¨Kà›ÕS FW€œÄ~©Î®Lp6Jv•K‘žâ·Úäi³›,N6ûO"ƒé½ $Ñ{½šÞá$QMïE#:Ðÿüν÷Ý'Þ|û-zsïÌ™3¿93s¦Ü™3”ýP8‚L§!õ©Œ{ðir¨@î&;óäHñŸ˜[l˳’‹H¡ÆJ¡FKåP˜0;\Yû§¸øZƒî3˜PÛÈ æV¥¡ìVfKó+¬µ˜ÔÌÅ=¤ZY@üU,í@r–I÷pœåûˆMÞš—©«Ùêl‰ÈZì“ÌrÜ’Å„­!í¤9?DØÅLe„"F)aS‘†õ¥¯Ñô %7F)è—Ö¯¿_™Û/É0‚S¡ H*0<»%I<>„¤ÆƒT¿ñ>f–Í@H^&™˜cÿkíÚ¿Æ­j”P`3jÿ:ÎÚ7°R1kÿJE¬áððWPo×*o‰õ µ†Í™bƒ"œy÷$±|×Û|?_ØšÚ ¾ŸÙ­ê¬Å÷¬"΃ÏÖLq‘7Ø‘o"òmм‘7Ú‘ïqäio8îÁžEÞ’) ò&Žœš~°Ö?w6s pAf£B³ £UQ¡bsæ®-_E`5Î.pT«bªÊµ/wršŒ ¥lL¸ŒV¬WCmÀ´1y°…côªc‹*¶©„i[¦Ø¡†ò6eš¶¶gSOäü%hO0í‰VŽ0´ôM NeP>¥ŠSj¸¨G¿òõâŒm˶žU‹.¿8™múŸWC‘â“qQ¥Ñ‹H))â² åÍL“Ĥ³#¦ã)¥¯,ôY†ùJÝ—BǯËDtüÎìx£¹OÅéø]<ÔЫ‚"Á_vdb]ʆWtz'ÊãŽLê\"¥;3¹wÙÍÝû  ø1‹ò)ÇÅOB™¡ÀÎ̼é­$‘‡«0²aL8 dù&Y¾xV"cݵ)Xdv˨ûÛž ?`Þ× szæ÷X/6Vň9y¡‚=™Ýöd:JwgŠôß㞆lãÒ7"ø fY(°eÉ6îN#ï¡Î©Ç „µ¦"`:D°?Û¸ÃæZÄ\IÌG'ɤž†«ešÍVÃrrÐUsâ±;3wÙ3Žk©× ó¹Ðݸ_vwf œYÊ{Ì·}™¥{3©ÂG“ºlíU µ»‹¸Ù¬¾}‰Ú¾Dko˜±.ko[þë’„ö%IíqÃYNÉWÚ–/ö•<ó3_ÅGÇE‰ZOP‚3=(_!gFP¹JÎÌ *È™Ô%^¹ÎWž¹nð`î›vOyn“3;˜p׉ï‘37˜ô9ó‚É÷É™Ly@΂`ê!R™ ƒi‡ÉÙÓ5ý(9‹‚÷¡Gƒ­p7LM°õr–ŸMÎÒàÓcÈY|f,9˃Ï~¢ˆ;ÒÏ© +IÄMŸ©á@¹K_Ì=íÂSå©%)âå½2Î;U4IþË¢qØŸRCÏÆ=Tå²?ÕH¥€Œ ÙA]dX/ÿz Æ‡Uœ¾2¯âü»ûË¿w(i£„P¿û’»Mî¯%ˆ—H%õ¨éÓ¨/SY0´SABn)0(5wh'©¢CúÓtÞÃAl¼o¨ 3"JíçŽâŸÞ‹ f1">hœAâ3…e± €¸[4»x‰OŒ±Þ‹Žt*”**¬w16FIãþqnꎇh&=!>hl\Ò㓞$Û±‹—úÄäø¤Ï{¨G·’®ŠQÒäb¬›n® yØ$¦‰…ílV˜§àgÄ…(*2ºcÄ/ÇÈq·Ûl9FÓ³$YÌ5_‚²9/î•’^`¾ú“ŠOib¡õ–\|B£á¥499Æöyhø°É—%f”vÅãSh`a¼äÝIpˆr8°NëY/VÒÃZ —®’‹¼8šßHv*b¬‘£áÀt­šèÖÊ8®=ƒžKÔ´íXcˆPຠC®-2(p§àV9Œ\59Å69ÌÕŠ¯;ÅN9r<«qÀq yž®ù3ª‹§kâ6ÞfðÛ WjÿZ`CÇvÅçž÷Ì—¼KÏá¦,)ÔfâF±Vâ¡üÍÓô¸æÌ>R¢”I¬—âWñDe«}Kæý”˜Ìû+É| “ù %NæÃ•¢¢û”Ü»¤ß—´¦1&ßž ù›~O±ÝP¦?ƒŠƒ&ò — ^žcŽ=•_ŸŸ(FLãý9d²¨3X,þTa…¹›¿olyç¹I¤¾W¿R£ˆÉJAµì§«ýÿ3Õþ§ýÏðá’¯ˆ© ù·5ÇüNð,_k‰¿ÓÿWüÏbÄ …b=#y.F2$Ïa{ÄBzB¦¾BJ YB´E1¿:Ãèj”‚žn‹}î ÅÅÿ<:ñâh¦X¦ ›5ŽóÛçó–ùÊk¤ÖOéMM”U¶ûôÔS­°DOãM«¼ºL™ÆÀfm™‚Ú²N1kËÔ–Ï”'Tƒ ÊcÕ`õ›j”þ$4Ét,-mS,½äOÎ;§Éb'n÷rñI_Ôü½±p(µ}JLo‘N‹(Ô„¡ £ÆC²¨5óÐruöi¹#J\×wÔ(ÉS(ÕcÊ—u}dzëKBÙÄz3ª±H¾6øüIEœTì >`8ö«”w\“(NsŽ¿Xâ349VÏ*VqNá tY畸~„2{)ŽÉe“ÉÒ8&WcLBç#♌Ž*f—ó•é %N‡ßTlÎw‡Üã44.šV|YدAË>PXW’’-WA⌑ôRa:ƒ”ho•IH‡öSãÔG5N}ð$¥ž™Ï``7SŒ±*jeÞ~š=|ÂvZyW/•ªyßn%¦A©ZŨNžªbO‚2]¥™Ì/ø.>RïPƒ2Ìò—w0öEtÀVŽéjtJZ%_ާF©0y¢9GøÕžFPvÆÏU zDI†Pr·¤I4Nqk¬£æQ¬¦éÇhQvMÛ°]ÐŒAA‡(6­óbx³P5^Û¯óº©UªÑ@£1K]‚@z7€â|ØRÕÄ:S¦w§‚Z¡âHÀAÞ˜qF‚,Ö[²XoÈb½!‹†,6«bÓ—É`³)ƒÁÁ6C/ó]iF¦é!– qv¨fÝØš&³½ëI€)šÙŒK9ûšå7ôX~ÃV~·P~qŸe”MÚÆ¦E”ßNËÍiÑršíÊ„¦E‡³šýåñû½ÆæK/.ÔI!†wþÚiJéB½Aÿ²Ü¡p‘Þ)¥x½}’¯d.ÆÛbz—¯æÖèºu¢1)ˆó5b{%ÏùJƒ4!ßõ*%‘ïþzƒ4éeO—ib~ÂkôœŸø ‚q$÷5® Š7ÍÑ›â”î‚Ø9òrøk»65¥ÎËø.? í¼<µg­ø(R0œê¯ªžµ| ëÛ&u¾zý!•DüÌ„Žf«ª¢þ ý õíâøyƒ´Î#ýW™Ê?ïDÓQïÕèaì´{"Øg׃ºŠBúŽ|3\ ¬ðEª+£3]*AøKYéCÈÑorÈY ¡˜Eˆép|ž­zu˜„´KÌ´K8múí×E¦ßþ]úÔE¥ßé>~gøœ%@æúøMA—n]å]JÜ"ˆÍÃý®áyUeQæwGýjÞdzü7¿–åàÆ¿…áI”›Q‚Õy•%ñô»"•ó?ünv,Û™¨¨½ëÃ÷^k|õµ‹o¿î„ÎÉ·²]ï·²M÷ñ­l3||+Ûú :÷=µ!äl:qÕÊÆ k9›‚îñn6!‘a¨9’žVú0`%…³x\¡ùµj¿ÓאַÌÝ÷u©x•—™l{R·RAOG¿‰Û¨Ç¹ r—ßUM¹pÛäã%âáWuUϘ ù=YŽ$ã–lŠFÿ«|ÃA;I"¡ódÉïÆÕD!óMפªWû䢅úPN•¢7tH7.·á1Û¦ØôL—h2)è„­KäÜ5:¬°$ˆ¸ ™ú­°­‹™ô.Ñ{Dó«ðHÃqù ŠP¥ÅKΰîžs¨£ï&àžèã…‰¸'zO0iƒÉÃÉÙLMN(˜:F§aR•Ô%ÎàµÔ-ÎâuÑ#Îá•1A|ÁuÃÜO…ª‘ñ†éž´V:…#¼—f*‘ít³Š¤‹&©`½îO§*B?-îÉ™»^׺Š>²ß­ÎrðyÓ¾²Ñx³d:'²)Àþ\W=~µtSr×øh"”ˆw,Ú øhImGK@4w,Z’†Û“) 1÷Á+Ru”FÛÆÛ´ÎR5ÑVb 8\ö'SKI#èÁï )7’é=&I3—ÇýSÄhÂÄöP-æ Æ›ÍÅ“‡(°—nxšçµf}:“­¥(ê,®Oçù3æ”÷ç¹òHpe8·º*WȹÝUÅåëG‚ÚuT¥ ó9Ÿ]7q{Ð}‹ë‚ç׌„‡\›¸f$•«â å¢þUF¯Š«ÆK„ûˆ*Vu¸_ ¬õå­ó)B(‘hîzŸ#ï3Ÿ$®+„1ž¤d–£ÛJùT›n°ïf¾.,—˜´÷b¾nÜoÒھܿÁ‡þe£Of–w —éáÂ5>ðp›nqÏðð˜ñÀªN ¹\öÑ+¿Óè ¸wþQò‘’ǪY¢h²É#†ñE›{ä‘8îI¢\}Œ|ä£ä1îÉX ¢F¤rMù˜ž“©cEåèCÏ þD_÷¥ç$2¯û©˜êžå9õߣƌáÕŽë]cT1V SƒÏ’æ§ðÂÔ¾ù…ïlù„Wúxpk®À 1;—ø”¢Žu‚ÛvÕ5¥ñH?æà‰Ûv•Rlpª^Sàìi¥Â9Ôàœ :áÌ~ÍgÖkn8Ó_óÀ™öZœóÁÄ9‚IQr.“÷“s)˜RKÎå`j=_ð3´SØüÌ’`|¡ˆØßXö©˜×¹h0ÞUDh¤T´XÇçÒ`Ø]ÂïU=yÅS¥¡oó@˜,ö«4t]¬s—T«úçTq0–zEóÔ+2úJqX-Ø­Ó/ͺÄ…#Žª¤|Rswë.ˆOœPýié?ÃM^W‚i§(WWƒé×TÜ ´M§ßpTœQ±á[œU‘ qÎàrÞà²MOà9Å%R)Ƶ ÁŒ+Ô|Õ‚qsŒhîF]áöÛJ\%%S´H¯Š¤àëEƒÊ(®«Ûuú%œ7ŒônéÝ2Ò»m¤·ÓË÷T†‘ž¶º¯Šûœ^Òˈ¥åÑZ ú9‰ôsÄÔõð¤Ô¬×Œa÷#BF‘TØëf 2|ÍÍ`FÄ%"g º©(‹ÆiÌåÔ˜lh4ºŸZ àt…a•¿Ï7á¢Êd+;É~—•ÃJÙùü“cdç Dáì“0œkI¤ÿ7.=‚AVôÐUÜpëì©â¦ËXBO·p§QšUWÓŒºš†ºš.n» vé˜_…k>IÚ©þôÜ]º&ùYÌbu2Òý%êäVwÇH7«8¤Nà:Cê©8¤Nà:3ó]÷F7”„g“J"a¿›ÕÉA7«“CnV'‡ÝP<)“žTFÏÿ";<ͳ3ÌóˆÊþ$ #<-ˆtôÿØG0Œ÷˜*c‚*c’Çè•SÅdÑ+§‰JÏ“UF•çKTÆål-CQWò"E‹^ íq[!¥‹æî¨ñ ¹Kpnu—ál *p¶U8ÛƒœA'œ£NW ·z7œ¾]<=Ð ›<¬&6“ÓP’%gÔ¿$ï'çM ɹL­#ç^0­Þ#ÖzÂhÓ0šórÄjÒë<Ô¤£ž¨_ WWE¦ðÞœæÍò<±†f~_°Vjë8Ä÷ÁZ~¬÷øÝ‘jjø™.±“K°;…ã¤Ct*HJå;J¢áH%ÔIæ+IðU†—Åm¦Nå1æZÖ(c‘á®'ñ'VW…§@]ÝCÁÒìŸÕËÀä%Z9ÜÈÍ dÆ|Mƒž”! OÊÎðÆó.Ÿ&ÄãG¥šœne&¦'øÝÃc9˜—ð¤̧xqYX—…Å °“x%;!]Q·'  íH0׸ÁÕ•­%8×»Èp¨òÀ¡Ê‡*ªÖ]ùðñ/ÑïæoIJªüàDªòÃÍ®ÉÍ]SÄøØëÄF™Q3ì¨à8ÖL(½y¿ø 8~J#vg÷h·X™ˆÅø–z½$Q•5b…%a‰ÃyÅeâ%có_ZSŠ˜™È ·fļ~n¢?ÉFedÙ4«4Ü@8pLj™~5oƒA B"ty"ÔE û±ò…Fz—Õ™XH½KÊ4“5¤îR«{ÖŠµ‰<Ô‰M‰û8"èÑÜ}º“6Sïe^ ·%‘X¦‘–žß«—±@Äo~§ý®‘O¤Y8Öéݺ˜h+$XÕ”»è’zYçF·AˆFp2G6z,è÷턤«ØÓçðнq@÷ý }9ÐpK@ç1Эot¸-Ñq@þ=ÔÐy1 ‡Ÿ,Ñ# ôÄ#@m‘žŒCzêÿéé/GzæÉ"=ËHÏ'B£^Í–EË;JnòÝ%Ké¸Iªî~PºIª.1Ü!CFïØË´Q' Ä]ÏéeùÝMĺ0† ¶ß½D,cìmû}‘ˆõd $l¿ûäw¦ ¶¼ÌéeÝšø€üÎvÁÎj¶Lõ01LÃ<@`×¾![Ñõ ûÄ—0ìÂ% »øÊ@ÊÀ $ÎÀ $1$ §Þ8"¹i¼j½É(OŠΜŒá1>,’‡QœŠ•á4K XŠáLÇŒÅÈ$|Vù0Ð$gŽ9EÞ’á-Åy&oÙð–ã¼Ç·bx+qÞä­Þjœ÷XòÖ o-ÎûòvÞÎ8ïqäí2¼]qÞãÉÛmx»ã¼'·ÇðöÄyJÞ †wBœ÷DòN4¼ã¼'‘w’áç=™¼“ ïä8ïJòN1¼S⼫È;Õð†3§«˜šÔ¬¸E¶æRÔ|”ör¾×ƒF‹Ë“x´ç¨S†3¬»çaP…ÓÔ–'‰uIp5‰êתñ1¹J¬OÂ÷È(½W¡r8³UjY`^›d^¤PK ÊˤÚ$QŸTÑÃí"¹]!âk6±°ˆ…A,’Ä5&~É"¾ž­&*êjþ*r'ɼ‡¬]‰³yiwÛòô³¸ƒºW&ÝaN2œÏÞQîÑ 'ÉÚÕ‡=Š–ëm[÷Á!¹p¹^”¨ì¤÷*Ë}ØQ*^®‹“)¼ÂhUFØ’û/ïë“\¸T/H4uÄ©¦â¥ºè÷X¼Þev¼þÉ…Ëbñ(ÀŒ·L#’‹–LjG&.Ñ ÆKEõ¥¾nã%¹x‰.F'GL«RE+õ¶ÆÕ’c’ WZ”âÛL¹Rc“‹V™¬>I.\e\0Véi{$œÒEý4¹Aú¸L[JNŸ2ç²dñir8ð™— ¥LÄ='¼»·}ø5Ò}Ãé7¢û «O~»uxIÆ|¥¸ÝÚ5%YLI“U>¾—{Z²ßÝËüfäw­ÐçVX›ëõù¯øÝK2F"êÁï¸g$‹YDÜ¡$P…~àp'è—~VTºbN²ßºËÃ6]Í5JÄðµ‹c~³VQ £( _»%® §x….–&-µ²¦ÇšKœbYrÑ2Ûs<]b—qÉô‡|ìw%É,LEÀóª;K0j+VáR˜gøÞ®B``³ŽþZxn¤Ö:á'>Kö;™Ù†ä0U¢.êЯ¼C-Oc6QIa›2<Äøä°%`“^ù:”蜊ô´‡Mb 1§Ftƒ·°' ¨!í­*7c›—Éçk[ÌÍË+”6¥õ™ðÃæå[Dätµdkàv¶,»ÜY+_s£w/¥lÒà×…çÔ¢ÁO•žSÅop©?‹ð?€xÄ Ž?ˆÿ …²ð9Iü 7e«šË½QE?>>Ù¶|5÷D}Ëø¨£4P$™×Š8–cøT¡O”ȃùð£2DC¤‚ÕRѼç"­¾ÜÕ’Ä<ÄPɯÍz®†o&ÌzίæÎzN Ì®g=›4AcjÏz1J¢9k A­£á'T~U])Æà½Q­$¢ )­då%“W¿kjŸðQÐ{¬S'ÁRf~V°-vÌw5ýÍzÝW*mè_éLÐ@Ð_d;$EÁþÔ:E—[Sôõ/‹ ¶ûÚv_¥”Êd²ú“l? Ò ¡—ÅwLßÁË÷¸<¾K¬:ÎJ§Àó½Pgñ~(pge‡pÄxÿ'"F‹ÿ)>D Þøì žË¤Ò"Ÿ0›,D Õ­³Ì壟ñö*Vã,ó( !À“Y=I€ŸP{q{~òÅÖÙòÅ’XB±ÂZGÅRé-±Üä‚+)§ZXãËäײ¸ød–X'…ò®Á=Ÿ =ÂHÏd…W3‹¸ƒüâ–‰™!‡a9æ¡{š7ø ?“tE6+›ù+‹q”è~3?ãå·Ä§²ŸI2åg¿–ö=WËF~Îd‰éü œÂiˆ„ñ8…OÂRV|9 æQ8Çle²ã%ñ9^-‹åq9^A9®£¯±s¼öoËñz+Ç+ÇuœãJÎqÞbåx‹,¶Q¢ufŽ·SŽwÆåx7r\§á΢çÒ«™b¿™ÝvvOÄe÷JŒµpvë‘Ý*»š‡…—“r\5««f¸šUÛÕì¼ò¼,.R¬zä%y%d@ÖÕìºY,²Ä Å- ˜b£Àæ_œ¶QˆCq‘QLµQô²l¤ôRÄÇJ(pÀDÑGyKôSlBqÀ@1D1P\ÌCÅpXF™f£³*c•8ãP\bÓm-qœ78h¢¨$Õq(¦ÅAÅLÅ¥,1ËD1(fØ(ØâÌâx‡C1ÓF±ÂB±BÁÜÀ!ÅjB±6lÒh‡ ›l›M[b–bP„ãQŽCq™QÌæÊûÈë-õŠ8H±›(Š#q(>ŠÃZŽCž4QPc<ÅØƒõK´Õj´âÓ&¸³7Ç×pñàŽÄ»Âàæ28?Èo[àn+â.Å:b‚»GàîÇ{pG´´v|PÕGM§·²‘ЪÑà>V d}qqžlލŽPãCv•‘Í· o¬ji9UŒ£XG--§’–Sã´œJÈŽ…Wm"»š%¦˜(¦ÅY¸=i`‹³ŸbÑ5°½/NïëØl¥·Y[Õ08½m”ÞØæiÈ;‰éÍ!vé"fš‰¸Áô°Z´àë|ÔüžІŸ«YX³I¯€´!F*˜]Å5ƒ´FWHÝ~Áƒ”ÞZ¨s»:Ö¶}4ÑG+‚ýÚ´0žÒÂE›µšŒUšôÿGi¨&†jÝ_Lyáe˜V°Y çnÖ¤À½Ù"Æp&‹ šSña­E,C|í>Ö[¡…òIˆc5ölãçHñõ,1^c§uÂa;-RaÝdq%óC¶ó\e“V¤bŠj[z%SL×Òp0m–æ»jÅ-œÞŽ&*s4í]&!t€ –jæiÉ¥—\ª‰åZˆOg®ÐB|8s%¢,µ£lâ(Ý›(ʵîÒ&Ml¡(¥û5±•¢”Öib¢,Ó%*üçe·fZÜ­‰½šQÈû@³\W‰ítDµ¼³/½¶myH«(s—©~`Œ ‡4qH3džµ‚Ú‘~ÝbÆ|T ¤²1,,½œ)Žkè)[ãôùI¢¾aP?Í{ò ÷ë ¿Fî×Å9#ÁV|ÁÀÍîÒM\ÐBÝ.g:Ï%-Ý•qG44Ð+x<ª¡E\Åc½†¾¦4(|ÇCô]#ÃÆ×ðÑ0»ŽÇ¨†‘Ð <î× ~nj!tÃhï· S*Ò;× nï?†¸šH\â#§Qs`\£7?³x¶û±3¤ÞHcŸÛYÅ}[§aÜ×ö¼•U¼Ö)ú;‰éJÌ\i@l‹ vǦ­:íÿjç¢(ÿu_Ë3×6¥—¸¡a^°Šçwï?~ÀyÏÏ$½ðó—õyo”~þrƒ´<_þFa­®‹ï•Öê ÒÞŸ)ß/<ö²>çÒcºïgj·Âã/ësß(=N¯¡Ÿiù…'^Ö«ž-=ñ2ŒµéqF•‰î0Ò›µ ¬e9kYG³–ë™ðºµÍfŸ©q³Ïu:vowk\&Þ@ð‚§oˆoí‘·Û§Cm|‡žá(¾Ý^|×ð-º‘™;ª“”ÕÄæ¿¾óäY1¦ØëIçó>Äómðœû¢ãm¼ü#L\å…Ói<$~ú–ø'j(73Å?‡73õ;C <Égñ? ãèRR`.MZî~¿`¢S]C/ wØãúk¡À}ã;{4’ÇÃã]Âö™Žk=†1¶ß› ñ÷lzø¿DÏa“:ËØë+úV¿â[™âÃ_Ós+3Ò;™â!xÂÚjéíLñÇPàv&lþÊÏÁ0왦€Ù‹ÿÑ÷ȰüÿÇ0QüØ•ÓaÑ쟀ë#Éö‘ÄÈzK4K|œÓÇR„„V}`õff`á‹0-ÜO²9÷ÇDb#³~ ¬Z¬¬K4e|œõ)bˆ܇Åñ~›tÜuñðiñ)áFi´$FKÀÂx濘zQ"I–«NŒ‘ ÊHóëŽ Ê Šp'Sïõ 3Eúåú;G±ÙØé'Hs3§ùÒo¥9ÞHs¢„ã×}>¤2éI©L¶R BXLÌ;MITšIT!‰-vS¬$¦IL“Ä´XÓŸ”ÄŒG“@.fšIÌB[uÜ%Q-#ɸÚÖ°å\c”Ç r>ÿ¼J¢Ù³}áë2š=®’Âår}Z9:äõ,âh ì+^ð"MœÓvÁwû¼Xä7.ŠÜÌy»^tˆ-RÚ Ðl'4å¯Ð¨¢…Bß«O{Ìú´€ëÓ>»ü=¸}T¬–¢ˆ¯D%jšÈûUó¶SOÞ õÆô”p?ÕwÛVÍ+O­«F¾jTq«ÏÏijR:75å65ýº©iÌJ@VÛbz„Õ¹ jêµõ¤×ndÂzm»îTä»c †};ÜïkÛý3¥´ÉX0Üà †m]0lVäK ët}e~i¬ÞîÕUMs¾Ö8´L¼eÚ³‹tö;ý®xG~ £6å-¿m.Ûücȯ–’”~Ûº&kNÁelȱØñ[ñÛ‚gÅo‹*Ÿ-ªèT4¶“ø÷P`­«Û³jù³µâwX( ñâ‹|(ôw-ç3‰þw߀Ägá<„cY=ÈYmÉtm ê(«•Òo3Õ!]¡œ~«E;y…õñv6ê©ûY•/ÿ´ð€Î߆Š@‡y}4£qX™ø{Jœ\hí·`<Ã\:%¿ßQûŸ¡À0/L]說9§Iðÿê´\σÛ?ÑXåué¯PtüáÖPú~Küo=ë ä¥üXÿz©t°!ý½æ7j<&¼^ÑËZÚG¤,ižµ´É’ædüq5–<+â¡À/% ×¶t‚W ’BÑÒO1T 金p^µW!MF¹øœs‘´ó±¸³â÷&a‡{kå] ,]`²BWÝšsŒ êeÖÚÎ2‰s†¶:ÄGmµAêc3 ƒÞU×3Ƨ­%§Âç\'‰Ä<먇ŒÓ«yy {×Ha b‡ùPô: *ŠüL óŽÈÔpoZÌnÛÖØµ4Ñrg·åN…bÁŒBÂÊì¢\÷íå …5ÎûnòZç,ò‹~{ȯ_¿“ý~{ɯ¿‹ýŽ~¤ôA]üû4üÂlEB7 ’t.@–—ÂòX\Ð c¨pÕÛU‰­—.Oˆ|ÒŽ< 0軑OÙ‘‡Z Ce1«,+`€"ŸÖa·h¦#òL˜‘ƒ|q"Ã<^…ˆçuØõÍý‹ç™Ëqž £{OŽM•u>’¦iÀ9¤zÛ¬M ã¬+Gb›Á)ò8§ã8gãØiáØiàØ-‹Ý_›p욆ì%‡-û€ã¼n{&¾ç€ã ³Â[tR ,k‡su8Ý„_¶Ò½l¤{UWã©ëDƒŽ´Êf»s¡0º#¤Ϋá1Ü®OéX/V”ô#Š›@qÑ.Ò±X§€/6ysò€ÉÖ2Àd…“¯RD“õ©ÕJOüéë5¥^1M éǬTf` â2§ò50[‹TÖ+Ü‚“Ì|Ð\Û |â…įpÒE ÞˆÒuœøFElFb‡´VßãYÕëÒVElå•ôvƒ%¸;£YÔØß.ÀúÄ+v+h&¬½€uÕ†u °Î4‡uØ‚5Ža50¬ß‚ú’ ë’"®Öa­ÕOLX Z½Ž[ˆ%.¼¡ÄΛ¡¯¿i¢.aãž=ïá+²xÀðzi~½¨‡÷¹sû¡uEéÆêV+Œ#—£Êœkâc­àu¢ÚO‘À»Ûë $+úð±<â*‰¾¸ö#Ns ⛃¦xe1X é§Ÿ‹¥:3öv©NÅŒ}:õ(Ÿ¢Tor5ûfi¦z˜¥qÅš£‰9Löa˜«‘^‚n˜5–O½b%qÂÒ ‹Ä-»zcm«1ñÕ{yŠY½'qõ¾ÍéúA½ËJw—‘nH{4ôfÆRà^í-âwªà-¦¢šQ£—§p®°I^QOÀ¦ûL`ìŽ ì"€]nl…l2»k»f»f»­‰zJØMv›ß Ø]Ø=Ø Ø}›ì Ø X€Ý³r°1ÎfÀ¬oCJöû5¨'8M`œ l¢SLtrIÓ0'•Ôw± ï´u³¹.pæ.pÀJÒN ],]€%™û6Àõ¸¡9@ëSN Š>°n³n3îpŠÎaØf§p· p_s€!`ĸ«¨hH™àCÝ•®97& ÍÓNG0𵇩ëN|8Á´7ežjj[Þ_Âvó=Ï8N¶ïJpF¾+Ã]¦œ%gL™zÉ)Î:1æ¶uÞéWùN† ηÄ%òkõØÔ¯Ò{?oì‚ßÁÞ3°‚*Ø;¯üU‡htÒ ²ŸWÜ02Œ/ì·œ4ö7G½4ú·Et\ýŠ;_±Õ)í¿ 4+Ê´ûhl™ó9“Þu å:ù]÷H—¸ï´†­œÖ°µÜeA ·k-Ô½]<ª9¬™'WMݳ_Ã1ìþùØ1tÌ~m xõ3"y$B],Bt{MA’ƒ\1û–¼w}° v{bû»bþCÙß%F¸âÆ{ØâL‡µJ®K‘ÀíÔžØX?Ò73è",‹î.èó3ÕÕ¬þ ¡ú“ÉçVcõg†Ë¨?3]!««À¼mŽ+Ô®tˆ7mšäób%j×z4y,"ÄÕØz»˜ÞzöîØ«†¼y…:?*Û'ež•.˜AIXã‚”ĵäŒ+KÚDÎø²ää<ü^Ê.—XÆÐx¡c¹r¥‹íB²¼5¦|pŠa­)œXç,Gñ™.â3óñl± ›]v'¶ Tluùr7é*š¯ØiœaAÕ¹ÛIÊ’ÙXÃ.Ó3b{¦Š½ÌZb;}U¦}¾*.׈+DÝjŠ?õ¥œÁõÖj”³àW)NÛ¶mC‰^ê^¢>V±r%Idv•£üI̯r3<ì Aª¥½âë´ÒA^ñ¹‹fÖC¼âDó;ç‚zÈào 7 R¯¸ÄEN;=™~Rÿ«5銫 ¿Ô­¿ä`m%®ºüi`T|À'G)ÈÉrtÀ%ÎNÖ-Gõ§åõn-‹FT Jï¦]N·ø‘•ÙW˜3‹I%åuåkª¸ë"]Ú¤KÖÜï¡ËÜQ÷tŠ;œWNRøÈM4å9NUsþ4}Ý Y®8úºYÅÃÙ/Ë}Ýb€»`@RÑûä†Âb ;ͽÖ^å5ÌAn’˯ ^åĸ#™WE!Ÿ2ý´LécÜоÜ9Œ¥Ç¡F6>a_®nãÜÔ(ú{ŧîP¤t¨WLt7“õ$JÁ•î^Qض-÷UH·WV}þÎXayõGÜ%›°ìÓ׋¬èôΉß|¿qìãì'|®qb™ø‰)ªŸàå§¼ÙígDч)¾ ϸUSñ)MÃ2Á‰uS"ê›ã”\î7ATIü4)ô“‡*5x©0”XNĺf(°áùP`Óó¿À‚&å^6ÓKÑ157œ¨–†Å°ê—£RzíÀj¡5í_(a‡P8Ë8è gIô›7F‡5 ïÏôA¿Â¢_!a¥ä1ú5À<Ÿ0¯åí9ªÓåž!!æv#g?pl‡5ÊHp†v‘wò ÊÞ6©î•ÄN©èº8ä+O¬{¤(_*©Š½R–£Dý4’¢~,:ìc‹¼" óÆâ½ÒF6JñTmS“Ø/…I«™cp Ók¥hÁa_8Òí°Oæ!õH-Z|È'ðÀk;$!~£àHì»ÒúÛ“ˆ¿î›íS½ AÑÊÁW›ìÇóVçK$ÅUzP§YIžü¤_P°%qpŽJqº4îìÀßDo©è°žŽO¤}¤ÂÃzÁ¿‰¾RÑY¿û‹Ü°WÊý7©ø°.€» s$ŠœŠÈcyœTtþCÙ?þ à¿þ]m(hX¾µAÐr«—Kb%(ÂÅ»ÚPab£Í`ìa»Á`„Í j1ˆJ$Pf°»¨ƒ‘6ƒs`pìƒQ6ƒ‹Aƒ$ {Úˆk¼¹< ªAX "SpÞÞ6¸âÛúìà*Oáà}mp¯öóåhš)ÕM¼|2黎M2®i•àLû® gúw•MØ5„„q…jn¨ 6e€/ òŽ<ù»Ž²8Ätyá6’8Œ4>±!àÂ&ÜÔD"mÆEMãìà»þ‚ƒ£m`ß7šÚÁ±ú0XAðþ6Ørƒ-m6†1¼sú9ÇF倡–0|²Om²ÉÙd,Ð0Y‘UƒlbNÜöI¢ ÏI9Ö‚=ùü¬à¨¹`¿EiS:Ý ?TéÉ9°=Ű&ßñ^á1=«mé1ªÅkó¥…Çõ¬ï—§·uùòû…'ô¯•K¥'èõÞO•’“ôª–ž¤×/~ªþªð½ºKOÑëú|í7…§©³-=MoŸå;ÿ£ðŒž%—ž¡· ù®?žÕ³”Ò³h*ùîRá9´œsôº)ß3P*<¯g©¥çéus~ ©ð‚ž¥•^ ×-ù‰ƒ¥Â‹z–³ô"½nÍO)^Ò‹>÷eþ³ô¦£ø’ŽuõäqRáåø…õËä}ÿ§)ãÕÂ+z§¤Ò+zÑ%JZáoyÀ=„,ÞÔÆª2Ñ™Šò,À¿Š c9¸-ðçðŸfÕôiwZæ-:¡Ïl×3¡¼U^¾;…ó¼g,/1Þ:ÝÆrXζĖ´q ,3rðõû]Pß´°Ü”Ä] VWsWëRÏZÞòù‡û6Ãö€€=Äbù ¯hŠÃSަ>ÓÆÓš—æ=Æ WåÍžY6žQÖÊï(š†ÈqxƵÄa¼Lxfx&û=Ã¥3iŒ#Ûx&ÏlÏà™Ö7l ƒÄà 3‹Á Åø?Â`ˆš6 †ƒ³Ì`xŒ‚Œx„ÁÈGRÓÞ'lL­\ ׋^* &jn`À…ýÕ¢ ¦‡„ËNÅPµè¢éñøÞåù¥MMʵ‡M_ojúϦ&zcÔ/QU˜IŸ2“æ[RV³x÷(o•êÜ®G밃Ԯ곰 2£Ø1MÓÔvµiÞ¥¥ªGÌAO´—QØ[tE_Ð!ý,¤Ì5fxMÿJÜ\‘%ÓSµE2Ï ™Ù2I+Ì7HX$ >¬ Õ´£úbÂ"jÔ´^–à%^ã@sX¦F²äÀ1Ÿq‘/ì,'/gs¯äånîµ’¼à%żV‘WŠIE©¯VÓ~‰{D:ƒ]ê­³Tªñ…¶H¥ú_hKTªO.´ÅTh+6uijúAS½ˆuj˜—K×›…v’«ŸLÜó2ÊqS¬\¹ÆmA±®ÉÁ…/ƒ¹ÕÔ«Æ!r>µ×ÅÏLë<œ»/Èõ*öï5r&/Á¦×/þgº„+±&uÄö:Û%R‰µ©ÏU«µg`Wôq`˜ç W–Îóâ²NŒ‚"•¥ó½â$^x£•¥ ¼â´j¶™=°Ú3û)å¬*ÎÆÍÏ©8qͧ®ùÀ1ì~ªYÉ|âú˜/Â^à•§­ù¢ìu‘ùøÕâM>q™ä9/²`%Ã}®Íñ(ª¶\‚TîòŽçÏÞqôÒÄ}[Ðê8»]E“jk4¶^¢J­—†ðò.µ¢·nÛúY¶ââïZêJk¼·L¼DßW óZY­èôÊjT ÐÐÓ¢«Ã*ê÷Å „àòÆä¸ñ­*^ Ѱ3g«Þâî‹?ÂÔ¾ãCžÔ¶5jÇX-æå²/ß0Ãħüæã¬•ZˆÔŠ¡€«ðÑe}M'µÞ*xÏæ½¾CrH|€o\¨äT}[³ª)/8ækøÞE²Î=îs€Ÿ½°2rÌkE—õ)%.ŒùE ?©-ŠùE ?ÊøbøÉF\ ]jbï ãˆ%±÷¨†N}™)mÖøL¸¨ÙÛb~ËxlJ™´‚÷JØ‚,郦ÛJî Ÿ„ ®ÔBJ¡U¨¿«ðŽ/j‹èªðj¼ã³Úbz_àåãÃë5^2@SœÏbïšâlˆ½hŠSÝo† Ïè­±mf«†õóKºÑ´ `yëtUl£¢ÁÔ‹"ƒóvãBãMЖvòÉy?pw”äºÇxUðJbÝk¼ªx%©î£XÄÖšu™QT†ÏrR¨2ìâ†r\3ÊyMœÔbí×Í[µ!×®âŒÖ¼¡œ5Êy/ÿU­¸`5”‹ÔP~ÕíWh(K¸¡üÊh(—͆r å*Êò|wV¦ˆ†XcAG#„†ný7œÆXâɫÈIÆÊøNø:7ž ÜxÞCžîY瞆ïÒh<­Æ³Ä˶v{9ÆÀz;ü÷1{…Ùêw_gˆºb£õÃw·±Jäï Nš [•6¥ËðKÄfU^¡¡ 6‘æÀDÉ¿5N-¯óPê9Çë4´)“¾-¾.ú^¿òïÕ‰ïDøÛwÛvoFÓµ˜ëH`¿p7Íá<Þ£ùÃHW‘)Zí5¶l¾E¯ÝB‘7qY÷–ܱûU$›g&›'~ŠIýÏh|¶Æ+þ [CyH–¢Èþ%Xã \râg;äC ù#‡\FÈv›ñ_Ì¡á_øvú5Þpñe§ø³×½ˆ†aö:‚ÃWÀ`gŽq#2…µæªc%1ÎdqÅ)ƃŮl*ÌŸ m°¸êäÑ=ÍÐ0`¨&Ž»yYàM>²Lt&-qÌ­MéG¸9)=q/ï±SÝ€T7©6´ê^›4Òý©ˆ‘N‘î³IOôŒAÚØ×Mz¤· Òk-p Û¤±)9\o4bKhˆ5Ù"‹arLBÓŸ ¡é–„®;ÅpLñ¢vÑNBª•Fª7P´ûí¢n%3]3e£ho8#—µ6‹å`±Ò`q,êlë-ëeÌ©™ÅM§Øõ6‹XD ·Àâ€Íâ€Å‚—> ·œÆÒçA[|Àâ’Áâv …rÈ&W$‚;-Hú°M:³œ=$‚»-p=bÊ(k–5Já ëßZmï:i*Ky9j§:©N7R½×ÀÏíTçZ©ÎÅU{U¸ç ê1;ÕØž8¢û¢…¼·I÷‚4dÞoà »hô„AúE{Ò.ÚsøsЏ EûÀ).Ø)›Å°¸g°x§måÖ‘¸r•ýßOI,ÎØ,F`3Ø(4ÅY›Å8‹Å8UL0Y49ŧ`qÎf1,æ,Ê]°¨n³Xl±X¬ÒÂ`Qî¢Ù±¸`³Ø[ ÅE›Å.‹Å.Uì1Y|ä{ÁâRŽq‰&‘}Ç9<¯—ËA£xlld6/"ü³¹êr\‚¡}f“×Û%‰« »Â%èe™‚Ï=&Àu¼áU›¶öõÓ˜¶Mk׌†êµv ií:©5H¡÷¥‘šÍ1Ѽ¾.™ÁØKh÷?“5Ó†ÑdÏâan?z¿Æ85›84°V{<ýkqj¤û ÒuÚãÙºnC=kÛ;kÛ;«ñPˆ¡®×d aë¸ÿúëÖ™½ëÆ™½ëŽ˜½ép£›“ñ%­çÐ,OyT)ä}FéßFú7ÍJ€3Ô™©&áò¥[vÀh+`2nÛ“­€JÜa©?‹€Jk‡¶Y¡¦U"­»vÌ9VÌ*ļg,³ªð…Ír¹År¹É²,ïÛ17Z1§ æ;æ&+æ&3æÄ|hÇÜkÅœŠ˜MvÌ}VÌ}fÌ©ˆYÞ1ósb~Ô1ó°ó°sbö²cžµbNGÌÞvÌsVÌsfÌéˆù±óšsbö±c^·b^7cÎ@̾cêá!v©aEž‰Èýì°Á. j„ÍBX;lÂ&a³6 cL­LtY§Ü]b²ËHw¶&*±gb ÍbXÌ3XÌ‹A6‹‹.Þ˜s4±,w´»°Xo°˜ÛBËÒ1Öim°8np‰M®¿½Óš«‰ÍHu¨ê^¤2Rׂjf§±R¸Ä~×ßÞAÏÓD-Rn‹ëR=a¤:âa‹ë”•Ì)—8cŠ‹¦âgÁb¤ÍB€Å5ƒÅ°e³¸a±¸áâ½/`±@·Áb´Í¢—›X|ìf ÁbŒÍÂØàB,úºE·Áb¡&`I…Íb4XT,ÅX›Å'‹OÜb¼Éb‘&&€Å'6‹i`1Ã`±,ÆÙ,fY,f¹Å“ÅbMÌ‹ñ6‹e`±Â`Ql«,«ÜbÉ¢FkÁâS›Å6°Øa°Xm»˜Åô2Ç.·Øc²X¢‰½`1©c¬+:Àd ï:¸Å!ƒ,w©†®h²MtÆ":ãçL¢eLTi]c¢eŽknqÃ$ZÎDU6Q“EÔäy ¢LT×ì=höX‰lMaÏq³÷˜“Âq1Áçnõ"öÔŽªªj/óÞcöpÓÙ2µgf™<Ý#fzp -w›V§ÙéÁ*¶Xj¤·éM·Å¸ÜcixXi.^£‰UÀèètªÚ@¶Õc€ÛJ©­|U‚s7I†sà9Αª[=b»ÁûüZÞÀNšØN3m íô˜[vzÄnSB:#³l¢½Vr{="dø:ˆf³ :qÓ·ˆ"¦ˆ)âû-yk;)¢æØÌë­xõqÐd~Êæs™è›<”b¢ w<âÝN®á3õ_x n'ó¸év²ν“,u÷=°z:¯#Æ!y<ÇH0ãJ€x¥A bHBŒ –c†&ij‰äÝM–Ù¬õð„‚{Oé³ÊºÝ{JRĈ|@ìˆaxÀš€«Áé­þ¸0/¡à-æó–”·-Á!æ#Ê;Ê DYÕ,Êê¸(Û)ÊDYhGÙŠ(Û›EÙeEÙ‰(‹ì(û¥®Y”ú¸(;)ÊDYÜÑZ§¡HÙ§ÍušmJ›ÒÕ<0ÅÆšŽNIQ_z|¯Óö|©[aƒŽô²oª¥ 8¦¸¤#NÒ¾Õ8»LøÍÛ‹ý|y±Ÿï.öóÕÅ~€…– …Ko§ŠÒP¤ônªø×P´ôNªø5ŽnÞKeÛ|K;j”­¿C\‡,ÖJ¯„·SC»ôw‡þî¥v{»y–qnž§Üí7 Θ¹ÙN¹y^ÈÌòŽØ¸õÌã™ñ‚ô LtÄ.˜ösÊÄ)±(:_žœ[(ôPÁ>©Û>Éñ¦T,tÑ•‚(Ñ•‰ª:PBŒ_°ÉÏiÜ¿ÀY‰~ç–ɿ೩ô;âÇ*ýÎ+svÝýÎÀY_àœ¯\+q‰wý®¶­ÞÄBíÂ2WÑ#ËQâñ»z•$¤µu8<þ¿ç6ZYP’üîÜ$Y­úp’&z¼šàI¯ojr'¸=¢Ðtœœ‰Ÿ†:¿Ó¡–r»¨ÌñSñO8¿¿²cyB™$üHAjkRßo9¤Çꎤˆâ¦Zû#^þ„rúo|Mé¨&¨ÚžÃù´\¢¶-¯“pºGÆé §{vt — ÎÎ7äá’)…‹úJ5ÆŽñpîyŸ#KZñ]þøñ-…§S¦Ýá^%\àŽËÜ^°Ç!t¿JÚc‡W!¢W=îôã”UÛ¶±—©“(•š2­JbÙΕÄ$© Ž”A$16Q%ùµÜ >0Š)’ßY”P“þ*ÕiRA£žÛ¨!Óù뢄~y}Ø»µlt:õo.ùÚÎá•Ï™{D‹/áúnz^PFE÷:¶n‹0†OöR7MêPâ†Hün·›¨Ópúca,—übÉVK°²¶¶£âQ5Á¥´Áp= X…€5ØÉÞ`xƒ$6µ(YŸ!Yy‹$¶@².’¬æqH®~¦Ú&…¢‘¼¼¯çU·+ý‰Õív¥•bUö±XÕ0‹U«“ľfbUEXò«¦X5%áA¬–e·ô“L«ç`ê(æƒ\ˆÃ$ˆÈ¯/ù^Ÿ#çë:Ú«Á빻̀î£É?”P›@ö·ñW¨S ·à²ÙÆwPßËR»,\1=w’ç>öDËßÀêq°d6ýVvÓß™/u)¼¦ë»òK¯é Òî|ù‡…×u}O~éuØÉWò oèú¾üÒôÊW{ÞÔõp~éMzäk¿/¼¥ëײKoÑk4ß9H*¼­ëûóKoÓ{m¾ë©ðŽ®×å—Þ¡÷ú|÷4©ð®®È/½ m¹±#f¿ßo\R†ƒÆFgŒ#ÊSK¤õ’XÓu¨ ô \õ‰ä4ø¨Ð#á›Éiô½ å·©#ÎÇŒŽKfŸz\âòpV¼#Ùý”r\Íi˸áY4¯ÒÞŠ8ÇÆHÙjζ è‹5¼þrÁv)vD>è­tÛ.!¹-(µ-•ìð_³ÏÆïÂ&éíœľµ£u8~GGËÀ²2ñµ‚½Þ¶Ýw+¥G$&ÛÙ1Þ JzÜ^ê]¥—åeâUßú¦ãU¼tAøõû¼â›03ÀåëEP!!/ B^>-T uÛçu”†¼¢ž„~Ó¦ƒö·Dû¡¶ýÌ ÄzD kSpݬJ{¨*íaÞ»ï‰`CaÐCo\Q&^3Á¾Ö Ý[z ^ßä7rÔ+|ÔáÕzÅ·a?ÀDNÿJh~ ì7C¡Ü(!ßïÿO¬Q3mhÿD´ÿSè_BZoÛV0ú×P^­×!Ê!ñh,3+™fföRf"œ2³¿ã“L¶Öv„ù€v+ËÄÌõ#®P?âúô#üØ2¶@ôu\ àÝTWÃ~Æ{X,“Þïô²kR·^’RÞKªïg9êC½JTC5©ÑúÔ‰Âp$ Üôßô‰÷_U•ôÓ¤™T·"Šñùª>Vó(N·ìš·5¯—dìgì{›–8˜/ý°ðž®Ê/½Gmòp¾\Rø…®ßûqéôz$_é-Þ×õ‰¯”ÞG=ØQujÎl\Ms}«eM4ZÖD£eÁ©8Mo«%VY l 7°+²˜JZi—z˜ƒ Q•æÌ©ùa¤àí¸†[uÞnoc†p¸£e‡‚ˆŸ/¸mç8„¿ odøH³’Œ?p”Cžn\S&¾Mi}·¨‡ø^ÑŠöÅ+Ú³Y Ï;*<§à®ˆ½¶ÌÑU¼FáÒXg»—K÷‰Au÷—AÕäêÑ }¬K…4õ)“K¤õeʋ‚Ԣ±_Ó?+¿ DJOäÖ‰bãž¿]WQB$aú TçäNÌ‘Ë{Ô‹_E9ô ýp„ú³$l:ùLƒÑÿè\þx÷û—ºŠžèGCßst(Ñ:tÎ.“Ú¸5ñßFªÊÄÿk–*uS1çý•8÷‚IÛÃÄ8#\[·FBFZ[¹} FlÍÔ¤øÔJíºÊþr©¯tï©^ÖHW¤üä8ޑƾ4I2¥„ñÉÆ2é¤ßJî˪±ƒô°—êD8°Ý›1º¤Â¯â-°ñÕÒ¯Ò0£ðŽßïøJïøÄlê7Œ÷»¾Ò»>1—£V»Œy‡T¸Úez”®v‰FèÖW9t¡T¸õUÓ£të«4êà—mFhT¸íUÓ£tÛ«b™D¢„Q!\Ž}K^ Ø $ØOsd>½ _ØÕÔã¯Ãa”ÃÞÜ^‰O¨m$ŠÌžSr$ÀÚ‹±‰bl“ êá܇ºÄcw#‚Ît{(t¿dE®Ê±®Õd÷¿…Ó†¹ã T 3…,îù_ø²šZCx3Rñ>qD´Ž+O½YšŠ8)Å¡$ýsJŠ˜G#ò$ÞDÜž¼HÑjW%žeñ.'™gþÌ7+ÂÛl<†P+:¤?õm»·—™ ³œ*z}˜áÅ©Q)¤×~ßdPYzÐ+.²èV»Bƒ^N튑ÚÎÔøÔv¦Z©KƒÍegjeé!¯1.‡ .×™‹Þ›æOG¼lxë†áó±ísSzK:+U&)\¡Ott*š³?WÝ&«B7á8O™ÔK½XÌ”[o9¢o-›cl?ÓÛÎØ[zÛ{ëKo»ËŒ+zúËÔÊÉ êÜ f'˨s{­s¹ ÖN¢‰9«@´™Æ(Y£ŸÙ,7HƒK¤­rÚ Éá»eʹuÛ=š¢ê;HyÈûaÆp~\6EÓi¿¯ûäHV›® ˆü²‘Üe% åy‰Y%yI,Õý2uÂ$îzùKË×ËîÚɱº~D~´àŽÊÜq¹hó«y[^ÅÎä´ÈÞÙÿ){Íì—ÍzdfïB,{—ÉÞe3{›gï*²Gu²QþÒ ÿ¯¦![òä:߯"1ª}ŠýjÖ|ÈãfL·lyÜ‘mwåGšÃƒ˜<Êiocb.*Ÿ­§Ú,vÊÖ.DÂA^œ–­]ˆÖ¦C™7ÊnåùMMMòþM5›èI|ÄßFc].Õ²,ã`gúß=Œ·Þ ot¹§;â¼1k9CÏN—“ÞÀþ Xh4ø*¸Ïv«ÎE{’ð×=‚Ód¥G½øúIDž„–F’ç;ªî„Ä&¥q/Ÿo[þÿ){𨮣xÏm»Bîqã—»€±VÅvºÒc‰c‘ÄKìØ»Y-özS“Ø&É›¼‰è½÷.z]ôfz/[@¢÷fš6Ætýç7÷^í‚íïy¾çí9çÌÌémÎÌ7±µžþ,Ðïé ~ЇNÊK5bè+jkêú´_ÖˆxýUZ‰Åjzï0b !®Xˆ#¦¢ÆB¼Ëˆi„"ʈ鄸j!þÀˆ„øÄBü‘3 ñ©…ø#fâš…ø3#*ñ™Ý…1›×íĈ4¦ï1¢Š"Þ²bü…Õ„¸i!þʈý„¸m!þƈ„¸c!ÞgÄâò¹…ø€s qÃB|Ȉ~‹Ü³¡é`ßQmuFì*+2íiØÙɵP( þeØn…íðÂ)”Riq„ëyV8ôRaƒ6Ä Û€°öí… w´þ† 9’£ÄK6xå(tá›|Y2@ Þ$g˜dY¾œ-ذæ½ÍݽԔ_5^jš3”‡Ñ ðä0Óþú"ë!žošsç›À°µÍÙâ‹MkŽHäT>_ÂÛ•TãZhÛådUÃ[| †\‹ï3˹X° ‹KM±•0’s9Þ6‘É b2¹˜¬„ñL*˜=^Ï\Æ’=\ÜN±Z«õ‚ v¦±Ú,äæ/aµ…XMaV[mVqfµ=Õ.°º“bµç>V{Üe¤³JÂiÆYí%VS™Õ>›U’YU§±:Vw™Õk`uø>V‡ÞS‚UÍê¸Ç¿„Õ b5YJ#~Ä賂Ÿ¿øyÁ®9Òˆ_8šýñËD|:¯I#ÎïÂk™ø@üÚ}į Vøü8eåRÓá‹mF7„¼ñ%Œn£Ìè–HÄ#«Ý(­;i<ï‰xÂF×Ú-°4 Ëò Æû£‹’.F¥Šñs[ŒŠì¡|QŒž´õ™ÉbôRêÄÀ¶Ç£ŸbñÞ˜w”{ö}¼)x2ú ïïÚ¼‡)rØ—ðN¼g1ï‘i GÛ Ç‚açÃñ÷1¯°ëW0œ¤ÈI_Âp21¬`†SÓN·²–k—ÊûVÀöãW2œ§Èy_Âp>1œÍ ¦1\d3\†]SÕ¹ì>†Ë¼[ýªê\…¬_d¸šÎa†kRÕ¹6÷z›÷Fðî–â½ù>Þ›Ú¼|%ïí íg¾È{ñžË¼w¦xïNã³y'À»{b¿ Þ{{€ß«È*uÑÉg\l°n?'§ŸÐO#ò»´_å¡å´·Yhñã‘+ÏÒT¦ÑÖÕ"{d{0Ù¿€ìQ‡ìQ…ÐÚd_Å ‹ì)=™O›1&{æ>²g¬8g”Ðù,-Dî6mžãœÍ˜.ỗÚÑÛ`|Ña|Qa+6ãŸZnV@´Æf,ëÓ Xå-íìlm–ŸX,9ìS›[ÏìÅÌZƒÙç³ÏX{p˜áÅØm‹Üm»ðîÔ¼k¬ÁÞyЦé³x¾íª¢)LUMʾ^ͤ»ª²»Š6™œÑ¸ ­ ëŸEo•V™?TúXO1ÏNνÕÀDš("µÏ¶™(¨àѯ#4$ú39úLdòÄÀò'§bMH¬&’%G—CÔd¢øn>­üÕD¤‹Ên)†©¡ÚïÏpY(ú°Ì‡ÈcXd[Ú1*Ë7Î’o¼*Ç9BÝK 5á~¡&~‰PSꄚj 5ÍŠ‹öÍÃ[¾.°@µº%Á¶¹ÅUVª)ÛÜ‹ÔVr‰Š ´ì®Š+C®TQ‰HYaÉ´§å*5»R…Åîv·W®U³Ç»!…yåF5»°[RØ„WnU³ÿ ìv®¶?´‹?›¡fö¨Ù¿Ah<º7UoUjö7zÀ …ÎCª5Wy&EåJIY¡<¢f{ù˜ú*'X’Èþº¸íD1Å–§Õì#Èë¹×óµø€—:ŽšýB/¥B/[¡)ôŠš=¡WS¡ŸX¡‡(ôS5» B¯[¡x“ù¹%Ä1o 0ÿjv±n§bݱbO‹uWÍþ6buÒ8Ö kœSºj²«öà8W-»iI{•Ø]K6à ×SCGKò ×ûKRô¡Ö’¯¯–L[òõOK7ðKÒ ¢tÖúm°ÎZ¿ MK7üKÒ tÖbl¤ÎZŒN¥ËÈ~I¸äRê\ Ûk”¹\­³Ï~Ýå"yåjµÎ8ûiÂLi%שuÆÙ„™ÚJnr0jöZÂLk%·9-{.a¦·’1£g%ÌŒV²ÚÁÙ½ 3³•<ê`ÜÙÿ ̬VòŒƒñdGSÑJ^p0Ù¯fv+Yã`êeÓèJ3Ÿ¼æ`2ñæ#yÓÁd9&æï9˜úu‡o øð­G{òü½Ú¸Sûß;µÃîÔVÜ©]w§öØÚ»wj[Þ­õß­}ÿní »µóîÖî»[{ûn-Å– hß/ϹÚÜ]ŸÎ…ÖÕæ>õ©èÙ¦ÀaÞ?/¥S0 ‡ ?»z¸ƒ,p,·¼ $D›„pE;™òÅ: ³)ißÒÉŒE:›%ƒ•ßÂ%C嫿Lë9ÐúÑú%Â"ƒE4¼ûkR–Ñl4AÐ_ÍÃ&­Ò¼Ei‚±H.S¤:ú=Ј yIï'Åh‹Ô<ÅÀœ{ØÚ+Z!h¯6à'?«Ÿµ ¯Ç‹ú›‚’Àöz2áûÐ/I„LõI"˜Äg?úLŸa€ˆµl¯‘hƒÚëÐ/*ébztšzŠ$1šb<ÉaŒMbÿŸˆIã)ל)ÆÓÀpÈ£ =2·)Æ3SŒ+¾‚ñlf<ŒNï€ñJ‡1̺é V ÞÉu2‰_Úœ0$¬b¯’kÖôq¸=â—‚(ÇŠáÔÖÒž/q_…Ñ”‘°Êw8O4ïƒÛ‡ÛΟˆóþ,^ÔóW%"Ñøg¬ñ‚l:e»p2^%‰&-«é3éQL{´–Õ”Õ!íµdXCNq¹}@$ œ‡«Ø&à}Îá}NàŠ(n·¢î&\Zä†ãCÄëØôßhQ–=ή-$s³„•µQLþ)¤êî¼úê®À$MehÓ¢= Z #”/¥Í­;E{LŽ8Õ8‡ö8ENPâ¡„¨DùÇ‘N¿âE=M;ÕXN•‡TSTSlîKE³uÏ8õO;ݸº€R>èbU4”™ÀaŸ÷'‹ÛÛŠŸµÈóbôX ¿ÊÃÿÏ®í öÉb€O|²€?5wZ‘JìóÅö8_`Ê·qµ?ДïÀFTžu³Ô:R•CEàïiÇŒh(h¶ù;nö'æ9× Gq³ßµ°î¤±'ù˜”—~³Ÿ~M09:?¼zÌÖ¶\þ ´-wþÚ–Ÿ?¬„ð¸ÈlÊ?ÅîVé^ÈÂGcq ¡d9%O0îxŒß«Ê2ðÄ"ƒIÒ!&%(ò Ä§æÁÀ÷n‘,›…ŸgO/מøYò²‚ŸÍA?; 4üœè ¯§ŸÁÏ›„,ÁÏÅ£Ÿ7’EðF£DôF#H‚7%£7ÉÉ"x«ô>Ѽ݈Jôv#ÅD†™ežö†Ü ‚×f‰Ð´z¡ëÂFdä3E][(mf ½ÖHn¤h“®²¤hï†cw¨Ga¤gaI¯B¹ ¹C„$Z„ʬ£À]Àí¡¬H¬µf 2.B/E¦Qeu¶I ÷ŠÐ¿"ÓSÈ*A" &G<Ô½—†&å1¢¸w¡`í¶Ègøâø¨]ƒ¸ž)ðŒ<¹®5*¾¢yšXå©T®Ÿ«(WêÅùÍÛkMº±ù&eáÒçL× *Ão‰Î JTé¢ÈÛ"Þ¤¢e#K¡‹Šoè1Tôˆœy/ t¶XÕ¬µì¤ÄÇ”6ÇWt¨);+¶ù§«ìŸ¸µµÊ—ÖYJ2"4Æýy%Â?çÝ KN*lÏ£—º×ˆW }”}Þ#‹=œ&ØÿÁr°’hR21‘D³’>…r$qð ;¡Ã.7ýLÇÆq¬þÎuPG+r´By—c(Ögý†—&#ƒž mÙÑâaV=ßA›¨È‰ JHNR8ïÁÌã…¢qæwµœ®„u°{Ø€5¥Y{ +9_²R k~ ‚k^Ñ—S©®ÿµ±BÁÛ¢¦ .ÕW(ÇB?ެmÙæ1j+•°;çãðmz­Qä²Ržs¡íÿËKÎ6ÿ±°»¸scA{ÿ°1¼5(Nt(NTådõ ‚;0Ús6A‡˜ ˆÆ4Иç8'*/úò°<ÞÑÅëû102‚‘yN¼{üè‹J¥‹ÚŠŸc-rzDc-jÄâ¶ÊÛÁx‹œýÑ8KÚª]E0Ñ"§WA4 hnžá6ÜÅW/wÀ1º5Í´”ÌfZJføéñ?Óž×ð“ü>S Å\Ö5òéeûÃFtvc¹ƒË¼<·0Ü- ~˜q–üoú“òzD£ZE£UTdvã6ÿÆÃÝùȽޔrO‰¾èçLJÒ¿×ðÝõ¿„ì/àìÙ ØBš× ÷W¯°Ê›À-ðC6û#¼+àÅ@öÐãØØ‘…&´³h%:¦µf›óÌ&܉‡ÓÕºFÔtp´n0f 1¿¿­"ÌC?ˆãAÚ¢<˜åýèÂä Ûœg6ÂPxH4o ³‚‘±j¨a¥m×訕ú®bºÐÓçá?Ég¢£UPÑÌÁR}I* ‰ê«‘ùXÊy‡œ%Ì!Eý·ù¦<ŠN±,Öî["­åË›¢ªF |ѵSÅiÛõݤ²¤8¼Ø¬¶’;ÕÀÑfMhÄ>¹[e‹ç‹LX<Þ×úÏ2f±…i<–ñÓ#ñõ}\…}“Ef6 Í&Ô´Ðp’I^lÊ}°P¶È,é__µ_Ç!j,2Ílók-:ÎäÓŠJ³ÉC Øqm,2Î\2Hg¶?KLy„~–šÅ×QpfAkÝrs­µÖ-·Öº'-9*¾—Ùiy9‰órF……— +/gÕ´œ—s<Û”#/fÉ€Bxpá¼T˜ˆêäe¼É³ì¼\¡ïñ&`äE2Ä?ËL> YnååÓ/ÍËu•È—Óêx^t’‰—ôÔ‚ëŽq'™Ã¿ˆife¸¥Ê[jঀ¦hsS(hò¶šÕÜÈEVZ“Äš–<æ’µj,t8/:ÙÄüXdbâ>Ú@´ÿxÑ=MÎa¼‘¹&Ÿ­uåOçÆ"«,šÝ°g^Îãoh‚½ñ8½¯{µVsñ±È8“|ðg1°5cñ'c[| ?4”Í[™‘Í&dfCƒ £SMøí% ¸LwÉQ`½‚ûN;°ÖåÄ“R¬'[¬’b=Õb ìt‹u¦åžÆ!?“­·åéD~˜ý¹ ?Ÿèw¢Ð…)ú•}`§è/±è» 9˜BÅ:Ù,GQ¯ÐPÒ¿G±V9¥>…K=™j:¿:Uðk¾¤àײ2.x?¤Ûé¶t]ˆã6Í©áí©Þ™y—%òg¸äž”È1Kd`ãl͋˶%¨WúþT9H•Ó!â9΀[b<¶ÈSUÃÝIαU´ ÂòtN“[É}hµŸv—4سjÑäe-øŸxÑÿ W8(Q2¨PJþˆ‡B„?sÌ-|¦ÉϵX¼x Mú7µXñ Ó%o!òÚ”µ÷IQ«ÉNú}R°Ç›t)ºéŽÔÉ»ëuRôÄ‹ïu))ú9Öúér€NR,#)é–ƒy=KÁ•3¦ àÚÝ™VÔ¢ÓÒ¨Ü\×k£r^a]ÝĶ(f—óX½®œÇëñFñx*i~ñ¿!O8sC…ã^¸B—sl æ"ÎF÷ˆSéÄ©Ôåb=Ð++·Ž0ܵО>ªÀXÔr›Ê PÙÄÓvsš¶‰N‹ÀàÂt;æ«ÄëyæÍ¥Â3ò ¼òô_Â{Mäká{¡êï[ò4·ªMW¯u?Aì9®ŸÔˆ!õEQ˜ùååÑçwj[ù³8O\?oÒZÆçÅ‹ÆçA™öåDN§0ëVË6I³ö! ä¿H$M¥¼hÇh›€ší¢fßÖÌüùVVéó»s9«¿NäŒ~»¼J¾–Ôæ´l¯GèïÚöTµHLáÑËav ²ãÈå'MÊZVÓ^AkR–Ù^g3Q˜n’­/+S8Ï„ÃBõ_òïÉÈUOgÛ v2ÒÅãø9p“ÿà“Õß–ÿJ.²T…“E†v„ÚºýÝ žH’PŽ%äÿ%Cª´\8{Kû¯üoàOÉ¢?‰È'õ!m¹Ã:ßta-çø[a=çÄ[E»žå9§Þ*/…®"Ñ„Z„µnXùR¼®yå‰ònTˆïC>Ê‹ü[²ÉÃùµµ²‡H©É¶ª³÷±­EÓÎJ/¥&¿sžk[žª©Ú{(.èñ“ ª^æQýN\Áìb5$,uÀiøìÑ­*»>?…K«é ‘VÕ³êºk¦§Wö<>åÚž—f¥œ˜óÛ·u':„y:0Ô>Ñ9¤>]m‡V»3íHwWžÞXÕö«W¯w߯øayñiR惟¼öÙøÓˆ5–¿]#N>#èïçú{£ƒJç}O£¿7;èô÷VƒþÞîàþ6ÜÊz>¨}Ÿñ!Þ@Öû^vgþS~DzeßiŸ!? g@-§¬eûzò¦ ^Lþ‰Ÿ,ù¯°Á»ãÿÐv?®#à¿ô—’YÙ/£ê/½’ÕSPM†Ý²åÿ@žéjÙ&O!Qݲ§׋‡ÝEšŠ¢õMû5é%Ø© hõìÊŒú øÏ±¼ß<Âw:ÔD#€dX'šNÓ@aŠT&O…a"ìiÜI;}«ÁHªê©¿k8 ›‹ßeÆò:œÑ¤YÑ·‚Ò¤v¸^¸adT-V¶maF;˜Frœ€¯•lX>¤ßFðÛ31œY4¸±R4¤±ùÇÛ1vŒ„Ö&†³RQ²äD*pf8‹¤‡õ°ôvBµ< ídO];¹ŽC³av;9Líd ÚIŒÛ ¿?ýšë)¼²ÊS=4Ž©WïvMÑZÞÃK,÷:¸šÖˆÚ‚þ–•*4~œ£6§‚)ÕZÈf‰²¶Õ²9ý¥.Ø¢IÙ¨³¶Lð!††Ó—D<¾ÉçZe¿‡Ãçü°F=‘Ï}žçOJÍßj:ß k¡Y=é{…µ¢ ¦X˜dú?´|ÀaÀ‘*¬ˆ—0BŠ\("]šväè'l.07¬5êE½ý¥ÐGf¤«/¬Áüã#H]dašTX~Yà )EkJî/ÚRói+˜í/ÂZGgÄ%žÿfÑ= ÿ²Fœ-2ÚÊ_:Ü;7E±ÉWÃ+·’mS‚…B=Pž4‚»ÃjàoH[y¸¤«O¾GK§äp[ä|ýþà7ÂF ’ª«D^š7uª¯·ñ˜­®Ú ñh`¸]íG¨Ú?2ãÇl_¹Ý—§h†»ÍÕÎ¥xòW#.¿âz»Rñ:¥òú‹ö•_+Š7uE7˜ò}Ü}HÛ¸-¦ìKD?ÕäßcÉèfSþïÝì !¥ÄÛMvþ¼ÂjžÐ_DÀ&ç“ÀƒÛxt£Éî`7š¡>Fî¶`;‘ÛE¬ø¶ßÏx¶fo_)1¬Âã>²s}žû7qÂ#-*¬%ÀpÅJ:’cïöf”’w6£–òN<ºÕ”±=˜|Xì¢ÄÛøPJð¤“8©`§n3ù`jSºàûmîlYýpžJ‰ßEâÖnQö±†ÅúÔÂekês»Ù±ñ7ÑÌ}Ãu †ÑcÍ¢ëMyMAPQÿ'Ùqãg û^¬Ïb–ñ¢–¹¸~G¸ ¼à×ö˺ªŽtÞe麩–tÝq¦s4O£ x\EôØ€w«®]^t TaáC Vå`5°6+ÙB›ªµYJç*9T ®ÊŠGWeሩyt)G‹O5êbÈC"”SÉ»;9ZE2t~Ž‘e½š Ö1Åâu´ˆ›¨Wf5‹®Ì‚§9µš¦RË¢6“‰cðx–_`¿¤T¨²‚Ìœ³ßÏéR*g«E·U¥[µœ£n=’d£Ùÿa«Ïj"2¢~@B.a(Q4²P*TäRÕòC¾ÊŠµÊŠµ:Ëåqš=‰–CáSÍt1v£šÝ—°Ðt`tñèB!w¨Ùw¹²ß‡‘g¢·Ùl¯ålÌ—•©[mÜon'W¤nµqCÜ­4ýV7Ä—rä–Ô­¶sC¬ñ ±æÑž¤ñMkZ[ûrmíßjk{ÖÖb¼Û£Rs¡ ‰±…=ZÅî ªö ŸùQ½´êõ°*?X¯GIÞuæ}µ—ºÇÕD“‡¿ÁÇ õYÅë³pÆ@•Ô•tm¡ ÚÂÇj«ì¹XOåÇ2† äÆm©”nZ¥DÉ.¢oÛ…†8wÕì¿QþJaè• ­evEu«üÈ*²Õy¬’k•Øgªc2û)«À®Ûˆ/–—ú䩼ޭ­¥ÿáãØ€pÍÉPWÍÉŸ çÝC3]©_³¼Tf凖óÿ×òæa­‰PŒ³'øBêËÍh”Àƒ4‡?sµ{©ü€ºfÇPw?óù{°»/öSWIwŸü'áàR:ÏPÌ3 ¢âÁ‚e­¢G©«·xGÐÒA±~TDèË'PHhw“Èç/ä@+a¥c}0]‘±…8Ä \¡Ò,Wè]9 ÈÊéUÚ¼Y›,µh|¡h„*-¨´â¦#ZÑ‚„S)‘ ¨fûPõSTè¹JÞN°“ËfÉgY T;-¬5ÚJµ0W ÁÇòãX•Wñ¢O3ã&s[ Z=åû-Ð&™b‘ã&+æ—êr™M,̹õJ,rÔ,žDr#îåÄ"',Ä*‘ý5›¸pˆäáu¢•2Bœø©êxe­²EÁ—:¹Ð%×”B—¢¸î~Ç¥*®Óy–;X*òC˜ÙpdšÀq†ç×çð ð~p¯Yç§v/a;òÄô‡´–ŸÓï.$=›¢Ù“N_¼pFÀ¹T@­Ôý8O;sÝø)–ðlÔ¯ÔµD©ýKÅ%çÄïä2%tééÈÉçñ ±Ü†š—L-„ë‘x¢øi;ù˜¯X)gÆË9‚#ìfÿØ|Úƒ[YÌa³˜Åøe¡r^aªqë€6©´²æÅ]&”(QJ‹¦Šè~“õ&÷›Ü–)V[:LñYñZñv›p>Ä ±Ç„d,²Û´æ‘Xdж1–s¸îÙmæ .µ‰ÌsÞàí1s¦¾iã¢1SžgÎ9š½ ûX¡mXEKô½g“ÁN»¢ñ·ùù_ ˆhÂÄåNŽˆî5¡=™ˆV™¸Ý!±†”Æ‹§QË¢Ù¸ {ÍfÅǨBn£B.æ¹uÝèÇãÂP>0ŸÅ–ûiE2TÅ;{½Ãa¥ÊX••ØÕ2‚¦Ö1*ä¡ÍæXDi¾3Ú$Ky¼õ3î7HΉj WVà¡_Dnå4o†T‰6¿Ð‹ze‰ÆÿÁ‘$¥™°¡›ª"ÃKãô™^HyP³ 1M,UyšÌ9£0EÇËsF—–[ÑÊsÆ”–ã~š…Ç´=ƒVË9ãJ‹gP̯ã~'§ys‡;|x Y¤ÒR“„\Œõ ½”=¬óõÖOP*Û®T¾9ˆ§n¶²´ãíúÛ¦>PÛAé2Sz ”ª™Òè—\Õ*Îøã͹²ëô<7õ‹™Ñ;Ë&Šy˜ B)¦×cjœW>8, ì)@‰ãš7vøÅ†ÄöÆDyÕþB9¥B‘+ÎR.cEs5”HÕйº²¹ÍesYIÚe#Ï?PliAl×¶&ÏrTI_rn/ÁU»¥+Ù×:-tuãˆsƒã {ÊuƒÏçOæÅù†ñ6¢]­»¤ˆ¯f¦9ƒ<†‹À&B0#~’窊üØ|ÇÎIy)íOo˜M^?®Fc:=—¯Ó¾ô*ï ξæz7ØÃgŠh_8÷šˆ{úL%Ú“ >åƒ`/_à×jóŽZÒ‹ç_S? öNCö&äǯiƒ}€²!/¼¦ÿ#Ø×šUz‡¢õõÁ!šñŸ`_š?´þ„½øš»LøòFxé5OgAÛ£×2z‰à _h¨¯d¡?}­Þ wp±ióŽ«da®½–yÓicFúBÄ®—¦ÑWﺯ>>ÛwÚø|CSµÕâê¤R¶ÅÆôa!jßoÙPÔ¦ß*ƒÙP”壚æîÀ;r¨HÒl^QÏ“’¦ÆŸ }RyÒôðw’¿³è»\£È"YO‹œ‘¹>GN‘•Td#-r½´È 8òZ#·y¯'äÃT}äb‚“‹ V.&Ð"_Äð§s…ùª®j×9¿3˜3­˜øYìS*ègd{u¶¢9ÍBÇó"“¾•³ïÇEiHGVrºåÍ.e™?D`]AXãò(ZW Ìz 2ØäT³jxÏ‘óìpá„»8|> ±P·Ã'üQ_ˆð¯³!+\uÂÛ·¦‹(\.I6±„[Å´ Ö÷XÆð`À´& òQþùpx31_ËPµÿEöWvöWp ,ð³<¨àgïŸUüŒGÃÏäR?Ý_4ð³&ýÒëŒxb`Òrؼވ³Ù3¸kÞ@ßF¨¿ÏrÕ¼‘ w¢<ìIZ.š7ÁÁ¤|½ªÑ$B2ìtdØiɰӒ?SJÕ,ж“EÑñ3µÔÀÏŽ?»ñ³óÏž,_ÆN–¯ÞN–/?7¿‘µÓ ƒ}ØJâºL2˜Á`B—{¬Ç`R—ûŒ8õâ9´'¨2Â°ŠŠ¨6B|xT½ß63äAïŠwȹåaÊ´Îþ«çªòˆUPam`ñ<Î,O†³Ê©Ìê—¯ù>Ö(–ÉùX¥ò<-†^À¢úÅX`©Ñf©áŠÞ1å7¡–żfˆ´Í9ÄØ&à$4rÇ„sxxþ+âuYOÚ¦æ[)z¡ÿ;&u-˜¸L‘:æ:&ä ›ÏI›Ô)šž"…Weü’ŒH%@jFŠÔu‡ÔuÁÚ EE{Ó&u ¤f¦HÁzÔ @* R³ò-‹ÂÖkÂÖo&+˜Ç  WäHøwëìe^£h57«¿Î^9F±òªÙ)ùîWg´ä[Úvþ9:?š“’od˜gÉ·´‰17Ej‰Cj‰‚WKLjY¨+1© 5/E >Ø‘ZRóS¤¶:¤¶âU‘Ejy¬Š™ÔNZ"©¤Ej9H-L‘:é:©ð“ªÖ±†eRgAª2E Ïtø}‘ªF,J‘ºéº©ð3گ㠓º R‹S¤êÎ{ˆÔ~Z’"5ÐY Ä‘ŽEê€çLj(ûtK‘Rc,R@jYŠÔ,‡Ô,n˜Ô!–q©¹ì°-Eª¤[¤ÔŠ©u©u¬îÁ¤ër£MjH­L‘ÚR;-R‡AjUŠÔ‡ÔU²Ia &u¤V§H©Ó©# µ&EªÆ!U£²¢H­6ðìƒI} R¥Hݩ۩ÕPZ›"Õ˹îí¥Á[“êþ0t ˜T?2¬K‘Œ›ê¡/Òýa"µžÇ¤<žV6Ñ Ô¨£}ù,›×™6™ÿhGؽKÑœtst¶1ÚÎÿDØ*G¼UßÓß5›<„3êµüÊŠ m‹ôõ²RØ:+¼dÞ£ð'Þ5寴$›H‚kþ-Œ‹!É6;ÇÛ‘ãM©1f'¤ÛÍñH´Íù°µù$w1íF®+®É¤x/oI%>‹Äç)q? P[¹Ø›"àŠ“¯+š”¶ŸW^µ‰|"ÛRDÊp½ §]@d{j”ëé\’÷Ôeoø`r}ôVð¿ðâ"‰öÇ]óŽÑ1 :ŽˆÑ)¢“¢“u9DYD§Ñé :È+gØDg‚è®|ØÏáñD—ÁyÑ=3ÔÃ7bFôž‰Ûn†{Ú0ßzïÎϨ§éŸ«HµÉñдGç~ŸÎ3|•ΫŒjWûu^eÐy•q¸©SoÑmf–K§­Þ2[ûµµºSëþ^û%A,2Ð[ç€( €O‚vêN÷€k)¢ÿh1¸}ÂånÜñÖ>#zË gx2iIÛñÓ>Ýž>¬’Uº=„X-«u{\ù‚ûu{dÀbá€n^¼JÐíi˃Cº=q~ØÞ#èŸo'é´È«JÇõ°;éâ-GüSœÙÆmqJQ¸—Ò9ÞY=ÌÄs˜ž£eÃôrð=Ït>Ãí“úX{NöÈKº]buîɸȆóšò2šÇ@/p¼²»¢†ùlF¬nÂv'ëÄLÔÿUöfµ'¿ACMŸ®£Üq@k‰×ÏZâõ·–x¬%Þ@k‰7ÈZâ ¶–xC¬%ÞPk‰7ÌZâ ·–x#¬%ÞHn±¬hµ‘ZoSélüÿl#ðe{²‡p ÖÓ°ÛH/Ãv Ö¾Aô¶nàià8ëcXm¤Ÿ‘j#ýT`Øó4jl Q×`t9Ȩk0†lØ“*jˆaOȨ¥¡†=¥~Ø>C3êÚU=9ܨkW™r„Q×®²äHÃ^R}ؾ¾mÔ5²±X×Örcg„3íF– Ïhd)Ê$ÃnT‡¬F5Ù°72CN1ìFu°[N5ìFUm5ªiF8ƒáý€3ät#\/Õ(ëÉÌ×i”™r¦ÎJ5Ê,9Ë×g8 ¸¾œc†ßßîÂ0¾œÎ ×gjóŒ¯hÅ8|žoÔµbSð‚|¡áŒXÜ`+ 4ØX¾êÑô›§&×%(ðsé?]ƒ*~f•j·é§¢T¿cÈ»Fp OÞ3|ÙTk$ಭì~L[ææ}yÙ;%¥3•"O¤8ˆ‰wl¼mÐlòÐwášÑM›6ªÂìÐ@vnGöp'Ã:–ù=ù;¡cÞ‹¿“:Ú}Ýa­ÉCoCkÐMié;èŒT&¥d±æMg5Øâ¶y ±‹ÙP `nÙpx4»Ôå–£Ü<úc1”£ÝG‡b 2öŽ&–Zá‰Tø2;œÆéýº\n…'Sá+ìpš„èr5(f´éŒ>âˆ@áˆ`­žÆhNŒhß¿Þ Oc´Á'F´™ßŒ¶ó®|kZ¡ls@KàíhÉ·Mƒ“í¶t[ž=h±9 Å­šÆÃÝq؈âçô‡X®]Ôça´æ³#h­Ž¡jz v),ÂÖÌÉëEn'tÂÙ‘pK8å “º½†äFpÖc“X=g¹Ô,/ YÊ‹¬ÇЇ{5yÎ…’ùŽË@šæÛJa'Ô§¢ÿ W.{óоò÷ê„Ո믉Jp´/gEiÎÊÒœU¥í”œó¾œÏ|9«ñyÉ—sÁ—³Ÿ•æ\ñå¬Åç®9ëJÛ‰œMrÖ—æl ”ß(탆Y>주suc)lYѤިj´4ã)®ÀÏÅvÊU!?‰ÆÈÖu‘pÞO.(¤Øxä,o~>I ¼%’ñ¢{¹‚±ÜP›+ZË»îmªò5ZF`·˜Õ­ZïFkÄí_º+Ì?[J•¥ô³µT]F?K_Ж+r©ÒÎU–Y-—+¦«½í‹“Û»³Ÿ‡vš›âåJ%Ð00ÊÖéæ´W)a%Z­ÐB™Í.Wžw6ÖÖzÜC~¤àÉ~u>lD!ÞnK¼jv¥´›„ØV*v³HJB•"~›Wš´– ¤%:·×³‡(4{4…aÒ½J뺩¡³ÜÒ` ?´¦p6̽çëªîî¦ à„ýÀ*êÁÉRqB«ÓŒw<¢œÐäiÍRò#¬ãwFƒ6O0gµæ­åÇó¬–³·T^Ô8jš»ˆª¼ ¤:ÜÒ™B8ÀÊá<ù\‰š:ûJåÕ/’Ðä§@jÌôRÜ òßÔ~|"¿¬^]Þq>N{ÕC?º5šu0ä]$68ñ=$®e+[»Œ ]âM×ÖÕ[[èRºÖº´†®õ….½žkC¡ËxÓu*_Õuc³¢ãeu5fÕÑí×Zlü(çQi˜Ž›ß8Œå•£ôàÆÂæÑ…r¬Ž `õµqz<ß&ß/ å´JãÅø>QO4þ ˜½)“uŒ,ê]NÖñëýj9E?žÁå4=ž …â‚ÂXdŠuW2E_O£Mò‘Ô‘ùàÿt¾&tãkh‰›Óµ §KAεüœÏòeµÞJgò¡Óó¢\äCÞC¥®‹º¼LƽÃÙ|MÕrn%·uû%ŹMÂ.wuÙɈ7¦m™ìbÄâEå^¼Eêf$êlQÐøCÛúJtƒ"m“n­eo#0Ù‹ŒòÚn!pê:Ê {ööª¿ƒˆ¬Ä¾‹— #`@Zè"€7ÒÀ4‹ä4ŸÞϘ‡lRñ­A'FZA¦‹åuN)⥬nöØ4ÆŠR4Éë²1ãÿ?3årˇ¶eÔtxÃi´ƒ}áóùBµë`+J)u-2P†b‘!—@kàc®ƒ‡e«a×ÁVCn7°î¹]ÍùÜæö9¡ûˆÀÑRQm@³aº7rÑ÷A•<`Þä" ÅÓÕyü=Þ*–ñ>ёߎ2HQ–;b¥9lA—|3?¨ÊÆ>ã¸Ly6E±î£¨k¶Ë>y—çŒ8Þlbð?o¥»Bò¢·h1þ¿„àWYðc¥®O š9>5h*ÿŒ«’‚– ƒ”èÛvl »#×t¥¸Á§¼—ò¡OÚTïY^‰rÝ£â˜ñ†(s£Ã(Ý8¤ÍŒ·ÉèRiYPÝ]¦«;‘„6eÉ‚BB¯W“ñGÎãEŸâ^fq¿£ݶvÛh·ëŽÅ‹§z…‡c•+܆rw˜ìÄšìÎò³Ü¡ÏÓ_Hmºd…%²$·xS¡*g»Ç sÜÙ{{!Ç^èĮ䨳­Ø‹êb/vgODì{…{%ÇžcÅ^U{µï2X~ªNªà´aº;‘¦ߥ@ΰ–üµ|9ßFXzð4<,³_ÔƒWžœX[«=V[Kÿ^ª­}¿¶v"Œ~¡tj°iÔ`à+BØÌ»Æ‘^üý$ÔúFxµ>™Ÿnâ=Ý;ÖUÖ{áê‰R<>¤ó[¼2ì+¾+¿Ø'Ú쮲}¢J~/ѬdK¡ü~"^¼µPÈBTâ'œ6i‹‘öT©«¸Fœ.ÅòWñȶÂý¯°= ý:‰}7Aÿ+à\=v劄Q$Rèá/+ xYá«=ýʃ³¡x9› ^~õ•àŸ©FçÔÛ¯½œë3µè\‚úøõhpžÏÔ£óêë7ÞÎ÷™Ft>AýüîÿøLwtAýýžþ"¸Ðgz¢ àÏ#‚•>3#ZIà@½i"¸ÈgÖ‹."p?s™.ö™™ÑÅögmÁ%>3+º„À!þúI\ê3ëG—8Ôßà¨.ó™ ¢ËæoxY—û̆Ñå÷gwR‚+|fvt4>ýú*Á•>³Qt%#ýG(ÁU>³qt£üMU‚«}æCÑÕŽö?\©×øÌ‡£kãd­üÈg>ýˆÀ±þGw)Áµ>óÑèZÇù;ª×ùÌÇ¢ëïü¢\ï3®'p‚ÿ‰Ï•àŸùDtåþ¯uQƒ}æ×¢ œè²¿Üä3ŸŒn"p’ÿë£ÔàfŸùõèf'ûŸš¢·øÌ§¢[œâÿÆB5¸Õg~#º•À©þ§W«Ám>óéè6§ù›lWƒÛ}f“èv§ûŸ©Rƒ;|æ3ÑÎðÿÏ)5¸ÓgþOt'3ýM¥Üå3›Fw8ËoÞVƒ»}¦ÝM`…ßÛK îñ™Þègû› Õ‚1ŸÙ,#pŽ¿y¹Œûðš‚À¹þZ0á3[DÎó?»\ &}æ³Ñ$óý-7iÁ½>³et/tyýÏÅ´à>Ÿù\t ý9‡µ`•Ï̉VXé÷]Ñ‚Õ>Ó­&p‘?÷¶Üï3s£û \ìÏë¥øÌ¼è—øóGêÁƒ>3?zÀ¥þ‚©zðÏ,ˆ"p™ÿùzð°Ï|>z˜ÀåþÖèÁ#>ó…èWø_Ü©úÌ£G \éÿfµ<æ3¿=Fà*ÿ·>ÖƒÇ}æ·¢Ç \íÿö5=xÂg~;z‚À5þïÔêÁ“>ó;Ñ“~äÿno#xÊg~7zŠÀµþï 3‚§}æ÷¢§ \çÿ~¹<ã3¿=Càza…<ë3 £g ÜàÿÁ#xÎgþ zŽÀþ®7‚ç}æ£ç ÜäÿÑ#ø±ÏüQôc7û|Ô^ð™?Ž^ p‹ÿ'—ŒàEŸéŠ^$p«ÿ§×à%täKnóÿ¬Ì¼Œž|™ÀíþŸ÷s¯ ó^!p‡ÿ¥î` ºd ;ýEÝA‰ž" Üåo5Ï¼Š†t•ÀÝþÖËÝÁOÀ÷÷ø_Þì~êó–‰è§Çümbîà5‚•è5‚ãþ_r?#X‹~FpÂÿÊYwð:Ážèu‚“þ_^u?'8;ú9Á{ý¯ÞuoÜ$zƒà}þâžžàM‚½Ip•¿í(OðÁÄð!ªý¿šï ÞöùÞ‰Þ&p¿ÿ×k<Á;>_$z‡Àþßlõïú|ïFïxÐÿZ¼çóE£÷<ä÷Ÿðk}¾?Dk <ìowÉ,Ëõý1Z–KÓ–ÿ·×=ÁN¹¾?E;xÔÿzYF°s®ïÏÑÎó¿Ñ;#Ø%××!Ú…ÀãþßÈvÍõ•F»xÂÿ椌`·\ßsÑnžô¿µ #Ø=××"ÚÀSþÀ¦Œ`\ß{Ñžö÷g{æúþíIàÿïOe{åúþíEàYèJF°w®ïoÑÞžó—ÜÈöÉõ5Šö!ð¼?Ü©^°o.Õ{_?ö·[/Ø/—ê½üoWÖ öÏ¥zïOàEÿ;±zÁ¹Tï¼äœ©˜Kõ>ÀËþwoÕ Ê¥zDà´kfpp.'ƒ ¬ñÿadfp(!Púÿ8-38”‡xÕÿ§E™Áa¹49 #ðÿŸ7e‡ƒÑp?õwHdGäÒô0‚ÀkþÒ™Á‘¹4?Œ$ð3ÿ{238*—&ˆQ^÷ÿånfp4¤Màçþ¿öÎ ŽÉ¥ b 7ü‘›KÄXoúߟš—KÄ8où?¨È ŽÏ¥ b<·ý.É NÈ¥ bwü7fËsi‚('ð®ÿàÄ\š &xÏÿYÁIÈþ$kýÿ¼’œœKÄdËÚýャà”\š ¦ةݿúÖNÍ¥ b*Ûý{\ýà´\𠦨¥ÝÿÍ©œžKÄt»¶ûÏÊúÁ¹4AÌ °[»ÿn«œ™KÄL»·+;Q?8+—ð,{´ëôiý`E®ïýh=ÛuîÓ 8;×÷At6½Úu™Ü 8'×÷at½Ûu]Ö 87××1:—À>íºmmœ—ëû{t}Ûu?Ô 8?×÷è|ûµëq©ApA®ïŸÑöo×ónƒàÂ\ßÿF8 ]¯! ƒ•¹¾E+ Ø®÷´†ÁE¹¾G8¨]Ÿ- ƒ‹s}ÿ]Lààv}«—äúþ]BàvýÎ4 .Íõý7º”À¡íúÖ0¸,×G]tÁÃÚ èœ\žëë$¢Ë Þnà€ìàŠ\_g]AðˆvƒÆgWæúºˆèJ‚G¶<;;¸*××UDW<ªÝ¥ÙÁÕ¹¾n"ºšàÑ톮Ï®ÉõuÑ5i7l_vð£\_ý(—Ö77ÒWF—ÊCÙpäR·2"ÌÿvÙ+£Ó´2šî+£[ùuÆÖÖs=ß'ùiî/К NJêHâÑÀn›Ô"5à HÝÍÿ*Ÿ£÷x£òòÕ‹¥òl†á ×ü'&ÿë<±Ÿå•ÆDi¬xž×%ߋţcUù—Xñ\‚þ ­þZÑ…–®è/ûæ­å­« "¡Ì=™ ¹ñéÔþŒ”eµ–Ó`%Îå*+°^Rä ˆ¼‰bÌÆQA§œŽ”)ÙÊvçªhçÕ¤ì ,\‡=åÚ*°=Ûñ4#WÙ! æN)ëÞ8ÎöòGh˜ì6ø~µÜCl«Øu9 ퟈ì),®ôÂoöz%‘|ä4í?öŠX\âe™¸ÁÄ-Lt¶WîK#T•"´?ÐB"T•"tˆRTÐëa6þ±åQõܹÞ½ùüÙ6´É¤ìÈc´¾-y<òÙ³%Û3àÛ¥WVXã‡R'±Šîœ*"Ø•·ˆæQ—…_PQÀ]GÉþ®€}uQÆ~4 °Á"ÎHÅ~6ó;®‘ uî·ÄHó¤]÷ÛDiŒò6&ø]ûXEŽUb‘YÞœoäLÌ•ã”x;Qt[UñTO ,x>ÙfÁóB•Ôjœ²OBu+Ð2tc¢ Ž•Ì±½ÖÜ6“ú”fÞhïËsW¥I~:½¥¬Räb%Q'IÂ’$×’D]Š»°4I–) [*¾å…v(,Ë*–Ußé«-(^²§Æ?“\Ï)´G=­Wìʹ 6‡K4ø¦¯²Ë‰ºjùXMuî iÕr™«%nŠ¢ yŠéâŽUSŒ îL5Ví,nžˆsíH'ý pÌø/v[e›¡4XÊ»jŒÝ6x‹_äæºj¹èE™#ŠV÷É2­nXeŠV_fVe «qV»i1]\×$—ì®Å¬”„²'4êû(†nüd˜®Ù…=æŽ•Ï üø®‚ŸÝ?Rñ³åQ­B“³µûú­.çja=Õoç/¡™o>}pw]@Ü“BUCW^¤ÅÂzñ’b1¤Àƒ÷Ãb3leÉ‹¶åaòÈ8·›=,â„°k†—ñ¢ßqa’M€È T¼ý/þ®k¿&jqÌ;Å•ßòâ .À³ÿçöÙF ͼèý,¾±BWkyI ŒÏ‹Á¼(TUßâIij5˜Ò«ð²•á /[.Ó­’Ÿ!vÒÙº§WvÆ¥ÀPNα?^ Ô­äëÒ’BÄa\ƒy>Ÿ€£L}˜tZC}Û5AG üÌû™2A—mžÄ¥Ÿž>㺒'Ó©ºœ¦?0™N§zˆ£¶f@¥mþc gÄ@9KOÍ®sõûÆò–°ëö¬œ§Ç­ñÆvƒ·ÚwEã_ëåRm.ê4”J ZÄ"'5ž-Ö¹¡<Ì—2@eË`=…^‰²^ RGÁy—Í[´ØùÀòš³M—;tnÝןESä.»h*ìÃîôL4~Å’RàqÅÌï(1]î!aãÐ9.‚°4ªèlácÌ4¶è‰dÑÐ<lÔÅ##Ôrä" -ïT{!àˆC±®“ºÝ—Nêò´Žûv éë•lmñ¬øz¼èëBžÓY(yž„]àe½ótyäFòxùS»é»©ËÛ÷“ÃS×»¹{6¹Z&W¼šú|'ÜvŒ*pž~_ÄÓïxúÓï³8#žéEÖÀ£ pÐø øþ•Ë Êgsn6‹Êgih+ž~Ü"gl»èǰò<¦ m™}¥T~ ÏÅ &Bœå*8×ú¹êCðó–è—5ùÀT3¼J½«m,²ÔË+é_ÇŠ—{]|TÜ.öjçú.ù:|ÀÀêSˆ è¿,ö†úÖ|:t7+têé6‹½¸¥›Hó†áÞ)í^Y7)[ì¥Övà÷®w廡ÕîPf²Ì}òñƓآ*þ¯žK¬'Žá“&j}1+D—xùÝC),ñÊ¿`±BÂåoòo$R$"‰Â¢Å^fòƒd#X§íHanõEÝꋺ°¿'›—,õÊp¢dI¢Pþ+Gjxëùw²Ùý &à‘4üˆ ` ô=dj€°ý/Ë5@°qj*¶—Ø65çâ{v®† 9Œ×ñOaÂ!4^Ü£>b+ Á­š¸¥ö«‡åùäÇ$q~"äØ>?ÔGàÿëçÙ$Ïb/BÑF¦ÀÖ—ùˆ˜J£¼ÛóÄÕ«¥òÛ÷+^eSÜÅpA@ƒ­ÛsUv©ãþs)üi’@c ÁZ ´b‹ËCÜu—7 ÙCÜð½€ ¡î:[Í›E,ô©Ù[ê–[DvCx-ß}DÛS¨Äî£qf@"{®Œ¶r¥°®Œö½)W çʨ´2Eèg‘ÑÍK£ÿu¹r:½w0ö¥|”¯EœÍk£vPÍì‡9a{Qú[d£XSìX:®*{Cî°)0öCûBvÖœ°Ý(9P¾€òx”'S[ëÙs¯6ý_£Zû…Ñ®i;êöÜÐPô©è[`:ï ×QÚîS ¦-Ã7•! ¼w²‘ð£"4Ô({aŸ<‘^˜¶VZZùul¼F´Eܾ|ŽGºè9‡ŒÈ¾ÂЭÜÙáK,Ϧ—þ9ªìº8Tæ°,&?¾?}·ëÒ· $Yò˜…ÆðaQû0[E|ª—lª_…ø< }r§%]Mk7Ù£ Aq_›iÊz“1d’¦ð/ã˜ý6kQ¦·¤_»ðü« âÖ®| ïO³ãŒø~)j’xK>ÌÚ莜jþð_ØPq©ÚUG __æ–]J•sá[EU…O²º)0Ú©Ùõ…»iP­.ìÈŽÒz(”– W*+ ÷Qb¦7eòƒ9Áþ«äþ6KÖz=Ïû´yš¥ö‹6û…«l¿hoÈ 5l„õ’Õ^9›¾â%k¼r}$JŽ=.çÒGOæ!’†× óÕXd‡—Õ}¨x˜ºÃ[rÇ“ ¥ŸJ‚-cs‘ã…„”K`RÒ6,uxb‘joñú|s›Å‡½´:QÃl‚7¶E(Ã|V3ã ×F*¢#†Ø¨ÊÍjñÕ¬m-·Ö!ÙÊ6Õ¤ÍöÕÄ6{eAÛßå<4°®2…VÝûE5ÊžÍtÑrô¤*rÙÏ´Êþ)VYF?N¨æÍâm׸t5Öan%OòA²UüÖ¶*þ7ˆ6êR9­²E‰u´ =VfòŒšŒ¬öÆ~Êö8JA¦à”‹vö/«ü0õ¤ Õý¹¶ê>ãZE› Ýx•{>,LÜeQgY¢b³vOµšã¬V–FGÒZ’´Kiºˆ—€ æÕ•ý"èTн¹d†òéÆž®Ñ´ºú¬TŒ×àÈ“¸T¤¸ŒÐ,.p©µ’c4šçÑBÙ=ŠÎ79‰r¬V´ÿqQöý}r‚Ϲ^ZT–)ÊV±åŠõÞX"´à¡ÈÅEU^…[Å$v¼ÀY B¤ù8YÈBÌN Qi 1û!‘K˜°uÒ…EËR-x¨¢Ý®¢GDñ~¯ËØ C\µÕd€Ïv­°_ìkR–E-#¯š~q@’…'§Y8=Ï¢·Ž‹Ñ¢=BuñÎù€û‘iO7ꃾz#WlÑàÀ¢YtÚÓr+K~#Ÿ%GÙ®³ØÄIîÔöK7lù‘‘ެ#©·èm¶è®è/ޤhÊú ¼§&4kHò" aðçÐå^ ©vS¼Ó-Ø­êÜj|ûäa‚÷xCÓšFä°.÷ ž‹OÐÚã8Ô–½~h•B­ÉFºy(›˜O1L­ç#g´X¼Í¯+ºÑ‹c®ÈFoãwÊøÍ7”«Ð¢ª}ôñy©6Xç°ÞPÛJÎû-ÐpQ[ÁÒ_´Bs¬ÐKZ ‡Csgè23¦x±­¡F{ÖV8Ÿ¡Q¢²ñ?1>k¼<íð"rÅÇ#»tT ¡z9?C­–×µ´°$l¿û¹•㫞¤e¨½ZÞ`LÒ~ÙuÓ†øaWöR8ìµähY ëðòÄhÉd[¦„¨CÜ/B­VR'Îøî c¾@Òt~ È&ÑÐ;zppÜy˜nCÖ›´¾8tË©êÀ ƒt?=Øn´šîOC˜­×ÍguV›4ñ€]ç&vÂM_–§ð„¹ß?ù¦_¢?ô«ëèër˜ÖÓèë)úÃëè×-çà#s¿[õ18=[íîñÂò{aYŒ&½ÙO —œ¤ÇšG·yå=ÕâºÁ½³TŸM­óf©±X‡]+ Ôfò¹*ÑšÅIšõ8+ûSY™‹¬ì¯ËŠ!çéa#-+†•¼·XP—•vQ-´ŠŠœ/yòRP>PGÙ-—éawewŠòŠ:Ê+ìBZiS^£×uš5ÔiÖê±â£ÔiÖëŽò8\Ëcþfó­϶4îµ­ÂIgd“·Ñt¾¤xÙµK‡›±[ç3OâºßjÛƒ"ËÝ 3€͸m?9IÛ4('t|ÓO耈œ*ŒENxeRO¯É½: ‘›¼²ZOØ©u©èø¦Ÿ´ÔïK}ÈN}”=Ù@‘wççTz~Îp~÷°ósÎÊÏyf¹??çÓósáü`ç}‘ó“Ç*îËÈŽ˜WXöcJ4I’÷v¦Ãç¹=Y^ëöôÖ ,ÚÅœÔêãŽn­>æ<¸ú¸«·’µ)1i‹VÙøÜqvÞ‹œõŸ¦ýagBX¾üÎYˆ.„°¼vÚˆn8ÇÝ&Q_Ö¨¯!ûhnJ¢†%ÑÜ%h´’ƒ/J44]¢3ÄoXºD@ O—ˆ‘h#oò ÐxÃÞ 7`¥ºödZiîôR¨ùn,rÒ[Ü›ÖPSn§ã­æL'ÝLZÕ>'سX¼ø ­æ áf¾ü.4ìÀ…oâ âO»¸Å´þ#»¼ÖFn±Ü“ØÉ-e4örñ¯áIÊ2#ÙšÂyKwŒ¶t+ Z º\[ø"© XludÛjÈ=6îx:žÉºö c;ºÙ‡ o÷Ê*#V¼ÏËÖí®|Roe= *huh…-ž7Ä ™PÎÓÏRõ‚!O¼xdÜÿkí;à›ºï}u†$o[¶ÓAš\ÒʇQ]ƒ%2‹Ò6mŒ›6qòÒr)’T%M¢Þxí½ï½k $¬0Â4¦Ùf…6IÆfï°‡ÿfo¿ß÷wαLH{û>Ÿ— Ÿsþÿßøïù±ÐÄž‹êÅ1›1ïÄõy§^·Å㬘ËãÉæ|C#¹6-œ`Œ¸1»œ4¾ôÙå´ W¸ú?g« •jtéìÚÐÉÎSC§;W·w<Š[žó]“Sc(|\°ùjrj kr¤Ðâœ^½hDvcžá<¤TíłڗPóÄe<7çe`þgÀ^& .Ñ}ÝFoè…OÇï §œH›ó¸-WØ lsžècoÞãõµ›¥Û·äeÿ‚àØõéäC{óÎr Ý\: ¶£‡¬}±yWø‘]_›®}ÑÜÁaÇÞÐüõ4ÒÔ5IÛ¦÷¤1v1Æ®_ ÏÃÅó§ö¸³)Þ?ÆÛѰÅ«ã‰öhñ>jU ¸•oy‹@qšIqšNq†]̸âLPÌÁðTÍÍmÇ\"¸ŸÎÁm|™ó”~NSà;Óò2ç.sb<>¬·ûÎRNg•GÂ{8pl烠¤eB‰ÅI{Þ©ƒ}¾Ó\ŸO;­ù ÿ—øú’¾ªJoƒt¾X}Á¿!ŸÍ}7PðäëüóÛ7ÒÇÔÛþÍô±¢\; •ÞXoÒ® ؈SŸ¯ ìÿC„¾c(¼#Þ#1"!"p…Ãx€ø/X·”›eÄGÜÂA¼øP"Ž1â(âä9VÐB~Œ@‡ 0^` }QÈ|çŒâ8OÅq:a8«åë¨7¬_§§-½œÊÝ›œÒU¬TJþš6®>îpM›iZ‰:CòoÍwõu‡·R™L/±n–üÛò]ýÝám(–]¶$›ýÆÞ¶6ÏNQ/éNQ/éNQ/éNQ/éNQ/éNQù«ÐvIâõ–¾Qoš¾QoÑ‹=|&OÜF¦ëøêäÇŸŒS’©r4t&†xÁ·ðe5Ûj÷IšÐ]$ûZÑŸ„?Õ9áO5ù£ZÙ¡ _`úT%ÄùÎßçSõßä´BJwÏ}‡Ž9-÷ÀÂÀÓ\¯A®ÃÒ½AŠýR¢¿;KåîˆøüÞŠÆÂçòÄÛÑxø|žøs´6|!O¼Ï/PO€ÿÅ÷£Yþ‹š „[.äŸË£i²¿@÷B_á+¯i^qߥž'Àá<ÐÜ\ô9ߣ¹\¤ær6aÈÐAÎPë}äÎ,‘NJþhþ,Á(êûPÜ‘½ÚØ'":±§¹K§©oDê„㹓x2ºØ6iÄÓ1BºØY<ƒgCgáEL¼6(:‹gc¡†Î¾ùñÂù’†x›=\ Ûu°â¿eeìÝNËØoeâõÛéëg¥ßŠc1Õ˜ë¤FZýð ý‡¹˜%z^Åæ»ÌÝâ&“åäkÉíÔWÅ«ÔÜB¢3¿ÇÝüȸµFp¥j-nûâ4uv…ÛÅ®¨ËHUX—i㤄9Ûôw`D‹vÒVC¡½Mý¥‹èƒZ!›Žé¥'X—*pUF '¸¥ ã†AüO” }äàã¯-Ë†ÒØK÷6°òâ?œ–2+€+Êl¸*KÆiÙ£„"Á|Uáå|)®?r_`g¥j·ûì~þY+r8y=ÌÉàjÞ|* —Qmñ¥Î’ø·Íêø¸© nüÄD´«£\.c¹\H- fÄ%ƒÇˆ×å’X&ÝW8*›¤î"VH\‡;†w—U“;jr‡›ÜâŠêïCúxÂ}<âªê¿A17ÜánqMõߥ»îð]·¸®ú{XoO¸·GÜ Z)öö†{{ÅMÕ_AÞp…WÜ"jôÑÇîã·[R»£úoÓÇmwø¶[ÜUý} ¬¯7Ü×+îáªåo-ÿ…ÆS*!ÍWéÅxú,ýëÖˆeO³6rAÂqí Úß*êÃã ƒm?kÁØ‘4Ñ6‹Ï„¦÷MZë+êïó¸ó8Ã<ŽN/?.ž¬Åê†Âñ™q6¬ý MßcñYÔ±{Í_P„ÓÂ1¿¤˜_Åâ£g~P'ž‡u‚[<1d‚øixySð Ô<9PÌ÷}ý¼úäp‰&‡›yCNnn&b.éïmÝí²¾•Ç`M-5ƒZÊ,–»­6«ÍÛ8ÉÈZ¿NÈÚšddmC¦¿3þE¡¿‡_TÐÓÍ’‹?‹–Z÷óDg¢ÒÛm<üÐ7€Óú¯ô¯Û|/#î– †–rq}ܲUµ¾ÔX!Âp:×Áò³©±@¢¿§ dú{¥@ù¢zŽÆØ…²ømªVËâ×´©Z,Ó”Wª†×É¢KT ßÍEÐŒqc—6[âjsû½šæƒÉi5»‘y)©‹ÖôÜMKÇxàÜ£¡ƒmsþÌKFþªùi.úñ¬ºjÑ){îÎú/ 9z¡½E^áA4ìömÓ£éÑ;ô虡ËÓµ¡tÒ—ŠhȺP®q«Tcd¤¹ÁLsƒžf6\W 7pÒ•ëm©¤Óh{ÛL{îXbª–V‹+ïA÷´³–ÃØ°\ë´ð…v¥ì´ìÊ¥*–/)µ…Ÿu”ÙÀø`Ù÷cÅ ü‘l–„£†È T.ÚmÁDù0Ù, Œ0P{ª#e³,0Ú@aJcœl–Æx¹HTÝ—¨©HÃTÙÈ…ÅÒÏM \ZsP-1Å;`^ï@W‰•ˆxy=´ÛòX±ÎÅ2¼wf·5]µPºE†ôNYý’é—›`©ô’¦»W‘Ù9Ð6zLî*ï Ç¶e§Œ«W5N)k==¦Fl{d±M6j¡^ì`§Ýb'²/ÞAB¢±+‰QŠv°ˆ8½¸näóšŸæC¨¾ØwÉÔ„ +5 ð» †ß)ñìS.'g ‹å h«Q+ô,Ò¹GöI˜|Bz % çÆ4í“KíN%ƒÕž¦Eì ödK:*CÈ!ù²õF lòVROÈâ€ì{ˆ§§2õVø¥-Ib"ŸÑØ•ÄÚElúK•a ’/¥ÉNer²ñ [1,K'`50-ëXŸ’y1¥§ŒVVÉ…½rðC¯8mpK!lš3iÃüRÄ#dRsD2‘]ŸF¤’¾7ƒvëç‰nñ ¯E\”A†Å×q ƒv£Œ[¯qãe¹ÇîÅâ •({o¿–hKܪMµžâb€¢ïnuÓðÁ  »IxL¡5ô’pfŠÚP…òáJŒYqEìŸ(Ôµj9·¡Á^ع¡RsMïZn=¼I•ŸŒ×P3Ó#Ê¢>#¢~ªˆ1 \f}èÅ®Ó'éïT¡l0ÈÅ™«PÓ™©¢f3NÑ)"Up[ÇþFð²tw·R­Ù"h…7E‰þÐMs™ugx‰¹n]¥ˆ´DË”8ýùZEØ;SÁå¤èå·B‰>6Ó«”¸/kZ€ñ0·jDÙäTÖ¹†”‰upÄ·¤k•nŸï+Åìé”"±‰íó t«©ªõ(÷Ë}z-Xég£÷϶°Íw°+{’‘*¬zŒ ^PŽÃ~`‰ ¨+ë =ÖvR¥Àhh¡lއ˜ÄrÊV–¸i]Û€ºžçq±'•6eö¬VŽ>«@!Œò#tç”õ*U£¸ ”Z絇Îh»R«ëRÙ<ý¬†óÊÕÙGQ¡Õ{ ú$]g?wØMNÖ %‰KJiTu{ˆNµK”\5,¼¬hevݾ uê«TÕ_P¢®Ó“z@ÖÿBºÙ2Y·ŒdÝþv²àRÜa +jî6ö7vWÑ“Éç÷('!ךew·Z®6NoJÕÚ 'ÊUö+v]YŸ\š\ûÐÿ¦¾wZVÜ{M´K1l*óÙºÑtyÄäÁذÐbãù#…ÍÒbçÞ †¨Eb!gwÃÄ ²q´”E߹ϱœ‡9å̰]Aîæ:ÔÝ|yúïMt()7ƒ÷2°/hU´™±‹i´fÆM•n©­ª²Â¥6ØÚäVÓTë…Û¿ !ï”¶e©z/ ýÑ¥g¥å*«é}N9e=Ö«+éQý’u=æFl«UøÈ³o Ç¼HÒ&U,WËr\ó#ÏIåËrêÅçj$œ­ v›KeªÓG|Kå«´T¾“‡0¬=?âµç³^”\yYúWÿÈv®9…G¶kÊ_•Ÿò÷ý©«÷«á¾?m*^U~å¯ü©«Ï«áÊŸBãÐÝâgaDtþ_3ÿ…X{lð¿Füûiÿ¡î–zC-×¾ÃÜðôþL㢈'wÂã$|.”¢b‘dj訉 ë‰L’ü§ÔÀXgø”*ª°úîÖ½È/ÒE­ Ô ùçÖ]ÐSÄ^s-¹W‚Êz,¿ˆ–ŠmˆäȯF€_fŠ•ˆø²ƒC”hh0"F»«-ùgi$ËEfÖ³+%f¤"F+̯VüZ<›VI”„OÕ°l©Ò<-¢Á,e`°‘SâȬÑu^×w•f)b–âËD0Û€¬‡ë°øs–ð z¾Åk–,¸•˜«cJ5¬}1NÌh4õí“^Ø'1üBÞtOó#|Š}¨¹†;]5±Ôt¿,ážfÉhh†ƒ½Ò¬$ü‹2fË.Òc.ÏoEËZ¼Úì ¸0¦³<àXg=¤Ñ-Ói4Y‘f«b¦½tG•Dµê댎uJ€sÕ84<¡ž:¯óÁùN1¯ÕÎ`µ‡%ÑÐgpŽS,Äëbgp±S,Âëgp‰SÔàu¶38Û)ãµÆ¬qÒ8H¯3Á™N±¯ Á…N± ¯‹œÁEN]’ñS·JõÛ ß É­**«Âôµ3Xc«‹)Æ•lE/3n€Ö “ 7@ñÍ–|W$Á#¯o(­bf8_ꕨ¸d€ ÉçVˆÛŸ¸Iƒ[-£²C¤:~5ä;†jlɲ^Ó…@Œ°Ýz˜.öa„í1q‡y›Ãö߸¿Ãàw4Áïø·øÁ1Ù7ß⇰ß⇰“ß⇰Óà7ž{æ£àwC5.Öo¨â„Nc|£`0¶XÛÐØ²7ȺN"®ËWò¯Ûu¾°ìϽÃÌD÷ßÛêOrã 3»ñóˆð9z°•†‹ø*·©`I¡¿ó çl¸†_·ØÁÓú“Ýv*¦çFKôïÉwõëäZ“\"÷äÓLY"¿îß›ïª~Æ5ç×䏿>ãš÷Œkþ3%¶à^Ü2NqC‡ÅÙ¸"""ÆÈÁÇ¿ó0ףܬ‡1Ê}%<Ê€=)ñ§0È‘{püY"ûeÑ(ö"|šštCøu6?ëa½£]§íóʈt[Â%tì¥áV*kÉ7ëáXᬇ%@Ñæ™šþªÔàªTÚ=ÓëêÔàêTÑ„×Å?,ʱ­\“\“*zãumjpm* Ÿèh—<,úàeºÛTt¡4¼äámYyC­øu»©+ºŒÐƒžÁ3Œ~:5“'ï7®â‹RÑ6úKx¤&^DŽ 7¤3žGük(¿é–×°x‘þ(þ Ôb¡O¼õÂÜÊo…¥ÔÕ­cÑÂË?•)8À ñà'^QþÙLíEP{Ë öié=ñç`óÞ;Z‘x¯%¿0yDý{›"Ñ#Aµ'FÿêæÆµ ³óH.„ÑßǯÛ-4®µbXÇçïΑsÝI™VÛv¥qMDtå};-(ËRiN¿ŒéLWKWN+ý=ÛU¦¿5]”?ÒÞ­úaÈÛhªŠm¥Ø8ØËhIIz“תÝyjš^Lý“ø#ocUá…–)X¥šÍ|Ó2­4°µ ¯©íT`…£¼–Ðh/¶Éob"þäûq,4^ã5ošx‹WCØÔ¾”fýë÷w˜­\h­kìêóô¹%í=ñ-Ê÷I®òn"ÂÓJYºø M+¥éú¼òöz¬˜RZF«ð˜dˆï¹tMïE‹ß^œ ‚H…ó÷1^Ú –eˆÿI«² S.¶u+U}ˆÿÐj]uÿ ŕѥ~þW)-ËÿO3xr:êó¿Ö'‹˜oÒCÉotùJÓ g,üK“KÓæbò…QIЮ”ˆøàn¢Ÿø°U,´G!ð•íe“M |â¯Å2W ¡R±òÁ“V8Ô¶ùây¾±ž Ð/Я¿¤9c ZÔ·jµÙ7HˆÙ’0Tiø¤gϸ1à Юi[’¿–ÄÞ™ö¨_Kª+D•D%ª“Xm‹io¤‰ãd.0V1*¥VÒkE»$T‹ªWË× à-¦ÒÙ‹UÕ§¯®Z㸆ÖW±JVá:hú‚¦PxŒ&Ž Ÿ ù¼‡|–Ó‚j,ò¹È­Òñ;Dô3ϹúÉbÔ˜Æib  6™¬‹¨Ÿ?•ËYPF,ÌÖÓJL.¼«Èårx¬&>f¥¬7Cj&šn‹™ÛóˆXnrc­@â6QƒÑ#S«e#SkL>_FÄZYÏÔM¬cݬ›fÝ©I`³4Áæ„Éæ„,NM•&Î4³9k²9g²ù*"Îl&iâ«hñÚõ ¸¢{iºbÁ-]4ô©^¦ˆ»x§…Çkâ^'já¸"šðZ¥…÷(¢7uËÝЗÿ+}bžŠÀ½CMi=výF /ÑØóó>N«Ä°ëòI±G4»i×å*uñ‚Zþ¨6®^Ç(ºíòñJ¼HLTÞ| ¥p_>.õ>w›*攄Çóü`¿n·yžßÏmCå OJþª5Î/‘6Kþý0}·Ÿ¦à%òNɆñÐçÂå0u‡E%ê7’ÿP~›à¡|Ü$[.\3m7ÑWºU%9ãÏ"Ы5®‘7F,½¡O8Ò|‘|8TvgV–õÁMòùþ«ä#ùÔD³Z}û.y°ì?œ¯óeòP,’Úþê¾M^å¶IÉ)‡$ð†øžT¥â¶Ül¦L’£Ûß ­l^¥‰“©æÇ„Åhð˜!G]’õt+1Kö¯r· ¯r‹Ù²{§6áíDµì_Ma«Ýb®8”Ïwœódÿ§^-ü©—zDà`¾±‹dÿÁ|Z*k®‰>×È’¡áæ‹¥²oY’árv§¾€\† צH4Õ`¡ŠRºZ6àbZ³qŒ5h¶«iÝ“œò²7Úlm£(òÅÂs5j[ј5fåíзãi+±MöªKÔ¹’S~ ô)ØiM×áø€x®Ö3 ÒrjÌÚ“šÕZšÓ“Sþ   LN ¨A¯ü¥´Hu—5V=ª^,Ï]VÞà<—BEÒG™I?ÝÊHú'j1ŠöjhlcÔhk$k¬Úœ¬qªž¬ñXÈÉœ~NÓLNÓT˜-ŠïÐ$ÚóAÓž õØ„À×ñŒšÜ a?Šˆ­&öVŽŒcpÿðMìþFÆ`pÐÀ;—…zb¾á×"Þ¤¬ÍdµÓ“üç-¢ŒžÆ„¼‰ù0ððf¼Pà±™yh€¹ wïéÇ3Árk ®\¶$²4ƃ†Yi‰ ïå[Uˆ˜BI±-±51CävŽÈäÒAÄWÖÀÔd ßA ý䔯eÅŒ÷뤭 œÏxN:he'½I¨R¨{èP$Z§[¹¤êzqÈçQà°5ê:ø:ªò¨Õ7Áë´NÀ]~8N˜¾±ãÊ)«SŽ…¶»qöô5ÃÉ)¹ÜÚ¦&k`µ3ZXñ¯ÈûÎDNFÁÀ?ü³.BuFå¬ëP9ëz±ð"ML†Ð}Œ){.Ù Ùª ¸‰x‚ö׈ŽâÖ´k™6õ&íz›Øcóè è$ö‚ËbZ¦Ø¢®5ßJ‘Ä0Ü• (@ñQ\Šu‰ÔÞ0)Þ°‰[ ³D·\Ÿ¨›avBaG1[,»á³>Çß“_‰ðÕFøÞDøv„m„ïK$î8ÂOØ©7#qû‰;g7wÎ..Ø)qK5q"ã90w€|Ï? Ýaæ ´o’Ù7Iôƒ3³C v)NT%ECËÀî0³ãÑeº‰4=IÌL"vË41;)ÚšK´TŽ$¨l•íDåsP9šHtܤO»@åsMÔùXù ÏòJ çæÞIhî]ê™@c’¸Ì0±œNXÂ^´KדÄUÐ\©‰ëIè.ý \ÜHгhã­¤xñf¡nÓs =ïñ7 Æ£“¡¶ŸL{a0>‘Hõ¤dSm?YLN&4OI†L`y?'äÕ@>•@^k"¯M_yµ&Öù47y®‘m@ÞAÈ35ÝmÕ™DîGÜÁdFžMÔáq“êñdqÔÎ1†q—q59ðÇÐÒ¶ð‘ˆé›B1ýR(f b.ð8ËóÁÈÃõ¤1:ÅÉS}’Œ[’ÀDo/6»6!%Ú äW‰I)+Y¡Ê\xŸœÖQ±Ð'§ÄBŸœŠû`´X.r2¸{# ‹RØVjC"CËSÌUxŠX‘Q´Êf lÕQ(Q%š"â@¹ÄùyqGÌüœMÇŒüœúv~0ŠŸN Lòö#;g[dç<²C1ßÊÍ~ÎÍåDÒn#iwõ¤]IN¥àS9øj¢‘LGðÌTš7ÐH®%ɼT$··Û2/U,H¥F²V áCðzy7áúÈ7ù%DìH5ÊaGªØ•sJóM׬ëhÙ1ŠM×Ôƒè:MìI¥d´xm;IìMjášØ—ªÏð»™àwü®¿/ÀïV"±wM~wSEèÒb´ËôÛ‰áìã4˜ÎKÓ‡³;‰:•fàŽJcØŽog:pf8÷8óLœyibKø$ùp6¦ECë‘ÈrOs"·›HÛÓÄ×i”ÈõšØ äÞt»ïæ0¦±†½È€z=Ѩð4¿†øDüKïÃćˆ{&ñ{i¢<ñ1>êÞEôI'f_j¢2Cë/öOo.ôéQ×}ú82; o¯èøt o?§áí7–‰éb"ã—·¯ËrñÉÇÞ×¥Éébrz,ðóþ%¦¤Çy©35ö`ö"1-=¦Ã‹Ié1ÇvÚ¡ÏLÇÀ_éIdºYéb!¸÷ã,uá5ŵ­_¥cÅç’rÛbPú¨eSºØ˜n®6¥£‡÷¬›ÓÕÁ–ôX‘ØÎÁ8ñ v½}醢Ètq€ˆ2ÚÁô@•×)e@,æPz  Ð]wEIÇõø€D\MG$êË3q™ï¡­ZÊSÜÍœÜM‡áK©)]41Xe½(Ï  Xž)*2ÑÖÑx¬¸·K}2`ÕÔÓ<ªËÀ´”( O3 ²ŸfˆqÀœHË`,ʈ†6"§%ZÚriy†XÞ5±È{TÕh0¦®À²1£AÚ‘ð8ÔUÞ˜!¶gЀ××;2ºˆ9{i“¦ˆÚ }ÿ±=bî?vèÕjTÙ^&º-bÙËÔ$„B.eð"k(¿"¦&™Ä°,ŸY!ÎŽ¥HE0j'FØc¿&0F?€a±ŒõHŠQu3Í”ÌÌâ#ð™Yb6R;ŽSû6÷H¹h·,Ï+²b®Ê¢ëÒ ±: ¶ÖiY0k½6+ðÕðºæ‹,,¡3ØÿÙ— kß`„c­°…Þ)a ³ ,Ç3ËWÀ²ÎLU]–Ø¥O¬{³°9vü^Å4]s è,d!s‹Y«ö`–Oæ¬ÊR4Ô”R<Õ+‰Ã <Á“D½r˜Êëa"ݦ®uù³õ­Ë³v‹‹ŒÏ â Y]Ä¥¬}j”¡ï¬î²"ˆæ~(å^ÎÂñ`’SÍhîr0&§öDõ_ÍjÑÚñë­"|dûðG'Y©]Ü$æ348boâËí,q; '(½êÄ‚rMíc4;ß mnWž£‰»zt{ÛëÅ3Ö½,ý¤¥ÂÁľ÷·^“ú:D_G´p»f¡¬ŠJGúlSj·øÈáŸè…öðD/ÛU†€¨+Öɧ@ñ‰#êÚìãÌÜÊÏù5š©Ãߘg†©cvø/QÀ=€ú÷‡ÿ lÕ¨›êð_¥€mzõöñì˜ý&:¢qæ%1ÉáŸ^Ç‘Ïg}dÝÔ<²ÎpDÛ !ÍÄsº&f9pçéÁ×@î•óX2t¢ÆÑ©^,tðY[­Xj¢†BhE»Ú†íbGÌÙ<ð¤XâˆáàŒ‚ªà‰Nb©ƒV½±àj”¿©GE¤±ÂÁêà »Ò8@W9â¸5x²“X ¤8!‰µHÓ$J“R=7ׯƸu4H+|Rœ~%×ÑcO9ïQ‡ïÙž¥J®q*å\:4o×ÑÇ€_ñÇnQ=— &»µ®šNÕº Gwèp;ö'†×#í*+ë!})öø6ƒï½üHü0ƒCb×E Çòµ®¹¯0¸Øï00êÅG,O嵎*ÊTÑ'»TuÍy¬Z7Nï}^Õ3Õ7[£x}«ÌM-Ó›`pLÔ/» hôÏŽ•ªÁÛn1 ›¸ÍëÊÌïºÅ‡ôZÎ'kNK¹ ”¨ë f].›Üb àÇ?Æð½=bÐwÁiÂ÷ñˆÁ€ß gîœ,>ÂçF½6ùªƒý¹¢2—ÏžqWÐ_c…Ÿy¥"Ñ?3—·1Ü”?Ê52ûQ®’‹=Î<^?qêGš‘#s¤ëOJ#sņ™ÏâS@†¹è³LÌU¹ì§uA‚ütŽõ”ez®˜É¨ «y¹ècºÈÓ|²¡Ësù<¤&¼ÁërùB6± Û˜k^«äŠÍ¹¸^M`ìÆN&¿”J[Jê¤ß›ýÁ7­YÞ¤}ÇÀËCémt ~Ýî°ÔÉ#„§òA>N–y,’ÕÊ€S—hwD¸}Ó½­»ÝU»4[åivXôáó–Ÿà2Ëšo5|_zÍâaóªO‹Ž´’ Ëç­ Dœ è£HxpOxãµÂjU*ϬOèƒÂ“%­ðù´oI«Øs–Â%­¤ò%­êÅ3þcùñÐÒVÁcù¢3ð-–5Ìñ?Áñ%pܱ¼Ô í‹H/‰WbU?Íu¡…¥° úœwÿç||:Ú³GÏøýàñûÁã&8 hÿžoºÆcSq±æi!J ù#nÂ<¦ (<ê›a‚ÞS ×kC~á–.ß³Þƒ[rÁð­„ï›É¨9;ÒðëÖÄ׿»! 󕂬/>xó»¤DÊ÷ŸÈw-- ŸÈo–•ÈOûOæ»–—„OÒgôå×þ£í\“>ÚŽvů¨ÅþCí\sŸ j‹F-³³ŸZn“š³CûfÙ)W ïцìlâäüÙHNn"9Ÿ—Híý§ò]‡;†Oÿ%r'ÿé|×Ê’ðiú\U¢<ë?“ïZ]>CŸkJÔ"ÿÙ|׊Žá³ô¹¶Äúªÿ\¾k]Iø}~QbóùÏ)Gø<ÄÆ6Óh ZÛ6ˆˆwyiõ¢å]||(A@ê€&"¸þw‡öiì®j‹‡f†¤í €ÆJ¦çòƒi¬Ïåý¤w•î’Óò®j80?±Œ•ÄxŠŒ†hì|¶—˜O”؉ù_%‹˜Œèhá!ÍòKáQMæøÏ(PL“t“û´Pµ÷¯eÖ@?É%='í†"-›ïüIû2[û2ûs¼¹^V*²-8Ûûü®Â0ç.Ý0gm’ÂŽ´ ‚óþ¬â,‹™{hW ç{-=ÞUÅl|Ñ|˜‹à\‰ù-ð: «:_òëà:(Ž*×ÑHä“2Ç[åªy»ªøX)ëEÜëd¤Œe @<ŸˆÇ#UÍX«;ŠR’ÀØÐÑÃGh¡¥\|X“źæ*@eG|ÉoEu‘×"I–/°/öZ”~’e‰×¢>dÙêQìÖ¤Ùª{«dŠ0œŒX¶ê.Äök޾ºÏ0j.û5…uqJÒB/â˜í.HTàªQàì <¹T­¥ò¶R‘sy/õòš1^[jåâ¶%Yݪ⨧âV“”x’ŒòuZ2°µ¯göìçBCföñ7n==j²5i£Œ4á4ï¦4ŸŠÈG$n”Ý¥ø»rƒ´9d9B ôtD:"‰ã°Ô^fEáPmFii«æ0(•ööeIœÊe”ÊdHÔSs±s:“’ì°dQ«[²(U“àÞ^ÖŠhŠøæÿ…ôòÿ'Ò'¤(ýþyêŸÿÔÅInm˜Á)šÄäÔ8¨A¬äֱݣ$«Ö¯¸A4H Ëý$]ψ˵A/W<ÎDXÇrOHi”D#ÒjU”%eE¼¤R»é\yH½,‰Ë­Wy™š¸"•ZúfѾ;¿¶^“Ä5 *Z4ˆ„V³ÂÇu)#dz½¬Èr›ûÈÙˆ¸ó@‡"îî$»£?e•r-š0?ïð@g­+2Siú{;±TB²»„ÇÑnrYô‡.žƒÙà‡L³Á•ÐøŒ×Æj)-hýeŒ G ÀƒeÈ~Ý<î€ñ5ƸߛÆý½Â0îïôü}Šõ0Çu!ßuê±ð»¿,‘濘ïÚ[¾'ŸÿC)ôßlïêÓ)|³=‘‰¶œwÎGÄ ¸ùnæšÖü+ˆÿ1 aà÷@Vô;¦Á›ÅÒþ m]k‹ÃÚÒÜP,ÿÂ?±­«ú¥ðDúüªDyÁßïúªc¸’³¡Dý½_ä»6–„f–Zž³/°õ/ª»=ºæEœ7©ž—ÄEP=£Q+†y*¤ßžL¤ß¦ÈÑÐyÍØ.ECœàz°--_øZDÖùNc(ܵ'XT›¢xÕ²˜ Q¼óš˜I¥}‰ô} QB¾À÷î‰\×›Èõ²Øä šØ'›ü\ï7¸Õœðç| 2:°`}Jeª œO¼^ÔzeC…þ$4Niâ”E`áÇ[ ¾/Î@âç S˵ˠvU1ylǼ¯):ïë€>äôh“ ðÞj´ãcõ°@Õ õédéM}zÜ›Rz\ŒÈ}UÑGõ­K‹†Îi±Âuiuî§FÛ„¿ÑDÕ¿*-^•&ªq651Xomøú×^ÕdÓ(wÖ¬=L|®„xÀ[Ãv®–ÁÛ¿¶øš&gAµ…×ÜÐÆ¥ý&ŽˆÐ:o`81ãsrÂ5Âj‹o>ޝ×À ‰Æ×uF|mñ MÑU\›C®Ót´ fº©ÉlV£ ŸÔÄRö¨v›½Â††X«švÐ0-ɰžŠi‰Úd­Þ&ëô6Y¯²Ý³Ýª¨ûvÓ„)îo4jg¿o ¥HqDõ­O+^ŸfÉ©Ln_ÑÅÁN©Ñ⻚EœA lƒx-º5Zô9j™âïµÃÆûÚáåD;WÿÛª+‚2©Ê~;ðé‹ê;(Å JRè8õÙ_ƒÞjEPñiE"¤õ¬ R{hSSSÖhZ}ß}°¢q&ݤ“ÿ)È÷¶ú¼ñB¯ÚfgâhF“Þi—¡™ô6"Ý™HWZÿ©¶ñÝ v‹°þÅ·4)ë&ŽÞ­Ü<þ†@cDdƒ¬ Õ\F(üÂ+éç€&>Û»±Š¬HK©5´Þ›¦ÛÆrî ¡Å_ze˜Ãf”Rkñmjo|?dE_š…C{‚ñ¥ˆu¼¬`œzãT¶"0Qg Zf\e…"½Áf<'›ŒmÍŒgA¾ÔR™±˜CTÎj®9ñÀ;×-n¤V¶Àªš ­fk[d5[[ Œá!ÜÍs(Äè`€ú‚– KR«€K#ÿjk´5†ü5U¼ý'Ôó€zÔ£¨¶ä12p7°ã£.Ë+wš V˜žþoZ%®¶ZÍ6 ´î_xV‘ŠÄvë-  ;Œäk+l/ÆíºóŸk1ÈNÔê.™¡¡¯¼…ÉgaC2Q‰?H¥0µÖ檋nÀWÕ$aì¶bäauÉ݆¶¤"öXMEÒ÷îJ}e¯>æQl6ûZ‰ç]+«Ñè£ 4Çô2;¦;ü®ÿœM»Ù¼õ&'Ù]ÝW9ÓÖÜÍÜ,‡q9¢ž±Š3V69i1ŒdÑ Ä ú¬5Zj^Òä» Oïm›œÔ¾çê%[ë´Ìu,¥¾‡ù“J‚€hIà’^Qóþ%gä‹|F“Ëxœ´Ü‚“Éç$<+òG6X°D“kZ8ü%òq%¢ô¶±)ëhrF6Jzm²ã1ÜØt§„®}/ECw46ý\ ë¾W4ÑÏÖ¦H äÎálbóVƒlÑ a˜??bƒÍìVöc[,^KeÀڪⓊL±ÐÙÉC4Ù µa%õªÝ‘—Q,^I¹eã\ŒÒmB³±èh3»OÁn›ìÆ%Ø¿ŸÝ»L±-ÙM€ æ •ÚÀ.º)&»)6¸+”¦0WKå3f®Î±‰Ïl<„ЀOK}ü€ãì¸9x¨b:ûƒ™aã±€g™iFÄl[”ÏÓ‘è96ìþ°F ˆ íáxUN í ‰&ûžc[›HûJû|Êr¼Tå1fòq²E>–˜ùX¢çc‰ž<#Ê2=kmlAû¾|ȉ| ­©âs3+l<˜rખùXÍùXïE>Ö¶ÈǺïÈÇ—^…`îËÇúùøù8•¨}Ý\÷´§-›õÚ߬×þ›ØÚ²ö·¡öÏ%#;µÿõýµ!Y¦Ø–µ¿ÜN{ }üspÛerÛÅl¤z›¨·ÁO"»Úm‹ñy)Y¢`vŽH3ä h9Î ºöÐ9dþ!½ðñØ%ˇlâˆ^ÜèNǺâ4}§·âM^I|C/Zñf¯Ìgý§\çgAþ,o.xÿÕÈäoä[mâ²-°*´]µéË—k¶(°IâÏy ÅÛˆ÷ Ã\nÆÙ7½™½Z¸}`p›zs%$„Ï{LíÂtêÚ75iŸó¯[ǯÇ5ÄbóùóœWh›b‘,ïþ5ÿOïÿ~«¬G~pðÍîïÿê`Ý{äÿ*òNäýW9èW1ùà¼ü çûÁÞŠ¼÷ˆÊÇ칞ïžúð~×óÝ·Þ‹ôx냿½ìñçï@¶ýwLyóOÝ¿ÑúŸÿkÙ;={|w.íÿ¨x"¡~÷ÖŸÂ|^ò?•Ëï@LúˆE=¿+kËO=áî^Pz¢ ÓãwïþdY§ROi™û‰‚Žžzòñ‚`§îžàãOtw—>õT÷§Ýˆ,-{üéÒ'º¿Y v|òɲ7BD)üÆ›oõøË;Á¿½ñê_Þëƒî–KQˆ8ÍýÕúò«þï'+^é(Y,¿ ÿ-–ÿ :ÎÆãred5-1.0~svn4374.orig/webapps/vod/osmf_1.0.0.16316.swf0000644000175000017500000065626011747635016021455 0ustar drazzibdrazzibCWS ©xÚ̽IŒIš.Æê"“¹/ÜŠÅZ:‹µpÏ “É-“[äFfUn•d-]=1žáž‘ÞŒpvóÈdöÌh3x’ŽÒQtÑA‚ ÐAt ‹nºè ƒAÀ@€€‡wyƒ …_暑Àê8÷NMŸš;µ€oüÓÔ©Î|8|nôÂå¿Ãÿ ÿfäÿþàßÛž·?þáÞ顳cã“SÓ3ç/^šý÷ßþÇÿùÿýÿü›¿¿ò_þ‹þ›þÏÿÅôß}ðòÿø®<ûÇÿôÜ?ÿ>ü»ÿõùàÿ§1ÏéSN‘ÿþõßÿþÕ‹ÿð?€ÿþ³4}õ%ùówìï© ò÷ïþÝÿš]³¿×Ùß9ö÷døÍþþW,ýsöw’ýý?ª§Ný#~„Y%—ÿø/«´ÿ׋{þÔÙeßo;–7‰ÛÝœ:sÇv­™-øwÏA~/h:Ërn 0°Ü-nú–íp«Ò´¼×–g·¸’-|úÈwí©Øý¸_‡Ÿ¿Íɦ~‘s¿çÄÝ Ü‚C§:ö¢óÞiöBîÍ›Þ<†jaàz­-d¯ íSÆÂRX)W_ç˾sN +º–/…KÑ#]ÖÍ|9¿m¿å¢gHÒ—ù€fÛ÷œo”®68DW:w°p°¸ì¿¯àÿoiˆ!<ч̵eñXÿ‡•Å_ü®ãÑ/ïd¿ûe?°¼æ¡ƒ~9t¿ÁÞÅ/dWâØÞ¡_ð[‡÷Š~<~AAs gH/p†¿(þ‚3\ÂÎYH§XáIWûˆ,~„Ó=<í»«Ø÷ßo:^+—© ü=+$ï9–}ò²ú­k;>Ã/Œ è..Ço•©JÑÆkq³o6é-—it§ò<ë«Pçðh õ¤A—yi Ké6“ܪ×m¿—¦|[ýàE4ØÆ óaž«Ð1…l¾• ÒFôFp×sÑa-ô»»t„›‘ÖÝtÙ9 cVÛõœ-+xçKñ婸­,SSSïêa;$#uE— kâçñ-×è`†í ñc‹Ô·õàôÀm˜8<ÖDÁlR¹{9Köµòí£`0+ Ó•œ{÷ˆès½0Ã$ž ᣼¹ã;|‚PIðàŽˆ´ÜZo_(Eì9¨×~õ<¡£Úƒ=iÜ.þ‡_3['€œ¬v›ts§Q¦L[ÊbµORÌé8É #‰j±\>â açà÷¿g;¸Ÿ²ZθjÙP%z ä£S/oH“Ô:ÛIú¦@6úqÛ~ÀþU‘¿¾Î–µ)î¤!ëÏó¥r2jZ¹ðïeËD{¯!/:djˆ@ò¡lÖ¶ôÉê‰YºwŽG´ \0†­yvTƒ\ñlÎêÙ®Ï6Çñj/ãl«‹"Oóe«peª^~kÎ{Ðq$êõ@xqM$ZAJ’Þ.%©#¿Ý£;Rðm6èï¯r¤;=\V ,ÂŒWs„º–rC‡–Ymµ§*6lœ’ø¬,™ç®•E+#\µ/–¾š‡n›|ÿ¥+ÕoÛ›. Þ|¿džsœ ›+>ç!›åü¯¦8?k3’‡Ã*rj¥ â§aóùÊ‹ë›ow­á…–ø5F6Zwza·—_ ü ÝC‡Ãë=/©­˜‹ëŸ%}ñĆYô®Ö{í6œË±¿óšâGTÏ¡°&S øyŽR–îj–ð mµÎA¦ Àôº@ôòÙÎâ^Ï«[ûm§’–¸W†ˆÓ±ä7{›[¾í¸¸¾áaM‰ä@ný|ž/vž±¯ù»k¹yƒÙ…EI”ÔÎÒ$³l;¥\[e¨\smØË'œoÃ^/Ãú¡Õæäù¶ËÐ$–¢„ Õ ¢ CFñë·Ù2dø½–}N¯k\+<'/èÁº½Å7ÛWzήïztœ–/þRc|ÛØszˆÔ‰ð¢3oþŠX!dðÐ(ñëZ|ºÜ;8p:—“~ßÈ“Û'¿Ùûv±d¤òq³X¸ÎuEqÿ2ÑóyT–ÓËjÞENÅ´ ¢¶¤ÙñãRP¼|xf¤O–º0D㜰ðfR—FXœëÕâf>›ˆêÌ]Wx‚\´ÄÑŽXƼ.ËÿÖû#â­þyYÚ”†ÓîmYx\ €½7¶^øq@´o,L;’aüSÚTaO5MÁ(MìzÉÜ6mÐ0Kc‘lªƒmS¡VIÎ/2ÇcŽß Ïm’?{އho³YLŠHzÓVkÕ Â“Oe{úEjꢮâ9k`ʸ¾/€|oí½ ›€I—"fÁ DµªÍ–Ž‹àZÜ%TºnJ÷”MÕô½Ðr=ú ÍŠar6À²mZœŠ†pàtü#‡ÊëZˆ {¸¦ñÛm‚ΩÎÛí8êŽýƒkÓuøÐkÇm’×¥ór]ÛÍÍiHsÙmÿx±D[`E|RJÿ<×jåÂb96WDj×£‡%!n¹ô 0A+FDl¡¿Â['í€_”á …©Úx|«–Çï‘–l¿,À‡¼à§<ËeÞxH¢ø®ñB@Îé™ñè²£Ä`¸ð€jØÎ}žLÍi[i9~gdËà×ÝvÌ*KlˆðšÆÓcô¡µÎ“•rd¢ ÖÜ?9Ûo«›«° QÝ*ÕhÏNÛó]ƒϱp˜›¯ !©ޤ9ƒÂä¾Õ|·bÀ#ú=×k‘ñ—©ÊÏȃ¹±l4²JhÝç2Õ5ÌuO º#õ[ 0úä_4z™Ð›€Éêd˜LºŸ´~Ž´p¸±v,åZ1†ÝUŠå™ùbyyDWG2!ü¨OU€ª¶}E½¼Q(Ï ïJÚÒfЗizö‘"?ùu5[†gúÛlò®«Óo¥r”×z3OP¼#¤*¦ˆÂÔ ¤g@ÕYusa˜–ÀrË+ïè ‚[<5mZáy!/¦ªhjƒ D9oäq*Sâky’ø[æ½äÍüRÂ×ËE¯T—{'Ç[Þ¶ô‘ ÕÁP J®ˆMÏêºNVê7˜Ë¼ä{zâlÖˆs‘¢ ì‚·œà¡YžöÄ8oà yK6Ì·Ô^W¢{¦HI))!Ìb…”{:²U…'2$'zY(OB¿ÿç:H6»aHúê(üB¬;‰yyË-M :¡Ø2=Ô­4Š!¾Cð,ãI ; ’®n'¶r_×·69–šéìZÔƽ|aÜNw¿ëá ŸÅ P±ÀS=ÿó­udQ›FüH‡¾¤­ ’šyýkè¤Ø7óQr—?"ée•Ø¢›×ñåùö–ô óÇž8µèUáq#+ý.²>§ª×ÌNº’H%þ0ÉÏ%#¦^Ðæ?•Õ¼6pÂà¤zÒ¡ó¥Y¾sÿ»í‡îqô£Ž†×iÛÃk ¿S%þ(A»2ïæF?Ä0!«áN’LNÄ„›ò?|ðçPkÍ+Ïœ….‘î_N_óð+íëE´Ó(]:Áüuˆqm~ôªíï§<ÉOýdØJådò+1ãgyÓ3h‘n;x©ŠÂM-ý.Åô`‘…ÿÿ,%9°ŽßmuÝ…ù‰ßô‹ï£ôû=äüÜ"÷>Æ’rÿЧ]Uæ½ ¸ØË‘{Y8Ö•gÞøOSîán. ÝZöÍŒ:`ï6«†ÄýŒ‡>Uö˜M¹×"GV‡Ì=†¤iyXûxžÖ£'±i<Îûw]‰%¯Ü ؼ”HpsZÈ2W,Z+‰”Ç üƒxyd~ì¨/Ÿ§&Àø[`^Ç uSÅQ/=ûJ&ÝÓ@êÔ*Õª4[Æt#æÊö±…×ë(©¤«»¯Œ»ô}¨IqÐ[¦xΆÁޝ‹oU‚<U˜8ö½«Á„„)@ßÒÔýª†¬²üÛŽ¿Ž§¦ +Ò{yb ®ñ]6BÆ«•ÿì‹¿ÃÊãE—Šð¢\‚WFøX3•ʱÖ?.M]Cá²æ®ÕN¡Ïº±Ýiò »ÊÊÙx´xí´»²‹Ú¹Pýå¾(¨óOýPä6ÕÜlgˆoÁŸû£ÏSÀþe€Ô %ìÚ ÈÇfZdàœ"J’Þ"ß«ÆÞë›ÁÐÖÔ—z.)ü»Ad”¡Mýeò(ƒïF ǽy2˜‚Ìód,›ºáý&G†îÂR½sNÈ äÑ#ù8øÏÅCÈ¡+"™ÅW°p¥Ú…ÏL‰† i^*Ï Ya8ò 0öñ¬ï»,ªä¹¤[ÎÛ…DÒ”rNW˜Î'³¹eÏÀ¬l•a#+“…™Þ½ùä£Îi#bóíâÁŒîN<^‹îFMèQqÝØUϦj0îÂÖZ½ºZ­W[ÕúÊëÆúΛíÕjrÍ¿W|µ¡b±™‘þDŸ!¶‰P®zÍC? j·”–xG ÉþzÒmç Ý%[:Í~'U:ô»•–‰°âÃ4O8àf4&â(Å”(U|ßC¿SiÊ+¹4úóÈ[h2éi9¢3¿Lg~»åÀÙOG„nð‹rÔ‡î}¼™„þöë²eV”«¶ýÝ@ˆhTïkÄLÒäDIUöýú}¯&7ûŠ"½ÓuèL ¿×ûÍË&wì—†e$Êw9«º6ûÍ‘LWY=Õú% UÇEÅø«hë_ö‰­\¯” ˆ¿™a¾Ið¦/²¬÷3ézËNxì8y+}e"¿’ TŒu1ÌUÝn)zÅì‡ß¦Îô¶ú*oü;û(U*éÛ>ŠÍzÞe«ùîØ JV°B…?y`{}pf,úyQ-XM0YØÊ$Û}Ór„ÛÐé¤*„Ç=䃖'–EË'|55¯ ƒÃÙ@Ÿ“eæ,ôÕ“‡×óXä‹/óñäø¿É“¡Ç: –›§×ëU=’§²©JÊfI©k Ë'vnÉa1E=Ìå‰qc–h:1á¼wQÈ£Q¼°È„Ø"Jx óŽa­²ÅE½ÔA%K5­sôiÙ¢8Ø%‡Ó÷" Li!kÓQTÍ_.:_9r'Uôk@yÔ]-eñxìÆJö­õb¥=w¤’}kÑ„Eú€ñàòEPbóž_„ د¡ÁWM°RGÝÞ(Ãà{J J:f­S,<ËJ9 o<-ÃÑdà ³âjˆû½ÐAbõ˜uãž6_ñÏk#\®'i ÁkÜß9'µaˆ”«Z™ú0$«]Áð›] ­¶Ý–§jl˜AQ¦C•衸²(ßò`œócýjò¬nÝßußÓH¹å€Šïž" ½Ï_h)œQݺ^³Ý³ J˜ÕmŒä/3|BÉ)s…êÝ•Y¨›ˆãÖ|‡p/%ŸÁBwŠË ì) ¤•/4û™3ìŽïB%kiÒÍ#$ch‚X(D¨–Ö µ3Ã8fB(ý¾š#Ö£Ö/JÈçE1í%ÓïÃÐËH(à×6Þh¶Ý.èãwy¿ ÒäÀžÑc«Ó\ +•ÚD´ñhÙqhT Z=áݾ$Å&`éH;耡1xcã¶9çôª„[ÞíüÐúV­Úí¶ñØF·PÁà!óð(.¤GQ&•’*Y7æôàÜ^ëB\VPô8ØD›¯VK ÈW#%<Ô£p=7t­vŠ}Š> ÅLc³aŠ™¸.t½šòlö­¢çÕˆ`óÚ!sâ×mÈ¡…hL(¥$"IÈâRyFHäèDçaÈãÀ óƒ®(â‚`F%wI‰ƒ¤BÞ7!¢žF·‡yKýÖÈ8jrkϱì“AB\'лÂ"3±zGo‘Câøi¬Ü}õí^ôý ¤šy-ì9ÁAÛ?H5Ó•òªƒkúµî$#2¹HO^1'J¬`¾3çÈ4;À{ðÈ«˜ýU?ÄiG9£%XßÉÍëRz‘v]¤Í2„ì³8 øX¹ q¼pFø-ÙëµÉÙëà²5M´W>Op'AÃ!*Y¡OSåÁˆèíâîºÕªÐ?7õ„a}‚þ†±ûæôpD{__|ÏéXøy­'%0t ß p«ŠzR¡8~õGø÷-=9Ñd­?ü6DÄl³.ZóšA7¤§óz âc¯Ê@Pì\=çað¬…V§›8‹×ÁèYñ¢©ª-Åâ(vÈ™)NÎí*Òïç0¶rÀñ’öÒ®¨²ÁUe33¨¢ò¥ ÝcÑ ËËäÈ›s9 ¢ô¥ dQ7‘ªôe F‡{1°‹ªÕ•ìyM‡n¶ú§F°%Ø\ñ½·%9ÿ¸oÀÁ¿ZcL,˜_l[[hp¡J2éB| ‡>¦—ŸT)7 dgâ˜Ìl D%ÿ‡´@¾¢ÔHv¢¹¦Òñ‡ø6[~±Ö;8p›.hãã¹æ1D…ƒÌ+éÏKPI[¦$b£KoE•ðT'êkxQ½|d&_¤ª0j€CNš‡<\~$Ïgfd±(¯OK Eä×Óç ¯NŽcê4a›Ÿ-lŠö"Óý²WÒ“Ÿ—#ãG ýÀñ+þ›?‡ûô2àéùËr…÷‰Oô‚¨(%â®e“å—jlžš:§‡å†šâÜ7€‰8Jq%.μH§ð§K ÿFò(%’iº|ä!À €R=g®ô8°ÂäÉ„l½“'ÐTWaI™.xowB¦g´?Ls«B3ï,ésxòU²+Çøz¬ëˆÃVµ]Éq¨ä.Òoµ`´ÝÄñ¼Žþù*ëvwX-f¹øY–íì÷ZÁv,‹%šîà>ÍÊÝõüÌ›ÇVàe–›ØŽeÞ=ÀÍ­]täÆÎ|ø5hÓTRÒVJиâ¶Û:ú†©\çi× $ªWýP1}$è Χð„»•æÊžFP¥q X@DÒ‚Ê–“Òc $Aäó1“çuQÀägÕŸ|²¡”ú‰)QÕ€…ìšRÉTš®ôË’êÇ>£Ã ×½.ÁÏ&ž+R¸sî}ß'u[ bªë 1Ñê·ú$T¿ˆíA°E_Ë/}Òåz™IO .fÞ½7°üýcQó/FÙOýz«ozn2áá»×¤þ(ä\Î)(2¹T¦RÃU¼œ"uègún@9¨TzŒgG<4¨ÝvÚ)YeßZë˜y%ý¥?–|ÇL£0‰†U­†ªŸOÂùÐeÙ‚û‡ÁäK¢…ʼÍÁðúžL ¸ùàòØRG©sIá7ƒÉªŦ‡ì ‚rËéQ¤#MÖ^—³ì—_hs²¶«ÔW¦ø7Ñ3±'_vð”~­<[X2e‘µ?+‡¥ªÖö#m4³wcáÙG„—ÿçú \›r,Ã~šŠù¿0§¯ÛÄ[ÙYÁ6õ2ñ–ý÷)¦ó©©szØdè‰\ñÀÁè9µ^G]¸h£6Ї£3ËKF!y®–¾Dˈ!YÉHQ’Žï»ö…Çóoý96^3 1g¡å’ÅGÑz¼_Š¢Ã¹ 9Æb߸k%9,L²#6£À‚ŠƒÔf±Ð=m09®b>p·šLñ£ÜÅl¯Ò•ì[u)Ôȉe`jz«úcãmuóÍÚc]‚x Ä%]`J ÄÒX÷'‘ƒåq ã~ñà 47¹»2MKÓ€ÉÑ»Ï6ÚDåë‘N= ¤K½R8EAGÕÅYÞK#0›Æ0 ²BT‘/¾Oµ ›'p_Úµö]°•cglD¡Hà©1£ãÁ¼ÉNU¼(}ˆM-ÒZ3p»Äm;6KO®–#óɲ…Ú'þ¿Ðb¥b%!lWªµû•ù»wVö{n;t½ñšJº\®¤$i d–ëòä $ްéI ð8XôÃN$Îi!É[Õþ*G)z©â–mÓè\,$éc-õÒ¨i“‘>Ëàè~òR(óÒÿÔÛ$ ¶Õ ‹Ž{'&zÇf©¨—×âÍÆ²¤íOú}#OŽôÜuç=Y÷|‘'IZô'Ì&+Mk>ËsdÿO¸_ IØ.c2í_š`Óìì¦#ù”¨¬œ‘ÆKçt·Îü.În‰g7g¡«Ùeá?ŒŽ“dzoíöG Ä.nô!8J ›[¿ï0zV,¶;Q«ùݯžæÙ¿ Š©áãIÁþ•ÈQî¼³÷¿(yâÀý§ÁÐL$lÜ÷Èñ ž½ sÇ Z)*q±0¶SÛ/¸þÑÛA•P½ÐÁŸÛ”}ôE‹W›jKùqP¼Õا“ˆ¿ 3\Öïð_ŸgËÀö7Ù·ñ8²kõP̱R’drrç×ò Aö8T検Ƙíl­¾³»»¶úX'r’:‡‡%€øÃÏÍ-°ÂÐétÃ]ûÛ‚èÚCtþðB/w”kìú©)^~×cÒæ¯M‰ò«[#¹”ùö`3ßnc¯ë[›lãI’ø0ì´9-HFÆOÊ•R}©§XšÈy@ì>ƾ˜%ˆMZš, ¡ã†Óñ ‹ ºWÁd¿ISů´ehµ:b¸Þ†(wªåuÍ·ùÕÌð¤órjÞøÿ/šËl{®Â|)gU‡ø¥‚sç/[zšÕÏ ?ÁœV1~pÃúÿÎñ²KmÑ÷“)EBì®2±¯2ÅÏæB_f uÀõm5€kBFjv)@O¸ÆKzGO~yNOz•ÕV,(RЉN±0‘2¯©Q,Ç‚+uü÷'‡sè/î;5ò‡ž74Øè&ðt|¥¢•[ÞcCyÑRužØõÚ®;ïë–Ûvl}ÈŽ÷ÖïÁf†NñÔ£‹_®Ð³Ò]4eŠn¶%“"‰Œÿ«E½•·’ùä.ß½—/nÈ*g­úÂéÇŠpæQå¢60q²øÜZxbƒKûð5þ°5'„0}_e¾2éýÎg y½N<¸#J â#AÄPðÖ ;–¯d‹·œ0žC5|-ï¢õXµ^·ë¸þnæ „wJš¸ž-ÚI‰Â· ¾ÜXdÙ[ï“lš˜aP¼K"‘“tqKÊ^&™×$!-–!MEÌ`Ó¹ê7Iødap•žþPŸAî fHœZ½Z_k¬¼®n¿Z+C¤ÓÂTÛ5'fB½²,GªήÒÛÇ+È5Ïeíjàw»ŽM¶¬ñ6›Hyl—|Ýšå+Õà–GàŸç{~VŠÝÅÓTè[g¬#'ÀS|.¹[K¨‡+SºUœLº«®ØØŸ Pí–¯k Èvbé­h¼ºdÒcu3xŽ M-Yu]Õ· €°¤ )•\T¢áA°¶ÚøUòІ¹¥ø— Pò9 úe€•6ØŒ ‡¹ xRÕù^-Á çNìĉo³ "Á‹s›T‚õI[¥ÉXWØfäs8Òî_•àço^:@s~.UsGþ;g«à0Y¿5?çëþz9ø­[–DKÅúU4–»Ð‹.añ,à-9æ{` Û‚#Äû¦¨]Ë{m„‰æìô8RZ½¾*ID?%žµ’<]ËK]™³óÍ Ù™W%÷îbÂuâ¤êy»òvÂÅu_eí8êŽâ˜±¶È1ãÊè–û¯¯[ùÊÕRÚ‰/ `õQQ"n¹è …Cì\®¼PxQH½™+®\%\ˆí1R1OÝÉšhîú궦ü{UçHé Ÿ˜0Ÿ¤ú>Ï>柆@ٜɊÏÅRÅ™UEüJÙ˜àÎ øj(vý¨¡( ²S[ôD'ïBì/·#ûiÓDJ_£\k4nt\oNÉÝdÇ|lԙ벒H$+íÀbe×B¼ý¦{ |¡êõ¤‹ü*vsKr>sú&§ü‡¢Ò›-†rÅä‹§¹S:¦VF÷ºV€®hFl†Ît¬?øÁC} ù"i7Ú;8àvËÒïyrûä7[ðÞ,–ä­é‹T¦Û±ƒÎ*Ûý*FòNû5Ko} qÞÈmV%{=8-\+ñºTîÓN° yÃF—…ÇZR 3šR].œ°êݰͿ£Làx$h¤ +ƒC1òÒ¼Óõ½ö]˜:Àåz}«†?¦ ýóeÚ­r6ˆsôfÌ¢$cu»Û,¨ýWi÷]FÀ…®¦ ÑçÈ™n ‹tøgqêkI‘Û%QÇnÑÖ“Z`?pñÄ©^H¤ûÂÜÎßw­ðð›B©ï{Npr3Ý.M(hK—I'io÷Øv#ûq=SÂE{NÓì„Öy\PÙØÚˆPO4R&’ªá£2È5Ïžx]¯ïŠøõvôá‘+dãðLiq8¯-«èdÊFGòúÂñ°šr y~&_W Esª' rp©ÝÀïBˆi½ÔFýQ6S¡ŽL‰âÑz)‚=' \çFJº¨ø:}ˆ#ö¢Ÿ™aB¢XLñ„Œ¡+òmLz^É÷®=j#>ïº_Ì”Àô1‘CŠ9]íCZÅL|>áþpÙõ¬à¤æX‰‚ βàê7re勤I­lHÄLjI4P~Û^%éà<ç8«èå÷CRC(W>2ªèÌ(,ep]@)¾I›;ÑXar”²¯rÄDœ¨qzܹ·¶µóvíF¬™÷œcÊÐC\Ê«UáÀ,½ü¥±1k˜8ÖNÖ3k’÷óZLæv;/§ø”)¥£ˆ›z#^Q‡©Ø“Ý*Œö¨nÊòì5%Qþ3Åü Þ(. æ0"|Ã]M9æ!÷MI!InÊEqInäË®EÁI®çKîŠ%óy}qä…¬]v‚úaàJ^r4в×;Zò|çꮾ4Ýg{¤ ËtºÄ]´-iã¢À¾`–¦nàfccÑHok=³9[ÐŽY™ÍiÄ.©N û½wÉw!jÒl‹°-Fb L“kÎzÅŽúÈ„X6j9ê…Jï5,óNö–†8 :×4dá|HÝó špìNžŒlH¤¤Ý)‰±—çpð¦à)YÎYèa¶›-®z˜–X-†Q›2uïÚ.‘sì üt°/H_÷ÉGä ¬Ïu]¢ Á¶åÎr1(%"o$ôsòû¢O’•>ñ å4.×þ¸l­¯ÅÎü*BQ[sþØs¼¦óÒ#ºG¨÷ˆÏÒ0àÓõÞã{‹µC+p$L%žâ_V±“R ÉîI³¹°@¸]Ý5>-–^•”팀ǮKúÀDgÆX9ÈKóœÕhËÆ‰€Ï‹)Äp-›—°¨è/uátú¢PÕÇBbß¿î zÞ=u}˜ÅSžk€"¸¥õÚaRCVŽÈn¼zÊ%L«y[zø½nE¹º[$í«Ê®ÕÊø„<n$XÂ$lË{Âpt®ÊœJ°´Ö`Nžç’’'î‰ +Œ'£ø6UZ}f_E¥b\hk;k…ÜÊŒy•øòΟªÞO²Yj'^‹!÷Od_=‘vW‰Äﯵ)¶{ívuFú‚>CT¸Ú ŠgjIÅÆ©ûOž,’C½ c¸i­Ä®â'OY|Ä:™iž!‡ïUmhÖ'Ú q;é%mdÒÞ¢66±I³hPà˜Ï¼%ch´«x×;Næ0‰8^zuõ¶|ºÿOÙCöóR\ô]á'¨ö§óUc:ž*Ç}?”(†B@ªDN¡µS/Õpg@IŸ• ­¦˜ê£÷ÒLõá5Ù82×. }´¸¾ùv©ñŠz™™Êñ:Þ D .¡‘HY*Ec…¡Õ<,‡.ÍÃZ)ll£'šê’j3NyöKX‡¹$ü C|ù° iqUž‘õ…­Lo4ø3¢ŸÑáëÞÓâRþ\BU9ÚCɽ»Ñµ|°ÙSì° ÞY†vöî€H…¢Oô…÷Àµñ¼DÝ B/W׳$ˆ CqÓ³3øå»ÒÉgLœÿxRì+X~ñÒÕc¤¼íöá¶µ½dŽùü"±ñÑvYèP6Ïþ*C‚®b˜P%Cˆén×+à¡«ÍãNæ4äÁãºø¡…¸ø qÕý6+:šÍ¿~4é`oz—‚¼!âŸ+ûÖwý‹ãkø&Æ…Å?û`°kR^¢_â%ZÊ.‘²b½ô²c5#ߦÊÕƒ"éT³õQtÊ޽ë  sЦ)Wù¢½ Í’•óÚ|Qp•nêÔWëk§Ýub>SDòËò„t®Òþ„%ƒ 6òG³–™DÊ›å"Ïcþ‹wî>Üß_X¸ûðɽû¶}·ùÀy¼`Í7/ØóÍGÜwœ‡÷îÞ{²°ðè¾ópþñc˾7ï<|ììß_¸¿?ß ›h4j87<ýuh[¿Ri-P¦Xõ;„*ß«mú¿f>rðhæHùmÅ51•IY4°^Ÿjeæß~dÈ–tv ‡ó……üsCdd.€TEE=8èáÄc£éáØ…ª’,¸œ÷aÌÅŽÃ>QqæÆá˦UFÍ…e‹ÝSŠfàvAÊv{–Ks¬»­ÉõÒ²çE•> iˆfò§yþF‡·,Ï=À/í^®WR.EÙt–~¥‰D”í’š-ž6œ!ûþ¸µùܨ¼²­0¡xYάc7ËìmUm›¶Ú¯õ×K“)b_•¡iÆ þ±WßÚen'MxèÔ‰[mŒã§kl­Õ««ÕzµZ¦<.â>;qI†h/Xª~pX͈o^Ÿ ¦æ%.ÕðеƒRpúT`OiTÕêeJèÏ·®íø|v+_ÉÊÁ— dE€Ë(yêe¾ERºØ‰91õŠ'|SpmuÉK˜móNªÛ† t'%Z“Lp½ˆ€»»Œvˆ›ÜŒ-nqa×\ÑY$GQ¡~/?ŸŒ¨5»…dòwƒ#¢Ü—b¹ã±á¾ÎƒÄ®ç z,ûïÙ·'~Ýц@¸îŸÃ“˜È×ÂY|ýÒ#íb2” ÷!þ{Ï‹/ô)ñ|ÂÝ­ìá/ÑïT›°#Œo¯jÓáT;ƒä¹IÂËi8%ýE›£@²Øôñ0²á…u»×Ù—ÙEäQ´ /4‘Ûò @·4Q7! ‰Õ¾òŠ—å3¯ûo\¯Ð[:õûÄËæ>ïÏ®÷Úmü÷Y9†~UhdßöÁó$õ]Të1L%‹Åiørj×rƒ½AKý°7ËQnúM«-S­yap²UŽìUÛßOa'ƒÅ*‰Gò~¹µL‘ˆ,÷ ÉñsTÛøC¬(W).sÛdžÅç†tÖm!Æ®Mñm±UYŠäˆ€šÐh ¶­zôˆ…VÔ¦‹ÔÒ‰ã-¸µø-ÐãœÓšk‹Yöëœ(Èê¸M8B ÚÝ$rzò3s")Ôó·æh ÐÇ3?§f§·¬ðp£<o÷&ŠÙF§Õ'±f&ÿ>ÈóÁöý’I ¨„fŽNVIU ¬š< @‘ÏM}Ô íg™Ó<²Ú.h´lûÇO4Ä£SV Y4DJ*!O ¡Š:Èm pŠ{’"aE×4[8òOb ­¸†“V$±IÖz$[>Ѐ$W}4Pi :ÜÚŠÛ,Uã4'·¶Û•½³cðëù„œ(…EGê¡ß¾Õ|× üžg¯øm꯽ ™Âªíî¡ež…)žŠÞÊœ†¤ÔSÜÒkäÜ1­jDrWCÉ=Æ @Q§‡Líãô 5ó3ß2u¼,µ:}¤8ý·qQéÑBì>=PHK| …ô‰a +Œ2zæ¡<çXAÝÔB‘cW©qp¨4Ï”bé¤ß{`Â#xÜ3A‘ò.çFŒÛ¤癦@2©jJ‘Ø5]3eHutùªoêú2GM=ùZwÛ\åŽ0*y7_—%Ýwpw©ž#ÜÛ,KäzÝ^H¶N¶‡Ù³[–¬ˆm!œ×ëeùð¨-=céÊ:h÷СT¨ûy'ú$RŠ1ɩƼ.(2gÐ([bq«ãr/׊eIp]5‰ :DoÙ Ž\ü:*Ò﹂²ï×E’[’KóJB8²î>Cº±Û&túŠãƒ4aÙÿ¼¶¤ðÔp3‚d ùïÀ‰ü/\Ëì ÷ ùµàz/§P{aáï­ßk:Á—¹ÂÔ|ás8lŽªÄ^hì K}±QK²|õ@>/&µ–¬:ðñ´ç:dðŠfn8•8 x¢ùH0gSâ£{ZHh`¼?IÔ.)¡Óf3(vè·Zm‡D±hVõDÆ‹>o„"9Þׂ0³;‹]+°Úm§ÅkL¤¬•¢‰f¶©çIŒ5EýÝ%©¹ÇΩç³Wˆ Ë…s+‰R½T™~è³Þº¶ ¥”›óxIDhV ;}rÅ\†ØŠú‘¯Nåê± R¸×Ã#ÝÿØ“V5àQdP$Oþt¹TušN²ÁU’I/Ê5¹_‚çåð!3CÉ×Ï‚)æÃ…U§éËÞ£›~÷¦ÕÕ °NÆl…®GX)W÷ €6ù{×ß§Wt¢ÆOÍè±||`¾U•yçjLÕœ6;ŠÂ¤ÝÏÁå «»0J`ªý¶#…Vû:³¾Y­½nܻ۸§†Q¥6w^½ÚØ~"Ÿgˆ°¿¯M¬¢£ŸdÒ³rD0×÷‘³VóS¶\ŽEvÚ±XŽÐOËA{±Õ·8ßÊðí@Hf†;ýÑ&â lõLJN¼fÝœ»ý–nYx´Hñ˜«^¼íA°EEì³Ýÿ¡Ó"Z±¢Œý“ *LË2¸4KØd^Äæxç`%æ¨g1Ëÿº°d%ÆZi‰{Ï¡ ¯dÕoö:ìÐ;R H½ó¦4eæ‰ýšgo”fU;@¸¤Á0áz?í4âêLó†ÛŸ¤òD¤"ý^ÔÑ;R浡bÿØ¡Ó fê~ÝÂ:9t m.óη¥)•0†:"s¨„1Ò‰í˜M„¿9ò7ßñ-•ǾŒ»ÝIEüJQ²&®°yK/æ dmk]6e1…(@Ò!²Ú÷ãÙ¸±¤øâÎQÄw~Q›,áuò¹)”žðoûQ!îy7j³Îvö­i±—O6lQ¦E„–m3áãwUˆú ê“P þn0X½þ뿞õœãYZØëjA”’ŒYÁ,ƒaÉú ×öölT ¥ìBüNHý3±‹œœÝƒ‘ë„áwWÅ)lÕ¶¯þ~ö \^»­H|ó ÍN–k̳ϞÍÞS¥•š‹U]’‡×xìñþF¾ú›‚—ÉöP˾Oõ=dUìR¬g¯ ­³‚çüãÙ«Q;Ûw7ëù!ÿ pÆÎ,ê:Mˆgk‹]¿ªÜŠšDâÎÕWsªQm¶»¯š[Øz¨êv¢âiC”Ê´É¿ÿûç5û͘ÆÓ4.ÑH¦H«Tf_9á¬58N>@gCÿö¬ÌúøuÇ.ràýSÿg·I][4)ù£Ù®.FÀÐ|AvV~Ög*OÎ-è°þêo²úK^'4 “J£Þ㟈Ùt=³†GõœB{êb‰ÄC¨ï/´fmg¿×ÂsÕÖíY<\¹¶ƒ_Ë50Ìs®‰þbÖ÷gÝpöØUš0¦8ðƒc+°É+êà±ÞjÁ«œ]‡Iz!òcBÁ'jøÅ§tJÖE£Œå•Ó}ñ·©~$™#cL rmPW%סx·g¯’2\½=û;–÷ïÕûŒFÒWXÍqfq @}‰wëîjG>1g-4»ï8þNZpœàIUz¥BÛqEtt\SüÁfq÷׸Šÿ͘VÄ^LÔþ~щî+gCúñªôLû'ä‰Èsø³WoE|·®’'³Ú`ar¹«’ÓFNV”oGy—Ò„Jy¦˜ûFs'qKSßði5³xHö”©£c_Uk^;òa©cI4’䂳F–üéiiÔfâ4’ÒíàQ剿¨’TŠ]ÒD¦)ÆNÂöþ²Ø¥n!’IO `eèZm÷O’ÍÜ5¸³öž¬hÚ$HÕE7— ¹¢~oÞa³‚qb¼—ÍÙ¸¿§«ÝWS ”¤xf\³ð¥qôk̓Ù\ª’–¸V†è-y¥<¡PÔø¡Ož´ó²ÿÝ€xûäê(Þç1×Ïå¹^Ê:xa§zmwÂÑ&xEoƒÍõ¯• ~€}T,¨'ü€ã™û'˜ý0;äØuŠ&‰,Éó"ÛääÚ7Å®¿5„Gûû4®¦¤Ü´QšŠÄÕ”˜^•fêZ^j‰ ôãÁ…,b¾’”üÝ1bú8ó”ëe™ÉŸ‚T£Vß[«nml¿j,ïìÔñUu·ñÝÚOkfìqSÌgÒ¹DŸ6ú#Ž\ £Ó@lX É$#%¤H9/™ô´õ»YL}nÖËóõ ÷LºæÙ¥Ë90=£LÒ„žÑˆÝé/ƒD@¿í~ùV˜B*¥û¶?:X=óò}ß«HKGßôǘ¡`3Ÿ¥`#ͼc sÅyÁy¯X<æMýE1B2a`YQ{_pŒ§ì'¢L¸Äáöj®BjŠ/ÂJJÚýTkFæM² ”SæŠ1²–ã|±x\³çZ1„LxŒ¾iÐOI{V’ŠvçeÑ´?ß+‰Î™P}ß7e|bµÓ7£:ÁzSš/otøa0¬‰áa”ªŒ@ÓÛî3 °ŸŠÞ–½Õ7ÝVô¦ìïúfÛåoÉløNᲺÝö }ÖºÏ9ÔAJž8âü~œø¹#Æ o båª^^/ö¢z‚ÙŽN"#LФe"Œ2­h…ðalÉØ2‡ ”xV1È‘â«e À9Ì=´guëþ®ûÞ!±ÂMij½Áqæhˆ½i7àzÍvÏv6<š®óâœËWÒ‹…4˜Nt˜N€©¨ù ×=z‚Š{”Œ¦)<öhJ¢Lp!ÙuðÄÆ Ì1OÊêóþdÀû“jÜ++¼[Ék|ËL>'˜].ešÑGßsæ˜Û«r˜ï›¹Ð'û…:b­6àÏ­'¨Ñj÷ý0ô;:­–Ijô‡]ËMÚMV•&âý!¯ÓŠ5Öi¿TzW³‘¼Nû¥òË¢ÒÍí7ô©7ÔÂAHÝ~RT+ÞúÓI5Ä9ì÷‘!ò‘ŽÕrz‰ûhW!LÊÂÔà:%‘€—öœ6^3õQÎ`\x¡ê5ñG`R¯ºÓ© »¸Ë¾EEú¡A=2)ƒ„û.7>…ä#&%DKünÕŒ+%öDz!CJèjY ùc­,ƒøã¹˾ä”X}ŸZpÜ=¨fÂZ8²Û2¹Få£Mª”¤"HlW­0 5 ,Ôæ4ê탷@²©‚ ú|'´‡îëƒÄÜãbŒˆ]†W-V›»èx\tÂGTÒßZHIï±’sï»>hã¾³>ZßXÛ\mlV÷^­5j?¯56×¶_Õ_ïô‘Gš[­­>ø’žµ¦ûÔIþ®ãÛÌ>ØU?[ýÔmÜÕÖN_Ï,ð¶V«uR›»àCïð§ç8pÿ„ìåи†$F瀟šî¹ßHZ…ÕÀã"wÁ'ýΗLxÚû9_>Õ¯^JÔ#Er@»ƒ¡ö=î8{gP„;Ä“ÐOƒá;$Zƒ@qnxóQ¤ÏüÀCí Ç$ ÑÉ,'¾IãRê"8‘r³BÒU˜ù¢¸õŽAƒNèdÁäÓi”oM+‰¦¨óŠ\€âú󞆅êê5 ¡lšˆ#÷ öŸnŠFûJº´-Ú¬JЬ ê#1¬R3mÊ;½¶ƒNfkNàZmöèì:™t_ÕŒ’_×ÁÀ<~U/ö‚¬F¤øÛ&“ÛQÒÚÈ&¡oÂw"—EH:²X|<üõò£îbø<½ùkfÄFL÷×ÌCAŸ”ÎiÉI] ì#¬ô;SçC|Å•xÂ7ÅhÄ×ôÄæ'ÙSKB%–•9¸~“'Eb¹Q$F_qÚg-Kúm[x„Íôœc!øEž é!æM¹ÛG‹ë›oëV‹Ä¬H¿Àˆ¾z×+TœñÁ5[scU݉Ӈ!y¯¦æÂbÒj¾s·V»Ûê1‡ãÜŸÀ­£&Eó..²¦I‚%MyX¿íˆ@ÉáAò$³˜‡+šcìO¬Ö¶ØÀ/~ÝÉ“JLgNwñš~4ò&û]ZýEÑ`¸øð—r³Io·af<·=Ø<Bwàz.:„›÷Œéî!èŠñ—| Ûˆ÷!xaL#/­*V÷¶äIÈù­½Çe3œÓ¶À㔾 ÚçA3†9@®,tn½ï´+©ºyQƒ®Ä®¿.’'#Î")±s=.Çx¬ãL‹é*W«ÀLÿHCt<ÏØ´Ž\Ú&“nAp¿AwÀžIJ›Ì²·\²>Ö±ÞIÜ}ÎÅ·ÖïëCĦø#]LÐ#O¸Ük}؇úyɰÅr°UÜä®*КÜ\‰~>Õ1&‰Ô˜ÕËM3p¾vþ·"[óìצTòi tù¼gZ/c®”´w{VІÇzY -ÅZ-Eàõ:rH«R–[ÄÁLT®:lê´âvϨþ›pBN7Ð HÊRB {ºí>ÚE Ýwe_p ×p‹Íê÷ú%%¦²y&ZåÈÊëÍÕFuuµ^Š/v–³"[}â)É'¥N«þb¼üE¡U§ Ñg¼æ Ó‡Þ鋞Eªao|´.¥›‡þ0ÈœH ¡UÒï¤Pf èò–m%=y^jõBŸ¦@·µ a­\‹û‘ϼªí¶ìØýáâáv²pˆ\Õýç:ÂÒŒÖòª¢F¶ýã—fð}nm¿évèvUHÖzË%`jJtFo>4A’@d‡þ‘ ¬Xý# éš¼0²@x®%ÎŒðàDhµ¶A£­ø=ü®˜áñ¢‡¬˜’gFuÝv¬@.·‰ú!n0aÛ!m˜õ:xyGf²üü.â̾L?öWŽì[ZËŽHÍH½|fŽ)`½6CK&Žþ1Ù ášcqߤ|ÅQš(¾tIlC)²ÏÀ\Í”!ðXª•¢éˆÍ UÏ<.§(û*SL Nöe¦P˜ìëL9€\N©ˆ‡oæìãóL±¬³ÄÄ7ÀVÃÑC<áI’}âtuõí^ä1€½ÑDÒu ¡¿¥!è2Çã:s!z"›ºTÉHÿ¶J*|lªQ(û£Âñßð+ù$Šh)£@s––‡¬Ç9üŽXr†×ÊzD¡/Ê3Ôßëf4|D8èƒÊõ–ðØq<9*ø` ñÃN,sýj1UgŒº†Jö­×åI© ¬÷uüæí»aÀ†íò,Vü4CÙÂ1/”\õץϚ’÷76Ê“½'¾ÃS]»Ñ%µf*Y7–û!¥>ú¢ Ž~ê‡B ¹D5uè-]ÖO´å´ß &g7(üÍ ¸qßÒëÊÁ|¿+þ`ê>iüvŒt¿ÂåpÚŸA›î[á—R',¼5 ©væ™wê}Ѧ„Mª‰–¯)Osï±6‰t„â•ñYö· Á:ÌÈ–Jù‘à3c¬ç“nÍý“³Zà¼Kðq_i‰US›­"÷à ªæc𠀡C& 1f;ïG<.“£Õ³¸*çLR&RÁ%‡˜+F@élŸî²[cc¹ZŠO"(pܫްtšL2:SÄKј?ž²TІޣå°tæ×S1w¡/K‘J ÿåRÊËRѾBµ\ÅH{åäÈïßöÍ bÇo•«Å…øŽX=<-W94"éßÐWY§iµ›½¶ž['fµç¼§çÏ„mwÐE¨õE8€ŽYœ‰¹G-hl•0šÂFµö¶([¯¥œ‰ªŒàë[µ×> +ìïé{Oî?ø,UÌ$àι‹²îvý KîbìÙPƒ©„…('˜I*O 4D5ÌÇ$¥½ Eo*Š‚JjcüÈj»K“Ž›~‹{! Äo<Ô#¡zí>£Fsü˜…§×° þsŽ2Éöã8SgK.&:Q¼æ™ñäò‚^Á¤’‚.)—Õ E"æ ‹±ÜÉqÏ8„þÞé‘£€à ùwª)DÈõ¸EŸÌlF£íó/Ò§›lÆA(ÇåÓÙ©Øéé$m $þ~ïCøöúnmÔün×±ñÏiÑk1ÊéxôÀqVBr1ÚÓ¾‘·“›hÈEjÀÓ5¬#¼dh9«"/¼ü\2}¬•ç|ât“Y:-‘‹j©R'8Û S)°\Š×Ùe–ÿ–õžÚ;n¾g¹hÓ=r>od òœyû†æ—äè «VšL<§$¹ˆ^DAË/ó$Q¼ÖëBïáØ³øÝN¯#ÖùÞ3“<ÏL¸ä‚ÜÍ-r à¢Ü“vŽ{W©Wº«’îŰ·ðÏ#…ÓwÎÉPãRFüÞÕ‚Ý©eÿýȾÿ~“Dá9Ó5¢3ð¤ëŒ6DòuÝU͸ã‚;s²²PVGãìá' O6ñ“´§;–‡/Ù©,žÄޏܕôôêÛ½WœNÃòï ±›çDÎ0¢Ÿ‘sÞõ°1°„¬[­‰ƒöþì´g@'£jÿ¡‡Âïiö£k½F¾®i>À ° 9¸Oܲ\úQŽ‘Î‰~­ä7?à»ä{{Î{"gFäË»ðYèw"Ðä$‹ñ/RžIàå7®*ÃN&ñM§|˜à~k’vÆüòSÌ9‰~¿)çÓì%Ëœ·r,Å F€Sø5|/½ÓOc× W v•ϱ^˜V4ù¼g¨.}-ô»Ì©ÁhC´‚™†×ëÈlh¢Á­¢F´c¦1G.S^Ц™“º!¯.'ò¡ïH‡¿îÉÑœ:ƒ x♑¼/ɯ-Ä”¶Æp|E7ñ.‘ž”/f…ËJ2/Þ9%•|3øq¾A¦’xˆ=rÞt©θ+½ÜÉF‘Ó9éù†üíÑR]PÒÖ]²âØã 6ÃÚ¡/ÿ¢¸ Ã/ú±C©§ÐgàV¨Vû[ègÉA>þÿjñ¬ˆ”üˆpŽWríá úüQ£çu{ûx¦{¸']'Ì…ÇE€¶]OÕ„Kœ§Já‰BðŽŽ±ð÷ëø,$šà0 ˜‰ Ñ©Þ9Òý)B·s,Tøs^"—}úSbŠB  ð{óœ€ Ï Þ>8ÚÇí„|:èóx8ëH» y–­8Gä6(¹Gåù³Ì¢`DX#Œ„\¹búwzû\Òð`ZIZóìц@7ØÍI¢®!r»££Ü!¤G#?®WâÝ¢Ž‘ÏgÆv-o&á)yJNÁ%Ž;>ž”ðýIÕñ¸¸Ä÷†Döt'žãmTœÙôél$ðHW‚¯‹™yÌòäÓx:¡œ½L{α’0D_ûPƒìlÏ4âÜ£ÇßÏLà+¼^l^G;‰3ĩ͙.\ŒFÕ(W²Z#Xž(B§C=¢³8ŒÆýÒpƒ]5Èõý‚2VmŸûÐÙëyuèa¯°á‚%ã±÷ç$À#ºÀ*E ¢g¡K–m×’éãñ‘§oàGá÷6ìIÒñóktN|ÆBú“Fv.6Ò ñqšå.i#m«þÌ>©Ï†Hj”ñ•ž³ë»ùæ?—f¾´ß[”olì9=Õt[£A á!º úIü{\îàµ%\Œì“ßøÍŒÓ_tî:J/ 3†˲tk\\cЗ>Ás±Dü!~$“K¢“éXúb”»${>žJº1‘×X#ºAìÀHúÈdçFÂá¥ú²ú@öyžÆ>/Ttk’hµ ôù”x S¡Ú}\RºüM½vÚ]<ñŒn«¹`Žü2Bð})îFoÌöwj[ëÔÛ%†g0æ¿Uг§¾Èâˆìºáfv1–Dã©ô£¢Ýùd¨vºçrVh,ZZ¡Ï’öö–˜½õQ$â(ŸO Œ|>%Òñ4€«üÆ%zù­udÑÅ;.ø¡oÃ,Їí'Œ³/”p†Å‡ŽÂ8—3Éã u§Íúî (½è¹§é†dÀ=z¢ÛZªl“n´´ùÏh±?[Ù5"±a>y†êîyp²[ Ǥ‚éø¾À’Î*O·÷päwªäœ6_Ừ“¸Ëmhòí5Owôq«íï§ß5Â6ž©àbçœiº–§«bÂûq#‹øJ#“ùCüž‹MÀpÒP`¿ ÚÃ`få7ýöp6ŠÈ.­„§»øíœÁ•œ °Çæ.Ê'Zd,µ:¤Ý[Ì#÷ˆó/ aÉ5LVn˜ýlƒæ2ÒàÙŒ4x>gpx¦Ùá¡5xVW³6C¢Ìa\dïè¬p½Ûñ2Kël ôפpÐDWââlc.îØåh´ 9 38:N°'] Œt,¶~Ë’ƒ¶ÿO{ÿEj¼°Wã³=ÅWù.f¼^GIEçR4Š·ïæ¶| rt _öŠtà“Gav12o”§‡‚ZžßÅq¥]‰ŸIÒ—SoAE7¢,Ï5:ÚÙ\fº‰êYÒ×+L`ñHo³c2®á.¾«‚¼0Põ·°' [¦j2t©h\I޳|8`ƒù:N¿sNðXvžíyb.8Óí‚ÐЊðÜr£Ùæd;¬¤ACc}ô¯ôÄjŠÒ¸S ×“bÓ‰?Iß"÷¾Ipß±ðŠ—p™\îÂ'Ý)Í!±úöXçù´DjW3jnP—$Ã1¹ '’a/Nõ«=} Ó¾ˆoHøsbÙ-ÊöÀd±.PÓ.¢ “—`&Šõǖ飑o£+duÎõx*i¶ì šcÙ¼\z–Kñ¥¼^ñâ>ÍótyAø½æî‘ Ã?¯¦‰Â»€ãc%šÕ$žÑ±vH½ c[Õ³é IºqÁKÙÛþh‹ü{‘BäÞH~p’ã é{KJ‹Õp¢Â|úÝ3$þÊ ™r¦ɧ8}¨AnœmÐ;Qã{ÍFC &Äôªfš: ‰öt†l²™}™-bÊÇ㤵0Ìt#¶m3™µLæ,aèôYäL“é>åÛë_Æ“M°øšd×Ìì"Q¸—x’‚ ÍÀg Ä-óçx_‰§£ r2:öG0¢žÔýµ÷.?H \N,Lp«'ø£´û…ŸÃx¬¿h¬;ð*ñŠ ¿–O6ìQbŒJvÎñ…J´ÞgSvBgœöN@N]hʧIÄò WBsR¾ƒ1#_5ÊU:!W\í²óœuóGc->ÇqvÌM¾¶ ÒN`‰@T)Øn`-’žhÈâfôèküÐBô€Ðj!¸ pqæÜ{B?JE‡á'.(ÌŠ‘0c¢!ãÈ• òÉbjÁhuÌÑ.òEŸ¸Sªp]O¹qúÙè€lùÞÞ4ß_å7.‡÷T€'N“E­LXûžLðœ„(›¡4¼øÌ"ê¸ùQ^¼rzŽý”B!—˪D½ÔH}Ì)þ…±¾/²W LâÌ1ü=ÛóÈ_¾3KoÚê^éD´UµíéèŠÎ&ðmi»j”]aI~ƒŠ‘…4lM±Ù¯Ø¬#%Àïö“” ?¬ÓÉåg©Ún|» É)+W+]õAUçóF.n*ÚÎ[Á"úm¶çGrÿã¤[sç™4?6 Ù3t«£‘.W/#"ÐQL‚¶Û†e9éÈXk„¤i<>*ƒÖ§q£Q9£%CƒS;¡ØÂ^Ž‹E ™"2¬ rÁ_ð…À9ÀÀ¡bÏÌ"‘¨µ„FQÚ‚Èøw~Þ#;huY•éM‹DÓ49Rƒ“º]zšv‘¯Õ…µiþyíàõ íÑxÕÁ¨™.‹È„РÐy9…îå I9.^iSð®ñh5MBÐ$û¸¢!»\¯nœ=JýjÎoÛÄꞢÀ± ~ƒbŽu!Þ.`ö2 'â¼q†ö²ä,•fyƆǛìöôné–Ö%¥UˆeÞ=Ý–.çp™x[Ø…#/¼œ¢àk-×ȧap!# îéPß;4+WÒ`´J·LÀ-ŒŸgC«ðQ­yÍ ‹×ÃÄ;þÉ+Š;]¦êF†¨›Z…#¢Sä下 ~cÒõù œþ‚ 't¶‹Î»¨Z]©Áî2ž Ðg¸à"胚¸ ;p[¬…•ÝÏ‹ó4&YêíPÕëáûñQ­wpà6]XVpÿWð&æst¹3 c ÅT»'Ep-}*Uúcù\w$ð™ #ì™FGÐCô¼üAA÷¶™¶›}r¶A¿ƒ¯ã³÷Ô‡Ã\'åJ¶ºÊi8*í–5út†œ5¢”„ká4­;2 L({“ år¬™%|ßoµàõl⿸ÍÃ1D Óá{¿×: ¾aNãe³wæ—¹=Òà÷ç j/EÓhü²¢ËDlV3Ño_3ªŸO~Î4â äÖuÂŒw–“ÆHÐóN8‰Räa#ZXú^VpÒ>Þ¥” ‚ÐáHy‹:–H¶›£¸#ã ©8ŸDFP‰‡xndC•€³£b~=Ódûâ ú ^€à÷×k†+‰[~ô{÷oä …>ÍW*múYùPÃ?ÆÐsD¦S ö˜N2¯psöäƒ<30†O¢gN>ó=ù2¦ê0ÃNn£÷Ç ³DêÇi“DfB“ª²Ççùº §=ßs.@7µÂgJ6S\PõøYüe¡ÀCβ;W¢b#ݺˆgÉÝ…DG–*…‡@Q¶ÖëŒñ35ü{¼!ÝoHwt¯ROÎ2­ÁQ ëì”,šyTqâ0W,kD2S U蚆>˜\‡á&F|“ §]í*¤ˆLÅü¨s=ÙÐnFãã9$I‰Ô_Ú’Ü…Ÿòàž/Ò?Ú„.á˜t dÙË2O ú—!9ÔlÃX;eÓ ŸÝŽ žhÂÌi÷ðmŸŒ“b¹[£OF˜F£õÑÈœ°¡ ¯êèôU¨¬Ù‰î<Õ%GìüÔáÌÐÏ8}ôd8šŽë²6DqÇQy‡‰‰°‡Æ„éjMá–àè¼Ú ™v·( ¿°n'ÀÈ;ÿý°‡í€žÊM«ÛŠAg&òÁ(òôŠÙ>$L¥ãÚ#¸zÙ!-ûK˜£éÐA÷ÓÄ`,ÝÅi[¸Ñà;Á NÈá6Ç ®Ÿlü„èVÁ·&ËÎJáÕV¬®µïÂ2‚ OPwS—³9€³ÕÐn°´f¼µXLã³>ÕRJø-Tv’IލbˆjlûUâØ.Eè ù¤Ù#¹ÇƒrM²Ãv¸1Õ$EÈ®‰†ÜÕçØ(Àâà“ø#ЃFªçLvžëxE>Ú?§#s Ú|‘cpA%†qBìèT%w¢4qêl4&иþö{x4_vÃ=¢h‡ßúTÇÁ™>Uø4(3tº=0^µ]Üí 3Ÿ]èBtÞ¾Aœ@/ZòG/w‰“XáÔÏS½]P£…#ÒöûBZÜsÉø—˜•Ø®zg´!DažK9§è«‹¢ è) ù!z÷V®RÒ¢¢”tž­qåøÉñ1)Eä,¤’ëèÏr£ÿ,tè¯ Ür ±tKŒ¹üݱTt|ÀRQ†tL Iz ¾öd6â¾ìBÚ’ãrbÏz×qÙãÅÅT÷ÃÜ1Ljpr–ù¢>?ˆ^-ù5N9©Xþ¬QArÂÎiœp¢çElöÙeƒþ€F"ëñqb11NŒáT¡áz0¼á[ÔÊ]ïxoýtOt`c pš_ÏŒsì÷¹È˜Ï¾ˆµ¤Äø¼ÇDÿ%¦òí‹d ©ñ¡·F5ö>ÎÌ>Þx´o4}3`¾Ør¸T5üÄEqKga=½šÙõNÊ¡$QŽcG!|v¦/ιF"éFC—îJ¼C'Û51]y6Š-W“•,Öh,Ï1©×›àÁ4È–Ë02ÊT¹^*¹š~WC>×$jÇ$í¼˜}ml’v)á’„4ÐË)^Eèz©÷|?JNž/DJ®Ñ±þ F£<γ™~œ9 ¡:± ™u˜¯§øøÃêê‹duÆ$>Wâ…{꾈NªÚY ¿M_Uˆž{Éë‹a®Á:&ïM6™‹4-“ó.JÛ}u,‰ñøz†O³„à¤ëÕ$e»)râWgƒqÝ'*[Ù}„|{‚LƹÊð'4Ω¬3 ¦NSÑÙùb.#–÷'±ÕöK¦ÍǶÏÉ×´ó–J󔦠Ÿq=~¢RÔt#¦ˆ6ÅX±'ʃ}´É¼:¬úMr0›³K—<ï3ß RÏþq\V4¡îVúD¤·söTÂ#PvÚ¸x5 Ï1þè^>Ùñåº~ìOG×uÿg'ð 1Bo“ A“?'ý‰ËÍ‹ê.*“±Ã±„å1¹SÃІ}+DÜŽ96LÀÌpFšÈ¾é²*›»¾`/â [Ê^1Ø­ ±ÈÒDðZ¶Œ–<Ó÷™>-Kòu{ØIfnÄ.G\§Ë ‘à+cÏ û+½”"!¶ŸÁ¿tIÕÇÎcj‰¤óvÒÁÈ$Le#sàÛÅóÞH¦ko‰-3t[`ˆÚ¸½°õ㨤§îÃhÐÃàžèxúj¼ôU*\™@îÐ-;D!• Uµ®gaËcjõ÷ äM¸j:€õ <¡ÎÍšµïmpS"¡d›¼±Ùu£.{)ÁOEW04'm˲LoúêY¾žšpð̺ý(ÞÖýxàb‰;®Sò™Y¿.̦P$â ݦ×˸ PÐÈZJpªÜ1ÊŸÇ<¾n/õ× ¾rL­·s3Ï;¡3Òð`³x¯ijÍâWæ·¸~u|óä¶pŒ„ÌZjôrI„¥—¥–2¾¼)qòâQ#ú¸] å#¨L€žP+°Ðrè8!P!ƒçÒšì[¥ž)ŒÈ X ‘;D¨š~„ÍZ =TxrÚn“Ì–_Ç;6“ëò2­°¡(û;~!FlGL¦"ºÝ?;]EXŠºµ.4aÔJkÌ©.®3—-¨-°Øœhmùj ¥³šwBó[#üx „ÅC[)Ý kŸ;+N‘,Ž´-Ë$ï]Yû{³ ÆÜ™µ º+ËFM‰Š,בµ¾‡;Ë_¤+k“îl}LàÍoÖ5UØX¶åÖh¼B_'P§¬foUÊÕˆš_Uµ¶Jµ\óP_3t&ôÒ_¿‹>k¾¬©=w–7ˆÆ•F‹í&à©ö¬Ñ¼;Ë[nÍÒŽ oJMoà CóêEmÇSlGÃ¼Æ g³ ÉñÌì¾R—LýéM©‡Ï£±Øùpq¶ö RµÎLË ©ö¬Æ:U[©.]!*’Ì•ÚPÍ–©W¶U#«3§¡J™;s[ >=.³æõê3oBÅØ Ò -¢¢ÒFj»)ŠÐèÅfNø`¾>ô£3$(–Y½œíRidUŒ‚´6.ÙwgùÛ×U6Òfˆ½üY_KÔÂÞ°zcZFJ°ôhõ†ýì áÅU ¡µAåmæt½ºŽ®1§[ºË×5‚çcÕ5jêjôÝú×Öõˆ’ ½AžF0nc&ýì­éNTóíÔ‹˜Ëuʹ깴š«.Ÿ¬Sæ›2ëx³²–~kÄ_²¤"þ’%Á ©íŠ~0Ã7”aIðƒ%Q\&K=ŠËdI¡Ø‘´ž7«·åÉŠÆ©”·&7Ú L!éE]RJ=KÖ?1ÕU¬TÖúMÞr‹ Õ~ˆ5§ •>8éÜcÈ-(o·07ï(h– €%±%Äc¹ŠFSónj¨œk+{ɇpp–ªLâ"†iÉ¢ü°ÅÁ¶>Ððg­Ï æë»BV&{¬/ïcš®®ñÀO¦@é°É*Æ2<ÓkrÇ×%}÷úÓµÄÈEÑ“MçGÛ™4ŒYHpÐãˆþ »Ñ¶@ÿntË"˜ñÁh¦ŽÔAfŒ:º­«àÉŠeÁü|Y?@{À‘³.’.síTÎn¸nºÌYì*”cöwk-Ð9`š ¶z™°£·.î£NS"•„ôØ 9-Â\°Aí3%ØGRÃT(¾ÓÜÛ& íò ,Mn· ¬ánxÖù‹@Cî,ß§ôΩ'+vªG÷ éÂ_Ö£+Ëw«7«o×ά}GgÙ¶Ý5°a9/¤b°r6ðð¡ÉH§öS•ºYp"Lyƒ4Ç„VÏ£Evv K;š·¬w÷J‡hþ›À£zÎx¦éFÊ@£ÍiቃiìÏ4Ž=›>d/L–‘8÷[xðጿ9_@cSV«ÛüÀ(Ð`ÃHMy~ Y²è*ì.Ö%ªú‹dPR²DÛ×*HÍyô_õ¸u…[«Ô °U£ImYöØ–eÏÃÛ]³ å"Yë`$ªÍÔF5É•mÌ*Eˆ=mèCY[5¯¼£y ¯ãPb½XlÕ}x~cFü¤SW^Ù1#ŒD+UT Œ§ü![ù:‡Çê ÃPݲ*ˆyÙ*§7kzz¸ºyÇ_†KßnfNaUw4*f³üô rŸaÐQžÁ´ŠttHz±í½P,IZÚ-¢/42†`¥aÛË æé‹2æ•$®uÛ99ïìôüƲ8#Ó°Šãv~²=ÁÐ~okÄîé§çoý/xE½²›Þ×µB1dCéäG/~¶7†e"Õ ÖaÌP[JTÅ ÿ&&<æO“ø‡ÆÆÎœ93šC ~Œ±Éññýc9v.S[·±èòÔ•¢È·( ÚMØIípÿˆßnÂ]ÕLˆÅ»Óž}±îü¿|oVGÃõsô cK¾Ý\,Í/ :è¼ n€ßÁ¨?`WêÍê?¯¼X‘ŸŽìØÃ—±Ù @ªÙŠê–5«í)ëxv|e|ÿÒÒôôøþ+'¦òùñå}êÁéÜäòÁéüäòû¦TuÿÄøÄ•K+Ó¦Ôý“æò“êþƒêÒÔôÔÒd–~Ð,_ûÙôº³¶²?9¤…˜Ca¼œJÏI4!^ÖÐ×P5eŒÚù² ]ÿ˜6ÛIN¨A][•!Jø_ê¯x¶æ]¢Ìu‘³!—wj6ãË#aÝ0zŒçx‰ReÃJ{sgy7YkíY£Ã®¬½‡Î¬­‹Þlƒ>ó¹raÚdçã›*'¬e™„Û>ú“àJì!5±Eûì¦ GÏ*ò104šãDnG,ømAÄ®‚÷®Â‡æuÅœ¼kŸÙ »=…9Ö Uqr§ÓªÖ•µ§ 7âƒMMýuáfÄR,mæàÌòrvú۲›U6dܺœM;§#3=¨Ç¿ÑF·ðï7’zymÍœè9R9˾í®óc8slw®à În yVÕúUCh4Š—U'XïÅÔ¹JyuؼL%±^Z‚7ÁÄÅ2‚ö ŒT̓ϔÛì4ç`J‡ž•©,Ê5êåÎ ÊÜ|áeëtÈ1xÒ‡ºqôÉvh#ÇîîÊ*5riPÉ:´Dcï·Aš·ëF—±qOCSÎìR®N1ÜŒ=QåŒébç{¼ƒ-}ý*;OùC¶ò}Ì{‰[Ø_Ög]бҶÄ_^EMEõ…n°86k½ùjÉ~®hmØ?‡½áôHùM´Ñ™ØÄ §qÎR¥\€]®öiE|öÂr{¶T«„êS; ¾uzûæïHÍà Þy¶´æ*U*§»Í9»Ò¶o&p·1ÖÓÀ‡ØÂè±]ÄV« ö¸X©šž#ŵS9ôÚ0‘Ùùjî̽„¤S&6S²Î¬­Ysm·ÅDz*pì±$1ÉcØ~5Û:â–(sÎß®¬žÑüYs–?kÎ0I1ÍæéØâ›¸`ØËnÿ«ÞhçÀ…zb›¢µàMØI ,ÊBymÝŒÑѽfdò£*Œ›¹ …Î7ål¶¢ØäšamýYóÓ`íµÉFºC@ûpËjŒoÃ~11]ÏJî¸Ãà9^Ã)¨·‡ˆFmÒõ .øÀÊ2ÛGúÛð®Q,šgN9?çÁ¥FmØý”‚/À yäKÛi>.HCDcrf‡©üg—9ðó‡u•Úó,Ú=ª„l‘®¸J/{AXcua‰ý¸ÆöOG1…Ez£sÑÖ<ýKàh(”Q›^Tó.4&?x>§(~ý± ÏkT°bLT ÇóB7ÌQ€|ø,®Ò6®ÍÚøžl@°é7ÑEA°éµ:0¾]¦¢‹Ì…4Ün H‹pe˜ rAÅ`Q­RC½\pÕ„ÙN1þƒò*~þÀ¸”ö5Ž=£®Ô¼üw¦²æã?SXÆÏŽPˆØ@1÷‚sÊC‡Jý£ôgÍæR.?ËäO4K˜Ä³,ñ䥵(€m;«Ã~c2GÇñÑtþ°wS¹§‰ý`Œ€ ‹ ÒDÍ0«Ñåf5z¾nüÌáëé§0]½virû;Î#q£ÎÞvòÂ4òCI™˜#d¢ñt4’¡tœ_»±°FAmiHKZ…Êð)´¹0{5BÑ1xÀÆ Iì)Ò…ò²Š@ÌG:K•³ÔÛŒ ­º²¥<¡Ò8&²;[f‚5‹D£Ø¨ú:â,«›SñÕ9:Üv~&ïáj¿P)–ÏáTt™i,*_P6!Âhv“ A d!‹ìN>t{€—Òf©r¶•É99&k¡#kmâàyboègÝmÑkÛ|tX@{=03=5ÚYSô²¹âÂä`´ìfXl¤¢²ñ}‡_LMYVÏÐ,2ÓìdE.5Ü¢¿. ïŒL¥.¸‰Ú‡[ŽG;pjhIµFQ ý¹ÓË쑚E“‰¶Á…ÇVÛ@C­%ÖLQAl·ŠMDá@Y¬»5án<Ïaeµ¶nœÍú&ì3Y|É.Ä£Mø0àÁ78ÀôüŽê:C·^_eÞËc·õã›ú4S‚O=»¦.ט™’£*ë>„pªüTañFXÄð´[j§Ke¢ÌÎHÐS/ÝÍœ—ÐQðQ<‚‰ÌI~úC¾¶£â•këƒ&ÄaÉØo…6åMˆK¦äm¦dJ’Z¢ uÚsC"€–™¨……(7JgÆ#âdçjQMtÔò2\¡r¶öúlI¬)Ù–J‡TȔڳ\W\ë-ÕÏ‚F²%ج¾¬i†w\ÜRçrÎÙ"Q9XœÎ\¡T¨ù¹5 Ë÷Ò«€¢;öp˜wŒô,,{Ðï3šŽ³B¹[-wZ•.kF ²g.‰@`hÅX«UÚ·Ð,€’FïtÛëš`ä.LÁº@O¦'¡ÐÌRa²á?NKt䵂¹ Ï }€Ávd­SÁA˜ŨSAÀ\ÐæÒK›B ÝG}пÔ<ÀŠI“ˆÀ‚öfõŸ­Yš7uqço9 p*ë8‹‡þ¡‹Âÿ·4´k¼?\)<Øc[Ûíü/NJW¡|D­QÕ² Ã}YSeoV¯íÎòj¾¬©~w¶®+/’Ä3¡Ææl—R€ÕÔ°³“aéäoWÖ^¯#k­èËšjŠ 5uN´¦®n_CÃ;=úMKâ§qí„sD·ÚN$õ›EÑ–Oû[)ǶTîeòKºfÂQ¨{­pê ¶UÊÔçµ=º¡ØØy4+z{íÔEôÄ.K özÇk{u…QñÍNGšÔ]ÕÝ*²8ŸÚ¡úÒ&+4msqVh¼R§pÈ;¨§ªêøÐBCÒ©»qV¼“_g¨!a×U±~!ŠóÔ§×îÏu¬¢ÕÚæ’‘h–Âìtd~aþÄŸ³”˜\“=r"K›K ÓzW'SWeÇRéx2‘]H%b©Ì‰lröÄÓÙú"éÅ……d*‹Z K s‹Gã‰xb6iÍðÀhcÙH4ê>ÍÕ},)›OµŸ6°ÕyÆÌ±Hâ(ÏàS;‰'蜤ô)€´ÔUðŒ©ÐVdæX,ÚÅ‚ËãÁ|#BÀ‡x©è"LŽŸ—ìc%…<ˆ—öòÒ0Z+€øï<‘×ÇÒyšL*‡)>z4;  j ¬æ»jv ™¾¹x:KÀüÍ‹ÏEùËvØ"Ãö°¯…«"&ÊtÕE¤íf¥2ÉLdŽê´Ç¢õ&"ÇãGé»{˹ÓfqFbÇc‰Œ/2ƒéé™T|!ã3«Üæ†Ù‡Ûšþ™äüB2‡¥ÆÞ<‘Ìdg“‹‰hPßftK¹>‹\´Ç%¥ÞÄâÜ\v!kÊS^/iâÀìb‚Ž";¿˜ÎdIJ0É©T<%¤ÞïüºV;¢"–yµâÓ™ƒï=*õåŠ4ð õŠZLKt>G²±¹Ø<¼m6sb!6°^6¸+³á.p ƒìâ‰t&’˜5k~Iá$1õÈ«¥béäÜq\<õÕ„‹±¹š4Yˆ‰ÏÅq£À4ê£.ëÞ*0:ôT{\ÙÙH|eç¨*‹awÑLÇ2lݤü¥u„/æÄÏKÌÎD`*`­DçbtÌ‹©™˜ÄYõœ°Ü&W= ‘ÅtÌ:¾.ê@dšþ9è¿âsP˜Ñ‘ŸÏÁ±Döb‚­õžÏIá­­ …NK hcG<ÇA<š‹œ€#‘€÷Ä7…¥I-Îd’)…¯Ã:—Ja>Ÿ›ƒ-›Z˜ÉF2™ØüB&݇0ø¹³…Òz ’# ¸PÂ⋉Ø5 0°óÒpFÓ33½€J‹eÁê³€DÌGASûg§çñT€u7Ç,¬ìì|<†Oݵ2]Z`¾Ùó Ê«FY¶€¥»¡4ÝÒÆ‹cÜe§¸ãIöYéØÌb 7}ôk<àý2í‘ô‰Ä ËñæPãÍŒ&"©£‹ô(aur<4ÍìÆ¡¤án™‰oÕ¹^…Ïy þ‰:†É…Êv0%¸Žª5¶ƒìÕ¯ZÞJ/“×pE>oi/Çë‡Än7^e€ÇüFé ´fWÏë,]©ü¡Ð‰†x#˜ˆe`$b3üÆüúMû,À`)õú-G¬…# sñË`†-õ,Q‚è€z­-°1õØPÈp\}Ö‚œD²FÅëv8å‹ßô¢Ø¨áÕÊ•’¦ÝBï´^\ß!ôRSŒ*tµ²ób1¥÷mzEjYDŒõªXÛꉤ‰ž‚kdæ*ÖóÞ@¢¢Ÿ²Õp#@hÎlúÐó‚0¤ mÿÒç€-™,}p#ÏDðbX<‚g ܰl6‚_3½¾„—þ’Ê&$$ÊÃTgp­'ggçâ‰X/ÎÍ’,ŒlXo½%S±L*ƒ©à=)¢'»§s®Èúô rý¾¶qŽTCÄ«Ápk…ÚzM eS)½8=ó±Lf&Âî®X¦Ëz‰w—ŠJªª¦^=5ÍÌvE“WÓ &‹Î\,£ dxÃ`ÃpÌ'Sx ’¬‚À³RÌ­F1l9ý5ƒ¡ËÛ+eŒÈGù3o^ˆêqÍud€w®?z8u ¤s£´× TŸþŠP¢½dˆß:ô F²J9\œ{)J!åÌ_¤.h‡N1³kTQ·˜§^[Àj*®¦éÐï†éÕÃÔ¡ Ùl4m©ËÌs†Îd‡Õƒ«L»©®j&ònº“6KÁœ¤Žf#‰=¶¤¹øñXȖƾY,ÚÉîæX‚Už›óÃm“IÎ$ç²8êN–¤4¡úkb†&Ö¬‰1š¨vXKÆZiQÕèžùKRšPN×(‡ÇŠ ¯=£Þ½'zçñ“!›6×\l6ãÌ$H*~ôX¦õH2“IÎwóÀše1@Í®¨ÛæJIxÓ3¼q(ÀÅ“Ã{f'~4Ñy,™Š?‘àO'" Àmdâ×Äæ\X¥+ž˜™[ŒâÉÇÉ/y~ÒcñXŒÒ›È£À®ZLd†¨¿ÉqÉŠj<-ѬÜ|z>·Wsì*c“ù53pØ€àk5=Šð?Ç€Ì8–œ‹2‘£tv²‘Åhãg™Tܱ婢éibÂò89iyœž¾ŠeÙƒGâ™t—)ab?¦ðáàƒ·MöH$ûlipí¦bÉ •·GnØäxG…<•êê˜Ù]elbt¼¾?œTQÿÒ«ïlTnƒÂi5/¶1¶àýÆ£»Ua&cºµÖéµóG¸X÷lR[8¹fkp(c räð¸‹0›¼)ÊËÃ%JïܤõG›HÅæàZ9~‘MD3lBæަúžµÙ¨åü¸.ñt©«Ù&õ¹± 6ÐÅ+CÔÌFz÷fë6,X·ïHòšl]ý½V©rÛh¸Fª%ÌóQ®/¦ÆO³Y@ '¯x8àù¡tUìDˆò(ŒœÃi­5œ]‹„ÛõèZí¶v8¨Ó&ÐÕ°­È5ó –üö&Sy$ìi,cÆ«5{œ#1䔀ŒEÑTiPö„©ÄPƒœ Æl/L"§û”& ô¹É÷‰$¢WÇ£`Æ#³1`7çáòŠéÔe4•\X€ƒ`v!=›?‹Rqßbl!Ç› ¨é…ÈLl²Ñä×8ÀäX]غL¢' z|¦Qs›6Ç¡Z,­uÍÀ2rPÈËÜñNW’ëEw,ò뼘¦ò8öqÓŽk'–Öc1¤ZÜT¬ˆBÊ(8 äÓN Ò|úy‘^œ÷éçUœòÆ£úc!?Õ󻋱¾[Ê {C Òðà ²`>ÛTÎÔ0FÙM5+­ÕÎõÕ•ž]œ›ë«+Œþûõ-ÏÎ-¦Õ·<‹°&‘6= :rìPèµIÔéì°¢£x^ŽRÛힺ’É…žº‚•µ>[ëg[]múÁ’ºc¶ÕµcÌÛÇìu¬nŒ°eÕš½øî0Iñ™8,µ#WÛ{±8C]½Ã®[€ùÒUüPÛa·z€°­DRéQU}á°­¡†ú€~[KP=Á¨é~[uÃд>to|Ö¼òène†·öùZX<2Oã•m½,¬/ Ú)VuØVu1a­1Ô(ðZºÂÆFH¨É þš­XZO©W¼¢“’ú”¥nÕ(Lo_C¨§AÔin£BùP~«ÛâMûu"ºtûÄ•SûöLOOí98.ë9\åDRŠjR:Q²‡*cè¿µËÆ|T³‡«^ð¦¦,/J\£p[·S-3ãi7)*(d:3_í4ë/`±dF\5^Ý­,¿õMváNs A~ú1dr«þÅD<ÓgÊóಊ!¨l"í5…Ĉ;tÇÌEÑjÆT¦¼²5$† µ)qôÚŠÓÜc-K¹º»^m0¬:eèAÈS+†PÑ$~7; QÅ­x áÓí4ÖÏ9Ž“úa!}Í yI&va%Yhxž‘ŽQ…¾ÐYä si+’˜·«ÁïÒÉ êè^äl©XÖ„|(~#oeš R²Ê¢Ü…‰MPB’²”ÕÉž¾ øyÜÎðe­)L’(©Gç’G`‹ÂèSñXºu>ÎÅZK…|¾¨"•‰Ä&…ÕZ¹Ÿí*Ü‚PÆL3›¡uM¤³‚bÌHº‘AëhPÛ_~;¼ç©?„AE6n!‰FQOh«ßC­®m õLEM%çíå%Ã.ÛZɇí3óÉHÆÇ[ Ï8r–C× s[—?£hŽ0q@P“^þmÌŸ¹ê_®¬CÂHµš;×KÏDèijñ­P†;OS%ŠÒ³ÇÝ p©(Ø,/¬ r&ƳmsÉ£G‘£Ë–r7TªŽ øQ(Ãñ.¹‹¡"“L9F†Œp¿nø†Oí¦ß]–ÃS<ÌT~µqÛ8BMå<:«ÀEtíL˜Œv;:1”Þ•g]×yÑxŠBVÕËõJ ¡87æ¦x#Ù4ß²@™çlQÀC‡™{ƒçÞªºZ@eîÛ¹ÊjaÙH4-'¬)BQpØ7N×Ü\l‘˨­}k^02W:°˜hkÌ·5¦©Ì ¢[罦’‹ ¨ é´x÷£“­ k¥ÇRŒµf/ɯÈR½SS+0¥p/·¢³4,æWc1mR„n–g†éh€ÎOG4èÍÎ7£PÞÆ7Óv;ùnÓsC›h¡àDlOŸHÀ>»=ÕËÏØ#É$’‘<)»Ù)k†Šs#7¤¢nüzù\5OàÆ¾æ¡!Ã,}NwÓ;£5#´í7b@Àô «³Ù´ÄèÕ¹Cøq­˜5l9Q1zÍê¦Ûr†IÚØÙ½Ú©Êògr§Õ½ ©‡šÀ3i9lô©Ó”F©¬SKÉtäÈÏÛfÊ;KPCý¨ÞT‡¥) Šñh™AÒï,ÄŽvéOé$¼|:™è0RàËÆ>ýùøÂþnóC62·p,Òm+Ÿ=>iT‰Ÿ†ÿ8sU,Ãm#b¿»C #ozíù‰ÈÜb]%¦=Óë™+@éM&-¨K†z~´èÔ¿}Òé5'\Æí|9ã äBJÖ- zÜŒ:Vó”ÀEúç/YMñüžÔâÜfIÕNAAâ„ Ë$­|% Bè ½ÜÕhŠ¥“ؑ٠:$¯NðšaQnf-.ØÃL9Ò† X¨¬t¡˜ˆïÌ•Ìà‹2þ^‚Ù{?2"\Ã+Ä–¸ð ðÐCgÔMý€ûìÕ“[CÇß%r)/s5ºKÓb˜GkI ø4 ÅÞ½z’½1ÌÕë0Y^aÏ~.ѫְOs.6eäb#]¦\ gça¥ëùp³–*åv\dœôªz¼'Š—\Ç"sש\±†ñ!h¤PmiæÐÉÊšZfÚ“ZþÆ“KU4Pµ“§Ôj%»V-œ†©?©G…ÖN±„GˆvÏ¿“Zu]ÒØN:̤Á¨mÍi~aÌG½ûâÌF\÷ì¢we·toe¶Ng.í¨è±~ÒâÐ}Ø[ ?)ê%ž²Z;œ@ˆÀö‡.º4{„àóØì ¡]„&`Íd*\Òwª§k=öÃû÷µñ„â•´Å“Lû1^ûÓfÓmW®ºª9áŸö¼Ê|Y@­F½PÌ/,iŠ ½ü[ÊËÞšw!pp¡)³eñµãKÈpãéá =Æ O7ÔmºûTa¥æ\«¬ lÐbxr| fªŠ,—c¥­º^F‹SRйęKþ–'-‡‘·²á;w•rg9´G>g¥œØ rxrò`¾Þ¼½Jßšš»±.Õ±ôü­Üs*®\Wøe/÷ņŸñù#B}xÜ›¢™¸hû¸{ŠÕ`¿{ Ï›!^LZc¦ª ±& î#<Žêô䙲Àlï± .<5uÀWÐŒíM*K§mï…Qµßâ…à-é?Ý"Ž¡,ÍÙæOvõÎyÏ ŒüêÙºèÖE+/ùÃh PnÜlxjß”ÀÄðA?£&#pÕàM/íû2ŸôÃÌ3EÛÒú\»ô[ÖbÂuØâ ï{>,a8[éª,çÊ@ä+Kªì¿R«(µSM¡ŽšJ®ÆžÐŒ¨ ÅèF7˜›Q¼ÒwíV8”Ÿ†uŠ*°ÏJ¥ ðC±¯ûHÂWŽ÷èØ¤†+4Y£®…5].ÙC—ñtPu³¨–[Íæ¬åV ÅísÔÜY4!ÈäV½Ùõ2ÿéBž7—¿a]«Q}QÔåÊ¡læu UëtjÚ5ÃÕ™PZwy½D' @]2uß { †Î§XóX¼µLm§éá¸jÞ-Àe¼8³q¿Lé.*?s¡°¢gVÈû(Ò³=!M ÝðÊ´}'¸­Z¾i]p·=E“#,D>…{–—N"%ïÆ eÅø¶ŒÐ@BQ™8¥¬—o,WΔ•,ŠBi¦Ò†»à¦6¨¸kr÷†u7¬3µqŸCŠ`ácä#cPvM‰5 7#´A¾j^¡ñqT¿1õZgÀ3 Øèás&‘ž¶˜š£‹WÕñx$ô—²J;Q#ïÂ쨡Q¨8µõH<IðæõW©qàœÂì§ÛX¸b­ÝôÝJM9…ì¬ÅiTj yT¸‰4µKæåOWS"Fmß<; ÁE©PµÜîkóCKîkT’½§¹õõ²¥ý½›ÕRt}6/=±¨ÏÒ²€tQ¬FJÁ"Œû­EM¥F­Ë“ß/ØXe UÖÐ![¶bMÇUÀp`•‡_8䊸0¸5ŸŸšã«EׄãüÃ1zª°çC~ô2]Õ`©(ì`LlêÚ©I.ÙR8Ç«cVÂd‰ƒ†sU¸IŽš?°IFˆ5o[¢ 1 bp V‘ío%;Š)Î$GŽQ€½:ªš!”ÔÂŒørš²ëY”QL®AÓ‰Å|ý”*GŽ9¤ìäð0J‰Á»(—¨è*hq•ZnU>ÛZ†N,f q€˜ ²ãcI…ròl+ˆuDOµ¡zذÄPÑc6n@h26,Ñ-¾¾FÁd ôB9ËðãCɯӕœSXTP…Š”]ÓgÏ*,:—‚ÆY»÷2Ѧ¨%ö¯Í¿8 Ôsa~ÓÒ°9¨xW±˜8ë†ÁEmˆ» H]Û˜á£è3 Æ.«E Îl+'Äe» ö[ßÙUîJ¢,SfçÓ|YLq,"¬Îö5Ö£SøO´¸Iß?d¹ÕûÄX„l {ñþÎï…ƒns¼me¹ ‚9·Ôî°½f'ß?¸Vð=eä!è¥#F¤ ³p)Q1î ¼¢°¬sžÌ(‰]Ž*n)Ía©aïKâ" E·“å—‹ .鯭[aî«05y¼1Äl_fœ‹"\•¢7Ë÷=|Í>þÉù!n_€¦Ð+W€³(/Ñ%æÄ)ÃuØJµRJFÓ¡dkĵ֔º;»Örò…-'_äXm«ªpÐ.«¥&‘°FðˆÃÀÒ迨*6Í„Ç0MŽŒ‡BÙàø{ Õë9žç¸Âqȹ˜™ñ‰mm<+ƒ¤ýþùŠÊi …_е::h|;Ú¿­è÷¸¶ã:øpôŒÀfF ×T¡ÌbéˆÃ'§R:LƒOì;àP=+(ƒÉmyfjÔ†’hü‹Ï‘jÕuNÍUI V×)oI Ó^¡HèÇ`~5?û= / ·Ù“h [8¥ÚJ,Û«QÅémü§¯Tº‡?8×kË.ì_Û ©ÉçÖjTЊ·txŠCKÕv›ÆL˽0‡xÀœÿ^S8\ØŒ‚ÁÍ5ÍÀApY(Ò¢ ÷µ­Ô ŠÞû­ô˜®Þžºò†K;fãv¸awn‚á]Ï0<ÔV ïuþpé8ý,QÝÉ}†ýÕx`î<38ä,!;rÖðŽ­K¸Ú´6f¯ uç Ô@nùØÊDaÆÀlÞ MRBœŠXt§š$UÑU ]õÒ¯n“FC¼ÊrµeÎÐÔÁöÞÀ-˜¿´KgÓ*³alåÖàëeÎɲá|m·Éø–ÉÜö«Í9[{r¯‰hðkÜIº OLøë¤€[¸O»EX(w†c¸…¡~ûŒ9ÖÊdè„ Ð ¹2JŸô u^aÊ ìüí œ4¦1#Ôv3쯓*0ÚòÚ"l ^Ʋ!àzg­%› ð=̓ÌuÕE›ó¢Ð€m:®.¬m…VžQ’\ˆ&\3ïú±¼ŒqÍk„¿!*)ܾYXe\3<¯”ð*xU:9vr,Ü^«ÌUÎ º¬¦¶<7ìÜuh·óú“cðÿç´\¿£m îj¹õÚ±ç\vÝåžgïºöúËv\wùnB¹k*¼o² í죕Z;þå0f­Œ‚rBGJYMãÇcÔžéujmHÓ/V‹îS­†_ý²ëw¡­ÒMøÏµ5M½Žþ:¹/º´{´w- ñºÝþCccE <õÆžsý®ks{_pÅÉ3'¯89zrïuWÐ7Üýœ]Xú98êçìªâçs®½žÿÚ1 †¡þÈÞß¿îŠçêUAö®CמÌc±šªé4ù²å´ ?^àlI‡Ç¥F…ÃS÷y–ÔUÚÆMõ!)u™:¦Ã_BQÛð›SË­¥ÜYø3 w`o0<îE)®ÒCŠ×Ë9‘CJÀKú²N)>4ò]^ÝŽš„j¤ÄÊy¬mÂb<¤ø½šŽ8ˆO¸h˜Kã!¥ÓËÏZ&íŮؘéà M!«,f».YAb‹.ë—9¶J¸Îƒ)4Z[^£?—štß 9t0ý˜nƒµq•z®iŠs´Ìà ø`ê¥)”%…ÂDPeý _8/àË´Â2£õGFD"µ' ÐW¦'8<æšqbã £Û¼ùðö ßDï pK¥`ær&C‹É-E16ܳàÓ<콈>ÝV`¡Uüü/ o .S£Ë/a6½›h]¯á\n¢j]|¢Ö•’wã9­ÀFÃþëñ‚ûYSýú= Åtˆ’‘êjkQ-ßr“Vó’šžX,ç#ô‰r©T±ÔQ惊88µAÀhòMÀPóÆ£fèE[®645°,¢æ0/ È®êOA8vŽåN‹¸â|&»ž)OY`±`³¢Pï©‹…F"‘G½áñNZÇ4#!s5Súóa3¥ÌèQDD°U#Öƒú1ëÞ}í§1–ÝØÙ½+ÅÓÆïéÓö»´6í×Þ«jz™Òôi/û=µº¶Önüœì`¿Ÿ¿^X¾e6×7e êoÑR­9ÏéDB¼¬ÑÈÌ”J<ˆûÂ7ÂËÀ¿ÀWã¿kÓì_ú@ÿ…!³×&éßɰ«Ts7ª ع&N7¸‚àß]k,°$&hÔëóùMºþp„Šf&—?xóbSn øÔÑ:Ûúýh6ÏjÕh¤l-¹c±PÓô¤€™‰/‰PJÌ è Ó£<•ÕpC€³5½‰n=2—žýQ~Ls3~-¹†ÒzP°OJ\qf»ƒšV'(n+:A¸Ζ»ÀÕÎTц5Ï+táô‰x,•«!ÏCÛÃÊa¦ž·»±¢U&7S¿hëøpŠÉÁ½r¹¨PÛ"îcçÓs’Êϓ뵖g”M †÷O­5QjjDj6.¡:{ªS˜Xjƺ4Ñ^ÐK¸Ò ¨¼æØBÛcöšzÞ$/<µoŸK«Tk.¸ 9r[e(É,"QÇÅÔ:¸u è’ b¹æVÑtlÜ£EvÒ_‹e&Ç‹—kz3»v+Ô{B©U*ŠwVí =-òz±4TΡÞôÚñë¨ÜoçìÎó—àeç. ì$/{|çÎ ÊrÏ'ZlüìøÄNó{°ÙP´â R•ëe4hË´å\5?¹É{Sj™A) çoDË£¸­ ¬ÜkD|ꬔ£–x¤¾ û*eü¶Œ¹ò,‹8VC÷ TÄt§=î•[ÔD%0ÿï2GØ­"_ÑÎý*°¿Ž|µd†NïÖL¥YR+CXnºÛ•Ú™Â&Çÿ/Ã&ÖFe,×ÝžJ¡´)oSš‡6(Ü Š€F6HÕ6i‘ÆÉiðÚ5.  ÂKp}À÷éÍ7Ãò¿Z2x œÅ·/4ãÛŽÞ&ƒ„•&±qœYƒvo…㥔[k]¢rÍ}=Ä9¶<…'§&éÎK´ÈÍ‚ÌÃÑž¼Ô”{—Jö›äj7c¿ô'ˆþmu±“ñ}ƒ Òš4qaô+Ÿî¡×l±†°ˆÓ‘L9ŒKQÄï` pc*åŒ÷:½‘ä3gùʦp¦;ÎÛQøJ‰¶”\©‹j15<ÞÃñ;¸.•¦®6QÌbqn˜žÚ¿o­‰#hHâmß<;<59Ù¬srÁdŒ‰ûH¢â¹#ÅÊòÜ•m@ 5ÈkšˆÃaG+Ë Ç]d'Z|TCÑ2\A kLâ…t¯Pþ“ù¦˜R“µf+­ÌÈêWD#§Õ*lE ¶/¤­Ã©ü¶âæöÁÕæ°Í–…%®€Õ&c´ {¢êVA‡Q=!|`²U‰¡×«h¹r Aºª>~²âáñNÍŠ»òfÈoLq­¬——Ç7¶5¦19vŒawìÂ…]Û":Þ‚ý ÇýqSPl`8æHØíh¤Âå£jS(‚8SW0åÃ¥2š,Îñ8â¨$=%‘`ÀÖw—ÐÇ’¨Y{íÍ„'§'ÊM™•W¹Ô)o›ÇöŠ0A!þ0ãì;Ð,Z©¾7W¾°²²8--¼õÚ9zånŠ~/׺m…š$ó¢PŽâ佡Ù& ûiáÉÉ}m7ªç¨Ï]¹rÆKÝ0¨ØÅ£»Î;K…|›Z¦Îp†.…^R’°eˆ ôŴ𸱈‰GþãLVû¹jóÁ”t›9Îx-5ó f/ýqf¶Ô5vLsΠȒ÷B­þ úƒg„yáÆMP¸4tëëÙì,•k’Ê"§›±TšŽÂcU!šwÛš‘i §›(/´÷õ‚gÎ-ÎèJÈ.ŠÚ´¾Î ëË ±¯ƒ?èÅ:ðlŒk Á^·2£jT|Ò2šßŠñ’pµ,Ó«RØ›®ý5I|‹4¡¿afxòÊ+%ê-bŽÉà‹Æ]+ù5͇—Ôq4¹œÍ¯Q‡Š|uí¥çgfçÓ ]ƵëäØîóÑjÜÓ8 ‰H#ÕZ"Ö¯OLíw]?zù¹ý¬ðß)ø·Ÿ:Pó«j²Z€¹YLÅ5g9¶ µ~y¤Åi2][­F“NÐ? ïr¥È#‡x5D¬á?©Ë þtÃ=Í®o¬À’ðW›Z>•«FjDC@2硱1ŽVãÅ2lÔÍÄK|àï5ÇŒîxJœßÍ÷6@Í¢Å|«Mƒè¦²g“;ÏÄ„‡ úÇÖÊ«ü×jaÅË~ݰ¦®ªÍ‚ëé=9 ݆o:9zÃÚ*þá„KM´Pc,Ÿ°SÓšãr©/2+øûÀéᩉý¿×T:9½¥×“þGàlÊ'i33A€È´`x¼½\I¯/³' jʾBó]TQvréÑmê~Ó>\jâÒæŽæš.˜mš)7«£)\_¤ºªµ¢»~IíoX vÑA'ŒÅ¯`rxÜUÖÖ*ùæ˜cʹ깴š«.ŸÂ{-l<ýùxdn1ÖcËþ}‚áàjk’(Õl ,è쥦)ÌD ­Wò•¨9–l»Æýòèµ_?Ú®e°òŽëÚ.§‰—wk7Öâ+qk–@ätaw¾Nåà7¢Dòy}m<ÙzèÚXÊ'²^«¤Ô3pÜôðSÄH wÒ`v,–-ik‘š\¶&$^Á¤ÅÈÓÚQÍã·vë¿i-Ä¿îà5„jÚÏC¤vRóÎÊÒ nGEÄ4Íh¡gÙèf/»3¹sŽ\ëÕ¢æGÁâBµR«§ùÌO¾\±X9£æ M뢨‹RxŒ/GÓè“cOwSQ]m–ôÁ̘#í`O€}v°IP„†œŽ¾ß,Ês…tâhµ²¾F•|ˆÍ$ÒKMö«Ò‘x)Ŭ«r¨µÔÃhæ9ÂPˆ§™žSèoÜXxb²iBëÅâo£ã³¾AsÐ?Ì´ˆMСÖ¨Ù²|£+¯ªk}(0¬sÂZ’t‡õ-ô%DèMbdR󢃛¶Þ…Ç œÜ° ÂMˆ™2Ò£¡‘$\Lš%ž7ΜK|ÇrÜl‹ÉÊËŸ1Ò B>o©‰Ùf@ßHéµ!¬ÐÄ>; M0Å$cìâtHñªz‹)rÍW„¹çg j1¯uâC5g þÕbe 8 D€V5W±šS]«ðOs vŽÃíT€û*R„o«¢YžÌçTœê Út£tq—I–ƒŸn Â1‰# ™ÓïðÔÁýçšm1—”aA¥ÖÜl°“=!ÖŠ‚¬ÿ¹2ìT£òµ”%|±mÃÆàU&oØ‚‰ÄãçÒ[º4P0¤×ÐçýyJ•uMÑWy?}ÖËô®Ìi°ûò3¡Ë”ÀÃêhÈ\Ãþœ¸ÄÃÖÝÚùÄèü+|úúêràn8ØËMάb/¶&6f‡­…êh?ß_l½ÚrµR,gWsÃÙ²vª°¬¼Ä«ra¶P,ºóÕÜ,fA˜Pl Ùd0Ä’Öl7\“}°èóLó­ÔÒ&ƒS]•ã§B\AýüÁ–âxÑæœ<†A \XAáèrXø^çÇ–;]mÔøN͆—c|kë5J0oøKÚò ¦Ër³£KÚGû€=ÒÔYZ)®k§šõ…¦Ûb‹å›ãÖf (‹û :DÞ™ƒû¡€ÁF!cÆ@gA7Ý0Jª1iÍS¦1äXd½v ÍÆ™qw¦r£Zîî5¸?®.”ó•3§+ëèNíB0&b€'Äʈ §vã6?ÎË0p4_dn.yu6K¥(Ï÷Ï&S3±l*6›Š¥µÎD3±9`bò­0@ Ü´ÕÌfs9d<õD©Q‰ðÔ¾ƒkTȬë{¹‘#’³·{¹ÌÜŸ¯èåÂãí¦>Íf ‘Òycáñ­J™Õ¡[‘_7I—Þ»¢¡]-û§£LR€¦ÔÀÈ/T˜Ð˜œ÷¢™ZúDj½öòá©©ý/Þ$PÝÅ"˜ÅiüS1Q×7CÆíÇØdbt|ëƒ%˜9&?eË 0PîÕ+1ô±~“n6<ɳS"Ö•hËÍb¡‡'©o Ýf@>rÔ+Ý•*<Þcí"S©åŠÝ¬”‘/5ÕLBWFp£ï;¶Â|Øîžfþk[åïD[¥¼1Ê.ŸôÕ&Û?ÅXóÚŠš%dÎ׆ðfÁŠì±e—>uGÀïUøÿ<¿5rí Ê2¯5¥­pï2%—ÏUÑ$uïn"âoî6•¡é·‡—¼v;FÛ•+ô ×™ yž­ˆNví¶dx^¨XŸ=Uµ¶^-+¼]¿×cÉÍfu&8›mK¹UÆ™6Èǹ̚´'âEfBÏkSŒ êÅ„•a꤄©çéc!W¾ tü }Ak¹ò&G¥q<ë×?bEÂ]?¨à t¼°σzÕâäÔ~Ç‹œÐV¹išÎ†·£ •ýôuó_YŽÈfa¾xÉlvHªÜÈ)T ,º®l–zãªz…Ó4¨)™žŸÍÖ+Û oœ¯”†ò\šÃðø¬ä’6êæsí.åªÚ)ø”±³Ë*µ+Ò:íj»ékwÚù­v©åÑ#y%*Jì,Eß.Ru-âº+zv§™úÌÓ¹ñ¨ì<´“S¡ye¥Z)™ÉT>]šÀ8A:5§_äÙ[Õ|ÃŽ-Rm;³Å¡îÙ”æE9SÚÏ@ÚQvöìÄFh‡È#aÙý;™mÀèM[jqa ¢l–ž:8ñ‚­–õ"Ú3S~ÉÖ‡xú²&aGqá±Jµð\›ºõÑé­ˆÛB/7 hÒú–ªÜúL[n‰Fsã_TF¶çOë..RÃ*áÉ}^îVSK[¯0ëÁº8°o^§}zêh¤ð†ƒ4XUιZ¡¹n•fsòPCãúûÎ6_§MÍÛ­s/½G©ÙÈÅPç÷·|©X6XˆŠw —©;­ðx¦SªËœÜK“T2'63¼Š ‡ÀnT®mÙ£ªZT®mÅ”]-»á?…¬åòʵ¾¢î|Hq(m4PÊ!¥Ú’RÜhP°Z†§øV­œ[;¤¬7ßìÜdèÑ\Ø?î@jÚHÚúÒr±°&˜æušG,¨þ†ÂSãã7n…-4÷Óé3¢63}œ$&©Du)uðôPm ÎZÎ'W°tûS¦bª ½y»õ@c‚˜Ÿ`“;Vj"œ„µÓÖ“£¥µ©po­²ºZTYZ õh܃ʦX|6 ÞÀóðø©mËì/÷ŸI››èà•™^zÿ©f«…Mi34«V4•™_°C%Xbbž·ÀԾ隭×äÐÚ,3ÌÍÌÁ‘ã5lÀ=Ô8 aŒC†9Ã,æœp¶¤§†Çý–Uæ¾~vÔ¡“c±À˜O_Ć OÍ’ÙÛ‡[}ñ”œ=¥éa,ØÇ§ŽõiáƒSÍÁ-d“'>þF%¥~2FTRñžºrÿQÎÃðÖ*A­£}%2«À]— 5dV×ËÔ„Ï{dggS‘ùX6sb!–'f“ÏÅvr§—Y3<ükÃVÐi9Å6f’ÑØL6ÍFŽÏè A伡-øÅ¶ä¼Ì¼Õ¼Ï Þê ¾=‚ÿ¥VÒ*}®‡|®GúBùBôDy¢Gú¯ò_=Ò¯{ȯ{¤Wô’WôJ¯ê%¯ê•^ßK^ß+ÝÚKní•ë%õJ÷JOö’'{¥ô’ôJ?î%?î•~ÙK~Ù+ýª—üªWzMyMŸôÚ>òÚ>éÖ>rkŸt[¹­Ozi yi‹tW¹«Oz[y[ŸôŽ>÷;û¤¿í#Û'}¤|¤Oz°Oú`‹ôPy¨Oz´OúFùFŸôý>òý>é‡}ä‡}ÒArgPº+Hî JwÉÝAéayØ#½/úby_0øOAéAò‰ ô¹ ù\PúZ|-(ý (ýwüwPz]ˆ¼.$Ý"·„‚o I"’Þí’î IoIw…È]!éî¹;$½=DÞ’î‘ûCÒ‡BäC!éy $}*D>’ ‘GBÒ{y .Jß…>à~"?I¿ ‘_†¤WIäU’t³Dn–¤[$r‹$½Y"o–¤·H¡—8È[$éy‡$}@"¤OHä’ô$}F"Ÿ‘¤ÏJÒ—$ò%Iú™D~&IOKÒËû¥×õKïô’wz¥[úÉ-ýÒ÷“?î—îè'wôKwö“;û¥7õ“7õKw÷“»û¥·ö“·öKÝOþº_º¿ŸÜß/}¸Ÿ|¸_úT?ùT¿ô¹~ò¹~é+ýä+ýÒ7úÉ7ú¥ïô“ïôK÷“Çû¥§úÉSýÁWÊÒ«eéõ2y½,Ý"K·Éä6Yº]–îɲt§L¿¥»er·,½U–Þ&K÷Éä>Yz—LÞ%Kï“Éûdé2ù€,}H&’¥OÉÒƒ2yP–¾.“¯Ë!hÿ1™<&Kÿ&““¥'dò„,ýX&?–¥ŸÈÒÈä?dé•Ò«¤× × H· [¤77Ho oÞ6@Þ6 ½s€¼s@úÛéþrÿ€ôñòñ÷CÒg¤‡ÈÃÒפGÈ£Òä‰éÉéßÈ¿Hß ß~5 ýf€üf@zù ôŠAòŠA镃䕃Ò J7’›¥7 J· ’[¥;Ƀ҃äÎAéËíÒ[É[¥{ɽƒÒGÉG¥G¥Ï’ÏJ_$_”¾:(}}|}Púö ùö ôAéñAòø ôä yrPzj<5(ýç ôóAééAòô ôëAé7ƒä7ƒÒë¶‘×m“>»Mzxÿ¾¶Mzt›ô­mä[Û¤ïn#ßÝ&=µ<µMzÄ/}ÑO~¶MúÅ6éémäémÒK‡¤—I¯"¯’^3|íô‡CÒë‡È뇤›‡¤[†È-CÒmCîÛ‡ÈmCÒ›†È›†¤?">$ýåùË!é­Cä­CÒ}CÒ;†È;†¤†ÈCÒƒCäÁ!é3Cä3Cî/ I_"_’~8üÑô“!ò“!é§CÒ/‡È/‡¤ß@ïÃäåÃÒ+†É+†¥7 “7 K·“Û‡¥?–î–î&w Kw“»‡ƒï–þ~˜üý°ôÞaòÞaé†É? Kï&ï––>6,}|˜||Xṵ́ôð0yxXúÜ0ùܰô…aò…aé+ÃÒ׆¥G‡É£ÃÒ7‡É7‡¥Ç‡ÉãÃÒSÃä©aé‡Ã҇ɇ¥ÿ–~:L~:,ýϰô›aò›aéÁNé¥ y©"½V!¯U¤?R¤›r³"Ý¢[é…Ü¡HoWÈÛé y§"ý"½[!ïV¤)äcŠô …|B‘VÈÊôˆBQ¤/*Ò—ò%Eú²B¾¬HßP¤Çò˜"=©'é{Šô”BžR¤Ÿ)Ò/ò Eú¥B~©H¯!¯‘žè–î!wHo!o‘î‘î!÷Ho!o‘Þ3BÞ3"=0B‘þy„üóˆôÉòÉéÓ#äÓ#ÒgGÈgGB7JŸ‘¾8B¾8"=:Bà¿ûBaòD>%“Wϯºo»Œ|l˜<ØI¾¨_â$Üé~Ø-¡GþA‹¿S†³ÿë;Coh“áør§ü빕ü|§ À‹wÉ·öÊ/Ùå¾}ùÐ.ùÉ^ùñ^÷#»È×wÉwõÉ/m‘ábøÏ]¡]òƒ}äƒ-äwËl =ä ßÚ-ÿ°ÏýÝä'»e8šŸÞ-áüúËÉí—Ëp"¿årNäÉý—Ëðï§/Ýëo …^æ!¿º\†Óö®+äGBò§Bò{e¸`ÞEd8dßu… ‡ëýWÈp¬¾ç ùÍ’|‹$Ãáúg­2œ£_½B†ôÑ+dxùǯ¿$ÉŸ•È_!Ãñù´D¾ß*ÿ/ï'/Ý#ÿ´G¾¥_†£ô/öÈŸê—?Ü/Ãù–=2ŠÝ#ÃøÐŽÀoí Ýê‘_/Ëp”~oOÈ-Ñ÷p*í‘áß§÷È÷É2\(oÙ+ÃÉuß^¬û÷Ê0íïÝ+¿f@†kë}{e<³¼2œYŸÜ+Ãñôõ½2|”oî•á±W†“è7{e8Y^=*¿uPþr;yͨ 'Ë-£2œ,5*uÜ?*{P†‹òQùéAÙ_’Ê¿”áŒøÑ¨ ÄOFe8ñ“ŸÊøe8^5ºÕ'¿~H†íæ!òš1þýã1ù¶!ùcäž16ùGÇdØäŸ“aoÿtˆüÛ˜ ÿ>9&îþéXè]NùÃòˇåÿ“6&ÿ|L~]yó¸ »÷íã2ìØŽË°?5.ÃV|r\†½÷“qÖÛ˰Ín›a/ýÙ„ [èÞ ùa%ô£!òÞ ¶Í7òþ þýÇ ¶Í&dØ-_™a“<6!¿nD†;éGò?ÈpTý|B† ðô„ à&ä/ŽÈÊw:]ŽVG£Ïát„½—;Üou)÷¸v¿Íu¯ë>—Cñîq¸ïqý•K¹âí,ÅÝ>ê¸Çõ×.ù®½ãb‰íãŽðØ=®wºnw¼Ëõ·4É7éßÏ÷¸&þÎ%mŽÎöƒïm®¿wÝã:ðn×{XÙú$—ÃÛþlÇ?¸w@ ¿õ>×ûYý€£Ý÷»t9ú;ïq-|Èõa×X¶½.É!yþÔåøˆ+ôÐèó>Š)!Ï?¹ ­¹¶ï¸öŸqÌùO¸=ƒ÷¸–?ÉzôÚþöâƒ.GKðןæEl Ž_å!—c |«ô/Ô^—äh¯9:võßãÒ>ÇGè9 ƒy¸þy|ü‚ËñEö¶g¾ÏÞ9¾ìòFÓWÙÛ\Žßwlóý¡ãëðIàƒ½Öñ(ŸdW{ƒDÿmð™¥o@õ[ßt}Ëõ/®¥éšîªÏh££åÛ.¼ë;ão_—ä…Õ¸Çu‡ã;®?uü{×;Þ»ŽÇ]8Mov<=¶ÿÿs8¾ë¾Åñ¤ëß]ßsÑb¾†É¾ûßg_÷^ÇSúoè{‡ÃñNü_;~(æÂóg.Ç\mwÂûýãÇø^çpôÿÄ5ïwü‡ë§lý5HƒÖýïvàºüO¨û÷ŽŸ¹ôùõü’ã=Ž_¸Úïq=Óð_˜ðK||¯ã¿YÒ²ãW®w@Ý8þÇõkœÙÑáÿœCrüÆÕuëaÇ‹ÉKÈK ›mßç/#tñ=âx9á ²½Abû׎–¯9^A`2_IØòò}ÃáxÔQ~¸Çõj"R#Þu8þÔkÈÐkÉ’×Ö“‡óõäÈ=®ï:n&ô¾8n!NLúwÇ­PÆåÿ‘ã6âè’îqýÐñÇä|ˆ._ÃdÇš÷e-WËí8¢—¶ü 4àó³ïÕ-wº#^Õò§Dì’‰ž7ÃÆ½“Àì¼¶åϰâëZÜŽ7XØòfr—˜«?jq¸ÿS_ßòú8|ohqÜM°½›[þRïäO[o!·;°F[þa«¸>Íq»Ãslæ·â˜ßÜrtíÿË–·±áÝÝr/ÑôÜÓäø+¬þÖ–·C¹öûZMè¾¼·å„mM_£DØ8Þ´8þ†à ¾¿å¬ç!ï‡[ïÂtëC-KîÇ6?Òâèü;§Å-OØâö~´ÅoünâþÇ–÷<1Ú!ÅeMòÿ¹ë½lСO¶üáËÕ÷P‹ã}·Õ§[ÞO> æë+0‹ÄYürˇȇyªçâøÁ%÷Õ–Ä/ð/-ŽmQàøVËGÉûù¬6Hô}§ÅñOtúkù´ý»-ÿLt"žhù8Ÿÿú4Ï'ˆßñI‚IO¶| —é÷Z?hÁa<Õò ›¨ïµø~Þâù4yfêg-Ÿ!ŸC~?É眤¿hy+ÿªýçáÙòòE\¯q:vlÿ”{µóËXÂöìrlü¡Óñ:þ×:¿JŒ]äjƒÓÑÙÿ5({³óëì ·:½’oÇö÷¸Þèü&¶àý§CþÁý~»ó_Ýï;:Þätü+éû6Tþ3çcä;äßÈãä ò]ÚŒÿ>'œ¼OBÞ½Î'ÆÁëy§†ÿ=²}Çß8¿+ñÃN÷€ã)CûóúÀ“]Þ8?d}:pþßöNÙñc:´;B‡æýK—Ãõ·{\Ÿuþ§R, ¾Ï;ÿ$x!=âü™>Û¾o:Ýôs¢|Ãù =Õÿ˜ói¾ð¾íü/±ðüOÀœü’vü¸ó¿‰q?}ßpümú{Î_vá{Cà }q+œ¡?t¾¤ÏPߎ—¶b«?r¾¬UTnèûÔÿ'ÜMà¢ÊÎôÿ:÷Ö­·.KAW TÉÒÒ­mkC›é³ugb'™ÎžL’NfI2I&Ó“¥“É̤“é™ÌQÁEpG7TpWTDAqQqGq_q_QÿÏs/J™ß|>ù|Ÿ÷}Ï9÷ÜsÏ=÷ÜsªÊ\Oúm}¤çYGÆ<ÔGyìùê>ÚÓóFÿ‰1ݺۛçáóõHÏ÷ŒñØC·[ÿÓÆ¹Ç:uóŒ÷ðá*p{U‡“‘{‚çÙt]èŽR…öæ÷D³HŠ)ÁÈñðèÉîbÏ$StEX”&š[”ˆnŠò‰–(î`_Q†)0¦xÒÄ“!òŠxú‹ç51‰7KÔ'D í ¢}IÌ/‹úªÈߊ|OÌ¿ÏE} Q¿’¨_KÔïÅøX¢s”Dç*‰Éc•x p¶b0ÌR[¥Ä»þ%¾ Jôz%q»aÏ(ÑÎâ˜[X¹ÝQŸ«õå™_š­‰,ÔD¯ÖD-ë4ño[5ñ´ ½M“Àep“åß‘>cuéS Kl±.]–ë’¸^ÙA«.F».ñ:ÊEâ;i¿†¶¹EŸë–Ø…n1Öº%©Ù-Òéï5pþDC¤ÄàTPaà˜¿“à|Cô…†`âEüC‘:Ú$ñ>¢ý‰ÄOôÀþLâ'y$j­G’ëÀ.¦ý«Ä·xÄ{–>:ïüq")EBDä°HànÒY‘ðA™ÏŠ·Ì+Þé^ñ/ðŠg¨õЬ‚]çß)¯ôÍ5EF›kJj1(1%m!âZS^: N€S(sÉ”àUØú( ì’Pi´Äß‹Æ9 ä—’>*v¢’¨‰1’Q#ÞšX$Lfî0Qí±¢ßˆ¹+¡Û±òòbŸô«ö‰ZæCþtÜÛõ>‰ß Z™07² Á pÞ'žú8ñ숓`[œd—Øuñ’Ü/ú‘x‘[ñ^ò’„—°ê%ÑŽ¿$ '^y#ži~yyŽ_2«üòR ü¼N€Ñ¤/ ˆ§1 ª ì;òJ3ØväÕ=`/Òï+Ðô}ð÷dàp´ƒCà08Ž‚c ZÉÀã°'@8 N$¦ö48΢.”S•°çÁp\—Áò(yýJ@]×@¸n€ntö¸ à¸cd0Ž}ãè’õX}$kxÉÎ#À·%3·¼‰K~—´a-ÿPþ1xžö‘w­yw8È#@.™ _8 ä £`G'ˆ7/A¾ˆr_D™/"ÿK¿cDÀ{aìøymy¯v(ä+0_)ä@A™É ò5Üø¯á¹úZ ü)`j‚D—"o(Ko”ƒéðg‚Y`6˜æ&È·*ÀÊ<ä§@7x ž€§ÀJ”Ÿ9`È#Á(0:Q~–òÁ0ŒãA˜ ÁDPŠÁ$0”€)`*(MD;ð/K”Ÿc|ý¼v:ÒfòÁÌDù`V¢üVmÆ8 *À<ÐùæÙDùå|°T…`b¼ürìb°$Q~µTƒe`9X¤Ë¯VÀÖ€Z°¬«Á€þýÚð+´]­ëÁ†Dùp#l]¢üfÀ½øÍfØ- >Q~Û» lG™&°ìL”ß5ƒ]`7Øö"½ìm`¢üÇp´'JÒ!¤GÁ1p×xöè'Á)^;8 Î$ÊïÏ‚sà<¸.‚Kà2¸¯ËﯠÜ5Юƒ¬Ü·ÁpÜã½ÀCP+ªö1xž&ʬ$ùÃpF€|·ü!v$F'ÉóÞgÄûìùðÇ$Ipl’üÊþÊ}ŒgîceA’ŒVf£UÚ¹0Iò˜™¯SÐÔ|…¶æ«% —Rª)Ë(Ë)hy¾ÚNAÛó&Š|…'~ŒªI‚ÔRVRÐÌ1læXµ* ²š‚Ù¬Âô?V­a¸–²Ž²žr«Ï I2^Õáš6ƒ- lM’ ª²²ÒˆÆ7%I¡Â[`¢zÙ™ÁLäªfæî¢ì¦ì¡ ÝÙä‰j/ s¶kI’"+b±"+Vûè5Ók£ì§àº‹Õz¸Úbu^;åå0šyÇÀqpt€“I2IJ “ršr†r–rŽržr!IJÔEz—’dªº‚C¯.p=I¦© Þiê&½[”Û”&ƒôîRîQîSàÐrŒªG°Ýà†`tÃ>O“¤\YAÈpJe%—2’2*ˆÈcÀX0.(3f‹j<½$aäÍR…pŠ@1˜&ƒ0%(sÔTJ)åš™F¯ŒRŽ3ÀÌ ¤Ï J…šMyb@æ ¹Ì•A©Tó) (UA™¯RQ£ÄRP –åA©R+(5ˆjÁJ°Š «)k(˜„ªÞ¾UjmëpØ6e‘ª£l¢l¦l¡ÔS¶Ršb!˜Âq‘¹H50me{PsÔ/æ¨WMAY¢vPvEšƒ²Laí²Lqrß‹3µ€V°´%y?ìÁ Ä·¥F¢¦¡¥£ìó@ŽÓ;Aé œ¤œ¢43·“ÞiÊÊYÊ9Êyît?€sÑEÊ%ÊeÊÊUÊ5»bÖÔEï:åå&åVP¢n¥–O{-ŸöZ>í+ÕÝ ä®áxnð<O•,j8ȘÜVqÅ=ÁH0 Œy Œc“%voˆF‡“e¿:B9Šè88:’å ïÉAu’Þz§èu&Ë!…×è!…w¨v&YsqwX£wžrr‘r)YŽ(,GŽ(ìm(,þB—Q÷Up tëàF²åñGÕM Ž?¦nÑ»Hï6åå.»Ócê½Ù^ñÞ§³Öy@ï!á#:ݔǔ'”§+2œ’CAÉ¥ŒL‘ãjt Æ2ƦHê¸éP)rRMH‘øÂ‘"äLJ‘Ój2œ))rŽ£M/EPc7Rž"ø~»À÷Û5á Êx†3SD¯‹ÂˆM‘ËjnŠø*Rä Î+|.}•)\"×Ö.×$×T.=,Kº8:º8:ºÔÂÈ"ÊbÊæP0öº8NºÔ~@€³”%ªÑ¸åàŠ)×ÕŠH ¥6En¨•”U”Õ)ÒwMŠÜdæMfÞRëRä³¶!Eî©–>ºIÙÄh3e ¥ž²•Ò@Ù–"¡ítчM8m3Øvƒ=`/hI‘ª•²ÒFÙŸ"ÕJ;åå0ʸKê8ž"Ýê¥#E«“)¢J‘§ ;‹Ðé±4 "K»@ÁЮuSÎâÀóà¸.ËìÉÑ®¦Èí¥+EFjØrŽÔ°÷©aãèÂ4q %;`oÃÞwÁ=p?EFk()(ݬøGkéᆌ֞¤Hžö”b… Ã)9””ÜîT6L ¡‘!Éçáù¬-ŸµG‡„K 5v,àÚKà :Nk@Æ… ã)Ø'ŒÓ èM tÄ[’ñFÐxm$eËàZ Š‚TÒCÝZeK ¤8$¡I8Uy¼Lаu™ UQæSJBR¨M¡`ßR¨a¤jé…ÚT¦•R¦QÊ(å”é””™”Y”Ù8ÜiLE¤" {•?Ícæ“”ÊLÒPª( )‹(‹)K(KCR¢a_¢a:ò.C›¿-¥ZMRKYIYEYMYCYKYGYOÙ@ÙH© Iæ&ÞÚ(D›é ³…y#ú@êQ`+£†üvNÖšÀŽLÓ¬H%7AÊ4<5eÚÎÙÒ¤\Ã{¥\ÃN³\÷\»Ky@ÁîVÛ*Z@+ØÚB2SÛO9@9Hi‰~½v$$³5lçhÇBã”,þçhØóÏѪèÍb‘fœ¤œ¢Üê#ê¤s:$:CçlH*4lÆ*4ìÎJÔùÌ×6&@êøšr\×BR¥uQ°­®Ò®Ó»A9A9N¹I¹E¹M¹C¹KÁ©â©Òî1,ä§·¯ÁÁ”YÅ6U±=UlK•vŸò€ò2™EáüÁ`…e‘6<,‹µœ°„F„e ø%|à—ð¯f¿U³ßªÙoÕì75:Œu Èc²\Ã4¼\Koe|XVhؘÔj˜k5̃«´"”-þ £•6) ™–ÕÖ«µ’°hS²†ék˜¾V+¥ðS©IXP–áØr0ÌËzm&ee6e{4d2ç†%µ¶2,uÚ±hÈ|DU`!Xƒ%`)¨Ë@»3:,¿$© Ëf­–²’²Š²š‚Eófm ½µ”u”õ” ¬¦7kéMg¹:z›Ââ­Çd ª­[Aض‡¥^k¤4QvPvRš)»(»){({QQKX´6Ê~ʰlÓ†%ã‚Gµe} ˜¼µå1Ž>Ò¤a5Þ¤a5>ŒÓDzS;N™9A¯5Ÿ K³¶>Avq"ÛÅ9Lë Kð 9–½¬h¯vÑŰ´j—(8K+GD+GÄTu9,ûج6 sk›†åC›vÞ¿ø®2ý¥‹‚µi›vÝ.K¹–À­°øî !÷ÂrPÃë² içŒÚ®=CRQ*™Ñ–ðc´ÇÂÐrÀ Fö•#Ú(ÊhJ%Ÿ2†2%Æóë0òÛPŠÁ$~ÙJÀ0”‚i  Âx,çw`˜ fÙüºÌ}å˜6‚9ýŸ×c|^i•L›OÁ昶€žõcZ=.Ò8íÓ2\DYLYB)ïÙ`†Õ”e”å””J-¥•åVÒ[EYMYC9ų­¥·Ž²ž²²‘RGÙDÙLÙB©§l¥4P¶Q¶S)M”””fÊ.Êî¾â½î–ZK_Èþ¤µ¯thû(m”ý””ƒ”vÊ¡¾rR;‚.<ÖWBÇa;úJ§v’‚·e'W\tò}ÞÉ÷ùiíT_H'å4åL_ dz}Å8Gçåb_9«]¢\F•WÁ5ÐÕWÎk×)å‰ôn"ýV_‰½ÝW.iwûš75Cƒ’á¶ãÕr•SÝUíA_ÌW5lZ®j>¢`Û|UÛLéfø˜ò„Ò yJÏJÅ~xªè#R%82UnhXˆÞа½¡fxÁ„`¡sCÃÊ3”—*·4¬š2Æ¥Ê]>åwùhÜå£~—á]>êI©òÛÂTyÀ·ä¼%%¦(cLN•GÚÊTJiªtkÓ(e©òD›ž*¡©ò”oÀ§Ú¬T±ô·$ÍÆsS%G¯H•\½Ô©¤W`@д\}>Ã(V•*æBØE`1X ªÁ2°¬5 ¬«Re´¾¶d5½5vHYg 3ÖÓÛ@ÙHÁü;ZÇ.öåºTÉ×7S¶Pê)[) ¨wí”FJ¥((¡©2Vo¦ìB©=`oªŒ×[(­”}¼‚ ôý©”ƒ©ߎ¢X «Ã°GÀQp éÇS¥P?Aé œ¤œ¢tRNSÎPÎRÎQÎS.P.R.Q.S®P®¦búÃNH¿ž*Å:¢“ô›©~¬ç¼î¦b\®SX&ÓY ç~ª¤›2‡2—RA™G©¤Ì§, TQâ¨Åér”óïQοG9ÿåü{T_ÂŒ&C¼KÓå¸~;‚uÙq^Õ1½2 Þ2f,§`qv\¯V¢­H—äÚt9©¯¢¬¦¬¡¬¥¬£`Þ;©ïy ²žáÊFJee3e ¥ž²5]NqÆ8Å£Sß–.Úv4¼ ìH—3úNÊð d½ÝlIÏè{Òå¬^›$çô{A‘–t¹ ïKnjۖ.¾s^¹Ì[¥°UVí¨êPº\åä{U?Lïå(Òƒ œ§Ò¥‹­ébk®ë§Ó!g(g)ç(çÓå&{.óbºÜâ£å½œ.·õ;}äûñ»ðŽ~5rÒEA;î°3ïè×)•,rƒÞMÊ­tñÞN—¸»ér£øGñ}ý~:äÜßð¨Ghb7x ž€§ÀʇúpJe%—2’2Š2ÚN AòèåSÆPÆfˆ·Ó#ôñ‚ éÖ'P )¸ŽnŠn}"Ã"J1ee2¥’E¶Ä@J$C¦Ð›J)¥L£åŠ=Ýà °^Eσ\0 Œy 4xDƒ-…¯J¿¢W±3žD™L)¡LAÞT0 ”ƒ`˜*@%˜¼Êýöô½Š×bÊÊR«ËÀòWe¶{¥–²êUì¦ÖPÖRÖQÖS6 ì×ñPÀlõlõ«ØÓl§4Rš(;(;)Í”]”Ý(»´€Xj¶Áíà08 Žƒ¯Êwå$¢Sàô«XŸ…s\—^•D<{'õ+¯b ŒÒ©c„têW‘w tëàÆ«2×}ÎmpÜ÷À}ð<@7x ž€§Àê· È#@.Ù‹ÙQpò@>Æõç2Ž2RH™ˆô"0 ”ôÇ‚d*¥”RFÁlRìžNo&e6e.ee>¥žEªèm¥·ˆÞâþX›,EËúK…{y³M3Ìáñ3M˜V#c XÛ?$YJ*Ý¥èäýáÔ!½Ná MpVá…¿™ |Éî{YÒ×÷—ô›/Iz=ìÖþfCT± yÛAc³‰ñNøÍýÍ}¯ðW j⽬½…ÒÚ?dJzŽßô<ËïƒýÍq‚ÅÎáþ¡hYâ>Ür”rŒr%;ûK&Öú™W$s±_2O#>ªc%ó,l+?ß?ƒíÂiüå'ìåþæí¨³«ŒYå÷HfCŠdÞDú-pÕÞéŠÅ]îoæöAÿ9!s†0iºçѯ¤œ~ż–Øßì5û›7`kaW‚Uàâ»`5ü5yÛJ<æÕÇœë6̱IÁÆØkf±žj–$ ”- vz‡)x¶¸ñcî¾û<\,6£ôn€îÃ=ƒ0×¢Lÿ÷$­5b¢US± l…¿´ýƒÌËÉ™fqÌ—Ñ߇plPè+x'ã ¢³à8?ÈÌAo|/¾AfiŠa¿fV¤ô1ƒ_}W‹§{;FÂðÁò@þ`óH¼á4~0dì`³!ñ›æ†” 1g 6O§dšÁo…¾iöÛ˜f¿m~)ÃìÝ þmè;æÉ”àTQ –옃7L .ú®krð£oè{æ wTè}sÍ€÷q•ï›ÁB™òaÝ`ùpXgÎAÓ0ج 3ƒ?̃%³5 o%™;‡þN21æ3—&ò=6@2÷ cóbÒß›ÛBß ýƒüG¼E‡~h.Ô|¡™Áã(íî+ƒ!·’ Wéî)w›¯øÌáLóLh yÉô™c|æzýŸB?Á3ñs¶¦Ìbó§¡Ÿ…þÙ¬ó¼ú9浟›§_ù¹9矛]}nÎ… þ‹ÙŽ2oÄæÏ—Íàf­™‰ËûW ŽKpg’Ñä`žÌÜ7Ðì¹oHc#ø8J‚«Þ0Ï„ƒæåð'Ì[aݼÆ®¡î sMÿ_˜£ü"ô Tó L¤ÛÞ0›Ü¿ ýRO„$ñÀ’ˆ:Òô•ô£oHú1<²¿ÂNùuIßg„~ Ï#éè²ôSÈìG^éÇ’~œ~#ô¡y¼/îêoB¿5×ŧ†þÍ\èN5o÷M5G‡ú˜ß0OáßíûïÌÉÂ`É2G¦ͼT^ܘãR¿úO΋o`×e¦~3ô{óê ß›EY¿7§‚éÉ¿—ôéÉ’~¡¯Y×iFМšb6&%mzÖª`fÆW–Y¬|2ËŸ‚küÈlîÿ‚Ydl “ƒ"ÊTÈmÊ}Js­4ÈÁ Y•õ‘¯Áý‘ïbø#ßBø‹@[è#ß¾kËa©²DÈÚ é‡7[¿Š,¼Q*é‡I§ß½W¤ß×}ù)ù®'~仺ÀãÐG¡ÌàP0QúmÄu  ¯£M°›Áѳ.õfð¿Ìèš%¦…üî-Ë ~Œ-\¼qÛSñ®ïÌ2¯§þ·üs±ïèÄ?™R‡™Õ¾ÿÅ}qtëYæˆ4=dñ-„ÀCðtƒÇYæ‰—ÜæÖÇüµß,ÑuQc³å1˜ÿØþnÙ¸# LE 8[æë“àL% : 7ة١áJ‚“^—àÌl Îs³Íš´ ¹*í›f[ý:nóÂìPÊ-CþrP VQ˜EÖd›ÛP~ž¡æø·1…P¸8H0W™GÒ2ñÔŒT#Uh$®é ÎzGÁ‰ls"Þ ¡¡QÊìJf.(³ÅãG«Pž2­t¿oãdw&¦áéAÔŸ¯ÌüôO˜süÄ*+–`ç³™{£ts2æù¢7Ç(ÏS\z‚K×=Þ¨‡]z_—Ò£ÓsÂJyÙBÜÏ¥é±Æ«ÈTºo€H~¹ÏkŒZ_ÊÆ±/½i vÅÁIÿ‘ÿ-Dþ¿¤÷WðŸ„ø½O»\πϢok8Û;Ö`Ôú9äõÖúר5ðy”¦¹Ô»ÏÛ¬¹ú_D–ÒþÆòéº;!ñ+cTLŒÏçS*ék9_WÊø†õõÈâßdq¥}Ëú¶Òƒß±¾«ôä÷©îïçP_¥ü½õígÇx\*q¹þ!ψ¿ûŸËùgü#ä‡àG.WèŸz{Òõ´ö§¼ÂŸYÿì2~Ïøxá…þ¼ž’ºËì›ú¡E_W¿±2\ê·8òߨK¿CäÿwdüóþQÚGðÒþ`e(=éˆõÿÊUzú3üã?áØÿå¹,eehz†¡òTTTF†R/TÖ(…ŠF3«_¿ÀeýéO*œ9NY>ôöxÅj^™`<¶™è˜"Û¼:IåÀô/q¢)Ž™ê˜R§ä4Åf”áŽé¯–ÛIý§;fŒŽ©™pÐ }ÀlçÈ9¶ñϵQa›Ìy¶‰©´«›¯žw¬›÷âµ…*Own…}^[„ÌÐbÑýKØÏReUã’Íe´½cià ô ŽE‰ee¢@­m’VÚ&´Ê‰VÛæõµ*‡f£À Êª‹¨Êؤø mæÃ³EE<[ƒ·2C5°mÊÚª” lW–×5¸‘iƒ›˜¦é*°ƒŽãît\ÑL¯wÐ~c«c™½ÊjQ-,ÓJ¯÷’÷Amöùö+뜃 T»Ù9‡À±õ£v‰cNpÜ.q :"/&þ$ÎŽ¼SÊ„ò¶ œ†yVÆë2Œ¬ììl¥Î©<7Þ׳¡ó(f\€d]„d_¢\¦\QrÀ¸ÊËt®ÙMéRÖutñȦ¨›vSÞ¼­¬áJ×û©!wéñƒÚOY÷Õýˆ^y ?duáGÊêV®ðc;xbÏ‹=…x-Ì,ºw¸fåh®¿Éࣨpx´fù\á<Í¥…?ÎGà{v¬aÏ1ZžÛ’ÊÓsÍc5\ó8H`¼14 "}½)#Ë!PÅ F«Ñ\CjYû•šµJcÖêçYÊ0Öh¹(âZÛ{´ú¤±^ËÙ€„‘×’ý©Íš=^¶°—ê!Ÿn`½ŸÞ¦YÛ5IãïÓò´çƒúY >«í·[ àÍ>È“´S±A‡)Gxã¨ÆI6pÌ1Çs‚ƒJï°uÒöOÙ…;mÿ4ýàú§;kŸ.á3Îkœ×/0H¼¨ENrúÛW4ë*®äíkŽ uѺ޾ÎÂoß°ƒwn1xç¶]âwîhÖÚ»¶UïÜÓ¬û¸­xyU(Ý”Çxô@à DEÞ§ˆï¼céÖp}¸®é3£ÛY¨~„n7àÜ;²ÇŽrìçFÓºôe™å*×]/¾ÜaÓõÿãíš‚ÆLÊ,ȰÙzäd˜£ç)ûiÌEF Bñ5˜§;¯©ž!P‰¡ùzÄs¾· W£Œ…ºµHWYÆbÝêÒ–ð µ¥ºU­»¾°BGgÃjUëj˜QkwÇ0c%­Ë»Šm[MYc—ÌZÛS2ËX‡ÚòÅ =)_46ꖦƥoÂAúfž+y KhYFV=ŠnÝj' ¶†žcõ/m§§ô¿iê±;zìN»Ï‡žÑ¬[_Å̸K·Ø×n„Œ÷蹌Õ^;ÖµÓßÛãÒÛØ/û)z{“«?Pqs0±êü{öVùò!öùažöHd—E>ÆK ×­ºë«'|õ”|ý4ƒ¯Ÿa ¾8«[Çôˆ·ù9oóó¼áXи¨[çðô_²ƒËNpÅ®:Á5;èr‚ëvpà nÚÁ-'¸mwœà.ø§[÷á<àÉò><ê½ ¬>ºu SWÒc=fЗñ´·Žôû-wž­éºnÏIÃÝ|›ç¸­n—?×u÷HÊ(&ûG3Yüyn+ cìıv¢î×cÇÓb•á/ Ã$5Á®N/tsõáŸø,Ý_ÔsH±“?Éñ’~k²/逿ÄmMAÞTä饔iöYËÜV9ÍšÞcg864ӱߘÝcçк¾YᎸ½óܼO•n{d%Íw;“ŒËX€ßëïív[™.}[ë½!½ngª ´à°@+/7°Ï™@´9f¿c¸9/´ ´;I‡˜ô|ؽedfŸáná-=J9ÆZÓ;ÁìàáY'ÝÖaÞÞSŽýÎéžX9áwÎa ޳nWOšK?çÖžûçÑþÁ"GÕÀ‹Î5¢o.¹­Ën-Þô\Áp_uëß5ã_êr[×ÝüSú÷nº­[ìæÛ=ö­®›îwíJn¹ù‡Œ{N×ï÷Ø=<ì±lëöt»­ÇîÞ[ÿ„íiä`Àæƒf¸ÁmjŽÁîaàÕȵý‘¶?ÊöGÛ~ží罯w»oÇNߎņSg—oX|L0¬Bìãß/²cýýbÇfM걓ûý)ŽýA©m˜fXe¨¨5¾5݈\ fÏ0ì¥àfÖ,mXsPt.Jýý<žüû•ÌÑÿ!ð÷þ†5[ãŸU=‹\ÿ¸¥ÅÿHûÑRÃÒuÍoü¨Ú°–˹œÕýp…Á [Cëò×"ñ‡þ•†µÊP?4VÛV×ÖØ…²µµ†µÎÐ~¨ýh=3õ#cëÍÖŒìoã:ƒJÿñ&§Þovýá#gáÒëˆ;´5òÚM£ÁîéAÛš´ÝÀ´à4yš[7ô&£ ï`‹“v¢Fœ!©Ù±Ñ»h]úîÈš÷Ø÷~¯}ï[ì{ÖjXûðòjc`ìw‚vpÐ Úíà¨Ã Ô'ç¨sÌÉ9n眰ƒç§ë`‡Ÿ´‹2¬NsÚÎØ÷¬aÏqçu*É8oX§i/ÐF¼í.²ÁÆ¥Þ+ìâR™—<w2ÊÃÜóõÞ}ö‰®Ö5Ãè²/õºܰƒ›vðO·üÓm;ȼà ó®¨{öÝ·ƒÞéËx`8Ó^…Hÿi7Kýô±a=1\þ§ ü–òÃ=VP üä'9ë‘ñ(ârúðôL¹žc¤ûB—e£`Û˜çØ~ù=vŒ]È?Öq7Ç!çaá5«Û ¼…vðÏE ~VÌ@ÿ9'“=œ´K<üÓ¨) ¦z,ºJý¬Ôc‰¦y¬2Oê)g]é¬Ký,<Ãc)-ü³ÀÌžìç‹Éa†1d–Çžp-³Qtt#–·s<¸ÓÃÔÜž„F®Å*<–mçõØÊ;¿Ç. ØOW٭夺Ðc˜¸Èchâ^L버M²Ô¹¹0üÕk¸Üãza¬+<Î>øùª×¥jøÞ©…„VFvó*Vœ´š×¬»’ÖÀ*í_þuk•g•Gý‹==Ù€¬Þ±’Þˆ»¹âù`“]ÅfõÌÖTûkÚê±< ¬i=-ðA`»ÇjÒšð’ñ7Ú¥ý4±4îôƸ’vzrš=Í5ô»=ÖÚ½¶ýå­kŸ››sH`¿}^ÿõÁAÕŽÖö?d§~p˜õ©ÂG˜ÜîÁ{2òÚyØáÇÙ©|‹ðXžý;é±~ýë_+}À)Õ‰ ¿wÚ“«´ƒÞó?Âíðàvø»™íŒçÒãò?±ƒ§v°„Ã|¸Ø99 ü#œ ×FÚ%ö£êyâreæ3%sŒò¼óÆJÄ¢à7ãÏ…¿i¿™™ñÛ";£i¿$/lÙ'3Çõ©Vþ©)bwc*­+PŠ¢iÌ •IĘǦ‘9Óí+™!ÖLqfÙÁl;x^lŽða˜ËS*ìó„ïûJÛŸoû l¿ÊöÚþ"±"?Q IÅÒ³»ä¬¸g0–B’ªåŽ«é‰]&ÿÇÞÕ\Ž‚žØH¨6²sŒ•lŸ±Šç6VKî]Ûc×õØõ=vmoÿ…Ãíþ ×!1¼‰U„7‹µE\áz‰ØŸ¤[%OÓ°‡d{RØÛ(ÛyLJ£XMÂvÐi™RvÒƒm~–µËÉ¢»Ûq#W/{ìv¼½‰)-¬¸•²òVäßBÞi§âwD¬Kxö‡•œKZdEÇìŠôã‚é4+û„XÒ!tO:®Òÿ½“¶À§û»3Žýƒ…«<¯Ïå=3ê*Wéÿ©¬ŠŸ…\”œjFÙç. ’\úågEÞ¹Â,Ø«ÌàG(×Äê’.±?¹.Ö áŸúüçnŠu GÝ–ˆiäŽ=ÖîÚcíž=Žî‹u#ó<´ƒç¥±wºíœÇb=Áýzjß<Ëký rì 0‚A × FÚÁ(;x^Ûhî ò˜£ò½Ö¯+<)þqLñg ló¼§µÏNðæiÎ Å:¯ÐkMôº>[ÄC>[Ì@skŸäµ&x'`2Gê%”)^ªý~ª$Ö÷Jí#õiÞˆçZû¨üyå®?Ì@V`¦ÝðY^k6œ9v[çÚ¿Ânæ<;T¢zœx¾×òz]¬â2ÿ;‹ì|}±WséK˜’´Ô›3–TíØÐ2–PzÌrÇþWc?^éØÿ^íÔ°†g®uÿg½c væóÝè|B뼜ÖMÞÜÍ,»¥ÇÖ÷Ø­=¶V× cè6¯µÙË?~žºÝk5z#*oò¾øá”Úáu>œzöæN5G6Á¿Ë›§ïÐÝlþÐ=^k¯÷…J´ï _Äh­¬dŸ7bˆ¶!ÈÞÏã³x­ý^C7†(¿:h¨ýÞg:³Ú½\Ž8 Øãâ1°‡iùÙÑ:,« ã¨ã³@èýÞÓÿ³Ë5N¼ØR£ƒ-=y¹êô>Û^žöZ^¾˜Ï<qß;ëµÎõî‚ùÉÀy¯uÁË?—ëbd=o]òÚ~\öòœo*k ?F¹âÍáG!WÙv?M¹ÆDfû»¼v±¬ë=ö†cí’.uÓ«)õÍ[^ë¶÷y߸ãå÷œ¶{×)ý{´½pŸ#ù[ýÞ#J7Äxl? O¼ÖS!Ë„uéÃMŽ·;x~1ÿ;Òäqó,•gZ×ù®Ì7s®£Ƙ—=\3í;ÞäkS/0ùõ†1 d«ÿô‰fïlš£&ñÜ9j²‰î¡Œ)¦5•FÖ<ÍäŽÇ(3ç¿Ü,7ñŒN7­rÓeÌ@ÉOΤ̂f³ºÀæ)ý“s{l…cyö1Ï+®dá¤ù¦•éJZ?W‹Lk±É³-é9[&¿+\jò»ÂØjÛ|¼Ì6ÿ½œÇ=ï „ìÊ„3bÎòŒT+Íç“–ZÅÓ©Õ¦UkrBZcZ+Í•¦K_˾\GYyô†lè=Ø¿YFÉ õ&ö•26›V.JÛbbq1¤ù?ÚÊ3ü¨Áì]mxœu{`›É„[¾ž„ÚÎîj¤4AB;"{|gdÐŒÀ¿ 5gûwóÌþì=¦µ×TÙÙ-µìì@«Ý ìì}´Ùþ6]ÛoZЕÙþƒt ©ÙíN’‘uÈI¢{Øq]ÃŽà<£Ô1è[Ç!£U»ä$/)Ou²ÓŽ“|†¶·‘gá;g”¬ó¦uÁ¼`W~Ñq{?xÍW—Më *£®™9WPè­!]tà}+ûºiÝ0o üMó…5å-Þ\—y›1ï˜Ö®ø»ôãïÑÿî}úß}÷Cš,㑉}¡k`7³>¶³Œ',xÊN·°)Óc†G!áùš*þ»/åD9ˆâ$“…%f’‘QÖ¨¨QQüœ—FQžcýùŽãؤ±´½£2{\”³kÎÏóeDYp¼¸#4 £¬‰QhiQ”µk£b–Ð&±»n2ñÌ/±ó‡MA½Þ©,ä-u e«i=…ôä2z˜ÊË{ìô;ñ_šÙÏê±³{ìœ;׶ʨ`£"×ó¢"Ö•QÖü(—¶€­U1Àraa]•3?ª÷½ð¿ß¿8*O÷ê¦e/R]þ%<п4ʪƹüË¢¬åQ/îpÕŠ¨g;Üg_E¨–©â7*r‡1?öYÅéñ½5QÖZvÇ:Çjë£rÖF¹úlÀy“´QV]”Kß„³7S¶°9cÕV§pv­¦ÉÞÆ£˜4d;“"§áFû<¦(«‘ã`‡c;{lsOú®žx7íó6§ì?NµDq5MÙǨ¶(~Â𞎟Úïøï½çrè½@ݯy½£ì×eµrû Ãëmb—« ï¡(‹_TŽì¢#QìØ£ÓcÅÉ8_]°í÷/Úæ;—`\ËvuW¢zçi—ÿª=®EY]Q.ãz”ýޏnFÜÏ$ãV”u w¢þü#»QÿÏG ÷Ø•÷9@DŽ‰ì‡¼pÿ#œä5w”õ7äµ'è&õÚkOòs<+ÝÆ–£-ž#'š/äѼ-¹Èâ']Ѽ#ôF!Á¥Ž¶¿fËs’‘þý|»`¾ú0êc£­L¾¸¢ÇÙ9þñÑ9º¦ü‚hëIÔ“(Ì,¢­Âh˜hx¿È1Å<ÁóžŸÑó~crô³ñJ¢ù!Ñ”hkjtÄËn¼šýìQåû­,Ú.½¥ôéÑãbF4¯u&¯50+ÚÞfGóþϱý¹¶_aûól¿ÒöçG÷Ž ·+ƒuA´ýéÿeWá…”ElÕâèÈŸë,‰¶Ÿš¥ÑÖ’èÚ¡ª£Ÿý´ãÙZ†2Ær\ízáW5ѽ¿ÕF¿°ç޶÷ÜliÖêhke´+k¬e ²²ÖEógYë{ ё_ýY£ßmÔEóÛ߬¬MÑÖæèÞ.Ûº²ë£­­Ñ®ì ìlc[´µ=z{4f £‘[1Œ¡F“ãoÆå툶N™Êo쌶š£ñ¶_ã<Žïq&¢Ö½<€oêçH$µÒÃÈÙçØ÷Ûzì~»Ï® ¶ÑÖA$´¿Ð‡z†Šq˜­6ŽD[—Ý,|4Ú:qMÇá‡O°H¸#Ú:í Ÿ²ƒN;P§í§àŒœµƒsN±óv± v¸hŽKNpÙ®ØqÕ>û5;ðv1ð^w‚vpÓ)vË.vÛ îØÁ];˜ î3š Øa¡zȰP=b¨Âáîh‹¿8âU<áe=|` eÅôŒN5œ}‘CAÉ¥Œ„©Ñ¶æAõ|ʘ˜ˆÇdlLäO£ÆõT§Æó·mª †_ß© 1üF¯0&bœšÅj’šãüêpÀä¬h{ë,±·@Sb¬©1Jw—ÆX%´Óh{ÏõNY Ÿ—wËc¬éÈ~wFÙcgÑFü€l6O˜c?½<V$/žw^ĵèïUÆXóQÑû zl­¦5ÆäÌ¡ëÎ^丌‹™ër-‰‰Üõüþ¥1yü…”ón7ªyzcYŒµ<ÆXa·¥Æüµ ü+`•¬¶ƒÞ.‹×Öôt˜ZcíÄ^nËE¯g€µÆ;±w3y›êb"n{¼¶)Æ~Í1Ö´>¦Þ±I[i]zCÌ(¥§o³ƒg3‘?iˆËïßÃÏÓ¢õƘgØØ÷ÖmrJIáætGLž÷ÙG‚\ÓG¬ëùYÜN”Ò ì¢ì¦ì¡ì…„Z"GUvkLÏ%³÷ÅXmüÆ~Z—:`²ƒNÐn‡œà°Ý·Gì pÔŽ9Áqì¼®ÊIÊ)J'å4å å,åå<›uÁ®ã¢Sû%ûT— ¯Ø9Wœk|@ºxÔuz7èÝ´ ܲ›®·c¬ï¹ô;¬ó.å‹Ü·+|`×áÃ7r ×Ý1Öc¤<±ÇÃSçV,ƒá± RrbQÅJ.D¤7Š2š¥yv©@>SÆÄÚ[Ô±±Î °-†=™4Î.aŒG‰OP&°l!ŽÎ2&ÆZE±X(ÇÚ½þþ¤;™Ó¸R%±|Á·Ù•ñ…?…9m1n~62dª8'ú~©sp¾šæ8ï•ÙgÖËÙÐïLw¿?ñjflmô,'ŽžíØ¿œãXc®spEläO æÅÚŸWãº+c­ù±óÒ»Èy½*ÖZˆkz}‘c=‹cshÍ%vlx–ÆZÕ±.s:Ëk¨å±œÏVÄ®ˆU%ʨµ’уj²ZÉRüëYfÇFþ&Aöˆ¶6–›fȰõìûlÿ†X+O¡zöFzÜÂÔ9It7=ËÍS›éºô-±Oí!õ±=«›![‘1¤!6ò}¶-–ïöí<Ѱa±VSlS¬6lذ±ÖÎØ±®)ª姨](á6lw¬ÅÕWhKö6~o¬Ëf ›¢Œa-±Vk쳿ˆùö–h‹µöÇ>ûë-qÀi—ú÷샱ÖW5WöTuˆseŽåÒþ4å(‡Ù1ÊñXû fûuÄÚ ü“=ÿ0ÞNÙ×m»±–mO;6åŒcw¶Çžsì»ç{ì…{‘¶·‰—"oØå؈Ó[ÙÆ•Xg{•·ïZ¬ý‰|W¬ÅÏÉè^w\¥—*çs°iêV¬óAXÄJ³L݉}þÉÈóSÝýówà=çdûìŠìŠc­{hsÌ#Úçw8`tãVaxk=AúÓØ>û²|öòq¸ÏÊá/;GÐ>?—n ñçú8ÌÞxã Œµ!#}Öo s”/—%ÜѾ8®<ŸÕäÆÒ`h¾ÏnÙ_ä ~¬Ï~ð¦÷ñ®÷Y¾ˆA8Çè…Hú߉¾>(²kûv1ûö$_Ä÷ZxO¾5dÈdçl.½ÄÇÛ}ö'*S}V©Î4:½ÝXÆ2åhº>íw’}ÎÞgèÐ/'©@†R3|y±Ï6A1=ÿøSµ?ûaxÏþh¦ë|ÈÐÙ”9/Ï…$Uð¼ó˜[ ɘÏp¥ Zq•å˜ô–ø8T—ú–ú´éj†2–ûøã9^¹Zá³DÄ`&Ã;ìkXéåj%\ õyVù¬Õ¾Õ>,’×ø¬µ>•™¹Î—Sƒ7p¹š¥6ð¹ÑgÝöâï{ỈM¾ˆ%6û¬M>×ï·ø"—'C†õ¾ž)sÇV'Ê6§’ˆŸÝèãçfÙM>ûc´>k'²›}c{ïYænŸµÇçš­Z5WíCZ…š­öûø±í³ÕŸu›¥vä†ù003ÃáÃ>ç;º=>þ¹ÂGpP8|ÔÇÊÇ|xþf«9ê8+Þãc0Ouôœìõ Ô©Þà—Ž¯ôŸ¦Ç´ uæY¯¨³Ž«ë_Sêœã;¥*Õ'콸‹/ŽæKöhM¼ÌKN¼âs¾¿½êØW®ù^øÖ¶+òÐß®³Ç¹ôßàÑ17}Ö-Ÿë··#»òNä37NÝí¹I)÷|œ?ïs0> <´ÂGö3™iϜݎŸ™éÒ3óÝ'>~ØðîSÇXq4áqüè!'Îþ˜íçÆE4òíqjdÜóÁ“=*Û<ØÑ¶UÙyqüæí|£Æ°56Îç Œ·k,p‚ vPÈÀnÚÄ86m\ÿ\zrSRŠãøQvJЬÉSR&ÛIzŠ¿„GŽ‹ãϪéñgÕ=¶Ô>>'øR™Dî—¿ð…ò¸gûåg_Fa:Ê|a$43îϾ˜™÷â3³YjNÜ ÿÁknœó_¶*âø¶Üóâ,¬êÝ•0½wm~œýßcÄáqªÐºÌ~ ã¬Eq°‹{ìÚˆ;)õö;)þ¥qyžÞ¯Ï{6 üb¹eßYIYñ¯`Ëjâ"FJ-c%;"´*ÎZÞIZ—³:Ε´6Î^î­ë¹‘«ãìÌõ,äúäöÉ@ÝäûñfÛæ*cKœU.ÞÊÜìƒôm þg»42˜¯šœ¨t4=W©fzL ír2C»iE7b?ùÉ@’±'.¯g>æ\ì´¬÷/òKñ½qÎo[â¬VÔóý}Ž­Rûãràü p Ë0û÷š­hÎÁ8ܓﷳPä‹ñP_Œêpœu$Žÿ¢Ç£øãqöå{¥£·1Ee†OÆñÝy*Ž.W'¯Ý8g!È<y;ÎFÆ9Þ›ó<ÇÊEæ]Š{á?Â\¶Ï©_‰s~z9®Ç¸Wã0‡_{žŽMEœöÜ¿nû7âœn:ö½[Ž5n÷Äwâ"*ÔïF¾ß¸ǯ) ÿƒ8ëaœËý(òBºã^˜ï;í|Âöd?Ãv>ÛŠüo0 UN¼Ý}#¼P寣àB52ÞêýŸPºËøÅ$5*>Oïý•ˆ1Å‘™¤òã#Î?&2y*ÏgÇÅ?_XÆÇÛ3N¼ýu¶6–ŸëÆ[ã'ÆcšÁ¡z1 ÅLb¦ë÷“{+SÃUvIüð)ñ˜Û¦Æ[¥´Ól«²Ëâ­òxL(Óã¹WŸÁãf¢&#{jŠçoçðšùÕ·kn<¦Fþá*¡ñ–+rÙ7dž+ÙŠðüxkA¼+\e í °È¾ˆÅNÎ;g©<¯ ~æ2æd.·VÄGlzjâíu_m¼µ2>ò=³ ׸ãö¯Fúo×DvèÚÞÀË9ëùEê[ëãó¤wŠø!60p„±2¬²Hmb[¾µ9ÞÚïúV=’B[#OÐÑÉ®7¶9MÜomûÿ;󸬖ûþÏ÷Ì9çyγŸs.¹³€àÍvsmÒ4K{Óå¶iº'MÓ=Ý—´M›¦Mšn¿†E‘]Ù7\PA‘EP÷ÅQQAEDP@EŸï<¹¹÷öŸ¾x½Þ³œÙg¾3ß9gž!I<3Ýãlþxt¼m${ODROFøv’y:’z& ùížHêÙý½y.’Ú‹ðç#ï¡ ª­åEîèKu¾5¢Îü_fÇ›ý‘Øçì+1³îG:{6]‹¤Ç,õ-¼ŽŒë‘iöoÆ)CÈAôu݈ˆ÷½‹Šõ±{þî-ÎË;’:ŒŠFØ|·1îDÞÿ~^[z7ò¿×'í-冼ÿÞ¶ûì˜b¸vãj˜LDR×hÅɘé>Œ™oNýÈ|3ëiæËãw,O~„b1g#éïqÒÜûœî<;ß­ÄS®æ3U‚ç‘T¸ŒÕØ/bŽ—Ê‘j+Gš­¾ã+eØê;AìÉrõ$3öd…z’¥n6;Üœ˜#W9òbŽ|å(ˆ9V*Ǫ˜£P9ŠbŽbå(‰9J•£,æ(WŽÕ1G…rTÆk”cm̱N9ÖÇ”£*æØ¨›bŽÍʱ%æ¨VŽ­1Ç6娉Õt»-Ä×v߯eìvQ½â.p75(6‚ ´G±l¤ÅVûýïÔxCó-j³cïÔÞÙļû=@ ÅvDJÜP£øÖ~¶ÚïÀÍí²ß9Ýçâ’ÇwÛ©‡m˜Gbfà(›Xéí÷öñ÷:NØJá9i§ž²OÙÂ=m³ÊsÆNí±ažý‘yŽM-y1õ²^rñyŽ!ä„ÿ5÷¢­~Mòã-æ%ûãÀ}vª©É/Òe;õ•W X÷Ûü;—Ÿ1®Ø<'³—q^PÄ®Ùél Àx·ŽM´‡¢7ì÷®7K‡¸¦KoÚ©·PöÛìІ•£‰FPµ=tŒÞµùçWj¬ŽòS~wÿ#sL…v „;Î!šiBy½û#‘IûS<íÔRgj§ìÔG6ÿÑ?þ󴪿O]:c¿O]ú˜ûëÉ»M­}ï•¥³vêœ=gkòš·SgíY”&á)Û¸Iž©<Ù—ìóüÇ.CêŸ&úô‚ó#ØŸï±T„xi¿÷W Zª£&Ô4‡ÙŸî¤f8ïÓWßÒ c™ó^}õÝuâ­å«g:¼°3²€„ì÷^øàä8Y䳺¹¿ÆÌsRsáä+GA̱R9VÅ…ÊQs+G‰r$—²#¹L9ÞýÆ]î¼Óø«Ô ‡ä^Zã¤òù§µÊHXç¤cN_ï°þ¾ÁQ¿„ªŠ=ÙCÊúô§7Ã_×±ßâ¤V;ïë«àVç}}•° σ5Î{š°•´±R¨oŒµNêNg§óî¸|CÔ©6†X×;©ËÐ.'u·³Åo`¤¯‘M!›¸–þ=1O³ò|÷óþ{›öS-Ž:ýÔêð×–6Ž—ÐçHÚ>ö{»ÃIM“0;ÙÎ~x¾ípø<ŒqPù]*à!åx»ÛáÄ×;ꇵtD%ð5㨓zÌÞã\KÆ 'õ¤#åÛo§b!Ó¤r~Ç%äNö+=±ü¿r6f¶Q/[4™PKçU³©À?^0!<ßùÇ Î*IÔψE—Ps§O ‡Ëð€ÑÏ9W>ïé^åGîµØ£eø¯+#0¨ŒøœŽB:ò¦JçV,ÔíXœa~üNÇ¿i|ÖX:â¤ÞqbBÜ}_Ëßãâ¹£ªÉï;©c誄?2ÇÙ|'¬Ú!¶AF|pÂy÷‰&ÿ—Â%Dü$¬‡À¦wš¥j†ñ˜Eë‰óž)})Ѭ“õž×[ sÎûwºñóÿkì>E€øgÎ{õ~.ê‚£ç9©/èù.Ϙi®r¤+G†r¸Ë\õ»2vü|¦òüü ÷=‡ÃÛÉp“㓳ÝÔw~½“ƒÇn.œ´S>_Àî•îû~¶JÅ‘…ð•E®zX즖¸Øñ—ÆÌ¥el YÎAVs7+bOÞ¬TOÞ}]û>Zë¾§5"¯¹î:÷ݳáè¨õnêDN¨Š™ñÙäsߛزÁ}·¿‹i³«×»ü¦ÚMÝê¾[ô¢mnì©pjT€ínêWüS­ûÞ…ºïç\k"YÏ•Ùŕ逦ÚàŠ/4ºÚ»Ž¦÷8Ü=.ö Í®Úæïuc{¢·ËÞâ"ü?ßÊ–m±4ÛÙ-ä>WãWÙ±§líŒYIþ÷~¶a·ÏÛu〛õã·§!½6€|p€¤øÐuØ><|dÎİ%Ý€mñlÉC°¥Ü„mÉ-àõÛÀG‡Q€¿|‚ï%‰¾˜Ä£*«ûŠc±Üùv’Ï‹q¾YEL(N*>TœRüçïXoˆOú›Ó”(–ÎÀöUÌ'*D+½e½)~ÒœEŽŸ~jøÜSàóÏT;òU$Q±@­dý„øi}?’ù™ÀϾ~.U#ñó_I°>#~Ñ“¦iâ—Ò/g¿¼LK_YÎwOˆL¾C¬PÜ„®ú¬ø5 "&~= BöÙ°ýf6l¿•ÛWs`û_PâŠ<›¯(YÙŠXŸ¿óõ<þFþîJà÷VÁùû«`ûƒBà áü£"Øþ¸¶o£xR‚‚üi)ðgeÀŸ—±ZKY§U üõàoÖ»øÖzàï6_üÃFàÛ›€ïlþy ðÝjà_¶ÿº ø^ ðýíÀ¿í~P üûNà?ê€ÿ¬þkðß»ÿ×üO#ðÃ& •ö ‚ša8šÜ«q÷´(¶r3`)„Ñ1ÞÇ/}>¾l# 3æÚ‹v æ:‹Ñ3©fìfjòp,Ä6ü~¾Bäƒâø!q<úDÌ8 w ÆMôÄ\ga$ç¸GÎE©—Í@à¼zËy!ä"ŒK(%_5rf,£+ªû®ÆÒ¾3b%ºs Æ\7bÆÆ/}›±Toi_±¾ 2HÞF¯.#UËiÏ>&>¡ûi‘EÚš1›î€9ô?·~Fä“g à—(VÒ]çæ{` ‚¥Ä?²ù¸@6ΗÄj’ãÈ¢‚&¢’&ÕØûæ›Öωuä{¨9b=•i¶Ø@Sx^Eà³t1¢§á¿™fà¿…ƒÕô±ß³ªyæ´oZ¿ jHΣ0Ûé)¸ƒø¾’O‰çÚ›Ö/Š: / çzZ@j»èì»A[¿—°7‚.ö!©’°j$š)ÜK` -[i9ØF™|ó„”+¤j»,©Z4[>׬/‹Òsd¢è¤\p?å(_ò,“E ÖWÄ!òsóv·Ãa*š8B+Á£´ O•àZ^¤µ*À:0Yð-'IßsR%Ñ®›ÈúMLÃæF”¤Ÿ6J‰ÉxìWA‰¹˜o;Y$¶(P5Y_ƒdU#Ä ªFˆ!Ú ûMÚ†œnQ x›¶Ãg˜vÀ>Bµ|ë‰Ø þ¤ø•ë·1ÿÜ&£T‡P÷©£]ª„»Uud¼ÿwxn„~,¦IkBBS´|DŸ{Óú]Ì´áfD›¥½àµ€ó O©UÚâµÏ©1hø‚:À—Ô ¦jûÁ4혮ŒõkW¬_ÅŒnù9ë÷é°\®EöÊ$L³-r±ÈÖŽ FŽvÌÕŽyÚq0_;h'Á•Ú)°P; kgP®­i~VœÏIÑ«êy^)Ý/ÊxëÅZM\‚åD•&>áùc±Ysû‹v¬ÖúÁ­ Û´Dvyl×®‚;´2øÔj×`ß© €uÚu°^wi7ÀÝÚL7ÁŸ·À/ŠÛ±ºÃ‘âN¬î•¸"š4¨âÖŸŠ½Z/À-wV«v«X4Âäy>û´{`‡6ŠöîÔîƒûµ1ð€öyÔÆÁ.m<¤M‚ÝÚCð°6ÑGµiäû–˜5ñX5Ï5 fç¤ný¹8¡™óÈè¤68¥=…ý4AÐø"•8ñ|E| -÷—â±öÉé`}’\Ô^Â~ tEŸ–ªÛ“4°_K¯hºƒ™txM[Ÿ-¼®­ÐI jYà -[×Ä–ûM-¼¥å·µ|pX+G´•àmxW+ïiEà¨V Þ×JÀ1­| •ãZ98¡­'µ ð¡V NikÀGÚZpZ[Îhëu!¾$6€?+ªtþ*)6Âø9±IWsíf¾ŽClQ¬Vo;¶*n‹=þ½ë¯1azXææ5ž‡žj5¨Ð3m;ø\Û¡s“×*îß‹·þV¼ÔôÕ›*ë*MÖ«äw)þN‚õwb™”ü|¹ät3ånõd)ÚÿD¶Lj@¤ÙˆòçÊ&0Oò(Ê—¬Çȗ辕rüWÉf°Pî‹d bËVØK$®T¶Á^&ÛÁr¹ý²Zv€²¬”ûá¿F×ʃà:Ù®—‡À ²¬’‡Áò¸I7Ëcày<Ö:'bÆÉ˜qJç¹ê´ÎCñŒj‹ð—D-µþ³Sð¬ù“çBì·Ëóª­/À¾C^kQÇŘî.Á^'ûÀzyuÙ%ûòŠ.®Æ²º¦üoã­ïŠ&é@ˆ=ò:Ø,Á½òžÿªâ+}ÄMÕ¸·o«ü¶ðDü¯¢Mú†º]£\ûäì |»ŠØJq@ÞE)J¾^e‘]ÜSŒéñÖ÷E·\ôËqð(ÅQ9û1PŠãrö 'åCØORœ–S°Ÿ¥è‘`? JLrÓ°÷‚óÜŒÎóÜcç¹':Or³`ŸœƒÏe9¯á©â3ÅçŠ Š/_*òm¦†ød¼õqU†Òàú‚HWïÌ3 n–eŠË•¦â õ4KÅËV>9*L®bžAâšÌT¯Ë¯¾iý»’ñV3Y` ÁåJØoKÞr KÞnŒ€.&ÊUˆwWâé=Yû¨,6lq_–€c²| Ëà?.ËÁ ¹œ”àCY NÉ5à#¹V•‘¯iº¹>flP÷¶V©'¯Zÿ‰uè± ­21/ò 4+yš“›à3/7ƒOå$÷LVƒÏåVpAn_Èð¥ÜŽ‚¦ê;øJÁ÷·`Ú©Òòúß"C7ën™^.×w™únÄY¡7€Yz£¡†l“ñ¶õC‘«{¶£kóô:äœ8P J!â$‰UúÄ/Ô› Ÿ½F¼•íP_ËJ'±ZWÛ ½Öë­à½ ªôvÍ€\éâ‡(Õ2H’.÷áIÞ¡ú°üºxãM+‹™îçi©Aç²Qß`Múp~lÖ»À½ú!°EïFw´ê‡Á6ýˆêü£ŠÇŒ7¬,Bëvè·k§Îíº_ŸÀ„v)'‰ƒúq°K?té'ÁnýxX? ÑÏ€Çôð¸~<©ŸOë½OçU{_ˆµ÷EU‡K/Á?xËÊ!qNsSôê}ˆs^¿lð,Ò^Ô¯ ×KúU°O¿ŸËúد_¯èƒàUý`}ˆ°~¼®ß2X¿ë«aôŠ!]k@§ÜÔGàý5h¿Ã†U€EKrïèwPÒ; wõ»<œA‰9âì÷A‰9bö ãú}ÕrcŠÇ'ŒoZ«¸-ênË)Õ–ôIä2­O¡Egô‡(åc} |¢?gõipNŸçõÇàSý c}–DZ>g8˜æUÃ=Umù,Ö–Ï Ã*‚"g„~šñL7^‚|E2&ƒ4{#öL#\a,31’å°g™&wà uËD–b¶©6V9|y‰ˆbü•@£3"¹¾ÒÈWùH Ð(€½ÈX «À£,5ŠÀ2£,7JÀÕF)Xa”•F9¸ÆX ®5*G¥)øÆôÓ‡ã­r,V†Xk"× ¬RFhrÚl¬·§Ú¨B`Kl4¹)6©2n6Õ†u ŒOŠj0^lEЭÆ6p›QÖÛÁíÆp‡ñ}ôüH“ñ ÷|½Q‹äwRì6vÂÞJÑhÔ™,èu°ï1êao%äxì- ­ÆnØÛ@)ÚØ÷Rt\42›T9÷(6+îUÜ¢ì­Ê޽Ê: â4Ú¿Ëh‡ý(E·ÁºÀacÊ~Äèà1c¬Ý¨´*ššµÂgh]ˆÊ8¤<«È´6’è1œnøž5º‘ê9ã0ì½ –&ãì@Σ°_¥è3ŽÁ~”¢ß8ûPŠ«Æ •îIÕü§O›ü"ëŒÉÛªSéÒvY›!†Å«æ q ܱO2ÎÁ~”â–Ñ‹ÊÜ6ÎƒÃÆDýKqÑTó>6ÕX\ ÿ%„¾g\BèQ£öû ÄѸŒ8Œ~pܸNWñtÒ¸Â1ã:_î"þZB äÐpXM˜6XM˜1xïöØà½ÛcqgHgÎç›àSãøÌ¸ >7†Ác|aÜ_wÁTó˜fŽªœî›¬9ñU1-˜ñÖH¡Gˆåæ‹¡9Ébh>4Yä¦X ÍG`Ž9 æš3`žùØäEã‰jèYÅ9ðÓb^ù?U#'ŸÞ²vB,MOŸ«ÌgõBó9Xd. 6Å %æ‹X‡¼äTO¼¿biŠßO°vAMã!Ô×µ&+±ëLVb×›i%¯Î„<6` 6 ÄÒ\n6—{Xè2Ájs¸ÕÌò|Ðj„œ™K²=šØßDQkf€;'QÔ!qÅ.3qv›¹`ƒ™6šù`“Yî1W‚Íæ*p¯Yèa‰)[Íb°Í,ÛÍRpŸYv˜å`§¹ÜoV€ÌJ¢5Š|‡Í:XϷɾµæïE•z°ü¾»·YÝò±D£V{øÝÕVåµM±†ÛB—ÛÙæðZϬ=XM“» Û܉ª6ëÀ#f=xÌÜ…Â7wƒ'̤xk/VEÓn€óŒÙö˜MàYsxÎl{ͽày“G÷³-y”â’Ù {ŸÙ^!”f;ìW@¥¹ök f‡G½Pëô$Y-ض™áýx8dîÇÛæØoRÜ6Â> J1bvÁ~Ä h‚ý‘3»a¿BäÌð?@&Ib\,&Ì#N­XæLñíx« »4SEù›Çô‰É7×|Gœð|ÛÚ‘2µ£h”§æI<{fžòèV'DÉôž†û¥yY¤zÎ Dšç.”ŽtÏ=0ÃÓƒô–yΪ±È÷Ý|QüZ¼u2äQc6˳Z“"ÛÓ‹Dr@)r=çUà Š¼Ôwaó¨¥~¥‡—úU^ê =¼Ôyx©/öðR_â᥾ÔÃK}™‡—úrÏE•Ì%Å>ÅËŠýžYÝXÔ<&¿‚Z㹂¬õ\×y®©¡6 xï/ŸH°Ž@»óx`£‡w›øºŒ;–¹-ž!/m7ùú"q‹ï/oãñç¹p5ža4ÄvϸÃs¬õ¬Ç Ùé¹ {çžÊì3ñÖ –Ç3Š( žû`£g Òbkåy û¸â„â÷Þ´NAÂóXg!7‹5Õ^O6b÷ä€<¹àEOxÉ“öy À~ÏJ¯ÒœVyÕâYèý’Õ‹EÆ*ò&‰kžbo¢ô”€7<¥à§ ¼å)o{VƒÃž pÄS Þñ¬ákEz_¥µ0^¬‹%º>V¼ 1£Ê‹áwÄ}‡‡ß˜g£2B‹ôl‚}”bÒ³Ù«Þ^(þF¼u «•'Ì|Z ðO5?±Zyxg9ëáåœg+üçA)žz¶Áþ „nè©QIñ½>‹ÄÅZå³Sñ˜Õ/c óxyŸ— J‘æå^º—wx^þ¢´ÌË»ºåÞ:õE¿ž¯:»¼K­+X¼¼~Þàg{w{‘bGém@#çyÁ|oXàÝ®ô6ƒ«¼{ÁBo XämõòË®6ï.¯u z£÷#í(z™wXJ±ÚÛ{(E¥·ö5 k½ûa_ç=€Xï=ˆÄ6x»`¯ò‚}“·öÍÞðoñ«½GÁ­Þcà6/_ô=q<é|ïODœÿCœ{¼"vÕÏ9UÑ^Ĩñž·{/€;øÎ4â%p§·¬ó^ör³ô#ü¯(ÀbAóz¯òÀ]jåæ}ù"M.‹±½zlO~MõÄ€W­%×½dÝÀâç… 'Šfï¸×{lñ®ÇªÞê½ {›wY¶{o€û¼CÞxë&$Ò+nz¬[$º¼òšçW½m÷ÞVÕIL²†¡8zµa<:æF+÷þY‚5‰óªR§Uø3Þ/¿ñ¹ãÅà¸ËÍ໋½Þ»ˆqÞ{-{Á; ^ôÞgÉòޱdy€—½ã,_Þ ðŠw’¯?½ñþQâú¥R‚u+‘WN!½!•ÙMï#ÕHÓÞX ýy%¯¡#Þ–,ïcð®÷ ª7NbÌ+f½_µ& ãymÞÿOzçð|Ê;>ò>g¼ÏÀÇÞçÈÿ‰wœõ¾ç½/Á§ÞT œ7 \ð¦ƒ/¼–š],5,ç;V,±ÂŠ}Û°Ô ˆ:zÓzÍÎò—h¶H·²-ˆ…uEÚˆu\nåÀ'ÓʵlÄÌCªYV>˜m€9_d¨û0ì­:²A,,=ÛJV‘Í* ­ù!6´º5ƒ”¥×A#-Å—(ʬƒ`¹UŠiØXYQë –Ë*G[¬] T [š50¦½‚oòùX.'Á×åCD`Taã£Ö#6YñÖƳ%:PÅyŒc+´ Ö[[À]V5ªµÛÚ 6XÛÀF«l²¶£¢{¬`³U îµv‚-VW´ï5ª·Ôì¿‹oBÌ+Þ²žaÀZVƒ%Å>PV#òé´6£öû‘g¢8`5Áç µ첚ÁCÖ^$Ðb‰VK³^`óciüâû¨Å·Å!=L©X=,O'-ž&NYûÖi«VïVû&²Â7i±öóü†à{†°ŽòUCG ¹1g,ž©[_µò¡dù‚¼à¯óñT°Þ÷InðÍ‚U¾9p£oÜä{Š„7ûž± øž«ø *ù*E¾lÈF-y¢Oó-µVjb›ïµt-_ºOŠí¾=Iìð5êØÅ "ØÅø(IÔù¸?ê}>ìb|ËÀݾå`ƒ/ÓçˆFÐM¾>Lä¾,°Ù— îõå€-¾\°Õ—¶ñõ@¢ÝWîó­;|«ÀN_!¸ßW„’5h=žIKøŠ!´^šÏ*ÔD—ÏÃe8¤ÊÓí+CøÃ¾rð¨oµçï °Ò'Öøx‰]ëû¶U AñyYù>é[‡€§|ëÁÓ¾ ªúUŠ7ùÔKÅßJ°J5qÖgðûÝs>Öz}<ÄÏû¶¨»sª·úâýåߊSɯnVCx|.¿ºæÛ†æðÕ ¯ë¾íà oxÃW ùv‚7}uà-_=xÛ· öíöñ±ÅF_ì+ŒfŸºZ¨Å‡Tž|&h@´ž Ü|Ï5«æóîGb÷|ÀQßA𾯠ý4æ;>ðuƒã¾Ã>5¯QuÿYaÐQߟy Å~è;NùN€|'Áiß)¤2ã; >öñÅ[ë4ñÜ'vóc=v0>µÁHõ÷ p(Eºÿ,ì T)ÿ9Ø—ƒRdú{a_J‘å?¯Zû‚âEÅKŠ}hØ*Hœ_\æžßIó‡ûQî•þ+(Ã*ÿU°Ð ,ò€ÅþëH¶„¨ù}±£1c(fÜô©×e·|j¡»íS÷À¸ãC›©ÿ U -f3¤Ìoò7ŽÕ~þÆQáço"•~þ&²ÆO5רjþûh‡jMTùÅO%X[±ñüEz‹Ÿ¿EW«þ[ýcj ”©2ІR¯ tÄâwªê}«š¬ØHÞÜ€û°*ûFPŠM°o¥ØhD«A)¶øí涿ݬ D˜íþuØŽ@ìµ ;‡`¯¥¨tþ ”bw€ß†6ømhcà0ü›@)öøts€?uí  (Ekà(ìm íc¨á¾Ÿvé‡gà|öNò@×ÌÓjœQìQ>gÕ :§Ø«j~^ù_ð«3’Š—”Ÿ"_¦´» «°ÍðéV–Ã@ä*²<¸vÀÃ,,VG×a?d ܆P¬›àÉÀ-U”Û*éaÅÅ;Šwý|Fµ2FýñþnMœ ˆ ¨Ì‡±Œöˆû£çcHñBàx10®ÒðWu"Ð'áÝxègg ,†úæç“hÐÐß²ŽkâZ@m~Ó ×3à`à±?Þ:9 ˜OüüÚcVqiÝ Ìƒ·OÁáÀ3p$ðÜÿ9ë„0 óAÑÀÒ¸xgc¾)"Rñþ3¿ärÑ£‰Ù€L`I d€ËÀ'¿ˆ·Îiâi@5á3PŠçåM,€R¼ð<ó2ÀóLjç™´ Ï3éÁL¾YFðÅM†à‹›‘­˜@CœÇÒôçEf0/À ‘àBø»ÍJpUb¤æ×"kMQ¬Ò+A¡V!D"+XfËQ‹Ð@ƒ¤xë’&V!LØ^õi¢(è­DÅÁ5Z\ –×eÁõ`ypƒº\¨Jå½1ÀïÚ6!‘~M¬ ŠI°®@ê‚Áͨí†à°*X n n7·›ƒ5à– OaÕÁíü yȳV•w§bb½bÝñZ× W¿{×»XlîB3î!’Áݰï!’ÁØëAˆd°öÝ D2Ø{#‘ ò)ä=Á=°7y†Ýl†½%¸l ¶€mÁV°=Øî ¶ƒÁ}`gw*ûA)yïr”¢+ا‡@)ºƒ°ò‰ª#Áý° ò«cAþFp<ȧ«NùâÉ Ÿ·:ä·…§ƒü¶ðLðÂ÷€Rœ „ý\ ô»Ðò烇àsIJì†ýRð0üû‚üÖñr¿b÷ù+ö• ëWƒ|¢íZµˆ Ÿh»äsVƒA>gu#ÈÛÕ¡ oWoy»z+xiÞ‡ƒÇÀ‘àq¤'x¼< Þ žGƒ§ÁûÁ3àX°|< ŽÏÁ^p2x|¼N/‚ÓÁK,)Á>–”àe–”`?8¼Î¯”zu- Þå bßžb†ºøÉç㫟ÜŠ ò›JNnÅünÇü†cGbƘ¡n‚’ò^Ì53îÇŒ±X®b®ñ˜k"æâ ¡M>Œ¹¦bEysM+)˜Q|¬øDQÝ %æçŸ*>S<é}úŽ9!HuX žŸ>n b.ø@lzˆÄf„ÐËB/Àå¡—`f(5¥ùž—tu¹ _uÁ‚jÑ[32cÆŠ`¼uS9!-‹¯§ƒê½xvð»Ö-Mä‡9AèÁ!Þú¬ å"ÍU¡¼`¢( åƒE¡°8´, ­KC…S*ËCÅHÑ!YË©4X´†¡Ö†ôr$º&´\ªà{ŽD¥b-Ÿô¿ƒÙ äã£bU!>«µ1Ägµ6…Ö øæÐZpKhÒ¯­·†6ÕwWuóæe|-Þº‡å8D›dGhsðkÖ(džÝPvC[Pé1ÈzHü+2| QupO(޳æÐVd°7ÄbÒÊ@!ZCËÀ¶Ð6¤Ôª÷…¶óýO˜TÔ¡¸Ú ¿ãÜÉ7aVЦ0­@ í;C»Áý¡ð@¨<j»B{ÀC¡f°;´<jA©&°v†0µÄû'5q2„é³ùCË3!/Ÿpè ñ ‡³¡vD9Úö†:À ¡NÕûƒüŠá@P½g;,õY4Ѽ‡0÷¼a=†˜‡ Œ x<úƒxk‹dHNaò› Ma²œÅ.º\j½„ê’}ˆ·ºŒ/BýªÂW‚º•&EZX^EÏ¥‡¯¥ÈóÝS¿&ˆ·2°ÿ «¦[æ¦Ë  vvø:˜TiÜP6¤ÆàMÅ[ÁÛAk¹ùam Â#àÊð’+SŠ¢pý†'ƒ¬Á>Tœ òÑ»GAþ~5­ê=£Dò1˜¨î•â PMŠóêéStLVµ°ŸO^o c¾›ÂÏÁÍápKø Kø% K85Db[8 ¬ §ƒÛÃàŽð2°6¼<Ôæµr¤ØV§ w‡3C’ðŠÿ&þ$Þʃ‚ö^Åö°9œ…G{ÃÙ`K˜¿Èµ†ù)CäòíB"O1_ùü˰,@ûÂ+ÁŽð*°3\‚ô­Äš~¥‡ÂÅ`w¸<.„ËÀ£árðXx5x<\žW‚'ÃkÀSáµàéð:ðLx=ØÞž WçÂÁÞð&ð|x3x!¼¼®/…·‚}a¾ñ)YÔ„âý…R\ câЭb)Ÿø½æ¿ƒá¡Dq#\‹Cá!>÷»{ŽR)n‡ý±]gªo:0Ù®ö¤ÝŠõÊŸ¿<|Aì‚}wˆçÑwá·;ìPì—{B߶ʤ¸6ùíÑÝp32»Þ‹F ·¨»ŠZURm!µKDö«¥x¶ÚánÁ¨öðîÿƒÂxLSïn—+Õ¨Cù¨k—…ºwÓ†y…Äü7vxÎ{æùo*Ì3ߣ0Ï|ÓažùfÂ<ó=gb*~Þb͆€sáƒà|øœo±x &‰gá^ØŸƒIb!Ü¥®3ÂD§êî˜ÁPa–ÜC!k¤#¡ÔHÂQ$“9¦GŽƒþ–¹,ru_BŠ#'a_J‘9{6(EN¤“Bn$SOy‘sV¢Èô‚‘óàÊÈit۪Ȱ0ÒE΂ősÈ¥$Ò –F·bQˆuþ‹ªq/)ö)^Vüåk«#F?ò®ˆ\+#,Æk"WC|\÷šâ@(ÁÚ Åúˆdíqƒ Q¹®úmŸ¯•¬RlލÈ–È ŠR¹n|Ò°IŠícˆe2rÔFnÁ¾3r¬‹ ƒõ‘_L°6Kѱ¸…##ÖáÎÛáÓUÍ*ǽ‘;ª2wCü%÷^ˆW'¾áÊ-V'ÿŽB´EX•kð—‚Ž)茰¢·?ŠÞ‘8á/]þ"q(Â_ º#üÕàp„¿)‰ÜgùŒŒ±|F°|FÆY>#,Ÿ‘I–ÏÈC–ÏÈËgäËgdšå32Ãòá‹°økÆ58ùú«¹à«¯ž†Ä3ÏC˜ð' «FŠ Ï ´ÔÅÈK–ÚHj8Q\ޤW"éàÕHFXé[|ÓÕR±<ŒMÊh²#5Œä€7"™9YVËU_¹$¶CŽvBŒ#:ÿDf8ŸG"Ù*•œ°:¼Ž·ê±ØE̼0´ÙH>8)+oe˜K¾*æ( óTþ7ñÖn)&"|ÿâM%R¢ì¥HªAŠÇ¬ºÕ(Å\Äá÷ëó~Mÿ<ªÖB„¿F½Œðר4»™¥Û«Á »\fW‚Ëí5`¦½̲×9öz0×ÞæÙUaèo6_tõYÁ7]AØV_ȰÛ#Å*[ª )Ø¢JW­XéÓ­f)Šm}+Ú©Ä.÷KQj³fTfoS ²ÇoµHQa5È¡ÒæA¾”b­½]…ØæûÄNú°Õ&ÅÛ¬EÀ*{'¸ÑnÂhÝdש’Ô‡•jÁ7`ý=›xÿ>)ªm,8ñþ)jlÑÞåµ:¥¨µü¥z§Í_ªëlõIÀnBwÙ{ÀÝv3Ø`ïEÅíäÓd·†ùWYmaÞy¶‡Õ÷ç}a^Æ:ÐþxÒi·ƒ<é´Ø<é´Ú<é´ÙHbŸ½?;ìëÒƒª°]Їx‡ÝPöap¿}<`Úoua[gŽ!ØaûXXŠ#6﵎ڬ+³Ãÿ8(Å ûì'A)NÙ'ÕÐ8¥xZuÄ™°ú~½•'Õ-E-ùÈÑY›³{Ôö½aXØÄ:ØEûløÛÖQ).Û’W~ûr¸b÷ªôΣQcI³E%X' v€Gû}¡nÚÁ[ö%ð¶Ý‡2 ƒ›ç’;öå0„ëWMpEÙùb­Z×Â|¾w‰Ÿ‚xØX+ŸkÖi¬I¶>ˆ>·o€ö8ißT}r Ð#Åë&$ô¬„r;oÛ¬¡=µYC{f#øs{\°ï e_ØwÁ—ö=0Íeypî³<8c,Îu…3®Š7¡FüdlÄ?T×M…Õ[åGêùtø ««†c±ú›ë°ú›ç̄Ֆð±j«'jÔ̆ù]É\X½+™G>ùÎS°ÀiÁtqAŠBG¾÷ísLÈEã^”¢Ä1ø;©£$ÇáF,wøö-M]»µ+#Ú©«^鄹êk®úZç*½Îy ®wR#‰bƒ“!Q夃 p“³ Üì,·8™àVgXãd;¾dë³êv-4@½mõCfœ/òÒPïðÁÛ]¼ÝíðÁÛ‡Û6:|ضÉáC¸{>„ÛìðÁÛ½¼mqøàm«ÃoÛ>xÛîðÁÛ}¿ïpøÝx§ÃïÆ÷;ünü€Ãï¬:üΪËáwV‡~gÕíäF  ÄÂɃý(±pòa?B,œØO‚ ‡ÏŽvøì؇ώõ8|vì¬ÃgÇÎ9|v¬×á³cç>;vÁY‰¸A).9«`ï!N!ìý ”;§ö« ל¨ ŸT¿îÃÐ)o8¥àSÞtÊÁ[Îjð¶S;•àˆ³¼ã¬ï:¯'XW± r‚¬ì9¬ì?pXÙwXÙŸpÖ!ؤÃG«ªÁ0åð]c._6&X;P?ºPÜ~ ú:yÃbƱx>vªÑ¿Oœ­à¬³ œsj0Bæíõ&bG̨ðèÝáÁV‰·%_ùPùuCŠ—NÜ–ÐT÷f(I¤¹·`Owoƒî0¸ÌÝ…t—»»ÁL·\á6‚YnÒÛBP1xÄÇ®!ÛËWž‰ÅVåÓ¦ìíàFL£0 C¢CU´S‘/Ãú\e½eÝ”"×U?ÊÈs …îA°ÈíR Š@/½¥‡ÿ$Èå#1å.ËÔj—ÌUáv£I+ÝÃà—?|®uyT¯syT¯wYÝà²&Zå²VºÑe}t“{„EÇ=ÊWúã¹ ³ÑÄJ =á+‚D…õkDŠ­®ÒÓ¶¹§P¸÷4bowÏD¬»Øq¹’_ŽÔ¹Ü¡õnJë,|TŠVšMĺ!q%ÿj½Ã埭wº|»¦“$X°=w-Þ_t¹çQ‹Cî°Û½È2¢Ò<â^Šð'å>P‡¦ÃóK¿âi-ɚ⸸‚Ð'Ü+Í'Ý«°Ÿ¥8í^ƒý ˆ•Àý,ˆ…ý{/(Åy—–^pù`éEw ½eMBT\/×·ßD}¯»7ÀAwµro‚7ù4á…¦ÄMÅ = ŠW¬)¬®úEވ˃üŽ;á#•w"X¿§±0¸tIÝwïE¾iÍH1î†ø·î(|'ÝûHú¡;N¹ÀGî88íN€3þÃØàžŠ¨yú‘ãÓjPÍ(>Ž ­'‘xÿ)f]1Áâ2+ÅSטC.ÏÜyð¹ûi.ð-gúy„¤LÌ‘óR¤F_åOOiQþè”åSQþ0µ,º€öZj"3úö &²¢/‘Xv4Õ†îMs£é`^4Ì. ¢ËÁ•ÑLpUtXÍ‹¢Ù`q4,‰æÚê­Už­ÔŽü˜Q`«•6¯¶«ìoXÏ Ñ‹Åêè ”ÄŠè °\,ÖD‹ŒD±6ZˆäÖE‹lG¬1¿D‹áS-7FKÁMÑ2ps´Ü] VG+À­ÑJp[t X]ksû®³ùÐÆzð¡ÆñÑâ*[5ÿƘ±ÉVï÷6«‚nQ7~T³—Ø{°Íæ÷HÐãÄv[ìˆÕНJC?®ÀºŠÒNdX­³ß°^`iŠ<ÕíŽÖ÷!º lŒî›¢|™Ú§Ä'X©ºØ 7Úšh‰ò‰ÞÖ(oTÚ¢¼QiòFe_”76Ñ&„éŒò°ÜÝ£ É÷¯}AìUä[Ø\ѪüÛlÞ1óåjA‘ƒ%<]]QcŠ–«Ï‹M°2tq$ªFùÑè2>ݧ¢ýñXËuq2î@~§¢60Ú ûÝûY={/Œ/€X´¢]ªùÙœW·âaU¾#6ï'þ.ÞZ) ª¾õGùûЕèQD¼åÓÿ×¢Ç`ˆ¯GO¨*TÑOÙêÀi›§í3ª¸=Ê~Ö~æ±²u( CQ?+ 7£¬€ÜŠžCkߎö‚ÃÑóàHú¥¸½Þ^ïEûÀÑèe[©ý0þzæX¹ºxÕ®¢ãÑk6_È}ó{V>¤7j\Gœ©è ø(zœŽ3Ñ›j¨ýÓw¬•º˜J¾ d.Ê?tœò•kÅ(ým«PÏ£:«µ ÑaÄ{A6/£|—¿µ·ã­]¤Ç‰{vY¥\¯åqq\¯Ì8®×ЏmV’ÈŽÛ æÆÕ€ùqÕ|20ŽOÅ­ŒãSq«âFY>ãx7VwŸ%3n ,{–Ńåqàê¸I°"î¡jé)&Ñ£XsL«Î›±Y +Ä(/×ÅÚ8“•³.Ž˺>ŽÏylˆãsUqU O…ðk³¶IØ;ÍÙ¦#¬ÍÃí†åS¸ÝˆLО±Û–Ïcî7hÝùí,ƽ×è%ž÷_£/RªŸqô¶LcÛH"¥;xv7‘2S£‰ô«âë´ ÏG¦“¾\…O¤L5‘H+8ÔÃDÊrLÝx7ßSÍÓÔZ̼½ãþí"™Íñf)‡ã=N¤\Žw%‘NbwO|ÝÎu ’yl6‘ò9Ø|"p°g‰4Nr%?ZH¤Uü¨%L…ü(5‰B!Çô‹õ_ûB‘cËr­ØqôÕ kTh%+#‰J9Ö²$*ãX™ITÎåÍJ¢ÕŽi9ITᘦ‘—D•Žé1 ’hczUI´Ö1-£(‰Ö9¦Ï(I¢õŽé7Ê’hƒcŒÕITå˜A£2‰6:fÈX›D›3l¬O¢ÍŽ1ª’h‹cÚÆ¦$ªvLÇØ’D[Ó5¶&Ñ6ÇŒ5ITã˜qÆŽ$Ú;“h‡cÆõITë˜0v'ÑNÇ|ÕhL¢:Ç|ÍØ“DõŽ™`ìM¢]޹ÈhI¢ÝŽùAc¯F Žù!£=‰óÃFG59æGŒýI´Ç1ƒIÔì˜IÆ¡$Ú똋ÃIÔâ˜ÉÆÑ$juÌãxµ9æãdµ;æëÆé$Úç˜5z’¨Ã1?fœK¢NÇü¸q>‰ö;æ'Œ‹ItÀ1?iô%ÑAÇ|ÃèO¢.Çü”q5‰9æ›Æ@u;æRc0‰;æOCItÄ1?ý€uyÛ¬ÔŽ9¶gvÜŸù4tyó';hXN¢÷6h›4:Å6ŠÊhtš­c(¿Æ·ÖœÕÌ3tNëql½W;ëØÆyíœ#è5èøB#èøB^pĬ¦_äˆÓIt‰;~&‰ú¸ãŸ$Ñeîø¹$z…[Ê~õ4‰®p¨çIt•CÍÇS´:I×ðÔË}´JqÛì‡%߉?GÅ:  0%:„w“n]‡}³>ˆ‚mÑo `Õú*»U¿‰ÊnÓo±¹ò6òÁš7ŒlMŽ ,píÐùî‚}º8«ûïp²Ó].PîbºÇÊ_L£\ì•‹é>×ÂÅ4Æãµx1=àñZº˜Æy¼–/¦ ¯D“®^l#L¿WÜÐÅm]Ÿâ„ÆÓ#N¸+ž¦9áCñ4à wÇÓ¤Î?fÏ5´Ç¨GžñõÈ7Öb£!vžY޽V§9Žý,žæ9öóxzʱ§<ôŒ‹µOϹX/âi‹õ2žöâ„!ÎbÀw zÁ­”S†È0E)_¢ëÈïOuMÍ‹†)½¢ÌüÀn%e·U@6r[²‰Û**1ž G—Φ'!•ç‰AíE(Œi ©cHû¯Äˆö;ñ:à|@b<W%†sÈyMb4‡‰ÁqIŒeÛù ÄPvÄHvI ä¨cIŒã8çÃÃøç#2³j¹™ášñŸ•&-sÑ*µ‹©Ê5&-‡k‘.±Ñ?eZ™p H+P3) UCÒÙ.ê(s\®ƒ™ë¢†™ç¢¦™ï¢ñ²ÀE¢rÐŒ[É)hr§ e!§Eœ‚!‹9…¨,átYÊ)ÄÉ2NáYÎ)˜rµ«Z¡ÂU­Pé¢^“k\´B‚\ëš!×c®sͰ›$×»fÄ],7¸¦í&Ë*­`Ê.Za‘Ü䢤Üì¢ò¡ùÊ®òéÅTb=‹i+Êeœ[LÛP0ãübªAÉŒ‹‹i;Šfô-¦(›Ñ¿˜jQ8ãêbÚ‰Ò‹©Å3S=ÊgÜXL»P@ãæbÚ›j@áÅÔˆ2#‹© …4ZiJi´%R3ŠiŒ.¦½(§ñðjAA©W¨%5ÆS›‹ùtr1M›bÎÔÚQjW3÷¹jD-˜"Ó#ò=ÿ§LTx´®ïôbêäú>^L<Ú~öš]LØkMà»ddé/øQï«ôR€dJâÑ©PZ•@ûX|d>ç¥Gm™éˈÚú _Ž:X¾Õ'úÄq-‹b¸/‘=>¹6ãf2eF‘ÚídZÁ© Ï}F?º›LÙüh4™røÑX2årFãÉ”EëMbø´|:•Lteð‰IŸ˜ó™+Q†yß*”ᩯ0jÏ|EQ5kGÕØ/‰ª±ÿ§—r稌“èM rÎí|­æÜ.$PŽ_Vpþ8ªä k>Hk8ȳdÊ÷˵\¡\åub}”× l¸Öûi °Á¿É¯Uqä´ÚÈ‘3R¨Æ¯mŠ*-x3|\¿yÈ/ŽøÅI¿8çÿ? 3àçˆwýÚ¸"…ª9`v ûi+{å¦Ð”_<ó‹Ô‰+ˆuq0`mÃÃEš¬AðE¹ÉBRvpª«R¨–´(…vF1KR¨.ŠáX–BõQ ÇǯЮ(«š Ó×vs&•)ÔÀù®M¡F.àúj⤪Rh'µ)…š9©-)¬yŒêÚËImK¡Nj{ µF1²kS¨-ŠY¶.…Ú£˜ew¥Ð¾(fÙ†êˆb–mBü(fÙæÚÅ,Û’B¢<˦ÐÁ(fÙ})ÔÅ,Û™B‡¢˜e¤Pw³lW Žb–íN¡#Qh­3¯ÒÑ(´Öǯұ(´ÖLBk=žBg¢/ ®´QžOª~ ˆ»1ÐOqmç_¥û<ä!ϧÕO¡3\Û3)üôæ|0)7(ßn™³H™Ãö¦PAÐwŽ“Y¥^~t1…Î󣾺ÀÉô§ÐEn´«)t‰m …ú¸ýSè2Í}]ö£ÍÜÊ+h27`é*åÉŠ ]Ã(« ® jœÅH ]ç,î¦Ð¶ ƆæÓ x Þàç£)4ÄÏÇRè&a<…nq ÕÝæ"@«æ"@«á"@«»Ãý­î.÷´º{ÜoÐêF¹ß ÕÝç~#ãn›L¡ì¨‰õ!Q;C|V 1¤=@9›Bã(«Ú!s‚‹ó(…&¹83hH.ÎC¢).Îl =ââôFhš‹ó4…N„ÌŽÒ÷=æ( )ô„£¼L¡YŽ’¶„æ8JÆšç(Ë—ÐéïýŸóÖµ¸Òž¢„·CÏ0a ‡î†Äƒx¢>আÅò°È ‹Â°ùœ‹0ôZà"ä,¡œRîzÉ)å/¡Ô8aåJ‹C —PU˜ÒãL¾¥Ç[Maþ’w0¬gÀo‘!—ÅA?Ž}>dñ23ÎÔ%Êþ°|Äk?ÖüxnT,á5_òš-ÌÿÖe$,ÆÂü•èeX”G( ik–кe³uÝÚ5±;âÉa K(—Ú¸„ò“±y å#+£z pqŸ¼F+¹¸³¯Ñª8ôyö‡©5¢"ªóIY§ôbDtÞ%qB_Füß-"âVDÜÈÒ8[Þ‹”!´û)YŽÐŸãñ0âÙ(9Yçè"qŽ1©ŒsÌ™È.SÓZËejF¹¹L-Kh6b¬Sô†85AWÅ© zcœR+7Å)µr¥-Šl±Z½ÔÛb{Þ³üÒ s mæÄö/¡ %Wj¾6x¾ÞÂlŒ£j®`×Úfÿ;êVŽÚ­’Ð9‰mÜ6G–Ð[4ÛÞTs¯½\Ob £1`ìDu£9ÁØ'<¿ ;c‹ó¶è³Å5[ÛÍU?»„¸ê½KhÐF™xµ]BMìuq íáRô-¡f.EÿÚË¥¸º„îÙò°…ƒ,ù±F8f‹)[oEÙmq¶>m·Ç¡zö¾8Û|lÏÙ"Û«QìÈÿ­±tpf·ÐZŽØéh\”á%´éoŠQGOeŸØhÖx4àðwßíÓŽxæÈƒjt uq¨±%t¡>/^8ÔÍ£, ¯Åa¦É8ìäìsµë\¤j‡¹º+^‡²H7ØkÄE»Š®xâêCì±cÝä0¹¯Ó-n¸ü×Y›ÓY›ƒöÒeQý6ËÍGå0WÃ#\%òªá¾‰µYÔGEs”îrjůcÅ£{l-}‹²µüu:}Qq#*Æ¢b2*žDų¨H‹ ßççç¢4Æe¨|pÖ¾Nã<² yNðÈZÿ:M²hT½NY46½NSh(cËëô-elE™ÑTFÍë4ƒ¶bMõ1ËØñ:=Ak±Æ:‹æ2ÎÅÑÚ˨{–ÅÑ|œ x±&N”k>zK"D;Hô‡¡}’¾£ ùiúgô/P+¼Œ_ æ¯ÐWtáùmÚ‡7¨¦•ItKÓ…/—èãºð—ý.kˆÞÔEp+Ñ7uª%šÓt ·=GØÈA¢l©“}‚( i8g‰6’Nî%¢Ëx ª†Ü¢˜¯< úâ'‰í3D0_ÍÐèsºx­T£n©‹„u]„¹h£F—ðøƒ }J§íѨ‰ø˜Fº.>Ò£ÑB%>ÑèKºHZÐè÷t±8]ÒÇt‘¼BÒïè”R-i©.–4HJCö¯·Hú[>Ú%i œë—4¦ëôñAIŸÔÅ'¦%}UŸLÓi£¡‹7²uz[Ÿ*Ò© Î7ËtÚkè´t£N_×ÅOlשÞŸ®×釺øL»Noèâ'{t:ßÏêô]üÔ-†áüÜ„N (ùç_è4÷r zó‹ë Šêâ§« ú°N?SkÐZSouô}¾tÜ 4áÏž6ž?wÍ *”ùçG ²uñ áDåßN7étñ‹ùXîM~©Ô¤|„úr…I©]üò“~_§¯l3éƒ:ýÊA“²àû«'Mª…ùk×MJÒůOšÔ ço<2éˆG§ßœ5éÛºø­ç&€÷W—{è̯åyè×tñÛ«=Ôˆº|}½‡úáý;Õú„.¾Qï¡ xÿn³‡>£‹ßëòÐ÷túý=C ?¸â¡,¯.þ𞇠aþÑCUyuúãý†NßÌôÒ7tú“b/íÂÓ?Ýå¥6˜Öè¥ÔæÏ;¼t¡ÿ‗†`þåa/Ý„ùW'¼”¨‹¿îñÒŸéô7W½t±þöº—âé·ny)%ú»{^š†ÿß?ðÒøÿÃKlã`~;×¢:¤þEZ:ýÓj‹®`\}§Ú¢2Kÿ\kÑ&ø·Õ¢¤ó/ÝxŽxÿzÌ¢VøïœEí÷ýkÅéâßnYT`?±è4¼ÿý¹EßÕŤûh¡ÿ3ÛG÷`þW¥~Wÿ]í£Çpþ¿>JóéâŽù¨æÏøh-ÌTºà£ßÒ1jû|´Õ§c+9â£J „ šðQ'‚,£Yý¬.–Ó‚Î H&eûi7а‚òüˆ§C$ËüØ»é”MëüTŠG9´ÑO÷á“KÛüôSºÈ£.?õ ZùtØOíR@'üÔÅJ:ë§•~]¬¢k~Ú…'…tËO¨SÝñcÿ§‹bzàGÚº(¡‡~j†¥”žúé˺(£ÿÏÙ{ÀÇUãoö½kª§“tG3H‡â;™ !&Bd[I¸„„`wß“„‚ìŠ\äÞ{·Ü{ï½7ÜÞlÉ÷nk…mlÜôŸÙ÷Þélà÷ÿþ~ŸÊîìììììììl}õ©0=U¡0 ~ªHÃ`HVB‘†Ã¨4XŽ)#`MDi$lOƒý»Òà8ö¦ÁpÄûÓà2BÆÂ—iPJ8×y\LƒÛµiPž¦À¸‘Òi"tJ‡R Otè€ÉÐ;†b` ôK‡a˜ ÃÒa8fš£Òa<¦ÃätøXðM:,ÀÊ΄;éð fôÌ`·e6tMWØ–ÝQ>sat N§ž=%ó)Ò|˜‘¿S¤0'& ÊBØ”Á>Q¤Å0c‹`k,Á K`{,ÅÀRØ“Ë0iÔdÀZ ,‡°“VÀ± X•p:¶"d\È€mY ×2à3ÖÀÍ xK‘ÖB}ìEŒuÐ9ö#Æzè™ š‡ Ð/ŽcÒF› iÌÊ„›ˆ²ægBE†"me™V¤­°&~©HÛ &úcÂp ¦f(°ŽeÂ4„쀓™ØJŠ´ÎgÂB„ì‚K™0!»án&¬BˆCœ°!1å„ Äaœ!™*˜â„¨5{`ŽU¤½°Ä ¯*R5àôc v†8è„;HdsBE¦"í‡ÓNl#E:X)B­TÁ×NŒ€ÃÐ' † îèŸý°¾„¡Y0 : £³`!*û1˜… ªHÇarÌÅ\'`ZÌÃÀIX˜…¢P¤S°. V"ä4ìÈ‚wé IJ`2jÂYØ›'‘Þ98»÷<΂8.À™,X†„/Âù,8„¹/ςøŒ/GœZèæ‚àÐ×W0P\¨Šô saOTà ÌpÁLº g]Ð “®ÁW.ð)Ò×pÓ \‡;.˜…Ð=f;é˜ •hjnÂÄlXI·`z6 GÈm˜“ ;r–eÃnD¾ «³ACH=lΆа½Ù°˜ìx6ŒÄ";²3Ùð Zv!历]C_ óT°Ù(o41ìn6N ÐİÁ9hp©›–ý²ÐİY9hy©[˜³pŒêÉÖäÀ¿Ñİ 9hx©7Ûš~´0lo¼£@_v$þ¬@?v>vcŽþìrìGbص8„8[„¿¢aå¹pQ³N¹(t†°¹è­£…aãrÑ4¡‰a8mP,²öT ñV‹5«nŽ·ÒžªE&µâ¿òµ”$Æ0!> „õnéþW-ÜÀ?ÄÿëðÿGH@&¼^0û QúS`="+TZ6!7‘ÇŸHI–DÒ|3i>ð…”du(ë_(i=&åUÔˆÔõP ûò`=ð©³äìW$T£š<¶øf HE ß ¡›¹|„à_@äµ—‹oß¿;Aã» ÆwC× ^ü€-x3ø*Òs€ÊWSc`b•´½—ý¶Á(j(Ú±Lq>„=¢ zgUS]x%eš} ;»Q›*rÖ¡úz»b—ù49’8(r€ZáNPÖ`7ãÓAkRƒ°µeJU©RrDöøD…È$m˜¥7ÅYâsÁ¹F’´§âOýIjRÓä©'ÚšçÐ.à ”)·©s]mØ vu§3´Ö‘*ˆˆRƒ»€5BòKÀùƒ˜– Ë ’)¬ø6…Õà|Þ ÀL k…u…yÉÖ›Â&h!O†‹ì ëæîî¦Ð"¹‡»§]—{¹{»•>n R¥¾n‰Y¤~nIn&õwKŠGʱáÐ3T&¥Û.ìé’Li;8e8fh›fþ.dy|‘h¾˜ÅŠŸ°ŠÆYF¤= ú?'Òk˜¡²k_Ç4¾ž™&¦j·}KG64¶›4¶3¾iì2hÌOÐØým1¢ñ iü„hÔ˜4jß44Vº4’T"•ðƒLä=Ly¢±ÇQÊýFh¸;iìg8öo-þ">œpäKsXøVVÁ»Ñ[8Þ~™sYø6 ¸·©9!ÏèŸu;|¼9aOΖšóWhØ}‡ý3À‹h¬¹ ¼ýçÀ[ÒÿZ@·ÿ×/ÖBÍŠ›IÑ‹À-Ƴ[úxvøo4õ‚9œÖ‡³`ÌPSzü·ÈA#ò3ˆƒ?á8úަž%§âQâ«)Aÿ‡øb•þÝXô,ðR-–—.I1u7Ö?ýAŠž^†ôKÐk‹ô>ÔÔ3D//ý'Bÿ­©çšO^úƒýÜ(ås¶cÑs€C5óR6'!ôB;G¾¼zž2>N&x0rö>²ž§µõl ÏQÆRÖq@âPG¸1÷(÷Ó”4ÑÌ=ød+áæS!V ¥Ó¨3]EIT'ZLT—br1äKÀ7|Â/ÜŸ€k#üÁ Ùšz›QÂaá6ìE>vú¤Ã8¦úÛâŸéS™þhšzÔÕv*jŽ Íoç¤/ °iÂ)½‚#±u9ŒûÁY›Qß ¯a=ÎTÐ.ŽBŒZ—Œm ŽÇ\&º%t‘NJw.93iß,뢨bp4ŽüEu!r;+#ULƒnui‡£cY+§ŒýÝé˜ä|¨cÝ•&Ú¬ÿ§mà òž>`íÜ/ÐH}Mœ˜EÍr‰‹Y휨Œ&%L™Ð.Šùop˜¢ñ9F>Bµ>>×Èr#Ôü¬<¶Ÿe=SÇXY%޳ÙÒ8g‘š04³€Z¦‹i º0'Íи ©Œw£ÏjÇFÔÔ£`z«½Ešpû2ç{„ÞŸ%”gsþƧ bvcb|š€ãS9—ª.LŒO4îô°E‰ñÉw˜èg Çåõõì³úú)õõÂy{‚Tú%bzˆÉôDBݢ醱¢‰npe"ý ®œvòðЪŸD«^Idæä ý84)ÙÀÉhà>$8Ù·2Të,*èh¾ôyøÙ³;dÏždÌj˯«ññ§ {ö4ÿ©küYÃR]Þ `µeâ/°_üRS¿¦nñ”"ÛÒ61ÿÊìû|Ò¯ŒNá'ð“7MФ ‰{X¿Þ"º‚Nv“ý^S¯ íúùŠ‘ÎÜÉÊHÁ*ÿ‘âB;[ëÊÉø[z@æo´oP †tÇØ ¦¨SHG“ ‘+;ÇE7ñ`¢oRB;ƒèŠ®Ò  ~rGaóEµîý(» .‡AÄPqf ¢Šó,§ç~ ÿ(¡à·€''±B¿•©B¿§¡~gKÓÑÌ–f ùˆôcFkýá‘CÐ^ŸŒaHÝ`|íTæÎÀviŠzaÁI'¡ÚH¦Z|ˆ?­•F¨Q M5Ÿ&ÍxœÚþX¾tÂw³gŠÞÅ¡ïx>Ü…p}VàüCÑzÒ•Ÿ0Ùjó×1ƾץæµÐ)šó—i|mùm@íˆGoñŠ*nûœð_Óž*ªóÊÃ5ø[¦ÔÂÅ\é5þ[—ަŖ9é€*Î_êKûjªOþ#ÿC,^´Þ˜“´à6T©ìE}­@dø›8=ÍÆîÆß¢¤R%ØË üõõ,S×:rbc…glV[Úl…øxŸt´L¡Êúä÷iŽ—ÓÖB ÔÖJ‘r[ý·µ‹‰_ˆ“Wµ•Å ÈûÄ7àß™.ö>ÿ  øP¥ÿJÍœ—ý7Të4 }àz&¿¼½n1ÕCÉUof­´B$§+•ÉÿŽ –¼72ÿdªHp…•ñ-#%¸Ñü¿:Ÿä;p°Õ­º|ÚÚy'ÙórȺU@h¦»x&êïD”’‚=­‚ÎÖµ¤ÚV SŽÒšF¾°aâ#7ä®B8ŠcÜF8%ßȼ·“KnÊ8¸‡6€¾NÜ€^W? I§öT©BJ^fѵ| ¢5n«4²[œ¿DÞ†2NÑ3ŽœÙ†ÄùläAõË\>|8I%@÷óÓ|¤øA…|Ta §ètqЧNê"Ú3¿ƒö,öl¢=Ç =éÎZ%Ôi/I¢®B øè$»ÀfºÇXí³°3*Òl쌹Ò¨;-m.öFæ¹%KŽ4ß-Y]Ò·d»!K Ý’=,=«(¶´Z [šXc8탥´ÆPÞ”TN,+`/XJ3XÒ$ÆWšÒ¿›U´m¿ «³Ê„¨‹Ýd¢p›WQ&j - PSÝhBX« áCÄYAnˆ¡^'FŠ¶Ñ„ ±HÓ®åMi˜B×Y"¦øJ™@èvË»‘Á™ê8ùe,wp:ï›ÇÓÄø”PÅ–°4¨2`”x¤%nº"°ef‘– ‘-G‘5•š1Åjë.äsV8t}ÒY”Ç%þ©…Ë>ÆiÞË›Ñ$‹†í˜Xdšá¢ú__KšêOÑÔ[P46Ê=Õèµ ¦ÇjøU4+ÜqüÓ$ë1Z«º–€ÌhâJ'È×Y‰•î¹Ø£ž#{Y€öYz&´*1޾€?­-d0— vÉbþŒŒp6±}"_ árWàbn´Ü…IÏ˲ÍþH÷ñ'u ù¤°Oò§´X¼ã?FœŸ3fàx‘úLoÐWæ¦eèKsMi\NîJhž_ä¿kÍ_ 4¢æ½ù‹„A‘æIVáz–àò—m¥ÞÅ‚F‡ö1¶æÐ>Æ—Vöo+¦*j¡‚â)º›ñ¿¡û¹½i­*º…ñOã‘ÆêíMÌD§lGñ;Ÿ¤ÇÛSü.ÆÇëñ¿S¼ã³õøg/ÏÕÔ‰züï€ñizü_ñˆ_=‡ñYzü¿UŸÀŸ Ç?§8áO×ãå@*`3÷7h¨³K,­dB·V2ch¬ŽÔYÀÄLµ hÆŠÐ|flx ˜Þ IÜÃ$¥æúÈ@ ýˆXô †:ˆ(¤é›“P†‘JŽ@’_PÓ½™€O"ø„o xk"ùÁ§›$§zWšº‘ÑŠÞ” ÎaàÄéyQ=S·}Å=SAÖw[ßJN,¼¬&ÂJÀW|• ˆð·uXk¸h§6ÝÈЙA’ï$²î ¬»0ëBÊJd™YcÀ«(ëB¦oĆeDù¡ì(×ÜÒ>àb¹œ°ÓÀv£›ÍËN¡ ÝB††O–¤X¹'ØÕFK6HꨓÝd¢eìú¤[hA¯ÿ²Z¸ãcƒí”’Ïiún)Jç®!NLË{mÞE,Ëve¡4Þ‰VåÝ™÷`¾ÀVïi¬4ê}sÞ`Åiºo:…*åâJY*¯Dã?ˆ Í//¨áƒY¼*Xƒþ¦Uça#™9“¥žÏ ÇØ(¦ÔGÐr32Z^öE«¯dßUot¼b’úÿ`'¬üx&ªÄ2‹±J™ÊŽ&eCt-ã“ÀZV ¥ùÈ1ÇÈQ¤F.ì4¦QD=dG4§ƒv†-†‘…F„/ÑéË™äª.Óé3ƒþaw•àü0ãk‰óc´ Q°m?¦öØ,–R:ú%´[‘Üvwd‡[ÝéÎ)ÀÌ»i'¹›%8eÓÃ1µ½–]îà &;› NU"Ónw€{2 `üµÁHá•\BZÕ¨èc¢è™HÈÕ†‚K³!ú9H»½ü"ŠCcz[d·¢õ6 aÑúGšR% „:ÖUŒR*øu³­nèmùµÞ–ßC0pÛÄb§ÔìœìtÄ‘‚w–Eû:³ÄR˜¬©Ëm+8œeXL™xÚË»ÉD÷jnÌXѢݕîö•±ÊÕCÀê K¬rÉb•K¶ÃÃ8ƒ”G××ë?4ì- žoè<÷•…£Åµþ2iþ5 ¬kþ ÙÇËBó‡ÈúzÚýš?RÖ^£]‘Q2ÖµLF[Мª:Žª:‰DÎ5×ùHºs]¹Èø$YÓÚ9È* >.z„ñˆ„lÇ»d;y²a;æÉ|æAéDcŒ/”ÑŒhŒ/¢RÛȲÕöa/ØÝüÒ¹ºûa‰Ì—!Í=,‹ÔfÖ\sGò¯HÑ=Œ¯–ã¡Z+Pb´ÈEä8mÇn¦T9Íj«H¥¶ÊÆ¢I~M^yA™â/³ä•ï`eVñ×&þÚ ¤2þ¦ä•¯²•¥ †¶ÊbAe»Ìw ꮓòË´º«+=ü,†8Órå¸Ì÷œ8uóü¾W®Š©Ëm%Ëm¼F6,K™Â÷ÉU¥Š°-ûI0ûY©‚]µ2ºŸñ2zSÂÚì–׳8£…²!Øü‡d-*ÿ%q›#óoÈÈ1Yo›ÌwiîrÁ¥œù ™ ¥µlM=Ä*Û•YøI¹ÔBˆ”³2£€Ñ•麮Lgd­qtãgvO#éž'æ3½ó`Ÿ¹,ãTñ bl#Œ"ĸf”ž–ƒ‘ëØ²Éå’m¼iÒ#„Û÷#dÎgQ};(±È¶ÀÕ•±“¢©»˜ëïT›ž~K…Â+”ÐV¼ƒI¢±x¥ÔjÊ´+†11V´ƒzÀYrÀÉ»!‰©ZnÉ~'ïnÄæ–tòžŠÐ¢L¨ÑvÆ{aaÛY©UèKo{÷.Æû)÷0IµÍü^~ëp…PÈ‚lc| ò­ÚðAŠ!Z2¢hTyÃðä:Øø¥ÔfÖa$†‰ 14•…°†JŒ6b‡D%Æê<ÛÏRÃýB {ûm“>E$ ý#}æÓ”R;R¥ü5¹Æ\!‡dî ×[$é>~ûL¥úú³>S‘–ÛÆ}Ræà³ˆÄaç'e)|vCpŽRšRêGÁ¹-M)9ìäó0dTLôÇÅ q¾TièË(‡Þ–+÷õ€ŠÙ&(¢l=àaì«ìØnk“H­Sb¥õ÷SÚ ´Q1º ­xlV·ä[]á·)¾–‚Õ]BpÂt8Gc<†J™¿ÀõS îI*no¢¸êû‹«1‹s†0Ó~̿ʶÀõ;’o?ÊA… ®Â´ðCJiªºÑæ¢/“ 8š(àØýOÔç4UáBR®‹‰\—îÏu9‘«Î”‚Še^ÁÈRÝÂ[……ßÅÚ»èxÀ £|£|ËŠÜTÈŠ,Õí¾0%B wˆ›Ž] ,(P‚v³ ´—ím¡Ùì{4ý8,¦Ã,Âûkp’# ³ðr\³~F=­¿V[ja€Ÿ­±ðQ–-ÉóñtlÈCæ--ø: 9Öè¾I-Š‘~X— ²IÛDdà'Õü -}þƒÚÕðí"s•p&wšd…?³hq™O‡"%M]Ä¦Çøa½¨DÚG¾ö—mr‚Û’Õ}wN“,]ΛØá!Ói³’'Qû}¤¸AŠ<Ÿ: -òK–øÚ&ŸTO¹°G\±Ä×Uók×ü–©F”ò:á¶ÜRFôKwP¢ƒüpÇÂë-q4QÔF¬y-ygkÜÕˆ<«¦îfj ]¸¸»2.º!­@óÞ÷$¢Ü)µ/eh¦¸ž'Uêgƒ­|°5n@Ç}RÇX«°qhf\¤ÝÍ­ V¹e>RhÉLjÿRÉÝ\^i¡¾ü™jR%j2ÁJÇH ªka˜_š`¥á&á¿á~6ÙÊ'[ ¤OkøTkŒ„̧c´%Ÿ…ôª™«s¬è–ìqó¹VòޱW̉±Æš:’GÈ2Ÿo­¢~S‰d`Ú>–E5\l­jÉWXŽVÍWŠlñàpø*+Z£jæ¤æYoQò6kUœúÙn5}Ôë¹Ù¤Z;­ØHÔ 5¤)Iï+™VÛ 7խʨ[^ù{èšeþã· Â1b¬ß: ÿUúm#~ÒŠ3Îø)«ó| º±‘6r«é×ò:«ó]µ:ÿ‚ÊúVâ¦ÆXY¿dÕÝÜÒ ÃÏ}†Üp«îç@³ÀZ«îèÀo{ºAO·g}½þƒ~ÝŠ6hzéI*qÓJSl±Õ|ÛªÑäˆFár›pc.ènL›3kÂ{ØD§ci4 é…‘Ård¯ûGšºD.ªv3ÑóûèYkEVgc„ L`fÞƒ98“³9W8°‘6ÍE3A̶†¹ú’úO}Ð>¥?Þï˜lãc0a 3»‡˜ îfåÓ›¯èdÒŒµ¡bŒA:ãm!O±G¢¦æl¥rÛ7æ”Ô¸ùDŒ¡ï^²ÏÍ'ÛBùÅù©Ÿb+M tÁaø¬ä¤Oµi¥)ÁHi:²]ÃøLñK:ã³lNFŒÏC¶â,‹j¼àÅáR[h¿;rÀ­t÷£Û±B' ¦6­±ÂZ*•iÝ=E®·9ûÚ±È/lä5-eÎß’Bí¶éäµÂÚUØj>×lÎy”Ze¤bJPÊ›s(¥TÛhâ?ÙO:X)fÿÎÏioÅf(åN›® ¥ü ìx±A)ISc6½AJIš@n¿}â-ãáÿÔ×+¿¬¯ÇŸ2ñƒq~ÀV%ñÒD©J=D'|]·Ü!’È ÆOبGQŠXº>e =WüœDýœŸÆSй¥è:æ|•ªxQ_.¾K6ç,Ñ)uèW:´ÎÇ!Ž©÷‹ã¬)Žóß%Ž ß%ŽËß%ŽÚÿ8~W_?;#€S{DrX¡¹ã%$ùMRÝošuGƒpÆWF¿4„P¯W÷¢^Ýr».„NvMgH@;Ûu!t±“¦Ý/„[¦î|—î~—:Ø¿CíÿOBx›ìŽýÓ·zÛÞßÇžóùkõ¿ºVŸûuý?¿®úzýäëõwnÒÏS·êÿp«þŸ·ê3o×ÿçNýõ;õ}îÖc>ÏÓ¤¿$v98híq–_Zàà‹zG]L(Ðòä+„²Ôa*\ê ×–;ør‡a{qV€ ®›ÞuŒNžNˆ®g|QÂá5Qj+3›íÍZ˜í—báó;"_º#«\‘£úþù¹:×9¦Cö m7!5ŽÈf†@u…-rÜìlc|‘ÿ+‘­æù¥‚ü¡o‘?ü-òG¾Eþ¨#4•§¢ëŒ¨~(Ë6Çe1ýZë0OÌ÷ÃZx]?Aàùž(«µCÔæmŤr€bg0¶c¡×ÅÞÿÙôâ×(ò ãŒ×¹t"Í7:Dì|º‹¦›âÁ ·zÒ]rÊ-¦Ä_$`§ Æwêqª{â¨Á.FµO(حèþ Øq¬¶åŒ[‚ÆÒ—n‰½.wK²G:*N§ >"µy”ø?iêÄI?íÐbê…tôpùÝßXçL¬s~¡ë"a}LXÏÖeë2:{„u&=º˜ñ: žN.aü+²‹iÖ]ÄøÊþ‰³×ˆö¹fæ¿æà×´ —µŒü-GL]“ŠcƒM?¬ËòŒ%ÀÐDœÈÇlt&vˆ˜RÝ¢’b6Ú#¹ëÐBËYñr&E—á+…Æ…ÈÔ³nM­d‰ûUt8‰YSÇ5À;êpµ¦Ni€wÒáúE$xEJòFL—ì4UŒwKÁú} fí‘bT¯G ï•¢ íM(í`ôоˆÂ¤ÐFÈÀ”P”¢o„ Nññ!)b#dh ‹ÅFH­§a#dQjO»^>¢4Ê,lT “‚b¹˜S/áïåôàL&ó±„þ÷ú8}\ Ÿðè ý3ÚJz“Ð'›è“Sø´”ä1dº`~1?Ó`~2?[g~Ž`~Ù·˜ŸOäÿ¡X¬¶ÿù…‚üÂG¥…)µ°èQ ‹e SøŠ”*m5®J‰,·»~Ž¡5Š©'íbíYœR¡+KëܤLI¤àO©£ýÉ—¡Ð®8éñ¬m盌o#&þI»w?&&¶›uÜžÂw’HNÙ"ƒ kô(öDªdÃ9¥Ý”ñ_$œVÂ@˜¤ðÃBGH_â8Šâ8¦‹ãø÷´å)"øï4$8\tŒ3)Æ.Ô™~.%&Ö;©3Äh m–Xº£½ôìßÑúr]ÍøeÒCœ@× &81Qg0ñ2qEgâª`b…±³XŠÃ=íº~á~C6ø»ù·R’wóï‡ÿ¡•ÐŽ‚Ãúcîš[ªÇÖª÷A‡TÞ!µ ¾šwJ%ŠyÙÍõS½¬"•W {Yã|œ\Ñ®©1J®Âsh§³{jÕ'èm¥ ¿¯"u½\EÉ´xCÿ±oj¼ ^¬DõO5– ¦"+ÿ%#ôq28•d5-WœÊG¤j±×ΡÇ3Šp>'œ— gLªÑBcRyeª8Ç_ã&)ÌÍAÓ’v¯'Üøñ©Zpö׉D¨¨Ã¾!:RâS±‚ǘëEZ´KêŸJêŸj¨*ªª®þ©TÈêomb.HÕ7lõ`;Dú O—râOk”(dN§d:“y‰ªsNJU¸ó£®Z¸”?wq.çG»`´6Ÿµ wux~´+Fëòå?„»¹_åG»Ñ™šN`ÅÎ÷óºå~6NN…ÅÉ©°89…OäÈa¡ÓR(UÔa¬²Tieá¥tnê$—†:ƒ~‰·†NÒnjX€Æ·CðßCÇYÒÁ§“¬ø8S­‹¨÷ãXoDüAè‚yä©%þ´N¡jg”DÕî ¯ týºó ?ÿ ’ÒÑ'ºÕèöSÁKŒ3•%¼¬ážøÐ†{â’ÔC¼Uà!äOyüƒÒ'¼]L¬ ¶Gb=Á¼S¿]L¾S‘Ь5!8qÖKp£sÖȘDëVúùˆèé<éGüÇZè"+¾ˆãÒÆŸÖbåMôéeèvZñí4©¼Iô<ã?ÕTüûŒ~kòYM=£Ÿëù™?¯ßÖû¹¦žÕÁ/Q•éèVÐÝA,ð—F•É[P¦Xðv•–-è+áŠLÊ»RˆKÔô7Ôm!ˆ¢S/`Ͽ䮨æ¿çeÓÿë1þûȰ45žÃÿÇ߈/»eÞZ ¾É]ÈßÖ©ŸFêï´ £»e{µÎ6’þZ÷ü—Jú<4ÊÊË!Rëæ ÂÝÅ£¬¬|”µšw†¸îàÕ¹EU* k¥#MH¬?8›í# ÝÐ/ë—¦Ÿwí‚rà=€.FFY» j½ ®Ž¶æe7ÆÙE_³ FPzäö©jGKãœ0Ölx½a0„žàC@éP “P>>\p:"_¹éð¹8 ¾Aœ7îBV‚.–<¬ŽÊ8ì+î¼’Z·sºN.6™®£…ú¥÷ÃvEæù¨,ô°”LÌäS¡*tŽ èƒ’I™|BÈ/9dç3!rE±7‡PÄñÿY&¬:§JæBä#V¸»ä’›/UZDUZ ºò,:nîãËD•–S•ŒÛ¶NšÒ¯ƒÐUw\cýõU7ê'ª@ :âB{¤M@Âß"èn%ºÛ Q}>ã± ¢»Sˆj—!ªõ®Ýy‰©×Ü4Ç @q:3E£"¢Ú³DË–˜Nù?”ûmÕ}r‡ðÉ+t—¼È''×Ü®ÿsèÿRõºѼŽ®1íOQE7QtES(ZÖp •‹äï#6*šÿY\<úÚ-ñ¿è·*ŒÚZxÛ6 nxXÄÔþC ©[­íiÁ€äkßÖÊ?n‘åq‹b¸PQtØÅ°*üSÌÚ.48n|`>RЧ³ò!émmüŸÔıãZ…"´+ŽbK¹ŽNýÒWèÔ[¥ZtêG§Þ"]A§¾¤nÉ Ò7nÉ6$]ºé–ìM¥:·äh*]uK)M¥AÂ:x©ö{Ìûæ{€WÃ=ÎL µÏ`PÄ DÝ/P/{¤ý@¬¿F_«“%¦vÆß–¢ëÙ2šî! Óš„n%¬cüiF¶[˜ÜôíœÓ= èÂÛ#uü8Ž`)},R)—¬™ŠL-ãï!ÒpÐß"Òßо¢©µ4ªŒà4w¤ƒ‰ï‘ 3à7B·“Ít:rñ#‚“™•d¦GrÙèçb ½’#½Ä_Ö"Ü®òìVty)ýš‰ËKcŒQ_Ã2«©×‰—±ÂÐÿ€À¢°•Iºa[TÇÄí/¬SãXð ú˜*©åµ&ìO ìOù¿4õk&ÚÓ´†æ4¾º—Çÿ£{|Sø¿1BTg)³õaCVËô‘„&–v¨Ç~& HAþšøoŒ˜ð­3¡_gB'­ü”p&›8“¸´gS¼å«L¼ø‹^gtú3¼F3”{"æ~ˆr/¹7ù¥ezîeÀWÊ$°1:¥…(ú³Xÿí€&„l šÖtß¿µÚ9›k@‡7}â¾-g¼ bÅ­õ‡ª‰Ðä„Ö!©f¡;‰Æþþ´Î ­ Qµ÷!½½§v¼n³Ÿ^`íí­ ÀË ÄÉáÆt[qâN¸~ Õ ˆÚø“11ç|JSo±xÎÝ5mAÓ”™ÍþCÊð¬Q¹gùs膒ˆ~ᬱ¸‰õbè óé*A÷ ªŠÕ‡UÁ|y Wó°&!üi)ÎÇß`”LÕ™™¤¾³€®žäÖmñ󷰱ߊ{ž—äÙ†ÆnIôž.ÔcçMø˜ÀíFnÏÿaj-‚òÑ)E'’Dýqåòó@9æÀ<ÍØ ÄiÆ.ôA9ûAÚo§SÀå2 Ϩ#]dºöì K¨ÈÑ\C;±èÄî®ÄÓ<ÁS3J¸÷FwŒeR¿`G¤,´¯«LÚì$ÓÁc¤<¿ò¢¼)w#Ê åÏ(a£Iy#аfV˜Úd›¨‰ØCÝTåTñ E¢Î»X/ꃂz¬ó⬛ÎY5qÖ9ÛGœu“éq°9;Dœ-ZÈ&.ê:ï—.¿Li‹À†\7¡4::ÌïPG͆ÈlPoeû|>’kñlÐ5ÿ.eYÜ@®‡8bºÍ/õ`¼÷\V$WHiÃ1d ängµ®DMŸxŒ¢K¨éïE|á—¦b§´e`Gj?¤´%DmYµ;Ä\ä®›d€õá}9åZž˜Â`¾`¨þÞžé$]¾Í(tyER×\ ú=¨í~ô“õ›Ç?F'„ŸÒÕ™?ƒH«DŸ|…š²lV »rágä ÷–Õ}rùóÕüùxä.3¯â¢kWr‡‘×Ü[Ž—ì“ù Hju©— 9¾$H½Œ@©Wâ1“ZÙÈ&Hý"AІ†5‚ÔÓDªÈb‘ Õ’·L"Õ*+©g¼8‘÷W˜w­èþ…(/Ìí»§ûßfôÛ:K€î2!ÐÖAâ†Ì•|éÙpwWàj~´;Î춧«á®ÀµühŒ~Ï^÷töçG{ÒDo=(‹õýº~ýí5œè}@/àßž¹ ÿîuÈø·W®‚{çZ> i õšÚ>@c£m†V2ÿŒ&~ƒdþº03Xæÿ¤ 3Cdþo4ždþ­*:PæÿÅ"7 FÒÍ,²)x„ºÎ5u€¬©ñw0þ‘‹»;ëF0^[ð‹g!h¤BDLØÔ0)asCÂ,J˜ƒ ƒ(aKCBâ^Á`JØÚ°p B0a›p £»óäÉ”{÷n\(ÿn@`’ÿÐpóf;¶¼b)¬Ûéç…$Òê ©‹þtRÝ'Pu‡Ê8~Ä£ÃdþC̱ôË:;ŠÃ:” ß teÆCàŸVêçüE=÷K˜mWC¶V˜íWš:Œ²í&žå‡gLxL×OëìFÑq@bWKb7&JùEÝ.?7¼wû¥ÇùˆQŸqcf´Ìý1q4¹‰Y’®^ΉŽ{ÆüIççD+.h=L´š-Í/5å?A«8Zvðÿ)âTbW,7m„ô,z¼ÌR •YÅy®gk¡ÊøwŸáß½~ù9 _ù®q™â%Kç%Ú*{Y‹E*eõ®«h¤Ìˆ¥Ô’—](Ñ#+Æå‡èX™Þ +—Z‚û¬ôì q[+¸§sPž2…ÿÚÙ‰â\7F˜êk‚ào‰à#4ç5hì·Ò‰ o·œ2Ñi8J$²‡){#Ú¬å`‰ðH©¥¨£Gú¤ÌêlMë\ªZe+µ¯²AtŒÌßs'èûZhCè& qî è_µP>óìCçR‚ýM yæ°%ÉY‰ü”–ZËlü݈Wí’]j3öáþ‚ mÔÃñÀ£êj‚˜¸uýgõ4A²³)‚>@P7¤Ðy*ÞA½L%±eXV»íáÒúz«·¾š‰Ÿ×ÄBÑÃ%ùÕ%ä÷ÉïŸÎ ´¿ø_lS¯Ú;{`B†Ÿ“ _þ…¦Ž¡6XhñÞÛY]fsÑ0ÜɯÉtÝÝ À -âÞ@…ôgˆJ¡÷dŒü‰rô(í"š-‚†ÞOi¤ 4œÙD 1Ü';Ag¼ CW£'št#IÔO&CÕ»”ö2´G'ûÕ™à\E ;G\Úç×7X§“s¨©£dlÕæzçK4ëǘöš®Ò‰v¥•Œ·õ K äÿÖÅžhÙgÄMM]p‰¶¥íɱ Wùÿк!lÝN·ë«n×{îÔ¿y·~ÕÝz[}=BùÏK•¬wn×ó…ûï‹Aô}úUïæ«ÜŒ/%‡e(Šbéd–CÃqÎå Žs.¾D¦{Îm®†¼–‰ ‰“™è{Ü€ÒÉÌ`žÌÜ|OùúÉÌ­‚@KaãGËúA€@'3÷‚ùè"²•êäÑ-gN£h #YÎê¤éj±ÒxÈУ]G›hAŸWÕg¨áÍ4uÙåýbvë!ðó†9ž¿€æ|‚Ì_Äl²µÄlèL¤l²ýÆÈö2Wщ²X×<æûUˆñX¨³àz<Ðoë\¤&%f G@‹°ûýü'XØ3Ä{3-Rá‰<-.Ì”ùsˆö¥1]@4ãE—ÄÓQá@{ÜÒà©%2‹ÎИc ÙÞÀlojêLÊvŒ‚ýÆÿ _*­…C~x·f?ÈþÌÛ¦¸È?[L”Õ¼ò§¤IïQ‚‘8Píâ)ºüéjþgqBöýx^¶‡,U\½`‹©çlqüWÏÛÆÓ¡Õ¿ÆªJ.Øhùy¦¬ß¢¡·dOÃ$xùœ†¡§«ká°_ú¼Žø¡ˆ­‰îdlШ§Q7ít·;N>­qþT\—¢Y%ØÑW±üLb·=i„IÄj¬hºÌ(cUÿOkªŒ:ä®Áî2@ÇJª–Ž+I'AÚwBæ“C2îCÄÊݹ`«Äœ§ÄzîS”s42 T5Móu’OÈ!ú¸1$3¡È”ñ´pÒk"«/Ô5¡G“Äok7yœ}„¼H™Î4xœSR¤¦á^®Àõüh/t1oäÃËáÞ®À7ùÑÞ½™Ï~îã ÜÊö!ó,(V‹µyÝ—Æ:{1Üß(÷Fû“. #’ª?A{ÔÏ_nA¦ÌôÚŽ&¦üžÖ4ŠÎ“ B塤@–É~^%dæBäc9¯õƒÑù²@º–ÔÉ¿6–Žûùo±z¯‹¥€ ´ð{L½ntRLÕß…U×RÝo4€]›uþF€3 ŒÝE Èë ~S˜‚·ÞÙœKwÞ51—nß„Æ $ñu Z èE¦y½>YîC“åÕ²þ”st½L#¸F–ô7ßnëÇ¿c`]Ò:ÀJs`¾°Ê\¸Ý@`¹I@ 11ª² °š,—éµO$°V¦;ÅÁ2=‡‚î3b$ _>á×/cÚ]1¿nLiÇH‡Nˆéú3‘gÔÊš]¯•‹ŸÑ'×' ½¾¤Nú±]ùW”VN³>[¥Ý!RõìÀzé¯7ú¥^Œ÷¡yuGFK>JE³ñ1Ì,{\ŽX(X…ëëc ¿3WÈŽÓ®U7Ï=óð‡¨ƒ?KI¤GYÃ4¼‚Yq.©;íÇAYØœ+=Q gð„þ²ÀèþÁœÐÑ{§ê¾h•Œ3€x4&ÓžVt—Œ£LH“ùO#—&F{X[d·ÊÅš¬DwËügXP&Ëvûgµ0IoÖÂ?¼E…¾z6Vô,”?K¯‘¨‹å¸ºDNû!6Û;áîžHwÁ*Kº{x(ÜÃéaÄ{xx8ÜÓÓ¸¤§G\N-½¹ÌD^¢#·¡D¦0{ÊZ R_2ß*»à—^úÖ[eô¬Îøcr$ž©ÎÍÍiƒ%üÎ|xìuóá±ßëˆohê.™h¾Ù¼ ãªÞ ƒóRm+ˆyŒ7Á:/Œ±Ž8À<:fÑ‚T˜Ð®-çû#z¦l§,Þ´¢V§m5`ôHÚ'´gÐRRzyèu°îz¬‡‡^ëé¡Çuº1ÆìöFBÄE=;ƒ.ÞHoO 6bi]wjˆ”)¹½¹sÑíí±<øYd ½ 9´ÏñÏ8ÅoLÍŽ&Ö¨lGhÞá°™TÝîâ9"°`98xúH[z®.½±\è-¸îºg³{ˆ=¿,ÞTÞ-7ÑóªÄ]φô”>JOߌé£)½³2›½³¨ÝXÑËö:¤±@{p"M@ü¸Lûäš¿%§_¼‹<»@\šze¦¨+V”$3Ãàt6©{kê69qägŽŽCà À¹ÄMoFKÀ¿%fæ›ÌˆçæuféÌЩ‚%:3h¥ [•+’ˆ ÀJ"܇ÑÓψðjsg5½ä‡µÂ’í¥öÕè2Ç#‹älZ¾Ü¡er<¸ -Ý&"Ñçë6ûÛDb‹Ib ½®ä‡íªúYè!µJ¦£¸|´@ˆòhWMËðEÛe©] ½¢ :þˆWeÛõÕÏ*jã}TF?êSö¡q'D›œ‚pO¤G×;Ñÿúxøi±Ç+:àDv ñ†&÷£w,º ?”xzò$u?º0,¡y' y?ÆÏ$kÞ9±›‡ó‚‡étLâ™Êou1²_Áý}lÉ=}L…°¥}„º`Æ;FXÁr&4Ÿ…ûz"}=8öÑ«èF=ÉíKúzx'2Å)OÊg„|#Qͯü8ú’Å~Óø+¹’4?»›¨d9k>€ñά¡’ô ïÉîgËOï´Gz}˜Áz_d¤A8"*ÔŸFŒ¨«sRE/dÆL)€½¡üY1kÌòÊŸE`0 *V?*H¤0Ô/yPyZ?,Ö*7židÂèý âÌMG¯ô‡ð W “7:¥~2¼ì töFc´ÂË"á!®@otF»zå6á¡®@7ot(F»{•÷ÃÃ\Þè0ŒöôZ> wzy£Ã1ÚÛkmá ôñFG`´¯×ö¯ðHW Ÿ7:£ý½öŽå ðFGa| ×Ñ£]AÞèhŒö¦ôðW`ˆ7:ãC½©!<ÖæŽÅøpoÚWº#¼ÑJŒô¦ƒð8W`”7:㣽“!<ÞãŽÇøXoæ Op*½Ñ çuÎ…ðDW`¼7:ã¼YK <ɘèNÂø$¯k5„'»“½ÑÉŸâÍÞá)®ÀTot Ƨysv@xª+0ÝŠñÞÜ*Osfz£Ó0>ËëÞáé®Àlot:Æçx=ç <ØëÎÀø<ï—!<Ó˜ïÎÄøïƒ× <ËXèÎÂø"ïC7!<ÛXìΦtöp=„ç GëÎÁøRï#]Xx.¦³è\Œ/ó6êÉÂó\åÞè<Œ¯ð>Ú…ç»+½Ñù_å}l0 /pV{£ 0¾Æ›7‚…ºk½Ñ…_çÍË‹\õÞè"Œoðz'²ðbW`£7º㛼Ocá%®Àfot Æ·x f³ðRW`«7ºãÛ¼?XÀÂË\/¼Ñe´êím¼”…—»;¼Ñåßéõ­bá®À.otÆw{ýëYx¥+ y£+1ónaáU®@Ü]…ñ*o“,¼ÚØã®Æø^ï1^ã T{£k0^ã T³ðZW`Ÿ7ºãû½?<ÈÂë\Þè:Œô>y”…×»‡¼Ñõ?ìýÑ)Þà ñF7`üKïSXx£+pÔ݈ñcÞ_fáM.ó,Ð&„ô6=%‡·º"›]%[1~Êûô1osN{£Û\‘M®vœ+þ’þ c¯¹f†±Ë|m†±¿\7ÃØYn˜aì)ߘaì&7Í0ö‘[fûÇm3Œ}ãŽÆ~q× cŸ¨7ÃØÊ 0ö…fûAG3Œ} “Fýïl†Q÷+Ì0ê}3Œ:ßÕ £¾w3èëÝÍ0êy3Œòéi†Qß{™aÔõÞfõ¼Fïk†Q¿û™aÔíþfõz€Fh†QŸ™aÔåÁfõxˆFj†Q‡™aÔÝáfõv„Fi†Q_G™aÔÕÑfõtŒFk†Q?+Í0êæ83Œz9Þ £NN0èÍ0êâ$#˜\˜Ba:žŽ ¬p ÷ØÚµÍ¦“‰t¾ð‡?ÿRØt< Ñ1¾]ÛZT*$g\ñs@½—Ž-~ÀŠFx¤ÀÊBqÿSÚšZU¨Ÿùÿ;½2}ï÷zþÑ«‰q¨ ¬)¬l›KG1šX[H˜ôH••Ø_ù¿%Rô>ðôç{ÁUÛM[ÏÔQžÜÑ8C±Hc<{Në¡ç+=tºqœG²4“Æ{$k¶4Á#Ù²¥‰Éž-MòHŽli²GJÉ–¦x¤Ôliª‡^™æ‘Ò›IÓ=RF¶4Ã#efK3=’³™4Ë#eeK³=’+[šã‘²³¥¹)'[šç‘r±¬dûˆæM|¹b3iRh.Òâìf¯L2ã­‹‹‡*Ïz¥7ÃÛ]sÞèvZöÀ¬²ÅúQÝÞB:™U 2¥·Ð•Ì…·øÛ´ŒÒbÑ£2kñèq™ÿz¾øy)zLæ%qãJÒᆥ…Ò¸q}éH¬,n\Qú²FkNdt+ @«88G5õ$NÅÛö'eu›n÷µ£§b4õ´,"ز“pšF_ÛÃLÆ3§Çi«A|ƒCgäñâÿYyÂÄžÌôÍ+ÄþbÿKSÑêðñi¿§ü_Ãø/­ŨZ´†LŒ¤ŠccŽÑ ±5•Ùkê×@9&žÇ®.z&\Øú­L?«¨¿‹=T§•³i¢m•ãbmJ¿B!ã»§åvEƒDOÊ|Œñ y²ã$©`*©äDƒ?Ú+LK'è X£Ú«3D g¾GSÉâÈú,ñÞ8¯"/Àô£ôÖeèA¾ÈxT|1øŒSØúéè¥ÉН6^É~úO%=Üc¬l-0€¼ÐCodOÍø ‰d-{m0ø{T<Э=-ÓZNð ,Ñ^§¸þ‚D:]dÿ1eO_±TÜJßÃnl ÕS6«'$šnbú&'µ½¤:B6iõrÑ>ã5$e¾¿Šè›E»?Aè£eÃÄFÁË15îÔrhße=›¹ÇSìeÖ“È?Ò'ÝÎè|±‡ÀOí+¾l½¥-ÞÑíyÌö‚¦Þ3²57²5×?m#ó_ÐÁÌÄ’8b„–$×EÁŸÖùúù}™Ò©B»±×+ÁB­Wši k®Ð‰ôâéR‰æB“ì…Y¶Z¨ó²Ù¶pÜYêÑèNIœì·†JªXÞ®û²^£7J7¬ü¦U|ƒîÅG⮘>kœ!^éãw¬-x¹Àâ8LG[$æòåÐ;ÌmÍ…ƒá2Od·K¸3]ltF…¬X^¤2ºÙŒ2º!G£èaã=lf íªyOÝÈ¥ÉBoÇ ¸ÜÃx_"d*€èô·Ñ¡›«…rô·ñ÷”Lãü`[8æj\s‰Ã6T&Œ´ñ‘D•¦A˜—²ÅÕ;èõ‘FµÅƒ]ýóWmq_É$…'d1‡ÊYY_ϧERäÓ‰*ÃgEnŒ‡êÇÐÅÓ=ÆXŽàwÖ}W\@£ð÷4B V@|Àboq•USÇ…jáèŸõüUó¥jAæü_tÊTÉÞFkEýƒÿðÿPÓùçñÄIÇà…â8í̾ŠîpäUµg.ïØÓŠ_U‚+MÖâê®”è…O§àî”èD…Ïõô‰ì³ˆ©/™‚í¨`j¾ÎTM^ùËdÕ"£vºPš¬)ú·ÉÇ–Éô <•ì‡z´XŒÅ}Á)ôì»n9Æ Ëñži9f-œ-”WÈôeLÂWѦŠ"SY|=ª®j)ø'–ÒXZ#W©[Rˆ ¾V.µ¸è!Ûõ@”])%»Rø=²;¥dw Lv¥¯aW¶ØQ!¶¡(û£(¿ šê”K=FM~BF#b!•í™îäbêUáËiKW‘ÝØÃ€µëX/:Ø+"¤î !õLêŽeÀcÐ]á=:oËèE…lB¡ýavMJ;Ù6ÃL›¡ðY”vª!m¥™¶Rák(ítCÚ.3m—Âc”v¦!í¨H;W(UøqJ;Ëô»Â˜V‹i¼Ž€ç˜E64ÿ–Iì–"†­; ¿£$ú-ŽwrrèSêå}ìнœŽ–ïe:Yîe*èUãó4+·6¦2‡ZŒ2‡ åúw¦ µðá–ÐËÅ/“˜/ü„½|”UÖ?>÷i“P$ d_åÝ,É™‰»êö]w­1ºÆ×Šeâ$qDZ쪫 ®[B ¡·Ð¤H(ÒB‘"½ƒàH¤#  ÅÜ€J2¿ó=÷yfÄÿÿó!»ûAÈ"ä rÈŠ:8Š¿á=öw.ï$OXa,··³ÖÅDƨý§´ŽE4•C“ yÖJ؇™fà‘`!n.ßjŽ]ÂPì_•Â÷ë@7K¾©ábyŽù~¬Ëz¦ƒëÖ’ž‚³B;!áÒBÜ^²ËSðu‡Ð. ~ÓA{ ¤ÎSðm‡PÏuП,©÷œïªÇ%ó¼¦<©î$_±™„¯0“ðf¾•QýœêW0›ÍWäk6ÛðuˆîÏ4äݧU½+CglFç‚'hy@û­Ãÿö?‘"šN*ÓiÌ0Šž€ ´‹öyˆ÷› Ú3qú.‘­EÄ¥dÄXDŒ‡".'ؘõSÿš¤Zg.µÞ€¢õšRžºãšÒêüÊflÖ\¿h5¦Ã€úå7tóšcÈ߆£¡¹ëÎTèJ=“rغ3sPv÷$X åçÜCwž–¾Ikí§÷¼ö!.äôÔ*ÀÄýÔSp±CèSê®ï:ˆÛJv{ .uí¦àåÚ}%{<²B{Ð{½ˆr8~oèwðÜ{Oqï=Ž÷j£?E—`Õc%è±y†|¢ßººáRÖ—‰Ú¿‡ƒóØ8“n œ lŽ«ÿÑ”Ž­=ŠDUº£EAÉRµ(~Jü(€¨U=©QÕ—Ñn²]JáZÝL ÿ͆Œ%C[ ì Nh«!ëÌp`}l m3Ðá÷A8.\b¸BÛ fòn7ƒÝ=áàeCq‚ëA°M VãÀzl£‚M¢ËÔJƒ%‡‹WöO£;pàÞ`Ÿ¶ìm=­q"_Î6Á²(“!kq1îÇ ˜‰±³¥”v›Q¸> ûu]gß©l_Pϰí ûÎõ‰¸6K06Óª´!+‡ïÏmÀsÄÁs®Èl<Ç~ωB2PW³Eª÷<œ?F?Ò5Þ‰)⢣?qQÈK`6|LG#$Nf®Â·ÂÈ…:2…V8 ›AkñS£ëd…¹ÖwõBµbϪZø˜–)L…sM¸»Šh–D´ÝA´]£[—(òˆvÚˆf;ˆª¹ÚÑ^´Â~Nœ-¤á×q§× ùï.º£`DJÃ#朆;:`—YU<O–úµ?¾Ïtøœí¤ ‡6µ mg¸QZ>kGrƒÖ¯ÝùÃáôˆ;¿¢°žnd1öÖ)Gé±hñ”æ‚­!ÒuŒZ| ÝØÆãª0Š z ôÌq虣ÃR k=‹u9O·›mÁüîŒºŠŸ×ñE)IƇ %/%2 ßo.:Ó(É)$ f¦ã±j·HŒoe?¯g*bªUbºÜ¥'Z!ì«EìV¨ÿbö$ŠÏÉ|§º¯;iGu¹ŸÀ[ˆChé†,yH¥Œâ÷Ñ”*ÔËÏõ#éÑšNžB³'7/^G-× ãù~cV8¸–fœM!gl 9ß ™ßåf^ȵ¬4ìv®4¸†éó-õ»!« î÷æÊ¹½p]û×®ë@#ÙÔur‘BDSÑ/n C œ>mMTp„sêË3ÊGb<,ÞUé8ÏXŒ1ÉÕ¢Ö¡/sNÙµÓՌҬÂl .`ã’Àí~àx]1c ¸Ópn´ÚW©BÒ÷t‹v¹!ÒîvJÞ­Z Ÿãí5öW”ÚsûŒhNæ³ì­ˆÆÝÃôã°ãÇ×ppµj•ÏXñWšKG‘t@y"¸Ë“Ÿ)zB=xœ€‹%þSLu<©JA³d¼+å„>óAÛCED½å•_f¤N_+Ì <—Jöž‹‰‚w¦ÌÊÚ—ŒX”™¢M)=>&¥Ç{˜õ›Àkðox89W©Jº_žë$ªLY¥.0…U}è&D³&1xûâBTÃùÉËé,C”¿úÑß”Íèƒc°é¬C‘y"÷àÈ\í^mÊ&6ˆHðÓëj½Éì$GÚÝ×Õ*ó½ï" …èJ?˜&éé„©˜Æ;˜Æ›r‚ KQ5¦ÿ 9ѤVªóÈIf¾œLSÌù>U¯»F—äH°‡FË4&¹ãfådFÙgZ­ƒ³Ö”³çàœ œõ9ðͧ¿„s¡Â¹ˆ>=Sq.álK‘m™MÊrÊòý­ l+U¶UW“²¤LIÖn½CÉzSnd”›€r³MÉB·•þ¶ÊÊíW£ åûº£NHÿ¦Ô{BG:„qaSu\IØHdS:ô•ìõ6ói*O¿K„(´×“çÂk}C›Ò-Y±rM£Ò”•) Áº–®ÔÃ/t’wÚç…;ÙlÍ?ØÆ™®knË=ÝD‚ûÂ7ÿ¤Ýk/vr݇9*î§ãl'í1¼½þ—q©“ñ Üï1TéA*¯²UUEe«zùÜÈà--«*¶´¤ËéƒüÃW4«ªXÑŒnÒ¿ƒÕ†Ç°ñ·¹–]ü… -\cõ¨“Oe\Û"%áà§Fp¶Ng3.!O¹]|áCü¹Œ£€yÝû¥÷`9äõ|ÆD½`GõUQùˆz1c¢þnckt°½’1ð×Ê È—QÙF¶,ÔÔÙþ‘ñ&¢ßHD×é©Ñ]3º úí2“£Íàe-5úŸªÚÿJD7iIŠþq"ÿ›ˆŒ_‘·Bd\r¹Ò3αåÏr«àr'ùX™eÛŸXìr|úcé·"ã}4u‚ ÛòÄp¤¸^þÕè= ï$C6À€ ‹‚ ¯ü› 03J ÐÝ+_µœëôðÊ×m€;ãvôôÊ·l@ZÆÏÐË+ß±éí Pé•ÿ±Í6,š³ ‹æiÖõ7ÅãÍ/\Ž_ß¿©)þç¦x )þNS¼º)¾ )iŠË¦xËxœáŽVк;ÍrO³0bûªç-‹Çl_Ö†øÐ¨…“t¶ƒÛÁwÔŽ¡¨7ê×ÁƒÄ áÁâÆp5,Êôöš£Dº%¢D¿â}jxà†` ÿ,³Jgët*³ 2­mæÍ8W³A½÷ Š6ÁE«¡ ËDú›d‹¢O•/š&2¼˜ µ"¬èŽDUñN&þ223GÄXmqžˆEKû¦Ë"ãN g:’O3iæk´]FÚü‡_?ÃsŸ€kn,>°±¿˜¯¸zã§\¢±ˆ­ù—Ñ•a™!(pì²yû,ªCŽð¨öYð¾okCÝËÏ¥L…é)Sá¢؆ÛÙ<fCÀФÜq-ÁeÛà 踡Î׋ޔäwþË›é_—|H7uç6gáS=ÉF]Hýa˜/4õ*ªë PæôµW£ÿ·´Óéÿ­íŒù3”w³2=wkØ_)*¡ƒ;§üu8‡~Êß…£¡C†ü}8úÌçò°!o¯ùˆÁ6ÙüV*ñvjˆ;ÃÁƒà­|ßCàÂpð0À‹“`Û¦Þ€?dî쨾‘°©wcûÐó ’Kô¤ÈëR]ÙJ9 Ã^†²‘ñ3wêJN•à¿#øÂÁã@¾Ü>.øOö\û“¼ƒŽËÇ 6 óQ2Ûý”N½_"ÛŠd¶‡ìlɇ)Û—ÛwY™Ìæ§lφƒ'mU2[™ F–#¡›ÀX­k´r?ƒøWÁ`¹Ÿ&Êp¯ëUvþù”“C¯×a]Io#¼ZWÙàhp{¥—ÝbÁÑZ¤%ÄÞŠu–ïÀëëÑ‚ƒÌÛ’™§!34".#óÇLέˆ˜ådž%`-C4Ï&hl’ êÀ¹=‰3a©· 8w$q¦ZêÝèàÜlã—ÄI=ËêŸ$q„ÜG8ãÀNâ<èà<(ägÎ#6ÎñIœ4J>ÎHgBÒ¹ÌÝhç9ç9Açw6Î÷’8iÄ1ç<–Ä™àœó€ÚIÃü"”ðs]£é€3Á+&h|„š¨¡ }D P¹œL Öõi¯ïL{;ÔBk¼t šè­)˜ÛZ¡òê êDi£…aè­ÕÓ†³óa]å‰`$«²’Î)S´2±‹_2AÆ\Ð7Ÿ²Ÿ6 ?<Ôé>½‘+˜Æ)^H9­¢4”ã¢Yâõ]´ËGòâP8⽽ш䉚ÂX–èLÄn_·^×݆Y«Q˜¥Ò†eÑFýÛºœÊzü¶5qqí’QMMT‡õiÏS%–´S»W~Ê ÐÜÓ¨¹ wò×ý=Z1¡F#ã¸FM÷º>£&œá‡é3Ó«åæÕû²‚¯Ñê¾^³¿N6°ÍòR3Þ…FÜÅ2WhOçF¬“G9XY/¿Ð¢9Ì‘;~³½¶*n_°9 TÔÐý ä£0•›r ’c™qOÛ÷Gè´!‡+ÔÓ¤žŸf…z™´Ìs`wV¨Ò¤“öd…zcáçÀÞ¬P•Içå"+ÔǤUŸû³B}My· È õ3éÌÀƒY¡þ¦,ÌÈ¿Z‘¬ó5oÐ*+ºWÜP+æ è8ŠCY.‘åÚ—Rçœ:/õŠ’u~€ö.±»‰:ÿŸ ô0Qç‡U §‰:?¢½LÔùQ¨4QçÇT ·‰:?®U&êü„ ô1Qç.*Ð×DŸT~&êü” ô7Qçg¾_ç’¬sàê:¸öó²RÁu¦sHÁ2/B¨v5˽ò¯5aª[MÁG^¤Ÿ=éç ¯|ž~ö¢Ÿ+½2D?+éç*¯|~ö¦Ÿ«½òEúYE?×xåKô³ý\ë•/ÓϾôsWþ~ö£Ÿë½òïô³¿ ÇØHÉõf¿¼ûÚ‡ Áùã`ÊáîßlïoÜ`oèÃZºÊı6‚þ¿ÔN£Í§¡ÕDû{hœI;z44Þ”/Ð!u‚)_ ǪCï™òeº.טlÊð3û¨¶!±Áîr˜j¿ø íÉà SiÏ`/I3§—P%õáâQ&làBäNWz9R¶ù À{4‘°œ=Ÿ'#!b1¬Ø"â ]¹.¢ˆ¥ÎþÆ" W¹l7«çòÔ áŸårÊùHSšH4:W!Í)Þ>Au¥Þè¥+5 AòÍ:‚vc¹-Ú…#ÑâÑT‰@@¹^‹ä³|Õn--N=»?Þ¥¬¬tZW F„û„Sþ MžBÜWºRV¢¸e%T¢JY2g§(+5èʯ¥ï§Ûtb»†BŠ®®¨R‡'ÉÛdœnwí8Hƒ :A÷Ó>Hø+3iÌ—“è¶¿àP*Gñ?§Ic’æŒd“—®³râÎèJ#‹âVBnv5€guG‰Àù_©ÆT€kÍCˆÂæøµžTcúF‡Éº?6nö*ß`Û²o0µ9†fšß·Ÿ8Å„ýÄ÷M¶ŸXk²ýÄou(&ýXn·« ×5Áf¤pˆ)hÀŸÓ¡Ñ”‰÷Í÷…ƒµ&Öƒ1–óÉÈbŠü?Ž„U½‡!«¥ÃTX{D>A‘Ok`Y:ˆö‚ðƒXtü”ê"Sð[¤*³) Ûe`¨ÙMyg™êuïy&«x Ñ1L^‚µOÝ0ÜiïiÀð‚ÕÝXÏ6óÞÝ"È“y L™-^ñ–|+x¨ŠRÈú«Íhp°Y\MhÞ)9(¢4O0þU2ˆ"™!"ó?øÑº¿ív°BÐRšçêZŸñ*¸v=D4†6 |¯û_¶-¥ «Îsav1­•ŠPI’UWe©U.xhñ¡øZæ[ô£Dœ±¿`Ï®"6´k='hWE×á!"£0œ®Üµe@oLU€a ¨"À4`«¨—tX,D3t¬ Žrt*:ðÛÞMEÀ˜TtŒe§Üo€n¼£<=^ÐöpÅ;{ [<å¤9H:ÉI: FΩ©#vSOe[§L"…éNÂé C³Lº$úGP†¡&:•–R^gƒ‰L‘l¸µÂPÖéÁ<,Û ñg:Öé:!µÝ²u:Œ¶N·HÐÈ´á¨â’Ÿú¤ÎLJè_—›Xo¢‰xö h$ÅÑzÊÀ÷V/äæ”‘8Ñée@^è^À_´"½(_ŽädB÷ï×–z-\`²„ ~D‚G³ì'CxD4ܦi@#º9×C‡ÐöRÏKøôÉÔ†øÕQL¼>âÚå@*’ Ê¼Ž ß'xw L¶nl—\WDKfÉj¯m^Á´ø°•>BÐxжeÍòÀóÍ(áïLƒŠ¥æ 'FÃ'ŸFLDŽÑ¢ÎfÅõìç=¤š Xf.åU)"'‹¨œ"bE­ŠëQ)4 ÊÔ ;}ÜÛpë,Mu_.ìÖ\®ª½VÐI®ïª¨ïÚd­ê`ž(ÿѯ•AÀ_<šÕ)鯮3üÕAØ/Å_]DnçªØÞèðÚWe@!åE´»<Þ½®0:øÜ–2¬HÛwëoÐzQS|>«§,0SÔSÀ%–Gm˜ðøL¤ª§|ÁjY}x¨µD‘°)/ °ÉúŽœ/Áò‘ú~ÿ3¶wŽQÛÏHPû̾mÜî•4îe'ŒZo˜…ÍB˜Ò©¢‚–9¥¹ Lq¥Ÿx¸i‚.e\ƒÌà<®D¶­cSY'‰"" ‘7Ä»U9hWš³T¯‘Ä–³\¤–¬ßØ žIÐomP$R³ œR~Êþd0C)-ËÙAÑÀ¥RÚ) y¸³¥S"‚÷A*1‰ìA;éƒ`ØÙ\F6ÄÀÜ)§ÆêbW›b†ÊÝ5ÅV¡ÿ?ñêôØkÀðr{󖌣q¯õ[ª•×}[ºü]Tþ>6¹k¹[þ±Ìèêm­ã¡§«üS™ib])6MÞ |œì϶ØËÒÊÜttm‡ëNŽªHR'Ù?ûï’…Qyo´,mrÑ]H…Žü ÁŒ•¥M’Å1.Á»gºìBQOFåS ø3Ó/%xY*å):iƒÿ›ٛTÄ/"åétìa’ËÒí³ÎxP´Ú0‘ñK‚=X¼ ÓØ˜k `MLO¼¡ü†f¤¥_?:764ÅéߣñøËñ8…å e9a¤j§~Â]m¤á\w¤<ÜÜ>´ØÝ<*e6Ž6Ô[@ŒÇ3dš`ê¿kØþ(â~Û9ëýtƒ¼A<„Y¨=%а+Ê:ù0 4¦£‡‰×XŽ^·|!Û[‚ÁÎh:˧ü' €‹N¢â¤Q/ŸŽO3j§â)~X­ârËgb63VÂó©-`±TŒw¨Øçu-›¯XÂT,»’оOÅ ¦b%¨XeS±š(XCkAÅ:¦b¾‡.ØÿTðmû=Œîëi(¸«Ã€:à]axïae»ïV˜íÃÇp¼ÊÌ©µí\]é¤ñWqǃÀ&pŒGp,‚‚S‡ Á%Ž7Ø1+ߤš±¤L©pÕÞþž7Öwþ*üE¶UX$+*EÓáã5\¸ÔtJùÞ{†Þ:Þ©Ád—m}N‡í:Yeüåj–Uo$q?—ãdÁªv” ìª>¾È9¥pRöCÊ´«Sn÷jÛÅ>qDôi×·~ Ô´Ø.ít–K®¯²Ø5k–K/rÊr»Nf¹Ì[]dz\Ö­®/³\î[]'²à˜u‚FįÐÊÃ*5ënX»¦Æ‰(“/Ü2û€¯3pýWcïb±ÃÿpÑÃà|L4œû(ÅýÒ/ÛÓé_—[°==‚(6]fÀŸ_{åºöˆ’Þ¼¦ÐabÎ{EÉO^Œ>®1]ËGmÍûÝ„"¡ ¦|‚>†z™ ¤¥´±”‡ƒp9Z¿Bà×ÂÁ/4»”À=x‰9éuõJè`‘~ìMˆÎqr\ÃÁl@u <Üͦ¤6˜Eª“É(ö†›Ä8™sòº&ƒÙËrɸùwÚëš/hE€I8òO9ˆÛˆqs¢˜=ž¢GU“nAÂ%|›¬H 7è7ª«°r„n[ký3õÄ0¥ècØï{1'# ú6K뺋å’*÷FGš$‚Å +Çç*÷FSY-óðùý‹¤“¤‘j×;í§$)#Å«M.”…¦ÿi¼‘l4a1Z¼†b)¦NgµjmBûoÏŠpñZÓ%¿E—šÎw}ª ¾ØìÓ. =Ò†…Üäˆ*~øˆ¯$üUG%³]6 ýÀË_E1µ”šPõ2P“AZJ㌴«7XC2@ç²Tí0<¿Ï6Š×–ì8q8!Úþì?w%³ü—8œðxa·ÀFŠ[`Ã2ÜiO46x¡YËÌò»ÙÑÝ0ªªÝ-ÿŒ•êÞp4´Ó”‰þ¨)ï ÇB»LYÄlôûÁF Qª­&Ô¶)6zÌd—z+ Åoð:îëbŠIÞbUÉH[¬*¦˜äXŒãÈfˆ,£H_]Í ¶½@ —ÂÅaêš¿…:˜[Ã,Λû*Åv wšÊÛ‡såë.Übºº±ÒÛáѯï@$ ×¢´9ÿÍR°˜j| è£\dFÞh£âÞTUqÓ.H¯SŒ[øIºJ¸=½Ú¹öÃzjÐP²»¶?Rq×ÒgˆˆvS‡¾n2*ÑI¶:¥ íÛr!ûæ!ü›ÌHá&SpêèÆ‡SÃ:éÞõD˜–Šð2~l&ì×Na ŒßnO§ÒÿÄ„ÇÕšl‚j½vóŸu¶ƒu¶`Ç<VÞ æ¥`dÀÛBÛ"`Û@‹‹;íz`[ì0¯ :—¨´K‘f#M­´´"vü²‘Ú¾Ñ+6s‡ÐjsS¤ð&QqSü˜Žç³jI±]Di¦F©=g³[õODÉ…¬üÒ Y´ÅCÔË€ã¥&Ʋ©]fwE—ؘð6ºò§¥Õó@›«á‰š`.5Áy¯˜¯ÉùNýëàêiA¢þüt·H#ÂêXAx‰VÒDMÑ”%—_Õ+µ’87EÜnŠxVF9óZ "»õ“ôk“ ÐøÁ¸ØÂ‰ãhŸx–ܦ•Tdw,­È†bO´O ì‘zE1î‘ëø5Zåqþz´ïÇܾo¢~Óíû×5M³}¹Ñ4’3<ÓnäZ5ÁäìDcÏÕîØfÈOS{¯æ_÷½Žß½é¬çÆnâÆ®ÈÆÞn?gN¶ÛuH³+?g}¦]{Éæç¬ÃÍ}ÈC&ž³pïž²cÞDÿºüŠŸ³61álYÒhNǾÃ}ˆFg‰(ÓEsx¨»W/`W›ÚÆ®ÑQ¢Ìˆ”~™_{‘2C Â:SV:^”™þ·ŠÞr•.K“#5Ì‘Òýt3¦_”ÚTé[WÖ›zé‰t:}”±ÒSéG‘ÅŸš‡¨.úŸæÉšÝp“5X»Ž¢D´CÒBgÜâÏ5!§#ÛnÃdÞ”m®£a5‡ƒ0 "Án^A®ÂÏL¨‚E‚#Ú¼UÅ{M].‚=Œ¿? ++U3­Ö`üÚÉ\aÔÉ5gõÿˆ|~~$xÐí ðõèhÊü؈2öò ¸eìpꙵÆ,†Ìš?½(ÝU‘^'#„ÖiÌ(•U\ÙN@),!‚!ÇoêÜPYƒ¬~8x„Û'Ø+;'·ÿý PäqQÚ+›Ý”–š.R\™-ä6«i@iqšÏ5å[ŠwÏUc£Ï@Ÿö¥&ÑNOmñ¥¨W6dôOh´ö¿MøOi1¬§"Þ¢¾Òby.J0ª¥Aey±Wv'ÑA<$r:×At,:aÒ½œ®yQžd¬äs™,øÃÔ‚?lRëTJÁËaW:YðY|Ê)ž¾C§L¹:YðZ|*Y0<áÂùBð4 >,x[jÁl§ i’;ÓÉ‚¿FÁ§‚£(ø´Iûk¢à:üé;Ñø¦ ’.!c[2á T'Ú_ÆØ¨M8ب¿&B/šò7áhè‚)dz߃cö‡ˆ¼-<ÅŠàYÅ1ûΔ·CNÖfж6åwŠcv/e“‘Päƒ ŽY1f 81îŒH~{²Žmë=&ŸGü†6¢'RµA õÑ>Ž~KûÅ“u²4lÔ˜áYŽC;PRµ¥¼÷é¿K¦_á¸Z! ¥wíô— ]@htˆšE8:_;áe{RÂ0[¤9vó°)qõ¥(Ÿ¿OêÕ×OÿºüާÉW&â1MâŒIM“ ÓÐÓÒ½Ã|J÷ˆ¦É-˜ âÈWƒk1¿mô>H°EC½-öýÐÝÔ¯KKŸm"ÏmŽAû٢ܼ±ÜÊ©ð—»9”F÷òòôœŠ§Ê›Øœî¶Qí¢±O»]þ)x¦ªâ™:y{4¸¢5†ƒTÃÇ_Uᯗw ®l EÁ»ÃC}-Y‹Wµ.I‡ÒŽ ý>ÝO«ŽÏ4ˆQ>“n™£}VO¼Ú^ïž!dÊUeÉ'Ãù¡>–|Š>„Ã.¬´\x08_Áš£óe)4¿x•™ìPé…hð£Öf›ô¦½,_vr¦0$ÊÓåßÊÒÁ†)·ðHÛ &™éÿÿ cF‹hpuëå-3ƒÈ`˲¹hùFY³à¨ævÍÂókäz×׬›ì–å4JysùfYó_j¼‘"VfqŽÑœ#Ÿ{ãíTR³NRo:ýÔ£-tZ¦ÿY- â³š6u ©]¨ŸÅJ²½­ïwA¬ƒ¤å´¹ÚtÔ5 ¾›É¾öæPDñpÍ•ñSÖUqc2m+ïeiÁ¾éÝØêÜ$„7-(êaVZú` Ãv9ïWÏÔcxš}5XÇá ËUñtmŒTEúg?ÀcéØ_¡“`‹ è·ñ>ƒ¾£t”ì› Ô0ÐbG7ÌQoQt5 ¾Û|ŽçüÈí¦èQA[j¬ci£&·ÂëõzéŠÖ´Ø¿W¶¦Ûs,Âx&–®jñsvK¦-ÚðÕ5¡2 {X:aãCj ê©@m˜1(o¿ˆå£¼Cl7¤§©‰´ôh—/°°Àöe/Ëö’ÞË JMyI§¤½L7µáDnCÉmx3&ÿMhÄ1>×j¶“ñµ`=‚o…<#ý²O±PðÓ»ä×`)Ò‚À[YG¾ê÷Ô³™ÝSÏ£…c…;ÒðÒµµÌ¸zŠ“ ^ÎHe Ò¦ó㹇ªº½úŸ’ÝéÎ'{hQÙS‹ršºÂ*„j²å×=e°Üq'E×:¾¥Ò"r0p Ž¡„cýUÿ@îoÅZ=†q±=½­ @n¹Ò4Ì´ôÞÜTãø6|s]~=o7ã4V5®²<µJ…)ØÇòŒÃÚ•.¦kà ¤ËZº§N\êæPÍÖî•34L6;z^s 6ón®ƒÍ¼Ö뉀y­s´ê- Ì}-Û æ_àŒÆNé öµí+3’y˵ðµSÐDÍ`Aî >m »j(Œ›®nõr­Fg(­ÍõãÐb Gß'\Z$8ZãÙÃE¯·©§¥¥ãöØÅíA+O½]O=|Æù4|Æúô=¬[e@ ¹ÆgÒõof_{©'òK?j-÷ñÉŸi±ê×ipÖÊÌ봭ʬk,¸nyZ‹PÌèæ­ÀòiÐÊÜ9,ˆÑDy¢ÆÆ%Ï€ aÙö,ò\˜¬7°Y‘”¨óàk0BLfùyî_Ò2îÆð¥ ¬¡ŠTè\0^zèt÷Ï@#÷ÖiiYÝšÖa¶z².t.³r2FÝ?@gõô*nðznðÁzjƒÖ¹Áñ¡LJ|8+‰cunðɰ‚šlð:¨¤©Û >VQåÑäãˆR¬­Ðèï¡l(N_Ñè“SÍX„Ñ=UG¼Û¼e)†õÀt]N× fèht4Å,–„¸Qçé):_¿¢Qév£~ gã-F_kÊ¥6ó”:"¥Ó¼¿Ú|”làÕW4ðÚÔž¢£ï¢Þ¨¸¯›¿EûnšÛ6]m÷±¸ª6üf±]§¾€ƒ©iié‚0ëÐ}~½+ªË¨~Í-q—Œéê>S ѽH°_z%aégÂ×ÏèøGx~îïÕñï+]~ßž—øÔ†C`3)Ú4ÀÔ܆ù¯Æ‰>yGJ‰Í„9H£a’Oà3Ù§}FŸƒùú]~¦dJx]¶^3 3f‡üýRØç:uX9u~nØ#:ÜÍì´ÝÍœd¿ÛMÍ„"â«$}ÿÇõ•"â+ö®I]Jø9ÁBÎôœÑå†Û@¢¨Š‹=‹^Ü“ÉþÂNYhFï·ÝBxAÏ‹C_ÂÔØV7•ø"õßËàeü=ñ(2Ö’¯@S„ÉÙÁ©zñþ`>kIýé³ÌÔ)í#ÛL„J¶ÍÍöùëÒtK‰ûj…Õ–¨x¶Žî%þo=È-üÖ£½^/‹˜í*l¨ˆÆ"¥³•ËU–PYh6€ ƒµ Ó6]Ñ6jD×"jÖ5—¶ý±袖YóD”}r:NE•›z¹ ÄÜù€´ùcK@ÕPS³Lëµ–ÍÖåÐiû²\ë K‰Pl†3‡‚Í9Íήm ‹N·$,:Õ¡ÚfÈ`ƒ¦(ÄÇ$åw›ˆ€ÿVó:ÀÂÓÛÂÓ'¬24Œ†³i}À-s€‰ ƒÞ³åì²Äu@‰‚tú¡1V'CU»Uw>Ù í¨GA—éÐeetq†te=èÒ¿8']1¦‹ÆÛ1ˆ7¶ ÿ—"‚§- °v’À¤¡RN±O]pøe£f"‘T`"¼gO„s,RM ·C~-I>¨â чœˆ~S<@“ý4®É04-‡pwFI—"|¾|*კëþkÕÇÆP ïù4éàˆH‹û0ì§ñ6xÎ\v»:#4~ä Á‰ÎhÛ‰Îf…7aÖ6Ô/Ðì'ÀÌ¡¶”-´w­HñKÈq0aÒÚcÕru·©ƒ’’<Þ¦áx(êñ­òÖkt%¥ê­n[8ÜÒèÈ#?gœ_ ¦ø´=ÌŽ¦Cø·r¿†¤kÚÊZ”’ë„–Î1–¾ŒUÜŒ£M´âf 9jy\ó÷‡Å°@ü¨-í§ùò$ýÒrè-ê/”"Ü®äHæŠèJ{µ2™êJµZáó¾OÀ‹–>H—UW#ç—þzNgÚ­)o½¤33ú>{Q3†èrˆŽ‹„³ª™r(m`4 ¦úlë}ØK†°3mË1%Ã1š‚ ˜Ô¼àͦo¯°£Lƒµ3‰æIŽ‘òI:Ì™ðĘ“‰ŽžªÂ‰ž–ø†²ÓØ`umÍMkŸ„³ìF°p%pS]Ò¢û÷få͸afQSLó |¦û4|èì¿€[ËX¤Ë:_&hïöö šö…ßx4©¦\¬GUÏõ ZÈ\¢Ó¾ŽÇžÂa–¦ÚÈÂ&O7>,×ÃeVá(‹¯ã!w¡P¬i›9(fø¬ÕÜ;îÍ:íû1Ð-7£›Ú¾^ž–ñ$wÅL_ÚV£+}›.·ÂTZu¢OÒiÏ—¥£”@÷fU\WÚùËš©G´ô«Ì]Ú£mïeÍüikÊÓÊÒò\Y¨cvÒц«]¯c&²‘왥4€÷©cÆ»¦ÅžÂ©‘/9>C/鲉=ö®ÇÚà9hŸ AªÞƒâи“ÌØÝ±ÞÝ=dÆãWgì{ácig±š?‰Œ½ GÒªÖ'z;RU´Ëô6dÖ~¹ùošìo(ùªÂ¾×¹0ЀJ÷%P f('Þ~gÿæïYÚ l—(q Îvi7»Æ™0´\ŒBGÀÈù(ëDNæo [o„ýc¬pÑK„Þµà&‹¢ªw88ÂbÖìXvœ`#l<ÛI79`ÂðÉN‘þˆ2Çè=3©‚8ÁLQo›å“yP%1KwÈqÔÛnkú1À01åH5ÉTÞfûäoìw÷ß@»CüFþçŒ?\±`·øãµ½ÂÜ]%ï GC-y´HLåydv‚¥<*yS’`Û@ßû¿oZ´¼€³ªç™,׃ bŽO<(b6Í$ŦÁå ê&G^WZ‡y0PÕ%œšZ¸`¥OÙÖ2s}ozLxëCï[±4þ‡³”ÒI–, û?Qx8ÏEŸ -4Ù’pñTZÆË`WÛ„¦í_@ûÍYs£ë5ùšDËppšN·ŠF´Ô*F¶Ü%_{ëˆÆêúhŒð²Ÿ­®á`Ý"Τ•b¢UüU;ÝæLãnWö- =ÞÞõ–üg¤›r¶t šl±ÌZþE•#ŠÿöD‚ò‹ êúŸpñLËEK0ª¯Êº“²Þ¦8ÖDTž‹­Õѹ08Ù 4ÆÛ†ƒ3Ôà«dXqE;åxµ¯PX¡>H 1í¦œÅM ô5 P3X¥¤£ ‚ófš‹úTóá³!ËU-À“‹ íH;-g˜P¾ÿ9Ò¾ëp¶ßàr_A8áã„ê‰ñl‘–gÞ­Èçž4ÖÑ%\IÇæ[m[OɧØÎÅJ F.ZÙ–:*ëä3¶Ž§`Ûâ¸mÛâY\¹7˜°Ô÷;”óªí'êU6=ñ*ÔÁ9¿Ü¼‘`®¬´à|¥‰–ŽÈ–oAe€kR UÂFQ%X+c¥zŒ` .”%8"»3-ºYÜdÂ÷\2½—°GBß¼‚"cGTŠ™$°Ùùaud² ½8"»­­ÑÎr£Ül:V éMþ‘Ùêœw{ûºyKÊ9o+oÐ74.ô]ËèîZKþ–aí£%º‹:ïžpp-:ïcÓq¶Gý£¸(þu¹ƒF•(ä…¶›Iy¡¦žf¹»5.ò)5*îaVT¥ÿ«³5úx¶NÿÈ6†J±Iÿ̶¦SY´RÉ¿Új¬¡-x…¶ZÊ­Ý6K> „;pL+s‡¶[² Æ¢?¶ä_Ñû”Á'¦2·(Eìf ª6• 5Šâ˜Á" øAAÕl#6™y2ÃíÜVdŽ&3Ot2³Ö e&òø¤Kf† s«¶!óÎdæNæVú"¨Ó,­šÌŒ—?<ê?FæºdæÕNæÕ‚-ð¡âëØ{2ófdÞ /xÈüi2óv'óv!?Afj½02ïNf†Ávx¾™÷$3ædþL°‰]tÁQdÞk:Be”êgþÑÎø°è_—;±òÔDaLî3“¢/ûMh@ý´ñŸ²s¦µëOFaž+´Ó’wÃÉ4/¯-‘ú/Daq` è;hB,áF@Ÿ&¨?ŒÑ$ÆãγáÀ»Ù2v'à ¡ÊpÈT‚”á¯v}þÊf)Í Å·{‰VݨU<&[(ãŽ\òuÈbwÜ L‡M• >ð]eÜ1Æ>š)[‚1Ø÷˜ÇÍ)6G¤˜¬DcîÄ)pÜ(!`Ê >þG®¡üP A°j‘窃†t:´»=›ìcR*°`‰/R“ fÎ(,Õb­µéi»’îôcs—ššáN{ÖrK}¬ú½?_Ô*G³¡úïZU¬`e‹(ýñ3Ç|e~­Ûòrb®s3»5Îä—ðÃíç‰ý‰Ê¸Å?.e|Ôüu¹‹÷§ÖˆÇJò… ;­AÌ´\WnI“'/=Ô„“ò1^}oj\æ“?Etõ®ŸÊ|,c¨ï`žÍŽj Y@ßÝô…Ùöãö¦D¹n¦¼5܇üÒÞ”–Ùk"uà¯x9ܧ–ÃÉlö¸ÙN&³]¹îU[à)ÞËF $¸‡nß躧AŒm ÏHË}Ú â#Ÿþ´,Œä§1vo$ïþÑ9’÷8ÿ¸/’'øÇýy®7êà=iŸÅrRFóŒy´0äáhžä1Úóã‰@“çzùd$VüŸ&å†ôGÊ ÃâÑiÞ¿fƒv+™ÀÿÊP$mG(Z`|Ñß¿yÁ*_Qÿæ4Jÿ)ì‘åÊ+d~ÿ+ˆYmǼ¦bà˜×³ÆŽéªbç˜7³ÖŽù§Šó/Ĭ³cþË1¯×áDµŽÜ‘öÑ/=©À½|'ŠNÈv…öóU(¸ßB ®S/„z½º‹ë™xPÝ£D/óê¸ lÑKÎ|ÝìÚ5…‘p"·M‡à 6ùhF¾ÑF>VøóŠò\„¶HF=U®âÝú'ˆDfÎ;‘ón²óN‘b¢_iE7Ð’f˜ÿú  [²9è`ñVšŽMJô½ùßM+­VÚÆ”íøŒ eêÿmÜì£ÞÍjßÿm801;ð¯'-6ÝuÖT¼”Ìvxû%üצr8@àÎö€ï,‹à§À’÷Ãôe2›­m{Ù¾Mf{ÊÎÆ.jC',¶4y.™íyÊöB8xÙÎÛ;Îf›5²ÅÖ"Õ£tg/˜¦e¹× $êãH¯õ¡ÕjÁ Ÿ™7hølñéƒyé4†Âþ p°2KK“…ˆr ¦’SñÄúi½zÃvÕ ¥,3ƒ“²9r8ÌÙ´çÊÓn,O¿±¼ÙåÍjÑ Vÿ˜_ͨ’ÓU%ñ©»N‡ŠÌVŸQËu5gãEÍ) “¿–*,7±ˆÓb`e|$À1Þæ³æR†}îy‚)T'KUÙ k†àƒÒh±/s7µJŠ¥Qh¶ç^ü) *Ç-ÛñÚæŒÑÂÖ†‚Ù)ÊRá]LÈ2j¨Hé°VtÊ)39kéðVtÃçÀæV ‰pi ϤšÒêVtÙÏh!\ìÈlM’(1‡ËÒ X¢›g/«ÇÚ¤\·3x»/mUr‡/꽟øšm' ÊÅLìZžG‰‚8礮åÍä&ꀚÃÖGzYóë`Ñl«ˆô¶nÇù朠†ñÕDçxºàI=¥¦ÛšîH­é'ÀÕ¬U¦íâJUºªÉFw%`é\õz3„p:eÑð²`û½ímMq:¤•™9™lG.ìkÎ/…Ük†ê²tb+kᨂ«>kA•šç™ÏN¢²[á¨PQÜ -œVøÜ: æò Õ ¯Â>~j+´àVha·Âÿ±¢p²N:­p 5ka·Âéd+4(ø­p6S­p‘ÂðnÂОú—íÙb6ˆˆÏuYMË<´8O½B“q ÿzY¡Eh2ÀþL:V£‡ïS)íeÊž‹WÑàë´R³kP/{krÛÔ u¨âߪ }ø7‘ÈRY ²ŸÆÇ¡ ­Ì ¾2Ê g)èCKÁ Ç¡K¼Àå£C5{… E"¥¶o›ƒˆ·´¢|›P=ùÒOäô´ ÀqDí Ÿ->m:}¢>}¸(/éZÁ^ðjaP¾¯åÑÂ=]S«Ñg5 S³^rä:H+ò¸Ð"šŒpQÆ]/£ZL “ÝSÄ:SŽèÐ7ê"N×B½æS —òîxÉr÷äÁ¹×i¤½¶'O̧ÁQžöúx›Rõo šR`S«Îò0Ñγ²^vÐuÔª1¤›ü ¹‰7Ð%G5†M¡x<Å}a6yœ±”5ÕpHoáZöSXÎõÉ|ÿäì«\ô܃3÷KˆdßôV’'ÔË‚ã’7wúè"†Íµ¥ëð+Äà»hôÿúlý:óÒ1â®+}W›lÒÊ~*ºçÚOE÷Òà‹ÎÑзÛõ8gÑy‚.÷çÕ¢Ò¢N3g ð ÊûXŸ xÑÊÇ£¨|2Ü1t áyÖ¶T*-HÜ—‡~kÙν‹è2ð|¤c&­è¬qÎRÆÀ^‚G Æ.ð”ÍmY=ŠÏ[‚å¸^QéÒUº+âåë´pj» $+>Û1³£Kqòó©xõÖò• —Ÿ8ª`/™êÂU–eær Xñâvw=<­»à²Î'©#ê+Ò¦5üŸÔû4¾DIñÞ"µù÷,ÛbëË6ÏhÃPþY˶&mÃ`Æõëij‹¢°F†±µÐI× *.¯,:¹D*Â4À÷ÀÝÏ‚§ž€û¤ƒû¤`Oç,Ï•ý ú tì¤î,¤·zhL2"®n‡¹¤ßiÿ$ÒËÒË‚¶ÌRØJA ûB©HûkW ˆ%w#½H;:£ƒ!³ÃHÿ—ý"&‚0JsªÊ8Ç_‰sp´v'aõ9¯Ún:e‚leÐ…‡ÙËÓsé6W÷t,³!1E”T´ L± œíÈF *ÚÀ†ö¾(鞈ƒ ƒíʆA÷6«³°YßиۧloÉvÁJ1-|¸5©õjž®Ý“R=ªlÚ‚‰²MÇÙá3òq¶#@…U´±í<‘jGàɤg;þXÂF¢,‰±íØ‘¢`©ê¸Ò˜m¥tœidÿ=¾+¬v–åjÁŠWGúš­ûšìø$#X§]V~8xÙ*ÞÒÖä—êavýŸ y/Ga»äíÅ[ÛjêÙ±Úl°‹RÂ<]”qãVŭؽr*n…à•¥.x»•·÷qlÖH( [YŽÎèn<ؾ¥žj!v®ÜÜèø‘ÖÿÐÖµ–}n/éàò•Ìóä‰Ð<êù¥ÄÍ%ó=yZh>…–wÐ~U²À“§‡PhEý÷% =yFh!…Vu0î(YäÉ3C‹(´¦ƒYXò'Ï }@¡êÖý%ã=yîÐx ­ëà~¨d±'/-´˜B:¤=^ò!øSRhS‡ôgJ–xòš…–PhK‡f¥%K=yÍCK)´­Có`É2O^‹Ð2 mïÐ⥒垼–¡åú¤CË×J>òä]úˆB‘×u+YáÉkZA¡X‡Vôäe„VRhW‡Œ Q²Ê“×:´Š‚õZWŠ’Õž°ãÀx°Ø,¶:€mÀ°Ä,uKmÀ2°Ì,wËmÀGà#°Â¬°+ÀJ°Ê¬²«Àj°Æ¬±kÀZ°Î¬³ëÀz<Þ.ÔëÍ(‹aÆëó,ÛÖèæ.Xà\)Ä\¥®2_à¾^YÇìWÛ çBèÙ&œšœ–ÉlÏ·pœ¼làôlœ¾(ËbåÃb>«‚ôlƒÓëj:½.cÎÑVŠùI"àSÌÄw-‡ÕDŽþ6«éÞö¡ 7@à׎±à Êrgæºn.éÕ¦ 67Ô õk–iÝѸÏf–JẽA\Ìôÿš þoÌÔoÇÙ`&j4vŸ.ïÆY°»[Þƒ‡nùgX{¶ÔÛÔ>ŸãÚ¤»›hŸÛüÿ¿gYθœÀõw ôÕÛ6µCF¤*ê‚ëäTÏhOÕ£¤Ô¾r=ýëÒ™–˜.b…©±’/i-åSb¿OþP¿‚½àUHRYxa»p~•ÉÏð9}ÀgëFN¦óiå!2¡Ép ‡ šO(KŠ”ø“xJ2ñt‡Ç†Ï0¯˜æ$~ŸKoÄÊ Ã0¯²(†T‡TS“©ÔSÉOAHuÄI5ÛäÇÔ&”î¹ä{ò Ñå>jÎŽV™nA.»}V.ÝÚJ*ÛÐúY‰nŸaá ÷xãQûiç …§Sêi·†p^ÝòagòLMíèb”#‡Ñ_µðq%ŠŠ`8!F—¢ŽE›q¡]iÙCå±î54ÅYæl œÌYE¥¼‡R& ”Ë™)žPòåd.eŠAá7ÛKà߃ݢ¨£[ ‚ê–âán8É`—ÕŒ†Ñ(Ãhž3áç© Ï8C[ý9úBÖ[xªXk!‰©F¤¾Y¡}ǃÊ÷šq55#Îm“Ý­oPNST ®¹¢3P¿-*nl"n¬j]<E#tbæ¥e´<€éÝœþ;jLaÅÃܰDàâQT¿¨ê;EÎÈÁÉW"ãÊæ³í˜É˜ÕˆYÝ|6©:þ¹šáÆu Ê  ðöʽRëxœšìéù‹R ¥Ú:`÷ÐAê™Cô÷ýæ:’ÒCG¿ßCÇE8ÆÄöˆæXVºå®çyÞ`s-pÉÝ9•ð㱺ۼäò'Ok„QlŸ Òc>ã;eÇuœ;ÊëL½<#r*ž§Nƒ˜Õ4·mu:+áݘ#ö-^è& öüލ)ê/•›ò4<æÙ¶8/Cwä¨1)Fe³Üaùˆ°ʸˆÚCy¶g0˜[|æh\ø¬±ôùÒçÇÎ2ð5“¸b…[š»@J>”³bÁUÍ»²t¬Â½èV6Ñí˜ÿ Ç kU8Ú­uó< µ>Må†yë>ò*Yšÿùœh^s¢.'êxû°Ûq’ÎíWf´|Fü´¦úc?v¿¯³B*›pË÷ñss+x1šª—¥±f,Þ—?©ài:-×ÝmÚhYÚĉÈ8‹Y@}ž®'°âqößéö²Hg¡ó­ ÓrWhh…õºzا¿úœŠŸàÜFók½.7ê8FÚì™ >±™È”>m«.7ëêÙ‚‘y¬B=e"ƒü?Êþ>ªêüÆï¹÷Î̽1d$µ´±ApR­]ÔZµF–hm‘ÖÎ8„ãT‹ÖµÕÖ°†Eö}ß‘}ß÷MY…™ vA\@–œâä}¾Ï¹wf‚öÿßLfÎó lhyˆ>‡és„>Gfò#ª²çèSMI-#kÌJyž0ÃÔ‚q 3l…÷:ªôÓ¨Î×nu¾6å·œÙwÈì22+o$¯Pì«ô©¥O¹™uöÐt¦OWút£OwO3ÙÓ(iVÓïåŸ/̰~ÎíÕÇã¬'}<¼"õõ€Ñûyd_O&·ÓÏãr UrýæSÇ "™æk8:+f5Ãͺ¨έ×)s+ñèL;fàa”±*ñètÖºIáiÁne½Zü€™˜2óôH*?ÊC•í¡Ê_Εc<ÍåXúŒã¬åx2)i¦n'{Ô}ÅTx•†oß@}§yœQ4+*¦{ätO<¡ª¶OÎðd”ÝËÏA\+Å}êÕ^oÙð§à÷g¦ ‡)]/'íâQüßlO³Gä<nùWóð2ò_èqž`ªö^ì‘‹=u®GöÉ%0‰T/›­mlÒw©­Ã@œ×ðn³<`œÕVPUè'wÎ*Ô|CÇò‘w[õ5ªêëÚÕÃŽ½ýî p¡jh8±êa«w1ä¶Tìn?»ÛÿŒÝbo÷$hGM`På7:µ;lÉnŠéº$]>’e žÂ=iŠ5{¼5îv€€ª2PÃ×5±Ý!KîÅØ ݹ9zª|²0²äf¥;[…nZëÕ½Î=àöÒdK¾.ÑæaºÃôõÕ-æbý=©%sò°§2ƒ•¦eŒÐï;è~°MvÔ£ŒY_¯ìWÏ€±‹-×OœœCt‰÷ ÿ㔿<'¾€¨ùSOœCú$Ü |æ XÔá¤'€žF-Ö§ž‰(_…¥ž‰šÒÿ¶%x&êéו¼iÑó^eôk–pPîFŠ ¾É éðOùt”H¤ƒE¬ ùGØì¥ÍêʧÅ٧ذõS¸íÔÿ\-¶æmªÅÎͧåŸCs³Kæfkå?©’mB=}•%=i 4¥V{:4f*K £|0š­m™§Y»ºüK™'òñõÉâD»Aºü+K?½ïõy|Väú8ܱ;RÖϱ©ìçØRösò…Ê›b¿|££ìz1,*J^ —/†4L$+éWfÏ÷‰’ éXõOȯ|àõê–õ/½ré#"‹óxE–äñƒ_Yš:WþFOÙ„MD?õE†Púçꥧm(‚bãuß§Øx¢èÏΗæe˜ëÀÎ3¼pž1›s~ËÕèþæñø¬ÁB¹Í¸=å5cccí-Ù Î?ðŒhÿùžçÁwâÐæ.žç óX#Ã]¡“9.#{¸Î7Ž´g'+Ø‘×ü _@÷dXAé`]°ò«¹”X«6Ú²<¸ \L¬Õ`⦈·º]Ûê…iÌÛQ¬á®Ã¶áJ`¤`g™4®æ¹ã R£ER ¯m^¨” ê8ŽÚ/_GQ¿½EL€ÒPdy^ä¬ÕqŸœ(’¡ %' æk&QxLV¢dL– Oæçí^W ŸýMhEæ›êô¿íc,…?Ë<&Ì𣆩ôdæjpÀŠõð#V(n Wøv¬‚Bó õfážþ@N¬'…æ-½ü‚X/ -(4[†{û#=ü‘^þ ±ÞZXè¹%ÜÇ©P >ZTè †ßõGz*лZ\è»5ÜרëK¡%…Ömá~þ€ë‡ç…,apgÍå[ ´Æ¯J·+ÕµßÄY ;¶Ú—Å«}‘¾þvWÁWñj:Û%Ú­ÌcIç½á¿ ÜíHÀß-弄öBÚÇî£ïÅôÝŠ¾—Ð÷ýô½”¾!Ü¿Ëkº9ÿÞ‰ø{Y ÙnZ»pl}rÝW¹îÇ*߀`!ðÇ¡šÄ9ߌZ; ´–tr|ÊÉñONކS¯‡"üžv"<-ÿÂ9fqŽÏ Ç«NŽa•£ zæ<Ÿ…FúQ$ÑÎI¢<­ ¢5(¢$: 9„9Áç`­“àó §æÿA)&Óí÷¢“â‹òŸ\(“Óxi”]5–n‡6šB› ¯»5<Æ«/6†B› Üë¿i`›ØX ¾_xý/Âãü7Mš-bã(üAaöíáñþ¢@l<…¶6üUx 0B[ s~žèdÇ&Rh[¡ÿŽð$T…¶æÞžŒêOÆòü?37®é„â/Ï¿•¿cíÌ{`LÞ CŒ¾Æíýî³€6!ºù¸ö!~ ôïÞ¦%6E”h·&­RÌÉütlH$3™€9-pýtJì­7ï« jí$ÖZ>‘"­çúéHúÉD&æÔ›¤˜>$O%"#ü¹°ûçxd¼?¶Þ'ÛÄ#“ý±>Z£›Ç6ùä_`ƒž+BÜ eþLü6ø0µå³‘1þGl‰ŒÅW»È8|•Q*ØÙ¯RŠ¡:EÒ§Œé{å³4Š wM„VÇHK ¶£ÅÃñÿ •2Z7þ‡«tqØÚZ³¼¶¶¢¶¶_míÐÚZ ËX«»ªµZÓ>õzL·‹ŽRÇp £”ÕcÕ¢[P<¯4d^$¨|){ ~¿ûä+Êùëk}Ÿì”Ý ¿ßûä›Ùoâ÷¿‘Cw•Cv”5,«dGj ׳ äíÿIMâ:6 B“ŒÚÆõk‚·Íש‘*ÿGÅ ®Ø?jk߬­íV[;@Uì??Ø•7]ÜÑÿýAl2 OåN~Šˆ<ÄnEStÆÛUÔé1 ªhÐwì."ý/™à‡u/döWrÏ÷u—¬¾";‚Æ$~¸XWT± ˜t~çRK7Ld·•ÒAëá4-,sö‰}Ä—RA’Nã6e TÀ¤ÓºnëéÜzº¥ß°¼¶V¡¶vPm-ýRnÛOr݃¨ÂXÔ}ü5uWŸ(hÜ?Bk~d*~*£â3ÜŠÏp*>÷Tüªªø<§â þGÅW|¡SñÅ\ñŠŒŠÏBÅç  ™Ÿþ¿­ø2ö`ÀUXН¢df<ÛëZÃùöt8›õnYQã[Üð´ô;@:ÍK@imw›c»`»#é$wq’½œ$"ÁF®+ÓI4ª¹#vœ 4[9ÃëíóÈåå‚w&[~JylòñÅÐç(Ð)‘}?à§ÖˆAÖ˜Šë~‘5¾è¿»Æ¸Í$¸™-ÛkkÅÂÚZú’ç¸bgy]åŠw·ó‹B^Loç_ºuÌÅ¢ôvTÉõ â;õ‰Ø’³QÑïR(Ô`Þ«¯ðÎÎ ;Isx8uvUAǧ*íGX&9’æ(}°=ôTv`*Ìäzêá>¾?Ö'Cý{¶˜™Žàtúꩲ!~צÓ?•Ž@:r „•«STTÖ2cñ3úßötÀZãÜ…ôBÏ9ÉÛQ¨ÃSüÁ…±)´£~X(~žêî*ŒM¥àîBýÎð40^›FÁD¡qOø=0Y{‚•…æáéþàžÂØt î-ô<žáî+ŒÍ `U¡÷ñðLpal&úž ÏòÆfQðP¡Õ&<Û<\›MÁ#…ö3á9þàÑÂØp9 ²"á¹þàG…±¹<ßœ”›OÁ…×½^à~R[€*d7x-¼Ðü´0¶‚Ÿ^ÿ¯ð"pù±Eü¼0û¿áÅþàŠc‹)x²°aW^âž*Œ-¡ð…9=Ex©Ÿ*¶”§ ý}Ex™?XÓ8¶ŒÂg s‰ðrðlal9…Ï6.Â+üÁêÂØ ð 5™ÂŒ½ƒÊ+ÊùÇG€+EÞºiì} è“ z0ù”óãš>A囃ÎàðÇw7ñDl«OÞíW•ˆØh+Õ_ò*Õq>FÀ?Ä£[!–øU*BÜZçpœ¥McÿùÍçO™m*ÔÞ ¯ôߪÇVR k ÅÛáUà±V¡~ß8<Ö»AåÊÆ®ˆÇú¡¿õÂêê!ü]lQ…í®ni©Ý]-úÅïäÝÚ½ÄE·û¢çñš=ÓyEù=ì~ð°ˆîf«W«à¦Û†7EkMº©Üšœ&ªŒ®Ï‹v¯YéŸu%ùHå«{å£lCô÷•ª*ZÞ:Z8Jå¨h¯ßOqàcYåŸÓÂ@-pDD—î¯eÆ<\‰'^åu¨öÕ½0 fˆ þ–‡ïX1u„(æ?#[|‘ÂâãåÔ$T‹ÐnçÐÿ¶OÐÜæ}%ãJð*߸4­éO1X¤1GkÁz-`SÖ(‚ðIáU¶ ˆêç”åmñh[îýa€é,S¿”¿¦A÷)_>ø yø;ß_ Ý)븫˅™ýß!¥?̺ߋŸ‘¢óâÑ]¾”"Ì} ¾)z²q&˜uapœœ±y¯ßÇ -®3»øPÚŸ![gÆ}9l/?î‹~n¤Þ;`]?Mú‘þ¹éÉ:¤Ý|^j© }—‡80¨=éÛÝ>'‚¿•cÒèY =JŒî£Ñ~9²¬¹lß\þ_$%™¬äQÅ'FÓ ÇvûäßSæ^€2˜Ï½¶¢üš‡6eÚ6éÛ'ùÚj‡xtj_zWø”u£ñ>Ù’jÄÜ-‚ŽOÍO‚SÐ)%šD7öò)Ó¾ÇéÆ{pKúd+èण•P´ÇãÑJD듎VêD+•O¦ˆOþ 1>wÚEAh³3íÿØ4ö (t__¦ß«»êú½z¨®ß«'ëú½ eú½êçSÛƒ‚Ê5*Üz,<@;þœcî9Ø;aã¬/°=¸Ž)¿W/)¿W/§ü^½ªü^uJù½zCù½úWÊïÕ[ÊïÕ;ÊÀÛŸ2…E¹õ ‹H{ÐR}ÊÖ Å§Laõ|µ²Ç—6…5fy®q{µÇç˜ÂÂ&S|Êù¼+|'2(±Ã´Æ£{‘ñàtÆ33Vö{ˆ&ñT!§]ëöj¯›ñtd¼×‡{ 7ãÙÈxH:c¸²çÛ‡}Èxh:㥙+WÔD“Îx¥ ^ó·WûÜŒ× ã}>%ª2Þ€Œ‡¥3þÃu2žÎx{fÆûY•‘ñ.¯ëöªÊÍ8Œ«|0zçf¼ð¹n¯(‡¢²:öOÌ…ã#}ØÚndS?PXí^(Œ­¦½íb¡øMx?øeal 6·Q>Ãëñ× *­+)´bV¢-†=þŽË7ŠñLmÓ¹>Yæ¡åù XnñѼ«Œ¢y‚#>ù”|JI€’ SEâÑÃh¡1ið îb•‚4øMÿ;=Â*>wO!DËÐû<‰[Ðÿ¶¢Zî÷ŒZŽO×òR¡vGx­?øUal-ÕòkÌäuþà7…±u¨åŸéóx[× Ê6N-Û°nDÖ ¿“òñ„4O˜ô÷S¿§|ÖÑh‡Úó)ÓWÇ}²=Lb}ìcwòqvÅxôÊ?) ~‹Àÿ‰G<™ÁÙ§¦êÇ@LñùÑ "‚\õ-JÇ|H´%·°ýVŸk$l¶ÜòR𦿹Ð|ØSÍXœßó)öj¹˜*ªÿ´|íVbfhÅ">&vÒÇŒÌtgÉ%"Ç©àI”n†’ñ4˜oÅ× íéj1«…xš¯^f¦Ñ/9è—ý’|ö@ý# •7ÂW&`[nÐH“ŒwIÆ+’ñ‚ÖHw§I–¹$Ë ;µƒ|qjå'¢›]†³MÓXWÆË¼Œ™ïƒþh‹š¡Ã9'Îà6øDqÔ.·Âõ¸Ždì¬}..pš‡bÜMÍsOÁÚÓ_ûˆ:Ó\ÂÑÐþýÒ'”-ÚÕ>C)úSº쿹êf¼Ä~Ý¥ûç‹ùçO t³†)A.Ú’(Ô¬a9ÅÈqDP_N´#ƒÆ ­!‘,½äÓySøÆ×©Šõž¿õujoâ"ÖYME@ó¬q8¨øŠ¨×£0k|B÷úü(ËN‡£‚ÚN!w·Öçc¿±„;¸ò¦Ú¨"C@à•È+Ñù͛'PÙ’W”Ë1D[GCÛëû¢åh£ƒÚY(,ÅY!«A²ÞWÏpzYÍGéhŽ >¡»¡ IT 5*yÅV&¼qRÞ€‘åù,Jæñô&B¼Ý­mÛbûx Œ°¾4¯¾‰9ÐÿÔŒ Êûop÷³7¸û¡QDà šD]-hE^®ˆu³ä£ñxq¹¥Åº[˜ ô÷1.X¸ÎVéš&Ø>Bg¼òÉdt†)ÿˆ‡Ù÷üò©øïb•œñš± ‹†s´Â*=ëÕäÓ0ZéSg*Å_hÌ=ö°ðFÏà†ÃõhdÝ’…çõ4ÆÙp³ ˜-iÌ«„éĘíÀlMgâ,Û]‘É6gÛ'p9<ì•?DË;Bïaož÷›ç} l‡½,šÑÞ{óìoɇ ©œ쵇ÑÏæ£òáxôª/í²ìÑÈ«efñ™\¬eI™‡æÃÃÑž0ÞµXÌ¡4`±ÃêíyÄT•yJûX4±XƒêªNÄFÓ¡ìU§³Q•ÚÒˆûk<Úßb÷ ÏPGR‰BñÖçtMÏ%}^xãê·Gõ_Ų91¨µg§bôwüOõçd‡ÏÎx´¯•:þ>‡ò$£ÛóÊ_­’¯,Èý›hkn¼@ç—W“NeLÙ1)_Tuy)U—W8n™‰ª¼ &T…Ÿ£1RíN(?GSIÞä’¼‰¤õ·å¿Ó%aé—·3Kñß$x8+ŸÞñÒ~ì~Ã.©ÏÔmûwÕ¢O#ÚAºP„wäEö6ŽìÈKD¥¯x_c½ÝŽ<ÚÃ;¼“À5 ¼3O.F"ûiñ²ëµG왼 ì¥Ì&µ™´&´Žê¯ÎKD ¶#ìUò…Ȣͭªðî«8Òõ°Õ†.ø°¦@>¨ôm§àÙô4Ës´yšž£ð¹N«(‰[C^3׿óáÓö¯ÊiUO T˜ñ}0Eq›äÛB­¯'¼ÞÙÅ&žfè±õtø®PŒð„7à u/ê#=á¸àÛHÁ+…Æ(Oxž7Qðj¡9ÚÞŒÇØÍ¬-ôŒõ„ß÷G6ø#ýbï¬<àç àlòG6ì‚uøÆ{Â[ü"ý€`ôk½? aîo·;!^Rg¸!¡™nÈ@h–2šôy?¾®f /dòn"À[=Ÿ¯_=ÜCÝÍÒî¦Æ+Åì!¾Û«ÅÔ ö7`ÃáÑVFuÑùÞîÙ>MSFí»ÇF[òY7j/ñ>¯é³ßˆu¿«0-¨ßŸ)ú?ð§àý|:–-ª<޳JÏѦ]ŽW¿E—ç|}t¡çÂŽtÖäõE‰"иåâ‰_rFÎjïèW9襱¢Õq?åg¼MZyYôCWUc-gÉ2i²Ñi3Ƀ©’S'mOžfPíÍÓÌ3^íBª3Üfuú–|1 :ÊH.ÝG9íƒßhŸßMûÓ\‘ä‰2O0n>†Ò'>êÌ:’[ÉÉÅoÐVRr‰¾fõÕ8ÿõÐjšp¥6'èy†ubx|UÉ "Y³Qah+ß,*±6TFgyS÷ψ_y_”™Yef]ŒWnìi•峕«p„½J^ÛËJÐñ›e줬–4Nr—(ófB`JÒsØ#`æY!ÉÐy ­„‘cö”¸†aéØçÍñúz5Fñ:xvAù«ýu4jÛ7((_ Ú__Pþ@ûlîŒcÐ'n!ðõy _ÓƒÆÇô57hž¦¯=8wÍ z¡yI£þ©‘]Nð취рs¼íB=½¬¡#@öaŽà—Ïç8@¯ò˜¡˜h¨C&Vž`àE—òûÒ oR[kþ¥¶–þ·«­}»¶–Âò5`ºÒ©ÇùÔ ÷q=h_pêñeÅðKõ8zÌE=Î^Ssûšºõ¨1·_§xáÿk=¾CÖó¼9O`ÍS+—²x_žà¥.Û­`Ôµ)X\Áh¸•›.,¡`4꺚éQ7«eC¥5ꎠYl®¼;‘Œ± ü¡ìAÎb{ïš0f?Æ¢âðW< -— ã¾\Ôn…JdñàbâI’ΧMÖXûÌgÖóúNyÁ¿gâÊ6`³\%þxñÇWP~LUÐÁ÷=TÌ0Áúê³L9à =@Ü=ý/y@/€N)fz³w˜Ñ9¦ÃŒVÉyf%[ZÇîqf.âg‚™Ç%fú¬ªÞ}–e¦\f¦b—›™üD™Ég·U&-`I‡•{½eCGÏ8é°8$ã,<,§#‚AsÕfeгž¾V½Lpþ¾M¦\g2×Íö&øM¶]ÚgeOšM ¾]ˆV‘ï›e•…Xu˜ù‘[¨}-ƒ3ihD¹Õ,ó27]—ŸÜ¦À»³ê2[Û80T}Ëð ‘ABƒi‡"IdlÏ$ÁŠ–9Xþ -¤ Û7›÷“áìd–Ñ?â¥\Ì„v­lì4{f’Åe™Ðn’%÷›4§;ˆü}ƒŒàx:ó~éÌOÔͼ_:óÏ32O¨Ì¿p3?£2ßÌa]íd.Ï›86Wå §Ûnϲ¶¾ZkeY¶¼d&“ªnU&@RäÒáÝ_‡~ºüÊä™Û‰-š|mÉýõ âïþáø‰Œøßš<ËUüïL ¹c+Œï)–|”èNó[Òƒ kíH#µ–O8ÒHdi¤?%"[ý,ZÔ&Ný÷ˆl›ˆlS€¿Æ©Û‘a%ktÆy [Ãê òùxt2ž»Î²øK)ÀÿÈ~ù‡| xAgÙ—Ê—Ó’/[ý `É—Wã ¼SJîå ¸Ig÷6e÷ßxt ²«v¤mÖ¨÷¸T~傟æ¦Xii›nPJKç¹ yNqó¬À[/µR¯´´M\½È”´ åðƒ>þþÆwÐ,°ÿ— ¹‚óŽÜÕkÄà.8ïýWSbpÓQ™‹Ž˜ÀÕkÅà¦[,÷e:š#7Ñ.¥£Õƒ›a±ÜWéh£háxt&¢}ŽÖΉíÄDl¦Åò,ߤ£½DÑ^ŽGg!Ú·éh¯9Ñ^“¯S´YwÔw-ø”HÀlD¼Ìo¢‡+“߃_g±Ù–z™¹âs(Uʉr¨iì y¯úÒ&Ak}C½±fmÐqõ(„8›ÅæXÔj‘œè’&±¹ªåÊ-%„³6%9EêlA˜· ÀO8%zJ¡H÷æ]8Z}à#­=Û;êšNËi—¹H«§•ðœ´þ#ß¡´¨å¨[wKêÕiŒ©õÖ6d'-Wȉ°·Õ1ý¦Ñõg€Qû +-îÑÓÂc‹šuŽlë<¡Ý ñYq'µÆ£lMÆ–[4’±ÃBÞ 3é.¼‚:E|OöÂ?/]fiòH[ZJÖc· µGt9*ØÇR×åë\!¯#ÄB™@ˆå] ¶/ €oï”§=—§½ì2‘H¢ÄÔ)¡¾œ~_Á½:Ä'T r5h ;™Â(¿òx<À‚‡ÃóP¨_6SsÞq)¿Q¢Zìø‰¥ü§¬›9ß*¿§ Ž Ø€G3 ó­‚[6ßJ¯¢ù¬œaX)ÖICМ}LJ_NÄ#x“]h„V™¯Ì[ˆ<ñàæ$e;I•yˆÿ€þË ø^Aº0+(gQ¥˜-²³ØWïí>oÃŵµ–ÏòÊÅ;[¯‚:GX*hG‚Ÿyˆ·’º 䈢êëÝg¿õBn‰è’È_5d{6ÛE¼t¡¥1Ǽ3…œÜˆ‘»¹ˆP£‹§Ó± $![¸X…P§å¡ìVqSïsïr¿-2ñžwÎ_¼È³¢ÜÜ+PCøXÎ̉‰ÒõÄB ØŠ|4ún¬EF—ª‡ÛÏDh¥“\éJSÀ¥.Õéì3"9Ìáâ–ŽlÎR"çœDª9‘æ¬Ò“–)ϋР'Dé S—Ù<ºåî¸ë w0µãÞFÿÛ>‹µ{ž¦× ;n!ªÚ- ½ë o÷»bÛiËí‹9áþ›ºü(¶{îP rëe5›‚ŽMa°)Lžm ' øéw„½Qò†VþŒ (Q‚±"áºìHD¼‹øVt¼õ¾ÆGaoø(d·a–ÎÎ)«´sK‹ýîáGt¥y³¢üMeêýMÈ ZØ,ˆ°6À§¥ÄÊ·Y0 —!V>‚ºÙg½'@½Ù]˜7 ù.Í……©_ÜŸlåä üyÊëÒjnõéjê½!E²ÍÊþ£M Ë½[™ m·J¶[aá§y•IIE¤±šYOtƒ‡8^ÉÌzzé*êÇcL´›cÒð<«¥Dm¨¼5¨ÝÂïÆ 5Ê{s;—ÜŠ(¿Ê‰Øn æ?£;-åjò;þh·Ú’Wæètš}àD¸¯Æ‘æ˜tš\M¨ºŸÀq ¦6SiÕUšk,9BVc¹Û¸Æ"M˜ÆD·Õwºm­Õ‰}ËðÆ8N7‚xºî 'ø¢á4]Çr›d¢¤ –Ïñ–’Y"ÊùHv¡úWÉ¿°3M°LÏ:£µœ^NlŠgîJ]®ÔëÎÜ6åmöÊUðûpDÄvXr¯§>Úi±Ìš­´Á Å-Ôo£Úi`–Ž%e¦eâ³ÙÁì°Jå ¹E½éŒÑâ7EäT½èû¹ñèf«ôÃët¹õ{Èù¾BnçÖŠÔvmnay’j±´¹HÂs£þ=œîS¢&IŠÈ:ŽRe¥žäÕžo¡öèÉèïëÛ€”¾O—ûÛUz¼²t¯Å2Ll7“þwô%œP Q°·¢G –T°cz¼t#-“ÇÑÍ-C·¬_òj|Ì@ÛlD>Ê‹ü)z 'rLoùÄpÖ&éÏãÕéSü›dù +k¥—;Óp,¶µùlråV¼°”¹X< è•‹ðý®ì¨Ë%?ëÀ\` ‘K %Ó…wùånY.øÙð ³*#Úéh«]Ò/˜´üVu±êe MJzâøk3âŸNÇ_çÆ?]7þåzÿr=7þŽï¦PÃ)´Ü‡4’–)ª@Ȇ²Ø÷(›ÑS²‘ ¿c“Xe•LÉ6˜ô7ãõ<¶f”ñ|ºŒÛ@*· ,wnIoÀØÙi„7D.ÕÎ}ÈᆦSìÝIV§“Œ»¹W§ª m¡‘õy(%#ëëNÉŒ$d:‰JÕaÄÀVd¥‡bËðÎ|¬1 xÝ‹F8™" nÓ“ÔH ÊéqØ÷>Œ;`6X8ÇtÖóz® CöÆÏDÇ(F«‰††ãQnmŰ˜òÿs*=”SÃç,Ñbú5¬(oØÑ”çÕä èä£G¿°ÁÚàbOfÔø¬[c¯¬qÓ=‹t½h´|4Ú—vª“¿°‘nÉ—¶á4ÞšCÞãyš¸Uû8OÓÛhåiF‘v"O3jÇò4ÏíÚ'yš÷Vm²wÅ{yeüšæìeþ𺴋–žËFÝ¥3øªáp)_(.¥Ö ŸVárÓ W«pg7\£Â]Üðyîꆥ wsÃgU¸»¾ Â½ÌºkÊÔÛ¬»4ÖǬ»„ö.Áö[l›Jöãß‘·£Ÿ7ŠG+¾¿›×•דöðý–jòæÆ ù0Àh‡ŽoÚFà{«%GÂŽáËgZ×àæmºÂ.Ûƒb4[êÜea h9´ßçØ ­ÓóµÑ¦k:‚.Ÿæ•ßIk[æÔë˜Ùœ—sžmuÒ _jFöû¢kü,3»Ëªà,ä$Ǥ'¼MÙ.+^²Ë ;Õ -v¢ñš°˜ÐtS•+».ªg"Î~Ÿœe:R&fô³¼èçyrvÀÉ<9§àTžœ[ðE^É~ŸÉ5•‹Lg~zJ«³„\b²…ÛLiYHÅNgC¨ë;ˆ[:º&QQéF±ÚZ¹Ê|X Ö'é3ôÞÇy=§i¼7ÑÎÐx¿S;Kã}—¥£Ÿ£UÓ€ßïÓ¦Z^êŒÌÏ­IuÆî Xc¦›} nAãщ;Ã#Ð3î6VìCÚÞݦZí 7ÕûNã|ÀæZÑ*[Ô/jŽ­êµÃ6õ+ݺÜÅù°, þà °‡*Y!†‰±•ÔU%©F:Õhó`÷£BU¦sî©2åóÚs3~¼ŽÀ‡0Pߣ¶ñYå¼Ku“:jV‹ê&â˜)ÑYòº}ÙÝYß ])§Ñ’3jQ™WrNHù™™ý ð'üÚkð§Ìì¬ïïà×]ƒ?cf¯þœƒ_ ¾Ú̉ב!|¹Ê¸š¼*yÂÄ"µ&ǵÜñ7B°E¹®õŽGø~°¥¹®¼V}Á°¹®X fØJf¦ÞL<üfⱌþ[[ë¹zµ–þÿ¤¶öÞÚÚpm-äE·Lˆ¿5—å¸/™ñÈù<,U–ßšÉ?ž*.ÃŽi(?’ý¨QóæÉ’|eñ*zb:÷éèˆÏ\geŸéìIñB^d»ßÙùä)—e=ýY0‹½oÃùbÀ΂›ÁIýIU»IUë²FÇJ—(]l yt3-˜…û;è¾dî¸Í>¦ýR—_1mtªY~]ô«ÜÜ{Á*nl,¾Ñå7?À3ï“ßÂñeæ!÷²žäÑw•¾1ÜÊÁÞÍâmççȱ vnFmËhÀ±Ç`[cÁTɾÍèÐ~Nøƒ± žQNúƒƒ±$ôÕþà@¬’‚CÆÏÂ{üÁaØ ˜…á½þàˆ@l/G<ð>pT ¶‚£Þ›ÂUþà˜@¬Š‚c¾æáýœÑ~ Ž X- €BãvËðA„RhGì[‡ ˆBõ‚áðUv˜Bõ>9û#Ûk3çÛGAV£\g¹ŽhêÞ÷·o;f‚XÏÓM©NM h¿õ'bG)ƒ)xûÈœˆ}DÁiýácþà{Ø1 NÏ„ûƒ3±ãœ0ÿþØœˆ}LÁÙÏáþàœ@ì,k¼ÝEøp^ ö ¬i|ƒEøSpA ö)Œg¬‰"ü™?¸(û µÙ`™4f[s,sµª-¬FŒ¯ Ù:¾†ü†V G}x5ÜøÄNXr îœ6ZJ˜’ØŠ{,8:;§M–‡½¨"DR„Ž[:À'¬’㼜l¶\å_"-Ìð¢ö4ˆŽ[€¢ ß·Òo&8+Ìñ ¼Ñ)ö²W˜,Á2ú! ›ýqP»YÞº³äN­üν²Eĵó¡¶ „PñÕ<í¶¤@4Ѹá§4Îݵ­–Aô6Rû6Ü&û8Å_T‹Ó-Äò—H­6/Zžß®s¾üU$e6ôשlä­*Ñ¥½ i@»Ì¬,¤Dä]„O–vÉòŽÛMùY&­%¿ ¯ð¡WQä‰0 ³wÛRtVºæ§¬u VºP4Òv+¥?¾8 ý:ü¹?¸$ûœú~i@<>é. ÄN¢ëwp×ß^s2(ŸtšðIîø'¹ßŸÄÝñ$ŒŠr§ÿ}þ©Å+ÝNçíè¤zP*‹G?E‡Èþc€ù-5ÉèíO­’:{—åºÌ#²›3:;JÕˆÈJoÜ×Yì“3 ÅF·`Xk“QsJÝ-Ê™:Þ‡fë‘Sþ‚ÜiĬÌÕçüÎsu»S~9(uÅ'ØvÝòå|v0¶€a½Dtj®:ú¸ÐNÉ.bà\ýίÑ.v—3€K\à• àR¶vó«#3`ËVíž«ŽÍ€-w`°¬Gl%à…«Žä€­r`G2`«†ÇŶÆõÍ€­u`ý2`ëö›è„\uMØz61¶aàË/ØF†Ñ9êÀÍ`b΢A}¹} ŸéÕCIžkµ˜=:›âËê=¸íL€È„mS{Ä~ö3Dÿ3Ävâß‘§£{ˆÃúB] va{ vZÁŽê4Ž.01#:3²û>\ˆ&›—ža¢Ìy×äÕ–ü$#»Ï®É Ýç×dØ©ÿ±ÿÉfœÝ©:ÙU£…*-¯Ïã qQw&(<, | êø:4ðu.hâ«:蹤ËKz¨{~¢¸{¾x½½‡¶×]æi Eȯ¹Œ)ÙÆoô2/ >²ÑþoÑa‰h·üÈŽ&³†Á­9<5s€‰Ò³Tº«(ÝË4a“ ×Õ冻\8|Qáºt2@έOQ¤†›+»'«0ܦóîi|/o:*4¯“7öZ°ŠW€¼ëžâ‰èY]5è@îKv t8`BÕÑÃ@Xŵ™æå¦ìçÑFP=j‚b„‘]!hkÄ“ ^L¸$ãœàAod—éD5‘Á¼”0|’ž¢Â“ìß‚n*Ãy!aø47|Y…ßsÃWTxº‘­#ÞL†cað,#û4 7‡ÁXD<× V¨à<'ØCçÙKi!ƒ±z0x‘<¢‚‹ì ZÊ`¬ ^æû©àr'ØWWÙÏ Ò*cÑ`ðj'8Q×Ù¿Õ:cÉ`ðz#û'od0¯ ßdd{ ž-h‰e$à_J­Ýî%Âz* µJ»—³YbY-½î%Âö ¥–^÷¡Ë«%Õ½D€öç&]Á<|Q±ÄPË¢‚yù¢b¥¡–@óñEÅZC- fñEÅC­€ f§.*²ø¢"Ë2n(¨­Íw¥vó•Ú3WjWkï¾ZûÏ«µÃ®Öî¸Z[sµÖª­% ù>Æë~ æÙÞÄpÝÊõ&¨Á-ŠøZv½¾Õ`SÕV’¯üÅxã4Ž€3M¾J^rð|¾+MXžãe‹M+&¯E`ùÜ‹`þêg(Àwf0ä!£Ž6ÿaäý6ˆxœꑟ!òíùŸYÀ`Ó?d]G§„ó¡+Ú­á/üÁ•ذ{w…Oûƒ«±Ó0uÐ Ÿñ×bg`Ý8`ü!|Ö\ˆ…Aã€ùtøœ?¸Í;‹ÆO»pµ?827V “Æï aIôõ1 ›Æ_§p?¸UÕÀ¦qÀz'|žäüØy˜4Øt¾àn Ä.ÀŒq k€_ôG*ò•Ã÷/ü‘ÓþÈä¬?rΩ¦Ý©ñGÎû#üm²î±‹`¶[ö/•›ò#©cAnr ±¦1i¤ÓìÜ6°s_úƒÛ±/qd ˆ×üÁØ%¶šì°sƒªäƒ*±sO1;G'ýÈÀ¡U±sOƒ;¯D^Ž9ìÜÅ rwžÇV|œÙ¹ŸÌö&Bå"ƒŸ«±JʺSŒéÅ”l3t§Î-€¢&'¬´ŽOøfèæš/Yù·Z|V Ý%ïNäBªäžÐKþ«•ÿæÁÏCðéSK7}ÖˆP¿­ù>< Wñãr ºâqÙ:žxb*ÍÀ|ÚRB>‘pÞQ«ä“•Pt‘OUF7yñôtÁ?kŸ|ÂŽŸñ­ÎO‘p™ã‡£ŒÍö•Éÿ ųÉ’x6^«?gé‚?î%G„ä%ùr"Ô»~"zÊÆ»s"zX”ô®¯k÷Í4Nj¯­M£±QðÉ>1¨Ïrº€]ô"ôD¢ø QþDŒUPáÝæz" rÁÏá~žÊh?O¬Ÿ‡ñæ‹ÊH?Æã"ø'®µ„\"Ç–Û|Y*ƒvV€eB±ˆñhX!Bƒ=Î$)ìÁ…Oø#áÇ>‚}AÈár³´F]Ö»uY½ëŒ Á(lÊÌ€Í™ðˆ—–ÛšÜ‚d¿æ9–σö·Ôªµ\›£ ø*YC·'eÆ£¼HÛ#d”´¼‡Ý¢}uWƒÂ‡D«¯-ùQæ(øØ­b@k·ÃŸ\Û Ÿ^Û _¨wÞ« \4rzØÚ·;àB~Í:Ün¡¯©›»‰oé«k‘þ}u+2®ù-wúw¢y•¼‚ Y3{8ÏÄîEf­µ˜îdì¬;ù%¯»õš›U±Óåîv™rHØ]ߨgÃÞQC“4¿Ë<,¾×KϾ›æïô³O®>FS_Š%ûéeæÊlß $kÉ}6SG•gëá~ùØ+0ÇQðH¿|VIì—/çààx™Ë5Ü>uw¹¬(õâf<°ßœrÐDLåD]NÖU×FŽ ,Xu9E_µ´œWàÑR§‘ß*Óu<‚wêhȺÛÝ3õVßYr®žÑÝó2S]ý-ä×îøÉZÎGÈ@nüÞ;?÷<Äêj0yXFÕ0¿¥…¹´~ýþ´Pøµ~ùšá×äk¦_»ÂS=†Ì7º¯xÔ¾›õDt §yÅb^$ ?Ðáµ§½NQiíƒSÔ­º³œ(Ÿ~¼Ì0³]ÇÊB-ÁkˇhЫÌK ÃÝn†»!HFkDB­²„µÌe4§­™H[Ö1–öýoûf2¾²€“Qn§…´;Û(½¹¦wdói›S‡­Gás¨Yl€-ÿìËŠŽÎõ·ÙíPŽÐž¥í=2·´±@e„ïj+álÂw$üKñèÒç6üºÝ°£ÑËæ‡ºrÁ)Œâ²!±Ù-Ã6ׄ´m.大;gÿ#¤©V¬ßª|\€á,«n+›D“®l£?ÊPaº×w/ \ñË‚VÖ 釨ÖˆbR­—±¼^BðKz Áç¶ÝØÓVfõ(%ŽÚ§H‰£B‚Ýö ȼ®yïÍHgj.\îõ¶)5õμ1zÛ™¾1ö»©í¼°õ·þ|XŽ'Jßµ±XR騎ÑòÚ×Ö”´iÛ ¦$ ̯c+¯#º~Ž]ÿ®fÑúÚ_?®y·H]¥¯ü‘ÖLÞ –¬%e3Ä–·@ð݆0g=Q}n…ÿþ¶E‹Ã‹< ïæžÈ;R.¢_ú#ƒòy¸×\JAZ%¢tÄ`P.ŒY?/š†òåïùù]>Ô\7§ò³ÌÁ’œŽ!×éî“üc¬·±À¼Ž ow——~Eâv%z¨;K 5ßíòWlŽf.D¾ïî Zõ·A…ØwÄ£ny™GÀy§ »”†ÝXé*bÃZ1˜¶6ˆÖ…Ûµ6ø¶HLi ´Fwü)ÒÛv2…팶¡ƒFéAC“…¬ºíêéPœ@9:GàÓöEž¥m «gtÕÛ`÷ƒý‹¨ƒnƒ18íf¶ Æ pyTg͡ܩ?å­Î¿Uþ"tÊH”ž2¦fc!;&@üùåkÑqÙ„Ý“MõÇäo")Ñ0†w¦çãÄŒùøÛHJ¨T¿KSMÊ ºrwÞEÍ™¦Ušf|̓q•NlŽ!Š8úöʇl»ì‘Dtƒ·;L¼…|´{÷}àà‡ÚÁmþdq¥©w©’¨lΪOÄU©‘‹†s³uášþ 5=ÙT{V¶‰¤T šp7¥Ê4%£Lu¨.æ2ÕßÒT“3¨žå’l÷CúeÙ+Û%TYþ/®b£,Q˜E¶SæÊi¾…†ä_k®ü%îÿ&ðl9c•Åc¡qÍwQ¥Iúr¼t8 ºW N‹«Ï—t¹­¿® 2Ê.YŽ·cÒ¨wE¨{ƒ‚Èh»¤{ Æ¦Q£j¢‹—F½§P#\Ôø4j‘BqQÒ¨u"´ðú‚Èx»dáõ@ML£¶+Ô5)Ú'B+í‚ÈX»d¥ Ôä4êcê_¯ 2Î.é_¨)6ÛíÏ àÞp9ÆEÚò_ñÐh/-Dl{òÊ·Báà "ØÈeG× Äy§µCØ(íãeWp¡ VÉK‹¶i›A” AqÁöqt´©h5&k0Åšå+™åÓbmÚŒk(b )b·lÝX#E«±©X(ÖH»d¤­ÅFØ´?!Ö$ÄZÄNÓF¸±¦‰VãR±fS,hiÄÆØrÇ™‹8Ê`d6:ƳP´ŸŠ³œâL°K&PNãm(ÖJÄ^„wÞèx7ÖZÑjB*Öf¦{t#ŠˆÏH}›h51E·›Rï.Jº -6Ö–qŽ•@¬‘¼óEǺ±öŠV“R±Q¬¾¢¤/ÅgÓ¾†XGkT‘'>Îu\´šœŠõ¶¹©©mŽÐíCCSó'—þ·ý'æÎ08Ìi6®QlLù] 6YßcÈu5Ôè´yÈ_E¾Uºé´Zf> w8«åò®ð7þD»oüò·ÝbŠ[@ñ°#ðò°|’b³DPAyW?¿N¯¨'(H©Î´3®O("ÖÿY¶{}B€æîõÉËMc“l@PèÙ~³9j¨¿•fuïü¨Ú çÚ°ÂÛØgØo‘ö b‹Ä3l"y3(Ù@³Ý¸)7Ân¤‹ÞŒÿ¦TߎGç€/Zà0LN9>œÄÂ4çd¶~<ˆEi̇±Á°¹@,fnæ V¹,Ö*¡ŒÔϵi¨AH(Msï£Dl¾-?ÍÒ4Í—æŸDlFÄ‚Ò4§]šÓv‰±9¶<šånëh#ôÑno¨²2}ã}åÃò«ªÅWùÚ`lÉN)”úL䵊òרL5< pU†Aó1­öEWPlÚ¨“þ–@N,ÒÙ÷r2º±qdX~Ò%¾¨R©ÎÁ;ÙZŠfl<3΃«%ì¿ÒD Ïÿ¾hg']+mP »6$årÐb»ÚSáoýÁx ö-^x’Ôò¦§Uͤ"å„åìà¸ûÌÄsÔ?4ä^ˆ' ü>J¢üYÞmFäGÂìãùÙØ[þ#žŒmµy¯äÜ 9.*¶àZ‰:mcr€r;-ô‘¡×G'pkÃAî@poCGÀ€w‚ÜãY1á$4Ÿˆé‹õ¡ë0Û½…&äH*¼-í£þ2=½RVZG5ÒæÑmJ‘XJ_S‹ôe0ÅÍÚ¦¸=aiÚ,öM·H4D.‘/²Åãs¤ª–!n° Š¶˜dtT~%}æµløSˆ¬NAfµ„EŒ´õ$££ 2:>üöÒÖhzü(Ñ^W)v/.ñöj+Äû Mt’ª³Sé@‘ÒçÜÄA[Y Ä÷ô9©c¾aÿ¶©Ÿ¨ ÉW;ÿëMcÁÈ8lã)ð6¤h·…¿ó“Øwpà÷†/ûƒ{±ËpàÐ_ñ÷bW0nŽØÊQÈ4žú¼C„ùe0Ì/ƒô÷j®A¯äšô·6צåA½–á•p› !žØv›Ž+eÞØ›}u–5JÖ1 ° µý( v®p¶|ÌV?ÓŠÒŽBvq܆£›p…ÌÍ|gÜf#—Ìpòqjݤ(?Ëxo|ƒ&Ò\(¿7òDb—HUí–ðU0‘»Jí³? ~®õbµ<ЗçwÄÊs«Å¡€Ñ:Ü97x8뜋·ÊL6í½"ù$ž#mW¾š7†Æ:½õfÓØN äÿYŸö9_ký²fzóiƒxd\~ä6¾ž>N€±Mb4©é‰l±K¶XðSÌbx§HäbEXþ?´ÃWŠ$¯!0Å–DºóxYý?µé"jY{{}Æ]àˆŒs÷&¦¤Ä|‡ý>»ÉØC¼ÎöIpÖ†©‡'Pìn±¨bb.ÒÍæÕ}ÄK&µ\‹£ÿ£ÇEj*ðµ HM_KŠŒ±‚õÆÁ»O­üÎ*b`ŽhœÒ?zÀñ5ãQ.CÊ<Ž—/Íád™—¥O&‹fíM¶»7Õ±Ý.ß•e^~õÇzI ¸”Y\[K/Ó=³2äífã`g·,—Éž]”ößûVÓØIL°ÞYéõ«Oò;k–Â}šréús– û¹¼-e¯7…|ÊþU<²Ò“,>š#blùk<£e©3÷ÒÔÁ¿»Cß,åí•À9;óCòaH˜Ûl¸ª_:šãKõ"¢õOGkëDkËÐ.Ú,†4 -JÑbñ¨D´éh/8Ñà"“6»‡”¥¤\ÿ?,6ÒÞ¡S·Ã²uÍଆÕyeGklÞVÚÍʧ9‚§¨,u1D) vE:nuHgA’jH–2P³”ï±oƒ4Lô<Š949Ãó;® ±ó¶ò’9,ËG4+ˆÔÓìþçiÖy‡úƒzœ^°‡µÌ `=XJ¡#4ø€6WÙ¯€»&Šü8º¤É,öò±ŠaŽ­„s¼ÿf?Q^áúƽ——ïxAì\gâžéQ–{nÞ¼ ýžhyÇܘBõS¨“)ÔfÔax®0~*lCìàÒB*vŒ`Î q¬ëP)ëºÙ‘Ž 1Y¾Cÿÿ»®çÝ‘Ü~û€{Û¦®KÉ5Tj¯y9pk~Óû(ÄfØ ï1Ñœ¸ÝæòcQÀ°˜Þ­åç×´$ÖðS¨ù¨Ô^GùC³¿÷´õ6ovm€ÆT1ÇÐr ÈË‹Ô ü4¿vGµè}ƒ ¿êëwÈ»âÉh?O2zTT*¿Ótx½›†Îe› È]±å=ñÊX­-ïK8EûV1Y­Bo&ÒÖ3¶äÆ£ßÙl¸ç~˜>âæÎC¶Rk?D½ž¬ àÃD0Ž'Ïc xÜáó—­‘þžÁó®3|â‡Å ŸŠGkm*r":'?Ú½>žÎ² ß}Òü ËD¶Ôþ¼ù_h‡]I„Ä£Wía9ŒPíʳX¦bO¡»ñ9§0¸RÂj/DzêDƆÚ1½BGëò,–³{ V€²ÔÃðò¢:f‰,ñ2ÜíNJ“¼í¼c>H>ò"™œeR ÐtvGZg‘ýHÜ/Ø,vÕ&v04ÔÓ ÕgMü¹ùÅ ¯’ké+âÍAñÿ0öàmÇþØ;òî S$‡²0!º€´Ÿóâ”÷^ì4ÚæKÌÄiJQ6‚$vŠ;=¡Õ¨Þ{¥zï½Z’-«K(QÅêV/æRÅ’,YøÏoöUòþßG¸Ý½-³³SúŠ‚_¢¿ÈÕz ~Ï•¼<1ìÜÂzDÊ¢¸2² tßO(o)Û(ÀQº×Xé^ËÓX‘Nk¯¥Ó“ÒiúE˼€ð²ÿ´}ˆÓö!¢à3hÉhn hÙ­#8¼yÁ8^V’›2‚Ѿ›iŠƒV0ZAh“é´XšNÓ—ÒŸœ™„õ‘;usþÁSãJ>²=iŠ‘.L5àß®}ãŠR¥Â<ºÀU¥"7ǶyR£„ýH²ƒ¹_%l¥¾¹©¿Np(²D¬·Áóâš< N3Ô}ЊŒ¸pB N7|¯¯VCú?²†Zÿ`3ÞBP°åÇüšð³¨%üætC$°AFI%±²§`ã¨A†mõ`Ö8ª·H„Ì-…Ï…»_ÀâÒSÀNj¿m'՛à ¡9¹ú~Tý`b÷=8»-ôp*%;Lwó&D%‡Šð³kÆQ׆‹’00(•Ö£i½âYµ„SMlÇMœxï&N¶›¸+·‰›4q:Þî C£žú :jް{jâc듺j¡óDtÛ|ÝU·›ö3B ÖìrK`|(‹q1d ÄÔÂv œ)æ€2Ê}6Ê•|Jšià,ø?À¹Î1ì]' ”©6ö ÷bl¢>U*†R-³ H ªªÙáT³Ctv 8^Tµ¥îQÛn8úª‡ÊR²|€A‡ Ça¨GOßâóØ£Íäõ¨½¼û°eu2쓚rø8€ È3fó ,FCŽcç;)PR|LjjMÁ@ 5ÇÀáöQ>ï0ç…üP(T`å%ÿNv8 äE¼£¹†—(} WB¯¡W/Š€™j”Ÿ¨ª°g²AÛ-UÞM»™8‰@[33~“Îàè[¼pŒì ¡Ä¯ï=P«Ùj©×W5+KÅ:úZUª­×0âõw4ù6l9ár=+×i8ÔËõš:lÖÔ|B(·j8%8“Á[ð:&ƒ·ÊÓÞvhPUr@h‹%U[g*ÿløídÏäCÃ.-U寔)€©ƒvi» ›Êåhuª<5ãI¯§ygšbÞ<Û~¢8 Ÿå¦Ð¶¯å¶í<¿ªÞÈ›¶gÕ*÷·ðÄÒÍ9Ä­3BªÜô†xñ9˘Û˜.Âò”zú#ÆRw–kÿ–3Xv5ÁòQ.ö^­+L òYÄóþCž÷5,ªyÐU£ "ktÙCOµ€Ê-\¸ 2lÉ^wµqôVijãé¡Òú8iØvzª´¾NZ=¥õRiýœ´=™´‚—Ï Ûð€§|¤ ¹ Ï6ðlŠiÃnô {±¡¤bDö(G*6J—cšJÅÆ¢èCÉÏ©h­S´– >“•ý ÚPhi¶Ðd§Ðd¶îT…¦¡Ð²,ÒN¡ºœÕél]ÎEGѹNѹºœ¯«… st¡®n1àVdÛ±Ô[ sMjå Z™-´Ê)´J—kœBo£Ð*.TÎûŠSh.7(£³Dñ’ôžJû–Â@^¼™RÐ0^ж¢ºÕ\¯6Ûê¶ë2‘­®òè«'+?jˆ%pÁÁ@¨Þ±Ö­×å^SØj„ŸIg2Ó õ¶á(ÔwÃó› 1ÿ öê-yì¬#ç豎ÙÁçWßå΃Eÿˆ8ðQ»¦Íä'©"ÖüYvCš³!Bñf½›ñÞU¾dïN/Ñ™=6ÜHb1âcÜ ¾ì—Œ7ˆi 4±Qô9 *è(aÀYýƒMs±a¹ÌÜ+ uÉþ-¶ýôóíJy¡ ½ÈßÛ¡3ñ8Ð|ǬfM9ù4¾9˜Ûÿ$ÿË~?ÿ’D¸‹aû:F…]D¤“ÚbÃLp]±£n0àPôd;åvÏÓ¿U‘5KD* •ÀqjyÏðèyÆn†¯Éƒ^[*jا¨½¡éY›ÁÑ_Y×VýÙ[õËâ™ ¦é¨Œc> T}o#g“05·ù‡~U#®‘½>¢¡»åôú¨ÛzaœP Q“U³Þ0\k!&¢¾¨Ð%žw-(tin×ÂB—þ¤k£áè P#¿^œ;Pß2ðiÿ/> 1P‚UD Ü ðz»fŠH—@pÞYï‚ûËÍÄ|z¼ßk\WŠ  4W ]_o3ôæýŸõ€þuù<ÛZþ/åqeëⵆünDz’c0Pœeoô ¾ÝÂ"åõªþ‘ÍÖn|ÔÕ¾Aô Ñaµ}qz·üYt£/Áx£¼s†‹]»CëKe‘z9 ±fjCï”Ö¢Lm×ú‚I8Õ:`µF3˜.Wáù(ÖÆã8­NU´AgR_kíx·Zk¹Vx{Ù©uœÑ âœ_*øAÙ:óœ:Ù5ÆïVã8Ô(“ÄÒ¢Ü($Ôlöêö*­—c R¥_Pùåc Ú—ÁYüE%¼¾›æØõ­æ{ŸBWæzÕモ€š·æÓ,­Ô÷tì /),_RÈ/…µ˜¶1øã怃ž qYŒy¶`Ç­ (›hŒv ̆’Žá8pZ™ÌRl¯Ð_ûjACl´t ±FFùà¼u „ŽÇ»Ä1x/ê}PïFÇὨ&:Q¯ÁðÛiÀCÕ3lå3âpì|fåú«µNÿúÝaZ •ÚA o’! µƒÉ«% ¥W@ÁÝþ±IXŸ’œ|’i}âp²“‘ž2¼ê²ªB•9Z“ ”«¨DŒ¡:ÃQ( Â¹î‡ÞBT"]°Ë€B9‰.è*Žw'šO‹ÿŠô„ÎÇ{ÐãÙbí[‘žÐ¹âxOz<_¬WFzBŠã½èñÃb÷O"½¡†âxotÐn#G¿à½Rùs8®0ýJȨvŧHBsöða'ï²ØuV‹ô „‹ã}ÅÅbqN‹ô „.ÇûÇ^Ž0~Ѹ±TÅÈx‘CdÄR/ÐE{Eo+¡ óöèÈÿ—³Ým-ÿÂ6w¿ÚíŽ'mwŽCí'p„Ñgo…Ä©ü‹^ízûÔMÝFèÎÓã~ƒ½#o„pŽÝ+;¢þ»žá»a7D±òi†@d ï ÞÞVcÔp›dw¸¹%Böäní…nímwkêÒ¾ôéÇX~= \ã|ƒÑ ð ÃÛð+Þ¢–39ôüË"¼ù^ –«Í+šB:2Ó ï°ºPŽVN¸½·oÞ>9é¾¢–_a+]ü–µÂÙËÕ•$ïÐ>>k8£U eví„…šÒä=çÒÒ†ƒdÜ#Wî§ì[I;¾æZE;þý®å´ã/2\køÊðíB8z^Qèò>ášÝÚås»JgŠ^Ô)¬aR‹ÛAC£·=2ý´zã[JE£)õò’@Xö£s?kbë¼”Îm¼J Ëò²ø:ÿ®¡¨›,m9dÀëá¥iư­ÔÕNïÛKE?eŠ€+>ŸÎ‹ô{%­¦Sé³Ü¨ CD|…!;S*d$vê'B‹¯2dw-‘´÷ @Þ[aÄÖ6HaTDôêÈnX0ßH²B?”î¯Eû þˆ­âÒ{ÌT¥ëå`.âÒC P9l ”Îýhö0/Fhá“@Tq²ªG²ù£‘?Vå¯ròòBù<òÇ;Æ”ã5è¹$‰©«œM‹Ël¹ŒV½ÏÕ°"¶£%QÄ—r>g¡d; ÃhÑ1þ¬*Q£Šeðd=¦—Qgî(Í€ŒKŒ&îឬ—«´D*Y9Ç@øŽÛ¾5¨÷ª×kþõ®Õœ æ¥ÚZ-÷.yG©k­|b-lPy²3º¶ª3pF•x¢.Œ;ºmÆn¹U{V<ö__ïeŽõjëh´>éZO£õ ×qF^ʤæøÁ# IÂ(€IYƤ´R¤|£j/ä^Ñ'j˜šz¦æ¨MÍ~PsÂpœÄPåß¿“ë#¦3vá‘^ä°^]ÎÙ씡l“¥òs¶ÁÛçd1íiï²ö·(ÐÐ~…±O[ÈÇ`t»ÁX £Û Ý–F>Ñ’ñO4ù¸Ê[—“dg²õÀ¡×¡õÀi›¦=tq©G|lCaÊÙ}D»ç(s½^Ÿ³­§Ór€€iðÍ\íŒzh‘@u,ÃôÖg,1îoߘÞí’8lšM=Vê½ÑÖõ¥È@(ñ@|½Ø›mÅ7#C¡äñ¡ôøI[í»‘aPêø0z¼ÕVÿydx T÷@|8^{š…÷5¾Ï ±â…,®ÚÄ‚Cú¯ìÈ‚¿¢ƒžŠ,ø*Gü]2:$ÀÎWþˆí0ž“¯'£CU‰ØNJøS2:L%ü%KPÂß’Ñá*á‰X’Þ*øà[¦Ò†x_úpÜ‹¥°Áw2U<@Êè—°l\P&pÀW&à@ùv<À¡82¦ „orâŽD_wÎ"†Ôåbu@Ü%‹xb.≷]T&‹x*<–dâ:ñ ®3ä¬,bçtÍ"†¿YVÖØÄݲˆ—æ"^ sz”É"^) œA< ˆw9ˆ×ñ.švbÖ´«É"ÞÄ›©ÒÝ@Ü=‹xk.â­ŠÊdïÄWñp Þí NñnCîÊ"fËý¦#Ï! ¡»…^¬Q‹Þ<¬„dfV³ëP]ímAãøãbñ…ÈÈ@híˆô˜ÎÓžŽŒ „nÇGaX÷2sÎ’Jy›èm:ÓŠ>ëL«î4­ê $aw>Ê9ñÍbW-2:üXÄGc&‹žZdL úžsñ3ªXë¥EÆæ¤Òï±;²«ì‡s¹sÎç>\Ê}¸ÀP„2½ôj‡lÕ¥Zë7ÌÌ(¦Ã†ü}"¼WDG*ö ?j`J5¢fì-:âï3JŠ]í*áóòõDŠ-cRÕOÐWø‰Š'\ÕOe(ÍÈDl¿:¡tjkh‰\®mŒˆt3¨ãÝ 9– šØ¯# n¢£Í`OæƒLÛ}AÖ¦CDZ‚iŒŠÎÀ=øa#~P…lž›‘;%bGŒñÁÓ¾‰”E'{B3Àtš¹Ü‰ < Ù QV)õë|iˆ3øT²jÇ ¨ËÒfM5½ƒà AõO?‚©Ì«ní‚Y¼i8mÝ’©}T¢8C©/1]³áUTnãþƒþ€ÍßlÿÔqt@ª*³¹á°õyXI,ØÚG5o!‘Z‹/`8\* 8\¢ñoÔ˃4ñéB‡1RNÓ ”ûT¦«g?Ú‚ÍNsJ±kî£ÍÕÅã)#ÓI3¹ÙçnkvCN³ùºzoTÿƒV_vºû2L 2}s5û¯Aã†(¹‘SËMÔ2Ø^©–[ùÕDÔ!,ŠCLº2:;ÖqiMÓî!»AÞHv¨×e Ø÷¡™5Ž"MÔ˜m‘uµÆí1PKÎ03«É<ÜT!Z „ ¥‰Øi4b„©B´Ròvž€²eü´!?…²,˜~ö ÀFeÁš†Ÿ=c°/Áѹ‹$B@€1™E’Ú9‹dOZ$‡$AçflN‹Ç™nbç‹Æ#¥ò3¶ÉÚgÄÑRñÙqÙÐÚÒi¼D/–ŸM†–¶+v¿Àõv[â’d1|<Év`ˆŠÅ}˜‡7¦Š]±M…å Åë{䣜©ÝùRˆ3…“I W¹‹ 2äÿÀ¯ ”ºlÈ/Ô…JªÜ?d ¹R q꟡2.ê{…g $áL03Î&«ƒ®'"µÐ[Áx--÷‚â«‘ñPç`|<6š‰¦’ê/U˜‰+|¥º/°T—þ/h¥ÓÿE­Ü/ÈïÚRÝ!Õ=gÐA£Ê?oÈ@ÙÊTRÝã³Ôsx‡“³Éìz2;ä)¦—=ÊgÛSùFø©‘î9¥*ž‚Hwªé¢¥¢Ÿ o.ÌÈt{ã4ù’Añ4“Cïr¤Ì ë´'2!PüR|QÜ5(Îz"›ñ‰ xº }šs¢ñD©ü'[Q·qýn‰ž‡¹­ÓEÜýÖÃ2¿eÂn¾]¼» Óyì[Ô¾ÕÍdk¸n¦½qݰ/à (F.ZZïd‚ûKfc¬EÃ5ñÎ&ôŸì\— pƒªHV ?ÞÅ„”­ì}™o¸’öÍùM…l8'àÚü•À,ù gíÏæ±Xj©™iCàLˆ#ÁmP™iâNöYåÜ@ÌÓ§Œœ”׫´Ò¶°-ž¸†Ùl4+Nƶ>' ˜§Íâþþ&ê[Ïõ}p­‡­ÝÕïÝCZI|]ˆ—çÚdåF[ü$peÏ ²z§²z¸‰³+ÛÊf*+Ÿë|hŽéóz}ëtÔôÕ¥ >%|À޾6iÚ úIøŽ ·LV´oì‘'E*úHMõ#4‡O+cVÃΞœ´Ž áð«Ê]4“U8ÎÞ£q¸ÏŠÿÍûC"ºÕqxwË`í¦[FË·/ª¼G8/m°]jÚ`ͱ‚%ØÔF»ÝרµØy­ƒêʯúëtýDTyŠ]Ö„#Ÿé HÅ>qË@NÖÁ3]šŸ«ÜH(ˆPù®ì °:Ð"·¥pæÐAÛE]nÝo¯.îzÛ…ê:l)dÑ JT¹ñ4@ކȥ¶‚' zNUîŠç”ß`Î8¦Ei±¥ûrLSrXÎ5¡¾x‚'ôHÍ>ìÔðþÄxÖÁÒ&²Mœ>E“£5{¤ŒÕî>ÃÇkö{®—µ¢N{än-±rº5ÅÝÊs&µ|ªFK¸ë¾ŸÂ/µ"Õ],ˆzDJebÝÀ-…Té¬ ±@lCëìZ»SN ´ µóØUß''¸X­kSöódw²?õÒ Ó«ù|/q_nt£a›ÝÑNX+°¸Dy’E·ÎcW [ÝÑ…ÌFw*¨mîh3š(üõ–ÂGävwv•ïT¢0³Èïý+!/Éï³fA&d懥bß?¢n÷ŠŒ—Uûî˜o‹‰_[à–‹Ü/3{ÀêS[ #çàíÚ‚¯4µ â¥*Æ'âï6늙EÏϬ0ù‚™š±œÃm:¬.ã–+T Tø*¶öWÝr›Ç_¬ugT z˜r=çdnxi÷—£‘rWe.i7p¶$õ†'Yè-\‰B—öˆkG¡Kß+\ÛÙEëN¾h]eê>¯o³rˆ¡I»áÃ=Ã’‘ºÁ4O— þzH;˜šè–¡¶Š­Z½†² ’cî’çä wÉyÊíp±DZ*:10~žm•zúöœÚ9öörÆ ¿ä&Méw1JõFÂ)Kݗ諱ÔsÅ-ÏÓ@ÃJÿ!}W^£ÁÞèÆHLÚ[ê%J.ÿØ`ÁWÜà š™PìžøFG¯üÈ]å¥ÞÇš\åUÆ`o çº7¬$7œitÓ ßãfÔôo$ï]#[³ÓÓjOfƒy‹Vy±¿tò¨}¥‹§ÝøÈ^ŠaŸk¥¼:pdFµª¹s[ÀB§O¶Ò¾žœ]«Ÿ]똗ÕÌ¿?‡W5Øc.{äP÷*o'·²‡‰a$ubÁÉp5¨u—á¡þ‡K,S°S0ªp’Ç^ 'yäÂz‰°NõÀ– è˼šÌw Í÷ü÷K<´+¾eÞq>[j·{™§`:Ê­È–krd[éQ±zWgó›ž×Öx â°+ê•^”aëåbÂçØá‚h¹GÕí˜8¡SWyT});î‰c¤ó–¬çiLO§õgÒéx:Ý=¦¹Îà ·|8\ê×2õ{™úmõÛ…ä—íŠ^–¿ŒVû’åZâȺ™E!ŸE‘RùH8Å¢^&>íûAâG‡Ž3³7ë[Måiì²-à™ËžY-Ä ò»¶§±mÕ}h{þ²†ëçm¦rF ?µAÊ ?•?oâ ÌôpèÜ˶ÝÚ¥×Kò¥»;‹ÝÛAØ/¡hÂN³U½B}óÛ¦^Á`׸Ótîž©Ì3ẻxâê¯D”ýLA$ÌÜËÆ/4½lüZÓËÆï4½lüIîecÒT—W×ó.wp¥XÈú2Òcöù3&ãöeã¯ù²ñ•ÌeãoÕeãï3—¯©ËÆ?f.ßT—Î\6þU]6þSÝ5ÖÙ²^–qß8#h—}v¾_s.ÀzÃóÊd/Àú³‹½¦wƒLûl[ãAÒ”¹cGÛ»³ˆGñXªt0×g׿"®r—É"ž„‹Ûî;ˆ§ñ`‘Ä3xOñ< ^@•â½YÄ‹r³¯"”É"^†ëÇÛî‡8ˆWñS®Î"~ˆ÷eÃõ7âĆñþ,âM¹ˆ7 Žš94ñ6\?Þv×8ÔA¼ˆ‡šp¥ê æËŒ÷3rø+MÌH³wÔ Ÿ+P‚½Šå,léàö|³ñ£Rù móó`ƒèþ  ÿ=ÔèÏõe[ `hÙŒ2e¨Ñ¦l—¨‹1e $¼cMù0܃ÙÒyªŒ$C‰Ø(tÁálòã”ü‰Øh$É&ÿ'%?•ˆAòÑlò—)ù¿±±H>f:Ž(£³Ú¤Õö§Ha÷_9‹Ùqžh­¯ÚjBƒRjBÏ „ò_‘•"»„i4W‰|$‘|áŠ&d(*µv¬º_¾¤•$+/iJè¤é8޼ m–]¹Ú,aúk?HuõIФSYñz7ˆ×'B5Áø$Z1ºC¼>9êŒOÆŠqÚ¯_»§xý|>ÄëóÛ¸_?²ÅëíÑùµ¦ü ÄëãMö'{ÆTZÐ×l7ü|RÍHÌ{æÃ¿>V!2?kï/×ì54«EWŸË&ÿ…’ÿ–ˆGòyÓQ¿û}0ö:ƒ]SD_`¢ÙŸaÏ ëáÈ”@¨W0>T~h"ê^qãuÛ 9Qù8Sù8Sù8 EÜ‘7˜njGþ"µãËáÅYJ* x(”™6Q¡¶áúl›† M‹ÒѦƜø¢ ¿ÿjü¸TE¦F|C~#ü[IeÉóìÝEa4¦™ìh÷’ÝG³ V(MMC]檂ä—m!mÍ4§›-a~ð+üjuÌß4Ý”¯àœõ@ôØ{÷W< B üްPÎïïÌÍΕ,ââ¡B8¬bÄ/!y‹»/>â¿—¶toÈ=®)`¿~A£1¡±Wµ÷ZŸc¦ò4€¸ ŒÄº ·L€+üì/×sa“â¿ÉÀ„OݾÌ1gâ6ƒfŽ ãj87™c¸‹0Äf›Ü¤®¬œÎðÊTó²K9ýµƼò y8ÄÊN¯·,½;ÞTŠVĸqæøR“˜>šd3çü%&k`u²òhé[£â ˆpꋪŸØ{búxx½!ÿDí_f¶­çOJ‘×»•öWù„Òù+²~«—™-‰ÿÄ/û¾k±É‚•ÙI¸ñZ¤’:!»– ®Tï³6”ŠÍw§b{ ¡ëוuÚ»‰pw·P쮸©*7;€ŸkV¹Áµ2k5׬ènðè$Ök)»&¸ÇÐ „],ã«;´rÏÊ,þê2÷0Áþásð{”æewèq)rr”¨ò`N¿‡ñiŠÈ]ðOMû”‰¢i§ UÝáÝ¿;´½€±W b´Šä ṳ́Ï,Q'g3 áó2>Vél)Ýõ›9Š^˰8u±´t¡ÍuwÑdPÛíõð•^QË"°¨»J<5š¬Ñàyko!PÉîˆMUvkªŸÌó5ŸM-ÍËóÉ^¸‡©±”¯ljèÇIã zúIŽmæš m•´WÞNðObûñË´.ÑíQ´Ñ”›8ÓæQ0oWèáY­+fµv!zrÂkì$u *ìoy‰—îͽ÷ŽsåóŽÎ.g70©ÚFXé'cƒZÛÎd7êjÎ\Ðìi³Y¯+j —_[õ:Z¤²4ogšw0Í;š:@eRO±¥>(Oé© åõhÕnÕxnÕ^§U{U«öëXc´ºÜŸÛªÙúà‚ó`n#›ÃàáLJf,Í-”âáø7ù87ù„3Oª&Ÿ¢·u:§©çÐÔ–Ã#R[ÞŸË#ødpÄ%+{blÁQxóÆ®eò+vܯÈÿÏ9ÄÊR6DxCC§£5JÃïÛn£G鵓@+ÆåpOÃy!y¤±[ŸQýƒ®,ß”u@¸ÊÄ9)¾ÚäcÒKÂ>0¯Æ¦;’+ºÉ_µ"_•Ï(08:eAù'ä—Ût¯[S&žCŠUÔ· «;‹zæy+Àó&b+Õ5¶_Õ•¦ãhf—/„;‹dEgP'õ[öÅðÁ¼dÅÁåE“ÛX,صñaÅ®çXwh¯ê4ü:·ç$´w“\})ª¿éTKƒñ;IOkÉò^è_¾ÔÓú½¦üløï-h ÌŸö£øG.{¸± –ëÏC·wÐÕYL…ÅÜÔ@ƒè]ôÈ4˜ÈM£Ç¾A­«™(vǧÓc¿ ^£GfBýƒñô< èî¡GfBƒñ™ô<(èé©GfBƒƒñYô<$èí¥GfBCƒñÙô<,èë£GæBWZÇçÐóð`^_=2—à?Ÿ ©à: ¶ÍßkìS¦VéwÝ®§ĺ¯ÕÏ ùõD*~Ì”ßH„DüS~ßÇMù-|Ÿ0iÿ¢ï“&í[•GL—|>Qy”¾Ci½½7RÍ? Iñ£DìæÄ;Ùde ûÉïf“KÉ¿OÄŽ#yC6ùo”üDì’ß³»”Ü EoZ(N"cc6¾’±îÆNóÅ]6c2ëù26[þNp#g99Þ¿‡ÆdG·Ò6÷¨ë]Á ˆÈmt;º¤ôÓÒŽ]×&ÂWÜÑ9ò+n*a®J .Z'ž¥…8:ðþPß²¯ B³›N×TIÒÑX߈¸7,eéW¦Áí_ÿ2}·rç|„×èTtj v¸ïa‹°_ÄVa¿‰"LU,‹ÎÔ†æú+Þ¯™Žºò]`š±s'¶O0ån :azAï†9‰}@2‘7 òÙ!-=£Ô:=¿N§6<<Ó‹fªÊCEkþû…fËÃC¸ó…éÄÁï˜Év(§oï¨s\ý2¨ŒþuÍn«:›'¢3Ô{lÛÑ)9øŽ’Tr—ÄÛ¸”)9¤IIƒÍóÑÙ(‰M††M¶‘'3¼qûË»…ýi‹å¾ÏãÝàãqÇZ-úø‹ª÷™›ÑŠZæH‹ç°21„¾†—icékD™>޾F–¹§Òר2Ï4#˼ÓékL™o}-Ë›I_ãÊògixÝÆ¶¯èÅìP»hµGÁ”ã¤M}ôëBÑ5³…k´giW£ÌбGÕ˜ÚMgˆ¹¾Êç°Ú2s$ɽ´ò#…®L%Gaì`ÉáZ•Uœæë—‘TÊ> ¡ƒ{ »P«åôbÇj%tnãs,íˆIe;#ëDıžÄ)ƒ`%AG3­kG}O£o¯œÎâ9_yr&¾òå,|r¾Ì‚Ÿkhæø2k>ǰ¨2ïÚN¿\¨Uù‹µÚש‚Åv±ªüòc…"´Ã˦°Ë´õùr•Zñå~P¨½NèW;‰;¼Nbž|[«ÊÃIýõVùà €Öeë>^(ˆ–‚y”úކóœÂUy³ÈJn ä׉”÷2@U¡ äF­Ê(ÜÞM„ Å6ßQÌ[ð";`´Û7©ŒZO‹PºØnCí¸³r¶ANe© M.“uŒ|VeV¹sÀTL)óÖ°ýÓÚWÄû4mñÑ…Ñ‚õÕO™ì¦ñ” ªèþCdQ 4!_Dƒž¿GB“‚ñÅô˜üœ·›ˆ¬nšŒ¯nAo+è "K¡©ÁøÊŸÌ-"K¡éÁøRzžÌŸ*"Ë¡™Áø2zž4ˆÈò@hv0¾œžçÍÕ"²"šŒ¯ çyAk›ˆ¬ „æã+éyAпGDVB ƒñUô¼(Øìá„~z^¼ï‚ˆ¬ „–ãkèyY°àšˆ¼-Æß¦çÁæµÈÚ@he0¾–žW[ Ð"ë¡ÕÁø:z^l9Z‹¬„ÞÆ×ÓóÚ``ºy'ZŒ¿CÏ냭i‘w¡w‚ñwéùÝ`ëuZdC t¹0¾ž7ïߪEÞ#æ¥0þ=¿üÔn-²1êfÄ7ÒóÆ`áO"›¡MÁø&ð2Û­;÷©er/^òŽŒ€R Ÿ´¥cÄCñ3&ÒÀŸíÌ9æ&,;T‹Í]nmŸ[/€ Ræ³Ä}ª&ö¡’о@<Åw± `)R\à ùö‘á²C¹-±®tL$+Ï™‚ÝAQ¥¿LTž'žéWg© ¡ÓÊT?‚ü›ü¼aY0n‹ X¨Û¡GŠèHÛÖ¢b¤ ½“ífÞ4ˆ2eòóáSMceÎt„@&H¯·²7÷{,¡þNãô2Ѻñ~×à by3Aÿ¯}ZSÑ­%Žÿ©x£)C‰ºøE„fôáØ™V‰Xƒ{>ž¨‹Õx¨—Pë^ þ_E­OÙB©§ä—p%,jPÅ—Ãg‰×¾H[1DÅ%8à‘êx³ò,õ‚xî³"ª¨]øt.Y#>íÇ)€Mqû-\ÈsÌÏm]Dds z†M¨_ Í, Í* Í.û‘þ5ß ÞØEdK¦D´ÚŠm üHPö ¯÷mùÇœ2X:ÒàxÞÅr¦ô 'd<òœrÔ¹Âõ|ƒèö˜ø_óÖ¾'ÿ7ºÝHF©þÍò~¨ô;EI±Áv‘ü? Ì|N~/ÉÁ¶÷Èë2\òûu±u^(£+ù»ný‡ò‡ásn¤Vœs Æ*TåŽ52s07—ï™9ô9Ù® Zð^þ4•• Ö·vÅäo å}G”´«ÜÜÊÍ®ÅY*•û«]î¯òïv¹Ê-­4•‡3#mFÚÙÌ+ùúk_Ë#­+÷ ^Æ‘IÞQ á Ø8¯L)#l(q=.1oå$£ßŒõ¦¡ô±Y¹š¸'ñ܇žo¨çÿÄsOz¾¦ž¿€ç^ô|]=#è1 6©O¡öïÛ#îûp´òm7}|þ“~Æ?2e鉨U³ò–.8,ë þU€WÙàpñNÅŠ²fϪ.%‹sÃÿ*Q„Jºó8Wó ªyÕ®æUù;`âVÐ)_¾®ZqÕ„ƒ½Lvõç&íêD¶=ÿ°+ú®TUEÏ(—ïE¨w¨T¶Óî"Ûª^XNZŽÒ$UÔÖQãO áI÷Ci&g58myiÞþwãü2e<¥%Ó;úOZÒ¦üBd©žŒ-ÕãKuù”èá–™ñðE¨ÄX*’.Uòß4i¾šˆ¥ÍØ蜵T`Êa‡:'”CÊOv  q„·®ïpĤ\HÔE,ÚE´±‰{¼ qÁŸƒH¦‹pg+Ê¥+;¬Wy‚»¼:Ð=ç¸[\¦=§¼º•Âlh+|ùÔW^®s².e®çøþü9Yñ²h÷ª.¿CLOpiWþË‚¯#Q«|­FÜ·;õóÈï"Ö!Ê ºò±ð=Ø…à´Ê!^ÄSæ¥Ïl#ÊO_Köó»þ£7IrM’˜; šÖÖ6Úâ·pîó²x¦Ñâà\ÔƒàXñ"}x„sÁg.á1¿R¸^áX\¶»AŠëL»DÒNx.îó?±ÔãÛ¸0½pK]˜Îe?‹lÈ5ŸÖYnüBz5y²Ð%¾äj(ti×eGv¾Ðå~Âu±Ðåq»>äð] ]¾']— ]yOº®Xy¯9GÎbá¼Ë¥eÚb‘û¦h³]Ì:b1ôas|+_mÞ2F­X­œ)íñÛž¥©W9¹ž ~ä;"\‰œ+Ê ¢D¾GŸ"ìVûbcZ¼¬Q½5­+üZE¡ºšÛЉÆôÁ1Ýñ¬xºâ{7ZõjD‘pƒ:í ×G|› a+®&‚RKÚS$+zÚÜ(+É^eÖÚfÊ „½ô\³t”ò•ð•Üë¿I8z½e!«Íõ®ácKiÌ.³w¤+­]ôÿ̃êÜhô¿îZ®´GÁsE%?O¬j7‹v¬ºxwK~J›=,fnXJÙ•*³Ã…Õ ÐMKù³ ä¦á¨2„ û$ ö"ý ë°[Y°Û`?“äP MgÁ^"°X"Ö`Õþ دl°_!²4 >ì-ìM#Þ À:eÁrÎ F´ýê@~Gc—Jd¼M¦e¼ )è×.þìNßÕxO'Eãrûb•ÿ¯0ãÿð±ÚWä«[ XʧÀƒÒÌ¥½<ïcQçÕE‡[±ÝòU^ ÕÄûZt\â´z•Öߪ‰÷³ä7áÑ^:õµè_1Ú«ÅZÔDZVôvñ3Ôâ ù,{k ð=Êaà ·¢,Û_ÃUêy$±ùÙÿ&¸N>o|'Q9Ør(-À»†Rû>´xü`=¾r;ØÝ×A¾œlñiÅËõ³¸Âžž“îƒ.`?+üåŠ/»:Ècㆿ ‹NÐÊ2^¸|XáØéÝý‚P|…º8cìx¿­Êq^— âÖÃa¯¢X§XÁ*Z±1Þ¢–ŸfÏn¨ßNªìãaS&FÎYil&û`{²A¬¡öL·E…_8Sœý‘õô;G)Âûxø£»¥¦(®£§…"/½ü/Y{Š]¡œÏ;‚â©ÈŽ@hg0¾ƒØŒDP{&²3Jã;Áfôöç°+Êä7 aãwå”ð¹ðUûP>•è0 iàEû2Fý<t}6’„†â ÂQŸ‹$¡]Áx’wµ¶‘T TŒ§èqOPF꡽Áx=î ºÛEvBûƒñ]ˆ8ô<ÙÆwÓãÁ ÷‘H} t(¯§ÇÃAßc‘=à²ûã{èñH0/Ù^Öã{éñh0¿4²/ð¸ßÒúå’¶²ŒO»ý3¤QÂgÂ×lÒ¦iÃ-¤¡3øaëÒ” ºv‰Èþ@ðlA|?*è÷Òdœ'W±RóÝ_æ@ˆôI‰ö-ù_XßþÇÖ—~úîê°XÔZ¸½¡£d|VyéXõëtÚû`:û÷ÅtšRåtÏèiNïLØ òå¼ …ósÂÊÍ AÞFýÎÿVîmVn!ÌôûÜyþó•¯Áϰ¸ÅŒë0ÞKÐÜíÜ7ëË\Ų̂yÉÊ!š@ØKnW ô ÷;öNñx““êlOûéj×a¡ºþ,÷6Òï3t÷e­ñæ¸pôÙNóÄ»e®gÄFKÐÿÃ%Ú3p" ?îgpóêy^~=øàÆE~ƒñX~÷•ïù*wÿ×i¶~»ÊmKª[‡ï$cÕm½^€Û¡ª<¯Ã¯Îw‘Æ~Eòø í9-¶c*hçý5©Ì÷Cù$+o>ùÃd•/öV(ðþ/†ÐOÃï’©:*âTþ~ÀÄ?+艬02Rðw%vP}tL­ò8E;üÃi~œz©®*ïk­?)NWåÛ£‘³~^첟ßöü¢XØÏwšßæ?° Ö_I§kÒé!é4=È—«¼ðÓ–»WÑø5|³ùÓ>%<ì°‰3h«š`!‰5Àü3ªãA×DB'‚ñ´ž Ч#¡SÁøAl\ciù÷xÿܸɖºIáú>}Ÿ ŒèõC:ýë!7ýïô‡þw~ÈKÿ»<ä£ÿ]Êû¾ü…m„ÔœútKVÁ¼j†EA•7>Ó"æ¹ÊŸeÑVP•Ÿm!vE~|ŽÅ:^ãüJY€ðbÌ^OĦƒY®õ«˜”üOxÝ£á=éãýJ%`SYÖìLdLÈf€û`—÷³11›1ðã8“² ±ˆ2æ c²ß Œ'‘±«Døµ“°éÚ´À€ÊWñBôNñ;q26•5‰“1¤×Š÷3Õ“f%}Öµ²Yäû=„72Í)îŸ7—Ùf:£ÚÀLçfÌaRìõK¾×$áKfGkGE":±tâG-øßJÆOåÉDڇ߭xq\öà¤Õ«´S¬ç‡ÒÑ~-¸¤b1U»÷0Ç}I°£üSy-cãïëAä¿ëØ¥NZò† Œ¢–§  M•¯±øB¶Z³½ª•o²ØtŸ×ÂNZ"¶ÜjñæíúÖ«Ñôm’‹=²+ô“AT;Ū«\KlEOͦ³r/ì{¸Å«”ß—«QêÏ[,æô³“ ½U%õç$,m³JÀ×ã”l+z·È(z×#r`ª¤rÄS¬•}ÜÖʆb¾‡úw¸Æ”÷ä;ø&øÑ«£šâGÒè¦ø‘T›C?Â1µ´DeÊrÉÉÿ¦qS©qí¸q“›4n{¼Z,¢‹ElJ b±}ÀŸ… ¶~¥!G¯xµ£!·!i¼¤= efú•†•Y ¹wáÎócV8é'5Yà–ÜàÙY`è÷³bÿÏÉŸr€Oiò »Í´äYö;–>àásÀóø¯È¸åßÒØcÔa+ÙògÊ7T2~Ø’õð¤ÖH¶=Ç©íÃV±kºtÕ1%Ø¥ĉ=øàZ£'´¥-Ö*ï­ÊáÌÚJÐó³mH[$;’:Œ¶-ȶm¢n·m¢Ž˜v±cvÛÓ.~Ì’ÓUÛŽ5mÛ±LÛfꘚ™¶ÍåG@Ûæéì„qÐ_da ¿m6Çzä+Öœ€–fk» ºŒÚ–e3n ãʸ‚ŒåÙŒ7B¹±±"›1C)ãcd¬ÌfŒGÆDʸ†ŒUÙŒ9ȘGב±:›±«)ã2Öøq?ûydlEÆvÊXjÁÚ4|S-Zg™Ìò›šˆ}¢½>$;e!NøÛ~ŸîõuN¸í×p7ˆ-e"å–)wI½Ü•©OÖ»sê‹ÞÔj’>áÐr/œÛœ²Z‚ÇÙïnW/•Í) wÚÅO[òˆ;Õâö¡ƒéL î»Ñ²KçåÛî8<­ÍR#AÍÅGÍ-íMEÍëM¢fAVk˜š+5W5WÝò*¨¹ž¥æÆÔÜRÔ|jÎ(jÒ ¦“^ei:zˆš³–ìêIq5ž,57[*b”°£¬Ï3ÔCÄÀGÍ=‰I;¯æ¿šwüyDL/&f”Ç&f”‡‰ã‘c=‰6-A+=<Ÿºs>)b#3YµA?ÐÝì¹}CÅQq °¼—ŲE÷üXFd±ldÐ8¯Ë=Ç ŽÃ¾óô´Ørö]ð$Š]åšp²?¤ì“Ö›ì©NRçT06ÿËw´u°æ’¡­›ác@Xí%„¼@–ÁöÔÊ áš˜Ô2 Ìf^c¿ ˜þ^ÛA¯è¥÷qÂ’ƒ¼MA“•Cé84ØKì åñBkh‡&95LòÊ)·C‚:ÄœãF>…â‹ÑÈ¥Þ»13ËUÓq×°’z¹ض1xÀ7|+¼š¥ñ¢ªæD£OùºÕ#x{l/Àöß ¬± Ø{`gvžÀ–eÁ.(°ïÖÄúzìÙßȳ'¯e=yÂ4xí Óàå Óè•^š0—T]…PÅô6­Qïy¾\ƒ ¸QÍ—½4_>ñÒ|i´ä-¼Ÿ‹–¬ö©ùÒɇùR­ŒÕJJ±w,ÀUTªÕ¬‹ =Ùý§¯héï»-‡DÖÁn2 4 @cîÔÏ“JeGÄ,Ÿã•×'çøn£²¼?»·­ËvòZàX/‡Å몓¬×áB†Ñ|ƒ·`ŸÝÇ|r£‡‡±Í·cìpXÈm>êÂKn÷QJKî@çìÎNhá{µa€'3uêÿ#¼Â3þ­e®+>yõv¤•=B^–=ÙQØ)°tÉãQxÿ£°ÁWÝFoÏ1 V °~Ǽ”Ó¸FVZ›í~PÅ.ŒÝ}Y¨Ñ€{/¨z=j¶#fj6A­ÈBSP_¬‰-Ö3ñ~ÓrÀ¬¼Ì’\L²¯}+ ¶ß j©noFx3:˜3·yŸ§ø„<™ÊŸ êÂܪÏkZ´*›U4›MÈ›E4bòh`|HlBžš[Çò0·žŠ>Ïsk±¸Š§lN!zB<^D“>ä&Moå’yRæ©»åÅ<æ/!øœgGÁåÖ¸kb§àíôJq¯I°®ð“ ¯*°yˆÑy8[u·|»êîù²{>—3»êÞù·U}U÷ÉoRu?6(UñÃ.‡÷¶)\õ¨R×”|š®¥bJ¾œ¦ê;¯ê[%j’©Ê‰ùšœžÅ%¿ŠuA'Ñ¡;_®¾¦rŒErŒ/dÈÔô•.Åë„}P;ÏÕòUBÄ&çwEÔŒè2?H»Rk?`øÿü~ÀPðÝ~J~õ—Õú2ÏŸðÙ<µ ð‰,ð òï[>-?w 9é×Ý^ß0® uö謁Êv6dWƒà‡ÚÚí§òØL|h‹Ÿ³SÆûEÑ ¶•iÝ YcØ"¾Ñ,â£3jw#Ú^åƒî׺î‘=ŒºÐû±|çý.Jêe¤B;Ëê¸@½ìc„o´J©Ë¿~ã¢SOñ«|‚_†-hÈáK&·biÀH£IÐÈQ£X¬RÀ1àCŽ3ØWŸ:?×¢à™lÁ NÁ †œdØNýø ‚gý¦ßëÛÒ%§¢¯ªKáV`¶€_›ZGoQõwquòG\¸;æU±£QÔµ£ÉÝ9Õ`'½øJ”iS 9×HÄÞŠŠ™JQ]Î3êÞTæ£r¾‘TfæP¶Xd<+×)–ú¯¥¶¥*·[ZÁ>z—z‚ª=ñ€û0}%Ë< ô•*ó"ÌW }ÓLˆ\òÓש‡ó÷šùò=#‘JÚ![ê¬Ê–[n¤¤øKn2Rupžçªæäœ­‡ò‘u‹á“ùÂc‡áœ®e—ÚÃN¹,/è)™‚£Øz½Øå˜ÒÝøô]x©áP3÷¶ÀÂV¯Wü@ö "±µD¹}™rû¸Ül·Sî}£Àíså˃L®í8¡è=z/Yò°žíÌåm²|¶üRå"j˜`/7vQöçk¨óó„5”e×ÇŒxÝ‚¯ÑïãF•'„¥%‡žäFf}"ó{äBjá’]á#™[~ôÈçsàÙÐIZ”‚w*.vÞ(hë%?1Y²Á Ó’MÌYE —xlJIÄœ¶øÝ]48‚ÆéDŠ»”Ëžª¼täm 7ôMž‰ììàì`••9ä\# ³ªºQÝ+~KUwÓÀUwKUwËhzò»kuÕf"v^U×ÉLà_equ]L«¥ÕqêÄ=èÄë–Ük†¿hwâ9Õ‰_ØÕä>ªæC5~ßÇø½`ʼnqEáƒ&žª bŒ[‚’ÃÜoOÑ7³¨òˆY"Òç}>€KÝáUO˜µXçÅÿ”épµµ6W[ñ”šxgÌ‚ÇÑêshâ Kžç’þ=vªU‚ø2”Þ@cû=úl´*þîc¨ fÁu\â]†m˜‘ìhÉ vh²*˾Ä[ç¼vì0;Q@ùQ^0Ôzj'j¸9”=lÿÅv¢^ð.ÑM5ÿíDwA‘‘M5‹ìDî$åS L;Ñ[ð%î6UGÛ‰¾‚Ïbù7g'æe.óùD›Ÿg=ðh:ÿĵôg®§]§ o¤ÿv#]q3}ýfú«·Ò—o¥)[^4S%¬j}ÙL$KÀ:ÈL(oû½¯o•<Í5Óö@t8…º2¯]eÚǦüØ$¦°@âŠ4mFæÅ޶$®ÚR»Î[VÁf¼‘βŽ#«‹¥ÆOW«`²j8ë$²º[£Ô““N ©—¥^eo« Y}9ë²úYjyío¼Œ¬œõ²Yj¢¶ *5”³!k˜¥6÷á–+#9ë0²FYjùm5–³Ž kœ¥X Z+;VnšIâ\n™öp猕N–ý¶Ü9c¥›e¿lwîX±ìWèÎ+},{¬¸sÆÊË2IJ¥;g¬Œ°ìñçÎ+c,{L»ï1VÜʙڊ‹\³rÎ{Üæ3E®6ç6ßTE®6ç6ßB›% q¾É"g?DÎþÜîììÿ¿öØ®~µÇÖøaEÁ°’; ‡ßQõË^þD;Œ¯>TÝüœ÷Û¤f–”÷óÛ’r„[ÀŇæ–ù6%ößMà<” ÏmR7W8ܯ„Ϭ…6:—8N߄܉ â"v}¾·}¶¤Ìõc”àäj¾?|&gH´SžY üÑÎmxÔ,ò‡k|Âù2x¯•SùJä¸U?nÉÕ@sɯë¾ü×Pÿd¿£cU_&&û•̓f«Zí.sMöË©~ øŽÚ5Û›?Êz::—jáW“x–?|ZµC¶ã}?QìbÁÿZB­unãÂÕ©K{ÒuÙï¥Wö{¾ÑvÞØz¿|×Y£‹›ÝÓèä!šgË›=+Ú¼ò:,MD—6°4¹å'OI‚¥sI‘Õ5<™‡OûYl[º;ZPçX3Üð+ÿãSýðSÆqŒ“¥ìÌîÊnrö§ýy[ˆþyù…Dò…w=‚ C>ñ;yTä³MÔKé¯ýl¥ä¸%ù&U°R¬au:蚣GBg‚ñÃq6(æê‘#й`ü=ŸjóôÈÑ@èB0~¾ÈÛê ôȱ@¨GÛø1zîÙÖ½P|õjÿ€ž{·õ,Ò#Ç¡>mãÇᨭw±9õk?AÏýÛú–葓Ѐ¶ñ“ô<°mÞR=r*Ô6~Šž·Í_¦GNBCÚÆOÓóжÆr=r&Ö6~FÏmÍzäl $âgéñàµRœ „‚ñsºçûƒûÊ$›QïzÈõMYí°çhuòËçႸ™ÏôùÖë(5ŒÆàc[z!µ¬ñClIÿóx¡F ó ¿O_ûË´IìÛFŸL_ üî-BŽÑ®m¢ÅÖ´ŒvS›Ä8;åí–Ñ•2^D»S ¼=T÷hS/'‰h7´g›X¯6Õ½Ûì‘“E±ëŽî‚ìòä`™gªSÁÎQ¶ªîè…å]'‹¾˜É‡Ê¼3„œ!¢]ìJ^zE«áfË™¢ÊWÔò!ìôëÑŽù±îþ øÞèÐÝŸgä僇n‡Ë|óá†7\㯨ñ»˜Z¹@Tå *'Ò¯dì¯Ã!Ÿ\dã©ÊëЫ\LÄù«è`á£$$¬)D7xL®Ü òmQ"×Òg@ r½¨òV<æa‡“E•{ ¿Y·ZµjNÜõF»+~Ý«Í#r |ãæ§:u4p{Nm®Êo‹#·Au¸J‹·ˆ'üæGhñ!j”kï·šåy}àEöÁ¼‹^ã~s ~eâ€@ŸjÍóöwµïŽwu É»Aìf,)¬_qÖF˜¹fmæ# ü¨àä1¢úúEò„¨“'©û*SB¸ƒ‹æ*{Ñ<›K÷9Ñ©™ÏãËO»AD{‡I8R&ÚÓ ÙUÅåêÝ6“%Êb2OYL°˜,v½š‡MâUC±¦ú²lÎb®pµ‡9#ko—b ªVä]üEX§þ"ã,²‹_F3]ý²Cæ¡›_vDè¯.~ŽÉ•v¯êò%¤wsÒ1ؽß5h¯[þ†ˆ¬³¯6ÈNþ7[@þ·HtP7uŒOlûúõ÷Ô­Pãéµùz‰ü#Jc<½ 0 ¨O ¾MËü_aYÔ{î?m3OÁ‘Ké¬K3›ø§êfè58èñ-[·ÜÁÖ‘Îb.ܯº YìÏ5ûóå<==a&£Íf]2*ñç¼:wcÏžUç\£‡r*r {Ñ×í ‰k0sg[%pW°ÅÔvÁ&ן»è»éóQ#AŸ£]̤.wëèBîBÙMCM”׸DÍh—%HË:#&¬ž_•²zÔrÞO$#Žò.ƒ{WR‡Eó–Eó&v[ë6Ú8³ÎòÒxL™ ËaÒr™´cLŒø”>tÖ?£ÏÇ]Œ“ð‡ÛÅl¦Ï']éóig+[˪1ä§Lï(6xDD6ÊÏôÐq3ai’'©©¤ú ¿WØ2€ôéÃV¹šÙjÔ§õðáB¨<ÑYÃGžÕÃGpNÇSŽü’p0ùJ÷ÆÕU?¶Ìh÷G»èøélL¤Ï‰.æ$CN40’¶‘-SN2ÀïÀŒ.u´¡!X}cZ´.ð¶ ô÷Ûa33z0¯®'Þñ¢gZ–µ£°'gÙ/áP@ÐFsý4ƒøö~gÖqúW Óìî´úÎw†u%ªMÄ„º±O¿ƒöÊù~z¯Ü™þu[À›ô¯xyØeØê% ÅÕ±Z`›€a;½sì6DVö-'»@Áµ nd]±9ÐSîFÒ47ÌÅ3ï‘ZPGºäX¬üCܰ7Ò(&ÅdŽ.„Y¦WÜÐÛ "ÊÒÞPQj½›m…¢iæD÷ƒß…xNÊ(Û  DÊ5(g˜§ˆ[ܬ6þWkoù†ˆÿd_ŽVsß^¸Lï+å}…'=Ñž꯽r»€øÉp7\¶uEÞ·…e‹þmö *ÞЩO$Ù“£Ã@£"¯×›JT/Ì“D¼r¸K“¬§¶ÃÊeB#c<,`¥1ñÈÞ8JP˜…¬¨8Ø'>ðtQ”®ò·sŒŸÉ’Â-ÿæ»rüš[kv á’-—ç8¼IÐtŽuÝ3+ûÓò•°®ü¿°<.ð™w³N«ÒE®`cÖ§ÐR3a§%¦Äò_.ûêVÕÑaÙ¦D­áäÉymÿ¢±âFt$­o£ŠÂÁZ H( á„b°~‡–= ê=CuÕpd^>?ߤÄ0d)Gë á%Fmåktº£°•T*’ã Qn'ê¡Uf¢}ßMÁJ6Šù=˜ë8Ãv¬? TÇ:\#P嚨ró¾Q…ù—Uïe(ÛB].ÔC«‰«Á‰F¹HO¦6yI¢o);-^¢'™Ö¥DëREk´.Y£Ý0ÖóPµF·®eÖèòu=¼?G®ÓÑaF[Ü®­çŸÑ9fÍ}ÜÉ7è%5÷U_ôÊͺêT[é;¾o²ÊÇ.ox—7ºÍ‡‹¨®Š]^u²EŽáÑZ‚"a{F‡©~ªŠå»szÌn$ë¶õObŸ]”áðoô¯Û"u¤îïB Öt§mÌŒwÃZúM-²‹¼Þi×ÓÊxµ¸^v¤3è8—,'cã]òåñFXXw+U0Ê£l•Gǹ`ø< .‹Ã˜Qt<À“ܶ!@™2—0Ú…ÿÝCÙj”  kr]SܰƒqgËÌ~5‹óºö ¬ÀŒõS"kŠK>) ßdž ë\ò‘ŒàT›Û©³è!O=OÅ£S@ÏT®ñßþ# »´?6‹ íÄåŸYÒTvXŠà¯ß®ù\“M«äV8¾±_&¶QäD™˜Ç÷Úð„ó\“Ü) cEø6Ña°C€_ÔÝ\£™Ü:¼½¶†ò^AÓý7Y°“ì,·m;…rÜW”a;e zë<®*zëìŒå{÷\OËé.ìòï{觸íšëÖ³LGoˆGwœÜ—mgºú{âjþË1èïç]ÌGY%÷Wò×SÍ©ÄôLjãE\q˪ˆ#Q^ïáûjË{=Á~ÛÀƹ=àÊï¨ÝÇY7J"™|šµTç¹mT"§shB‘Ú3,¥=ã¡Vó3Æ`½[évžë"¿Cµº•­“|[8áÊá›ãúÜÅõ¹‹ësׇþžïbÞ%»ÂƒÄB·íÎŽòt Mä’¥Ý^S§»Gñ‹2˜º8sOtI\Bó¢é¸ÅŽh§7ªNÒ.¥”¶)"vwjKit™Žõ4s^Û³‘èÔëp†å`¦ð‰Bøe÷+¿ìz6bˆN*J°Þ×to¡Ú'Ë•zIO,pÕž´\µ¯Õ-wiëhA ÏpýX§$ëu™,­ž\$7±ë×x¢é­ƒ’M¶-ŸM4¾è"6Áø¹…Fç [Í£=MʨÊÌ £*; :ÇcÔÑ9.KeqšbÞ²a{Ó°]6¬‘` ìmÖD°E ‡æ¼xÅçy"Vï‚åjN3HD_÷•/7ýªÍuÉ=o7]£C|ñèk*ë^ 4”@˨ѽB e ´¶R hµ;€‘µÌšBˆ1…¼ËAƒZÔá¼#âS¨»J ѵ?#‰ŠAB!'Dš@¤©|ö ’“C©-]ÀYà9ÅbD¬äˆÎˆ€>¸Ïs± LþÉZcî©[⵫ÒYúaõÎ2Pei±² ²³¬vÃ-É-È2œ÷_Â^µ©ƒŠð=KÙØÚh=tÂå÷ˆDåÎ\!DzŸ7œG¾Œ¬“8ëѵI8­Þ(ðù²‹>Ig§ :ÞÔ DɆʷr ï­l&À CŠõ.6¬Èϯrd¢:žË>¦æ»’Õ‰\9¬å®º†»jŸïŸW_ ÔÖ:¯ŠíñðÞÓz|³í²*˜×óŶ±Õúª‹h‚_¨„õDÆöè—ÊàÅ~Ú =ϪFtnÅ”„ZøùÚšç©R1Gu<ƒšjt©Š9®Ó¦…¢N¤Ñ4«ÄÒBӢР›žQ1Ÿ[hÎ*4ˆùB³ï(BíÝWªéYÂÉ~¤JjŠ*»à1Š˜ø:¯5·‚‡½lA½ 8ŠÎ6U¯-Dª5â Ú#Úë?ò®ãÞ@ÞvÞ†œ™/Û¯ñd†LëÝY»Ÿ£\#8W«µLˆQ†e ‘kŠáh 2y,Ñ:º­ó]r{o„ž• Å“‰F§NtNÊÉF¢âYu‰=ÝHPŸ³ôÉfÜ£Îå½ÈbóÐ= ê²Þu• ¶-*,Í‹d]ÍÊ5í…\ j7p¯±Ëì*.3ä pcFfãJ¤ÛÈé®CºÕvºÕ4ç—ÈŠ¿Ž¤›˜ãO#éz;ézCn4졃›ÔP‘[ …ˆbã[UÊ)EK!´/·¡)EœvJ‘oó›³ÑyNö^¶%nfâ~‡wÙ%î2äîKJLd”˜Ì(g§=éYä’›¸Dö„µ¥mI×ï»´w v$•.í½ŒÒ_V¿÷/­ß‡—”öQº~o¹áJ ~Ýy¡þ>üÎv‘ËE¨.s´kõsˆ9o„¦Z»‡e´{˜áë÷V7ÌJ…ØÌYG횪“…Sc' ›Å鎢¤ª¹0p¦c¬™‚ŸwÔ¯­’…)b’‚g;×UµÎuŒµPð|GóúªS…„7vŠ‚::üU§ _tŒÆ¿Íanã"í( ¦˜ÚÜàjû>dQ·Â¨{3MÝ—µ›ªÎ‹bgàf¶>/ |Ý1ö9ܞøçÙÂ@kÇØY Ö”U+ ô(£`ÏRó‰ªó…^¥±óì]êW]( ô)]u;2©kí®@w¦¨kͰ·’¨[éÔ½•qY³Ë ;UµÔ•±è­>‹>à±èc9–±èuxƒmˆ½îRqYŠò;á°ìKûµèjíG£k\qÃŒ­wñžôm¾q)êÒÒvo<ºÞUù{á<ú4_–”­:¶»ô7 YÏÞ›t˶ÊÅyº|9\‹ç£AÿTY ¶q÷Ÿû5ã‹öš/Ú´™^¤éã„6­0÷¸mÓr„ðúÐŒ¢oš–[¥û«¸Lôª½Ü¢ªW5‚M9·´ôÂ+¿<Ü,æ·ËJÚѺذßQ1Ah5D£ü¹:ó?%CEçzdþaèÕÌ[†¹eáQü¿Ûj.þêØÒ¡ü}î”AÝ&¿v{†i»}~q_UkA`¿?ÖJÁ~½²ª¦0°³$VKr~ã×U= ý±Uû3GUŸ ¬‚òÔ¨"@{T­¡QµÑÊ'cTtÃûoZú•wô–öZ'¶Ä؉M°ÃS:íæ4¬±7\2@»ˆ­] ±m.Ù%Ýê²L±ovY¦ØR¦Ü¶(;ŸçËÐëPÎ-4Šhn£ -úÍm„ÿyÑw²iÛø®[™p¦¤– ç­®èXÜŒ¾ç†e÷.ˆù‰5÷³­LÛ²;Qô@h‹ÃBU  ÒÃnØäâ:þÔÊöS¯­:‡69*794ùsïðØp›²ÜôQVt&í*akÝÿÅ W¼µUlhm¥»Š;â¶}ÆSIC³Š.—äX«zâ& %ÞÏ8Û}àv8 óu½¥_NËx¸1YXä{Pôß§F¹I¿]~~.åí‰ÀêÕ³C“¼SvÝ0}7»³‹:½j%ûa²Á/(è¿kZïI† ü:Ê ¼;±K4ºÊ®|÷p3xò eînÊ ïzÈfÏš²Ò'ªŸ±#Q´*WÞÂÊç‰îŽÀÀ | â°¸ÕEÓƒˆá@ÀWk`pưþ‡))GñüÖV£wkëðÖÖ)­­?˜¼ ÿ"Tðkª¬†ö:‘1©‚^l£Eq ú…pÄü»†9…ÙÈfЇµ?5‹Añ—f1(¨?Û,ä_Â{Û%¨ªÓËç!ó_C3Ú%mõMb2ˆJ¾@ÏZ gøïRi›äs”¶á²´ /PÄ é´38-±ëE(‡˜™© x{qOÂS¿›ààôçÖã…$°¬4Y>¾½Æ//=QMrH¾Ü€TnNÕÀ©z‚ü³'çÿˆ˜Hãá4T¸J”…rU*([fÎÄ,Øq=šš=ÐÑž=^§Ùc» ôÙ3fcü*qMËР¼¼>àÑ®“~ø\Ä%©š8°ùÄ­l¯Sº-¨åM4T.ÿ13òà†ÿOº ø$`º~½½ ˜ã`æà–¸ÓOy?·yò (Ô©«ÌÁ‚£Ù,j’ƒÕ•æV…ÌW„|…E£¸F9TDÑEÉÂ6ÑØº·)¸ƒù “åÖR%øÁ­™ÏåׂTåËr@g­ŽM Ë¥e²¼Á…ÕBºa=½R.¡¢jaQtQQŠnˆ@öSˆž2ž8.(f‹ß‰k{¦äz©ò³…œÇõbaTsÒÈ£H7¥Š¥Â4Õ‹Šè˜€Ðš¾¸Hš¶„v,švÊ­üFSêµL9¡^+pGl3”¨:í6³Ùá7¥Úo5;JN·Å~UÛýêùH'¥›$¬šÄ8Ì fò=ñ„†Æ8œÑ4ÔEˆ´ ÁÕ)A´ÊÔh–’dùÒ"ÕIްïôý–¤ÁÇ||Æ )DØ|&RßL¿Œ&]Øy³XÔç©;NJò]5¼åÂÿnëqpú;à§g3ÖÁsnØš¾ªeˆ[^ .*Ô®–€ó¸îtÉ¥º•jJDM9Ñ=¸×ºàVvª ÜÉšD°ƒál!¶™šß(Eqè5ëÀ¶&¸_Z¾t§}ó|åVÒˆãyIæ·ôïÉïÓ¦‹v,DÅ|í6iBìˆD´§“? ­2•,mhXN¼¼É¥U Ëü 7´ÝlŠ©ï§Ô†þîsUüßʯÛ~"boH¿nÓ†²¬ÛF~ÝÞëBè¬ñ¤çáœ'®n™@³6èœßVëÈ&|;xÃz¤Ô<ØX¹‘êf*švjï€i½<˜yÛ|‹Å´[ØåÆ;.ù=ÈÒxìiw¶ØË2§]“þuÛ¤¦Ýý.$i}<éæìë õŸ¶L´–ˆ!í:ÞýÕA§¿³;×Ñ‘Ž¸‰–z—ZŠö˜ï©ƒÜaì8#fìöš|$ Â"¶ÇI­ÿ3àüŽÚL¾çRN ãу®”?ïÙð?”†ß8vœ„ýÎxô]>î‚m®Òobë ˜‰˜c?º)ÃЮý=&u½Ç‘µ«µÉìJû£(îÛÞubgùJdvê%íA„KÑ!F"úŠQ¹áJƒg½Š˜@º|²iäXÈqÀÌDþXÉ‹qѹ'Ò&ö¹K–Ç#®ØYÍ!w윋]Œð¨×]ªFõÞ‡âÑóß#ÓàJ?^xTlùKmxtü+ÓH<& ®"p8mxlÜÀ¿‹GO<. Žøñèi€Ç§Á´5‡o¢3OHƒŸ%ðóñèçüxž¿Dà—ãѳüxžÿ‹Àÿ‰GÏ<Ùã!ð_î'^"T*{‹p]öá­íd_ÞÖNÖÒ*¸>%²`?zÔÅ{š]lÿ˜‹÷0Ÿ¸Ø<ë§.E»øaù3?(ŸpÉaô9éª(uSÁSЭÍkhøPÑ×…Ö¥ §¾5®`Œ ºŒIqªÇá6ï;Z¸áÛ«¤f²èîìÑuú‘ÍsøonIÍ$³4)ßÝ,¦ýÔï¡“z'ãGÍbFÐŒâ¤îxºY¼tþ 6W³žk ovÚ̾2‡öl÷„&ŠŠ‰B«™(šh}š,“…~SÞGÛ±µEå¯ÑÑÄâ' ²®H«>M':3º>3¾¢AA_OGC m°ãñ˜QÙÞk( %)ßÑVÀ‘ÁcÙ˜‰æñšÕNùK mÊŒÿUƒ‚ ~³S>E¡Í™ñU ‚xâb5…¶dÆwoP&ÓM;íh½»¤€-²×»ûðé®$Ïž†SUJúFQÏî.µrEÚ\Ï-"Ÿ¡Ñq4T~å2äYÌôé[\mXäÒ•ÝFþšL>g!ØÊÈDMK\0÷ù ꈣüK—έ)_lˆ~œÉã­ÕK‘¬ÓFò¢}”eÍe-´ÊúòðA¡õþõ"OôÿJËc,ÌÇè!,º¶1]WeÒ•ÿ]‘¦‚j÷µË¤ä™ëggÞþÍ̹.‘\;óEÊÜï’Ì4b*[]‚ ö‰Ó<†Ã‘»‡ûúˆ”šÙAòÎ%5=¸…,©ñ³K¡>J>¾=äãÓj¨óèëb„£!7=ITL¢þ¡žŠ›‚Ž#¸tµÒ詤¥_®·qåƒ=ZõZ·òù#¢ Ù$˜}¸Ùid‰4²mJ ŸQ¡ÝåvÜ÷kÕ{ÚÑIÂúÝãJ¹KÐ?Në(¿x…¡ò?9åÛ ô¹Û&.«zŽ)VÇ.õP÷BŠàdfí÷]Nðþ4ÁÉ4Á.­ý7¹y@,1?6Ošó&¶Ïj £Þd¡íaÙû½EšAH‹4“úiS‘F5ÚW¤9Úþ"-«½6ÝãÈ2»u –¢¤©ˆþ;¹¯V}šêñ9ßÁxâ•¡‘¢b$õû‘˜¹?‰@ÿ¢ŒF‡üàG"b&¢¸}L .ßWžÍO„üD$hT`ü.Ê{¸«i&’,äë`±Ü“‚eò7:¥$\²].OQ4ßg„¶]™ˆ¾ST¾íJ›ê^y†2´\žáì%¦3ôvÈó”¡93Ãõ,:t|!äDí¡"xuþ9ax+PœWÝÓ!/âÞ z©[¶b“9ã·¡••ÛƒŸíiÆuk³1ÕÀ 1¸Í) ‚ŸAŸéAâM/8Í.rô¦OÍ5ξPZ@ãȾzh…¨XAÌ_!hnî§ óè‘,›ùƒõ˘ÿ]ö˜ms}¨žÉõázC×Gæ:,0Ad,k,Q3?˜=N—cõº%ÕGŽÓÓ]—¦ôñ:œ}p9ª¯fÉÉ:Mä‹Ý‘,^oêØv²g÷<ï˜Öó"¹×3ä4=â¤ù+zBå²Yx†g իݔÜü]4ÇçeçÊY‘xÕc¯Wàõ›×ŽËx=GñzŽâõÅë9Ìds³Ü9¤Æ+œ tY^;åÝškVƒ×‹ˆ•_gÎn^–N¯ß-ªÇûr==±×gL쫾­¡Öd4ÔºËêSU 唩¡œh(Ë|Ù°´Ýf«ÍœuHwÜgf›½©Úl‡ßÛv›í¸´Ív¦Ûì­KÚlwº•ºf¶’C&tØÓÊ*aC  æéŸÅZ {UÔ% Ød§ ”hÀ%V@Îä³ùKh¿÷­ökDûhïëòCâí˜ ÎÕ)GuyRb Z÷{Zo³T5Êczxµ#Ýè,¯­²lñ)¼¾otbëu\ç{ú£,/ö¦%/ÖŒògyíLG­\`êØÙšlÚ£/õ¡½pŸînúï3oIM÷îùj[Ré^Àì”U‚ŸwŠô/é³(h| 0¿Vj- ®bµ–-fVA§¶`vú, æô¢ÏÒ`noú¼ÌëKŸeÁ6ëLù%„•›äWøÐ„ÛË7“þos©ÈÞF$7ÚbÖÁ6R#’ç×"yð‹žl/ðV0t:l…Š\(TÐ_hÌàõJëODòíÁŒ„½ã+”:<]ƒ 9€Á~-ú^Qx’¨UCw ACw£=l°fÉ!í9ÑmÛâºx¸Š'Òð¹„:·ŽaGÜÚ ¢1Ø"S ÄkÆ‘6@8)…BSŒPë™nvVÔ ÛÍû¤°,D0º2‰äq’]O”÷v‹túlWˆÚ|{ 9tSg/XÀ²5áÃ)½)šê 1nžÔªtÌ‚¹(*Iiœ/&ò- *ÑI9‰\jXEçÔ!ãk*c$+Þr#t_Å}·ü :ЄßÈŠ.)à• º\i°îµÙZm¥XVQÑë€kŽY–£6Pl ;ß”u‹•gi'ålÛm[e{3•mgF¶]V¶× 8)g‹èã“͇ÿëF ×z|Kxµ½¦l2Õ.÷óqVØ¿é ø®Iÿ”n·u*4ä{—LyXÌÀª MT DQ G`µrÊ÷ÈXc²ä ”Xk²å‡ ”a`!ÆÁ4G5/9MæÊMKS;‡·xÇT¦\ëÜ«ËOMoÑåÞ×>³+ jÍìøøñò"}…ŽSf.%©ÎGèÉJ£½ö>1Ûkг½ö!1Ûkñóh‘–Ý^û¸HËáãh.Q5—ÊtLh¨Sܾ´×;eòK>ÚéLy†zßRê¡0Õ{Ö¼_^HO_¨¡½¼)¢½Üï¿TÀ Ø[¿RÀ• ØS¿VÀU x ›­Ô ¸Ðšwjà`ažïx÷€Îž¶ :êõv$Òþ#•á]&UÙüt«#LYÏ÷dèK²~@^Ÿzï H0tÌzïØ*®Ž}á ·µ n¤k–f\d¿æjÉ+¢e3¿94‹þEZE³x»ƒ ¿»;èxL1*äÏð¼÷hÚ©ÞcÉÔÏŸ7XŠeO¤'ÃQ“ᓳ²ü®÷F7ø V.Ÿ"NpËP<è–Uñ†Ø ·ü ÞV»eºõ@Ltý¸øÇxt*½< ~™ÀÿŒG¼‚Á^€kÁt¼ BÄÊtÄHD€¿ƒ±Ê“re”7†Ž[h;u¢*€À¨ÕMu=RëСrËëCo¸Kº½)b?áTøë^0od)ƪ^>¿ëåk£JÅi³ª·¯cˆõ¦ðèRýŒYÕÇç¿7Ö‡‚cJÏͪ¾>I¬/ž±6zð ß®åm7«å÷Áò;â%±Yn~¦ÞäQBä]ÎS{P+g£:ÿ`<:Ë­¦Õ ˆt{ cCRv.ÝèÖªÐâ7òWH‰¶kÇʳÜÑD»ðáìèþü=PPWÏ&¾]òµ E—V;ø¿Áo•¢üD̪W‡¦ŠD²bª€,Æét8wë(ñ/8ÆšJjfH=Ìd« §oÒþÖ,¶iÈý-|²(HÁÒeœq÷´ß"ã›¶®z\°²–ê;yé¾ãÏfQ6¹ š^íA¥ß}'!Aï4ú‘ \GÁ=\ÃíÜëïAaG0B?øÖRLUÊG\Ê›V)ÇR¥À?GÝ€G©’Ïñ±*ùü+X•|»©[&OòÜ4ò†z«Ñ{G°¡Na‡±“YîD²¡üP;ƒ Ø‘&ÚP¬õMB…"t4#Ûi:Ž“–73¡;=ºÃá\$€h[øx’¢ÛM¾j;vµXÆ–;ôåP ÿrª„úKJX¤'ü¦ÛÍ÷j€¿eÁ—Q÷z¾Q.ǧÉdA®]Acõ¤?ûUŠ[•"Žè«u$uœ¥aØóM ßÎÖVù:kÿ½å¡EÝ9)ß¡(o¢µ"¨½¥ƒ~ѨC±[ „ç÷zK¹´ÝA}7l¦p!’ i’q½Á¯¢Ï'u–ÃÛeçâÏEŸï *³Ñ&¦9Mª50˜öñÏ$æ!8,â©gõ.ßAù1áăڻDÕ²€À§Ñ­¦ÏBãˆ.ë v/4Aÿ*s¤¢úp‡ qQò‘/ãÖ(õQñŽJyLOXÓÆ¾‚ÂïbÚHÍãÐÓ ù+ü¨€ÁˆÃ¯!ÑÁ‚ÊqnCž´THZôdCu?]žÒ“ÀVÝ_—§ÑÕ ÃÍÃÜéβÕë,Õ$guyÆ*'¹¡Ö•Œ—wkÕS ù%ý÷ò•O óû4C~<»=†ÇáÜᢋ̥!tê(©y¦»›qâvæ|‚:.ÒöW \¹™C oFŸ½AçúLñe¥Oc0{}]•3>MÁÜ×ðqæ-3à‘(›L”õ4ˆ²±DÙº<ÙÛ`"© ô5’ ~çÌêy°Òà/™í/™W‡}„Äl¿˜W½$6QTæM9¿©)ª7äÉAöïyr0~O¤ß›ò KÆk‡Xgìë‡f°pf!ä GàÖyxG5ÌP²–¾©×2h–¯Þœ'ÇØ¨²äØKPeËq¨&‘ì4ªq U£šD¨²«_5ä›Â-y²Îþ=Ç”Óì"rät.bˆZ_Á#í UH…Ì4ìåc¯œeØý®¡ ° ýn¤¿ÍއˆŠ!´ eå\j€ˆ«²ŽZ`,Ò¸x½*`—Ž˜ öÆšêf(²s|Éì%°XSýFž|Í&/O.còžaꆊîmärE]wP·2ƒºU)êöÞÌ¢³~×C®1BÏT<£¡¿Éµ Í]9•H{݈´QW€LÚÆo’¶\‘–çE¤m!ÒÚToÍ“o@±+î1³ηyäo3¬Á±ÍCÄ6î¬úNî¬Æ[܃Í]ôÙt4òÍT÷Ü™ê’o]Òʸ¦ÃÌìÀãDŽÜmDÌt3ï¢þ3Œâ"Žß¢+a`ÌRK7Ü]Ÿïî”{¬ì0ê)dèVŽâ?·ê•³ Ail<§¯‰íC½#Ûálæz00V gªÜüTå«ÊQ•{_Uî˜!¦*÷nÆð9œªè‘Ë*ú~fE?¼¤¢ï_VÑ£vE¥+ú‰•ý;<Ý¿y“ó¸!¡ßVüVáò3#ɪœæòåΪ|Ï)(OFÅ·âfT<ÉûŽŸ¡Þ-ÜžoÞ¤µò´‘PµØæ‘gð»G~nÃëMy÷ˆ&­*¸l½€L†ozd/ø§lð˜.‡³ŸÌ}Lpô§ÝóJjîÞ†ÙÚÇä >‚zú¼4Ðç`ÐHŸCAÇ ÜuŽ¡O²]Ö8¹]ÙãéÓÐ.gš ¢Ëû›q¿ÀÔKŒ@ÇåÞ¾Ù~m!qy ú¨€C¢@_pÊ!fº•Ƙ_³ä8ÍôSn¦‡hÖo‚Ï9PÁ">¿Ìhʉfè§?ÕP9ÉŒGòh_:ƒ¨˜lFlù”ñf$‡X ÓSY¾-Äê:ÓÒG4ýpsÐŒ3ÝŒ8ÛþZÕi"fZ…ÞÆ…¾Ì›mÊÙfèኇ5°OΡBÛà¹òUZÝæš4Ó´ábgf»‰Š­71­5å´ÈNëZd_d¼Ô1ÇÅ"S.1­V«Ë¥f’·gËlX" š'r•iµ~"Knʽ¸ÅrÎáa³‰q¾Ô6qcŠMŒZßdÊ-¨·j\>n·Q½š-ß´Ÿ6Ùwú. ûu^K)öítè4îÓ8ƒsf¶Ücÿž•ÍÏšûl|·ßþ=+[~’=tøv>Š?6­ ìcO«7å'¦½È7­­E“üÌŒÓ LJdt€>•÷'LÚL¬É’'ºÉc[ý ä7…Z2•^w@®m˜1¬Îæ:[û5»^ TjØØ>vª- ŠRq[U­/0®4VKÖI×ë÷ViØÜ>v/ û=(‡ƒò>该ÎÕ¸ÎÖ@ÙIÇêÙn€ÚC-Còù %ù|ÄÒ_›ßúk …`¹oH>Cîû%ùL©´õîÎÇ!þ]KòùËóÍwä­Pw³U÷<0rô2âoCü¾í6y{Âr附ŽñèFôTQô˜Qyœ&å»BŸ¦@•Ÿè+î=F{Ôyn[™›øG Ë€ã]€ÐŸÂ{ÛÙhÆêåW¿Æ¯]‰—"Ù_ã£ÁØJ·|Öû¤^_ˆ>fð‹lHС¿gijEòiè$.Né$Bçï-²@Ê£Às­´@ßÔ´Ó‹ç¶¶¿hmíÞÚ:¢µ•l…é>¡zQ±Ð(ùWx[Vø¯µTåO=¶EÝ:ÇùGú×ímL¯¹GƒÏèIŸñ½Ö•”éèXÒ3±Õnô‘Þè#'R}äHΞ·úÈnê#“`@y2Cð¼Ùcè9¹CE˧A6GgŽvÚ*!׈x¢fP'iË: …cÝдIYtÙâ–ë2 ·¬s³vêú Ã-hC†á–õ ´IT](*](’›EÕôë‹"ß{6jðXÊ"ñ.¶·"#†z}ÐE<ºÏ©tÄ)Dœ¡ˆMˆ8Žè‰K‚ÞtVÝŒˆ3ž\GNn1#)æ†ÆšJjžÅÉÿË.ÚH:wŠ ô9Ô'êr4Éá.½Å=›÷"úÇêV°²ÖÔäd;Ôö:ËP ‡¢½ÌakÎ ö6_hòòÓ—7ã¹á/‹¦Sü\ $rÃ_Q IÖÃNÉ&÷¼Ñª ä½tÏÝöìáWxŒÅ:nž•KuË%–|M/)‘ËtäCZ¹œÎ²Ïæ N¸SHÆ6¹åj=Þ£¸µ0Q¶àÖá<ú9-Ö9¹O»mû0»•}˜ÝÊ>Ìn–UUJ YX&žpÄsåBîHäòÜÛ¨7ðî`Ÿ”–Ê~¦®ÄcÎrcÜ€BÞCcIñ ¼ü Å˾&ÎùP]âþÙNÚFñNêRê¡DÎ%†3Zú<ëH\‹ÔgíÔ|(%sRF/. å…4Þ‹vÊ‹:’Co¹/1XÁFW¾`¼º¿a-ký Q¡ÎǶn!Ù—é®6 ŽíGVü*œœA'U•?‘+'"ÿ×éüS‘ºauÕ‹¬çA &¢æ‹Ð×Eÿ[Ý#n«{¼îFj øVÆ«|×0róji ÒôO”¬¿Rû½øÕ!­qFËAÍüsÍâTP{BvK(VO¦­Nΰ:uOâ÷Å¢ðÎö…ì:ô\P<-«2º_vßíç“¿¥®ý»D´ÕˆWܯìÅ<~.QþY¡ rä3Œ"Y}±O îde)䟜7Mðdã Ϧi•Aà X‚zz³Ìܼ\ƒ>)œT…>¬( y.¨²V$ÔSsñíuÂó’ªTÍsMÐÎl ¿6ÃDEÊ@¨m¨ìAÔŽPYþp±èF9R$`—sœàã¾]N 9QC& őɂX2…S”X<á±7S|{çð%r/¯®çæ• Š+xª§ê­˜öÓ0o4%ìí"7Ï‹„0—nbRa»Ù«SD[DÀ쩌‹pkQ çéëuò¢ì×¹!÷Š„å „S¶½žÍ Vµ…~ä×:-ÍüémVüÈŒµ± Ó~‘è4OIR¾Ù¸Ó;ÈVB)ä!¬µi"Ù½ö€È~\Í "NØ”œ²WÝ{ܼ]h±³=n¬•q·F‹ÔÍÒS Å^ FX«[ké\©'€¤‰0¶×-é áÌ1½NêSÏ!ßh{F­fÔÑjF éS¨1=2ÛeÈñ@Òè–0U7¹å$ýõípC}Ïu0ÏÅè§éÄoКbó2‘Tü“3Qö ®L{”=•©×ÁdžW ~°× :uBürÝ2`»WÐé4+Ý4mO]~~Îo×Ñêþ¿²½’.f«m«.·ÿ¯ôCÓżm§[ó¶.ãÿ+Û0.æzdk´góFØ ‹Ûsù#X#ö£æÃ¹5¯AÚwí´ïâ šÓ>‚âÒHãÅÿc¥yÝÿÝÖjC[V®=–›1^lSÛ¢Ìñ¥Ú-Uý| ¥±~xPëÅÓÀ½-ƒtêPj?fµÀ³Z ývA‡_cþXvµüÊñ}À Å38¯°óÂ1ͽk¼ì·j2V„–ä„O]ý¬ r í7Æ¥aû-¢‰â~ýÑ?¿0 Ý âGÿ¼XÀµš>°XíµÅð_øºÕ¥ádôœ:êçÀéu^‡Á¶g(F‰™L¸™ÅL&Þ,CÌéÔfYÆáÍŒÃJJó¥;<[PUãQ©.lV)à,=GÀf\Ù¥>›(Qî<_W\ôBz#çAÑ¥ùü\ ‘˜“Æĸ¼šœž©ÊûÚŒkµ¤ÀOŠÆÆÿAãþoCMY9¤Ø` hIv°°»íOPÈQp R*Ü%0^ù)ÿ޾RŒK ëgtfNÍÐMæðÐâš;`K×'ÌLoLcûؾÎÀÖúmØfeb–ÂÖK¶MŒíïÀ6 ;G¸0¶Üøê66OÛìœ`YÍB–º’bB_„QA+&:V· ôkjÇcYÓÙL–_{á–jš›ÂDÀf¯ÁBlDÀ|Þ'6·×æëtJˆ«žž@Ç– ±¥ÜÂ+I'$]ko)×êlŸ:úù@ëégåqÚKn@ú7uéßÒ­)û-½ ê …„YÀwÏH_ DÄdB¯é õ½…V=Ò‡ë%Š+­l!ö YÃ…ßšögDD¤«¼°ñüK÷XyR•sV•#uî½ÿ޼"=¡:o‹‚ý3ú.ÁŽ+ØiÝîVááÅÑÅ•#‹-Ém^X­ã!|–%6îhL_1ÈUø®1ŽÝ,¾€ H莊;4J'¿¤£Ð\•ØÞÍ!j%H±þEB­•¤ÿ‹:ëè²UÁ‡¦SbÏ+å‚¶5ÐeÀ^~Tqõ·ìcÄ+OºÙ°ê3Ê%HƒÙq®°ÄêVG‰S—ŠGϺ‰KN<ËÁ—&äñîËé~˜Ê”ÍúPñÊϨÐQ8Dlç–¸Œƒ‹¬qF&OG+žŽGÊ7½ÙK PÒ‰¶õÙ‰ŒÛüœ¯i¸±‡D†*b†ákÉ`€ÎÏ KJJüZ 2ÐL@eÉYìF;GαX1×°zsÈ• ;ÛΚ²å<¼åT‡:‘ršá³ß`ÒöU#<Üg¿ØWÿ:_ýëÙzñ¸ÖV=ÚÚúbk+ý’ P¯Ìï¢Z‹À%Æ¥½«ÝRãÒÞØkȼ“ÇÍÏy¹Í“å¤:.”‘a•qÙ¤ àjt†%ùX×j"\ Äoñlû+ ^g#^gÈ ß†xã·!Þ|ËϘšÍÈ-(a—×PO9TÄV.b^©¶ÒÅVCn7’m¿ F‚×»xô”u;0¦8x‹wEQŠÓ °‹îèâ4àmü#zè àý+je Å ™ˆØ“‰€½™ˆhÌD Ë€¼Ír *vÀæÝí Ù§OD‡n7óøn¤{ÏN÷ž!d¤{?ÍE¸TÝØö>~À’4Þ6´Û­e>5¬—Rèj5·ø¬ì¤ã3®ÌÀ'^dâ3ãZ>ãËœGY$ûÜ-?aÜŸ¡ÉãFø_Ñ}ò3#!OäIúßl4HiDLÙbDò”É’§ˆSž1’ÿÊåÛÖs,“:E¤í Ññ  ÛÌ9ˆÀù éMËù7xM#;§sËØÆR†ƒlaÏà XÆ]äKÒvûÖx2ÖÛÃ/Ä{¼†#;ç/ÈÂ~†Ý¿ËpEðè÷±]¼®ò‡ñÒX/üq"¼?¿¶f~£¼/=_³F4Y¦7á3“Nf0Z2¶8®œaa!ª›Ä¯iAë¬?EÇ 2#$Ÿ+VޱǫÍì¯ÃŠ£¯–`˜ö­µÀ+ŸJÇ´¨˜›k©, ÷ö|#ywSV¥Å“a‘W †»¥|v·TÝm4¢õæ¼Ñmï…ªvÊå;žÁŸdÿÜ~:7¾ÐòvŸŒöÏy‘…žŸIVî74ùCÐ`ÎÉû'8ò½ùžZ&Âæ;¤|pÞ’2x\W¦=$£}î^ìs dzD© YU•ªV¡Zä••ØêÚ¾º Ð?³íýÑ¢Æ.»ÿz¿fL ï¡£-oH_¬·hM^#;;ç0·Ô X†Cj¿¹»ãè8ÏÍÚ®k/о÷&ñKî¾,_ íϯ؟¯qWyÙOHβÍÈ›Œ¢ÍáŒî ä?Ãç puÑÔÿÊŒÊhºîùïˆma[qPK°ÕæiðöÆ}›€ò)nÞúŠd§ê]Ö ï? H(`åTe:Û^úÇ"ÉfZt„ƒE2Ú¢·esÓÊœlö14al’ä0¸–#tæ€!0”…ö!1F€|y“Ñ@Y¢»r|­[éd¬t˦ÿ'[„Måƒ}4çåÀ×t][(ÀïÅ¢jbqx"mdÔËp(Q4*^¬žX,—`³½yòº"ñ,aû¶žQ¦Í0-Ø‚ ¾õ ©Š{÷yéT¢ØÍ†ã”ý•41±þÚÊìœß!ñZÛ¿›yÄxL¹ïåQ®ð6‰ÐhÚ4©>‹ r 'ìdé7ÅË{x´NóØÏÆv:­wâħu]î@ÞÁL—„q¾2yshRq†´G¨,|ÒÿÝöYJ<_»‘ óÞÁŒ‹µC|gvUË«eÊáÕ¦\]Õzd'œša<ð]¯²ÏJ‰:[Ï e 40'Q9ÚófˆËxu3+{¯@š •SgçÆh?φ&ˆ*{² ;·&Âr FÑÖä{˜öní7xßáíðB ö?~—÷oÿ04RÇt ïñVC"â)âÅ÷òûjRÈ”…¸  —ÈBÜ­¦•ÿ- ±¨µÕ¨imÚÚZ×Ú c©÷)Š7fP ¹’øȾµc¹’7kÂõÖ#ƒ¨þÇ)uK¼ WÆ£µžÀ¡âDeƒ©ËG!““º½£Ì׆&g¶R½ÀÿnûÕí]’°TŽ7C*Ç ½Ì–É«¬‡†«Ø,ôUòj4Pj¬þy -LÕúŠ„Ò«Iõ6Á §ÛCrH& QYW,à¥qieH@‡E[¨C#ކúü ¨¡"1c˜l8æ®O¼^=‹ïêá?Ó¯Q´'ÌØ0¼]鯱Èbìë°}ê5³LÇBY*ãe745‹9eZ%ÈÊG¡«â¥ã¸Rù¹üy"Y>µ»Ñí+„M…'âÑažxçîŽèOç Ý!®âÉvf;:w7ý­ÕÓŠ³M]‘¿ ñ5D§ûïe/1Ýþ¯­´*7ÌÚ?éý\YŒâñ›…ŸÀbU/6Ä]¸W<@æ×€]• úݱUÌö›3ç0WÃq8FêÙ`9FêaÇÈN­#g+ÛÏïî€T )ùÍWSÉ©n!~;Ò§6ÒHŸæ#æ3)¤\žóÕT2…íߎíÑä°ç“°Öî{ŽVmlÎŽ{aÀô{h·ç-°å‹–8ê^ÚïŒò¡¬Dœ°UŽòòï`ÖP|òŸym¡PÊ_j …¾C³Ó@@˜NdL—'½‚¥ó) dÇÌ å å áˆÒ‹ùíVз¤T«U|¥¥± 4¿½V*zÐfÂXV›Háå¥z/Q5ÉXQ›„ÑÖÂy}-õª/ßžà OòÕ…'ú`kýçBìOâeeò—öbh ¿¥<±RÈy¥a0zùïNûÜ›¡ÅL¬'|6Å‚”Øõ9Dõå:ç…­a¶»²TbTM¦Sl2Ñ¿ªT¼bTMñùEl W—êCª:Ÿ_ÕQpM©1̨š =Ô©\[j7ª¦ùüflêzÞë4²²jYh½±Ñ9é6ø`·Ñ e}è;i=šê‘? õhº‡NFðÁr7|°ü0aØ1˜Öëa,Ó2妠xYÛþÑ Mø<™TM/ =fÔWO/–Ý)ExF1[釸ÆïªfÓL5£Xþž~Q R×!üˆN1ݸÜg¹¸çAÌóé_È,ÓÎK—ðrª€^VÀ¿aw{ÈÜg´ÒÞ•.¡‰îwâ†?ñŽT‡}ßéË[ Än~¡À4½Mõ0gîýÂ+ŸÁ6õ$oSY‚ï¯vì³÷~é•ÿIÇÊÖ&VŸA›Øm:`„ö5ïù~Š µ¶pJ!ûÃQñ^¶Œš";-ö¶éaÇ^6ènÙÅñ^9šõ5/ÒV&;ûQæž»ˆy¯ ”ðªH³o&môë õ‹ó£‡ÆY)àt³Ùer²r½Ðh›Á1fÚLF61µ™_Z¦MdC“&mã'§H^ä+„a¤©ÂæÈtqïE¯œ/28öÔ!)oÅeeÚú76^Î-)nl÷ÖäËݙ܀·õ½™ÜhLs£-jºŒó¼ï2f0/(^€ÚCi^ô̇¼ý\¦ù}ÛSõûB~(á£ƒÚÆ£ã<)Qï8„€ÒÀ3« Ÿp•T5Ê—æ ¿`g'D<6k‰ªÊñÁöuN‹xØ ³©ÂjÊà/.I7”ÊIM^Ÿ{åãTp7H®±…€jtÙSO“Ì,½ô4¹ è£+,}q[ß;#í>`ég?Vô£ƒ´ž®Ž}w2D‡ hSXCñ aQ6¸ú0®¿×HÆÕ·³6R—ãôDªaX®g¼ž°›DyžŽ£o²K¶©º%`§¦[¢ ª§Í ´h»YôHu`‰}ó•[ŒrçÚu˜«ã†ëY4µÔÂÙÙwro_«sßÔ«fË zxo;¹QÓïMzh²Gõ}ªWùdÀ5C5ÅlŠ~ܱws'Y¨Û{E™¶Pg2Ô³üšºï1ÿd°çêTø(*Ü6º¬ýs4]®Öí¿V¿·6_¾¡g̉;(%^dõò)ÑÇmÞ©+Îô¡’Ø_Ðn=5& וiS>¯'p?dPú°¼dFN¹W}ÂvF+?1h(QÅŒY4ÚLšyÛj4 SëŸu&ÌÜ‚2Í ‡™i‡õôÜpDçµæ˜ZknfÉd,6³Õb“ÇJÈU³±ÚÌ.–Çð“â¡€OÁÓÌÓûz_Š¥«Ê´}:¯8ò`ŠMïê÷öÏ—Ç3ÙtRWU> û‰Ù¼ˆ äŽX…l-Ü!fû´¼YÙ /¦¦…§úgì®É:‚|n÷7†L!ÈY»·2dAÎéáÉxIÄÅüÅ|ÁÅ,ti_èò+Ê0Õ5qUÚxÇ"ä6ä\þxÇ"ä6d&!m%È´d:AjŒ•cCf¤‡·ÐÁùذ܉b{ãѤ¯a-wìW°ÖÙS)h©Qgƒ~õMB1$ßVÕ!$BsŠ/WÕyW] ŒfÖcG÷J~z—;4?c—»ºŒí Ë·w…«3v…ïÑ®ph€€cx~úêgD¾RŸZS¦œêÍo §z …`wzªº ƒùNÞ›Q*vcOÑòôÖ©Í™*Éü[!È—¯Tª(éíÖŽávÞ΢í $öò•&ÅßM¨h38 cRœ ˆëCs¿Á‰ÃŠãs‘µ›Á‰qùêzd­u=’¸×#çEæõÈu=2W]ŒÏW÷ kS×#s@Æ„4غ™ ðÄ|åV„À«RÙ…6ø£˜”â:¥(²¹~„¸þZ.@ìÉ=?Ó{> !ÜÖòºÅõcW€ëŸ\W†ç;è7È ¨þPï‘·Õ =òÖxClzt¨ËW2+¯[gx´TNMƒ{£ ž–ßKàÇ£ žžoëô¼AœyÌñkè_·÷ñB2_ÂgäãdóŒå!²K†‡Èƒ×Š;ªÎå^/Ëoè]«¦ûëJcÓéÐpÁoTV+ ìóÅÆQÚ/üæ“Uã ¨ )¸¾ÔA[l_`‰/6ƒo(uþµêU_`ciìUœ0^ÍìÚëÊäs²K1™)ÍÀˆÉ‹<ÖYLëíKi½-ƒÖM¥ú½U3}Í¥±™Tþ#FEé[JÍÇ«fùo”ÆfšÙ™Ô¬§³äéRÔ å½òC¢f± P37c ÍãöXˆ28J`¹ÄîlCª;Ýy ýžM"áÞ$~i©2Ž” ×å,…Ÿaùô·GzþÉyH]Ô¬¶®ö`EÇ7Zo¾àÅ„©<2×ç;htÒ~›Òþ×êÉÿ¥½?­ ~P$üZ}[ìz )a_ܵ"´ÖTO •kM %±Õïc쨉Óþ€uâ¡Ù;²5Š¥C@h)GXoö››'GÙÁÑœ¯bnž^¹ÆÔå& = {«ù&‘[j§Ùçi‚N )#Z+<¶­Y–­Ùȸ¹}/2Ö ‹Ýõ‚ù]/äB³ÞÏ"z"™¨xB§™W·‹EhgvféŸ!õù”¿{9åïeP~Êf”ö¼®ª8ƒðCŽ:äQˆßg‹jùéÜéÙú'Ìá’(…¿ŒÛØ™Ÿ¡Õ¥•«M(cXa©ÂÒ·¨p‹þT…OÙáã* í¾•T¶bçø7¿v\°zÅV¯ø’¥8óáåö]Ä~m?}-ø)½UÈVÚÕº½}pÛ[W/ò¯·eíÐùÅ."é`á½€øZ+~Ýeñýtï~İâ×_?P÷®Bü`+~ÃeñCtï8<ÃŒd£GW_ÜOñŸä1 ÖsÌS,5ØÒÂë=^Ùú2l¹ÓÙ%l†­²`†·D¹‘'Øj f¦nüpãÈ6ŠÿÓÚê¸x±•þuhmýakkUk+ä0=YR€9s´CW†¯Œ¾çëÔ)Yq¥Ú¦ŒÂŽw)wŠGÀæ1¿‚ôÚšÁðˆ4A‡[föÖxàžâBu9u–Q½É ’2ª7•éͷzñÏB ‹/3ª·0»ÛGj'³Äƒ$X&–å›´hmâÆÞVª%õª9¾ðdØ\öc›CëÑöR1ܨšËÀ-Î%à›¥ú,£jÇx 8€;J½FÕ|¾”ó ¸³Ô¼hTÕ3pRÖð­Rdzj/DÀ­emeuíeuá9¾òEÅZ]x®õg}ç[ßzõ ì ô;ËêàF&¶€Ðí*u®‡Ìíò|Ú“™¿hyK Ý•ÔôM¬ºµ–mSé¬~“P⇛h«Ý#wi[ Ã-z2Ô#7QÞ#WD{æ–/.È툵@!ßÒáJdE~V¶é¸ €þ6V{kâóömD@™¸—K¸¿Y¼]f<Ø,¦zÍ ì6yn”wZŠ}w}»ܽ¡Ù¾DùlŸ ²å“*q×tâqéÄÝxþëÜÝ]g€,¶¿ÞÇxu°LXnôÐ.±.bÖV”ÖuwÀÓ:OÄLV/)–À<ÐnSþ,¼£=§L eåÉvº|¡´æ~Ù©“ìv‰áS¸>[™ŸE[ÝÉÌ‚ˆuÝA•Å3ò·ª²Q«²±o¯ì3ñDùfLðýÑrpügÈÖ'•l={gö$ÿ°¤øFùÑoLDeCY|!Édþ#!ÿIdþK‘ùo"ó?™ª}²'_ó­Ê‡iù'@¦ò(Ù¦å‰Xx’< £ìךPÌÉ··ÍÉ£ðºT©Ó!¢ôJÃñïY†ã‡ \‰¯Îw˜¦ã?@¯äë÷”iÓÙÄœ­ºÎ#geŽ .gŠßiGsc`/  }ua9GÔɹgæÓŸò¥ÅÚ4èé×õ‰mð`çPùºG£íBh¡¯sct¡ß°úøE˜eî×ÐÐ5c¹5–aiY!T¬ñ@S™\#ˆ…Ñ׊¹°µTØë¿ÁÃ#¶Š/­^V,7àWà@Y<ºÅS¹¼X—po(À&"ÀVØ€|C„øäV« ¹  †2ä›,“ž9ú›@ %±„+Š;ñKõ^V«xÏjú}"¼³=1÷õ|Ýi:þ„<ï°o’Æ’>j¿£ôK±š‚þœKBzI5¢ÃÛñÿtö€QUÙÿø»oJZf23X5®1lÔ êZvuQ× Y5êª_Vwf'ÞŽ.–U±l Hï½ H—Þ‹ Eió&’¢ˆôšAZ~çsî{3t¿ÿÿï§dfî¹÷žÛï=çÞS0ˆ® çµÝj`Œ UÆ‚\“'Ù^QESnŸà«Ý¢µË‰§A~/:ÄâóŒy¥Ò¡\|}؆+ÖŽBk¢¥8ª¼]çÙã¨Å¡ ü&á§)CëNŠ 'ßcÁ)I¢$î]jäiö@ô‰FJæ³·„¨còjˆ’\^–{¹×çÊ Ú× PzuZÔx¡ßvCÝÁât³2u×¥™•IÄLõ¹Ý Pã·å}(¶CäD¿"Q*¶¬ÈijïaÍååºYœf€ßˆ×kØ“<ÜqªD™o¬ÌœÄ¡]ÂØê®2–ç݈‡3³'6kÌŽð^ß&Ÿf=Ç«VÕÐâ¿òc¢bÿhZñ_Pf¾N);âtÝáU–Z‰b±ü[ÒRËÎä­ÎAˆƒ­ÈMZj9‚Úš 8úè+¾)áÙR¨Ý™(ÚZ›G¤\¼PÜ™(2 cóqû±+ýöã0u#$ƼIË-Ų ¼ÒšˆGi"&²CßðÑïÏ_äh7E‘Q[@ETŠ›# E_ÆRp[¡~KdQ ¨º0¶ˆ‚5…ŽâÈâ@ÑöÂØb î(t†"KE; cKPŸÝ^gTëŽX:œR@‡ó\Püšõê~ *ÃAŸ§®sÒçéë\ôùÃunú¯Ò$xû’£„jà7›H Jò*í©#l:Yqã+Üòf±BÞ‘¤ZUx±#iyj‹ª¡ –¨Xä.]&2 ÃÁäŒ!¿ ”RÈ;†³LŽá<äMšù 3_u9EŸ^«Ë©_ÁÌ×Ò@Ñ®ÂØR°10óu2§hõ±“0óu8}-fÙ#ÉìhÚeÞqš?»²‚ àÑ´Mäï·Õ³Dã‚Ei? R7íÉ–-Lc»#zQ/¿¨Ë–ü»^/¯WÖ¿ŽÓ‘y?2óõíç-´"šöq3,íɦԕ¿®–·$¢—tHÀhx¹u²b¤H”ow° ú)T,'²¡…v+£ºÞ†“¨~•0mD¸|»¨3ª;’¨°›Ö2ª[ŠÕ¿h¡Ýͨ~#“†êž„‰vÜ›Ìû[HªðžØŠºïXòöÑÚ/èøkwBmŠ_g#†¯.íìüÞëp;œ´Ñ/VvUNîJm± ÏÃ7è÷Á€ãZ±ÿçïä)¿'¿KóËå’šIIo“…rçòã`Û — ¿W¸°'Wšt¿¡¼Ÿôgi?(v<¹YÄHɵüœÈ¿T¸e¬"£t–pp;‚>åu8ÎZn÷+¬Ù\{uoÊ¿™Ê7ÃëùÉ7S«å[‰"foÓDn|ïð®.ù÷D®òþa*÷ hºþúW" uõ@öÿ˜ÊǃJP&ÎÓ`Ѽ@þ®0•Û‡TºnVº¥ÉtTv•îôt½¬t =P¹¾Ìœöf6s8¿u¢á˜q¼îä à·âùFùÝà —}€à“A‚=~Á;è¼[ÃèkéõÎ3—Ø2:š¸GÑׇ×gŒ¦¯e×g¾ÑsŒä l·òÅj˜°I¹Å±&ÉpqùÄ¡Y2B°mhÚ|ó1ÿݰzõö¨ôÒ€ù>·Y]œ5’&ìA5ƒN|xPÝ™ô J ]Zaš`cš(¸´;sS‰g¥Éî±DØUåN§üÍpôàü3 ¢ïÃEÛ,ú!uµÎR —Ótåæ Á\a9¸I&àRç!n¾°¼Ú\VJ–\(áä"Qáæ8úèÖ„¸¼ÌЬÒÜê:Œý¿æ)ÿ¯ž±XI§›7úÖzªÔˆ¯–O ôêÌÕ/…,Ô`•Uý†_¨5VÅ“U^ ègV•Ó+û¹0ÙIRcÈÌ„_€é_Z «»‰gÚÞ4©ºã0‰¹$aCâð§aSKÓwÙ€a+=›v0ýè…,\iÝI×Jî&–…»)õˆwB=âÏ–·±$Üí„û•‰óàä\ƒJ®V ¹žã÷?Pþ6Ž Ú¨Í.ûÌ¡1z>I$*7Ô*19Æ]à÷’±e–ˆz™|Òö؈”æÌž3”=ÁÆd6ÆŽÛâ0ýôGÓRÃBúsqãDvÑ(ÿ3šu¾ ±ô­ ›JöžSý™Sm 4H…Qž#â #¼,‡7ŽeÇ겉B2cßgË7âATæMØã›YîÑÄñLE5²ºGg¬_kÃuÙJȬ‡ˆ#7¾Ï.;’­Ã›B>ðöÆ7!îƒQ½Äƒô÷Ë@[®h v‰\1 ïf´—0¦øãÆ¡”(ÑLÐÃ)è0‚ÚšQp­’ì»û  ·àI¥(6BkÇRFï,TÐÓ” Çq §ŠxÙÑl †ži©›è€—t*l> ‘ºuªg‘£ß¢5 ìÖ,´BÓšÁ‹Ó›À¥ž§2G×33‹X¼d#wÎfZ=J×ê=¿5Ý*"«r+_•+M–+Ëq82uÑ‘|¹°­N‹å‚Åol «¥ÙÚrAëÞÒªÒÜê¶—t6@‘ì·ÇXïžSéT!`ÿÀª~Slà~E‰E›Ê™Ö|‚øÉ6ê'ÖÊBïv`‹]ÀÅýø ‹šq¼nwå»(UÀÌVp>ÓòfT†%°Qç+Yà„o1 Ä=”Å’e´‰ü².~]£¾pœ»B½„vþ MŸ-´U¹šÃ¥uÉQRPTÙöûÍ ¼©Ž¯c™±~/!ÍIN³?W;É7Q⤧ét¤êùÚòsQÂZŽl˜Z˜¬!Ÿó*†–à¬Êo½²˜ü꬛x^b=çîôŠ4½XÆ,ÇAÃ}÷¿azdunt5ô£ Zž-Ì’ÙB@»®|u®ÎÒdi¹>à\ÓõÈšÜèšÜn—å¢Á+_“+g°,r5ÚÅ“ªOR¢èL±ÖGg…*ž*J¾-9F²0›Ò·¤Û#>DoÓ5GŽÐÓF|´í•…Yå+g¹µp±ÒDÖɃö¤µ¢IÅAöY7%‰õ½M·93ëläÔóyÚÏÕÕœá9åUÞeûdaJQßp9R+õÕ¬ðµ&Ÿ{ä@è^xPZ©[ó)¢±éi³«Æ$«»}¬Cuæàrì÷#ÂsmxíÏ( IEÙïåvà8ê•“:ŽzçÀÑG¢î¬ÅëÔ]^gY3Q²I‡Ø ‡•ÌΘ` #aù_jýóï·ÓÑõC¶¼#a=’žSOÒwÅÃÛEtdc»¿t»±StxÅSÙÑÆFgJõ£Jõk€Ê*›kòžxRoó3IUÔ#v&›˜†U+ØÀ&=bg³™¿é“ƒ®7ƒ”ÛXcàù`Ü8“môp±¥±Ò¸q6Û˜œÍ_S²'ÈGØ~›’ È®LÛ”ÄøNÛØ=À“œ»·ËÎÐi›|Æ–|ÀÒDAÙCµ ¿Ô(I;\¸ôÍÁ±ëE}`K&7~È&ôËÁÙR‚˜¿ZËý¯µâh+ñ’|)ñ‹jù2mö§³}×ðÁ—ˆ¦S“OEŸ2väàaò)õ0 )—þ9`tïºNºNò~dý,·hò¼þ½ÊbäÿâþÅÿOxµ«lµ §$äÄrìK3BÔ*¼î'—fujÌFÌ¢9)þpPNÇ~®XþRc96etòBë-Êè{¢Œ– À€dH®|øŽ`Qvkä ¯hqAì ¯V,)m"‡|EK b‡(¸§P4²2Pô]al%.u†æ(Skç‹eĺԉð¥N„/u"˜¼úìA šŒZW8¸Â9ŸMdF…+v![¶‡üYŽº|9oÝŒÅó¸'žÿ3Ž ã‹åÀÔZÀ]q}Ò]„ûˆ4{e糑°´€¹µ‘9¶é¢óI-¾(9‰‹’>`t¨´õ8:ÇÍÒÁÒT%”fdâzyh€"ü (Â{Lpù=Šëâaа·‡/§ßËQDße¼ë!¢Ë'ò€Má ºYrAÑÏsÑl¼}*Óxm`\’Ä»X,Æ ‹¸£iD<.l8õò ÕDÑfJQ²– ŽSÈa‰ÏYøƒ´bçp±óRÅnÈÅHÌG±ÓRÅÎH{©X̰‹¥É9C€0¶Š#Ú|C4pZ±‹Pì>—§§»œ‹]™*ö‹\Ì„PìŒT±K’ÅÖ‹%v±4å—¶2¥Š].ÚLÏ!*6­ØOQìÜÚ™É#œ’¶ oÌýéåÜ)µù^ÌFl³rpŸÏï{ ißü(P´¯0öQ€(ÃBñƒ3òq <©i餦Zìcì–³y‡É®« YB´´Ÿ´¼Ã¸µ ñ(IÀ!c¦;]p.uŽ;ãj$}Òºt~†)‡zÌò™nù4Lç1¶|$)Cl1Û,ÛO/᚟ÂÕÁÂÕAþEášå–1ˆ5¥p½A¸Þl€kN®…)\o[¸Þ–W¸æ¸Ùµæ¢T+“ÎÓ°ÍNö˜±]‹¤—Ý­3ÂÙnu½¾„1^d£€ñ½†çºßôMƒzÞÒ±6±B¾o!œë¦EëuŒ0ˆd?„¥¾t„ó¨Š'ÑĸäC=—¥ÐηÑZÆÏ€vž›çµ¶NáLÚ/KùµÎOR8Ø8â®έäq~hOáÄ >¿Ò§áŒ7À¹*…ó‚ÓòÝœñFêñ~u goì}õ8Í8פpö·­*÷ס{Ã8ÍFıàñ9…ó}à„\Ø çˆËûó³ÎI6ÎI:3)#U²qäu)œósaCœ ûs} çbçbbû-œÔŸ`\´ÏS8×çg q6ìÏ )œëmœëu¹ÁÂIýùp~‘¹ 8kâlØŸS8wØ8wèò+ 'õç.àÜ”Ây8Rü( ç(qÀ•Žss çq'‘Uµ”g4á<à’’]â¥pB]D^hˆó`œ[S8/Ù8Ù.±ÂyÐ¥LîÇS8ûAd€£ÎC pš)œƒlûúƒl8¹äPöf•Â98'6Äy¸ΪÎÉ6ÎÉcœ‡]òàü2…s1p.¥ø÷,œï]ÞŸÛR8—Ù8—Á[Ü£ú“ÍtU§p‹|£¥ãlØŸ5)œmœr³…“ús pnOáÜœ_5ÄÙ°?w¤p~mãüÚ{VŒ“úó[àÜ™Ây87ÄÙ°?¿JᬵqÖ:àVŒq†ñ)¼ç@Áú#÷JWÔ9$ë)Í–F㋺„ÆËJgœ¨úÝ™~Ç­ß]è·I¿w/z7$ßuŽ—] ÔÇ£¢»Ñï¾Öïîô»Ÿõ»ýîïQÙº†dOÊÖ‹@\*º7ý>H¿»Ñï>ôûïK¿Óïî¡ñE=h†R¶þ`a@¿Z¿ÒïAÖïAô{°UZÏì§“k|Q/BÓ;$‡ <Ó ÷ É¡ϲÂ}Cr³­p¿Žð+Ü?$G <× õø¯SôÌX' ÍûÎèÇÐìú†»7ð)€à Ïfö³Ô'ˆ<ì&"ØñÍpZ¶f9å,'ÎÄJbàg;Í|?䕿:ÃJ;i€Ís†çX˜L~n\à›ÿ-x ¯¸Ô.pš*p®@‰{¸Ä¶HµÜ.q¥S®tâਜ+¶ÉP$î}>q†çŠÒ¹Bcð§v©Ó¬RWs©ß¥Jý ¥®·K®JÇ¥îM•ú…]ê&§ÜäÄöZ9Ðo¶KÝê Ï¥ó¨T€ãv©Ó­R\ê¾T©ÛPj]ê Uê|.uªÔv©»œr—›På|Bÿµ]êngx¾(O¥ü­]ê «Ôï¸Ô©R÷£Ôƒv©3U© ¸Ôƒ©RØ¥sÂk-ÕÊ„þ¸]j­3¼@”. R–v©3­R¿çR&wÝëÙ!Ù"¼)I“?@ÿÚ9ë+ jü0ßbü–Å… µ‚He h@a¬’¨ñ…âÆHç@Ñ ÂXg (Ô #ŸŠÆ>¡`ßBG0Rï/êW«÷CÈ!ÇÙÖR„”Ár)`±ü\P´äK ú\x­ƒ>]ë¤ÏÅ׺èsɵî–p¥šÑ"ÿ™-åmÖeǯpÙ1Î#ïÀeÇûy'äUÆCÈ­"#6Á#ÊD\(TdÅ&yäo AaÝzPîCýËüc)°ejá}€§Àø÷qc<À'R`‹©˜pm ü?7&²x ÜŽÀÏÆI×å4"ðý³œ\8(£Ñ^º,®k.+ §BìÅѦa>ÖÆLŽ7…<͉¦à#Æz` dœ»4˜[ÉkBö‹ðæ”Àʸ‡ ŒQ<™v s*ZýEÝÀòô6Õ§…XÏ‘>O\¥ÃëñP·ÇÍØLüUømÓXžYò¶€Âgþ¸1ÅS¶¹©.ïh±ž"¦ªˆ;MërôƒÔ½Å]ñDlGxró*Ü0ý¸°»'¼ÖUU¶Ö%øžótŽSddþÕúºØ™î‰Î¦Y>ÓÃט3<&°ï¢ÒtRˆF# †Í§+#ó}nd’§«Ý,ž©k½¸Dr”Ëg¢Ë]´S{JöäˆÊ+ªiŒÌ¢Á¡’ÅÍDLcK®m{76Ã##|š0¶æò…h,OñÜNÏ;eE…“0ûs¸aí£>cñ€¿HM„…8ÃÌåªUM¨`CqÜj(¬áç§PÏ—¬[‹—ð.heÓè6zøÅ½³ûH3”k½¸/ÁŽÖÅ×ÈíÎ8ì¼Ìòž_ƒì÷0I5<„u7"¤·“OÐT†z™§ ävþÿ|&¿² Z¶kP7Z[´].öä G)ÃW‹hšqc‘§@«*«jîÀcû‡LµÊòxÜXê©ÚÓ¾¹Âƒdeƒ› Ú?„Se4‚öÑåž”Wr¼‰Æª¬Ž 2_TØa•ë¯VI*’‹ëÈÅá ìe.Îʇ2_^.þJ{ê²u!õÝ›\žòâ\íóãê•­9Qg¿·êR5!¶Ìã¹›_0R Jño¤\æÁ³É6Ÿß£kÊí"hŒ>ôxþ"øùŸºµ@kö(Do¶Üâ`ó4h|ÈÓfÔ[p›r),ŠÛÖGpãJ­KÆs0"ÛrYZ…>B.ƒ œC”?¬œµdx3)@+ºÂ•ﻓW1 ÚŽtàÑ ñI€VnPަ¿÷D&Lj|9–ã|dU¸Jƒ™ì ¿EÃN¹3YÄ“¥ k&b =Pp)›ïÑàOZ°©,5ñbA‚ÿ50[¨Y?‡Uz=,£°@ÄÍ`É\މºX¹äò5&ª¬3~…í›c…`†|Âíýí]…öÖûåjjÚú[‹ö~Fí]Gõô÷9ýÞ éXçç¯MTb!J„S/Ÿ ¢ü(*aÅ–öay¡›Ïérg¬ˆÝÉ2b5¼þ8ÙNQ+F†¾ÖÞ¢ïr| A›èÊ ½³lžG°3Æe¨vG å¨ã€À…Á°Zgç° üež7`þ70ŠÄðVílI‡ßšÀ\¤’‡ýDìQ‘r°‹qZF“]fUVáäi'Y)¥»ÏétgôåF@¶ëÐnK¨ ù‘§I*8:$Ψ&]¬Eú‘ &¼Q-Ï Ô/Ñ$‹MÕp]«åÅT].qé .¼^MôOðJ+™à:vaû,>6Ù RÃø¾ãø/µz­ÖJŒÔåvÕmr¤ž_ùûjx3VR6mª¬ÇÐÂýÈãÑñÀ»ÒS²À#p2¯T.&†™AÉ PBÇZ§mp5 §Y™åL6ðâñê0›ë0´•6Fýí·Z(ÄÇ…Æ>çÄ’ƒN*»>UŒú¶—Ï&÷ Ga¸*Iî_KÿÚýÈäþ"q:õö9étb££nÐú둵è—,êÙ¾hLèqŸˆ­¥qd1@|–Œ‹V61Žø8ú3Š>^¨Ò#ëžØ:j}|¸AÈ«‚9âZñY¾ö‘lt˜=N§Õ*?Ïõå™<]Gªç,=õçjE÷_Šp­¸§¿Dît¼&ÃÑÍÌ(•½6P2Àïx½ZF2†úY©8ÊÁþ™ɗ̨»G¥»F¾ÌÖ–3XÈv•¿[¿Yuœ`ÈWƒÉ×ÂG—¥N<ê¤iüz…Ó8î,¼uw¢@3:øŠ¢q¡¢¹Mï×K¾¼BÔÏþ|‹Ó!ªÏ/Ó¢|°õg³ Ë¿sP•lÙ…úƒŠ–– c„­¼¹ÿó¿—÷hþõ#2 #£¼VÔ´)‚MµOè¿D"§€m‚™ìg9º-—EfeB=ZÍa&Ûæ¤¥ÁkÝÜ´4ósT|À”2¹‹X-àv9º.}3[Ë ×äF·ç©ÉÕ[Bo‚å›2hw ¯á Ûa'N¬7À—I•ÿW­ØÙJÛÑÕVb#cÞÜ×VÎÿÝ•Êâ ç# Mü« þ•fYE{è—ô·M„›Êj]íy9²F˜ŠŽÙœBÝJ›ê¶î3ßÐôeRÃþR+Ƈ´¯¹øÝ ‹ßóÓâ¿ãâ÷¢ø}Vñû©èôwÅââççÐfh¦•Ç·÷ƒh«Ëhö5Ïò¾É¶ !Ñ—M‘mÌPÖšî†ìŒtg¨¯Lëùmus<šNWš~>‚»¦ØÚôG0Á@0Á¯ˆ`‚ý-)4Ë<ÁKxn¥²Q/ø½ ß]z·†šÐ©NÑîö,+¼údbKYtl— 5F+¦dôZi©¨,}ÉI礇ùà9x¬¨›R&û?χÉþ ù‚>ŸÔCíÑ÷+A ¢Y¹Và EéB¡Q(ö9X…ªØ° ¤IT.Ri‰ÒE”f‘ˆ}ÂøÜ],Œ©þ¸ñ™‡w¢ûÃñ¬¸ñ…§,ž%ˆß§ÆÁL%pV·‚±ƒ™ì—m¸^p›¡––ÊÑzp#h÷Ëjt†kÿ'P>}¡VMŒþŸdIL_ Îü|³Ü·D–|ÞL('Ð6ˆý(B+q½W.œÅËYÖ{¢}…ñQ d‰SäÏÌy-ç¿È¿¤¼kWËX"n¬óà‰÷…DtZ3£G/ª/&¢»²¥<×þ5Qо¼ŸGvÄw$¢lÔ‰²EN]¾‚f›åÔèWázµ±UaµUV_ãpÙ:ªj'˜}â~)@û“¿ë=9MA¬÷°¥IE€Šåƒßä÷µ_i+éO$ rRôA#³d[T«<ÅèýزFû”sã©ê—x?Ǽ—Š˜‹ˆùõƒ(š‘YZ#¦`K1nlð@J ß•~P:ááY¥Ã³´J?æc7 ëØÎmÈ ·ië1ލ±¬F@„¢síÑÞ ª–n‡¶:î€Ö±Nvä_=x¼¾ ~g«(ïû”—gÂ}Ð‚m£|¡^õŽ ÙøT²Z;Y-Lž¨df#"^!;ÃMð!Yòö <$ÂU*á¯q&â&ù”lŠëfÛ ì¦ÃsmÚzè ªp2V|æm0Q²õƒÞ§ôyÛ§ôjîRlS|©»À©>¥úAH™q?¯Ì¸?,ä#0!åÓYž¢Ÿ°(²' G"ž–O+ujùŒrqÁf8ÿ'ºÜ•0j%»s`>‰Ý£þ1n>ø±oR§ù2\°ûDè Œà«àRê®Ð ÜA ˜uC¾X•ïãì•££ì~5Qúª@ZùRx ×LTU8ãÎ’MQ:ÐëzH¾6h:(¡Ìr ~ÍRm}æÀ/ÅòèîÜhGÖpy©ZvJ„7d˜¥2«?¼™oÍ6K·f«à[‰ð˜Ffé˜F*øv"¼¨™Yº¨™ ¾Æo†Ï–&¤²î ›¾Û¾EÿÚ]P÷L£²àJ˜»ò%}Žž(ÔB‘õ¢o¯‰­a<˧|ŽNý7¯ª»¯q\æOu‹‡=wÏö©Ëåé<60»ËdŽOù%ð ü\x³'M†o‹§t³ºds}öÅ1%Lw—z÷Æ›=³ËH}ìsºP©G6ŠNÆ6²_GM#g/Q7#kjl0¯ Äa}dáU¨ýY/4ç]åü]­˜v•«DÞŸ_yu|€X'hÐáË%KLãû«+÷ä>ï–šˆþCûE®pÓš¡³Qé}Îòú«åÓ AÎgŒÌíÂoTÁÞvéjÖšNç¶n¥MWñt®àL¢ˆï¡-t¶@iÊwáwŠ(ž£@LóîU ¹ çBÑ}ŠT/·°afvûÔ0³¥ižY©ÀÌŽº ú{Te"¨<-r…ïÏ ‚s?ÎDô`n¾o6–À¬øDàá «›?r0W¼Y-?¥Ö@ð(Ó¹ek›ƒÈÍ/?K´wxC z(7z87z$7˜_¶!àòÌC·"´ï‰[ÚAâVZ7ir’¸•éÍ´Ä®4×N»Bzšø•Rm®Ö¨µö]®Ö¸µ¶7WkÒZÛ—«5m­-%ÖÓá|C8P·\3ÔyŠàëdPLŒŸnZ[û*í-ӳ蔡z•qÎÁÈ0;æ”1¬ó¡/M‡Êà2Ÿ-)O»Ã?X’ò—Ä5±­ÀpÈ,ç£LQ$+øe#T·$¤L`yPÈ“lƒè’VñÄez¦‡ ³®ô9uwF!r²Ð}ŸVÌy˜šq&7n˜cJvAýcCugýˆï¤nCr6ÎÚ¥Œ³š|þÓJ_^Ù\ÞcÔ—oi Ó —~Ì,W5kIòø à¡íê™ãŠ{‡sò“ÔùÿA#íÖHßœ¢3×ÇúÂÀ§>¸FþS݇!å,›ÎÿùüÏÿqŽ9ÄH9é³&ßõ Üɹ”eEð(‚mù$^«=DT¸c5ù^·{Xvu•E)P!–kõm V§À ürܨxM üNj‡F Àk}Ê껃¨íIDívD|æƒäVˆèˆ"|eÅqÎ7ÄaUÑß—žÒ+á÷x]’øøW’gS¯Ö•:õÜ•c^¬çŽ«cRûT¡v}d|4l ÔŠÓ…â‘ÍpѰ™B?ê7D¶ÀCà )tD¶ÂAÃV -tÞ‰ \±8 ±º‚XL +t·ˆ$€%A¡ó…-#UÀRE¡ …™­"_Ë—ºX˜õËÈ6`ÙF¡K…Š"Õw¬šBõ…oŠÔ 2b5ª 6¹%²®%¶S¨s°iqdÊÛA¡.Áf¡ÈN”·“Bï³o|…”_Q¨kÐs[dRîœùÜCÍë–…”®„d×í¼î‚óMŸƒÝ9S4›·®Ìˆöóhãs œS ²§Q7áƒ?Ã2$jcq+mäýɤ òdO+ÿ1W>ð³‘&Å8§LG ø~ÚÈ…_¼¬q"*y—ü(RüÞ*ù÷òÑŸE~£\ôcÿµh.nß7s¹ÅÀjQ¼;<Ñx€ï ž÷i\´"TÚ§±pÈv T->8€|Ÿ³ª½Ž´ìNÏ^‘Ìn¢èç­ >¾üR@¶,Ë \–Á¶‹¶¦ªGð/ÆžhÂÙ8WZ8_¹¬Jq®Ò`œ¯YuzMvJÏÿòdåÿ{Ã:ѪÜå‰îø~OÙÉ hˆüvXáJaœà]àâ&uh“ mbo*&m¤.w®[O›Ï(ø‰«GüóvV%fç«”~þتð@‘¬¦…gÊ69H˜Éš–9eú6Ö7¶kG@‚ æM·NcõÍa¼%‡@#ÙŒ^‚ëÕ…ëõž]¯÷”#‹ÿ¥^ã¹^ŸXõš”ª—Yà™ ‡@è’É"Y5³ 3 ž’ê:Ó†MEUñ £*Ó¸*¦G› yI7>³ìZñËÁœd3]ã£èí e+®TŠá ’QQC¶‚Zü%·x6·x©Ý⥰¬kã~ˆí ¨ü°;2ÞÓÒ†øËæÐÏX™A'!’0þO0æl¨Ä5žž}<­i€G0žµ"Y7àùìr<ë’xðÈÏÑ9Û|¶ª÷uás¼¿ÿ‚þµëŒý}“8§òAÕãhX· öpäë@Ñ”œØ×ðk—Dä›@Q`ìlˆ5üölݧ|È7ÿƒ+”èy~º_‹}ç!Ž÷aÖÓÿÎý:À,ûŸÌ|ÖŽ$o›¶Éh<|®i鹦ZlŸ‡NC3¶×#+ hËPÝÊø î'Ü5ùÝpE1Wh¡38$^/ðã“]&J²Þ þj=;±5’— ’¯˜Q÷œ[ÁÅ]ÈÓÿV+ö5w¼&ÿv›%nG©ô·&㌳›zlŠ~˜ù| ¯;;øiâmåÿ‚kÕ[D/ä*öó¢b,û0„¹ÏK Ò—!Ì|Zþ?}Á€pÒl¸if9V¶™VÁÚéÓ™™ÄÀoo©Íà Ì"Öª9Oçp}n«j£>wÌ@Öç²Èù"ZŸ[ ±ÓÒ…"\™÷He{€-_¦+³q½,ƒ…ºB_ƒE­±/Z~åRAŒfëËrèOZ;ì'­þ“ÖŽ‘ÎyÑ}žkÚ]òÂ{N Ä*ÑVDˆá¢Oãw󜋮ÒD®VOü…Oëš§9– ­[žæl­í"î8³qoªµBi«oikFI‰¿Š©&Ÿ úG´ï>µ,­‡K*›éH'7 v/„ºY¦L¹nE'®‚ŒÝ›êÞ:¨o”ßÕálþq³LE”wÏÃ…ÄèFTHÉèFY>¢1ž“ce½-Vñ€šÐj5 Û~: Õÿ¿T—Û©×®[,VR¯së=ò4¡k=ó4½XûÚçrddíâ•ñoû]hSHüìù¡^òž´_òœêË•z3ú7¯ÄYïHŽ4^ÝÚ|… Ku>w©g> VZ¯I"íî]<µ=. »-ZÍpâžKŸ([ñ½^Füê†ë­n †…ÖšaÝ K) ÛA+×­Þš:S‹Çí1¢Oj—r1O.‚Õhf¹[kßðö\€j~#,Þòsäk„™öˆµ{Án~LŽñ:?ʽw\°Š&¯õ^ye½ó`xœAöb¨VìÕÑ®yá'/yR+2`d«N„»å>Ò-O´T÷=ßú®Œ¬5\Ô^~Á{Þ c!Ç^‘>*©«”Z±;¨í…vgHàkmÒ3G1 »“㳟;¿ôI:Ú) ѽÍ}ÍË÷7—U¸AÇR0«ã•óäà fu¼‚b˜u-ÂÃYö‰€L[ÍEkU¨µª·ÆH8Zk}hÝ>©õÊÃxìñ9‰¾õ;Ã#±Ö©AXæ›æâG«´×mq—$®%UWèݪa=‚÷ÉWDÊùÛpß¼¯ˆ]tð´ïqâäÞ›âi{µ["»Eû}±Ý8©÷YwÚñ².J¬Ë½ÌÓÞË<í½åv°½Qæ`ï»ßÖðöóåu²>Dät)­Ð'9ÎM‹RóƒJ‰žŽÃ¡±|èÁ$S‡(t¿¼$Sù.ˆŽ«fÓ}iχ}Êã‹iÝÌÊÑîä˸iI˜ëì¦å§º©ÚX¯ mØ}qS᳎„YzÖ¶£>[ÙÕ„`}ÿ¼ŸÚ;ïªóÛÀ’ 6ÇÒjsÜÁì‘¢.’·±¬Ï5Úmìèè6<è·+ðÎxUì{ËT×zäÝá·« hQrØ¿®²ä°ª×{`¤¢ QAûÒíBÕAÚÓ¨óX&*ާdµkëqãD Œk^Èü*ø ò8ú¹Ž ‹C׈¶²mÜ|°NÇíôÉ7-7h¥´µÇZå‘ix«vÛõ{ #p¿…4/fC£ßë´×‡}{Ða%šTâ;ÕÈ'̪9Õò)ÌÕZ‘ލG˜å‰Zhav–6sÊà3=Œ†¨|Üø^É KÏ„Ø)|zí¤œÚ÷ž ãÙayǸqÊ7NzØHÑkè¶Ôñv¼x j+±keÞ‚Bÿe‘âÿ’ÿ¹L^|@^RàVz”*}WvŽŒ]lÍô.õ² VYvÌwžë…‡°[kT†ÝZžL€Çˆ(ûËVÜMǘØ<¨¼·Lžo ¥½ƒ±YL{`^5íꘫ“rÚ#Ù) `«’rÚ]Ù?!`Ÿ&=C¿ÊÜ`‹,˜ƒ gØR æd-‡ [iÁ\ìÄ`¤H—w³ Ñ(†}bÁ2’òá™,ž™©çÞOLÝ¥zQW6üGqÄ¥Á`£Æex¦â‰ø/ã´'ÈÎéf{äØäÏ¡¦[Š:Éã×ùØÃ°V™ÔЧ¦ ØHž¦ {VÌdÙÆOE<¿ì„GÈÕÀwŠñÝ|km|kqD\…MWi|âÁ<©“y£Ó>[Jòµj ¥¦íº©âñØ!~à8VÀéÔB‘oE3òbßÔ;(~Ù(êŒíÆMPoù.PÔ/ûŽ‚ë ˆœô­/ˆ„ù¤3¾4yõ/Còèølyu$}Évׯ‰ýàåÿ˜¶Có¹ÙͶ¼Ñ²íf»Òï Ž¼·®: k¶èø0{ŠÊ‹>À,l/” l«ý}½Ð†°Cý¼´ !‚ïw»Ýótà™Ìé•߇ÉtÆŸ/3ñÎ@Lï•lA-å(ix𣤙4EûxMÈç:K$ êYtr,à—žhP ú:…‚”ÌJ/&±rчŒÎ9° aôðò±²ŒÀËî’Ih£§Ld_w±0çJ^7& — cI!F/•fÌ7y.Ì/° æßЭ.€ˆ{0å¬bU¸zçPUÖÕ‹+ØËOXöò·²ŒuœMýš\Æ~®Ä{¥YºL(v¶=×…{îî¹i=w@õÜqAä™ÕsGþKÏoÐs'Ðsœ^Š”½¨a){QÜ=uvzÓÇ›(e˯ÐáM“H3Õ‘gUG‚q=Oà VG^T p¥žêÈ.º 72ª#»êÜ‘l„EÿoÙ[Ë>”«¯žêÈ~zUY7/„ÌÒ;rÄÈÁ::r—±0 ‡êÔ‘ÃôTGŽÂ£Î»~l >ô#”õYK¿×¸5Õ®~0"N)Ýq*¥{ÓJ3/Í­Ö•ì‚2<ë2o^³ÐÕ+©i ΃”»5·ëç¶êùçpJ7ú{M6~¸I§-¨¿WnÑãeݽšŒ³é5®©ùLÔ´Š3Â)„ßÚ¿Õåw?ÀB¸xå á!–ÇN!L*áÂ^~¼[½„¥V×.éDÃ]!XG>¡&VÇÏO¬nޏYÒÙ+,÷bŽŸ÷pÖ›h¢~^3Q>8OöÎuoîíÇPêH‡UêH‡í°æñ˜ÿRÜûÉâp96A¡}qp^K9 hûøuZ)oí<nžP^/û<“{ râ{ÔÛÎæú‡\âPî/úy1 ÓÜ_|è¨2ÙŒãr.¨ŠÆ”0Êö±Äi·¦á§x}ýºËñ'T`³ƒ­Ï³ÚëV^QÂtÈ­ìš| W™¹MšvŸÒ׋ÛrŸr-±6U3Á›—éÀÉ낤ÚÛÕ~Üy¿A!ûìÎÛçìÎ;ô_:ï¨%Y3³¿?3Óñƒ–:î«eâyg~7˜fž)žwóSç€Ñb¯í!_;BŽ“yš¦…ï}îÂóŒ¶Ù]?:äGå—?r9.tPÉsŽ w¾¿=Uí‚%/9Â3¡)3Sà™“Uddf`‚T:+Üt¯»"nôVûí»N,î®N,îEÙÍI‹»»Ó”=œU²§3!{QZéÜÙB¦’Lè„qZL•ÁNÚ%*Ô^0NŽø33ܸýÃÿ¥ýÃÜ~|QûñõUÈ1Ò)G;©ý¬öqrûÇ:å'·¬ó²öS5ZL5O?÷š²½š‰´›âníTníâ€ü­F­N­A­Ù µs¬Âx,L¶wqZ{—¢½ý§;ã!4w7w¦Ø†zk+œr…³@«æYXã!ö'«*q¢åGÎx¾YÖÛ«SŠÖÝ»¦!îKÙKÔ ?ž­oµN›ŒtÊuÎ8_v<ÐÃ4ºèüÕYçóo=r NåÚ`çÚà”66ûMÈ5„7©W‘k‹k uû®¨vJ“Nêì|^©UN“÷c[¶1ÍI#P^-kœfIW]“Ûѧ=¨ßªåWèŸwÏ7VvPß:Íé;<ÔŸE«ä”ƒ×wÛ5ô£åT…}<ò__‡tI_ß„uôµ;ä²_bÆøHAt_ ¢ŽQ”¬0„6.5t?`èÀ|ÌÄнÏC—‹ˆsvÏŸ°fbž]dáw>øöp'öf ÷B‘Ö›(ÜOo}u˜VÐûëÄg„óKóµÊ|¸Ædc½Ê¶B¨'ªŒáy©„Ÿ#ò V5LyxQk£§«¼§ ’gqc’·|d± ‰è¦æÆÖæå›ÃAWal²—½PŽñ&Ê õ>äãÓÄ&yåð½³[å€Ù a~36Å'#íDoÙ(¯ÓaHÀ‹ Õ·åÃò”Òå¿ÃÅŒ"5õC„W`:¨>Ô1Pâ­Ò¡žoŒóB³OÙ“Ÿì}“u Wêmå':¯=±UÄžÕxî!Š Vì 9Öè04Fùª¨¾%ë2´×i»ÿL¯pB³OU¸Â™˜ ÍZ¹žÀŒaµ£ Yh –Ö×ËzB¥ÆND¼O‚Ë€’Í迉ޙÃY[=®Ó®”À´Æ~DèªäþòòÜÛìÜÊ_‡¬ÖѲáêúQÖèŒjŽ•x»O” òŠ7ùŠl7…°ätäDžè•tä^[¥a¯îÙ†«Ï㺵ˆ@gÕ꼈 6)ëtŒ—}Ù9Þ«.;±Ôí­IžÖ=7àfôŒbFœU³€/>G啘n›è•?êØ PN9­¢sjôcS½ò¼îÙ‡J\´²_Ò=_"\éPáÎD`OõhÙ(ö]G!lâÝžYlÑÜû:R.`(°£óªå1=ýöT¹€ýa+’7¯¸=½`¹ŠM¤¹€­×Óom• ØîŽôÕŸº€ÕÙìœKõ§.ÕßZ_ÿ@}ý_• Øþàè&ù¡ËüwÞœ™×™v•6Ðá¹mm·ÕÏc²­cñ‚ztÖ¬dynÇe¯Ãäæâê¬ý_l‘˜õõbZ}=}){k“ùþko ³atl®#^6’6Îù5Hc½å»„\è€þ3Ý"»ø%ë4-ÐæµÂëpK+œ:fóÁõ¡#nÅ ÿ 4ŒßGŽä´ùÔO;ŽÊÞ£™ú™#}ެCU§ðÁôçÜ[s›jÄt~áÀ檜Ålâß„dˆEÍMóʸ#¢ ‡ïò( ®”­mg#ª’[Ìèêô3-ð uÑ6”;ÕŸIOuPÕ8`÷r·ª6[ÕЖ1èy'”`h»"fV'vökGú¦/–!A&xóýAú½ÇÁ„Ç@à—Ÿ ^ùG[´ÇhE<ìgwÒAÔåîƒ;P•ÃkéVÌozVpZÇÐ~B{ÜÐÈ?Íï¢ü­_ÚM‘ù=åÿÀ[´?”³e'š;åId™î·¥j)Ó© Ö§é_»^L%ô"ŽÊûS6ºgúá{r”«î€õæØß…7Çu¼9Ê›ãÎl}μÉù |0¿ò–ç]ž l¿_ÌN”^ÌÉG<é, ¯q$ªJ×8t†>î¹Чª”m~%^þtøLf¢ôL&edwuÏ„'¸¥\æLÿãq Ó³ááÙ„jx¶Bõœç8J„÷º×‚þÙSèóÉr`C(|±Y‚øŽ‹Í(ûcï¾àä‚K· 1<ãñ…ðzfDéz—ƒá/zºþr„¯„{f"{ÏLá«á­^@¶zm„ó<ŠŒo„!¢ªôW!ìä¹ð·ÃËš2|YSÇs àÿ ÷il;C±Y;šlkWò°²œôÇù)\\)§àL`[•Ov܆éüZõGåAÞ‚9øµ*¬<X0'¿V•+§äÌÅûmLù¯°`nÞo;ö½ ËàýöuÀŽÙ°LÞoßì¤ ËJnpxƒk”éÎͪ¯o´æbýö‹õ'.Ößp©þ®Kõe—ê{^ª©~Ç¥úºKõ”‚ø LŸåO“ާiÚ4Õl¿-O–á÷òÔLoýšX&úêf®0íê†dõS Á¶´ Rm¾W)]þ¸1Ç›|¹½ÉŒÞll̉sS°›í‡šy)<†Îó+ÛþÙ6˜¼5nÌ÷ÕP­šïÇs׳ˆ¹ËÚî’¿á÷]JRÓà}÷ †÷ÝÔ Í|o²b¼g´ ¯uY©Ø¬ -ðã•(EüÎ*âw²ä²„Ð}[èWo5-µEJø0-eËè?4ùm-½ƒ“w¹5¨>ê©f67•=û“ ƒƒZqä` hH0v\俳±ËMüár'\Äpw.q«<úü0è¤ÏQÅ.úŒ_í¦Ï)×gÐçäë3és¿/ë>ù@ܤ•ú°C>H æ"/Tú²b˼ÄV4Š-÷£+¶Ø WŒîØ/\1fÄ–záŠ13ö¡—·Ô¯$ ¨:ÏÐ µ‹Ë@Ř?Oàqc9ÀËR`Ëãb€—û• Fÿ‡À`ó–¾Â¯ý¥äZŠˆ•©ˆñˆ€EžEˆø(1x^úûSįW¹H„ÿí¥#›-Ա؋bQò !¨ué?¡û‰ß–è8„1›’èè ‰ŽŒ‘û45rCƒZëÈ¡@Ѱ`ìFn•ßét¹oª;ÌÐMÔ`Y”Xåêîè¡Ë¡”ÒјÝ;¬æ ˆr=NÕ~2 wDãÒÞnIÖøméVŠ¿1<.U­~¨Vo8êµ6U¯áAí‘âÁØaÔë3¿’‘9’AkB¹^A®Wô™#ˆWU®[+\?¬ð²šË:¿’‘9¢ „µ·H“‘ÙŸQÚ22ë­1?‚-pF²ò9WýZø· Éü4­Ïþ¨y @álrƒ?å3ö kšÔçHÚ§äµØk®ƒ€UÁ¯Ã¥± %lò+·¹nàÁ6¶ÊËl7§²)/¼ÆjdÛ’ÊVlecÝØj/+ëlMe»²Ý7Ö [<•ín+Ûݰ|[ãe׬f*›å=l-²%RÙ~geû|¡ÆÖzy{©JÅ?lųVtì3µþ¾äùQ€xË äg^uïùd<|gé>(,'ûœ’_­úüô¯ÝôùŸeQè4r¦Æ¯9­;R>÷ß Ý/r‚>çé7À±ŸãxòsÞG~®¨3i\n¢-eƒWÞ¯Š}á•·`ÒlòR‡š±^ÚÎicÙì¥^¥e‹êÖí~åz™ ²ºuª¼#¦n…Î/Þ™[½¹ à¯R`Ë‚æF€w¥À–ÍÍ[}·àoø$¼>PC¶Ï+Ú ¤ƒð@ÐC»ùhR=ô­ßíÈÌŠÔ#:Ñr%rhí)Œ>9¨r\Á´ s—%ˆ-ÀF°Ç[¹(†7‚¸Qãe_#OÅ˪ˆÐ…vÕw©4ÏRš?q¸‰Ä˾¤4†´M(+MGë¼ê(_¦²9¸¬W 6ç×Ý™YãýÍJô·Z1è:ñ:H×éo°WöNµâxÈù–|Ý4¶7«|°Z¾a;èG tG¶{i—ª,~Þ)ߎ^È@¸¤‹S¼ItÚßÙ˜ùªè¥ £Þ13çjx©pÙ!ý¿­ôe•NÁ÷HïÕÂ5R½#Šh}FaÙÆFBiuäEËPÀŠd0ÜùÑO ø8½îãOôñZ`=DNf–X×ÙþWÖ e8ép*n£·QÈ-ˆ;‚u”q œá†äMá÷Óéž7Š£ç3ð×n®ŒBlõ"×Ñ´-ÿ˜JM×Õ¥¶üüxt|^tº`Öö+¯¼òŠÖîz‚·)ycÜø KùDòئˆô o06¼^€Qdm]+ý0×Ú¡NZZŸS}Ðú¬ ‰BØÐ aCÀƒ$¡ˆ§VptLçáOŒÓîö²ìcQ"úÎBæÓnN¡;!/n|­fJ«cRö6”ÖÚZi­åmÑÚŒTRLÓÛd"A¾Q™ñ3?üJŽÈ}§•ûNywøJ]òŽ0&åh¸9cùÇ_'Á“œ¦*Ý›–6*3—ò·i‰£uÏ«ûâiÉÓR”}ëÕå ªˆJà éInß_PöÖ]O[ù0,ÆSò,:=ÛÏ4©6ì–ÍD"U-~æ …ªx#`\ƒ'! 燄ãPÞS(/‘«=U+ªrÅSòª oDm·.ÿfJÿHA6°ò,ýHÀ„ÊŸÂ'3ÌDÙÉ ]†!/ç·åådM[5Ÿßh7DÑñ»¼ˆgy9Jäê ßk_Sw&mZ%ÕˆÍØwŠ¢:ËÑ‹T4ämqã;¯1½?ú•åû3!E_Œq2}¡œ×›Æx¡dç’÷”ðúð´ä¢{…þµÊ/#Ž­Î¦­´ ~ÝárßP÷cÔ[-ù%q׋_ÒYŽZÞB'ú/OÚ‹ÔÉ.÷D‰/nQMôbHkOgC ÑA¶/¨ßóÐûQóÑkª#¿Z³Û,›¥R²Ï+:UÃÞ'WÆ_Ã]n2Þ²“½¾Í3›ÂpÎÎþÚ-š€+ï"llb¼…ï]‘Dè$fùo¬hoW©ý\ûŽü€W©x ) TÔý”å¸*.⦅qD #.ÃG ”† óÓV¯o³ªC¹ŸŸ=V˜«¶ÑyÉŽK~hWþ]Õð½yÌ’.þ]ŸA¥#4‰òÔ3Q—ƒ<öA±>#ú2,°WlŠÿGŒïtߎô¯Ý0li{½€cl; «©œ·Œ j·FŽŠâþØ‘1…Aqoäh ht0v”‚ïõ6‘c¢1ÁØ1 ®*p”FŽŠ6øbÇ)86è|:r"P4.;AÁ÷ƒ®h¤6P4>«¥à„ »""Eƒ1IÁIÁŒW"u¢ÉÁX§3ÿù>P45ûž‚³ºŠÈÉ@Ñ´`ì$…W4 "§E£ü±Sžl¦½+ëM¶ ójdfÁ‘:`ôÅÆ^ Ry®»¬¼«|fºäk'BR½½Ž¸|:°it"4SJùüp¢ðF x$Ëm—§—BZ9ÔmîbŸ§•+áÿöy «ÍÒkõP;Âht€ôµNCó`6Œª{:öºRô Jðc¥PÈþ¢\çâŠì¡îÊšÙ](Ú÷¯@…julC4ä[ #û-ƒ©bðõ™yš¸K›•§é+…Ö›{ñÜ‹}¸9ýDtvª§R?ÞÌ»YdvEpGNEG²=\‚Ø99;ÏÓR‰àÏæžä'´Á±èʦ¼½&(±rmׇ;s%—^)ìÞ¬l­UŠË»³‹ áÝ8Ù¡Ï2%ÿÿУÝÅe]:õ².‰Ò[Ø}ÚG´é€’@ªWG «[g§wk_îÖ[¸[gpÃf‰Èœ¼èjù´¬&p@:'¯“27<-«Sùœ<Ú©+úqW,çï'»¢Kkí}*¦EZGL Ÿð_Ã6ZÒzâl7úÿ¡'¦Ø=ÑÄê ª–í$§“ÕÓ“1C´éÀ’êˆyvGÌɃk<«#úóbö î±g½:ÑN"ªZ"âc>PÞ»IûXÐQv“øX@¡hãÕfâ½ì0Qa«Ø”idßõÈ¡x†É׃gøœ’nºÚ|FpJæ îŒÌÙ:’ndcz+EM>8Gü‚ÙöÞÊ&ëê  Îbsz>©„ú¾UÈ­ÿ—½X#ã¢*ß–'!ªLcF^U¢lnžîœÛ²5Td·«Û›ý;åÍ·°Ík¬£ržŽ ¾Ο”B<î.bY)YjÓ'n¢Ròëð´&ëì&Ê®pqáò[Ñ–^Ÿò&ñZåÉTT¾¿7QûÑmƒP-¸½†3ž=³}O /¨™"¹ùÖ²»u/ì>vB×” â€Ã‘™y?OøÎ:õ`P¼Ëýÿ®N' ‘ÔYT%"yºê œžÆ69Ž*ët]pûÜÓê.÷ýT6ËhÌÈ6>•í+ûFipԺïîìPqëm·V´þ³Ñ±üõØŸÛ¿ðú«Ëßùó^}í…7:hÏ6¢“V#êAsÒI¨þ[4á?][R™mèMû?ó¬Œ9red5-1.0~svn4374.orig/webapps/live/0000755000175000017500000000000011760512575016724 5ustar drazzibdrazzibred5-1.0~svn4374.orig/webapps/live/WEB-INF/0000755000175000017500000000000011760512575017753 5ustar drazzibdrazzibred5-1.0~svn4374.orig/webapps/live/WEB-INF/web.xml0000644000175000017500000000233111332146107021236 0ustar drazzibdrazzib live webAppRootKey /live rtmpt org.red5.server.net.rtmpt.RTMPTServlet 1 rtmpt /fcs/* rtmpt /open/* rtmpt /close/* rtmpt /send/* rtmpt /idle/* red5-1.0~svn4374.orig/webapps/live/WEB-INF/red5-web.properties0000644000175000017500000000006111332146107023465 0ustar drazzibdrazzibwebapp.contextPath=/live webapp.virtualHosts=* red5-1.0~svn4374.orig/webapps/live/WEB-INF/red5-web.xml0000644000175000017500000000241411747114732022106 0ustar drazzibdrazzib red5-1.0~svn4374.orig/webapps/red5-default.xml0000644000175000017500000000346211747114732020773 0ustar drazzibdrazzib org.red5.server.persistence.FilePersistence red5-1.0~svn4374.orig/red5.sh0000755000175000017500000000242111263741720015513 0ustar drazzibdrazzib#!/bin/bash if [ -z "$RED5_HOME" ]; then export RED5_HOME=`pwd`; fi P=":" # The default classpath separator OS=`uname` case "$OS" in CYGWIN*|MINGW*) # Windows Cygwin or Windows MinGW P=";" # Since these are actually Windows, let Java know ;; Darwin*) ;; *) # Do nothing ;; esac echo "Running on " $OS # JAVA options # You can set JAVA_OPTS to add additional options if you want # Set up logging options LOGGING_OPTS="-Dlogback.ContextSelector=org.red5.logging.LoggingContextSelector -Dcatalina.useNaming=true" # Set up security options SECURITY_OPTS="-Djava.security.debug=failure" export JAVA_OPTS="$LOGGING_OPTS $SECURITY_OPTS $JAVA_OPTS" if [ -z "$RED5_MAINCLASS" ]; then export RED5_MAINCLASS=org.red5.server.Bootstrap fi # Jython options JYTHON="-Dpython.home=lib" for JAVA in "${JAVA_HOME}/bin/java" "${JAVA_HOME}/Home/bin/java" "/usr/bin/java" "/usr/local/bin/java" do if [ -x "$JAVA" ] then break fi done if [ ! -x "$JAVA" ] then echo "Unable to locate Java. Please set JAVA_HOME environment variable." exit fi export RED5_CLASSPATH="${RED5_HOME}/boot.jar${P}${RED5_HOME}/conf${P}${CLASSPATH}" # start Red5 echo "Starting Red5" exec "$JAVA" "$JYTHON" -Dred5.root="${RED5_HOME}" $JAVA_OPTS -cp "${RED5_CLASSPATH}" "$RED5_MAINCLASS" $RED5_OPTS red5-1.0~svn4374.orig/red5-debug.bat0000644000175000017500000000025011614272623016727 0ustar drazzibdrazzib@echo off if NOT DEFINED RED5_HOME set RED5_HOME=%~dp0 set JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n %RED5_HOME%\red5.bat red5-1.0~svn4374.orig/test/0000755000175000017500000000000011760512565015302 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/logback-selftest.xml0000644000175000017500000000132011134224473021242 0ustar drazzibdrazzib selftest log/selftest.log false UTF-8 false true %date [%thread] %-5level %logger{35} - %msg%n red5-1.0~svn4374.orig/test/org/0000755000175000017500000000000011760512565016071 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/0000755000175000017500000000000011760512565016730 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/spring/0000755000175000017500000000000011760512565020232 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/spring/placeholder_context.xml0000644000175000017500000000262211153004603024765 0ustar drazzibdrazzib classpath:/org/red5/spring/test.properties classpath:/org/red5/spring/test.properties classpath*:/org/red5/spring/test_*.properties classpath*:/org/red5/spring/test_*.properties classpath:/org/red5/spring/test.properties classpath*:/org/red5/spring/test_*.properties classpath:/org/red5/spring/test.properties red5-1.0~svn4374.orig/test/org/red5/spring/test.properties0000644000175000017500000000007711153004603023314 0ustar drazzibdrazzibkey1=value1 key2=value2 key3=value3 override_key=not_overridedred5-1.0~svn4374.orig/test/org/red5/spring/ExtendedPropertyPlaceholderConfigurerTest.java0000644000175000017500000000733711153004603031424 0ustar drazzibdrazzibpackage org.red5.spring; import java.io.IOException; import java.util.Properties; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import static org.junit.Assert.*; public class ExtendedPropertyPlaceholderConfigurerTest { protected ApplicationContext context; protected Properties testProperties; protected Properties testAProperties; protected Properties testBProperties; @Before public void loadSpringContext() throws IOException { context = new ClassPathXmlApplicationContext( "/org/red5/spring/placeholder_context.xml" ); testProperties = new Properties(); testProperties.load( this.getClass().getResourceAsStream( "/org/red5/spring/test.properties" ) ); testAProperties = new Properties(); testAProperties.load( this.getClass().getResourceAsStream( "/org/red5/spring/test_a.properties" ) ); testBProperties = new Properties(); testBProperties.load( this.getClass().getResourceAsStream( "/org/red5/spring/test_b.properties" ) ); } @Test public void testLocationsProperty() { ExtendedPropertyPlaceholderConfigurer configurer = (ExtendedPropertyPlaceholderConfigurer)context.getBean( "boringPlaceholderConfig" ); assertEquals( testProperties, configurer.getMergedProperties() ); } @Test public void testWildcardLocationsProperty() { ExtendedPropertyPlaceholderConfigurer configurer = (ExtendedPropertyPlaceholderConfigurer)context.getBean( "wildcard1PlaceholderConfig" ); Properties mergedProp = new Properties(); mergedProp.putAll( testProperties ); mergedProp.putAll( testAProperties ); mergedProp.putAll( testBProperties ); assertEquals( mergedProp, configurer.getMergedProperties() ); configurer = (ExtendedPropertyPlaceholderConfigurer)context.getBean( "wildcard2PlaceholderConfig" ); mergedProp = new Properties(); mergedProp.putAll( testAProperties ); mergedProp.putAll( testBProperties ); mergedProp.putAll( testProperties ); assertEquals( mergedProp, configurer.getMergedProperties() ); } @Test public void testLocationsPropertyOverridesWildcardLocationsProperty() { ExtendedPropertyPlaceholderConfigurer configurer = (ExtendedPropertyPlaceholderConfigurer)context.getBean( "locationsOverridesWildcardLocationsPlaceholderConfig" ); Properties mergedProp = new Properties(); mergedProp.putAll( testProperties ); assertEquals( mergedProp, configurer.getMergedProperties() ); } @Test public void testRuntimeProperties() { ExtendedPropertyPlaceholderConfigurer.addGlobalProperty( "runtime_key1", "value1" ); ExtendedPropertyPlaceholderConfigurer.addGlobalProperty( "runtime_key2", "value2" ); context = new ClassPathXmlApplicationContext( "/org/red5/spring/placeholder_context.xml" ); ExtendedPropertyPlaceholderConfigurer configurer = (ExtendedPropertyPlaceholderConfigurer)context.getBean( "locationsOverridesWildcardLocationsPlaceholderConfig" ); Properties mergedProp = new Properties(); mergedProp.putAll( testProperties ); mergedProp.put( "runtime_key1", "value1" ); mergedProp.put( "runtime_key2", "value2" ); assertEquals( mergedProp, configurer.getMergedProperties() ); } @Test public void testRuntimePropertiesOverrideLocationsProperty() { ExtendedPropertyPlaceholderConfigurer.addGlobalProperty( "override_key", "runtime config" ); context = new ClassPathXmlApplicationContext( "/org/red5/spring/placeholder_context.xml" ); ExtendedPropertyPlaceholderConfigurer configurer = (ExtendedPropertyPlaceholderConfigurer)context.getBean( "wildcard2PlaceholderConfig" ); assertEquals( "runtime config", configurer.getMergedProperties().getProperty( "override_key" ) ); } } red5-1.0~svn4374.orig/test/org/red5/spring/test_a.properties0000644000175000017500000000010011153004603023577 0ustar drazzibdrazzibkey4=value4 key5=value5 key6=value6 override_key=overrided_by_ared5-1.0~svn4374.orig/test/org/red5/spring/test_b.properties0000644000175000017500000000010011153004603023600 0ustar drazzibdrazzibkey7=value7 key8=value8 key9=value9 override_key=overrided_by_bred5-1.0~svn4374.orig/test/org/red5/io/0000755000175000017500000000000011760512565017337 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/io/m4a/0000755000175000017500000000000011760512565020020 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/io/m4a/impl/0000755000175000017500000000000011760512565020761 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/io/m4a/impl/M4AReaderTest.java0000644000175000017500000000255011706617130024164 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.m4a.impl; import java.io.File; import junit.framework.TestCase; import org.junit.Test; import org.red5.io.ITag; import org.red5.io.m4a.impl.M4AReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class M4AReaderTest extends TestCase { private static Logger log = LoggerFactory.getLogger(M4AReaderTest.class); @Test public void testCtor() throws Exception { File file = new File("fixtures/sample.m4a"); M4AReader reader = new M4AReader(file); ITag tag = reader.readTag(); log.debug("Tag: {}", tag); tag = reader.readTag(); log.debug("Tag: {}", tag); } } red5-1.0~svn4374.orig/test/org/red5/io/utils/0000755000175000017500000000000011760512565020477 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/io/utils/XMLUtilsTest.java0000644000175000017500000001604011706617130023656 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.utils; import static org.junit.Assert.*; import java.io.IOException; import org.junit.Test; import org.junit.Ignore; public class XMLUtilsTest { private static final String XML_STRING = "Red5 is awesome"; private static final String XML_STRING_HUGE = " *\"/> *\"/> *\"/> *\"/> *\"/> *\"/> *\"/> *\"/> *\"/> *\"/> *\"/> eclipse\"/> *\"/> *\"/> *\"/> *\"/> *\"/> "; @Test public void testStringToDoc() throws IOException { XMLUtils.stringToDoc(XML_STRING); XMLUtils.stringToDoc(XML_STRING_HUGE); } @Test @Ignore public void testDocToString() { fail("Not yet implemented"); } @Test @Ignore public void testDocToString1() { fail("Not yet implemented"); } @Test @Ignore public void testDocToString2() { fail("Not yet implemented"); } } red5-1.0~svn4374.orig/test/org/red5/io/mp4/0000755000175000017500000000000011760512565020037 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/io/mp4/MP4FrameTest.java0000644000175000017500000000473211706617130023115 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp4; import java.util.ArrayList; import java.util.Collections; import java.util.List; import junit.framework.TestCase; import org.junit.Test; import org.red5.io.mp4.MP4Frame; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MP4FrameTest extends TestCase { private static Logger log = LoggerFactory.getLogger(MP4FrameTest.class); @Test public void testSort() { log.debug("Test sort"); List frames = new ArrayList(6); //create some frames MP4Frame frame1 = new MP4Frame(); frame1.setTime(1); frame1.setOffset(1); frames.add(frame1); MP4Frame frame2 = new MP4Frame(); frame2.setTime(6); frame2.setOffset(6); frames.add(frame2); MP4Frame frame3 = new MP4Frame(); frame3.setTime(660); frame3.setOffset(660); frames.add(frame3); MP4Frame frame4 = new MP4Frame(); frame4.setTime(3); frame4.setOffset(3); frames.add(frame4); MP4Frame frame5 = new MP4Frame(); frame5.setTime(400); frame5.setOffset(400); frames.add(frame5); MP4Frame frame6 = new MP4Frame(); frame6.setTime(1000); frame6.setOffset(1010); frames.add(frame6); MP4Frame frame7 = new MP4Frame(); frame7.setTime(1000); frame7.setOffset(1000); frames.add(frame7); MP4Frame frame8 = new MP4Frame(); frame8.setTime(1000); frame8.setOffset(900); frames.add(frame8); System.out.printf("Frame 1 - time: %s (should be 660)\n", frames.get(2).getTime()); Collections.sort(frames); System.out.println("After sorting"); int f = 1; for (MP4Frame frame : frames) { System.out.printf("Frame %s - time: %s offset: %s\n", f++, frame.getTime(), frame.getOffset()); } } } red5-1.0~svn4374.orig/test/org/red5/io/mp4/impl/0000755000175000017500000000000011760512565021000 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/io/mp4/impl/MP4ReaderTest.java0000644000175000017500000001300311706617130024215 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp4.impl; import java.io.File; import java.nio.ByteBuffer; import java.nio.ByteOrder; import junit.framework.TestCase; import org.junit.Test; import org.red5.io.ITag; import org.red5.io.flv.IKeyFrameDataAnalyzer.KeyFrameMeta; import org.red5.io.mp4.impl.MP4Reader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MP4ReaderTest extends TestCase { private static Logger log = LoggerFactory.getLogger(MP4ReaderTest.class); @Test public void testCtor() throws Exception { File file = new File("fixtures/sample.mp4"); // contains version 1 sound description //File file = new File("E:/dev/red5/java/server/trunk/distx/webapps/oflaDemo/streams/transformers_720p.mp4"); // contains version 0 sound description //File file = new File("E:/dev/red5/java/server/trunk/distx/webapps/oflaDemo/streams/mp4_with_aac.mp4"); // contains some itunes atoms and junk aac bits //File file = new File("E:/dev/red5/java/server/trunk/distx/webapps/oflaDemo/streams/codonics-high.mp4"); //File file = new File("E:/dev/red5/java/server/trunk/distx/webapps/oflaDemo/streams/ANewHope.mov"); //File file = new File("E:/dev/red5/java/server/trunk/distx/webapps/oflaDemo/streams/IamLegend.mp4"); //File file = new File("E:/dev/red5/java/server/trunk/distx/webapps/oflaDemo/streams/mp4_with_mp3.mp4"); MP4Reader reader = new MP4Reader(file); KeyFrameMeta meta = reader.analyzeKeyFrames(); log.debug("Meta: {}", meta); ITag tag = null; for (int t = 0; t < 32; t++) { tag = reader.readTag(); log.debug("Tag: {}", tag); } log.info("----------------------------------------------------------------------------------"); //File file2 = new File("E:/media/test_clips/IronMan.mov"); //MP4Reader reader2 = new MP4Reader(file2, false); } @Test public void testBytes() throws Exception { //00 40 94 00 00 00 00 00 00 00 06 == byte width[] = { (byte) 0x00, (byte) 0x40, (byte) 0x94, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; System.out.println("width: {}" + bytesToLong(width)); // byte height[] = { (byte) 0x40, (byte) 0x86, (byte) 0x80, (byte) 0x00 }; // System.out.println("height: {}" + bytesToInt(height)); // // byte timescale[] = { (byte) 0x40, (byte) 0xA7, (byte) 0x6A, (byte) 0x00 }; // System.out.println("timescale: {}" + bytesToInt(timescale)); // // byte duration[] = { (byte) 0x40, (byte) 0x6D, (byte) 0xE9, (byte) 0x03, // (byte) 0x22, (byte) 0x7B, (byte) 0x4C, (byte) 0x47 }; // System.out.println("duration: {}" + bytesToLong(duration)); // // byte avcprofile[] = { (byte) 0x40, (byte) 0x53, (byte) 0x40, // (byte) 0x00 }; // System.out.println("avcprofile: {}" + bytesToInt(avcprofile)); // // byte avclevel[] = { (byte) 0x40, (byte) 0x49, (byte) 0x80, (byte) 0x00 }; // System.out.println("avclevel: {}" + bytesToInt(avclevel)); // // byte aacaot[] = { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x40 }; // System.out.println("aacaot: {}" + bytesToLong(aacaot)); // // byte videoframerate[] = { (byte) 0x40, (byte) 0x37, (byte) 0xF9, // (byte) 0xDB, (byte) 0x22, (byte) 0xD0, (byte) 0xE5, (byte) 0x60 }; // System.out.println("videoframerate: {}" + bytesToLong(videoframerate)); // // byte audiochannels[] = { (byte) 0x40, (byte) 0x00, (byte) 0x00, // (byte) 0x00 }; // System.out.println("audiochannels: {}" + bytesToInt(audiochannels)); // // byte moovposition[] = { (byte) 0x40, (byte) 0x40, (byte) 0x00, // (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; // System.out.println("moovposition: {}" + bytesToLong(moovposition)); // // //byte[] arr = {(byte) 0x0f}; //System.out.println("bbb: {}" + bytesToByte(arr)); //byte[] arr = {(byte) 0xE5, (byte) 0x88, (byte) 0x80, (byte) 0x00, //(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; //System.out.println("bbb: {}" + bytesToLong(arr)); byte[] arr = { (byte) 0, (byte) 0, (byte) 0x10, (byte) 0 }; System.out.println("bbb: {}" + bytesToInt(arr)); } public static long bytesToLong(byte[] data) { ByteBuffer buf = ByteBuffer.allocate(8); buf.put(data); buf.order(ByteOrder.BIG_ENDIAN); buf.flip(); return buf.getLong(); } public static int bytesToInt(byte[] data) { ByteBuffer buf = ByteBuffer.allocate(4); buf.put(data); buf.order(ByteOrder.BIG_ENDIAN); buf.flip(); return buf.getInt(); } public static short bytesToShort(byte[] data) { ByteBuffer buf = ByteBuffer.allocate(2); buf.put(data); buf.flip(); return buf.getShort(); } public static byte bytesToByte(byte[] data) { ByteBuffer buf = ByteBuffer.allocate(1); buf.put(data); buf.flip(); return buf.get(); } } red5-1.0~svn4374.orig/test/org/red5/server/0000755000175000017500000000000011760512565020236 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/net/0000755000175000017500000000000011760512565021024 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/net/RTMPUtilsTest.java0000644000175000017500000000651311746040404024327 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net; import junit.framework.TestCase; import org.junit.Test; import org.red5.io.utils.HexDump; import org.red5.server.net.rtmp.RTMPUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class RTMPUtilsTest extends TestCase { protected static Logger log = LoggerFactory.getLogger(RTMPUtilsTest.class); public void testDecodingHeader() { if (log.isDebugEnabled()) { log.debug("Testing"); /* log.debug(""+(0x03 >> 6)); log.debug(""+(0x43 >> 6)); log.debug(""+(0x83 >> 6)); log.debug(""+((byte)(((byte)0xC3) >> 6))); */ } byte test; test = 0x03; if (log.isDebugEnabled()) { log.debug(HexDump.byteArrayToHexString(new byte[] { test })); log.debug("" + test); log.debug("" + RTMPUtils.decodeHeaderSize(test, 1)); } assertEquals(0, RTMPUtils.decodeHeaderSize(test, 1)); test = (byte) (0x43); if (log.isDebugEnabled()) { log.debug(HexDump.byteArrayToHexString(new byte[] { test })); log.debug("" + test); log.debug("" + RTMPUtils.decodeHeaderSize(test, 1)); } assertEquals(1, RTMPUtils.decodeHeaderSize(test, 1)); test = (byte) (0x83); if (log.isDebugEnabled()) { log.debug(HexDump.byteArrayToHexString(new byte[] { test })); log.debug("" + test); log.debug("" + RTMPUtils.decodeHeaderSize(test, 1)); } assertEquals(-2, RTMPUtils.decodeHeaderSize(test, 1)); test = (byte) (0xC3 - 256); if (log.isDebugEnabled()) { log.debug(HexDump.byteArrayToHexString(new byte[] { test })); log.debug("" + test); log.debug("" + RTMPUtils.decodeHeaderSize(test, 1)); } assertEquals(-1, RTMPUtils.decodeHeaderSize(test, 1)); } @Test public void testDiffTimestamps() { int a; int b; a = 0; b = 1; assertEquals(-1, RTMPUtils.diffTimestamps(a, b)); assertEquals(1, RTMPUtils.diffTimestamps(b, a)); a = Integer.MAX_VALUE; b = Integer.MIN_VALUE; assertEquals(-1, RTMPUtils.diffTimestamps(a, b)); assertEquals(1, RTMPUtils.diffTimestamps(b, a)); a = Integer.MAX_VALUE; b = 0; assertEquals(Integer.MAX_VALUE, RTMPUtils.diffTimestamps(a, b)); assertEquals(-Integer.MAX_VALUE, RTMPUtils.diffTimestamps(b, a)); a = -1; b = 0; assertEquals(0xFFFFFFFFL, RTMPUtils.diffTimestamps(a, b)); assertEquals(-0xFFFFFFFFL, RTMPUtils.diffTimestamps(b, a)); a = Integer.MIN_VALUE; b = 0; assertEquals(0x80000000L, RTMPUtils.diffTimestamps(a, b)); assertEquals(-0x80000000L, RTMPUtils.diffTimestamps(b, a)); } } red5-1.0~svn4374.orig/test/org/red5/server/net/rtmps/0000755000175000017500000000000011760512565022171 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/net/rtmps/RTMPSClientTest.java0000644000175000017500000000424111706617130025733 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmps; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; /** * Testing RTMPS client. * * @author Paul Gregoire (mondain@gmail.com) */ @ContextConfiguration(locations={"../../service/testcontext.xml"}) public class RTMPSClientTest extends AbstractJUnit4SpringContextTests { protected static Logger log = LoggerFactory.getLogger(RTMPSClientTest.class); static { String userDir = System.getProperty("user.dir"); System.out.println("User dir: " + userDir); System.setProperty("red5.deployment.type", "junit"); System.setProperty("red5.root", "file:" + userDir + "/bin"); System.setProperty("red5.config_root", System.getProperty("red5.root") + "/conf"); } { log.debug("Property - user.dir: {}", System.getProperty("user.dir")); log.debug("Property - red5.root: {}", System.getProperty("red5.root")); log.debug("Property - red5.config_root: {}", System.getProperty("red5.config_root")); } @BeforeClass public static void setUpBeforeClass() throws Exception { } @AfterClass public static void tearDownAfterClass() throws Exception { } @Test public void testStartup() { Assert.assertTrue(true); } } red5-1.0~svn4374.orig/test/org/red5/server/net/rtmp/0000755000175000017500000000000011760512565022006 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/net/rtmp/message/0000755000175000017500000000000011760512565023432 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/net/rtmp/message/HeaderTest.java0000644000175000017500000000627011706617130026324 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.message; import java.util.concurrent.atomic.AtomicInteger; import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner; import net.sourceforge.groboutils.junit.v1.TestRunnable; import org.junit.Assert; import org.junit.Test; public class HeaderTest { private final static AtomicInteger timer = new AtomicInteger(1); @Test public void testLifecycle() throws Throwable { int threads = 500; TestRunnable[] trs = new TestRunnable[threads]; for (int t = 0; t < threads; t++) { trs[t] = new HeaderWorker(); } Runtime rt = Runtime.getRuntime(); long startFreeMem = rt.freeMemory(); System.out.printf("Free mem: %s\n", startFreeMem); MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs); long start = System.nanoTime(); mttr.runTestRunnables(); System.out.printf("Runtime: %s ns\n", (System.nanoTime() - start)); for (TestRunnable r : trs) { Header hdr = ((HeaderWorker) r).getHeader(); Assert.assertTrue(hdr == null); } System.gc(); Thread.sleep(1000); System.out.printf("Free mem diff at end: %s\n", Math.abs(startFreeMem - rt.freeMemory())); } @Test public void testExtendedTimestamp() throws Throwable { int threads = 10; TestRunnable[] trs = new TestRunnable[threads]; for (int t = 0; t < threads; t++) { trs[t] = new HeaderWorker(); } // update the timer to extended time timer.set(16777215); //16777215, or 4hrs 39 minutes 37.215 seconds MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs); long start = System.nanoTime(); mttr.runTestRunnables(); System.out.printf("Runtime: %s ns\n", (System.nanoTime() - start)); for (TestRunnable r : trs) { Header hdr = ((HeaderWorker) r).getHeader(); Assert.assertTrue(hdr == null); } System.gc(); Thread.sleep(1000); } private Header newHeader() { Header header = new Header(); header.setChannelId(1); header.setDataType(Header.TYPE_AUDIO_DATA); header.setSize(16); header.setStreamId(1); header.setTimer(timer.incrementAndGet()); return header; } @Test public void testReadExternal() { // TODO } @Test public void testWriteExternal() { // TODO } private class HeaderWorker extends TestRunnable { Header header; public void runTest() throws Throwable { header = newHeader(); header.toString(); header = null; } public Header getHeader() { return header; } } } red5-1.0~svn4374.orig/test/org/red5/server/net/rtmp/codec/0000755000175000017500000000000011760512565023063 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/net/rtmp/codec/RTMPProtocolEncoderTest.java0000644000175000017500000000416011706617130030365 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.codec; import static org.junit.Assert.fail; import org.junit.Ignore; import org.junit.Test; /** * Created initially to address * http://jira.red5.org/browse/APPSERVER-212 * * @author Paul Gregoire (mondain@gmail.com) */ public class RTMPProtocolEncoderTest { @Ignore @Test public void testEncode() { fail("Not yet implemented"); } @Ignore @Test public void testEncodeMessage() { fail("Not yet implemented"); } @Ignore @Test public void testEncodeFlexSharedObject() { fail("Not yet implemented"); } @Ignore @Test public void testEncodeSharedObject() { fail("Not yet implemented"); } @Ignore @Test public void testEncodeNotify() { fail("Not yet implemented"); } @Ignore @Test public void testEncodeInvoke() { fail("Not yet implemented"); } @Ignore @Test public void testEncodeAudioData() { fail("Not yet implemented"); } @Ignore @Test public void testEncodeVideoData() { fail("Not yet implemented"); } @Ignore @Test public void testEncodeUnknown() { fail("Not yet implemented"); } @Ignore @Test public void testEncodeStreamMetadata() { fail("Not yet implemented"); } @Ignore @Test public void testEncodeFlexMessage() { fail("Not yet implemented"); } @Ignore @Test public void testEncodeFlexStreamSend() { fail("Not yet implemented"); } } red5-1.0~svn4374.orig/test/org/red5/server/net/RTMPTestCase.java0000644000175000017500000000500311752001621024066 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net; import junit.framework.Assert; import junit.framework.TestCase; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.rtmp.codec.RTMPProtocolDecoder; import org.red5.server.net.rtmp.codec.RTMPProtocolEncoder; import org.red5.server.net.rtmp.event.Invoke; import org.red5.server.net.rtmp.message.Constants; import org.red5.server.net.rtmp.message.Header; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RTMPTestCase extends TestCase implements Constants { protected static Logger log = LoggerFactory.getLogger(RTMPTestCase.class); protected RTMPProtocolDecoder decoder; protected Deserializer deserializer; protected RTMPProtocolEncoder encoder; protected Serializer serializer; /** {@inheritDoc} */ @Override protected void setUp() throws Exception { super.setUp(); serializer = new Serializer(); deserializer = new Deserializer(); encoder = new RTMPProtocolEncoder(); decoder = new RTMPProtocolDecoder(); encoder.setSerializer(serializer); decoder.setDeserializer(deserializer); } public void testHeaders() { RTMP rtmp = new RTMP(); Header header = new Header(); header.setChannelId((byte) 0x12); header.setDataType(TYPE_INVOKE); header.setStreamId(100); header.setTimer(2); header.setSize(320); IoBuffer buf = encoder.encodeHeader(rtmp, header, null); buf.flip(); log.debug(buf.getHexDump()); Assert.assertNotNull(buf); Header result = decoder.decodeHeader(buf, null); Assert.assertEquals(header, result); } public void testInvokePacket() { @SuppressWarnings("unused") Invoke invoke = new Invoke(); } } red5-1.0~svn4374.orig/test/org/red5/server/so/0000755000175000017500000000000011760512565020657 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/so/SOApplication.java0000644000175000017500000000651611756460764024247 0ustar drazzibdrazzibpackage org.red5.server.so; import org.red5.server.adapter.MultiThreadedApplicationAdapter; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.scope.IScope; import org.red5.server.api.so.ISharedObject; public class SOApplication extends MultiThreadedApplicationAdapter { private String persistentSO = "persistentSO"; /* (non-Javadoc) * @see org.red5.server.adapter.MultiThreadedApplicationAdapter#appStart(org.red5.server.api.scope.IScope) */ @SuppressWarnings("unused") @Override public boolean appStart(IScope app) { // create persistent SO createSharedObject(app, persistentSO, true); // get the SO ISharedObject sharedObject = getSharedObject(app, persistentSO, true); // return super.appStart(app); } /* (non-Javadoc) * @see org.red5.server.adapter.MultiThreadedApplicationAdapter#appStop(org.red5.server.api.scope.IScope) */ @Override public void appStop(IScope app) { // TODO Auto-generated method stub super.appStop(app); } /* (non-Javadoc) * @see org.red5.server.adapter.MultiThreadedApplicationAdapter#roomStart(org.red5.server.api.scope.IScope) */ @Override public boolean roomStart(IScope room) { getSharedObject(scope, "persistentSO", true); return super.roomStart(room); } /* (non-Javadoc) * @see org.red5.server.adapter.MultiThreadedApplicationAdapter#roomStop(org.red5.server.api.scope.IScope) */ @Override public void roomStop(IScope room) { // TODO Auto-generated method stub super.roomStop(room); } /* (non-Javadoc) * @see org.red5.server.adapter.MultiThreadedApplicationAdapter#appConnect(org.red5.server.api.IConnection, java.lang.Object[]) */ @Override public boolean appConnect(IConnection conn, Object[] params) { // TODO Auto-generated method stub return super.appConnect(conn, params); } /* (non-Javadoc) * @see org.red5.server.adapter.MultiThreadedApplicationAdapter#roomConnect(org.red5.server.api.IConnection, java.lang.Object[]) */ @Override public boolean roomConnect(IConnection conn, Object[] params) { // TODO Auto-generated method stub return super.roomConnect(conn, params); } /* (non-Javadoc) * @see org.red5.server.adapter.MultiThreadedApplicationAdapter#appDisconnect(org.red5.server.api.IConnection) */ @Override public void appDisconnect(IConnection conn) { // TODO Auto-generated method stub super.appDisconnect(conn); } /* (non-Javadoc) * @see org.red5.server.adapter.MultiThreadedApplicationAdapter#roomDisconnect(org.red5.server.api.IConnection) */ @Override public void roomDisconnect(IConnection conn) { // TODO Auto-generated method stub super.roomDisconnect(conn); } /* (non-Javadoc) * @see org.red5.server.adapter.MultiThreadedApplicationAdapter#roomJoin(org.red5.server.api.IClient, org.red5.server.api.scope.IScope) */ @Override public boolean roomJoin(IClient client, IScope room) { // TODO Auto-generated method stub return super.roomJoin(client, room); } /* (non-Javadoc) * @see org.red5.server.adapter.MultiThreadedApplicationAdapter#roomLeave(org.red5.server.api.IClient, org.red5.server.api.scope.IScope) */ @Override public void roomLeave(IClient client, IScope room) { // TODO Auto-generated method stub super.roomLeave(client, room); } } red5-1.0~svn4374.orig/test/org/red5/server/so/SharedObjectTest.xml0000644000175000017500000001062211755203771024577 0ustar drazzibdrazzib file:///${user.dir}/bin/conf/red5.properties file:///${user.dir}/conf/red5.properties org.red5.server.persistence.FilePersistence red5-1.0~svn4374.orig/test/org/red5/server/so/SharedObjectTest.java0000644000175000017500000001174611756460764024740 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.so; import static junit.framework.Assert.assertTrue; import java.util.Set; import junit.framework.TestCase; import org.junit.Test; import org.red5.server.api.scope.IScope; import org.red5.server.api.so.ISharedObject; import org.red5.server.scope.WebScope; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; /** * This is for testing SharedObject issues. * * @author Paul Gregoire (mondain@gmail.com) */ @ContextConfiguration(locations = { "SharedObjectTest.xml" }) public class SharedObjectTest extends AbstractJUnit4SpringContextTests { protected static Logger log = LoggerFactory.getLogger(SharedObjectTest.class); private static WebScope appScope; @SuppressWarnings("unused") private String host = "localhost"; @SuppressWarnings("unused") private String appPath = "junit"; @SuppressWarnings("unused") private String roomPath = "/junit/room1"; static { System.setProperty("red5.deployment.type", "junit"); System.setProperty("red5.root", "bin"); System.setProperty("red5.config_root", "bin/conf"); System.setProperty("logback.ContextSelector", "org.red5.logging.LoggingContextSelector"); } { log.debug("Property - user.dir: {}", System.getProperty("user.dir")); log.debug("Property - red5.root: {}", System.getProperty("red5.root")); log.debug("Property - red5.config_root: {}", System.getProperty("red5.config_root")); } @Test public void testSharedObject() { log.debug("testSharedObject"); if (appScope == null) { appScope = (WebScope) applicationContext.getBean("web.scope"); log.debug("Application / web scope: {}", appScope); assertTrue(appScope.getDepth() == 1); } SOApplication app = (SOApplication) applicationContext.getBean("web.handler"); String soName = "foo"; //Room 1 // /default/junit/room1 TestCase.assertTrue(appScope.createChildScope("room1")); IScope room1 = appScope.getScope("room1"); log.debug("Room 1: {}", room1); assertTrue(room1.getDepth() == 2); // get the SO ISharedObject sharedObject = app.getSharedObject(room1, soName, true); log.debug("SO: {}", sharedObject); assertTrue(sharedObject != null); log.debug("testSharedObject-end"); } @Test public void testGetSONames() throws Exception { log.debug("testGetSONames"); if (appScope == null) { appScope = (WebScope) applicationContext.getBean("web.scope"); log.debug("Application / web scope: {}", appScope); assertTrue(appScope.getDepth() == 1); } IScope room1 = ScopeUtils.resolveScope(appScope, "/junit/room1"); log.debug("Room 1 scope: {}", room1); Set names = room1.getScopeNames(); log.debug("Names: {}", names); assertTrue(names.size() > 0); log.debug("testGetSONames-end"); } @Test public void testRemoveSO() throws Exception { log.debug("testRemoveSO"); if (appScope == null) { appScope = (WebScope) applicationContext.getBean("web.scope"); log.debug("Application / web scope: {}", appScope); assertTrue(appScope.getDepth() == 1); } String soName = "foo"; IScope room1 = ScopeUtils.resolveScope(appScope, "/junit/room1"); room1.removeChildren(); log.debug("Child exists: {}", room1.hasChildScope(soName)); log.debug("testRemoveSO-end"); } /** * Test for Issue 209 * http://code.google.com/p/red5/issues/detail?id=209 */ @Test public void testPersistentCreation() throws Exception { log.debug("testPersistentCreation"); if (appScope == null) { appScope = (WebScope) applicationContext.getBean("web.scope"); log.debug("Application / web scope: {}", appScope); assertTrue(appScope.getDepth() == 1); } SOApplication app = (SOApplication) applicationContext.getBean("web.handler"); String soName = "foo"; // get our room IScope room1 = ScopeUtils.resolveScope(appScope, "/junit/room1"); // create the SO app.createSharedObject(room1, soName, true); // get the SO ISharedObject sharedObject = app.getSharedObject(room1, soName, true); assertTrue(sharedObject != null); log.debug("testPersistentCreation-end"); } } red5-1.0~svn4374.orig/test/org/red5/server/FilenameGenerator.java0000644000175000017500000000667711747114732024507 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.io.File; import java.util.Random; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IStreamFilenameGenerator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Provides custom playback and recording directories. * * @author Paul Gregoire (mondain@gmail.com) */ public class FilenameGenerator implements IStreamFilenameGenerator { private static Logger logger = LoggerFactory.getLogger(FilenameGenerator.class); // Path that will store recorded videos public static String recordPath = "/"; // Path that contains VOD streams public static String playbackPath = "/"; // Create a random generator public static Random rnd = new Random(); public String generateFilename(IScope scope, String name, GenerationType type) { return generateFilename(scope, name, null, type); } public String generateFilename(IScope scope, String name, String extension, GenerationType type) { logger.debug("Get stream directory: scope={}, name={}, type={}", new Object[]{scope, name, type.toString()}); //determine current dir File tmp = new File(""); System.out.println("Location: " + tmp.getAbsolutePath()); StringBuilder filename = new StringBuilder(tmp.getAbsolutePath()); if (type.equals(GenerationType.PLAYBACK)) { logger.debug("Playback path used"); filename.append(playbackPath); } else { logger.debug("Record path used"); filename.append(recordPath); } if (filename.charAt(filename.length() - 1) != '/') { filename.append('/'); } filename.append(name); if (extension != null){ // Add extension filename.append(extension); } logger.debug("Generated filename: {}", filename.toString()); System.out.println("File name: " + filename.toString()); return filename.toString(); } public boolean resolvesToAbsolutePath() { return true; } public void setPlaybackPath(String path) { logger.debug("Set playback path: {}", path); playbackPath = path; } public void setRecordPath(String path) { logger.debug("Set record path: {}", path); recordPath = path; } public static String generateCustomName() { StringBuilder sb = new StringBuilder(); sb.append(System.currentTimeMillis() / 1000); sb.append('_'); int i = rnd.nextInt(99999); if (i < 10) { sb.append("0000"); } else if (i < 100) { sb.append("000"); } else if (i < 1000) { sb.append("00"); } else if (i < 10000) { sb.append("0"); } sb.append(i); return sb.toString(); } } red5-1.0~svn4374.orig/test/org/red5/server/service/0000755000175000017500000000000011760512565021676 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/service/IEchoService.java0000644000175000017500000000603111706617130025043 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import java.util.Date; import java.util.List; import org.w3c.dom.Document; /** * The Echo service is used to test all of the different datatypes * and to make sure that they are being returned properly. * * @author The Red5 Project (red5@osflash.org) * @author Chris Allen (mrchrisallen@gmail.com) */ public interface IEchoService { /** * Used to verify that Spring has loaded the bean. * */ public abstract void startUp(); /** * Verifies that a boolean that is passed in returns correctly. * * @param bool object to echo * @return input value */ public abstract boolean echoBoolean(boolean bool); /** * Verifies that a Number that is passed in returns correctly. * * Flash Number = double * * @param num object to echo * @return input value */ public abstract double echoNumber(double num); /** * Verifies that a String that is passed in returns correctly. * * @param string object to echo * @return input value */ public abstract String echoString(String string); /** * Verifies that a Date that is passed in returns correctly. * * @param date object to echo * @return input value */ public abstract Date echoDate(Date date); /** * Verifies that a Flash Object that is passed in returns correctly. * Flash Object = java.utils.Map. Let Apache bean utils do the magic * conversions. * * @param obj object to echo * @return input value */ public abstract Object echoObject(Object obj); /** * Verifies that a Flash simple Array that is passed in returns correctly. * Flash simple Array = Object[] * * @param array object to echo * @return input value */ public abstract Object[] echoArray(Object[] array); /** * Verifies that a Flash multi-dimensional Array that is passed in returns itself. * Flash multi-dimensional Array = java.utils.List * @param type of list * * @param list object to echo * @return input value */ public abstract List echoList(List list); /** * Verifies that Flash XML that is passed in returns itself. * Flash XML = org.w3c.dom.Document * * @param xml object to echo * @return input value */ public abstract Document echoXML(Document xml); } red5-1.0~svn4374.orig/test/org/red5/server/service/ConversionUtilsTest.java0000644000175000017500000001120511745776105026553 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.fail; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.apache.commons.beanutils.ConversionException; import org.junit.Test; import org.red5.server.util.ConversionUtils; /** * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class ConversionUtilsTest { class TestJavaBean { } //private static final Logger log = LoggerFactory.getLogger(ConversionUtilsTest.class); @Test public void testBasic() { Object result = ConversionUtils.convert(new Integer(42), String.class); if (!(result instanceof String)) { fail("Should be a string"); } String str = (String) result; assertEquals("42", str); } @Test public void testConvertListToStringArray() { ArrayList source = new ArrayList(); source.add("Testing 1"); source.add("Testing 2"); source.add("Testing 3"); Class target = (new String[0]).getClass(); Object result = ConversionUtils.convert(source, target); if (!(result.getClass().isArray() && result.getClass() .getComponentType().equals(String.class))) { fail("Should be String[]"); } String[] results = (String[]) result; assertEquals(results.length, source.size()); assertEquals(results[2], source.get(2)); } @Test public void testConvertListToPrimitiveArray() { List source = new ArrayList(); source.add(1); source.add(2); source.add(3); Class target = (new int[0]).getClass(); Object result = ConversionUtils.convert(source, target); if (!(result.getClass().isArray() && result.getClass() .getComponentType().equals(int.class))) { fail("Should be int[]"); } int[] results = (int[]) result; assertEquals(results.length, source.size()); assertEquals(results[2], source.get(2).intValue()); } @Test public void testConvertObjectArrayToStringArray() { Object[] source = new Object[3]; source[0] = new Integer(21); source[1] = Boolean.FALSE; source[2] = "Woot"; Class target = (new String[0]).getClass(); Object result = ConversionUtils.convert(source, target); if (!(result.getClass().isArray() && result.getClass() .getComponentType().equals(String.class))) { fail("Should be String[]"); } String[] results = (String[]) result; assertEquals(results.length, source.length); assertEquals(results[2], source[2]); } @Test public void testConvertToSet() { Object[] source = new Object[3]; source[0] = new Integer(21); source[1] = Boolean.FALSE; source[2] = "Woot"; Object result = ConversionUtils.convert(source, Set.class); if (!(result instanceof Set)) { fail("Should be a set"); } Set results = (Set) result; assertEquals(results.size(), source.length); } @Test public void testConvertArrayListToSet() { List source = new ArrayList(3); source.add("a"); source.add("b"); source.add("c"); Object result = ConversionUtils.convert(source, Set.class); if (!(result instanceof Set)) { fail("Should be a set"); } Set results = (Set) result; assertEquals(source.size(),results.size()); } @Test public void testNoOppConvert() { TestJavaBean source = new TestJavaBean(); Object result = ConversionUtils.convert(source, TestJavaBean.class); assertEquals(result, source); } @Test public void testNullConvert() { Object result = ConversionUtils.convert(null, TestJavaBean.class); assertNull(result); } @Test(expected=ConversionException.class) public void testNullConvertNoClass() { // should throw exception ConversionUtils.convert(new TestJavaBean(), null); } } red5-1.0~svn4374.orig/test/org/red5/server/service/ExternalizableClass.java0000644000175000017500000000555311706617130026502 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import org.red5.io.amf3.IDataInput; import org.red5.io.amf3.IDataOutput; import org.red5.io.amf3.IExternalizable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ExternalizableClass implements IExternalizable { private Logger log = LoggerFactory.getLogger(this.getClass()); private boolean[] a = new boolean[2]; private byte[] b = new byte[5]; private double c; private float d; private int[] e = new int[3]; private String[] f = new String[2]; private Object ob; private short[] g = new short[3]; private long[] h = new long[2]; private String i; private String j; public void readExternal(IDataInput input) { log.info("readExternal: {}", this); a[0] = input.readBoolean(); a[1] = input.readBoolean(); b[0] = input.readByte(); b[1] = input.readByte(); b[2] = input.readByte(); b[3] = input.readByte(); b[4] = input.readByte(); // TODO: input.readBytes c = input.readDouble(); d = input.readFloat(); e[0] = input.readInt(); e[1] = input.readInt(); e[2] = input.readInt(); f[0] = input.readMultiByte(7, "iso-8859-1"); f[1] = input.readMultiByte(14, "utf-8"); ob = input.readObject(); g[0] = input.readShort(); g[1] = input.readShort(); g[2] = input.readShort(); h[0] = input.readUnsignedInt(); h[1] = input.readUnsignedInt(); i = input.readUTF(); j = input.readUTFBytes(12); } public void writeExternal(IDataOutput output) { log.info("writeExternal: {}", this); output.writeBoolean(a[0]); output.writeBoolean(a[1]); output.writeByte(b[0]); output.writeByte(b[1]); output.writeByte(b[2]); output.writeByte(b[3]); output.writeByte(b[4]); output.writeDouble(c); output.writeFloat(d); output.writeInt(e[0]); output.writeInt(e[1]); output.writeInt(e[2]); output.writeMultiByte(f[0], "iso-8859-1"); output.writeMultiByte(f[1], "utf-8"); output.writeObject(ob); output.writeShort(g[0]); output.writeShort(g[1]); output.writeShort(g[2]); output.writeUnsignedInt(h[0]); output.writeUnsignedInt(h[1]); output.writeUTF(i); output.writeUTFBytes(j); } } red5-1.0~svn4374.orig/test/org/red5/server/service/ServiceInvokerTest.java0000644000175000017500000003254611747114732026350 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import junit.framework.Assert; import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner; import net.sourceforge.groboutils.junit.v1.TestRunnable; import org.junit.Test; import org.red5.server.Context; import org.red5.server.DummyClient; import org.red5.server.api.IClient; import org.red5.server.api.IClientRegistry; import org.red5.server.api.IConnection; import org.red5.server.api.IContext; import org.red5.server.api.Red5; import org.red5.server.api.TestConnection; import org.red5.server.api.scope.IScope; import org.red5.server.api.service.IPendingServiceCallback; import org.red5.server.api.service.IServiceCall; import org.red5.server.api.service.IServiceCapableConnection; import org.red5.server.scope.Scope; import org.red5.server.scope.WebScope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; /** * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Paul Gregoire (mondain@gmail.com) */ @ContextConfiguration(locations = { "testcontext.xml" }) public class ServiceInvokerTest extends AbstractJUnit4SpringContextTests { // TODO: Add more tests! // we dont have to test all the echo methods, more test the call object works as expected // the correct types of status are returned (method not found) etc. // Also, we need to add tests which show the way the parameter conversion works. // So have a few methods with the same name, and try with diff params, making sure right one gets called. protected static Logger log = LoggerFactory.getLogger(ServiceInvokerTest.class); private final static List workerList = new ArrayList(11); private static AtomicInteger finishedCount = new AtomicInteger(0); private final static Random rnd = new Random(); static { String userDir = System.getProperty("user.dir"); System.out.println("User dir: " + userDir); System.setProperty("red5.deployment.type", "junit"); System.setProperty("red5.root", "file:" + userDir + "/bin"); System.setProperty("red5.config_root", System.getProperty("red5.root") + "/conf"); } @Test public void testAppContextLoaded() { Assert.assertNotNull(applicationContext); //Assert.assertNotNull(applicationContext.getBean("serviceInvoker")); Assert.assertNotNull(applicationContext.getBean("echoService")); } @Test public void testExceptionStatus() { ServiceInvoker invoker = null; if (applicationContext.containsBean(ServiceInvoker.SERVICE_NAME)) { invoker = (ServiceInvoker) applicationContext.getBean(ServiceInvoker.SERVICE_NAME); } else { invoker = (ServiceInvoker) applicationContext.getBean("global.serviceInvoker"); } Object service = applicationContext.getBean("echoService"); Object[] params = new Object[] { "Woot this is cool" }; Call call = new Call("echoService", "doesntExist", params); invoker.invoke(call, service); Assert.assertEquals(false, call.isSuccess()); Assert.assertEquals(Call.STATUS_METHOD_NOT_FOUND, call.getStatus()); params = new Object[] { "too", "many", "params" }; call = new Call("echoService", "echoNumber", params); invoker.invoke(call, service); Assert.assertEquals(false, call.isSuccess()); Assert.assertEquals(Call.STATUS_METHOD_NOT_FOUND, call.getStatus()); } @Test public void testSimpleEchoCall() { ServiceInvoker invoker = null; if (applicationContext.containsBean(ServiceInvoker.SERVICE_NAME)) { invoker = (ServiceInvoker) applicationContext.getBean(ServiceInvoker.SERVICE_NAME); } else { invoker = (ServiceInvoker) applicationContext.getBean("global.serviceInvoker"); } Object[] params = new Object[] { "Woot this is cool" }; Object service = applicationContext.getBean("echoService"); PendingCall call = new PendingCall("echoService", "echoString", params); invoker.invoke(call, service); Assert.assertEquals(true, call.isSuccess()); Assert.assertEquals(params[0], call.getResult()); } /** * Test for memory leak bug #631 * http://trac.red5.org/ticket/631 */ @Test public void testBug631() { final String message = "This is a test"; //create our sender conn and set local IClientRegistry dummyReg = (IClientRegistry) applicationContext.getBean("global.clientRegistry"); IScope scp = (WebScope) applicationContext.getBean("web.scope"); //conn.getScope(); IContext ctx = (Context) applicationContext.getBean("web.context"); //scope.getContext(); IConnection recipient = new SvcCapableTestConnection("localhost", "/junit", "1");//host, path, session id IClient rClient = dummyReg.newClient(new Object[] { "recipient" }); ((TestConnection) recipient).setClient(rClient); ((TestConnection) recipient).setScope((Scope) scp); ((DummyClient) rClient).registerConnection(recipient); IConnection sender = new SvcCapableTestConnection("localhost", "/junit", "2");//host, path, session id IClient sClient = dummyReg.newClient(new Object[] { "sender" }); ((TestConnection) sender).setClient(sClient); ((TestConnection) sender).setScope((Scope) scp); ((DummyClient) sClient).registerConnection(sender); Red5.setConnectionLocal(sender); //start standard process IConnection conn = Red5.getConnectionLocal(); log.debug("Check s/c -\n s1: {} s2: {}\n c1: {} c2: {}", new Object[] { scp, conn.getScope(), ctx, conn.getScope().getContext() }); IClient client = conn.getClient(); IScope scope = (WebScope) conn.getScope(); IContext context = (Context) scope.getContext(); IClientRegistry reg = context.getClientRegistry(); log.debug("Client registry: {}", reg.getClass().getName()); IServiceCapableConnection serviceCapCon = null; if (reg.hasClient("recipient")) { IClient recip = reg.lookupClient("recipient"); Set rcons = recip.getConnections(scope); log.debug("Recipient has {} connections", rcons.size()); Object[] sendobj = new Object[] { client.getId(), message }; for (IConnection rcon : rcons) { if (rcon instanceof IServiceCapableConnection) { serviceCapCon = (IServiceCapableConnection) rcon; serviceCapCon.invoke("privMessage", sendobj); break; } else { log.info("Connection is not service capable"); } } } Assert.assertTrue(((SvcCapableTestConnection) serviceCapCon).getPrivateMessageCount() == 1); } /** * Test for memory leak bug #631 with multiple threads * http://trac.red5.org/ticket/631 */ @Test public void testMultiThreadBug631() throws Throwable { //leak doesnt appear unless this is around 1000 and running outside eclipse int threadCount = 2000; //init and run TestRunnable[] trs = new TestRunnable[threadCount]; for (int t = 0; t < threadCount; t++) { ConnectionWorker worker = new ConnectionWorker(createConnection(t), t); trs[t] = worker; workerList.add(worker.getName()); } MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs); long start = System.nanoTime(); mttr.runTestRunnables(); log.info("Runtime: {} ns", (System.nanoTime() - start)); for (TestRunnable r : trs) { ConnectionWorker wkr = (ConnectionWorker) r; String name = (wkr.getName()); Assert.assertNotNull(name); //close them all down wkr.close(); // Assert.assertTrue(wkr.getServiceCapableConnection().getPrivateMessageCount() > threadCount); } //make sure all threads finished Assert.assertEquals(threadCount, finishedCount.get()); } private IConnection createConnection(int id) { //create our sender conn and set local IClientRegistry dummyReg = (IClientRegistry) applicationContext.getBean("global.clientRegistry"); IScope scp = (WebScope) applicationContext.getBean("web.scope"); //IContext ctx = (Context) applicationContext.getBean("web.context"); IConnection conn = new SvcCapableTestConnection("localhost", "/junit", id + "");//host, path, session id IClient rClient = dummyReg.newClient(new Object[] { "client-" + id }); ((TestConnection) conn).setClient(rClient); ((TestConnection) conn).setScope((Scope) scp); ((DummyClient) rClient).registerConnection(conn); return conn; } final static class ConnectionWorker extends TestRunnable { IConnection conn; String name; public ConnectionWorker(IConnection conn, int index) { this.conn = conn; this.name = "client-" + index; } public void runTest() throws Throwable { Red5.setConnectionLocal(conn); //start standard process IConnection conn = Red5.getConnectionLocal(); IClient client = conn.getClient(); IScope scope = (WebScope) conn.getScope(); IContext context = (Context) scope.getContext(); IClientRegistry reg = context.getClientRegistry(); IServiceCapableConnection serviceCapCon = null; //go through the client list and send at least one message to everyone for (String worker : workerList) { //dont send to ourself if (name.equals(worker)) { log.debug("Dont send to self"); continue; } if (reg.hasClient(worker)) { IClient recip = reg.lookupClient(worker); Set rcons = recip.getConnections(scope); //log.debug("Recipient has {} connections", rcons.size()); Object[] sendobj = new Object[] { client.getId(), "This is a message from " + name }; for (IConnection rcon : rcons) { if (rcon instanceof IServiceCapableConnection) { serviceCapCon = (IServiceCapableConnection) rcon; serviceCapCon.invoke("privMessage", sendobj); break; } else { log.info("Connection is not service capable"); } } } else { log.warn("Client not registered {}", worker); } } //number of connections int connectionCount = workerList.size(); //now send N messages to random recipients for (int i = 0; i < 4000; i++) { String worker = workerList.get(rnd.nextInt(connectionCount)); //dont send to ourself if (name.equals(worker)) { log.debug("Dont send to self"); continue; } if (reg.hasClient(worker)) { IClient recip = reg.lookupClient(worker); Set rcons = recip.getConnections(scope); //log.debug("Recipient has {} connections", rcons.size()); Object[] sendobj = new Object[] { client.getId(), "This is a message from " + name }; for (IConnection rcon : rcons) { if (rcon instanceof IServiceCapableConnection) { serviceCapCon = (IServiceCapableConnection) rcon; serviceCapCon.invoke("privMessage", sendobj); break; } else { log.info("Connection is not service capable"); } } } else { log.warn("Client not registered {}", worker); } } finishedCount.incrementAndGet(); } public void close() { DummyClient client = (DummyClient) conn.getClient(); client.unregisterConnection(conn); conn.close(); } public String getName() { return name; } public SvcCapableTestConnection getServiceCapableConnection() { return (SvcCapableTestConnection) conn; } } final static class SvcCapableTestConnection extends TestConnection implements IServiceCapableConnection { private int privateMessageCount = 0; public SvcCapableTestConnection(String host, String path, String sessionId) { super(host, path, sessionId); } public int getPrivateMessageCount() { return privateMessageCount; } public void invoke(String method, Object[] params) { //log.debug("Invoke on connection: {}", this.client.getId()); if ("privMessage".equals(method)) { //log.info("Got a private message from: {} message: {}", params); privateMessageCount++; } else { log.warn("Method: {} not implemented", method); } } @Override public void invoke(IServiceCall call) { } @Override public void invoke(IServiceCall call, int channel) { } @Override public void invoke(String method) { } @Override public void invoke(String method, IPendingServiceCallback callback) { } @Override public void invoke(String method, Object[] params, IPendingServiceCallback callback) { } @Override public void notify(IServiceCall call) { } @Override public void notify(IServiceCall call, int channel) { } @Override public void notify(String method) { } @Override public void notify(String method, Object[] params) { } } } red5-1.0~svn4374.orig/test/org/red5/server/service/RemoteClass.java0000644000175000017500000000153411706617130024757 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; public class RemoteClass { public String attribute1; public int attribute2; } red5-1.0~svn4374.orig/test/org/red5/server/service/EchoServiceTest.java0000644000175000017500000001213711706617130025576 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import java.io.IOException; import java.io.StringReader; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import junit.framework.TestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * @author The Red5 Project (red5@osflash.org) * @author Chris Allen (mrchrisallen@gmail.com) */ public class EchoServiceTest extends TestCase { final private Logger log = LoggerFactory.getLogger(this.getClass()); private EchoService echoService; /** {@inheritDoc} */ @Override protected void setUp() throws Exception { super.setUp(); echoService = new EchoService(); } /** {@inheritDoc} */ @Override protected void tearDown() throws Exception { super.tearDown(); echoService = null; } public void testEchoArray() { Object[] startArray = { "first", "second", "third" }; Object[] resultArray = echoService.echoArray(startArray); assertEquals(startArray[0], resultArray[0]); assertEquals(startArray[1], resultArray[1]); assertEquals(startArray[2], resultArray[2]); } public void testEchoBoolean() { boolean b = true; assertTrue(echoService.echoBoolean(b)); } public void testEchoDate() throws ParseException { SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy"); Date startDate = dateFormat.parse("01-26-1974"); Date returnDate = echoService.echoDate(startDate); assertEquals(startDate.getTime(), returnDate.getTime()); } @SuppressWarnings("unchecked") public void testEchoList() { List startList = new ArrayList(); startList.add(0, "first"); startList.add(1, "second"); List resultList = echoService.echoList(startList); assertEquals(startList.get(0), resultList.get(0)); assertEquals(startList.get(1), resultList.get(1)); } public void testEchoNumber() { double num = 100; assertEquals(200, echoService.echoNumber(num), echoService.echoNumber(num)); } @SuppressWarnings("unchecked") public void testEchoObject() { String str = "entry one"; Date date = new Date(); Map> startMap = new HashMap>(); startMap.put("string", str); startMap.put("date", date); Map> resultMap = (Map>) echoService.echoObject(startMap); assertEquals(startMap.get("string"), resultMap.get("string")); assertEquals(startMap.get("date"), resultMap.get("date")); } public void testEchoString() { String str = "This is a test."; assertEquals("This is a test.", echoService.echoString(str)); } public void testEchoXML() throws SAXException, IOException, ParserConfigurationException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); String xmlStr = "this is a test"; StringReader reader = new StringReader(xmlStr); InputSource source = new InputSource(reader); Document xml = builder.parse(source); Document resultXML = echoService.echoXML(xml); assertEquals(xml.getFirstChild().getNodeValue(), resultXML.getFirstChild().getNodeValue()); } public void testEchoMultibyteStrings() { java.nio.ByteBuffer buf = ByteBuffer.allocate(7); buf.put((byte) 0xE4); buf.put((byte) 0xF6); buf.put((byte) 0xFC); buf.put((byte) 0xC4); buf.put((byte) 0xD6); buf.put((byte) 0xDC); buf.put((byte) 0xDF); buf.flip(); final Charset cs = Charset.forName("iso-8859-1"); assertNotNull(cs); final String inputStr = cs.decode(buf).toString(); log.debug("passing input string: {}", inputStr); final String outputStr = echoService.echoString(inputStr); assertEquals("unequal strings", inputStr, outputStr); log.debug("got output string: {}", outputStr); java.nio.ByteBuffer outputBuf = cs.encode(outputStr); for (int i = 0; i < 7; i++) { assertEquals("unexpected byte", buf.get(i), outputBuf.get(i)); } } } red5-1.0~svn4374.orig/test/org/red5/server/service/EchoService.java0000644000175000017500000000742411706617130024741 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; /** * The Echo service is used to test all of the different datatypes * and to make sure that they are being returned properly. * * @author The Red5 Project (red5@osflash.org) * @author Chris Allen (mrchrisallen@gmail.com) */ public class EchoService { private Logger log = LoggerFactory.getLogger(EchoService.class); public void startUp() { log.info("The Echo Service has started..."); } public boolean echoBoolean(boolean bool) { log.info("echoBoolean: {}", bool); return bool; } public double echoNumber(double number) { log.info("echoNumber: {}", number); return number; } public String echoString(String string) { log.info("echoString: {}", string); return string; } public Date echoDate(Date date) { log.info("echoDate: {}", date); return date; } public Object echoObject(Object obj) { log.info("echoObject: {}", obj); return obj; } public Object[] echoArray(Object[] array) { log.info("echoArray: {}", array); return array; } @SuppressWarnings({ "rawtypes" }) public List echoList(List list) { log.info("echoList: {}", list); return list; } public Document echoXML(Document xml) { log.info("echoXML: {}", xml); return xml; } public Object[] echoMultiParam(Map team, List words, String str) { Object[] result = new Object[3]; result[0] = team; result[1] = words; result[2] = str; log.info("echoMultiParam: {}, {}, {}", new Object[] { team, words, str }); return result; } public Object echoAny(Object any) { log.info("echoAny: " + any); return any; } /** * Test serialization of arbitrary objects. * * @param any object to echo * @return list containing distinct objects */ public List returnDistinctObjects(Object any) { List result = new ArrayList(); for (int i = 0; i < 4; i++) { result.add(new SampleObject()); } return result; } /** * Test references. * * @param any object to echo * @return list containing same objects */ public List returnSameObjects(Object any) { List result = new ArrayList(); SampleObject object = new SampleObject(); for (int i = 0; i < 4; i++) { result.add(object); } return result; } /** * Test returning of internal objects. * * @param any object to echo * @return the current connection */ public IConnection returnConnection(Object any) { return Red5.getConnectionLocal(); } /** * Sample object that contains attributes with all access possibilities. * This will test the serializer of arbitrary objects. */ public class SampleObject { public String value1 = "one"; public int value2 = 2; protected int value4 = 4; } } red5-1.0~svn4374.orig/test/org/red5/server/service/testcontext.xml0000644000175000017500000000705211746040404025000 0ustar drazzibdrazzib file:///${user.dir}/bin/conf/red5.properties file:///${user.dir}/conf/red5.properties red5-1.0~svn4374.orig/test/org/red5/server/DummyClient.java0000644000175000017500000000246411706617130023333 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import org.red5.server.api.IConnection; /** * Client is an abstraction representing user connected to Red5 application. * Clients are tied to connections and registred in ClientRegistry */ public class DummyClient extends Client { private IConnection conn; public DummyClient(String id, ClientRegistry registry) { super(id, registry); } public void registerConnection(IConnection conn) { this.conn = conn; register(this.conn); } public void unregisterConnection(IConnection conn) { unregister(conn); disconnect(); } }red5-1.0~svn4374.orig/test/org/red5/server/stream/0000755000175000017500000000000011760512565021531 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/stream/NoSyncServerStream.java0000644000175000017500000005205511747114732026156 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import org.red5.server.api.scheduling.IScheduledJob; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IPlayItem; import org.red5.server.api.stream.IPlaylistController; import org.red5.server.api.stream.IServerStream; import org.red5.server.api.stream.IStreamFilenameGenerator; import org.red5.server.api.stream.IStreamFilenameGenerator.GenerationType; import org.red5.server.api.stream.IStreamListener; import org.red5.server.api.stream.IStreamPacket; import org.red5.server.api.stream.ResourceExistException; import org.red5.server.api.stream.ResourceNotFoundException; import org.red5.server.messaging.IFilter; import org.red5.server.messaging.IMessage; import org.red5.server.messaging.IMessageComponent; import org.red5.server.messaging.IMessageInput; import org.red5.server.messaging.IMessageOutput; import org.red5.server.messaging.IPassive; import org.red5.server.messaging.IPipe; import org.red5.server.messaging.IPipeConnectionListener; import org.red5.server.messaging.IProvider; import org.red5.server.messaging.IPushableConsumer; import org.red5.server.messaging.InMemoryPushPushPipe; import org.red5.server.messaging.OOBControlMessage; import org.red5.server.messaging.PipeConnectionEvent; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.stream.consumer.FileConsumer; import org.red5.server.stream.message.RTMPMessage; import org.red5.server.stream.message.ResetMessage; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; /** * An implementation for server side stream. * * @author The Red5 Project (red5@osflash.org) */ public class NoSyncServerStream extends AbstractStream implements IServerStream, IFilter, IPushableConsumer, IPipeConnectionListener { /** * Enumeration for states */ private enum State { CLOSED, PLAYING, STOPPED, UNINIT, PAUSED } /** * Logger */ private static final Logger log = LoggerFactory.getLogger(NoSyncServerStream.class); /** * Actual playlist controller */ private IPlaylistController controller; /** * Current item */ private IPlayItem currentItem; /** * Current item index */ private int currentItemIndex; /** * Default playlist controller */ private IPlaylistController defaultController; /** * Random flag state */ private boolean isRandom; /** * Repeat flag state */ private boolean isRepeat; /** * Rewind flag state */ private boolean isRewind; /** * List of items in this playlist */ private List items; /** * Live broadcasting scheduled job name */ private String liveJobName; /** * Message input */ private IMessageInput msgIn; /** * Message output */ private IMessageOutput msgOut; /** * Next msg's audio timestamp */ private long nextAudioTS; /** * Next msg's data timestamp */ private long nextDataTS; /** * Next RTMP message */ private RTMPMessage nextRTMPMessage; /** * Next msg's timestamp */ private long nextTS; /** * Next msg's video timestamp */ private long nextVideoTS; /** * Stream published name */ private String publishedName; /** * The filename we are recording to. */ private String recordingFilename; /** * Pipe for recording */ private IPipe recordPipe; /** * Scheduling service */ private ISchedulingService scheduler; /** * Server start timestamp */ private long serverStartTS; /** * Current state */ private State state; /** * VOD scheduled job name */ private String vodJobName; /** * VOD start timestamp */ private long vodStartTS; /** Listeners to get notified about received packets. */ private Set listeners = new CopyOnWriteArraySet(); /** Constructs a new ServerStream. */ public NoSyncServerStream() { defaultController = new SimplePlaylistController(); items = new CopyOnWriteArrayList(); state = State.UNINIT; } /** {@inheritDoc} */ public void addItem(IPlayItem item) { items.add(item); } /** {@inheritDoc} */ public void addItem(IPlayItem item, int index) { items.add(index, item); } /** {@inheritDoc} */ public void close() { if (state == State.PLAYING || state == State.PAUSED) { stop(); } if (msgOut != null) { msgOut.unsubscribe(this); } recordPipe.unsubscribe((IProvider) this); state = State.CLOSED; } /** {@inheritDoc} */ public IPlayItem getCurrentItem() { return currentItem; } /** {@inheritDoc} */ public int getCurrentItemIndex() { return currentItemIndex; } /** {@inheritDoc} */ public IPlayItem getItem(int index) { try { return items.get(index); } catch (IndexOutOfBoundsException e) { return null; } } /** {@inheritDoc} */ public int getItemSize() { return items.size(); } /** * Getter for next RTMP message. * * @return Next RTMP message */ private RTMPMessage getNextRTMPMessage() { IMessage message; do { // Pull message from message input object... try { message = msgIn.pullMessage(); } catch (IOException err) { log.error("Error while pulling message.", err); message = null; } // If message is null then return null if (message == null) { return null; } } while (!(message instanceof RTMPMessage)); // Cast and return return (RTMPMessage) message; } /** {@inheritDoc} */ public IProvider getProvider() { return this; } /** {@inheritDoc} */ public String getPublishedName() { return publishedName; } /** {@inheritDoc} */ public String getSaveFilename() { return recordingFilename; } /** {@inheritDoc} */ public boolean hasMoreItems() { int nextItem = currentItemIndex + 1; if (nextItem >= items.size() && !isRepeat) { return false; } else { return true; } } /** {@inheritDoc} */ public boolean isRandom() { return isRandom; } /** {@inheritDoc} */ public boolean isRepeat() { return isRepeat; } /** {@inheritDoc} */ public boolean isRewind() { return isRewind; } /** * Move to the next item updating the currentItemIndex. Should be called * in context. */ private void moveToNext() { if (currentItemIndex >= items.size()) { currentItemIndex = items.size() - 1; } if (controller != null) { currentItemIndex = controller.nextItem(this, currentItemIndex); } else { currentItemIndex = defaultController.nextItem(this, currentItemIndex); } } /** * Move to the previous item updating the currentItemIndex. Should be * called in context. */ private void moveToPrevious() { if (currentItemIndex >= items.size()) { currentItemIndex = items.size() - 1; } if (controller != null) { currentItemIndex = controller.previousItem(this, currentItemIndex); } else { currentItemIndex = defaultController.previousItem(this, currentItemIndex); } } /** {@inheritDoc} */ public void nextItem() { stop(); moveToNext(); if (currentItemIndex == -1) { return; } IPlayItem item = items.get(currentItemIndex); play(item); } /** * Play next item on item end */ private void onItemEnd() { nextItem(); } /** {@inheritDoc} */ public void onOOBControlMessage(IMessageComponent source, IPipe pipe, OOBControlMessage oobCtrlMsg) { } /** * Pipe connection event handler. There are two types of pipe connection * events so far, provider push connection event and provider * disconnection event. * * Pipe events handling is the most common way of working with pipes. * * @param event Pipe connection event context */ public void onPipeConnectionEvent(PipeConnectionEvent event) { switch (event.getType()) { case PipeConnectionEvent.PROVIDER_CONNECT_PUSH: if (event.getProvider() == this && (event.getParamMap() == null || !event.getParamMap().containsKey("record"))) { this.msgOut = (IMessageOutput) event.getSource(); } break; case PipeConnectionEvent.PROVIDER_DISCONNECT: if (this.msgOut == event.getSource()) { this.msgOut = null; } break; default: break; } } /** * Play a specific IPlayItem. The strategy for now is VOD first, Live * second. Should be called in a context. * * @param item * Item to play */ private void play(IPlayItem item) { // Return if already playing if (state != State.STOPPED) { return; } // Assume this is not live stream boolean isLive = false; // Get provider service from Spring bean factory IProviderService providerService = (IProviderService) getScope().getContext().getBean(IProviderService.BEAN_NAME); msgIn = providerService.getVODProviderInput(getScope(), item.getName()); if (msgIn == null) { msgIn = providerService.getLiveProviderInput(getScope(), item.getName(), true); isLive = true; } if (msgIn == null) { log.warn("ABNORMAL Can't get both VOD and Live input from providerService"); return; } state = State.PLAYING; currentItem = item; sendResetMessage(); msgIn.subscribe(this, null); if (isLive) { if (item.getLength() >= 0) { liveJobName = scheduler.addScheduledOnceJob(item.getLength(), new IScheduledJob() { /** {@inheritDoc} */ public void execute(ISchedulingService service) { if (liveJobName == null) { return; } liveJobName = null; onItemEnd(); } }); } } else { long start = item.getStart(); if (start < 0) { start = 0; } sendVODInitCM(msgIn, (int) start); startBroadcastVOD(); } } /** {@inheritDoc} */ public void previousItem() { stop(); moveToPrevious(); if (currentItemIndex == -1) { return; } IPlayItem item = items.get(currentItemIndex); play(item); } /** * Push message * * @param message * Message */ private void pushMessage(IMessage message) throws IOException { msgOut.pushMessage(message); recordPipe.pushMessage(message); // Notify listeners about received packet if (message instanceof RTMPMessage) { final IRTMPEvent rtmpEvent = ((RTMPMessage) message).getBody(); if (rtmpEvent instanceof IStreamPacket) { for (IStreamListener listener : getStreamListeners()) { try { listener.packetReceived(this, (IStreamPacket) rtmpEvent); } catch (Exception e) { log.error("Error while notifying listener " + listener, e); } } } } } /** {@inheritDoc} */ public void pushMessage(IPipe pipe, IMessage message) throws IOException { pushMessage(message); } /** {@inheritDoc} */ public void removeAllItems() { items.clear(); } /** {@inheritDoc} */ public void removeItem(int index) { if (index < 0 || index >= items.size()) { return; } items.remove(index); } /** {@inheritDoc} */ public void saveAs(String name, boolean isAppend) throws IOException, ResourceNotFoundException, ResourceExistException { try { IScope scope = getScope(); IStreamFilenameGenerator generator = (IStreamFilenameGenerator) ScopeUtils.getScopeService(scope, IStreamFilenameGenerator.class, DefaultStreamFilenameGenerator.class); String filename = generator.generateFilename(scope, name, ".flv", GenerationType.RECORD); Resource res = scope.getContext().getResource(filename); if (!isAppend) { if (res.exists()) { // Per livedoc of FCS/FMS: // When "live" or "record" is used, // any previously recorded stream with the same stream // URI is deleted. if (!res.getFile().delete()) throw new IOException("file could not be deleted"); } } else { if (!res.exists()) { // Per livedoc of FCS/FMS: // If a recorded stream at the same URI does not already // exist, // "append" creates the stream as though "record" was // passed. isAppend = false; } } if (!res.exists()) { // Make sure the destination directory exists try { String path = res.getFile().getAbsolutePath(); int slashPos = path.lastIndexOf(File.separator); if (slashPos != -1) { path = path.substring(0, slashPos); } File tmp = new File(path); if (!tmp.isDirectory()) { tmp.mkdirs(); } } catch (IOException err) { log.error("Could not create destination directory.", err); } res = scope.getResource(filename); } if (!res.exists()) { if (!res.getFile().canWrite()) { log.warn("File cannot be written to " + res.getFile().getCanonicalPath()); } res.getFile().createNewFile(); } FileConsumer fc = new FileConsumer(scope, res.getFile()); Map paramMap = new HashMap(); if (isAppend) { paramMap.put("mode", "append"); } else { paramMap.put("mode", "record"); } if (null == recordPipe) { recordPipe = new InMemoryPushPushPipe(); } recordPipe.subscribe(fc, paramMap); recordingFilename = filename; } catch (IOException e) { log.warn("Save as exception", e); } } /** * Pull the next message from IMessageInput and schedule it for push * according to the timestamp. */ private void scheduleNextMessage() { boolean first = nextRTMPMessage == null; nextRTMPMessage = getNextRTMPMessage(); if (nextRTMPMessage == null) { onItemEnd(); return; } IRTMPEvent rtmpEvent = null; if (first) { rtmpEvent = nextRTMPMessage.getBody(); // FIXME hack the first Metadata Tag from FLVReader // the FLVReader will issue a metadata tag of ts 0 // even if it is seeked to somewhere in the middle // which will cause the stream to wait too long. // Is this an FLVReader's bug? if (!(rtmpEvent instanceof VideoData) && !(rtmpEvent instanceof AudioData) && rtmpEvent.getTimestamp() == 0) { rtmpEvent.release(); nextRTMPMessage = getNextRTMPMessage(); if (nextRTMPMessage == null) { onItemEnd(); return; } } } rtmpEvent = nextRTMPMessage.getBody(); if (rtmpEvent instanceof VideoData) { nextVideoTS = rtmpEvent.getTimestamp(); nextTS = nextVideoTS; } else if (rtmpEvent instanceof AudioData) { nextAudioTS = rtmpEvent.getTimestamp(); nextTS = nextAudioTS; } else { nextDataTS = rtmpEvent.getTimestamp(); nextTS = nextDataTS; } if (first) { vodStartTS = nextTS; } long delta = nextTS - vodStartTS - (System.currentTimeMillis() - serverStartTS); vodJobName = scheduler.addScheduledOnceJob(delta, new IScheduledJob() { /** {@inheritDoc} */ public void execute(ISchedulingService service) { if (vodJobName == null) { return; } vodJobName = null; try { pushMessage(nextRTMPMessage); } catch (IOException err) { log.error("Error while sending message.", err); } nextRTMPMessage.getBody().release(); long start = currentItem.getStart(); if (start < 0) { start = 0; } if (currentItem.getLength() >= 0 && nextTS - currentItem.getStart() > currentItem.getLength()) { onItemEnd(); return; } scheduleNextMessage(); } }); } /** * Send reset message */ private void sendResetMessage() { // Send new reset message try { pushMessage(new ResetMessage()); } catch (IOException err) { log.error("Error while sending reset message.", err); } } /** * Send VOD initialization control message * * @param msgIn * Message input * @param start * Start timestamp */ private void sendVODInitCM(IMessageInput msgIn, int start) { // Create new out-of-band control message OOBControlMessage oobCtrlMsg = new OOBControlMessage(); // Set passive type oobCtrlMsg.setTarget(IPassive.KEY); // Set service name of init oobCtrlMsg.setServiceName("init"); // Create map for parameters Map paramMap = new HashMap(); // Put start timestamp into Map of params paramMap.put("startTS", start); // Attach to OOB control message and send it oobCtrlMsg.setServiceParamMap(paramMap); msgIn.sendOOBControlMessage(this, oobCtrlMsg); } /** {@inheritDoc} */ public void setItem(int index) { if (index < 0 || index >= items.size()) { return; } stop(); currentItemIndex = index; IPlayItem item = items.get(currentItemIndex); play(item); } /** {@inheritDoc} */ public void setPlaylistController(IPlaylistController controller) { this.controller = controller; } /** {@inheritDoc} */ public void setPublishedName(String name) { publishedName = name; } /** {@inheritDoc} */ public void setRandom(boolean random) { isRandom = random; } /** {@inheritDoc} */ public void setRepeat(boolean repeat) { isRepeat = repeat; } /** {@inheritDoc} */ public void setRewind(boolean rewind) { isRewind = rewind; } /** * Start this server-side stream */ public void start() { if (state != State.UNINIT) { throw new IllegalStateException("State " + state + " not valid to start"); } if (items.size() == 0) { throw new IllegalStateException("At least one item should be specified to start"); } if (publishedName == null) { throw new IllegalStateException("A published name is needed to start"); } // publish this server-side stream IProviderService providerService = (IProviderService) getScope().getContext().getBean(IProviderService.BEAN_NAME); providerService.registerBroadcastStream(getScope(), publishedName, this); Map recordParamMap = new HashMap(); recordPipe = new InMemoryPushPushPipe(); recordParamMap.put("record", null); recordPipe.subscribe((IProvider) this, recordParamMap); recordingFilename = null; scheduler = (ISchedulingService) getScope().getContext().getBean(ISchedulingService.BEAN_NAME); state = State.STOPPED; currentItemIndex = -1; nextItem(); } /** * Begin VOD broadcasting */ private void startBroadcastVOD() { nextVideoTS = nextAudioTS = nextDataTS = 0; nextRTMPMessage = null; vodStartTS = 0; serverStartTS = System.currentTimeMillis(); scheduleNextMessage(); } /** * Stop this server-side stream */ public void stop() { if (state != State.PLAYING && state != State.PAUSED) { return; } if (liveJobName != null) { scheduler.removeScheduledJob(liveJobName); liveJobName = null; } if (vodJobName != null) { scheduler.removeScheduledJob(vodJobName); vodJobName = null; } if (msgIn != null) { msgIn.unsubscribe(this); msgIn = null; } if (nextRTMPMessage != null) { nextRTMPMessage.getBody().release(); } state = State.STOPPED; } /** {@inheritDoc} */ public void pause() { if (state == State.PLAYING) { state = State.PAUSED; } else if (state == State.PAUSED) { state = State.PLAYING; vodStartTS = 0; serverStartTS = System.currentTimeMillis(); scheduleNextMessage(); } } /** {@inheritDoc} */ public void seek(int position) { if (state != State.PLAYING && state != State.PAUSED) // Can't seek when stopped/closed return; sendVODSeekCM(msgIn, position); } /** * Send VOD seek control message * * @param msgIn Message input * @param position New timestamp to play from */ private void sendVODSeekCM(IMessageInput msgIn, int position) { OOBControlMessage oobCtrlMsg = new OOBControlMessage(); oobCtrlMsg.setTarget(ISeekableProvider.KEY); oobCtrlMsg.setServiceName("seek"); Map paramMap = new HashMap(); paramMap.put("position", new Integer(position)); oobCtrlMsg.setServiceParamMap(paramMap); msgIn.sendOOBControlMessage(this, oobCtrlMsg); synchronized (this) { // Reset properties vodStartTS = 0; serverStartTS = System.currentTimeMillis(); if (nextRTMPMessage != null) { try { pushMessage(nextRTMPMessage); } catch (IOException err) { log.error("Error while sending message.", err); } nextRTMPMessage.getBody().release(); nextRTMPMessage = null; } ResetMessage reset = new ResetMessage(); try { pushMessage(reset); } catch (IOException err) { log.error("Error while sending message.", err); } scheduleNextMessage(); } } /** {@inheritDoc} */ public void addStreamListener(IStreamListener listener) { listeners.add(listener); } /** {@inheritDoc} */ public Collection getStreamListeners() { return listeners; } /** {@inheritDoc} */ public void removeStreamListener(IStreamListener listener) { listeners.remove(listener); } }red5-1.0~svn4374.orig/test/org/red5/server/stream/CodecEnumTest.java0000644000175000017500000000235011706617130025070 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import junit.framework.Assert; import org.junit.Test; import org.red5.server.stream.codec.AudioCodec; import org.red5.server.stream.codec.VideoCodec; public class CodecEnumTest { @Test public void testAudio() { Assert.assertTrue(AudioCodec.MP3.getId() == 2); Assert.assertTrue(AudioCodec.SPEEX.getId() == 11); Assert.assertTrue(AudioCodec.MP3_8K.getId() == 14); } @Test public void testVideo() { Assert.assertTrue(VideoCodec.AVC.getId() == 7); } } red5-1.0~svn4374.orig/test/org/red5/server/stream/PlaylistSubscriberStreamTest.xml0000644000175000017500000000441711274377027030124 0ustar drazzibdrazzib red5-1.0~svn4374.orig/test/org/red5/server/stream/PlaylistSubscriberStreamTest.java0000644000175000017500000001267011747114732030242 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.io.IOException; import java.util.List; import java.util.Map; import org.junit.Test; import org.red5.server.Context; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.api.scope.ScopeType; import org.red5.server.api.stream.OperationNotSupportedException; import org.red5.server.api.stream.support.SimplePlayItem; import org.red5.server.messaging.IMessage; import org.red5.server.messaging.IMessageOutput; import org.red5.server.messaging.IProvider; import org.red5.server.messaging.OOBControlMessage; import org.red5.server.scope.Scope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.test.AbstractDependencyInjectionSpringContextTests; @SuppressWarnings("deprecation") public class PlaylistSubscriberStreamTest extends AbstractDependencyInjectionSpringContextTests { protected static Logger log = LoggerFactory.getLogger(PlaylistSubscriberStreamTest.class); private static PlaylistSubscriberStream pss; @Override protected String[] getConfigLocations() { return new String[] { "org/red5/server/stream/PlaylistSubscriberStreamTest.xml" }; } @Override protected void onSetUp() throws Exception { System.out.println("onSetUp"); super.onSetUp(); // System.setProperty("red5.deployment.type", "junit"); if (pss == null) { pss = (PlaylistSubscriberStream) applicationContext.getBean("playlistSubscriberStream"); Context ctx = new Context(); ctx.setApplicationContext(applicationContext); Scope scope = new DummyScope(); scope.setName(""); scope.setContext(ctx); pss.setScope(scope); // ISchedulingService schedulingService = (ISchedulingService) applicationContext.getBean(ISchedulingService.BEAN_NAME); IConsumerService consumerService = (IConsumerService) applicationContext.getBean(IConsumerService.KEY); IProviderService providerService = (IProviderService) applicationContext.getBean(IProviderService.BEAN_NAME); //create and get the engine PlayEngine engine = pss.createEngine(schedulingService, consumerService, providerService); //mock the message output engine.setMessageOut(new DummyMessageOut()); } } @Override protected void onTearDown() throws Exception { System.out.println("onTearDown"); super.onTearDown(); } @Test public void testGetExecutor() { System.out.println("testGetExecutor"); assertTrue(pss.getExecutor() != null); } @Test public void testStart() { System.out.println("testStart"); SimplePlayItem item = SimplePlayItem.build("DarkKnight.flv"); pss.addItem(item); pss.start(); } @Test public void testPlay() throws Exception { System.out.println("testPlay"); pss.play(); } @Test public void testPause() { System.out.println("testPause"); long sent = pss.getBytesSent(); pss.pause((int) sent); } @Test public void testResume() { System.out.println("testResume"); long sent = pss.getBytesSent(); pss.resume((int) sent); } @Test public void testSeek() { System.out.println("testSeek"); long sent = pss.getBytesSent(); try { pss.seek((int) (sent * 2)); } catch (OperationNotSupportedException e) { log.warn("Exception {}", e); } } @Test public void testAddItemIPlayItem() { System.out.println("testAddItemIPlayItem"); SimplePlayItem item = SimplePlayItem.build("IronMan.flv"); pss.addItem(item); } @Test public void testPreviousItem() { log.error("Not yet implemented -- get on that"); } @Test public void testNextItem() { log.error("Not yet implemented -- get on that"); } @Test public void testSetItem() { log.error("Not yet implemented -- get on that"); } @Test public void testStop() { System.out.println("testStop"); pss.stop(); } @Test public void testClose() { System.out.println("testClose"); pss.close(); } private class DummyScope extends Scope { DummyScope() { super(new Scope.Builder(null, ScopeType.ROOM, "dummy", false)); } } private class DummyMessageOut implements IMessageOutput { public List getProviders() { System.out.println("getProviders"); return null; } public void pushMessage(IMessage message) throws IOException { System.out.println("pushMessage: " + message); } public void sendOOBControlMessage(IProvider provider, OOBControlMessage oobCtrlMsg) { System.out.println("sendOOBControlMessage"); } public boolean subscribe(IProvider provider, Map paramMap) { System.out.println("subscribe"); return true; } public boolean unsubscribe(IProvider provider) { System.out.println("unsubscribe"); return true; } } } red5-1.0~svn4374.orig/test/org/red5/server/stream/PlayBufferTest.java0000644000175000017500000000505611706617130025273 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import junit.framework.JUnit4TestAdapter; import junit.framework.Test; import junit.framework.TestCase; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.stream.message.RTMPMessage; /** * TODO: extend testcase * * @author m.j.milicevic */ public class PlayBufferTest extends TestCase { public static Test suite() { return new JUnit4TestAdapter(PlayBufferTest.class); } PlayBuffer playBuffer; private RTMPMessage rtmpMessage; private void dequeue() throws Exception { setUp(); } /** * enqueue with messages */ private void enqueue() { boolean success = playBuffer.putMessage(rtmpMessage); assertTrue("message successfully put into play buffer", success); } /** {@inheritDoc} */ @Override protected void setUp() throws Exception { super.setUp(); VideoData message = new VideoData(IoBuffer.allocate(100)); playBuffer = new PlayBuffer(1000); rtmpMessage = RTMPMessage.build(message); } public void testClear() { enqueue(); playBuffer.clear(); assertTrue(playBuffer.getMessageCount() == 0); } public void testPeekMessage() throws Exception { enqueue(); assertTrue(playBuffer.peekMessage().equals(rtmpMessage)); dequeue(); } public void testPlayBuffer() { assertTrue("player buffer should be initialized", playBuffer != null); } public void testPutMessage() throws Exception { enqueue(); RTMPMessage peek_message = playBuffer.peekMessage(); assertNotNull("message shouldn't be null", peek_message); assertTrue(peek_message.equals(rtmpMessage)); dequeue(); } public void testTakeMessage() throws Exception { enqueue(); assertTrue(playBuffer.takeMessage().equals(rtmpMessage)); dequeue(); } }red5-1.0~svn4374.orig/test/org/red5/server/io/0000755000175000017500000000000011760512565020645 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/io/FLVServiceImplTest.java0000644000175000017500000001305511706617130025140 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import junit.framework.Assert; import junit.framework.TestCase; import org.red5.io.ITag; import org.red5.io.ITagReader; import org.red5.io.ITagWriter; import org.red5.io.flv.IFLV; import org.red5.io.flv.IFLVService; import org.red5.io.flv.impl.FLVService; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; import org.red5.server.cache.NoCacheImpl; /** * A FLVServiceImpl TestCase * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class FLVServiceImplTest extends TestCase { private IFLVService service; /** * SetUp is called before each test * */ @Override public void setUp() { service = new FLVService(); service.setSerializer(new Serializer()); service.setDeserializer(new Deserializer()); } /** * Tests: getFlv(String s) * * @param tag tag * @throws IOException if io error * @throws FileNotFoundException if file not found */ /* * public void testFLVString() throws FileNotFoundException, IOException { * FLV flv = service.getFLV("fixtures/test_cue.flv"); Reader reader = * flv.reader(); Tag tag = null; * * while(reader.hasMoreTags()) { tag = reader.readTag(); //printTag(tag); } * // simply tests to see if the last tag of the flv file // has a * timestamp of 2500 Assert.assertEquals(4166,tag.getTimestamp()); * //Assert.assertEquals(true,true); } */ private void printTag(ITag tag) { System.out.println("tag:\n-------\n" + tag); } /** * Tests: getFLVFile(File f) * * @throws IOException if io error * @throws FileNotFoundException if file not found */ public void testFLVFile() throws FileNotFoundException, IOException { File f = new File("fixtures/test.flv"); System.out.println("test: " + f); IFLV flv = (IFLV) service.getStreamableFile(f); flv.setCache(NoCacheImpl.getInstance()); System.out.println("test: " + flv); ITagReader reader = flv.getReader(); System.out.println("test: " + reader); ITag tag = null; System.out.println("test: " + reader.hasMoreTags()); while (reader.hasMoreTags()) { tag = reader.readTag(); // System.out.println("test: " + f); printTag(tag); } // simply tests to see if the last tag of the flv file // has a timestamp of 2500 // Assert.assertEquals(4166,tag.getTimestamp()); Assert.assertEquals(true, true); } /** * Tests: getFLVFileInputStream(FileInputStream fis) * * @return void * @throws IOException * @throws FileNotFoundException */ /* * public void testFLVFileInputStreamKeyFrameAnalyzer() throws * FileNotFoundException, IOException { File f = new * File("fixtures/test_cue3.flv"); FileInputStream fis = new * FileInputStream(f); FLV flv = service.getFLV(fis); Reader reader = * flv.reader(); reader.analyzeKeyFrames(); * * // simply tests to see if the last tag of the flv file // has a * timestamp of 2500 Assert.assertEquals(true,true); } */ /** * Tests: getFLVFileInputStream(FileInputStream fis) * * @throws IOException */ /* * public void testFLVFileInputStream() throws FileNotFoundException, * IOException { File f = new File("fixtures/test_cue3.flv"); FileInputStream * fis = new FileInputStream(f); FLV flv = service.getFLV(fis); Reader * reader = flv.reader(); Tag tag = null; * * while(reader.hasMoreTags()) { tag = reader.readTag(); printTag(tag); } * // simply tests to see if the last tag of the flv file // has a * timestamp of 2500 Assert.assertEquals(4166,tag.getTimestamp()); } */ /* * public void testWriteFLVFileOutputStream() throws IOException { File f = * new File("fixtures/test_cue2.flv"); * * if(f.exists()) { f.delete(); } * // Create new file f.createNewFile(); FileOutputStream fos = new * FileOutputStream(f); //fos.write((byte)0x01); FLV flv = * service.getFLV(fos); Writer writer = flv.writer(); * // Create a reader for testing File readfile = new * File("fixtures/test_cue.flv"); FileInputStream fis = new * FileInputStream(readfile); FLV readflv = service.getFLV(fis); Reader * reader = readflv.reader(); * * writeTags(reader, writer); * // Currently asserts to true. I just wanted to see // if the method * threw an exception Assert.assertEquals(true, true); } */ @SuppressWarnings("unused") private void writeTags(ITagReader reader, ITagWriter writer) throws IOException { ITag tag = null; while (reader.hasMoreTags()) { tag = reader.readTag(); writer.writeTag(tag); // printTag(tag); } } public void testWriteFLVString() { } public void testWriteFLVFile() { } } red5-1.0~svn4374.orig/test/org/red5/server/io/SimpleJavaBean.java0000644000175000017500000000301311706617130024320 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; /** * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class SimpleJavaBean { private String nameOfBean = "jeff"; /** * Getter for property 'nameOfBean'. * * @return Value for property 'nameOfBean'. */ public String getNameOfBean() { return nameOfBean; } /** * Setter for property 'nameOfBean'. * * @param nameOfBean Value to set for property 'nameOfBean'. */ public void setNameOfBean(String nameOfBean) { this.nameOfBean = nameOfBean; } /** {@inheritDoc} */ @Override public boolean equals(Object obj){ if(obj instanceof SimpleJavaBean){ SimpleJavaBean sjb = (SimpleJavaBean) obj; return sjb.getNameOfBean().equals(sjb.getNameOfBean()); } return false; } }red5-1.0~svn4374.orig/test/org/red5/server/io/AMF3IOTest.java0000644000175000017500000002326411706617130023267 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; import java.util.List; import java.util.Vector; import junit.framework.Assert; import org.apache.mina.core.buffer.IoBuffer; import org.junit.Test; import org.red5.io.amf3.ByteArray; import org.red5.io.amf3.Input; import org.red5.io.amf3.Output; import org.red5.io.utils.HexDump; import org.red5.server.net.rtmp.message.StreamAction; /* * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Art Clarke, Vlideshow Inc (aclarke@vlideshow.com) */ public class AMF3IOTest extends AbstractIOTest { IoBuffer buf; /** {@inheritDoc} */ @Override void dumpOutput() { buf.flip(); System.err.println(HexDump.formatHexDump(buf.getHexDump())); } /** {@inheritDoc} */ @Override void resetOutput() { setupIO(); } /** {@inheritDoc} */ @Override void setupIO() { buf = IoBuffer.allocate(0); // 1kb buf.setAutoExpand(true); buf.setAutoShrink(true); in = new Input(buf); out = new Output(buf); } @Test public void testEnum() { log.debug("Testing Enum"); serializer.serialize(out, StreamAction.CONNECT); dumpOutput(); Object object = deserializer.deserialize(in, StreamAction.class); log.debug("Enums - {} {}", object.getClass().getName(), StreamAction.CONNECT.getClass().getName()); Assert.assertEquals(object.getClass().getName(), StreamAction.CONNECT.getClass().getName()); resetOutput(); } @Test public void testByteArray() { log.debug("Testing ByteArray"); // just some ones and such ByteArray baIn = new ByteArray(); baIn.writeBytes(new byte[] { (byte) 0, (byte) 0x1, (byte) 0x42, (byte) 0x1, (byte) 0x42, (byte) 0x1, (byte) 0x42, (byte) 0x1, (byte) 0x42, (byte) 0x1, (byte) 0x42, (byte) 0x1, (byte) 0x42, (byte) 0x1, (byte) 0x42, (byte) 0x1, (byte) 0x42, (byte) 0x99 }); serializer.serialize(out, baIn); dumpOutput(); ByteArray baOut = deserializer.deserialize(in, ByteArray.class); Assert.assertNotNull(baOut); Assert.assertEquals(baIn.length(), baOut.length()); for (int i = 0; i < baOut.length(); i++) { System.err.println("Byte: " + baOut.readByte()); } resetOutput(); } @Test public void testVectorRoundTrip() { log.debug("Testing Vector on a round trip"); Vector vIn = new Vector(); vIn.add("This is my vector and her name is Sally"); serializer.serialize(out, vIn); dumpOutput(); // test fails without enforcing amf3 here ((org.red5.io.amf3.Input) in).enforceAMF3(); Vector vOut = deserializer.deserialize(in, Vector.class); Assert.assertNotNull(vOut); Assert.assertEquals(vIn.size(), vOut.size()); for (int i = 0; i < vOut.size(); i++) { System.err.println("Element: " + vOut.elementAt(i)); } resetOutput(); } @Test public void testVectorIntInput() { log.debug("Testing Vector"); //0D090000000002000007D07FFFFFFF80000000 byte[] v = new byte[] { (byte) 0x0D, (byte) 0x09, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0xD0, (byte) 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; in = new Input(IoBuffer.wrap(v)); List vectorOut = deserializer.deserialize(in, null); //[2, 2000, 2147483647, -2147483648] Assert.assertNotNull(vectorOut); Assert.assertEquals(vectorOut.size(), 4); for (int i = 0; i < vectorOut.size(); i++) { System.err.println("Vector: " + vectorOut.get(i)); } resetOutput(); } @Test public void testVectorUIntInput() { log.debug("Testing Vector"); //0E090000000002000007D0FFFFFFFF00000000 byte[] v = new byte[] { (byte) 0x0E, (byte) 0x09, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0xD0, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; in = new Input(IoBuffer.wrap(v)); List vectorOut = deserializer.deserialize(in, null); //[2, 2000, 4294967295, 0] Assert.assertNotNull(vectorOut); Assert.assertEquals(vectorOut.size(), 4); for (int i = 0; i < vectorOut.size(); i++) { System.err.println("Vector: " + vectorOut.get(i)); } resetOutput(); } @Test public void testVectorNumberInput() { log.debug("Testing Vector"); //0F0F003FF199999999999ABFF199999999999A7FEFFFFFFFFFFFFF0000000000000001FFF8000000000000FFF00000000000007FF0000000000000 byte[] v = new byte[] { (byte) 0x0F, (byte) 0x0F, (byte) 0x00, (byte) 0x3F, (byte) 0xF1, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x9A, (byte) 0xBF, (byte) 0xF1, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x9A, (byte) 0x7F, (byte) 0xEF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0xFF, (byte) 0xF8, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xF0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x7F, (byte) 0xF0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; in = new Input(IoBuffer.wrap(v)); ((org.red5.io.amf3.Input) in).enforceAMF3(); List vectorOut = deserializer.deserialize(in, null); //[1.1, -1.1, 1.7976931348623157E308, 4.9E-324, NaN, -Infinity, Infinity] Assert.assertNotNull(vectorOut); Assert.assertEquals(vectorOut.size(), 7); for (int i = 0; i < vectorOut.size(); i++) { System.err.println("Vector: " + vectorOut.get(i)); } resetOutput(); } @Test public void testVectorMixedInput() { log.debug("Testing Vector"); //100700010607666f6f010a13256f72672e726564352e74673742e466f6f33000403 //[foo, null, org.red5.test.Foo3[foo=0]] // Foo3 is a class instance byte[] v2 = new byte[] { (byte) 0x10, (byte) 0x07, (byte) 0x00, (byte) 0x01, (byte) 0x06, (byte) 0x07, (byte) 0x66, (byte) 0x6f, (byte) 0x6f, (byte) 0x01, (byte) 0x0a, (byte) 0x13, (byte) 0x25, (byte) 0x6f, (byte) 0x72, (byte) 0x67, (byte) 0x2e, (byte) 0x72, (byte) 0x65, (byte) 0x64, (byte) 0x35, (byte) 0x2e, (byte) 0x74, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x2e, (byte) 0x46, (byte) 0x6f, (byte) 0x6f, (byte) 0x33, (byte) 0x00, (byte) 0x04, (byte) 0x03 }; in = new Input(IoBuffer.wrap(v2)); ((org.red5.io.amf3.Input) in).enforceAMF3(); List vectorOut = deserializer.deserialize(in, null); Assert.assertNotNull(vectorOut); Assert.assertEquals(vectorOut.size(), 3); for (int i = 0; i < vectorOut.size(); i++) { System.err.println("Vector: " + vectorOut.get(i)); } resetOutput(); } @SuppressWarnings("unused") @Test public void testVectorStringInput() { log.debug("Testing Vector"); //[Paul, ] byte[] v = new byte[] { (byte) 0x10, (byte) 0x05, (byte) 0x00, (byte) 0x01, (byte) 0x06, (byte) 0x09, (byte) 0x50, (byte) 0x61, (byte) 0x75, (byte) 0x6c, (byte) 0x06, (byte) 0x01 }; //[Paul, Paul] byte[] v1 = new byte[] { (byte) 0x10, (byte) 0x05, (byte) 0x00, (byte) 0x01, (byte) 0x06, (byte) 0x09, (byte) 0x50, (byte) 0x61, (byte) 0x75, (byte) 0x6c, (byte) 0x06, (byte) 0x00 }; //[Paul, Paul, Paul] byte[] v2 = new byte[] { (byte) 0x10, (byte) 0x07, (byte) 0x00, (byte) 0x01, (byte) 0x06, (byte) 0x09, (byte) 0x50, (byte) 0x61, (byte) 0x75, (byte) 0x6c, (byte) 0x06, (byte) 0x00, (byte) 0x06, (byte) 0x00 }; //[Paul, Tawnya] byte[] v3 = new byte[] { (byte) 0x10, (byte) 0x05, (byte) 0x00, (byte) 0x01, (byte) 0x06, (byte) 0x09, (byte) 0x50, (byte) 0x61, (byte) 0x75, (byte) 0x6c, (byte) 0x06, (byte) 0x0d, (byte) 0x54, (byte) 0x61, (byte) 0x77, (byte) 0x6e, (byte) 0x79, (byte) 0x61 }; //[1.0, 3.0, aaa, 5.0, aaa, aaa, 5.0, bb, bb] byte[] v4 = new byte[] { (byte) 0x10, (byte) 0x13, (byte) 0x00, (byte) 0x01, (byte) 0x04, (byte) 0x01, (byte) 0x04, (byte) 0x03, (byte) 0x06, (byte) 0x07, (byte) 0x61, (byte) 0x61, (byte) 0x61, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x05, (byte) 0x62, (byte) 0x62, (byte) 0x06, (byte) 0x02 }; //[1.0, 3.0, aaa, [1, 2]] byte[] v5 = new byte[] { (byte) 0x10, (byte) 0x09, (byte) 0x00, (byte) 0x01, (byte) 0x04, (byte) 0x01, (byte) 0x04, (byte) 0x03, (byte) 0x06, (byte) 0x07, (byte) 0x61, (byte) 0x61, (byte) 0x61, (byte) 0x0d, (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02 }; in = new Input(IoBuffer.wrap(v5)); ((org.red5.io.amf3.Input) in).enforceAMF3(); List vectorOut = deserializer.deserialize(in, null); //[Paul, ] Assert.assertNotNull(vectorOut); //Assert.assertEquals(vectorOut.size(), 4); for (int i = 0; i < vectorOut.size(); i++) { System.err.println("Vector: " + vectorOut.get(i)); } resetOutput(); } } red5-1.0~svn4374.orig/test/org/red5/server/io/MetaServiceTest.java0000644000175000017500000000567711706617130024570 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; import java.io.File; import java.io.IOException; import junit.framework.TestCase; import org.red5.io.flv.IFLV; import org.red5.io.flv.impl.FLVService; import org.red5.io.flv.meta.ICueType; import org.red5.io.flv.meta.IMetaCue; import org.red5.io.flv.meta.MetaCue; import org.red5.io.flv.meta.MetaData; import org.red5.io.flv.meta.MetaService; import org.red5.server.cache.NoCacheImpl; public class MetaServiceTest extends TestCase { private FLVService service; private MetaService metaService; /** {@inheritDoc} */ @Override protected void setUp() throws Exception { super.setUp(); // Create a FLV Service service = new FLVService(); // Create a Meta Service metaService = new MetaService(); } /** * Test writing meta data * @throws IOException if io exception */ public void testWrite() throws IOException { String path = "fixtures/test.flv"; File f = new File(path); System.out.println("Path: " + f.getAbsolutePath()); if (!f.exists()) { // try test subdirectory path = "test/fixtures/test.flv"; f = new File(path); System.out.println("Path: " + f.getAbsolutePath()); } // Get MetaData to embed MetaData meta = createMeta(); // Read in a FLV file for reading tags IFLV flv = (IFLV) service.getStreamableFile(f); flv.setCache(NoCacheImpl.getInstance()); // set the MetaService flv.setMetaService(metaService); // set the MetaData flv.setMetaData(meta); } /** * Create some test Metadata for insertion. * * @return MetaData meta */ private MetaData createMeta() { IMetaCue metaCue[] = new MetaCue[2]; IMetaCue cp = new MetaCue(); cp.setName("cue_1"); cp.setTime(0.01); cp.setType(ICueType.EVENT); IMetaCue cp1 = new MetaCue(); cp1.setName("cue_2"); cp1.setTime(0.03); cp1.setType(ICueType.EVENT); // add cuepoints to array metaCue[0] = cp; metaCue[1] = cp1; MetaData meta = new MetaData(); meta.setMetaCue(metaCue); meta.setCanSeekToEnd(true); meta.setDuration(300); meta.setFrameRate(15); meta.setHeight(400); meta.setWidth(300); return meta; } } red5-1.0~svn4374.orig/test/org/red5/server/io/TestVO.java0000644000175000017500000000167711706617130022701 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; import java.io.Serializable; public class TestVO implements Serializable { private static final long serialVersionUID = 1L; @Override public boolean equals(Object obj) { return obj instanceof TestVO; } } red5-1.0~svn4374.orig/test/org/red5/server/io/MetaDataTest.java0000644000175000017500000000423411706617130024025 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; import junit.framework.Assert; import junit.framework.TestCase; import org.red5.io.flv.meta.MetaData; /** * MetaData TestCase * * @author The Red5 Project (red5@osflash.org) * @author daccattato (daccattato@gmail.com) */ public class MetaDataTest extends TestCase { MetaData data; /** Constructs a new MetaDataTest. */ public MetaDataTest() { data = new MetaData(); } /** {@inheritDoc} */ @Override protected void setUp() throws Exception { super.setUp(); data.setCanSeekToEnd(true); data.setDuration(7.347); data.setFrameRate(15); data.setHeight(333); data.setVideoCodecId(4); data.setVideoDataRate(400); data.setWidth(300); } /** {@inheritDoc} */ @Override public void tearDown() { data = null; } public void testCanSeekToEnd() { Assert.assertEquals(true, data.getCanSeekToEnd()); } public void testDuration() { Assert.assertEquals(7.347, data.getDuration(), 0); } public void testFrameRate() { Assert.assertEquals(15.0, data.getFrameRate()); } public void testHeight() { Assert.assertEquals(333, data.getHeight()); } public void testVideoCodecId() { Assert.assertEquals(4, data.getVideoCodecId()); } public void testVideoDataRate() { Assert.assertEquals(400, data.getVideoDataRate()); } public void testWidth() { Assert.assertEquals(400, data.getVideoDataRate()); } } red5-1.0~svn4374.orig/test/org/red5/server/io/FLVImpTest.java0000644000175000017500000000176611706617130023451 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; import org.junit.Test; import org.red5.io.flv.impl.FLV; import junit.framework.TestCase; public class FLVImpTest extends TestCase { @Test public void testCreation() { FLV exampleObj = new FLV(); assertNotNull(exampleObj); } } red5-1.0~svn4374.orig/test/org/red5/server/io/CircularRefBean.java0000644000175000017500000000263111706617130024473 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; /** * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class CircularRefBean extends SimpleJavaBean { private CircularRefBean refToSelf; /** * Constructs a new CircularRefBean. */ public CircularRefBean(){ super(); } /** * Getter for property 'refToSelf'. * * @return Value for property 'refToSelf'. */ public CircularRefBean getRefToSelf() { return refToSelf; } /** * Setter for property 'refToSelf'. * * @param refToSelf Value to set for property 'refToSelf'. */ public void setRefToSelf(CircularRefBean refToSelf) { this.refToSelf = refToSelf; } } red5-1.0~svn4374.orig/test/org/red5/server/io/MockIOTest.java0000644000175000017500000000257111706617130023470 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; import java.util.LinkedList; import java.util.List; import org.red5.io.mock.Input; import org.red5.io.mock.Mock; import org.red5.io.mock.Output; /* * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class MockIOTest extends AbstractIOTest { protected List list; /** {@inheritDoc} */ @Override void setupIO() { list = new LinkedList(); in = new Input(list); out = new Output(list); } /** {@inheritDoc} */ @Override void dumpOutput() { System.out.println(Mock.listToString(list)); } /** {@inheritDoc} */ @Override void resetOutput() { setupIO(); } } red5-1.0~svn4374.orig/test/org/red5/server/io/AbstractIOTest.java0000644000175000017500000002113711706617130024341 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import junit.framework.Assert; import junit.framework.TestCase; import org.apache.commons.beanutils.BeanMap; import org.red5.io.object.Deserializer; import org.red5.io.object.Input; import org.red5.io.object.Output; import org.red5.io.object.Serializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public abstract class AbstractIOTest extends TestCase { protected Logger log = LoggerFactory.getLogger(AbstractIOTest.class); protected Deserializer deserializer; protected Input in; protected Output out; protected Serializer serializer; abstract void dumpOutput(); abstract void resetOutput(); /** {@inheritDoc} */ @Override protected void setUp() { serializer = new Serializer(); deserializer = new Deserializer(); setupIO(); } abstract void setupIO(); public void testArray() { log.debug("Testing array"); String[] strArrIn = new String[] { "This", "Is", "An", "Array", "Of", "Strings" }; serializer.serialize(out, strArrIn); dumpOutput(); Object[] objArrayOut = deserializer.deserialize(in, Object[].class); for (int i = 0; i < strArrIn.length; i++) { Assert.assertEquals(strArrIn[i], objArrayOut[i]); } resetOutput(); } public void testArrayReference() { log.debug("Testing array reference"); TestVO mytest = new TestVO(); TestVO[] strArrIn = new TestVO[] { mytest, mytest }; serializer.serialize(out, strArrIn); dumpOutput(); TestVO[] objArrayOut = deserializer.deserialize(in, TestVO[].class); for (int i = 0; i < strArrIn.length; i++) { Assert.assertEquals(strArrIn[i], objArrayOut[i]); } resetOutput(); } public void testBoolean() { log.debug("Testing boolean"); serializer.serialize(out, Boolean.TRUE); dumpOutput(); Boolean val = deserializer.deserialize(in, Boolean.class); Assert.assertEquals(Boolean.TRUE, val); resetOutput(); serializer.serialize(out, Boolean.FALSE); dumpOutput(); val = deserializer.deserialize(in, Boolean.class); Assert.assertEquals(Boolean.FALSE, val); resetOutput(); } public void testCircularReference() { CircularRefBean beanIn = new CircularRefBean(); beanIn.setRefToSelf(beanIn); serializer.serialize(out, beanIn); dumpOutput(); CircularRefBean beanOut = deserializer.deserialize(in, CircularRefBean.class); Assert.assertNotNull(beanOut); Assert.assertEquals(beanOut, beanOut.getRefToSelf()); Assert.assertEquals(beanIn.getNameOfBean(), beanOut.getNameOfBean()); resetOutput(); } public void testDate() { log.debug("Testing date"); Date dateIn = new Date(); serializer.serialize(out, dateIn); dumpOutput(); Date dateOut = deserializer.deserialize(in, Date.class); Assert.assertEquals(dateIn, dateOut); resetOutput(); } @SuppressWarnings({ "rawtypes" }) public void testJavaBean() { log.debug("Testing list"); TestJavaBean beanIn = new TestJavaBean(); beanIn.setTestString("test string here"); beanIn.setTestBoolean((System.currentTimeMillis() % 2 == 0) ? true : false); beanIn.setTestBooleanObject((System.currentTimeMillis() % 2 == 0) ? Boolean.TRUE : Boolean.FALSE); beanIn.setTestNumberObject(Integer.valueOf((int) System.currentTimeMillis() / 1000)); serializer.serialize(out, beanIn); dumpOutput(); Object mapOrBean = deserializer.deserialize(in, Object.class); Assert.assertEquals(beanIn.getClass().getName(), mapOrBean.getClass().getName()); Map map = (mapOrBean instanceof Map) ? (Map) mapOrBean : new BeanMap(mapOrBean); Set entrySet = map.entrySet(); Iterator it = entrySet.iterator(); Map beanInMap = new BeanMap(beanIn); Assert.assertEquals(beanInMap.size(), map.size()); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String propOut = (String) entry.getKey(); Object valueOut = entry.getValue(); Assert.assertTrue(beanInMap.containsKey(propOut)); Assert.assertEquals(valueOut, beanInMap.get(propOut)); } resetOutput(); } public void testList() { log.debug("Testing list"); List> listIn = new LinkedList>(); listIn.add(null); listIn.add(Boolean.FALSE); listIn.add(Boolean.TRUE); listIn.add(Integer.valueOf(1)); listIn.add("This is a test string"); listIn.add(new Date()); serializer.serialize(out, listIn); dumpOutput(); List listOut = deserializer.deserialize(in, List.class); Assert.assertNotNull(listOut); Assert.assertEquals(listIn.size(), listOut.size()); for (int i = 0; i < listIn.size(); i++) { Assert.assertEquals(listOut.get(i), listIn.get(i)); } resetOutput(); } public void testMap() { Map mapIn = new HashMap(); mapIn.put("testNumber", Integer.valueOf(34)); mapIn.put("testString", "wicked"); mapIn.put("testBean", new SimpleJavaBean()); serializer.serialize(out, mapIn); dumpOutput(); Map mapOut = deserializer.deserialize(in, Map.class); Assert.assertNotNull(mapOut); Assert.assertEquals(mapIn.size(), mapOut.size()); Set entrySet = mapOut.entrySet(); Iterator it = entrySet.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String propOut = (String) entry.getKey(); Object valueOut = entry.getValue(); Assert.assertTrue(mapIn.containsKey(propOut)); Object valueIn = mapIn.get(propOut); Assert.assertEquals(valueOut, valueIn); } resetOutput(); } public void testNull() { log.debug("Testing null"); serializer.serialize(out, null); dumpOutput(); Object val = deserializer.deserialize(in, Object.class); Assert.assertEquals(val, null); resetOutput(); } public void testNumber() { log.debug("Testing number"); int num = 1000; serializer.serialize(out, Integer.valueOf(num)); dumpOutput(); Number n = deserializer.deserialize(in, Number.class); Assert.assertEquals(n.intValue(), num); resetOutput(); } public void testInteger() { log.debug("Testing integer"); int num = 129; serializer.serialize(out, Integer.valueOf(num)); dumpOutput(); Integer n = deserializer.deserialize(in, Integer.class); Assert.assertEquals(n.intValue(), num); resetOutput(); } public void testNegativeInteger() { log.debug("Testing negative integer"); int num = -129; serializer.serialize(out, Integer.valueOf(num)); dumpOutput(); Integer n = deserializer.deserialize(in, Integer.class); log.debug("Integer: {} {}", n, num); Assert.assertEquals(n.intValue(), num); resetOutput(); } @SuppressWarnings({ }) public void testSimpleReference() { Map mapIn = new HashMap(); Object bean = new SimpleJavaBean(); mapIn.put("thebean", bean); mapIn.put("thesamebeanagain", bean); // mapIn.put("thismap",mapIn); serializer.serialize(out, mapIn); dumpOutput(); Map mapOut = deserializer.deserialize(in, Map.class); Assert.assertNotNull(mapOut); Assert.assertEquals(mapIn.size(), mapOut.size()); Set entrySet = mapOut.entrySet(); Iterator it = entrySet.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String propOut = (String) entry.getKey(); SimpleJavaBean valueOut = (SimpleJavaBean) entry.getValue(); Assert.assertNotNull("couldn't get output bean", valueOut); Assert.assertTrue(mapIn.containsKey(propOut)); SimpleJavaBean valueIn = (SimpleJavaBean) mapIn.get(propOut); Assert.assertNotNull("couldn't get input bean", valueIn); Assert.assertEquals(valueOut.getNameOfBean(), valueIn.getNameOfBean()); } resetOutput(); } public void testString() { log.debug("Testing string"); String inStr = "hello world"; serializer.serialize(out, inStr); dumpOutput(); String outStr = deserializer.deserialize(in, String.class); Assert.assertEquals(inStr, outStr); resetOutput(); } } red5-1.0~svn4374.orig/test/org/red5/server/io/AMFIOTest.java0000644000175000017500000000263411706617130023202 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.amf.Input; import org.red5.io.amf.Output; import org.red5.io.utils.HexDump; /* * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class AMFIOTest extends AbstractIOTest { IoBuffer buf; /** {@inheritDoc} */ @Override void dumpOutput() { buf.flip(); System.err.println(HexDump.formatHexDump(buf.getHexDump())); } /** {@inheritDoc} */ @Override void resetOutput() { setupIO(); } /** {@inheritDoc} */ @Override void setupIO() { buf = IoBuffer.allocate(0); // 1kb buf.setAutoExpand(true); in = new Input(buf); out = new Output(buf); } } red5-1.0~svn4374.orig/test/org/red5/server/io/MetaDataInjectionTest.java0000644000175000017500000001253011706617130025666 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; import java.io.File; import java.io.IOException; import java.util.TreeSet; import junit.framework.TestCase; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.ITag; import org.red5.io.ITagReader; import org.red5.io.ITagWriter; import org.red5.io.IoConstants; import org.red5.io.amf.Output; import org.red5.io.flv.IFLV; import org.red5.io.flv.IFLVService; import org.red5.io.flv.impl.FLVService; import org.red5.io.flv.impl.Tag; import org.red5.io.flv.meta.ICueType; import org.red5.io.flv.meta.IMetaCue; import org.red5.io.flv.meta.MetaCue; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; import org.red5.server.cache.NoCacheImpl; /** * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class MetaDataInjectionTest extends TestCase { private IFLVService service; /** * SetUp is called before each test */ @Override public void setUp() { service = new FLVService(); service.setSerializer(new Serializer()); service.setDeserializer(new Deserializer()); } /** * Test MetaData injection * @throws IOException if io exception */ public void testMetaDataInjection() throws IOException { String path = "fixtures/test_cue1.flv"; File f = new File(path); System.out.println("Path: " + f.getAbsolutePath()); if (f.exists()) { f.delete(); } else { // try test subdirectory path = "test/fixtures/test_cue1.flv"; f = new File(path); System.out.println("Path: " + f.getAbsolutePath()); if (f.exists()) { f.delete(); } } // Create new file f.createNewFile(); // Use service to grab FLV file IFLV flv = (IFLV) service.getStreamableFile(f); // Grab a writer for writing a new FLV ITagWriter writer = flv.getWriter(); // Create a reader for testing File readfile = new File(path); IFLV readflv = (IFLV) service.getStreamableFile(readfile); readflv.setCache(NoCacheImpl.getInstance()); // Grab a reader for reading a FLV in ITagReader reader = readflv.getReader(); // Inject MetaData writeTagsWithInjection(reader, writer); } /** * Write FLV tags and inject Cue Points * @param reader * @param writer * @throws IOException */ private void writeTagsWithInjection(ITagReader reader, ITagWriter writer) throws IOException { IMetaCue cp = new MetaCue(); cp.setName("cue_1"); cp.setTime(0.01); cp.setType(ICueType.EVENT); IMetaCue cp1 = new MetaCue(); cp1.setName("cue_1"); cp1.setTime(2.01); cp1.setType(ICueType.EVENT); // Place in TreeSet for sorting TreeSet ts = new TreeSet(); ts.add(cp); ts.add(cp1); int cuePointTimeStamp = getTimeInMilliseconds(ts.first()); ITag tag = null; ITag injectedTag = null; while(reader.hasMoreTags()) { tag = reader.readTag(); if(tag.getDataType() != IoConstants.TYPE_METADATA) { //injectNewMetaData(); } else { //in } // if there are cuePoints in the TreeSet if(!ts.isEmpty()) { // If the tag has a greater timestamp than the // cuePointTimeStamp, then inject the tag while(tag.getTimestamp() > cuePointTimeStamp) { injectedTag = injectMetaData(ts.first(), tag); writer.writeTag(injectedTag); tag.setPreviousTagSize((injectedTag.getBodySize() + 11)); // Advance to the next CuePoint ts.remove(ts.first()); if(ts.isEmpty()) { break; } cuePointTimeStamp = getTimeInMilliseconds(ts.first()); } } writer.writeTag(tag); } } /** * Injects metadata (Cue Points) into a tag * @param cue * @param writer * @param tag * @return ITag tag */ private ITag injectMetaData(Object cue, ITag tag) { IMetaCue cp = (MetaCue) cue; Output out = new Output(IoBuffer.allocate(1000)); Serializer ser = new Serializer(); ser.serialize(out,"onCuePoint"); ser.serialize(out,cp); IoBuffer tmpBody = out.buf().flip(); int tmpBodySize = out.buf().limit(); int tmpPreviousTagSize = tag.getPreviousTagSize(); byte tmpDataType = IoConstants.TYPE_METADATA; int tmpTimestamp = getTimeInMilliseconds(cp); return new Tag(tmpDataType, tmpTimestamp, tmpBodySize, tmpBody, tmpPreviousTagSize); } /** * Returns a timestamp in milliseconds * @param object * @return int time */ private int getTimeInMilliseconds(Object object) { IMetaCue cp = (MetaCue) object; return (int) (cp.getTime() * 1000.00); } } red5-1.0~svn4374.orig/test/org/red5/server/io/TestJavaBean.java0000644000175000017500000000746511706617130024025 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; import java.util.Date; /** * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class TestJavaBean { private byte testByte = 65; private int testPrimitiveNumber = 3; private Integer testNumberObject = new Integer(33); private String testString = "red5 rocks!"; private Date testDate = new Date(); private Boolean testBooleanObject = Boolean.FALSE; private boolean testBoolean = true; /** * Getter for property 'testByte'. * * @return Value for property 'testByte'. */ public byte getTestByte() { return testByte; } /** * Setter for property 'testByte'. * * @param testByte Value to set for property 'testByte'. */ public void setTestByte(byte testByte) { this.testByte = testByte; } /** * Getter for property 'testBoolean'. * * @return Value for property 'testBoolean'. */ public boolean isTestBoolean() { return testBoolean; } /** * Setter for property 'testBoolean'. * * @param testBoolean Value to set for property 'testBoolean'. */ public void setTestBoolean(boolean testBoolean) { this.testBoolean = testBoolean; } /** * Getter for property 'testBooleanObject'. * * @return Value for property 'testBooleanObject'. */ public Boolean getTestBooleanObject() { return testBooleanObject; } /** * Setter for property 'testBooleanObject'. * * @param testBooleanObject Value to set for property 'testBooleanObject'. */ public void setTestBooleanObject(Boolean testBooleanObject) { this.testBooleanObject = testBooleanObject; } /** * Getter for property 'testDate'. * * @return Value for property 'testDate'. */ public Date getTestDate() { return testDate; } /** * Setter for property 'testDate'. * * @param testDate Value to set for property 'testDate'. */ public void setTestDate(Date testDate) { this.testDate = testDate; } /** * Getter for property 'testNumberObject'. * * @return Value for property 'testNumberObject'. */ public Integer getTestNumberObject() { return testNumberObject; } /** * Setter for property 'testNumberObject'. * * @param testNumberObject Value to set for property 'testNumberObject'. */ public void setTestNumberObject(Integer testNumberObject) { this.testNumberObject = testNumberObject; } /** * Getter for property 'testPrimitiveNumber'. * * @return Value for property 'testPrimitiveNumber'. */ public int getTestPrimitiveNumber() { return testPrimitiveNumber; } /** * Setter for property 'testPrimitiveNumber'. * * @param testPrimitiveNumber Value to set for property 'testPrimitiveNumber'. */ public void setTestPrimitiveNumber(int testPrimitiveNumber) { this.testPrimitiveNumber = testPrimitiveNumber; } /** * Getter for property 'testString'. * * @return Value for property 'testString'. */ public String getTestString() { return testString; } /** * Setter for property 'testString'. * * @param testString Value to set for property 'testString'. */ public void setTestString(String testString) { this.testString = testString; } } red5-1.0~svn4374.orig/test/org/red5/server/io/CuePointInjectionTest.java0000644000175000017500000001451211706617130025736 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.io; import java.io.File; import java.io.IOException; import java.util.TreeSet; import junit.framework.Assert; import junit.framework.TestCase; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.ITag; import org.red5.io.ITagReader; import org.red5.io.ITagWriter; import org.red5.io.IoConstants; import org.red5.io.amf.Output; import org.red5.io.flv.IFLV; import org.red5.io.flv.IFLVService; import org.red5.io.flv.impl.FLVService; import org.red5.io.flv.impl.Tag; import org.red5.io.flv.meta.ICueType; import org.red5.io.flv.meta.IMetaCue; import org.red5.io.flv.meta.MetaCue; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; import org.red5.server.cache.NoCacheImpl; /** * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class CuePointInjectionTest extends TestCase { private IFLVService service; /** * SetUp is called before each test * */ @Override public void setUp() { service = new FLVService(); service.setSerializer(new Serializer()); service.setDeserializer(new Deserializer()); } /** * Test MetaData injection * * @throws IOException for fun */ public void testCuePointInjection() throws IOException { String path = "fixtures/test_cue1.flv"; File f = new File(path); System.out.println("Path: " + f.getAbsolutePath()); if (f.exists()) { f.delete(); } else { // try test subdirectory path = "test/fixtures/test_cue1.flv"; f = new File(path); System.out.println("Path: " + f.getAbsolutePath()); if (f.exists()) { f.delete(); } } // Create new file f.createNewFile(); // Use service to grab FLV file IFLV flv = (IFLV) service.getStreamableFile(f); // Grab a writer for writing a new FLV ITagWriter writer = flv.getWriter(); // Create a reader for testing File readfile = new File(path); //assertTrue(readfile.exists()); IFLV readflv = (IFLV) service.getStreamableFile(readfile); readflv.setCache(NoCacheImpl.getInstance()); // Grab a reader for reading a FLV in ITagReader reader = readflv.getReader(); // Inject MetaData writeTagsWithInjection(reader, writer); } /** * Write FLV tags and inject Cue Points * * @param reader * @param writer * @throws IOException */ private void writeTagsWithInjection(ITagReader reader, ITagWriter writer) throws IOException { IMetaCue cp = new MetaCue(); cp.setName("cue_1"); cp.setTime(0.01); cp.setType(ICueType.EVENT); IMetaCue cp1 = new MetaCue(); cp1.setName("cue_2"); cp1.setTime(2.01); cp1.setType(ICueType.EVENT); // Place in TreeSet for sorting TreeSet ts = new TreeSet(); ts.add(cp); ts.add(cp1); // int cuePointTimeStamp = getTimeInMilliseconds(ts.first()); ITag tag = null; ITag injectedTag = null; // read any existing tags and insert cue points // while (reader.hasMoreTags()) { // tag = reader.readTag(); // // if there are cuePoints in the TreeSet // if (!ts.isEmpty()) { // // If the tag has a greater timestamp than the // // cuePointTimeStamp, then inject the tag // while (tag.getTimestamp() > cuePointTimeStamp) { // injectedTag = injectCuePoint(ts.first(), tag); // writer.writeTag(injectedTag); // tag.setPreviousTagSize((injectedTag.getBodySize() + 11)); // // Advance to the next CuePoint // ts.remove(ts.first()); // if (ts.isEmpty()) { // break; // } // cuePointTimeStamp = getTimeInMilliseconds(ts.first()); // } // } // writer.writeTag(tag); // } while (!ts.isEmpty()) { injectedTag = injectCuePoint(ts.first(), tag); writer.writeTag(injectedTag); // Advance to the next CuePoint ts.remove(ts.first()); } writer.close(); } /** * Injects metadata (Cue Points) into a tag * * @param cue * @param writer * @param tag * @return ITag tag */ private ITag injectCuePoint(Object cue, ITag tag) { IMetaCue cp = (MetaCue) cue; Output out = new Output(IoBuffer.allocate(1000)); Serializer ser = new Serializer(); ser.serialize(out, "onCuePoint"); ser.serialize(out, cp); IoBuffer tmpBody = out.buf().flip(); int tmpBodySize = out.buf().limit(); //int tmpPreviousTagSize = tag.getPreviousTagSize(); byte tmpDataType = ((IoConstants.TYPE_METADATA)); int tmpTimestamp = getTimeInMilliseconds(cp); //return new Tag(tmpDataType, tmpTimestamp, tmpBodySize, tmpBody, tmpPreviousTagSize); return new Tag(tmpDataType, tmpTimestamp, tmpBodySize, tmpBody, 0); } /** * Returns a timestamp in milliseconds * * @param object * @return int time */ private int getTimeInMilliseconds(Object object) { IMetaCue cp = (MetaCue) object; return (int) (cp.getTime() * 1000.00); } /** * Test to see if TreeSet is sorting properly */ public void testCuePointOrder() { IMetaCue cue = new MetaCue(); cue.setName("cue_1"); cue.setTime(0.01); cue.setType(ICueType.EVENT); IMetaCue cue1 = new MetaCue(); cue1.setName("cue_3"); cue1.setTime(2.01); cue1.setType(ICueType.EVENT); IMetaCue cue2 = new MetaCue(); cue2.setName("cue_2"); cue2.setTime(1.01); cue2.setType(ICueType.EVENT); TreeSet ts = new TreeSet(); ts.add(cue); ts.add(cue1); ts.add(cue2); System.out.println("ts: " + ts); Assert.assertEquals(true, true); } } red5-1.0~svn4374.orig/test/org/red5/server/ServerTest.java0000644000175000017500000001336211747114732023213 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner; import net.sourceforge.groboutils.junit.v1.TestRunnable; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.red5.server.api.scope.IGlobalScope; import org.red5.server.scope.GlobalScope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This test exercises the Server class. * * @author Paul Gregoire (mondain@gmail.com) */ public class ServerTest { protected static Logger log = LoggerFactory.getLogger(ServerTest.class); static { System.setProperty("red5.deployment.type", "junit"); System.setProperty("red5.root", "bin"); System.setProperty("red5.config_root", "bin/conf"); } { log.debug("Property - user.dir: {}", System.getProperty("user.dir")); log.debug("Property - red5.root: {}", System.getProperty("red5.root")); log.debug("Property - red5.config_root: {}", System.getProperty("red5.config_root")); } @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void testGlobalLookupsForVirtualHostsWithSameIP() { final Server server = new Server(); IGlobalScope g0 = new DummyGlobalScope("default"); IGlobalScope g1 = new DummyGlobalScope("default.vhost1"); IGlobalScope g2 = new DummyGlobalScope("default.vhost2"); //local server server.registerGlobal(g0); server.addMapping("localhost", "", "default"); server.addMapping("localhost", "oflaDemo", "default"); //virtual host 1 server.registerGlobal(g1); server.addMapping("", "", "default.vhost1"); server.addMapping("localhost", "oflaDemo", "default.vhost1"); server.addMapping("localhost:8088", "", "default.vhost1"); server.addMapping("127.0.0.1", "oflaDemo", "default.vhost1"); // server.addMapping("vhost1.localdomain", "", "default.vhost1"); server.addMapping("vhost1.localdomain", "oflaDemo", "default.vhost1"); //virtual host 2 server.registerGlobal(g2); server.addMapping("", "", "default.vhost2"); server.addMapping("localhost", "oflaDemo", "default.vhost2"); server.addMapping("localhost:8088", "", "default.vhost2"); server.addMapping("127.0.0.1", "oflaDemo", "default.vhost2"); // server.addMapping("vhost2.localdomain", "", "default.vhost2"); server.addMapping("vhost2.localdomain", "oflaDemo", "default.vhost2"); //assertions Assert.assertTrue(server.lookupGlobal("vhost2.localdomain", "blah") != null); Assert.assertTrue(server.lookupGlobal("vhost2.localdomain", "oflaDemo") != null); IGlobalScope tmp = server.lookupGlobal("vhost2.localdomain", "oflaDemo"); log.debug("Global 2: {}", tmp); Assert.assertTrue(tmp.getName().equals("default.vhost2")); tmp = server.lookupGlobal("vhost1.localdomain", "oflaDemo"); log.debug("Global 1: {}", tmp); Assert.assertTrue(tmp.getName().equals("default.vhost1")); } @Test public void testMultiThreaded() throws Throwable { int threads = 10; final Server server = new Server(); IGlobalScope g0 = new DummyGlobalScope("default"); //local server server.registerGlobal(g0); server.addMapping("localhost", "", "default"); server.addMapping("localhost", "oflaDemo", "default"); TestRunnable[] trs = new TestRunnable[threads]; for (int t = 0; t < threads; t++) { trs[t] = new HostAddWorker(server, t); } MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs); //kickstarts the MTTR & fires off threads long start = System.nanoTime(); mttr.runTestRunnables(); log.info("Runtime: {} ns", (System.nanoTime() - start)); for (TestRunnable r : trs) { String name = ((HostAddWorker) r).getName(); Assert.assertTrue(server.lookupGlobal(name + ".localdomain", "nonexistentscope") != null); IGlobalScope tmp = server.lookupGlobal(name + ".localdomain", "oflaDemo"); Assert.assertTrue(tmp.getName().equals("default." + name)); } } private class HostAddWorker extends TestRunnable { Server server; String name; public HostAddWorker(Server server, int index) { this.server = server; this.name = "vhost" + index; } public void runTest() throws Throwable { IGlobalScope gs = new DummyGlobalScope("default." + name); server.registerGlobal(gs); for (int i = 0; i < 6; i++) { server.addMapping("", "", "default." + name); server.addMapping("localhost", "oflaDemo", "default." + name); server.addMapping("localhost:8088", "", "default." + name); server.addMapping("127.0.0.1", "oflaDemo", "default." + name); // server.addMapping(name + ".localdomain", "", "default." + name); server.addMapping(name + ".localdomain", "oflaDemo", "default." + name); } } public String getName() { return name; } } private final static class DummyGlobalScope extends GlobalScope { public DummyGlobalScope(String name) { super(); this.name = name; } } } red5-1.0~svn4374.orig/test/org/red5/server/ClientRegistryTest.java0000644000175000017500000001104411706617130024702 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import static org.junit.Assert.fail; import junit.framework.Assert; import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner; import net.sourceforge.groboutils.junit.v1.TestRunnable; import org.junit.Test; import org.red5.server.api.IClient; import org.red5.server.exception.ClientNotFoundException; public class ClientRegistryTest { private static ClientRegistry reg; static { if (reg == null) { reg = new ClientRegistry(); } } @Test public void testNewClient() { IClient client = reg.newClient(null); Assert.assertNotNull(client); Assert.assertTrue(client.getId() != null); Assert.assertTrue(Integer.valueOf(client.getId()) >= 0); } @Test public void testAddClient() { reg.addClient(new Client(reg.nextId(), reg)); Assert.assertNotNull(reg.getClient("1")); Assert.assertTrue(reg.getClients().size() >= 1); } @Test public void testLookupClient() { IClient client = reg.lookupClient("0"); Assert.assertNotNull(client); } @Test public void testGetClient() { IClient client = reg.getClient("0"); Assert.assertNotNull(client); IClient client2 = null; try { client2 = reg.getClient("999999"); fail("An exception should occur here"); } catch (ClientNotFoundException e) { Assert.assertTrue(true); } Assert.assertNull(client2); } @Test public void testGetClientList() { ClientList clients = reg.getClientList(); int listSize = clients.size(); Assert.assertTrue(listSize > 0); System.out.println("List size: " + listSize); for (int c = 0; c < listSize; c++) { Client client = clients.get(c); System.out.println(client); Assert.assertTrue(client.getId() != null); } } @Test public void testGetClients() { //create and add 10 clients for (int c = 0; c < 10; c++) { reg.addClient(new Client(reg.nextId(), reg)); } Assert.assertNotNull(reg.getClient("2")); System.gc(); try { Thread.sleep(2000); System.gc(); } catch (InterruptedException e) { } Assert.assertTrue(reg.getClients().size() >= 10); } @Test public void testRemoveClient() { IClient client = reg.lookupClient("1"); Assert.assertNotNull(client); reg.removeClient(client); IClient client2 = null; try { client2 = reg.getClient("1"); fail("An exception should occur here"); } catch (ClientNotFoundException e) { Assert.assertTrue(true); } Assert.assertNull(client2); } // this should run last or it may affect the other tests @Test public void testLifecycle() throws Throwable { int threads = 500; TestRunnable[] trs = new TestRunnable[threads]; for (int t = 0; t < threads; t++) { trs[t] = new ClientCreatorWorker(); } Runtime rt = Runtime.getRuntime(); long startFreeMem = rt.freeMemory(); System.out.printf("Free mem: %s\n", startFreeMem); MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs); long start = System.nanoTime(); mttr.runTestRunnables(); System.out.printf("Runtime: %s ns\n", (System.nanoTime() - start)); for (TestRunnable r : trs) { IClient cli = ((ClientCreatorWorker) r).getClient(); Assert.assertTrue(cli == null); } System.gc(); Thread.sleep(1000); System.out.printf("Free mem diff at end: %s\n", Math.abs(startFreeMem - rt.freeMemory())); } private class ClientCreatorWorker extends TestRunnable { IClient client; public void runTest() throws Throwable { client = reg.newClient(null); String id = client.getId(); client.setAttribute("time", System.currentTimeMillis()); Thread.sleep(42); client.disconnect(); Thread.sleep(42); try { client = reg.getClient(id); } catch (ClientNotFoundException e) { client = null; } } public IClient getClient() { return client; } } } red5-1.0~svn4374.orig/test/org/red5/server/scope/0000755000175000017500000000000011760512565021347 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/scope/ScopeTest.java0000644000175000017500000002353011747114732024125 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.scope; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; import java.util.Set; import junit.framework.TestCase; import org.junit.Test; import org.red5.server.Context; import org.red5.server.api.IClient; import org.red5.server.api.IClientRegistry; import org.red5.server.api.IContext; import org.red5.server.api.Red5; import org.red5.server.api.TestConnection; import org.red5.server.api.scope.IScope; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; /** * This is for testing Scope issues. First created to address: * http://jira.red5.org/browse/APPSERVER-278 * * @author Paul Gregoire (mondain@gmail.com) */ @ContextConfiguration(locations = { "ScopeTest.xml" }) public class ScopeTest extends AbstractJUnit4SpringContextTests { protected static Logger log = LoggerFactory.getLogger(ScopeTest.class); private static Context context; private static WebScope appScope; private String host = "localhost"; private String appPath = "junit"; private String roomPath = "/junit/room1"; static { System.setProperty("red5.deployment.type", "junit"); System.setProperty("red5.root", "bin"); System.setProperty("red5.config_root", "bin/conf"); System.setProperty("logback.ContextSelector", "org.red5.logging.LoggingContextSelector"); } { log.debug("Property - user.dir: {}", System.getProperty("user.dir")); log.debug("Property - red5.root: {}", System.getProperty("red5.root")); log.debug("Property - red5.config_root: {}", System.getProperty("red5.config_root")); } @Test public void client() { context = (Context) applicationContext.getBean("web.context"); IClientRegistry reg = context.getClientRegistry(); IClient client = reg.newClient(null); assertTrue("client should not be null", client != null); } @Test public void connectionHandler() { context = (Context) applicationContext.getBean("web.context"); TestConnection conn = new TestConnection(host, "/", null); // add the connection to thread local Red5.setConnectionLocal(conn); // resolve root IScope scope = context.resolveScope("/"); IClientRegistry reg = context.getClientRegistry(); IClient client = reg.newClient(null); assertNotNull(client); log.debug("----------------------------------\nDump scope details"); ((Scope) scope).dump(); log.debug("----------------------------------\n"); conn.initialize(client); if (!conn.connect(scope)) { assertTrue("didnt connect", false); } else { assertTrue("should have a scope", conn.getScope() != null); conn.close(); assertTrue("should not be connected", !conn.isConnected()); } Red5.setConnectionLocal(null); } @Test public void context() { context = (Context) applicationContext.getBean("web.context"); IScope testRoom = context.resolveScope(roomPath); IContext context = testRoom.getContext(); assertTrue("context should not be null", context != null); log.debug("{}", testRoom.getContext().getResource("")); log.debug("{}", testRoom.getResource("")); log.debug("{}", testRoom.getParent().getResource("")); } @Test public void handler() { context = (Context) applicationContext.getBean("web.context"); Scope testApp = (Scope) context.resolveScope(appPath); assertTrue("should have a handler", testApp.hasHandler()); IClientRegistry reg = context.getClientRegistry(); IClient client = reg.newClient(null); TestConnection conn = new TestConnection(host, appPath, client.getId()); conn.initialize(client); Red5.setConnectionLocal(conn); assertTrue("client should not be null", client != null); log.debug("{}", client); String key = "key"; String value = "value"; client.setAttribute(key, value); assertTrue("attributes not working", client.getAttribute(key) == value); conn.connect(testApp); assertTrue("app should have 1 client", testApp.getClients().size() == 1); assertTrue("host should have 1 client", testApp.getParent() .getClients().size() == 1); conn.close(); assertTrue("app should have 0 client", testApp.getClients().size() == 0); assertTrue("host should have 0 client", testApp.getParent() .getClients().size() == 0); //client.disconnect(); Red5.setConnectionLocal(null); } @Test public void scopeResolver() { context = (Context) applicationContext.getBean("web.context"); // Global IScope global = context.getGlobalScope(); assertNotNull("global scope should be set", global); assertTrue("should be global", ScopeUtils.isGlobal(global)); log.debug("{}", global); // Test App IScope testApp = context.resolveScope(appPath); assertTrue("testApp scope not null", testApp != null); log.debug("{}", testApp); // Test Room IScope testRoom = context.resolveScope(roomPath); log.debug("{}", testRoom); // Test App Not Found try { IScope notFoundApp = context.resolveScope(appPath + "notfound"); log.debug("{}", notFoundApp); assertTrue("should have thrown an exception", false); } catch (RuntimeException e) { } } @Test public void testScope() { log.debug("testScope"); if (appScope == null) { appScope = (WebScope) applicationContext.getBean("web.scope"); log.debug("Application / web scope: {}", appScope); assertTrue(appScope.getDepth() == 1); } //Room 1 // /default/junit/room1 TestCase.assertTrue(appScope.createChildScope("room1")); IScope room1 = appScope.getScope("room1"); log.debug("Room 1: {}", room1); assertTrue(room1.getDepth() == 2); IContext rmCtx1 = room1.getContext(); log.debug("Context 1: {}", rmCtx1); //Room 2 // /default/junit/room1/room2 TestCase.assertTrue(room1.createChildScope("room2")); IScope room2 = room1.getScope("room2"); log.debug("Room 2: {}", room2); assertTrue(room2.getDepth() == 3); IContext rmCtx2 = room2.getContext(); log.debug("Context 2: {}", rmCtx2); //Room 3 // /default/junit/room1/room2/room3 TestCase.assertTrue(room2.createChildScope("room3")); IScope room3 = room2.getScope("room3"); log.debug("Room 3: {}", room3); assertTrue(room3.getDepth() == 4); IContext rmCtx3 = room3.getContext(); log.debug("Context 3: {}", rmCtx3); //Room 4 attaches at Room 1 (per bug example) // /default/junit/room1/room4 TestCase.assertTrue(room1.createChildScope("room4")); IScope room4 = room1.getScope("room4"); log.debug("Room 4: {}", room4); assertTrue(room4.getDepth() == 3); IContext rmCtx4 = room4.getContext(); log.debug("Context 4: {}", rmCtx4); //Room 5 // /default/junit/room1/room4/room5 TestCase.assertTrue(room4.createChildScope("room5")); IScope room5 = room4.getScope("room5"); log.debug("Room 5: {}", room5); assertTrue(room5.getDepth() == 4); IContext rmCtx5 = room5.getContext(); log.debug("Context 5: {}", rmCtx5); //Context ctx = new Context(); //ctx.setApplicationContext(applicationContext); //Scope scope = new DummyScope(); //scope.setName(""); //scope.setContext(ctx); } @Test public void testGetScopeNames() throws Exception { log.debug("testGetScopeNames"); if (appScope == null) { appScope = (WebScope) applicationContext.getBean("web.scope"); log.debug("Application / web scope: {}", appScope); assertTrue(appScope.getDepth() == 1); } IScope room1 = ScopeUtils.resolveScope(appScope, "/junit/room1"); log.debug("Room 1 scope: {}", room1); assertTrue(room1.getDepth() == 2); Set names = room1.getScopeNames(); log.debug("Scope: {}", names); IScope room5 = ScopeUtils.resolveScope(appScope, "/junit/room1/room4/room5"); log.debug("Room 5 scope: {}", room5); assertTrue(room5.getDepth() == 4); names = room1.getScopeNames(); log.debug("Scope: {}", names); } @Test public void testRemoveScope() throws Exception { log.debug("testRemoveScope"); if (appScope == null) { appScope = (WebScope) applicationContext.getBean("web.scope"); log.debug("Application / web scope: {}", appScope); assertTrue(appScope.getDepth() == 1); } IScope room1 = ScopeUtils.resolveScope(appScope, "/junit/room1"); IScope room4 = ScopeUtils.resolveScope(appScope, "/junit/room1/room4"); log.debug("Room 4 scope: {}", room4); assertTrue(room4.getDepth() == 3); log.debug("Room 4 child scope exists: {}", room1.hasChildScope("room4")); room1.removeChildScope(room4); log.debug("Room 4 child scope exists: {}", room1.hasChildScope("room4")); } /** * Test for Issue 73 * http://code.google.com/p/red5/issues/detail?id=73 * */ @Test public void testGetContextPath() throws Exception { log.debug("testGetContextPath"); if (appScope == null) { appScope = (WebScope) applicationContext.getBean("web.scope"); log.debug("Application / web scope: {}", appScope); assertTrue(appScope.getDepth() == 1); } log.debug("Context path: {}", appScope.getContextPath()); } } red5-1.0~svn4374.orig/test/org/red5/server/scope/ScopeTest.xml0000644000175000017500000001063411747114732024005 0ustar drazzibdrazzib file:///${user.dir}/bin/conf/red5.properties file:///${user.dir}/conf/red5.properties org.red5.server.persistence.FilePersistence red5-1.0~svn4374.orig/test/org/red5/server/api/0000755000175000017500000000000011760512565021007 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/api/stream/0000755000175000017500000000000011760512565022302 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/api/stream/support/0000755000175000017500000000000011760512565024016 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/api/stream/support/StreamUtilsTest.java0000644000175000017500000000773611706617130030004 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream.support; import static org.junit.Assert.fail; import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner; import net.sourceforge.groboutils.junit.v1.TestRunnable; import org.junit.Test; import org.red5.server.stream.NoSyncServerStream; import org.red5.server.stream.ServerStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class StreamUtilsTest { protected static Logger log = LoggerFactory.getLogger(StreamUtilsTest.class); /* ------- workers ------- */ private class SynchedWorker extends TestRunnable { private ServerStream stream; public SynchedWorker(ServerStream stream) { this.stream = stream; } public void runTest() throws Throwable { for (int i = 0; i < callsPerThread; i++) { // set item stream.addItem(SimplePlayItem.build("stream" + i)); // get item stream.getItem(1); // next item stream.nextItem(); // stop stream.stop(); } } } private class UnSynchedWorker extends TestRunnable { private NoSyncServerStream stream; public UnSynchedWorker(NoSyncServerStream stream) { this.stream = stream; } public void runTest() throws Throwable { for (int i = 0; i < callsPerThread; i++) { // set item stream.addItem(SimplePlayItem.build("stream" + i)); // get item stream.getItem(1); // next item stream.nextItem(); // stop stream.stop(); } } } private static int callsPerThread = 1000; private static int threads = 3; @Test public void testCreateServerStream() { System.out.println("Not yet implemented"); // TODO } @Test public void testForDeadlock() { // test synchronized String name = "synchronized"; ServerStream stream = new ServerStream(); stream.setName(name); stream.setPublishedName(name); // pass that instance to the MTTR TestRunnable[] synced = new TestRunnable[threads]; for (int t = 0; t < threads; t++) { synced[t] = new SynchedWorker(stream); } MultiThreadedTestRunner syncedrunner = new MultiThreadedTestRunner( synced); // kickstarts the MTTR & fires off threads long start = System.nanoTime(); try { syncedrunner.runTestRunnables(); } catch (Throwable e) { log.warn("Exception {}", e); fail(); } System.out.println("Runtime for synced runner: " + (System.nanoTime() - start) + "ns"); // test unsynchronized name = "non-synchronized"; NoSyncServerStream nstream = new NoSyncServerStream(); nstream.setName(name); nstream.setPublishedName(name); // pass that instance to the MTTR TestRunnable[] unsynced = new TestRunnable[threads]; for (int t = 0; t < threads; t++) { unsynced[t] = new UnSynchedWorker(nstream); } MultiThreadedTestRunner unsyncedrunner = new MultiThreadedTestRunner( unsynced); // kickstarts the MTTR & fires off threads start = System.nanoTime(); try { unsyncedrunner.runTestRunnables(); } catch (Throwable e) { log.warn("Exception {}", e); fail(); } System.out.println("Runtime for unsynced runner: " + (System.nanoTime() - start) + "ns"); } @Test public void testGetServerStream() { System.out.println("Not yet implemented"); // TODO } } red5-1.0~svn4374.orig/test/org/red5/server/api/BaseTest.java0000644000175000017500000000417111706617130023361 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; //http://static.springframework.org/spring/docs/2.5.x/reference/testing.html @ContextConfiguration(locations={"context.xml"}) public class BaseTest extends AbstractJUnit4SpringContextTests { protected Logger log = LoggerFactory.getLogger(BaseTest.class); static final String red5root = "dist"; static final String red5conf = red5root + "/conf"; static IContext context = null; static final String host = "localhost"; static final String path_app = "default"; static final String path_room = "default/test"; static { System.setProperty("red5.deployment.type", "junit"); // Get the full path name System.setProperty("red5.root", red5root); System.setProperty("red5.config_root", red5conf); System.setProperty("sun.lang.ClassLoader.allowArraySyntax", "true"); System.setProperty("logback.ContextSelector", "org.red5.logging.LoggingContextSelector"); } @Before public void setUp() throws Exception { context = (IContext) applicationContext.getBean("red5.context"); } @Test public void testCreation() { // Doesn't do anything except make sure initialization works } } red5-1.0~svn4374.orig/test/org/red5/server/api/context.xml0000644000175000017500000000537211747114732023223 0ustar drazzibdrazzib red5-1.0~svn4374.orig/test/org/red5/server/api/SharedObjectTest.java0000644000175000017500000000415211747114732025050 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import static junit.framework.Assert.assertTrue; import junit.framework.JUnit4TestAdapter; import org.junit.Test; import org.red5.server.api.event.IEvent; import org.red5.server.api.event.IEventListener; import org.red5.server.api.scope.IScope; import org.red5.server.api.so.ISharedObject; import org.red5.server.api.so.ISharedObjectService; import org.red5.server.so.SharedObjectService; public class SharedObjectTest extends BaseTest implements IEventListener { public static junit.framework.Test suite() { return new JUnit4TestAdapter(SharedObjectTest.class); } protected String name = "testso"; /** {@inheritDoc} */ public void notifyEvent(IEvent event) { log.debug("Event: {}", event); } @Test public void sharedObjectService() { IScope scope = context.resolveScope(path_app); ISharedObjectService service = new SharedObjectService(); assertTrue("should be empty", !service.hasSharedObject(scope, "blah")); assertTrue("create so", service.createSharedObject(scope, name, false)); assertTrue("so exists?", service.hasSharedObject(scope, name)); ISharedObject so = service.getSharedObject(scope, name); assertTrue("so not null", so != null); assertTrue("name same", so.getName().equals(name)); //assertTrue("persistent",!so.isPersistent()); so.addEventListener(this); so.setAttribute("this", "that"); } } red5-1.0~svn4374.orig/test/org/red5/server/api/ServiceTest.java0000644000175000017500000000312111706617130024101 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import static org.junit.Assert.assertTrue; import junit.framework.JUnit4TestAdapter; import org.junit.Test; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.service.EchoService; import org.red5.server.service.PendingCall; public class ServiceTest extends BaseTest { public static junit.framework.Test suite() { return new JUnit4TestAdapter(ServiceTest.class); } @Test public void simpletest() { if (context.hasBean("echoService")) { EchoService service = (EchoService) context.getBean("echoService"); IPendingServiceCall call = new PendingCall("echoService", "echoString", new Object[] { "My String" }); context.getServiceInvoker().invoke(call, service); assertTrue("result null", call.getResult() != null); } else { System.out.println("No echo service found"); assertTrue(false); } } } red5-1.0~svn4374.orig/test/org/red5/server/api/TestConnection.java0000644000175000017500000000335411747114732024615 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import org.red5.server.BaseConnection; import org.red5.server.scope.Scope; public class TestConnection extends BaseConnection { public TestConnection(String host, String path, String sessionId) { super(PERSISTENT, host, null, 0, path, sessionId, null); } /** * Return encoding (currently AMF0) * @return AMF0 encoding constant */ public Encoding getEncoding() { return Encoding.AMF0; } /** {@inheritDoc} */ public int getLastPingTime() { return 0; } /** {@inheritDoc} */ @Override public long getReadBytes() { return 0; } /** {@inheritDoc} */ @Override public long getWrittenBytes() { return 0; } /** {@inheritDoc} */ public void ping() { } public void setClient(IClient client) { this.client = client; } public void setScope(Scope scope) { this.scope = scope; } public void setContext(IContext context) { this.scope.setContext(context); } public void setBandwidth(int mbits) { } } red5-1.0~svn4374.orig/test/org/red5/server/AtomicCounterTest.java0000644000175000017500000001437211706617130024516 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import static org.junit.Assert.*; import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner; import net.sourceforge.groboutils.junit.v1.TestRunnable; import org.junit.Test; public class AtomicCounterTest { private static int threads = 3; private static int callsPerThread = 1000; private static int setSize = (threads * callsPerThread); @Test public void testIntPrimative() throws Throwable { IntCounter i = new IntCounter(); //pass that instance to the MTTR TestRunnable[] trs = new TestRunnable[threads]; for (int t = 0; t < threads; t++) { trs[t] = new IntCountWorker(i); } MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs); //kickstarts the MTTR & fires off threads long start = System.nanoTime(); mttr.runTestRunnables(); System.out.println("Runtime for int primative with synchronized: " + (System.nanoTime() - start) + "ns"); //dump our ints into a set Set intList = new HashSet(setSize); for (TestRunnable r : trs) { int[] nums = ((IntCountWorker) r).getNumbers(); for (int num : nums) { //a set will not allow duplicates intList.add(num); } } //check for dupes assertTrue(intList.size() == setSize); } @Test public void testAtomicInt() throws Throwable { AtomicIntCounter i = new AtomicIntCounter(); //pass that instance to the MTTR TestRunnable[] trs = new TestRunnable[threads]; for (int t = 0; t < threads; t++) { trs[t] = new AtomicIntCountWorker(i); } MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs); //kickstarts the MTTR & fires off threads long start = System.nanoTime(); mttr.runTestRunnables(); System.out.println("Runtime for Atomic: " + (System.nanoTime() - start) + "ns"); //dump our ints into a set Set intList = new HashSet(setSize); for (TestRunnable r : trs) { int[] nums = ((AtomicIntCountWorker) r).getNumbers(); for (int num : nums) { //a set will not allow duplicates intList.add(num); } } //check for dupes assertTrue(intList.size() == setSize); } @Test public void testVolatileIntPrimative() throws Throwable { VolatileIntCounter i = new VolatileIntCounter(); //pass that instance to the MTTR TestRunnable[] trs = new TestRunnable[threads]; for (int t = 0; t < threads; t++) { trs[t] = new VolatileIntCountWorker(i); } MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs); //kickstarts the MTTR & fires off threads long start = System.nanoTime(); mttr.runTestRunnables(); System.out.println("Runtime for volatile primative: " + (System.nanoTime() - start) + "ns"); //dump our ints into a set Set intList = new HashSet(setSize); for (TestRunnable r : trs) { int[] nums = ((VolatileIntCountWorker) r).getNumbers(); for (int num : nums) { //a set will not allow duplicates intList.add(num); } } //compare sizes.. this should be the same for volatile ints since the worker now locks assertEquals(intList.size(), setSize); } private class IntCountWorker extends TestRunnable { private IntCounter counter; private int[] nums = new int[callsPerThread]; public IntCountWorker(IntCounter counter) { this.counter = counter; } public void runTest() throws Throwable { for (int i = 0; i < callsPerThread; i++) { nums[i] = counter.next(); } } public int[] getNumbers() { return nums; } } private class AtomicIntCountWorker extends TestRunnable { private AtomicIntCounter counter; private int[] nums = new int[callsPerThread]; public AtomicIntCountWorker(AtomicIntCounter counter) { this.counter = counter; } public void runTest() throws Throwable { for (int i = 0; i < callsPerThread; i++) { nums[i] = counter.next(); } } public int[] getNumbers() { return nums; } } private class VolatileIntCountWorker extends TestRunnable { private VolatileIntCounter counter; private int[] nums = new int[callsPerThread]; public VolatileIntCountWorker(VolatileIntCounter counter) { this.counter = counter; } public void runTest() throws Throwable { for (int i = 0; i < callsPerThread; i++) { nums[i] = counter.next(); } } public int[] getNumbers() { return nums; } } /** * Simple counter using int and syncronized */ public class IntCounter { private int counter = 0; public synchronized int next() { return counter++; } public synchronized int getCurrent() { return counter; } } /** * Simple counter using AtomicInteger */ public class AtomicIntCounter { private AtomicInteger counter = new AtomicInteger(); public int next() { return counter.incrementAndGet(); } public int getCurrent() { return counter.get(); } } /** * Simple counter using only a primative int and volatile */ public class VolatileIntCounter { // Note: volatile just ensures that you're always READING the lastest // copy, but ++ is still not atomic, so this MUST be synced to work. private volatile int counter = 0; public int next() { int retval = 0; synchronized(this) { retval = counter; counter++; } return retval; } public int getCurrent() { // always an atomic read return counter; } } } red5-1.0~svn4374.orig/test/org/red5/server/DummyClientRegistry.java0000644000175000017500000000407311706617130025062 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.red5.io.utils.RandomGUID; import org.red5.server.api.IClient; import org.red5.server.exception.ClientNotFoundException; import org.red5.server.exception.ClientRejectedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Simple registry for unit tests * * @author Paul Gregoire (mondain@gmail.com) */ public final class DummyClientRegistry extends ClientRegistry { protected static Logger log = LoggerFactory.getLogger(DummyClientRegistry.class); private ConcurrentMap clients = new ConcurrentHashMap(); @Override public boolean hasClient(String id) { return clients.containsKey(id); } @Override public IClient lookupClient(String id) throws ClientNotFoundException { return clients.get(id); } @Override public IClient newClient(Object[] params) throws ClientNotFoundException, ClientRejectedException { String id = null; if (params != null) { id = params[0].toString(); } else { RandomGUID idGen = new RandomGUID(); id = idGen.toString(); } IClient client = new DummyClient(id, this); log.debug("New client: {}", client); //add it clients.put(client.getId(), client); return client; } }red5-1.0~svn4374.orig/test/org/red5/server/script/0000755000175000017500000000000011760512565021542 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/server/script/ScriptEngineTest.java0000644000175000017500000002132011706617130025627 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.script; import static org.junit.Assert.*; import java.util.HashMap; import java.util.Map; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Simple script engine tests. Some of the hello world scripts found here: * http://www.roesler-ac.de/wolfram/hello.htm * * @author paul.gregoire */ public class ScriptEngineTest { private static final Logger log = LoggerFactory.getLogger(ScriptEngineTest.class); // ScriptEngine manager private static boolean java15; private static ScriptEngineManager mgr; public ScriptEngineTest() { String javaVersion = System.getProperty("java.version"); String javaMajorRev = javaVersion.substring(0, 3); if (javaVersion != null && javaMajorRev.compareTo("1.5") == 0) { //should disable tests java15 = true; } else { java15 = false; mgr = new ScriptEngineManager(); } } // Javascript @Test public void testJavascriptHelloWorld() { if (java15) { return; } ScriptEngine jsEngine = null; for (ScriptEngineFactory factory : mgr.getEngineFactories()) { if (factory.getEngineName().toLowerCase().matches(".*(rhino|javascript|ecma).*")) { jsEngine = factory.getScriptEngine(); } } if (null == jsEngine) { log.error("Javascript is not supported in this build"); } try { jsEngine.eval("print('Javascript - Hello, world!\\n')"); } catch (Throwable ex) { System.err.println("Get by name failed for: javascript"); } } // Ruby @Test @Ignore public void testRubyHelloWorld() { if (java15) { return; } ScriptEngine rbEngine = mgr.getEngineByName("ruby"); if (rbEngine == null) { rbEngine = mgr.getEngineByExtension("rb"); } try { rbEngine.eval("puts 'Ruby - Hello, world!'"); } catch (Exception ex) { ex.printStackTrace(); assertFalse(true); } } // Python @Test @Ignore // Python support seems to not be in tree anymore; aclarke 2008-10-01 public void testPythonHelloWorld() { if (java15) { return; } ScriptEngine pyEngine = mgr.getEngineByName("python"); try { pyEngine.eval("print \"Python - Hello, world!\""); } catch (Exception ex) { //ex.printStackTrace(); fail("could not start Python"); } } // Groovy @Test public void testGroovyHelloWorld() { if (java15) { return; } ScriptEngine gvyEngine = mgr.getEngineByName("groovy"); try { gvyEngine.eval("println \"Groovy - Hello, world!\""); } catch (Exception ex) { //ex.printStackTrace(); assertFalse(true); } } // Judoscript // @Test // public void testJudoscriptHelloWorld() { // ScriptEngine jdEngine = mgr.getEngineByName("judo"); // try { // jdEngine.eval(". \'Judoscript - Hello World\';"); // } catch (Exception ex) { // //ex.printStackTrace(); // assertFalse(true); // } // } // Haskell // @Test // public void testHaskellHelloWorld() // { // ScriptEngine hkEngine = mgr.getEngineByName("jaskell"); // try // { // StringBuilder sb = new StringBuilder(); // sb.append("module Hello where "); // sb.append("hello::String "); // sb.append("hello = 'Haskell - Hello World!'"); // hkEngine.eval(sb.toString()); // } // catch (Exception ex) // { // //ex.printStackTrace(); // assertFalse(true); // } // } // Tcl // @Test // public void testTclHelloWorld() { // ScriptEngine tEngine = mgr.getEngineByName("tcl"); // try { // StringBuilder sb = new StringBuilder(); // sb.append("#!/usr/local/bin/tclsh\n"); // sb.append("puts \"Tcl - Hello World!\""); // tEngine.eval(sb.toString()); // } catch (Exception ex) { // //ex.printStackTrace(); // assertFalse(true); // } // } // Awk // @Test // public void testAwkHelloWorld() // { // ScriptEngine aEngine = mgr.getEngineByName("awk"); // try // { // StringBuilder sb = new StringBuilder(); // sb.append("BEGIN { print 'Awk - Hello World!' } END"); // aEngine.eval(sb.toString()); // } // catch (Exception ex) // { // //ex.printStackTrace(); // assertFalse(true); // } // } // E4X // @Test // public void testE4XHelloWorld() { // ScriptEngine eEngine = mgr.getEngineByName("rhino"); // try { // //Compilable compiler = (Compilable) eEngine; // //CompiledScript script = compiler.compile("var d = new XML('HelloWorld!');print(d..item);"); // //Namespace ns = eEngine.createNamespace(); // //ns.put('d', "new XML('HelloWorld!');"); // //System.out.println("E4X - " + script.eval(ns)); // eEngine // .eval("var d = new XML('HelloWorld!');print('E4X - ' + d..item);"); // } catch (Exception ex) { // //ex.printStackTrace(); // assertFalse(true); // } // } // PHP // @Test // public void testPHPHelloWorld() // { // //have to add php lib to java env // //java.library.path // //System.setProperty("java.library.path", "C:\\PHP;" + // System.getProperty("java.library.path")); // ScriptEngine pEngine = mgr.getEngineByName("php"); // try // { // pEngine.eval(""); // } // catch (Exception ex) // { // //ex.printStackTrace(); // assertFalse(true); // } // } // @Test // public void testE4X() // { // // Javascript // ScriptEngine jsEngine = mgr.getEngineByName("rhino"); // try // { // System.out.println("Engine: " + jsEngine.getClass().getName()); // jsEngine.eval(new FileReader("samples/E4X/e4x_example.js")); // } // catch (Exception ex) // { // //ex.printStackTrace(); // assertFalse(true); // } // } // @Test // public void testJavascriptApplication() { // ScriptEngine jsEngine = mgr.getEngineByName("rhino"); // try { // // jsEngine.eval(new FileReader("samples/application.js")); // jsEngine.eval(new FileReader("samples/application2.js")); // } catch (Exception ex) { // //ex.printStackTrace(); // assertFalse(true); // } // } // // @Test // public void testRubyApplication() { // ScriptEngine rbEngine = mgr.getEngineByName("ruby"); // try { // rbEngine.eval(new FileReader("samples/application.rb")); // } catch (Exception ex) { // //ex.printStackTrace(); // assertFalse(true); // } // } // // @Test // public void testGroovyApplication() { // ScriptEngine gvyEngine = mgr.getEngineByName("groovy"); // try { // gvyEngine.eval(new FileReader("samples/application.groovy")); // // gvyEngine.eval("def ap = new Application();println // // ap.toString();"); // } catch (Exception ex) { // //ex.printStackTrace(); // assertFalse(true); // } // } @Test public void testEngines() { if (java15) return; Map engineFactories = new HashMap(7); //List factories = mgr.getEngineFactories(); //jdk6 //ScriptEngineFactory[] factories = mgr.getEngineFactories(); //jdk5 for (ScriptEngineFactory factory : mgr.getEngineFactories()) { try { System.out.println("\n--------------------------------------------------------------"); String engName = factory.getEngineName(); String engVersion = factory.getEngineVersion(); String langName = factory.getLanguageName(); String langVersion = factory.getLanguageVersion(); System.out.printf("Script Engine: %s (%s) Language: %s (%s)", engName, engVersion, langName, langVersion); engineFactories.put(engName, factory); System.out.print("\nEngine Alias(es):"); for (String name : factory.getNames()) { System.out.printf("%s ", name); } System.out.printf("\nExtension: "); for (String name : factory.getExtensions()) { System.out.printf("%s ", name); } } catch (Throwable e) { log.error("{}", e); } } } } red5-1.0~svn4374.orig/test/org/red5/test/0000755000175000017500000000000011760512565017707 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/test/selftest/0000755000175000017500000000000011760512565021540 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/test/selftest/ExternalizableClass.java0000644000175000017500000000523711706617130026343 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.test.selftest; import org.red5.io.amf3.IDataInput; import org.red5.io.amf3.IDataOutput; import org.red5.io.amf3.IExternalizable; public class ExternalizableClass implements IExternalizable { private boolean[] a = new boolean[2]; private byte[] b = new byte[5]; private double c; private float d; private int[] e = new int[3]; private String[] f = new String[2]; private Object ob; private short[] g = new short[3]; private long[] h = new long[2]; private String i; private String j; public void readExternal(IDataInput input) { a[0] = input.readBoolean(); a[1] = input.readBoolean(); b[0] = input.readByte(); b[1] = input.readByte(); b[2] = input.readByte(); b[3] = input.readByte(); b[4] = input.readByte(); // TODO: input.readBytes c = input.readDouble(); d = input.readFloat(); e[0] = input.readInt(); e[1] = input.readInt(); e[2] = input.readInt(); f[0] = input.readMultiByte(7, "iso-8859-1"); f[1] = input.readMultiByte(14, "utf-8"); ob = input.readObject(); g[0] = input.readShort(); g[1] = input.readShort(); g[2] = input.readShort(); h[0] = input.readUnsignedInt(); h[1] = input.readUnsignedInt(); i = input.readUTF(); j = input.readUTFBytes(12); } public void writeExternal(IDataOutput output) { output.writeBoolean(a[0]); output.writeBoolean(a[1]); output.writeByte(b[0]); output.writeByte(b[1]); output.writeByte(b[2]); output.writeByte(b[3]); output.writeByte(b[4]); output.writeDouble(c); output.writeFloat(d); output.writeInt(e[0]); output.writeInt(e[1]); output.writeInt(e[2]); output.writeMultiByte(f[0], "iso-8859-1"); output.writeMultiByte(f[1], "utf-8"); output.writeObject(ob); output.writeShort(g[0]); output.writeShort(g[1]); output.writeShort(g[2]); output.writeUnsignedInt(h[0]); output.writeUnsignedInt(h[1]); output.writeUTF(i); output.writeUTFBytes(j); } } red5-1.0~svn4374.orig/test/org/red5/test/selftest/RemoteClass.java0000644000175000017500000000153011706617130024615 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.test.selftest; public class RemoteClass { public String attribute1; public int attribute2; } red5-1.0~svn4374.orig/test/org/red5/test/selftest/EchoApplication.java0000644000175000017500000000234511706617130025443 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.test.selftest; import org.red5.server.adapter.MultiThreadedApplicationAdapter; /** * Echo sample application. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class EchoApplication extends MultiThreadedApplicationAdapter { /** * Return passed parameter back to client. * * @param param Parameter to return. * @return Passed parameter. */ public Object echo(Object param) { return param; } } red5-1.0~svn4374.orig/test/org/red5/test/Foo.java0000644000175000017500000000076111614615534021277 0ustar drazzibdrazzibpackage org.red5.test; import org.red5.io.amf3.IDataInput; import org.red5.io.amf3.IDataOutput; import org.red5.io.amf3.IExternalizable; /** * Used for testing AMF3 Vectors * * @author Paul */ public class Foo implements IExternalizable { public void readExternal(IDataInput input) { } public void writeExternal(IDataOutput output) { } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "Foo[]"; } }red5-1.0~svn4374.orig/test/org/red5/test/Foo3.java0000644000175000017500000000127111614615534021357 0ustar drazzibdrazzibpackage org.red5.test; import org.red5.io.amf3.IDataInput; import org.red5.io.amf3.IDataOutput; import org.red5.io.amf3.IExternalizable; /** * Used for testing AMF3 Vectors * * @author Paul */ public class Foo3 implements IExternalizable { private int foo; public void setFoo3(int foo) { this.foo = foo; } public int getFoo() { return foo; } public void readExternal(IDataInput input) { this.foo = input.readInt(); } public void writeExternal(IDataOutput output) { output.writeInt(foo); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "Foo3 [foo=" + foo + "]"; } }red5-1.0~svn4374.orig/test/org/red5/logging/0000755000175000017500000000000011760512565020356 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/org/red5/logging/Red5LoggerFactoryTest.java0000644000175000017500000000304611706617130025345 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.logging; import static org.junit.Assert.*; import org.junit.Test; import org.slf4j.Logger; /** * @author aclarke * */ public class Red5LoggerFactoryTest { /** * Test method for {@link org.red5.logging.Red5LoggerFactory#getLogger(java.lang.Class)}. */ @Test public void testGetLoggerClass() { final Logger log = Red5LoggerFactory.getLogger(this.getClass()); assertNotNull(log); } /** * Test method for {@link org.red5.logging.Red5LoggerFactory#getLogger(java.lang.Class, java.lang.String)}. * * This test will fail before http://jira.red5.org/browse/APPSERVER-341 is fixed * with a NullPointerException */ @Test public void testGetLoggerClassString() { final Logger log = Red5LoggerFactory.getLogger(this.getClass(), "doesnotexist"); assertNotNull("should fall back to default logger", log); } } red5-1.0~svn4374.orig/test/www/0000755000175000017500000000000011760512560016121 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/www/streams/0000755000175000017500000000000011760512565017604 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/www/WEB-INF/0000755000175000017500000000000011760512560017150 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/www/WEB-INF/web.xml0000644000175000017500000000232011134224473020442 0ustar drazzibdrazzib selftest Self Test webAppRootKey /selftest org.red5.logging.ContextLoggingListener LoggerContextFilter org.red5.logging.LoggerContextFilter LoggerContextFilter /* gateway org.red5.server.net.servlet.AMFGatewayServlet 1 gateway /gateway red5-1.0~svn4374.orig/test/www/WEB-INF/red5-web.properties0000644000175000017500000000006511071236610022673 0ustar drazzibdrazzibwebapp.contextPath=/selftest webapp.virtualHosts=* red5-1.0~svn4374.orig/test/www/WEB-INF/red5-web.xml0000644000175000017500000000360011130726707021304 0ustar drazzibdrazzib red5-1.0~svn4374.orig/test/scripts/0000755000175000017500000000000011760512565016771 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/scripts/harvest-flashlog0000755000175000017500000000657411140361117022167 0ustar drazzibdrazzib#!/bin/sh # Copyright (C) 2008 Vlideshow Inc., All Rights Reservered # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # This script finds the flashlog for this particular OS, and then moves it to the given # directory, changing the name to include a timestamp in the process # # Log file locations assume Flash Player 9 or greater, and as of 2008-08-14 are based # on the documentation found here: # http://livedocs.adobe.com/flex/3/html/index.html?content=Part2_DevApps_1.html flash_check_cfg() { case "$OS" in cygwin6) FLASH_CFG_FILE=`cygpath "$HOMEDRIVE$HOMEPATH"`/mm.cfg ;; cygwin5) FLASH_CFG_FILE=`cygpath "$HOMEDRIVE$HOMEPATH"`/mm.cfg ;; darwin) FLASH_CFG_FILE=/Library/Application\ Support/Macromedia/mm.cfg ;; linux) FLASH_CFG_FILE=$HOME/mm.cfg ;; *) echo "Do not know flash config file location for the OS: $OS" exit 1; ;; esac echo "Flash Config File path: $FLASH_CFG_FILE"; if [ ! -r "$FLASH_CFG_FILE" ]; then echo "Could not read file: $FLASH_CFG_FILE"; exit 1; fi } flash_check_logfile() { case "$OS" in cygwin6) FLASH_LOG_FILE=`cygpath "$HOMEDRIVE$HOMEPATH\\AppData\\Roaming\\Macromedia\\Flash Player\\Logs\\flashlog.txt"` ;; cygwin5) FLASH_LOG_FILE=`cygpath "$HOMEDRIVE$HOMEPATH\\Application Data\\Macromedia\\Flash Player\\Logs\\flashlog.txt"` ;; darwin) FLASH_LOG_FILE=$HOME/Library/Preferences/Macromedia/Flash\ Player/Logs/flashlog.txt ;; linux) FLASH_LOG_FILE=$HOME/.macromedia/Flash_Player/Logs/flashlog.txt ;; *) echo "Do not know flash log file location for the OS: $OS" exit 1; ;; esac echo "Flash Log File path: $FLASH_LOG_FILE"; if [ ! -r "$FLASH_LOG_FILE" ]; then echo "Could not read file: $FLASH_LOG_FILE"; exit 1; fi } flash_copy_logfile() { echo "Copying \"$FLASH_LOG_FILE\" to \"$OUTPUT_FILE\"" cp -f "$FLASH_LOG_FILE" "$OUTPUT_FILE" } check_args() { USAGE_MSG="Usage: $2 [output_dir] [file_suffix]" if [ $1 -gt 2 ]; then echo $USAGE_MSG exit 1 fi OUTPUT_TS=`date -u +"%Y%m%d-%H%I%M%S.$$"` OUTPUT_DIR="$3" OUTPUT_FILENAME="$4" if [ -z "$OUTPUT_DIR" ]; then OUTPUT_DIR="." echo "Defaulting output dir to: " $OUTPUT_DIR fi if [ -z "$OUTPUT_FILENAME" ]; then OUTPUT_FILENAME="flashlog-$OUTPUT_TS.txt" echo "Defaulting log file suffix to: " $OUTPUT_FILENAME fi if [ \( ! -d "$OUTPUT_DIR" \) -o \( ! -w "$OUTPUT_DIR" \) ]; then echo "Cannot write to output directory: " $OUTPUT_DIR exit 1 fi OUTPUT_FILE="$OUTPUT_DIR/$OUTPUT_FILENAME" } . shell-tools.sh check_args "$#" "$0" "$1" "$2" detect_os flash_check_cfg flash_check_logfile flash_copy_logfile red5-1.0~svn4374.orig/test/scripts/cygwin6/0000755000175000017500000000000011760512565020357 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/scripts/cygwin6/flash-player0000755000175000017500000000155411140361117022664 0ustar drazzibdrazzib#!/bin/sh # Copyright (C) Vlideshow Inc., All Rights Reserved # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # exec flashplayer-debug $* red5-1.0~svn4374.orig/test/scripts/cygwin6/take-screenshot0000755000175000017500000000167411140361117023377 0ustar drazzibdrazzib#!/bin/sh # Copyright (C) Vlideshow Inc., All Rights Reserved # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # OUTFILE=$1 # Put the command here that will take a screen shot of the desktop # and output to $OUTFILE red5-1.0~svn4374.orig/test/scripts/red50000755000175000017500000000672711614615534017570 0ustar drazzibdrazzib#!/bin/bash # Copyright (C) 2008 Vlideshow Inc., All Rights Reservered # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Script to start up and shutdown red5 in the background; used by automated build # tests . shell-tools.sh init_env() { if [ ! -x "$RED5_HOME/$1" ]; then echo `date` "Unable to locate $1; make sure \$RED5_HOME is set and pointed to a valid red5 build" exit 1 fi cd "$RED5_HOME" process_status $? "cd $RED5_HOME" } setup_tomcat() { # create the plugins directory mkdir -p "$RED5_HOME/plugins" cd "$RED5_HOME/plugins" # get tomcat plugin wget http://red5.googlecode.com/svn/repository/red5/tomcatplugin-1.0.jar wget http://red5.googlecode.com/svn/repository/tomcat/catalina-6.0.26.jar wget http://red5.googlecode.com/svn/repository/tomcat/jasper-6.0.26.jar wget http://red5.googlecode.com/svn/repository/tomcat/jasper-jdt-6.0.26.jar wget http://red5.googlecode.com/svn/repository/tomcat/jasper-el-6.0.26.jar wget http://red5.googlecode.com/svn/repository/tomcat/tomcat-coyote-6.0.26.jar wget http://red5.googlecode.com/svn/repository/tomcat-juli-slf4j-1.5.0.jar # replace default jee container file exec "${JAVA_HOME}/bin/jar" xf tomcatplugin-1.0.jar jee-container.xml cp -f jee-container.xml "$RED5_HOME/conf" } red5_start() { echo -n `date` "Starting Red5" init_env "red5.sh" # setup_tomcat echo `date` "START to shutdown Red5" 1>log/stdout.log # red5.sh will read JAVA_OPTS; we increase the red5 jvm memory here export JAVA_OPTS="-Xms64M -Xmx256M" ./red5.sh 1>>log/stdout.log 2>>log/stderr.log & echo -n " ($!)..." ensure_background_process_running $! 30 "Red5 process didn't start" sleep 30 grep -q "Bootstrap complete" log/stdout.log process_status $? "check_startup not done in 30 seconds" grep -q " at .*\(.*\)$" log/stdout.log if [ $? -eq 0 ]; then echo "" echo -n `date` "Possible exception detected upon red5 start-up; you might want to check" fi echo "" } red5_stop() { RED5_TIMESTAMP=`date -u +"%Y%m%d-%H%I%M%S.$$"` echo -n `date` "Stopping Red5..." init_env "red5-shutdown.sh" echo `date` "START to shutdown Red5" 1>log/shutdown-stdout.log ./red5-shutdown.sh 1>>log/shutdown-stdout.log 2>>log/shutdown-stderr.log if [ -r log/stdout.log ]; then mv -f log/stdout.log log/stdout-$RED5_TIMESTAMP.log fi if [ -r log/stderr.log ]; then mv -f log/stderr.log log/stderr-$RED5_TIMESTAMP.log fi echo `date` "FINISH attempt to shutdown Red5" 1>>log/shutdown-stdout.log echo "" } case "$1" in 'start') red5_start process_status $? "red5_start" ;; 'stop') red5_stop process_status $? "red5_stop" ;; 'restart') red5_stop red5_start process_status $? "red5_restart" ;; *) echo "Usage: $0 { start | stop | restart }" exit 1 ;; esac exit 0 red5-1.0~svn4374.orig/test/scripts/cygwin5/0000755000175000017500000000000011760512565020356 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/scripts/cygwin5/flash-player0000755000175000017500000000155211140361117022661 0ustar drazzibdrazzib#!/bin/sh # Copyright (C) 2008 Vlideshow Inc., All Rights Reserved # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA flashplayer-debug $* red5-1.0~svn4374.orig/test/scripts/cygwin5/take-screenshot0000755000175000017500000000167711140361117023401 0ustar drazzibdrazzib#!/bin/sh # Copyright (C) 2008 Vlideshow Inc., All Rights Reserved # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA OUTFILE=$1 # Put the command here that will take a screen shot of the desktop # and output to $OUTFILE red5-1.0~svn4374.orig/test/scripts/linux/0000755000175000017500000000000011760512565020130 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/scripts/linux/readme.txt0000644000175000017500000000313011077132334022114 0ustar drazzibdrazzibCopyright (C) Vlideshow Inc., All Rights Reserved Some of the headless things we do actually require an X server (e.g. flash) to actually work; they don't like having no screen. So, before this leaves my head, here's what you have to do for that: *) First, make sure you can run all the tests in a non-headless mode -) Build all the necessary red5 applications -) Make sure $VLIDESHOW_HOME is defined -) Make sure $VLIDESHOW_HOME/share/vlideshow/scripts is in your path -) Make sure red5 is started by calling: red5 restart -) Make sure you have flash installed, and a debug player in your path as flashplayer-debug -) Make sure you have a mm.cfg file configured for flash -) Build the flash application you want to tests -) Run the tests once (ant run-tests), and configure the tests to always have access to your camera/mic. Check the remember checkbox to on (this is needed to make sure we can run camera/mic tests without having a user give permission on every run). -) Go to the Adobe Global Flash Security settings web page, and make sure Flash trusts any applications that are in $HOME or below (this is needed to make sure the flash player can exit in headless mode). *) Make sure you have Xvfb installed *) Make sure you have enabled (via xauth) Xvfb to create display :1 This command works assuming you've once logged onto an actual X Server on display :0 on this machine: xauth add "$(/bin/hostname)/unix:1" MIT-MAGIC-COOKIE-1 \ $( xauth list | egrep "$(/bin/hostname)/unix:0" | awk '{print $3}' ) *) Now, try "ant run-tests-unattended" red5-1.0~svn4374.orig/test/scripts/linux/flash-player0000755000175000017500000000160311140361117022430 0ustar drazzibdrazzib#!/bin/sh # Copyright (C) Vlideshow Inc., All Rights Reserved # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA exec $FLEX_HOME/runtimes/player/lnx/flashplayer $* red5-1.0~svn4374.orig/test/scripts/linux/take-screenshot0000755000175000017500000000030311140361117023134 0ustar drazzibdrazzib#!/bin/sh # Copyright (C) Vlideshow Inc., All Rights Reserved OUTFILE=$1 # Put the command here that will take a screen shot of the desktop # and output to $OUTFILE import -window root $OUTFILE red5-1.0~svn4374.orig/test/scripts/linux/multitest0000755000175000017500000000052011140361117022070 0ustar drazzibdrazzib#!/bin/bash # Copyright (C) Vlideshow Inc., All Rights Reserved usage0="USAGE:" usage1="$0 " if [ "$1" = "" ] then echo ERROR: missing test count echo echo " " $usage0 echo " " $usage1 echo exit 1 fi ant compile-tests for ((i=0; i < $1; ++i)); do flash-player bin/test/fity.swf ; done red5-1.0~svn4374.orig/test/scripts/call-os-specific0000755000175000017500000000216411140361117022022 0ustar drazzibdrazzib#!/bin/sh # # Copyright (C) 2008 Vlideshow Inc., All Rights Reservered # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # author: trebor # created: 14 august 2008 # # calls an os specific version of the script and parameters passed on # the command line to this script # identify the os . shell-tools.sh detect_os # construct full path to os specific script and call it exec `dirname $0`/$OS/$* red5-1.0~svn4374.orig/test/scripts/flash-player0000755000175000017500000000173311140361117021275 0ustar drazzibdrazzib#!/bin/sh # Copyright (C) 2008 Vlideshow Inc., All Rights Reservered # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # author: trebor # created: 14 august 2008 # # calls an os specific flash player script exec call-os-specific flash-player $* red5-1.0~svn4374.orig/test/scripts/darwin/0000755000175000017500000000000011760512565020255 5ustar drazzibdrazzibred5-1.0~svn4374.orig/test/scripts/darwin/flash-player0000755000175000017500000000166511140361117022565 0ustar drazzibdrazzib#!/bin/bash # Copyright (C) 2008 Vlideshow Inc., All Rights Reserved # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA exec open -a "$FLEX_HOME/runtimes/player/mac/Flash Player.app/Contents/MacOS/Flash Player" $* red5-1.0~svn4374.orig/test/scripts/darwin/take-screenshot0000755000175000017500000000170111140361117023264 0ustar drazzibdrazzib#!/bin/sh # Copyright (C) 2008 Vlideshow Inc., All Rights Reserved # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # OUTFILE=$1 # Put the command here that will take a screen shot of the desktop # and output to $OUTFILE red5-1.0~svn4374.orig/test/scripts/darwin/multitest0000755000175000017500000000215111140361117022217 0ustar drazzibdrazzib#!/bin/bash # Copyright (C) 2008 Vlideshow Inc., All Rights Reserved # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # usage0="USAGE:" usage1="$0 " if [ "$1" = "" ] then echo ERROR: missing test count echo echo " " $usage0 echo " " $usage1 echo exit 1 fi ant compile-tests for ((i=0; i < $1; ++i)); do flash-player bin/test/fity.swf ; done red5-1.0~svn4374.orig/test/scripts/take-screenshot0000755000175000017500000000173511140361117022007 0ustar drazzibdrazzib#!/bin/sh # Copyright (C) 2008 Vlideshow Inc., All Rights Reservered # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # author: aclarke # created: 8-OCT-08 # # calls an os specific program to take a screen shot call-os-specific take-screenshot $* red5-1.0~svn4374.orig/test/scripts/red5-flash-player-headless0000755000175000017500000000631411140361117023720 0ustar drazzibdrazzib#!/bin/bash # Copyright (C) 2008 Vlideshow Inc., All Rights Reservered # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # This script starts red5, runs the flash tests, stops red5, harvests # logs, and then exits with an error if the flash tests actually failed . shell-tools.sh echo `date` "Using Display: $DISPLAY" # Clear the red5 log if [ -e output ]; then if [ ! -d output ]; then echo `date` "output is not a directory; failing harvest" exit 1 fi else mkdir -p output mkdir -p output/red5 fi red5 stop if [ -d $RED5_HOME/log ]; then rm -rf $RED5_HOME/log/* fi red5 start process_status $? "red5 failed to start" # Run the flash-player flash-player $* & FLASH_PID=$! echo -n `date` "Checking if flashplayer started with PID: $FLASH_PID ..." ensure_background_process_running $! 30 "Flash player did not start" echo "done" if [ -z "$HEADLESS_MAX_RUN_SECONDS" ]; then # set a 10 min default HEADLESS_MAX_RUN_SECONDS=600 fi START_TIME=`date +"%s"` NOW_TIME=$START_TIME echo -n `date` "Running flash tests (start:$START_TIME): " while ((($NOW_TIME-$START_TIME)<=$HEADLESS_MAX_RUN_SECONDS)); do echo -n "." # First take a snap shot take-screenshot output/screenshot-$NOW_TIME.png # Harvest flash log so far harvest-flashlog output flashlog-$$.txt >/dev/null 2>&1 # Check if flash is still running ps -ef | grep -v grep | grep -q $FLASH_PID if [ $? -eq 0 ]; then # Flash is still running tail output/flashlog-$$.txt | grep -q "setting exitVal to: [0-9]* and exiting the player" if [ $? -eq 0 ]; then # Flash has actually finished; we should exit break; fi else # Flash has exited; leave the loop and check for doneness break; fi # Sleep for a little sleep 5 NOW_TIME=`date +"%s"` done echo "done (end:$NOW_TIME)" ps -ef | grep -v grep | grep -q $FLASH_PID if [ $? -eq 0 ]; then echo "Killing Zombie Flash Process: $FLASH_PID"; # Take one last screenshot before we kill it take-screenshot output/screenshot-$NOW_TIME.png kill -9 $FLASH_PID fi wait $FLASH_PID # Final harvest harvest-flashlog output flashlog-$$.txt >/dev/null 2>&1 red5 stop # Harvest the logs cp -r $RED5_HOME/log output/red5 # Now, check the actual status tail output/flashlog-$$.txt | grep -q "setting exitVal to: 0 and exiting the player" if [ $? -eq 0 ]; then cat output/flashlog-$$.txt echo `date` "All flash tests exited successfully" FLASH_STATUS=0 else cat output/flashlog-$$.txt echo `date` "Flash tests failed" FLASH_STATUS=255 fi exit $FLASH_STATUS red5-1.0~svn4374.orig/test/scripts/multitest0000755000175000017500000000172311140361117020737 0ustar drazzibdrazzib#!/bin/sh # Copyright (C) 2008 Vlideshow Inc., All Rights Reservered # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # author: trebor # created: 14 august 2008 # # calls an os specific flash player script call-os-specific multitest $* red5-1.0~svn4374.orig/test/scripts/shell-tools.sh0000755000175000017500000000460411140361117021564 0ustar drazzibdrazzib#!/bin/sh # Copyright (C) 2008 Vlideshow Inc., All Rights Reservered # http://www.theyard.net/ or http://www.vlideshow.com/ # # This library is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any later # version. # # This library is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with this library; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # author: trebor # author: aclarke # created: 14 august 2008 # # Contains a bunch of different shell tools that are used in # oru scripts # # detect the current os, adjust and simpify the name, and set the $OS # variable to that value # # to use put something like this in your code: # # . shell-tools.sh # detect_os # echo $OS detect_os() { OS=`uname` case "$OS" in CYGWIN_NT-6*) OS=cygwin6 ;; CYGWIN_NT-5*) OS=cygwin5 ;; Darwin*) OS=darwin ;; Linux*) OS=linux ;; *) echo "Could not detect OS" exit 1 ;; esac } # Checks the status passed in, and if not 0, outputs the # message in the second argument and exits # # To use do the following # $ command_i_want_to_check # $ process_status $? "command_i_want_to_check failed with code: $?" process_status() { if [ $1 -ne 0 ]; then echo "process failed: $2" exit -1; fi } # Checks if the passed in PID is running as a background process # If not, it exits the process, first displaying the message given # # To use: # $ background_process & # $ ensure_background_process_running $! 5 "background_process doesn't appear to be running" ensure_background_process_running() { _EBPS_PID=$1 _EBPS_SLEEPTIMEOUT=$2 _EBPS_FAILUREMSG=$3 sleep $_EBPS_SLEEPTIMEOUT ps -ef | grep -v grep | grep -q $_EBPS_PID if [ $? -ne 0 ]; then echo $_EBPS_FAILUREMSG # Just in case, send a kill signal /bin/kill $_EBPS_FAILUREMSG >/dev/null 2>&1 # And reap the failed child wait $_EBPS_PID exit 1 fi } red5-1.0~svn4374.orig/test/fixtures/0000755000175000017500000000000011760512566017154 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/0000755000175000017500000000000011760512571015107 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/META-INF/0000755000175000017500000000000011760512571016247 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/META-INF/services/0000755000175000017500000000000011760512571020072 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/META-INF/services/javax.script.ScriptEngineFactory0000644000175000017500000000041110743765347026361 0ustar drazzibdrazzib#list of ScriptEngineFactory's in this package #org.red5.server.script.rhino.RhinoScriptEngineFactory #javascript com.sun.script.jruby.JRubyScriptEngineFactory com.sun.script.jython.JythonScriptEngineFactory com.sun.script.groovy.GroovyScriptEngineFactory red5-1.0~svn4374.orig/src/org/0000755000175000017500000000000011760512575015702 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/0000755000175000017500000000000011760512575016541 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/spring/0000755000175000017500000000000011760512571020037 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/spring/ExtendedPropertyPlaceholderConfigurer.java0000644000175000017500000001303011706617130030370 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.spring; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; /** * An extension of {@link PropertyPlaceholderConfigurer}. Provides runtime * additions of properties and wildcard location lookups. * * Properties can be added at runtime by using the static * {@link #addGlobalProperty} before* the bean definition is instantiated in the * ApplicationContext. A property added by {@link #addGlobalProperty} will get * merged into properties specified by the bean definition, overriding keys that * overlap. * * wildcard locations can be used instead of locations, if both are declared the * last will override. Wildcard locations are handled by * {@link #setWildcardLocations(String[])}, using * {@link PathMatchingResourcePatternResolver} for matching locations. For * wildcard locations that matches multiple Properties files, they are merged in * by alphabetical filename order. * * @author Michael Guymon (michael.guymon@gmail.com) * */ public class ExtendedPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer { private static Logger logger = LoggerFactory .getLogger(ExtendedPropertyPlaceholderConfigurer.class); private static Properties globalPlaceholderProperties = new Properties(); private Properties mergedProperties; @Override protected void processProperties( ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException { props.putAll(copyOfGlobalProperties()); logger.debug("Placeholder props: {}", props.toString()); this.mergedProperties = props; super.processProperties(beanFactoryToProcess, props); } /** * Merged {@link Properties} created by {@link #processProperties} * * @return {@link Properties} */ public Properties getMergedProperties() { return mergedProperties; } /** * String[] of wildcard locations of properties that are converted to * Resource[] using using {@link PathMatchingResourcePatternResolver} * * @param locations * String[] * @throws IOException */ public void setWildcardLocations(String[] locations) throws IOException { List resources = new ArrayList(); PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver( this.getClass().getClassLoader()); for (String location : locations) { logger.debug("Loading location {}", location); try { // Get all Resources for a wildcard location Resource[] configs = resolver.getResources(location); if (configs != null && configs.length > 0) { List resourceGroup = new ArrayList(); for (Resource resource : configs) { logger.debug("Loading {} for location {}", resource .getFilename(), location); resourceGroup.add(resource); } // Sort all Resources for a wildcard location by filename Collections.sort(resourceGroup, new ResourceFilenameComparator()); // Add to master List resources.addAll(resourceGroup); } else { logger.info("Wildcard location does not exist: {}", location); } } catch (IOException ioException) { logger.error("Failed to resolve location: {} - {}", location, ioException); } } this.setLocations(resources.toArray(new Resource[resources .size()])); } /** * Add a global property to be merged * * @param key * String * @param val * String */ public static synchronized void addGlobalProperty(String key, String val) { globalPlaceholderProperties.setProperty(key, val); } /** * Copy of the manual properties * * @return {@link Properties} */ private static synchronized Properties copyOfGlobalProperties() { // return new Properties( runtimeProperties ); returns an empty prop ?? Properties prop = new Properties(); prop.putAll(globalPlaceholderProperties); return prop; } public static class ResourceFilenameComparator implements Comparator, Serializable { private static final long serialVersionUID = -6365943736917478749L; public int compare(Resource resource1, Resource resource2) { if (resource1 != null) { if (resource2 != null) { return resource1.getFilename().compareTo( resource2.getFilename()); } else { return 1; } } else if (resource2 == null) { return 0; } else { return -1; } } } } red5-1.0~svn4374.orig/src/org/red5/classloading/0000755000175000017500000000000011760512571021200 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/classloading/ChildFirstClassLoader.java0000644000175000017500000001134211706617130026211 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.classloading; import java.net.URL; import java.net.URLClassLoader; /** * An almost trivial no-fuss implementation of a class loader following the * child-first delegation model. * Based on code from Ceki Gulcu * * @author Paul Gregoire (mondain@gmail.com) */ public final class ChildFirstClassLoader extends URLClassLoader { private ClassLoader parent = null; private ClassLoader parentParent = null; private ClassLoader system = null; public ChildFirstClassLoader(URL[] urls) { super(urls); this.parent = super.getParent(); system = getSystemClassLoader(); //if we have a parent of the parent and its not the system classloader parentParent = this.parent.getParent() != system ? this.parent.getParent() : null; dumpClassLoaderNames(); } public ChildFirstClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent); this.parent = parent; system = getSystemClassLoader(); if (parent != null) { //if we have a parent of the parent and its not the system classloader parentParent = this.parent.getParent() != system ? this.parent.getParent() : null; } dumpClassLoaderNames(); } private void dumpClassLoaderNames() { System.out.printf("[ChildFirstClassLoader] Classloaders:\nSystem %s\nParents Parent %s\nParent %s\nThis class %s\nTCL %s\n\n", system, parentParent, this.parent, ChildFirstClassLoader.class.getClassLoader(), Thread.currentThread().getContextClassLoader()); } @Override public Class loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } /** * We override the parent-first behavior established by * java.lang.Classloader. *

* The implementation is surprisingly straightforward. * * @param name * the name of the class to load, should not be null * . * * @param resolve * flag that indicates whether the class should be resolved. * * @return the loaded class, never null. * * @throws ClassNotFoundException * if the class could not be loaded. */ @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { // First, check if the class has already been loaded Class c = findLoadedClass(name); // if not loaded, search the local (child) resources if (c == null) { try { c = findClass(name); } catch (ClassNotFoundException cnfe) { // ignore } } // If we could not find it, delegate to parent // Note that we do not attempt to catch any ClassNotFoundException if (c == null) { try { c = this.parent.loadClass(name); } catch (Exception e) { //ignore the Spring "BeanInfo" class lookup errors //if (e.getMessage().indexOf("BeanInfo") == -1) { // log.warn("Exception {}", e); //} } if (c == null && parentParent != null) { try { c = parentParent.loadClass(name); } catch (Exception e) { //if (e.getMessage().indexOf("BeanInfo") == -1) { // log.warn("Exception {}", e); //} } } if (c == null) { try { c = system.loadClass(name); } catch (Exception e) { //if (e.getMessage().indexOf("BeanInfo") == -1) { // log.warn("Exception {}", e); //} } } } // resolve if requested if (resolve) { resolveClass(c); } return c; } /** * Override the parent-first resource loading model established by * java.lang.Classloader with child-first behavior. * * @param name the name of the resource to load, should not be * null. * * @return a {@link URL} for the resource, or null if it could * not be found. */ @Override public URL getResource(String name) { URL url = findResource(name); // If local search failed, delegate to parent if (url == null) { url = this.parent.getResource(name); } return url; } }red5-1.0~svn4374.orig/src/org/red5/classloading/QuartzClassLoadHelper.java0000644000175000017500000000665011706617130026263 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.classloading; import java.io.InputStream; import java.net.URL; import org.quartz.spi.ClassLoadHelper; import org.red5.logging.Red5LoggerFactory; import org.slf4j.Logger; /** * A ClassLoadHelper that determines the correct class loader to * use for a scheduler. * * @see org.quartz.spi.ClassLoadHelper * * @author Paul Gregoire (mondain@gmail.com) */ public class QuartzClassLoadHelper implements ClassLoadHelper { private static Logger log = Red5LoggerFactory.getLogger(QuartzClassLoadHelper.class); private ClassLoader initClassLoader; /* ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null) { classLoader = this.getClass().getClassLoader(); result= classLoader.getResourceAsStream( name ); } else { result= classLoader.getResourceAsStream( name ); if (result == null) { classLoader = this.getClass().getClassLoader(); result= classLoader.getResourceAsStream( name ); } } */ /** * Called to give the ClassLoadHelper a chance to initialize itself, * including the opportunity to "steal" the class loader off of the calling * thread, which is the thread that is initializing Quartz. */ public void initialize() { initClassLoader = Thread.currentThread().getContextClassLoader(); log.debug("Initialized with classloader: {}", initClassLoader); } /** * Return the class with the given name. */ public Class loadClass(String name) throws ClassNotFoundException { return getClassLoader().loadClass(name); } /** * Finds a resource with a given name. This method returns null if no * resource with this name is found. * @param name name of the desired resource * @return a java.net.URL object */ public URL getResource(String name) { return getClassLoader().getResource(name); } /** * Finds a resource with a given name. This method returns null if no * resource with this name is found. * @param name name of the desired resource * @return a java.io.InputStream object */ public InputStream getResourceAsStream(String name) { return getClassLoader().getResourceAsStream(name); } /** * Enable sharing of the class-loader with 3rd party (e.g. digester). * * @return the class-loader user be the helper. */ public ClassLoader getClassLoader() { log.debug("Class classloader: {} Thread classloader: {}", this.getClass().getClassLoader(), Thread.currentThread().getContextClassLoader()); return Thread.currentThread().getContextClassLoader(); } } red5-1.0~svn4374.orig/src/org/red5/classloading/ClassLoaderBuilder.java0000644000175000017500000004467311756460764025577 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.classloading; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.StringTokenizer; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.regex.Pattern; /** * Class used to get the Servlet Class loader. The class loader returned is a * child first class loader. * *
* This class is based on original code from the XINS project, by * Anthony Goubard (anthony.goubard@japplis.com) * * @author Paul Gregoire (mondain@gmail.com) */ public final class ClassLoaderBuilder { /* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6500212 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6516909 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4976356 */ /** * Load the Servlet code from the WAR file and use the current classpath for * the libraries. */ public static final int USE_CLASSPATH_LIB = 1; /** * Load the servlet code from the WAR file and try to find the libraries in * the common red5 lib directory. */ public static final int USE_RED5_LIB = 2; /** * Load the servlet code and the libraries from the WAR file. This may take * some time as the libraries need to be extracted from the WAR file. */ public static final int USE_WAR_LIB = 3; /** * Filters jar files */ public final static class JarFileFilter implements FilenameFilter { /** * Check whether file matches filter rules * * @param dir Directory * @param name File name * @return true If file does match filter rules, false otherwise */ public boolean accept(File dir, String name) { return name.endsWith(".jar"); } } /** * Default build uses Red5 common lib without a parent classloader. * * @return the class loader */ public static ClassLoader build() { return ClassLoaderBuilder.build(null, USE_RED5_LIB, null); } /** * Gets a class loader based on mode. * * @param path the directory or file containing classes * * @param mode the mode in which the servlet should be loaded. The possible * values are USE_CURRENT_CLASSPATH, * USE_CLASSPATH_LIB, USE_XINS_LIB, * USE_WAR_LIB. * * @param parent the parent class loader or null if you want the current threads * class loader * * @return the Class loader to use to load the required class(es). * */ @SuppressWarnings("unused") public static ClassLoader build(File path, int mode, ClassLoader parent) { JarFileFilter jarFileFilter = new JarFileFilter(); List urlList = new ArrayList(31); //the class loader to return ClassLoader loader = null; //urls to load resources / classes from URL[] urls = null; if (mode == USE_RED5_LIB) { //get red5 home // look for red5 home as a system property String home = System.getProperty("red5.root"); // if home is null check environmental if (home == null) { //check for env variable home = System.getenv("RED5_HOME"); } //if home is null or equal to "current" directory if (home == null || ".".equals(home)) { //if home is still null look it up via this classes loader String classLocation = ClassLoaderBuilder.class.getProtectionDomain().getCodeSource().getLocation().toString(); //System.out.printf("Classloader location: %s\n", classLocation); //snip off anything beyond the last slash home = classLocation.substring(0, classLocation.lastIndexOf('/')); } try { //add red5.jar to the classpath urlList.add(new File(home, "red5.jar").toURI().toURL()); } catch (MalformedURLException e1) { e1.printStackTrace(); } //get red5 lib system property, if not found build it String libPath = System.getProperty("red5.lib_root"); if (libPath == null) { //construct the lib path libPath = home + "/lib"; } //System.out.printf("Library path: %s\n", libPath); //grab the urls for all the jars in "lib" File libDir = new File(libPath); //if we are on osx with spaces in our path this may occur if (libDir == null) { libDir = new File(home, "lib"); } File[] libFiles = libDir.listFiles(jarFileFilter); for (File lib : libFiles) { try { urlList.add(lib.toURI().toURL()); } catch (MalformedURLException e) { System.err.printf("Exception %s\n", e); } } //look over the libraries and remove the old versions scrubURLList(urlList); //get config dir String conf = System.getProperty("red5.config_root"); if (conf == null) { conf = home + "/conf"; } // add config dir try { URL confUrl = new File(conf).toURI().toURL(); if (!urlList.contains(confUrl)) { urlList.add(confUrl); } } catch (MalformedURLException e) { System.err.printf("Exception %s\n", e); } //add the plugins //get red5 lib system property, if not found build it String pluginsPath = System.getProperty("red5.plugins_root"); if (pluginsPath == null) { //construct the plugins path pluginsPath = home + "/plugins"; //update the property System.setProperty("red5.plugins_root", pluginsPath); } // create the directory if it doesnt exist File pluginsDir = new File(pluginsPath); //if we are on osx with spaces in our path this may occur if (pluginsDir == null) { pluginsDir = new File(home, "plugins"); //create the dir pluginsDir.mkdirs(); } // add the plugin directory to the path so that configs // will be resolved and not have to be copied to conf try { URL pluginsUrl = pluginsDir.toURI().toURL(); if (!urlList.contains(pluginsUrl)) { urlList.add(pluginsUrl); } } catch (MalformedURLException e) { System.err.printf("Exception %s\n", e); } //get all the plugin jars File[] pluginsFiles = pluginsDir.listFiles(jarFileFilter); //this can be null if the dir doesnt exist if (pluginsFiles != null) { for (File plugin : pluginsFiles) { try { urlList.add(plugin.toURI().toURL()); } catch (MalformedURLException e) { System.err.printf("Exception %s\n", e); } } } //create the url array that the classloader wants urls = urlList.toArray(new URL[0]); System.out.printf("Selected libraries: (%s items)\n", urls.length); for (URL url : urls) { System.out.println(url); } System.out.println(); // instance a url classloader using the selected jars if (parent == null) { loader = new URLClassLoader(urls); } else { loader = new URLClassLoader(urls, parent); } } else { List standardLibs = new ArrayList(7); try { urlList.add(path.toURI().toURL()); URL classesURL = new URL("jar:file:" + path.getAbsolutePath().replace(File.separatorChar, '/') + "!/WEB-INF/classes/"); urlList.add(classesURL); } catch (MalformedURLException e1) { e1.printStackTrace(); } if (mode == USE_CLASSPATH_LIB) { String classPath = System.getProperty("java.class.path"); StringTokenizer stClassPath = new StringTokenizer(classPath, File.pathSeparator); while (stClassPath.hasMoreTokens()) { String nextPath = stClassPath.nextToken(); if (nextPath.toLowerCase().endsWith(".jar")) { standardLibs.add(nextPath.substring(nextPath.lastIndexOf(File.separatorChar) + 1)); } try { urlList.add(new File(nextPath).toURI().toURL()); } catch (MalformedURLException e) { System.err.printf("Exception %s\n", e); } } } if (mode == USE_WAR_LIB) { if (path.isDirectory()) { File libDir = new File(path, "WEB-INF/lib"); //this should not be null but it can happen if (libDir != null && libDir.canRead()) { File[] libs = libDir.listFiles(jarFileFilter); //System.out.printf("Webapp lib count: %s\n", libs.length); for (File lib : libs) { try { urlList.add(lib.toURI().toURL()); } catch (MalformedURLException e) { System.err.printf("Exception %s\n", e); } } } } else { try { JarInputStream jarStream = new JarInputStream(new FileInputStream(path)); JarEntry entry = jarStream.getNextJarEntry(); while (entry != null) { String entryName = entry.getName(); if (entryName.startsWith("WEB-INF/lib/") && entryName.endsWith(".jar") && !standardLibs.contains(entryName.substring(12))) { File tempJarFile = unpack(jarStream, entryName); urlList.add(tempJarFile.toURI().toURL()); } entry = jarStream.getNextJarEntry(); } jarStream.close(); } catch (IOException e) { System.err.printf("Exception %s\n", e); } } } urls = urlList.toArray(new URL[0]); loader = new ChildFirstClassLoader(urls, parent); } Thread.currentThread().setContextClassLoader(loader); //loop thru all the current urls //System.out.printf("Classpath for %s:\n", loader); //for (URL url : urls) { //System.out.println(url.toExternalForm()); //} return loader; } /** * Unpack the specified entry from the JAR file. * * @param jarStream * The input stream of the JAR file positioned at the entry. * @param entryName * The name of the entry to extract. * * @return The extracted file. The created file is a temporary file in the * temporary directory. * * @throws IOException * if the JAR file cannot be read or is incorrect. */ private static File unpack(JarInputStream jarStream, String entryName) throws IOException { String libName = entryName.substring(entryName.lastIndexOf('/') + 1, entryName.length() - 4); File tempJarFile = File.createTempFile("tmp_" + libName, ".jar"); tempJarFile.deleteOnExit(); FileOutputStream out = new FileOutputStream(tempJarFile); // Transfer bytes from the JAR file to the output file byte[] buf = new byte[8192]; int len; while ((len = jarStream.read(buf)) > 0) { out.write(buf, 0, len); } out.close(); return tempJarFile; } /** * Removes older versions of libraries from a given list based * on their version numbers. * * @param list */ private final static void scrubURLList(List list) { String ALPHABET = "abcdefghijklmnopqrstuvwxyz"; Pattern punct = Pattern.compile("\\p{Punct}"); Set removalList = new HashSet(list.size()); String topName = null; String checkName = null; URL[] urls = list.toArray(new URL[0]); // System.out.printf("Library list: (%s items)\n", urls.length); // for (URL url : urls) { // System.out.println(url); // } // System.out.println(); for (URL top : urls) { if (removalList.contains(top)) { continue; } topName = parseUrl(top); //empty name - this happens inside eclipse if ("".equals(topName)) { removalList.add(top); continue; } //skip red5 if (topName.startsWith("red5")) { continue; } //skip version-less libraries if (topName.endsWith("-")) { removalList.add(top); continue; } //by default we will get rid of testing libraries if (topName.startsWith("grobo") || topName.startsWith("junit") || topName.startsWith("ivy")) { removalList.add(top); continue; } int topFirstDash = topName.indexOf('-'); //if theres no dash then just grab the first 3 chars // FIXME: why just grab the first 3 characters? String prefix = topName.substring(0, topFirstDash != -1 ? topFirstDash : 3); int topSecondDash = topName.indexOf('-', topFirstDash + 1); for (URL check : list) { if (removalList.contains(check)) { continue; } checkName = parseUrl(check); //if its the same lib just continue with the next if (checkName.equals(topName)) { continue; } //if the last character is a dash then skip it if (checkName.endsWith("-")) { continue; } //check starts with to see if we should do version check if (!checkName.startsWith(prefix)) { continue; } //check for next dash if (topSecondDash > 0) { if (checkName.length() <= topSecondDash) { continue; } //check for second dash in check lib at same position if (checkName.charAt(topSecondDash) != '-') { continue; } //split the names String[] topSubs = topName.split("-"); String[] checkSubs = checkName.split("-"); //check lib type "spring-aop" vs "spring-orm" if (!topSubs[1].equals(checkSubs[1])) { continue; } //see if next entry is a number if (!Character.isDigit(topSubs[2].charAt(0)) && !Character.isDigit(checkSubs[2].charAt(0))) { //check next lib name section for a match if (!topSubs[2].equals(checkSubs[2])) { continue; } } } //do the version check //read from end to get version info String checkVers = checkName.substring(topSecondDash != -1 ? (topSecondDash + 1) : (topFirstDash + 1)); if (checkVers.startsWith("-")) { continue; } //get top libs version info String topVers = topName.substring(topSecondDash != -1 ? (topSecondDash + 1) : (topFirstDash + 1)); int topThirdDash = -1; String topThirdName = null; if (topVers.length() > 0 && !Character.isDigit(topVers.charAt(0))) { //check if third level lib name matches topThirdDash = topVers.indexOf('-'); //no version most likely exists if (topThirdDash == -1) { continue; } topThirdName = topVers.substring(0, topThirdDash); topVers = topVers.substring(topThirdDash + 1); } //if check version starts with a non-number skip it int checkThirdDash = -1; String checkThirdName = null; if (!Character.isDigit(checkVers.charAt(0))) { //check if third level lib name matches checkThirdDash = checkVers.indexOf('-'); //no version most likely exists if (checkThirdDash == -1) { continue; } checkThirdName = checkVers.substring(0, checkThirdDash); if (topThirdName == null || !topThirdName.equals(checkThirdName)) { continue; } checkVers = checkVers.substring(checkThirdDash + 1); //if not if (!Character.isDigit(checkVers.charAt(0))) { continue; } } if (topThirdName != null && checkThirdName == null) { continue; } //check major String[] topVersion = punct.split(topVers); //System.out.println("topVersion (" + topVers + "): " + topVersion[0] + " length: " + topVersion.length); if (!topVersion[0].matches("[\\d].*")) { continue; } //check 3rd part of version for letters if (topVersion.length > 2) { String v = topVersion[2].toLowerCase(); if (v.length() > 1) { topVersion[2] = deleteAny(v, ALPHABET); } // after alpha removal, string is any digits or single char if (topVersion[2].length() == 1) { //if is a only a letter use its index as a version char ch = v.charAt(0); if (!Character.isDigit(ch)) { topVersion[2] = ALPHABET.indexOf(ch) + ""; } } } //System.out.println("AOB " + checkVers + " | " + topVersion[0] + " length: " + topVersion.length); int topVersionNumber; try{ topVersionNumber = topVersion.length == 1 ? Integer.valueOf(topVersion[0]) : Integer.valueOf( topVersion[0] + topVersion[1] + (topVersion.length > 2 ? topVersion[2] : '0')).intValue(); } catch (NumberFormatException nfe){ topVersionNumber = 0; System.err.println("Error parsing topVers:"+ topVers); } String[] checkVersion = punct.split(checkVers); //System.out.println("checkVersion (" + checkVers + "): " + checkVersion[0] + " length: " + checkVersion.length); //check 3rd part of version for letters if (checkVersion.length > 2) { String v = checkVersion[2].toLowerCase(); if (v.length() > 1) { checkVersion[2] = deleteAny(v, ALPHABET); } // after alpha removal, string is any digits or single char if (checkVersion[2].length() == 1) { //if is a only a letter use its index as a version char ch = v.charAt(0); if (!Character.isDigit(ch)) { checkVersion[2] = ALPHABET.indexOf(ch) + ""; } } } int checkVersionNumber; try{ checkVersionNumber = checkVersion.length == 1 ? Integer.valueOf(checkVersion[0]) : Integer.valueOf( checkVersion[0] + checkVersion[1] + (checkVersion.length > 2 ? checkVersion[2] : '0')).intValue(); } catch (NumberFormatException nfe){ checkVersionNumber=0; System.err.println("Error parsing checkVers:"+ checkVers); } // Check version numbers if (topVersionNumber >= checkVersionNumber) { //remove it removalList.add(check); } else { removalList.add(top); break; } } } //remove the old libs // System.out.println("Removal list:"); // for (URL url : removalList) { // System.out.println(url); // } list.removeAll(removalList); } /** * Parses url and returns the jar filename stripped of the ending .jar * @param url * @return */ private static String parseUrl(URL url) { String external = url.toExternalForm().toLowerCase(); //get everything after the last slash String[] parts = external.split("/"); //last part String libName = parts[parts.length - 1]; //strip .jar libName = libName.substring(0, libName.length() - 4); return libName; } private static String deleteAny(String str, String removalChars) { StringBuilder sb = new StringBuilder(str); //System.out.println("Before alpha delete: " + sb.toString()); String[] chars = removalChars.split(""); //System.out.println("Chars length: " + chars.length); for (String c : chars) { int index = -1; while ((index = sb.indexOf(c)) > 0) { sb.deleteCharAt(index); } } //System.out.println("After alpha delete: " + sb.toString()); return sb.toString(); } } red5-1.0~svn4374.orig/src/org/red5/io/0000755000175000017500000000000011760512575017150 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/m4a/0000755000175000017500000000000011760512574017630 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/m4a/IM4A.java0000644000175000017500000000162211706617130021160 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.m4a; import org.red5.io.IStreamableFile; /** * Represents M4A / AAC file * * @author Paul Gregoire (mondain@gmail.com) */ public interface IM4A extends IStreamableFile { } red5-1.0~svn4374.orig/src/org/red5/io/m4a/IM4AService.java0000644000175000017500000000256611706617130022511 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.m4a; import org.red5.io.IStreamableFileService; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; /** * A M4AService sets up the service and hands out M4A objects to * its callers * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public interface IM4AService extends IStreamableFileService { /** * Sets the serializer * * @param serializer Serializer object */ public void setSerializer(Serializer serializer); /** * Sets the deserializer * * @param deserializer Deserializer object */ public void setDeserializer(Deserializer deserializer); } red5-1.0~svn4374.orig/src/org/red5/io/m4a/impl/0000755000175000017500000000000011760512574020571 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/m4a/impl/M4A.java0000644000175000017500000000333211706617130022010 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.m4a.impl; import java.io.File; import java.io.IOException; import org.red5.io.ITagReader; import org.red5.io.ITagWriter; import org.red5.io.m4a.IM4A; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A M4AImpl implements the M4A api * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire, (mondain@gmail.com) */ public class M4A implements IM4A { protected static Logger log = LoggerFactory.getLogger(M4A.class); private File file; /** * Default constructor, used by Spring so that parameters may be injected. */ public M4A() { } /** * Create M4A from given file source * * @param file * File source */ public M4A(File file) { this.file = file; } /** * {@inheritDoc} */ public ITagReader getReader() throws IOException { return new M4AReader(file); } /** * {@inheritDoc} */ public ITagWriter getWriter() throws IOException { return null; } public ITagWriter getAppendWriter() throws IOException { return null; } } red5-1.0~svn4374.orig/src/org/red5/io/m4a/impl/M4AReader.java0000644000175000017500000005667611747635016023166 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.m4a.impl; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Vector; import java.util.concurrent.Semaphore; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.IStreamableFile; import org.red5.io.ITag; import org.red5.io.ITagReader; import org.red5.io.IoConstants; import org.red5.io.amf.Output; import org.red5.io.flv.impl.Tag; import org.red5.io.mp4.MP4Atom; import org.red5.io.mp4.MP4DataStream; import org.red5.io.mp4.MP4Descriptor; import org.red5.io.mp4.MP4Frame; import org.red5.io.mp4.impl.MP4Reader; import org.red5.io.object.Serializer; import org.red5.io.utils.HexDump; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A Reader is used to read the contents of a M4A file. * NOTE: This class is not implemented as threading-safe. The caller * should make sure the threading-safety. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire, (mondain@gmail.com) */ public class M4AReader implements IoConstants, ITagReader { /** * Logger */ private static Logger log = LoggerFactory.getLogger(M4AReader.class); /** * File */ private File file; /** * Input stream */ private MP4DataStream fis; /** * File channel */ private FileChannel channel; /** * Memory-mapped buffer for file content */ private MappedByteBuffer mappedFile; /** * Input byte buffer */ private IoBuffer in; private String audioCodecId = "mp4a"; //decoder bytes / configs private byte[] audioDecoderBytes; /** Duration in milliseconds. */ private long duration; private int timeScale; //audio sample rate kHz private double audioTimeScale; private int audioChannels; //default to aac lc private int audioCodecType = 1; private String formattedDuration; private long moovOffset; private long mdatOffset; //samples to chunk mappings private Vector audioSamplesToChunks; //samples private Vector audioSamples; //chunk offsets private Vector audioChunkOffsets; //sample duration private int audioSampleDuration = 1024; //keep track of current sample private int currentFrame = 1; private int prevFrameSize = 0; private List frames = new ArrayList(); /** * Container for metadata and any other tags that should * be sent prior to media data. */ private LinkedList firstTags = new LinkedList(); private final Semaphore lock = new Semaphore(1, true); /** Constructs a new M4AReader. */ M4AReader() { } /** * Creates M4A reader from file input stream, sets up metadata generation flag. * * @param f File input stream */ public M4AReader(File f) throws IOException { if (null == f) { log.warn("Reader was passed a null file"); log.debug("{}", ToStringBuilder.reflectionToString(this)); } this.file = f; this.fis = new MP4DataStream(new FileInputStream(f)); channel = fis.getChannel(); try { mappedFile = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); } catch (IOException e) { log.error("M4AReader {}", e); } // Wrap mapped byte buffer to MINA buffer in = IoBuffer.wrap(mappedFile); //decode all the info that we want from the atoms decodeHeader(); //analyze the samples/chunks and build the keyframe meta data analyzeFrames(); //add meta data firstTags.add(createFileMeta()); //create / add the pre-streaming (decoder config) tags createPreStreamingTags(); } /** * Accepts mapped file bytes to construct internal members. * * @param buffer Byte buffer */ public M4AReader(IoBuffer buffer) throws IOException { in = buffer; //decode all the info that we want from the atoms decodeHeader(); //analyze the samples/chunks and build the keyframe meta data analyzeFrames(); //add meta data firstTags.add(createFileMeta()); //create / add the pre-streaming (decoder config) tags createPreStreamingTags(); } /** * This handles the moov atom being at the beginning or end of the file, so the mdat may also * be before or after the moov atom. */ public void decodeHeader() { try { // the first atom will/should be the type MP4Atom type = MP4Atom.createAtom(fis); // expect ftyp log.debug("Type {}", MP4Atom.intToType(type.getType())); //log.debug("Atom int types - free={} wide={}", MP4Atom.typeToInt("free"), MP4Atom.typeToInt("wide")); // keep a running count of the number of atoms found at the "top" levels int topAtoms = 0; // we want a moov and an mdat, anything else throw the invalid file type error while (topAtoms < 2) { MP4Atom atom = MP4Atom.createAtom(fis); switch (atom.getType()) { case 1836019574: //moov topAtoms++; MP4Atom moov = atom; // expect moov log.debug("Type {}", MP4Atom.intToType(moov.getType())); log.debug("moov children: {}", moov.getChildren()); moovOffset = fis.getOffset() - moov.getSize(); MP4Atom mvhd = moov.lookup(MP4Atom.typeToInt("mvhd"), 0); if (mvhd != null) { log.debug("Movie header atom found"); //get the initial timescale timeScale = mvhd.getTimeScale(); duration = mvhd.getDuration(); log.debug("Time scale {} Duration {}", timeScale, duration); } /* nothing needed here yet MP4Atom meta = moov.lookup(MP4Atom.typeToInt("meta"), 0); if (meta != null) { log.debug("Meta atom found"); log.debug("{}", ToStringBuilder.reflectionToString(meta)); } */ MP4Atom trak = moov.lookup(MP4Atom.typeToInt("trak"), 0); if (trak != null) { log.debug("Track atom found"); log.debug("trak children: {}", trak.getChildren()); // trak: tkhd, edts, mdia MP4Atom edts = trak.lookup(MP4Atom.typeToInt("edts"), 0); if (edts != null) { log.debug("Edit atom found"); log.debug("edts children: {}", edts.getChildren()); } MP4Atom mdia = trak.lookup(MP4Atom.typeToInt("mdia"), 0); if (mdia != null) { log.debug("Media atom found"); // mdia: mdhd, hdlr, minf int scale = 0; //get the media header atom MP4Atom mdhd = mdia.lookup(MP4Atom.typeToInt("mdhd"), 0); if (mdhd != null) { log.debug("Media data header atom found"); //this will be for either video or audio depending media info scale = mdhd.getTimeScale(); log.debug("Time scale {}", scale); } MP4Atom hdlr = mdia.lookup(MP4Atom.typeToInt("hdlr"), 0); if (hdlr != null) { log.debug("Handler ref atom found"); // soun or vide log.debug("Handler type: {}", MP4Atom.intToType(hdlr.getHandlerType())); String hdlrType = MP4Atom.intToType(hdlr.getHandlerType()); if ("soun".equals(hdlrType)) { if (scale > 0) { audioTimeScale = scale * 1.0; log.debug("Audio time scale: {}", audioTimeScale); } } } MP4Atom minf = mdia.lookup(MP4Atom.typeToInt("minf"), 0); if (minf != null) { log.debug("Media info atom found"); // minf: (audio) smhd, dinf, stbl / (video) vmhd, // dinf, stbl MP4Atom smhd = minf.lookup(MP4Atom.typeToInt("smhd"), 0); if (smhd != null) { log.debug("Sound header atom found"); MP4Atom dinf = minf.lookup(MP4Atom.typeToInt("dinf"), 0); if (dinf != null) { log.debug("Data info atom found"); // dinf: dref log.debug("Sound dinf children: {}", dinf.getChildren()); MP4Atom dref = dinf.lookup(MP4Atom.typeToInt("dref"), 0); if (dref != null) { log.debug("Data reference atom found"); } } MP4Atom stbl = minf.lookup(MP4Atom.typeToInt("stbl"), 0); if (stbl != null) { log.debug("Sample table atom found"); // stbl: stsd, stts, stss, stsc, stsz, stco, // stsh log.debug("Sound stbl children: {}", stbl.getChildren()); // stsd - sample description // stts - time to sample // stsc - sample to chunk // stsz - sample size // stco - chunk offset //stsd - has codec child MP4Atom stsd = stbl.lookup(MP4Atom.typeToInt("stsd"), 0); if (stsd != null) { //stsd: mp4a log.debug("Sample description atom found"); MP4Atom mp4a = stsd.getChildren().get(0); //could set the audio codec here setAudioCodecId(MP4Atom.intToType(mp4a.getType())); //log.debug("{}", ToStringBuilder.reflectionToString(mp4a)); log.debug("Sample size: {}", mp4a.getSampleSize()); int ats = mp4a.getTimeScale(); //skip invalid audio time scale if (ats > 0) { audioTimeScale = ats * 1.0; } audioChannels = mp4a.getChannelCount(); log.debug("Sample rate (audio time scale): {}", audioTimeScale); log.debug("Channels: {}", audioChannels); //mp4a: esds if (mp4a.getChildren().size() > 0) { log.debug("Elementary stream descriptor atom found"); MP4Atom esds = mp4a.getChildren().get(0); log.debug("{}", ToStringBuilder.reflectionToString(esds)); MP4Descriptor descriptor = esds.getEsd_descriptor(); log.debug("{}", ToStringBuilder.reflectionToString(descriptor)); if (descriptor != null) { Vector children = descriptor.getChildren(); for (int e = 0; e < children.size(); e++) { MP4Descriptor descr = children.get(e); log.debug("{}", ToStringBuilder.reflectionToString(descr)); if (descr.getChildren().size() > 0) { Vector children2 = descr.getChildren(); for (int e2 = 0; e2 < children2.size(); e2++) { MP4Descriptor descr2 = children2.get(e2); log.debug("{}", ToStringBuilder.reflectionToString(descr2)); if (descr2.getType() == MP4Descriptor.MP4DecSpecificInfoDescriptorTag) { //we only want the MP4DecSpecificInfoDescriptorTag audioDecoderBytes = descr2.getDSID(); //compare the bytes to get the aacaot/aottype //match first byte switch (audioDecoderBytes[0]) { case 0x12: default: //AAC LC - 12 10 audioCodecType = 1; break; case 0x0a: //AAC Main - 0A 10 audioCodecType = 0; break; case 0x11: case 0x13: //AAC LC SBR - 11 90 & 13 xx audioCodecType = 2; break; } //we want to break out of top level for loop e = 99; break; } } } } } } } //stsc - has Records MP4Atom stsc = stbl.lookup(MP4Atom.typeToInt("stsc"), 0); if (stsc != null) { log.debug("Sample to chunk atom found"); audioSamplesToChunks = stsc.getRecords(); log.debug("Record count: {}", audioSamplesToChunks.size()); MP4Atom.Record rec = audioSamplesToChunks.firstElement(); log.debug("Record data: Description index={} Samples per chunk={}", rec.getSampleDescriptionIndex(), rec.getSamplesPerChunk()); } //stsz - has Samples MP4Atom stsz = stbl.lookup(MP4Atom.typeToInt("stsz"), 0); if (stsz != null) { log.debug("Sample size atom found"); audioSamples = stsz.getSamples(); //vector full of integers log.debug("Sample size: {}", stsz.getSampleSize()); log.debug("Sample count: {}", audioSamples.size()); } //stco - has Chunks MP4Atom stco = stbl.lookup(MP4Atom.typeToInt("stco"), 0); if (stco != null) { log.debug("Chunk offset atom found"); //vector full of integers audioChunkOffsets = stco.getChunks(); log.debug("Chunk count: {}", audioChunkOffsets.size()); } //stts - has TimeSampleRecords MP4Atom stts = stbl.lookup(MP4Atom.typeToInt("stts"), 0); if (stts != null) { log.debug("Time to sample atom found"); Vector records = stts.getTimeToSamplesRecords(); log.debug("Record count: {}", records.size()); MP4Atom.TimeSampleRecord rec = records.firstElement(); log.debug("Record data: Consecutive samples={} Duration={}", rec.getConsecutiveSamples(), rec.getSampleDuration()); //if we have 1 record then all samples have the same duration if (records.size() > 1) { //TODO: handle audio samples with varying durations log.warn("Audio samples have differing durations, audio playback may fail"); } audioSampleDuration = rec.getSampleDuration(); } } } } } } //real duration StringBuilder sb = new StringBuilder(); double clipTime = ((double) duration / (double) timeScale); log.debug("Clip time: {}", clipTime); int minutes = (int) (clipTime / 60); if (minutes > 0) { sb.append(minutes); sb.append('.'); } //formatter for seconds / millis NumberFormat df = DecimalFormat.getInstance(); df.setMaximumFractionDigits(2); sb.append(df.format((clipTime % 60))); formattedDuration = sb.toString(); log.debug("Time: {}", formattedDuration); break; case 1835295092: //mdat topAtoms++; long dataSize = 0L; MP4Atom mdat = atom; dataSize = mdat.getSize(); log.debug("{}", ToStringBuilder.reflectionToString(mdat)); mdatOffset = fis.getOffset() - dataSize; log.debug("File size: {} mdat size: {}", file.length(), dataSize); break; case 1718773093: //free case 2003395685: //wide break; default: log.warn("Unexpected atom: {}", MP4Atom.intToType(atom.getType())); } } //add the tag name (size) to the offsets moovOffset += 8; mdatOffset += 8; log.debug("Offsets moov: {} mdat: {}", moovOffset, mdatOffset); } catch (IOException e) { log.error("Exception decoding header / atoms", e); } } public long getTotalBytes() { try { return channel.size(); } catch (Exception e) { log.error("Error getTotalBytes", e); return 0; } } /** {@inheritDoc} */ public boolean hasVideo() { return false; } /** * Returns the file buffer. * * @return File contents as byte buffer */ public IoBuffer getFileData() { return null; } /** {@inheritDoc} */ public IStreamableFile getFile() { // TODO wondering if we need to have a reference return null; } /** {@inheritDoc} */ public int getOffset() { // XXX what's the difference from getBytesRead return 0; } /** {@inheritDoc} */ public long getBytesRead() { return in.position(); } /** {@inheritDoc} */ public long getDuration() { return duration; } public String getAudioCodecId() { return audioCodecId; } /** {@inheritDoc} */ public boolean hasMoreTags() { return currentFrame < frames.size(); } /** * Create tag for metadata event. * * @return Metadata event tag */ ITag createFileMeta() { log.debug("Creating onMetaData"); // Create tag for onMetaData event IoBuffer buf = IoBuffer.allocate(1024); buf.setAutoExpand(true); Output out = new Output(buf); out.writeString("onMetaData"); Map props = new HashMap(); // Duration property props.put("duration", ((double) duration / (double) timeScale)); // Audio codec id - watch for mp3 instead of aac props.put("audiocodecid", audioCodecId); props.put("aacaot", audioCodecType); props.put("audiosamplerate", audioTimeScale); props.put("audiochannels", audioChannels); props.put("moovposition", moovOffset); //tags will only appear if there is an "ilst" atom in the file //props.put("tags", ""); props.put("canSeekToEnd", false); out.writeMap(props, new Serializer()); buf.flip(); //now that all the meta properties are done, update the duration duration = Math.round(duration * 1000d); ITag result = new Tag(IoConstants.TYPE_METADATA, 0, buf.limit(), null, 0); result.setBody(buf); return result; } /** * Tag sequence * MetaData, Audio config, remaining audio * * Packet prefixes: * af 00 ... 06 = Audio extra data (first audio packet) * af 01 = Audio frame * * Audio extra data(s): * af 00 = Prefix * 11 90 4f 14 = AAC Main = aottype 0 * 12 10 = AAC LC = aottype 1 * 13 90 56 e5 a5 48 00 = HE-AAC SBR = aottype 2 * 06 = Suffix * * Still not absolutely certain about this order or the bytes - need to verify later */ private void createPreStreamingTags() { log.debug("Creating pre-streaming tags"); if (audioDecoderBytes != null) { IoBuffer body = IoBuffer.allocate(audioDecoderBytes.length + 3); body.put(new byte[] { (byte) 0xaf, (byte) 0 }); //prefix if (log.isDebugEnabled()) { log.debug("Audio decoder bytes: {}", HexDump.byteArrayToHexString(audioDecoderBytes)); } body.put(audioDecoderBytes); body.put((byte) 0x06); //suffix ITag tag = new Tag(IoConstants.TYPE_AUDIO, 0, body.position(), null, prevFrameSize); body.flip(); tag.setBody(body); //add tag firstTags.add(tag); } else { //default to aac-lc when the esds doesnt contain descripter bytes log.warn("Audio decoder bytes were not available"); } } /** * Packages media data for return to providers. * */ public ITag readTag() { //log.debug("Read tag"); ITag tag = null; try { lock.acquire(); //empty-out the pre-streaming tags first if (!firstTags.isEmpty()) { log.debug("Returning pre-tag"); // Return first tags before media data return firstTags.removeFirst(); } //log.debug("Read tag - sample {} prevFrameSize {} audio: {} video: {}", new Object[]{currentSample, prevFrameSize, audioCount, videoCount}); //get the current frame MP4Frame frame = frames.get(currentFrame); log.debug("Playback {}", frame); int sampleSize = frame.getSize(); int time = (int) Math.round(frame.getTime() * 1000.0); //log.debug("Read tag - dst: {} base: {} time: {}", new Object[]{frameTs, baseTs, time}); long samplePos = frame.getOffset(); //log.debug("Read tag - samplePos {}", samplePos); //determine frame type and packet body padding byte type = frame.getType(); //create a byte buffer of the size of the sample ByteBuffer data = ByteBuffer.allocate(sampleSize + 2); try { //log.debug("Writing audio prefix"); data.put(MP4Reader.PREFIX_AUDIO_FRAME); //do we need to add the mdat offset to the sample position? channel.position(samplePos); channel.read(data); } catch (IOException e) { log.error("Error on channel position / read", e); } //chunk the data IoBuffer payload = IoBuffer.wrap(data.array()); //create the tag tag = new Tag(type, time, payload.limit(), payload, prevFrameSize); //log.debug("Read tag - type: {} body size: {}", (type == TYPE_AUDIO ? "Audio" : "Video"), tag.getBodySize()); //increment the sample number currentFrame++; //set the frame / tag size prevFrameSize = tag.getBodySize(); } catch (InterruptedException e) { log.warn("Exception acquiring lock", e); } finally { lock.release(); } //log.debug("Tag: {}", tag); return tag; } /** * Performs frame analysis and generates metadata for use in seeking. All the frames * are analyzed and sorted together based on time and offset. */ public void analyzeFrames() { log.debug("Analyzing frames"); // tag == sample int sample = 1; Long pos = null; //add the audio frames / samples / chunks for (int i = 0; i < audioSamplesToChunks.size(); i++) { MP4Atom.Record record = audioSamplesToChunks.get(i); int firstChunk = record.getFirstChunk(); int lastChunk = audioChunkOffsets.size(); if (i < audioSamplesToChunks.size() - 1) { MP4Atom.Record nextRecord = audioSamplesToChunks.get(i + 1); lastChunk = nextRecord.getFirstChunk() - 1; } for (int chunk = firstChunk; chunk <= lastChunk; chunk++) { int sampleCount = record.getSamplesPerChunk(); pos = audioChunkOffsets.elementAt(chunk - 1); while (sampleCount > 0) { //calculate ts double ts = (audioSampleDuration * (sample - 1)) / audioTimeScale; //sample size int size = (audioSamples.get(sample - 1)).intValue(); //create a frame MP4Frame frame = new MP4Frame(); frame.setOffset(pos); frame.setSize(size); frame.setTime(ts); frame.setType(TYPE_AUDIO); frames.add(frame); log.debug("Sample #{} {}", sample, frame); //inc and dec stuff pos += size; sampleCount--; sample++; } } } //sort the frames Collections.sort(frames); log.debug("Frames count: {}", frames.size()); //log.debug("Frames: {}", frames); } /** * Put the current position to pos. The caller must ensure the pos is a valid one. * * @param pos position to move to in file / channel */ public void position(long pos) { log.debug("position: {}", pos); currentFrame = getFrame(pos); log.debug("Setting current sample: {}", currentFrame); } /** * Search through the frames by offset / position to find the sample. * * @param pos * @return */ private int getFrame(long pos) { int sample = 1; int len = frames.size(); MP4Frame frame = null; for (int f = 0; f < len; f++) { frame = frames.get(f); if (pos == frame.getOffset()) { sample = f; break; } } return sample; } /** {@inheritDoc} */ public void close() { log.debug("Close"); if (in != null) { in.free(); in = null; } if (channel != null) { try { channel.close(); fis.close(); fis = null; } catch (IOException e) { log.error("Channel close {}", e); } finally { if (frames != null) { frames.clear(); frames = null; } } } } public void setAudioCodecId(String audioCodecId) { this.audioCodecId = audioCodecId; } public ITag readTagHeader() { return null; } } red5-1.0~svn4374.orig/src/org/red5/io/m4a/impl/M4AService.java0000644000175000017500000000546711706617130023344 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.m4a.impl; import java.io.File; import java.io.IOException; import org.red5.io.BaseStreamableFileService; import org.red5.io.IStreamableFile; import org.red5.io.m4a.IM4AService; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; /** * A M4AServiceImpl sets up the service and hands out M4A objects to * its callers. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire, (mondain@gmail.com) */ public class M4AService extends BaseStreamableFileService implements IM4AService { /** * Serializer */ private Serializer serializer; /** * Deserializer */ private Deserializer deserializer; /** * File extensions handled by this service. If there are more than one, they * are comma separated. */ private static String extension = ".f4a,.m4a,.aac"; private static String prefix = "f4a"; /** {@inheritDoc} */ @Override public void setPrefix(String prefix) { M4AService.prefix = prefix; } /** {@inheritDoc} */ @Override public String getPrefix() { return prefix; } /** {@inheritDoc} */ @Override public void setExtension(String extension) { M4AService.extension = extension; } /** {@inheritDoc} */ @Override public String getExtension() { return extension; } /** * {@inheritDoc} */ public void setSerializer(Serializer serializer) { this.serializer = serializer; } /** {@inheritDoc} */ public void setDeserializer(Deserializer deserializer) { this.deserializer = deserializer; } /** {@inheritDoc} */ @Override public IStreamableFile getStreamableFile(File file) throws IOException { return new M4A(file); } /** * Getter for serializer * * @return Serializer */ public Serializer getSerializer() { return serializer; } /** * Getter for deserializer * * @return Deserializer */ public Deserializer getDeserializer() { return deserializer; } } red5-1.0~svn4374.orig/src/org/red5/io/object/0000755000175000017500000000000011760512575020416 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/object/Flag.java0000644000175000017500000000146711706617130022133 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; /** * Serial flag options. */ public enum Flag { Enabled, Disabled, Default }red5-1.0~svn4374.orig/src/org/red5/io/object/Input.java0000644000175000017500000001022011706617130022344 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; import java.lang.reflect.Type; import java.util.Date; import java.util.Map; import java.util.Vector; import org.red5.io.amf3.ByteArray; import org.w3c.dom.Document; /** * Interface for Input which defines the contract methods which are * to be implemented. Input object provides * ways to read primitives, complex object and object references from byte buffer. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public interface Input { /** * Read type of data * @return Type of data as byte */ byte readDataType(); /** * Read a string without the string type header. * * @return String */ String getString(); /** * Read Null data type * @param target target type * @return Null datatype (AS) */ Object readNull(Type target); /** * Read Boolean value * @param target target type * @return Boolean */ Boolean readBoolean(Type target); /** * Read Number object * @param target target type * @return Number */ Number readNumber(Type target); /** * Read String object * @param target target type * @return String */ String readString(Type target); /** * Read date object * @param target target type * @return Date */ Date readDate(Type target); /** * Read an array. This can result in a List or Map being * deserialized depending on the array type found. * * @param deserializer deserializer * @param target target type * @return array */ Object readArray(Deserializer deserializer, Type target); /** * Read a map containing key - value pairs. This can result * in a List or Map being deserialized depending on the * map type found. * * @param deserializer deserializer * @param target target type * @return Map */ Object readMap(Deserializer deserializer, Type target); /** * Read an object. * * @param deserializer deserializer * @param target target type * @return object */ Object readObject(Deserializer deserializer, Type target); /** * Read XML document * * @param target target type * @return XML DOM document */ Document readXML(Type target); /** * Read custom object * * @param target target type * @return Custom object */ Object readCustom(Type target); /** * Read ByteArray object. * * @param target target type * @return ByteArray object */ ByteArray readByteArray(Type target); /** * Read reference to Complex Data Type. Objects that are collaborators (properties) of other * objects must be stored as references in map of id-reference pairs. * * @param target target type * @return object */ Object readReference(Type target); /** * Clears all references */ void clearReferences(); /** * Read key - value pairs. This is required for the RecordSet deserializer. * * @param deserializer deserializer * @return key-value pairs */ Map readKeyValues(Deserializer deserializer); /** * Read Vector object. * * @return Vector */ Vector readVectorInt(); /** * Read Vector object. * * @return Vector */ Vector readVectorUInt(); /** * Read Vector object. * * @return Vector */ Vector readVectorNumber(); /** * Read Vector object. * * @return Vector */ Vector readVectorObject(); } red5-1.0~svn4374.orig/src/org/red5/io/object/Output.java0000644000175000017500000001017111706617130022552 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; import java.util.Collection; import java.util.Date; import java.util.Map; import java.util.Vector; import org.red5.io.amf3.ByteArray; import org.w3c.dom.Document; /** * Output interface which defines contract methods to be implemented * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public interface Output { boolean supportsDataType(byte type); void putString(String string); // Basic Data Types /** * Write number * @param num Number */ void writeNumber(Number num); /** * Write boolean * @param bol Boolean */ void writeBoolean(Boolean bol); /** * Write string * @param string String */ void writeString(String string); /** * Write date * @param date Date */ void writeDate(Date date); void writeNull(); /** * Write array. * @param array Array to write. * @param serializer Serializer to use for subobjects. */ void writeArray(Collection array, Serializer serializer); /** * Write array. * @param array Array to write. * @param serializer Serializer to use for subobjects. */ void writeArray(Object[] array, Serializer serializer); /** * Write primitive array. * @param array Array to write. * @param serializer Serializer to use for subobjects. */ void writeArray(Object array, Serializer serializer); /** * Write map. * * @param map Map to write * @param serializer Serializer to use for subobjects. */ void writeMap(Map map, Serializer serializer); /** * Write array as map. * * @param array Array to write * @param serializer Serializer to use for subobjects. */ void writeMap(Collection array, Serializer serializer); /** * Write object. * * @param object Object to write * @param serializer Serializer to use for subobjects. */ void writeObject(Object object, Serializer serializer); /** * Write map as object. * * @param map Map to write * @param serializer Serializer to use for subobjects. */ void writeObject(Map map, Serializer serializer); /** * Write recordset. * * @param recordset Recordset to write. * @param serializer Serializer to use for subobjects. */ void writeRecordSet(RecordSet recordset, Serializer serializer); /** * Write XML object * @param xml XML document */ void writeXML(Document xml); /** * Write ByteArray object (AMF3 only). * * @param array object to write */ void writeByteArray(ByteArray array); /** * Write a Vector. * * @param vector */ void writeVectorInt(Vector vector); /** * Write a Vector. * * @param vector */ void writeVectorUInt(Vector vector); /** * Write a Vector. * * @param vector */ void writeVectorNumber(Vector vector); /** * Write a Vector. * * @param vector */ void writeVectorObject(Vector vector); /** * Write reference to complex data type * @param obj Referenced object */ void writeReference(Object obj); /** * Whether object is custom * * @param custom Object * @return true if object is of user type, false otherwise */ boolean isCustom(Object custom); /** * Write custom (user) object * @param custom Custom data type object */ void writeCustom(Object custom); /** * Clear references */ void clearReferences(); } red5-1.0~svn4374.orig/src/org/red5/io/object/UnsignedNumber.java0000644000175000017500000000440711706617130024204 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; /** * @author Matteo Merli (matteo.merli@gmail.com) */ public abstract class UnsignedNumber extends Number { private static final long serialVersionUID = -6404256963187584919L; /** * Get a byte array representation of the number. The order will be MSB * first (Big Endian). * * @return the serialized number */ public abstract byte[] getBytes(); /** * Perform a bit right shift of the value. * * @param nBits * the number of positions to shift */ public abstract void shiftRight(int nBits); /** * Perform a bit left shift of the value. * * @param nBits * the number of positions to shift */ public abstract void shiftLeft(int nBits); public abstract String toString(); public abstract int compareTo(UnsignedNumber other); public abstract boolean equals(Object other); public abstract int hashCode(); public String toHexString() { return toHexString(false); } public String toHexString(boolean pad) { StringBuilder sb = new StringBuilder(); boolean started = false; for (byte b : getBytes()) { if (!started && b == 0) { if (pad) { sb.append("00"); } } else { sb.append(hexLetters[(byte) ((b >> 4) & 0x0F)]).append(hexLetters[b & 0x0F]); started = true; } } if (sb.length() == 0) { return "0"; } return sb.toString(); } protected static final char[] hexLetters = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; } red5-1.0~svn4374.orig/src/org/red5/io/object/Deserializer.java0000644000175000017500000000705511706617130023703 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; import java.lang.reflect.Type; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The Deserializer class reads data input and handles the data according to the core data types * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class Deserializer { // Initialize Logging private static final Logger log = LoggerFactory.getLogger(Deserializer.class); /** * Deserializes the input parameter and returns an Object which must then be cast to a core data type * * @param type * @param in input * @param target target * @return Object object */ @SuppressWarnings({ "unchecked", "rawtypes" }) public T deserialize(Input in, Type target) { byte type = in.readDataType(); log.trace("Type: {} target: {}", type, (target != null ? target.toString() : "Target not specified")); while (type == DataTypes.CORE_SKIP) { type = in.readDataType(); log.trace("Type (skip): {}", type); } log.debug("Datatype: {}", DataTypes.toStringValue(type)); Object result; switch (type) { case DataTypes.CORE_NULL: result = in.readNull(target); break; case DataTypes.CORE_BOOLEAN: result = in.readBoolean(target); break; case DataTypes.CORE_NUMBER: result = in.readNumber(target); break; case DataTypes.CORE_STRING: if (target != null && ((Class) target).isEnum()) { log.warn("Enum target specified"); String name = in.readString(target); result = Enum.valueOf((Class) target, name); } else { result = in.readString(target); } break; case DataTypes.CORE_DATE: result = in.readDate(target); break; case DataTypes.CORE_ARRAY: result = in.readArray(this, target); break; case DataTypes.CORE_MAP: result = in.readMap(this, target); break; case DataTypes.CORE_XML: result = in.readXML(target); break; case DataTypes.CORE_OBJECT: result = in.readObject(this, target); break; case DataTypes.CORE_BYTEARRAY: result = in.readByteArray(target); break; case DataTypes.CORE_VECTOR_INT: result = in.readVectorInt(); break; case DataTypes.CORE_VECTOR_UINT: result = in.readVectorUInt(); break; case DataTypes.CORE_VECTOR_NUMBER: result = in.readVectorNumber(); break; case DataTypes.CORE_VECTOR_OBJECT: result = in.readVectorObject(); break; case DataTypes.OPT_REFERENCE: result = in.readReference(target); break; default: result = in.readCustom(target); break; } return (T) postProcessExtension(result, target); } /** * Post processes the result * TODO Extension Point * @param result result * @param target target * @return object */ protected Object postProcessExtension(Object result, Type target) { // does nothing at the moment, but will later! return result; } } red5-1.0~svn4374.orig/src/org/red5/io/object/DataTypes.java0000644000175000017500000001255111706617130023154 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; /** * The core datatypes supported by red5, I have left out undefined (this is * up for debate). * If a codec returns one of these datatypes its handled by the base * serializer. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class DataTypes { /** * Padding marker */ public static final byte CORE_SKIP = 0x00; // padding /** * Null type marker */ public static final byte CORE_NULL = 0x01; // no undefined type /** * Boolean type marker */ public static final byte CORE_BOOLEAN = 0x02; /** * Number type marker */ public static final byte CORE_NUMBER = 0x03; /** * String type marker */ public static final byte CORE_STRING = 0x04; /** * Date type marker */ public static final byte CORE_DATE = 0x05; // Basic stuctures /** * Array type marker */ public static final byte CORE_ARRAY = 0x06; /** * Map type marker */ public static final byte CORE_MAP = 0x07; /** * XML type marker */ public static final byte CORE_XML = 0x08; /** * Object (Hash) type marker */ public static final byte CORE_OBJECT = 0x09; /** * ByteArray type marker (AMF3 only) */ public static final byte CORE_BYTEARRAY = 0x10; //16 /** * Vector type markers */ public static final byte CORE_VECTOR_INT = 0x0D + 0x30; //61 public static final byte CORE_VECTOR_UINT = 0x0E + 0x30; //62 public static final byte CORE_VECTOR_NUMBER = 0x0F + 0x30; //63 public static final byte CORE_VECTOR_OBJECT = 0x10 + 0x30; //64 /** * Reference type, this is optional for codecs to support */ public static final byte OPT_REFERENCE = 0x11; //17 // More datatypes can be added but they should be prefixed by the type // If a codec return one of these datatypes its handled by a custom // serializer /** * Custom datatype mock mask marker */ public static final byte CUSTOM_MOCK_MASK = 0x20; /** * Custom datatype AMF mask */ public static final byte CUSTOM_AMF_MASK = 0x30; /** * Custom datatype RTMP mask */ public static final byte CUSTOM_RTMP_MASK = 0x40; /** * Custom datatype JSON mask */ public static final byte CUSTOM_JSON_MASK = 0x50; /** * Custom datatype XML mask */ public static final byte CUSTOM_XML_MASK = 0x60; // Some helper methods.. /** * Returns the string value of the data type * * @return String String value of given ActionScript data type * @param dataType AS data type as byte */ public static String toStringValue(byte dataType) { switch (dataType) { case CORE_SKIP: return "skip"; case CORE_NULL: return "null"; case CORE_BOOLEAN: return "Boolean"; case CORE_NUMBER: return "Number"; case CORE_STRING: return "String"; case CORE_DATE: return "Date"; case CORE_ARRAY: return "Array"; case CORE_MAP: return "List"; case CORE_XML: return "XML"; case CORE_OBJECT: return "Object"; case CORE_BYTEARRAY: return "ByteArray"; case CORE_VECTOR_INT: return "Vector"; case CORE_VECTOR_UINT: return "Vector"; case CORE_VECTOR_NUMBER: return "Vector"; case CORE_VECTOR_OBJECT: return "Vector"; case OPT_REFERENCE: return "Reference"; default: } if (dataType >= CUSTOM_MOCK_MASK && dataType < CUSTOM_AMF_MASK) { return "MOCK[" + (dataType - CUSTOM_MOCK_MASK) + ']'; } if (dataType >= CUSTOM_AMF_MASK && dataType < CUSTOM_RTMP_MASK) { return "AMF[" + (dataType - CUSTOM_AMF_MASK) + ']'; } if (dataType >= CUSTOM_RTMP_MASK && dataType < CUSTOM_JSON_MASK) { return "RTMP[" + (dataType - CUSTOM_RTMP_MASK) + ']'; } if (dataType >= CUSTOM_JSON_MASK && dataType < CUSTOM_XML_MASK) { return "JSON[" + (dataType - CUSTOM_JSON_MASK) + ']'; } return "XML[" + (dataType - CUSTOM_XML_MASK) + ']'; } /** * Returns whether it is a basic data type * * @param type Data type as byte * @return boolean true if data type is primitive, false otherwise */ public static boolean isBasicType(byte type) { return type <= CORE_DATE; } /** * Returns whether it is a complex data type * * @param type Data type as byte * @return boolean true if data type is complex (non-primitive), false otherwise */ public static boolean isComplexType(byte type) { return type >= CORE_ARRAY || type <= CORE_OBJECT; } /** * Returns whether it is a custom data type * * @param type Data type as byte * @return boolean Whether given type is of custom type */ public static boolean isCustomType(byte type) { return type >= CUSTOM_AMF_MASK; } } red5-1.0~svn4374.orig/src/org/red5/io/object/RecordSet.java0000644000175000017500000001747311752001621023151 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.red5.server.net.remoting.RemotingClient; /** * Read only RecordSet object that might be received through remoting calls. There are 3 types of data fetching: * *
    *
  • On demand (used by default)
  • *
  • Fetch all at once
  • *
  • Page-by-page fetching
  • *
* *

For last mode, use page size property to specify maximum number of rows on one page

* * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @see osflash.org documentation */ public class RecordSet { /** * On demand fetching mode */ private static final String MODE_ONDEMAND = "ondemand"; /** * Fetch all at once fetching mode */ private static final String MODE_FETCHALL = "fetchall"; /** * Page-by-page fetching mode */ private static final String MODE_PAGE = "page"; /** * Total number of pages */ private int totalCount; /** * Recordset data */ private List> data; /** * Recordset cursor */ private int cursor; /** * Name of service */ private String serviceName; /** * Recordset column names set */ private List columns; /** * Recordset version */ private int version; /** * Recordset id */ private Object id; /** * Remoting client that fetches data */ private RemotingClient client; /** * Fetching mode, on demand by default */ private String mode = MODE_ONDEMAND; /** * Page size */ private int pageSize = 25; /** * Creates recordset from Input object * @param input input */ @SuppressWarnings({ "unchecked" }) public RecordSet(Input input) { // Create deserializer Deserializer deserializer = new Deserializer(); Map dataMap = input.readKeyValues(deserializer); Object map = dataMap.get("serverinfo"); Map serverInfo = null; if (map != null) { if (!(map instanceof Map)) { throw new RuntimeException("Expected Map but got " + map.getClass().getName()); } serverInfo = (Map) map; totalCount = (Integer) serverInfo.get("totalCount"); List> initialData = (List>) serverInfo.get("initialData"); cursor = (Integer) serverInfo.get("cursor"); serviceName = (String) serverInfo.get("serviceName"); columns = (List) serverInfo.get("columnNames"); version = (Integer) serverInfo.get("version"); id = serverInfo.get("id"); this.data = new ArrayList>(totalCount); for (int i = 0; i < initialData.size(); i++) { this.data.add(i + cursor - 1, initialData.get(i)); } } else { throw new RuntimeException("Map (serverinfo) was null"); } } /** * Set the remoting client to use for retrieving of paged results. * * @param client Remoting client that works with this Recordset */ public void setRemotingClient(RemotingClient client) { this.client = client; } /** * Set the mode for fetching paged results. * * @param mode Mode for fetching of results */ public void setDeliveryMode(String mode) { setDeliveryMode(mode, 25, 0); } /** * Set the mode for fetching paged results with given max page size. * * @param mode Mode for fetching of results * @param pageSize Max page size */ public void setDeliveryMode(String mode, int pageSize) { setDeliveryMode(mode, pageSize, 0); } /** * Set the mode for fetching paged results with given max page size and number of prefetched pages. * * @param mode Mode for fetching of results * @param pageSize Max page size * @param prefetchCount Number of prefetched pages (not implemented yet) */ public void setDeliveryMode(String mode, int pageSize, int prefetchCount) { this.mode = mode; this.pageSize = pageSize; } /** * Return a list containing the names of the columns in the recordset. * * @return Column names set */ public List getColumnNames() { return Collections.unmodifiableList(columns); } /** * Make sure the passed item has been fetched from the server. * * @param index Item index */ private void ensureAvailable(int index) { if (data.get(index) != null) { // Already have this item. return; } if (client == null) { throw new RuntimeException("no remoting client configured"); } Object result; int start = index; int count; if (mode.equals(MODE_ONDEMAND)) { // Only get requested item count = 1; } else if (mode.equals(MODE_FETCHALL)) { // Get remaining items count = totalCount - cursor; } else if (mode.equals(MODE_PAGE)) { // Get next page // TODO: implement prefetching of multiple pages count = 1; for (int i = 1; i < pageSize; i++) { if (this.data.get(start + i) == null) { count += 1; } } } else { // Default to "ondemand" count = 1; } result = client.invokeMethod(serviceName + ".getRecords", new Object[] { id, start + 1, count }); if (!(result instanceof RecordSetPage)) { throw new RuntimeException("expected RecordSetPage but got " + result); } RecordSetPage page = (RecordSetPage) result; if (page.getCursor() != start + 1) { throw new RuntimeException("expected offset " + (start + 1) + " but got " + page.getCursor()); } List> data = page.getData(); if (data.size() != count) { throw new RuntimeException("expected " + count + " results but got " + data.size()); } // Store received items for (int i = 0; i < count; i++) { this.data.add(start + i, data.get(i)); } } /** * Return a specified item from the recordset. If the item is not * available yet, it will be received from the server. * * @param index Item index * @return Item from recordset */ public List getItemAt(int index) { if (index < 0 || index >= totalCount) { // Out of range return null; } ensureAvailable(index); return data.get(index); } /** * Get the total number of items. * * @return Number of items */ public int getLength() { return totalCount; } /** * Get the number of items already received from the server. * * @return Nsumber of received items */ public int getNumberAvailable() { int result = 0; for (int i = 0; i < data.size(); i++) { if (data.get(i) != null) { result += 1; } } return result; } /** * Check if all items are available on the client. * * @return number of available items */ public boolean isFullyPopulated() { return getNumberAvailable() == getLength(); } /** * Return Map that can be serialized as result. * * @return serializable informations */ public Map serialize() { Map serverInfo = new HashMap(); serverInfo.put("totalCount", totalCount); serverInfo.put("cursor", cursor); serverInfo.put("serviceName", serviceName); serverInfo.put("columnNames", columns); serverInfo.put("version", version); serverInfo.put("id", id); serverInfo.put("initialData", data); return serverInfo; } } red5-1.0~svn4374.orig/src/org/red5/io/object/UnsignedInt.java0000644000175000017500000000660611706617130023511 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; /** * The UnsignedInt class wraps a value of an unsigned 32 bits number. * * @author Matteo Merli (matteo.merli@gmail.com) */ public final class UnsignedInt extends UnsignedNumber { static final long serialVersionUID = 1L; private long value; public UnsignedInt(byte c) { value = c; } public UnsignedInt(short c) { value = c; } public UnsignedInt(int c) { value = c; } public UnsignedInt(long c) { value = c & 0xFFFFFFFFL; } private UnsignedInt() { value = 0; } public static UnsignedInt fromBytes(byte[] c) { return fromBytes(c, 0); } public static UnsignedInt fromBytes(byte[] c, int idx) { UnsignedInt number = new UnsignedInt(); if ((c.length - idx) < 4) { throw new IllegalArgumentException("An UnsignedInt number is composed of 4 bytes."); } number.value = (c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3]); return number; } public static UnsignedInt fromString(String c) { return fromString(c, 10); } public static UnsignedInt fromString(String c, int radix) { UnsignedInt number = new UnsignedInt(); long v = Long.parseLong(c, radix); number.value = v & 0xFFFFFFFFL; return number; } @Override public double doubleValue() { return value; } @Override public float floatValue() { return value; } @Override public int intValue() { return (int) (value & 0xFFFFFFFFL); } @Override public long longValue() { return value & 0xFFFFFFFFL; } @Override public byte[] getBytes() { byte[] c = new byte[4]; c[0] = (byte) ((value >> 24) & 0xFF); c[1] = (byte) ((value >> 16) & 0xFF); c[2] = (byte) ((value >> 8) & 0xFF); c[3] = (byte) ((value >> 0) & 0xFF); return c; } @Override public int compareTo(UnsignedNumber other) { long otherValue = other.longValue(); if (value > otherValue) return +1; else if (value < otherValue) return -1; return 0; } @Override public boolean equals(Object other) { if (!(other instanceof Number)) return false; return value == ((Number) other).longValue(); } @Override public String toString() { return Long.toString(value & 0xFFFFFFFFL); } @Override public int hashCode() { return (int) (value ^ (value >>> 32)); } @Override public void shiftRight(int nBits) { if (Math.abs(nBits) > 32) throw new IllegalArgumentException("Cannot right shift " + nBits + " an UnsignedInt."); value >>>= nBits; } @Override public void shiftLeft(int nBits) { if (Math.abs(nBits) > 32) throw new IllegalArgumentException("Cannot left shift " + nBits + " an UnsignedInt."); value <<= nBits; } } red5-1.0~svn4374.orig/src/org/red5/io/object/UnsignedByte.java0000644000175000017500000000657011706617130023662 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; /** * The UnsignedByte class wraps a value of and unsigned 8 bits number. * * @author Matteo Merli (matteo.merli@gmail.com) */ public final class UnsignedByte extends UnsignedNumber { static final long serialVersionUID = 1L; private short value; public UnsignedByte(byte c) { value = c; } public UnsignedByte(short c) { value = (short) (c & 0xFF); } public UnsignedByte(int c) { value = (short) (c & 0xFF); } public UnsignedByte(long c) { value = (short) (c & 0xFFL); } private UnsignedByte() { value = 0; } public static UnsignedByte fromBytes(byte[] c) { return fromBytes(c, 0); } public static UnsignedByte fromBytes(byte[] c, int idx) { UnsignedByte number = new UnsignedByte(); if ((c.length - idx) < 1) throw new IllegalArgumentException( "An UnsignedByte number is composed of 1 byte."); number.value = (short) (c[0] & 0xFF); return number; } public static UnsignedByte fromString(String c) { return fromString(c, 10); } public static UnsignedByte fromString(String c, int radix) { UnsignedByte number = new UnsignedByte(); short v = Short.parseShort(c, radix); number.value = (short) (v & 0xFF); return number; } @Override public double doubleValue() { return value; } @Override public float floatValue() { return value; } @Override public short shortValue() { return (short) (value & 0xFF); } @Override public int intValue() { return value & 0xFF; } @Override public long longValue() { return value & 0xFFL; } @Override public byte[] getBytes() { byte[] c = { (byte) (value & 0xFF) }; return c; } @Override public int compareTo(UnsignedNumber other) { short otherValue = other.shortValue(); if (value > otherValue) { return +1; } else if (value < otherValue) { return -1; } return 0; } @Override public boolean equals(Object other) { if (other != null && other instanceof Number) { return value == ((Number) other).shortValue(); } else { return false; } } @Override public int hashCode() { return value; } @Override public String toString() { return Short.toString(value); } @Override public void shiftRight(int nBits) { if (Math.abs(nBits) > 8) { throw new IllegalArgumentException("Cannot right shift " + nBits + " an UnsignedByte."); } value >>>= nBits; } @Override public void shiftLeft(int nBits) { if (Math.abs(nBits) > 8) { throw new IllegalArgumentException("Cannot left shift " + nBits + " an UnsignedByte."); } value <<= nBits; } } red5-1.0~svn4374.orig/src/org/red5/io/object/ICustomSerializable.java0000644000175000017500000000235611706617130025172 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; /** * Interface for objects that know how to serialize their contents. * * NOTE: This is only used for AMF0 encoding and you should not need to * implement this in your own objects. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface ICustomSerializable { /** * Serialize this object to the given output stream. * * @param output output * @param serializer serializer */ public void serialize(Output output, Serializer serializer); } red5-1.0~svn4374.orig/src/org/red5/io/object/UnsignedLong.java0000644000175000017500000001420011706617130023643 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; import java.math.BigInteger; import java.util.Arrays; import java.util.Random; /** * The UnsignedLong class wraps a value of an unsigned 64 bits number. * * @author Matteo Merli (matteo.merli@gmail.com) */ public final class UnsignedLong extends UnsignedNumber { private static final long serialVersionUID = 1L; private byte[] value = new byte[8]; public UnsignedLong(byte c) { Arrays.fill(value, (byte) 0); value[7] = c; } public UnsignedLong(short c) { Arrays.fill(value, (byte) 0); value[6] = (byte) ((c >> 8) & 0xFF); value[7] = (byte) (c & 0xFF); } public UnsignedLong(int c) { Arrays.fill(value, (byte) 0); value[4] = (byte) ((c >> 24) & 0xFF); value[5] = (byte) ((c >> 16) & 0xFF); value[6] = (byte) ((c >> 8) & 0xFF); value[7] = (byte) (c & 0xFF); } public UnsignedLong(long c) { value[0] = (byte) ((c >> 56) & 0xFF); value[1] = (byte) ((c >> 48) & 0xFF); value[2] = (byte) ((c >> 40) & 0xFF); value[3] = (byte) ((c >> 32) & 0xFF); value[4] = (byte) ((c >> 24) & 0xFF); value[5] = (byte) ((c >> 16) & 0xFF); value[6] = (byte) ((c >> 8) & 0xFF); value[7] = (byte) (c & 0xFF); } /** * Construct a new random UnsignedLong. * * @param random * a Random handler */ public UnsignedLong(Random random) { random.nextBytes(value); } private UnsignedLong() { Arrays.fill(value, (byte) 0); } public static UnsignedLong fromBytes(byte[] c) { return fromBytes(c, 0); } public static UnsignedLong fromBytes(byte[] c, int offset) { UnsignedLong number = new UnsignedLong(); if ((c.length - offset) < 8) throw new IllegalArgumentException( "An UnsignedLong number is composed of 8 bytes."); for (int i = 7; i >= 0; i--) number.value[i] = c[offset + i]; return number; } public static UnsignedLong fromString(String c) { return fromString(c, 10); } public static UnsignedLong fromString(String c, int radix) { UnsignedLong number = new UnsignedLong(); BigInteger n = new BigInteger(c, radix); byte[] bytes = n.toByteArray(); int len = Math.min(8, bytes.length); for (int i = 0; i < len; i++) number.value[7 - i] = bytes[bytes.length - 1 - i]; return number; } @Override public byte[] getBytes() { return value; } @Override public String toString() { if ((byte) ((value[0] >> 7) & 0x01) == 1) { value[0] = (byte) (value[0] & 0x7F); BigInteger n = new BigInteger(value); n = n.setBit(63); value[0] = (byte) (value[0] | 0x80); return n.toString(); } else { BigInteger n = new BigInteger(value); return n.toString(); } } @Override public int intValue() { return ((value[4] << 24) & 0xFF000000 | (value[5] << 16) & 0xFF0000 | (value[6] << 8) & 0xFF00 | (value[7] & 0xFF)); } @Override public long longValue() { return (((long) value[0] << 56) & 0xFF00000000000000L | ((long) value[1] << 48) & 0xFF000000000000L | ((long) value[2] << 40) & 0xFF0000000000L | ((long) value[3] << 32) & 0xFF00000000L | ((long) value[4] << 24) & 0xFF000000L | ((long) value[5] << 16) & 0xFF0000L | ((long) value[6] << 8) & 0xFF00L | ((value[7]) & 0xFFL)); } @Override public float floatValue() { return longValue(); } @Override public double doubleValue() { return longValue(); } @Override public int compareTo(UnsignedNumber other) { byte[] otherValue = other.getBytes(); if (otherValue.length > 8) throw new IllegalArgumentException( "The number is more than 8 bytes."); byte[] normalValue = new byte[8]; Arrays.fill(normalValue, (byte) 0); for (int i = 1; i <= otherValue.length; i++) { normalValue[8 - i] = otherValue[otherValue.length - i]; } for (int i = 0; i < 8; i++) if ((char) value[i] > (char) normalValue[i]) return +1; else if ((char) value[i] < (char) normalValue[i]) return -1; return 0; } @Override public boolean equals(Object other) { if (other instanceof UnsignedLong) { // this is a special case byte[] bytes = ((UnsignedLong) other).getBytes(); for (int i = 7; i >= 0; i--) if (value[i] != bytes[i]) return false; return true; } else if (other instanceof Number) return longValue() == ((Number) other).longValue(); else return false; } @Override public int hashCode() { int hashCode = 0; for (int i=0; i 64 || nBits < 0) throw new IllegalArgumentException("Cannot right shift " + nBits + " an UnsignedLong."); if (nBits % 8 != 0) throw new IllegalArgumentException("nBits must be a multiple of 8."); int nBytes = nBits / 8; for (int i = 7; i >= nBytes; i--) value[i] = value[i - nBytes]; for (int i = nBytes - 1; i >= 0; i--) value[i] = 0; } @Override public void shiftLeft(int nBits) { if (nBits > 64 || nBits < 0) throw new IllegalArgumentException("Cannot left shift " + nBits + " an UnsignedLong."); if (nBits % 8 != 0) throw new IllegalArgumentException("nBits must be a multiple of 8."); int nBytes = nBits / 8; for (int i = 0; i <= 7 - nBytes; i++) { value[i] = value[i + nBytes]; } for (int i = 8 - nBytes; i < 8; i++) { value[i] = 0; } } } red5-1.0~svn4374.orig/src/org/red5/io/object/Serializer.java0000644000175000017500000002656211706617130023376 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Vector; import org.apache.commons.beanutils.BeanMap; import org.red5.annotations.DontSerialize; import org.red5.annotations.RemoteClass; import org.red5.io.amf3.ByteArray; import org.red5.io.amf3.IExternalizable; import org.red5.io.utils.ObjectMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; /** * The Serializer class writes data output and handles the data according to the * core data types * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Harald Radi (harald.radi@nme.at) */ public class Serializer { protected static Logger log = LoggerFactory.getLogger(Serializer.class); /** * Serializes output to a core data type object * * @param out Output writer * @param any Object to serialize */ public void serialize(Output out, Object any) { serialize(out, null, null, null, any); } /** * Serializes output to a core data type object * * @param out Output writer * @param field The field to serialize * @param getter The getter method if not a field * @param object Parent object * @param value Object to serialize */ @SuppressWarnings("unchecked") public void serialize(Output out, Field field, Method getter, Object object, Object value) { log.trace("serialize"); if (value instanceof IExternalizable) { // make sure all IExternalizable objects are serialized as objects out.writeObject(value, this); } else if (value instanceof ByteArray) { // write ByteArray objects directly out.writeByteArray((ByteArray) value); } else if (value instanceof Vector) { log.trace("Serialize Vector"); // scan the vector to determine the generic type Vector vector = (Vector) value; int ints = 0; int longs = 0; int dubs = 0; int nans = 0; for (Object o : vector) { if (o instanceof Integer) { ints++; } else if (o instanceof Long) { longs++; } else if (o instanceof Number || o instanceof Double) { dubs++; } else { nans++; } } // look at the type counts if (nans > 0) { // if we have non-number types, use object ((org.red5.io.amf3.Output) out).enforceAMF3(); out.writeVectorObject((Vector) value); } else if (dubs == 0 && longs == 0) { // no doubles or longs out.writeVectorInt((Vector) value); } else if (dubs == 0 && ints == 0) { // no doubles or ints out.writeVectorUInt((Vector) value); } else { // handle any other types of numbers ((org.red5.io.amf3.Output) out).enforceAMF3(); out.writeVectorNumber((Vector) value); } } else { if (writeBasic(out, value)) { log.trace("Wrote as basic"); } else if (!writeComplex(out, value)) { log.trace("Unable to serialize: {}", value); } } } /** * Writes a primitive out as an object * * @param out * Output writer * @param basic * Primitive * @return boolean true if object was successfully serialized, false * otherwise */ @SuppressWarnings("rawtypes") protected boolean writeBasic(Output out, Object basic) { if (basic == null) { out.writeNull(); } else if (basic instanceof Boolean) { out.writeBoolean((Boolean) basic); } else if (basic instanceof Number) { out.writeNumber((Number) basic); } else if (basic instanceof String) { out.writeString((String) basic); } else if (basic instanceof Enum) { out.writeString(((Enum) basic).name()); } else if (basic instanceof Date) { out.writeDate((Date) basic); } else { return false; } return true; } /** * Writes a complex type object out * * @param out Output writer * @param complex Complex datatype object * @return boolean true if object was successfully serialized, false * otherwise */ public boolean writeComplex(Output out, Object complex) { log.trace("writeComplex"); if (writeListType(out, complex)) { return true; } else if (writeArrayType(out, complex)) { return true; } else if (writeXMLType(out, complex)) { return true; } else if (writeCustomType(out, complex)) { return true; } else if (writeObjectType(out, complex)) { return true; } else { return false; } } /** * Writes Lists out as a data type * * @param out * Output write * @param listType * List type * @return boolean true if object was successfully serialized, false * otherwise */ protected boolean writeListType(Output out, Object listType) { log.trace("writeListType"); if (listType instanceof List) { writeList(out, (List) listType); } else { return false; } return true; } /** * Writes a List out as an Object * * @param out * Output writer * @param list * List to write as Object */ protected void writeList(Output out, List list) { if (!list.isEmpty()) { int size = list.size(); // if its a small list, write it as an array if (size < 100) { out.writeArray(list, this); return; } // else we should check for lots of null values, // if there are over 80% then its probably best to do it as a map int nullCount = 0; for (int i = 0; i < size; i++) { if (list.get(i) == null) { nullCount++; } } if (nullCount > (size * 0.8)) { out.writeMap(list, this); } else { out.writeArray(list, this); } } else { out.writeArray(new Object[] {}, this); } } /** * Writes array (or collection) out as output Arrays, Collections, etc * * @param out * Output object * @param arrType * Array or collection type * @return true if the object has been written, otherwise * false */ @SuppressWarnings("all") protected boolean writeArrayType(Output out, Object arrType) { log.trace("writeArrayType"); if (arrType instanceof Collection) { out.writeArray((Collection) arrType, this); } else if (arrType instanceof Iterator) { writeIterator(out, (Iterator) arrType); } else if (arrType.getClass().isArray() && arrType.getClass().getComponentType().isPrimitive()) { out.writeArray(arrType, this); } else if (arrType instanceof Object[]) { out.writeArray((Object[]) arrType, this); } else { return false; } return true; } /** * Writes an iterator out to the output * * @param out * Output writer * @param it * Iterator to write */ protected void writeIterator(Output out, Iterator it) { log.trace("writeIterator"); // Create LinkedList of collection we iterate thru and write it out later LinkedList list = new LinkedList(); while (it.hasNext()) { list.addLast(it.next()); } // Write out collection out.writeArray(list, this); } /** * Writes an xml type out to the output * * @param out * Output writer * @param xml * XML * @return boolean true if object was successfully written, * false otherwise */ protected boolean writeXMLType(Output out, Object xml) { log.trace("writeXMLType"); // If it's a Document write it as Document if (xml instanceof Document) { writeDocument(out, (Document) xml); } else { return false; } return true; } /** * Writes a document to the output * * @param out * Output writer * @param doc * Document to write */ protected void writeDocument(Output out, Document doc) { out.writeXML(doc); } /** * Write typed object to the output * * @param out * Output writer * @param obj * Object type to write * @return true if the object has been written, otherwise * false */ @SuppressWarnings("all") protected boolean writeObjectType(Output out, Object obj) { if (obj instanceof ObjectMap || obj instanceof BeanMap) { out.writeObject((Map) obj, this); } else if (obj instanceof Map) { out.writeMap((Map) obj, this); } else if (obj instanceof RecordSet) { out.writeRecordSet((RecordSet) obj, this); } else { out.writeObject(obj, this); } return true; } // Extension points /** * Pre processes an object TODO // must be implemented * * @return Prerocessed object * @param any Object to preprocess */ public Object preProcessExtension(Object any) { // Does nothing right now but will later return any; } /** * Writes a custom data to the output * * @param out Output writer * @param obj Custom data * @return true if the object has been written, otherwise * false */ protected boolean writeCustomType(Output out, Object obj) { if (out.isCustom(obj)) { // Write custom data out.writeCustom(obj); return true; } else { return false; } } /** * Checks whether the field should be serialized or not * * @param keyName key name * @param field The field to be serialized * @param getter Getter method for field * @return true if the field should be serialized, otherwise * false */ public boolean serializeField(String keyName, Field field, Method getter) { log.trace("serializeField - keyName: {} field: {} method: {}", new Object[] { keyName, field, getter }); if ("class".equals(keyName)) { return false; } if ((field != null && field.isAnnotationPresent(DontSerialize.class)) || (getter != null && getter.isAnnotationPresent(DontSerialize.class))) { log.trace("Skipping {} because its marked with @DontSerialize", keyName); return false; } log.trace("Serialize field: {}", field); return true; } /** * Handles classes by name, also provides "shortened" class aliases where appropriate. * * @param objectClass * @return class name for given object */ public String getClassName(Class objectClass) { RemoteClass annotation = objectClass.getAnnotation(RemoteClass.class); if (annotation != null) { return annotation.alias(); } String className = objectClass.getName(); if (className.startsWith("org.red5.compatibility.")) { // Strip compatibility prefix from classname className = className.substring(23); if ("flex.messaging.messages.AsyncMessageExt".equals(className)) { className = "DSA"; } else if ("flex.messaging.messages.CommandMessageExt".equals(className)) { className = "DSC"; } else if ("flex.messaging.messages.AcknowledgeMessageExt".equals(className)) { className = "DSK"; } } return className; } }red5-1.0~svn4374.orig/src/org/red5/io/object/RecordSetPage.java0000644000175000017500000000373211706617130023746 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; import java.util.Collections; import java.util.List; import java.util.Map; /** * Result of pageable request, one page of data. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @see osflash.org documentation */ public class RecordSetPage { /** * Recordset cursor */ private int cursor; /** * Data as List */ private List> data; /** * Creates recordset page from Input object * @param input Input object to use as source for data that has to be deserialized */ @SuppressWarnings({ "unchecked", "rawtypes" }) public RecordSetPage(Input input) { Deserializer deserizalizer = new Deserializer(); Map mapResult = deserizalizer.deserialize(input, Map.class); cursor = (Integer) mapResult.get("Cursor"); data = (List>) mapResult.get("Page"); } /** * Getter for recordset cursor * * @return Recordset cursor */ protected int getCursor() { return cursor; } /** * Getter for page data * * @return Page data as unmodifiable list */ protected List> getData() { return Collections.unmodifiableList(data); } } red5-1.0~svn4374.orig/src/org/red5/io/object/BaseInput.java0000644000175000017500000000376711706617130023161 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; import java.util.HashMap; import java.util.Map; /** * BaseInput represents a way to map input to a HashMap. This class * is meant to be extended. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class BaseInput { /** * References map */ protected Map refMap = new HashMap(); /** * References id */ protected int refId; /** * Store an object into a map * @param obj Object to store */ protected int storeReference(Object obj) { int newRefId = refId++; refMap.put(Integer.valueOf(newRefId), obj); return newRefId; } /** * Replace a referenced object with another one. This is used * by the AMF3 deserializer to handle circular references. * * @param refId * @param newRef */ protected void storeReference(int refId, Object newRef) { refMap.put(Integer.valueOf(refId), newRef); } /** * Clears the map */ public void clearReferences() { refMap.clear(); refId = 0; } /** * Returns the object with the parameters id * @param id Object reference id * @return Object Object reference with given id */ protected Object getReference(int id) { return refMap.get(Integer.valueOf(id)); } } red5-1.0~svn4374.orig/src/org/red5/io/object/BaseOutput.java0000644000175000017500000000536011706617130023351 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; import java.util.HashMap; import java.util.Map; /** * BaseOutput represents a way to map input to a HashMap. This class * is meant to be extended. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class BaseOutput { static class IdentityWrapper { /** * Wrapped object */ Object object; /** * Creates wrapper for object * @param object Object to wrap */ public IdentityWrapper(Object object) { this.object = object; } /** {@inheritDoc} */ @Override public int hashCode() { return System.identityHashCode(object); } /** {@inheritDoc} */ @Override public boolean equals(Object object) { if (object instanceof IdentityWrapper) { return ((IdentityWrapper) object).object == this.object; } return false; } } /** * References map */ protected Map refMap; /** * Reference id */ protected short refId; /** * BaseOutput Constructor * */ protected BaseOutput() { refMap = new HashMap(); } /** * Store an object into a map * * @param obj Object to store */ protected void storeReference(Object obj) { refMap.put(new IdentityWrapper(obj), Short.valueOf(refId++)); } /** * Returns a boolean stating whether the map contains an object with * that key * @param obj Object * @return boolean true if it does contain it, false otherwise */ protected boolean hasReference(Object obj) { return refMap.containsKey(new IdentityWrapper(obj)); } /** * Clears the map */ public void clearReferences() { refMap.clear(); refId = 0; } /** * Returns the reference id based on the parameter obj * * @param obj Object * @return short Reference id */ protected short getReferenceId(Object obj) { return refMap.get(new IdentityWrapper(obj)).shortValue(); } } red5-1.0~svn4374.orig/src/org/red5/io/object/UnsignedShort.java0000644000175000017500000000667111706617130024060 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.object; import java.util.Arrays; /** * The UnsignedByte class wraps a value of an unsigned 16 bits number. * * @author Matteo Merli (matteo.merli@gmail.com) */ public final class UnsignedShort extends UnsignedNumber { static final long serialVersionUID = 1L; private int value; public UnsignedShort(byte c) { value = c; } public UnsignedShort(short c) { value = c; } public UnsignedShort(int c) { value = c & 0xFFFF; } public UnsignedShort(long c) { value = (int) (c & 0xFFFFL); } private UnsignedShort() { value = 0; } public static UnsignedShort fromBytes(byte[] c) { return fromBytes(c, 0); } public static UnsignedShort fromBytes(byte[] c, int idx) { UnsignedShort number = new UnsignedShort(); if ((c.length - idx) < 2) { throw new IllegalArgumentException( "An UnsignedShort number is composed of 2 bytes."); } number.value = ((c[0] << 8) | (c[1] & 0xFFFF)); return number; } public static UnsignedShort fromString(String c) { return fromString(c, 10); } public static UnsignedShort fromString(String c, int radix) { UnsignedShort number = new UnsignedShort(); long v = Integer.parseInt(c, radix); number.value = (int) (v & 0xFFFF); return number; } @Override public double doubleValue() { return value; } @Override public float floatValue() { return value; } @Override public short shortValue() { return (short) (value & 0xFFFF); } @Override public int intValue() { return value & 0xFFFF; } @Override public long longValue() { return value & 0xFFFFL; } @Override public byte[] getBytes() { return new byte[]{(byte) ((value >> 8) & 0xFF), (byte) (value & 0xFF)}; } @Override public int compareTo(UnsignedNumber other) { int otherValue = other.intValue(); if (value > otherValue) { return 1; } else if (value < otherValue) { return -1; } return 0; } @Override public boolean equals(Object other) { if (other instanceof Number) { return Arrays.equals(getBytes(), ((UnsignedNumber) other).getBytes()); } else { return false; } } @Override public int hashCode() { return value; } @Override public String toString() { return Integer.toString(value); } @Override public void shiftRight(int nBits) { if (Math.abs(nBits) > 16) { throw new IllegalArgumentException("Cannot right shift " + nBits + " an UnsignedShort."); } value >>>= nBits; } @Override public void shiftLeft(int nBits) { if (Math.abs(nBits) > 16) { throw new IllegalArgumentException("Cannot left shift " + nBits + " an UnsignedShort."); } value <<= nBits; } } red5-1.0~svn4374.orig/src/org/red5/io/IoConstants.java0000644000175000017500000001027711706617130022257 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; /** * Constants found in FLV files / streams. * */ public interface IoConstants { /** * Video data */ public static final byte TYPE_VIDEO = 0x09; /** * Audio data */ public static final byte TYPE_AUDIO = 0x08; /** * Metadata */ public static final byte TYPE_METADATA = 0x12; /** * Encryption */ public static final byte TYPE_ENCRYPTED = 0x20; /** * Encrypted audio data */ public static final byte TYPE_ENCRYPTED_AUDIO = TYPE_AUDIO + TYPE_ENCRYPTED; /** * Encrypted video data */ public static final byte TYPE_ENCRYPTED_VIDEO = TYPE_VIDEO + TYPE_ENCRYPTED; /** * Encrypted meta data */ public static final byte TYPE_ENCRYPTED_METADATA = TYPE_METADATA + TYPE_ENCRYPTED; /** * Mask sound type */ public static final byte MASK_SOUND_TYPE = 0x01; /** * Mono mode */ public static final byte FLAG_TYPE_MONO = 0x00; /** * Stereo mode */ public static final byte FLAG_TYPE_STEREO = 0x01; /** * Mask sound size */ public static final byte MASK_SOUND_SIZE = 0x02; /** * 8 bit flag size */ public static final byte FLAG_SIZE_8_BIT = 0x00; /** * 16 bit flag size */ public static final byte FLAG_SIZE_16_BIT = 0x01; /** * Mask sound rate */ public static final byte MASK_SOUND_RATE = 0x0C; /** * 5.5 KHz rate flag */ public static final byte FLAG_RATE_5_5_KHZ = 0x00; /** * 11 KHz rate flag */ public static final byte FLAG_RATE_11_KHZ = 0x01; /** * 22 KHz rate flag */ public static final byte FLAG_RATE_22_KHZ = 0x02; /** * 44 KHz rate flag */ public static final byte FLAG_RATE_44_KHZ = 0x03; /** * 48 KHz rate flag */ public static final byte FLAG_RATE_48_KHZ = 0x04; /** * Mask sound format (unsigned) */ public static final int MASK_SOUND_FORMAT = 0xf0; /** * Raw data format flag */ public static final byte FLAG_FORMAT_RAW = 0x00; /** * ADPCM format flag */ public static final byte FLAG_FORMAT_ADPCM = 0x01; /** * MP3 format flag */ public static final byte FLAG_FORMAT_MP3 = 0x02; /** * 8 KHz NellyMoser audio format flag */ public static final byte FLAG_FORMAT_NELLYMOSER_8_KHZ = 0x05; /** * NellyMoser-encoded audio format flag */ public static final byte FLAG_FORMAT_NELLYMOSER = 0x06; /** * Mask video codec */ public static final byte MASK_VIDEO_CODEC = 0x0F; /** * H263 codec flag */ public static final byte FLAG_CODEC_H263 = 0x02; /** * Screen codec flag */ public static final byte FLAG_CODEC_SCREEN = 0x03; /** * On2 VP6 codec flag */ public static final byte FLAG_CODEC_VP6 = 0x04; /** * Video frametype flag */ public static final int MASK_VIDEO_FRAMETYPE = 0xf0; /** * Keyframe type flag */ public static final byte FLAG_FRAMETYPE_KEYFRAME = 0x01; /** * Interframe flag. Interframes are created from keyframes rather than independent image */ public static final byte FLAG_FRAMETYPE_INTERFRAME = 0x02; /** * Disposable frame type flag */ public static final byte FLAG_FRAMETYPE_DISPOSABLE = 0x03; /** * Generated keyframe type flag */ public static final byte FLAG_FRAMETYPE_GENERATED_KEYFRAME = 0x04; /** * Info frame type flag */ public static final byte FLAG_FRAMETYPE_INFO = 0x05; public static final byte AVC_PACKET_TYPE_SEQUENCE_HEADER = 0x00; public static final byte AVC_PACKET_TYPE_NALU = 0x01; public static final byte AVC_PACKET_TYPE_END_OF_SEQUENCE = 0x02; public static final byte INFO_PACKET_SEEK_START = 0x00; public static final byte INFO_PACKET_SEEK_END = 0x01; } red5-1.0~svn4374.orig/src/org/red5/io/BufferType.java0000644000175000017500000000152711706617130022064 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; /** * Buffer types (auto, direct or heap). */ public enum BufferType { AUTO, DIRECT, HEAP }red5-1.0~svn4374.orig/src/org/red5/io/mock/0000755000175000017500000000000011760512574020100 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/mock/Input.java0000644000175000017500000000702711706617130022042 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mock; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Vector; import java.lang.reflect.Type; import org.red5.io.amf3.ByteArray; import org.red5.io.object.BaseInput; import org.red5.io.object.Deserializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; public class Input extends BaseInput implements org.red5.io.object.Input { protected static Logger log = LoggerFactory.getLogger(Input.class); protected List list; protected int idx; public Input(List list) { super(); this.list = list; this.idx = 0; } /** * Getter for property 'next'. * * @return Value for property 'next'. */ protected Object getNext() { return list.get(idx++); } /** {@inheritDoc} */ public byte readDataType() { Byte b = (Byte) getNext(); return b.byteValue(); } // Basic /** {@inheritDoc} */ public Object readNull(Type target) { return null; } /** {@inheritDoc} */ public Boolean readBoolean(Type target) { return (Boolean) getNext(); } /** {@inheritDoc} */ public Number readNumber(Type target) { return (Number) getNext(); } /** {@inheritDoc} */ public String getString() { return (String) getNext(); } /** {@inheritDoc} */ public String readString(Type target) { return (String) getNext(); } /** {@inheritDoc} */ public Date readDate(Type target) { return (Date) getNext(); } // Array /** {@inheritDoc} */ public Object readArray(Deserializer deserializer, Type target) { return getNext(); } /** {@inheritDoc} */ public Object readMap(Deserializer deserializer, Type target) { return getNext(); } /** {@inheritDoc} */ @SuppressWarnings("unchecked") public Map readKeyValues(Deserializer deserializer) { return (Map) getNext(); } // Object /** {@inheritDoc} */ public Object readObject(Deserializer deserializer, Type target) { return getNext(); } /** {@inheritDoc} */ public Document readXML(Type target) { return (Document) getNext(); } /** {@inheritDoc} */ public Object readCustom(Type target) { // Not supported return null; } /** {@inheritDoc} */ public ByteArray readByteArray(Type target) { return (ByteArray) getNext(); } @SuppressWarnings("unchecked") public Vector readVectorInt() { return (Vector) getNext(); } @SuppressWarnings("unchecked") public Vector readVectorUInt() { return (Vector) getNext(); } @SuppressWarnings("unchecked") public Vector readVectorNumber() { return (Vector) getNext(); } @SuppressWarnings("unchecked") public Vector readVectorObject() { return (Vector) getNext(); } /** {@inheritDoc} */ public Object readReference(Type target) { final Short num = (Short) getNext(); return getReference(num.shortValue()); } } red5-1.0~svn4374.orig/src/org/red5/io/mock/Output.java0000644000175000017500000001136711706617130022245 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mock; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Vector; import org.red5.io.amf3.ByteArray; import org.red5.io.object.BaseOutput; import org.red5.io.object.DataTypes; import org.red5.io.object.RecordSet; import org.red5.io.object.Serializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; public class Output extends BaseOutput implements org.red5.io.object.Output { protected static Logger log = LoggerFactory.getLogger(Output.class); protected List list; public Output(List list) { super(); this.list = list; } /** {@inheritDoc} */ public boolean isCustom(Object custom) { // No custom types supported return false; } /** {@inheritDoc} */ public void putString(String string) { list.add(string); } /** {@inheritDoc} */ public boolean supportsDataType(byte type) { // does not yet support references return type <= DataTypes.OPT_REFERENCE; } /** {@inheritDoc} */ public void writeBoolean(Boolean bol) { list.add(Byte.valueOf(DataTypes.CORE_BOOLEAN)); list.add(bol); } /** {@inheritDoc} */ public void writeCustom(Object custom) { // Customs not supported by this version } /** {@inheritDoc} */ public void writeDate(Date date) { list.add(Byte.valueOf(DataTypes.CORE_DATE)); list.add(date); } /** {@inheritDoc} */ // DONE public void writeNull() { list.add(Byte.valueOf(DataTypes.CORE_NULL)); } /** {@inheritDoc} */ // DONE public void writeNumber(Number num) { list.add(Byte.valueOf(DataTypes.CORE_NUMBER)); list.add(num); } /** {@inheritDoc} */ public void writeReference(Object obj) { list.add(Byte.valueOf(DataTypes.OPT_REFERENCE)); list.add(Short.valueOf(getReferenceId(obj))); } /** {@inheritDoc} */ public void writeString(String string) { list.add(Byte.valueOf(DataTypes.CORE_STRING)); list.add(string); } /** {@inheritDoc} */ public void writeXML(Document xml) { list.add(Byte.valueOf(DataTypes.CORE_XML)); list.add(xml); } /** {@inheritDoc} */ public void writeArray(Collection array, Serializer serializer) { list.add(Byte.valueOf(DataTypes.CORE_ARRAY)); list.add(array); } /** {@inheritDoc} */ public void writeArray(Object[] array, Serializer serializer) { list.add(Byte.valueOf(DataTypes.CORE_ARRAY)); list.add(array); } /** {@inheritDoc} */ public void writeArray(Object array, Serializer serializer) { list.add(Byte.valueOf(DataTypes.CORE_ARRAY)); list.add(array); } /** {@inheritDoc} */ public void writeMap(Map map, Serializer serializer) { list.add(Byte.valueOf(DataTypes.CORE_MAP)); list.add(map); } /** {@inheritDoc} */ public void writeMap(Collection array, Serializer serializer) { list.add(Byte.valueOf(DataTypes.CORE_MAP)); list.add(array); } /** {@inheritDoc} */ public void writeObject(Object object, Serializer serializer) { list.add(Byte.valueOf(DataTypes.CORE_OBJECT)); list.add(object); } /** {@inheritDoc} */ public void writeObject(Map map, Serializer serializer) { list.add(Byte.valueOf(DataTypes.CORE_OBJECT)); list.add(map); } /** {@inheritDoc} */ public void writeRecordSet(RecordSet recordset, Serializer serializer) { list.add(Byte.valueOf(DataTypes.CORE_OBJECT)); list.add(recordset); } /** {@inheritDoc} */ public void writeByteArray(ByteArray array) { list.add(Byte.valueOf(DataTypes.CORE_BYTEARRAY)); list.add(array); } /** {@inheritDoc} */ public void writeVectorInt(Vector vector) { list.add(Byte.valueOf(DataTypes.CORE_VECTOR_INT)); list.add(vector); } /** {@inheritDoc} */ public void writeVectorUInt(Vector vector) { list.add(Byte.valueOf(DataTypes.CORE_VECTOR_UINT)); list.add(vector); } /** {@inheritDoc} */ public void writeVectorNumber(Vector vector) { list.add(Byte.valueOf(DataTypes.CORE_VECTOR_NUMBER)); list.add(vector); } /** {@inheritDoc} */ public void writeVectorObject(Vector vector) { list.add(Byte.valueOf(DataTypes.CORE_VECTOR_OBJECT)); list.add(vector); } } red5-1.0~svn4374.orig/src/org/red5/io/mock/Mock.java0000644000175000017500000000463111706617130021632 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mock; import java.util.Iterator; import java.util.List; import org.red5.io.object.DataTypes; public class Mock { public static final byte TYPE_END_OF_OBJECT = (byte) (DataTypes.CUSTOM_MOCK_MASK + 0x01); public static final byte TYPE_END_OF_ARRAY = (byte) (DataTypes.CUSTOM_MOCK_MASK + 0x02); public static final byte TYPE_ELEMENT_SEPARATOR = (byte) (DataTypes.CUSTOM_MOCK_MASK + 0x03); public static final byte TYPE_PROPERTY_SEPARATOR = (byte) (DataTypes.CUSTOM_MOCK_MASK + 0x04); public static final byte TYPE_ITEM_SEPARATOR = (byte) (DataTypes.CUSTOM_MOCK_MASK + 0x05); public static final byte TYPE_END_OF_MAP = (byte) (DataTypes.CUSTOM_MOCK_MASK + 0x06); public static String toStringValue(byte dataType) { switch (dataType) { case TYPE_END_OF_OBJECT: return "End of Object"; case TYPE_END_OF_ARRAY: return "End of Array"; case TYPE_ELEMENT_SEPARATOR: case TYPE_ITEM_SEPARATOR: return ","; case TYPE_PROPERTY_SEPARATOR: return "::"; default: return "MOCK[" + (dataType - DataTypes.CUSTOM_MOCK_MASK) + ']'; } } public static String listToString(List list) { StringBuffer sb = new StringBuffer(); Iterator it = list.iterator(); while (it.hasNext()) { Object val = it.next(); if (val instanceof Byte) { byte type = ((Byte) val).byteValue(); if (type < DataTypes.CUSTOM_MOCK_MASK) { sb.append(DataTypes.toStringValue(type)); } else { sb.append(toStringValue(type)); } } else { if (val != null) { sb.append(val.getClass().getName()); } sb.append(" { "); sb.append(val == null ? null : val.toString()); sb.append(" } "); } sb.append(" | "); } return sb.toString(); } } red5-1.0~svn4374.orig/src/org/red5/io/IStreamableFileService.java0000644000175000017500000000474311706617130024325 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; import java.io.File; import java.io.IOException; /** * Provides access to files that can be streamed. */ public interface IStreamableFileService { /** * Sets the prefix. * * @param prefix */ public void setPrefix(String prefix); /** * Getter for prefix. Prefix is used in filename composition to fetch real file name. * * @return Prefix */ public String getPrefix(); /** * Sets the file extensions serviced. If there are more than one, they are separated * by commas. * * @param extension */ public void setExtension(String extension); /** * Getter for extension of file * * @return File extension that is used */ public String getExtension(); /** * Prepair given string to conform filename requirements, for example, add * extension to the end if missing. * @param name String to format * @return Correct filename */ public String prepareFilename(String name); /** * Check whether file can be used by file service, that is, it does exist and have valid extension * @param file File object * @return true if file exist and has valid extension, * false otherwise */ public boolean canHandle(File file); /** * Return streamable file reference. For FLV files returned streamable file already has * generated metadata injected. * * @param file File resource * @return Streamable file resource * @throws IOException Thrown if there were problems accessing given file */ public IStreamableFile getStreamableFile(File file) throws IOException; } red5-1.0~svn4374.orig/src/org/red5/io/IStreamableFile.java0000644000175000017500000000320711706617130022776 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; import java.io.IOException; /** * Interface represents streamable file with tag reader and writers (one for plain mode and one for append) */ public interface IStreamableFile { /** * Returns a reader to parse and read the tags inside the file. * * @return the reader Tag reader * @throws java.io.IOException I/O exception */ public ITagReader getReader() throws IOException; /** * Returns a writer that creates a new file or truncates existing contents. * * @return the writer Tag writer * @throws java.io.IOException I/O exception */ public ITagWriter getWriter() throws IOException; /** * Returns a Writer which is setup to append to the file. * * @return the writer Tag writer used for append mode * @throws java.io.IOException I/O exception */ public ITagWriter getAppendWriter() throws IOException; } red5-1.0~svn4374.orig/src/org/red5/io/utils/0000755000175000017500000000000011760512574020307 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/utils/ArrayUtils.java0000644000175000017500000001141711706617130023247 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.utils; import java.lang.reflect.Array; import java.util.Collection; public final class ArrayUtils { @SuppressWarnings({ "rawtypes" }) public static Object toArray(Class type, Collection collection) { if (byte.class.isAssignableFrom(type)) { return toByteArray(collection); } else if (short.class.isAssignableFrom(type)) { return toShortArray(collection); } else if (int.class.isAssignableFrom(type)) { return toIntegerArray(collection); } else if (long.class.isAssignableFrom(type)) { return toLongArray(collection); } else if (float.class.isAssignableFrom(type)) { return toFloatArray(collection); } else if (double.class.isAssignableFrom(type)) { return toDoubleArray(collection); } else if (boolean.class.isAssignableFrom(type)) { return toBooleanArray(collection); } else if (char.class.isAssignableFrom(type)) { return toCharacterArray(collection); } else { return toObjectArray(type, collection); } } @SuppressWarnings({ "rawtypes" }) private static Object toByteArray(Collection collection) { byte[] ba = new byte[collection.size()]; int i = 0; for (Object o : collection) { byte b = ((Byte) o).byteValue(); ba[i++] = b; } return ba; } @SuppressWarnings({ "rawtypes" }) private static Object toShortArray(Collection collection) { short[] sa = new short[collection.size()]; int i = 0; for (Object o : collection) { short s = ((Short) o).shortValue(); sa[i++] = s; } return sa; } @SuppressWarnings({ "rawtypes" }) private static Object toIntegerArray(Collection collection) { int[] ia = new int[collection.size()]; int i = 0; for (Object o : collection) { int j = ((Integer) o).intValue(); ia[i++] = j; } return ia; } @SuppressWarnings({ "rawtypes" }) private static Object toLongArray(Collection collection) { long[] la = new long[collection.size()]; int i = 0; for (Object o : collection) { long l = ((Long) o).longValue(); la[i++] = l; } return la; } @SuppressWarnings({ "rawtypes" }) private static Object toFloatArray(Collection collection) { float[] fa = new float[collection.size()]; int i = 0; for (Object o : collection) { float f = ((Float) o).floatValue(); fa[i++] = f; } return fa; } @SuppressWarnings({ "rawtypes" }) private static Object toDoubleArray(Collection collection) { double[] da = new double[collection.size()]; int i = 0; for (Object o : collection) { double d; if (o instanceof Integer) { d = (Integer) o; } else { d = ((Double) o).doubleValue(); } da[i++] = d; } return da; } @SuppressWarnings({ "rawtypes" }) private static Object toBooleanArray(Collection collection) { boolean[] ba = new boolean[collection.size()]; int i = 0; for (Object o : collection) { boolean b = ((Boolean) o).booleanValue(); ba[i++] = b; } return ba; } @SuppressWarnings({ "rawtypes" }) private static Object toCharacterArray(Collection collection) { char[] ca = new char[collection.size()]; int i = 0; for (Object o : collection) { char c = ((Character) o).charValue(); ca[i++] = c; } return ca; } @SuppressWarnings({ "unchecked", "rawtypes" }) private static Object toObjectArray(Class type, Collection collection) { return collection.toArray((Object[]) Array.newInstance(type, collection.size())); } public static Class getGenericType(Class nested) { if (nested == byte.class) { nested = Byte.class; } else if (nested == short.class) { nested = Short.class; } else if (nested == int.class) { nested = Integer.class; } else if (nested == long.class) { nested = Long.class; } else if (nested == float.class) { nested = Float.class; } else if (nested == Double.class) { nested = Double.class; } else if (nested == boolean.class) { nested = Boolean.class; } else if (nested == Character.class) { nested = Character.class; } return nested; } } red5-1.0~svn4374.orig/src/org/red5/io/utils/RandomGUID.java0000644000175000017500000002365611706617130023051 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.utils; /* * RandomGUID * @version 1.2.1 11/05/02 * @author Marc A. Mnich * * From www.JavaExchange.com, Open Software licensing * * 11/05/02 -- Performance enhancement from Mike Dubman. * Moved InetAddr.getLocal to static block. Mike has measured * a 10 fold improvement in run time. * 01/29/02 -- Bug fix: Improper seeding of nonsecure Random object * caused duplicate GUIDs to be produced. Random object * is now only created once per JVM. * 01/19/02 -- Modified random seeding and added new constructor * to allow secure random feature. * 01/14/02 -- Added random function seeding with JVM run time * */ import java.net.InetAddress; import java.net.UnknownHostException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Random; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /* * In the multitude of java GUID generators, I found none that * guaranteed randomness. GUIDs are guaranteed to be globally unique * by using ethernet MACs, IP addresses, time elements, and sequential * numbers. GUIDs are not expected to be random and most often are * easy/possible to guess given a sample from a given generator. * SQL Server, for example generates GUID that are unique but * sequential within a given instance. * * GUIDs can be used as security devices to hide things such as * files within a filesystem where listings are unavailable (e.g. files * that are served up from a Web server with indexing turned off). * This may be desirable in cases where standard authentication is not * appropriate. In this scenario, the RandomGUIDs are used as directories. * Another example is the use of GUIDs for primary keys in a database * where you want to ensure that the keys are secret. Random GUIDs can * then be used in a URL to prevent hackers (or users) from accessing * records by guessing or simply by incrementing sequential numbers. * * There are many other possibilities of using GUIDs in the realm of * security and encryption where the element of randomness is important. * This class was written for these purposes but can also be used as a * general purpose GUID generator as well. * * RandomGUID generates truly random GUIDs by using the system's * IP address (name/IP), system time in milliseconds (as an integer), * and a very large random number joined together in a single String * that is passed through an MD5 hash. The IP address and system time * make the MD5 seed globally unique and the random number guarantees * that the generated GUIDs will have no discernible pattern and * cannot be guessed given any number of previously generated GUIDs. * It is generally not possible to access the seed information (IP, time, * random number) from the resulting GUIDs as the MD5 hash algorithm * provides one way encryption. * * ----> Security of RandomGUID: <----- * RandomGUID can be called one of two ways -- with the basic java Random * number generator or a cryptographically strong random generator * (SecureRandom). The choice is offered because the secure random * generator takes about 3.5 times longer to generate its random numbers * and this performance hit may not be worth the added security * especially considering the basic generator is seeded with a * cryptographically strong random seed. * * Seeding the basic generator in this way effectively decouples * the random numbers from the time component making it virtually impossible * to predict the random number component even if one had absolute knowledge * of the System time. Thanks to Ashutosh Narhari for the suggestion * of using the static method to prime the basic random generator. * * Using the secure random option, this class complies with the statistical * random number generator tests specified in FIPS 140-2, Security * Requirements for Cryptographic Modules, section 4.9.1. * * I converted all the pieces of the seed to a String before handing * it over to the MD5 hash so that you could print it out to make * sure it contains the data you expect to see and to give a nice * warm fuzzy. If you need better performance, you may want to stick * to byte[] arrays. * * I believe that it is important that the algorithm for * generating random GUIDs be open for inspection and modification. * This class is free for all uses. * * * - Marc */ public class RandomGUID extends Object { private static Logger log = LoggerFactory.getLogger(RandomGUID.class); private static final String hexChars = "0123456789ABCDEF"; private static Random myRand; private static SecureRandom mySecureRand; private static String s_id; public String valueBeforeMD5 = ""; public String valueAfterMD5 = ""; /* * Static block to take care of one time secureRandom seed. * It takes a few seconds to initialize SecureRandom. You might * want to consider removing this static block or replacing * it with a "time since first loaded" seed to reduce this time. * This block will run only once per JVM instance. */ static { mySecureRand = new SecureRandom(); long secureInitializer = mySecureRand.nextLong(); myRand = new Random(secureInitializer); try { s_id = InetAddress.getLocalHost().toString(); } catch (UnknownHostException e) { log.warn("Exception {}", e); } } /* * Default constructor. With no specification of security option, * this constructor defaults to lower security, high performance. */ public RandomGUID() { getRandomGUID(false); } /* * Constructor with security option. Setting secure true * enables each random number generated to be cryptographically * strong. Secure false defaults to the standard Random function seeded * with a single cryptographically strong random number. */ public RandomGUID(boolean secure) { getRandomGUID(secure); } /* * Method to generate the random GUID */ private void getRandomGUID(boolean secure) { MessageDigest md5 = null; StringBuilder sbValueBeforeMD5 = new StringBuilder(); try { md5 = MessageDigest.getInstance("MD5"); long time = System.currentTimeMillis(); long rand = 0; if (secure) { rand = mySecureRand.nextLong(); } else { rand = myRand.nextLong(); } // This StringBuffer can be a long as you need; the MD5 // hash will always return 128 bits. You can change // the seed to include anything you want here. // You could even stream a file through the MD5 making // the odds of guessing it at least as great as that // of guessing the contents of the file! sbValueBeforeMD5.append(s_id); sbValueBeforeMD5.append(':'); sbValueBeforeMD5.append(Long.toString(time)); sbValueBeforeMD5.append(':'); sbValueBeforeMD5.append(Long.toString(rand)); valueBeforeMD5 = sbValueBeforeMD5.toString(); md5.update(valueBeforeMD5.getBytes()); byte[] array = md5.digest(); StringBuilder sb = new StringBuilder(); for (int j = 0; j < array.length; ++j) { int b = array[j] & 0xFF; if (b < 0x10) sb.append('0'); sb.append(Integer.toHexString(b)); } valueAfterMD5 = sb.toString(); } catch (NoSuchAlgorithmException e) { System.out.println("Error: " + e); } catch (Exception e) { System.out.println("Error:" + e); } } /** * Returns a byte array for the given uuid or guid. * * @param uid * @return array of bytes containing the id */ public final static byte[] toByteArray(String uid) { byte[] result = new byte[16]; char[] chars = uid.toCharArray(); int r = 0; for (int i = 0; i < chars.length; ++i) { if (chars[i] == '-') { continue; } int h1 = Character.digit(chars[i], 16); ++i; int h2 = Character.digit(chars[i], 16); result[(r++)] = (byte) ((h1 << 4 | h2) & 0xFF); } return result; } /** * Returns a uuid / guid for a given byte array. * * @param ba array of bytes containing the id * @return id */ public static String fromByteArray(byte[] ba) { if ((ba != null) && (ba.length == 16)) { StringBuilder result = new StringBuilder(36); for (int i = 0; i < 16; ++i) { if ((i == 4) || (i == 6) || (i == 8) || (i == 10)) { result.append('-'); } result.append(hexChars.charAt(((ba[i] & 0xF0) >>> 4))); result.append(hexChars.charAt((ba[i] & 0xF))); } return result.toString(); } return null; } /** * Returns a nice neat formatted string. * * @param str unformatted string * @return formatted string */ public static String getPrettyFormatted(String str) { return String.format("%s-%s-%s-%s-%s", new Object[] { str.substring(0, 8), str.substring(8, 12), str.substring(12, 16), str.substring(16, 20), str.substring(20) }); } /* * Convert to the standard format for GUID * (Useful for SQL Server UniqueIdentifiers, etc.) * Example: C2FEEEAC-CFCD-11D1-8B05-00600806D9B6 */ public String toString() { return RandomGUID.getPrettyFormatted(valueAfterMD5.toUpperCase()); } /* * Demonstraton and self test of class */ public static void main(String args[]) { for (int i = 0; i < 100; i++) { RandomGUID myGUID = new RandomGUID(); System.out.println("Seeding String=" + myGUID.valueBeforeMD5); System.out.println("rawGUID=" + myGUID.valueAfterMD5); System.out.println("RandomGUID=" + myGUID.toString()); } } } red5-1.0~svn4374.orig/src/org/red5/io/utils/Stax2DomBuilder.java0000644000175000017500000002310611706617130024116 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.utils; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; /** * Builds a DOM {@link org.w3c.dom.Document} using a * {@link javax.xml.stream.XMLStreamReader}. * * @version $Revision: 1.00 $, $Date: 2004/12/11 00:00:00 $ * @author Tatu Saloranta */ public class Stax2DomBuilder { /** * Whether ignorable white space should be ignored, ie not added in the * resulting JDOM tree. If true, it will be ignored; if false, it will be * added in the tree. Default value if false. */ protected boolean mCfgIgnoreWs = false; protected boolean mNsAware = true; // // Trivial caching... protected String mLastPrefix = null; protected String mLastLocalName = null; protected String mLastQName = null; /** * Default constructor. */ public Stax2DomBuilder() { } /** * Method used to change whether the build methods will add ignorable * (element) white space in the DOM tree or not. *

* Whether all-whitespace text segment is ignorable white space or not is * based on DTD read in, as per XML specifications (white space is only * significant in mixed content or pure text elements). * @param ignoreWS true to ignore whitespace; false otherwise. */ public void setIgnoreWhitespace(boolean ignoreWS) { mCfgIgnoreWs = ignoreWS; } /** * This method will create a {@link org.w3c.dom.Document} instance using the * default JAXP mechanism and populate using the given StAX stream reader. * * @param r Stream reader from which input is read. * @return Document - DOM document object. * @throws ParserConfigurationException if parse is not configured * @throws XMLStreamException If the reader threw such exception (to indicate a parsing or * I/O problem) */ public Document build(XMLStreamReader r) throws ParserConfigurationException, XMLStreamException { return build(r, DocumentBuilderFactory.newInstance() .newDocumentBuilder()); } public Document build(XMLStreamReader r, DocumentBuilder docbuilder) throws XMLStreamException { Document doc = docbuilder.newDocument(); build(r, doc); return doc; } /** * This method will populate given {@link org.w3c.dom.Document} using the * given StAX stream reader instance. * * @param r Stream reader from which input is read. * @param doc Document - DOM document object. * @throws XMLStreamException If the reader threw such exception (to indicate a parsing or * I/O problem) */ public void build(XMLStreamReader r, Document doc) throws XMLStreamException { buildTree(r, doc); } /** * This method takes a XMLStreamReader and builds up a JDOM * tree. Recursion has been eliminated by using nodes' parent/child * relationship; this improves performance somewhat (classic * recursion-by-iteration-and-explicit stack transformation) * * @param r Stream reader to use for reading the document from which to * build the tree * @param doc JDOM Document being built. * @throws XMLStreamException for fun */ protected void buildTree(XMLStreamReader r, Document doc) throws XMLStreamException { checkReaderSettings(r); Node current = doc; // At top level main_loop: while (true) { int evtType = r.next(); Node child; switch (evtType) { case XMLStreamConstants.CDATA: child = doc.createCDATASection(r.getText()); break; case XMLStreamConstants.SPACE: if (mCfgIgnoreWs) { continue main_loop; } /* * Oh great. DOM is brain-dead in that ignorable white space * can not be added, even though it is legal, and often * reported by StAX/SAX impls... */ if (current == doc) { // better just ignore, thus... continue; } // fall through case XMLStreamConstants.CHARACTERS: child = doc.createTextNode(r.getText()); break; case XMLStreamConstants.COMMENT: child = doc.createComment(r.getText()); break; case XMLStreamConstants.END_DOCUMENT: break main_loop; case XMLStreamConstants.END_ELEMENT: current = current.getParentNode(); if (current == null) { current = doc; } continue main_loop; case XMLStreamConstants.ENTITY_DECLARATION: case XMLStreamConstants.NOTATION_DECLARATION: /* * Shouldn't really get these, but maybe some stream readers * do provide the info. If so, better ignore it -- DTD event * should have most/all we need. */ continue main_loop; case XMLStreamConstants.ENTITY_REFERENCE: child = doc.createEntityReference(r.getLocalName()); break; case XMLStreamConstants.PROCESSING_INSTRUCTION: child = doc.createProcessingInstruction(r.getPITarget(), r .getPIData()); break; case XMLStreamConstants.START_ELEMENT: // Ok, need to add a new element... { String ln = r.getLocalName(); Element newElem; if (mNsAware) { String elemPrefix = r.getPrefix(); // Doh, DOM requires a silly qualified name... if (elemPrefix != null && elemPrefix.length() > 0) { newElem = doc.createElementNS(r.getNamespaceURI(), getQualified(elemPrefix, ln)); } else { newElem = doc.createElementNS(r.getNamespaceURI(), ln); } } else { // if non-ns-aware, things are simpler: newElem = doc.createElement(ln); } /* * No need to check namespace bindings, unlikes with some * other frameworks (JDOM) */ // And then the attributes: for (int i = 0, len = r.getAttributeCount(); i < len; ++i) { ln = r.getAttributeLocalName(i); if (mNsAware) { String prefix = r.getAttributePrefix(i); if (prefix != null && prefix.length() > 0) { ln = getQualified(prefix, ln); } Attr attr = doc.createAttributeNS(r .getAttributeNamespace(i), ln); attr.setValue(r.getAttributeValue(i)); newElem.setAttributeNodeNS(attr); } else { Attr attr = doc.createAttribute(ln); attr.setValue(r.getAttributeValue(i)); newElem.setAttributeNode(attr); } } // And then 'push' new element... current.appendChild(newElem); current = newElem; continue main_loop; } case XMLStreamConstants.START_DOCUMENT: /* * This should only be received at the beginning of * document... so, should we indicate the problem or not? */ /* * For now, let it pass: maybe some (broken) readers pass * that info as first event in beginning of doc? */ continue main_loop; case XMLStreamConstants.DTD: /* * !!! Note: StAX does not expose enough information about * doctype declaration (specifically, public and system * id!); (altough StAX2 would...) * * Worse, DOM1/2 do not specify a way to create the DocType * node, even if StAX provided it. This is pretty silly, all * in all. */ continue main_loop; // Should never get these, from a stream reader: /* * (commented out entries are just FYI; default catches them * all) */ // case XMLStreamConstants.ATTRIBUTE: // case XMLStreamConstants.NAMESPACE: default: throw new XMLStreamException( "Unrecognized iterator event type: " + r.getEventType() + "; should not receive such types (broken stream reader?)"); } if (child != null) { current.appendChild(child); } } } // // // Overridable helper methods: protected String getQualified(String prefix, String localName) { /* * This mostly/only helps with empty/text-only elements... might make * sense to do 'real' caching... */ if (localName.equals(mLastLocalName) && prefix.endsWith(mLastPrefix)) { return mLastQName; } String qn = prefix + ':' + localName; mLastQName = qn; return qn; } protected void checkReaderSettings(XMLStreamReader r) throws XMLStreamException { Object o = r.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE); /* * StAX defaults to namespace aware, so let's use similar logics * (although all compliant implementations really should return a valid * value) */ if ((o instanceof Boolean) && !((Boolean) o).booleanValue()) { mNsAware = false; } else { mNsAware = true; } } } red5-1.0~svn4374.orig/src/org/red5/io/utils/BufferUtils.java0000644000175000017500000000733011706617130023401 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.utils; import org.apache.mina.core.buffer.IoBuffer; /** * Buffer Utility class which reads/writes intergers to the input/output buffer * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Andy Shaules (bowljoman@hotmail.com) */ public class BufferUtils { //private static Logger log = LoggerFactory.getLogger(BufferUtils.class); /** * Writes a Medium Int to the output buffer * * @param out Container to write to * @param value Integer to write */ public static void writeMediumInt(IoBuffer out, int value) { byte[] bytes = new byte[3]; bytes[0] = (byte) ((value >>> 16) & 0x000000FF); bytes[1] = (byte) ((value >>> 8) & 0x000000FF); bytes[2] = (byte) (value & 0x00FF); out.put(bytes); } /** * Reads an unsigned Medium Int from the in buffer * * @param in Source * @return int Integer value */ public static int readUnsignedMediumInt(IoBuffer in) { byte[] bytes = new byte[3]; in.get(bytes); int val = 0; val += (bytes[0] & 0xFF) * 256 * 256; val += (bytes[1] & 0xFF) * 256; val += (bytes[2] & 0xFF); return val; } /** * Reads a Medium Int to the in buffer * * @param in Source * @return int Medium int */ public static int readMediumInt(IoBuffer in) { byte[] bytes = new byte[3]; in.get(bytes); int val = 0; val += bytes[0] * 256 * 256; val += bytes[1] * 256; val += bytes[2]; if (val < 0) { val += 256; } return val; } /** * Puts input buffer stream to output buffer * and returns number of bytes written * @param out Output buffer * @param in Input buffer * @param numBytesMax Number of bytes max * @return int Number of bytes written */ @SuppressWarnings("unused") public final static int put(IoBuffer out, IoBuffer in, int numBytesMax) { //log.trace("Put - out buffer: {} in buffer: {} max bytes: {}", new Object[]{out, in, numBytesMax}); int limit = in.limit(); int capacity = in.capacity(); int numBytesRead = (numBytesMax > in.remaining()) ? in.remaining() : numBytesMax; //log.trace("limit: {} capacity: {} bytes read: {}", new Object[]{limit, capacity, numBytesRead}); // buffer.limit // The new limit value, must be non-negative and no larger than this buffer's capacity // http://java.sun.com/j2se/1.4.2/docs/api/java/nio/Buffer.html#limit(int); // This is causing decoding error by raising RuntimeException IllegalArgumentError in // RTMPProtocolDecoder.decode to ProtocolException. int thisLimit = (in.position() + numBytesRead <= in.capacity()) ? in.position() + numBytesRead : capacity; //somehow the "in" buffer becomes null here occasionally if (in != null) { in.limit(thisLimit); // any implication to giving output buffer in with limit set to capacity? // Reduces numBytesRead, triggers continueDecode? out.put(in); } else { numBytesRead = 0; } in.limit(limit); return numBytesRead; } } red5-1.0~svn4374.orig/src/org/red5/io/utils/DOM2Writer.java0000644000175000017500000000675711706617130023061 0ustar drazzibdrazzib /* * Copyright 2001-2011 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.utils; import java.io.PrintWriter; import java.io.Writer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Attr; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * This class is a utility to serialize a DOM node as XML. This class uses the * DOM Level 2 APIs. The main difference between this class and * DOMWriter is that this class generates and prints out namespace declarations. * * @author Matthew J. Duftler (duftler@us.ibm.com) * @author Joseph Kesselman */ public class DOM2Writer { private static Logger logger = LoggerFactory.getLogger(DOM2Writer.class); /** * Serialize this node into the writer as XML. * * @param writer Writer object * @param node DOM node */ public static void serializeAsXML(Node node, Writer writer) { PrintWriter out = new PrintWriter(writer); print(node, out); out.flush(); } /** * Dumps DOM node * * @param node * Node to dump * @param out * Writer object */ private static void print(Node node, PrintWriter out) { if (node == null) { return; } boolean hasChildren = false; int type = node.getNodeType(); NodeList children = null; switch (type) { case Node.DOCUMENT_NODE: children = node.getChildNodes(); if (children != null) { int numChildren = children.getLength(); for (int i = 0; i < numChildren; i++) { print(children.item(i), out); } } break; case Node.ELEMENT_NODE: out.print('<'); out.print(node.getNodeName()); if (node.hasAttributes()) { NamedNodeMap attrs = node.getAttributes(); int len = (attrs != null) ? attrs.getLength() : 0; for (int a = 0; a < len; a++) { Attr attr = (Attr) attrs.item(a); out.print(' '); out.print(attr.getNodeName()); out.print("=\""); out.print(attr.getValue()); out.print('\"'); } } children = node.getChildNodes(); if (children != null) { int numChildren = children.getLength(); hasChildren = (numChildren > 0); if (hasChildren) { out.print('>'); } for (int i = 0; i < numChildren; i++) { print(children.item(i), out); } } else { hasChildren = false; } if (!hasChildren) { out.print("/>"); } break; case Node.ENTITY_REFERENCE_NODE: out.print('&'); out.print(node.getNodeName()); out.print(';'); break; case Node.CDATA_SECTION_NODE: out.print(""); break; case Node.TEXT_NODE: out.print(node.getNodeValue()); break; default: if (logger.isDebugEnabled()) { logger.debug("Unknown type: " + type); } } if (type == Node.ELEMENT_NODE && hasChildren) { out.print("'); hasChildren = false; } } } red5-1.0~svn4374.orig/src/org/red5/io/utils/ObjectMap.java0000644000175000017500000000211711706617130023011 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.utils; import java.util.HashMap; /** * Map that should be transmitted as object through RTMP. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @param key type * @param value type */ public class ObjectMap extends HashMap { private static final long serialVersionUID = 5146266119400305646L; } red5-1.0~svn4374.orig/src/org/red5/io/utils/HexDump.java0000644000175000017500000004572411616523204022530 0ustar drazzibdrazzib/* * Copyright 1999-2011 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.red5.io.utils; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.nio.charset.UnsupportedCharsetException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Hexadecimal byte dumper * * @author Niko Schweitzer */ public class HexDump { /** * Logger */ private static final Logger logger = LoggerFactory.getLogger(HexDump.class); /** * Method prettyPrintHex * * * @param bbToConvert ByteBuffer to encode * @return Hexdump string */ public static String prettyPrintHex(ByteBuffer bbToConvert) { return prettyPrintHex(bbToConvert.array()); } /** * Method prettyPrintHex * * * @param baToConvert Array of bytes to encode * @return Hexdump string */ public static String prettyPrintHex(byte[] baToConvert) { HexCharset hde = null; try { hde = (HexCharset) HexCharset.forName("HEX"); } catch (UnsupportedCharsetException uce) { hde = new HexCharset(true); } return new String(hde.encode(new String(baToConvert)).array()); } /** * Method prettyPrintHex * * * @param sToConvert string to convert * @return hexdump string */ public static String prettyPrintHex(String sToConvert) { HexCharset hde = null; try { hde = (HexCharset) HexCharset.forName("HEX"); } catch (UnsupportedCharsetException uce) { hde = new HexCharset(true); } return new String(hde.encode(sToConvert).array()); } /** * Dumps a byte array as hex. * * @param sb * @param b */ public static void dumpHex(StringBuilder sb, byte[] b) { for (int i = 0; i < b.length; ++i) { if (i % 16 == 0) { sb.append(Integer.toHexString((i & 0xFFFF) | 0x10000).substring(1, 5) + " - "); } sb.append(Integer.toHexString((b[i] & 0xFF) | 0x100).substring(1, 3) + " "); if (i % 16 == 15 || i == b.length - 1) { int j; for (j = 16 - i % 16; j > 1; --j) sb.append(" "); sb.append(" - "); int start = (i / 16) * 16; int end = (b.length < i + 1) ? b.length : (i + 1); for (j = start; j < end; ++j) if (b[j] >= 32 && b[j] <= 126) sb.append((char) b[j]); else sb.append("."); sb.append("\n"); } } } /** Field HEX_DIGITS */ private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /** Field BIT_DIGIT */ private static char[] BIT_DIGIT = { '0', '1' }; /** Field COMPARE_BITS */ private static final byte[] COMPARE_BITS = { (byte) 0x80, (byte) 0x40, (byte) 0x20, (byte) 0x10, (byte) 0x08, (byte) 0x04, (byte) 0x02, (byte) 0x01 }; /** Field BYTE_SEPARATOR */ private static char BYTE_SEPARATOR = ' '; /** Field WITH_BYTE_SEPARATOR */ private static boolean WITH_BYTE_SEPARATOR = true; /** * Sets the WithByteSeparator attribute of the Convert class * * @param bs The new WithByteSeparator value */ public static void setWithByteSeparator(boolean bs) { WITH_BYTE_SEPARATOR = bs; } /** * Sets the ByteSeparator attribute of the Convert class * * @param bs The new ByteSeparator value */ public static void setByteSeparator(char bs) { BYTE_SEPARATOR = bs; } /** * Sets the BitDigits attribute of the Convert class * * @param bd The new BitDigits value * @exception Exception Description of Exception */ public static void setBitDigits(char[] bd) throws Exception { if (bd.length != 2) { throw new Exception("wrong number of characters!"); } BIT_DIGIT = bd; } /** * Method setBitDigits * * @param zeroBit zero bit * @param oneBit one bit * param redFish red fish * param blueFish blue fish */ public static void setBitDigits(char zeroBit, char oneBit) { BIT_DIGIT[0] = zeroBit; BIT_DIGIT[1] = oneBit; } /* * Converts a byte array to hex string */ /** * Description of the Method * * @param block Description of Parameter * @return Description of the Returned Value */ public static String byteArrayToBinaryString(byte[] block) { StringBuffer strBuf = new StringBuffer(); int iLen = block.length; // ---- for all bytes of array for (int i = 0; i < iLen; i++) { byte2bin(block[i], strBuf); // ---- if bit i is set ----// if ((i < iLen - 1) & WITH_BYTE_SEPARATOR) { strBuf.append(BYTE_SEPARATOR); } } return strBuf.toString(); } /** * Method toBinaryString * * @param ba binary array * @return the binary representation of the byte array */ public static String toBinaryString(byte[] ba) { return byteArrayToBinaryString(ba); } /** * Method toBinaryString * * @param b byte array * @return the binary representation of the byte */ public static String toBinaryString(byte b) { byte[] ba = new byte[1]; ba[0] = b; return byteArrayToBinaryString(ba); } /** * Method toBinaryString * * @param s short * @return the binary representation of the short */ public static String toBinaryString(short s) { return toBinaryString(toByteArray(s)); } /** * Method toBinaryString * * @param i integer * @return the binary representation of the int */ public static String toBinaryString(int i) { return toBinaryString(toByteArray(i)); } /** * Method toBinaryString * * @param l long * @return the binary representation of the long */ public static String toBinaryString(long l) { return toBinaryString(toByteArray(l)); } /** * Method toByteArray * * @param s short * @return the short as array of bytes */ public static final byte[] toByteArray(short s) { byte[] baTemp = new byte[2]; baTemp[1] = (byte) (s); baTemp[0] = (byte) (s >> 8); return baTemp; } /** * Method toByteArray * * @param i int * @return the int as array of bytes */ public static final byte[] toByteArray(int i) { byte[] baTemp = new byte[4]; baTemp[3] = (byte) i; baTemp[2] = (byte) (i >> 8); baTemp[1] = (byte) (i >> 16); baTemp[0] = (byte) (i >> 24); return baTemp; } /** * Method toByteArray * * @param l long * @return the long as array of bytes */ public static final byte[] toByteArray(long l) { byte[] baTemp = new byte[8]; baTemp[7] = (byte) l; baTemp[6] = (byte) (l >> 8); baTemp[5] = (byte) (l >> 16); baTemp[4] = (byte) (l >> 24); baTemp[3] = (byte) (l >> 32); baTemp[2] = (byte) (l >> 40); baTemp[1] = (byte) (l >> 48); baTemp[0] = (byte) (l >> 56); return baTemp; } /** * Description of the Method * * @param block Description of Parameter * @return Description of the Returned Value */ public static String byteArrayToHexString(byte[] block) { StringBuffer buf = new StringBuffer(); int len = block.length; for (int i = 0; i < len; i++) { byte2hex(block[i], buf); if ((i < len - 1) & WITH_BYTE_SEPARATOR) { buf.append(BYTE_SEPARATOR); } } return buf.toString(); } /** * Description of the Method * * @param in string to be converted * @return String in readable hex encoding */ public static String stringToHexString(String in) { byte[] ba = in.getBytes(); return toHexString(ba); } /** * Description of the Method * * @param block Description of Parameter * @param offset Description of Parameter * @param length Description of Parameter * @return Description of the Returned Value */ public static String byteArrayToHexString(byte[] block, int offset, int length) { StringBuffer buf = new StringBuffer(); int len = block.length; length = length + offset; if ((len < length)) { length = len; } for (int i = 0 + offset; i < length; i++) { byte2hex(block[i], buf); if (i < length - 1) { buf.append(':'); } } return buf.toString(); } /** * Returns a string of hexadecimal digits from a byte array. Each byte is * converted to 2 hex symbols. * * @param ba Description of Parameter * @return Description of the Returned Value */ public static String toHexString(byte[] ba) { return toHexString(ba, 0, ba.length); } /** * Method toHexString * * @param b byte * @return the hexadecimal representation of the byte */ public static String toHexString(byte b) { byte[] ba = new byte[1]; ba[0] = b; return toHexString(ba, 0, ba.length); } /** * Description of the Method * * @param s short * @return Description of the Returned Value */ public static String toHexString(short s) { return toHexString(toByteArray(s)); } /** * Method toHexString * * @param i int * @return the hexadecimal representation of the int */ public static String toHexString(int i) { return toHexString(toByteArray(i)); } /** * Method toHexString * * @param l long * @return the hexadecimal representation of the long */ public static String toHexString(long l) { return toHexString(toByteArray(l)); } /** * Method toString * * @param ba byte array * @return the byte array as string */ public static String toString(byte[] ba) { return new String(ba); } /** * Method toString * * @param b byte * @return the byte as string */ public static String toString(byte b) { byte[] ba = new byte[1]; ba[0] = b; return new String(ba); } /** * converts String to Hex String. Example: niko ->6E696B6F * * @param ba byte array * @param offset offset in array * @param length number of bytes * @return Description of the Returned Value */ public static String toHexString(byte[] ba, int offset, int length) { char[] buf; if (WITH_BYTE_SEPARATOR) { buf = new char[length * 3]; } else { buf = new char[length * 2]; } for (int i = offset, j = 0, k; i < offset + length;) { k = ba[i++]; buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F]; buf[j++] = HEX_DIGITS[k & 0x0F]; if (WITH_BYTE_SEPARATOR) { buf[j++] = BYTE_SEPARATOR; } } return new String(buf); } /** * Converts readable hex-String to byteArray * * @param strA string * @return the hexadecimal string as byte array */ public static byte[] hexStringToByteArray(String strA) { ByteArrayOutputStream result = new ByteArrayOutputStream(); byte sum = (byte) 0x00; boolean nextCharIsUpper = true; for (int i = 0; i < strA.length(); i++) { char c = strA.charAt(i); switch (Character.toUpperCase(c)) { case '0': if (nextCharIsUpper) { sum = (byte) 0x00; nextCharIsUpper = false; } else { sum |= (byte) 0x00; result.write(sum); nextCharIsUpper = true; } break; case '1': if (nextCharIsUpper) { sum = (byte) 0x10; nextCharIsUpper = false; } else { sum |= (byte) 0x01; result.write(sum); nextCharIsUpper = true; } break; case '2': if (nextCharIsUpper) { sum = (byte) 0x20; nextCharIsUpper = false; } else { sum |= (byte) 0x02; result.write(sum); nextCharIsUpper = true; } break; case '3': if (nextCharIsUpper) { sum = (byte) 0x30; nextCharIsUpper = false; } else { sum |= (byte) 0x03; result.write(sum); nextCharIsUpper = true; } break; case '4': if (nextCharIsUpper) { sum = (byte) 0x40; nextCharIsUpper = false; } else { sum |= (byte) 0x04; result.write(sum); nextCharIsUpper = true; } break; case '5': if (nextCharIsUpper) { sum = (byte) 0x50; nextCharIsUpper = false; } else { sum |= (byte) 0x05; result.write(sum); nextCharIsUpper = true; } break; case '6': if (nextCharIsUpper) { sum = (byte) 0x60; nextCharIsUpper = false; } else { sum |= (byte) 0x06; result.write(sum); nextCharIsUpper = true; } break; case '7': if (nextCharIsUpper) { sum = (byte) 0x70; nextCharIsUpper = false; } else { sum |= (byte) 0x07; result.write(sum); nextCharIsUpper = true; } break; case '8': if (nextCharIsUpper) { sum = (byte) 0x80; nextCharIsUpper = false; } else { sum |= (byte) 0x08; result.write(sum); nextCharIsUpper = true; } break; case '9': if (nextCharIsUpper) { sum = (byte) 0x90; nextCharIsUpper = false; } else { sum |= (byte) 0x09; result.write(sum); nextCharIsUpper = true; } break; case 'A': if (nextCharIsUpper) { sum = (byte) 0xA0; nextCharIsUpper = false; } else { sum |= (byte) 0x0A; result.write(sum); nextCharIsUpper = true; } break; case 'B': if (nextCharIsUpper) { sum = (byte) 0xB0; nextCharIsUpper = false; } else { sum |= (byte) 0x0B; result.write(sum); nextCharIsUpper = true; } break; case 'C': if (nextCharIsUpper) { sum = (byte) 0xC0; nextCharIsUpper = false; } else { sum |= (byte) 0x0C; result.write(sum); nextCharIsUpper = true; } break; case 'D': if (nextCharIsUpper) { sum = (byte) 0xD0; nextCharIsUpper = false; } else { sum |= (byte) 0x0D; result.write(sum); nextCharIsUpper = true; } break; case 'E': if (nextCharIsUpper) { sum = (byte) 0xE0; nextCharIsUpper = false; } else { sum |= (byte) 0x0E; result.write(sum); nextCharIsUpper = true; } break; case 'F': if (nextCharIsUpper) { sum = (byte) 0xF0; nextCharIsUpper = false; } else { sum |= (byte) 0x0F; result.write(sum); nextCharIsUpper = true; } break; default: break; } } if (!nextCharIsUpper) { throw new RuntimeException("The String did not contain an equal number of hex digits"); } return result.toByteArray(); } /* * Converts a byte to hex digit and writes to the supplied buffer */ /** * Description of the Method * * @param b * Description of Parameter * @param buf * Description of Parameter */ private static void byte2hex(byte b, StringBuffer buf) { int high = ((b & 0xf0) >> 4); int low = (b & 0x0f); buf.append(HEX_DIGITS[high]); buf.append(HEX_DIGITS[low]); } /** * Description of the Method * * @param b * Description of Parameter * @param buf * Description of Parameter */ private static void byte2bin(byte b, StringBuffer buf) { // test every 8 bit for (int i = 0; i < 8; i++) { // ---test if bit is set if ((b & COMPARE_BITS[i]) != 0) { buf.append(BIT_DIGIT[1]); } else { buf.append(BIT_DIGIT[0]); } } } /** * Returns a string of 8 hexadecimal digits (most significant digit first) * corresponding to the integer n , which is treated as unsigned. * * @param n * Description of Parameter * @return Description of the Returned Value */ private static String intToHexString(int n) { char[] buf = new char[8]; for (int i = 7; i >= 0; i--) { buf[i] = HEX_DIGITS[n & 0x0F]; n >>>= 4; } return new String(buf); } /** * test and demo for the Convert class * * @param args none needed */ public static void main(String args[]) { logger.info("-test and demo of the converter "); String str = "Niko"; byte[] ba = str.getBytes(); logger.info("to convert: " + str); logger.info("converted1: " + byteArrayToHexString(ba)); logger.info("converted1: " + byteArrayToHexString(ba, 0, ba.length)); logger.info("converted3: " + stringToHexString(str)); logger.info("----Convert integer to hexString..."); int i = -2; logger.info("to convert: " + i + " -> " + intToHexString(i)); logger.info("----Convert byte[] to binary String..."); byte[] baToConvert = { (byte) 0xff, (byte) 0x00, (byte) 0x33, (byte) 0x11, (byte) 0xff, (byte) 0x5f, (byte) 0x5f, (byte) 0x4f, (byte) 0x1f, (byte) 0xff }; logger.info("to convert: " + toHexString(baToConvert) + " -> " + byteArrayToBinaryString(baToConvert)); // ---- modify line separator setByteSeparator('-'); logger.info("to convert: " + toHexString(baToConvert) + " -> " + byteArrayToBinaryString(baToConvert)); // ---- modify line separator setByteSeparator('*'); setWithByteSeparator(true); logger.info("to convert: " + toHexString(baToConvert) + " -> " + byteArrayToBinaryString(baToConvert)); // ---- modify bit digits char[] bd = { 'a', 'b' }; try { setBitDigits(bd); } catch (Exception ex) { logger.debug("", ex); // ex.printStackTrace(); } logger.info("to convert: " + toHexString(baToConvert) + " -> " + byteArrayToBinaryString(baToConvert)); // ------------------------------------------------// setBitDigits('0', '1'); logger.info("---- Convert.toByteArray(int) "); for (int iToConvert = -10; iToConvert < 10; iToConvert++) { logger.info("to convert = " + iToConvert + " = " + HexDump.toBinaryString(iToConvert)); byte[] baConvInt = new byte[4]; baConvInt = HexDump.toByteArray(iToConvert); logger.info("convertet byteArray = " + HexDump.toBinaryString(baConvInt)); } logger.info("---- toHexString(int) "); i = -1; logger.info(i + " = 0x" + toHexString(i) + " = " + toBinaryString(i)); i++; logger.info(i + " = 0x" + toHexString(i) + " = " + toBinaryString(i)); // ------------------------------------------------// logger.info("---- toHexString(long) "); long l = 100; logger.info(l + " = 0x" + toHexString(l) + " = " + toBinaryString(l)); java.util.Random rnd = new java.util.Random(); l = rnd.nextLong(); logger.info(l + " = 0x" + toHexString(l) + " = " + toBinaryString(l)); // ------------------------------------------------// logger.info("---- toHexString(short) "); short s = 100; logger.info(s + " = 0x" + toHexString(s) + " = " + toBinaryString(s)); rnd = new java.util.Random(); s = (short) rnd.nextInt(); logger.info(s + " = 0x" + toHexString(s) + " = " + toBinaryString(s)); // ---------------------------------------------------------------------------// // convert dezimal-String to binary logger.info("---- read file in Hex-Format "); String strToConvert = "12345654321"; logger.info(strToConvert + " = " + stringToHexString(strToConvert)); logger.info("Das ist die Hex-Darstellung des obigen Strings"); logger.info("ba = " + toHexString(ba)); } public static String formatHexDump(String in) { int chunk = 60; StringBuilder out = new StringBuilder(); int from = 0; int to = 0; int size = in.length(); while (from < size) { if (size < from + chunk) { to = size; } else { to = from + chunk; } out.append(in.substring(from, to)); out.append('\n'); from = to; } return out.toString(); } } red5-1.0~svn4374.orig/src/org/red5/io/utils/IOUtils.java0000644000175000017500000001363011706617130022477 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.utils; import java.nio.ByteBuffer; import java.nio.charset.Charset; import org.apache.mina.core.buffer.IoBuffer; import org.slf4j.Logger; /** * Miscellaneous I/O utility methods * * @see Unsigned bytes in Java */ public class IOUtils { /** * UTF-8 is used */ public final static Charset CHARSET = Charset.forName("UTF-8"); /** * Writes integer in reverse order * @param out Data buffer to fill * @param value Integer */ public final static void writeReverseInt(IoBuffer out, int value) { byte[] bytes = new byte[4]; IoBuffer rev = IoBuffer.allocate(4); rev.putInt(value); rev.flip(); bytes[3] = rev.get(); bytes[2] = rev.get(); bytes[1] = rev.get(); bytes[0] = rev.get(); out.put(bytes); rev.free(); rev = null; } /** * Writes medium integer * @param out Output buffer * @param value Integer to write */ public final static void writeMediumInt(IoBuffer out, int value) { byte[] bytes = new byte[3]; bytes[0] = (byte) ((value >>> 16) & 0xff); bytes[1] = (byte) ((value >>> 8) & 0xff); bytes[2] = (byte) (value & 0xff); out.put(bytes); } /** * Writes medium integer * @param out Output buffer * @param value Integer to write */ public final static void writeMediumInt(ByteBuffer out, int value) { out.put((byte) ((value >>> 16) & 0xff)); out.put((byte) ((value >>> 8) & 0xff)); out.put((byte) (value & 0xff)); } /** * Writes extended medium integer (equivalent to a regular integer whose * most significant byte has been moved to its end, past its least significant * byte) * @param out Output buffer * @param value Integer to write */ public final static void writeExtendedMediumInt(IoBuffer out, int value) { value = ((value & 0xff000000) >> 24) | (value << 8); out.putInt(value); } /** * Writes extended medium integer (equivalent to a regular integer whose * most significant byte has been moved to its end, past its least significant * byte) * @param out Output buffer * @param value Integer to write */ public final static void writeExtendedMediumInt(ByteBuffer out, int value) { value = ((value & 0xff000000) >> 24) | (value << 8); out.putInt(value); } /** * Writes an unsigned byte value to the supplied buffer. * * @param out Output buffer * @param value Byte to write */ public final static void writeUnsignedByte(ByteBuffer out, byte value) { out.put((byte) (value & 0xff)); } /** * Reads unsigned medium integer * @param in Unsigned medium int source * @return int value */ public final static int readUnsignedMediumInt(IoBuffer in) { return ((in.get() & 0xff) << 16) + ((in.get() & 0xff) << 8) + ((in.get() & 0xff)); } /** * Reads medium int * @param in Source * @return int value */ public final static int readMediumInt(ByteBuffer in) { return ((in.get() & 0x000000ff) << 16) + ((in.get() & 0x000000ff) << 8) + ((in.get() & 0x000000ff)); } /** * Reads medium int * @param in Source * @return int value */ public final static int readMediumInt(IoBuffer in) { return ((in.get() & 0x000000ff) << 16) + ((in.get() & 0x000000ff) << 8) + ((in.get() & 0x000000ff)); } /** * Reads extended medium int * @param in Source * @return int value */ public final static int readExtendedMediumInt(IoBuffer in) { int result = in.getInt(); result = (result >>> 8) | ((result & 0x000000ff) << 24); return result; } /** * Reads extended medium int * @param in Source * @return int value */ public final static int readExtendedMediumInt(ByteBuffer in) { int result = in.getInt(); result = (result >>> 8) | ((result & 0x000000ff) << 24); return result; } /** * Reads reverse int * @param in Source * @return int */ public final static int readReverseInt(IoBuffer in) { byte[] bytes = new byte[4]; in.get(bytes); int val = 0; val += bytes[3] * 256 * 256 * 256; val += bytes[2] * 256 * 256; val += bytes[1] * 256; val += bytes[0]; return val; } /** * Format debug message * @param log Logger * @param msg Message * @param buf Byte buffer to debug */ public final static void debug(Logger log, String msg, IoBuffer buf) { if (log.isDebugEnabled()) { log.debug(msg); log.debug("Size: {}", buf.remaining()); log.debug("Data:\n{}", HexDump.formatHexDump(buf.getHexDump())); log.debug("\n{}\n", toString(buf)); } } /** * String representation of byte buffer * @param buf Byte buffer * @return String representation */ public final static String toString(IoBuffer buf) { int pos = buf.position(); int limit = buf.limit(); final java.nio.ByteBuffer strBuf = buf.buf(); final String string = CHARSET.decode(strBuf).toString(); buf.position(pos); buf.limit(limit); return string; } public static void main(String[] args) { ByteBuffer buf = ByteBuffer.allocate(4); IOUtils.writeExtendedMediumInt(buf, 1234567890); buf.flip(); System.out.println("Result: " + IOUtils.readExtendedMediumInt(buf)); } } red5-1.0~svn4374.orig/src/org/red5/io/utils/HexCharset.java0000644000175000017500000002305111706617130023203 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.utils; import java.nio.Buffer; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; /** * This was borrowed from the Soupdragon base64 library. * *

Codec to translate between hex coding and byte string.

*

Hex output is capital if the char set name is given in capitals.

*

hex:nn used as a charset name inserts \n after every nnth character.

* * @author Malcolm McMahon */ public class HexCharset extends Charset { private final static String codeHEX = "0123456789ABCDEF"; private final static String codehex = "0123456789abcdef"; private String codes; private Integer measure; /** Creates a new instance of HexCharset * @param caps true for A-F, false for a-f */ public HexCharset(boolean caps) { super(caps ? "HEX" : "hex", new String[] { "HEX" }); codes = caps ? codeHEX : codehex; } /** * Construct the charset * @param caps true for A-F, false for a-f * @param measure Line width for decoding */ public HexCharset(boolean caps, int measure) { super((caps ? "HEX" : "hex") + ":" + measure, new String[] { "HEX" }); codes = caps ? codeHEX : codehex; this.measure = measure; } /** * Constructs a new encoder for this charset.

* * @return A new encoder for this charset */ public CharsetEncoder newEncoder() { return new Encoder(); } /** * Constructs a new decoder for this charset.

* * @return A new decoder for this charset */ public CharsetDecoder newDecoder() { return new Decoder(); } /** * Tells whether or not this charset contains the given charset. * *

A charset C is said to contain a charset D if, * and only if, every character representable in D is also * representable in C. If this relationship holds then it is * guaranteed that every string that can be encoded in D can also be * encoded in C without performing any replacements. * *

That C contains D does not imply that each character * representable in C by a particular byte sequence is represented * in D by the same byte sequence, although sometimes this is the * case. * *

Every charset contains itself. * *

This method computes an approximation of the containment relation: * If it returns true then the given charset is known to be * contained by this charset; if it returns false, however, then * it is not necessarily the case that the given charset is not contained * in this charset. * * @return true if, and only if, the given charset * is contained in this charset */ public boolean contains(Charset cs) { return cs instanceof HexCharset; } private class Encoder extends CharsetEncoder { private boolean unpaired; private int nyble; private Encoder() { super(HexCharset.this, 0.49f, 1f); } /** * Flushes this encoder. * *

The default implementation of this method does nothing, and always * returns {@link CoderResult#UNDERFLOW}. This method should be overridden * by encoders that may need to write final bytes to the output buffer * once the entire input sequence has been read.

* * @param out * The output byte buffer * * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or * {@link CoderResult#OVERFLOW} */ protected java.nio.charset.CoderResult implFlush(java.nio.ByteBuffer out) { if (!unpaired) { implReset(); return CoderResult.UNDERFLOW; } else throw new IllegalArgumentException("Hex string must be an even number of digits"); } /** * Encodes one or more characters into one or more bytes. * *

This method encapsulates the basic encoding loop, encoding as many * characters as possible until it either runs out of input, runs out of room * in the output buffer, or encounters an encoding error. This method is * invoked by the {@link #encode encode} method, which handles result * interpretation and error recovery. * *

The buffers are read from, and written to, starting at their current * positions. At most {@link Buffer#remaining in.remaining()} characters * will be read, and at most {@link Buffer#remaining out.remaining()} * bytes will be written. The buffers' positions will be advanced to * reflect the characters read and the bytes written, but their marks and * limits will not be modified. * *

This method returns a {@link CoderResult} object to describe its * reason for termination, in the same manner as the {@link #encode encode} * method. Most implementations of this method will handle encoding errors * by returning an appropriate result object for interpretation by the * {@link #encode encode} method. An optimized implementation may instead * examine the relevant error action and implement that action itself. * *

An implementation of this method may perform arbitrary lookahead by * returning {@link CoderResult#UNDERFLOW} until it receives sufficient * input.

* * @param in * The input character buffer * * @param out * The output byte buffer * * @return A coder-result object describing the reason for termination */ public java.nio.charset.CoderResult encodeLoop(java.nio.CharBuffer in, java.nio.ByteBuffer out) { while (in.remaining() > 0) { if (out.remaining() <= 0) return CoderResult.OVERFLOW; char inch = in.get(); if (!Character.isWhitespace(inch)) { int d = Character.digit(inch, 16); if (d < 0) throw new IllegalArgumentException("Bad hex character " + inch); if (unpaired) out.put((byte) (nyble | d)); else nyble = d << 4; unpaired = !unpaired; } } return CoderResult.UNDERFLOW; } /** * Clear state */ protected void implReset() { unpaired = false; nyble = 0; } } private class Decoder extends CharsetDecoder { private int charCount; private Decoder() { super(HexCharset.this, 2f, measure == null ? 2f : 2f + (2f / (float) measure)); } /** * Decodes one or more bytes into one or more characters. * *

This method encapsulates the basic decoding loop, decoding as many * bytes as possible until it either runs out of input, runs out of room * in the output buffer, or encounters a decoding error. This method is * invoked by the {@link #decode decode} method, which handles result * interpretation and error recovery. * *

The buffers are read from, and written to, starting at their current * positions. At most {@link Buffer#remaining in.remaining()} bytes * will be read, and at most {@link Buffer#remaining out.remaining()} * characters will be written. The buffers' positions will be advanced to * reflect the bytes read and the characters written, but their marks and * limits will not be modified. * *

This method returns a {@link CoderResult} object to describe its * reason for termination, in the same manner as the {@link #decode decode} * method. Most implementations of this method will handle decoding errors * by returning an appropriate result object for interpretation by the * {@link #decode decode} method. An optimized implementation may instead * examine the relevant error action and implement that action itself. * *

An implementation of this method may perform arbitrary lookahead by * returning {@link CoderResult#UNDERFLOW} until it receives sufficient * input.

* * @param in * The input byte buffer * * @param out * The output character buffer * * @return A coder-result object describing the reason for termination */ public java.nio.charset.CoderResult decodeLoop(java.nio.ByteBuffer in, java.nio.CharBuffer out) { while (in.remaining() > 0) { if (measure != null && charCount >= measure) { if (out.remaining() == 0) return CoderResult.OVERFLOW; out.put('\n'); charCount = 0; } if (out.remaining() < 2) return CoderResult.OVERFLOW; int b = in.get() & 0xff; out.put(codes.charAt(b >>> 4)); out.put(codes.charAt(b & 0x0f)); charCount += 2; } return CoderResult.UNDERFLOW; } /** * Resets this decoder, clearing any charset-specific internal state. * *

The default implementation of this method does nothing. This method * should be overridden by decoders that maintain internal state.

*/ protected void implReset() { charCount = 0; } } } red5-1.0~svn4374.orig/src/org/red5/io/utils/XMLUtils.java0000644000175000017500000000747411706617130022641 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.utils; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.InputSource; /** * Misc XML utils * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Paul Gregoire (mondain@gmail.com) */ public class XMLUtils { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(XMLUtils.class); /** * Converts string representation of XML into Document * @param str String representation of XML * @return DOM object * @throws IOException I/O exception */ public static Document stringToDoc(String str) throws IOException { if (StringUtils.isNotEmpty(str)) { try { Reader reader = new StringReader(str); DocumentBuilder db = DocumentBuilderFactory.newInstance() .newDocumentBuilder(); Document doc = db.parse(new InputSource(reader)); reader.close(); return doc; } catch (Exception ex) { log.debug("String: {}", str); throw new IOException(String.format("Error converting from string to doc %s", ex.getMessage())); } } else { throw new IOException("Error - could not convert empty string to doc"); } } /** * Converts doc to String * @param dom DOM object to convert * @return XML as String */ public static String docToString(Document dom) { return XMLUtils.docToString1(dom); } /** * Convert a DOM tree into a String using Dom2Writer * @return XML as String * @param dom DOM object to convert */ public static String docToString1(Document dom) { StringWriter sw = new StringWriter(); DOM2Writer.serializeAsXML(dom, sw); return sw.toString(); } /** * Convert a DOM tree into a String using transform * @param domDoc DOM object * @throws java.io.IOException I/O exception * @return XML as String */ public static String docToString2(Document domDoc) throws IOException { try { TransformerFactory transFact = TransformerFactory.newInstance(); Transformer trans = transFact.newTransformer(); trans.setOutputProperty(OutputKeys.INDENT, "no"); StringWriter sw = new StringWriter(); Result result = new StreamResult(sw); trans.transform(new DOMSource(domDoc), result); return sw.toString(); } catch (Exception ex) { throw new IOException(String.format("Error converting from doc to string %s", ex.getMessage())); } } } red5-1.0~svn4374.orig/src/org/red5/io/ITagReader.java0000644000175000017500000000364311706617130021761 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; public interface ITagReader { /** * Return the file that is loaded. * * @return the file to be loaded */ public IStreamableFile getFile(); /** * Returns the offet length * * @return int */ public int getOffset(); /** * Returns the amount of bytes read * * @return long */ public long getBytesRead(); /** * Return length in seconds * @return length in seconds */ public long getDuration(); /** * Get the total readable bytes in a file or ByteBuffer * * @return Total readable bytes */ public long getTotalBytes(); /** * Decode the header of the stream; * */ public void decodeHeader(); /** * Move the reader pointer to given position in file. * * @param pos File position to move to */ public void position(long pos); /** * Returns a boolean stating whether the FLV has more tags * * @return boolean */ public boolean hasMoreTags(); /** * Returns a Tag object * * @return Tag */ public ITag readTag(); /** * Closes the reader and free any allocated memory. */ public void close(); /** * Check if the reader also has video tags. * * @return has video */ public boolean hasVideo(); } red5-1.0~svn4374.orig/src/org/red5/io/mp4/0000755000175000017500000000000011760512575017650 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/mp4/MP4Atom.java0000644000175000017500000011355211706617130021734 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp4; /** This software module was originally developed by Apple Computer, Inc. in the course of development of MPEG-4. This software module is an implementation of a part of one or more MPEG-4 tools as specified by MPEG-4. ISO/IEC gives users of MPEG-4 free license to this software module or modifications thereof for use in hardware or software products claiming conformance to MPEG-4. Those intending to use this software module in hardware or software products are advised that its use may infringe existing patents. The original developer of this software module and his/her company, the subsequent editors and their companies, and ISO/IEC have no liability for use of this software module or modifications thereof in an implementation. Copyright is not released for non MPEG-4 conforming products. Apple Computer, Inc. retains full right to use the code for its own purpose, assign or donate the code to a third party and to inhibit third parties from using the code for non MPEG-4 conforming products. This copyright notice must be included in all copies or derivative works. Copyright (c) 1999. */ import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Vector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The MP4Atom object represents the smallest information block * of the MP4 file. It could contain other atoms as children. * * 01/29/2008 - Added support for avc1 atom (video sample) * 02/05/2008 - Added stss - sync sample atom and stts - time to sample atom * 10/2008 - Added pasp - pixel aspect ratio atom * 10/2010 - Added ctts atom * 11/2011 - Added wide, frma, chan, and terminator handling * * @author Paul Gregoire (mondain@gmail.com) */ public class MP4Atom { private static Logger log = LoggerFactory.getLogger(MP4Atom.class); /** The size of the atom. */ protected long size; /** The type of the atom. */ protected int type; /** The user's extended type of the atom. */ protected String uuid; /** The amount of bytes that are read from the mpeg stream. */ protected long readed; /** The children of this atom. */ protected List children = new ArrayList(3); protected int version = 0; protected int flags = 0; private int channelCount = 0; protected int entryCount; /** The decoding time to sample table. */ protected Vector chunks; protected int handlerType; protected Date creationTime; protected Date modificationTime; protected int timeScale; protected long duration; protected int sampleSize; protected int sampleCount; /** The decoding time to sample table. */ protected Vector samples; protected int fieldSize; /** The decoding time to sample table. */ protected Vector records; protected Vector syncSamples; protected Vector timeToSamplesRecords; protected Vector comptimeToSamplesRecords; protected int balance; protected long trackId; protected int qt_trackWidth; protected int qt_trackHeight; protected int graphicsMode; protected int opColorRed; protected int opColorGreen; protected int opColorBlue; protected int width; protected int height; protected int avcLevel; protected int avcProfile; private byte[] videoConfigBytes; protected MP4Descriptor esd_descriptor; public MP4Atom(long size, int type, String uuid, long readed) { this.size = size; this.type = type; this.uuid = uuid; this.readed = readed; } /** * Constructs an Atom object from the data in the bitstream. * @param bitstream the input bitstream * @return the constructed atom. */ public final static MP4Atom createAtom(MP4DataStream bitstream) throws IOException { long size = bitstream.readBytes(4); long readed = 4; if (size == 0) { //throw new IOException("Invalid size"); return new MP4Atom(0, 0, null, 0); } int type = (int) bitstream.readBytes(4); readed += 4; log.trace("Creating atom: type = {} size = {}", intToType(type), size); // if atom is 'uuid' (extended atom type) read the uuid String uuid = null; if (type == 1970628964) { uuid = bitstream.readString(16); readed += 16; } // large size if (size == 1) { size = bitstream.readBytes(8); readed += 8; } MP4Atom atom = new MP4Atom(size, type, uuid, readed); switch (type) { case 1835297121: // MP4MediaAtomType mdia case 1684631142: // MP4DataInformationAtomType dinf case 1836019574: // MP4MovieAtomType moov case 1835626086: // MP4MediaInformationAtomType minf case 1937007212: // MP4SampleTableAtomType stbl case 1953653099: // MP4TrackAtomType trak readed = atom.create_composite_atom(bitstream); break; case 1836069985: // MP4AudioSampleEntryAtomType mp4a readed = atom.create_audio_sample_entry_atom(bitstream); break; case 1668232756: // MP4ChunkLargeOffsetAtomType co64 readed = atom.create_chunk_large_offset_atom(bitstream); break; case 1937007471: // MP4ChunkOffsetAtomType stco readed = atom.create_chunk_offset_atom(bitstream); break; case 1751411826: // MP4HandlerAtomType hdlr readed = atom.create_handler_atom(bitstream); break; case 1835296868: // MP4MediaHeaderAtomType hdhd readed = atom.create_media_header_atom(bitstream); break; case 1836476516: // MP4MovieHeaderAtomType mvhd readed = atom.create_movie_header_atom(bitstream); break; case 1937011556: // MP4SampleDescriptionAtomType stsd readed = atom.create_sample_description_atom(bitstream); break; case 1937011578: // MP4SampleSizeAtomType stsz readed = atom.create_sample_size_atom(bitstream); break; case 1937013298: // MP4CompactSampleSizeAtomType stz2 readed = atom.create_compact_sample_size_atom(bitstream); break; case 1937011555: // MP4SampleToChunkAtomType stsc readed = atom.create_sample_to_chunk_atom(bitstream); break; case 1937011571: // MP4SyncSampleAtomType stss readed = atom.create_sync_sample_atom(bitstream); break; case 1937011827: // MP4TimeToSampleAtomType stts readed = atom.create_time_to_sample_atom(bitstream); break; case 1936549988: // MP4SoundMediaHeaderAtomType smhd readed = atom.create_sound_media_header_atom(bitstream); break; case 1953196132: // MP4TrackHeaderAtomType tkhd readed = atom.create_track_header_atom(bitstream); break; case 1986881636: // MP4VideoMediaHeaderAtomType vmhd readed = atom.create_video_media_header_atom(bitstream); break; case 1836070006: // MP4VisualSampleEntryAtomType mp4v readed = atom.create_visual_sample_entry_atom(bitstream); break; case 1635148593: // MP4VideoSampleEntryAtomType avc1 readed = atom.create_video_sample_entry_atom(bitstream); break; case 1702061171: // MP4ESDAtomType esds readed = atom.create_esd_atom(bitstream); break; case 1635148611: // MP4AVCAtomType avcC readed = atom.create_avc_config_atom(bitstream); break; case 1885434736: // MP4PixelAspectAtomType pasp readed = atom.create_pasp_atom(bitstream); break; case 1668576371: // MP4CompositionTimeToSampleAtomType ctts readed = atom.create_composition_time_to_sample_atom(bitstream); break; case 2002876005: // siDecompressionParam wave readed = atom.create_decompression_param_atom(bitstream); break; case 1718775137: // Format frma readed = atom.create_format_atom(bitstream); break; case 1667785070: // Audio Channel Layout chan readed = atom.create_chan_atom(bitstream); break; case 1969517665: // User data udta readed = atom.create_udta_atom(bitstream); break; case 1835365473: // Meta data meta readed = atom.create_meta_atom(bitstream); break; case 0: // Terminator 0x00000000 break; } log.debug("Finished atom: type = {} size = {}", intToType(type), size); bitstream.skipBytes(size - readed); return atom; } /** * Loads the version of the full atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_full_atom(MP4DataStream bitstream) throws IOException { long value = bitstream.readBytes(4); version = (int) value >> 24; flags = (int) value & 0xffffff; readed += 4; return readed; } /** * Loads the composite atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_composite_atom(MP4DataStream bitstream) throws IOException { while (readed < size) { MP4Atom child = MP4Atom.createAtom(bitstream); if (child.getType() != 0) { children.add(child); } readed += child.getSize(); } return readed; } /** * Lookups for a child atom with the specified type, skips the number * children with the same type before finding a result. * @param type the type of the atom. * @param number the number of atoms to skip * @return the atom which was being searched. */ public MP4Atom lookup(long type, int number) { int position = 0; for (int i = 0; i < children.size(); i++) { MP4Atom atom = children.get(i); if (atom.getType() == type) { if (position >= number) { return atom; } position++; } } return null; } public int getChannelCount() { return channelCount; } /** * Creates a user data atom. * * @param bitstream * @return bytes read * @throws IOException */ public long create_udta_atom(MP4DataStream bitstream) throws IOException { //qtff page 44 log.trace("User data"); if (size > 12) { MP4Atom child = MP4Atom.createAtom(bitstream); children.add(child); readed += child.getSize(); log.trace("Child: {}", intToType(child.getType())); } return readed; } /** * Creates a meta data atom. * * @param bitstream * @return bytes read * @throws IOException */ public long create_meta_atom(MP4DataStream bitstream) throws IOException { //qtff page 110 log.trace("Meta data"); create_handler_atom(bitstream); // hdlr atom if (children.size() > 0) { // TODO handle children like ilst } else { @SuppressWarnings("unused") int subSize = (int) bitstream.readBytes(4); int subType = (int) bitstream.readBytes(4); readed += 8; if (subType == MP4Atom.typeToInt("mhdr")) { log.info("Metadata header atom"); create_full_atom(bitstream); // mhdr atom int nextItemId = (int) bitstream.readBytes(4); readed += 4; log.info("Next item id: {}", MP4Atom.intToType(nextItemId)); } else if (subType == MP4Atom.typeToInt("keys")) { log.info("Keys atom"); create_full_atom(bitstream); // keys atom } } return readed; } /** * Loads AudioSampleEntry atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ @SuppressWarnings("unused") public long create_audio_sample_entry_atom(MP4DataStream bitstream) throws IOException { //qtff page 117 log.trace("Audio sample entry"); bitstream.skipBytes(6); int dataReferenceIndex = (int) bitstream.readBytes(2); int version = (int) bitstream.readBytes(2); // version log.trace("Sample description version: {}", version); bitstream.skipBytes(6); channelCount = (int) bitstream.readBytes(2); log.trace("Channels: {}", channelCount); sampleSize = (int) bitstream.readBytes(2); log.trace("Sample size (bits): {}", sampleSize); bitstream.skipBytes(4); timeScale = (int) bitstream.readBytes(2); log.trace("Time scale: {}", timeScale); bitstream.skipBytes(2); readed += 28; // version 1 contains 4 additional fields if (version == 1) { int samplesPerPacket = (int) bitstream.readBytes(4); int bytesPerPacket = (int) bitstream.readBytes(4); int bytesPerFrame = (int) bitstream.readBytes(4); int bytesPerSample = (int) bitstream.readBytes(4); readed += 16; } // version 2 contains 8 more if (version == 2) { // TODO add support for v2 } MP4Atom child = MP4Atom.createAtom(bitstream); children.add(child); readed += child.getSize(); log.trace("Child: {}", intToType(child.getType())); return readed; } /** * Loads ChunkLargeOffset atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_chunk_large_offset_atom(MP4DataStream bitstream) throws IOException { create_full_atom(bitstream); chunks = new Vector(); entryCount = (int) bitstream.readBytes(4); readed += 4; for (int i = 0; i < entryCount; i++) { chunks.addElement(Long.valueOf(bitstream.readBytes(8))); readed += 8; } return readed; } public Vector getChunks() { return chunks; } /** * Loads ChunkOffset atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_chunk_offset_atom(MP4DataStream bitstream) throws IOException { create_full_atom(bitstream); chunks = new Vector(); entryCount = (int) bitstream.readBytes(4); readed += 4; for (int i = 0; i < entryCount; i++) { long chunkOffset = bitstream.readBytes(4); chunks.addElement(Long.valueOf(chunkOffset)); readed += 4; } return readed; } /** * Loads Handler atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ @SuppressWarnings("unused") public long create_handler_atom(MP4DataStream bitstream) throws IOException { create_full_atom(bitstream); int qt_componentType = (int) bitstream.readBytes(4); log.trace("Component type: {}", MP4Atom.intToType(qt_componentType)); handlerType = (int) bitstream.readBytes(4); // for qt this is component sub-type log.trace("Handler type: {}", MP4Atom.intToType(handlerType)); int qt_componentManufacturer = (int) bitstream.readBytes(4); int qt_componentFlags = (int) bitstream.readBytes(4); int qt_componentFlagsMask = (int) bitstream.readBytes(4); readed += 20; if (handlerType != MP4Atom.typeToInt("hdlr")) { int length = (int) (size - readed); String trackName = bitstream.readString(length); log.debug("Track name: {}", trackName); readed += length; } else { int tmp = (int) bitstream.readBytes(4); readed += 4; if (tmp == MP4Atom.typeToInt("appl")) { log.info("Apple flag?: {}", MP4Atom.intToType(tmp)); bitstream.skipBytes(9); readed += 9; MP4Atom child = MP4Atom.createAtom(bitstream); children.add(child); readed += child.getSize(); log.trace("Child: {}", intToType(child.getType())); } } return readed; } /** * Gets the handler type. * @return the handler type. */ public int getHandlerType() { return handlerType; } /** * Loads MediaHeader atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ @SuppressWarnings("unused") public long create_media_header_atom(MP4DataStream bitstream) throws IOException { create_full_atom(bitstream); if (version == 1) { creationTime = createDate(bitstream.readBytes(8)); modificationTime = createDate(bitstream.readBytes(8)); timeScale = (int) bitstream.readBytes(4); duration = bitstream.readBytes(8); readed += 28; } else { creationTime = createDate(bitstream.readBytes(4)); modificationTime = createDate(bitstream.readBytes(4)); timeScale = (int) bitstream.readBytes(4); duration = bitstream.readBytes(4); readed += 16; } int packedLanguage = (int) bitstream.readBytes(2); int qt_quality = (int) bitstream.readBytes(2); readed += 4; return readed; } public long getDuration() { return duration; } public int getTimeScale() { return timeScale; } /** * Loads MovieHeader atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ @SuppressWarnings("unused") public long create_movie_header_atom(MP4DataStream bitstream) throws IOException { create_full_atom(bitstream); if (version == 1) { creationTime = createDate(bitstream.readBytes(8)); modificationTime = createDate(bitstream.readBytes(8)); timeScale = (int) bitstream.readBytes(4); duration = bitstream.readBytes(8); readed += 28; } else { creationTime = createDate(bitstream.readBytes(4)); modificationTime = createDate(bitstream.readBytes(4)); timeScale = (int) bitstream.readBytes(4); duration = bitstream.readBytes(4); readed += 16; } int qt_preferredRate = (int) bitstream.readBytes(4); int qt_preferredVolume = (int) bitstream.readBytes(2); bitstream.skipBytes(10); long qt_matrixA = bitstream.readBytes(4); long qt_matrixB = bitstream.readBytes(4); long qt_matrixU = bitstream.readBytes(4); long qt_matrixC = bitstream.readBytes(4); long qt_matrixD = bitstream.readBytes(4); long qt_matrixV = bitstream.readBytes(4); long qt_matrixX = bitstream.readBytes(4); long qt_matrixY = bitstream.readBytes(4); long qt_matrixW = bitstream.readBytes(4); long qt_previewTime = bitstream.readBytes(4); long qt_previewDuration = bitstream.readBytes(4); long qt_posterTime = bitstream.readBytes(4); long qt_selectionTime = bitstream.readBytes(4); long qt_selectionDuration = bitstream.readBytes(4); long qt_currentTime = bitstream.readBytes(4); long nextTrackID = bitstream.readBytes(4); readed += 80; return readed; } /** * Loads SampleDescription atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_sample_description_atom(MP4DataStream bitstream) throws IOException { create_full_atom(bitstream); entryCount = (int) bitstream.readBytes(4); log.trace("stsd entry count: {}", entryCount); readed += 4; for (int i = 0; i < entryCount; i++) { MP4Atom child = MP4Atom.createAtom(bitstream); children.add(child); readed += child.getSize(); } return readed; } /** * Loads MP4SampleSizeAtom atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_sample_size_atom(MP4DataStream bitstream) throws IOException { create_full_atom(bitstream); samples = new Vector(); sampleSize = (int) bitstream.readBytes(4); sampleCount = (int) bitstream.readBytes(4); readed += 8; if (sampleSize == 0) { for (int i = 0; i < sampleCount; i++) { int size = (int) bitstream.readBytes(4); samples.addElement(Integer.valueOf(size)); readed += 4; } } return readed; } public Vector getSamples() { return samples; } public int getSampleSize() { return sampleSize; } /** * Loads CompactSampleSize atom from the input stream. * @param stream the input stream * @return the number of bytes which was being loaded. */ public long create_compact_sample_size_atom(MP4DataStream stream) throws IOException { create_full_atom(stream); stream.skipBytes(3); sampleSize = 0; fieldSize = (int) stream.readBytes(1); sampleCount = (int) stream.readBytes(4); readed += 8; for (int i = 0; i < sampleCount; i++) { int size = 0; switch (fieldSize) { case 4: size = (int) stream.readBytes(1); // TODO check the following code samples.addElement(Integer.valueOf(size & 0x0f)); size = (size >> 4) & 0x0f; i++; readed += 1; break; case 8: size = (int) stream.readBytes(1); readed += 1; break; case 16: size = (int) stream.readBytes(2); readed += 2; break; } if (i < sampleCount) { samples.addElement(Integer.valueOf(size)); } } return readed; } public Vector getRecords() { return records; } /** * Loads MP4SampleToChunkAtom atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_sample_to_chunk_atom(MP4DataStream bitstream) throws IOException { create_full_atom(bitstream); records = new Vector(); entryCount = (int) bitstream.readBytes(4); readed += 4; for (int i = 0; i < entryCount; i++) { int firstChunk = (int) bitstream.readBytes(4); int samplesPerChunk = (int) bitstream.readBytes(4); int sampleDescriptionIndex = (int) bitstream.readBytes(4); records.addElement(new Record(firstChunk, samplesPerChunk, sampleDescriptionIndex)); readed += 12; } return readed; } public Vector getSyncSamples() { return syncSamples; } /** * Loads MP4SyncSampleAtom atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_sync_sample_atom(MP4DataStream bitstream) throws IOException { log.trace("Sync sample atom contains keyframe info"); create_full_atom(bitstream); syncSamples = new Vector(); entryCount = (int) bitstream.readBytes(4); log.trace("Sync entries: {}", entryCount); readed += 4; for (int i = 0; i < entryCount; i++) { int sample = (int) bitstream.readBytes(4); //log.trace("Sync entry: {}", sample); syncSamples.addElement(Integer.valueOf(sample)); readed += 4; } return readed; } public Vector getTimeToSamplesRecords() { return timeToSamplesRecords; } /** * Loads MP4TimeToSampleAtom atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_time_to_sample_atom(MP4DataStream bitstream) throws IOException { log.trace("Time to sample atom"); create_full_atom(bitstream); timeToSamplesRecords = new Vector(); entryCount = (int) bitstream.readBytes(4); log.trace("Time to sample entries: {}", entryCount); readed += 4; for (int i = 0; i < entryCount; i++) { int sampleCount = (int) bitstream.readBytes(4); int sampleDuration = (int) bitstream.readBytes(4); //log.trace("Sync entry: {}", sample); timeToSamplesRecords.addElement(new TimeSampleRecord(sampleCount, sampleDuration)); readed += 8; } return readed; } /** * Loads MP4SoundMediaHeaderAtom atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_sound_media_header_atom(MP4DataStream bitstream) throws IOException { create_full_atom(bitstream); balance = (int) bitstream.readBytes(2); bitstream.skipBytes(2); readed += 4; return readed; } /** * Loads MP4TrackHeaderAtom atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ @SuppressWarnings("unused") public long create_track_header_atom(MP4DataStream bitstream) throws IOException { create_full_atom(bitstream); log.trace("Version: {}", version); if (version == 1) { creationTime = createDate(bitstream.readBytes(8)); modificationTime = createDate(bitstream.readBytes(8)); trackId = bitstream.readBytes(4); bitstream.skipBytes(4); duration = bitstream.readBytes(8); readed += 32; } else { creationTime = createDate(bitstream.readBytes(4)); modificationTime = createDate(bitstream.readBytes(4)); trackId = bitstream.readBytes(4); bitstream.skipBytes(4); duration = bitstream.readBytes(4); readed += 20; } bitstream.skipBytes(8); //reserved by apple int qt_layer = (int) bitstream.readBytes(2); int qt_alternateGroup = (int) bitstream.readBytes(2); int qt_volume = (int) bitstream.readBytes(2); log.trace("Volume: {}", qt_volume); bitstream.skipBytes(2); //reserved by apple long qt_matrixA = bitstream.readBytes(4); long qt_matrixB = bitstream.readBytes(4); long qt_matrixU = bitstream.readBytes(4); long qt_matrixC = bitstream.readBytes(4); long qt_matrixD = bitstream.readBytes(4); long qt_matrixV = bitstream.readBytes(4); long qt_matrixX = bitstream.readBytes(4); long qt_matrixY = bitstream.readBytes(4); long qt_matrixW = bitstream.readBytes(4); qt_trackWidth = (int) bitstream.readBytes(4); width = (qt_trackWidth >> 16); qt_trackHeight = (int) bitstream.readBytes(4); height = (qt_trackHeight >> 16); readed += 60; return readed; } /** * Loads MP4VideoMediaHeaderAtom atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_video_media_header_atom(MP4DataStream bitstream) throws IOException { create_full_atom(bitstream); if ((size - readed) == 8) { graphicsMode = (int) bitstream.readBytes(2); opColorRed = (int) bitstream.readBytes(2); opColorGreen = (int) bitstream.readBytes(2); opColorBlue = (int) bitstream.readBytes(2); readed += 8; } return readed; } /** * Loads MP4VisualSampleEntryAtom atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_visual_sample_entry_atom(MP4DataStream bitstream) throws IOException { log.trace("Visual entry atom contains wxh"); bitstream.skipBytes(24); width = (int) bitstream.readBytes(2); log.trace("Width: {}", width); height = (int) bitstream.readBytes(2); log.trace("Height: {}", height); bitstream.skipBytes(50); readed += 78; MP4Atom child = MP4Atom.createAtom(bitstream); children.add(child); readed += child.getSize(); return readed; } /** * Loads MP4VideoSampleEntryAtom atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ @SuppressWarnings("unused") public long create_video_sample_entry_atom(MP4DataStream bitstream) throws IOException { log.trace("Video entry atom contains wxh"); bitstream.skipBytes(6); int dataReferenceIndex = (int) bitstream.readBytes(2); bitstream.skipBytes(2); bitstream.skipBytes(2); bitstream.skipBytes(12); width = (int) bitstream.readBytes(2); log.trace("Width: {}", width); height = (int) bitstream.readBytes(2); log.trace("Height: {}", height); int horizontalRez = (int) bitstream.readBytes(4) >> 16; log.trace("H Resolution: {}", horizontalRez); int verticalRez = (int) bitstream.readBytes(4) >> 16; log.trace("V Resolution: {}", verticalRez); bitstream.skipBytes(4); int frameCount = (int) bitstream.readBytes(2); log.trace("Frame to sample count: {}", frameCount); int stringLen = (int) bitstream.readBytes(1); log.trace("String length (cpname): {}", stringLen); String compressorName = bitstream.readString(31); log.trace("Compressor name: {}", compressorName.trim()); int depth = (int) bitstream.readBytes(2); log.trace("Depth: {}", depth); bitstream.skipBytes(2); readed += 78; log.trace("Bytes read: {}", readed); MP4Atom child = MP4Atom.createAtom(bitstream); children.add(child); readed += child.getSize(); return readed; } public int getHeight() { return height; } public int getWidth() { return width; } public int getAvcLevel() { return avcLevel; } public int getAvcProfile() { return avcProfile; } public byte[] getVideoConfigBytes() { return videoConfigBytes; } /** * Loads AVCC atom from the input bitstream. * *
	              * 8+ bytes ISO/IEC 14496-10 or 3GPP AVC decode config box
	                  = long unsigned offset + long ASCII text string 'avcC'
	                -> 1 byte version = 8-bit hex version  (current = 1)
	                -> 1 byte H.264 profile = 8-bit unsigned stream profile
	                -> 1 byte H.264 compatible profiles = 8-bit hex flags
	                -> 1 byte H.264 level = 8-bit unsigned stream level
	                -> 1 1/2 nibble reserved = 6-bit unsigned value set to 63
	                -> 1/2 nibble NAL length = 2-bit length byte size type
	                  - 1 byte = 0 ; 2 bytes = 1 ; 4 bytes = 3
	                -> 1 byte number of SPS = 8-bit unsigned total
	                -> 2+ bytes SPS length = short unsigned length
	                -> + SPS NAL unit = hexdump
	                -> 1 byte number of PPS = 8-bit unsigned total
	                -> 2+ bytes PPS length = short unsigned length
	                -> + PPS NAL unit = hexdump 
	 * 
* * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_avc_config_atom(MP4DataStream bitstream) throws IOException { log.trace("AVC config"); log.trace("Offset: {}", bitstream.getOffset()); //store the decoder config bytes videoConfigBytes = new byte[(int) size - 8]; for (int b = 0; b < videoConfigBytes.length; b++) { videoConfigBytes[b] = (byte) bitstream.readBytes(1); switch (b) { //0 / version case 1: //profile avcProfile = videoConfigBytes[b]; log.trace("AVC profile: {}", avcProfile); break; case 2: //compatible profile int avcCompatProfile = videoConfigBytes[b]; log.trace("AVC compatible profile: {}", avcCompatProfile); break; case 3: //avc level avcLevel = videoConfigBytes[b]; log.trace("AVC level: {}", avcLevel); break; case 4: //NAL length break; case 5: //SPS number int numberSPS = videoConfigBytes[b]; log.trace("Number of SPS: {}", numberSPS); break; default: } readed++; } return readed; } /** * Creates the PASP atom or Pixel Aspect Ratio. It is created by Quicktime * when exporting an MP4 file. The atom is required for ipod's and acts as * a container for the avcC atom in these cases. * * @param bitstream the input bitstream * @return the number of bytes which was being loaded */ public long create_pasp_atom(MP4DataStream bitstream) throws IOException { log.trace("Pixel aspect ratio"); int hSpacing = (int) bitstream.readBytes(4); int vSpacing = (int) bitstream.readBytes(4); log.trace("hSpacing: {} vSpacing: {}", hSpacing, vSpacing); readed += 8; MP4Atom child = MP4Atom.createAtom(bitstream); children.add(child); readed += child.getSize(); return readed; } /** * Creates the decompression param (wave) atom. * * @param bitstream the input bitstream * @return the number of bytes which was being loaded */ private long create_decompression_param_atom(MP4DataStream bitstream) throws IOException { log.trace("Decompression param"); while (readed < size) { MP4Atom child = MP4Atom.createAtom(bitstream); //log.debug("Child: {} size: {}", child, child.getSize()); if (child.getType() != 0) { children.add(child); } readed += child.getSize(); } return readed; } /** * Creates the format (frma) atom. * * @param bitstream the input bitstream * @return the number of bytes which was being loaded */ private long create_format_atom(MP4DataStream bitstream) throws IOException { log.trace("Format"); // Data format - The value of this field is copied from the data-format field of the sound sample description. while (readed < size) { MP4Atom child = MP4Atom.createAtom(bitstream); children.add(child); readed += child.getSize(); } return readed; } /** * Loads Audio Channel Layout atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_chan_atom(MP4DataStream bitstream) throws IOException { log.trace("Audio Channel Layout Atom atom"); create_full_atom(bitstream); // Audio channel layout - A big-endian AudioChannelLayout structure as defined in CoreAudioTypes.h. // See the Mac OS X Developer Library for CoreAudio framework details while (readed < size) { MP4Atom child = MP4Atom.createAtom(bitstream); children.add(child); readed += child.getSize(); } return readed; } /** * Loads M4ESDAtom atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_esd_atom(MP4DataStream bitstream) throws IOException { log.trace("Elementary stream descriptor atom"); create_full_atom(bitstream); esd_descriptor = MP4Descriptor.createDescriptor(bitstream); readed += esd_descriptor.getReaded(); log.trace("Read for descriptor: {}", esd_descriptor.getReaded()); while (readed < size) { MP4Atom child = MP4Atom.createAtom(bitstream); children.add(child); readed += child.getSize(); } return readed; } /** * Returns the ESD descriptor. */ public MP4Descriptor getEsd_descriptor() { return esd_descriptor; } /** * Loads composition time to sample atom from the input bitstream. * @param bitstream the input bitstream * @return the number of bytes which was being loaded. */ public long create_composition_time_to_sample_atom(MP4DataStream bitstream) throws IOException { log.trace("Composition time to sample atom"); create_full_atom(bitstream); comptimeToSamplesRecords = new Vector(); entryCount = (int) bitstream.readBytes(4); log.trace("Composition time to sample entries: {}", entryCount); readed += 4; for (int i = 0; i < entryCount; i++) { int sampleCount = (int) bitstream.readBytes(4); int sampleOffset = (int) bitstream.readBytes(4); //log.trace("Sync entry: {}", sample); comptimeToSamplesRecords.addElement(new CompositionTimeSampleRecord(sampleCount, sampleOffset)); readed += 8; } return readed; } public Vector getCompositionTimeToSamplesRecords() { return comptimeToSamplesRecords; } /** * Converts the time in seconds since midnight 1 Jan 1904 to the Date. * @param movieTime the time in milliseconds since midnight 1 Jan 1904. * @return the Date object. */ public static final Date createDate(long movieTime) { return new Date(movieTime * 1000 - 2082850791998L); } /** * Convert the atom identifer to an integer. * * @param type * @return atom type as an integer */ public static int typeToInt(String type) { int result = (type.charAt(0) << 24) + (type.charAt(1) << 16) + (type.charAt(2) << 8) + type.charAt(3); return result; } /** * Convert the atom integer to a string. * * @param type * @return atom type as a string */ public static String intToType(int type) { StringBuilder st = new StringBuilder(); st.append((char) ((type >> 24) & 0xff)); st.append((char) ((type >> 16) & 0xff)); st.append((char) ((type >> 8) & 0xff)); st.append((char) (type & 0xff)); return st.toString(); } /** * Gets children from this atom. * @return children from this atom. */ public List getChildren() { return children; } /** * Gets the size of this atom. * @return the size of this atom. */ public long getSize() { return size; } /** * Returns the type of this atom. */ public int getType() { return type; } /** * Returns the name of this atom. */ public String toString() { return intToType(type); } public static class Record { private int firstChunk; private int samplesPerChunk; private int sampleDescriptionIndex; public Record(int firstChunk, int samplesPerChunk, int sampleDescriptionIndex) { this.firstChunk = firstChunk; this.samplesPerChunk = samplesPerChunk; this.sampleDescriptionIndex = sampleDescriptionIndex; } public int getFirstChunk() { return firstChunk; } public int getSamplesPerChunk() { return samplesPerChunk; } public int getSampleDescriptionIndex() { return sampleDescriptionIndex; } } public static class TimeSampleRecord { private int consecutiveSamples; private int sampleDuration; public TimeSampleRecord(int consecutiveSamples, int sampleDuration) { this.consecutiveSamples = consecutiveSamples; this.sampleDuration = sampleDuration; } public int getConsecutiveSamples() { return consecutiveSamples; } public int getSampleDuration() { return sampleDuration; } } public static class CompositionTimeSampleRecord { private int consecutiveSamples; private int sampleOffset; public CompositionTimeSampleRecord(int consecutiveSamples, int sampleOffset) { this.consecutiveSamples = consecutiveSamples; this.sampleOffset = sampleOffset; } public int getConsecutiveSamples() { return consecutiveSamples; } public int getSampleOffset() { return sampleOffset; } public void setSampleOffset(int offset) { sampleOffset = offset; } } } red5-1.0~svn4374.orig/src/org/red5/io/mp4/MP4DataStream.java0000644000175000017500000000635211706617130023060 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp4; import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /** * Wrapper class for input streams containing MPEG4 data. * * Original idea based on code from MediaFrame (http://www.mediaframe.org) * * 11/2011 - Converted to use NIO * * @author Paul Gregoire (mondain@gmail.com) */ public final class MP4DataStream { /** The input stream. */ private FileChannel channel; /** The current offset (position) in the stream. */ private long offset = 0; /** * Constructs an MP4DataStream object using the specified * MPEG4 input stream. * * @param is the MPEG4 input stream. */ public MP4DataStream(FileInputStream is) { channel = is.getChannel(); } /** * Reads "n" bytes from the channel. * * @param n * @return long value from the channel * @throws IOException */ public long readBytes(int n) throws IOException { ByteBuffer buf = ByteBuffer.allocate(n); channel.read(buf); buf.flip(); long result = 0; switch (n) { case 1: result = buf.get(); break; case 2: result = buf.getShort(); break; case 4: result = buf.getInt(); break; case 8: result = buf.getLong(); break; default: // anything longer than long is not yet supported } buf.clear(); // set the current position in offset offset = channel.position(); //System.out.println(result); return result; } /** * Returns a string of "n" bytes in length from the channel. * * @param n * @return string from the channel * @throws IOException */ public String readString(int n) throws IOException { ByteBuffer buf = ByteBuffer.allocate(n); channel.read(buf); buf.flip(); // set the current position in offset offset = channel.position(); String result = new String(buf.array()); //System.out.println(result); return result; } /** * Skip ahead in the channel by "n" bytes. * * @param n * @throws IOException */ public void skipBytes(long n) throws IOException { channel.position(channel.position() + n); // set the current position in offset offset = channel.position(); } public long getOffset() { try { return channel.position(); } catch (IOException e) { } return offset; } public FileChannel getChannel() { return channel; } public void close() throws IOException { channel.close(); channel = null; } } red5-1.0~svn4374.orig/src/org/red5/io/mp4/IMP4.java0000644000175000017500000000656511706617130021231 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp4; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map; import org.red5.io.IStreamableFile; import org.red5.io.ITagReader; import org.red5.io.ITagWriter; import org.red5.io.flv.meta.IMetaData; import org.red5.io.flv.meta.IMetaService; /** * Represents MP4 file * * @author Paul Gregoire (mondain@gmail.com) */ public interface IMP4 extends IStreamableFile { /** * Returns a boolean stating whether the mp4 has metadata * * @return boolean true if file has injected metadata, false otherwise */ public boolean hasMetaData(); /** * Sets the metadata * * @param metadata Metadata object * @throws FileNotFoundException File not found * @throws IOException Any other I/O exception */ public void setMetaData(IMetaData metadata) throws FileNotFoundException, IOException; /** * Sets the MetaService through Spring * * @param service Metadata service */ public void setMetaService(IMetaService service); /** * Returns a map of the metadata * * @return metadata File metadata * @throws FileNotFoundException File not found */ public IMetaData getMetaData() throws FileNotFoundException; /** * Returns a boolean stating whether a mp4 has keyframedata * * @return boolean true if file has keyframe metadata, false otherwise */ public boolean hasKeyFrameData(); /** * Sets the keyframe data of a mp4 file * * @param keyframedata Keyframe metadata */ public void setKeyFrameData(Map keyframedata); /** * Gets the keyframe data * * @return keyframedata Keyframe metadata */ public Map getKeyFrameData(); /** * Refreshes the headers. Usually used after data is added to the mp4 file * * @throws IOException Any I/O exception */ public void refreshHeaders() throws IOException; /** * Flushes Header * * @throws IOException Any I/O exception */ public void flushHeaders() throws IOException; /** * Returns a Reader closest to the nearest keyframe * * @param seekPoint Point in file we are seeking around * @return reader Tag reader closest to that point */ public ITagReader readerFromNearestKeyFrame(int seekPoint); /** * Returns a Writer based on the nearest key frame * * @param seekPoint Point in file we are seeking around * @return writer Tag writer closest to that point */ public ITagWriter writerFromNearestKeyFrame(int seekPoint); } red5-1.0~svn4374.orig/src/org/red5/io/mp4/impl/0000755000175000017500000000000011760512574020610 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/mp4/impl/MP4Service.java0000644000175000017500000000604011706617130023366 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp4.impl; import java.io.File; import java.io.IOException; import org.red5.io.BaseStreamableFileService; import org.red5.io.IStreamableFile; import org.red5.io.mp4.IMP4Service; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; /** * A MP4ServiceImpl sets up the service and hands out MP4 objects to * its callers. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire, (mondain@gmail.com) */ public class MP4Service extends BaseStreamableFileService implements IMP4Service { /** * Serializer */ private Serializer serializer; /** * Deserializer */ private Deserializer deserializer; /** * File extensions handled by this service. If there are more than one, they * are comma separated. '.mp4' must be the first on the list because it is the * default file extension for mp4 files. * * @see http://help.adobe.com/en_US/flashmediaserver/devguide/WS5b3ccc516d4fbf351e63e3d11a0773d117-7fc8.html */ private static String extension = ".mp4,.f4v,.mov,.3gp,.3g2"; private static String prefix = "mp4"; /** {@inheritDoc} */ @Override public void setPrefix(String prefix) { MP4Service.prefix = prefix; } /** {@inheritDoc} */ @Override public String getPrefix() { return prefix; } /** {@inheritDoc} */ @Override public void setExtension(String extension) { MP4Service.extension = extension; } /** {@inheritDoc} */ @Override public String getExtension() { return extension; } /** * {@inheritDoc} */ public void setSerializer(Serializer serializer) { this.serializer = serializer; } /** {@inheritDoc} */ public void setDeserializer(Deserializer deserializer) { this.deserializer = deserializer; } /** {@inheritDoc} */ @Override public IStreamableFile getStreamableFile(File file) throws IOException { return new MP4(file); } /** * Getter for serializer * * @return Serializer */ public Serializer getSerializer() { return serializer; } /** * Getter for deserializer * * @return Deserializer */ public Deserializer getDeserializer() { return deserializer; } } red5-1.0~svn4374.orig/src/org/red5/io/mp4/impl/MP4Reader.java0000644000175000017500000015502511747635016023210 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp4.impl; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Vector; import java.util.concurrent.Semaphore; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.IStreamableFile; import org.red5.io.ITag; import org.red5.io.ITagReader; import org.red5.io.IoConstants; import org.red5.io.amf.Output; import org.red5.io.flv.IKeyFrameDataAnalyzer; import org.red5.io.flv.impl.Tag; import org.red5.io.mp4.MP4Atom; import org.red5.io.mp4.MP4Atom.CompositionTimeSampleRecord; import org.red5.io.mp4.MP4DataStream; import org.red5.io.mp4.MP4Descriptor; import org.red5.io.mp4.MP4Frame; import org.red5.io.object.Serializer; import org.red5.io.utils.HexDump; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This reader is used to read the contents of an MP4 file. * * NOTE: This class is not implemented as thread-safe, the caller * should ensure the thread-safety. *

* New NetStream notifications *
* Two new notifications facilitate the implementation of the playback components: *

    *
  • NetStream.Play.FileStructureInvalid: This event is sent if the player detects * an MP4 with an invalid file structure. Flash Player cannot play files that have * invalid file structures.
  • *
  • NetStream.Play.NoSupportedTrackFound: This event is sent if the player does not * detect any supported tracks. If there aren't any supported video, audio or data * tracks found, Flash Player does not play the file.
  • *
*

* * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class MP4Reader implements IoConstants, ITagReader, IKeyFrameDataAnalyzer { private static Logger log = LoggerFactory.getLogger(MP4Reader.class); /** Audio packet prefix */ public final static byte[] PREFIX_AUDIO_FRAME = new byte[] { (byte) 0xaf, (byte) 0x01 }; /** Blank AAC data **/ public final static byte[] EMPTY_AAC = { (byte) 0x21, (byte) 0x10, (byte) 0x04, (byte) 0x60, (byte) 0x8c, (byte) 0x1c }; /** Video packet prefix for the decoder frame */ public final static byte[] PREFIX_VIDEO_CONFIG_FRAME = new byte[] { (byte) 0x17, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; /** Video packet prefix for key frames */ public final static byte[] PREFIX_VIDEO_KEYFRAME = new byte[] { (byte) 0x17, (byte) 0x01 }; /** Video packet prefix for standard frames (interframe) */ public final static byte[] PREFIX_VIDEO_FRAME = new byte[] { (byte) 0x27, (byte) 0x01 }; /** * File */ private File file; /** * Input stream */ private MP4DataStream fis; /** * File channel */ private FileChannel channel; /** Mapping between file position and timestamp in ms. */ private HashMap timePosMap; private HashMap samplePosMap; /** Whether or not the clip contains a video track */ private boolean hasVideo = false; /** Whether or not the clip contains an audio track */ private boolean hasAudio = false; //default video codec private String videoCodecId = "avc1"; //default audio codec private String audioCodecId = "mp4a"; //decoder bytes / configs private byte[] audioDecoderBytes; private byte[] videoDecoderBytes; // duration in milliseconds private long duration; // movie time scale private int timeScale; private int width; private int height; //audio sample rate kHz private double audioTimeScale; private int audioChannels; //default to aac lc private int audioCodecType = 1; private int videoSampleCount; private double fps; private double videoTimeScale; private int avcLevel; private int avcProfile; private String formattedDuration; private long moovOffset; private long mdatOffset; //samples to chunk mappings private Vector videoSamplesToChunks; private Vector audioSamplesToChunks; //keyframe - sample numbers private Vector syncSamples; //samples private Vector videoSamples; private Vector audioSamples; //chunk offsets private Vector videoChunkOffsets; private Vector audioChunkOffsets; //sample duration private int videoSampleDuration = 125; private int audioSampleDuration = 1024; //keep track of current frame / sample private int currentFrame = 0; private int prevFrameSize = 0; private int prevVideoTS = -1; private List frames = new ArrayList(); @SuppressWarnings("unused") private long audioCount; @SuppressWarnings("unused") private long videoCount; // composition time to sample entries private Vector compositionTimes; /** * Container for metadata and any other tags that should * be sent prior to media data. */ private LinkedList firstTags = new LinkedList(); /** * Container for seek points in the video. These are the time stamps * for the key frames or samples. */ private LinkedList seekPoints; private final Semaphore lock = new Semaphore(1, true); /** Constructs a new MP4Reader. */ MP4Reader() { } /** * Creates MP4 reader from file input stream, sets up metadata generation flag. * * @param f File input stream */ public MP4Reader(File f) throws IOException { if (null == f) { log.warn("Reader was passed a null file"); log.debug("{}", ToStringBuilder.reflectionToString(this)); } this.file = f; this.fis = new MP4DataStream(new FileInputStream(f)); channel = fis.getChannel(); //decode all the info that we want from the atoms decodeHeader(); //analyze the samples/chunks and build the keyframe meta data analyzeFrames(); //add meta data firstTags.add(createFileMeta()); //create / add the pre-streaming (decoder config) tags createPreStreamingTags(0, false); } /** * This handles the moov atom being at the beginning or end of the file, so the mdat may also * be before or after the moov atom. */ public void decodeHeader() { try { // the first atom will/should be the type MP4Atom type = MP4Atom.createAtom(fis); // expect ftyp log.debug("Type {}", MP4Atom.intToType(type.getType())); // we want a moov and an mdat, anything else will throw the invalid file type error MP4Atom moov = null; MP4Atom mdat = null; while (moov == null || mdat == null) { MP4Atom atom = MP4Atom.createAtom(fis); switch (atom.getType()) { case 1836019574: //moov moov = atom; // expect moov log.debug("Type {}", MP4Atom.intToType(moov.getType())); log.debug("moov children: {}", moov.getChildren()); moovOffset = fis.getOffset() - moov.getSize(); MP4Atom mvhd = moov.lookup(MP4Atom.typeToInt("mvhd"), 0); if (mvhd != null) { log.debug("Movie header atom found"); //get the initial timescale timeScale = mvhd.getTimeScale(); duration = mvhd.getDuration(); log.debug("Time scale {} Duration {}", timeScale, duration); } MP4Atom meta = moov.lookup(MP4Atom.typeToInt("meta"), 0); if (meta != null) { log.debug("Meta atom found"); log.debug("{}", ToStringBuilder.reflectionToString(meta)); } MP4Atom udta = moov.lookup(MP4Atom.typeToInt("udta"), 0); if (udta != null) { log.debug("User data atom found"); log.debug("{}", ToStringBuilder.reflectionToString(udta)); if ((meta = udta.lookup(MP4Atom.typeToInt("meta"), 0)) != null) { log.debug("Meta atom found"); log.debug("{}", ToStringBuilder.reflectionToString(meta)); } } //we would like to have two tracks, but it shouldn't be a requirement int loops = 0; int tracks = 0; do { MP4Atom trak = moov.lookup(MP4Atom.typeToInt("trak"), loops); if (trak != null) { log.debug("Track atom found"); log.debug("trak children: {}", trak.getChildren()); // trak: tkhd, edts, mdia MP4Atom tkhd = trak.lookup(MP4Atom.typeToInt("tkhd"), 0); if (tkhd != null) { log.debug("Track header atom found"); log.debug("tkhd children: {}", tkhd.getChildren()); if (tkhd.getWidth() > 0) { width = tkhd.getWidth(); height = tkhd.getHeight(); log.debug("Width {} x Height {}", width, height); } } MP4Atom edts = trak.lookup(MP4Atom.typeToInt("edts"), 0); if (edts != null) { log.debug("Edit atom found"); log.debug("edts children: {}", edts.getChildren()); //log.debug("Width {} x Height {}", edts.getWidth(), edts.getHeight()); } MP4Atom mdia = trak.lookup(MP4Atom.typeToInt("mdia"), 0); if (mdia != null) { log.debug("Media atom found"); // mdia: mdhd, hdlr, minf int scale = 0; //get the media header atom MP4Atom mdhd = mdia.lookup(MP4Atom.typeToInt("mdhd"), 0); if (mdhd != null) { log.debug("Media data header atom found"); //this will be for either video or audio depending media info scale = mdhd.getTimeScale(); log.debug("Time scale {}", scale); } MP4Atom hdlr = mdia.lookup(MP4Atom.typeToInt("hdlr"), 0); if (hdlr != null) { log.debug("Handler ref atom found"); // soun or vide log.debug("Handler type: {}", MP4Atom.intToType(hdlr.getHandlerType())); String hdlrType = MP4Atom.intToType(hdlr.getHandlerType()); if ("vide".equals(hdlrType)) { hasVideo = true; if (scale > 0) { videoTimeScale = scale * 1.0; log.debug("Video time scale: {}", videoTimeScale); } } else if ("soun".equals(hdlrType)) { hasAudio = true; if (scale > 0) { audioTimeScale = scale * 1.0; log.debug("Audio time scale: {}", audioTimeScale); } } tracks++; } MP4Atom minf = mdia.lookup(MP4Atom.typeToInt("minf"), 0); if (minf != null) { log.debug("Media info atom found"); // minf: (audio) smhd, dinf, stbl / (video) vmhd, // dinf, stbl MP4Atom smhd = minf.lookup(MP4Atom.typeToInt("smhd"), 0); if (smhd != null) { log.debug("Sound header atom found"); MP4Atom dinf = minf.lookup(MP4Atom.typeToInt("dinf"), 0); if (dinf != null) { log.debug("Data info atom found"); // dinf: dref log.debug("Sound dinf children: {}", dinf.getChildren()); MP4Atom dref = dinf.lookup(MP4Atom.typeToInt("dref"), 0); if (dref != null) { log.debug("Data reference atom found"); } } MP4Atom stbl = minf.lookup(MP4Atom.typeToInt("stbl"), 0); if (stbl != null) { log.debug("Sample table atom found"); // stbl: stsd, stts, stss, stsc, stsz, stco, // stsh log.debug("Sound stbl children: {}", stbl.getChildren()); // stsd - sample description // stts - time to sample // stsc - sample to chunk // stsz - sample size // stco - chunk offset //stsd - has codec child MP4Atom stsd = stbl.lookup(MP4Atom.typeToInt("stsd"), 0); if (stsd != null) { //stsd: mp4a log.debug("Sample description atom found, containing {} children", stsd.getChildren().size()); MP4Atom mp4a = stsd.getChildren().get(0); log.debug("MP4 audio atom found, containing {} children", mp4a.getChildren().size()); log.debug("mp4a: {}", ToStringBuilder.reflectionToString(mp4a)); //could set the audio codec here setAudioCodecId(MP4Atom.intToType(mp4a.getType())); //log.debug("{}", ToStringBuilder.reflectionToString(mp4a)); log.debug("Sample size: {}", mp4a.getSampleSize()); int ats = mp4a.getTimeScale(); //skip invalid audio time scale if (ats > 0) { audioTimeScale = ats * 1.0; } audioChannels = mp4a.getChannelCount(); log.debug("Sample rate (audio time scale): {}", audioTimeScale); log.debug("Channels: {}", audioChannels); // look for esds MP4Atom esds = mp4a.lookup(MP4Atom.typeToInt("esds"), 0); if (esds == null) { // check for decompression param atom MP4Atom wave = mp4a.lookup(MP4Atom.typeToInt("wave"), 0); log.debug("Decompression param atom found, containing {} children", wave.getChildren().size()); log.debug("wave: {}", ToStringBuilder.reflectionToString(wave)); MP4Atom tmp = wave.getChildren().get(0); log.debug("Temp: {}", ToStringBuilder.reflectionToString(tmp)); esds = wave.lookup(MP4Atom.typeToInt("esds"), 0); if (esds == null) { tmp = wave.lookup(MP4Atom.typeToInt("mp4a"), 0); esds = tmp.lookup(MP4Atom.typeToInt("esds"), 0); } } //mp4a: esds if (esds != null) { log.debug("Elementary stream descriptor atom found, containing {} children", esds.getChildren().size()); log.debug("esds: {}", ToStringBuilder.reflectionToString(esds)); MP4Descriptor descriptor = esds.getEsd_descriptor(); if (descriptor != null) { log.debug("ESD descriptor: {}", ToStringBuilder.reflectionToString(descriptor)); Vector children = descriptor.getChildren(); for (int e = 0; e < children.size(); e++) { MP4Descriptor descr = children.get(e); log.debug("Descriptor child: {}", ToStringBuilder.reflectionToString(descr)); if (descr.getChildren().size() > 0) { Vector children2 = descr.getChildren(); for (int e2 = 0; e2 < children2.size(); e2++) { MP4Descriptor descr2 = children2.get(e2); log.debug("{}", ToStringBuilder.reflectionToString(descr2)); // http://stackoverflow.com/questions/3987850/mp4-atom-how-to-discriminate-the-audio-codec-is-it-aac-or-mp3 if (descr2.getType() == MP4Descriptor.MP4DecSpecificInfoDescriptorTag) { //we only want the MP4DecSpecificInfoDescriptorTag audioDecoderBytes = descr2.getDSID(); /* the first 5 (0-4) bits tell us about the coder used for aacaot/aottype * http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio 0 - NULL 1 - AAC Main (a deprecated AAC profile from MPEG-2) 2 - AAC LC or backwards compatible HE-AAC 3 - AAC Scalable Sample Rate 4 - AAC LTP (a replacement for AAC Main, rarely used) 5 - HE-AAC explicitly signaled (Non-backward compatible) 23 - Low Delay AAC 29 - HE-AACv2 explicitly signaled 32 - MP3on4 Layer 1 33 - MP3on4 Layer 2 34 - MP3on4 Layer 3 */ byte audioCoderType = audioDecoderBytes[0]; //match first byte switch (audioCoderType) { case 0x02: log.debug("Audio type AAC LC"); case 0x11: //ER (Error Resilient) AAC LC log.debug("Audio type ER AAC LC"); default: audioCodecType = 1; //AAC LC break; case 0x01: log.debug("Audio type AAC Main"); audioCodecType = 0; //AAC Main break; case 0x03: log.debug("Audio type AAC SBR"); audioCodecType = 2; //AAC LC SBR break; case 0x05: case 0x1d: log.debug("Audio type AAC HE"); audioCodecType = 3; //AAC HE break; case 0x20: case 0x21: case 0x22: log.debug("Audio type MP3"); audioCodecType = 33; //MP3 audioCodecId = "mp3"; break; } log.debug("Audio coder type: {} {} id: {}", new Object[] { audioCoderType, Integer.toBinaryString(audioCoderType), audioCodecId }); //we want to break out of top level for loop e = 99; break; } } } } } } } //stsc - has Records MP4Atom stsc = stbl.lookup(MP4Atom.typeToInt("stsc"), 0); if (stsc != null) { log.debug("Sample to chunk atom found"); audioSamplesToChunks = stsc.getRecords(); log.debug("Record count: {}", audioSamplesToChunks.size()); MP4Atom.Record rec = audioSamplesToChunks.firstElement(); log.debug("Record data: Description index={} Samples per chunk={}", rec.getSampleDescriptionIndex(), rec.getSamplesPerChunk()); } //stsz - has Samples MP4Atom stsz = stbl.lookup(MP4Atom.typeToInt("stsz"), 0); if (stsz != null) { log.debug("Sample size atom found"); audioSamples = stsz.getSamples(); //vector full of integers log.debug("Sample size: {}", stsz.getSampleSize()); log.debug("Sample count: {}", audioSamples.size()); } //stco - has Chunks MP4Atom stco = stbl.lookup(MP4Atom.typeToInt("stco"), 0); if (stco != null) { log.debug("Chunk offset atom found"); //vector full of integers audioChunkOffsets = stco.getChunks(); log.debug("Chunk count: {}", audioChunkOffsets.size()); } else { //co64 - has Chunks MP4Atom co64 = stbl.lookup(MP4Atom.typeToInt("co64"), 0); if (co64 != null) { log.debug("Chunk offset (64) atom found"); //vector full of longs audioChunkOffsets = co64.getChunks(); log.debug("Chunk count: {}", audioChunkOffsets.size()); } } //stts - has TimeSampleRecords MP4Atom stts = stbl.lookup(MP4Atom.typeToInt("stts"), 0); if (stts != null) { log.debug("Time to sample atom found"); Vector records = stts.getTimeToSamplesRecords(); log.debug("Record count: {}", records.size()); MP4Atom.TimeSampleRecord rec = records.firstElement(); log.debug("Record data: Consecutive samples={} Duration={}", rec.getConsecutiveSamples(), rec.getSampleDuration()); //if we have 1 record it means all samples have the same duration audioSampleDuration = rec.getSampleDuration(); } } } MP4Atom vmhd = minf.lookup(MP4Atom.typeToInt("vmhd"), 0); if (vmhd != null) { log.debug("Video header atom found"); MP4Atom dinf = minf.lookup(MP4Atom.typeToInt("dinf"), 0); if (dinf != null) { log.debug("Data info atom found"); // dinf: dref log.debug("Video dinf children: {}", dinf.getChildren()); MP4Atom dref = dinf.lookup(MP4Atom.typeToInt("dref"), 0); if (dref != null) { log.debug("Data reference atom found"); } } MP4Atom stbl = minf.lookup(MP4Atom.typeToInt("stbl"), 0); if (stbl != null) { log.debug("Sample table atom found"); // stbl: stsd, stts, stss, stsc, stsz, stco, // stsh log.debug("Video stbl children: {}", stbl.getChildren()); // stsd - sample description // stts - (decoding) time to sample // stsc - sample to chunk // stsz - sample size // stco - chunk offset // ctts - (composition) time to sample // stss - sync sample // sdtp - independent and disposable samples //stsd - has codec child MP4Atom stsd = stbl.lookup(MP4Atom.typeToInt("stsd"), 0); if (stsd != null) { log.debug("Sample description atom found"); log.debug("Sample description (video) stsd children: {}", stsd.getChildren()); MP4Atom avc1 = stsd.lookup(MP4Atom.typeToInt("avc1"), 0); if (avc1 != null) { log.debug("AVC1 children: {}", avc1.getChildren()); //set the video codec here - may be avc1 or mp4v setVideoCodecId(MP4Atom.intToType(avc1.getType())); //video decoder config //TODO may need to be generic later MP4Atom codecChild = avc1.lookup(MP4Atom.typeToInt("avcC"), 0); if (codecChild != null) { avcLevel = codecChild.getAvcLevel(); log.debug("AVC level: {}", avcLevel); avcProfile = codecChild.getAvcProfile(); log.debug("AVC Profile: {}", avcProfile); log.debug("AVCC size: {}", codecChild.getSize()); videoDecoderBytes = codecChild.getVideoConfigBytes(); log.debug("Video config bytes: {}", ToStringBuilder.reflectionToString(videoDecoderBytes)); } else { //quicktime and ipods use a pixel aspect atom //since we have no avcC check for this and avcC may //be a child MP4Atom pasp = avc1.lookup(MP4Atom.typeToInt("pasp"), 0); if (pasp != null) { log.debug("PASP children: {}", pasp.getChildren()); codecChild = pasp.lookup(MP4Atom.typeToInt("avcC"), 0); if (codecChild != null) { avcLevel = codecChild.getAvcLevel(); log.debug("AVC level: {}", avcLevel); avcProfile = codecChild.getAvcProfile(); log.debug("AVC Profile: {}", avcProfile); log.debug("AVCC size: {}", codecChild.getSize()); videoDecoderBytes = codecChild.getVideoConfigBytes(); log.debug("Video config bytes: {}", ToStringBuilder.reflectionToString(videoDecoderBytes)); } } } } else { //look for mp4v MP4Atom mp4v = stsd.lookup(MP4Atom.typeToInt("mp4v"), 0); if (mp4v != null) { log.debug("MP4V children: {}", mp4v.getChildren()); //set the video codec here - may be avc1 or mp4v setVideoCodecId(MP4Atom.intToType(mp4v.getType())); //look for esds MP4Atom codecChild = mp4v.lookup(MP4Atom.typeToInt("esds"), 0); if (codecChild != null) { //look for descriptors MP4Descriptor descriptor = codecChild.getEsd_descriptor(); log.debug("{}", ToStringBuilder.reflectionToString(descriptor)); if (descriptor != null) { Vector children = descriptor.getChildren(); for (int e = 0; e < children.size(); e++) { MP4Descriptor descr = children.get(e); log.debug("{}", ToStringBuilder.reflectionToString(descr)); if (descr.getChildren().size() > 0) { Vector children2 = descr.getChildren(); for (int e2 = 0; e2 < children2.size(); e2++) { MP4Descriptor descr2 = children2.get(e2); log.debug("{}", ToStringBuilder.reflectionToString(descr2)); if (descr2.getType() == MP4Descriptor.MP4DecSpecificInfoDescriptorTag) { //we only want the MP4DecSpecificInfoDescriptorTag videoDecoderBytes = new byte[descr2.getDSID().length - 8]; System.arraycopy(descr2.getDSID(), 8, videoDecoderBytes, 0, videoDecoderBytes.length); log.debug("Video config bytes: {}", ToStringBuilder.reflectionToString(videoDecoderBytes)); //we want to break out of top level for loop e = 99; break; } } } } } } } } log.debug("{}", ToStringBuilder.reflectionToString(avc1)); } //stsc - has Records MP4Atom stsc = stbl.lookup(MP4Atom.typeToInt("stsc"), 0); if (stsc != null) { log.debug("Sample to chunk atom found"); videoSamplesToChunks = stsc.getRecords(); log.debug("Record count: {}", videoSamplesToChunks.size()); MP4Atom.Record rec = videoSamplesToChunks.firstElement(); log.debug("Record data: Description index={} Samples per chunk={}", rec.getSampleDescriptionIndex(), rec.getSamplesPerChunk()); } //stsz - has Samples MP4Atom stsz = stbl.lookup(MP4Atom.typeToInt("stsz"), 0); if (stsz != null) { log.debug("Sample size atom found"); //vector full of integers videoSamples = stsz.getSamples(); //if sample size is 0 then the table must be checked due //to variable sample sizes log.debug("Sample size: {}", stsz.getSampleSize()); videoSampleCount = videoSamples.size(); log.debug("Sample count: {}", videoSampleCount); } //stco - has Chunks MP4Atom stco = stbl.lookup(MP4Atom.typeToInt("stco"), 0); if (stco != null) { log.debug("Chunk offset atom found"); //vector full of integers videoChunkOffsets = stco.getChunks(); log.debug("Chunk count: {}", videoChunkOffsets.size()); } else { //co64 - has Chunks MP4Atom co64 = stbl.lookup(MP4Atom.typeToInt("co64"), 0); if (co64 != null) { log.debug("Chunk offset (64) atom found"); //vector full of longs videoChunkOffsets = co64.getChunks(); log.debug("Chunk count: {}", videoChunkOffsets.size()); // double the timescale for video, since it seems to run at // half-speed when co64 is used (seems hacky) videoTimeScale = scale * 2.0; log.debug("Video time scale: {}", videoTimeScale); } } //stss - has Sync - no sync means all samples are keyframes MP4Atom stss = stbl.lookup(MP4Atom.typeToInt("stss"), 0); if (stss != null) { log.debug("Sync sample atom found"); //vector full of integers syncSamples = stss.getSyncSamples(); log.debug("Keyframes: {}", syncSamples.size()); } //stts - has TimeSampleRecords MP4Atom stts = stbl.lookup(MP4Atom.typeToInt("stts"), 0); if (stts != null) { log.debug("Time to sample atom found"); Vector records = stts.getTimeToSamplesRecords(); log.debug("Record count: {}", records.size()); MP4Atom.TimeSampleRecord rec = records.firstElement(); log.debug("Record data: Consecutive samples={} Duration={}", rec.getConsecutiveSamples(), rec.getSampleDuration()); //if we have 1 record it means all samples have the same duration videoSampleDuration = rec.getSampleDuration(); } //ctts - (composition) time to sample MP4Atom ctts = stbl.lookup(MP4Atom.typeToInt("ctts"), 0); if (ctts != null) { log.debug("Composition time to sample atom found"); //vector full of integers compositionTimes = ctts.getCompositionTimeToSamplesRecords(); log.debug("Record count: {}", compositionTimes.size()); if (log.isTraceEnabled()) { for (MP4Atom.CompositionTimeSampleRecord rec : compositionTimes) { double offset = rec.getSampleOffset(); if (scale > 0d) { offset = (offset / (double) scale) * 1000.0; rec.setSampleOffset((int) offset); } log.trace("Record data: Consecutive samples={} Offset={}", rec.getConsecutiveSamples(), rec.getSampleOffset()); } } } } } } } } loops++; } while (loops < 3); log.trace("Busted out of track loop with {} tracks after {} loops", tracks, loops); //calculate FPS fps = (videoSampleCount * timeScale) / (double) duration; log.debug("FPS calc: ({} * {}) / {}", new Object[] { videoSampleCount, timeScale, duration }); log.debug("FPS: {}", fps); //real duration StringBuilder sb = new StringBuilder(); double videoTime = ((double) duration / (double) timeScale); log.debug("Video time: {}", videoTime); int minutes = (int) (videoTime / 60); if (minutes > 0) { sb.append(minutes); sb.append('.'); } //formatter for seconds / millis NumberFormat df = DecimalFormat.getInstance(); df.setMaximumFractionDigits(2); sb.append(df.format((videoTime % 60))); formattedDuration = sb.toString(); log.debug("Time: {}", formattedDuration); break; case 1835295092: //mdat mdat = atom; long dataSize = mdat.getSize(); log.debug("mdat: {}", ToStringBuilder.reflectionToString(mdat)); log.debug("Read the mdat atom at: {}", fis.getOffset()); mdatOffset = fis.getOffset() - dataSize; log.debug("File size: {} mdat size: {}", file.length(), dataSize); break; case 1718773093: //free case 2003395685: //wide break; default: log.debug("Unexpected atom: {}", MP4Atom.intToType(atom.getType())); FileChannel fc = fis.getChannel(); ByteBuffer buf = ByteBuffer.allocate(4); if (moov != null && mdat == null) { // if we have moov but no mdat fc.position(moov.getSize()); log.debug("Search starting at: {}", fc.position()); String atype = null; // search for mdat do { long pos = fc.position(); //long offset = fis.getOffset(); //log.debug("Pos: {} Offset: {}", pos, offset); fc.read(buf); buf.flip(); atype = MP4Atom.intToType(buf.getInt()); //log.debug("Type: {}", atype); fc.position(pos + 1); buf.clear(); } while (!atype.equals("mdat")); fc.position(fc.position() - 5); log.debug("Found the mdat atom at: {}", fc.position()); } if (moov == null && mdat == null) { // we're missing both primary atoms at the beginning log.debug("Search starting at: {}", fc.position()); String atype = null; // search for moov first do { long pos = fc.position(); log.debug("Pos: {}", pos); fc.read(buf); buf.flip(); atype = MP4Atom.intToType(buf.getInt()); //log.debug("Type: {}", atype); fc.position(pos + 1); buf.clear(); } while (!atype.equals("moov")); fc.position(fc.position() - 5); log.debug("Found the moov atom at: {}", fc.position()); } buf.clear(); } } //add the tag name (size) to the offsets moovOffset += 8; mdatOffset += 8; log.debug("Offsets moov: {} mdat: {}", moovOffset, mdatOffset); } catch (IOException e) { log.error("Exception decoding header / atoms", e); } } /** * Get the total readable bytes in a file or IoBuffer. * * @return Total readable bytes */ public long getTotalBytes() { try { return channel.size(); } catch (Exception e) { log.error("Error getTotalBytes", e); } if (file != null) { //just return the file size return file.length(); } else { return 0; } } /** * Get the current position in a file or IoBuffer. * * @return Current position in a file */ private long getCurrentPosition() { try { //if we are at the end of the file drop back to mdat offset if (channel.position() == channel.size()) { log.debug("Reached end of file, going back to data offset"); channel.position(mdatOffset); } return channel.position(); } catch (Exception e) { log.error("Error getCurrentPosition", e); return 0; } } /** {@inheritDoc} */ public boolean hasVideo() { return hasVideo; } /** * Returns the file buffer. * * @return File contents as byte buffer */ public IoBuffer getFileData() { // TODO as of now, return null will disable cache // we need to redesign the cache architecture so that // the cache is layered underneath FLVReader not above it, // thus both tag cache and file cache are feasible. return null; } /** {@inheritDoc} */ public IStreamableFile getFile() { // TODO wondering if we need to have a reference return null; } /** {@inheritDoc} */ public int getOffset() { // XXX what's the difference from getBytesRead return 0; } /** {@inheritDoc} */ public long getBytesRead() { // XXX should summarize the total bytes read or // just the current position? return getCurrentPosition(); } /** {@inheritDoc} */ public long getDuration() { return duration; } public String getVideoCodecId() { return videoCodecId; } public String getAudioCodecId() { return audioCodecId; } /** {@inheritDoc} */ public boolean hasMoreTags() { return currentFrame < frames.size(); } /** * Create tag for metadata event. * * Information mostly from http://www.kaourantin.net/2007/08/what-just-happened-to-video-on-web_20.html *
		width: Display width in pixels.
		height: Display height in pixels.
		duration: Duration in seconds. But unlike for FLV files this field will always be present.
		videocodecid: Usually a string such as "avc1" or "VP6F", for H.264 we report 'avc1'.
		audiocodecid: Usually a string such as ".mp3" or "mp4a", for AAC we report 'mp4a' and MP3 we report '.mp3'.
	    avcprofile: AVC profile number, values of 66, 77, 88, 100, 110, 122 or 144; which correspond to the H.264 profiles.
	    avclevel: AVC IDC level number, values between 10 and 51.
	    aottype: Either 0, 1 or 2. This corresponds to AAC Main, AAC LC and SBR audio types.
	    moovposition: The offset in bytes of the moov atom in a file.
	    trackinfo: An array of objects containing various infomation about all the tracks in a file
	      ex.
	    	trackinfo[0].length: 7081
	    	trackinfo[0].timescale: 600
	    	trackinfo[0].sampledescription.sampletype: avc1
	    	trackinfo[0].language: und
	    	trackinfo[1].length: 525312
	    	trackinfo[1].timescale: 44100
	    	trackinfo[1].sampledescription.sampletype: mp4a
	    	trackinfo[1].language: und
	    
	    chapters: As mentioned above information about chapters in audiobooks.
		seekpoints: Array that lists the available keyframes in a file as time stamps in milliseconds. 
				This is optional as the MP4 file might not contain this information. Generally speaking, 
				most MP4 files will include this by default. You can directly feed the values into NetStream.seek();
	    videoframerate: The frame rate of the video if a monotone frame rate is used. 
	    		Most videos will have a monotone frame rate.
	    audiosamplerate: The original sampling rate of the audio track.
	    audiochannels: The original number of channels of the audio track.
		progressivedownloadinfo: Object that provides information from the "pdin" atom. This is optional 
				and many files will not have this field.
		tags: Array of key value pairs representing the information present in the "ilst" atom, which is 
				the equivalent of ID3 tags for MP4 files. These tags are mostly used by iTunes. 
	 * 
* * @return Metadata event tag */ ITag createFileMeta() { log.debug("Creating onMetaData"); // Create tag for onMetaData event IoBuffer buf = IoBuffer.allocate(1024); buf.setAutoExpand(true); Output out = new Output(buf); out.writeString("onMetaData"); Map props = new HashMap(); // Duration property props.put("duration", ((double) duration / (double) timeScale)); props.put("width", width); props.put("height", height); // Video codec id props.put("videocodecid", videoCodecId); props.put("avcprofile", avcProfile); props.put("avclevel", avcLevel); props.put("videoframerate", fps); // Audio codec id - watch for mp3 instead of aac props.put("audiocodecid", audioCodecId); props.put("aacaot", audioCodecType); props.put("audiosamplerate", audioTimeScale); props.put("audiochannels", audioChannels); // position of the moov atom props.put("moovposition", moovOffset); //props.put("chapters", ""); //this is for f4b - books if (seekPoints != null) { log.debug("Seekpoint list size: {}", seekPoints.size()); props.put("seekpoints", seekPoints); } //tags will only appear if there is an "ilst" atom in the file //props.put("tags", ""); List> arr = new ArrayList>(2); if (hasAudio) { Map audioMap = new HashMap(4); audioMap.put("timescale", audioTimeScale); audioMap.put("language", "und"); List> desc = new ArrayList>(1); audioMap.put("sampledescription", desc); Map sampleMap = new HashMap(1); sampleMap.put("sampletype", audioCodecId); desc.add(sampleMap); if (audioSamples != null) { audioMap.put("length_property", audioSampleDuration * audioSamples.size()); //release some memory, since we're done with the vectors audioSamples.clear(); audioSamples = null; } arr.add(audioMap); } if (hasVideo) { Map videoMap = new HashMap(3); videoMap.put("timescale", videoTimeScale); videoMap.put("language", "und"); List> desc = new ArrayList>(1); videoMap.put("sampledescription", desc); Map sampleMap = new HashMap(1); sampleMap.put("sampletype", videoCodecId); desc.add(sampleMap); if (videoSamples != null) { videoMap.put("length_property", videoSampleDuration * videoSamples.size()); //release some memory, since we're done with the vectors videoSamples.clear(); videoSamples = null; } arr.add(videoMap); } props.put("trackinfo", arr); //set this based on existence of seekpoints props.put("canSeekToEnd", (seekPoints != null)); out.writeMap(props, new Serializer()); buf.flip(); //now that all the meta properties are done, update the duration duration = Math.round(duration * 1000d); ITag result = new Tag(IoConstants.TYPE_METADATA, 0, buf.limit(), null, 0); result.setBody(buf); return result; } /** * Tag sequence * MetaData, Video config, Audio config, remaining audio and video * * Packet prefixes: * 17 00 00 00 00 = Video extra data (first video packet) * 17 01 00 00 00 = Video keyframe * 27 01 00 00 00 = Video interframe * af 00 ... 06 = Audio extra data (first audio packet) * af 01 = Audio frame * * Audio extra data(s): * af 00 = Prefix * 11 90 4f 14 = AAC Main = aottype 0 // 11 90 * 12 10 = AAC LC = aottype 1 * 13 90 56 e5 a5 48 00 = HE-AAC SBR = aottype 2 * 06 = Suffix * * Still not absolutely certain about this order or the bytes - need to verify later */ private void createPreStreamingTags(int timestamp, boolean clear) { log.debug("Creating pre-streaming tags"); if (clear) { firstTags.clear(); } ITag tag = null; IoBuffer body = null; if (hasVideo) { //video tag #1 body = IoBuffer.allocate(41); body.setAutoExpand(true); body.put(PREFIX_VIDEO_CONFIG_FRAME); //prefix if (videoDecoderBytes != null) { //because of other processing we do this check if (log.isDebugEnabled()) { log.debug("Video decoder bytes: {}", HexDump.byteArrayToHexString(videoDecoderBytes)); try { log.debug("Video bytes data: {}", new String(videoDecoderBytes, "UTF-8")); } catch (UnsupportedEncodingException e) { log.error("", e); } } body.put(videoDecoderBytes); } tag = new Tag(IoConstants.TYPE_VIDEO, timestamp, body.position(), null, 0); body.flip(); tag.setBody(body); //add tag firstTags.add(tag); } // TODO: Handle other mp4 container audio codecs like mp3 // mp3 header magic number ((int & 0xffe00000) == 0xffe00000) if (hasAudio) { //audio tag #1 if (audioDecoderBytes != null) { //because of other processing we do this check if (log.isDebugEnabled()) { log.debug("Audio decoder bytes: {}", HexDump.byteArrayToHexString(audioDecoderBytes)); try { log.debug("Audio bytes data: {}", new String(audioDecoderBytes, "UTF-8")); } catch (UnsupportedEncodingException e) { log.error("", e); } } body = IoBuffer.allocate(audioDecoderBytes.length + 3); body.setAutoExpand(true); body.put(new byte[] { (byte) 0xaf, (byte) 0 }); //prefix body.put(audioDecoderBytes); body.put((byte) 0x06); //suffix tag = new Tag(IoConstants.TYPE_AUDIO, timestamp, body.position(), null, 0); body.flip(); tag.setBody(body); //add tag firstTags.add(tag); } else { log.info("Audio decoder bytes were not available"); } } } /** * Packages media data for return to providers */ public ITag readTag() { ITag tag = null; try { lock.acquire(); //log.debug("Read tag"); //empty-out the pre-streaming tags first if (!firstTags.isEmpty()) { //log.debug("Returning pre-tag"); // Return first tags before media data return firstTags.removeFirst(); } //log.debug("Read tag - sample {} prevFrameSize {} audio: {} video: {}", new Object[]{currentSample, prevFrameSize, audioCount, videoCount}); //get the current frame MP4Frame frame = frames.get(currentFrame); log.debug("Playback #{} {}", currentFrame, frame); int sampleSize = frame.getSize(); int time = (int) Math.round(frame.getTime() * 1000.0); //log.debug("Read tag - dst: {} base: {} time: {}", new Object[]{frameTs, baseTs, time}); long samplePos = frame.getOffset(); //log.debug("Read tag - samplePos {}", samplePos); //determine frame type and packet body padding byte type = frame.getType(); //assume video type int pad = 5; if (type == TYPE_AUDIO) { pad = 2; } //create a byte buffer of the size of the sample ByteBuffer data = ByteBuffer.allocate(sampleSize + pad); try { //prefix is different for keyframes if (type == TYPE_VIDEO) { if (frame.isKeyFrame()) { //log.debug("Writing keyframe prefix"); data.put(PREFIX_VIDEO_KEYFRAME); } else { //log.debug("Writing interframe prefix"); data.put(PREFIX_VIDEO_FRAME); } // match the sample with its ctts / mdhd adjustment time int timeOffset = prevVideoTS != -1 ? time - prevVideoTS : 0; data.put((byte) ((timeOffset >>> 16) & 0xff)); data.put((byte) ((timeOffset >>> 8) & 0xff)); data.put((byte) (timeOffset & 0xff)); if (log.isTraceEnabled()) { byte[] prefix = new byte[5]; int p = data.position(); data.position(0); data.get(prefix); data.position(p); log.trace("{}", prefix); } // track video frame count videoCount++; prevVideoTS = time; } else { //log.debug("Writing audio prefix"); data.put(PREFIX_AUDIO_FRAME); // track audio frame count audioCount++; } // do we need to add the mdat offset to the sample position? channel.position(samplePos); // read from the channel channel.read(data); } catch (IOException e) { log.error("Error on channel position / read", e); } // chunk the data IoBuffer payload = IoBuffer.wrap(data.array()); // create the tag tag = new Tag(type, time, payload.limit(), payload, prevFrameSize); //log.debug("Read tag - type: {} body size: {}", (type == TYPE_AUDIO ? "Audio" : "Video"), tag.getBodySize()); // increment the frame number currentFrame++; // set the frame / tag size prevFrameSize = tag.getBodySize(); } catch (InterruptedException e) { log.warn("Exception acquiring lock", e); } finally { lock.release(); } //log.debug("Tag: {}", tag); return tag; } /** * Performs frame analysis and generates metadata for use in seeking. All the frames * are analyzed and sorted together based on time and offset. */ public void analyzeFrames() { log.debug("Analyzing frames"); // Maps positions, samples, timestamps to one another timePosMap = new HashMap(); samplePosMap = new HashMap(); // tag == sample int sample = 1; // position Long pos = null; // if audio-only, skip this if (videoSamplesToChunks != null) { // handle composite times int compositeIndex = 0; CompositionTimeSampleRecord compositeTimeEntry = null; if (compositionTimes != null && !compositionTimes.isEmpty()) { compositeTimeEntry = compositionTimes.remove(0); } for (int i = 0; i < videoSamplesToChunks.size(); i++) { MP4Atom.Record record = videoSamplesToChunks.get(i); int firstChunk = record.getFirstChunk(); int lastChunk = videoChunkOffsets.size(); if (i < videoSamplesToChunks.size() - 1) { MP4Atom.Record nextRecord = videoSamplesToChunks.get(i + 1); lastChunk = nextRecord.getFirstChunk() - 1; } for (int chunk = firstChunk; chunk <= lastChunk; chunk++) { int sampleCount = record.getSamplesPerChunk(); pos = videoChunkOffsets.elementAt(chunk - 1); while (sampleCount > 0) { //log.debug("Position: {}", pos); samplePosMap.put(sample, pos); //calculate ts double ts = (videoSampleDuration * (sample - 1)) / videoTimeScale; //check to see if the sample is a keyframe boolean keyframe = false; //some files appear not to have sync samples if (syncSamples != null) { keyframe = syncSamples.contains(sample); if (seekPoints == null) { seekPoints = new LinkedList(); } // get the timestamp int frameTs = (int) Math.round(ts * 1000.0); // add each key frames timestamp to the seek points list if (keyframe) { seekPoints.add(frameTs); } timePosMap.put(frameTs, pos); } else { log.debug("No sync samples available"); } //size of the sample int size = (videoSamples.get(sample - 1)).intValue(); // exclude data that is not within the mdat box if ((moovOffset < mdatOffset && pos > mdatOffset) || (moovOffset > mdatOffset && pos < moovOffset)) { //create a frame MP4Frame frame = new MP4Frame(); frame.setKeyFrame(keyframe); frame.setOffset(pos); frame.setSize(size); frame.setTime(ts); frame.setType(TYPE_VIDEO); //set time offset value from composition records if (compositeTimeEntry != null) { // how many samples have this offset int consecutiveSamples = compositeTimeEntry.getConsecutiveSamples(); frame.setTimeOffset(compositeTimeEntry.getSampleOffset()); // increment our count compositeIndex++; if (compositeIndex - consecutiveSamples == 0) { // ensure there are still times available if (!compositionTimes.isEmpty()) { // get the next one compositeTimeEntry = compositionTimes.remove(0); } // reset compositeIndex = 0; } log.debug("Composite sample #{} {}", sample, frame); } // add the frame frames.add(frame); //log.debug("Sample #{} {}", sample, frame); } else { log.warn("Skipping video frame with invalid position"); } //inc and dec stuff pos += size; sampleCount--; sample++; } } } log.debug("Sample position map (video): {}", samplePosMap); } // if video-only, skip this if (audioSamplesToChunks != null) { //add the audio frames / samples / chunks sample = 1; for (int i = 0; i < audioSamplesToChunks.size(); i++) { MP4Atom.Record record = audioSamplesToChunks.get(i); int firstChunk = record.getFirstChunk(); int lastChunk = audioChunkOffsets.size(); if (i < audioSamplesToChunks.size() - 1) { MP4Atom.Record nextRecord = audioSamplesToChunks.get(i + 1); lastChunk = nextRecord.getFirstChunk() - 1; } for (int chunk = firstChunk; chunk <= lastChunk; chunk++) { int sampleCount = record.getSamplesPerChunk(); pos = audioChunkOffsets.elementAt(chunk - 1); while (sampleCount > 0) { //calculate ts double ts = (audioSampleDuration * (sample - 1)) / audioTimeScale; //sample size int size = (audioSamples.get(sample - 1)).intValue(); // skip empty AAC data which is 6 bytes long log.trace("Audio sample - size: {} pos: {}", size, pos); if (size == 6) { try { // get current pos long position = channel.position(); // jump to data position channel.position(pos); // create buffer to store bytes so we can check them ByteBuffer dst = ByteBuffer.allocate(6); // read the data channel.read(dst); // flip it dst.flip(); // reset the position channel.position(position); byte[] tmp = dst.array(); log.trace("Audio bytes: {} equal: {}", HexDump.byteArrayToHexString(tmp), Arrays.equals(EMPTY_AAC, tmp)); if (Arrays.equals(EMPTY_AAC, tmp)) { log.trace("Skipping empty AAC data frame"); // update counts pos += size; sampleCount--; sample++; // read next continue; } } catch (IOException e) { log.warn("Exception during audio analysis", e); } } // exclude data that is not within the mdat box if ((moovOffset < mdatOffset && pos > mdatOffset) || (moovOffset > mdatOffset && pos < moovOffset)) { //create a frame MP4Frame frame = new MP4Frame(); frame.setOffset(pos); frame.setSize(size); frame.setTime(ts); frame.setType(TYPE_AUDIO); frames.add(frame); //log.debug("Sample #{} {}", sample, frame); } else { log.warn("Skipping audio frame with invalid position"); } // update counts pos += size; sampleCount--; sample++; } } } } //sort the frames Collections.sort(frames); log.debug("Frames count: {}", frames.size()); //log.debug("Frames: {}", frames); //release some memory, since we're done with the vectors if (audioSamplesToChunks != null) { audioChunkOffsets.clear(); audioChunkOffsets = null; audioSamplesToChunks.clear(); audioSamplesToChunks = null; } if (videoSamplesToChunks != null) { videoChunkOffsets.clear(); videoChunkOffsets = null; videoSamplesToChunks.clear(); videoSamplesToChunks = null; } if (syncSamples != null) { syncSamples.clear(); syncSamples = null; } } /** * Put the current position to pos. The caller must ensure the pos is a valid one. * * @param pos position to move to in file / channel */ public void position(long pos) { log.debug("Position: {}", pos); log.debug("Current frame: {}", currentFrame); int len = frames.size(); MP4Frame frame = null; for (int f = 0; f < len; f++) { frame = frames.get(f); long offset = frame.getOffset(); //look for pos to match frame offset or grab the first keyframe //beyond the offset if (pos == offset || (offset > pos && frame.isKeyFrame())) { //ensure that it is a keyframe if (!frame.isKeyFrame()) { log.debug("Frame #{} was not a key frame, so trying again..", f); continue; } log.info("Frame #{} found for seek: {}", f, frame); createPreStreamingTags((int) (frame.getTime() * 1000), true); currentFrame = f; break; } prevVideoTS = (int) (frame.getTime() * 1000); } // log.debug("Setting current frame: {}", currentFrame); } /** {@inheritDoc} */ public void close() { log.debug("Close"); if (channel != null) { try { channel.close(); fis.close(); fis = null; } catch (IOException e) { log.error("Channel close {}", e); } finally { if (frames != null) { frames.clear(); frames = null; } } } } public void setVideoCodecId(String videoCodecId) { this.videoCodecId = videoCodecId; } public void setAudioCodecId(String audioCodecId) { this.audioCodecId = audioCodecId; } public ITag readTagHeader() { return null; } @Override public KeyFrameMeta analyzeKeyFrames() { KeyFrameMeta result = new KeyFrameMeta(); result.audioOnly = hasAudio && !hasVideo; result.duration = duration; if (result.audioOnly) { result.positions = new long[frames.size()]; result.timestamps = new int[frames.size()]; result.audioOnly = true; for (int i = 0; i < result.positions.length; i++) { frames.get(i).setKeyFrame(true); result.positions[i] = frames.get(i).getOffset(); result.timestamps[i] = (int) Math.round(frames.get(i).getTime() * 1000.0); } } else { result.positions = new long[seekPoints.size()]; result.timestamps = new int[seekPoints.size()]; for (int idx = 0; idx < seekPoints.size(); idx++) { final Integer ts = seekPoints.get(idx); result.positions[idx] = timePosMap.get(ts); result.timestamps[idx] = ts; } } return result; } } red5-1.0~svn4374.orig/src/org/red5/io/mp4/impl/MP4.java0000644000175000017500000001003111706617130022040 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp4.impl; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.ITagReader; import org.red5.io.ITagWriter; import org.red5.io.flv.meta.IMetaData; import org.red5.io.flv.meta.IMetaService; import org.red5.io.flv.meta.MetaService; import org.red5.io.mp4.IMP4; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A MP4Impl implements the MP4 api * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire, (mondain@gmail.com) */ public class MP4 implements IMP4 { protected static Logger log = LoggerFactory.getLogger(MP4.class); private File file; private IMetaService metaService; private IMetaData metaData; /** * Default constructor, used by Spring so that parameters may be injected. */ public MP4() { } /** * Create MP4 from given file source. * * @param file File source */ public MP4(File file) { this.file = file; /* try { MP4Reader reader = new MP4Reader(this.file); ITag tag = reader.createFileMeta(); if (metaService == null) { metaService = new MetaService(this.file); } metaData = metaService.readMetaData(tag.getBody()); reader.close(); } catch (Exception e) { log.error("An error occurred looking for metadata:", e); } */ } /** * {@inheritDoc} */ public boolean hasMetaData() { return metaData != null; } /** * {@inheritDoc} */ public IMetaData getMetaData() throws FileNotFoundException { metaService.setFile(file); return null; } /** * {@inheritDoc} */ public boolean hasKeyFrameData() { return false; } /** * {@inheritDoc} */ public void setKeyFrameData(Map keyframedata) { } /** * {@inheritDoc} */ public Map getKeyFrameData() { return null; } /** * {@inheritDoc} */ public void refreshHeaders() throws IOException { } /** * {@inheritDoc} */ public void flushHeaders() throws IOException { } /** * {@inheritDoc} */ public ITagReader getReader() throws IOException { MP4Reader reader = null; IoBuffer fileData = null; String fileName = file.getName(); if (file.exists()) { log.debug("File name: {} size: {}", fileName, file.length()); reader = new MP4Reader(file); // get a ref to the mapped byte buffer fileData = reader.getFileData(); log.trace("File data size: {}", fileData); } else { log.info("Creating new file: {}", file); file.createNewFile(); } return reader; } /** * {@inheritDoc} */ public ITagReader readerFromNearestKeyFrame(int seekPoint) { return null; } /** * {@inheritDoc} */ public ITagWriter getWriter() throws IOException { return null; } /** * {@inheritDoc} */ public ITagWriter writerFromNearestKeyFrame(int seekPoint) { return null; } /** {@inheritDoc} */ public void setMetaData(IMetaData meta) throws IOException { if (metaService == null) { metaService = new MetaService(file); } //if the file is not checked the write may produce an NPE if (metaService.getFile() == null) { metaService.setFile(file); } metaService.write(meta); metaData = meta; } /** {@inheritDoc} */ public void setMetaService(IMetaService service) { metaService = service; } public ITagWriter getAppendWriter() throws IOException { return null; } } red5-1.0~svn4374.orig/src/org/red5/io/mp4/MP4Frame.java0000644000175000017500000000752111706617130022064 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp4; /** * Represents an MP4 frame / chunk sample * * @author Paul Gregoire (mondain@gmail.com) */ public class MP4Frame implements Comparable { private byte type; private long offset; private int size; private double time; //this value originates from the ctts atom private int timeOffset; private boolean keyFrame; /** * Returns the data type, being audio or video. * * @return the data type */ public byte getType() { return type; } public void setType(byte type) { this.type = type; } /** * Returns the offset of the data chunk in the media source. * * @return the offset in bytes */ public long getOffset() { return offset; } public void setOffset(long offset) { this.offset = offset; } /** * Returns the size of the data chunk. * * @return the size in bytes */ public int getSize() { return size; } public void setSize(int size) { this.size = size; } /** * Returns the timestamp. * * @return the timestamp */ public double getTime() { return time; } public void setTime(double time) { this.time = time; } /** * @return the timeOffset */ public int getTimeOffset() { return timeOffset; } /** * @param timeOffset the timeOffset to set */ public void setTimeOffset(int timeOffset) { this.timeOffset = timeOffset; } /** * Returns whether or not this chunk represents a key frame. * * @return true if a key frame */ public boolean isKeyFrame() { return keyFrame; } public void setKeyFrame(boolean keyFrame) { this.keyFrame = keyFrame; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (offset ^ (offset >>> 32)); result = prime * result + type; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MP4Frame other = (MP4Frame) obj; if (offset != other.offset) return false; if (type != other.type) return false; return true; } @Override public String toString() { StringBuilder sb = new StringBuilder("MP4Frame type="); sb.append(type); sb.append(", time="); sb.append(time); sb.append(", timeOffset="); sb.append(timeOffset); sb.append(", size="); sb.append(size); sb.append(", offset="); sb.append(offset); sb.append(", keyframe="); sb.append(keyFrame); return sb.toString(); } /** * The frames are expected to be sorted by their timestamp */ public int compareTo(MP4Frame that) { int ret = 0; if (this.time > that.getTime()) { ret = 1; } else if (this.time < that.getTime()) { ret = -1; } else if (Double.doubleToLongBits(time) == Double.doubleToLongBits(that.getTime()) && this.offset > that.getOffset()) { ret = 1; } else if (Double.doubleToLongBits(time) == Double.doubleToLongBits(that.getTime()) && this.offset < that.getOffset()) { ret = -1; } return ret; } } red5-1.0~svn4374.orig/src/org/red5/io/mp4/IMP4Service.java0000644000175000017500000000256611706617130022547 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp4; import org.red5.io.IStreamableFileService; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; /** * A MP4Service sets up the service and hands out MP4 objects to * its callers * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public interface IMP4Service extends IStreamableFileService { /** * Sets the serializer * * @param serializer Serializer object */ public void setSerializer(Serializer serializer); /** * Sets the deserializer * * @param deserializer Deserializer object */ public void setDeserializer(Deserializer deserializer); } red5-1.0~svn4374.orig/src/org/red5/io/mp4/MP4Descriptor.java0000644000175000017500000001572111706617130023151 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp4; /** This software module was originally developed by Apple Computer, Inc. in the course of development of MPEG-4. This software module is an implementation of a part of one or more MPEG-4 tools as specified by MPEG-4. ISO/IEC gives users of MPEG-4 free license to this software module or modifications thereof for use in hardware or software products claiming conformance to MPEG-4. Those intending to use this software module in hardware or software products are advised that its use may infringe existing patents. The original developer of this software module and his/her company, the subsequent editors and their companies, and ISO/IEC have no liability for use of this software module or modifications thereof in an implementation. Copyright is not released for non MPEG-4 conforming products. Apple Computer, Inc. retains full right to use the code for its own purpose, assign or donate the code to a third party and to inhibit third parties from using the code for non MPEG-4 conforming products. This copyright notice must be included in all copies or derivative works. Copyright (c) 1999, 2000. */ import java.io.IOException; import java.util.Vector; /** * MP4Descriptor * */ public class MP4Descriptor { public final static int MP4ES_DescriptorTag = 3; public final static int MP4DecoderConfigDescriptorTag = 4; public final static int MP4DecSpecificInfoDescriptorTag = 5; protected int type; protected int size; protected int readed; protected Vector children = new Vector(); public MP4Descriptor(int type, int size) { super(); this.readed = 0; this.type = type; this.size = size; } public static MP4Descriptor createDescriptor(MP4DataStream bitstream) throws IOException { int tag = (int) bitstream.readBytes(1); int readed = 1; int size = 0; int b = 0; do { //System.out.println("Tag: " + tag + " size: " + size); b = (int) bitstream.readBytes(1); size <<= 7; size |= b & 0x7f; readed++; } while ((b & 0x80) == 0x80); MP4Descriptor descriptor = new MP4Descriptor(tag, size); switch (tag) { case MP4ES_DescriptorTag: descriptor.createES_Descriptor(bitstream); break; case MP4DecoderConfigDescriptorTag: descriptor.createDecoderConfigDescriptor(bitstream); break; case MP4DecSpecificInfoDescriptorTag: descriptor.createDecSpecificInfoDescriptor(bitstream); break; default: break; } bitstream.skipBytes(descriptor.size - descriptor.readed); descriptor.readed = readed + descriptor.size; return descriptor; } /** * Loads the MP4ES_Descriptor from the input bitstream. * * @param bitstream * the input bitstream */ @SuppressWarnings("unused") public void createES_Descriptor(MP4DataStream bitstream) throws IOException { int ES_ID = (int) bitstream.readBytes(2); int flags = (int) bitstream.readBytes(1); boolean streamDependenceFlag = (flags & (1 << 7)) != 0; boolean urlFlag = (flags & (1 << 6)) != 0; boolean ocrFlag = (flags & (1 << 5)) != 0; readed += 3; if (streamDependenceFlag) { bitstream.skipBytes(2); readed += 2; } if (urlFlag) { int str_size = (int) bitstream.readBytes(1); bitstream.readString(str_size); readed += str_size + 1; } if (ocrFlag) { bitstream.skipBytes(2); readed += 2; } while (readed < size) { MP4Descriptor descriptor = createDescriptor(bitstream); children.addElement(descriptor); readed += descriptor.getReaded(); } } /** * Loads the MP4DecoderConfigDescriptor from the input bitstream. * * @param bitstream * the input bitstream */ @SuppressWarnings("unused") public void createDecoderConfigDescriptor(MP4DataStream bitstream) throws IOException { int objectTypeIndication = (int) bitstream.readBytes(1); int value = (int) bitstream.readBytes(1); boolean upstream = (value & (1 << 1)) > 0; byte streamType = (byte) (value >> 2); value = (int) bitstream.readBytes(2); int bufferSizeDB = value << 8; value = (int) bitstream.readBytes(1); bufferSizeDB |= value & 0xff; int maxBitRate = (int) bitstream.readBytes(4); int minBitRate = (int) bitstream.readBytes(4); readed += 13; if (readed < size) { MP4Descriptor descriptor = createDescriptor(bitstream); children.addElement(descriptor); readed += descriptor.getReaded(); } } protected int decSpecificDataSize; protected long decSpecificDataOffset; private byte[] dsid; public byte[] getDSID() { return dsid; } /** * Loads the MP4DecSpecificInfoDescriptor from the input bitstream. * * @param bitstream * the input bitstream */ public void createDecSpecificInfoDescriptor(MP4DataStream bitstream) throws IOException { decSpecificDataOffset = bitstream.getOffset(); dsid = new byte[size]; for (int b = 0; b < size; b++) { dsid[b] = (byte) bitstream.readBytes(1); readed++; } decSpecificDataSize = size - readed; } public long getDecSpecificDataOffset() { return decSpecificDataOffset; } public int getDecSpecificDataSize() { return decSpecificDataSize; } /** * Lookups for a child descriptor with the specified type, * skips the number children with the same type before * finding a result. * * @param type * the type of the descriptor. * @param number * the number of child descriptors to skip * @return the descriptor which was being searched. */ public MP4Descriptor lookup(int type, int number) { int position = 0; for (int i = 0; i < children.size(); i++) { MP4Descriptor descriptor = children.elementAt(i); if (descriptor.getType() == type) { if (position >= number) { return descriptor; } position++; } } return null; } /** * Returns the type of this descriptor. */ public int getType() { return type; } /** * Gets the number of data bytes which were read from the stream; * * @return the number of read data bytes. */ public int getReaded() { return readed; } public Vector getChildren() { return children; } } red5-1.0~svn4374.orig/src/org/red5/io/ITag.java0000644000175000017500000000457711706617130020645 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; import org.apache.mina.core.buffer.IoBuffer; /** * A Tag represents the contents or payload of a streamable file. * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public interface ITag extends IoConstants { /** * Return the body ByteBuffer * * @return ByteBuffer Body as byte buffer */ public IoBuffer getBody(); /** * Return the size of the body * * @return int Body size */ public int getBodySize(); /** * Get the data type * * @return byte Data type as byte */ public byte getDataType(); /** * Return the timestamp * * @return int Timestamp */ public int getTimestamp(); /** * Returns the data as a ByteBuffer * * @return ByteBuffer Data as byte buffer */ public IoBuffer getData(); /** * Returns previous tag size * * @return int Previous tag size */ public int getPreviousTagSize(); /** * Set the body ByteBuffer. * @param body Body as ByteBuffer */ public void setBody(IoBuffer body); /** * Set the size of the body. * @param size Body size */ public void setBodySize(int size); /** * Set the data type. * @param datatype Data type */ public void setDataType(byte datatype); /** * Set the timestamp. * @param timestamp Timestamp */ public void setTimestamp(int timestamp); /** * Set the size of the previous tag. * @param size Previous tag size */ public void setPreviousTagSize(int size); } red5-1.0~svn4374.orig/src/org/red5/io/CachingFileKeyFrameMetaCache.java0000644000175000017500000000627311706617130025327 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.red5.io.flv.IKeyFrameDataAnalyzer.KeyFrameMeta; public class CachingFileKeyFrameMetaCache extends FileKeyFrameMetaCache { private Map inMemoryMetaCache = new HashMap(); private ReadWriteLock rwLock = new ReentrantReadWriteLock(); private int maxCacheEntry = 500; private Random random = new Random(); public void setMaxCacheEntry(int maxCacheEntry) { this.maxCacheEntry = maxCacheEntry; } @Override public KeyFrameMeta loadKeyFrameMeta(File file) { rwLock.readLock().lock(); try { String canonicalPath = file.getCanonicalPath(); if (!inMemoryMetaCache.containsKey(canonicalPath)) { rwLock.readLock().unlock(); rwLock.writeLock().lock(); try { if (inMemoryMetaCache.size() >= maxCacheEntry) { freeCachingMetadata(); } KeyFrameMeta keyFrameMeta = super.loadKeyFrameMeta(file); if (keyFrameMeta != null) { inMemoryMetaCache.put(canonicalPath, keyFrameMeta); } else { return null; } } finally { rwLock.writeLock().unlock(); rwLock.readLock().lock(); } } return inMemoryMetaCache.get(canonicalPath); } catch (IOException e) { return null; } finally { rwLock.readLock().unlock(); } } @Override public void saveKeyFrameMeta(File file, KeyFrameMeta meta) { rwLock.writeLock().lock(); try { String canonicalPath = file.getCanonicalPath(); if (inMemoryMetaCache.containsKey(canonicalPath)) { inMemoryMetaCache.remove(canonicalPath); } } catch (IOException e) { // ignore the exception here, let super class to handle it. } finally { rwLock.writeLock().unlock(); } super.saveKeyFrameMeta(file, meta); } private void freeCachingMetadata() { int cacheSize = inMemoryMetaCache.size(); int randomIndex = random.nextInt(cacheSize); Map.Entry entryToRemove = null; for (Map.Entry cacheEntry : inMemoryMetaCache.entrySet()) { if (randomIndex == 0) { entryToRemove = cacheEntry; break; } randomIndex--; } if (entryToRemove != null) { inMemoryMetaCache.remove(entryToRemove.getKey()); } } }red5-1.0~svn4374.orig/src/org/red5/io/amf/0000755000175000017500000000000011760512575017713 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/amf/AMF.java0000644000175000017500000000641111706617130021154 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.amf; import java.nio.charset.Charset; /** * These are the core AMF data types supported by Red5. * * For detailed specification please see the link below. * * @see AMF specification (external) * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class AMF { /** * UTF-8 is used */ public static final Charset CHARSET = Charset.forName("UTF-8"); /** * Max string lenght constant */ public static final int LONG_STRING_LENGTH = 65535; /** * Number marker constant */ public static final byte TYPE_NUMBER = 0x00; /** * Boolean value marker constant */ public static final byte TYPE_BOOLEAN = 0x01; /** * String marker constant */ public static final byte TYPE_STRING = 0x02; /** * Object marker constant */ public static final byte TYPE_OBJECT = 0x03; /** * MovieClip marker constant */ public static final byte TYPE_MOVIECLIP = 0x04; /** * Null marker constant */ public static final byte TYPE_NULL = 0x05; /** * Undefined marker constant */ public static final byte TYPE_UNDEFINED = 0x06; /** * Object reference marker constant */ public static final byte TYPE_REFERENCE = 0x07; /** * Mixed array marker constant */ public static final byte TYPE_MIXED_ARRAY = 0x08; /** * End of object marker constant */ public static final byte TYPE_END_OF_OBJECT = 0x09; /** * Array marker constant */ public static final byte TYPE_ARRAY = 0x0A; /** * Date marker constant */ public static final byte TYPE_DATE = 0x0B; /** * Long string marker constant */ public static final byte TYPE_LONG_STRING = 0x0C; /** * Unsupported type marker constant */ public static final byte TYPE_UNSUPPORTED = 0x0D; /** * Recordset marker constant */ public static final byte TYPE_RECORDSET = 0x0E; /** * XML marker constant */ public static final byte TYPE_XML = 0x0F; /** * Class marker constant */ public static final byte TYPE_CLASS_OBJECT = 0x10; /** * Object marker constant (for AMF3) */ public static final byte TYPE_AMF3_OBJECT = 0x11; /** * true marker constant */ public static final byte VALUE_TRUE = 0x01; /** * false marker constant */ public static final byte VALUE_FALSE = 0x00; } red5-1.0~svn4374.orig/src/org/red5/io/amf/Input.java0000644000175000017500000004630211745776105021666 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.amf; import java.beans.PropertyDescriptor; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Vector; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.commons.beanutils.PropertyUtilsBean; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.amf3.ByteArray; import org.red5.io.object.BaseInput; import org.red5.io.object.DataTypes; import org.red5.io.object.Deserializer; import org.red5.io.object.RecordSet; import org.red5.io.object.RecordSetPage; import org.red5.io.utils.ArrayUtils; import org.red5.io.utils.ObjectMap; import org.red5.io.utils.XMLUtils; import org.red5.server.util.ConversionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; /** * Input for Red5 data types * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ @SuppressWarnings("serial") public class Input extends BaseInput implements org.red5.io.object.Input { protected static Logger log = LoggerFactory.getLogger(Input.class); protected static Map classAliases = new HashMap(3) { { put("DSA", "org.red5.compatibility.flex.messaging.messages.AsyncMessageExt"); put("DSC", "org.red5.compatibility.flex.messaging.messages.CommandMessageExt"); put("DSK", "org.red5.compatibility.flex.messaging.messages.AcknowledgeMessageExt"); } }; protected IoBuffer buf; protected byte currentDataType; /** * Creates Input object from byte buffer * * @param buf Byte buffer */ public Input(IoBuffer buf) { super(); this.buf = buf; } /** * Reads the data type. * * @return byte Data type */ public byte readDataType() { if (buf != null) { // XXX Paul: prevent an NPE here by returning the current data type // when there is a null buffer currentDataType = buf.get(); } else { log.error("Why is buf null?"); } return readDataType(currentDataType); } /** * Reads the data type. * * @param dataType Data type as byte * @return One of AMF class constants with type * @see org.red5.io.amf.AMF */ protected byte readDataType(byte dataType) { byte coreType; switch (currentDataType) { case AMF.TYPE_NULL: case AMF.TYPE_UNDEFINED: coreType = DataTypes.CORE_NULL; break; case AMF.TYPE_NUMBER: coreType = DataTypes.CORE_NUMBER; break; case AMF.TYPE_BOOLEAN: coreType = DataTypes.CORE_BOOLEAN; break; case AMF.TYPE_STRING: case AMF.TYPE_LONG_STRING: coreType = DataTypes.CORE_STRING; break; case AMF.TYPE_CLASS_OBJECT: case AMF.TYPE_OBJECT: coreType = DataTypes.CORE_OBJECT; break; case AMF.TYPE_MIXED_ARRAY: coreType = DataTypes.CORE_MAP; break; case AMF.TYPE_ARRAY: coreType = DataTypes.CORE_ARRAY; break; case AMF.TYPE_DATE: coreType = DataTypes.CORE_DATE; break; case AMF.TYPE_XML: coreType = DataTypes.CORE_XML; break; case AMF.TYPE_REFERENCE: coreType = DataTypes.OPT_REFERENCE; break; case AMF.TYPE_UNSUPPORTED: case AMF.TYPE_MOVIECLIP: case AMF.TYPE_RECORDSET: // These types are not handled by core datatypes // So add the amf mask to them, this way the deserializer // will call back to readCustom, we can then handle or return null coreType = (byte) (currentDataType + DataTypes.CUSTOM_AMF_MASK); break; case AMF.TYPE_END_OF_OBJECT: default: // End of object, and anything else lets just skip coreType = DataTypes.CORE_SKIP; break; } return coreType; } // Basic /** * Reads a null. * * @return Object */ public Object readNull(Type target) { return null; } /** * Reads a boolean. * * @return boolean */ public Boolean readBoolean(Type target) { // TODO: check values return (buf.get() == AMF.VALUE_TRUE) ? Boolean.TRUE : Boolean.FALSE; } /** * Reads a Number. In ActionScript 1 and 2 Number type represents all numbers, * both floats and integers. * * @return Number */ public Number readNumber(Type target) { double num = buf.getDouble(); if (num == Math.round(num)) { if (num < Integer.MAX_VALUE) { return (int) num; } else { return Math.round(num); } } else { return num; } } /** * Reads string from buffer * @return String */ public String getString() { return getString(buf); } /** * Reads a string * * @return String */ public String readString(Type target) { int len = 0; switch (currentDataType) { case AMF.TYPE_LONG_STRING: len = buf.getInt(); break; case AMF.TYPE_STRING: len = buf.getShort() & 0xffff; //buf.getUnsignedShort(); break; default: log.debug("Unknown AMF type: {}", currentDataType); } int limit = buf.limit(); log.debug("Limit: {}", limit); String string = bufferToString(buf.buf(), len); buf.limit(limit); // Reset the limit return string; } /** * Returns a string based on the buffer * * @param buf Byte buffer with data * @return String Decoded string */ public static String getString(IoBuffer buf) { int len = buf.getShort() & 0xffff; //buf.getUnsignedShort(); XXX is appears to be broken in mina at 2.0.4 log.debug("Length: {}", len); int limit = buf.limit(); log.debug("Limit: {}", limit); String string = bufferToString(buf.buf(), len); buf.limit(limit); // Reset the limit return string; } /** * Returns a string based on the buffer * * @param buf Byte buffer with data * @return String Decoded string */ public static String getString(java.nio.ByteBuffer buf) { int len = buf.getShort() & 0xffff; log.debug("Length: {}", len); int limit = buf.limit(); log.debug("Limit: {}", limit); String string = bufferToString(buf, len); buf.limit(limit); // Reset the limit return string; } /** * Converts the bytes into a string. * * @param strBuf * @return contents of the ByteBuffer as a String */ private final static String bufferToString(final java.nio.ByteBuffer strBuf, int len) { //Trac #601 - part of the problem seems to be a null byte buffer String string = null; if (strBuf != null) { int pos = strBuf.position(); log.debug("String buf - position: {} limit: {}", pos, (pos + len)); strBuf.limit(pos + len); string = AMF.CHARSET.decode(strBuf).toString(); log.debug("String: {}", string); } else { log.warn("ByteBuffer was null attempting to read String"); } return string; } /** * Returns a date * * @return Date Decoded string object */ public Date readDate(Type target) { /* * Date: 0x0B T7 T6 .. T0 Z1 Z2 T7 to T0 form a 64 bit Big Endian number * that specifies the number of nanoseconds that have passed since * 1/1/1970 0:00 to the specified time. This format is UTC 1970. Z1 an * Z0 for a 16 bit Big Endian number indicating the indicated time's * timezone in minutes. */ long ms = (long) buf.getDouble(); // The timezone can be ignored as the date always is encoded in UTC @SuppressWarnings("unused") short timeZoneMins = buf.getShort(); Date date = new Date(ms); storeReference(date); return date; } // Array public Object readArray(Deserializer deserializer, Type target) { log.debug("readArray - deserializer: {} target: {}", deserializer, target); Object result = null; int count = buf.getInt(); log.debug("Count: {}", count); List resultCollection = new ArrayList(count); storeReference(result); for (int i = 0; i < count; i++) { resultCollection.add(deserializer.deserialize(this, Object.class)); } // To maintain conformance to the Input API, we should convert the output // into an Array if the Type asks us to. Class collection = Collection.class; if (target instanceof Class) { collection = (Class) target; } if (collection.isArray()) { result = ArrayUtils.toArray(collection.getComponentType(), resultCollection); } else { result = resultCollection; } return result; } // Map /** * Read key - value pairs. This is required for the RecordSet * deserializer. */ public Map readKeyValues(Deserializer deserializer) { Map result = new HashMap(); readKeyValues(result, deserializer); return result; } /** * Read key - value pairs into Map object * @param result Map to put resulting pair to * @param deserializer Deserializer used */ protected void readKeyValues(Map result, Deserializer deserializer) { while (hasMoreProperties()) { String name = readPropertyName(); log.debug("property: {}", name); Object property = deserializer.deserialize(this, Object.class); log.debug("val: {}", property); result.put(name, property); if (hasMoreProperties()) { skipPropertySeparator(); } } skipEndObject(); } public Object readMap(Deserializer deserializer, Type target) { // The maximum number used in this mixed array. int maxNumber = buf.getInt(); log.debug("Read start mixed array: {}", maxNumber); Object result; final Map mixedResult = new LinkedHashMap(maxNumber); // we must store the reference before we deserialize any items in it to ensure // that reference IDs are correct int reference = storeReference(mixedResult); Boolean normalArray = true; while (hasMoreProperties()) { String key = getString(buf); log.debug("key: {}", key); try { Integer.parseInt(key); } catch (NumberFormatException e) { log.debug("key {} is causing non normal array", key); normalArray = false; } Object item = deserializer.deserialize(this, Object.class); log.debug("item: {}", item); mixedResult.put(key, item); } if (mixedResult.size() <= maxNumber + 1 && normalArray) { // MixedArray actually is a regular array log.debug("mixed array is a regular array"); final List listResult = new ArrayList(maxNumber); for (int i = 0; i < maxNumber; i++) { listResult.add(i, mixedResult.get(String.valueOf(i))); } result = listResult; } else { // Convert initial indexes mixedResult.remove("length"); for (int i = 0; i < maxNumber; i++) { final Object value = mixedResult.remove(String.valueOf(i)); mixedResult.put(i, value); } result = mixedResult; } // Replace the original reference with the final result storeReference(reference, result); skipEndObject(); return result; } // Object /** * Creates a new instance of the className parameter and * returns as an Object * * @param className Class name as String * @return Object New object instance (for given class) */ @SuppressWarnings("all") protected Object newInstance(String className) { log.debug("Loading class: {}", className); Object instance = null; Class clazz = null; //fix for Trac #604 if ("".equals(className) || className == null) return instance; try { //check for special DS class aliases if (className.length() == 3) { className = classAliases.get(className); } if (className.startsWith("flex.")) { // Use Red5 compatibility class instead className = "org.red5.compatibility." + className; log.debug("Modified classname: {}", className); } clazz = Thread.currentThread().getContextClassLoader().loadClass(className); instance = clazz.newInstance(); } catch (InstantiationException iex) { try { //check for default ctor clazz.getConstructor(null); log.error("Error loading class: {}", className); } catch (NoSuchMethodException nse) { log.error("Error loading class: {}; this can be resolved by adding a default constructor to your class", className); } log.debug("Exception was: {}", iex); } catch (Exception ex) { log.error("Error loading class: {}", className); log.debug("Exception was: {}", ex); } return instance; } /** * Reads the input as a bean and returns an object * * @param deserializer Deserializer used * @param bean Input as bean * @return Decoded object */ @SuppressWarnings({ "unchecked", "rawtypes" }) protected Object readBean(Deserializer deserializer, Object bean) { log.debug("read bean"); storeReference(bean); Class theClass = bean.getClass(); while (hasMoreProperties()) { String name = readPropertyName(); Type type = getPropertyType(bean, name); log.debug("property: {}", name); Object property = deserializer.deserialize(this, type); log.debug("val: {}", property); //log.debug("val: "+property.getClass().getName()); if (property != null) { try { if (type instanceof Class) { Class t = (Class) type; if (!t.isAssignableFrom(property.getClass())) { property = ConversionUtils.convert(property, t); } } final Field field = theClass.getField(name); field.set(bean, property); } catch (Exception ex2) { try { BeanUtils.setProperty(bean, name, property); } catch (Exception ex) { log.error("Error mapping property: {} ({})", name, property); } } } else { log.debug("Skipping null property: {}", name); } if (hasMoreProperties()) { skipPropertySeparator(); } } skipEndObject(); return bean; } /** * Reads the input as a map and returns a Map * * @param deserializer Deserializer to use * @return Read map */ protected Map readSimpleObject(Deserializer deserializer) { log.debug("read map"); Map result = new ObjectMap(); readKeyValues(result, deserializer); storeReference(result); return result; } /** * Reads start object * * @param deserializer Deserializer to use * @return Read object */ public Object readObject(Deserializer deserializer, Type target) { String className; if (currentDataType == AMF.TYPE_CLASS_OBJECT) { className = getString(buf); } else { className = null; } log.debug("readObject: {}", className); Object result = null; if (className != null) { log.debug("read class object"); Object instance; if (className.equals("RecordSet")) { result = new RecordSet(this); storeReference(result); } else if (className.equals("RecordSetPage")) { result = new RecordSetPage(this); storeReference(result); } else { instance = newInstance(className); if (instance != null) { result = readBean(deserializer, instance); } else { log.debug("Forced to use simple object for class {}", className); result = readSimpleObject(deserializer); } } } else { result = readSimpleObject(deserializer); } return result; } /** * Returns a boolean stating whether there are more properties * * @return boolean true if there are more properties to read, false otherwise */ public boolean hasMoreProperties() { byte pad = 0x00; byte pad0 = buf.get(); byte pad1 = buf.get(); byte type = buf.get(); boolean isEndOfObject = (pad0 == pad && pad1 == pad && type == AMF.TYPE_END_OF_OBJECT); log.debug("End of object: ? {}", isEndOfObject); buf.position(buf.position() - 3); return !isEndOfObject; } /** * Reads property name * * @return String Object property name */ public String readPropertyName() { return getString(buf); } /** * Skips property seperator */ public void skipPropertySeparator() { // SKIP } /** * Skips end object */ public void skipEndObject() { // skip two marker bytes // then end of object byte buf.skip(3); } // Others /** * Reads XML * * @return String XML as string */ public Document readXML(Type target) { final String xmlString = readString(target); Document doc = null; try { doc = XMLUtils.stringToDoc(xmlString); } catch (IOException ioex) { log.error("IOException converting xml to dom", ioex); } storeReference(doc); return doc; } /** * Reads Custom * * @return Object Custom type object */ public Object readCustom(Type target) { // Return null for now return null; } /** * Read ByteArray object. This is not supported by the AMF0 deserializer. * * @return ByteArray object */ public ByteArray readByteArray(Type target) { throw new RuntimeException("ByteArray objects not supported with AMF0"); } /** * Read Vector object. This is not supported by the AMF0 deserializer. * * @return Vector object */ public Vector readVectorInt() { throw new RuntimeException("Vector objects not supported with AMF0"); } /** * Read Vector object. This is not supported by the AMF0 deserializer. * * @return Vector object */ public Vector readVectorUInt() { throw new RuntimeException("Vector objects not supported with AMF0"); } /** * Read Vector object. This is not supported by the AMF0 deserializer. * * @return Vector object */ public Vector readVectorNumber() { throw new RuntimeException("Vector objects not supported with AMF0"); } /** * Read Vector object. This is not supported by the AMF0 deserializer. * * @return Vector object */ public Vector readVectorObject() { throw new RuntimeException("Vector objects not supported with AMF0"); } /** * Reads Reference * * @return Object Read reference to object */ public Object readReference(Type target) { //return getReference(buf.getUnsignedShort()); return getReference(buf.getShort() & 0xffff); } /** * Resets map * */ public void reset() { this.clearReferences(); } protected Type getPropertyType(Object instance, String propertyName) { try { if (instance != null) { Field field = instance.getClass().getField(propertyName); return field.getGenericType(); } else { // instance is null for anonymous class, use default type } } catch (NoSuchFieldException e1) { try { BeanUtilsBean beanUtilsBean = BeanUtilsBean.getInstance(); PropertyUtilsBean propertyUtils = beanUtilsBean.getPropertyUtils(); PropertyDescriptor propertyDescriptor = propertyUtils.getPropertyDescriptor(instance, propertyName); return propertyDescriptor.getReadMethod().getGenericReturnType(); } catch (Exception e2) { // nothing } } catch (Exception e) { // ignore other exceptions } // return Object class type by default return Object.class; } } red5-1.0~svn4374.orig/src/org/red5/io/amf/Output.java0000644000175000017500000004176411754631106022065 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.amf; import java.io.File; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.TimeZone; import java.util.Vector; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheException; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.apache.commons.beanutils.BeanMap; import org.apache.mina.core.buffer.IoBuffer; import org.red5.annotations.Anonymous; import org.red5.io.amf3.ByteArray; import org.red5.io.object.BaseOutput; import org.red5.io.object.ICustomSerializable; import org.red5.io.object.RecordSet; import org.red5.io.object.Serializer; import org.red5.io.utils.XMLUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; /** * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Paul Gregoire (mondain@gmail.com) * @author Harald Radi (harald.radi@nme.at) */ public class Output extends BaseOutput implements org.red5.io.object.Output { protected static Logger log = LoggerFactory.getLogger(Output.class); private static Cache stringCache; private static Cache serializeCache; private static Cache fieldCache; private static Cache getterCache; private static CacheManager cacheManager; private static CacheManager getCacheManager() { if (cacheManager == null) { if (System.getProperty("red5.root") != null) { // we're running Red5 as a server. try { cacheManager = new CacheManager(System.getProperty("red5.root") + File.separator + "conf" + File.separator + "ehcache.xml"); } catch (CacheException e) { cacheManager = constructDefault(); } } else { // not a server, maybe running tests? cacheManager = constructDefault(); } } return cacheManager; } private static CacheManager constructDefault() { CacheManager manager = CacheManager.getInstance(); manager.addCacheIfAbsent("org.red5.io.amf.Output.stringCache"); manager.addCacheIfAbsent("org.red5.io.amf.Output.getterCache"); manager.addCacheIfAbsent("org.red5.io.amf.Output.fieldCache"); manager.addCacheIfAbsent("org.red5.io.amf.Output.serializeCache"); return manager; } /** * Output buffer */ protected IoBuffer buf; /** * Creates output with given byte buffer * @param buf Bute buffer */ public Output(IoBuffer buf) { super(); this.buf = buf; } /** {@inheritDoc} */ public boolean isCustom(Object custom) { return false; } protected boolean checkWriteReference(Object obj) { if (hasReference(obj)) { writeReference(obj); return true; } else return false; } /** {@inheritDoc} */ public void writeArray(Collection array, Serializer serializer) { if (checkWriteReference(array)) { return; } storeReference(array); buf.put(AMF.TYPE_ARRAY); buf.putInt(array.size()); for (Object item : array) { serializer.serialize(this, item); } } /** {@inheritDoc} */ public void writeArray(Object[] array, Serializer serializer) { log.debug("writeArray - array: {} serializer: {}", array, serializer); if (array != null) { if (checkWriteReference(array)) { return; } storeReference(array); buf.put(AMF.TYPE_ARRAY); buf.putInt(array.length); for (Object item : array) { serializer.serialize(this, item); } } else { writeNull(); } } /** {@inheritDoc} */ public void writeArray(Object array, Serializer serializer) { if (array != null) { if (checkWriteReference(array)) { return; } storeReference(array); buf.put(AMF.TYPE_ARRAY); buf.putInt(Array.getLength(array)); for (int i = 0; i < Array.getLength(array); i++) { serializer.serialize(this, Array.get(array, i)); } } else { writeNull(); } } /** {@inheritDoc} */ public void writeMap(Map map, Serializer serializer) { if (checkWriteReference(map)) { return; } storeReference(map); buf.put(AMF.TYPE_MIXED_ARRAY); int maxInt = -1; for (int i = 0; i < map.size(); i++) { try { if (!map.containsKey(i)) break; } catch (ClassCastException err) { // Map has non-number keys. break; } maxInt = i; } buf.putInt(maxInt + 1); // TODO: Need to support an incoming key named length for (Map.Entry entry : map.entrySet()) { final String key = entry.getKey().toString(); if ("length".equals(key)) { continue; } putString(key); serializer.serialize(this, entry.getValue()); } if (maxInt >= 0) { putString("length"); serializer.serialize(this, maxInt + 1); } buf.put((byte) 0x00); buf.put((byte) 0x00); buf.put(AMF.TYPE_END_OF_OBJECT); } /** {@inheritDoc} */ public void writeMap(Collection array, Serializer serializer) { if (checkWriteReference(array)) { return; } storeReference(array); buf.put(AMF.TYPE_MIXED_ARRAY); buf.putInt(array.size() + 1); int idx = 0; for (Object item : array) { if (item != null) { putString(String.valueOf(idx++)); serializer.serialize(this, item); } else { idx++; } } putString("length"); serializer.serialize(this, array.size() + 1); buf.put((byte) 0x00); buf.put((byte) 0x00); buf.put(AMF.TYPE_END_OF_OBJECT); } /** {@inheritDoc} */ public void writeRecordSet(RecordSet recordset, Serializer serializer) { if (checkWriteReference(recordset)) { return; } storeReference(recordset); // Write out start of object marker buf.put(AMF.TYPE_CLASS_OBJECT); putString("RecordSet"); // Serialize Map info = recordset.serialize(); // Write out serverInfo key putString("serverInfo"); // Serialize serializer.serialize(this, info); // Write out end of object marker buf.put((byte) 0x00); buf.put((byte) 0x00); buf.put(AMF.TYPE_END_OF_OBJECT); } /** {@inheritDoc} */ public boolean supportsDataType(byte type) { return false; } /** {@inheritDoc} */ public void writeBoolean(Boolean bol) { buf.put(AMF.TYPE_BOOLEAN); buf.put(bol ? AMF.VALUE_TRUE : AMF.VALUE_FALSE); } /** {@inheritDoc} */ public void writeCustom(Object custom) { } /** {@inheritDoc} */ public void writeDate(Date date) { buf.put(AMF.TYPE_DATE); buf.putDouble(date.getTime()); buf.putShort((short) (TimeZone.getDefault().getRawOffset() / 60 / 1000)); } /** {@inheritDoc} */ public void writeNull() { // System.err.println("Write null"); buf.put(AMF.TYPE_NULL); } /** {@inheritDoc} */ public void writeNumber(Number num) { buf.put(AMF.TYPE_NUMBER); buf.putDouble(num.doubleValue()); } /** {@inheritDoc} */ public void writeReference(Object obj) { log.debug("Write reference"); buf.put(AMF.TYPE_REFERENCE); buf.putShort(getReferenceId(obj)); } /** {@inheritDoc} */ @SuppressWarnings({ "rawtypes" }) public void writeObject(Object object, Serializer serializer) { if (checkWriteReference(object)) { return; } storeReference(object); // Create new map out of bean properties BeanMap beanMap = new BeanMap(object); // Set of bean attributes Set set = beanMap.keySet(); if ((set.size() == 0) || (set.size() == 1 && beanMap.containsKey("class"))) { // BeanMap is empty or can only access "class" attribute, skip it writeArbitraryObject(object, serializer); return; } // Write out either start of object marker for class name or "empty" start of object marker Class objectClass = object.getClass(); if (!objectClass.isAnnotationPresent(Anonymous.class)) { buf.put(AMF.TYPE_CLASS_OBJECT); putString(buf, serializer.getClassName(objectClass)); } else { buf.put(AMF.TYPE_OBJECT); } if (object instanceof ICustomSerializable) { ((ICustomSerializable) object).serialize(this, serializer); buf.put((byte) 0x00); buf.put((byte) 0x00); buf.put(AMF.TYPE_END_OF_OBJECT); return; } // Iterate thru entries and write out property names with separators for (Object key : set) { String fieldName = key.toString(); log.debug("Field name: {} class: {}", fieldName, objectClass); Field field = getField(objectClass, fieldName); Method getter = getGetter(objectClass, beanMap, fieldName); // Check if the Field corresponding to the getter/setter pair is transient if (!serializeField(serializer, objectClass, fieldName, field, getter)) { continue; } putString(buf, fieldName); serializer.serialize(this, field, getter, object, beanMap.get(key)); } // Write out end of object mark buf.put((byte) 0x00); buf.put((byte) 0x00); buf.put(AMF.TYPE_END_OF_OBJECT); } @SuppressWarnings("unchecked") protected boolean serializeField(Serializer serializer, Class objectClass, String keyName, Field field, Method getter) { // to prevent, NullPointerExceptions, get the element first and check if it's null. Element element = getSerializeCache().get(objectClass); Map serializeMap = (element == null ? null : (Map) element.getObjectValue()); if (serializeMap == null) { serializeMap = new HashMap(); getSerializeCache().put(new Element(objectClass, serializeMap)); } Boolean serialize; if (getSerializeCache().isKeyInCache(keyName)) { serialize = serializeMap.get(keyName); } else { serialize = serializer.serializeField(keyName, field, getter); serializeMap.put(keyName, serialize); } return serialize; } @SuppressWarnings("unchecked") protected Field getField(Class objectClass, String keyName) { //again, to prevent null pointers, check if the element exists first. Element element = getFieldCache().get(objectClass); Map fieldMap = (element == null ? null : (Map) element.getObjectValue()); if (fieldMap == null) { fieldMap = new HashMap(); getFieldCache().put(new Element(objectClass, fieldMap)); } Field field = null; if (fieldMap.containsKey(keyName)) { field = fieldMap.get(keyName); } else { for (Class clazz = objectClass; !clazz.equals(Object.class); clazz = clazz.getSuperclass()) { Field[] fields = clazz.getDeclaredFields(); if (fields.length > 0) { for (Field fld : fields) { if (fld.getName().equals(keyName)) { field = fld; break; } } } } fieldMap.put(keyName, field); } return field; } @SuppressWarnings("unchecked") protected Method getGetter(Class objectClass, BeanMap beanMap, String keyName) { //check element to prevent null pointer Element element = getGetterCache().get(objectClass); Map getterMap = (element == null ? null : (Map) element.getObjectValue()); if (getterMap == null) { getterMap = new HashMap(); getGetterCache().put(new Element(objectClass, getterMap)); } Method getter; if (getterMap.containsKey(keyName)) { getter = getterMap.get(keyName); } else { getter = beanMap.getReadMethod(keyName); getterMap.put(keyName, getter); } return getter; } /** {@inheritDoc} */ public void writeObject(Map map, Serializer serializer) { if (checkWriteReference(map)) { return; } storeReference(map); buf.put(AMF.TYPE_OBJECT); boolean isBeanMap = (map instanceof BeanMap); for (Map.Entry entry : map.entrySet()) { if (isBeanMap && "class".equals(entry.getKey())) { continue; } putString(entry.getKey().toString()); serializer.serialize(this, entry.getValue()); } buf.put((byte) 0x00); buf.put((byte) 0x00); buf.put(AMF.TYPE_END_OF_OBJECT); } /** * Writes an arbitrary object to the output. * * @param serializer Output writer * @param object Object to write */ protected void writeArbitraryObject(Object object, Serializer serializer) { log.debug("writeObject"); // If we need to serialize class information... Class objectClass = object.getClass(); if (!objectClass.isAnnotationPresent(Anonymous.class)) { // Write out start object marker for class name buf.put(AMF.TYPE_CLASS_OBJECT); putString(buf, serializer.getClassName(objectClass)); } else { // Write out start object marker without class name buf.put(AMF.TYPE_OBJECT); } // Iterate thru fields of an object to build "name-value" map from it for (Field field : objectClass.getFields()) { String fieldName = field.getName(); log.debug("Field: {} class: {}", field, objectClass); // Check if the Field corresponding to the getter/setter pair is transient if (!serializeField(serializer, objectClass, fieldName, field, null)) { continue; } Object value; try { // Get field value value = field.get(object); } catch (IllegalAccessException err) { // Swallow on private and protected properties access exception continue; } // Write out prop name putString(buf, fieldName); // Write out serializer.serialize(this, field, null, object, value); } // Write out end of object marker buf.put((byte) 0x00); buf.put((byte) 0x00); buf.put(AMF.TYPE_END_OF_OBJECT); } /** {@inheritDoc} */ public void writeString(String string) { final byte[] encoded = encodeString(string); final int len = encoded.length; if (len < AMF.LONG_STRING_LENGTH) { buf.put(AMF.TYPE_STRING); buf.putShort((short) len); } else { buf.put(AMF.TYPE_LONG_STRING); buf.putInt(len); } buf.put(encoded); } /** {@inheritDoc} */ public void writeByteArray(ByteArray array) { throw new RuntimeException("ByteArray objects not supported with AMF0"); } /** {@inheritDoc} */ public void writeVectorInt(Vector vector) { throw new RuntimeException("Vector objects not supported with AMF0"); } /** {@inheritDoc} */ public void writeVectorUInt(Vector vector) { throw new RuntimeException("Vector objects not supported with AMF0"); } /** {@inheritDoc} */ public void writeVectorNumber(Vector vector) { throw new RuntimeException("Vector objects not supported with AMF0"); } /** {@inheritDoc} */ public void writeVectorObject(Vector vector) { throw new RuntimeException("Vector objects not supported with AMF0"); } /** * Encode string. * * @param string * @return encoded string */ protected static byte[] encodeString(String string) { Element element = getStringCache().get(string); byte[] encoded = (element == null ? null : (byte[]) element.getObjectValue()); if (encoded == null) { ByteBuffer buf = AMF.CHARSET.encode(string); encoded = new byte[buf.limit()]; buf.get(encoded); getStringCache().put(new Element(string, encoded)); } return encoded; } /** * Write out string * @param buf Byte buffer to write to * @param string String to write */ public static void putString(IoBuffer buf, String string) { final byte[] encoded = encodeString(string); buf.putShort((short) encoded.length); buf.put(encoded); } /** {@inheritDoc} */ public void putString(String string) { putString(buf, string); } /** {@inheritDoc} */ public void writeXML(Document xml) { buf.put(AMF.TYPE_XML); putString(XMLUtils.docToString(xml)); } /** * Convenience method to allow XML text to be used, instead * of requiring an XML Document. * * @param xml xml to write */ public void writeXML(String xml) { buf.put(AMF.TYPE_XML); putString(xml); } /** * Return buffer of this Output object * @return Byte buffer of this Output object */ public IoBuffer buf() { return this.buf; } public void reset() { clearReferences(); } protected static Cache getStringCache() { if (stringCache == null) { stringCache = getCacheManager().getCache("org.red5.io.amf.Output.stringCache"); } return stringCache; } protected static Cache getSerializeCache() { if (serializeCache == null) { serializeCache = getCacheManager().getCache("org.red5.io.amf.Output.serializeCache"); } return serializeCache; } protected static Cache getFieldCache() { if (fieldCache == null) { fieldCache = getCacheManager().getCache("org.red5.io.amf.Output.fieldCache"); } return fieldCache; } protected static Cache getGetterCache() { if (getterCache == null) { getterCache = getCacheManager().getCache("org.red5.io.amf.Output.getterCache"); } return getterCache; } public static void destroyCache() { if (cacheManager != null) { cacheManager.shutdown(); fieldCache = null; getterCache = null; serializeCache = null; stringCache = null; } } }red5-1.0~svn4374.orig/src/org/red5/io/IKeyFrameMetaCache.java0000644000175000017500000000273411706617130023361 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; import java.io.File; import org.red5.io.flv.IKeyFrameDataAnalyzer.KeyFrameMeta; /** * Interface defining a cache for keyframe metadata informations. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IKeyFrameMetaCache { /** * Load keyframe informations for the given file. * * @param file File to load informations for. * @return The keyframe informations or null if none exist. */ public KeyFrameMeta loadKeyFrameMeta(File file); /** * Store keyframe informations for the given file. * * @param file File to save informations for. * @param meta Keyframe informations for this file. */ public void saveKeyFrameMeta(File file, KeyFrameMeta meta); } red5-1.0~svn4374.orig/src/org/red5/io/mp3/0000755000175000017500000000000011760512574017646 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/mp3/IMP3Service.java0000644000175000017500000000201011706617130022525 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp3; import org.red5.io.IStreamableFileService; /** * Provide access to MP3 objects. Marker interface. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IMP3Service extends IStreamableFileService { // TODO: add more methods } red5-1.0~svn4374.orig/src/org/red5/io/mp3/IMP3.java0000644000175000017500000000177211706617130021222 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp3; import org.red5.io.IStreamableFile; /** * Informations about a MP3 file. Marker interface by now. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IMP3 extends IStreamableFile { // TODO: add more methods } red5-1.0~svn4374.orig/src/org/red5/io/mp3/impl/0000755000175000017500000000000011760512574020607 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/mp3/impl/MP3Reader.java0000644000175000017500000004432611747635016023207 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp3.impl; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.Semaphore; import org.apache.mina.core.buffer.IoBuffer; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3AudioHeader; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.TagException; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v24Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyAPIC; import org.red5.io.IKeyFrameMetaCache; import org.red5.io.IStreamableFile; import org.red5.io.ITag; import org.red5.io.ITagReader; import org.red5.io.IoConstants; import org.red5.io.amf.Output; import org.red5.io.flv.IKeyFrameDataAnalyzer; import org.red5.io.flv.impl.Tag; import org.red5.io.object.Serializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Read MP3 files */ public class MP3Reader implements ITagReader, IKeyFrameDataAnalyzer { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(MP3Reader.class); /** * File */ private File file; /** * File input stream */ private FileInputStream fis; /** * File channel */ private FileChannel channel; /** * Byte buffer */ private ByteBuffer buf = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN); /** * Last read tag object */ private ITag tag; /** * Previous tag size */ private int prevSize; /** * Current time */ private double currentTime; /** * Frame metadata */ private KeyFrameMeta frameMeta; /** * Positions and time map */ private HashMap posTimeMap; private int dataRate; /** * File duration */ private long duration; /** * Frame cache */ static private IKeyFrameMetaCache frameCache; /** * Holder for ID3 meta data */ private MetaData metaData; /** * Container for metadata and any other tags that should * be sent prior to media data. */ private LinkedList firstTags = new LinkedList(); private long fileSize; private final Semaphore lock = new Semaphore(1, true); MP3Reader() { // Only used by the bean startup code to initialize the frame cache } /** * Creates reader from file input stream * * @param file file input * @throws IOException */ public MP3Reader(File file) throws IOException { this.file = file; // parse the id3 info try { MP3File mp3file = (MP3File) AudioFileIO.read(file); MP3AudioHeader audioHeader = (MP3AudioHeader) mp3file.getAudioHeader(); if (audioHeader != null) { log.debug("Track length: {}", audioHeader.getTrackLength()); log.debug("Sample rate: {}", audioHeader.getSampleRateAsNumber()); log.debug("Channels: {}", audioHeader.getChannels()); log.debug("Variable bit rate: {}", audioHeader.isVariableBitRate()); log.debug("Track length (2): {}", audioHeader.getTrackLengthAsString()); log.debug("Mpeg version: {}", audioHeader.getMpegVersion()); log.debug("Mpeg layer: {}", audioHeader.getMpegLayer()); log.debug("Original: {}", audioHeader.isOriginal()); log.debug("Copyrighted: {}", audioHeader.isCopyrighted()); log.debug("Private: {}", audioHeader.isPrivate()); log.debug("Protected: {}", audioHeader.isProtected()); log.debug("Bitrate: {}", audioHeader.getBitRate()); log.debug("Encoding type: {}", audioHeader.getEncodingType()); log.debug("Encoder: {}", audioHeader.getEncoder()); } ID3v24Tag idTag = mp3file.getID3v2TagAsv24(); if (idTag != null) { // create meta data holder metaData = new MetaData(); metaData.setAlbum(idTag.getFirst(FieldKey.ALBUM)); metaData.setArtist(idTag.getFirst(FieldKey.ARTIST)); metaData.setComment(idTag.getFirst(FieldKey.COMMENT)); metaData.setGenre(idTag.getFirst(FieldKey.GENRE)); metaData.setSongName(idTag.getFirst(FieldKey.TITLE)); metaData.setTrack(idTag.getFirst(FieldKey.TRACK)); metaData.setYear(idTag.getFirst(FieldKey.YEAR)); //send album image if included List tagFieldList = idTag.getArtworkList(); if (tagFieldList == null || tagFieldList.isEmpty()) { log.debug("No cover art was found"); } else { Artwork imageField = tagFieldList.get(0); log.debug("Picture type: {}", imageField.getPictureType()); FrameBodyAPIC imageFrameBody = new FrameBodyAPIC(); imageFrameBody.setImageData(imageField.getBinaryData()); if (!imageFrameBody.isImageUrl()) { byte[] imageBuffer = (byte[]) imageFrameBody.getObjectValue(DataTypes.OBJ_PICTURE_DATA); //set the cover image on the metadata metaData.setCovr(imageBuffer); // Create tag for onImageData event IoBuffer buf = IoBuffer.allocate(imageBuffer.length); buf.setAutoExpand(true); Output out = new Output(buf); out.writeString("onImageData"); Map props = new HashMap(); props.put("trackid", 1); props.put("data", imageBuffer); out.writeMap(props, new Serializer()); buf.flip(); //Ugh i hate flash sometimes!! //Error #2095: flash.net.NetStream was unable to invoke callback onImageData. ITag result = new Tag(IoConstants.TYPE_METADATA, 0, buf.limit(), null, 0); result.setBody(buf); //add to first frames firstTags.add(result); } } } else { log.info("File did not contain ID3v2 data: {}", file.getName()); } mp3file = null; } catch (TagException e) { log.error("MP3Reader (tag error) {}", e); } catch (Exception e) { log.error("MP3Reader {}", e); } fis = new FileInputStream(file); // grab file channel and map it to memory-mapped byte buffer in read-only mode channel = fis.getChannel(); // get the total bytes / file size fileSize = channel.size(); log.debug("File size: {}", fileSize); // analyze keyframes data analyzeKeyFrames(); // create file metadata object firstTags.addFirst(createFileMeta()); // MP3 header is length of 32 bits, that is, 4 bytes // read further if there's still data if ((fileSize - channel.position()) > 4) { // look for next frame searchNextFrame(); // get current position long pos = channel.position(); // Data in MP3 file goes header-data-header-data...header-data // Read header... MP3Header header = null; try { header = readHeader(); } catch (Exception e) { log.warn("Exception reading initial header", e); } // set position channel.position(pos); // Check header if (header != null) { checkValidHeader(header); } else { throw new RuntimeException("No initial header found"); } } } /** * A MP3 stream never has video. * * @return always returns false */ public boolean hasVideo() { return false; } public void setFrameCache(IKeyFrameMetaCache frameCache) { MP3Reader.frameCache = frameCache; } /** * Check if the file can be played back with Flash. Supported sample rates * are 44KHz, 22KHz, 11KHz and 5.5KHz * * @param header * Header to check */ private void checkValidHeader(MP3Header header) { switch (header.getSampleRate()) { case 48000: case 44100: case 22050: case 11025: case 5513: break; default: throw new RuntimeException("Unsupported sample rate: " + header.getSampleRate()); } } /** * Creates file metadata object * * @return Tag */ private ITag createFileMeta() { log.debug("createFileMeta"); // create tag for onMetaData event IoBuffer in = IoBuffer.allocate(1024); in.setAutoExpand(true); Output out = new Output(in); out.writeString("onMetaData"); Map props = new HashMap(); props.put("duration", frameMeta.timestamps[frameMeta.timestamps.length - 1] / 1000.0); props.put("audiocodecid", IoConstants.FLAG_FORMAT_MP3); if (dataRate > 0) { props.put("audiodatarate", dataRate); } props.put("canSeekToEnd", true); //set id3 meta data if it exists if (metaData != null) { props.put("artist", metaData.getArtist()); props.put("album", metaData.getAlbum()); props.put("songName", metaData.getSongName()); props.put("genre", metaData.getGenre()); props.put("year", metaData.getYear()); props.put("track", metaData.getTrack()); props.put("comment", metaData.getComment()); if (metaData.hasCoverImage()) { Map covr = new HashMap(1); covr.put("covr", new Object[] { metaData.getCovr() }); props.put("tags", covr); } //clear meta for gc metaData = null; } out.writeMap(props, new Serializer()); in.flip(); ITag result = new Tag(IoConstants.TYPE_METADATA, 0, in.limit(), null, prevSize); result.setBody(in); return result; } /** * Search for next frame sync word. Sync word identifies valid frame. */ public void searchNextFrame() { log.debug("searchNextFrame"); ByteBuffer in = ByteBuffer.allocate(1).order(ByteOrder.BIG_ENDIAN); try { while ((fileSize - channel.position()) > 1) { // read byte in.clear(); channel.read(in); in.flip(); // check byte int ch = in.get() & 0xff; if (ch != 0xff) { continue; } // read next byte in.clear(); channel.read(in); in.flip(); // check next byte if ((in.get() & 0xe0) == 0xe0) { // found it log.debug("Found frame"); channel.position(channel.position() - 2); break; } } } catch (IOException e) { log.warn("Exception getting next frame", e); } finally { in.clear(); in = null; } } /** {@inheritDoc} */ public IStreamableFile getFile() { return null; } /** {@inheritDoc} */ public int getOffset() { return 0; } /** {@inheritDoc} */ public long getBytesRead() { try { return channel.position(); } catch (IOException e) { log.warn("Exception getting bytes read", e); } return 0; } /** {@inheritDoc} */ public long getDuration() { return duration; } /** * Get the total readable bytes in a file or ByteBuffer. * * @return Total readable bytes */ public long getTotalBytes() { return fileSize; } /** {@inheritDoc} */ public boolean hasMoreTags() { log.debug("hasMoreTags"); MP3Header header = null; try { header = readHeader(); } catch (IOException e) { log.warn("Exception reading header", e); } catch (Exception e) { searchNextFrame(); } //log.debug("Header: {}", header); if (header == null || header.frameSize() == 0) { // TODO find better solution how to deal with broken files return false; } try { if (channel.position() + header.frameSize() - 4 > fileSize) { // last frame is incomplete channel.position(fileSize); return false; } channel.position(channel.position() - 4); } catch (IOException e) { log.warn("Exception checking for more tags", e); } return true; } private MP3Header readHeader() throws Exception { log.debug("readHeader at {}", channel.position()); buf.clear(); channel.read(buf); buf.flip(); return new MP3Header(buf.getInt()); } /** {@inheritDoc} */ public ITag readTag() { log.debug("readTag"); try { lock.acquire(); if (!firstTags.isEmpty()) { // Return first tags before media data return firstTags.removeFirst(); } MP3Header header = readHeader(); int frameSize = header.frameSize(); if (frameSize == 0) { // TODO find better solution how to deal with broken files return null; } if (channel.position() + frameSize - 4 > fileSize) { // last frame is incomplete channel.position(fileSize); return null; } tag = new Tag(IoConstants.TYPE_AUDIO, (int) currentTime, frameSize + 1, null, prevSize); prevSize = frameSize + 1; currentTime += header.frameDuration(); IoBuffer body = IoBuffer.allocate(tag.getBodySize()); body.setAutoExpand(true); byte tagType = (IoConstants.FLAG_FORMAT_MP3 << 4) | (IoConstants.FLAG_SIZE_16_BIT << 1); switch (header.getSampleRate()) { case 48000: tagType |= IoConstants.FLAG_RATE_48_KHZ << 2; break; case 44100: tagType |= IoConstants.FLAG_RATE_44_KHZ << 2; break; case 22050: tagType |= IoConstants.FLAG_RATE_22_KHZ << 2; break; case 11025: tagType |= IoConstants.FLAG_RATE_11_KHZ << 2; break; default: tagType |= IoConstants.FLAG_RATE_5_5_KHZ << 2; } tagType |= (header.isStereo() ? IoConstants.FLAG_TYPE_STEREO : IoConstants.FLAG_TYPE_MONO); body.put(tagType); body.putInt(header.getData()); ByteBuffer in = ByteBuffer.allocate(frameSize - 4).order(ByteOrder.BIG_ENDIAN); channel.read(in); in.flip(); body.put(in); body.flip(); tag.setBody(body); } catch (InterruptedException e) { log.warn("Exception acquiring lock", e); } catch (Exception e) { log.warn("Exception reading tag", e); } finally { lock.release(); } return tag; } /** {@inheritDoc} */ public void close() { if (posTimeMap != null) { posTimeMap.clear(); } if (buf != null) { buf.clear(); buf = null; } try { fis.close(); channel.close(); } catch (IOException e) { log.error("Exception on close", e); } } /** {@inheritDoc} */ public void decodeHeader() { } /** {@inheritDoc} */ public void position(long pos) { try { if (pos == Long.MAX_VALUE) { // seek at EOF channel.position(fileSize); currentTime = duration; return; } channel.position(pos); // advance to next frame searchNextFrame(); Double time = posTimeMap.get(channel.position()); if (time != null) { currentTime = time; } else { // Unknown frame position - this should never happen currentTime = 0; } } catch (IOException e) { log.warn("Exception setting position", e); } } /** {@inheritDoc} */ public KeyFrameMeta analyzeKeyFrames() { log.debug("analyzeKeyFrames"); if (frameMeta != null) { return frameMeta; } try { lock.acquire(); // check for cached frame informations if (frameCache != null) { frameMeta = frameCache.loadKeyFrameMeta(file); if (frameMeta != null && frameMeta.duration > 0) { // Frame data loaded, create other mappings duration = frameMeta.duration; frameMeta.audioOnly = true; posTimeMap = new HashMap(); for (int i = 0; i < frameMeta.positions.length; i++) { posTimeMap.put(frameMeta.positions[i], (double) frameMeta.timestamps[i]); } return frameMeta; } } List positionList = new ArrayList(); List timestampList = new ArrayList(); dataRate = 0; long rate = 0; int count = 0; long origPos = channel.position(); double time = 0; channel.position(0); searchNextFrame(); while (hasMoreTags()) { MP3Header header = readHeader(); if (header == null || header.frameSize() == 0) { // TODO find better solution how to deal with broken files... // See APPSERVER-62 for details break; } long pos = channel.position() - 4; if (pos + header.frameSize() > fileSize) { // last frame is incomplete break; } positionList.add(pos); timestampList.add(time); rate += header.getBitRate() / 1000; time += header.frameDuration(); channel.position(pos + header.frameSize()); count++; } // restore the pos channel.position(origPos); duration = (long) time; dataRate = (int) (rate / count); posTimeMap = new HashMap(); frameMeta = new KeyFrameMeta(); frameMeta.duration = duration; frameMeta.positions = new long[positionList.size()]; frameMeta.timestamps = new int[timestampList.size()]; frameMeta.audioOnly = true; for (int i = 0; i < frameMeta.positions.length; i++) { frameMeta.positions[i] = positionList.get(i); frameMeta.timestamps[i] = timestampList.get(i).intValue(); posTimeMap.put(positionList.get(i), timestampList.get(i)); } if (frameCache != null) { frameCache.saveKeyFrameMeta(file, frameMeta); } } catch (InterruptedException e) { log.warn("Exception acquiring lock", e); } catch (Exception e) { log.warn("Exception analyzing frames", e); } finally { lock.release(); } log.debug("Analysis complete"); return frameMeta; } /** * Simple holder for id3 meta data */ static class MetaData { String album = ""; String artist = ""; String genre = ""; String songName = ""; String track = ""; String year = ""; String comment = ""; byte[] covr = null; public String getAlbum() { return album; } public void setAlbum(String album) { this.album = album; } public String getArtist() { return artist; } public void setArtist(String artist) { this.artist = artist; } public String getGenre() { return genre; } public void setGenre(String genre) { this.genre = genre; } public String getSongName() { return songName; } public void setSongName(String songName) { this.songName = songName; } public String getTrack() { return track; } public void setTrack(String track) { this.track = track; } public String getYear() { return year; } public void setYear(String year) { this.year = year; } public String getComment() { return comment; } public void setComment(String comment) { this.comment = comment; } public byte[] getCovr() { return covr; } public void setCovr(byte[] covr) { this.covr = covr; log.debug("Cover image array size: {}", covr.length); } public boolean hasCoverImage() { return covr != null; } } } red5-1.0~svn4374.orig/src/org/red5/io/mp3/impl/MP3.java0000644000175000017500000000271611706617130022051 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp3.impl; import java.io.File; import java.io.IOException; import org.red5.io.ITagReader; import org.red5.io.ITagWriter; import org.red5.io.mp3.IMP3; /** * Represents MP3 file */ public class MP3 implements IMP3 { /** * Actual file object */ private File file; /** * Creates MP3 object using given file * @param file File object to use */ public MP3(File file) { this.file = file; } /** {@inheritDoc} */ public ITagReader getReader() throws IOException { return new MP3Reader(file); } /** {@inheritDoc} */ public ITagWriter getWriter() throws IOException { return null; } /** {@inheritDoc} */ public ITagWriter getAppendWriter() throws IOException { return null; } } red5-1.0~svn4374.orig/src/org/red5/io/mp3/impl/MP3Header.java0000644000175000017500000001313711747635016023171 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp3.impl; /** * Header of a MP3 frame. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @see File format */ public class MP3Header { /** * MP3 bitrates */ private static final int[][] BITRATES = { { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 }, { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 }, { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 }, { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 }, { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }, }; /** * Sample rates */ private static final int[][] SAMPLERATES = { // Version 2.5 { 11025, 12000, 8000, -1 }, // Unknown version { -1, -1, -1, -1 }, // Version 2 { 22050, 24000, 16000, -1 }, // Version 1 { 44100, 48000, 32000, -1 }, }; /** * Frame sync data */ private int data; /** * Audio version id */ private byte audioVersionId; /** * Layer description */ private byte layerDescription; /** * Protection bit */ private boolean protectionBit; /** * Bitrate used (index in array of bitrates) */ private byte bitRateIndex; /** * Sampling rate used (index in array of sample rates) */ private byte samplingRateIndex; /** * Padding bit */ private boolean paddingBit; /** * Channel mode */ private byte channelMode; /** * Creates MP3 header from frame sync value * @param data Frame sync data * @throws Exception On invalid frame synchronization */ public MP3Header(int data) throws Exception { if ((data & 0xffe00000) == 0xffe00000) { this.data = data; // strip signed bit data &= 0x1fffff; audioVersionId = (byte) ((data >> 19) & 3); layerDescription = (byte) ((data >> 17) & 3); protectionBit = ((data >> 16) & 1) == 0; bitRateIndex = (byte) ((data >> 12) & 15); samplingRateIndex = (byte) ((data >> 10) & 3); paddingBit = ((data >> 9) & 1) != 0; channelMode = (byte) ((data >> 6) & 3); } else { throw new Exception("Invalid frame sync word"); } } /** * Getter for frame sync word data * * @return Frame sync word data */ public int getData() { return data; } /** * Whether stereo playback mode is used * * @return true if stereo mode is used, false otherwise */ public boolean isStereo() { return (channelMode != 3); } /** * Whether MP3 has protection bit * * @return true if MP3 has protection bit, false otherwise */ public boolean isProtected() { return protectionBit; } /** * Getter for bitrate * * @return File bitrate */ public int getBitRate() { int result; switch (audioVersionId) { case 1: // Unknown return -1; case 0: case 2: // Version 2 or 2.5 if (layerDescription == 3) { // Layer 1 result = BITRATES[3][bitRateIndex]; } else if (layerDescription == 2 || layerDescription == 1) { // Layer 2 or 3 result = BITRATES[4][bitRateIndex]; } else { // Unknown layer return -1; } break; case 3: // Version 1 if (layerDescription == 3) { // Layer 1 result = BITRATES[0][bitRateIndex]; } else if (layerDescription == 2) { // Layer 2 result = BITRATES[1][bitRateIndex]; } else if (layerDescription == 1) { // Layer 3 result = BITRATES[2][bitRateIndex]; } else { // Unknown layer return -1; } break; default: // Unknown version return -1; } return result * 1000; } /** * Getter for sample rate * * @return Sampling rate */ public int getSampleRate() { return SAMPLERATES[audioVersionId][samplingRateIndex]; } /** * Calculate the size of a MP3 frame for this header. * * @return size of the frame including the header */ public int frameSize() { switch (layerDescription) { case 3: // Layer 1 return (12 * getBitRate() / getSampleRate() + (paddingBit ? 1 : 0)) * 4; case 2: case 1: // Layer 2 and 3 if (audioVersionId == 3) { // MPEG 1 return 144 * getBitRate() / getSampleRate() + (paddingBit ? 1 : 0); } else { // MPEG 2 or 2.5 return 72 * getBitRate() / getSampleRate() + (paddingBit ? 1 : 0); } default: // Unknown return -1; } } /** * Return the duration of the frame for this header. * * @return The duration in milliseconds */ public double frameDuration() { switch (layerDescription) { case 3: // Layer 1 return 384 / (getSampleRate() * 0.001); case 2: case 1: if (audioVersionId == 3) { // MPEG 1, Layer 2 and 3 return 1152 / (getSampleRate() * 0.001); } else { // MPEG 2 or 2.5, Layer 2 and 3 return 576 / (getSampleRate() * 0.001); } default: // Unknown return -1; } } } red5-1.0~svn4374.orig/src/org/red5/io/mp3/impl/MP3Service.java0000644000175000017500000000252711706617130023372 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.mp3.impl; import java.io.File; import java.io.IOException; import org.red5.io.BaseStreamableFileService; import org.red5.io.IStreamableFile; import org.red5.io.mp3.IMP3Service; /** * Streamable file service extension for MP3 */ public class MP3Service extends BaseStreamableFileService implements IMP3Service { /** {@inheritDoc} */ @Override public String getPrefix() { return "mp3"; } /** {@inheritDoc} */ @Override public String getExtension() { return ".mp3"; } /** {@inheritDoc} */ @Override public IStreamableFile getStreamableFile(File file) throws IOException { return new MP3(file); } } red5-1.0~svn4374.orig/src/org/red5/io/StreamableFileFactory.java0000644000175000017500000000361511706617130024220 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; import java.io.File; import java.util.HashSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Creates streamable file services */ public class StreamableFileFactory implements IStreamableFileFactory { // Initialize Logging public static Logger logger = LoggerFactory.getLogger(StreamableFileFactory.class); private Set services = new HashSet(); /** * Setter for services * * @param services Set of streamable file services */ public void setServices(Set services) { logger.debug("StreamableFileFactory set services"); this.services = services; } /** {@inheritDoc} */ public IStreamableFileService getService(File fp) { logger.debug("Get service for file: " + fp.getName()); // Return first service that can handle the passed file for (IStreamableFileService service : this.services) { if (service.canHandle(fp)) { logger.debug("Found service"); return service; } } return null; } /** {@inheritDoc} */ public Set getServices() { logger.debug("StreamableFileFactory get services"); return services; } } red5-1.0~svn4374.orig/src/org/red5/io/BaseStreamableFileService.java0000644000175000017500000000525211706617130025003 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base class for streamable file services. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public abstract class BaseStreamableFileService implements IStreamableFileService { private static final Logger log = LoggerFactory.getLogger(BaseStreamableFileService.class); /** {@inheritDoc} */ public void setPrefix(String prefix) { } /** {@inheritDoc} */ public abstract String getPrefix(); /** {@inheritDoc} */ public void setExtension(String extension) { } /** {@inheritDoc} */ public abstract String getExtension(); /** {@inheritDoc} */ public String prepareFilename(String name) { String prefix = getPrefix() + ':'; if (name.startsWith(prefix)) { name = name.substring(prefix.length()); // if there is no extension on the file add the first one log.debug("prepareFilename - lastIndexOf: {} length: {}", name.lastIndexOf('.'), name.length()); if (name.lastIndexOf('.') != name.length() - 4) { name = name + getExtension().split(",")[0]; } } return name; } /** {@inheritDoc} */ public boolean canHandle(File file) { boolean valid = false; if (file.exists()) { String absPath = file.getAbsolutePath().toLowerCase(); String fileExt = absPath.substring(absPath.lastIndexOf('.')); log.debug("canHandle - Path: {} Ext: {}", absPath, fileExt); String[] exts = getExtension().split(","); for (String ext : exts) { if (ext.equals(fileExt)) { valid = true; break; } } } return valid; } /** {@inheritDoc} */ public abstract IStreamableFile getStreamableFile(File file) throws IOException; } red5-1.0~svn4374.orig/src/org/red5/io/IStreamableFileFactory.java0000644000175000017500000000241611747114732024334 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; import java.io.File; import java.util.Set; import org.red5.server.api.scope.IScopeService; /** * Scope service extension that provides method to get streamable file services set */ public interface IStreamableFileFactory extends IScopeService { public static String BEAN_NAME = "streamableFileFactory"; public abstract IStreamableFileService getService(File fp); /** * Getter for services * * @return Set of streamable file services */ public abstract Set getServices(); }red5-1.0~svn4374.orig/src/org/red5/io/flv/0000755000175000017500000000000011760512574017736 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/flv/IFLVService.java0000644000175000017500000000267011706617130022661 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv; import org.red5.io.IStreamableFileService; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; /** * A FLVService sets up the service and hands out FLV objects to * its callers * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public interface IFLVService extends IStreamableFileService { /** * Sets the serializer * * @param serializer Serializer object */ public void setSerializer(Serializer serializer); /** * Sets the deserializer * * @param deserializer Deserializer object */ public void setDeserializer(Deserializer deserializer); } red5-1.0~svn4374.orig/src/org/red5/io/flv/IFLV.java0000644000175000017500000000713111706617130021335 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map; import org.red5.io.IStreamableFile; import org.red5.io.ITagReader; import org.red5.io.ITagWriter; import org.red5.io.flv.meta.IMetaData; import org.red5.io.flv.meta.IMetaService; import org.red5.server.api.cache.ICacheStore; /** * Represents FLV file */ public interface IFLV extends IStreamableFile { /** * Returns a boolean stating whether the flv has metadata * * @return boolean true if file has injected metadata, false otherwise */ public boolean hasMetaData(); /** * Sets the metadata * * @param metadata Metadata object * @throws FileNotFoundException File not found * @throws IOException Any other I/O exception */ @SuppressWarnings({ "rawtypes" }) public void setMetaData(IMetaData metadata) throws FileNotFoundException, IOException; /** * Sets the MetaService through Spring * * @param service Metadata service */ public void setMetaService(IMetaService service); /** * Returns a map of the metadata * * @return metadata File metadata * @throws FileNotFoundException File not found */ @SuppressWarnings({ "rawtypes" }) public IMetaData getMetaData() throws FileNotFoundException; /** * Returns a boolean stating whether a flv has keyframedata * * @return boolean true if file has keyframe metadata, false otherwise */ public boolean hasKeyFrameData(); /** * Sets the keyframe data of a flv file * * @param keyframedata Keyframe metadata */ @SuppressWarnings({ "rawtypes" }) public void setKeyFrameData(Map keyframedata); /** * Gets the keyframe data * * @return keyframedata Keyframe metadata */ @SuppressWarnings({ "rawtypes" }) public Map getKeyFrameData(); /** * Refreshes the headers. Usually used after data is added to the flv file * * @throws IOException Any I/O exception */ public void refreshHeaders() throws IOException; /** * Flushes Header * * @throws IOException Any I/O exception */ public void flushHeaders() throws IOException; /** * Returns a Reader closest to the nearest keyframe * * @param seekPoint Point in file we are seeking around * @return reader Tag reader closest to that point */ public ITagReader readerFromNearestKeyFrame(int seekPoint); /** * Returns a Writer based on the nearest key frame * * @param seekPoint Point in file we are seeking around * @return writer Tag writer closest to that point */ public ITagWriter writerFromNearestKeyFrame(int seekPoint); /** * Sets the caching implemenation * * @param cache cache */ public void setCache(ICacheStore cache); } red5-1.0~svn4374.orig/src/org/red5/io/flv/meta/0000755000175000017500000000000011760512574020664 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/flv/meta/MetaData.java0000644000175000017500000001005011706617130023175 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.meta; import java.util.HashMap; import java.util.Map; /** * MetaData Implementation * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * * Example: * * // private boolean canSeekToEnd = true; * // private int videocodecid = 4; * // private int framerate = 15; * // private int videodatarate = 600; * // private int height; * // private int width = 320; * // private double duration = 7.347; * @param key type * @param value type */ public class MetaData extends HashMap implements IMetaData { private static final long serialVersionUID = -5681069577717669925L; /** * Cue points array. Cue points can be injected on fly like any other data even on client-side. */ IMetaCue[] cuePoints; //CuePoint array /** MetaData constructor */ public MetaData() { } /** {@inheritDoc} */ public boolean getCanSeekToEnd() { return (Boolean) this.get("canSeekToEnd"); } /** {@inheritDoc} */ public void setCanSeekToEnd(boolean b) { this.put("canSeekToEnd", b); } /** {@inheritDoc} */ public int getVideoCodecId() { return (Integer) this.get("videocodecid"); } /** {@inheritDoc} */ public void setVideoCodecId(int id) { this.put("videocodecid", id); } public int getAudioCodecId() { return (Integer) this.get("audiocodecid"); } public void setAudioCodecId(int id) { this.put("audiocodecid", id); } /** {@inheritDoc} */ public double getFrameRate() { return (Double) this.get("framerate"); } /** {@inheritDoc} */ public void setFrameRate(double rate) { this.put("framerate", Double.valueOf(rate)); } /** {@inheritDoc} */ public int getVideoDataRate() { return (Integer) this.get("videodatarate"); } /** {@inheritDoc} */ public void setVideoDataRate(int rate) { this.put("videodatarate", rate); } /** {@inheritDoc} */ public int getWidth() { return (Integer) this.get("width"); } /** {@inheritDoc} */ public void setWidth(int w) { this.put("width", w); } /** {@inheritDoc} */ public double getDuration() { return (Double) this.get("duration"); } /** {@inheritDoc} */ public void setDuration(double d) { this.put("duration", d); } /** {@inheritDoc} */ public int getHeight() { return (Integer) this.get("height"); } /** {@inheritDoc} */ public void setHeight(int h) { this.put("height", h); } /** * Sets the Meta Cue Points * * @param cuePoints The cuePoints to set. */ public void setMetaCue(IMetaCue[] cuePoints) { Map cues = new HashMap(); this.cuePoints = cuePoints; int j = 0; for (j = 0; j < this.cuePoints.length; j++) { cues.put(String.valueOf(j), this.cuePoints[j]); } // "CuePoints", cuePointData // '0', MetaCue // name, "test" // type, "event" // time, "0.1" // '1', MetaCue // name, "test1" // type, "event1" // time, "0.5" this.put("cuePoints", cues); } /** * Return array of cue points * * @return Array of cue points */ public IMetaCue[] getMetaCue() { return this.cuePoints; } /** {@inheritDoc} */ @Override public String toString() { return "MetaData{" + "cuePoints=" + (cuePoints == null ? null : this.get("cuePoints")) + '}'; } } red5-1.0~svn4374.orig/src/org/red5/io/flv/meta/ICueType.java0000644000175000017500000000211111706617130023203 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.meta; /** * Cue point type * * @author The Red5 Project (red5@osflash.org) * @author daccattato(daccattato@gmail.com) */ public interface ICueType { /** * Cue point type of event */ String EVENT = "event"; /** * Cue point type of navigation */ String NAVIGATION = "navigation"; } red5-1.0~svn4374.orig/src/org/red5/io/flv/meta/MetaService.java0000644000175000017500000002236111706617130023734 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.meta; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.ITag; import org.red5.io.IoConstants; import org.red5.io.amf.Input; import org.red5.io.amf.Output; import org.red5.io.flv.impl.FLVReader; import org.red5.io.flv.impl.FLVWriter; import org.red5.io.flv.impl.Tag; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * MetaService represents a MetaData service in Spring * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class MetaService implements IMetaService { protected static Logger log = LoggerFactory.getLogger(MetaService.class); /** * Source file */ File file; /** * Serializer */ private Serializer serializer; /** * Deserializer */ private Deserializer deserializer; /** * @return Returns the deserializer. */ public Deserializer getDeserializer() { return deserializer; } /** * @param deserializer The deserializer to set. */ public void setDeserializer(Deserializer deserializer) { this.deserializer = deserializer; } /** * @return Returns the serializer. */ public Serializer getSerializer() { return serializer; } /** * @param serializer The serializer to set. */ public void setSerializer(Serializer serializer) { this.serializer = serializer; } /** * MetaService constructor */ public MetaService() { super(); } public MetaService(File poFil) { this(); this.file = poFil; } /** * {@inheritDoc} */ public void write(IMetaData meta) throws IOException { // Get cue points, FLV reader and writer IMetaCue[] metaArr = meta.getMetaCue(); FLVReader reader = new FLVReader(file, false); FLVWriter writer = new FLVWriter(file, false); ITag tag = null; // Read first tag if (reader.hasMoreTags()) { tag = reader.readTag(); if (tag.getDataType() == IoConstants.TYPE_METADATA) { if (!reader.hasMoreTags()) { throw new IOException("File we're writing is metadata only?"); } } } if (tag == null) { throw new IOException("Tag was null"); } meta.setDuration(((double) reader.getDuration() / 1000)); meta.setVideoCodecId(reader.getVideoCodecId()); meta.setAudioCodecId(reader.getAudioCodecId()); ITag injectedTag = injectMetaData(meta, tag); injectedTag.setPreviousTagSize(0); tag.setPreviousTagSize(injectedTag.getBodySize()); // TODO look into why this fails in the unit test try { writer.writeTag(injectedTag); writer.writeTag(tag); } catch (Exception e) { log.warn("Metadata insert failed", e); return; } int cuePointTimeStamp = 0; int counter = 0; if (metaArr != null) { Arrays.sort(metaArr); cuePointTimeStamp = getTimeInMilliseconds(metaArr[0]); } while (reader.hasMoreTags()) { tag = reader.readTag(); // if there are cuePoints in the array if (counter < metaArr.length) { // If the tag has a greater timestamp than the // cuePointTimeStamp, then inject the tag while (tag.getTimestamp() > cuePointTimeStamp) { injectedTag = injectMetaCue(metaArr[counter], tag); writer.writeTag(injectedTag); tag.setPreviousTagSize(injectedTag.getBodySize()); // Advance to the next CuePoint counter++; if (counter > (metaArr.length - 1)) { break; } cuePointTimeStamp = getTimeInMilliseconds(metaArr[counter]); } } if (tag.getDataType() != IoConstants.TYPE_METADATA) { writer.writeTag(tag); } } writer.close(); } /** * Merges the two Meta objects * * @param metaData1 * First metadata object * @param metaData2 * Second metadata object * @return Merged metadata */ @SuppressWarnings({ "unchecked" }) public static IMeta mergeMeta(IMetaData metaData1, IMetaData metaData2) { //walk the entries and merge them //1. higher number values trump lower ones //2. true considered higher than false //3. strings are not replaced Map map1 = ((Map) metaData1); Set> set1 = map1.entrySet(); Map map2 = ((Map) metaData2); Set> set2 = map2.entrySet(); //map to hold updates / replacements Map rep = new HashMap(); //loop to update common elements for (Entry entry1 : set1) { String key1 = entry1.getKey(); if (map2.containsKey(key1)) { Object value1 = map1.get(key1); Object value2 = map2.get(key1); //we dont replace strings //check numbers if (value1 instanceof Double) { if (Double.valueOf(value1.toString()).doubleValue() < Double.valueOf(value2.toString()).doubleValue()) { rep.put(key1, value2); } } else if (value1 instanceof Integer) { if (Integer.valueOf(value1.toString()).intValue() < Integer.valueOf(value2.toString()).intValue()) { rep.put(key1, value2); } } else if (value1 instanceof Long) { if (Long.valueOf(value1.toString()).longValue() < Long.valueOf(value2.toString()).longValue()) { rep.put(key1, value2); } } //check boolean if (value1 instanceof Boolean) { //consider true > false if (!Boolean.valueOf(value1.toString()) && Boolean.valueOf(value2.toString())) { rep.put(key1, value2); } } } } //remove all changed set1.removeAll(rep.entrySet()); //add the updates set1.addAll(rep.entrySet()); //perform a union / adds all elements missing from set1 set1.addAll(set2); //return the original object with merges return metaData1; } /** * Injects metadata (other than Cue points) into a tag * * @param meta * Metadata * @param tag * Tag * @return New tag with injected metadata */ private ITag injectMetaData(IMetaData meta, ITag tag) { IoBuffer bb = IoBuffer.allocate(1000); bb.setAutoExpand(true); Output out = new Output(bb); Serializer ser = new Serializer(); ser.serialize(out, "onMetaData"); ser.serialize(out, meta); IoBuffer tmpBody = out.buf().flip(); int tmpBodySize = out.buf().limit(); int tmpPreviousTagSize = tag.getPreviousTagSize(); return new Tag(IoConstants.TYPE_METADATA, 0, tmpBodySize, tmpBody, tmpPreviousTagSize); } /** * Injects metadata (Cue Points) into a tag * * @param meta * Metadata (cue points) * @param tag * Tag * @return ITag tag New tag with injected metadata */ private ITag injectMetaCue(IMetaCue meta, ITag tag) { // IMeta meta = (MetaCue) cue; Output out = new Output(IoBuffer.allocate(1000)); Serializer ser = new Serializer(); ser.serialize(out, "onCuePoint"); ser.serialize(out, meta); IoBuffer tmpBody = out.buf().flip(); int tmpBodySize = out.buf().limit(); int tmpPreviousTagSize = tag.getPreviousTagSize(); int tmpTimestamp = getTimeInMilliseconds(meta); return new Tag(IoConstants.TYPE_METADATA, tmpTimestamp, tmpBodySize, tmpBody, tmpPreviousTagSize); } /** * Returns a timestamp of cue point in milliseconds * * @param metaCue * Cue point * @return int time Timestamp of given cue point (in milliseconds) */ private int getTimeInMilliseconds(IMetaCue metaCue) { return (int) (metaCue.getTime() * 1000.00); } /** * {@inheritDoc} */ public void writeMetaData(IMetaData metaData) { IMetaCue meta = (MetaCue) metaData; Output out = new Output(IoBuffer.allocate(1000)); if (serializer == null) { serializer = new Serializer(); } serializer.serialize(out, "onCuePoint"); serializer.serialize(out, meta); } /** * {@inheritDoc} */ public void writeMetaCue() { } /** * @return Returns the file. */ public File getFile() { return file; } /** * @param file The file to set. */ public void setFile(File file) { this.file = file; } /** {@inheritDoc} */ // TODO need to fix public MetaData readMetaData(IoBuffer buffer) { MetaData retMeta = new MetaData(); Input input = new Input(buffer); if (deserializer == null) { deserializer = new Deserializer(); } String metaType = deserializer.deserialize(input, String.class); log.debug("Metadata type: {}", metaType); Map m = deserializer.deserialize(input, Map.class); retMeta.putAll(m); return retMeta; } /** {@inheritDoc} */ public IMetaCue[] readMetaCue() { return null; } } red5-1.0~svn4374.orig/src/org/red5/io/flv/meta/IMeta.java0000644000175000017500000000202511706617130022517 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.meta; import java.io.Serializable; /** * IMeta is a Marker Interface * CuePoint and MetaData both implement this interface * * @author The Red5 Project (red5@osflash.org) * @author daccattato(daccattato@gmail.com) */ public interface IMeta extends Serializable { } red5-1.0~svn4374.orig/src/org/red5/io/flv/meta/IMetaCue.java0000644000175000017500000000331511706617130023157 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.meta; /** * ICuePoint defines contract methods for use with * cuepoints * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) */ public interface IMetaCue extends IMeta, Comparable { /** * Sets the name * * @param name Cue point name * */ public void setName(String name); /** * Gets the name * * @return name Cue point name * */ public String getName(); /** * Sets the type type can be "event" or "navigation" * * @param type Cue point type * */ public void setType(String type); /** * Gets the type * * @return type Cue point type * */ public String getType(); /** * Sets the time * * @param d Timestamp * */ public void setTime(double d); /** * Gets the time * * @return time Timestamp * */ public double getTime(); } red5-1.0~svn4374.orig/src/org/red5/io/flv/meta/IMetaService.java0000644000175000017500000000476011706617130024050 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.meta; import java.io.File; import java.io.IOException; import org.apache.mina.core.buffer.IoBuffer; /** * IMetaService Defines the MetaData Service API * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public interface IMetaService { // Get FLV from FLVService // grab a reader from FLV // Set up CuePoints // Set up MetaData // Pass CuePoint array into MetaData // read in current MetaData if there is MetaData // if there isn't MetaData, write new MetaData // Call writeMetaData method on MetaService // that in turn will write the current metadata // and the cuepoint data // after that, call writeMetaCue() // this will loop through all the tags making // sure that the cuepoints are inserted /** * Initiates writing of the MetaData * * @param meta Metadata * @throws IOException I/O exception */ public void write(IMetaData meta) throws IOException; /** * Writes the MetaData * * @param metaData Metadata */ public void writeMetaData(IMetaData metaData); /** * Writes the Meta Cue Points */ public void writeMetaCue(); /** * Read the MetaData * * @return metaData Metadata * @param buffer IoBuffer source */ public MetaData readMetaData(IoBuffer buffer); /** * Read the Meta Cue Points * * @return Meta cue points */ public IMetaCue[] readMetaCue(); /** * Media file to be accessed * * @param file */ public void setFile(File file); /** * Returns the file being accessed * * @return file */ public File getFile(); } red5-1.0~svn4374.orig/src/org/red5/io/flv/meta/MetaCue.java0000644000175000017500000000603611706617130023051 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.meta; import java.util.HashMap; import java.util.Map; /** * Cue point is metadata marker used to control and accompany video playback with client-side application * events. Each cue point have at least one attribute, timestamp. Timestamp specifies position of cue point in * FLV file. * *

Cue points are usually used as event triggers down video flow or navigation points in a file. Cue points are * of two types: *

    *
  • Embedded into FLV or SWF
  • *
  • External, or added on fly (e.g. with FLVPlayback component or ActionScript) on both server-side and client-side.
  • *
*

* *

To add cue point trigger event listener at client-side in Flex/Flash application, use NetStream.onCuePoint event * handler.

* * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @param key type * @param value type */ public class MetaCue extends HashMap implements IMetaCue { /** * SerialVersionUID = -1769771340654996861L; */ private static final long serialVersionUID = -1769771340654996861L; /** * CuePoint constructor */ public MetaCue() { } /** {@inheritDoc} */ public void setName(String name) { this.put("name", name); } /** {@inheritDoc} */ public String getName() { return (String) this.get("name"); } /** {@inheritDoc} */ public void setType(String type) { this.put("type", type); } /** {@inheritDoc} */ public String getType() { return (String) this.get("type"); } /** {@inheritDoc} */ public void setTime(double d) { this.put("time", d); } /** {@inheritDoc} */ public double getTime() { return (Double) this.get("time"); } /** {@inheritDoc} */ public int compareTo(Object arg0) { MetaCue cp = (MetaCue) arg0; double cpTime = cp.getTime(); double thisTime = this.getTime(); if (cpTime > thisTime) { return -1; } else if (cpTime < thisTime) { return 1; } return 0; } /** {@inheritDoc} */ @Override public String toString() { StringBuilder sb = new StringBuilder("MetaCue{"); for (Map.Entry entry : entrySet()) { sb.append(entry.getKey().toLowerCase()); sb.append('='); sb.append(entry.getValue()); } sb.append('}'); return sb.toString(); } } red5-1.0~svn4374.orig/src/org/red5/io/flv/meta/IMetaData.java0000644000175000017500000000623311706617130023316 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.meta; /** * FLV MetaData interface * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * * Sample Data: * private boolean canSeekToEnd = true; * private int videocodecid = 4; * private int framerate = 15; * private int videodatarate = 400; * private int height = 215; * private int width = 320; * private int duration = 7.347; * @param key type * @param value type */ public interface IMetaData extends IMeta { /** * Returns a boolean depending on whether the video can * seek to end * @return true if file is seekable to the end, false otherwise */ public boolean getCanSeekToEnd(); /** * Sets whether a video can seek to end * @param b true if file is seekable to the end, false otherwise */ public void setCanSeekToEnd(boolean b); /** * Returns the video codec id * @return Video codec id */ public int getVideoCodecId(); /** * Sets the video codec id * @param id Video codec id */ public void setVideoCodecId(int id); public int getAudioCodecId(); public void setAudioCodecId(int id); /** * Returns the framerate. * @return FLV framerate in frames per second */ public double getFrameRate(); /** * Sets the framerate. * @param rate FLV framerate in frames per second */ public void setFrameRate(double rate); /** * Returns the videodatarate * @return Video data rate */ public int getVideoDataRate(); /** * Sets the videodatarate * @param rate Video data rate */ public void setVideoDataRate(int rate); /** * Returns the height * @return height Video height */ public int getHeight(); /** * Sets the height * @param h Video height */ public void setHeight(int h); /** * Returns the width Video width * @return width */ public int getWidth(); /** * Sets the width * @param w Video width */ public void setWidth(int w); /** * Returns the duration. * @return duration Video duration in seconds */ public double getDuration(); /** * Sets the duration. * @param d Video duration in seconds */ public void setDuration(double d); /** * Sets the cue points * @param metaCue Cue points */ public void setMetaCue(IMetaCue[] metaCue); /** * Gets the cue points * @return Cue points */ public IMetaCue[] getMetaCue(); } red5-1.0~svn4374.orig/src/org/red5/io/flv/IKeyFrameDataAnalyzer.java0000644000175000017500000000361511706617130024714 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv; import java.io.Serializable; import java.util.Arrays; /** * Analyzes key frame data. */ public interface IKeyFrameDataAnalyzer { /** * Analyze and return keyframe metadata. * * @return Metadata object */ public KeyFrameMeta analyzeKeyFrames(); /** * Keyframe metadata. */ public static class KeyFrameMeta implements Serializable { private static final long serialVersionUID = 5436632873705625365L; /** * Video codec id. */ public int videoCodecId = -1; /** * Audio codec id. */ public int audioCodecId = -1; /** * Duration in milliseconds */ public long duration; /** * Only audio frames? */ public boolean audioOnly; /** * Keyframe timestamps */ public int timestamps[]; /** * Keyframe positions */ public long positions[]; /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "KeyFrameMeta [videoCodecId=" + videoCodecId + ", audioCodecId=" + audioCodecId + ", duration=" + duration + ", audioOnly=" + audioOnly + ", timestamps=" + Arrays.toString(timestamps) + ", positions=" + Arrays.toString(positions) + "]"; } } } red5-1.0~svn4374.orig/src/org/red5/io/flv/FLVHeader.java0000644000175000017500000001422611706617130022340 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv; import java.nio.ByteBuffer; import org.apache.mina.core.buffer.IoBuffer; /** * FLVHeader parses out the contents of a FLV video file and returns * the Header data * * @see OSFlash (external) * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Tiago Jacobs (tiago@imdt.com.br) */ public class FLVHeader { static final int FLV_HEADER_FLAG_HAS_AUDIO = 4; static final int FLV_HEADER_FLAG_HAS_VIDEO = 1; /** * Signature */ public final static byte[] signature = new byte[] { (byte) (0x46 & 0xff), (byte) (0x4C & 0xff), (byte) (0x56 & 0xff) }; /** * FLV version */ public final static byte version = 0x01 & 0xff; //version 1 // TYPES /** * Reserved flag, one */ public static byte flagReserved01 = 0x00 & 0xff; /** * Audio flag */ public boolean flagAudio; /** * Reserved flag, two */ public static byte flagReserved02 = 0x00 & 0xff; /** * Video flag */ public boolean flagVideo; // DATA OFFSET /** * reserved for data up to 4,294,967,295 */ public int dataOffset = 0x00 & 0xff; /** * Returns the data offset bytes * * @return int Data offset */ public int getDataOffset() { return dataOffset; } /** * Sets the data offset bytes * * @param data_offset Data offset */ public void setDataOffset(int data_offset) { dataOffset = data_offset; } /** * Returns the signature bytes * * @return byte[] Signature */ public byte[] getSignature() { return signature; } /** * Overrides the toString method so that a FLVHeader can * be represented by its datatypes * * @return String String representation */ @Override public String toString() { String ret = ""; //ret += "SIGNATURE: \t" + getSIGNATURE() + "\n"; //ret += "SIGNATURE: \t\t" + new String(signature) + "\n"; ret += "VERSION: \t\t" + getVersion() + "\n"; ret += "TYPE FLAGS VIDEO: \t" + getFlagVideo() + "\n"; ret += "TYPE FLAGS AUDIO: \t" + getFlagAudio() + "\n"; ret += "DATA OFFSET: \t\t" + getDataOffset() + "\n"; return ret; } /** * Returns a boolean on whether this data contains audio * * @return boolean true if this FLV header contains audio data, false otherwise */ public boolean getFlagAudio() { return flagAudio; } /** * Sets the audioflag on whether this data contains audio * * @param flagAudio true if this FLV header contains audio data, false otherwise */ public void setFlagAudio(boolean flagAudio) { this.flagAudio = flagAudio; } /** * Sets the type flags on whether this data is audio or video * * @param typeFlags Type flags determining data types (audio or video) */ public void setTypeFlags(byte typeFlags) { flagVideo = (((byte) (((typeFlags << 0x7) >>> 0x7) & 0x01)) > 0x00); flagAudio = (((byte) (((typeFlags << 0x5) >>> 0x7) & 0x01)) > 0x00); } /** * Gets the FlagReserved01 which is a datatype specified in the Flash * Specification * * @return byte Flag reserved, first */ public byte getFlagReserved01() { return flagReserved01; } /** * Sets the FlagReserved01 which is a datatype specified in the Flash * Specification * * @param flagReserved01 Flag reserved, first */ @SuppressWarnings("static-access") public void setFlagReserved01(byte flagReserved01) { this.flagReserved01 = flagReserved01; } /** * Gets the FlagReserved02 which is a datatype specified in the Flash * Specification * * @return byte FlagReserved02 */ public byte getFlagReserved02() { return flagReserved02; } /** * Sets the Flag Reserved02 which is a datatype specified in the Flash * Specification * * @param flagReserved02 FlagReserved02 */ @SuppressWarnings("static-access") public void setFlagReserved02(byte flagReserved02) { this.flagReserved02 = flagReserved02; } /** * Returns a boolean on whether this data contains video * * @return boolean true if this FLV header contains vide data, false otherwise */ public boolean getFlagVideo() { return flagVideo; } /** * Sets the audioflag on whether this data contains audio * * @param type_flags_video true if this FLV header contains video data, false otherwise */ public void setFlagVideo(boolean type_flags_video) { flagVideo = type_flags_video; } /** * Gets the version byte * * @return byte FLV version byte */ public byte getVersion() { return version; } /** * Writes the FLVHeader to IoBuffer. * * @param buffer IoBuffer to write */ public void write(IoBuffer buffer) { // FLV buffer.put(signature); // version buffer.put(version); // flags buffer.put((byte) (FLV_HEADER_FLAG_HAS_AUDIO * (flagAudio ? 1 : 0) + FLV_HEADER_FLAG_HAS_VIDEO * (flagVideo ? 1 : 0))); // data offset buffer.putInt(9); // previous tag size 0 (this is the "first" tag) buffer.putInt(0); buffer.flip(); } public void write(ByteBuffer buffer) { // FLV buffer.put(signature); // version buffer.put(version); // flags buffer.put((byte) (FLV_HEADER_FLAG_HAS_AUDIO * (flagAudio ? 1 : 0) + FLV_HEADER_FLAG_HAS_VIDEO * (flagVideo ? 1 : 0))); // data offset buffer.putInt(9); // previous tag size 0 (this is the "first" tag) buffer.putInt(0); buffer.flip(); } } red5-1.0~svn4374.orig/src/org/red5/io/flv/impl/0000755000175000017500000000000011760512574020677 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/io/flv/impl/FLVMetaData.xsd0000644000175000017500000000200610406413120023424 0ustar drazzibdrazzib Root element red5-1.0~svn4374.orig/src/org/red5/io/flv/impl/FLVService.java0000644000175000017500000000530011706617130023502 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.impl; import java.io.File; import java.io.IOException; import org.red5.io.BaseStreamableFileService; import org.red5.io.IStreamableFile; import org.red5.io.flv.IFLVService; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; /** * A FLVServiceImpl sets up the service and hands out FLV objects to * its callers. * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Paul Gregoire (mondain@gmail.com) */ public class FLVService extends BaseStreamableFileService implements IFLVService { /** * Serializer */ private Serializer serializer; /** * Deserializer */ private Deserializer deserializer; /** * Generate FLV metadata? */ private boolean generateMetadata; /** {@inheritDoc} */ @Override public String getPrefix() { return "flv"; } /** {@inheritDoc} */ @Override public String getExtension() { return ".flv"; } /** * {@inheritDoc} */ public void setSerializer(Serializer serializer) { this.serializer = serializer; } /** {@inheritDoc} */ public void setDeserializer(Deserializer deserializer) { this.deserializer = deserializer; } /** {@inheritDoc} */ @Override public IStreamableFile getStreamableFile(File file) throws IOException { return new FLV(file, generateMetadata); } /** * Generate metadata or not * * @param generate true if there's need to generate metadata, false otherwise */ public void setGenerateMetadata(boolean generate) { generateMetadata = generate; } /** * Getter for serializer * * @return Serializer */ public Serializer getSerializer() { return serializer; } /** * Getter for deserializer * * @return Deserializer */ public Deserializer getDeserializer() { return deserializer; } } red5-1.0~svn4374.orig/src/org/red5/io/flv/impl/FLV.java0000644000175000017500000002045311752471465022201 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.impl; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.ITag; import org.red5.io.ITagReader; import org.red5.io.ITagWriter; import org.red5.io.IoConstants; import org.red5.io.flv.IFLV; import org.red5.io.flv.meta.IMetaData; import org.red5.io.flv.meta.IMetaService; import org.red5.io.flv.meta.MetaData; import org.red5.io.flv.meta.MetaService; import org.red5.server.api.cache.ICacheStore; import org.red5.server.api.cache.ICacheable; import org.red5.server.cache.NoCacheImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A FLVImpl implements the FLV api * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Paul Gregoire (mondain@gmail.com) */ public class FLV implements IFLV { protected static Logger log = LoggerFactory.getLogger(FLV.class); private static ICacheStore cache; private File file; private boolean generateMetadata; private IMetaService metaService; private IMetaData metaData; /* * 0x08 AUDIO Contains an audio packet similar to a SWF SoundStreamBlock plus codec information * 0x09 VIDEO Contains a video packet similar to a SWF VideoFrame plus codec information * 0x12 META Contains two AMF packets, the name of the event and the data to go with it * * soundType (byte & 0x01) == 0 0: mono, 1: stereo * soundSize (byte & 0x02) == 1 0: 8-bit, 2: 16-bit * soundRate (byte & 0x0C) == 2 0: 5.5kHz, 1: 11kHz, 2: 22kHz, 3: 44kHz * soundFormat (byte & 0xf0) == 4 0: Uncompressed, 1: ADPCM, 2: MP3, 5: Nellymoser 8kHz mono, 6: Nellymoser * * codecID (byte & 0x0f) == 0 2: Sorensen H.263, 3: Screen video, 4: On2 VP6 * frameType (byte & 0xf0) == 4 1: keyframe, 2: inter frame, 3: disposable inter frame * * http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v10.pdf */ /** * Default constructor, used by Spring so that parameters may be injected. */ public FLV() { } /** * Create FLV from given file source * * @param file File source */ public FLV(File file) { this(file, false); } /** * Create FLV from given file source and with specified metadata generation * option * * @param file File source * @param generateMetadata Metadata generation option */ public FLV(File file, boolean generateMetadata) { this.file = file; this.generateMetadata = generateMetadata; int count = 0; if (!generateMetadata) { try { FLVReader reader = new FLVReader(this.file); ITag tag = null; while (reader.hasMoreTags() && (++count < 5)) { tag = reader.readTag(); if (tag.getDataType() == IoConstants.TYPE_METADATA) { if (metaService == null) { metaService = new MetaService(); } metaData = metaService.readMetaData(tag.getBody()); } } reader.close(); } catch (Exception e) { log.error("An error occured looking for metadata", e); } } } /** * Sets the cache implementation to be used. * * @param cache Cache store */ public void setCache(ICacheStore cache) { FLV.cache = cache; } /** * {@inheritDoc} */ public boolean hasMetaData() { return metaData != null; } /** * {@inheritDoc} */ @SuppressWarnings({ "rawtypes" }) public IMetaData getMetaData() throws FileNotFoundException { metaService.setFile(file); return null; } /** * {@inheritDoc} */ public boolean hasKeyFrameData() { // if (hasMetaData()) { // return !((MetaData) metaData).getKeyframes().isEmpty(); // } return false; } /** * {@inheritDoc} */ @SuppressWarnings({ "rawtypes", "unchecked" }) public void setKeyFrameData(Map keyframedata) { if (!hasMetaData()) { metaData = new MetaData(); } //The map is expected to contain two entries named "times" and "filepositions", //both of which contain a map keyed by index and time or position values. Map times = new HashMap(); Map filepositions = new HashMap(); // if (keyframedata.containsKey("times")) { Map inTimes = (Map) keyframedata.get("times"); for (Object o : inTimes.entrySet()) { Map.Entry entry = (Map.Entry) o; times.put(entry.getKey(), entry.getValue()); } } ((MetaData) metaData).put("times", times); // if (keyframedata.containsKey("filepositions")) { Map inPos = (Map) keyframedata.get("filepositions"); for (Object o : inPos.entrySet()) { Map.Entry entry = (Map.Entry) o; filepositions.put(entry.getKey(), entry.getValue()); } } ((MetaData) metaData).put("filepositions", filepositions); } /** * {@inheritDoc} */ @SuppressWarnings({ "rawtypes" }) public Map getKeyFrameData() { Map keyframes = null; // if (hasMetaData()) { // keyframes = ((MetaData) metaData).getKeyframes(); // } return keyframes; } /** * {@inheritDoc} */ public void refreshHeaders() throws IOException { } /** * {@inheritDoc} */ public void flushHeaders() throws IOException { } /** * {@inheritDoc} */ public ITagReader getReader() throws IOException { FLVReader reader = null; IoBuffer fileData; String fileName = file.getName(); // if no cache is set an NPE will be thrown if (cache == null) { log.info("FLV cache is null, forcing NoCacheImpl instance"); cache = NoCacheImpl.getInstance(); } ICacheable ic = cache.get(fileName); // look in the cache before reading the file from the disk if (null == ic || (null == ic.getByteBuffer())) { if (file.exists()) { log.debug("File size: {}", file.length()); reader = new FLVReader(file, generateMetadata); // get a ref to the mapped byte buffer fileData = reader.getFileData(); // offer the uncached file to the cache if (fileData != null && cache.offer(fileName, fileData)) { log.debug("Item accepted by the cache: {}", fileName); } else { log.debug("Item will not be cached: {}", fileName); } } else { log.info("Creating new file: {}", file); file.createNewFile(); } } else { fileData = IoBuffer.wrap(ic.getBytes()); reader = new FLVReader(fileData, generateMetadata); } return reader; } /** * {@inheritDoc} */ public ITagReader readerFromNearestKeyFrame(int seekPoint) { return null; } /** * {@inheritDoc} */ public ITagWriter getWriter() throws IOException { if (file.exists()) { file.delete(); } file.createNewFile(); ITagWriter writer = new FLVWriter(file, false); return writer; } /** {@inheritDoc} */ public ITagWriter getAppendWriter() throws IOException { // If the file doesn't exist, we can't append to it, so return a writer if (!file.exists()) { log.info("File does not exist, calling writer. This will create a new file."); return getWriter(); } //Fix by Mhodgson: FLVWriter constructor allows for passing of file object ITagWriter writer = new FLVWriter(file, true); return writer; } /** * {@inheritDoc} */ public ITagWriter writerFromNearestKeyFrame(int seekPoint) { return null; } /** {@inheritDoc} */ @SuppressWarnings({ "rawtypes" }) public void setMetaData(IMetaData meta) throws IOException { if (metaService == null) { metaService = new MetaService(file); } //if the file is not checked the write may produce an NPE if (metaService.getFile() == null) { metaService.setFile(file); } metaService.write(meta); metaData = meta; } /** {@inheritDoc} */ public void setMetaService(IMetaService service) { metaService = service; } } red5-1.0~svn4374.orig/src/org/red5/io/flv/impl/FLVWriter.java0000644000175000017500000004345011747635016023376 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.impl; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Semaphore; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.IStreamableFile; import org.red5.io.ITag; import org.red5.io.ITagReader; import org.red5.io.ITagWriter; import org.red5.io.amf.Input; import org.red5.io.amf.Output; import org.red5.io.flv.FLVHeader; import org.red5.io.flv.IFLV; import org.red5.io.object.Serializer; import org.red5.io.utils.IOUtils; import org.red5.server.api.Red5; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A Writer is used to write the contents of a FLV file * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Tiago Jacobs (tiago@imdt.com.br) * @author Paul Gregoire (mondain@gmail.com) */ public class FLVWriter implements ITagWriter { private static Logger log = LoggerFactory.getLogger(FLVWriter.class); /** * Length of the flv header in bytes */ private final static int HEADER_LENGTH = 9; /** * Length of the flv tag in bytes */ private final static int TAG_HEADER_LENGTH = 11; /** * Position of the meta data tag in our file. */ private final static int META_POSITION = 13; /** * For now all recorded streams carry a stream id of 0. */ private final static byte[] DEFAULT_STREAM_ID = new byte[] { (byte) (0 & 0xff), (byte) (0 & 0xff), (byte) (0 & 0xff) }; /** * FLV object */ private IFLV flv; /** * Number of bytes written */ private volatile long bytesWritten; /** * Position in file */ private int offset; /** * Position in file */ private int timeOffset; /** * Id of the video codec used. */ private volatile int videoCodecId = -1; /** * Id of the audio codec used. */ private volatile int audioCodecId = -1; /** * Sampling rate */ private volatile int soundRate; /** * Size of each audio sample */ private volatile int soundSize; /** * Mono (0) or stereo (1) sound */ private volatile boolean soundType; /** * Are we appending to an existing file? */ private boolean append; /** * Duration of the file. */ private int duration; /** * Size of video data */ private int videoDataSize = 0; /** * Size of audio data */ private int audioDataSize = 0; /** * Flv file. */ private RandomAccessFile file; /** * File to which stream data is stored without an flv header or metadata. */ private RandomAccessFile dataFile; private Map metaTags = new HashMap(); // path to the original file passed to the writer private String filePath; private final Semaphore lock = new Semaphore(1, true); /** * Creates writer implementation with given file and last tag * * FLV.java uses this constructor so we have access to the file object * * @param file File output stream * @param append true if append to existing file */ public FLVWriter(File file, boolean append) { filePath = file.getAbsolutePath(); log.debug("Writing to: {}", filePath); try { this.append = append; if (append) { // if we are appending get the last tags timestamp to use as offset timeOffset = FLVReader.getDuration(file); // set duration to last timestamp value duration = timeOffset; log.debug("Duration: {}", timeOffset); // grab the file we will append to this.dataFile = new RandomAccessFile(file, "rws"); if (!file.exists() || !file.canRead() || !file.canWrite()) { log.warn("File does not exist or cannot be accessed"); } else { log.trace("File size: {} last modified: {}", file.length(), file.lastModified()); // update the bytes written so we write to the correct starting position bytesWritten = file.length(); } // if duration is 0 then we probably have larger issues with this file if (duration == 0) { // seek to where metadata would normally start dataFile.seek(META_POSITION); } } else { // temporary data file for storage of stream data File dat = new File(filePath + ".ser"); if (dat.exists()) { dat.delete(); dat.createNewFile(); } this.dataFile = new RandomAccessFile(dat, "rws"); // the final version of the file will go here this.file = new RandomAccessFile(file, "rws"); } } catch (Exception e) { log.error("Failed to create FLV writer", e); } } /** * Writes the header bytes * * @throws IOException Any I/O exception */ public void writeHeader() throws IOException { FLVHeader flvHeader = new FLVHeader(); flvHeader.setFlagAudio(audioCodecId != -1 ? true : false); flvHeader.setFlagVideo(videoCodecId != -1 ? true : false); // create a buffer ByteBuffer header = ByteBuffer.allocate(HEADER_LENGTH + 4); // FLVHeader (9 bytes) + PreviousTagSize0 (4 bytes) flvHeader.write(header); // write header to output channel file.setLength(HEADER_LENGTH + 4); if (header.hasArray()) { log.debug("Header bytebuffer has a backing array"); file.write(header.array()); } else { log.debug("Header bytebuffer does not have a backing array"); byte[] tmp = new byte[HEADER_LENGTH + 4]; header.get(tmp); file.write(tmp); } bytesWritten = file.length(); assert ((HEADER_LENGTH + 4) - bytesWritten == 0); log.debug("Header size: {} bytes written: {}", (HEADER_LENGTH + 4), bytesWritten); header.clear(); header = null; } /** * {@inheritDoc} */ public boolean writeTag(ITag tag) throws IOException { try { lock.acquire(); /* * Tag header = 11 bytes * |-|---|----|---| * 0 = type * 1-3 = data size * 4-7 = timestamp * 8-10 = stream id (always 0) * Tag data = variable bytes * Previous tag = 4 bytes (tag header size + tag data size) */ log.trace("writeTag: {}", tag); long prevBytesWritten = bytesWritten; log.trace("Previous bytes written: {}", prevBytesWritten); // skip tags with no data int bodySize = tag.getBodySize(); log.debug("Tag body size: {}", bodySize); // ensure that the channel is still open if (dataFile != null) { log.debug("Current file position: {}", dataFile.getChannel().position()); // get the data type byte dataType = tag.getDataType(); // if we're writing non-meta tags do seeking and tag size update if (dataType != ITag.TYPE_METADATA) { // get the current file offset long fileOffset = dataFile.getFilePointer(); log.debug("Current file offset: {} expected offset: {}", fileOffset, prevBytesWritten); if (fileOffset < prevBytesWritten) { log.debug("Seeking to expected offset"); // it's necessary to seek to the length of the file // so that we can append new tags dataFile.seek(prevBytesWritten); log.debug("New file position: {}", dataFile.getChannel().position()); } } else { tag.getBody().mark(); String metaType = Input.getString(tag.getBody()); log.debug("Metadata tag type: {}", metaType); tag.getBody().reset(); if (!"onCuePoint".equals(metaType)) { // store any incoming onMetaData tags until we close the file, allow onCuePoint tags to continue metaTags.put(System.currentTimeMillis(), tag); return true; } } // set a var holding the entire tag size including the previous tag length int totalTagSize = TAG_HEADER_LENGTH + bodySize + 4; // resize dataFile.setLength(dataFile.length() + totalTagSize); // create a buffer for this tag ByteBuffer tagBuffer = ByteBuffer.allocate(totalTagSize); // get the timestamp int timestamp = tag.getTimestamp() + timeOffset; // allow for empty tag bodies byte[] bodyBuf = null; if (bodySize > 0) { // create an array big enough bodyBuf = new byte[bodySize]; // put the bytes into the array tag.getBody().get(bodyBuf); // get the audio or video codec identifier if (dataType == ITag.TYPE_AUDIO) { audioDataSize += bodySize; if (audioCodecId == -1) { int id = bodyBuf[0] & 0xff; // must be unsigned audioCodecId = (id & ITag.MASK_SOUND_FORMAT) >> 4; log.debug("Audio codec id: {}", audioCodecId); switch ((id & ITag.MASK_SOUND_RATE) >> 2) { case ITag.FLAG_RATE_5_5_KHZ: soundRate = 5500; break; case ITag.FLAG_RATE_11_KHZ: soundRate = 11000; break; case ITag.FLAG_RATE_22_KHZ: soundRate = 22000; break; case ITag.FLAG_RATE_44_KHZ: soundRate = 44000; break; } log.debug("Sound rate: {}", soundRate); switch ((id & ITag.MASK_SOUND_SIZE) >> 1) { case ITag.FLAG_SIZE_8_BIT: soundSize = 8; break; case ITag.FLAG_SIZE_16_BIT: soundSize = 16; break; } log.debug("Sound size: {}", soundSize); soundType = (id & ITag.MASK_SOUND_TYPE) > 0; log.debug("Sound type: {}", soundType); } } else if (dataType == ITag.TYPE_VIDEO) { videoDataSize += bodySize; if (videoCodecId == -1) { int id = bodyBuf[0] & 0xff; // must be unsigned videoCodecId = id & ITag.MASK_VIDEO_CODEC; log.debug("Video codec id: {}", videoCodecId); } } } // Data Type IOUtils.writeUnsignedByte(tagBuffer, dataType); //1 // Body Size - Length of the message. Number of bytes after StreamID to end of tag // (Equal to length of the tag - 11) IOUtils.writeMediumInt(tagBuffer, bodySize); //3 // Timestamp IOUtils.writeExtendedMediumInt(tagBuffer, timestamp); //4 // Stream id tagBuffer.put(DEFAULT_STREAM_ID); //3 log.trace("Tag buffer (after tag header) limit: {} remaining: {}", tagBuffer.limit(), tagBuffer.remaining()); // get the body if we have one if (bodyBuf != null) { tagBuffer.put(bodyBuf); log.trace("Tag buffer (after body) limit: {} remaining: {}", tagBuffer.limit(), tagBuffer.remaining()); } // we add the tag size tagBuffer.putInt(TAG_HEADER_LENGTH + bodySize); log.trace("Tag buffer (after prev tag size) limit: {} remaining: {}", tagBuffer.limit(), tagBuffer.remaining()); // flip so we can process from the beginning tagBuffer.flip(); if (log.isDebugEnabled()) { //StringBuilder sb = new StringBuilder(); //HexDump.dumpHex(sb, tagBuffer.array()); //log.debug("\n{}", sb); } // write the tag dataFile.write(tagBuffer.array()); bytesWritten = dataFile.length(); log.trace("Tag written, check value: {} (should be 0)", (bytesWritten - prevBytesWritten) - totalTagSize); tagBuffer.clear(); // update the duration duration = Math.max(duration, timestamp); log.debug("Writer duration: {}", duration); // validate written amount if ((bytesWritten - prevBytesWritten) != totalTagSize) { log.debug("Not all of the bytes appear to have been written, prev-current: {}", (bytesWritten - prevBytesWritten)); } return true; } else { // throw an exception and let them know the cause throw new IOException("FLV write channel has been closed", new ClosedChannelException()); } } catch (InterruptedException e) { log.warn("Exception acquiring lock", e); } finally { lock.release(); } return false; } /** {@inheritDoc} */ public boolean writeTag(byte type, IoBuffer data) throws IOException { return false; } /** {@inheritDoc} */ public boolean writeStream(byte[] b) { try { dataFile.write(b); return true; } catch (IOException e) { log.error("", e); } return false; } /** * Write "onMetaData" tag to the file. * * @param duration Duration to write in milliseconds. * @param videoCodecId Id of the video codec used while recording. * @param audioCodecId Id of the audio codec used while recording. * @throws IOException if the tag could not be written */ private void writeMetadataTag(double duration, int videoCodecId, int audioCodecId) throws IOException { log.debug("writeMetadataTag - duration: {} video codec: {} audio codec: {}", new Object[] { duration, videoCodecId, audioCodecId }); IoBuffer buf = IoBuffer.allocate(1024); buf.setAutoExpand(true); Output out = new Output(buf); out.writeString("onMetaData"); Map params = new HashMap(); params.put("server", Red5.getVersion().replaceAll("\\$", "").trim()); params.put("creationdate", GregorianCalendar.getInstance().getTime().toString()); params.put("duration", (Number) duration); if (videoCodecId != -1) { params.put("videocodecid", videoCodecId); params.put("videodatarate", 8 * videoDataSize / 1024 / duration); //from bytes to kilobits } else { // place holder params.put("novideocodec", 0); } if (audioCodecId != -1) { params.put("audiocodecid", audioCodecId); params.put("audiosamplerate", soundRate); params.put("audiosamplesize", soundSize); params.put("stereo", soundType); params.put("audiodatarate", 8 * audioDataSize / 1024 / duration); //from bytes to kilobits } else { // place holder params.put("noaudiocodec", 0); } // this is actual only supposed to be true if the last video frame is a keyframe params.put("canSeekToEnd", true); out.writeMap(params, new Serializer()); buf.flip(); int bodySize = buf.limit(); log.debug("Metadata size: {}", bodySize); // set a var holding the entire tag size including the previous tag length int totalTagSize = TAG_HEADER_LENGTH + bodySize + 4; // resize file.setLength(file.length() + totalTagSize); // create a buffer for this tag ByteBuffer tagBuffer = ByteBuffer.allocate(totalTagSize); // get the timestamp int timestamp = 0; // create an array big enough byte[] bodyBuf = new byte[bodySize]; // put the bytes into the array buf.get(bodyBuf); // Data Type IOUtils.writeUnsignedByte(tagBuffer, ITag.TYPE_METADATA); //1 // Body Size - Length of the message. Number of bytes after StreamID to end of tag // (Equal to length of the tag - 11) IOUtils.writeMediumInt(tagBuffer, bodySize); //3 // Timestamp IOUtils.writeExtendedMediumInt(tagBuffer, timestamp); //4 // Stream id tagBuffer.put(DEFAULT_STREAM_ID); //3 log.trace("Tag buffer (after tag header) limit: {} remaining: {}", tagBuffer.limit(), tagBuffer.remaining()); // get the body tagBuffer.put(bodyBuf); log.trace("Tag buffer (after body) limit: {} remaining: {}", tagBuffer.limit(), tagBuffer.remaining()); // we add the tag size tagBuffer.putInt(TAG_HEADER_LENGTH + bodySize); log.trace("Tag buffer (after prev tag size) limit: {} remaining: {}", tagBuffer.limit(), tagBuffer.remaining()); // flip so we can process from the beginning tagBuffer.flip(); // write the tag file.write(tagBuffer.array()); bytesWritten = file.length(); tagBuffer.clear(); buf.clear(); } /** * Ends the writing process, then merges the data file with the flv file header and metadata. */ public void close() { log.debug("close"); log.debug("Meta tags: {}", metaTags); try { lock.acquire(); if (!append) { // write the file header writeHeader(); // write the metadata with the final duration writeMetadataTag(duration * 0.001d, videoCodecId, audioCodecId); // set the data file the beginning dataFile.seek(0); file.getChannel().transferFrom(dataFile.getChannel(), bytesWritten, dataFile.length()); } else { // TODO update duration } } catch (IOException e) { log.error("IO error on close", e); } catch (InterruptedException e) { log.warn("Exception acquiring lock", e); } finally { try { if (dataFile != null) { // close the file dataFile.close(); //TODO delete the data file File dat = new File(filePath + ".ser"); if (dat.exists()) { dat.delete(); } } } catch (IOException e) { log.error("", e); } try { if (file != null) { // run a test on the flv if debugging is on if (log.isDebugEnabled()) { // debugging try { ITagReader reader = null; if (flv != null) { reader = flv.getReader(); } if (reader == null) { file.seek(0); reader = new FLVReader(file.getChannel()); } log.trace("reader: {}", reader); log.debug("Has more tags: {}", reader.hasMoreTags()); ITag tag = null; while (reader.hasMoreTags()) { tag = reader.readTag(); log.debug("\n{}", tag); } } catch (IOException e) { log.warn("", e); } } // close the file file.close(); } } catch (IOException e) { log.error("", e); } lock.release(); } } /** {@inheritDoc} */ public IStreamableFile getFile() { return flv; } /** * Setter for FLV object * * @param flv FLV source * */ public void setFLV(IFLV flv) { this.flv = flv; } /** * {@inheritDoc} */ public int getOffset() { return offset; } /** * Setter for offset * * @param offset Value to set for offset */ public void setOffset(int offset) { this.offset = offset; } /** * {@inheritDoc} */ public long getBytesWritten() { return bytesWritten; } } red5-1.0~svn4374.orig/src/org/red5/io/flv/impl/FLVReader.java0000644000175000017500000005676211747635016023336 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.impl; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Semaphore; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.BufferType; import org.red5.io.IKeyFrameMetaCache; import org.red5.io.IStreamableFile; import org.red5.io.ITag; import org.red5.io.ITagReader; import org.red5.io.IoConstants; import org.red5.io.amf.Input; import org.red5.io.amf.Output; import org.red5.io.flv.FLVHeader; import org.red5.io.flv.IKeyFrameDataAnalyzer; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; import org.red5.io.utils.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A Reader is used to read the contents of a FLV file. * NOTE: This class is not implemented as threading-safe. The caller * should make sure the threading-safety. * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Paul Gregoire, (mondain@gmail.com) */ public class FLVReader implements IoConstants, ITagReader, IKeyFrameDataAnalyzer { /** * Logger */ private static Logger log = LoggerFactory.getLogger(FLVReader.class); /** * File */ private File file; /** * File input stream */ private FileInputStream fis; /** * File channel */ private FileChannel channel; private long channelSize; /** * Keyframe metadata */ private KeyFrameMeta keyframeMeta; /** * Input byte buffer */ private IoBuffer in; /** Set to true to generate metadata automatically before the first tag. */ private boolean generateMetadata; /** Position of first video tag. */ private long firstVideoTag = -1; /** Position of first audio tag. */ private long firstAudioTag = -1; /** metadata sent flag */ private boolean metadataSent = false; /** Duration in milliseconds. */ private long duration; /** Mapping between file position and timestamp in ms. */ private HashMap posTimeMap; /** Buffer type / style to use **/ private static BufferType bufferType = BufferType.AUTO; private static int bufferSize = 1024; /** Use load buffer */ private boolean useLoadBuf; /** Cache for keyframe informations. */ private static IKeyFrameMetaCache keyframeCache; /** The header of this FLV file. */ private FLVHeader header; private final Semaphore lock = new Semaphore(1, true); /** Constructs a new FLVReader. */ FLVReader() { } /** * Creates FLV reader from file input stream. * * @param f File * @throws IOException on error */ public FLVReader(File f) throws IOException { this(f, false); } /** * Creates FLV reader from file input stream, sets up metadata generation flag. * * @param f File input stream * @param generateMetadata true if metadata generation required, false otherwise * @throws IOException on error */ public FLVReader(File f, boolean generateMetadata) throws IOException { if (null == f) { log.warn("Reader was passed a null file"); log.debug("{}", org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString(this)); } this.file = f; this.fis = new FileInputStream(f); this.generateMetadata = generateMetadata; channel = fis.getChannel(); channelSize = channel.size(); in = null; fillBuffer(); postInitialize(); } /** * Creates FLV reader from file channel. * * @param channel * @throws IOException on error */ public FLVReader(FileChannel channel) throws IOException { if (null == channel) { log.warn("Reader was passed a null channel"); log.debug("{}", org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString(this)); } if (!channel.isOpen()) { log.warn("Reader was passed a closed channel"); return; } this.channel = channel; channelSize = channel.size(); log.debug("Channel size: {}", channelSize); if (channel.position() > 0) { log.debug("Channel position: {}", channel.position()); channel.position(0); } fillBuffer(); postInitialize(); } /** * Accepts mapped file bytes to construct internal members. * * @param generateMetadata true if metadata generation required, false otherwise * @param buffer IoBuffer */ public FLVReader(IoBuffer buffer, boolean generateMetadata) { this.generateMetadata = generateMetadata; in = buffer; postInitialize(); } public void setKeyFrameCache(IKeyFrameMetaCache keyframeCache) { FLVReader.keyframeCache = keyframeCache; } /** * Get the remaining bytes that could be read from a file or ByteBuffer. * * @return Number of remaining bytes */ private long getRemainingBytes() { if (!useLoadBuf) { return in.remaining(); } try { return channelSize - channel.position() + in.remaining(); } catch (Exception e) { log.error("Error getRemainingBytes", e); return 0; } } /** * Get the total readable bytes in a file or ByteBuffer. * * @return Total readable bytes */ public long getTotalBytes() { if (!useLoadBuf) { return in.capacity(); } try { return channelSize; } catch (Exception e) { log.error("Error getTotalBytes", e); return 0; } } /** * Get the current position in a file or ByteBuffer. * * @return Current position in a file */ private long getCurrentPosition() { long pos; if (!useLoadBuf) { return in.position(); } try { if (in != null) { pos = (channel.position() - in.remaining()); } else { pos = channel.position(); } return pos; } catch (Exception e) { log.error("Error getCurrentPosition", e); return 0; } } /** * Modifies current position. * * @param pos Current position in file */ private void setCurrentPosition(long pos) { if (pos == Long.MAX_VALUE) { pos = file.length(); } if (!useLoadBuf) { in.position((int) pos); return; } try { if (pos >= (channel.position() - in.limit()) && pos < channel.position()) { in.position((int) (pos - (channel.position() - in.limit()))); } else { channel.position(pos); fillBuffer(bufferSize, true); } } catch (Exception e) { log.error("Error setCurrentPosition", e); } } /** * Loads whole buffer from file channel, with no reloading (that is, appending). */ private void fillBuffer() { fillBuffer(bufferSize, false); } /** * Loads data from channel to buffer. * * @param amount Amount of data to load with no reloading */ private void fillBuffer(long amount) { fillBuffer(amount, false); } /** * Load enough bytes from channel to buffer. * After the loading process, the caller can make sure the amount * in buffer is of size 'amount' if we haven't reached the end of channel. * * @param amount The amount of bytes in buffer after returning, * no larger than bufferSize * @param reload Whether to reload or append */ private void fillBuffer(long amount, boolean reload) { try { if (amount > bufferSize) { amount = bufferSize; } log.debug("Buffering amount: {} buffer size: {}", amount, bufferSize); // Read all remaining bytes if the requested amount reach the end // of channel. if (channelSize - channel.position() < amount) { amount = channelSize - channel.position(); } if (in == null) { switch (bufferType) { case HEAP: in = IoBuffer.allocate(bufferSize, false); break; case DIRECT: in = IoBuffer.allocate(bufferSize, true); break; default: in = IoBuffer.allocate(bufferSize); } channel.read(in.buf()); in.flip(); useLoadBuf = true; } if (!useLoadBuf) { return; } if (reload || in.remaining() < amount) { if (!reload) { in.compact(); } else { in.clear(); } channel.read(in.buf()); in.flip(); } } catch (Exception e) { log.error("Error fillBuffer", e); } } /** * Post-initialization hook, reads keyframe metadata and decodes header (if any). */ private void postInitialize() { if (log.isDebugEnabled()) { log.debug("FLVReader 1 - Buffer size: {} position: {} remaining: {}", new Object[] { getTotalBytes(), getCurrentPosition(), getRemainingBytes() }); } if (getRemainingBytes() >= 9) { decodeHeader(); } if (file != null) { keyframeMeta = analyzeKeyFrames(); } long old = getCurrentPosition(); log.debug("Position: {}", old); } /** {@inheritDoc} */ public boolean hasVideo() { KeyFrameMeta meta = analyzeKeyFrames(); if (meta == null) { return false; } return (!meta.audioOnly && meta.positions.length > 0); } /** * Getter for buffer type (auto, direct or heap). * * @return Value for property 'bufferType' */ public static String getBufferType() { switch (bufferType) { case AUTO: return "auto"; case DIRECT: return "direct"; case HEAP: return "heap"; default: return null; } } /** * Setter for buffer type. * * @param bufferType Value to set for property 'bufferType' */ public static void setBufferType(String bufferType) { int bufferTypeHash = bufferType.hashCode(); switch (bufferTypeHash) { case 3198444: //heap //Get a heap buffer from buffer pool FLVReader.bufferType = BufferType.HEAP; break; case -1331586071: //direct //Get a direct buffer from buffer pool FLVReader.bufferType = BufferType.DIRECT; break; case 3005871: //auto //Let MINA choose default: FLVReader.bufferType = BufferType.AUTO; } } /** * Getter for buffer size. * * @return Value for property 'bufferSize' */ public static int getBufferSize() { return bufferSize; } /** * Setter for property 'bufferSize'. * * @param bufferSize Value to set for property 'bufferSize' */ public static void setBufferSize(int bufferSize) { // make sure buffer size is no less than 1024 bytes. if (bufferSize < 1024) { bufferSize = 1024; } FLVReader.bufferSize = bufferSize; } /** * Returns the file buffer. * * @return File contents as byte buffer */ public IoBuffer getFileData() { // TODO as of now, return null will disable cache // we need to redesign the cache architecture so that // the cache is layered underneath FLVReader not above it, // thus both tag cache and file cache are feasible. return null; } /** {@inheritDoc} */ public void decodeHeader() { // flv header is 9 bytes fillBuffer(9); header = new FLVHeader(); // skip signature in.skip(4); header.setTypeFlags(in.get()); header.setDataOffset(in.getInt()); if (log.isDebugEnabled()) { log.debug("Header: {}", header.toString()); } } /** {@inheritDoc} */ public IStreamableFile getFile() { // TODO wondering if we need to have a reference return null; } /** {@inheritDoc} */ public int getOffset() { // XXX what's the difference from getBytesRead return 0; } /** {@inheritDoc} */ public long getBytesRead() { // XXX should summarize the total bytes read or // just the current position? return getCurrentPosition(); } /** {@inheritDoc} */ public long getDuration() { return duration; } public int getVideoCodecId() { if (keyframeMeta != null) { return keyframeMeta.videoCodecId; } return -1; } public int getAudioCodecId() { if (keyframeMeta != null) { return keyframeMeta.audioCodecId; } return -1; } /** {@inheritDoc} */ public boolean hasMoreTags() { return getRemainingBytes() > 4; } /** * Create tag for metadata event. * * @return Metadata event tag */ private ITag createFileMeta() { // Create tag for onMetaData event IoBuffer buf = IoBuffer.allocate(192); buf.setAutoExpand(true); Output out = new Output(buf); // Duration property out.writeString("onMetaData"); Map props = new HashMap(); props.put("duration", duration / 1000.0); if (firstVideoTag != -1) { long old = getCurrentPosition(); setCurrentPosition(firstVideoTag); readTagHeader(); fillBuffer(1); byte frametype = in.get(); // Video codec id props.put("videocodecid", frametype & MASK_VIDEO_CODEC); setCurrentPosition(old); } if (firstAudioTag != -1) { long old = getCurrentPosition(); setCurrentPosition(firstAudioTag); readTagHeader(); fillBuffer(1); byte frametype = in.get(); // Audio codec id props.put("audiocodecid", (frametype & MASK_SOUND_FORMAT) >> 4); setCurrentPosition(old); } props.put("canSeekToEnd", true); out.writeMap(props, new Serializer()); buf.flip(); ITag result = new Tag(IoConstants.TYPE_METADATA, 0, buf.limit(), null, 0); result.setBody(buf); // out = null; return result; } /** {@inheritDoc} */ public ITag readTag() { ITag tag = null; try { lock.acquire(); long oldPos = getCurrentPosition(); tag = readTagHeader(); if (tag != null) { boolean isMetaData = tag.getDataType() == TYPE_METADATA; log.debug("readTag, oldPos: {}, tag header: \n{}", oldPos, tag); if (!metadataSent && !isMetaData && generateMetadata) { // Generate initial metadata automatically setCurrentPosition(oldPos); KeyFrameMeta meta = analyzeKeyFrames(); if (meta != null) { return createFileMeta(); } } int bodySize = tag.getBodySize(); IoBuffer body = IoBuffer.allocate(bodySize, false); // XXX Paul: this assists in 'properly' handling damaged FLV files long newPosition = getCurrentPosition() + bodySize; if (newPosition <= getTotalBytes()) { int limit; while (getCurrentPosition() < newPosition) { fillBuffer(newPosition - getCurrentPosition()); if (getCurrentPosition() + in.remaining() > newPosition) { limit = in.limit(); in.limit((int) (newPosition - getCurrentPosition()) + in.position()); body.put(in); in.limit(limit); } else { body.put(in); } } body.flip(); tag.setBody(body); } if (isMetaData) { metadataSent = true; } } else { log.debug("Tag was null"); } } catch (InterruptedException e) { log.warn("Exception acquiring lock", e); } finally { lock.release(); } return tag; } /** {@inheritDoc} */ public void close() { log.debug("Reader close"); if (in != null) { in.free(); in = null; } if (channel != null) { try { channel.close(); fis.close(); } catch (IOException e) { log.error("FLVReader :: close ::>\n", e); } } } /** * Key frames analysis may be used as a utility method so * synchronize it. * * @return Keyframe metadata */ public KeyFrameMeta analyzeKeyFrames() { if (keyframeMeta != null) { return keyframeMeta; } try { lock.acquire(); // check for cached keyframe informations if (keyframeCache != null) { keyframeMeta = keyframeCache.loadKeyFrameMeta(file); if (keyframeMeta != null) { // Keyframe data loaded, create other mappings duration = keyframeMeta.duration; posTimeMap = new HashMap(); for (int i = 0; i < keyframeMeta.positions.length; i++) { posTimeMap.put(keyframeMeta.positions[i], (long) keyframeMeta.timestamps[i]); } return keyframeMeta; } } // create a holder for the metadata keyframeMeta = new KeyFrameMeta(); // Lists of video positions and timestamps List positionList = new ArrayList(); List timestampList = new ArrayList(); // Lists of audio positions and timestamps List audioPositionList = new ArrayList(); List audioTimestampList = new ArrayList(); long origPos = getCurrentPosition(); // point to the first tag setCurrentPosition(9); // number of tags read int totalValidTags = 0; // start off as audio only boolean audioOnly = true; while (hasMoreTags()) { long pos = getCurrentPosition(); // Read tag header and duration ITag tmpTag = this.readTagHeader(); if (tmpTag != null) { totalValidTags++; } else { break; } duration = tmpTag.getTimestamp(); if (tmpTag.getDataType() == IoConstants.TYPE_VIDEO) { if (audioOnly) { audioOnly = false; audioPositionList.clear(); audioTimestampList.clear(); } if (firstVideoTag == -1) { firstVideoTag = pos; } // Grab Frame type fillBuffer(1); byte frametype = in.get(); if (keyframeMeta.videoCodecId == -1) { keyframeMeta.videoCodecId = frametype & MASK_VIDEO_CODEC; } if (((frametype & MASK_VIDEO_FRAMETYPE) >> 4) == FLAG_FRAMETYPE_KEYFRAME) { positionList.add(pos); timestampList.add(tmpTag.getTimestamp()); } } else if (tmpTag.getDataType() == IoConstants.TYPE_AUDIO) { if (firstAudioTag == -1) { firstAudioTag = pos; } // Grab Frame type fillBuffer(1); byte frametype = in.get(); if (keyframeMeta.audioCodecId == -1) { keyframeMeta.audioCodecId = frametype & MASK_SOUND_FORMAT; } if (audioOnly) { audioPositionList.add(pos); audioTimestampList.add(tmpTag.getTimestamp()); } } // XXX Paul: this 'properly' handles damaged FLV files - as far as // duration/size is concerned long newPosition = pos + tmpTag.getBodySize() + 15; // log.debug("---->" + in.remaining() + " limit=" + in.limit() + " // new pos=" + newPosition); if (newPosition >= getTotalBytes()) { log.error("New position exceeds limit"); if (log.isDebugEnabled()) { log.debug("-----"); log.debug("Keyframe analysis"); log.debug(" data type=" + tmpTag.getDataType() + " bodysize=" + tmpTag.getBodySize()); log.debug(" remaining=" + getRemainingBytes() + " limit=" + getTotalBytes() + " new pos=" + newPosition); log.debug(" pos=" + pos); log.debug("-----"); } //XXX Paul: A runtime exception is probably not needed here log.info("New position {} exceeds limit {}", newPosition, getTotalBytes()); //just break from the loop break; } else { setCurrentPosition(newPosition); } } // restore the pos setCurrentPosition(origPos); log.debug("Total valid tags found: {}", totalValidTags); keyframeMeta.duration = duration; posTimeMap = new HashMap(); if (audioOnly) { // The flv only contains audio tags, use their lists // to support pause and seeking positionList = audioPositionList; timestampList = audioTimestampList; } keyframeMeta.audioOnly = audioOnly; keyframeMeta.positions = new long[positionList.size()]; keyframeMeta.timestamps = new int[timestampList.size()]; for (int i = 0; i < keyframeMeta.positions.length; i++) { keyframeMeta.positions[i] = positionList.get(i); keyframeMeta.timestamps[i] = timestampList.get(i); posTimeMap.put((long) positionList.get(i), (long) timestampList.get(i)); } if (keyframeCache != null) { keyframeCache.saveKeyFrameMeta(file, keyframeMeta); } } catch (InterruptedException e) { log.warn("Exception acquiring lock", e); } finally { lock.release(); } return keyframeMeta; } /** * Put the current position to pos. * The caller must ensure the pos is a valid one * (eg. not sit in the middle of a frame). * * @param pos New position in file. Pass Long.MAX_VALUE to seek to end of file. */ public void position(long pos) { setCurrentPosition(pos); } /** * Read only header part of a tag. * * @return Tag header */ private ITag readTagHeader() { // previous tag size (4 bytes) + flv tag header size (11 bytes) fillBuffer(15); // if (log.isDebugEnabled()) { // in.mark(); // StringBuilder sb = new StringBuilder(); // HexDump.dumpHex(sb, in.array()); // log.debug("\n{}", sb); // in.reset(); // } // previous tag's size int previousTagSize = in.getInt(); // start of the flv tag byte dataType = in.get(); // loop counter int i = 0; while (dataType != 8 && dataType != 9 && dataType != 18) { log.debug("Invalid data type detected, reading ahead"); log.debug("Current position: {} limit: {}", in.position(), in.limit()); // only allow 10 loops if (i++ > 10) { return null; } // move ahead and see if we get a valid datatype dataType = in.get(); } int bodySize = IOUtils.readUnsignedMediumInt(in); int timestamp = IOUtils.readExtendedMediumInt(in); if (log.isDebugEnabled()) { int streamId = IOUtils.readUnsignedMediumInt(in); log.debug("Data type: {} timestamp: {} stream id: {} body size: {} previous tag size: {}", new Object[] { dataType, timestamp, streamId, bodySize, previousTagSize }); } else { in.skip(3); } return new Tag(dataType, timestamp, bodySize, null, previousTagSize); } /** * Returns the last tag's timestamp as the files duration. * * @param flvFile * @return duration */ public static int getDuration(File flvFile) { int duration = 0; RandomAccessFile flv = null; try { flv = new RandomAccessFile(flvFile, "r"); long flvLength = Math.max(flvFile.length(), flv.length()); log.debug("File length: {}", flvLength); if (flvLength > 13) { flv.seek(flvLength - 4); int lastTagSize = flv.readInt(); log.debug("Last tag size: {}", lastTagSize); if (lastTagSize > 0 && (lastTagSize < flvLength)) { // jump right to where tag timestamp would be flv.seek(flvLength - lastTagSize); // grab timestamp as a regular int duration = flv.readInt(); // adjust value to match extended timestamp duration = (duration >>> 8) | ((duration & 0x000000ff) << 24); } else { // attempt to read the metadata flv.seek(13); byte tagType = flv.readByte(); if (tagType == ITag.TYPE_METADATA) { ByteBuffer buf = ByteBuffer.allocate(3); flv.getChannel().read(buf); int bodySize = IOUtils.readMediumInt(buf); log.debug("Metadata body size: {}", bodySize); flv.skipBytes(4); // timestamp flv.skipBytes(3); // stream id buf.clear(); buf = ByteBuffer.allocate(bodySize); flv.getChannel().read(buf); // construct the meta IoBuffer ioBuf = IoBuffer.wrap(buf); Input input = new Input(ioBuf); Deserializer deserializer = new Deserializer(); String metaType = deserializer.deserialize(input, String.class); log.debug("Metadata type: {}", metaType); Map meta = deserializer.deserialize(input, Map.class); Object tmp = meta.get("duration"); if (tmp != null) { if (tmp instanceof Double) { duration = ((Double) tmp).intValue(); } else { duration = Integer.valueOf((String) tmp); } } input = null; meta.clear(); meta = null; ioBuf.clear(); ioBuf.free(); ioBuf = null; } } } } catch (IOException e) { log.warn("Exception getting file duration", e); } finally { try { if (flv != null) { flv.close(); } } catch (IOException e) { } flv = null; } return duration; } } red5-1.0~svn4374.orig/src/org/red5/io/flv/impl/FLVMetaData_Template.xml0000644000175000017500000000223610407356401025277 0ustar drazzibdrazzib FLV File One 333333333333 modified time Position1 TimeStamp1 Position2 TimeStamp2 Position3 TimeStamp3 Position4 TimeStamp4 Position5 TimeStamp5 FLV File Two 333333333333333 modified time Position TimeStamp red5-1.0~svn4374.orig/src/org/red5/io/flv/impl/Tag.java0000644000175000017500000001141111706617130022245 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.flv.impl; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.ITag; /** * A Tag represents the contents or payload of a FLV file. * * @see OSFlash (external) * * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class Tag implements ITag { /** * Tag type */ private byte type; /** * Tag data type */ private byte dataType; /** * Timestamp */ private int timestamp; /** * Tag body size */ private int bodySize; /** * Tag body as byte buffer */ private IoBuffer body; /** * Previous tag size */ private int previuosTagSize; /** * Bit flags */ private byte bitflags; /** * TagImpl Constructor * * @param dataType Tag data type * @param timestamp Timestamp * @param bodySize Tag body size * @param body Tag body * @param previousTagSize Previous tag size information */ public Tag(byte dataType, int timestamp, int bodySize, IoBuffer body, int previousTagSize) { this.dataType = dataType; this.timestamp = timestamp; this.bodySize = bodySize; this.body = body; this.previuosTagSize = previousTagSize; } /** Constructs a new Tag. */ public Tag() { } /** * Getter for bit flags * * @return Value for bit flags */ public byte getBitflags() { return bitflags; } /** * Setter for bit flags * * @param bitflags Bit flags */ public void setBitflags(byte bitflags) { this.bitflags = bitflags; } /** * Getter for previous tag size * * @return Value for previous tag size */ public int getPreviuosTagSize() { return previuosTagSize; } /** * Setter for previous tag size * * @param previuosTagSize Value to set for previous tag size */ public void setPreviuosTagSize(int previuosTagSize) { this.previuosTagSize = previuosTagSize; } /** {@inheritDoc} */ public IoBuffer getData() { return null; } /** * Return the body IoBuffer * * @return Tag body */ public IoBuffer getBody() { return body; } /** * Return the size of the body * * @return Tag body size */ public int getBodySize() { return bodySize; } /** * Get the data type * * @return Tag data type */ public byte getDataType() { return dataType; } /** * Return the timestamp * * @return Tag timestamp */ public int getTimestamp() { return timestamp; } /** * Return previous tag size * * @return Previous tag size */ public int getPreviousTagSize() { return previuosTagSize; } /** * Prints out the contents of the tag * * @return Tag contents */ @Override public String toString() { String ret = "Data Type\t=" + dataType + "\n"; ret += "Prev. Tag Size\t=" + previuosTagSize + "\n"; ret += "Body size\t=" + bodySize + "\n"; ret += "timestamp\t=" + timestamp + "\n"; ret += "Body Data\t=" + body + "\n"; return ret; } /** * Getter for tag type * * @return Tag type */ public byte getType() { return type; } /** * Setter for tag type * * @param type Tag type */ public void setType(byte type) { this.type = type; } /** {@inheritDoc} */ public void setBody(IoBuffer body) { this.body = body; } /** {@inheritDoc} */ public void setBodySize(int bodySize) { this.bodySize = bodySize; } /** {@inheritDoc} */ public void setDataType(byte dataType) { this.dataType = dataType; } /** {@inheritDoc} */ public void setTimestamp(int timestamp) { this.timestamp = timestamp; } /** * Setter for tag data. Empty method. */ public void setData() { } /** {@inheritDoc} */ public void setPreviousTagSize(int size) { this.previuosTagSize = size; } } red5-1.0~svn4374.orig/src/org/red5/io/FileKeyFrameMetaCache.java0000644000175000017500000001375711706617130024057 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.XMLSerializer; import org.red5.io.flv.IKeyFrameDataAnalyzer.KeyFrameMeta; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * File-based keyframe metadata cache. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ @SuppressWarnings("deprecation") public class FileKeyFrameMetaCache implements IKeyFrameMetaCache { /** * Logger */ private static Logger log = LoggerFactory.getLogger(FileKeyFrameMetaCache.class); /** {@inheritDoc} */ public KeyFrameMeta loadKeyFrameMeta(File file) { String filename = file.getAbsolutePath() + ".meta"; File metadataFile = new File(filename); if (!metadataFile.exists()) { // No such metadata return null; } Document dom; DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { // Using factory get an instance of document builder DocumentBuilder db = dbf.newDocumentBuilder(); // parse using builder to get DOM representation of the XML file dom = db.parse(filename); db.reset(); } catch (ParserConfigurationException pce) { log.error("Could not parse XML file.", pce); return null; } catch (SAXException se) { log.error("Could not parse XML file.", se); return null; } catch (IOException ioe) { log.error("Could not parse XML file.", ioe); return null; } Element root = dom.getDocumentElement(); // Check if .xml file is valid and for this .flv file if (!"FrameMetadata".equals(root.getNodeName())) { // Invalid XML return null; } String modified = root.getAttribute("modified"); if (modified == null || !modified.equals(String.valueOf(file.lastModified()))) { // File has changed in the meantime return null; } if (!root.hasAttribute("duration")) { // Old file without duration informations return null; } if (!root.hasAttribute("audioOnly")) { // Old file without audio/video informations return null; } XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); NodeList keyFrames; try { XPathExpression xexpr = xpath.compile("/FrameMetadata/KeyFrame"); keyFrames = (NodeList) xexpr.evaluate(dom, XPathConstants.NODESET); } catch (XPathExpressionException err) { log.error("could not compile xpath expression", err); return null; } int length = keyFrames.getLength(); if (keyFrames == null || length == 0) { // File doesn't contain informations about keyframes return null; } KeyFrameMeta result = new KeyFrameMeta(); result.duration = Long.parseLong(root.getAttribute("duration")); result.positions = new long[length]; result.timestamps = new int[length]; for (int i=0; i attributeNames; /** * Create new information about a class. * * @param className class name * @param type type * @param attributeNames attributes */ public ClassReference(String className, int type, List attributeNames) { log.debug("Pending property - className: {} type: {} attributeNames: {}", new Object[] { className, type, attributeNames }); this.className = className; this.type = type; this.attributeNames = attributeNames; } } /** * Dummy class that is stored as reference for objects currently * being deserialized that reference themselves. */ protected static class PendingObject { public PendingObject() { log.debug("PendingObject"); } static final class PendingProperty { Object obj; Class klass; String name; PendingProperty(Object obj, Class klass, String name) { log.debug("Pending property - obj: {} class: {} name: {}", new Object[] { obj, klass, name }); this.obj = obj; this.klass = klass; this.name = name; } } private List properties; public void addPendingProperty(Object obj, Class klass, String name) { if (properties == null) { properties = new ArrayList(); } properties.add(new PendingProperty(obj, klass, name)); } public void resolveProperties(Object result) { if (properties != null) { for (PendingProperty prop : properties) { try { prop.klass.getField(prop.name).set(prop.obj, result); } catch (Exception e) { try { BeanUtils.setProperty(prop.obj, prop.name, result); } catch (Exception ex) { log.error("Error mapping property: {} ({})", prop.name, result); } } } properties.clear(); } else { // No pending properties return; } } } /** * Class used to collect AMF3 references. * In AMF3 references should be collected through the whole "body" (across several Input objects). */ public static class RefStorage { // informations about previously deserialized classes private List classReferences = new ArrayList(); // list of string values found in the input stream private List stringReferences = new ArrayList(); private Map refMap = new HashMap(4); } /** * Logger */ protected static Logger log = LoggerFactory.getLogger(Input.class); /** * Set to a value above 0 to enforce AMF3 decoding mode. */ private int amf3_mode; /** * Stores references declared in this input of previous ones in the same message body */ private RefStorage refStorage; /** * Creates Input object for AMF3 from byte buffer * * @param buf Byte buffer */ public Input(IoBuffer buf) { super(buf); amf3_mode = 0; refStorage = new RefStorage(); } /** * Creates Input object for AMF3 from byte buffer and initializes references * from passed RefStorage * @param buf buffer * @param refStorage ref storage */ public Input(IoBuffer buf, RefStorage refStorage) { super(buf); this.refStorage = refStorage; this.refMap = refStorage.refMap; amf3_mode = 0; } /** * Force using AMF3 everywhere */ public void enforceAMF3() { amf3_mode++; } /** * Provide access to raw data. * * @return IoBuffer */ protected IoBuffer getBuffer() { return buf; } /** * Reads the data type * * @return byte Data type */ @Override public byte readDataType() { log.trace("readDataType"); byte coreType = AMF3.TYPE_UNDEFINED; if (buf != null) { currentDataType = buf.get(); log.debug("Current data type: {}", currentDataType); if (currentDataType == AMF.TYPE_AMF3_OBJECT) { currentDataType = buf.get(); } else if (amf3_mode == 0) { // AMF0 object return readDataType(currentDataType); } log.debug("Current data type (after amf checks): {}", currentDataType); switch (currentDataType) { case AMF3.TYPE_UNDEFINED: case AMF3.TYPE_NULL: coreType = DataTypes.CORE_NULL; break; case AMF3.TYPE_INTEGER: case AMF3.TYPE_NUMBER: coreType = DataTypes.CORE_NUMBER; break; case AMF3.TYPE_BOOLEAN_TRUE: case AMF3.TYPE_BOOLEAN_FALSE: coreType = DataTypes.CORE_BOOLEAN; break; case AMF3.TYPE_STRING: coreType = DataTypes.CORE_STRING; break; // TODO check XML_SPECIAL case AMF3.TYPE_XML: case AMF3.TYPE_XML_DOCUMENT: coreType = DataTypes.CORE_XML; break; case AMF3.TYPE_OBJECT: coreType = DataTypes.CORE_OBJECT; break; case AMF3.TYPE_ARRAY: // should we map this to list or array? coreType = DataTypes.CORE_ARRAY; break; case AMF3.TYPE_DATE: coreType = DataTypes.CORE_DATE; break; case AMF3.TYPE_BYTEARRAY: coreType = DataTypes.CORE_BYTEARRAY; break; case AMF3.TYPE_VECTOR_INT: coreType = DataTypes.CORE_VECTOR_INT; break; case AMF3.TYPE_VECTOR_UINT: coreType = DataTypes.CORE_VECTOR_UINT; break; case AMF3.TYPE_VECTOR_NUMBER: coreType = DataTypes.CORE_VECTOR_NUMBER; break; case AMF3.TYPE_VECTOR_OBJECT: coreType = DataTypes.CORE_VECTOR_OBJECT; break; default: log.info("Unknown datatype: {}", currentDataType); // End of object, and anything else lets just skip coreType = DataTypes.CORE_SKIP; break; } log.debug("Core type: {}", coreType); } else { log.error("Why is buf null?"); } return coreType; } /** * Reads a null (value) * * @return Object null */ @Override public Object readNull(Type target) { return null; } /** * Reads a boolean * * @return boolean Boolean value */ @Override public Boolean readBoolean(Type target) { return (currentDataType == AMF3.TYPE_BOOLEAN_TRUE) ? Boolean.TRUE : Boolean.FALSE; } /** * Reads a Number * * @return Number Number */ @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public Number readNumber(Type target) { log.debug("readNumber - target: {}", target); Number v; if (currentDataType == AMF3.TYPE_NUMBER) { v = buf.getDouble(); } else { // we are decoding an int v = readAMF3Integer(); } log.debug("readNumber - value: {}", v); if (target instanceof Class && Number.class.isAssignableFrom((Class) target)) { Class cls = (Class) target; if (!cls.isAssignableFrom(v.getClass())) { String value = v.toString(); log.debug("readNumber - value class: {} str: {}", v.getClass(), value); if (value.indexOf(".") > 0) { if (Float.class == v.getClass()) { v = (Number) convertUtilsBean.convert(value, Float.class); } else { v = (Number) convertUtilsBean.convert(value, Double.class); } } else { v = (Number) convertUtilsBean.convert(value, cls); } } } return v; } /** * Reads a string * * @return String String */ @Override public String readString(Type target) { int len = readAMF3Integer(); log.debug("readString - length: {}", len); // get the length of the string (0x03 = 1, 0x05 = 2, 0x07 = 3 etc..) // 0x01 is special and it means "empty" if (len == 1) { // Empty string return ""; } if ((len & 1) == 0) { //if the refs are empty an IndexOutOfBoundsEx will be thrown if (refStorage.stringReferences.isEmpty()) { log.debug("String reference list is empty"); } // Reference return refStorage.stringReferences.get(len >> 1); } len >>= 1; log.debug("readString - new length: {}", len); int limit = buf.limit(); log.debug("readString - limit: {}", limit); final ByteBuffer strBuf = buf.buf(); strBuf.limit(strBuf.position() + len); final String string = AMF.CHARSET.decode(strBuf).toString(); log.debug("String: {}", string); buf.limit(limit); // reset the limit refStorage.stringReferences.add(string); return string; } /** * Reads a string of a set length. This does not use * the string reference table. * * @param length the length of the string * @return String */ public String readString(int length) { log.debug("readString - length: {}", length); int limit = buf.limit(); final ByteBuffer strBuf = buf.buf(); strBuf.limit(strBuf.position() + length); final String string = AMF.CHARSET.decode(strBuf).toString(); log.debug("String: {}", string); buf.limit(limit); //check for null termination byte b = buf.get(); if (b != 0) { buf.position(buf.position() - 1); } return string; } public RefStorage getRefStorage() { return refStorage; } public String getString() { return readString(String.class); } /** * Returns a date * * @return Date Date object */ @Override public Date readDate(Type target) { int ref = readAMF3Integer(); if ((ref & 1) == 0) { // Reference to previously found date return (Date) getReference(ref >> 1); } long ms = (long) buf.getDouble(); Date date = new Date(ms); storeReference(date); return date; } // Array /** * Returns an array * * @return int Length of array */ @SuppressWarnings({ "unchecked", "rawtypes" }) public Object readArray(Deserializer deserializer, Type target) { int count = readAMF3Integer(); log.debug("Count: {} and {} ref {}", new Object[] { count, (count & 1), (count >> 1) }); if ((count & 1) == 0) { //Reference Object ref = getReference(count >> 1); if (ref != null) { return ref; } } count = (count >> 1); String key = readString(String.class); amf3_mode += 1; Object result; if (key.equals("")) { Class nested = Object.class; Class collection = Collection.class; Collection resultCollection; if (target instanceof ParameterizedType) { ParameterizedType t = (ParameterizedType) target; Type[] actualTypeArguments = t.getActualTypeArguments(); if (actualTypeArguments.length == 1) { nested = (Class) actualTypeArguments[0]; } target = t.getRawType(); } if (target instanceof Class) { collection = (Class) target; } if (collection.isArray()) { nested = ArrayUtils.getGenericType(collection.getComponentType()); result = Array.newInstance(nested, count); storeReference(result); for (int i = 0; i < count; i++) { final Object value = deserializer.deserialize(this, nested); Array.set(result, i, value); } } else { if (SortedSet.class.isAssignableFrom(collection)) { resultCollection = new TreeSet(); } else if (Set.class.isAssignableFrom(collection)) { resultCollection = new HashSet(count); } else { resultCollection = new ArrayList(count); } result = resultCollection; storeReference(result); for (int i = 0; i < count; i++) { final Object value = deserializer.deserialize(this, nested); resultCollection.add(value); } } } else { Class k = Object.class; Class v = Object.class; Class collection = Collection.class; if (target instanceof ParameterizedType) { ParameterizedType t = (ParameterizedType) target; Type[] actualTypeArguments = t.getActualTypeArguments(); if (actualTypeArguments.length == 2) { k = (Class) actualTypeArguments[0]; v = (Class) actualTypeArguments[1]; } target = t.getRawType(); } if (target instanceof Class) { collection = (Class) target; } if (SortedMap.class.isAssignableFrom(collection)) { collection = TreeMap.class; } else { collection = HashMap.class; } Map resultMap; try { resultMap = (Map) collection.newInstance(); } catch (Exception e) { resultMap = new HashMap(count); } // associative array storeReference(resultMap); while (!key.equals("")) { final Object value = deserializer.deserialize(this, v); resultMap.put(key, value); key = readString(k); } for (int i = 0; i < count; i++) { final Object value = deserializer.deserialize(this, v); resultMap.put(i, value); } result = resultMap; } amf3_mode -= 1; return result; } public Object readMap(Deserializer deserializer, Type target) { throw new RuntimeException("AMF3 doesn't support maps."); } @SuppressWarnings({ "unchecked", "rawtypes", "serial" }) public Object readObject(Deserializer deserializer, Type target) { int type = readAMF3Integer(); log.debug("Type: {} and {} ref {}", new Object[] { type, (type & 1), (type >> 1) }); if ((type & 1) == 0) { //Reference Object ref = getReference(type >> 1); if (ref != null) { return ref; } byte b = buf.get(); if (b == 7) { log.debug("BEL: {}", b); //7 } else { log.debug("Non-BEL byte: {}", b); log.debug("Extra byte: {}", buf.get()); } } type >>= 1; List attributes = null; String className; Object result = null; boolean inlineClass = (type & 1) == 1; log.debug("Class is in-line? {}", inlineClass); if (!inlineClass) { ClassReference info = refStorage.classReferences.get(type >> 1); className = info.className; attributes = info.attributeNames; type = info.type; if (attributes != null) { type |= attributes.size() << 2; } } else { type >>= 1; className = readString(String.class); log.debug("Type: {} classname: {}", type, className); //check for flex class alias since these wont be detected as externalizable if (classAliases.containsKey(className)) { //make sure type is externalizable type = 1; } else if (className.startsWith("flex")) { //set the attributes for messaging classes if (className.endsWith("CommandMessage")) { attributes = new LinkedList() { { add("timestamp"); add("headers"); add("operation"); add("body"); add("correlationId"); add("messageId"); add("timeToLive"); add("clientId"); add("destination"); } }; } else { log.debug("Attributes for {} were not set", className); } } } amf3_mode += 1; Object instance = newInstance(className); Map properties = null; PendingObject pending = new PendingObject(); int tempRefId = storeReference(pending); log.debug("Object type: {}", (type & 0x03)); switch (type & 0x03) { case AMF3.TYPE_OBJECT_PROPERTY: log.debug("Detected: Object property type"); // Load object properties into map int count = type >> 2; log.debug("Count: {}", count); if (attributes == null) { attributes = new ArrayList(count); for (int i = 0; i < count; i++) { attributes.add(readString(String.class)); } refStorage.classReferences.add(new ClassReference(className, AMF3.TYPE_OBJECT_PROPERTY, attributes)); } properties = new ObjectMap(); for (int i = 0; i < count; i++) { String name = attributes.get(i); properties.put(name, deserializer.deserialize(this, getPropertyType(instance, name))); } break; case AMF3.TYPE_OBJECT_EXTERNALIZABLE: log.debug("Detected: Externalizable type"); // Use custom class to deserialize the object if ("".equals(className)) { throw new RuntimeException("Classname is required to load an Externalizable object"); } log.debug("Externalizable class: {}", className); if (className.length() == 3) { //check for special DS class aliases className = classAliases.get(className); } result = newInstance(className); if (result == null) { throw new RuntimeException(String.format("Could not instantiate class: %s", className)); } if (!(result instanceof IExternalizable)) { throw new RuntimeException(String.format("Class must implement the IExternalizable interface: %s", className)); } refStorage.classReferences.add(new ClassReference(className, AMF3.TYPE_OBJECT_EXTERNALIZABLE, null)); storeReference(tempRefId, result); ((IExternalizable) result).readExternal(new DataInput(this, deserializer)); break; case AMF3.TYPE_OBJECT_VALUE: log.debug("Detected: Object value type"); // First, we should read typed (non-dynamic) properties ("sealed traits" according to AMF3 specification). // Property names are stored in the beginning, then values are stored. count = type >> 2; log.debug("Count: {}", count); if (attributes == null) { attributes = new ArrayList(count); for (int i = 0; i < count; i++) { attributes.add(readString(String.class)); } refStorage.classReferences.add(new ClassReference(className, AMF3.TYPE_OBJECT_VALUE, attributes)); } //use the size of the attributes if we have no count if (count == 0 && attributes != null) { count = attributes.size(); log.debug("Using class attribute size for property count: {}", count); //read the attributes from the stream and log if count doesnt match List tmpAttributes = new ArrayList(count); for (int i = 0; i < count; i++) { tmpAttributes.add(readString(String.class)); } if (count != tmpAttributes.size()) { log.debug("Count and attributes length does not match!"); } refStorage.classReferences.add(new ClassReference(className, AMF3.TYPE_OBJECT_VALUE, attributes)); } properties = new ObjectMap(); for (String key : attributes) { log.debug("Looking for property: {}", key); Object value = deserializer.deserialize(this, getPropertyType(instance, key)); log.debug("Key: {} Value: {}", key, value); properties.put(key, value); } log.trace("Buffer - position: {} limit: {}", buf.position(), buf.limit()); //no more items to read if we are at the end of the buffer if (buf.position() < buf.limit()) { // Now we should read dynamic properties which are stored as name-value pairs. // Dynamic properties are NOT remembered in 'classReferences'. String key = readString(String.class); while (!"".equals(key)) { Object value = deserializer.deserialize(this, getPropertyType(instance, key)); properties.put(key, value); key = readString(String.class); } } break; default: case AMF3.TYPE_OBJECT_PROXY: log.debug("Detected: Object proxy type"); if ("".equals(className)) { throw new RuntimeException("Classname is required to load an Externalizable object"); } log.debug("Externalizable class: {}", className); result = newInstance(className); if (result == null) { throw new RuntimeException(String.format("Could not instantiate class: %s", className)); } if (!(result instanceof IExternalizable)) { throw new RuntimeException(String.format("Class must implement the IExternalizable interface: %s", className)); } refStorage.classReferences.add(new ClassReference(className, AMF3.TYPE_OBJECT_PROXY, null)); storeReference(tempRefId, result); ((IExternalizable) result).readExternal(new DataInput(this, deserializer)); } amf3_mode -= 1; if (result == null) { // Create result object based on classname if ("".equals(className)) { // "anonymous" object, load as Map // Resolve circular references for (Map.Entry entry : properties.entrySet()) { if (entry.getValue() == pending) { entry.setValue(properties); } } storeReference(tempRefId, properties); result = properties; } else if ("RecordSet".equals(className)) { // TODO: how are RecordSet objects encoded? throw new RuntimeException("Objects of type RecordSet not supported yet."); } else if ("RecordSetPage".equals(className)) { // TODO: how are RecordSetPage objects encoded? throw new RuntimeException("Objects of type RecordSetPage not supported yet."); } else { // Apply properties to object result = newInstance(className); if (result != null) { storeReference(tempRefId, result); Class resultClass = result.getClass(); pending.resolveProperties(result); for (Map.Entry entry : properties.entrySet()) { // Resolve circular references final String key = entry.getKey(); Object value = entry.getValue(); if (value == pending) { value = result; } if (value instanceof PendingObject) { // Defer setting of value until real object is created ((PendingObject) value).addPendingProperty(result, resultClass, key); continue; } if (value != null) { try { final Field field = resultClass.getField(key); final Class fieldType = field.getType(); if (!fieldType.isAssignableFrom(value.getClass())) { value = ConversionUtils.convert(value, fieldType); } else if (value instanceof Enum) { value = Enum.valueOf(fieldType, value.toString()); } field.set(result, value); } catch (Exception e) { try { BeanUtils.setProperty(result, key, value); } catch (IllegalAccessException ex) { log.warn("Error mapping key: {} value: {}", key, value); } catch (InvocationTargetException ex) { log.warn("Error mapping key: {} value: {}", key, value); } } } else { log.debug("Skipping null property: {}", key); } } } // else fall through } } return result; } /** * Read ByteArray object. * * @return ByteArray object */ public ByteArray readByteArray(Type target) { int type = readAMF3Integer(); if ((type & 1) == 0) { return (ByteArray) getReference(type >> 1); } type >>= 1; ByteArray result = new ByteArray(buf, type); storeReference(result); return result; } /** * Read Vector object. * * @return Vector object */ @SuppressWarnings("unchecked") public Vector readVectorInt() { log.debug("readVectorInt"); int type = readAMF3Integer(); if ((type & 1) == 0) { return (Vector) getReference(type >> 1); } int len = type >> 1; Vector array = new Vector(len); storeReference(array); @SuppressWarnings("unused") int ref2 = readAMF3Integer(); for (int j = 0; j < len; ++j) { array.add(buf.getInt()); } return array; } /** * Read Vector object. * * @return Vector object */ @SuppressWarnings("unchecked") public Vector readVectorUInt() { log.debug("readVectorUInt"); int type = readAMF3Integer(); if ((type & 1) == 0) { return (Vector) getReference(type >> 1); } int len = type >> 1; Vector array = new Vector(len); storeReference(array); @SuppressWarnings("unused") int ref2 = readAMF3Integer(); for (int j = 0; j < len; ++j) { long value = (buf.get() & 0xff) << 24L; value += (buf.get() & 0xff) << 16L; value += (buf.get() & 0xff) << 8L; value += (buf.get() & 0xff); array.add(value); } return array; } /** * Read Vector object. * * @return Vector object */ @SuppressWarnings("unchecked") public Vector readVectorNumber() { log.debug("readVectorNumber"); int type = readAMF3Integer(); log.debug("Type: {}", type); if ((type & 1) == 0) { return (Vector) getReference(type >> 1); } int len = type >> 1; log.debug("Length: {}", len); Vector array = new Vector(len); storeReference(array); int ref2 = readAMF3Integer(); log.debug("Ref2: {}", ref2); for (int j = 0; j < len; ++j) { Double d = buf.getDouble(); log.debug("Double: {}", d); array.add(d); } return array; } /** * Read Vector object. * * @return Vector object */ @SuppressWarnings("unchecked") public Vector readVectorObject() { log.debug("readVectorObject"); int type = readAMF3Integer(); log.debug("Type: {}", type); if ((type & 1) == 0) { return (Vector) getReference(type >> 1); } int len = type >> 1; log.debug("Length: {}", len); Vector array = new Vector(len); storeReference(array); int ref2 = readAMF3Integer(); log.debug("Ref2: {}", ref2); buf.skip(1); Deserializer deserializer = new Deserializer(); Object object = null; for (int j = 0; j < len; ++j) { byte objectType = buf.get(); log.debug("Object type: {}", objectType); switch (objectType) { case AMF3.TYPE_UNDEFINED: case AMF3.TYPE_NULL: object = null; break; case AMF3.TYPE_STRING: object = readString(null); break; case AMF3.TYPE_NUMBER: case AMF3.TYPE_INTEGER: object = readNumber(null); break; case AMF3.TYPE_BYTEARRAY: object = readByteArray(null); break; case AMF3.TYPE_VECTOR_INT: object = readVectorInt(); break; case AMF3.TYPE_VECTOR_UINT: object = readVectorUInt(); break; case AMF3.TYPE_VECTOR_NUMBER: object = readVectorNumber(); break; case AMF3.TYPE_VECTOR_OBJECT: object = readVectorObject(); break; default: object = readObject(deserializer, null); } array.add(object); } log.debug("Vector: {}", array); return array; } /** * Reads Custom * * @return Object Custom type object */ @Override public Object readCustom(Type target) { // Return null for now return null; } /** {@inheritDoc} */ public Object readReference(Type target) { throw new RuntimeException("AMF3 doesn't support direct references."); } /** * Parser of AMF3 "compressed" integer data type * * @return a converted integer value * @see parsing AMF3 integers (external) */ private int readAMF3Integer() { int n = 0; int b = buf.get(); int result = 0; while ((b & 0x80) != 0 && n < 3) { result <<= 7; result |= (b & 0x7f); b = buf.get(); n++; } if (n < 3) { result <<= 7; result |= b; } else { // use all 8 bits from the 4th byte result <<= 8; result |= b & 0x0ff; // check if the integer should be negative if ((result & 0x10000000) != 0) { // extend the sign bit result |= 0xe0000000; } } return result; } //Read UInt29 style @SuppressWarnings("unused") private int readAMF3IntegerNew() { int b = buf.get() & 0xFF; if (b < 128) { return b; } int value = (b & 0x7F) << 7; b = buf.get() & 0xFF; if (b < 128) { return (value | b); } value = (value | b & 0x7F) << 7; b = buf.get() & 0xFF; if (b < 128) { return (value | b); } value = (value | b & 0x7F) << 8; b = buf.get() & 0xFF; return (value | b); } /** {@inheritDoc} */ public Document readXML(Type target) { int len = readAMF3Integer(); if (len == 1) { // Empty string, should not happen return null; } if ((len & 1) == 0) { // Reference return (Document) getReference(len >> 1); } len >>= 1; int limit = buf.limit(); final ByteBuffer strBuf = buf.buf(); strBuf.limit(strBuf.position() + len); final String xmlString = AMF.CHARSET.decode(strBuf).toString(); buf.limit(limit); // Reset the limit Document doc = null; try { doc = XMLUtils.stringToDoc(xmlString); } catch (IOException ioex) { log.error("IOException converting xml to dom", ioex); } storeReference(doc); return doc; } /** * Resets map */ @Override public void reset() { super.reset(); // input must keep the String references for all parameters //refStorage.stringReferences.clear(); } } red5-1.0~svn4374.orig/src/org/red5/io/amf3/Output.java0000644000175000017500000004135211706617130022137 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.amf3; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.Vector; import net.sf.ehcache.Element; import org.apache.commons.beanutils.BeanMap; import org.apache.mina.core.buffer.IoBuffer; import org.red5.annotations.Anonymous; import org.red5.compatibility.flex.messaging.io.ObjectProxy; import org.red5.io.amf.AMF; import org.red5.io.object.RecordSet; import org.red5.io.object.Serializer; import org.red5.io.object.UnsignedInt; import org.red5.io.utils.HexDump; import org.red5.io.utils.XMLUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; /** * AMF3 output writer * * @see org.red5.io.amf3.AMF3 * @see org.red5.io.amf3.Input * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Harald Radi (harald.radi@nme.at) */ public class Output extends org.red5.io.amf.Output implements org.red5.io.object.Output { protected static Logger log = LoggerFactory.getLogger(Output.class); /** * Set to a value above 0 to disable writing of the AMF3 object tag. */ private int amf3_mode; /** * List of strings already written. * */ private Map stringReferences; /** * Constructor of AMF3 output. * * @param buf instance of IoBuffer * @see IoBuffer */ public Output(IoBuffer buf) { super(buf); amf3_mode = 0; stringReferences = new HashMap(); } /** * Force using AMF3 everywhere */ public void enforceAMF3() { amf3_mode++; } /** * Provide access to raw data. * * @return IoBuffer */ protected IoBuffer getBuffer() { return buf; } /** {@inheritDoc} */ @Override public boolean supportsDataType(byte type) { return true; } protected void writeAMF3() { if (amf3_mode == 0) { buf.put(AMF.TYPE_AMF3_OBJECT); } } /** {@inheritDoc} */ @Override public void writeBoolean(Boolean bol) { writeAMF3(); buf.put(bol ? AMF3.TYPE_BOOLEAN_TRUE : AMF3.TYPE_BOOLEAN_FALSE); } /** {@inheritDoc} */ @Override public void writeNull() { writeAMF3(); buf.put(AMF3.TYPE_NULL); } protected void putInteger(long value) { if ((value >= -268435456) && (value <= 268435455)) { value &= 536870911; } if (value < 128) { buf.put((byte) value); } else if (value < 16384) { buf.put((byte) (((value >> 7) & 0x7F) | 0x80)); buf.put((byte) (value & 0x7F)); } else if (value < 2097152) { buf.put((byte) (((value >> 14) & 0x7F) | 0x80)); buf.put((byte) (((value >> 7) & 0x7F) | 0x80)); buf.put((byte) (value & 0x7F)); } else if (value < 1073741824) { buf.put((byte) (((value >> 22) & 0x7F) | 0x80)); buf.put((byte) (((value >> 15) & 0x7F) | 0x80)); buf.put((byte) (((value >> 8) & 0x7F) | 0x80)); buf.put((byte) (value & 0xFF)); } else { log.error("Integer out of range: {}", value); } } protected static byte[] encodeString(String string) { Element element = getStringCache().get(string); byte[] encoded = (element == null ? null : (byte[]) element.getObjectValue()); if (encoded == null) { ByteBuffer buf = AMF.CHARSET.encode(string); encoded = new byte[buf.limit()]; buf.get(encoded); getStringCache().put(new Element(string, encoded)); } return encoded; } protected void putString(String str, byte[] encoded) { final int len = encoded.length; Integer pos = stringReferences.get(str); if (pos != null) { // Reference to existing string putInteger(pos << 1); return; } putInteger(len << 1 | 1); buf.put(encoded); stringReferences.put(str, stringReferences.size()); } /** {@inheritDoc} */ @Override public void putString(String string) { if ("".equals(string)) { // Empty string; putInteger(1); return; } final byte[] encoded = encodeString(string); putString(string, encoded); } /** {@inheritDoc} */ @Override public void writeNumber(Number num) { writeAMF3(); if (num.longValue() < AMF3.MIN_INTEGER_VALUE || num.longValue() > AMF3.MAX_INTEGER_VALUE) { // Out of range for integer encoding buf.put(AMF3.TYPE_NUMBER); buf.putDouble(num.doubleValue()); } else if (num instanceof Long || num instanceof Integer || num instanceof Short || num instanceof Byte) { buf.put(AMF3.TYPE_INTEGER); putInteger(num.longValue()); } else { buf.put(AMF3.TYPE_NUMBER); buf.putDouble(num.doubleValue()); } } /** {@inheritDoc} */ @Override public void writeString(String string) { writeAMF3(); buf.put(AMF3.TYPE_STRING); if ("".equals(string)) { putInteger(1); } else { final byte[] encoded = encodeString(string); putString(string, encoded); } } /** {@inheritDoc} */ @Override public void writeDate(Date date) { writeAMF3(); buf.put(AMF3.TYPE_DATE); if (hasReference(date)) { putInteger(getReferenceId(date) << 1); return; } storeReference(date); putInteger(1); buf.putDouble(date.getTime()); } /** {@inheritDoc} */ public void writeArray(Collection array, Serializer serializer) { writeAMF3(); buf.put(AMF3.TYPE_ARRAY); if (hasReference(array)) { putInteger(getReferenceId(array) << 1); return; } storeReference(array); amf3_mode += 1; int count = array.size(); putInteger(count << 1 | 1); putString(""); for (Object item : array) { serializer.serialize(this, item); } amf3_mode -= 1; } /** {@inheritDoc} */ public void writeArray(Object[] array, Serializer serializer) { writeAMF3(); buf.put(AMF3.TYPE_ARRAY); if (hasReference(array)) { putInteger(getReferenceId(array) << 1); return; } storeReference(array); amf3_mode += 1; int count = array.length; putInteger(count << 1 | 1); putString(""); for (Object item : array) { serializer.serialize(this, item); } amf3_mode -= 1; } /** {@inheritDoc} */ public void writeArray(Object array, Serializer serializer) { writeAMF3(); buf.put(AMF3.TYPE_ARRAY); if (hasReference(array)) { putInteger(getReferenceId(array) << 1); return; } storeReference(array); amf3_mode += 1; int count = Array.getLength(array); putInteger(count << 1 | 1); putString(""); for (int i = 0; i < count; i++) { serializer.serialize(this, Array.get(array, i)); } amf3_mode -= 1; } /** {@inheritDoc} */ public void writeMap(Map map, Serializer serializer) { writeAMF3(); buf.put(AMF3.TYPE_ARRAY); if (hasReference(map)) { putInteger(getReferenceId(map) << 1); return; } storeReference(map); // Search number of starting integer keys int count = 0; for (int i = 0; i < map.size(); i++) { try { if (!map.containsKey(i)) break; } catch (ClassCastException err) { // Map has non-number keys. break; } count++; } amf3_mode += 1; if (count == map.size()) { // All integer keys starting from zero: serialize as regular array putInteger(count << 1 | 1); putString(""); for (int i = 0; i < count; i++) { serializer.serialize(this, map.get(i)); } amf3_mode -= 1; return; } putInteger(count << 1 | 1); // Serialize key-value pairs first for (Map.Entry entry : map.entrySet()) { Object key = entry.getKey(); if ((key instanceof Number) && !(key instanceof Float) && !(key instanceof Double) && ((Number) key).longValue() >= 0 && ((Number) key).longValue() < count) { // Entry will be serialized later continue; } putString(key.toString()); serializer.serialize(this, entry.getValue()); } putString(""); // Now serialize integer keys starting from zero for (int i = 0; i < count; i++) { serializer.serialize(this, map.get(i)); } amf3_mode -= 1; } /** {@inheritDoc} */ public void writeMap(Collection array, Serializer serializer) { writeAMF3(); buf.put(AMF3.TYPE_ARRAY); if (hasReference(array)) { putInteger(getReferenceId(array) << 1); return; } storeReference(array); // TODO: we could optimize this by storing the first integer // keys after the key-value pairs amf3_mode += 1; putInteger(1); int idx = 0; for (Object item : array) { if (item != null) { putString(String.valueOf(idx)); serializer.serialize(this, item); } idx++; } amf3_mode -= 1; putString(""); } /** {@inheritDoc} */ @Override protected void writeArbitraryObject(Object object, Serializer serializer) { Class objectClass = object.getClass(); // If we need to serialize class information... if (!objectClass.isAnnotationPresent(Anonymous.class)) { putString(serializer.getClassName(objectClass)); } else { putString(""); } // Store key/value pairs amf3_mode += 1; // Iterate thru fields of an object to build "name-value" map from it for (Field field : objectClass.getFields()) { String fieldName = field.getName(); log.debug("Field: {} class: {}", field, objectClass); // Check if the Field corresponding to the getter/setter pair is transient if (!serializeField(serializer, objectClass, fieldName, field, null)) { continue; } Object value; try { // Get field value value = field.get(object); } catch (IllegalAccessException err) { // Swallow on private and protected properties access exception continue; } // Write out prop name putString(fieldName); // Write out serializer.serialize(this, field, null, object, value); } amf3_mode -= 1; // Write out end of object marker putString(""); } /** {@inheritDoc} */ @SuppressWarnings({ "rawtypes" }) public void writeObject(Object object, Serializer serializer) { writeAMF3(); buf.put(AMF3.TYPE_OBJECT); if (hasReference(object)) { putInteger(getReferenceId(object) << 1); return; } storeReference(object); if (object instanceof IExternalizable) { // The object knows how to serialize itself. int type = 1 << 1 | 1; if (object instanceof ObjectProxy) { type |= AMF3.TYPE_OBJECT_PROXY << 2; } else { type |= AMF3.TYPE_OBJECT_EXTERNALIZABLE << 2; } putInteger(type); putString(serializer.getClassName(object.getClass())); amf3_mode += 1; ((IExternalizable) object).writeExternal(new DataOutput(this, serializer)); amf3_mode -= 1; return; } // We have an inline class that is not a reference. // We store the properties using key/value pairs int type = AMF3.TYPE_OBJECT_VALUE << 2 | 1 << 1 | 1; putInteger(type); // Create new map out of bean properties BeanMap beanMap = new BeanMap(object); // Set of bean attributes Set set = beanMap.keySet(); if ((set.size() == 0) || (set.size() == 1 && beanMap.containsKey("class"))) { // BeanMap is empty or can only access "class" attribute, skip it writeArbitraryObject(object, serializer); return; } // Write out either start of object marker for class name or "empty" start of object marker Class objectClass = object.getClass(); if (!objectClass.isAnnotationPresent(Anonymous.class)) { // classname putString(serializer.getClassName(object.getClass())); } else { putString(""); } // Store key/value pairs amf3_mode += 1; for (Object key : set) { String fieldName = key.toString(); log.debug("Field name: {} class: {}", fieldName, objectClass); Field field = getField(objectClass, fieldName); Method getter = getGetter(objectClass, beanMap, fieldName); // Check if the Field corresponding to the getter/setter pair is transient if (!serializeField(serializer, objectClass, fieldName, field, getter)) { continue; } putString(fieldName); serializer.serialize(this, field, getter, object, beanMap.get(key)); } amf3_mode -= 1; // End of object marker putString(""); } /** {@inheritDoc} */ @Override public void writeObject(Map map, Serializer serializer) { writeAMF3(); buf.put(AMF3.TYPE_OBJECT); if (hasReference(map)) { putInteger(getReferenceId(map) << 1); return; } storeReference(map); // We have an inline class that is not a reference. // We store the properties using key/value pairs int type = AMF3.TYPE_OBJECT_VALUE << 2 | 1 << 1 | 1; putInteger(type); // No classname putString(""); // Store key/value pairs amf3_mode += 1; for (Map.Entry entry : map.entrySet()) { putString(entry.getKey().toString()); serializer.serialize(this, entry.getValue()); } amf3_mode -= 1; // End of object marker putString(""); } /** {@inheritDoc} */ @Override public void writeRecordSet(RecordSet recordset, Serializer serializer) { writeString("Not implemented."); } /** {@inheritDoc} */ @Override public void writeXML(Document xml) { writeAMF3(); buf.put(AMF3.TYPE_XML); if (hasReference(xml)) { putInteger(getReferenceId(xml) << 1); return; } final byte[] encoded = encodeString(XMLUtils.docToString(xml)); putInteger(encoded.length << 1 | 1); buf.put(encoded); storeReference(xml); } /** {@inheritDoc} */ public void writeByteArray(ByteArray array) { writeAMF3(); buf.put(AMF3.TYPE_BYTEARRAY); if (hasReference(array)) { putInteger(getReferenceId(array) << 1); return; } storeReference(array); IoBuffer data = array.getData(); putInteger(data.limit() << 1 | 1); byte[] tmp = new byte[data.limit()]; int old = data.position(); try { data.position(0); data.get(tmp); buf.put(tmp); } finally { data.position(old); } } /** * Write a Vector. * * @param vector */ @Override public void writeVectorInt(Vector vector) { log.debug("writeVectorInt: {}", vector); writeAMF3(); buf.put(AMF3.TYPE_VECTOR_INT); if (hasReference(vector)) { putInteger(getReferenceId(vector) << 1); return; } storeReference(vector); putInteger(vector.size() << 1 | 1); buf.put((byte) 0x00); for (Integer v : vector) { buf.putInt(v); } // debug if (log.isDebugEnabled()) { int pos = buf.position(); buf.position(0); StringBuilder sb = new StringBuilder(); HexDump.dumpHex(sb, buf.array()); log.debug("\n{}", sb); buf.position(pos); } } /** * Write a Vector. * * @param vector */ @Override public void writeVectorUInt(Vector vector) { log.debug("writeVectorUInt: {}", vector); writeAMF3(); buf.put(AMF3.TYPE_VECTOR_UINT); if (hasReference(vector)) { putInteger(getReferenceId(vector) << 1); return; } storeReference(vector); putInteger(vector.size() << 1 | 1); buf.put((byte) 0x00); for (Long v : vector) { // update this class to implement valueOf like Long.valueOf UnsignedInt uint = new UnsignedInt(v); byte[] arr = uint.getBytes(); buf.put(arr); } } /** * Write a Vector. * * @param vector */ @Override public void writeVectorNumber(Vector vector) { log.debug("writeVectorNumber: {}", vector); buf.put(AMF3.TYPE_VECTOR_NUMBER); if (hasReference(vector)) { putInteger(getReferenceId(vector) << 1); return; } storeReference(vector); putInteger(vector.size() << 1 | 1); putInteger(0); buf.put((byte) 0x00); for (Double v : vector) { buf.putDouble(v); } } /** * Write a Vector. * * @param vector */ @Override public void writeVectorObject(Vector vector) { log.debug("writeVectorObject: {}", vector); buf.put(AMF3.TYPE_VECTOR_OBJECT); if (hasReference(vector)) { putInteger(getReferenceId(vector) << 1); return; } storeReference(vector); putInteger(vector.size() << 1 | 1); putInteger(0); buf.put((byte) 0x01); Serializer serializer = new Serializer(); for (Object v : vector) { serializer.serialize(this, v); } } }red5-1.0~svn4374.orig/src/org/red5/io/amf3/IDataOutput.java0000644000175000017500000000650711706617130023045 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.amf3; import java.nio.ByteOrder; /** * Interface implemented by classes that provide a way to store custom objects. * * @see IExternalizable#writeExternal(IDataOutput) * @see Adobe Livedocs (external) */ public interface IDataOutput { /** * Return the byteorder used when storing values. * * @return the byteorder */ public ByteOrder getEndian(); /** * Set the byteorder to use when storing values. * * @param endian the byteorder to use */ public void setEndian(ByteOrder endian); /** * Write boolean value. * * @param value the value */ public void writeBoolean(boolean value); /** * Write signed byte value. * * @param value the value */ public void writeByte(byte value); /** * Write multiple bytes. * * @param bytes the bytes */ public void writeBytes(byte[] bytes); /** * Write multiple bytes from given offset. * * @param bytes the bytes * @param offset offset in bytes to start writing from */ public void writeBytes(byte[] bytes, int offset); /** * Write given number of bytes from given offset. * * @param bytes the bytes * @param offset offset in bytes to start writing from * @param length number of bytes to write */ public void writeBytes(byte[] bytes, int offset, int length); /** * Write double-precision floating point value. * * @param value the value */ public void writeDouble(double value); /** * Write single-precision floating point value. * * @param value the value */ public void writeFloat(float value); /** * Write signed integer value. * * @param value the value */ public void writeInt(int value); /** * Write string in given character set. * * @param value the string * @param encoding the character set */ public void writeMultiByte(String value, String encoding); /** * Write arbitrary object. * * @param value the object */ public void writeObject(Object value); /** * Write signed short value. * * @param value the value */ public void writeShort(short value); /** * Write unsigned integer value. * * @param value the value */ public void writeUnsignedInt(long value); /** * Write UTF-8 encoded string. * * @param value the string */ public void writeUTF(String value); /** * Write UTF-8 encoded string as byte array. This string is stored without informations * about its length, so {@link IDataInput#readUTFBytes(int)} must be used to load it. * * @param value the string */ public void writeUTFBytes(String value); } red5-1.0~svn4374.orig/src/org/red5/io/amf3/ByteArray.java0000644000175000017500000002046011706617130022536 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.amf3; import java.io.IOException; import java.nio.ByteOrder; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; /** * Red5 version of the Flex ByteArray class. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class ByteArray implements IDataInput, IDataOutput { /** Internal storage for array contents. */ protected IoBuffer data; /** Object used to read from array. */ protected IDataInput dataInput; /** Object used to write to array. */ protected IDataOutput dataOutput; /** * Internal constructor used to create ByteArray during deserialization. * * @param buffer * @param length */ protected ByteArray(IoBuffer buffer, int length) { data = IoBuffer.allocate(length); data.setAutoExpand(true); byte[] tmp = new byte[length]; buffer.get(tmp); data.put(tmp); data.flip(); prepareIO(); } /** * Public constructor. Creates new empty ByteArray. */ public ByteArray() { data = IoBuffer.allocate(0); data.setAutoExpand(true); prepareIO(); } /** * Create internal objects used for reading and writing. */ protected void prepareIO() { // we assume that everything in ByteArray is in AMF3 Input input = new Input(data); input.enforceAMF3(); dataInput = new DataInput(input, new Deserializer()); Output output = new Output(data); output.enforceAMF3(); dataOutput = new DataOutput(output, new Serializer()); } /** * Get internal data. * * @return byte buffer */ protected IoBuffer getData() { return data; } /** * Get the current position in the data. * * @return current position */ public int position() { return data.position(); } /** * Set the current position in the data. * * @param position position to set */ public void position(int position) { data.position(position); } /** * Return number of bytes available for reading. * * @return bytes available */ public int bytesAvailable() { return length() - position(); } /** * Return total number of bytes in array. * * @return number of bytes in array */ public int length() { return data.limit(); } /** * Return string representation of the array's contents. * * @return string representaiton of array's contents. */ public String toString() { int old = data.position(); try { data.position(0); return data.asCharBuffer().toString(); } finally { data.position(old); } } /** * Compress contents using zlib. */ public void compress() { IoBuffer tmp = IoBuffer.allocate(0); tmp.setAutoExpand(true); DeflaterOutputStream deflater = new DeflaterOutputStream(tmp.asOutputStream(), new Deflater(Deflater.BEST_COMPRESSION)); byte[] tmpData = new byte[data.limit()]; data.position(0); data.get(tmpData); try { deflater.write(tmpData); deflater.finish(); } catch (IOException e) { //docs state that free is optional tmp.free(); throw new RuntimeException("could not compress data", e); } finally { if (deflater != null) { try { deflater.close(); } catch (IOException e1) { } } } data.free(); data = tmp; data.flip(); prepareIO(); } /** * Decompress contents using zlib. */ public void uncompress() { data.position(0); InflaterInputStream inflater = new InflaterInputStream(data.asInputStream()); byte[] buffer = new byte[8192]; IoBuffer tmp = IoBuffer.allocate(0); tmp.setAutoExpand(true); try { while (inflater.available() > 0) { int decompressed = inflater.read(buffer); if (decompressed <= 0) { // Finished decompression break; } tmp.put(buffer, 0, decompressed); } } catch (IOException e) { tmp.free(); throw new RuntimeException("could not uncompress data", e); } finally { if (inflater != null) { try { inflater.close(); } catch (IOException e1) { } } } data.free(); data = tmp; data.flip(); prepareIO(); } /** {@inheritDoc} */ public ByteOrder getEndian() { return dataInput.getEndian(); } /** {@inheritDoc} */ public boolean readBoolean() { return dataInput.readBoolean(); } /** {@inheritDoc} */ public byte readByte() { return dataInput.readByte(); } /** {@inheritDoc} */ public void readBytes(byte[] bytes) { dataInput.readBytes(bytes); } /** {@inheritDoc} */ public void readBytes(byte[] bytes, int offset) { dataInput.readBytes(bytes, offset); } /** {@inheritDoc} */ public void readBytes(byte[] bytes, int offset, int length) { dataInput.readBytes(bytes, offset, length); } /** {@inheritDoc} */ public double readDouble() { return dataInput.readDouble(); } /** {@inheritDoc} */ public float readFloat() { return dataInput.readFloat(); } /** {@inheritDoc} */ public int readInt() { return dataInput.readInt(); } /** {@inheritDoc} */ public String readMultiByte(int length, String charSet) { return dataInput.readMultiByte(length, charSet); } /** {@inheritDoc} */ public Object readObject() { // according to AMF3 spec, each object should have its own "reference" tables, // so we must recreate Input object before reading each object prepareIO(); return dataInput.readObject(); } /** {@inheritDoc} */ public short readShort() { return dataInput.readShort(); } /** {@inheritDoc} */ public String readUTF() { return dataInput.readUTF(); } /** {@inheritDoc} */ public String readUTFBytes(int length) { return dataInput.readUTFBytes(length); } /** {@inheritDoc} */ public int readUnsignedByte() { return dataInput.readUnsignedByte(); } /** {@inheritDoc} */ public long readUnsignedInt() { return dataInput.readUnsignedInt(); } /** {@inheritDoc} */ public int readUnsignedShort() { return dataInput.readUnsignedShort(); } /** {@inheritDoc} */ public void setEndian(ByteOrder endian) { dataInput.setEndian(endian); dataOutput.setEndian(endian); } /** {@inheritDoc} */ public void writeBoolean(boolean value) { dataOutput.writeBoolean(value); } /** {@inheritDoc} */ public void writeByte(byte value) { dataOutput.writeByte(value); } /** {@inheritDoc} */ public void writeBytes(byte[] bytes) { dataOutput.writeBytes(bytes); } /** {@inheritDoc} */ public void writeBytes(byte[] bytes, int offset) { dataOutput.writeBytes(bytes, offset); } /** {@inheritDoc} */ public void writeBytes(byte[] bytes, int offset, int length) { dataOutput.writeBytes(bytes, offset, length); } /** {@inheritDoc} */ public void writeDouble(double value) { dataOutput.writeDouble(value); } /** {@inheritDoc} */ public void writeFloat(float value) { dataOutput.writeFloat(value); } /** {@inheritDoc} */ public void writeInt(int value) { dataOutput.writeInt(value); } /** {@inheritDoc} */ public void writeMultiByte(String value, String encoding) { dataOutput.writeMultiByte(value, encoding); } /** {@inheritDoc} */ public void writeObject(Object value) { // according to AMF3 spec, each object should have its own "reference" tables, // so we must recreate Input object before writing each object prepareIO(); dataOutput.writeObject(value); } /** {@inheritDoc} */ public void writeShort(short value) { dataOutput.writeShort(value); } /** {@inheritDoc} */ public void writeUTF(String value) { dataOutput.writeUTF(value); } /** {@inheritDoc} */ public void writeUTFBytes(String value) { dataOutput.writeUTFBytes(value); } /** {@inheritDoc} */ public void writeUnsignedInt(long value) { dataOutput.writeUnsignedInt(value); } } red5-1.0~svn4374.orig/src/org/red5/io/amf3/IDataInput.java0000644000175000017500000000654311706617130022644 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.amf3; import java.nio.ByteOrder; /** * Interface implemented by classes that provide a way to load custom objects. * * @see IExternalizable#readExternal(IDataInput) * @see Adobe Livedocs (external) */ public interface IDataInput { /** * Return the byteorder used when loading values. * * @return the byteorder */ public ByteOrder getEndian(); /** * Set the byteorder to use when loading values. * * @param endian the byteorder to use */ public void setEndian(ByteOrder endian); /** * Read boolean value. * * @return the value */ public boolean readBoolean(); /** * Read signed single byte value. * * @return the value */ public byte readByte(); /** * Read list of bytes. * * @param bytes destination for read bytes */ public void readBytes(byte[] bytes); /** * Read list of bytes to given offset. * * @param bytes destination for read bytes * @param offset offset in destination to write to */ public void readBytes(byte[] bytes, int offset); /** * Read given number of bytes to given offset. * * @param bytes destination for read bytes * @param offset offset in destination to write to * @param length number of bytes to read */ public void readBytes(byte[] bytes, int offset, int length); /** * Read double-precision floating point value. * * @return the value */ public double readDouble(); /** * Read single-precision floating point value. * * @return the value */ public float readFloat(); /** * Read signed integer value. * * @return the value */ public int readInt(); /** * Read multibyte string. * * @param length length of string to read * @param charSet character set of string to read * @return the string */ public String readMultiByte(int length, String charSet); /** * Read arbitrary object. * * @return the object */ public Object readObject(); /** * Read signed short value. * * @return the value */ public short readShort(); /** * Read unsigned single byte value. * * @return the value */ public int readUnsignedByte(); /** * Read unsigned integer value. * * @return the value */ public long readUnsignedInt(); /** * Read unsigned short value. * * @return the value */ public int readUnsignedShort(); /** * Read UTF-8 encoded string. * * @return the string */ public String readUTF(); /** * Read UTF-8 encoded string with given length. * * @param length the length of the string * @return the string */ public String readUTFBytes(int length); } red5-1.0~svn4374.orig/src/org/red5/io/amf3/DataOutput.java0000644000175000017500000000715711706617130022736 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.amf3; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.Charset; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.amf.AMF; import org.red5.io.object.Serializer; /** * Implementation of the IDataOutput interface. Can be used to store an IExternalizable object. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * */ public class DataOutput implements IDataOutput { /** The output stream. */ private Output output; /** The serializer to use. */ private Serializer serializer; /** Raw data of output destination. */ private IoBuffer buffer; /** * Create a new DataOutput. * * @param output destination to write to * @param serializer the serializer to use */ protected DataOutput(Output output, Serializer serializer) { this.output = output; this.serializer = serializer; buffer = output.getBuffer(); } /** {@inheritDoc} */ public ByteOrder getEndian() { return buffer.order(); } /** {@inheritDoc} */ public void setEndian(ByteOrder endian) { buffer.order(endian); } /** {@inheritDoc} */ public void writeBoolean(boolean value) { buffer.put((byte) (value ? 1 : 0)); } /** {@inheritDoc} */ public void writeByte(byte value) { buffer.put(value); } /** {@inheritDoc} */ public void writeBytes(byte[] bytes) { buffer.put(bytes); } /** {@inheritDoc} */ public void writeBytes(byte[] bytes, int offset) { buffer.put(bytes, offset, bytes.length - offset); } /** {@inheritDoc} */ public void writeBytes(byte[] bytes, int offset, int length) { buffer.put(bytes, offset, length); } /** {@inheritDoc} */ public void writeDouble(double value) { buffer.putDouble(value); } /** {@inheritDoc} */ public void writeFloat(float value) { buffer.putFloat(value); } /** {@inheritDoc} */ public void writeInt(int value) { buffer.putInt(value); } /** {@inheritDoc} */ public void writeMultiByte(String value, String encoding) { final Charset cs = Charset.forName(encoding); final ByteBuffer strBuf = cs.encode(value); buffer.put(strBuf); } /** {@inheritDoc} */ public void writeObject(Object value) { serializer.serialize(output, value); } /** {@inheritDoc} */ public void writeShort(short value) { buffer.putShort(value); } /** {@inheritDoc} */ public void writeUnsignedInt(long value) { buffer.putInt((int) value); } /** {@inheritDoc} */ public void writeUTF(String value) { // fix from issue #97 try { byte[] strBuf = value.getBytes(AMF.CHARSET.name()); buffer.putShort((short) strBuf.length); buffer.put(strBuf); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } /** {@inheritDoc} */ public void writeUTFBytes(String value) { final java.nio.ByteBuffer strBuf = AMF.CHARSET.encode(value); buffer.put(strBuf); } } red5-1.0~svn4374.orig/src/org/red5/io/amf3/DataInput.java0000644000175000017500000000750611706617130022533 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.amf3; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.Charset; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.amf.AMF; import org.red5.io.object.Deserializer; /** * Implementation of the IDataInput interface. Can be used to load an * IExternalizable object. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * */ public class DataInput implements IDataInput { /** The input stream. */ private Input input; /** The deserializer to use. */ private Deserializer deserializer; /** Raw data of input source. */ private IoBuffer buffer; /** * Create a new DataInput. * * @param input input to use * @param deserializer the deserializer to use */ protected DataInput(Input input, Deserializer deserializer) { this.input = input; this.deserializer = deserializer; buffer = input.getBuffer(); } /** {@inheritDoc} */ public ByteOrder getEndian() { return buffer.order(); } /** {@inheritDoc} */ public void setEndian(ByteOrder endian) { buffer.order(endian); } /** {@inheritDoc} */ public boolean readBoolean() { return (buffer.get() != 0); } /** {@inheritDoc} */ public byte readByte() { return buffer.get(); } /** {@inheritDoc} */ public void readBytes(byte[] bytes) { buffer.get(bytes); } /** {@inheritDoc} */ public void readBytes(byte[] bytes, int offset) { buffer.get(bytes, offset, bytes.length - offset); } /** {@inheritDoc} */ public void readBytes(byte[] bytes, int offset, int length) { buffer.get(bytes, offset, length); } /** {@inheritDoc} */ public double readDouble() { return buffer.getDouble(); } /** {@inheritDoc} */ public float readFloat() { return buffer.getFloat(); } /** {@inheritDoc} */ public int readInt() { return buffer.getInt(); } /** {@inheritDoc} */ public String readMultiByte(int length, String charSet) { final Charset cs = Charset.forName(charSet); int limit = buffer.limit(); final ByteBuffer strBuf = buffer.buf(); strBuf.limit(strBuf.position() + length); final String string = cs.decode(strBuf).toString(); buffer.limit(limit); // Reset the limit return string; } /** {@inheritDoc} */ public Object readObject() { return deserializer.deserialize(input, Object.class); } /** {@inheritDoc} */ public short readShort() { return buffer.getShort(); } /** {@inheritDoc} */ public int readUnsignedByte() { return buffer.getUnsigned(); } /** {@inheritDoc} */ public long readUnsignedInt() { return buffer.getUnsignedInt(); } /** {@inheritDoc} */ public int readUnsignedShort() { return buffer.getShort() & 0xffff; //buffer.getUnsignedShort(); } /** {@inheritDoc} */ public String readUTF() { int length = buffer.getShort() & 0xffff; //buffer.getUnsignedShort(); return readUTFBytes(length); } /** {@inheritDoc} */ public String readUTFBytes(int length) { int limit = buffer.limit(); final ByteBuffer strBuf = buffer.buf(); strBuf.limit(strBuf.position() + length); final String string = AMF.CHARSET.decode(strBuf).toString(); buffer.limit(limit); // Reset the limit return string; } } red5-1.0~svn4374.orig/src/org/red5/io/amf3/AMF3.java0000644000175000017500000001143211706617130021321 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.amf3; /** * AMF3 data type definitions. * * For detailed specification please see the link below. * * @see AMF3 specification (external) * @see Official Adobe AMF3 Specification * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public class AMF3 { /** * Minimum possible value for integer number encoding. */ public static final long MIN_INTEGER_VALUE = -268435456; /** * Maximum possible value for integer number encoding. */ public static final long MAX_INTEGER_VALUE = 268435455; /** * Max string length */ public static final int LONG_STRING_LENGTH = 65535; /** * Undefined marker */ public static final byte TYPE_UNDEFINED = 0x00; /** * Null marker */ public static final byte TYPE_NULL = 0x01; /** * Boolean false marker */ public static final byte TYPE_BOOLEAN_FALSE = 0x02; /** * Boolean true marker */ public static final byte TYPE_BOOLEAN_TRUE = 0x03; /** * Integer marker */ public static final byte TYPE_INTEGER = 0x04; /** * Number marker */ public static final byte TYPE_NUMBER = 0x05; /** * String marker */ public static final byte TYPE_STRING = 0x06; /** * XML document marker *
* This is for the legacy XMLDocument type is retained in the language * as flash.xml.XMLDocument. Similar to AMF 0, the structure of an * XMLDocument needs to be flattened into a string representation for * serialization. As with other strings in AMF, the content is encoded in * UTF-8. * XMLDocuments can be sent as a reference to a previously occurring * XMLDocument instance by using an index to the implicit object reference * table. */ public static final byte TYPE_XML_DOCUMENT = 0x07; /** * Date marker */ public static final byte TYPE_DATE = 0x08; /** * Array start marker */ public static final byte TYPE_ARRAY = 0x09; /** * Object start marker */ public static final byte TYPE_OBJECT = 0x0A; /** * XML start marker */ public static final byte TYPE_XML = 0x0B; /** * ByteArray marker */ public static final byte TYPE_BYTEARRAY = 0x0C; /** * Vector marker */ public static final byte TYPE_VECTOR_INT = 0x0D; /** * Vector marker */ public static final byte TYPE_VECTOR_UINT = 0x0E; /** * Vector marker */ public static final byte TYPE_VECTOR_NUMBER = 0x0F; /** * Vector marker */ public static final byte TYPE_VECTOR_OBJECT = 0x10; /** * Property list encoding. * * The remaining integer-data represents the number of class members * that exist. The property names are read as string-data. The values * are then read as AMF3-data. */ public static final byte TYPE_OBJECT_PROPERTY = 0x00; /** * Externalizable object. * * What follows is the value of the "inner" object, including type code. * This value appears for objects that implement IExternalizable, such * as ArrayCollection and ObjectProxy. */ public static final byte TYPE_OBJECT_EXTERNALIZABLE = 0x01; /** * Name-value encoding. * * The property names and values are encoded as string-data followed by * AMF3-data until there is an empty string property name. If there is * a class-def reference there are no property names and the number of * values is equal to the number of properties in the class-def. */ public static final byte TYPE_OBJECT_VALUE = 0x02; /** * Proxy object. */ public static final byte TYPE_OBJECT_PROXY = 0x03; } red5-1.0~svn4374.orig/src/org/red5/io/amf3/IExternalizable.java0000644000175000017500000000244111706617130023715 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io.amf3; /** * Interface that needs to be implemented by classes that serialize / deserialize * themselves. * * @see Adobe Livedocs (external) */ public interface IExternalizable { /** * Load custom object from stream. * * @param input object to be used for data loading */ public void readExternal(IDataInput input); /** * Store custom object to stream. * * @param output object to be used for data storing */ public void writeExternal(IDataOutput output); } red5-1.0~svn4374.orig/src/org/red5/io/ITagWriter.java0000644000175000017500000000433411706617130022031 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.io; import java.io.IOException; import org.apache.mina.core.buffer.IoBuffer; /** * Writes tags to FLV file */ public interface ITagWriter { /** * Return the file that is written. * * @return the File to be written */ public IStreamableFile getFile(); /** * Return the offset * * @return Offset value */ public int getOffset(); /** * Return the bytes written * * @return Number of bytes written */ public long getBytesWritten(); /** * Writes the header bytes * * @throws IOException I/O exception */ public void writeHeader() throws IOException; /** * Writes a Tag object * * @param tag Tag to write * @return true on success, false otherwise * @throws IOException I/O exception */ public boolean writeTag(ITag tag) throws IOException; /** * Write a Tag using bytes * * @param type Tag type * @param data Byte data * @return true on success, false otherwise * @throws IOException I/O exception */ public boolean writeTag(byte type, IoBuffer data) throws IOException; /** * Write a Stream to disk using bytes * * @param b Array of bytes to write * @return true on success, false otherwise */ public boolean writeStream(byte[] b); /** * Closes a Writer */ public void close(); } red5-1.0~svn4374.orig/src/org/red5/compatibility/0000755000175000017500000000000011760512575021412 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/compatibility/flex/0000755000175000017500000000000011760512575022350 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/compatibility/flex/data/0000755000175000017500000000000011760512575023261 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/compatibility/flex/data/messages/0000755000175000017500000000000011760512575025070 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/compatibility/flex/data/messages/SequencedMessage.java0000644000175000017500000000302711706617130031147 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.data.messages; import org.red5.compatibility.flex.messaging.messages.AsyncMessage; /** * Response to DataMessage requests. * * @see DataMessage * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class SequencedMessage extends AsyncMessage { private static final long serialVersionUID = 5607350918278510061L; public long sequenceId; public Object sequenceProxies; public long sequenceSize; public String dataMessage; /** {@inheritDoc} */ protected void addParameters(StringBuilder result) { super.addParameters(result); result.append(",sequenceId="+sequenceId); result.append(",sequenceProxies="+sequenceProxies); result.append(",sequenceSize="+sequenceSize); result.append(",dataMessage="+dataMessage); } } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/data/messages/DataMessage.java0000644000175000017500000000250311706617130030102 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.data.messages; import org.red5.compatibility.flex.messaging.messages.AsyncMessage; /** * Message containing data update requests. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class DataMessage extends AsyncMessage { private static final long serialVersionUID = -4650851055941106677L; public Object identity; public int operation; /** {@inheritDoc} */ protected void addParameters(StringBuilder result) { super.addParameters(result); result.append(",identity="+identity); result.append(",operation="+operation); } } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/0000755000175000017500000000000011760512575024325 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/0000755000175000017500000000000011760512575026134 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/AcknowledgeMessageExt.java0000644000175000017500000000333211706617130033202 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.messages; import org.red5.io.amf3.IDataOutput; import org.red5.io.amf3.IExternalizable; /** * An externalizable version of a given AcknowledgeMessage. The class alias for this * class within flex is "DSK". * * @author Paul Gregoire (mondain@gmail.com) */ public class AcknowledgeMessageExt extends AcknowledgeMessage implements IExternalizable { private static final long serialVersionUID = -8764729006642310394L; private AcknowledgeMessage message; public AcknowledgeMessageExt() { } public AcknowledgeMessageExt(AcknowledgeMessage message) { this.setMessage(message); } public void setMessage(AcknowledgeMessage message) { this.message = message; } public AcknowledgeMessage getMessage() { return message; } @Override public void writeExternal(IDataOutput output) { if (this.message != null) { this.message.writeExternal(output); } else { super.writeExternal(output); } } } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/Message.java0000644000175000017500000000746211706617130030365 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.messages; import java.util.Map; public interface Message { public static final String NEEDS_CONFIG_HEADER = "DSNeedsConfig"; public static final String POLL_WAIT_HEADER = "DSPollWait"; public static final String PRESERVE_DURABLE_HEADER = "DSPreserveDurable"; public static final String REMOVE_SUBSCRIPTIONS = "DSRemSub"; public static final String SELECTOR_HEADER = "DSSelector"; public static final String SUBSCRIPTION_INVALIDATED_HEADER = "DSSubscriptionInvalidated"; public static final String SUBTOPIC_SEPARATOR = "_;_"; public static final String MESSAGING_VERSION = "DSMessagingVersion"; public static final String DESTINATION_CLIENT_ID_HEADER = "DSDstClientId"; public static final String ENDPOINT_HEADER = "DSEndpoint"; public static final String FLEX_CLIENT_ID_HEADER = "DSId"; public static final String REMOTE_CREDENTIALS_HEADER = "DSRemoteCredentials"; public static final String SYNC_HEADER = "sync"; /** * Returns the body of the message. * * @return message body */ Object getBody(); /** * Returns the client id indicating the client that sent the message. * * @return client id */ String getClientId(); /** * Returns the destination that the message targets. * * @return destination */ String getDestination(); /** * Returns a header value corresponding to the passed header name. * * @param name * @return header value */ Object getHeader(String name); /** * Returns the headers for the message. * * @return headers */ Map getHeaders(); /** * Returns the unique message id. * * @return message id */ String getMessageId(); /** * Returns the timestamp for the message. * * @return timestamp */ long getTimestamp(); /** * Returns the time to live for the message. * * @return time to live */ long getTimeToLive(); /** * Tests whether a header with the passed name exists. * * @param name * @return true if header exists, false otherwise */ boolean headerExists(String name); /** * Sets the body of the message. * * @param value */ void setBody(Object value); /** * Sets the client id indicating the client that sent the message. * * @param value */ void setClientId(String value); /** * Sets the destination that the message targets. * * @param value */ void setDestination(String value); /** * Sets a header on the message. * * @param name * @param value */ void setHeader(String name, Object value); /** * Sets the headers for the message. * * @param value */ void setHeaders(Map value); /** * Sets the unique message id. * * @param value */ void setMessageId(String value); /** * Sets the timestamp for the message. * * @param value */ void setTimestamp(long value); /** * Sets the time to live for the message. * * @param value */ void setTimeToLive(long value); } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/AuthenticationMessage.java0000644000175000017500000000236611706617130033263 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.messages; /** * Added to support flex.messaging.messages.AuthenticationMessage as noted in * http://jira.red5.org/browse/APPSERVER-176 * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class AuthenticationMessage extends CommandMessage { private static final long serialVersionUID = -9135142173898013075L; //TODO: we need to decode the body to actually make this viable //body=cXdlcXdldzpxd2Vxd2Vxd2Vxd2U } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/AbstractMessage.java0000644000175000017500000002225011706617130032041 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.messages; import java.io.Serializable; import java.util.Map; import org.red5.io.amf3.ByteArray; import org.red5.io.amf3.IDataInput; import org.red5.io.amf3.IDataOutput; import org.red5.io.utils.ObjectMap; import org.red5.io.utils.RandomGUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base class for all Flex compatibility messages. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ @SuppressWarnings("unchecked") public class AbstractMessage implements Message, Serializable { private static final long serialVersionUID = -834697863344344313L; public long timestamp; public Map headers = new ObjectMap(); public Object body; public String messageId; protected byte[] messageIdBytes; public long timeToLive; public String clientId; protected byte[] clientIdBytes; public String destination; /** * Initialize default message fields. */ public AbstractMessage() { timestamp = System.currentTimeMillis(); messageId = new RandomGUID().toString(); } /** * Add message properties to string. * * @param result StringBuilder to add properties to */ protected void addParameters(StringBuilder result) { result.append("ts="); result.append(timestamp); result.append(",headers="); result.append(headers); result.append(",body="); result.append(body); result.append(",messageId="); result.append(messageId); result.append(",timeToLive="); result.append(timeToLive); result.append(",clientId="); result.append(clientId); result.append(",destination="); result.append(destination); } @Override public Object getBody() { return body; } @Override public String getClientId() { return clientId; } @Override public String getDestination() { return destination; } @Override public Object getHeader(String name) { return headers.get(name); } @Override public Map getHeaders() { return headers; } @Override public String getMessageId() { return messageId; } @Override public long getTimestamp() { return timestamp; } @Override public long getTimeToLive() { return timeToLive; } @Override public boolean headerExists(String name) { return headers.containsKey(name); } @Override public void setBody(Object value) { body = value; } @Override public void setClientId(String value) { clientId = value; } @Override public void setDestination(String value) { destination = value; } @Override public void setHeader(String name, Object value) { headers.put(name, value); } @Override public void setHeaders(Map value) { if (!headers.isEmpty()) { headers.clear(); } headers.putAll(value); } @Override public void setMessageId(String value) { messageId = value; } @Override public void setTimestamp(long value) { timestamp = value; } @Override public void setTimeToLive(long value) { timeToLive = value; } /** * Return string representation of the message. * * @return value */ public String toString() { StringBuilder result = new StringBuilder(); result.append(getClass().getName()); result.append('('); addParameters(result); result.append(')'); return result.toString(); } static Logger log = LoggerFactory.getLogger(AbstractMessage.class); protected short[] readFlags(IDataInput input) { boolean hasNextFlag = true; short[] flagsArray = new short[2]; int i = 0; while (hasNextFlag) { short flags = (short) input.readUnsignedByte(); log.debug("Unsigned byte: {}", flags); if (i == flagsArray.length) { short[] tempArray = new short[i * 2]; System.arraycopy(flagsArray, 0, tempArray, 0, flagsArray.length); flagsArray = tempArray; } flagsArray[i] = flags; if ((flags & 0x80) != 0) { hasNextFlag = true; } else { hasNextFlag = false; } ++i; } log.debug("Flag count: {}", flagsArray.length); return flagsArray; } @SuppressWarnings("rawtypes") public void readExternal(IDataInput input) { log.debug("AbstractMessage - Read external"); short[] flagsArray = readFlags(input); for (int i = 0; i < flagsArray.length; ++i) { short flags = flagsArray[i]; short reservedPosition = 0; if (i == 0) { if ((flags & 0x1) != 0) { Object obj = input.readObject(); log.debug("Body object: {} name: {}", obj, obj.getClass().getName()); body = obj; } if ((flags & 0x2) != 0) { Object obj = input.readObject(); log.debug("Client id object: {} name: {}", obj, obj.getClass().getName()); clientId = ((String) obj); } if ((flags & 0x4) != 0) { Object obj = input.readObject(); log.debug("Destination object: {} name: {}", obj, obj.getClass().getName()); destination = ((String) obj); } if ((flags & 0x8) != 0) { Object obj = input.readObject(); log.debug("Headers object: {} name: {}", obj, obj.getClass().getName()); headers = ((ObjectMap) obj); } if ((flags & 0x10) != 0) { Object obj = input.readUTF(); log.debug("Message id object: {} name: {}", obj, obj.getClass().getName()); messageId = ((String) obj); } if ((flags & 0x20) != 0) { Object obj = input.readObject(); log.debug("Timestamp object: {} name: {}", obj, obj.getClass().getName()); timestamp = ((Number) obj).longValue(); } if ((flags & 0x40) != 0) { Object obj = input.readObject(); log.debug("TTL object: {} name: {}", obj, obj.getClass().getName()); timeToLive = ((Number) obj).longValue(); } reservedPosition = 7; } else if (i == 1) { if ((flags & 0x1) != 0) { Object obj = input.readObject(); log.debug("Client id (bytes) object: {} name: {}", obj, obj.getClass().getName()); if (obj instanceof ByteArray) { ByteArray ba = (ByteArray) obj; clientIdBytes = new byte[ba.length()]; ba.readBytes(clientIdBytes); clientId = RandomGUID.fromByteArray(clientIdBytes); } } if ((flags & 0x2) != 0) { Object obj = input.readObject(); log.debug("Message id (bytes) object: {} name: {}", obj, obj.getClass().getName()); if (obj instanceof ByteArray) { ByteArray ba = (ByteArray) obj; messageIdBytes = new byte[ba.length()]; ba.readBytes(messageIdBytes); messageId = RandomGUID.fromByteArray(messageIdBytes); } } reservedPosition = 2; } if (flags >> reservedPosition == 0) { continue; } for (short j = reservedPosition; j < 6; j = (short) (j + 1)) { if ((flags >> j & 0x1) == 0) { continue; } input.readObject(); } } } public void writeExternal(IDataOutput output) { short flags = 0; if (clientIdBytes == null) { if (clientId == null) { clientIdBytes = null; } else { clientIdBytes = RandomGUID.toByteArray(clientId); } } if (messageIdBytes == null) { if (messageId == null) { messageIdBytes = null; } else { messageIdBytes = RandomGUID.toByteArray(messageId); } } if (body != null) { flags = (short) (flags | 0x1); } if ((clientId != null) && (clientIdBytes == null)) { flags = (short) (flags | 0x2); } if (destination != null) { flags = (short) (flags | 0x4); } if (headers != null) { flags = (short) (flags | 0x8); } if ((messageId != null) && (messageIdBytes == null)) { flags = (short) (flags | 0x10); } if (timestamp != 0L) { flags = (short) (flags | 0x20); } if (timeToLive != 0L) { flags = (short) (flags | 0x40); } if ((clientIdBytes != null) || (messageIdBytes != null)) { flags = (short) (flags | 0x80); } output.writeByte((byte) flags); flags = 0; if (clientIdBytes != null) { flags = (short) (flags | 0x1); } if (messageIdBytes != null) { flags = (short) (flags | 0x2); } if (flags != 0) { output.writeByte((byte) flags); } if (body != null) { output.writeObject(body); } if ((clientId != null) && (clientIdBytes == null)) { output.writeUTF(clientId); } if (destination != null) { output.writeUTF(destination); } if (headers != null) { output.writeObject(headers); } if ((messageId != null) && (messageIdBytes == null)) { output.writeUTF(this.messageId); } if (timestamp != 0L) { output.writeObject(Long.valueOf(timestamp)); } if (this.timeToLive != 0L) { output.writeObject(Long.valueOf(timeToLive)); } if (this.clientIdBytes != null) { output.writeObject(clientIdBytes); } if (this.messageIdBytes != null) { output.writeObject(messageIdBytes); } } } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/AsyncMessage.java0000644000175000017500000000664111706617130031361 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.messages; import org.red5.io.amf3.ByteArray; import org.red5.io.amf3.IDataInput; import org.red5.io.amf3.IDataOutput; import org.red5.io.utils.RandomGUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base class for for asynchronous Flex compatibility messages. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public class AsyncMessage extends AbstractMessage { private static final long serialVersionUID = -3549535089417916783L; protected static byte CORRELATION_ID_FLAG = 1; protected static byte CORRELATION_ID_BYTES_FLAG = 2; /** Id of message this message belongs to. */ public String correlationId; protected byte[] correlationIdBytes; /** {@inheritDoc} */ protected void addParameters(StringBuilder result) { super.addParameters(result); result.append(",correlationId="); result.append(correlationId); } public void setCorrelationId(String id) { correlationId = id; } public String getCorrelationId() { return correlationId; } static Logger log = LoggerFactory.getLogger(AsyncMessage.class); @Override public void readExternal(IDataInput in) { super.readExternal(in); short[] flagsArray = readFlags(in); for (int i = 0; i < flagsArray.length; ++i) { short flags = flagsArray[i]; short reservedPosition = 0; if (i == 0) { if ((flags & CORRELATION_ID_FLAG) != 0) { correlationId = ((String) in.readObject()); } if ((flags & CORRELATION_ID_BYTES_FLAG) != 0) { ByteArray ba = (ByteArray) in.readObject(); correlationIdBytes = new byte[ba.length()]; ba.readBytes(correlationIdBytes); correlationId = RandomGUID.fromByteArray(correlationIdBytes); } reservedPosition = 2; } if (flags >> reservedPosition == 0) { continue; } for (short j = reservedPosition; j < 6; j = (short) (j + 1)) { if ((flags >> j & 0x1) == 0) { continue; } in.readObject(); } } } @Override public void writeExternal(IDataOutput output) { super.writeExternal(output); if (this.correlationIdBytes == null) { this.correlationIdBytes = RandomGUID.toByteArray(this.correlationId); } short flags = 0; if ((this.correlationId != null) && (this.correlationIdBytes == null)) { flags = (short) (flags | CORRELATION_ID_FLAG); } if (this.correlationIdBytes != null) { flags = (short) (flags | CORRELATION_ID_BYTES_FLAG); } output.writeByte((byte) flags); if ((this.correlationId != null) && (this.correlationIdBytes == null)) { output.writeObject(this.correlationId); } if (this.correlationIdBytes != null) { output.writeObject(this.correlationIdBytes); } } } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/AsyncMessageExt.java0000644000175000017500000000324511706617130032037 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.messages; import org.red5.io.amf3.IDataOutput; import org.red5.io.amf3.IExternalizable; /** * An externalizable version of a given AsyncMessage. The class alias for this * class within flex is "DSA". * * @author Paul Gregoire (mondain@gmail.com) */ public class AsyncMessageExt extends AsyncMessage implements IExternalizable { private static final long serialVersionUID = -5371460213241777011L; private AsyncMessage message; public AsyncMessageExt() { } public AsyncMessageExt(AsyncMessage message) { this.setMessage(message); } public void setMessage(AsyncMessage message) { this.message = message; } public AsyncMessage getMessage() { return message; } @Override public void writeExternal(IDataOutput output) { if (this.message != null) { this.message.writeExternal(output); } else { super.writeExternal(output); } } } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/CommandMessage.java0000644000175000017500000000645011706617130031660 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.messages; import org.red5.io.amf3.ByteArray; import org.red5.io.amf3.IDataInput; import org.red5.io.utils.RandomGUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Command message as sent by the mx:RemoteObject tag. * * @see osflash documentation (external) * @see Adobe Livedocs (external) * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public class CommandMessage extends AsyncMessage { private static final long serialVersionUID = 8805045741686625945L; protected static byte OPERATION_FLAG = 1; public String messageRefType; /** Command id to execute. */ public int operation = Constants.UNKNOWN_OPERATION; public CommandMessage() { this.messageId = new RandomGUID().toString(); this.timestamp = System.currentTimeMillis(); } /** {@inheritDoc} */ protected void addParameters(StringBuilder result) { super.addParameters(result); result.append(",messageRefType="); result.append(messageRefType); result.append(",operation="); result.append(operation); } public int getOperation() { return operation; } public void setOperation(int operation) { this.operation = operation; } static Logger log = LoggerFactory.getLogger(CommandMessage.class); @Override public void readExternal(IDataInput in) { log.debug("CommandMessage - Read external"); super.readExternal(in); short[] flagsArray = readFlags(in); for (int i = 0; i < flagsArray.length; ++i) { short flags = flagsArray[i]; log.debug("Unsigned byte: {}", flags); short reservedPosition = 0; if (i == 0) { if ((flags & OPERATION_FLAG) != 0) { Integer obj = in.readInt(); log.debug("Operation object: {} name: {}", obj, obj.getClass().getName()); this.operation = obj.intValue(); } reservedPosition = 1; } if (flags >> reservedPosition == 0) { continue; } for (short j = reservedPosition; j < 6; j = (short) (j + 1)) { if ((flags >> j & 0x1) == 0) { continue; } Object obj = in.readObject(); log.debug("Object2: {} name: {}", obj, obj.getClass().getName()); if (obj instanceof ByteArray) { ByteArray ba = (ByteArray) obj; byte[] arr = new byte[ba.length()]; ba.readBytes(arr); log.debug("Array length: {} Data: {}", arr.length, RandomGUID.fromByteArray(arr)); } } } log.debug("Operation: {}", operation); } } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/ErrorMessage.java0000644000175000017500000000227011706617130031367 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.messages; /** * Compatibility flex error message to be returned to the client. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class ErrorMessage extends AsyncMessage { private static final long serialVersionUID = -9069412644250075809L; public String faultCode; public String faultDetail; public String faultString; public Object rootCause; public Object extendedData; } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/Constants.java0000644000175000017500000000376511706617130030757 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.messages; /** * Constants for the flex compatibility messages. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class Constants { /** Operation id of register command. */ public static final int SUBSCRIBE_OPERATION = 0; public static final int UNSUBSCRIBE_OPERATION = 1; /** Operation id of poll command. */ public static final int POLL_OPERATION = 2; /** Update given attributes from a data message. */ public static final int DATA_OPERATION_UPDATE_ATTRIBUTES = 3; public static final int CLIENT_SYNC_OPERATION = 4; /** Operation id of ping commands. */ public static final int CLIENT_PING_OPERATION = 5; /** Update destination based on nested DataMessage packet. */ public static final int DATA_OPERATION_UPDATE = 7; public static final int CLUSTER_REQUEST_OPERATION = 7; /** Operation id of authentication commands. */ public static final int LOGIN_OPERATION = 8; public static final int LOGOUT_OPERATION = 9; /** Set all attributes from a data message. */ public static final int DATA_OPERATION_SET = 10; public static final int SUBSCRIPTION_INVALIDATE_OPERATION = 10; public static final int MULTI_SUBSCRIBE_OPERATION = 11; public static final int UNKNOWN_OPERATION = 10000; } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/CommandMessageExt.java0000644000175000017500000000337611706617130032345 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.messages; import org.red5.io.amf3.IDataOutput; import org.red5.io.amf3.IExternalizable; /** * An externalizable version of a given CommandMessage. The class alias for this * class within flex is "DSC". * * @author Paul Gregoire (mondain@gmail.com) */ public class CommandMessageExt extends CommandMessage implements IExternalizable { private static final long serialVersionUID = -5371460213241777011L; private CommandMessage message; public CommandMessageExt() { } public CommandMessageExt(CommandMessage message) { this.message = message; } @Override public void writeExternal(IDataOutput out) { //if (this.message != null) //this.message.writeExternal(output); //else //super.writeExternal(output); if (message != null) { short flags = 0; if (this.operation != 0) { flags = (short) (flags | OPERATION_FLAG); } out.writeByte((byte) flags); if (this.operation != 0) { out.writeInt(operation); } } } } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/AcknowledgeMessage.java0000644000175000017500000000400111706617130032513 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.messages; import org.red5.io.amf3.IDataInput; import org.red5.io.amf3.IDataOutput; import org.red5.io.utils.RandomGUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Flex compatibility message that is returned to the client. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public class AcknowledgeMessage extends AsyncMessage { private static final long serialVersionUID = 228072709981643313L; static Logger log = LoggerFactory.getLogger(AcknowledgeMessage.class); public AcknowledgeMessage() { this.messageId = new RandomGUID().toString(); this.timestamp = System.currentTimeMillis(); } @Override public void readExternal(IDataInput in) { super.readExternal(in); short[] flagsArray = readFlags(in); for (int i = 0; i < flagsArray.length; ++i) { short flags = flagsArray[i]; short reservedPosition = 0; if (flags >> reservedPosition == 0) { continue; } for (short j = reservedPosition; j < 6; j = (short) (j + 1)) { if ((flags >> j & 0x1) == 0) { continue; } in.readObject(); } } } @Override public void writeExternal(IDataOutput output) { super.writeExternal(output); output.writeByte((byte) 0); } } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/messages/RemotingMessage.java0000644000175000017500000000305511706617130032064 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.messages; /** * Flex compatibility message that is sent by the mx:RemoteObject mxml tag. * * @see osflash documentation (external) * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class RemotingMessage extends AsyncMessage { private static final long serialVersionUID = 1491092800943415719L; /** Method to execute. */ public String operation; /** Value of the source attribute of mx:RemoteObject that sent the message. */ public String source; /** {@inheritDoc} */ protected void addParameters(StringBuilder result) { super.addParameters(result); result.append(",operation="); result.append(operation); result.append(",source="); result.append(source); } } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/io/0000755000175000017500000000000011760512575024734 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/io/ObjectProxy.java0000644000175000017500000000737011706617130030047 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.io; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.red5.io.amf3.IDataInput; import org.red5.io.amf3.IDataOutput; import org.red5.io.amf3.IExternalizable; /** * Flex ObjectProxy compatibility class. * * @see Adobe Livedocs (external) * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @param type * @param value */ public class ObjectProxy implements Map, IExternalizable { private String uid; private Object type; /** The proxied object. */ private Map item; /** Create new empty proxy. */ public ObjectProxy() { this(new HashMap()); } /** * Create proxy for given object. * * @param item object to proxy */ public ObjectProxy(Map item) { this.item = new HashMap(item); } /** {@inheritDoc} */ @SuppressWarnings("unchecked") public void readExternal(IDataInput input) { item = (Map) input.readObject(); } /** {@inheritDoc} */ public void writeExternal(IDataOutput output) { output.writeObject(item); } /** * Return string representation of the proxied object. * * @return string */ public String toString() { return item.toString(); } public void clear() { item.clear(); } /** * Check if proxied object has a given property. * * @param name name * @return boolean */ public boolean containsKey(Object name) { return item.containsKey(name); } public boolean containsValue(Object value) { return item.containsValue(value); } public Set> entrySet() { return Collections.unmodifiableSet(item.entrySet()); } /** * Return the value of a property. * * @param name name * @return value */ public V get(Object name) { return item.get(name); } public boolean isEmpty() { return item.isEmpty(); } public Set keySet() { return item.keySet(); } /** * Change a property of the proxied object. * * @param name name * @param value value * @return old value */ public V put(T name, V value) { return item.put(name, value); } @SuppressWarnings({ "unchecked", "rawtypes" }) public void putAll(Map values) { item.putAll(values); } /** * Remove a property from the proxied object. * * @param name name * @return old value */ public V remove(Object name) { return item.remove(name); } public int size() { return item.size(); } public Collection values() { return Collections.unmodifiableCollection(item.values()); } /** * @return the uid */ public String getUid() { return uid; } /** * @param uid the uid to set */ public void setUid(String uid) { this.uid = uid; } /** * @return the type */ public Object getType() { return type; } /** * @param type the type to set */ public void setType(Object type) { this.type = type; } // TODO: implement other ObjectProxy methods } red5-1.0~svn4374.orig/src/org/red5/compatibility/flex/messaging/io/ArrayCollection.java0000644000175000017500000000341011706617130030660 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.compatibility.flex.messaging.io; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.red5.io.amf3.IDataInput; import org.red5.io.amf3.IDataOutput; import org.red5.io.amf3.IExternalizable; /** * Flex ArrayCollection compatibility class. * * @see Adobe Livedocs (external) * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @param type of collection */ public class ArrayCollection extends ArrayList implements Collection, IExternalizable { /** Serial number */ private static final long serialVersionUID = -9086041828446362637L; /** {@inheritDoc} */ @SuppressWarnings({ "unchecked", "rawtypes" }) public void readExternal(IDataInput input) { clear(); Object tmp = input.readObject(); if (tmp != null) { addAll((List) tmp); } } /** {@inheritDoc} */ public void writeExternal(IDataOutput output) { output.writeObject(this.toArray()); } } red5-1.0~svn4374.orig/src/org/red5/annotations/0000755000175000017500000000000011760512575021076 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/annotations/Anonymous.java0000644000175000017500000000242511706617130023725 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation for classes that should be serialized without their classname. * * This should only be used if you know what you're doing and currently is * only added to Red5 internal classes. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Anonymous { } red5-1.0~svn4374.orig/src/org/red5/annotations/DeclareProtected.java0000644000175000017500000000244711706617130025152 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation for public methods that should be protected by a named permission * when called through RTMP, RTMPT or Remoting. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DeclareProtected { /** * Permission required to execute method. */ String permission(); } red5-1.0~svn4374.orig/src/org/red5/annotations/RemoteClass.java0000644000175000017500000000242411706617130024155 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.annotations; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation for classes that should be serialized with a different classname. * * @author The Red5 Project (red5@osflash.org) * @author Harald Radi (harald.radi@catalysts.cc) */ @Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface RemoteClass { String alias(); } red5-1.0~svn4374.orig/src/org/red5/annotations/DontSerialize.java0000644000175000017500000000231011711413330024472 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation for fields that should not be serialized when sending * objects to a client. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface DontSerialize { } red5-1.0~svn4374.orig/src/org/red5/annotations/DeclarePrivate.java0000644000175000017500000000227111706617130024626 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation for public methods that should not be callable through RTMP, RTMPT * or Remoting. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DeclarePrivate { } red5-1.0~svn4374.orig/src/org/red5/server/0000755000175000017500000000000011760512574020046 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/0000755000175000017500000000000011760512572020632 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/IHandshake.java0000644000175000017500000000202311706617130023465 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net; import org.apache.mina.core.buffer.IoBuffer; /** * Base interface for Handshake classes. * * @author Paul Gregoire (mondain@gmail.com) */ public interface IHandshake { public IoBuffer doHandshake(IoBuffer input); public boolean validate(IoBuffer input); } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmpt/0000755000175000017500000000000011760512572022000 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/rtmpt/RTMPTServlet.java0000644000175000017500000004272411752053415025124 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmpt; import java.io.IOException; import java.net.URL; import java.util.Collection; import java.util.List; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.DummySession; import org.apache.mina.core.session.IoSession; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.Red5; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.rtmp.IRTMPConnManager; import org.red5.server.net.rtmp.RTMPConnection; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.servlet.ServletUtils; import org.slf4j.Logger; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; /** * Servlet that handles all RTMPT requests. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public class RTMPTServlet extends HttpServlet { /** * Serialization UID */ private static final long serialVersionUID = 5925399677454936613L; /** * Logger */ protected static Logger log = Red5LoggerFactory.getLogger(RTMPTServlet.class); /** * HTTP request method to use for RTMPT calls. */ private static final String REQUEST_METHOD = "POST"; /** * Content-Type to use for RTMPT requests / responses. */ private static final String CONTENT_TYPE = "application/x-fcs"; /** * Try to generate responses that contain at least 32768 bytes data. * Increasing this value results in better stream performance, but also increases the latency. */ private static int targetResponseSize = 32768; /** * Web app context */ protected transient WebApplicationContext appCtx; /** * Reference to RTMPT handler; */ private static RTMPTHandler handler; private static IRTMPConnManager rtmpConnManager; // Response sent for ident2 requests. If this is null a 404 will be returned private static String ident2; // Whether or not to enforce content type checking for requests private boolean enforceContentTypeCheck; public void setRtmpConnManager(IRTMPConnManager rtmpConnManager) { RTMPTServlet.rtmpConnManager = rtmpConnManager; } /** * Set the RTMPTHandler to use in this servlet. * * @param handler handler */ public void setHandler(RTMPTHandler handler) { RTMPTServlet.handler = handler; } /** * Set the fcs/ident2 string * * @param ident2 */ public void setIdent2(String ident2) { RTMPTServlet.ident2 = ident2; } /** * Sets the target size for responses * * @param targetResponseSize the targetResponseSize to set */ public void setTargetResponseSize(int targetResponseSize) { RTMPTServlet.targetResponseSize = targetResponseSize; } /** * Return an error message to the client. * * @param message * Message * @param resp * Servlet response * @throws IOException * I/O exception */ protected void handleBadRequest(String message, HttpServletResponse resp) throws IOException { log.debug("handleBadRequest {}", message); resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); resp.setContentType("text/plain"); resp.setContentLength(message.length()); resp.getWriter().write(message); resp.flushBuffer(); } /** * Return a single byte to the client. * * @param message * Message * @param resp * Servlet response * @throws IOException * I/O exception */ protected void returnMessage(byte message, HttpServletResponse resp) throws IOException { log.debug("returnMessage {}", message); resp.setStatus(HttpServletResponse.SC_OK); resp.setHeader("Connection", "Keep-Alive"); resp.setHeader("Cache-Control", "no-cache"); resp.setContentType(CONTENT_TYPE); resp.setContentLength(1); resp.getWriter().write(message); resp.flushBuffer(); } /** * Return a message to the client. * * @param message * Message * @param resp * Servlet response * @throws IOException * I/O exception */ protected void returnMessage(String message, HttpServletResponse resp) throws IOException { log.debug("returnMessage {}", message); resp.setStatus(HttpServletResponse.SC_OK); resp.setHeader("Connection", "Keep-Alive"); resp.setHeader("Cache-Control", "no-cache"); resp.setContentType(CONTENT_TYPE); resp.setContentLength(message.length()); resp.getWriter().write(message); resp.flushBuffer(); } /** * Return raw data to the client. * * @param client * RTMP connection * @param buffer * Raw data as byte buffer * @param resp * Servlet response * @throws IOException * I/O exception */ protected void returnMessage(RTMPTConnection client, IoBuffer buffer, HttpServletResponse resp) throws IOException { log.debug("returnMessage {}", buffer); resp.setStatus(HttpServletResponse.SC_OK); resp.setHeader("Connection", "Keep-Alive"); resp.setHeader("Cache-Control", "no-cache"); resp.setContentType(CONTENT_TYPE); log.debug("Sending {} bytes", buffer.limit()); resp.setContentLength(buffer.limit() + 1); ServletOutputStream output = resp.getOutputStream(); output.write(client.getPollingDelay()); ServletUtils.copy(buffer.asInputStream(), output); buffer.free(); buffer = null; } /** * Return the client id from a url like /send/123456/12 -> 123456 * * @param req Servlet request * @return Client id */ protected Integer getClientId(HttpServletRequest req) { String uri = req.getRequestURL().toString(); URL url = null; try { url = new URL(uri); } catch (Exception e) { log.warn("getclientId: error parsing url: {}", uri); return null; } // get path String path = url.getPath(); if (path.equals("")) { log.error("getClientId: path is empty"); return null; } // trim off end int pos = path.lastIndexOf('/'); path = path.substring(0, pos); // trim off beginning pos = path.lastIndexOf('/'); if (pos != -1) { path = path.substring(pos + 1); } try { return Integer.valueOf(path); } catch (Exception e) { log.error("getClientId: parse error", e); return null; } } /** * Get the RTMPT client for a session. * * @param req * Servlet request * @return RTMP client connection */ protected RTMPTConnection getClientConnection(HttpServletRequest req) { final Integer id = getClientId(req); return getConnection(id); } /** * Skip data sent by the client. * * @param req * Servlet request * @throws IOException * I/O exception */ protected void skipData(HttpServletRequest req) throws IOException { log.debug("skipData {}", req); IoBuffer data = IoBuffer.allocate(req.getContentLength()); ServletUtils.copy(req.getInputStream(), data.asOutputStream()); data.flip(); data.free(); data = null; } /** * Send pending messages to client. * * @param client * RTMP connection * @param resp * Servlet response * @throws IOException * I/O exception */ protected void returnPendingMessages(RTMPTConnection client, HttpServletResponse resp) throws IOException { log.debug("returnPendingMessages {}", client); IoBuffer data = client.getPendingMessages(targetResponseSize); if (data != null) { returnMessage(client, data, resp); } else { // no more messages to send... if (client.isClosing()) { // Tell client to close connection returnMessage((byte) 0, resp); } else { returnMessage(client.getPollingDelay(), resp); } } } /** * Start a new RTMPT session. * * @param req * Servlet request * @param resp * Servlet response * @throws ServletException * Servlet exception * @throws IOException * I/O exception */ protected void handleOpen(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { log.debug("handleOpen"); // Skip sent data skipData(req); // TODO: should we evaluate the pathinfo? RTMPTConnection connection = createConnection(); connection.setServlet(this); connection.setServletRequest(req); if (connection.getId() != 0) { // Return connection id to client returnMessage(connection.getId() + "\n", resp); } else { // no more clients are available for serving returnMessage((byte) 0, resp); } } /** * Close a RTMPT session. * * @param req * Servlet request * @param resp * Servlet response * @throws ServletException * Servlet exception * @throws IOException * I/O exception */ protected void handleClose(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { log.debug("handleClose"); // skip sent data skipData(req); // get the associated connection RTMPTConnection connection = getClientConnection(req); if (connection == null) { handleBadRequest(String.format("Close: unknown client with id: %s", getClientId(req)), resp); return; } removeConnection(connection.getId()); handler.connectionClosed(connection, connection.getState()); returnMessage((byte) 0, resp); connection.realClose(); } /** * Add data for an established session. * * @param req * Servlet request * @param resp * Servlet response * @throws ServletException * Servlet exception * @throws IOException * I/O exception */ protected void handleSend(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { log.debug("handleSend"); RTMPTConnection connection = getClientConnection(req); if (connection == null) { handleBadRequest(String.format("Send: unknown client with id: %s", getClientId(req)), resp); return; } else if (connection.getStateCode() == RTMP.STATE_DISCONNECTED) { removeConnection(connection.getId()); handleBadRequest("Connection already closed", resp); return; } // put the received data in a ByteBuffer int length = req.getContentLength(); IoBuffer data = IoBuffer.allocate(length); ServletUtils.copy(req.getInputStream(), data.asOutputStream()); data.flip(); // decode the objects in the data List messages = connection.decode(data); data.free(); data = null; if (messages == null || messages.isEmpty()) { returnMessage(connection.getPollingDelay(), resp); return; } // execute the received RTMP messages IoSession session = new DummySession(); session.setAttribute(RTMPConnection.RTMP_CONNECTION_KEY, connection); session.setAttribute(ProtocolState.SESSION_KEY, connection.getState()); for (Object message : messages) { try { handler.messageReceived(message, session); } catch (Exception e) { log.error("Could not process message", e); } } // send results to client returnPendingMessages(connection, resp); } /** * Poll RTMPT session for updates. * * @param req * Servlet request * @param resp * Servlet response * @throws ServletException * Servlet exception * @throws IOException * I/O exception */ protected void handleIdle(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { log.debug("handleIdle"); // skip sent data skipData(req); // get associated connection RTMPTConnection connection = getClientConnection(req); if (connection == null) { handleBadRequest("Idle: unknown client with id: " + getClientId(req), resp); return; } else if (connection.isClosing()) { // tell client to close the connection returnMessage((byte) 0, resp); connection.realClose(); return; } else if (connection.getStateCode() == RTMP.STATE_DISCONNECTED) { removeConnection(connection.getId()); handleBadRequest("Connection already closed", resp); return; } returnPendingMessages(connection, resp); } /** * Main entry point for the servlet. * * @param req * Request object * @param resp * Response object */ @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { log.debug("Request - method: {} content type: {} path: {}", new Object[] { req.getMethod(), req.getContentType(), req.getServletPath() }); // allow only POST requests with valid content length if (!REQUEST_METHOD.equals(req.getMethod()) || req.getContentLength() == 0) { // Bad request - return simple error page handleBadRequest("Bad request, only RTMPT supported.", resp); return; } // decide whether or not to enforce request content checks if (enforceContentTypeCheck && !CONTENT_TYPE.equals(req.getContentType())) { handleBadRequest(String.format("Bad request, unsupported content type: %s.", req.getContentType()), resp); return; } //get the path String path = req.getServletPath(); // since the only current difference in the type of request that we are interested in is the 'second' character, we can double // the speed of this entry point by using a switch on the second character. char p = path.charAt(1); switch (p) { case 'o': // OPEN_REQUEST handleOpen(req, resp); break; case 'c': // CLOSE_REQUEST handleClose(req, resp); break; case 's': // SEND_REQUEST handleSend(req, resp); break; case 'i': // IDLE_REQUEST handleIdle(req, resp); break; case 'f': // HTTPIdent request (ident and ident2) //if HTTPIdent is requested send back some Red5 info //http://livedocs.adobe.com/flashmediaserver/3.0/docs/help.html?content=08_xmlref_011.html String ident = "Red5Red5 Server"; // handle ident2 slightly different to appease osx clients String uri = req.getRequestURI().trim(); if (uri.charAt(uri.length() - 1) == '2') { // check for pre-configured ident2 value if (ident2 != null) { ident = ident2; } else { // just send 404 back if no ident2 value is set resp.setStatus(HttpServletResponse.SC_NOT_FOUND); resp.setHeader("Connection", "Keep-Alive"); resp.setHeader("Cache-Control", "no-cache"); resp.flushBuffer(); break; } } resp.setStatus(HttpServletResponse.SC_OK); resp.setHeader("Connection", "Keep-Alive"); resp.setHeader("Cache-Control", "no-cache"); resp.setContentType(CONTENT_TYPE); resp.setContentLength(ident.length()); resp.getWriter().write(ident); resp.flushBuffer(); break; default: handleBadRequest(String.format("RTMPT command %s is not supported.", path), resp); } // clear thread local reference Red5.setConnectionLocal(null); } /** {@inheritDoc} */ @Override public void init() throws ServletException { super.init(); ServletContext ctx = getServletContext(); appCtx = WebApplicationContextUtils.getWebApplicationContext(ctx); if (appCtx == null) { appCtx = (WebApplicationContext) ctx.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); } } /** {@inheritDoc} */ @Override public void destroy() { if (rtmpConnManager != null) { // Cleanup connections Collection conns = rtmpConnManager.removeConnections(); for (RTMPConnection conn : conns) { conn.close(); } } super.destroy(); } /** * A connection has been closed that was created by this servlet. * * @param conn */ protected void notifyClosed(RTMPTConnection conn) { rtmpConnManager.removeConnection(conn.getId()); } protected RTMPTConnection getConnection(int clientId) { RTMPTConnection conn = (RTMPTConnection) rtmpConnManager.getConnection(clientId); if (conn != null) { // clear thread local reference Red5.setConnectionLocal(conn); } else { log.warn("Null connection for clientId: {}", clientId); } return conn; } protected RTMPTConnection createConnection() { RTMPTConnection conn = (RTMPTConnection) rtmpConnManager.createConnection(RTMPTConnection.class); conn.setHandler(handler); conn.setDecoder(handler.getCodecFactory().getRTMPDecoder()); conn.setEncoder(handler.getCodecFactory().getRTMPEncoder()); handler.connectionOpened(conn, conn.getState()); // set thread local reference Red5.setConnectionLocal(conn); return conn; } protected void removeConnection(int clientId) { rtmpConnManager.removeConnection(clientId); } /** * @return the enforceContentTypeCheck */ public boolean isEnforceContentTypeCheck() { return enforceContentTypeCheck; } /** * @param enforceContentTypeCheck the enforceContentTypeCheck to set */ public void setEnforceContentTypeCheck(boolean enforceContentTypeCheck) { this.enforceContentTypeCheck = enforceContentTypeCheck; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmpt/RTMPTConnection.java0000644000175000017500000000776311752001621025573 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmpt; import javax.servlet.http.HttpServletRequest; import org.apache.mina.core.buffer.IoBuffer; import org.red5.logging.Red5LoggerFactory; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.servlet.ServletUtils; import org.slf4j.Logger; /** * A RTMPT client / session. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class RTMPTConnection extends BaseRTMPTConnection { private static final Logger log = Red5LoggerFactory.getLogger(RTMPTConnection.class); /** * Start to increase the polling delay after this many empty results */ private static final long INCREASE_POLLING_DELAY_COUNT = 10; /** * Polling delay to start with. */ private static final byte INITIAL_POLLING_DELAY = 0; /** * Maximum polling delay. */ private static final byte MAX_POLLING_DELAY = 32; /** * Polling delay value */ private byte pollingDelay = INITIAL_POLLING_DELAY; /** * Empty result counter, after reaching INCREASE_POLLING_DELAY_COUNT polling * delay will increase */ private long noPendingMessages; /** * Servlet that created this connection. */ private volatile RTMPTServlet servlet; /** Constructs a new RTMPTConnection. */ RTMPTConnection() { super(POLLING); state = new RTMP(); clientId = getNextClientId(); } /** * Set the servlet that created the connection. * * @param servlet */ protected void setServlet(RTMPTServlet servlet) { this.servlet = servlet; } /** {@inheritDoc} */ public void realClose() { super.realClose(); if (servlet != null) { servlet.notifyClosed(this); servlet = null; } } /** {@inheritDoc} */ @Override protected void onInactive() { log.debug("Inactive connection id: {}, closing", getId()); close(); realClose(); } /** * Setter for servlet request. * * @param request Servlet request */ public void setServletRequest(HttpServletRequest request) { host = request.getLocalName(); // Check if the request came in from the default port. // We strip default ports so don't include it in the host. if (request.getLocalPort() != 80) { host += ":" + request.getLocalPort(); } remoteAddress = request.getRemoteAddr(); remoteAddresses = ServletUtils.getRemoteAddresses(request); remotePort = request.getRemotePort(); } /** * Return the polling delay to use. * * @return the polling delay */ public byte getPollingDelay() { log.trace("getPollingDelay {}", pollingDelay); if (state.getState() == RTMP.STATE_DISCONNECTED) { // Special value to notify client about a closed connection. return (byte) 0; } return (byte) (pollingDelay + 1); } /** * {@inheritDoc} */ public IoBuffer getPendingMessages(int targetSize) { long currentPendingMessages = getPendingMessages(); if (currentPendingMessages == 0) { noPendingMessages += 1; if (noPendingMessages > INCREASE_POLLING_DELAY_COUNT) { if (pollingDelay == 0) { pollingDelay = 1; } pollingDelay = (byte) (pollingDelay * 2); if (pollingDelay > MAX_POLLING_DELAY) { pollingDelay = MAX_POLLING_DELAY; } } return null; } log.debug("Returning {} messages to client", currentPendingMessages); noPendingMessages = 0; pollingDelay = INITIAL_POLLING_DELAY; return foldPendingMessages(targetSize); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmpt/BaseRTMPTConnection.java0000644000175000017500000001620111752053415026361 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmpt; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicLong; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.net.rtmp.IRTMPHandler; import org.red5.server.net.rtmp.RTMPConnection; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.rtmp.codec.RTMPProtocolDecoder; import org.red5.server.net.rtmp.codec.RTMPProtocolEncoder; import org.red5.server.net.rtmp.message.Packet; import org.red5.server.net.rtmpt.codec.RTMPTProtocolDecoder; import org.red5.server.net.rtmpt.codec.RTMPTProtocolEncoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class BaseRTMPTConnection extends RTMPConnection { private static final Logger log = LoggerFactory.getLogger(BaseRTMPTConnection.class); /** * Protocol decoder */ private RTMPTProtocolDecoder decoder; /** * Protocol encoder */ private RTMPTProtocolEncoder encoder; private static class PendingData { private IoBuffer buffer; private Packet packet; private PendingData(IoBuffer buffer, Packet packet) { this.buffer = buffer; this.packet = packet; } private PendingData(IoBuffer buffer) { this.buffer = buffer; } public IoBuffer getBuffer() { return buffer; } public Packet getPacket() { return packet; } public String toString() { return getClass().getName() + "(buffer=" + buffer + "; packet=" + packet + ")"; } } /** * List of pending messages */ private ConcurrentLinkedQueue pendingMessages = new ConcurrentLinkedQueue(); /** * Closing flag */ private volatile boolean closing; /** * Number of read bytes */ private AtomicLong readBytes = new AtomicLong(0); /** * Number of written bytes */ private AtomicLong writtenBytes = new AtomicLong(0); /** * Byte buffer */ private IoBuffer buffer; /** * RTMP events handler */ private volatile IRTMPHandler handler; public BaseRTMPTConnection(String type) { super(type); this.buffer = IoBuffer.allocate(2048); this.buffer.setAutoExpand(true); } /** * Return any pending messages up to a given size. * * @param targetSize the size the resulting buffer should have * @return a buffer containing the data to send or null if no messages are * pending */ abstract public IoBuffer getPendingMessages(int targetSize); /** {@inheritDoc} */ @Override public void close() { log.debug("close - state: {}", state.getState()); // Defer actual closing so we can send back pending messages to the client. closing = true; } /** * Getter for property 'closing'. * * @return Value for property 'closing'. */ public boolean isClosing() { return closing; } /** * Real close */ public void realClose() { if (isClosing()) { if (buffer != null) { buffer.free(); buffer = null; } state.setState(RTMP.STATE_DISCONNECTED); pendingMessages.clear(); super.close(); } } /** * Send raw data down the connection. * * @param packet the buffer containing the raw data */ @Override public void writeRaw(IoBuffer packet) { pendingMessages.add(new PendingData(packet)); } /** {@inheritDoc} */ @Override public long getReadBytes() { return readBytes.get(); } /** {@inheritDoc} */ @Override public long getWrittenBytes() { return writtenBytes.get(); } /** {@inheritDoc} */ @Override public long getPendingMessages() { return pendingMessages.size(); } /** * Decode data sent by the client. * * @param data the data to decode * @return a list of decoded objects */ public List decode(IoBuffer data) { log.debug("decode"); if (closing || state.getState() == RTMP.STATE_DISCONNECTED) { // connection is being closed, don't decode any new packets return Collections.EMPTY_LIST; } readBytes.addAndGet(data.limit()); buffer.put(data); buffer.flip(); return decoder.decodeBuffer(state, buffer); } /** * Send RTMP packet down the connection. * * @param packet the packet to send */ @Override public void write(final Packet packet) { log.debug("write - packet: {}", packet); log.trace("state: {}", state); if (closing || state.getState() == RTMP.STATE_DISCONNECTED) { // connection is being closed, don't send any new packets return; } IoBuffer data; try { data = encoder.encode(state, packet); } catch (Exception e) { log.error("Could not encode message {}", packet, e); return; } if (data != null) { // mark packet as being written writingMessage(packet); // add to pending pendingMessages.add(new PendingData(data, packet)); } else { log.info("Response buffer was null after encoding"); } } protected IoBuffer foldPendingMessages(int targetSize) { log.debug("foldPendingMessages - target size: {}", targetSize); if (!pendingMessages.isEmpty()) { int sendSize = 0; LinkedList sendList = new LinkedList(); while (!pendingMessages.isEmpty()) { PendingData pendingMessage = pendingMessages.peek(); // get the buffer size int limit = pendingMessage.getBuffer().limit(); if ((limit + sendSize) < targetSize) { pendingMessage = pendingMessages.remove(); if (sendList.add(pendingMessage)) { sendSize += limit; } } else { break; } } log.debug("Send size: {}", sendSize); IoBuffer result = IoBuffer.allocate(sendSize); for (PendingData pendingMessage : sendList) { result.put(pendingMessage.getBuffer()); if (pendingMessage.getPacket() != null) { try { handler.messageSent(this, pendingMessage.getPacket()); } catch (Exception e) { log.error("Could not notify stream subsystem about sent message", e); } } } sendList.clear(); result.flip(); writtenBytes.addAndGet(sendSize); return result; } else { return null; } } public void setHandler(IRTMPHandler handler) { this.handler = handler; } public void setDecoder(RTMPProtocolDecoder decoder) { this.decoder = (RTMPTProtocolDecoder) decoder; } public void setEncoder(RTMPProtocolEncoder encoder) { this.encoder = (RTMPTProtocolEncoder) encoder; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmpt/RTMPTHandler.java0000644000175000017500000000734111752053415025051 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmpt; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.rtmp.InboundHandshake; import org.red5.server.net.rtmp.RTMPConnection; import org.red5.server.net.rtmp.RTMPHandler; import org.red5.server.net.rtmp.RTMPHandshake; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.rtmpt.codec.RTMPTCodecFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Handler for RTMPT messages. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public class RTMPTHandler extends RTMPHandler { /** * Logger */ private static final Logger log = LoggerFactory.getLogger(RTMPTHandler.class); /** * Handler constant */ public static final String HANDLER_ATTRIBUTE = "red5.RMPTHandler"; /** * Protocol codec factory */ protected RTMPTCodecFactory codecFactory; /** * Setter for codec factory * * @param factory Codec factory to use */ public void setCodecFactory(RTMPTCodecFactory factory) { this.codecFactory = factory; } /** * Getter for codec factory * * @return Codec factory */ public RTMPTCodecFactory getCodecFactory() { return this.codecFactory; } /** * Return hostname for URL. * * @param url * URL * @return Hostname from that URL */ @Override protected String getHostname(String url) { log.debug("url: {}", url); String[] parts = url.split("/"); if (parts.length == 2) { return ""; } else { String host = parts[2]; // Strip out default port in case the client // added the port explicitly. if (host.endsWith(":80")) { // Remove default port from connection string return host.substring(0, host.length() - 3); } return host; } } /** * Handle raw buffer received * @param conn RTMP connection * @param state Protocol state * @param in Byte buffer with input raw data */ private void rawBufferReceived(RTMPTConnection conn, RTMP state, IoBuffer in) { log.debug("rawBufferRecieved: {}", in); if (state.getState() != RTMP.STATE_HANDSHAKE) { log.warn("Raw buffer after handshake, something odd going on"); } log.debug("Writing handshake reply, handskake size: {}", in.remaining()); RTMPHandshake shake = new InboundHandshake(); shake.setHandshakeType(RTMPConnection.RTMP_NON_ENCRYPTED); conn.writeRaw(shake.doHandshake(in)); } /** {@inheritDoc} */ @Override public void messageReceived(Object in, IoSession session) throws Exception { log.debug("messageReceived"); if (in instanceof IoBuffer) { RTMPTConnection conn = (RTMPTConnection) session.getAttribute(RTMPConnection.RTMP_CONNECTION_KEY); RTMP state = (RTMP) session.getAttribute(ProtocolState.SESSION_KEY); log.trace("state: {}", state); rawBufferReceived(conn, state, (IoBuffer) in); ((IoBuffer) in).free(); in = null; } else { super.messageReceived(in, session); } } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmpt/codec/0000755000175000017500000000000011760512572023055 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/rtmpt/codec/RTMPTProtocolDecoder.java0000644000175000017500000000172711706617130027641 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmpt.codec; import org.red5.server.net.rtmp.codec.RTMPProtocolDecoder; /** * RTMPT protocol decoder. To be implemeted. */ public class RTMPTProtocolDecoder extends RTMPProtocolDecoder { /* * Nothing special here right now... */ } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmpt/codec/RTMPTCodecFactory.java0000644000175000017500000000477511752053415027126 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmpt.codec; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; import org.red5.server.net.rtmp.codec.RTMPCodecFactory; import org.red5.server.net.rtmp.codec.RTMPProtocolDecoder; import org.red5.server.net.rtmp.codec.RTMPProtocolEncoder; /** * RTMPT codec factory creates RTMP codec objects */ public class RTMPTCodecFactory extends RTMPCodecFactory { /** * RTMP decoder */ private RTMPTProtocolDecoder decoder; /** * RTMP encoder */ private RTMPTProtocolEncoder encoder; private long baseTolerance = 5000; private boolean dropLiveFuture; /** * Initialization */ public void init() { decoder = new RTMPTProtocolDecoder(); decoder.setDeserializer(deserializer); encoder = new RTMPTProtocolEncoder(); encoder.setSerializer(serializer); encoder.setBaseTolerance(baseTolerance); encoder.setDropLiveFuture(dropLiveFuture); } /** * Setter for deserializer. * * @param deserializer Deserializer used by this codec factory. */ public void setDeserializer(Deserializer deserializer) { this.deserializer = deserializer; } /** * Setter for serializer * * @param serializer Value to set for property 'serializer'. */ public void setSerializer(Serializer serializer) { this.serializer = serializer; } /** * @param baseTolerance the baseTolerance to set */ public void setBaseTolerance(long baseTolerance) { this.baseTolerance = baseTolerance; } /** * @param dropLiveFuture the dropLiveFuture to set */ public void setDropLiveFuture(boolean dropLiveFuture) { this.dropLiveFuture = dropLiveFuture; } /** {@inheritDoc} */ @Override public RTMPProtocolDecoder getRTMPDecoder() { return decoder; } /** {@inheritDoc} */ @Override public RTMPProtocolEncoder getRTMPEncoder() { return encoder; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmpt/codec/RTMPTProtocolEncoder.java0000644000175000017500000000367611752053415027661 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmpt.codec; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.service.IServiceCall; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.rtmp.codec.RTMPProtocolEncoder; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.status.Status; /** * RTMPT protocol encoder. To be implemented. */ public class RTMPTProtocolEncoder extends RTMPProtocolEncoder { @Override protected void encodeNotifyOrInvoke(IoBuffer out, Notify invoke, RTMP rtmp) { // if we get an InsufficientBW message for the client, we'll reduce the // base tolerance and set drop live to true final IServiceCall call = invoke.getCall(); if ("onStatus".equals(call.getServiceMethodName()) && call.getArguments().length >= 1) { Object arg0 = call.getArguments()[0]; if ("NetStream.Play.InsufficientBW".equals(((Status) arg0).getCode())) { long baseT = getBaseTolerance(); try { // drop the tolerances by half but not less than 500 setBaseTolerance(Math.max(baseT / 2, 500)); } catch (Exception e) { log.debug("Problem setting base tolerance: {}", e.getMessage()); } setDropLiveFuture(true); } } super.encodeNotifyOrInvoke(out, invoke, rtmp); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmps/0000755000175000017500000000000011760512572021777 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/rtmps/RTMPSMinaIoHandler.java0000644000175000017500000001350711752001621026135 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmps; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.NotActiveException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.ssl.SslFilter; import org.red5.server.net.rtmp.RTMPMinaIoHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Handles Native RTMPS protocol events fired by the MINA framework. *
 * var nc:NetConnection = new NetConnection();
 * nc.proxyType = "best";
 * nc.connect("rtmps:\\localhost\app");
 * 
* Originally created by: Kevin Green * * http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html * http://java.sun.com/j2se/1.5.0/docs/guide/security/CryptoSpec.html#AppA * http://java.sun.com/j2se/1.5.0/docs/api/java/security/KeyStore.html * http://tomcat.apache.org/tomcat-3.3-doc/tomcat-ssl-howto.html * * @author Kevin Green (kevygreen@gmail.com) * @author Paul Gregoire (mondain@gmail.com) */ public class RTMPSMinaIoHandler extends RTMPMinaIoHandler { private static Logger log = LoggerFactory.getLogger(RTMPSMinaIoHandler.class); /** * Password for accessing the keystore. */ private char[] password; /** * Stores the keystore file bytes. */ private byte[] keystore; /** * The keystore type, valid options are JKS and PKCS12 */ private String keyStoreType = "JKS"; /** {@inheritDoc} */ @Override public void sessionOpened(IoSession session) throws Exception { if (password == null || keystore == null) { throw new NotActiveException("Keystore or password are null"); } // START OF NATIVE SSL STUFF SSLContext context = SSLContext.getInstance("TLS"); //TLS, TLSv1, TLSv1.1 // The reference implementation only supports X.509 keys KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); //initialize the key manager kmf.init(getKeyStore(), password); // initialize the ssl context context.init(kmf.getKeyManagers(), null, null); //create the ssl filter using server mode SslFilter sslFilter = new SslFilter(context); if (sslFilter != null) { session.getFilterChain().addFirst("sslFilter", sslFilter); } // END OF NATIVE SSL STUFF super.sessionOpened(session); } /** {@inheritDoc} */ @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { log.warn("Exception caught {}", cause.getMessage()); if (log.isDebugEnabled()) { log.error("Exception detail", cause); } //if there are any errors using ssl, kill the session session.close(true); } /** * Returns a KeyStore. * @return KeyStore * @throws IOException * @throws CertificateException * @throws NoSuchAlgorithmException * @throws KeyStoreException */ private KeyStore getKeyStore() throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException { // Sun's default kind of key store KeyStore ks = KeyStore.getInstance(keyStoreType); // For security, every key store is encrypted with a // pass phrase that must be provided before we can load // it from disk. The pass phrase is stored as a char[] array // so it can be wiped from memory quickly rather than // waiting for a garbage collector. Of course using a string // literal here completely defeats that purpose. ks.load(new ByteArrayInputStream(keystore), password); return ks; } /** * Password used to access the keystore file. * * @param password */ public void setKeyStorePassword(String password) { this.password = password.toCharArray(); } /** * Set keystore data from a file. * * @param path contains keystore */ public void setKeystoreFile(String path) { FileInputStream fis = null; try { File file = new File(path); if (file.exists()) { fis = new FileInputStream(file); FileChannel fc = fis.getChannel(); ByteBuffer fb = ByteBuffer.allocate(Long.valueOf(file.length()).intValue()); fc.read(fb); fb.flip(); keystore = IoBuffer.wrap(fb).array(); } else { log.warn("Keystore file does not exist: {}", path); } file = null; } catch (Exception e) { log.warn("Error setting keystore data", e); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { } } } } /** * Set keystore data from a file. * * @param arr keystore bytes */ public void setKeystoreBytes(byte[] arr) { keystore = new byte[arr.length]; System.arraycopy(arr, 0, keystore, 0, arr.length); } /** * Set the key store type, JKS or PKCS12. * * @param keyStoreType */ public void setKeyStoreType(String keyStoreType) { this.keyStoreType = keyStoreType; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmpe/0000755000175000017500000000000011760512572021761 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/rtmpe/RTMPEIoFilter.java0000644000175000017500000001534311706617130025153 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmpe; import javax.crypto.Cipher; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.filterchain.IoFilterAdapter; import org.apache.mina.core.session.IoSession; import org.apache.mina.core.write.WriteRequest; import org.apache.mina.core.write.WriteRequestWrapper; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.rtmp.RTMPConnection; import org.red5.server.net.rtmp.RTMPHandshake; import org.red5.server.net.rtmp.RTMPMinaConnection; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.rtmp.message.Constants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * RTMPE IO filter * * @author Peter Thomas (ptrthomas@gmail.com) * @author Paul Gregoire (mondain@gmail.com) */ public class RTMPEIoFilter extends IoFilterAdapter { private static final Logger log = LoggerFactory.getLogger(RTMPEIoFilter.class); @Override public void messageReceived(NextFilter nextFilter, IoSession session, Object obj) throws Exception { RTMP rtmp = (RTMP) session.getAttribute(ProtocolState.SESSION_KEY); //if there is a handshake on the session, ensure the type has been set if (session.containsAttribute(RTMPConnection.RTMP_HANDSHAKE)) { log.trace("Handshake exists on the session"); //get the handshake from the session RTMPHandshake handshake = (RTMPHandshake) session.getAttribute(RTMPConnection.RTMP_HANDSHAKE); int handshakeType = handshake.getHandshakeType(); if (handshakeType == 0) { log.trace("Handshake type is not currently set"); // holds the handshake type, default is un-encrypted byte handshakeByte = RTMPConnection.RTMP_NON_ENCRYPTED; //get the current message if (obj instanceof IoBuffer) { IoBuffer message = (IoBuffer) obj; message.mark(); handshakeByte = message.get(); message.reset(); } //set the type handshake.setHandshakeType(handshakeByte); //set on the rtmp state rtmp.setEncrypted(handshakeByte == RTMPConnection.RTMP_ENCRYPTED ? true : false); } else if (handshakeType == 3) { if (rtmp.getState() == RTMP.STATE_CONNECTED) { log.debug("In connected state"); // remove handshake from session now that we are connected session.removeAttribute(RTMPConnection.RTMP_HANDSHAKE); log.debug("Using non-encrypted communications"); } } else if (handshakeType == 6) { // ensure we have received enough bytes to be encrypted RTMPMinaConnection conn = (RTMPMinaConnection) session.getAttribute(RTMPConnection.RTMP_CONNECTION_KEY); long readBytesCount = conn.getReadBytes(); long writeBytesCount = conn.getWrittenBytes(); log.trace("Bytes read: {} written: {}", readBytesCount, writeBytesCount); // don't remove the handshake when using RTMPE until we've written all the handshake data if (writeBytesCount >= (Constants.HANDSHAKE_SIZE * 2)) { //if we are connected and doing encryption, add the ciphers log.debug("Assumed to be in a connected state"); // remove handshake from session now that we are connected session.removeAttribute(RTMPConnection.RTMP_HANDSHAKE); log.debug("Using encrypted communications"); //make sure they are not already on the session if (session.containsAttribute(RTMPConnection.RTMPE_CIPHER_IN)) { log.debug("Ciphers already exist on the session"); } else { log.debug("Adding ciphers to the session"); session.setAttribute(RTMPConnection.RTMPE_CIPHER_IN, handshake.getCipherIn()); session.setAttribute(RTMPConnection.RTMPE_CIPHER_OUT, handshake.getCipherOut()); } } } } Cipher cipher = (Cipher) session.getAttribute(RTMPConnection.RTMPE_CIPHER_IN); if (cipher != null) { //may want to verify handshake is complete as well // assume message is an IoBuffer IoBuffer message = (IoBuffer) obj; if (rtmp.getState() == RTMP.STATE_HANDSHAKE) { //skip the first 1536 byte[] handshakeReply = new byte[Constants.HANDSHAKE_SIZE]; message.get(handshakeReply); // TODO verify reply, for now just set to connected rtmp.setState(RTMP.STATE_CONNECTED); } log.debug("Decrypting buffer: {}", message); byte[] encrypted = new byte[message.remaining()]; message.get(encrypted); message.clear(); message.free(); byte[] plain = cipher.update(encrypted); IoBuffer messageDecrypted = IoBuffer.wrap(plain); log.debug("Decrypted buffer: {}", messageDecrypted); nextFilter.messageReceived(session, messageDecrypted); } else { log.trace("Not decrypting message received: {}", obj); nextFilter.messageReceived(session, obj); } } @Override public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest request) throws Exception { Cipher cipher = (Cipher) session.getAttribute(RTMPConnection.RTMPE_CIPHER_OUT); if (cipher != null) { //may want to verify handshake is complete as well IoBuffer message = (IoBuffer) request.getMessage(); if (!message.hasRemaining()) { // Ignore empty buffers log.debug("Buffer was empty"); } else { log.debug("Encrypting buffer: {}", message); byte[] plain = new byte[message.remaining()]; message.get(plain); message.clear(); message.free(); //encrypt and write byte[] encrypted = cipher.update(plain); IoBuffer messageEncrypted = IoBuffer.wrap(encrypted); log.debug("Encrypted buffer: {}", messageEncrypted); nextFilter.filterWrite(session, new EncryptedWriteRequest(request, messageEncrypted)); } } else { log.trace("Not encrypting write request"); nextFilter.filterWrite(session, request); } } private static class EncryptedWriteRequest extends WriteRequestWrapper { private final IoBuffer encryptedMessage; private EncryptedWriteRequest(WriteRequest writeRequest, IoBuffer encryptedMessage) { super(writeRequest); this.encryptedMessage = encryptedMessage; } @Override public Object getMessage() { return encryptedMessage; } } } red5-1.0~svn4374.orig/src/org/red5/server/net/IConnectionEventQueue.java0000644000175000017500000000265511706617130025720 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net; import java.util.Iterator; import org.red5.server.api.IConnection; import org.red5.server.api.event.IEvent; /** * Queue of connection events */ public interface IConnectionEventQueue { /** * Whether queue has waiting connection events * @param conn Connection * @return true if queue has waiting events for connection, false otherwise */ public boolean hasEventsWaiting(IConnection conn); /** * Return iterator over waiting events * @param conn Connection * @return Iterator over events */ public Iterator pickupEvents(IConnection conn); } red5-1.0~svn4374.orig/src/org/red5/server/net/servlet/0000755000175000017500000000000011760512572022316 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/servlet/RedirectHTTPServlet.java0000644000175000017500000000356411706617130026773 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet to redirect to HTTP port of Red5. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class RedirectHTTPServlet extends HttpServlet { /** * Serialization UID */ private static final long serialVersionUID = -3543614516289102090L; /** * Redirect to HTTP port. */ @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String host = System.getProperty("http.host"); String port = System.getProperty("http.port"); if ("0.0.0.0".equals(host)) { host = "127.0.0.1"; } resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); resp.addHeader("Location", "http://" + host + ":" + port); resp.setContentType("text/plain"); String message = "Relocated to http://" + host + ":" + port; resp.setContentLength(message.length()); resp.getWriter().write(message); resp.flushBuffer(); } } red5-1.0~svn4374.orig/src/org/red5/server/net/servlet/ServletUtils.java0000644000175000017500000000733311706617130025630 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.servlet; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.servlet.http.HttpServletRequest; public class ServletUtils { /** * Default value is 2048. */ public static final int DEFAULT_BUFFER_SIZE = 2048; /** * Copies information from the input stream to the output stream using a * default buffer size of 2048 bytes. * @param input input * @param output output * * @throws java.io.IOException on error */ public static void copy(InputStream input, OutputStream output) throws IOException { copy(input, output, DEFAULT_BUFFER_SIZE); } /** * Copies information from the input stream to the output stream using the * specified buffer size * * @param input input * @param bufferSize buffer size * @param output output * @throws java.io.IOException on error */ public static void copy(InputStream input, OutputStream output, int bufferSize) throws IOException { byte[] buf = new byte[bufferSize]; int bytesRead = input.read(buf); while (bytesRead != -1) { output.write(buf, 0, bytesRead); bytesRead = input.read(buf); } output.flush(); } /** * Copies information between specified streams and then closes both of the * streams. * * @param output output * @param input input * @throws java.io.IOException on error */ public static void copyThenClose(InputStream input, OutputStream output) throws IOException { copy(input, output); input.close(); output.close(); } /** * @param input input stream * @return a byte[] containing the information contained in the specified * InputStream. * @throws java.io.IOException on error */ public static byte[] getBytes(InputStream input) throws IOException { ByteArrayOutputStream result = new ByteArrayOutputStream(); copy(input, result); result.close(); return result.toByteArray(); } /** * Return all remote addresses that were involved in the passed request. * * @param request request * @return remote addresses */ public static List getRemoteAddresses(HttpServletRequest request) { List addresses = new ArrayList(); addresses.add(request.getRemoteHost()); if (!request.getRemoteAddr().equals(request.getRemoteHost())) { // Store both remote host and remote address addresses.add(request.getRemoteAddr()); } final String forwardedFor = request.getHeader("X-Forwarded-For"); if (forwardedFor != null) { // Also store address this request was forwarded for. final String[] parts = forwardedFor.split(","); for (String part : parts) { addresses.add(part); } } final String httpVia = request.getHeader("Via"); if (httpVia != null) { // Also store address this request was forwarded for. final String[] parts = httpVia.split(","); for (String part : parts) { addresses.add(part); } } return Collections.unmodifiableList(addresses); } } red5-1.0~svn4374.orig/src/org/red5/server/net/servlet/StatisticsServlet.java0000644000175000017500000000530211706617130026654 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.servlet; import java.io.IOException; import java.io.OutputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.xmlrpc.XmlRpcServer; import org.red5.server.api.IContext; import org.red5.server.statistics.XmlRpcScopeStatistics; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; /** * Servlet that processes the statistics XML-RPC requests. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class StatisticsServlet extends HttpServlet { private static final long serialVersionUID = 5810139109603229027L; private final transient XmlRpcServer server = new XmlRpcServer(); protected transient WebApplicationContext webAppCtx; protected transient IContext webContext; /** {@inheritDoc} */ @Override public void init() throws ServletException { webAppCtx = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); if (webAppCtx == null) { webAppCtx = (WebApplicationContext) getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); } if (webAppCtx == null) { throw new ServletException("No web application context found."); } webContext = (IContext) webAppCtx.getBean("web.context"); // Register handlers in XML-RPC server server.addHandler("scopes", new XmlRpcScopeStatistics(webContext.getGlobalScope())); } /** {@inheritDoc} */ @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Process request with XML-RPC server byte[] result = server.execute(request.getInputStream()); response.setContentType("text/xml"); response.setContentLength(result.length); OutputStream out = response.getOutputStream(); out.write(result); out.close(); } } red5-1.0~svn4374.orig/src/org/red5/server/net/servlet/AMFGatewayServlet.java0000644000175000017500000002247611747114732026467 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.servlet; import java.io.IOException; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.mina.core.buffer.IoBuffer; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.IContext; import org.red5.server.api.IServer; import org.red5.server.api.Red5; import org.red5.server.api.remoting.IRemotingConnection; import org.red5.server.api.scope.IGlobalScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.service.IServiceInvoker; import org.red5.server.net.remoting.RemotingConnection; import org.red5.server.net.remoting.codec.RemotingCodecFactory; import org.red5.server.net.remoting.message.RemotingCall; import org.red5.server.net.remoting.message.RemotingPacket; import org.slf4j.Logger; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; /** * Servlet that handles remoting requests. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) * @author Paul Gregoire (mondain@gmail.com) */ public class AMFGatewayServlet extends HttpServlet { private static final long serialVersionUID = 7174018823796785619L; /** * Logger */ protected Logger log = Red5LoggerFactory.getLogger(AMFGatewayServlet.class); /** * AMF MIME type */ public static final String APPLICATION_AMF = "application/x-amf"; /** * Web app context */ protected transient WebApplicationContext webAppCtx; /** * Red5 server instance */ protected transient IServer server; /** * Remoting codec factory */ protected transient RemotingCodecFactory codecFactory; /** * Request attribute holding the Red5 connection object */ private static final String CONNECTION = "red5.remotingConnection"; /** {@inheritDoc} */ @Override public void init() throws ServletException { } /** {@inheritDoc} */ @Override public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { log.debug("Servicing Request"); if (codecFactory == null) { ServletContext ctx = getServletContext(); log.debug("Context path: {}", ctx.getContextPath()); //attempt to lookup the webapp context webAppCtx = WebApplicationContextUtils.getRequiredWebApplicationContext(ctx); //now try to look it up as an attribute if (webAppCtx == null) { log.debug("Webapp context was null, trying lookup as attr."); webAppCtx = (WebApplicationContext) ctx .getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); } //lookup the server and codec factory if (webAppCtx != null) { server = (IServer) webAppCtx.getBean("red5.server"); codecFactory = (RemotingCodecFactory) webAppCtx.getBean("remotingCodecFactory"); } else { log.debug("No web context"); } } log.debug("Remoting request {} {}", req.getContextPath(), req.getServletPath()); if (APPLICATION_AMF.equals(req.getContentType())) { serviceAMF(req, resp); } else { resp.getWriter().write("Red5 : Remoting Gateway"); } } /** * Return the global scope to use for the given request. * * @param req * @return scope */ protected IGlobalScope getGlobalScope(HttpServletRequest req) { String path = req.getContextPath() + req.getServletPath(); log.debug("getGlobalScope path: {}", path); if (path.startsWith("/")) { path = path.substring(1); } else { log.debug("Path length: {} Servlet name length: {}", path.length(), getServletName().length()); path = path.substring(0, path.length() - getServletName().length() - 1); } IGlobalScope global = server.lookupGlobal(req.getServerName(), path); if (global == null) { global = server.lookupGlobal(req.getLocalName(), path); if (global == null) { global = server.lookupGlobal(req.getLocalAddr(), path); } } return global; } /** * Works out AMF request * * @param req * Request * @param resp * Response * @throws ServletException * Servlet exception * @throws IOException * I/O exception */ protected void serviceAMF(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { log.debug("Servicing AMF"); IRemotingConnection conn = null; try { RemotingPacket packet = decodeRequest(req); if (packet == null) { log.error("Packet should not be null"); return; } // Provide a valid IConnection in the Red5 object final IGlobalScope global = getGlobalScope(req); final IContext context = global.getContext(); final IScope scope = context.resolveScope(global, packet.getScopePath()); conn = new RemotingConnection(req, scope, packet); // Make sure the connection object isn't garbage collected req.setAttribute(CONNECTION, conn); // set thread local reference Red5.setConnectionLocal(conn); //fixed so that true is not returned for calls that have failed boolean passed = handleRemotingPacket(req, context, scope, packet); if (passed) { resp.setStatus(HttpServletResponse.SC_OK); } else { log.warn("At least one invocation failed to execute"); resp.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED); } //send our response resp.setContentType(APPLICATION_AMF); sendResponse(resp, packet); } catch (Exception e) { log.error("Error handling remoting call", e); resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } finally { //ensure the conn attr gets removed req.removeAttribute(CONNECTION); //unregister the remote connection client if (conn != null) { ((RemotingConnection) conn).cleanup(); } // clear thread local reference Red5.setConnectionLocal(null); } } /** * Decode request * * @param req * Request * @return Remoting packet * @throws Exception * General exception */ protected RemotingPacket decodeRequest(HttpServletRequest req) throws Exception { log.debug("Decoding request"); IoBuffer reqBuffer = IoBuffer.allocate(req.getContentLength()); ServletUtils.copy(req.getInputStream(), reqBuffer.asOutputStream()); reqBuffer.flip(); RemotingPacket packet = (RemotingPacket) codecFactory.getRemotingDecoder().decode(null, reqBuffer); String path = req.getContextPath(); if (path == null) { path = ""; } if (req.getPathInfo() != null) { path += req.getPathInfo(); } // check for header path, this is used by the AMF tunnel servlet String headerPath = req.getHeader("Tunnel-request"); // it is only used if the path is set to root if (headerPath != null && path.length() < 1) { path = headerPath; } if (path.length() > 0 && path.charAt(0) == '/') { path = path.substring(1); } log.debug("Path: {} Scope path: {}", path, packet.getScopePath()); packet.setScopePath(path); reqBuffer.free(); reqBuffer = null; return packet; } /** * Handles AMF request by making calls * * @param req * Request * @param message * Remoting packet * @return true on success */ protected boolean handleRemotingPacket(HttpServletRequest req, IContext context, IScope scope, RemotingPacket message) { log.debug("Handling remoting packet"); boolean result = true; final IServiceInvoker invoker = context.getServiceInvoker(); for (RemotingCall call : message.getCalls()) { result = invoker.invoke(call, scope); //if we encounter a failure break out if (!result) { break; } } return result; } /** * Sends response to client * * @param resp * Response * @param packet * Remoting packet * @throws Exception * General exception */ protected void sendResponse(HttpServletResponse resp, RemotingPacket packet) throws Exception { log.debug("Sending response"); IoBuffer respBuffer = codecFactory.getRemotingEncoder().encode(null, packet); if (respBuffer != null) { final ServletOutputStream out = resp.getOutputStream(); resp.setContentLength(respBuffer.limit()); ServletUtils.copy(respBuffer.asInputStream(), out); out.flush(); out.close(); respBuffer.free(); respBuffer = null; } else { log.info("Response buffer was null after encoding"); } } } red5-1.0~svn4374.orig/src/org/red5/server/net/servlet/AMFTunnelServlet.java0000644000175000017500000001106111706617130026312 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.servlet; import java.io.IOException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.InputStreamEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.util.EntityUtils; import org.apache.mina.core.buffer.IoBuffer; import org.red5.logging.Red5LoggerFactory; import org.red5.server.util.HttpConnectionUtil; import org.slf4j.Logger; /** * Servlet to tunnel to the AMF gateway servlet. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class AMFTunnelServlet extends HttpServlet { private static final long serialVersionUID = -35436145164322090L; protected Logger log = Red5LoggerFactory.getLogger(AMFTunnelServlet.class); private static final String REQUEST_TYPE = "application/x-amf"; private static String postAcceptorURL = "http://localhost:8080/gateway"; private static int connectionTimeout = 30000; @Override public void init(ServletConfig config) throws ServletException { super.init(config); //get the url for posting if (config.getInitParameter("tunnel.acceptor.url") != null) { postAcceptorURL = config.getInitParameter("tunnel.acceptor.url"); } log.debug("POST acceptor URL: {}", postAcceptorURL); //get the connection timeout if (config.getInitParameter("tunnel.timeout") != null) { connectionTimeout = Integer.valueOf(config.getInitParameter("tunnel.timeout")); } log.debug("POST connection timeout: {}", postAcceptorURL); } /** * Redirect to HTTP port. */ @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { DefaultHttpClient client = HttpConnectionUtil.getClient(); client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, connectionTimeout); //setup POST HttpPost post = null; try { post = new HttpPost(postAcceptorURL); String path = req.getContextPath(); if (path == null) { path = ""; } log.debug("Path: {}", path); if (req.getPathInfo() != null) { path += req.getPathInfo(); } log.debug("Path 2: {}", path); int reqContentLength = req.getContentLength(); if (reqContentLength > 0) { log.debug("Request content length: {}", reqContentLength); IoBuffer reqBuffer = IoBuffer.allocate(reqContentLength); ServletUtils.copy(req.getInputStream(), reqBuffer.asOutputStream()); reqBuffer.flip(); post.setEntity(new InputStreamEntity(reqBuffer.asInputStream(), reqContentLength)); post.addHeader("Content-Type", REQUEST_TYPE); // get.setPath(path); post.addHeader("Tunnel-request", path); // execute the method HttpResponse response = client.execute(post); int code = response.getStatusLine().getStatusCode(); log.debug("HTTP response code: {}", code); if (code == HttpStatus.SC_OK) { HttpEntity entity = response.getEntity(); if (entity != null) { resp.setContentType(REQUEST_TYPE); // get the response as bytes byte[] bytes = EntityUtils.toByteArray(entity); IoBuffer resultBuffer = IoBuffer.wrap(bytes); resultBuffer.flip(); ServletUtils.copy(resultBuffer.asInputStream(), resp.getOutputStream()); resp.flushBuffer(); } } else { resp.sendError(code); } } else { resp.sendError(HttpStatus.SC_BAD_REQUEST); } } catch (Exception ex) { log.error("", ex); post.abort(); } } } red5-1.0~svn4374.orig/src/org/red5/server/net/protocol/0000755000175000017500000000000011760512572022473 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/protocol/ProtocolException.java0000644000175000017500000000251011706617130027010 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.protocol; public class ProtocolException extends RuntimeException { /** * Base exception for all protocol exceptions. */ private static final long serialVersionUID = -5380844081848027068L; /** * Create protocol exception with given message. * * @param message message */ public ProtocolException(String message) { super(message); } /** * Create protocol exception with given message and cause. * * @param message message * @param cause cause */ public ProtocolException(String message, Throwable cause) { super(message, cause); } } red5-1.0~svn4374.orig/src/org/red5/server/net/protocol/HandshakeFailedException.java0000644000175000017500000000210211706617130030177 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.protocol; public class HandshakeFailedException extends ProtocolException { /** * */ private static final long serialVersionUID = 8255789603304183796L; /** * Create handshake failed exception with given message * * @param message message */ public HandshakeFailedException(String message) { super(message); } } red5-1.0~svn4374.orig/src/org/red5/server/net/protocol/ProtocolState.java0000644000175000017500000000577511706617130026152 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.protocol; /** * Represents current state of protocol. */ public class ProtocolState { /** * Session key constant. */ public static final String SESSION_KEY = "protocol_state"; /** * Decoding finished successfully state constant. */ public static byte DECODER_OK = 0x00; /** * Deconding continues state constant. */ public static byte DECODER_CONTINUE = 0x01; /** * Decoder is buffering state constant. */ public static byte DECODER_BUFFER = 0x02; /** * Classes like the RTMP state object will extend this marker interface. */ private int decoderBufferAmount; /** * Current decoder state, decoder is stopped by default. */ private byte decoderState = DECODER_OK; /** * Returns current buffer amount. * * @return Buffer amount */ public int getDecoderBufferAmount() { return decoderBufferAmount; } /** * Specifies buffer decoding amount * * @param amount Buffer decoding amount */ public void bufferDecoding(int amount) { decoderState = DECODER_BUFFER; decoderBufferAmount = amount; } /** * Set decoding state as "needed to be continued". */ public void continueDecoding() { decoderState = DECODER_CONTINUE; } /** * Checks whether remaining buffer size is greater or equal than buffer amount and so if it makes sense to start decoding. * * @param remaining Remaining buffer size * @return true if there is data to decode, false otherwise */ public boolean canStartDecoding(int remaining) { if (remaining >= decoderBufferAmount) { return true; } else { return false; } } /** * Starts decoding. Sets state to "ready" and clears buffer amount. */ public void startDecoding() { decoderState = DECODER_OK; decoderBufferAmount = 0; } /** * Checks whether decoding is complete. * * @return true if decoding has finished, false otherwise */ public boolean hasDecodedObject() { return (decoderState == DECODER_OK); } /** * Checks whether decoding process can be continued. * * @return true if decoding can be continued, false otherwise */ public boolean canContinueDecoding() { return (decoderState != DECODER_BUFFER); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/0000755000175000017500000000000011760512572021614 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/Channel.java0000644000175000017500000001213211754456611024032 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IClientStream; import org.red5.server.api.stream.IRtmpSampleAccess; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.Invoke; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.message.Header; import org.red5.server.net.rtmp.message.Packet; import org.red5.server.net.rtmp.status.Status; import org.red5.server.net.rtmp.status.StatusCodes; import org.red5.server.service.Call; import org.red5.server.service.PendingCall; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Identified connection that transfers packets. */ public class Channel { protected static Logger log = LoggerFactory.getLogger(Channel.class); private final static String CALL_ON_STATUS = "onStatus"; /** * RTMP connection used to transfer packets. */ private final RTMPConnection connection; /** * Channel id */ private final int id; /** * Creates channel from connection and channel id * @param conn Connection * @param channelId Channel id */ public Channel(RTMPConnection conn, int channelId) { connection = conn; id = channelId; } /** * Closes channel with this id on RTMP connection. */ public void close() { if (connection != null) { connection.closeChannel(id); } } /** * Getter for id. * * @return Channel ID */ public int getId() { return id; } /** * Getter for RTMP connection. * * @return RTMP connection */ protected RTMPConnection getConnection() { return connection; } /** * Writes packet from event data to RTMP connection. * * @param event Event data */ public void write(IRTMPEvent event) { if (connection != null) { final IClientStream stream = connection.getStreamByChannelId(id); if (id > 3 && stream == null) { log.info("Stream doesn't exist any longer, discarding message {}", event); } else { final int streamId = (stream == null) ? 0 : stream.getStreamId(); write(event, streamId); } } } /** * Writes packet from event data to RTMP connection and stream id. * * @param event Event data * @param streamId Stream id */ private void write(IRTMPEvent event, int streamId) { final Header header = new Header(); final Packet packet = new Packet(header, event); header.setChannelId(id); header.setTimer(event.getTimestamp()); header.setStreamId(streamId); header.setDataType(event.getDataType()); // should use RTMPConnection specific method.. connection.write(packet); } /** * Sends status notification. * * @param status Status */ public void sendStatus(Status status) { if (connection != null) { final boolean andReturn = !status.getCode().equals(StatusCodes.NS_DATA_START); final Notify event; if (andReturn) { final PendingCall call = new PendingCall(null, CALL_ON_STATUS, new Object[] { status }); event = new Invoke(); if (status.getCode().equals(StatusCodes.NS_PLAY_START)) { IScope scope = connection.getScope(); if (scope.getContext().getApplicationContext().containsBean(IRtmpSampleAccess.BEAN_NAME)) { IRtmpSampleAccess sampleAccess = (IRtmpSampleAccess) scope.getContext().getApplicationContext().getBean(IRtmpSampleAccess.BEAN_NAME); boolean videoAccess = sampleAccess.isVideoAllowed(scope); boolean audioAccess = sampleAccess.isAudioAllowed(scope); if (videoAccess || audioAccess) { final Call call2 = new Call(null, "|RtmpSampleAccess", null); Notify notify = new Notify(); notify.setInvokeId(connection.getInvokeId()); notify.setCall(call2); notify.setData(IoBuffer.wrap(new byte[] { 0x01, (byte) (audioAccess ? 0x01 : 0x00), 0x01, (byte) (videoAccess ? 0x01 : 0x00) })); write(notify, connection.getStreamIdForChannel(id)); } } } event.setInvokeId(connection.getInvokeId()); event.setCall(call); } else { final Call call = new Call(null, CALL_ON_STATUS, new Object[] { status }); event = new Notify(); event.setInvokeId(connection.getInvokeId()); event.setCall(call); } // We send directly to the corresponding stream as for some status codes, no stream has been created // and thus "getStreamByChannelId" will fail. write(event, connection.getStreamIdForChannel(id)); } } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/RTMPMinaTransport.java0000644000175000017500000001627711751004261025767 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import java.lang.management.ManagementFactory; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.StandardMBean; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.buffer.SimpleBufferAllocator; import org.apache.mina.core.service.AbstractIoService; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.service.IoServiceStatistics; import org.apache.mina.transport.socket.SocketAcceptor; import org.apache.mina.transport.socket.SocketSessionConfig; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; import org.red5.server.jmx.mxbeans.RTMPMinaTransportMXBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Transport setup class configures socket acceptor and thread pools for RTMP in Mina. * *
* Note: This code originates from AsyncWeb. Originally modified by Luke Hubbard. *
* * @author Luke Hubbard * @author Paul Gregoire */ public class RTMPMinaTransport implements RTMPMinaTransportMXBean { private static final Logger log = LoggerFactory.getLogger(RTMPMinaTransport.class); protected SocketAcceptor acceptor; protected Set addresses = new HashSet(); protected IoHandlerAdapter ioHandler; protected IoServiceStatistics stats; protected int ioThreads = Runtime.getRuntime().availableProcessors() * 2; /** * MBean object name used for de/registration purposes. */ protected ObjectName serviceManagerObjectName; protected boolean enableMinaMonitor = false; protected int minaPollInterval = 1000; protected boolean tcpNoDelay = true; protected boolean useHeapBuffers = true; private void initIOHandler() { if (ioHandler == null) { log.info("No RTMP IO Handler associated - using defaults"); ioHandler = new RTMPMinaIoHandler(); } } public void start() throws Exception { initIOHandler(); IoBuffer.setUseDirectBuffer(!useHeapBuffers); // this is global, oh well if (useHeapBuffers) { // dont pool for heap buffers IoBuffer.setAllocator(new SimpleBufferAllocator()); } log.info("RTMP Mina Transport Settings"); log.info("I/O Threads: {}", ioThreads); // XXX Paul: come back and review why the separate executors didnt work as expected // ref: http://stackoverflow.com/questions/5088850/multi-threading-in-red5 //use default parameters, and given number of NioProcessor for multithreading I/O operations acceptor = new NioSocketAcceptor(ioThreads); // set acceptor props acceptor.setHandler(ioHandler); acceptor.setBacklog(50); //get the current session config that would be used during create SocketSessionConfig sessionConf = acceptor.getSessionConfig(); //reuse the addresses sessionConf.setReuseAddress(true); log.info("TCP No Delay: {}", tcpNoDelay); sessionConf.setTcpNoDelay(tcpNoDelay); // set the traffic class - http://docs.oracle.com/javase/6/docs/api/java/net/Socket.html#setTrafficClass(int) // IPTOS_LOWCOST (0x02) // IPTOS_RELIABILITY (0x04) // IPTOS_THROUGHPUT (0x08) * // IPTOS_LOWDELAY (0x10) sessionConf.setTrafficClass(0x08); // get info log.info("Settings - send buffer size: {} recv buffer size: {} so linger: {} traffic class: {}", new Object[] { sessionConf.getSendBufferSize(), sessionConf.getReceiveBufferSize(), sessionConf.getSoLinger(), sessionConf.getTrafficClass() }); //set reuse address on the socket acceptor as well acceptor.setReuseAddress(true); String addrStr = addresses.toString(); log.debug("Binding to {}", addrStr); acceptor.bind(addresses); //create a new mbean for this instance // RTMPMinaTransport String cName = this.getClass().getName(); if (cName.indexOf('.') != -1) { cName = cName.substring(cName.lastIndexOf('.')).replaceFirst("[\\.]", ""); } //enable only if user wants it if (enableMinaMonitor) { //add a service manager to allow for more introspection into the workings of mina stats = new IoServiceStatistics((AbstractIoService) acceptor); //poll every second stats.setThroughputCalculationInterval(minaPollInterval); //construct a object containing all the host and port combos StringBuilder addressAndPorts = new StringBuilder(); for (SocketAddress sa : addresses) { InetSocketAddress isa = ((InetSocketAddress) sa); if (!isa.isUnresolved()) { addressAndPorts.append(isa.getHostName()); addressAndPorts.append('|'); addressAndPorts.append(isa.getPort()); addressAndPorts.append(';'); } } addressAndPorts.deleteCharAt(addressAndPorts.length() - 1); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { serviceManagerObjectName = new ObjectName("org.red5.server:type=IoServiceManager,addresses=" + addressAndPorts.toString()); mbs.registerMBean(new StandardMBean(this, RTMPMinaTransportMXBean.class, true), serviceManagerObjectName); } catch (Exception e) { log.warn("Error on jmx registration", e); } } } public void stop() { log.info("RTMP Mina Transport unbind"); acceptor.unbind(); // deregister with jmx if (serviceManagerObjectName != null) { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { mbs.unregisterMBean(serviceManagerObjectName); } catch (Exception e) { log.warn("Error on jmx unregistration", e); } } } public void setConnector(InetSocketAddress connector) { addresses.add(connector); log.info("RTMP Mina Transport bound to {}", connector.toString()); } public void setConnectors(List connectors) { for (InetSocketAddress addr : connectors) { addresses.add(addr); log.info("RTMP Mina Transport bound to {}", addr.toString()); } } public void setIoHandler(IoHandlerAdapter rtmpIOHandler) { this.ioHandler = rtmpIOHandler; } public void setIoThreads(int ioThreads) { this.ioThreads = ioThreads; } public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; } public void setUseHeapBuffers(boolean useHeapBuffers) { this.useHeapBuffers = useHeapBuffers; } /** * @param enableMinaMonitor the enableMinaMonitor to set */ public void setEnableMinaMonitor(boolean enableMinaMonitor) { this.enableMinaMonitor = enableMinaMonitor; } public void setMinaPollInterval(int minaPollInterval) { this.minaPollInterval = minaPollInterval; } public String toString() { return String.format("RTMP Mina Transport %s", addresses.toString()); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/RTMPConnManager.java0000644000175000017500000000725511746066216025366 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import java.util.ArrayList; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.red5.server.BaseConnection; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.net.rtmpt.RTMPTConnection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class RTMPConnManager implements IRTMPConnManager, ApplicationContextAware { private static final Logger log = LoggerFactory.getLogger(RTMPConnManager.class); private ConcurrentMap connMap = new ConcurrentHashMap(); private ReadWriteLock lock = new ReentrantReadWriteLock(); private ApplicationContext appCtx; public RTMPConnection createConnection(Class connCls) { RTMPConnection conn = null; if (RTMPConnection.class.isAssignableFrom(connCls)) { try { conn = createConnectionInstance(connCls); lock.writeLock().lock(); try { int clientId = BaseConnection.getNextClientId(); conn.setId(clientId); connMap.put(clientId, conn); log.debug("Connection created, id: {}", conn.getId()); } finally { lock.writeLock().unlock(); } } catch (Exception e) { } } return conn; } public RTMPConnection getConnection(int clientId) { lock.readLock().lock(); try { return connMap.get(clientId); } finally { lock.readLock().unlock(); } } public RTMPConnection removeConnection(int clientId) { lock.writeLock().lock(); try { log.debug("Removing connection with id: {}", clientId); return connMap.remove(clientId); } finally { lock.writeLock().unlock(); } } public Collection removeConnections() { ArrayList list = new ArrayList(connMap.size()); lock.writeLock().lock(); try { list.addAll(connMap.values()); return list; } finally { lock.writeLock().unlock(); } } public void setApplicationContext(ApplicationContext appCtx) throws BeansException { this.appCtx = appCtx; } public RTMPConnection createConnectionInstance(Class cls) throws Exception { RTMPConnection conn = null; if (cls == RTMPMinaConnection.class) { conn = (RTMPMinaConnection) appCtx.getBean("rtmpMinaConnection"); } else if (cls == RTMPTConnection.class) { conn = (RTMPTConnection) appCtx.getBean("rtmptConnection"); } else { conn = (RTMPConnection) cls.newInstance(); } //set the scheduling service for easy access in the connection conn.setSchedulingService((ISchedulingService) appCtx.getBean(ISchedulingService.BEAN_NAME)); return conn; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/DeferredResult.java0000644000175000017500000000540311752742216025401 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import java.lang.ref.WeakReference; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.net.rtmp.event.Invoke; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Can be returned to delay returning the result of invoked methods. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class DeferredResult { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(DeferredResult.class); /** * Weak reference to used channel */ private WeakReference channel; /** * Pending call object */ private IPendingServiceCall call; /** * Invocation id */ private int invokeId; /** * Results sent flag */ private boolean resultSent = false; /** * Set the result of a method call and send to the caller. * * @param result deferred result of the method call */ public void setResult(Object result) { if (resultSent) { throw new RuntimeException("You can only set the result once."); } this.resultSent = true; Channel channel = this.channel.get(); if (channel == null) { log.warn("The client is no longer connected."); return; } Invoke reply = new Invoke(); call.setResult(result); reply.setCall(call); reply.setInvokeId(invokeId); channel.write(reply); channel.getConnection().unregisterDeferredResult(this); } /** * Check if the result has been sent to the client. * * @return true if the result has been sent, otherwise false */ public boolean wasSent() { return resultSent; } /** * Setter for invoke Id. * * @param id Invocation object identifier */ public void setInvokeId(int id) { this.invokeId = id; } /** * Setter for service call. * * @param call Service call */ public void setServiceCall(IPendingServiceCall call) { this.call = call; } /** * Setter for channel. * * @param channel Channel */ public void setChannel(Channel channel) { this.channel = new WeakReference(channel); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/0000755000175000017500000000000011760512572022735 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/AudioData.java0000644000175000017500000000765611706617130025445 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.stream.IStreamPacket; import org.red5.server.stream.IStreamData; public class AudioData extends BaseEvent implements IStreamData, IStreamPacket { private static final long serialVersionUID = -4102940670913999407L; protected IoBuffer data; /** * Data type */ private byte dataType = TYPE_AUDIO_DATA; /** Constructs a new AudioData. */ public AudioData() { this(IoBuffer.allocate(0).flip()); } public AudioData(IoBuffer data) { super(Type.STREAM_DATA); setData(data); } /** * Create audio data event with given data buffer * @param data Audio data * @param copy true to use a copy of the data or false to use reference */ public AudioData(IoBuffer data, boolean copy) { super(Type.STREAM_DATA); if (copy) { byte[] array = new byte[data.limit()]; data.mark(); data.get(array); data.reset(); setData(array); } else { setData(data); } } /** {@inheritDoc} */ @Override public byte getDataType() { return dataType; } public void setDataType(byte dataType) { this.dataType = dataType; } /** {@inheritDoc} */ public IoBuffer getData() { return data; } public void setData(IoBuffer data) { this.data = data; } public void setData(byte[] data) { this.data = IoBuffer.allocate(data.length); this.data.put(data).flip(); } /** {@inheritDoc} */ @Override protected void releaseInternal() { if (data != null) { data.free(); data = null; } } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); byte[] byteBuf = (byte[]) in.readObject(); if (byteBuf != null) { data = IoBuffer.allocate(0); data.setAutoExpand(true); SerializeUtils.ByteArrayToByteBuffer(byteBuf, data); } } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); if (data != null) { out.writeObject(SerializeUtils.ByteBufferToByteArray(data)); } else { out.writeObject(null); } } /** * Duplicate this message / event. * * @return duplicated event */ public AudioData duplicate() throws IOException, ClassNotFoundException { AudioData result = new AudioData(); // serialize ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); writeExternal(oos); oos.close(); // convert to byte array byte[] buf = baos.toByteArray(); baos.close(); // create input streams ByteArrayInputStream bais = new ByteArrayInputStream(buf); ObjectInputStream ois = new ObjectInputStream(bais); // deserialize result.readExternal(ois); ois.close(); bais.close(); // clone the header if there is one if (header != null) { result.setHeader(header.clone()); } return result; } /** {@inheritDoc} */ @Override public String toString() { return String.format("Audio - ts: %s length: %s", getTimestamp(), (data != null ? data.limit() : '0')); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/ClientBW.java0000644000175000017500000000517211706617130025250 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; /** * Client bandwidth event. Also known as a Peer Bandwidth message. */ public class ClientBW extends BaseEvent { private static final long serialVersionUID = 5848656135751336839L; /** * Bandwidth */ private int bandwidth; /** * Enforcement level or limit type of the bandwidth value based on three values. *
	 * TYPE_HARD 0
	 * TYPE_SOFT 1
	 * TYPE_DYNAMIC 2
	 * 
*/ private byte value2; public ClientBW() { super(Type.STREAM_CONTROL); } public ClientBW(int bandwidth, byte limitType) { this(); this.bandwidth = bandwidth; this.value2 = limitType; } /** {@inheritDoc} */ @Override public byte getDataType() { return TYPE_CLIENT_BANDWIDTH; } /** * Getter for property 'bandwidth'. * * @return Value for property 'bandwidth'. */ public int getBandwidth() { return bandwidth; } /** * Setter for bandwidth * * @param bandwidth New bandwidth */ public void setBandwidth(int bandwidth) { this.bandwidth = bandwidth; } /** * Getter for value2 * * @return Value for property 'value2'. */ public byte getValue2() { return value2; } /** * Setter for property 'value2'. * * @param value2 Value to set for property 'value2'. */ public void setValue2(byte value2) { this.value2 = value2; } /** {@inheritDoc} */ @Override public String toString() { return "ClientBW: " + bandwidth + " enforcementLevel: " + value2; } /** {@inheritDoc} */ @Override protected void releaseInternal() { } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); bandwidth = in.readInt(); value2 = in.readByte(); } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeInt(bandwidth); out.writeByte(value2); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/BaseEvent.java0000644000175000017500000001063511706617130025455 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.concurrent.atomic.AtomicInteger; import org.red5.server.api.event.IEventListener; import org.red5.server.net.rtmp.message.Constants; import org.red5.server.net.rtmp.message.Header; /** * Base abstract class for all RTMP events */ public abstract class BaseEvent implements Constants, IRTMPEvent, Externalizable { // XXX we need a better way to inject allocation debugging // (1) make it configurable in xml // (2) make it aspect oriented private static final boolean allocationDebugging = false; /** * Event type */ private Type type; /** * Source type */ private byte sourceType; /** * Event target object */ protected Object object; /** * Event listener */ protected IEventListener source; /** * Event timestamp */ protected int timestamp; /** * Event RTMP packet header */ protected Header header = null; /** * Event references count */ protected AtomicInteger refcount = new AtomicInteger(1); public BaseEvent() { // set a default type this(Type.SERVER, null); } /** * Create new event of given type * @param type Event type */ public BaseEvent(Type type) { this(type, null); } /** * Create new event of given type * @param type Event type * @param source Event source */ public BaseEvent(Type type, IEventListener source) { this.type = type; this.source = source; if (allocationDebugging) { AllocationDebugger.getInstance().create(this); } } /** {@inheritDoc} */ public Type getType() { return type; } public void setType(Type type) { this.type = type; } public byte getSourceType() { return sourceType; } public void setSourceType(byte sourceType) { this.sourceType = sourceType; } /** {@inheritDoc} */ public Object getObject() { return object; } /** {@inheritDoc} */ public Header getHeader() { return header; } /** {@inheritDoc} */ public void setHeader(Header header) { this.header = header; } /** {@inheritDoc} */ public boolean hasSource() { return source != null; } /** {@inheritDoc} */ public IEventListener getSource() { return source; } /** {@inheritDoc} */ public void setSource(IEventListener source) { this.source = source; } /** {@inheritDoc} */ public abstract byte getDataType(); /** {@inheritDoc} */ public int getTimestamp() { return timestamp; } /** {@inheritDoc} */ public void setTimestamp(int timestamp) { this.timestamp = timestamp; } /** {@inheritDoc} */ @SuppressWarnings("all") public void retain() { if (allocationDebugging) { AllocationDebugger.getInstance().retain(this); } final int baseCount = refcount.getAndIncrement(); if (allocationDebugging && baseCount < 1) { throw new RuntimeException("attempt to retain object with invalid ref count"); } } /** {@inheritDoc} */ @SuppressWarnings("all") public void release() { if (allocationDebugging) { AllocationDebugger.getInstance().release(this); } final int baseCount = refcount.decrementAndGet(); if (baseCount == 0) { releaseInternal(); } else if (allocationDebugging && baseCount < 0) { throw new RuntimeException("attempt to retain object with invalid ref count"); } } /** * Release event */ protected abstract void releaseInternal(); public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { type = (Type) in.readObject(); sourceType = in.readByte(); timestamp = in.readInt(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(type); out.writeByte(sourceType); out.writeInt(timestamp); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/Ping.java0000644000175000017500000001344311706617130024476 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; /** * Ping event, actually combination of different events. This is * also known as a user control message. */ public class Ping extends BaseEvent { private static final long serialVersionUID = -6478248060425544923L; /** * Stream begin / clear event */ public static final short STREAM_BEGIN = 0; /** * Stream EOF, playback of requested stream is completed. */ public static final short STREAM_PLAYBUFFER_CLEAR = 1; /** * Stream is empty */ public static final short STREAM_DRY = 2; /** * Client buffer. Sent by client to indicate its buffer time in milliseconds. */ public static final short CLIENT_BUFFER = 3; /** * Recorded stream. Sent by server to indicate a recorded stream. */ public static final short RECORDED_STREAM = 4; /** * One more unknown event */ public static final short UNKNOWN_5 = 5; /** * Client ping event. Sent by server to test if client is reachable. */ public static final short PING_CLIENT = 6; /** * Server response event. A clients ping response. */ public static final short PONG_SERVER = 7; /** * One more unknown event */ public static final short UNKNOWN_8 = 8; /** * SWF verification ping 0x001a */ public static final short PING_SWF_VERIFY = 26; /** * SWF verification pong 0x001b */ public static final short PONG_SWF_VERIFY = 27; /** * Event type is undefined */ public static final int UNDEFINED = -1; /** * The sub-type */ private short eventType; /** * Represents the stream id in all cases except PING_CLIENT and PONG_SERVER * where it represents the local server timestamp. */ private int value2; private int value3 = UNDEFINED; private int value4 = UNDEFINED; /** * Debug string */ private String debug = ""; /** Constructs a new Ping. */ public Ping() { super(Type.SYSTEM); } public Ping(short eventType, int value2) { super(Type.SYSTEM); this.eventType = eventType; this.value2 = value2; } public Ping(short eventType, int value2, int value3) { super(Type.SYSTEM); this.eventType = eventType; this.value2 = value2; this.value3 = value3; } public Ping(short eventType, int value2, int value3, int value4) { super(Type.SYSTEM); this.eventType = eventType; this.value2 = value2; this.value3 = value3; this.value4 = value4; } public Ping(Ping in) { super(Type.SYSTEM); this.eventType = in.getEventType(); this.value2 = in.getValue2(); this.value3 = in.getValue3(); this.value4 = in.getValue4(); } /** {@inheritDoc} */ @Override public byte getDataType() { return TYPE_PING; } /** * Returns the events sub-type * * @return the event type */ public short getEventType() { return eventType; } /** * Sets the events sub-type * * @param eventType */ public void setEventType(short eventType) { this.eventType = eventType; } /** * Getter for property 'value2'. * * @return Value for property 'value2'. */ public int getValue2() { return value2; } /** * Setter for property 'value2'. * * @param value2 Value to set for property 'value2'. */ public void setValue2(int value2) { this.value2 = value2; } /** * Getter for property 'value3'. * * @return Value for property 'value3'. */ public int getValue3() { return value3; } /** * Setter for property 'value3'. * * @param value3 Value to set for property 'value3'. */ public void setValue3(int value3) { this.value3 = value3; } /** * Getter for property 'value4'. * * @return Value for property 'value4'. */ public int getValue4() { return value4; } /** * Setter for property 'value4'. * * @param value4 Value to set for property 'value4'. */ public void setValue4(int value4) { this.value4 = value4; } /** * Getter for property 'debug'. * * @return Value for property 'debug'. */ public String getDebug() { return debug; } /** * Setter for property 'debug'. * * @param debug Value to set for property 'debug'. */ public void setDebug(String debug) { this.debug = debug; } protected void doRelease() { eventType = 0; value2 = 0; value3 = UNDEFINED; value4 = UNDEFINED; } /** {@inheritDoc} */ @Override public String toString() { return "Ping: " + eventType + ", " + value2 + ", " + value3 + ", " + value4 + "\n" + debug; } /** {@inheritDoc} */ @Override protected void releaseInternal() { } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); eventType = in.readShort(); value2 = in.readInt(); value3 = in.readInt(); value4 = in.readInt(); } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeShort(eventType); out.writeInt(value2); out.writeInt(value3); out.writeInt(value4); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/SerializeUtils.java0000644000175000017500000000324211706617130026545 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.nio.ByteBuffer; import org.apache.mina.core.buffer.IoBuffer; /** * The utility class provides conversion methods to ease the use of * byte arrays, Mina IoBuffers, and NIO ByteBuffers. * * @author Paul Gregoire (mondain@gmail.com) */ public class SerializeUtils { public static byte[] ByteBufferToByteArray(IoBuffer buf) { byte[] byteBuf = new byte[buf.limit()]; int pos = buf.position(); buf.rewind(); buf.get(byteBuf); buf.position(pos); return byteBuf; } public static byte[] NioByteBufferToByteArray(ByteBuffer buf) { byte[] byteBuf = new byte[buf.limit()]; int pos = buf.position(); buf.position(0); buf.get(byteBuf); buf.position(pos); return byteBuf; } public static void ByteArrayToByteBuffer(byte[] byteBuf, IoBuffer buf) { buf.put(byteBuf); buf.flip(); } public static void ByteArrayToNioByteBuffer(byte[] byteBuf, ByteBuffer buf) { buf.put(byteBuf); buf.flip(); } }red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/Invoke.java0000644000175000017500000000372011706617130025031 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.service.IPendingServiceCall; /** * Remote invocation event */ public class Invoke extends Notify { private static final long serialVersionUID = -769677790148010729L; /** Constructs a new Invoke. */ public Invoke() { super(); } /** {@inheritDoc} */ @Override public byte getDataType() { return TYPE_INVOKE; } /** * Create new invocation event with given data * @param data Event data */ public Invoke(IoBuffer data) { super(data); } /** * Create new invocation event with given pending service call * @param call Pending call */ public Invoke(IPendingServiceCall call) { super(call); } /** {@inheritDoc} */ @Override public IPendingServiceCall getCall() { return (IPendingServiceCall) call; } /** {@inheritDoc} */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Invoke: ").append(call); return sb.toString(); } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (!(obj instanceof Invoke)) { return false; } return super.equals(obj); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/Notify.java0000644000175000017500000001417611706617130025055 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.util.Map; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.service.IServiceCall; import org.red5.server.api.stream.IStreamPacket; import org.red5.server.stream.IStreamData; /** * Stream notification event * @author Red5 team * @author Tiago Daniel Jacobs (tiago@imdt.com.br) */ public class Notify extends BaseEvent implements IStreamData, IStreamPacket { private static final long serialVersionUID = -6085848257275156569L; /** * Service call */ protected IServiceCall call; /** * Event data */ protected IoBuffer data; /** * Invoke id */ private int invokeId = 0; /** * Connection parameters */ private Map connectionParams; /** Constructs a new Notify. */ public Notify() { super(Type.SERVICE_CALL); } /** * Create new notification event with given byte buffer * @param data Byte buffer */ public Notify(IoBuffer data) { super(Type.STREAM_DATA); this.data = data; } /** * Create new notification event with given service call * @param call Service call */ public Notify(IServiceCall call) { super(Type.SERVICE_CALL); this.call = call; } /** {@inheritDoc} */ @Override public byte getDataType() { return TYPE_NOTIFY; } /** * Setter for data * * @param data Data */ public void setData(IoBuffer data) { this.data = data; } /** * Setter for call * * @param call Service call */ public void setCall(IServiceCall call) { this.call = call; } /** * Getter for service call * * @return Service call */ public IServiceCall getCall() { return this.call; } /** {@inheritDoc} */ public IoBuffer getData() { return data; } /** * Getter for invoke id * * @return Invoke id */ public int getInvokeId() { return invokeId; } /** * Setter for invoke id * * @param invokeId Invoke id */ public void setInvokeId(int invokeId) { this.invokeId = invokeId; } /** * Release event (nullify call object) */ protected void doRelease() { call = null; } /** * Getter for connection parameters * * @return Connection parameters */ public Map getConnectionParams() { return connectionParams; } /** * Setter for connection parameters * * @param connectionParams Connection parameters */ public void setConnectionParams(Map connectionParams) { this.connectionParams = connectionParams; } /** {@inheritDoc} */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Notify: ").append(call); return sb.toString(); } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (!(obj instanceof Notify)) { return false; } Notify other = (Notify) obj; if (getConnectionParams() == null && other.getConnectionParams() != null) { return false; } if (getConnectionParams() != null && other.getConnectionParams() == null) { return false; } if (getConnectionParams() != null && !getConnectionParams().equals(other.getConnectionParams())) { return false; } if (getInvokeId() != other.getInvokeId()) { return false; } if (getCall() == null && other.getCall() != null) { return false; } if (getCall() != null && other.getCall() == null) { return false; } if (getCall() != null && !getCall().equals(other.getCall())) { return false; } return true; } /** {@inheritDoc} */ @Override protected void releaseInternal() { if (data != null) { data.free(); data = null; } } @SuppressWarnings("unchecked") @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); call = (IServiceCall) in.readObject(); connectionParams = (Map) in.readObject(); invokeId = in.readInt(); byte[] byteBuf = (byte[]) in.readObject(); if (byteBuf != null) { data = IoBuffer.allocate(0); data.setAutoExpand(true); SerializeUtils.ByteArrayToByteBuffer(byteBuf, data); } } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeObject(call); out.writeObject(connectionParams); out.writeInt(invokeId); if (data != null) { out.writeObject(SerializeUtils.ByteBufferToByteArray(data)); } else { out.writeObject(null); } } /** * Duplicate this Notify message to future injection * Serialize to memory and deserialize, safe way. * * @return duplicated Notify event */ public Notify duplicate() throws IOException, ClassNotFoundException { Notify result = new Notify(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); writeExternal(oos); oos.close(); byte[] buf = baos.toByteArray(); baos.close(); ByteArrayInputStream bais = new ByteArrayInputStream(buf); ObjectInputStream ois = new ObjectInputStream(bais); result.readExternal(ois); ois.close(); bais.close(); return result; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/FlexMessage.java0000644000175000017500000000204511706617130026000 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; /** * Flex method invocation. To be implemented. */ public class FlexMessage extends Invoke { private static final long serialVersionUID = 1854760132754344723L; public FlexMessage() { super(); } /** {@inheritDoc} */ @Override public byte getDataType() { return TYPE_FLEX_MESSAGE; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/Aggregate.java0000644000175000017500000001725411706617130025473 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.util.LinkedList; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.IoConstants; import org.red5.io.utils.IOUtils; import org.red5.server.api.stream.IStreamPacket; import org.red5.server.net.rtmp.message.Header; import org.red5.server.stream.IStreamData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Aggregate data event */ public class Aggregate extends BaseEvent implements IoConstants, IStreamData, IStreamPacket { private static final long serialVersionUID = 5538859593815804830L; private static Logger log = LoggerFactory.getLogger(Aggregate.class); /** * Data */ protected IoBuffer data; /** * Data type */ private byte dataType = TYPE_AGGREGATE; /** Constructs a new Aggregate. */ public Aggregate() { this(IoBuffer.allocate(0).flip()); } /** * Create aggregate data event with given data buffer * @param data */ public Aggregate(IoBuffer data) { super(Type.STREAM_DATA); setData(data); } /** * Create aggregate data event with given data buffer * @param data aggregate data * @param copy true to use a copy of the data or false to use reference */ public Aggregate(IoBuffer data, boolean copy) { super(Type.STREAM_DATA); if (copy) { byte[] array = new byte[data.limit()]; data.mark(); data.get(array); data.reset(); setData(array); } else { setData(data); } } /** {@inheritDoc} */ @Override public byte getDataType() { return dataType; } public void setDataType(byte dataType) { this.dataType = dataType; } /** {@inheritDoc} */ public IoBuffer getData() { return data; } public void setData(IoBuffer data) { this.data = data; } public void setData(byte[] data) { this.data = IoBuffer.allocate(data.length); this.data.put(data).flip(); } /** * Breaks-up the aggregate into its individual parts and returns them as a list. * The parts are returned based on the ordering of the aggregate itself. * * @return list of IRTMPEvent objects */ public LinkedList getParts() { LinkedList parts = new LinkedList(); //log.debug("Aggregate data length: {}", data.limit()); int position = data.position(); do { // read the header //log.trace("Hex: {}", data.getHexDump()); byte subType = data.get(); int size = IOUtils.readUnsignedMediumInt(data); log.debug("Data subtype: {} size: {}", subType, size); int timestamp = IOUtils.readExtendedMediumInt(data); /*timestamp = ntohap((GETIBPOINTER(buffer) + 4)); 0x12345678 == 34 56 78 12*/ int streamId = IOUtils.readUnsignedMediumInt(data); log.debug("Data timestamp: {} stream id: {}", timestamp, streamId); Header partHeader = new Header(); partHeader.setChannelId(header.getChannelId()); partHeader.setDataType(subType); partHeader.setSize(size); // use the stream id from the aggregate's header partHeader.setStreamId(header.getStreamId()); partHeader.setTimer(timestamp); // timer delta == time stamp - timer base //partHeader.setTimerBase(timerBase); //partHeader.setTimerDelta(timerDelta); // the back pointer may be used to verify the size of the individual part // it will be equal to the data size + header size int backPointer = 0; switch (subType) { case TYPE_AUDIO_DATA: AudioData audio = new AudioData(data.getSlice(size)); audio.setTimestamp(timestamp); audio.setHeader(partHeader); log.debug("Audio header: {}", audio.getHeader()); parts.add(audio); //log.trace("Hex: {}", data.getHexDump()); backPointer = data.getInt(); //log.trace("Back pointer: {}", backPointer); if (backPointer != (size + 11)) { log.debug("Data size ({}) and back pointer ({}) did not match", size, backPointer); } break; case TYPE_VIDEO_DATA: VideoData video = new VideoData(data.getSlice(size)); video.setTimestamp(timestamp); video.setHeader(partHeader); log.debug("Video header: {}", video.getHeader()); parts.add(video); //log.trace("Hex: {}", data.getHexDump()); backPointer = data.getInt(); //log.trace("Back pointer: {}", backPointer); if (backPointer != (size + 11)) { log.debug("Data size ({}) and back pointer ({}) did not match", size, backPointer); } break; default: log.debug("Non-A/V subtype: {}", subType); Unknown unk = new Unknown(subType, data.getSlice(size)); unk.setTimestamp(timestamp); unk.setHeader(partHeader); parts.add(unk); backPointer = data.getInt(); } position = data.position(); //log.trace("Data position: {}", position); } while (position < data.limit()); //log.debug("Aggregate processing complete, {} parts extracted", parts.size()); return parts; } /** {@inheritDoc} */ @Override public String toString() { return String.format("Aggregate - ts: %s length: %s", getTimestamp(), (data != null ? data.limit() : '0')); } /** {@inheritDoc} */ @Override protected void releaseInternal() { if (data != null) { final IoBuffer localData = data; // null out the data first so we don't accidentally // return a valid reference first data = null; localData.clear(); localData.free(); } } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); byte[] byteBuf = (byte[]) in.readObject(); if (byteBuf != null) { data = IoBuffer.allocate(byteBuf.length); data.setAutoExpand(true); SerializeUtils.ByteArrayToByteBuffer(byteBuf, data); } } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); if (data != null) { out.writeObject(SerializeUtils.ByteBufferToByteArray(data)); } else { out.writeObject(null); } } /** * Duplicate this message / event. * * @return duplicated event */ public Aggregate duplicate() throws IOException, ClassNotFoundException { Aggregate result = new Aggregate(); // serialize ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); writeExternal(oos); oos.close(); // convert to byte array byte[] buf = baos.toByteArray(); baos.close(); // create input streams ByteArrayInputStream bais = new ByteArrayInputStream(buf); ObjectInputStream ois = new ObjectInputStream(bais); // deserialize result.readExternal(ois); ois.close(); bais.close(); // clone the header if there is one if (header != null) { result.setHeader(header.clone()); } return result; } }red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/IRTMPEvent.java0000644000175000017500000000401711706617130025473 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import org.red5.server.api.event.IEvent; import org.red5.server.api.event.IEventListener; import org.red5.server.net.rtmp.message.Header; public interface IRTMPEvent extends IEvent { /** * Getter for data type * * @return Data type */ public byte getDataType(); /** * Setter for source * * @param source Source */ public void setSource(IEventListener source); /** * Getter for header * * @return RTMP packet header */ public Header getHeader(); /** * Setter for header * * @param header RTMP packet header */ public void setHeader(Header header); /** * Getter for timestamp * * @return Event timestamp */ public int getTimestamp(); /** * Setter for timestamp * * @param timestamp New event timestamp */ public void setTimestamp(int timestamp); /** * Getter for source type * * @return Source type */ public byte getSourceType(); /** * Setter for source type * * @param sourceType */ public void setSourceType(byte sourceType); /** * Retain event */ public void retain(); /** * Hook to free buffers allocated by the event. */ public void release(); } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/Unknown.java0000644000175000017500000000526611706617130025244 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.utils.HexDump; /** * Unknown event */ public class Unknown extends BaseEvent { private static final long serialVersionUID = -1352770037962252975L; /** * Event data */ protected IoBuffer data; /** * Type of data */ protected byte dataType; public Unknown() {} /** * Create new unknown event with given data and data type * @param dataType Data type * @param data Event data */ public Unknown(byte dataType, IoBuffer data) { super(Type.SYSTEM); this.dataType = dataType; this.data = data; } /** {@inheritDoc} */ @Override public byte getDataType() { return dataType; } /** * Getter for data * * @return Data */ public IoBuffer getData() { return data; } /** {@inheritDoc} */ @Override public String toString() { final IoBuffer buf = getData(); StringBuffer sb = new StringBuffer(); sb.append("Size: "); sb.append(buf.remaining()); sb.append(" Data:\n\n"); sb.append(HexDump.formatHexDump(buf.getHexDump())); return sb.toString(); } /** {@inheritDoc} */ @Override protected void releaseInternal() { if (data != null) { data.free(); data = null; } } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); dataType = in.readByte(); byte[] byteBuf = (byte[]) in.readObject(); if (byteBuf != null) { data = IoBuffer.allocate(0); data.setAutoExpand(true); SerializeUtils.ByteArrayToByteBuffer(byteBuf, data); } } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeByte(dataType); if (data != null) { out.writeObject(SerializeUtils.ByteBufferToByteArray(data)); } else { out.writeObject(null); } } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/VideoData.java0000644000175000017500000001233211706617130025435 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.IoConstants; import org.red5.server.api.stream.IStreamPacket; import org.red5.server.stream.IStreamData; /** * Video data event */ public class VideoData extends BaseEvent implements IoConstants, IStreamData, IStreamPacket { private static final long serialVersionUID = 5538859593815804830L; /** * Videoframe type */ public static enum FrameType { UNKNOWN, KEYFRAME, INTERFRAME, DISPOSABLE_INTERFRAME, } /** * Video data */ protected IoBuffer data; /** * Data type */ private byte dataType = TYPE_VIDEO_DATA; /** * Frame type, unknown by default */ protected FrameType frameType = FrameType.UNKNOWN; /** Constructs a new VideoData. */ public VideoData() { this(IoBuffer.allocate(0).flip()); } /** * Create video data event with given data buffer * @param data Video data */ public VideoData(IoBuffer data) { super(Type.STREAM_DATA); setData(data); } /** * Create video data event with given data buffer * @param data Video data * @param copy true to use a copy of the data or false to use reference */ public VideoData(IoBuffer data, boolean copy) { super(Type.STREAM_DATA); if (copy) { byte[] array = new byte[data.limit()]; data.mark(); data.get(array); data.reset(); setData(array); } else { setData(data); } } /** {@inheritDoc} */ @Override public byte getDataType() { return dataType; } public void setDataType(byte dataType) { this.dataType = dataType; } /** {@inheritDoc} */ public IoBuffer getData() { return data; } public void setData(IoBuffer data) { this.data = data; if (data != null && data.limit() > 0) { data.mark(); int firstByte = (data.get(0)) & 0xff; data.reset(); int frameType = (firstByte & MASK_VIDEO_FRAMETYPE) >> 4; if (frameType == FLAG_FRAMETYPE_KEYFRAME) { this.frameType = FrameType.KEYFRAME; } else if (frameType == FLAG_FRAMETYPE_INTERFRAME) { this.frameType = FrameType.INTERFRAME; } else if (frameType == FLAG_FRAMETYPE_DISPOSABLE) { this.frameType = FrameType.DISPOSABLE_INTERFRAME; } else { this.frameType = FrameType.UNKNOWN; } } } public void setData(byte[] data) { this.data = IoBuffer.allocate(data.length); this.data.put(data).flip(); } /** * Getter for frame type * * @return Type of video frame */ public FrameType getFrameType() { return frameType; } /** {@inheritDoc} */ @Override protected void releaseInternal() { if (data != null) { final IoBuffer localData = data; // null out the data first so we don't accidentally // return a valid reference first data = null; localData.clear(); localData.free(); } } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); frameType = (FrameType) in.readObject(); byte[] byteBuf = (byte[]) in.readObject(); if (byteBuf != null) { data = IoBuffer.allocate(byteBuf.length); data.setAutoExpand(true); SerializeUtils.ByteArrayToByteBuffer(byteBuf, data); } } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeObject(frameType); if (data != null) { out.writeObject(SerializeUtils.ByteBufferToByteArray(data)); } else { out.writeObject(null); } } /** * Duplicate this message / event. * * @return duplicated event */ public VideoData duplicate() throws IOException, ClassNotFoundException { VideoData result = new VideoData(); // serialize ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); writeExternal(oos); oos.close(); // convert to byte array byte[] buf = baos.toByteArray(); baos.close(); // create input streams ByteArrayInputStream bais = new ByteArrayInputStream(buf); ObjectInputStream ois = new ObjectInputStream(bais); // deserialize result.readExternal(ois); ois.close(); bais.close(); // clone the header if there is one if (header != null) { result.setHeader(header.clone()); } return result; } /** {@inheritDoc} */ @Override public String toString() { return String.format("Video - ts: %s length: %s", getTimestamp(), (data != null ? data.limit() : '0')); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/AllocationDebugger.java0000644000175000017500000000615211706617130027332 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Simple allocation debugger for Event reference counting. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) on behalf of * (ce@publishing-etc.de) * @author Paul Gregoire (mondain@gmail.com) */ public class AllocationDebugger { /** * Information on references count */ private static class Info { /** * References count */ public AtomicInteger refcount = new AtomicInteger(1); /** Constructs a new Info. */ public Info() { } } /** * Allocation debugger istance */ private static AllocationDebugger instance = new AllocationDebugger(); /** * Logger */ private Logger log; /** * Events-to-information objects map */ private ConcurrentMap events; /** * Getter for instance * * @return Allocation debugger instance */ public static AllocationDebugger getInstance() { return instance; } /** Do not instantiate AllocationDebugger. */ private AllocationDebugger() { log = LoggerFactory.getLogger(getClass()); events = new ConcurrentHashMap(); } /** * Add event to map * * @param event * Event */ protected void create(BaseEvent event) { events.put(event, new Info()); } /** * Retain event * * @param event * Event */ protected void retain(BaseEvent event) { Info info = events.get(event); if (info != null) { info.refcount.incrementAndGet(); } else { log.warn("Retain called on already released event."); } } /** * Release event if there's no more references to it * * @param event * Event */ protected void release(BaseEvent event) { Info info = events.get(event); if (info != null) { if (info.refcount.decrementAndGet() == 0) { events.remove(event); } } else { log.warn("Release called on already released event."); } } /** * Dumps allocations */ public synchronized void dump() { if (log.isDebugEnabled()) { log.debug("dumping allocations {}", events.size()); for (Entry entry : events.entrySet()) { log.debug("{} {}", entry.getKey(), entry.getValue().refcount); } } } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/FlexStreamSend.java0000644000175000017500000000243711706617130026466 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import org.apache.mina.core.buffer.IoBuffer; /** * AMF3 stream send message. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class FlexStreamSend extends Notify { private static final long serialVersionUID = -4226252245996614504L; public FlexStreamSend() {} /** * Create new stream send object. * * @param data data */ public FlexStreamSend(IoBuffer data) { super(data); } /** {@inheritDoc} */ @Override public byte getDataType() { return TYPE_FLEX_STREAM_SEND; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/Abort.java0000644000175000017500000000324711706617130024651 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; /** * RTMP Abort event. * * @author aclarke@xuggle.com * */ public class Abort extends BaseEvent { private int channelId=0; public Abort() { super(Type.SYSTEM); } public Abort(int channelId) { this.channelId = channelId; } public byte getDataType() { return TYPE_ABORT; } protected void releaseInternal() { } public void setChannelId(int channelId) { this.channelId = channelId; } public int getChannelId() { return channelId; } /** {@inheritDoc} */ @Override public String toString() { return "Abort Channel: " + channelId; } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); channelId= in.readInt(); } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeInt(channelId); } }red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/BytesRead.java0000644000175000017500000000437411706617130025466 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; /** * Bytes read event */ public class BytesRead extends BaseEvent { private static final long serialVersionUID = -127649312402709338L; /** * Bytes read */ private int bytesRead; public BytesRead() { super(Type.STREAM_CONTROL); } /** * Creates new event with given bytes number * @param bytesRead Number of bytes read */ public BytesRead(int bytesRead) { this(); this.bytesRead = bytesRead; } /** {@inheritDoc} */ @Override public byte getDataType() { return TYPE_BYTES_READ; } /** * Return number of bytes read * * @return Number of bytes */ public int getBytesRead() { return bytesRead; } /** * Setter for bytes read * * @param bytesRead Number of bytes read */ public void setBytesRead(int bytesRead) { this.bytesRead = bytesRead; } /** * Release event (set bytes read to zero) */ protected void doRelease() { bytesRead = 0; } /** {@inheritDoc} */ @Override public String toString() { return "StreamBytesRead: " + bytesRead; } /** {@inheritDoc} */ @Override protected void releaseInternal() { } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); bytesRead = in.readInt(); } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeInt(bytesRead); } }red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/ChunkSize.java0000644000175000017500000000475111706617130025506 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; /** * Chunk size event */ public class ChunkSize extends BaseEvent { private static final long serialVersionUID = -7680099175881755879L; /** * Chunk size */ private int size; public ChunkSize() { super(Type.SYSTEM); } /** * Create chunk size event with given size * @param size Chunk size */ public ChunkSize(int size) { this(); this.size = size; } /** {@inheritDoc} */ @Override public byte getDataType() { return TYPE_CHUNK_SIZE; } /** * Getter for size. * * @return Chunk size */ public int getSize() { return size; } /** * Setter for size. * * @param size Chunk size */ public void setSize(int size) { this.size = size; } /** * Releases chunk (set size to zero) */ protected void doRelease() { size = 0; } /** {@inheritDoc} */ @Override public String toString() { return "ChunkSize: " + size; } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (!(obj instanceof ChunkSize)) { return false; } final ChunkSize other = (ChunkSize) obj; return getSize() == other.getSize(); } /** {@inheritDoc} */ @Override protected void releaseInternal() { } /** {@inheritDoc} */ @Override public int hashCode() { // XXX Paul: use timestamp as the hash instead of Object.hashCode() return timestamp; } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); size = in.readInt(); } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeInt(size); } }red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/event/ServerBW.java0000644000175000017500000000411011706617130025267 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.event; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; /** * Server bandwidth event. Also known as a Window Acknowledgement size message. */ public class ServerBW extends BaseEvent { private static final long serialVersionUID = 24487902555977210L; /** * Bandwidth */ private int bandwidth; public ServerBW() { } /** * Server bandwidth event * @param bandwidth Bandwidth */ public ServerBW(int bandwidth) { super(Type.STREAM_CONTROL); this.bandwidth = bandwidth; } /** {@inheritDoc} */ @Override public byte getDataType() { return TYPE_SERVER_BANDWIDTH; } /** * Getter for bandwidth * * @return Bandwidth */ public int getBandwidth() { return bandwidth; } /** * Setter for bandwidth * * @param bandwidth New bandwidth. */ public void setBandwidth(int bandwidth) { this.bandwidth = bandwidth; } /** {@inheritDoc} */ @Override public String toString() { return "ServerBW: " + bandwidth; } /** {@inheritDoc} */ @Override protected void releaseInternal() { } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); bandwidth = in.readInt(); } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeInt(bandwidth); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/BaseRTMPHandler.java0000644000175000017500000002532211754312773025342 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import java.util.HashSet; import java.util.Set; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.red5.server.api.event.IEventDispatcher; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.api.service.IPendingServiceCallback; import org.red5.server.api.service.IServiceCall; import org.red5.server.api.stream.IClientStream; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.rtmp.event.BytesRead; import org.red5.server.net.rtmp.event.ChunkSize; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.Invoke; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.Ping; import org.red5.server.net.rtmp.event.Unknown; import org.red5.server.net.rtmp.message.Constants; import org.red5.server.net.rtmp.message.Header; import org.red5.server.net.rtmp.message.Packet; import org.red5.server.net.rtmp.message.StreamAction; import org.red5.server.net.rtmp.status.StatusCodes; import org.red5.server.so.SharedObjectMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * Base class for all RTMP handlers. * * @author The Red5 Project (red5@osflash.org) */ public abstract class BaseRTMPHandler implements IRTMPHandler, Constants, StatusCodes, ApplicationContextAware { /** * Logger */ private static Logger log = LoggerFactory.getLogger(BaseRTMPHandler.class); /** * Application context */ private ApplicationContext appCtx; // XXX: HACK HACK HACK to support stream ids private static ThreadLocal streamLocal = new ThreadLocal(); /** * Getter for stream ID. * * @return Stream ID */ // XXX: HACK HACK HACK to support stream ids public static int getStreamId() { return streamLocal.get().intValue(); } /** * Setter for stream Id. * * @param id * Stream id */ private static void setStreamId(int id) { streamLocal.set(id); } /** {@inheritDoc} */ public void setApplicationContext(ApplicationContext appCtx) throws BeansException { this.appCtx = appCtx; } /** {@inheritDoc} */ public void connectionOpened(RTMPConnection conn, RTMP state) { log.trace("connectionOpened - conn: {} state: {}", conn, state); if (appCtx != null) { ISchedulingService service = (ISchedulingService) appCtx.getBean(ISchedulingService.BEAN_NAME); conn.startWaitForHandshake(service); } } /** {@inheritDoc} */ public void messageReceived(Object in, IoSession session) throws Exception { RTMPConnection conn = (RTMPConnection) session.getAttribute(RTMPConnection.RTMP_CONNECTION_KEY); IRTMPEvent message = null; try { final Packet packet = (Packet) in; message = packet.getMessage(); final Header header = packet.getHeader(); final Channel channel = conn.getChannel(header.getChannelId()); final IClientStream stream = conn.getStreamById(header.getStreamId()); log.trace("Message received, header: {}", header); // XXX: HACK HACK HACK to support stream ids BaseRTMPHandler.setStreamId(header.getStreamId()); // increase number of received messages conn.messageReceived(); // set the source of the message message.setSource(conn); // process based on data type switch (header.getDataType()) { case TYPE_CHUNK_SIZE: onChunkSize(conn, channel, header, (ChunkSize) message); break; case TYPE_INVOKE: case TYPE_FLEX_MESSAGE: onInvoke(conn, channel, header, (Invoke) message, (RTMP) session.getAttribute(ProtocolState.SESSION_KEY)); IPendingServiceCall call = ((Invoke) message).getCall(); if (message.getHeader().getStreamId() != 0 && call.getServiceName() == null && StreamAction.PUBLISH.equals(call.getServiceMethodName())) { if (stream != null) { // Only dispatch if stream really was created ((IEventDispatcher) stream).dispatchEvent(message); } } break; case TYPE_NOTIFY: // just like invoke, but does not return if (((Notify) message).getData() != null && stream != null) { // Stream metadata ((IEventDispatcher) stream).dispatchEvent(message); } else { onInvoke(conn, channel, header, (Notify) message, (RTMP) session.getAttribute(ProtocolState.SESSION_KEY)); } break; case TYPE_FLEX_STREAM_SEND: if (stream != null) { ((IEventDispatcher) stream).dispatchEvent(message); } break; case TYPE_PING: onPing(conn, channel, header, (Ping) message); break; case TYPE_BYTES_READ: onStreamBytesRead(conn, channel, header, (BytesRead) message); break; case TYPE_AGGREGATE: log.debug("Aggregate type data - header timer: {} size: {}", header.getTimer(), header.getSize()); case TYPE_AUDIO_DATA: case TYPE_VIDEO_DATA: //mark the event as from a live source //log.trace("Marking message as originating from a Live source"); message.setSourceType(Constants.SOURCE_TYPE_LIVE); // NOTE: If we respond to "publish" with "NetStream.Publish.BadName", // the client sends a few stream packets before stopping. We need to ignore them. if (stream != null) { ((IEventDispatcher) stream).dispatchEvent(message); } break; case TYPE_FLEX_SHARED_OBJECT: case TYPE_SHARED_OBJECT: onSharedObject(conn, channel, header, (SharedObjectMessage) message); break; case Constants.TYPE_CLIENT_BANDWIDTH: //onBWDone log.debug("Client bandwidth: {}", message); break; case Constants.TYPE_SERVER_BANDWIDTH: log.debug("Server bandwidth: {}", message); break; default: log.debug("Unknown type: {}", header.getDataType()); } if (message instanceof Unknown) { log.info("Message type unknown: {}", message); } } catch (RuntimeException e) { log.error("Exception", e); } // XXX this may be causing 'missing' data if previous methods are not making copies // before buffering etc.. if (message != null) { message.release(); } } /** {@inheritDoc} */ public void messageSent(RTMPConnection conn, Object message) { log.trace("Message sent"); if (message instanceof IoBuffer) { return; } // increase number of sent messages conn.messageSent((Packet) message); } /** {@inheritDoc} */ public void connectionClosed(RTMPConnection conn, RTMP state) { state.setState(RTMP.STATE_DISCONNECTED); conn.close(); } /** * Return hostname for URL. * * @param url * URL * @return Hostname from that URL */ protected String getHostname(String url) { log.debug("url: {}", url); String[] parts = url.split("/"); if (parts.length == 2) { return ""; } else { String host = parts[2]; // strip out default port in case the client added the port explicitly if (host.endsWith(":1935")) { // remove default port from connection string return host.substring(0, host.length() - 5); } return host; } } /** * Handler for pending call result. Dispatches results to all pending call * handlers. * * @param conn * Connection * @param invoke * Pending call result event context */ protected void handlePendingCallResult(RTMPConnection conn, Notify invoke) { final IServiceCall call = invoke.getCall(); final IPendingServiceCall pendingCall = conn.retrievePendingCall(invoke.getInvokeId()); if (pendingCall != null) { // The client sent a response to a previously made call. Object[] args = call.getArguments(); if (args != null && args.length > 0) { // TODO: can a client return multiple results? pendingCall.setResult(args[0]); } Set callbacks = pendingCall.getCallbacks(); if (!callbacks.isEmpty()) { HashSet tmp = new HashSet(); tmp.addAll(callbacks); for (IPendingServiceCallback callback : tmp) { try { callback.resultReceived(pendingCall); } catch (Exception e) { log.error("Error while executing callback {}", callback, e); } } } } } /** * Chunk size change event handler. Abstract, to be implemented in * subclasses. * * @param conn * Connection * @param channel * Channel * @param source * Header * @param chunkSize * New chunk size */ protected abstract void onChunkSize(RTMPConnection conn, Channel channel, Header source, ChunkSize chunkSize); /** * Invocation event handler. * * @param conn * Connection * @param channel * Channel * @param source * Header * @param invoke * Invocation event context * @param rtmp * RTMP connection state */ protected abstract void onInvoke(RTMPConnection conn, Channel channel, Header source, Notify invoke, RTMP rtmp); /** * Ping event handler. * * @param conn * Connection * @param channel * Channel * @param source * Header * @param ping * Ping event context */ protected abstract void onPing(RTMPConnection conn, Channel channel, Header source, Ping ping); /** * Stream bytes read event handler. * * @param conn * Connection * @param channel * Channel * @param source * Header * @param streamBytesRead * Bytes read event context */ protected void onStreamBytesRead(RTMPConnection conn, Channel channel, Header source, BytesRead streamBytesRead) { conn.receivedBytesRead(streamBytesRead.getBytesRead()); } /** * Shared object event handler. * * @param conn * Connection * @param channel * Channel * @param source * Header * @param object * Shared object event context */ protected abstract void onSharedObject(RTMPConnection conn, Channel channel, Header source, SharedObjectMessage object); } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/RTMPHandler.java0000644000175000017500000005066411747114732024553 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import java.util.HashMap; import java.util.Map; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.IConnection.Encoding; import org.red5.server.api.IContext; import org.red5.server.api.IServer; import org.red5.server.api.Red5; import org.red5.server.api.scope.IBroadcastScope; import org.red5.server.api.scope.IGlobalScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeHandler; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.api.service.IServiceCall; import org.red5.server.api.so.ISharedObject; import org.red5.server.api.so.ISharedObjectSecurity; import org.red5.server.api.so.ISharedObjectSecurityService; import org.red5.server.api.so.ISharedObjectService; import org.red5.server.api.stream.IClientBroadcastStream; import org.red5.server.api.stream.IClientStream; import org.red5.server.api.stream.IStreamService; import org.red5.server.exception.ClientRejectedException; import org.red5.server.exception.ScopeNotFoundException; import org.red5.server.exception.ScopeShuttingDownException; import org.red5.server.messaging.IConsumer; import org.red5.server.messaging.OOBControlMessage; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.rtmp.event.ChunkSize; import org.red5.server.net.rtmp.event.Invoke; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.Ping; import org.red5.server.net.rtmp.message.Header; import org.red5.server.net.rtmp.message.StreamAction; import org.red5.server.net.rtmp.status.Status; import org.red5.server.net.rtmp.status.StatusObject; import org.red5.server.net.rtmp.status.StatusObjectService; import org.red5.server.service.Call; import org.red5.server.so.ISharedObjectEvent; import org.red5.server.so.SharedObjectEvent; import org.red5.server.so.SharedObjectMessage; import org.red5.server.so.SharedObjectService; import org.red5.server.stream.StreamService; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; /** * RTMP events handler. */ public class RTMPHandler extends BaseRTMPHandler { protected static Logger log = Red5LoggerFactory.getLogger(RTMPHandler.class); /** * Status object service. */ protected StatusObjectService statusObjectService; /** * Red5 server instance. */ protected IServer server; /** * Whether or not global scope connections are allowed. */ private boolean globalScopeConnectionAllowed = false; /** * Setter for server object. * * @param server Red5 server instance */ public void setServer(IServer server) { this.server = server; } /** * Setter for status object service. * * @param statusObjectService Status object service. */ public void setStatusObjectService(StatusObjectService statusObjectService) { this.statusObjectService = statusObjectService; } public boolean isGlobalScopeConnectionAllowed() { return globalScopeConnectionAllowed; } public void setGlobalScopeConnectionAllowed(boolean globalScopeConnectionAllowed) { this.globalScopeConnectionAllowed = globalScopeConnectionAllowed; } /** {@inheritDoc} */ @Override protected void onChunkSize(RTMPConnection conn, Channel channel, Header source, ChunkSize chunkSize) { for (IClientStream stream : conn.getStreams()) { if (stream instanceof IClientBroadcastStream) { IClientBroadcastStream bs = (IClientBroadcastStream) stream; IBroadcastScope scope = bs.getScope().getBroadcastScope(bs.getPublishedName()); if (scope == null) { continue; } OOBControlMessage setChunkSize = new OOBControlMessage(); setChunkSize.setTarget("ClientBroadcastStream"); setChunkSize.setServiceName("chunkSize"); if (setChunkSize.getServiceParamMap() == null) { setChunkSize.setServiceParamMap(new HashMap()); } setChunkSize.getServiceParamMap().put("chunkSize", chunkSize.getSize()); scope.sendOOBControlMessage((IConsumer) null, setChunkSize); log.debug("Sending chunksize {} to {}", chunkSize, bs.getProvider()); } } } /** * Remoting call invocation handler. * * @param conn RTMP connection * @param call Service call */ protected void invokeCall(RTMPConnection conn, IServiceCall call) { final IScope scope = conn.getScope(); if (scope.hasHandler()) { final IScopeHandler handler = scope.getHandler(); log.debug("Scope: {} handler: {}", scope, handler); if (!handler.serviceCall(conn, call)) { // XXX: What to do here? Return an error? return; } } final IContext context = scope.getContext(); log.debug("Context: {}", context); context.getServiceInvoker().invoke(call, scope); } /** * Remoting call invocation handler. * * @param conn * RTMP connection * @param call * Service call * @param service * Server-side service object * @return true if the call was performed, otherwise * false */ private boolean invokeCall(RTMPConnection conn, IServiceCall call, Object service) { final IScope scope = conn.getScope(); final IContext context = scope.getContext(); log.debug("Scope: {} Context: {}", scope, context); log.debug("Service: {}", service); return context.getServiceInvoker().invoke(call, service); } /** {@inheritDoc} */ @SuppressWarnings({ "unchecked" }) @Override protected void onInvoke(RTMPConnection conn, Channel channel, Header source, Notify invoke, RTMP rtmp) { log.debug("Invoke: {}", invoke); // Get call final IServiceCall call = invoke.getCall(); //log.debug("Call: {}", call); // method name final String action = call.getServiceMethodName(); // If it's a callback for server remote call then pass it over to // callbacks handler and return if ("_result".equals(action) || "_error".equals(action)) { handlePendingCallResult(conn, invoke); return; } boolean disconnectOnReturn = false; // If this is not a service call then handle connection... if (call.getServiceName() == null) { log.debug("call: {}", call); if (!conn.isConnected() && StreamAction.CONNECT.equals(action)) { // Handle connection log.debug("connect"); // Get parameters passed from client to // NetConnection#connection final Map params = invoke.getConnectionParams(); // Get hostname String host = getHostname((String) params.get("tcUrl")); // App name as path, but without query string if there is // one String path = (String) params.get("app"); if (path.indexOf("?") != -1) { int idx = path.indexOf("?"); params.put("queryString", path.substring(idx)); path = path.substring(0, idx); } params.put("path", path); final String sessionId = null; conn.setup(host, path, sessionId, params); try { // Lookup server scope when connected // Use host and application name IGlobalScope global = server.lookupGlobal(host, path); log.trace("Global lookup result: {}", global); if (global != null) { final IContext context = global.getContext(); IScope scope = null; try { scope = context.resolveScope(global, path); //if global scope connection is not allowed, reject if (scope.getDepth() < 1 && !globalScopeConnectionAllowed) { call.setStatus(Call.STATUS_ACCESS_DENIED); if (call instanceof IPendingServiceCall) { IPendingServiceCall pc = (IPendingServiceCall) call; StatusObject status = getStatus(NC_CONNECT_REJECTED); status.setDescription("Global scope connection disallowed on this server."); pc.setResult(status); } disconnectOnReturn = true; } } catch (ScopeNotFoundException err) { call.setStatus(Call.STATUS_SERVICE_NOT_FOUND); if (call instanceof IPendingServiceCall) { StatusObject status = getStatus(NC_CONNECT_REJECTED); status.setDescription(String.format("No scope '%s' on this server.", path)); ((IPendingServiceCall) call).setResult(status); } log.info("Scope {} not found on {}", path, host); disconnectOnReturn = true; } catch (ScopeShuttingDownException err) { call.setStatus(Call.STATUS_APP_SHUTTING_DOWN); if (call instanceof IPendingServiceCall) { StatusObject status = getStatus(NC_CONNECT_APPSHUTDOWN); status.setDescription(String.format("Application at '%s' is currently shutting down.", path)); ((IPendingServiceCall) call).setResult(status); } log.info("Application at {} currently shutting down on {}", path, host); disconnectOnReturn = true; } if (scope != null) { log.info("Connecting to: {}", scope); boolean okayToConnect; try { log.debug("Conn {}, scope {}, call {}", new Object[] { conn, scope, call }); log.debug("Call args {}", call.getArguments()); if (call.getArguments() != null) { okayToConnect = conn.connect(scope, call.getArguments()); } else { okayToConnect = conn.connect(scope); } if (okayToConnect) { log.debug("Connected - Client: {}", conn.getClient()); call.setStatus(Call.STATUS_SUCCESS_RESULT); if (call instanceof IPendingServiceCall) { IPendingServiceCall pc = (IPendingServiceCall) call; //send fmsver and capabilities StatusObject result = getStatus(NC_CONNECT_SUCCESS); result.setAdditional("fmsVer", Red5.getFMSVersion()); result.setAdditional("capabilities", Integer.valueOf(31)); result.setAdditional("mode", Integer.valueOf(1)); result.setAdditional("data", Red5.getDataVersion()); pc.setResult(result); } // Measure initial roundtrip time after connecting conn.ping(new Ping(Ping.STREAM_BEGIN, 0, -1)); conn.startRoundTripMeasurement(); } else { log.debug("Connect failed"); call.setStatus(Call.STATUS_ACCESS_DENIED); if (call instanceof IPendingServiceCall) { IPendingServiceCall pc = (IPendingServiceCall) call; pc.setResult(getStatus(NC_CONNECT_REJECTED)); } disconnectOnReturn = true; } } catch (ClientRejectedException rejected) { log.debug("Connect rejected"); call.setStatus(Call.STATUS_ACCESS_DENIED); if (call instanceof IPendingServiceCall) { IPendingServiceCall pc = (IPendingServiceCall) call; StatusObject status = getStatus(NC_CONNECT_REJECTED); Object reason = rejected.getReason(); if (reason != null) { status.setApplication(reason); //should we set description? status.setDescription(reason.toString()); } pc.setResult(status); } disconnectOnReturn = true; } } } else { call.setStatus(Call.STATUS_SERVICE_NOT_FOUND); if (call instanceof IPendingServiceCall) { StatusObject status = getStatus(NC_CONNECT_INVALID_APPLICATION); status.setDescription(String.format("No scope '%s' on this server.", path)); ((IPendingServiceCall) call).setResult(status); } log.info("No application scope found for {} on host {}", path, host); disconnectOnReturn = true; } } catch (RuntimeException e) { call.setStatus(Call.STATUS_GENERAL_EXCEPTION); if (call instanceof IPendingServiceCall) { IPendingServiceCall pc = (IPendingServiceCall) call; pc.setResult(getStatus(NC_CONNECT_FAILED)); } log.error("Error connecting {}", e); disconnectOnReturn = true; } // Evaluate request for AMF3 encoding if (Integer.valueOf(3).equals(params.get("objectEncoding"))) { if (call instanceof IPendingServiceCall) { Object pcResult = ((IPendingServiceCall) call).getResult(); Map result; if (pcResult instanceof Map) { result = (Map) pcResult; result.put("objectEncoding", 3); } else if (pcResult instanceof StatusObject) { result = new HashMap(); StatusObject status = (StatusObject) pcResult; result.put("code", status.getCode()); result.put("description", status.getDescription()); result.put("application", status.getApplication()); result.put("level", status.getLevel()); result.put("objectEncoding", 3); ((IPendingServiceCall) call).setResult(result); } } rtmp.setEncoding(Encoding.AMF3); } } else { //log.debug("Enum value of: {}", StreamAction.getEnum(action)); StreamAction streamAction = StreamAction.getEnum(action); //if the "stream" action is not predefined a custom type will be returned switch (streamAction) { case DISCONNECT: conn.close(); break; case CREATE_STREAM: case INIT_STREAM: case CLOSE_STREAM: case RELEASE_STREAM: case DELETE_STREAM: case PUBLISH: case PLAY: case PLAY2: case SEEK: case PAUSE: case PAUSE_RAW: case RECEIVE_VIDEO: case RECEIVE_AUDIO: IStreamService streamService = (IStreamService) ScopeUtils.getScopeService(conn.getScope(), IStreamService.class, StreamService.class); Status status = null; try { log.debug("Invoking {} from {} with service: {}", new Object[] { call, conn, streamService }); if (!invokeCall(conn, call, streamService)) { status = getStatus(NS_INVALID_ARGUMENT).asStatus(); status.setDescription(String.format("Failed to %s (stream id: %d)", action, source.getStreamId())); } } catch (Throwable err) { log.error("Error while invoking {} on stream service. {}", action, err); status = getStatus(NS_FAILED).asStatus(); status.setDescription(String.format("Error while invoking %s (stream id: %d)", action, source.getStreamId())); status.setDetails(err.getMessage()); } if (status != null) { channel.sendStatus(status); } break; default: invokeCall(conn, call); } } } else if (conn.isConnected()) { // Service calls, must be connected. invokeCall(conn, call); } else { // Warn user attempts to call service without being connected log.warn("Not connected, closing connection"); conn.close(); } if (invoke instanceof Invoke) { if ((source.getStreamId() != 0) && (call.getStatus() == Call.STATUS_SUCCESS_VOID || call.getStatus() == Call.STATUS_SUCCESS_NULL)) { // This fixes a bug in the FP on Intel Macs. log.debug("Method does not have return value, do not reply"); return; } boolean sendResult = true; if (call instanceof IPendingServiceCall) { IPendingServiceCall psc = (IPendingServiceCall) call; Object result = psc.getResult(); if (result instanceof DeferredResult) { // Remember the deferred result to be sent later DeferredResult dr = (DeferredResult) result; dr.setServiceCall(psc); dr.setChannel(channel); dr.setInvokeId(invoke.getInvokeId()); conn.registerDeferredResult(dr); sendResult = false; } } if (sendResult) { // The client expects a result for the method call. Invoke reply = new Invoke(); reply.setCall(call); reply.setInvokeId(invoke.getInvokeId()); channel.write(reply); if (disconnectOnReturn) { conn.close(); } } } } public StatusObject getStatus(String code) { return statusObjectService.getStatusObject(code); } /** {@inheritDoc} */ @Override protected void onPing(RTMPConnection conn, Channel channel, Header source, Ping ping) { switch (ping.getEventType()) { case Ping.CLIENT_BUFFER: IClientStream stream = null; //get the stream id int streamId = ping.getValue2(); //get requested buffer size in milliseconds int buffer = ping.getValue3(); if (streamId != 0) { // The client wants to set the buffer time stream = conn.getStreamById(streamId); if (stream != null) { stream.setClientBufferDuration(buffer); log.debug("Client sent a buffer size: {} ms for stream id: {}", buffer, streamId); log.trace("Stream type: {}", stream.getClass().getName()); } } //catch-all to make sure buffer size is set if (stream == null) { // Remember buffer time until stream is created conn.rememberStreamBufferDuration(streamId, buffer); log.info("Remembering client buffer on stream: {}", buffer); } break; case Ping.PONG_SERVER: // This is the response to an IConnection.ping request conn.pingReceived(ping); break; default: log.warn("Unhandled ping: {}", ping); } } /** * Create and send SO message stating that a SO could not be created. * * @param conn * @param name * @param persistent */ private void sendSOCreationFailed(RTMPConnection conn, String name, boolean persistent) { log.warn("sendSOCreationFailed - name: {} persistent: {} conn: {}", new Object[] { name, persistent, conn }); SharedObjectMessage msg = new SharedObjectMessage(name, 0, persistent); msg.addEvent(new SharedObjectEvent(ISharedObjectEvent.Type.CLIENT_STATUS, "error", SO_CREATION_FAILED)); conn.getChannel(3).write(msg); } /** {@inheritDoc} */ @Override protected void onSharedObject(RTMPConnection conn, Channel channel, Header source, SharedObjectMessage object) { log.debug("onSharedObject: {}", object); // so name String name = object.getName(); // whether or not the incoming so is persistent boolean persistent = object.isPersistent(); log.debug("Incoming shared object - name: {} persistence: {}", name, persistent); final IScope scope = conn.getScope(); if (scope != null) { ISharedObjectService sharedObjectService = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, SharedObjectService.class, false); if (!sharedObjectService.hasSharedObject(scope, name)) { log.debug("Shared object service doesnt have requested object, creation will be attempted"); ISharedObjectSecurityService security = (ISharedObjectSecurityService) ScopeUtils.getScopeService(scope, ISharedObjectSecurityService.class); if (security != null) { // Check handlers to see if creation is allowed for (ISharedObjectSecurity handler : security.getSharedObjectSecurity()) { if (!handler.isCreationAllowed(scope, name, persistent)) { log.debug("Shared object create failed, creation is not allowed"); sendSOCreationFailed(conn, name, persistent); return; } } } if (!sharedObjectService.createSharedObject(scope, name, persistent)) { log.debug("Shared object create failed"); sendSOCreationFailed(conn, name, persistent); return; } } ISharedObject so = sharedObjectService.getSharedObject(scope, name); so.dispatchEvent(object); if (so.isPersistent() != persistent) { log.warn("Shared object persistence mismatch - current: {} incoming: {}", so.isPersistent(), persistent); /* Sending the following message seems to screw up follow-on handling of SO events SharedObjectMessage msg = new SharedObjectMessage(name, 0, persistent); msg.addEvent(new SharedObjectEvent(ISharedObjectEvent.Type.CLIENT_STATUS, "error", SO_PERSISTENCE_MISMATCH)); conn.getChannel(3).write(msg); */ } } else { // The scope already has been deleted log.debug("Shared object scope was not found"); sendSOCreationFailed(conn, name, persistent); return; } } protected void onBWDone() { log.debug("onBWDone"); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/message/0000755000175000017500000000000011760512572023240 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/message/Header.java0000644000175000017500000001251211706617130025270 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.message; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; /** * RTMP packet header */ public class Header implements Constants, Cloneable, Externalizable { private static final long serialVersionUID = 8982665579411495024L; /** * Channel */ private int channelId; /** * Timer */ private int timerBase; /** * Delta */ private int timerDelta; /** * Header size */ private int size; /** * Type of data */ private byte dataType; /** * Stream id */ private int streamId; /** * Extended Timestamp */ private int extendedTimestamp; /** * Flash player occasionally sends garbage audio that as far as I can tell exists only to make folks who * don't know about it slowly get out-of-sync audio and video. We now detect that. */ private boolean isGarbage = false; /** * Getter for channel id * * @return Channel id */ public int getChannelId() { return channelId; } /** * Setter for channel id * * @param channelId Header channel id */ public void setChannelId(int channelId) { this.channelId = channelId; } /** * Getter for data type * * @return Data type */ public byte getDataType() { return dataType; } /** * Setter for data type * * @param dataType Data type */ public void setDataType(byte dataType) { this.dataType = dataType; } /** * Getter for size. * * @return Header size */ public int getSize() { return size; } /** * Setter for size * * @param size Header size */ public void setSize(int size) { this.size = size; } /** * Getter for stream id * * @return Stream id */ public int getStreamId() { return streamId; } /** * Setter for stream id * * @param streamId Stream id */ public void setStreamId(int streamId) { this.streamId = streamId; } /** * Getter for Extended Timestamp * * @return Extended Timestamp */ public int getExtendedTimestamp() { return extendedTimestamp; } /** * Setter for Extended Timestamp * * @param extendedTimestamp Extended Timestamp */ public void setExtendedTimestamp(int extendedTimestamp) { this.extendedTimestamp = extendedTimestamp; } /** * Getter for timer * * @return Timer */ public int getTimer() { return timerBase + timerDelta; } /** * Setter for timer * * @param timer Timer */ public void setTimer(int timer) { this.timerBase = timer; this.timerDelta = 0; } public void setTimerDelta(int timerDelta) { this.timerDelta = timerDelta; } public int getTimerDelta() { return timerDelta; } public void setTimerBase(int timerBase) { this.timerBase = timerBase; } public int getTimerBase() { return timerBase; } public void setIsGarbage(boolean isGarbage) { this.isGarbage = isGarbage; } public boolean isGarbage() { return isGarbage; } /** {@inheritDoc} */ @Override public boolean equals(Object other) { if (!(other instanceof Header)) { return false; } final Header header = (Header) other; return (header.getChannelId() == channelId && header.getDataType() == dataType && header.getSize() == size && header.getTimer() == this.getTimer() && header.getStreamId() == streamId && header.getExtendedTimestamp() == extendedTimestamp); } /** {@inheritDoc} */ @Override public Header clone() { final Header header = new Header(); header.setChannelId(channelId); header.setTimerBase(timerBase); header.setTimerDelta(timerDelta); header.setSize(size); header.setDataType(dataType); header.setStreamId(streamId); header.setExtendedTimestamp(extendedTimestamp); header.setIsGarbage(isGarbage); return header; } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { dataType = in.readByte(); channelId = in.readInt(); size = in.readInt(); streamId = in.readInt(); timerBase = in.readInt(); timerDelta = in.readInt(); extendedTimestamp = in.readInt(); isGarbage = in.readBoolean(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeByte(dataType); out.writeInt(channelId); out.writeInt(size); out.writeInt(streamId); out.writeInt(timerBase); out.writeInt(timerDelta); out.writeInt(extendedTimestamp); out.writeBoolean(isGarbage); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "Header [channelId=" + channelId + ", dataType=" + dataType + ", timerBase=" + timerBase + ", timerDelta=" + timerDelta + ", size=" + size + ", streamId=" + streamId + ", extendedTimestamp=" + extendedTimestamp + ", isGarbage=" + isGarbage + "]"; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/message/SharedObjectTypeMapping.java0000644000175000017500000000724011706617130030615 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.message; import org.red5.server.so.ISharedObjectEvent.Type; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * SO event types mapping */ public class SharedObjectTypeMapping { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(SharedObjectTypeMapping.class .getName()); /** * Types map */ public static final Type[] typeMap = new Type[] { null, Type.SERVER_CONNECT, // 01 Type.SERVER_DISCONNECT, // 02 Type.SERVER_SET_ATTRIBUTE, // 03 Type.CLIENT_UPDATE_DATA, // 04 Type.CLIENT_UPDATE_ATTRIBUTE, // 05 Type.SERVER_SEND_MESSAGE, // 06 Type.CLIENT_STATUS, // 07 Type.CLIENT_CLEAR_DATA, // 08 Type.CLIENT_DELETE_DATA, // 09 Type.SERVER_DELETE_ATTRIBUTE, // 0A Type.CLIENT_INITIAL_DATA, // 0B }; /** * Convert byte value of RTMP marker to event type * @param rtmpType RTMP marker value * @return Corresponding Shared Object event type */ public static Type toType(byte rtmpType) { return typeMap[rtmpType]; } /** * Convert SO event type to byte representation that RTMP uses * @param type Event type * @return Byte representation of given event type */ public static byte toByte(Type type) { switch (type) { case SERVER_CONNECT: return 0x01; case SERVER_DISCONNECT: return 0x02; case SERVER_SET_ATTRIBUTE: return 0x03; case CLIENT_UPDATE_DATA: return 0x04; case CLIENT_UPDATE_ATTRIBUTE: return 0x05; case SERVER_SEND_MESSAGE: return 0x06; case CLIENT_SEND_MESSAGE: return 0x06; case CLIENT_STATUS: return 0x07; case CLIENT_CLEAR_DATA: return 0x08; case CLIENT_DELETE_DATA: return 0x09; case SERVER_DELETE_ATTRIBUTE: return 0x0A; case CLIENT_INITIAL_DATA: return 0x0B; default: log.error("Unknown type " + type); return 0x00; } } /** * String representation of type * @param type Type * @return String representation of type */ public static String toString(Type type) { switch (type) { case SERVER_CONNECT: return "server connect"; case SERVER_DISCONNECT: return "server disconnect"; case SERVER_SET_ATTRIBUTE: return "server_set_attribute"; case CLIENT_UPDATE_DATA: return "client_update_data"; case CLIENT_UPDATE_ATTRIBUTE: return "client_update_attribute"; case SERVER_SEND_MESSAGE: return "server_send_message"; case CLIENT_SEND_MESSAGE: return "client_send_message"; case CLIENT_STATUS: return "client_status"; case CLIENT_CLEAR_DATA: return "client_clear_data"; case CLIENT_DELETE_DATA: return "client_delete_data"; case SERVER_DELETE_ATTRIBUTE: return "server_delete_attribute"; case CLIENT_INITIAL_DATA: return "client_initial_data"; default: log.error("Unknown type " + type); return "unknown"; } } }red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/message/Constants.java0000644000175000017500000001162611706617130026061 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.message; /** * Class for AMF and RTMP marker values constants */ public interface Constants { /** * Data originated from a file. */ public static final byte SOURCE_TYPE_VOD = 0x0; /** * Data originated from a live encoder or stream. */ public static final byte SOURCE_TYPE_LIVE = 0x01; /** * Medium integer max value */ public static final int MEDIUM_INT_MAX = 16777215; /** * RTMP chunk size constant */ public static final byte TYPE_CHUNK_SIZE = 0x01; /** * Abort message */ public static final byte TYPE_ABORT = 0x02; /** * Acknowledgment. Send every x bytes read by both sides. */ public static final byte TYPE_BYTES_READ = 0x03; /** * Ping is a stream control message, it has sub-types */ public static final byte TYPE_PING = 0x04; /** * Server (downstream) bandwidth marker */ public static final byte TYPE_SERVER_BANDWIDTH = 0x05; /** * Client (upstream) bandwidth marker */ public static final byte TYPE_CLIENT_BANDWIDTH = 0x06; /** * Edge / Origin message. */ public static final byte TYPE_EDGE_ORIGIN = 0x07; /** * Audio data marker */ public static final byte TYPE_AUDIO_DATA = 0x08; /** * Video data marker */ public static final byte TYPE_VIDEO_DATA = 0x09; // Unknown: 0x0A ... 0x0E /** * AMF3 stream send */ public static final byte TYPE_FLEX_STREAM_SEND = 0x0F; /** * AMF3 shared object */ public static final byte TYPE_FLEX_SHARED_OBJECT = 0x10; /** * AMF3 message */ public static final byte TYPE_FLEX_MESSAGE = 0x11; /** * Notification is invocation without response */ public static final byte TYPE_NOTIFY = 0x12; /** * Stream metadata */ public static final byte TYPE_STREAM_METADATA = 0x12; /** * Shared Object marker */ public static final byte TYPE_SHARED_OBJECT = 0x13; /** * Invoke operation (remoting call but also used for streaming) marker */ public static final byte TYPE_INVOKE = 0x14; /** * Aggregate data marker */ public static final byte TYPE_AGGREGATE = 0x16; /** * New header marker */ public static final byte HEADER_NEW = 0x00; /** * Same source marker */ public static final byte HEADER_SAME_SOURCE = 0x01; /** * Timer change marker */ public static final byte HEADER_TIMER_CHANGE = 0x02; /** * There's more to encode */ public static final byte HEADER_CONTINUE = 0x03; /** * Size of initial handshake between client and server */ public static final int HANDSHAKE_SIZE = 1536; /** * Client Shared Object data update */ public static final byte SO_CLIENT_UPDATE_DATA = 0x04; //update data /** * Client Shared Object attribute update */ public static final byte SO_CLIENT_UPDATE_ATTRIBUTE = 0x05; //5: update attribute /** * Send SO message flag */ public static final byte SO_CLIENT_SEND_MESSAGE = 0x06; // 6: send message /** * Shared Object status marker */ public static final byte SO_CLIENT_STATUS = 0x07; // 7: status (usually returned with error messages) /** * Clear event for Shared Object */ public static final byte SO_CLIENT_CLEAR_DATA = 0x08; // 8: clear data /** * Delete data for Shared Object */ public static final byte SO_CLIENT_DELETE_DATA = 0x09; // 9: delete data /** * Initial SO data flag */ public static final byte SO_CLIENT_INITIAL_DATA = 0x0B; // 11: initial data /** * Shared Object connection */ public static final byte SO_CONNECT = 0x01; /** * Shared Object disconnection */ public static final byte SO_DISCONNECT = 0x02; /** * Set Shared Object attribute flag */ public static final byte SO_SET_ATTRIBUTE = 0x03; /** * Send message flag */ public static final byte SO_SEND_MESSAGE = 0x06; /** * Shared Object attribute deletion flag */ public static final byte SO_DELETE_ATTRIBUTE = 0x0A; } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/message/Packet.java0000644000175000017500000000576711706617130025325 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.message; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.net.rtmp.event.IRTMPEvent; /** * RTMP packet. Consists of packet header, data and event context. */ public class Packet implements Externalizable { private static final long serialVersionUID = -6415050845346626950L; /** * Header */ private Header header; /** * RTMP event */ private IRTMPEvent message; /** * Packet data */ private IoBuffer data; public Packet() { data = null; header = null; } /** * Create packet with given header * @param header Packet header */ public Packet(Header header) { this.header = header; data = IoBuffer.allocate(header.getSize(), false); // Workaround for SN-19: BufferOverflowException // Size is checked in RTMPProtocolDecoder data.setAutoExpand(true); } /** * Create packet with given header and event context * @param header RTMP header * @param event RTMP message */ public Packet(Header header, IRTMPEvent event) { this.header = header; this.message = event; } /** * Getter for header * * @return Packet header */ public Header getHeader() { return header; } /** * Setter for event context * * @param message RTMP event context */ public void setMessage(IRTMPEvent message) { this.message = message; } /** * Getter for event context * * @return RTMP event context */ public IRTMPEvent getMessage() { return message; } /** * Setter for data * * @param data Packet data */ public void setData(IoBuffer data) { this.data = data; } /** * Getter for data * * @return Packet data */ public IoBuffer getData() { return data; } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { header = (Header) in.readObject(); message = (IRTMPEvent) in.readObject(); message.setHeader(header); message.setTimestamp(header.getTimer()); } public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(header); out.writeObject(message); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/message/StreamAction.java0000644000175000017500000000467011706617130026477 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.message; import java.util.HashMap; import java.util.Map; /** * Represents all the actions which may be permitted on a stream. * * @author Paul Gregoire */ public enum StreamAction { CONNECT("connect"), DISCONNECT("disconnect"), CREATE_STREAM("createStream"), DELETE_STREAM("deleteStream"), CLOSE_STREAM( "closeStream"), INIT_STREAM("initStream"), RELEASE_STREAM("releaseStream"), PUBLISH("publish"), PAUSE( "pause"), PAUSE_RAW("pauseRaw"), SEEK("seek"), PLAY("play"), PLAY2("play2"), STOP("disconnect"), RECEIVE_VIDEO( "receiveVideo"), RECEIVE_AUDIO("receiveAudio"), CUSTOM(""); //presize to fit all enums in private final static Map map = new HashMap(StreamAction.values().length); //the stream action this enum is for private final String actionString; StreamAction(String actionString) { this.actionString = actionString; } public String getActionString() { return actionString; } public static StreamAction getEnum(String actionString) { //fill the map if its empty if (map.isEmpty()) { //do this only once for (StreamAction action : values()) { map.put(action.getActionString(), action); } } //look up the action from the predefined set StreamAction match = map.get(actionString); if (match != null) { return match; } //return an action representing a custom type return CUSTOM; } public boolean equals(StreamAction action) { return action.getActionString().equals(actionString); } public boolean equals(String actionString) { return getActionString().equals(actionString); } public String toString() { return actionString; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/INetStreamEventHandler.java0000644000175000017500000000167111706617130026773 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import org.red5.server.net.rtmp.event.Notify; /** * Notify handler for client-side stream */ public interface INetStreamEventHandler { void onStreamEvent(Notify notify); } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/IRTMPHandler.java0000644000175000017500000000335411706617130024651 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import org.apache.mina.core.session.IoSession; import org.red5.server.net.rtmp.codec.RTMP; /** * RTMP events handler */ public interface IRTMPHandler { /** * Connection open event * * @param conn Connection * @param state RTMP state */ public void connectionOpened(RTMPConnection conn, RTMP state); /** * Message received * * @param message Message * @param session Connected session * @throws Exception Exception */ public void messageReceived(Object message, IoSession session) throws Exception; /** * Message sent * @param conn Connection * @param message Message */ public void messageSent(RTMPConnection conn, Object message); /** * Connection closed * @param conn Connection * @param state RTMP state */ public void connectionClosed(RTMPConnection conn, RTMP state); } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/IRTMPConnManager.java0000644000175000017500000000202611706617130025457 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import java.util.Collection; public interface IRTMPConnManager { RTMPConnection getConnection(int clientId); RTMPConnection createConnection(Class connCls); RTMPConnection removeConnection(int clientId); Collection removeConnections(); }red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/status/0000755000175000017500000000000011760512572023137 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/status/StatusObjectService.java0000644000175000017500000001704611746326760027753 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.status; import java.util.HashMap; import java.util.Map; import org.apache.commons.beanutils.BeanMap; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.amf.Output; import org.red5.io.object.Serializer; import org.red5.io.utils.HexDump; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; /** * Service that works with status objects. * Note all status object should aim to be under 128 bytes. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class StatusObjectService implements StatusCodes, InitializingBean { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(StatusObjectService.class); /** * Serializer */ protected Serializer serializer; /** * Status objects map */ protected Map statusObjects; /** * Cached status objects map */ protected Map cachedStatusObjects; /** * Setter for serializer * * @param serializer Serializer object */ public void setSerializer(Serializer serializer) { this.serializer = serializer; } /** * Initialization */ public void afterPropertiesSet() throws Exception { log.trace("Loading status objects"); loadStatusObjects(); log.trace("Caching status objects"); cacheStatusObjects(); log.debug("Status service ready"); } /** * Creates all status objects and adds them to status objects map */ public void loadStatusObjects() { statusObjects = new HashMap(); statusObjects.put(NC_CALL_FAILED, new StatusObject(NC_CALL_FAILED, StatusObject.ERROR, "")); statusObjects.put(NC_CALL_BADVERSION, new StatusObject(NC_CALL_BADVERSION, StatusObject.ERROR, "")); statusObjects.put(NC_CONNECT_APPSHUTDOWN, new StatusObject(NC_CONNECT_APPSHUTDOWN, StatusObject.ERROR, "")); statusObjects.put(NC_CONNECT_CLOSED, new StatusObject(NC_CONNECT_CLOSED, StatusObject.STATUS, "")); statusObjects.put(NC_CONNECT_FAILED, new StatusObject(NC_CONNECT_FAILED, StatusObject.ERROR, "")); statusObjects.put(NC_CONNECT_REJECTED, new StatusObject(NC_CONNECT_REJECTED, StatusObject.ERROR, "")); statusObjects.put(NC_CONNECT_SUCCESS, new StatusObject(NC_CONNECT_SUCCESS, StatusObject.STATUS, "Connection succeeded.")); statusObjects.put(NC_CONNECT_INVALID_APPLICATION, new StatusObject(NC_CONNECT_INVALID_APPLICATION, StatusObject.ERROR, "")); statusObjects.put(NS_INVALID_ARGUMENT, new StatusObject(NS_INVALID_ARGUMENT, StatusObject.ERROR, "")); statusObjects.put(NS_CLEAR_SUCCESS, new StatusObject(NS_CLEAR_SUCCESS, StatusObject.STATUS, "")); statusObjects.put(NS_CLEAR_FAILED, new StatusObject(NS_CLEAR_FAILED, StatusObject.ERROR, "")); statusObjects.put(NS_PUBLISH_START, new StatusObject(NS_PUBLISH_START, StatusObject.STATUS, "")); statusObjects.put(NS_PUBLISH_BADNAME, new StatusObject(NS_PUBLISH_BADNAME, StatusObject.ERROR, "")); statusObjects.put(NS_FAILED, new StatusObject(NS_FAILED, StatusObject.ERROR, "")); statusObjects.put(NS_UNPUBLISHED_SUCCESS, new StatusObject(NS_UNPUBLISHED_SUCCESS, StatusObject.STATUS, "")); statusObjects.put(NS_RECORD_START, new StatusObject(NS_RECORD_START, StatusObject.STATUS, "")); statusObjects.put(NS_RECORD_NOACCESS, new StatusObject(NS_RECORD_NOACCESS, StatusObject.ERROR, "")); statusObjects.put(NS_RECORD_STOP, new StatusObject(NS_RECORD_STOP, StatusObject.STATUS, "")); statusObjects.put(NS_RECORD_FAILED, new StatusObject(NS_RECORD_FAILED, StatusObject.ERROR, "")); statusObjects.put(NS_PLAY_INSUFFICIENT_BW, new RuntimeStatusObject(NS_PLAY_INSUFFICIENT_BW, StatusObject.WARNING, "")); statusObjects.put(NS_PLAY_START, new RuntimeStatusObject(NS_PLAY_START, StatusObject.STATUS, "")); statusObjects.put(NS_PLAY_STREAMNOTFOUND, new RuntimeStatusObject(NS_PLAY_STREAMNOTFOUND, StatusObject.ERROR, "")); statusObjects.put(NS_PLAY_STOP, new RuntimeStatusObject(NS_PLAY_STOP, StatusObject.STATUS, "")); statusObjects.put(NS_PLAY_FAILED, new RuntimeStatusObject(NS_PLAY_FAILED, StatusObject.ERROR, "")); statusObjects.put(NS_PLAY_RESET, new RuntimeStatusObject(NS_PLAY_RESET, StatusObject.STATUS, "")); statusObjects.put(NS_PLAY_PUBLISHNOTIFY, new RuntimeStatusObject(NS_PLAY_PUBLISHNOTIFY, StatusObject.STATUS, "")); statusObjects.put(NS_PLAY_UNPUBLISHNOTIFY, new RuntimeStatusObject(NS_PLAY_UNPUBLISHNOTIFY, StatusObject.STATUS, "")); statusObjects.put(NS_DATA_START, new StatusObject(NS_DATA_START, StatusObject.STATUS, "")); statusObjects.put(APP_SCRIPT_ERROR, new StatusObject(APP_SCRIPT_ERROR, StatusObject.STATUS, "")); statusObjects.put(APP_SCRIPT_WARNING, new StatusObject(APP_SCRIPT_WARNING, StatusObject.STATUS, "")); statusObjects.put(APP_RESOURCE_LOWMEMORY, new StatusObject(APP_RESOURCE_LOWMEMORY, StatusObject.STATUS, "")); statusObjects.put(APP_SHUTDOWN, new StatusObject(APP_SHUTDOWN, StatusObject.STATUS, "")); statusObjects.put(APP_GC, new StatusObject(APP_GC, StatusObject.STATUS, "")); statusObjects.put(NS_PLAY_FILE_STRUCTURE_INVALID, new StatusObject(NS_PLAY_FILE_STRUCTURE_INVALID, StatusObject.ERROR, "")); statusObjects.put(NS_PLAY_NO_SUPPORTED_TRACK_FOUND, new StatusObject(NS_PLAY_NO_SUPPORTED_TRACK_FOUND, StatusObject.ERROR, "")); } /** * Cache status objects */ public void cacheStatusObjects() { cachedStatusObjects = new HashMap(); String statusCode; IoBuffer out = IoBuffer.allocate(256); out.setAutoExpand(true); for (String s : statusObjects.keySet()) { statusCode = s; StatusObject statusObject = statusObjects.get(statusCode); if (statusObject instanceof RuntimeStatusObject) { continue; } serializeStatusObject(out, statusObject); out.flip(); if (log.isTraceEnabled()) { log.trace(HexDump.formatHexDump(out.getHexDump())); } byte[] cachedBytes = new byte[out.limit()]; out.get(cachedBytes); out.clear(); cachedStatusObjects.put(statusCode, cachedBytes); } out.free(); out = null; } /** * Serializes status object * @param out Byte buffer for output object * @param statusObject Status object to serialize */ public void serializeStatusObject(IoBuffer out, StatusObject statusObject) { Map statusMap = new BeanMap(statusObject); Output output = new Output(out); serializer.serialize(output, statusMap); } /** * Return status object by code * @param statusCode Status object code * @return Status object with given code */ public StatusObject getStatusObject(String statusCode) { return statusObjects.get(statusCode); } /** * Return status object by code as byte array * @param statusCode Status object code * @return Status object with given code as byte array */ public byte[] getCachedStatusObjectAsByteArray(String statusCode) { return cachedStatusObjects.get(statusCode); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/status/RuntimeStatusObject.java0000644000175000017500000000607511706617130027764 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.status; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; /** * Runtime status object */ public class RuntimeStatusObject extends StatusObject { /** * Serializable */ private static final long serialVersionUID = 6990998992583246039L; /** * Status event details */ protected String details = ""; /** * Client id */ protected int clientid = 0; /** Constructs a new RuntimeStatusObject. */ public RuntimeStatusObject() { super(); } /** * Create runtime status object with given code, level and description * @param code Status code * @param level Level * @param description Status event description */ public RuntimeStatusObject(String code, String level, String description) { super(code, level, description); } /** * Create runtime status object with given code, level, description, details and client id * @param code Status code * @param level Level * @param description Status event description * @param details Status event details * @param clientid Client id */ public RuntimeStatusObject(String code, String level, String description, String details, int clientid) { super(code, level, description); this.details = details; this.clientid = clientid; } /** * Getter for client id * * @return Client id */ public int getClientid() { return clientid; } /** * Setter for client id * * @param clientid Client id */ public void setClientid(int clientid) { this.clientid = clientid; } /** * Getter for details * * @return Status event details */ public String getDetails() { return details; } /** * Setter for details * * @param details Status event details */ public void setDetails(String details) { this.details = details; } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); clientid = in.readInt(); details = (String) in.readObject(); } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeInt(clientid); out.writeObject(details); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/status/Status.java0000644000175000017500000001225611706617130025267 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.status; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import org.red5.annotations.Anonymous; import org.red5.io.object.ICustomSerializable; import org.red5.io.object.Output; import org.red5.io.object.Serializer; /** * Represents status object that are transferred between server and client */ @Anonymous public class Status implements StatusCodes, ICustomSerializable, Externalizable { private static final long serialVersionUID = -5501563718489586136L; /** * Error constant */ public static final String ERROR = "error"; /** * Status constant */ public static final String STATUS = "status"; /** * Warning constant */ public static final String WARNING = "warning"; /** * Status code */ protected String code; /** * Status level */ protected String level; /** * Status event description */ protected String description = ""; /** * Status event details */ protected String details = ""; /** * Id of client */ protected int clientid; /** Constructs a new Status. */ public Status() { } /** * Creates status object with given status code * @param code Status code */ public Status(String code) { this.code = code; this.level = STATUS; } /** * Creates status object with given level, description and status code * @param code Status code * @param level Level * @param description Description */ public Status(String code, String level, String description) { this.code = code; this.level = level; this.description = description; } /** * Getter for status code. * * @return Status code */ public String getCode() { return code; } /** * Setter for code * * @param code Status code */ public void setCode(String code) { this.code = code; } /** * Getter for description. * * @return Status event description. */ public String getDescription() { return description; } /** * Setter for desciption. * * @param description Status event description. */ public void setDesciption(String description) { this.description = description; } /** * Getter for level. * * @return Level */ public String getLevel() { return level; } /** * Setter for level * * @param level Level */ public void setLevel(String level) { this.level = level; } /** * Getter for client id * * @return Client id */ public int getClientid() { return clientid; } /** * Setter for client id * * @param clientid Client id */ public void setClientid(int clientid) { this.clientid = clientid; } /** * Getter for details * * @return Status event details */ public String getDetails() { return details; } /** * Setter for details. * * @param details Status event details */ public void setDetails(String details) { this.details = details; } /** * Setter for description. * * @param description Status event description */ public void setDescription(String description) { this.description = description; } /** {@inheritDoc} */ @Override public String toString() { return "Status: code: " + getCode() + " desc: " + getDescription() + " level: " + getLevel(); } public void serialize(Output output, Serializer serializer) { output.putString("level"); output.writeString(getLevel()); output.putString("code"); output.writeString(getCode()); output.putString("description"); output.writeString(getDescription()); output.putString("details"); if (getDetails() != null) { output.writeString(getDetails()); } else { output.writeNull(); } output.putString("clientid"); output.writeNumber(getClientid()); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { clientid = in.readInt(); code = (String) in.readObject(); description = (String) in.readObject(); details = (String) in.readObject(); level = (String) in.readObject(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(clientid); out.writeObject(code); out.writeObject(description); out.writeObject(details); out.writeObject(level); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/status/StatusCodes.java0000644000175000017500000002411111706617130026236 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.status; /** * Collection of commonly used constants with status codes. Descriptions provided as in FMS 2.0.1 * documentation available at adobe.com with some minor additions and comments. */ public interface StatusCodes { /** * The NetConnection.call method was not able to invoke the server-side method or * command. */ public static final String NC_CALL_FAILED = "NetConnection.Call.Failed"; /** * The URI specified in the NetConnection.connect method did not * specify 'rtmp' as the protocol. 'rtmp' must be specified when connecting to * FMS and Red5. Either not supported version of AMF was used (3 when only 0 is supported) */ public static final String NC_CALL_BADVERSION = "NetConnection.Call.BadVersion"; /** * The application has been shut down (for example, if the application is out of * memory resources and must shut down to prevent the server from crashing) or the server has shut down. */ public static final String NC_CONNECT_APPSHUTDOWN = "NetConnection.Connect.AppShutdown"; /** * The connection was closed successfully */ public static final String NC_CONNECT_CLOSED = "NetConnection.Connect.Closed"; /** * The connection attempt failed. */ public static final String NC_CONNECT_FAILED = "NetConnection.Connect.Failed"; /** * The client does not have permission to connect to the application, the * application expected different parameters from those that were passed, * or the application name specified during the connection attempt was not found on * the server. */ public static final String NC_CONNECT_REJECTED = "NetConnection.Connect.Rejected"; /** * The connection attempt succeeded. */ public static final String NC_CONNECT_SUCCESS = "NetConnection.Connect.Success"; /** * The application name specified during connect is invalid. */ public static final String NC_CONNECT_INVALID_APPLICATION = "NetConnection.Connect.InvalidApp"; /** * Invalid arguments were passed to a NetStream method. */ public static final String NS_INVALID_ARGUMENT = "NetStream.InvalidArg"; /** * A recorded stream was deleted successfully. */ public static final String NS_CLEAR_SUCCESS = "NetStream.Clear.Success"; /** * A recorded stream failed to delete. */ public static final String NS_CLEAR_FAILED = "NetStream.Clear.Failed"; /** * An attempt to publish was successful. */ public static final String NS_PUBLISH_START = "NetStream.Publish.Start"; /** * An attempt was made to publish a stream that is already being published by someone else. */ public static final String NS_PUBLISH_BADNAME = "NetStream.Publish.BadName"; /** * An attempt to use a Stream method (at client-side) failed */ public static final String NS_FAILED = "NetStream.Failed"; /** * An attempt to unpublish was successful */ public static final String NS_UNPUBLISHED_SUCCESS = "NetStream.Unpublish.Success"; /** * Recording was started */ public static final String NS_RECORD_START = "NetStream.Record.Start"; /** * An attempt was made to record a read-only stream */ public static final String NS_RECORD_NOACCESS = "NetStream.Record.NoAccess"; /** * Recording was stopped */ public static final String NS_RECORD_STOP = "NetStream.Record.Stop"; /** * An attempt to record a stream failed */ public static final String NS_RECORD_FAILED = "NetStream.Record.Failed"; /** * The buffer is empty (sent from server to client) */ public static final String NS_BUFFER_EMPTY = "NetStream.Buffer.Empty"; /** * Data is playing behind the normal speed */ public static final String NS_PLAY_INSUFFICIENT_BW = "NetStream.Play.InsufficientBW"; /** * Play was started */ public static final String NS_PLAY_START = "NetStream.Play.Start"; /** * An attempt was made to play a stream that does not exist */ public static final String NS_PLAY_STREAMNOTFOUND = "NetStream.Play.StreamNotFound"; /** * Play was stopped */ public static final String NS_PLAY_STOP = "NetStream.Play.Stop"; /** * An attempt to play back a stream failed */ public static final String NS_PLAY_FAILED = "NetStream.Play.Failed"; /** * A playlist was reset */ public static final String NS_PLAY_RESET = "NetStream.Play.Reset"; /** * The initial publish to a stream was successful. This message is sent to all subscribers */ public static final String NS_PLAY_PUBLISHNOTIFY = "NetStream.Play.PublishNotify"; /** * An unpublish from a stream was successful. This message is sent to all subscribers */ public static final String NS_PLAY_UNPUBLISHNOTIFY = "NetStream.Play.UnpublishNotify"; /** * Playlist playback switched from one stream to another. */ public static final String NS_PLAY_SWITCH = "NetStream.Play.Switch"; /** * Transition to another stream has been initiated. */ public static final String NS_PLAY_TRANSITION = "NetStream.Play.Transition"; /** * Transition to another stream is processing normally. This is set as the "reason" property of the NetStatusEvent. */ public static final String NS_TRANSITION_SUCCESS = "NetStream.Transition.Success"; /** * Transition to another stream has been forced. * * If streams that are being switched do not have aligned content/timelines, or if the keyframes are not aligned between * the two streams, it is possible that the server will have to force a hard transition. This can also happen with * broadcast (live) dynamic streaming if the server cannot find a synchronization point within the two streams. * This is set as the "reason" property of the NetStatusEvent. */ public static final String NS_TRANSITION_FORCED = "NetStream.Transition.Forced"; /** * Transition to another stream is complete. */ public static final String NS_PLAY_TRANSITION_COMPLETE = "NetStream.Play.TransitionComplete"; /** * Playlist playback is complete. */ public static final String NS_PLAY_COMPLETE = "NetStream.Play.Complete"; /** * The subscriber has used the seek command to move to a particular location in the recorded stream. */ public static final String NS_SEEK_NOTIFY = "NetStream.Seek.Notify"; /** * The stream doesn't support seeking. */ public static final String NS_SEEK_FAILED = "NetStream.Seek.Failed"; /** * The subscriber has used the seek command to move to a particular location in the recorded stream. */ public static final String NS_PAUSE_NOTIFY = "NetStream.Pause.Notify"; /** * Publishing has stopped */ public static final String NS_UNPAUSE_NOTIFY = "NetStream.Unpause.Notify"; /** * */ public static final String NS_DATA_START = "NetStream.Data.Start"; /** * The ActionScript engine has encountered a runtime error. In addition to the standard infoObject * properties, the following properties are set: * * filename: name of the offending ASC file. * lineno: line number where the error occurred. * linebuf: source code of the offending line. */ public static final String APP_SCRIPT_ERROR = "Application.Script.Error"; /** * The ActionScript engine has encountered a runtime warning. In addition to the standard infoObject * properties, the following properties are set: * * filename: name of the offending ASC file. * lineno: line number where the error occurred. * linebuf: source code of the offending line */ public static final String APP_SCRIPT_WARNING = "Application.Script.Warning"; /** * The ActionScript engine is low on runtime memory. This provides an opportunity for the * application instance to free some resources or take suitable action. If the application instance * runs out of memory, it is unloaded and all users are disconnected. In this state, the server will * not invoke the Application.onDisconnect event handler or the Application.onAppStop event handler */ public static final String APP_RESOURCE_LOWMEMORY = "Application.Resource.LowMemory"; /** * This information object is passed to the onAppStop handler when the application is being shut down */ public static final String APP_SHUTDOWN = "Application.Shutdown"; /** * This information object is passed to the onAppStop event handler when the application instance * is about to be destroyed by the server. */ public static final String APP_GC = "Application.GC"; /** * Read access to a shared object was denied. */ public static final String SO_NO_READ_ACCESS = "SharedObject.NoReadAccess"; /** * Write access to a shared object was denied. */ public static final String SO_NO_WRITE_ACCESS = "SharedObject.NoWriteAccess"; /** * The creation of a shared object was denied. */ public static final String SO_CREATION_FAILED = "SharedObject.ObjectCreationFailed"; /** * The persistence parameter passed to SharedObject.getRemote() is different from the one used * when the shared object was created. */ public static final String SO_PERSISTENCE_MISMATCH = "SharedObject.BadPersistence"; /** * This event is sent if the player detects an MP4 with an invalid file structure. * Flash Player cannot play files that have invalid file structures. * * New for FMS3 */ public static final String NS_PLAY_FILE_STRUCTURE_INVALID = "NetStream.Play.FileStructureInvalid"; /** * This event is sent if the player does not detect any supported tracks. If there aren't any supported * video, audio or data tracks found, Flash Player does not play the file. * * New for FMS3 */ public static final String NS_PLAY_NO_SUPPORTED_TRACK_FOUND = "NetStream.Play.NoSupportedTrackFound"; } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/status/StatusObject.java0000644000175000017500000001246311706617130026416 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.status; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.Serializable; import java.util.HashMap; import java.util.Map; import org.red5.annotations.Anonymous; import org.red5.io.object.ICustomSerializable; import org.red5.io.object.Output; import org.red5.io.object.Serializer; /** * Status object that is sent to client with every status event * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ @Anonymous public class StatusObject implements Serializable, ICustomSerializable, Externalizable { private static final long serialVersionUID = 8817297676191096283L; public static final String ERROR = "error"; public static final String STATUS = "status"; public static final String WARNING = "warning"; protected String code; protected String level; protected String description = ""; protected Object application; protected Map additional; /** Constructs a new StatusObject. */ public StatusObject() { } public StatusObject(String code, String level, String description) { this.code = code; this.level = level; this.description = description; } /** * Getter for property 'code'. * * @return Value for property 'code'. */ public String getCode() { return code; } /** * Setter for property 'code'. * * @param code Value to set for property 'code'. */ public void setCode(String code) { this.code = code; } /** * Getter for property 'description'. * * @return Value for property 'description'. */ public String getDescription() { return description; } /** * Setter for property 'description'. * * @param description Value to set for property 'description'. */ public void setDescription(String description) { this.description = description; } /** * Getter for property 'level'. * * @return Value for property 'level'. */ public String getLevel() { return level; } /** * Setter for property 'level'. * * @param level Value to set for property 'level'. */ public void setLevel(String level) { this.level = level; } /** * Setter for property 'application'. * * @param application Value to set for property 'application'. */ public void setApplication(Object application) { this.application = application; } /** * Getter for property 'application'. * * @return Value for property 'application'. */ public Object getApplication() { return application; } /** {@inheritDoc} */ @Override public String toString() { return String.format("Status code: %s level: %s description: %s", code, level, description); } /** * Generate Status object that can be returned through a RTMP channel. * * @return status */ public Status asStatus() { return new Status(getCode(), getLevel(), getDescription()); } public void setAdditional(String name, Object value) { if ("code,level,description,application".indexOf(name) != -1) { throw new RuntimeException("the name \"" + name + "\" is reserved"); } if (additional == null) { additional = new HashMap(); } additional.put(name, value); } public void serialize(Output output, Serializer serializer) { output.putString("level"); output.writeString(getLevel()); output.putString("code"); output.writeString(getCode()); output.putString("description"); output.writeString(getDescription()); if (application != null) { output.putString("application"); serializer.serialize(output, application); } if (additional != null) { // Add additional parameters for (Map.Entry entry: additional.entrySet()) { output.putString(entry.getKey()); serializer.serialize(output, entry.getValue()); } } } @SuppressWarnings("unchecked") public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { code = (String) in.readObject(); description = (String) in.readObject(); level = (String) in.readObject(); additional = (Map) in.readObject(); application = in.readObject(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(code); out.writeObject(description); out.writeObject(level); if (application != null) { out.writeObject(additional); } if (additional != null) { out.writeObject(application); } } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/RTMPConnection.java0000644000175000017500000007636611754734766025321 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import java.beans.ConstructorProperties; import java.util.BitSet; import java.util.Collection; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.BaseConnection; import org.red5.server.api.Red5; import org.red5.server.api.scheduling.IScheduledJob; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.api.scope.IScope; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.api.service.IPendingServiceCallback; import org.red5.server.api.service.IServiceCall; import org.red5.server.api.service.IServiceCapableConnection; import org.red5.server.api.stream.IClientBroadcastStream; import org.red5.server.api.stream.IClientStream; import org.red5.server.api.stream.IPlaylistSubscriberStream; import org.red5.server.api.stream.ISingleItemSubscriberStream; import org.red5.server.api.stream.IStreamCapableConnection; import org.red5.server.api.stream.IStreamService; import org.red5.server.exception.ClientRejectedException; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.rtmp.event.BytesRead; import org.red5.server.net.rtmp.event.ClientBW; import org.red5.server.net.rtmp.event.Invoke; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.Ping; import org.red5.server.net.rtmp.event.ServerBW; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.net.rtmp.message.Packet; import org.red5.server.service.Call; import org.red5.server.service.PendingCall; import org.red5.server.stream.ClientBroadcastStream; import org.red5.server.stream.OutputStream; import org.red5.server.stream.PlaylistSubscriberStream; import org.red5.server.stream.SingleItemSubscriberStream; import org.red5.server.stream.StreamService; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * RTMP connection. Stores information about client streams, data transfer * channels, pending RPC calls, bandwidth configuration, used encoding * (AMF0/AMF3), connection state (is alive, last ping time and ping result) and * session. */ public abstract class RTMPConnection extends BaseConnection implements IStreamCapableConnection, IServiceCapableConnection { private static Logger log = LoggerFactory.getLogger(RTMPConnection.class); public static final String RTMP_CONNECTION_KEY = "rtmp.conn"; public static final String RTMP_HANDSHAKE = "rtmp.handshake"; /** * Marker byte for standard or non-encrypted RTMP data. */ public static final byte RTMP_NON_ENCRYPTED = (byte) 0x03; /** * Marker byte for encrypted RTMP data. */ public static final byte RTMP_ENCRYPTED = (byte) 0x06; /** * Cipher for RTMPE input */ public static final String RTMPE_CIPHER_IN = "rtmpe.cipher.in"; /** * Cipher for RTMPE output */ public static final String RTMPE_CIPHER_OUT = "rtmpe.cipher.out"; /** * Connection channels * * @see org.red5.server.net.rtmp.Channel */ private ConcurrentMap channels = new ConcurrentHashMap(); /** * Client streams * * @see org.red5.server.api.stream.IClientStream */ private ConcurrentMap streams = new ConcurrentHashMap(); /** * Reserved stream ids */ private volatile BitSet reservedStreams = new BitSet(); /** * Identifier for remote calls. */ private AtomicInteger invokeId = new AtomicInteger(1); /** * Hash map that stores pending calls and ids as pairs. */ private ConcurrentMap pendingCalls = new ConcurrentHashMap(); /** * Deferred results set. * * @see org.red5.server.net.rtmp.DeferredResult */ private CopyOnWriteArraySet deferredResults = new CopyOnWriteArraySet(); /** * Last ping round trip time */ private AtomicInteger lastPingTime = new AtomicInteger(-1); /** * Timestamp when last ping command was sent. */ private AtomicLong lastPingSent = new AtomicLong(0); /** * Timestamp when last ping result was received. */ private AtomicLong lastPongReceived = new AtomicLong(0); /** * Name of quartz job that keeps connection alive. */ private String keepAliveJobName; /** * Ping interval in ms to detect dead clients. */ private volatile int pingInterval = 5000; /** * Maximum time in ms after which a client is disconnected because of inactivity. */ private volatile int maxInactivity = 60000; /** * Data read interval */ protected int bytesReadInterval = 120 * 1024; /** * Number of bytes to read next. */ protected int nextBytesRead = 120 * 1024; /** * Number of bytes the client reported to have received. */ private AtomicLong clientBytesRead = new AtomicLong(0L); /** * Map for pending video packets and stream IDs. */ private ConcurrentMap pendingVideos = new ConcurrentHashMap(); /** * Number of streams used. */ private AtomicInteger usedStreams = new AtomicInteger(0); /** * AMF version, AMF0 by default. */ private volatile Encoding encoding = Encoding.AMF0; /** * Remembered stream buffer durations. */ private ConcurrentMap streamBuffers = new ConcurrentHashMap(); /** * Name of job that is waiting for a valid handshake. */ private String waitForHandshakeJob; /** * Maximum time in milliseconds to wait for a valid handshake. */ private volatile int maxHandshakeTimeout = 5000; /** * Bandwidth limit type / enforcement. (0=hard,1=soft,2=dynamic) */ protected int limitType = 0; protected volatile int clientId; /** * protocol state */ protected volatile RTMP state; private ISchedulingService schedulingService; /** * Creates anonymous RTMP connection without scope. * * @param type Connection type */ @ConstructorProperties({ "type" }) public RTMPConnection(String type) { // We start with an anonymous connection without a scope. // These parameters will be set during the call of "connect" later. super(type); } public int getId() { return clientId; } public void setId(int clientId) { this.clientId = clientId; } public RTMP getState() { return state; } public byte getStateCode() { return state.getState(); } public void setStateCode(byte code) { state.setState(code); } public void setState(RTMP state) { log.debug("Set state: {}", state); this.state = state; } /** {@inheritDoc} */ public void setBandwidth(int mbits) { // tell the flash player how fast we want data and how fast we shall send it getChannel(2).write(new ServerBW(mbits)); // second param is the limit type (0=hard,1=soft,2=dynamic) getChannel(2).write(new ClientBW(mbits, (byte) limitType)); } @Override public boolean connect(IScope newScope, Object[] params) { log.debug("Connect scope: {}", newScope); try { boolean success = super.connect(newScope, params); if (success) { unscheduleWaitForHandshakeJob(); } return success; } catch (ClientRejectedException e) { String reason = (String) e.getReason(); log.info("Client rejected, unscheduling waitForHandshakeJob. Reason: " + ((reason != null) ? reason : "None")); unscheduleWaitForHandshakeJob(); throw e; } } private void unscheduleWaitForHandshakeJob() { if (waitForHandshakeJob != null) { schedulingService.removeScheduledJob(waitForHandshakeJob); waitForHandshakeJob = null; log.debug("Removed waitForHandshakeJob for: {}", getId()); } } /** * Initialize connection. * * @param host Connection host * @param path Connection path * @param sessionId Connection session id * @param params Params passed from client */ public void setup(String host, String path, String sessionId, Map params) { this.host = host; this.path = path; this.sessionId = sessionId; this.params = params; if (Integer.valueOf(3).equals(params.get("objectEncoding"))) { log.info("Setting object encoding to AMF3"); encoding = Encoding.AMF3; } } /** * Return AMF protocol encoding used by this connection. * * @return AMF encoding used by connection */ public Encoding getEncoding() { return encoding; } /** * Getter for next available channel id. * * @return Next available channel id */ public int getNextAvailableChannelId() { int result = 4; while (isChannelUsed(result)) { result++; } return result; } /** * Checks whether channel is used. * * @param channelId Channel id * @return true if channel is in use, false * otherwise */ public boolean isChannelUsed(int channelId) { return channels.get(channelId) != null; } /** * Return channel by id. * * @param channelId Channel id * @return Channel by id */ public Channel getChannel(int channelId) { if (channels != null) { Channel channel = channels.putIfAbsent(channelId, new Channel(this, channelId)); if (channel == null) { channel = channels.get(channelId); } return channel; } else { return new Channel(null, channelId); } } /** * Closes channel. * * @param channelId Channel id */ public void closeChannel(int channelId) { channels.remove(channelId); } /** * Getter for client streams. * * @return Client streams as array */ protected Collection getStreams() { return streams.values(); } /** {@inheritDoc} */ public int reserveStreamId() { int result = -1; for (int i = 0; true; i++) { if (!reservedStreams.get(i)) { reservedStreams.set(i); result = i; break; } } return result + 1; } /** {@inheritDoc} */ public int reserveStreamId(int id) { int result = -1; if (!reservedStreams.get(id - 1)) { reservedStreams.set(id - 1); result = id - 1; } else { result = reserveStreamId(); } return result; } /** * Returns whether or not a given stream id is valid. * * @param streamId * @return true if its valid, false if its invalid */ public boolean isValidStreamId(int streamId) { int index = streamId - 1; if (index < 0 || !reservedStreams.get(index)) { // stream id has not been reserved before return false; } if (streams.get(streamId - 1) != null) { // another stream already exists with this id return false; } return true; } /** * Creates output stream object from stream id. Output stream consists of * audio, data and video channels. * * @see org.red5.server.stream.OutputStream * * @param streamId Stream id * @return Output stream object */ public OutputStream createOutputStream(int streamId) { int channelId = (4 + ((streamId - 1) * 5)); log.debug("Channel id range start: {}", channelId); final Channel data = getChannel(channelId++); final Channel video = getChannel(channelId++); final Channel audio = getChannel(channelId++); // final Channel unknown = getChannel(channelId++); // final Channel ctrl = getChannel(channelId++); return new OutputStream(video, audio, data); } /** {@inheritDoc} */ public IClientBroadcastStream newBroadcastStream(int streamId) { if (isValidStreamId(streamId)) { // get ClientBroadcastStream defined as a prototype in red5-common.xml ClientBroadcastStream cbs = (ClientBroadcastStream) scope.getContext().getBean("clientBroadcastStream"); Integer buffer = streamBuffers.get(streamId - 1); if (buffer != null) { cbs.setClientBufferDuration(buffer); } cbs.setStreamId(streamId); cbs.setConnection(this); cbs.setName(createStreamName()); cbs.setScope(this.getScope()); registerStream(cbs); usedStreams.incrementAndGet(); return cbs; } return null; } /** {@inheritDoc} */ public ISingleItemSubscriberStream newSingleItemSubscriberStream(int streamId) { if (isValidStreamId(streamId)) { // get SingleItemSubscriberStream defined as a prototype in red5-common.xml SingleItemSubscriberStream siss = (SingleItemSubscriberStream) scope.getContext().getBean("singleItemSubscriberStream"); Integer buffer = streamBuffers.get(streamId - 1); if (buffer != null) { siss.setClientBufferDuration(buffer); } siss.setName(createStreamName()); siss.setConnection(this); siss.setScope(this.getScope()); siss.setStreamId(streamId); registerStream(siss); usedStreams.incrementAndGet(); return siss; } return null; } /** {@inheritDoc} */ public IPlaylistSubscriberStream newPlaylistSubscriberStream(int streamId) { if (isValidStreamId(streamId)) { // get PlaylistSubscriberStream defined as a prototype in red5-common.xml PlaylistSubscriberStream pss = (PlaylistSubscriberStream) scope.getContext().getBean("playlistSubscriberStream"); Integer buffer = streamBuffers.get(streamId - 1); if (buffer != null) { pss.setClientBufferDuration(buffer); } pss.setName(createStreamName()); pss.setConnection(this); pss.setScope(this.getScope()); pss.setStreamId(streamId); registerStream(pss); usedStreams.incrementAndGet(); return pss; } return null; } public void addClientStream(IClientStream stream) { int streamId = stream.getStreamId(); if (reservedStreams.get(streamId - 1)) { return; } reservedStreams.set(streamId - 1); streams.put(streamId - 1, stream); usedStreams.incrementAndGet(); } public void removeClientStream(int streamId) { unreserveStreamId(streamId); } /** * Getter for used stream count. * * @return Value for property 'usedStreamCount'. */ protected int getUsedStreamCount() { return usedStreams.get(); } /** {@inheritDoc} */ public IClientStream getStreamById(int id) { if (id <= 0) { return null; } return streams.get(id - 1); } /** * Return stream id for given channel id. * * @param channelId Channel id * @return ID of stream that channel belongs to */ public int getStreamIdForChannel(int channelId) { if (channelId < 4) { return 0; } return ((channelId - 4) / 5) + 1; } /** * Return stream by given channel id. * * @param channelId Channel id * @return Stream that channel belongs to */ public IClientStream getStreamByChannelId(int channelId) { if (channelId < 4) { return null; } return streams.get(getStreamIdForChannel(channelId) - 1); } /** * Store a stream in the connection. * * @param stream */ private void registerStream(IClientStream stream) { streams.put(stream.getStreamId() - 1, stream); } /** * Remove a stream from the connection. * * @param stream */ @SuppressWarnings("unused") private void unregisterStream(IClientStream stream) { streams.remove(stream.getStreamId()); } /** {@inheritDoc} */ @Override public void close() { if (keepAliveJobName != null) { schedulingService.removeScheduledJob(keepAliveJobName); keepAliveJobName = null; } Red5.setConnectionLocal(this); IStreamService streamService = (IStreamService) ScopeUtils.getScopeService(scope, IStreamService.class, StreamService.class); if (streamService != null) { for (Map.Entry entry : streams.entrySet()) { IClientStream stream = entry.getValue(); if (stream != null) { log.debug("Closing stream: {}", stream.getStreamId()); streamService.deleteStream(this, stream.getStreamId()); usedStreams.decrementAndGet(); } } } // close the base connection - disconnect scopes and unregister client super.close(); // kill all the collections etc if (channels != null) { channels.clear(); } else { log.trace("Channels collection was null"); } if (streams != null) { streams.clear(); } else { log.trace("Streams collection was null"); } if (pendingCalls != null) { pendingCalls.clear(); } else { log.trace("PendingCalls collection was null"); } if (deferredResults != null) { deferredResults.clear(); } else { log.trace("DeferredResults collection was null"); } if (pendingVideos != null) { pendingVideos.clear(); } else { log.trace("PendingVideos collection was null"); } if (streamBuffers != null) { streamBuffers.clear(); } else { log.trace("StreamBuffers collection was null"); } // clear thread local reference Red5.setConnectionLocal(null); } /** * When the connection has been closed, notify any remaining pending service calls that they have failed because * the connection is broken. Implementors of IPendingServiceCallback may only deduce from this notification that * it was not possible to read a result for this service call. It is possible that (1) the service call was never * written to the service, or (2) the service call was written to the service and although the remote method was * invoked, the connection failed before the result could be read, or (3) although the remote method was invoked * on the service, the service implementor detected the failure of the connection and performed only partial * processing. The caller only knows that it cannot be confirmed that the callee has invoked the service call * and returned a result. */ public void sendPendingServiceCallsCloseError() { if (pendingCalls != null && !pendingCalls.isEmpty()) { for (IPendingServiceCall call : pendingCalls.values()) { call.setStatus(Call.STATUS_NOT_CONNECTED); for (IPendingServiceCallback callback : call.getCallbacks()) { callback.resultReceived(call); } } } } /** {@inheritDoc} */ public void unreserveStreamId(int streamId) { deleteStreamById(streamId); if (streamId > 0) { reservedStreams.clear(streamId - 1); } } /** {@inheritDoc} */ public void deleteStreamById(int streamId) { if (streamId > 0) { if (streams.get(streamId - 1) != null) { pendingVideos.remove(streamId); usedStreams.decrementAndGet(); streams.remove(streamId - 1); streamBuffers.remove(streamId - 1); } } } /** * Handler for ping event. * * @param ping Ping event context */ public void ping(Ping ping) { getChannel(2).write(ping); } /** * Write packet. * * @param out Packet */ public abstract void write(Packet out); /** * Write raw byte buffer. * * @param out IoBuffer */ public abstract void writeRaw(IoBuffer out); /** * Update number of bytes to read next value. */ protected void updateBytesRead() { long bytesRead = getReadBytes(); if (bytesRead >= nextBytesRead) { BytesRead sbr = new BytesRead((int) bytesRead); getChannel(2).write(sbr); nextBytesRead += bytesReadInterval; } } /** * Read number of received bytes. * * @param bytes Number of bytes */ public void receivedBytesRead(int bytes) { log.debug("Client received {} bytes, written {} bytes, {} messages pending", new Object[] { bytes, getWrittenBytes(), getPendingMessages() }); clientBytesRead.addAndGet(bytes); } /** * Get number of bytes the client reported to have received. * * @return Number of bytes */ public long getClientBytesRead() { return clientBytesRead.get(); } /** {@inheritDoc} */ public void invoke(IServiceCall call) { invoke(call, 3); } /** * Generate next invoke id. * * @return Next invoke id for RPC */ public int getInvokeId() { return invokeId.incrementAndGet(); } /** * Register pending call (remote function call that is yet to finish). * * @param invokeId Deferred operation id * @param call Call service */ public void registerPendingCall(int invokeId, IPendingServiceCall call) { pendingCalls.put(invokeId, call); } /** {@inheritDoc} */ public void invoke(IServiceCall call, int channel) { // We need to use Invoke for all calls to the client Invoke invoke = new Invoke(); invoke.setCall(call); invoke.setInvokeId(getInvokeId()); if (call instanceof IPendingServiceCall) { registerPendingCall(invoke.getInvokeId(), (IPendingServiceCall) call); } getChannel(channel).write(invoke); } /** {@inheritDoc} */ public void invoke(String method) { invoke(method, null, null); } /** {@inheritDoc} */ public void invoke(String method, Object[] params) { invoke(method, params, null); } /** {@inheritDoc} */ public void invoke(String method, IPendingServiceCallback callback) { invoke(method, null, callback); } /** {@inheritDoc} */ public void invoke(String method, Object[] params, IPendingServiceCallback callback) { IPendingServiceCall call = new PendingCall(method, params); if (callback != null) { call.registerCallback(callback); } invoke(call); } /** {@inheritDoc} */ public void notify(IServiceCall call) { notify(call, 3); } /** {@inheritDoc} */ public void notify(IServiceCall call, int channel) { Notify notify = new Notify(); notify.setCall(call); getChannel(channel).write(notify); } /** {@inheritDoc} */ public void notify(String method) { notify(method, null); } /** {@inheritDoc} */ public void notify(String method, Object[] params) { IServiceCall call = new Call(method, params); notify(call); } /** {@inheritDoc} */ @Override public long getReadBytes() { return 0; } /** {@inheritDoc} */ @Override public long getWrittenBytes() { return 0; } /** * Get pending call service by id. * * @param invokeId * Pending call service id * @return Pending call service object */ public IPendingServiceCall getPendingCall(int invokeId) { return pendingCalls.get(invokeId); } /** * Retrieves and removes the pending call service by id. * * @param invokeId * Pending call service id * @return Pending call service object */ public IPendingServiceCall retrievePendingCall(int invokeId) { return pendingCalls.remove(invokeId); } /** * Generates new stream name. * * @return New stream name */ protected String createStreamName() { return UUID.randomUUID().toString(); } /** * Mark message as being written. * * @param message * Message to mark */ protected void writingMessage(Packet message) { if (message.getMessage() instanceof VideoData) { int streamId = message.getHeader().getStreamId(); final AtomicInteger value = new AtomicInteger(); AtomicInteger old = pendingVideos.putIfAbsent(streamId, value); if (old == null) { old = value; } old.incrementAndGet(); } } /** * Increases number of read messages by one. Updates number of bytes read. */ public void messageReceived() { readMessages.incrementAndGet(); // trigger generation of BytesRead messages updateBytesRead(); } /** * Mark message as sent. * * @param message * Message to mark */ public void messageSent(Packet message) { if (message.getMessage() instanceof VideoData) { int streamId = message.getHeader().getStreamId(); AtomicInteger pending = pendingVideos.get(streamId); if (pending != null) { pending.decrementAndGet(); } } writtenMessages.incrementAndGet(); } /** * Increases number of dropped messages. */ protected void messageDropped() { droppedMessages.incrementAndGet(); } /** {@inheritDoc} */ @Override public long getPendingVideoMessages(int streamId) { AtomicInteger count = pendingVideos.get(streamId); long result = (count != null ? count.intValue() - getUsedStreamCount() : 0); return (result > 0 ? result : 0); } /** {@inheritDoc} */ public void ping() { long newPingTime = System.currentTimeMillis(); log.debug("Pinging client with id {} at {}, last ping sent at {}", new Object[] { getId(), newPingTime, lastPingSent.get() }); if (lastPingSent.get() == 0) { lastPongReceived.set(newPingTime); } Ping pingRequest = new Ping(); pingRequest.setEventType(Ping.PING_CLIENT); lastPingSent.set(newPingTime); int now = (int) (newPingTime & 0xffffffff); pingRequest.setValue2(now); ping(pingRequest); } /** * Marks that ping back was received. * * @param pong * Ping object */ public void pingReceived(Ping pong) { long now = System.currentTimeMillis(); long previousReceived = (int) (lastPingSent.get() & 0xffffffff); log.debug("Pong from client id {} at {} with value {}, previous received at {}", new Object[] { getId(), now, pong.getValue2(), previousReceived }); if (pong.getValue2() == previousReceived) { lastPingTime.set((int) (now & 0xffffffff) - pong.getValue2()); } lastPongReceived.set(now); } /** {@inheritDoc} */ public int getLastPingTime() { return lastPingTime.get(); } /** * Setter for ping interval. * * @param pingInterval Interval in ms to ping clients. Set to 0 to * disable ghost detection code. */ public void setPingInterval(int pingInterval) { this.pingInterval = pingInterval; } /** * Setter for maximum inactivity. * * @param maxInactivity Maximum time in ms after which a client is disconnected in * case of inactivity. */ public void setMaxInactivity(int maxInactivity) { this.maxInactivity = maxInactivity; } /** * Starts measurement. */ public void startRoundTripMeasurement() { if (pingInterval > 0 && keepAliveJobName == null) { keepAliveJobName = schedulingService.addScheduledJob(pingInterval, new KeepAliveJob()); log.debug("Keep alive job name {} for client id {}", keepAliveJobName, getId()); } } /** * Sets the scheduling service. * * @param schedulingService scheduling service */ public void setSchedulingService(ISchedulingService schedulingService) { this.schedulingService = schedulingService; } /** * Inactive state event handler. */ protected abstract void onInactive(); /** {@inheritDoc} */ @Override public String toString() { Object[] args = new Object[] { getClass().getSimpleName(), getRemoteAddress(), getRemotePort(), getHost(), getReadBytes(), getWrittenBytes() }; return String.format("%1$s from %2$s : %3$s to %4$s (in: %5$s out %6$s )", args); } /** * Registers deferred result. * * @param result Result to register */ public void registerDeferredResult(DeferredResult result) { deferredResults.add(result); } /** * Unregister deferred result * * @param result * Result to unregister */ public void unregisterDeferredResult(DeferredResult result) { deferredResults.remove(result); } public void rememberStreamBufferDuration(int streamId, int bufferDuration) { streamBuffers.put(streamId - 1, bufferDuration); } /** * Set maximum time to wait for valid handshake in milliseconds. * * @param maxHandshakeTimeout Maximum time in milliseconds */ public void setMaxHandshakeTimeout(int maxHandshakeTimeout) { this.maxHandshakeTimeout = maxHandshakeTimeout; } /** * Start waiting for a valid handshake. * * @param service * The scheduling service to use */ protected void startWaitForHandshake(ISchedulingService service) { waitForHandshakeJob = service.addScheduledOnceJob(maxHandshakeTimeout, new WaitForHandshakeJob()); } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + clientId; if (host != null) { result = result + host.hashCode(); } if (remoteAddress != null) { result = result + remoteAddress.hashCode(); } return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } RTMPConnection other = (RTMPConnection) obj; if (clientId != other.clientId) { return false; } if (host != null && !host.equals(other.getHost())) { return false; } if (remoteAddress != null && !remoteAddress.equals(other.getRemoteAddress())) { return false; } return true; } /** * Quartz job that keeps connection alive and disconnects if client is dead. */ private class KeepAliveJob implements IScheduledJob { private final AtomicBoolean running = new AtomicBoolean(false); private final AtomicLong lastBytesRead = new AtomicLong(0); private volatile long lastBytesReadTime = 0; /** {@inheritDoc} */ public void execute(ISchedulingService service) { // ensure the job is not already running if (running.compareAndSet(false, true)) { // get now long now = System.currentTimeMillis(); // get the current bytes read count on the connection long currentReadBytes = getReadBytes(); // get our last bytes read count long previousReadBytes = lastBytesRead.get(); log.debug("Time now: {} current read count: {} last read count: {}", new Object[] { now, currentReadBytes, previousReadBytes }); if (currentReadBytes > previousReadBytes) { log.debug("Client is still alive, no ping needed"); // client has sent data since last check and thus is not dead. No need to ping if (lastBytesRead.compareAndSet(previousReadBytes, currentReadBytes)) { // update the timestamp to match our update lastBytesReadTime = now; } } else { // client didn't send response to ping command and didn't sent data for too long, disconnect long lastPingTime = lastPingSent.get(); long lastPongTime = lastPongReceived.get(); if (lastPongTime > 0 && (lastPingTime - lastPongTime > maxInactivity) && !(now - lastBytesReadTime < maxInactivity)) { log.debug("Keep alive job name {}", keepAliveJobName); if (log.isTraceEnabled()) { log.trace("Scheduled job list"); for (String jobName : service.getScheduledJobNames()) { log.trace("Job: {}", jobName); } } service.removeScheduledJob(keepAliveJobName); keepAliveJobName = null; log.warn("Closing {}, with id {}, due to too much inactivity ({} ms), last ping sent {} ms ago", new Object[] { RTMPConnection.this, getId(), (lastPingTime - lastPongTime), (now - lastPingTime) }); // Add the following line to (hopefully) deal with a very common support request // on the Red5 list log.warn("This often happens if YOUR Red5 application generated an exception on start-up. Check earlier in the log for that exception first!"); onInactive(); } // send ping command to client to trigger sending of data ping(); } // reset running flag running.compareAndSet(true, false); } } } /** * Quartz job that waits for a valid handshake and disconnects the client if * none is received. */ private class WaitForHandshakeJob implements IScheduledJob { /** {@inheritDoc} */ public void execute(ISchedulingService service) { waitForHandshakeJob = null; // Client didn't send a valid handshake, disconnect log.warn("Closing {}, with id {} due to long handshake", RTMPConnection.this, getId()); onInactive(); } } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/RTMPMinaConnection.java0000644000175000017500000002267611754734766026121 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import java.beans.ConstructorProperties; import java.lang.management.ManagementFactory; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.ArrayList; import java.util.Collections; import java.util.concurrent.Semaphore; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.StandardMBean; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.filterchain.IoFilterChain; import org.apache.mina.core.future.CloseFuture; import org.apache.mina.core.future.IoFutureListener; import org.apache.mina.core.session.IoSession; import org.red5.server.api.scope.IScope; import org.red5.server.jmx.mxbeans.RTMPMinaConnectionMXBean; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.rtmp.event.ClientBW; import org.red5.server.net.rtmp.event.ServerBW; import org.red5.server.net.rtmp.message.Packet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jmx.export.annotation.ManagedResource; /** * Represents an RTMP connection using Mina. * * @see "http://mina.apache.org/report/trunk/apidocs/org/apache/mina/core/session/IoSession.html" * * @author Paul Gregoire */ @ManagedResource public class RTMPMinaConnection extends RTMPConnection implements RTMPMinaConnectionMXBean { protected static Logger log = LoggerFactory.getLogger(RTMPMinaConnection.class); /** * MINA I/O session, connection between two end points */ private volatile IoSession ioSession; /** * MBean object name used for de/registration purposes. */ private volatile ObjectName oName; protected int defaultServerBandwidth = 10000000; protected int defaultClientBandwidth = 10000000; protected boolean bandwidthDetection = true; /** Constructs a new RTMPMinaConnection. */ @ConstructorProperties(value = { "persistent" }) public RTMPMinaConnection() { super(PERSISTENT); } @SuppressWarnings("cast") @Override public boolean connect(IScope newScope, Object[] params) { log.debug("Connect scope: {}", newScope); boolean success = super.connect(newScope, params); if (success) { // tell the flash player how fast we want data and how fast we shall send it getChannel(2).write(new ServerBW(defaultServerBandwidth)); // second param is the limit type (0=hard,1=soft,2=dynamic) getChannel(2).write(new ClientBW(defaultClientBandwidth, (byte) limitType)); //if the client is null for some reason, skip the jmx registration if (client != null) { // perform bandwidth detection if (bandwidthDetection && !client.isBandwidthChecked()) { client.checkBandwidth(); } } else { log.warn("Client was null"); } registerJMX(); } return success; } /** {@inheritDoc} */ @Override public void close() { super.close(); if (ioSession != null) { // accept no further incoming data ioSession.suspendRead(); // clear the filter chain IoFilterChain filters = ioSession.getFilterChain(); //check if it exists and remove if (filters.contains("bandwidthFilter")) { ioSession.getFilterChain().remove("bandwidthFilter"); } // update our state if (ioSession.containsAttribute(ProtocolState.SESSION_KEY)) { RTMP rtmp = (RTMP) ioSession.getAttribute(ProtocolState.SESSION_KEY); if (rtmp != null) { log.debug("RTMP state: {}", rtmp); rtmp.setState(RTMP.STATE_DISCONNECTING); } } // close now, no flushing, no waiting CloseFuture future = ioSession.close(true); // wait for one second future.addListener(new IoFutureListener() { public void operationComplete(CloseFuture future) { if (future.isClosed()) { log.debug("Connection is closed"); } else { log.debug("Connection is not yet closed"); } //de-register with JMX unregisterJMX(); } }); } } /** * Return MINA I/O session. * * @return MINA O/I session, connection between two end-points */ public IoSession getIoSession() { return ioSession; } /** * @return the defaultServerBandwidth */ public int getDefaultServerBandwidth() { return defaultServerBandwidth; } /** * @param defaultServerBandwidth the defaultServerBandwidth to set */ public void setDefaultServerBandwidth(int defaultServerBandwidth) { this.defaultServerBandwidth = defaultServerBandwidth; } /** * @return the defaultClientBandwidth */ public int getDefaultClientBandwidth() { return defaultClientBandwidth; } /** * @param defaultClientBandwidth the defaultClientBandwidth to set */ public void setDefaultClientBandwidth(int defaultClientBandwidth) { this.defaultClientBandwidth = defaultClientBandwidth; } /** * @return the limitType */ public int getLimitType() { return limitType; } /** * @param limitType the limitType to set */ public void setLimitType(int limitType) { this.limitType = limitType; } /** * @return the bandwidthDetection */ public boolean isBandwidthDetection() { return bandwidthDetection; } /** * @param bandwidthDetection the bandwidthDetection to set */ public void setBandwidthDetection(boolean bandwidthDetection) { this.bandwidthDetection = bandwidthDetection; } /** {@inheritDoc} */ @Override public long getPendingMessages() { if (ioSession != null) { return ioSession.getScheduledWriteMessages(); } return 0; } /** {@inheritDoc} */ @Override public long getReadBytes() { if (ioSession != null) { return ioSession.getReadBytes(); } return 0; } /** {@inheritDoc} */ @Override public long getWrittenBytes() { if (ioSession != null) { return ioSession.getWrittenBytes(); } return 0; } public void invokeMethod(String method) { invoke(method); } /** {@inheritDoc} */ @Override public boolean isConnected() { // XXX Paul: not sure isClosing is actually working as we expect here return super.isConnected() && (ioSession != null && ioSession.isConnected()); } /** {@inheritDoc} */ @Override protected void onInactive() { this.close(); } /** * Setter for MINA I/O session (connection). * * @param protocolSession Protocol session */ public void setIoSession(IoSession protocolSession) { SocketAddress remote = protocolSession.getRemoteAddress(); if (remote instanceof InetSocketAddress) { remoteAddress = ((InetSocketAddress) remote).getAddress().getHostAddress(); remotePort = ((InetSocketAddress) remote).getPort(); } else { remoteAddress = remote.toString(); remotePort = -1; } remoteAddresses = new ArrayList(1); remoteAddresses.add(remoteAddress); remoteAddresses = Collections.unmodifiableList(remoteAddresses); this.ioSession = protocolSession; } /** {@inheritDoc} */ @Override public void write(Packet out) { if (ioSession != null) { final Semaphore lock = getLock(); log.trace("Write lock wait count: {}", lock.getQueueLength()); while (!closed) { try { lock.acquire(); } catch (InterruptedException e) { log.warn("Interrupted while waiting for write lock", e); continue; } try { log.debug("Writing message"); writingMessage(out); ioSession.write(out); break; } finally { lock.release(); } } } } /** {@inheritDoc} */ @Override public void writeRaw(IoBuffer out) { if (ioSession != null) { final Semaphore lock = getLock(); while (!closed) { try { lock.acquire(); } catch (InterruptedException e) { log.warn("Interrupted while waiting for write lock", e); continue; } try { log.debug("Writing raw message"); ioSession.write(out); break; } finally { lock.release(); } } } } protected void registerJMX() { // register with jmx MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { String cName = this.getClass().getName(); if (cName.indexOf('.') != -1) { cName = cName.substring(cName.lastIndexOf('.')).replaceFirst("[\\.]", ""); } String hostStr = host; int port = 1935; if (host != null && host.indexOf(":") > -1) { String[] arr = host.split(":"); hostStr = arr[0]; port = Integer.parseInt(arr[1]); } // Create a new mbean for this instance oName = new ObjectName(String.format("org.red5.server:type=%s,connectionType=%s,host=%s,port=%d,clientId=%s", cName, type, hostStr, port, client.getId())); mbs.registerMBean(new StandardMBean(this, RTMPMinaConnectionMXBean.class, true), oName); } catch (Exception e) { log.warn("Error on jmx registration", e); } } protected void unregisterJMX() { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); if (oName != null && mbs.isRegistered(oName)) { try { mbs.unregisterMBean(oName); } catch (Exception e) { log.warn("Exception unregistering: {}", oName, e); } oName = null; } } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/InboundHandshake.java0000644000175000017500000002645211706617130025671 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import java.security.KeyPair; import java.util.Arrays; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Hex; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.Red5; import org.red5.server.net.rtmp.message.Constants; /** * Performs handshaking for server connections. * * @author Paul Gregoire */ public class InboundHandshake extends RTMPHandshake { public InboundHandshake() { super(); } /** * Generates response for versioned connections. * * @param input incoming RTMP bytes * @return outgoing handshake */ public IoBuffer doHandshake(IoBuffer input) { log.trace("doHandshake: {}", input); if (log.isDebugEnabled()) { log.debug("Player encryption byte: {}", handshakeType); byte[] bIn = input.array(); log.debug("Detecting flash player version {},{},{},{}", new Object[]{(bIn[4] & 0x0ff), (bIn[5] & 0x0ff), (bIn[6] & 0x0ff), (bIn[7] & 0x0ff)}); //if the 5th byte is 0 then dont generate new-style handshake if (log.isTraceEnabled()) { log.trace("First few bytes (in): {},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}", new Object[] { bIn[0], bIn[1], bIn[2], bIn[3], bIn[4], bIn[5], bIn[6], bIn[7], bIn[8], bIn[9], bIn[10], bIn[11], bIn[12], bIn[13], bIn[14], bIn[15] }); //client version hex byte[] ver = new byte[4]; System.arraycopy(bIn, 4, ver, 0, 4); log.trace("Version string: {}", Hex.encodeHexString(ver)); //dump byte[] buf = new byte[KEY_LENGTH]; System.arraycopy(bIn, 0, buf, 0, KEY_LENGTH); log.trace("Hex: {}", Hex.encodeHexString(buf)); } } input.mark(); byte versionByte = input.get(4); log.debug("Player version byte: {}", (versionByte & 0x0ff)); input.reset(); if (versionByte == 0) { return generateUnversionedHandshake(input); } //create output buffer IoBuffer output = IoBuffer.allocate(HANDSHAKE_SIZE_SERVER); input.mark(); //make sure this is a client we can communicate with if (validate(input)) { log.debug("Valid RTMP client detected"); } else { log.info("Invalid RTMP connection data detected, you may experience errors"); } input.reset(); log.debug("Using new style handshake"); input.mark(); //create all the dh stuff and add to handshake bytes prepareResponse(input); input.reset(); if (handshakeType == RTMPConnection.RTMP_ENCRYPTED) { log.debug("Incoming public key [{}]: {}", incomingPublicKey.length, Hex.encodeHexString(incomingPublicKey)); log.debug("Outgoing public key [{}]: {}", outgoingPublicKey.length, Hex.encodeHexString(outgoingPublicKey)); byte[] sharedSecret = getSharedSecret(outgoingPublicKey, keyAgreement); // create output cipher byte[] digestOut = calculateHMAC_SHA256(outgoingPublicKey, sharedSecret); try { cipherOut = Cipher.getInstance("RC4"); cipherOut.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(digestOut, 0, 16, "RC4")); } catch (Exception e) { log.warn("Encryption cipher creation failed", e); } // create input cipher byte[] digestIn = calculateHMAC_SHA256(incomingPublicKey, sharedSecret); try { cipherIn = Cipher.getInstance("RC4"); cipherIn.init(Cipher.DECRYPT_MODE, new SecretKeySpec(digestIn, 0, 16, "RC4")); } catch (Exception e) { log.warn("Decryption cipher creation failed", e); } // update 'encoder / decoder state' for the RC4 keys // both parties *pretend* as if handshake part 2 (1536 bytes) was encrypted // effectively this hides / discards the first few bytes of encrypted session // which is known to increase the secure-ness of RC4 // RC4 state is just a function of number of bytes processed so far // that's why we just run 1536 arbitrary bytes through the keys below byte[] dummyBytes = new byte[Constants.HANDSHAKE_SIZE]; cipherIn.update(dummyBytes); cipherOut.update(dummyBytes); } input.mark(); //create the server digest int serverDigestOffset = getDigestOffset(handshakeBytes); byte[] tempBuffer = new byte[Constants.HANDSHAKE_SIZE - DIGEST_LENGTH]; System.arraycopy(handshakeBytes, 0, tempBuffer, 0, serverDigestOffset); System.arraycopy(handshakeBytes, serverDigestOffset + DIGEST_LENGTH, tempBuffer, serverDigestOffset, Constants.HANDSHAKE_SIZE - serverDigestOffset - DIGEST_LENGTH); //calculate the hash byte[] tempHash = calculateHMAC_SHA256(tempBuffer, GENUINE_FMS_KEY, 36); //add the digest System.arraycopy(tempHash, 0, handshakeBytes, serverDigestOffset, DIGEST_LENGTH); //compute the challenge digest byte[] inputBuffer = new byte[Constants.HANDSHAKE_SIZE - DIGEST_LENGTH]; //log.debug("Before get: {}", input.position()); input.get(inputBuffer); //log.debug("After get: {}", input.position()); int keyChallengeIndex = getDigestOffset(inputBuffer); byte[] challengeKey = new byte[DIGEST_LENGTH]; input.position(keyChallengeIndex); input.get(challengeKey, 0, DIGEST_LENGTH); input.reset(); //compute key tempHash = calculateHMAC_SHA256(challengeKey, GENUINE_FMS_KEY, 68); //generate hash byte[] randBytes = new byte[Constants.HANDSHAKE_SIZE - DIGEST_LENGTH]; random.nextBytes(randBytes); byte[] lastHash = calculateHMAC_SHA256(randBytes, tempHash, DIGEST_LENGTH); //set handshake with encryption type output.put(handshakeType); output.put(handshakeBytes); output.put(randBytes); output.put(lastHash); output.flip(); if (log.isTraceEnabled()) { byte[] bOut = output.array(); log.trace("First few bytes (out): {},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}", new Object[] { bOut[0], bOut[1], bOut[2], bOut[3], bOut[4], bOut[5], bOut[6], bOut[7], bOut[8], bOut[9], bOut[10], bOut[11], bOut[12], bOut[13], bOut[14], bOut[15]}); byte[] buf = new byte[KEY_LENGTH]; System.arraycopy(bOut, 0, buf, 0, KEY_LENGTH); log.trace("Hex: {}", Hex.encodeHexString(buf)); } return output; } /** * Generates response for non-versioned connections, such as those before FP9. * * @param input incoming RTMP bytes * @return outgoing handshake */ private IoBuffer generateUnversionedHandshake(IoBuffer input) { log.debug("Using old style (un-versioned) handshake"); //save resource by only doing this after the first request if (HANDSHAKE_PAD_BYTES == null) { HANDSHAKE_PAD_BYTES = new byte[Constants.HANDSHAKE_SIZE - 4]; //fill pad bytes Arrays.fill(HANDSHAKE_PAD_BYTES, (byte) 0x00); } IoBuffer output = IoBuffer.allocate(HANDSHAKE_SIZE_SERVER); //non-encrypted output.put(RTMPConnection.RTMP_NON_ENCRYPTED); //set server uptime in seconds output.putInt((int) Red5.getUpTime() / 1000); //0x01 output.put(RTMPHandshake.HANDSHAKE_PAD_BYTES); output.put(input); output.flip(); return output; } /** * Creates the servers handshake bytes */ @Override protected void createHandshakeBytes() { handshakeBytes = new byte[Constants.HANDSHAKE_SIZE]; //timestamp handshakeBytes[0] = 0; handshakeBytes[1] = 0; handshakeBytes[2] = 0; handshakeBytes[3] = 0; //version (0x01020304) handshakeBytes[4] = 1; handshakeBytes[5] = 2; handshakeBytes[6] = 3; handshakeBytes[7] = 4; //fill the rest with random bytes byte[] rndBytes = new byte[Constants.HANDSHAKE_SIZE - 8]; random.nextBytes(rndBytes); //copy random bytes into our handshake array System.arraycopy(rndBytes, 0, handshakeBytes, 8, (Constants.HANDSHAKE_SIZE - 8)); } /** * Gets the DH offset in the handshake bytes array based on validation scheme * Generates DH keypair * Adds public key to handshake bytes * @param input */ private void prepareResponse(IoBuffer input) { //put the clients input into a byte array byte[] inputBuffer = new byte[input.limit()]; input.get(inputBuffer); //get the clients dh offset int clientDHOffset = getDHOffset(inputBuffer); log.trace("Incoming DH offset: {}", clientDHOffset); //get the clients public key outgoingPublicKey = new byte[KEY_LENGTH]; System.arraycopy(inputBuffer, clientDHOffset, outgoingPublicKey, 0, KEY_LENGTH); //get the servers dh offset int serverDHOffset = getDHOffset(handshakeBytes); log.trace("Outgoing DH offset: {}", serverDHOffset); //create keypair KeyPair keys = generateKeyPair(); //get public key incomingPublicKey = getPublicKey(keys); //add to handshake bytes System.arraycopy(incomingPublicKey, 0, handshakeBytes, serverDHOffset, KEY_LENGTH); } /** * Determines the validation scheme for given input. * * @param input * @return true if client used a supported validation scheme, false if unsupported */ @Override public boolean validate(IoBuffer input) { byte[] pBuffer = new byte[input.remaining()]; //put all the input bytes into our buffer input.get(pBuffer, 0, input.remaining()); if (validateScheme(pBuffer, 0)) { validationScheme = 0; log.debug("Selected scheme: 0"); return true; } if (validateScheme(pBuffer, 1)) { validationScheme = 1; log.debug("Selected scheme: 1"); return true; } log.error("Unable to validate client"); return false; } private boolean validateScheme(byte[] pBuffer, int scheme) { int digestOffset = -1; switch (scheme) { case 0: digestOffset = getDigestOffset0(pBuffer); break; case 1: digestOffset = getDigestOffset1(pBuffer); break; default: log.error("Unknown scheme: {}", scheme); } log.debug("Scheme: {} client digest offset: {}", scheme, digestOffset); byte[] tempBuffer = new byte[Constants.HANDSHAKE_SIZE - DIGEST_LENGTH]; System.arraycopy(pBuffer, 0, tempBuffer, 0, digestOffset); System.arraycopy(pBuffer, digestOffset + DIGEST_LENGTH, tempBuffer, digestOffset, Constants.HANDSHAKE_SIZE - digestOffset - DIGEST_LENGTH); byte[] tempHash = calculateHMAC_SHA256(tempBuffer, GENUINE_FP_KEY, 30); log.debug("Temp: {}", Hex.encodeHexString(tempHash)); boolean result = true; for (int i = 0; i < DIGEST_LENGTH; i++) { //log.trace("Digest: {} Temp: {}", (pBuffer[digestOffset + i] & 0x0ff), (tempHash[i] & 0x0ff)); if (pBuffer[digestOffset + i] != tempHash[i]) { result = false; break; } } return result; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/codec/0000755000175000017500000000000011760512572022671 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/codec/RTMPMinaProtocolDecoder.java0000644000175000017500000000522711754302563030141 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.codec; import java.util.List; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecException; import org.apache.mina.filter.codec.ProtocolDecoderAdapter; import org.apache.mina.filter.codec.ProtocolDecoderOutput; import org.red5.io.object.Deserializer; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.rtmp.message.Constants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * RTMP protocol decoder. */ public class RTMPMinaProtocolDecoder extends ProtocolDecoderAdapter { protected static Logger log = LoggerFactory.getLogger(RTMPMinaProtocolDecoder.class); private RTMPProtocolDecoder decoder = new RTMPProtocolDecoder(); /** {@inheritDoc} */ public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws ProtocolCodecException { //get our state final ProtocolState state = (ProtocolState) session.getAttribute(ProtocolState.SESSION_KEY); //create a buffer and store it on the session IoBuffer buf = (IoBuffer) session.getAttribute("buffer"); if (buf == null) { buf = IoBuffer.allocate(Constants.HANDSHAKE_SIZE); buf.setAutoExpand(true); session.setAttribute("buffer", buf); } buf.put(in); buf.flip(); //construct any objects from the decoded bugger List objects = decoder.decodeBuffer(state, buf); if (objects != null) { for (Object object : objects) { out.write(object); } } } /** * Sets the RTMP protocol decoder. * * @param decoder */ public void setDecoder(RTMPProtocolDecoder decoder) { this.decoder = decoder; } /** * Returns an RTMP decoder * @return RTMP decoder */ public RTMPProtocolDecoder getDecoder() { return decoder; } /** * Setter for deserializer. * * @param deserializer Deserializer */ public void setDeserializer(Deserializer deserializer) { decoder.setDeserializer(deserializer); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/codec/MulticastEventProcessor.java0000644000175000017500000000370111706617130030400 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.codec; import org.apache.mina.core.buffer.IoBuffer; /** * Processes multicast events. */ public class MulticastEventProcessor { /** * Getter for cache ID. * * @return Cache ID */ public byte getCacheId() { return 0; } /** * Disposes cached object. * * @param obj Cached object */ public void disposeCached(Object obj) { if (obj == null) { return; } final IoBuffer[] chunks = (IoBuffer[]) obj; for (int c=0;c < chunks.length;c++) { chunks[c].free(); chunks[c] = null; } } /** * Breaks buffer into chunks of given size. * * @param buf IoBuffer * @param size Chunk size * @return Array of byte buffers, chunks */ public static IoBuffer[] chunkBuffer(IoBuffer buf, int size) { final int num = (int) Math.ceil(buf.limit() / (float) size); final IoBuffer[] chunks = new IoBuffer[num]; for (int i = 0; i < num; i++) { chunks[i] = buf.asReadOnlyBuffer(); final IoBuffer chunk = chunks[i]; int position = size * num; chunk.position(position); if (position + size < chunk.limit()) { chunk.limit(position + size); } } return chunks; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/codec/IEventDecoder.java0000644000175000017500000001066211706617130026215 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.codec; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.net.rtmp.event.Aggregate; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.BytesRead; import org.red5.server.net.rtmp.event.ChunkSize; import org.red5.server.net.rtmp.event.FlexMessage; import org.red5.server.net.rtmp.event.Invoke; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.Ping; import org.red5.server.net.rtmp.event.Unknown; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.so.ISharedObjectMessage; /** * Event decoder decodes event objects from incoming byte buffer. */ public interface IEventDecoder { /** * Decodes event of Unknown type. * * @param dataType Data type * @param in Byte buffer to decode * @return Unknown event */ public abstract Unknown decodeUnknown(byte dataType, IoBuffer in); /** * Decodes chunk size event. * * @param in Byte buffer to decode * @return ChunkSize event */ public abstract ChunkSize decodeChunkSize(IoBuffer in); /** * Decodes shared object message event. * * @param in Byte buffer to decode * @param rtmp RTMP protocol state * @return ISharedObjectMessage event */ public abstract ISharedObjectMessage decodeSharedObject(IoBuffer in, RTMP rtmp); /** * Decodes shared object message event from AMF3 encoding. * * @param in Byte buffer to decode * @param rtmp RTMP protocol state * @return ISharedObjectMessage event */ public abstract ISharedObjectMessage decodeFlexSharedObject(IoBuffer in, RTMP rtmp); /** * Decodes notification event. * * @param in Byte buffer to decode * @param rtmp RTMP protocol state * @return Notify event */ public abstract Notify decodeNotify(IoBuffer in, RTMP rtmp); /** * Decodes invocation event. * * @param in Byte buffer to decode * @param rtmp RTMP protocol state * @return Invoke event */ public abstract Invoke decodeInvoke(IoBuffer in, RTMP rtmp); /** * Decodes ping event. * * @param in Byte buffer to decode * @return Ping event */ public abstract Ping decodePing(IoBuffer in); /** * Decodes BytesRead event. * * @param in Byte buffer to decode * @return BytesRead event */ public abstract BytesRead decodeBytesRead(IoBuffer in); /** * Decodes the aggregated data. * * @param in Byte buffer to decode * @return Aggregate event */ public abstract Aggregate decodeAggregate(IoBuffer in); /** * Decodes audio data event. * * @param in Byte buffer to decode * @return AudioData event */ public abstract AudioData decodeAudioData(IoBuffer in); /** * Decodes video data event. * * @param in Byte buffer to decode * @return VideoData event */ public abstract VideoData decodeVideoData(IoBuffer in); /** * Decodes Flex message event. * * @param in Byte buffer to decode * @param rtmp RTMP protocol state * @return FlexMessage event */ public abstract FlexMessage decodeFlexMessage(IoBuffer in, RTMP rtmp); } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/codec/RTMPCodecFactory.java0000644000175000017500000000532111706617130026601 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.codec; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFactory; import org.apache.mina.filter.codec.ProtocolDecoder; import org.apache.mina.filter.codec.ProtocolEncoder; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; /** * RTMP codec factory creates RTMP encoders/decoders. */ public class RTMPCodecFactory implements ProtocolCodecFactory { /** * Deserializer. */ protected Deserializer deserializer; /** * Serializer. */ protected Serializer serializer; /** * Mina protocol decoder for RTMP. */ private RTMPMinaProtocolDecoder decoder; /** * Mina protocol encoder for RTMP. */ private RTMPMinaProtocolEncoder encoder; /** * Initialization */ public void init() { decoder = new RTMPMinaProtocolDecoder(); decoder.setDeserializer(deserializer); encoder = new RTMPMinaProtocolEncoder(); encoder.setSerializer(serializer); } /** * Setter for deserializer. * * @param deserializer Deserializer */ public void setDeserializer(Deserializer deserializer) { this.deserializer = deserializer; } /** * Setter for serializer. * * @param serializer Serializer */ public void setSerializer(Serializer serializer) { this.serializer = serializer; } /** {@inheritDoc} */ public ProtocolDecoder getDecoder(IoSession session) { return decoder; } /** {@inheritDoc} */ public ProtocolEncoder getEncoder(IoSession session) { return encoder; } /** * Returns the RTMP decoder. * * @return decoder */ public RTMPProtocolDecoder getRTMPDecoder() { return decoder.getDecoder(); } /** * Returns the RTMP encoder. * * @return encoder */ public RTMPProtocolEncoder getRTMPEncoder() { return encoder.getEncoder(); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/codec/RTMP.java0000644000175000017500000002625211754746347024341 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.codec; import java.util.HashMap; import java.util.Map; import org.red5.server.api.IConnection.Encoding; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.rtmp.message.Header; import org.red5.server.net.rtmp.message.Packet; /** * RTMP is the RTMP protocol state representation. */ public class RTMP extends ProtocolState { public String[] states = {"connect", "handshake", "connected", "error", "disconnecting", "disconnected"}; /** * Connect state. */ public static final byte STATE_CONNECT = 0x00; /** * Handshake state. Server sends handshake request to client right after connection established. */ public static final byte STATE_HANDSHAKE = 0x01; /** * Connected. */ public static final byte STATE_CONNECTED = 0x02; /** * Error. */ public static final byte STATE_ERROR = 0x03; /** * In the processing of disconnecting */ public static final byte STATE_DISCONNECTING = 0x04; /** * Disconnected. */ public static final byte STATE_DISCONNECTED = 0x05; /** * Sent the connect message to origin. */ public static final byte STATE_EDGE_CONNECT_ORIGIN_SENT = 0x11; /** * Forwarded client's connect call to origin. */ public static final byte STATE_ORIGIN_CONNECT_FORWARDED = 0x12; /** * Edge is disconnecting, waiting Origin close connection. */ public static final byte STATE_EDGE_DISCONNECTING = 0x13; /** * Default chunk size. Packets are read and written chunk-by-chunk. */ public static final int DEFAULT_CHUNK_SIZE = 128; /** * RTMP state. */ private volatile byte state = STATE_CONNECT; /** * Debug flag. */ private boolean debug; /** * Encryption flag. */ private boolean encrypted = false; /** * Last read channel. */ private int lastReadChannel = 0x00; /** * Last write channel. */ private int lastWriteChannel = 0x00; /** * Read headers, keyed by channel id. */ private final Map readHeaders = new HashMap(); /** * Write headers, keyed by channel id. */ private final Map writeHeaders = new HashMap(); /** * Headers actually used for a packet, keyed by channel id. */ private final Map readPacketHeaders = new HashMap(); /** * Read packets, keyed by channel id. */ private final Map readPackets = new HashMap(); /** * Written packets, keyed by channel id. */ private final Map writePackets = new HashMap(); /** * Written timestamps */ private final Map writeTimestamps = new HashMap(); /** * Class for mapping between clock time and stream time for live streams * @author aclarke * */ static class LiveTimestampMapping { private final long clockStartTime; private final long streamStartTime; private boolean keyFrameNeeded; private long lastStreamTime; public LiveTimestampMapping(long clockStartTime, long streamStartTime) { this.clockStartTime = clockStartTime; this.streamStartTime = streamStartTime; this.keyFrameNeeded = true; // Always start with a key frame this.lastStreamTime = streamStartTime; } public long getStreamStartTime() { return streamStartTime; } public long getClockStartTime() { return clockStartTime; } public void setKeyFrameNeeded(boolean keyFrameNeeded) { this.keyFrameNeeded = keyFrameNeeded; } public boolean isKeyFrameNeeded() { return keyFrameNeeded; } public long getLastStreamTime() { return lastStreamTime; } public void setLastStreamTime(long lastStreamTime) { this.lastStreamTime = lastStreamTime; } } /** * Mapping between channel and the last clock to stream mapping */ private final Map liveTimestamps = new HashMap(); /** * Read chunk size. Packets are read and written chunk-by-chunk. */ private int readChunkSize = DEFAULT_CHUNK_SIZE; /** * Write chunk size. Packets are read and written chunk-by-chunk. */ private int writeChunkSize = DEFAULT_CHUNK_SIZE; /** * Encoding type for objects. */ private Encoding encoding = Encoding.AMF0; /** * Creates RTMP object; essentially for storing session information. */ public RTMP() { } /** * Getter for debug. * * @return Debug state */ public boolean isDebug() { return debug; } /** * Setter for debug. * * @param debug Debug flag new value */ public void setDebug(boolean debug) { this.debug = debug; } /** * @return the encrypted */ public boolean isEncrypted() { return encrypted; } /** * @param encrypted the encrypted to set */ public void setEncrypted(boolean encrypted) { this.encrypted = encrypted; } /** * Return current state. * * @return State */ public byte getState() { return state; } /** * Releases number of packets. * * @param packets Packets to release */ private void freePackets(Map packets) { for (Packet packet : packets.values()) { if (packet != null && packet.getData() != null) { packet.getData().free(); packet.setData(null); } } packets.clear(); } /** * Setter for state. * * @param state New state */ public void setState(byte state) { this.state = state; if (state == STATE_DISCONNECTED) { // Free temporary packets freePackets(readPackets); freePackets(writePackets); readHeaders.clear(); writeHeaders.clear(); } } /** * Setter for last read header. * * @param channelId Channel id * @param header Header */ public void setLastReadHeader(int channelId, Header header) { lastReadChannel = channelId; readHeaders.put(channelId, header); } /** * Return last read header for channel. * * @param channelId Channel id * @return Last read header */ public Header getLastReadHeader(int channelId) { return readHeaders.get(channelId); } /** * Setter for last written header. * * @param channelId Channel id * @param header Header */ public void setLastWriteHeader(int channelId, Header header) { lastWriteChannel = channelId; writeHeaders.put(channelId, header); } /** * Return last written header for channel. * * @param channelId Channel id * @return Last written header */ public Header getLastWriteHeader(int channelId) { return writeHeaders.get(channelId); } /** * Setter for last read packet. * * @param channelId Channel id * @param packet Packet */ public void setLastReadPacket(int channelId, Packet packet) { Packet prevPacket = readPackets.put(channelId, packet); if (prevPacket != null && prevPacket.getData() != null) { prevPacket.getData().free(); prevPacket.setData(null); } } /** * Return last read packet for channel. * * @param channelId Channel id * @return Last read packet for that channel */ public Packet getLastReadPacket(int channelId) { return readPackets.get(channelId); } /** * Setter for last written packet. * * @param channelId Channel id * @param packet Last written packet */ public void setLastWritePacket(int channelId, Packet packet) { // Disabled to help GC because we currently don't use the write packets /* Packet prevPacket = writePackets.put(channelId, packet); if (prevPacket != null && prevPacket.getData() != null) { prevPacket.getData().release(); prevPacket.setData(null); } */ } /** * Return packet that has been written last. * * @param channelId Channel id * @return Packet that has been written last */ public Packet getLastWritePacket(int channelId) { return writePackets.get(channelId); } /** * Return channel being read last. * * @return Last read channel */ public int getLastReadChannel() { return lastReadChannel; } /** * Getter for channel being written last. * * @return Last write channel */ public int getLastWriteChannel() { return lastWriteChannel; } /** * Getter for write chunk size. Data is being read chunk-by-chunk. * * @return Read chunk size */ public int getReadChunkSize() { return readChunkSize; } /** * Setter for read chunk size. Data is being read chunk-by-chunk. * * @param readChunkSize Value to set for property 'readChunkSize'. */ public void setReadChunkSize(int readChunkSize) { this.readChunkSize = readChunkSize; } /** * Getter for write chunk size. Data is being written chunk-by-chunk. * * @return Write chunk size */ public int getWriteChunkSize() { return writeChunkSize; } /** * Setter for write chunk size. * * @param writeChunkSize Write chunk size */ public void setWriteChunkSize(int writeChunkSize) { this.writeChunkSize = writeChunkSize; } /** * Getter for encoding version. * * @return Encoding version */ public Encoding getEncoding() { return encoding; } /** * Setter for encoding version. * * @param encoding Encoding version */ public void setEncoding(Encoding encoding) { this.encoding = encoding; } public void setLastFullTimestampWritten(int channelId, int timer) { writeTimestamps.put(channelId, timer); } public Integer getLastFullTimestampWritten(int channelId) { return writeTimestamps.get(channelId); } public void setLastReadPacketHeader(int channelId, Header header) { readPacketHeaders.put(channelId, header); } public Header getLastReadPacketHeader(int channelId) { return readPacketHeaders.get(channelId); } LiveTimestampMapping getLastTimestampMapping(int channelId) { return liveTimestamps.get(channelId); } void setLastTimestampMapping(int channelId, LiveTimestampMapping mapping) { liveTimestamps.put(channelId, mapping); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "RTMP [state=" + states[state] + ", debug=" + debug + ", encrypted=" + encrypted + ", lastReadChannel=" + lastReadChannel + ", lastWriteChannel=" + lastWriteChannel + ", readHeaders=" + readHeaders + ", writeHeaders=" + writeHeaders + ", readPacketHeaders=" + readPacketHeaders + ", readPackets=" + readPackets + ", writePackets=" + writePackets + ", writeTimestamps=" + writeTimestamps + ", liveTimestamps=" + liveTimestamps + ", readChunkSize=" + readChunkSize + ", writeChunkSize=" + writeChunkSize + ", encoding=" + encoding + "]"; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/codec/RTMPMinaCodecFactory.java0000644000175000017500000000410311746326760027415 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.codec; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFactory; import org.apache.mina.filter.codec.ProtocolDecoder; import org.apache.mina.filter.codec.ProtocolEncoder; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * RTMP codec factory. */ public class RTMPMinaCodecFactory implements ProtocolCodecFactory, ApplicationContextAware, InitializingBean { protected ApplicationContext appCtx; /** * RTMP Mina protocol decoder. */ protected RTMPMinaProtocolDecoder decoder; /** * RTMP Mina protocol encoder. */ protected RTMPMinaProtocolEncoder encoder; public void afterPropertiesSet() throws Exception { decoder = (RTMPMinaProtocolDecoder) appCtx.getBean("minaDecoder"); encoder = (RTMPMinaProtocolEncoder) appCtx.getBean("minaEncoder"); } /** {@inheritDoc} */ public ProtocolDecoder getDecoder(IoSession session) { return decoder; } /** {@inheritDoc} */ public ProtocolEncoder getEncoder(IoSession session) { return encoder; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { appCtx = applicationContext; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/codec/RTMPProtocolEncoder.java0000644000175000017500000007635111754302563027354 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.codec; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.object.Output; import org.red5.io.object.Serializer; import org.red5.io.utils.BufferUtils; import org.red5.server.api.IConnection.Encoding; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.api.service.IServiceCall; import org.red5.server.api.stream.IClientStream; import org.red5.server.exception.ClientDetailsException; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.rtmp.RTMPConnection; import org.red5.server.net.rtmp.RTMPUtils; import org.red5.server.net.rtmp.codec.RTMP.LiveTimestampMapping; import org.red5.server.net.rtmp.event.Aggregate; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.BytesRead; import org.red5.server.net.rtmp.event.ChunkSize; import org.red5.server.net.rtmp.event.ClientBW; import org.red5.server.net.rtmp.event.FlexMessage; import org.red5.server.net.rtmp.event.FlexStreamSend; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.Invoke; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.Ping; import org.red5.server.net.rtmp.event.ServerBW; import org.red5.server.net.rtmp.event.Unknown; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.net.rtmp.event.VideoData.FrameType; import org.red5.server.net.rtmp.message.Constants; import org.red5.server.net.rtmp.message.Header; import org.red5.server.net.rtmp.message.Packet; import org.red5.server.net.rtmp.message.SharedObjectTypeMapping; import org.red5.server.net.rtmp.status.Status; import org.red5.server.net.rtmp.status.StatusCodes; import org.red5.server.net.rtmp.status.StatusObject; import org.red5.server.service.Call; import org.red5.server.so.ISharedObjectEvent; import org.red5.server.so.ISharedObjectMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * RTMP protocol encoder encodes RTMP messages and packets to byte buffers. */ public class RTMPProtocolEncoder implements Constants, IEventEncoder { protected static Logger log = LoggerFactory.getLogger(RTMPProtocolEncoder.class); /** * Serializer object. */ protected Serializer serializer; /** * Tolerance (in milliseconds) for late media on streams. A set of levels based on this * value will be determined. */ private long baseTolerance = 15000; /** * Middle tardiness level, between base and this value disposable frames * will be dropped. Between this and highest value regular interframes * will be dropped. */ private long midTolerance = baseTolerance + (long) (baseTolerance * 0.3); /** * Highest tardiness level before dropping key frames */ private long highestTolerance = baseTolerance + (long) (baseTolerance * 0.6); /** * Indicates if we should drop live packets with future timestamp * (i.e, when publisher bandwidth is limited) - EXPERIMENTAL */ private boolean dropLiveFuture; private RTMPConnection conn; /** * Encodes object with given protocol state to byte buffer * * @param state Protocol state * @param message Object to encode * @return IoBuffer with encoded data * @throws Exception Any decoding exception */ public IoBuffer encode(ProtocolState state, Object message) throws Exception { try { final RTMP rtmp = (RTMP) state; if (message instanceof IoBuffer) { return (IoBuffer) message; } else { return encodePacket(rtmp, (Packet) message); } } catch (RuntimeException e) { log.error("Error encoding object: ", e); } return null; } /** * Encode packet. * * @param rtmp RTMP protocol state * @param packet RTMP packet * @return Encoded data */ public IoBuffer encodePacket(RTMP rtmp, Packet packet) { IoBuffer out = null; IoBuffer data = null; final Header header = packet.getHeader(); final int channelId = header.getChannelId(); log.debug("Channel id: {}", channelId); final IRTMPEvent message = packet.getMessage(); if (message instanceof ChunkSize) { ChunkSize chunkSizeMsg = (ChunkSize) message; rtmp.setWriteChunkSize(chunkSizeMsg.getSize()); } //normally the message is expected not to be dropped if (!dropMessage(rtmp, channelId, message)) { data = encodeMessage(rtmp, header, message); if (data != null) { if (data.position() != 0) { data.flip(); } else { data.rewind(); } int dataLen = data.limit(); header.setSize(dataLen); Header lastHeader = rtmp.getLastWriteHeader(channelId); // maximum header size with extended timestamp (Chunk message header type 0 with 11 byte) int headerSize = 18; rtmp.setLastWriteHeader(channelId, header); rtmp.setLastWritePacket(channelId, packet); int chunkSize = rtmp.getWriteChunkSize(); // maximum chunk header size with extended timestamp int chunkHeaderSize = 7; int numChunks = (int) Math.ceil(dataLen / (float) chunkSize); int bufSize = dataLen + headerSize + (numChunks > 0 ? (numChunks - 1) * chunkHeaderSize : 0); out = IoBuffer.allocate(bufSize, false); encodeHeader(rtmp, header, lastHeader, out); if (numChunks == 1) { // we can do it with a single copy BufferUtils.put(out, data, dataLen); } else { int extendedTimestamp = header.getExtendedTimestamp(); for (int i = 0; i < numChunks - 1; i++) { BufferUtils.put(out, data, chunkSize); dataLen -= chunkSize; RTMPUtils.encodeHeaderByte(out, HEADER_CONTINUE, header.getChannelId()); if (extendedTimestamp != 0) { out.putInt(extendedTimestamp); } } BufferUtils.put(out, data, dataLen); } data.free(); out.flip(); data = null; } } message.release(); return out; } /** * Determine if this message should be dropped for lateness. Live publish data * does not come through this section, only outgoing data does. * * - determine latency between server and client using ping * - ping timestamp is unsigned int (4 bytes) and is set from value on sender * * 1st drop disposable frames - lowest mark * 2nd drop interframes - middle * 3rd drop key frames - high mark * * @param rtmp the protocol state * @param channelId the channel ID * @param message the message * @return true to drop; false to send */ protected boolean dropMessage(RTMP rtmp, int channelId, IRTMPEvent message) { //whether or not the packet will be dropped boolean drop = false; //whether or not the packet is video data boolean isVideo = false; if (message instanceof Ping) { final Ping pingMessage = (Ping) message; if (pingMessage.getEventType() == Ping.STREAM_PLAYBUFFER_CLEAR) { // client buffer cleared, make sure to reset timestamps for this stream final int channel = (4 + ((pingMessage.getValue2() - 1) * 5)); rtmp.setLastTimestampMapping(channel, null); rtmp.setLastTimestampMapping(channel + 1, null); rtmp.setLastTimestampMapping(channel + 2, null); } // never drop pings return false; } // we only drop audio or video data if ((isVideo = message instanceof VideoData) || message instanceof AudioData) { if (message.getTimestamp() == 0) { // never drop initial packages, also this could be the first packet after // MP4 seeking and therefore mess with the timestamp mapping return false; } // determine working type boolean isLive = message.getSourceType() == Constants.SOURCE_TYPE_LIVE; log.trace("Connection type: {}", (isLive ? "Live" : "VOD")); long timestamp = (message.getTimestamp() & 0xFFFFFFFFL); LiveTimestampMapping mapping = rtmp.getLastTimestampMapping(channelId); // just get the current time ONCE per packet long now = System.currentTimeMillis(); if (mapping == null || timestamp < mapping.getLastStreamTime()) { log.debug("Resetting clock time ({}) to stream time ({})", now, timestamp); // either first time through, or time stamps were reset mapping = new LiveTimestampMapping(now, timestamp); rtmp.setLastTimestampMapping(channelId, mapping); } mapping.setLastStreamTime(timestamp); long clockTimeOfMessage = mapping.getClockStartTime() + timestamp - mapping.getStreamStartTime(); //determine tardiness / how late it is long tardiness = clockTimeOfMessage - now; //TDJ: EXPERIMENTAL dropping for LIVE packets in future (default false) if (isLive && dropLiveFuture) { tardiness = Math.abs(tardiness); } //subtract the ping time / latency from the tardiness value log.debug("Connection: {}", conn); if (conn != null) { log.debug("Last ping time for connection: {}", conn.getLastPingTime()); tardiness -= conn.getLastPingTime(); //subtract the buffer time int streamId = conn.getStreamIdForChannel(channelId); IClientStream stream = conn.getStreamById(streamId); if (stream != null) { int clientBufferDuration = stream.getClientBufferDuration(); if (clientBufferDuration > 0) { //two times the buffer duration seems to work best with vod if (!isLive) { tardiness -= clientBufferDuration * 2; } else { tardiness -= clientBufferDuration; } } log.debug("Client buffer duration: {}", clientBufferDuration); } } //TODO: how should we differ handling based on live or vod? //TODO: if we are VOD do we "pause" the provider when we are consistently late? log.debug("Packet timestamp: {}; tardiness: {}; now: {}; message clock time: {}, dropLiveFuture: {}", new Object[] { timestamp, tardiness, now, clockTimeOfMessage, dropLiveFuture }); //anything coming in less than the base will be allowed to pass, it will not be //dropped or manipulated if (tardiness < baseTolerance) { //frame is below lowest bounds, let it go } else if (tardiness > highestTolerance) { //frame is really late, drop it no matter what type log.debug("Dropping late message: {}", message); //if we're working with video, indicate that we will need a key frame to proceed if (isVideo) { mapping.setKeyFrameNeeded(true); } //drop it drop = true; } else { if (isVideo) { VideoData video = (VideoData) message; if (video.getFrameType() == FrameType.KEYFRAME) { //if its a key frame the inter and disposible checks can be skipped log.debug("Resuming stream with key frame; message: {}", message); mapping.setKeyFrameNeeded(false); } else if (tardiness >= baseTolerance && tardiness < midTolerance) { //drop disposable frames if (video.getFrameType() == FrameType.DISPOSABLE_INTERFRAME) { log.debug("Dropping disposible frame; message: {}", message); drop = true; } } else if (tardiness >= midTolerance && tardiness <= highestTolerance) { //drop inter-frames and disposable frames log.debug("Dropping disposible or inter frame; message: {}", message); drop = true; } } } } log.debug("Message was{}dropped", (drop ? " " : " not ")); return drop; } /** * Determine type of header to use. * * @param rtmp The protocol state * @param header RTMP message header * @param lastHeader Previous header * @return Header type to use. */ private byte getHeaderType(final RTMP rtmp, final Header header, final Header lastHeader) { if (lastHeader == null) { return HEADER_NEW; } final Integer lastFullTs = rtmp.getLastFullTimestampWritten(header.getChannelId()); if (lastFullTs == null) { return HEADER_NEW; } final byte headerType; final long diff = RTMPUtils.diffTimestamps(header.getTimer(), lastHeader.getTimer()); final long timeSinceFullTs = RTMPUtils.diffTimestamps(header.getTimer(), lastFullTs); if (header.getStreamId() != lastHeader.getStreamId() || diff < 0 || timeSinceFullTs >= 250) { // New header mark if header for another stream headerType = HEADER_NEW; } else if (header.getSize() != lastHeader.getSize() || header.getDataType() != lastHeader.getDataType()) { // Same source header if last header data type or size differ headerType = HEADER_SAME_SOURCE; } else if (header.getTimer() != lastHeader.getTimer() + lastHeader.getTimerDelta()) { // Timer change marker if there's time gap between header time stamps headerType = HEADER_TIMER_CHANGE; } else { // Continue encoding headerType = HEADER_CONTINUE; } return headerType; } /** * Calculate number of bytes necessary to encode the header. * * @param rtmp The protocol state * @param header RTMP message header * @param lastHeader Previous header * @return Calculated size */ private int calculateHeaderSize(final RTMP rtmp, final Header header, final Header lastHeader) { final byte headerType = getHeaderType(rtmp, header, lastHeader); int channelIdAdd = 0; int channelId = header.getChannelId(); if (channelId > 320) { channelIdAdd = 2; } else if (channelId > 63) { channelIdAdd = 1; } return RTMPUtils.getHeaderLength(headerType) + channelIdAdd; } /** * Encode RTMP header. * @param rtmp The protocol state * @param header RTMP message header * @param lastHeader Previous header * @return Encoded header data */ public IoBuffer encodeHeader(final RTMP rtmp, final Header header, final Header lastHeader) { final IoBuffer result = IoBuffer.allocate(calculateHeaderSize(rtmp, header, lastHeader)); encodeHeader(rtmp, header, lastHeader, result); return result; } /** * Encode RTMP header into given IoBuffer. * * @param rtmp The protocol state * @param header RTMP message header * @param lastHeader Previous header * @param buf Buffer to write encoded header to */ public void encodeHeader(final RTMP rtmp, final Header header, final Header lastHeader, final IoBuffer buf) { final byte headerType = getHeaderType(rtmp, header, lastHeader); RTMPUtils.encodeHeaderByte(buf, headerType, header.getChannelId()); final int timer; switch (headerType) { case HEADER_NEW: timer = header.getTimer(); if (timer < 0 || timer >= 0xffffff) { RTMPUtils.writeMediumInt(buf, 0xffffff); } else { RTMPUtils.writeMediumInt(buf, timer); } RTMPUtils.writeMediumInt(buf, header.getSize()); buf.put(header.getDataType()); RTMPUtils.writeReverseInt(buf, header.getStreamId()); if (timer < 0 || timer >= 0xffffff) { buf.putInt(timer); header.setExtendedTimestamp(timer); } header.setTimerBase(timer); header.setTimerDelta(0); rtmp.setLastFullTimestampWritten(header.getChannelId(), timer); break; case HEADER_SAME_SOURCE: timer = (int) RTMPUtils.diffTimestamps(header.getTimer(), lastHeader.getTimer()); if (timer < 0 || timer >= 0xffffff) { RTMPUtils.writeMediumInt(buf, 0xffffff); } else { RTMPUtils.writeMediumInt(buf, timer); } RTMPUtils.writeMediumInt(buf, header.getSize()); buf.put(header.getDataType()); if (timer < 0 || timer >= 0xffffff) { buf.putInt(timer); header.setExtendedTimestamp(timer); } header.setTimerBase(header.getTimer() - timer); header.setTimerDelta(timer); break; case HEADER_TIMER_CHANGE: timer = (int) RTMPUtils.diffTimestamps(header.getTimer(), lastHeader.getTimer()); if (timer < 0 || timer >= 0xffffff) { RTMPUtils.writeMediumInt(buf, 0xffffff); buf.putInt(timer); header.setExtendedTimestamp(timer); } else { RTMPUtils.writeMediumInt(buf, timer); } header.setTimerBase(header.getTimer() - timer); header.setTimerDelta(timer); break; case HEADER_CONTINUE: timer = (int) RTMPUtils.diffTimestamps(header.getTimer(), lastHeader.getTimer()); header.setTimerBase(header.getTimer() - timer); header.setTimerDelta(timer); if (lastHeader.getExtendedTimestamp() != 0) { buf.putInt(lastHeader.getExtendedTimestamp()); header.setExtendedTimestamp(lastHeader.getExtendedTimestamp()); } break; default: break; } log.trace("CHUNK, E, {}, {}", header, headerType); } /** * Encode message. * * @param rtmp RTMP protocol state * @param header RTMP message header * @param message RTMP message (event) * @return Encoded message data */ public IoBuffer encodeMessage(RTMP rtmp, Header header, IRTMPEvent message) { IServiceCall call = null; switch (header.getDataType()) { case TYPE_CHUNK_SIZE: return encodeChunkSize((ChunkSize) message); case TYPE_INVOKE: log.trace("Invoke {}", message); call = ((Invoke) message).getCall(); if (call != null) { log.debug("{}", call.toString()); Object[] args = call.getArguments(); if (args != null && args.length > 0) { Object a0 = args[0]; if (a0 instanceof Status) { Status status = (Status) a0; //code: NetStream.Seek.Notify if (StatusCodes.NS_SEEK_NOTIFY.equals(status.getCode())) { //desc: Seeking 25000 (stream ID: 1). int seekTime = Integer.valueOf(status.getDescription().split(" ")[1]); log.trace("Seek to time: {}", seekTime); //audio and video channels int[] channels = new int[] { 5, 6 }; //if its a seek notification, reset the "mapping" for audio (5) and video (6) for (int channelId : channels) { LiveTimestampMapping mapping = rtmp.getLastTimestampMapping(channelId); if (mapping != null) { long timestamp = mapping.getClockStartTime() + (seekTime & 0xFFFFFFFFL); log.trace("Setting last stream time to: {}", timestamp); mapping.setLastStreamTime(timestamp); } else { log.debug("No ts mapping for channel id: {}", channelId); } } } } } } return encodeInvoke((Invoke) message, rtmp); case TYPE_NOTIFY: log.trace("Notify {}", message); call = ((Notify) message).getCall(); if (call == null) { return encodeStreamMetadata((Notify) message); } else { return encodeNotify((Notify) message, rtmp); } case TYPE_PING: return encodePing((Ping) message); case TYPE_BYTES_READ: return encodeBytesRead((BytesRead) message); case TYPE_AGGREGATE: log.trace("Encode aggregate message"); return encodeAggregate((Aggregate) message); case TYPE_AUDIO_DATA: log.trace("Encode audio message"); return encodeAudioData((AudioData) message); case TYPE_VIDEO_DATA: log.trace("Encode video message"); return encodeVideoData((VideoData) message); case TYPE_FLEX_SHARED_OBJECT: return encodeFlexSharedObject((ISharedObjectMessage) message, rtmp); case TYPE_SHARED_OBJECT: return encodeSharedObject((ISharedObjectMessage) message, rtmp); case TYPE_SERVER_BANDWIDTH: return encodeServerBW((ServerBW) message); case TYPE_CLIENT_BANDWIDTH: return encodeClientBW((ClientBW) message); case TYPE_FLEX_MESSAGE: return encodeFlexMessage((FlexMessage) message, rtmp); case TYPE_FLEX_STREAM_SEND: return encodeFlexStreamSend((FlexStreamSend) message); default: log.warn("Unknown object type: {}", header.getDataType()); } return null; } /** * Encode server-side bandwidth event. * * @param serverBW Server-side bandwidth event * @return Encoded event data */ private IoBuffer encodeServerBW(ServerBW serverBW) { final IoBuffer out = IoBuffer.allocate(4); out.putInt(serverBW.getBandwidth()); return out; } /** * Encode client-side bandwidth event. * * @param clientBW Client-side bandwidth event * @return Encoded event data */ private IoBuffer encodeClientBW(ClientBW clientBW) { final IoBuffer out = IoBuffer.allocate(5); out.putInt(clientBW.getBandwidth()); out.put(clientBW.getValue2()); return out; } /** {@inheritDoc} */ public IoBuffer encodeChunkSize(ChunkSize chunkSize) { final IoBuffer out = IoBuffer.allocate(4); out.putInt(chunkSize.getSize()); return out; } /** {@inheritDoc} */ public IoBuffer encodeFlexSharedObject(ISharedObjectMessage so, RTMP rtmp) { final IoBuffer out = IoBuffer.allocate(128); out.setAutoExpand(true); out.put((byte) 0x00); // unknown (not AMF version) doEncodeSharedObject(so, rtmp, out); return out; } /** {@inheritDoc} */ public IoBuffer encodeSharedObject(ISharedObjectMessage so, RTMP rtmp) { final IoBuffer out = IoBuffer.allocate(128); out.setAutoExpand(true); doEncodeSharedObject(so, rtmp, out); return out; } /** * Perform the actual encoding of the shared object contents. * * @param so shared object * @param rtmp rtmp * @param out output buffer */ private void doEncodeSharedObject(ISharedObjectMessage so, RTMP rtmp, IoBuffer out) { final Encoding encoding = rtmp.getEncoding(); final Output output = new org.red5.io.amf.Output(out); final Output amf3output = new org.red5.io.amf3.Output(out); output.putString(so.getName()); // SO version out.putInt(so.getVersion()); // Encoding (this always seems to be 2 for persistent shared objects) out.putInt(so.isPersistent() ? 2 : 0); // unknown field out.putInt(0); int mark, len; for (ISharedObjectEvent event : so.getEvents()) { byte type = SharedObjectTypeMapping.toByte(event.getType()); switch (event.getType()) { case SERVER_CONNECT: case CLIENT_INITIAL_DATA: case CLIENT_CLEAR_DATA: out.put(type); out.putInt(0); break; case SERVER_DELETE_ATTRIBUTE: case CLIENT_DELETE_DATA: case CLIENT_UPDATE_ATTRIBUTE: out.put(type); mark = out.position(); out.skip(4); // we will be back output.putString(event.getKey()); len = out.position() - mark - 4; out.putInt(mark, len); break; case SERVER_SET_ATTRIBUTE: case CLIENT_UPDATE_DATA: if (event.getKey() == null) { // Update multiple attributes in one request Map initialData = (Map) event.getValue(); for (Object o : initialData.keySet()) { out.put(type); mark = out.position(); out.skip(4); // we will be back String key = (String) o; output.putString(key); if (encoding == Encoding.AMF3) { serializer.serialize(amf3output, initialData.get(key)); } else { serializer.serialize(output, initialData.get(key)); } len = out.position() - mark - 4; out.putInt(mark, len); } } else { out.put(type); mark = out.position(); out.skip(4); // we will be back output.putString(event.getKey()); if (encoding == Encoding.AMF3) { serializer.serialize(amf3output, event.getValue()); } else { serializer.serialize(output, event.getValue()); } len = out.position() - mark - 4; out.putInt(mark, len); } break; case CLIENT_SEND_MESSAGE: case SERVER_SEND_MESSAGE: // Send method name and value out.put(type); mark = out.position(); out.skip(4); // Serialize name of the handler to call... serializer.serialize(output, event.getKey()); // ...and the arguments for (Object arg : (List) event.getValue()) { if (encoding == Encoding.AMF3) { serializer.serialize(amf3output, arg); } else { serializer.serialize(output, arg); } } len = out.position() - mark - 4; //log.debug(len); out.putInt(mark, len); //log.info(out.getHexDump()); break; case CLIENT_STATUS: out.put(type); final String status = event.getKey(); final String message = (String) event.getValue(); out.putInt(message.length() + status.length() + 4); output.putString(message); output.putString(status); break; default: log.warn("Unknown event: {}", event.getType()); // XXX: need to make this work in server or client mode out.put(type); mark = out.position(); out.skip(4); // we will be back output.putString(event.getKey()); if (encoding == Encoding.AMF3) { serializer.serialize(amf3output, event.getValue()); } else { serializer.serialize(output, event.getValue()); } len = out.position() - mark - 4; out.putInt(mark, len); break; } } } /** {@inheritDoc} */ public IoBuffer encodeNotify(Notify notify, RTMP rtmp) { return encodeNotifyOrInvoke(notify, rtmp); } /** {@inheritDoc} */ public IoBuffer encodeInvoke(Invoke invoke, RTMP rtmp) { return encodeNotifyOrInvoke(invoke, rtmp); } /** * Encode notification event. * * @param invoke Notification event * @return Encoded event data */ protected IoBuffer encodeNotifyOrInvoke(Notify invoke, RTMP rtmp) { IoBuffer out = IoBuffer.allocate(1024); out.setAutoExpand(true); encodeNotifyOrInvoke(out, invoke, rtmp); return out; } /** * Encode notification event and fill given byte buffer. * * @param out Byte buffer to fill * @param invoke Notification event */ protected void encodeNotifyOrInvoke(IoBuffer out, Notify invoke, RTMP rtmp) { // TODO: tidy up here Output output = new org.red5.io.amf.Output(out); final IServiceCall call = invoke.getCall(); final boolean isPending = (call.getStatus() == Call.STATUS_PENDING); log.debug("Call: {} pending: {}", call, isPending); if (!isPending) { log.debug("Call has been executed, send result"); serializer.serialize(output, call.isSuccess() ? "_result" : "_error"); } else { log.debug("This is a pending call, send request"); // for request we need to use AMF3 for client mode if the connection is AMF3 //if (rtmp.getEncoding() == Encoding.AMF3 && rtmp.getMode() == RTMP.MODE_CLIENT) { // output = new org.red5.io.amf3.Output(out); //} final String action = (call.getServiceName() == null) ? call.getServiceMethodName() : call.getServiceName() + '.' + call.getServiceMethodName(); serializer.serialize(output, action); // seems right } if (invoke instanceof Invoke) { serializer.serialize(output, Integer.valueOf(invoke.getInvokeId())); serializer.serialize(output, invoke.getConnectionParams()); } if (call.getServiceName() == null && "connect".equals(call.getServiceMethodName())) { // response to initial connect, always use AMF0 output = new org.red5.io.amf.Output(out); } else { if (rtmp.getEncoding() == Encoding.AMF3) { output = new org.red5.io.amf3.Output(out); } else { output = new org.red5.io.amf.Output(out); } } if (!isPending && (invoke instanceof Invoke)) { IPendingServiceCall pendingCall = (IPendingServiceCall) call; if (!call.isSuccess()) { log.debug("Call was not successful"); StatusObject status = generateErrorResult(StatusCodes.NC_CALL_FAILED, call.getException()); pendingCall.setResult(status); } Object res = pendingCall.getResult(); log.debug("Writing result: {}", res); serializer.serialize(output, res); } else { log.debug("Writing params"); final Object[] args = call.getArguments(); if (args != null) { for (Object element : args) { serializer.serialize(output, element); } } } if (invoke.getData() != null) { out.setAutoExpand(true); out.put(invoke.getData()); } } /** {@inheritDoc} */ public IoBuffer encodePing(Ping ping) { int len = 6; if (ping.getValue3() != Ping.UNDEFINED) { len += 4; } if (ping.getValue4() != Ping.UNDEFINED) { len += 4; } final IoBuffer out = IoBuffer.allocate(len); out.putShort(ping.getEventType()); out.putInt(ping.getValue2()); if (ping.getValue3() != Ping.UNDEFINED) { out.putInt(ping.getValue3()); } if (ping.getValue4() != Ping.UNDEFINED) { out.putInt(ping.getValue4()); } return out; } /** {@inheritDoc} */ public IoBuffer encodeBytesRead(BytesRead bytesRead) { final IoBuffer out = IoBuffer.allocate(4); out.putInt(bytesRead.getBytesRead()); return out; } /** {@inheritDoc} */ public IoBuffer encodeAggregate(Aggregate aggregate) { final IoBuffer result = aggregate.getData(); return result; } /** {@inheritDoc} */ public IoBuffer encodeAudioData(AudioData audioData) { final IoBuffer result = audioData.getData(); return result; } /** {@inheritDoc} */ public IoBuffer encodeVideoData(VideoData videoData) { final IoBuffer result = videoData.getData(); return result; } /** {@inheritDoc} */ public IoBuffer encodeUnknown(Unknown unknown) { final IoBuffer result = unknown.getData(); return result; } public IoBuffer encodeStreamMetadata(Notify metaData) { final IoBuffer result = metaData.getData(); return result; } /** * Generate error object to return for given exception. * * @param code call * @param error error * @return status object */ protected StatusObject generateErrorResult(String code, Throwable error) { // Construct error object to return String message = ""; while (error != null && error.getCause() != null) { error = error.getCause(); } if (error != null && error.getMessage() != null) { message = error.getMessage(); } StatusObject status = new StatusObject(code, "error", message); if (error instanceof ClientDetailsException) { // Return exception details to client status.setApplication(((ClientDetailsException) error).getParameters()); if (((ClientDetailsException) error).includeStacktrace()) { List stack = new ArrayList(); for (StackTraceElement element : error.getStackTrace()) { stack.add(element.toString()); } status.setAdditional("stacktrace", stack); } } else if (error != null) { status.setApplication(error.getClass().getCanonicalName()); } return status; } /** * Encodes Flex message event. * * @param msg Flex message event * @param rtmp RTMP * @return Encoded data */ public IoBuffer encodeFlexMessage(FlexMessage msg, RTMP rtmp) { IoBuffer out = IoBuffer.allocate(1024); out.setAutoExpand(true); // Unknown byte, always 0? out.put((byte) 0); encodeNotifyOrInvoke(out, msg, rtmp); return out; } public IoBuffer encodeFlexStreamSend(FlexStreamSend msg) { final IoBuffer result = msg.getData(); return result; } private void updateTolerance() { midTolerance = baseTolerance + (long) (baseTolerance * 0.3); highestTolerance = baseTolerance + (long) (baseTolerance * 0.6); } /** * Setter for serializer. * * @param serializer Serializer */ public void setSerializer(org.red5.io.object.Serializer serializer) { this.serializer = serializer; } public void setBaseTolerance(long baseTolerance) { this.baseTolerance = baseTolerance; //update high and low tolerance updateTolerance(); } /** * Setter for dropLiveFuture */ public void setDropLiveFuture(boolean dropLiveFuture) { this.dropLiveFuture = dropLiveFuture; } public long getBaseTolerance() { return baseTolerance; } /** * Set the connection being used with this encoder * * @param conn active connection */ public void setConnection(RTMPConnection conn) { this.conn = conn; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java0000644000175000017500000010501211754302563027325 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.codec; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.amf.AMF; import org.red5.io.amf.Output; import org.red5.io.amf3.AMF3; import org.red5.io.object.DataTypes; import org.red5.io.object.Deserializer; import org.red5.io.object.Input; import org.red5.io.object.Serializer; import org.red5.io.utils.BufferUtils; import org.red5.server.api.IConnection; import org.red5.server.api.IConnection.Encoding; import org.red5.server.api.Red5; import org.red5.server.net.protocol.HandshakeFailedException; import org.red5.server.net.protocol.ProtocolException; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.rtmp.RTMPUtils; import org.red5.server.net.rtmp.event.Abort; import org.red5.server.net.rtmp.event.Aggregate; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.BytesRead; import org.red5.server.net.rtmp.event.ChunkSize; import org.red5.server.net.rtmp.event.ClientBW; import org.red5.server.net.rtmp.event.FlexMessage; import org.red5.server.net.rtmp.event.FlexStreamSend; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.Invoke; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.Ping; import org.red5.server.net.rtmp.event.ServerBW; import org.red5.server.net.rtmp.event.Unknown; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.net.rtmp.message.Constants; import org.red5.server.net.rtmp.message.Header; import org.red5.server.net.rtmp.message.Packet; import org.red5.server.net.rtmp.message.SharedObjectTypeMapping; import org.red5.server.net.rtmp.message.StreamAction; import org.red5.server.service.Call; import org.red5.server.service.PendingCall; import org.red5.server.so.FlexSharedObjectMessage; import org.red5.server.so.ISharedObjectEvent; import org.red5.server.so.ISharedObjectMessage; import org.red5.server.so.SharedObjectMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * RTMP protocol decoder. */ public class RTMPProtocolDecoder implements Constants, IEventDecoder { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(RTMPProtocolDecoder.class); /** * Deserializer */ protected Deserializer deserializer; /** Constructs a new RTMPProtocolDecoder. */ public RTMPProtocolDecoder() { } /** * Setter for deserializer. * * @param deserializer Deserializer */ public void setDeserializer(Deserializer deserializer) { this.deserializer = deserializer; } /** * Decode all available objects in buffer. * * @param state Stores state for the protocol * @param buffer IoBuffer of data to be decoded * @return a list of decoded objects, may be empty if nothing could be * decoded */ public List decodeBuffer(ProtocolState state, IoBuffer buffer) { final List result = new LinkedList(); try { while (true) { final int remaining = buffer.remaining(); if (state.canStartDecoding(remaining)) { state.startDecoding(); } else { break; } final Object decodedObject = decode(state, buffer); if (state.hasDecodedObject()) { if (decodedObject != null) { result.add(decodedObject); } } else if (state.canContinueDecoding()) { continue; } else { break; } if (!buffer.hasRemaining()) { break; } } } catch (HandshakeFailedException hfe) { // patched by Victor to clear buffer if something is wrong in protocol decoding. buffer.clear(); // get the connection and close it IConnection conn = Red5.getConnectionLocal(); if (conn != null) { conn.close(); } else { log.error("Handshake validation failed but no current connection!?"); } return null; } catch (Exception ex) { // Exception handling is patched by Victor - we catch any exception in the decoding // Then clear the buffer to eliminate memory leaks when we can't parse protocol // Also close Connection because we can't parse data from it log.error("Error decoding buffer", ex); buffer.clear(); // get the connection and close it IConnection conn = Red5.getConnectionLocal(); if (conn != null) { log.warn("Closing connection because decoding failed: {}", conn); conn.close(); } else { log.error("Decoding buffer failed but no current connection!?"); } return null; } finally { buffer.compact(); } return result; } /** * Decodes the buffer data * * @param state Stores state for the protocol, ProtocolState is just a marker * interface * @param in IoBuffer of data to be decoded * @return one of three possible values. null : the object could not be * decoded, or some data was skipped, just continue. ProtocolState : * the decoder was unable to decode the whole object, refer to the * protocol state Object : something was decoded, continue * @throws Exception on error */ public Object decode(ProtocolState state, IoBuffer in) throws ProtocolException { int start = in.position(); log.trace("Start: {}", start); try { final RTMP rtmp = (RTMP) state; switch (rtmp.getState()) { case RTMP.STATE_CONNECTED: return decodePacket(rtmp, in); case RTMP.STATE_CONNECT: case RTMP.STATE_HANDSHAKE: return decodeHandshake(rtmp, in); case RTMP.STATE_ERROR: // attempt to correct error default: return null; } } catch (ProtocolException pe) { // Raise to caller unmodified throw pe; } catch (RuntimeException e) { throw new ProtocolException("Error during decoding", e); } } /** * Decodes handshake message. * * @param rtmp RTMP protocol state * @param in IoBuffer * @return IoBuffer */ public IoBuffer decodeHandshake(RTMP rtmp, IoBuffer in) { log.debug("decodeHandshake - rtmp: {} buffer: {}", rtmp, in); final int remaining = in.remaining(); if (rtmp.getState() == RTMP.STATE_CONNECT) { if (remaining < HANDSHAKE_SIZE + 1) { log.debug("Handshake init too small, buffering. remaining: {}", remaining); rtmp.bufferDecoding(HANDSHAKE_SIZE + 1); } else { final IoBuffer hs = IoBuffer.allocate(HANDSHAKE_SIZE); in.get(); // skip the header byte BufferUtils.put(hs, in, HANDSHAKE_SIZE); hs.flip(); rtmp.setState(RTMP.STATE_HANDSHAKE); return hs; } } else if (rtmp.getState() == RTMP.STATE_HANDSHAKE) { log.debug("Handshake reply"); if (remaining < HANDSHAKE_SIZE) { log.debug("Handshake reply too small, buffering. remaining: {}", remaining); rtmp.bufferDecoding(HANDSHAKE_SIZE); } else { in.skip(HANDSHAKE_SIZE); rtmp.setState(RTMP.STATE_CONNECTED); rtmp.continueDecoding(); } } return null; } /** * Decodes packet. * * @param rtmp RTMP protocol state * @param in IoBuffer * @return IoBuffer */ public Packet decodePacket(RTMP rtmp, IoBuffer in) { log.debug("decodePacket - rtmp: {} buffer: {}", rtmp, in); final int remaining = in.remaining(); // We need at least one byte if (remaining < 1) { rtmp.bufferDecoding(1); return null; } final int position = in.position(); byte headerByte = in.get(); int headerValue; int byteCount; if ((headerByte & 0x3f) == 0) { // Two byte header if (remaining < 2) { in.position(position); rtmp.bufferDecoding(2); return null; } headerValue = (headerByte & 0xff) << 8 | (in.get() & 0xff); byteCount = 2; } else if ((headerByte & 0x3f) == 1) { // Three byte header if (remaining < 3) { in.position(position); rtmp.bufferDecoding(3); return null; } headerValue = (headerByte & 0xff) << 16 | (in.get() & 0xff) << 8 | (in.get() & 0xff); byteCount = 3; } else { // Single byte header headerValue = headerByte & 0xff; byteCount = 1; } final int channelId = RTMPUtils.decodeChannelId(headerValue, byteCount); if (channelId < 0) { throw new ProtocolException("Bad channel id: " + channelId); } // Get the header size and length int headerLength = RTMPUtils.getHeaderLength(RTMPUtils.decodeHeaderSize(headerValue, byteCount)); headerLength += byteCount - 1; if (headerLength + byteCount - 1 > remaining) { log.debug("Header too small, buffering. remaining: {}", remaining); in.position(position); rtmp.bufferDecoding(headerLength + byteCount - 1); return null; } // Move the position back to the start in.position(position); Header lastHeader = rtmp.getLastReadHeader(channelId); final Header header = decodeHeader(in, lastHeader); if (header == null) { throw new ProtocolException("Header is null, check for error"); } rtmp.setLastReadHeader(channelId, header); // Check to see if this is a new packets or continue decoding an // existing one. Packet packet = rtmp.getLastReadPacket(channelId); if (packet == null) { packet = new Packet(header.clone()); rtmp.setLastReadPacket(channelId, packet); } final IoBuffer buf = packet.getData(); final int readRemaining = header.getSize() - buf.position(); final int chunkSize = rtmp.getReadChunkSize(); final int readAmount = (readRemaining > chunkSize) ? chunkSize : readRemaining; if (in.remaining() < readAmount) { log.debug("Chunk too small, buffering ({},{})", in.remaining(), readAmount); // skip the position back to the start in.position(position); rtmp.bufferDecoding(headerLength + readAmount); return null; } BufferUtils.put(buf, in, readAmount); if (buf.position() < header.getSize()) { rtmp.continueDecoding(); return null; } // Check workaround for SN-19 to find cause for BufferOverflowException if (buf.position() > header.getSize()) { log.warn("Packet size expanded from {} to {} ({})", new Object[] { (header.getSize()), buf.position(), header }); } buf.flip(); try { final IRTMPEvent message = decodeMessage(rtmp, packet.getHeader(), buf); message.setHeader(packet.getHeader()); // Unfortunately flash will, especially when resetting a video stream with a new key frame, sometime // send an earlier time stamp. To avoid dropping it, we just give it the minimal increment since the // last message. But to avoid relative time stamps being mis-computed, we don't reset the header we stored. final Header lastReadHeader = rtmp.getLastReadPacketHeader(channelId); if (lastReadHeader != null && (message instanceof AudioData || message instanceof VideoData) && RTMPUtils.compareTimestamps(lastReadHeader.getTimer(), packet.getHeader().getTimer()) >= 0) { log.trace("Non-monotonically increasing timestamps; type: {}; adjusting to {}; ts: {}; last: {}", new Object[] { header.getDataType(), lastReadHeader.getTimer() + 1, header.getTimer(), lastReadHeader.getTimer() }); message.setTimestamp(lastReadHeader.getTimer() + 1); } else { message.setTimestamp(header.getTimer()); } rtmp.setLastReadPacketHeader(channelId, packet.getHeader()); packet.setMessage(message); if (message instanceof ChunkSize) { ChunkSize chunkSizeMsg = (ChunkSize) message; rtmp.setReadChunkSize(chunkSizeMsg.getSize()); } else if (message instanceof Abort) { log.debug("Abort packet detected"); // The client is aborting a message; reset the packet // because the next chunk on that stream will start a new packet. Abort abort = (Abort) message; rtmp.setLastReadPacket(abort.getChannelId(), null); packet = null; } if (packet != null && packet.getHeader().isGarbage()) { // discard this packet; this gets rid of the garbage audio data FP inserts log.trace("Dropping garbage packet: {}, {}", packet, packet.getHeader()); packet = null; } else { // collapse the time stamps on the last packet so that it works // right for chunk type 3 later lastHeader = rtmp.getLastReadHeader(channelId); lastHeader.setTimerBase(header.getTimer()); } } finally { rtmp.setLastReadPacket(channelId, null); } return packet; } /** * Decodes packet header. * * @param in Input IoBuffer * @param lastHeader Previous header * @return Decoded header */ public Header decodeHeader(IoBuffer in, Header lastHeader) { log.debug("decodeHeader - lastHeader: {} buffer: {}", lastHeader, in); byte headerByte = in.get(); int headerValue; int byteCount = 1; if ((headerByte & 0x3f) == 0) { // Two byte header headerValue = (headerByte & 0xff) << 8 | (in.get() & 0xff); byteCount = 2; } else if ((headerByte & 0x3f) == 1) { // Three byte header headerValue = (headerByte & 0xff) << 16 | (in.get() & 0xff) << 8 | (in.get() & 0xff); byteCount = 3; } else { // Single byte header headerValue = headerByte & 0xff; byteCount = 1; } final int channelId = RTMPUtils.decodeChannelId(headerValue, byteCount); final int headerSize = RTMPUtils.decodeHeaderSize(headerValue, byteCount); Header header = new Header(); header.setChannelId(channelId); header.setIsGarbage(false); if (headerSize != HEADER_NEW && lastHeader == null) { log.error("Last header null not new, headerSize: {}, channelId {}", headerSize, channelId); //this will trigger an error status, which in turn will disconnect the "offending" flash player //preventing a memory leak and bringing the whole server to its knees return null; } int timeValue; switch (headerSize) { case HEADER_NEW: // an absolute time value timeValue = RTMPUtils.readUnsignedMediumInt(in); header.setSize(RTMPUtils.readUnsignedMediumInt(in)); header.setDataType(in.get()); header.setStreamId(RTMPUtils.readReverseInt(in)); if (timeValue == 0xffffff) { timeValue = in.getInt(); header.setExtendedTimestamp(timeValue); } header.setTimerBase(timeValue); header.setTimerDelta(0); break; case HEADER_SAME_SOURCE: // a delta time value timeValue = RTMPUtils.readUnsignedMediumInt(in); header.setSize(RTMPUtils.readUnsignedMediumInt(in)); header.setDataType(in.get()); header.setStreamId(lastHeader.getStreamId()); if (timeValue == 0xffffff) { timeValue = in.getInt(); header.setExtendedTimestamp(timeValue); } else if (timeValue == 0 && header.getDataType() == TYPE_AUDIO_DATA) { header.setIsGarbage(true); log.trace("Audio with zero delta; setting to garbage; ChannelId: {}; DataType: {}; HeaderSize: {}", new Object[] { header.getChannelId(), header.getDataType(), headerSize }); } header.setTimerBase(lastHeader.getTimerBase()); header.setTimerDelta(timeValue); break; case HEADER_TIMER_CHANGE: // a delta time value timeValue = RTMPUtils.readUnsignedMediumInt(in); header.setSize(lastHeader.getSize()); header.setDataType(lastHeader.getDataType()); header.setStreamId(lastHeader.getStreamId()); if (timeValue == 0xffffff) { timeValue = in.getInt(); header.setExtendedTimestamp(timeValue); } else if (timeValue == 0 && header.getDataType() == TYPE_AUDIO_DATA) { header.setIsGarbage(true); log.trace("Audio with zero delta; setting to garbage; ChannelId: {}; DataType: {}; HeaderSize: {}", new Object[] { header.getChannelId(), header.getDataType(), headerSize }); } header.setTimerBase(lastHeader.getTimerBase()); header.setTimerDelta(timeValue); break; case HEADER_CONTINUE: header.setSize(lastHeader.getSize()); header.setDataType(lastHeader.getDataType()); header.setStreamId(lastHeader.getStreamId()); header.setTimerBase(lastHeader.getTimerBase()); header.setTimerDelta(lastHeader.getTimerDelta()); if (lastHeader.getExtendedTimestamp() != 0) { timeValue = in.getInt(); header.setExtendedTimestamp(timeValue); log.trace("HEADER_CONTINUE with extended timestamp: {}", timeValue); } break; default: log.error("Unexpected header size: {}", headerSize); return null; } log.trace("CHUNK, D, {}, {}", header, headerSize); return header; } /** * Decodes RTMP message event. * * @param rtmp RTMP protocol state * @param header RTMP header * @param in Input IoBuffer * @return RTMP event */ public IRTMPEvent decodeMessage(RTMP rtmp, Header header, IoBuffer in) { IRTMPEvent message; byte dataType = header.getDataType(); switch (dataType) { case TYPE_CHUNK_SIZE: message = decodeChunkSize(in); break; case TYPE_ABORT: message = decodeAbort(in); break; case TYPE_INVOKE: message = decodeInvoke(in, rtmp); break; case TYPE_NOTIFY: if (header.getStreamId() == 0) { message = decodeNotify(in, header, rtmp); } else { message = decodeStreamMetadata(in, rtmp); } break; case TYPE_PING: message = decodePing(in); break; case TYPE_BYTES_READ: message = decodeBytesRead(in); break; case TYPE_AUDIO_DATA: message = decodeAudioData(in); message.setSourceType(Constants.SOURCE_TYPE_LIVE); break; case TYPE_VIDEO_DATA: message = decodeVideoData(in); message.setSourceType(Constants.SOURCE_TYPE_LIVE); break; case TYPE_FLEX_SHARED_OBJECT: // represents an SO in an AMF3 container message = decodeFlexSharedObject(in, rtmp); break; case TYPE_SHARED_OBJECT: message = decodeSharedObject(in, rtmp); break; case TYPE_SERVER_BANDWIDTH: message = decodeServerBW(in); break; case TYPE_CLIENT_BANDWIDTH: message = decodeClientBW(in); break; case TYPE_FLEX_MESSAGE: message = decodeFlexMessage(in, rtmp); break; case TYPE_FLEX_STREAM_SEND: message = decodeFlexStreamSend(in); break; case TYPE_AGGREGATE: message = decodeAggregate(in); break; default: log.warn("Unknown object type: {}", dataType); message = decodeUnknown(dataType, in); break; } return message; } public IRTMPEvent decodeAbort(IoBuffer in) { return new Abort(in.getInt()); } /** * Decodes server bandwidth. * * @param in IoBuffer * @return RTMP event */ private IRTMPEvent decodeServerBW(IoBuffer in) { return new ServerBW(in.getInt()); } /** * Decodes client bandwidth. * * @param in * Byte buffer * @return RTMP event */ private IRTMPEvent decodeClientBW(IoBuffer in) { return new ClientBW(in.getInt(), in.get()); } /** {@inheritDoc} */ public Unknown decodeUnknown(byte dataType, IoBuffer in) { return new Unknown(dataType, in); } /** {@inheritDoc} */ public Aggregate decodeAggregate(IoBuffer in) { return new Aggregate(in); } /** {@inheritDoc} */ public ChunkSize decodeChunkSize(IoBuffer in) { return new ChunkSize(in.getInt()); } /** {@inheritDoc} */ public ISharedObjectMessage decodeFlexSharedObject(IoBuffer in, RTMP rtmp) { byte encoding = in.get(); Input input; if (encoding == 0) { input = new org.red5.io.amf.Input(in); } else if (encoding == 3) { input = new org.red5.io.amf3.Input(in); } else { throw new RuntimeException("Unknown SO encoding: " + encoding); } String name = input.getString(); // Read version of SO to modify int version = in.getInt(); // Read persistence informations boolean persistent = in.getInt() == 2; // Skip unknown bytes in.skip(4); // create our shared object message final SharedObjectMessage so = new FlexSharedObjectMessage(null, name, version, persistent); doDecodeSharedObject(so, in, input); return so; } /** {@inheritDoc} */ public ISharedObjectMessage decodeSharedObject(IoBuffer in, RTMP rtmp) { final Input input = new org.red5.io.amf.Input(in); String name = input.getString(); // Read version of SO to modify int version = in.getInt(); // Read persistence informations boolean persistent = in.getInt() == 2; // Skip unknown bytes in.skip(4); // create our shared object message final SharedObjectMessage so = new SharedObjectMessage(null, name, version, persistent); doDecodeSharedObject(so, in, input); return so; } /** * Perform the actual decoding of the shared object contents. * * @param so * @param in * @param input */ protected void doDecodeSharedObject(SharedObjectMessage so, IoBuffer in, Input input) { // Parse request body Input amf3Input = new org.red5.io.amf3.Input(in); while (in.hasRemaining()) { final ISharedObjectEvent.Type type = SharedObjectTypeMapping.toType(in.get()); if (type == null) { in.skip(in.remaining()); return; } String key = null; Object value = null; // if(log.isDebugEnabled()) // log.debug("type: "+SharedObjectTypeMapping.toString(type)); // SharedObjectEvent event = new SharedObjectEvent(,null,null); final int length = in.getInt(); if (type == ISharedObjectEvent.Type.CLIENT_STATUS) { // Status code key = input.getString(); // Status level value = input.getString(); } else if (type == ISharedObjectEvent.Type.CLIENT_UPDATE_DATA) { key = null; // Map containing new attribute values final Map map = new HashMap(); final int start = in.position(); while (in.position() - start < length) { String tmp = input.getString(); map.put(tmp, deserializer.deserialize(input, Object.class)); } value = map; } else if (type != ISharedObjectEvent.Type.SERVER_SEND_MESSAGE && type != ISharedObjectEvent.Type.CLIENT_SEND_MESSAGE) { if (length > 0) { key = input.getString(); if (length > key.length() + 2) { // determine if the object is encoded with amf3 byte objType = in.get(); in.position(in.position() - 1); Input propertyInput; if (objType == AMF.TYPE_AMF3_OBJECT && !(input instanceof org.red5.io.amf3.Input)) { // The next parameter is encoded using AMF3 propertyInput = amf3Input; } else { // The next parameter is encoded using AMF0 propertyInput = input; } value = deserializer.deserialize(propertyInput, Object.class); } } } else { final int start = in.position(); // the "send" event seems to encode the handler name // as complete AMF string including the string type byte key = deserializer.deserialize(input, String.class); // read parameters final List list = new LinkedList(); // while loop changed for JIRA CODECS-9 while (in.position() - start < length) { byte objType = in.get(); in.position(in.position() - 1); // determine if the object is encoded with amf3 Input propertyInput; if (objType == AMF.TYPE_AMF3_OBJECT && !(input instanceof org.red5.io.amf3.Input)) { // The next parameter is encoded using AMF3 propertyInput = amf3Input; } else { // The next parameter is encoded using AMF0 propertyInput = input; } Object tmp = deserializer.deserialize(propertyInput, Object.class); list.add(tmp); } value = list; } so.addEvent(type, key, value); } } /** {@inheritDoc} */ public Notify decodeNotify(IoBuffer in, RTMP rtmp) { return decodeNotify(in, null, rtmp); } public Notify decodeNotify(IoBuffer in, Header header, RTMP rtmp) { return decodeNotifyOrInvoke(new Notify(), in, header, rtmp); } /** {@inheritDoc} */ public Invoke decodeInvoke(IoBuffer in, RTMP rtmp) { return (Invoke) decodeNotifyOrInvoke(new Invoke(), in, null, rtmp); } /** * Checks if the passed action is a reserved stream method. * * @param action * Action to check * @return true if passed action is a reserved stream method, * false otherwise */ private boolean isStreamCommand(String action) { switch (StreamAction.getEnum(action)) { case CREATE_STREAM: case DELETE_STREAM: case RELEASE_STREAM: case PUBLISH: case PLAY: case PLAY2: case SEEK: case PAUSE: case PAUSE_RAW: case CLOSE_STREAM: case RECEIVE_VIDEO: case RECEIVE_AUDIO: return true; default: log.debug("Stream action {} is not a recognized command", action); return false; } } /** * Decodes notification event. * * @param notify * Notify event * @param in * Byte buffer * @param header * Header * @param rtmp * RTMP protocol state * @return Notification event */ @SuppressWarnings({ "unchecked" }) protected Notify decodeNotifyOrInvoke(Notify notify, IoBuffer in, Header header, RTMP rtmp) { final Encoding encoding = rtmp.getEncoding(); // TODO: we should use different code depending on server or client mode int start = in.position(); Input input; // for response, the action string and invokeId is always encoded as AMF0 // we use the first byte to decide which encoding to use. byte tmp = in.get(); in.position(start); if (encoding == Encoding.AMF3 && tmp == AMF.TYPE_AMF3_OBJECT) { input = new org.red5.io.amf3.Input(in); ((org.red5.io.amf3.Input) input).enforceAMF3(); } else { input = new org.red5.io.amf.Input(in); } String action = deserializer.deserialize(input, String.class); log.info("Action {}", action); //throw a runtime exception if there is no action if (action == null) { //TODO replace this with something better as time permits throw new RuntimeException("Action was null"); } //TODO Handle NetStream.send? Where and how? if (!(notify instanceof Invoke) && rtmp != null && header != null && header.getStreamId() != 0 && !isStreamCommand(action)) { // don't decode "NetStream.send" requests in.position(start); notify.setData(in.asReadOnlyBuffer()); return notify; } if (header == null || header.getStreamId() == 0) { int invokeId = deserializer. deserialize(input, Number.class).intValue(); notify.setInvokeId(invokeId); } // now go back to the actual encoding to decode parameters if (encoding == Encoding.AMF3) { input = new org.red5.io.amf3.Input(in); ((org.red5.io.amf3.Input) input).enforceAMF3(); } else { input = new org.red5.io.amf.Input(in); } Object[] params = new Object[] {}; if (in.hasRemaining()) { List paramList = new ArrayList(); final Object obj = deserializer.deserialize(input, Object.class); if (obj instanceof Map) { // Before the actual parameters we sometimes (connect) get a map // of parameters, this is usually null, but if set should be // passed to the connection object. final Map connParams = (Map) obj; notify.setConnectionParams(connParams); } else if (obj != null) { paramList.add(obj); } while (in.hasRemaining()) { paramList.add(deserializer.deserialize(input, Object.class)); } params = paramList.toArray(); if (log.isDebugEnabled()) { log.debug("Num params: {}", paramList.size()); for (int i = 0; i < params.length; i++) { log.info(" > {}: {}", i, params[i]); } } } final int dotIndex = action.lastIndexOf('.'); String serviceName = (dotIndex == -1) ? null : action.substring(0, dotIndex); //pull off the prefixes since java doesnt allow this on a method name if (serviceName != null && (serviceName.startsWith("@") || serviceName.startsWith("|"))) { serviceName = serviceName.substring(1); } String serviceMethod = (dotIndex == -1) ? action : action.substring(dotIndex + 1, action.length()); //pull off the prefixes since java doesnt allow this on a method name if (serviceMethod.startsWith("@") || serviceMethod.startsWith("|")) { serviceMethod = serviceMethod.substring(1); } if (notify instanceof Invoke) { PendingCall call = new PendingCall(serviceName, serviceMethod, params); ((Invoke) notify).setCall(call); } else { Call call = new Call(serviceName, serviceMethod, params); notify.setCall(call); } return notify; } /** * Decodes ping event. * * @param in IoBuffer * @return Ping event */ public Ping decodePing(IoBuffer in) { final Ping ping = new Ping(); ping.setDebug(in.getHexDump()); ping.setEventType(in.getShort()); ping.setValue2(in.getInt()); if (in.hasRemaining()) { ping.setValue3(in.getInt()); } if (in.hasRemaining()) { ping.setValue4(in.getInt()); } return ping; } /** {@inheritDoc} */ public BytesRead decodeBytesRead(IoBuffer in) { return new BytesRead(in.getInt()); } /** {@inheritDoc} */ public AudioData decodeAudioData(IoBuffer in) { return new AudioData(in.asReadOnlyBuffer()); } /** {@inheritDoc} */ public VideoData decodeVideoData(IoBuffer in) { return new VideoData(in.asReadOnlyBuffer()); } /** * Decodes stream meta data, to include onMetaData, onCuePoint, and onFI. * * @param in * @param rtmp * @return Notify */ @SuppressWarnings("unchecked") public Notify decodeStreamMetadata(IoBuffer in, RTMP rtmp) { Input input; //we will make a pre-emptive copy of the incoming buffer here to //prevent issues that seem to occur fairly often IoBuffer copy = in.duplicate(); if (rtmp.getEncoding() == Encoding.AMF0) { input = new org.red5.io.amf.Input(copy); } else { org.red5.io.amf3.Input.RefStorage refStorage = new org.red5.io.amf3.Input.RefStorage(); input = new org.red5.io.amf3.Input(copy, refStorage); } //get the first datatype byte dataType = input.readDataType(); if (dataType == DataTypes.CORE_STRING) { String setData = input.readString(String.class); if ("@setDataFrame".equals(setData)) { //get the second datatype byte dataType2 = input.readDataType(); log.debug("Dataframe method type: {}", dataType2); String onCueOrOnMeta = input.readString(String.class); //get the params datatype byte object = input.readDataType(); log.debug("Dataframe params type: {}", object); Map params; if (object == DataTypes.CORE_MAP) { // The params are sent as a Mixed-Array. This is needed // to support the RTMP publish provided by ffmpeg/xuggler params = (Map) input.readMap(deserializer, null); } else { // Read the params as a standard object params = (Map) input.readObject(deserializer, Object.class); } log.debug("Dataframe: {} params: {}", onCueOrOnMeta, params.toString()); IoBuffer buf = IoBuffer.allocate(1024); buf.setAutoExpand(true); Output out = new Output(buf); out.writeString(onCueOrOnMeta); out.writeMap(params, new Serializer()); buf.flip(); return new Notify(buf); } else if ("onFI".equals(setData)) { // The onFI request contains 2 items relative to the publishing client application // sd = system date (12-07-2011) // st = system time (09:11:33.387) byte object = input.readDataType(); log.debug("onFI params type: {}", object); Map params; if (object == DataTypes.CORE_MAP) { // The params are sent as a Mixed-Array params = (Map) input.readMap(deserializer, null); } else { // Read the params as a standard object params = (Map) input.readObject(deserializer, Object.class); } log.debug("onFI params: {}", params.toString()); } else { log.info("Unhandled request: {}", setData); if (log.isDebugEnabled()) { byte object = input.readDataType(); log.debug("Params type: {}", object); if (object == DataTypes.CORE_MAP) { Map params = (Map) input.readMap(deserializer, null); log.debug("Params: {}", params.toString()); } else { log.debug("The unknown request was did not provide a parameter map"); } } } } return new Notify(in.asReadOnlyBuffer()); } /** * Decodes FlexMessage event. * * @param in IoBuffer * @param rtmp RTMP protocol state * @return FlexMessage event */ public FlexMessage decodeFlexMessage(IoBuffer in, RTMP rtmp) { // TODO: Unknown byte, probably encoding as with Flex SOs? byte flexByte = in.get(); log.trace("Flex byte: {}", flexByte); // Encoding of message params can be mixed - some params may be in AMF0, others in AMF3, // but according to AMF3 spec, we should collect AMF3 references for the whole message body (through all params) org.red5.io.amf3.Input.RefStorage refStorage = new org.red5.io.amf3.Input.RefStorage(); Input input = new org.red5.io.amf.Input(in); String action = deserializer.deserialize(input, String.class); int invokeId = deserializer. deserialize(input, Number.class).intValue(); FlexMessage msg = new FlexMessage(); msg.setInvokeId(invokeId); Object[] params = new Object[] {}; if (in.hasRemaining()) { ArrayList paramList = new ArrayList(); final Object obj = deserializer.deserialize(input, Object.class); if (obj != null) { paramList.add(obj); } while (in.hasRemaining()) { // Check for AMF3 encoding of parameters byte objectEncodingType = in.get(); in.position(in.position() - 1); log.debug("Object encoding: {}", objectEncodingType); switch (objectEncodingType) { case AMF.TYPE_AMF3_OBJECT: case AMF3.TYPE_VECTOR_NUMBER: case AMF3.TYPE_VECTOR_OBJECT: // The next parameter is encoded using AMF3 input = new org.red5.io.amf3.Input(in, refStorage); // Vectors with number and object have to have AMF3 forced ((org.red5.io.amf3.Input) input).enforceAMF3(); break; case AMF3.TYPE_VECTOR_INT: case AMF3.TYPE_VECTOR_UINT: // The next parameter is encoded using AMF3 input = new org.red5.io.amf3.Input(in, refStorage); break; default: // The next parameter is encoded using AMF0 input = new org.red5.io.amf.Input(in); } paramList.add(deserializer.deserialize(input, Object.class)); } params = paramList.toArray(); if (log.isDebugEnabled()) { log.debug("Parameter count: {}", paramList.size()); for (int i = 0; i < params.length; i++) { log.info(" > {}: {}", i, params[i]); } } } final int dotIndex = action.lastIndexOf('.'); String serviceName = (dotIndex == -1) ? null : action.substring(0, dotIndex); String serviceMethod = (dotIndex == -1) ? action : action.substring(dotIndex + 1, action.length()); log.debug("Service name: {} method: {}", serviceName, serviceMethod); PendingCall call = new PendingCall(serviceName, serviceMethod, params); msg.setCall(call); return msg; } public FlexStreamSend decodeFlexStreamSend(IoBuffer in) { return new FlexStreamSend(in.asReadOnlyBuffer()); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/codec/RTMPMinaProtocolEncoder.java0000644000175000017500000000604011754302563030145 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.codec; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecException; import org.apache.mina.filter.codec.ProtocolEncoderAdapter; import org.apache.mina.filter.codec.ProtocolEncoderOutput; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.rtmp.RTMPConnection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Mina protocol encoder for RTMP. */ public class RTMPMinaProtocolEncoder extends ProtocolEncoderAdapter { protected static Logger log = LoggerFactory.getLogger(RTMPMinaProtocolEncoder.class); private RTMPProtocolEncoder encoder = new RTMPProtocolEncoder(); /** {@inheritDoc} */ public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws ProtocolCodecException { final ProtocolState state = (ProtocolState) session.getAttribute(ProtocolState.SESSION_KEY); // pass the connection to the encoder for its use encoder.setConnection((RTMPConnection) session.getAttribute(RTMPConnection.RTMP_CONNECTION_KEY)); try { // We need to synchronize on the output and flush the generated data to prevent two packages to the same channel // to be sent in different order thus resulting in wrong headers being generated. final IoBuffer buf = encoder.encode(state, message); if (buf != null) { out.write(buf); out.mergeAll(); out.flush(); } else { log.trace("Response buffer was null after encoding"); } } catch (Exception ex) { log.error("Exception during encode", ex); } } /** * Sets an RTMP protocol encoder * @param encoder the RTMP encoder */ public void setEncoder(RTMPProtocolEncoder encoder) { this.encoder = encoder; } /** * Returns an RTMP encoder * @return RTMP encoder */ public RTMPProtocolEncoder getEncoder() { return encoder; } /** * Setter for serializer. * * @param serializer Serializer */ public void setSerializer(org.red5.io.object.Serializer serializer) { encoder.setSerializer(serializer); } /** * Setter for baseTolerance * */ public void setBaseTolerance(long baseTolerance) { encoder.setBaseTolerance(baseTolerance); } /** * Setter for dropLiveFuture * */ public void setDropLiveFuture(boolean dropLiveFuture) { encoder.setDropLiveFuture(dropLiveFuture); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/codec/IEventEncoder.java0000644000175000017500000000775411706617130026237 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp.codec; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.net.rtmp.event.Aggregate; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.BytesRead; import org.red5.server.net.rtmp.event.ChunkSize; import org.red5.server.net.rtmp.event.Invoke; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.Ping; import org.red5.server.net.rtmp.event.Unknown; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.so.ISharedObjectMessage; /** * Encodes events to byte buffer. */ public interface IEventEncoder { /** * Encodes Notify event to byte buffer. * * @param notify Notify event * @param rtmp RTMP protocol state * @return Byte buffer */ public abstract IoBuffer encodeNotify(Notify notify, RTMP rtmp); /** * Encodes Invoke event to byte buffer. * * @param invoke Invoke event * @param rtmp RTMP protocol state * @return Byte buffer */ public abstract IoBuffer encodeInvoke(Invoke invoke, RTMP rtmp); /** * Encodes Ping event to byte buffer. * * @param ping Ping event * @return Byte buffer */ public abstract IoBuffer encodePing(Ping ping); /** * Encodes BytesRead event to byte buffer. * * @param streamBytesRead BytesRead event * @return Byte buffer */ public abstract IoBuffer encodeBytesRead(BytesRead streamBytesRead); /** * Encodes Aggregate event to byte buffer. * * @param aggregate Aggregate event * @return Byte buffer */ public abstract IoBuffer encodeAggregate(Aggregate aggregate); /** * Encodes AudioData event to byte buffer. * * @param audioData AudioData event * @return Byte buffer */ public abstract IoBuffer encodeAudioData(AudioData audioData); /** * Encodes VideoData event to byte buffer. * * @param videoData VideoData event * @return Byte buffer */ public abstract IoBuffer encodeVideoData(VideoData videoData); /** * Encodes Unknown event to byte buffer. * * @param unknown Unknown event * @return Byte buffer */ public abstract IoBuffer encodeUnknown(Unknown unknown); /** * Encodes ChunkSize event to byte buffer. * * @param chunkSize ChunkSize event * @return Byte buffer */ public abstract IoBuffer encodeChunkSize(ChunkSize chunkSize); /** * Encodes SharedObjectMessage event to byte buffer. * * @param so ISharedObjectMessage event * @param rtmp RTMP protocol state * @return Byte buffer */ public abstract IoBuffer encodeSharedObject(ISharedObjectMessage so, RTMP rtmp); /** * Encodes SharedObjectMessage event to byte buffer using AMF3 encoding. * * @param so ISharedObjectMessage event * @param rtmp RTMP protocol state * @return Byte buffer */ public IoBuffer encodeFlexSharedObject(ISharedObjectMessage so, RTMP rtmp); } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/RTMPMinaIoHandler.java0000644000175000017500000001736311755465152025653 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFactory; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.logging.LoggingFilter; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.rtmpe.RTMPEIoFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * Handles all RTMP protocol events fired by the MINA framework. */ public class RTMPMinaIoHandler extends IoHandlerAdapter implements ApplicationContextAware { private static Logger log = LoggerFactory.getLogger(RTMPMinaIoHandler.class); /** * RTMP events handler */ protected IRTMPHandler handler; /** * Application context */ protected ApplicationContext appCtx; protected IRTMPConnManager rtmpConnManager; /** {@inheritDoc} */ @Override public void sessionCreated(IoSession session) throws Exception { log.debug("Session created"); // moved protocol state from connection object to RTMP object RTMP rtmp = new RTMP(); session.setAttribute(ProtocolState.SESSION_KEY, rtmp); //add rtmpe filter session.getFilterChain().addFirst("rtmpeFilter", new RTMPEIoFilter()); //add protocol filter next ProtocolCodecFactory codecFactory = (ProtocolCodecFactory) appCtx.getBean("rtmpCodecFactory"); session.getFilterChain().addLast("protocolFilter", new ProtocolCodecFilter(codecFactory)); if (log.isTraceEnabled()) { session.getFilterChain().addLast("logger", new LoggingFilter()); } //create a connection RTMPMinaConnection conn = createRTMPMinaConnection(); conn.setIoSession(session); conn.setState(rtmp); //add the connection session.setAttribute(RTMPConnection.RTMP_CONNECTION_KEY, conn); //add the inbound handshake session.setAttribute(RTMPConnection.RTMP_HANDSHAKE, new InboundHandshake()); } /** {@inheritDoc} */ @Override public void sessionOpened(IoSession session) throws Exception { log.debug("Session opened"); super.sessionOpened(session); // get protocol state RTMP rtmp = (RTMP) session.getAttribute(ProtocolState.SESSION_KEY); handler.connectionOpened((RTMPMinaConnection) session.getAttribute(RTMPConnection.RTMP_CONNECTION_KEY), rtmp); } /** {@inheritDoc} */ @Override public void sessionClosed(IoSession session) throws Exception { log.debug("Session closed"); RTMP rtmp = (RTMP) session.removeAttribute(ProtocolState.SESSION_KEY); log.debug("RTMP state: {}", rtmp); RTMPMinaConnection conn = (RTMPMinaConnection) session.removeAttribute(RTMPConnection.RTMP_CONNECTION_KEY); try { conn.sendPendingServiceCallsCloseError(); // fire-off closed event handler.connectionClosed(conn, rtmp); // clear any session attributes we may have previously set // TODO: verify this cleanup code is necessary. The session is over and will be garbage collected surely? session.removeAttribute(RTMPConnection.RTMP_HANDSHAKE); session.removeAttribute(RTMPConnection.RTMPE_CIPHER_IN); session.removeAttribute(RTMPConnection.RTMPE_CIPHER_OUT); } finally { // DW we *always* remove the connection from the RTMP manager even if unexpected exception gets thrown e.g. by handler.connectionClosed // Otherwise connection stays around forever, and everything it references e.g. Client, ... rtmpConnManager.removeConnection(conn.getId()); } } /** * Handle raw buffer receiving event. * * @param in * Data buffer * @param session * I/O session, that is, connection between two endpoints */ protected void rawBufferRecieved(IoBuffer in, IoSession session) { log.debug("rawBufferRecieved: {}", in); final RTMP rtmp = (RTMP) session.getAttribute(ProtocolState.SESSION_KEY); log.debug("state: {}", rtmp); final RTMPMinaConnection conn = (RTMPMinaConnection) session.getAttribute(RTMPConnection.RTMP_CONNECTION_KEY); RTMPHandshake handshake = (RTMPHandshake) session.getAttribute(RTMPConnection.RTMP_HANDSHAKE); if (handshake != null) { if (rtmp.getState() != RTMP.STATE_HANDSHAKE) { log.warn("Raw buffer after handshake, something odd going on"); } log.debug("Handshake - server phase 1 - size: {}", in.remaining()); IoBuffer out = handshake.doHandshake(in); if (out != null) { log.debug("Output: {}", out); session.write(out); //if we are connected and doing encryption, add the ciphers if (rtmp.getState() == RTMP.STATE_CONNECTED) { // remove handshake from session now that we are connected // if we are using encryption then put the ciphers in the session if (handshake.getHandshakeType() == RTMPConnection.RTMP_ENCRYPTED) { log.debug("Adding ciphers to the session"); session.setAttribute(RTMPConnection.RTMPE_CIPHER_IN, handshake.getCipherIn()); session.setAttribute(RTMPConnection.RTMPE_CIPHER_OUT, handshake.getCipherOut()); } } } } else { log.warn("Handshake was not found for this connection: {}", conn); log.debug("RTMP state: {} Session: {}", rtmp, session); } } /** {@inheritDoc} */ @Override public void messageReceived(IoSession session, Object message) throws Exception { log.trace("messageReceived"); if (message instanceof IoBuffer) { rawBufferRecieved((IoBuffer) message, session); } else { log.trace("Setting connection local"); Red5.setConnectionLocal((IConnection) session.getAttribute(RTMPConnection.RTMP_CONNECTION_KEY)); handler.messageReceived(message, session); log.trace("Removing connection local"); Red5.setConnectionLocal(null); } } /** {@inheritDoc} */ @Override public void messageSent(IoSession session, Object message) throws Exception { log.debug("messageSent"); final RTMPMinaConnection conn = (RTMPMinaConnection) session.getAttribute(RTMPConnection.RTMP_CONNECTION_KEY); handler.messageSent(conn, message); } /** {@inheritDoc} */ @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { log.warn("Exception caught {}", cause.getMessage()); if (log.isDebugEnabled()) { log.error("Exception detail", cause); } } /** * Setter for handler. * * @param handler RTMP events handler */ public void setHandler(IRTMPHandler handler) { this.handler = handler; } public void setRtmpConnManager(IRTMPConnManager rtmpConnManager) { this.rtmpConnManager = rtmpConnManager; } protected IRTMPConnManager getRtmpConnManager() { return rtmpConnManager; } /** {@inheritDoc} */ public void setApplicationContext(ApplicationContext appCtx) throws BeansException { log.debug("Setting application context: {} {}", appCtx.getDisplayName(), appCtx); this.appCtx = appCtx; } protected RTMPMinaConnection createRTMPMinaConnection() { return (RTMPMinaConnection) rtmpConnManager.createConnection(RTMPMinaConnection.class); } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/RTMPHandshake.java0000644000175000017500000003617511754510402025055 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.Security; import java.security.spec.KeySpec; import java.util.Random; import javax.crypto.Cipher; import javax.crypto.KeyAgreement; import javax.crypto.Mac; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; import javax.crypto.spec.DHPublicKeySpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Hex; import org.apache.mina.core.buffer.IoBuffer; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.red5.server.net.IHandshake; import org.red5.server.net.rtmp.message.Constants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Generates and validates the RTMP handshake response for Flash Players. * Client versions equal to or greater than Flash 9,0,124,0 require a nonzero * value as the fifth byte of the handshake request. * * @author Jacinto Shy II (jacinto.m.shy@ieee.org) * @author Steven Zimmer (stevenlzimmer@gmail.com) * @author Gavriloaie Eugen-Andrei * @author Ari-Pekka Viitanen * @author Paul Gregoire * @author Tiago Jacobs */ public abstract class RTMPHandshake implements IHandshake { protected static Logger log = LoggerFactory.getLogger(RTMPHandshake.class); //for old style handshake public static byte[] HANDSHAKE_PAD_BYTES; protected static final byte[] GENUINE_FMS_KEY = { (byte) 0x47, (byte) 0x65, (byte) 0x6e, (byte) 0x75, (byte) 0x69, (byte) 0x6e, (byte) 0x65, (byte) 0x20, (byte) 0x41, (byte) 0x64, (byte) 0x6f, (byte) 0x62, (byte) 0x65, (byte) 0x20, (byte) 0x46, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x68, (byte) 0x20, (byte) 0x4d, (byte) 0x65, (byte) 0x64, (byte) 0x69, (byte) 0x61, (byte) 0x20, (byte) 0x53, (byte) 0x65, (byte) 0x72, (byte) 0x76, (byte) 0x65, (byte) 0x72, (byte) 0x20, (byte) 0x30, (byte) 0x30, (byte) 0x31, // Genuine Adobe Flash Media Server 001 (byte) 0xf0, (byte) 0xee, (byte) 0xc2, (byte) 0x4a, (byte) 0x80, (byte) 0x68, (byte) 0xbe, (byte) 0xe8, (byte) 0x2e, (byte) 0x00, (byte) 0xd0, (byte) 0xd1, (byte) 0x02, (byte) 0x9e, (byte) 0x7e, (byte) 0x57, (byte) 0x6e, (byte) 0xec, (byte) 0x5d, (byte) 0x2d, (byte) 0x29, (byte) 0x80, (byte) 0x6f, (byte) 0xab, (byte) 0x93, (byte) 0xb8, (byte) 0xe6, (byte) 0x36, (byte) 0xcf, (byte) 0xeb, (byte) 0x31, (byte) 0xae}; protected static final byte[] GENUINE_FP_KEY = { (byte) 0x47, (byte) 0x65, (byte) 0x6E, (byte) 0x75, (byte) 0x69, (byte) 0x6E, (byte) 0x65, (byte) 0x20, (byte) 0x41, (byte) 0x64, (byte) 0x6F, (byte) 0x62, (byte) 0x65, (byte) 0x20, (byte) 0x46, (byte) 0x6C, (byte) 0x61, (byte) 0x73, (byte) 0x68, (byte) 0x20, (byte) 0x50, (byte) 0x6C, (byte) 0x61, (byte) 0x79, (byte) 0x65, (byte) 0x72, (byte) 0x20, (byte) 0x30, (byte) 0x30, (byte) 0x31, // Genuine Adobe Flash Player 001 (byte) 0xF0, (byte) 0xEE, (byte) 0xC2, (byte) 0x4A, (byte) 0x80, (byte) 0x68, (byte) 0xBE, (byte) 0xE8, (byte) 0x2E, (byte) 0x00, (byte) 0xD0, (byte) 0xD1, (byte) 0x02, (byte) 0x9E, (byte) 0x7E, (byte) 0x57, (byte) 0x6E, (byte) 0xEC, (byte) 0x5D, (byte) 0x2D, (byte) 0x29, (byte) 0x80, (byte) 0x6F, (byte) 0xAB, (byte) 0x93, (byte) 0xB8, (byte) 0xE6, (byte) 0x36, (byte) 0xCF, (byte) 0xEB, (byte) 0x31, (byte) 0xAE}; /** Modulus bytes from flazr */ protected static final byte[] DH_MODULUS_BYTES = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xc9, (byte) 0x0f, (byte) 0xda, (byte) 0xa2, (byte) 0x21, (byte) 0x68, (byte) 0xc2, (byte) 0x34, (byte) 0xc4, (byte) 0xc6, (byte) 0x62, (byte) 0x8b, (byte) 0x80, (byte) 0xdc, (byte) 0x1c, (byte) 0xd1, (byte) 0x29, (byte) 0x02, (byte) 0x4e, (byte) 0x08, (byte) 0x8a, (byte) 0x67, (byte) 0xcc, (byte) 0x74, (byte) 0x02, (byte) 0x0b, (byte) 0xbe, (byte) 0xa6, (byte) 0x3b, (byte) 0x13, (byte) 0x9b, (byte) 0x22, (byte) 0x51, (byte) 0x4a, (byte) 0x08, (byte) 0x79, (byte) 0x8e, (byte) 0x34, (byte) 0x04, (byte) 0xdd, (byte) 0xef, (byte) 0x95, (byte) 0x19, (byte) 0xb3, (byte) 0xcd, (byte) 0x3a, (byte) 0x43, (byte) 0x1b, (byte) 0x30, (byte) 0x2b, (byte) 0x0a, (byte) 0x6d, (byte) 0xf2, (byte) 0x5f, (byte) 0x14, (byte) 0x37, (byte) 0x4f, (byte) 0xe1, (byte) 0x35, (byte) 0x6d, (byte) 0x6d, (byte) 0x51, (byte) 0xc2, (byte) 0x45, (byte) 0xe4, (byte) 0x85, (byte) 0xb5, (byte) 0x76, (byte) 0x62, (byte) 0x5e, (byte) 0x7e, (byte) 0xc6, (byte) 0xf4, (byte) 0x4c, (byte) 0x42, (byte) 0xe9, (byte) 0xa6, (byte) 0x37, (byte) 0xed, (byte) 0x6b, (byte) 0x0b, (byte) 0xff, (byte) 0x5c, (byte) 0xb6, (byte) 0xf4, (byte) 0x06, (byte) 0xb7, (byte) 0xed, (byte) 0xee, (byte) 0x38, (byte) 0x6b, (byte) 0xfb, (byte) 0x5a, (byte) 0x89, (byte) 0x9f, (byte) 0xa5, (byte) 0xae, (byte) 0x9f, (byte) 0x24, (byte) 0x11, (byte) 0x7c, (byte) 0x4b, (byte) 0x1f, (byte) 0xe6, (byte) 0x49, (byte) 0x28, (byte) 0x66, (byte) 0x51, (byte) 0xec, (byte) 0xe6, (byte) 0x53, (byte) 0x81, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; protected static final BigInteger DH_MODULUS = new BigInteger(1, DH_MODULUS_BYTES); protected static final BigInteger DH_BASE = BigInteger.valueOf(2); protected static final int HANDSHAKE_SIZE_SERVER = (Constants.HANDSHAKE_SIZE * 2) + 1; protected static final int DIGEST_LENGTH = 32; protected static final int KEY_LENGTH = 128; protected static final Random random = new Random(); protected KeyAgreement keyAgreement; protected Cipher cipherOut; protected Cipher cipherIn; protected byte handshakeType; protected byte[] handshakeBytes; // validation scheme protected int validationScheme = 0; // servers public key protected byte[] incomingPublicKey; // clients public key protected byte[] outgoingPublicKey; // swf verification bytes protected byte[] swfVerificationBytes; private Mac hmacSHA256; static { //get security provider Security.addProvider(new BouncyCastleProvider()); } public RTMPHandshake() { log.trace("Handshake ctor"); try { hmacSHA256 = Mac.getInstance("HmacSHA256"); } catch (SecurityException e) { log.error("Security exception when getting HMAC", e); } catch (NoSuchAlgorithmException e) { log.error("HMAC SHA256 does not exist"); } //create our handshake bytes createHandshakeBytes(); } /** * Calculates an HMAC SHA256 hash using a default key length. * * @param input * @param key * @return hmac hashed bytes */ public byte[] calculateHMAC_SHA256(byte[] input, byte[] key) { byte[] output = null; try { hmacSHA256.init(new SecretKeySpec(key, "HmacSHA256")); output = hmacSHA256.doFinal(input); } catch (InvalidKeyException e) { log.error("Invalid key", e); } return output; } /** * Calculates an HMAC SHA256 hash using a set key length. * * @param input * @param key * @param length * @return hmac hashed bytes */ public byte[] calculateHMAC_SHA256(byte[] input, byte[] key, int length) { byte[] output = null; try { hmacSHA256.init(new SecretKeySpec(key, 0, length, "HmacSHA256")); output = hmacSHA256.doFinal(input); } catch (InvalidKeyException e) { log.error("Invalid key", e); } return output; } /** * Creates a Diffie-Hellman key pair. * * @return dh keypair */ protected KeyPair generateKeyPair() { KeyPair keyPair = null; DHParameterSpec keySpec = new DHParameterSpec(DH_MODULUS, DH_BASE); try { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH"); keyGen.initialize(keySpec); keyPair = keyGen.generateKeyPair(); keyAgreement = KeyAgreement.getInstance("DH"); keyAgreement.init(keyPair.getPrivate()); } catch (Exception e) { log.error("Error generating keypair", e); } return keyPair; } /** * Returns the public key for a given key pair. * * @param keyPair * @return public key */ protected static byte[] getPublicKey(KeyPair keyPair) { DHPublicKey incomingPublicKey = (DHPublicKey) keyPair.getPublic(); BigInteger dhY = incomingPublicKey.getY(); log.debug("Public key: {}", dhY); byte[] result = dhY.toByteArray(); log.debug("Public key as bytes - length [{}]: {}", result.length, Hex.encodeHexString(result)); byte[] temp = new byte[KEY_LENGTH]; if (result.length < KEY_LENGTH) { System.arraycopy(result, 0, temp, KEY_LENGTH - result.length, result.length); result = temp; log.debug("Padded public key length to 128"); } else if(result.length > KEY_LENGTH){ System.arraycopy(result, result.length - KEY_LENGTH, temp, 0, KEY_LENGTH); result = temp; log.debug("Truncated public key length to 128"); } return result; } /** * Determines the validation scheme for given input. * * @param otherPublicKeyBytes * @param agreement * @return shared secret bytes if client used a supported validation scheme */ protected static byte[] getSharedSecret(byte[] otherPublicKeyBytes, KeyAgreement agreement) { BigInteger otherPublicKeyInt = new BigInteger(1, otherPublicKeyBytes); try { KeyFactory keyFactory = KeyFactory.getInstance("DH"); KeySpec otherPublicKeySpec = new DHPublicKeySpec(otherPublicKeyInt, RTMPHandshake.DH_MODULUS, RTMPHandshake.DH_BASE); PublicKey otherPublicKey = keyFactory.generatePublic(otherPublicKeySpec); agreement.doPhase(otherPublicKey, true); } catch (Exception e) { log.error("Exception getting the shared secret", e); } byte[] sharedSecret = agreement.generateSecret(); log.debug("Shared secret [{}]: {}", sharedSecret.length, Hex.encodeHexString(sharedSecret)); return sharedSecret; } /** * Create the initial bytes for a request / response. */ protected abstract void createHandshakeBytes(); /** * Determines the validation scheme for given input. * * @param input * @return true if its a supported validation scheme, false if unsupported */ public abstract boolean validate(IoBuffer input); /** * Returns the DH offset from an array of bytes. * * @param bytes * @return DH offset */ protected int getDHOffset(byte[] bytes) { int dhOffset = -1; switch (validationScheme) { case 1: dhOffset = getDHOffset1(bytes); break; default: log.debug("Scheme 0 will be used for DH offset"); case 0: dhOffset = getDHOffset0(bytes); } return dhOffset; } /** * Returns the DH byte offset. * * @return dh offset */ protected int getDHOffset0(byte[] bytes) { int offset = (bytes[1532] & 0x0ff) + (bytes[1533] & 0x0ff) + (bytes[1534] & 0x0ff) + (bytes[1535] & 0x0ff); offset = offset % 632; offset = offset + 772; if (offset + KEY_LENGTH >= 1536) { log.error("Invalid DH offset"); } return offset; } /** * Returns the DH byte offset. * * @return dh offset */ protected int getDHOffset1(byte[] bytes) { int offset = (bytes[768] & 0x0ff) + (bytes[769] & 0x0ff) + (bytes[770] & 0x0ff) + (bytes[771] & 0x0ff); offset = offset % 632; offset = offset + 8; if (offset + KEY_LENGTH >= 1536) { log.error("Invalid DH offset"); } return offset; } /** * Returns the digest offset using current validation scheme. * * @param pBuffer * @return digest offset */ protected int getDigestOffset(byte[] pBuffer) { int serverDigestOffset = -1; switch (validationScheme) { case 1: serverDigestOffset = getDigestOffset1(pBuffer); break; default: log.debug("Scheme 0 will be used for DH offset"); case 0: serverDigestOffset = getDigestOffset0(pBuffer); } return serverDigestOffset; } /** * Returns a digest byte offset. * * @param pBuffer source for digest data * @return digest offset */ protected int getDigestOffset0(byte[] pBuffer) { if (log.isTraceEnabled()) { log.trace("Scheme 0 offset bytes {},{},{},{}", new Object[]{(pBuffer[8] & 0x0ff), (pBuffer[9] & 0x0ff), (pBuffer[10] & 0x0ff), (pBuffer[11] & 0x0ff)}); } int offset = (pBuffer[8] & 0x0ff) + (pBuffer[9] & 0x0ff) + (pBuffer[10] & 0x0ff) + (pBuffer[11] & 0x0ff); offset = offset % 728; offset = offset + 12; if (offset + DIGEST_LENGTH >= 1536) { log.error("Invalid digest offset"); } return offset; } /** * Returns a digest byte offset. * * @param pBuffer source for digest data * @return digest offset */ protected int getDigestOffset1(byte[] pBuffer) { if (log.isTraceEnabled()) { log.trace("Scheme 1 offset bytes {},{},{},{}", new Object[]{(pBuffer[772] & 0x0ff), (pBuffer[773] & 0x0ff), (pBuffer[774] & 0x0ff), (pBuffer[775] & 0x0ff)}); } int offset = (pBuffer[772] & 0x0ff) + (pBuffer[773] & 0x0ff) + (pBuffer[774] & 0x0ff) + (pBuffer[775] & 0x0ff); offset = offset % 728; offset = offset + 776; if (offset + DIGEST_LENGTH >= 1536) { log.error("Invalid digest offset"); } return offset; } /** * Creates the servers handshake bytes */ public byte[] getHandshakeBytes() { return handshakeBytes; } /** * Sets the handshake type. Currently only two types are supported, plain and encrypted. * * @param handshakeType */ public void setHandshakeType(byte handshakeType) { log.trace("Setting handshake type: {}", handshakeType); this.handshakeType = handshakeType; } /** * Returns the handshake type. * * @return handshakeType */ public byte getHandshakeType() { return handshakeType; } /** * Gets the DH offset in the handshake bytes array based on validation scheme * Generates DH keypair * Adds public key to handshake bytes */ public Cipher getCipherOut() { return cipherOut; } /** * Returns the contained handshake bytes. These are just random bytes * if the player is using an non-versioned player. * * @return handshake bytes */ public Cipher getCipherIn() { return cipherIn; } /** * Returns the SWF verification bytes. * * @return swf verification bytes */ public byte[] getSwfVerificationBytes() { return swfVerificationBytes; } } red5-1.0~svn4374.orig/src/org/red5/server/net/rtmp/RTMPUtils.java0000644000175000017500000001527111706617130024264 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.rtmp; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.net.rtmp.message.Constants; /** * RTMP utilities class. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Art Clarke (aclarke@xuggle.com) */ public class RTMPUtils implements Constants { /** * Writes reversed integer to buffer. * * @param out Buffer * @param value Integer to write */ public static void writeReverseIntOld(IoBuffer out, int value) { byte[] bytes = new byte[4]; IoBuffer rev = IoBuffer.allocate(4); rev.putInt(value); rev.flip(); bytes[3] = rev.get(); bytes[2] = rev.get(); bytes[1] = rev.get(); bytes[0] = rev.get(); out.put(bytes); rev.free(); rev = null; } /** * Writes reversed integer to buffer. * * @param out Buffer * @param value Integer to write */ public static void writeReverseInt(IoBuffer out, int value) { out.put((byte) (0xFF & value)); out.put((byte) (0xFF & (value >> 8))); out.put((byte) (0xFF & (value >> 16))); out.put((byte) (0xFF & (value >> 24))); } /** * * @param out output buffer * @param value value to write */ public static void writeMediumInt(IoBuffer out, int value) { out.put((byte) (0xFF & (value >> 16))); out.put((byte) (0xFF & (value >> 8))); out.put((byte) (0xFF & (value >> 0))); } /** * * @param in input * @return unsigned int */ public static int readUnsignedMediumInt(IoBuffer in) { final byte a = in.get(); final byte b = in.get(); final byte c = in.get(); int val = 0; val += (a & 0xff) << 16; val += (b & 0xff) << 8; val += (c & 0xff); return val; } /** * * @param in input * @return unsigned medium (3 byte) int. */ public static int readUnsignedMediumIntOld(IoBuffer in) { byte[] bytes = new byte[3]; in.get(bytes); int val = 0; val += (bytes[0] & 0xFF) * 256 * 256; val += (bytes[1] & 0xFF) * 256; val += (bytes[2] & 0xFF); return val; } /** * * @param in input * @return signed 3-byte int */ public static int readMediumIntOld(IoBuffer in) { IoBuffer buf = IoBuffer.allocate(4); buf.put((byte) 0x00); buf.put(in.get()); buf.put(in.get()); buf.put(in.get()); buf.flip(); int value = buf.getInt(); buf.free(); buf = null; return value; } /** * * @param in input * @return signed 3 byte int */ public static int readMediumInt(IoBuffer in) { final byte a = in.get(); final byte b = in.get(); final byte c = in.get(); // Fix unsigned values int val = 0; val += (a & 0xff) << 16; val += (b & 0xff) << 8; val += (c & 0xff); return val; } /** * Read integer in reversed order. * * @param in Input buffer * @return Integer */ public static int readReverseInt(IoBuffer in) { final byte a = in.get(); final byte b = in.get(); final byte c = in.get(); final byte d = in.get(); int val = 0; val += (d & 0xff) << 24; val += (c & 0xff) << 16; val += (b & 0xff) << 8; val += (a & 0xff); return val; } /** * Encodes header size marker and channel id into header marker. * @param out output buffer * * @param headerSize Header size marker * @param channelId Channel used */ public static void encodeHeaderByte(IoBuffer out, byte headerSize, int channelId) { if (channelId <= 63) { out.put((byte) ((headerSize << 6) + channelId)); } else if (channelId <= 320) { out.put((byte) (headerSize << 6)); out.put((byte) (channelId - 64)); } else { out.put((byte) ((headerSize << 6) | 1)); channelId -= 64; out.put((byte) (channelId & 0xff)); out.put((byte) (channelId >> 8)); } } /** * Decode channel id. * * @param header Header * @param byteCount byte count * @return Channel id */ public static int decodeChannelId(int header, int byteCount) { if (byteCount == 1) { return (header & 0x3f); } else if (byteCount == 2) { return 64 + (header & 0xff); } else { return 64 + ((header >> 8) & 0xff) + ((header & 0xff) << 8); } } /** * Decode header size. * * @param header Header byte * @param byteCount byte count * @return Header size byte */ public static byte decodeHeaderSize(int header, int byteCount) { if (byteCount == 1) { return (byte) (header >> 6); } else if (byteCount == 2) { return (byte) (header >> 14); } else { return (byte) (header >> 22); } } /** * Return header length from marker value. * * @param headerSize Header size marker value * @return Header length */ public static int getHeaderLength(byte headerSize) { switch (headerSize) { case HEADER_NEW: return 12; case HEADER_SAME_SOURCE: return 8; case HEADER_TIMER_CHANGE: return 4; case HEADER_CONTINUE: return 1; default: return -1; } } /** * Compares two RTMP time stamps, accounting for time stamp wrapping. * * @param a First time stamp * @param b Second time stamp * @return -1 if a < b, 1 if a > b, or 0 if a == b */ public static int compareTimestamps(final int a, final int b) { long diff = diffTimestamps(a, b); return diff < 0 ? -1 : (diff > 0 ? 1 : 0); } /** * Calculates the delta between two time stamps, adjusting * for time stamp wrapping. * * @param a First time stamp * @param b Second time stamp * @return the distance between a and b, which will be negative if a is less than b. */ public static long diffTimestamps(final int a, final int b) { // first convert each to unsigned integers final long unsignedA = a & 0xFFFFFFFFL; final long unsignedB = b & 0xFFFFFFFFL; // then find the delta final long delta = unsignedA-unsignedB; return delta; } } red5-1.0~svn4374.orig/src/org/red5/server/net/filter/0000755000175000017500000000000011760512572022117 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/filter/DefaultMessageSizeEstimator.java0000644000175000017500000000724011706617130030375 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.filter; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.mina.core.buffer.IoBuffer; /** * A default {@link MessageSizeEstimator} implementation. *

* Martin's Java Notes * was used for estimation of the size of non-{@link IoBuffer}s. For unknown * types, it inspects declaring fields of the class of the specified message. * The size of unknown declaring fields are approximated to the specified * averageSizePerField (default: 64). *

* All the estimated sizes of classes are cached for performance improvement. * *
* This originated from the Mina sandbox. */ public class DefaultMessageSizeEstimator implements MessageSizeEstimator { private final ConcurrentMap, Integer> class2size = new ConcurrentHashMap, Integer>(); public DefaultMessageSizeEstimator() { class2size.put(boolean.class, 4); // Probably an integer. class2size.put(byte.class, 1); class2size.put(char.class, 2); class2size.put(short.class, 2); class2size.put(int.class, 4); class2size.put(long.class, 8); class2size.put(float.class, 4); class2size.put(double.class, 8); class2size.put(void.class, 0); } public int estimateSize(Object message) { if (message == null) { return 8; } int answer = 8 + estimateSize(message.getClass(), null); if (message instanceof IoBuffer) { answer += ((IoBuffer) message).remaining(); } else if (message instanceof CharSequence) { answer += ((CharSequence) message).length() << 1; } else if (message instanceof Iterable) { for (Object m : (Iterable) message) { answer += estimateSize(m); } } return align(answer); } private int estimateSize(Class clazz, Set> visitedClasses) { Integer objectSize = class2size.get(clazz); if (objectSize != null) { return objectSize; } if (visitedClasses != null) { if (visitedClasses.contains(clazz)) { return 0; } } else { visitedClasses = new HashSet>(); } visitedClasses.add(clazz); int answer = 8; // Basic overhead. for (Class c = clazz; c != null; c = c.getSuperclass()) { Field[] fields = c.getDeclaredFields(); for (Field f : fields) { if ((f.getModifiers() & Modifier.STATIC) != 0) { // Ignore static fields. continue; } answer += estimateSize(f.getType(), visitedClasses); } } visitedClasses.remove(clazz); // Some alignment. answer = align(answer); // Put the final answer. class2size.putIfAbsent(clazz, answer); return answer; } private static int align(int size) { if (size % 8 != 0) { size /= 8; size++; size *= 8; } return size; } } red5-1.0~svn4374.orig/src/org/red5/server/net/filter/TrafficShapingFilter.java0000644000175000017500000002111511706617130027014 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.filter; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.filterchain.IoFilter; import org.apache.mina.core.filterchain.IoFilterAdapter; import org.apache.mina.core.filterchain.IoFilterChain; import org.apache.mina.core.session.AttributeKey; import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSessionConfig; import org.apache.mina.core.write.WriteRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An {@link IoFilter} that limits bandwidth (bytes per second) related with * read and write operations on a per-session basis. *

* It is always recommended to add this filter in the first place of the * {@link IoFilterChain}. * *
* This originated from the Mina sandbox. */ public class TrafficShapingFilter extends IoFilterAdapter { protected static Logger log = LoggerFactory.getLogger(TrafficShapingFilter.class); private final AttributeKey STATE = new AttributeKey(getClass(), "state"); private final ScheduledExecutorService scheduledExecutor; private final MessageSizeEstimator messageSizeEstimator; private volatile int maxReadThroughput; private volatile int maxWriteThroughput; private volatile int poolSize = 1; public TrafficShapingFilter(int maxReadThroughput, int maxWriteThroughput) { this(null, null, maxReadThroughput, maxWriteThroughput); } public TrafficShapingFilter(ScheduledExecutorService scheduledExecutor, int maxReadThroughput, int maxWriteThroughput) { this(scheduledExecutor, null, maxReadThroughput, maxWriteThroughput); } public TrafficShapingFilter(ScheduledExecutorService scheduledExecutor, MessageSizeEstimator messageSizeEstimator, int maxReadThroughput, int maxWriteThroughput) { log.debug("ctor - executor: {} estimator: {} max read: {} max write: {}", new Object[] { scheduledExecutor, messageSizeEstimator, maxReadThroughput, maxWriteThroughput }); if (scheduledExecutor == null) { scheduledExecutor = new ScheduledThreadPoolExecutor(poolSize); //throw new NullPointerException("scheduledExecutor"); } if (messageSizeEstimator == null) { messageSizeEstimator = new DefaultMessageSizeEstimator() { @Override public int estimateSize(Object message) { if (message instanceof IoBuffer) { return ((IoBuffer) message).remaining(); } return super.estimateSize(message); } }; } this.scheduledExecutor = scheduledExecutor; this.messageSizeEstimator = messageSizeEstimator; setMaxReadThroughput(maxReadThroughput); setMaxWriteThroughput(maxWriteThroughput); } public ScheduledExecutorService getScheduledExecutor() { return scheduledExecutor; } public MessageSizeEstimator getMessageSizeEstimator() { return messageSizeEstimator; } public int getMaxReadThroughput() { return maxReadThroughput; } public void setMaxReadThroughput(int maxReadThroughput) { if (maxReadThroughput < 0) { maxReadThroughput = 0; } this.maxReadThroughput = maxReadThroughput; } public int getMaxWriteThroughput() { return maxWriteThroughput; } public void setMaxWriteThroughput(int maxWriteThroughput) { if (maxWriteThroughput < 0) { maxWriteThroughput = 0; } this.maxWriteThroughput = maxWriteThroughput; } public int getPoolSize() { return poolSize; } public void setPoolSize(int poolSize) { if (poolSize < 1) { poolSize = 1; } this.poolSize = poolSize; } @Override public void onPreAdd(IoFilterChain parent, String name, NextFilter nextFilter) throws Exception { if (parent.contains(this)) { throw new IllegalArgumentException( "You can't add the same filter instance more than once. Create another instance and add it."); } parent.getSession().setAttribute(STATE, new State()); adjustReadBufferSize(parent.getSession()); } @Override public void onPostRemove(IoFilterChain parent, String name, NextFilter nextFilter) throws Exception { parent.getSession().removeAttribute(STATE); } @Override public void messageReceived(NextFilter nextFilter, final IoSession session, Object message) throws Exception { int maxReadThroughput = this.maxReadThroughput; //process the request if our max is greater than zero if (maxReadThroughput > 0) { final State state = (State) session.getAttribute(STATE); long currentTime = System.currentTimeMillis(); long suspendTime = 0; boolean firstRead = false; synchronized (state) { state.readBytes += messageSizeEstimator.estimateSize(message); if (!state.suspendedRead) { if (state.readStartTime == 0) { firstRead = true; state.readStartTime = currentTime - 1000; } long throughput = (state.readBytes * 1000 / (currentTime - state.readStartTime)); if (throughput >= maxReadThroughput) { suspendTime = Math.max(0, state.readBytes * 1000 / maxReadThroughput - (firstRead ? 0 : currentTime - state.readStartTime)); state.readBytes = 0; state.readStartTime = 0; state.suspendedRead = suspendTime != 0; adjustReadBufferSize(session); } } } if (suspendTime != 0) { session.suspendRead(); scheduledExecutor.schedule(new Runnable() { public void run() { synchronized (state) { state.suspendedRead = false; } session.resumeRead(); } }, suspendTime, TimeUnit.MILLISECONDS); } } nextFilter.messageReceived(session, message); } private void adjustReadBufferSize(IoSession session) { int maxReadThroughput = this.maxReadThroughput; if (maxReadThroughput == 0) { return; } IoSessionConfig config = session.getConfig(); if (config.getReadBufferSize() > maxReadThroughput) { config.setReadBufferSize(maxReadThroughput); } if (config.getMaxReadBufferSize() > maxReadThroughput) { config.setMaxReadBufferSize(maxReadThroughput); } } @Override public void messageSent(NextFilter nextFilter, final IoSession session, WriteRequest writeRequest) throws Exception { int maxWriteThroughput = this.maxWriteThroughput; //process the request if our max is greater than zero if (maxWriteThroughput > 0) { final State state = (State) session.getAttribute(STATE); long currentTime = System.currentTimeMillis(); long suspendTime = 0; boolean firstWrite = false; synchronized (state) { state.writtenBytes += messageSizeEstimator.estimateSize(writeRequest.getMessage()); if (!state.suspendedWrite) { if (state.writeStartTime == 0) { firstWrite = true; state.writeStartTime = currentTime - 1000; } long throughput = (state.writtenBytes * 1000 / (currentTime - state.writeStartTime)); if (throughput >= maxWriteThroughput) { suspendTime = Math.max(0, state.writtenBytes * 1000 / maxWriteThroughput - (firstWrite ? 0 : currentTime - state.writeStartTime)); state.writtenBytes = 0; state.writeStartTime = 0; state.suspendedWrite = suspendTime != 0; } } } if (suspendTime != 0) { log.trace("Suspending write"); session.suspendWrite(); scheduledExecutor.schedule(new Runnable() { public void run() { synchronized (state) { state.suspendedWrite = false; } session.resumeWrite(); log.trace("Resuming write"); } }, suspendTime, TimeUnit.MILLISECONDS); } } nextFilter.messageSent(session, writeRequest); } private static class State { private long readStartTime; private long writeStartTime; private boolean suspendedRead; private boolean suspendedWrite; private long readBytes; private long writtenBytes; } } red5-1.0~svn4374.orig/src/org/red5/server/net/filter/MessageSizeEstimator.java0000644000175000017500000000174411706617130027073 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.filter; /** * Estimates the amount of memory that the specified object occupies in the VM. *
* This originated from the Mina sandbox. */ public interface MessageSizeEstimator { int estimateSize(Object message); } red5-1.0~svn4374.orig/src/org/red5/server/net/proxy/0000755000175000017500000000000011760512572022013 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/proxy/DebugProxyHandler.java0000644000175000017500000001340311752001621026232 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.proxy; import java.io.File; import java.io.FileOutputStream; import java.net.InetSocketAddress; import java.nio.channels.WritableByteChannel; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.future.ConnectFuture; import org.apache.mina.core.service.IoConnector; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFactory; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.transport.socket.SocketSessionConfig; import org.apache.mina.transport.socket.nio.NioSocketConnector; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.rtmp.message.Header; import org.red5.server.net.rtmp.message.Packet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ResourceLoaderAware; import org.springframework.core.io.ResourceLoader; public class DebugProxyHandler extends IoHandlerAdapter implements ResourceLoaderAware { protected static Logger log = LoggerFactory.getLogger(DebugProxyHandler.class); private ResourceLoader loader; private ProtocolCodecFactory codecFactory; private InetSocketAddress forward; private String dumpTo = "./dumps/"; /** {@inheritDoc} */ public void setResourceLoader(ResourceLoader loader) { this.loader = loader; } /** * Setter for property 'codecFactory'. * * @param codecFactory Value to set for property 'codecFactory'. */ public void setCodecFactory(ProtocolCodecFactory codecFactory) { this.codecFactory = codecFactory; } /** * Setter for property 'forward'. * * @param forward Value to set for property 'forward'. */ public void setForward(String forward) { int split = forward.indexOf(':'); String host = forward.substring(0, split); int port = Integer.parseInt(forward.substring(split + 1, forward.length())); this.forward = new InetSocketAddress(host, port); } /** * Setter for property 'dumpTo'. * * @param dumpTo Value to set for property 'dumpTo'. */ public void setDumpTo(String dumpTo) { this.dumpTo = dumpTo; } /** {@inheritDoc} */ @Override public void sessionOpened(IoSession session) throws Exception { SocketSessionConfig ssc = (SocketSessionConfig) session.getConfig(); ssc.setTcpNoDelay(true); //ssc.setReceiveBufferSize(2048); //ssc.setSendBufferSize(2048); super.sessionOpened(session); } /** {@inheritDoc} */ @Override public void sessionCreated(IoSession session) throws Exception { boolean isClient = session.getRemoteAddress().equals(forward); if (log.isDebugEnabled()) { log.debug("Is downstream: " + isClient); session.setAttribute(ProtocolState.SESSION_KEY, new RTMP()); session.getFilterChain().addFirst("protocol", new ProtocolCodecFilter(codecFactory)); } session.getFilterChain().addFirst("proxy", new ProxyFilter(isClient ? "client" : "server")); if (true) { String fileName = System.currentTimeMillis() + '_' + forward.getHostName() + '_' + forward.getPort() + '_' + (isClient ? "DOWNSTREAM" : "UPSTREAM"); File headersFile = loader.getResource(dumpTo + fileName + ".cap").getFile(); headersFile.createNewFile(); File rawFile = loader.getResource(dumpTo + fileName + ".raw").getFile(); rawFile.createNewFile(); FileOutputStream headersFos = new FileOutputStream(headersFile); WritableByteChannel headers = headersFos.getChannel(); FileOutputStream rawFos = new FileOutputStream(rawFile); WritableByteChannel raw = rawFos.getChannel(); IoBuffer header = IoBuffer.allocate(1); header.put((byte) (isClient ? 0x00 : 0x01)); header.flip(); headers.write(header.buf()); session.getFilterChain().addFirst("dump", new NetworkDumpFilter(headers, raw)); } //session.getFilterChain().addLast("logger", new LoggingFilter() ); if (!isClient) { log.debug("Connecting.."); IoConnector connector = new NioSocketConnector(); connector.setHandler(this); ConnectFuture future = connector.connect(forward); future.awaitUninterruptibly(); // wait for connect, or timeout if (future.isConnected()) { if (log.isDebugEnabled()) { log.debug("Connected: {}", forward); } IoSession client = future.getSession(); client.setAttribute(ProxyFilter.FORWARD_KEY, session); session.setAttribute(ProxyFilter.FORWARD_KEY, client); } } super.sessionCreated(session); } /** {@inheritDoc} */ @Override public void messageReceived(IoSession session, Object in) { if (log.isDebugEnabled()) { if (in instanceof IoBuffer) { log.debug("Handskake"); return; } try { final Packet packet = (Packet) in; final Object message = packet.getMessage(); final Header source = packet.getHeader(); log.debug("{}", source); log.debug("{}", message); } catch (RuntimeException e) { log.error("Exception", e); } } } /** {@inheritDoc} */ @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { if (log.isDebugEnabled()) { log.debug("Exception caught", cause); } } } red5-1.0~svn4374.orig/src/org/red5/server/net/proxy/NetworkDumpFilter.java0000644000175000017500000000500111706617130026273 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.proxy; import java.nio.channels.WritableByteChannel; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.filterchain.IoFilterAdapter; import org.apache.mina.core.session.IoSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Network dump filter, performs raw data and headers dump on message recieve */ public class NetworkDumpFilter extends IoFilterAdapter { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(ProxyFilter.class); /** * Raw data byte channel */ protected WritableByteChannel raw; /** * Headers byte channel */ protected WritableByteChannel headers; /** * Create network dump filter from given dump channels * @param headers Channel to dump headers * @param raw Channel to dump raw data */ public NetworkDumpFilter(WritableByteChannel headers, WritableByteChannel raw) { this.raw = raw; this.headers = headers; } /** {@inheritDoc} */ @Override public void messageReceived(NextFilter next, IoSession session, Object message) throws Exception { if (message instanceof IoBuffer) { IoBuffer out = (IoBuffer) message; if (headers != null) { IoBuffer header = IoBuffer.allocate(12); header.putLong(System.currentTimeMillis()); header.putInt(out.limit() - out.position()); header.flip(); headers.write(header.buf()); } if (raw != null) { raw.write(out.asReadOnlyBuffer().buf()); } } next.messageReceived(session, message); } /** {@inheritDoc} */ @Override public void sessionClosed(NextFilter next, IoSession session) throws Exception { if (headers.isOpen()) { headers.close(); } if (raw.isOpen()) { raw.close(); } next.sessionClosed(session); } } red5-1.0~svn4374.orig/src/org/red5/server/net/proxy/ProxyFilter.java0000644000175000017500000000505411706617130025145 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.proxy; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.filterchain.IoFilterAdapter; import org.apache.mina.core.session.IoSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Proxy filter */ public class ProxyFilter extends IoFilterAdapter { /** * Forwarding key constant */ public static final String FORWARD_KEY = "proxy_forward_key"; /** * Logger */ protected static Logger log = LoggerFactory.getLogger(ProxyFilter.class); /** * Filter name */ protected String name; /** * Create proxy filter with given name * @param name name */ public ProxyFilter(String name) { this.name = name; } /** {@inheritDoc} */ @Override public void messageReceived(NextFilter next, IoSession session, Object message) throws Exception { // Create forwarding IO session IoSession forward = (IoSession) session.getAttribute(FORWARD_KEY); if (forward != null && forward.isConnected()) { if (message instanceof IoBuffer) { final IoBuffer buf = (IoBuffer) message; if (log.isDebugEnabled()) { log.debug("[{}] RAW >> {}", name, buf.getHexDump()); } IoBuffer copy = IoBuffer.allocate(buf.limit()); int limit = buf.limit(); copy.put(buf); copy.flip(); forward.write(copy); buf.flip(); buf.position(0); buf.limit(limit); } } next.messageReceived(session, message); } /** {@inheritDoc} */ @Override public void sessionClosed(NextFilter next, IoSession session) throws Exception { IoSession forward = (IoSession) session.getAttribute(FORWARD_KEY); if (forward != null && forward.isConnected() && !forward.isClosing()) { if (log.isDebugEnabled()) { log.debug("[{}] Closing: {}", name, forward); } forward.close(true); } next.sessionClosed(session); } }red5-1.0~svn4374.orig/src/org/red5/server/net/remoting/0000755000175000017500000000000011760512572022456 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/remoting/message/0000755000175000017500000000000011760512572024102 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/remoting/message/RemotingCall.java0000644000175000017500000000572311706617130027330 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.remoting.message; import org.red5.compatibility.flex.messaging.messages.ErrorMessage; import org.red5.server.service.PendingCall; /** * Remoting method call, specific pending call. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class RemotingCall extends PendingCall { /** * Handler success posfix constant */ public static final String HANDLER_SUCCESS = "/onResult"; /** * Handler error posfix constant */ public static final String HANDLER_ERROR = "/onStatus"; /** * Client callback name */ public String clientCallback; public boolean isAMF3; public boolean isMessaging; /** * Default / void constructor to prevent runtime exception. */ public RemotingCall() { } /** * Create remoting call from service name, method name, list of arguments and callback name. * * @param serviceName Service name * @param serviceMethod Service method name * @param args Parameters passed to method * @param callback Name of client callback * @param isAMF3 Does the client support AMF3? * @param isMessaging Is this a Flex messaging request? */ public RemotingCall(String serviceName, String serviceMethod, Object[] args, String callback, boolean isAMF3, boolean isMessaging) { super(serviceName, serviceMethod, args); setClientCallback(callback); this.isAMF3 = isAMF3; this.isMessaging = isMessaging; } /** * Setter for client callback. * * @param clientCallback Client callback */ public void setClientCallback(String clientCallback) { this.clientCallback = clientCallback; } /** * Getter for client response. * * @return Client response */ public String getClientResponse() { if (clientCallback != null) { return clientCallback + (isSuccess() && !(getClientResult() instanceof ErrorMessage) ? HANDLER_SUCCESS : HANDLER_ERROR); } else { return null; } } /** * Getter for client result. * * @return Client result */ public Object getClientResult() { return isSuccess() ? getResult() : getException(); } } red5-1.0~svn4374.orig/src/org/red5/server/net/remoting/message/RemotingPacket.java0000644000175000017500000000474711706617130027671 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.remoting.message; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.red5.server.api.IConnection.Encoding; /** * Packet of remote calls. Used by RemoteProtocolDecoder. */ public class RemotingPacket { /** * HTTP request object */ protected HttpServletRequest request; /** * Byte buffer data */ protected ByteBuffer data; /** * Headers sent with request. */ protected Map headers; /** * List of calls */ protected List calls; /** * Scope path */ protected String scopePath; /** * Create remoting packet from list of pending calls * @param headers headers * @param calls List of call objects */ public RemotingPacket(Map headers, List calls) { this.headers = headers; this.calls = calls; } /** * Get the headers sent with the request. * * @return headers */ public Map getHeaders() { return headers; } /** * Getter for calls. * * @return List of remote calls */ public List getCalls() { return calls; } /** * Setter for scope path. * * @param path Value to set for property 'scopePath'. */ public void setScopePath(String path) { scopePath = path; } /** * Getter for property scope path. * * @return Scope path to set */ public String getScopePath() { return scopePath; } /** * Return the encoding of the included calls. * * @return encoding */ public Encoding getEncoding() { List calls = getCalls(); if (calls == null || calls.isEmpty()) { return Encoding.AMF0; } RemotingCall call = calls.get(0); return call.isAMF3 ? Encoding.AMF3 : Encoding.AMF0; } } red5-1.0~svn4374.orig/src/org/red5/server/net/remoting/RemotingClient.java0000644000175000017500000003050311706617130026241 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.remoting; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.InputStreamEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.util.EntityUtils; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.amf.Input; import org.red5.io.amf.Output; import org.red5.io.object.Deserializer; import org.red5.io.object.RecordSet; import org.red5.io.object.Serializer; import org.red5.server.util.HttpConnectionUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; /** * Client interface for remoting calls. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public class RemotingClient implements InitializingBean { protected static Logger log = LoggerFactory.getLogger(RemotingClient.class); /** Default timeout to use. */ public static final int DEFAULT_TIMEOUT = 30000; /** Content MIME type for HTTP requests. */ protected static final String CONTENT_TYPE = "application/x-amf"; /** HTTP client for remoting calls. */ protected DefaultHttpClient client; /** Url to connect to. */ protected String url; /** Additional string to use while connecting. */ protected String appendToUrl = ""; /** Headers to send to the server. */ protected Map headers = new ConcurrentHashMap(); /** Thread pool to use for asynchronous requests. */ protected static ExecutorService executor; /** Maximum pool threads */ protected int poolSize = 1; /** * Dummy constructor used by the spring configuration. */ public RemotingClient() { log.debug("RemotingClient created"); } /** * Create new remoting client for the given url. * * @param url URL to connect to */ public RemotingClient(String url) { this(url, DEFAULT_TIMEOUT); log.debug("RemotingClient created - url: {}", url); } /** * Create new remoting client for the given url and given timeout. * * @param url URL to connect to * @param timeout Timeout for one request in milliseconds */ public RemotingClient(String url, int timeout) { client = HttpConnectionUtil.getClient(); client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, timeout); this.url = url; log.debug("RemotingClient created - url: {} timeout: {}", url, timeout); } public void afterPropertiesSet() throws Exception { executor = Executors.newFixedThreadPool(poolSize); } public int getPoolSize() { return poolSize; } public void setPoolSize(int poolSize) { this.poolSize = poolSize; } /** * Encode the method call. * * @param method * Remote method being called * @param params * Method parameters * @return Byte buffer with data to perform remoting call */ private IoBuffer encodeInvoke(String method, Object[] params) { log.debug("RemotingClient encodeInvoke - method: {} params: {}", method, params); IoBuffer result = IoBuffer.allocate(1024); result.setAutoExpand(true); // XXX: which is the correct version? result.putShort((short) 0); // Headers Collection hdr = headers.values(); result.putShort((short) hdr.size()); for (RemotingHeader header : hdr) { Output.putString(result, header.name); result.put(header.required ? (byte) 0x01 : (byte) 0x00); IoBuffer tmp = IoBuffer.allocate(1024); tmp.setAutoExpand(true); Output tmpOut = new Output(tmp); Serializer tmpSer = new Serializer(); tmpSer.serialize(tmpOut, header.data); tmp.flip(); // Size of header data result.putInt(tmp.limit()); // Header data result.put(tmp); tmp.free(); tmp = null; } // One body result.putShort((short) 1); // Method name Output.putString(result, method); // Client callback for response Output.putString(result, ""); // Serialize parameters IoBuffer tmp = IoBuffer.allocate(1024); tmp.setAutoExpand(true); Output tmpOut = new Output(tmp); //if the params are null send the NULL AMF type //this should fix APPSERVER-296 if (params == null) { tmpOut.writeNull(); } else { tmpOut.writeArray(params, new Serializer()); } tmp.flip(); // Store size and parameters result.putInt(tmp.limit()); result.put(tmp); tmp.free(); tmp = null; result.flip(); return result; } /** * Process any headers sent in the response. * * @param in * Byte buffer with response data */ @SuppressWarnings("static-access") protected void processHeaders(IoBuffer in) { log.debug("RemotingClient processHeaders - buffer limit: {}", (in != null ? in.limit() : 0)); int version = in.getUnsignedShort(); // skip log.debug("Version: {}", version); // the version by now, AMF3 is not yet implemented int count = in.getUnsignedShort(); log.debug("Count: {}", count); Deserializer deserializer = new Deserializer(); Input input = new Input(in); for (int i = 0; i < count; i++) { String name = input.getString(in); //String name = deserializer.deserialize(input, String.class); log.debug("Name: {}", name); boolean required = (in.get() == 0x01); log.debug("Required: {}", required); int len = in.getInt(); log.debug("Length: {}", len); Object value = deserializer.deserialize(input, Object.class); log.debug("Value: {}", value); // XXX: this is pretty much untested!!! if (RemotingHeader.APPEND_TO_GATEWAY_URL.equals(name)) { // Append string to gateway url appendToUrl = (String) value; } else if (RemotingHeader.REPLACE_GATEWAY_URL.equals(name)) { // Replace complete gateway url url = (String) value; // XXX: reset the ) { @SuppressWarnings("unchecked") Map valueMap = (Map) value; RemotingHeader header = new RemotingHeader((String) valueMap.get("name"), (Boolean) valueMap .get("mustUnderstand"), valueMap.get("data")); headers.put(header.name, header); } else { log.error("Expected Map but received {}", value); } } else { log.warn("Unsupported remoting header \"{}\" received with value \"{}\"", name, value); } } } /** * Decode response received from remoting server. * * @param data * Result data to decode * @return Object deserialized from byte buffer data */ private Object decodeResult(IoBuffer data) { log.debug("decodeResult - data limit: {}", (data != null ? data.limit() : 0)); processHeaders(data); int count = data.getUnsignedShort(); if (count != 1) { throw new RuntimeException("Expected exactly one result but got " + count); } Input input = new Input(data); String target = input.getString(); // expect "/onResult" log.debug("Target: {}", target); String nullString = input.getString(); // expect "null" log.debug("Null string: {}", nullString); // Read return value Deserializer deserializer = new Deserializer(); return deserializer.deserialize(input, Object.class); } /** * Send authentication data with each remoting request. * * @param userid User identifier * @param password Password */ public void setCredentials(String userid, String password) { Map data = new HashMap(); data.put("userid", userid); data.put("password", password); RemotingHeader header = new RemotingHeader(RemotingHeader.CREDENTIALS, true, data); headers.put(RemotingHeader.CREDENTIALS, header); } /** * Stop sending authentication data. */ public void resetCredentials() { removeHeader(RemotingHeader.CREDENTIALS); } /** * Send an additional header to the server. * * @param name Header name * @param required Header required? * @param value Header body */ public void addHeader(String name, boolean required, Object value) { RemotingHeader header = new RemotingHeader(name, required, value); headers.put(name, header); } /** * Stop sending a given header. * * @param name Header name */ public void removeHeader(String name) { headers.remove(name); } /** * Invoke a method synchronously on the remoting server. * * @param method Method name * @param params Parameters passed to method * @return the result of the method call */ public Object invokeMethod(String method, Object[] params) { log.debug("invokeMethod url: {}", (url + appendToUrl)); IoBuffer resultBuffer = null; IoBuffer data = encodeInvoke(method, params); //setup POST HttpPost post = null; try { post = new HttpPost(url + appendToUrl); post.addHeader("Content-Type", CONTENT_TYPE); post.setEntity(new InputStreamEntity(data.asInputStream(), data.limit())); // execute the method HttpResponse response = client.execute(post); int code = response.getStatusLine().getStatusCode(); log.debug("HTTP response code: {}", code); if (code / 100 != 2) { throw new RuntimeException("Didn't receive success from remoting server"); } else { HttpEntity entity = response.getEntity(); if (entity != null) { //fix for Trac #676 int contentLength = (int) entity.getContentLength(); //default the content length to 16 if post doesn't contain a good value if (contentLength < 1) { contentLength = 16; } // get the response as bytes byte[] bytes = EntityUtils.toByteArray(entity); resultBuffer = IoBuffer.wrap(bytes); Object result = decodeResult(resultBuffer); if (result instanceof RecordSet) { // Make sure we can retrieve paged results ((RecordSet) result).setRemotingClient(this); } return result; } } } catch (Exception ex) { log.error("Error while invoking remoting method.", ex); post.abort(); } finally { if (resultBuffer != null) { resultBuffer.free(); resultBuffer = null; } data.free(); data = null; } return null; } /** * Invoke a method asynchronously on the remoting server. * * @param method Method name * @param methodParams Parameters passed to method * @param callback Callback */ public void invokeMethod(String method, Object[] methodParams, IRemotingCallback callback) { try { RemotingWorker worker = new RemotingWorker(this, method, methodParams, callback); executor.execute(worker); } catch (Exception err) { log.warn("Exception invoking method: {}", method, err); } } /** * Worker class that is used for asynchronous remoting calls. */ public final static class RemotingWorker implements Runnable { private final RemotingClient client; private final String method; private final Object[] params; private final IRemotingCallback callback; /** * Execute task. * * @param client Remoting client * @param method Method name * @param params Parameters to pass to method on call * @param callback Callback */ public RemotingWorker(RemotingClient client, String method, Object[] params, IRemotingCallback callback) { this.client = client; this.method = method; this.params = params; this.callback = callback; } public void run() { try { Object result = client.invokeMethod(method, params); callback.resultReceived(client, method, params, result); } catch (Exception err) { callback.errorReceived(client, method, params, err); } } } } red5-1.0~svn4374.orig/src/org/red5/server/net/remoting/IRemotingCallback.java0000644000175000017500000000313411706617130026630 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.remoting; /** * Callback for asynchronous remoting calls. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IRemotingCallback { /** * The result of a remoting call has been received. * * @param client Remoting client * @param method Remote method name * @param params Call parameters * @param result Call result */ public void resultReceived(RemotingClient client, String method, Object[] params, Object result); /** * An error occured while performing the remoting call. * * @param client Remoting client * @param method Remoting method * @param params Call parameters * @param error Call result */ public void errorReceived(RemotingClient client, String method, Object[] params, Throwable error); } red5-1.0~svn4374.orig/src/org/red5/server/net/remoting/RemotingConnection.java0000644000175000017500000003010311747114732027123 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.remoting; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.red5.server.Client; import org.red5.server.api.IAttributeStore; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.event.IEvent; import org.red5.server.api.remoting.IRemotingConnection; import org.red5.server.api.remoting.IRemotingHeader; import org.red5.server.api.scope.IBasicScope; import org.red5.server.api.scope.IScope; import org.red5.server.net.remoting.message.RemotingPacket; import org.red5.server.net.servlet.ServletUtils; /** * Connection class so the Red5 object works in methods invoked through * remoting. Attributes are stored in the session of the implementing * servlet container. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public class RemotingConnection implements IRemotingConnection { /** * Session attribute holding an IClient object for this connection. */ private final static String CLIENT = "red5.client"; /** * Scope */ protected IScope scope; /** * Servlet request */ protected HttpServletRequest request; /** * Remoting packet that triggered the connection. */ protected RemotingPacket packet; /** * Session used to store properties. */ protected HttpSession session; /** * Headers to be returned to the client. */ protected List headers = new ArrayList(); /** * Create servlet connection from request and scope. * * @param request Servlet request * @param scope Scope * @param packet packet */ public RemotingConnection(HttpServletRequest request, IScope scope, RemotingPacket packet) { this.request = request; this.scope = scope; this.packet = packet; this.session = request.getSession(); RemotingClient client = (RemotingClient) session.getAttribute(CLIENT); if (client == null) { client = new RemotingClient(session.getId()); session.setAttribute(CLIENT, client); } client.register(this); } /** * Return string representation of the connection. * * @return string */ public String toString() { return getClass().getSimpleName() + " from " + getRemoteAddress() + ':' + getRemotePort() + " to " + getHost() + " (session: " + session.getId() + ')'; } /** * Update the current packet. * * @param packet */ protected void setPacket(RemotingPacket packet) { this.packet = packet; } /** * Throws Not supported runtime exception */ private void notSupported() { throw new RuntimeException("Not supported for this type of connection"); } /** * Return encoding (AMF0 or AMF3). * * @return Encoding, currently AMF0 */ public Encoding getEncoding() { return packet.getEncoding(); } /** {@inheritDoc} */ public String getType() { return IConnection.TRANSIENT; } /** {@inheritDoc} */ public void initialize(IClient client) { notSupported(); } /** {@inheritDoc} */ public boolean connect(IScope scope) { notSupported(); return false; } /** {@inheritDoc} */ public boolean connect(IScope scope, Object[] params) { notSupported(); return false; } /** {@inheritDoc} */ public boolean isConnected() { return false; } /** {@inheritDoc} */ public void close() { session.invalidate(); } /** {@inheritDoc} */ public Map getConnectParams() { return packet.getHeaders(); } /** {@inheritDoc} */ public IClient getClient() { return (IClient) session.getAttribute(CLIENT); } /** {@inheritDoc} */ public String getHost() { return request.getLocalName(); } /** {@inheritDoc} */ public String getRemoteAddress() { return request.getRemoteAddr(); } /** {@inheritDoc} */ public List getRemoteAddresses() { return ServletUtils.getRemoteAddresses(request); } /** {@inheritDoc} */ public int getRemotePort() { return request.getRemotePort(); } /** {@inheritDoc} */ public String getPath() { String path = request.getContextPath(); if (request.getPathInfo() != null) { path += request.getPathInfo(); } if (path.charAt(0) == '/') { path = path.substring(1); } return path; } /** {@inheritDoc} */ public String getSessionId() { return null; } /** {@inheritDoc} */ public long getReadBytes() { return request.getContentLength(); } /** {@inheritDoc} */ public long getWrittenBytes() { return 0; } /** {@inheritDoc} */ public long getPendingMessages() { return 0; } /** * Return pending video messages number. * * @return Pending video messages number */ public long getPendingVideoMessages() { return 0; } /** {@inheritDoc} */ public long getReadMessages() { return 1; } /** {@inheritDoc} */ public long getWrittenMessages() { return 0; } /** {@inheritDoc} */ public long getDroppedMessages() { return 0; } /** {@inheritDoc} */ public void ping() { notSupported(); } /** {@inheritDoc} */ public int getLastPingTime() { return -1; } /** {@inheritDoc} */ public IScope getScope() { return scope; } /** {@inheritDoc} */ public Iterator getBasicScopes() { notSupported(); return null; } public void dispatchEvent(Object event) { notSupported(); } /** {@inheritDoc} */ public void dispatchEvent(IEvent event) { notSupported(); } /** {@inheritDoc} */ public boolean handleEvent(IEvent event) { notSupported(); return false; } /** {@inheritDoc} */ public void notifyEvent(IEvent event) { notSupported(); } /** {@inheritDoc} */ public Boolean getBoolAttribute(String name) { return (Boolean) getAttribute(name); } /** {@inheritDoc} */ public Byte getByteAttribute(String name) { return (Byte) getAttribute(name); } /** {@inheritDoc} */ public Double getDoubleAttribute(String name) { return (Double) getAttribute(name); } /** {@inheritDoc} */ public Integer getIntAttribute(String name) { return (Integer) getAttribute(name); } /** {@inheritDoc} */ public List getListAttribute(String name) { return (List) getAttribute(name); } /** {@inheritDoc} */ public Long getLongAttribute(String name) { return (Long) getAttribute(name); } /** {@inheritDoc} */ public Map getMapAttribute(String name) { return (Map) getAttribute(name); } /** {@inheritDoc} */ public Set getSetAttribute(String name) { return (Set) getAttribute(name); } /** {@inheritDoc} */ public Short getShortAttribute(String name) { return (Short) getAttribute(name); } /** {@inheritDoc} */ public String getStringAttribute(String name) { return (String) getAttribute(name); } /** {@inheritDoc} */ public Object getAttribute(String name) { if (name == null) { return null; } return session.getAttribute(name); } /** {@inheritDoc} */ public Object getAttribute(String name, Object defaultValue) { if (name == null) { return null; } // Synchronize so default value doesn't override other default value synchronized (session) { Object result = session.getAttribute(name); if (result == null && defaultValue != null) { session.setAttribute(name, defaultValue); result = defaultValue; } return result; } } /** {@inheritDoc} */ @SuppressWarnings("unchecked") public Set getAttributeNames() { final Set result = new HashSet(); // Synchronize to prevent parallel modifications synchronized (session) { final Enumeration names = session.getAttributeNames(); while (names.hasMoreElements()) { result.add(names.nextElement()); } } return Collections.unmodifiableSet(result); } /** {@inheritDoc} */ @SuppressWarnings("unchecked") public Map getAttributes() { final Map result = new HashMap(); // Synchronize to prevent parallel modifications synchronized (session) { final Enumeration names = session.getAttributeNames(); while (names.hasMoreElements()) { final String name = names.nextElement(); result.put(name, session.getAttribute(name)); } } return Collections.unmodifiableMap(result); } /** {@inheritDoc} */ public boolean hasAttribute(String name) { if (name == null) { return false; } return (getAttribute(name) != null); } /** {@inheritDoc} */ public boolean removeAttribute(String name) { if (name == null) { return false; } // Synchronize to prevent parallel modifications synchronized (session) { if (!hasAttribute(name)) { return false; } session.removeAttribute(name); } return true; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") public void removeAttributes() { // Synchronize to prevent parallel modifications synchronized (session) { final Enumeration names = session.getAttributeNames(); while (names.hasMoreElements()) { session.removeAttribute(names.nextElement()); } } } /** {@inheritDoc} */ public boolean setAttribute(String name, Object value) { if (name == null) { return false; } if (value == null) { session.removeAttribute(name); } else { session.setAttribute(name, value); } return true; } /** {@inheritDoc} */ public void setAttributes(Map values) { for (Map.Entry entry : values.entrySet()) { final String name = entry.getKey(); final Object value = entry.getValue(); if (name != null && value != null) { session.setAttribute(name, value); } } } /** {@inheritDoc} */ public void setAttributes(IAttributeStore values) { setAttributes(values.getAttributes()); } /** {@inheritDoc} */ public void setBandwidth(int mbits) { throw new UnsupportedOperationException("Not supported in this class"); } /** {@inheritDoc} */ public void addHeader(String name, Object value) { addHeader(name, value, false); } /** {@inheritDoc} */ public void addHeader(String name, Object value, boolean mustUnderstand) { synchronized (headers) { headers.add(new RemotingHeader(name, mustUnderstand, value)); } } /** {@inheritDoc} */ public void removeHeader(String name) { addHeader(name, null, false); } /** {@inheritDoc} */ public Collection getHeaders() { return headers; } /** {@inheritDoc} */ public long getClientBytesRead() { // This is not supported for Remoting connections return 0; } /** * Cleans up the remoting connection client from the HttpSession and client * registry. * This should also fix APPSERVER-328 */ public void cleanup() { if (session != null) { RemotingClient rc = (RemotingClient) session.getAttribute(CLIENT); session.removeAttribute(CLIENT); if (rc != null) { rc.unregister(this); } } } /** Internal class for clients connected through Remoting. */ private static class RemotingClient extends Client { private RemotingClient(String id) { super(id, null); } /** {@inheritDoc} */ @Override protected void register(IConnection conn) { // We only have one connection per client for (IConnection c : getConnections()) { unregister(c); } super.register(conn); } /** {@inheritDoc} */ @Override protected void unregister(IConnection conn) { super.unregister(conn); } } } red5-1.0~svn4374.orig/src/org/red5/server/net/remoting/RemotingHeader.java0000644000175000017500000000353611706617130026221 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.remoting; import org.red5.server.api.remoting.IRemotingHeader; /** * Remoting header to be sent to a server. * * Informations about predefined headers can be found at * http://www.osflash.org/amf/envelopes/remoting/headers * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * */ public class RemotingHeader implements IRemotingHeader { /** * The name of the header. */ protected String name; /** * Is this header required? */ protected boolean required; /** * The actual data of the header. */ protected Object data; /** * Create a new header to be sent through remoting. * * @param name Header name * @param required Header required? * @param data Header data */ public RemotingHeader(String name, boolean required, Object data) { this.name = name; this.required = required; this.data = data; } /** {@inheritDoc} */ public boolean getMustUnderstand() { return required; } /** {@inheritDoc} */ public String getName() { return name; } /** {@inheritDoc} */ public Object getValue() { return data; } } red5-1.0~svn4374.orig/src/org/red5/server/net/remoting/codec/0000755000175000017500000000000011760512572023533 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/net/remoting/codec/RemotingProtocolEncoder.java0000644000175000017500000001427211747635016031216 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.remoting.codec; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.mina.core.buffer.IoBuffer; import org.red5.compatibility.flex.messaging.messages.AbstractMessage; import org.red5.compatibility.flex.messaging.messages.ErrorMessage; import org.red5.io.amf.Output; import org.red5.io.object.Serializer; import org.red5.server.api.Red5; import org.red5.server.api.IConnection.Encoding; import org.red5.server.api.remoting.IRemotingConnection; import org.red5.server.api.remoting.IRemotingHeader; import org.red5.server.exception.ClientDetailsException; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.remoting.FlexMessagingService; import org.red5.server.net.remoting.message.RemotingCall; import org.red5.server.net.remoting.message.RemotingPacket; import org.red5.server.net.rtmp.status.StatusCodes; import org.red5.server.net.rtmp.status.StatusObject; import org.red5.server.service.ServiceNotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Remoting protocol encoder. */ public class RemotingProtocolEncoder { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(RemotingProtocolEncoder.class); /** * Data serializer */ private Serializer serializer; /** * Encodes the given buffer. * * @param state * @param message * @return buffer * @throws Exception */ public IoBuffer encode(ProtocolState state, Object message) throws Exception { RemotingPacket resp = (RemotingPacket) message; IoBuffer buf = IoBuffer.allocate(1024); buf.setAutoExpand(true); Output output; if (resp.getEncoding() == Encoding.AMF0) { buf.putShort((short) 0); // encoded using AMF0 } else { buf.putShort((short) 3); // encoded using AMF3 } IRemotingConnection conn = (IRemotingConnection) Red5.getConnectionLocal(); Collection headers = conn.getHeaders(); buf.putShort((short) headers.size()); // write the header count if (resp.getEncoding() == Encoding.AMF0) { output = new Output(buf); } else { output = new org.red5.io.amf3.Output(buf); } for (IRemotingHeader header: headers) { Output.putString(buf, IRemotingHeader.PERSISTENT_HEADER); output.writeBoolean(false); Map param = new HashMap(); param.put("name", header.getName()); param.put("mustUnderstand", header.getMustUnderstand() ? Boolean.TRUE : Boolean.FALSE); param.put("data", header.getValue()); serializer.serialize(output, param); } headers.clear(); buf.putShort((short) resp.getCalls().size()); // write the number of bodies for (RemotingCall call: resp.getCalls()) { log.debug("Call"); Output.putString(buf, call.getClientResponse()); if (!call.isMessaging) { Output.putString(buf, "null"); } else { Output.putString(buf, ""); } buf.putInt(-1); log.info("result: {}", call.getResult()); if (call.isAMF3) { output = new org.red5.io.amf3.Output(buf); } else { output = new Output(buf); } Object result = call.getClientResult(); if (!call.isSuccess()) { if (call.isMessaging && !(result instanceof ErrorMessage)) { // Generate proper error result for the Flex messaging client AbstractMessage request = (AbstractMessage) call.getArguments()[0]; if (result instanceof ServiceNotFoundException) { ServiceNotFoundException ex = (ServiceNotFoundException) result; result = FlexMessagingService.returnError(request, "serviceNotAvailable", "Flex messaging not activated", ex.getMessage()); } else if (result instanceof Throwable) { result = FlexMessagingService.returnError(request, "Server.Invoke.Error", ((Throwable) result).getMessage(), (Throwable) result); } else { result = FlexMessagingService.returnError(request, "Server.Invoke.Error", result.toString(), ""); } } else if (!call.isMessaging) { // Generate proper error object to return result = generateErrorResult(StatusCodes.NC_CALL_FAILED, call.getException()); } } serializer.serialize(output, result); } buf.flip(); if (log.isDebugEnabled()) { log.debug(">>{}", buf.getHexDump()); } return buf; } /** * Generate error object to return for given exception. * * @param code call * @param error error * @return status object */ protected StatusObject generateErrorResult(String code, Throwable error) { // Construct error object to return String message = ""; while (error != null && error.getCause() != null) { error = error.getCause(); } if (error != null && error.getMessage() != null) { message = error.getMessage(); } StatusObject status = new StatusObject(code, "error", message); if (error instanceof ClientDetailsException) { // Return exception details to client status.setApplication(((ClientDetailsException) error).getParameters()); if (((ClientDetailsException) error).includeStacktrace()) { List stack = new ArrayList(); for (StackTraceElement element: error.getStackTrace()) { stack.add(element.toString()); } status.setAdditional("stacktrace", stack); } } else if (error != null) { status.setApplication(error.getClass().getCanonicalName()); } return status; } /** * Setter for serializer. * * @param serializer New serializer */ public void setSerializer(Serializer serializer) { this.serializer = serializer; } } red5-1.0~svn4374.orig/src/org/red5/server/net/remoting/codec/RemotingCodecFactory.java0000644000175000017500000000413111746326760030455 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.remoting.codec; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; /** * Factory for remoting codec */ public class RemotingCodecFactory { /** * Deserializer */ protected Deserializer deserializer; /** * Serializers */ protected Serializer serializer; /** * Remoting protocol decoder */ protected RemotingProtocolDecoder decoder; /** * Remoting protocol encoder */ protected RemotingProtocolEncoder encoder; /** * Initialization, creates and binds encoder and decoder to serializer and deserializer */ public void init() { decoder = new RemotingProtocolDecoder(); decoder.setDeserializer(deserializer); encoder = new RemotingProtocolEncoder(); encoder.setSerializer(serializer); } /** * Setter for deserializer. * * @param deserializer Deserializer. */ public void setDeserializer(Deserializer deserializer) { this.deserializer = deserializer; } /** * Setter for serializer. * * @param serializer Sserializer. */ public void setSerializer(Serializer serializer) { this.serializer = serializer; } /** * Returns the remoting decoder. * * @return decoder */ public RemotingProtocolDecoder getRemotingDecoder() { return decoder; } /** * Returns the remoting encoder. * * @return encoder */ public RemotingProtocolEncoder getRemotingEncoder() { return encoder; } } red5-1.0~svn4374.orig/src/org/red5/server/net/remoting/codec/RemotingProtocolDecoder.java0000644000175000017500000001513511706617130031173 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.remoting.codec; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.amf.AMF; import org.red5.io.amf3.Input.RefStorage; import org.red5.io.object.Deserializer; import org.red5.io.object.Input; import org.red5.server.net.protocol.ProtocolState; import org.red5.server.net.remoting.FlexMessagingService; import org.red5.server.net.remoting.message.RemotingCall; import org.red5.server.net.remoting.message.RemotingPacket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RemotingProtocolDecoder { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(RemotingProtocolDecoder.class); /** * Data deserializer */ private Deserializer deserializer; /** * Setter for deserializer. * * @param deserializer Deserializer */ public void setDeserializer(Deserializer deserializer) { this.deserializer = deserializer; } /** * Decodes the given buffer. * * @param state * @param buffer * @return a List of {@link RemotingPacket} objects. */ public List decodeBuffer(ProtocolState state, IoBuffer buffer) { List list = new LinkedList(); Object packet = null; try { packet = decode(state, buffer); } catch (Exception e) { log.error("Decoding error", e); packet = null; } if (packet != null) { list.add(packet); } return list; } /** * Decodes the buffer and returns a remoting packet. * * @param state * @param in * @return A {@link RemotingPacket} * @throws Exception */ public Object decode(ProtocolState state, IoBuffer in) throws Exception { Map headers = readHeaders(in); List calls = decodeCalls(in); return new RemotingPacket(headers, calls); } /** * Read remoting headers. * * @param in Input data as byte buffer */ @SuppressWarnings("unchecked") protected Map readHeaders(IoBuffer in) { int version = in.getUnsignedShort(); // skip the version int count = in.getUnsignedShort(); log.debug("Read headers - version: {} count: {}", version, count); if (count == 0) { // No headers present return Collections.EMPTY_MAP; } Deserializer deserializer = new Deserializer(); Input input; if (version == 3) { input = new org.red5.io.amf3.Input(in); } else { input = new org.red5.io.amf.Input(in); } Map result = new HashMap(); for (int i = 0; i < count; i++) { String name = input.getString(); boolean required = in.get() == 0x01; int size = in.getInt(); Object value = deserializer.deserialize(input, Object.class); log.debug("Header: {} Required: {} Size: {} Value: {}", new Object[] { name, required, size, value }); result.put(name, value); } return result; } /** * Decode calls. * * @param in Input data as byte buffer * @return List of pending calls */ protected List decodeCalls(IoBuffer in) { log.debug("Decode calls"); //in.getInt(); List calls = new LinkedList(); org.red5.io.amf.Input input; int count = in.getUnsignedShort(); log.debug("Calls: {}", count); int limit = in.limit(); // Loop over all the body elements for (int i = 0; i < count; i++) { in.limit(limit); String serviceString = org.red5.io.amf.Input.getString(in); String clientCallback = org.red5.io.amf.Input.getString(in); log.debug("callback: {}", clientCallback); Object[] args = null; boolean isAMF3 = false; @SuppressWarnings("unused") int length = in.getInt(); // Set the limit and deserialize // NOTE: disabled because the FP sends wrong values here /* * if (length != -1) in.limit(in.position()+length); */ byte type = in.get(); if (type == AMF.TYPE_ARRAY) { int elements = in.getInt(); List values = new ArrayList(); RefStorage refStorage = null; for (int j = 0; j < elements; j++) { byte amf3Check = in.get(); in.position(in.position() - 1); isAMF3 = (amf3Check == AMF.TYPE_AMF3_OBJECT); if (isAMF3) { if (refStorage == null) { input = new org.red5.io.amf3.Input(in); } else { input = new org.red5.io.amf3.Input(in, refStorage); } } else { input = new org.red5.io.amf.Input(in); } // prepare remoting mode input.reset(); // add deserialized object to the value list values.add(deserializer.deserialize(input, Object.class)); if (isAMF3) { refStorage = ((org.red5.io.amf3.Input) input).getRefStorage(); } } args = values.toArray(new Object[values.size()]); if (log.isDebugEnabled()) { for (Object element : args) { log.debug("> " + element); } } } else if (type == AMF.TYPE_NULL) { log.debug("Got null amf type"); } else if (type != AMF.TYPE_ARRAY) { throw new RuntimeException("AMF0 array type expected but found " + type); } String serviceName; String serviceMethod; int dotPos = serviceString.lastIndexOf('.'); if (dotPos != -1) { serviceName = serviceString.substring(0, dotPos); serviceMethod = serviceString.substring(dotPos + 1, serviceString.length()); } else { serviceName = ""; serviceMethod = serviceString; } boolean isMessaging = false; if ("".equals(serviceName) && "null".equals(serviceMethod)) { // Use fixed service and method name for Flex messaging requests, // this probably will change in the future. serviceName = FlexMessagingService.SERVICE_NAME; serviceMethod = "handleRequest"; isMessaging = true; } log.debug("Service: {} Method: {}", serviceName, serviceMethod); // Add the call to the list calls.add(new RemotingCall(serviceName, serviceMethod, args, clientCallback, isAMF3, isMessaging)); } return calls; } } red5-1.0~svn4374.orig/src/org/red5/server/net/remoting/FlexMessagingService.java0000644000175000017500000004541411745776105027415 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.net.remoting; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.commons.beanutils.ConversionException; import org.apache.commons.lang3.StringUtils; import org.red5.compatibility.flex.data.messages.DataMessage; import org.red5.compatibility.flex.data.messages.SequencedMessage; import org.red5.compatibility.flex.messaging.messages.AbstractMessage; import org.red5.compatibility.flex.messaging.messages.AcknowledgeMessage; import org.red5.compatibility.flex.messaging.messages.AcknowledgeMessageExt; import org.red5.compatibility.flex.messaging.messages.AsyncMessage; import org.red5.compatibility.flex.messaging.messages.AsyncMessageExt; import org.red5.compatibility.flex.messaging.messages.CommandMessage; import org.red5.compatibility.flex.messaging.messages.CommandMessageExt; import org.red5.compatibility.flex.messaging.messages.Constants; import org.red5.compatibility.flex.messaging.messages.ErrorMessage; import org.red5.compatibility.flex.messaging.messages.Message; import org.red5.compatibility.flex.messaging.messages.RemotingMessage; import org.red5.io.utils.RandomGUID; import org.red5.server.api.IClient; import org.red5.server.api.Red5; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.api.service.IServiceInvoker; import org.red5.server.exception.ClientDetailsException; import org.red5.server.messaging.ServiceAdapter; import org.red5.server.util.ConversionUtils; import org.red5.server.service.PendingCall; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Service that can execute compatibility Flex messages. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public class FlexMessagingService { /** Name of the service. */ public static final String SERVICE_NAME = "flexMessaging"; /** * Logger */ protected static Logger log = LoggerFactory.getLogger(FlexMessagingService.class); /** Service invoker to use. */ protected IServiceInvoker serviceInvoker; /** Configured endpoints. */ @SuppressWarnings("unchecked") protected Map endpoints = Collections.EMPTY_MAP; /** Registered clients. */ protected ConcurrentMap registrations = null; /** * Setup available end points. * * @param endpoints end points */ public void setEndpoints(Map endpoints) { this.endpoints = endpoints; log.info("Configured endpoints: {}", endpoints); } /** * Set the service invoker to use. * * @param serviceInvoker service invoker */ public void setServiceInvoker(IServiceInvoker serviceInvoker) { this.serviceInvoker = serviceInvoker; } /** * Construct error message. * * @param request request * @param faultCode fault code * @param faultString fault string * @param faultDetail fault detail * @return error message */ public static ErrorMessage returnError(AbstractMessage request, String faultCode, String faultString, String faultDetail) { ErrorMessage result = new ErrorMessage(); result.timestamp = System.currentTimeMillis(); result.headers = request.headers; result.destination = request.destination; result.correlationId = request.messageId; result.faultCode = faultCode; result.faultString = faultString; result.faultDetail = faultDetail; return result; } /** * Construct error message from exception. * * @param request request * @param faultCode fault code * @param faultString fautl string * @param error error * @return message */ public static ErrorMessage returnError(AbstractMessage request, String faultCode, String faultString, Throwable error) { ErrorMessage result = returnError(request, faultCode, faultString, ""); if (error instanceof ClientDetailsException) { result.extendedData = ((ClientDetailsException) error).getParameters(); if (((ClientDetailsException) error).includeStacktrace()) { StringBuilder stack = new StringBuilder(); for (StackTraceElement element : error.getStackTrace()) { stack.append(element.toString()).append('\n'); } result.faultDetail = stack.toString(); } } result.rootCause = error; return result; } /** * Handle request coming from mx:RemoteObject tags. * * @see Adobe Livedocs (external) * * @param msg message * @return aynsc message */ public AsyncMessage handleRequest(RemotingMessage msg) { log.debug("Handle RemotingMessage request"); log.trace("{}", msg); setClientId(msg); if (serviceInvoker == null) { log.error("No service invoker configured: {}", msg); return returnError(msg, "Server.Invoke.Error", "No service invoker configured.", "No service invoker configured."); } Object endpoint = endpoints.get(msg.destination); log.debug("End point / destination: {}", endpoint); if (endpoint == null) { String errMsg = String.format("Endpoint %s doesn't exist.", msg.destination); log.debug("{} ({})", errMsg, msg); return returnError(msg, "Server.Invoke.Error", errMsg, errMsg); } //prepare an ack message AcknowledgeMessage result = new AcknowledgeMessage(); result.setClientId(msg.getClientId()); result.setCorrelationId(msg.getMessageId()); //grab any headers Map headers = msg.getHeaders(); log.debug("Headers: {}", headers); //if (headers.containsKey(Message.FLEX_CLIENT_ID_HEADER)) { // headers.put(Message.FLEX_CLIENT_ID_HEADER, msg.getClientId()); //} //result.setHeaders(headers); //get the operation String operation = msg.operation; log.debug("Operation: {}", operation); if (endpoint instanceof ServiceAdapter) { log.debug("Endpoint is a ServiceAdapter so message will be invoked"); ServiceAdapter adapter = (ServiceAdapter) endpoint; //the result of the invocation will make up the message body result.body = adapter.invoke(msg); } else { //get arguments Object[] args = null; try { log.debug("Body: {} type: {}", msg.body, msg.body.getClass().getName()); args = (Object[]) ConversionUtils.convert(msg.body, Object[].class); } catch (ConversionException cex) { //if the conversion fails and the endpoint is not a ServiceAdapter //just drop the object directly into an array args = new Object[]{msg.body}; } IPendingServiceCall call = new PendingCall(operation, args); try { if (!serviceInvoker.invoke(call, endpoint)) { if (call.getException() != null) { // Use regular exception handling Throwable err = call.getException(); return returnError(msg, "Server.Invoke.Error", err.getMessage(), err); } return returnError(msg, "Server.Invoke.Error", "Can't invoke method.", ""); } } catch (Throwable err) { log.error("Error while invoking method.", err); return returnError(msg, "Server.Invoke.Error", err.getMessage(), err); } //we got a valid result from the method call. result.body = call.getResult(); } return result; } /** * Handle command message (external) request. * * @param msg message * @return message */ public Message handleRequest(CommandMessageExt msg) { log.debug("Handle CommandMessageExt request"); log.trace("{}", msg); setClientId(msg); String clientId = msg.getClientId(); //process messages to non-service adapter end-points switch (msg.operation) { case Constants.POLL_OPERATION: //2 //send back modifications log.debug("Poll: {}", clientId); //send back stored updates for this client if (registrations.containsKey(clientId)) { ServiceAdapter adapter = registrations.get(clientId); if (adapter != null) { CommandMessage result = new CommandMessage(); result.setOperation(Constants.CLIENT_SYNC_OPERATION); //result.setCorrelationId(msg.getMessageId()); //this will be the body of the responding command message AsyncMessageExt ext = new AsyncMessageExt(); ext.setClientId(clientId); ext.setCorrelationId(msg.getMessageId()); ext.setDestination("Red5Chat"); ext.setBody(adapter.manage(msg)); /* //grab any headers Map headers = msg.getHeaders(); log.debug("Headers: {}", headers); if (headers.containsKey(Message.FLEX_CLIENT_ID_HEADER)) { headers.put(Message.FLEX_CLIENT_ID_HEADER, msg.getClientId()); } ext.setHeaders(headers); */ //add as a child (body) of the command message result.setBody(new Object[]{ext}); return result; } else { log.warn("Adapter was not available"); } } break; default: log.error("Unhandled CommandMessageExt request: {}", msg); String errMsg = String.format("Don't know how to handle %s", msg); return returnError(msg, "notImplemented", errMsg, errMsg); } AcknowledgeMessageExt result = new AcknowledgeMessageExt(); result.setClientId(clientId); result.setCorrelationId(msg.getMessageId()); return result; } /** * Handle command message request. * * @param msg message * @return message */ public Message handleRequest(CommandMessage msg) { log.debug("Handle CommandMessage request"); log.trace("{}", msg); setClientId(msg); String clientId = msg.getClientId(); //grab any headers Map headers = msg.getHeaders(); log.debug("Headers: {}", headers); if (headers.containsKey(Message.FLEX_CLIENT_ID_HEADER)) { headers.put(Message.FLEX_CLIENT_ID_HEADER, msg.getClientId()); } String destination = msg.getDestination(); log.debug("Destination: {}", destination); //process messages to non-service adapter end-points switch (msg.operation) { case Constants.CLIENT_PING_OPERATION: //5 //send back pong message break; case Constants.POLL_OPERATION: //2 //send back modifications log.debug("Poll: {}", clientId); //send back stored updates for this client if (registrations.containsKey(clientId)) { ServiceAdapter adapter = registrations.get(clientId); if (adapter != null) { CommandMessage result = new CommandMessage(); result.setOperation(Constants.CLIENT_SYNC_OPERATION); //result.setCorrelationId(msg.getMessageId()); //this will be the body of the responding command message AsyncMessageExt ext = new AsyncMessageExt(); ext.setClientId(clientId); ext.setCorrelationId(msg.getMessageId()); ext.setDestination("Red5Chat"); ext.setBody(adapter.manage(msg)); //add as a child (body) of the command message result.setBody(new Object[]{ext}); return result; } else { log.debug("Adapter was not available"); } } break; case Constants.SUBSCRIBE_OPERATION: //0 log.debug("Subscribe: {}", clientId); //if there is a destination check for an adapter if (StringUtils.isNotBlank(destination)) { //look-up end-point and register if (endpoints.containsKey(destination)) { Object endpoint = endpoints.get(destination); //if the endpoint is an adapter, try to subscribe if (endpoint instanceof ServiceAdapter) { ServiceAdapter adapter = (ServiceAdapter) endpoint; boolean subscribed = ((Boolean) adapter.manage(msg)); if (subscribed) { log.debug("Client was subscribed"); registerClientToAdapter(clientId, adapter); } else { log.debug("Client was not subscribed"); } } } } // Send back registration ok break; case Constants.UNSUBSCRIBE_OPERATION: //1 log.trace("Unsubscribe: {}", clientId); if (registrations.containsKey(clientId)) { ServiceAdapter adapter = registrations.get(clientId); boolean unsubscribed = ((Boolean) adapter.manage(msg)); if (unsubscribed) { log.debug("Client was unsubscribed"); unregisterClientFromAdapter(clientId); } else { log.debug("Client was not unsubscribed"); } } else { log.debug("Client was not subscribed"); } // Send back unregistration ok break; default: log.error("Unknown CommandMessage request: {}", msg); String errMsg = String.format("Don't know how to handle %s", msg); return returnError(msg, "notImplemented", errMsg, errMsg); } AcknowledgeMessage result = new AcknowledgeMessage(); result.setBody(msg.getBody()); result.setClientId(clientId); result.setCorrelationId(msg.getMessageId()); result.setHeaders(headers); // put destination in ack if it exists if (StringUtils.isNotBlank(destination)) { result.setDestination(destination); } return result; } /** * Evaluate update requests sent by a client. * * @param msg * @param event */ @SuppressWarnings("unchecked") private void evaluateDataUpdate(DataMessage msg, DataMessage event) { switch (event.operation) { case Constants.DATA_OPERATION_UPDATE_ATTRIBUTES: List contents = (List) event.body; @SuppressWarnings("unused") List attributeNames = (List) contents.get(0); @SuppressWarnings("unused") Map oldValues = (Map) contents.get(1); @SuppressWarnings("unused") Map newValues = (Map) contents.get(2); /* // Commented out as it triggeres a crash in the compiler on Java 1.5 for (@SuppressWarnings("unused") String name: attributeNames) { // TODO: store attribute change for registered clients } */ break; default: log.error("Unknown data update request: {}", event); } } /** * Handle messages related to shared objects. * * @param msg message * @return async message */ @SuppressWarnings("unchecked") public AsyncMessage handleRequest(DataMessage msg) { log.debug("Handle DataMessage request"); log.trace("{}", msg); setClientId(msg); SequencedMessage result = new SequencedMessage(); result.clientId = msg.clientId; result.destination = msg.destination; result.correlationId = msg.messageId; switch (msg.operation) { case Constants.DATA_OPERATION_SET: result.body = new Object[] { msg.body }; result.sequenceId = 0; result.sequenceSize = 1; // TODO: store initial version of object break; case Constants.DATA_OPERATION_UPDATE: for (DataMessage event : (List) msg.body) { evaluateDataUpdate(msg, event); } AcknowledgeMessage res = new AcknowledgeMessage(); res.clientId = msg.clientId; res.destination = msg.destination; res.correlationId = msg.messageId; res.body = msg.body; return res; default: log.error("Unknown DataMessage request: {}", msg); String errMsg = String.format("Don't know how to handle %s", msg); return returnError(msg, "notImplemented", errMsg, errMsg); } return result; } /** * Fallback method to handle arbitrary messages. * * @param msg message * @return error message */ public Message handleRequest(AbstractMessage msg) { log.debug("Handle AbstractMessage request"); log.trace("{}", msg); setClientId(msg); Object endpoint = endpoints.get(msg.getDestination()); log.debug("End point / destination: {}", endpoint); if (endpoint == null) { String errMsg = String.format("Endpoint %s doesn't exist.", msg.getDestination()); log.debug("{} ({})", errMsg, msg); return returnError(msg, "Server.Invoke.Error", errMsg, errMsg); } //grab any headers Map headers = msg.getHeaders(); log.debug("Headers: {}", headers); if (headers.containsKey(Message.FLEX_CLIENT_ID_HEADER)) { headers.remove(Message.FLEX_CLIENT_ID_HEADER); } if (headers.containsKey(Message.ENDPOINT_HEADER)) { headers.remove(Message.ENDPOINT_HEADER); } if (endpoint instanceof ServiceAdapter) { log.debug("Endpoint is a ServiceAdapter so message will be invoked"); //prepare an ack message AcknowledgeMessage result = new AcknowledgeMessage(); result.setClientId(msg.getClientId()); result.setCorrelationId(msg.getMessageId()); result.setDestination(msg.getDestination()); result.setHeaders(headers); //get the adapter ServiceAdapter adapter = (ServiceAdapter) endpoint; //log.debug("Invoke: {}", adapter.invoke(msg)); Object o = adapter.invoke(msg); //the result of the invocation will make up the message body //AsyncMessage ext = new AsyncMessage(); //ext.setClientId(msg.getClientId()); //ext.setCorrelationId(result.getMessageId()); //ext.setBody(o); result.setBody(new Object[]{o}); return result; } else { log.error("Unknown Flex compatibility request: {}", msg); String errMsg = String.format("Don't know how to handle %s", msg); return returnError(msg, "notImplemented", errMsg, errMsg); } } /** * This is mandatory for client built from Flex 3 or later, or * client will hang with concurrent accesses. * @param msg */ private void setClientId(AbstractMessage msg) { String clientId = msg.getClientId(); if (clientId == null || "null".equals(clientId)) { log.trace("Dump: {}", msg); //use the connection client id before creating a new one IClient client = Red5.getConnectionLocal().getClient(); if (client != null) { //should we format it? clientId = client.getId(); msg.setClientId(RandomGUID.getPrettyFormatted(clientId)); } else { msg.setClientId(new RandomGUID().toString()); } } } /** * Maps a client to an adapter for lookups on messages that do not contain a destination. * * @param clientId a subscribed client id * @param adapter service adapter to register for */ private final void registerClientToAdapter(String clientId, ServiceAdapter adapter) { if (registrations == null) { registrations = new ConcurrentHashMap(); } registrations.put(clientId, adapter); } /** * Removes a mapping for a client with an adapter. * * @param clientId a subscribed client id */ private final void unregisterClientFromAdapter(String clientId) { registrations.remove(clientId); } } red5-1.0~svn4374.orig/src/org/red5/server/Context.java0000644000175000017500000002675411754746347022365 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.beans.ConstructorProperties; import java.io.IOException; import javax.management.openmbean.CompositeData; import org.red5.server.api.IClientRegistry; import org.red5.server.api.IContext; import org.red5.server.api.IMappingStrategy; import org.red5.server.api.persistence.IPersistenceStore; import org.red5.server.api.scope.IGlobalScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeHandler; import org.red5.server.api.scope.IScopeResolver; import org.red5.server.api.service.IServiceInvoker; import org.red5.server.exception.ScopeHandlerNotFoundException; import org.red5.server.jmx.mxbeans.ContextMXBean; import org.red5.server.service.ServiceNotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.access.ContextSingletonBeanFactoryLocator; import org.springframework.core.io.Resource; /** *

* This is basic context implementation used by Red5. *

*/ public class Context implements IContext, ApplicationContextAware, ContextMXBean { public static Logger logger = LoggerFactory.getLogger(Context.class); /** * Spring application context */ private ApplicationContext applicationContext; /** * Core context */ private BeanFactory coreContext; /** * Context path */ private String contextPath = ""; /** * Scope resolver collaborator */ private IScopeResolver scopeResolver; /** * Client registry */ private IClientRegistry clientRegistry; /** * Service invoker collaborator */ private IServiceInvoker serviceInvoker; /** * Mapping stategy collaborator */ private IMappingStrategy mappingStrategy; /** * Persistence store */ private IPersistenceStore persistanceStore; /** * Initializes core context bean factory using red5.core bean factory from * red5.xml context */ @ConstructorProperties(value = { "" }) public Context() { } /** * Initializes app context and context path from given parameters * * @param context Application context * @param contextPath Context path */ @ConstructorProperties({"context", "contextPath"}) public Context(ApplicationContext context, String contextPath) { setApplicationContext(context); this.contextPath = contextPath; } /** * Return global scope * * @return Global scope */ public IGlobalScope getGlobalScope() { IGlobalScope gs = scopeResolver.getGlobalScope(); logger.trace("Global scope: {}", gs); return gs; } /** * Return scope resolver * * @return scope resolver */ public IScopeResolver getScopeResolver() { return scopeResolver; } /** * Resolves scope using scope resolver collaborator * * @param path Path to resolve * @return Scope resolution result */ public IScope resolveScope(String path) { return scopeResolver.resolveScope(path); } /** * Resolves scope from given root using scope resolver. * * @param root Scope to start from. * @param path Path to resolve. * @return Scope resolution result. */ public IScope resolveScope(IScope root, String path) { return scopeResolver.resolveScope(root, path); } /** * Setter for client registry * * @param clientRegistry Client registry */ public void setClientRegistry(IClientRegistry clientRegistry) { this.clientRegistry = clientRegistry; } /** * Setter for mapping strategy * * @param mappingStrategy Mapping strategy */ public void setMappingStrategy(IMappingStrategy mappingStrategy) { this.mappingStrategy = mappingStrategy; } /** * Setter for scope resolver * * @param scopeResolver Scope resolver used to resolve scopes */ public void setScopeResolver(IScopeResolver scopeResolver) { this.scopeResolver = scopeResolver; } /** * Setter for service invoker * * @param serviceInvoker Service invoker object */ public void setServiceInvoker(IServiceInvoker serviceInvoker) { this.serviceInvoker = serviceInvoker; } /** * Return persistence store * * @return Persistence store */ public IPersistenceStore getPersistanceStore() { return persistanceStore; } /** * Setter for persistence store * * @param persistanceStore Persistence store */ public void setPersistanceStore(IPersistenceStore persistanceStore) { this.persistanceStore = persistanceStore; } /** * Setter for application context * * @param context App context */ public void setApplicationContext(ApplicationContext context) { this.applicationContext = context; String deploymentType = System.getProperty("red5.deployment.type"); logger.debug("Deployment type: " + deploymentType); if (deploymentType == null) { // standalone core context String config = System.getProperty("red5.conf_file"); if (config == null) { config = "red5.xml"; } coreContext = ContextSingletonBeanFactoryLocator.getInstance(config).useBeanFactory("red5.core") .getFactory(); } else { logger.info("Setting parent bean factory as core"); coreContext = applicationContext.getParentBeanFactory(); } } /** * Return application context * * @return App context */ public ApplicationContext getApplicationContext() { return applicationContext; } /** * Setter for context path. Adds a slash at the end of path if there isn't one * * @param contextPath Context path */ public void setContextPath(String contextPath) { if (!contextPath.endsWith("/")) { contextPath += '/'; } this.contextPath = contextPath; } /** * Return client registry * * @return Client registry */ public IClientRegistry getClientRegistry() { return clientRegistry; } /** * Return scope * * @return null */ public IScope getScope() { return null; } /** * Return service invoker * * @return Service invoker */ public IServiceInvoker getServiceInvoker() { return serviceInvoker; } /** * Look up service by name * * @param serviceName Service name * @return Service object * @throws ServiceNotFoundException When service found but null * @throws NoSuchBeanDefinitionException When bean with given name doesn't exist */ public Object lookupService(String serviceName) { serviceName = getMappingStrategy().mapServiceName(serviceName); try { Object bean = applicationContext.getBean(serviceName); if (bean != null) { return bean; } else { throw new ServiceNotFoundException(serviceName); } } catch (NoSuchBeanDefinitionException err) { throw new ServiceNotFoundException(serviceName); } } /** * Look up scope handler for context path * * @param contextPath Context path * @return Scope handler * @throws ScopeHandlerNotFoundException If there's no handler for given context path */ public IScopeHandler lookupScopeHandler(String contextPath) { // Get target scope handler name String scopeHandlerName = getMappingStrategy().mapScopeHandlerName(contextPath); // Get bean from bean factory Object bean = applicationContext.getBean(scopeHandlerName); if (bean != null && bean instanceof IScopeHandler) { return (IScopeHandler) bean; } else { throw new ScopeHandlerNotFoundException(scopeHandlerName); } } /** * Return mapping strategy used by this context. Mapping strategy define * naming rules (prefixes, postfixes, default application name, etc) for all * named objects in context. * * @return Mapping strategy */ public IMappingStrategy getMappingStrategy() { return mappingStrategy; } /** * Return array or resournce that match given pattern * * @param pattern Pattern to check against * @return Array of Resource objects * @throws IOException On I/O exception * * @see org.springframework.core.io.Resource */ public Resource[] getResources(String pattern) throws IOException { return applicationContext.getResources(contextPath + pattern); } /** * Return resouce by path * * @param path Resource path * @return Resource * * @see org.springframework.core.io.Resource */ public Resource getResource(String path) { return applicationContext.getResource(contextPath + path); } /** * Resolve scope from host and path * * @param host Host * @param path Path * @return Scope * * @see org.red5.server.api.scope.IScope * @see org.red5.server.scope.Scope */ public IScope resolveScope(String host, String path) { return scopeResolver.resolveScope(path); } /** * {@inheritDoc} */ public boolean hasBean(String beanId) { return applicationContext.containsBean(beanId); } /** * Return bean instantiated by bean factory * * @param beanId Bean name * @return Instantiated bean * * @see org.springframework.beans.factory.BeanFactory */ public Object getBean(String beanId) { // for war applications the "application" beans are not stored in the // sub-contexts, so look in the application context first and the core // context second Object bean = null; try { bean = applicationContext.getBean(beanId); } catch (NoSuchBeanDefinitionException e) { logger.warn("Bean lookup failed for {} in the application context", beanId, e); } if (bean == null) { bean = getCoreService(beanId); } return bean; } /** * Return core Red5 service instantiated by core context bean factory * * @param beanId Bean name * @return Core Red5 service instantiated * * @see org.springframework.beans.factory.BeanFactory */ public Object getCoreService(String beanId) { return coreContext.getBean(beanId); } public void setCoreBeanFactory(BeanFactory core) { coreContext = core; } /** * Return current thread's context classloader * * @return Classloder context of current thread */ public ClassLoader getClassLoader() { return applicationContext.getClassLoader(); } /** * Allows for reconstruction via CompositeData. * * @param cd composite data * @return Context class instance */ public static Context from(CompositeData cd) { Context instance = new Context(); if (cd.containsKey("context") && cd.containsKey("contextPath")) { Object context = cd.get("context"); Object contextPath = cd.get("contextPath"); if (context != null && contextPath != null) { instance = new Context((ApplicationContext) context, (String) contextPath); } } return instance; } } red5-1.0~svn4374.orig/src/org/red5/server/so/0000755000175000017500000000000011760512571020464 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/so/ISharedObjectEvent.java0000644000175000017500000000376111706617130025003 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.so; /** * One update event for a shared object received through a connection. */ public interface ISharedObjectEvent { enum Type { SERVER_CONNECT, SERVER_DISCONNECT, SERVER_SET_ATTRIBUTE, SERVER_DELETE_ATTRIBUTE, SERVER_SEND_MESSAGE, CLIENT_CLEAR_DATA, CLIENT_DELETE_ATTRIBUTE, CLIENT_DELETE_DATA, CLIENT_INITIAL_DATA, CLIENT_STATUS, CLIENT_UPDATE_DATA, CLIENT_UPDATE_ATTRIBUTE, CLIENT_SEND_MESSAGE }; /** * Returns the type of the event. * * @return the type of the event. */ public Type getType(); /** * Returns the key of the event. * * Depending on the type this contains: *
    *
  • the attribute name to set for SET_ATTRIBUTE
  • *
  • the attribute name to delete for DELETE_ATTRIBUTE
  • *
  • the handler name to call for SEND_MESSAGE
  • *
* In all other cases the key is null. * * @return the key of the event */ public String getKey(); /** * Returns the value of the event. * * Depending on the type this contains: *
    *
  • the attribute value to set for SET_ATTRIBUTE
  • *
  • a list of parameters to pass to the handler for SEND_MESSAGE
  • *
* In all other cases the value is null. * * @return the value of the event */ public Object getValue(); } red5-1.0~svn4374.orig/src/org/red5/server/so/FlexSharedObjectMessage.java0000644000175000017500000000345111706617130026010 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.so; import org.red5.server.api.event.IEventListener; public class FlexSharedObjectMessage extends SharedObjectMessage { private static final long serialVersionUID = -6458750398936033347L; public FlexSharedObjectMessage() { } /** * Creates Flex Shared Object event with given name, version and persistence flag * * @param name Event name * @param version SO version * @param persistent SO persistence flag */ public FlexSharedObjectMessage(String name, int version, boolean persistent) { this(null, name, version, persistent); } /** * Creates Flex Shared Object event with given listener, name, SO version and persistence flag * * @param source Event listener * @param name Event name * @param version SO version * @param persistent SO persistence flag */ public FlexSharedObjectMessage(IEventListener source, String name, int version, boolean persistent) { super(source, name, version, persistent); } /** {@inheritDoc} */ @Override public byte getDataType() { return TYPE_FLEX_SHARED_OBJECT; } }red5-1.0~svn4374.orig/src/org/red5/server/so/ClientSharedObject.java0000644000175000017500000002357111706617130025030 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.so; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.locks.ReentrantLock; import org.red5.server.api.IAttributeStore; import org.red5.server.api.IConnection; import org.red5.server.api.event.IEvent; import org.red5.server.api.event.IEventDispatcher; import org.red5.server.api.event.IEventListener; import org.red5.server.api.so.IClientSharedObject; import org.red5.server.api.so.ISharedObjectListener; import org.red5.server.net.rtmp.Channel; import org.red5.server.net.rtmp.RTMPConnection; import org.red5.server.so.ISharedObjectEvent.Type; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Works with client-side shared object */ @SuppressWarnings("unchecked") public class ClientSharedObject extends SharedObject implements IClientSharedObject, IEventDispatcher { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(ClientSharedObject.class); /** * Initial synchronization flag */ private boolean initialSyncReceived; /** * Synchronization lock */ private final ReentrantLock lock = new ReentrantLock(); /** * Set of listeners */ private Set listeners = new CopyOnWriteArraySet(); /** * Set of event handlers */ private ConcurrentMap handlers = new ConcurrentHashMap(); /** * Create new client SO with * * @param name Shared Object name * @param persistent Persistence flag */ public ClientSharedObject(String name, boolean persistent) { super(); this.name = name; this.persistent = persistent; } /** * Connect the shared object using the passed connection. * * @param conn Attach SO to given connection */ public void connect(IConnection conn) { if (!(conn instanceof RTMPConnection)) { throw new RuntimeException("can only connect through RTMP connections"); } if (isConnected()) { throw new RuntimeException("already connected"); } source = conn; SharedObjectMessage msg = new SharedObjectMessage(name, 0, isPersistent()); msg.addEvent(new SharedObjectEvent(Type.SERVER_CONNECT, null, null)); Channel c = ((RTMPConnection) conn).getChannel((byte) 3); c.write(msg); } /** {@inheritDoc} */ public void disconnect() { SharedObjectMessage msg = new SharedObjectMessage(name, 0, isPersistent()); msg.addEvent(new SharedObjectEvent(Type.SERVER_DISCONNECT, null, null)); Channel c = ((RTMPConnection) source).getChannel((byte) 3); c.write(msg); notifyDisconnect(); initialSyncReceived = false; } /** {@inheritDoc} */ public boolean isConnected() { return initialSyncReceived; } /** {@inheritDoc} */ public void addSharedObjectListener(ISharedObjectListener listener) { listeners.add(listener); } /** {@inheritDoc} */ public void removeSharedObjectListener(ISharedObjectListener listener) { listeners.remove(listener); } /** {@inheritDoc} */ public void dispatchEvent(IEvent e) { if (e instanceof ISharedObjectMessage || e.getType() == IEvent.Type.SHARED_OBJECT) { ISharedObjectMessage msg = (ISharedObjectMessage) e; if (msg.hasSource()) { beginUpdate(msg.getSource()); } else { beginUpdate(); } try { for (ISharedObjectEvent event : msg.getEvents()) { switch (event.getType()) { case CLIENT_INITIAL_DATA: initialSyncReceived = true; notifyConnect(); break; case CLIENT_CLEAR_DATA: attributes.clear(); notifyClear(); break; case CLIENT_DELETE_DATA: case CLIENT_DELETE_ATTRIBUTE: attributes.remove(event.getKey()); notifyDelete(event.getKey()); break; case CLIENT_SEND_MESSAGE: notifySendMessage(event.getKey(), (List) event.getValue()); break; case CLIENT_UPDATE_DATA: attributes.putAll((Map) event.getValue()); notifyUpdate(event.getKey(), (Map) event.getValue()); break; case CLIENT_UPDATE_ATTRIBUTE: Object val = event.getValue(); // null values are not allowed in concurrent hash maps if (val != null) { attributes.put(event.getKey(), val); } // we will however send the null out to the subscribers notifyUpdate(event.getKey(), val); break; default: log.warn("Unknown SO event: {}", event.getType()); } } } finally { endUpdate(); } } } /** * Notify listeners on event */ protected void notifyConnect() { for (ISharedObjectListener listener : listeners) { listener.onSharedObjectConnect(this); } } /** * Notify listeners on disconnect */ protected void notifyDisconnect() { for (ISharedObjectListener listener : listeners) { listener.onSharedObjectDisconnect(this); } } /** * Notify listeners on update * * @param key * Updated attribute key * @param value * Updated attribute value */ protected void notifyUpdate(String key, Object value) { for (ISharedObjectListener listener : listeners) { listener.onSharedObjectUpdate(this, key, value); } } /** * Notify listeners on map attribute update * * @param key * Updated attribute key * @param value * Updated attribute value */ protected void notifyUpdate(String key, Map value) { if (value.size() == 1) { Map.Entry entry = value.entrySet().iterator().next(); notifyUpdate(entry.getKey(), entry.getValue()); return; } for (ISharedObjectListener listener : listeners) { listener.onSharedObjectUpdate(this, key, value); } } /** * Notify listeners on attribute delete * * @param key * Attribute name */ protected void notifyDelete(String key) { for (ISharedObjectListener listener : listeners) { listener.onSharedObjectDelete(this, key); } } /** * Notify listeners on clear */ protected void notifyClear() { for (ISharedObjectListener listener : listeners) { listener.onSharedObjectClear(this); } } /** * Broadcast send event to listeners * * @param method * Method name * @param params * Params */ protected void notifySendMessage(String method, List params) { for (ISharedObjectListener listener : listeners) { listener.onSharedObjectSend(this, method, params); } } /** {@inheritDoc} */ @Override public boolean setAttribute(String name, Object value) { if (value == null) { return removeAttribute(name); } ownerMessage.addEvent(Type.SERVER_SET_ATTRIBUTE, name, value); notifyModified(); return true; } /** {@inheritDoc} */ @Override public void setAttributes(IAttributeStore values) { setAttributes(values.getAttributes()); } /** {@inheritDoc} */ @Override public void setAttributes(Map values) { for (Map.Entry entry : values.entrySet()) { setAttribute(entry.getKey(), entry.getValue()); } } /** {@inheritDoc} */ @Override public boolean removeAttribute(String name) { ownerMessage.addEvent(Type.SERVER_DELETE_ATTRIBUTE, name, null); notifyModified(); return true; } /** {@inheritDoc} */ @Override public void sendMessage(String handler, List arguments) { ownerMessage.addEvent(Type.SERVER_SEND_MESSAGE, handler, arguments); notifyModified(); } /** {@inheritDoc} */ @Override public void removeAttributes() { // TODO: there must be a direct way to clear the SO on the client // side... for (String key : getAttributeNames()) { ownerMessage.addEvent(Type.SERVER_DELETE_ATTRIBUTE, key, null); } notifyModified(); } /** {@inheritDoc} */ @Override public boolean clear() { return super.clear(); } /** {@inheritDoc} */ @Override public void close() { super.close(); } /** {@inheritDoc} */ @Override public void beginUpdate() { lock(); super.beginUpdate(); } /** {@inheritDoc} */ @Override public void beginUpdate(IEventListener listener) { lock(); super.beginUpdate(listener); } /** {@inheritDoc} */ @Override public void endUpdate() { super.endUpdate(); unlock(); } /** {@inheritDoc} */ public void lock() { lock.lock(); } /** {@inheritDoc} */ public void unlock() { lock.unlock(); } /** {@inheritDoc} */ public boolean isLocked() { return lock.isLocked(); } /** {@inheritDoc} */ public void registerServiceHandler(Object handler) { registerServiceHandler("", handler); } /** {@inheritDoc} */ public void unregisterServiceHandler(String name) { handlers.remove(name); } /** {@inheritDoc} */ public void registerServiceHandler(String name, Object handler) { if (name == null) { name = ""; } handlers.put(name, handler); } /** {@inheritDoc} */ public Object getServiceHandler(String name) { if (name == null) { name = ""; } return handlers.get(name); } /** {@inheritDoc} */ public Set getServiceHandlerNames() { return Collections.unmodifiableSet(handlers.keySet()); } /** {@inheritDoc} */ public Object getAttribute(String name, Object defaultValue) { if (!hasAttribute(name)) { setAttribute(name, defaultValue); } return getAttribute(name); } } red5-1.0~svn4374.orig/src/org/red5/server/so/SharedObject.java0000644000175000017500000005401111747635016023672 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.so; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; import org.red5.io.object.Deserializer; import org.red5.io.object.Input; import org.red5.io.object.Output; import org.red5.io.object.Serializer; import org.red5.server.AttributeStore; import org.red5.server.api.IAttributeStore; import org.red5.server.api.IConnection.Encoding; import org.red5.server.api.event.IEventListener; import org.red5.server.api.persistence.IPersistable; import org.red5.server.api.persistence.IPersistenceStore; import org.red5.server.api.scope.ScopeType; import org.red5.server.api.statistics.ISharedObjectStatistics; import org.red5.server.api.statistics.support.StatisticsCounter; import org.red5.server.net.rtmp.Channel; import org.red5.server.net.rtmp.RTMPConnection; import org.red5.server.net.rtmp.message.Constants; import org.red5.server.so.ISharedObjectEvent.Type; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Represents shared object on server-side. Shared Objects in Flash are like cookies that are stored * on client side. In Red5 and Flash Media Server there's one more special type of SOs : remote Shared Objects. * * These are shared by multiple clients and synchronized between them automatically on each data change. This is done * asynchronously, used as events handling and is widely used in multiplayer Flash online games. * * Shared object can be persistent or transient. The difference is that first are saved to the disk and can be * accessed later on next connection, transient objects are not saved and get lost each time they last client * disconnects from it. * * Shared Objects has name identifiers and path on server's HD (if persistent). On deeper level server-side * Shared Object in this implementation actually uses IPersistenceStore to delegate all (de)serialization work. * * SOs store data as simple map, that is, "name-value" pairs. Each value in turn can be complex object or map. * * All access to methods that change properties in the SO must be properly * synchronized for multi-threaded access. */ public class SharedObject extends AttributeStore implements ISharedObjectStatistics, IPersistable, Constants { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(SharedObject.class); /** * Shared Object name (identifier) */ protected String name = ""; /** * SO path */ protected String path = ""; /** * true if the SharedObject was stored by the persistence framework (NOT in database, * just plain serialization to the disk) and can be used later on reconnection */ protected boolean persistent; /** * Object that is delegated with all storage work for persistent SOs */ protected IPersistenceStore storage; /** * Version. Used on synchronization purposes. */ protected AtomicInteger version = new AtomicInteger(1); /** * Number of pending update operations */ protected AtomicInteger updateCounter = new AtomicInteger(); /** * Has changes? flag */ protected boolean modified; /** * Last modified timestamp */ protected long lastModified = -1; /** * Owner event */ protected SharedObjectMessage ownerMessage; /** * Synchronization events */ protected ConcurrentLinkedQueue syncEvents = new ConcurrentLinkedQueue(); /** * Listeners */ protected CopyOnWriteArraySet listeners = new CopyOnWriteArraySet(); /** * Event listener, actually RTMP connection */ protected IEventListener source; /** * Number of times the SO has been acquired */ protected AtomicInteger acquireCount = new AtomicInteger(); /** * Timestamp the scope was created. */ private long creationTime; /** * Manages listener statistics. */ protected StatisticsCounter listenerStats = new StatisticsCounter(); /** * Counts number of "change" events. */ protected AtomicInteger changeStats = new AtomicInteger(); /** * Counts number of "delete" events. */ protected AtomicInteger deleteStats = new AtomicInteger(); /** * Counts number of "send message" events. */ protected AtomicInteger sendStats = new AtomicInteger(); /** Constructs a new SharedObject. */ public SharedObject() { // This is used by the persistence framework super(); ownerMessage = new SharedObjectMessage(null, null, -1, false); creationTime = System.currentTimeMillis(); } /** * Constructs new SO from Input object * @param input Input source * @throws IOException I/O exception * * @see org.red5.io.object.Input */ public SharedObject(Input input) throws IOException { this(); deserialize(input); } /** * Creates new SO from given data map, name, path and persistence option * * @param name SO name * @param path SO path * @param persistent SO persistence */ public SharedObject(String name, String path, boolean persistent) { super(); this.name = name; this.path = path; this.persistent = persistent; ownerMessage = new SharedObjectMessage(null, name, 0, persistent); creationTime = System.currentTimeMillis(); } /** * Creates new SO from given data map, name, path, storage object and persistence option * * @param name SO name * @param path SO path * @param persistent SO persistence * @param storage Persistence storage */ public SharedObject(String name, String path, boolean persistent, IPersistenceStore storage) { this(name, path, persistent); setStore(storage); } /** * Creates new SO from given data map, name, path and persistence option * * @param data Data * @param name SO name * @param path SO path * @param persistent SO persistence */ public SharedObject(Map data, String name, String path, boolean persistent) { this(name, path, persistent); attributes.putAll(data); } /** * Creates new SO from given data map, name, path, storage object and persistence option * * @param data Data * @param name SO name * @param path SO path * @param persistent SO persistence * @param storage Persistence storage */ public SharedObject(Map data, String name, String path, boolean persistent, IPersistenceStore storage) { this(data, name, path, persistent); setStore(storage); } /** {@inheritDoc} */ public String getName() { return name; } /** {@inheritDoc} */ public void setName(String name) { throw new UnsupportedOperationException("Shared objects don't support setting of their name"); } /** {@inheritDoc} */ public String getPath() { return path; } /** {@inheritDoc} */ public void setPath(String path) { this.path = path; } /** {@inheritDoc} */ public String getType() { return ScopeType.SHARED_OBJECT.toString(); } /** {@inheritDoc} */ public long getLastModified() { return lastModified; } /** {@inheritDoc} */ public boolean isPersistent() { return persistent; } /** {@inheritDoc} */ public void setPersistent(boolean persistent) { log.debug("setPersistent: {}", persistent); this.persistent = persistent; } /** * Send update notification over data channel of RTMP connection */ protected void sendUpdates() { log.debug("sendUpdates"); //get the current version int currentVersion = getVersion(); //get the name String name = getName(); //used for notifying owner / consumers ConcurrentLinkedQueue events = new ConcurrentLinkedQueue(); //get owner events ConcurrentLinkedQueue ownerEvents = ownerMessage.getEvents(); //get all current owner events do { ISharedObjectEvent soe = ownerEvents.poll(); if (soe != null) { events.add(soe); } } while (!ownerEvents.isEmpty()); //null out our ref ownerEvents = null; // if (!events.isEmpty()) { // Send update to "owner" of this update request if (source != null) { // Only send updates when issued through RTMP request final SharedObjectMessage syncOwner = ((RTMPConnection) source).getEncoding() == Encoding.AMF3 ? new FlexSharedObjectMessage(null, name, currentVersion, persistent) : new SharedObjectMessage(null, name, currentVersion, persistent); syncOwner.addEvents(events); Channel channel = ((RTMPConnection) source).getChannel((byte) 3); if (channel != null) { //ownerMessage.acquire(); log.debug("Send to (owner) {}", channel); try { channel.write(syncOwner); } catch (Exception e) { log.warn("Exception sending shared object sync to owner", e); } } else { log.warn("No channel found for owner changes!?"); } } } //clear owner events events.clear(); //get all current sync events do { ISharedObjectEvent soe = syncEvents.poll(); if (soe != null) { events.add(soe); } } while (!syncEvents.isEmpty()); //tell all the listeners if (!events.isEmpty()) { //dont create the executor until we need it //get the listeners Set listeners = getListeners(); //updates all registered clients of this shared object for (IEventListener listener : listeners) { if (listener != source) { if (listener instanceof RTMPConnection) { //get the channel for so updates final Channel channel = ((RTMPConnection) listener).getChannel((byte) 3); //create a new sync message for every client to avoid //concurrent access through multiple threads final SharedObjectMessage syncMessage = ((RTMPConnection) listener).getEncoding() == Encoding.AMF3 ? new FlexSharedObjectMessage(null, name, currentVersion, persistent) : new SharedObjectMessage(null, name, currentVersion, persistent); syncMessage.addEvents(events); //create a worker Runnable worker = new Runnable() { public void run() { log.debug("Send to {}", channel); try { channel.write(syncMessage); } catch (Exception e) { log.warn("Exception sending shared object sync", e); } } }; SharedObjectService.SHAREDOBJECT_EXECUTOR.execute(worker); } else { log.warn("Can't send sync message to unknown connection {}", listener); } } else { // Don't re-send update to active client log.debug("Skipped {}", source); } } } //clear events events.clear(); } /** * Send notification about modification of SO */ protected void notifyModified() { log.debug("notifyModified"); if (updateCounter.get() == 0) { if (modified) { // The client sent at least one update -> increase version of SO updateVersion(); lastModified = System.currentTimeMillis(); if (storage != null) { if (!storage.save(this)) { log.error("Could not store shared object."); } } } else { log.debug("Not modified"); } sendUpdates(); //APPSERVER-291 modified = false; } else { log.debug("Update counter: {}", updateCounter.get()); } } /** * Return an error message to the client. * * @param message */ protected void returnError(String message) { ownerMessage.addEvent(Type.CLIENT_STATUS, "error", message); } /** * Return an attribute value to the owner. * * @param name */ protected void returnAttributeValue(String name) { ownerMessage.addEvent(Type.CLIENT_UPDATE_DATA, name, getAttribute(name)); } /** * Return attribute by name and set if it doesn't exist yet. * @param name Attribute name * @param value Value to set if attribute doesn't exist * @return Attribute value */ @Override public Object getAttribute(String name, Object value) { log.debug("getAttribute - name: {} value: {}", name, value); Object result = null; if (name != null) { result = attributes.putIfAbsent(name, value); if (result == null) { // No previous value modified = true; ownerMessage.addEvent(Type.CLIENT_UPDATE_DATA, name, value); syncEvents.add(new SharedObjectEvent(Type.CLIENT_UPDATE_DATA, name, value)); notifyModified(); changeStats.incrementAndGet(); result = value; } } return result; } /** * Set value of attribute with given name * @param name Attribute name * @param value Attribute value * @return true if there's such attribute and value was set, false otherwise */ @Override public boolean setAttribute(String name, Object value) { log.debug("setAttribute - name: {} value: {}", name, value); boolean result = true; ownerMessage.addEvent(Type.CLIENT_UPDATE_ATTRIBUTE, name, null); if (value == null && super.removeAttribute(name)) { // Setting a null value removes the attribute modified = true; syncEvents.add(new SharedObjectEvent(Type.CLIENT_DELETE_DATA, name, null)); deleteStats.incrementAndGet(); } else if (value != null && super.setAttribute(name, value)) { // only sync if the attribute changed modified = true; syncEvents.add(new SharedObjectEvent(Type.CLIENT_UPDATE_DATA, name, value)); changeStats.incrementAndGet(); } else { result = false; } notifyModified(); return result; } /** * Set attributes as map. * * @param values Attributes. */ @Override public void setAttributes(Map values) { if (values != null) { beginUpdate(); try { for (Map.Entry entry : values.entrySet()) { setAttribute(entry.getKey(), entry.getValue()); } } finally { endUpdate(); } } } /** * Set attributes as attributes store. * * @param values Attributes. */ @Override public void setAttributes(IAttributeStore values) { if (values != null) { setAttributes(values.getAttributes()); } } /** * Removes attribute with given name * @param name Attribute * @return true if there's such an attribute and it was removed, false otherwise */ @Override public boolean removeAttribute(String name) { boolean result = true; // Send confirmation to client ownerMessage.addEvent(Type.CLIENT_DELETE_DATA, name, null); if (super.removeAttribute(name)) { modified = true; syncEvents.add(new SharedObjectEvent(Type.CLIENT_DELETE_DATA, name, null)); deleteStats.incrementAndGet(); } else { result = false; } notifyModified(); return result; } /** * Broadcast event to event handler * @param handler Event handler * @param arguments Arguments */ protected void sendMessage(String handler, List arguments) { // Forward ownerMessage.addEvent(Type.CLIENT_SEND_MESSAGE, handler, arguments); syncEvents.add(new SharedObjectEvent(Type.CLIENT_SEND_MESSAGE, handler, arguments)); sendStats.incrementAndGet(); } /** * Getter for data. * * @return SO data as unmodifiable map */ public Map getData() { return getAttributes(); } /** * Getter for version. * * @return SO version. */ public int getVersion() { return version.get(); } /** * Increases version by one */ private void updateVersion() { version.incrementAndGet(); } /** * Remove all attributes (clear Shared Object) */ @Override public void removeAttributes() { // TODO: there must be a direct way to clear the SO on the client side... Set names = getAttributeNames(); for (String key : names) { ownerMessage.addEvent(Type.CLIENT_DELETE_DATA, key, null); syncEvents.add(new SharedObjectEvent(Type.CLIENT_DELETE_DATA, key, null)); } deleteStats.addAndGet(names.size()); // Clear data super.removeAttributes(); // Mark as modified modified = true; // Broadcast 'modified' event notifyModified(); } /** * Register event listener * @param listener Event listener */ protected void register(IEventListener listener) { log.debug("register - listener: {}", listener); listeners.add(listener); listenerStats.increment(); // prepare response for new client ownerMessage.addEvent(Type.CLIENT_INITIAL_DATA, null, null); if (!isPersistent()) { ownerMessage.addEvent(Type.CLIENT_CLEAR_DATA, null, null); } if (!attributes.isEmpty()) { ownerMessage.addEvent(new SharedObjectEvent(Type.CLIENT_UPDATE_DATA, null, getAttributes())); } // we call notifyModified here to send response if we're not in a // beginUpdate block notifyModified(); } /** * Unregister event listener * @param listener Event listener */ protected void unregister(IEventListener listener) { log.debug("unregister - listener: {}", listener); listeners.remove(listener); listenerStats.decrement(); checkRelease(); } /** * Check if shared object must be released. */ protected void checkRelease() { //part 3 of fix for TRAC #360 if (!isPersistent() && listeners.isEmpty() && !isAcquired()) { log.info("Deleting shared object {} because all clients disconnected and it is no longer acquired.", name); if (storage != null) { if (!storage.remove(this)) { log.error("Could not remove shared object"); } } close(); } } /** * Get event listeners. * * @return Value for property 'listeners'. */ public Set getListeners() { return listeners; } /** * Begin update of this Shared Object. * Increases number of pending update operations */ protected void beginUpdate() { log.debug("beginUpdate"); beginUpdate(source); } /** * Begin update of this Shared Object and setting listener * @param listener Update with listener */ protected void beginUpdate(IEventListener listener) { log.debug("beginUpdate - listener: {}", listener); source = listener; // Increase number of pending updates updateCounter.incrementAndGet(); } /** * End update of this Shared Object. Decreases number of pending update operations and * broadcasts modified event if it is equal to zero (i.e. no more pending update operations). */ protected void endUpdate() { log.debug("endUpdate"); // Decrease number of pending updates if (updateCounter.decrementAndGet() == 0) { notifyModified(); source = null; } } /** {@inheritDoc} */ public void serialize(Output output) throws IOException { log.debug("serialize"); Serializer ser = new Serializer(); ser.serialize(output, getName()); ser.serialize(output, getAttributes()); } /** {@inheritDoc} */ @SuppressWarnings({ "unchecked", "rawtypes" }) public void deserialize(Input input) throws IOException { log.debug("deserialize"); Deserializer deserializer = new Deserializer(); name = deserializer.deserialize(input, String.class); persistent = true; super.setAttributes(deserializer. deserialize(input, Map.class)); ownerMessage.setName(name); ownerMessage.setPersistent(persistent); } /** {@inheritDoc} */ public void setStore(IPersistenceStore store) { this.storage = store; } /** {@inheritDoc} */ public IPersistenceStore getStore() { return storage; } /** * Deletes all the attributes and sends a clear event to all listeners. The * persistent data object is also removed from a persistent shared object. * * @return true on success, false otherwise */ protected boolean clear() { log.debug("clear"); super.removeAttributes(); // send confirmation to client ownerMessage.addEvent(Type.CLIENT_CLEAR_DATA, name, null); notifyModified(); changeStats.incrementAndGet(); return true; } /** * Detaches a reference from this shared object, reset it's state, this will destroy the * reference immediately. This is useful when you don't want to proxy a * shared object any longer. */ protected void close() { log.debug("close"); // clear collections super.removeAttributes(); listeners.clear(); syncEvents.clear(); ownerMessage.getEvents().clear(); } /** * Prevent shared object from being released. Each call to acquire * must be paired with a call to release so the SO isn't held * forever. This is only valid for non-persistent SOs. */ public void acquire() { log.debug("acquire"); acquireCount.incrementAndGet(); } /** * Check if shared object currently is acquired. * * @return true if the SO is acquired, otherwise false */ public boolean isAcquired() { return acquireCount.get() > 0; } /** * Release previously acquired shared object. If the SO is non-persistent, * no more clients are connected the SO isn't acquired any more, the data * is released. */ public void release() { log.debug("release"); if (acquireCount.get() == 0) { throw new RuntimeException("The shared object was not acquired before."); } if (acquireCount.decrementAndGet() == 0) { checkRelease(); } } /** {@inheritDoc} */ public long getCreationTime() { return creationTime; } /** {@inheritDoc} */ public int getTotalListeners() { return listenerStats.getTotal(); } /** {@inheritDoc} */ public int getMaxListeners() { return listenerStats.getMax(); } /** {@inheritDoc} */ public int getActiveListeners() { return listenerStats.getCurrent(); } /** {@inheritDoc} */ public int getTotalChanges() { return changeStats.intValue(); } /** {@inheritDoc} */ public int getTotalDeletes() { return deleteStats.intValue(); } /** {@inheritDoc} */ public int getTotalSends() { return sendStats.intValue(); } } red5-1.0~svn4374.orig/src/org/red5/server/so/ISharedObjectMessage.java0000644000175000017500000000434111706617130025301 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.so; import java.util.Queue; import org.red5.server.net.rtmp.event.IRTMPEvent; /** * Shared object message */ public interface ISharedObjectMessage extends IRTMPEvent { /** * Returns the name of the shared object this message belongs to. * * @return name of the shared object */ public String getName(); /** * Returns the version to modify. * * @return version to modify */ public int getVersion(); /** * Does the message affect a persistent shared object? * * @return true if a persistent shared object should be updated otherwise * false */ public boolean isPersistent(); /** * Returns a set of ISharedObjectEvent objects containing informations what * to change. * * @return set of ISharedObjectEvents */ public Queue getEvents(); /** * Addition event handler * @param type Event type * @param key Handler key * @param value Event value (like arguments) */ public void addEvent(ISharedObjectEvent.Type type, String key, Object value); /** * Add event handler * @param event SO event */ public void addEvent(ISharedObjectEvent event); /** * Clear shared object */ public void clear(); /** * Is empty? * * @return true if shared object is empty, false otherwise */ public boolean isEmpty(); } red5-1.0~svn4374.orig/src/org/red5/server/so/SharedObjectScope.java0000644000175000017500000005100711755203771024664 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.so; import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.locks.ReentrantLock; import org.red5.server.BaseConnection; import org.red5.server.api.IAttributeStore; import org.red5.server.api.IContext; import org.red5.server.api.event.IEvent; import org.red5.server.api.event.IEventListener; import org.red5.server.api.persistence.IPersistenceStore; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.ScopeType; import org.red5.server.api.so.ISharedObject; import org.red5.server.api.so.ISharedObjectListener; import org.red5.server.api.so.ISharedObjectSecurity; import org.red5.server.api.so.ISharedObjectSecurityService; import org.red5.server.api.statistics.ISharedObjectStatistics; import org.red5.server.net.rtmp.status.StatusCodes; import org.red5.server.scope.BasicScope; import org.red5.server.service.ServiceUtils; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Special scope for shared objects */ public class SharedObjectScope extends BasicScope implements ISharedObject, StatusCodes { /** * Logger */ private Logger log = LoggerFactory.getLogger(SharedObjectScope.class); /** * Lock to synchronize shared object updates from multiple threads */ private final ReentrantLock lock = new ReentrantLock(); /** * Server-side listeners */ private CopyOnWriteArraySet serverListeners = new CopyOnWriteArraySet(); /** * Event handlers */ private ConcurrentMap handlers = new ConcurrentHashMap(); /** * Security handlers */ private CopyOnWriteArraySet securityHandlers = new CopyOnWriteArraySet(); /** * Scoped shared object */ protected volatile SharedObject so; /** * Creates shared object with given parent scope, name, persistence flag state and store object * @param parent Parent scope * @param name Name * @param persistent Persistence flag state * @param store Persistence store */ public SharedObjectScope(IScope parent, String name, boolean persistent, IPersistenceStore store) { super(parent, ScopeType.SHARED_OBJECT, name, persistent); // create shared object wrapper around the attributes String path = parent.getContextPath(); if ("".equals(path) || path.charAt(0) != '/') { path = '/' + path; } // Load SO so = (SharedObject) store.load(ScopeType.SHARED_OBJECT + path + '/' + name); // Create if it doesn't exist if (so == null) { so = new SharedObject(name, path, persistent, store); // Save store.save(so); } else { // fix for issue #209 http://code.google.com/p/red5/issues/detail?id=209 //so.setName(name); // rename is no longer supported // set path so.setPath(path); } } /** {@inheritDoc} */ public void registerSharedObjectSecurity(ISharedObjectSecurity handler) { securityHandlers.add(handler); } /** {@inheritDoc} */ public void unregisterSharedObjectSecurity(ISharedObjectSecurity handler) { securityHandlers.remove(handler); } /** {@inheritDoc} */ public Set getSharedObjectSecurity() { return Collections.unmodifiableSet(securityHandlers); } /** {@inheritDoc} */ @Override public IPersistenceStore getStore() { return so.getStore(); } /** {@inheritDoc} */ @Override public String getName() { return so.getName(); } /** {@inheritDoc} */ @Override public String getPath() { return so.getPath(); } public void setPath(String path) { so.setPath(path); } /** {@inheritDoc} */ public boolean isPersistent() { return so.isPersistent(); } /** {@inheritDoc} */ public void beginUpdate() { // Make sure only one thread can update the SO lock.lock(); so.beginUpdate(); } /** {@inheritDoc} */ public void beginUpdate(IEventListener listener) { // Make sure only one thread can update the SO lock.lock(); so.beginUpdate(listener); } /** {@inheritDoc} */ public void endUpdate() { // End update of SO try { so.endUpdate(); } finally { lock.unlock(); } } /** {@inheritDoc} */ public int getVersion() { return so.getVersion(); } /** {@inheritDoc} */ public void sendMessage(String handler, List arguments) { beginUpdate(); try { so.sendMessage(handler, arguments); } finally { endUpdate(); } // Invoke method on registered handler String serviceName, serviceMethod; // Find out last dot position int dotPos = handler.lastIndexOf('.'); // If any, split service name and service method name if (dotPos != -1) { serviceName = handler.substring(0, dotPos); serviceMethod = handler.substring(dotPos + 1); } else { // Otherwise only service method name is available serviceName = ""; serviceMethod = handler; } // Get previously registered handler for service Object soHandler = getServiceHandler(serviceName); if (soHandler == null && hasParent()) { // No custom handler, check for service defined in the scope's // context IContext context = getParent().getContext(); String serviceId = null; try { // The bean must have a name of // "..soservice" serviceId = so.getName() + '.' + serviceName + ".soservice"; if (context.hasBean(serviceId)) { soHandler = context.getBean(serviceId); } } catch (Exception err) { log.debug("No such bean: {}", serviceId); } } // Once handler is found, find matching method if (soHandler != null) { // With exact params... Object[] methodResult = ServiceUtils.findMethodWithExactParameters(soHandler, serviceMethod, arguments); // Or at least with suitable list params if (methodResult.length == 0 || methodResult[0] == null) { methodResult = ServiceUtils.findMethodWithListParameters(soHandler, serviceMethod, arguments); } // If method is found... if (methodResult.length > 0 && methodResult[0] != null) { Method method = (Method) methodResult[0]; Object[] params = (Object[]) methodResult[1]; //...try to invoke it and handle exceptions try { method.invoke(soHandler, params); } catch (Exception err) { log.error("Error while invoking method {} on shared object handler {}", new Object[] { serviceMethod, handler }, err); } } } // Notify server listeners for (ISharedObjectListener listener : serverListeners) { listener.onSharedObjectSend(this, handler, arguments); } } /** {@inheritDoc} */ @Override public boolean removeAttribute(String name) { boolean success; // Begin update of shared object beginUpdate(); try { // Try to remove attribute success = so.removeAttribute(name); } finally { // End update of SO endUpdate(); } // Notify listeners on success and return true if (success) { for (ISharedObjectListener listener : serverListeners) { listener.onSharedObjectDelete(this, name); } } return success; } /** {@inheritDoc} */ @Override public void removeAttributes() { // Begin update beginUpdate(); try { // Remove all attributes so.removeAttributes(); } finally { // End update endUpdate(); } // Notify listeners on attributes clear for (ISharedObjectListener listener : serverListeners) { listener.onSharedObjectClear(this); } } /** {@inheritDoc} */ @Override public void addEventListener(IEventListener listener) { super.addEventListener(listener); so.register(listener); for (ISharedObjectListener soListener : serverListeners) { soListener.onSharedObjectConnect(this); } } /** {@inheritDoc} */ @Override public void removeEventListener(IEventListener listener) { so.unregister(listener); //part 1 of the fix for TRAC #360 - if we have not been released by all that acquired then //keep on disconnection of the last listener if (so.isAcquired()) { log.debug("Shared object has been aquired so setting keep on disconnect"); keepOnDisconnect = true; } //remove the listener super.removeEventListener(listener); //part 2 of the fix for TRAC #360 - check acquire if (!so.isPersistent() && !so.isAcquired() && so.getListeners().isEmpty()) { log.debug("Removing scope: {}", this); getParent().removeChildScope(this); } else { log.debug("Shared object has listeners: {}", !so.getListeners().isEmpty()); } for (ISharedObjectListener soListener : serverListeners) { soListener.onSharedObjectDisconnect(this); } } /** {@inheritDoc} */ @Override public boolean hasAttribute(String name) { return so.hasAttribute(name); } /** {@inheritDoc} */ @Override public Object getAttribute(String name) { return so.getAttribute(name); } /** {@inheritDoc} */ @Override public Object getAttribute(String name, Object value) { beginUpdate(); try { return so.getAttribute(name, value); } finally { endUpdate(); } } /** {@inheritDoc} */ @Override public Map getAttributes() { return so.getAttributes(); } /** {@inheritDoc} */ @Override public Set getAttributeNames() { return so.getAttributeNames(); } /** {@inheritDoc} */ @Override public Boolean getBoolAttribute(String name) { return so.getBoolAttribute(name); } /** {@inheritDoc} */ @Override public Byte getByteAttribute(String name) { return so.getByteAttribute(name); } /** {@inheritDoc} */ @Override public Double getDoubleAttribute(String name) { return so.getDoubleAttribute(name); } /** {@inheritDoc} */ @Override public Integer getIntAttribute(String name) { return so.getIntAttribute(name); } /** {@inheritDoc} */ @Override public List getListAttribute(String name) { return so.getListAttribute(name); } /** {@inheritDoc} */ @Override public Long getLongAttribute(String name) { return so.getLongAttribute(name); } /** {@inheritDoc} */ @Override public Map getMapAttribute(String name) { return so.getMapAttribute(name); } /** {@inheritDoc} */ @Override public Set getSetAttribute(String name) { return so.getSetAttribute(name); } /** {@inheritDoc} */ @Override public Short getShortAttribute(String name) { return so.getShortAttribute(name); } /** {@inheritDoc} */ @Override public String getStringAttribute(String name) { return so.getStringAttribute(name); } /** {@inheritDoc} */ public Map getData() { return so.getData(); } /** * Return security handlers for this shared object or null if none are found. * * @return */ private Set getSecurityHandlers() { ISharedObjectSecurityService security = (ISharedObjectSecurityService) ScopeUtils.getScopeService(getParent(), ISharedObjectSecurityService.class); if (security == null) { return null; } return security.getSharedObjectSecurity(); } /** * Call handlers and check if connection to the existing SO is allowed. * * @return is connection allowed */ protected boolean isConnectionAllowed() { // Check internal handlers first for (ISharedObjectSecurity handler : securityHandlers) { if (!handler.isConnectionAllowed(this)) { return false; } } // Check global SO handlers next final Set handlers = getSecurityHandlers(); if (handlers == null) { return true; } for (ISharedObjectSecurity handler : handlers) { if (!handler.isConnectionAllowed(this)) { return false; } } return true; } /** * Call handlers and check if writing to the SO is allowed. * * @param key key * @param value value * @return is write allowed */ protected boolean isWriteAllowed(String key, Object value) { // Check internal handlers first for (ISharedObjectSecurity handler : securityHandlers) { if (!handler.isWriteAllowed(this, key, value)) { return false; } } // Check global SO handlers next final Set handlers = getSecurityHandlers(); if (handlers == null) { return true; } for (ISharedObjectSecurity handler : handlers) { if (!handler.isWriteAllowed(this, key, value)) { return false; } } return true; } /** * Call handlers and check if deleting a property from the SO is allowed. * * @param key key * @return is delete allowed */ protected boolean isDeleteAllowed(String key) { // Check internal handlers first for (ISharedObjectSecurity handler : securityHandlers) { if (!handler.isDeleteAllowed(this, key)) { return false; } } // Check global SO handlers next final Set handlers = getSecurityHandlers(); if (handlers == null) { return true; } for (ISharedObjectSecurity handler : handlers) { if (!handler.isDeleteAllowed(this, key)) { return false; } } return true; } /** * Call handlers and check if sending a message to the clients connected to the * SO is allowed. * * @param message message * @param arguments arguments * @return is send allowed */ protected boolean isSendAllowed(String message, List arguments) { // Check internal handlers first for (ISharedObjectSecurity handler : securityHandlers) { if (!handler.isSendAllowed(this, message, arguments)) { return false; } } // Check global SO handlers next final Set handlers = getSecurityHandlers(); if (handlers == null) { return true; } for (ISharedObjectSecurity handler : handlers) { if (!handler.isSendAllowed(this, message, arguments)) { return false; } } return true; } /** {@inheritDoc} */ @Override public void dispatchEvent(IEvent e) { if (e instanceof ISharedObjectMessage || e.getType() == IEvent.Type.SHARED_OBJECT) { ISharedObjectMessage msg = (ISharedObjectMessage) e; if (msg.hasSource()) { beginUpdate(msg.getSource()); } else { beginUpdate(); } try { for (ISharedObjectEvent event : msg.getEvents()) { switch (event.getType()) { case SERVER_CONNECT: if (!isConnectionAllowed()) { so.returnError(SO_NO_READ_ACCESS); } else if (msg.hasSource()) { IEventListener source = msg.getSource(); if (source instanceof BaseConnection) { ((BaseConnection) source).registerBasicScope(this); } else { addEventListener(source); } } break; case SERVER_DISCONNECT: if (msg.hasSource()) { IEventListener source = msg.getSource(); if (source instanceof BaseConnection) { ((BaseConnection) source).unregisterBasicScope(this); } else { removeEventListener(source); } } break; case SERVER_SET_ATTRIBUTE: final String key = event.getKey(); final Object value = event.getValue(); if (!isWriteAllowed(key, value)) { so.returnAttributeValue(key); so.returnError(SO_NO_WRITE_ACCESS); } else { setAttribute(key, value); } break; case SERVER_DELETE_ATTRIBUTE: final String property = event.getKey(); if (!isDeleteAllowed(property)) { so.returnAttributeValue(property); so.returnError(SO_NO_WRITE_ACCESS); } else { removeAttribute(property); } break; case SERVER_SEND_MESSAGE: final String message = event.getKey(); final List arguments = (List) event.getValue(); // Ignore request silently if not allowed if (isSendAllowed(message, arguments)) { sendMessage(message, arguments); } else { log.debug("Send is not allowed for {}", message); } break; default: log.warn("Unknown SO event: {}", event.getType()); } } } finally { endUpdate(); } } else { // Don't know how to handle this event. super.dispatchEvent(e); } } /** {@inheritDoc} */ @Override public boolean setAttribute(String name, Object value) { boolean success; beginUpdate(); try { success = so.setAttribute(name, value); } finally { endUpdate(); } if (success) { for (ISharedObjectListener listener : serverListeners) { listener.onSharedObjectUpdate(this, name, value); } } return success; } /** {@inheritDoc} */ @Override public void setAttributes(IAttributeStore values) { beginUpdate(); try { so.setAttributes(values); } finally { endUpdate(); } for (ISharedObjectListener listener : serverListeners) { listener.onSharedObjectUpdate(this, values); } } /** {@inheritDoc} */ @Override public void setAttributes(Map values) { beginUpdate(); try { so.setAttributes(values); } finally { endUpdate(); } for (ISharedObjectListener listener : serverListeners) { listener.onSharedObjectUpdate(this, values); } } /** {@inheritDoc} */ @Override public String toString() { return "Shared Object: " + getName(); } /** {@inheritDoc} */ public void addSharedObjectListener(ISharedObjectListener listener) { serverListeners.add(listener); } /** {@inheritDoc} */ public void removeSharedObjectListener(ISharedObjectListener listener) { serverListeners.remove(listener); } /** {@inheritDoc} */ public void registerServiceHandler(Object handler) { registerServiceHandler("", handler); } /** {@inheritDoc} */ public void registerServiceHandler(String name, Object handler) { if (name == null) { name = ""; } handlers.put(name, handler); } public void unregisterServiceHandler() { unregisterServiceHandler(""); } /** {@inheritDoc} */ public void unregisterServiceHandler(String name) { if (name == null) { name = ""; } handlers.remove(name); } /** {@inheritDoc} */ public Object getServiceHandler(String name) { if (name == null) { name = ""; } return handlers.get(name); } /** {@inheritDoc} */ public Set getServiceHandlerNames() { return Collections.unmodifiableSet(handlers.keySet()); } /** * Locks the shared object instance. Prevents any changes to this object by * clients until the SharedObject.unlock() method is called. */ public void lock() { lock.lock(); } /** * Unlocks a shared object instance that was locked with * SharedObject.lock(). */ public void unlock() { lock.unlock(); } /** * Returns the locked state of this SharedObject. * * @return true if in a locked state; false otherwise */ public boolean isLocked() { return lock.isLocked(); } /** {@inheritDoc} */ public boolean clear() { boolean success; beginUpdate(); try { success = so.clear(); } finally { endUpdate(); } if (success) { for (ISharedObjectListener listener : serverListeners) { listener.onSharedObjectClear(this); } } return success; } /** {@inheritDoc} */ public void close() { so.close(); so = null; } /** {@inheritDoc} */ public void acquire() { so.acquire(); } /** {@inheritDoc} */ public boolean isAcquired() { return so.isAcquired(); } /** {@inheritDoc} */ public void release() { so.release(); } /** {@inheritDoc} */ public ISharedObjectStatistics getStatistics() { return so; } }red5-1.0~svn4374.orig/src/org/red5/server/so/SharedObjectMessage.java0000644000175000017500000001206211706617130025167 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.so; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Iterator; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import org.red5.server.api.event.IEventListener; import org.red5.server.net.rtmp.event.BaseEvent; /** * Shared object event */ public class SharedObjectMessage extends BaseEvent implements ISharedObjectMessage { private static final long serialVersionUID = -8128704039659990049L; /** * SO event name */ private String name; /** * SO events chain */ private ConcurrentLinkedQueue events = new ConcurrentLinkedQueue(); /** * SO version, used for synchronization purposes */ private int version; /** * Whether SO persistent */ private boolean persistent; public SharedObjectMessage() { } /** * Creates Shared Object event with given name, version and persistence flag * * @param name Event name * @param version SO version * @param persistent SO persistence flag */ public SharedObjectMessage(String name, int version, boolean persistent) { this(null, name, version, persistent); } /** * Creates Shared Object event with given listener, name, SO version and * persistence flag * * @param source Event listener * @param name Event name * @param version SO version * @param persistent SO persistence flag */ public SharedObjectMessage(IEventListener source, String name, int version, boolean persistent) { super(Type.SHARED_OBJECT, source); this.name = name; this.version = version; this.persistent = persistent; } /** {@inheritDoc} */ @Override public byte getDataType() { return TYPE_SHARED_OBJECT; } /** {@inheritDoc} */ public int getVersion() { return version; } /** * Setter for version * * @param version * New version */ protected void setVersion(int version) { this.version = version; } /** {@inheritDoc} */ public String getName() { return name; } /** * Setter for name * * @param name * Event name */ protected void setName(String name) { this.name = name; } /** {@inheritDoc} */ public boolean isPersistent() { return persistent; } /** * Setter for persistence flag * * @param persistent * Persistence flag */ protected void setPersistent(boolean persistent) { this.persistent = persistent; } /** {@inheritDoc} */ public void addEvent(ISharedObjectEvent event) { events.add(event); } public void addEvents(List events) { this.events.addAll(events); } public void addEvents(Queue events) { this.events.addAll(events); } /** {@inheritDoc} */ public ConcurrentLinkedQueue getEvents() { return events; } /** {@inheritDoc} */ public void addEvent(ISharedObjectEvent.Type type, String key, Object value) { events.add(new SharedObjectEvent(type, key, value)); } /** {@inheritDoc} */ public void clear() { events.clear(); } /** {@inheritDoc} */ public boolean isEmpty() { return events.isEmpty(); } /** {@inheritDoc} */ @Override public Type getType() { return Type.SHARED_OBJECT; } /** {@inheritDoc} */ @Override public Object getObject() { return getEvents(); } /** {@inheritDoc} */ @Override protected void releaseInternal() { } /** {@inheritDoc} */ @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()).append(": ").append(name).append(" { "); final Iterator it = events.iterator(); while (it.hasNext()) { sb.append(it.next()); if (it.hasNext()) { sb.append(" , "); } } sb.append(" } "); return sb.toString(); } @SuppressWarnings({ "unchecked" }) @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); name = (String) in.readObject(); version = in.readInt(); persistent = in.readBoolean(); Object o = in.readObject(); if (o != null && o instanceof ConcurrentLinkedQueue) { events = (ConcurrentLinkedQueue) o; } } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeObject(name); out.writeInt(version); out.writeBoolean(persistent); out.writeObject(events); } } red5-1.0~svn4374.orig/src/org/red5/server/so/SharedObjectEvent.java0000644000175000017500000000421011706617130024660 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.so; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; public class SharedObjectEvent implements ISharedObjectEvent, Externalizable { private static final long serialVersionUID = -4129018814289863535L; /** * Event type */ private Type type; /** * Changed pair key */ private String key; /** * Changed pair value */ private Object value; public SharedObjectEvent() { } /** * * @param type type * @param key key * @param value value */ public SharedObjectEvent(Type type, String key, Object value) { this.type = type; this.key = key; this.value = value; } /** {@inheritDoc} */ public String getKey() { return key; } /** {@inheritDoc} */ public Type getType() { return type; } /** {@inheritDoc} */ public Object getValue() { return value; } /** {@inheritDoc} */ @Override public String toString() { return "SOEvent(" + getType() + ", " + getKey() + ", " + getValue() + ')'; } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { type = (Type) in.readObject(); key = (String) in.readObject(); value = in.readObject(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(type); out.writeObject(key); out.writeObject(value); } } red5-1.0~svn4374.orig/src/org/red5/server/so/SharedObjectService.java0000644000175000017500000001463511747635016025223 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.so; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.red5.server.api.persistence.IPersistable; import org.red5.server.api.persistence.IPersistenceStore; import org.red5.server.api.persistence.PersistenceUtils; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.ScopeType; import org.red5.server.api.so.ISharedObject; import org.red5.server.api.so.ISharedObjectService; import org.red5.server.persistence.RamPersistence; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.scheduling.concurrent.CustomizableThreadFactory; /** * Shared object service */ public class SharedObjectService implements ISharedObjectService, InitializingBean, DisposableBean { public static ExecutorService SHAREDOBJECT_EXECUTOR; /** * Logger */ private Logger log = LoggerFactory.getLogger(SharedObjectService.class); /** * Persistence store prefix */ private static final String SO_PERSISTENCE_STORE = IPersistable.TRANSIENT_PREFIX + "_SO_PERSISTENCE_STORE_"; /** * Transient store prefix */ private static final String SO_TRANSIENT_STORE = IPersistable.TRANSIENT_PREFIX + "_SO_TRANSIENT_STORE_"; /** * Persistence class name */ private String persistenceClassName = "org.red5.server.persistence.RamPersistence"; private int executorThreadPoolSize = 8; public void setExecutorThreadPoolSize(int value) { executorThreadPoolSize = value; } public void afterPropertiesSet() throws Exception { SHAREDOBJECT_EXECUTOR = Executors.newFixedThreadPool(executorThreadPoolSize, new CustomizableThreadFactory("SharedObjectExecutor-")); } /** * Setter for persistence class name. * * @param name Setter for persistence class name */ public void setPersistenceClassName(String name) { persistenceClassName = name; } /** * Return scope store * * @param scope Scope * @param persistent Persistent store or not? * @return Scope's store */ private IPersistenceStore getStore(IScope scope, boolean persistent) { IPersistenceStore store; if (!persistent) { // Use special store for non-persistent shared objects if (!scope.hasAttribute(SO_TRANSIENT_STORE)) { store = new RamPersistence(scope); scope.setAttribute(SO_TRANSIENT_STORE, store); return store; } return (IPersistenceStore) scope.getAttribute(SO_TRANSIENT_STORE); } // Evaluate configuration for persistent shared objects if (!scope.hasAttribute(SO_PERSISTENCE_STORE)) { try { store = PersistenceUtils.getPersistenceStore(scope, persistenceClassName); log.info("Created persistence store {} for shared objects.", store); } catch (Exception err) { log.warn("Could not create persistence store ({}) for shared objects, falling back to Ram persistence.", persistenceClassName, err); store = new RamPersistence(scope); } scope.setAttribute(SO_PERSISTENCE_STORE, store); return store; } return (IPersistenceStore) scope.getAttribute(SO_PERSISTENCE_STORE); } /** {@inheritDoc} */ public boolean createSharedObject(IScope scope, String name, boolean persistent) { if (!hasSharedObject(scope, name)) { return scope.addChildScope(new SharedObjectScope(scope, name, persistent, getStore(scope, persistent))); } // the shared object already exists return true; } /** {@inheritDoc} */ public ISharedObject getSharedObject(IScope scope, String name) { return (ISharedObject) scope.getBasicScope(ScopeType.SHARED_OBJECT, name); } /** {@inheritDoc} */ public ISharedObject getSharedObject(IScope scope, String name, boolean persistent) { if (!hasSharedObject(scope, name)) { createSharedObject(scope, name, persistent); } return getSharedObject(scope, name); } /** {@inheritDoc} */ public Set getSharedObjectNames(IScope scope) { return scope.getBasicScopeNames(ScopeType.SHARED_OBJECT); } /** {@inheritDoc} */ public boolean hasSharedObject(IScope scope, String name) { return scope.hasChildScope(ScopeType.SHARED_OBJECT, name); } /** {@inheritDoc} */ public boolean clearSharedObjects(IScope scope, String name) { boolean result = false; if (hasSharedObject(scope, name)) { // '/' clears all local and persistent shared objects associated with the instance // /foo/bar clears the shared object /foo/bar; if bar is a directory name, no shared objects are deleted. // /foo/bar/* clears all shared objects stored under the instance directory /foo/bar. // The bar directory is also deleted if no persistent shared objects are in use within this namespace. // /foo/bar/XX?? clears all shared objects that begin with XX, followed by any two characters. If a directory name matches // this specification, all the shared objects within this directory are cleared. result = ((ISharedObject) scope.getBasicScope(ScopeType.SHARED_OBJECT, name)).clear(); } return result; } public void destroy() throws Exception { //disable new tasks from being submitted SHAREDOBJECT_EXECUTOR.shutdown(); try { //wait a while for existing tasks to terminate if (!SHAREDOBJECT_EXECUTOR.awaitTermination(2, TimeUnit.SECONDS)) { SHAREDOBJECT_EXECUTOR.shutdownNow(); // cancel currently executing tasks //wait a while for tasks to respond to being canceled if (!SHAREDOBJECT_EXECUTOR.awaitTermination(1, TimeUnit.SECONDS)) { System.err.println("Notifier pool did not terminate"); } } } catch (InterruptedException ie) { // re-cancel if current thread also interrupted SHAREDOBJECT_EXECUTOR.shutdownNow(); // preserve interrupt status Thread.currentThread().interrupt(); } } } red5-1.0~svn4374.orig/src/org/red5/server/service/0000755000175000017500000000000011760512573021505 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/service/IServiceResolver.java0000644000175000017500000000261411747114732025606 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import org.red5.server.api.scope.IScope; /** * Interface for objects that resolve service names to services. * * This is used by the ServiceInvoker to lookup the service to invoke * a method on. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IServiceResolver { /** * Search for a service with the given name in the scope. * * @param scope the scope to search in * @param serviceName the name of the service * @return the object implementing the service or null if * service doesn't exist */ public Object resolveService(IScope scope, String serviceName); } red5-1.0~svn4374.orig/src/org/red5/server/service/ServiceNotFoundException.java0000644000175000017500000000313711706617130027303 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; /** * Thrown when service can't be found thus remote call throws an exception * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class ServiceNotFoundException extends RuntimeException { /** * */ private static final long serialVersionUID = 7543755414829244027L; /** Name of service that doesn't exist. */ private String serviceName; /** * Creates new exception with service name * @param serviceName Name of service that couldn't been found */ public ServiceNotFoundException(String serviceName) { super("Service not found: " + serviceName); this.serviceName = serviceName; } /** * Get the name of the service that doesn't exist. * * @return name of the service */ public String getServiceName() { return serviceName; } } red5-1.0~svn4374.orig/src/org/red5/server/service/MethodNotFoundException.java0000644000175000017500000000327011706617130027121 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import java.util.Arrays; /** * Thrown if service method is not found so call throws exception * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class MethodNotFoundException extends RuntimeException { /** * */ private static final long serialVersionUID = 7559230924102506068L; /** * Creates exception with given method name * @param methodName Service method name that can't be found */ public MethodNotFoundException(String methodName) { super("Method " + methodName + " without arguments not found"); } /** * Creates exception with given method name and arguments * @param methodName Service method name that can't be found * @param args Arguments given */ public MethodNotFoundException(String methodName, Object[] args) { super("Method " + methodName + " with arguments " + Arrays.asList(args) + " not found"); } } red5-1.0~svn4374.orig/src/org/red5/server/service/ScopeServiceResolver.java0000644000175000017500000000236111747114732026466 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import org.red5.server.api.scope.IScope; /** * Resolves service names in custom configured services of a scope. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @see org.red5.server.api.service.IServiceHandlerProvider#registerServiceHandler(String, Object) */ public class ScopeServiceResolver implements IServiceResolver { /** {@inheritDoc} */ public Object resolveService(IScope scope, String serviceName) { return scope.getServiceHandler(serviceName); } } red5-1.0~svn4374.orig/src/org/red5/server/service/PendingCall.java0000644000175000017500000000606011706617130024525 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.HashSet; import java.util.Set; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.api.service.IPendingServiceCallback; /** * Pending call is remote call operation that is in pending state. Remote calls to services * are asynchronous, that is, after call but before result callback remote calls are in * pending state. */ public class PendingCall extends Call implements IPendingServiceCall { private static final long serialVersionUID = 3219267601240355335L; /** * Result object */ private Object result; /** * List of callbacks (event listeners) */ private HashSet callbacks = new HashSet(); public PendingCall() { } /** * Creates pending call with given method name * @param method Method name */ public PendingCall(String method) { super(method); } /** * Creates pending call with given method name and array of parameters * @param method Method name * @param args Parameters */ public PendingCall(String method, Object[] args) { super(method, args); } /** * Creates pending call with given method name, service name and array of parametes * * @param name Service name * @param method Method name * @param args Parameters */ public PendingCall(String name, String method, Object[] args) { super(name, method, args); } /** {@inheritDoc} */ public Object getResult() { return result; } /** {@inheritDoc} */ public void setResult(Object result) { this.result = result; setStatus(result == null ? STATUS_SUCCESS_NULL : STATUS_SUCCESS_RESULT); } /** {@inheritDoc} */ public void registerCallback(IPendingServiceCallback callback) { callbacks.add(callback); } /** {@inheritDoc} */ public void unregisterCallback(IPendingServiceCallback callback) { callbacks.remove(callback); } /** {@inheritDoc} */ public Set getCallbacks() { return callbacks; } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); result = in.readObject(); } @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeObject(result); } } red5-1.0~svn4374.orig/src/org/red5/server/service/Installer.java0000644000175000017500000002510711746025624024312 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright (c) 2006-2011 by respective authors (see below). All rights reserved. * * This library is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any later * version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.red5.server.service; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.lang.management.ManagementFactory; import java.util.UUID; import javax.management.JMX; import javax.management.MBeanServer; import javax.management.ObjectName; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.HttpHostConnectException; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.util.EntityUtils; import org.red5.compatibility.flex.messaging.messages.AcknowledgeMessage; import org.red5.compatibility.flex.messaging.messages.AsyncMessage; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.red5.server.api.service.ServiceUtils; import org.red5.server.jmx.mxbeans.LoaderMXBean; import org.red5.server.util.FileUtil; import org.red5.server.util.HttpConnectionUtil; import org.slf4j.Logger; /** * This service provides the means to list, download, install, and un-install * applications from a given url. * * @author Paul Gregoire (mondain@gmail.com) * @author Dominick Accattato (daccattato@gmail.com) */ public final class Installer { private static Logger log = Red5LoggerFactory.getLogger(Installer.class); private String applicationRepositoryUrl; { log.info("Installer service created"); } public String getApplicationRepositoryUrl() { return applicationRepositoryUrl; } public void setApplicationRepositoryUrl(String applicationRepositoryUrl) { this.applicationRepositoryUrl = applicationRepositoryUrl; } /** * Returns the LoaderMBean. * @return LoaderMBean */ @SuppressWarnings("cast") public LoaderMXBean getLoader() { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); // proxy class LoaderMXBean proxy = null; ObjectName oName; try { oName = new ObjectName("org.red5.server:type=TomcatLoader"); if (mbs.isRegistered(oName)) { proxy = JMX.newMXBeanProxy(mbs, oName, LoaderMXBean.class, true); log.debug("Loader was found"); } else { log.warn("Loader not found"); } } catch (Exception e) { log.error("Exception getting loader", e); } return proxy; } /** * Returns a Map containing all of the application wars in the snapshot repository. * * @return async message */ public AsyncMessage getApplicationList() { AcknowledgeMessage result = new AcknowledgeMessage(); // create a singular HttpClient object DefaultHttpClient client = HttpConnectionUtil.getClient(); //setup GET HttpGet method = null; try { //get registry file method = new HttpGet(applicationRepositoryUrl + "registry.xml"); // execute the method HttpResponse response = client.execute(method); int code = response.getStatusLine().getStatusCode(); log.debug("HTTP response code: {}", code); if (code == 200) { HttpEntity entity = response.getEntity(); if (entity != null) { String responseText = EntityUtils.toString(entity); log.debug("Response: {}", responseText); //prepare response for flex result.body = responseText; IConnection conn = Red5.getConnectionLocal(); result.clientId = conn.getClient().getId(); result.messageId = UUID.randomUUID().toString(); result.timestamp = System.currentTimeMillis(); //send the servers java version so the correct apps are installed String javaVersion = System.getProperty("java.version").substring(0, 3); log.info("JRE version detected: {}", javaVersion); // allow any jre version greater than 1.5 to equal 1.6 for client compatibility // fix for issue #189 if (Double.valueOf(javaVersion) > 1.5d) { javaVersion = "1.6"; } if (!ServiceUtils.invokeOnConnection(conn, "onJavaVersion", new Object[] { javaVersion })) { log.warn("Client call to onJavaVersion failed"); } } } else { log.warn("Service returned an error"); if (log.isDebugEnabled()) { HttpConnectionUtil.handleError(response); } } } catch (HttpHostConnectException he) { log.error("Http error connecting to {}", applicationRepositoryUrl, he); method.abort(); } catch (IOException ioe) { log.error("Unable to connect to {}", applicationRepositoryUrl, ioe); method.abort(); } return result; } /** * Installs a given application. * * @param applicationWarName app war name * @return true if installed; false otherwise */ public boolean install(String applicationWarName) { IConnection conn = Red5.getConnectionLocal(); boolean result = false; //strip everything except the applications name String application = applicationWarName.substring(0, applicationWarName.indexOf('-')); log.debug("Application name: {}", application); //get webapp location String webappsDir = System.getProperty("red5.webapp.root"); log.debug("Webapp folder: {}", webappsDir); //setup context String contextPath = '/' + application; String contextDir = webappsDir + contextPath; //verify this is a unique app File appDir = new File(webappsDir, application); if (appDir.exists()) { if (appDir.isDirectory()) { log.debug("Application directory exists"); } else { log.warn("Application destination is not a directory"); } ServiceUtils.invokeOnConnection(conn, "onAlert", new Object[] { String.format("Application %s already installed, please un-install before attempting another install", application) }); } else { //use the system temp directory for moving files around String srcDir = System.getProperty("java.io.tmpdir"); log.debug("Source directory: {}", srcDir); //look for archive containing application (war, zip, etc..) File dir = new File(srcDir); if (!dir.exists()) { log.warn("Source directory not found"); //use another directory dir = new File(System.getProperty("red5.root"), "/webapps/installer/WEB-INF/cache"); if (!dir.exists()) { if (dir.mkdirs()) { log.info("Installer cache directory created"); } } } else { if (!dir.isDirectory()) { log.warn("Source directory is not a directory"); } } //get a list of temp files File[] files = dir.listFiles(); for (File f : files) { String fileName = f.getName(); if (fileName.equals(applicationWarName)) { log.debug("File found matching application name"); result = true; break; } } dir = null; //if the file was not found then download it if (!result) { // create a singular HttpClient object DefaultHttpClient client = HttpConnectionUtil.getClient(); // set transfer encoding client.getParams().setBooleanParameter(CoreProtocolPNames.STRICT_TRANSFER_ENCODING, Boolean.TRUE); //setup GET HttpGet method = null; FileOutputStream fos = null; try { //try the war version first method = new HttpGet(applicationRepositoryUrl + applicationWarName); //we dont want any transformation - RFC2616 method.addHeader("Accept-Encoding", "identity"); // execute the method HttpResponse response = client.execute(method); int code = response.getStatusLine().getStatusCode(); log.debug("HTTP response code: {}", code); if (code == 200) { HttpEntity entity = response.getEntity(); if (entity != null) { //create output file fos = new FileOutputStream(srcDir + '/' + applicationWarName); log.debug("Writing response to {}/{}", srcDir, applicationWarName); // have to receive the response as a byte array. This has the advantage of writing to the file system // faster and it also works on macs ;) byte[] buf = EntityUtils.toByteArray(entity); fos.write(buf); fos.flush(); // we should be good to go result = true; } } } catch (HttpHostConnectException he) { log.error("Http error connecting to {}", applicationRepositoryUrl, he); method.abort(); } catch (IOException ioe) { log.error("Unable to connect to {}", applicationRepositoryUrl, ioe); method.abort(); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { } } } } //if we've found or downloaded the war if (result) { //get the webapp loader LoaderMXBean loader = getLoader(); if (loader != null) { //un-archive it to app dir FileUtil.unzip(srcDir + '/' + applicationWarName, contextDir); //load and start the context loader.startWebApplication(application); } else { //just copy the war to the webapps dir try { FileUtil.moveFile(srcDir + '/' + applicationWarName, webappsDir + '/' + application + ".war"); ServiceUtils.invokeOnConnection(conn, "onAlert", new Object[] { String.format("Application %s will not be available until container is restarted", application) }); } catch (IOException e) { } } } ServiceUtils.invokeOnConnection(conn, "onAlert", new Object[] { String.format("Application %s was %s", application, (result ? "installed" : "not installed")) }); } appDir = null; return result; } /** * Un-installs a given application. * * @param applicationName name to uninstall * @return true if uninstalled; else false */ public boolean uninstall(String applicationName) { ServiceUtils.invokeOnConnection(Red5.getConnectionLocal(), "onAlert", new Object[] { "Uninstall function not available" }); return false; } } red5-1.0~svn4374.orig/src/org/red5/server/service/HandlerServiceResolver.java0000644000175000017500000000344211747114732026773 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeHandler; import org.red5.server.api.service.IServiceHandlerProvider; import org.red5.server.api.service.IServiceHandlerProviderAware; /** * Allow scope handlers to create service handlers dynamically. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class HandlerServiceResolver implements IServiceResolver { /** {@inheritDoc} */ public Object resolveService(IScope scope, String serviceName) { IScopeHandler handler = scope.getHandler(); if (handler instanceof IServiceHandlerProvider) { // TODO: deprecate this? Object result = ((IServiceHandlerProvider) handler) .getServiceHandler(serviceName); if (result != null) { return result; } } if (handler instanceof IServiceHandlerProviderAware) { IServiceHandlerProvider shp = ((IServiceHandlerProviderAware) handler) .getServiceHandlerProvider(); if (shp != null) { return shp.getServiceHandler(serviceName); } } return null; } } red5-1.0~svn4374.orig/src/org/red5/server/service/ServiceUtils.java0000644000175000017500000001547111755465152025005 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.red5.server.api.IConnection; import org.red5.server.util.ConversionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ServiceUtils { private static final Logger log = LoggerFactory.getLogger(ServiceUtils.class); //used to prevent extra object creation when a method with a set of params is not found private static final Object[] nullReturn = new Object[] { null, null }; /** * Returns (method, params) for the given service or (null, null) if no * method was found. * * @param service Service * @param methodName Method name * @param args Arguments * @return Method/params pairs */ public static Object[] findMethodWithExactParameters(Object service, String methodName, List args) { Object[] arguments = new Object[args.size()]; for (int i = 0; i < args.size(); i++) { arguments[i] = args.get(i); } return findMethodWithExactParameters(service, methodName, arguments); } /** * Returns (method, params) for the given service or (null, null) if not * method was found. XXX use ranking for method matching rather than exact * type matching plus type conversion. * * @param service Service * @param methodName Method name * @param args Arguments * @return Method/params pairs */ public static Object[] findMethodWithExactParameters(Object service, String methodName, Object[] args) { int numParams = (args == null) ? 0 : args.length; Method method = null; try { //try to skip the listing of all the methods by checking for exactly what we want first Class[] params = ConversionUtils.convertParams(args); if (log.isDebugEnabled()) { for (Class clazz : params) { log.debug("Parameter: {}", clazz); } } method = service.getClass().getMethod(methodName, params); log.debug("Exact method found (skipping list): {}", methodName); return new Object[] { method, args }; } catch (NoSuchMethodException nsme) { log.debug("Method not found using exact parameter types"); } List methods = ConversionUtils.findMethodsByNameAndNumParams(service, methodName, numParams); log.debug("Found {} methods", methods.size()); if (methods.isEmpty()) { return new Object[] { null, null }; } else if (methods.size() == 1 && args == null) { return new Object[] { methods.get(0), null }; } else if (methods.size() > 1) { log.debug("Multiple methods found with same name and parameter count. Parameter conversion will be attempted in order."); } Object[] params = null; // search for method with exact parameters for (int i = 0; i < methods.size(); i++) { method = methods.get(i); boolean valid = true; Class[] paramTypes = method.getParameterTypes(); for (int j = 0; j < args.length; j++) { if ((args[j] == null && paramTypes[j].isPrimitive()) || (args[j] != null && !args[j].getClass().equals(paramTypes[j]))) { valid = false; break; } } if (valid) { return new Object[] { method, args }; } } // try to convert parameters for (int i = 0; i < methods.size(); i++) { try { method = methods.get(i); params = ConversionUtils.convertParams(args, method.getParameterTypes()); if (args.length > 0 && (args[0] instanceof IConnection) && (!(params[0] instanceof IConnection))) { // don't convert first IConnection parameter continue; } return new Object[] { method, params }; } catch (Exception ex) { log.debug("Parameter conversion failed for {}", method); } } return new Object[] { null, null }; } /** * Returns (method, params) for the given service or (null, null) if no * method was found. * * @param service Service * @param methodName Method name * @param args Arguments * @return Method/params pairs */ public static Object[] findMethodWithListParameters(Object service, String methodName, List args) { Object[] arguments = new Object[args.size()]; for (int i = 0; i < args.size(); i++) { arguments[i] = args.get(i); } return findMethodWithListParameters(service, methodName, arguments); } /** * Returns (method, params) for the given service or (null, null) if not * method was found. * * @param service Service * @param methodName Method name * @param args Arguments * @return Method/params pairs */ public static Object[] findMethodWithListParameters(Object service, String methodName, Object[] args) { Method method = null; try { //try to skip the listing of all the methods by checking for exactly what //we want first method = service.getClass().getMethod(methodName, ConversionUtils.convertParams(args)); log.debug("Exact method found (skipping list): {}", methodName); return new Object[] { method, args }; } catch (NoSuchMethodException nsme) { log.debug("Method not found using exact parameter types"); } List methods = ConversionUtils.findMethodsByNameAndNumParams(service, methodName, 1); log.debug("Found {} methods", methods.size()); if (methods.isEmpty()) { return new Object[] { null, null }; } else if (methods.size() > 1) { log.debug("Multiple methods found with same name and parameter count."); log.debug("Parameter conversion will be attempted in order."); } ArrayList argsList = new ArrayList(); if (args != null) { for (Object element : args) { argsList.add(element); } } args = new Object[] { argsList }; Object[] params = null; for (int i = 0; i < methods.size(); i++) { try { method = methods.get(i); params = ConversionUtils.convertParams(args, method.getParameterTypes()); if (argsList.size() > 0 && (argsList.get(0) instanceof IConnection) && (!(params[0] instanceof IConnection))) { // Don't convert first IConnection parameter continue; } return new Object[] { method, params }; } catch (Exception ex) { log.debug("Parameter conversion failed", ex); } } return nullReturn; } } red5-1.0~svn4374.orig/src/org/red5/server/service/NotAllowedException.java0000644000175000017500000000223011706617130026267 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; /** * Thrown when a client is not allowed to execute a method. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class NotAllowedException extends RuntimeException { /** * */ private static final long serialVersionUID = -7552833324276839926L; public NotAllowedException() { super(); } public NotAllowedException(String message) { super(message); } } red5-1.0~svn4374.orig/src/org/red5/server/service/ContextServiceResolver.java0000644000175000017500000000247411747114732027046 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import org.red5.server.api.scope.IScope; /** * Resolve services that have been configured in the context of a scope. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class ContextServiceResolver implements IServiceResolver { /** {@inheritDoc} */ public Object resolveService(IScope scope, String serviceName) { Object service; try { service = scope.getContext().lookupService(serviceName); } catch (ServiceNotFoundException err) { return null; } if (service != null) { return service; } return null; } } red5-1.0~svn4374.orig/src/org/red5/server/service/Call.java0000644000175000017500000001502111706617130023215 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import org.red5.server.api.service.IServiceCall; /** * Basic service call (remote call) implementation * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class Call implements IServiceCall, Externalizable { private static final long serialVersionUID = -3699712251588013875L; /** * Pending status constant */ public static final byte STATUS_PENDING = 0x01; /** * Success result constant */ public static final byte STATUS_SUCCESS_RESULT = 0x02; /** * Returned value is null constant */ public static final byte STATUS_SUCCESS_NULL = 0x03; /** * Service returns no value constant */ public static final byte STATUS_SUCCESS_VOID = 0x04; /** * Service not found constant */ public static final byte STATUS_SERVICE_NOT_FOUND = 0x10; /** * Service's method not found constant */ public static final byte STATUS_METHOD_NOT_FOUND = 0x11; /** * Access denied constant */ public static final byte STATUS_ACCESS_DENIED = 0x12; /** * Exception on invocation constant */ public static final byte STATUS_INVOCATION_EXCEPTION = 0x13; /** * General exception constant */ public static final byte STATUS_GENERAL_EXCEPTION = 0x14; /** * The application for this service is currently shutting down */ public static final byte STATUS_APP_SHUTTING_DOWN = 0x15; /** * The remote method cannot be invoked because the client is not connected. NOTE that it is possible * that this error is returned in the situation where the method has been invoked on the server the connection * has failed before the result returned could be read. There is no way to establish whether this has happened. */ public static final byte STATUS_NOT_CONNECTED = 0x20; /** * Service name */ protected String serviceName; /** * Service method name */ protected String serviceMethodName; /** * Call arguments */ protected Object[] arguments = null; /** * Call status, initial one is pending */ protected byte status = STATUS_PENDING; /** * Call exception if any, null by default */ protected Exception exception; /** * Timestamp at which the call was deserialized. */ private long readTime; /** * Timestamp at which the call was serialized. */ private long writeTime; public Call() { } /** * Creates call from method name * @param method Method name */ public Call(String method) { serviceMethodName = method; } /** * Creates call from method name and array of call parameters * @param method Method name * @param args Call parameters */ public Call(String method, Object[] args) { serviceMethodName = method; arguments = args; } /** * Creates call from given service name, method name and array of call parameters * @param name Service name * @param method Service method name * @param args Call parameters */ public Call(String name, String method, Object[] args) { serviceName = name; serviceMethodName = method; arguments = args; } /** * {@inheritDoc} */ public boolean isSuccess() { return (status == STATUS_SUCCESS_RESULT) || (status == STATUS_SUCCESS_NULL) || (status == STATUS_SUCCESS_VOID); } /** * {@inheritDoc} */ public String getServiceMethodName() { return serviceMethodName; } /** * Setter for service method name * * @param serviceMethodName New service method name value */ public void setServiceMethodName(String serviceMethodName) { this.serviceMethodName = serviceMethodName; } /** * {@inheritDoc} */ public String getServiceName() { return serviceName; } /** * Setter for service name * * @param serviceName New service name value */ public void setServiceName(String serviceName) { this.serviceName = serviceName; } /** * {@inheritDoc} */ public Object[] getArguments() { return arguments; } /** * Setter for arguments. * * @param args Arguments. */ public void setArguments(Object[] args) { arguments = args; } /** * {@inheritDoc} */ public byte getStatus() { return status; } /** * {@inheritDoc} */ public void setStatus(byte status) { this.status = status; } /** * {@inheritDoc} */ public long getReadTime() { return readTime; } /** * {@inheritDoc} */ public long getWriteTime() { return writeTime; } /** * {@inheritDoc} */ public Exception getException() { return exception; } /** * {@inheritDoc} */ public void setException(Exception exception) { this.exception = exception; } /** {@inheritDoc} */ @Override public String toString() { StringBuilder sb = new StringBuilder("Service: "); sb.append(serviceName); sb.append(" Method: "); sb.append(serviceMethodName); if (arguments != null) { sb.append(" Num Params: "); sb.append(arguments.length); for (int i = 0; i < arguments.length; i++) { sb.append(' '); sb.append(i); sb.append(": "); sb.append(arguments[i]); } } else { sb.append(" No params"); } return sb.toString(); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { // keep a time of receipt readTime = System.currentTimeMillis(); // read-in properties serviceName = (String) in.readObject(); serviceMethodName = (String) in.readObject(); arguments = (Object[]) in.readObject(); status = in.readByte(); exception = (Exception) in.readObject(); } public void writeExternal(ObjectOutput out) throws IOException { // keep a time of receipt writeTime = System.currentTimeMillis(); // write-out properties out.writeObject(serviceName); out.writeObject(serviceMethodName); out.writeObject(arguments); out.writeByte(status); out.writeObject(exception); } } red5-1.0~svn4374.orig/src/org/red5/server/service/ServiceInvoker.java0000644000175000017500000002033311755465152025313 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.service; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.red5.annotations.DeclarePrivate; import org.red5.annotations.DeclareProtected; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.red5.server.api.scope.IScope; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.api.service.IServiceCall; import org.red5.server.api.service.IServiceInvoker; import org.red5.server.exception.ClientDetailsException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Makes remote calls, invoking services, resolves service handlers * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class ServiceInvoker implements IServiceInvoker { /** * Logger */ private static final Logger log = LoggerFactory.getLogger(ServiceInvoker.class); /** * Service name */ public static final String SERVICE_NAME = "serviceInvoker"; /** * Service resolvers set */ private Set serviceResolvers = new HashSet(); /** * Setter for service resolvers. * * @param resolvers Service resolvers */ public void setServiceResolvers(Set resolvers) { serviceResolvers = resolvers; } /** * Lookup a handler for the passed service name in the given scope. * * @param scope * Scope * @param serviceName * Service name * @return Service handler */ private Object getServiceHandler(IScope scope, String serviceName) { // Get application scope handler first Object service = scope.getHandler(); if (serviceName == null || serviceName.equals("")) { // No service requested, return application scope handler return service; } // Search service resolver that knows about service name for (IServiceResolver resolver : serviceResolvers) { service = resolver.resolveService(scope, serviceName); if (service != null) { return service; } } // Requested service does not exist. return null; } /** {@inheritDoc} */ public boolean invoke(IServiceCall call, IScope scope) { String serviceName = call.getServiceName(); log.trace("Service name {}", serviceName); Object service = getServiceHandler(scope, serviceName); if (service == null) { // Exception must be thrown if service was not found call.setException(new ServiceNotFoundException(serviceName)); // Set call status call.setStatus(Call.STATUS_SERVICE_NOT_FOUND); log.warn("Service not found: {}", serviceName); return false; } else { log.trace("Service found: {}", serviceName); } // Invoke if everything is ok return invoke(call, service); } /** {@inheritDoc} */ public boolean invoke(IServiceCall call, Object service) { IConnection conn = Red5.getConnectionLocal(); String methodName = call.getServiceMethodName(); log.debug("Service: {} name: {} method: {}", new Object[] { service, call.getServiceName(), methodName }); // pull off the prefixes since java doesnt allow this on a method name if (methodName.charAt(0) == '@') { log.debug("Method name contained an illegal prefix, it will be removed: {}", methodName); methodName = methodName.substring(1); } // build an array with the incoming args and the current connection as the first element Object[] args = call.getArguments(); Object[] argsWithConnection; if (args != null) { argsWithConnection = new Object[args.length + 1]; argsWithConnection[0] = conn; for (int i = 0; i < args.length; i++) { log.debug("{} => {}", i, args[i]); if (args[i] != null) { log.trace("Arg type: {}", args[i].getClass().getName()); } argsWithConnection[i + 1] = args[i]; } } else { argsWithConnection = new Object[] { conn }; } // find the method Object[] methodResult = null; // First, search for method with the connection as first parameter. methodResult = ServiceUtils.findMethodWithExactParameters(service, methodName, argsWithConnection); if (methodResult.length == 0 || methodResult[0] == null) { // Second, search for method without the connection as first parameter. methodResult = ServiceUtils.findMethodWithExactParameters(service, methodName, args); if (methodResult.length == 0 || methodResult[0] == null) { // Third, search for method with the connection as first parameter in a list argument. methodResult = ServiceUtils.findMethodWithListParameters(service, methodName, argsWithConnection); if (methodResult.length == 0 || methodResult[0] == null) { // Fourth, search for method without the connection as first parameter in a list argument. methodResult = ServiceUtils.findMethodWithListParameters(service, methodName, args); if (methodResult.length == 0 || methodResult[0] == null) { log.error("Method {} with parameters {} not found in {}", new Object[] { methodName, (args == null ? Collections.EMPTY_LIST : Arrays.asList(args)), service }); call.setStatus(Call.STATUS_METHOD_NOT_FOUND); if (args != null && args.length > 0) { call.setException(new MethodNotFoundException(methodName, args)); } else { call.setException(new MethodNotFoundException(methodName)); } return false; } } } } Object result = null; Method method = (Method) methodResult[0]; Object[] params = (Object[]) methodResult[1]; try { if (method.isAnnotationPresent(DeclarePrivate.class)) { // Method may not be called by clients. log.debug("Method {} is declared private.", method); throw new NotAllowedException("Access denied, method is private"); } final DeclareProtected annotation = method.getAnnotation(DeclareProtected.class); if (annotation != null) { if (!conn.getClient().hasPermission(conn, annotation.permission())) { // client doesn't have required permission log.debug("Client {} doesn't have required permission {} to call {}", new Object[] { conn.getClient(), annotation.permission(), method }); throw new NotAllowedException("Access denied, method is protected"); } } log.debug("Invoking method: {}", method.toString()); if (method.getReturnType().equals(Void.TYPE)) { log.debug("result: void"); method.invoke(service, params); call.setStatus(Call.STATUS_SUCCESS_VOID); } else { result = method.invoke(service, params); log.debug("result: {}", result); call.setStatus(result == null ? Call.STATUS_SUCCESS_NULL : Call.STATUS_SUCCESS_RESULT); } if (call instanceof IPendingServiceCall) { ((IPendingServiceCall) call).setResult(result); } } catch (NotAllowedException e) { call.setException(e); call.setStatus(Call.STATUS_ACCESS_DENIED); return false; } catch (IllegalAccessException accessEx) { call.setException(accessEx); call.setStatus(Call.STATUS_ACCESS_DENIED); log.error("Error executing call: {}", call); log.error("Service invocation error", accessEx); return false; } catch (InvocationTargetException invocationEx) { call.setException(invocationEx); call.setStatus(Call.STATUS_INVOCATION_EXCEPTION); if (!(invocationEx.getCause() instanceof ClientDetailsException)) { // only log if not handled by client log.error("Error executing call: {}", call, invocationEx); } return false; } catch (Exception ex) { call.setException(ex); call.setStatus(Call.STATUS_GENERAL_EXCEPTION); log.error("Error executing call: {}", call, ex); return false; } return true; } } red5-1.0~svn4374.orig/src/org/red5/server/service/WarDeployer.java0000644000175000017500000001550111745776105024615 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright (c) 2006-2011 by respective authors (see below). All rights reserved. * * This library is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any later * version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.red5.server.service; import java.io.File; import java.io.FilenameFilter; import java.lang.management.ManagementFactory; import javax.management.JMX; import javax.management.MBeanServer; import javax.management.ObjectName; import org.red5.server.api.scheduling.IScheduledJob; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.jmx.mxbeans.LoaderMXBean; import org.red5.server.util.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This service provides the means to auto-deploy a war. * * @author Paul Gregoire (mondain@gmail.com) */ public final class WarDeployer { private Logger log = LoggerFactory.getLogger(WarDeployer.class); private ISchedulingService scheduler; //how often to check for wars private int checkInterval = 600000; //ten minutes //where we deploy from - where the war files are located private String deploymentDirectory; private static String jobName; //that wars are currently being installed private static boolean deploying; { log.info("War deployer service created"); } public void setCheckInterval(int checkInterval) { this.checkInterval = checkInterval; } public int getCheckInterval() { return checkInterval; } public ISchedulingService getScheduler() { return scheduler; } public void setScheduler(ISchedulingService scheduler) { this.scheduler = scheduler; } public String getDeploymentDirectory() { return deploymentDirectory; } public void setDeploymentDirectory(String deploymentDirectory) { this.deploymentDirectory = deploymentDirectory; } public void init() { //create the job and schedule it jobName = scheduler.addScheduledJobAfterDelay(checkInterval, new DeployJob(), 20000); // log.debug("Source directory: {}", deploymentDirectory); //check the deploy from directory File dir = new File(deploymentDirectory); if (!dir.exists()) { log.warn("Source directory not found"); } else { if (!dir.isDirectory()) { log.warn("Source directory is not a directory"); } } dir = null; } public void shutdown() { scheduler.removeScheduledJob(jobName); } /** * Returns the LoaderMBean. * @return LoadeerMBean */ @SuppressWarnings("cast") public LoaderMXBean getLoader() { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); // proxy class LoaderMXBean proxy = null; ObjectName oName; try { oName = new ObjectName("org.red5.server:type=TomcatLoader"); if (mbs.isRegistered(oName)) { proxy = JMX.newMXBeanProxy(mbs, oName, LoaderMXBean.class, true); log.debug("Loader was found"); } else { log.warn("Loader not found"); } } catch (Exception e) { log.error("Exception getting loader", e); } return proxy; } /** * Filters directory content */ protected class DirectoryFilter implements FilenameFilter { /** * Check whether file matches filter rules * * @param dir Directory * @param name File name * @return true If file does match filter rules, false otherwise */ public boolean accept(File dir, String name) { File f = new File(dir, name); log.trace("Filtering: {} name: {}", dir.getName(), name); // filter out all but war files boolean result = f.getName().endsWith("war"); //nullify f = null; return result; } } private class DeployJob implements IScheduledJob { public void execute(ISchedulingService service) { log.trace("Executing job"); if (deploying) { return; } deploying = true; log.debug("Starting scheduled deployment of wars"); //short name String application = null; //file name String applicationWarName = null; //get webapp location String webappsDir = System.getProperty("red5.webapp.root"); log.debug("Webapp folder: {}", webappsDir); //look for web application archives File dir = new File(deploymentDirectory); //get a list of wars File[] files = dir.listFiles(new DirectoryFilter()); for (File f : files) { //get the war name applicationWarName = f.getName(); int dashIndex = applicationWarName.indexOf('-'); if (dashIndex != -1) { //strip everything except the applications name application = applicationWarName.substring(0, dashIndex); } else { //grab every char up to the last '.' application = applicationWarName.substring(0, applicationWarName.lastIndexOf('.')); } log.debug("Application name: {}", application); //setup context String contextPath = '/' + application; String contextDir = webappsDir + contextPath; log.debug("Web context: {} context directory: {}", contextPath, contextDir); //verify this is a unique app File appDir = new File(webappsDir, application); if (appDir.exists()) { if (appDir.isDirectory()) { log.debug("Application directory exists"); } else { log.warn("Application destination is not a directory"); } log.info("Application {} already installed, please un-install before attempting another install", application); } else { log.debug("Unwaring and starting..."); //un-archive it to app dir FileUtil.unzip(deploymentDirectory + '/' + applicationWarName, contextDir); //get the webapp loader LoaderMXBean loader = getLoader(); if (loader != null) { //load and start the context loader.startWebApplication(application); //remove the war file File warFile = new File(deploymentDirectory, applicationWarName); if (warFile.delete()) { log.debug("{} was deleted", warFile.getName()); } else { log.debug("{} was not deleted", warFile.getName()); warFile.deleteOnExit(); } warFile = null; } } appDir = null; } dir = null; //reset sentinel deploying = false; } } } red5-1.0~svn4374.orig/src/org/red5/server/adapter/0000755000175000017500000000000011760512571021463 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/adapter/ApplicationLifecycle.java0000644000175000017500000000647011747114732026422 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.adapter; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.scope.IScope; /** * * @author Dominick Accattato (daccattato@gmail.com) */ public class ApplicationLifecycle implements IApplication { /* * (non-Javadoc) * * @seeorg.red5.server.adapter.IApplication#appConnect(org.red5.server.api. * IConnection, java.lang.Object[]) */ public boolean appConnect(IConnection conn, Object[] params) { return true; } /* * (non-Javadoc) * * @see * org.red5.server.adapter.IApplication#appDisconnect(org.red5.server.api * .IConnection) */ public void appDisconnect(IConnection conn) { } /* * (non-Javadoc) * * @see * org.red5.server.adapter.IApplication#appJoin(org.red5.server.api.IClient, * org.red5.server.api.IScope) */ public boolean appJoin(IClient client, IScope app) { return true; } /* * (non-Javadoc) * * @see * org.red5.server.adapter.IApplication#appLeave(org.red5.server.api.IClient * , org.red5.server.api.IScope) */ public void appLeave(IClient client, IScope app) { } /* * (non-Javadoc) * * @see * org.red5.server.adapter.IApplication#appStart(org.red5.server.api.IScope) */ public boolean appStart(IScope app) { return true; } /* * (non-Javadoc) * * @see * org.red5.server.adapter.IApplication#appStop(org.red5.server.api.IScope) */ public void appStop(IScope app) { } /* * (non-Javadoc) * * @see * org.red5.server.adapter.IApplication#roomConnect(org.red5.server.api. * IConnection, java.lang.Object[]) */ public boolean roomConnect(IConnection conn, Object[] params) { return true; } /* * (non-Javadoc) * * @see * org.red5.server.adapter.IApplication#roomDisconnect(org.red5.server.api * .IConnection) */ public void roomDisconnect(IConnection conn) { } /* * (non-Javadoc) * * @see * org.red5.server.adapter.IApplication#roomJoin(org.red5.server.api.IClient * , org.red5.server.api.IScope) */ public boolean roomJoin(IClient client, IScope room) { return true; } /* * (non-Javadoc) * * @see * org.red5.server.adapter.IApplication#roomLeave(org.red5.server.api.IClient * , org.red5.server.api.IScope) */ public void roomLeave(IClient client, IScope room) { } /* * (non-Javadoc) * * @see * org.red5.server.adapter.IApplication#roomStart(org.red5.server.api.IScope * ) */ public boolean roomStart(IScope room) { return true; } /* * (non-Javadoc) * * @see * org.red5.server.adapter.IApplication#roomStop(org.red5.server.api.IScope) */ public void roomStop(IScope room) { } } red5-1.0~svn4374.orig/src/org/red5/server/adapter/AbstractScopeAdapter.java0000644000175000017500000001156211747114732026373 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.adapter; import java.util.Map; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.red5.server.api.event.IEvent; import org.red5.server.api.scope.IBasicScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeHandler; import org.red5.server.api.service.IServiceCall; /** * Base scope handler implementation. Meant to be subclassed. */ public abstract class AbstractScopeAdapter implements IScopeHandler { /** * Can start flag. * true if scope is ready to be activated, false otherwise */ private boolean canStart = true; /** * Can connect flag. * true if connections to scope are allowed, false otherwise */ private boolean canConnect; /** * Can join flag. * true if scope may be joined by users, false otherwise */ private boolean canJoin = true; /** * Can call service flag. * true if remote service calls are allowed for the scope, false otherwise */ private boolean canCallService; /** * Can add child scope flag. true if scope is allowed to add child scopes, false otherwise */ private boolean canAddChildScope = true; /** * Can handle event flag. * true if events handling is allowed, false otherwise */ private boolean canHandleEvent = true; /** * Setter for can start flag. * * @param canStart true if scope is ready to be activated, false otherwise */ public void setCanStart(boolean canStart) { this.canStart = canStart; } /** * Setter for can call service flag * * @param canCallService true if remote service calls are allowed for the scope, false otherwise */ public void setCanCallService(boolean canCallService) { this.canCallService = canCallService; } /** * Setter for can connect flag * * @param canConnect true if connections to scope are allowed, false otherwise */ public void setCanConnect(boolean canConnect) { this.canConnect = canConnect; } /** * Setter for 'can join' flag * * @param canJoin true if scope may be joined by users, false otherwise */ public void setJoin(boolean canJoin) { this.canJoin = canJoin; } /** {@inheritDoc} */ public boolean start(IScope scope) { return canStart; } /** {@inheritDoc} */ public void stop(IScope scope) { // nothing } /** {@inheritDoc} */ public boolean connect(IConnection conn, IScope scope, Object[] params) { return canConnect; } /** {@inheritDoc} */ public void disconnect(IConnection conn, IScope scope) { // nothing } /** {@inheritDoc} */ public boolean join(IClient client, IScope scope) { return canJoin; } /** {@inheritDoc} */ public void leave(IClient client, IScope scope) { // nothing } /** {@inheritDoc} */ public boolean serviceCall(IConnection conn, IServiceCall call) { return canCallService; } /** {@inheritDoc} */ public boolean addChildScope(IBasicScope scope) { return canAddChildScope; } /** {@inheritDoc} */ public void removeChildScope(IBasicScope scope) { } /** {@inheritDoc} */ public boolean handleEvent(IEvent event) { return canHandleEvent; } /** * Calls the checkBandwidth method on the current client. * @param o Object passed from Flash, not used at the moment */ public void checkBandwidth(Object o) { //Incoming object should be null IClient client = Red5.getConnectionLocal().getClient(); if (client != null) { client.checkBandwidth(); } } /** * Calls the checkBandwidthUp method on the current client. * @param params Object passed from Flash */ public Map checkBandwidthUp(Object[] params) { //Incoming object should be null IClient client = Red5.getConnectionLocal().getClient(); if (client != null) { return client.checkBandwidthUp(params); } return null; } } red5-1.0~svn4374.orig/src/org/red5/server/adapter/MultiThreadedApplicationAdapter.java0000644000175000017500000012722111754631106030552 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.adapter; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.red5.io.IStreamableFile; import org.red5.io.IStreamableFileFactory; import org.red5.io.IStreamableFileService; import org.red5.io.ITagReader; import org.red5.io.StreamableFileFactory; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.red5.server.api.plugin.IRed5Plugin; import org.red5.server.api.plugin.IRed5PluginHandler; import org.red5.server.api.scheduling.IScheduledJob; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.api.scope.IBroadcastScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.service.ServiceUtils; import org.red5.server.api.so.ISharedObject; import org.red5.server.api.so.ISharedObjectSecurity; import org.red5.server.api.so.ISharedObjectSecurityService; import org.red5.server.api.so.ISharedObjectService; import org.red5.server.api.stream.IBroadcastStream; import org.red5.server.api.stream.IBroadcastStreamService; import org.red5.server.api.stream.IOnDemandStream; import org.red5.server.api.stream.IOnDemandStreamService; import org.red5.server.api.stream.IPlayItem; import org.red5.server.api.stream.IStreamAwareScopeHandler; import org.red5.server.api.stream.IStreamPlaybackSecurity; import org.red5.server.api.stream.IStreamPublishSecurity; import org.red5.server.api.stream.IStreamSecurityService; import org.red5.server.api.stream.IStreamService; import org.red5.server.api.stream.ISubscriberStream; import org.red5.server.api.stream.ISubscriberStreamService; import org.red5.server.exception.ClientRejectedException; import org.red5.server.jmx.mxbeans.ApplicationMXBean; import org.red5.server.messaging.AbstractPipe; import org.red5.server.messaging.IMessageInput; import org.red5.server.plugin.PluginDescriptor; import org.red5.server.plugin.PluginRegistry; import org.red5.server.plugin.Red5Plugin; import org.red5.server.scheduling.QuartzSchedulingService; import org.red5.server.so.SharedObjectService; import org.red5.server.stream.IProviderService; import org.red5.server.stream.PlaylistSubscriberStream; import org.red5.server.stream.ProviderService; import org.red5.server.stream.StreamService; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; /** * ApplicationAdapter class serves as a base class for your Red5 applications. * It provides methods to work with SharedObjects and streams, as well as * connections and scheduling services. * * ApplicationAdapter is an application level IScope. To handle streaming * processes in your application you should implement * {@link IStreamAwareScopeHandler} interface and implement handling methods. * * Application adapter provides you with useful event handlers that can be used * to intercept streams, authorize users, etc. Also, all methods added in * subclasses can be called from client side with NetConnection.call method. * Unlike to Flash Media server which requires you to keep methods on Client * object at server side, Red5 offers much more convenient way to add methods * for remote invocation to your applications. * *

* EXAMPLE: *

*

* * public List<String> getLiveStreams() {
* // Implementation goes here, say, use Red5 object to obtain scope and all it's streams
* } *
* *

* This method added to ApplicationAdapter subclass can be called from client * side with the following code: *

* * * var nc:NetConnection = new NetConnection();
* nc.connect(...);
* nc.call("getLiveStreams", resultHandlerObj);
*
* *

* If you want to build a server-side framework this is a place to start and * wrap it around ApplicationAdapter subclass. *

*

* * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) * @author Michael Klishin */ public class MultiThreadedApplicationAdapter extends StatefulScopeWrappingAdapter implements ISharedObjectService, IBroadcastStreamService, IOnDemandStreamService, ISubscriberStreamService, ISchedulingService, IStreamSecurityService, ISharedObjectSecurityService, IStreamAwareScopeHandler, ApplicationMXBean { /** * Logger object */ protected Logger log = null; /** * List of application listeners. */ private Set listeners = new HashSet(); /** * Scheduling service. Uses Quartz. Adds and removes scheduled jobs. */ protected ISchedulingService schedulingService; /** * Client time to live is max allowed ping return time, in seconds */ private int clientTTL = 2; /** * Ghost connections (disconnected users listed as connected) cleanup period * in seconds */ private int ghostConnsCleanupPeriod = 5; /** * Ghost connections cleanup job name. Needed to cancel this job. */ private String ghostCleanupJobName; /** * List of handlers that protect stream publishing. */ private Set publishSecurity = new HashSet(); /** * List of handlers that protect stream playback. */ private Set playbackSecurity = new HashSet(); /** * List of handlers that protect shared objects. */ private Set sharedObjectSecurity = new HashSet(); /** * Register listener that will get notified about application events. Please * note that return values (e.g. from {@link IApplication#appStart(IScope)}) * will be ignored for listeners. * * @param listener * object to register */ public void addListener(IApplication listener) { listeners.add(listener); } /** * Unregister handler that will not get notified about application events * any longer. * * @param listener * object to unregister */ public void removeListener(IApplication listener) { listeners.remove(listener); } /** * Return handlers that get notified about application events. * * @return list of handlers */ public Set getListeners() { return Collections.unmodifiableSet(listeners); } /** {@inheritDoc} */ public void registerStreamPublishSecurity(IStreamPublishSecurity handler) { publishSecurity.add(handler); } /** {@inheritDoc} */ public void unregisterStreamPublishSecurity(IStreamPublishSecurity handler) { publishSecurity.remove(handler); } /** {@inheritDoc} */ public Set getStreamPublishSecurity() { return publishSecurity; } /** {@inheritDoc} */ public void registerStreamPlaybackSecurity(IStreamPlaybackSecurity handler) { playbackSecurity.add(handler); } /** {@inheritDoc} */ public void unregisterStreamPlaybackSecurity(IStreamPlaybackSecurity handler) { playbackSecurity.remove(handler); } /** {@inheritDoc} */ public Set getStreamPlaybackSecurity() { return playbackSecurity; } /** {@inheritDoc} */ public void registerSharedObjectSecurity(ISharedObjectSecurity handler) { sharedObjectSecurity.add(handler); } /** {@inheritDoc} */ public void unregisterSharedObjectSecurity(ISharedObjectSecurity handler) { sharedObjectSecurity.remove(handler); } /** {@inheritDoc} */ public Set getSharedObjectSecurity() { return sharedObjectSecurity; } /** * Reject the currently connecting client without a special error message. * This method throws {@link ClientRejectedException} exception. * * @return never returns * @throws org.red5.server.exception.ClientRejectedException * Thrown when client connection must be rejected by application * logic */ protected boolean rejectClient() throws ClientRejectedException { throw new ClientRejectedException(); } /** * Reject the currently connecting client with an error message. * * The passed object will be available as "application" property of the * information object that is returned to the caller. * * @param reason * Additional error message to return to client-side Flex/Flash * application * @return never returns * * @throws org.red5.server.exception.ClientRejectedException * Thrown when client connection must be rejected by application * logic */ protected boolean rejectClient(Object reason) throws ClientRejectedException { throw new ClientRejectedException(reason); } /** * Returns connection result for given scope and parameters. Whether the * scope is room or app level scope, this method distinguishes it and acts * accordingly. You override * {@link ApplicationAdapter#appConnect(IConnection, Object[])} or * {@link ApplicationAdapter#roomConnect(IConnection, Object[])} in your * application to make it act the way you want. * * @param conn * Connection object * @param scope * Scope * @param params * List of params passed to connection handler * @return true if connect is successful, false * otherwise */ @Override public boolean connect(IConnection conn, IScope scope, Object[] params) { //ensure the log is not null at this point if (log == null) { log = Red5LoggerFactory.getLogger(this.getClass()); } //hit the super class first if (!super.connect(conn, scope, params)) { return false; } if (log.isInfoEnabled()) { // log w3c connect event IClient client = conn.getClient(); if (client == null) { log.info("W3C x-category:session x-event:connect c-ip:{}", conn.getRemoteAddress()); } else { log.info("W3C x-category:session x-event:connect c-ip:{} c-client-id:{}", conn.getRemoteAddress(), client.getId()); } } boolean success = false; if (ScopeUtils.isApp(scope)) { success = appConnect(conn, params); } else if (ScopeUtils.isRoom(scope)) { success = roomConnect(conn, params); } return success; } /** * Starts scope. Scope can be both application or room level. * * @param scope * Scope object * @return true if scope can be started, false * otherwise. See {@link AbstractScopeAdapter#start(IScope)} for * details. */ @Override public boolean start(IScope scope) { //set the log here so that stuff is logged in the correct place if (log == null) { log = Red5LoggerFactory.getLogger(this.getClass()); } //setup plug-ins log.trace("Plugins: {}", plugins); if (plugins != null) { for (PluginDescriptor desc : plugins) { log.debug("Plugin: {}", desc); try { //ensure plug-in class can be resolved Class clazz = Class.forName(desc.getPluginType()); log.trace("Class: {}", clazz); //get the plug-in from the registry IRed5Plugin plugin = PluginRegistry.getPlugin(desc.getPluginName()); log.debug("Got plugin from the registry: {}", plugin); //if the plugin class extends the red5 plug-in we will add the application to it if (plugin instanceof Red5Plugin) { //pass the app to the plugin so that it may be manipulated directly by the plug-in ((Red5Plugin) plugin).setApplication(this); } //when a plug-in method is specified do invokes if (desc.getMethod() != null) { Method method = plugin.getClass().getMethod(desc.getMethod(), (Class[]) null); //if a return type is not specified for the plug-in method just invoke it if (desc.getMethodReturnType() == null) { log.debug("Invoking plugin"); method.invoke(plugin, (Object[]) null); } else { log.debug("Invoking plugin"); Object returnClass = method.invoke(plugin, (Object[]) null); if (returnClass instanceof IRed5PluginHandler) { //if there are props add them Map props = desc.getProperties(); if (props != null) { Method setProps = returnClass.getClass().getMethod("setProperties", new Class[] { Map.class }); setProps.invoke(returnClass, new Object[] { props }); } //initialize Method init = returnClass.getClass().getMethod("init", (Class[]) null); init.invoke(returnClass, (Object[]) null); } if (returnClass instanceof IApplication) { //if its an IApplcation add it to the listeners log.debug("Adding result class to listeners"); addListener((IApplication) returnClass); } else { log.info("Returned class did not implement IApplication"); } } } } catch (Exception e) { log.warn("Exception setting up a plugin", e); } } } // verify that we can start if (!super.start(scope)) { return false; } if (ScopeUtils.isApp(scope)) { boolean started = appStart(scope); // fix for issue 91 if (started) { // we dont allow connections until we are started super.setCanConnect(true); // we also dont allow service calls until started super.setCanCallService(true); } return started; } else { return ScopeUtils.isRoom(scope) && roomStart(scope); } } /** * Returns disconnection result for given scope and parameters. Whether the * scope is room or app level scope, this method distinguishes it and acts * accordingly. * * @param conn * Connection object * @param scope * Scope */ @Override public void disconnect(IConnection conn, IScope scope) { log.debug("disconnect: {} << {}", conn, scope); if (log.isInfoEnabled()) { // log w3c connect event IClient client = conn.getClient(); if (client == null) { // log w3c connect event log.info("W3C x-category:session x-event:disconnect c-ip:{}", conn.getRemoteAddress()); } else { // log w3c connect event log.info("W3C x-category:session x-event:disconnect c-ip:{} c-client-id:{}", conn.getRemoteAddress(), client.getId()); } } if (ScopeUtils.isApp(scope)) { appDisconnect(conn); } else if (ScopeUtils.isRoom(scope)) { roomDisconnect(conn); } super.disconnect(conn, scope); } /** * Stops scope handling (that is, stops application if given scope is app * level scope and stops room handling if given scope has lower scope * level). This method calls {@link ApplicationAdapter#appStop(IScope)} or * {@link ApplicationAdapter#roomStop(IScope)} handlers respectively. * * @param scope * Scope to stop */ @Override public void stop(IScope scope) { if (ScopeUtils.isApp(scope)) { appStop(scope); // we dont allow connections after we stop super.setCanConnect(false); // we also dont allow service calls super.setCanCallService(false); } else if (ScopeUtils.isRoom(scope)) { roomStop(scope); } super.stop(scope); } /** * Adds client to scope. Scope can be both application or room. Can be * applied to both application scope and scopes of lower level. This method * calls {@link ApplicationAdapter#appJoin(IClient, IScope)} or * {@link ApplicationAdapter#roomJoin(IClient, IScope)} handlers * respectively. * * @param client * Client object * @param scope * Scope object */ @Override public boolean join(IClient client, IScope scope) { if (!super.join(client, scope)) { return false; } if (ScopeUtils.isApp(scope)) { return appJoin(client, scope); } else { return ScopeUtils.isRoom(scope) && roomJoin(client, scope); } } /** * Disconnects client from scope. Can be applied to both application scope * and scopes of lower level. This method calls * {@link ApplicationAdapter#appLeave(IClient, IScope)} or * {@link ApplicationAdapter#roomLeave(IClient, IScope)} handlers * respectively. * * @param client * Client object * @param scope * Scope object */ @Override public void leave(IClient client, IScope scope) { log.debug("leave: {} << {}", client, scope); if (ScopeUtils.isApp(scope)) { appLeave(client, scope); } else if (ScopeUtils.isRoom(scope)) { roomLeave(client, scope); } super.leave(client, scope); } /** * Called once on scope (that is, application or application room) start. * You override {@link ApplicationAdapter#appStart(IScope)} or * {@link ApplicationAdapter#roomStart(IScope)} in your application to make * it act the way you want. * * @param app * Application scope object * @return true if scope can be started, false * otherwise */ public boolean appStart(IScope app) { log.debug("appStart: {}", app); for (IApplication listener : listeners) { if (!listener.appStart(app)) { return false; } } return true; } /** * Handler method. Called when application is stopped. * * @param app * Scope object */ public void appStop(IScope app) { log.debug("appStop: {}", app); for (IApplication listener : listeners) { listener.appStop(app); } } /** * Handler method. Called when room scope is started. * * @param room * Room scope * @return Boolean value */ public boolean roomStart(IScope room) { log.debug("roomStart: {}", room); // TODO : Get to know what does roomStart return mean for (IApplication listener : listeners) { if (!listener.roomStart(room)) { return false; } } return true; } /** * Handler method. Called when room scope is stopped. * * @param room * Room scope. */ public void roomStop(IScope room) { log.debug("roomStop: {}", room); for (IApplication listener : listeners) { listener.roomStop(room); } } /** * Handler method. Called every time new client connects (that is, new * IConnection object is created after call from a SWF movie) to the * application. * * You override this method to pass additional data from client to server * application using NetConnection.connect method. * *

* EXAMPLE:
* In this simple example we pass user's skin of choice identifier from * client to the server. *

* *

* Client-side:
* NetConnection.connect("rtmp://localhost/killerred5app", "silver"); *

* *

* Server-side:
* if (params.length > 0) log.debug("Theme selected: {}", params[0]); *

* * @param conn * Connection object * @param params * List of parameters after connection URL passed to * NetConnection.connect method. * @return Boolean value */ public boolean appConnect(IConnection conn, Object[] params) { log.debug("appConnect: {}", conn); for (IApplication listener : listeners) { if (!listener.appConnect(conn, params)) { return false; } } return true; } /** * Handler method. Called every time new client connects (that is, new * IConnection object is created after call from a SWF movie) to the * application. * * You override this method to pass additional data from client to server * application using NetConnection.connect method. * * See {@link ApplicationAdapter#appConnect(IConnection, Object[])} for code * example. * * @param conn * Connection object * @param params * List of params passed to room scope * @return Boolean value */ public boolean roomConnect(IConnection conn, Object[] params) { log.debug("roomConnect: {}", conn); for (IApplication listener : listeners) { if (!listener.roomConnect(conn, params)) { return false; } } return true; } /** * Handler method. Called every time client disconnects from the * application. * * @param conn * Disconnected connection object */ public void appDisconnect(IConnection conn) { log.debug("appDisconnect: {}", conn); for (IApplication listener : listeners) { listener.appDisconnect(conn); } } /** * Handler method. Called every time client disconnects from the room. * * @param conn * Disconnected connection object */ public void roomDisconnect(IConnection conn) { log.debug("roomDisconnect: {}", conn); for (IApplication listener : listeners) { listener.roomDisconnect(conn); } } public boolean appJoin(IClient client, IScope app) { log.debug("appJoin: {} >> {}", client, app); for (IApplication listener : listeners) { if (!listener.appJoin(client, app)) { return false; } } return true; } /** * Handler method. Called every time client leaves application scope. * * @param client * Client object that left * @param app * Application scope */ public void appLeave(IClient client, IScope app) { log.debug("appLeave: {} << {}", client, app); for (IApplication listener : listeners) { listener.appLeave(client, app); } } public boolean roomJoin(IClient client, IScope room) { log.debug("roomJoin: {} >> {}", client, room); for (IApplication listener : listeners) { if (!listener.roomJoin(client, room)) { return false; } } return true; } /** * Handler method. Called every time client leaves room scope. * * @param client * Disconnected client object * @param room * Room scope */ public void roomLeave(IClient client, IScope room) { log.debug("roomLeave: {} << {}", client, room); for (IApplication listener : listeners) { listener.roomLeave(client, room); } } /** * Try to measure bandwidth of current connection. * * This is required for some FLV player to work because they require the * "onBWDone" method to be called on the connection. */ public void measureBandwidth() { measureBandwidth(Red5.getConnectionLocal()); } /** * Try to measure bandwidth of given connection. * * This is required for some FLV player to work because they require the * "onBWDone" method to be called on the connection. * * @param conn * the connection to measure the bandwidth for */ public void measureBandwidth(IConnection conn) { // dummy for now, this makes flv player work // they dont wait for connected status they wait for onBWDone ServiceUtils.invokeOnConnection(conn, "onBWDone", new Object[] {}); } /* Wrapper around ISharedObjectService */ /** * Creates a new shared object for given scope. Server-side shared objects (also known as Remote SO) are special kind of * objects those variable are synchronized between clients. To get an instance of RSO at client-side, use * SharedObject.getRemote(). * * SharedObjects can be persistent and transient. Persistent RSO are stateful, i.e. store their data between sessions. * If you need to store some data on server while clients go back and forth use persistent SO (just use true ), * otherwise prefer usage of transient for extra performance. * * @param scope * Scope that shared object belongs to * @param name * Name of SharedObject * @param persistent * Whether SharedObject instance should be persistent or not * @return true if SO was created, false otherwise */ public boolean createSharedObject(IScope scope, String name, boolean persistent) { ISharedObjectService service = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, SharedObjectService.class, false); return service.createSharedObject(scope, name, persistent); } /** * Returns shared object from given scope by name. * * @param scope * Scope that shared object belongs to * @param name * Name of SharedObject * @return Shared object instance with name given */ public ISharedObject getSharedObject(IScope scope, String name) { ISharedObjectService service = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, SharedObjectService.class, false); return service.getSharedObject(scope, name); } /** * Returns shared object from given scope by name. * * @param scope * Scope that shared object belongs to * @param name * Name of SharedObject * @param persistent * Whether SharedObject instance should be persistent or not * @return Shared object instance with name given */ public ISharedObject getSharedObject(IScope scope, String name, boolean persistent) { ISharedObjectService service = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, SharedObjectService.class, false); return service.getSharedObject(scope, name, persistent); } /** * Returns available SharedObject names as List * * @param scope * Scope that SO belong to */ public Set getSharedObjectNames(IScope scope) { ISharedObjectService service = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, SharedObjectService.class, false); return service.getSharedObjectNames(scope); } /** * Checks whether there's a SO with given scope and name * * @param scope * Scope that SO belong to * @param name * Name of SharedObject */ public boolean hasSharedObject(IScope scope, String name) { ISharedObjectService service = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, SharedObjectService.class, false); return service.hasSharedObject(scope, name); } /* Wrapper around the stream interfaces */ /** {@inheritDoc} */ public boolean hasBroadcastStream(IScope scope, String name) { IProviderService service = (IProviderService) ScopeUtils.getScopeService(scope, IProviderService.class, ProviderService.class); return (service.getLiveProviderInput(scope, name, false) != null); } /** {@inheritDoc} */ public IBroadcastStream getBroadcastStream(IScope scope, String name) { IStreamService service = (IStreamService) ScopeUtils.getScopeService(scope, IStreamService.class, StreamService.class); if (service instanceof StreamService) { IBroadcastScope bs = ((StreamService) service).getBroadcastScope(scope, name); if (bs != null) { return bs.getClientBroadcastStream(); } } return null; } /** * Returns list of stream names broadcasted in * *
	 * scope
	 * 
* * . Broadcast stream name is somewhat different from server stream name. * Server stream name is just an ID assigned by Red5 to every created * stream. Broadcast stream name is the name that is being used to subscribe * to the stream at client side, that is, in NetStream.play * call. * * @param scope * Scope to retrieve broadcasted stream names * @return List of broadcasted stream names. */ public Set getBroadcastStreamNames(IScope scope) { IProviderService service = (IProviderService) ScopeUtils.getScopeService(scope, IProviderService.class, ProviderService.class); return service.getBroadcastStreamNames(scope); } /** * Check whether scope has VOD stream with given name or not * * @param scope * Scope * @param name * VOD stream name * * @return true if scope has VOD stream with given name, * false otherwise. */ public boolean hasOnDemandStream(IScope scope, String name) { IProviderService service = (IProviderService) ScopeUtils.getScopeService(scope, IProviderService.class, ProviderService.class); IMessageInput msgIn = service.getVODProviderInput(scope, name); if (msgIn instanceof AbstractPipe) { ((AbstractPipe) msgIn).close(); } return (msgIn != null); } /** * Returns VOD stream with given name from specified scope. * * @param scope * Scope object * @param name * VOD stream name * * @return IOnDemandStream object that represents stream that can be played * on demand, seekable and so forth. See {@link IOnDemandStream} for * details. */ public IOnDemandStream getOnDemandStream(IScope scope, String name) { log.warn("This won't work until the refactoring of the streaming code is complete."); IOnDemandStreamService service = (IOnDemandStreamService) ScopeUtils.getScopeService(scope, IOnDemandStreamService.class, StreamService.class, false); return service.getOnDemandStream(scope, name); } /** * Returns subscriber stream with given name from specified scope. * Subscriber stream is a stream that clients can subscribe to. * * @param scope * Scope * @param name * Stream name * * @return ISubscriberStream object */ public ISubscriberStream getSubscriberStream(IScope scope, String name) { log.warn("This won't work until the refactoring of the streaming code is complete."); ISubscriberStreamService service = (ISubscriberStreamService) ScopeUtils.getScopeService(scope, ISubscriberStreamService.class, StreamService.class, false); return service.getSubscriberStream(scope, name); } /** * Wrapper around ISchedulingService, adds a scheduled job to be run * periodically. We store this service in the scope as it can be shared * across all rooms of the applications. * * @param interval * Time interval to run the scheduled job * @param job * Scheduled job object * * @return Name of the scheduled job */ public String addScheduledJob(int interval, IScheduledJob job) { ISchedulingService service = (ISchedulingService) ScopeUtils.getScopeService(scope, ISchedulingService.class, QuartzSchedulingService.class, false); return service.addScheduledJob(interval, job); } /** * Adds a scheduled job that's gonna be executed once. Please note that the * jobs are not saved if Red5 is restarted in the meantime. * * @param timeDelta * Time offset in milliseconds from the current date when given * job should be run * @param job * Scheduled job object * * @return Name of the scheduled job */ public String addScheduledOnceJob(long timeDelta, IScheduledJob job) { ISchedulingService service = (ISchedulingService) ScopeUtils.getScopeService(scope, ISchedulingService.class, QuartzSchedulingService.class, false); return service.addScheduledOnceJob(timeDelta, job); } /** * Adds a scheduled job that's gonna be executed once on given date. Please * note that the jobs are not saved if Red5 is restarted in the meantime. * * @param date * When to run scheduled job * @param job * Scheduled job object * * @return Name of the scheduled job */ public String addScheduledOnceJob(Date date, IScheduledJob job) { ISchedulingService service = (ISchedulingService) ScopeUtils.getScopeService(scope, ISchedulingService.class, QuartzSchedulingService.class, false); return service.addScheduledOnceJob(date, job); } /** * Adds a scheduled job which starts after the specified delay period and * fires periodically. * * @param interval * time in milliseconds between two notifications of the job * @param job * the job to trigger periodically * @param delay * time in milliseconds to pass before first execution. * @return the name of the scheduled job */ public String addScheduledJobAfterDelay(int interval, IScheduledJob job, int delay) { ISchedulingService service = (ISchedulingService) ScopeUtils.getScopeService(scope, ISchedulingService.class, QuartzSchedulingService.class, false); return service.addScheduledJobAfterDelay(interval, job, delay); } /** * Pauses a scheduled job * * @param name * Scheduled job name */ public void pauseScheduledJob(String name) { ISchedulingService service = (ISchedulingService) ScopeUtils.getScopeService(scope, ISchedulingService.class, QuartzSchedulingService.class, false); service.pauseScheduledJob(name); } /** * Resumes a scheduled job * * @param name * Scheduled job name */ public void resumeScheduledJob(String name) { ISchedulingService service = (ISchedulingService) ScopeUtils.getScopeService(scope, ISchedulingService.class, QuartzSchedulingService.class, false); service.resumeScheduledJob(name); } /** * Removes scheduled job from scheduling service list * * @param name * Scheduled job name */ public void removeScheduledJob(String name) { ISchedulingService service = (ISchedulingService) ScopeUtils.getScopeService(scope, ISchedulingService.class, QuartzSchedulingService.class, false); service.removeScheduledJob(name); } /** * Returns list of scheduled job names * * @return List of scheduled job names as list of Strings. */ public List getScheduledJobNames() { ISchedulingService service = (ISchedulingService) ScopeUtils.getScopeService(scope, ISchedulingService.class, QuartzSchedulingService.class, false); return service.getScheduledJobNames(); } // NOTE: Method added to get flv player to work. /** * Returns stream length. This is a hook so it may be removed. * * @param name * Stream name * @return Stream length in seconds (?) */ public double getStreamLength(String name) { double duration = 0; IProviderService provider = (IProviderService) ScopeUtils.getScopeService(scope, IProviderService.class, ProviderService.class); File file = provider.getVODProviderFile(scope, name); if (file != null && file.canRead()) { IStreamableFileFactory factory = (IStreamableFileFactory) ScopeUtils.getScopeService(scope, IStreamableFileFactory.class, StreamableFileFactory.class); IStreamableFileService service = factory.getService(file); if (service != null) { ITagReader reader = null; try { IStreamableFile streamFile = service.getStreamableFile(file); reader = streamFile.getReader(); duration = (double) reader.getDuration() / 1000; } catch (IOException e) { log.error("Error read stream file {}. {}", file.getAbsolutePath(), e); } finally { if (reader != null) { reader.close(); } } } else { log.error("No service found for {}", file.getAbsolutePath()); } file = null; } return duration; } /** {@inheritDoc} */ public boolean clearSharedObjects(IScope scope, String name) { ISharedObjectService service = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, SharedObjectService.class, false); return service.clearSharedObjects(scope, name); } /** * Client time to live is max allowed connection ping return time in seconds * * @return TTL value used in seconds */ public long getClientTTL() { return clientTTL; } /** * Client time to live is max allowed connection ping return time in seconds * * @param clientTTL * New TTL value in seconds */ public void setClientTTL(int clientTTL) { this.clientTTL = clientTTL; } /** * Return period of ghost connections cleanup task call * * @return Ghost connections cleanup period */ public int getGhostConnsCleanupPeriod() { return ghostConnsCleanupPeriod; } /** * Set new ghost connections cleanup period * * @param ghostConnsCleanupPeriod * New ghost connections cleanup period */ public void setGhostConnsCleanupPeriod(int ghostConnsCleanupPeriod) { this.ghostConnsCleanupPeriod = ghostConnsCleanupPeriod; } /** * Schedules new ghost connections cleanup using current cleanup period */ public void scheduleGhostConnectionsCleanup() { IScheduledJob job = new IScheduledJob() { public void execute(ISchedulingService service) throws CloneNotSupportedException { killGhostConnections(); } }; // Cancel previous if was scheduled cancelGhostConnectionsCleanup(); // Store name so we can cancel it later ghostCleanupJobName = schedulingService.addScheduledJob(ghostConnsCleanupPeriod * 1000, job); } /** * Cancel ghost connections cleanup period */ public void cancelGhostConnectionsCleanup() { if (ghostCleanupJobName != null) { schedulingService.removeScheduledJob(ghostCleanupJobName); } } /** * Cleans up ghost connections */ protected void killGhostConnections() { Collection> conns = getConnections(); for (Set set : conns) { for (IConnection conn : set) { // Ping client conn.ping(); // FIXME: getLastPingTime doesn't get updated right after // conn.ping() // Time to live exceeded, disconnect if (conn.getLastPingTime() > clientTTL * 1000) { log.info("TTL exceeded, disconnecting {}", conn); disconnect(conn, scope); } } } } /** * Notification method that is sent by FME just before publishing starts. * * @param streamName * Name of stream that is about to be published. */ public void FCPublish(String streamName) { } /** * Notification method that is sent by FME when publishing of a stream ends. */ public void FCUnpublish() { } /** * Notification method that is sent by FME when publishing of a stream ends. */ public void FCUnpublish(String streamName) { } /** * Notification method that is sent by some clients just before playback starts. * * @param streamName * Name of stream that is about to be played. */ public void FCSubscribe(String streamName) { } /** * Notification that a broadcasting stream is closing. * * @param stream */ public void streamBroadcastClose(IBroadcastStream stream) { // log w3c connect event IConnection conn = Red5.getConnectionLocal(); // converted to seconds long publishDuration = (System.currentTimeMillis() - stream.getCreationTime()) / 1000; if (conn != null) { log.info("W3C x-category:stream x-event:unpublish c-ip:{} cs-bytes:{} sc-bytes:{} x-sname:{} x-file-length:{} x-name:{}", new Object[] { conn.getRemoteAddress(), conn.getReadBytes(), conn.getWrittenBytes(), stream.getName(), publishDuration, stream.getPublishedName() }); } else { log.info("W3C x-category:stream x-event:unpublish x-sname:{} x-file-length:{} x-name:{}", new Object[] { stream.getName(), publishDuration, stream.getPublishedName() }); } String recordingName = stream.getSaveFilename(); // if its not null then we did a recording if (recordingName != null) { if (conn != null) { // use cs-bytes for file size for now log.info( "W3C x-category:stream x-event:recordstop c-ip:{} cs-bytes:{} sc-bytes:{} x-sname:{} x-file-name:{} x-file-length:{} x-file-size:{}", new Object[] { conn.getRemoteAddress(), conn.getReadBytes(), conn.getWrittenBytes(), stream.getName(), recordingName, publishDuration, conn.getReadBytes() }); } else { log.info("W3C x-category:stream x-event:recordstop x-sname:{} x-file-name:{} x-file-length:{}", new Object[] { stream.getName(), recordingName, publishDuration }); } // if the stream length is 0 bytes then delete it, this // is a fix for SN-20 // get the web root String webappsPath = System.getProperty("red5.webapp.root"); // add context name File file = new File(webappsPath, getName() + '/' + recordingName); if (file != null) { log.debug("File path: {}", file.getAbsolutePath()); if (file.exists()) { // if publish duration or length are zero if (publishDuration == 0 || file.length() == 0) { if (file.delete()) { log.info("File {} was deleted", file.getName()); } else { log.info("File {} was not deleted, it will be deleted on exit", file.getName()); file.deleteOnExit(); } } } file = null; } } } public void streamBroadcastStart(IBroadcastStream stream) { } public void streamPlayItemPlay(ISubscriberStream stream, IPlayItem item, boolean isLive) { // log w3c connect event log.info("W3C x-category:stream x-event:play c-ip:{} x-sname:{} x-name:{}", new Object[] { Red5.getConnectionLocal().getRemoteAddress(), stream.getName(), item.getName() }); } public void streamPlayItemStop(ISubscriberStream stream, IPlayItem item) { // since there is a fair amount of processing below we will check log // level prior to proceeding if (log.isInfoEnabled()) { // log w3c connect event String remoteAddress = ""; long readBytes = -1; long writtenBytes = -1; IConnection conn = Red5.getConnectionLocal(); if (conn != null) { remoteAddress = conn.getRemoteAddress(); readBytes = conn.getReadBytes(); writtenBytes = conn.getWrittenBytes(); } long playDuration = -1; if (stream instanceof PlaylistSubscriberStream) { // converted to seconds playDuration = (System.currentTimeMillis() - ((PlaylistSubscriberStream) stream).getCreationTime()) / 1000; } long playItemSize = -1; String playItemName = ""; if (item != null) { playItemName = item.getName(); //get file size in bytes if available IProviderService providerService = (IProviderService) scope.getContext().getBean(IProviderService.BEAN_NAME); if (providerService != null) { File file = providerService.getVODProviderFile(scope, playItemName); if (file != null) { playItemSize = file.length(); } else { log.debug("File was null, this is ok for live streams"); } } else { log.debug("ProviderService was null"); } } log.info("W3C x-category:stream x-event:stop c-ip:{} cs-bytes:{} sc-bytes:{} x-sname:{} x-file-length:{} x-file-size:{} x-name:{}", new Object[] { remoteAddress, readBytes, writtenBytes, stream.getName(), playDuration, playItemSize, playItemName }); } } public void streamPlayItemPause(ISubscriberStream stream, IPlayItem item, int position) { // log w3c connect event log.info("W3C x-category:stream x-event:pause c-ip:{} x-sname:{}", Red5.getConnectionLocal().getRemoteAddress(), stream.getName()); } public void streamPlayItemResume(ISubscriberStream stream, IPlayItem item, int position) { // log w3c connect event log.info("W3C x-category:stream x-event:unpause c-ip:{} x-sname:{}", Red5.getConnectionLocal().getRemoteAddress(), stream.getName()); } public void streamPlayItemSeek(ISubscriberStream stream, IPlayItem item, int position) { // Override if necessary. } public void streamPublishStart(IBroadcastStream stream) { // log w3c connect event IConnection connection = Red5.getConnectionLocal(); log.info("W3C x-category:stream x-event:publish c-ip:{} x-sname:{} x-name:{}", new Object[] { connection != null ? connection.getRemoteAddress() : "0.0.0.0", stream.getName(), stream.getPublishedName() }); } public void streamRecordStart(IBroadcastStream stream) { // log w3c connect event IConnection connection = Red5.getConnectionLocal(); log.info("W3C x-category:stream x-event:record c-ip:{} x-sname:{} x-file-name:{}", new Object[] { connection != null ? connection.getRemoteAddress() : "0.0.0.0", stream.getName(), stream.getSaveFilename() }); } public void streamSubscriberClose(ISubscriberStream stream) { // log w3c connect event IConnection conn = Red5.getConnectionLocal(); log.info("W3C x-category:stream x-event:stop c-ip:{} cs-bytes:{} sc-bytes:{} x-sname:{}", new Object[] { conn.getRemoteAddress(), conn.getReadBytes(), conn.getWrittenBytes(), stream.getName() }); } public void streamSubscriberStart(ISubscriberStream stream) { // log w3c connect event log.info("W3C x-category:stream x-event:play c-ip:{} x-sname:{}", Red5.getConnectionLocal().getRemoteAddress(), stream.getName()); } } red5-1.0~svn4374.orig/src/org/red5/server/adapter/ApplicationAdapter.java0000644000175000017500000000427311747114732026102 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.adapter; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.scope.IScope; /** * Base class for applications, takes care that callbacks are executed single-threaded. * If you want to have maximum performance, use {@link MultiThreadedApplicationAdapter} * instead. * * Using this class may lead to problems if accepting a client in the *Connect * or *Join methods takes too long, so using the multi-threaded version is * preferred. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class ApplicationAdapter extends MultiThreadedApplicationAdapter { /** {@inheritDoc} */ @Override public synchronized boolean connect(IConnection conn, IScope scope, Object[] params) { return super.connect(conn, scope, params); } /** {@inheritDoc} */ @Override public synchronized void disconnect(IConnection conn, IScope scope) { super.disconnect(conn, scope); } /** {@inheritDoc} */ @Override public synchronized boolean start(IScope scope) { return super.start(scope); } /** {@inheritDoc} */ @Override public synchronized void stop(IScope scope) { super.stop(scope); } /** {@inheritDoc} */ @Override public synchronized boolean join(IClient client, IScope scope) { return super.join(client, scope); } /** {@inheritDoc} */ @Override public synchronized void leave(IClient client, IScope scope) { super.leave(client, scope); } } red5-1.0~svn4374.orig/src/org/red5/server/adapter/StatefulScopeWrappingAdapter.java0000644000175000017500000001442111747114732030124 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.adapter; import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import org.red5.server.api.IAttributeStore; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.IContext; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeAware; import org.red5.server.plugin.PluginDescriptor; import org.springframework.core.io.Resource; /** * StatefulScopeWrappingAdapter class wraps stateful IScope functionality. That * is, it has attributes that you can work with, subscopes, associated resources * and connections. * */ public class StatefulScopeWrappingAdapter extends AbstractScopeAdapter implements IScopeAware, IAttributeStore { /** * Wrapped scope */ protected IScope scope; /** * List of plug-in descriptors */ protected List plugins; /** {@inheritDoc} */ public void setScope(IScope scope) { this.scope = scope; } /** * Getter for wrapped scope * * @return Wrapped scope */ public IScope getScope() { return scope; } /** * Returns any plug-ins descriptors added * * @return plug-in descriptor list */ public List getPlugins() { return plugins; } /** * Adds a list of plug-in descriptors * * @param plugins */ public void setPlugins(List plugins) { this.plugins = plugins; } /** {@inheritDoc} */ public Object getAttribute(String name) { return scope.getAttribute(name); } /** {@inheritDoc} */ public Object getAttribute(String name, Object defaultValue) { Object value = scope.getAttribute(name); if (value == null) { value = defaultValue; } return value; } /** {@inheritDoc} */ public Set getAttributeNames() { return scope.getAttributeNames(); } /** * Wrapper for Scope#getAttributes * @return Scope attributes map */ public Map getAttributes() { return scope.getAttributes(); } /** {@inheritDoc} */ public boolean hasAttribute(String name) { return scope.hasAttribute(name); } /** {@inheritDoc} */ public boolean removeAttribute(String name) { return scope.removeAttribute(name); } /** {@inheritDoc} */ public void removeAttributes() { Set names = scope.getAttributeNames(); for (String name : names) { scope.removeAttribute(name); } } /** {@inheritDoc} */ public boolean setAttribute(String name, Object value) { return scope.setAttribute(name, value); } /** {@inheritDoc} */ public void setAttributes(IAttributeStore attributes) { for (Map.Entry entry : attributes.getAttributes().entrySet()) { scope.setAttribute(entry.getKey(), entry.getValue()); } } /** {@inheritDoc} */ public void setAttributes(Map attributes) { for (Map.Entry entry : attributes.entrySet()) { scope.setAttribute(entry.getKey(), entry.getValue()); } } /** * Creates child scope * @param name Child scope name * @return true on success, false otherwise */ public boolean createChildScope(String name) { return scope.createChildScope(name); } /** * Return child scope * @param name Child scope name * @return Child scope with given name */ public IScope getChildScope(String name) { return scope.getScope(name); } /** * Iterator for child scope names * * @return collection of child scope names */ public Set getChildScopeNames() { return scope.getScopeNames(); } /** * Getter for set of clients * * @return Set of clients */ public Set getClients() { return scope.getClients(); } /** * Returns all connections in the scope * * @return Connections */ public Collection> getConnections() { return scope.getConnections(); } /** * Getter for context * * @return Value for context */ public IContext getContext() { return scope.getContext(); } /** * Getter for depth * * @return Value for depth */ public int getDepth() { return scope.getDepth(); } /** * Getter for name * * @return Value for name */ public String getName() { return scope.getName(); } /** * Return parent scope * * @return Parent scope */ public IScope getParent() { return scope.getParent(); } /** * Getter for stateful scope path * * @return Value for path */ public String getPath() { return scope.getPath(); } /** * Whether this scope has a child scope with given name * @param name Child scope name * @return true if it does have it, false otherwise */ public boolean hasChildScope(String name) { return scope.hasChildScope(name); } /** * If this scope has a parent * @return true if this scope has a parent scope, false otherwise */ public boolean hasParent() { return scope.hasParent(); } public Set lookupConnections(IClient client) { return scope.lookupConnections(client); } /** * Returns array of resources (as Spring core Resource class instances) * * @param pattern Resource pattern * @return Returns array of resources * @throws IOException I/O exception */ public Resource[] getResources(String pattern) throws IOException { return scope.getResources(pattern); } /** * Return resource by name * @param path Resource name * @return Resource with given name */ public Resource getResource(String path) { return scope.getResource(path); } } red5-1.0~svn4374.orig/src/org/red5/server/adapter/IApplication.java0000644000175000017500000000767511754746347024736 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.adapter; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.scope.IScope; /** * IApplication provides lifecycle methods that most communication applications * will use. This interface defines the methods that are called by Red5 through * an applications life. * * @author Dominick Accattato * */ public interface IApplication { /** * Called once when application or room starts * * @param app Application or room level scope. See * {@link org.red5.server.api.scope.IScope} for details * @return true continues application run, false * terminates */ public boolean appStart(IScope app); /** * Called per each client connect * * @param conn Connection object used to provide basic connection methods. * See {@link org.red5.server.api.IConnection} * @param params List of params sent from client with NetConnection.connect * call * @return true accepts the connection, false * rejects it */ public boolean appConnect(IConnection conn, Object[] params); /** * Called every time client joins app level scope * * @param client Client object * @param app Scope object * @return true accepts the client, false * rejects it */ public boolean appJoin(IClient client, IScope app); /** * Called every time client disconnects from the application * * @param conn Connection object See {@link org.red5.server.api.IConnection} */ public void appDisconnect(IConnection conn); /** * Called every time client leaves the application scope * * @param client Client object * @param app Scope object */ public void appLeave(IClient client, IScope app); /** * Called on application stop * * @param app Scope object */ public void appStop(IScope app); /** * Called on application room start * * @param room Scope object * @return true if scope can be started, false * otherwise */ public boolean roomStart(IScope room); /** * Called every time client connects to the room * * @param conn Connection object * @param params List of params sent from client with NetConnection.connect * call * @return true accepts the connection, false * rejects it */ public boolean roomConnect(IConnection conn, Object[] params); /** * Called when user joins room scope * * @param client Client object * @param room Scope object * @return true accepts the client, false * rejects it */ public boolean roomJoin(IClient client, IScope room); /** * Called when client disconnects from room scope * * @param conn Connection object used to provide basic connection methods. * See {@link org.red5.server.api.IConnection} */ public void roomDisconnect(IConnection conn); /** * Called when user leaves room scope * * @param client Client object * @param room Scope object */ public void roomLeave(IClient client, IScope room); /** * Called on room scope stop * * @param room Scope object */ public void roomStop(IScope room); } red5-1.0~svn4374.orig/src/org/red5/server/adapter/Config.java0000644000175000017500000000241511706617130023532 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.adapter; import java.util.Collections; import java.util.List; /** * Provides configuration details for Applications. * * @author Paul Gregoire (mondain@gmail.com) */ @SuppressWarnings("unchecked") public final class Config { /** * Holder for classes implementing IoFilter. */ private List filterNames = Collections.EMPTY_LIST; public List getFilterNames() { return filterNames; } public void setFilterNames(List filterNames) { this.filterNames = filterNames; } }red5-1.0~svn4374.orig/src/org/red5/server/jmx/0000755000175000017500000000000011760512572020642 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/jmx/JMXUtil.java0000644000175000017500000001075711745776105023022 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx; import java.lang.management.ManagementFactory; import javax.management.MBeanAttributeInfo; import javax.management.MBeanConstructorInfo; import javax.management.MBeanInfo; import javax.management.MBeanNotificationInfo; import javax.management.MBeanOperationInfo; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.StandardMBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Helper methods for working with ObjectName or MBean instances. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class JMXUtil { private static Logger log = LoggerFactory.getLogger(JMXUtil.class); public static void printMBeanInfo(ObjectName objectName, String className) { log.info("Retrieve the management information for the {}", className); log.info("MBean using the getMBeanInfo() method of the MBeanServer"); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); MBeanInfo info = null; try { info = mbs.getMBeanInfo(objectName); } catch (Exception e) { log.error("Could not get MBeanInfo object for {}", className, e); return; } log.info("CLASSNAME: \t" + info.getClassName()); log.info("DESCRIPTION: \t" + info.getDescription()); log.info("ATTRIBUTES"); MBeanAttributeInfo[] attrInfo = info.getAttributes(); if (attrInfo.length > 0) { for (int i = 0; i < attrInfo.length; i++) { log.info(" ** NAME: \t" + attrInfo[i].getName()); log.info(" DESCR: \t" + attrInfo[i].getDescription()); log.info(" TYPE: \t" + attrInfo[i].getType() + "\tREAD: " + attrInfo[i].isReadable() + "\tWRITE: " + attrInfo[i].isWritable()); } } else log.info(" ** No attributes **"); log.info("CONSTRUCTORS"); MBeanConstructorInfo[] constrInfo = info.getConstructors(); for (int i = 0; i < constrInfo.length; i++) { log.info(" ** NAME: \t" + constrInfo[i].getName()); log.info(" DESCR: \t" + constrInfo[i].getDescription()); log.info(" PARAM: \t" + constrInfo[i].getSignature().length + " parameter(s)"); } log.info("OPERATIONS"); MBeanOperationInfo[] opInfo = info.getOperations(); if (opInfo.length > 0) { for (int i = 0; i < opInfo.length; i++) { log.info(" ** NAME: \t" + opInfo[i].getName()); log.info(" DESCR: \t" + opInfo[i].getDescription()); log.info(" PARAM: \t" + opInfo[i].getSignature().length + " parameter(s)"); } } else log.info(" ** No operations ** "); log.info("NOTIFICATIONS"); MBeanNotificationInfo[] notifInfo = info.getNotifications(); if (notifInfo.length > 0) { for (int i = 0; i < notifInfo.length; i++) { log.info(" ** NAME: \t" + notifInfo[i].getName()); log.info(" DESCR: \t" + notifInfo[i].getDescription()); String notifTypes[] = notifInfo[i].getNotifTypes(); for (int j = 0; j < notifTypes.length; j++) { log.info(" TYPE: \t" + notifTypes[j]); } } } else { log.info(" ** No notifications **"); } } @SuppressWarnings({ "unchecked", "rawtypes" }) public static boolean registerNewMBean(Class clazz, Class interfaceClass) { boolean status = false; try { String cName = clazz.getName(); if (cName.indexOf('.') != -1) { cName = cName.substring(cName.lastIndexOf('.')).replaceFirst("[\\.]", ""); } log.debug("Register name: {}", cName); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); mbs.registerMBean(new StandardMBean(Class.forName(clazz.getName()).newInstance(), interfaceClass), new ObjectName("org.red5.server:type=" + cName)); status = true; } catch (Exception e) { log.error("Could not register the {} MBean", clazz.getName(), e); } return status; } }red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/0000755000175000017500000000000011760512572022277 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/WebScopeMXBean.java0000644000175000017500000000232311745776105025713 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import javax.management.MXBean; /** * An MBean interface for the web scope object. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ @MXBean public interface WebScopeMXBean extends ScopeMXBean { public void setContextPath(String contextPath); public void setVirtualHosts(String virtualHosts); public void register(); public void unregister(); public boolean isShuttingDown(); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/ClientMXBean.java0000644000175000017500000000235611706617130025415 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import java.util.List; import java.util.Set; import javax.management.MXBean; import org.red5.server.api.IConnection; /** * MBean for Client. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ @MXBean public interface ClientMXBean { public String getId(); public long getCreationTime(); public Set getConnections(); public List iterateScopeNameList(); public void disconnect(); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/QuartzSchedulingServiceMXBean.java0000644000175000017500000000234411706617130031011 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import java.util.List; import javax.management.MXBean; /** * Scheduling service that uses Quartz as backend. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ @MXBean public interface QuartzSchedulingServiceMXBean { /** * Getter for job name. * * @return Job name */ public String getJobName(); public void removeScheduledJob(String name); public List getScheduledJobNames(); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/ContextMXBean.java0000644000175000017500000000424611747114732025630 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import java.io.IOException; import javax.management.MXBean; import org.red5.server.api.IClientRegistry; import org.red5.server.api.IMappingStrategy; import org.red5.server.api.persistence.IPersistenceStore; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeHandler; import org.red5.server.api.service.IServiceInvoker; import org.springframework.context.ApplicationContext; import org.springframework.core.io.Resource; /** *

This is basic context implementation used by Red5.

*/ @MXBean public interface ContextMXBean { public IScope getGlobalScope(); public IScope resolveScope(String path); public IScope resolveScope(IScope root, String path); public IPersistenceStore getPersistanceStore(); public ApplicationContext getApplicationContext(); public void setContextPath(String contextPath); public IClientRegistry getClientRegistry(); public IScope getScope(); public IServiceInvoker getServiceInvoker(); public Object lookupService(String serviceName); public IScopeHandler lookupScopeHandler(String contextPath); public IMappingStrategy getMappingStrategy(); public Resource[] getResources(String pattern) throws IOException; public Resource getResource(String path); public IScope resolveScope(String host, String path); public Object getBean(String beanId); public Object getCoreService(String beanId); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/Red5MXBean.java0000644000175000017500000000221311706617130024766 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import javax.management.MXBean; /** * JMX interface for accessing Red5 API objects * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ @MXBean public interface Red5MXBean { public ConnectionMXBean getConnection(); public ScopeMXBean getScope(); public ClientMXBean getClient(); public ContextMXBean getContext(); }red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/LoaderMXBean.java0000644000175000017500000000226211706617130025401 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import javax.management.MXBean; /** * Simple mbean interface for J2EE container loaders. Allows for * init and shutdown. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ @MXBean public interface LoaderMXBean extends ShutdownMXBean { public void init(); public void removeContext(String path); public boolean startWebApplication(String application); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/CoreHandlerMXBean.java0000644000175000017500000000335111747114732026366 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import javax.management.MXBean; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.event.IEvent; import org.red5.server.api.scope.IBasicScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.service.IServiceCall; /** * Base IScopeHandler implementation * * @author The Red5 Project (red5@osflash.org) */ @MXBean public interface CoreHandlerMXBean { public boolean connect(IConnection conn, IScope scope); public boolean connect(IConnection conn, IScope scope, Object[] params); public void disconnect(IConnection conn, IScope scope); public boolean join(IClient client, IScope scope); public void leave(IClient client, IScope scope); public void removeChildScope(IBasicScope scope); public boolean serviceCall(IConnection conn, IServiceCall call); public boolean start(IScope scope); public void stop(IScope scope); public boolean handleEvent(IEvent event); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/ScopeMXBean.java0000644000175000017500000001421511747114732025252 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import java.util.Set; import javax.management.MXBean; import org.red5.server.api.scope.ScopeType; /** * An MBean interface for the scope object. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ @MXBean public interface ScopeMXBean { /** * Check if scope is enabled * @return true if scope is enabled, false otherwise */ public boolean getEnabled(); /** * Enable or disable scope by setting enable flag * @param enabled Enable flag value */ public void setEnabled(boolean enabled); /** * Check if scope is in running state * @return true if scope is in running state, false otherwise */ public boolean getRunning(); /** * Setter for autostart flag * @param autoStart Autostart flag value */ public void setAutoStart(boolean autoStart); /** * Initialization actions, start if autostart is set to true */ public void init(); /** * Starts scope * @return true if scope has handler and it's start method returned true, false otherwise */ public boolean start(); /** * Stops scope */ public void stop(); /** * Destroys scope */ public void destroy(); /** * Set scope persistence class * * @param persistenceClass Scope's persistence class * @throws Exception Exception */ public void setPersistenceClass(String persistenceClass) throws Exception; /** * Setter for child load path. Should be implemented in subclasses? * @param pattern Load path pattern */ public void setChildLoadPath(String pattern); /** * Check whether scope has child scope with given name * @param name Child scope name * @return true if scope has child node with given name, false otherwise */ public boolean hasChildScope(String name); /** * Check whether scope has child scope with given name and type * @param type Child scope type * @param name Child scope name * @return true if scope has child node with given name and type, false otherwise */ public boolean hasChildScope(ScopeType type, String name); /** * Check if scope has a context * @return true if scope has context, false otherwise */ public boolean hasContext(); /** * Return scope context path * @return Scope context path */ public String getContextPath(); /** * Setter for scope name * @param name Scope name */ public void setName(String name); /** * Return scope path calculated from parent path and parent scope name * @return Scope path */ public String getPath(); /** * Check if scope or it's parent has handler * @return true if scope or it's parent scope has a handler, false otherwise */ public boolean hasHandler(); /** * Check if scope has parent scope * @return true if scope has parent scope, false otherwise` */ public boolean hasParent(); /** * Set scope depth * @param depth Scope depth */ public void setDepth(int depth); /** * return scope depth * @return Scope depth */ public int getDepth(); /** * Create child scope with given name * @param name Child scope name * @return true on success, false otherwise */ public boolean createChildScope(String name); /** * Unregisters service handler by name * @param name Service handler name */ public void unregisterServiceHandler(String name); /** * Return set of service handler names * @return Set of service handler names */ public Set getServiceHandlerNames(); /** * Return total number of connections to the scope. * * @return number of connections */ public int getTotalConnections(); /** * Return maximum number of concurrent connections to the scope. * * @return number of connections */ public int getMaxConnections(); /** * Return current number of connections to the scope. * * @return number of connections */ public int getActiveConnections(); /** * Return total number of clients connected to the scope. * * @return number of clients */ public int getTotalClients(); /** * Return maximum number of clients concurrently connected to the scope. * * @return number of clients */ public int getMaxClients(); /** * Return current number of clients connected to the scope. * * @return number of clients */ public int getActiveClients(); /** * Return total number of subscopes created. * * @return number of subscopes created */ public int getTotalSubscopes(); /** * Return maximum number of concurrently existing subscopes. * * @return number of subscopes */ public int getMaxSubscopes(); /** * Return number of currently existing subscopes. * * @return number of subscopes */ public int getActiveSubscopes(); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/ShutdownMXBean.java0000644000175000017500000000162611706617130026011 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import javax.management.MXBean; /** * Red5 shutdown hook */ @MXBean public interface ShutdownMXBean { public void shutdown(); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/AttributeStoreMXBean.java0000644000175000017500000000231111745776105027161 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import java.util.Set; import javax.management.MXBean; /** * Base interface for all API objects with attributes * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ @MXBean public interface AttributeStoreMXBean { public Set getAttributeNames(); public boolean hasAttribute(String name); public boolean removeAttribute(String name); public void removeAttributes(); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/GlobalScopeMXBean.java0000644000175000017500000000204511745776105026377 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import javax.management.MXBean; /** * An MBean interface for the scope object. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ @MXBean public interface GlobalScopeMXBean extends ScopeMXBean { public void register(); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/ApplicationMXBean.java0000644000175000017500000000313511747114732026443 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import javax.management.MXBean; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.scope.IScope; /** * JMX mbean for Application. * * @author Paul Gregoire (mondain@gmail.com) */ @MXBean public interface ApplicationMXBean { public boolean appStart(IScope app); public boolean appConnect(IConnection conn, Object[] params); public boolean appJoin(IClient client, IScope app); public void appDisconnect(IConnection conn); public void appLeave(IClient client, IScope app); public void appStop(IScope app); public boolean roomStart(IScope room); public boolean roomConnect(IConnection conn, Object[] params); public boolean roomJoin(IClient client, IScope room); public void roomDisconnect(IConnection conn); public void roomLeave(IClient client, IScope room); public void roomStop(IScope room); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/ConnectionMXBean.java0000644000175000017500000000423511706617130026274 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.management.MXBean; import javax.management.openmbean.CompositeData; /** * The connection object. * * Each connection has an associated client and scope. Connections may be * persistent, polling, or transient. The aim of this interface is to provide * basic connection methods shared between different types of connections * * Future subclasses: RTMPConnection, RemotingConnection, AJAXConnection, * HttpConnection, etc * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ @MXBean public interface ConnectionMXBean { public String getType(); public boolean isConnected(); public void close(); public Map getConnectParams(); public CompositeData getClient(); public String getHost(); public String getRemoteAddress(); public List getRemoteAddresses(); public int getRemotePort(); public String getPath(); public String getSessionId(); public long getReadBytes(); public long getWrittenBytes(); public long getReadMessages(); public long getWrittenMessages(); public long getDroppedMessages(); public long getPendingMessages(); public void ping(); public int getLastPingTime(); public CompositeData getScope(); public Iterator getBasicScopes(); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/RTMPMinaConnectionMXBean.java0000644000175000017500000000321111745776105027610 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import java.util.List; import javax.management.MXBean; /** * Base abstract class for connections. Adds connection specific functionality like work with clients * to AttributeStore. */ @MXBean public interface RTMPMinaConnectionMXBean extends AttributeStoreMXBean { public String getType(); public String getHost(); public String getRemoteAddress(); public List getRemoteAddresses(); public int getRemotePort(); public String getPath(); public String getSessionId(); public boolean isConnected(); public void close(); public long getReadBytes(); public long getWrittenBytes(); public long getReadMessages(); public long getWrittenMessages(); public long getDroppedMessages(); public long getPendingMessages(); public long getPendingVideoMessages(int streamId); public void invokeMethod(String method); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/RTMPMinaTransportMXBean.java0000644000175000017500000000204411745776105027510 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import javax.management.MXBean; /** * */ @MXBean public interface RTMPMinaTransportMXBean { public void setIoThreads(int ioThreads); public void setTcpNoDelay(boolean tcpNoDelay); public void setUseHeapBuffers(boolean useHeapBuffers); public void start() throws Exception; public void stop(); }red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/ClientBroadcastStreamMXBean.java0000644000175000017500000000374511745776105030432 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import java.io.IOException; import javax.management.MXBean; import org.red5.server.api.stream.ResourceExistException; import org.red5.server.api.stream.ResourceNotFoundException; /** * Represents live stream broadcasted from client. As Flash Media Server, Red5 supports * recording mode for live streams, that is, broadcasted stream has broadcast mode. It can be either * "live" or "record" and latter causes server-side application to record broadcasted stream. * * Note that recorded streams are recorded as FLV files. The same is correct for audio, because * NellyMoser codec that Flash Player uses prohibits on-the-fly transcoding to audio formats like MP3 * without paying of licensing fee or buying SDK. * * This type of stream uses two different pipes for live streaming and recording. */ @MXBean public interface ClientBroadcastStreamMXBean { public void start(); public void startPublishing(); public void stop(); public void close(); public void saveAs(String name, boolean isAppend) throws IOException, ResourceNotFoundException, ResourceExistException; public String getSaveFilename(); public String getPublishedName(); public void setPublishedName(String name); } red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/ClientRegistryMXBean.java0000644000175000017500000000250411706617130027141 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import java.util.List; import javax.management.MXBean; import org.red5.server.Client; import org.red5.server.exception.ClientNotFoundException; /** * An MBean interface for the client registry. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ @MXBean public interface ClientRegistryMXBean { public String nextId(); public String previousId(); public boolean hasClient(String id); public List getClientList(); public Client getClient(String id) throws ClientNotFoundException; }red5-1.0~svn4374.orig/src/org/red5/server/jmx/mxbeans/ContextLoaderMXBean.java0000644000175000017500000000237211745776105026763 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.jmx.mxbeans; import javax.management.MXBean; /** * Red5 applications loader */ @MXBean public interface ContextLoaderMXBean extends ShutdownMXBean { public void setContextsConfig(String contextsConfig); public void init() throws Exception; public void shutdown(); public void setParentContext(String parentContextKey, String appContextId); public String getContextsConfig(); public void loadContext(String name, String config); public void unloadContext(String name); } red5-1.0~svn4374.orig/src/org/red5/server/Server.java0000644000175000017500000002643311747114732022166 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.red5.server.api.IConnection; import org.red5.server.api.IServer; import org.red5.server.api.listeners.IConnectionListener; import org.red5.server.api.listeners.IScopeListener; import org.red5.server.api.scope.IGlobalScope; import org.red5.server.api.scope.IScope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.style.ToStringCreator; /** * Red5 server core class implementation. */ public class Server implements IServer, ApplicationContextAware, InitializingBean, DisposableBean { // Initialize Logging protected static Logger log = LoggerFactory.getLogger(Server.class); /** * Executor service used to provide asynchronous notifications. */ private static ExecutorService notifier; /** * List of global scopes */ protected ConcurrentMap globals = new ConcurrentHashMap(); /** * Mappings */ protected ConcurrentMap mapping = new ConcurrentHashMap(); /** * Spring application context */ protected ApplicationContext applicationContext; /** * Constant for slash */ protected static final String SLASH = "/"; /** * Constant for empty string */ protected static final String EMPTY = ""; public Set scopeListeners = new CopyOnWriteArraySet(); public Set connectionListeners = new CopyOnWriteArraySet(); //number of threads in the notifier pool private int notifierThreadPoolSize = 4; /** * Setter for Spring application context * * @param applicationContext Application context */ public void setApplicationContext(ApplicationContext applicationContext) { log.debug("Setting application context"); this.applicationContext = applicationContext; } /** * Initialization section. */ public void afterPropertiesSet() throws Exception { Server.notifier = Executors.newFixedThreadPool(notifierThreadPoolSize); } /** * Destruction section. */ public void destroy() throws Exception { //disable new tasks from being submitted notifier.shutdown(); try { //wait a while for existing tasks to terminate if (!notifier.awaitTermination(3, TimeUnit.SECONDS)) { notifier.shutdownNow(); // cancel currently executing tasks //wait a while for tasks to respond to being canceled if (!notifier.awaitTermination(3, TimeUnit.SECONDS)) { System.err.println("Notifier pool did not terminate"); } } } catch (InterruptedException ie) { // re-cancel if current thread also interrupted notifier.shutdownNow(); // preserve interrupt status Thread.currentThread().interrupt(); } } /** * Return scope key. Scope key consists of host name concatenated with * context path by slash symbol * * @param hostName Host name * @param contextPath Context path * @return Scope key as string */ protected String getKey(String hostName, String contextPath) { if (hostName == null) { hostName = EMPTY; } if (contextPath == null) { contextPath = EMPTY; } return hostName + SLASH + contextPath; } /** * Does global scope lookup for host name and context path * * @param hostName Host name * @param contextPath Context path * @return Global scope */ public IGlobalScope lookupGlobal(String hostName, String contextPath) { log.trace("{}", this); log.debug("Lookup global scope - host name: {} context path: {}", hostName, contextPath); // Init mappings key String key = getKey(hostName, contextPath); // If context path contains slashes get complex key and look for it // in mappings while (contextPath.indexOf(SLASH) != -1) { key = getKey(hostName, contextPath); log.trace("Check: {}", key); String globalName = mapping.get(key); if (globalName != null) { return getGlobal(globalName); } final int slashIndex = contextPath.lastIndexOf(SLASH); // Context path is substring from the beginning and till last slash // index contextPath = contextPath.substring(0, slashIndex); } // Get global scope key key = getKey(hostName, contextPath); log.trace("Check host and path: {}", key); // Look up for global scope switching keys if still not found String globalName = mapping.get(key); if (globalName != null) { return getGlobal(globalName); } key = getKey(EMPTY, contextPath); log.trace("Check wildcard host with path: {}", key); globalName = mapping.get(key); if (globalName != null) { return getGlobal(globalName); } key = getKey(hostName, EMPTY); log.trace("Check host with no path: {}", key); globalName = mapping.get(key); if (globalName != null) { return getGlobal(globalName); } key = getKey(EMPTY, EMPTY); log.trace("Check default host, default path: {}", key); return getGlobal(mapping.get(key)); } /** * Return global scope by name * * @param name Global scope name * @return Global scope */ public IGlobalScope getGlobal(String name) { if (name == null) { return null; } return globals.get(name); } /** * Register global scope * * @param scope Global scope to register */ public void registerGlobal(IGlobalScope scope) { log.trace("Registering global scope: {}", scope.getName(), scope); globals.put(scope.getName(), scope); } /** * Map key (host + / + context path) and global scope name * * @param hostName Host name * @param contextPath Context path * @param globalName Global scope name * @return true if mapping was added, false if already exist */ public boolean addMapping(String hostName, String contextPath, String globalName) { log.info("Add mapping global: {} host: {} context: {}", new Object[] { globalName, hostName, contextPath }); final String key = getKey(hostName, contextPath); log.debug("Add mapping: {} => {}", key, globalName); return (mapping.putIfAbsent(key, globalName) == null); } /** * Remove mapping with given key * * @param hostName Host name * @param contextPath Context path * @return true if mapping was removed, false if key doesn't exist */ public boolean removeMapping(String hostName, String contextPath) { log.info("Remove mapping host: {} context: {}", hostName, contextPath); final String key = getKey(hostName, contextPath); log.debug("Remove mapping: {}", key); return (mapping.remove(key) != null); } /** * Remove all mappings with given context path * * @param contextPath Context path * @return true if mapping was removed, false if key doesn't exist */ public boolean removeMapping(String contextPath) { log.info("Remove mapping context: {}", contextPath); final String key = getKey("", contextPath); log.debug("Remove mapping: {}", key); return (mapping.remove(key) != null); } /** * Return mapping * * @return Map of "scope key / scope name" pairs */ public Map getMappingTable() { return mapping; } /** * Return global scope names set iterator * * @return Iterator */ public Iterator getGlobalNames() { return globals.keySet().iterator(); } /** * Return global scopes set iterator * * @return Iterator */ public Iterator getGlobalScopes() { return globals.values().iterator(); } /** * String representation of server * * @return String representation of server */ @Override public String toString() { return new ToStringCreator(this).append(mapping).toString(); } /** {@inheritDoc} */ public void addListener(IScopeListener listener) { scopeListeners.add(listener); } /** {@inheritDoc} */ public void addListener(IConnectionListener listener) { connectionListeners.add(listener); } /** {@inheritDoc} */ public void removeListener(IScopeListener listener) { scopeListeners.remove(listener); } /** {@inheritDoc} */ public void removeListener(IConnectionListener listener) { connectionListeners.remove(listener); } /** * Notify listeners about a newly created scope. * * @param scope * the scope that was created */ public void notifyScopeCreated(final IScope scope) { Runnable notification = new Runnable(){ public void run() { for (IScopeListener listener : scopeListeners) { listener.notifyScopeCreated(scope); } } }; notifier.execute(notification); } /** * Notify listeners that a scope was removed. * * @param scope * the scope that was removed */ public void notifyScopeRemoved(final IScope scope) { Runnable notification = new Runnable(){ public void run() { for (IScopeListener listener : scopeListeners) { listener.notifyScopeRemoved(scope); } } }; notifier.execute(notification); } /** * Notify listeners that a new connection was established. * * @param conn * the new connection */ public void notifyConnected(final IConnection conn) { Runnable notification = new Runnable(){ public void run() { for (IConnectionListener listener : connectionListeners) { listener.notifyConnected(conn); } } }; notifier.execute(notification); } /** * Notify listeners that a connection was disconnected. * * @param conn * the disconnected connection */ public void notifyDisconnected(final IConnection conn) { Runnable notification = new Runnable(){ public void run() { for (IConnectionListener listener : connectionListeners) { listener.notifyDisconnected(conn); } } }; notifier.execute(notification); } public int getNotifierThreadPoolSize() { return notifierThreadPoolSize; } public void setNotifierThreadPoolSize(int notifierThreadPoolSize) { this.notifierThreadPoolSize = notifierThreadPoolSize; } } red5-1.0~svn4374.orig/src/org/red5/server/PersistableAttributeStore.java0000644000175000017500000001513211745776105026076 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.red5.io.object.Deserializer; import org.red5.io.object.Input; import org.red5.io.object.Output; import org.red5.io.object.Serializer; import org.red5.server.api.IAttributeStore; import org.red5.server.api.persistence.IPersistable; import org.red5.server.api.persistence.IPersistenceStore; /** * Persistable attributes store. Server-side SharedObjects feature based on this class. */ public class PersistableAttributeStore extends AttributeStore implements IPersistable { /** * Persistence flag */ protected boolean persistent = true; /** * Attribute store name */ protected String name; /** * Attribute store type */ protected String type; /** * Attribute store path (on local hard drive) */ protected String path; /** * Last modified Timestamp */ protected long lastModified = -1; /** * Store object that deals with save/load routines */ protected IPersistenceStore store; /** * Creates persistable attribute store * * @param type Attribute store type * @param name Attribute store name * @param path Attribute store path * @param persistent Whether store is persistent or not */ public PersistableAttributeStore(String type, String name, String path, boolean persistent) { super(); this.type = type; this.name = name; this.path = path; this.persistent = persistent; } /** * Set last modified flag to current system time */ protected void modified() { lastModified = System.currentTimeMillis(); if (store != null) { store.save(this); } } /** * Check whether object is persistent or not * * @return true if object is persistent, false otherwise */ public boolean isPersistent() { return persistent; } /** * Set for persistence * @param persistent Persistence flag value */ public void setPersistent(boolean persistent) { this.persistent = persistent; } /** * Returns last modification time as timestamp * @return Timestamp of last attribute modification */ public long getLastModified() { return lastModified; } /** * Return store name * @return Store name */ public String getName() { return name; } /** * Setter for name * @param name Name */ public void setName(String name) { this.name = name; } /** * Ruturn scope path * @return Path */ public String getPath() { return path; } /** * Setter for scope path * @param path Path */ public void setPath(String path) { this.path = path; } /** * Return scope type * @return Scope type */ public String getType() { return type; } /** * Serializes byte buffer output, storing them to attributes * * @param output Output object * @throws IOException if error */ public void serialize(Output output) throws IOException { Serializer serializer = new Serializer(); Map persistentAttributes = new HashMap(); for (Map.Entry entry : getAttributes().entrySet()) { final String name = entry.getKey(); if (name.startsWith(IPersistable.TRANSIENT_PREFIX)) { continue; } persistentAttributes.put(name, entry.getValue()); } serializer.serialize(output, persistentAttributes); } /** * Deserializes data from input to attributes * * @param input Input object * @throws IOException I/O exception */ public void deserialize(Input input) throws IOException { Deserializer deserializer = new Deserializer(); setAttributes(deserializer.> deserialize(input, Map.class)); } /** * Load data from another persistent store * * @param store Persistent store */ public void setStore(IPersistenceStore store) { if (this.store != null) { this.store.notifyClose(); } this.store = store; if (store != null) { store.load(this); } } /** * Return persistent store * @return Persistence store */ public IPersistenceStore getStore() { return store; } /** {@inheritDoc} */ @Override public Object getAttribute(String name, Object defaultValue) { if (name == null) { return null; } if (defaultValue == null) { throw new NullPointerException("the default value may not be null"); } Object result = attributes.putIfAbsent(name, defaultValue); if (result == null) { // The default value has been set modified(); result = defaultValue; } return result; } /** * Set attribute by name and return success as boolean * * @param name Attribute name * @param value Attribute value * @return true if attribute was set, false otherwise */ @Override public boolean setAttribute(String name, Object value) { boolean result = super.setAttribute(name, value); if (result && name != null && !name.startsWith(IPersistable.TRANSIENT_PREFIX)) { modified(); } return result; } /** * Set attributes from Map * * @param values Attributes as Map */ @Override public void setAttributes(Map values) { super.setAttributes(values); modified(); } /** * Bulk set of attributes from another attributes store * * @param values Attributes store */ @Override public void setAttributes(IAttributeStore values) { super.setAttributes(values); modified(); } /** * Removes attribute * @param name Attribute name * @return true if attribute was removed, false otherwise */ @Override public boolean removeAttribute(String name) { boolean result = super.removeAttribute(name); if (result && name != null && !name.startsWith(IPersistable.TRANSIENT_PREFIX)) { modified(); } return result; } /** * Removes all attributes and sets modified flag */ @Override public void removeAttributes() { super.removeAttributes(); modified(); } } red5-1.0~svn4374.orig/src/org/red5/server/Bootstrap.java0000644000175000017500000001400411706617130022657 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.red5.classloading.ClassLoaderBuilder; /** * Boot-straps Red5 using the latest available jars found in red5.home/lib directory. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) * @author Dominick Accattato (daccattato@gmail.com) */ public class Bootstrap { /** * BootStrapping entry point * * @param args command line arguments * @throws Exception if error occurs */ public static void main(String[] args) throws Exception { //retrieve path elements from system properties String root = getRed5Root(); getConfigurationRoot(root); //bootstrap dependencies and start red5 bootStrap(); System.out.println("Bootstrap complete"); } /** * Loads classloader with dependencies * * @throws InstantiationException * @throws IllegalAccessException * @throws ClassNotFoundException * @throws NoSuchMethodException * @throws InvocationTargetException */ private static void bootStrap() throws InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException { // print the classpath //String classPath = System.getProperty("java.class.path"); //System.out.printf("JVM classpath: %s\n", classPath); System.setProperty("red5.deployment.type", "bootstrap"); System.setProperty("sun.lang.ClassLoader.allowArraySyntax", "true"); //check system property before forcing out selector if (System.getProperty("logback.ContextSelector") == null) { //set to use our logger System.setProperty("logback.ContextSelector", "org.red5.logging.LoggingContextSelector"); } String policyFile = System.getProperty("java.security.policy"); if (policyFile == null) { System.setProperty("java.security.debug", "all"); System.setProperty("java.security.policy", "conf/red5.policy"); } //set the temp directory if we're vista or later String os = System.getProperty("os.name").toLowerCase(); //String arch = System.getProperty("os.arch").toLowerCase(); //System.out.printf("OS: %s Arch: %s\n", os, arch); if (os.contains("vista") || os.contains("windows 7")) { String dir = System.getProperty("user.home"); //detect base drive (c:\ etc) if (dir.length() == 3) { //use default dir += "Users\\Default\\AppData\\Red5"; //make sure the directory exists File f = new File(dir); if (!f.exists()) { f.mkdir(); } f = null; } else { dir += "\\AppData\\localLow"; } System.setProperty("java.io.tmpdir", dir); System.out.printf("Setting temp directory to %s\n", System.getProperty("java.io.tmpdir")); } /* try { // Enable the security manager SecurityManager sm = new SecurityManager(); System.setSecurityManager(sm); } catch (SecurityException se) { System.err.println("Security manager already set"); } */ //get current loader ClassLoader baseLoader = Thread.currentThread().getContextClassLoader(); // build a ClassLoader ClassLoader loader = ClassLoaderBuilder.build(); //set new loader as the loader for this thread Thread.currentThread().setContextClassLoader(loader); // create a new instance of this class using new classloader Object boot = Class.forName("org.red5.server.Launcher", true, loader).newInstance(); Method m1 = boot.getClass().getMethod("launch", (Class[]) null); m1.invoke(boot, (Object[]) null); //not that it matters, but set it back to the original loader Thread.currentThread().setContextClassLoader(baseLoader); } /** * Gets the configuration root * * @param root * @return */ private static String getConfigurationRoot(String root) { // look for config dir String conf = System.getProperty("red5.config_root"); // if root is not null and conf is null then default it if (root != null && conf == null) { conf = root + "/conf"; } //flip slashes only if windows based os if (File.separatorChar != '/') { conf = conf.replaceAll("\\\\", "/"); } //set conf sysprop System.setProperty("red5.config_root", conf); System.out.printf("Configuation root: %s\n", conf); return conf; } /** * Gets the Red5 root * * @return * @throws IOException */ private static String getRed5Root() throws IOException { // look for red5 root first as a system property String root = System.getProperty("red5.root"); // if root is null check environmental if (root == null) { //check for env variable root = System.getenv("RED5_HOME"); } // if root is null find out current directory and use it as root if (root == null || ".".equals(root)) { root = System.getProperty("user.dir"); //System.out.printf("Current directory: %s\n", root); } //if were on a windows based os flip the slashes if (File.separatorChar != '/') { root = root.replaceAll("\\\\", "/"); } //drop last slash if exists if (root.charAt(root.length() - 1) == '/') { root = root.substring(0, root.length() - 1); } //set/reset property System.setProperty("red5.root", root); System.out.printf("Red5 root: %s\n", root); return root; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/0000755000175000017500000000000011760512571021336 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/stream/PlayEngine.java0000644000175000017500000015465511747114732024256 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.amf.Output; import org.red5.io.object.Serializer; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.scheduling.IScheduledJob; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.api.scope.IBroadcastScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IAudioStreamCodec; import org.red5.server.api.stream.IBroadcastStream; import org.red5.server.api.stream.IPlayItem; import org.red5.server.api.stream.IPlaylistSubscriberStream; import org.red5.server.api.stream.IStreamCodecInfo; import org.red5.server.api.stream.ISubscriberStream; import org.red5.server.api.stream.IVideoStreamCodec; import org.red5.server.api.stream.OperationNotSupportedException; import org.red5.server.api.stream.StreamState; import org.red5.server.api.stream.support.DynamicPlayItem; import org.red5.server.messaging.AbstractMessage; import org.red5.server.messaging.IFilter; import org.red5.server.messaging.IMessage; import org.red5.server.messaging.IMessageComponent; import org.red5.server.messaging.IMessageInput; import org.red5.server.messaging.IMessageOutput; import org.red5.server.messaging.IPassive; import org.red5.server.messaging.IPipe; import org.red5.server.messaging.IPipeConnectionListener; import org.red5.server.messaging.IProvider; import org.red5.server.messaging.IPushableConsumer; import org.red5.server.messaging.OOBControlMessage; import org.red5.server.messaging.PipeConnectionEvent; import org.red5.server.net.rtmp.event.Aggregate; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.Ping; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.net.rtmp.event.VideoData.FrameType; import org.red5.server.net.rtmp.message.Constants; import org.red5.server.net.rtmp.message.Header; import org.red5.server.net.rtmp.status.Status; import org.red5.server.net.rtmp.status.StatusCodes; import org.red5.server.stream.codec.StreamCodecInfo; import org.red5.server.stream.message.RTMPMessage; import org.red5.server.stream.message.ResetMessage; import org.red5.server.stream.message.StatusMessage; import org.slf4j.Logger; /** * A play engine for playing an IPlayItem. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong * @author Paul Gregoire (mondain@gmail.com) * @author Dan Rossi * @author Tiago Daniel Jacobs (tiago@imdt.com.br) * @author Vladimir Hmelyoff (vlhm@splitmedialabs.com) */ public final class PlayEngine implements IFilter, IPushableConsumer, IPipeConnectionListener { private static final Logger log = Red5LoggerFactory.getLogger(PlayEngine.class); private IMessageInput msgIn; private IMessageOutput msgOut; private final ISubscriberStream subscriberStream; private ISchedulingService schedulingService; private IConsumerService consumerService; private IProviderService providerService; private int streamId; /** * Receive video? */ private boolean receiveVideo = true; /** * Receive audio? */ private boolean receiveAudio = true; private boolean pullMode; private String waitLiveJob; private boolean waiting; /** * timestamp of first sent packet */ private int streamStartTS; private IPlayItem currentItem; private RTMPMessage pendingMessage; /** * Interval in ms to check for buffer underruns in VOD streams. */ private int bufferCheckInterval = 0; /** * Number of pending messages at which a NetStream.Play.InsufficientBW * message is generated for VOD streams. */ private int underrunTrigger = 10; /** * threshold for number of pending video frames */ private int maxPendingVideoFramesThreshold = 10; /** * if we have more than 1 pending video frames, but less than maxPendingVideoFrames, * continue sending until there are this many sequential frames with more than 1 * pending */ private int maxSequentialPendingVideoFrames = 10; /** * the number of sequential video frames with > 0 pending frames */ private int numSequentialPendingVideoFrames = 0; /** * State machine for video frame dropping in live streams */ private IFrameDropper videoFrameDropper = new VideoFrameDropper(); private int timestampOffset = 0; /** * Timestamp of the last message sent to the client. */ private int lastMessageTs = -1; /** * Number of bytes sent. */ private AtomicLong bytesSent = new AtomicLong(0); /** * Start time of stream playback. * It's not a time when the stream is being played but the time when the stream should be played if it's played * from the very beginning. * Eg. A stream is played at timestamp 5s on 1:00:05. The playbackStart is 1:00:00. */ private volatile long playbackStart; /** * Scheduled future job that makes sure messages are sent to the client. */ private volatile ScheduledFuture pullAndPushFuture; /** * Monitor guarding completion of a given push/pull run. * Used to wait for job cancellation to finish. */ private final AtomicBoolean pushPullRunning = new AtomicBoolean(false); /** * Offset in milliseconds where the stream started. */ private int streamOffset; /** * Timestamp when buffer should be checked for underruns next. */ private long nextCheckBufferUnderrun; /** * Send blank audio packet next? */ private boolean sendBlankAudio; /** * decision: 0 for Live, 1 for File, 2 for Wait, 3 for N/A */ private int playDecision = 3; /** * List of pending operations */ private ConcurrentLinkedQueue pendingOperations; /** * Constructs a new PlayEngine. */ private PlayEngine(Builder builder) { subscriberStream = builder.subscriberStream; schedulingService = builder.schedulingService; consumerService = builder.consumerService; providerService = builder.providerService; // get the stream id streamId = subscriberStream.getStreamId(); // create pending operation list pendingOperations = new ConcurrentLinkedQueue(); } /** * Builder pattern */ public final static class Builder { //Required for play engine private ISubscriberStream subscriberStream; //Required for play engine private ISchedulingService schedulingService; //Required for play engine private IConsumerService consumerService; //Required for play engine private IProviderService providerService; public Builder(ISubscriberStream subscriberStream, ISchedulingService schedulingService, IConsumerService consumerService, IProviderService providerService) { this.subscriberStream = subscriberStream; this.schedulingService = schedulingService; this.consumerService = consumerService; this.providerService = providerService; } public PlayEngine build() { return new PlayEngine(this); } } public void setBufferCheckInterval(int bufferCheckInterval) { this.bufferCheckInterval = bufferCheckInterval; } public void setUnderrunTrigger(int underrunTrigger) { this.underrunTrigger = underrunTrigger; } void setMessageOut(IMessageOutput msgOut) { this.msgOut = msgOut; } /** * Start stream */ public void start() { switch (subscriberStream.getState()) { case UNINIT: // allow start if uninitialized // change state to stopped subscriberStream.setState(StreamState.STOPPED); if (msgOut == null) { msgOut = consumerService.getConsumerOutput(subscriberStream); msgOut.subscribe(this, null); } break; default: throw new IllegalStateException(String.format("Cannot start in current state: %s", subscriberStream.getState())); } } /** * Play stream * @param item Playlist item * @throws StreamNotFoundException Stream not found * @throws IllegalStateException Stream is in stopped state * @throws IOException Stream had io exception */ public void play(IPlayItem item) throws StreamNotFoundException, IllegalStateException, IOException { play(item, true); } /** * Play stream * @param item Playlist item * @param withReset Send reset status before playing. * @throws StreamNotFoundException Stream not found * @throws IllegalStateException Stream is in stopped state * @throws IOException Stream had IO exception */ public void play(IPlayItem item, boolean withReset) throws StreamNotFoundException, IllegalStateException, IOException { // cannot play if state is not stopped switch (subscriberStream.getState()) { case STOPPED: //allow play if stopped if (msgIn != null) { msgIn.unsubscribe(this); msgIn = null; } break; default: throw new IllegalStateException("Cannot play from non-stopped state"); } // Play type determination // http://livedocs.adobe.com/flex/3/langref/flash/net/NetStream.html#play%28%29 // The start time, in seconds. Allowed values are -2, -1, 0, or a positive number. // The default value is -2, which looks for a live stream, then a recorded stream, // and if it finds neither, opens a live stream. // If -1, plays only a live stream. // If 0 or a positive number, plays a recorded stream, beginning start seconds in. // // -2: live then recorded, -1: live, >=0: recorded int type = (int) (item.getStart() / 1000); log.debug("Type {}", type); // see if it's a published stream IScope thisScope = subscriberStream.getScope(); final String itemName = item.getName(); //check for input and type IProviderService.INPUT_TYPE sourceType = providerService.lookupProviderInput(thisScope, itemName, type); boolean isPublishedStream = sourceType == IProviderService.INPUT_TYPE.LIVE; boolean isPublishedStreamWait = sourceType == IProviderService.INPUT_TYPE.LIVE_WAIT; boolean isFileStream = sourceType == IProviderService.INPUT_TYPE.VOD; boolean sendNotifications = true; // decision: 0 for Live, 1 for File, 2 for Wait, 3 for N/A switch (type) { case -2: if (isPublishedStream) { playDecision = 0; } else if (isFileStream) { playDecision = 1; } else if (isPublishedStreamWait) { playDecision = 2; } break; case -1: if (isPublishedStream) { playDecision = 0; } else { playDecision = 2; } break; default: if (isFileStream) { playDecision = 1; } break; } log.debug("Play decision is {} (0=Live, 1=File, 2=Wait, 3=N/A)", playDecision); IMessage msg = null; currentItem = item; long itemLength = item.getLength(); log.debug("Item length: {}", itemLength); switch (playDecision) { case 0: //get source input without create msgIn = providerService.getLiveProviderInput(thisScope, itemName, false); //drop all frames up to the next keyframe videoFrameDropper.reset(IFrameDropper.SEND_KEYFRAMES_CHECK); if (msgIn instanceof IBroadcastScope) { IBroadcastStream stream = (IBroadcastStream) ((IBroadcastScope) msgIn).getClientBroadcastStream(); if (stream != null && stream.getCodecInfo() != null) { IVideoStreamCodec videoCodec = stream.getCodecInfo().getVideoCodec(); if (videoCodec != null) { if (withReset) { sendReset(); sendResetStatus(item); sendStartStatus(item); } sendNotifications = false; } } } //Subscribe to stream (ClientBroadcastStream.onPipeConnectionEvent) msgIn.subscribe(this, null); //execute the processes to get Live playback setup playLive(); break; case 2: //get source input with create msgIn = providerService.getLiveProviderInput(thisScope, itemName, true); msgIn.subscribe(this, null); waiting = true; if (type == -1 && itemLength >= 0) { log.debug("Creating wait job"); // Wait given timeout for stream to be published waitLiveJob = schedulingService.addScheduledOnceJob(itemLength, new IScheduledJob() { public void execute(ISchedulingService service) { //set the msgIn if its null if (msgIn == null) { connectToProvider(itemName); } waitLiveJob = null; waiting = false; subscriberStream.onChange(StreamState.END); } }); } else if (type == -2) { log.debug("Creating wait job"); // Wait x seconds for the stream to be published waitLiveJob = schedulingService.addScheduledOnceJob(15000, new IScheduledJob() { public void execute(ISchedulingService service) { //set the msgIn if its null if (msgIn == null) { connectToProvider(itemName); } waitLiveJob = null; waiting = false; } }); } else { connectToProvider(itemName); } break; case 1: msgIn = providerService.getVODProviderInput(thisScope, itemName); if (msgIn == null) { sendStreamNotFoundStatus(currentItem); throw new StreamNotFoundException(itemName); } else if (msgIn.subscribe(this, null)) { //execute the processes to get VOD playback setup msg = playVOD(withReset, itemLength); } else { log.error("Input source subscribe failed"); throw new IOException(String.format("Subscribe to %s failed", itemName)); } break; default: sendStreamNotFoundStatus(currentItem); throw new StreamNotFoundException(itemName); } //continue with common play processes (live and vod) if (sendNotifications) { if (withReset) { sendReset(); sendResetStatus(item); } sendStartStatus(item); if (!withReset) { sendSwitchStatus(); } // if its dynamic playback send the complete status if (item instanceof DynamicPlayItem) { sendTransitionStatus(); } } if (msg != null) { sendMessage((RTMPMessage) msg); } subscriberStream.onChange(StreamState.PLAYING, currentItem, !pullMode); if (withReset) { long currentTime = System.currentTimeMillis(); playbackStart = currentTime - streamOffset; nextCheckBufferUnderrun = currentTime + bufferCheckInterval; if (currentItem.getLength() != 0) { ensurePullAndPushRunning(); } } } /** * Performs the processes needed for live streams. * The following items are sent if they exist: * - Metadata * - Decoder configurations (ie. AVC codec) * - Most recent keyframe * * @throws IOException */ private final void playLive() throws IOException { //change state subscriberStream.setState(StreamState.PLAYING); streamOffset = 0; streamStartTS = -1; //get the stream so that we can grab any metadata and decoder configs IBroadcastStream stream = (IBroadcastStream) ((IBroadcastScope) msgIn).getClientBroadcastStream(); //prevent an NPE when a play list is created and then immediately flushed if (stream != null) { Notify metaData = stream.getMetaData(); //check for metadata to send if (metaData != null) { log.debug("Metadata is available"); RTMPMessage metaMsg = RTMPMessage.build(metaData, 0); try { msgOut.pushMessage(metaMsg); } catch (IOException e) { log.warn("Error sending metadata", e); } } else { log.debug("No metadata available"); } IStreamCodecInfo codecInfo = stream.getCodecInfo(); log.debug("Codec info: {}", codecInfo); if (codecInfo instanceof StreamCodecInfo) { StreamCodecInfo info = (StreamCodecInfo) codecInfo; IVideoStreamCodec videoCodec = info.getVideoCodec(); log.debug("Video codec: {}", videoCodec); if (videoCodec != null) { //check for decoder configuration to send IoBuffer config = videoCodec.getDecoderConfiguration(); if (config != null) { log.debug("Decoder configuration is available for {}", videoCodec.getName()); //log.debug("Dump:\n{}", Hex.encodeHex(config.array())); VideoData conf = new VideoData(config.asReadOnlyBuffer()); log.trace("Configuration ts: {}", conf.getTimestamp()); RTMPMessage confMsg = RTMPMessage.build(conf); try { log.debug("Pushing decoder configuration"); msgOut.pushMessage(confMsg); } finally { conf.release(); } } //check for a keyframe to send IoBuffer keyFrame = videoCodec.getKeyframe(); if (keyFrame != null) { log.debug("Keyframe is available"); VideoData video = new VideoData(keyFrame.asReadOnlyBuffer()); log.trace("Keyframe ts: {}", video.getTimestamp()); //log.debug("Dump:\n{}", Hex.encodeHex(keyFrame.array())); RTMPMessage videoMsg = RTMPMessage.build(video); try { log.debug("Pushing keyframe"); msgOut.pushMessage(videoMsg); } finally { video.release(); } } } else { log.debug("Could not initialize stream output, videoCodec is null."); } // SplitmediaLabs - begin AAC fix IAudioStreamCodec audioCodec = info.getAudioCodec(); log.debug("Audio codec: {}", audioCodec); if (audioCodec != null) { //check for decoder configuration to send IoBuffer config = audioCodec.getDecoderConfiguration(); if (config != null) { log.debug("Decoder configuration is available for {}", audioCodec.getName()); //log.debug("Dump:\n{}", Hex.encodeHex(config.array())); AudioData conf = new AudioData(config.asReadOnlyBuffer()); log.trace("Configuration ts: {}", conf.getTimestamp()); RTMPMessage confMsg = RTMPMessage.build(conf); try { log.debug("Pushing decoder configuration"); msgOut.pushMessage(confMsg); } finally { conf.release(); } } } else { log.debug("No decoder configuration available, audioCodec is null."); } } } } /** * Performs the processes needed for VOD / pre-recorded streams. * * @param withReset whether or not to perform reset on the stream * @param itemLength length of the item to be played * @return message for the consumer * @throws IOException */ private final IMessage playVOD(boolean withReset, long itemLength) throws IOException { IMessage msg = null; //change state subscriberStream.setState(StreamState.PLAYING); streamOffset = 0; streamStartTS = -1; if (withReset) { releasePendingMessage(); } sendVODInitCM(msgIn, currentItem); // Don't use pullAndPush to detect IOExceptions prior to sending // NetStream.Play.Start if (currentItem.getStart() > 0) { streamOffset = sendVODSeekCM(msgIn, (int) currentItem.getStart()); // We seeked to the nearest keyframe so use real timestamp now if (streamOffset == -1) { streamOffset = (int) currentItem.getStart(); } } msg = msgIn.pullMessage(); if (msg instanceof RTMPMessage) { // Only send first video frame IRTMPEvent body = ((RTMPMessage) msg).getBody(); if (itemLength == 0) { while (body != null && !(body instanceof VideoData)) { msg = msgIn.pullMessage(); if (msg != null && msg instanceof RTMPMessage) { body = ((RTMPMessage) msg).getBody(); } else { break; } } } if (body != null) { // Adjust timestamp when playing lists body.setTimestamp(body.getTimestamp() + timestampOffset); } } return msg; } /** * Connects to the data provider. * * @param itemName name of the item to play */ private final void connectToProvider(String itemName) { log.debug("Attempting connection to {}", itemName); IScope thisScope = subscriberStream.getScope(); msgIn = providerService.getLiveProviderInput(thisScope, itemName, true); if (msgIn != null) { log.debug("Provider: {}", msgIn); if (msgIn.subscribe(this, null)) { log.debug("Subscribed to {} provider", itemName); //execute the processes to get Live playback setup try { playLive(); } catch (IOException e) { log.warn("Could not play live stream: {}", itemName, e); } } else { log.warn("Subscribe to {} provider failed", itemName); } } else { log.warn("Provider was not found for {}", itemName); StreamService.sendNetStreamStatus(subscriberStream.getConnection(), StatusCodes.NS_PLAY_STREAMNOTFOUND, "Stream was not found", itemName, Status.ERROR, streamId); } } /** * Pause at position * * @param position Position in file * @throws IllegalStateException If stream is stopped */ public void pause(int position) throws IllegalStateException { switch (subscriberStream.getState()) { // allow pause if playing or stopped case PLAYING: case STOPPED: subscriberStream.setState(StreamState.PAUSED); clearWaitJobs(); sendClearPing(); sendPauseStatus(currentItem); subscriberStream.onChange(StreamState.PAUSED, currentItem, position); break; default: throw new IllegalStateException("Cannot pause in current state"); } } /** * Resume playback * * @param position Resumes playback * @throws IllegalStateException If stream is stopped */ public void resume(int position) throws IllegalStateException { switch (subscriberStream.getState()) { // allow resume from pause case PAUSED: subscriberStream.setState(StreamState.PLAYING); sendReset(); sendResumeStatus(currentItem); if (pullMode) { sendVODSeekCM(msgIn, position); subscriberStream.onChange(StreamState.RESUMED, currentItem, position); playbackStart = System.currentTimeMillis() - position; if (currentItem.getLength() >= 0 && (position - streamOffset) >= currentItem.getLength()) { // Resume after end of stream stop(); } else { ensurePullAndPushRunning(); } } else { subscriberStream.onChange(StreamState.RESUMED, currentItem, position); videoFrameDropper.reset(VideoFrameDropper.SEND_KEYFRAMES_CHECK); } break; default: throw new IllegalStateException("Cannot resume from non-paused state"); } } /** * Seek to a given position * * @param position Position * @throws IllegalStateException If stream is in stopped state * @throws OperationNotSupportedException If this object doesn't support the operation. */ public void seek(int position) throws IllegalStateException, OperationNotSupportedException { // add this pending seek operation to the list pendingOperations.add(new SeekRunnable(position)); } /** * Stop playback * * @throws IllegalStateException If stream is in stopped state */ public void stop() throws IllegalStateException { switch (subscriberStream.getState()) { // allow stop if playing or paused case PLAYING: case PAUSED: subscriberStream.setState(StreamState.STOPPED); if (msgIn != null && !pullMode) { msgIn.unsubscribe(this); msgIn = null; } subscriberStream.onChange(StreamState.STOPPED, currentItem); clearWaitJobs(); if (subscriberStream instanceof IPlaylistSubscriberStream) { IPlaylistSubscriberStream pss = (IPlaylistSubscriberStream) subscriberStream; if (!pss.hasMoreItems()) { releasePendingMessage(); if (pss.getItemSize() > 0) { sendCompleteStatus(); } bytesSent.set(0); sendClearPing(); sendStopStatus(currentItem); } else { if (lastMessageTs > 0) { // remember last timestamp so we can generate correct headers in playlists. timestampOffset = lastMessageTs; } pss.nextItem(); } } break; default: throw new IllegalStateException("Cannot stop in current state"); } } /** * Close stream */ public void close() { if (!subscriberStream.getState().equals(StreamState.CLOSED)) { if (msgIn != null) { msgIn.unsubscribe(this); msgIn = null; } subscriberStream.setState(StreamState.CLOSED); clearWaitJobs(); releasePendingMessage(); lastMessageTs = 0; sendClearPing(); } else { log.debug("Stream is already in closed state"); } } /** * Check if it's okay to send the client more data. This takes the configured * bandwidth as well as the requested client buffer into account. * * @param message * @return */ private boolean okayToSendMessage(IRTMPEvent message) { if (message instanceof IStreamData) { final long now = System.currentTimeMillis(); // check client buffer size if (isClientBufferFull(now)) { return false; } // get pending message count long pending = pendingMessages(); if (bufferCheckInterval > 0 && now >= nextCheckBufferUnderrun) { if (pending > underrunTrigger) { // client is playing behind speed, notify him sendInsufficientBandwidthStatus(currentItem); } nextCheckBufferUnderrun = now + bufferCheckInterval; } // check for under run if (pending > underrunTrigger) { // too many messages already queued on the connection return false; } return true; } else { String itemName = "Undefined"; // if current item exists get the name to help debug this issue if (currentItem != null) { itemName = currentItem.getName(); } Object[] errorItems = new Object[] { message.getClass(), message.getDataType(), itemName }; throw new RuntimeException(String.format("Expected IStreamData but got %s (type %s) for %s", errorItems)); } } /** * Estimate client buffer fill. * @param now The current timestamp being used. * @return True if it appears that the client buffer is full, otherwise false. */ private boolean isClientBufferFull(final long now) { // check client buffer length when we've already sent some messages if (lastMessageTs > 0) { // duration the stream is playing / playback duration final long delta = now - playbackStart; // buffer size as requested by the client final long buffer = subscriberStream.getClientBufferDuration(); // expected amount of data present in client buffer final long buffered = lastMessageTs - delta; log.trace("isClientBufferFull: timestamp {} delta {} buffered {} buffer duration {}", new Object[] { lastMessageTs, delta, buffered, buffer }); // fix for SN-122, this sends double the size of the client buffer if (buffer > 0 && buffered > (buffer * 2)) { // client is likely to have enough data in the buffer return true; } } return false; } private boolean isClientBufferEmpty() { // check client buffer length when we've already sent some messages if (lastMessageTs > 0) { // duration the stream is playing / playback duration final long delta = System.currentTimeMillis() - playbackStart; // expected amount of data present in client buffer final long buffered = lastMessageTs - delta; log.trace("isClientBufferEmpty: timestamp {} delta {} buffered {}", new Object[] { lastMessageTs, delta, buffered }); if (buffered < 0) { return true; } } return false; } /** * Make sure the pull and push processing is running. */ private void ensurePullAndPushRunning() { if (pullMode && pullAndPushFuture == null) { // client buffer is at least 100ms pullAndPushFuture = subscriberStream.getExecutor().scheduleWithFixedDelay(new PullAndPushRunnable(), 0, 10, TimeUnit.MILLISECONDS); } } /** * Clear all scheduled waiting jobs */ private void clearWaitJobs() { log.debug("Clear wait jobs"); if (pullAndPushFuture != null) { log.debug("Push / pull cancelled: {}", pullAndPushFuture.cancel(false)); releasePendingMessage(); pullAndPushFuture = null; } if (waitLiveJob != null) { schedulingService.removeScheduledJob(waitLiveJob); waitLiveJob = null; } } /** * Sends a status message. * * @param status */ private void doPushMessage(Status status) { StatusMessage message = new StatusMessage(); message.setBody(status); doPushMessage(message); } /** * Send message to output stream and handle exceptions. * * @param message The message to send. */ private void doPushMessage(AbstractMessage message) { try { msgOut.pushMessage(message); if (message instanceof RTMPMessage) { IRTMPEvent body = ((RTMPMessage) message).getBody(); //update the last message sent's timestamp lastMessageTs = body.getTimestamp(); IoBuffer streamData = null; if (body instanceof IStreamData && (streamData = ((IStreamData) body).getData()) != null) { bytesSent.addAndGet(streamData.limit()); } } } catch (IOException err) { log.error("Error while pushing message", err); } } /** * Send RTMP message * @param message RTMP message */ private void sendMessage(RTMPMessage messageIn) { //copy patch from Andy Shaules IRTMPEvent event; IoBuffer dataReference; switch (messageIn.getBody().getDataType()) { case Constants.TYPE_AGGREGATE: dataReference = ((Aggregate) messageIn.getBody()).getData(); event = new Aggregate(dataReference); event.setTimestamp(messageIn.getBody().getTimestamp()); break; case Constants.TYPE_AUDIO_DATA: dataReference = ((AudioData) messageIn.getBody()).getData(); event = new AudioData(dataReference); event.setTimestamp(messageIn.getBody().getTimestamp()); break; case Constants.TYPE_VIDEO_DATA: dataReference = ((VideoData) messageIn.getBody()).getData(); event = new VideoData(dataReference); event.setTimestamp(messageIn.getBody().getTimestamp()); break; default: dataReference = ((Notify) messageIn.getBody()).getData(); event = new Notify(dataReference); event.setTimestamp(messageIn.getBody().getTimestamp()); break; } RTMPMessage messageOut = RTMPMessage.build(event); //get the current timestamp from the message int ts = messageOut.getBody().getTimestamp(); if (log.isTraceEnabled()) { log.trace("sendMessage: streamStartTS={}, length={}, streamOffset={}, timestamp={}", new Object[] { streamStartTS, currentItem.getLength(), streamOffset, ts }); } // don't reset streamStartTS to 0 for live streams if ((streamStartTS == -1 && (ts > 0 || playDecision != 0)) || streamStartTS > ts) { log.debug("sendMessage: resetting streamStartTS"); streamStartTS = ts; messageOut.getBody().setTimestamp(0); } //relative timestamp adjustment for live streams if (playDecision == 0 && streamStartTS > 0) { //subtract the offset time of when the stream started playing for the client ts -= streamStartTS; messageOut.getBody().setTimestamp(ts); if (log.isTraceEnabled()) { log.trace("sendMessage (updated): streamStartTS={}, length={}, streamOffset={}, timestamp={}", new Object[] { streamStartTS, currentItem.getLength(), streamOffset, ts }); } } if (streamStartTS > -1 && currentItem.getLength() >= 0) { int duration = ts - streamStartTS; if (duration - streamOffset >= currentItem.getLength()) { // Sent enough data to client stop(); return; } } doPushMessage(messageOut); } /** * Send clear ping. Lets client know that stream has no more data to * send. */ private void sendClearPing() { Ping eof = new Ping(); eof.setEventType(Ping.STREAM_PLAYBUFFER_CLEAR); eof.setValue2(streamId); // eos RTMPMessage eofMsg = RTMPMessage.build(eof); doPushMessage(eofMsg); } /** * Send reset message */ private void sendReset() { if (pullMode) { Ping recorded = new Ping(); recorded.setEventType(Ping.RECORDED_STREAM); recorded.setValue2(streamId); // recorded RTMPMessage recordedMsg = RTMPMessage.build(recorded); doPushMessage(recordedMsg); } Ping begin = new Ping(); begin.setEventType(Ping.STREAM_BEGIN); begin.setValue2(streamId); // begin RTMPMessage beginMsg = RTMPMessage.build(begin); doPushMessage(beginMsg); // reset ResetMessage reset = new ResetMessage(); doPushMessage(reset); } /** * Send reset status for item * @param item Playlist item */ private void sendResetStatus(IPlayItem item) { Status reset = new Status(StatusCodes.NS_PLAY_RESET); reset.setClientid(streamId); reset.setDetails(item.getName()); reset.setDesciption(String.format("Playing and resetting %s.", item.getName())); doPushMessage(reset); } /** * Send playback start status notification * @param item Playlist item */ private void sendStartStatus(IPlayItem item) { Status start = new Status(StatusCodes.NS_PLAY_START); start.setClientid(streamId); start.setDetails(item.getName()); start.setDesciption(String.format("Started playing %s.", item.getName())); doPushMessage(start); } /** * Send playback stoppage status notification * @param item Playlist item */ private void sendStopStatus(IPlayItem item) { Status stop = new Status(StatusCodes.NS_PLAY_STOP); stop.setClientid(streamId); stop.setDesciption(String.format("Stopped playing %s.", item.getName())); stop.setDetails(item.getName()); doPushMessage(stop); } /** * Sends an onPlayStatus message. * * @param code * @param duration * @param bytes */ private void sendOnPlayStatus(String code, int duration, long bytes) { IoBuffer buf = IoBuffer.allocate(255); buf.setAutoExpand(true); Output out = new Output(buf); out.writeString("onPlayStatus"); Map props = new HashMap(); props.put("code", code); props.put("level", "status"); props.put("duration", duration); props.put("bytes", bytes); if (StatusCodes.NS_PLAY_TRANSITION_COMPLETE.equals(code)) { props.put("details", currentItem.getName()); props.put("description", String.format("Transitioned to %s", currentItem.getName())); props.put("clientId", streamId); props.put("isFastPlay", false); } out.writeMap(props, new Serializer()); buf.flip(); IRTMPEvent event = new Notify(buf); if (lastMessageTs > 0) { event.setTimestamp(lastMessageTs); } else { event.setTimestamp(0); } RTMPMessage msg = RTMPMessage.build(event); doPushMessage(msg); } /** * Send playlist switch status notification */ private void sendSwitchStatus() { // TODO: find correct duration to send sendOnPlayStatus(StatusCodes.NS_PLAY_SWITCH, 1, bytesSent.get()); } /** * Send transition status notification */ private void sendTransitionStatus() { sendOnPlayStatus(StatusCodes.NS_PLAY_TRANSITION_COMPLETE, 0, bytesSent.get()); } /** * Send playlist complete status notification * */ private void sendCompleteStatus() { // TODO: find correct duration to send sendOnPlayStatus(StatusCodes.NS_PLAY_COMPLETE, 1, bytesSent.get()); } /** * Send seek status notification * @param item Playlist item * @param position Seek position */ private void sendSeekStatus(IPlayItem item, int position) { Status seek = new Status(StatusCodes.NS_SEEK_NOTIFY); seek.setClientid(streamId); seek.setDetails(item.getName()); seek.setDesciption(String.format("Seeking %d (stream ID: %d).", position, streamId)); doPushMessage(seek); } /** * Send pause status notification * @param item Playlist item */ private void sendPauseStatus(IPlayItem item) { Status pause = new Status(StatusCodes.NS_PAUSE_NOTIFY); pause.setClientid(streamId); pause.setDetails(item.getName()); doPushMessage(pause); } /** * Send resume status notification * @param item Playlist item */ private void sendResumeStatus(IPlayItem item) { Status resume = new Status(StatusCodes.NS_UNPAUSE_NOTIFY); resume.setClientid(streamId); resume.setDetails(item.getName()); doPushMessage(resume); } /** * Send published status notification * @param item Playlist item */ private void sendPublishedStatus(IPlayItem item) { Status published = new Status(StatusCodes.NS_PLAY_PUBLISHNOTIFY); published.setClientid(streamId); published.setDetails(item.getName()); doPushMessage(published); } /** * Send unpublished status notification * @param item Playlist item */ private void sendUnpublishedStatus(IPlayItem item) { Status unpublished = new Status(StatusCodes.NS_PLAY_UNPUBLISHNOTIFY); unpublished.setClientid(streamId); unpublished.setDetails(item.getName()); doPushMessage(unpublished); } /** * Stream not found status notification * @param item Playlist item */ private void sendStreamNotFoundStatus(IPlayItem item) { Status notFound = new Status(StatusCodes.NS_PLAY_STREAMNOTFOUND); notFound.setClientid(streamId); notFound.setLevel(Status.ERROR); notFound.setDetails(item.getName()); doPushMessage(notFound); } /** * Insufficient bandwidth notification * @param item Playlist item */ private void sendInsufficientBandwidthStatus(IPlayItem item) { Status insufficientBW = new Status(StatusCodes.NS_PLAY_INSUFFICIENT_BW); insufficientBW.setClientid(streamId); insufficientBW.setLevel(Status.WARNING); insufficientBW.setDetails(item.getName()); insufficientBW.setDesciption("Data is playing behind the normal speed."); doPushMessage(insufficientBW); } /** * Send VOD init control message * @param msgIn Message input * @param item Playlist item */ private void sendVODInitCM(IMessageInput msgIn, IPlayItem item) { OOBControlMessage oobCtrlMsg = new OOBControlMessage(); oobCtrlMsg.setTarget(IPassive.KEY); oobCtrlMsg.setServiceName("init"); Map paramMap = new HashMap(1); paramMap.put("startTS", (int) item.getStart()); oobCtrlMsg.setServiceParamMap(paramMap); msgIn.sendOOBControlMessage(this, oobCtrlMsg); } /** * Send VOD seek control message * @param msgIn Message input * @param position Playlist item * @return Out-of-band control message call result or -1 on failure */ private int sendVODSeekCM(IMessageInput msgIn, int position) { OOBControlMessage oobCtrlMsg = new OOBControlMessage(); oobCtrlMsg.setTarget(ISeekableProvider.KEY); oobCtrlMsg.setServiceName("seek"); Map paramMap = new HashMap(1); paramMap.put("position", position); oobCtrlMsg.setServiceParamMap(paramMap); msgIn.sendOOBControlMessage(this, oobCtrlMsg); if (oobCtrlMsg.getResult() instanceof Integer) { return (Integer) oobCtrlMsg.getResult(); } else { return -1; } } /** * Send VOD check video control message * * @param msgIn * @return */ private boolean sendCheckVideoCM(IMessageInput msgIn) { OOBControlMessage oobCtrlMsg = new OOBControlMessage(); oobCtrlMsg.setTarget(IStreamTypeAwareProvider.KEY); oobCtrlMsg.setServiceName("hasVideo"); msgIn.sendOOBControlMessage(this, oobCtrlMsg); if (oobCtrlMsg.getResult() instanceof Boolean) { return (Boolean) oobCtrlMsg.getResult(); } else { return false; } } /** {@inheritDoc} */ public void onOOBControlMessage(IMessageComponent source, IPipe pipe, OOBControlMessage oobCtrlMsg) { if ("ConnectionConsumer".equals(oobCtrlMsg.getTarget())) { if (source instanceof IProvider) { msgOut.sendOOBControlMessage((IProvider) source, oobCtrlMsg); } } } /** {@inheritDoc} */ public void onPipeConnectionEvent(PipeConnectionEvent event) { switch (event.getType()) { case PipeConnectionEvent.PROVIDER_CONNECT_PUSH: if (event.getProvider() != this) { if (waiting) { schedulingService.removeScheduledJob(waitLiveJob); waitLiveJob = null; waiting = false; } sendPublishedStatus(currentItem); } break; case PipeConnectionEvent.PROVIDER_DISCONNECT: if (pullMode) { sendStopStatus(currentItem); } else { sendUnpublishedStatus(currentItem); } break; case PipeConnectionEvent.CONSUMER_CONNECT_PULL: if (event.getConsumer() == this) { pullMode = true; } break; case PipeConnectionEvent.CONSUMER_CONNECT_PUSH: if (event.getConsumer() == this) { pullMode = false; } break; default: } } /** {@inheritDoc} */ public void pushMessage(IPipe pipe, IMessage message) throws IOException { if (message instanceof RTMPMessage) { RTMPMessage rtmpMessage = (RTMPMessage) message; IRTMPEvent body = rtmpMessage.getBody(); if (body instanceof IStreamData) { // the subscriber paused if (subscriberStream.getState() == StreamState.PAUSED) { log.debug("Dropping packet because we are paused"); videoFrameDropper.dropPacket(rtmpMessage); return; } if (body instanceof VideoData) { IVideoStreamCodec videoCodec = null; if (msgIn instanceof IBroadcastScope) { IBroadcastStream stream = (IBroadcastStream) ((IBroadcastScope) msgIn).getClientBroadcastStream(); if (stream != null && stream.getCodecInfo() != null) { videoCodec = stream.getCodecInfo().getVideoCodec(); } } //dont try to drop frames if video codec is null - related to SN-77 if (videoCodec != null && videoCodec.canDropFrames()) { if (!receiveVideo) { // The client disabled video or the app doesn't have enough bandwidth // allowed for this stream. log.debug("Dropping packet because we cant receive video or token acquire failed"); videoFrameDropper.dropPacket(rtmpMessage); return; } // Only check for frame dropping if the codec supports it long pendingVideos = pendingVideoMessages(); if (!videoFrameDropper.canSendPacket(rtmpMessage, pendingVideos)) { // Drop frame as it depends on other frames that were dropped before. log.debug("Dropping packet because frame dropper says we cant send it"); return; } // increment the number of times we had pending video frames sequentially if (pendingVideos > 1) { numSequentialPendingVideoFrames++; } else { // reset number of sequential pending frames if 1 or 0 are pending. numSequentialPendingVideoFrames = 0; } if (pendingVideos > maxPendingVideoFramesThreshold || numSequentialPendingVideoFrames > maxSequentialPendingVideoFrames) { log.debug("Pending: {} Threshold: {} Sequential: {}", new Object[] { pendingVideos, maxPendingVideoFramesThreshold, numSequentialPendingVideoFrames }); // We drop because the client has insufficient bandwidth. long now = System.currentTimeMillis(); if (bufferCheckInterval > 0 && now >= nextCheckBufferUnderrun) { // Notify client about frame dropping (keyframe) sendInsufficientBandwidthStatus(currentItem); nextCheckBufferUnderrun = now + bufferCheckInterval; } videoFrameDropper.dropPacket(rtmpMessage); return; } } } else if (body instanceof AudioData) { if (!receiveAudio && sendBlankAudio) { // Send blank audio packet to reset player sendBlankAudio = false; body = new AudioData(); if (lastMessageTs > 0) { body.setTimestamp(lastMessageTs); } else { body.setTimestamp(0); } rtmpMessage = RTMPMessage.build(body); } else if (!receiveAudio) { return; } } sendMessage(rtmpMessage); } else { throw new RuntimeException(String.format("Expected IStreamData but got %s (type %s)", body.getClass(), body.getDataType())); } } else if (message instanceof ResetMessage) { sendReset(); } else { msgOut.pushMessage(message); } } /** * Get number of pending video messages * @return Number of pending video messages */ private long pendingVideoMessages() { OOBControlMessage pendingRequest = new OOBControlMessage(); pendingRequest.setTarget("ConnectionConsumer"); pendingRequest.setServiceName("pendingVideoCount"); msgOut.sendOOBControlMessage(this, pendingRequest); if (pendingRequest.getResult() != null) { return (Long) pendingRequest.getResult(); } else { return 0; } } /** * Get number of pending messages to be sent * @return Number of pending messages */ private long pendingMessages() { return subscriberStream.getConnection().getPendingMessages(); } public boolean isPullMode() { return pullMode; } public boolean isPaused() { return subscriberStream.isPaused(); } /** * Returns the timestamp of the last message sent. * * @return last message timestamp */ public int getLastMessageTimestamp() { return lastMessageTs; } public long getPlaybackStart() { return playbackStart; } public void sendBlankAudio(boolean sendBlankAudio) { this.sendBlankAudio = sendBlankAudio; } /** * Returns true if the engine currently receives audio. * * @return receive audio */ public boolean receiveAudio() { return receiveAudio; } /** * Returns true if the engine currently receives audio and * sets the new value. * * @param receive new value * @return old value */ public boolean receiveAudio(boolean receive) { boolean oldValue = receiveAudio; //set new value if (receiveAudio != receive) { receiveAudio = receive; } return oldValue; } /** * Returns true if the engine currently receives video. * * @return receive video */ public boolean receiveVideo() { return receiveVideo; } /** * Returns true if the engine currently receives video and * sets the new value. * @param receive new value * @return old value */ public boolean receiveVideo(boolean receive) { boolean oldValue = receiveVideo; //set new value if (receiveVideo != receive) { receiveVideo = receive; } return oldValue; } /** * Releases pending message body, nullifies pending message object */ private void releasePendingMessage() { if (pendingMessage != null) { IRTMPEvent body = pendingMessage.getBody(); if (body instanceof IStreamData && ((IStreamData) body).getData() != null) { ((IStreamData) body).getData().free(); } pendingMessage = null; } } /** * Check if sending the given message was enabled by the client. * * @param message the message to check * @return true if the message should be sent, false otherwise (and the message is discarded) */ protected boolean checkSendMessageEnabled(RTMPMessage message) { IRTMPEvent body = message.getBody(); if (!receiveAudio && body instanceof AudioData) { // The user doesn't want to get audio packets ((IStreamData) body).getData().free(); if (sendBlankAudio) { // Send reset audio packet sendBlankAudio = false; body = new AudioData(); // We need a zero timestamp if (lastMessageTs >= 0) { body.setTimestamp(lastMessageTs - timestampOffset); } else { body.setTimestamp(-timestampOffset); } message = RTMPMessage.build(body); } else { return false; } } else if (!receiveVideo && body instanceof VideoData) { // The user doesn't want to get video packets ((IStreamData) body).getData().free(); return false; } return true; } /** * Runnable worker to handle seek operations. */ private final class SeekRunnable implements Runnable { private final int position; SeekRunnable(int position) { this.position = position; } public void run() { log.trace("Seek: {}", position); boolean startPullPushThread = false; switch (subscriberStream.getState()) { case PLAYING: startPullPushThread = true; case PAUSED: case STOPPED: //allow seek if playing, paused, or stopped if (!pullMode) { // throw new OperationNotSupportedException(); throw new RuntimeException(); } releasePendingMessage(); clearWaitJobs(); break; default: throw new IllegalStateException("Cannot seek in current state"); } sendClearPing(); sendReset(); sendSeekStatus(currentItem, position); sendStartStatus(currentItem); int seekPos = sendVODSeekCM(msgIn, position); // we seeked to the nearest keyframe so use real timestamp now if (seekPos == -1) { seekPos = position; } //what should our start be? log.trace("Current playback start: {}", playbackStart); playbackStart = System.currentTimeMillis() - seekPos; log.trace("Playback start: {} seek pos: {}", playbackStart, seekPos); subscriberStream.onChange(StreamState.SEEK, currentItem, seekPos); // start off with not having sent any message boolean messageSent = false; // read our client state switch (subscriberStream.getState()) { case PAUSED: case STOPPED: // we send a single snapshot on pause if (sendCheckVideoCM(msgIn)) { IMessage msg = null; do { try { msg = msgIn.pullMessage(); } catch (Throwable err) { log.error("Error while pulling message", err); msg = null; } if (msg instanceof RTMPMessage) { RTMPMessage rtmpMessage = (RTMPMessage) msg; IRTMPEvent body = rtmpMessage.getBody(); if (body instanceof VideoData && ((VideoData) body).getFrameType() == FrameType.KEYFRAME) { //body.setTimestamp(seekPos); doPushMessage(rtmpMessage); rtmpMessage.getBody().release(); messageSent = true; lastMessageTs = body.getTimestamp(); break; } } } while (msg != null); } } // seeked past end of stream if (currentItem.getLength() >= 0 && (position - streamOffset) >= currentItem.getLength()) { stop(); } // if no message has been sent by this point send an audio packet if (!messageSent) { // Send blank audio packet to notify client about new position log.debug("Sending blank audio packet"); AudioData audio = new AudioData(); audio.setTimestamp(seekPos); audio.setHeader(new Header()); audio.getHeader().setTimer(seekPos); RTMPMessage audioMessage = RTMPMessage.build(audio); lastMessageTs = seekPos; doPushMessage(audioMessage); audioMessage.getBody().release(); } if (!messageSent && subscriberStream.getState() == StreamState.PLAYING) { // send all frames from last keyframe up to requested position and fill client buffer if (sendCheckVideoCM(msgIn)) { final long clientBuffer = subscriberStream.getClientBufferDuration(); IMessage msg = null; do { try { msg = msgIn != null ? msgIn.pullMessage() : null; if (msg instanceof RTMPMessage) { RTMPMessage rtmpMessage = (RTMPMessage) msg; IRTMPEvent body = rtmpMessage.getBody(); if (body.getTimestamp() >= position + (clientBuffer * 2)) { // client buffer should be full by now, continue regular pull/push releasePendingMessage(); if (checkSendMessageEnabled(rtmpMessage)) { pendingMessage = rtmpMessage; } break; } if (!checkSendMessageEnabled(rtmpMessage)) { continue; } sendMessage(rtmpMessage); } } catch (Throwable err) { log.error("Error while pulling message", err); msg = null; } } while (msg != null); playbackStart = System.currentTimeMillis() - lastMessageTs; } } // start pull-push if (startPullPushThread) { ensurePullAndPushRunning(); } } } /** * Periodically triggered by executor to send messages to the client. */ private final class PullAndPushRunnable implements Runnable { /** * Trigger sending of messages. */ public void run() { // ensure the job is not already running if (pushPullRunning.compareAndSet(false, true)) { try { // handle any pending operations Runnable worker = null; while (!pendingOperations.isEmpty()) { log.debug("Pending operations: {}", pendingOperations.size()); // remove the first operation and execute it worker = pendingOperations.remove(); log.debug("Worker: {}", worker); // if the operation is seek, ensure it is the last request in the set while (worker instanceof SeekRunnable) { Runnable tmp = pendingOperations.peek(); if (tmp != null && tmp instanceof SeekRunnable) { worker = pendingOperations.remove(); } else { break; } } if (worker != null) { log.debug("Executing pending operation"); worker.run(); } } // receive then send if message is data (not audio or video) if (subscriberStream.getState() == StreamState.PLAYING && pullMode) { if (pendingMessage != null) { IRTMPEvent body = pendingMessage.getBody(); if (okayToSendMessage(body)) { sendMessage(pendingMessage); releasePendingMessage(); } else { return; } } else { while (true) { IMessage msg = msgIn.pullMessage(); if (msg == null) { // No more packets to send log.debug("Ran out of packets"); runDeferredStop(); break; } else { if (msg instanceof RTMPMessage) { RTMPMessage rtmpMessage = (RTMPMessage) msg; if (!checkSendMessageEnabled(rtmpMessage)) { continue; } // Adjust timestamp when playing lists IRTMPEvent body = rtmpMessage.getBody(); body.setTimestamp(body.getTimestamp() + timestampOffset); if (okayToSendMessage(body)) { log.trace("ts: {}", rtmpMessage.getBody().getTimestamp()); sendMessage(rtmpMessage); ((IStreamData) body).getData().free(); } else { pendingMessage = rtmpMessage; } ensurePullAndPushRunning(); break; } } } } } } catch (IOException err) { // We couldn't get more data, stop stream. log.error("Error while getting message", err); runDeferredStop(); } finally { // reset running flag pushPullRunning.compareAndSet(true, false); } } else { log.debug("Push / pull already running"); } } /** * Schedule a stop to be run from a separate thread to allow the background thread to stop cleanly. */ private void runDeferredStop() { subscriberStream.getExecutor().schedule(new Runnable() { public void run() { log.trace("Ran deferred stop"); while (!isClientBufferEmpty()) { try { Thread.sleep(10L); } catch (InterruptedException e) { } } log.trace("Buffer is empty, stop will proceed"); stop(); } }, 1, TimeUnit.MILLISECONDS); } } /** * @param maxPendingVideoFrames the maxPendingVideoFrames to set */ public void setMaxPendingVideoFrames(int maxPendingVideoFrames) { this.maxPendingVideoFramesThreshold = maxPendingVideoFrames; } /** * @param maxSequentialPendingVideoFrames the maxSequentialPendingVideoFrames to set */ public void setMaxSequentialPendingVideoFrames(int maxSequentialPendingVideoFrames) { this.maxSequentialPendingVideoFrames = maxSequentialPendingVideoFrames; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/SingleItemSubscriberStream.java0000644000175000017500000003267011747114732027453 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.io.IOException; import java.util.concurrent.ScheduledThreadPoolExecutor; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.IConnection; import org.red5.server.api.IContext; import org.red5.server.api.Red5; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IPlayItem; import org.red5.server.api.stream.ISingleItemSubscriberStream; import org.red5.server.api.stream.IStreamAwareScopeHandler; import org.red5.server.api.stream.OperationNotSupportedException; import org.red5.server.api.stream.StreamState; import org.slf4j.Logger; /** * Stream of a single play item for a subscriber * * @author Paul Gregoire (mondain@gmail.com) */ public class SingleItemSubscriberStream extends AbstractClientStream implements ISingleItemSubscriberStream { private static final Logger log = Red5LoggerFactory.getLogger(SingleItemSubscriberStream.class); /** * Executor that will be used to schedule stream playback to keep * the client buffer filled. */ protected static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(3); /** * Interval in ms to check for buffer underruns in VOD streams. */ protected int bufferCheckInterval = 0; /** * Number of pending messages at which a NetStream.Play.InsufficientBW * message is generated for VOD streams. */ protected int underrunTrigger = 10; /** * Timestamp this stream was created. */ protected long creationTime = System.currentTimeMillis(); private volatile IPlayItem item; /** * Plays items back */ protected PlayEngine engine; public void setPlayItem(IPlayItem item) { this.item = item; } public void play() throws IOException { try { engine.play(item); } catch (StreamNotFoundException e) { //TODO send stream not found to subscriber } } /** {@inheritDoc} */ public void pause(int position) { try { engine.pause(position); } catch (IllegalStateException e) { log.debug("pause caught an IllegalStateException"); } } /** {@inheritDoc} */ public void resume(int position) { try { engine.resume(position); } catch (IllegalStateException e) { log.debug("resume caught an IllegalStateException"); } } /** {@inheritDoc} */ public void stop() { try { engine.stop(); } catch (IllegalStateException e) { log.debug("stop caught an IllegalStateException"); } } /** {@inheritDoc} */ public void seek(int position) throws OperationNotSupportedException { try { engine.seek(position); } catch (IllegalStateException e) { log.debug("seek caught an IllegalStateException"); } } public boolean isPaused() { return state == StreamState.PAUSED; } /** {@inheritDoc} */ public void receiveVideo(boolean receive) { boolean receiveVideo = engine.receiveVideo(receive); if (!receiveVideo && receive) { //video has been re-enabled seekToCurrentPlayback(); } } /** {@inheritDoc} */ public void receiveAudio(boolean receive) { //check if engine currently receives audio, returns previous value boolean receiveAudio = engine.receiveAudio(receive); if (receiveAudio && !receive) { //send a blank audio packet to reset the player engine.sendBlankAudio(true); } else if (!receiveAudio && receive) { //do a seek seekToCurrentPlayback(); } } /** * Creates a play engine based on current services (scheduling service, consumer service, and provider service). * This method is useful during unit testing. */ PlayEngine createEngine(ISchedulingService schedulingService, IConsumerService consumerService, IProviderService providerService) { engine = new PlayEngine.Builder(this, schedulingService, consumerService, providerService).build(); return engine; } /** * Set the executor to use. * * @param executor the executor */ public void setExecutor(ScheduledThreadPoolExecutor executor) { PlaylistSubscriberStream.executor = executor; } /** * Return the executor to use. * * @return the executor */ public ScheduledThreadPoolExecutor getExecutor() { if (executor == null) { log.warn("ScheduledThreadPoolExecutor was null on request"); } return executor; } /** * Set interval to check for buffer underruns. Set to 0 to * disable. * * @param bufferCheckInterval interval in ms */ public void setBufferCheckInterval(int bufferCheckInterval) { this.bufferCheckInterval = bufferCheckInterval; } /** * Set maximum number of pending messages at which a * NetStream.Play.InsufficientBW message will be * generated for VOD streams * * @param underrunTrigger the maximum number of pending messages */ public void setUnderrunTrigger(int underrunTrigger) { this.underrunTrigger = underrunTrigger; } public void start() { //ensure the play engine exists if (engine == null) { IScope scope = getScope(); if (scope != null) { IContext ctx = scope.getContext(); ISchedulingService schedulingService = null; if (ctx.hasBean(ISchedulingService.BEAN_NAME)) { schedulingService = (ISchedulingService) ctx.getBean(ISchedulingService.BEAN_NAME); } else { //try the parent schedulingService = (ISchedulingService) scope.getParent().getContext().getBean(ISchedulingService.BEAN_NAME); } IConsumerService consumerService = null; if (ctx.hasBean(IConsumerService.KEY)) { consumerService = (IConsumerService) ctx.getBean(IConsumerService.KEY); } else { //try the parent consumerService = (IConsumerService) scope.getParent().getContext().getBean(IConsumerService.KEY); } IProviderService providerService = null; if (ctx.hasBean(IProviderService.BEAN_NAME)) { providerService = (IProviderService) ctx.getBean(IProviderService.BEAN_NAME); } else { //try the parent providerService = (IProviderService) scope.getParent().getContext().getBean(IProviderService.BEAN_NAME); } engine = new PlayEngine.Builder(this, schedulingService, consumerService, providerService).build(); } else { log.info("Scope was null on start"); } } //set buffer check interval engine.setBufferCheckInterval(bufferCheckInterval); //set underrun trigger engine.setUnderrunTrigger(underrunTrigger); // Start playback engine engine.start(); // Notify subscribers on start onChange(StreamState.STARTED); } public void close() { engine.close(); onChange(StreamState.CLOSED); } /** * {@inheritDoc} */ public void onChange(final StreamState state, final Object... changed) { Notifier notifier = null; IStreamAwareScopeHandler handler = getStreamAwareHandler(); switch (state) { case SEEK: //notifies subscribers on seek if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); //get item being played IPlayItem item = (IPlayItem) changed[0]; //seek position int position = (Integer) changed[1]; try { handler.streamPlayItemSeek(stream, item, position); } catch (Throwable t) { log.error("error notify streamPlayItemSeek", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case PAUSED: //set the paused state this.setState(StreamState.PAUSED); //notifies subscribers on pause if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); //get item being played IPlayItem item = (IPlayItem) changed[0]; //playback position int position = (Integer) changed[1]; try { handler.streamPlayItemPause(stream, item, position); } catch (Throwable t) { log.error("error notify streamPlayItemPause", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case RESUMED: //resume playing this.setState(StreamState.PLAYING); //notifies subscribers on resume if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); //get item being played IPlayItem item = (IPlayItem) changed[0]; //playback position int position = (Integer) changed[1]; try { handler.streamPlayItemResume(stream, item, position); } catch (Throwable t) { log.error("error notify streamPlayItemResume", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case PLAYING: //notifies subscribers on play if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); //get item being played IPlayItem item = (IPlayItem) changed[0]; //is it a live broadcast boolean isLive = (Boolean) changed[1]; try { handler.streamPlayItemPlay(stream, item, isLive); } catch (Throwable t) { log.error("error notify streamPlayItemPlay", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case CLOSED: //notifies subscribers on close if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); try { handler.streamSubscriberClose(stream); } catch (Throwable t) { log.error("error notify streamSubscriberClose", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case STARTED: //notifies subscribers on start if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); try { handler.streamSubscriberStart(stream); } catch (Throwable t) { log.error("error notify streamSubscriberStart", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case STOPPED: //set the stopped state this.setState(StreamState.STOPPED); //notifies subscribers on stop if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); //get the item that was stopped IPlayItem item = (IPlayItem) changed[0]; try { handler.streamPlayItemStop(stream, item); } catch (Throwable t) { log.error("error notify streamPlaylistItemStop", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case END: //notified by the play engine when the current item reaches the end break; default: //there is no "default" handling } if (notifier != null) { notifier.setConnection(Red5.getConnectionLocal()); executor.execute(notifier); } } /** * Seek to current position to restart playback with audio and/or video. */ private void seekToCurrentPlayback() { if (engine.isPullMode()) { try { // TODO: figure out if this is the correct position to seek to final long delta = System.currentTimeMillis() - engine.getPlaybackStart(); engine.seek((int) delta); } catch (OperationNotSupportedException err) { // Ignore error, should not happen for pullMode engines } } } /** * Handles notifications in a separate thread. */ public class Notifier implements Runnable { ISingleItemSubscriberStream stream; IStreamAwareScopeHandler handler; IConnection conn; public Notifier(ISingleItemSubscriberStream stream, IStreamAwareScopeHandler handler) { log.trace("Notifier - stream: {} handler: {}", stream, handler); this.stream = stream; this.handler = handler; } public void setConnection(IConnection conn) { this.conn = conn; } public void run() { } } } red5-1.0~svn4374.orig/src/org/red5/server/stream/StreamService.java0000644000175000017500000007146711754746347025011 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.red5.io.utils.ObjectMap; import org.red5.server.BaseConnection; import org.red5.server.api.IConnection; import org.red5.server.api.IContext; import org.red5.server.api.Red5; import org.red5.server.api.scope.IBroadcastScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IBroadcastStream; import org.red5.server.api.stream.IClientBroadcastStream; import org.red5.server.api.stream.IClientStream; import org.red5.server.api.stream.IPlayItem; import org.red5.server.api.stream.IPlaylistSubscriberStream; import org.red5.server.api.stream.ISingleItemSubscriberStream; import org.red5.server.api.stream.IStreamCapableConnection; import org.red5.server.api.stream.IStreamPlaybackSecurity; import org.red5.server.api.stream.IStreamPublishSecurity; import org.red5.server.api.stream.IStreamSecurityService; import org.red5.server.api.stream.IStreamService; import org.red5.server.api.stream.ISubscriberStream; import org.red5.server.api.stream.OperationNotSupportedException; import org.red5.server.api.stream.support.DynamicPlayItem; import org.red5.server.api.stream.support.SimplePlayItem; import org.red5.server.net.rtmp.BaseRTMPHandler; import org.red5.server.net.rtmp.Channel; import org.red5.server.net.rtmp.RTMPConnection; import org.red5.server.net.rtmp.status.Status; import org.red5.server.net.rtmp.status.StatusCodes; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Stream service */ public class StreamService implements IStreamService { private static Logger log = LoggerFactory.getLogger(StreamService.class); /** * Use to determine playback type. */ private ThreadLocal simplePlayback = new ThreadLocal() { @Override protected Boolean initialValue() { return Boolean.TRUE; } }; /** {@inheritDoc} */ public int createStream() { IConnection conn = Red5.getConnectionLocal(); if (conn instanceof IStreamCapableConnection) { return ((IStreamCapableConnection) conn).reserveStreamId(); } else { return -1; } } /** {@inheritDoc} */ public void initStream(int streamId) { IConnection conn = Red5.getConnectionLocal(); if (conn instanceof IStreamCapableConnection) { ((IStreamCapableConnection) conn).reserveStreamId(streamId); IClientStream stream = ((IStreamCapableConnection) conn).getStreamById(getCurrentStreamId()); if (stream != null) { if (stream instanceof IClientBroadcastStream) { IClientBroadcastStream bs = (IClientBroadcastStream) stream; IBroadcastScope bsScope = getBroadcastScope(conn.getScope(), bs.getPublishedName()); if (bsScope != null && conn instanceof BaseConnection) { ((BaseConnection) conn).unregisterBasicScope(bsScope); } } stream.close(); } ((IStreamCapableConnection) conn).deleteStreamById(getCurrentStreamId()); } else { log.warn("ERROR in intiStream, connection is not stream capable"); } } /** * Close stream */ public void closeStream() { closeStream(Red5.getConnectionLocal(), getCurrentStreamId()); } /** * Close stream. * This method can close both IClientBroadcastStream (coming from Flash Player to Red5) * and ISubscriberStream (from Red5 to Flash Player). * Corresponding application handlers (streamSubscriberClose, etc.) are called as if close was initiated by Flash Player. * * It is recommended to remember stream id in application handlers, ex.: *
	 * public void streamBroadcastStart(IBroadcastStream stream) {
	 * 	super.streamBroadcastStart(stream);
	 * 	if (stream instanceof IClientBroadcastStream) {
	 * 		int publishedStreamId = ((ClientBroadcastStream)stream).getStreamId();
	 * 		Red5.getConnectionLocal().setAttribute(PUBLISHED_STREAM_ID_ATTRIBUTE, publishedStreamId);
	 * 	}
	 * }
	 * 
*
	 * public void streamPlaylistItemPlay(IPlaylistSubscriberStream stream, IPlayItem item, boolean isLive) {
	 * 	super.streamPlaylistItemPlay(stream, item, isLive);
	 * 	Red5.getConnectionLocal().setAttribute(WATCHED_STREAM_ID_ATTRIBUTE, stream.getStreamId());
	 * }
	 * 
* When stream is closed, corresponding NetStream status will be sent to stream provider / consumers. * Implementation is based on Red5's StreamService.close() * * @param connection client connection * @param streamId stream ID (number: 1,2,...) */ public void closeStream(IConnection connection, int streamId) { if (connection instanceof IStreamCapableConnection) { IStreamCapableConnection scConnection = (IStreamCapableConnection) connection; IClientStream stream = scConnection.getStreamById(streamId); if (stream != null) { if (stream instanceof IClientBroadcastStream) { // this is a broadcasting stream (from Flash Player to Red5) IClientBroadcastStream bs = (IClientBroadcastStream) stream; IBroadcastScope bsScope = connection.getScope().getBroadcastScope(bs.getPublishedName()); if (bsScope != null && connection instanceof BaseConnection) { ((BaseConnection) connection).unregisterBasicScope(bsScope); } } stream.close(); scConnection.deleteStreamById(streamId); // in case of broadcasting stream, status is sent automatically by Red5 if (!(stream instanceof IClientBroadcastStream)) { StreamService.sendNetStreamStatus(connection, StatusCodes.NS_PLAY_STOP, "Stream closed by server", stream.getName(), Status.STATUS, streamId); } } else { log.info("Stream not found: streamId={}, connection={}", streamId, connection); } } else { log.warn("Connection is not instance of IStreamCapableConnection: {}", connection); } } /** {@inheritDoc} */ public void releaseStream(String streamName) { // XXX: what to do here? } /** {@inheritDoc} */ public void deleteStream(int streamId) { IConnection conn = Red5.getConnectionLocal(); if (conn instanceof IStreamCapableConnection) { IStreamCapableConnection streamConn = (IStreamCapableConnection) conn; deleteStream(streamConn, streamId); } } /** {@inheritDoc} */ public void deleteStream(IStreamCapableConnection conn, int streamId) { IClientStream stream = conn.getStreamById(streamId); if (stream != null) { if (stream instanceof IClientBroadcastStream) { IClientBroadcastStream bs = (IClientBroadcastStream) stream; IBroadcastScope bsScope = getBroadcastScope(conn.getScope(), bs.getPublishedName()); if (bsScope != null && conn instanceof BaseConnection) { ((BaseConnection) conn).unregisterBasicScope(bsScope); } } stream.close(); } conn.unreserveStreamId(streamId); } /** {@inheritDoc} */ public void pauseRaw(Boolean pausePlayback, int position) { log.trace("pauseRaw - pausePlayback:{} position:{}", pausePlayback, position); pause(pausePlayback, position); } /** * Pause at given position. Required as "pausePlayback" can be "null" if no flag is passed by the * client * @param pausePlayback Pause playback or not * @param position Pause position */ public void pause(Boolean pausePlayback, int position) { IConnection conn = Red5.getConnectionLocal(); if (conn instanceof IStreamCapableConnection) { IStreamCapableConnection streamConn = (IStreamCapableConnection) conn; int streamId = getCurrentStreamId(); IClientStream stream = streamConn.getStreamById(streamId); if (stream != null && stream instanceof ISubscriberStream) { ISubscriberStream subscriberStream = (ISubscriberStream) stream; // pausePlayback can be "null" if "pause" is called without any parameters from flash if (pausePlayback == null) { pausePlayback = !subscriberStream.isPaused(); } if (pausePlayback) { subscriberStream.pause(position); } else { subscriberStream.resume(position); } } } } /** * Plays back a stream based on the supplied name, from the specified position for the given length of time. * * @param name - The name of a recorded file, or the identifier for live data. If * @param start - The start time, in seconds. Allowed values are -2, -1, 0, or a positive number. * The default value is -2, which looks for a live stream, then a recorded stream, and if it finds neither, * opens a live stream. If -1, plays only a live stream. If 0 or a positive number, plays a recorded stream, * beginning start seconds in. * @param length - The duration of the playback, in seconds. Allowed values are -1, 0, or a positive number. * The default value is -1, which plays a live or recorded stream until it ends. If 0, plays a single frame * that is start seconds from the beginning of a recorded stream. If a positive number, plays a live or recorded * stream for length seconds. * @param reset - Whether to clear a playlist. The default value is 1 or true, which clears any previous play * calls and plays name immediately. If 0 or false, adds the stream to a playlist. If 2, maintains the playlist * and returns all stream messages at once, rather than at intervals. If 3, clears the playlist and returns all * stream messages at once. */ public void play(String name, int start, int length, Object reset) { if (reset instanceof Boolean) { play(name, start, length, ((Boolean) reset).booleanValue()); } else { if (reset instanceof Integer) { int value = (Integer) reset; switch (value) { case 0: //adds the stream to a playlist IStreamCapableConnection streamConn = (IStreamCapableConnection) Red5.getConnectionLocal(); IPlaylistSubscriberStream playlistStream = (IPlaylistSubscriberStream) streamConn.getStreamById(getCurrentStreamId()); IPlayItem item = SimplePlayItem.build(name); playlistStream.addItem(item); play(name, start, length, false); break; case 2: //maintains the playlist and returns all stream messages at once, rather than at intervals break; case 3: //clears the playlist and returns all stream messages at once break; default: //clears any previous play calls and plays name immediately play(name, start, length, true); } } else { play(name, start, length); } } } /** {@inheritDoc} */ public void play(String name, int start, int length, boolean flushPlaylist) { log.debug("Play called - name: {} start: {} length: {} flush playlist: {}", new Object[] { name, start, length, flushPlaylist }); IConnection conn = Red5.getConnectionLocal(); if (conn instanceof IStreamCapableConnection) { IScope scope = conn.getScope(); IStreamCapableConnection streamConn = (IStreamCapableConnection) conn; int streamId = getCurrentStreamId(); if (StringUtils.isEmpty(name)) { sendNSFailed(streamConn, StatusCodes.NS_FAILED, "The stream name may not be empty.", name, streamId); return; } IStreamSecurityService security = (IStreamSecurityService) ScopeUtils.getScopeService(scope, IStreamSecurityService.class); if (security != null) { Set handlers = security.getStreamPlaybackSecurity(); for (IStreamPlaybackSecurity handler : handlers) { if (!handler.isPlaybackAllowed(scope, name, start, length, flushPlaylist)) { sendNSFailed(streamConn, StatusCodes.NS_FAILED, "You are not allowed to play the stream.", name, streamId); return; } } } IClientStream stream = streamConn.getStreamById(streamId); boolean created = false; if (stream == null) { if (streamId <= 0) { streamId = streamConn.reserveStreamId(); } stream = streamConn.newPlaylistSubscriberStream(streamId); stream.start(); created = true; } if (stream != null && stream instanceof ISubscriberStream) { ISubscriberStream subscriberStream = (ISubscriberStream) stream; IPlayItem item = simplePlayback.get() ? SimplePlayItem.build(name, start, length) : DynamicPlayItem.build(name, start, length); if (subscriberStream instanceof IPlaylistSubscriberStream) { IPlaylistSubscriberStream playlistStream = (IPlaylistSubscriberStream) subscriberStream; if (flushPlaylist) { playlistStream.removeAllItems(); } playlistStream.addItem(item); } else if (subscriberStream instanceof ISingleItemSubscriberStream) { ISingleItemSubscriberStream singleStream = (ISingleItemSubscriberStream) subscriberStream; singleStream.setPlayItem(item); } else { // not supported by this stream service log.warn("Stream instance type: {} is not supported", subscriberStream.getClass().getName()); return; } try { subscriberStream.play(); } catch (IOException err) { if (created) { stream.close(); streamConn.deleteStreamById(streamId); } sendNSFailed(streamConn, StatusCodes.NS_FAILED, err.getMessage(), name, streamId); } } } else { log.debug("Connection was not stream capable"); } } /** {@inheritDoc} */ public void play(String name, int start, int length) { play(name, start, length, true); } /** {@inheritDoc} */ public void play(String name, int start) { play(name, start, -1000, true); } /** {@inheritDoc} */ public void play(String name) { play(name, -2000, -1000, true); } /** {@inheritDoc} */ public void play(Boolean dontStop) { log.debug("Play called. Dont stop param: {}", dontStop); if (!dontStop) { IConnection conn = Red5.getConnectionLocal(); if (conn instanceof IStreamCapableConnection) { IStreamCapableConnection streamConn = (IStreamCapableConnection) conn; int streamId = getCurrentStreamId(); IClientStream stream = streamConn.getStreamById(streamId); if (stream != null) { stream.stop(); } } } } /** * Dynamic streaming play method. This is a convenience method. * * @param oldStreamName * @param start * @param transition * @param length * @param offset * @param streamName */ public void play2(String oldStreamName, int start, String transition, int length, double offset, String streamName) { Map playOptions = new HashMap(); playOptions.put("oldStreamName", oldStreamName); playOptions.put("streamName", streamName); playOptions.put("start", start); playOptions.put("len", length); playOptions.put("offset", offset); play2(playOptions); } /** * Dynamic streaming play method. This is a convenience method. * * @param params */ @SuppressWarnings("rawtypes") public void play2(ObjectMap params) { log.debug("play2 options: {}", params); Map playOptions = new HashMap(); for (Object key : params.keySet()) { String k = key.toString(); log.trace("Parameter: {}", k); playOptions.put(k, params.get(k)); } play2(playOptions); } /** * Dynamic streaming play method. * * The following properties are supported on the play options: *
		streamName: String. The name of the stream to play or the new stream to switch to.
		oldStreamName: String. The name of the initial stream that needs to be switched out. This is not needed and ignored 
		               when play2 is used for just playing the stream and not switching to a new stream.
		start: Number. The start time of the new stream to play, just as supported by the existing play API. and it has the 
		               same defaults. This is ignored when the method is called for switching (in other words, the transition 
		               is either NetStreamPlayTransition.SWITCH or NetStreamPlayTransitions.SWAP)
		len: Number. The duration of the playback, just as supported by the existing play API and has the same defaults.
		transition: String. The transition mode for the playback command. It could be one of the following:
							NetStreamPlayTransitions.RESET
							NetStreamPlayTransitions.APPEND
							NetStreamPlayTransitions.SWITCH
							NetStreamPlayTransitions.SWAP
		
NetStreamPlayTransitions:
					
			APPEND : String = "append" - Adds the stream to a playlist and begins playback with the first stream.
	 		APPEND_AND_WAIT : String = "appendAndWait" - Builds a playlist without starting to play it from the first stream.
	 		RESET : String = "reset" - Clears any previous play calls and plays the specified stream immediately.
	 		RESUME : String = "resume" - Requests data from the new connection starting from the point at which the previous connection ended.
	 		STOP : String = "stop" - Stops playing the streams in a playlist.
	 		SWAP : String = "swap" - Replaces a content stream with a different content stream and maintains the rest of the playlist.
	 		SWITCH : String = "switch" - Switches from playing one stream to another stream, typically with streams of the same content.			
	   
@see ActionScript guide to dynamic streaming @see Dynamic streaming in Flash Media Server - Part 1: Overview of the new capabilities @see NetStreamPlayTransitions */ public void play2(Map playOptions) { log.debug("play2 options: {}", playOptions.toString()); /* { streamName=streams/new.flv, oldStreamName=streams/old.flv, start=0, len=-1, offset=12.195, transition=switch } */ // get the transition type String transition = (String) playOptions.get("transition"); String streamName = (String) playOptions.get("streamName"); String oldStreamName = (String) playOptions.get("oldStreamName"); // now initiate new playback int start = (Integer) playOptions.get("start"); int length = (Integer) playOptions.get("len"); // get the stream id int streamId = getCurrentStreamId(); // get the clients connection IConnection conn = Red5.getConnectionLocal(); if (conn != null && conn instanceof IStreamCapableConnection) { IStreamCapableConnection streamConn = (IStreamCapableConnection) conn; if ("stop".equals(transition)) { play(Boolean.FALSE); } else if ("reset".equals(transition)) { // just reset the currently playing stream play(streamName); } else if ("switch".equals(transition)) { try { // set the playback type simplePlayback.set(Boolean.FALSE); // send the "start" of transition sendNSStatus(conn, StatusCodes.NS_PLAY_TRANSITION, String.format("Transitioning from %s to %s.", oldStreamName, streamName), streamName, streamId); // support offset? //playOptions.get("offset") play(streamName, start, length); } finally { // clean up simplePlayback.remove(); } } else if ("append".equals(transition) || "appendAndWait".equals(transition)) { IPlaylistSubscriberStream playlistStream = (IPlaylistSubscriberStream) streamConn.getStreamById(streamId); IPlayItem item = SimplePlayItem.build(streamName); playlistStream.addItem(item); if ("append".equals(transition)) { play(streamName, start, length, false); } } else if ("swap".equals(transition)) { IPlaylistSubscriberStream playlistStream = (IPlaylistSubscriberStream) streamConn.getStreamById(streamId); IPlayItem item = SimplePlayItem.build(streamName); int itemCount = playlistStream.getItemSize(); for (int i = 0; i < itemCount; i++) { IPlayItem tmpItem = playlistStream.getItem(i); if (tmpItem.getName().equals(oldStreamName)) { if (!playlistStream.replace(tmpItem, item)) { log.warn("Playlist item replacement failed"); sendNSFailed(streamConn, StatusCodes.NS_PLAY_FAILED, "Playlist swap failed.", streamName, streamId); } break; } } } else { log.warn("Unhandled transition: {}", transition); sendNSFailed(conn, StatusCodes.NS_FAILED, "Transition type not supported", streamName, streamId); } } else { log.info("Connection was null ?"); } } /** {@inheritDoc} */ public void publish(Boolean dontStop) { if (!dontStop) { IConnection conn = Red5.getConnectionLocal(); if (conn instanceof IStreamCapableConnection) { IStreamCapableConnection streamConn = (IStreamCapableConnection) conn; int streamId = getCurrentStreamId(); IClientStream stream = streamConn.getStreamById(streamId); if (stream instanceof IBroadcastStream) { IBroadcastStream bs = (IBroadcastStream) stream; if (bs.getPublishedName() != null) { IBroadcastScope bsScope = getBroadcastScope(conn.getScope(), bs.getPublishedName()); if (bsScope != null) { bsScope.unsubscribe(bs.getProvider()); if (conn instanceof BaseConnection) { ((BaseConnection) conn).unregisterBasicScope(bsScope); } } bs.close(); streamConn.deleteStreamById(streamId); } } } } } /** {@inheritDoc} */ public void publish(String name, String mode) { Map params = null; if (name != null && name.contains("?")) { // read and utilize the query string values params = new HashMap(); String tmp = name; // check if we start with '?' or not if (name.charAt(0) != '?') { tmp = name.split("\\?")[1]; } else if (name.charAt(0) == '?') { tmp = name.substring(1); } // now break up into key/value blocks String[] kvs = tmp.split("&"); // take each key/value block and break into its key value parts for (String kv : kvs) { String[] split = kv.split("="); params.put(split[0], split[1]); } // grab the streams name name = name.substring(0, name.indexOf("?")); } IConnection conn = Red5.getConnectionLocal(); if (conn instanceof IStreamCapableConnection) { IScope scope = conn.getScope(); IStreamCapableConnection streamConn = (IStreamCapableConnection) conn; int streamId = getCurrentStreamId(); if (StringUtils.isEmpty(name)) { sendNSFailed(streamConn, StatusCodes.NS_FAILED, "The stream name may not be empty.", name, streamId); return; } IStreamSecurityService security = (IStreamSecurityService) ScopeUtils.getScopeService(scope, IStreamSecurityService.class); if (security != null) { Set handlers = security.getStreamPublishSecurity(); for (IStreamPublishSecurity handler : handlers) { if (!handler.isPublishAllowed(scope, name, mode)) { sendNSFailed(streamConn, StatusCodes.NS_FAILED, "You are not allowed to publish the stream.", name, streamId); return; } } } IBroadcastScope bsScope = getBroadcastScope(scope, name); if (bsScope != null && !bsScope.getProviders().isEmpty()) { // another stream with that name is already published sendNSFailed(streamConn, StatusCodes.NS_PUBLISH_BADNAME, name, name, streamId); return; } IClientStream stream = streamConn.getStreamById(streamId); if (stream != null && !(stream instanceof IClientBroadcastStream)) { return; } boolean created = false; if (stream == null) { stream = streamConn.newBroadcastStream(streamId); created = true; } IClientBroadcastStream bs = (IClientBroadcastStream) stream; try { // set publish name bs.setPublishedName(name); // set stream parameters if they exist if (params != null) { bs.setParameters(params); } IContext context = conn.getScope().getContext(); IProviderService providerService = (IProviderService) context.getBean(IProviderService.BEAN_NAME); // TODO handle registration failure if (providerService.registerBroadcastStream(conn.getScope(), name, bs)) { bsScope = getBroadcastScope(conn.getScope(), name); bsScope.setClientBroadcastStream(bs); if (conn instanceof BaseConnection) { ((BaseConnection) conn).registerBasicScope(bsScope); } } log.debug("Mode: {}", mode); if (IClientStream.MODE_RECORD.equals(mode)) { bs.start(); bs.saveAs(name, false); } else if (IClientStream.MODE_APPEND.equals(mode)) { bs.start(); bs.saveAs(name, true); } else { bs.start(); } bs.startPublishing(); } catch (IOException e) { log.warn("Stream I/O exception", e); sendNSFailed(streamConn, StatusCodes.NS_RECORD_NOACCESS, "The file could not be created/written to.", name, streamId); bs.close(); if (created) { streamConn.deleteStreamById(streamId); } return; } catch (Exception e) { log.warn("Exception on publish", e); } } } /** {@inheritDoc} */ public void publish(String name) { publish(name, IClientStream.MODE_LIVE); } /** {@inheritDoc} */ public void seek(int position) { log.trace("seek - position:{}", position); IConnection conn = Red5.getConnectionLocal(); if (conn instanceof IStreamCapableConnection) { IStreamCapableConnection streamConn = (IStreamCapableConnection) conn; int streamId = getCurrentStreamId(); IClientStream stream = streamConn.getStreamById(streamId); if (stream != null && stream instanceof ISubscriberStream) { ISubscriberStream subscriberStream = (ISubscriberStream) stream; try { subscriberStream.seek(position); } catch (OperationNotSupportedException err) { sendNSFailed(streamConn, StatusCodes.NS_SEEK_FAILED, "The stream doesn't support seeking.", stream.getName(), streamId); } } } } /** {@inheritDoc} */ public void receiveVideo(boolean receive) { IConnection conn = Red5.getConnectionLocal(); if (conn instanceof IStreamCapableConnection) { IStreamCapableConnection streamConn = (IStreamCapableConnection) conn; int streamId = getCurrentStreamId(); IClientStream stream = streamConn.getStreamById(streamId); if (stream != null && stream instanceof ISubscriberStream) { ISubscriberStream subscriberStream = (ISubscriberStream) stream; subscriberStream.receiveVideo(receive); } } } /** {@inheritDoc} */ public void receiveAudio(boolean receive) { IConnection conn = Red5.getConnectionLocal(); if (conn instanceof IStreamCapableConnection) { IStreamCapableConnection streamConn = (IStreamCapableConnection) conn; int streamId = getCurrentStreamId(); IClientStream stream = streamConn.getStreamById(streamId); if (stream != null && stream instanceof ISubscriberStream) { ISubscriberStream subscriberStream = (ISubscriberStream) stream; subscriberStream.receiveAudio(receive); } } } /** * Getter for current stream id. * * @return Current stream id */ private int getCurrentStreamId() { // TODO: this must come from the current connection! return BaseRTMPHandler.getStreamId(); } /** * Return broadcast scope object for given scope and child scope name * @param scope Scope object * @param name Child scope name * @return Broadcast scope */ public IBroadcastScope getBroadcastScope(IScope scope, String name) { return scope.getBroadcastScope(name); } /** * Send a NetStream.Play.Failed message to the client. * * @param conn * @param errorCode * @param description * @param name * @param streamId */ private void sendNSFailed(IConnection conn, String errorCode, String description, String name, int streamId) { StreamService.sendNetStreamStatus(conn, errorCode, description, name, Status.ERROR, streamId); } /** * Send NetStream.Status to client (Flash Player) * @param conn * @param statusCode see StatusCodes class * @param description * @param name * @param streamId */ private void sendNSStatus(IConnection conn, String statusCode, String description, String name, int streamId) { StreamService.sendNetStreamStatus(conn, statusCode, description, name, Status.STATUS, streamId); } /** * Send NetStream.Status to client (Flash Player) * * @param conn connection * @param statusCode NetStream status code * @param description description * @param name name * @param status The status - error, warning, or status * @param streamId stream id */ public static void sendNetStreamStatus(IConnection conn, String statusCode, String description, String name, String status, int streamId) { if (conn instanceof RTMPConnection) { Status s = new Status(statusCode); s.setClientid(streamId); s.setDesciption(description); s.setDetails(name); s.setLevel(status); // get the channel Channel channel = ((RTMPConnection) conn).getChannel((byte) (4 + ((streamId - 1) * 5))); channel.sendStatus(s); } else { throw new RuntimeException("Connection is not RTMPConnection: " + conn); } } } red5-1.0~svn4374.orig/src/org/red5/server/stream/AbstractStream.java0000644000175000017500000000677711747114732025143 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeHandler; import org.red5.server.api.stream.IStream; import org.red5.server.api.stream.IStreamAwareScopeHandler; import org.red5.server.api.stream.IStreamCodecInfo; import org.red5.server.api.stream.StreamState; import org.red5.server.net.rtmp.event.Notify; /** * Abstract base implementation of IStream. Contains codec information, stream name, scope, event handling * meand, provides stream start and stop operations. * * @see org.red5.server.api.stream.IStream */ public abstract class AbstractStream implements IStream { /** * Current state */ protected StreamState state = StreamState.UNINIT; /** * Stream name */ private String name; /** * Stream audio and video codec information */ private IStreamCodecInfo codecInfo; /** * Stores the streams metadata */ protected Notify metaData; /** * Stream scope */ private IScope scope; /** * Timestamp the stream was created. */ protected long creationTime; /** * Return stream name * @return Stream name */ public String getName() { return name; } /** * Return codec information * @return Stream codec information */ public IStreamCodecInfo getCodecInfo() { return codecInfo; } /** * Returns the metadata for the associated stream, if it exists. * * @return stream meta data */ public Notify getMetaData() { return metaData; } /** * Return scope * @return Scope */ public IScope getScope() { return scope; } /** * Returns timestamp at which the stream was created. * * @return creation timestamp */ public long getCreationTime() { return creationTime; } /** * Setter for name * @param name Stream name */ public void setName(String name) { this.name = name; } /** * Setter for codec info * @param codecInfo Codec info */ public void setCodecInfo(IStreamCodecInfo codecInfo) { this.codecInfo = codecInfo; } /** * Setter for scope * @param scope Scope */ public void setScope(IScope scope) { this.scope = scope; } /** * Return stream aware scope handler or null if scope is null * @return IStreamAwareScopeHandler implementation */ protected IStreamAwareScopeHandler getStreamAwareHandler() { if (scope != null) { IScopeHandler handler = scope.getHandler(); if (handler instanceof IStreamAwareScopeHandler) { return (IStreamAwareScopeHandler) handler; } } return null; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/OutputStream.java0000644000175000017500000000376011746326760024672 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import org.red5.server.net.rtmp.Channel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Output stream that consists of audio, video and data channels * * @see org.red5.server.net.rtmp.Channel */ public class OutputStream { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(OutputStream.class); /** * Video channel */ private Channel video; /** * Audio channel */ private Channel audio; /** * Data channel */ private Channel data; /** * Creates output stream from channels * * @param video Video channel * @param audio Audio channel * @param data Data channel */ public OutputStream(Channel video, Channel audio, Channel data) { this.video = video; this.audio = audio; this.data = data; } /** * Closes audion, video and data channels */ public void close() { video.close(); audio.close(); data.close(); } /** * Getter for audio channel * * @return Audio channel */ public Channel getAudio() { return audio; } /** * Getter for data channel * * @return Data channel */ public Channel getData() { return data; } /** * Getter for video channel * * @return Video channel */ public Channel getVideo() { return video; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/IFrameDropper.java0000644000175000017500000000426511706617130024704 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import org.red5.server.stream.message.RTMPMessage; /** * Interface for classes that implement logic to drop frames. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IFrameDropper { /** Send keyframes, interframes and disposable interframes. */ public static final int SEND_ALL = 0; /** Send keyframes and interframes. */ public static final int SEND_INTERFRAMES = 1; /** Send keyframes only. */ public static final int SEND_KEYFRAMES = 2; /** Send keyframes only and switch to SEND_INTERFRAMES later. */ public static final int SEND_KEYFRAMES_CHECK = 3; /** * Checks if a message may be sent to the subscriber. * * @param message * the message to check * @param pending * the number of pending messages * @return true if the packet may be sent, otherwise * false */ boolean canSendPacket(RTMPMessage message, long pending); /** * Notify that a packet has been dropped. * * @param message * the message that was dropped */ void dropPacket(RTMPMessage message); /** * Notify that a message has been sent. * * @param message * the message that was sent */ void sendPacket(RTMPMessage message); /** Reset the frame dropper. */ void reset(); /** * Reset the frame dropper to a given state. * * @param state * the state to reset the frame dropper to */ void reset(int state); } red5-1.0~svn4374.orig/src/org/red5/server/stream/consumer/0000755000175000017500000000000011760512571023171 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/stream/consumer/FileConsumer.java0000644000175000017500000005200111747635016026432 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.consumer; import java.io.File; import java.io.IOException; import java.nio.channels.ClosedChannelException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.IStreamableFile; import org.red5.io.IStreamableFileFactory; import org.red5.io.IStreamableFileService; import org.red5.io.ITag; import org.red5.io.ITagWriter; import org.red5.io.StreamableFileFactory; import org.red5.io.flv.impl.Tag; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IClientStream; import org.red5.server.messaging.IMessage; import org.red5.server.messaging.IMessageComponent; import org.red5.server.messaging.IPipe; import org.red5.server.messaging.IPipeConnectionListener; import org.red5.server.messaging.IPushableConsumer; import org.red5.server.messaging.OOBControlMessage; import org.red5.server.messaging.PipeConnectionEvent; import org.red5.server.net.rtmp.event.FlexStreamSend; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.net.rtmp.event.VideoData.FrameType; import org.red5.server.net.rtmp.message.Constants; import org.red5.server.stream.IStreamData; import org.red5.server.stream.message.RTMPMessage; import org.red5.server.stream.message.ResetMessage; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.concurrent.CustomizableThreadFactory; /** * Consumer that pushes messages to file. Used when recording live streams. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) * @author Vladimir Hmelyoff (vlhm@splitmedialabs.com) */ public class FileConsumer implements Constants, IPushableConsumer, IPipeConnectionListener { /** * Logger */ private static final Logger log = LoggerFactory.getLogger(FileConsumer.class); /** * Executor for all writer jobs */ private static ScheduledExecutorService scheduledExecutorService; /** * Queue writer thread count */ private int schedulerThreadSize = 4; /** * Queue to hold data for delayed writing */ private List queue = Collections.emptyList(); /** * Reentrant lock */ private ReentrantReadWriteLock reentrantLock; /** * Write lock */ private volatile Lock writeLock; /** * Read lock */ private volatile Lock readLock; /** * Scope */ private IScope scope; /** * File */ private File file; /** * Tag writer */ private ITagWriter writer; /** * Operation mode */ private String mode; /** * Start timestamp */ private int startTimestamp = -1; /** * Last write timestamp */ @SuppressWarnings("unused") private int lastTimestamp; /** * Video decoder configuration */ private ITag videoConfigurationTag; /** * Audio decoder configuration */ private ITag audioConfigurationTag; /** * Number of queued items needed before writes are initiated */ private int queueThreshold = 42; /** * Percentage of the queue which is sliced for writing */ private int percentage = 25; /** * Size of the slice of queued data to write at a time */ private int sliceLength = (queueThreshold / (100 / percentage)); /** * Whether or not to use a queue for delaying file writes. The queue is useful * for keeping Tag items in their expected order based on their time stamp. */ private boolean delayWrite = false; /** * Tracks the last timestamp written to prevent backwards time stamped data. */ private volatile int lastWrittenTs = -1; /** * Keeps track of the last spawned write worker. */ private volatile Future writerFuture; private volatile boolean gotVideoKeyFrame; /** * Default ctor */ public FileConsumer() { if (scheduledExecutorService == null) { synchronized (this) { scheduledExecutorService = Executors.newScheduledThreadPool(schedulerThreadSize, new CustomizableThreadFactory("FileConsumerExecutor-")); } } } /** * Creates file consumer * @param scope Scope of consumer * @param file File */ public FileConsumer(IScope scope, File file) { this(); this.scope = scope; this.file = file; } /** * Push message through pipe * @param pipe Pipe * @param message Message to push * @throws IOException if message could not be written */ @SuppressWarnings("rawtypes") public void pushMessage(IPipe pipe, IMessage message) throws IOException { if (message instanceof RTMPMessage) { final IRTMPEvent msg = ((RTMPMessage) message).getBody(); // get the type byte dataType = msg.getDataType(); // get the timestamp int timestamp = msg.getTimestamp(); log.debug("Data type: {} timestamp: {}", dataType, timestamp); // if we're dealing with a FlexStreamSend IRTMPEvent, this avoids relative timestamp calculations if (!(msg instanceof FlexStreamSend)) { log.trace("Not FlexStreamSend type"); lastTimestamp = timestamp; } // ensure that our first video frame written is a key frame if (msg instanceof VideoData) { if (!gotVideoKeyFrame) { VideoData video = (VideoData) msg; if (video.getFrameType() == FrameType.KEYFRAME) { log.debug("Got our first keyframe"); gotVideoKeyFrame = true; } else { // skip this frame bail out log.debug("Skipping video data since keyframe has not been written yet"); return; } } } //initialize a writer if (writer == null) { init(); } // if writes are delayed, queue the data and sort it by time if (!delayWrite) { write(timestamp, msg); } else { QueuedData queued = null; if (msg instanceof IStreamData) { log.debug("Stream data, body saved. Data type: {} class type: {}", dataType, msg.getClass().getName()); try { queued = new QueuedData(timestamp, dataType, ((IStreamData) msg).duplicate()); } catch (ClassNotFoundException e) { log.warn("Exception queueing stream data", e); } } else { //XXX what type of message are we saving that has no body data?? log.debug("Non-stream data, body not saved. Data type: {} class type: {}", dataType, msg.getClass().getName()); queued = new QueuedData(timestamp, dataType); } writeLock.lock(); try { //add to the queue queue.add(queued); } finally { writeLock.unlock(); } int queueSize = 0; readLock.lock(); try { queueSize = queue.size(); } finally { readLock.unlock(); } // when we reach the threshold, sort the entire queue and spawn a worker // to write a slice of the data if (queueSize >= queueThreshold) { Object writeResult = null; // check for existing future if (writerFuture != null) { try { // timeout 1/2 second for every slice entry long timeout = sliceLength * 500L; //wait n seconds for a result from the last writer writeResult = writerFuture.get(timeout, TimeUnit.MILLISECONDS); } catch (Exception e) { log.warn("Exception waiting for write result", e); return; } } log.debug("Write future result (expect null): {}", writeResult); // get the slice final QueuedData[] slice = new QueuedData[sliceLength]; log.trace("Slice length: {}", slice.length); writeLock.lock(); try { // sort the queue Collections.sort(queue); log.trace("Queue length: {}", queue.size()); for (int q = 0; q < sliceLength; q++) { slice[q] = queue.remove(0); } log.trace("Queue length (after removal): {}", queue.size()); } finally { writeLock.unlock(); } // spawn a writer writerFuture = scheduledExecutorService.submit(new Runnable() { public void run() { log.trace("Spawning queue writer thread"); doWrites(slice); } }); } } } else if (message instanceof ResetMessage) { startTimestamp = -1; } } /** * Out-of-band control message handler * * @param source Source of message * @param pipe Pipe that is used to transmit OOB message * @param oobCtrlMsg OOB control message */ public void onOOBControlMessage(IMessageComponent source, IPipe pipe, OOBControlMessage oobCtrlMsg) { } /** * Pipe connection event handler * @param event Pipe connection event */ public void onPipeConnectionEvent(PipeConnectionEvent event) { switch (event.getType()) { case PipeConnectionEvent.CONSUMER_CONNECT_PUSH: if (event.getConsumer() == this) { Map paramMap = event.getParamMap(); if (paramMap != null) { mode = (String) paramMap.get("mode"); } } break; case PipeConnectionEvent.CONSUMER_DISCONNECT: if (event.getConsumer() != this) { break; } case PipeConnectionEvent.PROVIDER_DISCONNECT: // we only support one provider at a time // so do releasing when provider disconnects uninit(); break; default: break; } } /** * Initialization * * @throws IOException I/O exception */ private void init() throws IOException { log.debug("Init"); // if we plan to use a queue, create one if (delayWrite) { queue = new ArrayList(); // add associated locks reentrantLock = new ReentrantReadWriteLock(); writeLock = reentrantLock.writeLock(); readLock = reentrantLock.readLock(); } IStreamableFileFactory factory = (IStreamableFileFactory) ScopeUtils.getScopeService(scope, IStreamableFileFactory.class, StreamableFileFactory.class); File folder = file.getParentFile(); if (!folder.exists()) { if (!folder.mkdirs()) { throw new IOException("Could not create parent folder"); } } if (!file.isFile()) { // Maybe the (previously existing) file has been deleted file.createNewFile(); } else if (!file.canWrite()) { throw new IOException("The file is read-only"); } IStreamableFileService service = factory.getService(file); IStreamableFile flv = service.getStreamableFile(file); if (mode == null || mode.equals(IClientStream.MODE_RECORD)) { writer = flv.getWriter(); //write the decoder config tag if it exists if (videoConfigurationTag != null) { writer.writeTag(videoConfigurationTag); videoConfigurationTag = null; } if (audioConfigurationTag != null) { writer.writeTag(audioConfigurationTag); audioConfigurationTag = null; } } else if (mode.equals(IClientStream.MODE_APPEND)) { writer = flv.getAppendWriter(); } else { throw new IllegalStateException("Illegal mode type: " + mode); } } /** * Reset */ private void uninit() { log.debug("Uninit"); if (writer != null) { if (writerFuture != null) { try { writerFuture.get(); } catch (Exception e) { log.warn("Exception waiting for write result on uninit", e); } writerFuture.cancel(true); } writerFuture = null; if (delayWrite) { // write all the queued items doWrites(); // clear the queue queue.clear(); queue = null; } //close the writer writer.close(); writer = null; } // clear file ref file = null; } /** * Write all the queued items to the writer. */ public final void doWrites() { QueuedData[] slice = null; writeLock.lock(); try { slice = queue.toArray(new QueuedData[0]); queue.removeAll(Arrays.asList(slice)); } finally { writeLock.unlock(); } doWrites(slice); } /** * Write a slice of the queued items to the writer. */ public final void doWrites(QueuedData[] slice) { //empty the queue for (QueuedData queued : slice) { int tmpTs = queued.getTimestamp(); if (lastWrittenTs <= tmpTs) { write(queued); lastWrittenTs = tmpTs; } } //clear and null-out slice = null; } /** * Write incoming data to the file. * * @param timestamp adjusted timestamp * @param msg stream data */ private final void write(int timestamp, IRTMPEvent msg) { byte dataType = msg.getDataType(); log.debug("Write - timestamp: {} type: {}", timestamp, dataType); //if the last message was a reset or we just started, use the header timer if (startTimestamp == -1) { startTimestamp = timestamp; timestamp = 0; } else { timestamp -= startTimestamp; } // create a tag ITag tag = new Tag(); tag.setDataType(dataType); tag.setTimestamp(timestamp); // get data bytes IoBuffer data = ((IStreamData) msg).getData().duplicate(); if (data != null) { tag.setBodySize(data.limit()); tag.setBody(data); } // only allow blank tags if they are of audio type if (tag.getBodySize() > 0 || dataType == ITag.TYPE_AUDIO) { try { if (timestamp >= 0) { if (!writer.writeTag(tag)) { log.warn("Tag was not written"); } } else { log.warn("Skipping message with negative timestamp."); } } catch (IOException e) { log.error("Error writing tag", e); } finally { if (data != null) { data.clear(); data.free(); } } } data = null; } /** * Adjust timestamp and write to the file. * * @param queued queued data for write */ private final void write(QueuedData queued) { if (queued != null) { //get timestamp int timestamp = queued.getTimestamp(); log.debug("Write - timestamp: {} type: {}", timestamp, queued.getDataType()); //if the last message was a reset or we just started, use the header timer if (startTimestamp == -1) { startTimestamp = timestamp; timestamp = 0; } else { timestamp -= startTimestamp; } // get the type byte dataType = queued.getDataType(); // create a tag ITag tag = new Tag(); tag.setDataType(dataType); tag.setTimestamp(timestamp); // get queued IoBuffer data = queued.getData(); if (data != null) { tag.setBodySize(data.limit()); tag.setBody(data); } // only allow blank tags if they are of audio type if (tag.getBodySize() > 0 || dataType == ITag.TYPE_AUDIO) { try { if (timestamp >= 0) { if (!writer.writeTag(tag)) { log.warn("Tag was not written"); } } else { log.warn("Skipping message with negative timestamp."); } } catch (ClosedChannelException cce) { // the channel we tried to write to is closed, we should not try again on that writer log.error("The writer is no longer able to write to the file: {} writable: {}", file.getName(), file.canWrite()); } catch (IOException e) { log.warn("Error writing tag", e); if (e.getCause() instanceof ClosedChannelException) { // the channel we tried to write to is closed, we should not try again on that writer log.error("The writer is no longer able to write to the file: {} writable: {}", file.getName(), file.canWrite()); } } finally { if (data != null) { data.clear(); data.free(); } } } data = null; queued.dispose(); queued = null; } else { log.warn("Queued data was null"); } } /** * Sets a video decoder configuration; some codecs require this, such as AVC. * * @param decoderConfig video codec configuration */ public void setVideoDecoderConfiguration(IRTMPEvent decoderConfig) { videoConfigurationTag = new Tag(); videoConfigurationTag.setDataType(decoderConfig.getDataType()); videoConfigurationTag.setTimestamp(0); if (decoderConfig instanceof IStreamData) { IoBuffer data = ((IStreamData) decoderConfig).getData().asReadOnlyBuffer(); videoConfigurationTag.setBodySize(data.limit()); videoConfigurationTag.setBody(data); } } // SplitmediaLabs - begin AAC fix /** * Sets a audio decoder configuration; some codecs require this, such as AAC. * * @param decoderConfig audio codec configuration */ public void setAudioDecoderConfiguration(IRTMPEvent decoderConfig) { audioConfigurationTag = new Tag(); audioConfigurationTag.setDataType(decoderConfig.getDataType()); audioConfigurationTag.setTimestamp(0); if (decoderConfig instanceof IStreamData) { IoBuffer data = ((IStreamData) decoderConfig).getData().asReadOnlyBuffer(); audioConfigurationTag.setBodySize(data.limit()); audioConfigurationTag.setBody(data); } } // SplitmediaLabs - end AAC fix /** * Sets the scope for this consumer. * * @param scope */ public void setScope(IScope scope) { this.scope = scope; } /** * Sets the file we're writing to. * * @param file */ public void setFile(File file) { this.file = file; } /** * Sets the threshold for the queue. When the threshold is met a worker is spawned * to empty the sorted queue to the writer. * * @param queueThreshold number of items to queue before spawning worker */ public void setQueueThreshold(int queueThreshold) { this.queueThreshold = queueThreshold; } /** * Returns the size of the delayed writing queue. * * @return queue length */ public int getQueueThreshold() { return queueThreshold; } /** * Sets the amount of queued data items to be written at a time. * * @param sliceLength */ public void setSliceLength(int sliceLength) { this.sliceLength = sliceLength; } /** * Returns the amount of queued data items to be written at a time. * * @return sliceLength */ public int getSliceLength() { return sliceLength; } /** * Whether or not the queue should be utilized. * * @return true if using the queue, false if sending directly to the writer */ public boolean isDelayWrite() { return delayWrite; } /** * Sets whether or not to use the queue. * * @param delayWrite true to use the queue, false if not */ public void setDelayWrite(boolean delayWrite) { this.delayWrite = delayWrite; } /** * @return the schedulerThreadSize */ public int getSchedulerThreadSize() { return schedulerThreadSize; } /** * @param schedulerThreadSize the schedulerThreadSize to set */ public void setSchedulerThreadSize(int schedulerThreadSize) { this.schedulerThreadSize = schedulerThreadSize; } /** * Queued data wrapper. */ private final static class QueuedData implements Comparable { final int timestamp; final byte dataType; @SuppressWarnings("rawtypes") final IStreamData streamData; QueuedData(int timestamp, byte dataType) { this.timestamp = timestamp; this.dataType = dataType; this.streamData = null; } @SuppressWarnings("rawtypes") QueuedData(int timestamp, byte dataType, IStreamData streamData) { this.timestamp = timestamp; this.dataType = dataType; this.streamData = streamData; } public int getTimestamp() { return timestamp; } public byte getDataType() { return dataType; } public IoBuffer getData() { return streamData.getData().asReadOnlyBuffer(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + dataType; result = prime * result + timestamp; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } QueuedData other = (QueuedData) obj; if (dataType != other.dataType) { return false; } if (timestamp != other.timestamp) { return false; } return true; } @Override public int compareTo(QueuedData other) { if (timestamp > other.timestamp) { return 1; } else if (timestamp < other.timestamp) { return -1; } return 0; } public void dispose() { streamData.getData().free(); } } } red5-1.0~svn4374.orig/src/org/red5/server/stream/consumer/ConnectionConsumer.java0000644000175000017500000002226111706617130027647 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.consumer; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.stream.IClientStream; import org.red5.server.messaging.IMessage; import org.red5.server.messaging.IMessageComponent; import org.red5.server.messaging.IPipe; import org.red5.server.messaging.IPipeConnectionListener; import org.red5.server.messaging.IPushableConsumer; import org.red5.server.messaging.OOBControlMessage; import org.red5.server.messaging.PipeConnectionEvent; import org.red5.server.net.rtmp.Channel; import org.red5.server.net.rtmp.RTMPConnection; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.BytesRead; import org.red5.server.net.rtmp.event.ChunkSize; import org.red5.server.net.rtmp.event.FlexStreamSend; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.Ping; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.net.rtmp.message.Constants; import org.red5.server.net.rtmp.message.Header; import org.red5.server.stream.message.RTMPMessage; import org.red5.server.stream.message.ResetMessage; import org.red5.server.stream.message.StatusMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * RTMP connection consumer. */ public class ConnectionConsumer implements IPushableConsumer, IPipeConnectionListener { /** * Logger */ private static final Logger log = LoggerFactory.getLogger(ConnectionConsumer.class); /** * Connection consumer class name */ public static final String KEY = ConnectionConsumer.class.getName(); /** * Connection object */ private RTMPConnection conn; /** * Video channel */ private Channel video; /** * Audio channel */ private Channel audio; /** * Data channel */ private Channel data; /** * Chunk size. Packets are sent chunk-by-chunk. */ private int chunkSize = 1024; //TODO: Not sure of the best value here /** * Whether or not the chunk size has been sent. This seems to be * required for h264. */ private boolean chunkSizeSent; /** * Create rtmp connection consumer for given connection and channels * @param conn RTMP connection * @param videoChannel Video channel * @param audioChannel Audio channel * @param dataChannel Data channel */ public ConnectionConsumer(RTMPConnection conn, int videoChannel, int audioChannel, int dataChannel) { log.debug("Channel ids - video: {} audio: {} data: {}", new Object[] { videoChannel, audioChannel, dataChannel }); this.conn = conn; this.video = conn.getChannel(videoChannel); this.audio = conn.getChannel(audioChannel); this.data = conn.getChannel(dataChannel); } /** {@inheritDoc} */ public void pushMessage(IPipe pipe, IMessage message) { //log.trace("pushMessage - type: {}", message.getMessageType()); if (message instanceof ResetMessage) { //ignore } else if (message instanceof StatusMessage) { StatusMessage statusMsg = (StatusMessage) message; data.sendStatus(statusMsg.getBody()); } else if (message instanceof RTMPMessage) { //make sure chunk size has been sent if (!chunkSizeSent) { sendChunkSize(); } // cast to rtmp message RTMPMessage rtmpMsg = (RTMPMessage) message; IRTMPEvent msg = rtmpMsg.getBody(); // get timestamp int eventTime = msg.getTimestamp(); log.debug("Message timestamp: {}", eventTime); if (eventTime < 0) { log.debug("Message has negative timestamp: {}", eventTime); return; } // get the data type byte dataType = msg.getDataType(); log.trace("Data type: {}", dataType); //create a new header for the consumer final Header header = new Header(); header.setTimerBase(eventTime); //data buffer IoBuffer buf = null; switch (dataType) { case Constants.TYPE_AGGREGATE: log.trace("Aggregate data"); data.write(msg); break; case Constants.TYPE_AUDIO_DATA: log.trace("Audio data"); buf = ((AudioData) msg).getData(); if (buf != null) { AudioData audioData = new AudioData(buf.asReadOnlyBuffer()); audioData.setHeader(header); audioData.setTimestamp(header.getTimer()); log.trace("Source type: {}", ((AudioData) msg).getSourceType()); audioData.setSourceType(((AudioData) msg).getSourceType()); audio.write(audioData); } else { log.warn("Audio data was not found"); } break; case Constants.TYPE_VIDEO_DATA: log.trace("Video data"); buf = ((VideoData) msg).getData(); if (buf != null) { VideoData videoData = new VideoData(buf.asReadOnlyBuffer()); videoData.setHeader(header); videoData.setTimestamp(header.getTimer()); log.trace("Source type: {}", ((VideoData) msg).getSourceType()); videoData.setSourceType(((VideoData) msg).getSourceType()); video.write(videoData); } else { log.warn("Video data was not found"); } break; case Constants.TYPE_PING: log.trace("Ping"); Ping ping = new Ping((Ping) msg); ping.setHeader(header); conn.ping(ping); break; case Constants.TYPE_STREAM_METADATA: log.trace("Meta data"); Notify notify = new Notify(((Notify) msg).getData().asReadOnlyBuffer()); notify.setHeader(header); notify.setTimestamp(header.getTimer()); data.write(notify); break; case Constants.TYPE_FLEX_STREAM_SEND: log.trace("Flex stream send"); // TODO: okay to send this also to AMF0 clients? FlexStreamSend send = new FlexStreamSend(((Notify) msg).getData().asReadOnlyBuffer()); send.setHeader(header); send.setTimestamp(header.getTimer()); data.write(send); break; case Constants.TYPE_BYTES_READ: log.trace("Bytes read"); BytesRead bytesRead = new BytesRead(((BytesRead) msg).getBytesRead()); bytesRead.setHeader(header); bytesRead.setTimestamp(header.getTimer()); conn.getChannel((byte) 2).write(bytesRead); break; default: log.trace("Default: {}", dataType); data.write(msg); } } else { log.debug("Unhandled push message: {}", message); if (log.isTraceEnabled()) { Class clazz = message.getClass(); log.trace("Class info - name: {} declaring: {} enclosing: {}", new Object[] { clazz.getName(), clazz.getDeclaringClass(), clazz.getEnclosingClass() }); } } } /** {@inheritDoc} */ public void onPipeConnectionEvent(PipeConnectionEvent event) { switch (event.getType()) { case PipeConnectionEvent.PROVIDER_DISCONNECT: // XXX should put the channel release code in ConsumerService conn.closeChannel(video.getId()); conn.closeChannel(audio.getId()); conn.closeChannel(data.getId()); break; default: } } /** {@inheritDoc} */ public void onOOBControlMessage(IMessageComponent source, IPipe pipe, OOBControlMessage oobCtrlMsg) { if ("ConnectionConsumer".equals(oobCtrlMsg.getTarget())) { String serviceName = oobCtrlMsg.getServiceName(); log.trace("Service name: {}", serviceName); if ("pendingCount".equals(serviceName)) { oobCtrlMsg.setResult(conn.getPendingMessages()); } else if ("pendingVideoCount".equals(serviceName)) { IClientStream stream = conn.getStreamByChannelId(video.getId()); if (stream != null) { oobCtrlMsg.setResult(conn.getPendingVideoMessages(stream.getStreamId())); } else { oobCtrlMsg.setResult(0L); } } else if ("writeDelta".equals(serviceName)) { //TODO: Revisit the max stream value later long maxStream = 120 * 1024; // Return the current delta between sent bytes and bytes the client // reported to have received, and the interval the client should use // for generating BytesRead messages (half of the allowed bandwidth). oobCtrlMsg.setResult(new Long[] { conn.getWrittenBytes() - conn.getClientBytesRead(), maxStream / 2 }); } else if ("chunkSize".equals(serviceName)) { int newSize = (Integer) oobCtrlMsg.getServiceParamMap().get("chunkSize"); if (newSize != chunkSize) { chunkSize = newSize; sendChunkSize(); } } } } /** * Send the chunk size */ private void sendChunkSize() { log.debug("Sending chunk size: {}", chunkSize); ChunkSize chunkSizeMsg = new ChunkSize(chunkSize); conn.getChannel((byte) 2).write(chunkSizeMsg); chunkSizeSent = true; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/IProviderService.java0000644000175000017500000000775311747114732025443 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.io.File; import java.util.Set; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeService; import org.red5.server.api.stream.IBroadcastStream; import org.red5.server.messaging.IMessageInput; /** * Central unit to get access to different types of provider inputs */ public interface IProviderService extends IScopeService { public final static String BEAN_NAME = "providerService"; enum INPUT_TYPE { NOT_FOUND, LIVE, LIVE_WAIT, VOD; }; /** * Returns the input type for a named provider if a source of input exists. * Live is checked first and VOD second. * * @param scope Scope of provider * @param name Name of provider * @param type Type of video stream * @return LIVE if live, VOD if VOD, and NOT_FOUND otherwise */ INPUT_TYPE lookupProviderInput(IScope scope, String name, int type); /** * Get a named provider as the source of input. * Live stream first, VOD stream second. * @param scope Scope of provider * @param name Name of provider * @return null if nothing found. */ IMessageInput getProviderInput(IScope scope, String name); /** * Get a named Live provider as the source of input. * * @param scope Scope of provider * @param name Name of provider * @param needCreate Whether there's need to create basic scope / live provider if they don't exist * @return null if not found. */ IMessageInput getLiveProviderInput(IScope scope, String name, boolean needCreate); /** * Get a named VOD provider as the source of input. * * @param scope Scope of provider * @param name Name of provider * @return null if not found. */ IMessageInput getVODProviderInput(IScope scope, String name); /** * Get a named VOD source file. * * @param scope Scope of provider * @param name Name of provider * @return null if not found. */ File getVODProviderFile(IScope scope, String name); /** * Register a broadcast stream to a scope. * * @param scope Scope * @param name Name of stream * @param stream Broadcast stream to register * @return true if register successfully. */ boolean registerBroadcastStream(IScope scope, String name, IBroadcastStream stream); /** * Get names of existing broadcast streams in a scope. * * @param scope Scope to get stream names from * @return List of stream names */ Set getBroadcastStreamNames(IScope scope); /** * Unregister a broadcast stream of a specific name from a scope. * * @param scope Scope * @param name Stream name * @return true if unregister successfully. */ boolean unregisterBroadcastStream(IScope scope, String name); /** * Unregister a broadcast stream of a specific name from a scope. * * @param scope Scope * @param name Stream name * @param stream Broadcast stream * @return true if unregister successfully. */ boolean unregisterBroadcastStream(IScope scope, String name, IBroadcastStream stream); } red5-1.0~svn4374.orig/src/org/red5/server/stream/IStreamControl.java0000644000175000017500000000165711706617130025114 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; /** * Stream Control Event. * * Marker interface for stream control operations. Play, Pause, Resume, Seek, * Stop, etc. */ public interface IStreamControl { } red5-1.0~svn4374.orig/src/org/red5/server/stream/SimplePlaylistController.java0000644000175000017500000000507011706617130027217 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.util.Random; import org.red5.server.api.stream.IPlaylist; import org.red5.server.api.stream.IPlaylistController; /** * Simple playlist controller implementation */ public class SimplePlaylistController implements IPlaylistController { /** {@inheritDoc} */ public int nextItem(IPlaylist playlist, int itemIndex) { if (itemIndex < 0) { itemIndex = -1; } if (playlist.isRepeat()) { return itemIndex; } if (playlist.isRandom()) { int lastIndex = itemIndex; if (playlist.getItemSize() > 1) { // continuously generate a random number // until you get one that was not the last... Random rand = new Random(); while (itemIndex == lastIndex) { itemIndex = rand.nextInt(playlist.getItemSize()); } } return itemIndex; } int nextIndex = itemIndex + 1; if (nextIndex < playlist.getItemSize()) { return nextIndex; } else if (playlist.isRewind()) { return playlist.getItemSize() > 0 ? 0 : -1; } else { return -1; } } /** {@inheritDoc} */ public int previousItem(IPlaylist playlist, int itemIndex) { if (itemIndex > playlist.getItemSize()) { return playlist.getItemSize() - 1; } if (playlist.isRepeat()) { return itemIndex; } if (playlist.isRandom()) { Random rand = new Random(); int lastIndex = itemIndex; // continuously generate a random number // until you get one that was not the last... while (itemIndex == lastIndex) { itemIndex = rand.nextInt(playlist.getItemSize()); } lastIndex = itemIndex; return itemIndex; } int prevIndex = itemIndex - 1; if (prevIndex >= 0) { return prevIndex; } else if (playlist.isRewind()) { return playlist.getItemSize() - 1; } else { return -1; } } }red5-1.0~svn4374.orig/src/org/red5/server/stream/ClientBroadcastStream.java0000644000175000017500000010173011757012455026422 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.management.ManagementFactory; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import javax.management.InstanceAlreadyExistsException; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.StandardMBean; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.red5.server.api.event.IEvent; import org.red5.server.api.event.IEventDispatcher; import org.red5.server.api.event.IEventListener; import org.red5.server.api.scope.IScope; import org.red5.server.api.statistics.IClientBroadcastStreamStatistics; import org.red5.server.api.statistics.support.StatisticsCounter; import org.red5.server.api.stream.IAudioStreamCodec; import org.red5.server.api.stream.IClientBroadcastStream; import org.red5.server.api.stream.IStreamAwareScopeHandler; import org.red5.server.api.stream.IStreamCapableConnection; import org.red5.server.api.stream.IStreamCodecInfo; import org.red5.server.api.stream.IStreamFilenameGenerator; import org.red5.server.api.stream.IStreamFilenameGenerator.GenerationType; import org.red5.server.api.stream.IStreamListener; import org.red5.server.api.stream.IStreamPacket; import org.red5.server.api.stream.IVideoStreamCodec; import org.red5.server.api.stream.ResourceExistException; import org.red5.server.api.stream.ResourceNotFoundException; import org.red5.server.jmx.mxbeans.ClientBroadcastStreamMXBean; import org.red5.server.messaging.AbstractPipe; import org.red5.server.messaging.IConsumer; import org.red5.server.messaging.IFilter; import org.red5.server.messaging.IMessage; import org.red5.server.messaging.IMessageComponent; import org.red5.server.messaging.IMessageOutput; import org.red5.server.messaging.IPipe; import org.red5.server.messaging.IPipeConnectionListener; import org.red5.server.messaging.IProvider; import org.red5.server.messaging.IPushableConsumer; import org.red5.server.messaging.InMemoryPushPushPipe; import org.red5.server.messaging.OOBControlMessage; import org.red5.server.messaging.PipeConnectionEvent; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.Invoke; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.net.rtmp.status.Status; import org.red5.server.net.rtmp.status.StatusCodes; import org.red5.server.stream.codec.StreamCodecInfo; import org.red5.server.stream.consumer.FileConsumer; import org.red5.server.stream.message.RTMPMessage; import org.red5.server.stream.message.StatusMessage; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jmx.export.annotation.ManagedResource; /** * Represents live stream broadcasted from client. As Flash Media Server, Red5 supports * recording mode for live streams, that is, broadcasted stream has broadcast mode. It can be either * "live" or "record" and latter causes server-side application to record broadcasted stream. * * Note that recorded streams are recorded as FLV files. The same is correct for audio, because * NellyMoser codec that Flash Player uses prohibits on-the-fly transcoding to audio formats like MP3 * without paying of licensing fee or buying SDK. * * This type of stream uses two different pipes for live streaming and recording. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong * @author Paul Gregoire (mondain@gmail.com) * @author Vladimir Hmelyoff (vlhm@splitmedialabs.com) */ @ManagedResource(objectName = "org.red5.server:type=ClientBroadcastStream", description = "ClientBroadcastStream") public class ClientBroadcastStream extends AbstractClientStream implements IClientBroadcastStream, IFilter, IPushableConsumer, IPipeConnectionListener, IEventDispatcher, IClientBroadcastStreamStatistics, ClientBroadcastStreamMXBean { private static final Logger log = LoggerFactory.getLogger(ClientBroadcastStream.class); /** * Whether or not to automatically record the associated stream. */ protected boolean automaticRecording; /** * Total number of bytes received. */ protected long bytesReceived; /** * Is there need to check video codec? */ protected boolean checkVideoCodec = false; /** * Is there need to check audio codec? */ protected boolean checkAudioCodec = false; /** * Data is sent by chunks, each of them has size */ protected int chunkSize; /** * Is this stream still active? */ protected volatile boolean closed; /** * Output endpoint that providers use */ protected IMessageOutput connMsgOut; /** * Stores timestamp of first packet */ protected long firstPacketTime = -1; /** * Pipe for live streaming */ protected IPipe livePipe; /** * Stream published name */ protected String publishedName; /** * Streaming parameters */ protected Map parameters; /** * Whether we are recording or not */ private volatile boolean recording; /** * Whether we are appending or not */ private volatile boolean appending; /** * FileConsumer used to output recording to disk */ private FileConsumer recordingFile; /** * The filename we are recording to. */ private String recordingFilename; /** * Pipe for recording */ private IPipe recordPipe; /** * Is there need to send start notification? */ protected boolean sendStartNotification = true; /** * Stores statistics about subscribers. */ private StatisticsCounter subscriberStats = new StatisticsCounter(); /** Listeners to get notified about received packets. */ protected Set listeners = new CopyOnWriteArraySet(); protected long latestTimeStamp = -1; /** * Check and send notification if necessary * @param event Event */ private void checkSendNotifications(IEvent event) { IEventListener source = event.getSource(); sendStartNotifications(source); } /** * Closes stream, unsubscribes provides, sends stoppage notifications and broadcast close notification. */ public void close() { log.info("Stream close"); if (closed) { // Already closed return; } closed = true; if (livePipe != null) { livePipe.unsubscribe((IProvider) this); } if (recordPipe != null) { recordPipe.unsubscribe((IProvider) this); ((AbstractPipe) recordPipe).close(); recordPipe = null; } if (recording) { sendRecordStopNotify(); } sendPublishStopNotify(); // TODO: can we sent the client something to make sure he stops sending data? connMsgOut.unsubscribe(this); notifyBroadcastClose(); // deregister with jmx unregisterJMX(); } /** * Dispatches event * @param event Event to dispatch */ public void dispatchEvent(IEvent event) { if (event instanceof IRTMPEvent && !closed) { switch (event.getType()) { case STREAM_CONTROL: case STREAM_DATA: // create the event IRTMPEvent rtmpEvent; try { rtmpEvent = (IRTMPEvent) event; } catch (ClassCastException e) { log.error("Class cast exception in event dispatch", e); return; } int eventTime = -1; if (log.isTraceEnabled()) { // If this is first packet save its timestamp; expect it is // absolute? no matter: it's never used! if (firstPacketTime == -1) { firstPacketTime = rtmpEvent.getTimestamp(); log.trace(String.format("CBS=@%08x: rtmpEvent=%s creation=%s firstPacketTime=%d", System.identityHashCode(this), rtmpEvent.getClass().getSimpleName(), creationTime, firstPacketTime)); } else { log.trace(String.format("CBS=@%08x: rtmpEvent=%s creation=%s firstPacketTime=%d timestamp=%d", System.identityHashCode(this), rtmpEvent.getClass() .getSimpleName(), creationTime, firstPacketTime, rtmpEvent.getTimestamp())); } } //get the buffer only once per call IoBuffer buf = null; if (rtmpEvent instanceof IStreamData && (buf = ((IStreamData) rtmpEvent).getData()) != null) { bytesReceived += buf.limit(); } // get stream codec IStreamCodecInfo codecInfo = getCodecInfo(); StreamCodecInfo info = null; if (codecInfo instanceof StreamCodecInfo) { info = (StreamCodecInfo) codecInfo; } if (rtmpEvent instanceof AudioData) { // SplitmediaLabs - begin AAC fix IAudioStreamCodec audioStreamCodec = null; if (checkAudioCodec) { audioStreamCodec = AudioCodecFactory.getAudioCodec(buf); if (info != null) { info.setAudioCodec(audioStreamCodec); } checkAudioCodec = false; } else if (codecInfo != null) { audioStreamCodec = codecInfo.getAudioCodec(); } if (audioStreamCodec != null) { audioStreamCodec.addData(buf.asReadOnlyBuffer()); } if (info != null) { info.setHasAudio(true); } eventTime = rtmpEvent.getTimestamp(); log.trace("Audio: {}", eventTime); } else if (rtmpEvent instanceof VideoData) { IVideoStreamCodec videoStreamCodec = null; if (checkVideoCodec) { videoStreamCodec = VideoCodecFactory.getVideoCodec(buf); if (info != null) { info.setVideoCodec(videoStreamCodec); } checkVideoCodec = false; } else if (codecInfo != null) { videoStreamCodec = codecInfo.getVideoCodec(); } if (videoStreamCodec != null) { videoStreamCodec.addData(buf.asReadOnlyBuffer()); } if (info != null) { info.setHasVideo(true); } eventTime = rtmpEvent.getTimestamp(); log.trace("Video: {}", eventTime); } else if (rtmpEvent instanceof Invoke) { eventTime = rtmpEvent.getTimestamp(); //do we want to return from here? //event / stream listeners will not be notified of invokes return; } else if (rtmpEvent instanceof Notify) { //TDJ: store METADATA Notify notifyEvent = (Notify) rtmpEvent; if (metaData == null && notifyEvent.getHeader().getDataType() == Notify.TYPE_STREAM_METADATA) { try { metaData = notifyEvent.duplicate(); } catch (Exception e) { log.warn("Metadata could not be duplicated for this stream", e); } } eventTime = rtmpEvent.getTimestamp(); } // update last event time if (eventTime > latestTimeStamp) { latestTimeStamp = eventTime; } // notify event listeners checkSendNotifications(event); // note this timestamp is set in event/body but not in the associated header try { // route to recording if (recording) { if (recordPipe != null) { // get the current size of the buffer / data int bufferLimit = buf.limit(); if (bufferLimit > 0) { // make a copy for the record pipe buf.mark(); byte[] buffer = new byte[bufferLimit]; buf.get(buffer); buf.reset(); // Create new RTMP message, initialize it and push through pipe RTMPMessage msg = null; if (rtmpEvent instanceof AudioData) { AudioData audio = new AudioData(IoBuffer.wrap(buffer)); audio.setTimestamp(eventTime); msg = RTMPMessage.build(audio); } else if (rtmpEvent instanceof VideoData) { VideoData video = new VideoData(IoBuffer.wrap(buffer)); video.setTimestamp(eventTime); msg = RTMPMessage.build(video); } else if (rtmpEvent instanceof Notify) { Notify not = new Notify(IoBuffer.wrap(buffer)); not.setTimestamp(eventTime); msg = RTMPMessage.build(not); } else { log.info("Data was not of A/V type: {}", rtmpEvent.getType()); msg = RTMPMessage.build(rtmpEvent, eventTime); } // push it down to the recorder recordPipe.pushMessage(msg); } else if (bufferLimit == 0 && rtmpEvent instanceof AudioData) { log.debug("Stream data size was 0, sending empty audio message"); // allow for 0 byte audio packets AudioData audio = new AudioData(IoBuffer.allocate(0)); audio.setTimestamp(eventTime); RTMPMessage msg = RTMPMessage.build(audio); // push it down to the recorder recordPipe.pushMessage(msg); } else { log.debug("Stream data size was 0, recording pipe will not be notified"); } } else { log.debug("Record pipe was null, message was not pushed"); } } else { log.trace("Recording not active"); } // route to live if (livePipe != null) { // create new RTMP message, initialize it and push through pipe RTMPMessage msg = RTMPMessage.build(rtmpEvent, eventTime); livePipe.pushMessage(msg); } else { log.debug("Live pipe was null, message was not pushed"); } } catch (IOException err) { sendRecordFailedNotify(err.getMessage()); stop(); } // Notify listeners about received packet if (rtmpEvent instanceof IStreamPacket) { for (IStreamListener listener : getStreamListeners()) { try { listener.packetReceived(this, (IStreamPacket) rtmpEvent); } catch (Exception e) { log.error("Error while notifying listener {}", listener, e); } } } break; default: // ignored event log.debug("Ignoring event: {}", event.getType()); } } else { log.debug("Event was of wrong type or stream is closed ({})", closed); } } /** {@inheritDoc} */ public int getActiveSubscribers() { return subscriberStats.getCurrent(); } /** {@inheritDoc} */ public long getBytesReceived() { return bytesReceived; } /** {@inheritDoc} */ public int getCurrentTimestamp() { return (int) latestTimeStamp; } /** {@inheritDoc} */ public int getMaxSubscribers() { return subscriberStats.getMax(); } /** * Getter for provider * @return Provider */ public IProvider getProvider() { return this; } /** * Setter for stream published name * @param name Name that used for publishing. Set at client side when begin to broadcast with NetStream#publish. */ public void setPublishedName(String name) { log.debug("setPublishedName: {}", name); // a publish name of "false" is a special case, used when stopping a stream if (!"false".equals(name)) { this.publishedName = name; registerJMX(); } } /** * Getter for published name * @return Stream published name */ public String getPublishedName() { return publishedName; } /** {@inheritDoc} */ public void setParameters(Map params) { this.parameters = params; } /** {@inheritDoc} */ public Map getParameters() { return parameters; } /** {@inheritDoc} */ public String getSaveFilename() { return recordingFilename; } /** {@inheritDoc} */ public IClientBroadcastStreamStatistics getStatistics() { return this; } /** {@inheritDoc} */ public int getTotalSubscribers() { return subscriberStats.getTotal(); } /** * @return the automaticRecording */ public boolean isAutomaticRecording() { return automaticRecording; } /** * @param automaticRecording the automaticRecording to set */ public void setAutomaticRecording(boolean automaticRecording) { this.automaticRecording = automaticRecording; } /** * Notifies handler on stream broadcast stop */ private void notifyBroadcastClose() { IStreamAwareScopeHandler handler = getStreamAwareHandler(); if (handler != null) { try { handler.streamBroadcastClose(this); } catch (Throwable t) { log.error("Error in notifyBroadcastClose", t); } } } /** * Notifies handler on stream broadcast start */ private void notifyBroadcastStart() { IStreamAwareScopeHandler handler = getStreamAwareHandler(); if (handler != null) { try { handler.streamBroadcastStart(this); } catch (Throwable t) { log.error("Error in notifyBroadcastStart", t); } } } /** * Send OOB control message with chunk size */ private void notifyChunkSize() { if (chunkSize > 0 && livePipe != null) { OOBControlMessage setChunkSize = new OOBControlMessage(); setChunkSize.setTarget("ConnectionConsumer"); setChunkSize.setServiceName("chunkSize"); if (setChunkSize.getServiceParamMap() == null) { setChunkSize.setServiceParamMap(new HashMap()); } setChunkSize.getServiceParamMap().put("chunkSize", chunkSize); livePipe.sendOOBControlMessage(getProvider(), setChunkSize); } } /** * Out-of-band control message handler * * @param source OOB message source * @param pipe Pipe that used to send OOB message * @param oobCtrlMsg Out-of-band control message */ public void onOOBControlMessage(IMessageComponent source, IPipe pipe, OOBControlMessage oobCtrlMsg) { String target = oobCtrlMsg.getTarget(); if ("ClientBroadcastStream".equals(target)) { String serviceName = oobCtrlMsg.getServiceName(); if ("chunkSize".equals(serviceName)) { chunkSize = (Integer) oobCtrlMsg.getServiceParamMap().get("chunkSize"); notifyChunkSize(); } else { log.debug("Unhandled OOB control message for service: {}", serviceName); } } else { log.debug("Unhandled OOB control message to target: {}", target); } } /** * Pipe connection event handler * @param event Pipe connection event */ @SuppressWarnings("unused") public void onPipeConnectionEvent(PipeConnectionEvent event) { switch (event.getType()) { case PipeConnectionEvent.PROVIDER_CONNECT_PUSH: log.info("Provider connect"); if (event.getProvider() == this && event.getSource() != connMsgOut && (event.getParamMap() == null || !event.getParamMap().containsKey("record"))) { this.livePipe = (IPipe) event.getSource(); log.debug("Provider: {}", this.livePipe.getClass().getName()); for (IConsumer consumer : this.livePipe.getConsumers()) { subscriberStats.increment(); } } break; case PipeConnectionEvent.PROVIDER_DISCONNECT: log.info("Provider disconnect"); if (log.isDebugEnabled() && this.livePipe != null) { log.debug("Provider: {}", this.livePipe.getClass().getName()); } if (this.livePipe == event.getSource()) { this.livePipe = null; } break; case PipeConnectionEvent.CONSUMER_CONNECT_PUSH: log.info("Consumer connect"); IPipe pipe = (IPipe) event.getSource(); if (log.isDebugEnabled() && pipe != null) { log.debug("Consumer: {}", pipe.getClass().getName()); } if (this.livePipe == pipe) { notifyChunkSize(); } subscriberStats.increment(); break; case PipeConnectionEvent.CONSUMER_DISCONNECT: log.info("Consumer disconnect"); log.debug("Consumer: {}", event.getSource().getClass().getName()); subscriberStats.decrement(); break; default: } } /** * Currently not implemented * * @param pipe Pipe * @param message Message */ public void pushMessage(IPipe pipe, IMessage message) { } /** * Save broadcasted stream. * * @param name Stream name * @param isAppend Append mode * @throws IOException File could not be created/written to. * @throws ResourceNotFoundException Resource doesn't exist when trying to append. * @throws ResourceExistException Resource exist when trying to create. */ public void saveAs(String name, boolean isAppend) throws IOException, ResourceNotFoundException, ResourceExistException { log.debug("SaveAs - name: {} append: {}", name, isAppend); Map recordParamMap = new HashMap(1); //setup record objects if (recordPipe == null) { recordPipe = new InMemoryPushPushPipe(); // Clear record flag recordParamMap.put("record", null); recordPipe.subscribe((IProvider) this, recordParamMap); recordParamMap.clear(); } // Get stream scope IStreamCapableConnection conn = getConnection(); if (conn == null) { // TODO: throw other exception here? throw new IOException("Stream is no longer connected"); } // get connections scope IScope scope = conn.getScope(); // get the file for our filename File file = getRecordFile(scope, name); // If append mode is on... if (!isAppend) { if (file.exists()) { // when "live" or "record" is used, any previously recorded stream with the same stream URI is deleted. if (!file.delete()) { throw new IOException(String.format("File: %s could not be deleted", file.getName())); } } } else { if (file.exists()) { appending = true; } else { // if a recorded stream at the same URI does not already exist, "append" creates the stream as though "record" was passed. isAppend = false; } } // if the file doesn't exist yet, create it if (!file.exists()) { // Make sure the destination directory exists String path = file.getAbsolutePath(); int slashPos = path.lastIndexOf(File.separator); if (slashPos != -1) { path = path.substring(0, slashPos); } File tmp = new File(path); if (!tmp.isDirectory()) { tmp.mkdirs(); } file.createNewFile(); } //remove existing meta file File meta = new File(file.getCanonicalPath() + ".meta"); if (meta.exists()) { log.trace("Meta file exists"); if (meta.delete()) { log.debug("Meta file deleted - {}", meta.getName()); } else { log.warn("Meta file was not deleted - {}", meta.getName()); meta.deleteOnExit(); } } else { log.debug("Meta file does not exist: {}", meta.getCanonicalPath()); } log.debug("Recording file: {}", file.getCanonicalPath()); // get instance via spring if (scope.getContext().hasBean("fileConsumer")) { log.debug("Context contains a file consumer"); recordingFile = (FileConsumer) scope.getContext().getBean("fileConsumer"); recordingFile.setScope(scope); recordingFile.setFile(file); } else { log.debug("Context does not contain a file consumer, using direct instance"); // get a new instance recordingFile = new FileConsumer(scope, file); } //get decoder info if it exists for the stream IStreamCodecInfo codecInfo = getCodecInfo(); log.debug("Codec info: {}", codecInfo); if (codecInfo instanceof StreamCodecInfo) { StreamCodecInfo info = (StreamCodecInfo) codecInfo; IVideoStreamCodec videoCodec = info.getVideoCodec(); log.debug("Video codec: {}", videoCodec); if (videoCodec != null) { //check for decoder configuration to send IoBuffer config = videoCodec.getDecoderConfiguration(); if (config != null) { log.debug("Decoder configuration is available for {}", videoCodec.getName()); VideoData conf = new VideoData(config.asReadOnlyBuffer()); try { log.debug("Setting decoder configuration for recording"); recordingFile.setVideoDecoderConfiguration(conf); } finally { conf.release(); } } } else { log.debug("Could not initialize stream output, videoCodec is null."); } // SplitmediaLabs - begin AAC fix IAudioStreamCodec audioCodec = info.getAudioCodec(); log.debug("Audio codec: {}", audioCodec); if (audioCodec != null) { //check for decoder configuration to send IoBuffer config = audioCodec.getDecoderConfiguration(); if (config != null) { log.debug("Decoder configuration is available for {}", audioCodec.getName()); AudioData conf = new AudioData(config.asReadOnlyBuffer()); try { log.debug("Setting decoder configuration for recording"); recordingFile.setAudioDecoderConfiguration(conf); } finally { conf.release(); } } } else { log.debug("No decoder configuration available, audioCodec is null."); } } if (isAppend) { recordParamMap.put("mode", "append"); } else { recordParamMap.put("mode", "record"); } //mark as "recording" only if we get subscribed recording = recordPipe.subscribe(recordingFile, recordParamMap); } /** * Sends publish start notifications */ private void sendPublishStartNotify() { Status publishStatus = new Status(StatusCodes.NS_PUBLISH_START); publishStatus.setClientid(getStreamId()); publishStatus.setDetails(getPublishedName()); StatusMessage startMsg = new StatusMessage(); startMsg.setBody(publishStatus); try { connMsgOut.pushMessage(startMsg); } catch (IOException err) { log.error("Error while pushing message.", err); } } /** * Sends publish stop notifications */ private void sendPublishStopNotify() { Status stopStatus = new Status(StatusCodes.NS_UNPUBLISHED_SUCCESS); stopStatus.setClientid(getStreamId()); stopStatus.setDetails(getPublishedName()); StatusMessage stopMsg = new StatusMessage(); stopMsg.setBody(stopStatus); try { connMsgOut.pushMessage(stopMsg); } catch (IOException err) { log.error("Error while pushing message.", err); } } /** * Sends record failed notifications */ private void sendRecordFailedNotify(String reason) { Status failedStatus = new Status(StatusCodes.NS_RECORD_FAILED); failedStatus.setLevel(Status.ERROR); failedStatus.setClientid(getStreamId()); failedStatus.setDetails(getPublishedName()); failedStatus.setDesciption(reason); StatusMessage failedMsg = new StatusMessage(); failedMsg.setBody(failedStatus); try { connMsgOut.pushMessage(failedMsg); } catch (IOException err) { log.error("Error while pushing message.", err); } } /** * Sends record start notifications */ private void sendRecordStartNotify() { Status recordStatus = new Status(StatusCodes.NS_RECORD_START); recordStatus.setClientid(getStreamId()); recordStatus.setDetails(getPublishedName()); StatusMessage startMsg = new StatusMessage(); startMsg.setBody(recordStatus); try { connMsgOut.pushMessage(startMsg); } catch (IOException err) { log.error("Error while pushing message.", err); } } /** * Sends record stop notifications */ private void sendRecordStopNotify() { Status stopStatus = new Status(StatusCodes.NS_RECORD_STOP); stopStatus.setClientid(getStreamId()); stopStatus.setDetails(getPublishedName()); StatusMessage stopMsg = new StatusMessage(); stopMsg.setBody(stopStatus); try { connMsgOut.pushMessage(stopMsg); } catch (IOException err) { log.error("Error while pushing message.", err); } } private void sendStartNotifications(IEventListener source) { if (sendStartNotification) { // notify handler that stream starts recording/publishing sendStartNotification = false; if (source instanceof IConnection) { IScope scope = ((IConnection) source).getScope(); if (scope.hasHandler()) { Object handler = scope.getHandler(); if (handler instanceof IStreamAwareScopeHandler) { if (recording) { // callback for record start ((IStreamAwareScopeHandler) handler).streamRecordStart(this); } else { // delete any previously recorded versions of this now "live" stream per // http://livedocs.adobe.com/flashmediaserver/3.0/hpdocs/help.html?content=00000186.html try { File file = getRecordFile(scope, publishedName); if (file.exists()) { if (!file.delete()) { log.debug("File was not deleted: {}", file.getAbsoluteFile()); } } } catch (Exception e) { log.warn("Exception removing previously recorded file", e); } // callback for publish start ((IStreamAwareScopeHandler) handler).streamPublishStart(this); } } } } // send start notifications sendPublishStartNotify(); if (recording) { sendRecordStartNotify(); } notifyBroadcastStart(); } } /** * Starts stream. Creates pipes, connects */ public void start() { log.info("Stream start"); IConsumerService consumerManager = (IConsumerService) getScope().getContext().getBean(IConsumerService.KEY); checkVideoCodec = true; checkAudioCodec = true; firstPacketTime = -1; latestTimeStamp = -1; connMsgOut = consumerManager.getConsumerOutput(this); connMsgOut.subscribe(this, null); setCodecInfo(new StreamCodecInfo()); closed = false; bytesReceived = 0; creationTime = System.currentTimeMillis(); } /** {@inheritDoc} */ public void startPublishing() { // We send the start messages before the first packet is received. // This is required so FME actually starts publishing. sendStartNotifications(Red5.getConnectionLocal()); // force recording if (automaticRecording && !appending) { log.debug("Starting automatic recording of {}", publishedName); try { saveAs(publishedName, false); } catch (Exception e) { log.warn("Start of automatic recording failed", e); } } } /** {@inheritDoc} */ public void stop() { log.info("Stream stop"); stopRecording(); close(); } /** * Stops any currently active recordings. */ public void stopRecording() { if (recording) { recording = false; appending = false; recordingFilename = null; recordPipe.unsubscribe(recordingFile); sendRecordStopNotify(); recordPipe = null; } } public boolean isRecording() { return recording; } /** {@inheritDoc} */ public void addStreamListener(IStreamListener listener) { listeners.add(listener); } /** {@inheritDoc} */ public Collection getStreamListeners() { return listeners; } /** {@inheritDoc} */ public void removeStreamListener(IStreamListener listener) { listeners.remove(listener); } /** * Get the file we'd be recording to based on scope and given name. * * @param scope * @param name * @return file */ protected File getRecordFile(IScope scope, String name) { // get stream filename generator IStreamFilenameGenerator generator = (IStreamFilenameGenerator) ScopeUtils.getScopeService(scope, IStreamFilenameGenerator.class, DefaultStreamFilenameGenerator.class); // generate filename recordingFilename = generator.generateFilename(scope, name, ".flv", GenerationType.RECORD); File file = null; if (generator.resolvesToAbsolutePath()) { file = new File(recordingFilename); } else { try { file = scope.getContext().getResource(recordingFilename).getFile(); log.debug("File path: {}", file.getCanonicalPath()); log.debug("File exists: {} writable: {}", file.exists(), file.canWrite()); } catch (FileNotFoundException fnfe) { log.debug("File not found: {}", fnfe); String appScopeName = ScopeUtils.findApplication(scope).getName(); file = new File(String.format("%s/webapps/%s/%s", System.getProperty("red5.root"), appScopeName, recordingFilename)); } catch (IOException e) { log.debug("File error: {}", e); } } return file; } protected void registerJMX() { // register with jmx MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { ObjectName oName = new ObjectName(String.format("org.red5.server:type=ClientBroadcastStream,publishedName=%s", publishedName)); mbs.registerMBean(new StandardMBean(this, ClientBroadcastStreamMXBean.class, true), oName); } catch (InstanceAlreadyExistsException e) { log.info("Instance already registered", e); } catch (Exception e) { log.warn("Error on jmx registration", e); } } protected void unregisterJMX() { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { ObjectName oName = new ObjectName(String.format("org.red5.server:type=ClientBroadcastStream,publishedName=%s", publishedName)); mbs.unregisterMBean(oName); } catch (Exception e) { log.warn("Exception unregistering", e); } } } red5-1.0~svn4374.orig/src/org/red5/server/stream/provider/0000755000175000017500000000000011760512571023170 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/stream/provider/ConnectionProvider.java0000644000175000017500000000351611706617130027647 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.provider; import org.red5.server.messaging.IMessageComponent; import org.red5.server.messaging.IPipe; import org.red5.server.messaging.IPipeConnectionListener; import org.red5.server.messaging.IProvider; import org.red5.server.messaging.OOBControlMessage; import org.red5.server.messaging.PipeConnectionEvent; /** * Provides connection via pipe */ public class ConnectionProvider implements IProvider, IPipeConnectionListener { /** * Pipe used by connection */ private IPipe pipe; /** {@inheritDoc} */ public void onOOBControlMessage(IMessageComponent source, IPipe pipe, OOBControlMessage oobCtrlMsg) { } /** {@inheritDoc} */ public void onPipeConnectionEvent(PipeConnectionEvent event) { switch (event.getType()) { case PipeConnectionEvent.PROVIDER_CONNECT_PUSH: if (event.getProvider() == this) { this.pipe = (IPipe) event.getSource(); } break; case PipeConnectionEvent.PROVIDER_DISCONNECT: if (this.pipe == event.getSource()) { this.pipe = null; } break; default: break; } } } red5-1.0~svn4374.orig/src/org/red5/server/stream/provider/FileProvider.java0000644000175000017500000002033511747635016026435 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright (c) 2006-2011 by respective authors (see below). All rights reserved. * * This library is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any later * version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.red5.server.stream.provider; import java.io.File; import java.io.IOException; import org.red5.io.IStreamableFile; import org.red5.io.IStreamableFileFactory; import org.red5.io.IStreamableFileService; import org.red5.io.ITag; import org.red5.io.ITagReader; import org.red5.io.StreamableFileFactory; import org.red5.io.flv.IKeyFrameDataAnalyzer; import org.red5.io.flv.IKeyFrameDataAnalyzer.KeyFrameMeta; import org.red5.server.api.scope.IScope; import org.red5.server.messaging.IMessage; import org.red5.server.messaging.IMessageComponent; import org.red5.server.messaging.IPassive; import org.red5.server.messaging.IPipe; import org.red5.server.messaging.IPipeConnectionListener; import org.red5.server.messaging.IPullableProvider; import org.red5.server.messaging.OOBControlMessage; import org.red5.server.messaging.PipeConnectionEvent; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.FlexStreamSend; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.Invoke; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.Unknown; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.net.rtmp.message.Constants; import org.red5.server.stream.ISeekableProvider; import org.red5.server.stream.IStreamTypeAwareProvider; import org.red5.server.stream.message.RTMPMessage; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Pullable provider for files */ public class FileProvider implements IPassive, ISeekableProvider, IPullableProvider, IPipeConnectionListener, IStreamTypeAwareProvider { /** * Logger */ private static final Logger log = LoggerFactory.getLogger(FileProvider.class); /** * Class name */ public static final String KEY = FileProvider.class.getName(); /** * Provider scope */ private IScope scope; /** * Source file */ private File file; /** * Consumer pipe */ private IPipe pipe; /** * Tag reader */ private ITagReader reader; /** * Keyframe metadata */ private KeyFrameMeta keyFrameMeta; /** * Position at start */ private int start; /** * Create file provider for given file and scope * @param scope Scope * @param file File */ public FileProvider(IScope scope, File file) { this.scope = scope; this.file = file; } /** * Setter for start position * * @param start Start position */ public void setStart(int start) { this.start = start; } /** {@inheritDoc} */ public boolean hasVideo() { return (reader != null && reader.hasVideo()); } /** {@inheritDoc} */ public synchronized IMessage pullMessage(IPipe pipe) throws IOException { if (this.pipe == pipe) { if (reader == null) { init(); } if (reader.hasMoreTags()) { IRTMPEvent msg = null; ITag tag = reader.readTag(); if (tag != null) { int timestamp = tag.getTimestamp(); switch (tag.getDataType()) { case Constants.TYPE_AUDIO_DATA: msg = new AudioData(tag.getBody()); break; case Constants.TYPE_VIDEO_DATA: msg = new VideoData(tag.getBody()); break; case Constants.TYPE_INVOKE: msg = new Invoke(tag.getBody()); break; case Constants.TYPE_NOTIFY: msg = new Notify(tag.getBody()); break; case Constants.TYPE_FLEX_STREAM_SEND: msg = new FlexStreamSend(tag.getBody()); break; default: log.warn("Unexpected type? {}", tag.getDataType()); msg = new Unknown(tag.getDataType(), tag.getBody()); } msg.setTimestamp(timestamp); RTMPMessage rtmpMsg = RTMPMessage.build(msg); return rtmpMsg; } else { log.debug("Tag was null"); } } else { // TODO send OOBCM to notify EOF // Do not unsubscribe if there aren't any more tags, as this kills VOD seek while in buffer // this.pipe.unsubscribe(this); } } return null; } /** {@inheritDoc} */ public IMessage pullMessage(IPipe pipe, long wait) throws IOException { return pullMessage(pipe); } /** {@inheritDoc} */ public void onPipeConnectionEvent(PipeConnectionEvent event) { switch (event.getType()) { case PipeConnectionEvent.PROVIDER_CONNECT_PULL: if (pipe == null) { pipe = (IPipe) event.getSource(); } break; case PipeConnectionEvent.PROVIDER_DISCONNECT: if (pipe == event.getSource()) { this.pipe = null; uninit(); } break; case PipeConnectionEvent.CONSUMER_DISCONNECT: if (pipe == event.getSource()) { uninit(); } default: } } /** {@inheritDoc} */ public void onOOBControlMessage(IMessageComponent source, IPipe pipe, OOBControlMessage oobCtrlMsg) { String serviceName = oobCtrlMsg.getServiceName(); String target = oobCtrlMsg.getTarget(); log.debug("onOOBControlMessage - service name: {} target: {}", serviceName, target); if (serviceName != null) { if (IPassive.KEY.equals(target)) { if ("init".equals(serviceName)) { Integer startTS = (Integer) oobCtrlMsg.getServiceParamMap().get("startTS"); setStart(startTS); } } else if (ISeekableProvider.KEY.equals(target)) { if ("seek".equals(serviceName)) { Integer position = (Integer) oobCtrlMsg.getServiceParamMap().get("position"); int seekPos = seek(position.intValue()); // Return position we seeked to oobCtrlMsg.setResult(seekPos); } } else if (IStreamTypeAwareProvider.KEY.equals(target)) { if ("hasVideo".equals(serviceName)) { oobCtrlMsg.setResult(hasVideo()); } } } } /** * Initializes file provider. Creates streamable file factory and service, seeks to start position */ private void init() throws IOException { IStreamableFileFactory factory = (IStreamableFileFactory) ScopeUtils.getScopeService(scope, IStreamableFileFactory.class, StreamableFileFactory.class); IStreamableFileService service = factory.getService(file); if (service == null) { log.error("No service found for {}", file.getAbsolutePath()); return; } IStreamableFile streamFile = service.getStreamableFile(file); reader = streamFile.getReader(); if (start > 0) { seek(start); } } /** * Reset */ private void uninit() { if (reader != null) { reader.close(); reader = null; } } /** {@inheritDoc} */ public synchronized int seek(int ts) { log.trace("Seek ts: {}", ts); if (keyFrameMeta == null) { if (!(reader instanceof IKeyFrameDataAnalyzer)) { // Seeking not supported return ts; } keyFrameMeta = ((IKeyFrameDataAnalyzer) reader).analyzeKeyFrames(); } if (keyFrameMeta.positions.length == 0) { // no video keyframe metainfo, it's an audio-only FLV // we skip the seek for now. // TODO add audio-seek capability return ts; } if (ts >= keyFrameMeta.duration) { // Seek at or beyond EOF reader.position(Long.MAX_VALUE); return (int) keyFrameMeta.duration; } int frame = 0; for (int i = 0; i < keyFrameMeta.positions.length; i++) { if (keyFrameMeta.timestamps[i] > ts) { break; } frame = i; } reader.position(keyFrameMeta.positions[frame]); return keyFrameMeta.timestamps[frame]; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/PlaylistSubscriberStream.java0000644000175000017500000005400511747114732027210 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.io.IOException; import java.util.LinkedList; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.IConnection; import org.red5.server.api.IContext; import org.red5.server.api.Red5; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.api.scope.IScope; import org.red5.server.api.statistics.IPlaylistSubscriberStreamStatistics; import org.red5.server.api.stream.IPlayItem; import org.red5.server.api.stream.IPlaylistController; import org.red5.server.api.stream.IPlaylistSubscriberStream; import org.red5.server.api.stream.IStreamAwareScopeHandler; import org.red5.server.api.stream.OperationNotSupportedException; import org.red5.server.api.stream.StreamState; import org.slf4j.Logger; /** * Stream of playlist subscriber */ public class PlaylistSubscriberStream extends AbstractClientStream implements IPlaylistSubscriberStream, IPlaylistSubscriberStreamStatistics { private static final Logger log = Red5LoggerFactory.getLogger(PlaylistSubscriberStream.class); private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private final Lock read = readWriteLock.readLock(); private final Lock write = readWriteLock.writeLock(); /** * Playlist controller */ private IPlaylistController controller; /** * Default playlist controller */ private IPlaylistController defaultController; /** * Playlist items */ private final LinkedList items; /** * Current item index */ private int currentItemIndex = 0; /** * Plays items back */ protected PlayEngine engine; /** * Rewind mode state */ protected boolean rewind; /** * Random mode state */ protected boolean random; /** * Repeat mode state */ protected boolean repeat; /** * Executor that will be used to schedule stream playback to keep * the client buffer filled. */ protected static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(3); /** * Interval in ms to check for buffer underruns in VOD streams. */ protected int bufferCheckInterval = 0; /** * Number of pending messages at which a NetStream.Play.InsufficientBW * message is generated for VOD streams. */ protected int underrunTrigger = 10; /** * Timestamp this stream was created. */ protected long creationTime = System.currentTimeMillis(); /** * Number of bytes sent. */ protected long bytesSent = 0; /** Constructs a new PlaylistSubscriberStream. */ public PlaylistSubscriberStream() { defaultController = new SimplePlaylistController(); items = new LinkedList(); } /** * Creates a play engine based on current services (scheduling service, consumer service, and provider service). * This method is useful during unit testing. */ PlayEngine createEngine(ISchedulingService schedulingService, IConsumerService consumerService, IProviderService providerService) { engine = new PlayEngine.Builder(this, schedulingService, consumerService, providerService).build(); return engine; } /** * Set the executor to use. * * @param executor the executor */ public void setExecutor(ScheduledThreadPoolExecutor executor) { PlaylistSubscriberStream.executor = executor; } /** * Return the executor to use. * * @return the executor */ public ScheduledThreadPoolExecutor getExecutor() { if (executor == null) { log.warn("ScheduledThreadPoolExecutor was null on request"); } return executor; } /** * Set interval to check for buffer underruns. Set to 0 to * disable. * * @param bufferCheckInterval interval in ms */ public void setBufferCheckInterval(int bufferCheckInterval) { this.bufferCheckInterval = bufferCheckInterval; } /** * Set maximum number of pending messages at which a * NetStream.Play.InsufficientBW message will be * generated for VOD streams * * @param underrunTrigger the maximum number of pending messages */ public void setUnderrunTrigger(int underrunTrigger) { this.underrunTrigger = underrunTrigger; } /** {@inheritDoc} */ public void start() { //ensure the play engine exists if (engine == null) { IScope scope = getScope(); if (scope != null) { IContext ctx = scope.getContext(); ISchedulingService schedulingService = null; if (ctx.hasBean(ISchedulingService.BEAN_NAME)) { schedulingService = (ISchedulingService) ctx.getBean(ISchedulingService.BEAN_NAME); } else { //try the parent schedulingService = (ISchedulingService) scope.getParent().getContext().getBean(ISchedulingService.BEAN_NAME); } IConsumerService consumerService = null; if (ctx.hasBean(IConsumerService.KEY)) { consumerService = (IConsumerService) ctx.getBean(IConsumerService.KEY); } else { //try the parent consumerService = (IConsumerService) scope.getParent().getContext().getBean(IConsumerService.KEY); } IProviderService providerService = null; if (ctx.hasBean(IProviderService.BEAN_NAME)) { providerService = (IProviderService) ctx.getBean(IProviderService.BEAN_NAME); } else { //try the parent providerService = (IProviderService) scope.getParent().getContext().getBean(IProviderService.BEAN_NAME); } engine = new PlayEngine.Builder(this, schedulingService, consumerService, providerService).build(); } else { log.info("Scope was null on start"); } } //set buffer check interval engine.setBufferCheckInterval(bufferCheckInterval); //set underrun trigger engine.setUnderrunTrigger(underrunTrigger); // Start playback engine engine.start(); // Notify subscribers on start onChange(StreamState.STARTED); } /** {@inheritDoc} */ public void play() throws IOException { // Check how many is yet to play... int count = items.size(); // Return if playlist is empty if (count == 0) { return; } // Move to next if current item is set to -1 if (currentItemIndex == -1) { moveToNext(); } // If there's some more items on list then play current item while (count-- > 0) { IPlayItem item = null; read.lock(); try { // Get playlist item item = items.get(currentItemIndex); engine.play(item); break; } catch (StreamNotFoundException e) { // go for next item moveToNext(); if (currentItemIndex == -1) { // we reaches the end. break; } item = items.get(currentItemIndex); } catch (IllegalStateException e) { // an stream is already playing break; } finally { read.unlock(); } } } /** {@inheritDoc} */ public void pause(int position) { try { engine.pause(position); } catch (IllegalStateException e) { log.debug("pause caught an IllegalStateException"); } } /** {@inheritDoc} */ public void resume(int position) { try { engine.resume(position); } catch (IllegalStateException e) { log.debug("resume caught an IllegalStateException"); } } /** {@inheritDoc} */ public void stop() { try { engine.stop(); } catch (IllegalStateException e) { log.debug("stop caught an IllegalStateException"); } } /** {@inheritDoc} */ public void seek(int position) throws OperationNotSupportedException { try { engine.seek(position); } catch (IllegalStateException e) { log.debug("seek caught an IllegalStateException"); } } /** {@inheritDoc} */ public void close() { engine.close(); onChange(StreamState.CLOSED); items.clear(); } /** {@inheritDoc} */ public boolean isPaused() { return state == StreamState.PAUSED; } /** {@inheritDoc} */ public void addItem(IPlayItem item) { write.lock(); try { items.add(item); } finally { write.unlock(); } } /** {@inheritDoc} */ public void addItem(IPlayItem item, int index) { write.lock(); try { items.add(index, item); } finally { write.unlock(); } } /** {@inheritDoc} */ public void removeItem(int index) { if (index < 0 || index >= items.size()) { return; } int originSize = items.size(); write.lock(); try { items.remove(index); } finally { write.unlock(); } if (currentItemIndex == index) { // set the next item. if (index == originSize - 1) { currentItemIndex = index - 1; } } } /** {@inheritDoc} */ public void removeAllItems() { // we try to stop the engine first stop(); write.lock(); try { items.clear(); } finally { write.unlock(); } } /** {@inheritDoc} */ public void previousItem() { stop(); moveToPrevious(); if (currentItemIndex == -1) { return; } IPlayItem item = null; int count = items.size(); while (count-- > 0) { read.lock(); try { item = items.get(currentItemIndex); engine.play(item); break; } catch (IOException err) { log.error("Error while starting to play item, moving to previous.", err); // go for next item moveToPrevious(); if (currentItemIndex == -1) { // we reaches the end. break; } } catch (StreamNotFoundException e) { // go for next item moveToPrevious(); if (currentItemIndex == -1) { // we reaches the end. break; } } catch (IllegalStateException e) { // an stream is already playing break; } finally { read.unlock(); } } } /** {@inheritDoc} */ public boolean hasMoreItems() { int nextItem = currentItemIndex + 1; if (nextItem >= items.size() && !repeat) { return false; } else { return true; } } /** {@inheritDoc} */ public void nextItem() { moveToNext(); if (currentItemIndex == -1) { return; } IPlayItem item = null; int count = items.size(); while (count-- > 0) { read.lock(); try { item = items.get(currentItemIndex); engine.play(item, false); break; } catch (IOException err) { log.error("Error while starting to play item, moving to next", err); // go for next item moveToNext(); if (currentItemIndex == -1) { // we reaches the end. break; } } catch (StreamNotFoundException e) { // go for next item moveToNext(); if (currentItemIndex == -1) { // we reaches the end. break; } } catch (IllegalStateException e) { // an stream is already playing break; } finally { read.unlock(); } } } /** {@inheritDoc} */ public void setItem(int index) { if (index < 0 || index >= items.size()) { return; } stop(); currentItemIndex = index; read.lock(); try { IPlayItem item = items.get(currentItemIndex); engine.play(item); } catch (IOException e) { log.error("setItem caught a IOException", e); } catch (StreamNotFoundException e) { // let the engine retain the STOPPED state // and wait for control from outside log.debug("setItem caught a StreamNotFoundException"); } catch (IllegalStateException e) { log.error("Illegal state exception on playlist item setup", e); } finally { read.unlock(); } } /** {@inheritDoc} */ public boolean isRandom() { return random; } /** {@inheritDoc} */ public void setRandom(boolean random) { this.random = random; } /** {@inheritDoc} */ public boolean isRewind() { return rewind; } /** {@inheritDoc} */ public void setRewind(boolean rewind) { this.rewind = rewind; } /** {@inheritDoc} */ public boolean isRepeat() { return repeat; } /** {@inheritDoc} */ public void setRepeat(boolean repeat) { this.repeat = repeat; } /** * Seek to current position to restart playback with audio and/or video. */ private void seekToCurrentPlayback() { if (engine.isPullMode()) { try { // TODO: figure out if this is the correct position to seek to final long delta = System.currentTimeMillis() - engine.getPlaybackStart(); engine.seek((int) delta); } catch (OperationNotSupportedException err) { // Ignore error, should not happen for pullMode engines } } } /** {@inheritDoc} */ public void receiveVideo(boolean receive) { boolean receiveVideo = engine.receiveVideo(receive); if (!receiveVideo && receive) { //video has been re-enabled seekToCurrentPlayback(); } } /** {@inheritDoc} */ public void receiveAudio(boolean receive) { //check if engine currently receives audio, returns previous value boolean receiveAudio = engine.receiveAudio(receive); if (receiveAudio && !receive) { //send a blank audio packet to reset the player engine.sendBlankAudio(true); } else if (!receiveAudio && receive) { //do a seek seekToCurrentPlayback(); } } /** {@inheritDoc} */ public void setPlaylistController(IPlaylistController controller) { this.controller = controller; } /** {@inheritDoc} */ public int getItemSize() { return items.size(); } /** {@inheritDoc} */ public int getCurrentItemIndex() { return currentItemIndex; } /** * {@inheritDoc} */ public IPlayItem getCurrentItem() { return getItem(getCurrentItemIndex()); } /** {@inheritDoc} */ public IPlayItem getItem(int index) { read.lock(); try { return items.get(index); } catch (IndexOutOfBoundsException e) { return null; } finally { read.unlock(); } } /** {@inheritDoc} */ public boolean replace(IPlayItem oldItem, IPlayItem newItem) { boolean result = false; read.lock(); try { int index = items.indexOf(oldItem); items.remove(index); items.set(index, newItem); result = true; } catch (Exception e) { } finally { read.unlock(); } return result; } /** * Move the current item to the next in list. */ private void moveToNext() { if (controller != null) { currentItemIndex = controller.nextItem(this, currentItemIndex); } else { currentItemIndex = defaultController.nextItem(this, currentItemIndex); } } /** * Move the current item to the previous in list. */ private void moveToPrevious() { if (controller != null) { currentItemIndex = controller.previousItem(this, currentItemIndex); } else { currentItemIndex = defaultController.previousItem(this, currentItemIndex); } } /** * {@inheritDoc} */ public void onChange(final StreamState state, final Object... changed) { Notifier notifier = null; IStreamAwareScopeHandler handler = getStreamAwareHandler(); switch (state) { case SEEK: //notifies subscribers on seek if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); //get item being played IPlayItem item = (IPlayItem) changed[0]; //seek position int position = (Integer) changed[1]; try { handler.streamPlayItemSeek(stream, item, position); } catch (Throwable t) { log.error("error notify streamPlayItemSeek", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case PAUSED: //set the paused state this.setState(StreamState.PAUSED); //notifies subscribers on pause if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); //get item being played IPlayItem item = (IPlayItem) changed[0]; //playback position int position = (Integer) changed[1]; try { handler.streamPlayItemPause(stream, item, position); } catch (Throwable t) { log.error("error notify streamPlayItemPause", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case RESUMED: //resume playing this.setState(StreamState.PLAYING); //notifies subscribers on resume if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); //get item being played IPlayItem item = (IPlayItem) changed[0]; //playback position int position = (Integer) changed[1]; try { handler.streamPlayItemResume(stream, item, position); } catch (Throwable t) { log.error("error notify streamPlayItemResume", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case PLAYING: //notifies subscribers on play if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); //get item being played IPlayItem item = (IPlayItem) changed[0]; //is it a live broadcast boolean isLive = (Boolean) changed[1]; try { handler.streamPlayItemPlay(stream, item, isLive); } catch (Throwable t) { log.error("error notify streamPlayItemPlay", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case CLOSED: //notifies subscribers on close if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); try { handler.streamSubscriberClose(stream); } catch (Throwable t) { log.error("error notify streamSubscriberClose", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case STARTED: //notifies subscribers on start if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); try { handler.streamSubscriberStart(stream); } catch (Throwable t) { log.error("error notify streamSubscriberStart", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case STOPPED: //set the stopped state this.setState(StreamState.STOPPED); //notifies subscribers on stop if (handler != null) { notifier = new Notifier(this, handler) { public void run() { //make sure those notified have the correct connection Red5.setConnectionLocal(conn); //get the item that was stopped IPlayItem item = (IPlayItem) changed[0]; try { handler.streamPlayItemStop(stream, item); } catch (Throwable t) { log.error("error notify streamPlaylistItemStop", t); } // clear thread local reference Red5.setConnectionLocal(null); } }; } break; case END: //notified by the play engine when the current item reaches the end nextItem(); break; default: //there is no "default" handling log.warn("Unhandled change: {}", state); } if (notifier != null) { IConnection conn = Red5.getConnectionLocal(); notifier.setConnection(conn); executor.execute(notifier); } } /** {@inheritDoc} */ public IPlaylistSubscriberStreamStatistics getStatistics() { return this; } /** {@inheritDoc} */ public long getCreationTime() { return creationTime; } /** {@inheritDoc} */ public int getCurrentTimestamp() { int lastMessageTs = engine.getLastMessageTimestamp(); if (lastMessageTs >= 0) { return 0; } return lastMessageTs; } /** {@inheritDoc} */ public long getBytesSent() { return bytesSent; } /** {@inheritDoc} */ public double getEstimatedBufferFill() { // check to see if any messages have been sent int lastMessageTs = engine.getLastMessageTimestamp(); if (lastMessageTs < 0) { // nothing has been sent yet return 0.0; } // buffer size as requested by the client final long buffer = getClientBufferDuration(); if (buffer == 0) { return 100.0; } // duration the stream is playing final long delta = System.currentTimeMillis() - engine.getPlaybackStart(); // expected amount of data present in client buffer final long buffered = lastMessageTs - delta; return (buffered * 100.0) / buffer; } /** * Handles notifications in a separate thread. */ public class Notifier implements Runnable { IPlaylistSubscriberStream stream; IStreamAwareScopeHandler handler; IConnection conn; public Notifier(IPlaylistSubscriberStream stream, IStreamAwareScopeHandler handler) { log.trace("Notifier - stream: {} handler: {}", stream, handler); this.stream = stream; this.handler = handler; } public void setConnection(IConnection conn) { this.conn = conn; } public void run() { } } } red5-1.0~svn4374.orig/src/org/red5/server/stream/IStreamTypeAwareProvider.java0000644000175000017500000000231611706617130027101 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import org.red5.server.messaging.IProvider; /** * Interface for providers that know if they contain video frames. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * */ public interface IStreamTypeAwareProvider extends IProvider { public static final String KEY = IStreamTypeAwareProvider.class.getName(); /** * Check if the provider contains video tags. * * @return provider has video */ public boolean hasVideo(); } red5-1.0~svn4374.orig/src/org/red5/server/stream/AudioCodecFactory.java0000644000175000017500000000574411706617130025537 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.util.ArrayList; import java.util.List; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.stream.IAudioStreamCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Factory for audio codecs. Creates and returns audio codecs * * @author The Red5 Project (red5@osflash.org) * @author Vladimir Hmelyoff (vlhm@splitmedialabs.com) */ public class AudioCodecFactory { /** * Object key */ public static final String KEY = "audioCodecFactory"; /** * Logger for audio factory */ private static Logger log = LoggerFactory.getLogger(AudioCodecFactory.class); /** * List of available codecs */ private static List codecs = new ArrayList(1); /** * Setter for codecs * * @param codecs List of codecs */ public void setCodecs(List codecs) { AudioCodecFactory.codecs = codecs; } /** * Create and return new audio codec applicable for byte buffer data * @param data Byte buffer data * @return audio codec */ public static IAudioStreamCodec getAudioCodec(IoBuffer data) { IAudioStreamCodec result = null; //get the codec identifying byte int codecId = (data.get() & 0xf0) >> 4; try { switch (codecId) { case 10: //aac result = (IAudioStreamCodec) Class.forName("org.red5.server.stream.codec.AACAudio").newInstance(); break; } } catch (Exception ex) { log.error("Error creating codec instance", ex); } data.rewind(); //if codec is not found do the old-style loop if (result == null) { for (IAudioStreamCodec storedCodec: codecs) { IAudioStreamCodec codec; // XXX: this is a bit of a hack to create new instances of the // configured audio codec for each stream try { codec = storedCodec.getClass().newInstance(); } catch (Exception e) { log.error("Could not create audio codec instance", e); continue; } if (codec.canHandleData(data)) { result = codec; break; } } } return result; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/message/0000755000175000017500000000000011760512571022762 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/stream/message/StatusMessage.java0000644000175000017500000000241511706617130026414 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.message; import org.red5.server.messaging.AbstractMessage; import org.red5.server.net.rtmp.status.Status; public class StatusMessage extends AbstractMessage { private Status body; /** * Getter for property 'body'. * * @return Value for property 'body'. */ public Status getBody() { return body; } /** * Setter for property 'body'. * * @param body Value to set for property 'body'. */ public void setBody(Status body) { this.body = body; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/message/RTMPMessage.java0000644000175000017500000000454311706617130025717 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.message; import org.red5.server.messaging.AbstractMessage; import org.red5.server.net.rtmp.event.IRTMPEvent; /** * RTMP message */ public class RTMPMessage extends AbstractMessage { private final IRTMPEvent body; /** * Creates a new rtmp message. * * @param body value to set for property 'body' */ private RTMPMessage(IRTMPEvent body) { this.body = body; } /** * Creates a new rtmp message. * * @param body value to set for property 'body' * @param eventTime updated timestamp */ private RTMPMessage(IRTMPEvent body, int eventTime) { this.body = body; this.body.setTimestamp(eventTime); } /** * Return RTMP message body * * @return Value for property 'body'. */ public IRTMPEvent getBody() { return body; } /** * Builder for RTMPMessage. * * @param body event data * @return Immutable RTMPMessage */ public final static RTMPMessage build(IRTMPEvent body) { return new RTMPMessage(body); } /** * Builder for RTMPMessage. * * @param body event data * @param eventTime time value to set on the event body * @return Immutable RTMPMessage */ public final static RTMPMessage build(IRTMPEvent body, int eventTime) { return new RTMPMessage(body, eventTime); } /** * Builder for RTMPMessage. * * @param body event data * @param sourceType live or vod * @return Immutable RTMPMessage */ public final static RTMPMessage build(IRTMPEvent body, byte sourceType) { RTMPMessage msg = new RTMPMessage(body); msg.body.setSourceType(sourceType); return msg; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/message/ResetMessage.java0000644000175000017500000000203211706617130026206 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.message; import org.red5.server.messaging.AbstractMessage; /** * To notify the client to reset the playing state. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public class ResetMessage extends AbstractMessage { } red5-1.0~svn4374.orig/src/org/red5/server/stream/ITokenBucket.java0000644000175000017500000000767311706617130024542 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; /** * Basically token bucket is used to control the bandwidth used by a stream or a connection or a client. * There's a background thread that distributes tokens to the buckets in the system according * to the configuration of the bucket. The configuration includes how fast the tokens are distributed. * When a stream, for example, needs to send out a packet, the packet's byte count is calculated and * each byte corresponds to a token in the bucket. The stream is assigned a bucket and the tokens in * the bucket are acquired before the packet can be sent out. So if the speed(or bandwidth) in * configuration is low, the stream can't send out packets fast. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface ITokenBucket { /** * Acquire tokens amount of tokenCount * waiting wait milliseconds if token not available. * @param tokenCount The count of tokens to acquire. * @param wait Milliseconds to wait. 0 means no wait * and any value below zero means wait forever. * @return true if successfully acquired or false * if not acquired. */ boolean acquireToken(long tokenCount, long wait); /** * Nonblockingly acquire token. If the token is not available and * task is not null, the callback will be executed when the token * is available. The tokens are not consumed automatically before callback, * so it's recommended to acquire token again in callback function. * * @param tokenCount Number of tokens * @param callback Callback * @return true if successfully acquired or false * if not acquired. */ boolean acquireTokenNonblocking(long tokenCount, ITokenBucketCallback callback); /** * Nonblockingly acquire token. The upper limit is specified. If * not enough tokens are left in bucket, all remaining will be * returned. * @param upperLimitCount Upper limit of aquisition * @return Remaining tokens from bucket */ long acquireTokenBestEffort(long upperLimitCount); /** * Get the capacity of this bucket in Byte. * * @return Capacity of this bucket in bytes */ long getCapacity(); /** * The amount of tokens increased per millisecond. * * @return Amount of tokens increased per millisecond. */ double getSpeed(); /** * Reset this token bucket. All pending threads are woken up with false * returned for acquiring token and callback is removed without calling back. */ void reset(); /** * Callback for tocket bucket */ public interface ITokenBucketCallback { /** * Being called when the tokens requested are available. * @param bucket Bucket * @param tokenCount Number of tokens */ void available(ITokenBucket bucket, long tokenCount); /** * Resets tokens in bucket * @param bucket Bucket * @param tokenCount Number of tokens */ void reset(ITokenBucket bucket, long tokenCount); } } red5-1.0~svn4374.orig/src/org/red5/server/stream/VideoFrameDropper.java0000644000175000017500000001165211706617130025560 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.net.rtmp.event.VideoData.FrameType; import org.red5.server.stream.message.RTMPMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * State machine for video frame dropping in live streams. *

* We start sending all frame types. Disposable interframes can be dropped any * time without affecting the current state. If a regular interframe is dropped, * all future frames up to the next keyframes are dropped as well. Dropped * keyframes result in only keyframes being sent. If two consecutive keyframes * have been successfully sent, regular interframes will be sent in the next * iteration as well. If these frames all went through, disposable interframes * are sent again. * *

* So from highest to lowest bandwidth and back, the states go as follows: *

    *
  • all frames
  • *
  • keyframes and interframes
  • *
  • keyframes
  • *
  • keyframes and interframes
  • *
  • all frames
  • *
* * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class VideoFrameDropper implements IFrameDropper { protected static Logger log = LoggerFactory.getLogger(VideoFrameDropper.class.getName()); /** Current state. */ private int state; /** Constructs a new VideoFrameDropper. */ public VideoFrameDropper() { reset(); } /** {@inheritDoc} */ public void reset() { reset(SEND_ALL); } /** {@inheritDoc} */ public void reset(int state) { this.state = state; } /** {@inheritDoc} */ public boolean canSendPacket(RTMPMessage message, long pending) { IRTMPEvent packet = message.getBody(); boolean result = true; // We currently only drop video packets. if (packet instanceof VideoData) { VideoData video = (VideoData) packet; FrameType type = video.getFrameType(); switch (state) { case SEND_ALL: // All packets will be sent break; case SEND_INTERFRAMES: // Only keyframes and interframes will be sent. if (type == FrameType.KEYFRAME) { if (pending == 0) { // Send all frames from now on. state = SEND_ALL; } } else if (type == FrameType.INTERFRAME) { } break; case SEND_KEYFRAMES: // Only keyframes will be sent. result = (type == FrameType.KEYFRAME); if (result && pending == 0) { // Maybe switch back to SEND_INTERFRAMES after the next keyframe state = SEND_KEYFRAMES_CHECK; } break; case SEND_KEYFRAMES_CHECK: // Only keyframes will be sent. result = (type == FrameType.KEYFRAME); if (result && pending == 0) { // Continue with sending interframes as well state = SEND_INTERFRAMES; } break; default: } } return result; } /** {@inheritDoc} */ public void dropPacket(RTMPMessage message) { IRTMPEvent packet = message.getBody(); // Only check video packets. if (packet instanceof VideoData) { VideoData video = (VideoData) packet; FrameType type = video.getFrameType(); switch (state) { case SEND_ALL: if (type == FrameType.DISPOSABLE_INTERFRAME) { // Remain in state, packet is safe to drop. return; } else if (type == FrameType.INTERFRAME) { // Drop all frames until the next keyframe. state = SEND_KEYFRAMES; return; } else if (type == FrameType.KEYFRAME) { // Drop all frames until the next keyframe. state = SEND_KEYFRAMES; return; } break; case SEND_INTERFRAMES: if (type == FrameType.INTERFRAME) { // Drop all frames until the next keyframe. state = SEND_KEYFRAMES_CHECK; return; } else if (type == FrameType.KEYFRAME) { // Drop all frames until the next keyframe. state = SEND_KEYFRAMES; return; } break; case SEND_KEYFRAMES: // Remain in state. break; case SEND_KEYFRAMES_CHECK: if (type == FrameType.KEYFRAME) { // Switch back to sending keyframes, but don't move to // SEND_INTERFRAMES afterwards. state = SEND_KEYFRAMES; return; } break; default: } } } /** {@inheritDoc} */ public void sendPacket(RTMPMessage message) { } } red5-1.0~svn4374.orig/src/org/red5/server/stream/AbstractClientStream.java0000644000175000017500000000672111754746347026302 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.lang.ref.WeakReference; import java.util.concurrent.Semaphore; import org.red5.server.api.stream.IClientStream; import org.red5.server.api.stream.IStreamCapableConnection; import org.red5.server.api.stream.StreamState; /** * Abstract base for client streams */ public abstract class AbstractClientStream extends AbstractStream implements IClientStream { /** * Stream identifier. Unique across server. */ private int streamId; /** * Stream name of the broadcasting stream. */ private String broadcastStreamPublishName; /** * Connection that works with streams */ private WeakReference conn; /** * Buffer duration in ms as requested by the client */ private int clientBufferDuration; /** * Lock for protecting critical sections */ private final Semaphore lock = new Semaphore(1, true); /** * Setter for stream id * @param streamId Stream id */ public void setStreamId(int streamId) { this.streamId = streamId; } /** * Return stream id * @return Stream id */ public int getStreamId() { return streamId; } /** * Setter for stream capable connection * @param conn IStreamCapableConnection object */ public void setConnection(IStreamCapableConnection conn) { this.conn = new WeakReference(conn); } /** * Return connection associated with stream * @return Stream capable connection object */ public IStreamCapableConnection getConnection() { return conn.get(); } /** * Return stream state * @return StreamState */ public StreamState getState() { try { lock.acquireUninterruptibly(); return state; } finally { lock.release(); } } /** * Sets the stream state * @param state */ public void setState(StreamState state) { if (!this.state.equals(state)) { try { lock.acquireUninterruptibly(); this.state = state; } finally { lock.release(); } } } /** {@inheritDoc} */ public void setClientBufferDuration(int duration) { clientBufferDuration = duration; } /** * Get duration in ms as requested by the client. * * @return value */ public int getClientBufferDuration() { return clientBufferDuration; } /** * Sets the broadcasting streams name. * * @param broadcastStreamPublishName name of the broadcasting stream */ public void setBroadcastStreamPublishName(String broadcastStreamPublishName) { this.broadcastStreamPublishName = broadcastStreamPublishName; } /** {@inheritDoc} */ public String getBroadcastStreamPublishName() { return broadcastStreamPublishName; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/ITokenBucketService.java0000644000175000017500000000261611706617130026053 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; /** * A service used to create and manage token buckets. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface ITokenBucketService { public static final String KEY = "TokenBucketService"; /** * Create a token bucket. * @param capacity Capacity of the bucket. * @param speed Speed of the bucket. Bytes per millisecond. * @return null if fail to create. */ ITokenBucket createTokenBucket(long capacity, long speed); /** * Remove this bucket. * * @param bucket Bucket to remove */ void removeTokenBucket(ITokenBucket bucket); } red5-1.0~svn4374.orig/src/org/red5/server/stream/ConsumerService.java0000644000175000017500000000363511706617130025321 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import org.red5.server.api.stream.IClientStream; import org.red5.server.api.stream.IStreamCapableConnection; import org.red5.server.messaging.IMessageOutput; import org.red5.server.messaging.IPipe; import org.red5.server.messaging.InMemoryPushPushPipe; import org.red5.server.net.rtmp.RTMPConnection; import org.red5.server.stream.consumer.ConnectionConsumer; /** * Basic consumer service implementation. Used to get pushed messages at consumer endpoint. */ public class ConsumerService implements IConsumerService { /** {@inheritDoc} */ public IMessageOutput getConsumerOutput(IClientStream stream) { IStreamCapableConnection streamConn = stream.getConnection(); if (streamConn == null || !(streamConn instanceof RTMPConnection)) { return null; } RTMPConnection conn = (RTMPConnection) streamConn; // TODO Better manage channels. // now we use OutputStream as a channel wrapper. OutputStream o = conn.createOutputStream(stream.getStreamId()); IPipe pipe = new InMemoryPushPushPipe(); pipe.subscribe(new ConnectionConsumer(conn, o.getVideo().getId(), o.getAudio().getId(), o.getData().getId()), null); return pipe; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/VideoCodecFactory.java0000644000175000017500000000737511706617130025546 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.util.ArrayList; import java.util.List; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.stream.IVideoStreamCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Factory for video codecs. Creates and returns video codecs * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class VideoCodecFactory { /** * Object key */ public static final String KEY = "videoCodecFactory"; /** * Logger for video factory */ private static Logger log = LoggerFactory.getLogger(VideoCodecFactory.class); /** * List of available codecs */ private static List codecs = new ArrayList(3); /** * Setter for codecs * * @param codecs List of codecs */ public void setCodecs(List codecs) { VideoCodecFactory.codecs = codecs; } /** * Create and return new video codec applicable for byte buffer data * @param data Byte buffer data * @return Video codec */ public static IVideoStreamCodec getVideoCodec(IoBuffer data) { IVideoStreamCodec result = null; //get the codec identifying byte int codecId = data.get() & 0x0f; try { switch (codecId) { case 2: //sorenson result = (IVideoStreamCodec) Class.forName("org.red5.server.stream.codec.SorensonVideo").newInstance(); break; case 3: //screen video result = (IVideoStreamCodec) Class.forName("org.red5.server.stream.codec.ScreenVideo").newInstance(); break; case 6: //screen video 2 result = (IVideoStreamCodec) Class.forName("org.red5.server.stream.codec.ScreenVideo2").newInstance(); break; case 7: //avc/h.264 video result = (IVideoStreamCodec) Class.forName("org.red5.server.stream.codec.AVCVideo").newInstance(); break; } } catch (Exception ex) { log.error("Error creating codec instance", ex); } data.rewind(); //if codec is not found do the old-style loop if (result == null) { for (IVideoStreamCodec storedCodec: codecs) { IVideoStreamCodec codec; // XXX: this is a bit of a hack to create new instances of the // configured video codec for each stream try { codec = storedCodec.getClass().newInstance(); } catch (Exception e) { log.error("Could not create video codec instance", e); continue; } if (codec.canHandleData(data)) { result = codec; break; } } } return result; } // private boolean isScreenVideo(byte first) { // log.debug("Trying ScreenVideo"); // boolean result = ((first & 0x0f) == 3); // return result; // } // // private boolean isSorenson(byte first) { // log.debug("Trying Sorenson"); // boolean result = ((first & 0x0f) == 2); // return result; // } } red5-1.0~svn4374.orig/src/org/red5/server/stream/ISeekableProvider.java0000644000175000017500000000217711706617130025544 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import org.red5.server.messaging.IProvider; /** * Provider that is seekable */ public interface ISeekableProvider extends IProvider { public static final String KEY = ISeekableProvider.class.getName(); /** * Seek the provider to timestamp ts (in milliseconds). * @param ts Timestamp to seek to * @return Actual timestamp seeked to */ int seek(int ts); } red5-1.0~svn4374.orig/src/org/red5/server/stream/RtmpSampleAccess.java0000644000175000017500000000365511747114732025422 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IRtmpSampleAccess; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Default RtmpSampleAccess bean * @see org.red5.server.api.stream.IRtmpSampleAccess */ public class RtmpSampleAccess implements IRtmpSampleAccess { private static Logger logger = LoggerFactory.getLogger(RtmpSampleAccess.class); private boolean audioAllowed = false; private boolean videoAllowed = false; /** * Setter audioAllowed * @param permission */ public void setAudioAllowed(boolean permission) { logger.debug("setAudioAllowed: {}", permission); audioAllowed = permission; } /** * Setter videoAllowed * @param permission */ public void setVideoAllowed(boolean permission) { logger.debug("setVideoAllowed: {}", permission); videoAllowed = permission; } /** {@inheritDoc} */ public boolean isAudioAllowed(IScope scope) { logger.debug("isAudioAllowed: {}", audioAllowed); return audioAllowed; } /** {@inheritDoc} */ public boolean isVideoAllowed(IScope scope) { logger.debug("isVideoAllowed: {}", videoAllowed); return videoAllowed; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/ServerStream.java0000644000175000017500000005522011747114732024631 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import org.red5.server.api.scheduling.IScheduledJob; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IPlayItem; import org.red5.server.api.stream.IPlaylistController; import org.red5.server.api.stream.IServerStream; import org.red5.server.api.stream.IStreamAwareScopeHandler; import org.red5.server.api.stream.IStreamFilenameGenerator; import org.red5.server.api.stream.IStreamFilenameGenerator.GenerationType; import org.red5.server.api.stream.IStreamListener; import org.red5.server.api.stream.IStreamPacket; import org.red5.server.api.stream.ResourceExistException; import org.red5.server.api.stream.ResourceNotFoundException; import org.red5.server.api.stream.StreamState; import org.red5.server.messaging.IFilter; import org.red5.server.messaging.IMessage; import org.red5.server.messaging.IMessageComponent; import org.red5.server.messaging.IMessageInput; import org.red5.server.messaging.IMessageOutput; import org.red5.server.messaging.IPassive; import org.red5.server.messaging.IPipe; import org.red5.server.messaging.IPipeConnectionListener; import org.red5.server.messaging.IProvider; import org.red5.server.messaging.IPushableConsumer; import org.red5.server.messaging.InMemoryPushPushPipe; import org.red5.server.messaging.OOBControlMessage; import org.red5.server.messaging.PipeConnectionEvent; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.stream.consumer.FileConsumer; import org.red5.server.stream.message.RTMPMessage; import org.red5.server.stream.message.ResetMessage; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An implementation for server side stream. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public class ServerStream extends AbstractStream implements IServerStream, IFilter, IPushableConsumer, IPipeConnectionListener { /** * Logger */ private static final Logger log = LoggerFactory.getLogger(ServerStream.class); private static final long WAIT_THRESHOLD = 0; /** * Stream published name */ protected String publishedName; /** * Actual playlist controller */ protected IPlaylistController controller; /** * Default playlist controller */ protected IPlaylistController defaultController; /** * Rewind flag state */ private boolean isRewind; /** * Random flag state */ private boolean isRandom; /** * Repeat flag state */ private boolean isRepeat; /** * List of items in this playlist */ protected CopyOnWriteArrayList items; /** * Current item index */ private int currentItemIndex; /** * Current item */ protected IPlayItem currentItem; /** * Message input */ private IMessageInput msgIn; /** * Message output */ private IMessageOutput msgOut; /** * Pipe for recording */ private IPipe recordPipe; /** * The filename we are recording to. */ protected String recordingFilename; /** * Scheduling service */ private ISchedulingService scheduler; /** * Live broadcasting scheduled job name */ private String liveJobName; /** * VOD scheduled job name */ private String vodJobName; /** * VOD start timestamp */ private long vodStartTS; /** * Server start timestamp */ private long serverStartTS; /** * Next msg's timestamp */ private long nextTS; /** * Next RTMP message */ private RTMPMessage nextRTMPMessage; /** Listeners to get notified about received packets. */ private CopyOnWriteArraySet listeners = new CopyOnWriteArraySet(); /** Constructs a new ServerStream. */ public ServerStream() { defaultController = new SimplePlaylistController(); items = new CopyOnWriteArrayList(); } /** {@inheritDoc} */ public void addItem(IPlayItem item) { items.add(item); } /** {@inheritDoc} */ public void addItem(IPlayItem item, int index) { items.add(index, item); if (index <= currentItemIndex) { // item was added before the currently playing currentItemIndex++; } } /** {@inheritDoc} */ public void removeItem(int index) { if (index < 0 || index >= items.size()) { return; } items.remove(index); if (index < currentItemIndex) { // item was removed before the currently playing currentItemIndex--; } else if (index == currentItemIndex) { // TODO: the currently playing item is removed - this should be handled differently currentItemIndex--; } } /** {@inheritDoc} */ public void removeAllItems() { items.clear(); } /** {@inheritDoc} */ public int getItemSize() { return items.size(); } /** {@inheritDoc} */ public int getCurrentItemIndex() { return currentItemIndex; } /** {@inheritDoc} */ public IPlayItem getCurrentItem() { return currentItem; } /** {@inheritDoc} */ public IPlayItem getItem(int index) { try { return items.get(index); } catch (IndexOutOfBoundsException e) { return null; } } /** {@inheritDoc} */ public void previousItem() { stop(); moveToPrevious(); if (currentItemIndex == -1) { return; } IPlayItem item = items.get(currentItemIndex); play(item); } /** {@inheritDoc} */ public boolean hasMoreItems() { int nextItem = currentItemIndex + 1; if (nextItem >= items.size() && !isRepeat) { return false; } else { return true; } } /** {@inheritDoc} */ public void nextItem() { stop(); moveToNext(); if (currentItemIndex == -1) { return; } IPlayItem item = items.get(currentItemIndex); play(item); } /** {@inheritDoc} */ public void setItem(int index) { if (index < 0 || index >= items.size()) { return; } stop(); currentItemIndex = index; IPlayItem item = items.get(currentItemIndex); play(item); } /** {@inheritDoc} */ public boolean isRandom() { return isRandom; } /** {@inheritDoc} */ public void setRandom(boolean random) { isRandom = random; } /** {@inheritDoc} */ public boolean isRewind() { return isRewind; } /** {@inheritDoc} */ public void setRewind(boolean rewind) { isRewind = rewind; } /** {@inheritDoc} */ public boolean isRepeat() { return isRepeat; } /** {@inheritDoc} */ public void setRepeat(boolean repeat) { isRepeat = repeat; } /** {@inheritDoc} */ public void setPlaylistController(IPlaylistController controller) { this.controller = controller; } /** {@inheritDoc} */ public void saveAs(String name, boolean isAppend) throws IOException, ResourceNotFoundException, ResourceExistException { try { IScope scope = getScope(); IStreamFilenameGenerator generator = (IStreamFilenameGenerator) ScopeUtils.getScopeService(scope, IStreamFilenameGenerator.class, DefaultStreamFilenameGenerator.class); String filename = generator.generateFilename(scope, name, ".flv", GenerationType.RECORD); // Get file for that filename File file; if (generator.resolvesToAbsolutePath()) { file = new File(filename); } else { file = scope.getContext().getResource(filename).getFile(); } if (!isAppend) { if (file.exists()) { // Per livedoc of FCS/FMS: // When "live" or "record" is used, // any previously recorded stream with the same stream URI is deleted. if (!file.delete()) throw new IOException("file could not be deleted"); } } else { if (!file.exists()) { // Per livedoc of FCS/FMS: // If a recorded stream at the same URI does not already exist, // "append" creates the stream as though "record" was passed. isAppend = false; } } if (!file.exists()) { // Make sure the destination directory exists String path = file.getAbsolutePath(); int slashPos = path.lastIndexOf(File.separator); if (slashPos != -1) { path = path.substring(0, slashPos); } File tmp = new File(path); if (!tmp.isDirectory()) { tmp.mkdirs(); } if (!file.canWrite()) { log.warn("File cannot be written to {}", file.getCanonicalPath()); } file.createNewFile(); } else { //remove existing meta file File meta = new File(file.getAbsolutePath() + ".meta"); if (meta.delete()) { log.debug("Meta file deleted - {}", meta.getName()); } else { log.warn("Meta file was not deleted - {}", meta.getName()); meta.deleteOnExit(); } } FileConsumer recordingFile = null; log.debug("Recording file: {}", file.getCanonicalPath()); // get instance via spring if (scope.getContext().hasBean("fileConsumer")) { recordingFile = (FileConsumer) scope.getContext().getBean("fileConsumer"); recordingFile.setScope(scope); recordingFile.setFile(file); } else { // get a new instance recordingFile = new FileConsumer(scope, file); } Map paramMap = new HashMap(); if (isAppend) { paramMap.put("mode", "append"); } else { paramMap.put("mode", "record"); } if (null == recordPipe) { recordPipe = new InMemoryPushPushPipe(); } recordPipe.subscribe(recordingFile, paramMap); recordingFilename = filename; } catch (IOException e) { log.warn("Save as exception", e); } } /** {@inheritDoc} */ public String getSaveFilename() { return recordingFilename; } /** {@inheritDoc} */ public IProvider getProvider() { return this; } /** {@inheritDoc} */ public String getPublishedName() { return publishedName; } /** {@inheritDoc} */ public void setPublishedName(String name) { publishedName = name; } /** * Start this server-side stream */ public void start() { if (state != StreamState.UNINIT) { throw new IllegalStateException("State " + state + " not valid to start"); } if (items.size() == 0) { throw new IllegalStateException("At least one item should be specified to start"); } if (publishedName == null) { throw new IllegalStateException("A published name is needed to start"); } // publish this server-side stream IProviderService providerService = (IProviderService) getScope().getContext().getBean(IProviderService.BEAN_NAME); providerService.registerBroadcastStream(getScope(), publishedName, this); Map recordParamMap = new HashMap(); recordPipe = new InMemoryPushPushPipe(); recordParamMap.put("record", null); recordPipe.subscribe((IProvider) this, recordParamMap); recordingFilename = null; scheduler = (ISchedulingService) getScope().getContext().getBean(ISchedulingService.BEAN_NAME); state = StreamState.STOPPED; currentItemIndex = -1; nextItem(); } /** * Stop this server-side stream */ public synchronized void stop() { if (state != StreamState.PLAYING && state != StreamState.PAUSED) { return; } if (liveJobName != null) { scheduler.removeScheduledJob(liveJobName); liveJobName = null; } if (vodJobName != null) { scheduler.removeScheduledJob(vodJobName); vodJobName = null; } if (msgIn != null) { msgIn.unsubscribe(this); msgIn = null; } if (nextRTMPMessage != null) { nextRTMPMessage.getBody().release(); } state = StreamState.STOPPED; } /** {@inheritDoc} */ public void pause() { if (state == StreamState.PLAYING) { state = StreamState.PAUSED; } else if (state == StreamState.PAUSED) { state = StreamState.PLAYING; vodStartTS = 0; serverStartTS = System.currentTimeMillis(); scheduleNextMessage(); } } /** {@inheritDoc} */ public void seek(int position) { if (state != StreamState.PLAYING && state != StreamState.PAUSED) { // Can't seek when stopped/closed return; } sendVODSeekCM(msgIn, position); } /** {@inheritDoc} */ public synchronized void close() { if (state == StreamState.PLAYING || state == StreamState.PAUSED) { stop(); } if (msgOut != null) { msgOut.unsubscribe(this); } recordPipe.unsubscribe((IProvider) this); notifyBroadcastClose(); state = StreamState.CLOSED; } /** {@inheritDoc} */ public void onOOBControlMessage(IMessageComponent source, IPipe pipe, OOBControlMessage oobCtrlMsg) { } /** {@inheritDoc} */ public void pushMessage(IPipe pipe, IMessage message) throws IOException { pushMessage(message); } /** * Pipe connection event handler. There are two types of pipe connection events so far, * provider push connection event and provider disconnection event. * * Pipe events handling is the most common way of working with pipes. * * @param event Pipe connection event context */ public void onPipeConnectionEvent(PipeConnectionEvent event) { switch (event.getType()) { case PipeConnectionEvent.PROVIDER_CONNECT_PUSH: if (event.getProvider() == this && (event.getParamMap() == null || !event.getParamMap().containsKey("record"))) { this.msgOut = (IMessageOutput) event.getSource(); } break; case PipeConnectionEvent.PROVIDER_DISCONNECT: if (this.msgOut == event.getSource()) { this.msgOut = null; } break; default: break; } } /** * Play a specific IPlayItem. * The strategy for now is VOD first, Live second. * Should be called in a synchronized context. * * @param item Item to play */ protected void play(IPlayItem item) { // Return if already playing if (state != StreamState.STOPPED) { return; } // Assume this is not live stream boolean isLive = false; // Get provider service from Spring bean factory IProviderService providerService = (IProviderService) getScope().getContext().getBean(IProviderService.BEAN_NAME); msgIn = providerService.getVODProviderInput(getScope(), item.getName()); if (msgIn == null) { msgIn = providerService.getLiveProviderInput(getScope(), item.getName(), true); isLive = true; } if (msgIn == null) { log.warn("ABNORMAL Can't get both VOD and Live input from providerService"); return; } state = StreamState.PLAYING; currentItem = item; sendResetMessage(); msgIn.subscribe(this, null); if (isLive) { if (item.getLength() >= 0) { liveJobName = scheduler.addScheduledOnceJob(item.getLength(), new IScheduledJob() { public void execute(ISchedulingService service) { synchronized (ServerStream.this) { if (liveJobName == null) { return; } liveJobName = null; onItemEnd(); } } }); } } else { long start = item.getStart(); if (start < 0) { start = 0; } sendVODInitCM(msgIn, (int) start); startBroadcastVOD(); } } /** * Play next item on item end */ protected void onItemEnd() { nextItem(); } /** * Push message * @param message Message */ private void pushMessage(IMessage message) throws IOException { msgOut.pushMessage(message); recordPipe.pushMessage(message); // Notify listeners about received packet if (message instanceof RTMPMessage) { final IRTMPEvent rtmpEvent = ((RTMPMessage) message).getBody(); if (rtmpEvent instanceof IStreamPacket) { for (IStreamListener listener : getStreamListeners()) { try { listener.packetReceived(this, (IStreamPacket) rtmpEvent); } catch (Exception e) { log.error("Error while notifying listener " + listener, e); } } } } } /** * Send reset message */ private void sendResetMessage() { // Send new reset message try { pushMessage(new ResetMessage()); } catch (IOException err) { log.error("Error while sending reset message.", err); } } /** * Begin VOD broadcasting */ protected void startBroadcastVOD() { nextRTMPMessage = null; vodStartTS = 0; serverStartTS = System.currentTimeMillis(); IStreamAwareScopeHandler handler = getStreamAwareHandler(); if (handler != null) { if (recordingFilename != null) { handler.streamRecordStart(this); } else { handler.streamPublishStart(this); } } notifyBroadcastStart(); scheduleNextMessage(); } /** * Notifies handler on stream broadcast stop */ protected void notifyBroadcastClose() { IStreamAwareScopeHandler handler = getStreamAwareHandler(); if (handler != null) { try { handler.streamBroadcastClose(this); } catch (Throwable t) { log.error("error notify streamBroadcastStop", t); } } } /** * Notifies handler on stream broadcast start */ protected void notifyBroadcastStart() { IStreamAwareScopeHandler handler = getStreamAwareHandler(); if (handler != null) { try { handler.streamBroadcastStart(this); } catch (Throwable t) { log.error("error notify streamBroadcastStart", t); } } } /** * Pull the next message from IMessageInput and schedule * it for push according to the timestamp. */ protected void scheduleNextMessage() { boolean first = nextRTMPMessage == null; long delta; while (true) { nextRTMPMessage = getNextRTMPMessage(); if (nextRTMPMessage == null) { onItemEnd(); return; } IRTMPEvent rtmpEvent = nextRTMPMessage.getBody(); // filter all non-AV messages if (!(rtmpEvent instanceof VideoData) && !(rtmpEvent instanceof AudioData)) { continue; } rtmpEvent = nextRTMPMessage.getBody(); nextTS = rtmpEvent.getTimestamp(); if (first) { vodStartTS = nextTS; first = false; } delta = nextTS - vodStartTS - (System.currentTimeMillis() - serverStartTS); if (delta < WAIT_THRESHOLD) { if (!doPushMessage()) { return; } if (state != StreamState.PLAYING) { // Stream is paused, don't load more messages nextRTMPMessage = null; return; } } else { break; } } vodJobName = scheduler.addScheduledOnceJob(delta, new IScheduledJob() { /** {@inheritDoc} */ public void execute(ISchedulingService service) { synchronized (ServerStream.this) { if (vodJobName == null) { return; } vodJobName = null; if (!doPushMessage()) { return; } if (state == StreamState.PLAYING) { scheduleNextMessage(); } else { // Stream is paused, don't load more messages nextRTMPMessage = null; } } } }); } private boolean doPushMessage() { boolean sent = false; long start = currentItem.getStart(); if (start < 0) { start = 0; } if (currentItem.getLength() >= 0 && nextTS - start > currentItem.getLength()) { onItemEnd(); return sent; } if (nextRTMPMessage != null) { sent = true; try { pushMessage(nextRTMPMessage); } catch (IOException err) { log.error("Error while sending message.", err); } nextRTMPMessage.getBody().release(); } return sent; } /** * Getter for next RTMP message. * * @return Next RTMP message */ protected RTMPMessage getNextRTMPMessage() { IMessage message; do { // Pull message from message input object... try { message = msgIn.pullMessage(); } catch (IOException err) { log.error("Error while pulling message.", err); message = null; } // If message is null then return null if (message == null) { return null; } } while (!(message instanceof RTMPMessage)); // Cast and return return (RTMPMessage) message; } /** * Send VOD initialization control message * @param msgIn Message input * @param start Start timestamp */ private void sendVODInitCM(IMessageInput msgIn, int start) { // Create new out-of-band control message OOBControlMessage oobCtrlMsg = new OOBControlMessage(); // Set passive type oobCtrlMsg.setTarget(IPassive.KEY); // Set service name of init oobCtrlMsg.setServiceName("init"); // Create map for parameters Map paramMap = new HashMap(1); // Put start timestamp into Map of params paramMap.put("startTS", start); // Attach to OOB control message and send it oobCtrlMsg.setServiceParamMap(paramMap); msgIn.sendOOBControlMessage(this, oobCtrlMsg); } /** * Send VOD seek control message * * @param msgIn Message input * @param position New timestamp to play from */ private void sendVODSeekCM(IMessageInput msgIn, int position) { OOBControlMessage oobCtrlMsg = new OOBControlMessage(); oobCtrlMsg.setTarget(ISeekableProvider.KEY); oobCtrlMsg.setServiceName("seek"); Map paramMap = new HashMap(1); paramMap.put("position", Integer.valueOf(position)); oobCtrlMsg.setServiceParamMap(paramMap); msgIn.sendOOBControlMessage(this, oobCtrlMsg); synchronized (this) { // Reset properties vodStartTS = 0; serverStartTS = System.currentTimeMillis(); if (nextRTMPMessage != null) { try { pushMessage(nextRTMPMessage); } catch (IOException err) { log.error("Error while sending message.", err); } nextRTMPMessage.getBody().release(); nextRTMPMessage = null; } ResetMessage reset = new ResetMessage(); try { pushMessage(reset); } catch (IOException err) { log.error("Error while sending message.", err); } scheduleNextMessage(); } } /** * Move to the next item updating the currentItemIndex. * Should be called in synchronized context. */ protected void moveToNext() { if (currentItemIndex >= items.size()) { currentItemIndex = items.size() - 1; } if (controller != null) { currentItemIndex = controller.nextItem(this, currentItemIndex); } else { currentItemIndex = defaultController.nextItem(this, currentItemIndex); } } /** * Move to the previous item updating the currentItemIndex. * Should be called in synchronized context. */ protected void moveToPrevious() { if (currentItemIndex >= items.size()) { currentItemIndex = items.size() - 1; } if (controller != null) { currentItemIndex = controller.previousItem(this, currentItemIndex); } else { currentItemIndex = defaultController.previousItem(this, currentItemIndex); } } public void addStreamListener(IStreamListener listener) { listeners.add(listener); } public Collection getStreamListeners() { return listeners; } public void removeStreamListener(IStreamListener listener) { listeners.remove(listener); } } red5-1.0~svn4374.orig/src/org/red5/server/stream/bandwidth/0000755000175000017500000000000011760512571023302 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/stream/bandwidth/ClientServerDetection.java0000644000175000017500000000424411706617130030412 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.bandwidth; import java.util.HashMap; import java.util.Map; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.api.service.IPendingServiceCallback; import org.red5.server.api.stream.IStreamCapableConnection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author The Red5 Project (red5@osflash.org) * @author Dan Rossi */ public class ClientServerDetection implements IPendingServiceCallback { protected static Logger log = LoggerFactory.getLogger(ClientServerDetection.class); /** * Handle callback from service call. */ public void resultReceived(IPendingServiceCall call) { } private IStreamCapableConnection getStats() { IConnection conn = Red5.getConnectionLocal(); if (conn instanceof IStreamCapableConnection) { return (IStreamCapableConnection) conn; } return null; } public Map checkBandwidth(Object[] params) { final IStreamCapableConnection stats = getStats(); Map statsValues = new HashMap(); Integer time = (Integer) (params.length > 0 ? params[0] : 0); statsValues.put("cOutBytes", stats.getReadBytes()); statsValues.put("cInBytes", stats.getWrittenBytes()); statsValues.put("time", time); log.debug("cOutBytes: {} cInBytes: {} time: {}", new Object[] { stats.getReadBytes(), stats.getWrittenBytes(), time }); return statsValues; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/bandwidth/ServerClientDetection.java0000644000175000017500000001506211706617130030412 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.bandwidth; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.api.service.IPendingServiceCallback; import org.red5.server.api.service.IServiceCapableConnection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Calculates the bandwidth between the client and server. The checks originate from the server. * * @see FMS 3.5 Bandwidth Doc * * @author The Red5 Project (red5@osflash.org) * @author Dan Rossi * @author Paul Gregoire */ public class ServerClientDetection implements IPendingServiceCallback, IBandwidthDetection { private static Logger log = LoggerFactory.getLogger(ServerClientDetection.class); // maximum latency alloted for in milliseconds private static final double LATENCY_MAX = 1000d; // minimum latency alloted for in milliseconds private static final double LATENCY_MIN = 10d; private IConnection conn; private volatile double latency; private volatile double cumLatency = 1; private double kbitDown; private double deltaDown; private double deltaTime; // current bytes written on the connection private long startBytesWritten; // start time using nanos private long startTime; // time passed overall private long timePassed; private AtomicInteger packetsSent = new AtomicInteger(0); private AtomicInteger packetsReceived = new AtomicInteger(0); private byte[] payload = new byte[1024]; private byte[] payload1 = new byte[1024 * 32]; public void checkBandwidth(IConnection conn) { calculateClientBw(conn); } public void calculateClientBw(IConnection conn) { log.debug("calculateClientBw: {} ", conn); // set local connection ref this.conn = conn; // get random generator Random rnd = new Random(); rnd.nextBytes(payload); rnd.nextBytes(payload1); // get the current bytes written on the connection startBytesWritten = conn.getWrittenBytes(); // start time using nanos startTime = System.nanoTime(); log.debug("Starting bandwidth check at {} ns", startTime); callBWCheck(""); } /** * Handle callback from service call. */ public void resultReceived(IPendingServiceCall call) { // receive time using nanos long now = System.nanoTime(); // increment received int received = packetsReceived.incrementAndGet(); log.debug("Call time stamps - write: {} read: {}", call.getWriteTime(), call.getReadTime()); // time passed is in milliseconds timePassed = (now - startTime) / 1000000; log.debug("Received count: {} sent: {} timePassed: {} ms", new Object[] { received, packetsSent.get(), timePassed }); switch (received) { case 1: // first packet is used to test latency latency = Math.max(Math.min(timePassed, LATENCY_MAX), LATENCY_MIN); log.debug("Receive latency: {}", latency); // We now have a latency figure so can start sending test data. // Second call. 1st packet sent log.debug("Sending first payload at {} ns", now); callBWCheck(payload); // 1k break; case 2: log.debug("Sending second payload at {} ns", now); // increment cumulative latency cumLatency++; callBWCheck(payload1); // 32k break; default: log.debug("Doing calculations at {} ns", now); // increment cumulative latency cumLatency++; // bytes to kbits deltaDown = ((conn.getWrittenBytes() - startBytesWritten) * 8) / 1000d; log.debug("Delta kbits: {}", deltaDown); // total dl time - latency for each packet sent in secs deltaTime = (timePassed - (latency * cumLatency)); if (deltaTime <= 0) { deltaTime = (timePassed + latency); } log.debug("Delta time: {} ms", deltaTime); // calculate kbit/s kbitDown = Math.round(deltaDown / (deltaTime / 1000d)); log.debug("onBWDone: kbitDown: {} deltaDown: {} deltaTime: {} latency: {} ", new Object[] { kbitDown, deltaDown, deltaTime, latency }); callBWDone(); } } private void callBWCheck(Object payload) { if (log.isTraceEnabled()) { log.trace("callBWCheck: {} ", payload); } else { log.debug("callBWCheck"); } IConnection conn = Red5.getConnectionLocal(); Map statsValues = new HashMap(); statsValues.put("count", packetsReceived.get()); statsValues.put("sent", packetsSent.get()); statsValues.put("timePassed", timePassed); statsValues.put("latency", latency); statsValues.put("cumLatency", cumLatency); statsValues.put("payload", payload); if (conn instanceof IServiceCapableConnection) { log.debug("Invoking onBWCheck on the client"); // increment sent counter packetsSent.incrementAndGet(); // invoke on the client ((IServiceCapableConnection) conn).invoke("onBWCheck", new Object[] { statsValues }, this); } } private void callBWDone() { log.debug("callBWDone"); IConnection conn = Red5.getConnectionLocal(); Map statsValues = new HashMap(); statsValues.put("kbitDown", kbitDown); statsValues.put("deltaDown", deltaDown); statsValues.put("deltaTime", deltaTime); statsValues.put("latency", latency); if (conn instanceof IServiceCapableConnection) { log.debug("Invoking onBWDone on the client"); // invoke on the client ((IServiceCapableConnection) conn).invoke("onBWDone", new Object[] { statsValues }); // adjust bandwidth to mbit/s int mbits = (int) ((kbitDown / 1000d) * 1000000); log.debug("Setting bandwidth to {} mbit/s", mbits); // tell the flash player how fast we want data and how fast we shall send it conn.setBandwidth(mbits); } } public void onServerClientBWCheck() { log.debug("onServerClientBWCheck"); calculateClientBw(Red5.getConnectionLocal()); } } red5-1.0~svn4374.orig/src/org/red5/server/stream/bandwidth/IBandwidthDetection.java0000644000175000017500000000177411706617130030027 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.bandwidth; import org.red5.server.api.IConnection; /** * * @author The Red5 Project (red5@osflash.org) * @author Dan Rossi */ public interface IBandwidthDetection { public void checkBandwidth(IConnection conn); public void calculateClientBw(IConnection conn); }red5-1.0~svn4374.orig/src/org/red5/server/stream/IStreamSource.java0000644000175000017500000000242211706617130024723 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import org.red5.server.api.event.IEvent; /** * Source for streams */ public interface IStreamSource { /** * Is there something more to stream? * @return true if there's streamable data, false otherwise */ public abstract boolean hasMore(); /** * Double ended queue of event objects * @return Event from queue */ public abstract IEvent dequeue(); /** * Close stream source */ public abstract void close(); } red5-1.0~svn4374.orig/src/org/red5/server/stream/PlayBuffer.java0000644000175000017500000000706711706617130024247 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.util.LinkedList; import java.util.Queue; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.stream.message.RTMPMessage; /** * A Play buffer for sending VOD. * The implementation is not synchronized. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public class PlayBuffer { /** * Buffer capacity */ private long capacity; /** * Message size */ private long messageSize; /** * Queue of RTMP messages */ private Queue messageQueue = new LinkedList(); /** * Create play buffer with given capacity * @param capacity Capacity of buffer */ public PlayBuffer(long capacity) { this.capacity = capacity; } /** * Buffer capacity in bytes. * * @return Buffer capacity in bytes */ public long getCapacity() { return capacity; } /** * Setter for capacity * * @param capacity New capacity */ public void setCapacity(long capacity) { this.capacity = capacity; } /** * Number of messages in buffer. * * @return Number of messages in buffer */ public int getMessageCount() { return messageQueue.size(); } /** * Total message size in bytes. * * @return Total message size in bytes */ public long getMessageSize() { return messageSize; } /** * Put a message into this buffer. * * @param message RTMP message * @return true indicates success and false * indicates buffer is full. */ public boolean putMessage(RTMPMessage message) { IRTMPEvent body = message.getBody(); if (!(body instanceof IStreamData)) { throw new RuntimeException("Expected IStreamData but got " + body); } int size = ((IStreamData) body).getData().limit(); if (messageSize + size > capacity) { return false; } messageSize += size; messageQueue.offer(message); return true; } /** * Take a message from this buffer. The message count decreases. * * @return null if buffer is empty. */ public RTMPMessage takeMessage() { RTMPMessage message = messageQueue.poll(); if (message != null) { IRTMPEvent body = message.getBody(); if (!(body instanceof IStreamData)) { throw new RuntimeException("Expected IStreamData but got " + body); } messageSize -= ((IStreamData) body).getData().limit(); } return message; } /** * Peek a message but not take it from the buffer. The message count * doesn't change. * @return null if buffer is empty. */ public RTMPMessage peekMessage() { return messageQueue.peek(); } /** * Empty this buffer. */ public void clear() { messageQueue.clear(); messageSize = 0; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/FileStreamSource.java0000644000175000017500000000715311706617130025420 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import org.red5.io.ITag; import org.red5.io.ITagReader; import org.red5.io.flv.IKeyFrameDataAnalyzer; import org.red5.io.flv.IKeyFrameDataAnalyzer.KeyFrameMeta; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.Invoke; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.Unknown; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.net.rtmp.message.Constants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Represents stream source that is file */ public class FileStreamSource implements ISeekableStreamSource, Constants { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(FileStreamSource.class); /** * Tag reader */ private ITagReader reader; /** * Key frame metadata */ private KeyFrameMeta keyFrameMeta; /** * Creates file stream source with tag reader * @param reader Tag reader */ public FileStreamSource(ITagReader reader) { this.reader = reader; } /** * Closes tag reader */ public void close() { reader.close(); } /** * Get tag from queue and convert to message * @return RTMP event */ public IRTMPEvent dequeue() { if (!reader.hasMoreTags()) { return null; } ITag tag = reader.readTag(); IRTMPEvent msg; switch (tag.getDataType()) { case TYPE_AUDIO_DATA: msg = new AudioData(tag.getBody()); break; case TYPE_VIDEO_DATA: msg = new VideoData(tag.getBody()); break; case TYPE_INVOKE: msg = new Invoke(tag.getBody()); break; case TYPE_NOTIFY: msg = new Notify(tag.getBody()); break; default: log.warn("Unexpected type? {}", tag.getDataType()); msg = new Unknown(tag.getDataType(), tag.getBody()); break; } msg.setTimestamp(tag.getTimestamp()); //msg.setSealed(true); return msg; } /** {@inheritDoc} */ public boolean hasMore() { return reader.hasMoreTags(); } /** {@inheritDoc} */ public synchronized int seek(int ts) { log.trace("Seek ts: {}", ts); if (keyFrameMeta == null) { if (!(reader instanceof IKeyFrameDataAnalyzer)) { // Seeking not supported return ts; } keyFrameMeta = ((IKeyFrameDataAnalyzer) reader).analyzeKeyFrames(); } if (keyFrameMeta.positions.length == 0) { // no video keyframe metainfo, it's an audio-only FLV // we skip the seek for now. // TODO add audio-seek capability return ts; } int frame = 0; for (int i = 0; i < keyFrameMeta.positions.length; i++) { if (keyFrameMeta.timestamps[i] > ts) { break; } frame = i; } reader.position(keyFrameMeta.positions[frame]); return keyFrameMeta.timestamps[frame]; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/IConsumerService.java0000644000175000017500000000236611706617130025432 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import org.red5.server.api.stream.IClientStream; import org.red5.server.messaging.IMessageOutput; /** * Service for consumer objects, used to get pushed messages at consumer endpoint. */ public interface IConsumerService { public static final String KEY = "consumerService"; /** * Handles pushed messages * * @param stream Client stream object * @return Message object */ IMessageOutput getConsumerOutput(IClientStream stream); } red5-1.0~svn4374.orig/src/org/red5/server/stream/StreamNotFoundException.java0000644000175000017500000000203311706617130026763 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; /** * Throw when stream can't be found */ public class StreamNotFoundException extends Exception { private static final long serialVersionUID = 812106823615971891L; public StreamNotFoundException(String name) { super(String.format("Stream %s not found", name)); } }red5-1.0~svn4374.orig/src/org/red5/server/stream/filter/0000755000175000017500000000000011760512571022623 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/stream/filter/StreamBandwidthController.java0000644000175000017500000000716511706617130030620 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.filter; import org.red5.server.messaging.IFilter; import org.red5.server.messaging.IMessage; import org.red5.server.messaging.IMessageComponent; import org.red5.server.messaging.IPipe; import org.red5.server.messaging.IPipeConnectionListener; import org.red5.server.messaging.OOBControlMessage; import org.red5.server.messaging.PipeConnectionEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Controls stream bandwidth */ public class StreamBandwidthController implements IFilter, IPipeConnectionListener, Runnable { /** * Logger */ private static final Logger log = LoggerFactory.getLogger(StreamBandwidthController.class); /** * Class name */ public static final String KEY = StreamBandwidthController.class.getName(); /** * Stream provider pipe */ private IPipe providerPipe; /** * Stream consumer pipe */ private IPipe consumerPipe; /** * Daemon thread that pulls data from provider and pushes to consumer, using this controller */ private Thread puller; /** * Start state */ private volatile boolean isStarted; /** {@inheritDoc} */ public void onPipeConnectionEvent(PipeConnectionEvent event) { switch (event.getType()) { case PipeConnectionEvent.PROVIDER_CONNECT_PULL: if (event.getProvider() != this && providerPipe == null) { providerPipe = (IPipe) event.getSource(); } break; case PipeConnectionEvent.PROVIDER_DISCONNECT: if (event.getSource() == providerPipe) { providerPipe = null; } break; case PipeConnectionEvent.CONSUMER_CONNECT_PUSH: if (event.getConsumer() != this && consumerPipe == null) { consumerPipe = (IPipe) event.getSource(); } break; case PipeConnectionEvent.CONSUMER_DISCONNECT: if (event.getSource() == consumerPipe) { consumerPipe = null; } break; default: break; } } /** {@inheritDoc} */ public void onOOBControlMessage(IMessageComponent source, IPipe pipe, OOBControlMessage oobCtrlMsg) { } /** {@inheritDoc} */ public void run() { while (isStarted && providerPipe != null && consumerPipe != null) { try { IMessage message = providerPipe.pullMessage(); if (log.isDebugEnabled()) { log.debug("got message: {}", message); } consumerPipe.pushMessage(message); } catch (Exception e) { log.warn("Exception in pull and push", e); break; } } isStarted = false; } /** * Start pulling (streaming) */ public void start() { startThread(); } /** * Stop pulling, close stream */ public void close() { isStarted = false; } /** * Start puller thread */ private void startThread() { if (!isStarted && providerPipe != null && consumerPipe != null) { puller = new Thread(this, KEY); puller.setDaemon(true); isStarted = true; puller.start(); } } } red5-1.0~svn4374.orig/src/org/red5/server/stream/ISeekableStreamSource.java0000644000175000017500000000215311706617130026360 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; /** * Stream source that can be seeked in timeline * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface ISeekableStreamSource extends IStreamSource { /** * Seek the stream source to timestamp ts (in milliseconds). * @param ts Timestamp to seek to * @return Actual timestamp seeked to */ int seek(int ts); } red5-1.0~svn4374.orig/src/org/red5/server/stream/codec/0000755000175000017500000000000011760512571022413 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/stream/codec/AVCVideo.java0000644000175000017500000000642411706617130024661 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.codec; import org.apache.mina.core.buffer.IoBuffer; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.stream.IVideoStreamCodec; import org.slf4j.Logger; /** * Red5 video codec for the AVC (h264) video format. Stores DecoderConfigurationRecord and last keyframe. * * @author Tiago Jacobs (tiago@imdt.com.br) * @author Paul Gregoire (mondain@gmail.com) */ public class AVCVideo implements IVideoStreamCodec { private static Logger log = Red5LoggerFactory.getLogger(AVCVideo.class); /** * AVC video codec constant */ static final String CODEC_NAME = "AVC"; /** Last keyframe found */ private FrameData keyframe; /** Video decoder configuration data */ private FrameData decoderConfiguration; /** Constructs a new AVCVideo. */ public AVCVideo() { this.reset(); } /** {@inheritDoc} */ public String getName() { return CODEC_NAME; } /** {@inheritDoc} */ public boolean canDropFrames() { return true; } /** {@inheritDoc} */ public void reset() { keyframe = new FrameData(); decoderConfiguration = new FrameData(); } /** {@inheritDoc} */ public boolean canHandleData(IoBuffer data) { if (data.limit() == 0) { // Empty buffer return false; } byte first = data.get(); boolean result = ((first & 0x0f) == VideoCodec.AVC.getId()); data.rewind(); return result; } /** {@inheritDoc} */ public boolean addData(IoBuffer data) { if (data.limit() > 0) { //ensure that we can "handle" the data if (!canHandleData(data)) { return false; } // get frame type byte frameType = data.get(); // check for keyframe if ((frameType & 0xf0) == FLV_FRAME_KEY) { log.trace("Key frame found"); byte AVCPacketType = data.get(); // rewind data.rewind(); // sequence header / here comes a AVCDecoderConfigurationRecord log.debug("AVCPacketType: {}", AVCPacketType); if (AVCPacketType == 0) { log.trace("Decoder configuration found"); // Store AVCDecoderConfigurationRecord data decoderConfiguration.setData(data); // rewind data.rewind(); } // store last keyframe keyframe.setData(data); } // finished with the data, rewind one last time data.rewind(); } return true; } /** {@inheritDoc} */ public IoBuffer getKeyframe() { return keyframe.getFrame(); } /** {@inheritDoc} */ public IoBuffer getDecoderConfiguration() { return decoderConfiguration.getFrame(); } } red5-1.0~svn4374.orig/src/org/red5/server/stream/codec/AACAudio.java0000644000175000017500000000674211706617130024632 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.codec; import org.apache.mina.core.buffer.IoBuffer; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.stream.IAudioStreamCodec; import org.slf4j.Logger; /** * Red5 audio codec for the AAC audio format. * * Stores the decoder configuration * * @author Paul Gregoire (mondain@gmail.com) * @author Wittawas Nakkasem (vittee@hotmail.com) * @author Vladimir Hmelyoff (vlhm@splitmedialabs.com) */ public class AACAudio implements IAudioStreamCodec { private static Logger log = Red5LoggerFactory.getLogger(AACAudio.class); public static final int[] AAC_SAMPLERATES = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350 }; /** * AAC audio codec constant */ static final String CODEC_NAME = "AAC"; /** * Block of data (AAC DecoderConfigurationRecord) */ private byte[] blockDataAACDCR; /** Constructs a new AACAudio */ public AACAudio() { this.reset(); } /** {@inheritDoc} */ public String getName() { return CODEC_NAME; } /** {@inheritDoc} */ public void reset() { blockDataAACDCR = null; } /** {@inheritDoc} */ public boolean canHandleData(IoBuffer data) { if (data.limit() == 0) { // Empty buffer return false; } byte first = data.get(); boolean result = (((first & 0xf0) >> 4) == AudioCodec.AAC.getId()); data.rewind(); return result; } /** {@inheritDoc} */ public boolean addData(IoBuffer data) { int dataLength = data.limit(); if (dataLength > 1) { //ensure we are at the beginning data.rewind(); byte frameType = data.get(); log.trace("Frame type: {}", frameType); byte header = data.get(); //go back to beginning data.rewind(); //If we don't have the AACDecoderConfigurationRecord stored... if (blockDataAACDCR == null) { if ((((frameType & 0xF0) >> 4) == AudioCodec.AAC.getId()) && (header == 0)) { //go back to beginning data.rewind(); blockDataAACDCR = new byte[dataLength]; data.get(blockDataAACDCR); //go back to beginning data.rewind(); } } } return true; } /** {@inheritDoc} */ public IoBuffer getDecoderConfiguration() { if (blockDataAACDCR == null) { return null; } IoBuffer result = IoBuffer.allocate(4); result.setAutoExpand(true); result.put(blockDataAACDCR); result.rewind(); return result; } @SuppressWarnings("unused") private long sample2TC(long time, int sampleRate) { return (time * 1000L / sampleRate); } //private final byte[] getAACSpecificConfig() { // byte[] b = new byte[] { // (byte) (0x10 | /*((profile > 2) ? 2 : profile << 3) | */((sampleRateIndex >> 1) & 0x03)), // (byte) (((sampleRateIndex & 0x01) << 7) | ((channels & 0x0F) << 3)) // }; // log.debug("SpecificAudioConfig {}", HexDump.toHexString(b)); // return b; //} } red5-1.0~svn4374.orig/src/org/red5/server/stream/codec/ScreenVideo.java0000644000175000017500000001363711706617130025473 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.codec; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.stream.IVideoStreamCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Red5 video codec for the screen capture format. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public class ScreenVideo implements IVideoStreamCodec { private Logger log = LoggerFactory.getLogger(ScreenVideo.class); /** * FLV codec name constant */ static final String CODEC_NAME = "ScreenVideo"; /** * Block data */ private byte[] blockData; /** * Block size */ private int[] blockSize; /** * Video width */ private int width; /** * Video height */ private int height; /** * Width info */ private int widthInfo; /** * Height info */ private int heightInfo; /** * Block width */ private int blockWidth; /** * Block height */ private int blockHeight; /** * Number of blocks */ private int blockCount; /** * Block data size */ private int blockDataSize; /** * Total block data size */ private int totalBlockDataSize; /** Constructs a new ScreenVideo. */ public ScreenVideo() { this.reset(); } /** {@inheritDoc} */ public String getName() { return CODEC_NAME; } /** {@inheritDoc} */ public void reset() { this.blockData = null; this.blockSize = null; this.width = 0; this.height = 0; this.widthInfo = 0; this.heightInfo = 0; this.blockWidth = 0; this.blockHeight = 0; this.blockCount = 0; this.blockDataSize = 0; this.totalBlockDataSize = 0; } /** {@inheritDoc} */ public boolean canHandleData(IoBuffer data) { byte first = data.get(); boolean result = ((first & 0x0f) == VideoCodec.SCREEN_VIDEO.getId()); data.rewind(); return result; } /** {@inheritDoc} */ public boolean canDropFrames() { return false; } /* * This uses the same algorithm as "compressBound" from zlib */ private int maxCompressedSize(int size) { return size + (size >> 12) + (size >> 14) + 11; } /** * Update total block size * @param data Byte buffer */ private void updateSize(IoBuffer data) { this.widthInfo = data.getShort(); this.heightInfo = data.getShort(); // extract width and height of the frame this.width = this.widthInfo & 0xfff; this.height = this.heightInfo & 0xfff; // calculate size of blocks this.blockWidth = this.widthInfo & 0xf000; this.blockWidth = (this.blockWidth >> 12) + 1; this.blockWidth <<= 4; this.blockHeight = this.heightInfo & 0xf000; this.blockHeight = (this.blockHeight >> 12) + 1; this.blockHeight <<= 4; int xblocks = this.width / this.blockWidth; if ((this.width % this.blockWidth) != 0) { // partial block xblocks += 1; } int yblocks = this.height / this.blockHeight; if ((this.height % this.blockHeight) != 0) { // partial block yblocks += 1; } this.blockCount = xblocks * yblocks; int blockSize = this.maxCompressedSize(this.blockWidth * this.blockHeight * 3); int totalBlockSize = blockSize * this.blockCount; if (this.totalBlockDataSize != totalBlockSize) { log.info("Allocating memory for {} compressed blocks.", this.blockCount); this.blockDataSize = blockSize; this.totalBlockDataSize = totalBlockSize; this.blockData = new byte[blockSize * this.blockCount]; this.blockSize = new int[blockSize * this.blockCount]; // Reset the sizes to zero for (int idx = 0; idx < this.blockCount; idx++) { this.blockSize[idx] = 0; } } } /** {@inheritDoc} */ public boolean addData(IoBuffer data) { if (!this.canHandleData(data)) { return false; } data.get(); this.updateSize(data); int idx = 0; int pos = 0; byte[] tmpData = new byte[this.blockDataSize]; int countBlocks = this.blockCount; while (data.remaining() > 0 && countBlocks > 0) { short size = data.getShort(); countBlocks--; if (size == 0) { // Block has not been modified idx += 1; pos += this.blockDataSize; continue; } // Store new block data this.blockSize[idx] = size; data.get(tmpData, 0, size); System.arraycopy(tmpData, 0, this.blockData, pos, size); idx += 1; pos += this.blockDataSize; } data.rewind(); return true; } /** {@inheritDoc} */ public IoBuffer getKeyframe() { IoBuffer result = IoBuffer.allocate(1024); result.setAutoExpand(true); // Header result.put((byte) (FLV_FRAME_KEY | VideoCodec.SCREEN_VIDEO.getId())); // Frame size result.putShort((short) this.widthInfo); result.putShort((short) this.heightInfo); // Get compressed blocks byte[] tmpData = new byte[this.blockDataSize]; int pos = 0; for (int idx = 0; idx < this.blockCount; idx++) { int size = this.blockSize[idx]; if (size == 0) { // this should not happen: no data for this block return null; } result.putShort((short) size); System.arraycopy(this.blockData, pos, tmpData, 0, size); result.put(tmpData, 0, size); pos += this.blockDataSize; } result.rewind(); return result; } public IoBuffer getDecoderConfiguration() { return null; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/codec/StreamCodecInfo.java0000644000175000017500000000460711706617130026267 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.codec; import org.red5.server.api.stream.IAudioStreamCodec; import org.red5.server.api.stream.IStreamCodecInfo; import org.red5.server.api.stream.IVideoStreamCodec; public class StreamCodecInfo implements IStreamCodecInfo { /** * Audio support flag */ private boolean audio; /** * Video support flag */ private boolean video; /** * Audio codec */ private IAudioStreamCodec audioCodec; /** * Video codec */ private IVideoStreamCodec videoCodec; /** {@inheritDoc} */ public boolean hasAudio() { return audio; } /** * New value for audio support * * @param value Audio support */ public void setHasAudio(boolean value) { this.audio = value; } /** {@inheritDoc} */ public String getAudioCodecName() { if (audioCodec == null) { return null; } return audioCodec.getName(); } /** {@inheritDoc} */ public IAudioStreamCodec getAudioCodec() { return audioCodec; } /** * Setter for audio codec * * @param codec Audio codec */ public void setAudioCodec(IAudioStreamCodec codec) { this.audioCodec = codec; } /** {@inheritDoc} */ public boolean hasVideo() { return video; } /** * New value for video support * * @param value Video support */ public void setHasVideo(boolean value) { this.video = value; } /** {@inheritDoc} */ public String getVideoCodecName() { if (videoCodec == null) { return null; } return videoCodec.getName(); } /** {@inheritDoc} */ public IVideoStreamCodec getVideoCodec() { return videoCodec; } /** * Setter for video codec * * @param codec Video codec */ public void setVideoCodec(IVideoStreamCodec codec) { this.videoCodec = codec; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/codec/SorensonVideo.java0000644000175000017500000000571711706617130026062 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.codec; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.stream.IVideoStreamCodec; /** * Red5 video codec for the sorenson video format. * * VERY simple implementation, just stores last keyframe. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public class SorensonVideo implements IVideoStreamCodec { /** * Sorenson video codec constant */ static final String CODEC_NAME = "SorensonVideo"; /** * Block of data */ private byte[] blockData; /** * Number of data blocks */ private int dataCount; /** * Data block size */ private int blockSize; /** Constructs a new SorensonVideo. */ public SorensonVideo() { this.reset(); } /** {@inheritDoc} */ public String getName() { return CODEC_NAME; } /** {@inheritDoc} */ public boolean canDropFrames() { return true; } /** {@inheritDoc} */ public void reset() { this.blockData = null; this.blockSize = 0; this.dataCount = 0; } /** {@inheritDoc} */ public boolean canHandleData(IoBuffer data) { if (data.limit() == 0) { // Empty buffer return false; } byte first = data.get(); boolean result = ((first & 0x0f) == VideoCodec.H263.getId()); data.rewind(); return result; } /** {@inheritDoc} */ public boolean addData(IoBuffer data) { if (data.limit() == 0) { // Empty buffer return true; } if (!this.canHandleData(data)) { return false; } byte first = data.get(); data.rewind(); if ((first & 0xf0) != FLV_FRAME_KEY) { // Not a keyframe return true; } // Store last keyframe this.dataCount = data.limit(); if (this.blockSize < this.dataCount) { this.blockSize = this.dataCount; this.blockData = new byte[this.blockSize]; } data.get(this.blockData, 0, this.dataCount); data.rewind(); return true; } /** {@inheritDoc} */ public IoBuffer getKeyframe() { if (this.dataCount == 0) { return null; } IoBuffer result = IoBuffer.allocate(this.dataCount); result.put(this.blockData, 0, this.dataCount); result.rewind(); return result; } public IoBuffer getDecoderConfiguration() { return null; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/codec/AudioCodec.java0000644000175000017500000000303311706617130025251 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.codec; /** * Audio codecs that Red5 supports. * * @author Art Clarke * @author Paul Gregoire (mondain@gmail.com) */ public enum AudioCodec { PCM((byte) 0), ADPCM((byte) 0x01), MP3((byte) 0x02), PCM_LE((byte) 0x03), NELLY_MOSER_16K((byte) 0x04), NELLY_MOSER_8K((byte) 0x05), NELLY_MOSER((byte) 0x06), PCM_ALAW((byte) 0x07), PCM_MULAW((byte) 0x08), RESERVED((byte) 0x09), AAC((byte) 0x0a), SPEEX((byte) 0x0b), MP3_8K((byte) 0x0e), DEVICE_SPECIFIC((byte) 0x0f); private byte id; private AudioCodec(byte id) { this.id = id; } /** * Returns back a numeric id for this codec, that happens to correspond to the * numeric identifier that FLV will use for this codec. * * @return the codec id */ public byte getId() { return id; } }red5-1.0~svn4374.orig/src/org/red5/server/stream/codec/VideoCodec.java0000644000175000017500000000255311706617130025264 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.codec; /** * Video codecs that Red5 supports. * * @author Art Clarke * @author Paul Gregoire (mondain@gmail.com) */ public enum VideoCodec { JPEG((byte) 0x01), H263((byte) 0x02), SCREEN_VIDEO((byte) 0x03), VP6((byte) 0x04), VP6a((byte) 0x05), SCREEN_VIDEO2((byte) 0x06), AVC((byte) 0x07); private byte id; private VideoCodec(byte id) { this.id = id; } /** * Returns back a numeric id for this codec, * that happens to correspond to the numeric * identifier that FLV will use for this codec. * * @return the codec id */ public byte getId() { return id; } }red5-1.0~svn4374.orig/src/org/red5/server/stream/codec/ScreenVideo2.java0000644000175000017500000001534511706617130025553 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream.codec; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.stream.IVideoStreamCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Red5 video codec for the screen capture format. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public class ScreenVideo2 implements IVideoStreamCodec { private Logger log = LoggerFactory.getLogger(ScreenVideo2.class); /** * FLV codec name constant */ static final String CODEC_NAME = "ScreenVideo2"; /** * Block data */ private byte[] blockData; /** * Block size */ private int[] blockSize; /** * Video width */ private int width; /** * Video height */ private int height; /** * Width info */ private int widthInfo; /** * Height info */ private int heightInfo; /** * Block width */ private int blockWidth; /** * Block height */ private int blockHeight; /** * Number of blocks */ private int blockCount; /** * Block data size */ private int blockDataSize; /** * Total block data size */ private int totalBlockDataSize; /** * Special Info 1 */ private byte specInfo1; /** * Special Info 2 */ private byte specInfo2; /** Constructs a new ScreenVideo2. */ public ScreenVideo2() { this.reset(); } /** {@inheritDoc} */ public String getName() { return CODEC_NAME; } /** {@inheritDoc} */ public void reset() { this.blockData = null; this.blockSize = null; this.width = 0; this.height = 0; this.widthInfo = 0; this.heightInfo = 0; this.blockWidth = 0; this.blockHeight = 0; this.blockCount = 0; this.blockDataSize = 0; this.totalBlockDataSize = 0; } /** {@inheritDoc} */ public boolean canHandleData(IoBuffer data) { byte first = data.get(); boolean result = ((first & 0x0f) == VideoCodec.SCREEN_VIDEO2.getId()); data.rewind(); return result; } /** {@inheritDoc} */ public boolean canDropFrames() { return false; } /* * This uses the same algorithm as "compressBound" from zlib */ private int maxCompressedSize(int size) { return size + (size >> 12) + (size >> 14) + 11; } /** * Update total block size * @param data Byte buffer */ private void updateSize(IoBuffer data) { this.widthInfo = data.getShort(); this.heightInfo = data.getShort(); // extract width and height of the frame this.width = this.widthInfo & 0xfff; this.height = this.heightInfo & 0xfff; // calculate size of blocks this.blockWidth = this.widthInfo & 0xf000; this.blockWidth = (this.blockWidth >> 12) + 1; this.blockWidth <<= 4; this.blockHeight = this.heightInfo & 0xf000; this.blockHeight = (this.blockHeight >> 12) + 1; this.blockHeight <<= 4; int xblocks = this.width / this.blockWidth; if ((this.width % this.blockWidth) != 0) { // partial block xblocks += 1; } int yblocks = this.height / this.blockHeight; if ((this.height % this.blockHeight) != 0) { // partial block yblocks += 1; } this.blockCount = xblocks * yblocks; int blockSize = this.maxCompressedSize(this.blockWidth * this.blockHeight * 3); int totalBlockSize = blockSize * this.blockCount; if (this.totalBlockDataSize != totalBlockSize) { log.info("Allocating memory for {} compressed blocks.", this.blockCount); this.blockDataSize = blockSize; this.totalBlockDataSize = totalBlockSize; this.blockData = new byte[blockSize * this.blockCount]; this.blockSize = new int[blockSize * this.blockCount]; // Reset the sizes to zero for (int idx = 0; idx < this.blockCount; idx++) { this.blockSize[idx] = 0; } } } /** {@inheritDoc} */ public boolean addData(IoBuffer data) { if (!this.canHandleData(data)) { return false; } data.get(); this.updateSize(data); int idx = 0; int pos = 0; byte[] tmpData = new byte[this.blockDataSize]; // reserved (6) has iframeimage (1) has palleteinfo (1) this.specInfo1 = data.get(); int countBlocks = this.blockCount; while (data.remaining() > 0 && countBlocks > 0) { short size = data.getShort(); countBlocks--; if (size == 0) { // Block has not been modified idx += 1; pos += this.blockDataSize; continue; } else { // imageformat this.specInfo2 = data.get(); size--; } // Store new block data this.blockSize[idx] = size; data.get(tmpData, 0, size); System.arraycopy(tmpData, 0, this.blockData, pos, size); idx += 1; pos += this.blockDataSize; } data.rewind(); return true; } /** {@inheritDoc} */ public IoBuffer getKeyframe() { IoBuffer result = IoBuffer.allocate(1024); result.setAutoExpand(true); // Header result.put((byte) (FLV_FRAME_KEY | VideoCodec.SCREEN_VIDEO2.getId())); // Frame size result.putShort((short) this.widthInfo); result.putShort((short) this.heightInfo); // reserved (6) has iframeimage (1) has palleteinfo (1) result.put(this.specInfo1); // Get compressed blocks byte[] tmpData = new byte[this.blockDataSize]; int pos = 0; for (int idx = 0; idx < this.blockCount; idx++) { int size = this.blockSize[idx]; if (size == 0) { // this should not happen: no data for this block return null; } result.putShort((short)(size + 1)); // IMAGEFORMAT // reserved(3) color depth(2) has diff blocks(1) // ZlibPrimeCompressCurrent(1) ZlibPrimeCompressPrevious (1) result.put(this.specInfo2); System.arraycopy(this.blockData, pos, tmpData, 0, size); result.put(tmpData, 0, size); pos += this.blockDataSize; } result.rewind(); return result; } public IoBuffer getDecoderConfiguration() { return null; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/ProviderService.java0000644000175000017500000001762611747143220025324 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.io.File; import java.io.IOException; import java.util.Set; import org.red5.io.IStreamableFileFactory; import org.red5.io.IStreamableFileService; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.scope.IBroadcastScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.ScopeType; import org.red5.server.api.stream.IBroadcastStream; import org.red5.server.api.stream.IStreamFilenameGenerator; import org.red5.server.api.stream.IStreamFilenameGenerator.GenerationType; import org.red5.server.messaging.IMessageInput; import org.red5.server.messaging.IPipe; import org.red5.server.messaging.InMemoryPullPullPipe; import org.red5.server.scope.BasicScope; import org.red5.server.scope.BroadcastScope; import org.red5.server.scope.Scope; import org.red5.server.stream.provider.FileProvider; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; public class ProviderService implements IProviderService { private static final Logger log = Red5LoggerFactory.getLogger(ProviderService.class); /** {@inheritDoc} */ public INPUT_TYPE lookupProviderInput(IScope scope, String name, int type) { INPUT_TYPE result = INPUT_TYPE.NOT_FOUND; if (scope.getBasicScope(ScopeType.BROADCAST, name) != null) { //we have live input result = INPUT_TYPE.LIVE; } else { //"default" to VOD as a missing file will be picked up later on result = INPUT_TYPE.VOD; File file = null; try { file = getStreamFile(scope, name); if (file == null) { if (type == -2) { result = INPUT_TYPE.LIVE_WAIT; } log.debug("Requested stream: {} does not appear to be of VOD type", name); } } catch (IOException e) { log.warn("Exception attempting to lookup file: {}", name, e); } finally { //null it to prevent leak or file locking file = null; } } return result; } /** {@inheritDoc} */ public IMessageInput getProviderInput(IScope scope, String name) { IMessageInput msgIn = getLiveProviderInput(scope, name, false); if (msgIn == null) { return getVODProviderInput(scope, name); } return msgIn; } /** {@inheritDoc} */ public IMessageInput getLiveProviderInput(IScope scope, String name, boolean needCreate) { log.debug("Get live provider input for {} scope: {}", name, scope); if (log.isDebugEnabled()) { ((Scope) scope).dump(); } //make sure the create is actually needed IBroadcastScope broadcastScope = scope.getBroadcastScope(name); if (broadcastScope == null) { if (needCreate) { // re-check if another thread already created the scope broadcastScope = scope.getBroadcastScope(name); if (broadcastScope == null) { broadcastScope = new BroadcastScope(scope, name); scope.addChildScope(broadcastScope); } } else { return null; } } return broadcastScope; } /** {@inheritDoc} */ public IMessageInput getVODProviderInput(IScope scope, String name) { log.debug("getVODProviderInput - scope: {} name: {}", scope, name); File file = getVODProviderFile(scope, name); if (file == null) { return null; } IPipe pipe = new InMemoryPullPullPipe(); pipe.subscribe(new FileProvider(scope, file), null); return pipe; } /** {@inheritDoc} */ public File getVODProviderFile(IScope scope, String name) { log.debug("getVODProviderFile - scope: {} name: {}", scope, name); File file = null; try { log.trace("getVODProviderFile scope path: {} name: {}", scope.getContextPath(), name); file = getStreamFile(scope, name); } catch (IOException e) { log.error("Problem getting file: {}", name, e); } if (file == null || !file.exists()) { //if there is no file extension this is most likely a live stream if (name.indexOf('.') > 0) { log.info("File was null or did not exist: {}", name); } else { log.trace("VOD file {} was not found, may be live stream", name); } } return file; } /** {@inheritDoc} */ public boolean registerBroadcastStream(IScope scope, String name, IBroadcastStream bs) { log.debug("Registering - name: {} stream: {} scope: {}", new Object[] { name, bs, scope }); if (log.isDebugEnabled()) { ((Scope) scope).dump(); } IBroadcastScope broadcastScope = scope.getBroadcastScope(name); if (broadcastScope == null) { log.debug("Creating a new scope"); broadcastScope = new BroadcastScope(scope, name); if (scope.addChildScope(broadcastScope)) { log.debug("Broadcast scope added"); } else { log.warn("Broadcast scope was not added to {}", scope); } } log.debug("Subscribing scope {} to provider {}", broadcastScope, bs.getProvider()); return broadcastScope.subscribe(bs.getProvider(), null); } /** {@inheritDoc} */ public Set getBroadcastStreamNames(IScope scope) { return scope.getBasicScopeNames(ScopeType.BROADCAST); } /** {@inheritDoc} */ public boolean unregisterBroadcastStream(IScope scope, String name) { return unregisterBroadcastStream(scope, name, null); } /** {@inheritDoc} */ public boolean unregisterBroadcastStream(IScope scope, String name, IBroadcastStream bs) { log.debug("Unregistering - name: {} stream: {} scope: {}", new Object[] { name, bs, scope }); if (log.isDebugEnabled()) { ((Scope) scope).dump(); } IBroadcastScope broadcastScope = scope.getBroadcastScope(name); if (bs != null) { log.debug("Unsubscribing scope {} from provider {}", broadcastScope, bs.getProvider()); broadcastScope.unsubscribe(bs.getProvider()); } // if the scope has no listeners try to remove it if (!((BasicScope) broadcastScope).hasEventListeners()) { log.debug("Scope has no event listeners attempting removal"); scope.removeChildScope(broadcastScope); } // verify that scope was removed return scope.getBasicScope(ScopeType.BROADCAST, name) == null; } private File getStreamFile(IScope scope, String name) throws IOException { IStreamableFileFactory factory = (IStreamableFileFactory) ScopeUtils.getScopeService(scope, IStreamableFileFactory.class); if (name.indexOf(':') == -1 && name.indexOf('.') == -1) { // Default to .flv files if no prefix and no extension is given. name = "flv:" + name; } log.debug("getStreamFile null check - factory: {} name: {}", factory, name); for (IStreamableFileService service : factory.getServices()) { if (name.startsWith(service.getPrefix() + ':')) { name = service.prepareFilename(name); break; } } // look for a custom filename gen class IStreamFilenameGenerator filenameGenerator = (IStreamFilenameGenerator) ScopeUtils.getScopeService(scope, IStreamFilenameGenerator.class, DefaultStreamFilenameGenerator.class); // get the filename String filename = filenameGenerator.generateFilename(scope, name, GenerationType.PLAYBACK); File file; //most likely case first if (!filenameGenerator.resolvesToAbsolutePath()) { file = scope.getContext().getResource(filename).getFile(); } else { file = new File(filename); } //check files existence if (file != null && !file.exists()) { //if it does not exist then null it out file = null; } return file; } } red5-1.0~svn4374.orig/src/org/red5/server/stream/IStreamData.java0000644000175000017500000000245511706617130024342 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import java.io.IOException; import org.apache.mina.core.buffer.IoBuffer; /** * Stream data packet */ public interface IStreamData { /** * Getter for property 'data'. * * @return Value for property 'data'. */ public IoBuffer getData(); /** * Creates a byte accurate copy. * * @return duplicate of the current data item * @throws IOException * @throws ClassNotFoundException */ public IStreamData duplicate() throws IOException, ClassNotFoundException; } red5-1.0~svn4374.orig/src/org/red5/server/stream/DefaultStreamFilenameGenerator.java0000644000175000017500000000546711747114732030267 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.stream; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IStreamFilenameGenerator; import org.red5.server.util.ScopeUtils; /** * Default filename generator for streams. The files will be stored in a * directory "streams" in the application folder. Option for changing directory * streams are saved to is investigated as of 0.6RC1. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (bauch@struktur.de) */ public class DefaultStreamFilenameGenerator implements IStreamFilenameGenerator { /** * Generate stream directory based on relative scope path. The base directory is * streams, e.g. a scope /application/one/two/ will * generate a directory /streams/one/two/ inside the application. * * @param scope Scope * @return Directory based on relative scope path */ private String getStreamDirectory(IScope scope) { final StringBuilder result = new StringBuilder(); final IScope app = ScopeUtils.findApplication(scope); final String prefix = "streams/"; while (scope != null && scope != app) { result.insert(0, scope.getName() + "/"); scope = scope.getParent(); } if (result.length() == 0) { return prefix; } else { result.insert(0, prefix).append('/'); return result.toString(); } } /** {@inheritDoc} */ public String generateFilename(IScope scope, String name, GenerationType type) { return generateFilename(scope, name, null, type); } /** {@inheritDoc} */ public String generateFilename(IScope scope, String name, String extension, GenerationType type) { String result = getStreamDirectory(scope) + name; if (extension != null && !extension.equals("")) { result += extension; } return result; } /** * The default filenames are relative to the scope path, so always return false. * * @return always false */ public boolean resolvesToAbsolutePath() { return false; } }red5-1.0~svn4374.orig/src/org/red5/server/cache/0000755000175000017500000000000011760512571021106 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/cache/EhCacheImpl.java0000644000175000017500000002116111706617130024051 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.cache; import java.lang.ref.SoftReference; import java.util.Iterator; import java.util.List; import java.util.Set; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Ehcache; import net.sf.ehcache.Element; import net.sf.ehcache.config.CacheConfiguration; import net.sf.ehcache.config.Configuration; import net.sf.ehcache.config.ConfigurationHelper; import net.sf.ehcache.event.CacheManagerEventListener; import org.red5.server.api.cache.ICacheStore; import org.red5.server.api.cache.ICacheable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * Provides an implementation of an object cache using EhCache. * * @see ehcache homepage * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class EhCacheImpl implements ICacheStore, ApplicationContextAware { protected static Logger log = LoggerFactory.getLogger(EhCacheImpl.class); private static Ehcache cache; private List configs; private String memoryStoreEvictionPolicy = "LRU"; private int diskExpiryThreadIntervalSeconds = 120; private String diskStore = System.getProperty("java.io.tmpdir"); private CacheManagerEventListener cacheManagerEventListener; // We store the application context in a ThreadLocal so we can access it // later. private static ApplicationContext applicationContext; /** {@inheritDoc} */ public void setApplicationContext(ApplicationContext context) throws BeansException { EhCacheImpl.applicationContext = context; } /** * Getter for property 'applicationContext'. * * @return Value for property 'applicationContext'. */ public static ApplicationContext getApplicationContext() { return applicationContext; } @SuppressWarnings({ "unchecked", "unused" }) public void init() { log.info("Loading ehcache"); // log.debug("Appcontext: " + applicationContext.toString()); try { // instance the manager CacheManager cm = CacheManager.getInstance(); // Use the Configuration to create our caches Configuration configuration = new Configuration(); //set initial default cache name String defaultCacheName = Cache.DEFAULT_CACHE_NAME; //add the configs to a configuration for (CacheConfiguration conf : configs) { //set disk expiry conf.setDiskExpiryThreadIntervalSeconds(diskExpiryThreadIntervalSeconds); //set eviction policy conf.setMemoryStoreEvictionPolicy(memoryStoreEvictionPolicy); if (null == cache) { //get first cache name and use as default defaultCacheName = conf.getName(); configuration.addDefaultCache(conf); } else { configuration.addCache(conf); } } //instance the helper ConfigurationHelper helper = new ConfigurationHelper(cm, configuration); //create the default cache cache = helper.createDefaultCache(); //init the default cache.initialise(); cache.bootstrap(); //create the un-init'd caches Set caches = helper.createCaches(); if (log.isDebugEnabled()) { log.debug("Number of caches: " + caches.size() + " Default cache: " + (cache != null ? 1 : 0)); } for (Cache nonDefaultCache : caches) { nonDefaultCache.initialise(); nonDefaultCache.bootstrap(); //set first cache to be main local member if (null == nonDefaultCache) { log.debug("Default cache name: {}", defaultCacheName); nonDefaultCache = cm.getCache(defaultCacheName); } } } catch (Exception e) { log.warn("Error on cache init", e); } if (log.isDebugEnabled()) { log.debug("Cache is null? {}", (null == cache)); } } /** {@inheritDoc} */ public ICacheable get(String name) { ICacheable ic = null; try { ic = (ICacheable) cache.get(name).getObjectValue(); } catch (NullPointerException npe) { } return ic; } /** {@inheritDoc} */ public void put(String name, Object obj) { if (obj instanceof ICacheable) { cache.put(new Element(name, obj)); } else { cache.put(new Element(name, new CacheableImpl(obj))); } } /** {@inheritDoc} */ @SuppressWarnings("unchecked") public Iterator getObjectNames() { return cache.getKeys().iterator(); } /** {@inheritDoc} */ public Iterator> getObjects() { return null; } /** {@inheritDoc} */ public boolean offer(String name, Object obj) { boolean result = false; try { result = cache.isKeyInCache(name); // Put an object into the cache if (!result) { put(name, obj); } //check again result = cache.isKeyInCache(name); } catch (NullPointerException npe) { log.debug("Name: " + name + " Object: " + obj.getClass().getName(), npe); } return result; } /** {@inheritDoc} */ public boolean remove(ICacheable obj) { return cache.remove(obj.getName()); } /** {@inheritDoc} */ public boolean remove(String name) { return cache.remove(name); } /** * Setter for property 'cacheConfigs'. * * @param configs Value to set for property 'cacheConfigs'. */ public void setCacheConfigs(List configs) { this.configs = configs; } /** {@inheritDoc} */ public void setMaxEntries(int capacity) { if (log.isDebugEnabled()) { log.debug("Setting max entries for this cache to " + capacity); } } /** * Getter for property 'memoryStoreEvictionPolicy'. * * @return Value for property 'memoryStoreEvictionPolicy'. */ public String getMemoryStoreEvictionPolicy() { return memoryStoreEvictionPolicy; } /** * Setter for property 'memoryStoreEvictionPolicy'. * * @param memoryStoreEvictionPolicy Value to set for property 'memoryStoreEvictionPolicy'. */ public void setMemoryStoreEvictionPolicy(String memoryStoreEvictionPolicy) { this.memoryStoreEvictionPolicy = memoryStoreEvictionPolicy; } /** * Getter for property 'diskExpiryThreadIntervalSeconds'. * * @return Value for property 'diskExpiryThreadIntervalSeconds'. */ public int getDiskExpiryThreadIntervalSeconds() { return diskExpiryThreadIntervalSeconds; } /** * Setter for property 'diskExpiryThreadIntervalSeconds'. * * @param diskExpiryThreadIntervalSeconds Value to set for property 'diskExpiryThreadIntervalSeconds'. */ public void setDiskExpiryThreadIntervalSeconds(int diskExpiryThreadIntervalSeconds) { this.diskExpiryThreadIntervalSeconds = diskExpiryThreadIntervalSeconds; } /** * Getter for property 'diskStore'. * * @return Value for property 'diskStore'. */ public String getDiskStore() { return diskStore; } /** * Setter for property 'diskStore'. * * @param diskStore Value to set for property 'diskStore'. */ public void setDiskStore(String diskStore) { this.diskStore = System.getProperty("diskStore"); } /** * Getter for property 'cacheManagerEventListener'. * * @return Value for property 'cacheManagerEventListener'. */ public CacheManagerEventListener getCacheManagerEventListener() { return cacheManagerEventListener; } /** * Setter for property 'cacheManagerEventListener'. * * @param cacheManagerEventListener Value to set for property 'cacheManagerEventListener'. */ public void setCacheManagerEventListener(CacheManagerEventListener cacheManagerEventListener) { this.cacheManagerEventListener = cacheManagerEventListener; } /** * Getter for property 'cacheHit'. * * @return Value for property 'cacheHit'. */ public static long getCacheHit() { return cache.getStatistics().getCacheHits(); } /** * Getter for property 'cacheMiss'. * * @return Value for property 'cacheMiss'. */ public static long getCacheMiss() { return cache.getStatistics().getCacheMisses(); } /** {@inheritDoc} */ public void destroy() { // Shut down the cache manager try { CacheManager.getInstance().shutdown(); } catch (Exception e) { log.warn("Error on cache shutdown", e); } } } red5-1.0~svn4374.orig/src/org/red5/server/cache/NoCacheImpl.java0000644000175000017500000000671711706617130024103 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.cache; import java.lang.ref.SoftReference; import java.util.Iterator; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.cache.ICacheStore; import org.red5.server.api.cache.ICacheable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * Provides an implementation of an object cache which actually * does not provide a cache. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class NoCacheImpl implements ICacheStore, ApplicationContextAware { protected static Logger log = LoggerFactory.getLogger(NoCacheImpl.class); private static NoCacheImpl instance = new NoCacheImpl(); /** Do not instantiate NoCacheImpl. */ /* * This constructor helps to ensure that we are singleton. */ private NoCacheImpl() { } /** * Returns the instance of this class. * * @return class instance */ public static NoCacheImpl getInstance() { return instance; } // We store the application context in a ThreadLocal so we can access it // later. private static ApplicationContext applicationContext = null; /** {@inheritDoc} */ public void setApplicationContext(ApplicationContext context) throws BeansException { NoCacheImpl.applicationContext = context; } /** * Getter for property 'applicationContext'. * * @return Value for property 'applicationContext'. */ public static ApplicationContext getApplicationContext() { return applicationContext; } /** {@inheritDoc} */ public Iterator getObjectNames() { return null; } /** {@inheritDoc} */ public Iterator> getObjects() { return null; } public boolean offer(String key, IoBuffer obj) { return false; } /** {@inheritDoc} */ public boolean offer(String name, Object obj) { return false; } /** {@inheritDoc} */ public void put(String name, Object obj) { } /** {@inheritDoc} */ public ICacheable get(String name) { return null; } /** {@inheritDoc} */ public boolean remove(ICacheable obj) { return false; } /** {@inheritDoc} */ public boolean remove(String name) { return false; } /** * Getter for property 'cacheHit'. * * @return Value for property 'cacheHit'. */ public static long getCacheHit() { return 0; } /** * Getter for property 'cacheMiss'. * * @return Value for property 'cacheMiss'. */ public static long getCacheMiss() { return 0; } /** {@inheritDoc} */ public void setMaxEntries(int max) { } /** {@inheritDoc} */ public void destroy() { } } red5-1.0~svn4374.orig/src/org/red5/server/cache/CacheableImpl.java0000644000175000017500000000554311706617130024426 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.cache; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.cache.ICacheable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; /** * Provides an implementation of a cacheable object. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class CacheableImpl implements ICacheable { protected static Logger log = LoggerFactory.getLogger(CacheableImpl.class); protected ApplicationContext applicationContext; private byte[] bytes; private String name; private boolean cached; public CacheableImpl(Object obj) { IoBuffer tmp = IoBuffer.allocate(1024, true); tmp.setAutoExpand(true); tmp.putObject(obj); bytes = new byte[tmp.capacity()]; tmp.get(bytes); cached = true; tmp.free(); tmp = null; } public CacheableImpl(IoBuffer buffer) { if (log.isDebugEnabled()) { log.debug("Buffer is direct: {} capacity: {}", buffer.isDirect(), buffer.capacity()); log.debug("Buffer limit: {} remaining: {} position: {}", new Object[]{buffer.limit(), buffer.remaining(), buffer.position()}); } bytes = new byte[buffer.capacity()]; buffer.rewind(); int i = 0; while (i < buffer.limit()) { buffer.position(i); while (buffer.remaining() > 0) { bytes[i++] = buffer.get(); } } cached = true; if (log.isDebugEnabled()) { log.debug("Buffer size: " + buffer.capacity()); } buffer = null; } public void addRequest() { log.info("Adding request for: " + name); } /** {@inheritDoc} */ public byte[] getBytes() { return bytes; } /** {@inheritDoc} */ public IoBuffer getByteBuffer() { return IoBuffer.wrap(bytes).asReadOnlyBuffer(); } /** {@inheritDoc} */ public String getName() { return name; } /** {@inheritDoc} */ public boolean isCached() { return cached; } /** {@inheritDoc} */ public void setCached(boolean cached) { this.cached = cached; } /** {@inheritDoc} */ public void setName(String name) { this.name = name; } } red5-1.0~svn4374.orig/src/org/red5/server/cache/CacheImpl.java0000644000175000017500000001564311706617130023604 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.cache; import java.lang.ref.SoftReference; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.mina.core.buffer.IoBuffer; import org.red5.server.api.cache.ICacheStore; import org.red5.server.api.cache.ICacheable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * Provides an implementation of an object cache. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class CacheImpl implements ICacheStore, ApplicationContextAware { protected static Logger log = LoggerFactory.getLogger(CacheImpl.class); private static volatile CacheImpl instance; private static final Map> CACHE; // cache registry - keeps hard references to objects in the cache private static Map registry; private static int capacity = 5; private static volatile long cacheHit; private static volatile long cacheMiss; static { // create an instance instance = new CacheImpl(); // instance a static map with an initial small (prime) size CACHE = new HashMap>(3); // instance a hard-ref registry registry = new HashMap(3); } /** Do not instantiate CacheImpl. */ /* * This constructor helps to ensure that we are singleton. */ private CacheImpl() { } // We store the application context in a ThreadLocal so we can access it // later. private static ApplicationContext applicationContext = null; /** {@inheritDoc} */ public void setApplicationContext(ApplicationContext context) throws BeansException { CacheImpl.applicationContext = context; } /** * Getter for property 'applicationContext'. * * @return Value for property 'applicationContext'. */ public static ApplicationContext getApplicationContext() { return applicationContext; } /** * Returns the instance of this class. * * @return instance of this class */ public static CacheImpl getInstance() { return instance; } public void init() { log.info("Loading generic object cache"); log.debug("Appcontext: {}", applicationContext.toString()); } /** {@inheritDoc} */ public Iterator getObjectNames() { return Collections.unmodifiableSet(CACHE.keySet()).iterator(); } /** {@inheritDoc} */ public Iterator> getObjects() { return Collections.unmodifiableCollection(CACHE.values()).iterator(); } public boolean offer(String key, IoBuffer obj) { return offer(key, new CacheableImpl(obj)); } /** {@inheritDoc} */ public boolean offer(String name, Object obj) { boolean accepted = false; // check map size if (CACHE.size() < capacity) { SoftReference tmp = CACHE.get(name); // because soft references can be garbage collected when a system is // in need of memory, we will check that the cacheable object is // valid // log.debug("Softreference: " + (null == tmp)); // if (null != tmp) { // log.debug("Softreference value: " + (null == tmp.get())); // } if (null == tmp || null == tmp.get()) { ICacheable cacheable = null; if (obj instanceof ICacheable) { cacheable = (ICacheable) obj; } else { cacheable = new CacheableImpl(obj); } // set the objects name cacheable.setName(name); // set a registry entry registry.put(name, 1); // create a soft reference SoftReference value = new SoftReference( cacheable); CACHE.put(name, value); // set acceptance accepted = true; log.info("{} has been added to the cache. Current size: {}", name, CACHE.size()); } } else { log.warn("Cache has reached max element size: " + capacity); } return accepted; } /** {@inheritDoc} */ public void put(String name, Object obj) { if (obj instanceof ICacheable) { put(name, (ICacheable) obj); } else { put(name, new CacheableImpl(obj)); } } protected void put(String name, ICacheable obj) { // set the objects name obj.setName(name); // set a registry entry registry.put(name, 1); // create a soft reference SoftReference value = new SoftReference(obj); // put an object into the cache CACHE.put(name, value); log.info(name + " has been added to the cache. Current size: " + CACHE.size()); } /** {@inheritDoc} */ public ICacheable get(String name) { if (log.isDebugEnabled()) { log.debug("Looking up " + name + " in the cache. Current size: " + CACHE.size()); } ICacheable ic = null; SoftReference sr = null; if (!CACHE.isEmpty() && null != (sr = CACHE.get(name))) { ic = (ICacheable) sr.get(); // add a request count to the registry int requestCount = registry.get(name); registry.put(name, (requestCount += 1)); // increment cache hits cacheHit += 1; } else { // add a request count to the registry registry.put(name, 1); // increment cache misses cacheMiss += 1; } log.debug("Registry on get: {}", registry.toString()); return ic; } /** {@inheritDoc} */ public boolean remove(ICacheable obj) { log.debug("Looking up {} in the cache. Current size: {}", obj.getName(), CACHE.size()); return remove(obj.getName()); } /** {@inheritDoc} */ public boolean remove(String name) { return CACHE.remove(name) != null ? true : false; } /** * Getter for property 'cacheHit'. * * @return Value for property 'cacheHit'. */ public static long getCacheHit() { return cacheHit; } /** * Getter for property 'cacheMiss'. * * @return Value for property 'cacheMiss'. */ public static long getCacheMiss() { return cacheMiss; } /** {@inheritDoc} */ public void setMaxEntries(int max) { log.info("Setting max entries for this cache to {}", max); CacheImpl.capacity = max; } /** {@inheritDoc} */ public void destroy() { // Shut down the cache manager try { registry.clear(); registry = null; CACHE.clear(); } catch (Exception e) { log.warn("Error on cache shutdown", e); } } } red5-1.0~svn4374.orig/src/org/red5/server/statistics/0000755000175000017500000000000011760512571022235 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/statistics/StatisticsService.java0000644000175000017500000001002111747114732026547 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.statistics; import java.util.HashSet; import java.util.Set; import org.red5.server.api.Red5; import org.red5.server.api.scope.IScope; import org.red5.server.api.so.ISharedObject; import org.red5.server.api.so.ISharedObjectService; import org.red5.server.api.statistics.ISharedObjectStatistics; import org.red5.server.api.statistics.IStatisticsService; import org.red5.server.exception.ScopeNotFoundException; import org.red5.server.exception.SharedObjectException; import org.red5.server.util.ScopeUtils; /** * Implementation of the statistics service. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class StatisticsService implements IStatisticsService { private static final String SCOPE_STATS_SO_NAME = "red5ScopeStatistics"; private static final String SO_STATS_SO_NAME = "red5SharedObjectStatistics"; private IScope globalScope; public void setGlobalScope(IScope scope) { globalScope = scope; } public ISharedObject getScopeStatisticsSO(IScope scope) { ISharedObjectService soService = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, false); return soService.getSharedObject(scope, SCOPE_STATS_SO_NAME, false); } private IScope getScope(String path) throws ScopeNotFoundException { IScope scope; if (path != null && !path.equals("")) { scope = ScopeUtils.resolveScope(globalScope, path); } else { scope = globalScope; } if (scope == null) { throw new ScopeNotFoundException(globalScope, path); } return scope; } public Set getScopes() { return getScopes(null); } public Set getScopes(String path) throws ScopeNotFoundException { IScope scope = getScope(path); Set result = scope.getScopeNames(); return result; } public ISharedObject getSharedObjectStatisticsSO(IScope scope) { ISharedObjectService soService = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, false); return soService.getSharedObject(scope, SO_STATS_SO_NAME, false); } public Set getSharedObjects(String path) { IScope scope = getScope(path); ISharedObjectService soService = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, false); Set result = new HashSet(); for (String name : soService.getSharedObjectNames(scope)) { ISharedObject so = soService.getSharedObject(scope, name); result.add(so.getStatistics()); } return result; } public void updateScopeStatistics(String path) throws ScopeNotFoundException { IScope scope = getScope(path); ISharedObject so = getScopeStatisticsSO(Red5.getConnectionLocal().getScope()); so.setAttribute(path, scope.getAttributes()); } public void updateSharedObjectStatistics(String path, String name) throws ScopeNotFoundException, SharedObjectException { IScope scope = getScope(path); ISharedObjectService soService = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, false); ISharedObject sourceSO = soService.getSharedObject(scope, name); if (sourceSO == null) throw new SharedObjectException(); ISharedObject so = getSharedObjectStatisticsSO(Red5.getConnectionLocal().getScope()); so.setAttribute(path + '|' + name, sourceSO.getData()); } } red5-1.0~svn4374.orig/src/org/red5/server/statistics/XmlRpcScopeStatistics.java0000644000175000017500000001403411747114732027356 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.statistics; import java.lang.reflect.Array; import java.util.Collection; import java.util.Date; import java.util.Hashtable; import java.util.Map; import java.util.Set; import java.util.Vector; import org.red5.server.api.scope.IScope; import org.red5.server.api.so.ISharedObject; import org.red5.server.api.so.ISharedObjectService; import org.red5.server.exception.ScopeNotFoundException; import org.red5.server.util.ScopeUtils; /** * Public methods for XML-RPC scope statistics service. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class XmlRpcScopeStatistics { /** * Global scope */ private IScope globalScope; /** Constructs a new XmlScopeStatistics. */ public XmlRpcScopeStatistics() { } /** * Create new scope statistic. * * @param globalScope Global scope ref */ public XmlRpcScopeStatistics(IScope globalScope) { this.globalScope = globalScope; } /** * Setter for global scope. * * @param scope Value to set for property 'globalScope'. */ public void setGlobalScope(IScope scope) { globalScope = scope; } /** * Resolve path to scope. * * @param path Path to return scope for * @return The scope for the given path * * @throws ScopeNotFoundException Thrown when scope with given path can't be resolved */ private IScope getScope(String path) throws ScopeNotFoundException { IScope scope; if (path != null && !path.equals("")) { scope = ScopeUtils.resolveScope(globalScope, path); } else { scope = globalScope; } if (scope == null) { throw new ScopeNotFoundException(globalScope, path); } return scope; } /** * Return available applications. * * @return list of application names */ public String[] getScopes() { return getScopes(null); } /** * Return subscopes of another scope. * * @param path Path of scope to return subscopes of * @return List of subscope names */ public String[] getScopes(String path) { IScope scope = getScope(path); Set result = scope.getScopeNames(); return result.toArray(new String[result.size()]); } /** * Return attributes of the global scope. * * @return The scope's attributes */ public Map getScopeAttributes() { return getScopeAttributes(null); } /** * Return an object that can be serialized through XML-RPC. * Inspired by "Reflective XML-RPC" by "Stephan Maier". * * @param value * @return */ private Object getXMLRPCValue(Object value) { if (value == null) { return ""; } Class type = value.getClass(); if (type.equals(Integer.class) || type.equals(Double.class) || type.equals(Boolean.class) || type.equals(String.class) || type.equals(Date.class)) { return value; } else if (type.equals(Long.class)) { // XXX: long values are not supported by XML-RPC, convert to string // instead return ((Long) value).toString(); } else if (type.isArray() && type.getComponentType().equals(byte.class)) { return value; } else if (type.isArray()) { int length = Array.getLength(value); Vector res = new Vector(); for (int i = 0; i < length; i++) { res.add(getXMLRPCValue(Array.get(value, i))); } return res; } else if (value instanceof Map) { Hashtable res = new Hashtable(); for (Map.Entry entry : ((Map) value).entrySet()) { res.put(entry.getKey(), getXMLRPCValue(entry.getValue())); } return res; } else if (value instanceof Collection) { Collection coll = (Collection) value; Vector result = new Vector(coll.size()); for (Object item : coll) { result.add(getXMLRPCValue(item)); } return result; } throw new RuntimeException("Don't know how to convert " + value); } /** * Return attributes of a given scope. * * @param path Path of scope to return attributes of * @return The scope's attributes */ public Map getScopeAttributes(String path) { IScope scope = getScope(path); Map result = new Hashtable(); for (String name : scope.getAttributeNames()) { Object value = scope.getAttribute(name); try { result.put(name, getXMLRPCValue(value)); } catch (RuntimeException err) { // Could not convert attribute for XML-RPC serialization. } } return result; } /** * Return informations about shared objects of a given scope. * * @param path Path of scope to return shared objects for * @return A mapping containing the shared object name -> (persistent, data) */ public Map getSharedObjects(String path) { IScope scope = getScope(path); ISharedObjectService service = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, false); if (service == null) { return new Hashtable(); } Map result = new Hashtable(); for (String name : service.getSharedObjectNames(scope)) { ISharedObject so = service.getSharedObject(scope, name); try { result.put(name, new Object[] { so.isPersistent(), getXMLRPCValue(so.getData()) }); } catch (RuntimeException err) { // Could not convert attribute for XML-RPC serialization. result.put(name, "--- Error while serializing \"" + so.getData().toString() + "\" ---"); } } return result; } } red5-1.0~svn4374.orig/src/org/red5/server/plugin/0000755000175000017500000000000011760512571021341 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/plugin/PluginDescriptor.java0000644000175000017500000000352011706617130025476 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.plugin; import java.util.Map; /** * Simple descriptor for plug-ins. * * @author Paul Gregoire */ public final class PluginDescriptor { private String pluginName; private String pluginType; private String method; private String methodReturnType; private Map properties; public String getPluginName() { return pluginName; } public void setPluginName(String pluginName) { this.pluginName = pluginName; } public String getPluginType() { return pluginType; } public void setPluginType(String pluginType) { this.pluginType = pluginType; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public String getMethodReturnType() { return methodReturnType; } public void setMethodReturnType(String methodReturnType) { this.methodReturnType = methodReturnType; } public Map getProperties() { return properties; } public void setProperties(Map properties) { this.properties = properties; } } red5-1.0~svn4374.orig/src/org/red5/server/plugin/PluginRegistry.java0000644000175000017500000001045511706617130025175 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.plugin; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.plugin.IRed5Plugin; import org.slf4j.Logger; /** * Central registry for Red5 plug-ins. * * @author Paul Gregoire */ public class PluginRegistry { private static Logger log = Red5LoggerFactory.getLogger(PluginRegistry.class, "plugins"); //keeps track of plug-ins, keyed by plug-in name private static volatile ConcurrentMap plugins = new ConcurrentHashMap(); //locks for guarding plug-ins private final static ReadWriteLock pluginLock = new ReentrantReadWriteLock(); private final static Lock pluginReadLock; private final static Lock pluginWriteLock; static { pluginReadLock = pluginLock.readLock(); pluginWriteLock = pluginLock.writeLock(); } /** * Registers a plug-in. * * @param plugin */ public static void register(IRed5Plugin plugin) { log.debug("Register plugin: {}", plugin); String pluginName = plugin.getName(); //get a write lock pluginWriteLock.lock(); try { if (plugins.containsKey(pluginName)) { //get old plugin IRed5Plugin oldPlugin = plugins.get(pluginName); //if they are not the same shutdown the older one if (!plugin.equals(oldPlugin)) { try { oldPlugin.doStop(); } catch (Exception e) { log.warn("Exception caused when stopping old plugin", e); } //replace old one plugins.replace(pluginName, plugin); } } else { plugins.put(pluginName, plugin); } } finally { pluginWriteLock.unlock(); } } /** * Unregisters a plug-in. * * @param plugin */ public static void unregister(IRed5Plugin plugin) { log.debug("Unregister plugin: {}", plugin); //get a write lock pluginWriteLock.lock(); try { if (plugins.containsValue(plugin)) { boolean removed = false; for (Entry f : plugins.entrySet()) { if (plugin.equals(f.getValue())) { log.debug("Removing {}", plugin); plugins.remove(f.getKey()); removed = true; break; } else { log.debug("Not equal - {} {}", plugin, f.getValue()); } } if (!removed) { log.debug("Last try to remove the plugin"); plugins.remove(plugin.getName()); } } else { log.warn("Plugin is not registered {}", plugin); } } finally { pluginWriteLock.unlock(); } } /** * Returns a plug-in. * * @param pluginName * @return requested plug-in matching the name given or null if not found */ public static IRed5Plugin getPlugin(String pluginName) { IRed5Plugin plugin = null; pluginReadLock.lock(); try { plugin = plugins.get(pluginName); } finally { pluginReadLock.unlock(); } return plugin; } /** * Shuts down the registry and stops any plug-ins that are found. * * @throws Exception */ public static void shutdown() throws Exception { log.info("Destroying and cleaning up {} plugins", plugins.size()); //loop through the plugins and stop them pluginReadLock.lock(); try { for (Entry plugin : plugins.entrySet()) { plugin.getValue().doStop(); } } finally { pluginReadLock.unlock(); } plugins.clear(); } } red5-1.0~svn4374.orig/src/org/red5/server/plugin/PluginLauncher.java0000644000175000017500000001164211706617130025125 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.plugin; import java.io.File; import java.io.FilenameFilter; import java.lang.reflect.Method; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; import org.red5.server.Server; import org.red5.server.api.plugin.IRed5Plugin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * Creates the plug-in environment and cleans up on shutdown. * * @author Paul Gregoire (mondain@gmail.com) */ public class PluginLauncher implements ApplicationContextAware, InitializingBean, DisposableBean { // Initialize Logging protected static Logger log = LoggerFactory.getLogger(PluginLauncher.class); /** * Spring application context */ private ApplicationContext applicationContext; public void afterPropertiesSet() throws Exception { ApplicationContext common = (ApplicationContext) applicationContext.getBean("red5.common"); Server server = (Server) common.getBean("red5.server"); //server should be up and running at this point so load any plug-ins now //get the plugins dir File pluginsDir = new File(System.getProperty("red5.root"), "plugins"); File[] plugins = pluginsDir.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { //lower the case String tmp = name.toLowerCase(); //accept jars and zips return tmp.endsWith(".jar") || tmp.endsWith(".zip"); } }); if (plugins != null) { IRed5Plugin red5Plugin = null; log.debug("{} plugins to launch", plugins.length); for (File plugin : plugins) { JarFile jar = new JarFile(plugin, false); Manifest manifest = jar.getManifest(); if (manifest == null) { continue; } Attributes attributes = manifest.getMainAttributes(); if (attributes == null) { continue; } String pluginMainClass = attributes.getValue("Red5-Plugin-Main-Class"); if (pluginMainClass == null || pluginMainClass.length() <= 0) { continue; } // attempt to load the class; since it's in the plugins directory this should work ClassLoader loader = common.getClassLoader(); Class pluginClass; String pluginMainMethod = null; try { pluginClass = Class.forName(pluginMainClass, true, loader); } catch (ClassNotFoundException e) { continue; } try { //handle plug-ins without "main" methods pluginMainMethod = attributes.getValue("Red5-Plugin-Main-Method"); if (pluginMainMethod == null || pluginMainMethod.length() <= 0) { //just get an instance of the class red5Plugin = (IRed5Plugin) pluginClass.newInstance(); } else { Method method = pluginClass.getMethod(pluginMainMethod, (Class[]) null); Object o = method.invoke(null, (Object[]) null); if (o != null && o instanceof IRed5Plugin) { red5Plugin = (IRed5Plugin) o; } } //register and start if (red5Plugin != null) { //set top-level context red5Plugin.setApplicationContext(applicationContext); //set server reference red5Plugin.setServer(server); //register the plug-in to make it available for lookups PluginRegistry.register(red5Plugin); //start the plugin red5Plugin.doStart(); } log.info("Loaded plugin: {}", pluginMainClass); } catch (Throwable t) { log.warn("Error loading plugin: {}; Method: {}", pluginMainClass, pluginMainMethod); log.error("", t); } } } else { log.info("Plugins directory cannot be accessed or doesnt exist"); } } public void destroy() throws Exception { PluginRegistry.shutdown(); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.debug("Setting application context"); this.applicationContext = applicationContext; } } red5-1.0~svn4374.orig/src/org/red5/server/plugin/Red5Plugin.java0000644000175000017500000000375411706617130024170 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.plugin; import org.red5.server.Server; import org.red5.server.adapter.MultiThreadedApplicationAdapter; import org.red5.server.api.plugin.IRed5Plugin; import org.springframework.context.ApplicationContext; /** * Provides more features to the plug-in system. * * @author Paul Gregoire (mondain@gmail.com) */ public abstract class Red5Plugin implements IRed5Plugin { protected ApplicationContext context; protected Server server; /** {@inheritDoc} */ public void doStart() throws Exception { } /** {@inheritDoc} */ public void doStop() throws Exception { } /** * Initialize the plug-in */ public void init() { } /** {@inheritDoc} */ public String getName() { return null; } /** {@inheritDoc} */ public void setApplicationContext(ApplicationContext context) { this.context = context; } /** * Return the server reference. * * @return server */ public Server getServer() { return server; } /** {@inheritDoc} */ public void setServer(Server server) { this.server = server; } /** * Set the application making use of this plug-in. * * @param application */ public void setApplication(MultiThreadedApplicationAdapter application) { } } red5-1.0~svn4374.orig/src/org/red5/server/LoaderBase.java0000644000175000017500000001222211706617130022703 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.io.File; import java.util.HashMap; import java.util.Map; import org.red5.server.api.IApplicationContext; import org.red5.server.api.IApplicationLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * Base class for all JEE application loaders. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public abstract class LoaderBase implements ApplicationContextAware { private static Logger log = LoggerFactory.getLogger(LoaderBase.class); /** * We store the application context so we can access it later. */ protected static ApplicationContext applicationContext = null; /** * Current Red5 application context, set by the different loaders. */ public static Map red5AppCtx = new HashMap(); /** * Loader for new applications. */ protected static ThreadLocal loader = new ThreadLocal(); /** * Folder containing the webapps. */ protected String webappFolder = null; /** * Getter for the application loader. * * @return Application loader */ public static IApplicationLoader getApplicationLoader() { log.debug("Get application loader"); return loader.get(); } /** * Setter for the application loader. * * @param loader Application loader */ public static void setApplicationLoader(IApplicationLoader loader) { log.debug("Set application loader: {}", loader); LoaderBase.loader.set(loader); } /** * Returns the map containing all of the registered Red5 application contexts. * * @return a map */ public static Map getRed5ApplicationContexts() { log.debug("Get all red5 application contexts"); return red5AppCtx; } /** * Getter for a Red5 application context. * @param path path * * @return Red5 application context */ public static IApplicationContext getRed5ApplicationContext(String path) { log.debug("Get red5 application context - path: {}", path); //log.trace("Map at get: {}", red5AppCtx); return red5AppCtx.get(path); } /** * Setter for a Red5 application context. * @param path path * * @param context Red5 application context */ public static void setRed5ApplicationContext(String path, IApplicationContext context) { log.debug("Set red5 application context - path: {} context: {}", path, context); //log.trace("Map at set: {}", red5AppCtx); if (context != null) { red5AppCtx.put(path, context); } else { red5AppCtx.remove(path); } //log.trace("Map after set: {}", red5AppCtx); } /** * Remover for a Red5 application context. * @param path path * * @return Red5 application context */ public static IApplicationContext removeRed5ApplicationContext(String path) { log.debug("Remove red5 application context - path: {}", path); return red5AppCtx.remove(path); } /** * Getter for application context * @return Application context */ public static ApplicationContext getApplicationContext() { log.debug("Get application context: {}", applicationContext); return applicationContext; } /** * Setter for application context. * * @param context Application context * @throws BeansException Abstract superclass for all exceptions thrown in the beans * package and subpackages */ public void setApplicationContext(ApplicationContext context) throws BeansException { log.debug("Set application context: {}", context); applicationContext = context; } /** * Set the folder containing webapps. * * @param webappFolder web app folder */ public void setWebappFolder(String webappFolder) { File fp = new File(webappFolder); if (!fp.canRead()) { throw new RuntimeException(String.format("Webapp folder %s cannot be accessed.", webappFolder)); } if (!fp.isDirectory()) { throw new RuntimeException(String.format("Webapp folder %s doesn't exist.", webappFolder)); } fp = null; this.webappFolder = webappFolder; } /** * Remove context from the current host. * * @param path Path */ public void removeContext(String path) { throw new UnsupportedOperationException(); } /** * Entry point to shutdown this loader. */ public abstract void shutdown(); } red5-1.0~svn4374.orig/src/org/red5/server/ClientList.java0000644000175000017500000000521711706617130022762 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.beans.ConstructorProperties; import java.lang.ref.WeakReference; import java.util.AbstractList; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * Client list, implemented using weak references to prevent memory leaks. * * @author Paul Gregoire (mondain@gmail.com) * @param * type of class */ public class ClientList extends AbstractList { private CopyOnWriteArrayList> items = new CopyOnWriteArrayList>(); @ConstructorProperties(value = { "" }) public ClientList() { } @ConstructorProperties({"c"}) public ClientList(Collection c) { addAll(0, c); } public boolean add(E element) { return items.add(new WeakReference(element)); } public void add(int index, E element) { items.add(index, new WeakReference(element)); } @Override public E remove(int index) { WeakReference ref = items.remove(index); return ref.get(); } @Override public boolean remove(Object o) { boolean removed = false; E element = null; for (WeakReference ref : items) { element = ref.get(); if (element != null && element.equals(o)) { ref.clear(); removed = true; break; } } return removed; } @Override public boolean contains(Object o) { List list = new ArrayList(); for (WeakReference ref : items) { if (ref.get() != null) { list.add(ref.get()); } } boolean contains = list.contains(o); list.clear(); list = null; return contains; } public int size() { removeReleased(); return items.size(); } public E get(int index) { return (items.get(index)).get(); } private void removeReleased() { for (WeakReference ref : items) { if (ref.get() == null) { items.remove(ref); } } } } red5-1.0~svn4374.orig/src/org/red5/server/Client.java0000644000175000017500000002352311747114732022133 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.beans.ConstructorProperties; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.management.openmbean.CompositeData; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.red5.server.api.persistence.IPersistable; import org.red5.server.api.scope.IScope; import org.red5.server.stream.bandwidth.ClientServerDetection; import org.red5.server.stream.bandwidth.ServerClientDetection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Client is an abstraction representing user connected to Red5 application. * Clients are tied to connections and registered in ClientRegistry */ public class Client extends AttributeStore implements IClient { protected static Logger log = LoggerFactory.getLogger(Client.class); /** * Name of connection attribute holding the permissions. */ protected static final String PERMISSIONS = IPersistable.TRANSIENT_PREFIX + "_red5_permissions"; /** * Scopes this client connected to */ protected ConcurrentMap connToScope = new ConcurrentHashMap(); /** * Creation time as Timestamp */ protected long creationTime; /** * Clients identifier */ protected String id; /** * Client registry where Client is registered */ protected WeakReference registry; /** * Whether or not the bandwidth has been checked. */ protected boolean bandwidthChecked; /** * Creates client, sets creation time and registers it in ClientRegistry * DW: nope, does not currently register it in ClientRegistry! * * @param id Client id * @param registry ClientRegistry */ @ConstructorProperties({ "id", "registry" }) public Client(String id, ClientRegistry registry) { super(); this.id = id; // use a weak reference to prevent any hard-links to the registry this.registry = new WeakReference(registry); this.creationTime = System.currentTimeMillis(); } /** * Disconnects client from Red5 application */ public void disconnect() { log.debug("Disconnect - id: {}", id); if (connToScope != null && !connToScope.isEmpty()) { log.debug("Closing {} connections", connToScope.size()); // close all connections held to Red5 by client for (IConnection con : getConnections()) { try { con.close(); } catch (Exception e) { // closing a connection calls into application code, so exception possible log.error("Unexpected exception closing connection {}", e); } } } else { log.debug("Connection map is empty or null"); } // unregister client removeInstance(); } /** * Return set of connections for this client * * @return Set of connections */ public Set getConnections() { return connToScope.keySet(); } /** * Return client connections to given scope * * @param scope Scope * @return Set of connections for that scope */ public Set getConnections(IScope scope) { if (scope == null) { return getConnections(); } Set result = new HashSet(connToScope.size()); for (Entry entry : connToScope.entrySet()) { if (scope.equals(entry.getValue())) { result.add(entry.getKey()); } } return result; } /** * Sets the time at which the client was created. * * @param creationTime */ public void setCreationTime(long creationTime) { this.creationTime = creationTime; } /** * Returns the time at which the client was created. * * @return creation time */ public long getCreationTime() { return creationTime; } /** * Sets the client id */ public void setId(String id) { this.id = id; } /** * Returns the client id * @return client id */ public String getId() { return id; } /** * * @return scopes on this client */ public Collection getScopes() { return connToScope.values(); } /** * Iterate through the scopes and their attributes. * Used by JMX * * @return list of scope attributes */ public List iterateScopeNameList() { log.debug("iterateScopeNameList called"); int scopeCount = connToScope.values().size(); List scopeNames = new ArrayList(scopeCount); log.debug("Scopes: {}", scopeCount); for (IScope scope : connToScope.values()) { log.debug("Client scope: {}", scope); for (Map.Entry entry : scope.getAttributes().entrySet()) { log.debug("Client scope attr: {} = {}", entry.getKey(), entry.getValue()); } } return scopeNames; } /** * Associate connection with client * @param conn Connection object */ protected void register(IConnection conn) { log.debug("Registering connection for this client {}", id); if (conn != null) { IScope scp = conn.getScope(); if (scp != null) { connToScope.put(conn, scp); } else { log.warn("Clients scope is null. Id: {}", id); } } else { log.warn("Clients connection is null. Id: {}", id); } } /** * Removes client-connection association for given connection * @param conn Connection object */ protected void unregister(IConnection conn) { unregister(conn, true); } /** * Removes client-connection association for given connection * @param conn Connection object * @param deleteIfNoConns Whether to delete this client if it no longer has any connections */ protected void unregister(IConnection conn, boolean deleteIfNoConns) { // Remove connection from connected scopes list connToScope.remove(conn); // If client is not connected to any scope any longer then remove if (deleteIfNoConns && connToScope.isEmpty()) { // TODO DW dangerous the way this is called from BaseConnection.initialize(). Could we unexpectedly pop a Client out of the registry? removeInstance(); } } /** {@inheritDoc} */ public boolean isBandwidthChecked() { return bandwidthChecked; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") public Collection getPermissions(IConnection conn) { Collection result = (Collection) conn.getAttribute(PERMISSIONS); if (result == null) { result = Collections.emptySet(); } return result; } /** {@inheritDoc} */ public boolean hasPermission(IConnection conn, String permissionName) { final Collection permissions = getPermissions(conn); return permissions.contains(permissionName); } /** {@inheritDoc} */ public void setPermissions(IConnection conn, Collection permissions) { if (permissions == null) { conn.removeAttribute(PERMISSIONS); } else { conn.setAttribute(PERMISSIONS, permissions); } } /** {@inheritDoc} */ public void checkBandwidth() { log.debug("Check bandwidth"); bandwidthChecked = true; //do something to check the bandwidth, Dan what do you think? ServerClientDetection detection = new ServerClientDetection(); detection.checkBandwidth(Red5.getConnectionLocal()); } /** {@inheritDoc} */ public Map checkBandwidthUp(Object[] params) { log.debug("Check bandwidth: {}", Arrays.toString(params)); bandwidthChecked = true; //do something to check the bandwidth, Dan what do you think? ClientServerDetection detection = new ClientServerDetection(); // if dynamic bw is turned on, we switch to a higher or lower return detection.checkBandwidth(params); } /** * Allows for reconstruction via CompositeData. * * @param cd composite data * @return Client class instance */ public static Client from(CompositeData cd) { Client instance = null; if (cd.containsKey("id")) { String id = (String) cd.get("id"); instance = new Client(id, null); instance.setCreationTime((Long) cd.get("creationTime")); instance.setAttribute(PERMISSIONS, cd.get(PERMISSIONS)); } if (cd.containsKey("attributes")) { AttributeStore attrs = (AttributeStore) cd.get("attributes"); instance.setAttributes(attrs); } return instance; } /** * Removes this instance from the client registry. */ private void removeInstance() { // unregister client ClientRegistry ref = registry.get(); if (ref != null) { ref.removeClient(this); } else { log.warn("Client registry reference was not accessable, removal failed"); // TODO: attempt to lookup the registry via the global.clientRegistry } } /** * if overriding equals then also do hashCode * @return a has code */ @Override public int hashCode() { return Integer.valueOf(id); } /** * Check clients equality by id * * @param obj Object to check against * @return true if clients ids are the same, false otherwise */ @Override public boolean equals(Object obj) { if (obj instanceof Client) { return ((Client) obj).getId().equals(id); } return false; } /** * * @return string representation of client */ @Override public String toString() { return "Client: " + id; } } red5-1.0~svn4374.orig/src/org/red5/server/ContextLoader.java0000644000175000017500000003304011751004261023451 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.io.File; import java.io.IOException; import java.lang.management.ManagementFactory; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.StandardMBean; import org.red5.server.jmx.mxbeans.ContextLoaderMXBean; import org.red5.server.plugin.PluginRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; import org.springframework.core.io.Resource; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.web.context.support.XmlWebApplicationContext; /** * Red5 applications loader * * @author The Red5 Project (red5@osflash.org) * @author Tiago Jacobs (tiago@imdt.com.br) * @author Paul Gregoire (mondain@gmail.com) */ @ManagedResource(objectName = "org.red5.server:name=contextLoader,type=ContextLoader", description = "ContextLoader") public class ContextLoader implements ApplicationContextAware, InitializingBean, DisposableBean, ContextLoaderMXBean { protected static Logger log = LoggerFactory.getLogger(ContextLoader.class); /** * Spring Application context */ protected ApplicationContext applicationContext; /** * Spring parent app context */ protected ApplicationContext parentContext; /** * Context location files */ protected String contextsConfig; /** * MBean object name used for de/registration purposes. */ private ObjectName oName; /** * Context map */ protected ConcurrentMap contextMap; /** * Whether or not a JVM shutdown hook should be added to * the Spring application context. */ private boolean useShutdownHook; /** * Registers with JMX and registers a shutdown hook. * * @throws Exception I/O exception, casting exception and others */ public void afterPropertiesSet() throws Exception { log.info("ContextLoader init"); // register in jmx registerJMX(); //check to see if we should add a shutdown hook if (useShutdownHook) { //register a jvm shutdown hook ((AbstractApplicationContext) applicationContext).registerShutdownHook(); } // initialize init(); } /** * Un-loads or un-initializes the contexts; this is a shutdown method for this loader. */ public void destroy() throws Exception { log.info("ContextLoader un-init"); shutdown(); //if theres no jee loader then exit System.exit(0); } /** * Loads context settings from ResourceBundle (.properties file) */ public void init() throws IOException { // Load properties bundle Properties props = new Properties(); Resource res = applicationContext.getResource(contextsConfig); if (res.exists()) { // Load properties file props.load(res.getInputStream()); // Pattern for arbitrary property substitution Pattern patt = Pattern.compile("\\$\\{([^\\}]+)\\}"); Matcher matcher = null; // Iterate thru properties keys and replace config attributes with // system attributes for (Object key : props.keySet()) { String name = (String) key; String config = props.getProperty(name); String configReplaced = config + ""; // matcher = patt.matcher(config); //execute the regex while (matcher.find()) { String sysProp = matcher.group(1); String systemPropValue = System.getProperty(sysProp); if (systemPropValue == null) { systemPropValue = "null"; } configReplaced = configReplaced.replace(String.format("${%s}", sysProp), systemPropValue); } log.info("Loading: {} = {}", name, config + " => " + configReplaced); matcher.reset(); // Load context loadContext(name, configReplaced); } patt = null; matcher = null; } else { log.error("Contexts config must be set"); } } /** * Loads a context (Red5 application) and stores it in a context map, then adds * it's beans to parent (that is, Red5) * * @param name Context name * @param config Filename */ public void loadContext(String name, String config) { log.debug("Load context - name: {} config: {}", name, config); //check the existence of the config file try { File configFile = new File(config); if (!configFile.exists()) { log.warn("Config file was not found at: {}", configFile.getCanonicalPath()); configFile = new File("file://" + config); if (!configFile.exists()) { log.warn("Config file was not found at either: {}", configFile.getCanonicalPath()); } else { config = "file://" + config; } } } catch (IOException e) { log.error("Error looking for config file", e); } // add the context to the parent, this will be red5.xml ConfigurableBeanFactory factory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory(); if (factory.containsSingleton(name)) { log.warn("Singleton {} already exists, try unload first", name); return; } // if parent context was not set then lookup red5.common if (parentContext == null) { log.debug("Lookup common - bean:{} local:{} singleton:{}", new Object[] { factory.containsBean("red5.common"), factory.containsLocalBean("red5.common"), factory.containsSingleton("red5.common"), }); parentContext = (ApplicationContext) factory.getBean("red5.common"); } if (config.startsWith("/")) { // Spring always interprets files as relative, so will strip a leading slash unless we tell // it otherwise. It also appears to not need this for Windows // absolute paths (e.g. C:\Foo\Bar) so we don't catch that either String newConfig = "file://" + config; log.debug("Resetting {} to {}", config, newConfig); config = newConfig; } ApplicationContext context = new FileSystemXmlApplicationContext(new String[] { config }, parentContext); log.debug("Adding to context map - name: {} context: {}", name, context); if (contextMap == null) { contextMap = new ConcurrentHashMap(); } contextMap.put(name, context); // Register context in parent bean factory log.debug("Registering - name: {}", name); factory.registerSingleton(name, context); } /** * Unloads a context (Red5 application) and removes it from the context map, then removes * it's beans from the parent (that is, Red5) * * @param name Context name */ public void unloadContext(String name) { log.debug("Un-load context - name: {}", name); ApplicationContext context = contextMap.remove(name); log.debug("Context from map: {}", context); String[] bnames = BeanFactoryUtils.beanNamesIncludingAncestors(context); for (String bname : bnames) { log.debug("Bean: {}", bname); } ConfigurableBeanFactory factory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory(); if (factory.containsSingleton(name)) { log.debug("Context found in parent, destroying: {}", name); FileSystemXmlApplicationContext ctx = (FileSystemXmlApplicationContext) factory.getSingleton(name); if (ctx.isRunning()) { log.debug("Context was running, attempting to stop"); ctx.stop(); } if (ctx.isActive()) { log.debug("Context is active, attempting to close"); ctx.close(); } try { factory.destroyBean(name, ctx); } catch (Exception e) { log.warn("Context destroy failed for: {}", name, e); ctx.destroy(); } finally { if (factory.containsSingleton(name)) { log.debug("Singleton still exists, trying another destroy method"); ((DefaultListableBeanFactory) factory).destroySingleton(name); } } } else { log.debug("Context does not contain singleton: {}", name); } context = null; } /** * Shut server down. */ public void shutdown() { log.info("Shutting down server"); unregisterJMX(); //shutdown the plug-in launcher here try { PluginRegistry.shutdown(); } catch (Exception e) { log.warn("Exception shutting down plugin registry", e); } if (contextMap != null) { log.debug("Context map: {}", contextMap); try { //unload all the contexts in the map for (Map.Entry entry : contextMap.entrySet()) { String contextName = entry.getKey(); log.debug("Unloading context {} on uninit", contextName); unloadContext(contextName); } contextMap.clear(); } catch (Exception e) { log.warn("Exception shutting down contexts", e); } } try { // look up any shutdown enabled beans LoaderBase loader = BeanFactoryUtils.beanOfTypeIncludingAncestors(applicationContext, LoaderBase.class); if (loader != null) { loader.shutdown(); } else { log.debug("Loader was not found"); } } catch (Exception e) { log.warn("Exception looking for loader", e); } } /** * Return context by name * * @param name Context name * @return Application context for given name */ public ApplicationContext getContext(String name) { if (contextMap != null) { return contextMap.get(name); } else { return null; } } /** * Sets a parent context for child context based on a given key. * * @param parentContextKey key for the parent context * @param appContextId id of the child context */ public void setParentContext(String parentContextKey, String appContextId) { log.debug("Set parent context {} on {}", parentContextKey, appContextId); ApplicationContext parentContext = getContext(parentContextKey); if (parentContext != null) { XmlWebApplicationContext childContext = (XmlWebApplicationContext) getContext(appContextId); if (childContext != null) { childContext.setParent(parentContext); } else { log.debug("Child context not found"); } } else { log.debug("Parent context not found"); } } protected void registerJMX() { // register with jmx MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { oName = new ObjectName("org.red5.server:name=contextLoader,type=ContextLoader"); // check for existing registration before registering if (!mbs.isRegistered(oName)) { mbs.registerMBean(new StandardMBean(this, ContextLoaderMXBean.class, true), oName); } else { log.debug("ContextLoader is already registered in JMX"); } } catch (Exception e) { log.warn("Error on jmx registration", e); } } protected void unregisterJMX() { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { mbs.unregisterMBean(oName); } catch (Exception e) { log.warn("Exception unregistering: {}", oName, e); } oName = null; } /** * @param applicationContext Spring application context * @throws BeansException Top level exception for app context (that is, in fact, beans * factory) */ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } /** * Setter for parent application context * * @param parentContext Parent Spring application context */ public void setParentContext(ApplicationContext parentContext) { this.parentContext = parentContext; } /** * Return parent context * * @return parent application context */ public ApplicationContext getParentContext() { return parentContext; } /** * Setter for context config name * * @param contextsConfig Context config name */ public void setContextsConfig(String contextsConfig) { this.contextsConfig = contextsConfig; } public String getContextsConfig() { return contextsConfig; } /** * Whether or not the shutdown hook is enabled. * * @return true if enabled, false otherwise */ public boolean isUseShutdownHook() { return useShutdownHook; } /** * Enables or disables the shutdown hook. * * @param useShutdownHook true to enable, false to disable */ public void setUseShutdownHook(boolean useShutdownHook) { this.useShutdownHook = useShutdownHook; } } red5-1.0~svn4374.orig/src/org/red5/server/Launcher.java0000644000175000017500000000544311706617130022452 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.Red5; import org.slf4j.Logger; import org.slf4j.bridge.SLF4JBridgeHandler; import org.springframework.context.support.FileSystemXmlApplicationContext; /** * Launches Red5. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class Launcher { /* static { ClassLoader tcl = Thread.currentThread().getContextClassLoader(); System.out.printf("[Launcher] Classloaders:\nSystem %s\nParent %s\nThis class %s\nTCL %s\n\n", ClassLoader.getSystemClassLoader(), tcl.getParent(), Launcher.class.getClassLoader(), tcl); } */ /** * Launch Red5 under it's own classloader */ public void launch() { System.out.printf("Root: %s\nDeploy type: %s\nLogback selector: %s\n", System.getProperty("red5.root"), System.getProperty("red5.deployment.type"), System.getProperty("logback.ContextSelector")); try { //install the slf4j bridge (mostly for JUL logging) SLF4JBridgeHandler.install(); //we create the logger here so that it is instanced inside the expected //classloader Logger log = Red5LoggerFactory.getLogger(Launcher.class); //version info banner log.info("{} (http://code.google.com/p/red5/)", Red5.getVersion()); //pimp red5 System.out.printf("%s (http://code.google.com/p/red5/)\n", Red5.getVersion()); //create red5 app context FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(new String[] { "classpath:/red5.xml" }, false); //set the current threads classloader as the loader for the factory/appctx ctx.setClassLoader(Thread.currentThread().getContextClassLoader()); //refresh must be called before accessing the bean factory ctx.refresh(); /* if (log.isTraceEnabled()) { String[] names = ctx.getBeanDefinitionNames(); for (String name : names) { log.trace("Bean name: {}", name); } } */ } catch (Throwable t) { System.out.printf("Exception %s\n", t); System.exit(9999); } } } red5-1.0~svn4374.orig/src/org/red5/server/scope/0000755000175000017500000000000011760512574021157 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/scope/GlobalScope.java0000644000175000017500000000536011754746347024232 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.scope; import org.red5.server.api.IServer; import org.red5.server.api.persistence.IPersistenceStore; import org.red5.server.api.persistence.PersistenceUtils; import org.red5.server.api.scope.IGlobalScope; import org.red5.server.api.scope.ScopeType; import org.red5.server.jmx.mxbeans.GlobalScopeMXBean; import org.springframework.jmx.export.annotation.ManagedResource; /** * Global scope is a top level scope. Server instance is meant to be injected * with Spring before initialization (otherwise NullPointerException is thrown). * * @see org.red5.server.api.scope.IGlobalScope * @see org.red5.server.api.scope.IScope * @see org.red5.server.scope.Scope */ @ManagedResource public class GlobalScope extends Scope implements IGlobalScope, GlobalScopeMXBean { // Red5 Server instance protected IServer server; { type = ScopeType.GLOBAL; name = "default"; } /** * * @param persistenceClass Persistent class name * @throws Exception Exception */ @Override public void setPersistenceClass(String persistenceClass) throws Exception { this.persistenceClass = persistenceClass; // We'll have to wait for creation of the store object // until all classes have been initialized. } /** * Get persistence store for scope * * @return Persistence store */ @Override public IPersistenceStore getStore() { if (store == null) { try { store = PersistenceUtils.getPersistenceStore(this, this.persistenceClass); } catch (Exception error) { log.error("Could not create persistence store.", error); store = null; } } return store; } /** * Setter for server * * @param server Server */ public void setServer(IServer server) { this.server = server; } /** {@inheritDoc} */ @Override public IServer getServer() { return server; } /** * Register global scope in server instance, then call initialization */ public void register() { server.registerGlobal(this); init(); } } red5-1.0~svn4374.orig/src/org/red5/server/scope/ScopeResolver.java0000644000175000017500000000653011747114732024620 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.scope; import java.util.Arrays; import org.apache.commons.lang3.StringUtils; import org.red5.server.api.scope.IGlobalScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeResolver; import org.red5.server.api.scope.ScopeType; import org.red5.server.exception.ScopeNotFoundException; import org.red5.server.exception.ScopeShuttingDownException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Resolves scopes from path */ public class ScopeResolver implements IScopeResolver { protected static Logger log = LoggerFactory.getLogger(ScopeResolver.class); /** * Global scope */ protected IGlobalScope globalScope; /** * Getter for global scope * @return Global scope */ public IGlobalScope getGlobalScope() { return globalScope; } /** * Setter for global scope * @param root Global scope */ public void setGlobalScope(IGlobalScope root) { this.globalScope = root; } /** * Return scope associated with given path * * @param path Scope path * @return Scope object */ public IScope resolveScope(String path) { // start from global scope return resolveScope(globalScope, path); } /** * Return scope associated with given path from given root scope. * * @param root Scope to start from * @param path Scope path * @return Scope object */ public IScope resolveScope(IScope root, String path) { log.debug("resolveScope - root: {} path: {}", root, path); // start from root scope IScope scope = root; // if there's no path return root scope (e.i. root path scope) if (StringUtils.isNotEmpty(path)) { // Split path to parts final String[] parts = path.split("/"); log.debug("Split path: {}", Arrays.toString(parts)); // Iterate thru them, skip empty parts for (String child : parts) { if (StringUtils.isEmpty(child)) { // skip empty path elements continue; } if (scope.hasChildScope(child)) { scope = scope.getScope(child); } else if (!scope.equals(root)) { // no need for sync here, scope.children is concurrent if (scope.createChildScope(child)) { scope = scope.getScope(child); } } // if the scope is still equal to root then the room was not found if (scope == root) { throw new ScopeNotFoundException(scope, child); } if (scope.getType().equals(ScopeType.APPLICATION) && ((WebScope) scope).isShuttingDown()) { throw new ScopeShuttingDownException(scope); } } } return scope; } } red5-1.0~svn4374.orig/src/org/red5/server/scope/BroadcastScope.java0000644000175000017500000002054411747114732024722 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.scope; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.red5.server.api.scope.IBroadcastScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.ScopeType; import org.red5.server.api.stream.IClientBroadcastStream; import org.red5.server.messaging.IConsumer; import org.red5.server.messaging.IMessage; import org.red5.server.messaging.IPipeConnectionListener; import org.red5.server.messaging.IProvider; import org.red5.server.messaging.InMemoryPushPushPipe; import org.red5.server.messaging.OOBControlMessage; import org.red5.server.messaging.PipeConnectionEvent; import org.red5.server.stream.IProviderService; /** * Scope type for publishing that deals with pipe connection events, * like async message listening in JMS */ public class BroadcastScope extends BasicScope implements IBroadcastScope, IPipeConnectionListener { /** * Broadcasting stream associated with this scope */ private IClientBroadcastStream clientBroadcastStream; /** * Simple in memory push pipe, triggered by an active provider to push messages to consumer */ private InMemoryPushPushPipe pipe; /** * Number of components. */ private AtomicInteger compCounter; /** * Remove flag */ private boolean hasRemoved; /** * Lock for critical sections, to prevent concurrent modification. * A "fairness" policy is used wherein the longest waiting thread * will be granted access before others. */ protected Lock lock = new ReentrantLock(true); /** * Creates broadcast scope * @param parent Parent scope * @param name Scope name */ public BroadcastScope(IScope parent, String name) { super(parent, ScopeType.BROADCAST, name, false); pipe = new InMemoryPushPushPipe(); pipe.addPipeConnectionListener(this); compCounter = new AtomicInteger(0); hasRemoved = false; keepOnDisconnect = true; } /** * Register pipe connection event listener with this scope's pipe. * A listener that wants to listen to events when * provider/consumer connects to or disconnects from * a specific pipe. * @param listener Pipe connection event listener * * @see org.red5.server.messaging.IPipeConnectionListener */ public void addPipeConnectionListener(IPipeConnectionListener listener) { pipe.addPipeConnectionListener(listener); } /** * Unregisters pipe connection event listener with this scope's pipe * @param listener Pipe connection event listener * * @see org.red5.server.messaging.IPipeConnectionListener */ public void removePipeConnectionListener(IPipeConnectionListener listener) { pipe.removePipeConnectionListener(listener); } /** * Pull message from pipe * @return Message object * * @see org.red5.server.messaging.IMessage */ public IMessage pullMessage() { return pipe.pullMessage(); } /** * Pull message with timeout * @param wait Timeout * @return Message object * * @see org.red5.server.messaging.IMessage */ public IMessage pullMessage(long wait) { return pipe.pullMessage(wait); } /** * Connect scope's pipe to given consumer * * @param consumer Consumer * @param paramMap Parameters passed with connection * @return true on success, false otherwise */ public boolean subscribe(IConsumer consumer, Map paramMap) { lock(); try { return !hasRemoved && pipe.subscribe(consumer, paramMap); } finally { unlock(); } } /** * Disconnects scope's pipe from given consumer * @param consumer Consumer * @return true on success, false otherwise */ public boolean unsubscribe(IConsumer consumer) { return pipe.unsubscribe(consumer); } /** * Getter for pipe consumers * @return Pipe consumers */ public List getConsumers() { return pipe.getConsumers(); } /** * Send out-of-band ("special") control message * * @param consumer Consumer, may be used in concrete implementations * @param oobCtrlMsg Out-of-band control message */ public void sendOOBControlMessage(IConsumer consumer, OOBControlMessage oobCtrlMsg) { pipe.sendOOBControlMessage(consumer, oobCtrlMsg); } /** * Push a message to this output endpoint. May block * the pusher when output can't handle the message at * the time. * @param message Message to be pushed. * @throws IOException If message could not be pushed. */ public void pushMessage(IMessage message) throws IOException { pipe.pushMessage(message); } /** * Connect scope's pipe with given provider * @param provider Provider * @param paramMap Parameters passed on connection * @return true on success, false otherwise */ public boolean subscribe(IProvider provider, Map paramMap) { lock(); try { return !hasRemoved && pipe.subscribe(provider, paramMap); } finally { unlock(); } } /** * Disconnects scope's pipe from given provider * @param provider Provider * @return true on success, false otherwise */ public boolean unsubscribe(IProvider provider) { lock(); try { return pipe.unsubscribe(provider); } finally { unlock(); } } /** * Getter for providers list * @return List of providers */ public List getProviders() { return pipe.getProviders(); } /** * Send out-of-band ("special") control message * * @param provider Provider, may be used in concrete implementations * @param oobCtrlMsg Out-of-band control message */ public void sendOOBControlMessage(IProvider provider, OOBControlMessage oobCtrlMsg) { pipe.sendOOBControlMessage(provider, oobCtrlMsg); } /** * Pipe connection event handler * @param event Pipe connection event */ public void onPipeConnectionEvent(PipeConnectionEvent event) { // Switch event type switch (event.getType()) { case PipeConnectionEvent.CONSUMER_CONNECT_PULL: case PipeConnectionEvent.CONSUMER_CONNECT_PUSH: case PipeConnectionEvent.PROVIDER_CONNECT_PULL: case PipeConnectionEvent.PROVIDER_CONNECT_PUSH: compCounter.incrementAndGet(); break; case PipeConnectionEvent.CONSUMER_DISCONNECT: case PipeConnectionEvent.PROVIDER_DISCONNECT: if (compCounter.decrementAndGet() <= 0) { // XXX should we synchronize parent before removing? if (hasParent()) { IProviderService providerService = (IProviderService) getParent().getContext().getBean(IProviderService.BEAN_NAME); providerService.unregisterBroadcastStream(getParent(), getName()); } hasRemoved = true; } break; default: throw new UnsupportedOperationException("Event type not supported: " + event.getType()); } } public void lock() { lock.lock(); } public void unlock() { lock.unlock(); } /** * Returns the client broadcast stream */ public IClientBroadcastStream getClientBroadcastStream() { return clientBroadcastStream; } /** * Sets the client broadcast stream * * @param clientBroadcastStream */ public void setClientBroadcastStream(IClientBroadcastStream clientBroadcastStream) { this.clientBroadcastStream = clientBroadcastStream; } } red5-1.0~svn4374.orig/src/org/red5/server/scope/RoomScope.java0000644000175000017500000000041311747114732023725 0ustar drazzibdrazzibpackage org.red5.server.scope; import org.red5.server.api.scope.ScopeType; /** * Represents a subscope to other scopes. * * @author Paul Gregoire (mondain@gmail.com) */ public class RoomScope extends Scope { { type = ScopeType.ROOM; } } red5-1.0~svn4374.orig/src/org/red5/server/scope/BasicScope.java0000644000175000017500000001716711754746347024063 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.scope; import java.beans.ConstructorProperties; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.red5.server.api.event.IEvent; import org.red5.server.api.event.IEventListener; import org.red5.server.api.persistence.IPersistenceStore; import org.red5.server.api.scheduling.IScheduledJob; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.api.scope.IBasicScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.ScopeType; import org.red5.server.util.ScopeUtils; /** * Generalizations of one of main Red5 object types, Scope. * * @see org.red5.server.api.scope.IScope * @see org.red5.server.scope.Scope */ public abstract class BasicScope implements IBasicScope { /** * Parent scope. Scopes can be nested. * * @see org.red5.server.api.scope.IScope */ protected IScope parent; /** * Scope type. * * @see org.red5.server.api.scope.ScopeType */ protected ScopeType type = ScopeType.UNDEFINED; /** * String identifier for this scope */ protected String name; /** * Whether or not to persist attributes */ protected boolean persistent; /** * Storage for persistable attributes */ protected IPersistenceStore store; /** * Scope persistence storage type */ protected String persistenceClass; /** * Set to true to prevent the scope from being freed upon disconnect. */ protected boolean keepOnDisconnect = false; /** * Set to amount of time (in seconds) the scope will be kept before being freed, * after the last disconnect. */ protected int keepDelay = 0; /** * List of event listeners */ protected Set listeners; /** * Creates unnamed scope */ @ConstructorProperties(value = { "" }) public BasicScope() { } /** * Constructor for basic scope * * @param parent Parent scope * @param type Scope type * @param name Scope name. Used to identify scopes in application, must be unique among scopes of one level * @param persistent Whether scope is persistent */ @ConstructorProperties({ "parent", "type", "name", "persistent" }) public BasicScope(IScope parent, ScopeType type, String name, boolean persistent) { this.parent = parent; this.type = type; this.name = name; this.persistent = persistent; this.listeners = new HashSet(); } /** * {@inheritDoc} */ public boolean hasParent() { return true; } /** *{@inheritDoc} */ public IScope getParent() { return parent; } /** * @return the type */ public ScopeType getType() { return type; } /** * @return the name */ public String getName() { return name; } /** * @return the store */ public IPersistenceStore getStore() { return store; } /** *{@inheritDoc} */ public int getDepth() { return parent.getDepth() + 1; } /** *{@inheritDoc} */ @Override public String getPath() { return parent.getPath() + '/' + parent.getName(); } /** * Sets the amount of time to keep the scope available after the * last disconnect. * * @param keepDelay delay */ public void setKeepDelay(int keepDelay) { this.keepDelay = keepDelay; } /** * Validates a scope based on its name and type * * @return true if both name and type are valid, false otherwise */ public boolean isValid() { // to be valid a scope must have a type set other than undefined and its name will be set return (type != null && !type.equals(ScopeType.UNDEFINED) && (name != null && !("").equals(name))); } /** * Add event listener to list of notified objects * @param listener Listening object */ public void addEventListener(IEventListener listener) { listeners.add(listener); } /** * Remove event listener from list of listeners * @param listener Listener to remove */ public void removeEventListener(IEventListener listener) { listeners.remove(listener); if (!keepOnDisconnect) { if (ScopeUtils.isRoom(this) && listeners.isEmpty()) { if (keepDelay > 0) { // create a job to keep alive for n seconds ISchedulingService schedulingService = (ISchedulingService) parent.getContext().getBean(ISchedulingService.BEAN_NAME); schedulingService.addScheduledOnceJob(keepDelay * 1000, new KeepAliveJob(this)); } else { // delete empty rooms parent.removeChildScope(this); } } } } /** * Return listeners list iterator * * @return Listeners list iterator */ public Set getEventListeners() { return Collections.unmodifiableSet(listeners); } /** * Returns true if there are event listeners attached to * this scope. * * @return true if it has listeners; else false. */ public boolean hasEventListeners() { return !listeners.isEmpty(); } /** * Handles event. To be implemented in subclass realization * * @param event Event context * @return Event handling result */ public boolean handleEvent(IEvent event) { return false; } /** * Notifies listeners on event. Current implementation is empty. To be implemented in subclass realization * @param event Event to broadcast */ public void notifyEvent(IEvent event) { } /** * Dispatches event (notifies all listeners) * * @param event Event to dispatch */ public void dispatchEvent(IEvent event) { for (IEventListener listener : listeners) { if (event.getSource() == null || event.getSource() != listener) { listener.notifyEvent(event); } } } /** * Hash code is based on the scope's name and type * * @return hash code */ public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } /** * Equality is based on the scope's name and type * * @param obj */ public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; BasicScope other = (BasicScope) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (type != other.type) return false; return true; } /** * Keeps the scope alive for a set number of seconds. */ private class KeepAliveJob implements IScheduledJob { private IBasicScope scope = null; KeepAliveJob(IBasicScope scope) { this.scope = scope; } public void execute(ISchedulingService service) { if (listeners.isEmpty()) { // delete empty rooms parent.removeChildScope(scope); } } } } red5-1.0~svn4374.orig/src/org/red5/server/scope/Scope.java0000644000175000017500000010150211751004261023057 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.scope; import java.beans.ConstructorProperties; import java.io.IOException; import java.lang.management.ManagementFactory; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Semaphore; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.StandardMBean; import javax.management.openmbean.CompositeData; import org.apache.commons.lang3.StringUtils; import org.red5.server.AttributeStore; import org.red5.server.Server; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.IContext; import org.red5.server.api.IServer; import org.red5.server.api.event.IEvent; import org.red5.server.api.persistence.PersistenceUtils; import org.red5.server.api.scope.IBasicScope; import org.red5.server.api.scope.IBroadcastScope; import org.red5.server.api.scope.IGlobalScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeAware; import org.red5.server.api.scope.IScopeHandler; import org.red5.server.api.scope.ScopeType; import org.red5.server.api.statistics.IScopeStatistics; import org.red5.server.api.statistics.support.StatisticsCounter; import org.red5.server.jmx.mxbeans.ScopeMXBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; import org.springframework.core.style.ToStringCreator; import org.springframework.jmx.export.annotation.ManagedResource; /** * The scope object. *

* A stateful object shared between a group of clients connected to the same * context path. Scopes are arranged in a hierarchical way, so its possible for * a scope to have a parent. If a client is connect to a scope then they are * also connected to its parent scope. The scope object is used to access * resources, shared object, streams, etc.

* Scope layout: *
 *  /Global scope - Contains application scopes
 *      /Application scope - Contains room, shared object, and stream scopes
 *          /Room scope - Contains other room, shared object, and / or stream scopes
 *              /Shared object scope - Contains shared object
 *              /Broadcast stream scope - Contains a broadcast stream
 * 
* * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) * @author Nathan Smith (nathgs@gmail.com) */ @ManagedResource(objectName = "org.red5.server:type=Scope", description = "Scope") public class Scope extends BasicScope implements IScope, IScopeStatistics, ScopeMXBean { protected static Logger log = LoggerFactory.getLogger(Scope.class); /** * Unset flag constant */ private static final int UNSET = -1; /** * Auto-start flag */ private boolean autoStart = true; /** * Child scopes */ private final ConcurrentScopeSet children = new ConcurrentScopeSet(); /** * Clients and connection map */ private final ConcurrentMap> clients = new ConcurrentHashMap>(); /** * Storage for scope attributes */ protected final AttributeStore attributes = new AttributeStore(); /** * Statistics about clients connected to the scope. */ protected final StatisticsCounter clientStats = new StatisticsCounter(); /** * Statistics about connections to the scope. */ protected final StatisticsCounter connectionStats = new StatisticsCounter(); /** * Statistics about sub-scopes. */ protected final StatisticsCounter subscopeStats = new StatisticsCounter(); /** * Scope context */ private IContext context; /** * Timestamp the scope was created. */ private long creationTime; /** * Scope nesting depth, unset by default */ private int depth = UNSET; /** * Whether scope is enabled */ private boolean enabled = true; /** * Scope handler */ private IScopeHandler handler; /** * Whether scope is running */ private boolean running; /** * Lock for critical sections, to prevent concurrent modification. * A "fairness" policy is used wherein the longest waiting thread will be granted access before others. */ protected Semaphore lock = new Semaphore(1, true); /** * Registered service handlers for this scope. The map is created on-demand * only if it's accessed for writing. */ private volatile ConcurrentMap serviceHandlers; /** * Mbean object name. */ protected ObjectName oName; { creationTime = System.currentTimeMillis(); } /** * Creates a scope */ @ConstructorProperties(value = { "" }) public Scope() { super(null, ScopeType.UNDEFINED, null, false); } /** * Creates scope using a Builder * * @param builder */ @ConstructorProperties({ "builder" }) public Scope(Builder builder) { super(builder.parent, builder.type, builder.name, builder.persistent); } /** * Add child scope to this scope * * @param scope Child scope * @return true on success (if scope has handler and it * accepts child scope addition), false otherwise */ public boolean addChildScope(IBasicScope scope) { log.debug("Add child: {}", scope); if (!children.contains(scope)) { if (scope.isValid()) { log.debug("Add child scope: {} to {}", scope, this); // if child scope has no persistence store, use same class as parent if (scope.getStore() == null) { try { if (scope instanceof Scope) { ((Scope) scope).setPersistenceClass(persistenceClass); } } catch (Exception error) { log.error("Could not set persistence class.", error); } } return children.add(scope); } else { log.warn("Invalid scope was not added: {}", scope); } } else { log.warn("Child scope already exists"); } return false; } /** * Connect to scope * * @param conn Connection object * @return true on success, false otherwise */ public boolean connect(IConnection conn) { return connect(conn, null); } /** * Connect to scope with parameters. To successfully connect to scope it * must have handler that will accept this connection with given set of * parameters. Client associated with connection is added to scope clients set, * connection is registered as scope event listener. * * @param conn Connection object * @param params Parameters passed with connection * @return true on success, false otherwise */ public boolean connect(IConnection conn, Object[] params) { log.debug("Connect: {}", conn); if (hasParent() && !parent.connect(conn, params)) { return false; } if (hasHandler() && !getHandler().connect(conn, this, params)) { return false; } final IClient client = conn.getClient(); if (!conn.isConnected()) { // timeout while connecting client return false; } // we would not get this far if there is no handler if (hasHandler() && !getHandler().join(client, this)) { return false; } // checking the connection again? why? if (!conn.isConnected()) { // Timeout while connecting client return false; } Set conns = clients.get(client); if (conns == null) { conns = new CopyOnWriteArraySet(); clients.put(client, conns); } conns.add(conn); clientStats.increment(); addEventListener(conn); connectionStats.increment(); IScope connScope = conn.getScope(); log.trace("Connection scope: {}", connScope); if (this.equals(connScope)) { final IServer server = getServer(); if (server instanceof Server) { ((Server) server).notifyConnected(conn); } } return true; } /** * Create child scope with given name * * @param name Child scope name * @return true on success, false otherwise */ public boolean createChildScope(String name) { final Scope scope = new Builder(this, ScopeType.ROOM, name, false).build(); return addChildScope(scope); } /** * Destroys scope */ public void destroy() { log.debug("Destroy scope"); if (hasParent()) { parent.removeChildScope(this); } if (hasHandler()) { // Because handler can be null when there is a parent handler getHandler().stop(this); } // kill all child scopes for (IBasicScope child : children) { removeChildScope(child); if (child instanceof Scope) { ((Scope) child).uninit(); } } } /** * Disconnect connection from scope * * @param conn Connection object */ public void disconnect(IConnection conn) { log.debug("Disconnect: {}", conn); // We call the disconnect handlers in reverse order they were called // during connection, i.e. roomDisconnect is called before // appDisconnect. final IClient client = conn.getClient(); if (client == null) { // Early bail out removeEventListener(conn); connectionStats.decrement(); if (hasParent()) { parent.disconnect(conn); } return; } // remove it if it exists final Set conns = clients.remove(client); if (conns != null) { // decrement if there was a set of connections clientStats.decrement(); conns.remove(conn); IScopeHandler handler = null; if (hasHandler()) { handler = getHandler(); try { handler.disconnect(conn, this); } catch (Exception e) { log.error("Error while executing \"disconnect\" for connection {} on handler {}. {}", new Object[] { conn, handler, e }); } } if (conns.isEmpty()) { if (handler != null) { try { // there may be a timeout here ? handler.leave(client, this); } catch (Exception e) { log.error("Error while executing \"leave\" for client {} on handler {}. {}", new Object[] { conn, handler, e }); } } } removeEventListener(conn); connectionStats.decrement(); if (this.equals(conn.getScope())) { final IServer server = getServer(); if (server instanceof Server) { ((Server) server).notifyDisconnected(conn); } } } if (hasParent()) { parent.disconnect(conn); } } /** {@inheritDoc} */ @Override public void dispatchEvent(IEvent event) { Collection> conns = getConnections(); for (Set set : conns) { for (IConnection conn : set) { try { conn.dispatchEvent(event); } catch (RuntimeException e) { log.error("Exception during dispatching event: {}", event, e); } } } } /** {@inheritDoc} */ public Object getAttribute(String name) { return attributes.getAttribute(name); } /** {@inheritDoc} */ public boolean setAttribute(String name, Object value) { return attributes.setAttribute(name, value); } /** {@inheritDoc} */ public boolean hasAttribute(String name) { return attributes.hasAttribute(name); } /** {@inheritDoc} */ public boolean removeAttribute(String name) { return attributes.removeAttribute(name); } /** {@inheritDoc} */ public Set getAttributeNames() { return attributes.getAttributeNames(); } /** {@inheritDoc} */ public Map getAttributes() { return attributes.getAttributes(); } /** {@inheritDoc} */ public int getActiveClients() { return clients.size(); } /** {@inheritDoc} */ public int getActiveConnections() { return connectionStats.getCurrent(); } /** {@inheritDoc} */ public int getActiveSubscopes() { return subscopeStats.getCurrent(); } /** * Return the broadcast scope for a given name * * @param name * @return broadcast scope or null if not found */ public IBroadcastScope getBroadcastScope(String name) { for (IBasicScope child : children) { if (child.getType().equals(ScopeType.BROADCAST) && child.getName().equals(name)) { log.debug("Returning broadcast scope"); return (IBroadcastScope) child; } } return null; } /** * Return base scope of given type with given name * * @param type Scope type * @param name Scope name * @return Basic scope object */ public IBasicScope getBasicScope(ScopeType type, String name) { for (IBasicScope child : children) { if (child.getType().equals(type) && child.getName().equals(name)) { log.debug("Returning basic scope"); return child; } } return null; } /** * Return basic scope names matching given type * * @param type Scope type * @return set of scope names */ public Set getBasicScopeNames(ScopeType type) { if (type != null) { Set names = new HashSet(); for (IBasicScope child : children) { if (child.getType().equals(type)) { names.add(child.getName()); } } return names; } else { return getScopeNames(); } } /** * Return current thread context classloader * * @return Current thread context classloader */ public ClassLoader getClassLoader() { return getContext().getClassLoader(); } /** * Return set of clients * * @return Set of clients bound to scope */ public Set getClients() { return clients.keySet(); } /** * Return connection iterator * * @return Connections iterator */ public Collection> getConnections() { return clients.values(); } /** * Return scope context. If scope doesn't have context, parent's context is * returns, and so forth. * * @return Scope context or parent context */ public IContext getContext() { if (!hasContext() && hasParent()) { //log.debug("returning parent context"); return parent.getContext(); } else { //log.debug("returning context"); return context; } } /** * Return scope context path * * @return Scope context path */ public String getContextPath() { if (hasContext()) { return ""; } else if (hasParent()) { return parent.getContextPath() + '/' + name; } else { return null; } } /** {@inheritDoc} */ public long getCreationTime() { return creationTime; } /** * return scope depth * * @return Scope depth */ @Override public int getDepth() { if (depth == UNSET) { if (hasParent()) { depth = parent.getDepth() + 1; } else { depth = 0; } } return depth; } /** * Return scope handler or parent's scope handler if this scope doesn't have * one * * @return Scope handler (or parent's one) */ public IScopeHandler getHandler() { if (handler != null) { return handler; } else if (hasParent()) { return getParent().getHandler(); } else { return null; } } /** {@inheritDoc} */ public int getMaxClients() { return clientStats.getMax(); } /** {@inheritDoc} */ public int getMaxConnections() { return connectionStats.getMax(); } /** {@inheritDoc} */ public int getMaxSubscopes() { return subscopeStats.getMax(); } /** * Return parent scope * * @return Parent scope */ @Override public IScope getParent() { return parent; } /** * Return scope path calculated from parent path and parent scope name * * @return Scope path */ @Override public String getPath() { if (hasParent()) { return parent.getPath() + '/' + parent.getName(); } else { return ""; } } /** * Return resource located at given path * * @param path Resource path * @return Resource */ public Resource getResource(String path) { if (hasContext()) { return context.getResource(path); } return getContext().getResource(getContextPath() + '/' + path); } /** * Return array of resources from path string, usually used with pattern * path * * @param path Resources path * @return Resources * @throws IOException I/O exception */ public Resource[] getResources(String path) throws IOException { if (hasContext()) { return context.getResources(path); } return getContext().getResources(getContextPath() + '/' + path); } /** * Return child scope by name * * @param name Scope name * @return Child scope with given name */ public IScope getScope(String name) { for (IBasicScope child : children) { if (child.getName().equals(name)) { log.debug("Returning child scope"); return (IScope) child; } } return null; } /** * Return child scope names iterator * * @return Child scope names iterator */ public Set getScopeNames() { log.debug("Children: {}", children); Set names = new HashSet(); for (IBasicScope child : children) { names.add(child.getName()); } return names; } /** * Return service handler by name * * @param name Handler name * @return Service handler with given name */ public Object getServiceHandler(String name) { Map serviceHandlers = getServiceHandlers(false); if (serviceHandlers == null) { return null; } return serviceHandlers.get(name); } /** * Return set of service handler names. Removing entries from the set * unregisters the corresponding service handler. * * @return Set of service handler names */ @SuppressWarnings("unchecked") public Set getServiceHandlerNames() { Map serviceHandlers = getServiceHandlers(false); if (serviceHandlers == null) { return Collections.EMPTY_SET; } return serviceHandlers.keySet(); } /** * Return map of service handlers. The map is created if it doesn't exist * yet. * * @return Map of service handlers */ protected Map getServiceHandlers() { return getServiceHandlers(true); } /** * Return map of service handlers and optionally created it if it doesn't * exist. * * @param allowCreate * Should the map be created if it doesn't exist? * @return Map of service handlers */ protected Map getServiceHandlers(boolean allowCreate) { if (serviceHandlers == null) { if (allowCreate) { serviceHandlers = new ConcurrentHashMap(); } } return serviceHandlers; } /** {@inheritDoc} */ public IScopeStatistics getStatistics() { return this; } /** {@inheritDoc} */ public int getTotalClients() { return clientStats.getTotal(); } /** {@inheritDoc} */ public int getTotalConnections() { return connectionStats.getTotal(); } /** {@inheritDoc} */ public int getTotalSubscopes() { return subscopeStats.getTotal(); } /** * Handles event. To be implemented in subclasses. * * @param event Event to handle * @return true on success, false otherwise */ @Override public boolean handleEvent(IEvent event) { return false; } /** * Check whether scope has child scope with given name * * @param name Child scope name * @return true if scope has child node with given name, * false otherwise */ public boolean hasChildScope(String name) { log.debug("Has child scope? {} in {}", name, this); for (IBasicScope child : children) { if (child.getName().equals(name)) { log.debug("Child scope exists"); return true; } } log.debug("Child scope does not exist"); return false; } /** * Check whether scope has child scope with given name and type * * @param type Child scope type * @param name Child scope name * @return true if scope has child node with given name and * type, false otherwise */ public boolean hasChildScope(ScopeType type, String name) { log.debug("Has child scope? {} in {}", name, this); for (IBasicScope child : children) { if (child.getName().equals(name) && child.getType().equals(type)) { log.debug("Child scope exists"); return true; } } return false; } /** * Check if scope has a context * * @return true if scope has context, false * otherwise */ public boolean hasContext() { return context != null; } /** * Check if scope or it's parent has handler * * @return true if scope or it's parent scope has a handler, * false otherwise */ public boolean hasHandler() { return (handler != null || (hasParent() && getParent().hasHandler())); } /** * Check if scope has parent scope * * @return true if scope has parent scope, false * otherwise` */ @Override public boolean hasParent() { return (parent != null); } /** * Initialization actions, start if autostart is set to true */ public void init() { log.debug("Init scope: {} parent: {}", name, parent); if (hasParent()) { if (parent.addChildScope(this)) { log.debug("Scope added to parent"); } else { return; } } else { log.debug("Scope has no parent"); } if (autoStart) { start(); } } /** * Uninitialize scope and unregister from parent. */ public void uninit() { log.debug("Un-init scope"); for (IBasicScope child : children) { if (child instanceof Scope) { ((Scope) child).uninit(); } } stop(); if (hasParent()) { if (parent.hasChildScope(name)) { parent.removeChildScope(this); } } } /** * Check if scope is enabled * * @return true if scope is enabled, false * otherwise */ public boolean isEnabled() { return enabled; } /** * Here for JMX only, uses isEnabled() */ public boolean getEnabled() { return isEnabled(); } /** * Check if scope is in running state * * @return true if scope is in running state, * false otherwise */ public boolean isRunning() { return running; } /** * Here for JMX only, uses isEnabled() */ public boolean getRunning() { return isRunning(); } /** * Looks up connections for client * * @param client Client * @return Connection */ public Set lookupConnections(IClient client) { return clients.get(client); } /** * Register service handler by name * * @param name Service handler name * @param handler Service handler */ public void registerServiceHandler(String name, Object handler) { Map serviceHandlers = getServiceHandlers(); serviceHandlers.put(name, handler); } /** * Removes child scope * * @param scope Child scope to remove */ public void removeChildScope(IBasicScope scope) { log.debug("removeChildScope: {}", scope); if (hasChildScope(scope.getName())) { // remove from parent children.remove(scope); if (scope instanceof Scope) { unregisterJMX(); } } } /** * Removes all the child scopes */ public void removeChildren() { for (IBasicScope child : children) { removeChildScope(child); } } /** * Setter for autostart flag * * @param autoStart Autostart flag value */ public void setAutoStart(boolean autoStart) { this.autoStart = autoStart; } /** * Setter for child load path. Should be implemented in subclasses? * * @param pattern Load path pattern */ public void setChildLoadPath(String pattern) { } /** * Setter for context * * @param context Context object */ public void setContext(IContext context) { log.debug("Set context: {}", context); this.context = context; } /** * Set scope depth * * @param depth Scope depth */ public void setDepth(int depth) { this.depth = depth; } /** * Enable or disable scope by setting enable flag * * @param enabled Enable flag value */ public void setEnabled(boolean enabled) { this.enabled = enabled; } /** * Setter for scope event handler * * @param handler Event handler */ public void setHandler(IScopeHandler handler) { log.debug("Set handler: {}", handler); this.handler = handler; if (handler instanceof IScopeAware) { ((IScopeAware) handler).setScope(this); } } /** * Setter for scope name * * @param name Scope name */ @Override public void setName(String name) { log.debug("Set name: {}", name); if (oName != null) { unregisterJMX(); } this.name = name; if (StringUtils.isNotBlank(name)) { registerJMX(); } } /** * Setter for parent scope * * @param parent Parent scope */ public void setParent(IScope parent) { log.debug("Set parent scope: {}", parent); this.parent = parent; } /** * Set scope persistence class * * @param persistenceClass Scope's persistence class * @throws Exception Exception */ public void setPersistenceClass(String persistenceClass) throws Exception { this.persistenceClass = persistenceClass; if (persistenceClass != null) { store = PersistenceUtils.getPersistenceStore(this, persistenceClass); } } /** * Starts scope * * @return true if scope has handler and it's start method * returned true, false otherwise */ public boolean start() { log.debug("Start scope"); boolean result = false; if (enabled && !running) { // check for any handlers if (hasHandler()) { try { lock.acquire(); // if we dont have a handler of our own dont try to start it if (handler != null) { result = handler.start(this); } } catch (Throwable e) { log.error("Could not start scope {} {}", this, e); } finally { lock.release(); } } else { // Always start scopes without handlers log.debug("Scope {} has no handler, allowing start", this); result = true; } running = result; } return result; } /** * Stops scope */ public void stop() { log.debug("Stop scope"); if (enabled && running && handler != null) { try { lock.acquire(); // if we dont have a handler of our own dont try to stop it handler.stop(this); } catch (Throwable e) { log.error("Could not stop scope {}", this, e); } finally { lock.release(); } } running = false; } /** * {@inheritDoc} */ @Override public String toString() { final ToStringCreator tsc = new ToStringCreator(this); return tsc.append("Depth", getDepth()).append("Path", getPath()).append("Name", getName()).toString(); } /** * Unregisters service handler by name * * @param name Service handler name */ public void unregisterServiceHandler(String name) { Map serviceHandlers = getServiceHandlers(false); if (serviceHandlers == null) { return; } serviceHandlers.remove(name); } /** * Return the server instance connected to this scope. * * @return the server instance */ public IServer getServer() { if (!hasParent()) { return null; } final IScope parent = getParent(); if (parent instanceof Scope) { return ((Scope) parent).getServer(); } else if (parent instanceof IGlobalScope) { return ((IGlobalScope) parent).getServer(); } else { return null; } } //for debugging public void dump() { if (log.isDebugEnabled()) { log.debug("Scope: {} {}", this.getClass().getName(), this); log.debug("Running: {}", running); if (hasParent()) { log.debug("Parent: {}", parent); Set names = parent.getBasicScopeNames(null); log.debug("Sibling count: {}", names.size()); for (String sib : names) { log.debug("Siblings - {}", sib); } names = null; } log.debug("Handler: {}", handler); log.debug("Child count: {}", children.size()); for (IBasicScope entry : children) { log.debug("Child: {}", entry); } } } protected void registerJMX() { // register with jmx MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { String cName = this.getClass().getName(); if (cName.indexOf('.') != -1) { cName = cName.substring(cName.lastIndexOf('.')).replaceFirst("[\\.]", ""); } oName = new ObjectName(String.format("org.red5.server:type=%s,name=%s", cName, name)); mbs.registerMBean(new StandardMBean(this, ScopeMXBean.class, true), oName); } catch (Exception e) { log.warn("Error on jmx registration", e); } } protected void unregisterJMX() { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); if (oName != null && mbs.isRegistered(oName)) { try { mbs.unregisterMBean(oName); } catch (Exception e) { log.warn("Exception unregistering: {}", oName, e); } oName = null; } } /** * Allows for reconstruction via CompositeData. * * @param cd composite data * @return Scope class instance */ public static Scope from(CompositeData cd) { IScope parent = null; ScopeType type = ScopeType.UNDEFINED; String name = null; boolean persistent = false; if (cd.containsKey("parent")) { parent = (IScope) cd.get("parent"); } if (cd.containsKey("type")) { type = (ScopeType) cd.get("type"); } if (cd.containsKey("name")) { name = (String) cd.get("name"); } if (cd.containsKey("persistent")) { persistent = (Boolean) cd.get("persistent"); } return new Scope(new Builder(parent, type, name, persistent)); } @SuppressWarnings({ "hiding", "serial" }) private final class ConcurrentScopeSet extends CopyOnWriteArraySet { @Override public boolean add(IBasicScope scope) { if (scope instanceof IScope) { return add((IScope) scope); } else { log.debug("Adding basic scope to scope set"); if (hasHandler() && !getHandler().addChildScope((org.red5.server.api.scope.IBasicScope) scope)) { log.debug("Failed to add child scope: {} to {}", scope, this); return false; } boolean added = super.add(scope); if (added) { subscopeStats.increment(); } return added; } } public boolean add(IScope scope) { log.debug("Adding scope to scope set"); if (hasHandler()) { // add the scope to the handler if (!getHandler().addChildScope(scope)) { log.debug("Failed to add child scope: {} to {}", scope, this); return false; } // start the scope if (!getHandler().start((IScope) scope)) { log.debug("Failed to start child scope: {} in {}", scope, this); return false; } } // add the entry @SuppressWarnings("unchecked") boolean added = super.add((IBasicScope) scope); if (added) { subscopeStats.increment(); // post notification IServer server = getServer(); ((Server) server).notifyScopeCreated((IScope) scope); } return added; } @Override public boolean remove(Object scope) { log.debug("Remove child scope: {}", scope); if (hasHandler()) { log.debug("Remove child scope"); getHandler().removeChildScope((org.red5.server.api.scope.IBasicScope) scope); } if (scope instanceof IScope) { if (hasHandler()) { getHandler().stop((IScope) scope); } // remove all children ((IScope) scope).removeChildren(); // post notification final IServer server = getServer(); if (server instanceof Server) { ((Server) server).notifyScopeRemoved((IScope) scope); } } // remove the entry boolean removed = super.remove(scope); if (removed) { subscopeStats.decrement(); } return removed; } } /** * Builder pattern */ public final static class Builder { private IScope parent; private ScopeType type; private String name; private boolean persistent; public Builder(IScope parent, ScopeType type, String name, boolean persistent) { this.parent = parent; this.type = type; this.name = name; this.persistent = persistent; } public Scope build() { return new Scope(this); } } } red5-1.0~svn4374.orig/src/org/red5/server/scope/WebScope.java0000644000175000017500000002021511747114732023530 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.scope; import java.util.Collection; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import javax.servlet.ServletContext; import org.red5.server.LoaderBase; import org.red5.server.api.IApplicationContext; import org.red5.server.api.IApplicationLoader; import org.red5.server.api.IConnection; import org.red5.server.api.IServer; import org.red5.server.api.scope.IGlobalScope; import org.red5.server.api.scope.ScopeType; import org.red5.server.jmx.mxbeans.WebScopeMXBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.web.context.ServletContextAware; /** *

Web scope is special scope that is aware of servlet context and represents * scope of a Red5 application within a servlet container (or application server) * such as Tomcat, Jetty or JBoss.

*

Web scope is aware of virtual hosts configuration for Red5 application and is * the first scope that instantiated after Red5 application gets started.

*

Then it loads virtual hosts configuration, adds mappings of paths to global * scope that is injected thru Spring IoC context file and runs initialization process.

* * Red5 server implementation instance and ServletContext are injected as well. */ @ManagedResource public class WebScope extends Scope implements ServletContextAware, WebScopeMXBean { /** * Logger */ protected static Logger log = LoggerFactory.getLogger(WebScope.class); /** * Server instance */ protected IServer server; /** * Servlet context */ protected ServletContext servletContext; /** * Context path */ protected String contextPath; /** * Virtual hosts list as string */ protected String virtualHosts; /** * Hostnames */ protected String[] hostnames; /** * Has the web scope been registered? */ protected AtomicBoolean registered = new AtomicBoolean(false); /** * The application context this webscope is running in. */ protected IApplicationContext appContext; /** * Loader for new applications. */ protected IApplicationLoader appLoader; /** * Is the scope currently shutting down? */ protected AtomicBoolean shuttingDown = new AtomicBoolean(false); { type = ScopeType.APPLICATION; } /** * Setter for global scope. Sets persistence class. * * @param globalScope Red5 global scope */ public void setGlobalScope(IGlobalScope globalScope) { log.trace("Set global scope: {}", globalScope); // XXX: this is called from nowhere, remove? super.setParent(globalScope); try { setPersistenceClass(globalScope.getStore().getClass().getName()); } catch (Exception error) { log.error("Could not set persistence class.", error); } } /** * Web scope has no name */ public void setName() { throw new RuntimeException("Cannot set name, you must set context path"); } /** * Can't set parent to Web scope. Web scope is top level. */ public void setParent() { throw new RuntimeException("Cannot set parent, you must set global scope"); } /** * Setter for server * * @param server Server instance */ public void setServer(IServer server) { log.info("Set server {}", server); this.server = server; } /** * Servlet context * * @param servletContext Servlet context */ public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } /** * Setter for context path * * @param contextPath Context path */ public void setContextPath(String contextPath) { this.contextPath = contextPath; super.setName(contextPath.substring(1)); } /** * Return scope context path * * @return Scope context path */ @Override public String getContextPath() { return contextPath; } /** * Setter for virtual hosts. Creates array of hostnames. * * @param virtualHosts Virtual hosts list as string */ public void setVirtualHosts(String virtualHosts) { this.virtualHosts = virtualHosts; // Split string into array of vhosts hostnames = virtualHosts.split(","); for (int i = 0; i < hostnames.length; i++) { hostnames[i] = hostnames[i].trim(); if (hostnames[i].equals("*")) { hostnames[i] = ""; } } } /** * Map all vhosts to global scope then initialize */ public void register() { if (registered.get()) { log.info("Webscope already registered"); return; } log.debug("Webscope registering: {}", contextPath); getAppContext(); appLoader = LoaderBase.getApplicationLoader(); //get the parent name String parentName = getParent().getName(); //add host name mappings if (hostnames != null && hostnames.length > 0) { for (String hostName : hostnames) { server.addMapping(hostName, getName(), parentName); } } init(); // don't free configured scopes when a client disconnects keepOnDisconnect = true; registered.set(true); } /** * Uninitialize and remove all vhosts from the global scope. */ public void unregister() { if (!registered.get()) { log.info("Webscope not registered"); return; } log.debug("Webscope un-registering: {}", contextPath); shuttingDown.set(true); keepOnDisconnect = false; uninit(); // We need to disconnect all clients before unregistering Collection> conns = getConnections(); for (Set set : conns) { for (IConnection conn : set) { conn.close(); } //should we clear the set? set.clear(); } // conns.clear(); // if (hostnames != null && hostnames.length > 0) { for (String element : hostnames) { server.removeMapping(element, getName()); } } //check for null if (appContext == null) { log.debug("Application context is null, trying retrieve from loader"); getAppContext(); } //try to stop the app context if (appContext != null) { log.debug("Stopping app context"); appContext.stop(); } else { log.debug("Application context is null, could not be stopped"); } // Various cleanup tasks store = null; setServletContext(null); setServer(null); setName(null); appContext = null; registered.set(false); shuttingDown.set(false); } /** {@inheritDoc} */ @Override public IServer getServer() { return server; } /** * Return object that can be used to load new applications. * * @return the application loader */ public IApplicationLoader getApplicationLoader() { return appLoader; } /** * Sets the local app context variable based on host id if available in the * servlet context. */ private final void getAppContext() { //get the host id String hostId = null; //get host from servlet context if (servletContext != null) { ServletContext sctx = servletContext.getContext(contextPath); if (sctx != null) { hostId = (String) sctx.getAttribute("red5.host.id"); log.trace("Host id from init param: {}", hostId); } } if (hostId != null) { appContext = LoaderBase.getRed5ApplicationContext(hostId + contextPath); } else { appContext = LoaderBase.getRed5ApplicationContext(contextPath); } } /** * Is the scope currently shutting down? * * @return is shutting down */ public boolean isShuttingDown() { return shuttingDown.get(); } } red5-1.0~svn4374.orig/src/org/red5/server/CoreHandler.java0000644000175000017500000001332511747114732023102 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import org.red5.server.api.IClient; import org.red5.server.api.IClientRegistry; import org.red5.server.api.IConnection; import org.red5.server.api.IContext; import org.red5.server.api.Red5; import org.red5.server.api.event.IEvent; import org.red5.server.api.scope.IBasicScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeHandler; import org.red5.server.api.service.IServiceCall; import org.red5.server.jmx.mxbeans.CoreHandlerMXBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base IScopeHandler implementation */ public class CoreHandler implements IScopeHandler, CoreHandlerMXBean { protected static Logger log = LoggerFactory.getLogger(CoreHandler.class); /** {@inheritDoc} */ public boolean addChildScope(IBasicScope scope) { return true; } /** * Connects client to the scope * * @param conn Client conneciton * @param scope Scope * @return true if client was registred within scope, false otherwise */ public boolean connect(IConnection conn, IScope scope) { return connect(conn, scope, null); } /** * Connects client to the scope * * @param conn Client connection * @param scope Scope * @param params Params passed from client side with connect call * @return true if client was registered within scope, false otherwise */ public boolean connect(IConnection conn, IScope scope, Object[] params) { // DW urrr this is a slightly strange place to do this, but this is where we create the Client object that consolidates connections // from a single client/FP. Now for more strangeness, I've only been looking at RTMPConnection derivatives, but it's setup() method // seems the only way that the session id is passed in to the newly established connection and this is currently *always* passed in // as null. I'm guessing that either the Flash Player passes some kind of unique id to us that is not being used, or that the idea // originally was to make our own session id, for example by combining client information with the IP address or something like that. log.debug("Connect to core handler"); boolean connect = false; // Get session id String id = conn.getSessionId(); log.trace("Session id: {}", id); // Use client registry from scope the client connected to. IScope connectionScope = Red5.getConnectionLocal().getScope(); log.debug("Connection scope: {}", (connectionScope == null ? "is null" : "not null")); // when the scope is null bad things seem to happen, if a null scope is OK then // this block will need to be removed - Paul if (connectionScope != null) { // Get client registry for connection scope IClientRegistry clientRegistry = connectionScope.getContext().getClientRegistry(); log.debug("Client registry: {}", (clientRegistry == null ? "is null" : "not null")); if (clientRegistry != null) { IClient client = null; if (conn.getClient() != null) { // this is an existing connection that is being moved to another scope server-side client = conn.getClient(); } else if (clientRegistry.hasClient(id)) { // Use session id as client id. DW this is required for remoting client = clientRegistry.lookupClient(id); } else { // This is a new connection. Create a new client to hold it client = clientRegistry.newClient(params); } // Assign connection to client conn.initialize(client); // we could checked for banned clients here connect = true; } else { log.error("No client registry was found, clients cannot be looked-up or created"); } } else { log.error("No connection scope was found"); } return connect; } /** {@inheritDoc} */ public void disconnect(IConnection conn, IScope scope) { // do nothing here } /** {@inheritDoc} */ public boolean join(IClient client, IScope scope) { return true; } /** {@inheritDoc} */ public void leave(IClient client, IScope scope) { // do nothing here } /** {@inheritDoc} */ public void removeChildScope(IBasicScope scope) { // do nothing here } /** * Remote method invocation * * @param conn Connection to invoke method on * @param call Service call context * @return true on success */ public boolean serviceCall(IConnection conn, IServiceCall call) { final IContext context = conn.getScope().getContext(); if (call.getServiceName() != null) { context.getServiceInvoker().invoke(call, context); } else { context.getServiceInvoker().invoke(call, conn.getScope().getHandler()); } return true; } /** {@inheritDoc} */ public boolean start(IScope scope) { return true; } /** {@inheritDoc} */ public void stop(IScope scope) { // do nothing here } /** {@inheritDoc} */ public boolean handleEvent(IEvent event) { return false; } } red5-1.0~svn4374.orig/src/org/red5/server/scheduling/0000755000175000017500000000000011760512571022170 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/scheduling/QuartzSchedulingServiceJob.java0000644000175000017500000000405611706617130030305 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.scheduling; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.red5.server.api.scheduling.IScheduledJob; import org.red5.server.api.scheduling.ISchedulingService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Scheduled job that is registered in the Quartz scheduler. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class QuartzSchedulingServiceJob implements Job { /** * Scheduling service constant */ protected static final String SCHEDULING_SERVICE = "scheduling_service"; /** * Scheduled job constant */ protected static final String SCHEDULED_JOB = "scheduled_job"; /** * Logger */ private Logger log = LoggerFactory.getLogger(QuartzSchedulingServiceJob.class); /** {@inheritDoc} */ public void execute(JobExecutionContext arg0) throws JobExecutionException { ISchedulingService service = (ISchedulingService) arg0.getJobDetail() .getJobDataMap().get(SCHEDULING_SERVICE); IScheduledJob job = (IScheduledJob) arg0.getJobDetail().getJobDataMap() .get(SCHEDULED_JOB); try { job.execute(service); } catch (Throwable e) { log.error("Job {} execution failed", job.toString(), e); } } } red5-1.0~svn4374.orig/src/org/red5/server/scheduling/ApplicationSchedulingService.java0000644000175000017500000001136211751004261030620 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright (c) 2006-2011 by respective authors (see below). All rights reserved. * * This library is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any later * version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.red5.server.scheduling; import java.lang.management.ManagementFactory; import java.util.Properties; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.StandardMBean; import javax.servlet.ServletContext; import org.quartz.impl.StdSchedulerFactory; import org.red5.logging.Red5LoggerFactory; import org.red5.server.jmx.mxbeans.QuartzSchedulingServiceMXBean; import org.slf4j.Logger; import org.springframework.jmx.export.annotation.ManagedResource; /** * This class can be used to initialize Quartz for a Red5 application. * * @author Paul Gregoire (mondain@gmail.com) */ @ManagedResource(objectName = "org.red5.server:type=ApplicationSchedulingService,name=default") public class ApplicationSchedulingService extends QuartzSchedulingService { private static Logger log = Red5LoggerFactory.getLogger(ApplicationSchedulingService.class); public static final String QUARTZ_FACTORY_KEY = "org.quartz.impl.StdSchedulerFactory.KEY"; private String applicationName; private String configFile; public String getApplicationName() { return applicationName; } public void setApplicationName(String applicationName) { this.applicationName = applicationName; } public String getConfigFile() { return configFile; } public void setConfigFile(String configFile) { this.configFile = configFile; } /** * Sets the scheduler factory in the servlet context. * * @param servletContext */ public void setServletAttribute(ServletContext servletContext) { log.debug("Storing the scheduler factory in the servlet context"); servletContext.setAttribute(QUARTZ_FACTORY_KEY, factory); } @Override public void afterPropertiesSet() throws Exception { log.info("Application scheduler initializing..."); try { //set properties if (configFile != null) { factory = new StdSchedulerFactory(configFile); } else { Properties props = new Properties(); props.put("org.quartz.scheduler.instanceName", applicationName + "_Scheduler"); props.put("org.quartz.scheduler.instanceId", "AUTO"); props.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); props.put("org.quartz.threadPool.threadCount", "2"); props.put("org.quartz.threadPool.threadPriority", "5"); props.put("org.quartz.jobStore.misfireThreshold", "60000"); props.put("org.quartz.jobStore.class", "org.quartz.simpl.RAMJobStore"); factory = new StdSchedulerFactory(props); } super.afterPropertiesSet(); } catch (Exception e) { log.error("Quartz Scheduler failed to initialize", e); } } protected void registerJMX() { //register with jmx server MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); try { ObjectName oName = null; if (instanceId == null) { oName = new ObjectName("org.red5.server:type=ApplicationSchedulingService,applicationName=" + applicationName); } else { oName = new ObjectName("org.red5.server:type=ApplicationSchedulingService,applicationName=" + applicationName + ",instanceId=" + instanceId); } mbeanServer.registerMBean(new StandardMBean(this, QuartzSchedulingServiceMXBean.class, true), oName); } catch (Exception e) { log.warn("Error on jmx registration", e); } } protected void unregisterJMX() { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { ObjectName oName = null; if (instanceId == null) { oName = new ObjectName("org.red5.server:type=ApplicationSchedulingService,applicationName=" + applicationName); } else { oName = new ObjectName("org.red5.server:type=ApplicationSchedulingService,applicationName=" + applicationName + ",instanceId=" + instanceId); } mbs.unregisterMBean(oName); } catch (Exception e) { log.warn("Exception unregistering", e); } } } red5-1.0~svn4374.orig/src/org/red5/server/scheduling/QuartzSchedulingService.java0000644000175000017500000001705611745776105027671 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.scheduling; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.SimpleTrigger; import org.quartz.Trigger; import org.quartz.impl.StdSchedulerFactory; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.scheduling.IScheduledJob; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.jmx.mxbeans.QuartzSchedulingServiceMXBean; import org.slf4j.Logger; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.jmx.export.annotation.ManagedResource; /** * Scheduling service that uses Quartz as backend. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ @ManagedResource(objectName = "org.red5.server:name=schedulingService,type=QuartzSchedulingService") public class QuartzSchedulingService implements ISchedulingService, QuartzSchedulingServiceMXBean, InitializingBean, DisposableBean { private static Logger log = Red5LoggerFactory.getLogger(QuartzSchedulingService.class); /** * Number of job details */ protected AtomicLong jobDetailCounter = new AtomicLong(0); /** * Creates schedulers. */ protected SchedulerFactory factory; /** * Service scheduler */ protected Scheduler scheduler; /** * Instance id */ protected String instanceId; /** Constructs a new QuartzSchedulingService. */ public void afterPropertiesSet() throws Exception { log.debug("Initializing..."); try { //create the standard factory if we dont have one if (factory == null) { factory = new StdSchedulerFactory(); } if (instanceId == null) { scheduler = factory.getScheduler(); } else { scheduler = factory.getScheduler(instanceId); } //start the scheduler if (scheduler != null) { scheduler.start(); } else { log.error("Scheduler was not started"); } } catch (SchedulerException ex) { throw new RuntimeException(ex); } } public void setFactory(SchedulerFactory factory) { this.factory = factory; } public void setInstanceId(String instanceId) { this.instanceId = instanceId; } // protected void registerJMX() { // //register with jmx server // MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); // try { // ObjectName oName = null; // if (instanceId == null) { // oName = new ObjectName("org.red5.server:name=" + this.getClass().getName()); // } else { // oName = new ObjectName("org.red5.server:name=" + this.getClass().getName() + ",instanceId=" + instanceId); // } // mbeanServer.registerMBean(this, oName); // } catch (Exception e) { // log.warn("Error on jmx registration", e); // } // } /** {@inheritDoc} */ public String addScheduledJob(int interval, IScheduledJob job) { String result = getJobName(); // Create trigger that fires indefinitely every milliseconds SimpleTrigger trigger = new SimpleTrigger("Trigger_" + result, null, new Date(), null, SimpleTrigger.REPEAT_INDEFINITELY, interval); scheduleJob(result, trigger, job); return result; } /** {@inheritDoc} */ public String addScheduledOnceJob(Date date, IScheduledJob job) { String result = getJobName(); // Create trigger that fires once at SimpleTrigger trigger = new SimpleTrigger("Trigger_" + result, null, date); scheduleJob(result, trigger, job); return result; } /** {@inheritDoc} */ public String addScheduledOnceJob(long timeDelta, IScheduledJob job) { // Create trigger that fires once in milliseconds return addScheduledOnceJob(new Date(System.currentTimeMillis() + timeDelta), job); } /** {@inheritDoc} */ public String addScheduledJobAfterDelay(int interval, IScheduledJob job, int delay) { String result = getJobName(); // Initialize the start time to now and add the delay. long startTime = System.currentTimeMillis() + delay; // Create trigger that fires indefinitely every milliseconds. SimpleTrigger trigger = new SimpleTrigger("Trigger_" + result, null, new Date(startTime), null, SimpleTrigger.REPEAT_INDEFINITELY, interval); // Schedule the job with Quartz. scheduleJob(result, trigger, job); // Return the job name. return result; } /** * Getter for job name. * * @return Job name */ public String getJobName() { String result = "ScheduledJob_" + jobDetailCounter.getAndIncrement(); return result; } /** {@inheritDoc} */ public List getScheduledJobNames() { List result = new ArrayList(); if (scheduler != null) { try { for (String name : scheduler.getJobNames(null)) { result.add(name); } } catch (SchedulerException ex) { throw new RuntimeException(ex); } } else { log.warn("No scheduler is available"); } return result; } /** {@inheritDoc} */ public void pauseScheduledJob(String name) { try { scheduler.pauseJob(name, null); } catch (SchedulerException ex) { throw new RuntimeException(ex); } } /** {@inheritDoc} */ public void resumeScheduledJob(String name) { try { scheduler.resumeJob(name, null); } catch (SchedulerException ex) { throw new RuntimeException(ex); } } public void pauseScheduledTrigger(String name) { try { scheduler.pauseTrigger("Trigger_" + name, null); } catch (SchedulerException ex) { throw new RuntimeException(ex); } } public void resumeScheduledTrigger(String name) { try { scheduler.resumeTrigger("Trigger_" + name, null); } catch (SchedulerException ex) { throw new RuntimeException(ex); } } /** {@inheritDoc} */ public void removeScheduledJob(String name) { try { scheduler.deleteJob(name, null); } catch (SchedulerException ex) { throw new RuntimeException(ex); } } /** * Schedules job * @param name Job name * @param trigger Job trigger * @param job Scheduled job object * * @see org.red5.server.api.scheduling.IScheduledJob */ private void scheduleJob(String name, Trigger trigger, IScheduledJob job) { if (scheduler != null) { // Store reference to applications job and service JobDetail jobDetail = new JobDetail(name, null, QuartzSchedulingServiceJob.class); jobDetail.getJobDataMap().put(QuartzSchedulingServiceJob.SCHEDULING_SERVICE, this); jobDetail.getJobDataMap().put(QuartzSchedulingServiceJob.SCHEDULED_JOB, job); try { scheduler.scheduleJob(jobDetail, trigger); } catch (SchedulerException ex) { throw new RuntimeException(ex); } } else { log.warn("No scheduler is available"); } } public void destroy() throws Exception { if (scheduler != null) { log.debug("Destroying..."); scheduler.shutdown(); } } } red5-1.0~svn4374.orig/src/org/red5/server/api/0000755000175000017500000000000011760512574020617 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/IApplicationLoader.java0000644000175000017500000000267711706617130025173 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import org.springframework.context.ApplicationContext; /** * Interface for servers that can load new applications. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IApplicationLoader { /** * Load a new application for the given context path from a directory. * * @param contextPath context path * @param virtualHosts virtual hosts * @param directory directory * @throws Exception for fun */ public void loadApplication(String contextPath, String virtualHosts, String directory) throws Exception; /** * Return the root {@link ApplicationContext}. * * @return application context */ public ApplicationContext getRootContext(); } red5-1.0~svn4374.orig/src/org/red5/server/api/IClient.java0000644000175000017500000001123011747114732023005 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import java.util.Collection; import java.util.Map; import java.util.Set; import org.red5.server.adapter.IApplication; import org.red5.server.api.scope.IScope; /** * The client object represents a single client. One client may have multiple * connections to different scopes on the same host. In some ways the client * object is like a HTTP session. You can create IClient objects with * {@link IClientRegistry#newClient(Object[])} * * * NOTE: I removed session, since client serves the same purpose as a client * with attributes * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) */ public interface IClient extends IAttributeStore { /** * The key used to store the client object in a http session. */ public static final String ID = "red5.client"; /** * Sets the clients id * @param id client id */ public void setId(String id); /** * Get the unique ID for this client. This will be generated by the server * if not passed upon connection from client-side Flex/Flash app. To assign a custom ID to the client use * params object of * {@link IApplication#appConnect(IConnection, Object[])} method, that * contains 2nd all the rest values you pass to * NetConnection.connect method. * * Example: * * At client side: * NetConnection.connect( "http://localhost/killerapp/", "user123" ); * * then at server side: * public boolean appConnect( IConnection connection, Object[] params ){
* try { * connection.getClient().setId( (String) params[0] ); * } catch(Exception e){
* log.error("{}", e); * } * } *
* * @return client id */ public String getId(); /** * Get the creation time for this client object. * * @return Creation time in milliseconds */ public long getCreationTime(); /** * Get a set of scopes the client is connected to. * * @return Set of scopes */ public Collection getScopes(); /** * Get a set of connections. * * @return Set of connections */ public Set getConnections(); /** * Get a set of connections of a given scope. * * @param scope scope to get connections for * @return Set of connections to the passed scope */ public Set getConnections(IScope scope); /** * Closes all the connections. */ public void disconnect(); /** * Set the permissions for this client in a given context. * * @param conn Connection specifying the context to set the permissions for. * @param permissions Permissions the client has in this context or null for no permissions. */ public void setPermissions(IConnection conn, Collection permissions); /** * Return the permissions in a given context. * * @param conn Connection specifying the context to get the permissions for. * @return Permission names. */ public Collection getPermissions(IConnection conn); /** * Check if the client has a permission in the given context. * * @param conn Connection specifying the context to check the permissions for. * @param permissionName Name of the permission to check. * @return true if the client has the permission, otherwise false */ public boolean hasPermission(IConnection conn, String permissionName); /** * Performs a bandwidth checking routine. * Information may be found here: http://www.adobe.com/devnet/flashmediaserver/articles/dynamic_stream_switching_04.html */ public void checkBandwidth(); /** * Performs a bandwidth checking callback for the client. * Information may be found here: http://www.adobe.com/devnet/flashmediaserver/articles/dynamic_stream_switching_04.html */ public Map checkBandwidthUp(Object[] params); /** * Returns whether or not a bandwidth check has been requested. * @return true if requested and false otherwise */ public boolean isBandwidthChecked(); } red5-1.0~svn4374.orig/src/org/red5/server/api/IApplicationContext.java0000644000175000017500000000176011706617130025401 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; /** * Interface that wraps the application server context. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IApplicationContext { /** * Stop the web application. */ public void stop(); } red5-1.0~svn4374.orig/src/org/red5/server/api/so/0000755000175000017500000000000011760512573021237 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/so/ISharedObjectSecurity.java0000644000175000017500000000443611747114732026307 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.so; import java.util.List; import org.red5.server.api.scope.IScope; /** * Interface for handlers that control access to shared objects. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface ISharedObjectSecurity { /** * Check if the a shared object may be created in the given scope. * * @param scope scope * @param name name * @param persistent is persistent * @return is creation allowed */ public boolean isCreationAllowed(IScope scope, String name, boolean persistent); /** * Check if a connection to the given existing shared object is allowed. * * @param so shared ojbect * @return is connection alowed */ public boolean isConnectionAllowed(ISharedObject so); /** * Check if a modification is allowed on the given shared object. * * @param so shared object * @param key key * @param value value * @return true if given key is modifiable; false otherwise */ public boolean isWriteAllowed(ISharedObject so, String key, Object value); /** * Check if the deletion of a property is allowed on the given shared object. * * @param so shared object * @param key key * @return true if delete allowed; false otherwise */ public boolean isDeleteAllowed(ISharedObject so, String key); /** * Check if sending a message to the shared object is allowed. * * @param so shared object * @param message message * @param arguments arguments * @return true if allowed */ public boolean isSendAllowed(ISharedObject so, String message, List arguments); } red5-1.0~svn4374.orig/src/org/red5/server/api/so/ISharedObjectService.java0000644000175000017500000001166411747114732026101 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.so; import java.util.Set; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeService; /** * Service that manages shared objects for given scope. * */ public interface ISharedObjectService extends IScopeService { public static String BEAN_NAME = "sharedObjectService"; /** * Get a set of the shared object names. * * @param scope the scope to return the shared object names from * @return set containing the shared object names */ public Set getSharedObjectNames(IScope scope); /** * Create a new shared object. * * @param scope the scope to create the shared object in * @param name the name of the shared object * @param persistent will the shared object be persistent * @return true if the shared object was created, otherwise * false */ public boolean createSharedObject(IScope scope, String name, boolean persistent); /** * Get a shared object by name. * * @param scope the scope to get the shared object from * @param name the name of the shared object * @return shared object, or null if not found */ public ISharedObject getSharedObject(IScope scope, String name); /** * Get a shared object by name and create it if it doesn't exist. * * @param scope the scope to get the shared object from * @param name the name of the shared object * @param persistent should the shared object be created persistent * @return the shared object */ public ISharedObject getSharedObject(IScope scope, String name, boolean persistent); /** * Check if a shared object exists. * * @param scope the scope to check for the shared object * @param name the name of the shared object * @return true if the shared object exists, otherwise * false */ public boolean hasSharedObject(IScope scope, String name); /** *

* Deletes persistent shared objects specified by name and clears all * properties from active shared objects (persistent and nonpersistent). The * name parameter specifies the name of a shared object, which can include a * slash (/) as a delimiter between directories in the path. The last * element in the path can contain wildcard patterns (for example, a * question mark [?] and an asterisk [*]) or a shared object name. The * clearSharedObjects() method traverses the shared object hierarchy along * the specified path and clears all the shared objects. Specifying a slash * (/) clears all the shared objects associated with an application * instance. *

*

* The following values are possible for the soPath parameter:
/ * clears all local and persistent shared objects associated with the * instance.
* /foo/bar clears the shared object /foo/bar; if bar is a directory name, * no shared objects are deleted.
* /foo/bar/* clears all shared objects stored under the instance directory * /foo/bar. The bar directory is also deleted if no persistent shared * objects are in use within this namespace.
* /foo/bar/XX?? clears all shared objects that begin with XX, followed by * any two characters. If a directory name matches this specification, all * the shared objects within this directory are cleared. *

*

* If you call the clearSharedObjects() method and the specified path * matches a shared object that is currently active, all its properties are * deleted, and a "clear" event is sent to all subscribers of the shared * object. If it is a persistent shared object, the persistent store is also * cleared. *

*
* * @param scope the scope to check for the shared object * @param name the name of the shared object * @return true if the shared object at the specified path was deleted; * otherwise, false. If using wildcard characters to delete multiple * files, the method returns true only if all the shared objects * matching the wildcard pattern were successfully deleted; * otherwise, it will return false. */ public boolean clearSharedObjects(IScope scope, String name); } red5-1.0~svn4374.orig/src/org/red5/server/api/so/IClientSharedObject.java0000644000175000017500000000251711706617130025707 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.so; import org.red5.server.api.IConnection; /** * Clientside access to shared objects. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IClientSharedObject extends ISharedObjectBase { /** * Connect the shared object using the passed connection. * * @param conn connect to connect to */ public void connect(IConnection conn); /** * Check if the shared object is connected to the server. * * @return is connected */ public boolean isConnected(); /** * Disconnect the shared object. */ public void disconnect(); } red5-1.0~svn4374.orig/src/org/red5/server/api/so/ISharedObjectListener.java0000644000175000017500000000607111706617130026255 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.so; import java.util.List; import java.util.Map; import org.red5.server.api.IAttributeStore; /** * Notifications about shared object updates. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) * @author Joachim Bauch (jojo@struktur.de) */ public interface ISharedObjectListener { /** * Called when a client connects to a shared object. * * @param so * the shared object */ void onSharedObjectConnect(ISharedObjectBase so); /** * Called when a client disconnects from a shared object. * * @param so * the shared object */ void onSharedObjectDisconnect(ISharedObjectBase so); /** * Called when a shared object attribute is updated. * * @param so * the shared object * @param key * the name of the attribute * @param value * the value of the attribute */ void onSharedObjectUpdate(ISharedObjectBase so, String key, Object value); /** * Called when multiple attributes of a shared object are updated. * * @param so * the shared object * @param values * the new attributes of the shared object */ void onSharedObjectUpdate(ISharedObjectBase so, IAttributeStore values); /** * Called when multiple attributes of a shared object are updated. * * @param so * the shared object * @param values * the new attributes of the shared object */ void onSharedObjectUpdate(ISharedObjectBase so, Map values); /** * Called when an attribute is deleted from the shared object. * * @param so * the shared object * @param key * the name of the attribute to delete */ void onSharedObjectDelete(ISharedObjectBase so, String key); /** * Called when all attributes of a shared object are removed. * * @param so * the shared object */ void onSharedObjectClear(ISharedObjectBase so); /** * Called when a shared object method call is sent. * * @param so * the shared object * @param method * the method name to call * @param params * the arguments */ void onSharedObjectSend(ISharedObjectBase so, String method, List params); } red5-1.0~svn4374.orig/src/org/red5/server/api/so/ISharedObject.java0000644000175000017500000000366311747114732024560 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.so; import org.red5.server.api.scope.IBasicScope; import org.red5.server.api.statistics.ISharedObjectStatistics; /** * Serverside access to shared objects. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface ISharedObject extends IBasicScope, ISharedObjectBase, ISharedObjectSecurityService { /** * Prevent shared object from being released. Each call to acquire * must be paired with a call to release so the SO isn't held * forever. * * This method basically is a noop for persistent SOs as their data is stored * and they can be released without losing their contents. */ public void acquire(); /** * Check if shared object currently is acquired. * * @return true if the SO is acquired, otherwise false */ public boolean isAcquired(); /** * Release previously acquired shared object. If the SO is non-persistent, * no more clients are connected the SO isn't acquired any more, the data * is released. */ public void release(); /** * Return statistics about the shared object. * * @return statistics */ public ISharedObjectStatistics getStatistics(); }red5-1.0~svn4374.orig/src/org/red5/server/api/so/ISharedObjectHandlerProvider.java0000644000175000017500000000261011706617130027553 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.so; import org.red5.server.api.service.IServiceHandlerProvider; /** * Supports registration and lookup of shared object handlers. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * */ public interface ISharedObjectHandlerProvider extends IServiceHandlerProvider { /** * Register an object that provides methods which handle calls without * a service name to a shared object. * * @param handler the handler object */ public void registerServiceHandler(Object handler); /** * Unregister the shared object handler for calls without a service name. */ public void unregisterServiceHandler(String name); } red5-1.0~svn4374.orig/src/org/red5/server/api/so/ISharedObjectBase.java0000644000175000017500000001040111747114732025337 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.so; import java.util.List; import java.util.Map; import org.red5.server.api.ICastingAttributeStore; import org.red5.server.api.event.IEventListener; /** * Base interface for shared objects. Changes to the shared objects are * propagated to all subscribed clients. * * If you want to modify multiple attributes and notify the clients about all * changes at once, you can use code like this: *

* * SharedObject.beginUpdate();
* SharedObject.setAttribute("One", '1');
* SharedObject.setAttribute("Two", '2');
* SharedObject.removeAttribute("Three");
* SharedObject.endUpdate();
*
*

* * All changes between "beginUpdate" and "endUpdate" will be sent to the clients * using one notification event. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface ISharedObjectBase extends ISharedObjectHandlerProvider, ICastingAttributeStore { /** * Returns the version of the shared object. The version is incremented * automatically on each modification. * * @return the version of the shared object */ public int getVersion(); /** * Check if the object has been created as persistent shared object by the * client. * * @return true if the shared object is persistent, false otherwise */ public boolean isPersistent(); /** * Return a map containing all attributes of the shared object.
* NOTE: The returned map will be read-only. * * @return a map containing all attributes of the shared object */ public Map getData(); /** * Send a message to a handler of the shared object. * * @param handler the name of the handler to call * @param arguments a list of objects that should be passed as arguments to the * handler */ public void sendMessage(String handler, List arguments); /** * Start performing multiple updates to the shared object from serverside * code. */ public void beginUpdate(); /** * Start performing multiple updates to the shared object from a connected * client. * @param source Update events listener */ public void beginUpdate(IEventListener source); /** * The multiple updates are complete, notify clients about all changes at * once. */ public void endUpdate(); /** * Register object that will be notified about update events. * * @param listener the object to notify */ public void addSharedObjectListener(ISharedObjectListener listener); /** * Unregister object to not longer receive update events. * * @param listener the object to unregister */ public void removeSharedObjectListener(ISharedObjectListener listener); /** * Locks the shared object instance. Prevents any changes to this object by * clients until the SharedObject.unlock() method is called. */ public void lock(); /** * Unlocks a shared object instance that was locked with * SharedObject.lock(). */ public void unlock(); /** * Returns the locked state of this SharedObject. * * @return true if in a locked state; false otherwise */ public boolean isLocked(); /** * Deletes all the attributes and sends a clear event to all listeners. The * persistent data object is also removed from a persistent shared object. * * @return true if successful; false otherwise */ public boolean clear(); /** * Detaches a reference from this shared object, this will destroy the * reference immediately. This is useful when you don't want to proxy a * shared object any longer. */ public void close(); } red5-1.0~svn4374.orig/src/org/red5/server/api/so/ISharedObjectSecurityService.java0000644000175000017500000000323511747114732027624 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.so; import java.util.Set; import org.red5.server.api.scope.IScopeService; /** * Service that supports protecting access to shared objects. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface ISharedObjectSecurityService extends IScopeService { /** * Name of a bean defining that scope service. * */ public static final String BEAN_NAME = "sharedObjectSecurityService"; /** * Add handler that protects shared objects. * * @param handler Handler to add. */ public void registerSharedObjectSecurity(ISharedObjectSecurity handler); /** * Remove handler that protects shared objects. * * @param handler Handler to remove. */ public void unregisterSharedObjectSecurity(ISharedObjectSecurity handler); /** * Get handlers that protect shared objects. * * @return list of handlers */ public Set getSharedObjectSecurity(); } red5-1.0~svn4374.orig/src/org/red5/server/api/event/0000755000175000017500000000000011760512573021737 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/event/IEventDispatcher.java0000644000175000017500000000170411706617130026000 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.event; /** * IEventDispatcher interface implementations dispatch events */ public interface IEventDispatcher { /** * Dispatches event * @param event Event object */ public void dispatchEvent(IEvent event); } red5-1.0~svn4374.orig/src/org/red5/server/api/event/IEventObservable.java0000644000175000017500000000265111747114732026005 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.event; import java.util.Set; /** * IEventObservable hold functionality of the well-known Observer pattern, that is * it has a list of objects that listen to events. */ public interface IEventObservable { /** * Add event listener to this observable * * @param listener Event listener */ public void addEventListener(IEventListener listener); /** * Remove event listener from this observable * * @param listener Event listener */ public void removeEventListener(IEventListener listener); /** * Returns event listeners * * @return Event listeners iterator */ public Set getEventListeners(); } red5-1.0~svn4374.orig/src/org/red5/server/api/event/IEventListener.java0000644000175000017500000000163311706617130025500 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.event; public interface IEventListener { /** * Notify of event. * @param event the event object */ public void notifyEvent(IEvent event); } red5-1.0~svn4374.orig/src/org/red5/server/api/event/IEvent.java0000644000175000017500000000264611706617130023777 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.event; /** * IEvent interfaces is the essential interface every Event should implement */ public interface IEvent { /** * Returns even type * * @return Event type enumeration */ public Type getType(); /** * Returns event context object * * @return Event context object */ public Object getObject(); /** * Whether event has source (event listener(s)) * @return true if so, false otherwise */ public boolean hasSource(); /** * Returns event listener * @return Event listener object */ public IEventListener getSource(); enum Type { SYSTEM, STATUS, SERVICE_CALL, SHARED_OBJECT, STREAM_CONTROL, STREAM_DATA, CLIENT, SERVER } } red5-1.0~svn4374.orig/src/org/red5/server/api/event/IEventHandler.java0000644000175000017500000000173211706617130025270 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.event; public interface IEventHandler { /** * Handle an event * @param event event to handle * @return true if event was handled, false if it should bubble */ public boolean handleEvent(IEvent event); }red5-1.0~svn4374.orig/src/org/red5/server/api/listeners/0000755000175000017500000000000011760512574022627 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/listeners/IConnectionListener.java0000644000175000017500000000237111706617130027405 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.listeners; import org.red5.server.api.IConnection; /** * Interface for listeners to connection events. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (bauch@struktur.de) */ public interface IConnectionListener { /** * A new connection was established. * * @param conn the new connection */ public void notifyConnected(IConnection conn); /** * A connection was disconnected. * * @param conn the disconnected connection */ public void notifyDisconnected(IConnection conn); } red5-1.0~svn4374.orig/src/org/red5/server/api/listeners/IScopeListener.java0000644000175000017500000000232111747114732026357 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.listeners; import org.red5.server.api.scope.IScope; /** * Interface for listeners to scope events. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (bauch@struktur.de) */ public interface IScopeListener { /** * A scope has been created. * * @param scope the new scope */ public void notifyScopeCreated(IScope scope); /** * A scope has been removed. * * @param scope the removed scope */ public void notifyScopeRemoved(IScope scope); } red5-1.0~svn4374.orig/src/org/red5/server/api/service/0000755000175000017500000000000011760512573022256 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/service/IServiceCall.java0000644000175000017500000000412611706617130025424 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.service; /** * Container for a Service Call */ public interface IServiceCall { /** * Whether call was successful or not * * @return true on success, false otherwise */ public abstract boolean isSuccess(); /** * Returns service method name * * @return Service method name as string */ public abstract String getServiceMethodName(); /** * Returns service name * * @return Service name */ public abstract String getServiceName(); /** * Returns array of service method arguments * * @return array of service method arguments */ public abstract Object[] getArguments(); /** * Get service call status * * @return service call status */ public abstract byte getStatus(); /** * Returns the time stamp at which this object was deserialized. * * @return the readTime */ public long getReadTime(); /** * Returns the time stamp at which this object was serialized. * * @return the writeTime */ public long getWriteTime(); /** * Get service call exception * * @return service call exception */ public abstract Exception getException(); /** * Sets status * * @param status Status as byte */ public abstract void setStatus(byte status); /** * Sets exception * * @param exception Call exception */ public abstract void setException(Exception exception); }red5-1.0~svn4374.orig/src/org/red5/server/api/service/IPendingServiceCallback.java0000644000175000017500000000222111706617130027544 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.service; /** * Callback that will be executed when the result of a pending service call * has been received. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * */ public interface IPendingServiceCallback { /** * Triggered when results are recieved * * @param call Call object this callback is applied to */ public void resultReceived(IPendingServiceCall call); } red5-1.0~svn4374.orig/src/org/red5/server/api/service/IServiceInvoker.java0000644000175000017500000000334211747114732026172 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.service; import org.red5.server.api.scope.IScope; /** * Interface for objects that execute service calls (remote calls from client). * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) */ public interface IServiceInvoker { /** * Execute the passed service call in the given scope. This looks up the * handler for the call in the scope and the context of the scope. * * @param call * the call to invoke * @param scope * the scope to search for a handler * @return true if the call was performed, otherwise false */ boolean invoke(IServiceCall call, IScope scope); /** * Execute the passed service call in the given object. * * @param call * the call to invoke * @param service * the service to use * @return true if the call was performed, otherwise false */ boolean invoke(IServiceCall call, Object service); } red5-1.0~svn4374.orig/src/org/red5/server/api/service/IServiceHandlerProvider.java0000644000175000017500000000365611706617130027650 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.service; import java.util.Set; /** * Supports registration and lookup of service handlers. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * */ public interface IServiceHandlerProvider { /** * Register an object that provides methods which can be called from a * client. * *

* Example:
* If you registered a handler with the name "one.two" that * provides a method "callMe", you can call a method * "one.two.callMe" from the client.

* * @param name the name of the handler * @param handler the handler object */ public void registerServiceHandler(String name, Object handler); /** * Unregister service handler. * * @param name the name of the handler */ public void unregisterServiceHandler(String name); /** * Return a previously registered service handler. * * @param name the name of the handler to return * @return the previously registered handler */ public Object getServiceHandler(String name); /** * Get list of registered service handler names. * * @return the names of the registered handlers */ public Set getServiceHandlerNames(); } red5-1.0~svn4374.orig/src/org/red5/server/api/service/IServiceCapableConnection.java0000644000175000017500000000427411706617130030124 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.service; import org.red5.server.api.IConnection; /** * Connection that has options to invoke and handle remote calls */ // TODO: this should really extend IServiceInvoker public interface IServiceCapableConnection extends IConnection { /** * Invokes service using remoting call object * @param call Service call object */ void invoke(IServiceCall call); /** * Invoke service using call and channel * @param call Service call * @param channel Channel used */ void invoke(IServiceCall call, int channel); /** * Invoke method by name * @param method Called method name */ void invoke(String method); /** * Invoke method by name with callback * @param method Called method name * @param callback Callback */ void invoke(String method, IPendingServiceCallback callback); /** * Invoke method with parameters * @param method Method name * @param params Invocation parameters passed to method */ void invoke(String method, Object[] params); /** * * @param method * @param params * @param callback */ void invoke(String method, Object[] params, IPendingServiceCallback callback); /** * * @param call */ void notify(IServiceCall call); /** * * @param call * @param channel */ void notify(IServiceCall call, int channel); /** * * @param method */ void notify(String method); /** * * @param method * @param params */ void notify(String method, Object[] params); } red5-1.0~svn4374.orig/src/org/red5/server/api/service/IPendingServiceCall.java0000644000175000017500000000373211706617130026733 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.service; import java.util.Set; /** * IPendingServiceCall is a call that have a list of callbacks. * * */ public interface IPendingServiceCall extends IServiceCall { /** * Returns service call result * * @return Remote call result */ public abstract Object getResult(); /** * Setter for property 'result'. * * @param result Value to set for property 'result'. */ public abstract void setResult(Object result); /** * Registers callback object usually represented as an anonymous class * instance that implements IPendingServiceCallback interface. * * @param callback Callback object */ public void registerCallback(IPendingServiceCallback callback); /** * Unregisters callback object usually represented as an anonymous class * instance that implements IPendingServiceCallback interface. * * @param callback Callback object */ public void unregisterCallback(IPendingServiceCallback callback); /** * Returns list of callback objects, usually callback object represented as * an anonymous class instance that implements IPendingServiceCallback * interface. * * @return Set of pending operations callbacks */ public Set getCallbacks(); } red5-1.0~svn4374.orig/src/org/red5/server/api/service/IServiceHandlerProviderAware.java0000644000175000017500000000217211706617130030620 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.service; /** * Class that knows about objects which can provide service handlers. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * */ public interface IServiceHandlerProviderAware { /** * Return object that knows about service handlers. * * @return service handler provider */ public IServiceHandlerProvider getServiceHandlerProvider(); } red5-1.0~svn4374.orig/src/org/red5/server/api/service/ServiceUtils.java0000644000175000017500000002443711747114732025554 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.service; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.red5.server.api.scope.IScope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility functions to invoke methods on connections. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * */ public class ServiceUtils { private static final Logger log = LoggerFactory.getLogger(ServiceUtils.class); /** * Invoke a method on the current connection. * * @param method name of the method to invoke * @param params parameters to pass to the method * @return true if the connection supports method calls, * otherwise false */ public static boolean invokeOnConnection(String method, Object[] params) { return invokeOnConnection(method, params, null); } /** * Invoke a method on the current connection and handle result. * * @param method name of the method to invoke * @param params parameters to pass to the method * @param callback object to notify when result is received * @return true if the connection supports method calls, * otherwise false */ public static boolean invokeOnConnection(String method, Object[] params, IPendingServiceCallback callback) { IConnection conn = Red5.getConnectionLocal(); if (conn != null) { log.debug("Connection for invoke: {}", conn); return invokeOnConnection(conn, method, params, callback); } else { log.warn("Connection was null (thread local), cannot execute invoke request"); return false; } } /** * Invoke a method on a given connection. * * @param conn connection to invoke method on * @param method name of the method to invoke * @param params parameters to pass to the method * @return true if the connection supports method calls, * otherwise false */ public static boolean invokeOnConnection(IConnection conn, String method, Object[] params) { return invokeOnConnection(conn, method, params, null); } /** * Invoke a method on a given connection and handle result. * * @param conn connection to invoke method on * @param method name of the method to invoke * @param params parameters to pass to the method * @param callback object to notify when result is received * @return true if the connection supports method calls, * otherwise false */ public static boolean invokeOnConnection(IConnection conn, String method, Object[] params, IPendingServiceCallback callback) { if (conn instanceof IServiceCapableConnection) { if (callback == null) { ((IServiceCapableConnection) conn).invoke(method, params); } else { ((IServiceCapableConnection) conn).invoke(method, params, callback); } return true; } else { return false; } } /** * Invoke a method on all connections to the current scope. * * @param method name of the method to invoke * @param params parameters to pass to the method */ public static void invokeOnAllConnections(String method, Object[] params) { invokeOnAllConnections(method, params, null); } /** * Invoke a method on all connections to the current scope and handle * result. * * @param method name of the method to invoke * @param params parameters to pass to the method * @param callback object to notify when result is received */ public static void invokeOnAllConnections(String method, Object[] params, IPendingServiceCallback callback) { IConnection conn = Red5.getConnectionLocal(); if (conn != null) { log.debug("Connection for invoke on all: {}", conn); IScope scope = conn.getScope(); log.debug("Scope for invoke on all: {}", scope); invokeOnAllConnections(scope, method, params, callback); } else { log.warn("Connection was null (thread local), scope cannot be located and cannot execute invoke request"); } } /** * Invoke a method on all connections to a given scope. * * @param scope scope to get connections for * @param method name of the method to invoke * @param params parameters to pass to the method */ public static void invokeOnAllConnections(IScope scope, String method, Object[] params) { invokeOnAllConnections(scope, method, params, null); } /** * Invoke a method on all connections to a given scope and handle result. * * @param scope scope to get connections for * @param method name of the method to invoke * @param params parameters to pass to the method * @param callback object to notify when result is received */ public static void invokeOnAllConnections(IScope scope, String method, Object[] params, IPendingServiceCallback callback) { invokeOnClient(null, scope, method, params, callback); } /** * Invoke a method on all connections of a client to a given scope. * * @param client client to get connections for * @param scope scope to get connections of the client from * @param method name of the method to invoke * @param params parameters to pass to the method */ public static void invokeOnClient(IClient client, IScope scope, String method, Object[] params) { invokeOnClient(client, scope, method, params, null); } /** * Invoke a method on all connections of a client to a given scope and * handle result. * * @param client client to get connections for * @param scope scope to get connections of the client from * @param method name of the method to invoke * @param params parameters to pass to the method * @param callback object to notify when result is received */ public static void invokeOnClient(IClient client, IScope scope, String method, Object[] params, IPendingServiceCallback callback) { Set connections; if (client == null) { connections = new HashSet(); Collection> conns = scope.getConnections(); for (Set set : conns) { connections.addAll(set); } } else { connections = scope.lookupConnections(client); if (connections == null) { // Client is not connected to the scope return; } } if (callback == null) { for (IConnection conn : connections) { invokeOnConnection(conn, method, params); } } else { for (IConnection conn : connections) { invokeOnConnection(conn, method, params, callback); } } if (connections != null && client == null) { connections.clear(); connections = null; } } /** * Notify a method on the current connection. * * @param method name of the method to notify * @param params parameters to pass to the method * @return true if the connection supports method calls, * otherwise false */ public static boolean notifyOnConnection(String method, Object[] params) { IConnection conn = Red5.getConnectionLocal(); if (conn != null) { log.debug("Connection for notify: {}", conn); return notifyOnConnection(conn, method, params); } else { log.warn("Connection was null (thread local), cannot execute notify request"); return false; } } /** * Notify a method on a given connection. * * @param conn connection to notify method on * @param method name of the method to notify * @param params parameters to pass to the method * @return true if the connection supports method calls, * otherwise false */ public static boolean notifyOnConnection(IConnection conn, String method, Object[] params) { if (conn instanceof IServiceCapableConnection) { ((IServiceCapableConnection) conn).notify(method, params); return true; } else { return false; } } /** * Notify a method on all connections to the current scope. * * @param method name of the method to notify * @param params parameters to pass to the method */ public static void notifyOnAllConnections(String method, Object[] params) { IConnection conn = Red5.getConnectionLocal(); if (conn != null) { log.debug("Connection for notify on all: {}", conn); IScope scope = conn.getScope(); log.debug("Scope for notify on all: {}", scope); notifyOnAllConnections(scope, method, params); } else { log.warn("Connection was null (thread local), scope cannot be located and cannot execute notify request"); } } /** * Notify a method on all connections to a given scope. * * @param scope scope to get connections for * @param method name of the method to notify * @param params parameters to pass to the method */ public static void notifyOnAllConnections(IScope scope, String method, Object[] params) { notifyOnClient(null, scope, method, params); } /** * Notify a method on all connections of a client to a given scope. * * @param client client to get connections for * @param scope scope to get connections of the client from * @param method name of the method to notify * @param params parameters to pass to the method */ @SuppressWarnings("unchecked") public static void notifyOnClient(IClient client, IScope scope, String method, Object[] params) { Set connections = Collections.EMPTY_SET; if (client == null) { connections = new HashSet(); Collection> conns = scope.getConnections(); for (Set set : conns) { connections.addAll(set); } } else { connections = scope.lookupConnections(client); } for (IConnection conn : connections) { notifyOnConnection(conn, method, params); } if (connections != null) { connections.clear(); connections = null; } } } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/0000755000175000017500000000000011760512573022111 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/stream/IStream.java0000644000175000017500000000336411747114732024326 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.red5.server.api.scope.IScope; /** * Base interface for stream objects. * A stream object is always associated with a scope. */ public interface IStream { /** * Get the name of the stream. The name is unique across the server. This is * just an id of the stream and NOT the name that is used at client side to * subscribe to the stream. For that name, use * {@link IBroadcastStream#getPublishedName()} * * @return the name of the stream */ public String getName(); /** * Get Codec info for a stream. * * @return codec info */ IStreamCodecInfo getCodecInfo(); /** * Get the scope this stream is associated with. * * @return scope object */ public IScope getScope(); /** * Start this stream. */ public void start(); /** * Stop this stream. */ public void stop(); /** * Close this stream. */ public void close(); /** * Returns the timestamp at which the stream was created. * * @return creation timestamp */ public long getCreationTime(); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IPlaylist.java0000644000175000017500000000660511706617130024670 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; /** * Playlist */ public interface IPlaylist { /** * Add an item to the list. * * @param item Playlist item */ void addItem(IPlayItem item); /** * Add an item to specific index. * * @param item Playlist item * @param index Index in list */ void addItem(IPlayItem item, int index); /** * Remove an item from list. * * @param index Index in list */ void removeItem(int index); /** * Remove all items. */ void removeAllItems(); /** * Return number of items in list * * @return Number of items in list */ int getItemSize(); /** * Get currently playing item index. * @return Currently playing item index. */ int getCurrentItemIndex(); /** * Get currently playing item * @return Item */ IPlayItem getCurrentItem(); /** * Get the item according to the index. * @param index Item index * @return Item at that index in list */ IPlayItem getItem(int index); /** * Check if the playlist has more items after the currently * playing one. * * @return true if more items are available, false otherwise */ boolean hasMoreItems(); /** * Go for the previous played item. */ void previousItem(); /** * Go for next item decided by controller logic. */ void nextItem(); /** * Set the current item for playing. * * @param index Position in list */ void setItem(int index); /** * Whether items are randomly played. * * @return true if shuffle is on for this list, false otherwise */ boolean isRandom(); /** * Set whether items should be randomly played. * * @param random Shuffle flag */ void setRandom(boolean random); /** * Whether rewind the list. * * @return true if playlist is rewind on end, false otherwise */ boolean isRewind(); /** * Set whether rewind the list. * * @param rewind New vallue for rewind flag */ void setRewind(boolean rewind); /** * Whether repeat playing an item. * * @return true if repeat mode is on for this playlist, false otherwise */ boolean isRepeat(); /** * Set whether repeat playing an item. * * @param repeat New value for item playback repeat flag */ void setRepeat(boolean repeat); /** * Set list controller. * * @param controller Playlist controller */ void setPlaylistController(IPlaylistController controller); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IStreamCodecInfo.java0000644000175000017500000000333311706617130026067 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; /** * Stream codec information */ public interface IStreamCodecInfo { /** * Has audio support? * @return true if stream codec has audio support, false otherwise */ boolean hasAudio(); /** * Has video support? * @return true if stream codec has video support, false otherwise */ boolean hasVideo(); /** * Getter for audio codec name * * @return Audio codec name */ String getAudioCodecName(); /** * Getter for video codec name * * @return Video codec name */ String getVideoCodecName(); /** * Return video codec * * @return Video codec used by stream codec */ IVideoStreamCodec getVideoCodec(); /** * Return audio codec * * @return Audio codec used by stream codec */ IAudioStreamCodec getAudioCodec(); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IStreamSecurityService.java0000644000175000017500000000424211747114732027373 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import java.util.Set; import org.red5.server.api.scope.IScopeService; /** * Service that supports protecting access to streams. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IStreamSecurityService extends IScopeService { /** * Name of a bean defining that scope service. * */ public static final String BEAN_NAME = "streamSecurityService"; /** * Add handler that protects stream publishing. * * @param handler Handler to add. */ public void registerStreamPublishSecurity(IStreamPublishSecurity handler); /** * Remove handler that protects stream publishing. * * @param handler Handler to remove. */ public void unregisterStreamPublishSecurity(IStreamPublishSecurity handler); /** * Get handlers that protect stream publishing. * * @return list of handlers */ public Set getStreamPublishSecurity(); /** * Add handler that protects stream playback. * * @param handler Handler to add. */ public void registerStreamPlaybackSecurity(IStreamPlaybackSecurity handler); /** * Remove handler that protects stream playback. * * @param handler Handler to remove. */ public void unregisterStreamPlaybackSecurity(IStreamPlaybackSecurity handler); /** * Get handlers that protect stream plaback. * * @return list of handlers */ public Set getStreamPlaybackSecurity(); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/ResourceExistException.java0000644000175000017500000000235011706617130027432 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; public class ResourceExistException extends Exception { private static final long serialVersionUID = 443389396219999143L; /** Constructs a new ResourceExistException. */ public ResourceExistException() { super(); } public ResourceExistException(String message, Throwable cause) { super(message, cause); } public ResourceExistException(String message) { super(message); } public ResourceExistException(Throwable cause) { super(cause); } } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IBroadcastStreamService.java0000644000175000017500000000335611747114732027473 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import java.util.Set; import org.red5.server.api.scope.IScope; public interface IBroadcastStreamService { public final static String BROADCAST_STREAM_SERVICE = "broadcastStreamService"; /** * Does the scope have a broadcast stream registered with a given name * * @param scope the scope to check for the stream * @param name name of the broadcast * @return true is a stream exists, otherwise false */ public boolean hasBroadcastStream(IScope scope, String name); /** * Get a broadcast stream by name * * @param scope the scope to return the stream from * @param name the name of the broadcast * @return broadcast stream object */ public IBroadcastStream getBroadcastStream(IScope scope, String name); /** * Get a set containing the names of all the broadcasts * * @param scope the scope to search for streams * @return set containing all broadcast names */ public Set getBroadcastStreamNames(IScope scope); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IStreamService.java0000644000175000017500000001024111747114732025637 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.red5.server.api.IConnection; import org.red5.server.api.scope.IScopeService; /** * This interface represents the stream methods that can be called throug RTMP. */ public interface IStreamService extends IScopeService { public static String BEAN_NAME = "streamService"; /** * Create a stream and return a corresponding id. * * @return ID of created stream */ public int createStream(); /** * Close the stream but not deallocate the resources. * * @param connection Connection * @param streamId Stream id */ public void closeStream(IConnection connection, int streamId); /** * Close the stream if not been closed. * Deallocate the related resources. * @param streamId Stream id */ public void deleteStream(int streamId); /** * Called by FMS. * * @param streamId Stream id */ public void initStream(int streamId); /** * Called by FME. * * @param streamName stream name */ public void releaseStream(String streamName); /** * Delete stream * @param conn Stream capable connection * @param streamId Stream id */ public void deleteStream(IStreamCapableConnection conn, int streamId); /** * Play stream without initial stop * @param dontStop Stoppage flag */ public void play(Boolean dontStop); /** * Play stream with name * @param name Stream name */ public void play(String name); /** * Play stream with name from start position * @param name Stream name * @param start Start position */ public void play(String name, int start); /** * Play stream with name from start position and for given amount if time * @param name Stream name * @param start Start position * @param length Playback length */ public void play(String name, int start, int length); /** * Publishes stream from given position for given amount of time * @param name Stream published name * @param start Start position * @param length Playback length * @param flushPlaylist Flush playlist? */ public void play(String name, int start, int length, boolean flushPlaylist); /** * Publishes stream with given name * @param name Stream published name */ public void publish(String name); /** * Publishes stream with given name and mode * @param name Stream published name * @param mode Stream publishing mode */ public void publish(String name, String mode); /** * Publish * @param dontStop Whether need to stop first */ public void publish(Boolean dontStop); /** * Seek to position * @param position Seek position */ public void seek(int position); /** * Pauses playback * @param pausePlayback Pause or resume flash * @param position Pause position */ public void pause(Boolean pausePlayback, int position); /** * Undocumented Flash Plugin 10 call, assuming to be the alias to pause(boolean, int) * * @param pausePlayback Pause or resume flash * @param position Pause position */ public void pauseRaw(Boolean pausePlayback, int position); /** * Can recieve video? * @param receive Boolean flag */ public void receiveVideo(boolean receive); /** * Can recieve audio? * @param receive Boolean flag */ public void receiveAudio(boolean receive); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IVideoStreamCodec.java0000644000175000017500000000527711706617130026253 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.apache.mina.core.buffer.IoBuffer; /** * Represents a Video codec and its associated decoder configuration. */ public interface IVideoStreamCodec { /** * FLV frame marker constant */ static final byte FLV_FRAME_KEY = 0x10; /** * @return the name of the video codec. */ public String getName(); /** * Reset the codec to its initial state. */ public void reset(); /** * Check if the codec supports frame dropping. * @return if the codec supports frame dropping. */ public boolean canDropFrames(); /** * Returns true if the codec knows how to handle the passed * stream data. * @param data some sample data to see if this codec can handle it. * @return can this code handle the data. */ public boolean canHandleData(IoBuffer data); /** * Update the state of the codec with the passed data. * @param data data to tell the codec we're adding * @return true for success. false for error. */ public boolean addData(IoBuffer data); /** * @return the data for a keyframe. */ public IoBuffer getKeyframe(); /** * Returns information used to configure the decoder. * * @return the data for decoder setup. */ public IoBuffer getDecoderConfiguration(); /** * Holder for video frame data. */ public final static class FrameData { private IoBuffer frame; /** * Makes a copy of the incoming bytes and places them in an IoBuffer. No flip or rewind is performed on the source data. * * @param data */ public void setData(IoBuffer data) { if (frame == null) { frame = IoBuffer.allocate(data.limit()); } else { frame.clear(); frame.free(); frame = IoBuffer.allocate(data.limit()); } byte[] buf = new byte[frame.limit()]; data.get(buf); frame.put(buf).flip(); } public IoBuffer getFrame() { return frame == null ? null : frame.asReadOnlyBuffer(); } } } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IClientBroadcastStream.java0000644000175000017500000000325211706617130027277 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import java.util.Map; import org.red5.server.api.statistics.IClientBroadcastStreamStatistics; /** * A broadcast stream that comes from client. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) * @author Paul Gregoire (mondain@gmail.com) */ public interface IClientBroadcastStream extends IClientStream, IBroadcastStream { /** * Notify client that stream is ready for publishing. */ public void startPublishing(); /** * Return statistics about the stream. * * @return statistics */ public IClientBroadcastStreamStatistics getStatistics(); /** * Sets streaming parameters as supplied by the publishing application. * * @param params */ public void setParameters(Map params); /** * Returns streaming parameters. * * @return parameters */ public Map getParameters(); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IOnDemandStream.java0000644000175000017500000000360711706617130025727 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; /** * Extends stream to add methods for on demand access. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) */ public interface IOnDemandStream extends IStream { /** * Start playback */ public void play(); /** * Start playback with a given maximum duration. * * @param length maximum duration in milliseconds */ public void play(int length); /** * Seek to the keyframe nearest to position * * @param position position in milliseconds */ public void seek(int position); /** * Pause the stream */ public void pause(); /** * Resume a paused stream */ public void resume(); /** * Stop the stream, this resets the position to the start */ public void stop(); /** * Is the stream paused * * @return true if the stream is paused */ public boolean isPaused(); /** * Is the stream stopped * * @return true if the stream is stopped */ public boolean isStopped(); /** * Is the stream playing * * @return true if the stream is playing */ public boolean isPlaying(); }red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IAudioStreamCodec.java0000644000175000017500000000333211706617130026234 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.apache.mina.core.buffer.IoBuffer; /** * Represents an Audio codec and its associated decoder configuration. * * @author Paul Gregoire (mondain@gmail.com) */ public interface IAudioStreamCodec { /** * @return the name of the audio codec. */ public String getName(); /** * Reset the codec to its initial state. */ public void reset(); /** * Returns true if the codec knows how to handle the passed * stream data. * @param data some sample data to see if this codec can handle it. * @return can this code handle the data. */ public boolean canHandleData(IoBuffer data); /** * Update the state of the codec with the passed data. * @param data data to tell the codec we're adding * @return true for success. false for error. */ public boolean addData(IoBuffer data); /** * Returns information used to configure the decoder. * * @return the data for decoder setup. */ public IoBuffer getDecoderConfiguration(); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IClientStream.java0000644000175000017500000000414111706617130025452 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; /** * A stream that is bound to a client. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IClientStream extends IStream { public static final String MODE_READ = "read"; public static final String MODE_RECORD = "record"; public static final String MODE_APPEND = "append"; public static final String MODE_LIVE = "live"; public static final String MODE_PUBLISH = "publish"; /** * Get stream id allocated in a connection. * * @return the stream id */ int getStreamId(); /** * Get connection containing the stream. * * @return the connection object or null if the connection is no longer active */ IStreamCapableConnection getConnection(); /** * Set the buffer duration for this stream as requested by the client. * * @param bufferTime duration in ms the client wants to buffer */ void setClientBufferDuration(int bufferTime); /** * Get the buffer duration for this stream as requested by the client. * * @return bufferTime duration in ms the client wants to buffer */ int getClientBufferDuration(); /** * Returns the published stream name that this client is consuming. * * @return stream name of stream being consumed */ String getBroadcastStreamPublishName(); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IStreamListener.java0000644000175000017500000000225611706617130026026 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; /** * Listener that is notified about packets received from a stream. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IStreamListener { /** * A packet has been received from a stream. * * @param stream the stream the packet has been received for * @param packet the packet received */ public void packetReceived(IBroadcastStream stream, IStreamPacket packet); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IPlayItem.java0000644000175000017500000000306411706617130024607 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.red5.server.messaging.IMessageInput; /** * Playlist item. Each playlist item has name, start time, length in milliseconds and * message input source. */ public interface IPlayItem { /** * Get name of item. * The VOD or Live stream provider is found according to this name. * @return the name */ String getName(); /** * Start time in milliseconds. * * @return start time */ long getStart(); /** * Play length in milliseconds. * * @return length in milliseconds */ long getLength(); /** * Get a message input for play. * This object overrides the default algorithm for finding the appropriate VOD or Live stream provider according to * the item name. * * @return message input */ IMessageInput getMessageInput(); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IStreamCapableConnection.java0000644000175000017500000000505711754302563027616 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.red5.server.api.IConnection; /** * A connection that supports streaming. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) * @author Steven Gong (steven.gong@gmail.com) */ public interface IStreamCapableConnection extends IConnection { /** * Return a reserved stream id for use. * According to FCS/FMS regulation, the base is 1. * @return Reserved stream id */ int reserveStreamId(); int reserveStreamId(int id); /** * Unreserve this id for future use. * * @param streamId ID of stream to unreserve */ void unreserveStreamId(int streamId); /** * Deletes the stream with the given id. * * @param streamId ID of stream to delete */ void deleteStreamById(int streamId); /** * Get a stream by its id. * * @param streamId Stream id * @return Stream with given id */ IClientStream getStreamById(int streamId); /** * Create a stream that can play only one item. * * @param streamId Stream id * @return New subscriber stream that can play only one item */ ISingleItemSubscriberStream newSingleItemSubscriberStream(int streamId); /** * Create a stream that can play a list. * * @param streamId Stream id * @return New stream that can play sequence of items */ IPlaylistSubscriberStream newPlaylistSubscriberStream(int streamId); /** * Create a broadcast stream. * * @param streamId Stream id * @return New broadcast stream */ IClientBroadcastStream newBroadcastStream(int streamId); /** * Total number of video messages that are pending to be sent to a stream. * * @param streamId Stream id * @return Number of pending video messages */ long getPendingVideoMessages(int streamId); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IStreamPacket.java0000644000175000017500000000244611706617130025451 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.apache.mina.core.buffer.IoBuffer; /** * Packet containing stream data. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IStreamPacket { /** * Type of this packet. This is one of the TYPE_ constants. * * @return the type */ public byte getDataType(); /** * Timestamp of this packet. * * @return the timestamp in milliseconds */ public int getTimestamp(); /** * Packet contents. * * @return the contents */ public IoBuffer getData(); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IStreamPublishSecurity.java0000644000175000017500000000256011747114732027402 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.red5.server.api.scope.IScope; /** * Interface for handlers that control access to stream publishing. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IStreamPublishSecurity { /** * Check if publishing a stream with the given name is allowed. * * @param scope Scope the stream is about to be published in. * @param name Name of the stream to publish. * @param mode Publishing mode. * @return True if publishing is allowed, otherwise False */ public boolean isPublishAllowed(IScope scope, String name, String mode); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IStreamFilenameGenerator.java0000644000175000017500000000502511747114732027632 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeService; /** * A class that can generate filenames for streams. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (bauch@struktur.de) */ public interface IStreamFilenameGenerator extends IScopeService { /** Name of the bean to setup a custom filename generator in an application. */ public static String BEAN_NAME = "streamFilenameGenerator"; /** Possible filename generation types. */ public static enum GenerationType { PLAYBACK, RECORD }; /** * Generate a filename without an extension. * * @param scope Scope to use * @param name Stream name * @param type Generation strategy (either playback or record) * @return Full filename */ public String generateFilename(IScope scope, String name, GenerationType type); /** * Generate a filename with an extension. * * @param scope Scope to use * @param name Stream filename * @param extension Extension * @param type Generation strategy (either playback or record) * @return Full filename with extension */ public String generateFilename(IScope scope, String name, String extension, GenerationType type); /** * True if returned filename is an absolute path, else relative to application. * * If relative to application, you need to use * scope.getContext().getResources(fileName)[0].getFile() to resolve * this to a file. * * If absolute (ie returns true) simply use new File(generateFilename(scope, name)) * * @return true if an absolute path; else false */ public boolean resolvesToAbsolutePath(); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/support/0000755000175000017500000000000011760512573023625 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/stream/support/DynamicPlayItem.java0000644000175000017500000001004711706617130027516 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream.support; import org.red5.server.api.stream.IPlayItem; import org.red5.server.messaging.IMessageInput; /** * Dynamic playlist item implementation */ public class DynamicPlayItem implements IPlayItem { /** * Playlist item name */ protected final String name; /** * Start mark */ protected final long start; /** * Length - amount to play */ protected final long length; /** * Size - for VOD items this will be the file size */ protected long size = -1; /** * Offset */ protected double offset; /** * Message source */ protected IMessageInput msgInput; private DynamicPlayItem(String name, long start, long length) { this.name = name; this.start = start; this.length = length; } private DynamicPlayItem(String name, long start, long length, double offset) { this.name = name; this.start = start; this.length = length; this.offset = offset; } /** * Returns play item length in milliseconds * * @return Play item length in milliseconds */ public long getLength() { return length; } /** * Returns IMessageInput object. IMessageInput is an endpoint for a consumer * to connect. * * @return IMessageInput object */ public IMessageInput getMessageInput() { return msgInput; } /** * Returns item name * * @return item name */ public String getName() { return name; } /** * Returns boolean value that specifies whether item can be played */ public long getStart() { return start; } /** * Alias for getMessageInput * * @return Message input source */ public IMessageInput getMsgInput() { return msgInput; } /** * Setter for message input * * @param msgInput Message input */ public void setMsgInput(IMessageInput msgInput) { this.msgInput = msgInput; } /** * Returns size in bytes */ public long getSize() { return size; } /** * Set the size in bytes * * @param size size in bytes */ public void setSize(long size) { this.size = size; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + (int) (size ^ (size >>> 32)); result = prime * result + (int) (start ^ (start >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; DynamicPlayItem other = (DynamicPlayItem) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (size != other.size) return false; if (start != other.start) return false; return true; } /** * Builder for DynamicPlayItem * * @param name * @param start * @param length * @return play item instance */ public static DynamicPlayItem build(String name, long start, long length) { DynamicPlayItem playItem = new DynamicPlayItem(name, start, length); return playItem; } /** * Builder for DynamicPlayItem * * @param name * @param start * @param length * @param offset * @return play item instance */ public static DynamicPlayItem build(String name, long start, long length, double offset) { DynamicPlayItem playItem = new DynamicPlayItem(name, start, length, offset); return playItem; } } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/support/SimplePlayItem.java0000644000175000017500000000664611706617130027375 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream.support; import org.red5.server.api.stream.IPlayItem; import org.red5.server.messaging.IMessageInput; /** * Simple playlist item implementation */ public class SimplePlayItem implements IPlayItem { /** * Playlist item name */ protected final String name; /** * Start mark */ protected final long start; /** * Length - amount to play */ protected final long length; /** * Message source */ protected IMessageInput msgInput; private SimplePlayItem(String name) { this.name = name; this.start = -2L; this.length = -1L; } private SimplePlayItem(String name, long start, long length) { this.name = name; this.start = start; this.length = length; } /** * Returns play item length in milliseconds * * @return Play item length in milliseconds */ public long getLength() { return length; } /** * Returns IMessageInput object. IMessageInput is an endpoint for a consumer * to connect. * * @return IMessageInput object */ public IMessageInput getMessageInput() { return msgInput; } /** * Returns item name * * @return item name */ public String getName() { return name; } /** * Returns boolean value that specifies whether item can be played */ public long getStart() { return start; } /** * Alias for getMessageInput * * @return Message input source */ public IMessageInput getMsgInput() { return msgInput; } /** * Setter for message input * * @param msgInput Message input */ public void setMsgInput(IMessageInput msgInput) { this.msgInput = msgInput; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + (int) (start ^ (start >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; SimplePlayItem other = (SimplePlayItem) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (start != other.start) return false; return true; } /** * Builder for SimplePlayItem * * @param name * @return play item instance */ public static SimplePlayItem build(String name) { SimplePlayItem playItem = new SimplePlayItem(name); return playItem; } /** * Builder for SimplePlayItem * * @param name * @param start * @param length * @return play item instance */ public static SimplePlayItem build(String name, long start, long length) { SimplePlayItem playItem = new SimplePlayItem(name, start, length); return playItem; } } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/support/StreamUtils.java0000644000175000017500000000724511747114732026754 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream.support; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IServerStream; import org.red5.server.stream.ServerStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Stream helper methods. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) * @author Paul Gregoire (mondain@gmail.com) */ public abstract class StreamUtils { private static final Logger logger = LoggerFactory.getLogger(StreamUtils.class); /* Map to hold reference to the instanced server streams */ private static volatile ConcurrentMap serverStreamMap = new ConcurrentHashMap(); /** * Creates server stream * * @param scope Scope of stream * @param name Name of stream * @return IServerStream object */ public static IServerStream createServerStream(IScope scope, String name) { logger.debug("Creating server stream: {} scope: {}", name, scope); ServerStream stream = new ServerStream(); stream.setScope(scope); stream.setName(name); stream.setPublishedName(name); //save to the list for later lookups String key = scope.getName() + '/' + name; serverStreamMap.put(key, stream); return stream; } /** * Looks up a server stream in the stream map. Null will be returned if the * stream is not found. * * @param scope Scope of stream * @param name Name of stream * @return IServerStream object */ public static IServerStream getServerStream(IScope scope, String name) { logger.debug("Looking up server stream: {} scope: {}", name, scope); String key = scope.getName() + '/' + name; if (serverStreamMap.containsKey(key)) { return serverStreamMap.get(key); } else { logger.warn("Server stream not found with key: {}", key); return null; } } /** * Puts a server stream in the stream map * * @param scope Scope of stream * @param name Name of stream * @param stream ServerStream object */ public static void putServerStream(IScope scope, String name, IServerStream stream) { logger.debug("Putting server stream in the map - name: {} scope: {} stream: {}", new Object[] { name, scope, stream }); String key = scope.getName() + '/' + name; if (!serverStreamMap.containsKey(key)) { serverStreamMap.put(key, stream); } else { logger.warn("Server stream already exists in the map with key: {}", key); } } /** * Removes a server stream from the stream map * * @param scope Scope of stream * @param name Name of stream */ public static void removeServerStream(IScope scope, String name) { logger.debug("Removing server stream from the map - name: {} scope: {}", name, scope); String key = scope.getName() + '/' + name; if (serverStreamMap.containsKey(key)) { serverStreamMap.remove(key); } else { logger.warn("Server stream did not exist in the map with key: {}", key); } } } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/support/DenyAllStreamAccess.java0000644000175000017500000000265011747114732030321 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream.support; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IStreamPlaybackSecurity; import org.red5.server.api.stream.IStreamPublishSecurity; /** * Stream security handler that denies access to all streams. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class DenyAllStreamAccess implements IStreamPublishSecurity, IStreamPlaybackSecurity { /** {@inheritDoc} */ public boolean isPublishAllowed(IScope scope, String name, String mode) { return false; } /** {@inheritDoc} */ public boolean isPlaybackAllowed(IScope scope, String name, int start, int length, boolean flushPlaylist) { return false; } } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/ISubscriberStream.java0000644000175000017500000000535111706617130026343 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import java.io.IOException; import java.util.concurrent.ScheduledThreadPoolExecutor; /** * ISubscriberStream is a stream from subscriber's point of view. That is, it * provides methods for common stream operations like play, pause or seek. */ public interface ISubscriberStream extends IClientStream { /** * Start playing. * * @throws IOException if an IO error occurred while starting to play the stream */ void play() throws IOException; /** * Pause at a position for current playing item. * * @param position * Position for pause in millisecond. */ void pause(int position); /** * Resume from a position for current playing item. * * @param position * Position for resume in millisecond. */ void resume(int position); /** * Stop playing. */ void stop(); /** * Seek into a position for current playing item. * * @param position * Position for seek in millisecond. * @throws OperationNotSupportedException if the stream doesn't support seeking. */ void seek(int position) throws OperationNotSupportedException; /** * Check if the stream is currently paused. * * @return stream is paused */ boolean isPaused(); /** * Should the stream send video to the client? * * @param receive */ void receiveVideo(boolean receive); /** * Should the stream send audio to the client? * * @param receive */ void receiveAudio(boolean receive); /** * Return the streams state enum. * * @return current state */ public StreamState getState(); /** * Sets the streams state enum. * * @param state sets current state */ public void setState(StreamState state); /** * Notification of state change and associated parameters. * * @param state new state * @param changed parameters associated with the change */ public void onChange(final StreamState state, final Object... changed); /** * Returns the Executor. * @return executor */ ScheduledThreadPoolExecutor getExecutor(); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IPlaylistController.java0000644000175000017500000000335111706617130026727 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; /** * A play list controller that controls the order of play items. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IPlaylistController { /** * Get next item to play. * * @param playlist * The related play list. * @param itemIndex * The current item index. -1 indicates to retrieve * the first item for play. * @return The next item index to play. -1 reaches the end. */ int nextItem(IPlaylist playlist, int itemIndex); /** * Get previous item to play. * * @param playlist * The related play list. * @param itemIndex * The current item index. IPlaylist.itemSize * indicated to retrieve the last item for play. * @return The previous item index to play. -1 reaches the * beginning. */ int previousItem(IPlaylist playlist, int itemIndex); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/ResourceNotFoundException.java0000644000175000017500000000244111706617130030073 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; /** * @author daccattato * */ public class ResourceNotFoundException extends Exception { private static final long serialVersionUID = -1963629259187714996L; /** Constructs a new ResourceNotFoundException. */ public ResourceNotFoundException() { super(); } public ResourceNotFoundException(String message, Throwable cause) { super(message, cause); } public ResourceNotFoundException(String message) { super(message); } public ResourceNotFoundException(Throwable cause) { super(cause); } } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IStreamHandler.java0000644000175000017500000000446511706617130025622 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; public interface IStreamHandler { /** * Called when the client begins publishing * * @param stream * the stream object */ void onStreamPublishStart(IStream stream); /** * Called when the client stops publishing * * @param stream * the stream object */ void onStreamPublishStop(IStream stream); /** * Called when the broadcast starts * * @param stream * the stream object */ void onBroadcastStreamStart(IStream stream); /** * Called when a recording starts * * @param stream * the stream object */ void onRecordStreamStart(IStream stream); /** * Called when a recording stops * * @param stream * the stream object */ void onRecordStreamStop(IStream stream); /** * Called when a client subscribes to a broadcast * * @param stream * the stream object */ void onBroadcastStreamSubscribe(IBroadcastStream stream); /** * Called when a client unsubscribes from a broadcast * * @param stream * the stream object */ void onBroadcastStreamUnsubscribe(IBroadcastStream stream); /** * Called when a client connects to an on demand stream * * @param stream * the stream object */ void onOnDemandStreamConnect(IOnDemandStream stream); /** * Called when a client disconnects from an on demand stream * * @param stream * the stream object */ void onOnDemandStreamDisconnect(IOnDemandStream stream); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/ISingleItemSubscriberStream.java0000644000175000017500000000223011706617130030315 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; /** * A subscriber stream that has only one item for play. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface ISingleItemSubscriberStream extends ISubscriberStream { /** * Setter for property 'playItem'. * * @param item Value to set for property 'playItem'. */ void setPlayItem(IPlayItem item); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/StreamState.java0000644000175000017500000000202011706617130025175 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; /** * Represents all the states that a stream may be in at a requested * point in time. * * @author Paul Gregoire (mondain@gmail.com) */ public enum StreamState { INIT, UNINIT, OPEN, CLOSED, STARTED, STOPPED, PLAYING, PAUSED, RESUMED, END, SEEK; } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/ISubscriberStreamService.java0000644000175000017500000000243111747114732027665 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeService; public interface ISubscriberStreamService extends IScopeService { public static String BEAN_NAME = "subscriberStreamService"; /** * Returns a stream that can subscribe a broadcast stream with the given * name using "IBroadcastStream.subscribe". * * @param scope the scope to return the stream from * @param name the name of the stream * @return the stream object */ public ISubscriberStream getSubscriberStream(IScope scope, String name); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IRtmpSampleAccess.java0000644000175000017500000000243311747114732026275 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.red5.server.api.scope.IScope; public interface IRtmpSampleAccess { public static String BEAN_NAME = "rtmpSampleAccess"; /** * Return true if sample access allowed on audio stream * @param scope * @return true if sample access allowed on audio stream */ public boolean isAudioAllowed(IScope scope); /** * Return true if sample access allowed on video stream * @param scope * @return true if sample access allowed on video stream */ public boolean isVideoAllowed(IScope scope); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/OperationNotSupportedException.java0000644000175000017500000000171611706617130031162 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; /** * The requested operation is not supported by the stream. * */ public class OperationNotSupportedException extends Exception { /** * */ private static final long serialVersionUID = -6166602683688991431L; } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IOnDemandStreamService.java0000644000175000017500000000300111747114732027241 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeService; public interface IOnDemandStreamService extends IScopeService { public static String BEAN_NAME = "onDemandStreamService"; /** * Has the service an on-demand stream with the passed name? * * @param scope the scope to check for the stream * @param name the name of the stream * @return true if the stream exists, false otherwise */ public boolean hasOnDemandStream(IScope scope, String name); /** * Get a stream that can be used for playback of the on-demand stream * * @param scope the scope to return the stream from * @param name the name of the stream * @return the on-demand stream */ public IOnDemandStream getOnDemandStream(IScope scope, String name); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IPlaylistSubscriberStream.java0000644000175000017500000000340111706617130030057 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import java.util.concurrent.ScheduledThreadPoolExecutor; import org.red5.server.api.statistics.IPlaylistSubscriberStreamStatistics; /** * IPlaylistSubscriberStream has methods of both ISubscriberStream and IPlaylist * but adds nothing new */ public interface IPlaylistSubscriberStream extends ISubscriberStream, IPlaylist { /** * Return statistics about this stream. * * @return statistics */ public IPlaylistSubscriberStreamStatistics getStatistics(); /** * Returns the job executor. * * @return executor */ public ScheduledThreadPoolExecutor getExecutor(); /** * Handles a change occurring on the stream. * * @param state stream state that we are changing to or notifying of * @param changed changed items */ public void onChange(StreamState state, Object... changed); /** * Replaces an item in the list with another item. * * @param oldItem * @param newItem * @return true if successful and false otherwise */ public boolean replace(IPlayItem oldItem, IPlayItem newItem); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IStreamAwareScopeHandler.java0000644000175000017500000000616011747114732027573 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.red5.server.api.scope.IScopeHandler; /** * A scope handler that is stream aware. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IStreamAwareScopeHandler extends IScopeHandler { /** * A broadcast stream starts being published. This will be called * when the first video packet has been received. * * @param stream stream */ public void streamPublishStart(IBroadcastStream stream); /** * A broadcast stream starts being recorded. This will be called * when the first video packet has been received. * * @param stream stream */ public void streamRecordStart(IBroadcastStream stream); /** * Notified when a broadcaster starts. * * @param stream stream */ public void streamBroadcastStart(IBroadcastStream stream); /** * Notified when a broadcaster closes. * * @param stream stream */ public void streamBroadcastClose(IBroadcastStream stream); /** * Notified when a subscriber starts. * * @param stream stream */ public void streamSubscriberStart(ISubscriberStream stream); /** * Notified when a subscriber closes. * * @param stream stream */ public void streamSubscriberClose(ISubscriberStream stream); /** * Notified when a play item plays. * * @param stream stream * @param item item * @param isLive true if live */ public void streamPlayItemPlay(ISubscriberStream stream, IPlayItem item, boolean isLive); /** * Notified when a play item stops. * * @param stream stream * @param item item */ public void streamPlayItemStop(ISubscriberStream stream, IPlayItem item); /** * Notified when a play item pauses. * * @param stream stream * @param item item * @param position position */ public void streamPlayItemPause(ISubscriberStream stream, IPlayItem item, int position); /** * Notified when a play item resumes. * * @param stream stream * @param item item * @param position position */ public void streamPlayItemResume(ISubscriberStream stream, IPlayItem item, int position); /** * Notified when a play item seeks. * * @param stream stream * @param item item * @param position position */ public void streamPlayItemSeek(ISubscriberStream stream, IPlayItem item, int position); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IBroadcastStream.java0000644000175000017500000000630711706617130026144 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import java.io.IOException; import java.util.Collection; import org.red5.server.messaging.IProvider; import org.red5.server.net.rtmp.event.Notify; /** * A broadcast stream is a stream source to be subscribed by clients. To * subscribe a stream from your client Flash application use NetStream.play * method. Broadcast stream can be saved at server-side. * * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) * @author Steven Gong (steven.gong@gmail.com) */ public interface IBroadcastStream extends IStream { /** * Save the broadcast stream as a file. * * @param filePath * The path of the file relative to the scope. * @param isAppend * Whether to append to the end of file. * @throws IOException * File could not be created/written to. * @throws ResourceExistException * Resource exist when trying to create. * @throws ResourceNotFoundException * Resource not exist when trying to append. */ void saveAs(String filePath, boolean isAppend) throws IOException, ResourceNotFoundException, ResourceExistException; /** * Get the filename the stream is being saved as. * * @return The filename relative to the scope or null * if the stream is not being saved. */ String getSaveFilename(); /** * Get the provider corresponding to this stream. Provider objects are * object that * * @return the provider */ IProvider getProvider(); /** * Get stream publish name. Publish name is the value of the first parameter * had been passed to NetStream.publish on client side in * SWF. * * @return Stream publish name */ String getPublishedName(); /** * * @param name * Set stream publish name */ void setPublishedName(String name); /** * Add a listener to be notified about received packets. * * @param listener the listener to add */ public void addStreamListener(IStreamListener listener); /** * Remove a listener from being notified about received packets. * * @param listener the listener to remove */ public void removeStreamListener(IStreamListener listener); /** * Return registered stream listeners. * * @return the registered listeners */ public Collection getStreamListeners(); /** * Returns the metadata for the associated stream, if it exists. * * @return stream meta data */ public Notify getMetaData(); }red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IStreamPlaybackSecurity.java0000644000175000017500000000302311747114732027515 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; import org.red5.server.api.scope.IScope; /** * Interface for handlers that control access to stream playback. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IStreamPlaybackSecurity { /** * Check if playback of a stream with the given name is allowed. * * @param scope Scope the stream is about to be played back from. * @param name Name of the stream to play. * @param start Position to start playback from (in milliseconds). * @param length Duration to play (in milliseconds). * @param flushPlaylist Flush playlist? * @return True if playback is allowed, otherwise False */ public boolean isPlaybackAllowed(IScope scope, String name, int start, int length, boolean flushPlaylist); } red5-1.0~svn4374.orig/src/org/red5/server/api/stream/IServerStream.java0000644000175000017500000000224311706617130025503 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.stream; /** * IServerStream has both IPlaylist and IBroadcastStream methods but add nothing * new. It represents a stream broadcasted from the server. */ public interface IServerStream extends IPlaylist, IBroadcastStream { /** * Toggles the paused state. */ public void pause(); /** * Seek to a given position in the stream. * * @param position new playback position in milliseconds */ public void seek(int position); } red5-1.0~svn4374.orig/src/org/red5/server/api/cache/0000755000175000017500000000000011760512574021662 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/cache/ICacheable.java0000644000175000017500000000377411706617130024472 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.cache; import org.apache.mina.core.buffer.IoBuffer; /** * Base interface for objects that can be made cacheable. * * @see ICacheStore * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public interface ICacheable { /** * Returns true if the object is cached, false * otherwise. * * @return true if object is cached, false otherwise */ public boolean isCached(); /** * Sets a flag to represent the cached status of a cacheable object. * * @param cached true if object is cached, false otherwise */ public void setCached(boolean cached); /** * Returns the name of the cached object. * * @return Object name */ public String getName(); /** * Set the name of the cached object. * * @param name New object name */ public void setName(String name); /** * Returns the object contained within the cacheable reference. * * @return Cached representation of object */ public byte[] getBytes(); /** * Returns a readonly byte buffer. * * @return Read-only IoBuffer with cached data */ public IoBuffer getByteBuffer(); } red5-1.0~svn4374.orig/src/org/red5/server/api/cache/ICacheStore.java0000644000175000017500000000641511706617130024656 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.cache; import java.lang.ref.SoftReference; import java.util.Iterator; /** * Storage for cacheable objects. Selected cache engines must implement this * interface. * * @see Soft references provide for quick-and-dirty caching * @see Reference Objects and Garbage Collection * @see Top Ten New Things You Can Do with NIO * @see Proxy Cache Solution * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public interface ICacheStore { /** * Offer an object to the cache with an associated key. * If the named object exists in cache, it will not be accepted. * * @param name string name representing the object * @param obj cacheable object * @return true if accepted, false otherwise */ public boolean offer(String name, Object obj); /** * Puts an object in the cache with the associated key. * * @param name string name representing the object * @param obj cacheable object */ public void put(String name, Object obj); /** * Return a cached object with the given name. * * @param name the name of the object to return * @return the object or null if no such object was found */ public ICacheable get(String name); /** * Delete the passed cached object. * * @param obj the object to delete * @return true if was removed; false it wasn't in cache to begin with */ public boolean remove(ICacheable obj); /** * Delete the cached object with the given name. * * @param name the name of the object to delete * @return true if was removed; false it wasn't in cache to begin with */ public boolean remove(String name); /** * Return iterator over the names of all already loaded objects in the * storage. * * @return iterator over all objects names */ public Iterator getObjectNames(); /** * Return iterator over the already loaded objects in the storage. * * @return iterator over all objects */ public Iterator> getObjects(); /** * Sets the maximum number of entries for the cache. * * @param max upper-limit of the cache */ public void setMaxEntries(int max); /** * Allows for cleanup of a cache implementation. */ public void destroy(); } red5-1.0~svn4374.orig/src/org/red5/server/api/statistics/0000755000175000017500000000000011760512573023010 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/statistics/IStatisticsService.java0000644000175000017500000000732611747114732027447 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.statistics; import java.util.Set; import org.red5.server.api.scope.IScope; import org.red5.server.api.so.ISharedObject; import org.red5.server.exception.ScopeNotFoundException; import org.red5.server.exception.SharedObjectException; /** * Statistics methods for Red5. They can be used to poll for updates of * given elements inside the server. Statistics data will be stored as * properties of different shared objects. * * Use getScopeStatisticsSO and getSharedObjectStatisticsSO * to get these shared objects. The property names are scopeName * for scope attributes and scopeName|sharedObjectName for * shared object attributes. Each property holds a Map containing key/value * mappings of the corresponding attributes. * * Sometime in the future, the updates on the shared objects will be done * automatically so a client doesn't need to poll for them. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IStatisticsService { /** * Return the shared object that will be used to keep scope statistics. * * @param scope A scope to return the shared object for. * @return the shared object containing scope statistics */ public ISharedObject getScopeStatisticsSO(IScope scope); /** * Return the shared object that will be used to keep SO statistics. * * @param scope A scope to return the shared object for. * @return the shared object containing SO statistics */ public ISharedObject getSharedObjectStatisticsSO(IScope scope); /** * Return a list of all scopes that currently exist on the server. * * @return list of scope names */ public Set getScopes(); /** * Return a list of all scopes that currently exist on the server * below a current path. * * @param path Path to start looking for scopes. * @return list of scope names * @throws ScopeNotFoundException if the path on the server doesn't exist */ public Set getScopes(String path) throws ScopeNotFoundException; /** * Update statistics for a given scope. * * @param path Path to scope to update. * @throws ScopeNotFoundException if the given scope doesn't exist */ public void updateScopeStatistics(String path) throws ScopeNotFoundException; /** * Return informations about shared objects for a given scope. * * @param path Path to scope to return shared object names for. * @return list of informations about shared objects */ public Set getSharedObjects(String path); /** * Update informations about a shared object in a given scope. * * @param path Path to scope that contains the shared object. * @param name Name of shared object to update. * @throws ScopeNotFoundException if the given scope doesn't exist * @throws SharedObjectException if no shared object with the given name exists */ public void updateSharedObjectStatistics(String path, String name) throws ScopeNotFoundException, SharedObjectException; } red5-1.0~svn4374.orig/src/org/red5/server/api/statistics/IStatisticsBase.java0000644000175000017500000000214011706617130026701 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.statistics; /** * Base class for all statistics informations. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IStatisticsBase { /** * Return the timestamp the object was created. * * @return the timestamp in milliseconds since midnight, January 1, 1970 UTC. */ public long getCreationTime(); } red5-1.0~svn4374.orig/src/org/red5/server/api/statistics/IPlaylistSubscriberStreamStatistics.java0000644000175000017500000000267711706617130033047 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.statistics; /** * Statistical informations about a stream that is subscribed by a client. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IPlaylistSubscriberStreamStatistics extends IStreamStatistics { /** * Return total number of bytes sent to the client from this stream. * * @return number of bytes */ public long getBytesSent(); /** * Return the buffer duration as requested by the client. * * @return the buffer duration in milliseconds */ public int getClientBufferDuration(); /** * Return estimated fill ratio of the client buffer. * * @return fill ratio in percent */ public double getEstimatedBufferFill(); } red5-1.0~svn4374.orig/src/org/red5/server/api/statistics/IClientBroadcastStreamStatistics.java0000644000175000017500000000373211706617130032254 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.statistics; /** * Statistical informations about a stream that is broadcasted by a client. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IClientBroadcastStreamStatistics extends IStreamStatistics { /** * Get the filename the stream is being saved as. * * @return The filename relative to the scope or null * if the stream is not being saved. */ public String getSaveFilename(); /** * Get stream publish name. Publish name is the value of the first parameter * had been passed to NetStream.publish on client side in * SWF. * * @return Stream publish name */ public String getPublishedName(); /** * Return total number of subscribers. * * @return number of subscribers */ public int getTotalSubscribers(); /** * Return maximum number of concurrent subscribers. * * @return number of subscribers */ public int getMaxSubscribers(); /** * Return current number of subscribers. * * @return number of subscribers */ public int getActiveSubscribers(); /** * Return total number of bytes received from client for this stream. * * @return number of bytes */ public long getBytesReceived(); } red5-1.0~svn4374.orig/src/org/red5/server/api/statistics/support/0000755000175000017500000000000011760512573024524 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/statistics/support/StatisticsCounter.java0000644000175000017500000000355611706617130031065 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.statistics.support; import java.util.concurrent.atomic.AtomicInteger; /** * Counts numbers used by the statistics. Keeps track of current, * maximum and total numbers. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class StatisticsCounter { /** Current number. */ private AtomicInteger current = new AtomicInteger(); /** Total number. */ private AtomicInteger total = new AtomicInteger(); /** Maximum number. */ private AtomicInteger max = new AtomicInteger(); /** * Increment statistics by one. */ public void increment() { total.incrementAndGet(); max.compareAndSet(current.intValue(), current.incrementAndGet()); } /** * Decrement statistics by one. */ public void decrement() { current.decrementAndGet(); } /** * Get current number. * * @return current number */ public int getCurrent() { return current.intValue(); } /** * Get total number. * * @return total */ public int getTotal() { return total.intValue(); } /** * Get maximum number. * * @return max */ public int getMax() { return max.intValue(); } } red5-1.0~svn4374.orig/src/org/red5/server/api/statistics/ISharedObjectStatistics.java0000644000175000017500000000420111706617130030364 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.statistics; /** * Statistics informations about a shared object. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface ISharedObjectStatistics extends IStatisticsBase { /** * Return the name of the shared object. * * @return the name of the shared object */ public String getName(); /** * Check if the shared object is persistent. * * @return True if the shared object is persistent, otherwise False */ public boolean isPersistent(); /** * Return the version number of the shared object. * * @return the version */ public int getVersion(); /** * Return total number of subscribed listeners. * * @return number of listeners */ public int getTotalListeners(); /** * Return maximum number of concurrent subscribed listenes. * * @return number of listeners */ public int getMaxListeners(); /** * Return current number of subscribed listeners. * * @return number of listeners */ public int getActiveListeners(); /** * Return number of attribute changes. * * @return number of changes */ public int getTotalChanges(); /** * Return number of attribute deletes. * * @return number of deletes */ public int getTotalDeletes(); /** * Return number of times a message was sent. * * @return number of sends */ public int getTotalSends(); } red5-1.0~svn4374.orig/src/org/red5/server/api/statistics/IScopeStatistics.java0000644000175000017500000000530511706617130027106 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.statistics; /** * Statistical informations about a scope. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IScopeStatistics extends IStatisticsBase { /** * Get the name of this scope. Eg. someroom. * * @return the name */ public String getName(); /** * Get the full absolute path. Eg. host/myapp/someroom. * * @return Absolute scope path */ public String getPath(); /** * Get the scopes depth, how far down the scope tree is it. The lowest depth * is 0x00, the depth of Global scope. Application scope depth is 0x01. Room * depth is 0x02, 0x03 and so forth. * * @return the depth */ public int getDepth(); /** * Return total number of connections to the scope. * * @return number of connections */ public int getTotalConnections(); /** * Return maximum number of concurrent connections to the scope. * * @return number of connections */ public int getMaxConnections(); /** * Return current number of connections to the scope. * * @return number of connections */ public int getActiveConnections(); /** * Return total number of clients connected to the scope. * * @return number of clients */ public int getTotalClients(); /** * Return maximum number of clients concurrently connected to the scope. * * @return number of clients */ public int getMaxClients(); /** * Return current number of clients connected to the scope. * * @return number of clients */ public int getActiveClients(); /** * Return total number of subscopes created. * * @return number of subscopes created */ public int getTotalSubscopes(); /** * Return maximum number of concurrently existing subscopes. * * @return number of subscopes */ public int getMaxSubscopes(); /** * Return number of currently existing subscopes. * * @return number of subscopes */ public int getActiveSubscopes(); } red5-1.0~svn4374.orig/src/org/red5/server/api/statistics/IStreamStatistics.java0000644000175000017500000000213611706617130027267 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.statistics; /** * Base class for all stream statistics. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IStreamStatistics extends IStatisticsBase { /** * Return the currently active timestamp inside the stream. * * @return the timestamp in milliseconds */ public int getCurrentTimestamp(); } red5-1.0~svn4374.orig/src/org/red5/server/api/plugin/0000755000175000017500000000000011760512573022114 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/plugin/IRed5PluginHandler.java0000644000175000017500000000254711706617130026347 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.plugin; import java.util.Map; import org.red5.server.adapter.MultiThreadedApplicationAdapter; /** * Base interface for handlers originating from plug-ins. * * @author Paul Gregoire */ public interface IRed5PluginHandler { /** * Initialize the plug-in handler. */ void init(); /** * Set the application making use of this plug-in handler. * * @param application */ void setApplication(MultiThreadedApplicationAdapter application); /** * Set properties to be used by this handler. * * @param props */ void setProperties(Map props); } red5-1.0~svn4374.orig/src/org/red5/server/api/plugin/IRed5Plugin.java0000644000175000017500000000317611706617130025050 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.plugin; import org.red5.server.Server; import org.springframework.context.ApplicationContext; /** * Base interface for a Red5 server Plug-in. * * @author Paul Gregoire (mondain@gmail.com) */ public interface IRed5Plugin { /** * Returns a name / identifier for the plug-in. * * @return plug-in's name */ String getName(); /** * Sets the top-most ApplicationContext within Red5. * * @param context */ void setApplicationContext(ApplicationContext context); /** * Sets a reference to the server. * * @param server */ void setServer(Server server); /** * Lifecycle method called when the plug-in is started. * * @throws Exception */ void doStart() throws Exception; /** * Lifecycle method called when the plug-in is stopped. * * @throws Exception */ void doStop() throws Exception; }red5-1.0~svn4374.orig/src/org/red5/server/api/ICoreObject.java0000644000175000017500000000222111747114732023606 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import org.red5.server.api.event.IEventDispatcher; import org.red5.server.api.event.IEventHandler; import org.red5.server.api.event.IEventListener; /** * Base marker interface for all core objects. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) * */ public interface ICoreObject extends IEventDispatcher, IEventHandler, IEventListener { }red5-1.0~svn4374.orig/src/org/red5/server/api/IConnection.java0000644000175000017500000001516511747114732023701 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import java.util.Iterator; import java.util.List; import java.util.Map; import org.red5.server.api.scope.IBasicScope; import org.red5.server.api.scope.IScope; /** * The connection object. * * Each connection has an associated client and scope. Connections may be * persistent, polling, or transient. The aim of this interface is to provide * basic connection methods shared between different types of connections * * Future subclasses: RTMPConnection, RemotingConnection, AJAXConnection, * HttpConnection, etc * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) */ public interface IConnection extends ICoreObject, ICastingAttributeStore { /** * AMF version types, either AMF0 or AMF3. */ public static enum Encoding { AMF0, AMF3 }; /** * Persistent connection type, eg RTMP. */ public static final String PERSISTENT = "persistent"; /** * Polling connection type, eg RTMPT. */ public static final String POLLING = "polling"; /** * Transient connection type, eg Remoting, HTTP, etc. */ public static final String TRANSIENT = "transient"; /** * Get the connection type. * * @return string containing one of connection types */ public String getType(); // PERSISTENT | POLLING | TRANSIENT /** * Get the object encoding (AMF version) for this connection. * * @return the used encoding. */ public Encoding getEncoding(); /** * Initialize the connection. * @param client Client object associated with connection */ public void initialize(IClient client); /** * Try to connect to the scope. * @return true on success, false otherwise * @param scope Scope object */ public boolean connect(IScope scope); /** * Try to connect to the scope with a list of connection parameters. * @param params Connections parameters * @return true on success, false otherwise * @param scope Scope object */ public boolean connect(IScope scope, Object[] params); /** * Is the client connected to the scope. Result depends on connection type, * true for persistent and polling connections, false for transient. * * @return true if the connection is persistent or polling, * otherwise false */ public boolean isConnected(); /** * Close this connection. This will disconnect the client from the * associated scope. */ public void close(); /** * Return the parameters that were given in the call to "connect". * * @return Connection parameters passed from client-side (Flex/Flash application) */ public Map getConnectParams(); /** * Get the client object associated with this connection. * * @return Client object */ public IClient getClient(); /** * Get the hostname that the client is connected to. If they are connected * to an IP, the IP address will be returned as a String. * * @return String containing the hostname */ public String getHost(); /** * Get the IP address the client is connected from. * * @return The IP address of the client */ public String getRemoteAddress(); /** * Get the IP addresses the client is connected from. If a client is connected * through RTMPT and uses a proxy to connect, this will contain all hosts the * client used to connect to the server. * * @return The IP addresses of the client */ public List getRemoteAddresses(); /** * Get the port the client is connected from. * * @return The port of the client */ public int getRemotePort(); /** * Get the path for this connection. * This is not updated if you switch scope. * * @return path Connection path */ public String getPath(); /** * Get the session id, this may be null. * * @return Session id */ public String getSessionId(); /** * Total number of bytes read from the connection. * * @return Number of read bytes */ public long getReadBytes(); /** * Total number of bytes written to the connection. * * @return Number of written bytes */ public long getWrittenBytes(); /** * Total number of messages read from the connection. * * @return Number of read messages */ public long getReadMessages(); /** * Total number of messages written to the connection. * * @return Number of written messages */ public long getWrittenMessages(); /** * Total number of messages that have been dropped. * * @return Number of dropped messages */ public long getDroppedMessages(); /** * Total number of messages that are pending to be sent to the connection. * * @return Number of pending messages */ public long getPendingMessages(); /** * Return number of written bytes the client reports to have received. * This is the last value of the BytesRead message received from a client. * * @see org.red5.server.net.rtmp.event.BytesRead * @return number of written bytes received by the client */ public long getClientBytesRead(); /** * Start measuring the roundtrip time for a packet on the connection. */ public void ping(); /** * Return roundtrip time of last ping command. * * @return roundtrip time in milliseconds */ public int getLastPingTime(); /** * Get the scope this is connected to. * * @return The connected scope */ public IScope getScope(); /** * Get the basic scopes this connection has subscribed. This list will * contain the shared objects and broadcast streams the connection * connected to. * * @return List of basic scopes */ public Iterator getBasicScopes(); /** * Sets the bandwidth using a mbit/s value. * * @param mbits */ public void setBandwidth(int mbits); } red5-1.0~svn4374.orig/src/org/red5/server/api/ICastingAttributeStore.java0000644000175000017500000000474211706617130026065 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import java.util.List; import java.util.Map; import java.util.Set; /** * Attribute storage with automatic object casting support. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface ICastingAttributeStore extends IAttributeStore { /** * Get Boolean attribute by name * * @param name Attribute name * @return Attribute */ public Boolean getBoolAttribute(String name); /** * Get Byte attribute by name * * @param name Attribute name * @return Attribute */ public Byte getByteAttribute(String name); /** * Get Double attribute by name * * @param name Attribute name * @return Attribute */ public Double getDoubleAttribute(String name); /** * Get Integer attribute by name * * @param name Attribute name * @return Attribute */ public Integer getIntAttribute(String name); /** * Get List attribute by name * * @param name Attribute name * @return Attribute */ public List getListAttribute(String name); /** * Get boolean attribute by name * * @param name Attribute name * @return Attribute */ public Long getLongAttribute(String name); /** * Get Long attribute by name * * @param name Attribute name * @return Attribute */ public Map getMapAttribute(String name); /** * Get Set attribute by name * * @param name Attribute name * @return Attribute */ public Set getSetAttribute(String name); /** * Get Short attribute by name * * @param name Attribute name * @return Attribute */ public Short getShortAttribute(String name); /** * Get String attribute by name * * @param name Attribute name * @return Attribute */ public String getStringAttribute(String name); } red5-1.0~svn4374.orig/src/org/red5/server/api/scope/0000755000175000017500000000000011760512574021730 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/scope/IScopeResolver.java0000644000175000017500000000317311747114732025502 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.scope; import org.red5.server.exception.ScopeNotFoundException; /** * Resolve the scope from given a host and path. Resolver implementations * depend on context naming strategy and so forth. */ public interface IScopeResolver { /** * Return the global scope. * * @return Global scope */ public IGlobalScope getGlobalScope(); /** * Get the scope for a given path. * * @param path Path to return the scope for * @return Scope for passed path * @throws ScopeNotFoundException If scope doesn't exist an can't be created */ public IScope resolveScope(String path); /** * Get the scope for a given path from a root scope. * * @param root The scope to start traversing from. * @param path Path to return the scope for. * @return Scope for passed path. */ public IScope resolveScope(IScope root, String path); }red5-1.0~svn4374.orig/src/org/red5/server/api/scope/ScopeType.java0000644000175000017500000000036411747114732024510 0ustar drazzibdrazzibpackage org.red5.server.api.scope; /** * Represents all the supported scope types. * * @author Paul Gregoire (mondain@gmail.com) */ public enum ScopeType { UNDEFINED, GLOBAL, APPLICATION, ROOM, BROADCAST, SHARED_OBJECT; } red5-1.0~svn4374.orig/src/org/red5/server/api/scope/IGlobalScope.java0000644000175000017500000000237011747114732025077 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.scope; import org.red5.server.api.IServer; /** * The global scope that acts as root for all applications in a host. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) * */ public interface IGlobalScope extends IScope { /** * Register the global scope in the server and initialize it */ public void register(); /** * Return the server this global scope runs in. * * @return the server */ public IServer getServer(); }red5-1.0~svn4374.orig/src/org/red5/server/api/scope/IScopeHandler.java0000644000175000017500000000773311747114732025264 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.scope; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.event.IEventHandler; import org.red5.server.api.service.IServiceCall; /** * The scope handler controls actions performed against a scope object, and also * is notified of all events. * * Gives fine grained control over what actions can be performed with the can* * methods. Allows for detailed reporting on what is happening within the scope * with the on* methods. This is the core interface users implement to create * applications. * * The thread local connection is always available via the Red5 object within * these methods * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) */ public interface IScopeHandler extends IEventHandler { /** * Called when a scope is created for the first time. * * @param scope * the new scope object * @return true to allow, false to deny */ boolean start(IScope scope); /** * Called just before a scope is disposed. * @param scope Scope that id disposed */ void stop(IScope scope); /** * Called just before every connection to a scope. You can pass additional * params from client using NetConnection.connect method (see * below). * * @param conn * Connection object * @param params * List of params passed from client via * NetConnection.connect method. All parameters * but the first one passed to NetConnection.connect * method are available as params array. * * * @return true to allow, false to deny * @param scope Scope object */ boolean connect(IConnection conn, IScope scope, Object[] params); /** * Called just after the a connection is disconnected. * * @param conn * Connection object * @param scope * Scope object */ void disconnect(IConnection conn, IScope scope); /** * Called just before a child scope is added. * * @param scope * Scope that will be added * @return true to allow, false to deny */ boolean addChildScope(IBasicScope scope); /** * Called just after a child scope has been removed. * * @param scope * Scope that has been removed */ void removeChildScope(IBasicScope scope); /** * Called just before a client enters the scope. * * @param client * Client object * @return true to allow, false to deny * connection * @param scope Scope that is joined by client */ boolean join(IClient client, IScope scope); /** * Called just after the client leaves the scope. * * @param client * Client object * @param scope * Scope object */ void leave(IClient client, IScope scope); /** * Called when a service is called. * * @param conn * The connection object * @param call * The call object. * * @return true to allow, false to deny */ boolean serviceCall(IConnection conn, IServiceCall call); } red5-1.0~svn4374.orig/src/org/red5/server/api/scope/IScopeAware.java0000644000175000017500000000217211747114732024736 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.scope; /** * Maker interface for all objects that are aware of the scope they are located * in. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) */ public interface IScopeAware { /** * Set the scope the object is located in. * * @param scope Scope for this object */ public void setScope(IScope scope); }red5-1.0~svn4374.orig/src/org/red5/server/api/scope/IScope.java0000644000175000017500000001674411747114732023770 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.scope; import java.util.Collection; import java.util.Map; import java.util.Set; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.IContext; import org.red5.server.api.service.IServiceHandlerProvider; import org.red5.server.api.statistics.IScopeStatistics; import org.springframework.core.io.support.ResourcePatternResolver; /** * The scope object. * * A stateful object shared between a group of clients connected to the same * context path. Scopes are arranged in hierarchical way, so its possible for * a scope to have a parent and children scopes. If a client connects to a scope then they are * also connected to its parent scope. The scope object is used to access * resources, shared object, streams, etc. That is, scope are general option for grouping things * in application. * * The following are all names for scopes: application, room, place, lobby. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) */ public interface IScope extends IBasicScope, ResourcePatternResolver, IServiceHandlerProvider { /** * Scope separator */ public static final String SEPARATOR = ":"; /** * Check to see if this scope has a child scope matching a given name. * * @param name the name of the child scope * @return true if a child scope exists, otherwise * false */ public boolean hasChildScope(String name); /** * Checks whether scope has a child scope with given name and type * * @param type Child scope type * @param name Child scope name * @return true if a child scope exists, otherwise * false */ public boolean hasChildScope(ScopeType type, String name); /** * Creates child scope with name given and returns success value. Returns * true on success, false if given scope * already exists among children. * * @param name New child scope name * @return true if child scope was successfully creates, * false otherwise */ public boolean createChildScope(String name); /** * Adds scope as a child scope. Returns true on success, * false if given scope is already a child of current. * * @param scope Scope given * @return true if child scope was successfully added, * false otherwise */ public boolean addChildScope(IBasicScope scope); /** * Removes scope from the children scope list. * * @param scope Scope given */ public void removeChildScope(IBasicScope scope); /** * Removes all the child scopes */ public void removeChildren(); /** * Get a set of the child scope names. * * @return set containing child scope names */ public Set getScopeNames(); public Set getBasicScopeNames(ScopeType type); /** * Return the broadcast scope for a given name * * @param name * @return broadcast scope or null if not found */ public IBroadcastScope getBroadcastScope(String name); /** * Get a child scope by type and name. * * @param type Child scope type * @param name Name of the child scope * @return the child scope, or null if no scope is found */ public IBasicScope getBasicScope(ScopeType type, String name); /** * Return scope by name * * @param name Scope name * @return Scope with given name */ public IScope getScope(String name); /** * Get a set of connected clients. You can get the connections by passing * the scope to the clients {@link IClient#getConnections()} method. * * @return Set containing all connected clients * @see org.red5.server.api.IClient#getConnections(IScope) */ public Set getClients(); /** * Get a connection iterator. You can call remove, and the connection will * be closed. * * @return Iterator holding all connections */ public Collection> getConnections(); /** * Lookup connections. * * @param client object * @return Set of connection objects (readonly) */ public Set lookupConnections(IClient client); /** * Returns scope context * * @return Scope context */ public IContext getContext(); /** * Checks whether scope has handler or not. * * @return true if scope has a handler, false * otherwise */ public boolean hasHandler(); /** * Return handler of the scope * * @return Scope handler */ public IScopeHandler getHandler(); /** * Return context path. * * @return Context path */ public String getContextPath(); /** * Adds given connection to the scope * * @param conn Given connection * @return true on success, false if given * connection already belongs to this scope */ public boolean connect(IConnection conn); /** * Add given connection to the scope, overloaded for parameters pass case. * @param conn Given connection * @param params Parameters passed * @return true on success, false if given * connection already belongs to this scope */ public boolean connect(IConnection conn, Object[] params); /** * Removes given connection from list of scope connections. This disconnects * all clients of given connection from the scope. * * @param conn Connection given */ public void disconnect(IConnection conn); /** * Return statistics informations about the scope. * * @return statistics */ public IScopeStatistics getStatistics(); /** * Set attribute by name * * @param name * @param value * @return true if added, false if not added */ public boolean setAttribute(String name, Object value); /** * Get attribute by name * * @param name * @return value for the given name in the attributes or null if not found */ public Object getAttribute(String name); /** * Whether or not an attribute exists, keyed by the given name * * @param name * @return true if it exists, false otherwise */ public boolean hasAttribute(String name); /** * Remove attribute by name * * @param name * @return true if removed, false otherwise */ public boolean removeAttribute(String name); /** * Return attribute names * * @return attribute names */ public Set getAttributeNames(); /** * Return scope attributes * * @return attributes */ public Map getAttributes(); } red5-1.0~svn4374.orig/src/org/red5/server/api/scope/IScopeService.java0000644000175000017500000000243411747114732025300 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.scope; /** * Base marker interface for all scope services. Used by the ScopeUtils to lookup * services defined as beans in Spring application context. A scope service usually can perform various * tasks on a scope like managing shared objects, streams, etc. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (bauch@struktur.de) */ public interface IScopeService { /** * Name of a bean defining that scope service. Override in * subinterfaces. * */ public static String BEAN_NAME = null; } red5-1.0~svn4374.orig/src/org/red5/server/api/scope/IBroadcastScope.java0000644000175000017500000000234311747114732025601 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.scope; import org.red5.server.api.stream.IClientBroadcastStream; import org.red5.server.messaging.IPipe; /** * Broadcast scope is marker interface that represents object that works as basic scope and * has pipe connection event dispatching capabilities. */ public interface IBroadcastScope extends IBasicScope, IPipe { public IClientBroadcastStream getClientBroadcastStream(); public void setClientBroadcastStream(IClientBroadcastStream clientBroadcastStream); } red5-1.0~svn4374.orig/src/org/red5/server/api/scope/IBasicScope.java0000644000175000017500000000512111747114732024715 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.scope; import org.red5.server.api.ICoreObject; import org.red5.server.api.event.IEventObservable; import org.red5.server.api.persistence.IPersistenceStore; /** * Base interface for all scope objects, including SharedObjects. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) */ public interface IBasicScope extends ICoreObject, IEventObservable { /** * Does this scope have a parent? You can think of scopes as of tree items * where scope may have a parent and children (child). * * @return true if this scope has a parent, otherwise * false */ public boolean hasParent(); /** * Get this scopes parent. * * @return parent scope, or null if this scope doesn't have a * parent */ public IScope getParent(); /** * Get the scopes depth, how far down the scope tree is it. The lowest depth * is 0x00, the depth of Global scope. Application scope depth is 0x01. Room * depth is 0x02, 0x03 and so forth. * * @return the depth */ public int getDepth(); /** * Get the name of this scope. Eg. someroom. * * @return the name */ public String getName(); /** * Get the persistable store * @return the store */ public IPersistenceStore getStore(); /** * Get the full absolute path. Eg. host/myapp/someroom. * * @return Absolute scope path */ public String getPath(); /** * Get the type of the scope. * * @return Type of scope */ public ScopeType getType(); /** * Sets the amount of time to keep the scope available after the * last disconnect. * * @param keepDelay delay */ public void setKeepDelay(int keepDelay); /** * Validates a scope based on its name and type * * @return true if both name and type are valid, false otherwise */ public boolean isValid(); } red5-1.0~svn4374.orig/src/org/red5/server/api/IContext.java0000644000175000017500000000770311747114732023225 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import org.red5.server.api.persistence.IPersistenceStore; import org.red5.server.api.scope.IGlobalScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeHandler; import org.red5.server.api.service.IServiceInvoker; import org.springframework.context.ApplicationContext; import org.springframework.core.io.support.ResourcePatternResolver; /** * The current context, this object basically wraps the Spring context * or in the case of the .Net version, any similar system. * */ public interface IContext extends ResourcePatternResolver { public static final String ID = "red5.context"; /** * Getter for application context * * @return Application context */ ApplicationContext getApplicationContext(); // public IScopeResolver getScopeResolver(); /** * Get client registry. Client registry is a place where all clients are * registred. * * @return Client registry object */ IClientRegistry getClientRegistry(); /** * Returns service invoker object. Service invokers are objects that make * service calls to client side NetConnection objects. * * @return Service invoker object */ IServiceInvoker getServiceInvoker(); /** * Returns persistence store object, a storage for persistent objects like * persistent SharedObjects. * * @return Persistence store object */ IPersistenceStore getPersistanceStore(); /** * Returns scope handler (object that handle all actions related to the * scope) by path. See {@link IScopeHandler} for details. * * @param path * Path of scope handler * @return Scope handler */ IScopeHandler lookupScopeHandler(String path); /** * Returns scope by path. You can think of IScope as of tree items, used to * separate context and resources between users. See {@link IScope} for more * details. * * @param path * Path of scope * @return IScope object */ IScope resolveScope(String path); /** * Returns scope by path from given root. You can think of IScope as of tree * items, used to separate context and resources between users. * See {@link IScope} for more details. * * @param root * Root to start from * @param path * Path of scope * @return IScope object */ IScope resolveScope(IScope root, String path); /** * Returns global scope reference * * @return global scope reference */ IGlobalScope getGlobalScope(); /** * Returns service by name. * * @param serviceName * Name of service * @return Service object */ Object lookupService(String serviceName); /** * Returns bean by ID * * @param beanId * Bean ID * @return Given bean instance */ Object getBean(String beanId); /** * Returns true if the context contains a certain bean, * false otherwise. * @param beanId The name of the bean to find. * @return True if the bean exists, false otherwise. */ boolean hasBean(String beanId); /** * Returns core service by bean id * * @param beanId * Bean ID * @return Core service */ Object getCoreService(String beanId); /** * Returns IMappingStrategy object * * @return IMappingStrategy object */ public IMappingStrategy getMappingStrategy(); }red5-1.0~svn4374.orig/src/org/red5/server/api/IAttributeStore.java0000644000175000017500000000631511706617130024552 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import java.util.Map; import java.util.Set; import org.red5.server.jmx.mxbeans.AttributeStoreMXBean; /** * Base interface for all API objects with attributes * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) */ public interface IAttributeStore extends AttributeStoreMXBean { /** * Get the attribute names. The resulting set will be read-only. * * @return set containing all attribute names */ public Set getAttributeNames(); /** * Get the attributes. The resulting map will be read-only. * * @return map containing all attributes */ public Map getAttributes(); /** * Set an attribute on this object. * * @param name the name of the attribute to change * @param value the new value of the attribute * @return true if the attribute value changed otherwise false */ public boolean setAttribute(String name, Object value); /** * Set multiple attributes on this object. * * @param values the attributes to set */ public void setAttributes(Map values); /** * Set multiple attributes on this object. * * @param values the attributes to set */ public void setAttributes(IAttributeStore values); /** * Return the value for a given attribute. * * @param name the name of the attribute to get * @return the attribute value or null if the attribute doesn't exist */ public Object getAttribute(String name); /** * Return the value for a given attribute and set it if it doesn't exist. * *

* This is a utility function that internally performs the following code: *

* * if (!hasAttribute(name)) setAttribute(name, defaultValue);
* return getAttribute(name);
*
*

*

* * @param name the name of the attribute to get * @param defaultValue the value of the attribute to set if the attribute doesn't * exist * @return the attribute value */ public Object getAttribute(String name, Object defaultValue); /** * Check the object has an attribute. * * @param name the name of the attribute to check * @return true if the attribute exists otherwise false */ public boolean hasAttribute(String name); /** * Remove an attribute. * * @param name the name of the attribute to remove * @return true if the attribute was found and removed otherwise false */ public boolean removeAttribute(String name); /** * Remove all attributes. */ public void removeAttributes(); } red5-1.0~svn4374.orig/src/org/red5/server/api/scheduling/0000755000175000017500000000000011760512573022743 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/scheduling/IScheduledJob.java0000644000175000017500000000250011706617130026242 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.scheduling; /** * Interface that must be implemented by classes that can be scheduled for * periodic execution. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * */ public interface IScheduledJob { /** * Called each time the job is triggered by the scheduling service. * * @param service the service that called the job * @throws CloneNotSupportedException throws is Darth Vader attempts to use * this object for his own nefarious purposes. */ public void execute(ISchedulingService service) throws CloneNotSupportedException; } red5-1.0~svn4374.orig/src/org/red5/server/api/scheduling/ISchedulingService.java0000644000175000017500000000630011747114732027324 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.scheduling; import java.util.Date; import java.util.List; import org.red5.server.api.scope.IScopeService; /** * Service that supports periodic execution of jobs, adding, removing and * getting their name as list. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Paul Gregoire (mondain@gmail.com) */ public interface ISchedulingService extends IScopeService { public static String BEAN_NAME = "schedulingService"; /** * Schedule a job for periodic execution. * * @param interval time in milliseconds between two notifications of the job * @param job the job to trigger periodically * @return the name of the scheduled job */ public String addScheduledJob(int interval, IScheduledJob job); /** * Schedule a job for single execution in the future. Please note * that the jobs are not saved if Red5 is restarted in the meantime. * * @param timeDelta time delta in milliseconds from the current date * @param job the job to trigger * @return the name of the scheduled job */ public String addScheduledOnceJob(long timeDelta, IScheduledJob job); /** * Schedule a job for single execution at a given date. Please note * that the jobs are not saved if Red5 is restarted in the meantime. * * @param date date when the job should be executed * @param job the job to trigger * @return the name of the scheduled job */ public String addScheduledOnceJob(Date date, IScheduledJob job); /** * Schedule a job for periodic execution which will start after the specifed delay. * * @param interval time in milliseconds between two notifications of the job * @param job the job to trigger periodically * @param delay time in milliseconds to pass before first execution. * @return * the name of the scheduled job */ public String addScheduledJobAfterDelay(int interval, IScheduledJob job, int delay); /** * Pauses the trigger which initiates job execution. * * @param name name of the job to stop */ public void pauseScheduledJob(String name); /** * Resumes the trigger which initiates job execution. * * @param name name of the job to stop */ public void resumeScheduledJob(String name); /** * Stop executing a previously scheduled job. * * @param name name of the job to stop */ public void removeScheduledJob(String name); /** * Return names of scheduled jobs. * * @return list of job names */ public List getScheduledJobNames(); } red5-1.0~svn4374.orig/src/org/red5/server/api/Red5.java0000644000175000017500000001253411757012455022265 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Map; import javax.management.openmbean.CompositeData; import org.red5.server.api.scope.IScope; /** * Utility class for accessing Red5 API objects. * * This class uses a thread local, and will be setup by the service invoker. * * The code below shows various uses. *
*
 
 * IConnection conn = Red5.getConnectionLocal();
 * Red5 r5 = new Red5(); 
 * IScope scope = r5.getScope();
 * conn = r5.getConnection();
 * r5 = new Red5(conn);
 * IClient client = r5.getClient();
 * 
* * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) * @author Paul Gregoire (mondain@gmail.com) */ public final class Red5 { //private static Logger log = LoggerFactory.getLogger(Red5.class); /** * Current connection thread. Each connection of Red5 application runs in a * separate thread. This is thread object associated with the current connection. */ private static ThreadLocal> connThreadLocal = new ThreadLocal>(); /** * Connection local to the current thread */ public IConnection conn; /** * Current server version with revision */ public static final String VERSION = "Red5 Server 1.0.0 RC3 $Rev: 4374 $"; /** * Current server version for fmsVer requests */ public static final String FMS_VERSION = "RED5/1,0,0,0"; /** * Data version for NetStatusEvents */ @SuppressWarnings("serial") public static final Map DATA_VERSION = new HashMap(2) { { put("version", "4,0,0,1121"); put("type", "red5"); } }; /** * Server start time */ private static final long START_TIME = System.currentTimeMillis(); /** * Create a new Red5 object using given connection. * * @param conn Connection object. */ public Red5(IConnection conn) { this.conn = conn; } /** * Create a new Red5 object using the connection local to the current thread * A bit of magic that lets you access the red5 scope from anywhere */ public Red5() { conn = Red5.getConnectionLocal(); } /** * Setter for connection * * @param connection Thread local connection */ public static void setConnectionLocal(IConnection connection) { //log.info("Set connection: {}", connection); if (connection != null) { connThreadLocal.set(new WeakReference(connection)); IScope scope = connection.getScope(); if (scope != null) { Thread.currentThread().setContextClassLoader(scope.getClassLoader()); } } else { // use null to clear the value connThreadLocal.remove(); } } /** * Get the connection associated with the current thread. This method allows * you to get connection object local to current thread. When you need to * get a connection associated with event handler and so forth, this method * provides you with it. * * @return Connection object */ public static IConnection getConnectionLocal() { WeakReference ref = connThreadLocal.get(); if (ref != null) { return ref.get(); } else { return null; } } /** * Get the connection object. * * @return Connection object */ public IConnection getConnection() { return conn; } /** * Get the scope * * @return Scope object */ public IScope getScope() { return conn.getScope(); } /** * Get the client * * @return Client object */ public IClient getClient() { return conn.getClient(); } /** * Get the spring application context * * @return Application context */ public IContext getContext() { return conn.getScope().getContext(); } /** * Returns the current version with revision number * * @return String version */ public static String getVersion() { return VERSION; } /** * Returns the current version for fmsVer requests * * @return String fms version */ public static String getFMSVersion() { return FMS_VERSION; } public static Object getDataVersion() { return DATA_VERSION; } /** * Returns server uptime in milliseconds. * * @return String version */ public static long getUpTime() { return System.currentTimeMillis() - START_TIME; } /** * Allows for reconstruction via CompositeData. * * @param cd composite data * @return Red5 class instance */ public static Red5 from(CompositeData cd) { Red5 instance = null; if (cd.containsKey("connection")) { Object cn = cd.get("connection"); if (cn != null && cn instanceof IConnection) { instance = new Red5((IConnection) cn); } else { instance = new Red5(); } } else { instance = new Red5(); } return instance; } } red5-1.0~svn4374.orig/src/org/red5/server/api/IMappingStrategy.java0000644000175000017500000000302411706617130024702 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; /** * This interface encapsulates the mapping strategy used by the context. */ public interface IMappingStrategy { /** * Map a name to the name of a service. * * @param name name to map * @return The name of the service with the passed name */ public String mapServiceName(String name); /** * Map a context path to the name of a scope handler. * * @param contextPath context path to map * @return The name of a scope handler */ public String mapScopeHandlerName(String contextPath); /** * Map a context path to a path prefix for resources. * * @param contextPath context path to map * @return The path prefix for resources with the given name */ public String mapResourcePrefix(String contextPath); }red5-1.0~svn4374.orig/src/org/red5/server/api/persistence/0000755000175000017500000000000011760512573023142 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/persistence/IPersistenceStore.java0000644000175000017500000000546611706617130027425 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.persistence; import java.util.Collection; import java.util.Set; /** * Storage for persistent objects. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) * @author Joachim Bauch (jojo@struktur.de) */ public interface IPersistenceStore { /** * Persist given object. * * @param obj Object to store * @return true on success, false otherwise */ public boolean save(IPersistable obj); /** * Load a persistent object with the given name. The object must provide * either a constructor that takes an input stream as only parameter or an * empty constructor so it can be loaded from the persistence store. * * @param name the name of the object to load * @return The loaded object or null if no such object was * found */ public IPersistable load(String name); /** * Load state of an already instantiated persistent object. * * @param obj the object to initializ * @return true if the object was initialized, false otherwise */ public boolean load(IPersistable obj); /** * Delete the passed persistent object. * * @param obj the object to delete * @return true if object was persisted and thus can be removed, false otherwise */ public boolean remove(IPersistable obj); /** * Delete the persistent object with the given name. * * @param name the name of the object to delete * @return true if object was persisted and thus can be removed, false otherwise */ public boolean remove(String name); /** * Return iterator over the names of all already loaded objects in the * storage. * * @return Set of all object names */ public Set getObjectNames(); /** * Return iterator over the already loaded objects in the storage. * * @return Set of all objects */ public Collection getObjects(); /** * Notify store that it's being closed. This allows the store to write * any pending objects to disk. */ public void notifyClose(); } red5-1.0~svn4374.orig/src/org/red5/server/api/persistence/IPersistable.java0000644000175000017500000000704111706617130026370 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.persistence; import java.io.IOException; import org.red5.io.object.Input; import org.red5.io.object.Output; /** * Base interface for objects that can be made persistent. * * Every object that complies to this interface must provide either a * constructor that takes an input stream as only parameter or an empty * constructor so it can be loaded from the persistence store. * * However this is not required for objects that are created by the application * and initialized afterwards. * * @see org.red5.io.object.Input * @see IPersistenceStore#load(String) * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) * @author Joachim Bauch (jojo@struktur.de) */ public interface IPersistable { /** * Prefix for attribute names that should not be made persistent. */ public static final String TRANSIENT_PREFIX = "_transient"; /** * Returns true if the object is persistent, * false otherwise. * * @return true if object is persistent, false otherwise */ public boolean isPersistent(); /** * Set the persistent flag of the object. * * @param persistent true if object is persistent, false otherwise */ public void setPersistent(boolean persistent); /** * Returns the name of the persistent object. * * @return Object name */ public String getName(); /** * Set the name of the persistent object. * * @param name New object name */ public void setName(String name); /** * Returns the type of the persistent object. * * @return Object type */ public String getType(); /** * Returns the path of the persistent object. * * @return Persisted object path */ public String getPath(); /** * Set the path of the persistent object. * * @param path New persisted object path */ public void setPath(String path); /** * Returns the timestamp when the object was last modified. * * @return Last modification date in milliseconds */ public long getLastModified(); /** * Returns the persistence store this object is stored in * * @return This object's persistence store */ public IPersistenceStore getStore(); /** * Store a reference to the persistence store in the object. * * @param store * Store the object is saved in */ void setStore(IPersistenceStore store); /** * Write the object to the passed output stream. * * @param output * Output stream to write to * @throws java.io.IOException Any I/O exception */ void serialize(Output output) throws IOException; /** * Load the object from the passed input stream. * * @param input * Input stream to load from * @throws java.io.IOException Any I/O exception */ void deserialize(Input input) throws IOException; } red5-1.0~svn4374.orig/src/org/red5/server/api/persistence/PersistenceUtils.java0000644000175000017500000000606511745776105027327 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.persistence; import java.lang.reflect.Constructor; import org.springframework.core.io.support.ResourcePatternResolver; /** * Helper class for persistence. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class PersistenceUtils { /** * Returns persistence store object class constructor * * @param theClass Persistence store class * @param interfaces Interfaces that are being implemented by persistence store object class * @return Constructor * @throws Exception */ private static Constructor getPersistenceStoreConstructor(Class theClass, Class[] interfaces) throws Exception { Constructor constructor = null; for (Class interfaceClass : interfaces) { try { constructor = theClass.getConstructor(new Class[] { interfaceClass }); } catch (NoSuchMethodException err) { // Ignore this error } if (constructor != null) { break; } constructor = getPersistenceStoreConstructor(theClass, interfaceClass.getInterfaces()); if (constructor != null) { break; } } return constructor; } /** * Returns persistence store object. Persistence store is a special object * that stores persistence objects and provides methods to manipulate them * (save, load, remove, list). * * @param resolver Resolves connection pattern into Resource object * @param className Name of persistence class * @return IPersistence store object that provides methods for persistence object handling * @throws Exception if error */ public static IPersistenceStore getPersistenceStore(ResourcePatternResolver resolver, String className) throws Exception { Class persistenceClass = Class.forName(className); Constructor constructor = getPersistenceStoreConstructor(persistenceClass, resolver.getClass().getInterfaces()); if (constructor == null) { // Search in superclasses of the object. Class superClass = resolver.getClass().getSuperclass(); while (superClass != null) { constructor = getPersistenceStoreConstructor(persistenceClass, superClass.getInterfaces()); if (constructor != null) { break; } superClass = superClass.getSuperclass(); } } if (constructor == null) { throw new NoSuchMethodException(); } return (IPersistenceStore) constructor.newInstance(new Object[] { resolver }); } } red5-1.0~svn4374.orig/src/org/red5/server/api/IClientRegistry.java0000644000175000017500000000430711706617130024540 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import org.red5.server.exception.ClientNotFoundException; import org.red5.server.exception.ClientRejectedException; /** * Provides a registry of client objects. * You can lookup a client by its client id / session id using lookupClient method. * This interface implementations also create new client objects from given params, usually * passed from client-side Flex/Flash application upon initial connection. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) */ public interface IClientRegistry { /** * Check if a client with a given id exists. * * @param id the id of the client to check for * @return true if the client exists, false otherwise */ public boolean hasClient(String id); /** * Create a new client client object from connection params. * * @param params the parameters the client passed during connection * @return the new client * @throws ClientNotFoundException no client could be created from the passed parameters * @throws ClientRejectedException the client is not allowed to connect */ public IClient newClient(Object[] params) throws ClientNotFoundException, ClientRejectedException; /** * Return an existing client from a client id. * * @param id the id of the client to return * @return the client object * @throws ClientNotFoundException no client with the passed id exists */ public IClient lookupClient(String id) throws ClientNotFoundException; }red5-1.0~svn4374.orig/src/org/red5/server/api/session/0000755000175000017500000000000011760512573022301 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/session/ISession.java0000644000175000017500000000436011706617130024676 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.session; import java.io.Serializable; /** * Represents the most basic type of "Session", loosely modeled after the HTTP Session used * in J2EE applications. * * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public interface ISession extends Serializable { /** * Returns creation time in milliseconds. * * @return creation time */ public long getCreated(); /** * Returns the session's identifier. * * @return session id */ public String getSessionId(); /** * Resets a specified set of internal parameters. */ public void reset(); /** * Returns the active state of the session. * @return is active */ public boolean isActive(); /** * Ends the session, no further modifications should be allowed. */ public void end(); /** * Sets the associated client id. * * @param clientId client id */ public void setClientId(String clientId); /** * Returns the client id associated with this session. * * @return client id */ public String getClientId(); /** * Sets where session resources will be located if persisted to disk. * * @param destinationDirectory destination directory */ public void setDestinationDirectory(String destinationDirectory); /** * Returns the directory used to store session resources. * * @return destination directory */ public String getDestinationDirectory(); } red5-1.0~svn4374.orig/src/org/red5/server/api/remoting/0000755000175000017500000000000011760512573022442 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/api/remoting/IRemotingHeader.java0000644000175000017500000000363011706617130026310 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.remoting; /** * A Remoting header. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IRemotingHeader { /** Name of header specifying string to add to gateway url. */ public static final String APPEND_TO_GATEWAY_URL = "AppendToGatewayUrl"; /** Name of header specifying new gateway url to use. */ public static final String REPLACE_GATEWAY_URL = "ReplaceGatewayUrl"; /** Name of header specifying new header to send. */ public static final String PERSISTENT_HEADER = "RequestPersistentHeader"; /** Name of header containing authentication data. */ public static final String CREDENTIALS = "Credentials"; /** Name of header to request debug informations from the server. */ public static final String DEBUG_SERVER = "amf_server_debug"; /** * Return name of header. * * @return name of header */ public String getName(); /** * Return value of header. * * @return value of header */ public Object getValue(); /** * Return boolean flag if receiver must process header before handling * other headers or messages. * * @return must understand */ public boolean getMustUnderstand(); } red5-1.0~svn4374.orig/src/org/red5/server/api/remoting/IRemotingConnection.java0000644000175000017500000000417311706617130027222 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api.remoting; import java.util.Collection; import org.red5.server.api.IConnection; /** * Connection coming from Remoting clients. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public interface IRemotingConnection extends IConnection { /** * Tell the client to add a header with all further requests. This is * returned to the client as response for the next request received. * * @param name name of the header to add * @param value value of the header to add */ public void addHeader(String name, Object value); /** * Tell the client to add a header with all further requests. This is * returned to the client as response for the next request received. * * @param name name of the header to add * @param value value of the header to add * @param mustUnderstand a boolean flag specifying if the server must pocess this header * before handling following headers or messages */ public void addHeader(String name, Object value, boolean mustUnderstand); /** * Tell the client to no longer send a header with all further requests. * This is returned to the client as response for the next request * received. * * @param name name of the header to remove */ public void removeHeader(String name); /** * Return headers to send. * * @return headers to send */ public Collection getHeaders(); } red5-1.0~svn4374.orig/src/org/red5/server/api/IServer.java0000644000175000017500000000736711747114732023055 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.api; import java.util.Iterator; import java.util.Map; import org.red5.server.api.listeners.IConnectionListener; import org.red5.server.api.listeners.IScopeListener; import org.red5.server.api.scope.IGlobalScope; /** * The interface that represents the Red5 server. * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard (luke@codegent.com) * */ public interface IServer { /** * Server ID */ public static final String ID = "red5.server"; /** * Get the global scope with given name. * * @param name Name of the global scope * @return the global scope */ public IGlobalScope getGlobal(String name); /** * Register a global scope. * * @param scope The global scope to register */ public void registerGlobal(IGlobalScope scope); /** * Lookup the global scope for a host. * * @param hostName The name of the host * @param contextPath The path in the host * @return The found global scope or null */ public IGlobalScope lookupGlobal(String hostName, String contextPath); /** * Map a virtual hostname and a path to the name of a global scope. * * @param hostName The name of the host to map * @param contextPath The path to map * @param globalName The name of the global scope to map to * @return true if the name was mapped, otherwise * false */ public boolean addMapping(String hostName, String contextPath, String globalName); /** * Unregister a previously mapped global scope. * * @param hostName The name of the host to unmap * @param contextPath The path for this host to unmap * @return true if the global scope was unmapped, otherwise * false */ public boolean removeMapping(String hostName, String contextPath); /** * Query informations about the global scope mappings. * * @return Map containing informations about the mappings */ public Map getMappingTable(); /** * Get list of global scope names. * * @return Iterator for names of global scopes */ public Iterator getGlobalNames(); /** * Get list of global scopes. * * @return Iterator for global scopes objects */ public Iterator getGlobalScopes(); /** * Add listener to get notified about scope events. * * @param listener the listener to add */ public void addListener(IScopeListener listener); /** * Add listener to get notified about connection events. * * @param listener the listener to add */ public void addListener(IConnectionListener listener); /** * Remove listener that got notified about scope events. * * @param listener the listener to remove */ public void removeListener(IScopeListener listener); /** * Remove listener that got notified about connection events. * * @param listener the listener to remove */ public void removeListener(IConnectionListener listener); } red5-1.0~svn4374.orig/src/org/red5/server/MappingStrategy.java0000644000175000017500000000547511706617130024034 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import org.red5.server.api.IMappingStrategy; /** * Basic mapping strategy implementation. This one uses slash as filesystem path separator, * '.service' postfix for services naming, '.handler' for handlers naming and 'default' string as * default application name. */ public class MappingStrategy implements IMappingStrategy { /** * Root constant */ private static final String ROOT = ""; /** * Handler extension constant */ private static final String HANDLER = ".handler"; /** * Dir separator constant */ private static final String DIR = "/"; /** * Service extension constant */ private static final String SERVICE = ".service"; /** * Default application name */ private String defaultApp = "default"; /** * Setter for default application name ('default' by default). * @param defaultApp Default application */ public void setDefaultApp(String defaultApp) { this.defaultApp = defaultApp; } /** * Resolves resource prefix from path. Default application used as root when path is specified * @param path Path * @return Resource prefix according to this naming strategy */ public String mapResourcePrefix(String path) { if (path == null || path.equals(ROOT)) { return defaultApp + DIR; } else { return path + DIR; } } /** * Resolves scope handler name for path& Default application used as root when path is specified * @param path Path * @return Scope handler name according to this naming strategy */ public String mapScopeHandlerName(String path) { if (path == null || path.equals(ROOT)) { return defaultApp + HANDLER; } else { return path + HANDLER; } } /** * Resolves service filename name from name * @param name Service name * @return Service filename according to this naming strategy */ public String mapServiceName(String name) { return name + SERVICE; } } red5-1.0~svn4374.orig/src/org/red5/server/exception/0000755000175000017500000000000011760512571022041 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/exception/ServiceNotFoundException.java0000644000175000017500000000172311706617130027640 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.exception; /** * Thrown when server can't be found */ public class ServiceNotFoundException extends RuntimeException { /** * */ private static final long serialVersionUID = -2400159517485748708L; } red5-1.0~svn4374.orig/src/org/red5/server/exception/AccessDeniedException.java0000644000175000017500000000167311706617130027101 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.exception; /** * Access denied */ public class AccessDeniedException extends RuntimeException { /** * */ private static final long serialVersionUID = 2023603817704741161L; } red5-1.0~svn4374.orig/src/org/red5/server/exception/StreamControlException.java0000644000175000017500000000171011706617130027353 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.exception; /** * Stream control exception */ public class StreamControlException extends RuntimeException { /** * */ private static final long serialVersionUID = -8396541091694329882L; } red5-1.0~svn4374.orig/src/org/red5/server/exception/ClientNotFoundException.java0000644000175000017500000000217711706617130027462 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.exception; /** * Client not found */ public class ClientNotFoundException extends RuntimeException { /** * */ private static final long serialVersionUID = 3135070223941800751L; /** * Create exception from given string message * @param id id */ public ClientNotFoundException(String id) { super("Client \"" + id + "\" not found."); } } red5-1.0~svn4374.orig/src/org/red5/server/exception/StreamDataException.java0000644000175000017500000000171311706617130026607 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.exception; /** * Thrown on stream data exception */ public class StreamDataException extends RuntimeException { /** * */ private static final long serialVersionUID = 5529626622367065317L; } red5-1.0~svn4374.orig/src/org/red5/server/exception/ScopeNotFoundException.java0000644000175000017500000000251311747114732027314 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.exception; import org.red5.server.api.scope.IScope; /** * Scope not found, thrown when child scope wasn't found. */ public class ScopeNotFoundException extends RuntimeException { /** * */ private static final long serialVersionUID = -8512088658139018041L; /** * Create exception from given scope object and given child subscope * @param scope Scope * @param childName Subscope name */ public ScopeNotFoundException(IScope scope, String childName) { super("Scope not found: " + childName + " in " + scope); } } red5-1.0~svn4374.orig/src/org/red5/server/exception/ScopeHandlerNotFoundException.java0000644000175000017500000000234211747114732030612 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.exception; /** * Scope handler not found. Thrown when scope handler with given name can't be found */ public class ScopeHandlerNotFoundException extends RuntimeException { private static final long serialVersionUID = 1894151808129303439L; /** * Create exception from given scope handler name * @param handlerName Scope handler name */ public ScopeHandlerNotFoundException(String handlerName) { super("No scope handler found: " + handlerName); } } red5-1.0~svn4374.orig/src/org/red5/server/exception/ClientRejectedException.java0000644000175000017500000000303111706617130027441 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.exception; /** * The client is not allowed to connect. Reason that provided with this * exception is sent to client-side status event description. * */ public class ClientRejectedException extends RuntimeException { private static final long serialVersionUID = 9204597649465357898L; @SuppressWarnings("all") private Object reason; /** Constructs a new ClientRejectedException. */ public ClientRejectedException() { this("Client rejected"); } /** * Create new exception with given rejection reason * @param reason Rejection reason */ public ClientRejectedException(Object reason) { super("Client rejected"); this.reason = reason; } /** * Getter for reason * * @return Rejection reason */ public Object getReason() { return reason; } } red5-1.0~svn4374.orig/src/org/red5/server/exception/ScopeShuttingDownException.java0000644000175000017500000000221311747114732030212 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.exception; import org.red5.server.api.scope.IScope; /** * Scope is currently shutting down. */ public class ScopeShuttingDownException extends RuntimeException { private static final long serialVersionUID = 9129189610425512289L; /** * Create exception from given scope object * @param scope Scope */ public ScopeShuttingDownException(IScope scope) { super("Scope shutting down: " + scope); } } red5-1.0~svn4374.orig/src/org/red5/server/exception/ClientDetailsException.java0000644000175000017500000000430311706617130027304 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.exception; /** * Exception class than contains additional parameters to return to the client. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class ClientDetailsException extends RuntimeException { /** * */ private static final long serialVersionUID = -1908769505547253205L; /** * Parameters to return to the client. */ private Object parameters; /** * Also return stacktrace to client? */ private boolean stacktrace; /** * Create new exception object from message and parameters. By default, no * stacktrace is returned to the client. * * @param message message * @param params parameters for message */ public ClientDetailsException(String message, Object params) { this(message, params, false); } /** * Create new exception object from message and parameters with optional stacktrace. * * @param message message * @param params parameters * @param includeStacktrace whether or not to include a stack trace */ public ClientDetailsException(String message, Object params, boolean includeStacktrace) { super(message); this.parameters = params; this.stacktrace = includeStacktrace; } /** * Get parameters to return to the client. * * @return parameters */ public Object getParameters() { return parameters; } /** * Should the stacktrace returned to the client? * * @return stacktrace */ public boolean includeStacktrace() { return stacktrace; } } red5-1.0~svn4374.orig/src/org/red5/server/exception/SharedObjectException.java0000644000175000017500000000173311706617130027121 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.exception; /** * Base for all shared object-related exceptions */ public class SharedObjectException extends RuntimeException { /** * */ private static final long serialVersionUID = 4152370716169030341L; } red5-1.0~svn4374.orig/src/org/red5/server/ClientRegistry.java0000644000175000017500000001467311751004261023660 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.lang.management.ManagementFactory; import java.util.Collection; import java.util.Collections; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.StandardMBean; import org.apache.commons.lang3.StringUtils; import org.red5.server.api.IClient; import org.red5.server.api.IClientRegistry; import org.red5.server.exception.ClientNotFoundException; import org.red5.server.exception.ClientRejectedException; import org.red5.server.jmx.mxbeans.ClientRegistryMXBean; import org.springframework.jmx.export.annotation.ManagedResource; /** * Registry for clients. Associates client with it's id so it's possible to get client by id * from whenever we need. * * @author The Red5 Project (red5@osflash.org) */ @ManagedResource(objectName="org.red5.server:type=ClientRegistry,name=default", description="ClientRegistry") public class ClientRegistry implements IClientRegistry, ClientRegistryMXBean { /** * Clients map */ private ConcurrentMap clients = new ConcurrentHashMap(); /** * Next client id */ private AtomicInteger nextId = new AtomicInteger(); /** * The identifier for this client registry */ private String name; public ClientRegistry() { } //allows for setting a "name" to be used with jmx for lookup public ClientRegistry(String name) { this.name = name; if (StringUtils.isNotBlank(this.name)) { try { MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); ObjectName oName = new ObjectName("org.red5.server:type=ClientRegistry,name=" + name); mbeanServer.registerMBean(new StandardMBean(this, ClientRegistryMXBean.class, true), oName); } catch (Exception e) { //log.warn("Error on jmx registration", e); } } } /** * Add client to registry * @param client Client to add */ protected void addClient(IClient client) { addClient(client.getId(), client); } /** * Add the client to the registry */ private void addClient(String id, IClient client) { //check to see if the id already exists first if (!hasClient(id)) { clients.put(id, client); } else { // DW the Client object is meant to be unifying connections from a remote user. But currently the only case we // specify this currently is when we use a remoting session. So we actually just create an arbitrary id, which means // RTMP connections from same user are not combined. //get the next available client id String newId = nextId(); //update the client client.setId(newId); //add the client to the list addClient(newId, client); } } public Client getClient(String id) throws ClientNotFoundException { Client result = (Client) clients.get(id); if (result == null) { throw new ClientNotFoundException(id); } return result; } /** * Returns a list of Clients. */ public ClientList getClientList() { ClientList list = new ClientList(); for (IClient c : clients.values()) { list.add((Client) c); } return list; } /** * Check if client registry contains clients. * * @return True if clients exist, otherwise False */ protected boolean hasClients() { return !clients.isEmpty(); } /** * Return collection of clients * @return Collection of clients */ @SuppressWarnings("unchecked") protected Collection getClients() { if (!hasClients()) { // Avoid creating new Collection object if no clients exist. return Collections.EMPTY_SET; } return Collections.unmodifiableCollection(clients.values()); } /** * Check whether registry has client with given id * * @param id Client id * @return true if client with given id was register with this registry, false otherwise */ public boolean hasClient(String id) { if (id == null) { // null ids are not supported return false; } return clients.containsKey(id); } /** * Return client by id * * @param id Client id * @return Client object associated with given id * @throws ClientNotFoundException if we can't find client */ public IClient lookupClient(String id) throws ClientNotFoundException { return getClient(id); } /** * Return client from next id with given params * * @param params Client params * @return Client object * @throws ClientNotFoundException if client not found * @throws ClientRejectedException if client rejected */ public IClient newClient(Object[] params) throws ClientNotFoundException, ClientRejectedException { // DW I'm guessing perhaps that originally there was some idea to derive client id from the connection params? String id = nextId(); IClient client = new Client(id, this); addClient(id, client); return client; } /** * Return next client id * @return Next client id */ public String nextId() { //when we reach max int, reset to zero if (nextId.get() == Integer.MAX_VALUE) { nextId.set(0); } return String.format("%s", nextId.getAndIncrement()); } /** * Return previous client id * @return Previous client id */ public String previousId() { return String.format("%s", nextId.get()); } /** * Removes client from registry * @param client Client to remove */ protected void removeClient(IClient client) { clients.remove(client.getId()); } } red5-1.0~svn4374.orig/src/org/red5/server/persistence/0000755000175000017500000000000011760512571022367 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/persistence/RamPersistence.java0000644000175000017500000001155211747114732026164 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.persistence; import java.util.Collection; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.red5.server.api.persistence.IPersistable; import org.red5.server.api.persistence.IPersistenceStore; import org.red5.server.api.scope.IScope; import org.red5.server.util.ScopeUtils; import org.springframework.core.io.support.ResourcePatternResolver; /** * Persistence implementation that stores the objects in memory. * This serves as default persistence if nothing has been configured. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) * @author Michael Klishin (michael@novemberain.com) */ public class RamPersistence implements IPersistenceStore { /** This is used in the id for objects that have a name of null **/ protected static final String PERSISTENCE_NO_NAME = "__null__"; /** * Map for persistable objects */ protected ConcurrentMap objects = new ConcurrentHashMap(); /** * Resource pattern resolver. Resolves resources from patterns, loads resources. */ protected ResourcePatternResolver resources; /** * Creates RAM persistence object from resource pattern resolvers * @param resources Resource pattern resolver and loader */ public RamPersistence(ResourcePatternResolver resources) { this.resources = resources; } /** * Creates RAM persistence object from scope * @param scope Scope */ public RamPersistence(IScope scope) { this((ResourcePatternResolver) ScopeUtils.findApplication(scope)); } /** * Get resource name from path * @param id Object ID. The format of the object id is //. * @return Resource name */ protected String getObjectName(String id) { // The format of the object id is // String result = id.substring(id.lastIndexOf('/') + 1); if (result.equals(PERSISTENCE_NO_NAME)) { result = null; } return result; } /** * Get object path for given id and name * @param id Object ID. The format of the object id is // * @param name Object name * @return Resource path */ protected String getObjectPath(String id, String name) { // The format of the object id is // id = id.substring(id.indexOf('/') + 1); if (id.charAt(0) == '/') { id = id.substring(1); } if (id.lastIndexOf(name) <= 0) { return id; } return id.substring(0, id.lastIndexOf(name) - 1); } /** * Get object id * @param object Persistable object whose id is asked for * @return Given persistable object id */ protected String getObjectId(IPersistable object) { // The format of the object id is // String result = object.getType(); if (object.getPath().charAt(0) != '/') { result += '/'; } result += object.getPath(); if (!result.endsWith("/")) { result += '/'; } String name = object.getName(); if (name == null) { name = PERSISTENCE_NO_NAME; } if (name.charAt(0) == '/') { // "result" already ends with a slash name = name.substring(1); } return result + name; } /** {@inheritDoc} */ public boolean save(IPersistable object) { final String key = getObjectId(object); objects.put(key, object); return true; } /** {@inheritDoc} */ public IPersistable load(String name) { return objects.get(name); } /** {@inheritDoc} */ public boolean load(IPersistable obj) { return obj.isPersistent(); } /** {@inheritDoc} */ public boolean remove(IPersistable object) { return remove(getObjectId(object)); } /** {@inheritDoc} */ public boolean remove(String name) { if (!objects.containsKey(name)) { return false; } objects.remove(name); return true; } /** {@inheritDoc} */ public Set getObjectNames() { return objects.keySet(); } /** {@inheritDoc} */ public Collection getObjects() { return objects.values(); } /** {@inheritDoc} */ public void notifyClose() { objects.clear(); } } red5-1.0~svn4374.orig/src/org/red5/server/persistence/FilePersistence.java0000644000175000017500000003705211747114732026327 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.persistence; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import org.apache.mina.core.buffer.IoBuffer; import org.red5.io.amf.Input; import org.red5.io.amf.Output; import org.red5.io.object.Deserializer; import org.red5.server.api.persistence.IPersistable; import org.red5.server.api.scope.IScope; import org.red5.server.net.servlet.ServletUtils; import org.red5.server.so.SharedObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.web.context.support.ServletContextResource; /** * Simple file-based persistence for objects. Lowers memory usage if used instead of RAM memory storage. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class FilePersistence extends RamPersistence { /** * Logger */ private Logger log = LoggerFactory.getLogger(FilePersistence.class); /** * Files path */ private String path = "persistence"; /** * Root directory under file storage path */ private String rootDir = ""; /** * File extension for persistent objects */ private String extension = ".red5"; /** * Whether there's need to check for empty directories */ // TODO: make this configurable private boolean checkForEmptyDirectories = true; /** * Thread to serialize persistent objects. */ private FilePersistenceThread storeThread = null; /** * Create file persistence object from given resource pattern resolver * @param resolver Resource pattern resolver and loader */ public FilePersistence(ResourcePatternResolver resolver) { super(resolver); setPath(path); } /** * Create file persistence object for given scope * @param scope Scope */ public FilePersistence(IScope scope) { super(scope); setPath(path); } /** * Setter for file path. * * @param path New path */ public void setPath(String path) { log.debug("Set path: {}", path); Resource rootFile = resources.getResource(path); try { // check for existence if (!rootFile.exists()) { log.debug("Persistence directory does not exist"); if (rootFile instanceof ServletContextResource) { ServletContextResource servletResource = (ServletContextResource) rootFile; String contextPath = servletResource.getServletContext().getContextPath(); log.debug("Persistence context path: {}", contextPath); if ("/".equals(contextPath)) { contextPath = "/root"; } rootDir = String.format("%s/webapps%s/persistence", System.getProperty("red5.root"), contextPath); log.debug("Persistence directory path: {}", rootDir); File persistDir = new File(rootDir); if (!persistDir.mkdir()) { log.warn("Persistence directory creation failed"); } else { log.debug("Persistence directory access - read: {} write: {}", persistDir.canRead(), persistDir.canWrite()); } persistDir = null; } } else { rootDir = rootFile.getFile().getAbsolutePath(); } log.debug("Root dir: {} path: {}", rootDir, path); this.path = path; } catch (IOException err) { log.error("I/O exception thrown when setting file path to {}", path, err); throw new RuntimeException(err); } storeThread = FilePersistenceThread.getInstance(); } /** * Setter for extension. * * @param extension New extension. */ public void setExtension(String extension) { this.extension = extension; } /** * Return file path for persistable object * @param object Object to obtain file path for * @return Path on disk */ private String getObjectFilepath(IPersistable object) { return getObjectFilepath(object, false); } /** * Return file path for persistable object * @param object Object to obtain file path for * @param completePath Whether it full path full path sould be returned * @return Path on disk */ private String getObjectFilepath(IPersistable object, boolean completePath) { StringBuilder result = new StringBuilder(path); result.append('/'); result.append(object.getType()); result.append('/'); String objectPath = object.getPath(); log.debug("Object path: {}", objectPath); result.append(objectPath); if (!objectPath.endsWith("/")) { result.append('/'); } if (completePath) { String name = object.getName(); log.debug("Object name: {}", name); int pos = name.lastIndexOf('/'); if (pos >= 0) { result.append(name.substring(0, pos)); } } //fix up path int idx = -1; if (File.separatorChar != '/') { while ((idx = result.indexOf(File.separator)) != -1) { result.deleteCharAt(idx); result.insert(idx, '/'); } } if (log.isDebugEnabled()) { log.debug("Path step 1: {}", result.toString()); } //remove any './' if ((idx = result.indexOf("./")) != -1) { result.delete(idx, idx + 2); } if (log.isDebugEnabled()) { log.debug("Path step 2: {}", result.toString()); } //remove any '//' while ((idx = result.indexOf("//")) != -1) { result.deleteCharAt(idx); } if (log.isDebugEnabled()) { log.debug("Path step 3: {}", result.toString()); } return result.toString(); } /** {@inheritDoc} */ @Override protected String getObjectPath(String id, String name) { if (id.startsWith(path)) { id = id.substring(path.length() + 1); } return super.getObjectPath(id, name); } /** * Get filename for persistable object * @param object Persistable object * @return Name of file where given object is persisted to */ private String getObjectFilename(IPersistable object) { String path = getObjectFilepath(object); String name = object.getName(); if (name == null) { name = PERSISTENCE_NO_NAME; } return path + name + extension; } /** * Load resource with given name * @param name Resource name * @return Persistable object */ private IPersistable doLoad(String name) { return doLoad(name, null); } /** * Load resource with given name and attaches to persistable object * @param name Resource name * @param object Object to attach to * @return Persistable object */ private IPersistable doLoad(String name, IPersistable object) { IPersistable result = object; Resource data = resources.getResource(name); if (data == null || !data.exists()) { // No such file return null; } FileInputStream input; String filename; try { File fp = data.getFile(); if (fp.length() == 0) { // File is empty log.error("The file at {} is empty.", data.getFilename()); return null; } filename = fp.getAbsolutePath(); input = new FileInputStream(filename); } catch (FileNotFoundException e) { log.error("The file at {} does not exist.", data.getFilename()); return null; } catch (IOException e) { log.error("Could not load file from {}.", data.getFilename(), e); return null; } try { IoBuffer buf = IoBuffer.allocate(input.available()); try { ServletUtils.copy(input, buf.asOutputStream()); buf.flip(); Input in = new Input(buf); Deserializer deserializer = new Deserializer(); String className = deserializer.deserialize(in, String.class); if (result == null) { // we need to create the object first try { Class theClass = Class.forName(className); Constructor constructor = null; try { // try to create object by calling constructor with Input stream as parameter for (Class interfaceClass : in.getClass().getInterfaces()) { constructor = theClass.getConstructor(new Class[] { interfaceClass }); if (constructor != null) { break; } } if (constructor == null) { throw new NoSuchMethodException(); } result = (IPersistable) constructor.newInstance(in); } catch (NoSuchMethodException err) { // no valid constructor found, use empty constructor result = (IPersistable) theClass.newInstance(); result.deserialize(in); } catch (InvocationTargetException err) { // error while invoking found constructor, use empty constructor result = (IPersistable) theClass.newInstance(); result.deserialize(in); } } catch (ClassNotFoundException cnfe) { log.error("Unknown class {}", className); return null; } catch (IllegalAccessException iae) { log.error("Illegal access", iae); return null; } catch (InstantiationException ie) { log.error("Could not instantiate class {}", className); return null; } // set object's properties result.setName(getObjectName(name)); result.setPath(getObjectPath(name, result.getName())); } else { // Initialize existing object String resultClass = result.getClass().getName(); if (!resultClass.equals(className)) { log.error("The classes differ: {} != {}", resultClass, className); return null; } result.deserialize(in); } } finally { buf.free(); buf = null; } if (result.getStore() != this) { result.setStore(this); } super.save(result); log.debug("Loaded persistent object {} from {}", result, filename); } catch (IOException e) { log.error("Could not load file at {}", filename); return null; } return result; } /** {@inheritDoc} */ @Override public IPersistable load(String name) { IPersistable result = super.load(name); if (result != null) { // Object has already been loaded return result; } return doLoad(path + '/' + name + extension); } /** {@inheritDoc} */ @Override public boolean load(IPersistable object) { if (object.isPersistent()) { // Already loaded return true; } return (doLoad(getObjectFilename(object), object) != null); } /** * Save persistable object * @param object Persistable object * @return true on success, false otherwise */ protected boolean saveObject(IPersistable object) { boolean result = true; String path = getObjectFilepath(object, true); log.debug("Path: {}", path); Resource resPath = resources.getResource(path); boolean exists = resPath.exists(); log.debug("Resource (dir) check #1 - file name: {} exists: {}", resPath.getFilename(), exists); File dir = null; try { if (!exists) { resPath = resources.getResource("classpath:" + path); exists = resPath.exists(); log.debug("Resource (dir) check #2 - file name: {} exists: {}", resPath.getFilename(), exists); if (!exists) { StringBuilder root = new StringBuilder(rootDir); //fix up path int idx = -1; if (File.separatorChar != '/') { while ((idx = root.indexOf(File.separator)) != -1) { root.deleteCharAt(idx); root.insert(idx, '/'); } } resPath = resources.getResource("file://" + root.toString() + path.substring(11)); exists = resPath.exists(); log.debug("Resource (dir) check #3 - file name: {} exists: {}", resPath.getFilename(), exists); } } dir = resPath.getFile(); if (!dir.isDirectory() && !dir.mkdirs()) { log.error("Could not create directory {}", dir.getAbsolutePath()); result = false; } } catch (IOException err) { log.error("Could not create resource file for path {}", path, err); err.printStackTrace(); result = false; } //if we made it this far and everything seems ok if (result) { // if it's a persistent SharedObject and it's empty don't write it to disk. APPSERVER-364 if (object instanceof SharedObject) { SharedObject soRef = (SharedObject) object; if (soRef.getAttributes().size() == 0) { // return true to trick the server into thinking everything is just fine :P return true; } } String filename = getObjectFilename(object); log.debug("File name: {}", filename); //strip path if (filename.indexOf('/') != -1) { filename = filename.substring(filename.lastIndexOf('/')); log.debug("New file name: {}", filename); } File file = new File(dir, filename); //Resource resFile = resources.getResource(filename); //log.debug("Resource (file) check #1 - file name: {} exists: {}", resPath.getFilename(), exists); IoBuffer buf = null; try { int initialSize = 8192; if (file.exists()) { // We likely also need the original file size when writing object initialSize += (int) file.length(); } buf = IoBuffer.allocate(initialSize); buf.setAutoExpand(true); Output out = new Output(buf); out.writeString(object.getClass().getName()); object.serialize(out); buf.flip(); FileOutputStream output = new FileOutputStream(file.getAbsolutePath()); ServletUtils.copy(buf.asInputStream(), output); output.close(); log.debug("Stored persistent object {} at {}", object, filename); } catch (IOException e) { log.error("Could not create / write file {}", filename, e); log.warn("Exception {}", e); result = false; } finally { if (buf != null) { buf.free(); buf = null; } file = null; dir = null; } } return result; } /** {@inheritDoc} */ @Override public boolean save(IPersistable object) { if (!super.save(object)) { return false; } storeThread.modified(object, this); return true; } /** * Remove empty dirs * @param base Base directory */ protected void checkRemoveEmptyDirectories(String base) { if (!checkForEmptyDirectories) { return; } String dir; Resource resFile = resources.getResource(base.substring(0, base.lastIndexOf('/'))); try { dir = resFile.getFile().getAbsolutePath(); } catch (IOException err) { return; } while (!dir.equals(rootDir)) { File fp = new File(dir); if (!fp.isDirectory()) { // This should never happen break; } if (fp.list().length != 0) { // Directory is not empty break; } if (!fp.delete()) { // Could not remove directory break; } // Move up one directory dir = fp.getParent(); } } /** {@inheritDoc} */ @Override public boolean remove(String name) { super.remove(name); String filename = path + '/' + name + extension; Resource resFile = resources.getResource(filename); if (!resFile.exists()) { // File already deleted return true; } try { boolean result = resFile.getFile().delete(); if (result) { checkRemoveEmptyDirectories(filename); } return result; } catch (IOException err) { return false; } } /** {@inheritDoc} */ @Override public boolean remove(IPersistable object) { return remove(getObjectId(object)); } /** {@inheritDoc} */ @Override public void notifyClose() { // Write any pending objects storeThread.notifyClose(this); super.notifyClose(); } } red5-1.0~svn4374.orig/src/org/red5/server/persistence/FilePersistenceThread.java0000644000175000017500000001201211706617130027437 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.persistence; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import org.red5.server.api.persistence.IPersistable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Thread that writes modified persistent objects to the file system * periodically. * * @author The Red5 Project (red5@osflash.org) * @author Joachim Bauch (jojo@struktur.de) */ public class FilePersistenceThread implements Runnable { /** * Logger */ private Logger log = LoggerFactory.getLogger(FilePersistenceThread.class); /** * Interval to serialize modified objects in milliseconds. * */ // TODO: make this configurable private long storeInterval = 10000; /** * Modified objects. */ private Map objects = new ConcurrentHashMap(); /** * Singleton instance. */ private static volatile FilePersistenceThread instance = null; /** * Each FilePersistenceThread has its own scheduler and the executor is * guaranteed to only run a single task at a time. */ private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); /** * Return singleton instance of the thread. * * @return singleton instance of thread. */ public static FilePersistenceThread getInstance() { return instance; } /** * Create instance of the thread. */ private FilePersistenceThread() { if (instance != null) { log.error("Instance was not null, this is not a good sign"); } instance = this; @SuppressWarnings("unused") final ScheduledFuture instanceHandle = scheduler.scheduleAtFixedRate(this, storeInterval, storeInterval, java.util.concurrent.TimeUnit.MILLISECONDS); } /** * Notify thread that an object was modified in a persistence store. * * @param object * @param store */ protected void modified(IPersistable object, FilePersistence store) { FilePersistence previous = objects.put(new UpdateEntry(object, store), store); if (previous != null && !previous.equals(store)) { log.warn("Object {} was also modified in {}, saving instantly", new Object[] { object, previous }); previous.saveObject(object); } } /** * Write any pending objects for the given store to disk. * * @param store */ protected void notifyClose(FilePersistence store) { // Store pending objects for this store for (UpdateEntry entry : objects.keySet()) { if (!store.equals(entry.store)) { // Object is from different store continue; } try { objects.remove(entry); store.saveObject(entry.object); } catch (Throwable e) { log.error("Error while saving {} in {}. {}", new Object[] { entry.object, store, e }); } } } /** * Write modified objects to the file system periodically. */ public void run() { if (!objects.isEmpty()) { for (UpdateEntry entry : objects.keySet()) { try { objects.remove(entry); entry.store.saveObject(entry.object); } catch (Throwable e) { log.error("Error while saving {} in {}. {}", new Object[] { entry.object, entry.store, e }); } } } } /** * Cleanly shutdown the tasks */ public void shutdown() { scheduler.shutdown(); } /** * Informations about one entry to object. */ private static class UpdateEntry { /** Object to store. */ IPersistable object; /** Store the object should be serialized to. */ FilePersistence store; /** * Create new update entry. * * @param object object to serialize * @param store store the object should be serialized in */ UpdateEntry(IPersistable object, FilePersistence store) { this.object = object; this.store = store; } /** * Compare with another entry. * * @param other entry to compare to * @return true if entries match, otherwise false */ @Override public boolean equals(Object other) { if (!(other instanceof UpdateEntry)) { return false; } return (object.equals(((UpdateEntry) other).object) && store.equals(((UpdateEntry) other).store)); } /** * Return hash value for entry. * * @return the hash value */ @Override public int hashCode() { return object.hashCode() + store.hashCode(); } } } red5-1.0~svn4374.orig/src/org/red5/server/session/0000755000175000017500000000000011760512572021527 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/session/Session.java0000644000175000017500000000567311706617130024024 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.session; import org.red5.server.api.session.ISession; /** * Represents the most basic type of "Session", loosely modeled after the HTTP Session used * in J2EE applications. * * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class Session implements ISession { private static final long serialVersionUID = 2893666721L; //time at which this session instance was created protected long created; //whether or not this session is in an active state protected boolean active; //unique identifier for this session protected String sessionId; //location where resources may be stored for this instance protected String destinationDirectory; //flash client identifier protected String clientId; { //set current time as created time created = System.currentTimeMillis(); //set as active active = true; } public Session() { } public Session(String sessionId) { this.sessionId = sessionId; } public long getCreated() { return created; } public String getSessionId() { return sessionId; } public void reset() { clientId = null; } public boolean isActive() { return active; } public void end() { active = false; } public String getClientId() { return clientId; } public void setClientId(String clientId) { this.clientId = clientId; } public void setDestinationDirectory(String destinationDirectory) { this.destinationDirectory = destinationDirectory; } public String getDestinationDirectory() { return destinationDirectory; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((sessionId == null) ? 0 : sessionId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final Session other = (Session) obj; if (sessionId == null) { if (other.sessionId != null) return false; } else if (!sessionId.equals(other.sessionId)) return false; return true; } } red5-1.0~svn4374.orig/src/org/red5/server/session/SessionManager.java0000644000175000017500000001221011706617130025300 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright (c) 2006-2011 by respective authors (see below). All rights reserved. * * This library is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any later * version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.red5.server.session; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; import org.red5.server.api.scheduling.IScheduledJob; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.api.session.ISession; import org.red5.server.util.PropertyConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Manages sessions. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class SessionManager { private static final Logger log = LoggerFactory .getLogger(SessionManager.class); private static ConcurrentMap sessions = new ConcurrentHashMap(); //thread-safe long provider private static AtomicLong sessionIdGenerator = new AtomicLong(); private static String destinationDirectory; private static Long maxLifetime; private static ISchedulingService schedulingService; // Create a random generator public static Random rnd = new Random(); public void init() { if (schedulingService != null) { // set to run once per hour schedulingService.addScheduledJob(3600000, new ReaperJob()); } else { log.warn("Session reaper job was not scheduled"); } } public static String getSessionId() { //random int from 1 - 100000 int part1 = rnd.nextInt(99999) + 1; //thread-safe "long" part long part2 = sessionIdGenerator.incrementAndGet(); //current time in millis long part3 = System.currentTimeMillis(); //generate uuid-type id String sessionId = createHash(part1 + "-" + part2 + "-" + part3); log.debug("Session id created: {}", sessionId); return sessionId; } public static ISession createSession() { // create a new session return createSession(getSessionId()); } public static ISession createSession(String sessionId) { // create a new session Session session = new Session(sessionId); session.setDestinationDirectory(destinationDirectory); // add to list sessions.put(sessionId, session); return session; } public static ISession getSession(String sessionId) { return sessions.get(sessionId); } public static ISession removeSession(String sessionId) { return sessions.remove(sessionId); } public String getDestinationDirectory() { return destinationDirectory; } public void setDestinationDirectory(String destinationDir) { log.debug("Setting session destination directory {}", destinationDir); SessionManager.destinationDirectory = destinationDir; } public void setMaxLifetime(String maxLifetime) { if (StringUtils.isNumeric(maxLifetime)) { SessionManager.maxLifetime = Long.valueOf(maxLifetime); } else { SessionManager.maxLifetime = PropertyConverter.convertStringToTimeMillis(maxLifetime); } log.debug("Max lifetime set to {} ms", SessionManager.maxLifetime); } public void setSchedulingService(ISchedulingService schedulingService) { SessionManager.schedulingService = schedulingService; } public static String createHash(String str) { return DigestUtils.md5Hex(str.getBytes()); } /** * Quartz job to kill off old sessions */ private final static class ReaperJob implements IScheduledJob { public ReaperJob() { log.debug("Creating job to remove stale sessions"); } public void execute(ISchedulingService service) { log.debug("Reaper running..."); if (sessions != null) { if (!sessions.isEmpty()) { long now = System.currentTimeMillis(); for (Map.Entry entry : sessions.entrySet()) { ISession session = entry.getValue(); long creationTime = session.getCreated(); // check if session life exceeds max lifetime if (now - creationTime > SessionManager.maxLifetime) { String key = session.getSessionId(); log.info("Reaper killing stale session: {}", key); sessions.remove(key); session.reset(); session = null; } } } } } } } red5-1.0~svn4374.orig/src/org/red5/server/AttributeStore.java0000644000175000017500000002032411757012455023671 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.management.openmbean.CompositeData; import org.red5.server.api.IAttributeStore; import org.red5.server.api.ICastingAttributeStore; public class AttributeStore implements ICastingAttributeStore { /** * Map for attributes */ protected ConcurrentMap attributes = new ConcurrentHashMap(1); /** * Filter null keys and values from given map. * * @param values the map to filter * @return filtered map */ protected Map filterNull(Map values) { Map result = new HashMap(); for (Map.Entry entry : values.entrySet()) { String key = entry.getKey(); if (key == null) { continue; } Object value = entry.getValue(); if (value == null) { continue; } result.put(key, value); } return result; } /** * Creates empty attribute store. Object is not associated with a persistence storage. */ public AttributeStore() { } /** * Creates attribute store with initial values. Object is not associated with a persistence storage. * @param values map */ public AttributeStore(Map values) { setAttributes(values); } /** * Creates attribute store with initial values. Object is not associated with a persistence storage. * @param values map */ public AttributeStore(IAttributeStore values) { setAttributes(values); } /** * Get the attribute names. The resulting set will be read-only. * * @return set containing all attribute names */ public Set getAttributeNames() { return Collections.unmodifiableSet(attributes.keySet()); } /** * Get the attributes. The resulting map will be read-only. * * @return map containing all attributes */ public Map getAttributes() { return Collections.unmodifiableMap(attributes); } /** * Return the value for a given attribute. * * @param name the name of the attribute to get * @return the attribute value or null if the attribute doesn't exist */ public Object getAttribute(String name) { if (name == null) { return null; } return attributes.get(name); } /** * Return the value for a given attribute and set it if it doesn't exist. * * @param name the name of the attribute to get * @param defaultValue the value of the attribute to set if the attribute doesn't * exist * @return the attribute value */ public Object getAttribute(String name, Object defaultValue) { if (name == null) { return null; } if (defaultValue == null) { throw new NullPointerException("the default value may not be null"); } Object result = attributes.putIfAbsent(name, defaultValue); // if no previous value result will be null if (result == null) { // use the default value result = defaultValue; } return result; } /** * Check the object has an attribute. * * @param name the name of the attribute to check * @return true if the attribute exists otherwise false */ public boolean hasAttribute(String name) { if (name == null) { return false; } return attributes.containsKey(name); } /** * Set an attribute on this object. * * @param name the name of the attribute to change * @param value the new value of the attribute * @return true if the attribute value was added or changed, otherwise false */ public boolean setAttribute(String name, Object value) { if (name != null) { if (value != null) { // update with new value Object previous = attributes.put(name, value); // previous will be null if the attribute didn't exist return (previous == null || !value.equals(previous)); } } return false; } /** * Set multiple attributes on this object. * * @param values the attributes to set */ public void setAttributes(Map values) { attributes.putAll(filterNull(values)); } /** * Set multiple attributes on this object. * * @param values the attributes to set */ public void setAttributes(IAttributeStore values) { setAttributes(values.getAttributes()); } /** * Remove an attribute. * * @param name the name of the attribute to remove * @return true if the attribute was found and removed otherwise false */ public boolean removeAttribute(String name) { if (name != null) { return (attributes.remove(name) != null); } return false; } /** * Remove all attributes. */ public void removeAttributes() { attributes.clear(); } /** * Get Boolean attribute by name * * @param name Attribute name * @return Attribute */ public Boolean getBoolAttribute(String name) { return (Boolean) getAttribute(name); } /** * Get Byte attribute by name * * @param name Attribute name * @return Attribute */ public Byte getByteAttribute(String name) { return (Byte) getAttribute(name); } /** * Get Double attribute by name * * @param name Attribute name * @return Attribute */ public Double getDoubleAttribute(String name) { return (Double) getAttribute(name); } /** * Get Integer attribute by name * * @param name Attribute name * @return Attribute */ public Integer getIntAttribute(String name) { return (Integer) getAttribute(name); } /** * Get List attribute by name * * @param name Attribute name * @return Attribute */ public List getListAttribute(String name) { return (List) getAttribute(name); } /** * Get boolean attribute by name * * @param name Attribute name * @return Attribute */ public Long getLongAttribute(String name) { return (Long) getAttribute(name); } /** * Get Long attribute by name * * @param name Attribute name * @return Attribute */ public Map getMapAttribute(String name) { return (Map) getAttribute(name); } /** * Get Set attribute by name * * @param name Attribute name * @return Attribute */ public Set getSetAttribute(String name) { return (Set) getAttribute(name); } /** * Get Short attribute by name * * @param name Attribute name * @return Attribute */ public Short getShortAttribute(String name) { return (Short) getAttribute(name); } /** * Get String attribute by name * * @param name Attribute name * @return Attribute */ public String getStringAttribute(String name) { return (String) getAttribute(name); } /** * Allows for reconstruction via CompositeData. * * @param cd composite data * @return AttributeStore class instance */ @SuppressWarnings("unchecked") public static AttributeStore from(CompositeData cd) { AttributeStore instance = null; if (cd.containsKey("attributes")) { Object cn = cd.get("attributes"); if (cn != null) { if (cn instanceof IAttributeStore) { instance = new AttributeStore((IAttributeStore) cn); } else if (cn instanceof Map) { instance = new AttributeStore((Map) cn); } } else { instance = new AttributeStore(); } } else { instance = new AttributeStore(); } return instance; } } red5-1.0~svn4374.orig/src/org/red5/server/BaseConnection.java0000644000175000017500000003014511747114732023605 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.beans.ConstructorProperties; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.event.IEvent; import org.red5.server.api.scope.IBasicScope; import org.red5.server.api.scope.IScope; import org.red5.server.scope.Scope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base abstract class for connections. Adds connection specific functionality like work with clients * to AttributeStore. */ public abstract class BaseConnection extends AttributeStore implements IConnection { private static final Logger log = LoggerFactory.getLogger(BaseConnection.class); /** * Connection type */ protected final String type; /** * Connection host */ protected volatile String host; /** * Connection remote address */ protected volatile String remoteAddress; /** * Connection remote addresses */ protected volatile List remoteAddresses; /** * Remote port */ protected volatile int remotePort; /** * Path of scope client connected to */ protected volatile String path; /** * Connection session identifier */ protected volatile String sessionId; /** * Number of read messages */ protected AtomicLong readMessages = new AtomicLong(0); /** * Number of written messages */ protected AtomicLong writtenMessages = new AtomicLong(0); /** * Number of dropped messages */ protected AtomicLong droppedMessages = new AtomicLong(0); /** * Connection params passed from client with NetConnection.connect call * * @see NetConnection in Flash Media Server docs (external) */ @SuppressWarnings("all") protected volatile Map params = null; /** * Client bound to connection */ protected volatile IClient client; /** * Scope that connection belongs to */ protected volatile Scope scope; /** * Set of basic scopes. */ protected Set basicScopes = new CopyOnWriteArraySet(); /** * Is the connection closed? */ protected volatile boolean closed; /** * Used to protect mulit-threaded operations on write */ private final Semaphore writeLock = new Semaphore(1, true); /** * Used for generation of client ids that may be shared across the server */ private final static AtomicInteger clientIdGenerator = new AtomicInteger(0); /** * Creates a new persistent base connection */ @ConstructorProperties(value = { "persistent" }) public BaseConnection() { log.debug("New BaseConnection"); this.type = PERSISTENT; } /** * Creates a new base connection with the given type. * * @param type Connection type */ @ConstructorProperties({ "type" }) public BaseConnection(String type) { log.debug("New BaseConnection - type: {}", type); this.type = type; } /** * Creates a new base connection with the given parameters. * * @param type Connection type * @param host Host * @param remoteAddress Remote address * @param remotePort Remote port * @param path Scope path on server * @param sessionId Session id * @param params Params passed from client */ @ConstructorProperties({ "type", "host", "remoteAddress", "remotePort", "path", "sessionId" }) public BaseConnection(String type, String host, String remoteAddress, int remotePort, String path, String sessionId, Map params) { log.debug("New BaseConnection - type: {} host: {} remoteAddress: {} remotePort: {} path: {} sessionId: {}", new Object[] { type, host, remoteAddress, remotePort, path, sessionId }); log.debug("Params: {}", params); this.type = type; this.host = host; this.remoteAddress = remoteAddress; this.remoteAddresses = new ArrayList(1); this.remoteAddresses.add(remoteAddress); this.remoteAddresses = Collections.unmodifiableList(this.remoteAddresses); this.remotePort = remotePort; this.path = path; this.sessionId = sessionId; this.params = params; } /** * Returns the next available client id. * * @return new client id */ public static int getNextClientId() { return clientIdGenerator.incrementAndGet(); } /** * @return lock for changing state operations */ public Semaphore getLock() { return writeLock; } /** * Initializes client * @param client Client bound to connection */ public void initialize(IClient client) { if (this.client != null && this.client instanceof Client) { // Unregister old client ((Client) this.client).unregister(this, false); } this.client = client; if (this.client instanceof Client) { // Register new client ((Client) this.client).register(this); } } /** * * @return type */ public String getType() { return type; } /** * * @return host */ public String getHost() { return host; } /** * * @return remote address */ public String getRemoteAddress() { return remoteAddress; } /** * @return remote address */ public List getRemoteAddresses() { return remoteAddresses; } /** * * @return remote port */ public int getRemotePort() { return remotePort; } /** * * @return path */ public String getPath() { return path; } /** * * @return session id */ public String getSessionId() { return sessionId; } /** * Return connection parameters * @return connection parameters */ public Map getConnectParams() { return Collections.unmodifiableMap(params); } /** * * @return client */ public IClient getClient() { return client; } /** * Check whether connection is alive * @return true if connection is bound to scope, false otherwise */ public boolean isConnected() { return scope != null; } /** * Connect to another scope on server * @param newScope New scope * @return true on success, false otherwise */ public boolean connect(IScope newScope) { return connect(newScope, new Object[] {}); } /** * Connect to another scope on server with given parameters * @param newScope New scope * @param params Parameters to connect with * @return true on success, false otherwise */ public boolean connect(IScope newScope, Object[] params) { if (log.isDebugEnabled()) { log.debug("Connect Params: {}", params); for (Object e : params) { log.debug("Param: {}", e); } } final Scope oldScope = scope; scope = (Scope) newScope; // disconnect from old scope(s), then reconnect to new scopes. // this is necessary because there may be an intersection between the hierarchies. if (oldScope != null) { oldScope.disconnect(this); } return scope.connect(this, params); } /** * * @return scope */ public IScope getScope() { return scope; } /** * Closes connection */ public void close() { if (closed || scope == null) { log.debug("Close, not connected nothing to do."); return; } closed = true; log.debug("Close, disconnect from scope, and children"); try { // Unregister all child scopes first for (IBasicScope basicScope : basicScopes) { unregisterBasicScope(basicScope); } } catch (Exception err) { log.error("Error while unregistering basic scopes.", err); } // Disconnect try { scope.disconnect(this); } catch (Exception err) { log.error("Error while disconnecting from scope: {}. {}", scope, err); } // Unregister client if (client != null && client instanceof Client) { ((Client) client).unregister(this); /* Following code should be unnecessary and was causing client to set its registry to null (via tmp.disconnect()) * resulting NPE + memory leaks in various cases Client tmp = (Client) client; tmp.unregister(this); tmp.removeAttributes(); tmp.disconnect(); client = null;*/ } scope = null; } /** * Notified on event * @param event Event */ public void notifyEvent(IEvent event) { log.debug("Event notify was not handled: {}", event); } /** * Dispatches event * @param event Event */ public void dispatchEvent(IEvent event) { log.debug("Event notify was not dispatched: {}", event); } /** * Handles event * @param event Event * @return true if associated scope was able to handle event, false otherwise */ public boolean handleEvent(IEvent event) { return getScope().handleEvent(event); } /** * * @return basic scopes */ public Iterator getBasicScopes() { return basicScopes.iterator(); } /** * Registers basic scope * @param basicScope Basic scope to register */ public void registerBasicScope(IBasicScope basicScope) { basicScopes.add(basicScope); basicScope.addEventListener(this); } /** * Unregister basic scope * * @param basicScope Unregister basic scope */ public void unregisterBasicScope(IBasicScope basicScope) { basicScopes.remove(basicScope); basicScope.removeEventListener(this); } /** * * @return bytes read */ public abstract long getReadBytes(); /** * * @return bytes written */ public abstract long getWrittenBytes(); /** * * @return messages read */ public long getReadMessages() { return readMessages.get(); } /** * * @return messages written */ public long getWrittenMessages() { return writtenMessages.get(); } /** * * @return dropped messages */ public long getDroppedMessages() { return droppedMessages.get(); } /** * * @return pending messages */ public long getPendingMessages() { return 0; } /** * * @param streamId the id you want to know about * @return pending messages for this streamId */ public long getPendingVideoMessages(int streamId) { return 0; } /** {@inheritDoc} */ public long getClientBytesRead() { return 0; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; if (host != null) { result = prime * result + host.hashCode(); } if (remoteAddress != null) { result = prime * result + remoteAddress.hashCode(); } return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } BaseConnection other = (BaseConnection) obj; if (host != null && !host.equals(other.getHost())) { return false; } if (remoteAddress != null && !remoteAddress.equals(other.getRemoteAddress())) { return false; } return true; } } red5-1.0~svn4374.orig/src/org/red5/server/messaging/0000755000175000017500000000000011760512571022020 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/messaging/IMessageComponent.java0000644000175000017500000000221211747114732026242 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; /** * Message component handles out-of-band control messages */ public interface IMessageComponent { /** * * @param source Message component source * @param pipe Connection pipe * @param oobCtrlMsg Out-of-band control message */ void onOOBControlMessage(IMessageComponent source, IPipe pipe, OOBControlMessage oobCtrlMsg); } red5-1.0~svn4374.orig/src/org/red5/server/messaging/IPullableProvider.java0000644000175000017500000000224511706617130026247 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; import java.io.IOException; /** * A provider that supports passive pulling of messages. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IPullableProvider extends IProvider { public static final String KEY = IPullableProvider.class.getName(); IMessage pullMessage(IPipe pipe) throws IOException; IMessage pullMessage(IPipe pipe, long wait) throws IOException; } red5-1.0~svn4374.orig/src/org/red5/server/messaging/AbstractMessage.java0000644000175000017500000000604211706617130025732 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; import java.util.Map; /** * Abstract base for all messages * * @see org.red5.server.messaging.IMessage */ public class AbstractMessage implements IMessage { protected String messageID; protected String correlationID; protected String messageType; protected Map extraHeaders = null; /** {@inheritDoc} */ public String getMessageID() { return messageID; } /** {@inheritDoc} */ public void setMessageID(String id) { this.messageID = id; } /** {@inheritDoc} */ public String getCorrelationID() { return correlationID; } /** {@inheritDoc} */ public void setCorrelationID(String id) { this.correlationID = id; } /** {@inheritDoc} */ public String getMessageType() { return messageType; } /** {@inheritDoc} */ public void setMessageType(String type) { this.messageType = type; } /** {@inheritDoc} */ public boolean getBooleanProperty(String name) { return false; } /** {@inheritDoc} */ public void setBooleanProperty(String name, boolean value) { } /** {@inheritDoc} */ public byte getByteProperty(String name) { return 0; } /** {@inheritDoc} */ public void setByteProperty(String name, byte value) { } /** {@inheritDoc} */ public double getDoubleProperty(String name) { return 0; } /** {@inheritDoc} */ public void setDoubleProperty(String name, double value) { } /** {@inheritDoc} */ public float getFloatProperty(String name) { return 0; } /** {@inheritDoc} */ public void setFloatProperty(String name, float value) { } /** {@inheritDoc} */ public int getIntProperty(String name) { return 0; } /** {@inheritDoc} */ public void setIntProperty(String name, int value) { } /** {@inheritDoc} */ public long getLongProperty(String name) { return 0; } /** {@inheritDoc} */ public void setLongProperty(String name, long value) { } /** {@inheritDoc} */ public short getShortProperty(String name) { return 0; } /** {@inheritDoc} */ public void setShortProperty(String name, short value) { } /** {@inheritDoc} */ public String getStringProperty(String name) { return null; } /** {@inheritDoc} */ public void setStringProperty(String name, String value) { } /** {@inheritDoc} */ public Object getObjectProperty(String name) { return null; } /** {@inheritDoc} */ public void setObjectProperty(String name, Object value) { } } red5-1.0~svn4374.orig/src/org/red5/server/messaging/AbstractPipe.java0000644000175000017500000002204511747114732025251 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Abstract pipe that books providers/consumers and listeners. * Aim to ease the implementation of concrete pipes. For more * information on what pipe is, see IPipe interface documentation. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) * * @see org.red5.server.messaging.IPipe */ public abstract class AbstractPipe implements IPipe { /** * Logger */ private static final Logger log = LoggerFactory.getLogger(AbstractPipe.class); /** * Pipe consumers list */ protected volatile CopyOnWriteArrayList consumers = new CopyOnWriteArrayList(); /** * Pipe providers list */ protected volatile CopyOnWriteArrayList providers = new CopyOnWriteArrayList(); /** * Event listeners */ protected volatile CopyOnWriteArrayList listeners = new CopyOnWriteArrayList(); /** * Executor service used to run pipe tasks. */ private ExecutorService taskExecutor; /** * Connect consumer to this pipe. Doesn't allow to connect one consumer twice. * Does register event listeners if instance of IPipeConnectionListener is given. * * @param consumer Consumer * @param paramMap Parameters passed with connection, used in concrete pipe implementations * @return true if consumer was added, false otherwise */ public boolean subscribe(IConsumer consumer, Map paramMap) { // if consumer is listener object register it as listener if (consumer instanceof IPipeConnectionListener) { listeners.addIfAbsent((IPipeConnectionListener) consumer); } // pipe is possibly used by dozens of threads at once (like many subscribers for one server stream) return consumers.addIfAbsent(consumer); } /** * Connect provider to this pipe. Doesn't allow to connect one provider twice. * Does register event listeners if instance of IPipeConnectionListener is given. * * @param provider Provider * @param paramMap Parameters passed with connection, used in concrete pipe implementations * @return true if provider was added, false otherwise */ public boolean subscribe(IProvider provider, Map paramMap) { // register event listener if given if (provider instanceof IPipeConnectionListener) { listeners.add((IPipeConnectionListener) provider); } return providers.addIfAbsent(provider); } /** * Disconnects provider from this pipe. Fires pipe connection event. * @param provider Provider that should be removed * @return true on success, false otherwise */ public boolean unsubscribe(IProvider provider) { if (providers.remove(provider)) { fireProviderConnectionEvent(provider, PipeConnectionEvent.PROVIDER_DISCONNECT, null); listeners.remove(provider); return true; } else { return false; } } /** * Disconnects consumer from this pipe. Fires pipe connection event. * @param consumer Consumer that should be removed * @return true on success, false otherwise */ public boolean unsubscribe(IConsumer consumer) { if (consumers.remove(consumer)) { fireConsumerConnectionEvent(consumer, PipeConnectionEvent.CONSUMER_DISCONNECT, null); listeners.remove(consumer); return true; } else { return false; } } /** * Registers pipe connect events listener * @param listener Listener */ public void addPipeConnectionListener(IPipeConnectionListener listener) { listeners.add(listener); } /** * Removes pipe connection listener * @param listener Listener */ public void removePipeConnectionListener(IPipeConnectionListener listener) { listeners.remove(listener); } /** * Send out-of-band ("special") control message to all consumers * * @param provider Provider, may be used in concrete implementations * @param oobCtrlMsg Out-of-band control message */ public void sendOOBControlMessage(IProvider provider, OOBControlMessage oobCtrlMsg) { for (IConsumer consumer : consumers) { try { consumer.onOOBControlMessage(provider, this, oobCtrlMsg); } catch (Throwable t) { log.error("exception when passing OOBCM from provider to consumers", t); } } } /** * Send out-of-band ("special") control message to all providers * * @param consumer Consumer, may be used in concrete implementations * @param oobCtrlMsg Out-of-band control message */ public void sendOOBControlMessage(IConsumer consumer, OOBControlMessage oobCtrlMsg) { for (IProvider provider : providers) { try { provider.onOOBControlMessage(consumer, this, oobCtrlMsg); } catch (Throwable t) { log.error("exception when passing OOBCM from consumer to providers", t); } } } /** * Getter for pipe connection events listeners * * @return Listeners */ public List getListeners() { return Collections.unmodifiableList(listeners); } /** * Setter for pipe connection events listeners * * @param newListeners Listeners */ public void setListeners(List newListeners) { listeners.clear(); listeners.addAll(newListeners); } /** * Getter for providers * * @return Providers list */ public List getProviders() { return Collections.unmodifiableList(providers); } /** * Getter for consumers * * @return consumers list */ public List getConsumers() { return Collections.unmodifiableList(consumers); } /** * Broadcast consumer connection event * * @param consumer Consumer that has connected * @param type Event type * @param paramMap Parameters passed with connection */ protected void fireConsumerConnectionEvent(IConsumer consumer, int type, Map paramMap) { // Create event object PipeConnectionEvent event = new PipeConnectionEvent(this); // Fill it up event.setConsumer(consumer); event.setType(type); event.setParamMap(paramMap); // Fire it firePipeConnectionEvent(event); } /** * Broadcast provider connection event * @param provider Provider that has connected * @param type Event type * @param paramMap Parameters passed with connection */ protected void fireProviderConnectionEvent(IProvider provider, int type, Map paramMap) { PipeConnectionEvent event = new PipeConnectionEvent(this); event.setProvider(provider); event.setType(type); event.setParamMap(paramMap); firePipeConnectionEvent(event); } /** * Fire any pipe connection event and run all it's tasks * @param event Pipe connection event */ protected void firePipeConnectionEvent(PipeConnectionEvent event) { for (IPipeConnectionListener element : listeners) { try { element.onPipeConnectionEvent(event); } catch (Throwable t) { log.error("Exception when handling pipe connection event", t); } } if (taskExecutor == null) { taskExecutor = Executors.newSingleThreadExecutor(); } // Run all of event's tasks for (Runnable task : event.getTaskList()) { try { taskExecutor.execute(task); } catch (Throwable t) { log.warn("Exception executing pipe task {}", t); } } // Clear event's tasks list event.getTaskList().clear(); //disable new tasks from being submitted taskExecutor.shutdown(); try { //wait a while for existing tasks to terminate if (!taskExecutor.awaitTermination(250, TimeUnit.MILLISECONDS)) { taskExecutor.shutdownNow(); // cancel currently executing tasks } } catch (InterruptedException ie) { // preserve interrupt status Thread.currentThread().interrupt(); } } /** * Close the pipe */ public void close() { //clean up collections if (consumers != null) { consumers.clear(); consumers = null; } if (providers != null) { providers.clear(); providers = null; } if (listeners != null) { listeners.clear(); listeners = null; } } } red5-1.0~svn4374.orig/src/org/red5/server/messaging/IFilter.java0000644000175000017500000000161611706617130024222 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; /** * Filter marker interface groups consumer and provider interfaces */ public interface IFilter extends IConsumer, IProvider { } red5-1.0~svn4374.orig/src/org/red5/server/messaging/IPassive.java0000644000175000017500000000205111706617130024401 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; /** * Signature to mark a provider/consumer never actively providers/consumers * messages. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IPassive { public static final String KEY = IPassive.class.getName(); } red5-1.0~svn4374.orig/src/org/red5/server/messaging/IProvider.java0000644000175000017500000000166511706617130024573 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; /** * Signature for message provider. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IProvider extends IMessageComponent { } red5-1.0~svn4374.orig/src/org/red5/server/messaging/IPushableConsumer.java0000644000175000017500000000252011706617130026247 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; import java.io.IOException; /** * A consumer that supports event-driven message handling and message pushing through pipes. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IPushableConsumer extends IConsumer { public static final String KEY = IPushableConsumer.class.getName(); /** * Pushes message through pipe * * @param pipe Pipe * @param message Message * @throws IOException if message could not be written */ void pushMessage(IPipe pipe, IMessage message) throws IOException; } red5-1.0~svn4374.orig/src/org/red5/server/messaging/InMemoryPushPushPipe.java0000644000175000017500000000525111747114732026745 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; import java.io.IOException; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A simple in-memory version of push-push pipe. * It is triggered by an active provider to push messages * through it to an event-driven consumer. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public class InMemoryPushPushPipe extends AbstractPipe { private static final Logger log = LoggerFactory.getLogger(InMemoryPushPushPipe.class); /** {@inheritDoc} */ @Override public boolean subscribe(IConsumer consumer, Map paramMap) { if (consumer instanceof IPushableConsumer) { boolean success = super.subscribe(consumer, paramMap); if (success) { fireConsumerConnectionEvent(consumer, PipeConnectionEvent.CONSUMER_CONNECT_PUSH, paramMap); } return success; } else { throw new IllegalArgumentException("Non-pushable consumer not supported by PushPushPipe"); } } /** {@inheritDoc} */ @Override public boolean subscribe(IProvider provider, Map paramMap) { boolean success = super.subscribe(provider, paramMap); if (success) { fireProviderConnectionEvent(provider, PipeConnectionEvent.PROVIDER_CONNECT_PUSH, paramMap); } return success; } /** {@inheritDoc} */ public IMessage pullMessage() { return null; } /** {@inheritDoc} */ public IMessage pullMessage(long wait) { return null; } /** * Pushes a message out to all the PushableConsumers. * * @param message the message to be pushed to consumers. */ public void pushMessage(IMessage message) throws IOException { for (IConsumer consumer : consumers) { try { IPushableConsumer pcon = (IPushableConsumer) consumer; pcon.pushMessage(this, message); } catch (Throwable t) { if (t instanceof IOException) { // Pass this along throw (IOException) t; } log.error("Exception when pushing message to consumer", t); } } } } red5-1.0~svn4374.orig/src/org/red5/server/messaging/IMessageInput.java0000644000175000017500000000500411706617130025374 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; import java.io.IOException; import java.util.List; import java.util.Map; /** * Input Endpoint for a consumer to connect. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IMessageInput { /** * Pull message from this input endpoint. Return * w/o waiting. * @return The pulled message or null if message is * not available. * @throws IOException on error */ IMessage pullMessage() throws IOException; /** * Pull message from this input endpoint. Wait * wait milliseconds if message is not available. * @param wait milliseconds to wait when message is not * available. * @return The pulled message or null if message is * not available. */ IMessage pullMessage(long wait); /** * Connect to a consumer. * * @param consumer Consumer * @param paramMap Parameters map * @return true when successfully subscribed, * false otherwise. */ boolean subscribe(IConsumer consumer, Map paramMap); /** * Disconnect from a consumer. * * @param consumer Consumer to disconnect * @return true when successfully unsubscribed, * false otherwise. */ boolean unsubscribe(IConsumer consumer); /** * Getter for consumers list. * * @return Consumers. */ List getConsumers(); /** * Send OOB Control Message to all providers on the other side of pipe. * * @param consumer * The consumer that sends the message * @param oobCtrlMsg * Out-of-band control message */ void sendOOBControlMessage(IConsumer consumer, OOBControlMessage oobCtrlMsg); } red5-1.0~svn4374.orig/src/org/red5/server/messaging/PipeConnectionEvent.java0000644000175000017500000000715111747114732026610 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; import java.util.ArrayList; import java.util.EventObject; import java.util.List; import java.util.Map; /** * Event object corresponds to the connect/disconnect events * among providers/consumers and pipes. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public class PipeConnectionEvent extends EventObject { private static final long serialVersionUID = 9078843765378168072L; private List taskList = new ArrayList(3); /** * A provider connects as pull mode. */ public static final int PROVIDER_CONNECT_PULL = 0; /** * A provider connects as push mode. */ public static final int PROVIDER_CONNECT_PUSH = 1; /** * A provider disconnects. */ public static final int PROVIDER_DISCONNECT = 2; /** * A consumer connects as pull mode. */ public static final int CONSUMER_CONNECT_PULL = 3; /** * A consumer connects as push mode. */ public static final int CONSUMER_CONNECT_PUSH = 4; /** * A consumer disconnects. */ public static final int CONSUMER_DISCONNECT = 5; /** * Provider */ private transient IProvider provider; /** * Consumer */ private transient IConsumer consumer; /** * Event type */ private int type; /** * Parameters map */ private Map paramMap; /** * Construct an object with the specific pipe as the * source * @param source A pipe that triggers this event. */ public PipeConnectionEvent(Object source) { super(source); } /** * Return pipe connection provider * @return Provider */ public IProvider getProvider() { return provider; } /** * Setter for pipe connection provider * @param provider Provider */ public void setProvider(IProvider provider) { this.provider = provider; } /** * Return pipe connection consumer * @return Consumer */ public IConsumer getConsumer() { return consumer; } /** * Setter for pipe connection consumer * @param consumer Consumer */ public void setConsumer(IConsumer consumer) { this.consumer = consumer; } /** * Return event type * @return Event type */ public int getType() { return type; } /** * Setter for event type * @param type Event type */ public void setType(int type) { this.type = type; } /** * Return event parameters as Map * @return Event parameters as Map */ public Map getParamMap() { return paramMap; } /** * Setter for event parameters map * @param paramMap Event parameters as Map */ public void setParamMap(Map paramMap) { this.paramMap = paramMap; } /** * Add task to list * @param task Task to add */ public void addTask(Runnable task) { taskList.add(task); } /** * Return list of tasks * @return List of tasks */ List getTaskList() { return taskList; } } red5-1.0~svn4374.orig/src/org/red5/server/messaging/IConsumer.java0000644000175000017500000000167111706617130024571 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; /** * Signature for the message consumer. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IConsumer extends IMessageComponent { } red5-1.0~svn4374.orig/src/org/red5/server/messaging/IPipeConnectionListener.java0000644000175000017500000000224111706617130027413 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; /** * A listener that wants to listen to events when * provider/consumer connects to or disconnects from * a specific pipe. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IPipeConnectionListener { /** * Pipe connection event handler * @param event Pipe connection event */ void onPipeConnectionEvent(PipeConnectionEvent event); } red5-1.0~svn4374.orig/src/org/red5/server/messaging/OOBControlMessage.java0000644000175000017500000000651711706617130026156 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; import java.io.Serializable; import java.util.Map; /** * Out-of-band control message used by inter-components communication * which are connected with pipes. * Out-of-band data is a separate data stream used for specific purposes (in TCP * it's referenced as "urgent data"), like lifecycle control. * * 'Target' is used to represent the receiver who may be * interested for receiving. It's a string of any form. * XXX shall we design a standard form for Target, like "class.instance"? * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public class OOBControlMessage implements Serializable { private static final long serialVersionUID = -6037348177653934300L; /** * Target */ private String target; /** * Service name */ private String serviceName; /** * Service params name */ private Map serviceParamMap; /** * Result */ private Object result; /** * Getter for property 'serviceName'. * * @return Value for property 'serviceName'. */ public String getServiceName() { return serviceName; } /** * Setter for property 'serviceName'. * * @param serviceName Value to set for property 'serviceName'. */ public void setServiceName(String serviceName) { this.serviceName = serviceName; } /** * Getter for property 'serviceParamMap'. * * @return Value for property 'serviceParamMap'. */ public Map getServiceParamMap() { return serviceParamMap; } /** * Setter for property 'serviceParamMap'. * * @param serviceParamMap Value to set for property 'serviceParamMap'. */ public void setServiceParamMap(Map serviceParamMap) { this.serviceParamMap = serviceParamMap; } /** * Getter for property 'target'. * * @return Value for property 'target'. */ public String getTarget() { return target; } /** * Setter for property 'target'. * * @param target Value to set for property 'target'. */ public void setTarget(String target) { this.target = target; } /** * Getter for property 'result'. * * @return Value for property 'result'. */ public Object getResult() { return result; } /** * Setter for property 'result'. * * @param result Value to set for property 'result'. */ public void setResult(Object result) { this.result = result; } } red5-1.0~svn4374.orig/src/org/red5/server/messaging/IMessageOutput.java0000644000175000017500000000455311706617130025605 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; import java.io.IOException; import java.util.List; import java.util.Map; /** * Output Endpoint for a provider to connect. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IMessageOutput { /** * Push a message to this output endpoint. May block * the pusher when output can't handle the message at * the time. * @param message Message to be pushed. * @throws IOException If message could not be written. */ void pushMessage(IMessage message) throws IOException; /** * Connect to a provider. Note that params passed has nothing to deal with * NetConnection.connect in client-side Flex/Flash RIA. * * @param provider Provider * @param paramMap Parameters passed with connection * @return true when successfully subscribed, * false otherwise. */ boolean subscribe(IProvider provider, Map paramMap); /** * Disconnect from a provider. * * @param provider Provider * @return true when successfully unsubscribed, * false otherwise. */ boolean unsubscribe(IProvider provider); /** * Getter for providers * * @return Providers */ List getProviders(); /** * Send OOB Control Message to all consumers on the other side of pipe. * * @param provider * The provider that sends the message * @param oobCtrlMsg * Out-of-band control message */ void sendOOBControlMessage(IProvider provider, OOBControlMessage oobCtrlMsg); } red5-1.0~svn4374.orig/src/org/red5/server/messaging/InMemoryPullPullPipe.java0000644000175000017500000000656311706617130026741 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; import java.io.IOException; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A simple in-memory version of pull-pull pipe. * It is triggered by an active consumer that pulls messages * through it from a pullable provider. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public class InMemoryPullPullPipe extends AbstractPipe { private static final Logger log = LoggerFactory.getLogger(InMemoryPullPullPipe.class); /** {@inheritDoc} */ @Override public boolean subscribe(IConsumer consumer, Map paramMap) { boolean success = super.subscribe(consumer, paramMap); if (success) { fireConsumerConnectionEvent(consumer, PipeConnectionEvent.CONSUMER_CONNECT_PULL, paramMap); } return success; } /** {@inheritDoc} */ @Override public boolean subscribe(IProvider provider, Map paramMap) { if (provider instanceof IPullableProvider) { boolean success = super.subscribe(provider, paramMap); if (success) { fireProviderConnectionEvent(provider, PipeConnectionEvent.PROVIDER_CONNECT_PULL, paramMap); } return success; } else { throw new IllegalArgumentException("Non-pullable provider not supported by PullPullPipe"); } } /** {@inheritDoc} */ public IMessage pullMessage() throws IOException { IMessage message = null; for (IProvider provider : providers) { if (provider instanceof IPullableProvider) { // choose the first available provider try { message = ((IPullableProvider) provider).pullMessage(this); if (message != null) { break; } } catch (Throwable t) { if (t instanceof IOException) { // Pass this along throw (IOException) t; } log.error("exception when pulling message from provider", t); } } } return message; } /** {@inheritDoc} */ public IMessage pullMessage(long wait) { IMessage message = null; // divided evenly int size = providers.size(); long averageWait = size > 0 ? wait / size : 0; // choose the first available provider for (IProvider provider : providers) { if (provider instanceof IPullableProvider) { try { message = ((IPullableProvider) provider).pullMessage(this, averageWait); if (message != null) { break; } } catch (Throwable t) { log.error("exception when pulling message from provider", t); } } } return message; } /** {@inheritDoc} */ public void pushMessage(IMessage message) { // push mode ignored } } red5-1.0~svn4374.orig/src/org/red5/server/messaging/PipeUtils.java0000644000175000017500000000312211706617130024574 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; /** * Helper class for pipe structure. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public class PipeUtils { /** * Connect a provider/consumer with a pipe. * * @param provider Provider * @param pipe Pipe that used to estabilish connection * @param consumer Consumer */ public static void connect(IProvider provider, IPipe pipe, IConsumer consumer) { pipe.subscribe(provider, null); pipe.subscribe(consumer, null); } /** * Disconnect a provider/consumer from a pipe. * * @param provider Provider * @param pipe Pipe to disconnect from * @param consumer Consumer */ public static void disconnect(IProvider provider, IPipe pipe, IConsumer consumer) { pipe.unsubscribe(provider); pipe.unsubscribe(consumer); } } red5-1.0~svn4374.orig/src/org/red5/server/messaging/IMessage.java0000644000175000017500000001231411706617130024356 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; /** * Common interface for all messages. *

Structure of messages is designed according to * JMS Message interface. Message is composed of header and body. * Header contains commonly used pre-defined headers * and extensible headers.

* *

Each message has correlation ID that is never used so far and is subject to be removed in future.

* *

Message has type and number of properties.

* * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IMessage { /** * Return message id * @return Message id */ String getMessageID(); /** * Setter for new message id * @param id Message id */ void setMessageID(String id); /** * Return correlation id * @return Correlation id */ String getCorrelationID(); /** * Setter for correlation id * @param id Correlation id */ void setCorrelationID(String id); /** * Return message type * @return Message type */ String getMessageType(); /** * Setter for message type * @param type Message type */ void setMessageType(String type); /** * Getter for boolean property * @param name Boolean property name * @return Boolean property */ boolean getBooleanProperty(String name); /** * Add boolean property to message * @param name Boolean property name * @param value Boolean property value */ void setBooleanProperty(String name, boolean value); /** * Add byte property to message * @param name Byte property name * @return Byte property value */ byte getByteProperty(String name); /** * Add byte property to message * @param name Byte property name * @param value Byte property value */ void setByteProperty(String name, byte value); /** * Return double property by name * @param name Double property name * @return Double property value */ double getDoubleProperty(String name); /** * Add double property to message * @param name Double property name * @param value Double property value */ void setDoubleProperty(String name, double value); /** * Return float property by name * @param name Float property name * @return Float property value */ float getFloatProperty(String name); /** * Add float property to message * @param name Float property name * @param value Float property value */ void setFloatProperty(String name, float value); /** * Return int property by name * @param name Int property name * @return Int property value */ int getIntProperty(String name); /** * Add int property to message * @param name Int property name * @param value Int property value */ void setIntProperty(String name, int value); /** * Return long property to message * @param name Long property name * @return Long property value */ long getLongProperty(String name); /** * Add long property to message * @param name Long property name * @param value Long property value */ void setLongProperty(String name, long value); /** * Return short property to message * @param name Short property name * @return Short property value */ short getShortProperty(String name); /** * Add short property to message * @param name Short property name * @param value Short property value */ void setShortProperty(String name, short value); /** * Return string property to message * @param name String property name * @return String property value */ String getStringProperty(String name); /** * Add string property to message * @param name String property name * @param value String property value */ void setStringProperty(String name, String value); /** * Return object property to message * @param name Object property name * @return Object property value */ Object getObjectProperty(String name); /** * Add object property to message * @param name Object property name * @param value Object property value */ void setObjectProperty(String name, Object value); } red5-1.0~svn4374.orig/src/org/red5/server/messaging/ServiceAdapter.java0000644000175000017500000000704311706617130025565 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; import org.red5.compatibility.flex.messaging.messages.CommandMessage; import org.red5.compatibility.flex.messaging.messages.Message; /** * The ServiceAdapter class is the base definition of a service adapter. * * @author Paul Gregoire */ public abstract class ServiceAdapter { /** * Starts the adapter if its associated Destination is started and if the adapter * is not already running. If subclasses override, they must call super.start(). */ public void start() { } /** * Stops the ServiceAdapter. If subclasses override, they must call super.start(). */ public void stop() { } /** * Handle a data message intended for this adapter. This method is responsible for * handling the message and returning a result (if any). The return value of this * message is used as the body of the acknowledge message returned to the client. It * may be null if there is no data being returned for this message. * Typically the data content for the message is stored in the body property of the * message. The headers of the message are used to store fields which relate to the * transport of the message. The type of operation is stored as the operation property * of the message. * * @param message the message as sent by the client intended for this adapter * @return the body of the acknowledge message (or null if there is no body) */ public abstract Object invoke(Message message); /** * Accept a command from the adapter's service and perform some internal * action based upon it. CommandMessages are used for messages which control * the state of the connection between the client and the server. For example, * this handles subscribe, unsubscribe, and ping operations. The messageRefType * property of the CommandMessage is used to associate a command message with a * particular service. Services are configured to handle messages of a particular * concrete type. For example, the MessageService is typically invoked to handle * messages of type flex.messaging.messages.AsyncMessage. To ensure a given * CommandMessage is routed to the right service, its MessageRefType is set to the * string name of the message type for messages handled by that service. * * @param commandMessage * @return Exception if not implemented */ public Object manage(CommandMessage commandMessage) { throw new UnsupportedOperationException("This adapter does not support the manage call"); } /** * Returns true if the adapter performs custom subscription management. * The default return value is false, and subclasses should override this * method as necessary. * * @return true if subscriptions are handled */ public boolean handlesSubscriptions() { return true; } } red5-1.0~svn4374.orig/src/org/red5/server/messaging/IPipe.java0000644000175000017500000000305011706617130023664 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.messaging; /** * A pipe is an object that connects message providers and * message consumers. Its main function is to transport messages * in kind of ways it provides. * * Pipes fire events as they go, these events are common way to work with pipes for * higher level parts of server. * * @author The Red5 Project (red5@osflash.org) * @author Steven Gong (steven.gong@gmail.com) */ public interface IPipe extends IMessageInput, IMessageOutput { /** * Add connection event listener to pipe * @param listener Connection event listener */ void addPipeConnectionListener(IPipeConnectionListener listener); /** * Add connection event listener to pipe * @param listener Connection event listener */ void removePipeConnectionListener(IPipeConnectionListener listener); } red5-1.0~svn4374.orig/src/org/red5/server/Shutdown.java0000644000175000017500000001073111706617130022520 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server; import java.lang.reflect.UndeclaredThrowableException; import java.util.HashMap; import javax.management.JMX; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; import org.red5.server.jmx.mxbeans.ShutdownMXBean; /** * Provides a means to cleanly shutdown an instance from the command line. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class Shutdown { /** * Connects to the given RMI port (default: 9999) and invokes shutdown on * the loader. * * @param args The first parameter should be a port number */ @SuppressWarnings("cast") public static void main(String[] args) { try { String policyFile = System.getProperty("java.security.policy"); if (policyFile == null) { System.setProperty("java.security.debug", "failure"); System.setProperty("java.security.policy", "conf/red5.policy"); } /* try { // Enable the security manager SecurityManager sm = new SecurityManager(); System.setSecurityManager(sm); } catch (SecurityException se) { System.err.println("Security manager already set"); } */ // check for the host name as a system prop String rmiAdapterHost = System.getProperty("java.rmi.server.hostname"); if (rmiAdapterHost == null) { rmiAdapterHost = "localhost"; } JMXServiceURL url = null; JMXConnector jmxc = null; HashMap env = null; if (null == args || args.length < 1) { System.out.printf("Attempting to connect to RMI %s:9999\n", rmiAdapterHost); url = new JMXServiceURL("service:jmx:rmi://" + rmiAdapterHost + ":9999/jndi/rmi://" + rmiAdapterHost + ":9999/red5"); } else { System.out.printf("Attempting to connect to RMI %s:%s\n", rmiAdapterHost, args[0]); url = new JMXServiceURL("service:jmx:rmi://" + rmiAdapterHost + ":" + args[0] + "/jndi/rmi://" + rmiAdapterHost + ":" + args[0] + "/red5"); if (args.length > 1) { env = new HashMap(1); String[] credentials = new String[] { args[1], args[2] }; env.put("jmx.remote.credentials", credentials); } } jmxc = JMXConnectorFactory.connect(url, env); MBeanServerConnection mbs = jmxc.getMBeanServerConnection(); //class supporting shutdown ShutdownMXBean proxy = null; //check for loader registration ObjectName tomcatObjectName = new ObjectName("org.red5.server:type=TomcatLoader"); ObjectName jettyObjectName = new ObjectName("org.red5.server:type=JettyLoader"); ObjectName contextLoaderObjectName = new ObjectName("org.red5.server:type=ContextLoader"); if (mbs.isRegistered(jettyObjectName)) { System.out.println("Red5 Jetty loader was found"); proxy = JMX.newMXBeanProxy(mbs, jettyObjectName, ShutdownMXBean.class, true); } else if (mbs.isRegistered(tomcatObjectName)) { System.out.println("Red5 Tomcat loader was found"); proxy = JMX.newMXBeanProxy(mbs, tomcatObjectName, ShutdownMXBean.class, true); } else if (mbs.isRegistered(contextLoaderObjectName)) { System.out.println("Red5 Context loader was found"); proxy = JMX.newMXBeanProxy(mbs, contextLoaderObjectName, ShutdownMXBean.class, true); } else { System.out.println("Red5 Loader was not found, is the server running?"); } if (proxy != null) { System.out.println("Calling shutdown"); proxy.shutdown(); } jmxc.close(); } catch (UndeclaredThrowableException e) { //ignore } catch (NullPointerException e) { //ignore } catch (Exception e) { e.printStackTrace(); } } } red5-1.0~svn4374.orig/src/org/red5/server/util/0000755000175000017500000000000011760512574021023 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/util/ScopeUtils.java0000644000175000017500000002122511747114732023761 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.util; import java.lang.reflect.Field; import org.red5.server.api.IContext; import org.red5.server.api.persistence.IPersistable; import org.red5.server.api.scope.IBasicScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeHandler; import org.red5.server.api.scope.IScopeService; import org.red5.server.api.scope.ScopeType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; /** * Collection of utilities for working with scopes */ public class ScopeUtils { private static final Logger log = LoggerFactory.getLogger(ScopeUtils.class); private static final String SERVICE_CACHE_PREFIX = "__service_cache:"; /** * Constant for slash symbol */ private static final String SLASH = "/"; /** * Resolves scope for specified scope and path. * * @param from Scope to use as context (to start from) * @param path Path to resolve * @return Resolved scope */ public static IScope resolveScope(IScope from, String path) { IScope current = from; if (path.startsWith(SLASH)) { current = ScopeUtils.findRoot(current); path = path.substring(1, path.length()); } if (path.endsWith(SLASH)) { path = path.substring(0, path.length() - 1); } String[] parts = path.split(SLASH); for (String part : parts) { if (part.equals(".")) { continue; } if (part.equals("..")) { if (!current.hasParent()) { return null; } current = current.getParent(); continue; } if (!current.hasChildScope(part)) { return null; } current = current.getScope(part); } return current; } /** * Finds root scope for specified scope object. Root scope is the top level * scope among scope's parents. * * @param from Scope to find root for * @return Root scope object */ public static IScope findRoot(IScope from) { IScope current = from; while (current.hasParent()) { current = current.getParent(); } return current; } /** * Returns the application scope for specified scope. Application scope has * depth of 1 and has no parent. * * See isApp method for details. * * @param from Scope to find application for * @return Application scope. */ public static IScope findApplication(IScope from) { IScope current = from; while (current.hasParent() && !current.getType().equals(ScopeType.APPLICATION)) { current = current.getParent(); } return current; } /** * Check whether one scope is an ancestor of another * * @param from Scope * @param ancestor Scope to check * @return true if ancestor scope is really an ancestor of * scope passed as from parameter, false otherwise. */ public static boolean isAncestor(IBasicScope from, IBasicScope ancestor) { IBasicScope current = from; while (current.hasParent()) { current = current.getParent(); if (current.equals(ancestor)) { return true; } } return false; } /** * Checks whether scope is root or not * * @param scope Scope to check * @return true if scope is root scope (top level scope), * false otherwise. */ public static boolean isRoot(IBasicScope scope) { return !scope.hasParent(); } /** * Check whether scope is the global scope (level 0 leaf in scope tree) or * not * * When user connects the following URL: rtmp://localhost/myapp/foo/bar then / * is the global level scope, myapp is app level, foo is room level and bar * is room level as well (but with higher depth level) * * @param scope Scope to check * @return true if scope is the global scope, * false otherwise. */ public static boolean isGlobal(IBasicScope scope) { return scope.getType().equals(ScopeType.GLOBAL); } /** * Check whether scope is an application scope (level 1 leaf in scope tree) * or not * * @param scope Scope to check * @return true if scope is an application scope, * false otherwise. */ public static boolean isApp(IBasicScope scope) { return scope.getType().equals(ScopeType.APPLICATION); } /** * Check whether scope is a room scope (level 2 leaf in scope tree or lower, * e.g. 3, 4, ...) or not * * @param scope Scope to check * @return true if scope is a room scope, false * otherwise. */ public static boolean isRoom(IBasicScope scope) { return scope.getType().equals(ScopeType.ROOM); } /** * Returns scope service by bean name. See overloaded method for details. * * @param scope scope * @param name name * @return object */ protected static Object getScopeService(IScope scope, String name) { return getScopeService(scope, name, null); } /** * Returns scope services (e.g. SharedObject, etc) for the scope. Method * uses either bean name passes as a string or class object. * * @param scope * The scope service belongs to * @param name * Bean name * @param defaultClass * Class of service * @return Service object */ protected static Object getScopeService(IScope scope, String name, Class defaultClass) { if (scope == null) { return null; } final IContext context = scope.getContext(); ApplicationContext appCtx = context.getApplicationContext(); Object result; if (!appCtx.containsBean(name)) { if (defaultClass == null) { return null; } try { result = defaultClass.newInstance(); } catch (Exception e) { log.error("{}", e); return null; } } else { result = appCtx.getBean(name); } return result; } /** * Returns scope service that implements a given interface. * * @param scope The scope service belongs to * @param intf The interface the service must implement * @return Service object */ public static Object getScopeService(IScope scope, Class intf) { return getScopeService(scope, intf, null); } public static Object getScopeService(IScope scope, Class intf, boolean checkHandler) { return getScopeService(scope, intf, null, checkHandler); } /** * Returns scope service that implements a given interface. * * @param scope The scope service belongs to * @param intf The interface the service must implement * @param defaultClass Class that should be used to create a new service if no service was found. * @return Service object */ public static Object getScopeService(IScope scope, Class intf, Class defaultClass) { return getScopeService(scope, intf, defaultClass, true); } public static Object getScopeService(IScope scope, Class intf, Class defaultClass, boolean checkHandler) { if (scope == null || intf == null) { return null; } // We expect an interface assert intf.isInterface(); String attr = IPersistable.TRANSIENT_PREFIX + SERVICE_CACHE_PREFIX + intf.getCanonicalName(); if (scope.hasAttribute(attr)) { // return cached service return scope.getAttribute(attr); } Object handler = null; if (checkHandler) { IScope current = scope; while (current != null) { IScopeHandler scopeHandler = current.getHandler(); if (intf.isInstance(scopeHandler)) { handler = scopeHandler; break; } if (!current.hasParent()) { break; } current = current.getParent(); } } if (handler == null && IScopeService.class.isAssignableFrom(intf)) { // we've got an IScopeService, try to lookup bean Field key = null; Object serviceName = null; try { key = intf.getField("BEAN_NAME"); serviceName = key.get(null); if (serviceName instanceof String) { handler = getScopeService(scope, (String) serviceName, defaultClass); } } catch (Exception e) { log.debug("No string field 'BEAN_NAME' in that interface"); } } if (handler == null && defaultClass != null) { try { handler = defaultClass.newInstance(); } catch (Exception e) { log.error("", e); } } // cache service scope.setAttribute(attr, handler); return handler; } } red5-1.0~svn4374.orig/src/org/red5/server/util/HttpConnectionUtil.java0000644000175000017500000001005411706617130025455 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.util; import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.ParseException; import org.apache.http.client.params.ClientPNames; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpParams; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility for using HTTP connections. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class HttpConnectionUtil { private static Logger log = LoggerFactory.getLogger(HttpConnectionUtil.class); private static final String userAgent = "Mozilla/4.0 (compatible; Red5 Server)"; private static ThreadSafeClientConnManager connectionManager; private static int connectionTimeout = 7000; static { // Create an HttpClient with the ThreadSafeClientConnManager. // This connection manager must be used if more than one thread will // be using the HttpClient. connectionManager = new ThreadSafeClientConnManager(); connectionManager.setMaxTotal(40); } /** * Returns a client with all our selected properties / params. * * @return client */ public static final DefaultHttpClient getClient() { // create a singular HttpClient object DefaultHttpClient client = new DefaultHttpClient(connectionManager); // dont retry client.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false)); // get the params for the client HttpParams params = client.getParams(); // establish a connection within x seconds params.setParameter(CoreConnectionPNames.SO_TIMEOUT, connectionTimeout); // no redirects params.setParameter(ClientPNames.HANDLE_REDIRECTS, false); // set custom ua params.setParameter(CoreProtocolPNames.USER_AGENT, userAgent); // set the proxy if the user has one set if ((System.getProperty("http.proxyHost") != null) && (System.getProperty("http.proxyPort") != null)) { HttpHost proxy = new HttpHost(System.getProperty("http.proxyHost").toString(), Integer.valueOf(System.getProperty("http.proxyPort"))); client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); } return client; } /** * Logs details about the request error. * * @param response * @throws IOException * @throws ParseException */ public static void handleError(HttpResponse response) throws ParseException, IOException { log.debug("{}", response.getStatusLine().toString()); HttpEntity entity = response.getEntity(); if (entity != null) { log.debug("{}", EntityUtils.toString(entity)); } } /** * @return the connectionTimeout */ public int getConnectionTimeout() { return connectionTimeout; } /** * @param connectionTimeout the connectionTimeout to set */ public void setConnectionTimeout(int connectionTimeout) { HttpConnectionUtil.connectionTimeout = connectionTimeout; } } red5-1.0~svn4374.orig/src/org/red5/server/util/ConversionUtils.java0000644000175000017500000003703711745776105025053 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.util; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.beanutils.BeanMap; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.ConversionException; import org.red5.server.api.IConnection; import org.red5.server.api.remoting.IRemotingConnection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Misc utils for conversions * * @author The Red5 Project (red5@osflash.org) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) * @author Paul Gregoire (mondain@gmail.com) */ public class ConversionUtils { private static final Logger log = LoggerFactory.getLogger(ConversionUtils.class); private static final Class[] PRIMITIVES = { boolean.class, byte.class, char.class, short.class, int.class, long.class, float.class, double.class }; private static final Class[] WRAPPERS = { Boolean.class, Byte.class, Character.class, Short.class, Integer.class, Long.class, Float.class, Double.class }; private static final String NUMERIC_TYPE = "[-]?\\b\\d+\\b|[-]?\\b[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?\\b"; /** * Parameter chains */ private static final Class[][] PARAMETER_CHAINS = { { boolean.class, null }, { byte.class, Short.class }, { char.class, Integer.class }, { short.class, Integer.class }, { int.class, Long.class }, { long.class, Float.class }, { float.class, Double.class }, { double.class, null } }; /** Mapping of primitives to wrappers */ private static Map, Class> primitiveMap = new HashMap, Class>(); /** Mapping of wrappers to primitives */ private static Map, Class> wrapperMap = new HashMap, Class>(); /** * Mapping from wrapper class to appropriate parameter types (in order) * Each entry is an array of Classes, the last of which is either null * (for no chaining) or the next class to try */ private static Map, Class[]> parameterMap = new HashMap, Class[]>(); static { for (int i = 0; i < PRIMITIVES.length; i++) { primitiveMap.put(PRIMITIVES[i], WRAPPERS[i]); wrapperMap.put(WRAPPERS[i], PRIMITIVES[i]); parameterMap.put(WRAPPERS[i], PARAMETER_CHAINS[i]); } } /** * Convert source to given class * @param source Source object * @param target Target class * @return Converted object * @throws ConversionException If object can't be converted * */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Object convert(Object source, Class target) throws ConversionException { if (target == null) { throw new ConversionException("Unable to perform conversion, target was null"); } if (source == null) { if (target.isPrimitive()) { throw new ConversionException(String.format("Unable to convert null to primitive value of %s", target)); } return source; } else if ((source instanceof Float && ((Float) source).isNaN()) || (source instanceof Double && ((Double) source).isNaN())) { // Don't convert NaN values return source; } //log.trace("Source: {} Target: {}", source.getClass(), target); if (IConnection.class.isAssignableFrom(source.getClass()) && (!target.equals(IConnection.class) || !target.equals(IRemotingConnection.class))) { throw new ConversionException("IConnection must match exactly"); } if (target.isInstance(source)) { return source; } if (target.isAssignableFrom(source.getClass())) { return source; } if (target.isArray()) { return convertToArray(source, target); } if (target.equals(String.class)) { return source.toString(); } if (target.isPrimitive()) { return convertToWrappedPrimitive(source, primitiveMap.get(target)); } if (wrapperMap.containsKey(target)) { return convertToWrappedPrimitive(source, target); } if (target.equals(Map.class)) { return convertBeanToMap(source); } if (target.equals(List.class) || target.equals(Collection.class)) { if (source.getClass().equals(LinkedHashMap.class)) { return convertMapToList((LinkedHashMap) source); } else if (source.getClass().isArray()) { return convertArrayToList((Object[]) source); } } if (target.equals(Set.class) && source.getClass().isArray()) { return convertArrayToSet((Object[]) source); } if (target.equals(Set.class) && source instanceof List) { return new HashSet((List) source); } //Trac #352 if (source instanceof Map) { return convertMapToBean((Map) source, target); } throw new ConversionException(String.format("Unable to preform conversion from %s to %s", source, target)); } /** * Convert to array * @param source Source object * @param target Target class * @return Converted object * @throws ConversionException If object can't be converted */ public static Object convertToArray(Object source, Class target) throws ConversionException { try { Class targetType = target.getComponentType(); if (source.getClass().isArray()) { Object targetInstance = Array.newInstance(targetType, Array.getLength(source)); for (int i = 0; i < Array.getLength(source); i++) { Array.set(targetInstance, i, convert(Array.get(source, i), targetType)); } return targetInstance; } if (source instanceof Collection) { Collection sourceCollection = (Collection) source; Object targetInstance = Array.newInstance(target.getComponentType(), sourceCollection.size()); Iterator it = sourceCollection.iterator(); int i = 0; while (it.hasNext()) { Array.set(targetInstance, i++, convert(it.next(), targetType)); } return targetInstance; } throw new ConversionException("Unable to convert to array"); } catch (Exception ex) { throw new ConversionException("Error converting to array", ex); } } public static List convertMapToList(Map map) { List list = new ArrayList(map.size()); list.addAll(map.values()); return list; } /** * Convert to wrapped primitive * @param source Source object * @param wrapper Primitive wrapper type * @return Converted object */ public static Object convertToWrappedPrimitive(Object source, Class wrapper) { if (source == null || wrapper == null) { return null; } if (wrapper.isInstance(source)) { return source; } if (wrapper.isAssignableFrom(source.getClass())) { return source; } if (source instanceof Number) { return convertNumberToWrapper((Number) source, wrapper); } else { //ensure we dont try to convert text to a number, prevent NumberFormatException if (Number.class.isAssignableFrom(wrapper)) { //test for int or fp number if (!source.toString().matches(NUMERIC_TYPE)) { throw new ConversionException(String.format("Unable to convert string %s its not a number type: %s", source, wrapper)); } } return convertStringToWrapper(source.toString(), wrapper); } } /** * Convert string to primitive wrapper like Boolean or Float * @param str String to convert * @param wrapper Primitive wrapper type * @return Converted object */ public static Object convertStringToWrapper(String str, Class wrapper) { log.trace("String: {} to wrapper: {}", str, wrapper); if (wrapper.equals(String.class)) { return str; } else if (wrapper.equals(Boolean.class)) { return Boolean.valueOf(str); } else if (wrapper.equals(Double.class)) { return Double.valueOf(str); } else if (wrapper.equals(Long.class)) { return Long.valueOf(str); } else if (wrapper.equals(Float.class)) { return Float.valueOf(str); } else if (wrapper.equals(Integer.class)) { return Integer.valueOf(str); } else if (wrapper.equals(Short.class)) { return Short.valueOf(str); } else if (wrapper.equals(Byte.class)) { return Byte.valueOf(str); } throw new ConversionException(String.format("Unable to convert string to: %s", wrapper)); } /** * Convert number to primitive wrapper like Boolean or Float * @param num Number to conver * @param wrapper Primitive wrapper type * @return Converted object */ public static Object convertNumberToWrapper(Number num, Class wrapper) { //XXX Paul: Using valueOf will reduce object creation if (wrapper.equals(String.class)) { return num.toString(); } else if (wrapper.equals(Boolean.class)) { return Boolean.valueOf(num.intValue() == 1); } else if (wrapper.equals(Double.class)) { return Double.valueOf(num.doubleValue()); } else if (wrapper.equals(Long.class)) { return Long.valueOf(num.longValue()); } else if (wrapper.equals(Float.class)) { return Float.valueOf(num.floatValue()); } else if (wrapper.equals(Integer.class)) { return Integer.valueOf(num.intValue()); } else if (wrapper.equals(Short.class)) { return Short.valueOf(num.shortValue()); } else if (wrapper.equals(Byte.class)) { return Byte.valueOf(num.byteValue()); } throw new ConversionException(String.format("Unable to convert number to: %s", wrapper)); } /** * Find method by name and number of parameters * @param object Object to find method on * @param method Method name * @param numParam Number of parameters * @return List of methods that match by name and number of parameters */ public static List findMethodsByNameAndNumParams(Object object, String method, int numParam) { LinkedList list = new LinkedList(); Method[] methods = object.getClass().getMethods(); for (Method m : methods) { if (log.isDebugEnabled()) { Class[] params = m.getParameterTypes(); log.debug("Method name: {} parameter count: {}", m.getName(), params.length); for (Class param : params) { log.debug("Parameter: {}", param); } } //check parameter length first since this should speed things up if (m.getParameterTypes().length != numParam) { log.debug("Param length not the same"); continue; } //now try to match the name if (!m.getName().equals(method)) { log.trace("Method name not the same"); continue; } list.add(m); } return list; } /** * Convert parameters using methods of this utility class * @param source Array of source object * @param target Array of target classes * @return Array of converted objects * @throws ConversionException If object can't be converted */ public static Object[] convertParams(Object[] source, Class[] target) throws ConversionException { Object[] converted = new Object[target.length]; for (int i = 0; i < target.length; i++) { converted[i] = convert(source[i], target[i]); } return converted; } /** * Convert parameters using methods of this utility class. Special handling is afforded to * classes that implement IConnection. * * @param source Array of source object * @return Array of converted objects */ public static Class[] convertParams(Object[] source) { Class[] converted = null; if (source != null) { converted = new Class[source.length]; for (int i = 0; i < source.length; i++) { if (source[i] != null) { // if the class is not an instance of IConnection use its class if (!IConnection.class.isInstance(source[i])) { converted[i] = source[i].getClass(); } else { // if it does implement IConnection use the interface converted[i] = IConnection.class; } } else { converted[i] = null; } } } else { converted = new Class[0]; } if (log.isTraceEnabled()) { log.trace("Converted parameters: {}", Arrays.toString(converted)); } return converted; } /** * * @param source source arra * @return list * @throws ConversionException on failure */ public static List convertArrayToList(Object[] source) throws ConversionException { List list = new ArrayList(source.length); for (Object element : source) { list.add(element); } return list; } /** * Convert map to bean * @param source Source map * @param target Target class * @return Bean of that class * @throws ConversionException on failure */ public static Object convertMapToBean(Map source, Class target) throws ConversionException { Object bean = newInstance(target); if (bean == null) { //try with just the target name as specified in Trac #352 bean = newInstance(target.getName()); if (bean == null) { throw new ConversionException("Unable to create bean using empty constructor"); } } try { BeanUtils.populate(bean, source); } catch (Exception e) { throw new ConversionException("Error populating bean", e); } return bean; } /** * Convert bean to map * @param source Source bean * @return Converted map */ public static Map convertBeanToMap(Object source) { return new BeanMap(source); } /** * Convert array to set, removing duplicates * @param source Source array * @return Set */ public static Set convertArrayToSet(Object[] source) { Set set = new HashSet(); for (Object element : source) { set.add(element); } return set; } /** * Create new class instance * * @param className Class name; may not be loaded by JVM yet * @return Instance of given class */ protected static Object newInstance(String className) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); log.debug("Conversion utils classloader: {}", cl); Object instance = null; try { Class clazz = cl.loadClass(className); instance = clazz.newInstance(); } catch (Exception ex) { log.error("Error loading class: {}", className, ex); } return instance; } /** * Create new class instance * * @param clazz Class; may not be loaded by JVM yet * @return Instance of given class */ private static Object newInstance(Class clazz) { Object instance = null; try { instance = clazz.newInstance(); } catch (Exception ex) { log.error("Error loading class: {}", clazz.getName(), ex); } return instance; } } red5-1.0~svn4374.orig/src/org/red5/server/util/FileUtil.java0000644000175000017500000004213111754510402023373 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.util; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.util.Enumeration; import java.util.Random; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Generic file utility containing useful file or directory * manipulation functions. * * @author Paul Gregoire (mondain@gmail.com) * @author Dominick Accattato (daccattato@gmail.com) */ public class FileUtil { private static Logger log = LoggerFactory.getLogger(FileUtil.class); public static void copyFile(File source, File dest) throws IOException { log.debug("Copy from {} to {}", source.getAbsoluteFile(), dest .getAbsoluteFile()); FileInputStream fi = new FileInputStream(source); FileChannel fic = fi.getChannel(); MappedByteBuffer mbuf = fic.map(FileChannel.MapMode.READ_ONLY, 0, source.length()); fic.close(); fi.close(); fi = null; // ensure the destination directory exists if (!dest.exists()) { String destPath = dest.getPath(); log.debug("Destination path: {}", destPath); String destDir = destPath.substring(0, destPath .lastIndexOf(File.separatorChar)); log.debug("Destination dir: {}", destDir); File dir = new File(destDir); if (!dir.exists()) { if (dir.mkdirs()) { log.debug("Directory created"); } else { log.warn("Directory not created"); } } dir = null; } FileOutputStream fo = new FileOutputStream(dest); FileChannel foc = fo.getChannel(); foc.write(mbuf); foc.close(); fo.close(); fo = null; mbuf.clear(); mbuf = null; } public static void copyFile(String source, String dest) throws IOException { copyFile(new File(source), new File(dest)); } public static void moveFile(String source, String dest) throws IOException { copyFile(source, dest); File src = new File(source); if (src.exists() && src.canRead()) { if (src.delete()) { log.debug("Source file was deleted"); } else { log .debug("Source file was not deleted, the file will be deleted on exit"); src.deleteOnExit(); } } else { log.warn("Source file could not be accessed for removal"); } src = null; } /** * Deletes a directory and its contents. This will fail if there are any * file locks or if the directory cannot be emptied. * * @param directory directory to delete * @throws IOException if directory cannot be deleted * @return true if directory was successfully deleted; false if directory * did not exist */ public static boolean deleteDirectory(String directory) throws IOException { return deleteDirectory(directory, false); } /** * Deletes a directory and its contents. This will fail if there are any * file locks or if the directory cannot be emptied. * * @param directory directory to delete * @param useOSNativeDelete flag to signify use of operating system delete function * @throws IOException if directory cannot be deleted * @return true if directory was successfully deleted; false if directory * did not exist */ public static boolean deleteDirectory(String directory, boolean useOSNativeDelete) throws IOException { boolean result = false; if (!useOSNativeDelete) { File dir = new File(directory); // first all files have to be cleared out for (File file : dir.listFiles()) { if (file.delete()) { log.debug("{} was deleted", file.getName()); } else { log.debug("{} was not deleted", file.getName()); file.deleteOnExit(); } file = null; } // not you may remove the dir if (dir.delete()) { log.debug("Directory was deleted"); result = true; } else { log.debug("Directory was not deleted, it may be deleted on exit"); dir.deleteOnExit(); } dir = null; } else { Process p = null; Thread std = null; try { Runtime runTime = Runtime.getRuntime(); log.debug("Execute runtime"); //determine file system type if (File.separatorChar == '\\') { //we are windows p = runTime.exec("CMD /D /C \"RMDIR /Q /S " + directory.replace('/', '\\') + "\""); } else { //we are unix variant p = runTime.exec("rm -rf " + directory.replace('\\', File.separatorChar)); } // observe std out std = stdOut(p); // wait for the observer threads to finish while (std.isAlive()) { try { Thread.sleep(250); } catch (Exception e) { } } log.debug("Process threads wait exited"); result = true; } catch (Exception e) { log.error("Error running delete script", e); } finally { if (null != p) { log.debug("Destroying process"); p.destroy(); p = null; } std = null; } } return result; } /** * Rename a file natively; using REN on Windows and mv on *nix. * * @param from old name * @param to new name */ public static void rename(String from, String to) { Process p = null; Thread std = null; try { Runtime runTime = Runtime.getRuntime(); log.debug("Execute runtime"); //determine file system type if (File.separatorChar == '\\') { //we are windows p = runTime.exec("CMD /D /C \"REN " + from + ' ' + to + "\""); } else { //we are unix variant p = runTime.exec("mv -f " + from + ' ' + to); } // observe std out std = stdOut(p); // wait for the observer threads to finish while (std.isAlive()) { try { Thread.sleep(250); } catch (Exception e) { } } log.debug("Process threads wait exited"); } catch (Exception e) { log.error("Error running delete script", e); } finally { if (null != p) { log.debug("Destroying process"); p.destroy(); p = null; std = null; } } } /** * Special method for capture of StdOut. * * @return */ private final static Thread stdOut(final Process p) { final byte[] empty = new byte[128]; for (int b = 0; b < empty.length; b++) { empty[b] = (byte) 0; } Thread std = new Thread() { public void run() { StringBuilder sb = new StringBuilder(1024); byte[] buf = new byte[128]; BufferedInputStream bis = new BufferedInputStream(p .getInputStream()); log.debug("Process output:"); try { while (bis.read(buf) != -1) { sb.append(new String(buf).trim()); // clear buffer System.arraycopy(empty, 0, buf, 0, buf.length); } log.debug(sb.toString()); bis.close(); } catch (Exception e) { log.error("{}", e); } } }; std.setDaemon(true); std.start(); return std; } /** * Create a directory. * * @param directory directory to make * @return whether a new directory was made * @throws IOException if directory does not already exist or cannot be made */ public static boolean makeDirectory(String directory) throws IOException { return makeDirectory(directory, false); } /** * Create a directory. The parent directories will be created if * createParents is passed as true. * * @param directory directory * @param createParents whether to create all parents * @return true if directory was created; false if it already existed * @throws IOException if we cannot create directory * */ public static boolean makeDirectory(String directory, boolean createParents) throws IOException { boolean created = false; File dir = new File(directory); if (createParents) { created = dir.mkdirs(); if (created) { log.debug("Directory created: {}", dir.getAbsolutePath()); } else { log.debug("Directory was not created: {}", dir .getAbsolutePath()); } } else { created = dir.mkdir(); if (created) { log.debug("Directory created: {}", dir.getAbsolutePath()); } else { log.debug("Directory was not created: {}", dir .getAbsolutePath()); } } dir = null; return created; } /** * Unzips a war file to an application located under the webapps directory * * @param compressedFileName The String name of the war file * @param destinationDir The destination directory, ie: webapps */ public static void unzip(String compressedFileName, String destinationDir) { //strip everything except the applications name String dirName = null; // checks to see if there is a dash "-" in the filename of the war. String applicationName = compressedFileName.substring(compressedFileName.lastIndexOf("/")); int dashIndex = applicationName.indexOf('-'); if (dashIndex != -1) { //strip everything except the applications name dirName = compressedFileName.substring(0, dashIndex); } else { //grab every char up to the last '.' dirName = compressedFileName.substring(0, compressedFileName.lastIndexOf('.')); } log.debug("Directory: {}", dirName); //String tmpDir = System.getProperty("java.io.tmpdir"); File zipDir = new File(compressedFileName); File parent = zipDir.getParentFile(); log.debug("Parent: {}", (parent != null ? parent.getName() : null)); //File tmpDir = new File(System.getProperty("java.io.tmpdir"), dirName); File tmpDir = new File(destinationDir); // make the war directory log.debug("Making directory: {}", tmpDir.mkdirs()); try { ZipFile zf = new ZipFile(compressedFileName); Enumeration e = zf.entries(); while(e.hasMoreElements()) { ZipEntry ze = (ZipEntry) e.nextElement(); log.debug("Unzipping {}", ze.getName()); if(ze.isDirectory()) { log.debug("is a directory"); File dir = new File(tmpDir + "/" + ze.getName()); Boolean tmp = dir.mkdir(); log.debug("{}", tmp); continue; } // checks to see if a zipEntry contains a path // i.e. ze.getName() == "META-INF/MANIFEST.MF" // if this case is true, then we create the path first if(ze.getName().lastIndexOf("/") != -1) { String zipName = ze.getName(); String zipDirStructure = zipName.substring(0, zipName.lastIndexOf("/")); File completeDirectory = new File(tmpDir + "/" + zipDirStructure); if(!completeDirectory.exists()) { if(!completeDirectory.mkdirs()) { log.error("could not create complete directory structure"); } } } // creates the file FileOutputStream fout = new FileOutputStream(tmpDir + "/" + ze.getName()); InputStream in = zf.getInputStream(ze); copy(in, fout); in.close(); fout.close(); } e = null; } catch (IOException e) { log.error("Errord unzipping", e); //log.warn("Exception {}", e); } } public static void copy(InputStream in, OutputStream out) throws IOException { synchronized(in) { synchronized(out) { byte[] buffer = new byte[256]; while (true) { int bytesRead = in.read(buffer); if(bytesRead == -1) break; out.write(buffer, 0, bytesRead); } } } } /** * Unzips a given archive to a specified destination directory. * * @param compressedFileName * @param destinationDir */ // public static void unzip(String compressedFileName, String destinationDir) { // log.debug("Unzip - file: {} destination: {}", compressedFileName, destinationDir); // try { // final int BUFFER = 2048; // BufferedOutputStream dest = null; // FileInputStream fis = new FileInputStream(compressedFileName); // CheckedInputStream checksum = new CheckedInputStream(fis, // new Adler32()); // ZipInputStream zis = new ZipInputStream(new BufferedInputStream( // checksum)); // ZipEntry entry; // while ((entry = zis.getNextEntry()) != null) { // log.debug("Extracting: {}", entry); // String name = entry.getName(); // int count; // byte data[] = new byte[BUFFER]; // // write the files to the disk // File destFile = new File(destinationDir, name); // log.debug("Absolute path: {}", destFile.getAbsolutePath()); // //create dirs as needed, look for file extension to determine type // if (entry.isDirectory()) { // log.debug("Entry is detected as a directory"); // if (destFile.mkdirs()) { // log.debug("Directory created: {}", destFile.getName()); // } else { // log.warn("Directory was not created: {}", destFile.getName()); // } // destFile = null; // continue; // } // // FileOutputStream fos = new FileOutputStream(destFile); // dest = new BufferedOutputStream(fos, BUFFER); // while ((count = zis.read(data, 0, BUFFER)) != -1) { // dest.write(data, 0, count); // } // dest.flush(); // dest.close(); // destFile = null; // } // zis.close(); // log.debug("Checksum: {}", checksum.getChecksum().getValue()); // } catch (Exception e) { // log.error("Error unzipping {}", compressedFileName, e); // log.warn("Exception {}", e); // } // // } /** * Quick-n-dirty directory formatting to support launching in windows, specifically from ant. * @param absWebappsPath abs webapps path * @param contextDirName conext directory name * @return full path */ public static String formatPath(String absWebappsPath, String contextDirName) { StringBuilder path = new StringBuilder(absWebappsPath.length() + contextDirName.length()); path.append(absWebappsPath); if (log.isTraceEnabled()) { log.trace("Path start: {}", path.toString()); } int idx = -1; if (File.separatorChar != '/') { while ((idx = path.indexOf(File.separator)) != -1) { path.deleteCharAt(idx); path.insert(idx, '/'); } } if (log.isTraceEnabled()) { log.trace("Path step 1: {}", path.toString()); } //remove any './' if ((idx = path.indexOf("./")) != -1) { path.delete(idx, idx + 2); } if (log.isTraceEnabled()) { log.trace("Path step 2: {}", path.toString()); } //add / to base path if one doesnt exist if (path.charAt(path.length() - 1) != '/') { path.append('/'); } if (log.isTraceEnabled()) { log.trace("Path step 3: {}", path.toString()); } //remove the / from the beginning of the context dir if (contextDirName.charAt(0) == '/' && path.charAt(path.length() - 1) == '/') { path.append(contextDirName.substring(1)); } else { path.append(contextDirName); } if (log.isTraceEnabled()) { log.trace("Path step 4: {}", path.toString()); } return path.toString(); } /** * Generates a custom name containing numbers and an underscore ex. 282818_00023. * The name contains current seconds and a random number component. * * @return custom name */ public static String generateCustomName() { Random random = new Random(); StringBuilder sb = new StringBuilder(); sb.append(PropertyConverter.getCurrentTimeSeconds()); sb.append('_'); int i = random.nextInt(99999); if (i < 10) { sb.append("0000"); } else if (i < 100) { sb.append("000"); } else if (i < 1000) { sb.append("00"); } else if (i < 10000) { sb.append('0'); } sb.append(i); return sb.toString(); } /** * Reads all the bytes of a given file into an array. If the file size exceeds Integer.MAX_VALUE, it will * be truncated. * * @param localSwfFile * @return file bytes */ public static byte[] readAsByteArray(File localSwfFile) { byte[] fileBytes = new byte[(int) localSwfFile.length()]; byte[] b = new byte[1]; FileInputStream fis = null; try { fis = new FileInputStream(localSwfFile); for (int i = 0; i < Integer.MAX_VALUE; i++) { if (fis.read(b) != -1) { fileBytes[i] = b[0]; } else { break; } } } catch (IOException e) { log.warn("Exception reading file bytes", e); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { } } } return fileBytes; } } red5-1.0~svn4374.orig/src/org/red5/server/util/ServerDetector.java0000644000175000017500000001241311706617130024621 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.util; /** * Simple J2EE server detector, based on an idea created by Brian Wing Shun * Chan. * * @author Paul Gregoire (mondain@gmail.com) */ public class ServerDetector { private static String type; private static boolean geronimo; private static boolean glassfish; private static boolean jboss; private static boolean jetty; private static boolean jonas; private static boolean resin; private static boolean tomcat; private static boolean weblogic; private static boolean websphere; public static final String GERONIMO_CLASS = "/org/apache/geronimo/system/main/Daemon.class"; public static final String GERONIMO_ID = "geronimo"; public static final String GLASSFISH_ID = "glassfish"; public static final String GLASSFISH_SYSTEM_PROPERTY = "com.sun.aas.instanceRoot"; public static final String JBOSS_CLASS = "/org/jboss/Main.class"; public static final String JBOSS_ID = "jboss"; public static final String JETTY_CLASS = "/org/mortbay/jetty/Server.class"; public static final String JETTY_ID = "jetty"; public static final String JONAS_CLASS = "/org/objectweb/jonas/server/Server.class"; public static final String JONAS_ID = "jonas"; public static final String RESIN_CLASS = "/com/caucho/server/resin/Resin.class"; public static final String RESIN_ID = "resin"; public static final String TOMCAT_BOOTSTRAP_CLASS = "/org/apache/catalina/startup/Bootstrap.class"; public static final String TOMCAT_EMBEDDED_CLASS = "/org/apache/catalina/startup/Embedded.class"; public static final String TOMCAT_ID = "tomcat"; public static final String WEBLOGIC_CLASS = "/weblogic/Server.class"; public static final String WEBLOGIC_ID = "weblogic"; public static final String WEBSPHERE_CLASS = "/com/ibm/websphere/product/VersionInfo.class"; public static final String WEBSPHERE_ID = "websphere"; static { // do the check only once per classloader / execution type = getServerType(); } private static String getServerType() { if (type == null) { String tmp = null; if (isGeronimo()) { tmp = GERONIMO_ID; } else if (isGlassfish()) { tmp = GLASSFISH_ID; } else if (isJBoss()) { tmp = JBOSS_ID; } else if (isJOnAS()) { tmp = JONAS_ID; } else if (isResin()) { tmp = RESIN_ID; } else if (isWebLogic()) { tmp = WEBLOGIC_ID; } else if (isWebSphere()) { tmp = WEBSPHERE_ID; } //check for tomcat or jetty - standalone or embedded if (isTomcat()) { if (tmp == null) { tmp = TOMCAT_ID; } else { tmp += "-" + TOMCAT_ID; } } else if (isJetty()) { if (tmp == null) { tmp = JETTY_ID; } else { tmp += "-" + JETTY_ID; } } if (tmp == null) { throw new RuntimeException("Server is not supported"); } return tmp; } else { return type; } } public static boolean isGeronimo() { if (!geronimo) { geronimo = detect(GERONIMO_CLASS); } return geronimo; } public static boolean isGlassfish() { if (!glassfish) { String value = System.getProperty(GLASSFISH_SYSTEM_PROPERTY); if (value != null) { glassfish = true; } } return glassfish; } public static boolean isJBoss() { if (!jboss) { jboss = detect(JBOSS_CLASS); } return jboss; } public static boolean isJetty() { if (!jetty) { jetty = detect(JETTY_CLASS); } return jetty; } public static boolean isJOnAS() { if (!jonas) { jonas = detect(JONAS_CLASS); } return jonas; } public static boolean isResin() { if (!resin) { resin = detect(RESIN_CLASS); } return resin; } public static boolean isTomcat() { if (!tomcat) { tomcat = detect(TOMCAT_BOOTSTRAP_CLASS); //check embedded if (!tomcat) { tomcat = detect(TOMCAT_EMBEDDED_CLASS); } } return tomcat; } public static boolean isWebLogic() { if (!weblogic) { weblogic = detect(WEBLOGIC_CLASS); } return weblogic; } public static boolean isWebSphere() { if (!websphere) { websphere = detect(WEBSPHERE_CLASS); } return websphere; } private static boolean detect(String className) { try { ClassLoader.getSystemClassLoader().loadClass(className); return true; } catch (ClassNotFoundException cnfe) { try { //try the current classloader Thread.currentThread().getContextClassLoader().loadClass(className); return true; } catch (ClassNotFoundException cnfe2) { return false; } } } }red5-1.0~svn4374.orig/src/org/red5/server/util/PropertyConverter.java0000644000175000017500000001310211706617130025371 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.util; import java.util.Calendar; import org.apache.commons.lang3.StringUtils; /** * Converter for properties originating from properties files. Predetermined * string formats are converted into other usable types such as timestamps. * * @author Paul Gregoire (mondain@gmail.com) */ public class PropertyConverter { /** * Converts a string denoting an amount of time into milliseconds and adds * it to the current date. Strings are expected to follow this form where # * equals a digit: #M The following are permitted for denoting time: H = * hours, M = minutes, S = seconds * * @param time time * @return time in milliseconds */ public static long convertStringToFutureTimeMillis(String time) { Calendar exp = Calendar.getInstance(); if (time.endsWith("H")) { exp.add(Calendar.HOUR, Integer.valueOf(StringUtils .remove(time, 'H'))); } else if (time.endsWith("M")) { exp.add(Calendar.MINUTE, Integer.valueOf(StringUtils.remove(time, 'M'))); } else if (time.endsWith("S")) { exp.add(Calendar.MILLISECOND, Integer.valueOf(StringUtils.remove( time, 'S')) * 1000); } return exp.getTimeInMillis(); } /** * Converts a string denoting an amount of time into seconds. Strings are * expected to follow this form where # equals a digit: #M The following are * permitted for denoting time: H = hours, M = minutes, S = seconds * * @param time time * @return time in seconds */ public static int convertStringToTimeSeconds(String time) { int result = 0; if (time.endsWith("H")) { int hoursToAdd = Integer.valueOf(StringUtils.remove(time, 'H')); result = (60 * 60) * hoursToAdd; } else if (time.endsWith("M")) { int minsToAdd = Integer.valueOf(StringUtils.remove(time, 'M')); result = 60 * minsToAdd; } else if (time.endsWith("S")) { int secsToAdd = Integer.valueOf(StringUtils.remove(time, 'S')); result = secsToAdd; } return result; } /** * Converts a string denoting an amount of time into milliseconds. Strings * are expected to follow this form where # equals a digit: #M The following * are permitted for denoting time: H = hours, M = minutes, S = seconds * * @param time time * @return time in milliseconds */ public static long convertStringToTimeMillis(String time) { long result = 0; if (time.endsWith("H")) { long hoursToAdd = Integer.valueOf(StringUtils.remove(time, 'H')); result = ((1000 * 60) * 60) * hoursToAdd; } else if (time.endsWith("M")) { long minsToAdd = Integer.valueOf(StringUtils.remove(time, 'M')); result = (1000 * 60) * minsToAdd; } else if (time.endsWith("S")) { long secsToAdd = Integer.valueOf(StringUtils.remove(time, 'S')); result = 1000 * secsToAdd; } return result; } /** * Converts a string denoting an amount of bytes into an integer value. * Strings are expected to follow this form where # equals a digit: #M The * following are permitted for denoting binary size: K = kilobytes, M = * megabytes, G = gigabytes * * @param memSize memory * @return size as an integer */ public static int convertStringToMemorySizeInt(String memSize) { int result = 0; if (memSize.endsWith("K")) { result = Integer.valueOf(StringUtils.remove(memSize, 'K')) * 1000; } else if (memSize.endsWith("M")) { result = Integer.valueOf(StringUtils.remove(memSize, 'M')) * 1000 * 1000; } else if (memSize.endsWith("G")) { result = Integer.valueOf(StringUtils.remove(memSize, 'G')) * 1000 * 1000 * 1000; } return result; } /** * Converts a string denoting an amount of bytes into an long value. Strings * are expected to follow this form where # equals a digit: #M The following * are permitted for denoting binary size: K = kilobytes, M = megabytes, G = * gigabytes * * @param memSize memory size * @return size as an long */ public static long convertStringToMemorySizeLong(String memSize) { long result = 0; if (memSize.endsWith("K")) { result = Long.valueOf(StringUtils.remove(memSize, 'K')) * 1000; } else if (memSize.endsWith("M")) { result = Long.valueOf(StringUtils.remove(memSize, 'M')) * 1000 * 1000; } else if (memSize.endsWith("G")) { result = Long.valueOf(StringUtils.remove(memSize, 'G')) * 1000 * 1000 * 1000; } return result; } /** * Quick time converter to keep our timestamps compatible with PHP's time() * (seconds) * @return time in seconds */ public static Integer getCurrentTimeSeconds() { return convertMillisToSeconds(System.currentTimeMillis()); } /** * Quick time converter to keep our timestamps compatible with PHP's time() * (seconds) * @param millis milliseconds * @return seconds */ public static Integer convertMillisToSeconds(Long millis) { return Long.valueOf(millis / 1000).intValue(); } } red5-1.0~svn4374.orig/src/org/red5/server/script/0000755000175000017500000000000011760512573021351 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/script/groovy/0000755000175000017500000000000011760512573022676 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/script/groovy/GroovyScriptFactory.java0000644000175000017500000002064311616523204027541 0ustar drazzibdrazzib/* * Copyright 2002-2011 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.script.groovy; import groovy.lang.GroovyClassLoader; import groovy.lang.GroovyObject; import groovy.lang.Script; import java.io.IOException; import org.codehaus.groovy.control.CompilationFailedException; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.scripting.ScriptCompilationException; import org.springframework.scripting.ScriptFactory; import org.springframework.scripting.ScriptSource; import org.springframework.scripting.groovy.GroovyObjectCustomizer; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** * {@link org.springframework.scripting.ScriptFactory} implementation * for a Groovy script. * *

Typically used in combination with a * {@link org.springframework.scripting.support.ScriptFactoryPostProcessor}; * see the latter's * {@link org.springframework.scripting.support.ScriptFactoryPostProcessor Javadoc} * for a configuration example. * * @author Juergen Hoeller * @author Rob Harrop * @since 2.0 * @see org.springframework.scripting.support.ScriptFactoryPostProcessor * @see groovy.lang.GroovyClassLoader */ public class GroovyScriptFactory implements ScriptFactory, BeanClassLoaderAware { private final String scriptSourceLocator; private final GroovyObjectCustomizer groovyObjectCustomizer; private GroovyClassLoader groovyClassLoader = new GroovyClassLoader(ClassUtils.getDefaultClassLoader()); private Class scriptClass; private Class scriptResultClass; private final Object scriptClassMonitor = new Object(); @SuppressWarnings({ "rawtypes" }) private Class[] scriptInterfaces; /** * Create a new GroovyScriptFactory for the given script source. *

We don't need to specify script interfaces here, since * a Groovy script defines its Java interfaces itself. * @param scriptSourceLocator a locator that points to the source of the script. * Interpreted by the post-processor that actually creates the script. */ public GroovyScriptFactory(String scriptSourceLocator) { Assert.hasText(scriptSourceLocator, "'scriptSourceLocator' must not be empty"); this.scriptSourceLocator = scriptSourceLocator; this.groovyObjectCustomizer = null; // this(scriptSourceLocator, null); } /** * Create a new GroovyScriptFactory for the given script source, * specifying a strategy interface that can create a custom MetaClass * to supply missing methods and otherwise change the behavior of the object. *

We don't need to specify script interfaces here, since * a Groovy script defines its Java interfaces itself. * @param scriptSourceLocator a locator that points to the source of the script. * Interpreted by the post-processor that actually creates the script. * @param groovyObjectCustomizer a customizer that can set a custom metaclass * or make other changes to the GroovyObject created by this factory * (may be null) */ public GroovyScriptFactory(String scriptSourceLocator, GroovyObjectCustomizer groovyObjectCustomizer) { Assert.hasText(scriptSourceLocator, "'scriptSourceLocator' must not be empty"); this.scriptSourceLocator = scriptSourceLocator; this.groovyObjectCustomizer = groovyObjectCustomizer; } @SuppressWarnings({ "rawtypes" }) public GroovyScriptFactory(String scriptSourceLocator, Class[] scriptInterfaces) { Assert.hasText(scriptSourceLocator, "'scriptSourceLocator' must not be empty"); this.scriptSourceLocator = scriptSourceLocator; this.groovyObjectCustomizer = null; // this(scriptSourceLocator, null); if (null == scriptInterfaces || scriptInterfaces.length < 1) { this.scriptInterfaces = new Class[] {}; } else { this.scriptInterfaces = scriptInterfaces; } } public void setBeanClassLoader(ClassLoader classLoader) { this.groovyClassLoader = new GroovyClassLoader(classLoader); } public String getScriptSourceLocator() { return this.scriptSourceLocator; } /** * Groovy scripts determine their interfaces themselves, * hence we don't need to explicitly expose interfaces here. * @return null always */ @SuppressWarnings({ "rawtypes" }) public Class[] getScriptInterfaces() { return scriptInterfaces; } /** * Groovy scripts do not need a config interface, * since they expose their setters as public methods. */ public boolean requiresConfigInterface() { return false; } /** * Loads and parses the Groovy script via the GroovyClassLoader. * @see groovy.lang.GroovyClassLoader */ @SuppressWarnings({ "rawtypes" }) public Object getScriptedObject(ScriptSource scriptSource, Class[] actualInterfaces) throws IOException, ScriptCompilationException { try { Class scriptClassToExecute = null; synchronized (this.scriptClassMonitor) { if (this.scriptClass == null || scriptSource.isModified()) { this.scriptClass = this.groovyClassLoader.parseClass(scriptSource.getScriptAsString()); if (Script.class.isAssignableFrom(this.scriptClass)) { // A Groovy script, probably creating an instance: let's execute it. Object result = executeScript(this.scriptClass); this.scriptResultClass = (result != null ? result.getClass() : null); return result; } else { this.scriptResultClass = this.scriptClass; } } scriptClassToExecute = this.scriptClass; } // Process re-execution outside of the synchronized block. return executeScript(scriptClassToExecute); } catch (CompilationFailedException ex) { throw new ScriptCompilationException( "Could not compile Groovy script: " + scriptSource, ex); } } public Class getScriptedObjectType(ScriptSource scriptSource) throws IOException, ScriptCompilationException { synchronized (this.scriptClassMonitor) { if (this.scriptClass == null || scriptSource.isModified()) { this.scriptClass = this.groovyClassLoader.parseClass(scriptSource.getScriptAsString()); if (Script.class.isAssignableFrom(this.scriptClass)) { // A Groovy script, probably creating an instance: let's execute it. Object result = executeScript(this.scriptClass); this.scriptResultClass = (result != null ? result.getClass() : null); } else { this.scriptResultClass = this.scriptClass; } } return this.scriptResultClass; } } /** * Instantiate the given Groovy script class and run it if necessary. * @param scriptClass the Groovy script class * @return the result object (either an instance of the script class * or the result of running the script instance) * @throws ScriptCompilationException in case of instantiation failure */ protected Object executeScript(Class scriptClass) throws ScriptCompilationException { try { GroovyObject goo = (GroovyObject) scriptClass.newInstance(); if (this.groovyObjectCustomizer != null) { // Allow metaclass and other customization. this.groovyObjectCustomizer.customize(goo); } if (goo instanceof Script) { // A Groovy script, probably creating an instance: let's execute it. return ((Script) goo).run(); } else { // An instance of the scripted class: let's return it as-is. return goo; } } catch (InstantiationException ex) { throw new ScriptCompilationException( "Could not instantiate Groovy script class: " + scriptClass.getName(), ex); } catch (IllegalAccessException ex) { throw new ScriptCompilationException( "Could not access Groovy script constructor: " + scriptClass.getName(), ex); } } public boolean requiresScriptedObjectRefresh(ScriptSource src) { return false; } public String toString() { return "GroovyScriptFactory: script source locator [" + this.scriptSourceLocator + "]"; } } red5-1.0~svn4374.orig/src/org/red5/server/script/jython/0000755000175000017500000000000011760512573022664 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/script/jython/JythonScriptFactory.java0000644000175000017500000001355211756460764027536 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.script.jython; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import org.python.core.Py; import org.python.core.PyFunction; import org.python.core.PyJavaType; import org.python.core.PyObject; import org.python.core.PySystemState; import org.python.util.PythonInterpreter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scripting.ScriptCompilationException; import org.springframework.scripting.ScriptFactory; import org.springframework.scripting.ScriptSource; import org.springframework.util.Assert; /** * {@link org.springframework.scripting.ScriptFactory} implementation for a * Python script. * * @author Yan Weng * @see A prototype of Jython ScriptFactory for Spring Framework */ public class JythonScriptFactory implements ScriptFactory { private static Logger logger = LoggerFactory.getLogger(JythonScriptFactory.class); private final String scriptSourceLocator; @SuppressWarnings({ "rawtypes" }) private final Class[] scriptInterfaces; private final Object[] arguments; public JythonScriptFactory(String scriptSourceLocator) { Assert.hasText(scriptSourceLocator); this.scriptSourceLocator = scriptSourceLocator; this.scriptInterfaces = new Class[] {}; this.arguments = null; } @SuppressWarnings({ "rawtypes" }) public JythonScriptFactory(String scriptSourceLocator, Class[] scriptInterfaces) { Assert.hasText(scriptSourceLocator); Assert.notEmpty(scriptInterfaces); this.scriptSourceLocator = scriptSourceLocator; this.scriptInterfaces = scriptInterfaces; this.arguments = null; } @SuppressWarnings({ "rawtypes" }) public JythonScriptFactory(String scriptSourceLocator, Class[] scriptInterfaces, Object[] arguments) { Assert.hasText(scriptSourceLocator); Assert.notEmpty(scriptInterfaces); this.scriptSourceLocator = scriptSourceLocator; this.scriptInterfaces = scriptInterfaces; if (arguments == null || arguments.length == 0) { this.arguments = null; } else { this.arguments = arguments; } } /** {@inheritDoc} */ public String getScriptSourceLocator() { return scriptSourceLocator; } /** {@inheritDoc} */ @SuppressWarnings({ "rawtypes" }) public Class[] getScriptInterfaces() { return scriptInterfaces; } /** {@inheritDoc} */ public boolean requiresConfigInterface() { return true; } /** {@inheritDoc} */ @SuppressWarnings({ "rawtypes" }) public Object getScriptedObject(ScriptSource scriptSourceLocator, Class[] scriptInterfaces) throws IOException, ScriptCompilationException { String basePath = ""; /* TODO: how to do this when running under Tomcat? ContextHandler handler = WebAppContext.getCurrentWebAppContext(); if (handler != null) { File root = handler.getBaseResource().getFile(); if (root != null && root.exists()) { basePath = root.getAbsolutePath() + File.separator + "WEB-INF" + File.separator; } } */ String strScript = scriptSourceLocator.getScriptAsString(); if (scriptInterfaces.length > 0) { try { PySystemState state = new PySystemState(); if (!"".equals(basePath)) { // Add webapp paths that can contain classes and .jar files to python search path state.path.insert(0, Py.newString(basePath + "classes")); File jarRoot = new File(basePath + "lib"); if (jarRoot.exists()) { for (String filename : jarRoot.list(new FilenameFilter() { public boolean accept(File dir, String name) { return (name.endsWith(".jar")); } })) { state.path.insert(1, Py.newString(basePath + "lib" + File.separator + filename)); } } } PythonInterpreter interp = new PythonInterpreter(null, state); interp.exec(strScript); PyObject getInstance = interp.get("getInstance"); if (!(getInstance instanceof PyFunction)) { throw new ScriptCompilationException("\"getInstance\" is not a function."); } PyObject _this; if (arguments == null) { _this = ((PyFunction) getInstance).__call__(); } else { PyObject[] args = new PyObject[arguments.length]; for (int i = 0; i < arguments.length; i++) { args[i] = PyJavaType.wrapJavaObject(arguments[i]); } _this = ((PyFunction) getInstance).__call__(args); } return _this.__tojava__(scriptInterfaces[0]); } catch (Exception ex) { logger.error("Error while loading script.", ex); if (ex instanceof IOException) { // Raise to caller throw (IOException) ex; } else if (ex instanceof ScriptCompilationException) { // Raise to caller throw (ScriptCompilationException) ex; } throw new ScriptCompilationException(ex.getMessage()); } } logger.error("No scriptInterfaces provided."); return null; } @SuppressWarnings({ "rawtypes" }) public Class getScriptedObjectType(ScriptSource src) throws IOException, ScriptCompilationException { return null; } public boolean requiresScriptedObjectRefresh(ScriptSource src) { return false; } } red5-1.0~svn4374.orig/src/org/red5/server/script/rhino/0000755000175000017500000000000011760512573022470 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/script/rhino/RhinoScriptUtils.java0000644000175000017500000001635411616523204026622 0ustar drazzibdrazzib/* * Copyright 2002-2011 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.script.rhino; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Map; import java.util.regex.PatternSyntaxException; import javax.script.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scripting.ScriptCompilationException; import org.springframework.util.ClassUtils; /** * Utility methods for handling Rhino / Javascript objects. * * @author Paul Gregoire * @since 0.6 */ public class RhinoScriptUtils { private static final Logger log = LoggerFactory.getLogger(RhinoScriptUtils.class); // ScriptEngine manager private static ScriptEngineManager mgr = new ScriptEngineManager(); // Javascript wrapper private static final String jsWrapper = "function Wrapper(obj){return new JSAdapter(){ __has__ : function(name){return true;}, __get__ : function(name){if(name in obj){return obj[name];}else if(typeof(obj['doesNotUnderstand']) == 'function'){return function(){return obj.doesNotUnderstand(name, arguments);}}else{return undefined;}}};}"; /** * Create a new Rhino-scripted object from the given script source. * * @param scriptSource * the script source text * @param interfaces * the interfaces that the scripted Java object is supposed to * implement * @param extendedClass * @return the scripted Java object * @throws ScriptCompilationException * in case of Rhino parsing failure * @throws java.io.IOException */ public static Object createRhinoObject(String scriptSource, Class[] interfaces, Class extendedClass) throws ScriptCompilationException, IOException, Exception { if (log.isDebugEnabled()) { log.debug("Script Engine Manager: " + mgr.getClass().getName()); } ScriptEngine engine = mgr.getEngineByExtension("js"); if (null == engine) { log.warn("Javascript is not supported in this build"); } // set engine scope namespace Bindings nameSpace = engine.getBindings(ScriptContext.ENGINE_SCOPE); // add the logger to the script nameSpace.put("log", log); // compile the wrapper script CompiledScript wrapper = ((Compilable) engine).compile(jsWrapper); nameSpace.put("Wrapper", wrapper); // get the function name ie. class name / ctor String funcName = RhinoScriptUtils.getFunctionName(scriptSource); if (log.isDebugEnabled()) { log.debug("New script: " + funcName); } // set the 'filename' nameSpace.put(ScriptEngine.FILENAME, funcName); if (null != interfaces) { nameSpace.put("interfaces", interfaces); } if (null != extendedClass) { if (log.isDebugEnabled()) { log.debug("Extended: " + extendedClass.getName()); } nameSpace.put("supa", extendedClass.newInstance()); } // // compile the script CompiledScript script = ((Compilable) engine).compile(scriptSource); // eval the script with the associated namespace Object o = null; try { o = script.eval(); } catch (Exception e) { log.error("Problem evaluating script", e); } if (log.isDebugEnabled()) { log.debug("Result of script call: " + o); } // script didnt return anything we can use so try the wrapper if (null == o) { wrapper.eval(); } else { wrapper.eval(); o = ((Invocable) engine).invokeFunction("Wrapper", new Object[] { engine.get(funcName) }); if (log.isDebugEnabled()) { log.debug("Result of invokeFunction: " + o); } } return Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(), interfaces, new RhinoObjectInvocationHandler(engine, o)); } /** * InvocationHandler that invokes a Rhino script method. */ private static class RhinoObjectInvocationHandler implements InvocationHandler { private final ScriptEngine engine; private final Object instance; public RhinoObjectInvocationHandler(ScriptEngine engine, Object instance) { this.engine = engine; this.instance = instance; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object o = null; // ensure a set of args are available if (args == null || args.length == 0) { args = new Object[] { "" }; } String name = method.getName(); if (log.isDebugEnabled()) { log.debug("Calling: " + name); } try { Method apiMethod = null; Invocable invocable = (Invocable) engine; if (null == instance) { o = invocable.invokeFunction(name, args); } else { try { o = invocable.invokeMethod(instance, name, args); } catch (NoSuchMethodException nex) { log.debug("Method not found: " + name); try { // try to invoke it directly, this will work if the // function is in the engine context // ie. the script has been already evaluated o = invocable.invokeFunction(name, args); } catch (Exception ex) { log.debug("Function not found: " + name); Class[] interfaces = (Class[]) engine .get("interfaces"); for (Class clazz : interfaces) { // java6 style o = invocable.getInterface(engine .get((String) engine.get("className")), clazz); if (null != o) { log.debug("Interface return type: " + o.getClass().getName()); break; } } } } } if (log.isDebugEnabled()) { log.debug("Invocable result: " + o); } } catch (NoSuchMethodException nex) { log.warn("Method not found"); } catch (Throwable t) { log.warn("{}", t); } return o; } } /** * Uses a regex to get the first "function" name, this name is used to * create an instance of the javascript object. * * @param scriptSource * @return */ private static String getFunctionName(String scriptSource) { String ret = "undefined"; try { ret = scriptSource.replaceAll( "[\\S\\w\\s]*?function ([\\w]+)\\(\\)[\\S\\w\\s]+", "$1"); // if undefined then look for the first var if (ret.equals("undefined") || ret.length() > 64) { ret = scriptSource.replaceAll( "[\\S\\w\\s]*?var ([\\w]+)[\\S\\w\\s]+", "$1"); } } catch (PatternSyntaxException ex) { log.error("Syntax error in the regular expression"); } catch (IllegalArgumentException ex) { log .error("Syntax error in the replacement text (unescaped $ signs?)"); } catch (IndexOutOfBoundsException ex) { log.error("Non-existent backreference used the replacement text"); } log.debug("Got a function name: " + ret); return ret; } } red5-1.0~svn4374.orig/src/org/red5/server/script/rhino/RhinoScriptFactory.java0000644000175000017500000001201711616523204027121 0ustar drazzibdrazzib/* * Copyright 2002-2011 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.script.rhino; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scripting.ScriptCompilationException; import org.springframework.scripting.ScriptFactory; import org.springframework.scripting.ScriptSource; import org.springframework.util.Assert; /** * {@link org.springframework.scripting.ScriptFactory} implementation for a * Rhino / Javascript script. * *

* Typically used in combination with a * {@link org.springframework.scripting.support.ScriptFactoryPostProcessor}; * see the latter's * {@link org.springframework.scripting.support.ScriptFactoryPostProcessor Javadoc} * for a configuration example. * * @author Paul Gregoire * @since 0.6 * @see org.springframework.scripting.support.ScriptFactoryPostProcessor * @see RhinoScriptUtils */ public class RhinoScriptFactory implements ScriptFactory { static Logger log = LoggerFactory.getLogger(RhinoScriptFactory.class); private final String scriptSourceLocator; private final Class[] scriptInterfaces; private final Class extendedClass; public RhinoScriptFactory(String scriptSourceLocator) { Assert.hasText(scriptSourceLocator); this.scriptSourceLocator = scriptSourceLocator; this.scriptInterfaces = new Class[] {}; this.extendedClass = null; } public RhinoScriptFactory(String scriptSourceLocator, Class scriptInterface) { Assert.hasText(scriptSourceLocator); this.scriptSourceLocator = scriptSourceLocator; this.extendedClass = null; if (null == scriptInterface) { this.scriptInterfaces = new Class[] {}; } else { this.scriptInterfaces = new Class[] { scriptInterface }; } } /** * Create a new RhinoScriptFactory for the given script source. * * @param scriptSourceLocator * a locator that points to the source of the script. Interpreted * by the post-processor that actually creates the script. * @param scriptInterfaces * the Java interfaces that the scripted object is supposed to * implement * @throws IllegalArgumentException * if either of the supplied arguments is null; * or the supplied scriptSourceLocator argument * is composed wholly of whitespace; or if the supplied * scriptInterfaces argument array has no * elements */ public RhinoScriptFactory(String scriptSourceLocator, Class[] scriptInterfaces) { Assert.hasText(scriptSourceLocator); this.scriptSourceLocator = scriptSourceLocator; this.extendedClass = null; if (null == scriptInterfaces || scriptInterfaces.length < 1) { this.scriptInterfaces = new Class[] {}; } else { this.scriptInterfaces = scriptInterfaces; } } public RhinoScriptFactory(String scriptSourceLocator, Class[] scriptInterfaces, Class extendedClass) { Assert.hasText(scriptSourceLocator); Assert.notNull(extendedClass); this.scriptSourceLocator = scriptSourceLocator; this.extendedClass = extendedClass; if (null == scriptInterfaces || scriptInterfaces.length < 1) { this.scriptInterfaces = new Class[] {}; } else { this.scriptInterfaces = scriptInterfaces; } } /** {@inheritDoc} */ public String getScriptSourceLocator() { return this.scriptSourceLocator; } /** {@inheritDoc} */ public Class[] getScriptInterfaces() { return this.scriptInterfaces; } /** * Rhino scripts do not require a config interface. * * @return false always */ public boolean requiresConfigInterface() { return false; } /** * Load and parse the Rhino script via RhinoScriptUtils. * */ public Object getScriptedObject(ScriptSource actualScriptSource, Class[] actualInterfaces) throws IOException, ScriptCompilationException { log.debug("Getting scripted object..."); try { return RhinoScriptUtils.createRhinoObject(actualScriptSource .getScriptAsString(), actualInterfaces, extendedClass); } catch (Exception ex) { throw new ScriptCompilationException( "Could not compile Rhino script: " + actualScriptSource, ex); } } public Class getScriptedObjectType(ScriptSource src) throws IOException, ScriptCompilationException { return null; } public boolean requiresScriptedObjectRefresh(ScriptSource src) { return false; } } red5-1.0~svn4374.orig/src/org/red5/server/war/0000755000175000017500000000000011760512572020635 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/war/WarLoaderServlet.java0000644000175000017500000002000011747114732024716 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.war; import java.beans.Introspector; import java.io.File; import java.sql.Driver; import java.sql.DriverManager; import java.util.ArrayList; import java.util.Enumeration; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import org.red5.io.amf.Output; import org.red5.logging.Red5LoggerFactory; import org.red5.server.ClientRegistry; import org.red5.server.Context; import org.red5.server.MappingStrategy; import org.red5.server.Server; import org.red5.server.api.Red5; import org.red5.server.persistence.FilePersistenceThread; import org.red5.server.scope.GlobalScope; import org.red5.server.scope.ScopeResolver; import org.red5.server.scope.WebScope; import org.red5.server.service.ServiceInvoker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.web.context.ConfigurableWebApplicationContext; import org.springframework.web.context.ContextLoader; import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.WebApplicationContext; import ch.qos.logback.classic.LoggerContext; /** * Entry point from which the server config file is loaded while running within * a J2EE application container. * * This listener should be registered after Log4jConfigListener in web.xml, if * the latter is used. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class WarLoaderServlet extends ContextLoaderListener { // Initialize Logging public static Logger logger = Red5LoggerFactory.getLogger(WarLoaderServlet.class); private static ArrayList registeredContexts = new ArrayList(3); private ConfigurableWebApplicationContext applicationContext; private DefaultListableBeanFactory parentFactory; private static ServletContext servletContext; private ClientRegistry clientRegistry; private ServiceInvoker globalInvoker; private MappingStrategy globalStrategy; private ScopeResolver globalResolver; private GlobalScope global; private Server server; /** * Main entry point for the Red5 Server as a war */ // Notification that the web application is ready to process requests @Override public void contextInitialized(ServletContextEvent sce) { if (null != servletContext) { return; } System.setProperty("red5.deployment.type", "war"); servletContext = sce.getServletContext(); String prefix = servletContext.getRealPath("/"); if (System.getProperty("red5.webapp.root") == null) { File webapps = new File(prefix); System.setProperty("red5.webapp.root", webapps.getParent()); webapps = null; } long time = System.currentTimeMillis(); logger.info("{} WAR loader", Red5.VERSION); logger.debug("Path: {}", prefix); try { //use super to initialize super.contextInitialized(sce); //get the web context applicationContext = (ConfigurableWebApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); logger.debug("Root context path: {}", applicationContext.getServletContext().getContextPath()); ConfigurableBeanFactory factory = applicationContext.getBeanFactory(); // register default factory.registerSingleton("default.context", applicationContext); // get the main factory parentFactory = (DefaultListableBeanFactory) factory.getParentBeanFactory(); } catch (Throwable t) { logger.error("", t); } long startupIn = System.currentTimeMillis() - time; logger.info("Startup done in: {} ms", startupIn); } /* * Registers a subcontext with red5 */ public void registerSubContext(String webAppKey) { // get the sub contexts - servlet context ServletContext ctx = servletContext.getContext(webAppKey); if (ctx == null) { ctx = servletContext; } ContextLoader loader = new ContextLoader(); ConfigurableWebApplicationContext appCtx = (ConfigurableWebApplicationContext) loader.initWebApplicationContext(ctx); appCtx.setParent(applicationContext); appCtx.refresh(); ctx.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, appCtx); ConfigurableBeanFactory appFactory = appCtx.getBeanFactory(); logger.debug("About to grab Webcontext bean for {}", webAppKey); Context webContext = (Context) appCtx.getBean("web.context"); webContext.setCoreBeanFactory(parentFactory); webContext.setClientRegistry(clientRegistry); webContext.setServiceInvoker(globalInvoker); webContext.setScopeResolver(globalResolver); webContext.setMappingStrategy(globalStrategy); WebScope scope = (WebScope) appFactory.getBean("web.scope"); scope.setServer(server); scope.setParent(global); scope.register(); scope.start(); // register the context so we dont try to reinitialize it registeredContexts.add(ctx); } @Deprecated public ContextLoader getContextLoader() { return super.getContextLoader(); } /** * Clearing the in-memory configuration parameters, we will receive * notification that the servlet context is about to be shut down */ @Override public void contextDestroyed(ServletContextEvent sce) { synchronized (servletContext) { logger.info("Webapp shutdown"); // XXX Paul: grabbed this from // http://opensource.atlassian.com/confluence/spring/display/DISC/Memory+leak+-+classloader+won%27t+let+go // in hopes that we can clear all the issues with J2EE containers // during shutdown ServletContext ctx = null; try { ctx = sce.getServletContext(); // prepare spring for shutdown Introspector.flushCaches(); // dereg any drivers for (Enumeration e = DriverManager.getDrivers(); e.hasMoreElements();) { Driver driver = (Driver) e.nextElement(); if (driver.getClass().getClassLoader() == getClass().getClassLoader()) { DriverManager.deregisterDriver(driver); } } // shutdown the persistence thread FilePersistenceThread persistenceThread = FilePersistenceThread.getInstance(); if (persistenceThread != null) { persistenceThread.shutdown(); } // clear the AMF output cache Output.destroyCache(); // stop the logger try { ((LoggerContext) LoggerFactory.getILoggerFactory()).stop(); } catch (Exception e) { } // shutdown spring Object attr = ctx.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); if (attr != null) { // get web application context from the servlet context ConfigurableWebApplicationContext applicationContext = (ConfigurableWebApplicationContext) attr; ConfigurableBeanFactory factory = applicationContext.getBeanFactory(); // for (String scope : factory.getRegisteredScopeNames()) { // logger.debug("Registered scope: " + scope); // } try { for (String singleton : factory.getSingletonNames()) { logger.debug("Registered singleton: {}", singleton); factory.destroyScopedBean(singleton); } } catch (RuntimeException e) { } factory.destroySingletons(); applicationContext.close(); } } catch (Throwable e) { logger.warn("Exception {}", e); } finally { super.contextDestroyed(sce); if (ctx != null) { ctx.removeAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); } } } } } red5-1.0~svn4374.orig/src/org/red5/server/midi/0000755000175000017500000000000011760512571020765 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/server/midi/Test.java0000644000175000017500000000505311706617130022547 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.midi; import javax.sound.midi.MidiDevice; import javax.sound.midi.MidiMessage; import javax.sound.midi.MidiSystem; import javax.sound.midi.MidiUnavailableException; import javax.sound.midi.Receiver; import javax.sound.midi.MidiDevice.Info; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Test { // Initialize Logging protected static Logger log = LoggerFactory.getLogger(Test.class); public static void main(String[] args) throws Exception { @SuppressWarnings("unused") Test t = new Test(); } public static MidiDevice getMidiDevice(String name) { MidiDevice.Info[] info = MidiSystem.getMidiDeviceInfo(); for (Info element : info) { if (element.getName().equals(name)) { try { return MidiSystem.getMidiDevice(element); } catch (MidiUnavailableException e) { log.error("{}", e); } } } return null; } /** Constructs a new Test. * @throws Exception if it feels like it. */ public Test() throws Exception { String MIDI_NAME = "USB Uno MIDI In"; MidiDevice dev = getMidiDevice(MIDI_NAME); dev.open(); MyReceiver rec = new MyReceiver(); dev.getTransmitter().setReceiver(rec); Thread.sleep(20000); dev.close(); } public static class MyReceiver extends Object implements Receiver { /** {@inheritDoc} */ public void send(MidiMessage midi, long time) { byte[] msg = midi.getMessage(); int len = midi.getLength(); if (len <= 1) { return; } StringBuilder out = new StringBuilder("Status: "); out.append(msg[0]); out.append(" Data: ["); for (int i = 1; i < len; i++) { out.append(msg[i]); if (i == len - 1) { out.append(""); } else { out.append(','); } } out.append(']'); log.debug(out.toString()); } /** {@inheritDoc} */ public void close() { log.debug("Closing"); } } }red5-1.0~svn4374.orig/src/org/red5/server/midi/MidiPlayer.java0000644000175000017500000000462511706617130023673 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.server.midi; import java.io.File; import java.io.IOException; import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.MidiSystem; import javax.sound.midi.MidiUnavailableException; import javax.sound.midi.Sequencer; import org.red5.logging.Red5LoggerFactory; import org.slf4j.Logger; /** Plays a midi file provided on command line */ public class MidiPlayer { protected static Logger log = Red5LoggerFactory.getLogger(MidiPlayer.class); public static void main(String args[]) { // Argument check if (args.length == 0) { helpAndExit(); } String file = args[0]; if (!file.endsWith(".mid")) { helpAndExit(); } File midiFile = new File(file); if (!midiFile.exists() || midiFile.isDirectory() || !midiFile.canRead()) { helpAndExit(); } } public MidiPlayer(File midiFile) { // Play once try { Sequencer sequencer = MidiSystem.getSequencer(); sequencer.setSequence(MidiSystem.getSequence(midiFile)); sequencer.open(); sequencer.start(); /* while(true) { if(sequencer.isRunning()) { try { Thread.sleep(1000); // Check every second } catch(InterruptedException ignore) { break; } } else { break; } } // Close the MidiDevice & free resources sequencer.stop(); sequencer.close(); */ } catch (MidiUnavailableException mue) { log.error("Midi device unavailable!", mue); } catch (InvalidMidiDataException imde) { log.error("Invalid Midi data!", imde); } catch (IOException ioe) { log.error("I/O Error!", ioe); } } /** Provides help message and exits the program */ private static void helpAndExit() { log.error("Usage: java MidiPlayer midifile.mid"); //System.exit(1); } } red5-1.0~svn4374.orig/src/org/red5/server/midi/SharedMidiObject.java0000644000175000017500000000610511706617130024767 0ustar drazzibdrazzibpackage org.red5.server.midi; /* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.util.ArrayList; import java.util.List; import javax.sound.midi.MidiDevice; import javax.sound.midi.MidiMessage; import javax.sound.midi.MidiSystem; import javax.sound.midi.MidiUnavailableException; import javax.sound.midi.Receiver; import javax.sound.midi.MidiDevice.Info; import org.red5.server.api.so.ISharedObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SharedMidiObject { private static final Logger log = LoggerFactory.getLogger(SharedMidiObject.class); protected String deviceName; protected ISharedObject so; protected MidiDevice dev; public SharedMidiObject(String deviceName, ISharedObject so) { this.deviceName = deviceName; this.so = so; } public boolean connect() { try { dev = getMidiDevice(deviceName); if (dev == null) { log.error("Midi device not found: " + deviceName); return false; } if (!dev.isOpen()) { dev.open(); } dev.getTransmitter().setReceiver(new MidiReceiver()); return true; } catch (MidiUnavailableException e) { log.error("Error connecting to midi device", e); } return false; } public void close() { if (dev != null && dev.isOpen()) { dev.close(); } } public static MidiDevice getMidiDevice(String name) { MidiDevice.Info[] info = MidiSystem.getMidiDeviceInfo(); for (Info element : info) { if (element.getName().equals(name)) { try { return MidiSystem.getMidiDevice(element); } catch (MidiUnavailableException e) { log.error("{}", e); } } } return null; } public class MidiReceiver extends Object implements Receiver { /** {@inheritDoc} */ public void send(MidiMessage midi, long time) { byte[] msg = midi.getMessage(); int len = midi.getLength(); if (len <= 1) { return; } List list = new ArrayList(3); list.add(time); list.add(len); list.add(msg); so.beginUpdate(); so.sendMessage("midi", list); so.endUpdate(); StringBuilder out = new StringBuilder("Midi >> Status: "); out.append(msg[0]); out.append(" Data: ["); for (int i = 1; i < len; i++) { out.append(msg[i]); if (i == len - 1) { out.append(""); } else { out.append(','); } } out.append(']'); log.debug(out.toString()); } /** {@inheritDoc} */ public void close() { log.debug("Midi device closed"); } } } red5-1.0~svn4374.orig/src/org/red5/logging/0000755000175000017500000000000011760512574020166 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/red5/logging/Red5LoggerFactory.java0000644000175000017500000001427111747114732024324 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.logging; import java.lang.reflect.Method; import org.red5.server.adapter.StatefulScopeWrappingAdapter; import org.red5.server.api.scope.IScope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.impl.StaticLoggerBinder; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.selector.ContextSelector; /** * LoggerFactory to simplify requests for Logger instances within * Red5 applications. This class is expected to be run only once per * logger request and is optimized as such. * * @author Paul Gregoire (mondain@gmail.com) */ public class Red5LoggerFactory { @SuppressWarnings({ "unchecked", "rawtypes" }) public static Logger getLogger(Class clazz) { //determine the red5 app name or servlet context name String contextName = null; //if the incoming class extends StatefulScopeWrappingAdapter we lookup the context //by scope name boolean scopeAware = StatefulScopeWrappingAdapter.class.isAssignableFrom(clazz); //System.out.printf("Wrapper - %s\n", StatefulScopeWrappingAdapter.class.isAssignableFrom(clazz)); if (scopeAware) { try { Class wrapper = null; if ((wrapper = clazz.asSubclass(StatefulScopeWrappingAdapter.class)) != null) { Method getScope = wrapper.getMethod("getScope", new Class[0]); //NPE will occur here if the scope is not yet set on the application adapter IScope scope = (IScope) getScope.invoke(null, new Object[0]); contextName = scope.getName(); } } catch (Exception cce) { //cclog.warn("Exception {}", e); } } else { //route the Launcher entries to the correct context String[] parts = Thread.currentThread().getName().split("Launcher:/"); if (parts.length > 1) { contextName = parts[1]; } } /* TODO: For a future day, the context or application will be determined //get a reference to our caller Class caller = Reflection.getCallerClass(2); //System.err.printf("Caller class: %s classloader: %s\n", caller, caller.getClassLoader()); try { //check to see if we've been called by a servlet Class sub = caller.asSubclass(Servlet.class); //System.err.println("Caller is a Servlet"); //Method[] methods = caller.getMethods(); //for (Method meth : methods) { // System.err.printf("Method: %s\n", meth.getName()); //} Method getContext = caller.getMethod("getServletContext", new Class[0]); //System.err.printf("got context method - %s\n", getContext); ServletContext context = (ServletContext) getContext.invoke(caller, null); System.err.printf("invoked context\n"); contextName = context.getServletContextName(); //System.err.printf("Servlet context name: %s\n", contextName); Method getContextName = context.getClass().getMethod("getServletContextName", new Class[0]); System.err.printf("got context name\n"); Object ctxName = getContextName.invoke(null, new Object[0]); System.err.printf("Servlet context result: %s\n", ctxName); if (ctxName != null && ctxName instanceof String) { contextName = ctxName.toString(); } } catch (Exception ex) { //ex.printStackTrace(); } */ return getLogger(clazz, contextName); } @SuppressWarnings({ "rawtypes" }) public static Logger getLogger(Class clazz, String contextName) { Logger logger = null; try { //check for logback Class cs = Class.forName("ch.qos.logback.classic.selector.ContextSelector"); //trigger an exception if the class doesn't actually exist cs.getDeclaredMethods(); // get the class for static binding cs = Class.forName("org.slf4j.impl.StaticLoggerBinder"); // get its declared methods Method[] methods = cs.getDeclaredMethods(); for (Method method : methods) { //ensure method exists if (method.getName().equals("getContextSelector")) { //System.out.println("Logger context selector method found"); //get the context selector StaticLoggerBinder binder = StaticLoggerBinder.getSingleton(); Method m1 = binder.getClass().getMethod("getContextSelector", (Class[]) null); ContextSelector selector = (ContextSelector) m1.invoke(binder, (Object[]) null); //get the context for the given context name or default if null LoggerContext ctx = null; if (contextName != null && contextName.length() > 0) { ctx = selector.getLoggerContext(contextName); } // and if we get here, fall back to the default context if (ctx == null) { ctx = selector.getLoggerContext(); } //debug //StatusPrinter.print(ctx); //get the logger from the context or default context logger = ((ctx != null) ? ctx.getLogger(clazz) : selector.getDefaultLoggerContext().getLogger(clazz)); break; } } } catch (Exception e) { //no logback, use whatever logger is in-place System.err.printf("Exception %s", e.getMessage()); } if (logger == null) { //no logback, use whatever logger is in-place logger = LoggerFactory.getLogger(clazz); } return logger; } public static ContextSelector getContextSelector() { ContextSelector selector = null; StaticLoggerBinder binder = StaticLoggerBinder.getSingleton(); try { Method m1 = binder.getClass().getMethod("getContextSelector", (Class[]) null); selector = (ContextSelector) m1.invoke(binder, (Object[]) null); } catch (Exception e) { System.err.printf("Exception %s", e.getMessage()); } return selector; } }red5-1.0~svn4374.orig/src/org/red5/logging/ContextLoggingListener.java0000644000175000017500000000633711706617130025475 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.logging; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import org.slf4j.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.selector.ContextSelector; /** * A servlet context listener that puts this contexts LoggerContext * into a static map of logger contexts within an overall singleton * log context selector. * * To use it, add the following line to a web.xml file *
	<listener>
		<listener-class>org.red5.logging.ContextLoggingListener</listener-class>
	</listener>
 *
* * @author Paul Gregoire (mondain@gmail.com) */ public class ContextLoggingListener implements ServletContextListener { public void contextDestroyed(ServletContextEvent event) { System.out.println("Context destroying..."); String contextName = pathToName(event); //System.out.printf("About to detach context named %s\n", contextName); ContextSelector selector = Red5LoggerFactory.getContextSelector(); LoggerContext context = selector.detachLoggerContext(contextName); if (context != null) { Logger logger = context.getLogger(Logger.ROOT_LOGGER_NAME); logger.debug("Shutting down context {}", contextName); context.reset(); } else { System.err.printf("No context named %s was found", contextName); } } public void contextInitialized(ServletContextEvent event) { System.out.println("Context init..."); String contextName = pathToName(event); System.out.printf("Logger name for context: %s\n", contextName); LoggingContextSelector selector = null; try { selector = (LoggingContextSelector) Red5LoggerFactory.getContextSelector(); //set this contexts name selector.setContextName(contextName); LoggerContext context = selector.getLoggerContext(); if (context != null) { Logger logger = context.getLogger(Logger.ROOT_LOGGER_NAME); logger.debug("Starting up context {}", contextName); } else { System.err.printf("No context named %s was found", contextName); } } catch (Exception e) { System.err.printf("LoggingContextSelector is not the correct type", e); } finally { //reset the name if (selector != null) { selector.setContextName(null); } } } private String pathToName(ServletContextEvent event) { String contextName = event.getServletContext().getContextPath().replaceAll("/", ""); if ("".equals(contextName)) { contextName = "root"; } return contextName; } } red5-1.0~svn4374.orig/src/org/red5/logging/DerbyLogInterceptor.java0000644000175000017500000000400111706617130024744 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.logging; import java.io.IOException; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DerbyLogInterceptor { protected static Logger log = LoggerFactory.getLogger(DerbyLogInterceptor.class); private static ThreadLocal local = new ThreadLocal(); public static OutputStream handleDerbyLogFile(){ return new OutputStream() { @Override public void write(byte[] b) throws IOException { log.info("Derby log: {}", new String(b)); } @Override public void write(int i) throws IOException { StringBuilder sb = local.get(); if (sb == null) { sb = new StringBuilder(); } //look for LF if (i == 10) { log.info("Derby log: {}", sb.toString()); sb.delete(0, sb.length() - 1); } else { log.trace("Derby log: {}", i); sb.append(new String(intToDWord(i))); } local.set(sb); } }; } private static byte[] intToDWord(int i) { byte[] dword = new byte[4]; dword[0] = (byte) (i & 0x00FF); dword[1] = (byte) ((i >> 8) & 0x000000FF); dword[2] = (byte) ((i >> 16) & 0x000000FF); dword[3] = (byte) ((i >> 24) & 0x000000FF); return dword; } } red5-1.0~svn4374.orig/src/org/red5/logging/LoggingContextSelector.java0000644000175000017500000001367711706617130025475 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.logging; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.classic.selector.ContextSelector; import ch.qos.logback.classic.util.ContextInitializer; import ch.qos.logback.core.joran.spi.JoranException; import ch.qos.logback.core.util.Loader; import ch.qos.logback.core.util.StatusPrinter; /** * A class that allows the LoggerFactory to access an web context based LoggerContext. * * Add this java option -Dlogback.ContextSelector=org.red5.logging.LoggingContextSelector * * @author Paul Gregoire (mondain@gmail.com) */ public class LoggingContextSelector implements ContextSelector { private static final ConcurrentMap contextMap = new ConcurrentHashMap(); private final ThreadLocal threadLocal = new ThreadLocal(); private final LoggerContext defaultContext; private volatile String contextName; private volatile String contextConfigFile; public LoggingContextSelector(LoggerContext context) { System.out.printf("Setting default logging context: %s\n", context.getName()); defaultContext = context; } public LoggerContext getLoggerContext() { //System.out.println("getLoggerContext request"); // First check if ThreadLocal has been set already LoggerContext lc = threadLocal.get(); if (lc != null) { //System.out.printf("Thread local found: %s\n", lc.getName()); return lc; } if (contextName == null) { //System.out.println("Context name was null, returning default"); // We return the default context return defaultContext; } else { // Let's see if we already know such a context LoggerContext loggerContext = contextMap.get(contextName); //System.out.printf("Logger context for %s is %s\n", contextName, loggerContext); if (loggerContext == null) { // We have to create a new LoggerContext loggerContext = new LoggerContext(); loggerContext.setName(contextName); // allow override using logbacks system prop String overrideProperty = System.getProperty("logback.configurationFile"); if (overrideProperty == null) { contextConfigFile = String.format("logback-%s.xml", contextName); } else { contextConfigFile = String.format(overrideProperty, contextName); } System.out.printf("Context logger config file: %s\n", contextConfigFile); ClassLoader classloader = Thread.currentThread().getContextClassLoader(); //System.out.printf("Thread context cl: %s\n", classloader); //ClassLoader classloader2 = Loader.class.getClassLoader(); //System.out.printf("Loader tcl: %s\n", classloader2); //URL url = Loader.getResourceBySelfClassLoader(contextConfigFile); URL url = Loader.getResource(contextConfigFile, classloader); if (url != null) { try { JoranConfigurator configurator = new JoranConfigurator(); loggerContext.reset(); configurator.setContext(loggerContext); configurator.doConfigure(url); } catch (JoranException e) { StatusPrinter.print(loggerContext); } } else { try { ContextInitializer ctxInit = new ContextInitializer(loggerContext); ctxInit.autoConfig(); } catch (JoranException je) { StatusPrinter.print(loggerContext); } } System.out.printf("Adding logger context: %s to map for context: %s\n", loggerContext.getName(), contextName); contextMap.put(contextName, loggerContext); } return loggerContext; } } public LoggerContext getLoggerContext(String name) { //System.out.printf("getLoggerContext request for %s\n", name); //System.out.printf("Context is in map: %s\n", contextMap.containsKey(name)); return contextMap.get(name); } public LoggerContext getDefaultLoggerContext() { return defaultContext; } public void attachLoggerContext(String contextName, LoggerContext loggerContext) { contextMap.put(contextName, loggerContext); } public LoggerContext detachLoggerContext(String loggerContextName) { return contextMap.remove(loggerContextName); } public List getContextNames() { List list = new ArrayList(); list.addAll(contextMap.keySet()); return list; } public void setContextName(String contextName) { this.contextName = contextName; } public void setContextConfigFile(String contextConfigFile) { this.contextConfigFile = contextConfigFile; } /** * Returns the number of managed contexts Used for testing purposes * * @return the number of managed contexts */ public int getCount() { return contextMap.size(); } /** * These methods are used by the LoggerContextFilter. * * They provide a way to tell the selector which context to use, thus saving * the cost of a JNDI call at each new request. * * @param context logging context */ public void setLocalContext(LoggerContext context) { threadLocal.set(context); } public void removeLocalContext() { threadLocal.remove(); } } red5-1.0~svn4374.orig/src/org/red5/logging/LoggerContextFilter.java0000644000175000017500000000576611706617130024773 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.logging; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.slf4j.LoggerFactory; import ch.qos.logback.classic.LoggerContext; /** * A servlet filter that puts this contexts LoggerContext into a Threadlocal variable. * * It removes it after the request is processed. * * To use it, add the following lines to a web.xml file *
	<filter>
		<filter-name>LoggerContextFilter</filter-name>
		<filter-class>org.red5.logging.LoggerContextFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>LoggerContextFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
 *
* * @author Paul Gregoire (mondain@gmail.com) */ public class LoggerContextFilter implements Filter { private String contextName; public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //System.out.printf("Context name: %s\n", contextName); LoggingContextSelector selector = (LoggingContextSelector) Red5LoggerFactory.getContextSelector(); //System.out.printf("Context select type: %s\n", selector.getClass().getName()); LoggerContext ctx = selector.getLoggerContext(contextName); //load default logger context if its null if (ctx == null) { //System.out.println("Logger context was null, getting default"); ctx = (LoggerContext) LoggerFactory.getILoggerFactory(); } //evaluate context name against logger context name if (!contextName.equals(ctx.getName())) { System.err.printf("Logger context name and context name dont match (%s != %s)\n", contextName, ctx.getName()); } //System.out.printf("Logger context name: %s\n", ctx.getName()); selector.setLocalContext(ctx); try { chain.doFilter(request, response); } finally { selector.removeLocalContext(); } } public void init(FilterConfig config) throws ServletException { contextName = config.getServletContext().getContextPath().replaceAll("/", ""); } } red5-1.0~svn4374.orig/src/org/red5/logging/W3CAppender.java0000644000175000017500000002331011706617130023075 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.red5.logging; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.red5.server.api.Red5; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.core.FileAppender; import ch.qos.logback.core.status.ErrorStatus; /** * Logback appender for the Extended W3C format. * * @see "http://www.w3.org/TR/WD-logfile.html" * @author Paul Gregoire (mondain@gmail.com) */ public class W3CAppender extends FileAppender { /** #Software: Red5 0.7.1 #Version: 1.0 #Date: 1998-11-19 22:48:39 #Fields: date time c-ip cs-username s-ip cs-method */ //whether or not the header has been written private static boolean headerWritten; //events that are to be logged private static String events; //linked list to preserve order private static List eventsList = new ArrayList(); //fields that are to be logged private static String fields; //linked list to preserve order private static LinkedList fieldList = new LinkedList(); public W3CAppender() { setPrudent(true); } public void setEvents(String events) { W3CAppender.events = events; //make a list out of the event names String[] arr = events.split(";"); for (String s : arr) { eventsList.add(s); } } public String getEvents() { return events; } public void setFields(String fields) { W3CAppender.fields = fields; //make a list out of the field names String[] arr = fields.split(";"); for (String s : arr) { fieldList.add(s); } } public String getFields() { return fields; } @Override public synchronized void doAppend(LoggingEvent event) { //get the log message String message = event.getFormattedMessage(); //look for w3c prefix if (!message.startsWith("W3C")) { return; } // http://logback.qos.ch/apidocs/ch/qos/logback/classic/spi/LoggingEvent.html StringBuilder sbuf = new StringBuilder(128); //see if header has been written if (!headerWritten) { //build the header StringBuilder sb = new StringBuilder("#Software: "); sb.append(Red5.VERSION); sb.append("\n#Version: 1.0"); sb.append("\n#Date: "); sb.append(new Date()); sb.append("\n#Fields: "); for (String field : fields.split(";")) { sb.append(field); sb.append(' '); } sb.append('\n'); //String header = sb.toString(); //System.out.print(header); sbuf.append(sb.toString()); headerWritten = true; sb = null; } //break the message into pieces String[] arr = message.split(" "); //create a map Map elements = new HashMap(arr.length); int i = 0; for (String s : arr) { if ((i = s.indexOf(':')) != -1) { String key = s.substring(0, i); String value = s.substring(i + 1); //System.out.println("Key: " + key + " Value: " + value); elements.put(key, value); } } //Events Categories //connect-pending session //connect session //disconnect session //publish stream //unpublish stream //play stream //pause stream //unpause stream //seek stream //stop stream //record stream //recordstop stream //server-start server //server-stop server //vhost-start vhost //vhost-stop vhost //app-start application //app-stop application //filter based on event type - asterik allows all events if (!events.equals("*")) { if (!eventsList.contains(elements.get("x-event"))) { //System.err.println("Filtered out - event: "+elements.get("x-event")+" event list: "+eventsList); elements.clear(); elements = null; sbuf = null; return; } } //x-category event category //x-event type of event //date date at which the event occurred //time time at which the event occurred //tz time zone information //x-ctx event dependant context information //s-ip ip address[es] of the server //x-pid server process id //x-cpu-load cpu load //x-mem-load memory load (as reported in getServerStats) //x-adaptor adaptor name //x-vhost vhost name //x-app application name //x-appinst application instance name //x-duration duration of an event/session //x-status status code //c-ip client ip address //c-proto connection protocol - rtmp or rtmpt //s-uri uri of the fms application //cs-uri-stem stem of s-uri //cs-uri-query query portion of s-uri //c-referrer uri of the referrer //c-user-agent user agent //c-client-id client id //cs-bytes bytes transferred from client to server //sc-bytes bytes transferred from server to client //c-connect-type type of connection received by the server //x-sname stream name //x-sname-query query portion of stream uri //x-suri-query same as x-sname-query //x-suri-stem cs-uri-stem + x-sname + x-file-ext //x-suri x-suri-stem + x-suri-query //x-file-name full file path of recorded stream //x-file-ext stream type (flv or mp3) //x-file-size stream size in bytes //x-file-length stream length in seconds //x-spos stream position //cs-stream-bytes stream bytes transferred from client to server //sc-stream-bytes stream bytes transferred from server to client //x-service-name name of the service providing the connection //x-sc-qos-bytes bytes transferred from server to client for quality of service //x-comment comments //we may need date and/or time Calendar cal = GregorianCalendar.getInstance(); cal.clear(); cal.setTimeInMillis(event.getTimeStamp()); //loop through the field names and grab the values from the map //fields without a value get a tab character as a place holder if //their value is not available to the server for (String field : fieldList) { String value = elements.get(field); if (value == null) { if ("date".equals(field)) { sbuf.append(cal.get(Calendar.MONTH) + 1); sbuf.append('/'); sbuf.append(cal.get(Calendar.DAY_OF_MONTH)); sbuf.append('/'); sbuf.append(cal.get(Calendar.YEAR)); } else if ("time".equals(field)) { sbuf.append(cal.get(Calendar.HOUR_OF_DAY)); sbuf.append(':'); int min = cal.get(Calendar.MINUTE); if (min < 10) { sbuf.append('0'); sbuf.append(min); } else { sbuf.append(min); } } else if ("s-ip".equals(field)) { //where should we grab the server ip from? sbuf.append("127.0.0.1"); } else if ("x-pid".equals(field)) { //should we pass thread name? sbuf.append(event.getThreadName()); } else { sbuf.append('\t'); } } else { sbuf.append(value); } //space padded sbuf.append(' '); } sbuf.append('\n'); //System.out.println(sbuf.toString()); try { //switch out the message event.setMessage(sbuf.toString()); //write it writeOut(event); } catch (IOException ioe) { addStatus(new ErrorStatus("IO failure in appender", this, ioe)); } } } red5-1.0~svn4374.orig/src/org/slf4j/0000755000175000017500000000000011760512575016724 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/slf4j/impl/0000755000175000017500000000000011760512575017665 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/org/slf4j/impl/StaticLoggerBinder.java0000644000175000017500000000766311706617130024250 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.slf4j.impl; import org.slf4j.ILoggerFactory; import org.slf4j.LoggerFactory; import org.slf4j.helpers.Util; import org.slf4j.spi.LoggerFactoryBinder; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.selector.ContextSelector; import ch.qos.logback.classic.util.ContextInitializer; import ch.qos.logback.classic.util.ContextSelectorStaticBinder; import ch.qos.logback.core.CoreConstants; import ch.qos.logback.core.joran.spi.JoranException; import ch.qos.logback.core.util.StatusPrinter; /** * The binding of {@link LoggerFactory} class with an actual instance of * {@link ILoggerFactory} is performed using information returned by this class. * Modified for use in Red5. * * @author Ceki * Gülcü * @author Paul Gregoire */ public class StaticLoggerBinder implements LoggerFactoryBinder, LoggerContextSelectorProvider { /** * Declare the version of the SLF4J API this implementation is compiled * against. The value of this field is usually modified with each release. */ // to avoid constant folding by the compiler, this field must *not* be final public static String REQUESTED_API_VERSION = "1.6"; // !final final static String NULL_CS_URL = CoreConstants.CODES_URL + "#null_CS"; /** * The unique instance of this class. */ private static StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); private static Object KEY = new Object(); static { SINGLETON.init(); } private boolean initialized = false; private LoggerContext defaultLoggerContext = new LoggerContext(); private final ContextSelectorStaticBinder contextSelectorBinder = ContextSelectorStaticBinder.getSingleton(); private StaticLoggerBinder() { defaultLoggerContext.setName(CoreConstants.DEFAULT_CONTEXT_NAME); } public static StaticLoggerBinder getSingleton() { return SINGLETON; } /** * Package access for testing purposes. */ static void reset() { SINGLETON = new StaticLoggerBinder(); SINGLETON.init(); } /** * Package access for testing purposes. */ void init() { try { try { new ContextInitializer(defaultLoggerContext).autoConfig(); } catch (JoranException je) { Util.report("Failed to auto configure default logger context", je); } StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext); contextSelectorBinder.init(defaultLoggerContext, KEY); initialized = true; } catch (Throwable t) { // we should never get here Util.report("Failed to instantiate [" + LoggerContext.class.getName() + "]", t); } } public ILoggerFactory getLoggerFactory() { if (!initialized) { return defaultLoggerContext; } if (contextSelectorBinder.getContextSelector() == null) { throw new IllegalStateException("contextSelector cannot be null. See also " + NULL_CS_URL); } return contextSelectorBinder.getContextSelector().getLoggerContext(); } public String getLoggerFactoryClassStr() { return contextSelectorBinder.getContextSelector().getClass().getName(); } public ContextSelector getContextSelector() { return contextSelectorBinder.getContextSelector(); } } red5-1.0~svn4374.orig/src/org/slf4j/impl/LoggerContextSelectorProvider.java0000644000175000017500000000200511706617130026516 0ustar drazzibdrazzib/* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright 2006-2012 by respective authors (see below). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.slf4j.impl; import ch.qos.logback.classic.selector.ContextSelector; /** * Interface to provide a ContextSelector. * * @author Paul Gregoire (mondain@gmail.com) */ public interface LoggerContextSelectorProvider { public ContextSelector getContextSelector(); } red5-1.0~svn4374.orig/src/conf/0000755000175000017500000000000011760512571016034 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/conf/red5.policy0000644000175000017500000003064411274232432020116 0ustar drazzibdrazzib// ============================================================================ // red5.policy - Security Policy Permissions for Red5 // // This file contains a default set of security policies to be enforced (by the // JVM) In addition to the permissions granted here, the following additional permissions are // granted to the codebase specific to each web application: // // ============================================================================ // ========== SYSTEM CODE PERMISSIONS ========================================= // These permissions apply to javac grant codeBase "file:${java.home}/lib/-" { permission java.security.AllPermission; }; // These permissions apply to all shared system extensions grant codeBase "file:${java.home}/jre/lib/ext/-" { permission java.security.AllPermission; }; // These permissions apply to javac when ${java.home] points at $JAVA_HOME/jre grant codeBase "file:${java.home}/../lib/-" { permission java.security.AllPermission; }; // These permissions apply to all shared system extensions when // ${java.home} points at $JAVA_HOME/jre grant codeBase "file:${java.home}/lib/ext/-" { permission java.security.AllPermission; }; // ========== RED5 CODE PERMISSIONS ======================================= // These permissions apply to the main code grant codeBase "file:boot.jar" { permission java.security.AllPermission; }; grant codeBase "file:red5.jar" { permission java.security.AllPermission; }; // These permissions apply to the classes // and those that are shared across all class loaders // located in the "common" directory grant codeBase "file:lib/-" { permission java.security.AllPermission; }; grant codeBase "file:plugins/-" { permission java.security.AllPermission; }; grant principal javax.management.remote.JMXPrincipal "red5user" { permission java.security.AllPermission; }; grant principal javax.management.remote.JMXPrincipal "guest" { permission javax.management.MBeanPermission "*", "queryNames"; permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.*"; }; //required for the Admin plugin grant codeBase "file:plugins/adminplugin.jar" { permission java.lang.RuntimePermission "getenv.DERBY_HOME"; permission java.util.PropertyPermission "derby.*", "read"; permission java.io.FilePermission "${derby.system.home}","read"; permission java.io.FilePermission "${derby.system.home}${/}*", "read,write,delete"; permission java.io.FilePermission "${user.dir}${/}-", "read,write,delete"; permission java.io.FilePermission "${derby.system.home}${/}Admin${/}-", "read,write,delete"; }; //required for the Admin plugin when using derby db grant codeBase "file:plugins/derby-10.5.3.0.jar" { permission java.lang.RuntimePermission "createClassLoader"; permission java.util.PropertyPermission "derby.*", "read"; permission java.io.FilePermission "${derby.system.home}","read"; permission java.io.FilePermission "${derby.system.home}${/}*", "read,write,delete"; permission java.io.FilePermission "${user.dir}${/}-", "read,write,delete"; permission java.io.FilePermission "${derby.system.home}${/}Admin${/}-", "read,write,delete"; permission java.util.PropertyPermission "derby.storage.jvmInstanceId", "write"; }; // ========== APPLICATION PERMISSIONS ===================================== // These permissions are granted by default to all applications // In addition, an application will be given a read FilePermission // and JndiPermission for all files and directories in its document root. grant { //Red5 specific properties permission java.util.PropertyPermission "red5.root", "read,write"; permission java.util.PropertyPermission "red5.lib_root", "read,write"; permission java.util.PropertyPermission "red5.config_root", "read,write"; permission java.util.PropertyPermission "red5.plugins_root", "read,write"; permission java.util.PropertyPermission "red5.deployment.type", "read,write"; permission java.util.PropertyPermission "logback.ContextSelector", "read"; permission java.util.PropertyPermission "sun.lang.ClassLoader.allowArraySyntax", "write"; permission java.util.PropertyPermission "user.dir", "read"; permission java.util.PropertyPermission "user.home", "read"; permission java.io.FilePermission "${user.home}", "read"; permission javax.management.MBeanPermission "*", "invoke"; permission javax.management.MBeanPermission "*", "removeNotificationListener"; permission javax.management.MBeanPermission "*", "registerMBean"; permission javax.management.MBeanPermission "*", "unregisterMBean"; permission javax.management.MBeanPermission "*", "queryNames"; permission java.lang.RuntimePermission "getenv.RED5_HOME"; permission java.lang.RuntimePermission "exitVM"; permission java.lang.RuntimePermission "loadLibrary"; permission java.lang.RuntimePermission "getClassLoader"; permission java.lang.RuntimePermission "setContextClassLoader"; //specifically so that tomcat can be shutdown permission java.lang.RuntimePermission "modifyThread"; permission java.util.PropertyPermission "java.io.tmpdir", "read,write"; permission java.io.FilePermission "${java.io.tmpdir}", "read,write,delete"; permission javax.security.auth.AuthPermission "doAsPrivileged"; permission java.net.SocketPermission "127.0.0.1:9999", "connect,resolve"; permission java.net.SocketPermission "red5.googlecode.com:80", "connect,resolve"; permission java.net.SocketPermission "www.springframework.org:80", "connect,resolve"; permission java.io.FilePermission "file:red5.jar", "read"; permission java.io.FilePermission "file:conf/red5.properties", "read"; permission java.io.FilePermission "file:webapps/installer/WEB-INF/cache", "read,write"; //permission java.io.FilePermission "file:C:/red5/work/red5Engine/0.0.0.0/oflaDemo/loader", "read,write"; // Required for JNDI lookup of named JDBC DataSource's and // javamail named MimePart DataSource used to send mail permission java.util.PropertyPermission "java.home", "read"; permission java.util.PropertyPermission "java.naming.*", "read"; permission java.util.PropertyPermission "javax.sql.*", "read"; // OS Specific properties to allow read access permission java.util.PropertyPermission "os.name", "read"; permission java.util.PropertyPermission "os.version", "read"; permission java.util.PropertyPermission "os.arch", "read"; permission java.util.PropertyPermission "file.separator", "read"; permission java.util.PropertyPermission "path.separator", "read"; permission java.util.PropertyPermission "line.separator", "read"; // JVM properties to allow read access permission java.util.PropertyPermission "java.version", "read"; permission java.util.PropertyPermission "java.vendor", "read"; permission java.util.PropertyPermission "java.vendor.url", "read"; permission java.util.PropertyPermission "java.class.version", "read"; permission java.util.PropertyPermission "java.specification.version", "read"; permission java.util.PropertyPermission "java.specification.vendor", "read"; permission java.util.PropertyPermission "java.specification.name", "read"; permission java.util.PropertyPermission "java.vm.specification.version", "read"; permission java.util.PropertyPermission "java.vm.specification.vendor", "read"; permission java.util.PropertyPermission "java.vm.specification.name", "read"; permission java.util.PropertyPermission "java.vm.version", "read"; permission java.util.PropertyPermission "java.vm.vendor", "read"; permission java.util.PropertyPermission "java.vm.name", "read"; permission java.util.PropertyPermission "java.security.debug", "read"; permission java.util.PropertyPermission "java.security.policy", "read"; // Required for OpenJMX permission java.lang.RuntimePermission "getAttribute"; // Required by MX4J implementation permission javax.security.auth.AuthPermission "doAsPrivileged"; // Allow read of JAXP compliant XML parser debug permission java.util.PropertyPermission "jaxp.debug", "read"; // Precompiled JSPs need access to this package. permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.startup"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.startup.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.core"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.core.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.connector"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.connector.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.security"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.security.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.session"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.session.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.loader"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.loader.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.util.modeler"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.util.modeler.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.misc"; permission java.lang.RuntimePermission "accessClassInPackage.sun.misc.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect"; permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.server"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.server.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.tcp"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.tcp.*"; }; // The permissions granted to the balancer WEB-INF/classes directory //grant codeBase "file:${catalina.home}/webapps/balancer/WEB-INF/classes/-" { // permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.util.digester"; // permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.util.digester.*"; //}; // You can assign additional permissions to particular web applications by // adding additional "grant" entries here, based on the code base for that // application, /WEB-INF/classes/, or /WEB-INF/lib/ jar files. // // Different permissions can be granted to JSP pages, classes loaded from // the /WEB-INF/classes/ directory, all jar files in the /WEB-INF/lib/ // directory, or even to individual jar files in the /WEB-INF/lib/ directory. // // For instance, assume that the standard "examples" application // included a JDBC driver that needed to establish a network connection to the // corresponding database and used the scrape taglib to get the weather from // the NOAA web server. You might create a "grant" entries like this: // // The permissions granted to the context root directory apply to JSP pages. // grant codeBase "file:${red5.home}/webapps/examples/-" { // permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect"; // permission java.net.SocketPermission "*.noaa.gov:80", "connect"; // }; // // The permissions granted to the context WEB-INF/classes directory // grant codeBase "file:${red5.home}/webapps/examples/WEB-INF/classes/-" { // }; // // The permission granted to your JDBC driver // grant codeBase "jar:file:${red5.home}/webapps/examples/WEB-INF/lib/driver.jar!/-" { // permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect"; // }; // The permission granted to the scrape taglib // grant codeBase "jar:file:${red5.home}/webapps/examples/WEB-INF/lib/scrape.jar!/-" { // permission java.net.SocketPermission "*.noaa.gov:80", "connect"; // }; red5-1.0~svn4374.orig/src/conf/jee-container.xml0000644000175000017500000001677711755553132021325 0ustar drazzibdrazzib ${http.port} ${https.port} false true ${http.URIEncoding} red5-1.0~svn4374.orig/src/conf/red5.properties0000644000175000017500000000371211754545067021025 0ustar drazzibdrazzib# Socket policy policy.host=0.0.0.0 policy.port=843 # HTTP http.host=0.0.0.0 http.port=5080 https.port=5443 http.URIEncoding=UTF-8 http.max_keep_alive_requests=-1 http.max_threads=20 http.acceptor_thread_count=10 http.processor_cache=20 # RTMP rtmp.host=0.0.0.0 rtmp.port=1935 rtmp.io_threads=16 rtmp.send_buffer_size=271360 rtmp.receive_buffer_size=65536 rtmp.ping_interval=1000 rtmp.max_inactivity=60000 rtmp.max_handshake_time=5000 rtmp.tcp_nodelay=true rtmp.default_server_bandwidth=10000000 rtmp.default_client_bandwidth=10000000 rtmp.client_bandwidth_limit_type=2 rtmp.bandwidth_detection=true rtmp.encoder_base_tolerance=5000 rtmp.encoder_drop_live_future=false # RTMPS rtmps.host=0.0.0.0 rtmps.port=8443 rtmps.ping_interval=5000 rtmps.max_inactivity=60000 rtmps.max_keep_alive_requests=-1 rtmps.max_threads=20 rtmps.acceptor_thread_count=2 rtmps.processor_cache=20 # RTMPS Keystore Password rtmps.keystorepass=password # RTMPT rtmpt.host=0.0.0.0 rtmpt.port=8088 rtmpt.ping_interval=5000 rtmpt.max_inactivity=60000 rtmpt.max_handshake_time=5000 rtmpt.max_keep_alive_requests=-1 rtmpt.max_threads=20 rtmpt.acceptor_thread_count=2 rtmpt.processor_cache=20 rtmpt.encoder_base_tolerance=5000 rtmpt.encoder_drop_live_future=true rtmpt.target_reponse_size=8192 # Debug proxy (needs to be activated in red5-core.xml) proxy.source_host=127.0.0.1 proxy.source_port=1936 proxy.destination_host=127.0.0.1 proxy.destination_port=1935 # JMX jmx.rmi.host=localhost jmx.rmi.port=9999 jmx.rmi.port.remoteobjects= jmx.keystorepass=password jmx.mina.monitor.enable=true jmx.mina.poll.interval=1000 jmx.registry.create=true jmx.reuse.existing.server=true # Server properties notifier.threads=4 keyframe.cache.entry.max=500 stream.executor.threads.min=4 stream.executor.threads.max=32 war.deploy.server.check.interval=600000 fileconsumer.delayed.write=true fileconsumer.queue.size=21 subscriberstream.buffer.check.interval=5000 subscriberstream.underrun.trigger=100 broadcaststream.auto.record=false red5-1.0~svn4374.orig/src/conf/red5.globals0000644000175000017500000000006710421545730020237 0ustar drazzibdrazzibdefault.context=${red5.root}/webapps/red5-default.xml red5-1.0~svn4374.orig/src/conf/red5-core.xml0000644000175000017500000001663311755553132020356 0ustar drazzibdrazzib red5-1.0~svn4374.orig/src/conf/password.properties0000644000175000017500000000250210621365776022023 0ustar drazzibdrazzib# password.properties # Password file for Remote JMX API authentication. This file defines # the different roles and their passwords. # The file format for the password file is syntactically the same as # the Properties file format. The syntax is described in the Javadoc # for java.util.Properties.load. # A typical password file has multiple lines, where each line is blank, # a comment (like this one), or a password entry. # A password entry consists of a role name and an associated password. # The role name is any string that does not itself contain spaces or # tabs. The password is again any string that does not contain spaces # or tabs. Note that passwords appear in the clear in this file, so it # is a good idea not to use valuable passwords. # A given role should have at most one entry in this file. If a role # has no entry, it has no access. # If multiple entries are found for the same role name, then the last # one is used. # In a typical installation, this file can be read by anybody on the # local machine, and possibly by people on other machines. # For security, you should either restrict the access to this file, # or specify another, less accessible file in the management config # file as described above. # Role and password used for authentication by the RMI connector in # this example. # red5user changeme red5-1.0~svn4374.orig/src/conf/red5-common.xml0000644000175000017500000003031511752053415020703 0ustar drazzibdrazzib org.red5.server.persistence.FilePersistence org.red5.io.flv.impl.FLVReader.setBufferType org.red5.io.flv.impl.FLVReader.setBufferSize red5-1.0~svn4374.orig/src/conf/truststore.jmx0000644000175000017500000000122510621365776021022 0ustar drazzibdrazzibþíþídukecertôºžùmX.509T0‚P0‚¹>¦ŽÈ0  *†H†÷ 0o1 0 UUS1 0 UCA10U Santa Clara10U Sun Microsystems, Inc.1 0 U J2SE1 0 UDuke0 030423130200Z 300908130200Z0o1 0 UUS1 0 UCA10U Santa Clara10U Sun Microsystems, Inc.1 0 U J2SE1 0 UDuke0Ÿ0  *†H†÷ 0‰¿ÌW…âÝ£ýcÍhCä¾U¦6Kàï·¿¥œTÀ•ÙR¤Äl7¦ºÈ1Zè¸CYÃ@šo^ÓÜLK·9NÝ«Xqý<þt)˜€ê¸þk5q½•½±ÌnƒïJ†ÍÕN\\³ÂÀ>᪟åò¹ œBViökò#0  *†H†÷ E~…âÆñòaåŸÙ¼²±}a‹jÚøCã¸w+òöÍDÜ¢ÄI(a_ër„дˆ™*Æð'Áì|•ñÌνÞ@†’$š*T=…¹96½cV¥kßôk£‡¨›ä2ý˜ç]kk¾ã´Ç8"â?ô à¤?Ý»red5-1.0~svn4374.orig/src/conf/keystore.jmx0000644000175000017500000000252410621365776020434 0ustar drazzibdrazzibþíþídukeôºÂ»0‚·0 +*‚£U5{ÃÏ‚£È¯íÓíš‹ZO\SAaª?…z ^KP‰r¿¯¸O¢ìk¹c{2‚+Üç·ŸÙyD^Èõ÷Çú?k-þ´¹Ç¹l³–Ñ9e\ »—óZ˜³$ò•È›uõ+„Ƕ>a÷i LŠºdû¹ÕØ?ã4ê4Á—عŠÍÏéØ2ÿÖîXyÙýÎûìÞÝl–ÁÊBÈSSëÝ%¬;Þ$øé­ž®Hœ"µD‡âŒ¶-;›0õQ;P<Ûâó¼Ýƒ‹; Di +‘Ì“×èÈuvÑÕçªí–:Ç M†ƒ@ªøû®˜i‡5…As1õ:—*w(ýH¬)9 ÷Æý¤66ƒe õ|&¯ÈzAÍU?ž¸@cY½›"#•#B[tâ^sʦËp’ƒ‡eño¾à!"Û®Ïø“ZÓÀy:‡P=¡ú 𓸟&Jga¶1üF!×ÕÞ»BwÆ‚W?²Fö˜È.åÆÒGÎCÏde»œ:Ýø`b‡x,µú«EÕ¢•O <;ˆÍ?ªóKƒÐëÂßü¤¸›öCe'CÀÒÑ-¥0EF•ùZuú3üz«ÅCLôìJ·œËè„qö þ[±¼Ÿzk‚Œ¬!ó q5H>‚*'Z1Y–æIÖu÷­Q¦Òé‰q;JäØî6’ÿßÜm >´‚mâÖ°5xüÿ€›ÿ±ñ°…2(ۗܨ9±ÕH€|a&‡ë wv•™Ï2î±e×/võô_ø´;4øÉ=¶é¦Y…É 7i^›ÖèRtêPJ¾ØÁ¦¶vL”ÎJ‰ékØÆOsæ{Œ8‰9¡Ô€ ©¸ÞOäM߯'&@ÈÖVí1³™_NM1$€Éq"“y’‰º ']“H‚X.509T0‚P0‚¹>¦ŽÈ0  *†H†÷ 0o1 0 UUS1 0 UCA10U Santa Clara10U Sun Microsystems, Inc.1 0 U J2SE1 0 UDuke0 030423130200Z 300908130200Z0o1 0 UUS1 0 UCA10U Santa Clara10U Sun Microsystems, Inc.1 0 U J2SE1 0 UDuke0Ÿ0  *†H†÷ 0‰¿ÌW…âÝ£ýcÍhCä¾U¦6Kàï·¿¥œTÀ•ÙR¤Äl7¦ºÈ1Zè¸CYÃ@šo^ÓÜLK·9NÝ«Xqý<þt)˜€ê¸þk5q½•½±ÌnƒïJ†ÍÕN\\³ÂÀ>᪟åò¹ œBViökò#0  *†H†÷ E~…âÆñòaåŸÙ¼²±}a‹jÚøCã¸w+òöÍDÜ¢ÄI(a_ër„дˆ™*Æð'Áì|•ñÌνÞ@†’$š*T=…¹96½cV¥kßôk£‡¨›ä2ý˜͘ǃw¥üZ èÒ*1ÑX@.hred5-1.0~svn4374.orig/src/conf/keystore0000644000175000017500000000162411016334664017626 0ustar drazzibdrazzibþíþíred5!yÝŒ™0‚•0 +*‚ WÂXRÕ‹+ýQãJ/F5=u×hÞ ‚¸dM±ÓhâÏÿÇNuÔÞ#!Ny;vëq£3I³œP¾F<>Åš~Òºýè]£—hü7›¢ò–Ÿýý+áˆüÚ¡Î/ƒ³ÓØðÍœölÔ{áî\¿—XvÎÞ)¥À¦ªŸ^°©£>âçÏxËNwTž½´ï)‚O˜†6¤eÕØõçìÁ™jº&` _DhQí²çÎŒ¶@€PP^xÏ®±Ç'Ÿ"„‹~´tCT¥ïÙ°•Ï òj½8ª32IŽÅaD6|M§uÆèI¬ãÁ[‹â¥” <ù¶JózýÛCLÜÁ~ïÿÆÞдÉÃå@œ‹ù+ýY¨b<üÉŒ¡qcûÍLlØ@á'ŠÏûjÞYO̸©iAÒs™¹¯BÅÛÓÂ7zxíAÚ‚xòwÄv9ÃÇ›rçÇtNÞ÷(n ÞÔœ î4è$CõZL'ñ¥+ɯñ¸7ÖlØZ·¯”X.509¶0‚²0‚\ H9¸Ì0  *†H†÷ 0`1 0 UUS1 0 UNV10U Henderson1 0 U Red51 0 U Red510U localhost0 080525190652Z 180523190652Z0`1 0 UUS1 0 UNV10U Henderson1 0 U Red51 0 U Red510U localhost0\0  *†H†÷ K0HA•n÷éy ¿¿HÔã½Y¿CYZa~Ó¢ßsgÖ‚”Š'µ€-Éiý>©qbã|°“÷arÄ™Ñͽ[Ƽár_0  *†H†÷ A\³¸¡¢âAÔ\¸Kö²S–Áê­çEò/ÒÄSùí]‡ÅçIcÞ—B¿DÎd—ëÝП/„7vêÕ¢Í)¬ˆ¹=ôd–t_sR¯[»+˜ü“Båred5-1.0~svn4374.orig/src/conf/access.properties0000644000175000017500000000320610621365776021424 0ustar drazzibdrazzib# access.properties # Access control file for Remote JMX API access to MBeanServer resources. # This file defines the allowed access for different roles. # The file format for the access file is syntactically the same as the # Properties file format. The syntax is described in the Javadoc for # java.util.Properties.load. # A typical access file has multiple lines, where each line is blank, # a comment (like this one), or an access control entry. # An access control entry consists of a role name, and an associated access # level. The role name is any string that does not itself contain spaces or # tabs. It corresponds to an entry in the password file. The access level # is one of the following: # # "readonly" grants access to read attributes of MBeans. # For monitoring, this means that a remote client in this # role can read measurements but cannot perform any action # that changes the environment of the running program. # # "readwrite" grants access to read and write attributes of MBeans, to # invoke operations on them, and to create or remove them. # This access should be only granted to trusted clients, # since they can potentially interfere with the smooth # operation of a running program. # A given role should have at most one entry in this file. If a role has no # entry, it has no access. # If multiple entries are found for the same role name, then the last access # entry is used. # Access rights granted to the authenticated identity by the RMI connector # in this example. # red5user readwrite red5-1.0~svn4374.orig/src/conf/realm.properties0000644000175000017500000000066310453577436021270 0ustar drazzibdrazzib# # This file defines users passwords and roles for a HashUserRealm # # The format is # : [, ...] # # Passwords may be clear text, obfuscated or checksummed. The class # org.mortbay.util.Password should be used to generate obfuscated # passwords or password checksums # # If DIGEST Authentication is used, the password must be in a recoverable # format, either plain text or OBF:. # admin: admin,admin red5-1.0~svn4374.orig/src/conf/ehcache.xml0000644000175000017500000003334011441567417020146 0ustar drazzibdrazzib red5-1.0~svn4374.orig/src/conf/build_standalone.properties0000644000175000017500000000146610663373141023467 0ustar drazzibdrazzib#Filter file context.config.location=/WEB-INF/red5-*.xml locator.factory.selector=red5.xml global.scope=globalScopedefault parent.context.key=parentContextKeydefault.context context.loader.listener=org.springframework.web.context.ContextLoaderListener request.context.listener= gateway.servlet=gatewayorg.red5.server.net.servlet.AMFGatewayServlet1 gateway.servlet.mapping=gateway/gateway rtmpt.servlet= rtmpt.servlet.mappings= red5-1.0~svn4374.orig/src/conf/tomcat-users.xml0000644000175000017500000000077210506066467021217 0ustar drazzibdrazzib red5-1.0~svn4374.orig/src/conf/web.xml0000644000175000017500000014440311377574332017350 0ustar drazzibdrazzib default org.apache.catalina.servlets.DefaultServlet debug 0 listings true 1 jsp org.apache.jasper.servlet.JspServlet fork false xpoweredBy false 3 default / jsp *.jsp jsp *.jspx 30 abs audio/x-mpeg ai application/postscript aif audio/x-aiff aifc audio/x-aiff aiff audio/x-aiff aim application/x-aim art image/x-jg asf video/x-ms-asf asx video/x-ms-asf au audio/basic avi video/x-msvideo avx video/x-rad-screenplay bcpio application/x-bcpio bin application/octet-stream bmp image/bmp body text/html cdf application/x-cdf cer application/x-x509-ca-cert class application/java cpio application/x-cpio csh application/x-csh css text/css dcr application/x-director dib image/bmp doc application/msword dtd application/xml-dtd dv video/x-dv dvi application/x-dvi eps application/postscript etx text/x-setext exe application/octet-stream f4v video/mp4 f4p video/mp4 f4a audio/mp4 f4b audio/mp4 gif image/gif gtar application/x-gtar gz application/x-gzip hdf application/x-hdf hqx application/mac-binhex40 htc text/x-component htm text/html html text/html hqx application/mac-binhex40 ief image/ief jad text/vnd.sun.j2me.app-descriptor jar application/java-archive java text/plain jnlp application/x-java-jnlp-file jpe image/jpeg jpeg image/jpeg jpg image/jpeg js text/javascript jsf text/plain jspf text/plain kar audio/x-midi latex application/x-latex m3u audio/x-mpegurl m3u8 application/x-mpegURL mac image/x-macpaint man application/x-troff-man mathml application/mathml+xml me application/x-troff-me mid audio/x-midi midi audio/x-midi mif application/x-mif mov video/quicktime movie video/x-sgi-movie mp1 audio/x-mpeg mp2 audio/x-mpeg mp3 audio/x-mpeg mp4 video/mp4 mpa audio/x-mpeg mpe video/mpeg mpeg video/mpeg mpega audio/x-mpeg mpg video/mpeg mpv2 video/mpeg2 ms application/x-wais-source nc application/x-netcdf oda application/oda ogg application/ogg pbm image/x-portable-bitmap pct image/pict pdf application/pdf pgm image/x-portable-graymap pic image/pict pict image/pict pls audio/x-scpls png image/png pnm image/x-portable-anymap pnt image/x-macpaint ppm image/x-portable-pixmap ppt application/powerpoint ps application/postscript psd image/x-photoshop qt video/quicktime qti image/x-quicktime qtif image/x-quicktime ras image/x-cmu-raster rdf application/rdf+xml rgb image/x-rgb rm application/vnd.rn-realmedia roff application/x-troff rtf application/rtf rtx text/richtext sh application/x-sh shar application/x-shar shtml text/x-server-parsed-html smf audio/x-midi sit application/x-stuffit snd audio/basic src application/x-wais-source sv4cpio application/x-sv4cpio sv4crc application/x-sv4crc svg image/svg+xml swf application/x-shockwave-flash t application/x-troff tar application/x-tar tcl application/x-tcl tex application/x-tex texi application/x-texinfo texinfo application/x-texinfo tif image/tiff tiff image/tiff tr application/x-troff ts video/MP2T tsv text/tab-separated-values txt text/plain ulw audio/basic ustar application/x-ustar vxml application/voicexml+xml xbm image/x-xbitmap xht application/xhtml+xml xhtml application/xhtml+xml xml application/xml xpm image/x-xpixmap xsl application/xml xslt application/xslt+xml xul application/vnd.mozilla.xul+xml xwd image/x-xwindowdump wav audio/x-wav svg image/svg svgz image/svg vsd application/x-visio w3d application/octet-stream wbmp image/vnd.wap.wbmp wml text/vnd.wap.wml wmlc application/vnd.wap.wmlc wmls text/vnd.wap.wmlscript wmlscriptc application/vnd.wap.wmlscriptc wrl x-world/x-vrml Z application/x-compress z application/x-compress zip application/zip index.html index.htm index.jsp arISO-8859-6 beISO-8859-5 bgISO-8859-5 caISO-8859-1 csISO-8859-2 daISO-8859-1 deISO-8859-1 elISO-8859-7 enISO-8859-1 esISO-8859-1 etISO-8859-1 fiISO-8859-1 frISO-8859-1 hrISO-8859-2 huISO-8859-2 isISO-8859-1 itISO-8859-1 iwISO-8859-8 jaShift_JIS koEUC-KR ltISO-8859-2 lvISO-8859-2 mkISO-8859-5 nlISO-8859-1 noISO-8859-1 plISO-8859-2 ptISO-8859-1 roISO-8859-2 ruISO-8859-5 shISO-8859-5 skISO-8859-2 slISO-8859-2 sqISO-8859-2 srISO-8859-5 svISO-8859-1 trISO-8859-9 ukISO-8859-5 zhGB2312 zh_TWBig5 Forbidden /WEB-INF/* Forbidden /persistence/* red5-1.0~svn4374.orig/src/conf/catalina.policy0000644000175000017500000002367011141776723021045 0ustar drazzibdrazzib// ============================================================================ // red5.policy - Security Policy Permissions for Red5 // // This file contains a default set of security policies to be enforced (by the // JVM) In addition to the permissions granted here, the following additional permissions are // granted to the codebase specific to each web application: // // ============================================================================ // ========== SYSTEM CODE PERMISSIONS ========================================= // These permissions apply to javac grant codeBase "file:${java.home}/lib/-" { permission java.security.AllPermission; }; // These permissions apply to all shared system extensions grant codeBase "file:${java.home}/jre/lib/ext/-" { permission java.security.AllPermission; }; // These permissions apply to javac when ${java.home] points at $JAVA_HOME/jre grant codeBase "file:${java.home}/../lib/-" { permission java.security.AllPermission; }; // These permissions apply to all shared system extensions when // ${java.home} points at $JAVA_HOME/jre grant codeBase "file:${java.home}/lib/ext/-" { permission java.security.AllPermission; }; // ========== RED5 CODE PERMISSIONS ======================================= // These permissions apply to the main code grant codeBase "file:red5.jar" { permission java.security.AllPermission; }; grant codeBase "file:${red5.home}/red5.jar" { permission java.security.AllPermission; }; grant codeBase "file:${red5.root}/red5.jar" { permission java.security.AllPermission; }; // These permissions apply to the servlet API classes // and those that are shared across all class loaders // located in the "common" directory grant codeBase "file:lib/-" { permission java.security.AllPermission; }; grant codeBase "file:${red5.home}/lib/-" { permission java.security.AllPermission; }; grant codeBase "file:${red5.root}/lib/-" { permission java.security.AllPermission; }; // The permissions granted to the balancer WEB-INF/classes directory //grant codeBase "file:${catalina.home}/webapps/balancer/WEB-INF/classes/-" { // permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.util.digester"; // permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.util.digester.*"; //}; // ========== WEB APPLICATION PERMISSIONS ===================================== // These permissions are granted by default to all web applications // In addition, a web application will be given a read FilePermission // and JndiPermission for all files and directories in its document root. grant { //Red5 specific properties permission java.util.PropertyPermission "red5.root", "read"; permission java.util.PropertyPermission "red5.lib_root", "read"; permission java.util.PropertyPermission "red5.deployment.type", "read"; permission java.util.PropertyPermission "logback.ContextSelector", "read"; permission javax.management.MBeanPermission "*", "invoke"; permission javax.management.MBeanPermission "*", "removeNotificationListener"; permission javax.management.MBeanPermission "*", "unregisterMBean"; permission javax.management.MBeanPermission "*", "queryNames"; permission java.lang.RuntimePermission "exitVM"; permission java.lang.RuntimePermission "loadLibrary"; permission java.lang.RuntimePermission "getClassLoader"; permission java.lang.RuntimePermission "setContextClassLoader"; //specifically so that tomcat can be shutdown permission java.lang.RuntimePermission "modifyThread"; permission javax.security.auth.AuthPermission "doAsPrivileged"; permission java.net.SocketPermission "127.0.0.1:9999", "connect,resolve"; //permission java.io.FilePermission "file:C:/red5/work/red5Engine/0.0.0.0/oflaDemo/loader", "read,write"; // Required for JNDI lookup of named JDBC DataSource's and // javamail named MimePart DataSource used to send mail permission java.util.PropertyPermission "java.home", "read"; permission java.util.PropertyPermission "java.naming.*", "read"; permission java.util.PropertyPermission "javax.sql.*", "read"; // OS Specific properties to allow read access permission java.util.PropertyPermission "os.name", "read"; permission java.util.PropertyPermission "os.version", "read"; permission java.util.PropertyPermission "os.arch", "read"; permission java.util.PropertyPermission "file.separator", "read"; permission java.util.PropertyPermission "path.separator", "read"; permission java.util.PropertyPermission "line.separator", "read"; // JVM properties to allow read access permission java.util.PropertyPermission "java.version", "read"; permission java.util.PropertyPermission "java.vendor", "read"; permission java.util.PropertyPermission "java.vendor.url", "read"; permission java.util.PropertyPermission "java.class.version", "read"; permission java.util.PropertyPermission "java.specification.version", "read"; permission java.util.PropertyPermission "java.specification.vendor", "read"; permission java.util.PropertyPermission "java.specification.name", "read"; permission java.util.PropertyPermission "java.vm.specification.version", "read"; permission java.util.PropertyPermission "java.vm.specification.vendor", "read"; permission java.util.PropertyPermission "java.vm.specification.name", "read"; permission java.util.PropertyPermission "java.vm.version", "read"; permission java.util.PropertyPermission "java.vm.vendor", "read"; permission java.util.PropertyPermission "java.vm.name", "read"; permission java.util.PropertyPermission "java.security.debug", "read"; permission java.util.PropertyPermission "java.security.policy", "read"; // Required for OpenJMX permission java.lang.RuntimePermission "getAttribute"; // Allow read of JAXP compliant XML parser debug permission java.util.PropertyPermission "jaxp.debug", "read"; // Precompiled JSPs need access to this package. permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.startup"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.startup.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.core"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.core.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.connector"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.connector.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.security"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.security.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.session"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.session.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.loader"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.loader.*"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.util.modeler"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.util.modeler.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.misc"; permission java.lang.RuntimePermission "accessClassInPackage.sun.misc.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect"; permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.server"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.server.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.tcp"; permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.tcp.*"; }; // You can assign additional permissions to particular web applications by // adding additional "grant" entries here, based on the code base for that // application, /WEB-INF/classes/, or /WEB-INF/lib/ jar files. // // Different permissions can be granted to JSP pages, classes loaded from // the /WEB-INF/classes/ directory, all jar files in the /WEB-INF/lib/ // directory, or even to individual jar files in the /WEB-INF/lib/ directory. // // For instance, assume that the standard "examples" application // included a JDBC driver that needed to establish a network connection to the // corresponding database and used the scrape taglib to get the weather from // the NOAA web server. You might create a "grant" entries like this: // // The permissions granted to the context root directory apply to JSP pages. // grant codeBase "file:${red5.home}/webapps/examples/-" { // permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect"; // permission java.net.SocketPermission "*.noaa.gov:80", "connect"; // }; // // The permissions granted to the context WEB-INF/classes directory // grant codeBase "file:${red5.home}/webapps/examples/WEB-INF/classes/-" { // }; // // The permission granted to your JDBC driver // grant codeBase "jar:file:${red5.home}/webapps/examples/WEB-INF/lib/driver.jar!/-" { // permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect"; // }; // The permission granted to the scrape taglib // grant codeBase "jar:file:${red5.home}/webapps/examples/WEB-INF/lib/scrape.jar!/-" { // permission java.net.SocketPermission "*.noaa.gov:80", "connect"; // }; red5-1.0~svn4374.orig/src/conf/quartz.properties0000644000175000017500000000370711435603314021502 0ustar drazzibdrazzib#============================================================================ # Configure Main Scheduler Properties # # http://www.opensymphony.com/quartz/wikidocs/ConfigMain.html # http://www.opensymphony.com/quartz/api/ #============================================================================ org.quartz.scheduler.instanceName = Red5_Scheduler org.quartz.scheduler.instanceId = AUTO # org.quartz.scheduler.classLoadHelper.class # Defaults to the most robust approach, which is to use the "org.quartz.simpl.CascadingClassLoadHelper" class # which in turn uses every other ClassLoadHelper class until one works. You should probably not find the need # to specify any other class for this property, though strange things seem to happen within application servers. # All of the current possible ClassLoadHelper implementation can be found in the org.quartz.simpl package. # Default helper org.quartz.scheduler.classLoadHelper.class = org.quartz.simpl.CascadingClassLoadHelper #org.quartz.scheduler.classLoadHelper.class = org.quartz.simpl.LoadingLoaderClassLoadHelper #org.quartz.scheduler.classLoadHelper.class = org.quartz.simpl.ThreadContextClassLoadHelper #org.quartz.scheduler.classLoadHelper.class = org.quartz.simpl.SimpleClassLoadHelper #org.quartz.scheduler.classLoadHelper.class = org.red5.classloading.QuartzClassLoadHelper #============================================================================ # Configure ThreadPool #============================================================================ org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 4 org.quartz.threadPool.threadPriority = 5 #============================================================================ # Configure JobStore #============================================================================ org.quartz.jobStore.misfireThreshold = 60000 org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore red5-1.0~svn4374.orig/src/conf/context.xml0000644000175000017500000000312611131005562020231 0ustar drazzibdrazzib WEB-INF/web.xml META-INF/context.xml red5-1.0~svn4374.orig/src/conf/red5.xml0000644000175000017500000000416411745776105017432 0ustar drazzibdrazzib classpath:/red5-common.xml classpath:/red5-core.xml red5-1.0~svn4374.orig/src/conf/logback.xml0000644000175000017500000000242411746326760020171 0ustar drazzibdrazzib [%p] [%thread] %logger - %msg%n log/red5.log false %d{ISO8601} [%thread] %-5level %logger{35} - %msg%n log/error.log false WARN %d{ISO8601} [%thread] %-5level %logger{35} - %msg%n red5-1.0~svn4374.orig/src/conf/war/0000755000175000017500000000000011760512571016625 5ustar drazzibdrazzibred5-1.0~svn4374.orig/src/conf/war/red5.properties0000644000175000017500000000203511211357035021573 0ustar drazzibdrazzib# HTTP http.host=0.0.0.0 http.port=8080 # RTMP rtmp.host=0.0.0.0 rtmp.port=1935 rtmp.event_threads_core=16 rtmp.event_threads_max=32 # event threads queue: -1 unbounded, 0 direct (no queue), n bounded queue rtmp.event_threads_queue=-1 rtmp.event_threads_keepalive=60 rtmp.send_buffer_size=271360 rtmp.receive_buffer_size=65536 rtmp.ping_interval=5000 rtmp.max_inactivity=60000 rtmp.tcp_nodelay=true # RTMPT rtmpt.host=0.0.0.0 rtmpt.port=8080 rtmpt.ping_interval=5000 rtmpt.max_inactivity=60000 # MRTMP mrtmp.host=0.0.0.0 mrtmp.port=9035 mrtmp.event_threads_core=16 mrtmp.event_threads_max=32 # event threads queue: -1 unbounded, 0 direct (no queue), n bounded queue mrtmp.event_threads_queue=-1 mrtmp.event_threads_keepalive=60 mrtmp.send_buffer_size=271360 mrtmp.receive_buffer_size=65536 mrtmp.ping_interval=5000 mrtmp.max_inactivity=60000 # Debug proxy (needs to be activated in red5-core.xml) proxy.source_host=127.0.0.1 proxy.source_port=1936 proxy.destination_host=127.0.0.1 proxy.destination_port=1935 red5-1.0~svn4374.orig/src/conf/war/red5-core.xml0000644000175000017500000001113411522125744021132 0ustar drazzibdrazzib red5-1.0~svn4374.orig/src/conf/war/red5-common.xml0000644000175000017500000002061311522125744021474 0ustar drazzibdrazzib org.red5.server.persistence.FilePersistence org.red5.io.flv.impl.FLVReader.setBufferType org.red5.io.flv.impl.FLVReader.setBufferSize red5-1.0~svn4374.orig/src/conf/war/beanRefContext.xml0000644000175000017500000000072410665571001022255 0ustar drazzibdrazzib defaultContext.xml red5-common.xml red5-core.xml red5-1.0~svn4374.orig/src/conf/war/root-context.xml0000644000175000017500000000062410663566550022025 0ustar drazzibdrazzib red5-1.0~svn4374.orig/src/conf/war/web.xml0000644000175000017500000000647211211357035020126 0ustar drazzibdrazzib Red5 @display.name@ War globalScope default parentContextKey default.context webAppRootKey @webapp.root.key@ contextConfigLocation WEB-INF/classes/*-web.xml org.red5.server.war.WarLoaderServlet org.springframework.web.context.request.RequestContextListener gateway org.red5.server.net.servlet.AMFGatewayServlet 1 rtmpt org.red5.server.net.rtmpt.RTMPTServlet 2 gateway /gateway rtmpt /fcs/* rtmpt /open/* rtmpt /idle/* rtmpt /send/* rtmpt /close/* login.html index.html index.htm Forbidden /WEB-INF/* Forbidden /persistence/* Forbidden /streams/* red5-1.0~svn4374.orig/src/conf/war/README.txt0000644000175000017500000000006710566443227020332 0ustar drazzibdrazzibThese files are used only by the WAR version of Red5. red5-1.0~svn4374.orig/src/conf/war/context.xml0000644000175000017500000000062210663566550021042 0ustar drazzibdrazzib red5-1.0~svn4374.orig/src/conf/war/build_war.properties0000644000175000017500000000406611522125744022717 0ustar drazzibdrazzib#Filter file context.config.location=/WEB-INF/applicationContext.xml /WEB-INF/red5-*.xml locator.factory.selector=applicationContext.xml global.scope=globalScopedefault parent.context.key=parentContextKeydefault.context context.loader.listener=org.red5.server.MainServlet request.context.listener=org.springframework.web.context.request.RequestContextListener gateway.servlet=gatewayorg.red5.server.net.servlet.AMFGatewayServlet1 gateway.servlet.mapping=gateway/gateway rtmpt.servlet=rtmptorg.red5.server.net.rtmpt.RTMPTServlet2 rtmpt.servlet.mappings=rtmpt/open/*rtmpt/idle/*rtmpt/send/*rtmpt/close/* welcome.file=index.jsp context.override=false virtual.hosts=*,localhost, localhost:8080, 127.0.0.1:8080 # Used by the installer to locate the available wars application.repository.url=http://red5.googlecode.com/svn/snapshots/ # HTTP http.host=0.0.0.0 http.port=8080 # RTMP rtmp.host=0.0.0.0 rtmp.port=1935 rtmp.io_threads=16 rtmp.connect_threads=4 rtmp.send_buffer_size=271360 rtmp.receive_buffer_size=65536 rtmp.ping_interval=5000 rtmp.max_inactivity=60000 # RTMPT rtmpt.host=0.0.0.0 rtmpt.port=8080 rtmpt.ping_interval=5000 rtmpt.max_inactivity=60000 red5-1.0~svn4374.orig/src/conf/war/red5-web.properties0000644000175000017500000000014210663566550022361 0ustar drazzibdrazzibwebapp.contextPath=@context.path@ webapp.virtualHosts=*,localhost, localhost:8080, 127.0.0.1:8080red5-1.0~svn4374.orig/src/conf/war/logback.xml0000644000175000017500000001446211211357035020751 0ustar drazzibdrazzib INFO ACCEPT DENY %date [%thread] %-5level %logger - %msg%n ../logs/red5.log false UTF-8 false true %date [%thread] %-5level %logger{35} - %msg%n ../logs/error.log false UTF-8 false true WARN %date [%thread] %-5level %logger{35} - %msg%n red5-1.0~svn4374.orig/src/conf/war/defaultContext.xml0000644000175000017500000000366711211357035022345 0ustar drazzibdrazzib org.red5.server.persistence.FilePersistence red5-1.0~svn4374.orig/src/conf/war/root-web.xml0000644000175000017500000000165111211357035021101 0ustar drazzibdrazzib red5-1.0~svn4374.orig/src/conf/no-jee-container.xml0000644000175000017500000000147611466260052021720 0ustar drazzibdrazzib red5-1.0~svn4374.orig/red5.bat0000644000175000017500000000212611614272623015647 0ustar drazzibdrazzib@echo off SETLOCAL if NOT DEFINED RED5_HOME set RED5_HOME=%~dp0 if NOT DEFINED RED5_MAINCLASS set RED5_MAINCLASS=org.red5.server.Bootstrap if NOT DEFINED JAVA_HOME goto err REM JAVA options REM You can set JAVA_OPTS to add additional options if you want REM Set up logging options set LOGGING_OPTS=-Dlogback.ContextSelector=org.red5.logging.LoggingContextSelector -Dcatalina.useNaming=true REM Set up security options REM set SECURITY_OPTS= -Djava.security.debug=failure -Djava.security.manager -Djava.security.policy="%RED5_HOME%/conf/red5.policy" set SECURITY_OPTS=-Djava.security.debug=failure set JAVA_OPTS=%LOGGING_OPTS% %SECURITY_OPTS% %JAVA_OPTS% set JYTHON_OPTS=-Dpython.home=lib set RED5_CLASSPATH=%RED5_HOME%\boot.jar;%RED5_HOME%\conf;%CLASSPATH% if NOT DEFINED RED5_OPTS set RED5_OPTS= goto launchRed5 :launchRed5 echo Starting Red5 "%JAVA_HOME%\bin\java" %JYTHON_OPTS% %JAVA_OPTS% -cp "%RED5_CLASSPATH%" %RED5_MAINCLASS% %RED5_OPTS% goto finally :err echo JAVA_HOME environment variable not set! Take a look at the readme. pause :finally ENDLOCAL red5-1.0~svn4374.orig/red5-highperf.bat0000644000175000017500000000223511614272623017442 0ustar drazzibdrazzib@echo off if NOT DEFINED RED5_HOME set RED5_HOME=%~dp0 REM Previous option set REM -Xrs -Xms512M -Xmx768M -Xss128K -XX:PermSize=256M -XX:MaxPermSize=512M -XX:NewRatio=2 -XX:MinHeapFreeRatio=20 -XX:+AggressiveHeap -XX:+DisableExplicitGC -XX:ParallelGCThreads=2 -XX:+UseParallelOldGC -XX:+MaxFDLimit -Dsun.rmi.dgc.client.gcInterval=990000 -Dsun.rmi.dgc.server.gcInterval=990000 -Djava.net.preferIPv4Stack=true -Xverify:none REM Latest 06/2008 REM -Xmx768m -Xms256 -Xmn512m -Xss128k -XX:+AggressiveOpts -XX:+AggressiveHeap -XX:+DisableExplicitGC -XX:ParallelGCThreads=4 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=31 -Djava.net.preferIPv4Stack=true -Dsun.rmi.dgc.client.gcInterval=990000 -Dsun.rmi.dgc.server.gcInterval=990000 set JAVA_OPTS= -Xmx768m -Xms256 -Xmn512m -Xss256k -XX:+AggressiveOpts -XX:+DisableExplicitGC -XX:ParallelGCThreads=4 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:SurvivorRatio=16 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=31 -Djava.net.preferIPv4Stack=true echo Running High Performance Red5 start cmd /c "%RED5_HOME%\red5.bat" >> "%RED5_HOME%\log\jvm.stdout" red5-1.0~svn4374.orig/util.xml0000644000175000017500000000514611333123453016016 0ustar drazzibdrazzib Cannot specify '.' as it will overwrite red5's files red5-1.0~svn4374.orig/red5-shutdown.bat0000644000175000017500000000046411614272623017523 0ustar drazzibdrazzib@echo off SETLOCAL if NOT DEFINED RED5_HOME set RED5_HOME=%~dp0 set JAVA_OPTS=-Djavax.net.ssl.keyStore="%RED5_HOME%\conf\keystore.jmx" -Djavax.net.ssl.keyStorePassword=password set RED5_MAINCLASS=org.red5.server.Shutdown set RED5_OPTS=9999 red5user changeme "%RED5_HOME%\red5.bat" ENDLOCAL red5-1.0~svn4374.orig/.settings/0000755000175000017500000000000011760512600016227 5ustar drazzibdrazzibred5-1.0~svn4374.orig/.settings/org.eclipse.jdt.core.prefs0000644000175000017500000005731111430437662023230 0ustar drazzibdrazzib#Tue Aug 10 20:18:27 PDT 2010 eclipse.preferences.version=1 org.eclipse.jdt.core.builder.cleanOutputFolder=clean org.eclipse.jdt.core.builder.duplicateResourceTask=warning org.eclipse.jdt.core.builder.invalidClasspath=abort org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch org.eclipse.jdt.core.circularClasspath=error org.eclipse.jdt.core.classpath.exclusionPatterns=enabled org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.maxProblemPerUnit=100 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.source=1.6 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_assignment=0 org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 org.eclipse.jdt.core.formatter.blank_lines_after_package=1 org.eclipse.jdt.core.formatter.blank_lines_before_field=1 org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 org.eclipse.jdt.core.formatter.blank_lines_before_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 org.eclipse.jdt.core.formatter.blank_lines_before_package=0 org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false org.eclipse.jdt.core.formatter.comment.format_block_comments=false org.eclipse.jdt.core.formatter.comment.format_comments=false org.eclipse.jdt.core.formatter.comment.format_header=false org.eclipse.jdt.core.formatter.comment.format_html=true org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false org.eclipse.jdt.core.formatter.comment.format_line_comments=false org.eclipse.jdt.core.formatter.comment.format_source_code=true org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true org.eclipse.jdt.core.formatter.comment.indent_root_tags=true org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert org.eclipse.jdt.core.formatter.comment.line_length=80 org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true org.eclipse.jdt.core.formatter.compact_else_if=true org.eclipse.jdt.core.formatter.continuation_indentation=2 org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_empty_lines=false org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true org.eclipse.jdt.core.formatter.indentation.size=4 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.join_lines_in_comments=true org.eclipse.jdt.core.formatter.join_wrapped_lines=true org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false org.eclipse.jdt.core.formatter.lineSplit=180 org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true org.eclipse.jdt.core.formatter.tabulation.char=mixed org.eclipse.jdt.core.formatter.tabulation.size=4 org.eclipse.jdt.core.formatter.use_on_off_tags=false org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true org.eclipse.jdt.core.incompatibleJDKLevel=ignore org.eclipse.jdt.core.incompleteClasspath=error red5-1.0~svn4374.orig/.settings/org.apache.ivyde.eclipse.prefs0000644000175000017500000000153011745262602024047 0ustar drazzibdrazzibacceptedTypes=[inherited] eclipse.preferences.version=1 ivy_conf_path=file\:ivysettings.xml javadocTypes=[inherited] org.apache.ivyde.eclipse.standaloneretrieve= retreive.pattern=lib/[artifact]-[revision].[ext] sourceTypes=[inherited] red5-1.0~svn4374.orig/.settings/org.eclipse.wst.validation.prefs0000644000175000017500000000070411614100102024434 0ustar drazzibdrazzib#Wed Jul 27 09:56:05 PDT 2011 DELEGATES_PREFERENCE=delegateValidatorList USER_BUILD_PREFERENCE=enabledBuildValidatorListorg.eclipse.wst.wsi.ui.internal.WSIMessageValidator; USER_MANUAL_PREFERENCE=enabledManualValidatorListorg.eclipse.wst.wsi.ui.internal.WSIMessageValidator; USER_PREFERENCE=overrideGlobalPreferencestruedisableAllValidationtrueversion1.2.202.v201103212041 eclipse.preferences.version=1 override=true suspend=true vf.version=3 red5-1.0~svn4374.orig/.settings/org.eclipse.jdt.ui.prefs0000644000175000017500000000035311236713201022675 0ustar drazzibdrazzib#Thu Aug 06 14:25:49 PDT 2009 eclipse.preferences.version=1 formatter_profile=_Red5 formatter_settings_version=11 org.eclipse.jdt.ui.text.custom_code_templates= red5-1.0~svn4374.orig/.settings/red5_codeformat.xml0000644000175000017500000006510210511100646022013 0ustar drazzibdrazzib red5-1.0~svn4374.orig/.settings/red5_codetemplate.xml0000644000175000017500000001332211236340361022340 0ustar drazzibdrazzib