knopflerfish-osgi-5.1.0/0000755000175000017500000000000012475375720014162 5ustar felixfelixknopflerfish-osgi-5.1.0/strings.properties0000644000175000017500000000353612346513620017766 0ustar felixfelixframe_title=Knopflerfish OSGi $(1) installation page_license_title=Knopflerfish OSGi License page_installdir_title=Select installation directory page_finish_title=Installing Knopflerfish OSGi cancel=Cancel yes=Yes no=No ok=OK select=Select finish=Finish back=Back << forward=Next >> browse=Browse... tt_browse_file=Browse for file tt_browse_dir=Browse for directory title_select_dir=Browse for directory title_select_file=Browse for file cb_open_dir=Open OSGi directory when done license_res_name=/license.html fmt_install_info=Total installation requires about $(1).\

\ The framework can be started by running \ framework.jar in $(2)$(sep)osgi\

\ It can also be started from a command prompt in that directory by typing
\ java -jar framework.jar
replace_array4=Yes,"Yes to all",No,Cancel title_replace_dir=Overwrite directory? q_replace_dir=\ The destination folder '$(name)' already exists.\n\ \n\ Overwrite directory? title_replace_file=Replace file? destfolder_contains=The destination folder already contains a file '$(1)' title_origfile=Would you like to replace the existing file title_newfile=with this one? file_info_fmt=$(1), $(2) bytes cancel_install_title=Cancel installation? cancel_install_msg=Are you sure you want to cancel the the installation? cancel_install_array2="Yes","No, continue" page_installselection_title=Select components to install install_comp_base=OSGi framework runtime files install_comp_src=Java sources and build environment install_comp_htdocs=Knopflerfish documentation install_comp_base_tt=Compiled OSGi framework files. install_comp_src_tt=All java sources for the framework and bundles + ant build environment. install_comp_htdocs_tt=Create 'docs'-subdirectory with Knopflerfish documentation comp_size=Installation requires about $(1). knopflerfish-osgi-5.1.0/kf_16x16.gif0000644000175000017500000000173612346513620016113 0ustar felixfelixGIF89a!)!))))1)11119!19!99!9B)9B)BB)BJ1BJ1JJ9JR9RRBRRBRZJZZJZcRccZksckscsss{{{,H*L@ "P!Ä(`` D&X4P (,` |CV €VX À QpC $` ` dxRh+JH"?1E0$\` 0@-H 4 @5;QE \@Y*@c6;knopflerfish-osgi-5.1.0/org/0000755000175000017500000000000012475375714014754 5ustar felixfelixknopflerfish-osgi-5.1.0/org/knopflerfish/0000755000175000017500000000000012475375714017446 5ustar felixfelixknopflerfish-osgi-5.1.0/org/knopflerfish/tools/0000755000175000017500000000000012475375714020606 5ustar felixfelixknopflerfish-osgi-5.1.0/org/knopflerfish/tools/jarunpacker/0000755000175000017500000000000012475375720023110 5ustar felixfelixknopflerfish-osgi-5.1.0/META-INF/0000755000175000017500000000000012475375714015325 5ustar felixfelixknopflerfish-osgi-5.1.0/META-INF/MANIFEST.MF0000644000175000017500000000047012346515652016752 0ustar felixfelixManifest-Version: 1.0 Ant-Version: Apache Ant 1.9.4 Created-By: 1.6.0_65-b14-462-11M4609 (Apple Inc.) Main-class: org.knopflerfish.tools.jarunpacker.Main jarunpacker-destdir: knopflerfish_osgi_5.1.0 jarunpacker-opendir: ${destdir}/osgi jarunpacker-licensepath: /LICENSE.txt knopflerfish-version: 5.1.0 knopflerfish-osgi-5.1.0/fish32x32.gif0000644000175000017500000000246012346513620016274 0ustar felixfelixGIF89a !)!))))1)11119!19!99!9B)9B)BB1BJ1JJ9JJ9JRBRRBRZJZZJZcRccRckZckZkkckscsscs{ks{k{{s{s{{ƽ, HPpÆJ`E 3 FC^ĈQ .0A@Gc`!TH0%D@ vphiC*Z0ب  =G*DѣF ?j(X>+Zx@P D:@(*2wa@Z, N ~rl^ & 60 p7 =PH]%1AʩhB1@Nsp}-ޡ3/ java -jar framework.jar 3. This starts the framework + a large set of bundles, including the desktop Building: ---------------------------------------- Prerequisites - JDK 1.6 (or 1.5), available from Oracle. See http://java.com/en/download/faq/java_6.xml for details. Note that JDK 1.7 or later can NOT be used to build Knopflerfish, but Knopflerfish will run on them. - Ant 1.8.1 or later, available from ant.apache.org. - openssl, to create and manipulate certificates when using security and the Conditional Permission Admin (CPA) service. Test suites for CPA can not be built and executed without openssl. - ProGuard 4, tested with 4.10. This is only need if you want to build the compact version of the framework. 1. Step into the osgi dir 2. Start the build by: > ant all knopflerfish-osgi-5.1.0/LICENSE.txt0000644000175000017500000000274412346515440016004 0ustar felixfelixCopyright (c) 2003-2014, KNOPFLERFISH project All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the KNOPFLERFISH project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. knopflerfish-osgi-5.1.0/knopflerfish_red400pxl.gif0000644000175000017500000001573512346513620021146 0ustar felixfelixGIF89aK!)!))))1)11119!19!99!9B)99)9B)BB)BJ1BB1BJ1JJ9BJ9JJ9JR9RRBJRBRRBRZBZZJRZJZZJZcRZZRZcRccRckZccZckZkkZksckkckscsskssks{k{{s{{s{s{{{{{ƽ,KH*\ȰÇ#JHŋ3jx1 ? Irɒ(OLr˖0_ʌIs͚8osϞ@ 9#AE "TQPJM:iTXVu֮M^J֫Y[т{ڲoۦuKwݵwF5*Ҿ&&ˆ +X/~,qĖ+SƼyeϚ?g,hФCNM:+_ƞ l۴oݿ{.xđO|sؖ-`%u)]>w৆'|ß~w2% :@tpB .|U}avކ~v("kX"*".fpJup LX1  e6vRXA雔QIOwY2%w[zycrYkd!PBM@m`0C]0mt'z)&UQ*U>(|*i!Zަ:Ji8ş-ed!v iXiJc#"I,g(ڤf: G41) Y D{nꬡl rݻo -G.(Q+T yH- D]ȀHA:<006֬,𑹝ܢ%<%< ]`CMXd(QRt sLuy(_}YWz[ܫ IF< "Jх"vKxY4=pc)h]yѐx7>82JvaE @K+a4YXwW02cV^-5Q{ +\"E ]; ctx}aPW)Iظy;{sa#@ "T`dqAʠ=p\Zv0IIHfK|HPg\E"$AݹW"އnQL)^\` Dpia0BE W1 /UDBv_!%t!0)8b^PK+94,RHHDreߺ1G "& B'q !x pDs SƓ8ZYLtyFF)h)1# B0G@w  KPi.ON\ ¾R_ #TK>X|E8ўZa'_f: @Us "EI_o"gKrŐk^Oo@#`$Q )A|Qfvf)'+-EkfEzQyou♒=1 y JLq[8EOˉL4DtcיQx}ceٴ0RTX@$Uܬr VM+.pfCF8y Ҩ$/ h7܋~p>`u N D pb͔z[EnJ10aK yrc  C,D ?]3fQL;@ |,p ns̕b>i! MIt` Ax-Y':W K#V { rط.x) Ve8jUjl6/Ə/"UJ:]H:,8K4E? ym]&`2xVU| l2G,DG M0t #V>P_D9 ҢB&4 Rtׂ+Mtr/HfiB0hB5̹ۘow _ɚl;4Vh/n5^pZLP:~F'kw4sV:yr5`dFZe}hyGY^r,]m|-ɾ [E-? g<@΍tmNWsA:ϩ|VGw ȂL*pu=:NB#2x) <8 .u`"*$ @8B)o!@bA<" A }pxN@P$ .0qx@3$$A H0࿝[@wAeP.>Z)PWP=^wD6p2D@y}!|Vml[@7wTW&RtzWZ!_@c1b0ӂ6HP(c] t]`?`;Pb>haY`BP l%p Ƃ.80Y\&J]K CQWgK-KWMEW#Oca`?Y0$PJ,b2@&vDJsƂhX>:R`u%VƄ^01.0ZFxa2z:2@bvDYPg4uFQ#{i30wLF[vD\@dq+hK37Jm7nT7H]@m"o"Bxb=Fg]_eߘ:XZES`Jb1yBio7U(P#1~|`$PS hA@@$6J,5jS%&VgP pR`30*B>=0OK:WGk3>HRL`XPMcS/4c[cXPɔQy>@Z@gSPZ ~B )=L=J@IHIE&#>(@t_QtFG!ZJQ0H@PRZu6y&p`Ud9$whI1 %V:DDr6e~`UK۸4R`(3[ ~)Yu0Xtf0>$Y*`$/r1 PM_FZfT@ZqE1UQ.Gd yfFMHrդpuf? E0P?#7 z14>$g@<ڣXR[Pg9IVyoZ`N0d>Tg"PFZz&@t}6Qu=@FGN7x) D#% pEgHѡդљ`Re)5h.!Igp >S`)eU676c;AcJ"p\JZUIZXQwh{e}Zg#iJgQՔޤմdUYg;]pb&dFa$P]FʎڱZ՗6#&WXԦ U#|lL@UB0 r\Fm~>xDd $iUy &*AK nDWuE-]zD J*= P"P$0$/rՄMQ`/*ZM9qo!P[a^}ItfRQP=J852RVAhJ*JBFe4 up [Hw JF`V+u#1s :;ZR{D @RpP?pՔJ}iѰ}c+!e(Le|oZgG#:@+F9;hF ))@EPa #RB+&]Pl Z:P`>0207:ER0e$QOP:+p&P( D&ƻ4cg&p17R@q]ֆF1ñ!p+2$xjqq%[*jYP;q*zתHp@ER:}$_bhBįbA!=`8T9\gpkAYW hMw< C  >0&)Pt@rdd+@~\qxth7SV}C9Yc&Ax,pGg;n @g+,A |) \ @0qGA P/@7B6@+@V  r 80,ipK! iC(5p6p:}g <;I2(3pF:p ] ldD[BfK{T1xۈ/ 5,f;0eqѯ5(F7(Y]8PC\GxaAEzQqEvDXVhW Q9%q`LgƋU5is6Y #E#ELz:U@\[ >&$7Pe|KMM#5vفدcq$ĕXKؼmA59e;avXRk.!hWMv)E8241)vnaQM8h85qa}Q5n}eK^U@P/Kfތq,P]{Nnv±SQ"R>k8@CUvD`ֆGuYk@g5V)]Aۣ6aNm'dSÊ.?PS&Ф}?DrkwD@eȍAZ3fO]&!}杼2Kr2p8q_qmdt5Y8s^SYNTߓ/C87SPEl~Yf`Blhe$Wa;Xn/6CM.Rrx`¡\A6h)#B'^EK}>vXGA,Bpd3+!1S9J@1fY7BH$~k%VVKcJPlmvc?t7i{!@UVxP*_I0Ulմ-ٗFߝQCn/Rn~ U L1 UFbVk@@l,M|@Uݪ1B+ۢ&oV7502`S1itQ4/UD?>m\M85Sw\PPAdPJ+dcEKn&r/Ÿp0A aX P!*&"4qACz )$I"%\QI._a˙#Aܙ%ϛ6s9ΣI- iʈ2N5igXd(e͈\,ESI2 ХJiMi\s8`,1\ 7eʖ RK A6s$8r1w!g.WlvN~nͰ׶-0ɍ.<^|xHta@):IGzNq8*-`궫?zـk)$[? 0?ߦ.V"Š%Lp x2!6 X.|@kPc?+1;=擱+N@6 С1`q (F >>ނ4oH3\ǽ @q3wmP:g}\njɹsT^U9Lo67{cOg^ϵ%xsw}}kuqe6OyBl}~k 6H!% ;knopflerfish-osgi-5.1.0/changelog.txt0000644000175000017500000006412312346513700016645 0ustar felixfelix2014-06-13 00:51:04 +0200 (Fri, 13 Jun 2014), revision 4320, cl Renamed Application-Icon => Bundle-Icon to map 1:1 with manifest header name U knopflerfish.org/trunk/ant/bundlebuild.xml U knopflerfish.org/trunk/osgi/bundles_opt/desktop_displayers/boing/build.xml 2014-06-12 22:19:49 +0200 (Thu, 12 Jun 2014), revision 4319, cl Added support to include content from ${out.dir}/resources. To be used when adding dynamically created resources in e.g. a custom.pre target U knopflerfish.org/trunk/ant/bundlebuild.xml 2014-06-12 17:20:29 +0200 (Thu, 12 Jun 2014), revision 4318, jan Fixed some small problems in preparation for next KF release. U knopflerfish.org/trunk/osgi/framework/build.xml U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/Main.java U knopflerfish.org/trunk/release_notes.in.html 2014-06-12 12:17:11 +0200 (Thu, 12 Jun 2014), revision 4317, cl Added bundle icon for Prefs. Changed to use Bundle-Icon for UserAdmin U knopflerfish.org/trunk/osgi/bundles/prefs/bundle.manifest A knopflerfish.org/trunk/osgi/bundles/prefs/resources/ A knopflerfish.org/trunk/osgi/bundles/prefs/resources/icon.png U knopflerfish.org/trunk/osgi/bundles/useradmin/bundle.manifest U knopflerfish.org/trunk/release_notes.in.html 2014-06-12 11:50:26 +0200 (Thu, 12 Jun 2014), revision 4316, jan Changed RSA key length to avoid restrictions in Java 7 and later. Be more flexible in validation date parsing. U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/build_keystore.xml U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/validator/JKSValidator.java 2014-06-10 19:39:20 +0200 (Tue, 10 Jun 2014), revision 4315, jan Fixed listRescources (SF#178) and added a testcase. Detect dead-lock when doing dynamic import in permssion check (SF#179). U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/Activator.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/BadBundleListener.java A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/BundleWiringTestSuite.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/CapabilityTestSuite.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/FWTestCase.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/FragmentTestSuite.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/FrameworkTestSuite.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/NativeCodeTestSuite.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/PackageAdminTestSuite.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/PackageTestSuite.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/PermissionTest.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/PermissionTestSuite.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/RegListenThread.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/RegServThread.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/RequireBundleTestSuite.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/ServiceListenerTestSuite.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/Util.java U knopflerfish.org/trunk/osgi/framework/build.xml U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/BundleClassLoader.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/Resolver.java U knopflerfish.org/trunk/osgi/init-tests.xargs.in U knopflerfish.org/trunk/release_notes.in.html 2014-06-09 14:43:48 +0200 (Mon, 09 Jun 2014), revision 4314, jan Add framework property to put framework in read-only mode. U knopflerfish.org/trunk/osgi/framework/doc/index.html U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/FWProps.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/FrameworkContext.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/Main.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/StartLevelController.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/Util.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/Archive.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/BundleArchiveImpl.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/BundleStorageImpl.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermissionInfoStorage.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/permissions/PermissionInfoStorage.java U knopflerfish.org/trunk/release_notes.in.html 2014-06-09 08:00:49 +0200 (Mon, 09 Jun 2014), revision 4313, jan Added framework resource protocol U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/src/org/knopflerfish/bundle/component_test/ComponentTestSuite.java U knopflerfish.org/trunk/osgi/framework/build.xml U knopflerfish.org/trunk/osgi/framework/doc/index.html A knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/FWResourceURLStreamHandler.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/FrameworkContext.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/Main.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/ServiceURLStreamHandlerFactory.java U knopflerfish.org/trunk/release_notes.in.html 2014-05-15 17:53:50 +0200 (Thu, 15 May 2014), revision 4312, ekolin Fix buidling of the compact framework version when using Java SE 7+. U knopflerfish.org/trunk/osgi/framework/build.xml 2014-04-11 09:58:17 +0200 (Fri, 11 Apr 2014), revision 4311, ekolin Make sure that CM-Desktop can be installed by the Desktop Repository when using the Felix Resolver service. U knopflerfish.org/trunk/KnopflerfishEclipseDictionary.txt U knopflerfish.org/trunk/osgi/bundles/metatype/cm_desktop/build.xml U knopflerfish.org/trunk/osgi/bundles/metatype/cm_desktop/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/build.xml U knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/bundle.manifest U knopflerfish.org/trunk/release_notes.in.html 2014-04-11 09:07:19 +0200 (Fri, 11 Apr 2014), revision 4310, ekolin The eol format was mixed, change to on all lines U knopflerfish.org/trunk/osgi/template.xargs.in 2014-03-19 13:25:40 +0100 (Wed, 19 Mar 2014), revision 4309, perg Made UserAdmin self-contained wrt kf log utility U knopflerfish.org/trunk/osgi/bundles/useradmin/build.xml U knopflerfish.org/trunk/osgi/bundles/useradmin/bundle.manifest U knopflerfish.org/trunk/release_notes.in.html 2014-02-25 16:00:35 +0100 (Tue, 25 Feb 2014), revision 4308, perg Changed spelling error sources to source U knopflerfish.org/trunk/ant/bundletasks.xml 2014-02-24 21:52:00 +0100 (Mon, 24 Feb 2014), revision 4307, perg Fixed bug in kf_metatype bundle and refactored handling of standardized and proprietary xml formats. U knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/src/org/knopflerfish/bundle/metatype/Activator.java A knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/src/org/knopflerfish/util/metatype/KFLegacyMetaTypeParser.java A knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/src/org/knopflerfish/util/metatype/OsgiMetaTypeXmlParser.java U knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/src/org/knopflerfish/util/metatype/SystemMetatypeProvider.java U knopflerfish.org/trunk/release_notes.in.html 2014-02-20 13:40:39 +0100 (Thu, 20 Feb 2014), revision 4306, jan Fixed an IllegalStateException for factory components. U knopflerfish.org/trunk/osgi/bundles/component/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/ReferenceListener.java U knopflerfish.org/trunk/release_notes.in.html 2014-02-14 21:46:06 +0100 (Fri, 14 Feb 2014), revision 4305, jan U knopflerfish.org/trunk/osgi/bundles/cm/cm/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/cm/cm/src/org/knopflerfish/bundle/cm/ConfigurationAdminFactory.java U knopflerfish.org/trunk/osgi/bundles/cm/cm/src/org/knopflerfish/bundle/cm/ConfigurationStore.java U knopflerfish.org/trunk/release_notes.in.html 2014-02-05 17:24:41 +0100 (Wed, 05 Feb 2014), revision 4304, ekolin Http 4.0.5; more fixes for handling of transfer encoding chunked. U knopflerfish.org/trunk/osgi/bundles/http/http/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/http/http/src/org/knopflerfish/bundle/http/RequestImpl.java U knopflerfish.org/trunk/release_notes.in.html 2014-01-29 13:32:42 +0100 (Wed, 29 Jan 2014), revision 4303, ekolin Add missing ignore for generated file. _U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/resources/ 2014-01-29 12:04:57 +0100 (Wed, 29 Jan 2014), revision 4302, ekolin Rewrite unchunk code to simple read the number of bytes that the shunk shall contian, ignoring any CR or LF in the data. U knopflerfish.org/trunk/osgi/bundles/http/http/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/http/http/src/org/knopflerfish/bundle/http/RequestImpl.java U knopflerfish.org/trunk/release_notes.in.html 2014-01-29 11:10:48 +0100 (Wed, 29 Jan 2014), revision 4301, perg Improvements to Repository Desktop and some minor fixes U knopflerfish.org/trunk/osgi/bundles/repository/repository_desktop/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/repository/repository_desktop/src/org/knopflerfish/bundle/repository_desktop/RepositoryDisplayer.java U knopflerfish.org/trunk/osgi/bundles/repository/repository_xml/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/repository/repository_xml/src/org/knopflerfish/bundle/repository/xml/CapabilityImpl.java U knopflerfish.org/trunk/osgi/bundles/repository/repository_xml/src/org/knopflerfish/bundle/repository/xml/RequirementImpl.java U knopflerfish.org/trunk/osgi/bundles/repository/repository_xml/src/org/knopflerfish/bundle/repository/xml/ResourceImpl.java U knopflerfish.org/trunk/release_notes.in.html 2014-01-29 10:19:30 +0100 (Wed, 29 Jan 2014), revision 4300, ekolin Fix problem with decoding of chunked tranfer encoding in the Htt-Server. U knopflerfish.org/trunk/osgi/bundles/http/http/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/http/http/src/org/knopflerfish/bundle/http/RequestImpl.java U knopflerfish.org/trunk/release_notes.in.html 2014-01-22 10:43:46 +0100 (Wed, 22 Jan 2014), revision 4298, jan Fixed bug with ConditionalPermissionUpdate. U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/condpermadmin_test/src/org/knopflerfish/bundle/condpermadmin_test/CondPermAdminTestSuite.java U knopflerfish.org/trunk/osgi/framework/build.xml U knopflerfish.org/trunk/osgi/framework/doc/index.html U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermissionInfoStorage.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/validator/JKSValidator.java U knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/validator/SelfSignedValidator.java U knopflerfish.org/trunk/release_notes.in.html 2013-12-12 14:55:26 +0100 (Thu, 12 Dec 2013), revision 4296, perg Fixed spelling error: source -> sources U knopflerfish.org/trunk/ant/bundletasks.xml 2013-12-12 13:44:26 +0100 (Thu, 12 Dec 2013), revision 4295, perg Work in progress - support for repoindex U knopflerfish.org/trunk/tools/mvnrepo/build.xml 2013-12-12 13:42:21 +0100 (Thu, 12 Dec 2013), revision 4294, perg Work in progress - support for repoindex U knopflerfish.org/trunk/tools/mvnrepo/build.xml A knopflerfish.org/trunk/tools/mvnrepo/mvnrepoindex2html.xsl 2013-12-12 13:20:25 +0100 (Thu, 12 Dec 2013), revision 4293, perg Work in progress - support for repoindex U knopflerfish.org/trunk/ant/bundletasks.xml 2013-12-12 12:47:13 +0100 (Thu, 12 Dec 2013), revision 4292, perg Work in progress - support for repoindex U knopflerfish.org/trunk/ant/bundletasks.xml 2013-12-12 12:25:07 +0100 (Thu, 12 Dec 2013), revision 4291, perg Work in progress - support for repoindex U knopflerfish.org/trunk/tools/mvnrepo/build.xml 2013-12-12 12:21:20 +0100 (Thu, 12 Dec 2013), revision 4290, perg Work in progress - support for repoindex U knopflerfish.org/trunk/tools/mvnrepo/build.xml 2013-12-12 12:14:02 +0100 (Thu, 12 Dec 2013), revision 4289, perg Work in progress - support for repoindex U knopflerfish.org/trunk/tools/mvnrepo/build.xml 2013-12-11 10:32:25 +0100 (Wed, 11 Dec 2013), revision 4288, jan Fixed a bug that caused factory components to be falsely created or missed being created when we use target filters. Also added test-cases for this. U knopflerfish.org/trunk/osgi/bundles/component/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/Component.java U knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/DelayedComponent.java U knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/FactoryComponent.java U knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/ImmediateComponent.java U knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/Reference.java U knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/ReferenceListener.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/build.xml U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/bundle.manifest U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/src/org/knopflerfish/bundle/component_test/ComponentTestSuite.java A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/ A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/build.xml A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/bundle.manifest A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/resources/ A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/resources/service.xml A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/ A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/ A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/ A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/bundle/ A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/bundle/componentM_test/ A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/bundle/componentM_test/ComponentAImpl.java A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/bundle/componentM_test/ComponentB1Impl.java A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/bundle/componentM_test/ComponentB2Impl.java A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/bundle/componentM_test/ComponentCImpl.java A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/service/ A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/service/componentM_test/ A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/service/componentM_test/ComponentA.java A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/service/componentM_test/ComponentB.java A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/service/componentM_test/ComponentC.java U knopflerfish.org/trunk/release_notes.in.html 2013-12-10 13:45:26 +0100 (Tue, 10 Dec 2013), revision 4287, perg Corrected bundle and package versions U knopflerfish.org/trunk/osgi/bundles/repository/repository_desktop/src/org/knopflerfish/bundle/repository_desktop/RepositoryDisplayer.java U knopflerfish.org/trunk/osgi/bundles/repository/repositorycommands/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/service/repositorymanager/packageinfo U knopflerfish.org/trunk/release_notes.in.html 2013-12-09 14:56:08 +0100 (Mon, 09 Dec 2013), revision 4286, perg Improved support for Resolver in Repository Manager. Updated Repository console and desktop bundles to use the improved support. Embedded Resolver and Repository APIs in Repository Manager. U knopflerfish.org/trunk/osgi/bundles/repository/repository_desktop/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/repository/repository_desktop/src/org/knopflerfish/bundle/repository_desktop/RepositoryDisplayer.java U knopflerfish.org/trunk/osgi/bundles/repository/repositorycommands/src/org/knopflerfish/bundle/repositorycommands/RepositoryCommandGroup.java U knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/build.xml U knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/bundle/repositorymanager/RepositoryManagerImpl.java U knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/service/repositorymanager/RepositoryManager.java U knopflerfish.org/trunk/osgi/template.xargs.in U knopflerfish.org/trunk/release_notes.in.html 2013-11-18 11:26:55 +0100 (Mon, 18 Nov 2013), revision 4285, perg Updated w/ Resolver related updates U knopflerfish.org/trunk/release_notes.in.html 2013-11-16 00:14:56 +0100 (Sat, 16 Nov 2013), revision 4284, perg Added commented out line to install a resolver U knopflerfish.org/trunk/osgi/template.xargs.in 2013-11-15 23:44:51 +0100 (Fri, 15 Nov 2013), revision 4283, perg Added support for Resolver Service 1.0 U knopflerfish.org/trunk/osgi/bundles/repository/repositorycommands/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/repository/repositorycommands/src/org/knopflerfish/bundle/repositorycommands/Activator.java U knopflerfish.org/trunk/osgi/bundles/repository/repositorycommands/src/org/knopflerfish/bundle/repositorycommands/RepositoryCommandGroup.java U knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/build.xml U knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/bundle/repositorymanager/Activator.java U knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/bundle/repositorymanager/RepositoryManagerImpl.java A knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/bundle/repositorymanager/ResolveContextImpl.java U knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/service/repositorymanager/RepositoryManager.java U knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/service/repositorymanager/packageinfo 2013-11-15 23:44:02 +0100 (Fri, 15 Nov 2013), revision 4282, perg Fix in equals impl U knopflerfish.org/trunk/osgi/bundles/repository/repository_xml/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/repository/repository_xml/src/org/knopflerfish/bundle/repository/xml/CapabilityImpl.java 2013-10-24 14:49:23 +0200 (Thu, 24 Oct 2013), revision 4280, perg Updated release notes and set correct bundle version U knopflerfish.org/trunk/osgi/bundles/repository/repoindex_kf/bundle.manifest U knopflerfish.org/trunk/release_notes.in.html 2013-10-24 14:34:07 +0200 (Thu, 24 Oct 2013), revision 4279, perg Updated changelog.txt U knopflerfish.org/trunk/changelog.txt U knopflerfish.org/trunk/osgi/bundles_opt/junit/osgi_ct_adapter/src/org/knopflerfish/bundle/osgi_ct_adapter/Activator.java 2013-10-24 14:26:15 +0200 (Thu, 24 Oct 2013), revision 4278, perg Fixed parsing of Bundle-License U knopflerfish.org/trunk/osgi/bundles/repository/repoindex_kf/bundle.manifest 2013-10-24 14:21:24 +0200 (Thu, 24 Oct 2013), revision 4277, perg Fixed parsing of Bundle-License U knopflerfish.org/trunk/osgi/bundles/repository/repoindex_kf/src/org/knopflerfish/bundle/repository/index/KnopflerfishExtentions.java A knopflerfish.org/trunk/osgi/bundles/repository/repoindex_kf/src/org/knopflerfish/bundle/repository/index/Util.java 2013-10-23 18:00:48 +0200 (Wed, 23 Oct 2013), revision 4276, jan Fixed a bug that caused problems when adding a CM configuration with a target filter to an unsatisfied component. U knopflerfish.org/trunk/osgi/bundles/component/bundle.manifest U knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/Component.java U knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/ReferenceListener.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/src/org/knopflerfish/bundle/component_test/ComponentTestSuite.java U knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentC_test/resources/service.xml A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentC_test/src/org/knopflerfish/bundle/componentC_test/ComponentUImpl.java A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentC_test/src/org/knopflerfish/bundle/componentC_test/ComponentVImpl.java A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentC_test/src/org/knopflerfish/service/componentC_test/ComponentU.java A knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentC_test/src/org/knopflerfish/service/componentC_test/ComponentV.java U knopflerfish.org/trunk/release_notes.in.html 2013-10-23 17:50:15 +0200 (Wed, 23 Oct 2013), revision 4275, jan Update framework documentation with some 5.0.0 changes. U knopflerfish.org/trunk/osgi/framework/doc/index.html U knopflerfish.org/trunk/osgi/framework/resources/help.txt 2013-10-23 10:17:09 +0200 (Wed, 23 Oct 2013), revision 4274, ekolin Switch to proguard 4.10 U knopflerfish.org/trunk/ant/build.xml U knopflerfish.org/trunk/ant/bundletasks.xml U knopflerfish.org/trunk/osgi/framework/build.xml 2013-10-22 16:44:48 +0200 (Tue, 22 Oct 2013), revision 4273, ekolin Automatically download proguard from maven central. U knopflerfish.org/trunk/ant/bundletasks.xml U knopflerfish.org/trunk/osgi/framework/build.xml 2013-10-22 15:53:19 +0200 (Tue, 22 Oct 2013), revision 4272, ekolin Remove reference to OSGiR4v4.3 U knopflerfish.org/trunk/osgi/framework/doc/index.html 2013-10-22 13:40:10 +0200 (Tue, 22 Oct 2013), revision 4271, ekolin Fix another bundle repository link. U knopflerfish.org/trunk/htdocs/html_templates/template.html 2013-10-22 13:03:21 +0200 (Tue, 22 Oct 2013), revision 4270, ekolin Nightly builds should say maintenance release, not major release... U knopflerfish.org/trunk/release_notes.in.html 2013-10-22 12:56:46 +0200 (Tue, 22 Oct 2013), revision 4269, ekolin Remove some warnings for the ant tasks. Fix link to Makewave logo in nightlybuilds page. U knopflerfish.org/trunk/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleArchives.java U knopflerfish.org/trunk/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleInfoTask.java U knopflerfish.org/trunk/tools/nightlybuild/snap_index.html.pre 2013-10-21 21:06:51 +0200 (Mon, 21 Oct 2013), revision 4267, jan Post release 5.0.0 update U knopflerfish.org/trunk/build.xml U knopflerfish.org/trunk/release_notes.in.html 2013-10-21 21:01:35 +0200 (Mon, 21 Oct 2013), revision 4266, ekolin Fix href to the style sheet. U knopflerfish.org/trunk/ant/bundletasks.xml 2013-10-21 21:01:14 +0200 (Mon, 21 Oct 2013), revision 4265, jan update version U knopflerfish.org/trunk/tools/mvnrepo/build.xml 2013-10-21 20:57:21 +0200 (Mon, 21 Oct 2013), revision 4264, ekolin Bundle repository link should point to the new repository file. U knopflerfish.org/trunk/htdocs/html_src/release_page.html.in 2013-10-21 19:25:29 +0200 (Mon, 21 Oct 2013), revision 4261, ekolin Also search for the repoindex bundle in the direcotry to index. U knopflerfish.org/trunk/ant/bundletasks.xml 2013-10-21 17:29:38 +0200 (Mon, 21 Oct 2013), revision 4260, ekolin U knopflerfish.org/trunk/changelog.txt 2013-10-21 17:02:56 +0200 (Mon, 21 Oct 2013), revision 4259, ekolin Merge of the KF-5 development branch. knopflerfish-osgi-5.1.0/osgi/0000755000175000017500000000000012475375720015123 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/init-tests.xargs0000644000175000017500000001011412346515440020261 0ustar felixfelix# # Startup file for framework testing # # List of test IDs #-Forg.knopflerfish.junit_runner.tests=PerformanceRegistryTestSuite -Forg.knopflerfish.junit_runner.tests=filter:(objectclass=junit.framework.TestSuite) #-Forg.knopflerfish.junit_runner.tests=FrameworkTestSuite ServiceTrackerTestSuite ConstantsTestSuite FilterTestSuite -Forg.knopflerfish.bundle.perf.servicereg.nlisteners=100 -Forg.knopflerfish.bundle.perf.servicereg.nservices=1000 # true means "quit framework when all tests are run" -Forg.knopflerfish.junit_runner.quit=true # Initial startup verbosity, 0 is low verbosity -Dorg.knopflerfish.framework.main.verbosity=0 # Prefix for searching for bundle URLs from console or command line -Dorg.knopflerfish.gosg.jars=file:jars/;file:test_jars/ # Various debug flags -Forg.knopflerfish.framework.debug.resolver=false -Forg.knopflerfish.framework.debug.errors=false -Forg.knopflerfish.framework.debug.warnings=false -Forg.knopflerfish.framework.debug.classloader=false -Forg.knopflerfish.framework.debug.startlevel=false -Forg.knopflerfish.framework.debug.ldap=false -Forg.knopflerfish.framework.debug.service_reference=false -Forg.knopflerfish.framework.debug.bundle_resource=false -Forg.knopflerfish.framework.debug.permissions=false -Forg.knopflerfish.framework.debug.lazy_activation=false -Forg.knopflerfish.framework.debug.framework=false -Forg.knopflerfish.framework.debug.certificates=false # JKSValidator properties -Forg.knopflerfish.framework.validator=JKSValidator -Forg.knopflerfish.framework.validator.jks.ca_certs=${user.dir}/test_jars/test.castore -Forg.knopflerfish.framework.validator.jks.ca_certs_password=catest # Avoid java verifier bug -Forg.knopflerfish.framework.bundlestorage.file.jar_verifier_bug=true # Comma-separated list of packges exported by system classloader -Forg.osgi.framework.system.packages.extra= # Web server properties -Forg.knopflerfish.http.dnslookup=false -Forg.osgi.service.http.port=0 -Forg.knopflerfish.startlevel.use=true # Log service properties -Forg.knopflerfish.log.out=false -Forg.knopflerfish.log.level=info -Forg.knopflerfish.log.grabio=true -Forg.knopflerfish.log.file=true # bootdelegation # The test case FRAME163a requires boot delegation for javax.naming # to actually check that it works. -Forg.osgi.framework.bootdelegation=sun.*,javax.naming # Shall bc.getService(ServiceReference) return the service while it is # in the state unregistering or not. -Forg.knopflerfish.servicereference.valid.during.unregistering=true # Directory to store preferences in. -Forg.knopflerfish.prefs.dir=junit_grunt/prefs # Native code testing -Forg.osgi.framework.os.name=linux -Forg.osgi.framework.processor=arm_le -init -initlevel 1 -install log/log_all-5.0.0.jar -install cm/cm_all-5.0.1.jar -install console/console_all-4.0.1.jar -install event/event_all-4.0.1.jar -initlevel 2 -install util/util-4.1.0.jar -install jsdk/jsdk_api-2.5.0.kf3-2.jar -istart junit/junit_all-3.8.1.kf4-001.jar -istart kxml/kxml-2.3.0.kf4-001.jar -initlevel 4 -install http/http_all-4.0.5.jar -install io/io_all-4.0.0.jar -install prefs/prefs_all-4.0.2.jar # the test cases -istart framework_test/framework_test-1.0.3.jar -istart filter_test/filter_test-1.0.0.jar -istart servicetracker_test/servicetracker_test-1.0.1.jar -istart constants_test/constants_test-1.0.0.jar -istart registryperformance_test/registryperformance_test-1.0.0.jar ## eventadmin_tests are disabled because of timing problems on Linux!? #-istart eventadmin_test/eventadmin_test-1.0.0.jar -istart http_test/http_test-1.0.0.jar -istart io_test/io_test-1.0.0.jar -istart preferences_test/preferences_test-1.0.0.jar -istart startlevel_test/startlevel_test-1.0.0.jar -istart condpermadmin_test/condpermadmin_test-1.0.0.jar # packages required by component_test -start log/log_all-5.0.0.jar -start cm/cm_all-5.0.1.jar -istart component/component_all-5.0.3.jar -istart component_test/component_test-1.6.0.jar -startlevel 7 -start http/http_all-4.0.5.jar -start event/event_all-4.0.1.jar -start io/io_all-4.0.0.jar -start prefs/prefs_all-4.0.2.jar -launch # the test case runner bundle. -istart junit_runner/junit_runner_all-4.0.0.jar knopflerfish-osgi-5.1.0/osgi/init-tests.xargs.in0000644000175000017500000000750412346513636020704 0ustar felixfelix# # Startup file for framework testing # # List of test IDs #-Forg.knopflerfish.junit_runner.tests=PerformanceRegistryTestSuite -Forg.knopflerfish.junit_runner.tests=filter:(objectclass=junit.framework.TestSuite) #-Forg.knopflerfish.junit_runner.tests=FrameworkTestSuite ServiceTrackerTestSuite ConstantsTestSuite FilterTestSuite -Forg.knopflerfish.bundle.perf.servicereg.nlisteners=100 -Forg.knopflerfish.bundle.perf.servicereg.nservices=1000 # true means "quit framework when all tests are run" -Forg.knopflerfish.junit_runner.quit=true # Initial startup verbosity, 0 is low verbosity -Dorg.knopflerfish.framework.main.verbosity=0 # Prefix for searching for bundle URLs from console or command line -Dorg.knopflerfish.gosg.jars=$(GOSG_JARS) # Various debug flags -Forg.knopflerfish.framework.debug.resolver=false -Forg.knopflerfish.framework.debug.errors=false -Forg.knopflerfish.framework.debug.warnings=false -Forg.knopflerfish.framework.debug.classloader=false -Forg.knopflerfish.framework.debug.startlevel=false -Forg.knopflerfish.framework.debug.ldap=false -Forg.knopflerfish.framework.debug.service_reference=false -Forg.knopflerfish.framework.debug.bundle_resource=false -Forg.knopflerfish.framework.debug.permissions=false -Forg.knopflerfish.framework.debug.lazy_activation=false -Forg.knopflerfish.framework.debug.framework=false -Forg.knopflerfish.framework.debug.certificates=false # JKSValidator properties -Forg.knopflerfish.framework.validator=JKSValidator -Forg.knopflerfish.framework.validator.jks.ca_certs=$(TESTJARS)/test.castore -Forg.knopflerfish.framework.validator.jks.ca_certs_password=catest # Avoid java verifier bug -Forg.knopflerfish.framework.bundlestorage.file.jar_verifier_bug=true # Comma-separated list of packges exported by system classloader -Forg.osgi.framework.system.packages.extra= # Web server properties -Forg.knopflerfish.http.dnslookup=false -Forg.osgi.service.http.port=0 -Forg.knopflerfish.startlevel.use=true # Log service properties -Forg.knopflerfish.log.out=false -Forg.knopflerfish.log.level=info -Forg.knopflerfish.log.grabio=true -Forg.knopflerfish.log.file=true # bootdelegation # The test case FRAME163a requires boot delegation for javax.naming # to actually check that it works. -Forg.osgi.framework.bootdelegation=sun.*,javax.naming # Shall bc.getService(ServiceReference) return the service while it is # in the state unregistering or not. -Forg.knopflerfish.servicereference.valid.during.unregistering=true # Directory to store preferences in. -Forg.knopflerfish.prefs.dir=junit_grunt/prefs # Native code testing -Forg.osgi.framework.os.name=linux -Forg.osgi.framework.processor=arm_le -init -initlevel 1 -install @log_all-N.N.N.jar@ -install @cm_all-N.N.N.jar@ -install @console_all-N.N.N.jar@ -install @event_all-N.N.N.jar@ -initlevel 2 -install @util-N.N.N.jar@ -install @jsdk_api-N.N.N.jar@ -istart @junit_all-N.N.N.jar@ -istart @kxml-N.N.N.jar@ -initlevel 4 -install @http_all-N.N.N.jar@ -install @io_all-N.N.N.jar@ -install @prefs_all-N.N.N.jar@ # the test cases -istart @framework_test-N.N.N.jar@ -istart @filter_test-N.N.N.jar@ -istart @servicetracker_test-N.N.N.jar@ -istart @constants_test-N.N.N.jar@ -istart @registryperformance_test-N.N.N.jar@ ## eventadmin_tests are disabled because of timing problems on Linux!? #-istart @eventadmin_test-N.N.N.jar@ -istart @http_test-N.N.N.jar@ -istart @io_test-N.N.N.jar@ -istart @preferences_test-N.N.N.jar@ -istart @startlevel_test-N.N.N.jar@ $(DO_CPA_TEST)-istart @condpermadmin_test-N.N.N.jar@ # packages required by component_test -start @log_all-N.N.N.jar@ -start @cm_all-N.N.N.jar@ -istart @component_all-N.N.N.jar@ -istart @component_test-N.N.N.jar@ -startlevel 7 -start @http_all-N.N.N.jar@ -start @event_all-N.N.N.jar@ -start @io_all-N.N.N.jar@ -start @prefs_all-N.N.N.jar@ -launch # the test case runner bundle. -istart @junit_runner_all-N.N.N.jar@ knopflerfish-osgi-5.1.0/osgi/kf20000644000175000017500000000462512346513624015531 0ustar felixfelix#!/bin/sh JAVA=java # the default java command BOOTCLASSPATH_FLAG="-Xbootclasspath/a:" # the bootclass path flag for the specific CLASSPATH_FLAG="-classpath " # the class path flag for the specific # constants KF_MAIN_CLASS=org.knopflerfish.framework.Main # path to main class if [ -f framework.jar ] ; then KF_CLASSPATH=framework.jar # the class path to use else KF_CLASSPATH=framework_compact.jar # the class path to use fi # args always sent to the JRE KF_JRE_ARGS="-Dorg.knopflerfish.framework.usingwrapperscript=true" EXIT_CODE_RESTART=200 # Read all the args. args_orig="" # all -xargs and -init args args="" # like args excepts for -xargs and -init args jre_args="" # arguments for the jre fwdir="`pwd`/fwdir" # default framework dir init=0 # whether the -init flag has been given or not. # read the arguments while [ -n "$1" ] do case "$1" in "-init" ) init=1; args_orig=$args_orig" "$1;; "-xargs" ) shift; args_orig=$args_orig" -xargs "$1;; "--" ) shift; break;; "---" ) break;; * ) args=$args" "$1;; esac shift done # the rest is jre-specific args while [ -n "$1" ] do case "$1" in "-Dorg.osgi.framework.dir="* ) fwdir=`echo $1 | cut -c26-`;; # store fwdir. "---" ) shift; break ;; esac jre_args=$jre_args" "$1 shift done # command line options while [ -n "$1" ] do case "$1" in "-java" ) shift; JAVA="$1" ;; "-clean" ) shift; CLEAN_FWDIR=1 ;; "-classpathflag" ) shift; CLASSPATH_FLAG="$1" ;; # * "-bootclasspathflag" ) shift ; BOOTCLASSPATH_FLAG="$1" ;; * ) echo "Error: unknown option: $1" echo "Use option -help to see all options" exit 1 ;; esac shift done # *: are these needed? or are they standard? if [ $init = 1 ] ; then if [ -d $fwdir ] ; then rm -rf $fwdir if [ $? = 0 ] ; then echo "Removed existing fwdir $fwdir" else echo "Failed to remove existing fwdir $fwdir" fi fi fi retval=$EXIT_CODE_RESTART while [ "$retval" -eq $EXIT_CODE_RESTART ] do if [ -r $fwdir/boot_cp ] ; then bootclasspath=$BOOTCLASSPATH_FLAG`cat $fwdir/boot_cp` fi classpath=$CLASSPATH_FLAG$KF_CLASSPATH:$CLASSPATH $JAVA $bootclasspath $jre_args $KF_JRE_ARGS $classpath $KF_MAIN_CLASS $args_orig $args retval=$? # only use args_orig the first time args_orig= done exit $retval knopflerfish-osgi-5.1.0/osgi/build.xml0000644000175000017500000004441712346513670016751 0ustar felixfelix </HEAD> targetPage = "" + window.location.search; if (targetPage != "" && targetPage != "undefined") targetPage = targetPage.substring(1); if (targetPage.indexOf(":") != -1) targetPage = "undefined"; function loadFrames() { if (targetPage != "" && targetPage != "undefined") top.classFrame.location = top.targetPage; } ]]> knopflerfish-osgi-5.1.0/osgi/init.xargs0000644000175000017500000000613412346515370017132 0ustar felixfelix# # Generated from template.xargs # Knopflerfish release 5.1.0 # # load common properties -xargs props.xargs # Semicolon seprated list of base URLs for searching (completing) # bundle URLs in "-install URL" command line options and in the console. -Forg.knopflerfish.gosg.jars=file:jars/ # Comma seprated list of OSGi Repository xml URLs for instantiating # RepositoryServices -Forg.knopflerfish.repository.xml.urls=file:jars/index.xml, http://www.knopflerfish.org/releases/current/osgi/jars/index.xml ## Basic KF bundles -initlevel 1 -install log/log_all-5.0.0.jar -install cm/cm_all-5.0.1.jar -install console/console_all-4.0.1.jar -install component/component_all-5.0.3.jar -install event/event_all-4.0.1.jar -install prefs/prefs_all-4.0.2.jar -istart trayicon_fw/trayicon_fw-4.0.0.jar ## Some library bundles -initlevel 2 -install util/util-4.1.0.jar -install crimson/crimson-2.1.0.kf4-001.jar -install jsdk/jsdk_api-2.5.0.kf3-2.jar -install kxml/kxml-2.3.0.kf4-001.jar # The Bundle repo commands and desktop plugin -install repository_xml/repository_xml_all-1.0.2.jar -install repositorymanager/repositorymanager_all-1.2.0.jar -install repository_desktop/repository_desktop_all-1.1.1.jar ## More basic KF bundles -initlevel 3 -install device/device_all-4.0.1.jar -install useradmin/useradmin_all-4.1.1.jar -initlevel 4 -install http/http_all-4.0.5.jar ## console command bundles -initlevel 5 -install frameworkcommands/frameworkcommands-4.0.1.jar -install logcommands/logcommands-5.0.0.jar -install cm_cmd/cm_cmd-5.0.1.jar -install repositorycommands/repositorycommands-1.1.1.jar -install scrcommands/scrcommands-4.0.1.jar -install consoletty/consoletty-4.0.1.jar -install consoletelnet/consoletelnet-4.0.1.jar -initlevel 6 -install remotefw/remotefw_api-4.0.0.jar -install desktop/desktop_all-5.0.1.jar -initlevel 7 -install httproot/httproot-4.0.0.jar -startlevel 7 # Start of these bundles are delayed since this makes start # order dependencies much easier -start log/log_all-5.0.0.jar -start crimson/crimson-2.1.0.kf4-001.jar -start cm/cm_all-5.0.1.jar -start console/console_all-4.0.1.jar -start component/component_all-5.0.3.jar -start event/event_all-4.0.1.jar -start prefs/prefs_all-4.0.2.jar -start device/device_all-4.0.1.jar -start useradmin/useradmin_all-4.1.1.jar -start repository_xml/repository_xml_all-1.0.2.jar -start repositorymanager/repositorymanager_all-1.2.0.jar -start repository_desktop/repository_desktop_all-1.1.1.jar -start consoletty/consoletty-4.0.1.jar -start consoletelnet/consoletelnet-4.0.1.jar -start frameworkcommands/frameworkcommands-4.0.1.jar -start logcommands/logcommands-5.0.0.jar -start cm_cmd/cm_cmd-5.0.1.jar -start repositorycommands/repositorycommands-1.1.1.jar -start scrcommands/scrcommands-4.0.1.jar -start desktop/desktop_all-5.0.1.jar -start http/http_all-4.0.5.jar -start httproot/httproot-4.0.0.jar # Uncomment the following line to add Resolver support # -istart http://repo2.maven.org/maven2/org/apache/felix/org.apache.felix.resolver/1.0.0/org.apache.felix.resolver-1.0.0.jar knopflerfish-osgi-5.1.0/osgi/test-restart2.xargs0000644000175000017500000000101612346515440020702 0ustar felixfelix# # Restart file for framework restart testing # # NOTE: The base URLs for bundles assumes that the current working # directory is the osgi-direcotry when this xargs-file is used. # # List of test IDs -Forg.knopflerfish.junit_runner.tests=RestartTestSuite # true means "quit framework when all tests are run" -Forg.knopflerfish.junit_runner.quit=true # true means wait for complete framework start until run -Forg.knopflerfish.junit_runner.wait=false -Dorg.knopflerfish.gosg.jars=file:jars/;file:test_jars/ -launch knopflerfish-osgi-5.1.0/osgi/template.xargs.in0000644000175000017500000000524312346513624020407 0ustar felixfelix# # Generated from template.xargs # Knopflerfish release $(VERSION) # # load common properties -xargs props.xargs # Semicolon seprated list of base URLs for searching (completing) # bundle URLs in "-install URL" command line options and in the console. -Forg.knopflerfish.gosg.jars=$(GOSG_JARS) # Comma seprated list of OSGi Repository xml URLs for instantiating # RepositoryServices -Forg.knopflerfish.repository.xml.urls=$(REPOSITORY_XML_URLS) ## Basic KF bundles -initlevel 1 -install @log_all-N.N.N.jar@ -install @cm_all-N.N.N.jar@ -install @console_all-N.N.N.jar@ -install @component_all-N.N.N.jar@ -install @event_all-N.N.N.jar@ -install @prefs_all-N.N.N.jar@ $(AWT)-istart @trayicon_fw-N.N.N.jar@ ## Some library bundles -initlevel 2 -install @util-N.N.N.jar@ -install @crimson-N.N.N.jar@ -install @jsdk_api-N.N.N.jar@ -install @kxml-N.N.N.jar@ # The Bundle repo commands and desktop plugin -install @repository_xml_all-N.N.N.jar@ -install @repositorymanager_all-N.N.N.jar@ $(AWT)-install @repository_desktop_all-N.N.N.jar@ ## More basic KF bundles -initlevel 3 -install @device_all-N.N.N.jar@ -install @useradmin_all-N.N.N.jar@ -initlevel 4 -install @http_all-N.N.N.jar@ ## console command bundles -initlevel 5 -install @frameworkcommands-N.N.N.jar@ -install @logcommands-N.N.N.jar@ -install @cm_cmd-N.N.N.jar@ -install @repositorycommands-N.N.N.jar@ -install @scrcommands-N.N.N.jar@ -install @consoletty-N.N.N.jar@ -install @consoletelnet-N.N.N.jar@ -initlevel 6 $(AWT)-install @remotefw_api-N.N.N.jar@ $(AWT)-install @desktop_all-N.N.N.jar@ -initlevel 7 -install @httproot-N.N.N.jar@ $(OS_ARGS) -startlevel 7 # Start of these bundles are delayed since this makes start # order dependencies much easier -start @log_all-N.N.N.jar@ -start @crimson-N.N.N.jar@ -start @cm_all-N.N.N.jar@ -start @console_all-N.N.N.jar@ -start @component_all-N.N.N.jar@ -start @event_all-N.N.N.jar@ -start @prefs_all-N.N.N.jar@ -start @device_all-N.N.N.jar@ -start @useradmin_all-N.N.N.jar@ -start @repository_xml_all-N.N.N.jar@ -start @repositorymanager_all-N.N.N.jar@ $(AWT)-start @repository_desktop_all-N.N.N.jar@ -start @consoletty-N.N.N.jar@ -start @consoletelnet-N.N.N.jar@ -start @frameworkcommands-N.N.N.jar@ -start @logcommands-N.N.N.jar@ -start @cm_cmd-N.N.N.jar@ -start @repositorycommands-N.N.N.jar@ -start @scrcommands-N.N.N.jar@ $(AWT)-start @desktop_all-N.N.N.jar@ -start @http_all-N.N.N.jar@ -start @httproot-N.N.N.jar@ # Uncomment the following line to add Resolver support # -istart http://repo2.maven.org/maven2/org/apache/felix/org.apache.felix.resolver/1.0.0/org.apache.felix.resolver-1.0.0.jar knopflerfish-osgi-5.1.0/osgi/remote-init.xargs0000644000175000017500000000620712346515370020424 0ustar felixfelix# # Generated from template.xargs # Knopflerfish release 5.1.0 # # load common properties -xargs props.xargs # Semicolon seprated list of base URLs for searching (completing) # bundle URLs in "-install URL" command line options and in the console. -Forg.knopflerfish.gosg.jars=http://www.knopflerfish.org/releases/5.1.0/osgi/jars/ # Comma seprated list of OSGi Repository xml URLs for instantiating # RepositoryServices -Forg.knopflerfish.repository.xml.urls=file:jars/index.xml, http://www.knopflerfish.org/releases/current/osgi/jars/index.xml ## Basic KF bundles -initlevel 1 -install log/log_all-5.0.0.jar -install cm/cm_all-5.0.1.jar -install console/console_all-4.0.1.jar -install component/component_all-5.0.3.jar -install event/event_all-4.0.1.jar -install prefs/prefs_all-4.0.2.jar -istart trayicon_fw/trayicon_fw-4.0.0.jar ## Some library bundles -initlevel 2 -install util/util-4.1.0.jar -install crimson/crimson-2.1.0.kf4-001.jar -install jsdk/jsdk_api-2.5.0.kf3-2.jar -install kxml/kxml-2.3.0.kf4-001.jar # The Bundle repo commands and desktop plugin -install repository_xml/repository_xml_all-1.0.2.jar -install repositorymanager/repositorymanager_all-1.2.0.jar -install repository_desktop/repository_desktop_all-1.1.1.jar ## More basic KF bundles -initlevel 3 -install device/device_all-4.0.1.jar -install useradmin/useradmin_all-4.1.1.jar -initlevel 4 -install http/http_all-4.0.5.jar ## console command bundles -initlevel 5 -install frameworkcommands/frameworkcommands-4.0.1.jar -install logcommands/logcommands-5.0.0.jar -install cm_cmd/cm_cmd-5.0.1.jar -install repositorycommands/repositorycommands-1.1.1.jar -install scrcommands/scrcommands-4.0.1.jar -install consoletty/consoletty-4.0.1.jar -install consoletelnet/consoletelnet-4.0.1.jar -initlevel 6 -install remotefw/remotefw_api-4.0.0.jar -install desktop/desktop_all-5.0.1.jar -initlevel 7 -install httproot/httproot-4.0.0.jar -startlevel 7 # Start of these bundles are delayed since this makes start # order dependencies much easier -start log/log_all-5.0.0.jar -start crimson/crimson-2.1.0.kf4-001.jar -start cm/cm_all-5.0.1.jar -start console/console_all-4.0.1.jar -start component/component_all-5.0.3.jar -start event/event_all-4.0.1.jar -start prefs/prefs_all-4.0.2.jar -start device/device_all-4.0.1.jar -start useradmin/useradmin_all-4.1.1.jar -start repository_xml/repository_xml_all-1.0.2.jar -start repositorymanager/repositorymanager_all-1.2.0.jar -start repository_desktop/repository_desktop_all-1.1.1.jar -start consoletty/consoletty-4.0.1.jar -start consoletelnet/consoletelnet-4.0.1.jar -start frameworkcommands/frameworkcommands-4.0.1.jar -start logcommands/logcommands-5.0.0.jar -start cm_cmd/cm_cmd-5.0.1.jar -start repositorycommands/repositorycommands-1.1.1.jar -start scrcommands/scrcommands-4.0.1.jar -start desktop/desktop_all-5.0.1.jar -start http/http_all-4.0.5.jar -start httproot/httproot-4.0.0.jar # Uncomment the following line to add Resolver support # -istart http://repo2.maven.org/maven2/org/apache/felix/org.apache.felix.resolver/1.0.0/org.apache.felix.resolver-1.0.0.jar knopflerfish-osgi-5.1.0/osgi/framework/0000755000175000017500000000000012475375714017123 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/build.xml0000644000175000017500000004227512346513670020746 0ustar felixfelix knopflerfish-osgi-5.1.0/osgi/framework/src/0000755000175000017500000000000012475375714017712 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/0000755000175000017500000000000012475375714020501 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/0000755000175000017500000000000012475375714021442 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/resource/0000755000175000017500000000000012475375714023271 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/resource/packageinfo0000644000175000017500000000001412346513664025451 0ustar felixfelixversion 1.0 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/resource/Wiring.java0000644000175000017500000001437312346513664025376 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.resource; import java.util.List; /** * A wiring for a resource. A wiring is associated with a resource and * represents the dependencies with other wirings. * *

* Instances of this type must be effectively immutable. That is, for a * given instance of this interface, the methods defined by this interface must * always return the same result. * * @ThreadSafe * @version $Id: b65dec3887cfa1d5731e860db558a01503c0f47d $ */ public interface Wiring { /** * Returns the capabilities provided by this wiring. * *

* Only capabilities considered by the resolver are returned. For example, * capabilities with {@link Namespace#CAPABILITY_EFFECTIVE_DIRECTIVE * effective} directive not equal to {@link Namespace#EFFECTIVE_RESOLVE * resolve} are not returned. * *

* A capability may not be required by any wiring and thus there may be no * {@link #getProvidedResourceWires(String) wires} for the capability. * *

* A wiring for a non-fragment resource provides a subset of the declared * capabilities from the resource and all attached fragment * resources. Not all declared capabilities may be * provided since some may be discarded. For example, if a package is * declared to be both exported and imported, only one is selected and the * other is discarded. *

* A wiring for a fragment resource with a symbolic name must provide * exactly one {@code osgi.identity} capability. *

* † The {@code osgi.identity} capability provided by attached * fragment resource must not be included in the capabilities of the host * wiring. * * @param namespace The namespace of the capabilities to return or * {@code null} to return the capabilities from all namespaces. * @return A list containing a snapshot of the {@link Capability}s, or an * empty list if this wiring provides no capabilities in the * specified namespace. For a given namespace, the list contains the * wires in the order the capabilities were specified in the * manifests of the {@link #getResource() resource} and the attached * fragment resources of this wiring. There is no * ordering defined between capabilities in different namespaces. */ List getResourceCapabilities(String namespace); /** * Returns the requirements of this wiring. * *

* Only requirements considered by the resolver are returned. For example, * requirements with {@link Namespace#REQUIREMENT_EFFECTIVE_DIRECTIVE * effective} directive not equal to {@link Namespace#EFFECTIVE_RESOLVE * resolve} are not returned. * *

* A wiring for a non-fragment resource has a subset of the declared * requirements from the resource and all attached fragment resources. Not * all declared requirements may be present since some may be discarded. For * example, if a package is declared to be optionally imported and is not * actually imported, the requirement must be discarded. * * @param namespace The namespace of the requirements to return or * {@code null} to return the requirements from all namespaces. * @return A list containing a snapshot of the {@link Requirement}s, or an * empty list if this wiring uses no requirements in the specified * namespace. For a given namespace, the list contains the wires in * the order the requirements were specified in the manifests of the * {@link #getResource() resource} and the attached fragment * resources of this wiring. There is no ordering defined between * requirements in different namespaces. */ List getResourceRequirements(String namespace); /** * Returns the {@link Wire}s to the provided {@link Capability capabilities} * of this wiring. * * @param namespace The namespace of the capabilities for which to return * wires or {@code null} to return the wires for the capabilities in * all namespaces. * @return A list containing a snapshot of the {@link Wire}s for the * {@link Capability capabilities} of this wiring, or an empty list * if this wiring has no capabilities in the specified namespace. * For a given namespace, the list contains the wires in the order * the capabilities were specified in the manifests of the * {@link #getResource() resource} and the attached fragment * resources of this wiring. There is no ordering defined between * capabilities in different namespaces. */ List getProvidedResourceWires(String namespace); /** * Returns the {@link Wire}s to the {@link Requirement requirements} in use * by this wiring. * * @param namespace The namespace of the requirements for which to return * wires or {@code null} to return the wires for the requirements in * all namespaces. * @return A list containing a snapshot of the {@link Wire}s for the * {@link Requirement requirements} of this wiring, or an empty list * if this wiring has no requirements in the specified namespace. * For a given namespace, the list contains the wires in the order * the requirements were specified in the manifests of the * {@link #getResource() resource} and the attached fragment * resources of this wiring. There is no ordering defined between * requirements in different namespaces. */ List getRequiredResourceWires(String namespace); /** * Returns the resource associated with this wiring. * * @return The resource associated with this wiring. */ Resource getResource(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/resource/Capability.java0000644000175000017500000000472612346513664026221 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.resource; import java.util.Map; /** * A capability that has been declared from a {@link Resource}. * *

* Instances of this type must be effectively immutable. That is, for a * given instance of this interface, the methods defined by this interface must * always return the same result. * * @ThreadSafe * @version $Id: 5f40514f7bf45f6dce59651e8812b0922580e77e $ */ public interface Capability { /** * Returns the namespace of this capability. * * @return The namespace of this capability. */ String getNamespace(); /** * Returns the directives of this capability. * * @return An unmodifiable map of directive names to directive values for * this capability, or an empty map if this capability has no * directives. */ Map getDirectives(); /** * Returns the attributes of this capability. * * @return An unmodifiable map of attribute names to attribute values for * this capability, or an empty map if this capability has no * attributes. */ Map getAttributes(); /** * Returns the resource declaring this capability. * * @return The resource declaring this capability. */ Resource getResource(); /** * Compares this {@code Capability} to another {@code Capability}. * *

* This {@code Capability} is equal to another {@code Capability} if they * have the same namespace, directives and attributes and are declared by * the same resource. * * @param obj The object to compare against this {@code Capability}. * @return {@code true} if this {@code Capability} is equal to the other * object; {@code false} otherwise. */ boolean equals(Object obj); /** * Returns the hashCode of this {@code Capability}. * * @return The hashCode of this {@code Capability}. */ int hashCode(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/resource/Wire.java0000644000175000017500000000472212346513664025042 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.resource; /** * A wire connecting a {@link Capability} to a {@link Requirement}. * *

* Instances of this type must be effectively immutable. That is, for a * given instance of this interface, the methods defined by this interface must * always return the same result. * * @ThreadSafe * @version $Id: d7ca9a5d3e8dd2277f8243a750e40fbcf79185bd $ */ public interface Wire { /** * Returns the {@link Capability} for this wire. * * @return The {@link Capability} for this wire. */ Capability getCapability(); /** * Returns the {@link Requirement} for this wire. * * @return The {@link Requirement} for this wire. */ Requirement getRequirement(); /** * Returns the resource providing the {@link #getCapability() capability}. * *

* The returned resource may differ from the resource referenced by the * {@link #getCapability() capability}. * * @return The resource providing the capability. */ Resource getProvider(); /** * Returns the resource who {@link #getRequirement() requires} the * {@link #getCapability() capability}. * *

* The returned resource may differ from the resource referenced by the * {@link #getRequirement() requirement}. * * @return The resource who requires the capability. */ Resource getRequirer(); /** * Compares this {@code Wire} to another {@code Wire}. * *

* This {@code Wire} is equal to another {@code Wire} if they have the same * capability, requirement, provider and requirer. * * @param obj The object to compare against this {@code Wire}. * @return {@code true} if this {@code Wire} is equal to the other object; * {@code false} otherwise. */ boolean equals(Object obj); /** * Returns the hashCode of this {@code Wire}. * * @return The hashCode of this {@code Wire}. */ int hashCode(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/resource/Requirement.java0000644000175000017500000000525612346513664026437 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.resource; import java.util.Map; /** * A requirement that has been declared from a {@link Resource} . * *

* Instances of this type must be effectively immutable. That is, for a * given instance of this interface, the methods defined by this interface must * always return the same result. * * @ThreadSafe * @version $Id: 212b26179910f98fd2c59c3e1e7dd0d086f42b5d $ */ public interface Requirement { /** * Returns the namespace of this requirement. * * @return The namespace of this requirement. */ String getNamespace(); /** * Returns the directives of this requirement. * * @return An unmodifiable map of directive names to directive values for * this requirement, or an empty map if this requirement has no * directives. */ Map getDirectives(); /** * Returns the attributes of this requirement. * *

* Requirement attributes have no specified semantics and are considered * extra user defined information. * * @return An unmodifiable map of attribute names to attribute values for * this requirement, or an empty map if this requirement has no * attributes. */ Map getAttributes(); /** * Returns the resource declaring this requirement. * * @return The resource declaring this requirement. This can be {@code null} * if this requirement is synthesized. */ Resource getResource(); /** * Compares this {@code Requirement} to another {@code Requirement}. * *

* This {@code Requirement} is equal to another {@code Requirement} if they * have the same namespace, directives and attributes and are declared by * the same resource. * * @param obj The object to compare against this {@code Requirement}. * @return {@code true} if this {@code Requirement} is equal to the other * object; {@code false} otherwise. */ boolean equals(Object obj); /** * Returns the hashCode of this {@code Requirement}. * * @return The hashCode of this {@code Requirement}. */ int hashCode(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/resource/package-info.java0000644000175000017500000000175212346513664026460 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Resource Package Version 1.0. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. For example: * *

 * Import-Package: org.osgi.resource; version="[1.0,2.0)"
 * 
* * @version $Id: d0272f91b8f76d63729dc851569da04b2ea88092 $ */ package org.osgi.resource; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/resource/Resource.java0000644000175000017500000000571412346513664025725 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.resource; import java.util.List; /** * A resource is the representation of a uniquely identified and typed data. A * resource declares requirements that need to be satisfied by capabilities * before it can provide its capabilities. * *

* Instances of this type must be effectively immutable. That is, for a * given instance of this interface, the methods defined by this interface must * always return the same result. * * @ThreadSafe * @version $Id: 40958d5777ee269d27d58e9f646a4c91bcc6daa4 $ */ public interface Resource { /** * Returns the capabilities declared by this resource. * * @param namespace The namespace of the declared capabilities to return or * {@code null} to return the declared capabilities from all * namespaces. * @return An unmodifiable list containing the declared {@link Capability}s * from the specified namespace. The returned list will be empty if * this resource declares no capabilities in the specified * namespace. */ List getCapabilities(String namespace); /** * Returns the requirements declared by this bundle resource. * * @param namespace The namespace of the declared requirements to return or * {@code null} to return the declared requirements from all * namespaces. * @return An unmodifiable list containing the declared {@link Requirement} * s from the specified namespace. The returned list will be empty * if this resource declares no requirements in the specified * namespace. */ List getRequirements(String namespace); /** * Compares this {@code Resource} to another {@code Resource}. * *

* This {@code Resource} is equal to another {@code Resource} if both have * the same content and come from the same location. Location may be defined * as the bundle location if the resource is an installed bundle or the * repository location if the resource is in a repository. * * @param obj The object to compare against this {@code Resource}. * @return {@code true} if this {@code Resource} is equal to the other * object; {@code false} otherwise. */ boolean equals(Object obj); /** * Returns the hashCode of this {@code Resource}. * * @return The hashCode of this {@code Resource}. */ int hashCode(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/resource/Namespace.java0000644000175000017500000001216612346513664026031 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.resource; /** * Capability and Requirement Namespaces base class. * *

* This class is the common class shared by all OSGi defined namespaces. It * defines the names for the common attributes and directives for the OSGi * specified namespaces. * *

* The OSGi Alliance reserves the right to extend the set of directives and * attributes which have specified semantics for all of the specified * namespaces. * *

* The values associated with these keys are of type {@code String}, unless * otherwise indicated. * * @Immutable * @version $Id: 43c9ff5cea19546d71c4703db71a2b5070a3f2fa $ */ public abstract class Namespace { /** * The capability directive used to specify the comma separated list of * package names used by a capability. */ public final static String CAPABILITY_USES_DIRECTIVE = "uses"; /** * The capability directive used to specify the effective time for the * capability. The default value is {@link #EFFECTIVE_RESOLVE resolve}. * * @see #EFFECTIVE_RESOLVE resolve * @see #EFFECTIVE_ACTIVE active */ public final static String CAPABILITY_EFFECTIVE_DIRECTIVE = "effective"; /** * The requirement directive used to specify a capability filter. This * filter is used to match against a capability's attributes. */ public final static String REQUIREMENT_FILTER_DIRECTIVE = "filter"; /** * The requirement directive used to specify the resolution type for a * requirement. The default value is {@link #RESOLUTION_MANDATORY mandatory} * . * * @see #RESOLUTION_MANDATORY mandatory * @see #RESOLUTION_OPTIONAL optional */ public final static String REQUIREMENT_RESOLUTION_DIRECTIVE = "resolution"; /** * The directive value identifying a mandatory requirement resolution type. * A mandatory resolution type indicates that the requirement must be * resolved when the resource is resolved. If such a requirement cannot be * resolved, the resource fails to resolve. * * @see #REQUIREMENT_RESOLUTION_DIRECTIVE */ public final static String RESOLUTION_MANDATORY = "mandatory"; /** * The directive value identifying an optional requirement resolution type. * An optional resolution type indicates that the requirement is optional * and the resource may be resolved without the requirement being resolved. * * @see #REQUIREMENT_RESOLUTION_DIRECTIVE */ public final static String RESOLUTION_OPTIONAL = "optional"; /** * The requirement directive used to specify the effective time for the * requirement. The default value is {@link #EFFECTIVE_RESOLVE resolve}. * * @see #EFFECTIVE_RESOLVE resolve * @see #EFFECTIVE_ACTIVE active */ public final static String REQUIREMENT_EFFECTIVE_DIRECTIVE = "effective"; /** * The directive value identifying a {@link #CAPABILITY_EFFECTIVE_DIRECTIVE * capability} or {@link #REQUIREMENT_EFFECTIVE_DIRECTIVE requirement} that * is effective at resolve time. Capabilities and requirements with an * effective time of resolve are the only capabilities which are processed * while resolving a resource. * * @see #REQUIREMENT_EFFECTIVE_DIRECTIVE * @see #CAPABILITY_EFFECTIVE_DIRECTIVE */ public final static String EFFECTIVE_RESOLVE = "resolve"; /** * The directive value identifying a {@link #CAPABILITY_EFFECTIVE_DIRECTIVE * capability} or {@link #REQUIREMENT_EFFECTIVE_DIRECTIVE requirement} that * is effective at active time. Capabilities and requirements with an * effective time of active are ignored while resolving a resource. * * @see #REQUIREMENT_EFFECTIVE_DIRECTIVE * @see #CAPABILITY_EFFECTIVE_DIRECTIVE */ public final static String EFFECTIVE_ACTIVE = "active"; /** * The requirement directive used to specify the cardinality for a * requirement. The default value is {@link #CARDINALITY_SINGLE single}. * * @see #CARDINALITY_MULTIPLE multiple * @see #CARDINALITY_SINGLE single */ public final static String REQUIREMENT_CARDINALITY_DIRECTIVE = "cardinality"; /** * The directive value identifying a multiple * {@link #REQUIREMENT_CARDINALITY_DIRECTIVE cardinality} type. * * @see #REQUIREMENT_CARDINALITY_DIRECTIVE */ public final static String CARDINALITY_MULTIPLE = "multiple"; /** * The directive value identifying a * {@link #REQUIREMENT_CARDINALITY_DIRECTIVE cardinality} type of single. * * @see #REQUIREMENT_CARDINALITY_DIRECTIVE */ public final static String CARDINALITY_SINGLE = "single"; /** * Protected constructor for Namespace sub-types. */ protected Namespace() { // empty } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/0000755000175000017500000000000012475375714023102 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/url/0000755000175000017500000000000012475375714023704 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/url/packageinfo0000644000175000017500000000001412346513664026064 0ustar felixfelixversion 1.0 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/url/AbstractURLStreamHandlerService.java0000644000175000017500000001047512346513664032672 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2002, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.url; import java.net.*; /** * Abstract implementation of the {@code URLStreamHandlerService} interface. All * the methods simply invoke the corresponding methods on * {@code java.net.URLStreamHandler} except for {@code parseURL} and * {@code setURL}, which use the {@code URLStreamHandlerSetter} parameter. * Subclasses of this abstract class should not need to override the * {@code setURL} and {@code parseURL(URLStreamHandlerSetter,...)} methods. * * @ThreadSafe * @version $Id: b86572a4f13b7bb4a343ac4d6b6fb3487e01bd31 $ */ public abstract class AbstractURLStreamHandlerService extends URLStreamHandler implements URLStreamHandlerService { /** * @see "java.net.URLStreamHandler.openConnection" */ public abstract URLConnection openConnection(URL u) throws java.io.IOException; /** * The {@code URLStreamHandlerSetter} object passed to the parseURL method. */ protected volatile URLStreamHandlerSetter realHandler; /** * Parse a URL using the {@code URLStreamHandlerSetter} object. This method * sets the {@code realHandler} field with the specified * {@code URLStreamHandlerSetter} object and then calls * {@code parseURL(URL,String,int,int)}. * * @param realHandler The object on which the {@code setURL} method must be * invoked for the specified URL. * @see "java.net.URLStreamHandler.parseURL" */ public void parseURL(URLStreamHandlerSetter realHandler, URL u, String spec, int start, int limit) { this.realHandler = realHandler; parseURL(u, spec, start, limit); } /** * This method calls {@code super.toExternalForm}. * * @see "java.net.URLStreamHandler.toExternalForm" */ public String toExternalForm(URL u) { return super.toExternalForm(u); } /** * This method calls {@code super.equals(URL,URL)}. * * @see "java.net.URLStreamHandler.equals(URL,URL)" */ public boolean equals(URL u1, URL u2) { return super.equals(u1, u2); } /** * This method calls {@code super.getDefaultPort}. * * @see "java.net.URLStreamHandler.getDefaultPort" */ public int getDefaultPort() { return super.getDefaultPort(); } /** * This method calls {@code super.getHostAddress}. * * @see "java.net.URLStreamHandler.getHostAddress" */ public InetAddress getHostAddress(URL u) { return super.getHostAddress(u); } /** * This method calls {@code super.hashCode(URL)}. * * @see "java.net.URLStreamHandler.hashCode(URL)" */ public int hashCode(URL u) { return super.hashCode(u); } /** * This method calls {@code super.hostsEqual}. * * @see "java.net.URLStreamHandler.hostsEqual" */ public boolean hostsEqual(URL u1, URL u2) { return super.hostsEqual(u1, u2); } /** * This method calls {@code super.sameFile}. * * @see "java.net.URLStreamHandler.sameFile" */ public boolean sameFile(URL u1, URL u2) { return super.sameFile(u1, u2); } /** * This method calls * {@code realHandler.setURL(URL,String,String,int,String,String)}. * * @see "java.net.URLStreamHandler.setURL(URL,String,String,int,String,String)" * @deprecated This method is only for compatibility with handlers written * for JDK 1.1. */ protected void setURL(URL u, String proto, String host, int port, String file, String ref) { realHandler.setURL(u, proto, host, port, file, ref); } /** * This method calls * {@code realHandler.setURL(URL,String,String,int,String,String,String,String)} * . * * @see "java.net.URLStreamHandler.setURL(URL,String,String,int,String,String,String,String)" */ protected void setURL(URL u, String proto, String host, int port, String auth, String user, String path, String query, String ref) { realHandler.setURL(u, proto, host, port, auth, user, path, query, ref); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/url/URLStreamHandlerService.java0000644000175000017500000000527612346513664031211 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2002, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.url; import java.net.*; /** * Service interface with public versions of the protected * {@code java.net.URLStreamHandler} methods. *

* The important differences between this interface and the * {@code URLStreamHandler} class are that the {@code setURL} method is absent * and the {@code parseURL} method takes a {@link URLStreamHandlerSetter} object * as the first argument. Classes implementing this interface must call the * {@code setURL} method on the {@code URLStreamHandlerSetter} object received * in the {@code parseURL} method instead of {@code URLStreamHandler.setURL} to * avoid a {@code SecurityException}. * * @see AbstractURLStreamHandlerService * * @ThreadSafe * @version $Id: 4a453f61b9acdc6449df389b2a0538d0ccb33ed2 $ */ public interface URLStreamHandlerService { /** * @see "java.net.URLStreamHandler.openConnection" */ public URLConnection openConnection(URL u) throws java.io.IOException; /** * Parse a URL. This method is called by the {@code URLStreamHandler} proxy, * instead of {@code java.net.URLStreamHandler.parseURL}, passing a * {@code URLStreamHandlerSetter} object. * * @param realHandler The object on which {@code setURL} must be invoked for * this URL. * @see "java.net.URLStreamHandler.parseURL" */ public void parseURL(URLStreamHandlerSetter realHandler, URL u, String spec, int start, int limit); /** * @see "java.net.URLStreamHandler.toExternalForm" */ public String toExternalForm(URL u); /** * @see "java.net.URLStreamHandler.equals(URL, URL)" */ public boolean equals(URL u1, URL u2); /** * @see "java.net.URLStreamHandler.getDefaultPort" */ public int getDefaultPort(); /** * @see "java.net.URLStreamHandler.getHostAddress" */ public InetAddress getHostAddress(URL u); /** * @see "java.net.URLStreamHandler.hashCode(URL)" */ public int hashCode(URL u); /** * @see "java.net.URLStreamHandler.hostsEqual" */ public boolean hostsEqual(URL u1, URL u2); /** * @see "java.net.URLStreamHandler.sameFile" */ public boolean sameFile(URL u1, URL u2); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/url/package-info.java0000644000175000017500000000206312346513664027067 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * URL Stream and Content Handlers Package Version 1.0. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. * *

* Example import for consumers using the API in this package: *

* {@code Import-Package: org.osgi.service.url; version="[1.0,2.0)"} * * @version $Id: 4dd6b685a79b76ce57708f69487533abe4828943 $ */ package org.osgi.service.url; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/url/URLStreamHandlerSetter.java0000644000175000017500000000355712346513664031057 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2002, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.url; import java.net.URL; /** * Interface used by {@code URLStreamHandlerService} objects to call the * {@code setURL} method on the proxy {@code URLStreamHandler} object. * *

* Objects of this type are passed to the * {@link URLStreamHandlerService#parseURL(URLStreamHandlerSetter, URL, String, int, int)} * method. Invoking the {@code setURL} method on the * {@code URLStreamHandlerSetter} object will invoke the {@code setURL} method * on the proxy {@code URLStreamHandler} object that is actually registered with * {@code java.net.URL} for the protocol. * * @ThreadSafe * @version $Id: 90f25e3961fea2150cfd31117a2237304f1518f9 $ */ public interface URLStreamHandlerSetter { /** * @see "java.net.URLStreamHandler.setURL(URL,String,String,int,String,String)" * * @deprecated This method is only for compatibility with handlers written * for JDK 1.1. */ public void setURL(URL u, String protocol, String host, int port, String file, String ref); /** * @see "java.net.URLStreamHandler.setURL(URL,String,String,int,String,String,String,String)" */ public void setURL(URL u, String protocol, String host, int port, String authority, String userInfo, String path, String query, String ref); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/url/URLConstants.java0000644000175000017500000000303212346513664027077 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2002, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.url; /** * Defines standard names for property keys associated with * {@link URLStreamHandlerService} and {@code java.net.ContentHandler} services. * *

* The values associated with these keys are of type {@code java.lang.String[]} * or {@code java.lang.String}, unless otherwise indicated. * * @noimplement * @version $Id: ac2b9670972d6e41d989c51067219ff7be459831 $ */ public interface URLConstants { /** * Service property naming the protocols serviced by a * URLStreamHandlerService. The property's value is a protocol name or an * array of protocol names. */ public static final String URL_HANDLER_PROTOCOL = "url.handler.protocol"; /** * Service property naming the MIME types serviced by a * java.net.ContentHandler. The property's value is a MIME type or an array * of MIME types. */ public static final String URL_CONTENT_MIMETYPE = "url.content.mimetype"; } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/permissionadmin/0000755000175000017500000000000012475375714026303 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/permissionadmin/packageinfo0000644000175000017500000000001412346513664030463 0ustar felixfelixversion 1.2 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/permissionadmin/package-info.java0000644000175000017500000000207412346513664031470 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Permission Admin Package Version 1.2. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. * *

* Example import for consumers using the API in this package: *

* {@code Import-Package: org.osgi.service.permissionadmin; version="[1.2,2.0)"} * * @version $Id: 735e3020913649e9606caf0ad3b6bfee690f2b8a $ */ package org.osgi.service.permissionadmin; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/permissionadmin/PermissionAdmin.java0000644000175000017500000001111212346513664032236 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2001, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.permissionadmin; /** * The Permission Admin service allows management agents to manage the * permissions of bundles. There is at most one Permission Admin service present * in the OSGi environment. *

* Access to the Permission Admin service is protected by corresponding * {@code ServicePermission}. In addition {@code AdminPermission} is required to * actually set permissions. * *

* Bundle permissions are managed using a permission table. A bundle's location * serves as the key into this permission table. The value of a table entry is * the set of permissions (of type {@code PermissionInfo}) granted to the bundle * named by the given location. A bundle may have an entry in the permission * table prior to being installed in the Framework. * *

* The permissions specified in {@code setDefaultPermissions} are used as the * default permissions which are granted to all bundles that do not have an * entry in the permission table. * *

* Any changes to a bundle's permissions in the permission table will take * effect no later than when bundle's {@code java.security.ProtectionDomain} is * next involved in a permission check, and will be made persistent. * *

* Only permission classes on the system classpath or from an exported package * are considered during a permission check. Additionally, only permission * classes that are subclasses of {@code java.security.Permission} and define a * 2-argument constructor that takes a name string and an actions * string can be used. *

* Permissions implicitly granted by the Framework (for example, a bundle's * permission to access its persistent storage area) cannot be changed, and are * not reflected in the permissions returned by {@code getPermissions} and * {@code getDefaultPermissions}. * * @ThreadSafe * @noimplement * @version $Id: 846b7ff8d3e9f03d2a6ee75d2dcc9ab52d959754 $ */ public interface PermissionAdmin { /** * Gets the permissions assigned to the bundle with the specified location. * * @param location The location of the bundle whose permissions are to be * returned. * * @return The permissions assigned to the bundle with the specified * location, or {@code null} if that bundle has not been assigned * any permissions. */ PermissionInfo[] getPermissions(String location); /** * Assigns the specified permissions to the bundle with the specified * location. * * @param location The location of the bundle that will be assigned the * permissions. * @param permissions The permissions to be assigned, or {@code null} if the * specified location is to be removed from the permission table. * @throws SecurityException If the caller does not have * {@code AllPermission}. */ void setPermissions(String location, PermissionInfo[] permissions); /** * Returns the bundle locations that have permissions assigned to them, that * is, bundle locations for which an entry exists in the permission table. * * @return The locations of bundles that have been assigned any permissions, * or {@code null} if the permission table is empty. */ String[] getLocations(); /** * Gets the default permissions. * *

* These are the permissions granted to any bundle that does not have * permissions assigned to its location. * * @return The default permissions, or {@code null} if no default * permissions are set. */ PermissionInfo[] getDefaultPermissions(); /** * Sets the default permissions. * *

* These are the permissions granted to any bundle that does not have * permissions assigned to its location. * * @param permissions The default permissions, or {@code null} if the * default permissions are to be removed from the permission table. * @throws SecurityException If the caller does not have * {@code AllPermission}. */ void setDefaultPermissions(PermissionInfo[] permissions); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/permissionadmin/PermissionInfo.java0000644000175000017500000002601712346513664032113 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2001, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.permissionadmin; /** * Permission representation used by the Permission Admin service. * *

* This class encapsulates three pieces of information: a Permission type * (class name), which must be a subclass of * {@code java.security.Permission}, and the name and actions * arguments passed to its constructor. * *

* In order for a permission represented by a {@code PermissionInfo} to be * instantiated and considered during a permission check, its Permission class * must be available from the system classpath or an exported package. This * means that the instantiation of a permission represented by a * {@code PermissionInfo} may be delayed until the package containing its * Permission class has been exported by a bundle. * * @Immutable * @version $Id: d904a01a7ff64b702e8d92071d063ff6927bef14 $ */ public class PermissionInfo { private final String type; private final String name; private final String actions; /** * Constructs a {@code PermissionInfo} from the specified type, name, and * actions. * * @param type The fully qualified class name of the permission represented * by this {@code PermissionInfo}. The class must be a subclass of * {@code java.security.Permission} and must define a 2-argument * constructor that takes a name string and an actions * string. * * @param name The permission name that will be passed as the first argument * to the constructor of the {@code Permission} class identified by * {@code type}. * * @param actions The permission actions that will be passed as the second * argument to the constructor of the {@code Permission} class * identified by {@code type}. * * @throws NullPointerException If {@code type} is {@code null}. * @throws IllegalArgumentException If {@code action} is not {@code null} * and {@code name} is {@code null}. */ public PermissionInfo(String type, String name, String actions) { this.type = type; this.name = name; this.actions = actions; if (type == null) { throw new NullPointerException("type is null"); } if ((name == null) && (actions != null)) { throw new IllegalArgumentException("name missing"); } } /** * Constructs a {@code PermissionInfo} object from the specified encoded * {@code PermissionInfo} string. White space in the encoded * {@code PermissionInfo} string is ignored. * * * @param encodedPermission The encoded {@code PermissionInfo}. * @see #getEncoded() * @throws IllegalArgumentException If the specified * {@code encodedPermission} is not properly formatted. */ public PermissionInfo(String encodedPermission) { if (encodedPermission == null) { throw new NullPointerException("missing encoded permission"); } if (encodedPermission.length() == 0) { throw new IllegalArgumentException("empty encoded permission"); } String parsedType = null; String parsedName = null; String parsedActions = null; try { char[] encoded = encodedPermission.toCharArray(); int length = encoded.length; int pos = 0; /* skip whitespace */ while (Character.isWhitespace(encoded[pos])) { pos++; } /* the first character must be '(' */ if (encoded[pos] != '(') { throw new IllegalArgumentException("expecting open parenthesis"); } pos++; /* skip whitespace */ while (Character.isWhitespace(encoded[pos])) { pos++; } /* type is not quoted or encoded */ int begin = pos; while (!Character.isWhitespace(encoded[pos]) && (encoded[pos] != ')')) { pos++; } if (pos == begin || encoded[begin] == '"') { throw new IllegalArgumentException("expecting type"); } parsedType = new String(encoded, begin, pos - begin); /* skip whitespace */ while (Character.isWhitespace(encoded[pos])) { pos++; } /* type may be followed by name which is quoted and encoded */ if (encoded[pos] == '"') { pos++; begin = pos; while (encoded[pos] != '"') { if (encoded[pos] == '\\') { pos++; } pos++; } parsedName = unescapeString(encoded, begin, pos); pos++; if (Character.isWhitespace(encoded[pos])) { /* skip whitespace */ while (Character.isWhitespace(encoded[pos])) { pos++; } /* * name may be followed by actions which is quoted and * encoded */ if (encoded[pos] == '"') { pos++; begin = pos; while (encoded[pos] != '"') { if (encoded[pos] == '\\') { pos++; } pos++; } parsedActions = unescapeString(encoded, begin, pos); pos++; /* skip whitespace */ while (Character.isWhitespace(encoded[pos])) { pos++; } } } } /* the final character must be ')' */ char c = encoded[pos]; pos++; while ((pos < length) && Character.isWhitespace(encoded[pos])) { pos++; } if ((c != ')') || (pos != length)) { throw new IllegalArgumentException("expecting close parenthesis"); } } catch (ArrayIndexOutOfBoundsException e) { throw new IllegalArgumentException("parsing terminated abruptly"); } type = parsedType; name = parsedName; actions = parsedActions; } /** * Returns the string encoding of this {@code PermissionInfo} in a form * suitable for restoring this {@code PermissionInfo}. * *

* The encoded format is: * *

	 * (type)
	 * 
* * or * *
	 * (type "name")
	 * 
* * or * *
	 * (type "name" "actions")
	 * 
* * where name and actions are strings that must be encoded for * proper parsing. Specifically, the {@code "},{@code \}, carriage * return, and line feed characters must be escaped using {@code \"}, * {@code \\},{@code \r}, and {@code \n}, respectively. * *

* The encoded string contains no leading or trailing whitespace characters. * A single space character is used between type and * "name" and between "name" and * "actions". * * @return The string encoding of this {@code PermissionInfo}. */ public final String getEncoded() { StringBuffer output = new StringBuffer(8 + type.length() + ((((name == null) ? 0 : name.length()) + ((actions == null) ? 0 : actions.length())) << 1)); output.append('('); output.append(type); if (name != null) { output.append(" \""); escapeString(name, output); if (actions != null) { output.append("\" \""); escapeString(actions, output); } output.append('\"'); } output.append(')'); return output.toString(); } /** * Returns the string representation of this {@code PermissionInfo}. The * string is created by calling the {@code getEncoded} method on this * {@code PermissionInfo}. * * @return The string representation of this {@code PermissionInfo}. */ public String toString() { return getEncoded(); } /** * Returns the fully qualified class name of the permission represented by * this {@code PermissionInfo}. * * @return The fully qualified class name of the permission represented by * this {@code PermissionInfo}. */ public final String getType() { return type; } /** * Returns the name of the permission represented by this * {@code PermissionInfo}. * * @return The name of the permission represented by this * {@code PermissionInfo}, or {@code null} if the permission does * not have a name. */ public final String getName() { return name; } /** * Returns the actions of the permission represented by this * {@code PermissionInfo}. * * @return The actions of the permission represented by this * {@code PermissionInfo}, or {@code null} if the permission does * not have any actions associated with it. */ public final String getActions() { return actions; } /** * Determines the equality of two {@code PermissionInfo} objects. * * This method checks that specified object has the same type, name and * actions as this {@code PermissionInfo} object. * * @param obj The object to test for equality with this * {@code PermissionInfo} object. * @return {@code true} if {@code obj} is a {@code PermissionInfo}, and has * the same type, name and actions as this {@code PermissionInfo} * object; {@code false} otherwise. */ public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof PermissionInfo)) { return false; } PermissionInfo other = (PermissionInfo) obj; if (!type.equals(other.type) || ((name == null) ^ (other.name == null)) || ((actions == null) ^ (other.actions == null))) { return false; } if (name != null) { if (actions != null) { return name.equals(other.name) && actions.equals(other.actions); } else { return name.equals(other.name); } } else { return true; } } /** * Returns the hash code value for this object. * * @return A hash code value for this object. */ public int hashCode() { int h = 31 * 17 + type.hashCode(); if (name != null) { h = 31 * h + name.hashCode(); if (actions != null) { h = 31 * h + actions.hashCode(); } } return h; } /** * This escapes the quotes, backslashes, \n, and \r in the string using a * backslash and appends the newly escaped string to a StringBuffer. */ private static void escapeString(String str, StringBuffer output) { int len = str.length(); for (int i = 0; i < len; i++) { char c = str.charAt(i); switch (c) { case '"' : case '\\' : output.append('\\'); output.append(c); break; case '\r' : output.append("\\r"); break; case '\n' : output.append("\\n"); break; default : output.append(c); break; } } } /** * Takes an encoded character array and decodes it into a new String. */ private static String unescapeString(char[] str, int begin, int end) { StringBuffer output = new StringBuffer(end - begin); for (int i = begin; i < end; i++) { char c = str[i]; if (c == '\\') { i++; if (i < end) { c = str[i]; switch (c) { case '"' : case '\\' : break; case 'r' : c = '\r'; break; case 'n' : c = '\n'; break; default : c = '\\'; i--; break; } } } output.append(c); } return output.toString(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/packageadmin/0000755000175000017500000000000012475375714025506 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/packageadmin/packageinfo0000644000175000017500000000001412346513664027666 0ustar felixfelixversion 1.2 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/packageadmin/RequiredBundle.java0000644000175000017500000000665612346513664031273 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.packageadmin; import org.osgi.framework.Bundle; import org.osgi.framework.Version; /** * A required bundle. * * Objects implementing this interface are created by the Package Admin service. * *

* The term required bundle refers to a resolved bundle that has a bundle * symbolic name and is not a fragment. That is, a bundle that may be required * by other bundles. This bundle may or may not be currently required by other * bundles. * *

* The information about a required bundle provided by this object may change. A * {@code RequiredBundle} object becomes stale if an exported package of * the bundle it references has been updated or removed as a result of calling * {@code PackageAdmin.refreshPackages()}). * * If this object becomes stale, its {@code getSymbolicName()} and * {@code getVersion()} methods continue to return their original values, * {@code isRemovalPending()} returns true, and {@code getBundle()} * and {@code getRequiringBundles()} return {@code null}. * * @since 1.2 * @ThreadSafe * @noimplement * @deprecated The PackageAdmin service has been replaced by the * org.osgi.framework.wiring package. * @version $Id: 1606b0422cae6769b7eedc2d565df61841da1e22 $ */ public interface RequiredBundle { /** * Returns the symbolic name of this required bundle. * * @return The symbolic name of this required bundle. */ public String getSymbolicName(); /** * Returns the bundle associated with this required bundle. * * @return The bundle, or {@code null} if this * {@code RequiredBundle} object has become stale. */ public Bundle getBundle(); /** * Returns the bundles that currently require this required bundle. * *

* If this required bundle is required and then re-exported by another * bundle then all the requiring bundles of the re-exporting bundle are * included in the returned array. * * @return An array of bundles currently requiring this required bundle, or * {@code null} if this {@code RequiredBundle} object * has become stale. The array will be empty if no bundles require * this required package. */ public Bundle[] getRequiringBundles(); /** * Returns the version of this required bundle. * * @return The version of this required bundle, or * {@link Version#emptyVersion} if no version information is * available. */ public Version getVersion(); /** * Returns {@code true} if the bundle associated with this * {@code RequiredBundle} object has been updated or uninstalled. * * @return {@code true} if the required bundle has been updated or * uninstalled, or if the {@code RequiredBundle} object has * become stale; {@code false} otherwise. */ public boolean isRemovalPending(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/packageadmin/PackageAdmin.java0000644000175000017500000003062212346513664030653 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2001, 2010). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.packageadmin; import org.osgi.framework.Bundle; /** * Framework service which allows bundle programmers to inspect the package * wiring state of bundles in the Framework as well as other functions related * to the class loader network among bundles. * *

* If present, there will only be a single instance of this service registered * with the Framework. * * @ThreadSafe * @noimplement * @version $Id: a268c3bdc986080fa16bdb2f56ba1d3800d030dd $ * @deprecated This service has been replaced by the * org.osgi.framework.wiring package. * @see org.osgi.service.packageadmin.ExportedPackage * @see org.osgi.service.packageadmin.RequiredBundle */ public interface PackageAdmin { /** * Gets the exported packages for the specified bundle. * * @param bundle The bundle whose exported packages are to be returned, or * {@code null} if all exported packages are to be returned. If * the specified bundle is the system bundle (that is, the bundle * with id zero), this method returns all the packages known to be * exported by the system bundle. This will include the package * specified by the {@code org.osgi.framework.system.packages} * system property as well as any other package exported by the * framework implementation. * * @return An array of exported packages, or {@code null} if the * specified bundle has no exported packages. * @throws IllegalArgumentException If the specified {@code Bundle} was * not created by the same framework instance that registered this * {@code PackageAdmin} service. */ public ExportedPackage[] getExportedPackages(Bundle bundle); /** * Gets the exported packages for the specified package name. * * @param name The name of the exported packages to be returned. * * @return An array of the exported packages, or {@code null} if no * exported packages with the specified name exists. * @since 1.2 */ public ExportedPackage[] getExportedPackages(String name); /** * Gets the exported package for the specified package name. * *

* If there are multiple exported packages with specified name, the exported * package with the highest version will be returned. * * @param name The name of the exported package to be returned. * * @return The exported package, or {@code null} if no exported * package with the specified name exists. * @see #getExportedPackages(String) */ public ExportedPackage getExportedPackage(String name); /** * Forces the update (replacement) or removal of packages exported by the * specified bundles. * *

* If no bundles are specified, this method will update or remove any * packages exported by any bundles that were previously updated or * uninstalled since the last call to this method. The technique by which * this is accomplished may vary among different Framework implementations. * One permissible implementation is to stop and restart the Framework. * *

* This method returns to the caller immediately and then performs the * following steps on a separate thread: * *

    *
  1. Compute a graph of bundles starting with the specified bundles. If no * bundles are specified, compute a graph of bundles starting with bundle * updated or uninstalled since the last call to this method. Add to the * graph any bundle that is wired to a package that is currently exported by * a bundle in the graph. The graph is fully constructed when there is no * bundle outside the graph that is wired to a bundle in the graph. The * graph may contain {@code UNINSTALLED} bundles that are currently * still exporting packages. * *
  2. Each bundle in the graph that is in the {@code ACTIVE} state * will be stopped as described in the {@code Bundle.stop} method. * *
  3. Each bundle in the graph that is in the {@code RESOLVED} state * is unresolved and thus moved to the {@code INSTALLED} state. The * effect of this step is that bundles in the graph are no longer * {@code RESOLVED}. * *
  4. Each bundle in the graph that is in the {@code UNINSTALLED} * state is removed from the graph and is now completely removed from the * Framework. * *
  5. Each bundle in the graph that was in the {@code ACTIVE} state * prior to Step 2 is started as described in the {@code Bundle.start} * method, causing all bundles required for the restart to be resolved. It * is possible that, as a result of the previous steps, packages that were * previously exported no longer are. Therefore, some bundles may be * unresolvable until another bundle offering a compatible package for * export has been installed in the Framework. *
  6. A framework event of type * {@code FrameworkEvent.PACKAGES_REFRESHED} is fired. *
* *

* For any exceptions that are thrown during any of these steps, a * {@code FrameworkEvent} of type {@code ERROR} is fired * containing the exception. The source bundle for these events should be * the specific bundle to which the exception is related. If no specific * bundle can be associated with the exception then the System Bundle must * be used as the source bundle for the event. * * @param bundles The bundles whose exported packages are to be updated or * removed, or {@code null} for all bundles updated or * uninstalled since the last call to this method. * @throws SecurityException If the caller does not have * {@code AdminPermission[System Bundle,RESOLVE]} and the Java * runtime environment supports permissions. * @throws IllegalArgumentException If the specified {@code Bundle}s * were not created by the same framework instance that registered * this {@code PackageAdmin} service. */ public void refreshPackages(Bundle[] bundles); /** * Resolve the specified bundles. The Framework must attempt to resolve the * specified bundles that are unresolved. Additional bundles that are not * included in the specified bundles may be resolved as a result of calling * this method. A permissible implementation of this method is to attempt to * resolve all unresolved bundles installed in the framework. * *

* If {@code null} is specified then the Framework will attempt to * resolve all unresolved bundles. This method must not cause any bundle to * be refreshed, stopped, or started. This method will not return until the * operation has completed. * * @param bundles The bundles to resolve or {@code null} to resolve all * unresolved bundles installed in the Framework. * @return {@code true} if all specified bundles are resolved; * @throws SecurityException If the caller does not have * {@code AdminPermission[System Bundle,RESOLVE]} and the Java * runtime environment supports permissions. * @throws IllegalArgumentException If the specified {@code Bundle}s * were not created by the same framework instance that registered * this {@code PackageAdmin} service. * @since 1.2 */ public boolean resolveBundles(Bundle[] bundles); /** * Returns an array of required bundles having the specified symbolic name. * *

* If {@code null} is specified, then all required bundles will be * returned. * * @param symbolicName The bundle symbolic name or {@code null} for * all required bundles. * @return An array of required bundles or {@code null} if no * required bundles exist for the specified symbolic name. * @since 1.2 */ public RequiredBundle[] getRequiredBundles(String symbolicName); /** * Returns the bundles with the specified symbolic name whose bundle version * is within the specified version range. If no bundles are installed that * have the specified symbolic name, then {@code null} is returned. * If a version range is specified, then only the bundles that have the * specified symbolic name and whose bundle versions belong to the specified * version range are returned. The returned bundles are ordered by version * in descending version order so that the first element of the array * contains the bundle with the highest version. * * @see org.osgi.framework.Constants#BUNDLE_VERSION_ATTRIBUTE * @param symbolicName The symbolic name of the desired bundles. * @param versionRange The version range of the desired bundles, or * {@code null} if all versions are desired. * @return An array of bundles with the specified name belonging to the * specified version range ordered in descending version order, or * {@code null} if no bundles are found. * @since 1.2 */ public Bundle[] getBundles(String symbolicName, String versionRange); /** * Returns an array of attached fragment bundles for the specified bundle. * If the specified bundle is a fragment then {@code null} is returned. * If no fragments are attached to the specified bundle then * {@code null} is returned. *

* This method does not attempt to resolve the specified bundle. If the * specified bundle is not resolved then {@code null} is returned. * * @param bundle The bundle whose attached fragment bundles are to be * returned. * @return An array of fragment bundles or {@code null} if the bundle * does not have any attached fragment bundles or the bundle is not * resolved. * @throws IllegalArgumentException If the specified {@code Bundle} was * not created by the same framework instance that registered this * {@code PackageAdmin} service. * @since 1.2 */ public Bundle[] getFragments(Bundle bundle); /** * Returns the host bundles to which the specified fragment bundle is * attached. * * @param bundle The fragment bundle whose host bundles are to be returned. * @return An array containing the host bundles to which the specified * fragment is attached or {@code null} if the specified bundle * is not a fragment or is not attached to any host bundles. * @throws IllegalArgumentException If the specified {@code Bundle} was * not created by the same framework instance that registered this * {@code PackageAdmin} service. * @since 1.2 */ public Bundle[] getHosts(Bundle bundle); /** * Returns the bundle from which the specified class is loaded. The class * loader of the returned bundle must have been used to load the specified * class. If the class was not loaded by a bundle class loader then * {@code null} is returned. * * @param clazz The class object from which to locate the bundle. * @return The bundle from which the specified class is loaded or * {@code null} if the class was not loaded by a bundle class * loader created by the same framework instance that registered * this {@code PackageAdmin} service. * @since 1.2 */ public Bundle getBundle(Class clazz); /** * Bundle type indicating the bundle is a fragment bundle. * *

* The value of {@code BUNDLE_TYPE_FRAGMENT} is 0x00000001. * * @since 1.2 */ public static final int BUNDLE_TYPE_FRAGMENT = 0x00000001; /** * Returns the special type of the specified bundle. The bundle type values * are: *

* * A bundle may be more than one type at a time. A type code is used to * identify the bundle type for future extendability. * *

* If a bundle is not one or more of the defined types then 0x00000000 is * returned. * * @param bundle The bundle for which to return the special type. * @return The special type of the bundle. * @throws IllegalArgumentException If the specified {@code Bundle} was * not created by the same framework instance that registered this * {@code PackageAdmin} service. * @since 1.2 */ public int getBundleType(Bundle bundle); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/packageadmin/package-info.java0000644000175000017500000000227412346513664030675 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Package Admin Package Version 1.2. * *

* Deprecated. * This package is deprecated and has been replaced by the * {@code org.osgi.framework.wiring} package. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. * *

* Example import for consumers using the API in this package: *

* {@code Import-Package: org.osgi.service.packageadmin; version="[1.2,2.0)"} * * @version $Id: b1c7db22b9c84e48d3c6c711f0ed976e825053c9 $ */ package org.osgi.service.packageadmin; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/packageadmin/ExportedPackage.java0000644000175000017500000000754512346513664031425 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2001, 2011). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.packageadmin; import org.osgi.framework.Bundle; import org.osgi.framework.Version; /** * An exported package. * * Objects implementing this interface are created by the Package Admin service. * *

* The term exported package refers to a package that has been exported * from a resolved bundle. This package may or may not be currently wired to * other bundles. * *

* The information about an exported package provided by this object may change. * An {@code ExportedPackage} object becomes stale if the package it * references has been updated or removed as a result of calling * {@code PackageAdmin.refreshPackages()}. * * If this object becomes stale, its {@code getName()} and * {@code getVersion()} methods continue to return their original values, * {@code isRemovalPending()} returns {@code true}, and * {@code getExportingBundle()} and {@code getImportingBundles()} * return {@code null}. * * @ThreadSafe * @noimplement * @deprecated The PackageAdmin service has been replaced by the * org.osgi.framework.wiring package. * @version $Id: 22ce5e8e388107b04edba3aea2f3036b8026798d $ */ public interface ExportedPackage { /** * Returns the name of the package associated with this exported package. * * @return The name of this exported package. */ public String getName(); /** * Returns the bundle exporting the package associated with this exported * package. * * @return The exporting bundle, or {@code null} if this * {@code ExportedPackage} object has become stale. */ public Bundle getExportingBundle(); /** * Returns the resolved bundles that are currently wired to this exported * package. * *

* Bundles which require the exporting bundle associated with this exported * package are considered to be wired to this exported package are included * in the returned array. See {@link RequiredBundle#getRequiringBundles()}. * * @return The array of resolved bundles currently wired to this exported * package, or {@code null} if this * {@code ExportedPackage} object has become stale. The array * will be empty if no bundles are wired to this exported package. */ public Bundle[] getImportingBundles(); /** * Returns the version of this exported package. * * @return The version of this exported package, or {@code null} if no * version information is available. * @deprecated As of 1.2, replaced by {@link #getVersion()}. */ public String getSpecificationVersion(); /** * Returns the version of this exported package. * * @return The version of this exported package, or * {@link Version#emptyVersion} if no version information is * available. * @since 1.2 */ public Version getVersion(); /** * Returns {@code true} if the package associated with this * {@code ExportedPackage} object has been exported by a bundle that * has been updated or uninstalled. * * @return {@code true} if the associated package is being exported * by a bundle that has been updated or uninstalled, or if this * {@code ExportedPackage} object has become stale; * {@code false} otherwise. */ public boolean isRemovalPending(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/startlevel/0000755000175000017500000000000012475375714025267 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/startlevel/packageinfo0000644000175000017500000000001412346513664027447 0ustar felixfelixversion 1.1 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/startlevel/StartLevel.java0000644000175000017500000002761212346513664030222 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2002, 2011). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.startlevel; import org.osgi.framework.Bundle; /** * The StartLevel service allows management agents to manage a start level * assigned to each bundle and the active start level of the Framework. There is * at most one StartLevel service present in the OSGi environment. * *

* A start level is defined to be a state of execution in which the Framework * exists. StartLevel values are defined as unsigned integers with 0 (zero) * being the state where the Framework is not launched. Progressively higher * integral values represent progressively higher start levels. e.g. 2 is a * higher start level than 1. *

* Access to the StartLevel service is protected by corresponding * {@code ServicePermission}. In addition {@code AdminPermission} * is required to actually modify start level information. *

* Start Level support in the Framework includes the ability to control the * beginning start level of the Framework, to modify the active start level of * the Framework and to assign a specific start level to a bundle. How the * beginning start level of a Framework is specified is implementation * dependent. It may be a command line argument when invoking the Framework * implementation. *

* When the Framework is first started it must be at start level zero. In this * state, no bundles are running. This is the initial state of the Framework * before it is launched. * * When the Framework is launched, the Framework will enter start level one and * all bundles which are assigned to start level one and whose autostart setting * indicates the bundle should be started are started as described in the * {@code Bundle.start} method. The Framework will continue to increase * the start level, starting bundles at each start level, until the Framework * has reached a beginning start level. At this point the Framework has * completed starting bundles and will then fire a Framework event of type * {@code FrameworkEvent.STARTED} to announce it has completed its * launch. * *

* Within a start level, bundles may be started in an order defined by the * Framework implementation. This may be something like ascending * {@code Bundle.getBundleId} order or an order based upon dependencies * between bundles. A similar but reversed order may be used when stopping * bundles within a start level. * *

* The StartLevel service can be used by management bundles to alter the active * start level of the framework. * * @ThreadSafe * @noimplement * @version $Id: ec0295bdf246c0258261374b3ac0e4aef11f7315 $ * @deprecated This service has been replaced by the * org.osgi.framework.startlevel package. */ public interface StartLevel { /** * Return the active start level value of the Framework. * * If the Framework is in the process of changing the start level this * method must return the active start level if this differs from the * requested start level. * * @return The active start level value of the Framework. */ public int getStartLevel(); /** * Modify the active start level of the Framework. * *

* The Framework will move to the requested start level. This method will * return immediately to the caller and the start level change will occur * asynchronously on another thread. * *

* If the specified start level is higher than the active start level, the * Framework will continue to increase the start level until the Framework * has reached the specified start level. * * At each intermediate start level value on the way to and including the * target start level, the Framework must: *

    *
  1. Change the active start level to the intermediate start level value. *
  2. Start bundles at the intermediate start level whose autostart * setting indicate they must be started. They are started as described in * the {@link Bundle#start(int)} method using the * {@link Bundle#START_TRANSIENT} option. The * {@link Bundle#START_ACTIVATION_POLICY} option must also be used if * {@link #isBundleActivationPolicyUsed(Bundle)} returns {@code true} * for the bundle. *
* When this process completes after the specified start level is reached, * the Framework will fire a Framework event of type * {@code FrameworkEvent.STARTLEVEL_CHANGED} to announce it has moved * to the specified start level. * *

* If the specified start level is lower than the active start level, the * Framework will continue to decrease the start level until the Framework * has reached the specified start level. * * At each intermediate start level value on the way to and including the * specified start level, the framework must: *

    *
  1. Stop bundles at the intermediate start level as described in the * {@link Bundle#stop(int)} method using the {@link Bundle#STOP_TRANSIENT} * option. *
  2. Change the active start level to the intermediate start level value. *
* When this process completes after the specified start level is reached, * the Framework will fire a Framework event of type * {@code FrameworkEvent.STARTLEVEL_CHANGED} to announce it has moved * to the specified start level. * *

* If the specified start level is equal to the active start level, then no * bundles are started or stopped, however, the Framework must fire a * Framework event of type {@code FrameworkEvent.STARTLEVEL_CHANGED} * to announce it has finished moving to the specified start level. This * event may arrive before this method return. * * @param startlevel The requested start level for the Framework. * @throws IllegalArgumentException If the specified start level is less * than or equal to zero. * @throws SecurityException If the caller does not have * {@code AdminPermission[System Bundle,STARTLEVEL]} and the * Java runtime environment supports permissions. */ public void setStartLevel(int startlevel); /** * Return the assigned start level value for the specified Bundle. * * @param bundle The target bundle. * @return The start level value of the specified Bundle. * @throws java.lang.IllegalArgumentException If the specified bundle has * been uninstalled or if the specified bundle was not created by * the same framework instance that registered this * {@code StartLevel} service. */ public int getBundleStartLevel(Bundle bundle); /** * Assign a start level value to the specified Bundle. * *

* The specified bundle will be assigned the specified start level. The * start level value assigned to the bundle will be persistently recorded by * the Framework. *

* If the new start level for the bundle is lower than or equal to the * active start level of the Framework and the bundle's autostart setting * indicates the bundle must be started, the Framework will start the * specified bundle as described in the {@link Bundle#start(int)} method * using the {@link Bundle#START_TRANSIENT} option. The * {@link Bundle#START_ACTIVATION_POLICY} option must also be used if * {@link #isBundleActivationPolicyUsed(Bundle)} returns {@code true} * for the bundle. The actual starting of this bundle must occur * asynchronously. *

* If the new start level for the bundle is higher than the active start * level of the Framework, the Framework will stop the specified bundle as * described in the {@link Bundle#stop(int)} method using the * {@link Bundle#STOP_TRANSIENT} option. The actual stopping of this bundle * must occur asynchronously. * * @param bundle The target bundle. * @param startlevel The new start level for the specified Bundle. * @throws IllegalArgumentException If the specified bundle has been * uninstalled, or if the specified start level is less than or * equal to zero, or if the specified bundle is the system bundle, * or if the specified bundle was not created by the same framework * instance that registered this {@code StartLevel} service. * @throws SecurityException If the caller does not have * {@code AdminPermission[bundle,EXECUTE]} and the Java runtime * environment supports permissions. */ public void setBundleStartLevel(Bundle bundle, int startlevel); /** * Return the initial start level value that is assigned to a Bundle when it * is first installed. * * @return The initial start level value for Bundles. * @see #setInitialBundleStartLevel(int) */ public int getInitialBundleStartLevel(); /** * Set the initial start level value that is assigned to a Bundle when it is * first installed. * *

* The initial bundle start level will be set to the specified start level. * The initial bundle start level value will be persistently recorded by the * Framework. * *

* When a Bundle is installed via {@code BundleContext.installBundle}, * it is assigned the initial bundle start level value. * *

* The default initial bundle start level value is 1 unless this method has * been called to assign a different initial bundle start level value. * *

* This method does not change the start level values of installed bundles. * * @param startlevel The initial start level for newly installed bundles. * @throws IllegalArgumentException If the specified start level is less * than or equal to zero. * @throws SecurityException If the caller does not have * {@code AdminPermission[System Bundle,STARTLEVEL]} and the * Java runtime environment supports permissions. */ public void setInitialBundleStartLevel(int startlevel); /** * Returns whether the specified bundle's autostart setting indicates the * bundle must be started. *

* The autostart setting of a bundle indicates whether the bundle is to be * started when its start level is reached. * * @param bundle The bundle whose autostart setting is to be examined. * @return {@code true} if the autostart setting of the bundle * indicates the bundle is to be started. {@code false} * otherwise. * @throws java.lang.IllegalArgumentException If the specified bundle has * been uninstalled or if the specified bundle was not created by * the same framework instance that registered this * {@code StartLevel} service. * @see Bundle#START_TRANSIENT */ public boolean isBundlePersistentlyStarted(Bundle bundle); /** * Returns whether the specified bundle's autostart setting indicates that * the activation policy declared in the bundle's manifest must be used. *

* The autostart setting of a bundle indicates whether the bundle's declared * activation policy is to be used when the bundle is started. * * @param bundle The bundle whose autostart setting is to be examined. * @return {@code true} if the bundle's autostart setting indicates the * activation policy declared in the manifest must be used. * {@code false} if the bundle must be eagerly activated. * @throws java.lang.IllegalArgumentException If the specified bundle has * been uninstalled or if the specified bundle was not created by * the same framework instance that registered this * {@code StartLevel} service. * @since 1.1 * @see Bundle#START_ACTIVATION_POLICY */ public boolean isBundleActivationPolicyUsed(Bundle bundle); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/startlevel/package-info.java0000644000175000017500000000227212346513664030454 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Start Level Package Version 1.1. * *

* Deprecated. * This package is deprecated and has been replaced by the * {@code org.osgi.framework.startlevel} package. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. * *

* Example import for consumers using the API in this package: *

* {@code Import-Package: org.osgi.service.startlevel; version="[1.1,2.0)"} * * @version $Id: 6e311e6e404688d5f5f88cde403ca2066de7c20b $ */ package org.osgi.service.startlevel; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/0000755000175000017500000000000012475375714025722 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/packageinfo0000644000175000017500000000001612346513664030104 0ustar felixfelixversion 1.1.1 ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/ConditionalPermissionAdmin0000644000175000017500000002530312346513664033130 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2005, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.condpermadmin; import java.security.AccessControlContext; import java.util.Enumeration; import org.osgi.service.permissionadmin.PermissionInfo; /** * Framework service to administer Conditional Permissions. Conditional * Permissions can be added to, retrieved from, and removed from the framework. * Conditional Permissions are conceptually managed in an ordered table called * the Conditional Permission Table. * * @ThreadSafe * @noimplement * @version $Id: 5be9948e8181bdf55154f25af1462a9d84990d93 $ */ public interface ConditionalPermissionAdmin { /** * Create a new Conditional Permission Info in the Conditional Permission * Table. *

* The Conditional Permission Info will be given a unique, never reused * name. This entry will be added at the beginning of the Conditional * Permission Table with an access decision of * {@link ConditionalPermissionInfo#ALLOW ALLOW}. *

* Since this method changes the Conditional Permission Table any * {@link ConditionalPermissionUpdate}s that were created prior to calling * this method can no longer be committed. * * @param conditions The conditions that need to be satisfied to enable the * specified permissions. This argument can be {@code null} or an * empty array indicating the specified permissions are not guarded * by any conditions. * @param permissions The permissions that are enabled when the specified * conditions, if any, are satisfied. This argument must not be * {@code null} and must specify at least one permission. * @return The ConditionalPermissionInfo for the specified Conditions and * Permissions. * @throws IllegalArgumentException If no permissions are specified. * @throws SecurityException If the caller does not have * {@code AllPermission}. * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()} * instead. */ ConditionalPermissionInfo addConditionalPermissionInfo(ConditionInfo[] conditions, PermissionInfo[] permissions); /** * Set or create a Conditional Permission Info with a specified name in the * Conditional Permission Table. *

* If the specified name is {@code null}, a new Conditional Permission Info * must be created and will be given a unique, never reused name. If there * is currently no Conditional Permission Info with the specified name, a * new Conditional Permission Info must be created with the specified name. * Otherwise, the Conditional Permission Info with the specified name must * be updated with the specified Conditions and Permissions. If a new entry * was created in the Conditional Permission Table it will be added at the * beginning of the table with an access decision of * {@link ConditionalPermissionInfo#ALLOW ALLOW}. *

* Since this method changes the underlying permission table any * {@link ConditionalPermissionUpdate}s that were created prior to calling * this method can no longer be committed. * * @param name The name of the Conditional Permission Info, or {@code null}. * @param conditions The conditions that need to be satisfied to enable the * specified permissions. This argument can be {@code null} or an * empty array indicating the specified permissions are not guarded * by any conditions. * @param permissions The permissions that are enabled when the specified * conditions, if any, are satisfied. This argument must not be * {@code null} and must specify at least one permission. * @return The ConditionalPermissionInfo for the specified name, Conditions * and Permissions. * @throws IllegalArgumentException If no permissions are specified. * @throws SecurityException If the caller does not have * {@code AllPermission}. * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()} * instead. */ ConditionalPermissionInfo setConditionalPermissionInfo(String name, ConditionInfo[] conditions, PermissionInfo[] permissions); /** * Returns the Conditional Permission Infos from the Conditional Permission * Table. *

* The returned Enumeration will return elements in the order they are kept * in the Conditional Permission Table. *

* The Enumeration returned is based on a copy of the Conditional Permission * Table and therefore will not throw exceptions if the Conditional * Permission Table is changed during the course of reading elements from * the Enumeration. * * @return An enumeration of the Conditional Permission Infos that are * currently in the Conditional Permission Table. * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()} * instead. */ Enumeration getConditionalPermissionInfos(); /** * Return the Conditional Permission Info with the specified name. * * @param name The name of the Conditional Permission Info to be returned. * @return The Conditional Permission Info with the specified name or * {@code null} if no Conditional Permission Info with the specified * name exists in the Conditional Permission Table. * @deprecated Since 1.1. Use {@link #newConditionalPermissionUpdate()} * instead. */ ConditionalPermissionInfo getConditionalPermissionInfo(String name); /** * Returns the Access Control Context that corresponds to the specified * signers. * * The returned Access Control Context must act as if its protection domain * came from a bundle that has the following characteristics: *

* * @param signers The signers for which to return an Access Control Context. * @return An {@code AccessControlContext} that has the Permissions * associated with the signer. */ AccessControlContext getAccessControlContext(String[] signers); /** * Creates a new update for the Conditional Permission Table. The update is * a working copy of the current Conditional Permission Table. If the * running Conditional Permission Table is modified before commit is called * on the returned update, then the call to commit on the returned update * will fail. That is, the commit method will return false and no change * will be made to the running Conditional Permission Table. There is no * requirement that commit is eventually called on the returned update. * * @return A new update for the Conditional Permission Table. * @since 1.1 */ ConditionalPermissionUpdate newConditionalPermissionUpdate(); /** * Creates a new ConditionalPermissionInfo with the specified fields * suitable for insertion into a {@link ConditionalPermissionUpdate}. The * {@code delete} method on {@code ConditionalPermissionInfo} objects * created with this method must throw UnsupportedOperationException. * * @param name The name of the created {@code ConditionalPermissionInfo} or * {@code null} to have a unique name generated when the returned * {@code ConditionalPermissionInfo} is committed in an update to the * Conditional Permission Table. * @param conditions The conditions that need to be satisfied to enable the * specified permissions. This argument can be {@code null} or an * empty array indicating the specified permissions are not guarded * by any conditions. * @param permissions The permissions that are enabled when the specified * conditions, if any, are satisfied. This argument must not be * {@code null} and must specify at least one permission. * @param access Access decision. Must be one of the following values: * * The specified access decision value must be evaluated case * insensitively. * @return A {@code ConditionalPermissionInfo} object suitable for insertion * into a {@link ConditionalPermissionUpdate}. * @throws IllegalArgumentException If no permissions are specified or if * the specified access decision is not a valid value. * @since 1.1 */ ConditionalPermissionInfo newConditionalPermissionInfo(String name, ConditionInfo[] conditions, PermissionInfo[] permissions, String access); /** * Creates a new {@code ConditionalPermissionInfo} from the specified * encoded {@code ConditionalPermissionInfo} string suitable for insertion * into a {@link ConditionalPermissionUpdate}. The {@code delete} method on * {@code ConditionalPermissionInfo} objects created with this method must * throw UnsupportedOperationException. * * @param encodedConditionalPermissionInfo The encoded * {@code ConditionalPermissionInfo}. White space in the encoded * {@code ConditionalPermissionInfo} is ignored. The access decision * value in the encoded {@code ConditionalPermissionInfo} must be * evaluated case insensitively. If the encoded * {@code ConditionalPermissionInfo} does not contain the optional * name, {@code null} must be used for the name and a unique name * will be generated when the returned * {@code ConditionalPermissionInfo} is committed in an update to the * Conditional Permission Table. * @return A {@code ConditionalPermissionInfo} object suitable for insertion * into a {@link ConditionalPermissionUpdate}. * @throws IllegalArgumentException If the specified * {@code encodedConditionalPermissionInfo} is not properly * formatted. * @see ConditionalPermissionInfo#getEncoded() * @since 1.1 */ ConditionalPermissionInfo newConditionalPermissionInfo(String encodedConditionalPermissionInfo); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/ConditionInfo.java0000644000175000017500000002221412346513664031323 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2004, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.condpermadmin; import java.util.ArrayList; import java.util.List; /** * Condition representation used by the Conditional Permission Admin service. * *

* This class encapsulates two pieces of information: a Condition type * (class name), which must implement {@code Condition}, and the arguments * passed to its constructor. * *

* In order for a Condition represented by a {@code ConditionInfo} to be * instantiated and considered during a permission check, its Condition class * must be available from the system classpath. * *

* The Condition class must either: *

* * @Immutable * @version $Id: c2497fefba5a0011a141f9548c3d383b34d3dc8d $ */ public class ConditionInfo { private final String type; private final String[] args; /** * Constructs a {@code ConditionInfo} from the specified type and args. * * @param type The fully qualified class name of the Condition represented * by this {@code ConditionInfo}. * @param args The arguments for the Condition. These arguments are * available to the newly created Condition by calling the * {@link #getArgs()} method. * @throws NullPointerException If {@code type} is {@code null}. */ public ConditionInfo(String type, String[] args) { this.type = type; this.args = (args != null) ? args.clone() : new String[0]; if (type == null) { throw new NullPointerException("type is null"); } } /** * Constructs a {@code ConditionInfo} object from the specified encoded * {@code ConditionInfo} string. White space in the encoded * {@code ConditionInfo} string is ignored. * * @param encodedCondition The encoded {@code ConditionInfo}. * @see #getEncoded() * @throws IllegalArgumentException If the specified * {@code encodedCondition} is not properly formatted. */ public ConditionInfo(String encodedCondition) { if (encodedCondition == null) { throw new NullPointerException("missing encoded condition"); } if (encodedCondition.length() == 0) { throw new IllegalArgumentException("empty encoded condition"); } try { char[] encoded = encodedCondition.toCharArray(); int length = encoded.length; int pos = 0; /* skip whitespace */ while (Character.isWhitespace(encoded[pos])) { pos++; } /* the first character must be '[' */ if (encoded[pos] != '[') { throw new IllegalArgumentException("expecting open bracket"); } pos++; /* skip whitespace */ while (Character.isWhitespace(encoded[pos])) { pos++; } /* type is not quoted or encoded */ int begin = pos; while (!Character.isWhitespace(encoded[pos]) && (encoded[pos] != ']')) { pos++; } if (pos == begin || encoded[begin] == '"') { throw new IllegalArgumentException("expecting type"); } this.type = new String(encoded, begin, pos - begin); /* skip whitespace */ while (Character.isWhitespace(encoded[pos])) { pos++; } /* type may be followed by args which are quoted and encoded */ List argsList = new ArrayList(); while (encoded[pos] == '"') { pos++; begin = pos; while (encoded[pos] != '"') { if (encoded[pos] == '\\') { pos++; } pos++; } argsList.add(unescapeString(encoded, begin, pos)); pos++; if (Character.isWhitespace(encoded[pos])) { /* skip whitespace */ while (Character.isWhitespace(encoded[pos])) { pos++; } } } this.args = argsList.toArray(new String[argsList.size()]); /* the final character must be ']' */ char c = encoded[pos]; pos++; while ((pos < length) && Character.isWhitespace(encoded[pos])) { pos++; } if ((c != ']') || (pos != length)) { throw new IllegalArgumentException("expecting close bracket"); } } catch (ArrayIndexOutOfBoundsException e) { throw new IllegalArgumentException("parsing terminated abruptly"); } } /** * Returns the string encoding of this {@code ConditionInfo} in a form * suitable for restoring this {@code ConditionInfo}. * *

* The encoded format is: * *

	 *   [type "arg0" "arg1" ...]
	 * 
* * where argN are strings that must be encoded for proper parsing. * Specifically, the {@code "}, {@code \}, carriage return, and line * feed characters must be escaped using {@code \"}, {@code \\}, * {@code \r}, and {@code \n}, respectively. * *

* The encoded string contains no leading or trailing whitespace characters. * A single space character is used between type and "arg0" * and between the arguments. * * @return The string encoding of this {@code ConditionInfo}. */ public final String getEncoded() { StringBuffer output = new StringBuffer(); output.append('['); output.append(type); for (int i = 0; i < args.length; i++) { output.append(" \""); escapeString(args[i], output); output.append('\"'); } output.append(']'); return output.toString(); } /** * Returns the string representation of this {@code ConditionInfo}. The * string is created by calling the {@code getEncoded} method on this * {@code ConditionInfo}. * * @return The string representation of this {@code ConditionInfo}. */ public String toString() { return getEncoded(); } /** * Returns the fully qualified class name of the condition represented by * this {@code ConditionInfo}. * * @return The fully qualified class name of the condition represented by * this {@code ConditionInfo}. */ public final String getType() { return type; } /** * Returns arguments of this {@code ConditionInfo}. * * @return The arguments of this {@code ConditionInfo}. An empty array is * returned if the {@code ConditionInfo} has no arguments. */ public final String[] getArgs() { return args.clone(); } /** * Determines the equality of two {@code ConditionInfo} objects. * * This method checks that specified object has the same type and args as * this {@code ConditionInfo} object. * * @param obj The object to test for equality with this * {@code ConditionInfo} object. * @return {@code true} if {@code obj} is a {@code ConditionInfo}, and has * the same type and args as this {@code ConditionInfo} object; * {@code false} otherwise. */ public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof ConditionInfo)) { return false; } ConditionInfo other = (ConditionInfo) obj; if (!type.equals(other.type) || args.length != other.args.length) return false; for (int i = 0; i < args.length; i++) { if (!args[i].equals(other.args[i])) return false; } return true; } /** * Returns the hash code value for this object. * * @return A hash code value for this object. */ public int hashCode() { int h = 31 * 17 + type.hashCode(); for (int i = 0; i < args.length; i++) { h = 31 * h + args[i].hashCode(); } return h; } /** * This escapes the quotes, backslashes, \n, and \r in the string using a * backslash and appends the newly escaped string to a StringBuffer. */ private static void escapeString(String str, StringBuffer output) { int len = str.length(); for (int i = 0; i < len; i++) { char c = str.charAt(i); switch (c) { case '"' : case '\\' : output.append('\\'); output.append(c); break; case '\r' : output.append("\\r"); break; case '\n' : output.append("\\n"); break; default : output.append(c); break; } } } /** * Takes an encoded character array and decodes it into a new String. */ private static String unescapeString(char[] str, int begin, int end) { StringBuffer output = new StringBuffer(end - begin); for (int i = begin; i < end; i++) { char c = str[i]; if (c == '\\') { i++; if (i < end) { c = str[i]; switch (c) { case '"' : case '\\' : break; case 'r' : c = '\r'; break; case 'n' : c = '\n'; break; default : c = '\\'; i--; break; } } } output.append(c); } return output.toString(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/Condition.java0000644000175000017500000001172212346513664030511 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2004, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.condpermadmin; import java.util.Dictionary; /** * The interface implemented by a Condition. Conditions are bound to Permissions * using Conditional Permission Info. The Permissions of a ConditionalPermission * Info can only be used if the associated Conditions are satisfied. * * @ThreadSafe * @version $Id: ae2500276f1204a47a981347579f5b53cc8a7e4f $ */ public interface Condition { /** * A Condition object that will always evaluate to true and that is never * postponed. */ public final static Condition TRUE = new BooleanCondition(true); /** * A Condition object that will always evaluate to false and that is never * postponed. */ public final static Condition FALSE = new BooleanCondition(false); /** * Returns whether the evaluation must be postponed until the end of the * permission check. If this method returns {@code false} (or this Condition * is immutable), then this Condition must be able to directly answer the * {@link #isSatisfied()} method. In other words, isSatisfied() will return * very quickly since no external sources, such as for example users or * networks, need to be consulted.
* This method must always return the same value whenever it is called so * that the Conditional Permission Admin can cache its result. * * @return {@code true} to indicate the evaluation must be postponed. * Otherwise, {@code false} if the evaluation can be performed * immediately. */ boolean isPostponed(); /** * Returns whether the Condition is satisfied. This method is only called * for immediate Condition objects or immutable postponed conditions, and * must always be called inside a permission check. Mutable postponed * Condition objects will be called with the grouped version * {@link #isSatisfied(Condition[],Dictionary)} at the end of the permission * check. * * @return {@code true} to indicate the Conditions is satisfied. Otherwise, * {@code false} if the Condition is not satisfied. */ boolean isSatisfied(); /** * Returns whether the Condition is mutable. A Condition can go from mutable * ({@code true}) to immutable ({@code false}) over time but never from * immutable ({@code false}) to mutable ({@code true}). * * @return {@code true} {@link #isSatisfied()} can change. Otherwise, * {@code false} if the value returned by {@link #isSatisfied()} * will not change for this condition. */ boolean isMutable(); /** * Returns whether the specified set of Condition objects are satisfied. * Although this method is not static, it must be implemented as if it were * static. All of the passed Condition objects will be of the same type and * will correspond to the class type of the object on which this method is * invoked. This method must be called inside a permission check only. * * @param conditions The array of Condition objects, which must all be of * the same class and mutable. The receiver must be one of those * Condition objects. * @param context A Dictionary object that implementors can use to track * state. If this method is invoked multiple times in the same * permission check, the same Dictionary will be passed multiple * times. The SecurityManager treats this Dictionary as an opaque * object and simply creates an empty dictionary and passes it to * subsequent invocations if multiple invocations are needed. * @return {@code true} if all the Condition objects are satisfied. * Otherwise, {@code false} if one of the Condition objects is not * satisfied. */ boolean isSatisfied(Condition conditions[], Dictionary context); } /** * Package private class used to define the {@link Condition#FALSE} and * {@link Condition#TRUE} constants. * * @Immutable */ final class BooleanCondition implements Condition { private final boolean satisfied; BooleanCondition(boolean satisfied) { this.satisfied = satisfied; } public boolean isPostponed() { return false; } public boolean isSatisfied() { return satisfied; } public boolean isMutable() { return false; } public boolean isSatisfied(Condition[] conds, Dictionary context) { for (int i = 0, length = conds.length; i < length; i++) { if (!conds[i].isSatisfied()) return false; } return true; } } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/ConditionalPermissionUpdate.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/ConditionalPermissionUpdat0000644000175000017500000000741112346513664033155 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2008, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.condpermadmin; import java.util.List; /** * Update the Conditional Permission Table. There may be many update objects in * the system at one time. If commit is called and the Conditional Permission * Table has been modified since this update was created, then the call to * commit will fail and this object should be discarded. * * @ThreadSafe * @noimplement * @version $Id: 7487aa7d2558f34c0115b924180ed17e6e13e22e $ * @since 1.1 */ public interface ConditionalPermissionUpdate { /** * This method returns the list of {@link ConditionalPermissionInfo}s for * this update. This list is originally based on the Conditional Permission * Table at the time this update was created. The list returned by this * method will be replace the Conditional Permission Table if commit is * called and is successful. *

* The {@link ConditionalPermissionInfo#delete() delete} method of the * ConditionalPermissionInfos in the list must throw * UnsupportedOperationException. *

* The list returned by this method is ordered and the most significant * table entry is the first entry in the list. * * @return A {@code List} of the {@link ConditionalPermissionInfo}s which * represent the Conditional Permissions maintained by this update. * Modifications to this list will not affect the Conditional * Permission Table until successfully committed. The list may be * empty if the Conditional Permission Table was empty when this * update was created. */ List getConditionalPermissionInfos(); /** * Commit this update. If no changes have been made to the Conditional * Permission Table since this update was created, then this method will * replace the Conditional Permission Table with this update's Conditional * Permissions. This method may only be successfully called once on this * object. *

* If any of the {@link ConditionalPermissionInfo}s in the update list has * {@code null} as a name it will be replaced with a new * {@link ConditionalPermissionInfo} object that has a generated name which * is unique within the list. *

* No two entries in this update's Conditional Permissions may have the same * name. Other consistency checks may also be performed. If this update's * Conditional Permissions are determined to be inconsistent in some way * then an {@code IllegalStateException} will be thrown. *

* This method returns {@code false} if the commit did not occur because the * Conditional Permission Table has been modified since the creation of this * update. * * @return {@code true} if the commit was successful. {@code false} if the * commit did not occur because the Conditional Permission Table has * been modified since the creation of this update. * @throws SecurityException If the caller does not have * {@code AllPermission}. * @throws IllegalStateException If this update's Conditional Permissions * are not valid or inconsistent. For example, this update has two * Conditional Permissions in it with the same name. */ boolean commit(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/package-info.java0000644000175000017500000000210412346513664031101 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Conditional Permission Admin Package Version 1.1. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. * *

* Example import for consumers using the API in this package: *

* {@code Import-Package: org.osgi.service.condpermadmin; version="[1.1,2.0)"} * * @version $Id: 233676a532c6248ff670390f6a25ba6d8399f4ff $ */ package org.osgi.service.condpermadmin; ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/BundleLocationCondition.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/BundleLocationCondition.ja0000644000175000017500000001117612346513664033010 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2005, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.condpermadmin; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Dictionary; import java.util.Hashtable; import org.osgi.framework.Bundle; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; /** * Condition to test if the location of a bundle matches or does not match a * pattern. Since the bundle's location cannot be changed, this condition is * immutable. * *

* Pattern matching is done according to the filter string matching rules. * * @ThreadSafe * @version $Id: 43b6af515f7f92b5fe8fde94cc0b03dc7044807b $ */ public class BundleLocationCondition { private static final String CONDITION_TYPE = "org.osgi.service.condpermadmin.BundleLocationCondition"; /** * Constructs a condition that tries to match the passed Bundle's location * to the location pattern. * * @param bundle The Bundle being evaluated. * @param info The ConditionInfo from which to construct the condition. The * ConditionInfo must specify one or two arguments. The first * argument of the ConditionInfo specifies the location pattern * against which to match the bundle location. Matching is done * according to the filter string matching rules. Any '*' characters * in the first argument are used as wildcards when matching bundle * locations unless they are escaped with a '\' character. The * Condition is satisfied if the bundle location matches the pattern. * The second argument of the ConditionInfo is optional. If a second * argument is present and equal to "!", then the satisfaction of the * Condition is negated. That is, the Condition is satisfied if the * bundle location does NOT match the pattern. If the second argument * is present but does not equal "!", then the second argument is * ignored. * @return Condition object for the requested condition. */ static public Condition getCondition(final Bundle bundle, final ConditionInfo info) { if (!CONDITION_TYPE.equals(info.getType())) throw new IllegalArgumentException("ConditionInfo must be of type \"" + CONDITION_TYPE + "\""); String[] args = info.getArgs(); if (args.length != 1 && args.length != 2) throw new IllegalArgumentException("Illegal number of args: " + args.length); String bundleLocation = AccessController.doPrivileged(new PrivilegedAction() { public String run() { return bundle.getLocation(); } }); Filter filter = null; try { filter = FrameworkUtil.createFilter("(location=" + escapeLocation(args[0]) + ")"); } catch (InvalidSyntaxException e) { // this should never happen, but just in case throw new RuntimeException("Invalid filter: " + e.getFilter(), e); } Dictionary matchProps = new Hashtable(2); matchProps.put("location", bundleLocation); boolean negate = (args.length == 2) ? "!".equals(args[1]) : false; return (negate ^ filter.match(matchProps)) ? Condition.TRUE : Condition.FALSE; } private BundleLocationCondition() { // private constructor to prevent objects of this type } /** * Escape the value string such that '(', ')' and '\' are escaped. The '\' * char is only escaped if it is not followed by a '*'. * * @param value unescaped value string. * @return escaped value string. */ private static String escapeLocation(final String value) { boolean escaped = false; int inlen = value.length(); int outlen = inlen << 1; /* inlen * 2 */ char[] output = new char[outlen]; value.getChars(0, inlen, output, inlen); int cursor = 0; for (int i = inlen; i < outlen; i++) { char c = output[i]; switch (c) { case '\\' : if (i + 1 < outlen && output[i + 1] == '*') break; case '(' : case ')' : output[cursor] = '\\'; cursor++; escaped = true; break; } output[cursor] = c; cursor++; } return escaped ? new String(output, 0, cursor) : value; } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/ConditionalPermissionInfo.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/ConditionalPermissionInfo.0000644000175000017500000001470412346513664033054 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2004, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.condpermadmin; import org.osgi.service.permissionadmin.PermissionInfo; /** * A list of Permissions guarded by a list of conditions with an access * decision. Instances of this interface are obtained from the Conditional * Permission Admin service. * * @Immutable * @noimplement * @version $Id: c4222b04d7ab4f8ccdb5def2bf5423c2e1d31f20 $ */ public interface ConditionalPermissionInfo { /** * This string is used to indicate that a row in the Conditional Permission * Table should return an access decision of "allow" if the * conditions are all satisfied and at least one of the permissions is * implied. * * @since 1.1 */ public final static String ALLOW = "allow"; /** * This string is used to indicate that a row in the Conditional Permission * Table should return an access decision of "deny" if the * conditions are all satisfied and at least one of the permissions is * implied. * * @since 1.1 */ public final static String DENY = "deny"; /** * Returns the Condition Infos for the Conditions that must be satisfied to * enable the Permissions. * * @return The Condition Infos for the Conditions in this Conditional * Permission Info. */ ConditionInfo[] getConditionInfos(); /** * Returns the Permission Infos for the Permissions in this Conditional * Permission Info. * * @return The Permission Infos for the Permissions in this Conditional * Permission Info. */ PermissionInfo[] getPermissionInfos(); /** * Removes this Conditional Permission Info from the Conditional Permission * Table. *

* Since this method changes the underlying permission table, any * {@link ConditionalPermissionUpdate}s that were created prior to calling * this method can no longer be committed. * * @throws UnsupportedOperationException If this object was created by * {@link ConditionalPermissionAdmin#newConditionalPermissionInfo(String)} * or * {@link ConditionalPermissionAdmin#newConditionalPermissionInfo(String, ConditionInfo[] , PermissionInfo[] , String)} * or obtained from a {@link ConditionalPermissionUpdate}. This * method only functions if this object was obtained from one of the * {@link ConditionalPermissionAdmin} methods deprecated in version * 1.1. * @throws SecurityException If the caller does not have * {@code AllPermission}. * @deprecated Since 1.1. Use * {@link ConditionalPermissionAdmin#newConditionalPermissionUpdate()} * instead to manage the Conditional Permissions. */ void delete(); /** * Returns the name of this Conditional Permission Info. * * @return The name of this Conditional Permission Info. This can be * {@code null} if this Conditional Permission Info was created * without a name. */ String getName(); /** * Returns the access decision for this Conditional Permission Info. * * @return One of the following values: *

* @since 1.1 */ String getAccessDecision(); /** * Returns the string encoding of this {@code ConditionalPermissionInfo} in * a form suitable for restoring this {@code ConditionalPermissionInfo}. * *

* The encoded format is: * *

	 *   access {conditions permissions} name
	 * 
* * where access is the access decision, conditions is zero or * more {@link ConditionInfo#getEncoded() encoded conditions}, * permissions is one or more {@link PermissionInfo#getEncoded() * encoded permissions} and name is the name of the * {@code ConditionalPermissionInfo}. * *

* name is optional. If name is present in the encoded string, * it must quoted, beginning and ending with {@code "}. The name * value must be encoded for proper parsing. Specifically, the * {@code "}, {@code \}, carriage return, and line feed characters must * be escaped using {@code \"}, {@code \\}, {@code \r}, and {@code \n}, * respectively. * *

* The encoded string contains no leading or trailing whitespace characters. * A single space character is used between access and { * and between } and name, if name is present. * All encoded conditions and permissions are separated by a single space * character. * * @return The string encoding of this {@code ConditionalPermissionInfo}. * @since 1.1 */ String getEncoded(); /** * Returns the string representation of this * {@code ConditionalPermissionInfo}. The string is created by calling the * {@code getEncoded} method on this {@code ConditionalPermissionInfo}. * * @return The string representation of this * {@code ConditionalPermissionInfo}. * @since 1.1 */ String toString(); /** * Determines the equality of two {@code ConditionalPermissionInfo} objects. * * This method checks that specified object has the same access decision, * conditions, permissions and name as this * {@code ConditionalPermissionInfo} object. * * @param obj The object to test for equality with this * {@code ConditionalPermissionInfo} object. * @return {@code true} if {@code obj} is a * {@code ConditionalPermissionInfo}, and has the same access * decision, conditions, permissions and name as this * {@code ConditionalPermissionInfo} object; {@code false} * otherwise. * @since 1.1 */ boolean equals(Object obj); /** * Returns the hash code value for this object. * * @return A hash code value for this object. * @since 1.1 */ int hashCode(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/service/condpermadmin/BundleSignerCondition.java0000644000175000017500000001103212346513664033005 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2005, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.condpermadmin; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; /** * Condition to test if the signer of a bundle matches or does not match a * pattern. Since the bundle's signer can only change when the bundle is * updated, this condition is immutable. *

* The condition expressed using a single String that specifies a Distinguished * Name (DN) chain to match bundle signers against. DN's are encoded using IETF * RFC 2253. Usually signers use certificates that are issued by certificate * authorities, which also have a corresponding DN and certificate. The * certificate authorities can form a chain of trust where the last DN and * certificate is known by the framework. The signer of a bundle is expressed as * signers DN followed by the DN of its issuer followed by the DN of the next * issuer until the DN of the root certificate authority. Each DN is separated * by a semicolon. *

* A bundle can satisfy this condition if one of its signers has a DN chain that * matches the DN chain used to construct this condition. Wildcards (`*') can be * used to allow greater flexibility in specifying the DN chains. Wildcards can * be used in place of DNs, RDNs, or the value in an RDN. If a wildcard is used * for a value of an RDN, the value must be exactly "*" and will match any value * for the corresponding type in that RDN. If a wildcard is used for a RDN, it * must be the first RDN and will match any number of RDNs (including zero * RDNs). * * @ThreadSafe * @version $Id: 8f8619a999cf2afba3d9c1e52e3fc0df2cde636c $ */ public class BundleSignerCondition { private static final String CONDITION_TYPE = "org.osgi.service.condpermadmin.BundleSignerCondition"; /** * Constructs a Condition that tries to match the passed Bundle's location * to the location pattern. * * @param bundle The Bundle being evaluated. * @param info The ConditionInfo from which to construct the condition. The * ConditionInfo must specify one or two arguments. The first * argument of the ConditionInfo specifies the chain of distinguished * names pattern to match against the signer of the bundle. The * Condition is satisfied if the signer of the bundle matches the * pattern. The second argument of the ConditionInfo is optional. If * a second argument is present and equal to "!", then the * satisfaction of the Condition is negated. That is, the Condition * is satisfied if the signer of the bundle does NOT match the * pattern. If the second argument is present but does not equal "!", * then the second argument is ignored. * @return A Condition which checks the signers of the specified bundle. */ public static Condition getCondition(final Bundle bundle, final ConditionInfo info) { if (!CONDITION_TYPE.equals(info.getType())) throw new IllegalArgumentException("ConditionInfo must be of type \"" + CONDITION_TYPE + "\""); String[] args = info.getArgs(); if (args.length != 1 && args.length != 2) throw new IllegalArgumentException("Illegal number of args: " + args.length); Map> signers = bundle.getSignerCertificates(Bundle.SIGNERS_TRUSTED); boolean match = false; for (List signerCerts : signers.values()) { List dnChain = new ArrayList(signerCerts.size()); for (X509Certificate signer : signerCerts) { dnChain.add(signer.getSubjectDN().getName()); } if (FrameworkUtil.matchDistinguishedNameChain(args[0], dnChain)) { match = true; break; } } boolean negate = (args.length == 2) ? "!".equals(args[1]) : false; return negate ^ match ? Condition.TRUE : Condition.FALSE; } private BundleSignerCondition() { // private constructor to prevent objects of this type } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/util/0000755000175000017500000000000012475375714022417 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/util/tracker/0000755000175000017500000000000012475375714024052 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/util/tracker/packageinfo0000644000175000017500000000001612346513664026234 0ustar felixfelixversion 1.5.1 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/util/tracker/AbstractTracked.java0000644000175000017500000003206012346513664027752 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2007, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.util.tracker; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * Abstract class to track items. If a Tracker is reused (closed then reopened), * then a new AbstractTracked object is used. This class acts a map of tracked * item -> customized object. Subclasses of this class will act as the listener * object for the tracker. This class is used to synchronize access to the * tracked items. This is not a public class. It is only for use by the * implementation of the Tracker class. * * @param The tracked item. It is the key. * @param The value mapped to the tracked item. * @param The reason the tracked item is being tracked or untracked. * @ThreadSafe * @version $Id: 16340086b98d308c2d12f13bcd87fc6467a5a367 $ * @since 1.4 */ abstract class AbstractTracked { /* set this to true to compile in debug messages */ static final boolean DEBUG = false; /** * Map of tracked items to customized objects. * * @GuardedBy this */ private final Map tracked; /** * Modification count. This field is initialized to zero and incremented by * modified. * * @GuardedBy this */ private int trackingCount; /** * List of items in the process of being added. This is used to deal with * nesting of events. Since events may be synchronously delivered, events * can be nested. For example, when processing the adding of a service and * the customizer causes the service to be unregistered, notification to the * nested call to untrack that the service was unregistered can be made to * the track method. * * Since the ArrayList implementation is not synchronized, all access to * this list must be protected by the same synchronized object for * thread-safety. * * @GuardedBy this */ private final List adding; /** * true if the tracked object is closed. * * This field is volatile because it is set by one thread and read by * another. */ volatile boolean closed; /** * Initial list of items for the tracker. This is used to correctly process * the initial items which could be modified before they are tracked. This * is necessary since the initial set of tracked items are not "announced" * by events and therefore the event which makes the item untracked could be * delivered before we track the item. * * An item must not be in both the initial and adding lists at the same * time. An item must be moved from the initial list to the adding list * "atomically" before we begin tracking it. * * Since the LinkedList implementation is not synchronized, all access to * this list must be protected by the same synchronized object for * thread-safety. * * @GuardedBy this */ private final LinkedList initial; /** * AbstractTracked constructor. */ AbstractTracked() { tracked = new HashMap(); trackingCount = 0; adding = new ArrayList(6); initial = new LinkedList(); closed = false; } /** * Set initial list of items into tracker before events begin to be * received. * * This method must be called from Tracker's open method while synchronized * on this object in the same synchronized block as the add listener call. * * @param list The initial list of items to be tracked. {@code null} entries * in the list are ignored. * @GuardedBy this */ void setInitial(S[] list) { if (list == null) { return; } for (S item : list) { if (item == null) { continue; } if (DEBUG) { System.out.println("AbstractTracked.setInitial: " + item); //$NON-NLS-1$ } initial.add(item); } } /** * Track the initial list of items. This is called after events can begin to * be received. * * This method must be called from Tracker's open method while not * synchronized on this object after the add listener call. * */ void trackInitial() { while (true) { S item; synchronized (this) { if (closed || (initial.size() == 0)) { /* * if there are no more initial items */ return; /* we are done */ } /* * move the first item from the initial list to the adding list * within this synchronized block. */ item = initial.removeFirst(); if (tracked.get(item) != null) { /* if we are already tracking this item */ if (DEBUG) { System.out.println("AbstractTracked.trackInitial[already tracked]: " + item); //$NON-NLS-1$ } continue; /* skip this item */ } if (adding.contains(item)) { /* * if this item is already in the process of being added. */ if (DEBUG) { System.out.println("AbstractTracked.trackInitial[already adding]: " + item); //$NON-NLS-1$ } continue; /* skip this item */ } adding.add(item); } if (DEBUG) { System.out.println("AbstractTracked.trackInitial: " + item); //$NON-NLS-1$ } trackAdding(item, null); /* * Begin tracking it. We call trackAdding * since we have already put the item in the * adding list. */ } } /** * Called by the owning Tracker object when it is closed. */ void close() { closed = true; } /** * Begin to track an item. * * @param item Item to be tracked. * @param related Action related object. */ void track(final S item, final R related) { final T object; synchronized (this) { if (closed) { return; } object = tracked.get(item); if (object == null) { /* we are not tracking the item */ if (adding.contains(item)) { /* if this item is already in the process of being added. */ if (DEBUG) { System.out.println("AbstractTracked.track[already adding]: " + item); //$NON-NLS-1$ } return; } adding.add(item); /* mark this item is being added */ } else { /* we are currently tracking this item */ if (DEBUG) { System.out.println("AbstractTracked.track[modified]: " + item); //$NON-NLS-1$ } modified(); /* increment modification count */ } } if (object == null) { /* we are not tracking the item */ trackAdding(item, related); } else { /* Call customizer outside of synchronized region */ customizerModified(item, related, object); /* * If the customizer throws an unchecked exception, it is safe to * let it propagate */ } } /** * Common logic to add an item to the tracker used by track and * trackInitial. The specified item must have been placed in the adding list * before calling this method. * * @param item Item to be tracked. * @param related Action related object. */ private void trackAdding(final S item, final R related) { if (DEBUG) { System.out.println("AbstractTracked.trackAdding: " + item); //$NON-NLS-1$ } T object = null; boolean becameUntracked = false; /* Call customizer outside of synchronized region */ try { object = customizerAdding(item, related); /* * If the customizer throws an unchecked exception, it will * propagate after the finally */ } finally { synchronized (this) { if (adding.remove(item) && !closed) { /* * if the item was not untracked during the customizer * callback */ if (object != null) { tracked.put(item, object); modified(); /* increment modification count */ notifyAll(); /* notify any waiters */ } } else { becameUntracked = true; } } } /* * The item became untracked during the customizer callback. */ if (becameUntracked && (object != null)) { if (DEBUG) { System.out.println("AbstractTracked.trackAdding[removed]: " + item); //$NON-NLS-1$ } /* Call customizer outside of synchronized region */ customizerRemoved(item, related, object); /* * If the customizer throws an unchecked exception, it is safe to * let it propagate */ } } /** * Discontinue tracking the item. * * @param item Item to be untracked. * @param related Action related object. */ void untrack(final S item, final R related) { final T object; synchronized (this) { if (initial.remove(item)) { /* * if this item is already in the list * of initial references to process */ if (DEBUG) { System.out.println("AbstractTracked.untrack[removed from initial]: " + item); //$NON-NLS-1$ } return; /* * we have removed it from the list and it will not be * processed */ } if (adding.remove(item)) { /* * if the item is in the process of * being added */ if (DEBUG) { System.out.println("AbstractTracked.untrack[being added]: " + item); //$NON-NLS-1$ } return; /* * in case the item is untracked while in the process of * adding */ } object = tracked.remove(item); /* * must remove from tracker before * calling customizer callback */ if (object == null) { /* are we actually tracking the item */ return; } modified(); /* increment modification count */ } if (DEBUG) { System.out.println("AbstractTracked.untrack[removed]: " + item); //$NON-NLS-1$ } /* Call customizer outside of synchronized region */ customizerRemoved(item, related, object); /* * If the customizer throws an unchecked exception, it is safe to let it * propagate */ } /** * Returns the number of tracked items. * * @return The number of tracked items. * * @GuardedBy this */ int size() { return tracked.size(); } /** * Returns if the tracker is empty. * * @return Whether the tracker is empty. * * @GuardedBy this * @since 1.5 */ boolean isEmpty() { return tracked.isEmpty(); } /** * Return the customized object for the specified item * * @param item The item to lookup in the map * @return The customized object for the specified item. * * @GuardedBy this */ T getCustomizedObject(final S item) { return tracked.get(item); } /** * Copy the tracked items into an array. * * @param list An array to contain the tracked items. * @return The specified list if it is large enough to hold the tracked * items or a new array large enough to hold the tracked items. * @GuardedBy this */ S[] copyKeys(final S[] list) { return tracked.keySet().toArray(list); } /** * Increment the modification count. If this method is overridden, the * overriding method MUST call this method to increment the tracking count. * * @GuardedBy this */ void modified() { trackingCount++; } /** * Returns the tracking count for this {@code ServiceTracker} object. * * The tracking count is initialized to 0 when this object is opened. Every * time an item is added, modified or removed from this object the tracking * count is incremented. * * @GuardedBy this * @return The tracking count for this object. */ int getTrackingCount() { return trackingCount; } /** * Copy the tracked items and associated values into the specified map. * * @param Type of {@code Map} to hold the tracked items and associated * values. * @param map The map into which to copy the tracked items and associated * values. This map must not be a user provided map so that user code * is not executed while synchronized on this. * @return The specified map. * @GuardedBy this * @since 1.5 */ > M copyEntries(final M map) { map.putAll(tracked); return map; } /** * Call the specific customizer adding method. This method must not be * called while synchronized on this object. * * @param item Item to be tracked. * @param related Action related object. * @return Customized object for the tracked item or {@code null} if the * item is not to be tracked. */ abstract T customizerAdding(final S item, final R related); /** * Call the specific customizer modified method. This method must not be * called while synchronized on this object. * * @param item Tracked item. * @param related Action related object. * @param object Customized object for the tracked item. */ abstract void customizerModified(final S item, final R related, final T object); /** * Call the specific customizer removed method. This method must not be * called while synchronized on this object. * * @param item Tracked item. * @param related Action related object. * @param object Customized object for the tracked item. */ abstract void customizerRemoved(final S item, final R related, final T object); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/util/tracker/ServiceTracker.java0000644000175000017500000010020312346513664027620 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.util.tracker; import java.lang.reflect.Array; import java.util.Collections; import java.util.SortedMap; import java.util.TreeMap; import org.osgi.framework.AllServiceListener; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; /** * The {@code ServiceTracker} class simplifies using services from the * Framework's service registry. *

* A {@code ServiceTracker} object is constructed with search criteria and a * {@code ServiceTrackerCustomizer} object. A {@code ServiceTracker} can use a * {@code ServiceTrackerCustomizer} to customize the service objects to be * tracked. The {@code ServiceTracker} can then be opened to begin tracking all * services in the Framework's service registry that match the specified search * criteria. The {@code ServiceTracker} correctly handles all of the details of * listening to {@code ServiceEvent}s and getting and ungetting services. *

* The {@code getServiceReferences} method can be called to get references to * the services being tracked. The {@code getService} and {@code getServices} * methods can be called to get the service objects for the tracked service. *

* The {@code ServiceTracker} class is thread-safe. It does not call a * {@code ServiceTrackerCustomizer} while holding any locks. * {@code ServiceTrackerCustomizer} implementations must also be thread-safe. * * @param The type of the service being tracked. * @param The type of the tracked object. * @ThreadSafe * @version $Id: 21926ad8717a91633face6bbf570febfcd23b1c7 $ */ public class ServiceTracker implements ServiceTrackerCustomizer { /* set this to true to compile in debug messages */ static final boolean DEBUG = false; /** * The Bundle Context used by this {@code ServiceTracker}. */ protected final BundleContext context; /** * The Filter used by this {@code ServiceTracker} which specifies the search * criteria for the services to track. * * @since 1.1 */ protected final Filter filter; /** * The {@code ServiceTrackerCustomizer} for this tracker. */ final ServiceTrackerCustomizer customizer; /** * Filter string for use when adding the ServiceListener. If this field is * set, then certain optimizations can be taken since we don't have a user * supplied filter. */ final String listenerFilter; /** * Class name to be tracked. If this field is set, then we are tracking by * class name. */ private final String trackClass; /** * Reference to be tracked. If this field is set, then we are tracking a * single ServiceReference. */ private final ServiceReference trackReference; /** * Tracked services: {@code ServiceReference} -> customized Object and * {@code ServiceListener} object */ private volatile Tracked tracked; /** * Accessor method for the current Tracked object. This method is only * intended to be used by the unsynchronized methods which do not modify the * tracked field. * * @return The current Tracked object. */ private Tracked tracked() { return tracked; } /** * Cached ServiceReference for getServiceReference. * * This field is volatile since it is accessed by multiple threads. */ private volatile ServiceReference cachedReference; /** * Cached service object for getService. * * This field is volatile since it is accessed by multiple threads. */ private volatile T cachedService; /** * Create a {@code ServiceTracker} on the specified {@code ServiceReference} * . * *

* The service referenced by the specified {@code ServiceReference} will be * tracked by this {@code ServiceTracker}. * * @param context The {@code BundleContext} against which the tracking is * done. * @param reference The {@code ServiceReference} for the service to be * tracked. * @param customizer The customizer object to call when services are added, * modified, or removed in this {@code ServiceTracker}. If customizer * is {@code null}, then this {@code ServiceTracker} will be used as * the {@code ServiceTrackerCustomizer} and this * {@code ServiceTracker} will call the * {@code ServiceTrackerCustomizer} methods on itself. */ public ServiceTracker(final BundleContext context, final ServiceReference reference, final ServiceTrackerCustomizer customizer) { this.context = context; this.trackReference = reference; this.trackClass = null; this.customizer = (customizer == null) ? this : customizer; this.listenerFilter = "(" + Constants.SERVICE_ID + "=" + reference.getProperty(Constants.SERVICE_ID).toString() + ")"; try { this.filter = context.createFilter(listenerFilter); } catch (InvalidSyntaxException e) { /* * we could only get this exception if the ServiceReference was * invalid */ IllegalArgumentException iae = new IllegalArgumentException("unexpected InvalidSyntaxException: " + e.getMessage()); iae.initCause(e); throw iae; } } /** * Create a {@code ServiceTracker} on the specified class name. * *

* Services registered under the specified class name will be tracked by * this {@code ServiceTracker}. * * @param context The {@code BundleContext} against which the tracking is * done. * @param clazz The class name of the services to be tracked. * @param customizer The customizer object to call when services are added, * modified, or removed in this {@code ServiceTracker}. If customizer * is {@code null}, then this {@code ServiceTracker} will be used as * the {@code ServiceTrackerCustomizer} and this * {@code ServiceTracker} will call the * {@code ServiceTrackerCustomizer} methods on itself. */ public ServiceTracker(final BundleContext context, final String clazz, final ServiceTrackerCustomizer customizer) { this.context = context; this.trackReference = null; this.trackClass = clazz; this.customizer = (customizer == null) ? this : customizer; // we call clazz.toString to verify clazz is non-null! this.listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz.toString() + ")"; try { this.filter = context.createFilter(listenerFilter); } catch (InvalidSyntaxException e) { /* * we could only get this exception if the clazz argument was * malformed */ IllegalArgumentException iae = new IllegalArgumentException("unexpected InvalidSyntaxException: " + e.getMessage()); iae.initCause(e); throw iae; } } /** * Create a {@code ServiceTracker} on the specified {@code Filter} object. * *

* Services which match the specified {@code Filter} object will be tracked * by this {@code ServiceTracker}. * * @param context The {@code BundleContext} against which the tracking is * done. * @param filter The {@code Filter} to select the services to be tracked. * @param customizer The customizer object to call when services are added, * modified, or removed in this {@code ServiceTracker}. If customizer * is null, then this {@code ServiceTracker} will be used as the * {@code ServiceTrackerCustomizer} and this {@code ServiceTracker} * will call the {@code ServiceTrackerCustomizer} methods on itself. * @since 1.1 */ public ServiceTracker(final BundleContext context, final Filter filter, final ServiceTrackerCustomizer customizer) { this.context = context; this.trackReference = null; this.trackClass = null; this.listenerFilter = filter.toString(); this.filter = filter; this.customizer = (customizer == null) ? this : customizer; if ((context == null) || (filter == null)) { /* * we throw a NPE here to be consistent with the other constructors */ throw new NullPointerException(); } } /** * Create a {@code ServiceTracker} on the specified class. * *

* Services registered under the name of the specified class will be tracked * by this {@code ServiceTracker}. * * @param context The {@code BundleContext} against which the tracking is * done. * @param clazz The class of the services to be tracked. * @param customizer The customizer object to call when services are added, * modified, or removed in this {@code ServiceTracker}. If customizer * is {@code null}, then this {@code ServiceTracker} will be used as * the {@code ServiceTrackerCustomizer} and this * {@code ServiceTracker} will call the * {@code ServiceTrackerCustomizer} methods on itself. * @since 1.5 */ public ServiceTracker(final BundleContext context, final Class clazz, final ServiceTrackerCustomizer customizer) { this(context, clazz.getName(), customizer); } /** * Open this {@code ServiceTracker} and begin tracking services. * *

* This implementation calls {@code open(false)}. * * @throws java.lang.IllegalStateException If the {@code BundleContext} with * which this {@code ServiceTracker} was created is no longer valid. * @see #open(boolean) */ public void open() { open(false); } /** * Open this {@code ServiceTracker} and begin tracking services. * *

* Services which match the search criteria specified when this * {@code ServiceTracker} was created are now tracked by this * {@code ServiceTracker}. * * @param trackAllServices If {@code true}, then this {@code ServiceTracker} * will track all matching services regardless of class loader * accessibility. If {@code false}, then this {@code ServiceTracker} * will only track matching services which are class loader * accessible to the bundle whose {@code BundleContext} is used by * this {@code ServiceTracker}. * @throws java.lang.IllegalStateException If the {@code BundleContext} with * which this {@code ServiceTracker} was created is no longer valid. * @since 1.3 */ public void open(boolean trackAllServices) { final Tracked t; synchronized (this) { if (tracked != null) { return; } if (DEBUG) { System.out.println("ServiceTracker.open: " + filter); } t = trackAllServices ? new AllTracked() : new Tracked(); synchronized (t) { try { context.addServiceListener(t, listenerFilter); ServiceReference[] references = null; if (trackClass != null) { references = getInitialReferences(trackAllServices, trackClass, null); } else { if (trackReference != null) { if (trackReference.getBundle() != null) { ServiceReference[] single = new ServiceReference[] {trackReference}; references = single; } } else { /* user supplied filter */ references = getInitialReferences(trackAllServices, null, listenerFilter); } } /* set tracked with the initial references */ t.setInitial(references); } catch (InvalidSyntaxException e) { throw new RuntimeException("unexpected InvalidSyntaxException: " + e.getMessage(), e); } } tracked = t; } /* Call tracked outside of synchronized region */ t.trackInitial(); /* process the initial references */ } /** * Returns the list of initial {@code ServiceReference}s that will be * tracked by this {@code ServiceTracker}. * * @param trackAllServices If {@code true}, use * {@code getAllServiceReferences}. * @param className The class name with which the service was registered, or * {@code null} for all services. * @param filterString The filter criteria or {@code null} for all services. * @return The list of initial {@code ServiceReference}s. * @throws InvalidSyntaxException If the specified filterString has an * invalid syntax. */ private ServiceReference[] getInitialReferences(boolean trackAllServices, String className, String filterString) throws InvalidSyntaxException { ServiceReference[] result = (ServiceReference[]) ((trackAllServices) ? context.getAllServiceReferences(className, filterString) : context.getServiceReferences(className, filterString)); return result; } /** * Close this {@code ServiceTracker}. * *

* This method should be called when this {@code ServiceTracker} should end * the tracking of services. * *

* This implementation calls {@link #getServiceReferences()} to get the list * of tracked services to remove. */ public void close() { final Tracked outgoing; final ServiceReference[] references; synchronized (this) { outgoing = tracked; if (outgoing == null) { return; } if (DEBUG) { System.out.println("ServiceTracker.close: " + filter); } outgoing.close(); references = getServiceReferences(); tracked = null; try { context.removeServiceListener(outgoing); } catch (IllegalStateException e) { /* In case the context was stopped. */ } } modified(); /* clear the cache */ synchronized (outgoing) { outgoing.notifyAll(); /* wake up any waiters */ } if (references != null) { for (int i = 0; i < references.length; i++) { outgoing.untrack(references[i], null); } } if (DEBUG) { if ((cachedReference == null) && (cachedService == null)) { System.out.println("ServiceTracker.close[cached cleared]: " + filter); } } } /** * Default implementation of the * {@code ServiceTrackerCustomizer.addingService} method. * *

* This method is only called when this {@code ServiceTracker} has been * constructed with a {@code null ServiceTrackerCustomizer} argument. * *

* This implementation returns the result of calling {@code getService} on * the {@code BundleContext} with which this {@code ServiceTracker} was * created passing the specified {@code ServiceReference}. *

* This method can be overridden in a subclass to customize the service * object to be tracked for the service being added. In that case, take care * not to rely on the default implementation of * {@link #removedService(ServiceReference, Object) removedService} to unget * the service. * * @param reference The reference to the service being added to this * {@code ServiceTracker}. * @return The service object to be tracked for the service added to this * {@code ServiceTracker}. * @see ServiceTrackerCustomizer#addingService(ServiceReference) */ public T addingService(ServiceReference reference) { T result = (T) context.getService(reference); return result; } /** * Default implementation of the * {@code ServiceTrackerCustomizer.modifiedService} method. * *

* This method is only called when this {@code ServiceTracker} has been * constructed with a {@code null ServiceTrackerCustomizer} argument. * *

* This implementation does nothing. * * @param reference The reference to modified service. * @param service The service object for the modified service. * @see ServiceTrackerCustomizer#modifiedService(ServiceReference, Object) */ public void modifiedService(ServiceReference reference, T service) { /* do nothing */ } /** * Default implementation of the * {@code ServiceTrackerCustomizer.removedService} method. * *

* This method is only called when this {@code ServiceTracker} has been * constructed with a {@code null ServiceTrackerCustomizer} argument. * *

* This implementation calls {@code ungetService}, on the * {@code BundleContext} with which this {@code ServiceTracker} was created, * passing the specified {@code ServiceReference}. *

* This method can be overridden in a subclass. If the default * implementation of {@link #addingService(ServiceReference) addingService} * method was used, this method must unget the service. * * @param reference The reference to removed service. * @param service The service object for the removed service. * @see ServiceTrackerCustomizer#removedService(ServiceReference, Object) */ public void removedService(ServiceReference reference, T service) { context.ungetService(reference); } /** * Wait for at least one service to be tracked by this * {@code ServiceTracker}. This method will also return when this * {@code ServiceTracker} is closed. * *

* It is strongly recommended that {@code waitForService} is not used during * the calling of the {@code BundleActivator} methods. * {@code BundleActivator} methods are expected to complete in a short * period of time. * *

* This implementation calls {@link #getService()} to determine if a service * is being tracked. * * @param timeout The time interval in milliseconds to wait. If zero, the * method will wait indefinitely. * @return Returns the result of {@link #getService()}. * @throws InterruptedException If another thread has interrupted the * current thread. * @throws IllegalArgumentException If the value of timeout is negative. */ public T waitForService(long timeout) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("timeout value is negative"); } T object = getService(); if (object != null) { return object; } final long endTime = (timeout == 0) ? 0 : (System.currentTimeMillis() + timeout); do { final Tracked t = tracked(); if (t == null) { /* if ServiceTracker is not open */ return null; } synchronized (t) { if (t.size() == 0) { t.wait(timeout); } } object = getService(); if (endTime > 0) { // if we have a timeout timeout = endTime - System.currentTimeMillis(); if (timeout <= 0) { // that has expired break; } } } while (object == null); return object; } /** * Return an array of {@code ServiceReference}s for all services being * tracked by this {@code ServiceTracker}. * * @return Array of {@code ServiceReference}s or {@code null} if no services * are being tracked. */ public ServiceReference[] getServiceReferences() { final Tracked t = tracked(); if (t == null) { /* if ServiceTracker is not open */ return null; } synchronized (t) { int length = t.size(); if (length == 0) { return null; } ServiceReference[] result = new ServiceReference[length]; return t.copyKeys(result); } } /** * Returns a {@code ServiceReference} for one of the services being tracked * by this {@code ServiceTracker}. * *

* If multiple services are being tracked, the service with the highest * ranking (as specified in its {@code service.ranking} property) is * returned. If there is a tie in ranking, the service with the lowest * service ID (as specified in its {@code service.id} property); that is, * the service that was registered first is returned. This is the same * algorithm used by {@code BundleContext.getServiceReference}. * *

* This implementation calls {@link #getServiceReferences()} to get the list * of references for the tracked services. * * @return A {@code ServiceReference} or {@code null} if no services are * being tracked. * @since 1.1 */ public ServiceReference getServiceReference() { ServiceReference reference = cachedReference; if (reference != null) { if (DEBUG) { System.out.println("ServiceTracker.getServiceReference[cached]: " + filter); } return reference; } if (DEBUG) { System.out.println("ServiceTracker.getServiceReference: " + filter); } ServiceReference[] references = getServiceReferences(); int length = (references == null) ? 0 : references.length; if (length == 0) { /* if no service is being tracked */ return null; } int index = 0; if (length > 1) { /* if more than one service, select highest ranking */ int rankings[] = new int[length]; int count = 0; int maxRanking = Integer.MIN_VALUE; for (int i = 0; i < length; i++) { Object property = references[i].getProperty(Constants.SERVICE_RANKING); int ranking = (property instanceof Integer) ? ((Integer) property).intValue() : 0; rankings[i] = ranking; if (ranking > maxRanking) { index = i; maxRanking = ranking; count = 1; } else { if (ranking == maxRanking) { count++; } } } if (count > 1) { /* if still more than one service, select lowest id */ long minId = Long.MAX_VALUE; for (int i = 0; i < length; i++) { if (rankings[i] == maxRanking) { long id = ((Long) (references[i].getProperty(Constants.SERVICE_ID))).longValue(); if (id < minId) { index = i; minId = id; } } } } } return cachedReference = references[index]; } /** * Returns the service object for the specified {@code ServiceReference} if * the specified referenced service is being tracked by this * {@code ServiceTracker}. * * @param reference The reference to the desired service. * @return A service object or {@code null} if the service referenced by the * specified {@code ServiceReference} is not being tracked. */ public T getService(ServiceReference reference) { final Tracked t = tracked(); if (t == null) { /* if ServiceTracker is not open */ return null; } synchronized (t) { return t.getCustomizedObject(reference); } } /** * Return an array of service objects for all services being tracked by this * {@code ServiceTracker}. * *

* This implementation calls {@link #getServiceReferences()} to get the list * of references for the tracked services and then calls * {@link #getService(ServiceReference)} for each reference to get the * tracked service object. * * @return An array of service objects or {@code null} if no services are * being tracked. */ public Object[] getServices() { final Tracked t = tracked(); if (t == null) { /* if ServiceTracker is not open */ return null; } synchronized (t) { ServiceReference[] references = getServiceReferences(); int length = (references == null) ? 0 : references.length; if (length == 0) { return null; } Object[] objects = new Object[length]; for (int i = 0; i < length; i++) { objects[i] = getService(references[i]); } return objects; } } /** * Returns a service object for one of the services being tracked by this * {@code ServiceTracker}. * *

* If any services are being tracked, this implementation returns the result * of calling {@code getService(getServiceReference())}. * * @return A service object or {@code null} if no services are being * tracked. */ public T getService() { T service = cachedService; if (service != null) { if (DEBUG) { System.out.println("ServiceTracker.getService[cached]: " + filter); } return service; } if (DEBUG) { System.out.println("ServiceTracker.getService: " + filter); } ServiceReference reference = getServiceReference(); if (reference == null) { return null; } return cachedService = getService(reference); } /** * Remove a service from this {@code ServiceTracker}. * * The specified service will be removed from this {@code ServiceTracker}. * If the specified service was being tracked then the * {@code ServiceTrackerCustomizer.removedService} method will be called for * that service. * * @param reference The reference to the service to be removed. */ public void remove(ServiceReference reference) { final Tracked t = tracked(); if (t == null) { /* if ServiceTracker is not open */ return; } t.untrack(reference, null); } /** * Return the number of services being tracked by this * {@code ServiceTracker}. * * @return The number of services being tracked. */ public int size() { final Tracked t = tracked(); if (t == null) { /* if ServiceTracker is not open */ return 0; } synchronized (t) { return t.size(); } } /** * Returns the tracking count for this {@code ServiceTracker}. * * The tracking count is initialized to 0 when this {@code ServiceTracker} * is opened. Every time a service is added, modified or removed from this * {@code ServiceTracker}, the tracking count is incremented. * *

* The tracking count can be used to determine if this * {@code ServiceTracker} has added, modified or removed a service by * comparing a tracking count value previously collected with the current * tracking count value. If the value has not changed, then no service has * been added, modified or removed from this {@code ServiceTracker} since * the previous tracking count was collected. * * @since 1.2 * @return The tracking count for this {@code ServiceTracker} or -1 if this * {@code ServiceTracker} is not open. */ public int getTrackingCount() { final Tracked t = tracked(); if (t == null) { /* if ServiceTracker is not open */ return -1; } synchronized (t) { return t.getTrackingCount(); } } /** * Called by the Tracked object whenever the set of tracked services is * modified. Clears the cache. */ /* * This method must not be synchronized since it is called by Tracked while * Tracked is synchronized. We don't want synchronization interactions * between the listener thread and the user thread. */ void modified() { cachedReference = null; /* clear cached value */ cachedService = null; /* clear cached value */ if (DEBUG) { System.out.println("ServiceTracker.modified: " + filter); } } /** * Return a {@code SortedMap} of the {@code ServiceReference}s and service * objects for all services being tracked by this {@code ServiceTracker}. * The map is sorted in reverse natural order of {@code ServiceReference}. * That is, the first entry is the service with the highest ranking and the * lowest service id. * * @return A {@code SortedMap} with the {@code ServiceReference}s and * service objects for all services being tracked by this * {@code ServiceTracker}. If no services are being tracked, then * the returned map is empty. * @since 1.5 */ public SortedMap, T> getTracked() { SortedMap, T> map = new TreeMap, T>(Collections.reverseOrder()); final Tracked t = tracked(); if (t == null) { /* if ServiceTracker is not open */ return map; } synchronized (t) { return t.copyEntries(map); } } /** * Return if this {@code ServiceTracker} is empty. * * @return {@code true} if this {@code ServiceTracker} is not tracking any * services. * @since 1.5 */ public boolean isEmpty() { final Tracked t = tracked(); if (t == null) { /* if ServiceTracker is not open */ return true; } synchronized (t) { return t.isEmpty(); } } /** * Return an array of service objects for all services being tracked by this * {@code ServiceTracker}. The runtime type of the returned array is that of * the specified array. * *

* This implementation calls {@link #getServiceReferences()} to get the list * of references for the tracked services and then calls * {@link #getService(ServiceReference)} for each reference to get the * tracked service object. * * @param array An array into which the tracked service objects will be * stored, if the array is large enough. * @return An array of service objects being tracked. If the specified array * is large enough to hold the result, then the specified array is * returned. If the specified array is longer then necessary to hold * the result, the array element after the last service object is * set to {@code null}. If the specified array is not large enough * to hold the result, a new array is created and returned. * @since 1.5 */ public T[] getServices(T[] array) { final Tracked t = tracked(); if (t == null) { /* if ServiceTracker is not open */ if (array.length > 0) { array[0] = null; } return array; } synchronized (t) { ServiceReference[] references = getServiceReferences(); int length = (references == null) ? 0 : references.length; if (length == 0) { if (array.length > 0) { array[0] = null; } return array; } if (length > array.length) { array = (T[]) Array.newInstance(array.getClass().getComponentType(), length); } for (int i = 0; i < length; i++) { array[i] = getService(references[i]); } if (array.length > length) { array[length] = null; } return array; } } /** * Inner class which subclasses AbstractTracked. This class is the * {@code ServiceListener} object for the tracker. * * @ThreadSafe */ private class Tracked extends AbstractTracked, T, ServiceEvent> implements ServiceListener { /** * Tracked constructor. */ Tracked() { super(); } /** * {@code ServiceListener} method for the {@code ServiceTracker} class. * This method must NOT be synchronized to avoid deadlock potential. * * @param event {@code ServiceEvent} object from the framework. */ final public void serviceChanged(final ServiceEvent event) { /* * Check if we had a delayed call (which could happen when we * close). */ if (closed) { return; } final ServiceReference reference = (ServiceReference) event.getServiceReference(); if (DEBUG) { System.out.println("ServiceTracker.Tracked.serviceChanged[" + event.getType() + "]: " + reference); } switch (event.getType()) { case ServiceEvent.REGISTERED : case ServiceEvent.MODIFIED : track(reference, event); /* * If the customizer throws an unchecked exception, it is * safe to let it propagate */ break; case ServiceEvent.MODIFIED_ENDMATCH : case ServiceEvent.UNREGISTERING : untrack(reference, event); /* * If the customizer throws an unchecked exception, it is * safe to let it propagate */ break; } } /** * Increment the tracking count and tell the tracker there was a * modification. * * @GuardedBy this */ final void modified() { super.modified(); /* increment the modification count */ ServiceTracker.this.modified(); } /** * Call the specific customizer adding method. This method must not be * called while synchronized on this object. * * @param item Item to be tracked. * @param related Action related object. * @return Customized object for the tracked item or {@code null} if the * item is not to be tracked. */ final T customizerAdding(final ServiceReference item, final ServiceEvent related) { return customizer.addingService(item); } /** * Call the specific customizer modified method. This method must not be * called while synchronized on this object. * * @param item Tracked item. * @param related Action related object. * @param object Customized object for the tracked item. */ final void customizerModified(final ServiceReference item, final ServiceEvent related, final T object) { customizer.modifiedService(item, object); } /** * Call the specific customizer removed method. This method must not be * called while synchronized on this object. * * @param item Tracked item. * @param related Action related object. * @param object Customized object for the tracked item. */ final void customizerRemoved(final ServiceReference item, final ServiceEvent related, final T object) { customizer.removedService(item, object); } } /** * Subclass of Tracked which implements the AllServiceListener interface. * This class is used by the ServiceTracker if open is called with true. * * @since 1.3 * @ThreadSafe */ private class AllTracked extends Tracked implements AllServiceListener { /** * AllTracked constructor. */ AllTracked() { super(); } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/util/tracker/BundleTracker.java0000644000175000017500000003620312346513664027441 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2007, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.util.tracker; import java.util.HashMap; import java.util.Map; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.SynchronousBundleListener; /** * The {@code BundleTracker} class simplifies tracking bundles much like the * {@code ServiceTracker} simplifies tracking services. *

* A {@code BundleTracker} is constructed with state criteria and a * {@code BundleTrackerCustomizer} object. A {@code BundleTracker} can use the * {@code BundleTrackerCustomizer} to select which bundles are tracked and to * create a customized object to be tracked with the bundle. The * {@code BundleTracker} can then be opened to begin tracking all bundles whose * state matches the specified state criteria. *

* The {@code getBundles} method can be called to get the {@code Bundle} objects * of the bundles being tracked. The {@code getObject} method can be called to * get the customized object for a tracked bundle. *

* The {@code BundleTracker} class is thread-safe. It does not call a * {@code BundleTrackerCustomizer} while holding any locks. * {@code BundleTrackerCustomizer} implementations must also be thread-safe. * * @param The type of the tracked object. * @ThreadSafe * @version $Id: f21db4fe54284d4810bd9b5fa2528957804e3a21 $ * @since 1.4 */ public class BundleTracker implements BundleTrackerCustomizer { /* set this to true to compile in debug messages */ static final boolean DEBUG = false; /** * The Bundle Context used by this {@code BundleTracker}. */ protected final BundleContext context; /** * The {@code BundleTrackerCustomizer} object for this tracker. */ final BundleTrackerCustomizer customizer; /** * Tracked bundles: {@code Bundle} object -> customized Object and * {@code BundleListener} object */ private volatile Tracked tracked; /** * Accessor method for the current Tracked object. This method is only * intended to be used by the unsynchronized methods which do not modify the * tracked field. * * @return The current Tracked object. */ private Tracked tracked() { return tracked; } /** * State mask for bundles being tracked. This field contains the ORed values * of the bundle states being tracked. */ final int mask; /** * Create a {@code BundleTracker} for bundles whose state is present in the * specified state mask. * *

* Bundles whose state is present on the specified state mask will be * tracked by this {@code BundleTracker}. * * @param context The {@code BundleContext} against which the tracking is * done. * @param stateMask The bit mask of the {@code OR}ing of the bundle states * to be tracked. * @param customizer The customizer object to call when bundles are added, * modified, or removed in this {@code BundleTracker}. If customizer * is {@code null}, then this {@code BundleTracker} will be used as * the {@code BundleTrackerCustomizer} and this {@code BundleTracker} * will call the {@code BundleTrackerCustomizer} methods on itself. * @see Bundle#getState() */ public BundleTracker(BundleContext context, int stateMask, BundleTrackerCustomizer customizer) { this.context = context; this.mask = stateMask; this.customizer = (customizer == null) ? this : customizer; } /** * Open this {@code BundleTracker} and begin tracking bundles. * *

* Bundle which match the state criteria specified when this * {@code BundleTracker} was created are now tracked by this * {@code BundleTracker}. * * @throws java.lang.IllegalStateException If the {@code BundleContext} with * which this {@code BundleTracker} was created is no longer valid. * @throws java.lang.SecurityException If the caller and this class do not * have the appropriate * {@code AdminPermission[context bundle,LISTENER]}, and the Java * Runtime Environment supports permissions. */ public void open() { final Tracked t; synchronized (this) { if (tracked != null) { return; } if (DEBUG) { System.out.println("BundleTracker.open"); //$NON-NLS-1$ } t = new Tracked(); synchronized (t) { context.addBundleListener(t); Bundle[] bundles = context.getBundles(); if (bundles != null) { int length = bundles.length; for (int i = 0; i < length; i++) { int state = bundles[i].getState(); if ((state & mask) == 0) { /* null out bundles whose states are not interesting */ bundles[i] = null; } } /* set tracked with the initial bundles */ t.setInitial(bundles); } } tracked = t; } /* Call tracked outside of synchronized region */ t.trackInitial(); /* process the initial references */ } /** * Close this {@code BundleTracker}. * *

* This method should be called when this {@code BundleTracker} should end * the tracking of bundles. * *

* This implementation calls {@link #getBundles()} to get the list of * tracked bundles to remove. */ public void close() { final Bundle[] bundles; final Tracked outgoing; synchronized (this) { outgoing = tracked; if (outgoing == null) { return; } if (DEBUG) { System.out.println("BundleTracker.close"); //$NON-NLS-1$ } outgoing.close(); bundles = getBundles(); tracked = null; try { context.removeBundleListener(outgoing); } catch (IllegalStateException e) { /* In case the context was stopped. */ } } if (bundles != null) { for (int i = 0; i < bundles.length; i++) { outgoing.untrack(bundles[i], null); } } } /** * Default implementation of the * {@code BundleTrackerCustomizer.addingBundle} method. * *

* This method is only called when this {@code BundleTracker} has been * constructed with a {@code null BundleTrackerCustomizer} argument. * *

* This implementation simply returns the specified {@code Bundle}. * *

* This method can be overridden in a subclass to customize the object to be * tracked for the bundle being added. * * @param bundle The {@code Bundle} being added to this * {@code BundleTracker} object. * @param event The bundle event which caused this customizer method to be * called or {@code null} if there is no bundle event associated with * the call to this method. * @return The specified bundle. * @see BundleTrackerCustomizer#addingBundle(Bundle, BundleEvent) */ public T addingBundle(Bundle bundle, BundleEvent event) { T result = (T) bundle; return result; } /** * Default implementation of the * {@code BundleTrackerCustomizer.modifiedBundle} method. * *

* This method is only called when this {@code BundleTracker} has been * constructed with a {@code null BundleTrackerCustomizer} argument. * *

* This implementation does nothing. * * @param bundle The {@code Bundle} whose state has been modified. * @param event The bundle event which caused this customizer method to be * called or {@code null} if there is no bundle event associated with * the call to this method. * @param object The customized object for the specified Bundle. * @see BundleTrackerCustomizer#modifiedBundle(Bundle, BundleEvent, Object) */ public void modifiedBundle(Bundle bundle, BundleEvent event, T object) { /* do nothing */ } /** * Default implementation of the * {@code BundleTrackerCustomizer.removedBundle} method. * *

* This method is only called when this {@code BundleTracker} has been * constructed with a {@code null BundleTrackerCustomizer} argument. * *

* This implementation does nothing. * * @param bundle The {@code Bundle} being removed. * @param event The bundle event which caused this customizer method to be * called or {@code null} if there is no bundle event associated with * the call to this method. * @param object The customized object for the specified bundle. * @see BundleTrackerCustomizer#removedBundle(Bundle, BundleEvent, Object) */ public void removedBundle(Bundle bundle, BundleEvent event, T object) { /* do nothing */ } /** * Return an array of {@code Bundle}s for all bundles being tracked by this * {@code BundleTracker}. * * @return An array of {@code Bundle}s or {@code null} if no bundles are * being tracked. */ public Bundle[] getBundles() { final Tracked t = tracked(); if (t == null) { /* if BundleTracker is not open */ return null; } synchronized (t) { int length = t.size(); if (length == 0) { return null; } return t.copyKeys(new Bundle[length]); } } /** * Returns the customized object for the specified {@code Bundle} if the * specified bundle is being tracked by this {@code BundleTracker}. * * @param bundle The {@code Bundle} being tracked. * @return The customized object for the specified {@code Bundle} or * {@code null} if the specified {@code Bundle} is not being * tracked. */ public T getObject(Bundle bundle) { final Tracked t = tracked(); if (t == null) { /* if BundleTracker is not open */ return null; } synchronized (t) { return t.getCustomizedObject(bundle); } } /** * Remove a bundle from this {@code BundleTracker}. * * The specified bundle will be removed from this {@code BundleTracker} . If * the specified bundle was being tracked then the * {@code BundleTrackerCustomizer.removedBundle} method will be called for * that bundle. * * @param bundle The {@code Bundle} to be removed. */ public void remove(Bundle bundle) { final Tracked t = tracked(); if (t == null) { /* if BundleTracker is not open */ return; } t.untrack(bundle, null); } /** * Return the number of bundles being tracked by this {@code BundleTracker}. * * @return The number of bundles being tracked. */ public int size() { final Tracked t = tracked(); if (t == null) { /* if BundleTracker is not open */ return 0; } synchronized (t) { return t.size(); } } /** * Returns the tracking count for this {@code BundleTracker}. * * The tracking count is initialized to 0 when this {@code BundleTracker} is * opened. Every time a bundle is added, modified or removed from this * {@code BundleTracker} the tracking count is incremented. * *

* The tracking count can be used to determine if this {@code BundleTracker} * has added, modified or removed a bundle by comparing a tracking count * value previously collected with the current tracking count value. If the * value has not changed, then no bundle has been added, modified or removed * from this {@code BundleTracker} since the previous tracking count was * collected. * * @return The tracking count for this {@code BundleTracker} or -1 if this * {@code BundleTracker} is not open. */ public int getTrackingCount() { final Tracked t = tracked(); if (t == null) { /* if BundleTracker is not open */ return -1; } synchronized (t) { return t.getTrackingCount(); } } /** * Return a {@code Map} with the {@code Bundle}s and customized objects for * all bundles being tracked by this {@code BundleTracker}. * * @return A {@code Map} with the {@code Bundle}s and customized objects for * all services being tracked by this {@code BundleTracker}. If no * bundles are being tracked, then the returned map is empty. * @since 1.5 */ public Map getTracked() { Map map = new HashMap(); final Tracked t = tracked(); if (t == null) { /* if BundleTracker is not open */ return map; } synchronized (t) { return t.copyEntries(map); } } /** * Return if this {@code BundleTracker} is empty. * * @return {@code true} if this {@code BundleTracker} is not tracking any * bundles. * @since 1.5 */ public boolean isEmpty() { final Tracked t = tracked(); if (t == null) { /* if BundleTracker is not open */ return true; } synchronized (t) { return t.isEmpty(); } } /** * Inner class which subclasses AbstractTracked. This class is the * {@code SynchronousBundleListener} object for the tracker. * * @ThreadSafe * @since 1.4 */ private final class Tracked extends AbstractTracked implements SynchronousBundleListener { /** * Tracked constructor. */ Tracked() { super(); } /** * {@code BundleListener} method for the {@code BundleTracker} class. * This method must NOT be synchronized to avoid deadlock potential. * * @param event {@code BundleEvent} object from the framework. */ public void bundleChanged(final BundleEvent event) { /* * Check if we had a delayed call (which could happen when we * close). */ if (closed) { return; } final Bundle bundle = event.getBundle(); final int state = bundle.getState(); if (DEBUG) { System.out.println("BundleTracker.Tracked.bundleChanged[" + state + "]: " + bundle); //$NON-NLS-1$ //$NON-NLS-2$ } if ((state & mask) != 0) { track(bundle, event); /* * If the customizer throws an unchecked exception, it is safe * to let it propagate */ } else { untrack(bundle, event); /* * If the customizer throws an unchecked exception, it is safe * to let it propagate */ } } /** * Call the specific customizer adding method. This method must not be * called while synchronized on this object. * * @param item Item to be tracked. * @param related Action related object. * @return Customized object for the tracked item or {@code null} if the * item is not to be tracked. */ T customizerAdding(final Bundle item, final BundleEvent related) { return customizer.addingBundle(item, related); } /** * Call the specific customizer modified method. This method must not be * called while synchronized on this object. * * @param item Tracked item. * @param related Action related object. * @param object Customized object for the tracked item. */ void customizerModified(final Bundle item, final BundleEvent related, final T object) { customizer.modifiedBundle(item, related, object); } /** * Call the specific customizer removed method. This method must not be * called while synchronized on this object. * * @param item Tracked item. * @param related Action related object. * @param object Customized object for the tracked item. */ void customizerRemoved(final Bundle item, final BundleEvent related, final T object) { customizer.removedBundle(item, related, object); } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/util/tracker/package-info.java0000644000175000017500000000203512346513664027234 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Tracker Package Version 1.5. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. * *

* Example import for consumers using the API in this package: *

* {@code Import-Package: org.osgi.util.tracker; version="[1.5,2.0)"} * * @version $Id: e24ccaae9b18ecce26ce0add3a47f1fe6dac84bb $ */ package org.osgi.util.tracker; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/util/tracker/BundleTrackerCustomizer.java0000644000175000017500000001012112346513664031515 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2007, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.util.tracker; import org.osgi.framework.Bundle; import org.osgi.framework.BundleEvent; /** * The {@code BundleTrackerCustomizer} interface allows a {@code BundleTracker} * to customize the {@code Bundle}s that are tracked. A * {@code BundleTrackerCustomizer} is called when a bundle is being added to a * {@code BundleTracker}. The {@code BundleTrackerCustomizer} can then return an * object for the tracked bundle. A {@code BundleTrackerCustomizer} is also * called when a tracked bundle is modified or has been removed from a * {@code BundleTracker}. * *

* The methods in this interface may be called as the result of a * {@code BundleEvent} being received by a {@code BundleTracker}. Since * {@code BundleEvent}s are received synchronously by the {@code BundleTracker}, * it is highly recommended that implementations of these methods do not alter * bundle states while being synchronized on any object. * *

* The {@code BundleTracker} class is thread-safe. It does not call a * {@code BundleTrackerCustomizer} while holding any locks. * {@code BundleTrackerCustomizer} implementations must also be thread-safe. * * @param The type of the tracked object. * @ThreadSafe * @version $Id: 727e757d2fa2940c88c9b74c8d299de6b3a7d0d0 $ * @since 1.4 */ public interface BundleTrackerCustomizer { /** * A bundle is being added to the {@code BundleTracker}. * *

* This method is called before a bundle which matched the search parameters * of the {@code BundleTracker} is added to the {@code BundleTracker}. This * method should return the object to be tracked for the specified * {@code Bundle}. The returned object is stored in the * {@code BundleTracker} and is available from the * {@link BundleTracker#getObject(Bundle) getObject} method. * * @param bundle The {@code Bundle} being added to the {@code BundleTracker} * . * @param event The bundle event which caused this customizer method to be * called or {@code null} if there is no bundle event associated with * the call to this method. * @return The object to be tracked for the specified {@code Bundle} object * or {@code null} if the specified {@code Bundle} object should not * be tracked. */ public T addingBundle(Bundle bundle, BundleEvent event); /** * A bundle tracked by the {@code BundleTracker} has been modified. * *

* This method is called when a bundle being tracked by the * {@code BundleTracker} has had its state modified. * * @param bundle The {@code Bundle} whose state has been modified. * @param event The bundle event which caused this customizer method to be * called or {@code null} if there is no bundle event associated with * the call to this method. * @param object The tracked object for the specified bundle. */ public void modifiedBundle(Bundle bundle, BundleEvent event, T object); /** * A bundle tracked by the {@code BundleTracker} has been removed. * *

* This method is called after a bundle is no longer being tracked by the * {@code BundleTracker}. * * @param bundle The {@code Bundle} that has been removed. * @param event The bundle event which caused this customizer method to be * called or {@code null} if there is no bundle event associated with * the call to this method. * @param object The tracked object for the specified bundle. */ public void removedBundle(Bundle bundle, BundleEvent event, T object); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/util/tracker/ServiceTrackerCustomizer.java0000644000175000017500000000744612346513664031724 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.util.tracker; import org.osgi.framework.ServiceReference; /** * The {@code ServiceTrackerCustomizer} interface allows a * {@code ServiceTracker} to customize the service objects that are tracked. A * {@code ServiceTrackerCustomizer} is called when a service is being added to a * {@code ServiceTracker}. The {@code ServiceTrackerCustomizer} can then return * an object for the tracked service. A {@code ServiceTrackerCustomizer} is also * called when a tracked service is modified or has been removed from a * {@code ServiceTracker}. * *

* The methods in this interface may be called as the result of a * {@code ServiceEvent} being received by a {@code ServiceTracker}. Since * {@code ServiceEvent}s are synchronously delivered by the Framework, it is * highly recommended that implementations of these methods do not register ( * {@code BundleContext.registerService}), modify ( * {@code ServiceRegistration.setProperties}) or unregister ( * {@code ServiceRegistration.unregister}) a service while being synchronized on * any object. * *

* The {@code ServiceTracker} class is thread-safe. It does not call a * {@code ServiceTrackerCustomizer} while holding any locks. * {@code ServiceTrackerCustomizer} implementations must also be thread-safe. * * @param The type of the service being tracked. * @param The type of the tracked object. * @ThreadSafe * @version $Id: c14b8d47026b6bd4ba1f2db7bf7e755d00fc6f6a $ */ public interface ServiceTrackerCustomizer { /** * A service is being added to the {@code ServiceTracker}. * *

* This method is called before a service which matched the search * parameters of the {@code ServiceTracker} is added to the * {@code ServiceTracker}. This method should return the service object to * be tracked for the specified {@code ServiceReference}. The returned * service object is stored in the {@code ServiceTracker} and is available * from the {@code getService} and {@code getServices} methods. * * @param reference The reference to the service being added to the * {@code ServiceTracker}. * @return The service object to be tracked for the specified referenced * service or {@code null} if the specified referenced service * should not be tracked. */ public T addingService(ServiceReference reference); /** * A service tracked by the {@code ServiceTracker} has been modified. * *

* This method is called when a service being tracked by the * {@code ServiceTracker} has had it properties modified. * * @param reference The reference to the service that has been modified. * @param service The service object for the specified referenced service. */ public void modifiedService(ServiceReference reference, T service); /** * A service tracked by the {@code ServiceTracker} has been removed. * *

* This method is called after a service is no longer being tracked by the * {@code ServiceTracker}. * * @param reference The reference to the service that has been removed. * @param service The service object for the specified referenced service. */ public void removedService(ServiceReference reference, T service); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/0000755000175000017500000000000012475375714023437 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/VersionRange.java0000644000175000017500000003726012346513664026707 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.util.NoSuchElementException; import java.util.StringTokenizer; /** * Version range. A version range is an interval describing a set of * {@link Version versions}. * *

* A range has a left (lower) endpoint and a right (upper) endpoint. Each * endpoint can be open (excluded from the set) or closed (included in the set). * *

* {@code VersionRange} objects are immutable. * * @since 1.7 * @Immutable * @version $Id: d0c21e6a5015a7fa0b33179a29122ea7d137145a $ */ public class VersionRange { /** * The left endpoint is open and is excluded from the range. *

* The value of {@code LEFT_OPEN} is {@code '('}. */ public static final char LEFT_OPEN = '('; /** * The left endpoint is closed and is included in the range. *

* The value of {@code LEFT_CLOSED} is {@code '['}. */ public static final char LEFT_CLOSED = '['; /** * The right endpoint is open and is excluded from the range. *

* The value of {@code RIGHT_OPEN} is {@code ')'}. */ public static final char RIGHT_OPEN = ')'; /** * The right endpoint is closed and is included in the range. *

* The value of {@code RIGHT_CLOSED} is {@code ']'}. */ public static final char RIGHT_CLOSED = ']'; private final boolean leftClosed; private final Version left; private final Version right; private final boolean rightClosed; private final boolean empty; private transient String versionRangeString /* default to null */; private transient int hash /* default to 0 */; private static final String LEFT_OPEN_DELIMITER = "("; private static final String LEFT_CLOSED_DELIMITER = "["; private static final String LEFT_DELIMITERS = LEFT_CLOSED_DELIMITER + LEFT_OPEN_DELIMITER; private static final String RIGHT_OPEN_DELIMITER = ")"; private static final String RIGHT_CLOSED_DELIMITER = "]"; private static final String RIGHT_DELIMITERS = RIGHT_OPEN_DELIMITER + RIGHT_CLOSED_DELIMITER; private static final String ENDPOINT_DELIMITER = ","; /** * Creates a version range from the specified versions. * * @param leftType Must be either {@link #LEFT_CLOSED} or {@link #LEFT_OPEN} * . * @param leftEndpoint Left endpoint of range. Must not be {@code null}. * @param rightEndpoint Right endpoint of range. May be {@code null} to * indicate the right endpoint is Infinity. * @param rightType Must be either {@link #RIGHT_CLOSED} or * {@link #RIGHT_OPEN}. * @throws IllegalArgumentException If the arguments are invalid. */ public VersionRange(char leftType, Version leftEndpoint, Version rightEndpoint, char rightType) { if ((leftType != LEFT_CLOSED) && (leftType != LEFT_OPEN)) { throw new IllegalArgumentException("invalid leftType \"" + leftType + "\""); } if ((rightType != RIGHT_OPEN) && (rightType != RIGHT_CLOSED)) { throw new IllegalArgumentException("invalid rightType \"" + rightType + "\""); } if (leftEndpoint == null) { throw new IllegalArgumentException("null leftEndpoint argument"); } leftClosed = leftType == LEFT_CLOSED; rightClosed = rightType == RIGHT_CLOSED; left = leftEndpoint; right = rightEndpoint; empty = isEmpty0(); } /** * Creates a version range from the specified string. * *

* Version range string grammar: * *

	 * range ::= interval | atleast
	 * interval ::= ( '[' | '(' ) left ',' right ( ']' | ')' )
	 * left ::= version
	 * right ::= version
	 * atleast ::= version
	 * 
* * @param range String representation of the version range. The versions in * the range must contain no whitespace. Other whitespace in the * range string is ignored. * @throws IllegalArgumentException If {@code range} is improperly * formatted. */ public VersionRange(String range) { boolean closedLeft; boolean closedRight; Version endpointLeft; Version endpointRight; try { StringTokenizer st = new StringTokenizer(range, LEFT_DELIMITERS, true); String token = st.nextToken().trim(); // whitespace or left delim if (token.length() == 0) { // leading whitespace token = st.nextToken(); // left delim } closedLeft = LEFT_CLOSED_DELIMITER.equals(token); if (!closedLeft && !LEFT_OPEN_DELIMITER.equals(token)) { // first token is not a delimiter, so it must be "atleast" if (st.hasMoreTokens()) { // there must be no more tokens throw new IllegalArgumentException("invalid range \"" + range + "\": invalid format"); } leftClosed = true; rightClosed = false; left = parseVersion(token, range); right = null; empty = false; return; } String version = st.nextToken(ENDPOINT_DELIMITER); endpointLeft = parseVersion(version, range); token = st.nextToken(); // consume comma version = st.nextToken(RIGHT_DELIMITERS); token = st.nextToken(); // right delim closedRight = RIGHT_CLOSED_DELIMITER.equals(token); if (!closedRight && !RIGHT_OPEN_DELIMITER.equals(token)) { throw new IllegalArgumentException("invalid range \"" + range + "\": invalid format"); } endpointRight = parseVersion(version, range); if (st.hasMoreTokens()) { // any more tokens have to be whitespace token = st.nextToken("").trim(); if (token.length() != 0) { // trailing whitespace throw new IllegalArgumentException("invalid range \"" + range + "\": invalid format"); } } } catch (NoSuchElementException e) { IllegalArgumentException iae = new IllegalArgumentException("invalid range \"" + range + "\": invalid format"); iae.initCause(e); throw iae; } leftClosed = closedLeft; rightClosed = closedRight; left = endpointLeft; right = endpointRight; empty = isEmpty0(); } /** * Parse version component into a Version. * * @param version version component string * @param range Complete range string for exception message, if any * @return Version */ private static Version parseVersion(String version, String range) { try { return Version.parseVersion(version); } catch (IllegalArgumentException e) { IllegalArgumentException iae = new IllegalArgumentException("invalid range \"" + range + "\": " + e.getMessage()); iae.initCause(e); throw iae; } } /** * Returns the left endpoint of this version range. * * @return The left endpoint. */ public Version getLeft() { return left; } /** * Returns the right endpoint of this version range. * * @return The right endpoint. May be {@code null} which indicates the right * endpoint is Infinity. */ public Version getRight() { return right; } /** * Returns the type of the left endpoint of this version range. * * @return {@link #LEFT_CLOSED} if the left endpoint is closed or * {@link #LEFT_OPEN} if the left endpoint is open. */ public char getLeftType() { return leftClosed ? LEFT_CLOSED : LEFT_OPEN; } /** * Returns the type of the right endpoint of this version range. * * @return {@link #RIGHT_CLOSED} if the right endpoint is closed or * {@link #RIGHT_OPEN} if the right endpoint is open. */ public char getRightType() { return rightClosed ? RIGHT_CLOSED : RIGHT_OPEN; } /** * Returns whether this version range includes the specified version. * * @param version The version to test for inclusion in this version range. * @return {@code true} if the specified version is included in this version * range; {@code false} otherwise. */ public boolean includes(Version version) { if (empty) { return false; } if (left.compareTo(version) >= (leftClosed ? 1 : 0)) { return false; } if (right == null) { return true; } return right.compareTo(version) >= (rightClosed ? 0 : 1); } /** * Returns the intersection of this version range with the specified version * ranges. * * @param ranges The version ranges to intersect with this version range. * @return A version range representing the intersection of this version * range and the specified version ranges. If no version ranges are * specified, then this version range is returned. */ public VersionRange intersection(VersionRange... ranges) { if ((ranges == null) || (ranges.length == 0)) { return this; } // prime with data from this version range boolean closedLeft = leftClosed; boolean closedRight = rightClosed; Version endpointLeft = left; Version endpointRight = right; for (VersionRange range : ranges) { int comparison = endpointLeft.compareTo(range.left); if (comparison == 0) { closedLeft = closedLeft && range.leftClosed; } else { if (comparison < 0) { // move endpointLeft to the right endpointLeft = range.left; closedLeft = range.leftClosed; } } if (range.right != null) { if (endpointRight == null) { endpointRight = range.right; closedRight = range.rightClosed; } else { comparison = endpointRight.compareTo(range.right); if (comparison == 0) { closedRight = closedRight && range.rightClosed; } else { if (comparison > 0) { // move endpointRight to the left endpointRight = range.right; closedRight = range.rightClosed; } } } } } return new VersionRange(closedLeft ? LEFT_CLOSED : LEFT_OPEN, endpointLeft, endpointRight, closedRight ? RIGHT_CLOSED : RIGHT_OPEN); } /** * Returns whether this version range is empty. A version range is empty if * the set of versions defined by the interval is empty. * * @return {@code true} if this version range is empty; {@code false} * otherwise. */ public boolean isEmpty() { return empty; } /** * Internal isEmpty behavior. * * @return {@code true} if this version range is empty; {@code false} * otherwise. */ private boolean isEmpty0() { if (right == null) { // infinity return false; } int comparison = left.compareTo(right); if (comparison == 0) { // endpoints equal return !leftClosed || !rightClosed; } return comparison > 0; // true if left > right } /** * Returns whether this version range contains only a single version. * * @return {@code true} if this version range contains only a single * version; {@code false} otherwise. */ public boolean isExact() { if (empty || (right == null)) { return false; } if (leftClosed) { if (rightClosed) { // [l,r]: exact if l == r return left.equals(right); } else { // [l,r): exact if l++ >= r Version adjacent1 = new Version(left.getMajor(), left.getMinor(), left.getMicro(), left.getQualifier() + "-"); return adjacent1.compareTo(right) >= 0; } } else { if (rightClosed) { // (l,r] is equivalent to [l++,r]: exact if l++ == r Version adjacent1 = new Version(left.getMajor(), left.getMinor(), left.getMicro(), left.getQualifier() + "-"); return adjacent1.equals(right); } else { // (l,r) is equivalent to [l++,r): exact if (l++)++ >=r Version adjacent2 = new Version(left.getMajor(), left.getMinor(), left.getMicro(), left.getQualifier() + "--"); return adjacent2.compareTo(right) >= 0; } } } /** * Returns the string representation of this version range. * *

* The format of the version range string will be a version string if the * right end point is Infinity ({@code null}) or an interval string. * * @return The string representation of this version range. */ public String toString() { if (versionRangeString != null) { return versionRangeString; } String leftVersion = left.toString(); if (right == null) { StringBuffer result = new StringBuffer(leftVersion.length() + 1); result.append(left.toString0()); return versionRangeString = result.toString(); } String rightVerion = right.toString(); StringBuffer result = new StringBuffer(leftVersion.length() + rightVerion.length() + 5); result.append(leftClosed ? LEFT_CLOSED : LEFT_OPEN); result.append(left.toString0()); result.append(ENDPOINT_DELIMITER); result.append(right.toString0()); result.append(rightClosed ? RIGHT_CLOSED : RIGHT_OPEN); return versionRangeString = result.toString(); } /** * Returns a hash code value for the object. * * @return An integer which is a hash code value for this object. */ public int hashCode() { if (hash != 0) { return hash; } if (empty) { return hash = 31; } int h = 31 + (leftClosed ? 7 : 5); h = 31 * h + left.hashCode(); if (right != null) { h = 31 * h + right.hashCode(); h = 31 * h + (rightClosed ? 7 : 5); } return hash = h; } /** * Compares this {@code VersionRange} object to another object. * *

* A version range is considered to be equal to another version * range if both the endpoints and their types are equal or if both version * ranges are {@link #isEmpty() empty}. * * @param object The {@code VersionRange} object to be compared. * @return {@code true} if {@code object} is a {@code VersionRange} and is * equal to this object; {@code false} otherwise. */ public boolean equals(Object object) { if (object == this) { // quicktest return true; } if (!(object instanceof VersionRange)) { return false; } VersionRange other = (VersionRange) object; if (empty && other.empty) { return true; } if (right == null) { return (leftClosed == other.leftClosed) && (other.right == null) && left.equals(other.left); } return (leftClosed == other.leftClosed) && (rightClosed == other.rightClosed) && left.equals(other.left) && right.equals(other.right); } /** * Returns the filter string for this version range using the specified * attribute name. * * @param attributeName The attribute name to use in the returned filter * string. * @return A filter string for this version range using the specified * attribute name. * @throws IllegalArgumentException If the specified attribute name is not a * valid attribute name. * * @see "Core Specification, Filters, for a description of the filter string syntax." */ public String toFilterString(String attributeName) { if (attributeName.length() == 0) { throw new IllegalArgumentException("invalid attributeName \"" + attributeName + "\""); } for (char ch : attributeName.toCharArray()) { if ((ch == '=') || (ch == '>') || (ch == '<') || (ch == '~') || (ch == '(') || (ch == ')')) { throw new IllegalArgumentException("invalid attributeName \"" + attributeName + "\""); } } StringBuffer result = new StringBuffer(128); if (right != null) { result.append("(&"); } if (leftClosed) { result.append('('); result.append(attributeName); result.append(">="); result.append(left.toString0()); result.append(')'); } else { result.append("(!("); result.append(attributeName); result.append("<="); result.append(left.toString0()); result.append("))"); } if (right != null) { if (rightClosed) { result.append('('); result.append(attributeName); result.append("<="); result.append(right.toString0()); result.append(')'); } else { result.append("(!("); result.append(attributeName); result.append(">="); result.append(right.toString0()); result.append("))"); } result.append(')'); } return result.toString(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/packageinfo0000644000175000017500000000001412346513664025617 0ustar felixfelixversion 1.7 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/BundleEvent.java0000644000175000017500000001434412346513664026516 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.util.EventObject; /** * An event from the Framework describing a bundle lifecycle change. *

* {@code BundleEvent} objects are delivered to * {@code SynchronousBundleListener}s and {@code BundleListener}s when a change * occurs in a bundle's lifecycle. A type code is used to identify the event * type for future extendability. * *

* OSGi Alliance reserves the right to extend the set of types. * * @Immutable * @see BundleListener * @see SynchronousBundleListener * @version $Id: 9e2102212eb526b5f11fdde4b0fc5c171a0b39c8 $ */ public class BundleEvent extends EventObject { static final long serialVersionUID = 4080640865971756012L; /** * Bundle that had a change occur in its lifecycle. */ private final Bundle bundle; /** * Type of bundle lifecycle change. */ private final int type; /** * The bundle has been installed. * * @see BundleContext#installBundle(String) */ public final static int INSTALLED = 0x00000001; /** * The bundle has been started. *

* The bundle's {@link BundleActivator#start(BundleContext) BundleActivator * start} method has been executed if the bundle has a bundle activator * class. * * @see Bundle#start() */ public final static int STARTED = 0x00000002; /** * The bundle has been stopped. *

* The bundle's {@link BundleActivator#stop(BundleContext) BundleActivator * stop} method has been executed if the bundle has a bundle activator * class. * * @see Bundle#stop() */ public final static int STOPPED = 0x00000004; /** * The bundle has been updated. * * @see Bundle#update() */ public final static int UPDATED = 0x00000008; /** * The bundle has been uninstalled. * * @see Bundle#uninstall() */ public final static int UNINSTALLED = 0x00000010; /** * The bundle has been resolved. * * @see Bundle#RESOLVED * @since 1.3 */ public final static int RESOLVED = 0x00000020; /** * The bundle has been unresolved. * * @see Bundle#INSTALLED * @since 1.3 */ public final static int UNRESOLVED = 0x00000040; /** * The bundle is about to be activated. *

* The bundle's {@link BundleActivator#start(BundleContext) BundleActivator * start} method is about to be called if the bundle has a bundle activator * class. This event is only delivered to {@link SynchronousBundleListener} * s. It is not delivered to {@code BundleListener}s. * * @see Bundle#start() * @since 1.3 */ public final static int STARTING = 0x00000080; /** * The bundle is about to deactivated. *

* The bundle's {@link BundleActivator#stop(BundleContext) BundleActivator * stop} method is about to be called if the bundle has a bundle activator * class. This event is only delivered to {@link SynchronousBundleListener} * s. It is not delivered to {@code BundleListener}s. * * @see Bundle#stop() * @since 1.3 */ public final static int STOPPING = 0x00000100; /** * The bundle will be lazily activated. *

* The bundle has a {@link Constants#ACTIVATION_LAZY lazy activation policy} * and is waiting to be activated. It is now in the {@link Bundle#STARTING * STARTING} state and has a valid {@code BundleContext}. This event is only * delivered to {@link SynchronousBundleListener}s. It is not delivered to * {@code BundleListener}s. * * @since 1.4 */ public final static int LAZY_ACTIVATION = 0x00000200; /** * Bundle that was the origin of the event. For install event type, this is * the bundle whose context was used to install the bundle. Otherwise it is * the bundle itself. * * @since 1.6 */ private final Bundle origin; /** * Creates a bundle event of the specified type. * * @param type The event type. * @param bundle The bundle which had a lifecycle change. * @param origin The bundle which is the origin of the event. For the event * type {@link #INSTALLED}, this is the bundle whose context was used * to install the bundle. Otherwise it is the bundle itself. * @since 1.6 */ public BundleEvent(int type, Bundle bundle, Bundle origin) { super(bundle); if (origin == null) { throw new IllegalArgumentException("null origin"); } this.bundle = bundle; this.type = type; this.origin = origin; } /** * Creates a bundle event of the specified type. * * @param type The event type. * @param bundle The bundle which had a lifecycle change. This bundle is * used as the origin of the event. */ public BundleEvent(int type, Bundle bundle) { super(bundle); this.bundle = bundle; this.type = type; this.origin = bundle; } /** * Returns the bundle which had a lifecycle change. This bundle is the * source of the event. * * @return The bundle that had a change occur in its lifecycle. */ public Bundle getBundle() { return bundle; } /** * Returns the type of lifecyle event. The type values are: *

    *
  • {@link #INSTALLED} *
  • {@link #RESOLVED} *
  • {@link #LAZY_ACTIVATION} *
  • {@link #STARTING} *
  • {@link #STARTED} *
  • {@link #STOPPING} *
  • {@link #STOPPED} *
  • {@link #UPDATED} *
  • {@link #UNRESOLVED} *
  • {@link #UNINSTALLED} *
* * @return The type of lifecycle event. */ public int getType() { return type; } /** * Returns the bundle that was the origin of the event. * *

* For the event type {@link #INSTALLED}, this is the bundle whose context * was used to install the bundle. Otherwise it is the bundle itself. * * @return The bundle that was the origin of the event. * @since 1.6 */ public Bundle getOrigin() { return origin; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/Configurable.java0000644000175000017500000000352712346513664026704 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; /** * Supports a configuration object. * *

* {@code Configurable} is an interface that should be used by a bundle * developer in support of a configurable service. Bundles that need to * configure a service may test to determine if the service object is an * {@code instanceof Configurable}. * * @deprecated As of 1.2. Please use Configuration Admin service. * @version $Id: 1018601ae90d2d16ec34136db4b04dca3ccf8e65 $ */ public interface Configurable { /** * Returns this service's configuration object. * *

* Services implementing {@code Configurable} should take care when * returning a service configuration object since this object is probably * sensitive. *

* If the Java Runtime Environment supports permissions, it is recommended * that the caller is checked for some appropriate permission before * returning the configuration object. * * @return The configuration object for this service. * @throws SecurityException If the caller does not have an appropriate * permission and the Java Runtime Environment supports permissions. * @deprecated As of 1.2. Please use Configuration Admin service. */ public Object getConfigurationObject(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/ServiceException.java0000644000175000017500000000714112346513664027557 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2007, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; /** * A service exception used to indicate that a service problem occurred. * *

* A {@code ServiceException} object is created by the Framework or service * implementation to denote an exception condition in the service. A type code * is used to identify the exception type for future extendability. Service * implementations may also create subclasses of {@code ServiceException}. When * subclassing, the subclass should set the type to {@link #SUBCLASSED} to * indicate that {@code ServiceException} has been subclassed. * *

* This exception conforms to the general purpose exception chaining mechanism. * * @version $Id: 9f763412635f59585bb615cbc449fc7ab72b7103 $ * @since 1.5 */ public class ServiceException extends RuntimeException { static final long serialVersionUID = 3038963223712959631L; /** * Type of service exception. */ private final int type; /** * No exception type is unspecified. */ public static final int UNSPECIFIED = 0; /** * The service has been unregistered. */ public static final int UNREGISTERED = 1; /** * The service factory produced an invalid service object. */ public static final int FACTORY_ERROR = 2; /** * The service factory threw an exception. */ public static final int FACTORY_EXCEPTION = 3; /** * The exception is a subclass of ServiceException. The subclass should be * examined for the type of the exception. */ public static final int SUBCLASSED = 4; /** * An error occurred invoking a remote service. */ public static final int REMOTE = 5; /** * The service factory resulted in a recursive call to itself for the * requesting bundle. * * @since 1.6 */ public static final int FACTORY_RECURSION = 6; /** * Creates a {@code ServiceException} with the specified message and * exception cause. * * @param msg The associated message. * @param cause The cause of this exception. */ public ServiceException(String msg, Throwable cause) { this(msg, UNSPECIFIED, cause); } /** * Creates a {@code ServiceException} with the specified message. * * @param msg The message. */ public ServiceException(String msg) { this(msg, UNSPECIFIED); } /** * Creates a {@code ServiceException} with the specified message, type and * exception cause. * * @param msg The associated message. * @param type The type for this exception. * @param cause The cause of this exception. */ public ServiceException(String msg, int type, Throwable cause) { super(msg, cause); this.type = type; } /** * Creates a {@code ServiceException} with the specified message and type. * * @param msg The message. * @param type The type for this exception. */ public ServiceException(String msg, int type) { super(msg); this.type = type; } /** * Returns the type for this exception or {@code UNSPECIFIED} if the type * was unspecified or unknown. * * @return The type of this exception. */ public int getType() { return type; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/SignerProperty.java0000644000175000017500000000662312346513664027300 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2009, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Package private class used by permissions for filter matching on signer key * during filter expression evaluation in the permission implies method. * * @Immutable * @version $Id: 94eea19050b84907f1257d7a12ebf8ab404f4473 $ */ final class SignerProperty { private final Bundle bundle; private final String pattern; /** * String constructor used by the filter matching algorithm to construct a * SignerProperty from the attribute value in a filter expression. * * @param pattern Attribute value in the filter expression. */ public SignerProperty(String pattern) { this.pattern = pattern; this.bundle = null; } /** * Used by the permission implies method to build the properties for a * filter match. * * @param bundle The bundle whose signers are to be matched. */ SignerProperty(Bundle bundle) { this.bundle = bundle; this.pattern = null; } /** * Used by the filter matching algorithm. This methods does NOT satisfy the * normal equals contract. Since the class is only used in filter expression * evaluations, it only needs to support comparing an instance created with * a Bundle to an instance created with a pattern string from the filter * expression. * * @param o SignerProperty to compare against. * @return true if the DN name chain matches the pattern. */ public boolean equals(Object o) { if (!(o instanceof SignerProperty)) return false; SignerProperty other = (SignerProperty) o; Bundle matchBundle = bundle != null ? bundle : other.bundle; String matchPattern = bundle != null ? other.pattern : pattern; Map> signers = matchBundle.getSignerCertificates(Bundle.SIGNERS_TRUSTED); for (List signerCerts : signers.values()) { List dnChain = new ArrayList(signerCerts.size()); for (X509Certificate signerCert : signerCerts) { dnChain.add(signerCert.getSubjectDN().getName()); } try { if (FrameworkUtil.matchDistinguishedNameChain(matchPattern, dnChain)) { return true; } } catch (IllegalArgumentException e) { continue; // bad pattern } } return false; } /** * Since the equals method does not obey the general equals contract, this * method cannot generate hash codes which obey the equals contract. */ public int hashCode() { return 31; } /** * Check if the bundle is signed. * * @return true if constructed with a bundle that is signed. */ boolean isBundleSigned() { if (bundle == null) { return false; } Map> signers = bundle.getSignerCertificates(Bundle.SIGNERS_TRUSTED); return !signers.isEmpty(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/0000755000175000017500000000000012475375714024562 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/resolver/0000755000175000017500000000000012475375714026423 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/resolver/packageinfo0000644000175000017500000000001412346513664030603 0ustar felixfelixversion 1.0 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/resolver/ResolverHook.java0000644000175000017500000002453012346513664031707 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.hooks.resolver; import java.util.Collection; import org.osgi.framework.Bundle; import org.osgi.framework.namespace.BundleNamespace; import org.osgi.framework.namespace.IdentityNamespace; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.FrameworkWiring; /** * OSGi Framework Resolver Hook instances are obtained from the OSGi * {@link ResolverHookFactory Framework Resolver Hook Factory} service. * *

* A Resolver Hook instance is called by the framework during a resolve process. * A resolver hook may influence the outcome of a resolve process by removing * entries from shrinkable collections that are passed to the hook during a * resolve process. A shrinkable collection is a {@code Collection} that * supports all remove operations. Any other attempts to modify a shrinkable * collection will result in an {@code UnsupportedOperationException} being * thrown. * *

* The following steps outline the way a framework uses the resolver hooks * during a resolve process. *

    *
  1. Collect a snapshot of registered resolver hook factories that will be * called during the current resolve process. Any hook factories registered * after the snapshot is taken must not be called during the current resolve * process. A resolver hook factory contained in the snapshot may become * unregistered during the resolve process. The framework should handle this and * stop calling the resolver hook instance provided by the unregistered hook * factory and the current resolve process must fail. If possible, an exception * must be thrown to the caller of the API which triggered the resolve process. * In cases where the the caller is not available a framework event of type * error should be fired.
  2. * *
  3. For each registered hook factory call the * {@link ResolverHookFactory#begin(Collection)} method to inform the hooks * about a resolve process beginning and to obtain a Resolver Hook instance that * will be used for the duration of the resolve process.
  4. * *
  5. Determine the collection of unresolved bundle revisions that may be * considered for resolution during the current resolution process and place * each of the bundle revisions in a shrinkable collection {@code Resolvable}. * For each resolver hook call the {@link #filterResolvable(Collection)} method * with the shrinkable collection {@code Resolvable}.
  6. *
  7. The shrinkable collection {@code Resolvable} now contains all the * unresolved bundle revisions that may end up as resolved at the end of the * current resolve process. Any other bundle revisions that got removed from the * shrinkable collection {@code Resolvable} must not end up as resolved at the * end of the current resolve process.
  8. *
  9. For each bundle revision {@code B} left in the shrinkable collection * {@code Resolvable} and any bundle revision {@code B} which is currently * resolved that represents a singleton bundle do the following: *

    * Determine the collection of available capabilities that have a namespace of * {@link IdentityNamespace osgi.identity}, are singletons, and have the same * symbolic name as the singleton bundle revision {@code B} and place each of * the matching capabilities into a shrinkable collection {@code Collisions}. *

    * Remove the {@link IdentityNamespace osgi.identity} capability provided by * bundle revision {@code B} from shrinkable collection {@code Collisions}. A * singleton bundle cannot collide with itself. *

    * For each resolver hook call the * {@link #filterSingletonCollisions(BundleCapability, Collection)} with the * {@link IdentityNamespace osgi.identity} capability provided by bundle * revision {@code B} and the shrinkable collection {@code Collisions} *

    * The shrinkable collection {@code Collisions} now contains all singleton * {@link IdentityNamespace osgi.identity} capabilities that can influence the * ability of bundle revision {@code B} to resolve. *

    * If the bundle revision {@code B} is already resolved then any resolvable * bundle revision contained in the collection {@code Collisions} is not allowed * to resolve.

  10. *
  11. During a resolve process a framework is free to attempt to resolve any or * all bundles contained in shrinkable collection {@code Resolvable}. For each * bundle revision {@code B} left in the shrinkable collection * {@code Resolvable} which the framework attempts to resolve the following * steps must be followed: *

    * For each requirement {@code R} specified by bundle revision {@code B} * determine the collection of capabilities that satisfy (or match) the * requirement and place each matching capability into a shrinkable collection * {@code Candidates}. A capability is considered to match a particular * requirement if its attributes satisfy a specified requirement and the * requirer bundle has permission to access the capability. * *

    * For each resolver hook call the * {@link #filterMatches(BundleRequirement, Collection)} with the requirement * {@code R} and the shrinkable collection {@code Candidates}. * *

    * The shrinkable collection {@code Candidates} now contains all the * capabilities that may be used to satisfy the requirement {@code R}. Any other * capabilities that got removed from the shrinkable collection * {@code Candidates} must not be used to satisfy requirement {@code R}.

  12. *
  13. For each resolver hook call the {@link #end()} method to inform the hooks * about a resolve process ending.
  14. *
* In all cases, the order in which the resolver hooks are called is the reverse * compareTo ordering of their Service References. That is, the service with the * highest ranking number must be called first. In cases where a shrinkable * collection becomes empty the framework is required to call the remaining * registered hooks. *

* Resolver hooks are low level. Implementations of the resolver hook must be * careful not to create an unresolvable state which is very hard for a * developer or a provisioner to diagnose. Resolver hooks also must not be * allowed to start another synchronous resolve process (e.g. by calling * {@link Bundle#start()} or {@link FrameworkWiring#resolveBundles(Collection)} * ). The framework must detect this and throw an {@link IllegalStateException}. * * @see ResolverHookFactory * @NotThreadSafe * @version $Id: 9d3ef6240aead0952b5a47b793780c1c0589089a $ */ public interface ResolverHook { /** * Filter resolvable candidates hook method. This method may be called * multiple times during a single resolve process. This method can filter * the collection of candidates by removing potential candidates. Removing a * candidate will prevent the candidate from resolving during the current * resolve process. * * @param candidates the collection of resolvable candidates available * during a resolve process. */ void filterResolvable(Collection candidates); /** * Filter singleton collisions hook method. This method is called during the * resolve process for the specified singleton. The specified singleton * represents a singleton capability and the specified collection represent * a collection of singleton capabilities which are considered collision * candidates. The singleton capability and the collection of collision * candidates must all use the same namespace. *

* Currently only capabilities with the namespace of {@link BundleNamespace * osgi.wiring.bundle} and {@link IdentityNamespace osgi.identity} can be * singletons. The collision candidates will all have the same namespace, be * singletons, and have the same symbolic name as the specified singleton * capability. *

* In the future, capabilities in other namespaces may support the singleton * concept. Hook implementations should be prepared to receive calls to this * method for capabilities in namespaces other than {@link BundleNamespace * osgi.wiring.bundle} or {@link IdentityNamespace osgi.identity}. *

* This method can filter the list of collision candidates by removing * potential collisions. Removing a collision candidate will allow the * specified singleton to resolve regardless of the resolution state of the * removed collision candidate. * * @param singleton the singleton involved in a resolve process * @param collisionCandidates a collection of singleton collision candidates */ void filterSingletonCollisions(BundleCapability singleton, Collection collisionCandidates); /** * Filter matches hook method. This method is called during the resolve * process for the specified requirement. The collection of candidates match * the specified requirement. This method can filter the collection of * matching candidates by removing candidates from the collection. Removing * a candidate will prevent the resolve process from choosing the removed * candidate to satisfy the requirement. *

* All of the candidates will have the same namespace and will match the * specified requirement. *

* If the Java Runtime Environment supports permissions then the collection * of candidates will only contain candidates for which the requirer has * permission to access. * * @param requirement the requirement to filter candidates for * @param candidates a collection of candidates that match the requirement */ void filterMatches(BundleRequirement requirement, Collection candidates); /** * This method is called once at the end of the resolve process. After the * end method is called the resolve process has ended. The framework must * not hold onto this resolver hook instance after end has been called. */ void end(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/resolver/package-info.java0000644000175000017500000000210612346513664031604 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Framework Resolver Hooks Package Version 1.0. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. * *

* Example import for consumers using the API in this package: *

* {@code Import-Package: org.osgi.framework.hooks.resolver; version="[1.0,2.0)"} * * @version $Id: 3621469ed02ccc323f6d8e1715f74537ec58e6df $ */ package org.osgi.framework.hooks.resolver; ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/resolver/ResolverHookFactory.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/resolver/ResolverHookFactory.jav0000644000175000017500000001157412346513664033102 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.hooks.resolver; import java.util.Collection; import org.osgi.framework.Bundle; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.FrameworkWiring; /** * OSGi Framework Resolver Hook Factory Service. * *

* Bundles registering this service will be called by the framework during a * bundle resolver process to obtain a {@link ResolverHook resolver hook} * instance which will be used for the duration of a resolve process. * * @ThreadSafe * @see ResolverHook * @version $Id: e0a2f3ad081c31bbb682fa366c15a3080bf6da2b $ */ public interface ResolverHookFactory { /** * This method is called by the framework each time a resolve process begins * to obtain a {@link ResolverHook resolver hook} instance. This resolver * hook instance will be used for the duration of the resolve process. At * the end of the resolve process the method {@link ResolverHook#end()} must * be called by the framework and the framework must not hold any references * of the resolver hook instance. *

* The triggers represent the collection of bundles which triggered the * resolve process. This collection may be empty if the triggers cannot be * determined by the framework. In most cases the triggers can easily be * determined. Calling certain methods on {@link Bundle bundle} when a * bundle is in the {@link Bundle#INSTALLED INSTALLED} state will cause the * framework to begin a resolve process in order to resolve the bundle. The * following methods will start a resolve process in this case: *

    *
  • {@link Bundle#start() start}
  • *
  • {@link Bundle#loadClass(String) loadClass}
  • *
  • {@link Bundle#findEntries(String, String, boolean) findEntries}
  • *
  • {@link Bundle#getResource(String) getResource}
  • *
  • {@link Bundle#getResources(String) getResources}
  • *
* In such cases the collection will contain the single bundle which the * framework is trying to resolve. Other cases will cause multiple bundles * to be included in the trigger bundles collection. When * {@link FrameworkWiring#resolveBundles(Collection) resolveBundles} is * called the collection of triggers must include all the current bundle * revisions for bundles passed to resolveBundles which are in the * {@link Bundle#INSTALLED INSTALLED} state. *

* When * {@link FrameworkWiring#refreshBundles(Collection, org.osgi.framework.FrameworkListener...)} * is called the collection of triggers is determined with the following * steps: *

    *
  • If the collection of bundles passed is null then * {@link FrameworkWiring#getRemovalPendingBundles()} is called to get the * initial collection of bundles.
  • *
  • The equivalent of calling * {@link FrameworkWiring#getDependencyClosure(Collection)} is called with * the initial collection of bundles to get the dependency closure * collection of the bundles being refreshed.
  • *
  • Remove any non-active bundles from the dependency closure collection. *
  • *
  • For each bundle remaining in the dependency closure collection get * the current bundle revision and add it to the collection of triggers.
  • *
*

* As described above, a resolve process is typically initiated as a result * of calling API that causes the framework to attempt to resolve one or * more bundles. The framework is free to start a resolve process at any * time for reasons other than calls to framework API. For example, a * resolve process may be used by the framework for diagnostic purposes and * result in no bundles actually becoming resolved at the end of the * process. Resolver hook implementations must be prepared for resolve * processes that are initiated for other reasons besides calls to framework * API. * * @param triggers an unmodifiable collection of bundles which triggered the * resolve process. This collection may be empty if the collection of * trigger bundles cannot be determined. * @return a resolver hook instance to be used for the duration of the * resolve process. A {@code null} value may be returned which * indicates this resolver hook factory abstains from the resolve * process. */ ResolverHook begin(Collection triggers); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/weaving/0000755000175000017500000000000012475375714026222 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/weaving/packageinfo0000644000175000017500000000001412346513664030402 0ustar felixfelixversion 1.0 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/weaving/WeavingHook.java0000644000175000017500000000503612346513664031305 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.hooks.weaving; /** * OSGi Framework Weaving Hook Service. * *

* Bundles registering this service will be called during framework class * loading operations. Weaving hook services are called when a class is being * loaded by the framework and have an opportunity to transform the class file * bytes that represents the class being loaded. Weaving hooks may also ask the * framework to wire in additional dynamic imports to the bundle. * *

* When a class is being loaded, the framework will create a {@link WovenClass} * object for the class and pass it to each registered weaving hook service for * possible modification. The first weaving hook called will see the original * class file bytes. Subsequently called weaving hooks will see the class file * bytes as modified by previously called weaving hooks. * * @ThreadSafe * @version $Id: d1985029024baba2db1c56aab1e06ee953fd6365 $ */ public interface WeavingHook { /** * Weaving hook method. * * This method can modify the specified woven class object to weave the * class being defined. * *

* If this method throws any exception, the framework must log the exception * and fail the class load in progress. This weaving hook service must be * blacklisted by the framework and must not be called again. The * blacklisting of this weaving hook service must expire when this weaving * hook service is unregistered. However, this method can throw a * {@link WeavingException} to deliberately fail the class load in progress * without being blacklisted by the framework. * * @param wovenClass The {@link WovenClass} object that represents the data * that will be used to define the class. * @throws WeavingException If this weaving hook wants to deliberately fail * the class load in progress without being blacklisted by the * framework */ public void weave(WovenClass wovenClass); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/weaving/package-info.java0000644000175000017500000000212712346513664031406 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Framework Weaving Hooks Package Version 1.0. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. *

* *

* Example import for consumers using the API in this package: *

*

* {@code Import-Package: org.osgi.framework.hooks.weaving; version="[1.0,2.0)"} *

* @version $Id: 8b788094aec5fd8ca4d2dfe6a8e4afc04a461290 $ */ package org.osgi.framework.hooks.weaving; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/weaving/WovenClass.java0000644000175000017500000001401712346513664031147 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.hooks.weaving; import java.security.ProtectionDomain; import java.util.List; import org.osgi.framework.wiring.BundleWiring; /** * A class being woven. * * This object represents a class being woven and is passed to each * {@link WeavingHook} for possible modification. It allows access to the most * recently transformed class file bytes and to any additional packages that * should be added to the bundle as dynamic imports. * *

* After weaving is {@link #isWeavingComplete() complete}, this object becomes * effectively immutable. * * @NotThreadSafe * @noimplement * @version $Id: 549caef41027c8f0d0fdb4deae756eae6b69d1ee $ */ public interface WovenClass { /** * Returns the class file bytes to be used to define the * {@link WovenClass#getClassName() named} class. * *

* While weaving is not {@link #isWeavingComplete() complete}, this method * returns a reference to the class files byte array contained in this * object. After weaving is {@link #isWeavingComplete() complete}, this * object becomes effectively immutable and a copy of the class file byte * array is returned. * * @return The bytes to be used to define the * {@link WovenClass#getClassName() named} class. * @throws SecurityException If the caller does not have * {@code AdminPermission[bundle,WEAVE]} and the Java runtime * environment supports permissions. */ public byte[] getBytes(); /** * Set the class file bytes to be used to define the * {@link WovenClass#getClassName() named} class. This method must not be * called outside invocations of the {@link WeavingHook#weave(WovenClass) * weave} method by the framework. * *

* While weaving is not {@link #isWeavingComplete() complete}, this method * replaces the reference to the array contained in this object with the * specified array. After weaving is {@link #isWeavingComplete() complete}, * this object becomes effectively immutable and this method will throw an * {@link IllegalStateException}. * * @param newBytes The new classfile that will be used to define the * {@link WovenClass#getClassName() named} class. The specified array * is retained by this object and the caller must not modify the * specified array. * @throws NullPointerException If newBytes is {@code null}. * @throws IllegalStateException If weaving is {@link #isWeavingComplete() * complete}. * @throws SecurityException If the caller does not have * {@code AdminPermission[bundle,WEAVE]} and the Java runtime * environment supports permissions. */ public void setBytes(byte[] newBytes); /** * Returns the list of dynamic import package descriptions to add to the * {@link #getBundleWiring() bundle wiring} for this woven class. Changes * made to the returned list will be visible to later {@link WeavingHook * weaving hooks} called with this object. The returned list must not be * modified outside invocations of the {@link WeavingHook#weave(WovenClass) * weave} method by the framework. * *

* After weaving is {@link #isWeavingComplete() complete}, this object * becomes effectively immutable and the returned list will be unmodifiable. * *

* If the Java runtime environment supports permissions, the caller must * have {@code AdminPermission[bundle,WEAVE]} to modify the returned list. * * @return A list containing zero or more dynamic import package * descriptions to add to the bundle wiring for this woven class. * This list must throw {@code IllegalArgumentException} if a * malformed dynamic import package description is added. * @see "Core Specification, Dynamic Import Package, for the syntax of a dynamic import package description." */ public List getDynamicImports(); /** * Returns whether weaving is complete in this woven class. Weaving is * complete after the last {@link WeavingHook weaving hook} is called and * the class is defined. * *

* After weaving is complete, this object becomes effectively immutable. * * @return {@code true} weaving is complete, {@code false} otherwise. */ public boolean isWeavingComplete(); /** * Returns the fully qualified name of the class being woven. * * @return The fully qualified name of the class being woven. */ public String getClassName(); /** * Returns the protection domain to which the woven class will be assigned * when it is defined. * * @return The protection domain to which the woven class will be assigned * when it is defined, or {@code null} if no protection domain will * be assigned. */ public ProtectionDomain getProtectionDomain(); /** * Returns the class defined by this woven class. During weaving, this * method will return {@code null}. Once weaving is * {@link #isWeavingComplete() complete}, this method will return the class * object if this woven class was used to define the class. * * @return The class associated with this woven class, or {@code null} if * weaving is not complete, the class definition failed or this * woven class was not used to define the class. */ public Class getDefinedClass(); /** * Returns the bundle wiring whose class loader will define the woven class. * * @return The bundle wiring whose class loader will define the woven class. */ public BundleWiring getBundleWiring(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/weaving/WeavingException.java0000644000175000017500000000276612346513664032352 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.hooks.weaving; /** * A weaving exception used to indicate that the class load should be failed but * the weaving hook must not be blacklisted by the framework. * *

* This exception conforms to the general purpose exception chaining mechanism. * * @version $Id: eb38b85f6ed66ec445fb2f0ee7143df021327a9a $ */ public class WeavingException extends RuntimeException { private static final long serialVersionUID = 1L; /** * Creates a {@code WeavingException} with the specified message and * exception cause. * * @param msg The associated message. * @param cause The cause of this exception. */ public WeavingException(String msg, Throwable cause) { super(msg, cause); } /** * Creates a {@code WeavingException} with the specified message. * * @param msg The message. */ public WeavingException(String msg) { super(msg); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/service/0000755000175000017500000000000012475375714026222 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/service/packageinfo0000644000175000017500000000001412346513664030402 0ustar felixfelixversion 1.1 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/service/EventHook.java0000644000175000017500000000411512346513664030763 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2008, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.hooks.service; import java.util.Collection; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceEvent; /** * OSGi Framework Service Event Hook Service. * *

* Bundles registering this service will be called during framework service * (register, modify, and unregister service) operations. * * @ThreadSafe * @deprecated As of 1.1. Replaced by {@link EventListenerHook}. * @version $Id: 84757a5f719db4d7671e81a76af2b320404ae0f5 $ */ public interface EventHook { /** * Event hook method. This method is called prior to service event delivery * when a publishing bundle registers, modifies or unregisters a service. * This method can filter the bundles which receive the event. * * @param event The service event to be delivered. * @param contexts A collection of Bundle Contexts for bundles which have * listeners to which the specified event will be delivered. The * implementation of this method may remove bundle contexts from the * collection to prevent the event from being delivered to the * associated bundles. The collection supports all the optional * {@code Collection} operations except {@code add} and * {@code addAll}. Attempting to add to the collection will result in * an {@code UnsupportedOperationException}. The collection is not * synchronized. */ void event(ServiceEvent event, Collection contexts); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/service/EventListenerHook.java0000644000175000017500000000474312346513664032500 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.hooks.service; import java.util.Collection; import java.util.Map; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceEvent; import org.osgi.framework.hooks.service.ListenerHook.ListenerInfo; /** * OSGi Framework Service Event Listener Hook Service. * *

* Bundles registering this service will be called during framework service * (register, modify, and unregister service) operations. * * @ThreadSafe * @since 1.1 * @version $Id: b0b99b29206f272ad479fa08ffcd5ef5fda909b8 $ */ public interface EventListenerHook { /** * Event listener hook method. This method is called prior to service event * delivery when a publishing bundle registers, modifies or unregisters a * service. This method can filter the listeners which receive the event. * * @param event The service event to be delivered. * @param listeners A map of Bundle Contexts to a collection of Listener * Infos for the bundle's listeners to which the specified event will * be delivered. The implementation of this method may remove bundle * contexts from the map and listener infos from the collection * values to prevent the event from being delivered to the associated * listeners. The map supports all the optional {@code Map} * operations except {@code put} and {@code putAll}. Attempting to * add to the map will result in an * {@code UnsupportedOperationException}. The collection values in * the map supports all the optional {@code Collection} operations * except {@code add} and {@code addAll}. Attempting to add to a * collection will result in an {@code UnsupportedOperationException} * . The map and the collections are not synchronized. */ void event(ServiceEvent event, Map> listeners); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/service/ListenerHook.java0000644000175000017500000001153012346513664031466 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2008, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.hooks.service; import java.util.Collection; import org.osgi.framework.BundleContext; /** * OSGi Framework Service Listener Hook Service. * *

* Bundles registering this service will be called during service listener * addition and removal. * * @ThreadSafe * @version $Id: 94029e2b70119793b3e7d77d6e1d5052d9ee1723 $ */ public interface ListenerHook { /** * Added listeners hook method. This method is called to provide the hook * implementation with information on newly added service listeners. This * method will be called as service listeners are added while this hook is * registered. Also, immediately after registration of this hook, this * method will be called to provide the current collection of service * listeners which had been added prior to the hook being registered. * * @param listeners A collection of {@link ListenerInfo}s for newly added * service listeners which are now listening to service events. * Attempting to add to or remove from the collection will result in * an {@code UnsupportedOperationException}. The collection is not * synchronized. */ void added(Collection listeners); /** * Removed listeners hook method. This method is called to provide the hook * implementation with information on newly removed service listeners. This * method will be called as service listeners are removed while this hook is * registered. * * @param listeners A collection of {@link ListenerInfo}s for newly removed * service listeners which are no longer listening to service events. * Attempting to add to or remove from the collection will result in * an {@code UnsupportedOperationException}. The collection is not * synchronized. */ void removed(Collection listeners); /** * Information about a Service Listener. This interface describes the bundle * which added the Service Listener and the filter with which it was added. * * @ThreadSafe * @noimplement */ public interface ListenerInfo { /** * Return the context of the bundle which added the listener. * * @return The context of the bundle which added the listener. */ BundleContext getBundleContext(); /** * Return the filter string with which the listener was added. * * @return The filter string with which the listener was added. This may * be {@code null} if the listener was added without a filter. */ String getFilter(); /** * Return the state of the listener for this addition and removal life * cycle. Initially this method will return {@code false} indicating the * listener has been added but has not been removed. After the listener * has been removed, this method must always return {@code true}. * *

* There is an extremely rare case in which removed notification to * {@link ListenerHook}s can be made before added notification if two * threads are racing to add and remove the same service listener. * Because {@link ListenerHook}s are called synchronously during service * listener addition and removal, the Framework cannot guarantee * in-order delivery of added and removed notification for a given * service listener. This method can be used to detect this rare * occurrence. * * @return {@code false} if the listener has not been been removed, * {@code true} otherwise. */ boolean isRemoved(); /** * Compares this {@code ListenerInfo} to another {@code ListenerInfo}. * Two {@code ListenerInfo}s are equals if they refer to the same * listener for a given addition and removal life cycle. If the same * listener is added again, it must have a different * {@code ListenerInfo} which is not equal to this {@code ListenerInfo}. * * @param obj The object to compare against this {@code ListenerInfo}. * @return {@code true} if the other object is a {@code ListenerInfo} * object and both objects refer to the same listener for a * given addition and removal life cycle. */ boolean equals(Object obj); /** * Returns the hash code for this {@code ListenerInfo}. * * @return The hash code of this {@code ListenerInfo}. */ int hashCode(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/service/package-info.java0000644000175000017500000000210312346513664031400 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Framework Service Hooks Package Version 1.1. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. * *

* Example import for consumers using the API in this package: *

* {@code Import-Package: org.osgi.framework.hooks.service; version="[1.1,2.0)"} * * @version $Id: 80468eff0eb0820494b56e05605e5cb1b6087c24 $ */ package org.osgi.framework.hooks.service; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/service/FindHook.java0000644000175000017500000000475212346513664030571 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2008, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.hooks.service; import java.util.Collection; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; /** * OSGi Framework Service Find Hook Service. * *

* Bundles registering this service will be called during framework service find * (get service references) operations. * * @ThreadSafe * @version $Id: 45612d6a10a25ca0b40ba695eb8dba21c2c78c24 $ */ public interface FindHook { /** * Find hook method. This method is called during the service find operation * (for example, {@link BundleContext#getServiceReferences(String, String)} * ). This method can filter the result of the find operation. * * @param context The bundle context of the bundle performing the find * operation. * @param name The class name of the services to find or {@code null} to * find all services. * @param filter The filter criteria of the services to find or {@code null} * for no filter criteria. * @param allServices {@code true} if the find operation is the result of a * call to * {@link BundleContext#getAllServiceReferences(String, String)} * @param references A collection of Service References to be returned as a * result of the find operation. The implementation of this method * may remove service references from the collection to prevent the * references from being returned to the bundle performing the find * operation. The collection supports all the optional * {@code Collection} operations except {@code add} and * {@code addAll}. Attempting to add to the collection will result in * an {@code UnsupportedOperationException}. The collection is not * synchronized. */ void find(BundleContext context, String name, String filter, boolean allServices, Collection> references); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/bundle/0000755000175000017500000000000012475375714026033 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/bundle/packageinfo0000644000175000017500000000001412346513664030213 0ustar felixfelixversion 1.1 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/bundle/EventHook.java0000644000175000017500000000477312346513664030606 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.hooks.bundle; import java.util.Collection; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; /** * OSGi Framework Bundle Event Hook Service. * *

* Bundles registering this service will be called during framework lifecycle * (install, start, stop, update, and uninstall bundle) operations. * * @ThreadSafe * @version $Id: e1471b36491a02bd8598a30d05c889ee58edc760 $ */ public interface EventHook { /** * Bundle event hook method. This method is called prior to bundle event * delivery when a bundle is installed, resolved, started, stopped, * unresolved, or uninstalled. This method can filter the bundles which * receive the event. *

* This method must be called by the framework one and only one time for * each bundle event generated, this included bundle events which are * generated when there are no bundle listeners registered. This method must * be called on the same thread that is performing the action which * generated the specified event. The specified collection includes bundle * contexts with synchronous and asynchronous bundle listeners registered * with them. * * @param event The bundle event to be delivered * @param contexts A collection of Bundle Contexts for bundles which have * listeners to which the specified event will be delivered. The * implementation of this method may remove bundle contexts from the * collection to prevent the event from being delivered to the * associated bundles. The collection supports all the optional * {@code Collection} operations except {@code add} and * {@code addAll}. Attempting to add to the collection will result in * an {@code UnsupportedOperationException}. The collection is not * synchronized. */ void event(BundleEvent event, Collection contexts); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/bundle/package-info.java0000644000175000017500000000210012346513664031206 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Framework Bundle Hooks Package Version 1.1. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. * *

* Example import for consumers using the API in this package: *

* {@code Import-Package: org.osgi.framework.hooks.bundle; version="[1.1,2.0)"} * * @version $Id: 0f53749f486ffe21404f4601fcc67c956f25ca6f $ */ package org.osgi.framework.hooks.bundle; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/bundle/CollisionHook.java0000644000175000017500000000704412346513664031452 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.hooks.bundle; import java.util.Collection; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; /** * OSGi Framework Bundle Collision Hook Service. * *

* If the framework was launched with the {@link Constants#FRAMEWORK_BSNVERSION * org.osgi.framework.bsnversion} framework launching property set to * {@link Constants#FRAMEWORK_BSNVERSION_MANAGED managed}, then all registered * collision hook services will be called during framework bundle install and * update operations to determine if an install or update operation will result * in a bundle symbolic name and version collision. * * @ThreadSafe * @version $Id: a1a25ee0432f210a56e911246f477f19edc28bc1 $ */ public interface CollisionHook { /** * Specifies a bundle install operation is being performed. */ int INSTALLING = 1; /** * Specifies a bundle update operation is being performed. */ int UPDATING = 2; /** * Filter bundle collisions hook method. This method is called during the * install or update operation. The operation type will be * {@link #INSTALLING installing} or {@link #UPDATING updating}. Depending * on the operation type the target bundle and the collision candidate * collection are the following: *

    *
  • {@link #INSTALLING installing} - The target is the bundle associated * with the {@link BundleContext} used to call one of the * {@link BundleContext#installBundle(String) install} methods. The * collision candidate collection contains the existing bundles installed * which have the same symbolic name and version as the bundle being * installed. *
  • {@link #UPDATING updating} - The target is the bundle used to call * one of the {@link Bundle#update() update} methods. The collision * candidate collection contains the existing bundles installed which have * the same symbolic name and version as the content the target bundle is * being updated to. *
* This method can filter the collection of collision candidates by removing * potential collisions. For the specified operation to succeed, the * collection of collision candidates must be empty after all registered * collision hook services have been called. * * @param operationType The operation type. Must be the value of * {@link #INSTALLING installing} or {@link #UPDATING updating}. * @param target The target bundle used to determine what collision * candidates to filter. * @param collisionCandidates The collection of collision candidates. The * collection supports all the optional {@code Collection} operations * except {@code add} and {@code addAll}. Attempting to add to the * collection will result in an {@code UnsupportedOperationException} * . The collection is not synchronized. */ void filterCollisions(int operationType, Bundle target, Collection collisionCandidates); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/hooks/bundle/FindHook.java0000644000175000017500000000515012346513664030373 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.hooks.bundle; import java.util.Collection; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; /** * OSGi Framework Bundle Context Hook Service. * *

* Bundles registering this service will be called during framework bundle find * (get bundles) operations. * * @ThreadSafe * @version $Id: ae6bf5fc5cf999ac39dfc195c99ef7e223e3b847 $ */ public interface FindHook { /** * Find hook method. This method is called for the following: *

    *
  • Bundle find operations using {@link BundleContext#getBundle(long)} * and {@link BundleContext#getBundles()} methods. The find method can * filter the result of the find operation. Note that a find operation using * the {@link BundleContext#getBundle(String)} method does not cause the * find method to be called.
  • *
  • Bundle install operations when an existing bundle is already * installed at a given location. In this case, the find method is called to * determine if the context performing the install operation is able to find * the bundle. If the context cannot find the existing bundle then the * install operation must fail with a * {@link BundleException#REJECTED_BY_HOOK} exception.
  • *
* * @param context The bundle context of the bundle performing the find * operation. * @param bundles A collection of Bundles to be returned as a result of the * find operation. The implementation of this method may remove * bundles from the collection to prevent the bundles from being * returned to the bundle performing the find operation. The * collection supports all the optional {@code Collection} operations * except {@code add} and {@code addAll}. Attempting to add to the * collection will result in an {@code UnsupportedOperationException} * . The collection is not synchronized. */ void find(BundleContext context, Collection bundles); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/ServiceListener.java0000644000175000017500000000473712346513664027416 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.util.EventListener; /** * A {@code ServiceEvent} listener. {@code ServiceListener} is a listener * interface that may be implemented by a bundle developer. When a * {@code ServiceEvent} is fired, it is synchronously delivered to a * {@code ServiceListener}. The Framework may deliver {@code ServiceEvent} * objects to a {@code ServiceListener} out of order and may concurrently call * and/or reenter a {@code ServiceListener}. * *

* A {@code ServiceListener} object is registered with the Framework using the * {@code BundleContext.addServiceListener} method. {@code ServiceListener} * objects are called with a {@code ServiceEvent} object when a service is * registered, modified, or is in the process of unregistering. * *

* {@code ServiceEvent} object delivery to {@code ServiceListener} objects is * filtered by the filter specified when the listener was registered. If the * Java Runtime Environment supports permissions, then additional filtering is * done. {@code ServiceEvent} objects are only delivered to the listener if the * bundle which defines the listener object's class has the appropriate * {@code ServicePermission} to get the service using at least one of the named * classes under which the service was registered. * *

* {@code ServiceEvent} object delivery to {@code ServiceListener} objects is * further filtered according to package sources as defined in * {@link ServiceReference#isAssignableTo(Bundle, String)}. * * @see ServiceEvent * @see ServicePermission * @ThreadSafe * @version $Id: 601dfda6183ab7f18cd3916958a39734ea141c25 $ */ public interface ServiceListener extends EventListener { /** * Receives notification that a service has had a lifecycle change. * * @param event The {@code ServiceEvent} object. */ public void serviceChanged(ServiceEvent event); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/AdminPermission.java0000644000175000017500000007625412346513664027414 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.security.AccessController; import java.security.BasicPermission; import java.security.Permission; import java.security.PermissionCollection; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; /** * A bundle's authority to perform specific privileged administrative operations * on or to get sensitive information about a bundle. The actions for this * permission are: * *

 * Action             Methods
 * class              Bundle.loadClass
 * execute            Bundle.start
 *                    Bundle.stop
 *                    BundleStartLevel.setStartLevel
 * extensionLifecycle BundleContext.installBundle for extension bundles
 *                    Bundle.update for extension bundles
 *                    Bundle.uninstall for extension bundles
 * lifecycle          BundleContext.installBundle
 *                    Bundle.update
 *                    Bundle.uninstall
 * listener           BundleContext.addBundleListener for SynchronousBundleListener
 *                    BundleContext.removeBundleListener for SynchronousBundleListener
 * metadata           Bundle.getHeaders
 *                    Bundle.getLocation
 * resolve            FrameworkWiring.refreshBundles
 *                    FrameworkWiring.resolveBundles
 * resource           Bundle.getResource
 *                    Bundle.getResources
 *                    Bundle.getEntry
 *                    Bundle.getEntryPaths
 *                    Bundle.findEntries
 *                    Bundle resource/entry URL creation
 * startlevel         FrameworkStartLevel.setStartLevel
 *                    FrameworkStartLevel.setInitialBundleStartLevel
 * context            Bundle.getBundleContext
 * weave              WovenClass.setBytes
 *                    WovenClass.getDynamicImports for modification
 * 
* *

* The special action "*" will represent all actions. The * {@code resolve} action is implied by the {@code class}, {@code execute} and * {@code resource} actions. *

* The name of this permission is a filter expression. The filter gives access * to the following attributes: *

    *
  • signer - A Distinguished Name chain used to sign a bundle. Wildcards in a * DN are not matched according to the filter string rules, but according to the * rules defined for a DN chain.
  • *
  • location - The location of a bundle.
  • *
  • id - The bundle ID of the designated bundle.
  • *
  • name - The symbolic name of a bundle.
  • *
* Filter attribute names are processed in a case sensitive manner. * * @ThreadSafe * @version $Id: cd883e81fde210ce8f0cabaebea377378d672818 $ */ public final class AdminPermission extends BasicPermission { static final long serialVersionUID = 307051004521261705L; /** * The action string {@code class}. The {@code class} action implies the * {@code resolve} action. * * @since 1.3 */ public final static String CLASS = "class"; /** * The action string {@code execute}. The {@code execute} action implies the * {@code resolve} action. * * @since 1.3 */ public final static String EXECUTE = "execute"; /** * The action string {@code extensionLifecycle}. * * @since 1.3 */ public final static String EXTENSIONLIFECYCLE = "extensionLifecycle"; /** * The action string {@code lifecycle}. * * @since 1.3 */ public final static String LIFECYCLE = "lifecycle"; /** * The action string {@code listener}. * * @since 1.3 */ public final static String LISTENER = "listener"; /** * The action string {@code metadata}. * * @since 1.3 */ public final static String METADATA = "metadata"; /** * The action string {@code resolve}. The {@code resolve} action is implied * by the {@code class}, {@code execute} and {@code resource} actions. * * @since 1.3 */ public final static String RESOLVE = "resolve"; /** * The action string {@code resource}. The {@code resource} action implies * the {@code resolve} action. * * @since 1.3 */ public final static String RESOURCE = "resource"; /** * The action string {@code startlevel}. * * @since 1.3 */ public final static String STARTLEVEL = "startlevel"; /** * The action string {@code context}. * * @since 1.4 */ public final static String CONTEXT = "context"; /** * The action string {@code weave}. * * @since 1.6 */ public final static String WEAVE = "weave"; private final static int ACTION_CLASS = 0x00000001; private final static int ACTION_EXECUTE = 0x00000002; private final static int ACTION_LIFECYCLE = 0x00000004; private final static int ACTION_LISTENER = 0x00000008; private final static int ACTION_METADATA = 0x00000010; private final static int ACTION_RESOLVE = 0x00000040; private final static int ACTION_RESOURCE = 0x00000080; private final static int ACTION_STARTLEVEL = 0x00000100; private final static int ACTION_EXTENSIONLIFECYCLE = 0x00000200; private final static int ACTION_CONTEXT = 0x00000400; private final static int ACTION_WEAVE = 0x00000800; private final static int ACTION_ALL = ACTION_CLASS | ACTION_EXECUTE | ACTION_LIFECYCLE | ACTION_LISTENER | ACTION_METADATA | ACTION_RESOLVE | ACTION_RESOURCE | ACTION_STARTLEVEL | ACTION_EXTENSIONLIFECYCLE | ACTION_CONTEXT | ACTION_WEAVE; final static int ACTION_NONE = 0; /** * The actions in canonical form. * * @serial */ private volatile String actions = null; /** * The actions mask. */ transient int action_mask; /** * If this AdminPermission was constructed with a filter, this holds a * Filter matching object used to evaluate the filter in implies. */ transient Filter filter; /** * The bundle governed by this AdminPermission - only used if filter == null */ transient final Bundle bundle; /** * This map holds the properties of the permission, used to match a filter * in implies. This is not initialized until necessary, and then cached in * this object. */ private transient volatile Map properties; /** * ThreadLocal used to determine if we have recursively called * getProperties. */ private static final ThreadLocal recurse = new ThreadLocal(); /** * Creates a new {@code AdminPermission} object that matches all bundles and * has all actions. Equivalent to AdminPermission("*","*"); */ public AdminPermission() { this(null, ACTION_ALL); } /** * Create a new AdminPermission. * * This constructor must only be used to create a permission that is going * to be checked. *

* Examples: * *

	 * (signer=\*,o=ACME,c=US)   
	 * (&(signer=\*,o=ACME,c=US)(name=com.acme.*)(location=http://www.acme.com/bundles/*))
	 * (id>=1)
	 * 
* *

* When a signer key is used within the filter expression the signer value * must escape the special filter chars ('*', '(', ')'). *

* Null arguments are equivalent to "*". * * @param filter A filter expression that can use signer, location, id, and * name keys. A value of "*" or {@code null} matches all * bundle. Filter attribute names are processed in a case sensitive * manner. * @param actions {@code class}, {@code execute}, {@code extensionLifecycle} * , {@code lifecycle}, {@code listener}, {@code metadata}, * {@code resolve} , {@code resource}, {@code startlevel}, * {@code context} or {@code weave}. A value of "*" or {@code null} * indicates all actions. * @throws IllegalArgumentException If the filter has an invalid syntax. */ public AdminPermission(String filter, String actions) { // arguments will be null if called from a PermissionInfo defined with // no args this(parseFilter(filter), parseActions(actions)); } /** * Creates a new requested {@code AdminPermission} object to be used by the * code that must perform {@code checkPermission}. {@code AdminPermission} * objects created with this constructor cannot be added to an * {@code AdminPermission} permission collection. * * @param bundle A bundle. * @param actions {@code class}, {@code execute}, {@code extensionLifecycle} * , {@code lifecycle}, {@code listener}, {@code metadata}, * {@code resolve} , {@code resource}, {@code startlevel}, * {@code context}, {@code weave}. A value of "*" or {@code null} * indicates all actions. * @since 1.3 */ public AdminPermission(Bundle bundle, String actions) { super(createName(bundle)); setTransients(null, parseActions(actions)); this.bundle = bundle; } /** * Create a permission name from a Bundle * * @param bundle Bundle to use to create permission name. * @return permission name. */ private static String createName(Bundle bundle) { if (bundle == null) { throw new IllegalArgumentException("bundle must not be null"); } StringBuffer sb = new StringBuffer("(id="); sb.append(bundle.getBundleId()); sb.append(")"); return sb.toString(); } /** * Package private constructor used by AdminPermissionCollection. * * @param filter name filter or {@code null} for wildcard. * @param mask action mask */ AdminPermission(Filter filter, int mask) { super((filter == null) ? "*" : filter.toString()); setTransients(filter, mask); this.bundle = null; } /** * Called by constructors and when deserialized. * * @param filter Permission's filter or {@code null} for wildcard. * @param mask action mask */ private void setTransients(Filter filter, int mask) { this.filter = filter; if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { throw new IllegalArgumentException("invalid action string"); } this.action_mask = mask; } /** * Parse action string into action mask. * * @param actions Action string. * @return action mask. */ private static int parseActions(String actions) { if ((actions == null) || actions.equals("*")) { return ACTION_ALL; } boolean seencomma = false; int mask = ACTION_NONE; char[] a = actions.toCharArray(); int i = a.length - 1; if (i < 0) return mask; while (i != -1) { char c; // skip whitespace while ((i != -1) && ((c = a[i]) == ' ' || c == '\r' || c == '\n' || c == '\f' || c == '\t')) i--; // check for the known strings int matchlen; if (i >= 4 && (a[i - 4] == 'c' || a[i - 4] == 'C') && (a[i - 3] == 'l' || a[i - 3] == 'L') && (a[i - 2] == 'a' || a[i - 2] == 'A') && (a[i - 1] == 's' || a[i - 1] == 'S') && (a[i] == 's' || a[i] == 'S')) { matchlen = 5; mask |= ACTION_CLASS | ACTION_RESOLVE; } else if (i >= 6 && (a[i - 6] == 'e' || a[i - 6] == 'E') && (a[i - 5] == 'x' || a[i - 5] == 'X') && (a[i - 4] == 'e' || a[i - 4] == 'E') && (a[i - 3] == 'c' || a[i - 3] == 'C') && (a[i - 2] == 'u' || a[i - 2] == 'U') && (a[i - 1] == 't' || a[i - 1] == 'T') && (a[i] == 'e' || a[i] == 'E')) { matchlen = 7; mask |= ACTION_EXECUTE | ACTION_RESOLVE; } else if (i >= 17 && (a[i - 17] == 'e' || a[i - 17] == 'E') && (a[i - 16] == 'x' || a[i - 16] == 'X') && (a[i - 15] == 't' || a[i - 15] == 'T') && (a[i - 14] == 'e' || a[i - 14] == 'E') && (a[i - 13] == 'n' || a[i - 13] == 'N') && (a[i - 12] == 's' || a[i - 12] == 'S') && (a[i - 11] == 'i' || a[i - 11] == 'I') && (a[i - 10] == 'o' || a[i - 10] == 'O') && (a[i - 9] == 'n' || a[i - 9] == 'N') && (a[i - 8] == 'l' || a[i - 8] == 'L') && (a[i - 7] == 'i' || a[i - 7] == 'I') && (a[i - 6] == 'f' || a[i - 6] == 'F') && (a[i - 5] == 'e' || a[i - 5] == 'E') && (a[i - 4] == 'c' || a[i - 4] == 'C') && (a[i - 3] == 'y' || a[i - 3] == 'Y') && (a[i - 2] == 'c' || a[i - 2] == 'C') && (a[i - 1] == 'l' || a[i - 1] == 'L') && (a[i] == 'e' || a[i] == 'E')) { matchlen = 18; mask |= ACTION_EXTENSIONLIFECYCLE; } else if (i >= 8 && (a[i - 8] == 'l' || a[i - 8] == 'L') && (a[i - 7] == 'i' || a[i - 7] == 'I') && (a[i - 6] == 'f' || a[i - 6] == 'F') && (a[i - 5] == 'e' || a[i - 5] == 'E') && (a[i - 4] == 'c' || a[i - 4] == 'C') && (a[i - 3] == 'y' || a[i - 3] == 'Y') && (a[i - 2] == 'c' || a[i - 2] == 'C') && (a[i - 1] == 'l' || a[i - 1] == 'L') && (a[i] == 'e' || a[i] == 'E')) { matchlen = 9; mask |= ACTION_LIFECYCLE; } else if (i >= 7 && (a[i - 7] == 'l' || a[i - 7] == 'L') && (a[i - 6] == 'i' || a[i - 6] == 'I') && (a[i - 5] == 's' || a[i - 5] == 'S') && (a[i - 4] == 't' || a[i - 4] == 'T') && (a[i - 3] == 'e' || a[i - 3] == 'E') && (a[i - 2] == 'n' || a[i - 2] == 'N') && (a[i - 1] == 'e' || a[i - 1] == 'E') && (a[i] == 'r' || a[i] == 'R')) { matchlen = 8; mask |= ACTION_LISTENER; } else if (i >= 7 && (a[i - 7] == 'm' || a[i - 7] == 'M') && (a[i - 6] == 'e' || a[i - 6] == 'E') && (a[i - 5] == 't' || a[i - 5] == 'T') && (a[i - 4] == 'a' || a[i - 4] == 'A') && (a[i - 3] == 'd' || a[i - 3] == 'D') && (a[i - 2] == 'a' || a[i - 2] == 'A') && (a[i - 1] == 't' || a[i - 1] == 'T') && (a[i] == 'a' || a[i] == 'A')) { matchlen = 8; mask |= ACTION_METADATA; } else if (i >= 6 && (a[i - 6] == 'r' || a[i - 6] == 'R') && (a[i - 5] == 'e' || a[i - 5] == 'E') && (a[i - 4] == 's' || a[i - 4] == 'S') && (a[i - 3] == 'o' || a[i - 3] == 'O') && (a[i - 2] == 'l' || a[i - 2] == 'L') && (a[i - 1] == 'v' || a[i - 1] == 'V') && (a[i] == 'e' || a[i] == 'E')) { matchlen = 7; mask |= ACTION_RESOLVE; } else if (i >= 7 && (a[i - 7] == 'r' || a[i - 7] == 'R') && (a[i - 6] == 'e' || a[i - 6] == 'E') && (a[i - 5] == 's' || a[i - 5] == 'S') && (a[i - 4] == 'o' || a[i - 4] == 'O') && (a[i - 3] == 'u' || a[i - 3] == 'U') && (a[i - 2] == 'r' || a[i - 2] == 'R') && (a[i - 1] == 'c' || a[i - 1] == 'C') && (a[i] == 'e' || a[i] == 'E')) { matchlen = 8; mask |= ACTION_RESOURCE | ACTION_RESOLVE; } else if (i >= 9 && (a[i - 9] == 's' || a[i - 9] == 'S') && (a[i - 8] == 't' || a[i - 8] == 'T') && (a[i - 7] == 'a' || a[i - 7] == 'A') && (a[i - 6] == 'r' || a[i - 6] == 'R') && (a[i - 5] == 't' || a[i - 5] == 'T') && (a[i - 4] == 'l' || a[i - 4] == 'L') && (a[i - 3] == 'e' || a[i - 3] == 'E') && (a[i - 2] == 'v' || a[i - 2] == 'V') && (a[i - 1] == 'e' || a[i - 1] == 'E') && (a[i] == 'l' || a[i] == 'L')) { matchlen = 10; mask |= ACTION_STARTLEVEL; } else if (i >= 6 && (a[i - 6] == 'c' || a[i - 6] == 'C') && (a[i - 5] == 'o' || a[i - 5] == 'O') && (a[i - 4] == 'n' || a[i - 4] == 'N') && (a[i - 3] == 't' || a[i - 3] == 'T') && (a[i - 2] == 'e' || a[i - 2] == 'E') && (a[i - 1] == 'x' || a[i - 1] == 'X') && (a[i] == 't' || a[i] == 'T')) { matchlen = 7; mask |= ACTION_CONTEXT; } else if (i >= 4 && (a[i - 4] == 'w' || a[i - 4] == 'W') && (a[i - 3] == 'e' || a[i - 3] == 'E') && (a[i - 2] == 'a' || a[i - 2] == 'A') && (a[i - 1] == 'v' || a[i - 1] == 'V') && (a[i] == 'e' || a[i] == 'E')) { matchlen = 5; mask |= ACTION_WEAVE; } else if (i >= 0 && (a[i] == '*')) { matchlen = 1; mask |= ACTION_ALL; } else { // parse error throw new IllegalArgumentException("invalid permission: " + actions); } // make sure we didn't just match the tail of a word // like "ackbarfstartlevel". Also, skip to the comma. seencomma = false; while (i >= matchlen && !seencomma) { switch (a[i - matchlen]) { case ',' : seencomma = true; /* FALLTHROUGH */ case ' ' : case '\r' : case '\n' : case '\f' : case '\t' : break; default : throw new IllegalArgumentException("invalid permission: " + actions); } i--; } // point i at the location of the comma minus one (or -1). i -= matchlen; } if (seencomma) { throw new IllegalArgumentException("invalid permission: " + actions); } return mask; } /** * Parse filter string into a Filter object. * * @param filterString The filter string to parse. * @return a Filter for this bundle. If the specified filterString is * {@code null} or equals "*", then {@code null} is returned to * indicate a wildcard. * @throws IllegalArgumentException If the filter syntax is invalid. */ private static Filter parseFilter(String filterString) { if (filterString == null) { return null; } filterString = filterString.trim(); if (filterString.equals("*")) { return null; } try { return FrameworkUtil.createFilter(filterString); } catch (InvalidSyntaxException e) { IllegalArgumentException iae = new IllegalArgumentException("invalid filter"); iae.initCause(e); throw iae; } } /** * Determines if the specified permission is implied by this object. This * method throws an exception if the specified permission was not * constructed with a bundle. * *

* This method returns {@code true} if the specified permission is an * AdminPermission AND *

    *
  • this object's filter matches the specified permission's bundle ID, * bundle symbolic name, bundle location and bundle signer distinguished * name chain OR
  • *
  • this object's filter is "*"
  • *
* AND this object's actions include all of the specified permission's * actions. *

* Special case: if the specified permission was constructed with "*" * filter, then this method returns {@code true} if this object's filter is * "*" and this object's actions include all of the specified permission's * actions * * @param p The requested permission. * @return {@code true} if the specified permission is implied by this * object; {@code false} otherwise. */ public boolean implies(Permission p) { if (!(p instanceof AdminPermission)) { return false; } AdminPermission requested = (AdminPermission) p; if (bundle != null) { return false; } // if requested permission has a filter, then it is an invalid argument if (requested.filter != null) { return false; } return implies0(requested, ACTION_NONE); } /** * Internal implies method. Used by the implies and the permission * collection implies methods. * * @param requested The requested AdminPermision which has already be * validated as a proper argument. The requested AdminPermission must * not have a filter expression. * @param effective The effective actions with which to start. * @return {@code true} if the specified permission is implied by this * object; {@code false} otherwise. */ boolean implies0(AdminPermission requested, int effective) { /* check actions first - much faster */ effective |= action_mask; final int desired = requested.action_mask; if ((effective & desired) != desired) { return false; } /* Get our filter */ Filter f = filter; if (f == null) { // it's "*" return true; } /* is requested a wildcard filter? */ if (requested.bundle == null) { return false; } Map requestedProperties = requested.getProperties(); if (requestedProperties == null) { /* * If the requested properties are null, then we have detected a * recursion getting the bundle location. So we return true to * permit the bundle location request in the AdminPermission check * up the stack to succeed. */ return true; } return f.matches(requestedProperties); } /** * Returns the canonical string representation of the * {@code AdminPermission} actions. * *

* Always returns present {@code AdminPermission} actions in the following * order: {@code class}, {@code execute}, {@code extensionLifecycle}, * {@code lifecycle}, {@code listener}, {@code metadata}, {@code resolve}, * {@code resource}, {@code startlevel}, {@code context}, {@code weave}. * * @return Canonical string representation of the {@code AdminPermission} * actions. */ public String getActions() { String result = actions; if (result == null) { StringBuffer sb = new StringBuffer(); int mask = action_mask; if ((mask & ACTION_CLASS) == ACTION_CLASS) { sb.append(CLASS); sb.append(','); } if ((mask & ACTION_EXECUTE) == ACTION_EXECUTE) { sb.append(EXECUTE); sb.append(','); } if ((mask & ACTION_EXTENSIONLIFECYCLE) == ACTION_EXTENSIONLIFECYCLE) { sb.append(EXTENSIONLIFECYCLE); sb.append(','); } if ((mask & ACTION_LIFECYCLE) == ACTION_LIFECYCLE) { sb.append(LIFECYCLE); sb.append(','); } if ((mask & ACTION_LISTENER) == ACTION_LISTENER) { sb.append(LISTENER); sb.append(','); } if ((mask & ACTION_METADATA) == ACTION_METADATA) { sb.append(METADATA); sb.append(','); } if ((mask & ACTION_RESOLVE) == ACTION_RESOLVE) { sb.append(RESOLVE); sb.append(','); } if ((mask & ACTION_RESOURCE) == ACTION_RESOURCE) { sb.append(RESOURCE); sb.append(','); } if ((mask & ACTION_STARTLEVEL) == ACTION_STARTLEVEL) { sb.append(STARTLEVEL); sb.append(','); } if ((mask & ACTION_CONTEXT) == ACTION_CONTEXT) { sb.append(CONTEXT); sb.append(','); } if ((mask & ACTION_WEAVE) == ACTION_WEAVE) { sb.append(WEAVE); sb.append(','); } // remove trailing comma if (sb.length() > 0) { sb.setLength(sb.length() - 1); } actions = result = sb.toString(); } return result; } /** * Returns a new {@code PermissionCollection} object suitable for storing * {@code AdminPermission}s. * * @return A new {@code PermissionCollection} object. */ public PermissionCollection newPermissionCollection() { return new AdminPermissionCollection(); } /** * Determines the equality of two {@code AdminPermission} objects. * * @param obj The object being compared for equality with this object. * @return {@code true} if {@code obj} is equivalent to this * {@code AdminPermission}; {@code false} otherwise. */ public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof AdminPermission)) { return false; } AdminPermission ap = (AdminPermission) obj; return (action_mask == ap.action_mask) && ((bundle == ap.bundle) || ((bundle != null) && bundle.equals(ap.bundle))) && (filter == null ? ap.filter == null : filter.equals(ap.filter)); } /** * Returns the hash code value for this object. * * @return Hash code value for this object. */ public int hashCode() { int h = 31 * 17 + getName().hashCode(); h = 31 * h + getActions().hashCode(); if (bundle != null) { h = 31 * h + bundle.hashCode(); } return h; } /** * WriteObject is called to save the state of this permission object to a * stream. The actions are serialized, and the superclass takes care of the * name. */ private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { if (bundle != null) { throw new NotSerializableException("cannot serialize"); } // Write out the actions. The superclass takes care of the name // call getActions to make sure actions field is initialized if (actions == null) getActions(); s.defaultWriteObject(); } /** * readObject is called to restore the state of this permission from a * stream. */ private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the data, then initialize the transients s.defaultReadObject(); setTransients(parseFilter(getName()), parseActions(actions)); } /** * Called by {@code implies0} on an AdminPermission which was constructed * with a Bundle. This method loads a map with the filter-matchable * properties of this bundle. The map is cached so this lookup only happens * once. * * This method should only be called on an AdminPermission which was * constructed with a bundle * * @return a map of properties for this bundle */ private Map getProperties() { Map result = properties; if (result != null) { return result; } /* * We may have recursed here due to the Bundle.getLocation call in the * doPrivileged below. If this is the case, return null to allow implies * to return true. */ final Object mark = recurse.get(); if (mark == bundle) { return null; } recurse.set(bundle); try { final Map map = new HashMap(4); AccessController.doPrivileged(new PrivilegedAction() { public Object run() { map.put("id", new Long(bundle.getBundleId())); map.put("location", bundle.getLocation()); String name = bundle.getSymbolicName(); if (name != null) { map.put("name", name); } SignerProperty signer = new SignerProperty(bundle); if (signer.isBundleSigned()) { map.put("signer", signer); } return null; } }); return properties = map; } finally { recurse.set(null); } } } /** * Stores a collection of {@code AdminPermission}s. */ final class AdminPermissionCollection extends PermissionCollection { private static final long serialVersionUID = 3906372644575328048L; /** * Collection of permissions. * * @GuardedBy this */ private transient Map permissions; /** * Boolean saying if "*" is in the collection. * * @serial * @GuardedBy this */ private boolean all_allowed; /** * Create an empty AdminPermissions object. * */ public AdminPermissionCollection() { permissions = new HashMap(); } /** * Adds a permission to this permission collection. * * @param permission The {@code AdminPermission} object to add. * @throws IllegalArgumentException If the specified permission is not an * {@code AdminPermission} instance or was constructed with a Bundle * object. * @throws SecurityException If this {@code AdminPermissionCollection} * object has been marked read-only. */ public void add(Permission permission) { if (!(permission instanceof AdminPermission)) { throw new IllegalArgumentException("invalid permission: " + permission); } if (isReadOnly()) { throw new SecurityException("attempt to add a Permission to a " + "readonly PermissionCollection"); } final AdminPermission ap = (AdminPermission) permission; if (ap.bundle != null) { throw new IllegalArgumentException("cannot add to collection: " + ap); } final String name = ap.getName(); synchronized (this) { Map pc = permissions; AdminPermission existing = pc.get(name); if (existing != null) { int oldMask = existing.action_mask; int newMask = ap.action_mask; if (oldMask != newMask) { pc.put(name, new AdminPermission(existing.filter, oldMask | newMask)); } } else { pc.put(name, ap); } if (!all_allowed) { if (name.equals("*")) { all_allowed = true; } } } } /** * Determines if the specified permissions implies the permissions expressed * in {@code permission}. * * @param permission The Permission object to compare with the * {@code AdminPermission} objects in this collection. * @return {@code true} if {@code permission} is implied by an * {@code AdminPermission} in this collection, {@code false} * otherwise. */ public boolean implies(Permission permission) { if (!(permission instanceof AdminPermission)) { return false; } AdminPermission requested = (AdminPermission) permission; // if requested permission has a filter, then it is an invalid argument if (requested.filter != null) { return false; } int effective = AdminPermission.ACTION_NONE; Collection perms; synchronized (this) { Map pc = permissions; // short circuit if the "*" Permission was added if (all_allowed) { AdminPermission ap = pc.get("*"); if (ap != null) { effective |= ap.action_mask; final int desired = requested.action_mask; if ((effective & desired) == desired) { return true; } } } perms = pc.values(); } // just iterate one by one for (AdminPermission perm : perms) { if (perm.implies0(requested, effective)) { return true; } } return false; } /** * Returns an enumeration of all {@code AdminPermission} objects in the * container. * * @return Enumeration of all {@code AdminPermission} objects. */ public synchronized Enumeration elements() { List all = new ArrayList(permissions.values()); return Collections.enumeration(all); } /* serialization logic */ private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("permissions", Hashtable.class), new ObjectStreamField("all_allowed", Boolean.TYPE)}; private synchronized void writeObject(ObjectOutputStream out) throws IOException { Hashtable hashtable = new Hashtable(permissions); ObjectOutputStream.PutField pfields = out.putFields(); pfields.put("permissions", hashtable); pfields.put("all_allowed", all_allowed); out.writeFields(); } private synchronized void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gfields = in.readFields(); Hashtable hashtable = (Hashtable) gfields.get("permissions", null); permissions = new HashMap(hashtable); all_allowed = gfields.get("all_allowed", false); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/PackagePermission.java0000644000175000017500000005601312346513664027706 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.security.AccessController; import java.security.BasicPermission; import java.security.Permission; import java.security.PermissionCollection; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; /** * A bundle's authority to import or export a package. * *

* A package is a dot-separated string that defines a fully qualified Java * package. *

* For example: * *

 * org.osgi.service.http
 * 
* *

* {@code PackagePermission} has three actions: {@code exportonly}, * {@code import} and {@code export}. The {@code export} action, which is * deprecated, implies the {@code import} action. * * @ThreadSafe * @version $Id: e993fbc36b6bff84182a8594af5af3cad8c4e2a3 $ */ public final class PackagePermission extends BasicPermission { static final long serialVersionUID = -5107705877071099135L; /** * The action string {@code export}. The {@code export} action implies the * {@code import} action. * * @deprecated Since 1.5. Use {@code exportonly} instead. */ public final static String EXPORT = "export"; /** * The action string {@code exportonly}. The {@code exportonly} action does * not imply the {@code import} action. * * @since 1.5 */ public final static String EXPORTONLY = "exportonly"; /** * The action string {@code import}. */ public final static String IMPORT = "import"; private final static int ACTION_EXPORT = 0x00000001; private final static int ACTION_IMPORT = 0x00000002; private final static int ACTION_ALL = ACTION_EXPORT | ACTION_IMPORT; final static int ACTION_NONE = 0; /** * The actions mask. */ transient int action_mask; /** * The actions in canonical form. * * @serial */ private volatile String actions = null; /** * The bundle used by this PackagePermission. */ transient final Bundle bundle; /** * If this PackagePermission was constructed with a filter, this holds a * Filter matching object used to evaluate the filter in implies. */ transient Filter filter; /** * This map holds the properties of the permission, used to match a filter * in implies. This is not initialized until necessary, and then cached in * this object. */ private transient volatile Map properties; /** * Creates a new {@code PackagePermission} object. * *

* The name is specified as a normal Java package name: a dot-separated * string. Wildcards may be used. * *

	 * name ::= <package name> | <package name ending in ".*"> | *
	 * 
* * Examples: * *
	 * org.osgi.service.http
	 * javax.servlet.*
	 * *
	 * 
* * For the {@code import} action, the name can also be a filter expression. * The filter gives access to the following attributes: *
    *
  • signer - A Distinguished Name chain used to sign the exporting * bundle. Wildcards in a DN are not matched according to the filter string * rules, but according to the rules defined for a DN chain.
  • *
  • location - The location of the exporting bundle.
  • *
  • id - The bundle ID of the exporting bundle.
  • *
  • name - The symbolic name of the exporting bundle.
  • *
  • package.name - The name of the requested package.
  • *
* Filter attribute names are processed in a case sensitive manner. * *

* Package Permissions are granted over all possible versions of a package. * * A bundle that needs to export a package must have the appropriate * {@code PackagePermission} for that package; similarly, a bundle that * needs to import a package must have the appropriate * {@code PackagePermssion} for that package. *

* Permission is granted for both classes and resources. * * @param name Package name or filter expression. A filter expression can * only be specified if the specified action is {@code import}. * @param actions {@code exportonly},{@code import} (canonical order). * @throws IllegalArgumentException If the specified name is a filter * expression and either the specified action is not {@code import} * or the filter has an invalid syntax. */ public PackagePermission(String name, String actions) { this(name, parseActions(actions)); if ((filter != null) && ((action_mask & ACTION_ALL) != ACTION_IMPORT)) { throw new IllegalArgumentException("invalid action string for filter expression"); } } /** * Creates a new requested {@code PackagePermission} object to be used by * code that must perform {@code checkPermission} for the {@code import} * action. {@code PackagePermission} objects created with this constructor * cannot be added to a {@code PackagePermission} permission collection. * * @param name The name of the requested package to import. * @param exportingBundle The bundle exporting the requested package. * @param actions The action {@code import}. * @throws IllegalArgumentException If the specified action is not * {@code import} or the name is a filter expression. * @since 1.5 */ public PackagePermission(String name, Bundle exportingBundle, String actions) { super(name); setTransients(name, parseActions(actions)); this.bundle = exportingBundle; if (exportingBundle == null) { throw new IllegalArgumentException("bundle must not be null"); } if (filter != null) { throw new IllegalArgumentException("invalid name"); } if ((action_mask & ACTION_ALL) != ACTION_IMPORT) { throw new IllegalArgumentException("invalid action string"); } } /** * Package private constructor used by PackagePermissionCollection. * * @param name package name * @param mask action mask */ PackagePermission(String name, int mask) { super(name); setTransients(name, mask); this.bundle = null; } /** * Called by constructors and when deserialized. * * @param mask action mask */ private void setTransients(String name, int mask) { if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { throw new IllegalArgumentException("invalid action string"); } action_mask = mask; filter = parseFilter(name); } /** * Parse action string into action mask. * * @param actions Action string. * @return action mask. */ private static int parseActions(String actions) { boolean seencomma = false; int mask = ACTION_NONE; if (actions == null) { return mask; } char[] a = actions.toCharArray(); int i = a.length - 1; if (i < 0) return mask; while (i != -1) { char c; // skip whitespace while ((i != -1) && ((c = a[i]) == ' ' || c == '\r' || c == '\n' || c == '\f' || c == '\t')) i--; // check for the known strings int matchlen; if (i >= 5 && (a[i - 5] == 'i' || a[i - 5] == 'I') && (a[i - 4] == 'm' || a[i - 4] == 'M') && (a[i - 3] == 'p' || a[i - 3] == 'P') && (a[i - 2] == 'o' || a[i - 2] == 'O') && (a[i - 1] == 'r' || a[i - 1] == 'R') && (a[i] == 't' || a[i] == 'T')) { matchlen = 6; mask |= ACTION_IMPORT; } else if (i >= 5 && (a[i - 5] == 'e' || a[i - 5] == 'E') && (a[i - 4] == 'x' || a[i - 4] == 'X') && (a[i - 3] == 'p' || a[i - 3] == 'P') && (a[i - 2] == 'o' || a[i - 2] == 'O') && (a[i - 1] == 'r' || a[i - 1] == 'R') && (a[i] == 't' || a[i] == 'T')) { matchlen = 6; mask |= ACTION_EXPORT | ACTION_IMPORT; } else { if (i >= 9 && (a[i - 9] == 'e' || a[i - 9] == 'E') && (a[i - 8] == 'x' || a[i - 8] == 'X') && (a[i - 7] == 'p' || a[i - 7] == 'P') && (a[i - 6] == 'o' || a[i - 6] == 'O') && (a[i - 5] == 'r' || a[i - 5] == 'R') && (a[i - 4] == 't' || a[i - 4] == 'T') && (a[i - 3] == 'o' || a[i - 3] == 'O') && (a[i - 2] == 'n' || a[i - 2] == 'N') && (a[i - 1] == 'l' || a[i - 1] == 'L') && (a[i] == 'y' || a[i] == 'Y')) { matchlen = 10; mask |= ACTION_EXPORT; } else { // parse error throw new IllegalArgumentException("invalid permission: " + actions); } } // make sure we didn't just match the tail of a word // like "ackbarfimport". Also, skip to the comma. seencomma = false; while (i >= matchlen && !seencomma) { switch (a[i - matchlen]) { case ',' : seencomma = true; /* FALLTHROUGH */ case ' ' : case '\r' : case '\n' : case '\f' : case '\t' : break; default : throw new IllegalArgumentException("invalid permission: " + actions); } i--; } // point i at the location of the comma minus one (or -1). i -= matchlen; } if (seencomma) { throw new IllegalArgumentException("invalid permission: " + actions); } return mask; } /** * Parse filter string into a Filter object. * * @param filterString The filter string to parse. * @return a Filter for this bundle. If the specified filterString is not a * filter expression, then {@code null} is returned. * @throws IllegalArgumentException If the filter syntax is invalid. */ private static Filter parseFilter(String filterString) { filterString = filterString.trim(); if (filterString.charAt(0) != '(') { return null; } try { return FrameworkUtil.createFilter(filterString); } catch (InvalidSyntaxException e) { IllegalArgumentException iae = new IllegalArgumentException("invalid filter"); iae.initCause(e); throw iae; } } /** * Determines if the specified permission is implied by this object. * *

* This method checks that the package name of the target is implied by the * package name of this object. The list of {@code PackagePermission} * actions must either match or allow for the list of the target object to * imply the target {@code PackagePermission} action. *

* The permission to export a package implies the permission to import the * named package. * *

	 * x.y.*,"export" -> x.y.z,"export" is true
	 * *,"import" -> x.y, "import"      is true
	 * *,"export" -> x.y, "import"      is true
	 * x.y,"export" -> x.y.z, "export"  is false
	 * 
* * @param p The requested permission. * @return {@code true} if the specified permission is implied by this * object; {@code false} otherwise. */ public boolean implies(Permission p) { if (!(p instanceof PackagePermission)) { return false; } PackagePermission requested = (PackagePermission) p; if (bundle != null) { return false; } // if requested permission has a filter, then it is an invalid argument if (requested.filter != null) { return false; } return implies0(requested, ACTION_NONE); } /** * Internal implies method. Used by the implies and the permission * collection implies methods. * * @param requested The requested PackagePermission which has already be * validated as a proper argument. The requested PackagePermission * must not have a filter expression. * @param effective The effective actions with which to start. * @return {@code true} if the specified permission is implied by this * object; {@code false} otherwise. */ boolean implies0(PackagePermission requested, int effective) { /* check actions first - much faster */ effective |= action_mask; final int desired = requested.action_mask; if ((effective & desired) != desired) { return false; } /* Get filter if any */ Filter f = filter; if (f == null) { return super.implies(requested); } return f.matches(requested.getProperties()); } /** * Returns the canonical string representation of the * {@code PackagePermission} actions. * *

* Always returns present {@code PackagePermission} actions in the following * order: {@code EXPORTONLY},{@code IMPORT}. * * @return Canonical string representation of the {@code PackagePermission} * actions. */ public String getActions() { String result = actions; if (result == null) { StringBuffer sb = new StringBuffer(); boolean comma = false; int mask = action_mask; if ((mask & ACTION_EXPORT) == ACTION_EXPORT) { sb.append(EXPORTONLY); comma = true; } if ((mask & ACTION_IMPORT) == ACTION_IMPORT) { if (comma) sb.append(','); sb.append(IMPORT); } actions = result = sb.toString(); } return result; } /** * Returns a new {@code PermissionCollection} object suitable for storing * {@code PackagePermission} objects. * * @return A new {@code PermissionCollection} object. */ public PermissionCollection newPermissionCollection() { return new PackagePermissionCollection(); } /** * Determines the equality of two {@code PackagePermission} objects. * * This method checks that specified package has the same package name and * {@code PackagePermission} actions as this {@code PackagePermission} * object. * * @param obj The object to test for equality with this * {@code PackagePermission} object. * @return {@code true} if {@code obj} is a {@code PackagePermission}, and * has the same package name and actions as this * {@code PackagePermission} object; {@code false} otherwise. */ public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof PackagePermission)) { return false; } PackagePermission pp = (PackagePermission) obj; return (action_mask == pp.action_mask) && getName().equals(pp.getName()) && ((bundle == pp.bundle) || ((bundle != null) && bundle.equals(pp.bundle))); } /** * Returns the hash code value for this object. * * @return A hash code value for this object. */ public int hashCode() { int h = 31 * 17 + getName().hashCode(); h = 31 * h + getActions().hashCode(); if (bundle != null) { h = 31 * h + bundle.hashCode(); } return h; } /** * WriteObject is called to save the state of this permission object to a * stream. The actions are serialized, and the superclass takes care of the * name. */ private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { if (bundle != null) { throw new NotSerializableException("cannot serialize"); } // Write out the actions. The superclass takes care of the name // call getActions to make sure actions field is initialized if (actions == null) getActions(); s.defaultWriteObject(); } /** * readObject is called to restore the state of this permission from a * stream. */ private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the action, then initialize the rest s.defaultReadObject(); setTransients(getName(), parseActions(actions)); } /** * Called by {@code <@link PackagePermission#implies(Permission)>}. This * method is only called on a requested permission which cannot have a * filter set. * * @return a map of properties for this permission. */ private Map getProperties() { Map result = properties; if (result != null) { return result; } final Map map = new HashMap(5); map.put("package.name", getName()); if (bundle != null) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { map.put("id", new Long(bundle.getBundleId())); map.put("location", bundle.getLocation()); String name = bundle.getSymbolicName(); if (name != null) { map.put("name", name); } SignerProperty signer = new SignerProperty(bundle); if (signer.isBundleSigned()) { map.put("signer", signer); } return null; } }); } return properties = map; } } /** * Stores a set of {@code PackagePermission} permissions. * * @see java.security.Permission * @see java.security.Permissions * @see java.security.PermissionCollection */ final class PackagePermissionCollection extends PermissionCollection { static final long serialVersionUID = -3350758995234427603L; /** * Table of permissions with names. * * @GuardedBy this */ private transient Map permissions; /** * Boolean saying if "*" is in the collection. * * @serial * @GuardedBy this */ private boolean all_allowed; /** * Table of permissions with filter expressions. * * @serial * @GuardedBy this */ private Map filterPermissions; /** * Create an empty PackagePermissions object. */ public PackagePermissionCollection() { permissions = new HashMap(); all_allowed = false; } /** * Adds a permission to this permission collection. * * @param permission The {@code PackagePermission} object to add. * @throws IllegalArgumentException If the specified permission is not a * {@code PackagePermission} instance or was constructed with a * Bundle object. * @throws SecurityException If this {@code PackagePermissionCollection} * object has been marked read-only. */ public void add(final Permission permission) { if (!(permission instanceof PackagePermission)) { throw new IllegalArgumentException("invalid permission: " + permission); } if (isReadOnly()) { throw new SecurityException("attempt to add a Permission to a " + "readonly PermissionCollection"); } final PackagePermission pp = (PackagePermission) permission; if (pp.bundle != null) { throw new IllegalArgumentException("cannot add to collection: " + pp); } final String name = pp.getName(); final Filter f = pp.filter; synchronized (this) { /* select the bucket for the permission */ Map pc; if (f != null) { pc = filterPermissions; if (pc == null) { filterPermissions = pc = new HashMap(); } } else { pc = permissions; } final PackagePermission existing = pc.get(name); if (existing != null) { final int oldMask = existing.action_mask; final int newMask = pp.action_mask; if (oldMask != newMask) { pc.put(name, new PackagePermission(name, oldMask | newMask)); } } else { pc.put(name, pp); } if (!all_allowed) { if (name.equals("*")) { all_allowed = true; } } } } /** * Determines if the specified permissions implies the permissions expressed * in {@code permission}. * * @param permission The Permission object to compare with this * {@code PackagePermission} object. * @return {@code true} if {@code permission} is a proper subset of a * permission in the set; {@code false} otherwise. */ public boolean implies(final Permission permission) { if (!(permission instanceof PackagePermission)) { return false; } final PackagePermission requested = (PackagePermission) permission; /* if requested permission has a filter, then it is an invalid argument */ if (requested.filter != null) { return false; } String requestedName = requested.getName(); final int desired = requested.action_mask; int effective = PackagePermission.ACTION_NONE; Collection perms; synchronized (this) { Map pc = permissions; PackagePermission pp; /* short circuit if the "*" Permission was added */ if (all_allowed) { pp = pc.get("*"); if (pp != null) { effective |= pp.action_mask; if ((effective & desired) == desired) { return true; } } } /* * strategy: Check for full match first. Then work our way up the * name looking for matches on a.b.* */ pp = pc.get(requestedName); if (pp != null) { /* we have a direct hit! */ effective |= pp.action_mask; if ((effective & desired) == desired) { return true; } } /* work our way up the tree... */ int last; int offset = requestedName.length() - 1; while ((last = requestedName.lastIndexOf(".", offset)) != -1) { requestedName = requestedName.substring(0, last + 1) + "*"; pp = pc.get(requestedName); if (pp != null) { effective |= pp.action_mask; if ((effective & desired) == desired) { return true; } } offset = last - 1; } /* * we don't have to check for "*" as it was already checked before * we were called. */ pc = filterPermissions; if (pc == null) { return false; } perms = pc.values(); } /* iterate one by one over filteredPermissions */ for (PackagePermission perm : perms) { if (perm.implies0(requested, effective)) { return true; } } return false; } /** * Returns an enumeration of all {@code PackagePermission} objects in the * container. * * @return Enumeration of all {@code PackagePermission} objects. */ public synchronized Enumeration elements() { List all = new ArrayList(permissions.values()); Map pc = filterPermissions; if (pc != null) { all.addAll(pc.values()); } return Collections.enumeration(all); } /* serialization logic */ private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("permissions", Hashtable.class), new ObjectStreamField("all_allowed", Boolean.TYPE), new ObjectStreamField("filterPermissions", HashMap.class) }; private synchronized void writeObject(ObjectOutputStream out) throws IOException { Hashtable hashtable = new Hashtable(permissions); ObjectOutputStream.PutField pfields = out.putFields(); pfields.put("permissions", hashtable); pfields.put("all_allowed", all_allowed); pfields.put("filterPermissions", filterPermissions); out.writeFields(); } private synchronized void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gfields = in.readFields(); Hashtable hashtable = (Hashtable) gfields.get("permissions", null); permissions = new HashMap(hashtable); all_allowed = gfields.get("all_allowed", false); HashMap fp = (HashMap) gfields.get("filterPermissions", null); filterPermissions = fp; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/FrameworkListener.java0000644000175000017500000000336712346513664027751 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2011). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.util.EventListener; /** * A {@code FrameworkEvent} listener. {@code FrameworkListener} is a listener * interface that may be implemented by a bundle developer. When a * {@code FrameworkEvent} is fired, it is asynchronously delivered to a * {@code FrameworkListener}. The Framework delivers {@code FrameworkEvent} * objects to a {@code FrameworkListener} in order and must not concurrently * call a {@code FrameworkListener}. * *

* A {@code FrameworkListener} object is registered with the Framework using the * {@link BundleContext#addFrameworkListener(FrameworkListener)} method. * {@code FrameworkListener} objects are called with a {@code FrameworkEvent} * objects when the Framework starts and when asynchronous errors occur. * * @see FrameworkEvent * @NotThreadSafe * @version $Id: ad7f563bd13b60e2b8a378f147057ca7f0accae2 $ */ public interface FrameworkListener extends EventListener { /** * Receives notification of a general {@code FrameworkEvent} object. * * @param event The {@code FrameworkEvent} object. */ public void frameworkEvent(FrameworkEvent event); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/Bundle.java0000644000175000017500000014462412346513664025521 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.cert.X509Certificate; import java.util.Dictionary; import java.util.Enumeration; import java.util.List; import java.util.Map; import org.osgi.framework.wiring.FrameworkWiring; /** * An installed bundle in the Framework. * *

* A {@code Bundle} object is the access point to define the lifecycle of an * installed bundle. Each bundle installed in the OSGi environment must have an * associated {@code Bundle} object. * *

* A bundle must have a unique identity, a {@code long}, chosen by the * Framework. This identity must not change during the lifecycle of a bundle, * even when the bundle is updated. Uninstalling and then reinstalling the * bundle must create a new unique identity. * *

* A bundle can be in one of six states: *

    *
  • {@link #UNINSTALLED} *
  • {@link #INSTALLED} *
  • {@link #RESOLVED} *
  • {@link #STARTING} *
  • {@link #STOPPING} *
  • {@link #ACTIVE} *
*

* Values assigned to these states have no specified ordering; they represent * bit values that may be ORed together to determine if a bundle is in one of * the valid states. * *

* A bundle should only have active threads of execution when its state is one * of {@code STARTING},{@code ACTIVE}, or {@code STOPPING}. An * {@code UNINSTALLED} bundle can not be set to another state; it is a zombie * and can only be reached because references are kept somewhere. * *

* The Framework is the only entity that is allowed to create {@code Bundle} * objects, and these objects are only valid within the Framework that created * them. * *

* Bundles have a natural ordering such that if two {@code Bundle}s have the * same {@link #getBundleId() bundle id} they are equal. A {@code Bundle} is * less than another {@code Bundle} if it has a lower {@link #getBundleId() * bundle id} and is greater if it has a higher bundle id. * * @ThreadSafe * @noimplement * @version $Id: 8a58ab72af389b1999b88348e4944203b7096510 $ */ public interface Bundle extends Comparable { /** * The bundle is uninstalled and may not be used. * *

* The {@code UNINSTALLED} state is only visible after a bundle is * uninstalled; the bundle is in an unusable state but references to the * {@code Bundle} object may still be available and used for introspection. *

* The value of {@code UNINSTALLED} is 0x00000001. */ int UNINSTALLED = 0x00000001; /** * The bundle is installed but not yet resolved. * *

* A bundle is in the {@code INSTALLED} state when it has been installed in * the Framework but is not or cannot be resolved. *

* This state is visible if the bundle's code dependencies are not resolved. * The Framework may attempt to resolve an {@code INSTALLED} bundle's code * dependencies and move the bundle to the {@code RESOLVED} state. *

* The value of {@code INSTALLED} is 0x00000002. */ int INSTALLED = 0x00000002; /** * The bundle is resolved and is able to be started. * *

* A bundle is in the {@code RESOLVED} state when the Framework has * successfully resolved the bundle's code dependencies. These dependencies * include: *

    *
  • The bundle's class path from its {@link Constants#BUNDLE_CLASSPATH} * Manifest header. *
  • The bundle's package dependencies from its * {@link Constants#EXPORT_PACKAGE} and {@link Constants#IMPORT_PACKAGE} * Manifest headers. *
  • The bundle's required bundle dependencies from its * {@link Constants#REQUIRE_BUNDLE} Manifest header. *
  • A fragment bundle's host dependency from its * {@link Constants#FRAGMENT_HOST} Manifest header. *
*

* Note that the bundle is not active yet. A bundle must be put in the * {@code RESOLVED} state before it can be started. The Framework may * attempt to resolve a bundle at any time. *

* The value of {@code RESOLVED} is 0x00000004. */ int RESOLVED = 0x00000004; /** * The bundle is in the process of starting. * *

* A bundle is in the {@code STARTING} state when its {@link #start(int) * start} method is active. A bundle must be in this state when the bundle's * {@link BundleActivator#start(BundleContext)} is called. If the * {@code BundleActivator.start} method completes without exception, then * the bundle has successfully started and must move to the {@code ACTIVE} * state. *

* If the bundle has a {@link Constants#ACTIVATION_LAZY lazy activation * policy}, then the bundle may remain in this state for some time until the * activation is triggered. *

* The value of {@code STARTING} is 0x00000008. */ int STARTING = 0x00000008; /** * The bundle is in the process of stopping. * *

* A bundle is in the {@code STOPPING} state when its {@link #stop(int) * stop} method is active. A bundle must be in this state when the bundle's * {@link BundleActivator#stop(BundleContext)} method is called. When the * {@code BundleActivator.stop} method completes the bundle is stopped and * must move to the {@code RESOLVED} state. *

* The value of {@code STOPPING} is 0x00000010. */ int STOPPING = 0x00000010; /** * The bundle is now running. * *

* A bundle is in the {@code ACTIVE} state when it has been successfully * started and activated. *

* The value of {@code ACTIVE} is 0x00000020. */ int ACTIVE = 0x00000020; /** * The bundle start operation is transient and the persistent autostart * setting of the bundle is not modified. * *

* This bit may be set when calling {@link #start(int)} to notify the * framework that the autostart setting of the bundle must not be modified. * If this bit is not set, then the autostart setting of the bundle is * modified. * * @since 1.4 * @see #start(int) */ int START_TRANSIENT = 0x00000001; /** * The bundle start operation must activate the bundle according to the * bundle's declared {@link Constants#BUNDLE_ACTIVATIONPOLICY activation * policy}. * *

* This bit may be set when calling {@link #start(int)} to notify the * framework that the bundle must be activated using the bundle's declared * activation policy. * * @since 1.4 * @see Constants#BUNDLE_ACTIVATIONPOLICY * @see #start(int) */ int START_ACTIVATION_POLICY = 0x00000002; /** * The bundle stop is transient and the persistent autostart setting of the * bundle is not modified. * *

* This bit may be set when calling {@link #stop(int)} to notify the * framework that the autostart setting of the bundle must not be modified. * If this bit is not set, then the autostart setting of the bundle is * modified. * * @since 1.4 * @see #stop(int) */ int STOP_TRANSIENT = 0x00000001; /** * Request that all certificates used to sign the bundle be returned. * * @since 1.5 * @see #getSignerCertificates(int) */ int SIGNERS_ALL = 1; /** * Request that only certificates used to sign the bundle that are trusted * by the framework be returned. * * @since 1.5 * @see #getSignerCertificates(int) */ int SIGNERS_TRUSTED = 2; /** * Returns this bundle's current state. * *

* A bundle can be in only one state at any time. * * @return An element of {@code UNINSTALLED},{@code INSTALLED}, * {@code RESOLVED}, {@code STARTING}, {@code STOPPING}, * {@code ACTIVE}. */ int getState(); /** * Starts this bundle. * *

* If this bundle's state is {@code UNINSTALLED} then an * {@code IllegalStateException} is thrown. *

* If the current start level is less than this bundle's start level: *

    *
  • If the {@link #START_TRANSIENT} option is set, then a * {@code BundleException} is thrown indicating this bundle cannot be * started due to the Framework's current start level. * *
  • Otherwise, the Framework must set this bundle's persistent autostart * setting to Started with declared activation if the * {@link #START_ACTIVATION_POLICY} option is set or * Started with eager activation if not set. *
*

* When the Framework's current start level becomes equal to or more than * this bundle's start level, this bundle will be started. *

* Otherwise, the following steps are required to start this bundle: *

    *
  1. If this bundle is in the process of being activated or deactivated * then this method must wait for activation or deactivation to complete * before continuing. If this does not occur in a reasonable time, a * {@code BundleException} is thrown to indicate this bundle was unable to * be started. * *
  2. If this bundle's state is {@code ACTIVE} then this method returns * immediately. * *
  3. If the {@link #START_TRANSIENT} option is not set then set this * bundle's autostart setting to Started with declared activation * if the {@link #START_ACTIVATION_POLICY} option is set or * Started with eager activation if not set. When the Framework is * restarted and this bundle's autostart setting is not Stopped, * this bundle must be automatically started. * *
  4. If this bundle's state is not {@code RESOLVED}, an attempt is made to * resolve this bundle. If the Framework cannot resolve this bundle, a * {@code BundleException} is thrown. * *
  5. If the {@link #START_ACTIVATION_POLICY} option is set and this * bundle's declared activation policy is {@link Constants#ACTIVATION_LAZY * lazy} then: *
      *
    • If this bundle's state is {@code STARTING} then this method returns * immediately. *
    • This bundle's state is set to {@code STARTING}. *
    • A bundle event of type {@link BundleEvent#LAZY_ACTIVATION} is fired. *
    • This method returns immediately and the remaining steps will be * followed when this bundle's activation is later triggered. *
    * *
  6. This bundle's state is set to {@code STARTING}. * *
  7. A bundle event of type {@link BundleEvent#STARTING} is fired. * *
  8. The {@link BundleActivator#start(BundleContext)} method of this * bundle's {@code BundleActivator}, if one is specified, is called. If the * {@code BundleActivator} is invalid or throws an exception then: *
      *
    • This bundle's state is set to {@code STOPPING}. *
    • A bundle event of type {@link BundleEvent#STOPPING} is fired. *
    • Any services registered by this bundle must be unregistered. *
    • Any services used by this bundle must be released. *
    • Any listeners registered by this bundle must be removed. *
    • This bundle's state is set to {@code RESOLVED}. *
    • A bundle event of type {@link BundleEvent#STOPPED} is fired. *
    • A {@code BundleException} is then thrown. *
    * *
  9. If this bundle's state is {@code UNINSTALLED}, because this bundle * was uninstalled while the {@code BundleActivator.start} method was * running, a {@code BundleException} is thrown. * *
  10. This bundle's state is set to {@code ACTIVE}. * *
  11. A bundle event of type {@link BundleEvent#STARTED} is fired. *
* * Preconditions *
    *
  • {@code getState()} in { {@code INSTALLED}, {@code RESOLVED} * } or { {@code INSTALLED}, {@code RESOLVED}, * {@code STARTING} } if this bundle has a lazy activation policy. *
* Postconditions, no exceptions thrown *
    *
  • Bundle autostart setting is modified unless the * {@link #START_TRANSIENT} option was set. *
  • {@code getState()} in { {@code ACTIVE} } unless the * lazy activation policy was used. *
  • {@code BundleActivator.start()} has been called and did not throw an * exception unless the lazy activation policy was used. *
* Postconditions, when an exception is thrown *
    *
  • Depending on when the exception occurred, bundle autostart setting is * modified unless the {@link #START_TRANSIENT} option was set. *
  • {@code getState()} not in { {@code STARTING}, {@code ACTIVE} * }. *
* * @param options The options for starting this bundle. See * {@link #START_TRANSIENT} and {@link #START_ACTIVATION_POLICY}. The * Framework must ignore unrecognized options. * @throws BundleException If this bundle could not be started. * BundleException types thrown by this method include: * {@link BundleException#START_TRANSIENT_ERROR}, * {@link BundleException#NATIVECODE_ERROR}, * {@link BundleException#RESOLVE_ERROR}, * {@link BundleException#STATECHANGE_ERROR}, and * {@link BundleException#ACTIVATOR_ERROR}. * @throws IllegalStateException If this bundle has been uninstalled or this * bundle tries to change its own state. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,EXECUTE]}, and the Java Runtime * Environment supports permissions. * @since 1.4 */ void start(int options) throws BundleException; /** * Starts this bundle with no options. * *

* This method performs the same function as calling {@code start(0)}. * * @throws BundleException If this bundle could not be started. * BundleException types thrown by this method include: * {@link BundleException#NATIVECODE_ERROR}, * {@link BundleException#RESOLVE_ERROR}, * {@link BundleException#STATECHANGE_ERROR}, and * {@link BundleException#ACTIVATOR_ERROR}. * @throws IllegalStateException If this bundle has been uninstalled or this * bundle tries to change its own state. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,EXECUTE]}, and the Java Runtime * Environment supports permissions. * @see #start(int) */ void start() throws BundleException; /** * Stops this bundle. * *

* The following steps are required to stop a bundle: *

    *
  1. If this bundle's state is {@code UNINSTALLED} then an * {@code IllegalStateException} is thrown. * *
  2. If this bundle is in the process of being activated or deactivated * then this method must wait for activation or deactivation to complete * before continuing. If this does not occur in a reasonable time, a * {@code BundleException} is thrown to indicate this bundle was unable to * be stopped. *
  3. If the {@link #STOP_TRANSIENT} option is not set then then set this * bundle's persistent autostart setting to to Stopped. When the * Framework is restarted and this bundle's autostart setting is * Stopped, this bundle must not be automatically started. * *
  4. If this bundle's state is not {@code STARTING} or {@code ACTIVE} then * this method returns immediately. * *
  5. This bundle's state is set to {@code STOPPING}. * *
  6. A bundle event of type {@link BundleEvent#STOPPING} is fired. * *
  7. If this bundle's state was {@code ACTIVE} prior to setting the state * to {@code STOPPING}, the {@link BundleActivator#stop(BundleContext)} * method of this bundle's {@code BundleActivator}, if one is specified, is * called. If that method throws an exception, this method must continue to * stop this bundle and a {@code BundleException} must be thrown after * completion of the remaining steps. * *
  8. Any services registered by this bundle must be unregistered. *
  9. Any services used by this bundle must be released. *
  10. Any listeners registered by this bundle must be removed. * *
  11. If this bundle's state is {@code UNINSTALLED}, because this bundle * was uninstalled while the {@code BundleActivator.stop} method was * running, a {@code BundleException} must be thrown. * *
  12. This bundle's state is set to {@code RESOLVED}. * *
  13. A bundle event of type {@link BundleEvent#STOPPED} is fired. *
* * Preconditions *
    *
  • {@code getState()} in { {@code ACTIVE} }. *
* Postconditions, no exceptions thrown *
    *
  • Bundle autostart setting is modified unless the * {@link #STOP_TRANSIENT} option was set. *
  • {@code getState()} not in { {@code ACTIVE}, {@code STOPPING} * }. *
  • {@code BundleActivator.stop} has been called and did not throw an * exception. *
* Postconditions, when an exception is thrown *
    *
  • Bundle autostart setting is modified unless the * {@link #STOP_TRANSIENT} option was set. *
* * @param options The options for stopping this bundle. See * {@link #STOP_TRANSIENT}. The Framework must ignore unrecognized * options. * @throws BundleException BundleException types thrown by this method * include: {@link BundleException#STATECHANGE_ERROR} and * {@link BundleException#ACTIVATOR_ERROR}. * @throws IllegalStateException If this bundle has been uninstalled or this * bundle tries to change its own state. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,EXECUTE]}, and the Java Runtime * Environment supports permissions. * @since 1.4 */ void stop(int options) throws BundleException; /** * Stops this bundle with no options. * *

* This method performs the same function as calling {@code stop(0)}. * * @throws BundleException BundleException types thrown by this method * include: {@link BundleException#STATECHANGE_ERROR} and * {@link BundleException#ACTIVATOR_ERROR}. * @throws IllegalStateException If this bundle has been uninstalled or this * bundle tries to change its own state. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,EXECUTE]}, and the Java Runtime * Environment supports permissions. * @see #start(int) */ void stop() throws BundleException; /** * Updates this bundle from an {@code InputStream}. * *

* If the specified {@code InputStream} is {@code null}, the Framework must * create the {@code InputStream} from which to read the updated bundle by * interpreting, in an implementation dependent manner, this bundle's * {@link Constants#BUNDLE_UPDATELOCATION Bundle-UpdateLocation} Manifest * header, if present, or this bundle's original location. * *

* If this bundle's state is {@code ACTIVE}, it must be stopped before the * update and started after the update successfully completes. * *

* If this bundle has exported any packages that are imported by another * bundle, these packages must remain exported until the * {@link FrameworkWiring#refreshBundles(java.util.Collection, FrameworkListener...) * FrameworkWiring.refreshBundles} method has been has been called or the * Framework is relaunched. * *

* The following steps are required to update a bundle: *

    *
  1. If this bundle's state is {@code UNINSTALLED} then an * {@code IllegalStateException} is thrown. * *
  2. If this bundle's state is {@code ACTIVE}, {@code STARTING} or * {@code STOPPING}, this bundle is stopped as described in the * {@code Bundle.stop} method. If {@code Bundle.stop} throws an exception, * the exception is rethrown terminating the update. * *
  3. The updated version of this bundle is read from the input stream and * installed. If the Framework is unable to install the updated version of * this bundle, the original version of this bundle must be restored and a * {@code BundleException} must be thrown after completion of the remaining * steps. * *
  4. This bundle's state is set to {@code INSTALLED}. * *
  5. If the updated version of this bundle was successfully installed, a * bundle event of type {@link BundleEvent#UPDATED} is fired. * *
  6. If this bundle's state was originally {@code ACTIVE}, the updated * bundle is started as described in the {@code Bundle.start} method. If * {@code Bundle.start} throws an exception, a Framework event of type * {@link FrameworkEvent#ERROR} is fired containing the exception. *
* * Preconditions *
    *
  • {@code getState()} not in { {@code UNINSTALLED} }. *
* Postconditions, no exceptions thrown *
    *
  • {@code getState()} in { {@code INSTALLED}, {@code RESOLVED}, * {@code ACTIVE} }. *
  • This bundle has been updated. *
* Postconditions, when an exception is thrown *
    *
  • {@code getState()} in { {@code INSTALLED}, {@code RESOLVED}, * {@code ACTIVE} }. *
  • Original bundle is still used; no update occurred. *
* * @param input The {@code InputStream} from which to read the new bundle or * {@code null} to indicate the Framework must create the input * stream from this bundle's {@link Constants#BUNDLE_UPDATELOCATION * Bundle-UpdateLocation} Manifest header, if present, or this * bundle's original location. The input stream must always be closed * when this method completes, even if an exception is thrown. * @throws BundleException If this bundle could not be updated. * BundleException types thrown by this method include: * {@link BundleException#READ_ERROR}, * {@link BundleException#DUPLICATE_BUNDLE_ERROR}, * {@link BundleException#MANIFEST_ERROR}, * {@link BundleException#NATIVECODE_ERROR}, * {@link BundleException#RESOLVE_ERROR}, * {@link BundleException#STATECHANGE_ERROR}, and * {@link BundleException#ACTIVATOR_ERROR}. * @throws IllegalStateException If this bundle has been uninstalled or this * bundle tries to change its own state. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,LIFECYCLE]} for both the current * bundle and the updated bundle, and the Java Runtime Environment * supports permissions. * @see #stop() * @see #start() */ void update(InputStream input) throws BundleException; /** * Updates this bundle. * *

* This method performs the same function as calling * {@link #update(InputStream)} with a {@code null} InputStream. * * @throws BundleException If this bundle could not be updated. * BundleException types thrown by this method include: * {@link BundleException#READ_ERROR}, * {@link BundleException#DUPLICATE_BUNDLE_ERROR}, * {@link BundleException#MANIFEST_ERROR}, * {@link BundleException#NATIVECODE_ERROR}, * {@link BundleException#RESOLVE_ERROR}, * {@link BundleException#STATECHANGE_ERROR}, and * {@link BundleException#ACTIVATOR_ERROR}. * @throws IllegalStateException If this bundle has been uninstalled or this * bundle tries to change its own state. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,LIFECYCLE]} for both the current * bundle and the updated bundle, and the Java Runtime Environment * supports permissions. * @see #update(InputStream) */ void update() throws BundleException; /** * Uninstalls this bundle. * *

* This method causes the Framework to notify other bundles that this bundle * is being uninstalled, and then puts this bundle into the * {@code UNINSTALLED} state. The Framework must remove any resources * related to this bundle that it is able to remove. * *

* If this bundle has exported any packages, the Framework must continue to * make these packages available to their importing bundles until the * {@link FrameworkWiring#refreshBundles(java.util.Collection, FrameworkListener...) * FrameworkWiring.refreshBundles} method has been called or the Framework * is relaunched. * *

* The following steps are required to uninstall a bundle: *

    *
  1. If this bundle's state is {@code UNINSTALLED} then an * {@code IllegalStateException} is thrown. * *
  2. If this bundle's state is {@code ACTIVE}, {@code STARTING} or * {@code STOPPING}, this bundle is stopped as described in the * {@code Bundle.stop} method. If {@code Bundle.stop} throws an exception, a * Framework event of type {@link FrameworkEvent#ERROR} is fired containing * the exception. * *
  3. This bundle's state is set to {@code UNINSTALLED}. * *
  4. A bundle event of type {@link BundleEvent#UNINSTALLED} is fired. * *
  5. This bundle and any persistent storage area provided for this bundle * by the Framework are removed. *
* * Preconditions *
    *
  • {@code getState()} not in { {@code UNINSTALLED} }. *
* Postconditions, no exceptions thrown *
    *
  • {@code getState()} in { {@code UNINSTALLED} }. *
  • This bundle has been uninstalled. *
* Postconditions, when an exception is thrown *
    *
  • {@code getState()} not in { {@code UNINSTALLED} }. *
  • This Bundle has not been uninstalled. *
* * @throws BundleException If the uninstall failed. This can occur if * another thread is attempting to change this bundle's state and * does not complete in a timely manner. BundleException types * thrown by this method include: * {@link BundleException#STATECHANGE_ERROR} * @throws IllegalStateException If this bundle has been uninstalled or this * bundle tries to change its own state. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,LIFECYCLE]}, and the Java Runtime * Environment supports permissions. * @see #stop() */ void uninstall() throws BundleException; /** * Returns this bundle's Manifest headers and values. This method returns * all the Manifest headers and values from the main section of this * bundle's Manifest file; that is, all lines prior to the first blank line. * *

* Manifest header names are case-insensitive. The methods of the returned * {@code Dictionary} object must operate on header names in a * case-insensitive manner. * * If a Manifest header value starts with "%", it must be * localized according to the default locale. If no localization is found * for a header value, the header value without the leading "%" is * returned. * *

* For example, the following Manifest headers and values are included if * they are present in the Manifest file: * *

	 *     Bundle-Name
	 *     Bundle-Vendor
	 *     Bundle-Version
	 *     Bundle-Description
	 *     Bundle-DocURL
	 *     Bundle-ContactAddress
	 * 
* *

* This method must continue to return Manifest header information while * this bundle is in the {@code UNINSTALLED} state. * * @return An unmodifiable {@code Dictionary} object containing this * bundle's Manifest headers and values. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,METADATA]}, and the Java Runtime * Environment supports permissions. * @see Constants#BUNDLE_LOCALIZATION */ Dictionary getHeaders(); /** * Returns this bundle's unique identifier. This bundle is assigned a unique * identifier by the Framework when it was installed in the OSGi * environment. * *

* A bundle's unique identifier has the following attributes: *

    *
  • Is unique and persistent. *
  • Is a {@code long}. *
  • Its value is not reused for another bundle, even after a bundle is * uninstalled. *
  • Does not change while a bundle remains installed. *
  • Does not change when a bundle is updated. *
* *

* This method must continue to return this bundle's unique identifier while * this bundle is in the {@code UNINSTALLED} state. * * @return The unique identifier of this bundle. */ long getBundleId(); /** * Returns this bundle's location identifier. * *

* The location identifier is the location passed to * {@code BundleContext.installBundle} when a bundle is installed. The * location identifier does not change while this bundle remains installed, * even if this bundle is updated. * *

* This method must continue to return this bundle's location identifier * while this bundle is in the {@code UNINSTALLED} state. * * @return The string representation of this bundle's location identifier. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,METADATA]}, and the Java Runtime * Environment supports permissions. */ String getLocation(); /** * Returns this bundle's {@code ServiceReference} list for all services it * has registered or {@code null} if this bundle has no registered services. * *

* If the Java runtime supports permissions, a {@code ServiceReference} * object to a service is included in the returned list only if the caller * has the {@code ServicePermission} to get the service using at least one * of the named classes the service was registered under. * *

* The list is valid at the time of the call to this method, however, as the * Framework is a very dynamic environment, services can be modified or * unregistered at anytime. * * @return An array of {@code ServiceReference} objects or {@code null}. * @throws IllegalStateException If this bundle has been uninstalled. * @see ServiceRegistration * @see ServiceReference * @see ServicePermission */ ServiceReference[] getRegisteredServices(); /** * Returns this bundle's {@code ServiceReference} list for all services it * is using or returns {@code null} if this bundle is not using any * services. A bundle is considered to be using a service if its use count * for that service is greater than zero. * *

* If the Java Runtime Environment supports permissions, a * {@code ServiceReference} object to a service is included in the returned * list only if the caller has the {@code ServicePermission} to get the * service using at least one of the named classes the service was * registered under. *

* The list is valid at the time of the call to this method, however, as the * Framework is a very dynamic environment, services can be modified or * unregistered at anytime. * * @return An array of {@code ServiceReference} objects or {@code null}. * @throws IllegalStateException If this bundle has been uninstalled. * @see ServiceReference * @see ServicePermission */ ServiceReference[] getServicesInUse(); /** * Determines if this bundle has the specified permissions. * *

* If the Java Runtime Environment does not support permissions, this method * always returns {@code true}. *

* {@code permission} is of type {@code Object} to avoid referencing the * {@code java.security.Permission} class directly. This is to allow the * Framework to be implemented in Java environments which do not support * permissions. * *

* If the Java Runtime Environment does support permissions, this bundle and * all its resources including embedded JAR files, belong to the same * {@code java.security.ProtectionDomain}; that is, they must share the same * set of permissions. * * @param permission The permission to verify. * @return {@code true} if this bundle has the specified permission or the * permissions possessed by this bundle imply the specified * permission; {@code false} if this bundle does not have the * specified permission or {@code permission} is not an * {@code instanceof} {@code java.security.Permission}. * @throws IllegalStateException If this bundle has been uninstalled. */ boolean hasPermission(Object permission); /** * Find the specified resource from this bundle's class loader. * * This bundle's class loader is called to search for the specified * resource. If this bundle's state is {@code INSTALLED}, this method must * attempt to resolve this bundle before attempting to get the specified * resource. If this bundle cannot be resolved, then only this bundle must * be searched for the specified resource. Imported packages cannot be * searched when this bundle has not been resolved. If this bundle is a * fragment bundle then {@code null} is returned. *

* Note: Jar and zip files are not required to include directory entries. * URLs to directory entries will not be returned if the bundle contents do * not contain directory entries. * * @param name The name of the resource. See {@code ClassLoader.getResource} * for a description of the format of a resource name. * @return A URL to the named resource, or {@code null} if the resource * could not be found or if this bundle is a fragment bundle or if * the caller does not have the appropriate * {@code AdminPermission[this,RESOURCE]}, and the Java Runtime * Environment supports permissions. * @throws IllegalStateException If this bundle has been uninstalled. * @see #getEntry(String) * @see #findEntries(String, String, boolean) * @since 1.1 */ URL getResource(String name); /** * Returns this bundle's Manifest headers and values localized to the * specified locale. * *

* This method performs the same function as {@code Bundle.getHeaders()} * except the manifest header values are localized to the specified locale. * *

* If a Manifest header value starts with "%", it must be * localized according to the specified locale. If a locale is specified and * cannot be found, then the header values must be returned using the * default locale. Localizations are searched for in the following order: * *

	 *   bn + "_" + Ls + "_" + Cs + "_" + Vs
	 *   bn + "_" + Ls + "_" + Cs
	 *   bn + "_" + Ls
	 *   bn + "_" + Ld + "_" + Cd + "_" + Vd
	 *   bn + "_" + Ld + "_" + Cd
	 *   bn + "_" + Ld
	 *   bn
	 * 
* * Where {@code bn} is this bundle's localization basename, {@code Ls}, * {@code Cs} and {@code Vs} are the specified locale (language, country, * variant) and {@code Ld}, {@code Cd} and {@code Vd} are the default locale * (language, country, variant). * * If {@code null} is specified as the locale string, the header values must * be localized using the default locale. If the empty string ("") * is specified as the locale string, the header values must not be * localized and the raw (unlocalized) header values, including any leading * "%", must be returned. If no localization is found for a header * value, the header value without the leading "%" is returned. * *

* This method must continue to return Manifest header information while * this bundle is in the {@code UNINSTALLED} state, however the header * values must only be available in the raw and default locale values. * * @param locale The locale name into which the header values are to be * localized. If the specified locale is {@code null} then the locale * returned by {@code java.util.Locale.getDefault} is used. If the * specified locale is the empty string, this method will return the * raw (unlocalized) manifest headers including any leading * "%". * @return An unmodifiable {@code Dictionary} object containing this * bundle's Manifest headers and values. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,METADATA]}, and the Java Runtime * Environment supports permissions. * @see #getHeaders() * @see Constants#BUNDLE_LOCALIZATION * @since 1.3 */ Dictionary getHeaders(String locale); /** * Returns the symbolic name of this bundle as specified by its * {@code Bundle-SymbolicName} manifest header. The bundle symbolic name * should be based on the reverse domain name naming convention like that * used for java packages. * *

* This method must continue to return this bundle's symbolic name while * this bundle is in the {@code UNINSTALLED} state. * * @return The symbolic name of this bundle or {@code null} if this bundle * does not have a symbolic name. * @since 1.3 */ String getSymbolicName(); /** * Loads the specified class using this bundle's class loader. * *

* If this bundle is a fragment bundle then this method must throw a * {@code ClassNotFoundException}. * *

* If this bundle's state is {@code INSTALLED}, this method must attempt to * resolve this bundle before attempting to load the class. * *

* If this bundle cannot be resolved, a Framework event of type * {@link FrameworkEvent#ERROR} is fired containing a * {@code BundleException} with details of the reason this bundle could not * be resolved. This method must then throw a {@code ClassNotFoundException}. * *

* If this bundle's state is {@code UNINSTALLED}, then an * {@code IllegalStateException} is thrown. * * @param name The name of the class to load. * @return The Class object for the requested class. * @throws ClassNotFoundException If no such class can be found or if this * bundle is a fragment bundle or if the caller does not have the * appropriate {@code AdminPermission[this,CLASS]}, and the Java * Runtime Environment supports permissions. * @throws IllegalStateException If this bundle has been uninstalled. * @since 1.3 */ Class loadClass(String name) throws ClassNotFoundException; /** * Find the specified resources from this bundle's class loader. * * This bundle's class loader is called to search for the specified * resources. If this bundle's state is {@code INSTALLED}, this method must * attempt to resolve this bundle before attempting to get the specified * resources. If this bundle cannot be resolved, then only this bundle must * be searched for the specified resources. Imported packages cannot be * searched when a bundle has not been resolved. If this bundle is a * fragment bundle then {@code null} is returned. *

* Note: Jar and zip files are not required to include directory entries. * URLs to directory entries will not be returned if the bundle contents do * not contain directory entries. * * @param name The name of the resource. See * {@code ClassLoader.getResources} for a description of the format * of a resource name. * @return An enumeration of URLs to the named resources, or {@code null} if * the resource could not be found or if this bundle is a fragment * bundle or if the caller does not have the appropriate * {@code AdminPermission[this,RESOURCE]}, and the Java Runtime * Environment supports permissions. * @throws IllegalStateException If this bundle has been uninstalled. * @throws IOException If there is an I/O error. * @since 1.3 */ Enumeration getResources(String name) throws IOException; /** * Returns an Enumeration of all the paths ({@code String} objects) to * entries within this bundle whose longest sub-path matches the specified * path. This bundle's class loader is not used to search for entries. Only * the contents of this bundle are searched. *

* The specified path is always relative to the root of this bundle and may * begin with a "/". A path value of "/" indicates the * root of this bundle. *

* Returned paths indicating subdirectory paths end with a "/". * The returned paths are all relative to the root of this bundle and must * not begin with "/". *

* Note: Jar and zip files are not required to include directory entries. * Paths to directory entries will not be returned if the bundle contents do * not contain directory entries. * * @param path The path name for which to return entry paths. * @return An Enumeration of the entry paths ({@code String} objects) or * {@code null} if no entry could be found or if the caller does not * have the appropriate {@code AdminPermission[this,RESOURCE]} and * the Java Runtime Environment supports permissions. * @throws IllegalStateException If this bundle has been uninstalled. * @since 1.3 */ Enumeration getEntryPaths(String path); /** * Returns a URL to the entry at the specified path in this bundle. This * bundle's class loader is not used to search for the entry. Only the * contents of this bundle are searched for the entry. *

* The specified path is always relative to the root of this bundle and may * begin with "/". A path value of "/" indicates the * root of this bundle. *

* Note: Jar and zip files are not required to include directory entries. * URLs to directory entries will not be returned if the bundle contents do * not contain directory entries. * * @param path The path name of the entry. * @return A URL to the entry, or {@code null} if no entry could be found or * if the caller does not have the appropriate * {@code AdminPermission[this,RESOURCE]} and the Java Runtime * Environment supports permissions. * @throws IllegalStateException If this bundle has been uninstalled. * @since 1.3 */ URL getEntry(String path); /** * Returns the time when this bundle was last modified. A bundle is * considered to be modified when it is installed, updated or uninstalled. * *

* The time value is the number of milliseconds since January 1, 1970, * 00:00:00 UTC. * * @return The time when this bundle was last modified. * @since 1.3 */ long getLastModified(); /** * Returns entries in this bundle and its attached fragments. This bundle's * class loader is not used to search for entries. Only the contents of this * bundle and its attached fragments are searched for the specified entries. * * If this bundle's state is {@code INSTALLED}, this method must attempt to * resolve this bundle before attempting to find entries. * *

* This method is intended to be used to obtain configuration, setup, * localization and other information from this bundle. This method takes * into account that the "contents" of this bundle can be extended * with fragments. This "bundle space" is not a namespace with * unique members; the same entry name can be present multiple times. This * method therefore returns an enumeration of URL objects. These URLs can * come from different JARs but have the same path name. This method can * either return only entries in the specified path or recurse into * subdirectories returning entries in the directory tree beginning at the * specified path. Fragments can be attached after this bundle is resolved, * possibly changing the set of URLs returned by this method. If this bundle * is not resolved, only the entries in the JAR file of this bundle are * returned. *

* Examples: * *

	 * // List all XML files in the OSGI-INF directory and below
	 * Enumeration e = b.findEntries("OSGI-INF", "*.xml", true);
	 * 
	 * // Find a specific localization file
	 * Enumeration e = b.findEntries("OSGI-INF/l10n",
	 *     "bundle_nl_DU.properties", false);
	 * if (e.hasMoreElements())
	 *     return (URL) e.nextElement();
	 * 
* *

* URLs for directory entries must have their path end with "/". *

* Note: Jar and zip files are not required to include directory entries. * URLs to directory entries will not be returned if the bundle contents do * not contain directory entries. * * @param path The path name in which to look. The path is always relative * to the root of this bundle and may begin with "/". A * path value of "/" indicates the root of this bundle. * @param filePattern The file name pattern for selecting entries in the * specified path. The pattern is only matched against the last * element of the entry path. If the entry is a directory then the * trailing "/" is not used for pattern matching. Substring * matching is supported, as specified in the Filter specification, * using the wildcard character ("*"). If null is * specified, this is equivalent to "*" and matches all * files. * @param recurse If {@code true}, recurse into subdirectories. Otherwise * only return entries from the specified path. * @return An enumeration of URL objects for each matching entry, or * {@code null} if no matching entry could be found or if the caller * does not have the appropriate * {@code AdminPermission[this,RESOURCE]}, and the Java Runtime * Environment supports permissions. The URLs are sorted such that * entries from this bundle are returned first followed by the * entries from attached fragments in attachment order. If this * bundle is a fragment, then only matching entries in this fragment * are returned. * @throws IllegalStateException If this bundle has been uninstalled. * @since 1.3 */ Enumeration findEntries(String path, String filePattern, boolean recurse); /** * Returns this bundle's {@link BundleContext}. The returned * {@code BundleContext} can be used by the caller to act on behalf of this * bundle. * *

* If this bundle is not in the {@link #STARTING}, {@link #ACTIVE}, or * {@link #STOPPING} states or this bundle is a fragment bundle, then this * bundle has no valid {@code BundleContext}. This method will return * {@code null} if this bundle has no valid {@code BundleContext}. * * @return A {@code BundleContext} for this bundle or {@code null} if this * bundle has no valid {@code BundleContext}. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,CONTEXT]}, and the Java Runtime * Environment supports permissions. * @since 1.4 */ BundleContext getBundleContext(); /** * Return the certificates for the signers of this bundle and the * certificate chains for those signers. * * @param signersType If {@link #SIGNERS_ALL} is specified, then information * on all signers of this bundle is returned. If * {@link #SIGNERS_TRUSTED} is specified, then only information on * the signers of this bundle trusted by the framework is returned. * @return The {@code X509Certificate}s for the signers of this bundle and * the {@code X509Certificate} chains for those signers. The keys of * the {@code Map} are the {@code X509Certificate}s of the signers * of this bundle. The value for a key is a {@code List} containing * the {@code X509Certificate} chain for the signer. The first item * in the {@code List} is the signer's {@code X509Certificate} which * is then followed by the rest of the {@code X509Certificate} * chain. The returned {@code Map} will be empty if there are no * signers. The returned {@code Map} is the property of the caller * who is free to modify it. * @throws IllegalArgumentException If the specified {@code signersType} is * not {@link #SIGNERS_ALL} or {@link #SIGNERS_TRUSTED}. * @since 1.5 */ Map> getSignerCertificates(int signersType); /** * Returns the version of this bundle as specified by its * {@code Bundle-Version} manifest header. If this bundle does not have a * specified version then {@link Version#emptyVersion} is returned. * *

* This method must continue to return this bundle's version while this * bundle is in the {@code UNINSTALLED} state. * * @return The version of this bundle. * @since 1.5 */ Version getVersion(); /** * Adapt this bundle to the specified type. * *

* Adapting this bundle to the specified type may require certain checks, * including security checks, to succeed. If a check does not succeed, then * this bundle cannot be adapted and {@code null} is returned. * * @param The type to which this bundle is to be adapted. * @param type Class object for the type to which this bundle is to be * adapted. * @return The object, of the specified type, to which this bundle has been * adapted or {@code null} if this bundle cannot be adapted to the * specified type. * @throws SecurityException If the caller does not have the appropriate * {@code AdaptPermission[type,this,ADAPT]}, and the Java Runtime * Environment supports permissions. * @since 1.6 */ A adapt(Class type); /** * Creates a {@code File} object for a file in the persistent storage area * provided for this bundle by the Framework. This method will return * {@code null} if the platform does not have file system support or this * bundle is a fragment bundle. * *

* A {@code File} object for the base directory of the persistent storage * area provided for this bundle by the Framework can be obtained by calling * this method with an empty string as {@code filename}. * *

* If the Java Runtime Environment supports permissions, the Framework will * ensure that this bundle has the {@code java.io.FilePermission} with * actions {@code read},{@code write},{@code delete} for all files * (recursively) in the persistent storage area provided for this bundle. * * @param filename A relative name to the file to be accessed. * @return A {@code File} object that represents the requested file or * {@code null} if the platform does not have file system support or * this bundle is a fragment bundle. * @throws IllegalStateException If this bundle has been uninstalled. * @since 1.6 */ File getDataFile(String filename); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/FrameworkEvent.java0000644000175000017500000001470112346513664027237 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2004, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.util.EventObject; import org.osgi.framework.startlevel.FrameworkStartLevel; import org.osgi.framework.wiring.FrameworkWiring; /** * A general event from the Framework. * *

* {@code FrameworkEvent} objects are delivered to {@code FrameworkListener}s * when a general event occurs within the OSGi environment. A type code is used * to identify the event type for future extendability. * *

* OSGi Alliance reserves the right to extend the set of event types. * * @Immutable * @see FrameworkListener * @version $Id: f679c7581879a2e6006ecdd317a5dd5f735764e3 $ */ public class FrameworkEvent extends EventObject { static final long serialVersionUID = 207051004521261705L; /** * Bundle related to the event. */ private final Bundle bundle; /** * Exception related to the event. */ private final Throwable throwable; /** * Type of event. */ private final int type; /** * The Framework has started. * *

* This event is fired when the Framework has started after all installed * bundles that are marked to be started have been started and the Framework * has reached the initial start level. The source of this event is the * System Bundle. * * @see "The Start Level Specification" */ public final static int STARTED = 0x00000001; /** * An error has occurred. * *

* There was an error associated with a bundle. */ public final static int ERROR = 0x00000002; /** * A FrameworkWiring.refreshBundles operation has completed. * *

* This event is fired when the Framework has completed the refresh bundles * operation initiated by a call to the FrameworkWiring.refreshBundles * method. The source of this event is the System Bundle. * * @since 1.2 * @see FrameworkWiring#refreshBundles(java.util.Collection, * FrameworkListener...) */ public final static int PACKAGES_REFRESHED = 0x00000004; /** * A FrameworkStartLevel.setStartLevel operation has completed. * *

* This event is fired when the Framework has completed changing the active * start level initiated by a call to the StartLevel.setStartLevel method. * The source of this event is the System Bundle. * * @since 1.2 * @see FrameworkStartLevel#setStartLevel(int, FrameworkListener...) */ public final static int STARTLEVEL_CHANGED = 0x00000008; /** * A warning has occurred. * *

* There was a warning associated with a bundle. * * @since 1.3 */ public final static int WARNING = 0x00000010; /** * An informational event has occurred. * *

* There was an informational event associated with a bundle. * * @since 1.3 */ public final static int INFO = 0x00000020; /** * The Framework has stopped. * *

* This event is fired when the Framework has been stopped because of a stop * operation on the system bundle. The source of this event is the System * Bundle. * * @since 1.5 */ public final static int STOPPED = 0x00000040; /** * The Framework has stopped during update. * *

* This event is fired when the Framework has been stopped because of an * update operation on the system bundle. The Framework will be restarted * after this event is fired. The source of this event is the System Bundle. * * @since 1.5 */ public final static int STOPPED_UPDATE = 0x00000080; /** * The Framework has stopped and the boot class path has changed. * *

* This event is fired when the Framework has been stopped because of a stop * operation on the system bundle and a bootclasspath extension bundle has * been installed or updated. The source of this event is the System Bundle. * * @since 1.5 */ public final static int STOPPED_BOOTCLASSPATH_MODIFIED = 0x00000100; /** * The Framework did not stop before the wait timeout expired. * *

* This event is fired when the Framework did not stop before the wait * timeout expired. The source of this event is the System Bundle. * * @since 1.5 */ public final static int WAIT_TIMEDOUT = 0x00000200; /** * Creates a Framework event. * * @param type The event type. * @param source The event source object. This may not be {@code null}. * @deprecated As of 1.2. This constructor is deprecated in favor of using * the other constructor with the System Bundle as the event * source. */ public FrameworkEvent(int type, Object source) { super(source); this.type = type; this.bundle = null; this.throwable = null; } /** * Creates a Framework event regarding the specified bundle. * * @param type The event type. * @param bundle The event source. * @param throwable The related exception. This argument may be {@code null} * if there is no related exception. */ public FrameworkEvent(int type, Bundle bundle, Throwable throwable) { super(bundle); this.type = type; this.bundle = bundle; this.throwable = throwable; } /** * Returns the exception related to this event. * * @return The related exception or {@code null} if none. */ public Throwable getThrowable() { return throwable; } /** * Returns the bundle associated with the event. This bundle is also the * source of the event. * * @return The bundle associated with the event. */ public Bundle getBundle() { return bundle; } /** * Returns the type of framework event. *

* The type values are: *

* * @return The type of state change. */ public int getType() { return type; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/Filter.java0000644000175000017500000001126212346513664025524 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.util.Dictionary; import java.util.Map; /** * An RFC 1960-based Filter. *

* {@code Filter}s can be created by calling * {@link BundleContext#createFilter(String)} or * {@link FrameworkUtil#createFilter(String)} with a filter string. *

* A {@code Filter} can be used numerous times to determine if the match * argument matches the filter string that was used to create the {@code Filter}. *

* Some examples of LDAP filters are: * *

 *  "(cn=Babs Jensen)"
 *  "(!(cn=Tim Howes))"
 *  "(&(" + Constants.OBJECTCLASS + "=Person)(|(sn=Jensen)(cn=Babs J*)))"
 *  "(o=univ*of*mich*)"
 * 
* * @since 1.1 * @see "Core Specification, Filters, for a description of the filter string syntax." * @ThreadSafe * @noimplement * @version $Id: 807a04ac07c3230b8f4d4e0f9588a35fbdc41e18 $ */ public interface Filter { /** * Filter using a service's properties. *

* This {@code Filter} is executed using the keys and values of the * referenced service's properties. The keys are looked up in a case * insensitive manner. * * @param reference The reference to the service whose properties are used * in the match. * @return {@code true} if the service's properties match this * {@code Filter}; {@code false} otherwise. */ boolean match(ServiceReference reference); /** * Filter using a {@code Dictionary} with case insensitive key lookup. This * {@code Filter} is executed using the specified {@code Dictionary}'s keys * and values. The keys are looked up in a case insensitive manner. * * @param dictionary The {@code Dictionary} whose key/value pairs are used * in the match. * @return {@code true} if the {@code Dictionary}'s values match this * filter; {@code false} otherwise. * @throws IllegalArgumentException If {@code dictionary} contains case * variants of the same key name. */ boolean match(Dictionary dictionary); /** * Returns this {@code Filter}'s filter string. *

* The filter string is normalized by removing whitespace which does not * affect the meaning of the filter. * * @return This {@code Filter}'s filter string. */ String toString(); /** * Compares this {@code Filter} to another {@code Filter}. * *

* This implementation returns the result of calling * {@code this.toString().equals(obj.toString())}. * * @param obj The object to compare against this {@code Filter}. * @return If the other object is a {@code Filter} object, then returns the * result of calling {@code this.toString().equals(obj.toString())}; * {@code false} otherwise. */ boolean equals(Object obj); /** * Returns the hashCode for this {@code Filter}. * *

* This implementation returns the result of calling * {@code this.toString().hashCode()}. * * @return The hashCode of this {@code Filter}. */ int hashCode(); /** * Filter using a {@code Dictionary}. This {@code Filter} is executed using * the specified {@code Dictionary}'s keys and values. The keys are looked * up in a normal manner respecting case. * * @param dictionary The {@code Dictionary} whose key/value pairs are used * in the match. * @return {@code true} if the {@code Dictionary}'s values match this * filter; {@code false} otherwise. * @since 1.3 */ boolean matchCase(Dictionary dictionary); /** * Filter using a {@code Map}. This {@code Filter} is executed using the * specified {@code Map}'s keys and values. The keys are looked up in a * normal manner respecting case. * * @param map The {@code Map} whose key/value pairs are used in the match. * Maps with {@code null} key or values are not supported. A * {@code null} value is considered not present to the filter. * @return {@code true} if the {@code Map}'s values match this filter; * {@code false} otherwise. * @since 1.6 */ boolean matches(Map map); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/namespace/0000755000175000017500000000000012475375714025373 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/namespace/packageinfo0000644000175000017500000000001412346513664027553 0ustar felixfelixversion 1.0 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/namespace/PackageNamespace.java0000644000175000017500000001062212346513664031402 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.namespace; import org.osgi.resource.Namespace; /** * Package Capability and Requirement Namespace. * *

* A resource provides zero or more package capabilities (this is, exported * packages) and requires zero or more package requirements (that is, imported * packages). * *

* This class defines the names for the attributes and directives for this * namespace. All unspecified capability attributes are of type {@code String} * and are used as arbitrary matching attributes for the capability. The values * associated with the specified directive and attribute keys are of type * {@code String}, unless otherwise indicated. * *

* Unless otherwise noted, all directives specified on the * {@code Export-Package} header are visible in the capability and all * directives specified on the {@code Import-Package} and * {@code DynamicImport-Package} headers are visible in the requirement. * *

    *
  • The {@link Namespace#CAPABILITY_EFFECTIVE_DIRECTIVE effective} * {@link Namespace#REQUIREMENT_EFFECTIVE_DIRECTIVE directives} must be ignored. * This namespace is only effective at {@link Namespace#EFFECTIVE_RESOLVE * resolve} time. An {@code effective} directive specified on the * {@code Export-Package}, {@code Import-Package} or * {@code DynamicImport-Package} headers must be ignored. An {@code effective} * directive must not be present in a capability or requirement.
  • *
  • The {@link Namespace#REQUIREMENT_CARDINALITY_DIRECTIVE cardinality} * directive has limited applicability to this namespace. A {@code cardinality} * directive specified on the {@code Import-Package} or * {@code DynamicImport-Package} headers must be ignored. Only requirements with * {@link Namespace#REQUIREMENT_RESOLUTION_DIRECTIVE resolution} set to * {@link #RESOLUTION_DYNAMIC dynamic} and the package name contains a wildcard * must have the {@code cardinality} directive set to * {@link Namespace#CARDINALITY_MULTIPLE multiple}. Otherwise, a * {@code cardinality} directive must not be present in a requirement.
  • *
* * @Immutable * @version $Id: 5adc45bd1ae26120cbff3562c7c8cefc01e38bd3 $ */ public final class PackageNamespace extends AbstractWiringNamespace { /** * Namespace name for package capabilities and requirements. * *

* Also, the capability attribute used to specify the name of the package. */ public static final String PACKAGE_NAMESPACE = "osgi.wiring.package"; /** * The capability directive used to specify the comma separated list of * classes which must be allowed to be exported. */ public final static String CAPABILITY_INCLUDE_DIRECTIVE = "include"; /** * The capability directive used to specify the comma separated list of * classes which must not be allowed to be exported. */ public final static String CAPABILITY_EXCLUDE_DIRECTIVE = "exclude"; /** * The capability attribute contains the {@code Version} of the package if * one is specified or {@code 0.0.0} if not specified. The value of this * attribute must be of type {@code Version}. */ public final static String CAPABILITY_VERSION_ATTRIBUTE = "version"; /** * The capability attribute contains the symbolic name of the resource * providing the package. */ public final static String CAPABILITY_BUNDLE_SYMBOLICNAME_ATTRIBUTE = "bundle-symbolic-name"; /** * The directive value identifying a dynamic requirement resolution type. A * dynamic resolution type indicates that the requirement is resolved * dynamically at runtime (such as a dynamically imported package) and the * resource will be resolved without the requirement being resolved. * * @see Namespace#REQUIREMENT_RESOLUTION_DIRECTIVE */ public final static String RESOLUTION_DYNAMIC = "dynamic"; private PackageNamespace() { // empty } } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/namespace/ExecutionEnvironmentNamespace.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/namespace/ExecutionEnvironmentNamespac0000644000175000017500000000347412346513664033161 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.namespace; import org.osgi.resource.Namespace; /** * Execution Environment Capability and Requirement Namespace. * *

* This class defines the names for the attributes and directives for this * namespace. All unspecified capability attributes are of type {@code String} * and are used as arbitrary matching attributes for the capability. The values * associated with the specified directive and attribute keys are of type * {@code String}, unless otherwise indicated. * * @Immutable * @version $Id: e1c30aac8efacc1b21ab20ffebcc1af30a1054a8 $ */ public final class ExecutionEnvironmentNamespace extends Namespace { /** * Namespace name for execution environment capabilities and requirements. * *

* Also, the capability attribute used to specify the name of the execution * environment. */ public static final String EXECUTION_ENVIRONMENT_NAMESPACE = "osgi.ee"; /** * The capability attribute contains the versions of the execution * environment. The value of this attribute must be of type * {@code List}. */ public final static String CAPABILITY_VERSION_ATTRIBUTE = "version"; private ExecutionEnvironmentNamespace() { // empty } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/namespace/IdentityNamespace.java0000644000175000017500000001234212346513664031641 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.namespace; import org.osgi.resource.Namespace; /** * Identity Capability and Requirement Namespace. * *

* This class defines the names for the attributes and directives for this * namespace. All unspecified capability attributes are of type {@code String} * and are used as arbitrary matching attributes for the capability. The values * associated with the specified directive and attribute keys are of type * {@code String}, unless otherwise indicated. * *

* Each resource provides exactly one identity capability that * can be used to identify the resource. * *

* The bundle wiring for the bundle revision provides exactly * one identity capability. * *

* † A resource with no symbolic name must not provide an identity * capability. * * @Immutable * @version $Id: e34dcaba1f828326a0db13b3d811b2d170ff97a5 $ */ public final class IdentityNamespace extends Namespace { /** * Namespace name for identity capabilities and requirements. * *

* Also, the capability attribute used to specify the symbolic name of the * resource. */ public static final String IDENTITY_NAMESPACE = "osgi.identity"; /** * The capability directive identifying if the resource is a singleton. A * {@code String} value of "true" indicates the resource is a * singleton; any other value or {@code null} indicates the resource is not * a singleton. */ public static final String CAPABILITY_SINGLETON_DIRECTIVE = "singleton"; /** * The capability attribute identifying the {@code Version} of the resource * if one is specified or {@code 0.0.0} if not specified. The value of this * attribute must be of type {@code Version}. */ public static final String CAPABILITY_VERSION_ATTRIBUTE = "version"; /** * The capability attribute identifying the resource type. If the resource * has no type then the value {@link #TYPE_UNKNOWN unknown} must be used for * the attribute. * * @see #TYPE_BUNDLE * @see #TYPE_FRAGMENT * @see #TYPE_UNKNOWN */ public static final String CAPABILITY_TYPE_ATTRIBUTE = "type"; /** * The attribute value identifying the resource * {@link #CAPABILITY_TYPE_ATTRIBUTE type} as an OSGi bundle. * * @see #CAPABILITY_TYPE_ATTRIBUTE */ public static final String TYPE_BUNDLE = "osgi.bundle"; /** * The attribute value identifying the resource * {@link #CAPABILITY_TYPE_ATTRIBUTE type} as an OSGi fragment. * * @see #CAPABILITY_TYPE_ATTRIBUTE */ public static final String TYPE_FRAGMENT = "osgi.fragment"; /** * The attribute value identifying the resource * {@link #CAPABILITY_TYPE_ATTRIBUTE type} as unknown. * * @see #CAPABILITY_TYPE_ATTRIBUTE */ public static final String TYPE_UNKNOWN = "unknown"; /** * The capability attribute that contains a human readable copyright notice * for the resource. See the {@code Bundle-Copyright} manifest header. */ public static final String CAPABILITY_COPYRIGHT_ATTRIBUTE = "copyright"; /** * The capability attribute that contains a human readable description for * the resource. See the {@code Bundle-Description} manifest header. */ public static final String CAPABILITY_DESCRIPTION_ATTRIBUTE = "description"; /** * The capability attribute that contains the URL to documentation for the * resource. See the {@code Bundle-DocURL} manifest header. */ public static final String CAPABILITY_DOCUMENTATION_ATTRIBUTE = "documentation"; /** * The capability attribute that contains the URL to the license for the * resource. See the {@code name} portion of the {@code Bundle-License} * manifest header. */ public static final String CAPABILITY_LICENSE_ATTRIBUTE = "license"; /** * The requirement directive that classifies the relationship with another * resource. * * @see #CLASSIFIER_SOURCES * @see #CLASSIFIER_JAVADOC */ public static final String REQUIREMENT_CLASSIFIER_DIRECTIVE = "classifier"; /** * The attribute value identifying the resource * {@link #REQUIREMENT_CLASSIFIER_DIRECTIVE classifier} as an archive * containing the source code in the same directory layout as the resource. * * @see #REQUIREMENT_CLASSIFIER_DIRECTIVE */ public static final String CLASSIFIER_SOURCES = "sources"; /** * The attribute value identifying the resource * {@link #REQUIREMENT_CLASSIFIER_DIRECTIVE classifier} as an archive * containing the javadoc in the same directory layout as the resource. * * @see #REQUIREMENT_CLASSIFIER_DIRECTIVE */ public static final String CLASSIFIER_JAVADOC = "javadoc"; private IdentityNamespace() { // empty } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/namespace/package-info.java0000644000175000017500000000173212346513664030560 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Namespace Package Version 1.0. * *

* Bundles should not need to import this package at runtime since all * the types in this package just contain constants for capability and * requirement namespaces specified by the OSGi Alliance. * * @version $Id: e40cb47c153c5bd53a1a5c9f7cedf047f8b31cf5 $ */ package org.osgi.framework.namespace; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/namespace/AbstractWiringNamespace.java0000644000175000017500000000362412346513664032776 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.namespace; import org.osgi.resource.Namespace; /** * Wiring Capability and Requirement Namespaces base class. * *

* This class is the common class shared by all OSGi defined wiring namespaces. * It defines the names for the common attributes and directives for the OSGi * specified wiring namespaces. * *

* The values associated with these keys are of type {@code String}, unless * otherwise indicated. * * @Immutable * @version $Id: 383e84df9190757ce6bb6fb722e80a3b7d6b68da $ */ public abstract class AbstractWiringNamespace extends Namespace { /** * The capability directive used to specify the comma separated list of * mandatory attributes which must be specified in the * {@link Namespace#REQUIREMENT_FILTER_DIRECTIVE filter} of a requirement in * order for the capability to match the requirement. */ public final static String CAPABILITY_MANDATORY_DIRECTIVE = "mandatory"; /** * The capability attribute contains the {@code Version} of the resource * providing the capability if one is specified or {@code 0.0.0} if not * specified. The value of this attribute must be of type {@code Version}. */ public static final String CAPABILITY_BUNDLE_VERSION_ATTRIBUTE = "bundle-version"; AbstractWiringNamespace() { // empty } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/namespace/HostNamespace.java0000644000175000017500000001430612346513664030767 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.namespace; import org.osgi.resource.Namespace; /** * Host Capability and Requirement Namespace. * *

* This class defines the names for the attributes and directives for this * namespace. All unspecified capability attributes are of type {@code String} * and are used as arbitrary matching attributes for the capability. The values * associated with the specified directive and attribute keys are of type * {@code String}, unless otherwise indicated. * *

* Unless otherwise noted, all directives specified on the * {@code Bundle-SymbolicName} header are visible in the capability and all * directives specified on the {@code Fragment-Host} header are visible in the * requirement. * *

    *
  • The {@link Namespace#CAPABILITY_USES_DIRECTIVE uses} directive must be * ignored. A {@code uses} directive specified on the * {@code Bundle-SymbolicName} header must be ignored. A {@code uses} directive * must not be present in the capability.
  • *
  • The {@link Namespace#CAPABILITY_EFFECTIVE_DIRECTIVE effective} * {@link Namespace#REQUIREMENT_EFFECTIVE_DIRECTIVE directives} must be ignored. * This namespace is only effective at {@link Namespace#EFFECTIVE_RESOLVE * resolve} time. An {@code effective} directive specified on the * {@code Bundle-SymbolicName} or {@code Fragment-Host} headers must be ignored. * An {@code effective} directive must not be present in a capability or * requirement.
  • *
  • The {@link Namespace#REQUIREMENT_CARDINALITY_DIRECTIVE cardinality} * directive has limited applicability to this namespace. A {@code cardinality} * directive specified on the {@code Fragment-Host} header must be ignored. All * requirements must have the {@code cardinality} directive set to * {@link Namespace#CARDINALITY_MULTIPLE multiple}.
  • *
* *

* A non-fragment resource with the with the * {@link IdentityNamespace#TYPE_BUNDLE osgi.bundle} type * {@link IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE identity} provides zero or * one host capabilities. A fragment resource with the * {@link IdentityNamespace#TYPE_FRAGMENT osgi.fragment} type * {@link IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE identity} must not declare * a host capability and must declare exactly one host requirement. *

* † A resource with no bundle symbolic name must not provide a host * capability. * * @Immutable * @version $Id: aa3cc744c7b9c21d908260f456567ab8a6de1430 $ */ public final class HostNamespace extends AbstractWiringNamespace { /** * Namespace name for host capabilities and requirements. * *

* Also, the capability attribute used to specify the symbolic name of the * host. * */ public static final String HOST_NAMESPACE = "osgi.wiring.host"; /** * The capability directive identifying if the resource is a singleton. A * {@code String} value of "{@code true}" indicates the resource * is a singleton; any other value or {@code null} indicates the resource is * not a singleton. * *

* This directive should be examined using the {@link IdentityNamespace * identity} namespace. * * @see IdentityNamespace#CAPABILITY_SINGLETON_DIRECTIVE */ public static final String CAPABILITY_SINGLETON_DIRECTIVE = "singleton"; /** * The capability directive identifying if and when a fragment may attach to * a host bundle. The default value is {@link #FRAGMENT_ATTACHMENT_ALWAYS * always}. * * @see #FRAGMENT_ATTACHMENT_ALWAYS * @see #FRAGMENT_ATTACHMENT_RESOLVETIME * @see #FRAGMENT_ATTACHMENT_NEVER */ public static final String CAPABILITY_FRAGMENT_ATTACHMENT_DIRECTIVE = "fragment-attachment"; /** * The directive value indicating that fragments are allowed to attach to * the host bundle at any time (while the host is resolved or during the * process of resolving the host bundle). * * @see #CAPABILITY_FRAGMENT_ATTACHMENT_DIRECTIVE */ public static final String FRAGMENT_ATTACHMENT_ALWAYS = "always"; /** * The directive value indicating that fragments are allowed to attach to * the host bundle only during the process of resolving the host bundle. * * @see #CAPABILITY_FRAGMENT_ATTACHMENT_DIRECTIVE */ public static final String FRAGMENT_ATTACHMENT_RESOLVETIME = "resolve-time"; /** * The directive value indicating that no fragments are allowed to attach to * the host bundle at any time. * * @see #CAPABILITY_FRAGMENT_ATTACHMENT_DIRECTIVE */ public static final String FRAGMENT_ATTACHMENT_NEVER = "never"; /** * The requirement directive used to specify the type of the extension * fragment. * * @see #EXTENSION_FRAMEWORK * @see #EXTENSION_BOOTCLASSPATH */ public final static String REQUIREMENT_EXTENSION_DIRECTIVE = "extension"; /** * The directive value indicating that the extension fragment is to be * loaded by the framework's class loader. * * * @see #REQUIREMENT_EXTENSION_DIRECTIVE */ public final static String EXTENSION_FRAMEWORK = "framework"; /** * The directive value indicating that the extension fragment is to be * loaded by the boot class loader. * * @see #REQUIREMENT_EXTENSION_DIRECTIVE */ public final static String EXTENSION_BOOTCLASSPATH = "bootclasspath"; /** * The requirement directive used to specify the visibility type for a * requirement. * *

* This directive should be examined using the {@link BundleNamespace * bundle} namespace. * * @see BundleNamespace#REQUIREMENT_VISIBILITY_DIRECTIVE */ public final static String REQUIREMENT_VISIBILITY_DIRECTIVE = "visibility"; private HostNamespace() { // empty } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/namespace/BundleNamespace.java0000644000175000017500000001336712346513664031271 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.namespace; import org.osgi.resource.Namespace; /** * Bundle Capability and Requirement Namespace. * *

* This class defines the names for the attributes and directives for this * namespace. All unspecified capability attributes are of type {@code String} * and are used as arbitrary matching attributes for the capability. The values * associated with the specified directive and attribute keys are of type * {@code String}, unless otherwise indicated. * *

* Unless otherwise noted, all directives specified on the * {@code Bundle-SymbolicName} header are visible in the capability and all * directives specified on the {@code Require-Bundle} header are visible in the * requirement. * *

    *
  • The {@link Namespace#CAPABILITY_USES_DIRECTIVE uses} directive must be * ignored. A {@code uses} directive specified on the * {@code Bundle-SymbolicName} header must be ignored. A {@code uses} directive * must not be present in the capability.
  • *
  • The {@link Namespace#CAPABILITY_EFFECTIVE_DIRECTIVE effective} * {@link Namespace#REQUIREMENT_EFFECTIVE_DIRECTIVE directives} must be ignored. * This namespace is only effective at {@link Namespace#EFFECTIVE_RESOLVE * resolve} time. An {@code effective} directive specified on the * {@code Bundle-SymbolicName} or {@code Require-Bundle} headers must be * ignored. An {@code effective} directive must not be present in a capability * or requirement.
  • *
  • The {@link Namespace#REQUIREMENT_CARDINALITY_DIRECTIVE cardinality} * directive must be ignored. A {@code cardinality} directive specified on the * {@code Require-Bundle} header must be ignored. A {@code cardinality} * directive must not be present in a requirement.
  • *
* *

* A non-fragment resource with the {@link IdentityNamespace#TYPE_BUNDLE * osgi.bundle} type {@link IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE * identity} provides exactly one bundle capability (that is, * the bundle can be required by another bundle). A fragment resource with the * {@link IdentityNamespace#TYPE_FRAGMENT osgi.fragment} type * {@link IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE identity} must not declare * a bundle capability. A resource requires zero or more bundle requirements * (that is, required bundles). *

* † A resource with no symbolic name must not provide a bundle * capability. * * @Immutable * @version $Id: 339f1204725aa9d9c2463b1224b2e38e505024e9 $ */ public final class BundleNamespace extends AbstractWiringNamespace { /** * Namespace name for bundle capabilities and requirements. * *

* Also, the capability attribute used to specify the symbolic name of the * bundle. */ public static final String BUNDLE_NAMESPACE = "osgi.wiring.bundle"; /** * The capability directive identifying if the resource is a singleton. A * {@code String} value of "{@code true}" indicates the resource * is a singleton; any other value or {@code null} indicates the resource is * not a singleton. * *

* This directive should be examined using the {@link IdentityNamespace * identity} namespace. * * @see IdentityNamespace#CAPABILITY_SINGLETON_DIRECTIVE */ public static final String CAPABILITY_SINGLETON_DIRECTIVE = "singleton"; /** * The capability directive identifying if and when a fragment may attach to * a host bundle. * *

* This directive should be examined using the {@link HostNamespace host} * namespace. * * @see HostNamespace#CAPABILITY_FRAGMENT_ATTACHMENT_DIRECTIVE */ public static final String CAPABILITY_FRAGMENT_ATTACHMENT_DIRECTIVE = "fragment-attachment"; /** * The requirement directive used to specify the type of the extension * fragment. * *

* This directive should be examined using the {@link HostNamespace host} * namespace. * * @see HostNamespace#REQUIREMENT_EXTENSION_DIRECTIVE */ public final static String REQUIREMENT_EXTENSION_DIRECTIVE = "extension"; /** * The requirement directive used to specify the visibility type for a * requirement. The default value is {@link #VISIBILITY_PRIVATE private}. * * @see #VISIBILITY_PRIVATE private * @see #VISIBILITY_REEXPORT reexport */ public final static String REQUIREMENT_VISIBILITY_DIRECTIVE = "visibility"; /** * The directive value identifying a private * {@link #REQUIREMENT_VISIBILITY_DIRECTIVE visibility} type. A private * visibility type indicates that any {@link PackageNamespace packages} that * are exported by the required bundle are not made visible on the export * signature of the requiring bundle. . * * @see #REQUIREMENT_VISIBILITY_DIRECTIVE */ public final static String VISIBILITY_PRIVATE = "private"; /** * The directive value identifying a reexport * {@link #REQUIREMENT_VISIBILITY_DIRECTIVE visibility} type. A reexport * visibility type indicates any {@link PackageNamespace packages} that are * exported by the required bundle are re-exported by the requiring bundle. * * @see #REQUIREMENT_VISIBILITY_DIRECTIVE */ public final static String VISIBILITY_REEXPORT = "reexport"; private BundleNamespace() { // empty } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/launch/0000755000175000017500000000000012475375714024711 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/launch/packageinfo0000644000175000017500000000001412346513664027071 0ustar felixfelixversion 1.1 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/launch/Framework.java0000644000175000017500000003407312346513664027513 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2008, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.launch; import java.io.InputStream; import java.net.URL; import java.util.Enumeration; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.FrameworkEvent; /** * A Framework instance. A Framework is also known as a System Bundle. * *

* Framework instances are created using a {@link FrameworkFactory}. The methods * of this interface can be used to manage and control the created framework * instance. * * @ThreadSafe * @noimplement * @version $Id: e76240d5de584d1666880d9bc358571a76cbd8fb $ */ public interface Framework extends Bundle { /** * Initialize this Framework. After calling this method, this Framework * must: *

    *
  • Have generated a new {@link Constants#FRAMEWORK_UUID framework UUID}. *
  • *
  • Be in the {@link #STARTING} state.
  • *
  • Have a valid Bundle Context.
  • *
  • Be at start level 0.
  • *
  • Have event handling enabled.
  • *
  • Have reified Bundle objects for all installed bundles.
  • *
  • Have registered any framework services. For example, * {@code ConditionalPermissionAdmin}.
  • *
  • Be {@link #adapt(Class) adaptable} to the OSGi defined types to which * a system bundle can be adapted.
  • *
* *

* This Framework will not actually be started until {@link #start() start} * is called. * *

* This method does nothing if called when this Framework is in the * {@link #STARTING}, {@link #ACTIVE} or {@link #STOPPING} states. * * @throws BundleException If this Framework could not be initialized. * @throws SecurityException If the Java Runtime Environment supports * permissions and the caller does not have the appropriate * {@code AdminPermission[this,EXECUTE]} or if there is a security * manager already installed and the * {@link Constants#FRAMEWORK_SECURITY} configuration property is * set. * */ void init() throws BundleException; /** * Wait until this Framework has completely stopped. The {@code stop} and * {@code update} methods on a Framework performs an asynchronous stop of * the Framework. This method can be used to wait until the asynchronous * stop of this Framework has completed. This method will only wait if * called when this Framework is in the {@link #STARTING}, {@link #ACTIVE}, * or {@link #STOPPING} states. Otherwise it will return immediately. *

* A Framework Event is returned to indicate why this Framework has stopped. * * @param timeout Maximum number of milliseconds to wait until this * Framework has completely stopped. A value of zero will wait * indefinitely. * @return A Framework Event indicating the reason this method returned. The * following {@code FrameworkEvent} types may be returned by this * method. *

    *
  • {@link FrameworkEvent#STOPPED STOPPED} - This Framework has * been stopped.
  • * *
  • {@link FrameworkEvent#STOPPED_UPDATE STOPPED_UPDATE} - This * Framework has been updated which has shutdown and will now * restart.
  • * *
  • {@link FrameworkEvent#STOPPED_BOOTCLASSPATH_MODIFIED * STOPPED_BOOTCLASSPATH_MODIFIED} - This Framework has been stopped * and a bootclasspath extension bundle has been installed or * updated. The VM must be restarted in order for the changed boot * class path to take effect.
  • * *
  • {@link FrameworkEvent#ERROR ERROR} - The Framework * encountered an error while shutting down or an error has occurred * which forced the framework to shutdown.
  • * *
  • {@link FrameworkEvent#WAIT_TIMEDOUT WAIT_TIMEDOUT} - This * method has timed out and returned before this Framework has * stopped.
  • *
* @throws InterruptedException If another thread interrupted the current * thread before or while the current thread was waiting for this * Framework to completely stop. The interrupted status of * the current thread is cleared when this exception is thrown. * @throws IllegalArgumentException If the value of timeout is negative. */ FrameworkEvent waitForStop(long timeout) throws InterruptedException; /** * Start this Framework. * *

* The following steps are taken to start this Framework: *

    *
  1. If this Framework is not in the {@link #STARTING} state, * {@link #init() initialize} this Framework.
  2. *
  3. All installed bundles must be started in accordance with each * bundle's persistent autostart setting. This means some bundles * will not be started, some will be started with eager activation * and some will be started with their declared activation policy. * The start level of this Framework is moved to the start level specified * by the {@link Constants#FRAMEWORK_BEGINNING_STARTLEVEL beginning start * level} framework property, as described in the Start Level * Specification. If this framework property is not specified, then the * start level of this Framework is moved to start level one (1). Any * exceptions that occur during bundle starting must be wrapped in a * {@link BundleException} and then published as a framework event of type * {@link FrameworkEvent#ERROR}
  4. *
  5. This Framework's state is set to {@link #ACTIVE}.
  6. *
  7. A framework event of type {@link FrameworkEvent#STARTED} is fired
  8. *
* * @throws BundleException If this Framework could not be started. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,EXECUTE]}, and the Java Runtime * Environment supports permissions. * @see "Start Level Specification" */ void start() throws BundleException; /** * Start this Framework. * *

* Calling this method is the same as calling {@link #start()}. There are no * start options for the Framework. * * @param options Ignored. There are no start options for the Framework. * @throws BundleException If this Framework could not be started. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,EXECUTE]}, and the Java Runtime * Environment supports permissions. * @see #start() */ void start(int options) throws BundleException; /** * Stop this Framework. * *

* The method returns immediately to the caller after initiating the * following steps to be taken on another thread. *

    *
  1. This Framework's state is set to {@link #STOPPING}.
  2. *
  3. All installed bundles must be stopped without changing each bundle's * persistent autostart setting. The start level of this Framework is * moved to start level zero (0), as described in the Start Level * Specification. Any exceptions that occur during bundle stopping must * be wrapped in a {@link BundleException} and then published as a framework * event of type {@link FrameworkEvent#ERROR}
  4. *
  5. Unregister all services registered by this Framework.
  6. *
  7. Event handling is disabled.
  8. *
  9. This Framework's state is set to {@link #RESOLVED}.
  10. *
  11. All resources held by this Framework are released. This includes * threads, bundle class loaders, open files, etc.
  12. *
  13. Notify all threads that are waiting at {@link #waitForStop(long) * waitForStop} that the stop operation has completed.
  14. *
*

* After being stopped, this Framework may be discarded, initialized or * started. * * @throws BundleException If stopping this Framework could not be * initiated. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,EXECUTE]}, and the Java Runtime * Environment supports permissions. * @see "Start Level Specification" */ void stop() throws BundleException; /** * Stop this Framework. * *

* Calling this method is the same as calling {@link #stop()}. There are no * stop options for the Framework. * * @param options Ignored. There are no stop options for the Framework. * @throws BundleException If stopping this Framework could not be * initiated. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,EXECUTE]}, and the Java Runtime * Environment supports permissions. * @see #stop() */ void stop(int options) throws BundleException; /** * The Framework cannot be uninstalled. * *

* This method always throws a BundleException. * * @throws BundleException This Framework cannot be uninstalled. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,LIFECYCLE]}, and the Java Runtime * Environment supports permissions. */ void uninstall() throws BundleException; /** * Stop and restart this Framework. * *

* The method returns immediately to the caller after initiating the * following steps to be taken on another thread. *

    *
  1. Perform the steps in the {@link #stop()} method to stop this * Framework.
  2. *
  3. Perform the steps in the {@link #start()} method to start this * Framework.
  4. *
* * @throws BundleException If stopping and restarting this Framework could * not be initiated. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,LIFECYCLE]}, and the Java Runtime * Environment supports permissions. */ void update() throws BundleException; /** * Stop and restart this Framework. * *

* Calling this method is the same as calling {@link #update()} except that * any provided InputStream is immediately closed. * * @param in Any provided InputStream is immediately closed before returning * from this method and otherwise ignored. * @throws BundleException If stopping and restarting this Framework could * not be initiated. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,LIFECYCLE]}, and the Java Runtime * Environment supports permissions. */ void update(InputStream in) throws BundleException; /** * Returns the Framework unique identifier. This Framework is assigned the * unique identifier zero (0) since this Framework is also a System Bundle. * * @return 0. * @see Bundle#getBundleId() */ long getBundleId(); /** * Returns the Framework location identifier. This Framework is assigned the * unique location "{@code System Bundle}" since this Framework is * also a System Bundle. * * @return The string "{@code System Bundle}". * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[this,METADATA]}, and the Java Runtime * Environment supports permissions. * @see Bundle#getLocation() * @see Constants#SYSTEM_BUNDLE_LOCATION */ String getLocation(); /** * Returns the symbolic name of this Framework. The symbolic name is unique * for the implementation of the framework. However, the symbolic name * "{@code system.bundle}" must be recognized as an alias to the * implementation-defined symbolic name since this Framework is also a * System Bundle. * * @return The symbolic name of this Framework. * @see Bundle#getSymbolicName() * @see Constants#SYSTEM_BUNDLE_SYMBOLICNAME */ String getSymbolicName(); /** * Returns {@code null} as a framework implementation does not have a proper * bundle from which to return entry paths. * * @param path Ignored. * @return {@code null} as a framework implementation does not have a proper * bundle from which to return entry paths. */ Enumeration getEntryPaths(String path); /** * Returns {@code null} as a framework implementation does not have a proper * bundle from which to return an entry. * * @param path Ignored. * @return {@code null} as a framework implementation does not have a proper * bundle from which to return an entry. */ URL getEntry(String path); /** * Returns {@code null} as a framework implementation does not have a proper * bundle from which to return entries. * * @param path Ignored. * @param filePattern Ignored. * @param recurse Ignored. * @return {@code null} as a framework implementation does not have a proper * bundle from which to return entries. */ Enumeration findEntries(String path, String filePattern, boolean recurse); /** * Adapt this Framework to the specified type. * *

* Adapting this Framework to the specified type may require certain checks, * including security checks, to succeed. If a check does not succeed, then * this Framework cannot be adapted and {@code null} is returned. If this * Framework is not {@link #init() initialized}, then {@code null} is * returned if the specified type is one of the OSGi defined types to which * a system bundle can be adapted. * * @param The type to which this Framework is to be adapted. * @param type Class object for the type to which this Framework is to be * adapted. * @return The object, of the specified type, to which this Framework has * been adapted or {@code null} if this Framework cannot be adapted */ A adapt(Class type); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/launch/package-info.java0000644000175000017500000000205212346513664030072 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Framework Launch Package Version 1.1. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. * *

* Example import for consumers using the API in this package: *

* {@code Import-Package: org.osgi.framework.launch; version="[1.1,2.0)"} * * @version $Id: f1e5d25386dfcda77fb66659963a62209c4f6d60 $ */ package org.osgi.framework.launch; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/launch/FrameworkFactory.java0000644000175000017500000000567712346513664031053 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2009, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.launch; import java.util.Map; import org.osgi.framework.Bundle; /** * A factory for creating {@link Framework} instances. * *

* A framework implementation jar must contain the following resource: * *

 * /META-INF/services/org.osgi.framework.launch.FrameworkFactory
 * 
* * This UTF-8 encoded resource must contain the name of the framework * implementation's FrameworkFactory implementation class. Space and tab * characters, including blank lines, in the resource must be ignored. The * number sign ({@code '#'} \u0023) and all characters following it on each * line are a comment and must be ignored. * *

* Launchers can find the name of the FrameworkFactory implementation class in * the resource and then load and construct a FrameworkFactory object for the * framework implementation. The FrameworkFactory implementation class must have * a public, no-argument constructor. Java™ SE 6 introduced the * {@code ServiceLoader} class which can create a FrameworkFactory instance from * the resource. * * @ThreadSafe * @noimplement * @version $Id: 1684e14aa98a1f6e1ff3e0f3afa2c55982210f72 $ */ public interface FrameworkFactory { /** * Create a new {@link Framework} instance. * * @param configuration The framework properties to configure the new * framework instance. If framework properties are not provided by * the configuration argument, the created framework instance must * use some reasonable default configuration appropriate for the * current VM. For example, the system packages for the current * execution environment should be properly exported. The specified * configuration argument may be {@code null}. The created framework * instance must copy any information needed from the specified * configuration argument since the configuration argument can be * changed after the framework instance has been created. * @return A new, configured {@link Framework} instance. The framework * instance must be in the {@link Bundle#INSTALLED} state. * @throws SecurityException If the caller does not have * {@code AllPermission}, and the Java Runtime Environment supports * permissions. */ Framework newFramework(Map configuration); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/AllServiceListener.java0000644000175000017500000000515512346513664030042 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2005, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; /** * A {@code ServiceEvent} listener that does not filter based upon package * wiring. {@code AllServiceListener} is a listener interface that may be * implemented by a bundle developer. When a {@code ServiceEvent} is fired, it * is synchronously delivered to an {@code AllServiceListener}. The Framework * may deliver {@code ServiceEvent} objects to an {@code AllServiceListener} out * of order and may concurrently call and/or reenter an * {@code AllServiceListener}. *

* An {@code AllServiceListener} object is registered with the Framework using * the {@code BundleContext.addServiceListener} method. * {@code AllServiceListener} objects are called with a {@code ServiceEvent} * object when a service is registered, modified, or is in the process of * unregistering. * *

* {@code ServiceEvent} object delivery to {@code AllServiceListener} objects is * filtered by the filter specified when the listener was registered. If the * Java Runtime Environment supports permissions, then additional filtering is * done. {@code ServiceEvent} objects are only delivered to the listener if the * bundle which defines the listener object's class has the appropriate * {@code ServicePermission} to get the service using at least one of the named * classes under which the service was registered. * *

* Unlike normal {@code ServiceListener} objects, {@code AllServiceListener} * objects receive all {@code ServiceEvent} objects regardless of whether the * package source of the listening bundle is equal to the package source of the * bundle that registered the service. This means that the listener may not be * able to cast the service object to any of its corresponding service * interfaces if the service object is retrieved. * * @see ServiceEvent * @see ServicePermission * @ThreadSafe * @since 1.3 * @version $Id: 7a0c82db414be7064a06e1868eb41a8c8f8d9d6c $ */ public interface AllServiceListener extends ServiceListener { // This is a marker interface } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/CapabilityPermission.java0000644000175000017500000005615612346513664030444 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.security.AccessController; import java.security.BasicPermission; import java.security.Permission; import java.security.PermissionCollection; import java.security.PrivilegedAction; import java.util.AbstractMap; 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.List; import java.util.Map; import java.util.Set; /** * A bundle's authority to provide or require a capability. *

    *
  • The {@code provide} action allows a bundle to provide a capability * matching the specified filter. *
  • The {@code require} action allows a bundle to require a capability * matching the specified filter. *
* * @ThreadSafe * @version $Id: b17bcaec959f67c3eae4c4c80c39a0a8716b22dc $ * @since 1.6 */ public final class CapabilityPermission extends BasicPermission { static final long serialVersionUID = -7662148639076511574L; /** * The action string {@code require}. */ public final static String REQUIRE = "require"; /** * The action string {@code provide}. */ public final static String PROVIDE = "provide"; private final static int ACTION_REQUIRE = 0x00000001; private final static int ACTION_PROVIDE = 0x00000002; private final static int ACTION_ALL = ACTION_REQUIRE | ACTION_PROVIDE; final static int ACTION_NONE = 0; /** * The actions mask. */ transient int action_mask; /** * The actions in canonical form. * * @serial */ private volatile String actions = null; /** * The attributes of the requested capability. Must be null if not * constructed with attributes. */ transient final Map attributes; /** * The bundle of the requested capability. Must be null if not constructed * with bundle. */ transient final Bundle bundle; /** * If this CapabilityPermission was constructed with a filter, this holds a * Filter matching object used to evaluate the filter in implies. */ transient Filter filter; /** * This map holds the properties of the permission, used to match a filter * in implies. This is not initialized until necessary, and then cached in * this object. */ private transient volatile Map properties; /** * Create a new CapabilityPermission. * *

* The name is specified as a dot-separated string. Wildcards may be used. * *

	 * name ::= <namespace> | <namespace ending in ".*"> | *
	 * 
* * Examples: * *
	 * com.acme.capability.*
	 * org.foo.capability
	 * *
	 * 
* * For the {@code require} action, the name can also be a filter expression. * The filter gives access to the capability attributes as well as the * following attributes: *
    *
  • signer - A Distinguished Name chain used to sign the bundle providing * the capability. Wildcards in a DN are not matched according to the filter * string rules, but according to the rules defined for a DN chain.
  • *
  • location - The location of the bundle providing the capability.
  • *
  • id - The bundle ID of the bundle providing the capability.
  • *
  • name - The symbolic name of the bundle providing the capability.
  • *
  • capability.namespace - The namespace of the required capability.
  • *
* Since the above attribute names may conflict with attribute names of a * capability, you can prefix an attribute name with '@' in the filter * expression to match against the capability attributes and not one of the * above attributes. Filter attribute names are processed in a case * sensitive manner. * *

* There are two possible actions: {@code require} and {@code provide}. The * {@code require} permission allows the owner of this permission to require * a capability matching the attributes. The {@code provide} permission * allows the bundle to provide a capability in the specified capability * namespace. * * @param name The capability namespace or a filter over the attributes. * @param actions {@code require},{@code provide} (canonical order) * @throws IllegalArgumentException If the specified name is a filter * expression and either the specified action is not {@code require} * or the filter has an invalid syntax. */ public CapabilityPermission(String name, String actions) { this(name, parseActions(actions)); if ((this.filter != null) && ((action_mask & ACTION_ALL) != ACTION_REQUIRE)) { throw new IllegalArgumentException("invalid action string for filter expression"); } } /** * Creates a new requested {@code CapabilityPermission} object to be used by * code that must perform {@code checkPermission} for the {@code require} * action. {@code CapabilityPermission} objects created with this * constructor cannot be added to a {@code CapabilityPermission} permission * collection. * * @param namespace The requested capability namespace. * @param attributes The requested capability attributes. * @param providingBundle The bundle providing the requested capability. * @param actions The action {@code require}. * @throws IllegalArgumentException If the specified action is not * {@code require} or attributes or providingBundle are {@code null} * . */ public CapabilityPermission(String namespace, Map attributes, Bundle providingBundle, String actions) { super(namespace); setTransients(namespace, parseActions(actions)); if (attributes == null) { throw new IllegalArgumentException("attributes must not be null"); } if (providingBundle == null) { throw new IllegalArgumentException("bundle must not be null"); } this.attributes = new HashMap(attributes); this.bundle = providingBundle; if ((action_mask & ACTION_ALL) != ACTION_REQUIRE) { throw new IllegalArgumentException("invalid action string"); } } /** * Package private constructor used by CapabilityPermissionCollection. * * @param name class name * @param mask action mask */ CapabilityPermission(String name, int mask) { super(name); setTransients(name, mask); this.attributes = null; this.bundle = null; } /** * Called by constructors and when deserialized. * * @param mask action mask */ private void setTransients(String name, int mask) { if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { throw new IllegalArgumentException("invalid action string"); } action_mask = mask; filter = parseFilter(name); } /** * Parse action string into action mask. * * @param actions Action string. * @return action mask. */ private static int parseActions(String actions) { boolean seencomma = false; int mask = ACTION_NONE; if (actions == null) { return mask; } char[] a = actions.toCharArray(); int i = a.length - 1; if (i < 0) return mask; while (i != -1) { char c; // skip whitespace while ((i != -1) && ((c = a[i]) == ' ' || c == '\r' || c == '\n' || c == '\f' || c == '\t')) i--; // check for the known strings int matchlen; if (i >= 6 && (a[i - 6] == 'r' || a[i - 6] == 'R') && (a[i - 5] == 'e' || a[i - 5] == 'E') && (a[i - 4] == 'q' || a[i - 4] == 'Q') && (a[i - 3] == 'u' || a[i - 3] == 'U') && (a[i - 2] == 'i' || a[i - 2] == 'I') && (a[i - 1] == 'r' || a[i - 1] == 'R') && (a[i] == 'e' || a[i] == 'E')) { matchlen = 7; mask |= ACTION_REQUIRE; } else if (i >= 6 && (a[i - 6] == 'p' || a[i - 6] == 'P') && (a[i - 5] == 'r' || a[i - 5] == 'R') && (a[i - 4] == 'o' || a[i - 4] == 'O') && (a[i - 3] == 'v' || a[i - 3] == 'V') && (a[i - 2] == 'i' || a[i - 2] == 'I') && (a[i - 1] == 'd' || a[i - 1] == 'D') && (a[i] == 'e' || a[i] == 'E')) { matchlen = 7; mask |= ACTION_PROVIDE; } else { // parse error throw new IllegalArgumentException("invalid permission: " + actions); } // make sure we didn't just match the tail of a word // like "ackbarfprovide". Also, skip to the comma. seencomma = false; while (i >= matchlen && !seencomma) { switch (a[i - matchlen]) { case ',' : seencomma = true; /* FALLTHROUGH */ case ' ' : case '\r' : case '\n' : case '\f' : case '\t' : break; default : throw new IllegalArgumentException("invalid permission: " + actions); } i--; } // point i at the location of the comma minus one (or -1). i -= matchlen; } if (seencomma) { throw new IllegalArgumentException("invalid permission: " + actions); } return mask; } /** * Parse filter string into a Filter object. * * @param filterString The filter string to parse. * @return a Filter for this bundle. If the specified filterString is not a * filter expression, then {@code null} is returned. * @throws IllegalArgumentException If the filter syntax is invalid. */ private static Filter parseFilter(String filterString) { filterString = filterString.trim(); if (filterString.charAt(0) != '(') { return null; } try { return FrameworkUtil.createFilter(filterString); } catch (InvalidSyntaxException e) { IllegalArgumentException iae = new IllegalArgumentException("invalid filter"); iae.initCause(e); throw iae; } } /** * Determines if a {@code CapabilityPermission} object "implies" the * specified permission. * * @param p The target permission to check. * @return {@code true} if the specified permission is implied by this * object; {@code false} otherwise. */ public boolean implies(Permission p) { if (!(p instanceof CapabilityPermission)) { return false; } CapabilityPermission requested = (CapabilityPermission) p; if (bundle != null) { return false; } // if requested permission has a filter, then it is an invalid argument if (requested.filter != null) { return false; } return implies0(requested, ACTION_NONE); } /** * Internal implies method. Used by the implies and the permission * collection implies methods. * * @param requested The requested CapabilityPermission which has already be * validated as a proper argument. The requested CapabilityPermission * must not have a filter expression. * @param effective The effective actions with which to start. * @return {@code true} if the specified permission is implied by this * object; {@code false} otherwise. */ boolean implies0(CapabilityPermission requested, int effective) { /* check actions first - much faster */ effective |= action_mask; final int desired = requested.action_mask; if ((effective & desired) != desired) { return false; } /* Get filter if any */ Filter f = filter; if (f == null) { return super.implies(requested); } return f.matches(requested.getProperties()); } /** * Returns the canonical string representation of the actions. Always * returns present actions in the following order: {@code require}, * {@code provide}. * * @return The canonical string representation of the actions. */ public String getActions() { String result = actions; if (result == null) { StringBuffer sb = new StringBuffer(); boolean comma = false; int mask = action_mask; if ((mask & ACTION_REQUIRE) == ACTION_REQUIRE) { sb.append(REQUIRE); comma = true; } if ((mask & ACTION_PROVIDE) == ACTION_PROVIDE) { if (comma) sb.append(','); sb.append(PROVIDE); } actions = result = sb.toString(); } return result; } /** * Returns a new {@code PermissionCollection} object for storing * {@code CapabilityPermission} objects. * * @return A new {@code PermissionCollection} object suitable for storing * {@code CapabilityPermission} objects. */ public PermissionCollection newPermissionCollection() { return new CapabilityPermissionCollection(); } /** * Determines the equality of two CapabilityPermission objects. * * Checks that specified object has the same name and action as this * {@code CapabilityPermission}. * * @param obj The object to test for equality. * @return true if obj is a {@code CapabilityPermission}, and has the same * name and actions as this {@code CapabilityPermission} object; * {@code false} otherwise. */ public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof CapabilityPermission)) { return false; } CapabilityPermission cp = (CapabilityPermission) obj; return (action_mask == cp.action_mask) && getName().equals(cp.getName()) && ((attributes == cp.attributes) || ((attributes != null) && (attributes.equals(cp.attributes)))) && ((bundle == cp.bundle) || ((bundle != null) && bundle.equals(cp.bundle))); } /** * Returns the hash code value for this object. * * @return Hash code value for this object. */ public int hashCode() { int h = 31 * 17 + getName().hashCode(); h = 31 * h + getActions().hashCode(); if (attributes != null) { h = 31 * h + attributes.hashCode(); } if (bundle != null) { h = 31 * h + bundle.hashCode(); } return h; } /** * WriteObject is called to save the state of this permission to a stream. * The actions are serialized, and the superclass takes care of the name. */ private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { if (bundle != null) { throw new NotSerializableException("cannot serialize"); } // Write out the actions. The superclass takes care of the name // call getActions to make sure actions field is initialized if (actions == null) getActions(); s.defaultWriteObject(); } /** * readObject is called to restore the state of this permission from a * stream. */ private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the action, then initialize the rest s.defaultReadObject(); setTransients(getName(), parseActions(actions)); } /** * Called by {@code <@link CapabilityPermission#implies(Permission)>}. This * method is only called on a requested permission which cannot have a * filter set. * * @return a map of properties for this permission. */ private Map getProperties() { Map result = properties; if (result != null) { return result; } final Map props = new HashMap(5); props.put("capability.namespace", getName()); if (bundle == null) { return properties = props; } AccessController.doPrivileged(new PrivilegedAction() { public Object run() { props.put("id", new Long(bundle.getBundleId())); props.put("location", bundle.getLocation()); String name = bundle.getSymbolicName(); if (name != null) { props.put("name", name); } SignerProperty signer = new SignerProperty(bundle); if (signer.isBundleSigned()) { props.put("signer", signer); } return null; } }); return properties = new Properties(props, attributes); } static private final class Properties extends AbstractMap { private final Map properties; private final Map attributes; private transient volatile Set> entries; Properties(Map properties, Map attributes) { this.properties = properties; this.attributes = attributes; entries = null; } public Object get(Object k) { if (!(k instanceof String)) { return null; } String key = (String) k; if (key.charAt(0) == '@') { return attributes.get(key.substring(1)); } Object value = properties.get(key); if (value != null) { // fall back to service properties return value; } return attributes.get(key); } public Set> entrySet() { if (entries != null) { return entries; } Set> all = new HashSet>(attributes.size() + properties.size()); all.addAll(attributes.entrySet()); all.addAll(properties.entrySet()); return entries = Collections.unmodifiableSet(all); } } } /** * Stores a set of CapabilityPermission permissions. * * @see java.security.Permission * @see java.security.Permissions * @see java.security.PermissionCollection */ final class CapabilityPermissionCollection extends PermissionCollection { static final long serialVersionUID = -615322242639008920L; /** * Table of permissions. * * @serial * @GuardedBy this */ private Map permissions; /** * Boolean saying if "*" is in the collection. * * @serial * @GuardedBy this */ private boolean all_allowed; /** * Table of permissions with filter expressions. * * @serial * @GuardedBy this */ private Map filterPermissions; /** * Creates an empty CapabilityPermissionCollection object. */ public CapabilityPermissionCollection() { permissions = new HashMap(); all_allowed = false; } /** * Adds a permission to this permission collection. * * @param permission The Permission object to add. * @throws IllegalArgumentException If the specified permission is not a * CapabilityPermission object. * @throws SecurityException If this {@code CapabilityPermissionCollection} * object has been marked read-only. */ public void add(final Permission permission) { if (!(permission instanceof CapabilityPermission)) { throw new IllegalArgumentException("invalid permission: " + permission); } if (isReadOnly()) { throw new SecurityException("attempt to add a Permission to a " + "readonly PermissionCollection"); } final CapabilityPermission cp = (CapabilityPermission) permission; if (cp.bundle != null) { throw new IllegalArgumentException("cannot add to collection: " + cp); } final String name = cp.getName(); final Filter f = cp.filter; synchronized (this) { /* select the bucket for the permission */ Map pc; if (f != null) { pc = filterPermissions; if (pc == null) { filterPermissions = pc = new HashMap(); } } else { pc = permissions; } final CapabilityPermission existing = pc.get(name); if (existing != null) { final int oldMask = existing.action_mask; final int newMask = cp.action_mask; if (oldMask != newMask) { pc.put(name, new CapabilityPermission(name, oldMask | newMask)); } } else { pc.put(name, cp); } if (!all_allowed) { if (name.equals("*")) { all_allowed = true; } } } } /** * Determines if a set of permissions implies the permissions expressed in * {@code permission}. * * @param permission The Permission object to compare. * @return {@code true} if {@code permission} is a proper subset of a * permission in the set; {@code false} otherwise. */ public boolean implies(final Permission permission) { if (!(permission instanceof CapabilityPermission)) { return false; } final CapabilityPermission requested = (CapabilityPermission) permission; /* if requested permission has a filter, then it is an invalid argument */ if (requested.filter != null) { return false; } String requestedName = requested.getName(); final int desired = requested.action_mask; int effective = CapabilityPermission.ACTION_NONE; Collection perms; synchronized (this) { Map pc = permissions; CapabilityPermission cp; /* short circuit if the "*" Permission was added */ if (all_allowed) { cp = pc.get("*"); if (cp != null) { effective |= cp.action_mask; if ((effective & desired) == desired) { return true; } } } /* * strategy: Check for full match first. Then work our way up the * name looking for matches on a.b.* */ cp = pc.get(requestedName); if (cp != null) { /* we have a direct hit! */ effective |= cp.action_mask; if ((effective & desired) == desired) { return true; } } /* work our way up the tree... */ int last; int offset = requestedName.length() - 1; while ((last = requestedName.lastIndexOf(".", offset)) != -1) { requestedName = requestedName.substring(0, last + 1) + "*"; cp = pc.get(requestedName); if (cp != null) { effective |= cp.action_mask; if ((effective & desired) == desired) { return true; } } offset = last - 1; } /* * we don't have to check for "*" as it was already checked before * we were called. */ pc = filterPermissions; if (pc == null) { return false; } perms = pc.values(); } /* iterate one by one over filteredPermissions */ for (CapabilityPermission perm : perms) { if (perm.implies0(requested, effective)) { return true; } } return false; } /** * Returns an enumeration of all the {@code CapabilityPermission} objects in * the container. * * @return Enumeration of all the CapabilityPermission objects. */ public synchronized Enumeration elements() { List all = new ArrayList(permissions.values()); Map pc = filterPermissions; if (pc != null) { all.addAll(pc.values()); } return Collections.enumeration(all); } /* serialization logic */ private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("permissions", HashMap.class), new ObjectStreamField("all_allowed", Boolean.TYPE), new ObjectStreamField("filterPermissions", HashMap.class) }; private synchronized void writeObject(ObjectOutputStream out) throws IOException { ObjectOutputStream.PutField pfields = out.putFields(); pfields.put("permissions", permissions); pfields.put("all_allowed", all_allowed); pfields.put("filterPermissions", filterPermissions); out.writeFields(); } private synchronized void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gfields = in.readFields(); HashMap p = (HashMap) gfields.get("permissions", null); permissions = p; all_allowed = gfields.get("all_allowed", false); HashMap fp = (HashMap) gfields.get("filterPermissions", null); filterPermissions = fp; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/Version.java0000644000175000017500000002607012346513664025727 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2004, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.util.NoSuchElementException; import java.util.StringTokenizer; /** * Version identifier for capabilities such as bundles and packages. * *

* Version identifiers have four components. *

    *
  1. Major version. A non-negative integer.
  2. *
  3. Minor version. A non-negative integer.
  4. *
  5. Micro version. A non-negative integer.
  6. *
  7. Qualifier. A text string. See {@code Version(String)} for the format of * the qualifier string.
  8. *
* *

* {@code Version} objects are immutable. * * @since 1.3 * @Immutable * @version $Id: a0b5a865f7fbf2b3dcb77a13b2e99da0b64702bb $ */ public class Version implements Comparable { private final int major; private final int minor; private final int micro; private final String qualifier; private static final String SEPARATOR = "."; private transient String versionString /* default to null */; private transient int hash /* default to 0 */; /** * The empty version "0.0.0". */ public static final Version emptyVersion = new Version(0, 0, 0); /** * Creates a version identifier from the specified numerical components. * *

* The qualifier is set to the empty string. * * @param major Major component of the version identifier. * @param minor Minor component of the version identifier. * @param micro Micro component of the version identifier. * @throws IllegalArgumentException If the numerical components are * negative. */ public Version(int major, int minor, int micro) { this(major, minor, micro, null); } /** * Creates a version identifier from the specified components. * * @param major Major component of the version identifier. * @param minor Minor component of the version identifier. * @param micro Micro component of the version identifier. * @param qualifier Qualifier component of the version identifier. If * {@code null} is specified, then the qualifier will be set to the * empty string. * @throws IllegalArgumentException If the numerical components are negative * or the qualifier string is invalid. */ public Version(int major, int minor, int micro, String qualifier) { if (qualifier == null) { qualifier = ""; } this.major = major; this.minor = minor; this.micro = micro; this.qualifier = qualifier; validate(); } /** * Creates a version identifier from the specified string. * *

* Version string grammar: * *

	 * version ::= major('.'minor('.'micro('.'qualifier)?)?)?
	 * major ::= digit+
	 * minor ::= digit+
	 * micro ::= digit+
	 * qualifier ::= (alpha|digit|'_'|'-')+
	 * digit ::= [0..9]
	 * alpha ::= [a..zA..Z]
	 * 
* * @param version String representation of the version identifier. There * must be no whitespace in the argument. * @throws IllegalArgumentException If {@code version} is improperly * formatted. */ public Version(String version) { int maj = 0; int min = 0; int mic = 0; String qual = ""; try { StringTokenizer st = new StringTokenizer(version, SEPARATOR, true); maj = parseInt(st.nextToken(), version); if (st.hasMoreTokens()) { // minor st.nextToken(); // consume delimiter min = parseInt(st.nextToken(), version); if (st.hasMoreTokens()) { // micro st.nextToken(); // consume delimiter mic = parseInt(st.nextToken(), version); if (st.hasMoreTokens()) { // qualifier separator st.nextToken(); // consume delimiter qual = st.nextToken(""); // remaining string if (st.hasMoreTokens()) { // fail safe throw new IllegalArgumentException("invalid version \"" + version + "\": invalid format"); } } } } } catch (NoSuchElementException e) { IllegalArgumentException iae = new IllegalArgumentException("invalid version \"" + version + "\": invalid format"); iae.initCause(e); throw iae; } major = maj; minor = min; micro = mic; qualifier = qual; validate(); } /** * Parse numeric component into an int. * * @param value Numeric component * @param version Complete version string for exception message, if any * @return int value of numeric component */ private static int parseInt(String value, String version) { try { return Integer.parseInt(value); } catch (NumberFormatException e) { IllegalArgumentException iae = new IllegalArgumentException("invalid version \"" + version + "\": non-numeric \"" + value + "\""); iae.initCause(e); throw iae; } } /** * Called by the Version constructors to validate the version components. * * @throws IllegalArgumentException If the numerical components are negative * or the qualifier string is invalid. */ private void validate() { if (major < 0) { throw new IllegalArgumentException("invalid version \"" + toString0() + "\": negative number \"" + major + "\""); } if (minor < 0) { throw new IllegalArgumentException("invalid version \"" + toString0() + "\": negative number \"" + minor + "\""); } if (micro < 0) { throw new IllegalArgumentException("invalid version \"" + toString0() + "\": negative number \"" + micro + "\""); } for (char ch : qualifier.toCharArray()) { if (('A' <= ch) && (ch <= 'Z')) { continue; } if (('a' <= ch) && (ch <= 'z')) { continue; } if (('0' <= ch) && (ch <= '9')) { continue; } if ((ch == '_') || (ch == '-')) { continue; } throw new IllegalArgumentException("invalid version \"" + toString0() + "\": invalid qualifier \"" + qualifier + "\""); } } /** * Parses a version identifier from the specified string. * *

* See {@code Version(String)} for the format of the version string. * * @param version String representation of the version identifier. Leading * and trailing whitespace will be ignored. * @return A {@code Version} object representing the version identifier. If * {@code version} is {@code null} or the empty string then * {@code emptyVersion} will be returned. * @throws IllegalArgumentException If {@code version} is improperly * formatted. */ public static Version parseVersion(String version) { if (version == null) { return emptyVersion; } version = version.trim(); if (version.length() == 0) { return emptyVersion; } return new Version(version); } /** * Returns the major component of this version identifier. * * @return The major component. */ public int getMajor() { return major; } /** * Returns the minor component of this version identifier. * * @return The minor component. */ public int getMinor() { return minor; } /** * Returns the micro component of this version identifier. * * @return The micro component. */ public int getMicro() { return micro; } /** * Returns the qualifier component of this version identifier. * * @return The qualifier component. */ public String getQualifier() { return qualifier; } /** * Returns the string representation of this version identifier. * *

* The format of the version string will be {@code major.minor.micro} if * qualifier is the empty string or {@code major.minor.micro.qualifier} * otherwise. * * @return The string representation of this version identifier. */ public String toString() { return toString0(); } /** * Internal toString behavior * * @return The string representation of this version identifier. */ String toString0() { if (versionString != null) { return versionString; } int q = qualifier.length(); StringBuffer result = new StringBuffer(20 + q); result.append(major); result.append(SEPARATOR); result.append(minor); result.append(SEPARATOR); result.append(micro); if (q > 0) { result.append(SEPARATOR); result.append(qualifier); } return versionString = result.toString(); } /** * Returns a hash code value for the object. * * @return An integer which is a hash code value for this object. */ public int hashCode() { if (hash != 0) { return hash; } int h = 31 * 17; h = 31 * h + major; h = 31 * h + minor; h = 31 * h + micro; h = 31 * h + qualifier.hashCode(); return hash = h; } /** * Compares this {@code Version} object to another object. * *

* A version is considered to be equal to another version if the * major, minor and micro components are equal and the qualifier component * is equal (using {@code String.equals}). * * @param object The {@code Version} object to be compared. * @return {@code true} if {@code object} is a {@code Version} and is equal * to this object; {@code false} otherwise. */ public boolean equals(Object object) { if (object == this) { // quicktest return true; } if (!(object instanceof Version)) { return false; } Version other = (Version) object; return (major == other.major) && (minor == other.minor) && (micro == other.micro) && qualifier.equals(other.qualifier); } /** * Compares this {@code Version} object to another {@code Version}. * *

* A version is considered to be less than another version if its * major component is less than the other version's major component, or the * major components are equal and its minor component is less than the other * version's minor component, or the major and minor components are equal * and its micro component is less than the other version's micro component, * or the major, minor and micro components are equal and it's qualifier * component is less than the other version's qualifier component (using * {@code String.compareTo}). * *

* A version is considered to be equal to another version if the * major, minor and micro components are equal and the qualifier component * is equal (using {@code String.compareTo}). * * @param other The {@code Version} object to be compared. * @return A negative integer, zero, or a positive integer if this version * is less than, equal to, or greater than the specified * {@code Version} object. * @throws ClassCastException If the specified object is not a * {@code Version} object. */ public int compareTo(Version other) { if (other == this) { // quicktest return 0; } int result = major - other.major; if (result != 0) { return result; } result = minor - other.minor; if (result != 0) { return result; } result = micro - other.micro; if (result != 0) { return result; } return qualifier.compareTo(other.qualifier); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/SynchronousBundleListener.java0000644000175000017500000000560212346513664031472 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2001, 2011). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; /** * A synchronous {@code BundleEvent} listener. {@code SynchronousBundleListener} * is a listener interface that may be implemented by a bundle developer. When a * {@code BundleEvent} is fired, it is synchronously delivered to a * {@code SynchronousBundleListener}. The Framework may deliver * {@code BundleEvent} objects to a {@code SynchronousBundleListener} out of * order and may concurrently call and/or reenter a * {@code SynchronousBundleListener}. * *

* For {@code BundleEvent} types {@link BundleEvent#STARTED STARTED} and * {@link BundleEvent#LAZY_ACTIVATION LAZY_ACTIVATION}, the Framework must not * hold the referenced bundle's "state change" lock when the * {@code BundleEvent} is delivered to a {@code SynchronousBundleListener}. For * the other {@code BundleEvent} types, the Framework must hold the referenced * bundle's "state change" lock when the {@code BundleEvent} is * delivered to a {@code SynchronousBundleListener}. A * {@code SynchronousBundleListener} cannot directly call life cycle methods on * the referenced bundle when the Framework is holding the referenced bundle's * "state change" lock. * *

* A {@code SynchronousBundleListener} object is registered with the Framework * using the {@link BundleContext#addBundleListener(BundleListener)} method. * {@code SynchronousBundleListener} objects are called with a * {@code BundleEvent} object when a bundle has been installed, resolved, * starting, started, stopping, stopped, updated, unresolved, or uninstalled. *

* Unlike normal {@code BundleListener} objects, * {@code SynchronousBundleListener}s are synchronously called during bundle * lifecycle processing. The bundle lifecycle processing will not proceed until * all {@code SynchronousBundleListener}s have completed. * {@code SynchronousBundleListener} objects will be called prior to * {@code BundleListener} objects. *

* {@code AdminPermission[bundle,LISTENER]} is required to add or remove a * {@code SynchronousBundleListener} object. * * @since 1.1 * @see BundleEvent * @ThreadSafe * @version $Id: 74246f4ceeba7f9a5ee198048522f93d4691c51a $ */ public interface SynchronousBundleListener extends BundleListener { // This is a marker interface } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/package-info.java0000644000175000017500000000203112346513664026615 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Framework Package Version 1.7. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. * *

* Example import for consumers using the API in this package: *

* {@code Import-Package: org.osgi.framework; version="[1.7,2.0)"} * * @version $Id: a11d8e2964dacf128f21fef1e72f8cbaf0ce0ab3 $ */ package org.osgi.framework; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/BundleReference.java0000644000175000017500000000206012346513664027323 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2009, 2010). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; /** * A reference to a Bundle. * * @since 1.5 * @ThreadSafe * @noimplement * @version $Id: e61bd3e020264b04022a430fe09a85ee3aabf1a3 $ */ public interface BundleReference { /** * Returns the {@code Bundle} object associated with this * {@code BundleReference}. * * @return The {@code Bundle} object associated with this * {@code BundleReference}. */ public Bundle getBundle(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/BundlePermission.java0000644000175000017500000004163012346513664027563 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2004, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.security.BasicPermission; import java.security.Permission; import java.security.PermissionCollection; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; /** * A bundle's authority to require or provide a bundle or to receive or attach * fragments. * *

* A bundle symbolic name defines a unique fully qualified name. Wildcards may * be used. * *

 * name ::= <symbolic name> | <symbolic name ending in ".*"> | *
 * 
* * Examples: * *
 * org.osgi.example.bundle
 * org.osgi.example.*
 * *
 * 
* *

* {@code BundlePermission} has four actions: {@code provide}, {@code require}, * {@code host}, and {@code fragment}. The {@code provide} action implies the * {@code require} action. * * @since 1.3 * @ThreadSafe * @version $Id: ccba905e3373800dfdb080118e97145abf778da2 $ */ public final class BundlePermission extends BasicPermission { private static final long serialVersionUID = 3257846601685873716L; /** * The action string {@code provide}. The {@code provide} action implies the * {@code require} action. */ public final static String PROVIDE = "provide"; /** * The action string {@code require}. The {@code require} action is implied * by the {@code provide} action. */ public final static String REQUIRE = "require"; /** * The action string {@code host}. */ public final static String HOST = "host"; /** * The action string {@code fragment}. */ public final static String FRAGMENT = "fragment"; private final static int ACTION_PROVIDE = 0x00000001; private final static int ACTION_REQUIRE = 0x00000002; private final static int ACTION_HOST = 0x00000004; private final static int ACTION_FRAGMENT = 0x00000008; private final static int ACTION_ALL = ACTION_PROVIDE | ACTION_REQUIRE | ACTION_HOST | ACTION_FRAGMENT; final static int ACTION_NONE = 0; /** * The actions mask. */ private transient int action_mask; /** * The actions in canonical form. * * @serial */ private volatile String actions = null; /** * Defines the authority to provide and/or require and or specify a host * fragment symbolic name within the OSGi environment. *

* Bundle Permissions are granted over all possible versions of a bundle. * * A bundle that needs to provide a bundle must have the appropriate * {@code BundlePermission} for the symbolic name; a bundle that requires a * bundle must have the appropriate {@code BundlePermssion} for that * symbolic name; a bundle that specifies a fragment host must have the * appropriate {@code BundlePermission} for that symbolic name. * * @param symbolicName The bundle symbolic name. * @param actions {@code provide},{@code require}, {@code host}, * {@code fragment} (canonical order). */ public BundlePermission(String symbolicName, String actions) { this(symbolicName, parseActions(actions)); } /** * Package private constructor used by BundlePermissionCollection. * * @param symbolicName the bundle symbolic name * @param mask the action mask */ BundlePermission(String symbolicName, int mask) { super(symbolicName); setTransients(mask); } /** * Called by constructors and when deserialized. * * @param mask */ private synchronized void setTransients(int mask) { if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { throw new IllegalArgumentException("invalid action string"); } action_mask = mask; } /** * Returns the current action mask. *

* Used by the BundlePermissionCollection class. * * @return Current action mask. */ synchronized int getActionsMask() { return action_mask; } /** * Parse action string into action mask. * * @param actions Action string. * @return action mask. */ private static int parseActions(String actions) { boolean seencomma = false; int mask = ACTION_NONE; if (actions == null) { return mask; } char[] a = actions.toCharArray(); int i = a.length - 1; if (i < 0) return mask; while (i != -1) { char c; // skip whitespace while ((i != -1) && ((c = a[i]) == ' ' || c == '\r' || c == '\n' || c == '\f' || c == '\t')) i--; // check for the known strings int matchlen; if (i >= 6 && (a[i - 6] == 'p' || a[i - 6] == 'P') && (a[i - 5] == 'r' || a[i - 5] == 'R') && (a[i - 4] == 'o' || a[i - 4] == 'O') && (a[i - 3] == 'v' || a[i - 3] == 'V') && (a[i - 2] == 'i' || a[i - 2] == 'I') && (a[i - 1] == 'd' || a[i - 1] == 'D') && (a[i] == 'e' || a[i] == 'E')) { matchlen = 7; mask |= ACTION_PROVIDE | ACTION_REQUIRE; } else if (i >= 6 && (a[i - 6] == 'r' || a[i - 6] == 'R') && (a[i - 5] == 'e' || a[i - 5] == 'E') && (a[i - 4] == 'q' || a[i - 4] == 'Q') && (a[i - 3] == 'u' || a[i - 3] == 'U') && (a[i - 2] == 'i' || a[i - 2] == 'I') && (a[i - 1] == 'r' || a[i - 1] == 'R') && (a[i] == 'e' || a[i] == 'E')) { matchlen = 7; mask |= ACTION_REQUIRE; } else if (i >= 3 && (a[i - 3] == 'h' || a[i - 3] == 'H') && (a[i - 2] == 'o' || a[i - 2] == 'O') && (a[i - 1] == 's' || a[i - 1] == 'S') && (a[i] == 't' || a[i] == 'T')) { matchlen = 4; mask |= ACTION_HOST; } else if (i >= 7 && (a[i - 7] == 'f' || a[i - 7] == 'F') && (a[i - 6] == 'r' || a[i - 6] == 'R') && (a[i - 5] == 'a' || a[i - 5] == 'A') && (a[i - 4] == 'g' || a[i - 4] == 'G') && (a[i - 3] == 'm' || a[i - 3] == 'M') && (a[i - 2] == 'e' || a[i - 2] == 'E') && (a[i - 1] == 'n' || a[i - 1] == 'N') && (a[i] == 't' || a[i] == 'T')) { matchlen = 8; mask |= ACTION_FRAGMENT; } else { // parse error throw new IllegalArgumentException("invalid permission: " + actions); } // make sure we didn't just match the tail of a word // like "ackbarfrequire". Also, skip to the comma. seencomma = false; while (i >= matchlen && !seencomma) { switch (a[i - matchlen]) { case ',' : seencomma = true; /* FALLTHROUGH */ case ' ' : case '\r' : case '\n' : case '\f' : case '\t' : break; default : throw new IllegalArgumentException("invalid permission: " + actions); } i--; } // point i at the location of the comma minus one (or -1). i -= matchlen; } if (seencomma) { throw new IllegalArgumentException("invalid permission: " + actions); } return mask; } /** * Determines if the specified permission is implied by this object. * *

* This method checks that the symbolic name of the target is implied by the * symbolic name of this object. The list of {@code BundlePermission} * actions must either match or allow for the list of the target object to * imply the target {@code BundlePermission} action. *

* The permission to provide a bundle implies the permission to require the * named symbolic name. * *

	 *       x.y.*,"provide" -> x.y.z,"provide" is true
	 *       *,"require" -> x.y, "require"      is true
	 *       *,"provide" -> x.y, "require"      is true
	 *       x.y,"provide" -> x.y.z, "provide"  is false
	 * 
* * @param p The requested permission. * @return {@code true} if the specified {@code BundlePermission} action is * implied by this object; {@code false} otherwise. */ public boolean implies(Permission p) { if (!(p instanceof BundlePermission)) { return false; } BundlePermission requested = (BundlePermission) p; final int effective = getActionsMask(); final int desired = requested.getActionsMask(); return ((effective & desired) == desired) && super.implies(requested); } /** * Returns the canonical string representation of the * {@code BundlePermission} actions. * *

* Always returns present {@code BundlePermission} actions in the following * order: {@code provide}, {@code require}, {@code host}, {@code fragment}. * * @return Canonical string representation of the {@code BundlePermission * } actions. */ public String getActions() { String result = actions; if (result == null) { StringBuffer sb = new StringBuffer(); boolean comma = false; if ((action_mask & ACTION_PROVIDE) == ACTION_PROVIDE) { sb.append(PROVIDE); comma = true; } if ((action_mask & ACTION_REQUIRE) == ACTION_REQUIRE) { if (comma) sb.append(','); sb.append(REQUIRE); comma = true; } if ((action_mask & ACTION_HOST) == ACTION_HOST) { if (comma) sb.append(','); sb.append(HOST); comma = true; } if ((action_mask & ACTION_FRAGMENT) == ACTION_FRAGMENT) { if (comma) sb.append(','); sb.append(FRAGMENT); } actions = result = sb.toString(); } return result; } /** * Returns a new {@code PermissionCollection} object suitable for storing * {@code BundlePermission} objects. * * @return A new {@code PermissionCollection} object. */ public PermissionCollection newPermissionCollection() { return new BundlePermissionCollection(); } /** * Determines the equality of two {@code BundlePermission} objects. * * This method checks that specified bundle has the same bundle symbolic * name and {@code BundlePermission} actions as this * {@code BundlePermission} object. * * @param obj The object to test for equality with this * {@code BundlePermission} object. * @return {@code true} if {@code obj} is a {@code BundlePermission}, and * has the same bundle symbolic name and actions as this * {@code BundlePermission} object; {@code false} otherwise. */ public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof BundlePermission)) { return false; } BundlePermission bp = (BundlePermission) obj; return (getActionsMask() == bp.getActionsMask()) && getName().equals(bp.getName()); } /** * Returns the hash code value for this object. * * @return A hash code value for this object. */ public int hashCode() { int h = 31 * 17 + getName().hashCode(); h = 31 * h + getActions().hashCode(); return h; } /** * WriteObject is called to save the state of the {@code BundlePermission} * object to a stream. The actions are serialized, and the superclass takes * care of the name. */ private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { // Write out the actions. The superclass takes care of the name // call getActions to make sure actions field is initialized if (actions == null) getActions(); s.defaultWriteObject(); } /** * readObject is called to restore the state of the BundlePermission from a * stream. */ private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the action, then initialize the rest s.defaultReadObject(); setTransients(parseActions(actions)); } } /** * Stores a set of {@code BundlePermission} permissions. * * @see java.security.Permission * @see java.security.Permissions * @see java.security.PermissionCollection */ final class BundlePermissionCollection extends PermissionCollection { private static final long serialVersionUID = 3258407326846433079L; /** * Table of permissions. * * @GuardedBy this */ private transient Map permissions; /** * Boolean saying if "*" is in the collection. * * @serial * @GuardedBy this */ private boolean all_allowed; /** * Create an empty BundlePermissions object. * */ public BundlePermissionCollection() { permissions = new HashMap(); all_allowed = false; } /** * Add a permission to this permission collection. * * @param permission The {@code BundlePermission} object to add. * @throws IllegalArgumentException If the permission is not a * {@code BundlePermission} instance. * @throws SecurityException If this {@code BundlePermissionCollection} * object has been marked read-only. */ public void add(final Permission permission) { if (!(permission instanceof BundlePermission)) { throw new IllegalArgumentException("invalid permission: " + permission); } if (isReadOnly()) { throw new SecurityException("attempt to add a Permission to a " + "readonly PermissionCollection"); } final BundlePermission bp = (BundlePermission) permission; final String name = bp.getName(); synchronized (this) { Map pc = permissions; BundlePermission existing = pc.get(name); if (existing != null) { final int oldMask = existing.getActionsMask(); final int newMask = bp.getActionsMask(); if (oldMask != newMask) { pc.put(name, new BundlePermission(name, oldMask | newMask)); } } else { pc.put(name, bp); } if (!all_allowed) { if (name.equals("*")) all_allowed = true; } } } /** * Determines if the specified permissions implies the permissions expressed * in {@code permission}. * * @param permission The Permission object to compare with this * {@code BundlePermission} object. * @return {@code true} if {@code permission} is a proper subset of a * permission in the set; {@code false} otherwise. */ public boolean implies(final Permission permission) { if (!(permission instanceof BundlePermission)) { return false; } BundlePermission requested = (BundlePermission) permission; String requestedName = requested.getName(); final int desired = requested.getActionsMask(); int effective = BundlePermission.ACTION_NONE; BundlePermission bp; synchronized (this) { Map pc = permissions; /* short circuit if the "*" Permission was added */ if (all_allowed) { bp = pc.get("*"); if (bp != null) { effective |= bp.getActionsMask(); if ((effective & desired) == desired) { return true; } } } bp = pc.get(requestedName); // strategy: // Check for full match first. Then work our way up the // name looking for matches on a.b.* if (bp != null) { // we have a direct hit! effective |= bp.getActionsMask(); if ((effective & desired) == desired) { return true; } } // work our way up the tree... int last; int offset = requestedName.length() - 1; while ((last = requestedName.lastIndexOf(".", offset)) != -1) { requestedName = requestedName.substring(0, last + 1) + "*"; bp = pc.get(requestedName); if (bp != null) { effective |= bp.getActionsMask(); if ((effective & desired) == desired) { return true; } } offset = last - 1; } // we don't have to check for "*" as it was already checked // at the top (all_allowed), so we just return false return false; } } /** * Returns an enumeration of all {@code BundlePermission} objects in the * container. * * @return Enumeration of all {@code BundlePermission} objects. */ public synchronized Enumeration elements() { List all = new ArrayList(permissions.values()); return Collections.enumeration(all); } /* serialization logic */ private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("permissions", Hashtable.class), new ObjectStreamField("all_allowed", Boolean.TYPE)}; private synchronized void writeObject(ObjectOutputStream out) throws IOException { Hashtable hashtable = new Hashtable(permissions); ObjectOutputStream.PutField pfields = out.putFields(); pfields.put("permissions", hashtable); pfields.put("all_allowed", all_allowed); out.writeFields(); } private synchronized void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gfields = in.readFields(); Hashtable hashtable = (Hashtable) gfields.get("permissions", null); permissions = new HashMap(hashtable); all_allowed = gfields.get("all_allowed", false); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/BundleException.java0000644000175000017500000001363312346513664027373 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; /** * A Framework exception used to indicate that a bundle lifecycle problem * occurred. * *

* A {@code BundleException} object is created by the Framework to denote an * exception condition in the lifecycle of a bundle. {@code BundleException}s * should not be created by bundle developers. A type code is used to identify * the exception type for future extendability. * *

* OSGi Alliance reserves the right to extend the set of types. * *

* This exception conforms to the general purpose exception chaining mechanism. * * @version $Id: 0c97ed2696b4576d61440020922b1a97545beb1e $ */ public class BundleException extends Exception { static final long serialVersionUID = 3571095144220455665L; /** * Type of bundle exception. * * @since 1.5 */ private final int type; /** * No exception type is specified. * * @since 1.5 */ public static final int UNSPECIFIED = 0; /** * The operation was unsupported. This type can be used anywhere a * BundleException can be thrown. * * @since 1.5 */ public static final int UNSUPPORTED_OPERATION = 1; /** * The operation was invalid. * * @since 1.5 */ public static final int INVALID_OPERATION = 2; /** * The bundle manifest was in error. * * @since 1.5 */ public static final int MANIFEST_ERROR = 3; /** * The bundle was not resolved. * * @since 1.5 */ public static final int RESOLVE_ERROR = 4; /** * The bundle activator was in error. * * @since 1.5 */ public static final int ACTIVATOR_ERROR = 5; /** * The operation failed due to insufficient permissions. * * @since 1.5 */ public static final int SECURITY_ERROR = 6; /** * The operation failed to complete the requested lifecycle state change. * * @since 1.5 */ public static final int STATECHANGE_ERROR = 7; /** * The bundle could not be resolved due to an error with the * Bundle-NativeCode header. * * @since 1.5 */ public static final int NATIVECODE_ERROR = 8; /** * The install or update operation failed because another already installed * bundle has the same symbolic name and version. This exception type will * only occur if the framework is configured to only allow a single bundle * to be installed for a given symbolic name and version. * * @see Constants#FRAMEWORK_BSNVERSION * @since 1.5 */ public static final int DUPLICATE_BUNDLE_ERROR = 9; /** * The start transient operation failed because the start level of the * bundle is greater than the current framework start level * * @since 1.5 */ public static final int START_TRANSIENT_ERROR = 10; /** * The framework received an error while reading the input stream for a * bundle. * * @since 1.6 */ public static final int READ_ERROR = 11; /** * A framework hook rejected the operation. * * @since 1.6 */ public static final int REJECTED_BY_HOOK = 12; /** * Creates a {@code BundleException} with the specified message and * exception cause. * * @param msg The associated message. * @param cause The cause of this exception. */ public BundleException(String msg, Throwable cause) { this(msg, UNSPECIFIED, cause); } /** * Creates a {@code BundleException} with the specified message. * * @param msg The message. */ public BundleException(String msg) { this(msg, UNSPECIFIED); } /** * Creates a {@code BundleException} with the specified message, type and * exception cause. * * @param msg The associated message. * @param type The type for this exception. * @param cause The cause of this exception. * @since 1.5 */ public BundleException(String msg, int type, Throwable cause) { super(msg, cause); this.type = type; } /** * Creates a {@code BundleException} with the specified message and type. * * @param msg The message. * @param type The type for this exception. * @since 1.5 */ public BundleException(String msg, int type) { super(msg); this.type = type; } /** * Returns the cause of this exception or {@code null} if no cause was * specified when this exception was created. * *

* This method predates the general purpose exception chaining mechanism. * The {@code getCause()} method is now the preferred means of obtaining * this information. * * @return The result of calling {@code getCause()}. */ public Throwable getNestedException() { return getCause(); } /** * Returns the cause of this exception or {@code null} if no cause was set. * * @return The cause of this exception or {@code null} if no cause was set. * @since 1.3 */ public Throwable getCause() { return super.getCause(); } /** * Initializes the cause of this exception to the specified value. * * @param cause The cause of this exception. * @return This exception. * @throws IllegalArgumentException If the specified cause is this * exception. * @throws IllegalStateException If the cause of this exception has already * been set. * @since 1.3 */ public Throwable initCause(Throwable cause) { return super.initCause(cause); } /** * Returns the type for this exception or {@code UNSPECIFIED} if the type * was unspecified or unknown. * * @return The type of this exception. * @since 1.5 */ public int getType() { return type; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/ServicePermission.java0000644000175000017500000006507012346513664027756 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.security.AccessController; import java.security.BasicPermission; import java.security.Permission; import java.security.PermissionCollection; import java.security.PrivilegedAction; import java.util.AbstractMap; 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.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; /** * A bundle's authority to register or get a service. *

    *
  • The {@code register} action allows a bundle to register a service on the * specified names. *
  • The {@code get} action allows a bundle to detect a service and get it. *
* Permission to get a service is required in order to detect events regarding * the service. Untrusted bundles should not be able to detect the presence of * certain services unless they have the appropriate {@code ServicePermission} * to get the specific service. * * @ThreadSafe * @version $Id: 96438ad164d7f0f4273787226298bf8208cf0034 $ */ public final class ServicePermission extends BasicPermission { static final long serialVersionUID = -7662148639076511574L; /** * The action string {@code get}. */ public final static String GET = "get"; /** * The action string {@code register}. */ public final static String REGISTER = "register"; private final static int ACTION_GET = 0x00000001; private final static int ACTION_REGISTER = 0x00000002; private final static int ACTION_ALL = ACTION_GET | ACTION_REGISTER; final static int ACTION_NONE = 0; /** * The actions mask. */ transient int action_mask; /** * The actions in canonical form. * * @serial */ private volatile String actions = null; /** * The service used by this ServicePermission. Must be null if not * constructed with a service. */ transient final ServiceReference service; /** * The object classes for this ServicePermission. Must be null if not * constructed with a service. */ transient final String[] objectClass; /** * If this ServicePermission was constructed with a filter, this holds a * Filter matching object used to evaluate the filter in implies. */ transient Filter filter; /** * This map holds the properties of the permission, used to match a filter * in implies. This is not initialized until necessary, and then cached in * this object. */ private transient volatile Map properties; /** * True if constructed with a name and the name is "*" or ends with ".*". */ private transient boolean wildcard; /** * If constructed with a name and the name ends with ".*", this contains the * name without the final "*". */ private transient String prefix; /** * Create a new ServicePermission. * *

* The name of the service is specified as a fully qualified class name. * Wildcards may be used. * *

	 * name ::= <class name> | <class name ending in ".*"> | *
	 * 
* * Examples: * *
	 * org.osgi.service.http.HttpService
	 * org.osgi.service.http.*
	 * *
	 * 
* * For the {@code get} action, the name can also be a filter expression. The * filter gives access to the service properties as well as the following * attributes: *
    *
  • signer - A Distinguished Name chain used to sign the bundle * publishing the service. Wildcards in a DN are not matched according to * the filter string rules, but according to the rules defined for a DN * chain.
  • *
  • location - The location of the bundle publishing the service.
  • *
  • id - The bundle ID of the bundle publishing the service.
  • *
  • name - The symbolic name of the bundle publishing the service.
  • *
* Since the above attribute names may conflict with service property names * used by a service, you can prefix an attribute name with '@' in the * filter expression to match against the service property and not one of * the above attributes. Filter attribute names are processed in a case * sensitive manner unless the attribute references a service property. * Service properties names are case insensitive. * *

* There are two possible actions: {@code get} and {@code register}. The * {@code get} permission allows the owner of this permission to obtain a * service with this name. The {@code register} permission allows the bundle * to register a service under that name. * * @param name The service class name * @param actions {@code get},{@code register} (canonical order) * @throws IllegalArgumentException If the specified name is a filter * expression and either the specified action is not {@code get} or * the filter has an invalid syntax. */ public ServicePermission(String name, String actions) { this(name, parseActions(actions)); if ((filter != null) && ((action_mask & ACTION_ALL) != ACTION_GET)) { throw new IllegalArgumentException("invalid action string for filter expression"); } } /** * Creates a new requested {@code ServicePermission} object to be used by * code that must perform {@code checkPermission} for the {@code get} * action. {@code ServicePermission} objects created with this constructor * cannot be added to a {@code ServicePermission} permission collection. * * @param reference The requested service. * @param actions The action {@code get}. * @throws IllegalArgumentException If the specified action is not * {@code get} or reference is {@code null}. * @since 1.5 */ public ServicePermission(ServiceReference reference, String actions) { super(createName(reference)); setTransients(null, parseActions(actions)); this.service = reference; this.objectClass = (String[]) reference.getProperty(Constants.OBJECTCLASS); if ((action_mask & ACTION_ALL) != ACTION_GET) { throw new IllegalArgumentException("invalid action string"); } } /** * Create a permission name from a ServiceReference * * @param reference ServiceReference to use to create permission name. * @return permission name. */ private static String createName(ServiceReference reference) { if (reference == null) { throw new IllegalArgumentException("reference must not be null"); } StringBuffer sb = new StringBuffer("(service.id="); sb.append(reference.getProperty(Constants.SERVICE_ID)); sb.append(")"); return sb.toString(); } /** * Package private constructor used by ServicePermissionCollection. * * @param name class name * @param mask action mask */ ServicePermission(String name, int mask) { super(name); setTransients(parseFilter(name), mask); this.service = null; this.objectClass = null; } /** * Called by constructors and when deserialized. * * @param mask action mask */ private void setTransients(Filter f, int mask) { if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { throw new IllegalArgumentException("invalid action string"); } action_mask = mask; filter = f; if (f == null) { String name = getName(); int l = name.length(); /* if "*" or endsWith ".*" */ wildcard = ((name.charAt(l - 1) == '*') && ((l == 1) || (name.charAt(l - 2) == '.'))); if (wildcard && (l > 1)) { prefix = name.substring(0, l - 1); } } } /** * Parse action string into action mask. * * @param actions Action string. * @return action mask. */ private static int parseActions(String actions) { boolean seencomma = false; int mask = ACTION_NONE; if (actions == null) { return mask; } char[] a = actions.toCharArray(); int i = a.length - 1; if (i < 0) return mask; while (i != -1) { char c; // skip whitespace while ((i != -1) && ((c = a[i]) == ' ' || c == '\r' || c == '\n' || c == '\f' || c == '\t')) i--; // check for the known strings int matchlen; if (i >= 2 && (a[i - 2] == 'g' || a[i - 2] == 'G') && (a[i - 1] == 'e' || a[i - 1] == 'E') && (a[i] == 't' || a[i] == 'T')) { matchlen = 3; mask |= ACTION_GET; } else if (i >= 7 && (a[i - 7] == 'r' || a[i - 7] == 'R') && (a[i - 6] == 'e' || a[i - 6] == 'E') && (a[i - 5] == 'g' || a[i - 5] == 'G') && (a[i - 4] == 'i' || a[i - 4] == 'I') && (a[i - 3] == 's' || a[i - 3] == 'S') && (a[i - 2] == 't' || a[i - 2] == 'T') && (a[i - 1] == 'e' || a[i - 1] == 'E') && (a[i] == 'r' || a[i] == 'R')) { matchlen = 8; mask |= ACTION_REGISTER; } else { // parse error throw new IllegalArgumentException("invalid permission: " + actions); } // make sure we didn't just match the tail of a word // like "ackbarfregister". Also, skip to the comma. seencomma = false; while (i >= matchlen && !seencomma) { switch (a[i - matchlen]) { case ',' : seencomma = true; /* FALLTHROUGH */ case ' ' : case '\r' : case '\n' : case '\f' : case '\t' : break; default : throw new IllegalArgumentException("invalid permission: " + actions); } i--; } // point i at the location of the comma minus one (or -1). i -= matchlen; } if (seencomma) { throw new IllegalArgumentException("invalid permission: " + actions); } return mask; } /** * Parse filter string into a Filter object. * * @param filterString The filter string to parse. * @return a Filter for this bundle. If the specified filterString is not a * filter expression, then {@code null} is returned. * @throws IllegalArgumentException If the filter syntax is invalid. */ private static Filter parseFilter(String filterString) { filterString = filterString.trim(); if (filterString.charAt(0) != '(') { return null; } try { return FrameworkUtil.createFilter(filterString); } catch (InvalidSyntaxException e) { IllegalArgumentException iae = new IllegalArgumentException("invalid filter"); iae.initCause(e); throw iae; } } /** * Determines if a {@code ServicePermission} object "implies" the specified * permission. * * @param p The target permission to check. * @return {@code true} if the specified permission is implied by this * object; {@code false} otherwise. */ public boolean implies(Permission p) { if (!(p instanceof ServicePermission)) { return false; } ServicePermission requested = (ServicePermission) p; if (service != null) { return false; } // if requested permission has a filter, then it is an invalid argument if (requested.filter != null) { return false; } return implies0(requested, ACTION_NONE); } /** * Internal implies method. Used by the implies and the permission * collection implies methods. * * @param requested The requested ServicePermission which has already be * validated as a proper argument. The requested ServicePermission * must not have a filter expression. * @param effective The effective actions with which to start. * @return {@code true} if the specified permission is implied by this * object; {@code false} otherwise. */ boolean implies0(ServicePermission requested, int effective) { /* check actions first - much faster */ effective |= action_mask; final int desired = requested.action_mask; if ((effective & desired) != desired) { return false; } /* we have name of "*" */ if (wildcard && (prefix == null)) { return true; } /* if we have a filter */ Filter f = filter; if (f != null) { return f.matches(requested.getProperties()); } /* if requested permission not created with ServiceReference */ String[] requestedNames = requested.objectClass; if (requestedNames == null) { return super.implies(requested); } /* requested permission created with ServiceReference */ if (wildcard) { int pl = prefix.length(); for (int i = 0, l = requestedNames.length; i < l; i++) { String requestedName = requestedNames[i]; if ((requestedName.length() > pl) && requestedName.startsWith(prefix)) { return true; } } } else { String name = getName(); for (int i = 0, l = requestedNames.length; i < l; i++) { if (requestedNames[i].equals(name)) { return true; } } } return false; } /** * Returns the canonical string representation of the actions. Always * returns present actions in the following order: {@code get}, * {@code register}. * * @return The canonical string representation of the actions. */ public String getActions() { String result = actions; if (result == null) { StringBuffer sb = new StringBuffer(); boolean comma = false; int mask = action_mask; if ((mask & ACTION_GET) == ACTION_GET) { sb.append(GET); comma = true; } if ((mask & ACTION_REGISTER) == ACTION_REGISTER) { if (comma) sb.append(','); sb.append(REGISTER); } actions = result = sb.toString(); } return result; } /** * Returns a new {@code PermissionCollection} object for storing * {@code ServicePermission} objects. * * @return A new {@code PermissionCollection} object suitable for storing * {@code ServicePermission} objects. */ public PermissionCollection newPermissionCollection() { return new ServicePermissionCollection(); } /** * Determines the equality of two ServicePermission objects. * * Checks that specified object has the same class name and action as this * {@code ServicePermission}. * * @param obj The object to test for equality. * @return true if obj is a {@code ServicePermission}, and has the same * class name and actions as this {@code ServicePermission} object; * {@code false} otherwise. */ public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof ServicePermission)) { return false; } ServicePermission sp = (ServicePermission) obj; return (action_mask == sp.action_mask) && getName().equals(sp.getName()) && ((service == sp.service) || ((service != null) && (service.compareTo(sp.service) == 0))); } /** * Returns the hash code value for this object. * * @return Hash code value for this object. */ public int hashCode() { int h = 31 * 17 + getName().hashCode(); h = 31 * h + getActions().hashCode(); if (service != null) { h = 31 * h + service.hashCode(); } return h; } /** * WriteObject is called to save the state of this permission to a stream. * The actions are serialized, and the superclass takes care of the name. */ private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { if (service != null) { throw new NotSerializableException("cannot serialize"); } // Write out the actions. The superclass takes care of the name // call getActions to make sure actions field is initialized if (actions == null) getActions(); s.defaultWriteObject(); } /** * readObject is called to restore the state of this permission from a * stream. */ private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the action, then initialize the rest s.defaultReadObject(); setTransients(parseFilter(getName()), parseActions(actions)); } /** * Called by {@code <@link ServicePermission#implies(Permission)>}. This * method is only called on a requested permission which cannot have a * filter set. * * @return a map of properties for this permission. */ private Map getProperties() { Map result = properties; if (result != null) { return result; } if (service == null) { result = new HashMap(1); result.put(Constants.OBJECTCLASS, new String[] {getName()}); return properties = result; } final Map props = new HashMap(4); final Bundle bundle = service.getBundle(); if (bundle != null) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { props.put("id", new Long(bundle.getBundleId())); props.put("location", bundle.getLocation()); String name = bundle.getSymbolicName(); if (name != null) { props.put("name", name); } SignerProperty signer = new SignerProperty(bundle); if (signer.isBundleSigned()) { props.put("signer", signer); } return null; } }); } return properties = new Properties(props, service); } static private final class Properties extends AbstractMap { private final Map properties; private final ServiceReference service; private transient volatile Set> entries; Properties(Map properties, ServiceReference service) { this.properties = properties; this.service = service; entries = null; } public Object get(Object k) { if (!(k instanceof String)) { return null; } String key = (String) k; if (key.charAt(0) == '@') { return service.getProperty(key.substring(1)); } Object value = properties.get(key); if (value != null) { // fall back to service properties return value; } return service.getProperty(key); } public Set> entrySet() { if (entries != null) { return entries; } Set> all = new HashSet>(properties.entrySet()); add: for (String key : service.getPropertyKeys()) { for (String k : properties.keySet()) { if (key.equalsIgnoreCase(k)) { continue add; } } all.add(new Entry(key, service.getProperty(key))); } return entries = Collections.unmodifiableSet(all); } static private final class Entry implements Map.Entry { private final String k; private final Object v; Entry(String key, Object value) { this.k = key; this.v = value; } public String getKey() { return k; } public Object getValue() { return v; } public Object setValue(Object value) { throw new UnsupportedOperationException(); } public String toString() { return k + "=" + v; } public int hashCode() { return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode()); } public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof Map.Entry)) { return false; } Map.Entry e = (Map.Entry) obj; final Object key = e.getKey(); if ((k == key) || ((k != null) && k.equals(key))) { final Object value = e.getValue(); if ((v == value) || ((v != null) && v.equals(value))) { return true; } } return false; } } } } /** * Stores a set of ServicePermission permissions. * * @see java.security.Permission * @see java.security.Permissions * @see java.security.PermissionCollection */ final class ServicePermissionCollection extends PermissionCollection { static final long serialVersionUID = 662615640374640621L; /** * Table of permissions. * * @GuardedBy this */ private transient Map permissions; /** * Boolean saying if "*" is in the collection. * * @serial * @GuardedBy this */ private boolean all_allowed; /** * Table of permissions with filter expressions. * * @serial * @GuardedBy this */ private Map filterPermissions; /** * Creates an empty ServicePermissions object. */ public ServicePermissionCollection() { permissions = new HashMap(); all_allowed = false; } /** * Adds a permission to this permission collection. * * @param permission The Permission object to add. * @throws IllegalArgumentException If the specified permission is not a * ServicePermission object. * @throws SecurityException If this {@code ServicePermissionCollection} * object has been marked read-only. */ public void add(final Permission permission) { if (!(permission instanceof ServicePermission)) { throw new IllegalArgumentException("invalid permission: " + permission); } if (isReadOnly()) { throw new SecurityException("attempt to add a Permission to a " + "readonly PermissionCollection"); } final ServicePermission sp = (ServicePermission) permission; if (sp.service != null) { throw new IllegalArgumentException("cannot add to collection: " + sp); } final String name = sp.getName(); final Filter f = sp.filter; synchronized (this) { /* select the bucket for the permission */ Map pc; if (f != null) { pc = filterPermissions; if (pc == null) { filterPermissions = pc = new HashMap(); } } else { pc = permissions; } final ServicePermission existing = pc.get(name); if (existing != null) { final int oldMask = existing.action_mask; final int newMask = sp.action_mask; if (oldMask != newMask) { pc.put(name, new ServicePermission(name, oldMask | newMask)); } } else { pc.put(name, sp); } if (!all_allowed) { if (name.equals("*")) { all_allowed = true; } } } } /** * Determines if a set of permissions implies the permissions expressed in * {@code permission}. * * @param permission The Permission object to compare. * @return {@code true} if {@code permission} is a proper subset of a * permission in the set; {@code false} otherwise. */ public boolean implies(final Permission permission) { if (!(permission instanceof ServicePermission)) { return false; } final ServicePermission requested = (ServicePermission) permission; /* if requested permission has a filter, then it is an invalid argument */ if (requested.filter != null) { return false; } int effective = ServicePermission.ACTION_NONE; Collection perms; synchronized (this) { final int desired = requested.action_mask; /* short circuit if the "*" Permission was added */ if (all_allowed) { ServicePermission sp = permissions.get("*"); if (sp != null) { effective |= sp.action_mask; if ((effective & desired) == desired) { return true; } } } String[] requestedNames = requested.objectClass; /* if requested permission not created with ServiceReference */ if (requestedNames == null) { effective |= effective(requested.getName(), desired, effective); if ((effective & desired) == desired) { return true; } } /* requested permission created with ServiceReference */ else { for (int i = 0, l = requestedNames.length; i < l; i++) { if ((effective(requestedNames[i], desired, effective) & desired) == desired) { return true; } } } Map pc = filterPermissions; if (pc == null) { return false; } perms = pc.values(); } /* iterate one by one over filteredPermissions */ for (ServicePermission perm : perms) { if (perm.implies0(requested, effective)) { return true; } } return false; } /** * Consult permissions map to compute the effective permission for the * requested permission name. * * @param requestedName The requested service name. * @param desired The desired actions. * @param effective The effective actions. * @return The new effective actions. */ private int effective(String requestedName, final int desired, int effective) { final Map pc = permissions; ServicePermission sp = pc.get(requestedName); // strategy: // Check for full match first. Then work our way up the // name looking for matches on a.b.* if (sp != null) { // we have a direct hit! effective |= sp.action_mask; if ((effective & desired) == desired) { return effective; } } // work our way up the tree... int last; int offset = requestedName.length() - 1; while ((last = requestedName.lastIndexOf(".", offset)) != -1) { requestedName = requestedName.substring(0, last + 1) + "*"; sp = pc.get(requestedName); if (sp != null) { effective |= sp.action_mask; if ((effective & desired) == desired) { return effective; } } offset = last - 1; } /* * we don't have to check for "*" as it was already checked before we * were called. */ return effective; } /** * Returns an enumeration of all the {@code ServicePermission} objects in * the container. * * @return Enumeration of all the ServicePermission objects. */ public synchronized Enumeration elements() { List all = new ArrayList(permissions.values()); Map pc = filterPermissions; if (pc != null) { all.addAll(pc.values()); } return Collections.enumeration(all); } /* serialization logic */ private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("permissions", Hashtable.class), new ObjectStreamField("all_allowed", Boolean.TYPE), new ObjectStreamField("filterPermissions", HashMap.class) }; private synchronized void writeObject(ObjectOutputStream out) throws IOException { Hashtable hashtable = new Hashtable(permissions); ObjectOutputStream.PutField pfields = out.putFields(); pfields.put("permissions", hashtable); pfields.put("all_allowed", all_allowed); pfields.put("filterPermissions", filterPermissions); out.writeFields(); } private synchronized void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gfields = in.readFields(); Hashtable hashtable = (Hashtable) gfields.get("permissions", null); permissions = new HashMap(hashtable); all_allowed = gfields.get("all_allowed", false); HashMap fp = (HashMap) gfields.get("filterPermissions", null); filterPermissions = fp; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/wiring/0000755000175000017500000000000012475375714024736 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/wiring/packageinfo0000644000175000017500000000001412346513664027116 0ustar felixfelixversion 1.1 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/wiring/BundleCapability.java0000644000175000017500000000442412346513664031013 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.wiring; import java.util.Map; import org.osgi.framework.namespace.AbstractWiringNamespace; import org.osgi.resource.Capability; /** * A capability that has been declared from a {@link BundleRevision bundle * revision}. * * @ThreadSafe * @noimplement * @version $Id: 39086f7e6086c2b3d83fbcb976a011cf69483ad8 $ */ public interface BundleCapability extends Capability { /** * Returns the bundle revision declaring this capability. * * @return The bundle revision declaring this capability. */ BundleRevision getRevision(); /** * Returns the namespace of this capability. * * @return The namespace of this capability. */ String getNamespace(); /** * Returns the directives of this capability. * *

* All capability directives not specified by the * {@link AbstractWiringNamespace wiring namespaces} have no specified * semantics and are considered extra user defined information. * * @return An unmodifiable map of directive names to directive values for * this capability, or an empty map if this capability has no * directives. */ Map getDirectives(); /** * Returns the attributes of this capability. * * @return An unmodifiable map of attribute names to attribute values for * this capability, or an empty map if this capability has no * attributes. */ Map getAttributes(); /** * Returns the resource declaring this capability. * *

* This method returns the same value as {@link #getRevision()}. * * @return The resource declaring this capability. * @since 1.1 */ BundleRevision getResource(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/wiring/BundleRevision.java0000644000175000017500000003050412346513664030526 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.wiring; import java.util.List; import org.osgi.framework.Bundle; import org.osgi.framework.BundleReference; import org.osgi.framework.Constants; import org.osgi.framework.Version; import org.osgi.framework.namespace.BundleNamespace; import org.osgi.framework.namespace.HostNamespace; import org.osgi.framework.namespace.PackageNamespace; import org.osgi.resource.Capability; import org.osgi.resource.Requirement; import org.osgi.resource.Resource; /** * Bundle Revision. When a bundle is installed and each time a bundle is * updated, a new bundle revision of the bundle is created. Since a bundle * update can change the entries in a bundle, different bundle wirings for the * same bundle can be associated with different bundle revisions. * *

* For a bundle that has not been uninstalled, the most recent bundle revision * is defined to be the current bundle revision. A bundle in the UNINSTALLED * state does not have a current revision. The current bundle revision for a * bundle can be obtained by calling {@link Bundle#adapt(Class) bundle.adapt} * (BundleRevision.class). Since a bundle in the UNINSTALLED state does not have * a current revision, adapting such a bundle returns {@code null}. * *

* The framework defines namespaces for {@link PackageNamespace package}, * {@link BundleNamespace bundle} and {@link HostNamespace host} capabilities * and requirements. These namespaces are defined only to express wiring * information by the framework. They must not be used in * {@link Constants#PROVIDE_CAPABILITY Provide-Capability} and * {@link Constants#REQUIRE_CAPABILITY Require-Capability} manifest headers. * * @ThreadSafe * @noimplement * @version $Id: e68e01a670f0ae9d6eb736414f875c8b216ed1bc $ */ public interface BundleRevision extends BundleReference, Resource { /** * Returns the symbolic name for this bundle revision. * * @return The symbolic name for this bundle revision. * @see Bundle#getSymbolicName() */ String getSymbolicName(); /** * Returns the version for this bundle revision. * * @return The version for this bundle revision, or * {@link Version#emptyVersion} if this bundle revision has no * version information. * @see Bundle#getVersion() */ Version getVersion(); /** * Returns the capabilities declared by this bundle revision. * * @param namespace The namespace of the declared capabilities to return or * {@code null} to return the declared capabilities from all * namespaces. * @return An unmodifiable list containing the declared * {@link BundleCapability}s from the specified namespace. The * returned list will be empty if this bundle revision declares no * capabilities in the specified namespace. The list contains the * declared capabilities in the order they are specified in the * manifest. */ List getDeclaredCapabilities(String namespace); /** * Returns the requirements declared by this bundle revision. * * @param namespace The namespace of the declared requirements to return or * {@code null} to return the declared requirements from all * namespaces. * @return An unmodifiable list containing the declared * {@link BundleRequirement}s from the specified namespace. The * returned list will be empty if this bundle revision declares no * requirements in the specified namespace. The list contains the * declared requirements in the order they are specified in the * manifest. */ List getDeclaredRequirements(String namespace); /** * Namespace for package capabilities and requirements. * *

* The name of the package is stored in the capability attribute of the same * name as this namespace (osgi.wiring.package). The other directives and * attributes of the package, from the {@link Constants#EXPORT_PACKAGE * Export-Package} manifest header, can be found in the cabability's * {@link BundleCapability#getDirectives() directives} and * {@link BundleCapability#getAttributes() attributes}. The * {@link Constants#VERSION_ATTRIBUTE version} capability attribute must * contain the {@link Version} of the package if one is specified or * {@link Version#emptyVersion} if not specified. The * {@link Constants#BUNDLE_SYMBOLICNAME_ATTRIBUTE bundle-symbolic-name} * capability attribute must contain the * {@link BundleRevision#getSymbolicName() symbolic name} of the provider if * one is specified. The {@link Constants#BUNDLE_VERSION_ATTRIBUTE * bundle-version} capability attribute must contain the * {@link BundleRevision#getVersion() version} of the provider if one is * specified or {@link Version#emptyVersion} if not specified. * *

* The package capabilities provided by the system bundle, that is the * bundle with id zero, must include the package specified by the * {@link Constants#FRAMEWORK_SYSTEMPACKAGES} and * {@link Constants#FRAMEWORK_SYSTEMPACKAGES_EXTRA} framework properties as * well as any other package exported by the framework implementation. * *

* A bundle revision {@link BundleRevision#getDeclaredCapabilities(String) * declares} zero or more package capabilities (this is, exported packages) * and {@link BundleRevision#getDeclaredRequirements(String) declares} zero * or more package requirements. *

* A bundle wiring {@link BundleWiring#getCapabilities(String) provides} * zero or more resolved package capabilities (that is, exported packages) * and {@link BundleWiring#getRequiredWires(String) requires} zero or more * resolved package requirements (that is, imported packages). The number of * package wires required by a bundle wiring may change as the bundle wiring * may dynamically import additional packages. * * @see PackageNamespace */ String PACKAGE_NAMESPACE = PackageNamespace.PACKAGE_NAMESPACE; /** * Namespace for bundle capabilities and requirements. * *

* The bundle symbolic name of the bundle is stored in the capability * attribute of the same name as this namespace (osgi.wiring.bundle). The * other directives and attributes of the bundle, from the * {@link Constants#BUNDLE_SYMBOLICNAME Bundle-SymbolicName} manifest * header, can be found in the cabability's * {@link BundleCapability#getDirectives() directives} and * {@link BundleCapability#getAttributes() attributes}. The * {@link Constants#BUNDLE_VERSION_ATTRIBUTE bundle-version} capability * attribute must contain the {@link Version} of the bundle from the * {@link Constants#BUNDLE_VERSION Bundle-Version} manifest header if one is * specified or {@link Version#emptyVersion} if not specified. * *

* A non-fragment revision * {@link BundleRevision#getDeclaredCapabilities(String) declares} exactly * one bundle capability (that is, the bundle can be * required by another bundle). A fragment revision must not declare a * bundle capability. * *

* A bundle wiring for a non-fragment revision * {@link BundleWiring#getCapabilities(String) provides} exactly * one bundle capability (that is, the bundle can be * required by another bundle) and * {@link BundleWiring#getRequiredWires(String) requires} zero or more * bundle capabilities (that is, requires other bundles). * *

* † A bundle with no bundle symbolic name (that is, a bundle with * {@link Constants#BUNDLE_MANIFESTVERSION Bundle-ManifestVersion} * {@literal <} 2) must not provide a bundle capability. * * @see BundleNamespace */ String BUNDLE_NAMESPACE = BundleNamespace.BUNDLE_NAMESPACE; /** * Namespace for host capabilities and requirements. * *

* The bundle symbolic name of the bundle is stored in the capability * attribute of the same name as this namespace (osgi.wiring.host). The * other directives and attributes of the bundle, from the * {@link Constants#BUNDLE_SYMBOLICNAME Bundle-SymbolicName} manifest * header, can be found in the cabability's * {@link BundleCapability#getDirectives() directives} and * {@link BundleCapability#getAttributes() attributes}. The * {@link Constants#BUNDLE_VERSION_ATTRIBUTE bundle-version} capability * attribute must contain the {@link Version} of the bundle from the * {@link Constants#BUNDLE_VERSION Bundle-Version} manifest header if one is * specified or {@link Version#emptyVersion} if not specified. * *

* A non-fragment revision * {@link BundleRevision#getDeclaredCapabilities(String) declares} zero or * one host capability if the bundle * {@link Constants#FRAGMENT_ATTACHMENT_DIRECTIVE allows fragments to be * attached}. A fragment revision must * {@link BundleRevision#getDeclaredRequirements(String) declare} exactly * one host requirement. * *

* A bundle wiring for a non-fragment revision * {@link BundleWiring#getCapabilities(String) provides} zero or * one host capability if the bundle * {@link Constants#FRAGMENT_ATTACHMENT_DIRECTIVE allows fragments to be * attached}. A bundle wiring for a fragment revision * {@link BundleWiring#getRequiredWires(String) requires} a host capability * for each host to which it is attached. * *

* † A bundle with no bundle symbolic name (that is, a bundle with * {@link Constants#BUNDLE_MANIFESTVERSION Bundle-ManifestVersion} * {@literal <} 2) must not provide a host capability. * * @see HostNamespace */ String HOST_NAMESPACE = HostNamespace.HOST_NAMESPACE; /** * Returns the special types of this bundle revision. The bundle revision * type values are: *

    *
  • {@link #TYPE_FRAGMENT} *
* * A bundle revision may be more than one type at a time. A type code is * used to identify the bundle revision type for future extendability. * *

* If this bundle revision is not one or more of the defined types then 0 is * returned. * * @return The special types of this bundle revision. The type values are * ORed together. */ int getTypes(); /** * Bundle revision type indicating the bundle revision is a fragment. * * @see #getTypes() */ int TYPE_FRAGMENT = 0x00000001; /** * Returns the bundle wiring which is using this bundle revision. * * @return The bundle wiring which is using this bundle revision or * {@code null} if no bundle wiring is using this bundle revision. * @see BundleWiring#getRevision() */ BundleWiring getWiring(); /** * Returns the capabilities declared by this resource. * *

* This method returns the same value as * {@link #getDeclaredCapabilities(String)}. * * @param namespace The namespace of the declared capabilities to return or * {@code null} to return the declared capabilities from all * namespaces. * @return An unmodifiable list containing the declared {@link Capability}s * from the specified namespace. The returned list will be empty if * this resource declares no capabilities in the specified * namespace. * @since 1.1 */ List getCapabilities(String namespace); /** * Returns the requirements declared by this bundle resource. * *

* This method returns the same value as * {@link #getDeclaredRequirements(String)}. * * @param namespace The namespace of the declared requirements to return or * {@code null} to return the declared requirements from all * namespaces. * @return An unmodifiable list containing the declared {@link Requirement} * s from the specified namespace. The returned list will be empty * if this resource declares no requirements in the specified * namespace. * @since 1.1 */ List getRequirements(String namespace); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/wiring/BundleWire.java0000644000175000017500000000645312346513664027644 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.wiring; import org.osgi.resource.Wire; /** * A wire connecting a {@link BundleCapability} to a {@link BundleRequirement}. * * @ThreadSafe * @noimplement * @version $Id: 02e7cd6ec0fa9fdb73f782a6890984d5d4e7ca21 $ */ public interface BundleWire extends Wire { /** * Returns the {@link BundleCapability} for this wire. * * @return The {@link BundleCapability} for this wire. */ BundleCapability getCapability(); /** * Return the {@link BundleRequirement} for this wire. * * @return The {@link BundleRequirement} for this wire. */ BundleRequirement getRequirement(); /** * Returns the bundle wiring {@link BundleWiring#getProvidedWires(String) * providing} the {@link #getCapability() capability}. * *

* The bundle revision referenced by the returned bundle wiring may differ * from the bundle revision referenced by the {@link #getCapability() * capability}. * * @return The bundle wiring providing the capability. If the bundle wiring * providing the capability is not {@link BundleWiring#isInUse() in * use}, {@code null} will be returned. */ BundleWiring getProviderWiring(); /** * Returns the bundle wiring who * {@link BundleWiring#getRequiredWires(String) requires} the * {@link #getCapability() capability}. * *

* The bundle revision referenced by the returned bundle wiring may differ * from the bundle revision referenced by the {@link #getRequirement() * requirement}. * * @return The bundle wiring whose requirement is wired to the capability. * If the bundle wiring requiring the capability is not * {@link BundleWiring#isInUse() in use}, {@code null} will be * returned. */ BundleWiring getRequirerWiring(); /** * Returns the resource providing the {@link #getCapability() capability}. * *

* The returned resource may differ from the resource referenced by the * {@link #getCapability() capability}. * *

* This method returns the same value as {@link #getProviderWiring()}. * {@link BundleWiring#getRevision() getRevision()}. * * @return The resource providing the capability. * @since 1.1 */ BundleRevision getProvider(); /** * Returns the resource who {@link #getRequirement() requires} the * {@link #getCapability() capability}. * *

* The returned resource may differ from the resource referenced by the * {@link #getRequirement() requirement}. * *

* This method returns the same value as {@link #getRequirerWiring()}. * {@link BundleWiring#getRevision() getRevision()}. * * @return The resource who requires the capability. * @since 1.1 */ BundleRevision getRequirer(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/wiring/FrameworkWiring.java0000644000175000017500000001774012346513664030722 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2001, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.wiring; import java.util.Collection; import org.osgi.framework.Bundle; import org.osgi.framework.BundleReference; import org.osgi.framework.FrameworkListener; /** * Query and modify wiring information for the framework. The framework wiring * object for the framework can be obtained by calling * {@link Bundle#adapt(Class) bundle.adapt(FrameworkWiring.class)} on the system * bundle. Only the system bundle can be adapted to a FrameworkWiring object. * *

* The system bundle associated with this FrameworkWiring object can be obtained * by calling {@link BundleReference#getBundle()}. * * @ThreadSafe * @noimplement * @version $Id: bff4cdf85c632e2946e18c1640a86e80c069dd37 $ */ public interface FrameworkWiring extends BundleReference { /** * Refreshes the specified bundles. This forces the update (replacement) or * removal of packages exported by the specified bundles. * *

* The technique by which the framework refreshes bundles may vary among * different framework implementations. A permissible implementation is to * stop and restart the framework. * *

* This method returns to the caller immediately and then performs the * following steps on a separate thread: * *

    *
  1. Compute the {@link #getDependencyClosure(Collection) dependency * closure} of the specified bundles. If no bundles are specified, compute * the dependency closure of the {@link #getRemovalPendingBundles() removal * pending} bundles. * *
  2. Each bundle in the dependency closure that is in the {@code ACTIVE} * state will be stopped as described in the {@code Bundle.stop} method. * *
  3. Each bundle in the dependency closure that is in the {@code RESOLVED} * state is unresolved and thus moved to the {@code INSTALLED} state. The * effect of this step is that bundles in the dependency closure are no * longer {@code RESOLVED}. * *
  4. Each bundle in the dependency closure that is in the * {@code UNINSTALLED} state is removed from the dependency closure and is * now completely removed from the Framework. * *
  5. Each bundle in the dependency closure that was in the {@code ACTIVE} * state prior to Step 2 is started as described in the {@code Bundle.start} * method, causing all bundles required for the restart to be resolved. It * is possible that, as a result of the previous steps, packages that were * previously exported no longer are. Therefore, some bundles may be * unresolvable until bundles satisfying the dependencies have been * installed in the Framework. *
* *

* For any exceptions that are thrown during any of these steps, a framework * event of type {@code FrameworkEvent.ERROR} is fired containing the * exception. The source bundle for these events should be the specific * bundle to which the exception is related. If no specific bundle can be * associated with the exception then the System Bundle must be used as the * source bundle for the event. All framework events fired by this method * are also delivered to the specified {@code FrameworkListener}s in the * order they are specified. * *

* When this process completes after the bundles are refreshed, the * Framework will fire a Framework event of type * {@code FrameworkEvent.PACKAGES_REFRESHED} to announce it has completed * the bundle refresh. The specified {@code FrameworkListener}s are notified * in the order specified. Each specified {@code FrameworkListener} will be * called with a Framework event of type * {@code FrameworkEvent.PACKAGES_REFRESHED}. * * @param bundles The bundles to be refreshed, or {@code null} to refresh * the {@link #getRemovalPendingBundles() removal pending} bundles. * @param listeners Zero or more listeners to be notified when the bundle * refresh has been completed. The specified listeners do not need to * be otherwise registered with the framework. If a specified * listener is already registered with the framework, it will be * notified twice. * @throws IllegalArgumentException If the specified {@code Bundle}s were * not created by the same framework instance associated with this * FrameworkWiring. * @throws SecurityException If the caller does not have * {@code AdminPermission[System Bundle,RESOLVE]} and the Java * runtime environment supports permissions. */ void refreshBundles(Collection bundles, FrameworkListener... listeners); /** * Resolves the specified bundles. The Framework must attempt to resolve the * specified bundles that are unresolved. Additional bundles that are not * included in the specified bundles may be resolved as a result of calling * this method. A permissible implementation of this method is to attempt to * resolve all unresolved bundles installed in the framework. * *

* If no bundles are specified, then the Framework will attempt to resolve * all unresolved bundles. This method must not cause any bundle to be * refreshed, stopped, or started. This method will not return until the * operation has completed. * * @param bundles The bundles to resolve or {@code null} to resolve all * unresolved bundles installed in the Framework. * @return {@code true} if all specified bundles are resolved; {@code false} * otherwise. * @throws IllegalArgumentException If the specified {@code Bundle}s were * not created by the same framework instance associated with this * FrameworkWiring. * @throws SecurityException If the caller does not have * {@code AdminPermission[System Bundle,RESOLVE]} and the Java * runtime environment supports permissions. */ boolean resolveBundles(Collection bundles); /** * Returns the bundles that have {@link BundleWiring#isCurrent() * non-current}, {@link BundleWiring#isInUse() in use} bundle wirings. This * is typically the bundles which have been updated or uninstalled since the * last call to {@link #refreshBundles(Collection, FrameworkListener...)}. * * @return A collection containing a snapshot of the {@code Bundle}s which * have non-current, in use {@code BundleWiring}s, or an empty * collection if there are no such bundles. */ Collection getRemovalPendingBundles(); /** * Returns the dependency closure for the specified bundles. * *

* A graph of bundles is computed starting with the specified bundles. The * graph is expanded by adding any bundle that is either wired to a package * that is currently exported by a bundle in the graph or requires a bundle * in the graph. The graph is fully constructed when there is no bundle * outside the graph that is wired to a bundle in the graph. The graph may * contain {@code UNINSTALLED} bundles that are * {@link #getRemovalPendingBundles() removal pending}. * * @param bundles The initial bundles for which to generate the dependency * closure. * @return A collection containing a snapshot of the dependency closure of * the specified bundles, or an empty collection if there were no * specified bundles. * @throws IllegalArgumentException If the specified {@code Bundle}s were * not created by the same framework instance associated with this * FrameworkWiring. */ Collection getDependencyClosure(Collection bundles); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/wiring/package-info.java0000644000175000017500000000200212346513664030112 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Framework Wiring Package Version 1.1. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. For example: * *

 * Import-Package: org.osgi.framework.wiring; version="[1.1,2.0)"
 * 
* * @version $Id: 6f5c519e9ff1ee6ebc7a2564006e97385bb972ca $ */ package org.osgi.framework.wiring; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/wiring/BundleRevisions.java0000644000175000017500000000503212346513664030707 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.wiring; import java.util.List; import org.osgi.framework.Bundle; import org.osgi.framework.BundleReference; /** * The {@link BundleRevision bundle revisions} of a bundle. When a bundle is * installed and each time a bundle is updated, a new bundle revision of the * bundle is created. For a bundle that has not been uninstalled, the most * recent bundle revision is defined to be the current bundle revision. A bundle * in the UNINSTALLED state does not have a current revision. An in use bundle * revision is associated with an {@link BundleWiring#isInUse() in use} * {@link BundleWiring}. The current bundle revision, if there is one, and all * in use bundle revisions are returned. * *

* The bundle revisions for a bundle can be obtained by calling * {@link Bundle#adapt(Class) bundle.adapt}({@link BundleRevisions}.class). * {@link #getRevisions()} on the bundle. * * @ThreadSafe * @noimplement * @version $Id: 8423242078417873faf0f8979e153e3c1f3a0e4b $ */ public interface BundleRevisions extends BundleReference { /** * Return the bundle revisions for the {@link BundleReference#getBundle() * referenced} bundle. * *

* The result is a list containing the current bundle revision, if there is * one, and all in use bundle revisions. The list may also contain * intermediate bundle revisions which are not in use. * *

* The list is ordered in reverse chronological order such that the first * item is the most recent bundle revision and last item is the oldest * bundle revision. * *

* Generally the list will have at least one bundle revision for the bundle: * the current bundle revision. However, for an uninstalled bundle with no * in use bundle revisions, the list may be empty. * * @return A list containing a snapshot of the {@link BundleRevision}s for * the referenced bundle. */ List getRevisions(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/wiring/BundleRequirement.java0000644000175000017500000000576312346513664031241 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.wiring; import java.util.Map; import org.osgi.framework.namespace.AbstractWiringNamespace; import org.osgi.resource.Requirement; /** * A requirement that has been declared from a {@link BundleRevision bundle * revision}. * * @ThreadSafe * @noimplement * @version $Id: 212ffb64f724d982db86ff7e49ed64ea530e670a $ */ public interface BundleRequirement extends Requirement { /** * Returns the bundle revision declaring this requirement. * * @return The bundle revision declaring this requirement. */ BundleRevision getRevision(); /** * Returns whether the specified capability matches this requirement. * * @param capability The capability to match to this requirement. * @return {@code true} if the specified capability has the same * {@link #getNamespace() namespace} as this requirement and the * filter for this requirement matches the * {@link BundleCapability#getAttributes() attributes of the * specified capability}; {@code false} otherwise. */ boolean matches(BundleCapability capability); /** * Returns the namespace of this requirement. * * @return The namespace of this requirement. */ String getNamespace(); /** * Returns the directives of this requirement. * *

* All requirement directives not specified by the * {@link AbstractWiringNamespace wiring namespaces} have no specified * semantics and are considered extra user defined information. * * @return An unmodifiable map of directive names to directive values for * this requirement, or an empty map if this requirement has no * directives. */ Map getDirectives(); /** * Returns the attributes of this requirement. * *

* Requirement attributes have no specified semantics and are considered * extra user defined information. * * @return An unmodifiable map of attribute names to attribute values for * this requirement, or an empty map if this requirement has no * attributes. */ Map getAttributes(); /** * Returns the resource declaring this requirement. * *

* This method returns the same value as {@link #getRevision()}. * * @return The resource declaring this requirement. This can be {@code null} * if this requirement is synthesized. * @since 1.1 */ BundleRevision getResource(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/wiring/BundleWiring.java0000644000175000017500000005637712346513664030207 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.wiring; import java.net.URL; import java.util.Collection; import java.util.List; import org.osgi.framework.Bundle; import org.osgi.framework.BundleReference; import org.osgi.framework.namespace.IdentityNamespace; import org.osgi.framework.namespace.PackageNamespace; import org.osgi.resource.Capability; import org.osgi.resource.Namespace; import org.osgi.resource.Requirement; import org.osgi.resource.Wire; import org.osgi.resource.Wiring; /** * A wiring for a bundle. Each time a bundle is resolved, a new bundle wiring * for the bundle is created. A bundle wiring is associated with a bundle * revision and represents the dependencies with other bundle wirings. * *

* The bundle wiring for a bundle is the {@link #isCurrent() current} bundle * wiring if it is the most recent bundle wiring for the current bundle * revision. A bundle wiring is {@link #isInUse() in use} if it is the current * bundle wiring or if some other in use bundle wiring is dependent upon it. For * example, another bundle wiring is wired to a capability provided by the * bundle wiring. An in use bundle wiring for a non-fragment bundle has a class * loader. All bundles with non-current, in use bundle wirings are considered * removal pending. Once a bundle wiring is no longer in use, it is considered * stale and is discarded by the framework. * *

* The current bundle wiring for a bundle can be obtained by calling * {@link Bundle#adapt(Class) bundle.adapt}(BundleWiring.class). A bundle in the * INSTALLED or UNINSTALLED state does not have a current wiring, adapting such * a bundle returns {@code null}. * * @ThreadSafe * @noimplement * @version $Id: a3b3fd7ad7d289a5bfc6e4e02c875bc42a34df89 $ */ public interface BundleWiring extends BundleReference, Wiring { /** * Returns {@code true} if this bundle wiring is the current bundle wiring. * The bundle wiring for a bundle is the current bundle wiring if it is the * most recent bundle wiring for the current bundle revision. All bundles * with non-current, in use bundle wirings are considered * {@link FrameworkWiring#getRemovalPendingBundles() removal pending}. * * @return {@code true} if this bundle wiring is the current bundle wiring; * {@code false} otherwise. */ boolean isCurrent(); /** * Returns {@code true} if this bundle wiring is in use. A bundle wiring is * in use if it is the {@link #isCurrent() current} wiring or if some other * in use bundle wiring is dependent upon it. Once a bundle wiring is no * longer in use, it is considered stale and is discarded by the framework. * * @return {@code true} if this bundle wiring is in use; {@code false} * otherwise. */ boolean isInUse(); /** * Returns the capabilities provided by this bundle wiring. * *

* Only capabilities considered by the resolver are returned. For example, * capabilities with {@link Namespace#CAPABILITY_EFFECTIVE_DIRECTIVE * effective} directive not equal to {@link Namespace#EFFECTIVE_RESOLVE * resolve} are not returned. * *

* A capability may not be required by any bundle wiring and thus there may * be no {@link #getProvidedWires(String) wires} for the capability. * *

* A bundle wiring for a non-fragment revision provides a subset of the * declared capabilities from the bundle revision and all attached fragment * revisions. Not all declared capabilities may be * provided since some may be discarded. For example, if a package is * declared to be both exported and imported, only one is selected and the * other is discarded. *

* A bundle wiring for a fragment revision with a symbolic name must provide * exactly one {@link IdentityNamespace identity} capability. *

* † The {@link IdentityNamespace identity} capability provided by * attached fragment revisions must not be included in the capabilities of * the host bundle wiring. * * @param namespace The namespace of the capabilities to return or * {@code null} to return the capabilities from all namespaces. * @return A list containing a snapshot of the {@link BundleCapability}s, or * an empty list if this bundle wiring provides no capabilities in * the specified namespace. If this bundle wiring is not * {@link #isInUse() in use}, {@code null} will be returned. For a * given namespace, the list contains the wires in the order the * capabilities were specified in the manifests of the * {@link #getRevision() bundle revision} and the attached * fragments of this bundle wiring. There is no * ordering defined between capabilities in different namespaces. */ List getCapabilities(String namespace); /** * Returns the requirements of this bundle wiring. * *

* Only requirements considered by the resolver are returned. For example, * requirements with {@link Namespace#REQUIREMENT_EFFECTIVE_DIRECTIVE * effective} directive not equal to {@link Namespace#EFFECTIVE_RESOLVE * resolve} are not returned. * *

* A bundle wiring for a non-fragment revision has a subset of the declared * requirements from the bundle revision and all attached fragment * revisions. Not all declared requirements may be present since some may be * discarded. For example, if a package is declared to be optionally * imported and is not actually imported, the requirement must be discarded. * * @param namespace The namespace of the requirements to return or * {@code null} to return the requirements from all namespaces. * @return A list containing a snapshot of the {@link BundleRequirement}s, * or an empty list if this bundle wiring uses no requirements in * the specified namespace. If this bundle wiring is not * {@link #isInUse() in use}, {@code null} will be returned. For a * given namespace, the list contains the wires in the order the * requirements were specified in the manifests of the * {@link #getRevision() bundle revision} and the attached fragments * of this bundle wiring. There is no ordering defined between * requirements in different namespaces. */ List getRequirements(String namespace); /** * Returns the {@link BundleWire}s to the provided {@link BundleCapability * capabilities} of this bundle wiring. * * @param namespace The namespace of the capabilities for which to return * wires or {@code null} to return the wires for the capabilities in * all namespaces. * @return A list containing a snapshot of the {@link BundleWire}s for the * {@link BundleCapability capabilities} of this bundle wiring, or * an empty list if this bundle wiring has no capabilities in the * specified namespace. If this bundle wiring is not * {@link #isInUse() in use}, {@code null} will be returned. For a * given namespace, the list contains the wires in the order the * capabilities were specified in the manifests of the * {@link #getRevision() bundle revision} and the attached fragments * of this bundle wiring. There is no ordering defined between * capabilities in different namespaces. */ List getProvidedWires(String namespace); /** * Returns the {@link BundleWire}s to the {@link BundleRequirement * requirements} in use by this bundle wiring. * *

* This method may return different results if this bundle wiring adds wires * to more requirements. For example, dynamically importing a package will * establish a new wire to the dynamically imported package. * * @param namespace The namespace of the requirements for which to return * wires or {@code null} to return the wires for the requirements in * all namespaces. * @return A list containing a snapshot of the {@link BundleWire}s for the * {@link BundleRequirement requirements} of this bundle wiring, or * an empty list if this bundle wiring has no requirements in the * specified namespace. If this bundle wiring is not * {@link #isInUse() in use}, {@code null} will be returned. For a * given namespace, the list contains the wires in the order the * requirements were specified in the manifests of the * {@link #getRevision() bundle revision} and the attached fragments * of this bundle wiring. There is no ordering defined between * requirements in different namespaces. */ List getRequiredWires(String namespace); /** * Returns the bundle revision for the bundle in this bundle wiring. Since a * bundle update can change the entries in a bundle, different bundle * wirings for the same bundle can have different bundle revisions. * *

* The bundle object {@link BundleReference#getBundle() referenced} by the * returned {@code BundleRevision} may return different information than the * returned {@code BundleRevision} since the returned {@code BundleRevision} * may refer to an older revision of the bundle. * * @return The bundle revision for this bundle wiring. * @see BundleRevision#getWiring() */ BundleRevision getRevision(); /** * Returns the class loader for this bundle wiring. Since a bundle refresh * creates a new bundle wiring for a bundle, different bundle wirings for * the same bundle will have different class loaders. * * @return The class loader for this bundle wiring. If this bundle wiring is * not {@link #isInUse() in use} or this bundle wiring is for a * fragment revision, {@code null} will be returned. * @throws SecurityException If the caller does not have the appropriate * {@code RuntimePermission("getClassLoader")}, and the Java Runtime * Environment supports permissions. */ ClassLoader getClassLoader(); /** * Returns entries in this bundle wiring's {@link #getRevision() bundle * revision} and its attached fragment revisions. This bundle wiring's class * loader is not used to search for entries. Only the contents of this * bundle wiring's bundle revision and its attached fragment revisions are * searched for the specified entries. * *

* This method takes into account that the "contents" of this * bundle wiring can have attached fragments. This "bundle space" * is not a namespace with unique members; the same entry name can be * present multiple times. This method therefore returns a list of URL * objects. These URLs can come from different JARs but have the same path * name. This method can either return only entries in the specified path or * recurse into subdirectories returning entries in the directory tree * beginning at the specified path. * *

* URLs for directory entries must have their path end with "/". *

* Note: Jar and zip files are not required to include directory entries. * URLs to directory entries will not be returned if the bundle contents do * not contain directory entries. * * @param path The path name in which to look. The path is always relative * to the root of this bundle wiring and may begin with * "/". A path value of "/" indicates the root of * this bundle wiring. * @param filePattern The file name pattern for selecting entries in the * specified path. The pattern is only matched against the last * element of the entry path. If the entry is a directory then the * trailing "/" is not used for pattern matching. Substring * matching is supported, as specified in the Filter specification, * using the wildcard character ("*"). If {@code null} is * specified, this is equivalent to "*" and matches all * files. * @param options The options for listing resource names. See * {@link #FINDENTRIES_RECURSE}. The method must ignore unrecognized * options. * @return An unmodifiable list of URL objects for each matching entry, or * an empty list if no matching entry could be found, if this bundle * wiring is for a fragment revision or if the caller does not have * the appropriate {@code AdminPermission[bundle,RESOURCE]} and the * Java Runtime Environment supports permissions. The list is * ordered such that entries from the {@link #getRevision() bundle * revision} are returned first followed by the entries from * attached fragment revisions in attachment order. If this bundle * wiring is not {@link #isInUse() in use}, {@code null} must be * returned. * @see Bundle#findEntries(String, String, boolean) */ List findEntries(String path, String filePattern, int options); /** * The find entries operation must recurse into subdirectories. * *

* This bit may be set when calling * {@link #findEntries(String, String, int)} to specify the result must * include the matching entries from the specified path and its * subdirectories. If this bit is not set, then the result must only include * matching entries from the specified path. * * @see #findEntries(String, String, int) */ int FINDENTRIES_RECURSE = 0x00000001; /** * Returns the names of resources visible to this bundle wiring's * {@link #getClassLoader() class loader}. The returned names can be used to * access the resources via this bundle wiring's class loader. * *

    *
  • Only the resource names for resources in bundle wirings will be * returned. The names of resources visible to a bundle wiring's parent * class loader, such as the bootstrap class loader, must not be included in * the result. *
  • Only established wires will be examined for resources. This method * must not cause new wires for dynamic imports to be established. *
* * @param path The path name in which to look. The path is always relative * to the root of this bundle wiring's class loader and may begin * with "/". A path value of "/" indicates the * root of this bundle wiring's class loader. * @param filePattern The file name pattern for selecting resource names in * the specified path. The pattern is only matched against the last * element of the resource path. If the resource is a directory then * the trailing "/" is not used for pattern matching. * Substring matching is supported, as specified in the Filter * specification, using the wildcard character ("*"). If * {@code null} is specified, this is equivalent to "*" and * matches all files. * @param options The options for listing resource names. See * {@link #LISTRESOURCES_LOCAL} and {@link #LISTRESOURCES_RECURSE}. * This method must ignore unrecognized options. * @return An unmodifiable collection of resource names for each matching * resource, or an empty collection if no matching resource could be * found, if this bundle wiring is for a fragment revision or if the * caller does not have the appropriate * {@code AdminPermission[bundle,RESOURCE]} and the Java Runtime * Environment supports permissions. The collection is unordered and * must contain no duplicate resource names. If this bundle wiring * is not {@link #isInUse() in use}, {@code null} must be returned. */ Collection listResources(String path, String filePattern, int options); /** * The list resource names operation must recurse into subdirectories. * *

* This bit may be set when calling * {@link #listResources(String, String, int)} to specify the result must * include the names of matching resources from the specified path and its * subdirectories. If this bit is not set, then the result must only include * names of matching resources from the specified path. * * @see #listResources(String, String, int) */ int LISTRESOURCES_RECURSE = 0x00000001; /** * The list resource names operation must limit the result to the names of * matching resources contained in this bundle wiring's * {@link #getRevision() bundle revision} and its attached fragment * revisions. The result must not include resource names for resources in * {@link PackageNamespace package} names which are * {@link #getRequiredWires(String) imported} by this wiring. * *

* This bit may be set when calling * {@link #listResources(String, String, int)} to specify the result must * only include the names of matching resources contained in this bundle * wiring's bundle revision and its attached fragment revisions. If this bit * is not set, then the result must include the names of matching resources * reachable from this bundle wiring's class loader which may include the * names of matching resources contained in imported packages and required * bundles. * * @see #listResources(String, String, int) */ int LISTRESOURCES_LOCAL = 0x00000002; /** * Returns the capabilities provided by this wiring. * *

* Only capabilities considered by the resolver are returned. For example, * capabilities with {@link Namespace#CAPABILITY_EFFECTIVE_DIRECTIVE * effective} directive not equal to {@link Namespace#EFFECTIVE_RESOLVE * resolve} are not returned. * *

* A capability may not be required by any wiring and thus there may be no * {@link #getProvidedResourceWires(String) wires} for the capability. * *

* A wiring for a non-fragment resource provides a subset of the declared * capabilities from the resource and all attached fragment * resources. Not all declared capabilities may be * provided since some may be discarded. For example, if a package is * declared to be both exported and imported, only one is selected and the * other is discarded. *

* A wiring for a fragment resource with a symbolic name must provide * exactly one {@code osgi.identity} capability. *

* † The {@code osgi.identity} capability provided by attached * fragment resource must not be included in the capabilities of the host * wiring. * *

* This method returns the same value as {@link #getCapabilities(String)}. * * @param namespace The namespace of the capabilities to return or * {@code null} to return the capabilities from all namespaces. * @return A list containing a snapshot of the {@link Capability}s, or an * empty list if this wiring provides no capabilities in the * specified namespace. For a given namespace, the list contains the * wires in the order the capabilities were specified in the * manifests of the {@link #getResource() resource} and the attached * fragment resources of this wiring. There is no * ordering defined between capabilities in different namespaces. * @since 1.1 */ List getResourceCapabilities(String namespace); /** * Returns the requirements of this wiring. * *

* Only requirements considered by the resolver are returned. For example, * requirements with {@link Namespace#REQUIREMENT_EFFECTIVE_DIRECTIVE * effective} directive not equal to {@link Namespace#EFFECTIVE_RESOLVE * resolve} are not returned. * *

* A wiring for a non-fragment resource has a subset of the declared * requirements from the resource and all attached fragment resources. Not * all declared requirements may be present since some may be discarded. For * example, if a package is declared to be optionally imported and is not * actually imported, the requirement must be discarded. * *

* This method returns the same value as {@link #getRequirements(String)}. * * @param namespace The namespace of the requirements to return or * {@code null} to return the requirements from all namespaces. * @return A list containing a snapshot of the {@link Requirement}s, or an * empty list if this wiring uses no requirements in the specified * namespace. For a given namespace, the list contains the wires in * the order the requirements were specified in the manifests of the * {@link #getResource() resource} and the attached fragment * resources of this wiring. There is no ordering defined between * requirements in different namespaces. * @since 1.1 */ List getResourceRequirements(String namespace); /** * Returns the {@link Wire}s to the provided {@link Capability capabilities} * of this wiring. * *

* This method returns the same value as {@link #getProvidedWires(String)}. * * @param namespace The namespace of the capabilities for which to return * wires or {@code null} to return the wires for the capabilities in * all namespaces. * @return A list containing a snapshot of the {@link Wire}s for the * {@link Capability capabilities} of this wiring, or an empty list * if this wiring has no capabilities in the specified namespace. * For a given namespace, the list contains the wires in the order * the capabilities were specified in the manifests of the * {@link #getResource() resource} and the attached fragment * resources of this wiring. There is no ordering defined between * capabilities in different namespaces. * @since 1.1 */ List getProvidedResourceWires(String namespace); /** * Returns the {@link Wire}s to the {@link Requirement requirements} in use * by this wiring. * *

* This method returns the same value as {@link #getRequiredWires(String)}. * * @param namespace The namespace of the requirements for which to return * wires or {@code null} to return the wires for the requirements in * all namespaces. * @return A list containing a snapshot of the {@link Wire}s for the * {@link Requirement requirements} of this wiring, or an empty list * if this wiring has no requirements in the specified namespace. * For a given namespace, the list contains the wires in the order * the requirements were specified in the manifests of the * {@link #getResource() resource} and the attached fragment * resources of this wiring. There is no ordering defined between * requirements in different namespaces. * @since 1.1 */ List getRequiredResourceWires(String namespace); /** * Returns the resource associated with this wiring. * *

* This method returns the same value as {@link #getRevision()}. * * @return The resource associated with this wiring. * @since 1.1 */ BundleRevision getResource(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/InvalidSyntaxException.java0000644000175000017500000000700412346513664030752 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; /** * A Framework exception used to indicate that a filter string has an invalid * syntax. * *

* An {@code InvalidSyntaxException} object indicates that a filter string * parameter has an invalid syntax and cannot be parsed. See {@link Filter} for * a description of the filter string syntax. * *

* This exception conforms to the general purpose exception chaining mechanism. * * @version $Id: 8820ca2db85b557cef8da09ee861249dfb5ee914 $ */ public class InvalidSyntaxException extends Exception { static final long serialVersionUID = -4295194420816491875L; /** * The invalid filter string. */ private final String filter; /** * Creates an exception of type {@code InvalidSyntaxException}. * *

* This method creates an {@code InvalidSyntaxException} object with the * specified message and the filter string which generated the exception. * * @param msg The message. * @param filter The invalid filter string. */ public InvalidSyntaxException(String msg, String filter) { super(message(msg, filter)); this.filter = filter; } /** * Creates an exception of type {@code InvalidSyntaxException}. * *

* This method creates an {@code InvalidSyntaxException} object with the * specified message and the filter string which generated the exception. * * @param msg The message. * @param filter The invalid filter string. * @param cause The cause of this exception. * @since 1.3 */ public InvalidSyntaxException(String msg, String filter, Throwable cause) { super(message(msg, filter), cause); this.filter = filter; } /** * Return message string for super constructor. */ private static String message(String msg, String filter) { if ((msg == null) || (filter == null) || msg.indexOf(filter) >= 0) { return msg; } return msg + ": " + filter; } /** * Returns the filter string that generated the * {@code InvalidSyntaxException} object. * * @return The invalid filter string. * @see BundleContext#getServiceReferences(Class, String) * @see BundleContext#getServiceReferences(String, String) * @see BundleContext#addServiceListener(ServiceListener,String) */ public String getFilter() { return filter; } /** * Returns the cause of this exception or {@code null} if no cause was set. * * @return The cause of this exception or {@code null} if no cause was set. * @since 1.3 */ public Throwable getCause() { return super.getCause(); } /** * Initializes the cause of this exception to the specified value. * * @param cause The cause of this exception. * @return This exception. * @throws IllegalArgumentException If the specified cause is this * exception. * @throws IllegalStateException If the cause of this exception has already * been set. * @since 1.3 */ public Throwable initCause(Throwable cause) { return super.initCause(cause); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/BundleContext.java0000644000175000017500000011605612346513664027064 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.io.File; import java.io.InputStream; import java.util.Collection; import java.util.Dictionary; /** * A bundle's execution context within the Framework. The context is used to * grant access to other methods so that this bundle can interact with the * Framework. * *

* {@code BundleContext} methods allow a bundle to: *

    *
  • Subscribe to events published by the Framework. *
  • Register service objects with the Framework service registry. *
  • Retrieve {@code ServiceReferences} from the Framework service registry. *
  • Get and release service objects for a referenced service. *
  • Install new bundles in the Framework. *
  • Get the list of bundles installed in the Framework. *
  • Get the {@link Bundle} object for a bundle. *
  • Create {@code File} objects for files in a persistent storage area * provided for the bundle by the Framework. *
* *

* A {@code BundleContext} object will be created for a bundle when the bundle * is started. The {@code Bundle} object associated with a {@code BundleContext} * object is called the context bundle. * *

* The {@code BundleContext} object will be passed to the * {@link BundleActivator#start(BundleContext)} method during activation of the * context bundle. The same {@code BundleContext} object will be passed to the * {@link BundleActivator#stop(BundleContext)} method when the context bundle is * stopped. A {@code BundleContext} object is generally for the private use of * its associated bundle and is not meant to be shared with other bundles in the * OSGi environment. * *

* The {@code BundleContext} object is only valid during the execution of its * context bundle; that is, during the period from when the context bundle is in * the {@code STARTING}, {@code STOPPING}, and {@code ACTIVE} bundle states. If * the {@code BundleContext} object is used subsequently, an * {@code IllegalStateException} must be thrown. The {@code BundleContext} * object must never be reused after its context bundle is stopped. * *

* Two {@code BundleContext} objects are equal if they both refer to the same * execution context of a bundle. The Framework is the only entity that can * create {@code BundleContext} objects and they are only valid within the * Framework that created them. * *

* A {@link Bundle} can be {@link Bundle#adapt(Class) adapted} to its * {@code BundleContext}. In order for this to succeed, the caller must have the * appropriate {@code AdminPermission[bundle,CONTEXT]} if the Java Runtime * Environment supports permissions. * * @ThreadSafe * @noimplement * @version $Id: 4f166fd274f3965e48a7dbc239213d00e062b6d0 $ */ public interface BundleContext extends BundleReference { /** * Returns the value of the specified property. If the key is not found in * the Framework properties, the system properties are then searched. The * method returns {@code null} if the property is not found. * *

* All bundles must have permission to read properties whose names start * with "org.osgi.". * * @param key The name of the requested property. * @return The value of the requested property, or {@code null} if the * property is undefined. * @throws SecurityException If the caller does not have the appropriate * {@code PropertyPermission} to read the property, and the Java * Runtime Environment supports permissions. */ String getProperty(String key); /** * Returns the {@code Bundle} object associated with this * {@code BundleContext}. This bundle is called the context bundle. * * @return The {@code Bundle} object associated with this * {@code BundleContext}. * @throws IllegalStateException If this BundleContext is no longer valid. */ Bundle getBundle(); /** * Installs a bundle from the specified {@code InputStream} object. * *

* If the specified {@code InputStream} is {@code null}, the Framework must * create the {@code InputStream} from which to read the bundle by * interpreting, in an implementation dependent manner, the specified * {@code location}. * *

* The specified {@code location} identifier will be used as the identity of * the bundle. Every installed bundle is uniquely identified by its location * identifier which is typically in the form of a URL. * *

* The following steps are required to install a bundle: *

    *
  1. If a bundle containing the same location identifier is already * installed, the {@code Bundle} object for that bundle is returned. * *
  2. The bundle's content is read from the input stream. If this fails, a * {@link BundleException} is thrown. * *
  3. The bundle's associated resources are allocated. The associated * resources minimally consist of a unique identifier and a persistent * storage area if the platform has file system support. If this step fails, * a {@code BundleException} is thrown. * *
  4. The bundle's state is set to {@code INSTALLED}. * *
  5. A bundle event of type {@link BundleEvent#INSTALLED} is fired. * *
  6. The {@code Bundle} object for the newly or previously installed * bundle is returned. *
* * Postconditions, no exceptions thrown *
    *
  • {@code getState()} in { {@code INSTALLED}, {@code RESOLVED} * }. *
  • Bundle has a unique ID. *
* Postconditions, when an exception is thrown *
    *
  • Bundle is not installed. If there was an existing bundle for the * specified location, then that bundle must still be in the state it was * prior to calling this method.
  • *
* * @param location The location identifier of the bundle to install. * @param input The {@code InputStream} object from which this bundle will * be read or {@code null} to indicate the Framework must create the * input stream from the specified location identifier. The input * stream must always be closed when this method completes, even if * an exception is thrown. * @return The {@code Bundle} object of the installed bundle. * @throws BundleException If the installation failed. BundleException types * thrown by this method include: {@link BundleException#READ_ERROR} * , {@link BundleException#DUPLICATE_BUNDLE_ERROR}, * {@link BundleException#MANIFEST_ERROR}, and * {@link BundleException#REJECTED_BY_HOOK}. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[installed bundle,LIFECYCLE]}, and the Java * Runtime Environment supports permissions. * @throws IllegalStateException If this BundleContext is no longer valid. */ Bundle installBundle(String location, InputStream input) throws BundleException; /** * Installs a bundle from the specified {@code location} identifier. * *

* This method performs the same function as calling * {@link #installBundle(String,InputStream)} with the specified * {@code location} identifier and a {@code null} InputStream. * * @param location The location identifier of the bundle to install. * @return The {@code Bundle} object of the installed bundle. * @throws BundleException If the installation failed. BundleException types * thrown by this method include: {@link BundleException#READ_ERROR} * , {@link BundleException#DUPLICATE_BUNDLE_ERROR}, * {@link BundleException#MANIFEST_ERROR}, and * {@link BundleException#REJECTED_BY_HOOK}. * @throws SecurityException If the caller does not have the appropriate * {@code AdminPermission[installed bundle,LIFECYCLE]}, and the Java * Runtime Environment supports permissions. * @throws IllegalStateException If this BundleContext is no longer valid. * @see #installBundle(String, InputStream) */ Bundle installBundle(String location) throws BundleException; /** * Returns the bundle with the specified identifier. * * @param id The identifier of the bundle to retrieve. * @return A {@code Bundle} object or {@code null} if the identifier does * not match any installed bundle. */ Bundle getBundle(long id); /** * Returns a list of all installed bundles. *

* This method returns a list of all bundles installed in the OSGi * environment at the time of the call to this method. However, since the * Framework is a very dynamic environment, bundles can be installed or * uninstalled at anytime. * * @return An array of {@code Bundle} objects, one object per installed * bundle. */ Bundle[] getBundles(); /** * Adds the specified {@code ServiceListener} object with the specified * {@code filter} to the context bundle's list of listeners. See * {@link Filter} for a description of the filter syntax. * {@code ServiceListener} objects are notified when a service has a * lifecycle state change. * *

* If the context bundle's list of listeners already contains a listener * {@code l} such that {@code (l==listener)}, then this method replaces that * listener's filter (which may be {@code null}) with the specified one * (which may be {@code null}). * *

* The listener is called if the filter criteria is met. To filter based * upon the class of the service, the filter should reference the * {@link Constants#OBJECTCLASS} property. If {@code filter} is {@code null} * , all services are considered to match the filter. * *

* When using a {@code filter}, it is possible that the {@code ServiceEvent} * s for the complete lifecycle of a service will not be delivered to the * listener. For example, if the {@code filter} only matches when the * property {@code x} has the value {@code 1}, the listener will not be * called if the service is registered with the property {@code x} not set * to the value {@code 1}. Subsequently, when the service is modified * setting property {@code x} to the value {@code 1}, the filter will match * and the listener will be called with a {@code ServiceEvent} of type * {@code MODIFIED}. Thus, the listener will not be called with a * {@code ServiceEvent} of type {@code REGISTERED}. * *

* If the Java Runtime Environment supports permissions, the * {@code ServiceListener} object will be notified of a service event only * if the bundle that is registering it has the {@code ServicePermission} to * get the service using at least one of the named classes the service was * registered under. * * @param listener The {@code ServiceListener} object to be added. * @param filter The filter criteria. * @throws InvalidSyntaxException If {@code filter} contains an invalid * filter string that cannot be parsed. * @throws IllegalStateException If this BundleContext is no longer valid. * @see ServiceEvent * @see ServiceListener * @see ServicePermission */ void addServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException; /** * Adds the specified {@code ServiceListener} object to the context bundle's * list of listeners. * *

* This method is the same as calling * {@code BundleContext.addServiceListener(ServiceListener listener, * String filter)} with {@code filter} set to {@code null}. * * @param listener The {@code ServiceListener} object to be added. * @throws IllegalStateException If this BundleContext is no longer valid. * @see #addServiceListener(ServiceListener, String) */ void addServiceListener(ServiceListener listener); /** * Removes the specified {@code ServiceListener} object from the context * bundle's list of listeners. * *

* If {@code listener} is not contained in this context bundle's list of * listeners, this method does nothing. * * @param listener The {@code ServiceListener} to be removed. * @throws IllegalStateException If this BundleContext is no longer valid. */ void removeServiceListener(ServiceListener listener); /** * Adds the specified {@code BundleListener} object to the context bundle's * list of listeners if not already present. BundleListener objects are * notified when a bundle has a lifecycle state change. * *

* If the context bundle's list of listeners already contains a listener * {@code l} such that {@code (l==listener)}, this method does nothing. * * @param listener The {@code BundleListener} to be added. * @throws IllegalStateException If this BundleContext is no longer valid. * @throws SecurityException If listener is a * {@code SynchronousBundleListener} and the caller does not have * the appropriate {@code AdminPermission[context bundle,LISTENER]}, * and the Java Runtime Environment supports permissions. * @see BundleEvent * @see BundleListener */ void addBundleListener(BundleListener listener); /** * Removes the specified {@code BundleListener} object from the context * bundle's list of listeners. * *

* If {@code listener} is not contained in the context bundle's list of * listeners, this method does nothing. * * @param listener The {@code BundleListener} object to be removed. * @throws IllegalStateException If this BundleContext is no longer valid. * @throws SecurityException If listener is a * {@code SynchronousBundleListener} and the caller does not have * the appropriate {@code AdminPermission[context bundle,LISTENER]}, * and the Java Runtime Environment supports permissions. */ void removeBundleListener(BundleListener listener); /** * Adds the specified {@code FrameworkListener} object to the context * bundle's list of listeners if not already present. FrameworkListeners are * notified of general Framework events. * *

* If the context bundle's list of listeners already contains a listener * {@code l} such that {@code (l==listener)}, this method does nothing. * * @param listener The {@code FrameworkListener} object to be added. * @throws IllegalStateException If this BundleContext is no longer valid. * @see FrameworkEvent * @see FrameworkListener */ void addFrameworkListener(FrameworkListener listener); /** * Removes the specified {@code FrameworkListener} object from the context * bundle's list of listeners. * *

* If {@code listener} is not contained in the context bundle's list of * listeners, this method does nothing. * * @param listener The {@code FrameworkListener} object to be removed. * @throws IllegalStateException If this BundleContext is no longer valid. */ void removeFrameworkListener(FrameworkListener listener); /** * Registers the specified service object with the specified properties * under the specified class names into the Framework. A * {@code ServiceRegistration} object is returned. The * {@code ServiceRegistration} object is for the private use of the bundle * registering the service and should not be shared with other bundles. The * registering bundle is defined to be the context bundle. Other bundles can * locate the service by using one of the * {@link #getServiceReferences(Class, String)}, * {@link #getServiceReferences(String, String)}, * {@link #getServiceReference(Class)} or * {@link #getServiceReference(String)} methods. * *

* A bundle can register a service object that implements the * {@link ServiceFactory} interface to have more flexibility in providing * service objects to other bundles. * *

* The following steps are required to register a service: *

    *
  1. If {@code service} is not a {@code ServiceFactory}, an * {@code IllegalArgumentException} is thrown if {@code service} is not an * {@code instanceof} all the specified class names. *
  2. The Framework adds the following service properties to the service * properties from the specified {@code Dictionary} (which may be * {@code null}):
    * A property named {@link Constants#SERVICE_ID} identifying the * registration number of the service
    * A property named {@link Constants#OBJECTCLASS} containing all the * specified classes.
    * Properties with these names in the specified {@code Dictionary} will be * ignored. *
  3. The service is added to the Framework service registry and may now be * used by other bundles. *
  4. A service event of type {@link ServiceEvent#REGISTERED} is fired. *
  5. A {@code ServiceRegistration} object for this registration is * returned. *
* * @param clazzes The class names under which the service can be located. * The class names in this array will be stored in the service's * properties under the key {@link Constants#OBJECTCLASS}. * @param service The service object or a {@code ServiceFactory} object. * @param properties The properties for this service. The keys in the * properties object must all be {@code String} objects. See * {@link Constants} for a list of standard service property keys. * Changes should not be made to this object after calling this * method. To update the service's properties the * {@link ServiceRegistration#setProperties(Dictionary)} method must * be called. The set of properties may be {@code null} if the * service has no properties. * @return A {@code ServiceRegistration} object for use by the bundle * registering the service to update the service's properties or to * unregister the service. * @throws IllegalArgumentException If one of the following is true: *
    *
  • {@code service} is {@code null}.
  • {@code service} is not a * {@code ServiceFactory} object and is not an instance of all the * named classes in {@code clazzes}.
  • {@code properties} * contains case variants of the same key name. *
* @throws SecurityException If the caller does not have the * {@code ServicePermission} to register the service for all the * named classes and the Java Runtime Environment supports * permissions. * @throws IllegalStateException If this BundleContext is no longer valid. * @see ServiceRegistration * @see ServiceFactory */ ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties); /** * Registers the specified service object with the specified properties * under the specified class name with the Framework. * *

* This method is otherwise identical to * {@link #registerService(String[], Object, Dictionary)} and is provided as * a convenience when {@code service} will only be registered under a single * class name. Note that even in this case the value of the service's * {@link Constants#OBJECTCLASS} property will be an array of string, rather * than just a single string. * * @param clazz The class name under which the service can be located. * @param service The service object or a {@code ServiceFactory} object. * @param properties The properties for this service. * @return A {@code ServiceRegistration} object for use by the bundle * registering the service to update the service's properties or to * unregister the service. * @throws IllegalStateException If this BundleContext is no longer valid. * @see #registerService(String[], Object, Dictionary) */ ServiceRegistration registerService(String clazz, Object service, Dictionary properties); /** * Registers the specified service object with the specified properties * under the name of the specified class with the Framework. * *

* This method is otherwise identical to * {@link #registerService(String, Object, Dictionary)} and is provided to * return a type safe {@code ServiceRegistration}. * * @param Type of Service. * @param clazz The class under whose name the service can be located. * @param service The service object or a {@code ServiceFactory} object. * @param properties The properties for this service. * @return A {@code ServiceRegistration} object for use by the bundle * registering the service to update the service's properties or to * unregister the service. * @throws IllegalStateException If this BundleContext is no longer valid. * @see #registerService(String, Object, Dictionary) * @since 1.6 */ ServiceRegistration registerService(Class clazz, S service, Dictionary properties); /** * Returns an array of {@code ServiceReference} objects. The returned array * of {@code ServiceReference} objects contains services that were * registered under the specified class, match the specified filter * expression, and the packages for the class names under which the services * were registered match the context bundle's packages as defined in * {@link ServiceReference#isAssignableTo(Bundle, String)}. * *

* The list is valid at the time of the call to this method. However since * the Framework is a very dynamic environment, services can be modified or * unregistered at any time. * *

* The specified {@code filter} expression is used to select the registered * services whose service properties contain keys and values which satisfy * the filter expression. See {@link Filter} for a description of the filter * syntax. If the specified {@code filter} is {@code null}, all registered * services are considered to match the filter. If the specified * {@code filter} expression cannot be parsed, an * {@link InvalidSyntaxException} will be thrown with a human readable * message where the filter became unparsable. * *

* The result is an array of {@code ServiceReference} objects for all * services that meet all of the following conditions: *

    *
  • If the specified class name, {@code clazz}, is not {@code null}, the * service must have been registered with the specified class name. The * complete list of class names with which a service was registered is * available from the service's {@link Constants#OBJECTCLASS objectClass} * property. *
  • If the specified {@code filter} is not {@code null}, the filter * expression must match the service. *
  • If the Java Runtime Environment supports permissions, the caller must * have {@code ServicePermission} with the {@code GET} action for at least * one of the class names under which the service was registered. *
  • For each class name with which the service was registered, calling * {@link ServiceReference#isAssignableTo(Bundle, String)} with the context * bundle and the class name on the service's {@code ServiceReference} * object must return {@code true} *
* * @param clazz The class name with which the service was registered or * {@code null} for all services. * @param filter The filter expression or {@code null} for all services. * @return An array of {@code ServiceReference} objects or {@code null} if * no services are registered which satisfy the search. * @throws InvalidSyntaxException If the specified {@code filter} contains * an invalid filter expression that cannot be parsed. * @throws IllegalStateException If this BundleContext is no longer valid. */ ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException; /** * Returns an array of {@code ServiceReference} objects. The returned array * of {@code ServiceReference} objects contains services that were * registered under the specified class and match the specified filter * expression. * *

* The list is valid at the time of the call to this method. However since * the Framework is a very dynamic environment, services can be modified or * unregistered at any time. * *

* The specified {@code filter} expression is used to select the registered * services whose service properties contain keys and values which satisfy * the filter expression. See {@link Filter} for a description of the filter * syntax. If the specified {@code filter} is {@code null}, all registered * services are considered to match the filter. If the specified * {@code filter} expression cannot be parsed, an * {@link InvalidSyntaxException} will be thrown with a human readable * message where the filter became unparsable. * *

* The result is an array of {@code ServiceReference} objects for all * services that meet all of the following conditions: *

    *
  • If the specified class name, {@code clazz}, is not {@code null}, the * service must have been registered with the specified class name. The * complete list of class names with which a service was registered is * available from the service's {@link Constants#OBJECTCLASS objectClass} * property. *
  • If the specified {@code filter} is not {@code null}, the filter * expression must match the service. *
  • If the Java Runtime Environment supports permissions, the caller must * have {@code ServicePermission} with the {@code GET} action for at least * one of the class names under which the service was registered. *
* * @param clazz The class name with which the service was registered or * {@code null} for all services. * @param filter The filter expression or {@code null} for all services. * @return An array of {@code ServiceReference} objects or {@code null} if * no services are registered which satisfy the search. * @throws InvalidSyntaxException If the specified {@code filter} contains * an invalid filter expression that cannot be parsed. * @throws IllegalStateException If this BundleContext is no longer valid. * @since 1.3 */ ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException; /** * Returns a {@code ServiceReference} object for a service that implements * and was registered under the specified class. * *

* The returned {@code ServiceReference} object is valid at the time of the * call to this method. However as the Framework is a very dynamic * environment, services can be modified or unregistered at any time. * *

* This method is the same as calling * {@link #getServiceReferences(String, String)} with a {@code null} filter * expression and then finding the reference with the highest priority. It * is provided as a convenience for when the caller is interested in any * service that implements the specified class. *

* If multiple such services exist, the service with the highest priority is * selected. This priority is defined as the service reference with the * highest ranking (as specified in its {@link Constants#SERVICE_RANKING} * property) is returned. *

* If there is a tie in ranking, the service with the lowest service ID (as * specified in its {@link Constants#SERVICE_ID} property); that is, the * service that was registered first is returned. * * @param clazz The class name with which the service was registered. * @return A {@code ServiceReference} object, or {@code null} if no services * are registered which implement the named class. * @throws IllegalStateException If this BundleContext is no longer valid. * @see #getServiceReferences(String, String) */ ServiceReference getServiceReference(String clazz); /** * Returns a {@code ServiceReference} object for a service that implements * and was registered under the name of the specified class. * *

* The returned {@code ServiceReference} object is valid at the time of the * call to this method. However as the Framework is a very dynamic * environment, services can be modified or unregistered at any time. * *

* This method is the same as calling * {@link #getServiceReferences(Class, String)} with a {@code null} filter * expression. It is provided as a convenience for when the caller is * interested in any service that implements the specified class. *

* If multiple such services exist, the service with the highest ranking (as * specified in its {@link Constants#SERVICE_RANKING} property) is returned. *

* If there is a tie in ranking, the service with the lowest service ID (as * specified in its {@link Constants#SERVICE_ID} property); that is, the * service that was registered first is returned. * * @param Type of Service. * @param clazz The class under whose name the service was registered. Must * not be {@code null}. * @return A {@code ServiceReference} object, or {@code null} if no services * are registered which implement the specified class. * @throws IllegalStateException If this BundleContext is no longer valid. * @see #getServiceReferences(Class, String) * @since 1.6 */ ServiceReference getServiceReference(Class clazz); /** * Returns a collection of {@code ServiceReference} objects. The returned * collection of {@code ServiceReference} objects contains services that * were registered under the name of the specified class, match the * specified filter expression, and the packages for the class names under * which the services were registered match the context bundle's packages as * defined in {@link ServiceReference#isAssignableTo(Bundle, String)}. * *

* The collection is valid at the time of the call to this method. However * since the Framework is a very dynamic environment, services can be * modified or unregistered at any time. * *

* The specified {@code filter} expression is used to select the registered * services whose service properties contain keys and values which satisfy * the filter expression. See {@link Filter} for a description of the filter * syntax. If the specified {@code filter} is {@code null}, all registered * services are considered to match the filter. If the specified * {@code filter} expression cannot be parsed, an * {@link InvalidSyntaxException} will be thrown with a human readable * message where the filter became unparsable. * *

* The result is a collection of {@code ServiceReference} objects for all * services that meet all of the following conditions: *

    *
  • The service must have been registered with the name of the specified * class. The complete list of class names with which a service was * registered is available from the service's {@link Constants#OBJECTCLASS * objectClass} property. *
  • If the specified {@code filter} is not {@code null}, the filter * expression must match the service. *
  • If the Java Runtime Environment supports permissions, the caller must * have {@code ServicePermission} with the {@code GET} action for at least * one of the class names under which the service was registered. *
  • For each class name with which the service was registered, calling * {@link ServiceReference#isAssignableTo(Bundle, String)} with the context * bundle and the class name on the service's {@code ServiceReference} * object must return {@code true} *
* * @param Type of Service * @param clazz The class under whose name the service was registered. Must * not be {@code null}. * @param filter The filter expression or {@code null} for all services. * @return A collection of {@code ServiceReference} objects. May be empty if * no services are registered which satisfy the search. * @throws InvalidSyntaxException If the specified {@code filter} contains * an invalid filter expression that cannot be parsed. * @throws IllegalStateException If this BundleContext is no longer valid. * @since 1.6 */ Collection> getServiceReferences(Class clazz, String filter) throws InvalidSyntaxException; /** * Returns the service object referenced by the specified * {@code ServiceReference} object. *

* A bundle's use of a service is tracked by the bundle's use count of that * service. Each time a service's service object is returned by * {@link #getService(ServiceReference)} the context bundle's use count for * that service is incremented by one. Each time the service is released by * {@link #ungetService(ServiceReference)} the context bundle's use count * for that service is decremented by one. *

* When a bundle's use count for a service drops to zero, the bundle should * no longer use that service. * *

* This method will always return {@code null} when the service associated * with this {@code reference} has been unregistered. * *

* The following steps are required to get the service object: *

    *
  1. If the service has been unregistered, {@code null} is returned. *
  2. If the context bundle's use count for the service is currently zero * and the service was registered with an object implementing the * {@code ServiceFactory} interface, the * {@link ServiceFactory#getService(Bundle, ServiceRegistration)} method is * called to create a service object for the context bundle. If the service * object returned by the {@code ServiceFactory} object is {@code null}, not * an {@code instanceof} all the classes named when the service was * registered or the {@code ServiceFactory} object throws an exception or * will be recursively called for the context bundle, {@code null} is * returned and a Framework event of type {@link FrameworkEvent#ERROR} * containing a {@link ServiceException} describing the error is fired.
    * This service object is cached by the Framework. While the context * bundle's use count for the service is greater than zero, subsequent calls * to get the services's service object for the context bundle will return * the cached service object. *
  3. The context bundle's use count for this service is incremented by * one. *
  4. The service object for the service is returned. *
* * @param Type of Service. * @param reference A reference to the service. * @return A service object for the service associated with * {@code reference} or {@code null} if the service is not * registered, the service object returned by a * {@code ServiceFactory} does not implement the classes under which * it was registered or the {@code ServiceFactory} threw an * exception. * @throws SecurityException If the caller does not have the * {@code ServicePermission} to get the service using at least one * of the named classes the service was registered under and the * Java Runtime Environment supports permissions. * @throws IllegalStateException If this BundleContext is no longer valid. * @throws IllegalArgumentException If the specified * {@code ServiceReference} was not created by the same framework * instance as this {@code BundleContext}. * @see #ungetService(ServiceReference) * @see ServiceFactory */ S getService(ServiceReference reference); /** * Releases the service object referenced by the specified * {@code ServiceReference} object. If the context bundle's use count for * the service is zero, this method returns {@code false}. Otherwise, the * context bundle's use count for the service is decremented by one. * *

* The service's service object should no longer be used and all references * to it should be destroyed when a bundle's use count for the service drops * to zero. * *

* The following steps are required to unget the service object: *

    *
  1. If the context bundle's use count for the service is zero or the * service has been unregistered, {@code false} is returned. *
  2. The context bundle's use count for this service is decremented by * one. *
  3. If the context bundle's use count for the service is currently zero * and the service was registered with a {@code ServiceFactory} object, the * {@link ServiceFactory#ungetService(Bundle, ServiceRegistration, Object)} * method is called to release the service object for the context bundle. *
  4. {@code true} is returned. *
* * @param reference A reference to the service to be released. * @return {@code false} if the context bundle's use count for the service * is zero or if the service has been unregistered; {@code true} * otherwise. * @throws IllegalStateException If this BundleContext is no longer valid. * @throws IllegalArgumentException If the specified * {@code ServiceReference} was not created by the same framework * instance as this {@code BundleContext}. * @see #getService(ServiceReference) * @see ServiceFactory */ boolean ungetService(ServiceReference reference); /** * Creates a {@code File} object for a file in the persistent storage area * provided for the bundle by the Framework. This method will return * {@code null} if the platform does not have file system support. * *

* A {@code File} object for the base directory of the persistent storage * area provided for the context bundle by the Framework can be obtained by * calling this method with an empty string as {@code filename}. * *

* If the Java Runtime Environment supports permissions, the Framework will * ensure that the bundle has the {@code java.io.FilePermission} with * actions {@code read},{@code write},{@code delete} for all files * (recursively) in the persistent storage area provided for the context * bundle. * * @param filename A relative name to the file to be accessed. * @return A {@code File} object that represents the requested file or * {@code null} if the platform does not have file system support. * @throws IllegalStateException If this BundleContext is no longer valid. */ File getDataFile(String filename); /** * Creates a {@code Filter} object. This {@code Filter} object may be used * to match a {@code ServiceReference} object or a {@code Dictionary} * object. * *

* If the filter cannot be parsed, an {@link InvalidSyntaxException} will be * thrown with a human readable message where the filter became unparsable. * * @param filter The filter string. * @return A {@code Filter} object encapsulating the filter string. * @throws InvalidSyntaxException If {@code filter} contains an invalid * filter string that cannot be parsed. * @throws NullPointerException If {@code filter} is null. * @throws IllegalStateException If this BundleContext is no longer valid. * @see "Framework specification for a description of the filter string syntax." * @see FrameworkUtil#createFilter(String) * @since 1.1 */ Filter createFilter(String filter) throws InvalidSyntaxException; /** * Returns the bundle with the specified location. * * @param location The location of the bundle to retrieve. * @return A {@code Bundle} object or {@code null} if the location does not * match any installed bundle. * @since 1.6 */ Bundle getBundle(String location); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/startlevel/0000755000175000017500000000000012475375714025624 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/startlevel/packageinfo0000644000175000017500000000001412346513664030004 0ustar felixfelixversion 1.0 knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/startlevel/BundleStartLevel.java0000644000175000017500000001022612346513664031702 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.startlevel; import org.osgi.framework.Bundle; import org.osgi.framework.BundleReference; /** * Query and modify the start level information for a bundle. The start level * object for a bundle can be obtained by calling {@link Bundle#adapt(Class) * bundle.adapt(BundleStartLevel.class)} on the bundle. * *

* The bundle associated with this BundleStartLevel object can be obtained by * calling {@link BundleReference#getBundle()}. * * @ThreadSafe * @noimplement * @version $Id: 9a000be191fe3cb4ae82535a30940db0340d5356 $ */ public interface BundleStartLevel extends BundleReference { /** * Return the assigned start level value for the bundle. * * @return The start level value of the bundle. * @see #setStartLevel(int) * @throws IllegalStateException If the bundle has been uninstalled. */ int getStartLevel(); /** * Assign a start level value to the bundle. * *

* The bundle will be assigned the specified start level. The start level * value assigned to the bundle will be persistently recorded by the * Framework. *

* If the new start level for the bundle is lower than or equal to the * active start level of the Framework and the bundle's autostart setting * indicates this bundle must be started, the Framework will start the * bundle as described in the {@link Bundle#start(int)} method using the * {@link Bundle#START_TRANSIENT} option. The * {@link Bundle#START_ACTIVATION_POLICY} option must also be used if * {@link #isActivationPolicyUsed()} returns {@code true}. The actual * starting of the bundle must occur asynchronously. *

* If the new start level for the bundle is higher than the active start * level of the Framework, the Framework will stop the bundle as described * in the {@link Bundle#stop(int)} method using the * {@link Bundle#STOP_TRANSIENT} option. The actual stopping of the bundle * must occur asynchronously. * * @param startlevel The new start level for the bundle. * @throws IllegalArgumentException If the specified start level is less * than or equal to zero, or if the bundle is the system bundle. * @throws IllegalStateException If the bundle has been uninstalled. * @throws SecurityException If the caller does not have * {@code AdminPermission[bundle,EXECUTE]} and the Java runtime * environment supports permissions. */ void setStartLevel(int startlevel); /** * Returns whether the bundle's autostart setting indicates it must be * started. *

* The autostart setting of a bundle indicates whether the bundle is to be * started when its start level is reached. * * @return {@code true} if the autostart setting of the bundle indicates it * is to be started. {@code false} otherwise. * @throws IllegalStateException If this bundle has been uninstalled. * @see Bundle#START_TRANSIENT */ boolean isPersistentlyStarted(); /** * Returns whether the bundle's autostart setting indicates that the * activation policy declared in the bundle manifest must be used. *

* The autostart setting of a bundle indicates whether the bundle's declared * activation policy is to be used when the bundle is started. * * @return {@code true} if the bundle's autostart setting indicates the * activation policy declared in the manifest must be used. * {@code false} if the bundle must be eagerly activated. * @throws IllegalStateException If the bundle has been uninstalled. * @see Bundle#START_ACTIVATION_POLICY */ boolean isActivationPolicyUsed(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/startlevel/FrameworkStartLevel.java0000644000175000017500000001537412346513664032437 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2002, 2011). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework.startlevel; import org.osgi.framework.Bundle; import org.osgi.framework.BundleReference; import org.osgi.framework.FrameworkListener; /** * Query and modify the start level information for the framework. The start * level object for the framework can be obtained by calling * {@link Bundle#adapt(Class) bundle.adapt(FrameworkStartLevel.class)} on the * system bundle. Only the system bundle can be adapted to a FrameworkStartLevel * object. * *

* The system bundle associated with this FrameworkStartLevel object can be * obtained by calling {@link BundleReference#getBundle()}. * * @ThreadSafe * @noimplement * @version $Id: 12c6f60842df994c7de2cc3cfd02f791b95fc35b $ */ public interface FrameworkStartLevel extends BundleReference { /** * Return the active start level value of the Framework. * * If the Framework is in the process of changing the start level this * method must return the active start level if this differs from the * requested start level. * * @return The active start level value of the Framework. */ int getStartLevel(); /** * Modify the active start level of the Framework and notify when complete. * *

* The Framework will move to the requested start level. This method will * return immediately to the caller and the start level change will occur * asynchronously on another thread. The specified {@code FrameworkListener} * s are notified, in the order specified, when the start level change is * complete. When the start level change completes normally, each specified * {@code FrameworkListener} will be called with a Framework event of type * {@code FrameworkEvent.STARTLEVEL_CHANGED}. If the start level change does * not complete normally, each specified {@code FrameworkListener} will be * called with a Framework event of type {@code FrameworkEvent.ERROR}. * *

* If the specified start level is higher than the active start level, the * Framework will continue to increase the start level until the Framework * has reached the specified start level. * * At each intermediate start level value on the way to and including the * target start level, the Framework must: *

    *
  1. Change the active start level to the intermediate start level value. *
  2. Start bundles at the intermediate start level whose autostart setting * indicate they must be started. They are started as described in the * {@link Bundle#start(int)} method using the {@link Bundle#START_TRANSIENT} * option. The {@link Bundle#START_ACTIVATION_POLICY} option must also be * used if {@link BundleStartLevel#isActivationPolicyUsed()} returns * {@code true} for the bundle. *
* When this process completes after the specified start level is reached, * the Framework will fire a Framework event of type * {@code FrameworkEvent.STARTLEVEL_CHANGED} to announce it has moved to the * specified start level. * *

* If the specified start level is lower than the active start level, the * Framework will continue to decrease the start level until the Framework * has reached the specified start level. * * At each intermediate start level value on the way to and including the * specified start level, the framework must: *

    *
  1. Stop bundles at the intermediate start level as described in the * {@link Bundle#stop(int)} method using the {@link Bundle#STOP_TRANSIENT} * option. *
  2. Change the active start level to the intermediate start level value. *
* When this process completes after the specified start level is reached, * the Framework will fire a Framework event of type * {@code FrameworkEvent.STARTLEVEL_CHANGED} to announce it has moved to the * specified start level. * *

* If the specified start level is equal to the active start level, then no * bundles are started or stopped, however, the Framework must fire a * Framework event of type {@code FrameworkEvent.STARTLEVEL_CHANGED} to * announce it has finished moving to the specified start level. This event * may arrive before this method returns. * * @param startlevel The requested start level for the Framework. * @param listeners Zero or more listeners to be notified when the start * level change has been completed. The specified listeners do not * need to be otherwise registered with the framework. If a specified * listener is already registered with the framework, it will be * notified twice. * @throws IllegalArgumentException If the specified start level is less * than or equal to zero. * @throws SecurityException If the caller does not have * {@code AdminPermission[System Bundle,STARTLEVEL]} and the Java * runtime environment supports permissions. */ void setStartLevel(int startlevel, FrameworkListener... listeners); /** * Return the initial start level value that is assigned to a Bundle when it * is first installed. * * @return The initial start level value for Bundles. * @see #setInitialBundleStartLevel(int) */ int getInitialBundleStartLevel(); /** * Set the initial start level value that is assigned to a Bundle when it is * first installed. * *

* The initial bundle start level will be set to the specified start level. * The initial bundle start level value will be persistently recorded by the * Framework. * *

* When a Bundle is installed via {@code BundleContext.installBundle}, it is * assigned the initial bundle start level value. * *

* The default initial bundle start level value is 1 unless this method has * been called to assign a different initial bundle start level value. * *

* This method does not change the start level values of installed bundles. * * @param startlevel The initial start level for newly installed bundles. * @throws IllegalArgumentException If the specified start level is less * than or equal to zero. * @throws SecurityException If the caller does not have * {@code AdminPermission[System Bundle,STARTLEVEL]} and the Java * runtime environment supports permissions. */ void setInitialBundleStartLevel(int startlevel); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/startlevel/package-info.java0000644000175000017500000000657312346513664031021 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Framework Start Level Package Version 1.0. * *

* The Framework Start Level package allows management agents to manage a start * level assigned to each bundle and the active start level of the Framework. * This package is a replacement for the now deprecated * {@code org.osgi.service.startlevel} package. * *

* A start level is defined to be a state of execution in which the Framework * exists. Start level values are defined as unsigned integers with 0 (zero) * being the state where the Framework is not launched. Progressively higher * integral values represent progressively higher start levels. For example, 2 * is a higher start level than 1. * *

* {@code AdminPermission} is required to modify start level information. * *

* Start Level support in the Framework includes the ability to modify the * active start level of the Framework and to assign a specific start level to a * bundle. The beginning start level of a Framework is specified via the * {@link org.osgi.framework.Constants#FRAMEWORK_BEGINNING_STARTLEVEL} framework * property when configuring a framework. * *

* When the Framework is first started it must be at start level zero. In this * state, no bundles are running. This is the initial state of the Framework * before it is launched. When the Framework is launched, the Framework will * enter start level one and all bundles which are assigned to start level one * and whose autostart setting indicates the bundle should be started are * started as described in the {@link org.osgi.framework.Bundle#start(int)} * method. The Framework will continue to increase the start level, starting * bundles at each start level, until the Framework has reached a beginning * start level. At this point the Framework has completed starting bundles and * will then fire a Framework event of type * {@link org.osgi.framework.FrameworkEvent#STARTED} to announce it has * completed its launch. * *

* Within a start level, bundles may be started in an order defined by the * Framework implementation. This may be something like ascending * {@link org.osgi.framework.Bundle#getBundleId()} order or an order based upon * dependencies between bundles. A similar but reversed order may be used when * stopping bundles within a start level. * *

* The Framework Start Level package can be used by management bundles to alter * the active start level of the framework. * *

* Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. For example: * *

 * Import-Package: org.osgi.framework.startlevel; version="[1.0,2.0)"
 * 
* * @version $Id: 78bab33a230f0d6ee1de30fcac7ff6eaa04f0a52 $ */ package org.osgi.framework.startlevel; knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/BundleActivator.java0000644000175000017500000000706412346513664027372 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; /** * Customizes the starting and stopping of a bundle. *

* {@code BundleActivator} is an interface that may be implemented when a bundle * is started or stopped. The Framework can create instances of a bundle's * {@code BundleActivator} as required. If an instance's * {@code BundleActivator.start} method executes successfully, it is guaranteed * that the same instance's {@code BundleActivator.stop} method will be called * when the bundle is to be stopped. The Framework must not concurrently call a * {@code BundleActivator} object. * *

* {@code BundleActivator} is specified through the {@code Bundle-Activator} * Manifest header. A bundle can only specify a single {@code BundleActivator} * in the Manifest file. Fragment bundles must not have a * {@code BundleActivator}. The form of the Manifest header is: * *

* {@code Bundle-Activator: class-name} * *

* where {@code class-name} is a fully qualified Java classname. *

* The specified {@code BundleActivator} class must have a public constructor * that takes no parameters so that a {@code BundleActivator} object can be * created by {@code Class.newInstance()}. * * @NotThreadSafe * @version $Id: f5b2debe0064ab60669102d0a087feaeab13dc0e $ */ public interface BundleActivator { /** * Called when this bundle is started so the Framework can perform the * bundle-specific activities necessary to start this bundle. This method * can be used to register services or to allocate any resources that this * bundle needs. * *

* This method must complete and return to its caller in a timely manner. * * @param context The execution context of the bundle being started. * @throws Exception If this method throws an exception, this bundle is * marked as stopped and the Framework will remove this bundle's * listeners, unregister all services registered by this bundle, and * release all services used by this bundle. */ public void start(BundleContext context) throws Exception; /** * Called when this bundle is stopped so the Framework can perform the * bundle-specific activities necessary to stop the bundle. In general, this * method should undo the work that the {@code BundleActivator.start} method * started. There should be no active threads that were started by this * bundle when this bundle returns. A stopped bundle must not call any * Framework objects. * *

* This method must complete and return to its caller in a timely manner. * * @param context The execution context of the bundle being stopped. * @throws Exception If this method throws an exception, the bundle is still * marked as stopped, and the Framework will remove the bundle's * listeners, unregister all services registered by the bundle, and * release all services used by the bundle. */ public void stop(BundleContext context) throws Exception; } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/UnfilteredServiceListener.java0000644000175000017500000000637112346513664031434 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2011). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import org.osgi.framework.hooks.service.ListenerHook; /** * A {@code ServiceEvent} listener that does not filter based upon any * filter string specified to * {@link BundleContext#addServiceListener(ServiceListener, String)}. Using an * {@code UnfilteredServiceListener} and specifying a filter string to * {@link BundleContext#addServiceListener(ServiceListener, String)} allows the * listener to receive all {@code ServiceEvent} objects while still advising * {@link ListenerHook} implementation of the service interests in the filter * string. * * For example, an implementation of Declarative Services would add an * {@code UnfilteredServiceListener} with a filter string listing all the * services referenced by all the service components. The Declarative Services * implementation would receive all {@code ServiceEvent} objects for internal * processing and a Remote Services discovery service implementation can observe * the service interests of the service components using a {@link ListenerHook}. * When the set of service components being processed changes, the Declarative * Services implementation would re-add the {@code UnfilteredServiceListener} * with an updated filter string. * *

* When a {@code ServiceEvent} is fired, it is synchronously delivered to an * {@code UnfilteredServiceListener}. The Framework may deliver * {@code ServiceEvent} objects to an {@code UnfilteredServiceListener} out of * order and may concurrently call and/or reenter an * {@code UnfilteredServiceListener}. * *

* An {@code UnfilteredServiceListener} object is registered with the Framework * using the {@code BundleContext.addServiceListener} method. * {@code UnfilteredServiceListener} objects are called with a * {@code ServiceEvent} object when a service is registered, modified, or is in * the process of unregistering. * *

* {@code ServiceEvent} object delivery to {@code UnfilteredServiceListener} * objects are not filtered by the filter specified when the listener was * registered. If the Java Runtime Environment supports permissions, then some * filtering is done. {@code ServiceEvent} objects are only delivered to the * listener if the bundle which defines the listener object's class has the * appropriate {@code ServicePermission} to get the service using at least one * of the named classes under which the service was registered. * * @see ServiceEvent * @see ServicePermission * @ThreadSafe * @since 1.7 * @version $Id: 543a345802f8dc7a49d29e8fb7aee7004ee2b329 $ */ public interface UnfilteredServiceListener extends ServiceListener { // This is a marker interface } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/FrameworkUtil.java0000644000175000017500000017021012346513664027071 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2005, 2013). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.Dictionary; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.security.auth.x500.X500Principal; /** * Framework Utility class. * *

* This class contains utility methods which access Framework functions that may * be useful to bundles. * * @since 1.3 * @ThreadSafe * @author $Id: e93d15cef98c0e7f425f3b076d317c46ebb9a52a $ */ public class FrameworkUtil { /** * FrameworkUtil objects may not be constructed. */ private FrameworkUtil() { // private empty constructor to prevent construction } /** * Creates a {@code Filter} object. This {@code Filter} object may be used * to match a {@code ServiceReference} object or a {@code Dictionary} * object. * *

* If the filter cannot be parsed, an {@link InvalidSyntaxException} will be * thrown with a human readable message where the filter became unparsable. * *

* This method returns a Filter implementation which may not perform as well * as the framework implementation-specific Filter implementation returned * by {@link BundleContext#createFilter(String)}. * * @param filter The filter string. * @return A {@code Filter} object encapsulating the filter string. * @throws InvalidSyntaxException If {@code filter} contains an invalid * filter string that cannot be parsed. * @throws NullPointerException If {@code filter} is null. * * @see Filter */ public static Filter createFilter(String filter) throws InvalidSyntaxException { return FilterImpl.newInstance(filter); } /** * Match a Distinguished Name (DN) chain against a pattern. DNs can be * matched using wildcards. A wildcard ({@code '*'} \u002A) replaces all * possible values. Due to the structure of the DN, the comparison is more * complicated than string-based wildcard matching. *

* A wildcard can stand for zero or more DNs in a chain, a number of * relative distinguished names (RDNs) within a DN, or the value of a single * RDN. The DNs in the chain and the matching pattern are canonicalized * before processing. This means, among other things, that spaces must be * ignored, except in values. *

* The format of a wildcard match pattern is: * *

	 * matchPattern ::= dn-match ( ';' dn-match ) *
	 * dn-match     ::= ( '*' | rdn-match ) ( ',' rdn-match ) * | '-'
	 * rdn-match    ::= name '=' value-match
	 * value-match  ::= '*' | value-star
	 * value-star   ::= < value, requires escaped '*' and '-' >
	 * 
*

* The most simple case is a single wildcard; it must match any DN. A * wildcard can also replace the first list of RDNs of a DN. The first RDNs * are the least significant. Such lists of matched RDNs can be empty. *

* For example, a match pattern with a wildcard that matches all DNs that * end with RDNs of o=ACME and c=US would look like this: * *

	 * *, o=ACME, c=US
	 * 
* * This match pattern would match the following DNs: * *
	 * cn = Bugs Bunny, o = ACME, c = US
	 * ou = Carrots, cn=Daffy Duck, o=ACME, c=US
	 * street = 9C\, Avenue St. Drézéry, o=ACME, c=US
	 * dc=www, dc=acme, dc=com, o=ACME, c=US
	 * o=ACME, c=US
	 * 
* * The following DNs would not match: * *
	 * street = 9C\, Avenue St. Drézéry, o=ACME, c=FR
	 * dc=www, dc=acme, dc=com, c=US
	 * 
* * If a wildcard is used for a value of an RDN, the value must be exactly *. * The wildcard must match any value, and no substring matching must be * done. For example: * *
	 * cn=*,o=ACME,c=*
	 * 
* * This match pattern with wildcard must match the following DNs: * *
	 * cn=Bugs Bunny,o=ACME,c=US
	 * cn = Daffy Duck , o = ACME , c = US
	 * cn=Road Runner, o=ACME, c=NL
	 * 
* * But not: * *
	 * o=ACME, c=NL
	 * dc=acme.com, cn=Bugs Bunny, o=ACME, c=US
	 * 
* *

* A match pattern may contain a chain of DN match patterns. The semicolon( * {@code ';'} \u003B) must be used to separate DN match patterns in a * chain. Wildcards can also be used to match against a complete DN within a * chain. *

* The following example matches a certificate signed by Tweety Inc. in the * US. *

* *
	 * * ; ou=S & V, o=Tweety Inc., c=US
	 * 
*

* The wildcard ('*') matches zero or one DN in the chain, however, * sometimes it is necessary to match a longer chain. The minus sign ( * {@code '-'} \u002D) represents zero or more DNs, whereas the asterisk * only represents a single DN. For example, to match a DN where the Tweety * Inc. is in the DN chain, use the following expression: *

* *
	 * - ; *, o=Tweety Inc., c=US
	 * 
* * @param matchPattern The pattern against which to match the DN chain. * @param dnChain The DN chain to match against the specified pattern. Each * element of the chain must be of type {@code String} and use the * format defined in RFC 2253. * @return {@code true} If the pattern matches the DN chain; otherwise * {@code false} is returned. * @throws IllegalArgumentException If the specified match pattern or DN * chain is invalid. * @since 1.5 */ public static boolean matchDistinguishedNameChain(String matchPattern, List dnChain) { return DNChainMatching.match(matchPattern, dnChain); } /** * Return a {@code Bundle} for the specified bundle class. The returned * {@code Bundle} is the bundle associated with the bundle class loader * which defined the specified class. * * @param classFromBundle A class defined by a bundle class loader. * @return A {@code Bundle} for the specified bundle class or {@code null} * if the specified class was not defined by a bundle class loader. * @since 1.5 */ public static Bundle getBundle(final Class classFromBundle) { // We use doPriv since the caller may not have permission // to call getClassLoader. Object cl = AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return classFromBundle.getClassLoader(); } }); if (cl instanceof BundleReference) { return ((BundleReference) cl).getBundle(); } return null; } /** * RFC 1960-based Filter. Filter objects can be created by calling the * constructor with the desired filter string. A Filter object can be called * numerous times to determine if the match argument matches the filter * string that was used to create the Filter object. * *

* The syntax of a filter string is the string representation of LDAP search * filters as defined in RFC 1960: A String Representation of LDAP Search * Filters (available at http://www.ietf.org/rfc/rfc1960.txt). It should * be noted that RFC 2254: A String Representation of LDAP Search * Filters (available at http://www.ietf.org/rfc/rfc2254.txt) supersedes * RFC 1960 but only adds extensible matching and is not applicable for this * API. * *

* The string representation of an LDAP search filter is defined by the * following grammar. It uses a prefix format. * *

	 *   <filter> ::= '(' <filtercomp> ')'
	 *   <filtercomp> ::= <and> | <or> | <not> | <item>
	 *   <and> ::= '&' <filterlist>
	 *   <or> ::= '|' <filterlist>
	 *   <not> ::= '!' <filter>
	 *   <filterlist> ::= <filter> | <filter> <filterlist>
	 *   <item> ::= <simple> | <present> | <substring>
	 *   <simple> ::= <attr> <filtertype> <value>
	 *   <filtertype> ::= <equal> | <approx> | <greater> | <less>
	 *   <equal> ::= '='
	 *   <approx> ::= '˜='
	 *   <greater> ::= '>='
	 *   <less> ::= '<='
	 *   <present> ::= <attr> '=*'
	 *   <substring> ::= <attr> '=' <initial> <any> <final>
	 *   <initial> ::= NULL | <value>
	 *   <any> ::= '*' <starval>
	 *   <starval> ::= NULL | <value> '*' <starval>
	 *   <final> ::= NULL | <value>
	 * 
* * {@code <attr>} is a string representing an attribute, or key, in * the properties objects of the registered services. Attribute names are * not case sensitive; that is cn and CN both refer to the same attribute. * {@code <value>} is a string representing the value, or part of one, * of a key in the properties objects of the registered services. If a * {@code <value>} must contain one of the characters ' {@code *}' or * '{@code (}' or '{@code )}', these characters should be escaped by * preceding them with the backslash '{@code \}' character. Note that * although both the {@code <substring>} and {@code <present>} * productions can produce the {@code 'attr=*'} construct, this construct is * used only to denote a presence filter. * *

* Examples of LDAP filters are: * *

	 *   "(cn=Babs Jensen)"
	 *   "(!(cn=Tim Howes))"
	 *   "(&(" + Constants.OBJECTCLASS + "=Person)(|(sn=Jensen)(cn=Babs J*)))"
	 *   "(o=univ*of*mich*)"
	 * 
* *

* The approximate match ({@code ~=}) is implementation specific but should * at least ignore case and white space differences. Optional are codes like * soundex or other smart "closeness" comparisons. * *

* Comparison of values is not straightforward. Strings are compared * differently than numbers and it is possible for a key to have multiple * values. Note that that keys in the match argument must always be strings. * The comparison is defined by the object type of the key's value. The * following rules apply for comparison: * *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Property Value Type Comparison Type
StringString comparison
Integer, Long, Float, Double, Byte, Short, BigInteger, BigDecimalnumerical comparison
Charactercharacter comparison
Booleanequality comparisons only
[] (array)recursively applied to values
Collectionrecursively applied to values
* Note: arrays of primitives are also supported.
* * A filter matches a key that has multiple values if it matches at least * one of those values. For example, * *
	 * Dictionary d = new Hashtable();
	 * d.put("cn", new String[] {"a", "b", "c"});
	 * 
* * d will match {@code (cn=a)} and also {@code (cn=b)} * *

* A filter component that references a key having an unrecognizable data * type will evaluate to {@code false} . */ static private final class FilterImpl implements Filter { /* filter operators */ private static final int EQUAL = 1; private static final int APPROX = 2; private static final int GREATER = 3; private static final int LESS = 4; private static final int PRESENT = 5; private static final int SUBSTRING = 6; private static final int AND = 7; private static final int OR = 8; private static final int NOT = 9; /** filter operation */ private final int op; /** filter attribute or null if operation AND, OR or NOT */ private final String attr; /** filter operands */ private final Object value; /* normalized filter string for Filter object */ private transient String filterString; /** * Constructs a {@link FilterImpl} object. This filter object may be * used to match a {@link ServiceReference} or a Dictionary. * *

* If the filter cannot be parsed, an {@link InvalidSyntaxException} * will be thrown with a human readable message where the filter became * unparsable. * * @param filterString the filter string. * @throws InvalidSyntaxException If the filter parameter contains an * invalid filter string that cannot be parsed. */ static FilterImpl newInstance(String filterString) throws InvalidSyntaxException { return new Parser(filterString).parse(); } FilterImpl(int operation, String attr, Object value) { this.op = operation; this.attr = attr; this.value = value; filterString = null; } /** * Filter using a service's properties. *

* This {@code Filter} is executed using the keys and values of the * referenced service's properties. The keys are looked up in a case * insensitive manner. * * @param reference The reference to the service whose properties are * used in the match. * @return {@code true} if the service's properties match this * {@code Filter}; {@code false} otherwise. */ public boolean match(ServiceReference reference) { return matches(new ServiceReferenceMap(reference)); } /** * Filter using a {@code Dictionary} with case insensitive key lookup. * This {@code Filter} is executed using the specified * {@code Dictionary}'s keys and values. The keys are looked up in a * case insensitive manner. * * @param dictionary The {@code Dictionary} whose key/value pairs are * used in the match. * @return {@code true} if the {@code Dictionary}'s values match this * filter; {@code false} otherwise. * @throws IllegalArgumentException If {@code dictionary} contains case * variants of the same key name. */ public boolean match(Dictionary dictionary) { return matches(new CaseInsensitiveMap(dictionary)); } /** * Filter using a {@code Dictionary}. This {@code Filter} is executed * using the specified {@code Dictionary}'s keys and values. The keys * are looked up in a normal manner respecting case. * * @param dictionary The {@code Dictionary} whose key/value pairs are * used in the match. * @return {@code true} if the {@code Dictionary}'s values match this * filter; {@code false} otherwise. * @since 1.3 */ public boolean matchCase(Dictionary dictionary) { switch (op) { case AND : { FilterImpl[] filters = (FilterImpl[]) value; for (FilterImpl f : filters) { if (!f.matchCase(dictionary)) { return false; } } return true; } case OR : { FilterImpl[] filters = (FilterImpl[]) value; for (FilterImpl f : filters) { if (f.matchCase(dictionary)) { return true; } } return false; } case NOT : { FilterImpl filter = (FilterImpl) value; return !filter.matchCase(dictionary); } case SUBSTRING : case EQUAL : case GREATER : case LESS : case APPROX : { Object prop = (dictionary == null) ? null : dictionary.get(attr); return compare(op, prop, value); } case PRESENT : { Object prop = (dictionary == null) ? null : dictionary.get(attr); return prop != null; } } return false; } /** * Filter using a {@code Map}. This {@code Filter} is executed using the * specified {@code Map}'s keys and values. The keys are looked up in a * normal manner respecting case. * * @param map The {@code Map} whose key/value pairs are used in the * match. Maps with {@code null} key or values are not supported. * A {@code null} value is considered not present to the filter. * @return {@code true} if the {@code Map}'s values match this filter; * {@code false} otherwise. * @since 1.6 */ public boolean matches(Map map) { switch (op) { case AND : { FilterImpl[] filters = (FilterImpl[]) value; for (FilterImpl f : filters) { if (!f.matches(map)) { return false; } } return true; } case OR : { FilterImpl[] filters = (FilterImpl[]) value; for (FilterImpl f : filters) { if (f.matches(map)) { return true; } } return false; } case NOT : { FilterImpl filter = (FilterImpl) value; return !filter.matches(map); } case SUBSTRING : case EQUAL : case GREATER : case LESS : case APPROX : { Object prop = (map == null) ? null : map.get(attr); return compare(op, prop, value); } case PRESENT : { Object prop = (map == null) ? null : map.get(attr); return prop != null; } } return false; } /** * Returns this {@code Filter}'s filter string. *

* The filter string is normalized by removing whitespace which does not * affect the meaning of the filter. * * @return This {@code Filter}'s filter string. */ @Override public String toString() { String result = filterString; if (result == null) { filterString = result = normalize().toString(); } return result; } /** * Returns this {@code Filter}'s normalized filter string. *

* The filter string is normalized by removing whitespace which does not * affect the meaning of the filter. * * @return This {@code Filter}'s filter string. */ private StringBuffer normalize() { StringBuffer sb = new StringBuffer(); sb.append('('); switch (op) { case AND : { sb.append('&'); FilterImpl[] filters = (FilterImpl[]) value; for (FilterImpl f : filters) { sb.append(f.normalize()); } break; } case OR : { sb.append('|'); FilterImpl[] filters = (FilterImpl[]) value; for (FilterImpl f : filters) { sb.append(f.normalize()); } break; } case NOT : { sb.append('!'); FilterImpl filter = (FilterImpl) value; sb.append(filter.normalize()); break; } case SUBSTRING : { sb.append(attr); sb.append('='); String[] substrings = (String[]) value; for (String substr : substrings) { if (substr == null) /* * */{ sb.append('*'); } else /* xxx */{ sb.append(encodeValue(substr)); } } break; } case EQUAL : { sb.append(attr); sb.append('='); sb.append(encodeValue((String) value)); break; } case GREATER : { sb.append(attr); sb.append(">="); sb.append(encodeValue((String) value)); break; } case LESS : { sb.append(attr); sb.append("<="); sb.append(encodeValue((String) value)); break; } case APPROX : { sb.append(attr); sb.append("~="); sb.append(encodeValue(approxString((String) value))); break; } case PRESENT : { sb.append(attr); sb.append("=*"); break; } } sb.append(')'); return sb; } /** * Compares this {@code Filter} to another {@code Filter}. * *

* This implementation returns the result of calling * {@code this.toString().equals(obj.toString()}. * * @param obj The object to compare against this {@code Filter}. * @return If the other object is a {@code Filter} object, then returns * the result of calling * {@code this.toString().equals(obj.toString()}; {@code false} * otherwise. */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof Filter)) { return false; } return this.toString().equals(obj.toString()); } /** * Returns the hashCode for this {@code Filter}. * *

* This implementation returns the result of calling * {@code this.toString().hashCode()}. * * @return The hashCode of this {@code Filter}. */ @Override public int hashCode() { return this.toString().hashCode(); } /** * Encode the value string such that '(', '*', ')' and '\' are escaped. * * @param value unencoded value string. * @return encoded value string. */ private static String encodeValue(String value) { boolean encoded = false; int inlen = value.length(); int outlen = inlen << 1; /* inlen 2 */ char[] output = new char[outlen]; value.getChars(0, inlen, output, inlen); int cursor = 0; for (int i = inlen; i < outlen; i++) { char c = output[i]; switch (c) { case '(' : case '*' : case ')' : case '\\' : { output[cursor] = '\\'; cursor++; encoded = true; break; } } output[cursor] = c; cursor++; } return encoded ? new String(output, 0, cursor) : value; } private boolean compare(int operation, Object value1, Object value2) { if (value1 == null) { return false; } if (value1 instanceof String) { return compare_String(operation, (String) value1, value2); } Class clazz = value1.getClass(); if (clazz.isArray()) { Class type = clazz.getComponentType(); if (type.isPrimitive()) { return compare_PrimitiveArray(operation, type, value1, value2); } return compare_ObjectArray(operation, (Object[]) value1, value2); } if (value1 instanceof Collection) { return compare_Collection(operation, (Collection) value1, value2); } if (value1 instanceof Integer) { return compare_Integer(operation, ((Integer) value1).intValue(), value2); } if (value1 instanceof Long) { return compare_Long(operation, ((Long) value1).longValue(), value2); } if (value1 instanceof Byte) { return compare_Byte(operation, ((Byte) value1).byteValue(), value2); } if (value1 instanceof Short) { return compare_Short(operation, ((Short) value1).shortValue(), value2); } if (value1 instanceof Character) { return compare_Character(operation, ((Character) value1).charValue(), value2); } if (value1 instanceof Float) { return compare_Float(operation, ((Float) value1).floatValue(), value2); } if (value1 instanceof Double) { return compare_Double(operation, ((Double) value1).doubleValue(), value2); } if (value1 instanceof Boolean) { return compare_Boolean(operation, ((Boolean) value1).booleanValue(), value2); } if (value1 instanceof Comparable) { @SuppressWarnings("unchecked") Comparable comparable = (Comparable) value1; return compare_Comparable(operation, comparable, value2); } return compare_Unknown(operation, value1, value2); } private boolean compare_Collection(int operation, Collection collection, Object value2) { for (Object value1 : collection) { if (compare(operation, value1, value2)) { return true; } } return false; } private boolean compare_ObjectArray(int operation, Object[] array, Object value2) { for (Object value1 : array) { if (compare(operation, value1, value2)) { return true; } } return false; } private boolean compare_PrimitiveArray(int operation, Class type, Object primarray, Object value2) { if (Integer.TYPE.isAssignableFrom(type)) { int[] array = (int[]) primarray; for (int value1 : array) { if (compare_Integer(operation, value1, value2)) { return true; } } return false; } if (Long.TYPE.isAssignableFrom(type)) { long[] array = (long[]) primarray; for (long value1 : array) { if (compare_Long(operation, value1, value2)) { return true; } } return false; } if (Byte.TYPE.isAssignableFrom(type)) { byte[] array = (byte[]) primarray; for (byte value1 : array) { if (compare_Byte(operation, value1, value2)) { return true; } } return false; } if (Short.TYPE.isAssignableFrom(type)) { short[] array = (short[]) primarray; for (short value1 : array) { if (compare_Short(operation, value1, value2)) { return true; } } return false; } if (Character.TYPE.isAssignableFrom(type)) { char[] array = (char[]) primarray; for (char value1 : array) { if (compare_Character(operation, value1, value2)) { return true; } } return false; } if (Float.TYPE.isAssignableFrom(type)) { float[] array = (float[]) primarray; for (float value1 : array) { if (compare_Float(operation, value1, value2)) { return true; } } return false; } if (Double.TYPE.isAssignableFrom(type)) { double[] array = (double[]) primarray; for (double value1 : array) { if (compare_Double(operation, value1, value2)) { return true; } } return false; } if (Boolean.TYPE.isAssignableFrom(type)) { boolean[] array = (boolean[]) primarray; for (boolean value1 : array) { if (compare_Boolean(operation, value1, value2)) { return true; } } return false; } return false; } private boolean compare_String(int operation, String string, Object value2) { switch (operation) { case SUBSTRING : { String[] substrings = (String[]) value2; int pos = 0; for (int i = 0, size = substrings.length; i < size; i++) { String substr = substrings[i]; if (i + 1 < size) /* if this is not that last substr */{ if (substr == null) /* * */{ String substr2 = substrings[i + 1]; if (substr2 == null) /* ** */ continue; /* ignore first star */ /* xxx */ int index = string.indexOf(substr2, pos); if (index == -1) { return false; } pos = index + substr2.length(); if (i + 2 < size) // if there are more // substrings, increment // over the string we just // matched; otherwise need // to do the last substr // check i++; } else /* xxx */{ int len = substr.length(); if (string.regionMatches(pos, substr, 0, len)) { pos += len; } else { return false; } } } else /* last substr */{ if (substr == null) /* * */{ return true; } /* xxx */ return string.endsWith(substr); } } return true; } case EQUAL : { return string.equals(value2); } case APPROX : { string = approxString(string); String string2 = approxString((String) value2); return string.equalsIgnoreCase(string2); } case GREATER : { return string.compareTo((String) value2) >= 0; } case LESS : { return string.compareTo((String) value2) <= 0; } } return false; } private boolean compare_Integer(int operation, int intval, Object value2) { if (operation == SUBSTRING) { return false; } int intval2; try { intval2 = Integer.parseInt(((String) value2).trim()); } catch (IllegalArgumentException e) { return false; } switch (operation) { case APPROX : case EQUAL : { return intval == intval2; } case GREATER : { return intval >= intval2; } case LESS : { return intval <= intval2; } } return false; } private boolean compare_Long(int operation, long longval, Object value2) { if (operation == SUBSTRING) { return false; } long longval2; try { longval2 = Long.parseLong(((String) value2).trim()); } catch (IllegalArgumentException e) { return false; } switch (operation) { case APPROX : case EQUAL : { return longval == longval2; } case GREATER : { return longval >= longval2; } case LESS : { return longval <= longval2; } } return false; } private boolean compare_Byte(int operation, byte byteval, Object value2) { if (operation == SUBSTRING) { return false; } byte byteval2; try { byteval2 = Byte.parseByte(((String) value2).trim()); } catch (IllegalArgumentException e) { return false; } switch (operation) { case APPROX : case EQUAL : { return byteval == byteval2; } case GREATER : { return byteval >= byteval2; } case LESS : { return byteval <= byteval2; } } return false; } private boolean compare_Short(int operation, short shortval, Object value2) { if (operation == SUBSTRING) { return false; } short shortval2; try { shortval2 = Short.parseShort(((String) value2).trim()); } catch (IllegalArgumentException e) { return false; } switch (operation) { case APPROX : case EQUAL : { return shortval == shortval2; } case GREATER : { return shortval >= shortval2; } case LESS : { return shortval <= shortval2; } } return false; } private boolean compare_Character(int operation, char charval, Object value2) { if (operation == SUBSTRING) { return false; } char charval2; try { charval2 = ((String) value2).charAt(0); } catch (IndexOutOfBoundsException e) { return false; } switch (operation) { case EQUAL : { return charval == charval2; } case APPROX : { return (charval == charval2) || (Character.toUpperCase(charval) == Character.toUpperCase(charval2)) || (Character.toLowerCase(charval) == Character.toLowerCase(charval2)); } case GREATER : { return charval >= charval2; } case LESS : { return charval <= charval2; } } return false; } private boolean compare_Boolean(int operation, boolean boolval, Object value2) { if (operation == SUBSTRING) { return false; } boolean boolval2 = Boolean.valueOf(((String) value2).trim()).booleanValue(); switch (operation) { case APPROX : case EQUAL : case GREATER : case LESS : { return boolval == boolval2; } } return false; } private boolean compare_Float(int operation, float floatval, Object value2) { if (operation == SUBSTRING) { return false; } float floatval2; try { floatval2 = Float.parseFloat(((String) value2).trim()); } catch (IllegalArgumentException e) { return false; } switch (operation) { case APPROX : case EQUAL : { return Float.compare(floatval, floatval2) == 0; } case GREATER : { return Float.compare(floatval, floatval2) >= 0; } case LESS : { return Float.compare(floatval, floatval2) <= 0; } } return false; } private boolean compare_Double(int operation, double doubleval, Object value2) { if (operation == SUBSTRING) { return false; } double doubleval2; try { doubleval2 = Double.parseDouble(((String) value2).trim()); } catch (IllegalArgumentException e) { return false; } switch (operation) { case APPROX : case EQUAL : { return Double.compare(doubleval, doubleval2) == 0; } case GREATER : { return Double.compare(doubleval, doubleval2) >= 0; } case LESS : { return Double.compare(doubleval, doubleval2) <= 0; } } return false; } private static Object valueOf(Class target, String value2) { do { Method method; try { method = target.getMethod("valueOf", String.class); } catch (NoSuchMethodException e) { break; } if (Modifier.isStatic(method.getModifiers()) && target.isAssignableFrom(method.getReturnType())) { setAccessible(method); try { return method.invoke(null, value2.trim()); } catch (IllegalAccessException e) { return null; } catch (InvocationTargetException e) { return null; } } } while (false); do { Constructor constructor; try { constructor = target.getConstructor(String.class); } catch (NoSuchMethodException e) { break; } setAccessible(constructor); try { return constructor.newInstance(value2.trim()); } catch (IllegalAccessException e) { return null; } catch (InvocationTargetException e) { return null; } catch (InstantiationException e) { return null; } } while (false); return null; } private static void setAccessible(AccessibleObject accessible) { if (!accessible.isAccessible()) { AccessController.doPrivileged(new SetAccessibleAction(accessible)); } } private boolean compare_Comparable(int operation, Comparable value1, Object value2) { if (operation == SUBSTRING) { return false; } value2 = valueOf(value1.getClass(), (String) value2); if (value2 == null) { return false; } try { switch (operation) { case APPROX : case EQUAL : { return value1.compareTo(value2) == 0; } case GREATER : { return value1.compareTo(value2) >= 0; } case LESS : { return value1.compareTo(value2) <= 0; } } } catch (Exception e) { // if the compareTo method throws an exception; return false return false; } return false; } private boolean compare_Unknown(int operation, Object value1, Object value2) { if (operation == SUBSTRING) { return false; } value2 = valueOf(value1.getClass(), (String) value2); if (value2 == null) { return false; } try { switch (operation) { case APPROX : case EQUAL : case GREATER : case LESS : { return value1.equals(value2); } } } catch (Exception e) { // if the equals method throws an exception; return false return false; } return false; } /** * Map a string for an APPROX (~=) comparison. * * This implementation removes white spaces. This is the minimum * implementation allowed by the OSGi spec. * * @param input Input string. * @return String ready for APPROX comparison. */ private static String approxString(String input) { boolean changed = false; char[] output = input.toCharArray(); int cursor = 0; for (char c : output) { if (Character.isWhitespace(c)) { changed = true; continue; } output[cursor] = c; cursor++; } return changed ? new String(output, 0, cursor) : input; } /** * Parser class for OSGi filter strings. This class parses the complete * filter string and builds a tree of Filter objects rooted at the * parent. */ static private final class Parser { private final String filterstring; private final char[] filterChars; private int pos; Parser(String filterstring) { this.filterstring = filterstring; filterChars = filterstring.toCharArray(); pos = 0; } FilterImpl parse() throws InvalidSyntaxException { FilterImpl filter; try { filter = parse_filter(); } catch (ArrayIndexOutOfBoundsException e) { throw new InvalidSyntaxException("Filter ended abruptly", filterstring, e); } if (pos != filterChars.length) { throw new InvalidSyntaxException("Extraneous trailing characters: " + filterstring.substring(pos), filterstring); } return filter; } private FilterImpl parse_filter() throws InvalidSyntaxException { FilterImpl filter; skipWhiteSpace(); if (filterChars[pos] != '(') { throw new InvalidSyntaxException("Missing '(': " + filterstring.substring(pos), filterstring); } pos++; filter = parse_filtercomp(); skipWhiteSpace(); if (filterChars[pos] != ')') { throw new InvalidSyntaxException("Missing ')': " + filterstring.substring(pos), filterstring); } pos++; skipWhiteSpace(); return filter; } private FilterImpl parse_filtercomp() throws InvalidSyntaxException { skipWhiteSpace(); char c = filterChars[pos]; switch (c) { case '&' : { pos++; return parse_and(); } case '|' : { pos++; return parse_or(); } case '!' : { pos++; return parse_not(); } } return parse_item(); } private FilterImpl parse_and() throws InvalidSyntaxException { int lookahead = pos; skipWhiteSpace(); if (filterChars[pos] != '(') { pos = lookahead - 1; return parse_item(); } List operands = new ArrayList(10); while (filterChars[pos] == '(') { FilterImpl child = parse_filter(); operands.add(child); } return new FilterImpl(FilterImpl.AND, null, operands.toArray(new FilterImpl[operands.size()])); } private FilterImpl parse_or() throws InvalidSyntaxException { int lookahead = pos; skipWhiteSpace(); if (filterChars[pos] != '(') { pos = lookahead - 1; return parse_item(); } List operands = new ArrayList(10); while (filterChars[pos] == '(') { FilterImpl child = parse_filter(); operands.add(child); } return new FilterImpl(FilterImpl.OR, null, operands.toArray(new FilterImpl[operands.size()])); } private FilterImpl parse_not() throws InvalidSyntaxException { int lookahead = pos; skipWhiteSpace(); if (filterChars[pos] != '(') { pos = lookahead - 1; return parse_item(); } FilterImpl child = parse_filter(); return new FilterImpl(FilterImpl.NOT, null, child); } private FilterImpl parse_item() throws InvalidSyntaxException { String attr = parse_attr(); skipWhiteSpace(); switch (filterChars[pos]) { case '~' : { if (filterChars[pos + 1] == '=') { pos += 2; return new FilterImpl(FilterImpl.APPROX, attr, parse_value()); } break; } case '>' : { if (filterChars[pos + 1] == '=') { pos += 2; return new FilterImpl(FilterImpl.GREATER, attr, parse_value()); } break; } case '<' : { if (filterChars[pos + 1] == '=') { pos += 2; return new FilterImpl(FilterImpl.LESS, attr, parse_value()); } break; } case '=' : { if (filterChars[pos + 1] == '*') { int oldpos = pos; pos += 2; skipWhiteSpace(); if (filterChars[pos] == ')') { return new FilterImpl(FilterImpl.PRESENT, attr, null); } pos = oldpos; } pos++; Object string = parse_substring(); if (string instanceof String) { return new FilterImpl(FilterImpl.EQUAL, attr, string); } return new FilterImpl(FilterImpl.SUBSTRING, attr, string); } } throw new InvalidSyntaxException("Invalid operator: " + filterstring.substring(pos), filterstring); } private String parse_attr() throws InvalidSyntaxException { skipWhiteSpace(); int begin = pos; int end = pos; char c = filterChars[pos]; while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') { pos++; if (!Character.isWhitespace(c)) { end = pos; } c = filterChars[pos]; } int length = end - begin; if (length == 0) { throw new InvalidSyntaxException("Missing attr: " + filterstring.substring(pos), filterstring); } return new String(filterChars, begin, length); } private String parse_value() throws InvalidSyntaxException { StringBuffer sb = new StringBuffer(filterChars.length - pos); parseloop: while (true) { char c = filterChars[pos]; switch (c) { case ')' : { break parseloop; } case '(' : { throw new InvalidSyntaxException("Invalid value: " + filterstring.substring(pos), filterstring); } case '\\' : { pos++; c = filterChars[pos]; /* fall through into default */ } default : { sb.append(c); pos++; break; } } } if (sb.length() == 0) { throw new InvalidSyntaxException("Missing value: " + filterstring.substring(pos), filterstring); } return sb.toString(); } private Object parse_substring() throws InvalidSyntaxException { StringBuffer sb = new StringBuffer(filterChars.length - pos); List operands = new ArrayList(10); parseloop: while (true) { char c = filterChars[pos]; switch (c) { case ')' : { if (sb.length() > 0) { operands.add(sb.toString()); } break parseloop; } case '(' : { throw new InvalidSyntaxException("Invalid value: " + filterstring.substring(pos), filterstring); } case '*' : { if (sb.length() > 0) { operands.add(sb.toString()); } sb.setLength(0); operands.add(null); pos++; break; } case '\\' : { pos++; c = filterChars[pos]; /* fall through into default */ } default : { sb.append(c); pos++; break; } } } int size = operands.size(); if (size == 0) { return ""; } if (size == 1) { Object single = operands.get(0); if (single != null) { return single; } } return operands.toArray(new String[size]); } private void skipWhiteSpace() { for (int length = filterChars.length; (pos < length) && Character.isWhitespace(filterChars[pos]);) { pos++; } } } } /** * This Map is used for case-insensitive key lookup during filter * evaluation. This Map implementation only supports the get operation using * a String key as no other operations are used by the Filter * implementation. */ static private final class CaseInsensitiveMap extends AbstractMap implements Map { private final Dictionary dictionary; private final String[] keys; /** * Create a case insensitive map from the specified dictionary. * * @param dictionary * @throws IllegalArgumentException If {@code dictionary} contains case * variants of the same key name. */ CaseInsensitiveMap(Dictionary dictionary) { if (dictionary == null) { this.dictionary = null; this.keys = new String[0]; return; } this.dictionary = dictionary; List keyList = new ArrayList(dictionary.size()); for (Enumeration e = dictionary.keys(); e.hasMoreElements();) { Object k = e.nextElement(); if (k instanceof String) { String key = (String) k; for (String i : keyList) { if (key.equalsIgnoreCase(i)) { throw new IllegalArgumentException(); } } keyList.add(key); } } this.keys = keyList.toArray(new String[keyList.size()]); } @Override public Object get(Object o) { String k = (String) o; for (String key : keys) { if (key.equalsIgnoreCase(k)) { return dictionary.get(key); } } return null; } public Set> entrySet() { throw new UnsupportedOperationException(); } } /** * This Map is used for key lookup from a ServiceReference during filter * evaluation. This Map implementation only supports the get operation using * a String key as no other operations are used by the Filter * implementation. */ static private final class ServiceReferenceMap extends AbstractMap implements Map { private final ServiceReference reference; ServiceReferenceMap(ServiceReference reference) { this.reference = reference; } @Override public Object get(Object key) { if (reference == null) { return null; } return reference.getProperty((String) key); } public Set> entrySet() { throw new UnsupportedOperationException(); } } static private final class SetAccessibleAction implements PrivilegedAction { private final AccessibleObject accessible; SetAccessibleAction(AccessibleObject accessible) { this.accessible = accessible; } public Void run() { accessible.setAccessible(true); return null; } } /** * This class contains a method to match a distinguished name (DN) chain * against and DN chain pattern. *

* The format of DNs are given in RFC 2253. We represent a signature chain * for an X.509 certificate as a semicolon separated list of DNs. This is * what we refer to as the DN chain. Each DN is made up of relative * distinguished names (RDN) which in turn are made up of key value pairs. * For example: * *

	 *   cn=ben+ou=research,o=ACME,c=us;ou=Super CA,c=CA
	 * 
* * is made up of two DNs: "{@code cn=ben+ou=research,o=ACME,c=us} " and " * {@code ou=Super CA,c=CA} ". The first DN is made of of three RDNs: " * {@code cn=ben+ou=research}" and "{@code o=ACME}" and " {@code c=us} * ". The first RDN has two name value pairs: " {@code cn=ben}" and " * {@code ou=research}". *

* A chain pattern makes use of wildcards ('*' or '-') to match against DNs, * and wildcards ('*') to match againts DN prefixes, and value. If a DN in a * match pattern chain is made up of a wildcard ("*"), that wildcard will * match zero or one DNs in the chain. If a DN in a match pattern chain is * made up of a wildcard ("-"), that wildcard will match zero or more DNs in * the chain. If the first RDN of a DN is the wildcard ("*"), that DN will * match any other DN with the same suffix (the DN with the wildcard RDN * removed). If a value of a name/value pair is a wildcard ("*"), the value * will match any value for that name. */ static private final class DNChainMatching { private static final String MINUS_WILDCARD = "-"; private static final String STAR_WILDCARD = "*"; /** * Check the name/value pairs of the rdn against the pattern. * * @param rdn List of name value pairs for a given RDN. * @param rdnPattern List of name value pattern pairs. * @return true if the list of name value pairs match the pattern. */ private static boolean rdnmatch(List rdn, List rdnPattern) { if (rdn.size() != rdnPattern.size()) { return false; } for (int i = 0; i < rdn.size(); i++) { String rdnNameValue = (String) rdn.get(i); String patNameValue = (String) rdnPattern.get(i); int rdnNameEnd = rdnNameValue.indexOf('='); int patNameEnd = patNameValue.indexOf('='); if (rdnNameEnd != patNameEnd || !rdnNameValue.regionMatches(0, patNameValue, 0, rdnNameEnd)) { return false; } String patValue = patNameValue.substring(patNameEnd); String rdnValue = rdnNameValue.substring(rdnNameEnd); if (!rdnValue.equals(patValue) && !patValue.equals("=*") && !patValue.equals("=#16012a")) { return false; } } return true; } private static boolean dnmatch(List dn, List dnPattern) { int dnStart = 0; int patStart = 0; int patLen = dnPattern.size(); if (patLen == 0) { return false; } if (dnPattern.get(0).equals(STAR_WILDCARD)) { patStart = 1; patLen--; } if (dn.size() < patLen) { return false; } else { if (dn.size() > patLen) { if (!dnPattern.get(0).equals(STAR_WILDCARD)) { // If the number of rdns do not match we must have a // prefix map return false; } // The rdnPattern and rdn must have the same number of // elements dnStart = dn.size() - patLen; } } for (int i = 0; i < patLen; i++) { if (!rdnmatch((List) dn.get(i + dnStart), (List) dnPattern.get(i + patStart))) { return false; } } return true; } /** * Parses a distinguished name chain pattern and returns a List where * each element represents a distinguished name (DN) in the chain of * DNs. Each element will be either a String, if the element represents * a wildcard ("*" or "-"), or a List representing an RDN. Each element * in the RDN List will be a String, if the element represents a * wildcard ("*"), or a List of Strings, each String representing a * name/value pair in the RDN. * * @param pattern * @return a list of DNs. * @throws IllegalArgumentException */ private static List parseDNchainPattern(String pattern) { if (pattern == null) { throw new IllegalArgumentException("The pattern must not be null."); } List parsed = new ArrayList(); final int length = pattern.length(); char c = ';'; // start with semi-colon to detect empty pattern for (int startIndex = skipSpaces(pattern, 0); startIndex < length;) { int cursor = startIndex; int endIndex = startIndex; out: for (boolean inQuote = false; cursor < length; cursor++) { c = pattern.charAt(cursor); switch (c) { case '"' : inQuote = !inQuote; break; case '\\' : cursor++; // skip the escaped char if (cursor == length) { throw new IllegalArgumentException("unterminated escape"); } break; case ';' : if (!inQuote) { break out; // end of pattern } break; } if (c != ' ') { // ignore trailing whitespace endIndex = cursor + 1; } } parsed.add(pattern.substring(startIndex, endIndex)); startIndex = skipSpaces(pattern, cursor + 1); } if (c == ';') { // last non-whitespace character was a semi-colon throw new IllegalArgumentException("empty pattern"); } // Now we have parsed into a list of strings, lets make List of rdn // out of them for (int i = 0; i < parsed.size(); i++) { String dn = (String) parsed.get(i); if (dn.equals(STAR_WILDCARD) || dn.equals(MINUS_WILDCARD)) { continue; } List rdns = new ArrayList(); if (dn.charAt(0) == '*') { int index = skipSpaces(dn, 1); if (dn.charAt(index) != ',') { throw new IllegalArgumentException("invalid wildcard prefix"); } rdns.add(STAR_WILDCARD); dn = new X500Principal(dn.substring(index + 1)).getName(X500Principal.CANONICAL); } else { dn = new X500Principal(dn).getName(X500Principal.CANONICAL); } // Now dn is a nice CANONICAL DN parseDN(dn, rdns); parsed.set(i, rdns); } return parsed; } private static List parseDNchain(List chain) { if (chain == null) { throw new IllegalArgumentException("DN chain must not be null."); } List result = new ArrayList(chain.size()); // Now we parse is a list of strings, lets make List of rdn out // of them for (String dn : chain) { dn = new X500Principal(dn).getName(X500Principal.CANONICAL); // Now dn is a nice CANONICAL DN List rdns = new ArrayList(); parseDN(dn, rdns); result.add(rdns); } if (result.size() == 0) { throw new IllegalArgumentException("empty DN chain"); } return result; } /** * Increment startIndex until the end of dnChain is hit or until it is * the index of a non-space character. */ private static int skipSpaces(String dnChain, int startIndex) { while (startIndex < dnChain.length() && dnChain.charAt(startIndex) == ' ') { startIndex++; } return startIndex; } /** * Takes a distinguished name in canonical form and fills in the * rdnArray with the extracted RDNs. * * @param dn the distinguished name in canonical form. * @param rdn the list to fill in with RDNs extracted from the dn * @throws IllegalArgumentException if a formatting error is found. */ private static void parseDN(String dn, List rdn) { int startIndex = 0; char c = '\0'; List nameValues = new ArrayList(); while (startIndex < dn.length()) { int endIndex; for (endIndex = startIndex; endIndex < dn.length(); endIndex++) { c = dn.charAt(endIndex); if (c == ',' || c == '+') { break; } if (c == '\\') { endIndex++; // skip the escaped char } } if (endIndex > dn.length()) { throw new IllegalArgumentException("unterminated escape " + dn); } nameValues.add(dn.substring(startIndex, endIndex)); if (c != '+') { rdn.add(nameValues); if (endIndex != dn.length()) { nameValues = new ArrayList(); } else { nameValues = null; } } startIndex = endIndex + 1; } if (nameValues != null) { throw new IllegalArgumentException("improperly terminated DN " + dn); } } /** * This method will return an 'index' which points to a non-wildcard DN * or the end-of-list. */ private static int skipWildCards(List dnChainPattern, int dnChainPatternIndex) { int i; for (i = dnChainPatternIndex; i < dnChainPattern.size(); i++) { Object dnPattern = dnChainPattern.get(i); if (dnPattern instanceof String) { if (!dnPattern.equals(STAR_WILDCARD) && !dnPattern.equals(MINUS_WILDCARD)) { throw new IllegalArgumentException("expected wildcard in DN pattern"); } // otherwise continue skipping over wild cards } else { if (dnPattern instanceof List) { // if its a list then we have our 'non-wildcard' DN break; } else { // unknown member of the DNChainPattern throw new IllegalArgumentException("expected String or List in DN Pattern"); } } } // i either points to end-of-list, or to the first // non-wildcard pattern after dnChainPatternIndex return i; } /** * recursively attempt to match the DNChain, and the DNChainPattern * where DNChain is of the format: "DN;DN;DN;" and DNChainPattern is of * the format: "DNPattern;*;DNPattern" (or combinations of this) */ private static boolean dnChainMatch(List dnChain, int dnChainIndex, List dnChainPattern, int dnChainPatternIndex) throws IllegalArgumentException { if (dnChainIndex >= dnChain.size()) { return false; } if (dnChainPatternIndex >= dnChainPattern.size()) { return false; } // check to see what the pattern starts with Object dnPattern = dnChainPattern.get(dnChainPatternIndex); if (dnPattern instanceof String) { if (!dnPattern.equals(STAR_WILDCARD) && !dnPattern.equals(MINUS_WILDCARD)) { throw new IllegalArgumentException("expected wildcard in DN pattern"); } // here we are processing a wild card as the first DN // skip all wildcard DN's if (dnPattern.equals(MINUS_WILDCARD)) { dnChainPatternIndex = skipWildCards(dnChainPattern, dnChainPatternIndex); } else { dnChainPatternIndex++; // only skip the '*' wildcard } if (dnChainPatternIndex >= dnChainPattern.size()) { // return true iff the wild card is '-' or if we are at the // end of the chain return dnPattern.equals(MINUS_WILDCARD) ? true : dnChain.size() - 1 == dnChainIndex; } // // we will now recursively call to see if the rest of the // DNChainPattern matches increasingly smaller portions of the // rest of the DNChain // if (dnPattern.equals(STAR_WILDCARD)) { // '*' option: only wildcard on 0 or 1 return dnChainMatch(dnChain, dnChainIndex, dnChainPattern, dnChainPatternIndex) || dnChainMatch(dnChain, dnChainIndex + 1, dnChainPattern, dnChainPatternIndex); } for (int i = dnChainIndex; i < dnChain.size(); i++) { // '-' option: wildcard 0 or more if (dnChainMatch(dnChain, i, dnChainPattern, dnChainPatternIndex)) { return true; } } // if we are here, then we didn't find a match.. fall through to // failure } else { if (dnPattern instanceof List) { // here we have to do a deeper check for each DN in the // pattern until we hit a wild card do { if (!dnmatch((List) dnChain.get(dnChainIndex), (List) dnPattern)) { return false; } // go to the next set of DN's in both chains dnChainIndex++; dnChainPatternIndex++; // if we finished the pattern then it all matched if ((dnChainIndex >= dnChain.size()) && (dnChainPatternIndex >= dnChainPattern.size())) { return true; } // if the DN Chain is finished, but the pattern isn't // finished then if the rest of the pattern is not // wildcard then we are done if (dnChainIndex >= dnChain.size()) { dnChainPatternIndex = skipWildCards(dnChainPattern, dnChainPatternIndex); // return TRUE iff the pattern index moved past the // list-size (implying that the rest of the pattern // is all wildcards) return dnChainPatternIndex >= dnChainPattern.size(); } // if the pattern finished, but the chain continues then // we have a mis-match if (dnChainPatternIndex >= dnChainPattern.size()) { return false; } // get the next DN Pattern dnPattern = dnChainPattern.get(dnChainPatternIndex); if (dnPattern instanceof String) { if (!dnPattern.equals(STAR_WILDCARD) && !dnPattern.equals(MINUS_WILDCARD)) { throw new IllegalArgumentException("expected wildcard in DN pattern"); } // if the next DN is a 'wildcard', then we will // recurse return dnChainMatch(dnChain, dnChainIndex, dnChainPattern, dnChainPatternIndex); } else { if (!(dnPattern instanceof List)) { throw new IllegalArgumentException("expected String or List in DN Pattern"); } } // if we are here, then we will just continue to the // match the next set of DN's from the DNChain, and the // DNChainPattern since both are lists } while (true); // should never reach here? } else { throw new IllegalArgumentException("expected String or List in DN Pattern"); } } // if we get here, the the default return is 'mis-match' return false; } /** * Matches a distinguished name chain against a pattern of a * distinguished name chain. * * @param dnChain * @param pattern the pattern of distinguished name (DN) chains to match * against the dnChain. Wildcards ("*" or "-") can be used in * three cases: *
    *
  1. As a DN. In this case, the DN will consist of just the "*" * or "-". When "*" is used it will match zero or one DNs. When * "-" is used it will match zero or more DNs. For example, * "cn=me,c=US;*;cn=you" will match * "cn=me,c=US";cn=you" and "cn=me,c=US;cn=her;cn=you". The * pattern "cn=me,c=US;-;cn=you" will match "cn=me,c=US";cn=you" * and "cn=me,c=US;cn=her;cn=him;cn=you".
  2. *
  3. As a DN prefix. In this case, the DN must start with "*,". * The wild card will match zero or more RDNs at the start of a * DN. For example, "*,cn=me,c=US;cn=you" will match * "cn=me,c=US";cn=you" and * "ou=my org unit,o=my org,cn=me,c=US;cn=you"
  4. *
  5. As a value. In this case the value of a name value pair in * an RDN will be a "*". The wildcard will match any value for * the given name. For example, "cn=*,c=US;cn=you" will match * "cn=me,c=US";cn=you" and "cn=her,c=US;cn=you", but it will not * match "ou=my org unit,c=US;cn=you". If the wildcard does not * occur by itself in the value, it will not be used as a * wildcard. In other words, "cn=m*,c=US;cn=you" represents the * common name of "m*" not any common name starting with "m".
  6. *
* @return true if dnChain matches the pattern. * @throws IllegalArgumentException */ static boolean match(String pattern, List dnChain) { List parsedDNChain; List parsedDNPattern; try { parsedDNChain = parseDNchain(dnChain); } catch (RuntimeException e) { IllegalArgumentException iae = new IllegalArgumentException("Invalid DN chain: " + toString(dnChain)); iae.initCause(e); throw iae; } try { parsedDNPattern = parseDNchainPattern(pattern); } catch (RuntimeException e) { IllegalArgumentException iae = new IllegalArgumentException("Invalid match pattern: " + pattern); iae.initCause(e); throw iae; } return dnChainMatch(parsedDNChain, 0, parsedDNPattern, 0); } private static String toString(List dnChain) { if (dnChain == null) { return null; } StringBuffer sb = new StringBuffer(); for (Iterator iChain = dnChain.iterator(); iChain.hasNext();) { sb.append(iChain.next()); if (iChain.hasNext()) { sb.append("; "); } } return sb.toString(); } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/ServiceReference.java0000644000175000017500000001674112346513664027525 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.util.Dictionary; /** * A reference to a service. * *

* The Framework returns {@code ServiceReference} objects from the * {@code BundleContext.getServiceReference} and * {@code BundleContext.getServiceReferences} methods. *

* A {@code ServiceReference} object may be shared between bundles and can be * used to examine the properties of the service and to get the service object. *

* Every service registered in the Framework has a unique * {@code ServiceRegistration} object and may have multiple, distinct * {@code ServiceReference} objects referring to it. {@code ServiceReference} * objects associated with a {@code ServiceRegistration} object have the same * {@code hashCode} and are considered equal (more specifically, their * {@code equals()} method will return {@code true} when compared). *

* If the same service object is registered multiple times, * {@code ServiceReference} objects associated with different * {@code ServiceRegistration} objects are not equal. * * @param Type of Service. * @see BundleContext#getServiceReference(Class) * @see BundleContext#getServiceReference(String) * @see BundleContext#getServiceReferences(Class, String) * @see BundleContext#getServiceReferences(String, String) * @see BundleContext#getService(ServiceReference) * @ThreadSafe * @noimplement * @version $Id: 75352193f9f11a2c19692890153c6ff91611023b $ */ public interface ServiceReference extends Comparable { /** * Returns the property value to which the specified property key is mapped * in the properties {@code Dictionary} object of the service referenced by * this {@code ServiceReference} object. * *

* Property keys are case-insensitive. * *

* This method must continue to return property values after the service has * been unregistered. This is so references to unregistered services (for * example, {@code ServiceReference} objects stored in the log) can still be * interrogated. * * @param key The property key. * @return The property value to which the key is mapped; {@code null} if * there is no property named after the key. */ public Object getProperty(String key); /** * Returns an array of the keys in the properties {@code Dictionary} object * of the service referenced by this {@code ServiceReference} object. * *

* This method will continue to return the keys after the service has been * unregistered. This is so references to unregistered services (for * example, {@code ServiceReference} objects stored in the log) can still be * interrogated. * *

* This method is case-preserving ; this means that every key in the * returned array must have the same case as the corresponding key in the * properties {@code Dictionary} that was passed to the * {@link BundleContext#registerService(String[],Object,Dictionary)} or * {@link ServiceRegistration#setProperties(Dictionary)} methods. * * @return An array of property keys. */ public String[] getPropertyKeys(); /** * Returns the bundle that registered the service referenced by this * {@code ServiceReference} object. * *

* This method must return {@code null} when the service has been * unregistered. This can be used to determine if the service has been * unregistered. * * @return The bundle that registered the service referenced by this * {@code ServiceReference} object; {@code null} if that service has * already been unregistered. * @see BundleContext#registerService(String[],Object,Dictionary) */ public Bundle getBundle(); /** * Returns the bundles that are using the service referenced by this * {@code ServiceReference} object. Specifically, this method returns the * bundles whose usage count for that service is greater than zero. * * @return An array of bundles whose usage count for the service referenced * by this {@code ServiceReference} object is greater than zero; * {@code null} if no bundles are currently using that service. * * @since 1.1 */ public Bundle[] getUsingBundles(); /** * Tests if the bundle that registered the service referenced by this * {@code ServiceReference} and the specified bundle use the same source for * the package of the specified class name. *

* This method performs the following checks: *

    *
  1. Get the package name from the specified class name.
  2. *
  3. For the bundle that registered the service referenced by this * {@code ServiceReference} (registrant bundle); find the source for the * package. If no source is found then return {@code true} if the registrant * bundle is equal to the specified bundle; otherwise return {@code false}.
  4. *
  5. If the package source of the registrant bundle is equal to the * package source of the specified bundle then return {@code true}; * otherwise return {@code false}.
  6. *
* * @param bundle The {@code Bundle} object to check. * @param className The class name to check. * @return {@code true} if the bundle which registered the service * referenced by this {@code ServiceReference} and the specified * bundle use the same source for the package of the specified class * name. Otherwise {@code false} is returned. * @throws IllegalArgumentException If the specified {@code Bundle} was not * created by the same framework instance as this * {@code ServiceReference}. * @since 1.3 */ public boolean isAssignableTo(Bundle bundle, String className); /** * Compares this {@code ServiceReference} with the specified * {@code ServiceReference} for order. * *

* If this {@code ServiceReference} and the specified * {@code ServiceReference} have the same {@link Constants#SERVICE_ID * service id} they are equal. This {@code ServiceReference} is less than * the specified {@code ServiceReference} if it has a lower * {@link Constants#SERVICE_RANKING service ranking} and greater if it has a * higher service ranking. Otherwise, if this {@code ServiceReference} and * the specified {@code ServiceReference} have the same * {@link Constants#SERVICE_RANKING service ranking}, this * {@code ServiceReference} is less than the specified * {@code ServiceReference} if it has a higher {@link Constants#SERVICE_ID * service id} and greater if it has a lower service id. * * @param reference The {@code ServiceReference} to be compared. * @return Returns a negative integer, zero, or a positive integer if this * {@code ServiceReference} is less than, equal to, or greater than * the specified {@code ServiceReference}. * @throws IllegalArgumentException If the specified * {@code ServiceReference} was not created by the same framework * instance as this {@code ServiceReference}. * @since 1.4 */ public int compareTo(Object reference); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/ServiceFactory.java0000644000175000017500000001146612346513664027235 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; /** * Allows services to provide customized service objects in the OSGi * environment. * *

* When registering a service, a {@code ServiceFactory} object can be used * instead of a service object, so that the bundle developer can gain control of * the specific service object granted to a bundle that is using the service. * *

* When this happens, the {@code BundleContext.getService(ServiceReference)} * method calls the {@code ServiceFactory.getService} method to create a service * object specifically for the requesting bundle. The service object returned by * the {@code ServiceFactory} is cached by the Framework until the bundle * releases its use of the service. * *

* When the bundle's use count for the service is decremented to zero (including * the bundle stopping or the service being unregistered), the * {@code ServiceFactory.ungetService} method is called. * *

* {@code ServiceFactory} objects are only used by the Framework and are not * made available to other bundles in the OSGi environment. The Framework may * concurrently call a {@code ServiceFactory}. * * @param Type of Service * @see BundleContext#getService(ServiceReference) * @ThreadSafe * @version $Id: 535776e702ec5ace54f577218ff8f7920741558b $ */ public interface ServiceFactory { /** * Creates a new service object. * *

* The Framework invokes this method the first time the specified * {@code bundle} requests a service object using the * {@code BundleContext.getService(ServiceReference)} method. The service * factory can then return a specific service object for each bundle. * *

* The Framework must check that the returned service object is valid. If * the returned service object is {@code null} or is not an * {@code instanceof} all the classes named when the service was registered, * a framework event of type {@link FrameworkEvent#ERROR} is fired * containing a service exception of type * {@link ServiceException#FACTORY_ERROR} and {@code null} is returned to * the bundle. If this method throws an exception, a framework event of type * {@link FrameworkEvent#ERROR} is fired containing a service exception of * type {@link ServiceException#FACTORY_EXCEPTION} with the thrown exception * as the cause and {@code null} is returned to the bundle. If this method * is recursively called for the specified bundle, a framework event of type * {@link FrameworkEvent#ERROR} is fired containing a service exception of * type {@link ServiceException#FACTORY_RECURSION} and {@code null} is * returned to the bundle. * *

* The Framework caches the valid service object and will return the same * service object on any future call to {@code BundleContext.getService} for * the specified bundle. This means the Framework must not allow this method * to be concurrently called for the specified bundle. * * @param bundle The bundle requesting the service. * @param registration The {@code ServiceRegistration} object for the * requested service. * @return A service object that must be an instance of all * the classes named when the service was registered. * @see BundleContext#getService(ServiceReference) */ public S getService(Bundle bundle, ServiceRegistration registration); /** * Releases a service object. * *

* The Framework invokes this method when a service has been released by a * bundle. The service object may then be destroyed. * *

* If this method throws an exception, a framework event of type * {@link FrameworkEvent#ERROR} is fired containing a service exception of * type {@link ServiceException#FACTORY_EXCEPTION} with the thrown exception * as the cause. * * @param bundle The bundle releasing the service. * @param registration The {@code ServiceRegistration} object for the * service being released. * @param service The service object returned by a previous call to the * {@link #getService(Bundle, ServiceRegistration) getService} * method. * @see BundleContext#ungetService(ServiceReference) */ public void ungetService(Bundle bundle, ServiceRegistration registration, S service); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/ServiceRegistration.java0000644000175000017500000001042412346513664030271 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.util.Dictionary; /** * A registered service. * *

* The Framework returns a {@code ServiceRegistration} object when a * {@code BundleContext.registerService} method invocation is successful. The * {@code ServiceRegistration} object is for the private use of the registering * bundle and should not be shared with other bundles. *

* The {@code ServiceRegistration} object may be used to update the properties * of the service or to unregister the service. * * @param Type of Service. * @see BundleContext#registerService(String[],Object,Dictionary) * @ThreadSafe * @noimplement * @version $Id: a84248da0db0538708d2394a9478153e06b8afb9 $ */ public interface ServiceRegistration { /** * Returns a {@code ServiceReference} object for a service being registered. *

* The {@code ServiceReference} object may be shared with other bundles. * * @throws IllegalStateException If this {@code ServiceRegistration} object * has already been unregistered. * @return {@code ServiceReference} object. */ public ServiceReference getReference(); /** * Updates the properties associated with a service. * *

* The {@link Constants#OBJECTCLASS} and {@link Constants#SERVICE_ID} keys * cannot be modified by this method. These values are set by the Framework * when the service is registered in the OSGi environment. * *

* The following steps are required to modify service properties: *

    *
  1. The service's properties are replaced with the provided properties. *
  2. A service event of type {@link ServiceEvent#MODIFIED} is fired. *
* * @param properties The properties for this service. See {@link Constants} * for a list of standard service property keys. Changes should not * be made to this object after calling this method. To update the * service's properties this method should be called again. * * @throws IllegalStateException If this {@code ServiceRegistration} object * has already been unregistered. * @throws IllegalArgumentException If {@code properties} contains case * variants of the same key name. */ public void setProperties(Dictionary properties); /** * Unregisters a service. Remove a {@code ServiceRegistration} object from * the Framework service registry. All {@code ServiceReference} objects * associated with this {@code ServiceRegistration} object can no longer be * used to interact with the service once unregistration is complete. * *

* The following steps are required to unregister a service: *

    *
  1. The service is removed from the Framework service registry so that it * can no longer be obtained. *
  2. A service event of type {@link ServiceEvent#UNREGISTERING} is fired * so that bundles using this service can release their use of the service. * Once delivery of the service event is complete, the * {@code ServiceReference} objects for the service may no longer be used to * get a service object for the service. *
  3. For each bundle whose use count for this service is greater than * zero:
    * The bundle's use count for this service is set to zero.
    * If the service was registered with a {@link ServiceFactory} object, the * {@code ServiceFactory.ungetService} method is called to release the * service object for the bundle. *
* * @throws IllegalStateException If this {@code ServiceRegistration} object * has already been unregistered. * @see BundleContext#ungetService(ServiceReference) * @see ServiceFactory#ungetService(Bundle, ServiceRegistration, Object) */ public void unregister(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/Constants.java0000644000175000017500000015553212346513664026264 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import org.osgi.framework.hooks.bundle.CollisionHook; import org.osgi.framework.launch.Framework; /** * Defines standard names for the OSGi environment system properties, service * properties, and Manifest header attribute keys. * *

* The values associated with these keys are of type {@code String}, unless * otherwise indicated. * * @since 1.1 * @noimplement * @version $Id: 6d07a4c3e29a5cd93b3daf0f9fcdab5472b357f6 $ */ public interface Constants { /** * Location identifier of the OSGi system bundle , which is defined * to be "System Bundle". */ String SYSTEM_BUNDLE_LOCATION = "System Bundle"; /** * Alias for the symbolic name of the OSGi system bundle . It is * defined to be "system.bundle". * * @since 1.3 */ String SYSTEM_BUNDLE_SYMBOLICNAME = "system.bundle"; /** * Manifest header identifying the bundle's category. *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String BUNDLE_CATEGORY = "Bundle-Category"; /** * Manifest header identifying a list of directories and embedded JAR files, * which are bundle resources used to extend the bundle's classpath. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String BUNDLE_CLASSPATH = "Bundle-ClassPath"; /** * Manifest header identifying the bundle's copyright information. *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String BUNDLE_COPYRIGHT = "Bundle-Copyright"; /** * Manifest header containing a brief description of the bundle's * functionality. *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String BUNDLE_DESCRIPTION = "Bundle-Description"; /** * Manifest header identifying the bundle's name. *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String BUNDLE_NAME = "Bundle-Name"; /** * Manifest header identifying a number of hardware environments and the * native language code libraries that the bundle is carrying for each of * these environments. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String BUNDLE_NATIVECODE = "Bundle-NativeCode"; /** * Manifest header identifying the packages that the bundle offers to the * Framework for export. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String EXPORT_PACKAGE = "Export-Package"; /** * Manifest header identifying the fully qualified class names of the * services that the bundle may register (used for informational purposes * only). * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. * * @deprecated As of 1.2. */ String EXPORT_SERVICE = "Export-Service"; /** * Manifest header identifying the packages on which the bundle depends. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String IMPORT_PACKAGE = "Import-Package"; /** * Manifest header identifying the packages that the bundle may dynamically * import during execution. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. * * @since 1.2 */ String DYNAMICIMPORT_PACKAGE = "DynamicImport-Package"; /** * Manifest header identifying the fully qualified class names of the * services that the bundle requires (used for informational purposes only). * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. * * @deprecated As of 1.2. */ String IMPORT_SERVICE = "Import-Service"; /** * Manifest header identifying the bundle's vendor. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String BUNDLE_VENDOR = "Bundle-Vendor"; /** * Manifest header identifying the bundle's version. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String BUNDLE_VERSION = "Bundle-Version"; /** * Manifest header identifying the bundle's documentation URL, from which * further information about the bundle may be obtained. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String BUNDLE_DOCURL = "Bundle-DocURL"; /** * Manifest header identifying the contact address where problems with the * bundle may be reported; for example, an email address. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String BUNDLE_CONTACTADDRESS = "Bundle-ContactAddress"; /** * Manifest header attribute identifying the bundle's activator class. * *

* If present, this header specifies the name of the bundle resource class * that implements the {@code BundleActivator} interface and whose * {@code start} and {@code stop} methods are called by the Framework when * the bundle is started and stopped, respectively. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String BUNDLE_ACTIVATOR = "Bundle-Activator"; /** * Manifest header identifying the location from which a new bundle version * is obtained during a bundle update operation. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. */ String BUNDLE_UPDATELOCATION = "Bundle-UpdateLocation"; /** * Manifest header attribute identifying the version of a package specified * in the Export-Package or Import-Package manifest header. * * @deprecated As of 1.3. This has been replaced by * {@link #VERSION_ATTRIBUTE}. */ String PACKAGE_SPECIFICATION_VERSION = "specification-version"; /** * Manifest header attribute identifying the processor required to run * native bundle code specified in the Bundle-NativeCode manifest header). * *

* The attribute value is encoded in the Bundle-NativeCode manifest header * like: * *

	 *     Bundle-NativeCode: http.so ; processor=x86 ...
	 * 
* * @see #BUNDLE_NATIVECODE */ String BUNDLE_NATIVECODE_PROCESSOR = "processor"; /** * Manifest header attribute identifying the operating system required to * run native bundle code specified in the Bundle-NativeCode manifest * header). *

* The attribute value is encoded in the Bundle-NativeCode manifest header * like: * *

	 *     Bundle-NativeCode: http.so ; osname=Linux ...
	 * 
* * @see #BUNDLE_NATIVECODE */ String BUNDLE_NATIVECODE_OSNAME = "osname"; /** * Manifest header attribute identifying the operating system version * required to run native bundle code specified in the Bundle-NativeCode * manifest header). *

* The attribute value is encoded in the Bundle-NativeCode manifest header * like: * *

	 *     Bundle-NativeCode: http.so ; osversion="2.34" ...
	 * 
* * @see #BUNDLE_NATIVECODE */ String BUNDLE_NATIVECODE_OSVERSION = "osversion"; /** * Manifest header attribute identifying the language in which the native * bundle code is written specified in the Bundle-NativeCode manifest * header. See ISO 639 for possible values. *

* The attribute value is encoded in the Bundle-NativeCode manifest header * like: * *

	 *     Bundle-NativeCode: http.so ; language=nl_be ...
	 * 
* * @see #BUNDLE_NATIVECODE */ String BUNDLE_NATIVECODE_LANGUAGE = "language"; /** * Manifest header identifying the required execution environment for the * bundle. The service platform may run this bundle if any of the execution * environments named in this header matches one of the execution * environments it implements. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. * * @since 1.2 * @deprecated As of 1.6. Replaced by the {@code osgi.ee} capability. */ String BUNDLE_REQUIREDEXECUTIONENVIRONMENT = "Bundle-RequiredExecutionEnvironment"; /** * Manifest header identifying the bundle's symbolic name. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. * * @since 1.3 */ String BUNDLE_SYMBOLICNAME = "Bundle-SymbolicName"; /** * Manifest header directive identifying whether a bundle is a singleton. * The default value is {@code false}. * *

* The directive value is encoded in the Bundle-SymbolicName manifest header * like: * *

	 *     Bundle-SymbolicName: com.acme.module.test; singleton:=true
	 * 
* * @see #BUNDLE_SYMBOLICNAME * @since 1.3 */ String SINGLETON_DIRECTIVE = "singleton"; /** * Manifest header directive identifying if and when a fragment may attach * to a host bundle. The default value is * {@link #FRAGMENT_ATTACHMENT_ALWAYS always}. * *

* The directive value is encoded in the Bundle-SymbolicName manifest header * like: * *

	 *     Bundle-SymbolicName: com.acme.module.test; fragment-attachment:="never"
	 * 
* * @see #BUNDLE_SYMBOLICNAME * @see #FRAGMENT_ATTACHMENT_ALWAYS * @see #FRAGMENT_ATTACHMENT_RESOLVETIME * @see #FRAGMENT_ATTACHMENT_NEVER * @since 1.3 */ String FRAGMENT_ATTACHMENT_DIRECTIVE = "fragment-attachment"; /** * Manifest header directive value identifying a fragment attachment type of * always. A fragment attachment type of always indicates that fragments are * allowed to attach to the host bundle at any time (while the host is * resolved or during the process of resolving the host bundle). * *

* The directive value is encoded in the Bundle-SymbolicName manifest header * like: * *

	 *     Bundle-SymbolicName: com.acme.module.test; fragment-attachment:="always"
	 * 
* * @see #FRAGMENT_ATTACHMENT_DIRECTIVE * @since 1.3 */ String FRAGMENT_ATTACHMENT_ALWAYS = "always"; /** * Manifest header directive value identifying a fragment attachment type of * resolve-time. A fragment attachment type of resolve-time indicates that * fragments are allowed to attach to the host bundle only during the * process of resolving the host bundle. * *

* The directive value is encoded in the Bundle-SymbolicName manifest header * like: * *

	 *     Bundle-SymbolicName: com.acme.module.test; fragment-attachment:="resolve-time"
	 * 
* * @see #FRAGMENT_ATTACHMENT_DIRECTIVE * @since 1.3 */ String FRAGMENT_ATTACHMENT_RESOLVETIME = "resolve-time"; /** * Manifest header directive value identifying a fragment attachment type of * never. A fragment attachment type of never indicates that no fragments * are allowed to attach to the host bundle at any time. * *

* The directive value is encoded in the Bundle-SymbolicName manifest header * like: * *

	 *     Bundle-SymbolicName: com.acme.module.test; fragment-attachment:="never"
	 * 
* * @see #FRAGMENT_ATTACHMENT_DIRECTIVE * @since 1.3 */ String FRAGMENT_ATTACHMENT_NEVER = "never"; /** * Manifest header identifying the base name of the bundle's localization * entries. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. * * @see #BUNDLE_LOCALIZATION_DEFAULT_BASENAME * @since 1.3 */ String BUNDLE_LOCALIZATION = "Bundle-Localization"; /** * Default value for the {@code Bundle-Localization} manifest header. * * @see #BUNDLE_LOCALIZATION * @since 1.3 */ String BUNDLE_LOCALIZATION_DEFAULT_BASENAME = "OSGI-INF/l10n/bundle"; /** * Manifest header identifying the symbolic names of other bundles required * by the bundle. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. * * @since 1.3 */ String REQUIRE_BUNDLE = "Require-Bundle"; /** * Manifest header attribute identifying a range of versions for a bundle * specified in the {@code Require-Bundle} or {@code Fragment-Host} manifest * headers. The default value is {@code 0.0.0}. * *

* The attribute value is encoded in the Require-Bundle manifest header * like: * *

	 *     Require-Bundle: com.acme.module.test; bundle-version="1.1"
	 *     Require-Bundle: com.acme.module.test; bundle-version="[1.0,2.0)"
	 * 
* *

* The bundle-version attribute value uses a mathematical interval notation * to specify a range of bundle versions. A bundle-version attribute value * specified as a single version means a version range that includes any * bundle version greater than or equal to the specified version. * * @see #REQUIRE_BUNDLE * @since 1.3 */ String BUNDLE_VERSION_ATTRIBUTE = "bundle-version"; /** * Manifest header identifying the symbolic name of another bundle for which * that the bundle is a fragment. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. * * @since 1.3 */ String FRAGMENT_HOST = "Fragment-Host"; /** * Manifest header attribute is used for selection by filtering based upon * system properties. * *

* The attribute value is encoded in manifest headers like: * *

	 *     Bundle-NativeCode: libgtk.so; selection-filter="(ws=gtk)"; ...
	 * 
* * @see #BUNDLE_NATIVECODE * @since 1.3 */ String SELECTION_FILTER_ATTRIBUTE = "selection-filter"; /** * Manifest header identifying the bundle manifest version. A bundle * manifest may express the version of the syntax in which it is written by * specifying a bundle manifest version. Bundles exploiting OSGi Release 4, * or later, syntax must specify a bundle manifest version. *

* The bundle manifest version defined by OSGi Release 4 or, more * specifically, by version 1.3 of the OSGi Core Specification is "2". * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. * * @since 1.3 */ String BUNDLE_MANIFESTVERSION = "Bundle-ManifestVersion"; /** * Manifest header attribute identifying the version of a package specified * in the Export-Package or Import-Package manifest header. * *

* The attribute value is encoded in the Export-Package or Import-Package * manifest header like: * *

	 *     Export-Package: org.osgi.framework; version="1.1"
	 * 
* * @see #EXPORT_PACKAGE * @see #IMPORT_PACKAGE * @since 1.3 */ String VERSION_ATTRIBUTE = "version"; /** * Manifest header attribute identifying the symbolic name of a bundle that * exports a package specified in the Import-Package manifest header. * *

* The attribute value is encoded in the Import-Package manifest header * like: * *

	 *     Import-Package: org.osgi.framework; bundle-symbolic-name="com.acme.module.test"
	 * 
* * @see #IMPORT_PACKAGE * @since 1.3 */ String BUNDLE_SYMBOLICNAME_ATTRIBUTE = "bundle-symbolic-name"; /** * Manifest header directive identifying the resolution type in the * Import-Package, Require-Bundle or Require-Capability manifest header. The * default value is {@link #RESOLUTION_MANDATORY mandatory}. * *

* The directive value is encoded in the Import-Package, Require-Bundle or * Require-Capability manifest header like: * *

	 *     Import-Package: org.osgi.framework; resolution:="optional"
	 *     Require-Bundle: com.acme.module.test; resolution:="optional"
	 *     Require-Capability: com.acme.capability; resolution:="optional"
	 * 
* * @see #IMPORT_PACKAGE * @see #REQUIRE_BUNDLE * @see #REQUIRE_CAPABILITY * @see #RESOLUTION_MANDATORY * @see #RESOLUTION_OPTIONAL * @since 1.3 */ String RESOLUTION_DIRECTIVE = "resolution"; /** * Manifest header directive value identifying a mandatory resolution type. * A mandatory resolution type indicates that the import package, require * bundle or require capability must be resolved when the bundle is * resolved. If such an import, require bundle or require capability cannot * be resolved, the module fails to resolve. * *

* The directive value is encoded in the Import-Package, Require-Bundle or * Require-Capability manifest header like: * *

	 *     Import-Package: org.osgi.framework; resolution:="mandatory"
	 *     Require-Bundle: com.acme.module.test; resolution:="mandatory"
	 *     Require-Capability: com.acme.capability; resolution:="mandatory"
	 * 
* * @see #RESOLUTION_DIRECTIVE * @since 1.3 */ String RESOLUTION_MANDATORY = "mandatory"; /** * Manifest header directive value identifying an optional resolution type. * An optional resolution type indicates that the import, require bundle or * require capability is optional and the bundle may be resolved without the * import, require bundle or require capability being resolved. If the * import, require bundle or require capability is not resolved when the * bundle is resolved, the import, require bundle or require capability may * not be resolved until the bundle is refreshed. * *

* The directive value is encoded in the Import-Package, Require-Bundle or * Require-Capability manifest header like: * *

	 *     Import-Package: org.osgi.framework; resolution:="optional"
	 *     Require-Bundle: com.acme.module.test; resolution:="optional"
	 *     Require-Capability: com.acme.capability; resolution:="optional"
	 * 
* * @see #RESOLUTION_DIRECTIVE * @since 1.3 */ String RESOLUTION_OPTIONAL = "optional"; /** * Manifest header directive identifying a list of packages that an exported * package or provided capability uses. * *

* The directive value is encoded in the Export-Package or * Provide-Capability manifest header like: * *

	 *     Export-Package: org.osgi.util.tracker; uses:="org.osgi.framework"
	 *     Provide-Capability: com.acme.capability; uses:="com.acme.service"
	 * 
* * @see #EXPORT_PACKAGE * @see #PROVIDE_CAPABILITY * @since 1.3 */ String USES_DIRECTIVE = "uses"; /** * Manifest header directive identifying a list of classes to include in the * exported package. * *

* This directive is used by the Export-Package manifest header to identify * a list of classes of the specified package which must be allowed to be * exported. The directive value is encoded in the Export-Package manifest * header like: * *

	 *     Export-Package: org.osgi.framework; include:="MyClass*"
	 * 
* *

* This directive is also used by the Bundle-ActivationPolicy manifest * header to identify the packages from which class loads will trigger lazy * activation. The directive value is encoded in the Bundle-ActivationPolicy * manifest header like: * *

	 *     Bundle-ActivationPolicy: lazy; include:="org.osgi.framework"
	 * 
* * @see #EXPORT_PACKAGE * @see #BUNDLE_ACTIVATIONPOLICY * @since 1.3 */ String INCLUDE_DIRECTIVE = "include"; /** * Manifest header directive identifying a list of classes to exclude in the * exported package.. *

* This directive is used by the Export-Package manifest header to identify * a list of classes of the specified package which must not be allowed to * be exported. The directive value is encoded in the Export-Package * manifest header like: * *

	 *     Export-Package: org.osgi.framework; exclude:="*Impl"
	 * 
* *

* This directive is also used by the Bundle-ActivationPolicy manifest * header to identify the packages from which class loads will not trigger * lazy activation. The directive value is encoded in the * Bundle-ActivationPolicy manifest header like: * *

	 *     Bundle-ActivationPolicy: lazy; exclude:="org.osgi.framework"
	 * 
* * @see #EXPORT_PACKAGE * @see #BUNDLE_ACTIVATIONPOLICY * @since 1.3 */ String EXCLUDE_DIRECTIVE = "exclude"; /** * Manifest header directive identifying names of matching attributes which * must be specified by matching Import-Package statements in the * Export-Package manifest header. * *

* The directive value is encoded in the Export-Package manifest header * like: * *

	 *     Export-Package: org.osgi.framework; mandatory:="bundle-symbolic-name"
	 * 
* * @see #EXPORT_PACKAGE * @since 1.3 */ String MANDATORY_DIRECTIVE = "mandatory"; /** * Manifest header directive identifying the visibility of a required bundle * in the Require-Bundle manifest header. The default value is * {@link #VISIBILITY_PRIVATE private}. * *

* The directive value is encoded in the Require-Bundle manifest header * like: * *

	 *     Require-Bundle: com.acme.module.test; visibility:="reexport"
	 * 
* * @see #REQUIRE_BUNDLE * @see #VISIBILITY_PRIVATE * @see #VISIBILITY_REEXPORT * @since 1.3 */ String VISIBILITY_DIRECTIVE = "visibility"; /** * Manifest header directive value identifying a private visibility type. A * private visibility type indicates that any packages that are exported by * the required bundle are not made visible on the export signature of the * requiring bundle. * *

* The directive value is encoded in the Require-Bundle manifest header * like: * *

	 *     Require-Bundle: com.acme.module.test; visibility:="private"
	 * 
* * @see #VISIBILITY_DIRECTIVE * @since 1.3 */ String VISIBILITY_PRIVATE = "private"; /** * Manifest header directive value identifying a reexport visibility type. A * reexport visibility type indicates any packages that are exported by the * required bundle are re-exported by the requiring bundle. Any arbitrary * arbitrary matching attributes with which they were exported by the * required bundle are deleted. * *

* The directive value is encoded in the Require-Bundle manifest header * like: * *

	 *     Require-Bundle: com.acme.module.test; visibility:="reexport"
	 * 
* * @see #VISIBILITY_DIRECTIVE * @since 1.3 */ String VISIBILITY_REEXPORT = "reexport"; /** * Manifest header directive identifying the type of the extension fragment. * *

* The directive value is encoded in the Fragment-Host manifest header like: * *

	 *     Fragment-Host: system.bundle; extension:="framework"
	 * 
* * @see #FRAGMENT_HOST * @see #EXTENSION_FRAMEWORK * @see #EXTENSION_BOOTCLASSPATH * @since 1.3 */ String EXTENSION_DIRECTIVE = "extension"; /** * Manifest header directive value identifying the type of extension * fragment. An extension fragment type of framework indicates that the * extension fragment is to be loaded by the framework's class loader. * *

* The directive value is encoded in the Fragment-Host manifest header like: * *

	 *     Fragment-Host: system.bundle; extension:="framework"
	 * 
* * @see #EXTENSION_DIRECTIVE * @since 1.3 */ String EXTENSION_FRAMEWORK = "framework"; /** * Manifest header directive value identifying the type of extension * fragment. An extension fragment type of bootclasspath indicates that the * extension fragment is to be loaded by the boot class loader. * *

* The directive value is encoded in the Fragment-Host manifest header like: * *

	 *     Fragment-Host: system.bundle; extension:="bootclasspath"
	 * 
* * @see #EXTENSION_DIRECTIVE * @since 1.3 */ String EXTENSION_BOOTCLASSPATH = "bootclasspath"; /** * Manifest header identifying the bundle's activation policy. *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. * * @since 1.4 * @see #ACTIVATION_LAZY * @see #INCLUDE_DIRECTIVE * @see #EXCLUDE_DIRECTIVE */ String BUNDLE_ACTIVATIONPOLICY = "Bundle-ActivationPolicy"; /** * Bundle activation policy declaring the bundle must be activated when the * first class load is made from the bundle. *

* A bundle with the lazy activation policy that is started with the * {@link Bundle#START_ACTIVATION_POLICY START_ACTIVATION_POLICY} option * will wait in the {@link Bundle#STARTING STARTING} state until the first * class load from the bundle occurs. The bundle will then be activated * before the class is returned to the requester. *

* The activation policy value is specified as in the * Bundle-ActivationPolicy manifest header like: * *

	 *       Bundle-ActivationPolicy: lazy
	 * 
* * @see #BUNDLE_ACTIVATIONPOLICY * @see Bundle#start(int) * @see Bundle#START_ACTIVATION_POLICY * @since 1.4 */ String ACTIVATION_LAZY = "lazy"; /** * Framework environment property identifying the Framework version. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. */ String FRAMEWORK_VERSION = "org.osgi.framework.version"; /** * Framework environment property identifying the Framework implementation * vendor. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. */ String FRAMEWORK_VENDOR = "org.osgi.framework.vendor"; /** * Framework launching property identifying the Framework implementation * language (see ISO 639 for possible values). * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. */ String FRAMEWORK_LANGUAGE = "org.osgi.framework.language"; /** * Framework launching property identifying the Framework host-computer's * operating system. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. */ String FRAMEWORK_OS_NAME = "org.osgi.framework.os.name"; /** * Framework launching property identifying the Framework host-computer's * operating system version number. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. */ String FRAMEWORK_OS_VERSION = "org.osgi.framework.os.version"; /** * Framework launching property identifying the Framework host-computer's * processor name. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. */ String FRAMEWORK_PROCESSOR = "org.osgi.framework.processor"; /** * Framework launching property identifying execution environments provided * by the Framework. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. * * @since 1.2 * @deprecated As of 1.6. Replaced by the {@code osgi.ee} capability. */ String FRAMEWORK_EXECUTIONENVIRONMENT = "org.osgi.framework.executionenvironment"; /** * Framework launching property identifying packages for which the Framework * must delegate class loading to the parent class loader of the bundle. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. * * @see #FRAMEWORK_BUNDLE_PARENT * @since 1.3 */ String FRAMEWORK_BOOTDELEGATION = "org.osgi.framework.bootdelegation"; /** * Framework launching property identifying packages which the system bundle * must export. * *

* If this property is not specified then the framework must calculate a * reasonable default value for the current execution environment. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. * * @since 1.3 */ String FRAMEWORK_SYSTEMPACKAGES = "org.osgi.framework.system.packages"; /** * Framework launching property identifying extra packages which the system * bundle must export from the current execution environment. * *

* This property is useful for configuring extra system packages in addition * to the system packages calculated by the framework. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. * * @see #FRAMEWORK_SYSTEMPACKAGES * @since 1.5 */ String FRAMEWORK_SYSTEMPACKAGES_EXTRA = "org.osgi.framework.system.packages.extra"; /** * Framework environment property identifying whether the Framework supports * framework extension bundles. * *

* As of version 1.4, the value of this property must be {@code true}. The * Framework must support framework extension bundles. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. * * @since 1.3 */ String SUPPORTS_FRAMEWORK_EXTENSION = "org.osgi.supports.framework.extension"; /** * Framework environment property identifying whether the Framework supports * bootclasspath extension bundles. * *

* If the value of this property is {@code true}, then the Framework * supports bootclasspath extension bundles. The default value is * {@code false}. *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. * * @since 1.3 */ String SUPPORTS_BOOTCLASSPATH_EXTENSION = "org.osgi.supports.bootclasspath.extension"; /** * Framework environment property identifying whether the Framework supports * fragment bundles. * *

* As of version 1.4, the value of this property must be {@code true}. The * Framework must support fragment bundles. *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. * * @since 1.3 */ String SUPPORTS_FRAMEWORK_FRAGMENT = "org.osgi.supports.framework.fragment"; /** * Framework environment property identifying whether the Framework supports * the {@link #REQUIRE_BUNDLE Require-Bundle} manifest header. * *

* As of version 1.4, the value of this property must be {@code true}. The * Framework must support the {@code Require-Bundle} manifest header. *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. * * @since 1.3 */ String SUPPORTS_FRAMEWORK_REQUIREBUNDLE = "org.osgi.supports.framework.requirebundle"; /** * Framework launching property specifying the type of security manager the * framework must use. If not specified then the framework will not set the * VM security manager. * * @see #FRAMEWORK_SECURITY_OSGI * @since 1.5 */ String FRAMEWORK_SECURITY = "org.osgi.framework.security"; /** * Specifies that a security manager that supports all security aspects of * the OSGi core specification including postponed conditions must be * installed. * *

* If this value is specified and there is a security manager already * installed, then a {@code SecurityException} must be thrown when the * Framework is initialized. * * @see #FRAMEWORK_SECURITY * @since 1.5 */ String FRAMEWORK_SECURITY_OSGI = "osgi"; /** * Framework launching property specifying the persistent storage area used * by the framework. The value of this property must be a valid file path in * the file system to a directory. If the specified directory does not exist * then the framework will create the directory. If the specified path * exists but is not a directory or if the framework fails to create the * storage directory, then framework initialization must fail. The framework * is free to use this directory as it sees fit. This area can not be shared * with anything else. *

* If this property is not set, the framework should use a reasonable * platform default for the persistent storage area. * * @since 1.5 */ String FRAMEWORK_STORAGE = "org.osgi.framework.storage"; /** * Framework launching property specifying if and when the persistent * storage area for the framework should be cleaned. If this property is not * set, then the framework storage area must not be cleaned. * * @see #FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT * @since 1.5 */ String FRAMEWORK_STORAGE_CLEAN = "org.osgi.framework.storage.clean"; /** * Specifies that the framework storage area must be cleaned before the * framework is initialized for the first time. Subsequent inits, starts or * updates of the framework will not result in cleaning the framework * storage area. * * @since 1.5 */ String FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT = "onFirstInit"; /** * Framework launching property specifying a comma separated list of * additional library file extensions that must be used when a bundle's * class loader is searching for native libraries. If this property is not * set, then only the library name returned by * {@code System.mapLibraryName(String)} will be used to search. This is * needed for certain operating systems which allow more than one extension * for a library. For example, AIX allows library extensions of {@code .a} * and {@code .so}, but {@code System.mapLibraryName(String)} will only * return names with the {@code .a} extension. * * @since 1.5 */ String FRAMEWORK_LIBRARY_EXTENSIONS = "org.osgi.framework.library.extensions"; /** * Framework launching property specifying an optional OS specific command * to set file permissions on extracted native code. On some operating * systems, it is required that native libraries be set to executable. This * optional property allows you to specify the command. For example, on a * UNIX style OS, this property could have the following value. * *

	 * chmod +rx ${abspath}
	 * 
* * The ${abspath} is used by the framework to substitute the * actual absolute file path. * * @since 1.5 */ String FRAMEWORK_EXECPERMISSION = "org.osgi.framework.command.execpermission"; /** * Specified the substitution string for the absolute path of a file. * * @see #FRAMEWORK_EXECPERMISSION * @since 1.6 */ String FRAMEWORK_COMMAND_ABSPATH = "abspath"; /** * Framework launching property specifying the trust repositories used by * the framework. The value is a {@code java.io.File.pathSeparator} * separated list of valid file paths to files that contain key stores. Key * stores of type {@code JKS} must be supported and other key store types * may be supported. The framework will use the key stores as trust * repositories to authenticate certificates of trusted signers. The key * stores are only used as read-only trust repositories to access public * keys. No passwords are required to access the key stores' public keys. *

* Note that framework implementations are allowed to use other trust * repositories in addition to the trust repositories specified by this * property. How these other trust repositories are configured and populated * is implementation specific. * * @since 1.5 */ String FRAMEWORK_TRUST_REPOSITORIES = "org.osgi.framework.trust.repositories"; /** * Framework launching property specifying the current windowing system. The * framework should provide a reasonable default if this is not set. * * @since 1.5 */ String FRAMEWORK_WINDOWSYSTEM = "org.osgi.framework.windowsystem"; /** * Framework launching property specifying the beginning start level of the * framework. * * @see "Core Specification, Starting the Framework." * @since 1.5 */ String FRAMEWORK_BEGINNING_STARTLEVEL = "org.osgi.framework.startlevel.beginning"; /** * Framework launching property specifying the parent class loader type for * all bundle class loaders. Default value is * {@link #FRAMEWORK_BUNDLE_PARENT_BOOT boot}. * * @see #FRAMEWORK_BUNDLE_PARENT_BOOT * @see #FRAMEWORK_BUNDLE_PARENT_EXT * @see #FRAMEWORK_BUNDLE_PARENT_APP * @see #FRAMEWORK_BUNDLE_PARENT_FRAMEWORK * @since 1.5 */ String FRAMEWORK_BUNDLE_PARENT = "org.osgi.framework.bundle.parent"; /** * Specifies to use of the boot class loader as the parent class loader for * all bundle class loaders. * * @since 1.5 * @see #FRAMEWORK_BUNDLE_PARENT */ String FRAMEWORK_BUNDLE_PARENT_BOOT = "boot"; /** * Specifies to use the extension class loader as the parent class loader * for all bundle class loaders. * * @since 1.5 * @see #FRAMEWORK_BUNDLE_PARENT */ String FRAMEWORK_BUNDLE_PARENT_EXT = "ext"; /** * Specifies to use the application class loader as the parent class loader * for all bundle class loaders. Depending on how the framework is launched, * this may refer to the same class loader as * {@link #FRAMEWORK_BUNDLE_PARENT_FRAMEWORK}. * * @since 1.5 * @see #FRAMEWORK_BUNDLE_PARENT */ String FRAMEWORK_BUNDLE_PARENT_APP = "app"; /** * Specifies to use the framework class loader as the parent class loader * for all bundle class loaders. The framework class loader is the class * loader used to load the framework implementation. Depending on how the * framework is launched, this may refer to the same class loader as * {@link #FRAMEWORK_BUNDLE_PARENT_APP}. * * @since 1.5 * @see #FRAMEWORK_BUNDLE_PARENT */ String FRAMEWORK_BUNDLE_PARENT_FRAMEWORK = "framework"; /* * Service properties. */ /** * Service property identifying all of the class names under which a service * was registered in the Framework. The value of this property must be of * type {@code String[]}. * *

* This property is set by the Framework when a service is registered. */ String OBJECTCLASS = "objectClass"; /** * Service property identifying a service's registration number. The value * of this property must be of type {@code Long}. * *

* The value of this property is assigned by the Framework when a service is * registered. The Framework assigns a unique value that is larger than all * previously assigned values since the Framework was started. These values * are NOT persistent across restarts of the Framework. */ String SERVICE_ID = "service.id"; /** * Service property identifying a service's persistent identifier. * *

* This property may be supplied in the {@code properties} * {@code Dictionary} object passed to the * {@code BundleContext.registerService} method. The value of this property * must be of type {@code String}, {@code String[]}, or {@code Collection} * of {@code String}. * *

* A service's persistent identifier uniquely identifies the service and * persists across multiple Framework invocations. * *

* By convention, every bundle has its own unique namespace, starting with * the bundle's identifier (see {@link Bundle#getBundleId()}) and followed * by a dot (.). A bundle may use this as the prefix of the persistent * identifiers for the services it registers. */ String SERVICE_PID = "service.pid"; /** * Service property identifying a service's ranking number. * *

* This property may be supplied in the {@code properties * Dictionary} object passed to the {@code BundleContext.registerService} * method. The value of this property must be of type {@code Integer}. * *

* The service ranking is used by the Framework to determine the natural * order of services, see {@link ServiceReference#compareTo(Object)}, * and the default service to be returned from a call to the * {@link BundleContext#getServiceReference(Class)} or * {@link BundleContext#getServiceReference(String)} method. * *

* The default ranking is zero (0). A service with a ranking of * {@code Integer.MAX_VALUE} is very likely to be returned as the default * service, whereas a service with a ranking of {@code Integer.MIN_VALUE} is * very unlikely to be returned. * *

* If the supplied property value is not of type {@code Integer}, it is * deemed to have a ranking value of zero. */ String SERVICE_RANKING = "service.ranking"; /** * Service property identifying a service's vendor. * *

* This property may be supplied in the properties {@code Dictionary} object * passed to the {@code BundleContext.registerService} method. */ String SERVICE_VENDOR = "service.vendor"; /** * Service property identifying a service's description. * *

* This property may be supplied in the properties {@code Dictionary} object * passed to the {@code BundleContext.registerService} method. */ String SERVICE_DESCRIPTION = "service.description"; /** * Framework environment property identifying the Framework's universally * unique identifier (UUID). A UUID represents a 128-bit value. A new UUID * is generated by the {@link Framework#init()} method each time a framework * is initialized. The value of this property must conform to the UUID * string representation specified in RFC 4122. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. * * @since 1.6 */ String FRAMEWORK_UUID = "org.osgi.framework.uuid"; /** * Service property identifying the configuration types supported by a * distribution provider. Registered by the distribution provider on one of * its services to indicate the supported configuration types. * *

* The value of this property must be of type {@code String}, * {@code String[]}, or {@code Collection} of {@code String}. * * @since 1.6 * @see "Remote Services Specification" */ String REMOTE_CONFIGS_SUPPORTED = "remote.configs.supported"; /** * Service property identifying the intents supported by a distribution * provider. Registered by the distribution provider on one of its services * to indicate the vocabulary of implemented intents. * *

* The value of this property must be of type {@code String}, * {@code String[]}, or {@code Collection} of {@code String}. * * @since 1.6 * @see "Remote Services Specification" */ String REMOTE_INTENTS_SUPPORTED = "remote.intents.supported"; /** * Service property identifying the configuration types that should be used * to export the service. Each configuration type represents the * configuration parameters for an endpoint. A distribution provider should * create an endpoint for each configuration type that it supports. * *

* This property may be supplied in the {@code properties} * {@code Dictionary} object passed to the * {@code BundleContext.registerService} method. The value of this property * must be of type {@code String}, {@code String[]}, or {@code Collection} * of {@code String}. * * @since 1.6 * @see "Remote Services Specification" */ String SERVICE_EXPORTED_CONFIGS = "service.exported.configs"; /** * Service property identifying the intents that the distribution provider * must implement to distribute the service. Intents listed in this property * are reserved for intents that are critical for the code to function * correctly, for example, ordering of messages. These intents should not be * configurable. * *

* This property may be supplied in the {@code properties} * {@code Dictionary} object passed to the * {@code BundleContext.registerService} method. The value of this property * must be of type {@code String}, {@code String[]}, or {@code Collection} * of {@code String}. * * @since 1.6 * @see "Remote Services Specification" */ String SERVICE_EXPORTED_INTENTS = "service.exported.intents"; /** * Service property identifying the extra intents that the distribution * provider must implement to distribute the service. This property is * merged with the {@code service.exported.intents} property before the * distribution provider interprets the listed intents; it has therefore the * same semantics but the property should be configurable so the * administrator can choose the intents based on the topology. Bundles * should therefore make this property configurable, for example through the * Configuration Admin service. * *

* This property may be supplied in the {@code properties} * {@code Dictionary} object passed to the * {@code BundleContext.registerService} method. The value of this property * must be of type {@code String}, {@code String[]}, or {@code Collection} * of {@code String}. * * @since 1.6 * @see "Remote Services Specification" */ String SERVICE_EXPORTED_INTENTS_EXTRA = "service.exported.intents.extra"; /** * Service property marking the service for export. It defines the * interfaces under which this service can be exported. This list must be a * subset of the types under which the service was registered. The single * value of an asterisk ({@code '*'} \u002A) indicates all the interface * types under which the service was registered excluding the non-interface * types. It is strongly recommended to only export interface types and not * concrete classes due to the complexity of creating proxies for some type * of concrete classes. * *

* This property may be supplied in the {@code properties} * {@code Dictionary} object passed to the * {@code BundleContext.registerService} method. The value of this property * must be of type {@code String}, {@code String[]}, or {@code Collection} * of {@code String}. * * @since 1.6 * @see "Remote Services Specification" */ String SERVICE_EXPORTED_INTERFACES = "service.exported.interfaces"; /** * Service property identifying the service as imported. This service * property must be set by a distribution provider to any value when it * registers the endpoint proxy as an imported service. A bundle can use * this property to filter out imported services. * *

* The value of this property may be of any type. * * @since 1.6 * @see "Remote Services Specification" */ String SERVICE_IMPORTED = "service.imported"; /** * Service property identifying the configuration types used to import the * service. Any associated properties for this configuration types must be * properly mapped to the importing system. For example, a URL in these * properties must point to a valid resource when used in the importing * framework. If multiple configuration types are listed in this property, * then they must be synonyms for exactly the same remote endpoint that is * used to export this service. * *

* The value of this property must be of type {@code String}, * {@code String[]}, or {@code Collection} of {@code String}. * * @since 1.6 * @see "Remote Services Specification" * @see #SERVICE_EXPORTED_CONFIGS */ String SERVICE_IMPORTED_CONFIGS = "service.imported.configs"; /** * Service property identifying the intents that this service implement. * This property has a dual purpose: *

    *
  • A bundle can use this service property to notify the distribution * provider that these intents are already implemented by the exported * service object.
  • *
  • A distribution provider must use this property to convey the combined * intents of: the exporting service, the intents that the exporting * distribution provider adds, and the intents that the importing * distribution provider adds.
  • *
* * To export a service, a distribution provider must expand any qualified * intents. Both the exporting and importing distribution providers must * recognize all intents before a service can be distributed. * *

* The value of this property must be of type {@code String}, * {@code String[]}, or {@code Collection} of {@code String}. * * @since 1.6 * @see "Remote Services Specification" */ String SERVICE_INTENTS = "service.intents"; /** * Manifest header identifying the capabilities that the bundle offers to * provide to other bundles. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. * * @since 1.6 */ String PROVIDE_CAPABILITY = "Provide-Capability"; /** * Manifest header identifying the capabilities on which the bundle depends. * *

* The header value may be retrieved from the {@code Dictionary} object * returned by the {@code Bundle.getHeaders} method. * * @since 1.6 */ String REQUIRE_CAPABILITY = "Require-Capability"; /** * Manifest header directive identifying the effective time of the provided * capability. The default value is {@link #EFFECTIVE_RESOLVE resolve}. * *

* The directive value is encoded in the Provide-Capability manifest header * like: * *

	 *     Provide-Capability: com.acme.capability; effective:="resolve"
	 * 
* * @see #PROVIDE_CAPABILITY * @see #EFFECTIVE_RESOLVE * @see #EFFECTIVE_ACTIVE * @since 1.6 */ String EFFECTIVE_DIRECTIVE = "effective"; /** * Manifest header directive value identifying a capability that is * effective at resolve time. Capabilities with an effective time of resolve * are the only capabilities which are processed by the resolver. * *

* The directive value is encoded in the Provide-Capability manifest header * like: * *

	 *     Provide-Capability: com.acme.capability; effective:="resolve"
	 * 
* * @see #EFFECTIVE_DIRECTIVE * @since 1.6 */ String EFFECTIVE_RESOLVE = "resolve"; /** * Manifest header directive value identifying a capability that is * effective at active time. Capabilities with an effective time of active * are ignored by the resolver. * *

* The directive value is encoded in the Provide-Capability manifest header * like: * *

	 *     Provide-Capability: com.acme.capability; effective:="active"
	 * 
* * @see #EFFECTIVE_DIRECTIVE * @since 1.6 */ String EFFECTIVE_ACTIVE = "active"; /** * Manifest header directive identifying the capability filter specified in * the Require-Capability manifest header. * *

* The directive value is encoded in the Require-Capability manifest header * like: * *

	 *     Require-Capability: com.acme.capability; filter:="(someattr=somevalue)"
	 * 
* * @see #REQUIRE_CAPABILITY * @since 1.6 */ String FILTER_DIRECTIVE = "filter"; /** * Framework launching property identifying capabilities which the system * bundle must provide. * *

* If this property is not specified then the framework must calculate a * reasonable default value for the current execution environment. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. * * @since 1.6 */ String FRAMEWORK_SYSTEMCAPABILITIES = "org.osgi.framework.system.capabilities"; /** * Framework launching property identifying extra capabilities which the * system bundle must additionally provide. * *

* This property is useful for configuring extra system capabilities in * addition to the system capabilities calculated by the framework. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. * * @see #FRAMEWORK_SYSTEMCAPABILITIES * @since 1.6 */ String FRAMEWORK_SYSTEMCAPABILITIES_EXTRA = "org.osgi.framework.system.capabilities.extra"; /** * Framework launching property specifying whether multiple bundles having * the same {@link #BUNDLE_SYMBOLICNAME symbolic name} and * {@link #BUNDLE_VERSION version} may be installed. * *

* Default value is {@link #FRAMEWORK_BSNVERSION_MANAGED managed} in this * release of the specification. This default may change in a future * specification release. Therefore, code must not assume the default * behavior is {@code managed} and should interrogate the value of this * property to determine the behavior. * *

* The value of this property may be retrieved by calling the * {@code BundleContext.getProperty} method. * * @see #FRAMEWORK_BSNVERSION_MULTIPLE * @see #FRAMEWORK_BSNVERSION_SINGLE * @see #FRAMEWORK_BSNVERSION_MANAGED * @since 1.6 */ String FRAMEWORK_BSNVERSION = "org.osgi.framework.bsnversion"; /** * Specifies the framework will allow multiple bundles to be installed * having the same symbolic name and version. * * @since 1.6 * @see #FRAMEWORK_BSNVERSION */ String FRAMEWORK_BSNVERSION_MULTIPLE = "multiple"; /** * Specifies the framework will only allow a single bundle to be installed * for a given symbolic name and version. It will be an error to install a * bundle or update a bundle to have the same symbolic name and version as * another installed bundle. * * @since 1.6 * @see #FRAMEWORK_BSNVERSION * @see BundleException#DUPLICATE_BUNDLE_ERROR */ String FRAMEWORK_BSNVERSION_SINGLE = "single"; /** * Specifies the framework must consult the {@link CollisionHook bundle * collision hook} services to determine if it will be an error to install a * bundle or update a bundle to have the same symbolic name and version as * another installed bundle. If no bundle collision hook services are * registered, then it will be an error to install a bundle or update a * bundle to have the same symbolic name and version as another installed * bundle. * * @since 1.7 * @see #FRAMEWORK_BSNVERSION * @see BundleException#DUPLICATE_BUNDLE_ERROR */ String FRAMEWORK_BSNVERSION_MANAGED = "managed"; } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/ServiceEvent.java0000644000175000017500000001062012346513664026676 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.util.Dictionary; import java.util.EventObject; /** * An event from the Framework describing a service lifecycle change. *

* {@code ServiceEvent} objects are delivered to {@code ServiceListener}s and * {@code AllServiceListener}s when a change occurs in this service's lifecycle. * A type code is used to identify the event type for future extendability. * *

* OSGi Alliance reserves the right to extend the set of types. * * @Immutable * @see ServiceListener * @see AllServiceListener * @version $Id: 49e34e0ad5564d6f4ca0ab0053b272c22b9fb917 $ */ public class ServiceEvent extends EventObject { static final long serialVersionUID = 8792901483909409299L; /** * Reference to the service that had a change occur in its lifecycle. */ private final ServiceReference reference; /** * Type of service lifecycle change. */ private final int type; /** * This service has been registered. *

* This event is synchronously delivered after the service * has been registered with the Framework. * * @see BundleContext#registerService(String[],Object,Dictionary) */ public final static int REGISTERED = 0x00000001; /** * The properties of a registered service have been modified. *

* This event is synchronously delivered after the service * properties have been modified. * * @see ServiceRegistration#setProperties(Dictionary) */ public final static int MODIFIED = 0x00000002; /** * This service is in the process of being unregistered. *

* This event is synchronously delivered before the service * has completed unregistering. * *

* If a bundle is using a service that is {@code UNREGISTERING}, the bundle * should release its use of the service when it receives this event. If the * bundle does not release its use of the service when it receives this * event, the Framework will automatically release the bundle's use of the * service while completing the service unregistration operation. * * @see ServiceRegistration#unregister() * @see BundleContext#ungetService(ServiceReference) */ public final static int UNREGISTERING = 0x00000004; /** * The properties of a registered service have been modified and the new * properties no longer match the listener's filter. *

* This event is synchronously delivered after the service * properties have been modified. This event is only delivered to listeners * which were added with a non-{@code null} filter where the filter matched * the service properties prior to the modification but the filter does not * match the modified service properties. * * @see ServiceRegistration#setProperties(Dictionary) * @since 1.5 */ public final static int MODIFIED_ENDMATCH = 0x00000008; /** * Creates a new service event object. * * @param type The event type. * @param reference A {@code ServiceReference} object to the service that * had a lifecycle change. */ public ServiceEvent(int type, ServiceReference reference) { super(reference); this.reference = reference; this.type = type; } /** * Returns a reference to the service that had a change occur in its * lifecycle. *

* This reference is the source of the event. * * @return Reference to the service that had a lifecycle change. */ public ServiceReference getServiceReference() { return reference; } /** * Returns the type of event. The event type values are: *

    *
  • {@link #REGISTERED}
  • *
  • {@link #MODIFIED}
  • *
  • {@link #MODIFIED_ENDMATCH}
  • *
  • {@link #UNREGISTERING}
  • *
* * @return Type of service lifecycle change. */ public int getType() { return type; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/AdaptPermission.java0000644000175000017500000004317412346513664027410 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2010, 2012). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.security.AccessController; import java.security.BasicPermission; import java.security.Permission; import java.security.PermissionCollection; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A bundle's authority to adapt an object to a type. * *

* {@code AdaptPermission} has one action: {@code adapt}. * * @ThreadSafe * @version $Id: 3bc095bd294db2d8ea25971a3d71991de1495b1a $ */ public final class AdaptPermission extends BasicPermission { private static final long serialVersionUID = 1L; /** * The action string {@code initiate}. */ public final static String ADAPT = "adapt"; private final static int ACTION_ADAPT = 0x00000001; private final static int ACTION_ALL = ACTION_ADAPT; final static int ACTION_NONE = 0; /** * The actions mask. */ transient int action_mask; /** * The actions in canonical form. * * @serial */ private volatile String actions = null; /** * The bundle used by this AdaptPermission. */ transient final Bundle bundle; /** * This holds a Filter matching object used to evaluate the filter in * implies. */ transient Filter filter; /** * This map holds the properties of the permission, used to match a filter * in implies. This is not initialized until necessary, and then cached in * this object. */ private transient volatile Map properties; /** * Creates a new granted {@code AdaptPermission} object. * * This constructor must only be used to create a permission that is going * to be checked. *

* Examples: * *

	 * (adaptClass=com.acme.*)
	 * (&(signer=\*,o=ACME,c=US)(adaptClass=com.acme.*))
	 * (signer=\*,o=ACME,c=US)
	 * 
* *

* When a signer key is used within the filter expression the signer value * must escape the special filter chars ('*', '(', ')'). *

* The name is specified as a filter expression. The filter gives access to * the following attributes: *

    *
  • signer - A Distinguished Name chain used to sign the exporting * bundle. Wildcards in a DN are not matched according to the filter string * rules, but according to the rules defined for a DN chain.
  • *
  • location - The location of the exporting bundle.
  • *
  • id - The bundle ID of the exporting bundle.
  • *
  • name - The symbolic name of the exporting bundle.
  • *
  • adaptClass - The name of the type to which an object can be adapted.
  • *
* Filter attribute names are processed in a case sensitive manner. * * @param filter A filter expression. Filter attribute names are processed * in a case sensitive manner. A special value of {@code "*"} can be * used to match all adaptations. * @param actions {@code adapt}. * @throws IllegalArgumentException If the filter has an invalid syntax. */ public AdaptPermission(String filter, String actions) { this(parseFilter(filter), parseActions(actions)); } /** * Creates a new requested {@code AdaptPermission} object to be used by the * code that must perform {@code checkPermission}. {@code AdaptPermission} * objects created with this constructor cannot be added to an * {@code AdaptPermission} permission collection. * * @param adaptClass The name of the type to which an object can be adapted. * @param adaptableBundle The bundle associated with the object being * adapted. * @param actions {@code adapt}. */ public AdaptPermission(String adaptClass, Bundle adaptableBundle, String actions) { super(adaptClass); setTransients(null, parseActions(actions)); this.bundle = adaptableBundle; if (adaptClass == null) { throw new NullPointerException("adaptClass must not be null"); } if (adaptableBundle == null) { throw new NullPointerException("adaptableBundle must not be null"); } } /** * Package private constructor used by AdaptPermissionCollection. * * @param filter name filter * @param mask action mask */ AdaptPermission(Filter filter, int mask) { super((filter == null) ? "*" : filter.toString()); setTransients(filter, mask); this.bundle = null; } /** * Called by constructors and when deserialized. * * @param filter Permission's filter or {@code null} for wildcard. * @param mask action mask */ private void setTransients(Filter filter, int mask) { this.filter = filter; if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { throw new IllegalArgumentException("invalid action string"); } this.action_mask = mask; } /** * Parse action string into action mask. * * @param actions Action string. * @return action mask. */ private static int parseActions(String actions) { boolean seencomma = false; int mask = ACTION_NONE; if (actions == null) { return mask; } char[] a = actions.toCharArray(); int i = a.length - 1; if (i < 0) return mask; while (i != -1) { char c; // skip whitespace while ((i != -1) && ((c = a[i]) == ' ' || c == '\r' || c == '\n' || c == '\f' || c == '\t')) i--; // check for the known strings int matchlen; if (i >= 4 && (a[i - 4] == 'a' || a[i - 4] == 'A') && (a[i - 3] == 'd' || a[i - 3] == 'D') && (a[i - 2] == 'a' || a[i - 2] == 'A') && (a[i - 1] == 'p' || a[i - 1] == 'P') && (a[i] == 't' || a[i] == 'T')) { matchlen = 5; mask |= ACTION_ADAPT; } else { // parse error throw new IllegalArgumentException("invalid actions: " + actions); } // make sure we didn't just match the tail of a word // like "ackbarfadapt". Also, skip to the comma. seencomma = false; while (i >= matchlen && !seencomma) { switch (a[i - matchlen]) { case ',' : seencomma = true; /* FALLTHROUGH */ case ' ' : case '\r' : case '\n' : case '\f' : case '\t' : break; default : throw new IllegalArgumentException("invalid permission: " + actions); } i--; } // point i at the location of the comma minus one (or -1). i -= matchlen; } if (seencomma) { throw new IllegalArgumentException("invalid actions: " + actions); } return mask; } /** * Parse filter string into a Filter object. * * @param filterString The filter string to parse. * @return a Filter for this bundle. * @throws IllegalArgumentException If the filter syntax is invalid. */ private static Filter parseFilter(String filterString) { filterString = filterString.trim(); if (filterString.equals("*")) { return null; } try { return FrameworkUtil.createFilter(filterString); } catch (InvalidSyntaxException e) { IllegalArgumentException iae = new IllegalArgumentException("invalid filter"); iae.initCause(e); throw iae; } } /** * Determines if the specified permission is implied by this object. * *

* This method checks that the filter of the target is implied by the adapt * class name of this object. The list of {@code AdaptPermission} actions * must either match or allow for the list of the target object to imply the * target {@code AdaptPermission} action. *

* * @param p The requested permission. * @return {@code true} if the specified permission is implied by this * object; {@code false} otherwise. */ public boolean implies(Permission p) { if (!(p instanceof AdaptPermission)) { return false; } AdaptPermission requested = (AdaptPermission) p; if (bundle != null) { return false; } // if requested permission has a filter, then it is an invalid argument if (requested.filter != null) { return false; } return implies0(requested, ACTION_NONE); } /** * Internal implies method. Used by the implies and the permission * collection implies methods. * * @param requested The requested AdaptPermission which has already be * validated as a proper argument. The requested AdaptPermission must * not have a filter expression. * @param effective The effective actions with which to start. * @return {@code true} if the specified permission is implied by this * object; {@code false} otherwise. */ boolean implies0(AdaptPermission requested, int effective) { /* check actions first - much faster */ effective |= action_mask; final int desired = requested.action_mask; if ((effective & desired) != desired) { return false; } /* Get filter */ Filter f = filter; if (f == null) { // it's "*" return true; } return f.matches(requested.getProperties()); } /** * Returns the canonical string representation of the * {@code AdaptPermission} actions. * *

* Always returns present {@code AdaptPermission} actions in the following * order: {@code adapt}. * * @return Canonical string representation of the {@code AdaptPermission} * actions. */ public String getActions() { String result = actions; if (result == null) { actions = result = ADAPT; } return result; } /** * Returns a new {@code PermissionCollection} object suitable for storing * {@code AdaptPermission} objects. * * @return A new {@code PermissionCollection} object. */ public PermissionCollection newPermissionCollection() { return new AdaptPermissionCollection(); } /** * Determines the equality of two {@code AdaptPermission} objects. * * This method checks that specified permission has the same name and * {@code AdaptPermission} actions as this {@code AdaptPermission} object. * * @param obj The object to test for equality with this * {@code AdaptPermission} object. * @return {@code true} if {@code obj} is a {@code AdaptPermission}, and has * the same name and actions as this {@code AdaptPermission} object; * {@code false} otherwise. */ public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof AdaptPermission)) { return false; } AdaptPermission cp = (AdaptPermission) obj; return (action_mask == cp.action_mask) && getName().equals(cp.getName()) && ((bundle == cp.bundle) || ((bundle != null) && bundle.equals(cp.bundle))); } /** * Returns the hash code value for this object. * * @return A hash code value for this object. */ public int hashCode() { int h = 31 * 17 + getName().hashCode(); h = 31 * h + getActions().hashCode(); if (bundle != null) { h = 31 * h + bundle.hashCode(); } return h; } /** * WriteObject is called to save the state of this permission object to a * stream. The actions are serialized, and the superclass takes care of the * name. */ private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { if (bundle != null) { throw new NotSerializableException("cannot serialize"); } // Write out the actions. The superclass takes care of the name // call getActions to make sure actions field is initialized if (actions == null) getActions(); s.defaultWriteObject(); } /** * readObject is called to restore the state of this permission from a * stream. */ private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the action, then initialize the rest s.defaultReadObject(); setTransients(parseFilter(getName()), parseActions(actions)); } /** * Called by {@code <@link AdaptPermission#implies(Permission)>}. This * method is only called on a requested permission which cannot have a * filter set. * * @return a map of properties for this permission. */ private Map getProperties() { Map result = properties; if (result != null) { return result; } final Map map = new HashMap(5); map.put("adaptClass", getName()); if (bundle != null) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { map.put("id", new Long(bundle.getBundleId())); map.put("location", bundle.getLocation()); String name = bundle.getSymbolicName(); if (name != null) { map.put("name", name); } SignerProperty signer = new SignerProperty(bundle); if (signer.isBundleSigned()) { map.put("signer", signer); } return null; } }); } return properties = map; } } /** * Stores a set of {@code AdaptPermission} permissions. * * @see java.security.Permission * @see java.security.Permissions * @see java.security.PermissionCollection */ final class AdaptPermissionCollection extends PermissionCollection { static final long serialVersionUID = -3350758995234427603L; /** * Collection of permissions. * * @serial * @GuardedBy this */ private Map permissions; /** * Boolean saying if "*" is in the collection. * * @serial * @GuardedBy this */ private boolean all_allowed; /** * Create an empty AdaptPermissions object. */ public AdaptPermissionCollection() { permissions = new HashMap(); all_allowed = false; } /** * Adds a permission to this permission collection. * * @param permission The {@code AdaptPermission} object to add. * @throws IllegalArgumentException If the specified permission is not a * {@code AdaptPermission} instance or was constructed with a Bundle * object. * @throws SecurityException If this {@code AdaptPermissionCollection} * object has been marked read-only. */ public void add(final Permission permission) { if (!(permission instanceof AdaptPermission)) { throw new IllegalArgumentException("invalid permission: " + permission); } if (isReadOnly()) { throw new SecurityException("attempt to add a Permission to a " + "readonly PermissionCollection"); } final AdaptPermission ap = (AdaptPermission) permission; if (ap.bundle != null) { throw new IllegalArgumentException("cannot add to collection: " + ap); } final String name = ap.getName(); synchronized (this) { Map pc = permissions; final AdaptPermission existing = pc.get(name); if (existing != null) { final int oldMask = existing.action_mask; final int newMask = ap.action_mask; if (oldMask != newMask) { pc.put(name, new AdaptPermission(existing.filter, oldMask | newMask)); } } else { pc.put(name, ap); } if (!all_allowed) { if (name.equals("*")) { all_allowed = true; } } } } /** * Determines if the specified permissions implies the permissions expressed * in {@code permission}. * * @param permission The Permission object to compare with this * {@code AdaptPermission} object. * @return {@code true} if {@code permission} is a proper subset of a * permission in the set; {@code false} otherwise. */ public boolean implies(final Permission permission) { if (!(permission instanceof AdaptPermission)) { return false; } final AdaptPermission requested = (AdaptPermission) permission; /* if requested permission has a filter, then it is an invalid argument */ if (requested.filter != null) { return false; } int effective = AdaptPermission.ACTION_NONE; Collection perms; synchronized (this) { Map pc = permissions; /* short circuit if the "*" Permission was added */ if (all_allowed) { AdaptPermission ap = pc.get("*"); if (ap != null) { effective |= ap.action_mask; final int desired = requested.action_mask; if ((effective & desired) == desired) { return true; } } } perms = pc.values(); } /* iterate one by one over filteredPermissions */ for (AdaptPermission perm : perms) { if (perm.implies0(requested, effective)) { return true; } } return false; } /** * Returns an enumeration of all {@code AdaptPermission} objects in the * container. * * @return Enumeration of all {@code AdaptPermission} objects. */ public synchronized Enumeration elements() { List all = new ArrayList(permissions.values()); return Collections.enumeration(all); } /* serialization logic */ private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("permissions", HashMap.class), new ObjectStreamField("all_allowed", Boolean.TYPE)}; private synchronized void writeObject(ObjectOutputStream out) throws IOException { ObjectOutputStream.PutField pfields = out.putFields(); pfields.put("permissions", permissions); pfields.put("all_allowed", all_allowed); out.writeFields(); } private synchronized void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gfields = in.readFields(); permissions = (HashMap) gfields.get("permissions", null); all_allowed = gfields.get("all_allowed", false); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/osgi/framework/BundleListener.java0000644000175000017500000000333012346513664027213 0ustar felixfelix/* * Copyright (c) OSGi Alliance (2000, 2011). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.framework; import java.util.EventListener; /** * A {@code BundleEvent} listener. {@code BundleListener} is a listener * interface that may be implemented by a bundle developer. When a * {@code BundleEvent} is fired, it is asynchronously delivered to a * {@code BundleListener}. The Framework delivers {@code BundleEvent} objects to * a {@code BundleListener} in order and must not concurrently call a * {@code BundleListener}. *

* A {@code BundleListener} object is registered with the Framework using the * {@link BundleContext#addBundleListener(BundleListener)} method. * {@code BundleListener}s are called with a {@code BundleEvent} object when a * bundle has been installed, resolved, started, stopped, updated, unresolved, * or uninstalled. * * @see BundleEvent * @NotThreadSafe * @version $Id: d48b4a8a59c839466a3d749dde23980d236f58c6 $ */ public interface BundleListener extends EventListener { /** * Receives notification that a bundle has had a lifecycle change. * * @param event The {@code BundleEvent}. */ public void bundleChanged(BundleEvent event); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/0000755000175000017500000000000012475375714023173 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/0000755000175000017500000000000012475375714025170 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleGeneration.java0000644000175000017500000011340112346513666031255 0ustar felixfelix/* * Copyright (c) 2010-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.security.ProtectionDomain; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.Vector; import org.knopflerfish.framework.Util.HeaderEntry; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.Version; import org.osgi.framework.hooks.bundle.CollisionHook; import org.osgi.framework.namespace.ExecutionEnvironmentNamespace; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRevision; /** * Bundle generation specific data. * * @see org.osgi.framework.Bundle * @author Jan Stein */ public class BundleGeneration implements Comparable { /** * Symbolic name system bundle. */ final static String KNOPFLERFISH_SYMBOLICNAME = "org.knopflerfish.framework"; /** * Bundle */ final BundleImpl bundle; /** * Packages that the bundle wants to export and import. */ final BundlePackages bpkgs; /** * Bundle JAR data. */ final BundleArchive archive; /** * Generation of BundlePackages. */ final int generation; /** * Does bundle have a version 2 manifest. */ final boolean v2Manifest; /** * Bundle symbolic name. */ final String symbolicName; /** * Symbolic name parameters */ final HeaderEntry symbolicNameParameters; /** * Bundle is a singleton. */ final boolean singleton; /** * Bundle version. */ final Version version; /** * This bundle's fragment attach policy. */ final String attachPolicy; /** * Fragment description. This is null when the bundle isn't a fragment bundle. */ final Fragment fragment; /** * The bundle requirements from the Require-Capability header. */ final Map> requirements = new HashMap>(); /** * The bundle capabilities from the Provide-Capability header. */ final Map> capabilities = new HashMap>(); /** * True when this bundle has its activation policy set to "lazy" */ final boolean lazyActivation; final private Set lazyIncludes; final private Set lazyExcludes; /** * Time when bundle was last created. * */ final long timeStamp; /** * All fragment bundles this bundle hosts. */ Vector fragments = null; /** * Stores the raw manifest headers. */ private volatile HeaderDictionary cachedRawHeaders = null; /** * Classloader for bundle. */ private volatile ClassLoader classLoader; /** * Bundle protect domain. Will always be null for the system bundle, * methods requiring access to it must be overridden in the SystemBundle * class. */ private ProtectionDomain protectionDomain; private BundleClassPath unresolvedBundleClassPath = null; final BundleRevisionImpl bundleRevision; final private BundleCapability identity; /** * Construct a new BundleGeneration for the System Bundle. * * @param b BundleImpl this bundle data. * @param exportStr The value of the Export-Package header. * @param capabilityStr The value of the Provide-Capability header. */ BundleGeneration(BundleImpl b, String exportStr, String capabilityStr) { bundle = b; archive = null; generation = 0; v2Manifest = true; symbolicName = KNOPFLERFISH_SYMBOLICNAME; symbolicNameParameters = null; singleton = false; version = new Version(Util.readFrameworkVersion()); attachPolicy = Constants.FRAGMENT_ATTACHMENT_ALWAYS; fragment = null; protectionDomain = null; lazyActivation = false; lazyIncludes = null; lazyExcludes = null; timeStamp = System.currentTimeMillis(); bpkgs = new BundlePackages(this, exportStr); bundleRevision = new BundleRevisionImpl(this); classLoader = b.getClassLoader(); processCapabilities(capabilityStr); identity = new BundleCapabilityImpl(this); } /** * Construct a new BundleGeneration. * * Construct a new Bundle based on a BundleArchive. * * @param b BundleImpl this bundle data. * @param ba Bundle archive with holding the contents of the bundle. * @param prev the previous generation of this bundle. * * @throws BundleException If we have duplicate symbolicname and version. * * @exception IOException If we fail to read and store our JAR bundle or if * the input data is corrupted. * @exception SecurityException If we don't have permission to install * extension. * @exception IllegalArgumentException Faulty manifest for bundle */ BundleGeneration(BundleImpl b, BundleArchive ba, BundleGeneration prev, Bundle caller) throws BundleException { bundle = b; generation = (prev != null ? prev.generation : -1) + 1; archive = ba; checkCertificates(); // TODO, v2Manifest unnecessary to cache? final String mv = archive.getAttribute(Constants.BUNDLE_MANIFESTVERSION); v2Manifest = mv != null && mv.trim().equals("2"); final String mbv = archive.getAttribute(Constants.BUNDLE_VERSION); Version newVer = Version.emptyVersion; if (mbv != null) { try { newVer = new Version(mbv); } catch (final Exception ee) { if (v2Manifest) { throw new IllegalArgumentException("Bundle does not specify a valid " + Constants.BUNDLE_VERSION + " header. Got exception: " + ee.getMessage()); } } } version = newVer; List hes = Util.parseManifestHeader(Constants.FRAGMENT_HOST, archive .getAttribute(Constants.FRAGMENT_HOST), true, true, true); if (!hes.isEmpty()) { fragment = new Fragment(this, hes.get(0)); } else { fragment = null; } hes = Util.parseManifestHeader(Constants.BUNDLE_ACTIVATIONPOLICY, archive .getAttribute(Constants.BUNDLE_ACTIVATIONPOLICY), true, true, true); if (!hes.isEmpty()) { HeaderEntry he = hes.get(0); lazyActivation = Constants.ACTIVATION_LAZY.equals(he.getKey()); if (lazyActivation) { if (he.getDirectives().containsKey(Constants.INCLUDE_DIRECTIVE)) { lazyIncludes = Util.parseEnumeration(Constants.INCLUDE_DIRECTIVE, he.getDirectives().get(Constants.INCLUDE_DIRECTIVE)); } else { lazyIncludes = null; } if (he.getDirectives().containsKey(Constants.EXCLUDE_DIRECTIVE)) { lazyExcludes = Util.parseEnumeration(Constants.EXCLUDE_DIRECTIVE, he.getDirectives().get(Constants.EXCLUDE_DIRECTIVE)); if (lazyIncludes != null) { for (final String entry : lazyExcludes) { if (lazyIncludes.contains(entry)) { throw new IllegalArgumentException("Conflicting " + Constants.INCLUDE_DIRECTIVE + "/" + Constants.EXCLUDE_DIRECTIVE + " entries in " + Constants.BUNDLE_ACTIVATIONPOLICY + ": '" + entry + "' both included and excluded"); } } } } else { lazyExcludes = null; } } else { lazyIncludes = null; lazyExcludes = null; } } else { lazyActivation = false; lazyIncludes = null; lazyExcludes = null; } hes = Util.parseManifestHeader(Constants.REQUIRE_CAPABILITY, archive .getAttribute(Constants.REQUIRE_CAPABILITY), true, true, false); for (final HeaderEntry e : hes) { final BundleRequirementImpl bri = new BundleRequirementImpl(this, e); final String ns = bri.getNamespace(); List nsReqs = requirements.get(ns); if (null == nsReqs) { if (isExtension() && !ns.equals(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE)) { throw new IllegalArgumentException("An extension bundle can only specify capability requirements in the " + ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE + " namespace. Not in " + ns); } nsReqs = new ArrayList(); requirements.put(ns, nsReqs); } nsReqs.add(bri); } @SuppressWarnings("deprecation") String ee = archive.getAttribute(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT); if (ee != null) { final BundleRequirementImpl bri = new BundleRequirementImpl(this, ee); List nsReqs = requirements.get(bri.getNamespace()); if (null == nsReqs) { nsReqs = new ArrayList(); requirements.put(bri.getNamespace(), nsReqs); } nsReqs.add(bri); } processCapabilities(archive.getAttribute(Constants.PROVIDE_CAPABILITY)); bpkgs = new BundlePackages(this); try { if (b.fwCtx.startLevelController == null) { archive.setStartLevel(0); } else { if (archive.getStartLevel() == -1) { archive.setStartLevel(b.fwCtx.startLevelController.getInitialBundleStartLevel()); } } } catch (final Exception exc) { b.fwCtx.frameworkError(b, exc); } archive.setBundleGeneration(this); long lastModified = prev != null ? 0 : archive.getLastModified(); if (lastModified == 0) { lastModified = System.currentTimeMillis(); } bundleRevision = new BundleRevisionImpl(this); timeStamp = lastModified; hes = Util .parseManifestHeader(Constants.BUNDLE_SYMBOLICNAME, archive .getAttribute(Constants.BUNDLE_SYMBOLICNAME), true, true, true); HeaderEntry he = null; if (!hes.isEmpty()) { he = hes.get(0); symbolicName = he.getKey(); } else { if (v2Manifest) { throw new IllegalArgumentException("Bundle has no symbolic name, location=" + bundle.location); } else { symbolicName = null; } } if (he != null) { singleton = "true".equals(he.getDirectives().get(Constants.SINGLETON_DIRECTIVE)); final String tmp = he.getDirectives().get(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE); attachPolicy = tmp == null ? Constants.FRAGMENT_ATTACHMENT_ALWAYS : tmp; symbolicNameParameters = he; if (!bundle.fwCtx.bsnversionMode.equals(Constants.FRAMEWORK_BSNVERSION_MULTIPLE)) { final Collection snbl = b.fwCtx.bundles.getBundles(symbolicName, version); if (!snbl.isEmpty() && (snbl.size() > 1 || !snbl.contains(bundle))) { boolean fail; if (bundle.fwCtx.bsnversionMode.equals(Constants.FRAMEWORK_BSNVERSION_MANAGED)) { bundle.fwCtx.bundleHooks.filterCollisions(prev != null ? CollisionHook.UPDATING : CollisionHook.INSTALLING, caller, snbl); fail = !snbl.isEmpty() && (snbl.size() > 1 || !snbl.contains(bundle)); } else { fail = true; } if (fail) { throw new BundleException("Bundle#" + b.id + ", a bundle with same symbolic name and version " + "is already installed (" + symbolicName + ", " + version, BundleException.DUPLICATE_BUNDLE_ERROR); } } } } else { attachPolicy = Constants.FRAGMENT_ATTACHMENT_ALWAYS; singleton = false; symbolicNameParameters = null; } identity = symbolicName != null ? new BundleCapabilityImpl(this) : null; } /** * Construct a new BundleGeneration for an uninstalled bundle. * * @param prev Previous BundleGeneration. */ BundleGeneration(BundleGeneration prev) { bundle = prev.bundle; archive = null; generation = prev.generation + 1; v2Manifest = prev.v2Manifest; symbolicName = prev.symbolicName; symbolicNameParameters = prev.symbolicNameParameters; singleton = prev.singleton; version = prev.version; attachPolicy = Constants.FRAGMENT_ATTACHMENT_NEVER; fragment = prev.fragment; protectionDomain = null; lazyActivation = false; lazyIncludes = null; lazyExcludes = null; timeStamp = System.currentTimeMillis(); bpkgs = null; cachedRawHeaders = prev.cachedRawHeaders; classLoader = null; bundleRevision = null; identity = null; } private void processCapabilities(String capabilityStr) { if (capabilityStr != null && capabilityStr.length() > 0) { for (final HeaderEntry he : Util .parseManifestHeader(Constants.PROVIDE_CAPABILITY, capabilityStr, true, true, false)) { final BundleCapabilityImpl bci = new BundleCapabilityImpl(this, he); List nsCaps = capabilities.get(bci.getNamespace()); if (null == nsCaps) { nsCaps = new ArrayList(); capabilities.put(bci.getNamespace(), nsCaps); } nsCaps.add(bci); } } } /** * Compares this {@code BundleGeneration} object to another * {@code BundleGeneration}. It compares the bundle identifier value. * * @param bg the other object to compare this one to. */ public int compareTo(BundleGeneration bg) { final long diff = bundle.id - bg.bundle.id; if (diff < 0) { return -1; } else if (diff == 0) { return 0; } else { return 1; } } public String toString() { return "BundleGeneration[bid=" + bundle.id + ", gen=" + generation + "]"; } // // Package methods // /** * Finish construction by doing protectDomain creation and permission checks. * * @return Bundles classloader. */ void checkPermissions(Object checkContext) { protectionDomain = bundle.secure.getProtectionDomain(this); try { bundle.secure.checkExtensionLifecycleAdminPerm(bundle, checkContext); if (isExtension() && !bundle.secure.okAllPerm(bundle)) { throw new IllegalArgumentException("An extension bundle must have AllPermission"); } } catch (final RuntimeException re) { purgeProtectionDomain(); throw re; } // Bundle ok save timeStamp if (archive.getLastModified() != timeStamp) { try { archive.setLastModified(timeStamp); } catch (final IOException ioe) { bundle.fwCtx.frameworkError(bundle, ioe); } } } /** * Get capabilities specified by this bundle generation. * * Returns capabilities declared in the Bundle-Capability manifest header. *

* The key in the map is the {@code name-space} of the capability. */ Map> getDeclaredCapabilities() { return capabilities; } /** * Get requirements specified by this bundle generation. * * Returns all requirements declared in the Bundle-Requirement manifest header. *

* The key in the map is the {@code name-space} of the bundle requirement. */ Map> getDeclaredRequirements() { return requirements; } /** * */ boolean resolvePackages(BundleImpl[] triggers) throws BundleException { ArrayList detached = null; attachFragments(); while (true) { if (bpkgs.resolvePackages(triggers)) { if (detached != null) { // TODO should we report fragment that failed to attach for (int i = detached.size() - 2; i >= 0; i--) { final BundleGeneration bg = detached.get(i); if (bg.bundle.attachToFragmentHost(this)) { fragments.add(bg); } } } classLoader = bundle.secure.newBundleClassLoader(this); return true; } if (isFragmentHost()) { if (bundle.fwCtx.debug.resolver) { bundle.fwCtx.debug.println("Resolve failed, remove last fragment and retry"); } if (detached == null) { detached = new ArrayList(); } detached.add(detachLastFragment(true)); } else { break; } } return false; } /** * @param packageName * @return true if this package name should trigger activation of a lazyBundle */ boolean isPkgActivationTrigger(String packageName) { return lazyActivation && ((lazyIncludes == null && lazyExcludes == null) || (lazyIncludes != null && lazyIncludes.contains(packageName)) || (lazyExcludes != null && !lazyExcludes .contains(packageName))); } /** * Get class loader for this bundle generation. * * @return Bundles classloader. */ ClassLoader getClassLoader() { return classLoader; } /** * Get protection domain for this bundle generation. * * @return ProtectionDomain */ ProtectionDomain getProtectionDomain() { return protectionDomain; } /** * Attaches all relevant fragments to this bundle. * @throws BundleException Resolve hook throw an exception. */ private void attachFragments() throws BundleException { if (!attachPolicy.equals(Constants.FRAGMENT_ATTACHMENT_NEVER)) { final Collection hosting = bundle.fwCtx.bundles.getFragmentBundles(this); if (hosting.size() > 0 && bundle.secure.okHostBundlePerm(bundle)) { // retrieve all fragments this bundle host for (final BundleGeneration fbg : hosting) { // TODO, do we need to clean in case of BundleException? fbg.bundle.attachToFragmentHost(this); } } } } /** * Attaches a fragment to this bundle generation. * @throws BundleException */ void attachFragment(BundleGeneration fragmentBundle) throws BundleException { if (attachPolicy.equals(Constants.FRAGMENT_ATTACHMENT_NEVER)) { throw new IllegalStateException("Bundle does not allow fragments to attach"); } if (attachPolicy.equals(Constants.FRAGMENT_ATTACHMENT_RESOLVETIME) && bundle.isResolved()) { throw new IllegalStateException("Bundle does not allow fragments to attach dynamically"); } if (!bundle.fwCtx.resolverHooks.filterMatches(fragmentBundle.fragment, new BundleNameVersionCapability(this, BundleRevision.HOST_NAMESPACE))) { throw new IllegalStateException("Resolver hooks vetoed attach to: " + this); } final String failReason = bpkgs.attachFragment(fragmentBundle.bpkgs); if (failReason != null) { throw new IllegalStateException("Failed to attach: " + failReason); } if (classLoader != null && classLoader instanceof BundleClassLoader) { try { ((BundleClassLoader)classLoader).attachFragment(fragmentBundle); } catch (final BundleException be) { // TODO, should we unregister fragment packaaes throw new IllegalStateException(be.getMessage()); } } if (bundle.fwCtx.debug.resolver) { bundle.fwCtx.debug.println("Fragment(" + fragmentBundle.bundle + ") attached to host(id=" + bundle.id + ",gen=" + generation + ")"); } if (fragments == null) { fragments = new Vector(); } int i = 0; // TODO: use sorted list!? for (; i < fragments.size(); i++) { final BundleGeneration b = fragments.get(i); if (b.bundle.id > fragmentBundle.bundle.id) { break; } } fragments.add(i, fragmentBundle); } /** * Detach last fragment from this bundle. * * @return BundleGeneration for fragment removed, otherwise null. */ private BundleGeneration detachLastFragment(boolean unregister) { // TODO, handle extensions final int last = fragments.size() - 1; if (last >= 0) { final BundleGeneration fbg = fragments.remove(last); bpkgs.detachFragmentSynchronized(fbg, unregister); if (bundle.fwCtx.debug.resolver) { bundle.fwCtx.debug.println("Fragment(id=" + fbg.bundle.id + ") detached from host(id=" + bundle.id + ",gen=" + generation + ")"); } if (fbg.bundle.state != Bundle.UNINSTALLED) { fbg.fragment.removeHost(this); if (!fbg.fragment.hasHosts()) { if (fbg.isCurrent()) { fbg.bundle.setStateInstalled(true); } else { // ... NYI zombie detach } } } return fbg; } return null; } void updateStateFragments() { if (fragments != null) { @SuppressWarnings("unchecked") final Vector fix = (Vector)fragments.clone(); for (final BundleGeneration bundleGeneration : fix) { final BundleImpl fb = bundleGeneration.bundle; fb.getUpdatedState(null); } } } /** * Get hosts if this bundle is a fragment. * Return null if not a fragment. */ Vector getHosts() { return fragment != null ? fragment.getHosts() : null; } /** * Checks if this bundle is a fragment */ boolean isFragment() { return fragment != null; } /** * Determines whether this bundle is a fragment host or not. */ boolean isFragmentHost() { return fragments != null && !fragments.isEmpty(); } /** * Checks if this bundle is a boot class path extension bundle */ boolean isBootClassPathExtension() { return fragment != null && fragment.extension != null && fragment.extension.equals(Constants.EXTENSION_BOOTCLASSPATH); } /** * Checks if this bundle is an extension bundle */ boolean isExtension() { return fragment != null && fragment.extension != null; } /** * Get locale dictionary for this bundle. */ private Dictionary getLocaleDictionary(String locale, String baseName) { final String defaultLocale = Locale.getDefault().toString(); if (locale == null) { locale = defaultLocale; } else if (locale.equals("")) { return null; } final Hashtable localization_entries = new Hashtable(); // TODO, should we do like this and allow mixed locales? if (baseName == null) { baseName = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME; } final Vector h = getHosts(); if (h != null) { BundleGeneration best; while (true) { try { best = null; for (final BundleGeneration bundleGeneration : h) { final BundleGeneration bg = bundleGeneration; if (best == null || bg.version.compareTo(best.version) > 0) { best = bg; } } break; } catch (final ConcurrentModificationException ignore) { } } if (best == bundle.fwCtx.systemBundle.current()) { bundle.fwCtx.systemBundle.readLocalization("", localization_entries, baseName); bundle.fwCtx.systemBundle.readLocalization(defaultLocale, localization_entries, baseName); if (!locale.equals(defaultLocale)) { bundle.fwCtx.systemBundle.readLocalization(locale, localization_entries, baseName); } return localization_entries; } else if (best != null) { return best.getLocaleDictionary(locale, baseName); } // Didn't find a host, fall through. } readLocalization("", localization_entries, baseName); readLocalization(defaultLocale, localization_entries, baseName); if (!locale.equals(defaultLocale)) { readLocalization(locale, localization_entries, baseName); } return localization_entries; } /** * */ HeaderDictionary getHeaders0(String locale) { if (cachedRawHeaders == null) { cachedRawHeaders = archive.getUnlocalizedAttributes(); } if ("".equals(locale)) { return (HeaderDictionary)cachedRawHeaders.clone(); } if (bundle.state != Bundle.UNINSTALLED) { final String base = cachedRawHeaders.get(Constants.BUNDLE_LOCALIZATION); try { return localize(getLocaleDictionary(locale, base)); } catch (final RuntimeException e) { // We assume that we got an exception because we got // state change during the operation. Check! // NYI if (true) { throw e; } } } return null; } /** * */ void addResourceEntries(Vector res, String path, String pattern, boolean recurse) { if (archive == null) { // We are not called as systembundle throw new IllegalStateException("Bundle is in UNINSTALLED state"); } final Enumeration e = archive.findResourcesPath(path); if (e != null) { while (e.hasMoreElements()) { final String fp = e.nextElement(); final boolean isDirectory = fp.endsWith("/"); int searchBackwardFrom = fp.length() - 1; if (isDirectory) { // Skip last / in case of directories searchBackwardFrom = searchBackwardFrom - 1; } final int l = fp.lastIndexOf('/', searchBackwardFrom); final String lastComponentOfPath = fp.substring(l + 1, searchBackwardFrom + 1); if (pattern == null || Util.filterMatch(pattern, lastComponentOfPath)) { final URL url = getURL(0, fp); if (url != null) { res.add(url); } } if (isDirectory && recurse) { addResourceEntries(res, fp, pattern, recurse); } } } } /** * */ Vector findEntries(String path, String filePattern, boolean recurse) { final Vector res = new Vector(); addResourceEntries(res, path, filePattern, recurse); if (isFragmentHost()) { @SuppressWarnings("unchecked") final Vector fix = (Vector)fragments.clone(); for (final BundleGeneration fbg : fix) { fbg.addResourceEntries(res, path, filePattern, recurse); } } return res; } /** * Construct URL to bundle resource */ URL getURL(int subId, String path) { try { final StringBuffer u = new StringBuffer(BundleURLStreamHandler.PROTOCOL); u.append("://"); u.append(bundle.id); if (generation > 0) { u.append('.').append(generation); } if (bundle.fwCtx.id > 0) { u.append('!').append(bundle.fwCtx.id); } if (subId > 0) { u.append(':').append(subId); } if (!path.startsWith("/")) { u.append('/'); } u.append(path); return bundle.secure.getBundleURL(bundle.fwCtx, u.toString()); } catch (final MalformedURLException e) { return null; } } /** * Purge classloader resources connected to object. * */ void closeClassLoader() { if (bundle.fwCtx.debug.classLoader) { bundle.fwCtx.debug.println("closeClassLoader: " + bundle + " gen = " + generation); } final BundleClassLoader tmp = (BundleClassLoader)classLoader; if (tmp != null) { classLoader = null; tmp.close(); } } /** * Purge classloader resources connected to object. * */ void purge(boolean unregister) { if (bundle.fwCtx.debug.classLoader) { bundle.fwCtx.debug.println("BundleGeneration.purge: " + bundle + " gen = " + generation); } if (unregister) { unregisterPackages(true); } closeClassLoader(); purgeProtectionDomain(); if (archive != null) { archive.purge(); } clearWiring(); } /** * * */ boolean unregisterPackages(boolean force) { final boolean res = bpkgs.unregisterPackages(force); if (res && isFragmentHost()) { while (detachLastFragment(false) != null) ; } return res; } /** * Purge permission resources connected to object. * */ void purgeProtectionDomain() { bundle.secure.purge(bundle, protectionDomain); } // // Private methods // /** * Check bundle certificates */ private void checkCertificates() { ArrayList> cs = archive.getCertificateChains(false); if (cs != null) { if (bundle.fwCtx.validator != null) { if (bundle.fwCtx.debug.certificates) { bundle.fwCtx.debug.println("Validate certs for bundle #" + archive.getBundleId()); } cs = new ArrayList>(cs); for (final Iterator vi = bundle.fwCtx.validator.iterator(); !cs.isEmpty() && vi.hasNext();) { final Validator v = vi.next(); for (final Iterator> ci = cs.iterator(); ci.hasNext();) { final List c = ci.next(); if (v.validateCertificateChain(c)) { archive.trustCertificateChain(c); ci.remove(); if (bundle.fwCtx.debug.certificates) { bundle.fwCtx.debug.println("Validated cert: " + c.get(0)); } } else { if (bundle.fwCtx.debug.certificates) { bundle.fwCtx.debug.println("Failed to validate cert: " + c.get(0)); } } } } if (cs.isEmpty()) { // Ok, bundle is signed and validated! return; } } } if (bundle.fwCtx.props.getBooleanProperty(FWProps.ALL_SIGNED_PROP)) { throw new IllegalArgumentException("All installed bundles must be signed!"); } } /** * "Localizes" this bundle's headers * * @param localization_entries A mapping of localization variables to values. * @returns a new localized dictionary. */ private HeaderDictionary localize(final Dictionary localization_entries) { final HeaderDictionary localized = (HeaderDictionary)cachedRawHeaders.clone(); if (localization_entries != null) { for (final Enumeration e = localized.keys(); e.hasMoreElements();) { final String key = e.nextElement(); final String unlocalizedEntry = localized.get(key); if (unlocalizedEntry.startsWith("%")) { final String k = unlocalizedEntry.substring(1); final String val = localization_entries.get(k); if (val == null) { localized.put(key, k); } else { localized.put(key, val); } } } } return localized; } /** * Reads all localization entries that affects this bundle (including its * host/fragments) * * @param locale locale == "" the bundle.properties will be read o/w it will * read the files as described in the spec. * @param localization_entries will append the new entries to this dictionary * @param baseName the basename for localization properties, null * will choose OSGi default */ private void readLocalization(String locale, Hashtable localization_entries, String baseName) { if (!locale.equals("")) { locale = "_" + locale; } while (true) { final String l = baseName + locale + ".properties"; final Hashtable res = getLocalizationEntries(l); if (res != null) { localization_entries.putAll(res); break; } final int pos = locale.lastIndexOf('_'); if (pos == -1) { break; } locale = locale.substring(0, pos); } } /** * Find localization files and load. * */ private Hashtable getLocalizationEntries(String name) { Hashtable res = archive.getLocalizationEntries(name); if (res == null && isFragmentHost()) { @SuppressWarnings("unchecked") final Vector fix = (Vector)fragments.clone(); for (final BundleGeneration bg : fix) { if (bg.archive != null) { res = bg.archive.getLocalizationEntries(name); if (res != null) { break; } } } } return res; } boolean isUninstalled() { return bpkgs == null; } BundleCapability getHostCapability() { if (v2Manifest && !attachPolicy.equals(Constants.FRAGMENT_ATTACHMENT_NEVER) && fragment == null) { return new BundleNameVersionCapability(this, BundleRevision.HOST_NAMESPACE); } return null; } BundleNameVersionCapability getBundleCapability() { if (v2Manifest && fragment==null) { return new BundleNameVersionCapability(this, BundleRevision.BUNDLE_NAMESPACE); } return null; } Vector getBundleClassPathEntries(final String name, final boolean onlyFirst) { BundleClassPath bcp = unresolvedBundleClassPath; if (bcp == null) { bcp = new BundleClassPath(archive, bundle.fwCtx); unresolvedBundleClassPath = bcp; } final Vector fas = bcp.componentExists(name, onlyFirst, false); if (fas != null) { final Vector res = new Vector(); for (final FileArchive fa : fas) { final URL url = fa.getBundleGeneration().getURL(fa.getSubId(), name); if (url != null) { res.addElement(url); } else { // Internal error return null; } } return res; } return null; } List getCapabilityWires() { if (bpkgs != null) { List res = new ArrayList(); for (List lbc : bpkgs.getOtherCapabilities().values()) { for (BundleCapabilityImpl bc : lbc) { bc.getWires(res); } } return res; } else { return null; } } List getRequirementWires() { List res = new ArrayList(); for (List lbr : getOtherRequirements().values()) { for (BundleRequirementImpl br : lbr) { final BundleWireImpl wire = br.getWire(); if (wire != null) { res.add(wire); } } } return res; } Map> getOtherRequirements() { Map> res = getDeclaredRequirements(); if (isFragmentHost()) { boolean copied = false; @SuppressWarnings("unchecked") final Vector fix = (Vector)fragments.clone(); for (final BundleGeneration fbg : fix) { Map> frm = fbg.getDeclaredRequirements(); if (!frm.isEmpty()) { if (!copied) { res = new HashMap>(res); copied = true; } for (Entry> e : frm.entrySet()) { String ns = e.getKey(); List p = res.get(ns); if (p != null) { p = new ArrayList(p); p.addAll(e.getValue()); } else { p = e.getValue(); } res.put(ns, p); } } } } // TODO filter optional return res; } boolean isCurrent() { return this == bundle.current(); } boolean bsnAttrMatch(Map attributes) { if (symbolicNameParameters != null) { final Map attr = symbolicNameParameters.getAttributes(); final String mandatory = symbolicNameParameters.getDirectives().get(Constants.MANDATORY_DIRECTIVE); HashSet mAttr = new HashSet(); if (mandatory != null) { String [] split = Util.splitwords(mandatory, ","); for (String e : split) { mAttr.add(e.trim()); } } for (Entry e : attributes.entrySet()) { final String key = e.getKey(); if (e.getValue().equals(attr.get(key))) { mAttr.remove(key); } else { return false; } } return mAttr.isEmpty(); } return true; } void setWired() { bundleRevision.setWired(); } void clearWiring() { bundleRevision.clearWiring(); } Set getResolvedHosts() { Set res = new HashSet(); List tgts = fragment.targets(); for (BundleGeneration t : tgts) { if (t.bundle.isResolved()) { res.add(t.bundle); } } return res; } BundleCapability getIdentityCapability() { return identity; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Resolver.java0000644000175000017500000014107112346513666027635 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; import java.util.Vector; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; /** * Here we handle all the java packages that are imported and exported within * the framework. * * @author Jan Stein, Erik Wistrand */ class Resolver { static final String RESOLVER_HOOK_VETO = "ResolverHook Veto"; /** * Framework for bundle. */ final FrameworkContext framework; /** * All exported and imported packages. */ private final Hashtable packages = new Hashtable(); /* * All BundleCapabilities that can be or is resolved. */ private final Capabilities capabilities = new Capabilities(); /** * Temporary set of resolved bundles during a resolve operation. */ private volatile HashSet tempResolved = null; /** * Temporary map of package providers during a resolve operation. */ private HashMap tempProvider = null; /** * Temporary map of required bundle connections done during a resolve * operation. */ private HashMap tempRequired = null; /** * Temporary set of package providers that are black listed in the resolve * operation. */ private HashSet tempBlackList = null; /** * Temporary set of bundle checked package uses back track. */ private HashSet tempBackTracked = null; /** * Temporary list of bundle wires during a resolve operation. */ private ArrayList tempWires = null; /** * Temporary to keep track exports that causes colliding imports. */ private ExportPkg tempCollision; /** * Thread currently doing resolve */ private Object resolveThread; /* Statistics to check need for tempBlackList */ int tempBlackListChecks = 0; int tempBlackListHits = 0; /** * Construct Packages object. */ Resolver(FrameworkContext fw) { framework = fw; } /** * Clear all datastructures in this object. */ void clear() { packages.clear(); if (null != tempResolved) { tempResolved.clear(); } if (null != tempProvider) { tempProvider.clear(); } if (null != tempRequired) { tempRequired.clear(); } if (null != tempBlackList) { tempBlackList.clear(); } if (null != tempBackTracked) { tempBackTracked.clear(); } if (null != tempWires) { tempWires.clear(); } } /** * Register all packages a bundle needs to export and import. If it is * registered by the system bundle, export it immediately. * * @param exports Exported packages. * @param imports Imported packages. */ synchronized void registerCapabilities(Map> capabilities, Iterator exports, Iterator imports) { this.capabilities.addCapabilities(capabilities); while (exports.hasNext()) { final ExportPkg pe = exports.next(); Pkg p = packages.get(pe.name); if (p == null) { p = new Pkg(pe.name); packages.put(pe.name, p); } p.addExporter(pe); if (framework.debug.resolver) { framework.debug.println("registerPackages: export, " + pe); } } while (imports.hasNext()) { final ImportPkg pe = imports.next(); Pkg p = packages.get(pe.name); if (p == null) { p = new Pkg(pe.name); packages.put(pe.name, p); } p.addImporter(pe); if (framework.debug.resolver) { framework.debug.println("registerPackages: import, " + pe); } } } /** * Dynamically check and register a dynamic package import. * * @param pe ImportPkg import to add. * @return ExportPkg for package provider. * @throws BundleException Resolver hook complaint. */ synchronized ExportPkg registerDynamicImport(ImportPkg ip) throws BundleException { if (framework.debug.resolver) { framework.debug.println("registerDynamicImport: try " + ip); } ExportPkg res = null; final Pkg p = packages.get(ip.name); if (p != null) { // Wait for other resolve operations to while (tempResolved != null) { checkThread(); try { wait(); } catch (final InterruptedException _ignore) { } } resolveThread = Thread.currentThread(); tempResolved = new HashSet(); tempProvider = new HashMap(); tempRequired = new HashMap(); tempBlackList = new HashSet(); tempBackTracked = new HashSet(); backTrackUses(ip); tempBackTracked = null; final List pkgs = Collections.singletonList(ip); p.addImporter(ip); try { if (resolvePackages(pkgs.iterator(), null)) { registerNewProviders(ip.bpkgs.bg.bundle); res = tempProvider.get(ip.name); ip.provider = res; } else { p.removeImporter(ip); } } catch (BundleException be) { p.removeImporter(ip); throw be; } finally { tempBlackList = null; tempProvider = null; tempRequired = null; tempResolved = null; resolveThread = null; notifyAll(); } } if (framework.debug.resolver) { framework.debug.println("registerDynamicImport: Done for " + ip.name + ", res = " + res); } return res; } /** * Unregister bundle packages in framework. If we find exported packages that * has been selected as providers don't unregister them unless the parameter * force is true. If not all exporters were removed, the don't remove any * importers * * @param exports Exported packages. * @param imports Imported packages. * @param force If true force unregistration of package providers. * @return True if all packages were successfully unregistered, otherwise * false. */ synchronized boolean unregisterCapabilities(Map> capabilities, Iterator exports, Iterator imports, boolean force) { // Check if somebody other than ourselves use our exports if (!force) { final ArrayList saved = new ArrayList(); for (final Iterator i = exports; i.hasNext();) { final ExportPkg ep = i.next(); saved.add(ep); // Is the exporting bundle wired to any bundle via Require-Bundle if (ep.bpkgs.isRequired()) { if (framework.debug.resolver) { framework.debug.println("unregisterPackages: Failed to unregister, " + ep + " is still in use via Require-Bundle."); } markAsZombies(saved, exports); return false; } final Pkg p = ep.pkg; if (p.providers.contains(ep)) { for (final Object element : p.importers) { final ImportPkg ip = (ImportPkg)element; if (ep == ip.provider && ep.bpkgs != ip.bpkgs) { if (framework.debug.resolver) { framework.debug.println("unregisterPackages: Failed to unregister, " + ep + " is still in use via import-package."); } markAsZombies(saved, exports); return false; } } } } exports = saved.iterator(); for (List lbc : capabilities.values()) { for (BundleCapabilityImpl bc : lbc) { if (bc.isWired()) { return false; } } } } while (exports.hasNext()) { final ExportPkg ep = exports.next(); final Pkg p = ep.pkg; if (framework.debug.resolver) { framework.debug.println("unregisterPackages: unregister export - " + ep); } p.removeExporter(ep); if (p.isEmpty()) { packages.remove(ep.name); } } while (imports.hasNext()) { final ImportPkg ip = imports.next(); final Pkg p = ip.pkg; if (framework.debug.resolver) { framework.debug.println("unregisterPackages: unregister import - " + ip.pkgString()); } p.removeImporter(ip); if (p.isEmpty()) { packages.remove(ip.name); } } this.capabilities.removeCapabilities(capabilities); for (List lbc : capabilities.values()) { for (BundleCapabilityImpl bc : lbc) { bc.removeWires(); } } return true; } /** * Try to resolve all packages for a bundle. * * @param bundle Bundle owning packages. * @param pkgs List of packages to be resolved. * @return String with reason for failure or null if all were resolved. * @throws BundleException Resolver hook complaint. */ synchronized String resolve(BundleGeneration bg, BundlePackages importBpkgs, BundleImpl[] triggers) throws BundleException { String res = null; if (framework.debug.resolver) { framework.debug.println("resolve: " + bg); } // If we enter with tempResolved set, it means that we already have // resolved bundles. Check that it is true! if (tempResolved != null) { if (tempResolved.remove(bg)) { return null; } // Not true, wait before starting new resolve process. checkThread(); do { try { wait(); } catch (final InterruptedException _ignore) { } } while (tempResolved != null); } resolveThread = Thread.currentThread(); tempResolved = new HashSet(); try { if (!addTempResolved(bg)) { res = RESOLVER_HOOK_VETO; } } catch (BundleException be) { tempResolved = null; resolveThread = null; notifyAll(); throw be; } if (res == null) { final BundleGeneration sbg = checkBundleSingleton(bg); if (sbg != null) { res = "Singleton bundle failed to resolve because " + sbg.bundle + " is already resolved"; } } if (res != null) { tempResolved = null; resolveThread = null; notifyAll(); return res; } HashSet baseTempBlackList = new HashSet(); tempBlackList = new HashSet(); tempProvider = new HashMap(); tempRequired = new HashMap(); tempWires = new ArrayList(); try { while (true) { tempCollision = null; res = checkBundleRequirements(bg); if (res == null) { res = checkRequireBundle(bg); if (res == null) { StringBuffer failReason = new StringBuffer( "Missing package(s) or can not resolve all of the them:"); if (resolvePackages(importBpkgs.getImports(), failReason)) { if (triggers != null && triggers.length == 1) { framework.resolverHooks.endResolve(triggers); } registerNewWires(); registerNewProviders(bg.bundle); res = null; } else { res = failReason.toString(); } } } if (res != null && tempCollision != null) { baseTempBlackList.add(tempCollision); tempResolved.clear(); tempResolved.add(bg); tempBlackList.clear(); tempBlackList.addAll(baseTempBlackList); tempProvider.clear(); tempRequired.clear(); tempWires.clear(); } else { break; } } } finally { tempResolved = null; tempProvider = null; tempRequired = null; tempBlackList = null; tempWires = null; resolveThread = null; notifyAll(); } if (framework.debug.resolver) { framework.debug.println("resolve: Done for " + bg); } return res; } private boolean addTempResolved(BundleGeneration bg) throws BundleException { if (framework.resolverHooks.filterResolvable(bg)) { tempResolved.add(bg); return true; } return false; } /** * Get Pkg object for named package. * * @param pkg Package name. * @return Pkg that represents the package, null if no such package. */ Pkg getPkg(String pkg) { return packages.get(pkg); } /** * Get bundles affected by zombie packages. * * Compute a graph of bundles starting with the specified bundles. If no * bundles are specified, compute a graph of bundles starting with all * exporting a zombie package. Any bundle that imports a package that is * currently exported by a bundle in the graph (or requires a bundle that is * in the graph) is added to the graph. The graph is fully constructed when * there is no bundle outside the graph that imports a package from a bundle * in the graph (and there is no bundle outside the graph that requires a * bundle in the graph). The graph may contain UNINSTALLED bundles * that are currently still exporting packages. * * @param bundles Initial bundle set. * @return List of bundles affected. */ synchronized TreeSet getZombieAffected(Bundle[] bundles) { // set of affected bundles will be in start-level/bundle-id order final TreeSet affected = new TreeSet(new Comparator() { public int compare(Bundle b1, Bundle b2) { int dif = ((BundleImpl) b1).getStartLevel() - ((BundleImpl) b2).getStartLevel(); if (dif == 0) { dif = (int)(b1.getBundleId() - b2.getBundleId()); } return dif; } public boolean equals(Object o) { return ((o != null) && getClass().equals(o.getClass())); } }); if (bundles == null) { if (framework.debug.resolver) { framework.debug.println("getZombieAffected: check - null"); } framework.bundles.getRemovalPendingBundles(affected); framework.bundles.getUnattachedBundles(affected); } else { for (final Bundle bundle : bundles) { final BundleImpl tmp = (BundleImpl)bundle; if (tmp != null) { if (framework.debug.resolver) { framework.debug.println("getZombieAffected: check - " + bundle); } affected.add(tmp); } } } closure(affected); return affected; } synchronized void closure(Set bundles) { final ArrayList moreBundles = new ArrayList(bundles); for (int i = 0; i < moreBundles.size(); i++) { final BundleImpl b = (BundleImpl) moreBundles.get(i); for (final Iterator j = b.getExports(); j.hasNext();) { final ExportPkg ep = j.next(); if (ep.pkg != null && ep.pkg.providers.contains(ep)) { for (final ImportPkg ip : ep.getPackageImporters()) { final BundleImpl ib = ip.bpkgs.bg.bundle; if (!bundles.contains(ib)) { moreBundles.add(ib); if (framework.debug.resolver) { framework.debug.println("closure: added importing bundle - " + ib); } bundles.add(ib); } } } for (final Object element : ep.bpkgs.getRequiredBy()) { final BundlePackages rbpkgs = (BundlePackages)element; final BundleImpl rb = rbpkgs.bg.bundle; if (!bundles.contains(rb)) { moreBundles.add(rb); if (framework.debug.resolver) { framework.debug.println("closure: added requiring bundle - " + rb); } bundles.add(rb); } } } for (BundleGeneration bbg : b.generations) { List bwl = bbg.getCapabilityWires(); if (bwl != null) { for (final BundleWireImpl bcw : bwl) { BundleImpl bbr = bcw.getRequirerGeneration().bundle; if (!bundles.contains(bbr)) { moreBundles.add(bbr); if (framework.debug.resolver) { framework.debug.println("closure: added wired bundle - " + bbr); } bundles.add(bbr); } } } if (bbg.isFragmentHost()) { @SuppressWarnings("unchecked") final Vector fix = (Vector)bbg.fragments.clone(); for (BundleGeneration fbg : fix) { if (!bundles.contains(fbg.bundle)) { moreBundles.add(fbg.bundle); if (framework.debug.resolver) { framework.debug.println("closure: added fragment bundle - " + fbg.bundle); } bundles.add(fbg.bundle); } } } if (bbg.isFragment()) { final Set hosts = bbg.getResolvedHosts(); for (BundleImpl hb : hosts) { if (!bundles.contains(hb)) { moreBundles.add(hb); if (framework.debug.resolver) { framework.debug.println("closure: added fragment host bundle - " + hb); } bundles.add(hb); } } } } } } // // Private methods. // /** * Backtrack package "uses" so that we can initialize tempProvider with * relevent packages. This perhaps to ambitious. * * @param ip Imported package to back-track from. * @return True if we found bundles "using" this package, otherwise we return * false. */ private boolean backTrackUses(ImportPkg ip) { if (framework.debug.resolver) { framework.debug.println("backTrackUses: check - " + ip.pkgString()); } if (tempBackTracked.contains(ip.bpkgs)) { return false; } tempBackTracked.add(ip.bpkgs); final Iterator i = getPackagesProvidedBy(ip.bpkgs).iterator(); if (i.hasNext()) { do { final ExportPkg ep = i.next(); boolean foundUses = false; for (final Object element : ep.pkg.importers) { final ImportPkg iip = (ImportPkg)element; if (iip.provider == ep) { if (backTrackUses(iip)) { foundUses = true; } } } if (!foundUses) { checkUses(ep.uses, ep, ep.bpkgs); } } while (i.hasNext()); return true; } else { return false; } } /** * Mark list of exporters as zombie packages. * * @param exporters List of ExportPkg. */ private void markAsZombies(List e1, Iterator e2) { for (final ExportPkg exportPkg : e1) { exportPkg.zombie = true; } while (e2.hasNext()) { e2.next().zombie = true; } } /** * Get packages provide by specified BundlePackages. * * @param bpkgs BundlePackages exporting packages. * @return List of packages exported by BundlePackages. */ private Collection getPackagesProvidedBy(BundlePackages bpkgs) { final ArrayList res = new ArrayList(); for (final Iterator i = bpkgs.getExports(); i.hasNext();) { final ExportPkg ep = i.next(); if (ep.pkg.providers.contains(ep)) { res.add(ep); } } return res; } /** * Check if a bundle has all its package dependencies resolved. * * @param pkgs List of packages to be resolved. * @param failReason If not null, puts resolve fail message here. * @return True if all packages resolvable, otherwise false. * @throws BundleException Resolver hook throw an exception. */ private boolean resolvePackages(Iterator pkgs, StringBuffer failReason) throws BundleException { StringBuffer pkgFail = failReason != null ? new StringBuffer() : null; boolean res = true; tempCollision = null; while (pkgs.hasNext()) { ExportPkg provider = null; final ImportPkg ip = pkgs.next(); if (ip.provider != null) { framework.frameworkError(ip.bpkgs.bg.bundle, new Exception("resolvePackages: InternalError1!")); } if (framework.debug.resolver) { framework.debug.println("resolvePackages: check - " + ip.pkgString()); } List possibleProvider = new LinkedList(); for (ExportPkg ep : ip.pkg.exporters) { if (ip.checkAttributes(ep)) { if (ip.bpkgs == ep.bpkgs || ip.checkPermission(ep)) { possibleProvider.add(ep); } else if (pkgFail != null) { newFailReason(pkgFail, "No import permission", ep); } } else if (pkgFail != null) { newFailReason(pkgFail, "Attributes don't match", ep); } } if (pkgFail != null) { if (possibleProvider.isEmpty() && pkgFail.length() == 0) { pkgFail.append("No providers found."); } } framework.resolverHooks.filterMatches((BundleRequirement)ip, (Collection) possibleProvider); if (pkgFail != null && pkgFail.length() == 0 && possibleProvider.isEmpty()) { pkgFail.append("Resolver hooks filtered all possible providers"); } provider = tempProvider.get(ip.name); if (provider != null) { if (framework.debug.resolver) { framework.debug.println("resolvePackages: " + ip.name + " - has temporary provider - " + provider); } if (!possibleProvider.contains(provider)) { String r = "provider not used, rejected by constraints or resolver hooks - " + provider; if (framework.debug.resolver) { framework.debug.println("resolvePackages: " + ip.name + " - " + r); } if (possibleProvider.isEmpty()) { provider = null; } else { // Try with different provider tempCollision = provider; return false; } } } else { for (ExportPkg ep : ip.pkg.providers) { if (!possibleProvider.contains(ep)) { continue; } if (tempBlackList.contains(ep)) { possibleProvider.remove(ep); tempBlackListHits++; if (pkgFail != null) { newFailReason(pkgFail, "Collied with previous selection", ep); } continue; } if (ep.zombie) { continue; } final HashMap oldTempProvider = tempProviderClone(); if (checkUses(ep.uses, ep, ep.bpkgs)) { provider = ep; break; } else { tempProvider = oldTempProvider; tempBlackList.add(ep); possibleProvider.remove(ep); if (pkgFail != null) { newFailReason(pkgFail, "Provider rejected because of uses directive ", ep); } } } if (provider == null) { provider = pickProvider(ip, possibleProvider, pkgFail); } if (provider != null) { tempProvider.put(ip.pkg.pkg, provider); } } if (provider == null) { if (ip.mustBeResolved()) { res = false; if (failReason != null) { failReason.append(FWProps.NL); failReason.append(ip.pkgString()); failReason.append(" -- "); failReason.append(pkgFail); } } else { if (framework.debug.resolver) { framework.debug.println("resolvePackages: Ok, no provider for optional " + ip.name); } } } if (pkgFail != null) { pkgFail.setLength(0); } } return res; } @SuppressWarnings("unchecked") private HashMap tempProviderClone() { return (HashMap)tempProvider.clone(); } /** * Find a provider for specified package. * * @param pkg Package to find provider for. * @return Package entry that can provide. * @throws BundleException Resolver hook throw an exception. */ private ExportPkg pickProvider(ImportPkg ip, List possibleProvider, StringBuffer failReason) throws BundleException { if (framework.debug.resolver) { framework.debug.println("pickProvider: for - " + ip); } boolean zombieExists = false; for (Iterator i = possibleProvider.iterator(); i.hasNext();) { ExportPkg ep = i.next(); tempBlackListChecks++; if (tempBlackList.contains(ep)) { tempBlackListHits++; i.remove(); if (failReason != null) { newFailReason(failReason, "Collied with previous selection", ep); } continue; } if (ip.bpkgs == ep.bpkgs) { if (framework.debug.resolver) { framework.debug.println("pickProvider: internal wire ok for - " + ep); } ip.internalOk = ep; } else if (!ep.checkPermission()) { if (framework.debug.resolver) { framework.debug.println("pickProvider: no export permission for - " + ep); } i.remove(); if (failReason != null) { newFailReason(failReason, "No export permission for", ep); } continue; } if (ep.bpkgs.bg.bundle.state != Bundle.INSTALLED) { final HashMap oldTempProvider = tempProviderClone(); if (checkUses(ep.uses, ep, ep.bpkgs)) { if (framework.debug.resolver) { framework.debug.println("pickProvider: " + ip + " - got resolved provider - " + ep); } return ep; } else { tempProvider = oldTempProvider; tempBlackList.add(ep); i.remove(); if (failReason != null) { newFailReason(failReason, "Uses directive block", ep); } continue; } } if (ep.zombie) { zombieExists = true; } } if (zombieExists) { for (Iterator iep = possibleProvider.iterator(); iep.hasNext();) { final ExportPkg ep = iep.next(); if (tempResolved.contains(ep.bpkgs.bg)) { if (framework.debug.resolver) { framework.debug.println("pickProvider: " + ip + " - got temp provider - " + ep); } return ep; } else if (ep.zombie) { final HashMap oldTempProvider = tempProviderClone(); if (checkUses(ep.uses, ep, ep.bpkgs)) { if (framework.debug.resolver) { framework.debug.println("pickProvider: " + ip + " - got zombie provider - " + ep); } return ep; } tempProvider = oldTempProvider; tempBlackList.add(ep); if (failReason != null) { newFailReason(failReason, "Uses directive block", ep); } iep.remove(); } } } ExportPkg savedCollision = null; for (final ExportPkg ep : possibleProvider) { if (framework.debug.resolver) { framework.debug.println("pickProvider: check possible provider - " + ep); } if (checkResolve(ep.bpkgs.bg, ep)) { if (framework.debug.resolver) { framework.debug.println("pickProvider: " + ip + " - got provider - " + ep); } return ep; } if (tempCollision != null && savedCollision == null) { // Save collision so that we can backtrack and try to avoid collision // if we don't find a provider. savedCollision = tempCollision; } if (failReason != null) { newFailReason(failReason, "Could not resolve exporting bundle", ep); } } if (framework.debug.resolver) { framework.debug.println("pickProvider: " + ip + " - found no provider"); } if (savedCollision != null) { tempCollision = savedCollision; } return null; } private void newFailReason(StringBuffer failReason, String string, ExportPkg ep) { if (failReason.length() > 0) { failReason.append(" || "); } failReason.append(string); if (ep != null) { failReason.append(" - "); failReason.append(ep); } failReason.append("."); } /** * Check if a bundle can be resolved. If resolvable, then the objects * tempResolved, tempProvider and tempBlackList are updated. Bundle must be in * installed state. * * @param bg BundleGeneration to be checked. * @param ep ExportPkg that must be exported by bundle. * @return true if resolvable otherwise false. * @throws BundleException Resolver hook throw an exception. */ private boolean checkResolve(BundleGeneration bg, ExportPkg ep) throws BundleException { if (tempResolved.contains(bg)) { return true; } if (checkBundleSingleton(bg) == null) { boolean retry; final HashSet collisions = new HashSet(); do { retry = false; @SuppressWarnings("unchecked") final HashSet oldTempResolved = (HashSet)tempResolved.clone(); if (!addTempResolved(bg)) { return false; } final HashMap oldTempProvider = tempProviderClone(); @SuppressWarnings("unchecked") final HashMap oldTempRequired = (HashMap)tempRequired.clone(); @SuppressWarnings("unchecked") final HashSet oldTempBlackList = (HashSet)tempBlackList.clone(); tempBlackList.addAll(collisions); final int oldTempWiresSize = tempWires.size(); if (ep != null) { tempProvider.put(ep.pkg.pkg, ep); } final String breq = checkBundleRequirements(bg); if (breq == null) { if (checkRequireBundle(bg) == null) { if (resolvePackages(bg.bpkgs.getImports(), null)) { return true; } if (tempCollision != null) { if (!oldTempProvider.containsValue(tempCollision)) { collisions.add(tempCollision); retry = true; tempCollision = null; } } } } tempResolved = oldTempResolved; tempProvider = oldTempProvider; tempRequired = oldTempRequired; tempBlackList = oldTempBlackList; tempWires.subList(oldTempWiresSize, tempWires.size()).clear(); } while (retry); } return false; } /** * Check that the packages that this provider uses do not collied with * previous selections. If a bundle doesn't have a uses directive we check all * currently imported packages. This is then applied recursively. * * @param pkg Exported package to check * @return True if we checked all packages without collision. */ private boolean checkUses(Set uses, BundleCapability bc, BundlePackages bpkgs) { if (framework.debug.resolver) { framework.debug.println("checkUses: check if packages used by " + bc + " is okay."); } if (framework.debug.resolver) { framework.debug.println("checkUses: provider with bpkgs=" + bpkgs); } final Iterator i = bpkgs.getActiveImports(); if (i != null) { final ArrayList checkList = new ArrayList(); while (i.hasNext()) { final ImportPkg ip = i.next(); if (uses != null && !uses.contains(ip.pkg.pkg)) { continue; } final ExportPkg ep = tempProvider.get(ip.pkg.pkg); if (framework.debug.resolver) { framework.debug.println("checkUses: check import, " + ip + " with provider, " + ip.provider); } if (ep == null) { tempProvider.put(ip.pkg.pkg, ip.provider); checkList.add(ip.provider); } else if (ep != ip.provider) { if (framework.debug.resolver) { framework.debug.println("checkUses: mismatch in providers for, " + ip.pkg.pkg); } return false; } } for (final ExportPkg exportPkg : checkList) { if (!checkUses(exportPkg.uses, exportPkg, exportPkg.bpkgs)) { return false; } } } if (framework.debug.resolver) { framework.debug.println("checkUses: " + bc + " is okay."); } return true; } /** * Check that the bundle specified can be resolved without violating any * singleton requirements. * * @param b Bundle to check, must be in INSTALLED state * @return Bundle blocking resolve, otherwise null. * @throws BundleException Resolver hook throw an exception. */ private BundleGeneration checkBundleSingleton(BundleGeneration bg) throws BundleException { if (bg.symbolicName != null && bg.singleton) { if (framework.debug.resolver) { framework.debug.println("checkBundleSingleton: check singleton bundle " + bg); } final List bl = framework.bundles.getBundleGenerations(bg.symbolicName); if (bl.size() > 1) { if (framework.resolverHooks.hasHooks()) { final BundleCapability bc = bg.getBundleCapability(); Collection candidates = new LinkedList(); List active = new ArrayList(bl.size()); for (final BundleGeneration bg2 : bl) { if (bg2.singleton) { if (bg2 != bg) { BundleNameVersionCapability bc2 = bg2.getBundleCapability(); if (bc2 != null) { if (bg2.bpkgs.isActive()) { active.add(bc2); } else { candidates.add(bc2); } } } } } if (!active.isEmpty()) { for (BundleNameVersionCapability abc : active) { Collection c = new LinkedList(candidates); c.add(bc); framework.resolverHooks.filterSingletonCollisions(abc, c); if (c.contains(bc)) { return abc.gen; } else { candidates.removeAll(c); } } } if (!candidates.isEmpty()) { framework.resolverHooks.filterSingletonCollisions(bc, candidates); for (final BundleCapability bc2 : candidates) { BundleGeneration bg2 = ((BundleRevisionImpl)bc2.getRevision()).gen; if (tempResolved.contains(bg2)) { // TODO add to blacklist to avoid resolve tries?! if (framework.debug.resolver) { framework.debug.println("checkBundleSingleton: Reject because of bundle: " + bg2.bundle); } return bg2; } } } } else { for (final BundleGeneration bg2 : bl) { if (bg != bg2 && bg2.singleton && (bg2.bpkgs.isActive() || tempResolved.contains(bg2))) { if (framework.debug.resolver) { framework.debug.println("checkBundleSingleton: Reject because of bundle: " + bg2.bundle); } return bg2; } } } } } return null; } /** * Check that the bundle specified can resolve all its Require-Capability * constraints. * * @param b Bundle to check, must be in INSTALLED state * @return Capability not full name of bundle blocking resolve, otherwise null. * @throws BundleException Resolver hook throw an exception. */ private String checkBundleRequirements(BundleGeneration bg) throws BundleException { for (Entry> e : bg.getOtherRequirements().entrySet()) { String namespace = e.getKey(); for (BundleRequirementImpl br : e.getValue()) { if (!br.shouldResolve()) { continue; } if (framework.debug.resolver) { framework.debug.println("checkBundleRequirements: Check requirement: " + br); } final boolean reqPerm = framework.perm.hasRequirePermission(br); List bcs = capabilities.getCapabilities(namespace); BundleWireImpl found = null; if (bcs != null) { List mbcs = new LinkedList(); for (BundleCapabilityImpl bc : bcs) { if (br.matches(bc) && bc.checkPermission() && (reqPerm || framework.perm.hasRequirePermission(br, bc))) { mbcs.add(bc); } } if (framework.resolverHooks.hasHooks()) { framework.resolverHooks.filterMatches(br, (Collection) mbcs); } List matches = new ArrayList(); int n_active = 0; for (BundleCapabilityImpl bc : mbcs) { BundleGeneration bcbg = bc.getBundleGeneration(); if (bcbg.isCurrent()) { // Select active or soon active first if (bcbg.bpkgs.isActive() || tempResolved.contains(bcbg)) { matches.add(0, bc); n_active++; if (framework.debug.resolver) { framework.debug.println("checkBundleRequirements: Found active capability: " + bc); } } else { matches.add(n_active, bc); if (framework.debug.resolver) { framework.debug.println("checkBundleRequirements: Found unresolved capability: " + bc); } } } else { // Select zombies last matches.add(bc); if (framework.debug.resolver) { framework.debug.println("checkBundleRequirements: Found zombie capability: " + bc); } } } for (BundleCapabilityImpl bc : matches) { BundleGeneration bcbg = bc.getBundleGeneration(); if (!tempResolved.contains(bcbg)) { if (bcbg.bundle.state == Bundle.INSTALLED) { if (!checkResolve(bcbg, null)) { continue; } } else { // Check uses Set uses = bc.getUses(); if (uses != null && !checkUses(uses, bc, bc.getBundleGeneration().bpkgs)) { continue; } } } found = new BundleWireImpl(bc, bcbg, br, bg); break; } } if (found != null) { tempWires.add(found); } else if (!br.isOptional()) { return "Failed to satisfy: " + br; } } } return null; } /** * Check that the bundle specified can resolve all its Require-Bundle * constraints. * * @param b Bundle to check, must be in INSTALLED state * @return Symbolic name of bundle blocking resolve, otherwise null. * @throws BundleException Resolver hook throw an exception. */ private String checkRequireBundle(BundleGeneration bg) throws BundleException { // NYI! More speed? final Iterator i = bg.bpkgs.getRequire(); if (i.hasNext()) { if (framework.debug.resolver) { framework.debug.println("checkRequireBundle: check requiring bundle " + bg); } if (!framework.perm.okRequireBundlePerm(bg.bundle)) { return "No permission to require bundle: " + bg.symbolicName; } final HashMap res = new HashMap(); do { final RequireBundle br = i.next(); BundleGeneration ok = null; List possibleProvider = new LinkedList(); for (BundleGeneration bg2 : framework.bundles.getBundles(br.name, br.bundleRange)) { possibleProvider.add(new BundleNameVersionCapability(bg2, BundleRevision.BUNDLE_NAMESPACE)); } framework.resolverHooks.filterMatches((BundleRequirement)br, (Collection) possibleProvider); for (final BundleNameVersionCapability bc : possibleProvider) { final BundleGeneration bg2 = bc.gen; if (!bg2.bsnAttrMatch(br.attributes)) { continue; } if (tempResolved.contains(bg2)) { ok = bg2; break; } else if (bg2.bpkgs.isActive()) { final HashMap oldTempProvider = tempProviderClone(); ok = bg2; for (final Iterator epi = bg2.bpkgs.getExports(); epi.hasNext();) { final ExportPkg ep = epi.next(); if (!checkUses(ep.uses, ep, ep.bpkgs)) { tempProvider = oldTempProvider; tempBlackList.add(ep); ok = null; break; } } if (ok != null) { break; } } else if (bg2.bundle.state == Bundle.INSTALLED && framework.perm.okProvideBundlePerm(bg2.bundle) && checkResolve(bg2, null)) { ok = bg2; break; } } if (ok != null) { if (framework.debug.resolver) { framework.debug.println("checkRequireBundle: added required bundle " + ok); } res.put(br, ok.bpkgs); } else if (br.resolution == Constants.RESOLUTION_MANDATORY) { if (framework.debug.resolver) { framework.debug.println("checkRequireBundle: failed to satisfy: " + br.name); } return "Failed to resolve required bundle: " + br.name; } } while (i.hasNext()); tempRequired.putAll(res); } return null; } /** * */ private void registerNewProviders(BundleImpl bundle) { for (final ExportPkg ep : tempProvider.values()) { ep.pkg.addProvider(ep); } for (final Entry entry : tempRequired.entrySet()) { final BundlePackages bpkgs = entry.getValue(); final RequireBundle br = entry.getKey(); br.bpkgs = bpkgs; bpkgs.addRequiredBy(br.requestor); if (framework.debug.resolver) { framework.debug.println("registerNewProviders: '" + Constants.REQUIRE_BUNDLE + ": " + br.name + "' for " + br.requestor.bg.bundle.getBundleId() + " bound to (id=" + bpkgs.bg.bundle.getBundleId() + ",gen=" + bpkgs.bg.generation + ")"); } if (br.visibility == Constants.VISIBILITY_REEXPORT) { // Create necessary re-export entries for (final Iterator be = bpkgs.getExports(); be.hasNext();) { final ExportPkg ep = be.next(); br.requestor.checkReExport(ep); if (framework.debug.resolver) { framework.debug.println("registerNewProviders: " + br.requestor.bg.bundle.getBundleId() + " reexports package " + ep.name); } } } } List resolve = new ArrayList(tempResolved.size()); for (final BundleGeneration bg : tempResolved) { if (!bg.bpkgs.isActive()) { for (final Iterator bi = bg.bpkgs.getImports(); bi.hasNext();) { final ImportPkg ip = bi.next(); final ExportPkg ep = tempProvider.get(ip.name); if (ep == null) { // There could be an internal connection, that should export a // package if (ip.internalOk != null) { if (ip.internalOk.pkg.providers.isEmpty() && ip.internalOk.checkPermission()) { ip.internalOk.pkg.addProvider(ip.internalOk); if (framework.debug.resolver) { framework.debug.println("registerNewProviders: exported internal wire, " + ip + " -> " + ip.internalOk); } } else { if (framework.debug.resolver) { framework.debug.println("registerNewProviders: internal wire, " + ip + " -> " + ip.internalOk); } } } } else { // TODO! This check is already done, we should cache result if (ip.checkAttributes(ep) && ip.checkPermission(ep)) { ip.provider = ep; } else { // Check if got a missmatching internal wire. if (ip.internalOk != null) { if (ip.internalOk == ep) { if (framework.debug.resolver) { framework.debug.println("registerNewProviders: internal wire, " + ip + ", " + ep); } } else { // TODO, should we resolve when this happens!? framework.frameworkError(bg.bundle, new Exception("registerNewProviders: Warning! Internal wire for, " + ip + ", does not match exported. " + ep)); } } } } } if (bg.bundle != bundle) { resolve.add(bg.bundle); } } } for (final BundleImpl b : resolve) { if (b.getUpdatedState(null) == Bundle.INSTALLED) { framework.frameworkError(b, new Exception("registerNewProviders: InternalError!")); } } } /** * */ private void registerNewWires() { for (final BundleWireImpl bw : tempWires) { ((BundleRequirementImpl)bw.getRequirement()).setWire(bw); } } /** * Check if current thread is a bundle thread involved in * resolve operation, if so abort to avoid deadlock. * @throws BundleException * */ private void checkThread() throws BundleException { Thread t = Thread.currentThread(); if (t.equals(resolveThread)) { throw new BundleException("Can not currently start new resolve during a resolve."); } for (BundleGeneration bg : tempResolved) { if (bg.bundle.isBundleThread(t)) { throw new BundleException("Can not resolve a bundle inside current BundleListener." + "Will cause a dead-lock. BID=" + bg.bundle.id); } } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ServiceRegistrationImpl.java0000644000175000017500000003327412346513666032656 0ustar felixfelix/* * Copyright (c) 2003-2012, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Set; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceException; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; /** * Implementation of the ServiceRegistration object. * * @see org.osgi.framework.ServiceRegistration * @author Jan Stein */ public class ServiceRegistrationImpl implements ServiceRegistration { /** * Bundle registering this service. */ final FrameworkContext fwCtx; /** * Bundle registering this service. */ BundleImpl bundle; /** * Service or ServiceFactory object. */ Object service; /** * Reference object to this service registration. */ ServiceReferenceImpl reference; /** * Service properties. */ private PropertiesDictionary properties; /** * Bundles dependent on this service. Integer is used as * reference counter, counting number of unbalanced getService(). */ private Hashtable dependents = new Hashtable(); /** * Object instances that factory has produced. */ private HashMap serviceInstances = new HashMap(); /** * Unget in progress for bundle in set. */ private final HashSet ungetInProgress = new HashSet(); /** * Is service available. I.e., if true then holders * of a ServiceReference for the service are allowed to get it. */ private volatile boolean available; /** * Lock object for synchronous event delivery. */ private final Object eventLock = new Object(); /** * Avoid recursive unregistrations. I.e., if true then * unregistration of this service have started but are not yet * finished. */ private volatile boolean unregistering = false; /** * Detect recursive service factory calls. Is set to thread executing * service factory code, otherwise null. */ private Thread factoryThread = null; /** * Construct a ServiceRegistration for a registered service. * * @param b Bundle providing service. * @param s Service object. * @param props Properties describing service. */ ServiceRegistrationImpl(BundleImpl b, Object s, PropertiesDictionary props) { fwCtx = b.fwCtx; bundle = b; service = s; properties = props; reference = new ServiceReferenceImpl(this); available = true; } // // ServiceRegistration interface // /** * Returns a ServiceReference object for this registration. * * @see org.osgi.framework.ServiceRegistration#getReference */ public ServiceReference getReference() { final ServiceReference res = reference; if (res != null) { return res; } else { throw new IllegalStateException("Service is unregistered"); } } /** * Update the properties associated with this service. * * @see org.osgi.framework.ServiceRegistration#setProperties */ public void setProperties(Dictionary props) { synchronized (eventLock) { if (available) { Set before; // TODO, optimize the locking of services synchronized (fwCtx.services) { synchronized (properties) { // NYI! Optimize the MODIFIED_ENDMATCH code final Object old_rank = properties.get(Constants.SERVICE_RANKING); before = fwCtx.listeners.getMatchingServiceListeners(reference); final String[] classes = (String[])properties.get(Constants.OBJECTCLASS); final Long sid = (Long)properties.get(Constants.SERVICE_ID); properties = new PropertiesDictionary(props, classes, sid); final Object new_rank = properties.get(Constants.SERVICE_RANKING); if (old_rank != new_rank && new_rank instanceof Integer && !((Integer)new_rank).equals(old_rank)) { fwCtx.services.updateServiceRegistrationOrder(this, classes); } } } fwCtx.perm .callServiceChanged(fwCtx, fwCtx.listeners.getMatchingServiceListeners(reference), new ServiceEvent(ServiceEvent.MODIFIED, reference), before); if (!before.isEmpty()) { fwCtx.perm .callServiceChanged(fwCtx, before, new ServiceEvent(ServiceEvent.MODIFIED_ENDMATCH, reference), null); } } else { throw new IllegalStateException("Service is unregistered"); } } } /** * Unregister the service. * * @see org.osgi.framework.ServiceRegistration#unregister */ public void unregister() { if (unregistering) return; // Silently ignore redundant unregistration. synchronized (eventLock) { if (unregistering) return; unregistering = true; if (available) { if (null!=bundle) { fwCtx.services.removeServiceRegistration(this); } } else { throw new IllegalStateException("Service is unregistered"); } } if (null!=bundle) { fwCtx.perm .callServiceChanged(fwCtx, fwCtx.listeners.getMatchingServiceListeners(reference), new ServiceEvent(ServiceEvent.UNREGISTERING, reference), null); } synchronized (eventLock) { available = false; final Bundle [] using = getUsingBundles(); if (using != null) { for (final Bundle element : using) { ungetService(element, false); } } synchronized (properties) { bundle = null; dependents = null; reference = null; service = null; serviceInstances = null; unregistering = false; } } } // // Framework internal // /** * Get all properties */ PropertiesDictionary getProperties() { return properties; } /** * Get specified property */ Object getProperty(String key) { return properties.get(key); } /** * Get the service object. * * @param bundle requester of service. * @return Service requested or null in case of failure. */ S getService(Bundle b) { Integer ref; BundleImpl sBundle = null; synchronized (properties) { if (available) { ref = dependents.get(b); if (service instanceof ServiceFactory) { if (ref == null) { dependents.put(b, new Integer(0)); factoryThread = Thread.currentThread(); } else if (factoryThread != null) { if (factoryThread.equals(Thread.currentThread())) { throw new IllegalStateException("Recursive call of getService"); } } } else { dependents.put(b, new Integer(ref != null ? ref.intValue() + 1 : 1)); @SuppressWarnings("unchecked") final S res = (S) service; return res; } sBundle = bundle; } else { return null; } } S s = null; if (ref == null) { try { s = sBundle.fwCtx.perm.callGetService(this, b); if (s == null) { sBundle.fwCtx.frameworkWarning(sBundle, new ServiceException("ServiceFactory produced null", ServiceException.FACTORY_ERROR)); } } catch (final Throwable pe) { sBundle.fwCtx.frameworkError(sBundle, new ServiceException("ServiceFactory throw an exception", ServiceException.FACTORY_EXCEPTION, pe)); } if (s != null) { final String[] classes = (String[])getProperty(Constants.OBJECTCLASS); for (final String classe : classes) { final String cls = classe; if (!sBundle.fwCtx.services.checkServiceClass(s, cls)) { sBundle.fwCtx.frameworkError(sBundle, new ServiceException("ServiceFactory produced an object " + "that did not implement: " + cls, ServiceException.FACTORY_ERROR)); s = null; break; } } } if (s == null) { synchronized (properties) { if (dependents != null) { dependents.remove(b); } factoryThread = null; return null; } } } boolean recall = false; synchronized (properties) { if (s == null) { // Wait for service factory while (true) { s = serviceInstances.get(b); if (s != null) { break; } try { properties.wait(500); } catch (final InterruptedException ie) { } if (dependents == null || !dependents.containsKey(b)) { // Service has been returned break; } } } else { factoryThread = null; serviceInstances.put(b, s); properties.notifyAll(); } if (s != null) { ref = dependents != null ? (Integer)dependents.get(b) : null; if (ref != null) { dependents.put(b, new Integer(ref.intValue() + 1)); } else { // ungetService has been called during factory call. // Recall service recall = true; } } } if (recall) { try { sBundle.fwCtx.perm.callUngetService(this, b, s); } catch (final Throwable e) { sBundle.fwCtx.frameworkError(sBundle, e); } return null; } else { return s; } } Bundle[] getUsingBundles() { final Hashtable d = dependents; if (d != null) { synchronized (d) { int size = d.size() + ungetInProgress.size(); if (size > 0) { final Bundle[] res = new Bundle[size]; for (final Enumeration e = d.keys(); e.hasMoreElements(); ) { res[--size] = e.nextElement(); } for (final Bundle b : ungetInProgress) { res[--size] = b; } return res; } } } return null; } /** * Check if a bundle uses this service * * @param b Bundle to check * @return true if bundle uses this service */ boolean isUsedByBundle(Bundle b) { final Hashtable deps = dependents; if (deps != null) { return deps.containsKey(b); } else { return false; } } /** * Unget the service object. * * @param b Bundle who wants remove service. * @param checkRefCounter If true decrement reference counter and remove service * if we reach zero. If false remove service without * checking reference counter. * @return True if service was used, otherwise false. * */ boolean ungetService(Bundle b, boolean checkRefCounter) { S serviceToRemove = null; Hashtable deps; BundleImpl sBundle; synchronized (properties) { if (dependents == null) { return false; } final Object countInteger = dependents.get(b); if (countInteger == null) { return false; } final int count = ((Integer) countInteger).intValue(); if (checkRefCounter && count > 1) { dependents.put(b, new Integer(count - 1)); } else { synchronized (dependents) { ungetInProgress.add(b); dependents.remove(b); } serviceToRemove = serviceInstances.remove(b); } deps = dependents; sBundle = bundle; } if (serviceToRemove != null) { if (service instanceof ServiceFactory) { try { sBundle.fwCtx.perm.callUngetService(this, b, serviceToRemove); } catch (final Throwable e) { sBundle.fwCtx.frameworkError(sBundle, e); } } } synchronized (deps) { ungetInProgress.remove(b); } return true; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleReferenceImpl.java0000644000175000017500000000361512346513666031707 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import org.osgi.framework.Bundle; import org.osgi.framework.BundleReference; public class BundleReferenceImpl implements BundleReference { final BundleImpl bundle; BundleReferenceImpl(BundleImpl bundle) { this.bundle = bundle; } public Bundle getBundle() { return bundle; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Pkg.java0000644000175000017500000001532712346513666026561 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.ArrayList; import org.osgi.framework.Version; /** * Class representing a package. * * @author Jan Stein */ class Pkg { final String pkg; final ArrayList exporters = new ArrayList(1); final ArrayList importers = new ArrayList(); final ArrayList providers = new ArrayList(1); /** * Create package entry. */ Pkg(String pkg) { this.pkg = pkg; } /** * Add an exporter entry from this package. * * @param pe ExportPkg to add. */ synchronized void addExporter(ExportPkg ep) { final int i = Math.abs(Util.binarySearch(exporters, epComp, ep) + 1); exporters.add(i, ep); ep.attachPkg(this); } /** * Remove an exporter entry from this package. * * @param p ExportPkg to remove. * @return false if package is provider otherwise true. */ synchronized boolean removeExporter(ExportPkg p) { providers.remove(p); exporters.remove(p); p.detachPkg(); return true; } /** * Add an importer entry to this package. * * @param pe ImportPkg to add. */ synchronized void addImporter(ImportPkg ip) { final int i = Math.abs(Util.binarySearch(importers, ipComp, ip) + 1); importers.add(i, ip); ip.attachPkg(this); } /** * Remove an importer entry from this package. * * @param p ImportPkg to remove. */ synchronized void removeImporter(ImportPkg ip) { importers.remove(ip); ip.detachPkg(); } /** * Add an exporter entry as a provider for this package. * If exporter already is provider don't add duplicate. * * @param pe ExportPkg to add. */ synchronized void addProvider(ExportPkg ep) { final int i = Util.binarySearch(providers, epComp, ep); if (i < 0) { providers.add(-i - 1, ep); } } /** * Get best provider. Best provider is provider * with highest version number. * * @return Provider ExportPkg or null if none.. */ synchronized ExportPkg getBestProvider() { if (!providers.isEmpty()) { return providers.get(0); } else { ExportPkg best = null; // See if there are any resolved exporters. for (final ExportPkg exportPkg : exporters) { final ExportPkg ep = exportPkg; if (ep.bpkgs.bg.bundle.isResolved()) { if (best == null || best.version.compareTo(ep.version) < 0) { best = ep; } } } return best; } } /** * Check if this package has any exporters or importers. * * @return true if no exporters or importers, otherwise false. */ synchronized boolean isEmpty() { return exporters.size() == 0 && importers.size() == 0; } @Override public String toString() { return toString(2); } public String toString(int level) { final StringBuffer sb = new StringBuffer(); sb.append("Pkg["); if(level > 0) { sb.append("pkg=" + pkg); } if(level > 1) { sb.append(", providers=" + providers); } if(level > 2) { sb.append(", exporters=" + exporters); } sb.append("]"); return sb.toString(); } static final Util.Comparator epComp = new Util.Comparator() { /** * Version compare two ExportPkg objects. If same version, order according * to bundle id, lowest first. * * @param a * ExportPkg to compare. * @param b * ExportPkg to compare. * @return Return 0 if equals, negative if first object is less than second * object and positive if first object is larger then second object. */ public int compare(ExportPkg a, ExportPkg b) { int d = a.version.compareTo(b.version); if (d == 0) { final long ld = b.bpkgs.bg.bundle.id - a.bpkgs.bg.bundle.id; if (ld < 0) d = -1; else if (ld > 0) d = 1; } return d; } }; static final Util.Comparator ipComp = new Util.Comparator() { /** * Version compare two ImportPkg objects. If same version, order according * to bundle id, lowest first. * * @param a * ImportPkg to compare. * @param b * ImportPkg to compare. * @return Return 0 if equals, negative if first object is less than second * object and positive if first object is larger then second object. * @exception ClassCastException * if object is not a ImportPkg object. */ public int compare(ImportPkg a, ImportPkg b) { int d; if (a.packageRange == null) { d = b.packageRange == null ? 0 : Version.emptyVersion.compareTo(b.packageRange.getLeft()); } else if (b.packageRange == null) { d = a.packageRange.getLeft().compareTo(Version.emptyVersion); } else { d = a.packageRange.getLeft().compareTo(b.packageRange.getLeft()); } if (d == 0) { final long ld = b.bpkgs.bg.bundle.id - a.bpkgs.bg.bundle.id; if (ld < 0) d = -1; else if (ld > 0) d = 1; } return d; } }; } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleResourceStream.java0000644000175000017500000001002212346513666032120 0ustar felixfelix/* * Copyright (c) 2009, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.InputStream; import java.io.IOException; /** * InputStream for bundle content * * @author Jan Stein */ public class BundleResourceStream extends InputStream { protected InputStream wis; protected long contentLen; /** * BundleResourceStream * * @param is Underlying input stream. * @parma length Length of content, -1 if unknown. */ public BundleResourceStream(InputStream is, long length) { wis = is; contentLen = length; } /** * Get length of resource stream. * * @return Length of resource stream. If length is unknown * -1 is returned. */ public long getContentLength() { return contentLen; } /** * Read a byte from the input stream. * * @return Byte read */ public int read() throws IOException { return wis.read(); } /** * Read bytes from the input stream. * * @param dest Byte array to read into * @return Number of bytes actually read */ public int read(byte[] dest) throws IOException { return wis.read(dest); } /** * Read a specified number of bytes from the input stream. * * @param dest Byte array to read into * @param off Starting offset into the byte array * @param len Maximum number of bytes to read * @return Number of bytes actually read */ public int read(byte[] dest, int off, int len) throws IOException { return wis.read(dest, off, len); } /** * Skip over (and discard) a specified number of bytes in this input * stream. * * @param len Number of bytes to be skipped * @return Number of bytes skipped */ public long skip(long len) throws IOException { return wis.skip(len); } /** * Return the number of bytes available for immediate read * * @return the number of bytes */ public int available() throws IOException { return wis.available(); } /** * Close input stream */ public void close() throws IOException { wis.close(); } /** * Mark current position in input stream * * @param readlimit Maximum of bytes when can save. */ public void mark(int readlimit) { wis.mark(readlimit); } /** * Return to marked position. */ public void reset() throws IOException { wis.reset(); } /** * Check it mark/reset is supported. * * @return True if supported, otherwise false. */ public boolean markSupported() { return wis.markSupported(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleURLStreamHandler.java0000644000175000017500000002502512346513666032302 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.IOException; import java.net.InetAddress; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.util.ArrayList; import java.util.Iterator; /** * Bundle URL handling. * * @author Jan Stein, Gunnar Ekolin */ public class BundleURLStreamHandler extends URLStreamHandler { final public static String PROTOCOL = "bundle"; final public static String PERM_OK = "P"; // Currently we only support a single framework instance in the same // class-loader context! private final ArrayList framework = new ArrayList(2); // TODO, we need a more efficient and cleaner solution here. @Override public URLConnection openConnection(URL u) throws IOException { final String h = u.getHost(); final FrameworkContext fw = getFramework(h); if (fw == null) { throw new IOException("Framework associated with URL is not active"); } if (u.getAuthority() != PERM_OK) { fw.perm.checkResourceAdminPerm(fw.bundles.getBundle(getId(h))); // NYI, set authority } return new BundleURLConnection(u, fw); } @Override protected void parseURL(URL u, String s, int start, int limit) { String path = u.getPath(); String host = u.getHost(); long id = -1; int cpElem = u.getPort(); if (limit > start) { int len = limit - start; char [] sc = new char[len]; s.getChars(start, limit, sc, 0); int pos = 0; if (len >= 2 && sc[0] == '/' && sc[1] == '/') { for (pos = 2; pos < len; pos++) { if (sc[pos] == ':' || sc[pos] == '/') { break; } else if (sc[pos] == '!' || sc[pos] == '.') { if (id == -1) { id = Long.parseLong(new String(sc, 2, pos - 2)); } } else if (!Character.isDigit(sc[pos])) { throw new IllegalArgumentException ("Illegal chars in bundle id specification"); } } host = new String(sc, 2, pos - 2); if (pos < len && sc[pos] == ':') { ++pos; cpElem = 0; while (pos < len) { if (sc[pos] == '/') { break; } else if (!Character.isDigit(sc[pos])) { throw new IllegalArgumentException ("Illegal chars in bundle port specification"); } cpElem = 10 * cpElem + (sc[pos++] - '0'); } } else { cpElem = -1; } } if (pos < len) { int pstart; if (sc[pos] != '/') { if (path != null) { final int dirend = path.lastIndexOf('/') + 1; if (dirend > 0) { final int plen = len - pos; pstart = path.startsWith("/") ? 0 : 1; len = dirend + plen + pstart; if (len > sc.length) { final char [] newsc = new char [len]; System.arraycopy(sc, pos, newsc, dirend + pstart, plen); sc = newsc; } else if (pos != dirend) { System.arraycopy(sc, pos, sc, dirend + pstart, plen); } path.getChars(1 - pstart, dirend, sc, 1); } else { len = 1; } } else { len = 1; } sc[0] = '/'; pstart = 0; pos = 0; } else { pstart = pos; } int dots = 0; int ipos = pstart - 1; boolean slash = false; for (; pos < len; pos++) { if (sc[pos] == '/') { if (slash) { continue; } slash = true; if (dots == 1) { dots = 0; continue; } else if (dots == 2) { if (ipos>pstart) { // There is a path-level to remove. dots = 0; while (ipos > pstart && sc[--ipos] != '/') ; continue; } } } else if (sc[pos] == '.') { if (slash) { dots = 1; slash = false; continue; } else if (dots == 1) { dots = 2; continue; } } else { slash = false; } while (dots-- > 0) { sc[++ipos] = '.'; } if (++ipos != pos) { sc[ipos] = sc[pos]; } } if (dots == 2) { if (ipos > pstart) { // There is a level to remove while (ipos > pstart && sc[--ipos] != '/') ; } else { // On top level, keep the ".." while (dots-- > 0) { sc[++ipos] = '.'; } // Add trailing '/' to ensure that a relative URL created // with path ".." results in the same URL as one created // using "../". sc[++ipos] = '/'; } } path = new String(sc, pstart, ipos - pstart + 1); } } if (id == -1) { id = getId(host); } final FrameworkContext fw = getFramework(host); if (fw == null) { throw new IllegalArgumentException("Framework associated with URL is not active"); } fw.perm.checkResourceAdminPerm(fw.bundles.getBundle(id)); setURL(u, PROTOCOL, host, cpElem, PERM_OK, null, path, null, null); } /** * Equals calculation for bundle URLs. * @return true if the two urls are * considered equal, ie. they refer to the same * fragment in the same file. * */ @Override protected boolean equals(URL u1, URL u2) { return sameFile(u1, u2); } /** * Provides the hash calculation * @return an int suitable for hash table indexing */ @Override protected int hashCode(URL u) { int h = 0; if (PROTOCOL.equals(u.getProtocol())) { final String host = u.getHost(); if (host != null) h = host.hashCode(); final String file = u.getFile(); if (file != null) h += file.hashCode(); h += u.getPort(); } else { h = u.hashCode(); } return h; } /** * Compare two urls to see whether they refer to the same file, * i.e., having the same protocol, host, port, and path. * @return true if u1 and u2 refer to the same file */ @Override protected boolean sameFile(URL u1, URL u2) { final String p1 = u1.getProtocol(); if (PROTOCOL.equals(p1)) { if (!p1.equals(u2.getProtocol())) return false; if (!hostsEqual(u1, u2)) return false; if (!(u1.getFile() == u2.getFile() || (u1.getFile() != null && u1.getFile().equals(u2.getFile())))) return false; if (u1.getPort() != u2.getPort()) return false; return true; } else { return u1.equals(u2); } } /** * Compares the host components of two URLs. * @param u1 the URL of the first host to compare * @param u2 the URL of the second host to compare * @return true if and only if they * are equal, false otherwise. */ @Override protected boolean hostsEqual(URL u1, URL u2) { final String s1 = u1.getHost(); final String s2 = u2.getHost(); return (s1 == s2) || (s1 != null && s1.equals(s2)); } /** * Converts a bundle URL to a String. * * @param url the URL. * @return a string representation of the URL. */ @Override protected String toExternalForm(URL url) { final StringBuffer res = new StringBuffer(url.getProtocol()); res.append("://"); res.append(url.getHost()); final int port = url.getPort(); if (port >= 0) { res.append(":").append(port); } res.append(url.getPath()); return res.toString(); } @Override protected synchronized InetAddress getHostAddress(URL url) { return null; } // // Package // /** * Add framework that uses this URLStreamHandlerFactory. * * @param fw Framework context for framework to add. */ void addFramework(FrameworkContext fw) { framework.add(fw); } /** * Remove framework that uses this URLStreamHandlerFactory. * * @param fw Framework context for framework to remove. */ void removeFramework(FrameworkContext fw) { framework.remove(fw); } // // Private // private FrameworkContext getFramework(String host) { final Iterator i = framework.iterator(); final int e = host.indexOf("!"); int fwId; if (e == -1) { fwId = 0; } else { try { fwId = Integer.parseInt(host.substring(e + 1)); } catch (final NumberFormatException _) { return null; } } while (i.hasNext()) { final FrameworkContext fw = i.next(); if (fw.id == fwId) { return fw; } } return null; } public static long getId(String host) { int e = host.indexOf("."); if (e == -1) { e = host.indexOf("!"); } if (e >= 0) { host = host.substring(0, e); } return Long.parseLong(host); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleRevisionsImpl.java0000644000175000017500000000460012346513666031765 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.ArrayList; import java.util.List; import java.util.Vector; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleRevisions; public class BundleRevisionsImpl extends BundleReferenceImpl implements BundleRevisions { private Vector generations; BundleRevisionsImpl(Vector generations) { super(generations.get(0).bundle); this.generations = generations; } public List getRevisions() { synchronized (generations) { List res = new ArrayList(generations.size()); for (BundleGeneration bg : generations) { if (!bg.isUninstalled()) { res.add(bg.bundleRevision); } } return res; } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/validator/0000755000175000017500000000000012475375714027155 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/validator/JKSValidator.java0000644000175000017500000002007512346513664032314 0ustar felixfelix/* * Copyright (c) 2009-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.validator; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.cert.CertPath; import java.security.cert.CertPathParameters; import java.security.cert.CertPathValidator; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.PKIXParameters; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.text.DateFormat; import java.text.ParseException; import java.util.Date; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Locale; import org.knopflerfish.framework.Debug; import org.knopflerfish.framework.FrameworkContext; import org.knopflerfish.framework.Util; import org.knopflerfish.framework.Validator; import org.osgi.framework.Constants; /** * JKS certificate validator * * @author Jan Stein */ public class JKSValidator implements Validator { /** * Property strings. */ final private static String CA_CERTS_PROP = "org.knopflerfish.framework.validator.jks.ca_certs"; final private static String CA_CERTS_PASSWORD_PROP = "org.knopflerfish.framework.validator.jks.ca_certs_password"; final private static String CERT_PROVIDER_PROP = "org.knopflerfish.framework.validator.jks.cert_provider"; final private static String CERT_DATE_PROP = "org.knopflerfish.framework.validator.date"; /** * Certificate provider; */ private String certProvider; /** * */ private CertificateFactory certFactory = null; /** * */ private CertPathValidator certValidator = null; /** * */ final private KeyStore keystore; /** * */ private Date validationDate; /** * NYI make it configurable */ private boolean trustKeys = true; /** * Debug handle */ final private Debug debug; /** * Create a JKS based validator. * * @param fw FrameworkContext used to get configuration properties. * @throws KeyStoreException * @throws ParseException */ public JKSValidator(FrameworkContext fw) throws KeyStoreException, ParseException { debug = fw.debug; keystore = KeyStore.getInstance(KeyStore.getDefaultType()); // NYI! Handle serveral repositories. fw.props.setPropertyDefault(CERT_PROVIDER_PROP, ""); certProvider = fw.props.getProperty(CERT_PROVIDER_PROP); String repos = fw.props.getProperty(Constants.FRAMEWORK_TRUST_REPOSITORIES); if (repos.length() > 0) { String [] l = Util.splitwords(repos, File.pathSeparator); for (int i = 0; i < l.length; i++) { String certRepo = l[i].trim(); if (certRepo.length() > 0) { loadKeyStore(certRepo, null); } } } else { fw.props.setPropertyDefault(CA_CERTS_PROP, System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar)); fw.props.setPropertyDefault(CA_CERTS_PASSWORD_PROP, "changeit"); final String caCertsFileName = fw.props.getProperty(CA_CERTS_PROP); if (caCertsFileName != null) { loadKeyStore(caCertsFileName, fw.props.getProperty(CA_CERTS_PASSWORD_PROP)); } } String d = fw.props.getProperty(CERT_DATE_PROP); if (d != null) { try { validationDate = DateFormat.getDateInstance(DateFormat.SHORT).parse(d); } catch (ParseException _ignore) { // Always try US format validationDate = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US).parse(d); } if (debug.certificates) { debug.println("Set validation date to " + validationDate); } } else { validationDate = null; } } /** * Check if a certificate chain is to be trusted. * * @return true, if validator trusts certificate chain, otherwise false. */ public boolean validateCertificateChain(List chain) { if (keystore == null) { return false; } try { CertPath c = getCertificateFactory().generateCertPath(chain); CertPathValidator cpv = getCertPathValidator(); CertPathParameters params = getCertPathParameters(keystore); cpv.validate(c, params); } catch (GeneralSecurityException gse) { if (debug.certificates) { debug.printStackTrace("Failed to validate cert", gse); } // NYI! Log this? return false; } return true; } /** * */ private CertificateFactory getCertificateFactory() throws GeneralSecurityException { if (certFactory == null) { if (certProvider.length() > 0) { certFactory = CertificateFactory.getInstance("X.509", certProvider); } else { certFactory = CertificateFactory.getInstance("X.509"); } } return certFactory; } /** * */ private CertPathParameters getCertPathParameters(KeyStore keystore) throws GeneralSecurityException { HashSet tas = new HashSet(); for (Enumeration e = keystore.aliases(); e.hasMoreElements(); ) { String name = e.nextElement(); Certificate c = keystore.getCertificate(name); if (c != null) { if (trustKeys || keystore.isCertificateEntry(name)) { tas.add(new TrustAnchor((X509Certificate)c, null)); } } } PKIXParameters p = new PKIXParameters(tas); // NYI! Handle CRLs p.setRevocationEnabled(false); if (validationDate != null) { p.setDate(validationDate); } return p; } /** * */ private CertPathValidator getCertPathValidator() throws GeneralSecurityException { if (certValidator == null) { if (certProvider.length() > 0) { certValidator = CertPathValidator.getInstance("PKIX", certProvider); } else { certValidator = CertPathValidator.getInstance("PKIX"); } } return certValidator; } /** * */ private void loadKeyStore(String file, String password) { FileInputStream is = null; try { is = new FileInputStream(file); keystore.load(is, password != null ? password.toCharArray() : null); if (debug.certificates) { debug.println("Loaded keystore, " + file); } } catch (Exception e) { if (is != null) { try { is.close(); } catch (IOException ignore) { } } debug.printStackTrace("Failed to load keystore, " + file, e); } } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/validator/SelfSignedValidator.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/validator/SelfSignedValidator.0000644000175000017500000000625012346513664033045 0ustar felixfelix/* * Copyright (c) 2009-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.validator; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.text.DateFormat; import java.text.ParseException; import java.util.Date; import java.util.List; import org.knopflerfish.framework.FrameworkContext; import org.knopflerfish.framework.Validator; /** * Self signed certificate validator * * @author Jan Stein */ public class SelfSignedValidator implements Validator { final private static String CERT_DATE_PROP = "org.knopflerfish.framework.validator.date"; /** * */ private Date validationDate; /** * Create a SelfSignedCertificate validator. * * @param fw * FrameworkContext used to get configuration properties. * @throws ParseException */ public SelfSignedValidator(FrameworkContext fw) throws ParseException { String d = fw.props.getProperty(CERT_DATE_PROP); if (d != null) { validationDate = DateFormat.getDateInstance(DateFormat.SHORT).parse(d); } else { validationDate = null; } } /** * Check if a certificate chain is to be trusted. We expect the input to be a * correct chain. * * @return true, if validator trusts certificate chain, otherwise false. */ public boolean validateCertificateChain(List chain) { try { for (X509Certificate cert : chain) { if (validationDate != null) { cert.checkValidity(validationDate); } else { cert.checkValidity(); } } } catch (CertificateException _) { return false; } return true; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/SecurePermissionOps.java0000644000175000017500000006640012346513666032017 0ustar felixfelix/* * Copyright (c) 2006-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLStreamHandler; import java.security.AccessControlContext; import java.security.AccessController; import java.security.AllPermission; import java.security.CodeSource; import java.security.PermissionCollection; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Vector; import org.knopflerfish.framework.permissions.PermissionsHandle; import org.osgi.framework.AdaptPermission; import org.osgi.framework.AdminPermission; import org.osgi.framework.Bundle; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleException; import org.osgi.framework.BundlePermission; import org.osgi.framework.CapabilityPermission; import org.osgi.framework.Constants; import org.osgi.framework.FrameworkListener; import org.osgi.framework.PackagePermission; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServicePermission; import org.osgi.framework.ServiceReference; import org.osgi.service.condpermadmin.ConditionalPermissionAdmin; import org.osgi.service.permissionadmin.PermissionAdmin; public class SecurePermissionOps extends PermissionOps { private static final int AP_CLASS = 0; private static final int AP_EXECUTE = 1; private static final int AP_EXTENSIONLIFECYCLE = 2; private static final int AP_LIFECYCLE = 3; private static final int AP_LISTENER = 4; private static final int AP_METADATA = 5; private static final int AP_RESOURCE = 6; private static final int AP_CONTEXT = 7; private static final int AP_WEAVE = 8; private static final int AP_MAX = 9; private static String[] AP_TO_STRING = new String[] { AdminPermission.CLASS, AdminPermission.EXECUTE, AdminPermission.EXTENSIONLIFECYCLE, AdminPermission.LIFECYCLE, AdminPermission.LISTENER, AdminPermission.METADATA, AdminPermission.RESOURCE, AdminPermission.CONTEXT, AdminPermission.WEAVE }; private final FrameworkContext framework; private PermissionsHandle ph; private AdminPermission ap_resolve = null; private AdminPermission ap_startlevel = null; private RuntimePermission rp_getprotectiondomain = null; Hashtable adminPerms = new Hashtable(); public SecurePermissionOps(FrameworkContext fw) { framework = fw; } @Override void init() { ph = new PermissionsHandle(framework); } @Override void registerService() { if (framework.props .getBooleanProperty(FWProps.SERVICE_PERMISSIONADMIN_PROP)) { final String[] classes = new String[] { PermissionAdmin.class.getName() }; framework.services.register(framework.systemBundle, classes, ph.getPermissionAdminService(), null); } if (framework.props .getBooleanProperty(FWProps.SERVICE_CONDITIONALPERMISSIONADMIN_PROP)) { final ConditionalPermissionAdmin cpa = ph .getConditionalPermissionAdminService(); if (cpa != null) { final String[] classes = new String[] { ConditionalPermissionAdmin.class .getName() }; framework.services.register(framework.systemBundle, classes, cpa, null); } } } @Override boolean checkPermissions() { return true; } // // Permission checks // @Override boolean okClassAdminPerm(Bundle b) { try { final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(getAdminPermission(b, AP_CLASS)); } return true; } catch (final SecurityException _ignore) { return false; } } @Override void checkExecuteAdminPerm(Bundle b) { final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(getAdminPermission(b, AP_EXECUTE)); } } @Override void checkExtensionLifecycleAdminPerm(Bundle b) { final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(getAdminPermission(b, AP_EXTENSIONLIFECYCLE)); } } @Override void checkExtensionLifecycleAdminPerm(Bundle b, Object checkContext) { final SecurityManager sm = System.getSecurityManager(); if (null != sm && checkContext != null) { sm.checkPermission(getAdminPermission(b, AP_EXTENSIONLIFECYCLE), checkContext); } } @Override void checkLifecycleAdminPerm(Bundle b) { final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(getAdminPermission(b, AP_LIFECYCLE)); } } @Override void checkLifecycleAdminPerm(Bundle b, Object checkContext) { final SecurityManager sm = System.getSecurityManager(); if (null != sm && checkContext != null) { sm.checkPermission(getAdminPermission(b, AP_LIFECYCLE), checkContext); } } @Override void checkListenerAdminPerm(Bundle b) { final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(getAdminPermission(b, AP_LISTENER)); } } @Override void checkMetadataAdminPerm(Bundle b) { final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(getAdminPermission(b, AP_METADATA)); } } @Override void checkResolveAdminPerm() { if (ap_resolve == null) { ap_resolve = new AdminPermission(framework.systemBundle, AdminPermission.RESOLVE); } final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(ap_resolve); } } @Override void checkResourceAdminPerm(Bundle b) { final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(getAdminPermission(b, AP_RESOURCE)); } } @Override boolean okResourceAdminPerm(Bundle b) { try { checkResourceAdminPerm(b); return true; } catch (final SecurityException ignore) { if (framework.debug.bundle_resource) { framework.debug .printStackTrace("No permission to access resources in bundle #" + b.getBundleId(), ignore); } return false; } } @Override void checkContextAdminPerm(Bundle b) { final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(getAdminPermission(b, AP_CONTEXT)); } } @Override void checkStartLevelAdminPerm() { if (ap_startlevel == null) { ap_startlevel = new AdminPermission(framework.systemBundle, AdminPermission.STARTLEVEL); } final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(ap_startlevel); } } @Override void checkGetProtectionDomain() { if (rp_getprotectiondomain == null) { rp_getprotectiondomain = new RuntimePermission("getProtectionDomain"); } final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(rp_getprotectiondomain); } } @Override void checkWeaveAdminPerm(Bundle b) { final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(getAdminPermission(b, AP_WEAVE)); } } // // Bundle permission checks // @Override boolean okFragmentBundlePerm(BundleImpl b) { final PermissionCollection pc = ph.getPermissionCollection(new Long(b.id)); return pc.implies(new BundlePermission(b.getSymbolicName(), BundlePermission.FRAGMENT)); } @Override boolean okHostBundlePerm(BundleImpl b) { final PermissionCollection pc = ph.getPermissionCollection(new Long(b.id)); return pc.implies(new BundlePermission(b.getSymbolicName(), BundlePermission.HOST)); } @Override boolean okProvideBundlePerm(BundleImpl b) { final PermissionCollection pc = ph.getPermissionCollection(new Long(b.id)); return pc.implies(new BundlePermission(b.getSymbolicName(), BundlePermission.PROVIDE)); } @Override boolean okRequireBundlePerm(BundleImpl b) { final PermissionCollection pc = ph.getPermissionCollection(new Long(b.id)); return pc.implies(new BundlePermission(b.getSymbolicName(), BundlePermission.REQUIRE)); } @Override boolean okAllPerm(BundleImpl b) { final PermissionCollection pc = ph.getPermissionCollection(new Long(b.id)); return pc.implies(new AllPermission()); } // // Package permission checks // @Override boolean hasExportPackagePermission(ExportPkg ep) { final BundleImpl b = ep.bpkgs.bg.bundle; if (b.id != 0) { final PermissionCollection pc = ph .getPermissionCollection(new Long(b.id)); return pc.implies(new PackagePermission(ep.name, PackagePermission.EXPORTONLY)); } return true; } @Override boolean hasImportPackagePermission(BundleImpl b, ExportPkg ep) { if (b.id != 0) { final PermissionCollection pc = ph .getPermissionCollection(new Long(b.id)); return pc.implies(new PackagePermission(ep.name, ep.bpkgs.bg.bundle, PackagePermission.IMPORT)); } return true; } // // Service permission checks // @Override void checkRegisterServicePerm(String clazz) { final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(new ServicePermission(clazz, ServicePermission.REGISTER)); } } @Override void checkGetServicePerms(ServiceReference sr) { final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(new ServicePermission(sr, ServicePermission.GET)); } } @Override boolean okGetServicePerms(ServiceReference sr) { try { checkGetServicePerms(sr); return true; } catch (final SecurityException ignore) { if (framework.debug.service_reference) { framework.debug .printStackTrace("No permission to get service ref: " + sr.getProperty(Constants.OBJECTCLASS), ignore); } } return false; } /** * Filter out all services that we don't have permission to get. * * @param srs * Set of ServiceRegistrationImpls to check. */ @Override void filterGetServicePermission(Set> srs) { for (final Iterator> i = srs.iterator(); i .hasNext();) { final ServiceRegistrationImpl sr = i.next(); ; if (!okGetServicePerms(sr.getReference())) { i.remove(); } } } // // Capability and Requirement checks // @Override boolean hasProvidePermission(BundleCapabilityImpl bc) { final BundleImpl b = bc.getBundleGeneration().bundle; if (b.id != 0) { final PermissionCollection pc = ph.getPermissionCollection(new Long(b.id)); return pc.implies(new CapabilityPermission(bc.getNamespace(), CapabilityPermission.PROVIDE)); } return true; } @Override boolean hasRequirePermission(BundleRequirementImpl br) { final BundleImpl b = br.getBundleGeneration().bundle; if (b.id != 0) { final PermissionCollection pc = ph.getPermissionCollection(new Long(b.id)); return pc.implies(new CapabilityPermission(br.getNamespace(), CapabilityPermission.REQUIRE)); } return true; } @Override boolean hasRequirePermission(BundleRequirementImpl br, BundleCapabilityImpl bc) { final BundleImpl bbr = br.getBundleGeneration().bundle; if (bbr.id != 0) { final PermissionCollection pc = ph.getPermissionCollection(new Long(bbr.id)); return pc.implies(new CapabilityPermission(bc.getNamespace(), bc.getAttributes(), bc.getBundleGeneration().bundle, CapabilityPermission.REQUIRE)); } return true; } // // AdaptPermission checks // @Override void checkAdaptPerm(BundleImpl b, Class type) { final SecurityManager sm = System.getSecurityManager(); if (null != sm) { sm.checkPermission(new AdaptPermission(type.getName(), b, AdaptPermission.ADAPT)); } } // // BundleArchive secure operations // @Override BundleResourceStream callGetBundleResourceStream(final BundleArchive archive, final String name, final int ix) { return AccessController .doPrivileged(new PrivilegedAction() { public BundleResourceStream run() { return archive.getBundleResourceStream(name, ix); } }); } @Override Enumeration callFindResourcesPath(final BundleArchive archive, final String path) { return AccessController .doPrivileged(new PrivilegedAction>() { public Enumeration run() { return archive.findResourcesPath(path); } }); } // // BundleClassLoader secure operations // @Override Object callSearchFor(final BundleClassLoader cl, final String name, final String pkg, final String path, final BundleClassLoader.SearchAction action, final int options, final BundleClassLoader requestor, final HashSet visited) { return AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return cl.searchFor(name, pkg, path, action, options, requestor, visited); } }); } @Override String callFindLibrary0(final BundleClassLoader cl, final String name) { return AccessController.doPrivileged(new PrivilegedAction() { public String run() { return cl.findLibrary0(name); } }); } // // BundleImpl secure operations // @Override void callFinalizeActivation(final BundleImpl b) throws BundleException { try { AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws BundleException { b.finalizeActivation(); return null; } }); } catch (final PrivilegedActionException e) { throw (BundleException) e.getException(); } } @Override BundleThread createBundleThread(final FrameworkContext fc) { return AccessController.doPrivileged(new PrivilegedAction() { public BundleThread run() { return new BundleThread(fc); } }); } @Override void callUpdate0(final BundleImpl b, final InputStream in, final boolean wasActive) throws BundleException { try { final AccessControlContext acc = AccessController.getContext(); AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws BundleException { b.update0(in, wasActive, acc); return null; } }); } catch (final PrivilegedActionException e) { throw (BundleException) e.getException(); } } @Override void callUninstall0(final BundleImpl b) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { b.uninstall0(); return null; } }); } @Override void callSetAutostartSetting(final BundleImpl b, final int settings) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { b.setAutostartSetting0(settings); return null; } }); } @Override HeaderDictionary callGetHeaders0(final BundleGeneration bg, final String locale) { return AccessController .doPrivileged(new PrivilegedAction() { public HeaderDictionary run() { return bg.getHeaders0(locale); } }); } @Override Vector callFindEntries(final BundleGeneration bg, final String path, final String filePattern, final boolean recurse) { return AccessController.doPrivileged(new PrivilegedAction>() { public Vector run() { return bg.findEntries(path, filePattern, recurse); } }); } @Override BundleClassLoader newBundleClassLoader(final BundleGeneration bg) throws BundleException { try { return AccessController .doPrivileged(new PrivilegedExceptionAction() { public BundleClassLoader run() throws Exception { return new BundleClassLoader(bg); } }); } catch (final PrivilegedActionException pe) { throw (BundleException) pe.getException(); } } Vector getBundleClassPathEntry(final BundleGeneration bg, final String name, final boolean onlyFirst) { return AccessController.doPrivileged(new PrivilegedAction>() { public Vector run() { return bg.getBundleClassPathEntries(name, onlyFirst); } }); } @Override AccessControlContext getAccessControlContext(BundleImpl bundle) { ProtectionDomain pd = bundle.current().getProtectionDomain(); return pd != null ?new AccessControlContext(new ProtectionDomain[] {pd}) : null; } // // Bundles Secure operation // @Override BundleImpl callInstall0(final Bundles bs, final String location, final InputStream in, final Bundle caller) throws BundleException { try { final AccessControlContext acc = AccessController.getContext(); return AccessController .doPrivileged(new PrivilegedExceptionAction() { public BundleImpl run() throws BundleException { return bs.install0(location, in, acc, caller); } }); } catch (final PrivilegedActionException e) { throw (BundleException) e.getException(); } } // // Listeners Secure operations // @Override void callBundleChanged(final FrameworkContext fwCtx, final BundleEvent evt) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { fwCtx.listeners.bundleChanged(evt); return null; } }); } @Override void callServiceChanged(final FrameworkContext fwCtx, final Collection receivers, final ServiceEvent evt, final Set matchBefore) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { fwCtx.listeners.serviceChanged(receivers, evt, matchBefore); return null; } }); } // // PackageAdmin secure operations // @Override void callRefreshPackages0(final PackageAdminImpl pa, final Bundle[] bundles, final FrameworkListener[] fl) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { pa.refreshPackages0(bundles, fl); return null; } }); } // // ServiceRegisterationImpl secure operations // @Override S callGetService(final ServiceRegistrationImpl sr, final Bundle b) { return AccessController.doPrivileged(new PrivilegedAction() { public S run() { @SuppressWarnings("unchecked") final ServiceFactory srf = (ServiceFactory) sr.service; return srf.getService(b, sr); } }); } @Override void callUngetService(final ServiceRegistrationImpl sr, final Bundle b, final S instance) { @SuppressWarnings("unchecked") final ServiceFactory srf = (ServiceFactory) sr.service; AccessController.doPrivileged(new PrivilegedAction() { public Object run() { srf.ungetService(b, sr, instance); return null; } }); } // // StartLevelController secure operations // @Override void callSetStartLevel(final BundleImpl b, final int startlevel) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { b.setStartLevel(startlevel); return null; } }); } @Override void callSetInitialBundleStartLevel0(final StartLevelController slc, final int startlevel) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { slc.setInitialBundleStartLevel0(startlevel, true); return null; } }); } // // SystemBundle secure operations // @Override void callShutdown(final SystemBundle sb, final boolean restart) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { sb.shutdown(restart); return null; } }); } // // Permissions package functionality // /** * Get protection domain for bundle */ @Override ProtectionDomain getProtectionDomain(final BundleGeneration bg) { try { // We cannot use getBundleURL() here because that will // trigger a persmission check while we're still in // the phase of building permissions String h = Long.toString(bg.bundle.id); if (bg.generation != 0) { h += "." + Long.toString(bg.generation); } final URLStreamHandler ush = bg.bundle.fwCtx.urlStreamHandlerFactory .createURLStreamHandler(BundleURLStreamHandler.PROTOCOL); final URL bundleUrl = new URL(BundleURLStreamHandler.PROTOCOL, h, -1, "", ush); final InputStream pis = bg.archive .getBundleResourceStream("OSGI-INF/permissions.perm", 0); final PermissionCollection pc = ph .createPermissionCollection(bg.bundle.location, bg.bundle, pis); final ArrayList> cc = bg.archive.getCertificateChains(false); Certificate[] cca; if (cc != null) { final ArrayList tmp = new ArrayList(); for (final List list : cc) { tmp.addAll(list); } cca = tmp.toArray(new Certificate[tmp.size()]); } else { cca = null; } return new ProtectionDomain(new CodeSource(bundleUrl, cca), pc); } catch (final MalformedURLException _ignore) { } return null; } @Override URL getBundleURL(final FrameworkContext fwCtx, final String s) throws MalformedURLException { try { return AccessController .doPrivileged(new PrivilegedExceptionAction() { public URL run() throws MalformedURLException { return new URL(null, s, fwCtx.urlStreamHandlerFactory .createURLStreamHandler(BundleURLStreamHandler.PROTOCOL)); } }); } catch (final PrivilegedActionException e) { throw (MalformedURLException) e.getException(); } } // // Privileged system calls // @Override ClassLoader getClassLoaderOf(final Class c) { return AccessController.doPrivileged(new PrivilegedAction() { public ClassLoader run() { return c.getClassLoader(); } }); } // // Cleaning // /** * Purge all cached information for specified bundle. */ @Override void purge(BundleImpl b, ProtectionDomain pd) { if (ph.purgePermissionCollection(new Long(b.id), pd.getPermissions())) { adminPerms.remove(b); } } // // Private // AdminPermission getAdminPermission(Bundle b, int ti) { AdminPermission[] res; res = adminPerms.get(b); if (res != null) { if (res[ti] != null) { return res[ti]; } } else { res = new AdminPermission[AP_MAX]; adminPerms.put(b, res); } res[ti] = new AdminPermission(b, AP_TO_STRING[ti]); return res[ti]; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundlePackages.java0000644000175000017500000010556012346513666030707 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import org.knopflerfish.framework.Util.Comparator; import org.knopflerfish.framework.Util.HeaderEntry; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.wiring.BundleRequirement; /** * Class representing all packages imported and exported. * * @author Jan Stein * @author Mats-Ola Persson * @author Gunnar Ekolin */ class BundlePackages { final BundleGeneration bg; /* Sorted list of exports */ private final ArrayList exports = new ArrayList(1); /* Sorted list of declared imports */ private final ArrayList imports = new ArrayList(1); /* Sorted list of declared dynamic imports */ private final ArrayList dImportPatterns = new ArrayList(1); private final Map> capabilities; private TreeMap fragments = null; private ArrayList require; private ArrayList requiredBy = null; /* Sorted list of active imports */ private ArrayList okImports = null; /* Is our packages registered */ private boolean registered = false; /* Reason we failed to resolve */ private String failReason = null; /* Ordering of dynamic imports */ private int nextDynId = 0; final static String EMPTY_STRING = ""; /** * Create package entry. */ BundlePackages(BundleGeneration bg) { this.bg = bg; final BundleArchive ba = bg.archive; for (final HeaderEntry he : Util.parseManifestHeader(Constants.IMPORT_PACKAGE, ba .getAttribute(Constants.IMPORT_PACKAGE), false, true, false)) { final Iterator pi = he.getKeys().iterator(); ImportPkg ip = new ImportPkg(pi.next(), he, this, false); for (;;) { final int ii = Util.binarySearch(imports, ipComp, ip); if (ii < 0) { imports.add(-ii - 1, ip); } else { throw new IllegalArgumentException("Duplicate import definitions for - " + ip.name); } if (pi.hasNext()) { ip = new ImportPkg(ip, pi.next()); } else { break; } } } for (final HeaderEntry he : Util .parseManifestHeader(Constants.EXPORT_PACKAGE, ba.getAttribute(Constants.EXPORT_PACKAGE), false, true, false)) { final List keys = he.getKeys(); final Iterator pi = keys.iterator(); ExportPkg ep = new ExportPkg(pi.next(), he, this); for (;;) { final int ei = Math.abs(Util.binarySearch(exports, epComp, ep) + 1); exports.add(ei, ep); if (!bg.v2Manifest) { final ImportPkg ip = new ImportPkg(ep); final int ii = Util.binarySearch(imports, ipComp, ip); if (ii < 0) { imports.add(-ii - 1, ip); } } if (pi.hasNext()) { ep = new ExportPkg(ep, pi.next()); } else { break; } } } parseDynamicImports(ba.getAttribute(Constants.DYNAMICIMPORT_PACKAGE)); final List hes = Util .parseManifestHeader(Constants.REQUIRE_BUNDLE, ba.getAttribute(Constants.REQUIRE_BUNDLE), true, true, false); if (!hes.isEmpty()) { require = new ArrayList(); for (final HeaderEntry he : hes) { require.add(new RequireBundle(this, he)); } } else { require = null; } capabilities = bg.getDeclaredCapabilities(); } /** * Create package entry used by system bundle. */ BundlePackages(BundleGeneration bg, String exportString) { this.bg = bg; for (final HeaderEntry he : Util.parseManifestHeader(Constants.EXPORT_PACKAGE, exportString, false, true, false)) { final List keys = he.getKeys(); final Iterator pi = keys.iterator(); ExportPkg ep = new ExportPkg(pi.next(), he, this); for (;;) { final int ei = Util.binarySearch(exports, epComp, ep); if (ei >= 0) { // Duplicate export entries from system bundle // use the last one since it is configured by // the user. exports.set(ei, ep); } else { exports.add(-ei - 1, ep); } if (pi.hasNext()) { ep = new ExportPkg(ep, pi.next()); } else { break; } } } require = null; capabilities = bg.getDeclaredCapabilities(); } /** * Create package entry used to clone fragment bundle. */ BundlePackages(BundlePackages host, BundlePackages frag, boolean noNew) { this.bg = host.bg; /* * make sure that the fragment's bundle does not conflict with this bundle's * (see 3.1.4 r4-core) */ for (final Iterator iiter = frag.getImports(); iiter.hasNext();) { final ImportPkg fip = iiter.next(); final ImportPkg ip = host.getImport(fip.name); if (ip != null) { if (!fip.intersect(ip)) { throw new IllegalStateException( "Host bundle import package and fragment bundle " + "import package doesn't intersect, resolve isn't possible."); } } else if (noNew){ throw new IllegalStateException("Resolve host bundle package would " + "be shadow by new fragment import."); } imports.add(new ImportPkg(fip, this)); } if (frag.require != null) { require = new ArrayList(); for (final RequireBundle fragReq : frag.require) { boolean match = false; if (host.require != null) { // check for conflicts for (final RequireBundle req : host.require) { if (fragReq.name.equals(req.name)) { if (fragReq.overlap(req)) { match = true; } else { throw new IllegalStateException( "Fragment bundle required bundle doesn't completely " + "overlap required bundle in host bundle."); } } } } if (!match) { if (bg.bundle.state != Bundle.INSTALLED) { throw new IllegalStateException("Can not attach a fragment with new required " + "bundles to a resolved host"); } require.add(new RequireBundle(fragReq, this)); } } } else { require = null; } for (final Iterator eiter = frag.getExports(); eiter.hasNext();) { final ExportPkg fep = eiter.next(); final ExportPkg hep = getExport(fep.name); if (fep.pkgEquals(hep)) { continue; } exports.add(new ExportPkg(fep, this)); } capabilities = new HashMap>(); for (Entry> e : frag.bg.getDeclaredCapabilities().entrySet()) { List l = new ArrayList(); for (BundleCapabilityImpl bc : e.getValue()) { l.add(new BundleCapabilityImpl(bc, bg)); } capabilities.put(e.getKey(), l); } } /** * Register bundle packages in framework. * */ void registerPackages() { bg.bundle.fwCtx.resolver.registerCapabilities(capabilities, exports.iterator(), imports.iterator()); registered = true; } /** * Unregister bundle packages in framework. * */ synchronized boolean unregisterPackages(boolean force) { if (registered) { if (bg.bundle.fwCtx.resolver.unregisterCapabilities(capabilities, getExports(), getImports(), force)) { registered = false; if (okImports != null) { okImports = null; for (List lbr : bg.getOtherRequirements().values()) { for (BundleRequirementImpl br : lbr) { br.resetWire(); } } unRequireBundles(); detachFragments(); } } else { return false; } } return true; } /** * Resolve all the bundles' packages. * * @return true if we resolved all packages. If we failed return false. Reason * for fail can be fetched with getResolveFailReason(). * @throws BundleException Resolver hook complaint. */ boolean resolvePackages(BundleImpl[] triggers) throws BundleException { failReason = bg.bundle.fwCtx.resolver.resolve(bg, this, triggers); if (failReason == null) { okImports = new ArrayList(imports.size()); for (final Iterator i = getImports(); i.hasNext();) { final ImportPkg ip = i.next(); if (ip.provider != null) { // <=> optional import with unresolved // provider okImports.add(ip); } } return true; } else { return false; } } /** * Return a string with a reason for why resolve failed. * * @return A error message string. */ String getResolveFailReason() { return failReason; } /** * If bundle package has been resolved look for a BundlePackages that provides * the requested package. * * @param pkg Package name * @return BundlePackages exporting the pkg. */ synchronized BundlePackages getProviderBundlePackages(String pkg) { if (bg.bundle instanceof SystemBundle) { return isExported(pkg) ? this : null; } if (okImports == null) { return null; } final int ii = Util.binarySearch(okImports, ipFind, pkg); if (ii >= 0) { return okImports.get(ii).provider.bpkgs; } return null; } /** * List available sub packages. * * @param pkg Package name * @return . */ synchronized Set getSubProvider(String pkg) { Set res = new HashSet(); if (pkg.length() > 0) { pkg = pkg + "."; } if (okImports != null) { for (ImportPkg ip : okImports) { if (ip.provider != null && ip.name.startsWith(pkg)) { String n = ip.name.substring(pkg.length()); if (n.indexOf('.') == -1) { res.add(n); } } } for (Iterator irb = getRequire(); irb.hasNext(); ) { RequireBundle rb = irb.next(); if (rb.bpkgs != null) { for (Iterator iep = rb.bpkgs.getExports(); iep.hasNext(); ) { ExportPkg ep = iep.next(); if (ep.name.startsWith(pkg)) { String n = ep.name.substring(pkg.length()); if (n.indexOf('.') == -1) { res.add(n); } } } } } } return res; } /** * Check if we can dynamically import a package. Re-check that we haven't * gotten a provider. (Do we need to do that?) * * @param pkg Package name * @return Bundle exporting */ synchronized BundlePackages getDynamicProviderBundlePackages(String pkg) { if (okImports == null) { return null; } final int ii = Util.binarySearch(okImports, ipFind, pkg); if (ii >= 0) { return okImports.get(ii).provider.bpkgs; } BundlePackages res = null; BundleImpl [] trigger = null; final FrameworkContext fwCtx = bg.bundle.fwCtx; try { for (final ImportPkg ip : dImportPatterns) { if (ip.name == EMPTY_STRING || (ip.name.endsWith(".") && pkg.startsWith(ip.name)) || pkg.equals(ip.name)) { if (trigger == null) { trigger = new BundleImpl[] { bg.bundle }; fwCtx.resolverHooks.beginResolve(trigger); } final ImportPkg nip = new ImportPkg(ip, pkg); final ExportPkg ep = fwCtx.resolver.registerDynamicImport(nip); if (ep != null) { nip.provider = ep; nip.dynId = ++nextDynId; okImports.add(-ii - 1, nip); res = ep.bpkgs; break; } } } } catch (BundleException be) { fwCtx.frameworkError(bg.bundle, be); } if (trigger != null) { try { fwCtx.resolverHooks.endResolve(trigger); } catch (BundleException be) { fwCtx.frameworkError(bg.bundle, be); } } return res; } /** * Get all RequiredBundle for this BundlePackages. * * @return Iterator of RequireBundle. */ Iterator getRequire() { if (fragments != null) { synchronized (fragments) { final ArrayList> iters = new ArrayList>(fragments.size() + 1); if (require != null) { iters.add(require.iterator()); } for (final BundlePackages bundlePackages : fragments.values()) { iters.add(bundlePackages.getRequire()); } return new IteratorIterator(iters); } } else if (require != null) { return require.iterator(); } else { @SuppressWarnings("unchecked") final Iteratorres = Collections.EMPTY_LIST.iterator(); return res; } } /** * Get a list of all BundleGenerations that exports package * pkg that comes from bundles that we have required, * in correct order. Correct order is a depth first search order. * * @param pkg String with package name we are searching for, if null get all. * @return List of required BundleGenerations or null if we don't * require any bundles. */ ArrayList getRequiredBundleGenerations(String pkg) { ArrayList res = null; for (final Iterator i = getRequire(); i.hasNext(); ) { final RequireBundle rb = i.next(); if (rb.bpkgs != null && rb.bpkgs.isExported(pkg)) { if (res == null) { res = new ArrayList(2); } res.add(rb.bpkgs.bg); } } return res; } /** * Check if this BundlePackages is required by another Bundle. * * @return True if is required */ void addRequiredBy(BundlePackages r) { if (requiredBy == null) { requiredBy = new ArrayList(); } requiredBy.add(r); } /** * Check if this BundlePackages is required by another Bundle. * * @return True if is required */ boolean isRequired() { return requiredBy != null && !requiredBy.isEmpty(); } /** * Check if this BundlePackages is required by another Bundle. * * @return True if is required */ boolean isRequiredBy(BundlePackages cbp) { return requiredBy != null && requiredBy.contains(cbp); } /** * Get a list of all BundlePackages that requires the exported packages that * comes from the bundle owning this object. * * @return List of required BundlePackages */ List getRequiredBy() { final List res = new ArrayList(); if (requiredBy != null) { synchronized (requiredBy) { res.addAll(requiredBy); } if (fragments != null) { synchronized (fragments) { for (final BundlePackages bundlePackages : fragments.values()) { final List fl = bundlePackages.getRequiredBy(); if (fl != null) { res.addAll(fl); } } } } } return res; } /** * Check if package needs to be added as re-exported package. * * @param ep ExportPkg to re-export. */ void checkReExport(ExportPkg ep) { // NYI. Rework this solution and include fragments final int i = Util.binarySearch(exports, epFind, ep.name); if (i < 0) { final ExportPkg nep = new ExportPkg(ep, this); exports.add(-i - 1, nep); // Perhaps we should avoid this shortcut and go through Packages. ep.pkg.addExporter(nep); } } /** * Get ExportPkg for exported package. * * @return ExportPkg entry or null if package is not exported. */ private ExportPkg getExport(String pkg) { final int i = Util.binarySearch(exports, epFind, pkg); if (i >= 0) { return exports.get(i); } else { return null; } } /** * Get an iterator over all exported packages sorted * according to epComp. * * @return An Iterator over ExportPkg. */ Iterator getExports() { if (fragments != null) { synchronized (fragments) { final ArrayList> iters = new ArrayList>(fragments.size() + 1); iters.add(exports.iterator()); for (final BundlePackages bundlePackages : fragments.values()) { iters.add(bundlePackages.getExports()); } return new IteratorIteratorSorted(iters, epComp); } } else { return exports.iterator(); } } /** * Get an iterator over all exported packages with specific name. * * @return An Iterator over ExportPkg. */ Iterator getExports(String pkg) { final ArrayList res = new ArrayList(2); ExportPkg ep = getExport(pkg); if (ep != null) { res.add(ep); } if (fragments != null) { synchronized (fragments) { for (final BundlePackages bundlePackages : fragments.values()) { ep = bundlePackages.getExport(pkg); if (ep != null) { res.add(ep); } } } } return res.isEmpty() ? null : res.iterator(); } /** * Check if this packaged is exported */ boolean isExported(String pkg) { if (getExport(pkg) != null) { return true; } if (fragments != null) { synchronized (fragments) { for (final BundlePackages bundlePackages : fragments.values()) { if (bundlePackages.getExport(pkg) != null) { return true; } } } } return false; } /** * Get an iterator over all static imported packages sorted * according to ipComp. * * @return An Iterator over ImportPkg. */ Iterator getImports() { if (fragments != null) { synchronized (fragments) { final ArrayList> iters = new ArrayList>(fragments.size() + 1); iters.add(imports.iterator()); for (final BundlePackages bundlePackages : fragments.values()) { iters.add(bundlePackages.getImports()); } return new IteratorIteratorSorted(iters, ipComp); } } else { return imports.iterator(); } } /** * Get an iterator over all active imported packages. * * @return An Iterator over ImportPkg. */ Iterator getActiveImports() { if (okImports != null) { return okImports.iterator(); } else if (bg.isFragment()){ // This is fragment BP, use host return bg.bpkgs.getActiveImports(); } else { return null; } } /** * Get the list of package capabilities derived from the Export-Package header. * * The bundle capability objects in the list has the same order as the packages * in the Export-Package header. * * @return ordered list with bundle capabilities for packages. */ SortedSet getDeclaredPackageCapabilities() { final TreeSet epCreationOrder = new TreeSet(exports); return epCreationOrder; } /** * Get the list package requirements derived from the Import-Package header. * The bundle requirement objects for imported packages in the list has the * same order as the packages in the Import-Package header. * * @return all defined import package requirements for this bundle revision. */ SortedSet getDeclaredPackageRequirements() { final TreeSet ipCreationOrder = new TreeSet(imports); ipCreationOrder.addAll(dImportPatterns); return ipCreationOrder; } /** * Get the list of package capabilities available for export. Contains exports from fragments. * * The bundle capability objects in the list has the same order as the packages * in the Export-Package header. * * @return ordered list with bundle capabilities for packages. */ List getPackageCapabilities() { List res = new ArrayList(getDeclaredPackageCapabilities()); if (fragments != null) { synchronized (fragments) { for (final BundlePackages bpkgs : fragments.values()) { res.addAll(bpkgs.getDeclaredPackageCapabilities()); } } } return res; } /** * Get the list of package capabilities available for export. Contains exports from fragments. * * The bundle capability objects in the list has the same order as the packages * in the Export-Package header. * * @return ordered list with bundle capabilities for packages. */ List getPackageRequirements() { List res = new ArrayList(); for (ImportPkg ip : getDeclaredPackageRequirements()) { if (ip.provider != null || ip.isDynamic()) { res.add(ip); } } if (fragments != null) { HashSet parents = new HashSet(); synchronized (this) { // Get fragment parents for (ImportPkg oip : okImports) { if (oip.parent != null && oip.parent.bpkgs != oip.bpkgs) { parents.add(oip.parent); } } } synchronized (fragments) { for (final BundlePackages bpkgs : fragments.values()) { for (ImportPkg ip : bpkgs.getDeclaredPackageRequirements()) { if (ip.isDynamic() || parents.contains(ip)) { res.add(ip); } } } } } return res; } synchronized List getActiveChildImports(ImportPkg ip) { List res = new ArrayList(); for (ImportPkg oip : okImports) { if (oip.parent == ip) { res.add(oip); } } return res; } /** * Get the list bundle requirements derived from the Require-Bundle header. * The bundle requirement objects for required bundles in the list has the * same order as the bundles in the Require-Bundle header. * * @return all defined require bundle requirements for this bundle revision. */ List getDeclaredBundleRequirements() { final List res = new ArrayList(); if (require!=null) { final TreeSet rbCreationOrder = new TreeSet(require); res.addAll(rbCreationOrder); } return res; } /** * * @return */ Map> getOtherCapabilities() { Map> res = capabilities; if (fragments != null) { synchronized (fragments) { boolean copied = false; for (final BundlePackages bpkgs : fragments.values()) { Map> frm = bpkgs.getOtherCapabilities(); if (!frm.isEmpty()) { if (!copied) { res = new HashMap>(res); copied = true; } for (Entry> e : frm.entrySet()) { String ns = e.getKey(); List p = res.get(ns); if (p != null) { p = new ArrayList(p); p.addAll(e.getValue()); } else { p = e.getValue(); } res.put(ns, p); } } } } } return res; } /** * Get class loader for these packages. * * @return ClassLoader handling these packages. */ ClassLoader getClassLoader() { return bg.getClassLoader(); } /** * Is these packages registered in the Packages object. * * @return True if packages are registered otherwise false. */ boolean isRegistered() { return registered; } /** * Attach a fragment bundle packages. * * @param fbpkgs The BundlePackages of the fragment to be attached. * @return null if okay, otherwise a String with fail reason. * @throws BundleException Resolver hook complaint. */ String attachFragment(BundlePackages fbpkgs) throws BundleException { // TODO, should we lock this?! final boolean resolvedHost = okImports != null; final BundlePackages nfbpkgs = new BundlePackages(this, fbpkgs, resolvedHost); nfbpkgs.registerPackages(); if (resolvedHost) { try { failReason = bg.bundle.fwCtx.resolver.resolve(bg, nfbpkgs, null); } catch (BundleException be) { nfbpkgs.unregisterPackages(true); throw be; } if (failReason == null) { for (final Iterator i = nfbpkgs.getImports(); i.hasNext();) { final ImportPkg ip = i.next(); if (ip.provider != null) { // <=> optional import with unresolved // provider final int ii = Util.binarySearch(okImports, ipComp, ip); if (ii < 0) { okImports.add(-ii - 1, ip); } } } } else { nfbpkgs.unregisterPackages(true); return failReason; } } if (fragments == null) { fragments = new TreeMap(); } fragments.put(fbpkgs.bg, nfbpkgs); return null; } /** * An attached fragment is now a zombie since it have been updated or * uninstalled. Mark all packages exported by this host as zombies, since * their contents may have changed. * * @param fb The fragment bundle that have been updated or uninstalled. */ void fragmentIsZombie(BundleImpl fb) { if (null != exports) { if (bg.bundle.fwCtx.debug.resolver) { bg.bundle.fwCtx.debug.println("Marking all packages exported by host bundle(id=" + bg.bundle.id + ",gen=" + bg.generation + ") as zombies since the attached fragment (id=" + fb.getBundleId() + ") was updated/uninstalled."); } for (final ExportPkg exportPkg : exports) { exportPkg.zombie = true; } } } /** * Detach a fragment bundle's packages. * * I.e., unregister and remove the fragments import / exports from the set of * packages that are imported / exported by this bundle packages. * * If this bundle packages is resolved, do nothing since in that case must not * change the set of imports and exports. * * @param fb The fragment bundle to detach. */ void detachFragmentSynchronized(BundleGeneration fbg, boolean unregister) { if (fragments != null) { synchronized (fragments) { detachFragment(fbg, unregister); } } } /** * Sets these packages registered in the Packages object. * * @return True if packages are registered otherwise false. */ void unregister() { registered = false; unRequireBundles(); } /** * Return a string representing this object * * @return A message string. */ @Override public String toString() { return "BundlePackages" + bundleGenInfo(); } String bundleGenInfo() { return "[id=" + bg.bundle.id + ",gen=" + bg.generation + "]"; } boolean isActive() { return okImports != null; } // // Private methods // /** * Get a specific import * * @return an import */ private ImportPkg getImport(String pkg) { final int i = Util.binarySearch(imports, ipFind, pkg); if (i >= 0) { return imports.get(i); } else { return null; } } /** * Remove this bundle packages from the requiredBy list in the wired required * bundle package. */ private void unRequireBundles() { if (require != null) { for (final RequireBundle req : require) { if (null != req.bpkgs && null != req.bpkgs.requiredBy) { req.bpkgs.requiredBy.remove(this); // TODO check if we can reset bpkgs to make checking easier } } } } /** * Detach all remaining fragments. */ private void detachFragments() { if (fragments != null) { synchronized (fragments) { while (!fragments.isEmpty()) { detachFragment(fragments.lastKey(), false); } fragments = null; } } } /** * Detach a fragment bundle's packages. * * I.e., unregister and remove the fragments import / exports from the set of * packages that are imported / exported by this bundle packages. * * If this bundle packages is resolved, do nothing since in that case must not * change the set of imports and exports. * * Note! Must be called with fragments locked. * * @param fb The fragment bundle to detach. * @param unregisterPkg Unregister the imports and exports of the specified * fragment. */ private void detachFragment(final BundleGeneration fbg, final boolean unregisterPkg) { if (null == okImports) { final BundlePackages fbpkgs = fragments.remove(fbg); if (fbpkgs != null) { if (unregisterPkg) { fbpkgs.unregisterPackages(true); } else { fbpkgs.unregister(); } } } } /** * Parse the dynamic import attribute */ void parseDynamicImports(final String s) { for (final HeaderEntry he : Util .parseManifestHeader(Constants.DYNAMICIMPORT_PACKAGE, s, false, true, false)) { if (he.getDirectives().containsKey(Constants.RESOLUTION_DIRECTIVE)) { throw new IllegalArgumentException(Constants.DYNAMICIMPORT_PACKAGE + " entry illegal contains a " + Constants.RESOLUTION_DIRECTIVE + " directive."); } ImportPkg tmpl = null; for (String key : he.getKeys()) { if (key.equals("*")) { key = EMPTY_STRING; } else if (key.endsWith(".*")) { key = key.substring(0, key.length() - 1); } else if (key.endsWith(".")) { throw new IllegalArgumentException(Constants.DYNAMICIMPORT_PACKAGE + " entry ends with '.': " + key); } else if (key.indexOf("*") != -1) { throw new IllegalArgumentException(Constants.DYNAMICIMPORT_PACKAGE + " entry contains a '*': " + key); } if (tmpl != null) { dImportPatterns.add(new ImportPkg(tmpl, key)); } else { tmpl = new ImportPkg(key, he, this, true); dImportPatterns.add(tmpl); } } } } // // Pkg Comparators // static final Comparator epComp = new Util.Comparator() { /** * Compare two ExportPkg objects on package name. * * @param a Object to compare. * @param b Object to compare. * @return Return 0 if equals, negative if first object is less than second * object and positive if first object is larger then second object. * @exception ClassCastException if object is not a ExportPkg object. */ public int compare(ExportPkg a, ExportPkg b) throws ClassCastException { return a.name.compareTo(b.name); } }; static final Util.Comparator epFind = new Util.Comparator() { /** * Compare package name of ExportPkg object with String object. * * @param a ExportPkg object to compare. * @param b String object to compare. * @return Return 0 if equals, negative if first object is less than second * object and positive if first object is larger then second object. * @exception ClassCastException if object is not a ExportPkg object. */ public int compare(ExportPkg a, String b) { return a.name.compareTo(b); } }; static final Util.Comparator ipComp = new Util.Comparator() { /** * Compare two ImportPkg objects by package name. * * @param a Object to compare. * @param b Object to compare. * @return Return 0 if equals, negative if first object is less than second * object and positive if first object is larger then second object. * @exception ClassCastException if object is not a ImportPkg object. */ public int compare(ImportPkg a, ImportPkg b) throws ClassCastException { return a.name.compareTo(b.name); } }; static final Util.Comparator ipFind = new Util.Comparator() { /** * Compare package name in ImportPkg object with a package name as a String. * * @param a Candidate ImportPkg object to compare. * @param b Package name of the ImportPkg to find. * @return Return 0 if equals, negative if first object is less than second * object and positive if first object is larger then second object. */ public int compare(ImportPkg a, String b) { return a.name.compareTo(b); } }; } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Listeners.java0000644000175000017500000004037012346513666030004 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Collection; import java.util.EventObject; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Set; import org.osgi.framework.AllServiceListener; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleListener; import org.osgi.framework.Constants; import org.osgi.framework.FrameworkEvent; import org.osgi.framework.FrameworkListener; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServicePermission; import org.osgi.framework.ServiceReference; import org.osgi.framework.SynchronousBundleListener; /** * Here we handle all listeners that bundles have registered. * * @author Jan Stein, Philippe Laporte, Gunnar Ekolin */ class Listeners { /** * All bundle event listeners. */ HashSet bundleListeners = new HashSet(); HashSet syncBundleListeners = new HashSet(); /** * All framework event listeners. */ private final HashSet frameworkListeners = new HashSet(); /** * All service event listeners. */ ServiceListenerState serviceListeners; /** * Queue of async events to deliver */ private LinkedList asyncEventQueue = null; /** * All threads for delivering async events */ private AsyncEventThread [] threads = null; /** * Map of active listeners to thread. */ private HashMap activeListeners = null; /** * Handle to secure call class. */ private PermissionOps secure; FrameworkContext fwCtx; boolean nocacheldap; volatile boolean quit = false; Listeners(FrameworkContext framework, PermissionOps perm) { this.fwCtx = framework; secure = perm; nocacheldap = framework.props.getBooleanProperty(FWProps.LDAP_NOCACHE_PROP); serviceListeners = new ServiceListenerState(this); final String ets = framework.props.getProperty(FWProps.LISTENER_N_THREADS_PROP); int n_threads = 1; if (ets != null) { try { n_threads = Integer.parseInt(ets); } catch (final NumberFormatException nfe) { // NYI, report error } } if (n_threads > 0) { asyncEventQueue = new LinkedList(); threads = new AsyncEventThread[n_threads]; for (int i = 0; i < n_threads; i++) { threads[i] = new AsyncEventThread(i); threads[i].start(); } if (n_threads > 1) { activeListeners = new HashMap(); } } } void clear() { bundleListeners.clear(); syncBundleListeners.clear(); frameworkListeners.clear(); serviceListeners.clear(); secure = null; fwCtx = null; } /** * Add a bundle listener to the current framework. * * @param bundle Who wants to add listener. * @param listener Object to add. */ void addBundleListener(BundleContextImpl bc, BundleListener listener) { final ListenerEntry le = new ListenerEntry(bc, listener); if (listener instanceof SynchronousBundleListener) { secure.checkListenerAdminPerm(bc.bundle); synchronized (syncBundleListeners) { syncBundleListeners.add(le); } } else { synchronized (bundleListeners) { bundleListeners.add(le); } } } /** * Remove bundle listener from current framework. Silently ignore * if listener doesn't exist. If listener is registered more than * once remove one instances. * * @param bundle Who wants to remove listener. * @param listener Object to remove. */ void removeBundleListener(BundleContextImpl bc, BundleListener listener) { final ListenerEntry le = new ListenerEntry(bc, listener); if (listener instanceof SynchronousBundleListener) { synchronized (syncBundleListeners) { secure.checkListenerAdminPerm(bc.bundle); syncBundleListeners.remove(le); } } else { synchronized (bundleListeners) { bundleListeners.remove(le); } } } /** * Add a bundle listener to current framework. * * @param bc Who wants to add listener. * @param listener Object to add. */ void addFrameworkListener(BundleContextImpl bc, FrameworkListener listener) { final ListenerEntry le = new ListenerEntry(bc, listener); synchronized (frameworkListeners) { frameworkListeners.add(le); } } /** * Remove framework listener from current framework. Silently ignore * if listener doesn't exist. If listener is registered more than * once remove all instances. * * @param bc Who wants to remove listener. * @param listener Object to remove. */ void removeFrameworkListener(BundleContextImpl bc, FrameworkListener listener) { synchronized (frameworkListeners) { frameworkListeners.remove(new ListenerEntry(bc, listener)); } } /** * Add a service listener with filter to current framework. * If no filter is wanted, call with filter param set to null. * * @param bundle Who wants to add listener. * @param listener Object to add. * @param filter LDAP String used for filtering event before calling listener. */ void addServiceListener(BundleContextImpl bc, ServiceListener listener, String filter) throws InvalidSyntaxException { serviceListeners.add(bc, listener, filter); } /** * Remove service listener from current framework. Silently ignore * if listener doesn't exist. If listener is registered more than * once remove all instances. * * @param bundle Who wants to remove listener. * @param listener Object to remove. */ void removeServiceListener(BundleContextImpl bc, ServiceListener listener) { serviceListeners.remove(bc, listener); } /** * Remove all listener registered by a bundle in the current framework. * * @param bi Bundle which listeners we want to remove. */ void removeAllListeners(BundleContextImpl bc) { removeAllListeners(syncBundleListeners, bc); removeAllListeners(bundleListeners, bc); removeAllListeners(frameworkListeners, bc); serviceListeners.removeAll(bc); } /** * Receive notification that a bundle has had a change occur in its lifecycle. * NOTE! Must be called with AllPermission!? * * @see org.osgi.framework.BundleListener#bundleChanged */ void bundleChanged(final BundleEvent evt) { final HashSet filteredSyncBundleListeners = new HashSet(); HashSet filteredBundleListeners = null; final int type = evt.getType(); if (type != BundleEvent.LAZY_ACTIVATION && type != BundleEvent.STARTING && type != BundleEvent.STOPPING) { filteredBundleListeners = new HashSet(); } fwCtx.bundleHooks.filterBundleEventReceivers( evt, filteredSyncBundleListeners, filteredBundleListeners); for(final ListenerEntry le : filteredSyncBundleListeners) { bundleChanged(le, evt); } if (filteredBundleListeners != null) { if (asyncEventQueue != null) { synchronized (asyncEventQueue) { for(final ListenerEntry le : filteredBundleListeners) { asyncEventQueue.addLast(new AsyncEvent(le, evt)); } asyncEventQueue.notify(); } } else { for(final ListenerEntry le : filteredBundleListeners) { bundleChanged(le, evt); } } } } /** * Receive notification of a general framework event. * * @see org.osgi.framework.FrameworkListener#frameworkEvent */ void frameworkEvent(final FrameworkEvent evt, FrameworkListener... oneTimeListeners) { if (fwCtx.debug.errors) { if (evt.getType() == FrameworkEvent.ERROR) { fwCtx.debug.println("errors - FrameworkErrorEvent bundle #" + evt.getBundle().getBundleId()); fwCtx.debug.printStackTrace("errors - FrameworkErrorEvent throwable: ", evt.getThrowable()); } } if (fwCtx.debug.warnings) { if (evt.getType() == FrameworkEvent.WARNING) { fwCtx.debug.println("warnings - FrameworkErrorEvent bundle #" + evt.getBundle().getBundleId()); fwCtx.debug.printStackTrace("warnings - FrameworkErrorEvent throwable: ", evt.getThrowable()); } } if (fwCtx.debug.startlevel) { if (evt.getType() == FrameworkEvent.STARTLEVEL_CHANGED) { fwCtx.debug .println("startlevel: FrameworkEvent Startlevel Changed"); } else if (evt.getType() == FrameworkEvent.STARTED) { fwCtx.debug.println("startlevel: FrameworkEvent Started"); } } if (asyncEventQueue != null) { synchronized (asyncEventQueue) { if (oneTimeListeners!=null) { for (final FrameworkListener fl : oneTimeListeners) { asyncEventQueue.addLast(new AsyncEvent(new ListenerEntry(null, fl), evt)); } } synchronized (frameworkListeners) { for (final ListenerEntry listenerEntry : frameworkListeners) { asyncEventQueue.addLast(new AsyncEvent(listenerEntry, evt)); } } asyncEventQueue.notify(); } } else { if (oneTimeListeners != null) { for (final FrameworkListener ofl : oneTimeListeners) { frameworkEvent(new ListenerEntry(null, ofl), evt); } } ListenerEntry [] fl; synchronized (frameworkListeners) { fl = new ListenerEntry[frameworkListeners.size()]; frameworkListeners.toArray(fl); } for (final ListenerEntry element : fl) { frameworkEvent(element, evt); } } } /** * Receive notification that a service has had a change occur in its lifecycle. * * @see org.osgi.framework.ServiceListener#serviceChanged */ void serviceChanged(final Collection receivers, final ServiceEvent evt, final Set matchBefore) { final ServiceReferenceImpl sr = (ServiceReferenceImpl)evt.getServiceReference(); final String[] classes = (String[])sr.getProperty(Constants.OBJECTCLASS); final int n = 0; // TODO: OSGi43 the interplay between ldap filters, hooks and MODIFIED_ENDMATCH should be revised if (matchBefore != null) { for (final ServiceListenerEntry l : receivers) { matchBefore.remove(l); } } fwCtx.serviceHooks.filterServiceEventReceivers(evt, receivers); for (final ServiceListenerEntry l : receivers) { try { if (!l.isRemoved() && (!secure.checkPermissions() || l.bc.bundle.hasPermission(new ServicePermission(sr, ServicePermission.GET)))) { final boolean testAssignable = !(l.listener instanceof AllServiceListener); for (int i = 0; i < classes.length; i++) { if (testAssignable && !sr.isAssignableTo(l.bc.bundle, classes[i])){ continue; } try { ((ServiceListener)l.listener).serviceChanged(evt); } catch (final Throwable pe) { fwCtx.frameworkError(l.bc, pe); } break; } } } catch (final IllegalStateException ignore) { // Bundle got UNINSTALLED, skip it } } if (fwCtx.debug.ldap) { fwCtx.debug.println("Notified " + n + " listeners"); } } /** * * */ Set getMatchingServiceListeners(final ServiceReference sr) { return serviceListeners.getMatchingListeners((ServiceReferenceImpl)sr); } // // Private methods // /** * Remove all listener registered by a bundle in specified list within * the current framework. Silently ignore if listener doesn't exist. * * @param s Which set to remove from bundle, framework or service. * @param bc Bundle which listeners we want to remove. */ private void removeAllListeners(Set s, BundleContext bc) { synchronized (s) { for (final Iterator i = s.iterator(); i.hasNext();) { if (i.next().bc == bc) { i.remove(); } } } } /** * */ private void bundleChanged(final ListenerEntry le, final BundleEvent evt) { try { ((BundleListener)le.listener).bundleChanged(evt); } catch (final Throwable pe) { fwCtx.frameworkError(le.bc, pe); } } /** * */ private void frameworkEvent(final ListenerEntry le, FrameworkEvent evt) { try { ((FrameworkListener)le.listener).frameworkEvent(evt); } catch (final Exception pe) { // Don't report Error events again, since probably would go into an infinite loop. if (evt.getType() != FrameworkEvent.ERROR) { fwCtx.frameworkError(le.bc, pe); } } } // // Private classes // static class AsyncEvent { final ListenerEntry le; final EventObject evt; AsyncEvent(ListenerEntry le, EventObject evt) { this.le = le; this.evt = evt; } } /** * Thread that deliver asynchronous events. */ private class AsyncEventThread extends Thread { AsyncEventThread(int i) { super(fwCtx.threadGroup, "AsyncEventThread#" + i); } @Override public void run() { while (true) { AsyncEvent ae; synchronized (asyncEventQueue) { while (!quit && asyncEventQueue.isEmpty()) { try { asyncEventQueue.wait(); } catch (final InterruptedException ignored) { } } if (quit) { break; } ae = asyncEventQueue.removeFirst(); } if (activeListeners != null) { synchronized (activeListeners) { while (activeListeners.containsKey(ae.le)) { // TODO, implement detection of hanging listeners? try { activeListeners.wait(); } catch (final InterruptedException ignore) { } } activeListeners.put(ae.le, Thread.currentThread()); } } // Either an unregistered one-time listener or the bundle // owning the listener must be valid. if (ae.le.bc==null || ae.le.bc.isValid()) { if (ae.evt instanceof BundleEvent) { bundleChanged(ae.le, (BundleEvent)ae.evt); } else { frameworkEvent(ae.le, (FrameworkEvent)ae.evt); } } if (activeListeners != null) { synchronized (activeListeners) { activeListeners.remove(ae.le); activeListeners.notifyAll(); } } } } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/MainClassBundleActivator.java0000644000175000017500000000723512346513666032720 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.lang.reflect.Method; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; /** * BundleActivator implementation that can handle a jar file * with just a Main-class attribute. * *

* When the start method is called, a new thread is started for * the bundle and the static main method is called with zero * arguments. *

* *

* When the stop method is called, any static method named "stop" * is called. *

*/ public class MainClassBundleActivator implements BundleActivator, Runnable { Method startMethod = null; Method stopMethod = null; Thread runner = null; String[] argv = new String[] { }; public MainClassBundleActivator(Class clazz) throws Exception { startMethod = clazz.getMethod("main", new Class[] { argv.getClass() }); // Check for optional stop method try { stopMethod = clazz.getMethod("stop", new Class[] { }); } catch (final Exception ignored) { } } public void start(BundleContext bc) throws BundleException { try { final BundleImpl b = (BundleImpl)bc.getBundle(); runner = new Thread(b.fwCtx.threadGroup, "start thread for executable jar file, bundle id=" + b.getBundleId()); runner.start(); } catch (final Exception e) { throw new BundleException("Failed to start main class", BundleException.UNSPECIFIED, e); } } public void stop(BundleContext bc) throws BundleException { if(stopMethod != null) { try { stopMethod.invoke(null, new Object[] { } ); } catch (final Exception e) { throw new BundleException("Failed to stop main class", BundleException.UNSPECIFIED, e); } } } public void run() { try { startMethod.invoke(null, new Object[] { argv } ); } catch (final Exception e) { System.err.println("Failed to start executable jar file: " + e); } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleClassPath.java0000644000175000017500000004036112346513666031050 0ustar felixfelix/* * Copyright (c) 2009-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.Vector; import org.knopflerfish.framework.Util.HeaderEntry; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.Version; import org.osgi.framework.VersionRange; /** * Bundle Class Path handler. * * @author Jan Stein */ public class BundleClassPath { /** * Framework context. */ final private FrameworkContext fwCtx; /** * Archives that we load code from. */ private final ArrayList archives = new ArrayList(4); /** * */ private Map nativeLibs; /** * */ private final Debug debug; /** * */ private final long bid; /** * Create class loader for specified bundle. * * @throws BundleException if native code resolve failed. */ BundleClassPath(BundleArchive ba, List frags, FrameworkContext fwCtx) throws BundleException { this.fwCtx = fwCtx; debug = fwCtx.debug; bid = ba.getBundleId(); checkBundleArchive(ba, frags); if (frags != null) { for (final BundleGeneration bundleGeneration : frags) { checkBundleArchive(bundleGeneration.archive, null); } } resolveNativeCode(ba, false); if (frags != null) { for (final BundleGeneration bundleGeneration : frags) { resolveNativeCode(bundleGeneration.archive, true); } } } /** * */ BundleClassPath(BundleArchive ba, FrameworkContext fwCtx) { this.fwCtx = fwCtx; debug = fwCtx.debug; bid = ba.getBundleId(); checkBundleArchive(ba, null); } /** * @throws BundleException * */ void attachFragment(BundleGeneration gen) throws BundleException { checkBundleArchive(gen.archive, null); resolveNativeCode(gen.archive, true); } /** * Check if named entry exist in bundle class path. Leading '/' is stripped. * * @param component Entry to get reference to. * @param onlyFirst End search when we find first entry if this is true. * @return Vector or entry numbers, or null if it doesn't exist. */ Vector componentExists(String component, boolean onlyFirst, boolean dirs) { Vector v = null; if (component.startsWith("/")) { component = component.substring(1); } if (debug.classLoader) { debug.println(this + "compentExists: " + component); } if (0 == component.length()) { // The special case asking for "/" if (onlyFirst) { v = new Vector(1); v.addElement(archives.get(0)); if (debug.classLoader) { debug.println(this + "compentExists added first top in classpath."); } } else { v = new Vector(archives); if (debug.classLoader) { debug.println(this + "compentExists added all tops in classpath."); } } } else { for (final FileArchive fa : archives) { if (fa.exists(component, dirs)) { if (v == null) { v = new Vector(); } v.addElement(fa); if (debug.classLoader) { debug.println(this + "compentExists added: " + fa); } if (onlyFirst) { break; } } } } return v; } /** * Get an specific InputStream to named entry inside a bundle. Leading '/' is * stripped. * * @param component Entry to get reference to. * @param ix index of sub archives. A positive number is the classpath entry * index. 0 means look in the main bundle. * @return InputStream to entry or null if it doesn't exist. */ InputStream getInputStream(String component, int ix) { if (component.startsWith("/")) { component = component.substring(1); } return archives.get(ix).getBundleResourceStream(component); } /** * Get native library from class path. * * @param libName Name of Jar file to get. * @return A string with the path to the native library. */ String getNativeLibrary(String libName) { if (debug.classLoader) { debug.println(this + "getNativeLibrary: lib=" + libName); } if (nativeLibs != null) { String [] keys = new String [] { System.mapLibraryName(libName), libName }; FileArchive fa = null; String key = null; for (String k : keys) { key = k; if (debug.classLoader) { debug.println(this + "getNativeLibrary: try, " + key); } fa = nativeLibs.get(key); if (fa == null) { // Try other non-default lib-extensions final String libExtensions = fwCtx.props .getProperty(Constants.FRAMEWORK_LIBRARY_EXTENSIONS); final int pos = key.lastIndexOf("."); if (libExtensions.length() > 0 && pos > -1) { final String baseKey = key.substring(0, pos + 1); final String[] exts = Util.splitwords(libExtensions, ", \t"); for (final String ext : exts) { key = baseKey + ext; if (debug.classLoader) { debug.println(this + "getNativeLibrary: try, " + key); } fa = nativeLibs.get(key); if (fa != null) { break; } } } } if (fa != null) { break; } } if (fa == null) { return null; } if (debug.classLoader) { debug.println(this + "getNativeLibrary: got, " + fa); } return fa.getNativeLibrary(key); } return null; } /** * */ @Override public String toString() { return "BundleClassPath(#" + bid + ")."; } // // Private methods // /** * */ private void checkBundleArchive(BundleArchive ba, List frags) { final String bcp = ba.getAttribute(Constants.BUNDLE_CLASSPATH); if (bcp != null) { final StringTokenizer st = new StringTokenizer(bcp, ","); while (st.hasMoreTokens()) { final String path = st.nextToken().trim(); FileArchive a = ba.getFileArchive(path); if (a == null && frags != null) { for (final BundleGeneration bundleGeneration : frags) { a = bundleGeneration.archive.getFileArchive(path); if (a != null) { break; } } } if (a != null) { archives.add(a); if (debug.classLoader) { debug.println(this + "- Added path entry: " + a); } } else { fwCtx.frameworkWarning(ba.getBundleGeneration().bundle, new IllegalArgumentException(Constants.BUNDLE_CLASSPATH + " entry " + path + " not found in bundle")); if (debug.classLoader) { debug.println(this + "- Failed to find class path entry: " + path); } } } } else { archives.add(ba.getFileArchive(".")); } } /** * Resolve native code libraries. * * @throws BundleException if native code resolve failed. */ private void resolveNativeCode(BundleArchive ba, boolean isFrag) throws BundleException { final String bnc = ba.getAttribute(Constants.BUNDLE_NATIVECODE); if (bnc != null) { final ArrayList proc = new ArrayList(3); final String procP = fwCtx.props.getProperty(Constants.FRAMEWORK_PROCESSOR).toLowerCase(); proc.add(procP); final String procS = System.getProperty("os.arch").toLowerCase(); if (!procP.equals(procS)) { proc.add(procS); } // Handle deprecated value "arm" if (procP.startsWith("arm_")) { proc.add("arm"); } for (int i = 0; i < Alias.processorAliases.length; i++) { if (procP.equalsIgnoreCase(Alias.processorAliases[i][0])) { for (int j = 1; j < Alias.processorAliases[i].length; j++) { if (!procS.equals(Alias.processorAliases[i][j])) { proc.add(Alias.processorAliases[i][j]); } } break; } } final ArrayList os = new ArrayList(); final String osP = fwCtx.props.getProperty(Constants.FRAMEWORK_OS_NAME).toLowerCase(); os.add(osP); final String osS = System.getProperty("os.name").toLowerCase(); if (!osS.equals(osP)) { os.add(osS); } for (int i = 0; i < Alias.osNameAliases.length; i++) { if (osP.equalsIgnoreCase(Alias.osNameAliases[i][0])) { for (int j = 1; j < Alias.osNameAliases[i].length; j++) { if (!osS.equals(Alias.osNameAliases[i][j])) { os.add(Alias.osNameAliases[i][j]); } } break; } } final Version osVer = new Version(fwCtx.props.getProperty(Constants.FRAMEWORK_OS_VERSION)); final String osLang = fwCtx.props.getProperty(Constants.FRAMEWORK_LANGUAGE); boolean optional = false; List best = null; VersionRange bestVer = null; boolean bestLang = false; final List hes = Util .parseManifestHeader(Constants.BUNDLE_NATIVECODE, bnc, false, false, false); for (final Iterator heIt = hes.iterator(); heIt.hasNext();) { final HeaderEntry he = heIt.next(); VersionRange matchVer = null; boolean matchLang = false; final List keys = he.getKeys(); if (keys.size() == 1 && "*".equals(keys.get(0)) && !heIt.hasNext()) { optional = true; break; } @SuppressWarnings("unchecked") final List pl = (List) he.getAttributes().get(Constants.BUNDLE_NATIVECODE_PROCESSOR); if (pl != null) { if (!containsIgnoreCase(proc, pl)) { continue; } } else { // NYI! Handle null continue; } @SuppressWarnings("unchecked") final List ol = (List) he.getAttributes().get(Constants.BUNDLE_NATIVECODE_OSNAME); if (ol != null) { if (!containsIgnoreCase(os, ol)) { continue; } } else { // NYI! Handle null continue; } @SuppressWarnings("unchecked") final List ver = (List) he.getAttributes().get(Constants.BUNDLE_NATIVECODE_OSVERSION); if (ver != null) { boolean okVer = false; for (final String string : ver) { // TODO! Handle format Exception matchVer = new VersionRange(string); if (matchVer.includes(osVer)) { okVer = true; break; } } if (!okVer) { continue; } } @SuppressWarnings("unchecked") final List lang = (List) he.getAttributes().get(Constants.BUNDLE_NATIVECODE_LANGUAGE); if (lang != null) { for (final String string : lang) { if (osLang.equalsIgnoreCase(string)) { // Found specified language version, search no more matchLang = true; break; } } if (!matchLang) { continue; } } @SuppressWarnings("unchecked") final List sf = (List) he.getAttributes().get(Constants.SELECTION_FILTER_ATTRIBUTE); if (sf != null) { final String sfs = sf.get(0); if (sf.size() == 1) { try { if (!(FrameworkUtil.createFilter(sfs)).match(fwCtx.props.getProperties())) { continue; } } catch (final InvalidSyntaxException ise) { throw new BundleException("Bundle#" + bid + ", Invalid syntax for native code selection filter: " + sfs, BundleException.NATIVECODE_ERROR, ise); } } else { throw new BundleException("Bundle#" + bid + ", Invalid character after native code selection filter: " + sfs, BundleException.NATIVECODE_ERROR); } } // Compare to previous best if (best != null) { boolean verEqual = false; if (bestVer != null) { if (matchVer == null) { continue; } final int d = bestVer.getLeft().compareTo(matchVer.getLeft()); if (d == 0) { verEqual = true; } else if (d > 0) { continue; } } else if (matchVer == null) { verEqual = true; } if (verEqual && (!matchLang || bestLang)) { continue; } } best = keys; bestVer = matchVer; bestLang = matchLang; } if (best == null) { if (optional) { return; } else { throw new BundleException("Bundle#" + bid + ", no matching native code libraries found for os=" + os + " version=" + osVer + ", processor=" + proc + " and language=" + osLang + ".", BundleException.NATIVECODE_ERROR); } } nativeLibs = new HashMap(); bloop: for (final String name : best) { for (final FileArchive fa : archives) { if (!isFrag || fa.getBundleGeneration().archive == ba) { final String key = fa.checkNativeLibrary(name); if (key != null) { nativeLibs.put(key, fa); if (debug.classLoader) { debug.println(this + "- Registered native library: " + key + " -> " + fa); } continue bloop; } } } throw new BundleException("Bundle#" + bid + ", failed to resolve native code: " + name, BundleException.NATIVECODE_ERROR); } } else { // No native code in this bundle nativeLibs = null; } } /** * Check if a string exists in a list. Ignore case when comparing. */ private boolean containsIgnoreCase(List fl, List l) { for (final String string : l) { final String s = string.toLowerCase(); for (final String string2 : fl) { if (Util.filterMatch(string2, s)) { return true; } } } return false; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Debug.java0000644000175000017500000002313112346513666027056 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.security.AccessController; import java.security.PrivilegedAction; import org.osgi.framework.BundleException; /** * Variables that controls debugging of the framework code. * * @author Jan Stein */ public class Debug { /** * Thread local storage to prevent recursive debug message * in permission checks */ private ThreadLocal insideDebug; /** * Report Automanifest handling */ public static String AUTOMANIFEST_PROP = "org.knopflerfish.framework.debug.automanifest"; boolean automanifest; /** * When security is enabled, print information about resource * lookups that are rejected due to missing permissions for the * calling bundle. */ public static String BUNDLE_RESOURCE_PROP = "org.knopflerfish.framework.debug.bundle_resource"; boolean bundle_resource; /** * Report certificate matching */ public static String CERTIFICATES_PROP = "org.knopflerfish.framework.debug.certificates"; public boolean certificates; /** * Report whenever the bundle classloader does something. */ public static String CLASSLOADER_PROP = "org.knopflerfish.framework.debug.classloader"; boolean classLoader; /** * Report error handling events. */ public static String ERRORS_PROP = "org.knopflerfish.framework.debug.errors"; boolean errors; /** * Report framework create, init, start, stop */ public static String FRAMEWORK_PROP = "org.knopflerfish.framework.debug.framework"; boolean framework; /** * Report hooks handling */ public static String HOOKS_PROP = "org.knopflerfish.framework.debug.hooks"; boolean hooks; /** * Report triggering of lazy activation */ public static String LAZY_ACTIVATION_PROP = "org.knopflerfish.framework.debug.lazy_activation"; boolean lazy_activation; /** * Report LDAP handling */ public static String LDAP_PROP = "org.knopflerfish.framework.debug.ldap"; boolean ldap; /** * Report resolver handling events. */ public static String RESOLVER_PROP = "org.knopflerfish.framework.debug.resolver"; boolean resolver; /** * Report Class patching handling */ public static String PATCH_PROP = "org.knopflerfish.framework.debug.patch"; public boolean patch; /** * Report permission handling */ public static String PERMISSIONS_PROP = "org.knopflerfish.framework.debug.permissions"; public boolean permissions; /** * When security is enabled, print information about service * reference lookups that are rejected due to missing permissions * for calling bundle. */ public static String SERVICE_REFERENCE_PROP = "org.knopflerfish.framework.debug.service_reference"; boolean service_reference; /** * Report startlevel. */ public static String STARTLEVEL_PROP = "org.knopflerfish.framework.debug.startlevel"; boolean startlevel; /** * Report url */ public static String URL_PROP = "org.knopflerfish.framework.debug.url"; boolean url; /** * Report warning handling events. */ public static String WARNINGS_PROP = "org.knopflerfish.framework.debug.warnings"; boolean warnings; public Debug(FWProps props) { props.setPropertyDefault(AUTOMANIFEST_PROP, FWProps.FALSE); props.setPropertyDefault(BUNDLE_RESOURCE_PROP, FWProps.FALSE); props.setPropertyDefault(CERTIFICATES_PROP, FWProps.FALSE); props.setPropertyDefault(CLASSLOADER_PROP, FWProps.FALSE); props.setPropertyDefault(ERRORS_PROP, FWProps.FALSE); props.setPropertyDefault(FRAMEWORK_PROP, FWProps.FALSE); props.setPropertyDefault(HOOKS_PROP, FWProps.FALSE); props.setPropertyDefault(LAZY_ACTIVATION_PROP, FWProps.FALSE); props.setPropertyDefault(RESOLVER_PROP, FWProps.FALSE); props.setPropertyDefault(PATCH_PROP, FWProps.FALSE); props.setPropertyDefault(PERMISSIONS_PROP, FWProps.FALSE); props.setPropertyDefault(SERVICE_REFERENCE_PROP, FWProps.FALSE); props.setPropertyDefault(STARTLEVEL_PROP, FWProps.FALSE); props.setPropertyDefault(URL_PROP, FWProps.FALSE); automanifest = props.getBooleanProperty(AUTOMANIFEST_PROP); bundle_resource = props.getBooleanProperty(BUNDLE_RESOURCE_PROP); certificates = props.getBooleanProperty(CERTIFICATES_PROP); classLoader = props.getBooleanProperty(CLASSLOADER_PROP); errors = props.getBooleanProperty(ERRORS_PROP); framework = props.getBooleanProperty(FRAMEWORK_PROP); hooks = props.getBooleanProperty(HOOKS_PROP); lazy_activation = props.getBooleanProperty(LAZY_ACTIVATION_PROP); resolver = props.getBooleanProperty(RESOLVER_PROP); patch = props.getBooleanProperty(PATCH_PROP); permissions = props.getBooleanProperty(PERMISSIONS_PROP); service_reference = props.getBooleanProperty(SERVICE_REFERENCE_PROP); startlevel = props.getBooleanProperty(STARTLEVEL_PROP); url = props.getBooleanProperty(URL_PROP); warnings = props.getBooleanProperty(WARNINGS_PROP); } /** * Check if we should use doPriviledged */ private boolean useDoPrivileged() { if (System.getSecurityManager() != null) { if (insideDebug == null) { insideDebug = new ThreadLocal() { @Override protected synchronized Boolean initialValue() { return new Boolean(false); } }; } return true; } return false; } /** * Are we already inside a debug print? */ private void inside(boolean b) { insideDebug.set(new Boolean(b)); } /** * Are we already inside a debug print? */ private boolean isInside() { return (insideDebug.get()).booleanValue(); } /** * The actual println implementation. * * @param str the message to print. */ private void println0(final String str) { System.err.println("## DEBUG: " + str); } /** * Common {@code println()} method for debug messages. * * @param str the message to print. */ public void println(final String str) { if(useDoPrivileged()) { // The call to this method can be made from a the framework on // behalf of a bundle that have no permissions at all assigned // to it. // // Use doPrivileged() here to protect the Framework from // PrintStream implementations that does not wrap calls needing // permissions in their own doPrivileged(). if (!isInside()) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { inside(true); println0(str); inside(false); return null; } }); } } else { println0(str); } } /** * The actual printStackTrace() implementation. * * @param str the message to print. * @param t the throwable to print a stack trace for. */ private void printStackTrace0(final String str, final Throwable t) { System.err.println("## DEBUG: " + str); t.printStackTrace(); if (t instanceof BundleException) { final Throwable n = ((BundleException)t).getNestedException(); if (n != null) { System.err.println("Nested bundle exception:"); n.printStackTrace(); } } } /** * Common printStackTrace method for debug messages. * * @param str the message to print. * @param t the throwable to print a stack trace for. */ public void printStackTrace(final String str, final Throwable t) { if(useDoPrivileged()) { // The call to this method can be made from a the framework on // behalf of a bundle that have no permissions at all assigned // to it. // // Use doPrivileged() here to protect the Framework from // PrintStream implementations that does not wrap calls needing // permissions in their own doPrivileged(). if (!isInside()) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { inside(true); printStackTrace0(str,t); inside(false); return null; } }); } } else { printStackTrace0(str,t); } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Fragment.java0000644000175000017500000002122012346513664027566 0ustar felixfelix/* * Copyright (c) 2010-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Vector; import org.knopflerfish.framework.Util.HeaderEntry; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.VersionRange; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; /** * Fragment information */ class Fragment implements BundleRequirement { final BundleGeneration gen; final String hostName; final String extension; final VersionRange versionRange; final Map attributes; final Map directives; private final Vector hosts = new Vector(2); /** * @param gen * The bundle generation of this fragment. * @param headerEntry * the fragment-host manifest header describing this fragment. */ Fragment(final BundleGeneration gen, final HeaderEntry headerEntry) { this.gen = gen; this.hostName = headerEntry.getKey(); if (gen.archive.getAttribute(Constants.BUNDLE_ACTIVATOR) != null) { throw new IllegalArgumentException("A fragment bundle can not have a Bundle-Activator."); } final Mapdirs = headerEntry.getDirectives(); final String extension = dirs.get(Constants.EXTENSION_DIRECTIVE); if (Constants.EXTENSION_FRAMEWORK.equals(extension) || Constants.EXTENSION_BOOTCLASSPATH.equals(extension)) { // an extension bundle must target the system bundle. if (!Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(hostName) && !BundleGeneration.KNOPFLERFISH_SYMBOLICNAME.equals(hostName)) { throw new IllegalArgumentException("An extension bundle must target " + "the system bundle(" + Constants.SYSTEM_BUNDLE_SYMBOLICNAME + " or " + BundleGeneration.KNOPFLERFISH_SYMBOLICNAME + ")"); } if (gen.archive.getAttribute(Constants.IMPORT_PACKAGE) != null || gen.archive.getAttribute(Constants.REQUIRE_BUNDLE) != null || gen.archive.getAttribute(Constants.BUNDLE_NATIVECODE) != null || gen.archive.getAttribute(Constants.DYNAMICIMPORT_PACKAGE) != null || gen.archive.getAttribute(Constants.BUNDLE_ACTIVATOR) != null) { throw new IllegalArgumentException("An extension bundle cannot specify: " + Constants.IMPORT_PACKAGE + ", " + Constants.REQUIRE_BUNDLE + ", " + Constants.BUNDLE_NATIVECODE + ", " + Constants.DYNAMICIMPORT_PACKAGE + " or " + Constants.BUNDLE_ACTIVATOR); } if (!gen.bundle.fwCtx.props.getBooleanProperty(Constants.SUPPORTS_FRAMEWORK_EXTENSION) && Constants.EXTENSION_FRAMEWORK.equals(extension)) { throw new UnsupportedOperationException( "Framework extension bundles are not supported " + "by this framework. Consult the documentation"); } if (!gen.bundle.fwCtx.props.getBooleanProperty(Constants.SUPPORTS_BOOTCLASSPATH_EXTENSION) && Constants.EXTENSION_BOOTCLASSPATH.equals(extension)) { throw new UnsupportedOperationException( "Bootclasspath extension bundles are not supported " + "by this framework. Consult the documentation"); } } else { if (extension != null) { throw new IllegalArgumentException("Did not recognize directive " + Constants.EXTENSION_DIRECTIVE + ":=" + extension + "."); } } this.extension = extension; final String range = (String) headerEntry.getAttributes() .remove(Constants.BUNDLE_VERSION_ATTRIBUTE); this.versionRange = range == null ? null : new VersionRange(range); this.attributes = headerEntry.getAttributes(); final Filter filter = toFilter(); if (null!=filter) { dirs.put(Constants.FILTER_DIRECTIVE, filter.toString()); } this.directives = Collections.unmodifiableMap(dirs); } void addHost(BundleGeneration host) { hosts.add(host); } void removeHost(BundleGeneration host) { if (host == null) { hosts.clear(); } else { hosts.remove(host); } } boolean isHost(BundleGeneration host) { return hosts.contains(host); } @SuppressWarnings("unchecked") Vector getHosts() { return (Vector)hosts.clone(); } boolean hasHosts() { return !hosts.isEmpty(); } boolean isTarget(BundleGeneration bg) { return hostName.equals(bg.symbolicName) && (versionRange == null || versionRange.includes(bg.version)) && bg.bsnAttrMatch(attributes); } List targets() { final List lbg = gen.bundle.fwCtx.bundles.getBundles(hostName, versionRange); for (Iterator i = lbg.iterator(); i.hasNext();) { final BundleGeneration tbg = i.next(); if (tbg.attachPolicy.equals(Constants.FRAGMENT_ATTACHMENT_NEVER) || !isTarget(tbg)) { i.remove(); } } return lbg; } @Override public String getNamespace() { return BundleRevision.HOST_NAMESPACE; } @Override public Map getDirectives() { return directives; } private Filter toFilter() { final StringBuffer sb = new StringBuffer(80); boolean multipleConditions = false; sb.append('('); sb.append(BundleRevision.HOST_NAMESPACE); sb.append('='); if (Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(hostName)) { sb.append(BundleGeneration.KNOPFLERFISH_SYMBOLICNAME); } else { sb.append(hostName); } sb.append(')'); if (versionRange != null) { sb.append(versionRange.toFilterString(Constants.BUNDLE_VERSION_ATTRIBUTE)); multipleConditions = true; } for (final Entry entry : attributes.entrySet()) { sb.append('('); sb.append(entry.getKey()); sb.append('='); sb.append(entry.getValue().toString()); sb.append(')'); multipleConditions |= true; } if (multipleConditions) { sb.insert(0, "(&"); sb.append(')'); } try { return FrameworkUtil.createFilter(sb.toString()); } catch (final InvalidSyntaxException _ise) { // Should not happen... System.err.println("createFilter: '" +sb.toString() +"': " +_ise.getMessage()); return null; } } @SuppressWarnings("unchecked") @Override public Map getAttributes() { return Collections.EMPTY_MAP; } @Override public BundleRevision getRevision() { return gen.bundleRevision; } @Override public BundleRevision getResource() { return gen.bundleRevision; } @Override public boolean matches(BundleCapability capability) { if (BundleRevision.HOST_NAMESPACE.equals(capability.getNamespace())) { return toFilter().matches(capability.getAttributes()); } return false; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleRequirementImpl.java0000644000175000017500000002152012346513666032304 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Arrays; import java.util.Collections; import java.util.Map; import org.knopflerfish.framework.Util.HeaderEntry; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.Version; import org.osgi.framework.namespace.ExecutionEnvironmentNamespace; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; public class BundleRequirementImpl implements BundleRequirement { private final BundleGeneration gen; private final String nameSpace; private final Map attributes; private final Map directives; private final Filter filter; private BundleWireImpl wire = null; /** * Creates a {@link BundleRequirement} from one entry in the parsed * "Require-Capability" manifest header. * * @param gen * the owning bundle revision. * @param he * the parsed entry from the "Require-Capability" manifest header. */ BundleRequirementImpl(final BundleGeneration gen, final HeaderEntry he) { this.gen = gen; nameSpace = he.getKey(); for (final String ns : Arrays .asList(new String[] { BundleRevision.BUNDLE_NAMESPACE, BundleRevision.HOST_NAMESPACE, BundleRevision.PACKAGE_NAMESPACE })) { if (ns.equals(nameSpace)) { throw new IllegalArgumentException("Capability with name-space '" + ns + "' must not be required in the " + Constants.REQUIRE_CAPABILITY + " manifest header."); } } final String filterStr = he.getDirectives().remove("filter"); if (null!=filterStr && filterStr.length()>0) { try { filter = FrameworkUtil.createFilter(filterStr); he.getDirectives().put("filter", filter.toString()); } catch (final InvalidSyntaxException ise) { final String msg = "Invalid filter '" + filterStr + "' in " + Constants.REQUIRE_CAPABILITY + " for name-space " + nameSpace + ": " + ise; throw (IllegalArgumentException) new IllegalArgumentException(msg).initCause(ise); } } else { filter = null; } directives = Collections.unmodifiableMap(he.getDirectives()); attributes = Collections.unmodifiableMap(he.getAttributes()); } /** * Creates a {@link BundleRequirement} from a * "Bundle-RequiredExecutionEnvironment" manifest header. * * @param gen * the owning bundle revision. * @param ee * the entry from the "Bundle-RequiredExecutionEnvironment" manifest header. */ @SuppressWarnings("unchecked") BundleRequirementImpl(final BundleGeneration gen, final String ee) { this.gen = gen; nameSpace = ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE; final StringBuffer filterStrB = new StringBuffer(); final String[] l = Util.splitwords(ee, ","); if (l.length > 1) { filterStrB.append("(|"); } for (final String e : l) { final String[] es = Util.splitwords(e, "-"); try { if (es.length == 2) { final int si = es[1].indexOf('/'); new Version(si == -1 ? es[1] : es[1].substring(0, si)); filterStrB.append("(&(").append(nameSpace).append('='); if (es[0].equalsIgnoreCase("J2SE")) { es[0]="JavaSE"; } filterStrB.append(es[0]); if (si != -1) { filterStrB.append(es[1].substring(si)); } filterStrB.append(")(version=").append(es[1]).append("))"); continue; } else if (es.length > 2) { final StringBuffer esStrB = new StringBuffer(es[0]); Version v = null; for (int i = 1; i < es.length; i++) { if (Character.isDigit(es[i].charAt(0))) { if (v == null) { final int si = es[i].indexOf('/'); v = new Version(si == -1 ? es[i] : es[i].substring(0, si)); if (si != -1) { esStrB.append(es[1].substring(si)); } else if (i != es.length - 1) { throw new IllegalArgumentException("Version not at end"); } } else { if (v.equals(new Version(es[i])) && i == es.length - 1) { break; } throw new IllegalArgumentException("Version mismatch"); } } else { esStrB.append('-').append(es[i]); } } if (v != null) { filterStrB.append("(&(").append(nameSpace).append('='); filterStrB.append(esStrB).append(")(version="); filterStrB.append(v).append("))"); continue; } } } catch (IllegalArgumentException _ignore) { } filterStrB.append('(').append(nameSpace).append('='); filterStrB.append(e).append(')'); } if (l.length > 1) { filterStrB.append(')'); } try { filter = FrameworkUtil.createFilter(filterStrB.toString()); } catch (final InvalidSyntaxException ise) { throw new RuntimeException("Internal error"); } directives = Collections.singletonMap("filter", filter.toString()); attributes = Collections.EMPTY_MAP; } @Override public String getNamespace() { return nameSpace; } @Override public Map getDirectives() { return directives; } @Override public Map getAttributes() { return attributes; } @Override public BundleRevision getRevision() { return gen.bundleRevision; } @Override public BundleRevision getResource() { return gen.bundleRevision; } @Override public boolean matches(BundleCapability capability) { if (nameSpace.equals(capability.getNamespace())) { return null==filter ? true : filter.matches(capability.getAttributes()); } return false; } @Override public String toString() { final StringBuffer sb = new StringBuffer(40); sb.append("[") .append(BundleRequirement.class.getName()) .append(": ") .append(nameSpace) .append(" directives: ") .append(directives.toString()) .append("]"); return sb.toString(); } BundleGeneration getBundleGeneration() { return gen; } BundleWireImpl getWire() { return wire; } void resetWire() { if (wire != null) { ((BundleCapabilityImpl)wire.getCapability()).removeWire(this.wire); this.wire = null; } } void setWire(BundleWireImpl wire) { ((BundleCapabilityImpl)wire.getCapability()).addWire(wire); this.wire = wire; } boolean isOptional() { final String resolution = directives.get(Constants.RESOLUTION_DIRECTIVE); return Constants.RESOLUTION_OPTIONAL.equals(resolution); } boolean shouldResolve() { final String effective = directives.get(Constants.EFFECTIVE_DIRECTIVE); return effective == null || effective.equals(Constants.EFFECTIVE_RESOLVE); } boolean isWired() { return wire != null; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleClassLoader.java0000644000175000017500000012611112346513666031360 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.URL; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Vector; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.osgi.framework.BundleReference; /** * Classloader for bundle JAR files. * * @author Jan Stein, Philippe Laporte, Mats-Ola Persson, Gunna Ekolin * @author Vilmos Nebehaj (Android application support) */ final public class BundleClassLoader extends ClassLoader implements BundleReference { final static int ONLY_FIRST = 1; final static int LIST = 2; final static int ONLY_RECURSE = 4; final static int RECURSE = 256; final static int LOCAL = 512; /** * Framework class loader */ final FrameworkContext fwCtx; /** * Handle to secure operations. */ final PermissionOps secure; /** * Bundle classloader protect domain. */ final ProtectionDomain protectionDomain; /** * Archive that we load code from. */ BundleArchive archive; /** * Imported and Exported java packages. */ BundlePackages bpkgs; /** * Bundle class path for this classloader. */ final private BundleClassPath classPath; // Array of bundles for which a classload is triggering activation. private static ThreadLocal> tlBundlesToActivate = new ThreadLocal>(); // android/dalvik VM stuff private static Method dexFileClassLoadDexMethod; private static Method dexFileClassLoadClassMethod; // bDalvik will be set to true if we're running on the android // dalvik VM. // package protected to enable other parts of framework to check // for dalvik VM static boolean bDalvik = false; private ArrayList dexFile = null; static { try { Class dexFileClass = null; try { dexFileClass = Class.forName("android.dalvik.DexFile"); } catch (final Exception ex) { dexFileClass = Class.forName("dalvik.system.DexFile"); } dexFileClassLoadDexMethod = dexFileClass.getMethod("loadDex", new Class[] { String.class, String.class, Integer.TYPE }); dexFileClassLoadClassMethod = dexFileClass.getMethod("loadClass", new Class[] { String.class, ClassLoader.class }); bDalvik = true; // if(debug.classLoader) { // debug.println("running on dalvik VM"); // } } catch (final Exception e) { dexFileClassLoadDexMethod = null; dexFileClassLoadClassMethod = null; } } Debug debug; /** * Create class loader for specified bundle. */ BundleClassLoader(final BundleGeneration gen) throws BundleException { // otherwise getResource will bypass OUR parent super(gen.bundle.fwCtx.parentClassLoader); fwCtx = gen.bundle.fwCtx; debug = fwCtx.debug; secure = fwCtx.perm; protectionDomain = gen.getProtectionDomain(); bpkgs = gen.bpkgs; archive = gen.archive; classPath = new BundleClassPath(archive, gen.fragments, fwCtx); fwCtx.bundleClassLoaderCreated(this); if (debug.classLoader) { debug.println(this + " Created new classloader"); } } /** * Find bundle class to load. First check if this load comes from an imported * package. Otherwise load class from our bundle. * * @see java.lang.ClassLoader#findClass */ @Override protected Class findClass(String name) throws ClassNotFoundException { if (name.startsWith("java.")) { return fwCtx.parentClassLoader.loadClass(name); } if (fwCtx.isBootDelegated(name)) { try { final Class bootDelegationCls = fwCtx.parentClassLoader.loadClass(name); if (debug.classLoader && bootDelegationCls != null) { debug.println(this + " findClass: " + name + " boot delegation: " + bootDelegationCls); } return bootDelegationCls; } catch (final ClassNotFoundException e) { } } String path; String pkg; final int pos = name.lastIndexOf('.'); if (pos != -1) { path = name.replace('.', '/'); pkg = name.substring(0, pos); } else { path = name; pkg = null; } Class res = (Class) secure.callSearchFor(this, name, pkg, path + ".class", classSearch, ONLY_FIRST, this, null); if (res != null) { return res; } if (!fwCtx.props.STRICTBOOTCLASSLOADING) { if (isBootClassContext(name)) { if (debug.classLoader) { debug.println(this + " trying parent loader for class=" + name + ", since it was loaded on the system loader itself"); } res = fwCtx.parentClassLoader.loadClass(name); if (res != null) { if (debug.classLoader) { debug.println(this + " loaded " + name + " from " + fwCtx.parentClassLoader); } } return res; } } throw new ClassNotFoundException(name); } /** * Find native library code to load. * * @see java.lang.ClassLoader#findLibrary */ @Override protected String findLibrary(String name) { final String res = secure.callFindLibrary0(this, name); if (debug.classLoader) { debug.println(this + " Find library: " + name + (res != null ? " OK" : " FAIL")); } return res; } /** * Returns an Enumeration of all the resources with the given name. * * @see java.lang.ClassLoader#findResources */ @Override protected Enumeration findResources(String name) { // Step 1 and 2 are done by getResources return getBundleResources(name, false); } /** * Finds the resource with the given name. * * @see java.lang.ClassLoader#findResource */ @Override protected URL findResource(String name) { final Enumeration res = getBundleResources(name, true); if (res != null) { return res.nextElement(); } else { return null; } } /** * Wrapper class around SecurityManager which exposes the getClassLoader() * method. */ static class SecurityManagerExposer extends SecurityManager { @Override public Class[] getClassContext() { return super.getClassContext(); } } static protected SecurityManagerExposer smex = new SecurityManagerExposer(); /** * @return true if the given class is not loaded by a bundle * class loader, false otherwise. */ private boolean isNonBundleClass(Class cls) { return (this.getClass().getClassLoader() != cls.getClassLoader()) && !ClassLoader.class.isAssignableFrom(cls) && !Class.class.equals(cls) && !Proxy.class.equals(cls); } /** * Check if the current call is made from a class loaded on the boot class * path (or rather, on a class loaded from something else than a bundle class * loader) * * @param name * The name of the class to load. */ public boolean isBootClassContext(String name) { Class[] classStack = smex.getClassContext(); if (classStack == null) { // Android 4.0 returns null // TODO: Find a cheaper and better solution try { final StackTraceElement[] classNames = new Throwable().getStackTrace(); classStack = new Class[classNames.length]; for (int i = 1; i < classNames.length; i++) classStack[i] = Class.forName(classNames[i].getClassName()); } catch (final ClassNotFoundException e) { return false; } } for (int i = 1; i < classStack.length; i++) { final Class currentCls = classStack[i]; if (isNonBundleClass(currentCls)) { final ClassLoader currentCL = currentCls.getClassLoader(); // If any of the classloaders for the caller's class is // a BundleClassLoader, we're not in a VM class context // ANDROID FIX, android-7/8 unexpectedly returns // java.lang.BootClassLoader as the ClassLoader for the // BootClassLoader Class other jvm's return null for (ClassLoader cl = currentCL; cl != null && cl != cl.getClass().getClassLoader(); cl = cl.getClass() .getClassLoader()) { if (BundleClassLoader.class.isInstance(cl)) { return false; } } return !Bundle.class.isInstance(classStack[i - 1]); } } return false; } /** * Find Class and load it. This function is abstract in PJava 1.2 so we define * it here to work as closely as it can to Java 2. Should work okey if we * don't use the Java 2 stuff. * * @param name * the name of the class * @param resolve * if true then resolve the class * @return the resulting Class object * @exception ClassNotFoundException * if the class could not be found * @see java.lang.ClassLoader#loadClass */ @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class c = findLoadedClass(name); if (c == null) { c = findClass(name); } else if (secure.getClassLoaderOf(c) == this) { // Handle bundles that are lazely started after having been // stopped. In this case the triggering classes will already // be loaded. Only consider classes loaded by this classloader final BundleImpl b = (BundleImpl) getBundle(); if (b.triggersActivationCls(name)) { if (debug.lazy_activation) { debug.println(this + " lazy activation of #" + b.id + " triggered by loadClass(" + name + ")"); } final ArrayList bundlesToActivate = tlBundlesToActivate.get(); if (null == bundlesToActivate) { // Not part of a load chain; activate bundle here. if (debug.lazy_activation) { debug.println(this + " requesting lazy activation of #" + b.id); } try { secure.callFinalizeActivation(b); } catch (final BundleException e) { fwCtx.frameworkError(b, e); } } else { // add bundle to list of bundles to activate when the // initiator class has been loaded. boolean bundlePresent = false; for (int i = 0, size = bundlesToActivate.size(); i < size; i++) { final BundleImpl tmp = bundlesToActivate.get(i); if (tmp.id == b.id) { bundlePresent = true; break; } } if (!bundlePresent) { bundlesToActivate.add(b); if (debug.lazy_activation) { debug.println(this + " added #" + b.id + " to list of bundles to be activated."); } } } } } if (resolve) { resolveClass(c); } return c; } /** * Finds the resource with the given name. This is defined a little different * in PJava 1.2 versus Java 2. So we first try to use the super() version and * if it fails we try to find it in the local bundle. * * @param name * resource name * @return an URL to resource, or null if the resource could not * be found or the caller doesn't have adequate privileges to get the * resource. * @see java.lang.ClassLoader#getResource */ @Override public URL getResource(String name) { if (debug.classLoader) { debug.println(this + " getResource: " + name); } URL res = null; if (name.startsWith("java/")) { res = fwCtx.parentClassLoader.getResource(name); if (debug.classLoader) { debug.println(this + " getResource: " + name + " file in java pkg: " + res); } return res; } if (fwCtx.isBootDelegatedResource(name)) { res = fwCtx.parentClassLoader.getResource(name); if (res != null) { if (debug.classLoader) { debug.println(this + " getResource: " + name + " boot delegation: " + res); } return res; } } res = findResource(name); if (debug.classLoader) { debug.println(this + " getResource: " + name + " bundle space: " + res); } return res; } // We would like to use the following implementation of // getResources() but that method is final in JDK 1.4 // thus we can not redefine it here. /** * Finds all the resources with the given name. A resource is some data * (images, audio, text, etc) that can be accessed by class code in a way that * is independent of the location of the code. * *

* The name of a resource is a /-separated path name that identifies * the resource. * * @param name * resource name * @return An enumeration of {@link java.net.URL URL} objects for the * resource. If no resources could be found, the enumeration will be * empty. Resources that the class loader doesn't have access to will * not be in the enumeration. * * @see java.lang.ClassLoader#getResources * @see org.osgi.framework.Bundle#getResources(String name) * */ public Enumeration getResourcesOSGi(String name) throws IOException { if (debug.classLoader) { debug.println(this + " getResources: " + name); } final int start = name.startsWith("/") ? 1 : 0; if (name.substring(start).startsWith("java/")) { return fwCtx.parentClassLoader.getResources(name); } Enumeration res = null; if (fwCtx.isBootDelegatedResource(name)) { res = fwCtx.parentClassLoader.getResources(name); } if (res == null || !res.hasMoreElements()) { res = findResources(name); } return res; } /** * Finds the resource with the given name and returns the InputStream. The * method is overridden to make sure it does the right thing. * * @param name * resource name * @return an InputStream to resource, or null if the resource * could not be found or the caller doesn't have adequate privileges * to get the resource. * @see java.lang.ClassLoader#getResourceAsStream */ @Override public InputStream getResourceAsStream(String name) { try { final URL url = getResource(name); if (url != null) { return url.openStream(); } } catch (final IOException ignore) { } return null; } /** * Return a string representing this object * * @return A message string. */ @Override public String toString() { return "BundleClassLoader(" // +"fw=" +bpkgs.bundle.fwCtx.hashCode() + "id=" + bpkgs.bg.bundle.id + ",gen=" + bpkgs.bg.generation + ")"; } // Implements BundleReference public Bundle getBundle() { return bpkgs.bg.bundle; } // // BundleClassLoader specific // /** * Close down this classloader. We don't give out any new classes. Perhaps we * should block all classloads. */ void close() { archive = null; fwCtx.bundleClassLoaderClosed(this); if (debug.classLoader) { debug.println(this + " Cleared archives"); } } /** * Get all the resources with the given name in this bundle. * */ Enumeration getBundleResources(String name, boolean onlyFirst) { // Removed this check pending outcome of OSGi bug 1489. // if (secure.okResourceAdminPerm(bpkgs.bundle)) { if (debug.classLoader) { debug.println(this + " Find bundle resource" + (onlyFirst ? "" : "s") + ": " + name); } String pkg = null; final int pos = name.lastIndexOf('/'); if (pos > 0) { final int start = name.startsWith("/") ? 1 : 0; pkg = name.substring(start, pos).replace('/', '.'); } else { pkg = null; } @SuppressWarnings("unchecked") final Enumeration res = (Enumeration) secure.callSearchFor(this, null, pkg, name, resourceSearch, onlyFirst ? ONLY_FIRST : 0, this, null); return res; // } else { // return null; // } } /** * Get bundle package handler. * */ BundlePackages getBpkgs() { return bpkgs; } /** * Attach fragment to classloader. * * @throws BundleException * */ void attachFragment(BundleGeneration gen) throws BundleException { if (debug.classLoader) { debug.println(this + " fragment attached update classpath"); } classPath.attachFragment(gen); } Collection listResources(String path, String filePattern, int options) { if (debug.classLoader) { debug.println(this + " List bundle resources: " + path + ", pattern=" + filePattern); } if (path.startsWith("/")) { path = path.substring(1); } if (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } // TODO handle . within path String pkg = path.replace('/', '.'); @SuppressWarnings("unchecked") final Set res = (Set) secure.callSearchFor(this, filePattern, pkg, path, listSearch, (options << 8) | LIST, this, null); return res; } // // Private // /** * Searches for and loads classes and resources according to OSGi search * order. When lazy activation of bundles are used this method will detect and * perform the activation. The actual searching and loading is done in * {@link #searchFor0()} * * @param name * Name of class or pattern we are looking for, null if we look for a * resource * @param pkg * Package name for item * @param path * File path to item searched ("/" separated) * @param action * Action to be taken when item is found * @param options * Options controlling what should be included in search result. * * @return Object returned from action class. */ Object searchFor(String name, String pkg, String path, SearchAction action, int options, BundleClassLoader requestor, HashSet visited) { try { final BundleImpl b = (BundleImpl) getBundle(); boolean initiator = false; ArrayList bundlesToActivate = null; if (action == classSearch) { boolean bundlePresent = false; bundlesToActivate = tlBundlesToActivate.get(); initiator = bundlesToActivate == null; if (initiator) { bundlesToActivate = new ArrayList(); tlBundlesToActivate.set(bundlesToActivate); } else { bundlePresent = bundlesToActivate.contains(b); } if (!bundlePresent && b.triggersActivationPkg(pkg)) { bundlesToActivate.add(b); if (debug.lazy_activation) { debug.println(this + " lazy activation of #" + b.id + " triggered by searchFor(" + name + ")"); } } } final Object res = searchFor0(name, pkg, path, action, options, requestor, visited); if (initiator) { tlBundlesToActivate.set(null); for (int i = bundlesToActivate.size() - 1; i >= 0; i--) { final BundleImpl tmp = bundlesToActivate.get(i); if (debug.lazy_activation) { debug.println(this + " requesting lazy activation of #" + tmp.id); } try { tmp.finalizeActivation(); } catch (final BundleException e) { fwCtx.frameworkError(tmp, e); } } } return res; } catch (final Error te) { tlBundlesToActivate.set(null); throw te; } } /** * Search for classloader to use according to OSGi search order. * * 3 If the class or resource is in a package that is imported using * Import-Package or was imported dynamically in a previous load, then the * request is delegated to the exporting bundles class loader; otherwise the * search continues with the next step. If the request is delegated to an * exporting class loader and the class or resource is not found, then the * search terminates and the request fails. * * 4 If the class or resource is in a package that is imported from one or * more other bundles using Require-Bundle, the request is delegated to the * class loaders of the other bundles, in the order in which they are * specified in this bundles manifest. If the class or resource is not found, * then the search continues with the next step. * * 5 The bundles own internal bundle class path is searched. If the class or * resource is not found, then the search continues with the next step. * * 6 Each attached fragment's internal bundle class path is searched. The * fragments are searched in ascending bundle ID order. If the class or * resource is not found, then the search continues with the next step. * * 7 If the class or resource is in a package that is exported by the bundle * or the package is imported by the bundle (using Import-Package or * Require-Bundle), then the search ends and the class or resource is not * found. * * 8 Otherwise, if the class or resource is in a package that is imported * using DynamicImport-Package, then a dynamic import of the package is now * attempted. An exporter must conform to any implied package constraints. If * an appropriate exporter is found, a wire is established so that future * loads of the package are handled in Step 3. If a dynamic wire is not * established, then the request fails. * * 9 If the dynamic import of the package is established, the request is * delegated to the exporting bundle's class loader. If the request is * delegated to an exporting class loader and the class or resource is not * found, then the search terminates and the request fails. * * @param name * Name of class or null if we look for a resource * @param pkg * Package name for item * @param path * File path to item searched ("/" separated) * @param action * Action to be taken when item is found * @param onlyFirst * Stop search when first matching item is found. * * @return Object returned from action class. */ Object searchFor0(String name, String pkg, String path, SearchAction action, int options, BundleClassLoader requestor, HashSet visited) { BundlePackages pbp; Iterator ep; // TODO, Should this be an action method if (action == classSearch && requestor != this) { final Class c = findLoadedClass(name); if (c != null) { return c; } } final boolean list = (options & LIST) != 0; final boolean local = (options & LOCAL) != 0; final boolean recurse = (options & RECURSE) != 0; Object answer = null; if (debug.classLoader) { debug.println(this + " Search for: " + path); } /* 3 */ if (pkg != null) { pbp = bpkgs.getProviderBundlePackages(pkg); if (pbp != null) { final ClassLoader cl = pbp.getClassLoader(); if (!local || cl == this) { if (isSystemBundle(pbp.bg.bundle)) { answer = frameworkSearchFor(cl, name, path, action); if (!recurse) { return answer; } } else { final BundleClassLoader bcl = (BundleClassLoader) cl; // Second check avoids a loop when a required bundle imports a // package from its requiring host that it self should // provide contents for to the requiring bundle. if (bcl != this && (visited == null || (bcl != null && !visited.contains(bcl)))) { if (bcl != null) { if (debug.classLoader) { debug.println(this + " Import search: " + path + " from #" + pbp.bg.bundle.id); } answer = secure.callSearchFor(bcl, name, pkg, path, action, options & ~RECURSE, requestor, visited); } else { if (debug.classLoader) { debug.println(this + " No import found: " + path); } } if (!recurse) { return answer; } } } } if (cl != this) { // Import checked we don't need to list any more in this directory. options |= ONLY_RECURSE; } } else if (!local) { /* 4 */ final ArrayList pl = bpkgs.getRequiredBundleGenerations(pkg); if (pl != null) { if (visited == null) { visited = new HashSet(); } visited.add(this); for (final BundleGeneration pbg : pl) { final ClassLoader cl = pbg.getClassLoader(); if (cl instanceof BundleClassLoader) { final BundleClassLoader bcl = (BundleClassLoader)cl; if (bcl != null && !visited.contains(bcl)) { if (debug.classLoader) { debug.println(this + " Required bundle search: " + path + " from #" + pbg.bundle.id); } answer = secure.callSearchFor(bcl, name, pkg, path, action, options, requestor, visited); } } else { answer = frameworkSearchFor(cl, name, path, action); } if (answer != null) { if (list || recurse) { break; } else { return answer; } } } if (debug.classLoader && answer == null) { debug.println(this + " Required bundle search: " + "Not found, continuing with local search."); } } } ep = bpkgs.getExports(pkg); } else { ep = null; } /* 5 + 6 */ if (this != requestor && ep != null) { // TODO should we block resources? if (action == classSearch) { boolean blocked = true; while (ep.hasNext()) { if (ep.next().checkFilter(name)) { blocked = false; break; } } if (blocked) { if (debug.classLoader) { debug.println(this + " Filter check blocked search for: " + name); } return null; } } } final Vector av = classPath.componentExists(path, (options & ONLY_FIRST) != 0, (options & LIST) != 0); if (av != null || recurse) { try { Object res = action.get(av, path, name, pkg, options, requestor, this); if (answer != null) { if (res != null) { @SuppressWarnings("unchecked") Collection ca = (Collection) answer; @SuppressWarnings("unchecked") Collection cr = (Collection) res; ca.addAll(cr); } } else { answer = res; } return answer; } catch (final ClassFormatError cfe) { // TODO: OSGI43 WeavingHook CT has some specific demands that // ClassFormatErrors are thrown that doesn't seem to be in the spec throw cfe; } catch (final IOException ioe) { fwCtx.frameworkError(bpkgs.bg.bundle, ioe); return null; } } /* 7 */ if (ep != null || (options & LIST) != 0) { return null; } /* 8 */ if (pkg != null) { pbp = bpkgs.getDynamicProviderBundlePackages(pkg); if (pbp != null) { /* 9 */ if (isSystemBundle(pbp.bg.bundle)) { try { return fwCtx.systemBundle.getClassLoader().loadClass(name); } catch (final ClassNotFoundException e) { // continue } } else { final BundleClassLoader cl = (BundleClassLoader) pbp.getClassLoader(); if (cl != null) { if (debug.classLoader) { debug.println(this + " Dynamic import search: " + path + " from #" + pbp.bg.bundle.id); } return secure.callSearchFor(cl, name, pkg, path, action, options, requestor, visited); } } } if (debug.classLoader) { debug.println(this + " No dynamic import: " + path); } } return null; } /** * Get resources/classes from the framework. * Rewrite this since this solution will leak * resources that aren't bootdelegated. * * @param cl * @param name * @param path * @param action * @return */ private Object frameworkSearchFor(final ClassLoader cl, String name, String path, SearchAction action) { if (action == classSearch) { try { return cl.loadClass(name); } catch (final ClassNotFoundException e) { } } else if (action == resourceSearch) { try { return cl.getResources(path); } catch (IOException e) { } } else if (action == listSearch) { // TODO, listSearch throw new UnsupportedOperationException("listResources not available on system bundle"); } return null; } private static boolean isSystemBundle(BundleImpl bundle) { return bundle == bundle.fwCtx.systemBundle; } /** * Search action */ interface SearchAction { public abstract Object get(Vector items, String path, String name, String pkg, int options, BundleClassLoader requestor, BundleClassLoader cl) throws IOException; } /** * Search action for class searching */ static final SearchAction classSearch = new SearchAction() { public Object get(Vector items, String path, String name, String pkg, int options, BundleClassLoader requestor, BundleClassLoader cl) throws IOException { byte[] bytes = items.get(0).getClassBytes(path); if (bytes != null) { if (cl.debug.classLoader) { cl.debug.println("classLoader(#" + cl.bpkgs.bg.bundle.id + ") - load class: " + name); } synchronized (cl) { Class c = cl.findLoadedClass(name); if (c == null) { if (pkg != null) { if (cl.getPackage(pkg) == null) { cl.definePackage(pkg, null, null, null, null, null, null, null); } } // Use dalvik DexFile class loading when running // on the dalvik VM if (bDalvik) { try { c = cl.getDexFileClass(name); } catch (final Exception e) { throw new IOException("Failed to load dex class '" + name + "', " + e); } } if (c == null) { WeavingHooks.WovenClassImpl wc = null; if (cl != null && cl.bpkgs != null && cl.bpkgs.bg != null && cl.bpkgs.bg.bundle != null) { wc = new WeavingHooks.WovenClassImpl(cl.bpkgs.bg.bundle, name, bytes); try { cl.fwCtx.weavingHooks.callHooks(wc); if (wc.hasAdditionalDynamicImports()) { cl.bpkgs.parseDynamicImports(wc.getDynamicImportsAsString()); } bytes = wc.getBytes(); } catch (final ClassFormatError cfe) { throw cfe; } catch (final Throwable t) { final ClassFormatError cfe = new ClassFormatError( "Failed to call WeavingHooks for " + name); cfe.initCause(t); throw cfe; } } if (cl.protectionDomain == null) { // Kaffe can't handle null protectiondomain c = cl.defineClass(name, bytes, 0, bytes.length); } else { c = cl.defineClass(name, bytes, 0, bytes.length, cl.protectionDomain); } if (wc != null) { wc.setDefinedClass(c); } } } return c; } } return null; } }; private void walkAndAddJars(List dexlist, String path) throws Exception { final File root = new File(path); final File[] list = root.listFiles(); for (final File f : list) { if (f.isDirectory()) { walkAndAddJars(dexlist, f.getAbsolutePath()); } else { if (f.getAbsolutePath().endsWith(".jar")) { if (debug.classLoader) { debug.println("creating DexFile from " + f.getAbsolutePath()); } final Object dex = dexFileClassLoadDexMethod.invoke(null, new Object[] { f.getAbsolutePath(), f.getAbsolutePath() + ".dexopt", new Integer(0) }); dexlist.add(dex); } } } } /** * Load a class using the Dalvik DexFile API. *

* This relies in the bundle having a "classes.dex" in its root *

* TODO: We should create a specific bundle storage module for DEX files. *

* * To create such a bundle, do *

    *
  1. dx --dex --output=classes.dex bundle.jar *
  2. aapt add bundle.jar classes.dex *
*/ private Class getDexFileClass(String name) throws Exception { if (debug.classLoader) { debug.println("loading dex class " + name); } if (dexFile == null) { dexFile = new ArrayList(); final File f = new File(archive.getJarLocation()); if (!f.isDirectory()) { if (debug.classLoader) { debug.println("creating DexFile from " + f); } final Object dex = dexFileClassLoadDexMethod.invoke(null, new Object[] { f.getAbsolutePath(), f.getAbsolutePath() + ".dexopt", new Integer(0) }); dexFile.add(dex); if (debug.classLoader) { debug.println("created DexFile from " + f); } } else { // if it has an internal jar file then it was unpacked into a folder if (debug.classLoader) { System.err.println("creating DexFile from " + f + "/classes.dex"); } final Object dex = dexFileClassLoadDexMethod.invoke(null, new Object[] { f.getAbsolutePath() + "/classes.dex", f.getAbsolutePath() + ".dexopt", new Integer(0) }); dexFile.add(dex); if (debug.classLoader) { debug.println("created DexFile from " + f + File.pathSeparatorChar + "classes.dex"); } // check for internal jar files walkAndAddJars(dexFile, f.getAbsolutePath()); } } final String path = name.replace('.', '/'); final Iterator i = dexFile.iterator(); while (i.hasNext()) { final Object dex = i.next(); if (debug.classLoader) { debug.println("trying to load " + path + " from " + dex); } try { final Class clz = (Class) dexFileClassLoadClassMethod.invoke(dex, new Object[] { path, this }); if (clz != null) { if (debug.classLoader) { debug.println("loaded " + path + " from " + dex); } return clz; } } catch (final Exception e) { } if (debug.classLoader) { debug.println("failed to load " + path + " from " + dex); } } throw new ClassNotFoundException("could not find dex class " + path); } /** * Search action for resource searching */ static final SearchAction resourceSearch = new SearchAction() { public Object get(Vector items, String path, String name, String pkg, int options, BundleClassLoader requestor, BundleClassLoader cl) throws IOException { final Vector answer = new Vector(); for (int i = 0; i < items.size(); i++) { final FileArchive fa = items.elementAt(i); final URL url = fa.getBundleGeneration().getURL(fa.getSubId(), path); if (url != null) { if (cl.debug.classLoader) { cl.debug.println("classLoader(#" + cl.bpkgs.bg.bundle.id + ") - found: " + path + " -> " + url); } answer.addElement(url); } else { return null; } } return answer.elements(); } }; /** * Search action for listResource searching */ static final SearchAction listSearch = new SearchAction() { public Object get(Vector items, String path, String name, String pkg, int options, BundleClassLoader requestor, BundleClassLoader cl) throws IOException { Set answer = new HashSet(); boolean onlyRecurse = (options & ONLY_RECURSE) != 0; HashSet scanned = new HashSet(); for (String subPkg : cl.bpkgs.getSubProvider(pkg)) { if ((options & RECURSE) != 0) { String next = path.length() > 0 ? path + "/" + subPkg : subPkg; @SuppressWarnings("unchecked") Set subAnswer = (Set) cl.searchFor(name, next.replace('/', '.'), next, listSearch, options & ~ONLY_RECURSE, requestor, null); if (subAnswer != null) { answer.addAll(subAnswer); } } if (!onlyRecurse && (name == null || Util.filterMatch(name, subPkg))) { answer.add(path + "/" + subPkg); } scanned.add(subPkg + "/"); } if (items != null) { for (FileArchive fa : items) { for (String e : fa.listDir(path)) { if (scanned.contains(e)) { if (cl.debug.classLoader) { cl.debug.println("classLoader(#" + cl.bpkgs.bg.bundle.id + ") - list search skip: " + e); } continue; } else if (cl.debug.classLoader) { cl.debug.println("classLoader(#" + cl.bpkgs.bg.bundle.id + ") - list search check: " + e + (onlyRecurse ? " (scan)" : "")); } if (e.endsWith("/")) { e = e.substring(0, e.length() - 1); if ((options & RECURSE) != 0) { String next = path.length() > 0 ? path + "/" + e : e; @SuppressWarnings("unchecked") Set subAnswer = (Set) cl.searchFor(name, next.replace('/', '.'), next, listSearch, options & ~ONLY_RECURSE, requestor, null); if (subAnswer != null) { answer.addAll(subAnswer); } } } if (!onlyRecurse && (name == null || Util.filterMatch(name, e))) { answer.add(path + "/" + e); if (cl.debug.classLoader) { cl.debug.println("classLoader(#" + cl.bpkgs.bg.bundle.id + ") - list search match: " + e); } } } } } return answer; } }; /** * Find native library code to load. This method is called from * findLibrary(name) within a doPriviledged-block via the secure object. * */ String findLibrary0(final String name) { return classPath.getNativeLibrary(name); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Bundles.java0000644000175000017500000003316112346513666027430 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import org.osgi.framework.Bundle; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.Version; import org.osgi.framework.VersionRange; /** * Here we handle all the bundles that are installed in the framework. * Also handles load and save of bundle states to file, so that we * can restart the platform. * * @author Jan Stein, Mats-Ola Persson, Gunnar Ekolin */ public class Bundles { /** * Table of all installed bundles in this framework. * Key is bundle location. */ final private Hashtable bundles = new Hashtable(); final private HashSet zombies = new HashSet(); /** * Link to framework object. */ private FrameworkContext fwCtx; /** * Create a container for all bundles in this framework. */ Bundles(FrameworkContext fw) { fwCtx = fw; bundles.put(fw.systemBundle.location, fw.systemBundle); } void clear() { bundles.clear(); fwCtx = null; } /** * Install a new bundle. * * @param location The location to be installed */ BundleImpl install(final String location, final InputStream in, final Bundle caller) throws BundleException { checkIllegalState(); BundleImpl b; synchronized (this) { b = bundles.get(location); if (b != null) { b = (BundleImpl)b.fwCtx.bundleHooks.filterBundle(b.bundleContext, b); if(b == null) { throw new BundleException("Rejected by a bundle hook", BundleException.REJECTED_BY_HOOK); } else { return b; } } b = fwCtx.perm.callInstall0(this, location, in, caller); } return b; } BundleImpl install0(String location, InputStream in, Object checkContext, Bundle caller) throws BundleException { InputStream bin; BundleArchive ba = null; try { if (in == null) { // Do it the manual way to have a chance to // set request properties final URL url = new URL(location); final URLConnection conn = url.openConnection(); // Support for http proxy authentication //TODO put in update as well final String auth = fwCtx.props.getProperty("http.proxyAuth"); if (auth != null && !"".equals(auth)) { if ("http".equals(url.getProtocol()) || "https".equals(url.getProtocol())) { final String base64 = Util.base64Encode(auth); conn.setRequestProperty("Proxy-Authorization", "Basic " + base64); } } // Support for http basic authentication final String basicAuth = fwCtx.props.getProperty("http.basicAuth"); if (basicAuth != null && !"".equals(basicAuth)) { if ("http".equals(url.getProtocol()) || "https".equals(url.getProtocol())) { final String base64 = Util.base64Encode(basicAuth); conn.setRequestProperty("Authorization", "Basic " +base64); } } bin = conn.getInputStream(); } else { bin = in; } try { ba = fwCtx.storage.insertBundleJar(location, bin); } finally { bin.close(); } final BundleImpl res = new BundleImpl(fwCtx, ba, checkContext, caller); bundles.put(location, res); fwCtx.listeners.bundleChanged(new BundleEvent(BundleEvent.INSTALLED, res, caller)); return res; } catch (final Exception e) { if (ba != null) { ba.purge(); } if (e instanceof SecurityException) { throw (SecurityException)e; } else if (e instanceof BundleException) { throw (BundleException)e; } else { throw new BundleException("Failed to install bundle: " + e, BundleException.UNSPECIFIED, e); } } } /** * Remove bundle registration. * * @param location The location to be removed */ void remove(String location) { bundles.remove(location); } void addZombie(BundleImpl b) { synchronized (bundles) { zombies.add(b); } } void removeZombie(BundleImpl b) { synchronized (bundles) { zombies.remove(b); } } /** * Get bundle that has specified bundle identifier. * * @param id The identifier of bundle to get. * @return BundleImpl representing bundle or null * if bundle was not found. */ Bundle getBundle(long id) { checkIllegalState(); synchronized (bundles) { for (final Enumeration e = bundles.elements(); e.hasMoreElements();) { final BundleImpl b = e.nextElement(); if (b.id == id) { return b; } } } return null; } /** * Get bundle that has specified bundle location. * * @param location The location of bundle to get. * @return BundleImpl representing bundle or null * if bundle was not found. */ Bundle getBundle(String location) { checkIllegalState(); return bundles.get(location); } /** * Get all bundles that has specified bundle symbolic name and version. * * @param name The symbolic name of bundle to get. * @param version The bundle version of bundle to get. * @return Collection of BundleImpls. */ Collection getBundles(String name, Version version) { checkIllegalState(); final ArrayList res = new ArrayList(bundles.size()); if (Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(name) && version.equals(fwCtx.systemBundle.getVersion())) { res.add(fwCtx.systemBundle); } synchronized (bundles) { for (final Enumeration e = bundles.elements(); e.hasMoreElements();) { final BundleImpl b = e.nextElement(); if (name.equals(b.getSymbolicName()) && version.equals(b.getVersion())) { res.add(b); } } } return res; } /** * Get all installed bundles. * * @return A Bundle array with bundles. */ List getBundles() { final ArrayList res = new ArrayList(bundles.size()); synchronized (bundles) { res.addAll(bundles.values()); } return res; } /** * Get all bundles that has specified bundle symbolic name. * * @param name The symbolic name of bundles to get, if null get all. * @return A List of current BundleGenerations. */ List getBundleGenerations(String name) { final ArrayList res = new ArrayList(); if (Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(name)) { res.add(fwCtx.systemBundle.current()); } synchronized (bundles) { for (final BundleImpl b : bundles.values()) { if (name == null || name.equals(b.getSymbolicName())) { res.add(b.current()); } } } return res; } /** * Get all bundles that has specified bundle symbolic name and * version range. Result is sorted in decreasing version order. * * @param name The symbolic name of bundles to get. * @param range Version range of bundles to get. * @return A List of current BundleGenerations. */ List getBundles(String name, VersionRange range) { checkIllegalState(); final List res = getBundleGenerations(name); for (int i = 0; i < res.size(); ) { final BundleGeneration bg = res.remove(i); if (range == null || range.includes(bg.version)) { int j = i; while (--j >= 0) { if (bg.version.compareTo(res.get(j).version) <= 0) { break; } } res.add(j + 1, bg); i++; } } return res; } /** * Get all bundles currently in bundle state ACTIVE. * * @return A List of BundleImpl. */ List getActiveBundles() { checkIllegalState(); final ArrayList slist = new ArrayList(); synchronized (bundles) { for (final Enumeration e = bundles.elements(); e.hasMoreElements();) { final BundleImpl b = e.nextElement(); final int s = b.getState(); if (s == Bundle.ACTIVE || s == Bundle.STARTING) { slist.add(b); } } } return slist; } /** * Get removal pending bundles. * * @return A Bundle array with bundles. */ void getRemovalPendingBundles(Collection res) { synchronized (bundles) { for (BundleImpl b : bundles.values()) { if (b.hasZombies()) { res.add(b); } } res.addAll(zombies); } } /** * Get unattached fragments that has a resolved host. * * @return A Bundle array with bundles. */ void getUnattachedBundles(Collection res) { synchronized (bundles) { for (BundleImpl b : bundles.values()) { if (b.getState() == Bundle.INSTALLED) { final BundleGeneration curr = b.current(); if (curr.isFragment() && curr.getResolvedHosts().size() > 0) { res.add(b); } } } } } /** * Check if any extension bundle needs a framework restart. * * @return A Bundle array with bundles. */ boolean checkExtensionBundleRestart() { synchronized (bundles) { for (BundleImpl b : zombies) { if (b.extensionNeedsRestart()) { return true; } } for (BundleImpl b : bundles.values()) { if (b.extensionNeedsRestart()) { return true; } } } return false; } /** * Try to load any saved framework state. * This is done by installing all saved bundles from the local archive * copy, and restoring the saved state for each bundle. This is only * intended to be executed during the start of the framework. * */ synchronized void load() { final BundleArchive [] bas = fwCtx.storage.getAllBundleArchives(); for (final BundleArchive ba : bas) { try { final BundleImpl b = new BundleImpl(fwCtx, ba, null, fwCtx.systemBundle); bundles.put(b.location, b); } catch (final Exception e) { try { ba.setAutostartSetting(-1); // Do not start on launch ba.setStartLevel(-2); // Mark as uninstalled } catch (final IOException _ioe) { } System.err.println("Error: Failed to load bundle " +ba.getBundleId() +" (" +ba.getBundleLocation() +")" +" uninstalled it!" ); e.printStackTrace(); } } } /** * Returns all fragment bundles that is * already attached and targets given bundle. * * @param target the targeted bundle * @return a list of all matching fragment bundle generations. */ Collection getFragmentBundles(BundleGeneration target) { final HashMap res = new HashMap(); for (final Enumeration e = bundles.elements(); e.hasMoreElements();) { final BundleImpl b = e.nextElement(); final BundleGeneration bg = b.current(); if (bg.isFragment() && b.state != Bundle.UNINSTALLED && bg.fragment.isTarget(target)) { final String sym = bg.symbolicName; final BundleGeneration old = res.get(sym); if (old != null && old.symbolicName.equals(sym)) { if (old.version.compareTo(bg.version) > 0) { continue; } } res.put(sym, bg); } } return res.values(); } /** * Check if this bundles object have been closed! */ private void checkIllegalState() { if (null == fwCtx) { throw new IllegalStateException("This framework instance is not active."); } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/FileTree.java0000644000175000017500000000764312346513666027541 0ustar felixfelix/* * Copyright (c) 2003-2011, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.*; /** * FileTree is extension to java.io.File that handles copying and deletion of * complete file structures. * * @author Jan Stein */ public class FileTree extends File { private static final long serialVersionUID = 3396907770563704920L; /** * Creates a new FileTree instance based on given pathname string. */ public FileTree(String name) { super(name); } /** * Creates a new Filetree instance by a pathname string to an existing File or * FileTree. */ public FileTree(File file, String name) { super(file, name); } /** * Creates a new FileTree instance from a parent pathname string and a child * pathname string. */ public FileTree(String n1, String n2) { super(n1, n2); } /** * Copy this file tree to specified destination. * * @param copyFile File object representing the destination. * @exception IOException if copy failed. Will leave destination in an * unspecified state. */ public void copyTo(File copyFile) throws IOException { if (isDirectory()) { copyFile.mkdirs(); String[] dirs = list(); for (int i = dirs.length - 1; i >= 0; i--) { (new FileTree(this, dirs[i])).copyTo(new File(copyFile, dirs[i])); } } else { InputStream is = null; OutputStream os = null; try { is = new BufferedInputStream(new FileInputStream(this)); os = new BufferedOutputStream(new FileOutputStream(copyFile)); byte[] buf = new byte[4096]; for (;;) { int n = is.read(buf); if (n < 0) { break; } os.write(buf, 0, n); } } finally { try { if (is != null) { is.close(); } } finally { if (os != null) { os.close(); } } } } } /** * Delete this file tree from disk. * * @return True if operation completed okay. */ public boolean delete() { boolean allDeleted = true; if (isDirectory()) { String[] dirs = list(); if (dirs != null) { for (int i = dirs.length - 1; i >= 0; i--) { allDeleted &= (new FileTree(this, dirs[i])).delete(); } } } boolean thisDeleted = super.delete(); return allDeleted & thisDeleted; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ServiceListenerState.java0000644000175000017500000002410412346513666032140 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; 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 org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceListener; /** * Container of all service listeners. */ class ServiceListenerState { protected final static String[] hashedKeys = new String[] { Constants.OBJECTCLASS.toLowerCase(), Constants.SERVICE_ID.toLowerCase(), Constants.SERVICE_PID.toLowerCase() }; private final static int OBJECTCLASS_IX = 0; private final static int SERVICE_ID_IX = 1; private final static int SERVICE_PID_IX = 2; protected static List hashedKeysV; /* Service listeners with complicated or empty filters */ List complicatedListeners = new ArrayList(); /* Service listeners with "simple" filters are cached. */ /* [Value -> List(ServiceListenerEntry)] */ @SuppressWarnings("unchecked") Map>[] cache = new HashMap[hashedKeys.length]; Set serviceSet = new HashSet(); Listeners listeners; ServiceListenerState(Listeners listeners) { this.listeners = listeners; hashedKeysV = new ArrayList(); for (int i = 0; i < hashedKeys.length; i++) { hashedKeysV.add(hashedKeys[i]); cache[i] = new HashMap>(); } } void clear() { hashedKeysV.clear(); complicatedListeners.clear(); for (int i = 0; i < hashedKeys.length; i++) { cache[i].clear(); } serviceSet.clear(); listeners = null;; } /** * Add a new service listener. If an old one exists, and it has the * same owning bundle, the old listener is removed first. * * @param bc The bundle context adding this listener. * @param listener The service listener to add. * @param filter An LDAP filter string to check when a service is modified. * @exception org.osgi.framework.InvalidSyntaxException * If the filter is not a correct LDAP expression. */ synchronized void add(BundleContextImpl bc, ServiceListener listener, String filter) throws InvalidSyntaxException { final ServiceListenerEntry sle = new ServiceListenerEntry(bc, listener, filter); if (serviceSet.contains(sle)) { remove(bc, listener); } serviceSet.add(sle); listeners.fwCtx.serviceHooks.handleServiceListenerReg(sle); checkSimple(sle); } /** * Remove a service listener. * * @param bc The bundle context removing this listener. * @param listener The service listener to remove. */ synchronized void remove(BundleContextImpl bc, ServiceListener listener) { for (final Iterator it = serviceSet.iterator(); it.hasNext();) { final ServiceListenerEntry sle = it.next(); if (sle.bc == bc && sle.listener == listener) { sle.setRemoved(true); listeners.fwCtx.serviceHooks.handleServiceListenerUnreg(sle); removeFromCache(sle); it.remove(); break; } } } /** * Remove all references to a service listener from the service listener * cache. */ private void removeFromCache(ServiceListenerEntry sle) { if (sle.local_cache != null) { for (int i = 0; i < hashedKeys.length; i++) { final Map> keymap = cache[i]; final List l = sle.local_cache[i]; if (l != null) { for (final Object value : l) { final List sles = keymap.get(value); if(sles != null) { sles.remove(sles.indexOf(sle)); if (sles.isEmpty()) { keymap.remove(value); } } } } } } else { complicatedListeners.remove(sle); } } /** * Remove all service listeners registered by the specified bundle context. * * @param bc The bundle context to remove listeners for. */ synchronized void removeAll(BundleContextImpl bc) { for (final Iterator it = serviceSet.iterator(); it.hasNext();) { final ServiceListenerEntry sle = it.next(); if (sle.bc == bc) { removeFromCache(sle); it.remove(); } } } /** * Remove all service listeners registered by the specified bundle. * * @param bundle The bundle to remove listeners for. */ synchronized void hooksBundleStopped(BundleContextImpl bc) { final List entries = new ArrayList(); for (final ServiceListenerEntry sle : serviceSet) { if (sle.bc == bc) { entries.add(sle); } } listeners.fwCtx.serviceHooks.handleServiceListenerUnreg(Collections.unmodifiableList(entries)); } /** * Checks if the specified service listener's filter is simple enough * to cache. */ public void checkSimple(ServiceListenerEntry sle) { if (sle.noFiltering || listeners.nocacheldap) { complicatedListeners.add(sle); } else { @SuppressWarnings("unchecked") final List[] local_cache = new List[hashedKeys.length]; if (sle.ldap.isSimple(hashedKeysV, local_cache, false)) { sle.local_cache = local_cache; for (int i = 0; i < hashedKeys.length; i++) { if (local_cache[i] != null) { for (final Object value : local_cache[i]) { List sles = cache[i].get(value); if (sles == null) cache[i].put(value, sles = new ArrayList()); sles.add(sle); } } } } else { if (listeners.fwCtx.debug.ldap) { listeners.fwCtx.debug.println("Too complicated filter: " + sle.ldap); } complicatedListeners.add(sle); } } } /** * Gets the listeners interested in modifications of the service reference * * @param sr The reference related to the event describing the service modification. * @return A set of listeners to notify. */ synchronized Set getMatchingListeners(ServiceReferenceImpl sr) { final Set set = new HashSet(); // Check complicated or empty listener filters int n = 0; for (final ServiceListenerEntry sle : complicatedListeners) { if (sle.noFiltering || sle.ldap.evaluate(sr.getProperties(), false)) { set.add(sle); } ++n; } if (listeners.fwCtx.debug.ldap) { listeners.fwCtx.debug.println("Added " + set.size() + " out of " + n + " listeners with complicated filters"); } // Check the cache final String[] c = (String[])sr.getProperty(Constants.OBJECTCLASS); for (final String element : c) { addToSet(set, OBJECTCLASS_IX, element); } final Long service_id = (Long)sr.getProperty(Constants.SERVICE_ID); if (service_id != null) { addToSet(set, SERVICE_ID_IX, service_id.toString()); } final Object service_pid = sr.getProperty(Constants.SERVICE_PID); if (service_pid != null) { if (service_pid instanceof String) { addToSet(set, SERVICE_PID_IX, service_pid); } else if (service_pid instanceof String []) { final String [] sa = (String [])service_pid; for (final String element : sa) { addToSet(set, SERVICE_PID_IX, element); } } else if (service_pid instanceof Collection) { // TODO should we report if type isn't a String? @SuppressWarnings("unchecked") final Collection pids = (Collection) service_pid; for (final String pid : pids) { addToSet(set, SERVICE_PID_IX, pid); } } } return set; } /** * Add all members of the specified list to the specified set. */ private void addToSet(Set set, int cache_ix, Object val) { final List l = cache[cache_ix].get(val); if (l != null) { if (listeners.fwCtx.debug.ldap) { listeners.fwCtx.debug.println(hashedKeys[cache_ix] + " matches " + l.size()); } set.addAll(l); } else { if (listeners.fwCtx.debug.ldap) { listeners.fwCtx.debug.println(hashedKeys[cache_ix] + " matches none"); } } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleImpl.java0000644000175000017500000015371712346513666030101 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.AccessControlContext; import java.security.Permission; import java.security.PermissionCollection; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.Dictionary; 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 java.util.Vector; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.osgi.framework.Version; import org.osgi.framework.startlevel.BundleStartLevel; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleRevisions; import org.osgi.framework.wiring.BundleWiring; /** * Implementation of the Bundle object. * * @see org.osgi.framework.Bundle * @author Jan Stein * @author Philippe Laporte * @author Mats-Ola Persson */ public class BundleImpl implements Bundle { /** * Framework for bundle. */ final FrameworkContext fwCtx; /** * Bundle identifier. */ final long id; /** * Bundle location identifier. */ final String location; /** * Handle to secure operations. */ PermissionOps secure; /** * State of bundle. */ volatile int state; /** * Bundle generation data. */ protected final Vector generations; /** * Directory for bundle data. */ protected FileTree bundleDir = null; /** * BundleContext for bundle. */ protected BundleContextImpl bundleContext = null; /** * BundleActivator for bundle. */ protected BundleActivator bactivator = null; /** * Stores the default locale entries when uninstalled. */ volatile private HeaderDictionary cachedHeaders = null; /** * Type of operation in progress. Blocks bundle calls during activator and * listener calls */ volatile protected int operation; final static int IDLE = 0; final static int ACTIVATING = 1; final static int DEACTIVATING = 2; final static int RESOLVING = 3; final static int UNINSTALLING = 4; final static int UNRESOLVING = 5; final static int UPDATING = 6; /** Saved exception of resolve failure. */ private BundleException resolveFailException; /** Remember if bundle was started */ private boolean wasStarted; /** start/stop time-out/uninstall flag, see BundleThread */ volatile Boolean aborted; /** current bundle thread */ private BundleThread bundleThread; /** * Construct a new Bundle empty. * * Only called for system bundle * * @param fw Framework for this bundle. */ BundleImpl(FrameworkContext fw) { fwCtx = fw; secure = fwCtx.perm; id = 0; generations = new Vector(1); location = Constants.SYSTEM_BUNDLE_LOCATION; state = INSTALLED; bundleDir = fwCtx.getDataStorage(id); } /** * Construct a new Bundle based on a BundleArchive. * * @param fw FrameworkContext for this bundle. * @param ba Bundle archive with holding the contents of the bundle. * @param checkContext AccessConrolContext to do permission checks against. * @throws BundleException If we have duplicate symbolicname and version. * @exception IOException If we fail to read and store our JAR bundle or if * the input data is corrupted. * @exception SecurityException If we don't have permission to install * extension. * @exception IllegalArgumentException Faulty manifest for bundle */ BundleImpl(FrameworkContext fw, BundleArchive ba, Object checkContext, Bundle caller) throws BundleException { fwCtx = fw; secure = fwCtx.perm; id = ba.getBundleId(); location = ba.getBundleLocation(); state = INSTALLED; generations = new Vector(2); final BundleGeneration gen = new BundleGeneration(this, ba, null, caller); generations.add(gen); gen.checkPermissions(checkContext); doExportImport(); bundleDir = fwCtx.getDataStorage(id); // Activate extension as soon as they are installed so that // they get added in bundle id order. if (gen.isExtension() && attachToFragmentHost(fwCtx.systemBundle.current())) { gen.setWired(); state = RESOLVED; } } // // Bundle interface // /** * Get bundle state. * * @see org.osgi.framework.Bundle#getState */ public int getState() { return state; } public void start() throws BundleException { start(0); } /** * Start this bundle. * * @see org.osgi.framework.Bundle#start */ public void start(int options) throws BundleException { secure.checkExecuteAdminPerm(this); synchronized (fwCtx.resolver) { final BundleGeneration current = current(); if (current.isFragment()) { throw new BundleException("Bundle#" + id + ", cannot start a fragment bundle", BundleException.INVALID_OPERATION); } if (state == UNINSTALLED) { throw new IllegalStateException("Bundle is uninstalled"); } fwCtx.resolverHooks.checkResolveBlocked(); // The value -1 is used by this implementation to indicate a bundle // that has not been started, thus ensure that options is != -1. options &= 0xFF; if (fwCtx.startLevelController != null) { if (getStartLevel() > fwCtx.startLevelController.getStartLevel()) { if ((options & START_TRANSIENT) != 0) { throw new BundleException("Bundle#" + id + ", can not transiently activate bundle with start level " + getStartLevel() + " when running on start level " + fwCtx.startLevelController.getStartLevel(), BundleException.START_TRANSIENT_ERROR); } else { setAutostartSetting(options); return; } } } // Initialize the activation; checks initialization of lazy // activation. // 1: If an operation is in progress, wait a little waitOnOperation(fwCtx.resolver, "Bundle.start", false); // 2: start() is idempotent, i.e., nothing to do when already started if (state == ACTIVE) { return; } // 3: Record non-transient start requests. if ((options & START_TRANSIENT) == 0) { setAutostartSetting(options); } // 5: Lazy? if ((options & START_ACTIVATION_POLICY) != 0 && current.lazyActivation) { // 4: Resolve bundle (if needed) if (INSTALLED == getUpdatedState(new BundleImpl [] { this })) { throw resolveFailException; } if (STARTING == state) return; state = STARTING; bundleContext = new BundleContextImpl(this); operation = ACTIVATING; } else { secure.callFinalizeActivation(this); return; } } // Last step of lazy activation secure.callBundleChanged(fwCtx, new BundleEvent(BundleEvent.LAZY_ACTIVATION, this)); synchronized (fwCtx.resolver) { operation = IDLE; fwCtx.resolver.notifyAll(); } } // Performs the actual activation. void finalizeActivation() throws BundleException { synchronized (fwCtx.resolver) { // 4: Resolve bundle (if needed) switch (getUpdatedState(new BundleImpl [] { this })) { case INSTALLED: throw resolveFailException; case STARTING: if (operation == ACTIVATING) { // finalization already in progress. return; } // Lazy activation; fall through to RESOLVED. case RESOLVED: // 6: state = STARTING; operation = ACTIVATING; if (fwCtx.debug.lazy_activation) { fwCtx.debug.println("activating #" + getBundleId()); } // 7: if (null == bundleContext) { bundleContext = new BundleContextImpl(this); } final BundleException e = bundleThread().callStart0(this); operation = IDLE; fwCtx.resolver.notifyAll(); if (e != null) { throw e; } break; case ACTIVE: break; case STOPPING: // This happens if call start from inside the BundleActivator.stop // method. // Don't allow it. throw new BundleException("Bundle#" + id + ", start called from BundleActivator.stop", BundleException.ACTIVATOR_ERROR); case UNINSTALLED: throw new IllegalStateException("Bundle is in UNINSTALLED state"); } } } /** * Start code that is executed in the bundleThread without holding the * packages lock. */ BundleException start0() { final BundleArchive archive = current().archive; final String ba = archive.getAttribute(Constants.BUNDLE_ACTIVATOR); boolean bStarted = false; // res is used to signal that start did not complete in a normal way BundleException res = null; fwCtx.listeners.bundleChanged(new BundleEvent(BundleEvent.STARTING, this)); // If SETCONTEXTCLASSLOADER, set the thread's context // class loader to the bundle class loader. This // is useful for debugging external libs using // the context class loader. ClassLoader oldLoader = null; if (fwCtx.props.SETCONTEXTCLASSLOADER) { oldLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getClassLoader()); } int error_type = BundleException.MANIFEST_ERROR; try { if (ba != null) { @SuppressWarnings("unchecked") final Class c = (Class) getClassLoader().loadClass(ba.trim()); error_type = BundleException.ACTIVATOR_ERROR; bactivator = c.newInstance(); bactivator.start(bundleContext); bStarted = true; } else { final String locations = fwCtx.props.getProperty(FWProps.MAIN_CLASS_ACTIVATION_PROP); if (locations.length() > 0) { final String mc = archive.getAttribute("Main-Class"); if (mc != null) { final String[] locs = Util.splitwords(locations, ","); for (final String loc : locs) { if (loc.equals(location)) { if (fwCtx.debug.resolver) { fwCtx.debug.println("starting main class " + mc); } error_type = BundleException.ACTIVATOR_ERROR; final Class mainClass = getClassLoader().loadClass(mc.trim()); bactivator = new MainClassBundleActivator(mainClass); bactivator.start(bundleContext); bStarted = true; break; } } } } } if (!bStarted) { // Even bundles without an activator are marked as // ACTIVE. // Should we possible log an information message to // make sure users are aware of the missing activator? } } catch (Throwable t) { res = new BundleException("Bundle#" + id + " start failed", error_type, t); } // activator.start() done // - normal -> state = active, started event // - exception from start() -> res = ex, start-failed clean-up // - unexpected state change (uninstall, refresh?): // -> res = new exception // - start time-out -> res = new exception (not used?) // if start was aborted (uninstall or timeout), make sure // finalizeActivation() has finished before checking aborted/state synchronized (fwCtx.resolver) { if (!isBundleThread(Thread.currentThread())) { // newer BundleThread instance has been active for this BundleImpl, // end thread execution throw new RuntimeException("Aborted bundle thread ending execution"); } Exception cause = null; if (aborted == Boolean.TRUE) { if (UNINSTALLED == state) { cause = new Exception("Bundle uninstalled during start()"); } else { cause = new Exception("Bundle activator start() time-out"); } } else { aborted = Boolean.FALSE; // signal to other thread that BundleThread // concludes start/stop if (STARTING != state) { cause = new Exception("Bundle changed state because of refresh during start()"); } } if (cause != null) { res = new BundleException("Bundle#" + id + " start failed", BundleException.STATECHANGE_ERROR, cause); } } if (fwCtx.debug.lazy_activation) { fwCtx.debug.println("activating #" + getBundleId() + " completed."); } if (fwCtx.props.SETCONTEXTCLASSLOADER) { Thread.currentThread().setContextClassLoader(oldLoader); } if (res == null) { // 10: state = ACTIVE; fwCtx.listeners.bundleChanged(new BundleEvent(BundleEvent.STARTED, this)); } else if (operation == ACTIVATING) { // 8: startFailed(); } return res; } void startFailed() { // 8: state = STOPPING; fwCtx.listeners.bundleChanged(new BundleEvent(BundleEvent.STOPPING, this)); removeBundleResources(); bundleContext.invalidate(); bundleContext = null; state = RESOLVED; fwCtx.listeners.bundleChanged(new BundleEvent(BundleEvent.STOPPED, this)); } /** * Stop this bundle. * * @see org.osgi.framework.Bundle#stop */ public void stop() throws BundleException { stop(0); } /** * Stop this bundle. * * @see org.osgi.framework.Bundle#stop */ public void stop(int options) throws BundleException { Exception savedException = null; secure.checkExecuteAdminPerm(this); synchronized (fwCtx.resolver) { if (current().isFragment()) { throw new BundleException("Bundle#" + id + ", can not stop a fragment", BundleException.INVALID_OPERATION); } // 1: if (state == UNINSTALLED) { throw new IllegalStateException("Bundle is uninstalled"); } // 2: If an operation is in progress, wait a little waitOnOperation(fwCtx.resolver, "Bundle.stop", false); // 3: if ((options & STOP_TRANSIENT) == 0) { setAutostartSetting(-1); } switch (state) { case INSTALLED: case RESOLVED: case STOPPING: case UNINSTALLED: // 4: return; case ACTIVE: case STARTING: // Lazy start... savedException = stop0(); break; } } if (savedException != null) { if (savedException instanceof BundleException) { throw (BundleException)savedException; } else { throw (RuntimeException)savedException; } } } Exception stop0() { wasStarted = state == ACTIVE; // 5: state = STOPPING; operation = DEACTIVATING; // 6-13: final Exception savedException = bundleThread().callStop1(this); if (state != UNINSTALLED) { state = RESOLVED; bundleThread().bundleChanged(new BundleEvent(BundleEvent.STOPPED, this)); fwCtx.resolver.notifyAll(); operation = IDLE; } return savedException; } /** * Stop code that is executed in the bundleThread without holding the packages * lock. */ Exception stop1() { BundleException res = null; // 6: fwCtx.listeners.bundleChanged(new BundleEvent(BundleEvent.STOPPING, this)); // 7: if (wasStarted && bactivator != null) { try { bactivator.stop(bundleContext); } catch (final Throwable e) { res = new BundleException("Bundle#" + id + ", BundleActivator.stop() failed", BundleException.ACTIVATOR_ERROR, e); } // if stop was aborted (uninstall or timeout), make sure // finalizeActivation() has finished before checking aborted/state synchronized (fwCtx.resolver) { Exception cause = null; if (aborted == Boolean.TRUE) { if (UNINSTALLED == state) { cause = new Exception("Bundle uninstalled during stop()"); } else { cause = new Exception("Bundle activator stop() time-out"); } } else { aborted = Boolean.FALSE; // signal to other thread that BundleThread // concludes stop if (STOPPING != state) { cause = new Exception("Bundle changed state because of refresh during stop()"); } } if (cause != null) { res = new BundleException("Bundle stop failed", BundleException.STATECHANGE_ERROR, cause); } } bactivator = null; } if (operation == DEACTIVATING) { stop2(); } return res; } void stop2() { // Call hooks after we've called Activator.stop(), but before we've // cleared all resources if (null != bundleContext) { fwCtx.listeners.serviceListeners.hooksBundleStopped(bundleContext); // 8-10: removeBundleResources(); bundleContext.invalidate(); bundleContext = null; } } /** * Wait for an ongoing operation to finish. * * @param lock Object used for locking. * @param src Caller to include in exception message. * @param longWait True, if we should wait extra long before aborting. * @throws BundleException if the ongoing (de-)activation does not finish * within reasonable time. */ void waitOnOperation(Object lock, final String src, boolean longWait) throws BundleException { if (operation != IDLE) { long left = longWait ? 20000 : 500; final long waitUntil = Util.timeMillis() + left; do { try { lock.wait(left); if (operation == IDLE) { return; } } catch (final InterruptedException _ie) { } left = waitUntil - Util.timeMillis(); } while (left > 0); String op; switch (operation) { case IDLE: // Should not happen! return; case ACTIVATING: op = "start"; break; case DEACTIVATING: op = "stop"; break; case RESOLVING: op = "resolve"; break; case UNINSTALLING: op = "uninstall"; break; case UNRESOLVING: op = "unresolve"; break; case UPDATING: op = "update"; break; default: op = "unknown operation"; break; } throw new BundleException(src + " called during " + op + " of Bundle#" + id, BundleException.STATECHANGE_ERROR); } } /** * Update this bundle. * * @see org.osgi.framework.Bundle#update */ public void update() throws BundleException { update(null); } /** * Update this bundle. * * @see org.osgi.framework.Bundle#update */ public void update(final InputStream in) throws BundleException { try { secure.checkLifecycleAdminPerm(this); if (current().isExtension()) { secure.checkExtensionLifecycleAdminPerm(this); } synchronized (fwCtx.resolver) { final boolean wasActive = state == ACTIVE; switch (getState()) { case ACTIVE: stop(STOP_TRANSIENT); // Fall through case RESOLVED: case INSTALLED: // Load new bundle secure.callUpdate0(this, in, wasActive); break; case STARTING: // Wait for RUNNING state, this doesn't happen now // since we are synchronized. throw new IllegalStateException("Bundle is in STARTING state"); case STOPPING: // Wait for RESOLVED state, this doesn't happen now // since we are synchronized. throw new IllegalStateException("Bundle is in STOPPING state"); case UNINSTALLED: throw new IllegalStateException("Bundle is in UNINSTALLED state"); } } } finally { if (in != null) { try { in.close(); } catch (final IOException ignore) { } } } } void update0(InputStream in, boolean wasActive, Object checkContext) throws BundleException { final boolean wasResolved = state == RESOLVED; final BundleGeneration current = current(); final Fragment oldFragment = current.fragment; final int oldStartLevel = getStartLevel(); BundleArchive newArchive = null; BundleGeneration newGeneration = null; operation = UPDATING; try { // New bundle as stream supplied? InputStream bin; final BundleArchive archive = current.archive; if (in == null) { // Try Bundle-UpdateLocation String update = archive != null ? archive .getAttribute(Constants.BUNDLE_UPDATELOCATION) : null; if (update == null) { // Take original location update = location; } final URL url = new URL(update); // Handle case where bundle location is a reference and/or a directory // URL. In these cases, send a NULL input stream to the archive // indicating that is should re-use the old bundle location String fname = url.getFile(); // if reference URL, the getFile() result // may be a file: string if (fname.startsWith("file:")) { fname = fname.substring(5); } final File file = new File(fname); if (file.isDirectory()) { bin = null; } else { bin = url.openStream(); } } else { bin = in; } newArchive = fwCtx.storage.updateBundleArchive(archive, bin); newGeneration = new BundleGeneration(this, newArchive, current, this); newGeneration.checkPermissions(checkContext); newArchive.setStartLevel(oldStartLevel); fwCtx.storage.replaceBundleArchive(archive, newGeneration.archive); } catch (final Exception e) { if (newArchive != null) { newArchive.purge(); } operation = IDLE; if (wasActive) { try { start(); } catch (final BundleException be) { fwCtx.frameworkError(this, be); } } if (e instanceof BundleException) { throw (BundleException)e; } else { throw new BundleException("Failed to get update Bundle#" + id , BundleException.UNSPECIFIED, e); } } boolean saveZombie; if (oldFragment != null) { saveZombie = oldFragment.hasHosts(); if (saveZombie) { if (oldFragment.extension != null) { if (oldFragment.extension.equals(Constants.EXTENSION_BOOTCLASSPATH)) { fwCtx.systemBundle.bootClassPathHasChanged = true; } } else { for (final BundleGeneration bundleGeneration : oldFragment.getHosts()) { bundleGeneration.bpkgs.fragmentIsZombie(this); } } } } else { // Remove this bundle's packages saveZombie = !current.unregisterPackages(false); // Loose old bundle if no exporting packages left if (!saveZombie) { current.closeClassLoader(); } } // Activate new bundle generation final BundleGeneration oldGen = current; state = INSTALLED; if (saveZombie) { generations.add(0, newGeneration); fwCtx.bundles.addZombie(this); } else { generations.set(0, newGeneration); } doExportImport(); // Purge old archive if (!saveZombie) { oldGen.purge(false); } // Broadcast events if (wasResolved) { bundleThread().bundleChanged(new BundleEvent(BundleEvent.UNRESOLVED, this)); } bundleThread().bundleChanged(new BundleEvent(BundleEvent.UPDATED, this)); operation = IDLE; // Restart bundles previously stopped in the operation if (wasActive) { try { start(); } catch (final BundleException be) { fwCtx.frameworkError(this, be); } } } /** * Uninstall this bundle. * * @see org.osgi.framework.Bundle#uninstall */ public void uninstall() throws BundleException { secure.checkLifecycleAdminPerm(this); if (current().isExtension()) { secure.checkExtensionLifecycleAdminPerm(this); } secure.callUninstall0(this); } void uninstall0() { synchronized (fwCtx.resolver) { final BundleGeneration current = current(); if (!current.isUninstalled()) { try { current.archive.setStartLevel(-2); // Mark as uninstalled } catch (final Exception ignored) { } } boolean doPurge = false; switch (state) { case UNINSTALLED: throw new IllegalStateException("Bundle is in UNINSTALLED state"); case STARTING: // Lazy start case ACTIVE: case STOPPING: Exception exception; try { waitOnOperation(fwCtx.resolver, "Bundle.uninstall", true); exception = (state & (ACTIVE | STARTING)) != 0 ? stop0() : null; } catch (final Exception se) { // Force to install setStateInstalled(false); fwCtx.resolver.notifyAll(); exception = se; } operation = UNINSTALLING; if (exception != null) { fwCtx.frameworkError(this, exception); } // Fall through case RESOLVED: case INSTALLED: fwCtx.bundles.remove(location); if (operation != UNINSTALLING) { try { waitOnOperation(fwCtx.resolver, "Bundle.uninstall", true); operation = UNINSTALLING; } catch (final BundleException be) { // Make sure that bundleContext is invalid if (bundleContext != null) { bundleContext.invalidate(); bundleContext = null; } operation = UNINSTALLING; fwCtx.frameworkError(this, be); } } if (state == UNINSTALLED) { operation = IDLE; throw new IllegalStateException("Bundle is in UNINSTALLED state"); } boolean saveZombie = false; if (current.isFragment()) { if (isAttached()) { if (current.isExtension()) { if (current.isBootClassPathExtension()) { fwCtx.systemBundle.bootClassPathHasChanged = true; } } else { for (final BundleGeneration hbg : current.getHosts()) { if (hbg.bpkgs != null) { hbg.bpkgs.fragmentIsZombie(this); } } } // Fragment in use, save as zombie generation saveZombie = true; } else { doPurge = true; } } else { // Non-fragment bundle // Try to unregister this bundle's packages final boolean pkgsUnregistered = current.unregisterPackages(false); if (pkgsUnregistered) { // No exports in use, clean up. current.closeClassLoader(); doPurge = true; } else { // Exports are in use, save as zombie generation saveZombie = true; } } state = INSTALLED; bundleThread().bundleChanged(new BundleEvent(BundleEvent.UNRESOLVED, this)); cachedHeaders = current.getHeaders0(null); bactivator = null; state = UNINSTALLED; // Purge old archive final BundleGeneration oldGen = current; if (saveZombie) { generations.add(0, new BundleGeneration(oldGen)); fwCtx.bundles.addZombie(this); } else { generations.set(0, new BundleGeneration(oldGen)); } if (doPurge) { oldGen.purge(false); } operation = IDLE; if (bundleDir != null) { if (bundleDir.exists() && !bundleDir.delete()) { fwCtx.frameworkError(this, new IOException("Failed to delete bundle data")); } bundleDir = null; } // id, location and headers survives after uninstall. // There might be bundle threads that are running start or stop // operation. This will wake them and give them an chance to terminate. fwCtx.resolver.notifyAll(); break; } } fwCtx.listeners.bundleChanged(new BundleEvent(BundleEvent.UNINSTALLED, this)); } /** * Get header data. This is all entries in the bundles MANIFEST file. * * @see org.osgi.framework.Bundle#getHeaders */ public Dictionary getHeaders() { return getHeaders(null); } /** * Get bundle identifier. * * @see org.osgi.fwCtx.Bundle#getBundleId */ public long getBundleId() { return id; } /** * Get bundle location. * * @see org.osgi.framework.Bundle#getLocation */ public String getLocation() { secure.checkMetadataAdminPerm(this); return location; } /** * Get services that this bundle has registrated. * * @see org.osgi.framework.Bundle#getRegisteredServices */ public ServiceReference[] getRegisteredServices() { checkUninstalled(); final Set> sr = fwCtx.services.getRegisteredByBundle(this); secure.filterGetServicePermission(sr); if (sr.size() > 0) { final ServiceReference[] res = new ServiceReference[sr.size()]; int pos = 0; for (final ServiceRegistrationImpl serviceRegistrationImpl : sr) { res[pos++] = serviceRegistrationImpl.getReference(); } return res; } return null; } /** * Get services that this bundle uses. * * @see org.osgi.framework.Bundle#getServicesInUse */ public ServiceReference[] getServicesInUse() { checkUninstalled(); final Set> sr = fwCtx.services.getUsedByBundle(this); secure.filterGetServicePermission(sr); if (sr.size() > 0) { final ServiceReference[] res = new ServiceReference[sr.size()]; int pos = 0; for (final ServiceRegistrationImpl serviceRegistrationImpl : sr) { res[pos++] = serviceRegistrationImpl.getReference(); } return res; } return null; } /** * Determine whether the bundle has the requested permission. * * @see org.osgi.framework.Bundle#hasPermission */ public boolean hasPermission(Object permission) { final BundleGeneration fix = current(); checkUninstalled(); if (permission instanceof Permission) { if (secure.checkPermissions()) { // get the current status from permission admin final PermissionCollection pc = fix.getProtectionDomain().getPermissions(); return pc != null ? pc.implies((Permission)permission) : false; } else { return true; } } else { return false; } } /** * Returns this bundle's BundleContext. * * @see org.osgi.framework.Bundle#getBundleContext * @since org.osgi.framework 1.4 */ public BundleContext getBundleContext() { secure.checkContextAdminPerm(this); return bundleContext; } /** * @see org.osgi.framework.Bundle#getResource(String name) */ public URL getResource(String name) { checkUninstalled(); // NYI, sync BundleGeneration if (secure.okResourceAdminPerm(this) && !current().isFragment()) { if (getUpdatedState(new BundleImpl [] { this }) != INSTALLED) { final ClassLoader cl0 = getClassLoader(); if (cl0 != null) { return cl0.getResource(name); } } else { final Vector uv = secure.getBundleClassPathEntries(current(), name, true); if (uv != null) { return uv.firstElement(); } } } return null; } /** * @see org.osgi.framework.Bundle#getSymbolicName() */ public String getSymbolicName() { return current().symbolicName; } /** * * @see org.osgi.framework.Bundle#getLastModified() */ public long getLastModified() { return current().timeStamp; } /** * * @see org.osgi.framework.Bundle#getSignerCertificates() */ @SuppressWarnings("unchecked") public Map> getSignerCertificates(int signersType) { boolean onlyTrusted; if (signersType == SIGNERS_ALL) { onlyTrusted = false; } else if (signersType == SIGNERS_TRUSTED) { onlyTrusted = true; } else { throw new IllegalArgumentException("signersType not SIGNER_ALL or SIGNERS_TRUSTED"); } final BundleArchive fix = current().archive; if (fix != null) { final List> cs = fix.getCertificateChains(onlyTrusted); if (cs != null) { final Map> res = new HashMap>(); for (final List chain : cs) { final List copy = new ArrayList(chain); res.put(chain.get(0), copy); } return res; } } return Collections.EMPTY_MAP; } /** * * @see org.osgi.framework.Bundle#getVersion() */ public Version getVersion() { return current().version; } public A adapt(Class type) { secure.checkAdaptPerm(this, type); return adaptSecure(type); } public File getDataFile(String filename) { return bundleContext.getDataFile(filename); } public int compareTo(Bundle bundle) { return new Long(getBundleId()).compareTo(new Long(bundle.getBundleId())); } // // Package methods // /** * Get updated bundle state. That means check if an installed bundle has been * resolved. * * @return Bundles state */ int getUpdatedState(BundleImpl [] triggers) { if (state == INSTALLED) { try { synchronized (fwCtx.resolver) { waitOnOperation(fwCtx.resolver, "Bundle.resolve", true); if (state == INSTALLED) { final BundleGeneration current = current(); if (triggers != null) { fwCtx.resolverHooks.beginResolve(triggers); } if (current.isFragment()) { final List hosts = current.fragment.targets(); if (!hosts.isEmpty()) { for (final BundleGeneration host : hosts) { if (!host.bpkgs.isActive()) { // Try resolve our host // NYI! Detect circular attach host.bundle.getUpdatedState(null); } else { if (!current.fragment.isHost(host)) { attachToFragmentHost(host); } } } if (state == INSTALLED && current.fragment.hasHosts()) { current.setWired(); state = RESOLVED; operation = RESOLVING; bundleThread().bundleChanged(new BundleEvent(BundleEvent.RESOLVED, this)); operation = IDLE; } } } else { if (current.resolvePackages(triggers)) { current.setWired(); state = RESOLVED; operation = RESOLVING; current.updateStateFragments(); bundleThread().bundleChanged(new BundleEvent(BundleEvent.RESOLVED, this)); operation = IDLE; } else { String reason = current.bpkgs.getResolveFailReason(); throw new BundleException("Bundle#" + id + ", unable to resolve: " + reason, reason == Resolver.RESOLVER_HOOK_VETO ? BundleException.REJECTED_BY_HOOK : BundleException.RESOLVE_ERROR); } } if (triggers != null && triggers.length == 1) { BundleImpl[] t = triggers; triggers = null; fwCtx.resolverHooks.endResolve(t); } } } } catch (final BundleException be) { resolveFailException = be; fwCtx.frameworkError(this, be); if (triggers != null && triggers.length == 1) { try { fwCtx.resolverHooks.endResolve(triggers); } catch (final BundleException be2) { resolveFailException = be2; fwCtx.frameworkError(this, be2); } } } } return state; } /** * Attach a fragment to host bundle * @throws BundleException */ boolean attachToFragmentHost(BundleGeneration host) throws BundleException { final BundleGeneration fix = current(); if (fix.isFragment() && secure.okFragmentBundlePerm(this)) { try { if (fix.isExtension()) { fwCtx.systemBundle.attachExtension(fix); } else { host.attachFragment(fix); } fix.fragment.addHost(host); return true; } catch (final BundleException be) { throw be; } catch (final Exception e) { fwCtx.frameworkWarning(this, e); } } return false; } /** * Get root for persistent storage area for this bundle. * * @return A File object representing the data root. */ File getDataRoot() { return bundleDir; } /** * Get class loader for this bundle. Create the classloader if we haven't done * this previously. This method can only be called when the bundle is * resolved. * * @return Bundles classloader. */ ClassLoader getClassLoader() { return current().getClassLoader(); } /** * Set state to INSTALLED and throw away our classloader. Reset all package * registration. We assume that the bundle is resolved when entering this * method. */ void setStateInstalled(boolean sendEvent) { synchronized (fwCtx.resolver) { // Make sure that bundleContext is invalid if (bundleContext != null) { bundleContext.invalidate(); bundleContext = null; } final BundleGeneration current = current(); if (current.isFragment()) { current.fragment.removeHost(null); } else { current.closeClassLoader(); current.unregisterPackages(true); current.bpkgs.registerPackages(); } current.clearWiring(); state = INSTALLED; if (sendEvent) { operation = UNRESOLVING; bundleThread().bundleChanged(new BundleEvent(BundleEvent.UNRESOLVED, this)); } operation = IDLE; } } /** * Purge any old files and data associated with this bundle. */ void purge() { fwCtx.bundles.removeZombie(this); Vector old; synchronized (generations) { final List sub = generations.subList(1, generations.size()); old = new Vector(sub); sub.clear(); } for (final BundleGeneration bg : old) { bg.purge(true); } } /** * Get bundle archive. * * @return BundleArchive object. */ BundleArchive getBundleArchive(long generation) { synchronized (generations) { for (final BundleGeneration bg : generations) { if (bg.generation == generation) { return bg.archive; } } } return null; } /** * Get exported packages. Note! Can be called without packages lock held. * * @return Iterator of all exported packages as ExportPkg. */ @SuppressWarnings("unchecked") Iterator getExports() { synchronized (generations) { HashSet res; if (generations.size() > 1) { res = new HashSet(); for (final BundleGeneration bg : generations) { final BundlePackages bp = bg.bpkgs; if (bp != null) { for (final Iterator j = bp.getExports(); j.hasNext();) { res.add(j.next()); } } } return res.iterator(); } else { final BundlePackages bp = generations.get(0).bpkgs; if (bp != null) { return bp.getExports(); } else { return Collections.EMPTY_LIST.iterator(); } } } } /** * Get Hosts for this bundle packages. * * @return Vector of all host bundles BundleGeneration. */ Vector getHosts(final boolean zombieHosts) { Vector res = null; if (zombieHosts) { synchronized (generations) { for (final BundleGeneration bg : generations) { final Vector h = bg.getHosts(); if (h != null) { if (res != null) { res.addAll(h); } else { res = h; } } } } } else { res = current().getHosts(); } return res; } /** * Get a list of all BundlePackages that require the exported packages that * comes from this bundle. * * @return List of all requiring bundles as BundlePackages. */ @SuppressWarnings("unchecked") List getRequiredBy() { List res = null; synchronized (generations) { for (final BundleGeneration bg : generations) { final BundlePackages bp = bg.bpkgs; if (bp != null) { final List rb = bp.getRequiredBy(); if (res != null) { res.addAll(rb); } else { res = rb; } } } } return res != null ? res : Collections.EMPTY_LIST; } /** * Save the autostart setting to the persistent bundle storage. * * @param setting The autostart options to save. */ void setAutostartSetting(int setting) { secure.callSetAutostartSetting(this, setting); } /** * Internal version; only to be used from inside PriviledgedActions running on * the framework's security context. * * @param setting The autostart setting to store. */ void setAutostartSetting0(int setting) { try { final BundleArchive ba = current().archive; if (null != ba) { ba.setAutostartSetting(setting); } } catch (final IOException e) { fwCtx.frameworkError(this, e); } } /** * Get the autostart setting from the bundle storage. * * @return the current autostart setting, "-1" if bundle not started. */ int getAutostartSetting() { final BundleArchive ba = current().archive; return ba != null ? ba.getAutostartSetting() : -1; } // Start level related /** * */ int getStartLevel() { final BundleArchive ba = current().archive; if (ba != null) { return ba.getStartLevel(); } else { return 0; } } /** * */ void setStartLevel(int n) { // as soon as anoyone sets the start level explicitly // the level becomes persistent final BundleArchive ba = current().archive; if (ba != null) { try { ba.setStartLevel(n); } catch (final Exception e) { fwCtx.frameworkError(this, new BundleException( "Failed to set start level on #" + id, e)); } } } // Misc other /** * Return a string representing this bundle. Only return identifier, since it * requires AdminPermisson to get the location. * * @return a String representing this bundle. */ public String toString() { return toString(0); // 0 is lowest detail } String toString(int detail) { final StringBuffer sb = new StringBuffer(); sb.append("BundleImpl["); sb.append("id=" + getBundleId()); if (detail > 0) { sb.append(", state=" + getState()); } if (detail > 1) { sb.append(", startlevel=" + getStartLevel()); } if (detail > 3) { try { sb.append(", autostart setting="); sb.append(getAutostartSetting()); } catch (final Exception e) { sb.append(e.toString()); } } if (detail > 4) { sb.append(", loc=" + location); } if (detail > 4) { sb.append(", symName=" + getSymbolicName()); } sb.append("]"); return sb.toString(); } /** * Get bundle data. Get resources from bundle or fragment jars. * * @see org.osgi.framework.Bundle#findEntries */ public Enumeration findEntries(String path, String filePattern, boolean recurse) { if (secure.okResourceAdminPerm(this)) { // Try to resolve, so that fragments attach. getUpdatedState(new BundleImpl [] { this }); final Vector res = secure.callFindEntries(current(), path, filePattern, recurse); if (!res.isEmpty()) { return res.elements(); } } return null; } /** * */ public URL getEntry(String name) { if (secure.okResourceAdminPerm(this)) { checkUninstalled(); try { final BundleGeneration fix = current(); if ("/".equals(name)) { return fix.getURL(0, "/"); } final InputStream is = secure.callGetBundleResourceStream(fix.archive, name, 0); if (is != null) { is.close(); return fix.getURL(0, name); } } catch (final IOException _ignore) { } } return null; } /** * */ public Enumeration getEntryPaths(String path) { if (secure.okResourceAdminPerm(this)) { checkUninstalled(); return secure.callFindResourcesPath(current().archive, path); } else { return null; } } /** * @see org.osgi.framework.Bundle#getHeaders(String locale) */ public Dictionary getHeaders(String locale) { secure.checkMetadataAdminPerm(this); Dictionary res = secure.callGetHeaders0(current(), locale); if (res == null && cachedHeaders != null) { res = cachedHeaders.cloneHD(); // If we went to uninstalled, then use saved value. // Otherwise try again, NYI make sure we don't inf-loop. if (cachedHeaders == null) { return getHeaders(locale); } } return res; } /** * * @see org.osgi.framework.Bundle#getResources(String name) */ public Enumeration getResources(String name) throws IOException { checkUninstalled(); final BundleGeneration current = current(); if (secure.okResourceAdminPerm(this) && !current.isFragment()) { Enumeration e = null; if (getUpdatedState(new BundleImpl [] { this }) != INSTALLED) { if (this instanceof SystemBundle) { e = getClassLoader().getResources(name); } else { final BundleClassLoader cl0 = (BundleClassLoader)current.getClassLoader(); if (cl0 != null) { e = cl0.getResourcesOSGi(name); } } } else { final Vector uv = secure.getBundleClassPathEntries(current, name, false); if (uv != null) { e = uv.elements(); } } if (e != null && e.hasMoreElements()) { return e; } } return null; } /** * * @see org.osgi.framework.Bundle#loadClass() */ public Class loadClass(final String name) throws ClassNotFoundException { if (secure.okClassAdminPerm(this)) { checkUninstalled(); final BundleGeneration current = current(); if (current.isFragment()) { throw new ClassNotFoundException("Can not load classes from fragment/extension bundles"); } // NYI! Fix BundleGeneration if (getUpdatedState(new BundleImpl [] { this }) == INSTALLED) { throw new ClassNotFoundException(resolveFailException.getMessage()); } ClassLoader cl; if (this instanceof SystemBundle) { cl = ((SystemBundle)this).getClassLoader(); } else { cl = current.getClassLoader(); if (cl == null) { throw new IllegalStateException("state is uninstalled?"); } } return cl.loadClass(name); } else { throw new ClassNotFoundException("No AdminPermission to get class: " + name); } } /** * Get the current generation. * */ BundleGeneration current() { return generations.get(0); } /** * Checks if this bundle is an extension bundle that is updated/uninstalled * and needs to be restarted. */ boolean extensionNeedsRestart() { return current().isExtension() && (state & (INSTALLED | UNINSTALLED)) != 0; } /** * Checks if this bundle is attached to a fragment host. */ boolean isAttached() { final BundleGeneration fix = current(); return fix.fragment != null && fix.fragment.hasHosts(); } /** * Returns the name of the bundle's fragment host. Returns null if this is not * a fragment. */ String getFragmentHostName() { final BundleGeneration fix = current(); if (fix.isFragment()) { return fix.fragment.hostName; } else { return null; } } // Lazy bundles in state STARTING must not be actiavted during shutdown boolean triggersActivationPkg(String pkg) { return Bundle.STOPPING != fwCtx.systemBundle.getState() && state == Bundle.STARTING && operation != ACTIVATING && current().isPkgActivationTrigger(pkg); } // Lazy bundles in state STARTING must not be actiavted during shutdown boolean triggersActivationCls(String name) { if (Bundle.STOPPING != fwCtx.systemBundle.getState() && state == Bundle.STARTING && operation != ACTIVATING) { String pkg = ""; final int pos = name.lastIndexOf('.'); if (pos != -1) { pkg = name.substring(0, pos); } return current().isPkgActivationTrigger(pkg); } return false; } /** * */ BundleThread bundleThread() { synchronized (fwCtx.bundleThreads) { if (fwCtx.bundleThreads.isEmpty()) { bundleThread = secure.createBundleThread(fwCtx); } else { bundleThread = (BundleThread)fwCtx.bundleThreads.removeFirst(); } return bundleThread; } } @SuppressWarnings("unchecked") A adaptSecure(Class type) { Object res = null; if (BundleRevision.class.equals(type)) { res = current().bundleRevision; } else if (BundleRevisions.class.equals(type)) { res = new BundleRevisionsImpl(generations); } else if (BundleWiring.class.equals(type)) { BundleRevision bundleRevision = current().bundleRevision; if (bundleRevision != null) { res = bundleRevision.getWiring(); } } else if (fwCtx.startLevelController != null && BundleStartLevel.class.equals(type)) { res = fwCtx.startLevelController.bundleStartLevel(this); } else if (BundleContext.class.equals(type)) { res = bundleContext; } else if (AccessControlContext.class.equals(type)) { res = secure.getAccessControlContext(this); } return (A) res; } boolean usesBundleGeneration(BundleGeneration check) { return generations.contains(check); } boolean hasZombies() { return generations.size() > 1; } boolean isBundleThread(Thread t) { return bundleThread == t; } void resetBundleThread() { bundleThread = null; } // // Private methods // /** * Register all our import and export packages. * */ private void doExportImport() { final BundleGeneration current = current(); if (!current.isFragment()) { // fragments don't export anything themselves. current.bpkgs.registerPackages(); } } /** * Remove a bundles all registered listeners, registered services and used * services. * */ private void removeBundleResources() { fwCtx.listeners.removeAllListeners(bundleContext); final Set> srs = fwCtx.services.getRegisteredByBundle(this); for (final ServiceRegistrationImpl serviceRegistrationImpl : srs) { try { serviceRegistrationImpl.unregister(); } catch (final IllegalStateException ignore) { // Someone has unregistered the service after stop completed. // This should not occur, but we don't want get stuck in // an illegal state so we catch it. } } final Set> s = fwCtx.services.getUsedByBundle(this); for (final ServiceRegistrationImpl sri : s) { sri.ungetService(this, false); } } /** * Check if bundle is in state UNINSTALLED. If so, throw exception. */ private void checkUninstalled() { if (state == UNINSTALLED) { throw new IllegalStateException("Bundle is in UNINSTALLED state"); } } /** * State is resolved, allowing bundle package access. *

* State is * Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING *

*/ boolean isResolved() { return (state & (RESOLVED | STARTING | ACTIVE | STOPPING)) != 0; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Main.java0000644000175000017500000014453612346513666026731 0ustar felixfelix/* * Copyright (c) 2003-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.FrameworkEvent; import org.osgi.framework.launch.Framework; import org.osgi.framework.launch.FrameworkFactory; import org.osgi.framework.startlevel.FrameworkStartLevel; /** * This is the main startup code for the framework and enables * basic operations as install, start, stop, uninstall * and update. * * @author Jan Stein, Erik Wistrand, Mats-Ola Persson, Gunnar Ekolin */ public class Main { // Main object static Main main; // Verbosity level of printouts. 0 is low. int verbosity; // Will be filled in from manifest entry during startup String version = ""; // Top directory (excluding trailing /) String topDir = ""; // Set to true if JRE is started without any arguments boolean bZeroArgs; // Save beginning start level as long as true boolean saveStartLevel = true; // will be initialized by main() - up for anyone for grabbing public String bootText; // Framework properties, i.e., configuration properties from -Fkey=value Map fwProps = new HashMap(); // System properties, i.e., configuration properties from -Dkey=value Map sysProps = new HashMap(); static public final String JARDIR_PROP = "org.knopflerfish.gosg.jars"; static public final String JARDIR_DEFAULT = "file:jars/;" + FWResourceURLStreamHandler.PROTOCOL + ":jars/"; static public final String XARGS_INIT = "init.xargs"; static public final String XARGS_RESTART = "restart.xargs"; static public final String FWPROPS_XARGS = "fwprops.xargs"; static public final String CMDIR_PROP = "org.knopflerfish.bundle.cm.store"; static public final String CMDIR_DEFAULT = "cmdir"; static public final String VERBOSITY_PROP = "org.knopflerfish.framework.main.verbosity"; static public final String VERBOSITY_DEFAULT = "0"; /** * Name of framework property controlling whether to write an * FWPROPS_XARGS file or not at startup. */ static public final String WRITE_FWPROPS_XARGS_PROP = "org.knopflerfish.framework.main.write.fwprops.xargs"; static public final String XARGS_WRITESYSPROPS_PROP = "org.knopflerfish.framework.main.xargs.writesysprops"; static public final String XARGS_DEFAULT = "default"; static public final String PRODVERSION_PROP = "org.knopflerfish.prodver"; static public final String BOOT_TEXT_PROP = "org.knopflerfish.framework.main.bootText"; /** * Default values for some framework properties. */ Map defaultFwProps = new HashMap() { private static final long serialVersionUID = 1L; { put(CMDIR_PROP, CMDIR_DEFAULT); }}; FrameworkFactory ff; Framework framework; /** * Help class for starting the OSGi framework. */ public static void main(String[] args) { main = new Main(); main.start(args); System.exit(0); } public Main() { try { // Set the initial verbosity level. final String vpv = System.getProperty(VERBOSITY_PROP); verbosity = Integer.parseInt(null==vpv ? VERBOSITY_DEFAULT: vpv); } catch (final Exception ignored) { } populateSysProps(); // Setup URLStremFactory so that we can use fwresource: FrameworkContext.setupURLStreamHandleFactory(); } protected void start(String[] args) { version = Util.readFrameworkVersion(); final String tstampYear = Util.readTstampYear(); bootText = "Knopflerfish OSGi framework launcher, version " + version + "\n" + "Copyright 2003-" +tstampYear +" Knopflerfish. All Rights Reserved.\n" + "See http://www.knopflerfish.org for more information.\n"; System.out.println(bootText); // Check if framework is started with no args at all. // This typically happens when starting with "java -jar framework.jar" // or similar (e.g by double-clicking on framework.jar) bZeroArgs = (args.length == 0); if (!bZeroArgs) {// Also true if started with only -D/-F/-ff args bZeroArgs = true; for (int i=0; bZeroArgs && i 0 && !w[i].startsWith("#")) { factoryClassName = w[i].trim(); break; } } } catch (final Exception e) { // META-INF/services may be lost when putting framework in Android .apk println("failed to get FrameworkFactory, using default", 6, e); } return getFrameworkFactory(factoryClassName); } public FrameworkFactory getFrameworkFactory(String factoryClassName) { try { println("getFrameworkFactory(" + factoryClassName + ")", 2); final Class clazz = Class.forName(factoryClassName); final Constructor cons = clazz.getConstructor(new Class[] { }); final FrameworkFactory ff = (FrameworkFactory) cons.newInstance(new Object[] { }); return ff; } catch (final Exception e) { error("failed to create " + factoryClassName, e); throw new RuntimeException("failed to create " + factoryClassName + ": " + e); } } URL[] getJarBase() { assertFramework(); String jars = framework.getBundleContext().getProperty(JARDIR_PROP); if(jars == null) { jars = JARDIR_DEFAULT; } final String[] ja = Util.splitwords(jars, ";"); ArrayList res = new ArrayList(); for (int i=0; i 5) { for(int i = 0; i < args.length; i++) { println("argv[" + i + "]=" + args[i], 5); } } // Process all other options. for (int i = 0; i < args.length; i++) { try { if ("-exit".equals(args[i])) { println("Exit.", 0); System.exit(0); } else if (args[i].startsWith("-F")) { // Skip, handled in processProperties(String[]) } else if (args[i].startsWith("-D")) { // Skip, handled in processProperties(String[]) } else if ("-init".equals(args[i])) { // Skip, handled in processProperties(String[]) } else if ("-version".equals(args[i])) { System.out.println("Knopflerfish release: " + readRelease()); System.out.println("Framework version: " + Util.readFrameworkVersion()); printResource("/tstamp"); System.exit(0); } else if ("-help".equals(args[i])) { printResource("/help.txt"); System.exit(0); } else if ("-jvminfo".equals(args[i])) { assertFramework(); printJVMInfo(framework); System.exit(0); } else if ("-ff".equals(args[i])) { // Already handled; skip class name i++; } else if ("-create".equals(args[i])) { if (null!=framework && ((Bundle.RESOLVED)&framework.getState())==0) { throw new IllegalArgumentException ("a framework instance is already created." +" The '-create' command must either be the first command" +" or come directly after a '-shutdown mSEC' command."); } framework = null; } else if ("-install".equals(args[i])) { assertFramework(); if (i+1 < args.length) { final String bundle = args[i+1]; final Bundle b = framework.getBundleContext() .installBundle(completeLocation(bundle), null); println("Installed: ", b); i++; } else { error("No URL for install command"); } } else if ("-istart".equals(args[i])) { assertFramework(); if (i+1 < args.length) { final String bundle = args[i+1]; final Bundle b = framework.getBundleContext() .installBundle(completeLocation(bundle), null); b.start(Bundle.START_ACTIVATION_POLICY); println("Installed and started (policy): ", b); i++; } else { error("No URL for install command"); } } else if ("-launch".equals(args[i])) { bLaunched = doLaunch(); } else if ("-shutdown".equals(args[i])) { if (i+1 < args.length) { i++; final long timeout = Long.parseLong(args[i]); try { if(framework != null) { framework.stop(); final FrameworkEvent stopEvent = framework.waitForStop(timeout); switch (stopEvent.getType()) { case FrameworkEvent.STOPPED: // FW terminated, Main is done! println("Framework terminated", 0); break; case FrameworkEvent.STOPPED_UPDATE: // Automatic FW restart, wait again. println("Framework stopped for update", 0); break; case FrameworkEvent.STOPPED_BOOTCLASSPATH_MODIFIED: // A manual FW restart with new boot class path is needed. println("Framework stopped for bootclasspath update", 0); break; case FrameworkEvent.ERROR: // Stop failed or other error, give up. error("Fatal framework error, terminating.", stopEvent.getThrowable()); break; case FrameworkEvent.WAIT_TIMEDOUT: // Should not happen with timeout==0, give up. error("Framework waitForStop(" +timeout +") timed out!", stopEvent.getThrowable()); break; } println("Framework shutdown", 0); } else { throw new IllegalArgumentException("No framework to shutdown"); } } catch (final Exception e) { error("Failed to shutdown", e); } } else { error("No timout for shutdown command"); } } else if ("-sleep".equals(args[i])) { if (i+1 < args.length) { final long t = Long.parseLong(args[i+1]); try { println("Sleeping " + t + " seconds...", 0); Thread.sleep(t * 1000); } catch (final InterruptedException e) { error("Sleep interrupted."); } i++; } else { error("No time for sleep command"); } } else if ("-start".equals(args[i])) { i = doStartBundle(args, i, Bundle.START_ACTIVATION_POLICY, "Started (policy): "); } else if ("-start_e".equals(args[i])) { i = doStartBundle(args, i, 0, "Started (eager): "); } else if ("-start_et".equals(args[i])) { i = doStartBundle(args, i, Bundle.START_TRANSIENT, "Started (eager,transient): "); } else if ("-start_pt".equals(args[i])) { i = doStartBundle(args, i, Bundle.START_TRANSIENT | Bundle.START_ACTIVATION_POLICY, "Start (policy,transient): "); } else if ("-stop".equals(args[i])) { i = doStopBundle(args, i, 0); } else if ("-stop_t".equals(args[i])) { i = doStopBundle(args, i, Bundle.STOP_TRANSIENT); } else if ("-uninstall".equals(args[i])) { assertFramework(); if (i+1 < args.length) { final long id = getBundleID(framework, args[i+1]); final Bundle b = framework.getBundleContext().getBundle(id); b.uninstall(); println("Uninstalled: ", b); i++; } else { error("No id for uninstall command"); } } else if ("-update".equals(args[i])) { assertFramework(); if (i+1 < args.length) { Bundle[] bl = null; if("ALL".equals(args[i+1])) { bl = framework.getBundleContext().getBundles(); } else { bl = new Bundle[] { framework.getBundleContext().getBundle(getBundleID(framework, args[i+1])) }; } for(int n = 0; bl != null && n < bl.length; n++) { final Bundle b = bl[n]; b.update(); println("Updated: ", b); } i++; } else { error("No id for update command"); } } else if ("-initlevel".equals(args[i])) { assertFramework(); if (i+1 < args.length) { final int n = Integer.parseInt(args[i+1]); final FrameworkStartLevel fsl = framework.adapt(FrameworkStartLevel.class); if (fsl!=null) { fsl.setInitialBundleStartLevel(n); } i++; } else { error("No integer level for initlevel command"); } } else if ("-startlevel".equals(args[i])) { assertFramework(); if (i+1 < args.length) { final int n = Integer.parseInt(args[i+1]); final FrameworkStartLevel fsl = framework.adapt(FrameworkStartLevel.class); if (fsl!=null) { fsl.setStartLevel(n); } i++; } else { error("No integer level for startlevel command"); } } else { error("Unknown option: " + args[i] + "\nUse option -help to see all options"); } } catch (final BundleException e) { final Throwable ne = e.getNestedException(); if (ne != null) { e.getNestedException().printStackTrace(System.err); } else { e.printStackTrace(System.err); } error("Command \"" + args[i] + ((i+1 < args.length && !args[i+1].startsWith("-")) ? " " + args[i+1] : "") + "\" failed, " + e.getMessage()); } catch (final Exception e) { e.printStackTrace(System.err); error("Command \"" + args[i] + ((i+1 < args.length && !args[i+1].startsWith("-")) ? " " + args[i+1] : "") + "\" failed, " + e.getMessage()); } } assertFramework(); if(!bLaunched) { try { bLaunched = doLaunch(); } catch (Throwable t) { if (t instanceof BundleException) { final BundleException be = (BundleException) t; final Throwable ne = be.getNestedException(); if (ne != null) t = ne; } error("Framework launch failed, " + t.getMessage(), t); } } FrameworkEvent stopEvent = null; while (true) { // Ignore interrupted exception. try { stopEvent = framework.waitForStop(0L); switch (stopEvent.getType()) { case FrameworkEvent.STOPPED: // FW terminated, Main is done! println("Framework terminated", 0); return; case FrameworkEvent.STOPPED_UPDATE: // Automatic FW restart, wait again. break; case FrameworkEvent.STOPPED_BOOTCLASSPATH_MODIFIED: // A manual FW restart with new boot class path is needed. return; case FrameworkEvent.ERROR: // Stop failed or other error, give up. error("Fatal framework error, terminating.", stopEvent.getThrowable()); return; case FrameworkEvent.WAIT_TIMEDOUT: // Should not happen with timeout==0, give up. error("Framework waitForStop(0) timed out!", stopEvent.getThrowable()); break; } } catch (final InterruptedException ie) { } } } private int doStopBundle(final String[] args, int i, final int options) { assertFramework(); if (i+1 < args.length) { final long id = getBundleID(framework, args[i+1]); final Bundle b = framework.getBundleContext().getBundle(id); try { b.stop(options); println("Stopped: ", b); } catch (final Exception e) { error("Failed to stop", e); } i++; } else { error("No ID for stop command"); } return i; } private boolean doLaunch() throws BundleException { boolean bLaunched; if (null!=framework && (Bundle.ACTIVE&framework.getState())!=0) { throw new IllegalArgumentException ("a framework instance is already active."); } assertFramework(); framework.start(); bLaunched = true; closeSplash(); println("Framework launched", 0); return bLaunched; } private int doStartBundle(final String[] args, int i, final int options, final String logMsg) throws BundleException { assertFramework(); if (i+1 < args.length) { final long id = getBundleID(framework, args[i+1]); final Bundle b = framework.getBundleContext().getBundle(id); b.start(options); println(logMsg, b); i++; } else { error("No ID for start command"); } return i; } /** * Returns a bundle id from a string. The string is either a number * or the location used for the bundle in the * "-install bundleLocation" or "-istart" command. * @param base Base URL to complete locations with. * @param idLocation bundle id or location of the bundle to lookup */ private long getBundleID(Framework fw, String idLocation) { try { return Long.parseLong(idLocation); } catch (final NumberFormatException nfe) { final Bundle[] bl = fw.getBundleContext().getBundles(); final String loc = completeLocation(idLocation); for(int i = 0; bl != null && i < bl.length; i++) { if(loc.equals(bl[i].getLocation())) { return bl[i].getBundleId(); } } throw new IllegalArgumentException ("Invalid bundle id/location: " +idLocation); } } /** * Complete location relative to topDir. * @param location The location to be completed. */ private String completeLocation(String location) { // Handle file: case where topDir is not "" if(location.startsWith("file:jars/") && !topDir.equals("")) { location = ("file:" + topDir + "/" + location.substring(5)).replace('\\', '/'); println("mangled bundle location to " + location, 2); } final int ic = location.indexOf(":"); if (ic<2 || ic>location.indexOf("/")) { println("location=" + location, 2); final URL[] base = getJarBase(); // URL without protocol complete it. for (int i=0; i e = props.keys(); e.hasMoreElements(); ) { final String key = (String) e.nextElement(); System.out.println(key + ": " + props.get(key)); } System.out.println("\n"); System.out.println("--- Framework properties ---"); final String keyStr = framework.getBundleContext().getProperty("org.knopflerfish.framework.bundleprops.keys"); final String[] keys = Util.splitwords(keyStr != null ? keyStr : "", ","); for (final String key : keys) { System.out.println(key + ": " + framework.getBundleContext().getProperty(key)); } } catch (final Exception e) { e.printStackTrace(); } } // should this be read from the manifest instead? static String readRelease() { return Util.readResource("/release", "0.0.0.snapshot", "UTF-8"); } /** * Helper method which tries to find a default xargs files to use. * Note: Make sure that fwProps are up to date by calling * processProperties(args) before calling this method. * * @throws IOException */ BufferedReader getDefaultXArgs() throws IOException { boolean bInit = Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT .equals(fwProps.get(Constants.FRAMEWORK_STORAGE_CLEAN)); final String fwDirStr = Util.getFrameworkDir(fwProps); // avoid getAbsoluteFile since some profiles don't have this final File fwDir = new File(new File(fwDirStr).getAbsolutePath()); println("fwdir is " + fwDir, 1); if (!bInit) { // Implicit init needed? bInit = !(fwDir.exists() && fwDir.isDirectory()); if (bInit) println("Implicit -init since fwdir does not exist.", 2); } println("init is " +bInit, 2); // avoid getParentFile since some profiles don't have this final String defDirStr = fwDir.getParent(); final File defDir = defDirStr != null ? new File(defDirStr) : null; println("defDir=" +defDir, 5); final File[] dirs = null!=defDir ? new File[]{ fwDir, defDir } : new File[]{ fwDir }; // Determine the root OSGi dir, a.k.a. topDir for (final File dir : dirs) { final File jarsDir = new File(dir,"jars"); if (jarsDir.exists() && jarsDir.isDirectory()) { topDir = dir.getAbsolutePath(); break; } } println("Knopflerfish root directory is " +topDir, 2); final String osName = Alias.unifyOsName(System.getProperty("os.name")); final String[] xargNames = bInit ? new String[]{"init_" +osName +".xargs", XARGS_INIT, "remote-" +XARGS_INIT } : new String[]{XARGS_RESTART}; String xargsFound = null; println("Searching for default xargs file:", 5); xargsSearch: for (int i = 0; idefaultFwProps variable. * *

The org.knopflerfish.gosg.jars system property (if * not defined) is created by scanning the "jars" directory for * subdirs.

* * @see defaultSysProps */ protected void addDefaultProps() { for (final Entry entry : defaultFwProps.entrySet()) { final String key = entry.getKey(); if(!fwProps.containsKey(key)) { final String val = entry.getValue(); println("Using default " + key + "=" + val, 1); fwProps.put(key, val); } else { println("framework prop " + key + "=" + fwProps.get(key), 1); } } // Set version info if(null == fwProps.get(PRODVERSION_PROP)) { fwProps.put(PRODVERSION_PROP, version); } // If jar dir is not specified, default to "file:jars/" and its // subdirs String jars = fwProps.get(JARDIR_PROP); if (jars == null) { jars = sysProps.get(JARDIR_PROP); } if(!(jars == null || "".equals(jars))) { println("old jars=" + jars, 1); } else { final String jarBaseDir = topDir + File.separator + "jars"; println("jarBaseDir=" + jarBaseDir, 2); // avoid getAbsoluteFile since some profiles don't have this final File jarDir = new File(new File(jarBaseDir).getAbsolutePath()); if(jarDir.exists() && jarDir.isDirectory()) { // avoid FileNameFilter since some profiles don't have it final String [] names = jarDir.list(); final List v = new ArrayList(); for (final String name : names) { final File f = new File(jarDir, name); if(f.isDirectory()) { v.add(name); } } final String [] subdirs = new String[v.size()]; v.toArray(subdirs); final StringBuffer sb = new StringBuffer(); sb.append("file:" + jarBaseDir + "/"); for (final String subdir : subdirs) { sb.append(";file:" + jarBaseDir + "/" + subdir + "/"); } sb.append(FWResourceURLStreamHandler.PROTOCOL + ":jars/"); jars = sb.toString().replace('\\', '/'); fwProps.put(JARDIR_PROP, jars); println("scanned " +JARDIR_PROP +"=" + jars, 2); } } } /** * Populates the sysProps Map<String,String> with all entries * from the system properties object. */ void populateSysProps() { final Properties systemProperties = System.getProperties(); final Enumeration systemPropertiesNames = systemProperties.propertyNames(); while (systemPropertiesNames.hasMoreElements()) { try { final String name = (String) systemPropertiesNames.nextElement(); final String value = systemProperties.getProperty(name); sysProps.put(name, value); if (Constants.FRAMEWORK_BEGINNING_STARTLEVEL.equals(name)) { saveStartLevel = false; } println("Initial system property: " +name +"=" +value, 3); } catch (final Exception e) { println("Failed to process system property: " +e, 1, e); } } } /** * Add all entires in the given map to the set of system properties. * * @param props The map with name value pairs to add to the system * properties. */ void mergeSystemProperties(Map props) { final Properties p = System.getProperties(); p.putAll(props); System.setProperties(p); } /** * Do the final processing of framework and system properties before * creating the framework instance using them. * *
    *
  • Perform variable expansion on property values. *
  • System properties are then merged into the real system * properties. *
  • If writeSysProps() is true merge * framework properties into the real system properties. *
  • Add default properties. *
*/ void finalizeProperties() { expandPropValues(sysProps, null); expandPropValues(fwProps, sysProps); addDefaultProps(); mergeSystemProperties(sysProps); if(writeSysProps()) { mergeSystemProperties(fwProps); println("merged Framework to System properties " + fwProps, 2); } } /** * If any of the values in toExpand contains a sub-string * like "${propname}" replace it with value of the named * property in the map if found, else if fallback is * non-null then replace with the value from that map if any. * * @param toExpand Map in which to expand variables in the values. * @param fallback Optional map to get expansion values from if not * found in the map to be expanded. */ void expandPropValues(Map toExpand, Map fallback) { Map all = null; for (final Entry entry : toExpand.entrySet()) { String value = entry.getValue(); if(-1 != value.indexOf("${")) { if (null==all) { all = new HashMap(); if (null!=fallback) { all.putAll(fallback); } all.putAll(toExpand); } for (final Entry allEntry : all.entrySet()) { final String rk = "${" + allEntry.getKey() + "}"; final String rv = allEntry.getValue(); value = Util.replace(value, rk, rv); } entry.setValue(value); println("Expanded property: " +entry.getKey() +"=" +value, 1); } } } /** * If the last to elements in args "-xargs" or "--xargs" then expand * it with arg as argument and replace the last element in args with * the expansion. Otherwise just add arg to args. *

* This expansion is necessarry to allow redefinition of a system * property after inclusion of xargs-file that sets the same property. * * @param args The list to add elements to. * @param arg The element to add. */ private void addArg(List args, String arg) { if (0==args.size()) { args.add(arg); } else { final String lastArg = args.get(args.size()-1); if ("-xargs".equals(lastArg) || "--xargs".equals(lastArg)) { final String[] exArgs = expandArgs( new String[]{ lastArg, arg } ); args.remove(args.size()-1); for (final String exArg : exArgs) { args.add(exArg); } } else { args.add(arg); } } } /** * Helper method when OS shell does not allow long command lines. This * method has now days become the only reasonable way to start the * framework due to the amount of properties. * *

* Loads a specified file or URL and * creates a new String array where each entry corresponds to entries * in the loaded file. *

* *

* File format:
* *

    *
  • Each line starting with '-D' or '-F' is used dirctly as an * entry in the new command line array. *
  • Each line of length zero is ignored. *
  • Each line starting with '#' is ignored. *
  • Lines starting with '-' is used a command with optional argument * after space. *
  • All other lines is used directly as an entry to the new * command line array. *
*

* * @param xargsPath The URL to load the xargs-file from. The URL * protcoll defaults to "file:". File URLs are * first search for in the parent directory of the * current FW-dir, then in the current working directory. * @param oldArgs The command line arguments as it looks before * the file named in xargsPath have been * expanded. * @return array with command line options loaded from * xargsPath suitable to be merged into * argv by the caller. */ String [] loadArgs(String xargsPath, String[] oldArgs) { // out result final List v = new ArrayList(); BufferedReader in = null; try { if (XARGS_DEFAULT.equals(xargsPath)) { processProperties(oldArgs); in = getDefaultXArgs(); } else { in = getXargsReader(xargsPath); } StringBuffer contLine = new StringBuffer(); String line = null; String tmpline = null; for(tmpline = in.readLine(); tmpline != null; tmpline = in.readLine()) { tmpline = tmpline.trim(); // check for line continuation char and // build up line until a line without such a mark is found. if(tmpline.endsWith("\\")) { // found continuation mark, store actual line to // buffered continuation line tmpline = tmpline.substring(0, tmpline.length() - 1); if(contLine == null) { contLine = new StringBuffer(tmpline); } else { contLine.append(tmpline); } // read next line continue; } else { // No continuation mark, gather stored line + newly read line if(contLine != null) { contLine.append(tmpline); line = contLine.toString(); contLine = null; } else { // this is the normal case if no continuation char is found // or any buffered line is found line = tmpline; } } if(line.startsWith("-D")) { // Preserve System property addArg(v,line); } else if(line.startsWith("-F")) { // Preserve framework property addArg(v,line); } else if(line.startsWith("#")) { // Ignore comments } else if(line.startsWith("-")) { // Split command that contains a ' ' int two args final int i = line.indexOf(' '); if (i != -1) { addArg(v, line.substring(0,i)); line = line.substring(i).trim(); if(line.length() > 0) { addArg(v, line); } } else { addArg(v, line); } } else if(line.length() > 0) { // Add argument addArg(v,line); } } // Write to framework properties. This should be the primary // source for all code, including the framework itself. // framework.props.setProperties(sysProps); } catch (final Exception e) { if(e instanceof RuntimeException) { throw (RuntimeException)e; } throw new IllegalArgumentException("xargs loading failed: " + e); } finally { if (null!=in) { try { in.close(); } catch (final IOException ignore) { } } } final String [] args2 = new String[v.size()]; v.toArray(args2); return args2; } private BufferedReader getXargsReader(String xargsPath) throws IOException { BufferedReader in = null; println("Searching for xargs file with '" +xargsPath +"'.", 2); // 1) Search in parent dir of the current framework directory final String fwDirStr = Util.getFrameworkDir(fwProps); // avoid getAbsoluteFile() since some profiles don't have this final File fwDir = new File(new File(fwDirStr).getAbsolutePath()); // avoid getParentFile() since some profiles don't have this final String defDirStr = fwDir.getParent(); final File defDir = defDirStr != null ? new File(defDirStr) : null; if (null!=defDir) { // Make the file object absolute before calling exists(), see // http://forum.java.sun.com/thread.jspa?threadID=428403&messageID=2595075 // for details. final File f = new File(new File(defDir,xargsPath).getAbsolutePath()); println(" trying " +f, 5); if(f.exists()) { println("Loading xargs file " + f, 1); in = new BufferedReader(new FileReader(f)); } } // 2) Search in the current working directory if (null==in) { // Make the file object absolute before calling exists(), see // http://forum.java.sun.com/thread.jspa?threadID=428403&messageID=2595075 // for details. final File f = new File(new File(xargsPath).getAbsolutePath()); println(" trying " +f, 5); if(f.exists()) { println("Loading xargs file " + f, 1); in = new BufferedReader(new FileReader(f)); } } // 3) Try argument as URL if it contains ':'. if (in == null && xargsPath.indexOf(':') != -1) { try { println(" trying URL " +xargsPath, 5); final URL url = new URL(xargsPath); println("Loading xargs url " + url, 1); in = new BufferedReader(new InputStreamReader(url.openStream())); } catch (final MalformedURLException _ignore) { } } // 4) Try as resource if (null==in) { ClassLoader cl = getClass().getClassLoader(); while (cl != null) { InputStream is = cl.getResourceAsStream(xargsPath); if (is != null) { in = new BufferedReader(new InputStreamReader(is)); break; } cl = cl.getParent(); } } if (null==in) { throw new FileNotFoundException("Didn't find xargs file: " + xargsPath); } return in; } // If a splash screen hash been shown, try to close it. void closeSplash() { // User reflection, and ignore errors since this is only supported // in Java SE 6. try { final Class splashScreenCls = Class.forName("java.awt.SplashScreen"); final Method getSplashScreenMethod = splashScreenCls.getMethod("getSplashScreen", (Class[]) null); final Object splashScreen = getSplashScreenMethod.invoke( (Object) null, (Object[])null); if (null!=splashScreen) { final Method closeMethod = splashScreenCls.getMethod("close", (Class[]) null); closeMethod.invoke(splashScreen, (Object[]) null); } } catch (final Exception e) { // Ignore any error. println("close splash screen: ", 6, e); } } /** * Print string to System.out if level >= current verbosity. * * @param s String to print. * @param level print level. */ void println(String s, int level) { println(s, level, null); } void println(String s, Bundle b) { println(s + b.getLocation() + " (id#" + b.getBundleId() + ")", 1); } void println(String s, int level, Exception e) { if(verbosity >= level) { System.out.println((level > 0 ? ("#" + level + ": ") : "") + s); if(e != null) { e.printStackTrace(); } } } /** * Report error and exit. */ void error(final String s) { error(s, null); } void error(final String s, final Throwable t) { System.err.println("Error: " + s); if(t != null) { t.printStackTrace(); } System.exit(1); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleHooks.java0000644000175000017500000001523212346513666030250 0ustar felixfelix/* * Copyright (c) 2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.hooks.bundle.CollisionHook; import org.osgi.framework.hooks.bundle.EventHook; import org.osgi.framework.hooks.bundle.FindHook; class BundleHooks { final private FrameworkContext fwCtx; BundleHooks(FrameworkContext fwCtx) { this.fwCtx = fwCtx; } Bundle filterBundle(BundleContextImpl bc, Bundle bundle) { if(bundle == null) { return bundle; } final List> srl = fwCtx.services.get(FindHook.class.getName()); if (srl == null || srl.isEmpty()) { return bundle; } else { final ArrayList bl = new ArrayList(); bl.add(bundle); filterBundles(bc, bl); return bl.isEmpty() ? null : bundle; } } void filterBundles(BundleContextImpl bc, Collection bundles) { final List> srl = fwCtx.services.get(FindHook.class.getName()); if (srl != null) { final RemoveOnlyCollection filtered = new RemoveOnlyCollection(bundles); for (final ServiceRegistrationImpl serviceRegistrationImpl : srl) { final ServiceReferenceImpl sr = serviceRegistrationImpl.reference; final FindHook fh = (FindHook) sr.getService(fwCtx.systemBundle); if (fh != null) { try { fh.find(bc, filtered); } catch (final Exception e) { fwCtx.frameworkError(bc, new BundleException("Failed to call Bundle FindHook #" + sr.getProperty(Constants.SERVICE_ID), e)); } } } } } void filterBundleEventReceivers(final BundleEvent evt, final HashSet syncBundleListeners, final HashSet bundleListeners) { final List> eventHooks = fwCtx.services.get(EventHook.class.getName()); synchronized (fwCtx.listeners.syncBundleListeners) { syncBundleListeners.addAll(fwCtx.listeners.syncBundleListeners); } synchronized (fwCtx.listeners.bundleListeners) { if(bundleListeners != null) { bundleListeners.addAll(fwCtx.listeners.bundleListeners); } } if(eventHooks != null) { final HashSet bundleContexts = new HashSet(); for (final ListenerEntry le : syncBundleListeners) { bundleContexts.add(le.bc); } if(bundleListeners != null) { for (final ListenerEntry le : bundleListeners) { bundleContexts.add(le.bc); } } final int unfilteredSize = bundleContexts.size(); final RemoveOnlyCollection filtered = new RemoveOnlyCollection(bundleContexts); for (final ServiceRegistrationImpl serviceRegistrationImpl : eventHooks) { final ServiceReferenceImpl sr = serviceRegistrationImpl.reference; final EventHook eh = (EventHook)sr.getService(fwCtx.systemBundle); if (eh != null) { try { eh.event(evt, filtered); } catch (final Exception e) { fwCtx.frameworkError(fwCtx.systemBundle, new BundleException("Failed to call Bundle EventHook #" + sr.getProperty(Constants.SERVICE_ID), e)); } } } if (unfilteredSize != bundleContexts.size()) { for (final ListenerEntry le : syncBundleListeners) { if(!bundleContexts.contains(le.bc)) { syncBundleListeners.remove(le); } } if(bundleListeners != null) { for (final ListenerEntry le : bundleListeners) { if(!bundleContexts.contains(le.bc)) { bundleListeners.remove(le); } } } } } } void filterCollisions(int mode, Bundle b, Collection bundles) { final List> srl = fwCtx.services.get(CollisionHook.class.getName()); if (srl != null) { final RemoveOnlyCollection filtered = new RemoveOnlyCollection(bundles); for (final ServiceRegistrationImpl serviceRegistrationImpl : srl) { final ServiceReferenceImpl sr = serviceRegistrationImpl.reference; final CollisionHook ch = (CollisionHook) sr.getService(fwCtx.systemBundle); if (ch != null) { try { ch.filterCollisions(mode, b, filtered); } catch (final Exception e) { fwCtx.frameworkError(b, new BundleException("Failed to call Bundle CollisionHook #" + sr.getProperty(Constants.SERVICE_ID), e)); } } } } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ContentHandlerWrapper.java0000644000175000017500000001513512346513666032306 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.IOException; import java.net.ContentHandler; import java.net.URLConnection; import org.osgi.framework.Constants; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.osgi.service.url.URLConstants; /** * Wrapper which delegates an MIME ContentHandlers * OSGi registered ContentHandlers * *

* Each instance of ContentHandlerWrapper tracks ContentHandlers * for a named MIME type and selects the best from all available services. *

*/ public class ContentHandlerWrapper extends ContentHandler { FrameworkContext framework; String mimetype; String filter; ServiceReference best; ContentHandlerWrapper(FrameworkContext framework, String mimetype) { this.framework = framework; this.mimetype = mimetype; filter = "(&" + "(" + Constants.OBJECTCLASS + "=" + ContentHandler.class.getName() + ")" + "(" + URLConstants.URL_CONTENT_MIMETYPE + "=" + mimetype + ")" + ")"; final ServiceListener serviceListener = new ServiceListener() { public void serviceChanged(ServiceEvent evt) { @SuppressWarnings("unchecked") final ServiceReference ref = (ServiceReference) evt.getServiceReference(); switch (evt.getType()) { case ServiceEvent.MODIFIED: // fall through case ServiceEvent.REGISTERED: if (best == null) { updateBest(); return ; } if (compare(best, ref) > 0) { best = ref; } break; case ServiceEvent.MODIFIED_ENDMATCH: // fall through case ServiceEvent.UNREGISTERING: if (best.equals(ref)) { best = null; } } } }; try { framework.systemBundle.bundleContext.addServiceListener(serviceListener, filter); } catch (final Exception e) { throw new IllegalArgumentException("Could not register service listener for content handler: " + e); } if (framework.debug.url) { framework.debug.println("created wrapper for " + mimetype + ", filter=" + filter); } } private int compare(ServiceReference ref1, ServiceReference ref2) { final Object tmp1 = ref1.getProperty(Constants.SERVICE_RANKING); final Object tmp2 = ref2.getProperty(Constants.SERVICE_RANKING); final int r1 = (tmp1 instanceof Integer) ? ((Integer)tmp1).intValue() : 0; final int r2 = (tmp2 instanceof Integer) ? ((Integer)tmp2).intValue() : 0; if (r2 == r1) { final Long i1 = (Long)ref1.getProperty(Constants.SERVICE_ID); final Long i2 = (Long)ref2.getProperty(Constants.SERVICE_ID); return i1.compareTo(i2); } else { return r2 -r1; } } private void updateBest() { try { @SuppressWarnings("unchecked") final ServiceReference[] refs = (ServiceReference[]) framework.systemBundle.bundleContext .getServiceReferences(ContentHandler.class.getName(), filter); if (refs != null) { best = refs[0]; for (int i = 1; i < refs.length; i++) { if (compare(best, refs[i]) > 0) { best = refs[i]; } } } } catch (final Exception e) { // TODO, handle differently!? this should not happen. throw new IllegalArgumentException("Could not register url handler: " + e); } } private ContentHandler getService() { ContentHandler obj; try { if (best == null) { updateBest(); } if (best == null) { throw new IllegalStateException("null: Lost service for protocol="+ mimetype); } obj = framework.systemBundle.bundleContext.getService(best); if (obj == null) { throw new IllegalStateException("null: Lost service for protocol=" + mimetype); } } catch (final Exception e) { throw new IllegalStateException("null: Lost service for protocol=" + mimetype); } return obj; } @Override public Object getContent(URLConnection urlc) throws IOException { return getService().getContent(urlc); } @Override public Object getContent(URLConnection urlc, @SuppressWarnings("rawtypes") Class[] classes) throws IOException { return getService().getContent(urlc, classes); } @Override public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("ContentHandlerWrapper["); final ServiceReference ref = best; sb.append("mimetype=" + mimetype); if(ref != null) { sb.append(", id=" + ref.getProperty(Constants.SERVICE_ID)); sb.append(", rank=" + ref.getProperty(Constants.SERVICE_RANKING)); } else { sb.append(" no service tracked"); } sb.append("]"); return sb.toString(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/IteratorIteratorSorted.java0000644000175000017500000000700312346513666032514 0ustar felixfelix/* * Copyright (c) 2012-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.*; /** * Meta Iterator that takes sorted list and returns * a sorted result. * * @author Jan Stein */ public class IteratorIteratorSorted
implements Iterator { final private Iterator [] iter; final private A [] top; final private Util.Comparator comp; int size; public IteratorIteratorSorted(List> ilist, Util.Comparator comp) { this.comp = comp; size = ilist.size(); @SuppressWarnings("unchecked") Iterator [] iters = new Iterator [size + 1]; iter = iters; @SuppressWarnings("unchecked") A[] topA = (A[]) new Object[size + 1]; top = topA; int pos = 1; for (Iterator> i = ilist.iterator(); i.hasNext(); ) { Iterator si = i.next(); if (si.hasNext()) { top[pos] = si.next(); iter[pos++] = si; } else { size--; } } for (pos = size / 2; pos > 0; pos--) { balance(pos); } } public boolean hasNext() { return size > 0; } public void remove() { throw new UnsupportedOperationException(); } public A next() { if (hasNext()) { A res = top[1]; if (iter[1].hasNext()) { top[1] = iter[1].next(); } else { top[1] = top[size]; iter[1] = iter[size--]; } balance(1); return res; } throw new NoSuchElementException(); } /** * Balance heap. */ private void balance(int current) { A tmp = top[current]; Iterator itmp = iter[current]; int child; while (current * 2 <= size) { child = current * 2; if (child != size && comp.compare(top[child + 1], top[child]) > 0) { child++; } if (comp.compare(top[child], tmp) > 0) { top[current] = top[child]; iter[current] = iter[child]; } else { break; } current = child; } top[current] = tmp; iter[current] = itmp; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Validator.java0000644000175000017500000000375012346513666027762 0ustar felixfelix/* * Copyright (c) 2009-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.security.cert.X509Certificate; import java.util.List; /** * Interface for certificate validators. * * @author Jan Stein */ public interface Validator { /** * Check if a certificate chain is to be trusted. * * @return true, if validator trusts certificate chain, otherwise false. */ boolean validateCertificateChain(List certs); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleURLConnection.java0000644000175000017500000001166012346513666031650 0ustar felixfelix/* * Copyright (c) 2003-2012, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.*; import java.net.*; import java.security.Permission; import org.osgi.framework.AdminPermission; /** * Bundle URL handling. * * @author Jan Stein, Gunnar Ekolin */ class BundleURLConnection extends URLConnection { // Should maybe only allow the bundle that fetched the URL to connect? final static Permission ADMIN_PERMISSION = new AdminPermission( (String)null, AdminPermission.RESOURCE); private BundleResourceStream is = null; /** * Handle to the current framework instance used in the conversion * from bundle id on string form in the URL to the actual bundle * instance. */ private FrameworkContext fwCtx; /** The bundle that provides the data for this URL. */ private BundleImpl bundle; private int contentLength; private String contentType; private long lastModified; BundleURLConnection(URL u, FrameworkContext fwCtx) { super(u); this.fwCtx = fwCtx; } /** * Analyzes the URL to determine the bundle and which of its related * bundle archives that actually provides the contents of this * URL. The bundle is stored in the private member field * bundle for later use, the bundle archive is returned. * * @return The bundle archive that provides the contents of this * bundle URL. */ private BundleArchive getBundleArchive() { bundle = null; long gen = 0; try { String s = url.getHost(); int i = s.indexOf('!'); if (i >= 0) { s = s.substring(0,i); } i = s.indexOf('.'); if (i >= 0) { gen = Long.parseLong(s.substring(i+1)); s = s.substring(0,i); } bundle = (BundleImpl) fwCtx.bundles.getBundle(Long.parseLong(s)); } catch (NumberFormatException _ignore) { } if (bundle != null) { return bundle.getBundleArchive(gen); } return null; } public void connect() throws IOException { if (!connected) { final BundleArchive a = getBundleArchive(); if (a != null) { // Some storage kinds (e.g., expanded storage of sub-JARs) // requieres the Framework's permisisons to allow access // thus we must call bundleArchive.getInputStream() // via doPrivileged(). int port = url.getPort(); is = bundle.secure.callGetBundleResourceStream(a, url.getFile(), port != -1 ? port : 0); } if (is != null) { connected = true; if(BundleClassLoader.bDalvik) { contentLength = -1; } else { contentLength = (int)is.getContentLength(); } contentType = URLConnection.guessContentTypeFromName(url.getFile()); lastModified = a.getLastModified(); } else { throw new IOException("URL not found"); } } } public InputStream getInputStream() throws IOException { connect(); return is; } public String getContentType() { try { connect(); return contentType; } catch (IOException e) { return null; } } public int getContentLength() { try { connect(); return contentLength; } catch (IOException e) { return -1; } } public long getLastModified() { try { connect(); return lastModified; } catch (IOException e) { return 0; } } public Permission getPermission() throws IOException { return ADMIN_PERMISSION; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleWireImpl.java0000644000175000017500000001120012346513666030704 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWire; import org.osgi.framework.wiring.BundleWiring; public class BundleWireImpl implements BundleWire { private final BundleCapability capability; private final BundleRequirement requirement; private final BundleGeneration providerGen; private final BundleGeneration requirerGen; BundleWireImpl(BundleCapability capability, BundleGeneration provider, BundleRequirement requirement, BundleGeneration requirer) { this.capability = capability; this.providerGen = provider; this.requirement = requirement; this.requirerGen = requirer; } @Override public BundleCapability getCapability() { return capability; } @Override public BundleRequirement getRequirement() { return requirement; } @Override public BundleWiring getProviderWiring() { return providerGen.bundleRevision.getWiring(); } @Override public BundleWiring getRequirerWiring() { return requirerGen.bundleRevision.getWiring(); } @Override public BundleRevision getProvider() { // TODO What should we return if getWiring() is null return providerGen.bundleRevision; } @Override public BundleRevision getRequirer() { // TODO What should we return if getWiring() is null return requirerGen.bundleRevision; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((capability == null) ? 0 : capability.hashCode()); result = prime * result + ((providerGen == null) ? 0 : providerGen.hashCode()); result = prime * result + ((requirement == null) ? 0 : requirement.hashCode()); result = prime * result + ((requirerGen == null) ? 0 : requirerGen.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof BundleWireImpl)) { return false; } BundleWireImpl other = (BundleWireImpl) obj; if (capability == null) { if (other.capability != null) { return false; } } else if (!capability.equals(other.capability)) { return false; } if (providerGen == null) { if (other.providerGen != null) { return false; } } else if (!providerGen.equals(other.providerGen)) { return false; } if (requirement == null) { if (other.requirement != null) { return false; } } else if (!requirement.equals(other.requirement)) { return false; } if (requirerGen == null) { if (other.requirerGen != null) { return false; } } else if (!requirerGen.equals(other.requirerGen)) { return false; } return true; } BundleGeneration getProviderGeneration() { return providerGen; } BundleGeneration getRequirerGeneration() { return requirerGen; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Util.java0000644000175000017500000011116512346513666026752 0ustar felixfelix/* * Copyright (c) 2003-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; 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.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import org.osgi.framework.Constants; import org.osgi.framework.Version; public class Util { // Type names used for types OSGi attributes in manifest headers. private static final String DOUBLE_TYPE = "Double"; private static final String LONG_TYPE = "Long"; private static final String LIST_TYPE = "List"; private static final String STRING_TYPE = "String"; private static final String VERSION_TYPE = "Version"; /** * Pre OSGi 4.2 property used by KF, replaced by Constants.FRAMEWORK_STORAGE * as of OSGi R4 v4.2. */ static public final String FWDIR_PROP = "org.osgi.framework.dir"; static public final String FWDIR_DEFAULT = "fwdir"; static private final Method nanoTimeMethod = getMethod(System.class, "nanoTime", new Class[] { }); public static String getFrameworkDir(Map props) { String s = props.get(Constants.FRAMEWORK_STORAGE); if (s == null || s.length() == 0) { s = props.get(FWDIR_PROP); } if (s == null || s.length() == 0) { s = System.getProperty(FWDIR_PROP); } if (s == null || s.length() == 0) { s = FWDIR_DEFAULT; } return s; } public static String getFrameworkDir(FrameworkContext ctx) { String s = ctx.props.getProperty(Constants.FRAMEWORK_STORAGE); if (s == null || s.length() == 0) { s = ctx.props.getProperty(FWDIR_PROP); } if (s == null || s.length() == 0) { s = FWDIR_DEFAULT; } return s; } /** * Check for local file storage directory. * * @return A FileTree object of directory or null if no storage is available. */ public static FileTree getFileStorage(FrameworkContext ctx, String name, boolean create) { // See if we have a storage directory final String fwdir = getFrameworkDir(ctx); if (fwdir == null) { return null; } final FileTree dir = new FileTree((new File(fwdir)).getAbsoluteFile(), name); if (dir != null) { if (dir.exists()) { if (!dir.isDirectory()) { throw new RuntimeException("Not a directory: " + dir); } } else { if (create && !dir.mkdirs()) { throw new RuntimeException("Cannot create directory: " + dir); } } } return dir; } public static FileTree getFileStorage(FrameworkContext ctx, String name) { return getFileStorage(ctx, name, true); } /** * Compare to strings formatted as '[.[.]]'. If string is null, * then it counts as ZERO. * * @param ver1 First version string. * @param ver2 Second version string. * @return Return 0 if equals, -1 if ver1 < ver2 and 1 if ver1 > ver2. * @exception NumberFormatException on syntax error in input. */ public static int compareStringVersion(String ver1, String ver2) throws NumberFormatException { int i1, i2; while (ver1 != null || ver2 != null) { if (ver1 != null) { final int d1 = ver1.indexOf("."); if (d1 == -1) { i1 = Integer.parseInt(ver1.trim()); ver1 = null; } else { i1 = Integer.parseInt(ver1.substring(0, d1).trim()); ver1 = ver1.substring(d1 + 1); } } else { i1 = 0; } if (ver2 != null) { final int d2 = ver2.indexOf("."); if (d2 == -1) { i2 = Integer.parseInt(ver2.trim()); ver2 = null; } else { i2 = Integer.parseInt(ver2.substring(0, d2).trim()); ver2 = ver2.substring(d2 + 1); } } else { i2 = 0; } if (i1 < i2) { return -1; } if (i1 > i2) { return 1; } } return 0; } /** * Parse strings of format: * * ENTRY (, ENTRY)* * * @param d Directive being parsed * @param s String to parse * @return A HashSet with enumeration or null if enumeration string was null. * @exception IllegalArgumentException If syntax error in input string. */ public static Set parseEnumeration(String d, String s) { final HashSet result = new HashSet(); if (s != null) { final AttributeTokenizer at = new AttributeTokenizer(s); do { final String key = at.getKey(true); if (key == null) { throw new IllegalArgumentException("Directive " + d + ", unexpected character at: " + at.getRest()); } if (!at.getEntryEnd()) { throw new IllegalArgumentException("Directive " + d + ", expected end of entry at: " + at.getRest()); } result.add(key); } while (!at.getEnd()); return result; } else { return null; } } /** * Parse manifest header values on format: *
   * ENTRY (',' ENTRY)*
   * ENTRY = key (';' key)* (';' PARAM)*
   * PARAM = attribute (':' TYPE)? '=' value
   * PARAM = directive ':=' value
   * TYPE = SCALAR | LIST
   * SCALAR = 'String' | 'Version' | 'Long' | 'Double'
   * LIST = 'List<' SCALAR '>'
   * 
* * The default attribute value type is 'String'. For list values the 'List' * and its following '<' are treated as separate tokens to comply with the * OSGi TCK. * * The parse result is one {@link HeaderEntry}-instance for each entry. * If {@code single} is true then the entry only contains one key that can be * accesses by calling {@link HeaderEntry#getKey()}. * * If {@code unique} is true the attribute values in the map are scalars * otherwise the values from different attribute definitions with the same * name are wrapped in a {@code List}. * * @param a Name of attribute being parsed, for error messages. * @param s String to parse. * @param single If true, only allow one key per ENTRY. * @param unique Only allow unique attributes for each ENTRY. * @param single_entry If true, only allow one ENTRY in {@code s}. * * @return List of {@link HeaderEntry}-object, one per entry in {@code s}. * * @exception IllegalArgumentException If syntax error in input string. */ public static List parseManifestHeader(String a, String s, boolean single, boolean unique, boolean single_entry) { final List res = new ArrayList(); if (s != null) { final AttributeTokenizer at = new AttributeTokenizer(s); do { final HeaderEntry he = new HeaderEntry(a, single); String key = at.getKey(single); if (key == null) { final String msg = "Definition, " + a + ", expected key at: " + at.getRest() + ". Key values are terminated " + "by a ';' or a ',' and may not " + "contain unquoted ':', '=' if multiple keys are allowed."; throw new IllegalArgumentException(msg); } he.keys.add(key); if (!single) { while ((key = at.getKey(false)) != null) { he.keys.add(key); } } String param; while ((param = at.getParam()) != null) { final boolean is_directive = at.isDirective(); if (is_directive) { if (he.directives.containsKey(param)) { final String msg = "Definition, " + a + ", duplicate directive: " + param; throw new IllegalArgumentException(msg); } final String valueStr = at.getValue(false); if (valueStr == null) { final String msg = "Definition, " + a + ", expected value for " + " directive " + param + " at: " + at.getRest(); throw new IllegalArgumentException(msg); } he.directives.put(param, valueStr); } else { // Attribute definition with optional type final Object old = he.attributes.get(param); if (old != null && unique) { final String msg = "Definition, " + a + ", duplicate attribute: " + param; throw new IllegalArgumentException(msg); } final String paramType = at.getParamType(); final boolean keepEscape = paramType != null && paramType.startsWith("List"); final String valueStr = at.getValue(keepEscape); if (valueStr == null) { final String msg = "Definition, " + a + ", expected value for " + " attribute " + param + " at: " + at.getRest(); throw new IllegalArgumentException(msg); } final Object value = toValue(a, param, paramType, valueStr); if (unique) { he.attributes.put(param, value); } else { @SuppressWarnings("unchecked") List oldValues = (List) old; if (oldValues == null) { oldValues = new ArrayList(); he.attributes.put(param, oldValues); } oldValues.add(value); } } } if (at.getEntryEnd()) { res.add(he); } else { throw new IllegalArgumentException("Definition, " + a + ", expected end of entry at: " + at.getRest()); } if (single_entry && !at.getEnd()) { throw new IllegalArgumentException("Definition, " + a + ", expected end of single entry at: " + at.getRest()); } } while (!at.getEnd()); } return res; } /** * Convert an attribute value from string to the requested type. * * The types supported are described in * {@link #parseEntries(String, String, boolean, boolean, boolean)}. * * @param a Name of attribute being parsed, for error messages. * @param p Name of parameter to assign the value to, for error messages. * @param type the type to convert to. * @param value the value to convert. * @return */ private static Object toValue(String a, String param, String type, String value) { Object res; type = type == null ? STRING_TYPE : type.intern(); if (STRING_TYPE == type) { res = value; } else if (LONG_TYPE == type) { try { res = new Long(value.trim()); } catch (final Exception e) { throw (IllegalArgumentException) new IllegalArgumentException("Definition, " +a +", expected value of type Long but found '" +value +"' for attribute '" +param + "'.").initCause(e); } } else if (DOUBLE_TYPE == type) { try { res = new Double(value.trim()); } catch (final Exception e) { throw (IllegalArgumentException) new IllegalArgumentException("Definition, " +a +", expected value of type Double but found '" +value +"' for attribute '" +param + "'.").initCause(e); } } else if (VERSION_TYPE == type) { try { res = new Version(value); } catch (final Exception e) { throw (IllegalArgumentException) new IllegalArgumentException("Definition, " +a +", expected value of type Version but found '" +value +"' for attribute '" +param + "'.").initCause(e); } } else if (type.startsWith(LIST_TYPE)) { String elemType = type.substring(LIST_TYPE.length()).trim(); // Let "List" without any "" default to "List" if (elemType.length()>0) { if ('<' != elemType.charAt(0) || elemType.charAt(elemType.length() - 1) != '>') { throw new IllegalArgumentException ("Definition, " + a + ", expected List type definition '" + type + "' for attribute '" + param + "'."); } elemType = elemType.substring(1, elemType.length() - 1).trim().intern(); } // The default element type is STRING. if (elemType.length()==0) elemType = STRING_TYPE; try { final List elements = splitWords(value, ',', STRING_TYPE!=elemType); final List l = new ArrayList(elements.size()); for (final String elem : elements) { l.add(toValue(a, param, elemType, elem)); } res = l; } catch (final Exception e) { throw (IllegalArgumentException) new IllegalArgumentException ("Definition, " + a + ", expected '" + type + "' value but found '" + value + "' for attribute '" + param + "'.").initCause(e); } } else { throw new IllegalArgumentException("Definition, " +a +", unknown type '" +type +"' for attribute '" +param + "'."); } return res; } /** * Read a resource into a byte array. * * @param name resource name to read * @return byte array with contents of resource. */ static byte[] readResource(String name) throws IOException { final byte[] buf = new byte[1024]; final InputStream in = Util.class.getResourceAsStream(name); try { final ByteArrayOutputStream bout = new ByteArrayOutputStream(); int n; while ((n = in.read(buf)) > 0) { bout.write(buf, 0, n); } return bout.toByteArray(); } finally { try { in.close(); } catch (final Exception ignored) { } } } /** * Read a resource into a String. * * @param name resource name to read * @param defaultValue if no resource is available * @param encoding resource encoding * @return String with contents of resource or supplied default value. */ static String readResource(String file, String defaultValue, String encoding) { try { return (new String(readResource(file), encoding)).trim(); } catch (final Exception e) { return defaultValue; } } /** * Read framework version file */ static String readFrameworkVersion() { return readResource("/version", "0.0.0", "UTF-8"); } /** * Read framework build year from the tstamp-file */ static String readTstampYear() { // tstamp format: "Build EE MMMM d yyyy, HH:mm:ss" String year = readResource("/tstamp", "2013", "UTF-8"); int pos = year.indexOf(','); if (pos>-1) { year = year.substring(0, pos); pos = year.lastIndexOf(' '); if (pos>-1) { year = year.substring(pos+1); } } return year; } /** * Default whitespace string for splitwords(). Value is " \t\n\r") */ protected static String WHITESPACE = " \t\n\r"; /** * Default citation char for splitwords(). Value is '"' */ protected static char CITCHAR = '"'; /** * Utility method to split a string into words separated by whitespace. * *

* Equivalent to splitwords(s, WHITESPACE) *

*/ public static String[] splitwords(String s) { return splitwords(s, WHITESPACE); } /** * Utility method to split a string into words separated by whitespace. * *

* Equivalent to splitwords(s, WHITESPACE, CITCHAR) *

*/ public static String[] splitwords(String s, String whiteSpace) { return splitwords(s, whiteSpace, CITCHAR); } /** * Split a string into words separated by whitespace. *

* Citation chars may be used to group words with embedded whitespace. *

* * @param s String to split. * @param whiteSpace whitespace to use for splitting. Any of the characters in * the whiteSpace string are considered whitespace between words and * will be removed from the result. If no words are found, return an * array of length zero. * @param citChar Citation character used for grouping words with embedded * whitespace. Typically '"' */ public static String[] splitwords(String s, String whiteSpace, char citChar) { boolean bCit = false; // true when inside citation chars. final Vector v = new Vector(); // (String) individual words after splitting StringBuffer buf = new StringBuffer(); int i = 0; while (i < s.length()) { final char c = s.charAt(i); if (bCit || whiteSpace.indexOf(c) == -1) { // Build up word until we breaks on either a citation char or whitespace if (c == citChar) { bCit = !bCit; } else { if (buf == null) { buf = new StringBuffer(); } buf.append(c); } i++; } else { // found whitespace or end of citation, append word if we have one if (buf != null) { v.addElement(buf.toString()); buf = null; } // and skip whitespace so we start clean on a word or citation char while ((i < s.length()) && (-1 != whiteSpace.indexOf(s.charAt(i)))) { i++; } } } // Add possible remaining word if (buf != null) { v.addElement(buf.toString()); } // Copy back into an array final String[] r = new String[v.size()]; v.copyInto(r); return r; } /** * Split a string into words separated by a separator char. * * If the separator char shall be part of a word it must be escaped with a * '\' (\u005C). One level of escaping is consumed by this method. * * @param s String to split. * @param sepChar separator char to split on. * @param trim trim whitespace from the words if {@code true}. * * @return List with the words of the specified string. */ public static List splitWords(String s, char sepChar, boolean trim) { final List res = new ArrayList(); final StringBuffer buf = new StringBuffer(); int pos = 0; final int length = s.length(); boolean esc = false; int end = 0; for (; pos < length; pos++) { if (esc) { esc = false; buf.append(s.charAt(pos)); end = buf.length(); } else { final char c = s.charAt(pos); if (c == '\\') { esc = true; } else if (c == sepChar) { // trim trailing whitespace. if (trim) buf.setLength(end); res.add(buf.toString()); buf.setLength(0); end = 0; } else if (Character.isWhitespace(c)) { if (buf.length()>0 || !trim) { buf.append(c); } } else { buf.append(c); end = buf.length(); } } } if (esc) { throw new IllegalArgumentException("Value ends on escape character"); } // The last element. if (trim) buf.setLength(end); res.add(buf.toString()); return res; } /** * Replace all occurrences of a substring with another string. * *

* The returned string will shrink or grow as necessary depending on the * lengths of v1 and v2. *

* *

* Implementation note: This method avoids using the standard String * manipulation methods to increase execution speed. Using the * replace method does however include two new operations in * the case when matches are found. *

* * * @param s * Source string. * @param v1 * String to be replaced with v2. * @param v2 * String replacing v1. * @return Modified string. If any of the input strings are null, the * source string s will be returned unmodified. If * v1.length == 0, v1.equals(v2) or no occurrences * of v1 is found, also return s unmodified. * * @author Erik Wistrand */ public static String replace(final String s, final String v1, final String v2) { // return quick when nothing to do if (s == null || v1 == null || v2 == null || v1.length() == 0 || v1.equals(v2)) { return s; } int ix = 0; final int v1Len = v1.length(); int n = 0; // count number of occurances to be able to correctly size // the resulting output char array while (-1 != (ix = s.indexOf(v1, ix))) { n++; ix += v1Len; } // No occurances at all, just return source string if (n == 0) { return s; } // Set up an output char array of correct size int start = 0; final int v2Len = v2.length(); final char[] r = new char[s.length() + n * (v2Len - v1Len)]; int rPos = 0; // for each occurance, copy v2 where v1 used to be while (-1 != (ix = s.indexOf(v1, start))) { while (start < ix) r[rPos++] = s.charAt(start++); for (int j = 0; j < v2Len; j++) { r[rPos++] = v2.charAt(j); } start += v1Len; } // ...and add all remaining chars ix = s.length(); while (start < ix) r[rPos++] = s.charAt(start++); // ..ouch. this hurts. return new String(r); } public static String getContent(File f) { DataInputStream in = null; try { in = new DataInputStream(new FileInputStream(f)); return in.readUTF(); } catch (final IOException ignore) { } finally { if (in != null) { try { in.close(); } catch (final IOException ignore) { } } } return null; } public static void putContent(File f, String content) throws IOException { putContent(f, content, true); } public static void putContent(File f, String content, boolean useUTF8) throws IOException { DataOutputStream out = null; try { out = new DataOutputStream(new FileOutputStream(f)); if (useUTF8) { out.writeUTF(content); } else { out.writeChars(content); } } finally { if (out != null) { out.close(); } } } /** * Compare two object. Normally both types are the same, but sometimes its * convenient to avoid creating a template object when using the comparator * for lookup. In the latter case {@code B} would be the type of the key used * in a {@code Comparator}. */ public interface Comparator { public int compare(A a, B b); } /** * Sort a vector with objects comparable using a comparison function. * * @param a Vector to sort * @param cf comparison function */ static public void sort(List a, Comparator cf, boolean bReverse) { sort(a, 0, a.size() - 1, cf, bReverse ? -1 : 1); } /** * Vector QSort implementation. */ static void sort(List a, int lo0, int hi0, Comparator cf, int k) { int lo = lo0; int hi = hi0; A mid; if (hi0 > lo0) { mid = a.get((lo0 + hi0) / 2); while (lo <= hi) { while ((lo < hi0) && (k * cf.compare(a.get(lo), mid) < 0)) { ++lo; } while ((hi > lo0) && (k * cf.compare(a.get(hi), mid) > 0)) { --hi; } if (lo <= hi) { swap(a, lo, hi); ++lo; --hi; } } if (lo0 < hi) { sort(a, lo0, hi, cf, k); } if (lo < hi0) { sort(a, lo, hi0, cf, k); } } } private static void swap(List a, int i, int j) { final A tmp = a.get(i); a.set(i, a.get(j)); a.set(j, tmp); } /** * Do binary search for a package entry in the list with the same version * number add the specifies package entry. * * @param pl Sorted list of package entries to search. * @param c comparator determining the ordering. * @param k The key of the Package entry to search for. * @return index of the found entry. If no entry is found, return * {@code (-(insertion point) - 1)}. The insertion point is * defined as the point at which the key would be inserted into the * list. */ public static int binarySearch(List pl, Comparator c, B k) { int l = 0; int u = pl.size() - 1; while (l <= u) { final int m = (l + u) / 2; final int v = c.compare(pl.get(m), k); if (v > 0) { l = m + 1; } else if (v < 0) { u = m - 1; } else { return m; } } return -(l + 1); // key not found. } private static final byte encTab[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f }; public static String base64Encode(String s) throws IOException { return encode(s.getBytes(), 0); } /** * Encode a raw byte array to a Base64 String. * * @param in Byte array to encode. */ // public static String encode(byte[] in) throws IOException { // return encode(in, 0); // } /** * Encode a raw byte array to a Base64 String. * * @param in Byte array to encode. * @param len Length of Base64 lines. 0 means no line breaks. */ public static String encode(byte[] in, int len) throws IOException { ByteArrayOutputStream baos = null; ByteArrayInputStream bais = null; try { baos = new ByteArrayOutputStream(); bais = new ByteArrayInputStream(in); encode(bais, baos, len); // ASCII byte array to String return (new String(baos.toByteArray())); } finally { if (baos != null) baos.close(); if (bais != null) bais.close(); } } public static void encode(InputStream in, OutputStream out, int len) throws IOException { // Check that length is a multiple of 4 bytes if (len % 4 != 0) throw new IllegalArgumentException("Length must be a multiple of 4"); // Read input stream until end of file int bits = 0; int nbits = 0; int nbytes = 0; int b; while ((b = in.read()) != -1) { bits = (bits << 8) | b; nbits += 8; while (nbits >= 6) { nbits -= 6; out.write(encTab[0x3f & (bits >> nbits)]); nbytes++; // New line if (len != 0 && nbytes >= len) { out.write(0x0d); out.write(0x0a); nbytes -= len; } } } switch (nbits) { case 2: out.write(encTab[0x3f & (bits << 4)]); out.write(0x3d); // 0x3d = '=' out.write(0x3d); break; case 4: out.write(encTab[0x3f & (bits << 2)]); out.write(0x3d); break; } if (len != 0) { if (nbytes != 0) { out.write(0x0d); out.write(0x0a); } out.write(0x0d); out.write(0x0a); } } /** * Merges target with the entries in extra. After this method has returned * target will contain all entries in extra that did not exist in target. */ static void mergeDictionaries(Dictionary target, Dictionary extra) { for (final Enumeration e = extra.keys(); e.hasMoreElements();) { final A key = e.nextElement(); if (target.get(key) == null) { target.put(key, extra.get(key)); } } } /** * Check wild-card filter matches the string */ public static boolean filterMatch(String filter, String s) { return patSubstr(s.toCharArray(), 0, filter.toCharArray(), 0); } /** */ private static boolean patSubstr(char[] s, int si, char[] pat, int pi) { if (pat.length - pi == 0) return s.length - si == 0; if (pat[pi] == '*') { pi++; for (;;) { if (patSubstr(s, si, pat, pi)) return true; if (s.length - si == 0) return false; si++; } } else { if (s.length - si == 0) { return false; } if (s[si] != pat[pi]) { return false; } return patSubstr(s, ++si, pat, ++pi); } } /** * Get method from class */ public static Method getMethod(Class c, String name, Class [] args) { Method m = null; while (true) { try { m = c.getDeclaredMethod(name, args); break; } catch (NoSuchMethodException e) { c = c.getSuperclass(); if (c == null) { return null; } } } m.setAccessible(true); return m; } /** * Use System.nanoTime() if available, otherwise revert to * System.currentTimeMillis(). Return */ public static long timeMillis() { if (nanoTimeMethod != null) { try { Object res = nanoTimeMethod.invoke(null, new Object[] { }); if (res != null) { return ((Long)res).longValue() / 1000000L; } } catch (IllegalAccessException _ignore) { } catch (InvocationTargetException _ignore) { } } return System.currentTimeMillis(); } /** * Class for tokenize an attribute string. */ static class AttributeTokenizer { final String s; int length; int pos = 0; AttributeTokenizer(final String input) { s = input; length = s.length(); } // get word (non-whitespace chars) up to the next non-quoted // ',', ';' or ':', '=' if not valueWord is set String getWord(boolean keepEscapse, boolean valueWord) { skipWhite(); boolean backslash = false; boolean quote = false; final StringBuffer val = new StringBuffer(); int end = 0; loop: for (; pos < length; pos++) { if (backslash) { backslash = false; if (keepEscapse) { val.append('\\'); } val.append(s.charAt(pos)); end = val.length(); } else { final char c = s.charAt(pos); switch (c) { case '"': quote = !quote; end = val.length(); break; case '\\': backslash = true; break; case ':': case ',': case ';': case '=': if (!quote && !(valueWord && (c==':' || c=='='))) { break loop; } // Fall through default: val.append(c); if (!Character.isWhitespace(c)) { end = val.length(); } break; } } } if (quote || backslash || end == 0) { return null; } val.setLength(end); return val.toString(); } String getKey(boolean singleKey) { if (pos >= length) { return null; } final int save = pos; if (s.charAt(pos) == ';') { pos++; } final String res = getWord(false, singleKey); if (res != null) { if (pos == length) { return res; } final char c = s.charAt(pos); if (c == ';' || c == ',') { return res; } } pos = save; return null; } String getParam() { if (pos == length || s.charAt(pos) != ';') { return null; } final int save = pos++; final String res = getWord(false, false); if (res != null) { if (pos < length && s.charAt(pos) == '=') { // Untyped parameter return res; } if (pos < length && s.charAt(pos) == ':') { // Typed parameter or directive return res; } } pos = save; return null; } boolean isDirective() { if (pos + 1 < length && s.charAt(pos) == ':' && s.charAt(pos + 1) == '=') { pos++; return true; } else { return false; } } String getParamType() { if (pos == length || s.charAt(pos) != ':') { return null; } final int save = pos++; final String res = getWord(false, false); if (res != null) { if (pos < length && s.charAt(pos) == '=') { return res; } } pos = save; return null; } String getValue() { return getValue(false); } String getValue(boolean keepEscapes) { if (s.charAt(pos) != '=') { return null; } final int save = pos++; skipWhite(); final String val = getWord(keepEscapes, true); if (val == null) { pos = save; return null; } return val; } boolean getEntryEnd() { final int save = pos; skipWhite(); if (pos == length) { return true; } else if (s.charAt(pos) == ',') { pos++; return true; } else { pos = save; return false; } } boolean getEnd() { final int save = pos; skipWhite(); if (pos == length) { return true; } else { pos = save; return false; } } String getRest() { final String res = s.substring(pos).trim(); return res.length() == 0 ? "" : res; } private void skipWhite() { for (; pos < length; pos++) { if (!Character.isWhitespace(s.charAt(pos))) { break; } } } } /** * A class that holds the parse result for one entry of a manifest header * following the general OSGi manifest header syntax. See * {@link Util#parseManifestHeader()} for * details on the syntax. */ public static class HeaderEntry { final String headerName; final boolean singleKey; final List keys = new ArrayList(); final Map attributes = new HashMap(); final Map directives = new HashMap(); /** * @param singleKey */ HeaderEntry(String headerName, boolean singleKey) { this.headerName = headerName; this.singleKey = singleKey; } public String getKey() { if (singleKey) return keys.get(0); throw new IllegalArgumentException("Requesting single key for multi key header clause"); } public List getKeys() { return keys; } public Map getAttributes() { return attributes; } public Map getDirectives() { return directives; } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/RemoveOnlyCollection.java0000644000175000017500000000454312346513666032151 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.AbstractCollection; import java.util.Collection; import java.util.Iterator; /** * */ class RemoveOnlyCollection extends AbstractCollection { final Collection org; public RemoveOnlyCollection(Collection values) { org = values; } @Override public boolean add(E obj) { throw new UnsupportedOperationException("objects can only be removed"); } @Override public boolean addAll(Collection objs) { throw new UnsupportedOperationException("objects can only be removed"); } @Override public Iterator iterator() { return org.iterator(); } @Override public boolean remove(Object o) { return org.remove(o); } @Override public int size() { return org.size(); } }knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/StartLevelController.java0000644000175000017500000004643012346513666032170 0ustar felixfelix/* * Copyright (c) 2003-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.File; import java.util.List; import java.util.Vector; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; import org.osgi.framework.FrameworkEvent; import org.osgi.framework.FrameworkListener; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceRegistration; import org.osgi.framework.startlevel.BundleStartLevel; import org.osgi.framework.startlevel.FrameworkStartLevel; import org.osgi.service.startlevel.StartLevel; /** * StartLevel service implementation. * */ @SuppressWarnings("deprecation") public class StartLevelController implements Runnable, ServiceFactory { // The version of the StartLevel service API public static final String SPEC_VERSION = "1.1"; // The version of the StartLevel API public static final String API_SPEC_VERSION = "1.0"; final static int START_MIN = 0; final static int START_MAX = Integer.MAX_VALUE; final static String LEVEL_FILE = "currentlevel"; final static String INITIAL_LEVEL_FILE = "initiallevel"; Thread wc; long wcDelay = 2000; boolean bRun = false; Queue jobQueue = new Queue(100); int currentLevel = 0; int initStartLevel = 1; int targetStartLevel = currentLevel; boolean acceptChanges = true; final FrameworkContext fwCtx; FileTree storage; // Set to true indicates startlevel compatibility mode. // all bundles and current start level will be 1 final boolean bCompat /*= false*/; final private boolean readOnly; StartLevelController(FrameworkContext fwCtx) { this.fwCtx = fwCtx; bCompat = fwCtx.props.getBooleanProperty(FWProps.STARTLEVEL_COMPAT_PROP); readOnly = fwCtx.props.getBooleanProperty(FWProps.READ_ONLY_PROP); storage = Util.getFileStorage(fwCtx, "startlevel", !readOnly); } void open() { if (fwCtx.debug.startlevel) { fwCtx.debug.println("startlevel: open"); } final Runnable lastJob = jobQueue.lastElement(); wc = new Thread(fwCtx.threadGroup, this, "startlevel job"); synchronized (lastJob) { bRun = true; wc.start(); if (!acceptChanges) { acceptChanges = true; } // Wait for the last of the jobs scheduled before starting the // framework to complete before return try { lastJob.wait(); } catch (final InterruptedException _ignore) { } } } /** * Load persistent state from storage and set up all actions * necessary to bump bundle states. If no persistent state was found, * try to set the target start level from the beginning start level * framework property. * *

Note that {@link open()} needs to be called for any work to * be done.

*/ void restoreState() { if (fwCtx.debug.startlevel) { fwCtx.debug.println("startlevel: restoreState"); } if (storage != null) { // Set the target start level to go to when open() is called. int startLevel = -1; try { final String s = Util.getContent(new File(storage, LEVEL_FILE)); if (s != null) { startLevel = Integer.parseInt(s); if (fwCtx.debug.startlevel) { fwCtx.debug.println("startlevel: restored level " + startLevel); } } } catch (final Exception _ignored) { } if (startLevel == -1) { // No stored start level to restore, try the beginning start level final String sBeginningLevel = fwCtx.props.getProperty(Constants.FRAMEWORK_BEGINNING_STARTLEVEL); try { startLevel = Integer.parseInt(sBeginningLevel); if (fwCtx.debug.startlevel) { fwCtx.debug.println("startlevel: beginning level " + startLevel); } } catch (final NumberFormatException nfe) { fwCtx.debug.printStackTrace("Invalid number '" + sBeginningLevel + "' in value of property named '" + Constants.FRAMEWORK_BEGINNING_STARTLEVEL + "'.", nfe); } } if (startLevel<0) { startLevel = 1; } setStartLevel0(startLevel, false, false, true); // Restore the initial bundle start level try { final String s = Util.getContent(new File(storage, INITIAL_LEVEL_FILE)); if (s != null) { setInitialBundleStartLevel0(Integer.parseInt(s), false); } } catch (final Exception _ignored) { } } } void close() { if (fwCtx.debug.startlevel) { fwCtx.debug.println("*** closing startlevel service"); } bRun = false; jobQueue.insert(new Runnable() { public void run() { jobQueue.close(); } }); if(wc != null) { try { wc.join(wcDelay * 2); } catch (final Exception ignored) { } wc = null; } } void shutdown() { acceptChanges = false; synchronized (wc) { setStartLevel0(0, false, true, false); while (currentLevel > 0) { try { wc.wait(); } catch (final Exception e) {} } } close(); } public void run() { while(bRun) { try { final Runnable job = jobQueue.removeWait((float)(wcDelay / 1000.0)); if (job != null) { job.run(); synchronized (job) { job.notify(); } } } catch (final Exception ignored) { ignored.printStackTrace(); } } } int getStartLevel() { return currentLevel; } void setStartLevel(final int startLevel) { setStartLevel(startLevel, (FrameworkListener[]) null); } void setStartLevel(final int startLevel, final FrameworkListener... listeners) { fwCtx.perm.checkStartLevelAdminPerm(); if (startLevel <= 0) { throw new IllegalArgumentException("Initial start level must be > 0, is " + startLevel); } if (acceptChanges) { // No start-level changed events if called before open() or after close(). setStartLevel0(startLevel, bRun, false, true, listeners); } } private void setStartLevel0(final int startLevel, final boolean notifyFw, final boolean notifyWC, final boolean storeLevel, final FrameworkListener... listeners) { if (fwCtx.debug.startlevel) { fwCtx.debug.println("startlevel: setStartLevel " + startLevel); } jobQueue.insert(new Runnable() { public void run() { final int sl = bCompat ? 1 : startLevel; targetStartLevel = sl; while (targetStartLevel > currentLevel) { increaseStartLevel(); } while (targetStartLevel < currentLevel) { decreaseStartLevel(); } // Skip level save in mem storage since bundle levels // won't be saved anyway if (storeLevel && storage != null && !readOnly) { try { Util.putContent(new File(storage, LEVEL_FILE), Integer.toString(currentLevel)); } catch (final Exception e) { e.printStackTrace(); } } if (notifyFw) { final FrameworkEvent event = new FrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, fwCtx.systemBundle, null); // Send event to all registered framework listeners fwCtx.listeners.frameworkEvent(event, listeners); } if (notifyWC && wc != null) { synchronized (wc) { wc.notifyAll(); } } } }); } Object lock = new Object(); void increaseStartLevel() { synchronized (lock) { currentLevel++; if (fwCtx.debug.startlevel) { fwCtx.debug.println("startlevel: increaseStartLevel currentLevel=" + currentLevel); } final Vector set = new Vector(); final List bundles = fwCtx.bundles.getBundles(); for (final BundleImpl bs : bundles) { if (canStart(bs)) { if (bs.getStartLevel() == currentLevel) { if (bs.current().archive.getAutostartSetting()!=-1) { set.addElement(bs); } } } } Util.sort(set, BSComparator, false); for (int i = 0; i < set.size(); i++) { final BundleImpl bs = set.elementAt(i); try { if (bs.current().archive.getAutostartSetting()!=-1) { if (fwCtx.debug.startlevel) { fwCtx.debug.println("startlevel: start " + bs); } int startOptions = Bundle.START_TRANSIENT; if (isBundleActivationPolicyUsed(bs.current().archive)) { startOptions |= Bundle.START_ACTIVATION_POLICY; } bs.start(startOptions); } } catch (final IllegalStateException ignore) { // Tried to start an uninstalled bundle, skip } catch (final Exception e) { fwCtx.frameworkError(bs, e); } } } } void decreaseStartLevel() { synchronized (lock) { currentLevel--; final Vector set = new Vector(); final List bundles = fwCtx.bundles.getBundles(); for (final BundleImpl bs : bundles) { if (bs.getState() == Bundle.ACTIVE || (bs.getState() == Bundle.STARTING && bs.current().lazyActivation)) { if (bs.getStartLevel() == currentLevel + 1) { set.addElement(bs); } } } Util.sort(set, BSComparator, true); synchronized (fwCtx.resolver) { for (int i = 0; i < set.size(); i++) { final BundleImpl bs = set.elementAt(i); if (bs.getState() == Bundle.ACTIVE || (bs.getState() == Bundle.STARTING && bs.current().lazyActivation)) { if (fwCtx.debug.startlevel) { fwCtx.debug.println("startlevel: stop " + bs); } try { bs.stop(Bundle.STOP_TRANSIENT); } catch (final Throwable t) { fwCtx.frameworkError(bs, t); } } } } } } boolean canStart(BundleImpl b) { return b.getState() != Bundle.UNINSTALLED; } static final Util.Comparator BSComparator = new Util.Comparator() { public int compare(BundleImpl b1, BundleImpl b2) { int res = b1.getStartLevel() - b2.getStartLevel(); if (res == 0) { res = (int) (b1.getBundleId() - b2.getBundleId()); } return res; } }; int getBundleStartLevel(BundleImpl bundle) { if (bundle.getBundleId() == 0) { return 0; } return bundle.getStartLevel(); } void setBundleStartLevel(final BundleImpl bundle, final int startLevel) { fwCtx.perm.checkExecuteAdminPerm(bundle); if (startLevel <= 0) { throw new IllegalArgumentException("Initial start level must be > 0, is " + startLevel); } if (bundle.getBundleId() == 0) { throw new IllegalArgumentException("System bundle start level cannot be changed"); } fwCtx.perm.callSetStartLevel(bundle, bCompat ? 1 : startLevel); jobQueue.insert(new Runnable() { public void run() { syncStartLevel(bundle); } }); } void syncStartLevel(BundleImpl bs) { try { if (fwCtx.debug.startlevel) { fwCtx.debug.println("syncstartlevel: " + bs); } synchronized (lock) { synchronized (fwCtx.resolver) { if (bs.getStartLevel() <= currentLevel) { final BundleGeneration current = bs.current(); if ((bs.getState() & (Bundle.INSTALLED|Bundle.RESOLVED|Bundle.STOPPING)) != 0 && current.archive.getAutostartSetting()!=-1) { if (fwCtx.debug.startlevel) { fwCtx.debug.println("startlevel: start " + bs); } int startOptions = Bundle.START_TRANSIENT; if (isBundleActivationPolicyUsed(current.archive)) { startOptions |= Bundle.START_ACTIVATION_POLICY; } bs.start(startOptions); } } else if (bs.getStartLevel() > currentLevel) { if ((bs.getState() & (Bundle.ACTIVE|Bundle.STARTING)) != 0) { if (fwCtx.debug.startlevel) { fwCtx.debug.println("startlevel: stop " + bs); } bs.stop(Bundle.STOP_TRANSIENT); } } } } } catch (final Throwable t) { fwCtx.frameworkError(bs, t); } } int getInitialBundleStartLevel() { return initStartLevel; } void setInitialBundleStartLevel(int startLevel) { fwCtx.perm.checkStartLevelAdminPerm(); fwCtx.perm.callSetInitialBundleStartLevel0(this, startLevel); } void setInitialBundleStartLevel0(int startLevel, boolean save) { if(startLevel <= 0) { throw new IllegalArgumentException("Initial start level must be > 0, is " + startLevel); } initStartLevel = bCompat ? 1 : startLevel; if (storage != null && !readOnly && save) { try { Util.putContent(new File(storage, INITIAL_LEVEL_FILE), Integer.toString(initStartLevel)); } catch (final Exception e) { e.printStackTrace(); } } } boolean isBundlePersistentlyStarted(BundleArchive archive) { return archive == null || archive.getAutostartSetting() != -1; } boolean isBundleActivationPolicyUsed(BundleArchive archive) { return archive != null && archive.getAutostartSetting() == Bundle.START_ACTIVATION_POLICY; } public StartLevel getService(Bundle bundle, ServiceRegistration registration) { return new StartLevelImpl(this); } public void ungetService(Bundle bundle, ServiceRegistration registration, StartLevel service) { } public static class StartLevelImpl implements StartLevel { private final StartLevelController st; StartLevelImpl(StartLevelController st) { this.st = st; } public int getBundleStartLevel(Bundle bundle) { return st.getBundleStartLevel(checkBundle(bundle)); } public int getInitialBundleStartLevel() { return st.getInitialBundleStartLevel(); } public int getStartLevel() { return st.getStartLevel(); } public boolean isBundleActivationPolicyUsed(Bundle bundle) { return st.isBundleActivationPolicyUsed(getBundleArchive(bundle)); } public boolean isBundlePersistentlyStarted(Bundle bundle) { return st.isBundlePersistentlyStarted(getBundleArchive(bundle)); } public void setBundleStartLevel(Bundle bundle, int startlevel) { st.setBundleStartLevel(checkBundle(bundle), startlevel); } public void setInitialBundleStartLevel(int startlevel) { st.setInitialBundleStartLevel(startlevel); } public void setStartLevel(int startlevel) { st.setStartLevel(startlevel); } private BundleImpl checkBundle(Bundle b) { if (b instanceof BundleImpl) { final BundleImpl res = (BundleImpl)b; if (res.fwCtx == st.fwCtx) { if (res.state != Bundle.UNINSTALLED) { return res; } throw new IllegalArgumentException("Bundle is in UNINSTALLED state"); } } throw new IllegalArgumentException("Bundle doesn't belong to the same framework as the StartLevel service"); } private BundleArchive getBundleArchive(Bundle b) { final BundleImpl bi = checkBundle(b); final BundleArchive res = bi.current().archive; if (res == null && bi.id != 0) { throw new IllegalArgumentException("Bundle is in UNINSTALLED state"); } return res; } } BundleStartLevel bundleStartLevel(final BundleImpl bi) { return new BundleStartLevelImpl(this, bi); } static class BundleStartLevelImpl implements BundleStartLevel { final StartLevelController st; final BundleImpl bi; BundleStartLevelImpl(final StartLevelController st, final BundleImpl bi) { this.st = st; this.bi = bi; } public Bundle getBundle() { return bi; } public int getStartLevel() { return st.getBundleStartLevel(bi); } public void setStartLevel(int startlevel) { st.setBundleStartLevel(bi, startlevel); } public boolean isPersistentlyStarted() { return st.isBundlePersistentlyStarted(getBundleArchive()); } public boolean isActivationPolicyUsed() { return st.isBundleActivationPolicyUsed(getBundleArchive()); } private BundleArchive getBundleArchive() { final BundleArchive res = bi.current().archive; if (res == null && bi.id != 0) { throw new IllegalArgumentException("Bundle is in UNINSTALLED state"); } return res; } } FrameworkStartLevel frameworkStartLevel(final BundleImpl bi) { return new FrameworkStartLevelImpl(this, bi); } static class FrameworkStartLevelImpl implements FrameworkStartLevel { final StartLevelController st; final BundleImpl bi; public FrameworkStartLevelImpl(StartLevelController startLevelController, BundleImpl bi) { this.st = startLevelController; this.bi = bi; } public Bundle getBundle() { return bi; } public int getStartLevel() { return st.getStartLevel(); } public void setStartLevel(int startlevel, FrameworkListener... listeners) { st.setStartLevel(startlevel, listeners); } public int getInitialBundleStartLevel() { return st.getInitialBundleStartLevel(); } public void setInitialBundleStartLevel(int startlevel) { st.setInitialBundleStartLevel(startlevel); } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Services.java0000644000175000017500000003564712346513666027632 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.ArrayList; import java.util.Collection; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.condpermadmin.ConditionalPermissionAdmin; import org.osgi.service.permissionadmin.PermissionAdmin; /** * Here we handle all the services that are registered in framework. * * @author Jan Stein, Philippe Laporte, Gunnar Ekolin */ class Services { /** * All registered services in the current framework. * Mapping of registered service to class names under which service * is registered. */ HashMap, String[]> services = new HashMap, String[]>(); /** * Mapping of class name to registered service. * The List of registered service are order in with highest * ranked service first. */ private final HashMap>> classServices = new HashMap>>(); /** * Handle to secure call class. */ private PermissionOps secure; FrameworkContext framework; Services(FrameworkContext fwCtx, PermissionOps perm) { this.framework = fwCtx; secure = perm; } void clear() { services.clear(); classServices.clear(); secure = null; framework = null; } /** * Register a service in the framework wide register. * * @param bundle The bundle registering the service. * @param classes The class names under which the service can be located. * @param service The service object. * @param properties The properties for this service. * @return A {@link ServiceRegistration} object. * @exception java.lang.IllegalArgumentException If one of the following is true: *
    *
  • The service object is null.
  • *
  • The defining class of the service parameter is not owned by the bundle.
  • *
  • The service parameter is not a ServiceFactory and is not an * instance of all the named classes in the classes parameter.
  • *
*/ @SuppressWarnings("deprecation") ServiceRegistration register(BundleImpl bundle, String[] classes, Object service, Dictionary properties) { if (service == null) { throw new IllegalArgumentException("Can't register null as a service"); } // Check if service implements claimed classes and that they exist. for (final String classe : classes) { final String cls = classe; if (cls == null) { throw new IllegalArgumentException("Can't register as null class"); } secure.checkRegisterServicePerm(cls); if (bundle.id != 0) { if (cls.equals(org.osgi.service.packageadmin.PackageAdmin.class.getName())) { throw new IllegalArgumentException ("Registeration of a PackageAdmin service is not allowed"); } if (cls.equals(PermissionAdmin.class.getName())) { throw new IllegalArgumentException ("Registeration of a PermissionAdmin service is not allowed"); } if (cls.equals(ConditionalPermissionAdmin.class.getName())) { throw new IllegalArgumentException ("Registeration of a ConditionalPermissionAdmin service is not allowed"); } } if (!(service instanceof ServiceFactory)) { if (!checkServiceClass(service, cls)) { throw new IllegalArgumentException ("Service object is not an instance of " + cls); } } } @SuppressWarnings("rawtypes") final ServiceRegistrationImpl res = new ServiceRegistrationImpl(bundle, service, new PropertiesDictionary(properties, classes, null)); synchronized (this) { services.put(res, classes); for (final String clazz : classes) { List> s = classServices.get(clazz); if (s == null) { s = new ArrayList>(1); classServices.put(clazz, s); } final int ip = Math.abs(Util.binarySearch(s, sComp, res) + 1); s.add(ip, res); } } final ServiceReference r = res.getReference(); bundle.fwCtx.perm .callServiceChanged(bundle.fwCtx, bundle.fwCtx.listeners.getMatchingServiceListeners(r), new ServiceEvent(ServiceEvent.REGISTERED, r), null); return res; } /** * Service ranking changed, reorder registered services * according to ranking. * * @param serviceRegistration The serviceRegistration object. * @param rank New rank of object. */ synchronized void updateServiceRegistrationOrder(ServiceRegistrationImpl sr, String[] classes) { for (final String clazz : classes) { final List> s = classServices.get(clazz); s.remove(sr); s.add(Math.abs(Util.binarySearch(s, sComp, sr) + 1), sr); } } /** * Checks that a given service object is an instance of the given * class name. * * @param service The service object to check. * @param cls The class name to check for. * @throws IllegalArgumentException if the given class is not an * instance of the given class name. */ boolean checkServiceClass(Object service, String cls) { final Class sc = service.getClass(); final ClassLoader scl = secure.getClassLoaderOf(sc); Class c = null; boolean ok = false; try { if (scl != null) { c = scl.loadClass(cls); } else { c = Class.forName(cls); } ok = c.isInstance(service); } catch (final ClassNotFoundException e) { for (Class csc = sc; csc != null; csc = csc.getSuperclass()) { if (cls.equals(csc.getName())) { ok = true; break; } else { final Class [] ic = csc.getInterfaces(); for (int iic = ic.length - 1; iic >= 0; iic--) { if (cls.equals(ic[iic].getName())) { ok = true; break; } } } } } return ok; } /** * Get all service implementing a certain class. * Only used internally by framework. * * @param clazz The class name of requested service. * @return A sorted list of {@link ServiceRegistrationImpl} objects * or null if no services is available. */ synchronized List> get(String clazz) { final List> v = classServices.get(clazz); if (v != null) { @SuppressWarnings({ "rawtypes", "unchecked" }) final List> res = (List>) ((ArrayList) v).clone(); return res; } return null; } /** * Get a service implementing a certain class. * * @param bundle bundle requesting reference * @param clazz The class name of requested service. * @return A {@link ServiceReference} object. */ synchronized ServiceReference get(BundleImpl bundle, String clazz) { try { final ServiceReference[] srs = get(clazz, null, bundle); if (framework.debug.service_reference) { framework.debug.println("get service ref " + clazz + " for bundle " + bundle.location + " = " + (srs != null ? srs[0] : null)); } if (srs != null) { return srs[0]; } } catch (final InvalidSyntaxException _never) { } return null; } /** * Get all services implementing a certain class and then * filter these with a property filter. * * @param clazz The class name of requested service. * @param filter The property filter. * @param bundle bundle requesting reference. can be null if doAssignableToTest is false * (this is not an interface class so don't check) * @param isAssignableToTest whether to if the bundle that registered the service * referenced by this ServiceReference and the specified bundle are both wired to * same source for the registration class. * @return An array of {@link ServiceReference} object. */ synchronized ServiceReference[] get(String clazz, String filter, BundleImpl bundle) throws InvalidSyntaxException { Iterator> s; LDAPExpr ldap = null; if (clazz == null) { if (filter != null) { ldap = new LDAPExpr(filter); final Set matched = ldap.getMatchedObjectClasses(); if (matched != null) { List> v = null; boolean vReadOnly = true;; for (final String match : matched) { final List> cl = classServices.get(match); if (cl != null) { if (v == null) { v = cl; } else { if (vReadOnly) { v = new ArrayList>(v); vReadOnly = false; } v.addAll(cl); } } } if (v != null) { s = v.iterator(); } else { return null; } } else { s = services.keySet().iterator(); } } else { s = services.keySet().iterator(); } } else { final List> v = classServices.get(clazz); if (v != null) { s = v.iterator(); } else { return null; } if (filter != null) { ldap = new LDAPExpr(filter); } } final Collection> res = new ArrayList>(); while (s.hasNext()) { final ServiceRegistrationImpl sr = s.next(); ServiceReference sri = sr.getReference(); if (!secure.okGetServicePerms(sri)) { continue; //sr not part of returned set } if (filter == null || ldap.evaluate(sr.getProperties(), false)) { if (bundle != null) { final String[] classes = services.get(sr); for (int i = 0; i < classes.length; i++) { if (!sri.isAssignableTo(bundle, classes[i])){ sri = null; break; } } } if (sri != null) { res.add(sri); } } } if (res.isEmpty()) { return null; } else { if (bundle != null) { framework.serviceHooks.filterServiceReferences(bundle.bundleContext, clazz, filter, false, res); } else { framework.serviceHooks.filterServiceReferences(null, clazz, filter, true, res); } if (res.isEmpty()) { return null; } else { return res.toArray(new ServiceReference [res.size()]); } } } /** * Remove a registered service. * * @param sr The ServiceRegistration object that is registered. */ synchronized void removeServiceRegistration(ServiceRegistrationImpl sr) { final String[] classes = (String[]) sr.getProperty(Constants.OBJECTCLASS); services.remove(sr); for (final String clazz : classes) { final List> s = classServices.get(clazz); if (s.size() > 1) { s.remove(sr); } else { classServices.remove(clazz); } } } /** * Get all services that a bundle has registered. * * @param b The bundle * @return A set of {@link ServiceRegistration} objects */ synchronized Set> getRegisteredByBundle(Bundle b) { final HashSet> res = new HashSet>(); for (final ServiceRegistrationImpl sr : services.keySet()) { if (sr.bundle == b) { res.add(sr); } } return res; } /** * Get all services that a bundle uses. * * @param b The bundle * @return A set of {@link ServiceRegistration} objects */ synchronized Set> getUsedByBundle(Bundle b) { final HashSet> res = new HashSet>(); for (final ServiceRegistrationImpl sr : services.keySet()) { if (sr.isUsedByBundle(b)) { res.add(sr); } } return res; } static final Util.Comparator,ServiceRegistrationImpl> sComp = new Util.Comparator, ServiceRegistrationImpl>() { /** * Name compare two ServiceRegistrationImpl objects according * to the ServiceReference compareTo. * * @param a ServiceRegistrationImpl to compare. * @param b ServiceRegistrationImpl to compare. * @return Return 0 if equals, negative if first object is less than second * object and positive if first object is larger then second object. */ public int compare(ServiceRegistrationImpl a, ServiceRegistrationImpl b) { return a.reference.compareTo(b.reference); } }; } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleArchive.java0000644000175000017500000001400212346513666030540 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.IOException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; /** * Interface for managing bundle data. * * @author Jan Stein * @author Philippe Laporte * @author Mats-Ola Persson * @author Gunnar Ekolin */ public interface BundleArchive { /** * Autostart setting stopped. * * @see BundleArchive#setAutostartSetting(String) */ public String AUTOSTART_SETTING_STOPPED = "stopped"; /** * Autostart setting eager. * * @see BundleArchive#setAutostartSetting(String) */ public String AUTOSTART_SETTING_EAGER = "eager"; /** * Autostart setting declared activation policy. * * @see BundleArchive#setAutostartSetting(String) */ public String AUTOSTART_SETTING_ACTIVATION_POLICY = "activation_policy"; /** * Get an attribute from the manifest of a bundle. * * Not localized * * @param key Name of attribute to get. * @return A string with result or null if the entry doesn't exists. */ String getAttribute(String key); /** * Get a FileArchive handle to a named Jar file or directory within this * archive. * * @param path Name of Jar file or directory to get. * @return A FileArchive object representing new archive, null if not found. */ FileArchive getFileArchive(String path); /** * Gets all localization entries from this bundle. Will typically read the * file OSGI-INF/bundle_<locale>.properties. * * @param localeFile Filename within archive for localization properties. * @return null or a mapping of the entries. */ Hashtable getLocalizationEntries(String localeFile); /** * @returns the (raw/unlocalized) attributes */ HeaderDictionary getUnlocalizedAttributes(); /** * Get bundle generation associated with this bundle archive. * * @return BundleGeneration object. */ BundleGeneration getBundleGeneration(); /** * Set bundle generation associated with this bundle archive. * * @param BundleGeneration object. */ void setBundleGeneration(BundleGeneration bg); /** * Get bundle identifier for this bundle archive. * * @return Bundle identifier. */ long getBundleId(); /** * Get bundle location for this bundle archive. * * @return Bundle location. */ String getBundleLocation(); /** * Get a BundleResourceStream to named entry inside a bundle. Leading '/' is * stripped. * * @param component Entry to get reference to. * @param ix index of sub archives. A postive number is the classpath entry * index. 0 means look in the main bundle. * @return BundleResourceStream to entry or null if it doesn't exist. */ BundleResourceStream getBundleResourceStream(String component, int ix); /** * Returns an Enumeration of all the paths (String objects) to * entries within the bundle whose longest sub-path matches the supplied path * argument. * * @param name * @return */ Enumeration findResourcesPath(String path); /** * Get stored bundle start level. */ int getStartLevel(); /** * Set stored bundle start level. */ void setStartLevel(int level) throws IOException; /** * Get last modified timestamp. */ long getLastModified(); /** * Set stored last modified timestamp. */ void setLastModified(long timemillisecs) throws IOException; /** * Get auto-start setting. * * @return the autostart setting. "-1" if bundle not started. */ int getAutostartSetting(); /** * Set the auto-start setting. * * @param setting the autostart setting to use. */ void setAutostartSetting(int setting) throws IOException; /** * @return the location of the cached bundle. */ String getJarLocation(); /** * Get certificate chains associated with with bundle archive. * * @param onlyTrusted Only return trusted certificates. * @return All certificates or null if bundle is unsigned. */ ArrayList> getCertificateChains(boolean onlyTrusted); /** * Mark certificate associated with with bundle archive as trusted. * */ void trustCertificateChain(List trustedChain); /** * Remove bundle archive from persistent storage. */ void purge(); /** * Close archive and all its open files. */ void close(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/IteratorIterator.java0000644000175000017500000000475612346513666031347 0ustar felixfelix/* * Copyright (c) 2010-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.*; /** * Meta Iterator * * @author Jan Stein */ public class IteratorIterator
implements Iterator { final private Iterator> iter; /* The current iterator */ private Iterator current = null; public IteratorIterator(List> ilist) { iter = ilist.iterator(); if (iter.hasNext()) { current = iter.next(); } else { // We need an empty iterator as current, reuse iter. @SuppressWarnings("unchecked") Iterator empty = (Iterator) iter; current = empty; } } public boolean hasNext() { return getIterator().hasNext(); } public void remove() { current.remove(); } public A next() { return getIterator().next(); } private Iterator getIterator() { while (!current.hasNext() && iter.hasNext()) { current = iter.next(); } return current; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/FrameworkFactoryImpl.java0000644000175000017500000000376712346513666032154 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Map; import org.osgi.framework.launch.Framework; import org.osgi.framework.launch.FrameworkFactory; public class FrameworkFactoryImpl implements FrameworkFactory { public FrameworkFactoryImpl() { } public Framework newFramework(Map configuration) { final FrameworkContext ctx = new FrameworkContext(configuration); return ctx.systemBundle; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/FWProps.java0000644000175000017500000004474112346513666027402 0ustar felixfelix/* * Copyright (c) 2009-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.net.URLClassLoader; import java.util.Dictionary; import java.util.Hashtable; import java.util.Locale; import java.util.Map; import java.util.StringTokenizer; import org.osgi.framework.Constants; import org.osgi.framework.Version; /** * This class contains properties used by the framework */ public class FWProps { /** * Constants for knopflerfish framework properties */ public final static String ALL_SIGNED_PROP = "org.knopflerfish.framework.all_signed"; public final static String AUTOMANIFEST_PROP = "org.knopflerfish.framework.automanifest"; public final static String AUTOMANIFEST_CONFIG_PROP = "org.knopflerfish.framework.automanifest.config"; public final static String BUNDLESTORAGE_PROP = "org.knopflerfish.framework.bundlestorage"; public final static String BUNDLESTORAGE_CHECKSIGNED_PROP = "org.knopflerfish.framework.bundlestorage.checksigned"; public final static String PATCH_PROP = "org.knopflerfish.framework.patch"; public final static String PATCH_CONFIGURL_PROP = "org.knopflerfish.framework.patch.configurl"; public final static String PATCH_DUMPCLASSES_PROP = "org.knopflerfish.framework.patch.dumpclasses"; public final static String PATCH_DUMPCLASSES_DIR_PROP = "org.knopflerfish.framework.patch.dumpclasses.dir"; public final static String SERVICE_CONDITIONALPERMISSIONADMIN_PROP = "org.knopflerfish.framework.service.conditionalpermissionadmin"; public final static String SERVICE_PERMISSIONADMIN_PROP = "org.knopflerfish.framework.service.permissionadmin"; /** * Property specifying how bundle threads which are aborted should be handled. * Possible values are {@link BundleThread#ABORT_ACTION_STOP}, * {@link BundleThread#ABORT_ACTION_MINPRIO}, * {@link BundleThread#ABORT_ACTION_IGNORE}. The default value is * {@link BundleThread#ABORT_ACTION_IGNORE}. */ public final static String BUNDLETHREAD_ABORT = "org.knopflerfish.framework.bundlethread.abort"; /** * Property specifying the amount of time in seconds that the framework waits for a * BundleActivator.start() or .stop() call to complete and return. The default value is 0 which * means to wait indefinitely. */ public final static String BUNDLETHREAD_TIMEOUT = "org.knopflerfish.framework.bundlethread.timeout"; /** * Name of system property for basic system packages to be exported. The * normal OSGi exports will be added to this list. */ public final static String SYSTEM_PACKAGES_BASE_PROP = "org.knopflerfish.framework.system.packages.base"; /** * Property name pointing to file listing of system-exported packages */ public final static String SYSTEM_PACKAGES_FILE_PROP = "org.knopflerfish.framework.system.packages.file"; /** * Property name for selecting exporting profile of system packages. */ public final static String SYSTEM_PACKAGES_VERSION_PROP = "org.knopflerfish.framework.system.packages.version"; public final static String IS_DOUBLECHECKED_LOCKING_SAFE_PROP = "org.knopflerfish.framework.is_doublechecked_locking_safe"; public final static String LDAP_NOCACHE_PROP = "org.knopflerfish.framework.ldap.nocache"; public final static String LISTENER_N_THREADS_PROP = "org.knopflerfish.framework.listener.n_threads"; /** * If the Main-Class manifest attribute is set and this bundles location is * present in the value (comma separated list) of the Framework property named * org.knopflerfish.framework.main.class.activation then setup up a bundle * activator that calls the main-method of the Main-Class when the bundle is * started, and if the Main-Class contains a method named stop() call that * method when the bundle is stopped. */ public final static String MAIN_CLASS_ACTIVATION_PROP = "org.knopflerfish.framework.main.class.activation"; public final static String STRICTBOOTCLASSLOADING_PROP = "org.knopflerfish.framework.strictbootclassloading"; public final static String VALIDATOR_PROP = "org.knopflerfish.framework.validator"; public final static String SETCONTEXTCLASSLOADER_PROP = "org.knopflerfish.osgi.setcontextclassloader"; public final static String REGISTERSERVICEURLHANDLER_PROP = "org.knopflerfish.osgi.registerserviceurlhandler"; public final static String STARTLEVEL_USE_PROP = "org.knopflerfish.startlevel.use"; /** * Set to true indicates startlevel compatability mode. all bundles and * current start level will be 1 */ public final static String STARTLEVEL_COMPAT_PROP = "org.knopflerfish.framework.startlevel.compat"; /** * Set to true indicates that the framework shouldn't write any files. */ public static final String READ_ONLY_PROP = "org.knopflerfish.framework.readonly"; /** * Name of special property containing a comma-separated list of all other * property names. */ public static final String KEY_KEYS = "org.knopflerfish.framework.bundleprops.keys"; /** * Common true string. */ public final static String TRUE = "true"; /** * Common false string. */ public final static String FALSE = "false"; /** * Common new line string. */ public static final String NL = System.getProperty("line.separator"); // If set to true, use strict rules for loading classes from the // boot class loader. If false, accept class loading from the boot // class path from classes themselves on the boot class, but which // incorrectly assumes they may access all of the boot classes on // any class loader (such as the bundle class loader). // // Setting this to TRUE will, for example, result in broken // serialization on the Sun JVM It's debatable what is the correct // OSGi R4 behavior. public boolean STRICTBOOTCLASSLOADING; /** * The properties for this framework instance. */ protected Map props = new Hashtable(); /** * The default properties for this framework instance. TBD, maybe we should * make this JVM global!? */ protected Map props_default = new Hashtable(); // If set to true, then during the UNREGISTERING event the Listener // can use the ServiceReference to receive an instance of the service. public boolean UNREGISTERSERVICE_VALID_DURING_UNREGISTERING = true; // If set to true, set the bundle startup thread's context class // loader to the bundle class loader. This is useful for tests // but shouldn't really be used in production. public boolean SETCONTEXTCLASSLOADER = false; public boolean REGISTERSERVICEURLHANDLER = true; public static int javaVersionMajor = -1; public static int javaVersionMinor = -1; public static int javaVersionMicro = -1; static { String javaVersion = System.getProperty("java.specification.version"); if (javaVersion == null || javaVersion.length()==0) { javaVersion = System.getProperty("java.version"); } // Value is on the form M.N.U_P[-xxx] where M,N,U,P are decimal integers if (null != javaVersion) { int startPos = 0; int endPos = 0; final int max = javaVersion.length(); while (endPos < max && Character.isDigit(javaVersion.charAt(endPos))) { endPos++; } if (startPos < endPos) { try { javaVersionMajor = Integer.parseInt(javaVersion.substring(startPos, endPos)); startPos = endPos + 1; endPos = startPos; while (endPos < max && Character.isDigit(javaVersion.charAt(endPos))) { endPos++; } if (startPos < endPos) { javaVersionMinor = Integer.parseInt(javaVersion.substring(startPos, endPos)); startPos = endPos + 1; endPos = startPos; while (endPos < max && Character.isDigit(javaVersion.charAt(endPos))) { endPos++; } if (startPos < endPos) { javaVersionMicro = Integer.parseInt(javaVersion.substring(startPos, endPos)); } } } catch (final NumberFormatException _nfe) { } } } } @SuppressWarnings("deprecation") private static final String FRAMEWORK_EXECUTIONENVIRONMENT = Constants.FRAMEWORK_EXECUTIONENVIRONMENT; /** * Is it safe to use double-checked locking or not. It is safe if JSR 133 is * included in the running JRE. I.e., for Java SE if version is 1.5 or higher. */ public boolean isDoubleCheckedLockingSafe; public FWProps(Map initProps, FrameworkContext fwCtx) { // Add explicitly given properties. props.putAll(initProps); // Setup Debug as early as possible. fwCtx.debug = new Debug(this); // Setup default (launch) OSGi properties, see OSGi R4 v4.2 sec 4.2.2 initProperties(fwCtx); // Setup default KF framework properties initKFProperties(); // Set up some instance variables that depends on the properties SETCONTEXTCLASSLOADER = getBooleanProperty(SETCONTEXTCLASSLOADER_PROP); REGISTERSERVICEURLHANDLER = getBooleanProperty(REGISTERSERVICEURLHANDLER_PROP); STRICTBOOTCLASSLOADING = getBooleanProperty(STRICTBOOTCLASSLOADING_PROP); isDoubleCheckedLockingSafe = getBooleanProperty(IS_DOUBLECHECKED_LOCKING_SAFE_PROP); } /** * Retrieve boolean value of the named framework property, with a default * value. * */ public boolean getBooleanProperty(String key) { final String v = getProperty(key); if (v != null) { return TRUE.equalsIgnoreCase(v); } return false; } /** * Retrieve the value of the named framework property, with a default value. * */ public String getProperty(String key) { if (KEY_KEYS.equals(key)) { return makeKeys(); } String v = props.get(key); if (v == null) { v = System.getProperty(key); if (v == null) { // We know that we don't need to trim the result return props_default.get(key); } } return v.trim(); } public void setPropertyDefault(String key, String val) { // No need to save default if already have a value if (!props.containsKey(key)) { props_default.put(key, val); } } /** * Set property if not set to system property if it exists otherwise set to * supplied value. */ public void setPropertyIfNotSet(String key, String val) { if (!props.containsKey(key)) { props.put(key, System.getProperty(key, val)); } } public Dictionary getProperties() { final Hashtable p = new Hashtable(props_default); @SuppressWarnings({ "rawtypes", "unchecked" }) final Hashtable sysProps = (Hashtable) System.getProperties(); p.putAll(sysProps); p.putAll(props); p.put(KEY_KEYS, makeKeys()); return p; } protected String makeKeys() { final StringBuffer sb = new StringBuffer(); for (final String string : props.keySet()) { if (sb.length() > 0) { sb.append(','); } sb.append(string.toString()); } for (final String string : props_default.keySet()) { sb.append(','); sb.append(string.toString()); } return sb.toString(); } /** * Create the default set of framework (launch) properties. */ protected void initProperties(FrameworkContext fwCtx) { setPropertyIfNotSet(Constants.FRAMEWORK_BOOTDELEGATION, ""); setPropertyIfNotSet(Constants.FRAMEWORK_BSNVERSION, Constants.FRAMEWORK_BSNVERSION_MANAGED); setPropertyIfNotSet(Constants.FRAMEWORK_BUNDLE_PARENT, Constants.FRAMEWORK_BUNDLE_PARENT_BOOT); setPropertyIfNotSet(Constants.FRAMEWORK_EXECPERMISSION, ""); if (!props.containsKey(FRAMEWORK_EXECUTIONENVIRONMENT)) { final StringBuffer ee = new StringBuffer(); // Always allow ee minimum ee.append("OSGi/Minimum-1.0"); ee.append(",OSGi/Minimum-1.1"); ee.append(",OSGi/Minimum-1.2"); // Set up the default ExecutionEnvironment if (1 == javaVersionMajor) { for (int i = javaVersionMinor; i > 1; i--) { ee.append((i > 5) ? ",JavaSE-1." : ",J2SE-1."); ee.append(i); } } props.put(FRAMEWORK_EXECUTIONENVIRONMENT, ee.toString()); } // The actual value is created in SytemBundle. setPropertyIfNotSet(Constants.FRAMEWORK_SYSTEMCAPABILITIES, ""); setPropertyIfNotSet(Constants.FRAMEWORK_SYSTEMCAPABILITIES_EXTRA, ""); setPropertyIfNotSet(Constants.FRAMEWORK_LANGUAGE, Locale.getDefault().getLanguage()); setPropertyIfNotSet(Constants.FRAMEWORK_LIBRARY_EXTENSIONS, ""); setPropertyIfNotSet(Constants.FRAMEWORK_OS_NAME, Alias.unifyOsName(System.getProperty("os.name"))); if (!props.containsKey(Constants.FRAMEWORK_OS_VERSION)) { final String ver = System.getProperty("os.version"); int maj = 0; int min = 0; int mic = 0; String qual = null; if (ver != null) { // Convert os.version to a reasonable default try { final StringTokenizer st = new StringTokenizer(ver.trim(), "."); maj = Integer.parseInt(st.nextToken()); if (st.hasMoreTokens()) { qual = st.nextToken(); min = Integer.parseInt(qual); qual = null; if (st.hasMoreTokens()) { qual = st.nextToken(); mic = Integer.parseInt(qual); qual = null; if (st.hasMoreTokens()) { qual = st.nextToken(); } } } } catch (final Exception ignore) { } } Version osVersion; try { osVersion = new Version(maj, min, mic, qual); } catch (final IllegalArgumentException skip) { osVersion = new Version(maj, min, mic, null); } props.put(Constants.FRAMEWORK_OS_VERSION, osVersion.toString()); } setPropertyIfNotSet(Constants.FRAMEWORK_PROCESSOR, Alias.unifyProcessor(System.getProperty("os.arch"))); setPropertyIfNotSet(Constants.FRAMEWORK_SECURITY, ""); setPropertyIfNotSet(Constants.FRAMEWORK_BEGINNING_STARTLEVEL, "1"); setPropertyIfNotSet(Constants.FRAMEWORK_STORAGE, "fwdir"); setPropertyIfNotSet(Constants.FRAMEWORK_STORAGE_CLEAN, ""); // The SystemBundle will fill in this later. setPropertyIfNotSet(Constants.FRAMEWORK_SYSTEMPACKAGES, ""); setPropertyIfNotSet(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, ""); setPropertyIfNotSet(Constants.FRAMEWORK_TRUST_REPOSITORIES, ""); // NYI setPropertyIfNotSet(Constants.FRAMEWORK_WINDOWSYSTEM, ""); // Impl. constants props.put(Constants.FRAMEWORK_VERSION, Util.readFrameworkVersion()); props.put(Constants.FRAMEWORK_VENDOR, "Knopflerfish"); props.put(Constants.SUPPORTS_FRAMEWORK_REQUIREBUNDLE, TRUE); props.put(Constants.SUPPORTS_FRAMEWORK_FRAGMENT, TRUE); // Only first framework support framework extension // TODO Improve this in the future setPropertyIfNotSet(Constants.SUPPORTS_FRAMEWORK_EXTENSION, getClass().getClassLoader() instanceof URLClassLoader && fwCtx.id == 0 ? TRUE : FALSE); // Only first framework can support bootclasspath extension // TODO Improve this in the future setPropertyIfNotSet(Constants.SUPPORTS_BOOTCLASSPATH_EXTENSION, FALSE); if (getBooleanProperty(Constants.SUPPORTS_BOOTCLASSPATH_EXTENSION) && !(getClass().getClassLoader() instanceof URLClassLoader && fwCtx.id == 1)) { props.put(Constants.SUPPORTS_BOOTCLASSPATH_EXTENSION, FALSE); } } /** * Create the default set of KF specific framework properties. */ protected void initKFProperties() { setPropertyDefault(ALL_SIGNED_PROP, FALSE); setPropertyDefault(AUTOMANIFEST_PROP, FALSE); setPropertyDefault(AUTOMANIFEST_CONFIG_PROP, "!!/automanifest.props"); setPropertyDefault(BUNDLESTORAGE_PROP, "file"); setPropertyDefault(BUNDLESTORAGE_CHECKSIGNED_PROP, TRUE); setPropertyDefault(PATCH_PROP, FALSE); setPropertyDefault(PATCH_CONFIGURL_PROP, "!!/patches.props"); setPropertyDefault(PATCH_DUMPCLASSES_PROP, FALSE); setPropertyDefault(PATCH_DUMPCLASSES_DIR_PROP, "patchedclasses"); setPropertyDefault(SERVICE_CONDITIONALPERMISSIONADMIN_PROP, TRUE); setPropertyDefault(SERVICE_PERMISSIONADMIN_PROP, TRUE); setPropertyDefault(SYSTEM_PACKAGES_BASE_PROP, ""); setPropertyDefault(SYSTEM_PACKAGES_FILE_PROP, ""); setPropertyDefault(SYSTEM_PACKAGES_VERSION_PROP, Integer.toString(javaVersionMajor) + "." + javaVersionMinor); setPropertyDefault(IS_DOUBLECHECKED_LOCKING_SAFE_PROP, javaVersionMajor >= 1 && javaVersionMinor >= 5 ? TRUE : FALSE); setPropertyDefault(LDAP_NOCACHE_PROP, FALSE); setPropertyDefault(MAIN_CLASS_ACTIVATION_PROP, ""); setPropertyDefault(STRICTBOOTCLASSLOADING_PROP, FALSE); setPropertyDefault(VALIDATOR_PROP, getProperty(Constants.FRAMEWORK_TRUST_REPOSITORIES) .length() > 0 ? "JKSValidator" : "none"); setPropertyDefault(SETCONTEXTCLASSLOADER_PROP, FALSE); setPropertyDefault(REGISTERSERVICEURLHANDLER_PROP, TRUE); setPropertyDefault(STARTLEVEL_COMPAT_PROP, FALSE); setPropertyDefault(STARTLEVEL_USE_PROP, TRUE); setPropertyDefault(READ_ONLY_PROP, FALSE); } }knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ListenerEntry.java0000644000175000017500000000470112346513666030641 0ustar felixfelix/* * Copyright (c) 2003-2011, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.EventListener; class ListenerEntry { final BundleContextImpl bc; final EventListener listener; boolean bRemoved = false; ListenerEntry(BundleContextImpl bc, EventListener l) { this.bc = bc; listener = l; } /** * Listener are considered equal if bc and listener are equal, this so that * the HashSet of listeners should work. */ public boolean equals(Object o) { if (o instanceof ListenerEntry) { return bc == ((ListenerEntry) o).bc && listener == ((ListenerEntry) o).listener; } return false; } /** * Only use listener as hash value, since it is almost always unique. */ public int hashCode() { return listener.hashCode(); } /** */ void setRemoved(boolean b) { this.bRemoved = b; } /** */ public boolean isRemoved() { return bRemoved; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/PropertiesDictionary.java0000644000175000017500000001213012346513666032207 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Dictionary; import java.util.Enumeration; import org.osgi.framework.Constants; /** * Creates a copy of the properties associated with a service registration. * Checks that all the keys are strings and adds the class names. * Note! Creation of PropertiesDictionary must be synchronized. * * @author Jan Stein */ class PropertiesDictionary extends Dictionary { private final String [] keys; private final Object [] values; private int size; private int ocIndex = -1; private int sidIndex = -1; private static long nextServiceID = 1; PropertiesDictionary(@SuppressWarnings("rawtypes") Dictionary in) { final int max_size = in != null ? in.size() + 2 : 2; keys = new String[max_size]; values = new Object[max_size]; size = 0; if (in != null) { try { for (@SuppressWarnings("rawtypes") final Enumeration e = in.keys(); e.hasMoreElements();) { final String key = (String) e.nextElement(); if (ocIndex == -1 && key.equalsIgnoreCase(Constants.OBJECTCLASS)) { ocIndex = size; } else if (sidIndex == -1 && key.equalsIgnoreCase(Constants.SERVICE_ID)) { sidIndex = size; } else { for (int i = size - 1; i >= 0; i--) { if (key.equalsIgnoreCase(keys[i])) { throw new IllegalArgumentException( "Several entries for property: " + key); } } } keys[size] = key; values[size++] = in.get(key); } } catch (final ClassCastException ignore) { throw new IllegalArgumentException( "Properties contains key that is not of type java.lang.String"); } } } PropertiesDictionary(@SuppressWarnings("rawtypes") Dictionary in, String[] classes, Long sid) { this(in); if (ocIndex == -1) { keys[size] = Constants.OBJECTCLASS; ocIndex = size++; } values[ocIndex] = classes; if (sidIndex == -1) { keys[size] = Constants.SERVICE_ID; sidIndex = size++; } values[sidIndex] = sid != null ? sid : new Long(nextServiceID++); } @Override public Object get(Object key) { if (key == Constants.OBJECTCLASS) { return (ocIndex >= 0) ? values[ocIndex] : null; } else if (key == Constants.SERVICE_ID) { return (sidIndex >= 0) ? values[sidIndex] : null; } for (int i = size - 1; i >= 0; i--) { if (((String)key).equalsIgnoreCase(keys[i])) { return values[i]; } } return null; } public String [] keyArray() { final String [] nkeys = new String[size]; System.arraycopy(keys, 0, nkeys, 0, size); return nkeys; } @Override public int size() { return size; } // These aren't used but we implement to fulfill Dictionary class @Override public Enumeration elements() { throw new UnsupportedOperationException("Not implemented"); } @Override public boolean isEmpty() { throw new UnsupportedOperationException("Not implemented"); } @Override public Enumeration keys() { throw new UnsupportedOperationException("Not implemented"); } @Override public Object put(String k, Object v) { throw new UnsupportedOperationException("Not implemented"); } @Override public Object remove(Object k) { throw new UnsupportedOperationException("Not implemented"); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleRevisionImpl.java0000644000175000017500000001430412346513666031604 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.osgi.framework.Version; import org.osgi.framework.namespace.IdentityNamespace; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWiring; import org.osgi.resource.Capability; import org.osgi.resource.Requirement; public class BundleRevisionImpl extends BundleReferenceImpl implements BundleRevision { static final int NS_BUNDLE = 1; static final int NS_HOST = 2; static final int NS_IDENTITY = 4; static final int NS_PACKAGE = 8; static final int NS_OTHER = 16; final BundleGeneration gen; private BundleWiring bundleWiring = null; BundleRevisionImpl(BundleGeneration gen) { super(gen.bundle); this.gen = gen; } @Override public String getSymbolicName() { return gen.symbolicName; } @Override public Version getVersion() { return gen.version; } @Override public List getDeclaredCapabilities(String namespace) { final ArrayList res = new ArrayList(); final int ns = whichNameSpaces(namespace); if ((ns & NS_BUNDLE) != 0) { final BundleCapability bc = gen.getBundleCapability(); if (bc!=null) { res.add(bc); } } if ((ns & NS_HOST) != 0) { final BundleCapability bc = gen.getHostCapability(); if (bc!=null) { res.add(bc); } } if ((ns & NS_IDENTITY) != 0) { final BundleCapability bc = gen.getIdentityCapability(); if (bc!=null) { res.add(bc); } } if ((ns & NS_PACKAGE) != 0) { res.addAll(gen.bpkgs.getDeclaredPackageCapabilities()); } if ((ns & NS_OTHER) != 0) { final Map> caps = gen.getDeclaredCapabilities(); if (null != namespace) { final List lcap = caps.get(namespace); if (lcap != null) { res.addAll(lcap); } } else { for (final List lcap : caps.values()) { res.addAll(lcap); } } } return res; } @Override public List getDeclaredRequirements(String namespace) { final ArrayList res = new ArrayList(); final int ns = whichNameSpaces(namespace); if ((ns & NS_BUNDLE) != 0) { res.addAll(gen.bpkgs.getDeclaredBundleRequirements()); } if ((ns & NS_HOST) != 0) { if (gen.isFragment()) { res.add(gen.fragment); } } if ((ns & NS_PACKAGE) != 0) { res.addAll(gen.bpkgs.getDeclaredPackageRequirements()); } if ((ns & (NS_IDENTITY|NS_OTHER)) != 0) { final Map> reqs = gen.getDeclaredRequirements(); if (null != namespace) { final List lbr = reqs.get(namespace); if (lbr != null) { res.addAll(lbr); } } else { for (final List lbr : reqs.values()) { res.addAll(lbr); } } } return res; } @SuppressWarnings("unchecked") @Override public List getCapabilities(String namespace) { return (List)(List)getDeclaredCapabilities(namespace); } @SuppressWarnings("unchecked") @Override public List getRequirements(String namespace) { return (List)(List)getDeclaredRequirements(namespace); } @Override public int getTypes() { return gen.isFragment() ? TYPE_FRAGMENT : 0; } @Override public BundleWiring getWiring() { return bundleWiring; } @Override public String toString() { return "BundleRevision[" + getSymbolicName() + ":" + getVersion() + "]"; } BundleGeneration getBundleGeneration() { return gen; } void setWired() { bundleWiring = new BundleWiringImpl(this); } void clearWiring() { bundleWiring = null; } static int whichNameSpaces(String namespace) { int ns; if (namespace == null) { ns = NS_BUNDLE|NS_HOST|NS_IDENTITY|NS_PACKAGE|NS_OTHER; } else if (BundleRevision.BUNDLE_NAMESPACE.equals(namespace)) { ns = NS_BUNDLE; } else if (BundleRevision.HOST_NAMESPACE.equals(namespace)) { ns = NS_HOST; } else if (IdentityNamespace.IDENTITY_NAMESPACE.equals(namespace)) { ns = NS_IDENTITY; } else if (BundleRevision.PACKAGE_NAMESPACE.equals(namespace)) { ns = NS_PACKAGE; } else { ns = NS_OTHER; } return ns; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Alias.java0000644000175000017500000000761212346513666027067 0ustar felixfelix/* * Copyright (c) 2003-2011, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; /** * This class contains aliases for system properties. * * @author Jan Stein */ public class Alias { /** * List of processor aliases. The first entry is the true name. All matching * aliases must be in lowercase. */ final public static String[][] processorAliases = { { "arm_le", "armv*l" }, { "arm_be", "armv*" }, { "Ignite", "psc1k" }, { "PowerPC", "power", "ppc", "ppcbe" }, { "x86", "pentium", "i386", "i486", "i586", "i686" }, { "x86-64", "amd64", "em64t", "x86_64" } }; /** * List of OS name aliases. The first entry is the true name. All matching * aliases must be in lowercase. */ final public static String[][] osNameAliases = { { "Epoc32", "symbianos" }, { "HPUX", "hp-ux" }, { "MacOS", "mac os" }, { "MacOSX", "mac os x" }, { "OS2", "os/2" }, { "QNX", "procnto" }, { "Windows95", "win*95", "win32" }, { "Windows98", "win*98", "win32" }, { "WindowsNT", "win*nt", "win32" }, { "WindowsCE", "win*ce", "win32" }, { "Windows2000", "win*2000", "win32" }, { "WindowsXP", "win*xp", "win32" }, { "Windows2003", "win*2003", "win32" }, { "WindowsVista", "win*vista", "win32" }, { "Windows7", "win*7", "win32" }, { "WindowsServer2008", "win*2008", "win32" }, { "Windows8", "win*8", "win32" }, { "WindowsServer2012", "win*2012", "win32" } }; /** * Unify processor names. * * @param name Processor name. * @return The unified name. */ static public String unifyProcessor(String name) { String lname = name.toLowerCase(); for (int i = 0; i < processorAliases.length; i++) { for (int j = 1; j < processorAliases[i].length; j++) { if (Util.filterMatch(processorAliases[i][j], lname)) { return processorAliases[i][0]; } } } return name; } /** * Unify OS names. * * @param name OS name. * @return The unified name. */ static public String unifyOsName(String name) { String lname = name.toLowerCase(); for (int i = 0; i < osNameAliases.length; i++) { for (int j = 1; j < osNameAliases[i].length; j++) { if (Util.filterMatch(osNameAliases[i][j], lname)) { return osNameAliases[i][0]; } } } return name; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleCapabilityImpl.java0000644000175000017500000001714112346513666032071 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import org.knopflerfish.framework.Util.HeaderEntry; import org.osgi.framework.Constants; import org.osgi.framework.namespace.IdentityNamespace; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRevision; /** * Implementation of bundle capability for generic capabilities specified in the * Bundle-Capability header. */ public class BundleCapabilityImpl implements BundleCapability { private final BundleGeneration gen; private final BundleGeneration owner; private final String nameSpace; private final Map attributes; private final Map directives; private Vector wires = new Vector(2); /** * Creates a {@link BundleCapability} from one entry of the Bundle-Capability * header. * * @param gen * the owning bundle revision. * @param he * the parsed bundle capability header entry. */ public BundleCapabilityImpl(final BundleGeneration gen, final HeaderEntry he) { this.gen = gen; owner = gen; nameSpace = he.getKey(); for (final String ns : Arrays .asList(new String[] { BundleRevision.BUNDLE_NAMESPACE, BundleRevision.HOST_NAMESPACE, BundleRevision.PACKAGE_NAMESPACE, IdentityNamespace.IDENTITY_NAMESPACE})) { if (ns.equals(nameSpace)) { throw new IllegalArgumentException("Capability with name-space '" + ns + "' must not be provided in the " + Constants.PROVIDE_CAPABILITY + " manifest header."); } } attributes = Collections.unmodifiableMap(he.getAttributes()); directives = Collections.unmodifiableMap(he.getDirectives()); } public BundleCapabilityImpl(BundleCapability bc, BundleGeneration bg) { gen = bg; owner = ((BundleCapabilityImpl)bc).owner; nameSpace = bc.getNamespace(); attributes = bc.getAttributes(); directives = bc.getDirectives(); } public BundleCapabilityImpl(BundleGeneration bg) { gen = bg; owner = gen; nameSpace = IdentityNamespace.IDENTITY_NAMESPACE; Map attrs = new HashMap(); attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, gen.symbolicName); attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, gen.fragment != null ? IdentityNamespace.TYPE_FRAGMENT : IdentityNamespace.TYPE_BUNDLE); attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, gen.version); if (gen.archive != null) { String a = gen.archive.getAttribute(Constants.BUNDLE_COPYRIGHT); if (a != null) { attrs.put(IdentityNamespace.CAPABILITY_COPYRIGHT_ATTRIBUTE, a); } a = gen.archive.getAttribute(Constants.BUNDLE_DESCRIPTION); if (a != null) { attrs.put(IdentityNamespace.CAPABILITY_DESCRIPTION_ATTRIBUTE, a); } a = gen.archive.getAttribute(Constants.BUNDLE_DOCURL); if (a != null) { attrs.put(IdentityNamespace.CAPABILITY_DOCUMENTATION_ATTRIBUTE, a); } a = gen.archive.getAttribute("Bundle-License"); if (a != null) { StringBuffer sb = new StringBuffer(); try { List lic = Util.parseManifestHeader("Bundle-License", a, true, true, false); for (HeaderEntry he : lic) { if (sb.length() > 0) { sb.append(", "); } sb.append(he.getKey()); } } catch (IllegalArgumentException iae) { gen.bundle.fwCtx.frameworkInfo(gen.bundle, iae); sb.append(a); } attrs.put(IdentityNamespace.CAPABILITY_LICENSE_ATTRIBUTE, sb.toString()); } } attributes = Collections.unmodifiableMap(attrs); Map dirs = new HashMap(); dirs.put(Constants.SINGLETON_DIRECTIVE, gen.singleton ? "true" : "false"); // TODO, should we try to find classfiers? directives = Collections.unmodifiableMap(dirs); } @Override public String getNamespace() { return nameSpace; } @Override public Map getDirectives() { return Collections.unmodifiableMap(directives); } @Override public Map getAttributes() { return attributes; } @Override public BundleRevision getRevision() { return owner.bundleRevision; } @Override public BundleRevision getResource() { return owner.bundleRevision; } @Override public String toString() { return "BundleCapability[nameSpace=" + nameSpace + ", attributes=" + attributes + ", directives=" + directives + ", revision=" + getRevision() + "]"; } BundleGeneration getBundleGeneration() { return gen; } boolean isEffectiveResolve() { final String effective = directives.get(Constants.EFFECTIVE_DIRECTIVE); return effective == null || effective.equals(Constants.EFFECTIVE_RESOLVE); } boolean isZombie() { return !gen.isCurrent(); } void addWire(BundleWireImpl bw) { wires.add(bw); } void getWires(List res) { synchronized (wires) { res.addAll(wires); } } void removeWire(BundleWireImpl wire) { wires.remove(wire); } void removeWires() { wires.clear(); } boolean isWired() { return !wires.isEmpty(); } /** * Check if we have provide permissions. * * @return true if we have provide permission */ boolean checkPermission() { return gen.bundle.fwCtx.perm.hasProvidePermission(this); } Set getUses() { try { return Util.parseEnumeration(Constants.USES_DIRECTIVE, directives.get(Constants.USES_DIRECTIVE)); } catch (IllegalArgumentException iae) { final BundleImpl b = gen.bundle; b.fwCtx.frameworkError(b, iae); } return null; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/LDAPExpr.java0000644000175000017500000005153212346513666027415 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collection; import java.util.Dictionary; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import java.util.TreeSet; import org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; public class LDAPExpr { public static final int AND = 0; public static final int OR = 1; public static final int NOT = 2; public static final int EQ = 4; public static final int LE = 8; public static final int GE = 16; public static final int APPROX = 32; public static final int COMPLEX = AND | OR | NOT; public static final int SIMPLE = EQ | LE | GE | APPROX; private static final char WILDCARD = 65535; private static final String WILDCARD_STRING = new String(new char[] { WILDCARD }); private static final String NULL = "Null query"; private static final String GARBAGE = "Trailing garbage"; private static final String EOS = "Unexpected end of query"; private static final String MALFORMED = "Malformed query"; private static final String OPERATOR = "Undefined operator"; private static Class classBigDecimal; private static Constructor consBigDecimal; private static Method compBigDecimal; private static Class classBigInteger; private static Constructor consBigInteger; private static Method compBigInteger; public int operator; public LDAPExpr[] args; public String attrName; public String attrValue; public LDAPExpr(String filter) throws InvalidSyntaxException { final ParseState ps = new ParseState(filter); LDAPExpr expr = null; try { expr = parseExpr(ps); } catch (final StringIndexOutOfBoundsException e) { ps.error(EOS); } if (ps.rest().trim().length() != 0) ps.error(GARBAGE + " '" + ps.rest() + "'"); operator = expr.operator; args = expr.args; attrName = expr.attrName; attrValue = expr.attrValue; } private LDAPExpr(int operator, LDAPExpr[] args) { this.operator = operator; this.args = args; this.attrName = null; this.attrValue = null; } private LDAPExpr(int operator, String attrName, String attrValue) { this.operator = operator; this.args = null; this.attrName = attrName; this.attrValue = attrValue; } /** * Get a set of object classes that might match this LDAP expression. This will not work * with wildcards and NOT expressions. If a set can not be determined return * null - meaning that all object classes must be considered when looking for matches. * * @return A set of classes that might match, otherwise null. */ public Set getMatchedObjectClasses() { Set objClasses = null; if (operator == EQ) { if (attrName.equalsIgnoreCase(Constants.OBJECTCLASS) && attrValue.indexOf(WILDCARD) < 0) { objClasses = new OneSet(attrValue); } } else if (operator == AND) { for (final LDAPExpr arg : args) { final Set r = arg.getMatchedObjectClasses(); if (r != null) { if (objClasses == null) { objClasses = new TreeSet(); } objClasses.addAll(r); } } } else if (operator == OR) { for (final LDAPExpr arg : args) { final Set r = arg.getMatchedObjectClasses(); if (r != null) { if (objClasses == null) { objClasses = new TreeSet(); } objClasses.addAll(r); } else { objClasses = null; break; } } } return objClasses; } /** * Checks if this LDAP expression is "simple". The definition of a simple * filter is: *
    *
  • {@code (name=value)} is simple if name * is a member of the provided {@code keywords}, and value does * not contain a wildcard character;
  • *
  • {@code (| EXPR+ )} is simple if all {@code EXPR} expressions * are simple;
  • *
  • No other expressions are simple.
  • *
* If the filter is found to be simple, the {@code cache} is filled with * mappings from the provided keywords to lists of attribute values. The * keyword-value-pairs are the ones that satisfy this expression, for the * given keywords. * * @param keywords The keywords to look for. * @param cache An array (indexed by the keyword indexes) of lists to fill in * with values saturating this expression. * @return {@code true} if this expression is simple, {@code false} * otherwise. */ public boolean isSimple(List keywords, List[] cache, boolean matchCase) { if (operator == EQ) { int index; if ((index = keywords.indexOf(matchCase ? attrName : attrName.toLowerCase())) >= 0 && attrValue.indexOf(WILDCARD) < 0) { if (cache[index] == null) { cache[index] = new ArrayList(); } cache[index].add(attrValue); return true; } } else if (operator == OR) { for (int i = 0; i < args.length; i++) { if (!args[i].isSimple(keywords, cache, matchCase)) return false; } return true; } return false; } public static boolean query(String filter, Dictionary pd) throws InvalidSyntaxException { return new LDAPExpr(filter).evaluate(pd, false); } /** * Evaluate this LDAP filter. */ public boolean evaluate(Dictionary p, boolean matchCase) { if ((operator & SIMPLE) != 0) { return compare(p.get(matchCase ? attrName : attrName.toLowerCase()), operator, attrValue); } else { // (operator & COMPLEX) != 0 switch (operator) { case AND: for (int i = 0; i < args.length; i++) { if (!args[i].evaluate(p, matchCase)) return false; } return true; case OR: for (final LDAPExpr arg : args) { if (arg.evaluate(p, matchCase)) return true; } return false; case NOT: return !args[0].evaluate(p, matchCase); default: return false; // Cannot happen } } } /**** Private methods ****/ protected boolean compare(Object obj, int op, String s) { if (obj == null) return false; if (op == EQ && s.equals(WILDCARD_STRING)) return true; try { if (obj instanceof String) { return compareString((String)obj, op, s); } else if (obj instanceof Character) { return compareString(obj.toString(), op, s); } else if (obj instanceof Boolean) { if (op == LE || op == GE) return false; if (((Boolean)obj).booleanValue()) { return s.equalsIgnoreCase("true"); } else { return s.equalsIgnoreCase("false"); } } else if (obj instanceof Number) { if (obj instanceof Byte) { switch (op) { case LE: return ((Byte)obj).byteValue() <= Byte.parseByte(s); case GE: return ((Byte)obj).byteValue() >= Byte.parseByte(s); default: /* APPROX and EQ */ return (new Byte(s)).equals(obj); } } else if (obj instanceof Integer) { switch (op) { case LE: return ((Integer)obj).intValue() <= Integer.parseInt(s); case GE: return ((Integer)obj).intValue() >= Integer.parseInt(s); default: /* APPROX and EQ */ return (new Integer(s)).equals(obj); } } else if (obj instanceof Short) { switch (op) { case LE: return ((Short)obj).shortValue() <= Short.parseShort(s); case GE: return ((Short)obj).shortValue() >= Short.parseShort(s); default: /* APPROX and EQ */ return (new Short(s)).equals(obj); } } else if (obj instanceof Long) { switch (op) { case LE: return ((Long)obj).longValue() <= Long.parseLong(s); case GE: return ((Long)obj).longValue() >= Long.parseLong(s); default: /* APPROX and EQ */ return (new Long(s)).equals(obj); } } else if (obj instanceof Float) { switch (op) { case LE: return ((Float)obj).floatValue() <= (new Float(s)).floatValue(); case GE: return ((Float)obj).floatValue() >= (new Float(s)).floatValue(); default: /* APPROX and EQ */ return (new Float(s)).equals(obj); } } else if (obj instanceof Double) { switch (op) { case LE: return ((Double)obj).doubleValue() <= (new Double(s)).doubleValue(); case GE: return ((Double)obj).doubleValue() >= (new Double(s)).doubleValue(); default: /* APPROX and EQ */ return (new Double(s)).equals(obj); } } else if (classBigInteger != null && classBigInteger.isInstance(obj)) { final Object n = consBigInteger.newInstance(new Object[] { s }); final int c = ((Integer)compBigInteger.invoke(obj, new Object[] { n })).intValue(); switch (op) { case LE: return c <= 0; case GE: return c >= 0; default: /* APPROX and EQ */ return c == 0; } } else if (classBigDecimal != null && classBigDecimal.isInstance(obj)) { final Object n = consBigDecimal.newInstance(new Object[] { s }); final int c = ((Integer)compBigDecimal.invoke(obj, new Object[] { n })).intValue(); switch (op) { case LE: return c <= 0; case GE: return c >= 0; default: /* APPROX and EQ */ return c == 0; } } } else if (obj instanceof Collection) { for (final Object name : ((Collection) obj)) if (compare(name, op, s)) return true; } else if (obj.getClass().isArray()) { final int len = Array.getLength(obj); for (int i = 0; i < len; i++) if (compare(Array.get(obj, i), op, s)) return true; } else { // Extended comparison // Allow simple EQ comparison on all classes having // a string constructor, and use compareTo if they // implement Comparable final Class clazz = obj.getClass(); final Constructor cons = getConstructor(clazz); if (cons != null) { final Object other = cons.newInstance(new Object[] { s }); if (obj instanceof Comparable) { @SuppressWarnings({ "unchecked" }) final int c = ((Comparable)obj).compareTo(other); switch (op) { case LE: return c <= 0; case GE: return c >= 0; default: /* APPROX and EQ */ return c == 0; } } else { boolean b = false; if (op == LE || op == GE || op == EQ || op == APPROX) { b = obj.equals(other); } return b; } } } } catch (final Exception ignored_but_evals_to_false) { // This might happen if a string-to-datatype conversion fails // Just consider it a false match and ignore the exception } return false; } // Clazz -> Constructor(String) private static HashMap, Constructor> constructorMap = new HashMap, Constructor>(); /** * Get cached String constructor for a class */ private static Constructor getConstructor(Class clazz) { synchronized (constructorMap) { // This might be null Constructor cons = constructorMap.get(clazz); // ...check if we have tried before. A failed try // is stored as null if (!constructorMap.containsKey(clazz)) { try { cons = clazz.getConstructor(new Class[] { String.class }); } catch (final Exception e) { // remember by storing null in map } constructorMap.put(clazz, cons); } return cons; } } static { try { classBigDecimal = Class.forName("java.math.BigDecimal"); consBigDecimal = getConstructor(classBigDecimal); compBigDecimal = classBigDecimal.getMethod("compareTo", new Class[] { classBigDecimal }); } catch (final Exception ignore) { classBigDecimal = null; } try { classBigInteger = Class.forName("java.math.BigInteger"); consBigInteger = getConstructor(classBigInteger); compBigInteger = classBigInteger.getMethod("compareTo", new Class[] { classBigInteger }); } catch (final Exception ignore) { classBigInteger = null; } } private static boolean compareString(String s1, int op, String s2) { switch (op) { case LE: return s1.compareTo(s2) <= 0; case GE: return s1.compareTo(s2) >= 0; case EQ: return patSubstr(s1, s2); case APPROX: return fixupString(s2).equals(fixupString(s1)); default: return false; } } private static String fixupString(String s) { final StringBuffer sb = new StringBuffer(); final int len = s.length(); for (int i = 0; i < len; i++) { char c = s.charAt(i); if (!Character.isWhitespace(c)) { if (Character.isUpperCase(c)) c = Character.toLowerCase(c); sb.append(c); } } return sb.toString(); } private static boolean patSubstr(String s, String pat) { return s == null ? false : patSubstr(s.toCharArray(), 0, pat.toCharArray(), 0); } private static boolean patSubstr(char[] s, int si, char[] pat, int pi) { if (pat.length - pi == 0) return s.length - si == 0; if (pat[pi] == WILDCARD) { pi++; for (;;) { if (patSubstr(s, si, pat, pi)) return true; if (s.length - si == 0) return false; si++; } } else { if (s.length - si == 0) { return false; } if (s[si] != pat[pi]) { return false; } return patSubstr(s, ++si, pat, ++pi); } } private static LDAPExpr parseExpr(ParseState ps) throws InvalidSyntaxException { ps.skipWhite(); if (!ps.prefix("(")) ps.error(MALFORMED); int operator; ps.skipWhite(); switch (ps.peek()) { case '&': operator = AND; break; case '|': operator = OR; break; case '!': operator = NOT; break; default: return parseSimple(ps); } ps.skip(1); // Ignore the operator final List v = new ArrayList(); do { v.add(parseExpr(ps)); ps.skipWhite(); } while (ps.peek() == '('); final int n = v.size(); if (!ps.prefix(")") || n == 0 || (operator == NOT && n > 1)) ps.error(MALFORMED); final LDAPExpr[] args = new LDAPExpr[n]; v.toArray(args); return new LDAPExpr(operator, args); } private static LDAPExpr parseSimple(ParseState ps) throws InvalidSyntaxException { final String attrName = ps.getAttributeName(); if (attrName == null) ps.error(MALFORMED); int operator = 0; if (ps.prefix("=")) operator = EQ; else if (ps.prefix("<=")) operator = LE; else if (ps.prefix(">=")) operator = GE; else if (ps.prefix("~=")) operator = APPROX; else { // System.out.println("undef op='" + ps.peek() + "'"); ps.error(OPERATOR); // Does not return } final String attrValue = ps.getAttributeValue(); if (!ps.prefix(")")) ps.error(MALFORMED); return new LDAPExpr(operator, attrName, attrValue); } @Override public String toString() { final StringBuffer res = new StringBuffer(); res.append("("); if ((operator & SIMPLE) != 0) { res.append(attrName); switch (operator) { case EQ: res.append("="); break; case LE: res.append("<="); break; case GE: res.append(">="); break; case APPROX: res.append("~="); break; } for (int i = 0; i < attrValue.length(); i++) { char c = attrValue.charAt(i); if (c == '(' || c == ')' || c == '*' || c == '\\') { res.append('\\'); } else if (c == WILDCARD) { c = '*'; } res.append(c); } } else { switch (operator) { case AND: res.append("&"); break; case OR: res.append("|"); break; case NOT: res.append("!"); break; } for (final LDAPExpr arg : args) { res.append(arg.toString()); } } res.append(")"); return res.toString(); } /** * Contains the current parser position and parsing utility methods. */ private static class ParseState { int pos; String str; public ParseState(String str) throws InvalidSyntaxException { this.str = str; if (str.length() == 0) error(NULL); pos = 0; } public boolean prefix(String pre) { if (!str.startsWith(pre, pos)) return false; pos += pre.length(); return true; } public char peek() { return str.charAt(pos); } public void skip(int n) { pos += n; } public String rest() { return str.substring(pos); } public void skipWhite() { while (Character.isWhitespace(str.charAt(pos))) { pos++; } } public String getAttributeName() { final int start = pos; int end = -1; for (;; pos++) { final char c = str.charAt(pos); if (c == '(' || c == ')' || c == '<' || c == '>' || c == '=' || c == '~') { break; } else if (!Character.isWhitespace(c)) { end = pos; } } if (end == -1) { return null; } return str.substring(start, end + 1); } public String getAttributeValue() { final StringBuffer sb = new StringBuffer(); label: for (;; pos++) { final char c = str.charAt(pos); switch (c) { case '(': case ')': break label; case '*': sb.append(WILDCARD); break; case '\\': sb.append(str.charAt(++pos)); break; default: sb.append(c); break; } } return sb.toString(); } public void error(String m) throws InvalidSyntaxException { throw new InvalidSyntaxException(m, (str == null) ? "" : str.substring(pos)); } } /** * Set with one element maximum. */ private static class OneSet extends AbstractSet { final private E elem; OneSet(E o) { elem = o; } @Override public Iterator iterator() { return new Iterator() { E ielem = elem; public boolean hasNext() { return ielem != null; } public E next() { if (ielem != null) { final E r = ielem; ielem = null; return r; } else { throw new NoSuchElementException(); } } public void remove() { throw new UnsupportedOperationException(); } }; } @Override public int size() { return elem == null ? 0 : 1; } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ExportedPackageImpl.java0000644000175000017500000001161412346513666031723 0ustar felixfelix/* * Copyright (c) 2003-2010, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.HashSet; import java.util.List; import org.osgi.framework.Bundle; import org.osgi.framework.Version; import org.osgi.service.packageadmin.ExportedPackage; import org.osgi.service.packageadmin.PackageAdmin; /** * An exported package. * * Instances implementing this interface are created by the * {@link PackageAdmin} service. *

Note that the information about an exported package provided by * this class is valid only until the next time * PackageAdmin.refreshPackages() is * called. * If an ExportedPackage becomes stale (that is, the package it references * has been updated or removed as a result of calling * PackageAdmin.refreshPackages()), * its getName() and getSpecificationVersion() continue to return their * old values, isRemovalPending() returns true, and getExportingBundle() * and getImportingBundles() return null. */ @SuppressWarnings("deprecation") public class ExportedPackageImpl implements ExportedPackage { final private ExportPkg pkg; ExportedPackageImpl(ExportPkg pkg) { this.pkg = pkg; } /** * Returns the name of this ExportedPackage. * * @return The name of this ExportedPackage. */ public String getName() { return pkg.name; } /** * Returns the bundle that is exporting this ExportedPackage. * * @return The exporting bundle, or null if this ExportedPackage * has become stale. */ public Bundle getExportingBundle() { if (pkg.pkg != null) { return pkg.bpkgs.bg.bundle; } else { return null; } } /** * Returns the resolved bundles that are currently importing this * ExportedPackage. * * @return The array of resolved bundles currently importing this * ExportedPackage, or null if this ExportedPackage * has become stale. */ public Bundle[] getImportingBundles() { final List imps = pkg.getPackageImporters(); if (imps != null) { final HashSet bs = new HashSet(); for (final ImportPkg ip : imps) { bs.add(ip.bpkgs.bg.bundle); } final List rl = pkg.bpkgs.getRequiredBy(); for (final BundlePackages bp : rl) { bs.add(bp.bg.bundle); } return bs.toArray(new Bundle[bs.size()]); } else { return null; } } /** * Returns the specification version of this ExportedPackage, as * specified in the exporting bundle's manifest file. * * @return The specification version of this ExportedPackage, or * null if no version information is available. */ public String getSpecificationVersion() { return pkg.version.toString(); } /** * Returns true if this ExportedPackage has been * exported by a bundle that has been updated or uninstalled. * * @return true if this ExportedPackage is being * exported by a bundle that has been updated or uninstalled; * false otherwise. */ public boolean isRemovalPending() { if (pkg.isProvider()) { return pkg.zombie; } else { return false; } } public Version getVersion() { return pkg.version; } @Override public String toString() { return pkg.name +"(" +pkg.version +")"; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ServiceListenerEntry.java0000644000175000017500000000706212346513666032165 0ustar felixfelix/* * Copyright (c) 2003-20103, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.EventListener; import java.util.List; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.UnfilteredServiceListener; import org.osgi.framework.hooks.service.ListenerHook; /** * Data structure for saving service listener info. Contains * the optional service listener filter, in addition to the info * in ListenerEntry. */ class ServiceListenerEntry extends ListenerEntry implements ListenerHook.ListenerInfo { final LDAPExpr ldap; final boolean noFiltering; /** * The elements of "simple" filters are cached, for easy lookup. * * The grammar for simple filters is as follows: * *

   * Simple = '(' attr '=' value ')'
   *        | '(' '|' Simple+ ')'
   * 
* where attr is one of {@link Constants#OBJECTCLASS}, * {@link Constants#SERVICE_ID} or {@link Constants#SERVICE_PID}, and * value must not contain a wildcard character. *

* The index of the vector determines which key the cache is for * (see {@link ServiceListenerState#hashedKeys}). For each key, there is * a vector pointing out the values which are accepted by this * ServiceListenerEntry's filter. This cache is maintained to make * it easy to remove this service listener. */ List[] local_cache; ServiceListenerEntry(BundleContextImpl bc, EventListener l, String filter) throws InvalidSyntaxException { super(bc, l); if (filter != null) { ldap = new LDAPExpr(filter); noFiltering = l instanceof UnfilteredServiceListener; } else { ldap = null; noFiltering = true; } } ServiceListenerEntry(BundleContextImpl bc, EventListener l) { super(bc, l); ldap = null; noFiltering = true; } public BundleContext getBundleContext() { return bc; } public String getFilter() { return ldap != null ? ldap.toString() : null; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/RequiredBundleImpl.java0000644000175000017500000001005412346513666031564 0ustar felixfelix/* * Copyright (c) 2006-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.List; import org.osgi.framework.Bundle; import org.osgi.framework.Version; import org.osgi.service.packageadmin.RequiredBundle; /** * Implementation for required bundle interface. * */ @SuppressWarnings("deprecation") public class RequiredBundleImpl implements RequiredBundle { /** */ private final BundlePackages bpkgs; /** * */ RequiredBundleImpl(BundlePackages b) { bpkgs = b; } /** * Returns the symbolic name of this required bundle. * * @return The symbolic name of this required bundle. */ public String getSymbolicName() { return bpkgs.bg.symbolicName; } /** * Returns the bundle associated with this required bundle. * * @return The bundle, or null if this * RequiredBundle object has become stale. */ public Bundle getBundle() { if (bpkgs.isRegistered()) { return bpkgs.bg.bundle; } else { return null; } } /** * Returns the bundles that currently require this required bundle. * *

* If this required bundle is required and then re-exported by another * bundle then all the requiring bundles of the re-exporting bundle are * included in the returned array. * * @return An array of bundles currently requiring this required bundle, or * null if this RequiredBundle object * has become stale. */ public Bundle[] getRequiringBundles() { if (bpkgs.isRegistered()) { final List rl = bpkgs.bg.bundle.getRequiredBy(); final Bundle[] res = new Bundle[rl.size()]; for (int i = rl.size() - 1; i >= 0; i--) { res[i] = rl.get(i).bg.bundle; } return res; } return null; } /** * Returns the version of this required bundle. * * @return The version of this required bundle, or * {@link Version#emptyVersion} if no version information is * available. */ public Version getVersion() { return bpkgs.bg.version; } /** * Returns true if the bundle associated with this * RequiredBundle object has been updated or uninstalled. * * @return true if the reqiured bundle has been updated or * uninstalled, or if the RequiredBundle object has * become stale; false otherwise. */ public boolean isRemovalPending() { return !bpkgs.bg.isCurrent(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ResolverHooks.java0000644000175000017500000003021612346513666030637 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.ServiceReference; import org.osgi.framework.hooks.resolver.ResolverHook; import org.osgi.framework.hooks.resolver.ResolverHookFactory; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; public class ResolverHooks { private final FrameworkContext fwCtx; private ServiceTracker resolverHookTracker; private List active = null; private BundleImpl [] currentTriggers = null; private Map resolvableBundles = null; private Thread blockThread = null; ResolverHooks(FrameworkContext frameworkContext) { this.fwCtx = frameworkContext; } synchronized void open() { if (fwCtx.debug.hooks) { fwCtx.debug.println("Begin Tracking Resolver Hooks"); } resolverHookTracker = new ServiceTracker( (BundleContext) fwCtx.systemBundle.bundleContext, ResolverHookFactory.class, new ServiceTrackerCustomizer() { public TrackedResolverHookFactory addingService( ServiceReference reference) { return new TrackedResolverHookFactory( (ResolverHookFactory) fwCtx.systemBundle.bundleContext .getService(reference), reference.getBundle()); } public void modifiedService(ServiceReference reference, TrackedResolverHookFactory service) { } public void removedService(ServiceReference reference, TrackedResolverHookFactory service) { service.resetResolverHook(); } }); resolverHookTracker.open(); } synchronized void close() { resolverHookTracker.close(); resolverHookTracker = null; } boolean isOpen() { return resolverHookTracker != null; } synchronized void beginResolve(final BundleImpl [] triggers) throws BundleException { if (!isOpen()) { return; } if (currentTriggers == null) { Collection triggerCollection = new ArrayList(); for (BundleImpl b : triggers) { triggerCollection.add(b.current().bundleRevision); } active = new ArrayList(); for (Entry, TrackedResolverHookFactory> e : resolverHookTracker.getTracked().entrySet()) { TrackedResolverHookFactory rhf = resolverHookTracker.getService(e.getKey()); if (null != rhf) { blockResolveForHooks(); try { if (rhf.begin(triggerCollection)) { active.add(rhf); currentTriggers = triggers; } } catch (RuntimeException re) { throw new BundleException("Resolver hook throw an exception, bid=" + rhf.bundle.getBundleId(), BundleException.REJECTED_BY_HOOK, re); } finally { unblockResolveForHooks(); } } } if (active.isEmpty()) { active = null; } else { resolvableBundles = new HashMap(); } } } synchronized void endResolve(final BundleImpl [] triggers) throws BundleException { if (triggers == currentTriggers) { BundleException saved = null; if (active != null) { blockResolveForHooks(); for (TrackedResolverHookFactory rhf : active) { final ResolverHook rh = rhf.getResolverHook(); try { rh.end(); } catch (RuntimeException re) { saved = new BundleException("Resolver end hook throw an exception, bid=" + rhf.bundle.getBundleId(), BundleException.REJECTED_BY_HOOK, re); } } unblockResolveForHooks(); active = null; resolvableBundles = null; } currentTriggers = null; if (saved != null) { throw saved; } } } void filterMatches(BundleRequirement requirement , Collection candidates) throws BundleException { if (hasHooks()) { @SuppressWarnings("unchecked") Collection c = new RemoveOnlyCollection((Collection) candidates); blockResolveForHooks(); try { for (TrackedResolverHookFactory rhf : active) { final ResolverHook rh = checkActiveRemoved(rhf); try { rh.filterMatches(requirement, c); } catch (RuntimeException re) { throw new BundleException("Resolver hook throw an exception, bid=" + rhf.bundle.getBundleId(), BundleException.REJECTED_BY_HOOK, re); } } } finally { unblockResolveForHooks(); } } } boolean filterMatches(BundleRequirement requirement , BundleCapability candidate) throws BundleException { if (hasHooks()) { Collection c = new ShrinkableSingletonCollection(candidate); filterMatches(requirement, c); return !c.isEmpty(); } return true; } boolean filterResolvable(BundleGeneration bg) throws BundleException { if (hasHooks()) { Boolean res = resolvableBundles.get(bg); if (res == null) { Collection c = new ShrinkableSingletonCollection(bg.bundleRevision); blockResolveForHooks(); try { for (TrackedResolverHookFactory rhf : active) { final ResolverHook rh = checkActiveRemoved(rhf); try { rh.filterResolvable(c); } catch (RuntimeException re) { throw new BundleException("Resolver hook throw an exception, bid=" + rhf.bundle.getBundleId(), BundleException.REJECTED_BY_HOOK, re); } } } finally { unblockResolveForHooks(); } res = Boolean.valueOf(!c.isEmpty()); resolvableBundles.put(bg, res); } return res.booleanValue(); } return true; } void filterSingletonCollisions(BundleCapability singleton , Collection candidates) throws BundleException { if (hasHooks()) { Collection c = new RemoveOnlyCollection(candidates); blockResolveForHooks(); try { for (TrackedResolverHookFactory rhf : active) { final ResolverHook rh = checkActiveRemoved(rhf); try { rh.filterSingletonCollisions(singleton, c); } catch (RuntimeException re) { throw new BundleException("Resolver hook throw an exception, bid=" + rhf.bundle.getBundleId(), BundleException.REJECTED_BY_HOOK, re); } } } finally { unblockResolveForHooks(); } } } void checkResolveBlocked() { if (blockThread != null && Thread.currentThread() == blockThread) { throw new IllegalStateException("Resolve hooks aren't allowed to resolve bundle"); } } boolean hasHooks() throws BundleException { return active != null; } private ResolverHook checkActiveRemoved(TrackedResolverHookFactory rhf) throws BundleException { ResolverHook rh = rhf.getResolverHook(); if (null == rh) { throw new BundleException("Resolver hook service was unregistered", BundleException.REJECTED_BY_HOOK); } return rh; } private void blockResolveForHooks() { blockThread = Thread.currentThread(); } private void unblockResolveForHooks() { blockThread = null; } // Classes static class TrackedResolverHookFactory { final ResolverHookFactory tracked; final Bundle bundle; private ResolverHook resolverHook = null; TrackedResolverHookFactory(ResolverHookFactory tracked, Bundle bundle) { this.tracked = tracked; this.bundle = bundle; } boolean begin(final Collection triggers) { resolverHook = tracked.begin(triggers); return resolverHook != null; } ResolverHook getResolverHook() { return resolverHook; } void resetResolverHook() { resolverHook = null; } } static class ShrinkableSingletonCollection extends AbstractCollection { T singleton; public ShrinkableSingletonCollection(T singleton) { this.singleton = singleton; } @Override public boolean add(T br) { throw new UnsupportedOperationException("Add not allowed"); } @Override public boolean addAll(Collection c) { throw new UnsupportedOperationException("Add not allowed"); } @Override public boolean isEmpty() { return singleton == null; } @Override public Iterator iterator() { return new Iterator() { boolean hasNext = !isEmpty(); @Override public boolean hasNext() { return hasNext; } @Override public T next() { if (hasNext) { hasNext = false; if (isEmpty()) { throw new ConcurrentModificationException(); } return singleton; } throw new NoSuchElementException(); } @Override public void remove() { if (hasNext || isEmpty()) { throw new IllegalStateException(); } singleton = null; } }; } @Override public boolean remove(Object o) { if (singleton != null && singleton.equals(o)) { singleton = null; return true; } return false; } @Override public int size() { return singleton != null ? 1 : 0; } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/AutoManifest.java0000644000175000017500000004141512346513666030434 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.jar.Attributes; import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.osgi.framework.Constants; /** * Manifest subclass which modifies some of the attributes automatically. * This can be used to add or remove manifest headers to any loaded bundle. For example, * adding package import/export headers. * *

* To enable automatic manifest generation, set the system property *

*
 *  org.knopflerfish.framework.automanifest=true
 * 
* *

* The automatic manifest config can be specified as an URL using * the system property: *

*
 *  org.knopflerfish.framework.automanifest.config=[URL]
 * 
* *

* Default is "!!/automanifest.props" The "!!" part is used to refer * to a resource on the system classloader, but any URL can be used. *

* *

* The configuration file for automatic manifest generation is on java property * file format with any number of sections as: *

 * [id].match.filter=[ldap filter]
 * [id].export.filter=[ldap filter]
 * [id].export.file.filter=[ldap filter]
 * [id].header.[header-name]=[header-value]
 * [id].header.[header-name]=[header-value]
 * [id].header.[header-name]=[header-value]
 * ...
 * 
* *

* The default config file only has one section, setting all installed * bundles to automatically export all of their packages, and dynamically * install every class. This is implemented by a single section: *

*
 * 1.match.filter=(location=*)
 * 1.export.filter=(pkg=*)
 * 1.export.file.filter=(file=*.class)
 * 1.header.DynamicImport-Package=*
 * 1.header.Import-Package=[remove]
 * 1.header.Export-Package=[autoexport]
 * 
* *

* [id] is any string. The [id] is also used for sorting the sections. Matching is * done is this sort order. *

* *

* The match.filter value is an LDAP filter expression used to select * which bundles the section applies to. Only the first matching section is applied to * a bundle. All original bundle manifest attributes can be used in the matching, plus the * special key "location" which represents the bundle location string. *

* *

* The export.filter value is an LDAP filter expression which selects * which resources are valid for automatic package export. The special * key "pkg" represents the export candidate. E.g. a filter of "(pkg=*)" * exports all packages. *

* *

* The export.file.filter value is an optional LDAP filter expression which selects * which files are considered for auto package generation. The special key * key "file" represents the file candidate. E.g. a filter of "(name=*)" * considers all files. Default is "(file=*.class) *

* *

* The [header-name] values are stored directly in the generated * manifest. Any number of header names can be specified. *

* *

* Two special header values can be used: *

*
 *  "[remove]"     -  Removes the header completely from the manifest
 *  "[autoexport]" -  Uses the generated package names as value.
 *                    Package names are only present if the passes
 *                    the export.filter
 * 
*

* Note 1: An extra attribute * "Bundle-AutoManifest-config" * is always added to the manifest. The value is the URL of the config file *

* *

* Note 2: Debug output of automatic manifest can be enabled by setting the system property *

*
 * org.knopflerfish.framework.debug.automanifest=true
 * 
* * @author Erik Wistrand */ public class AutoManifest extends Manifest { FrameworkContext fwCtx; Manifest mf; String location; AutoInfo autoInfo; Attributes mainAttrs; Set packages = new TreeSet(); static String configSource = null; static Map configs = null; /** * Create an AutoManifest instance based on an original manifest * and a bundle location. * *

* An AutoManifest instance is a proxy to the original manifest except in the * case of getting the main attributes. In this case the result may be modified * according the auto manifest configuration file. *

* *

* Note: The first time an AutoManifest instance is created, the configuration * file is read. *

* * @param mf original manifest. Must not be null. * @param location bundle location. Must not be null. */ public AutoManifest(FrameworkContext fwCtx, Manifest mf, String location) { if(mf == null) { throw new NullPointerException("Manifest cannot be null"); } if(location == null) { throw new NullPointerException("location cannot be null"); } this.fwCtx = fwCtx; this.mf = mf; this.location = location; // just read the config once if(configs == null) { if(fwCtx.props.getBooleanProperty(FWProps.AUTOMANIFEST_PROP)) { configSource = fwCtx.props.getProperty(FWProps.AUTOMANIFEST_CONFIG_PROP); configs = loadConfig(configSource); if(fwCtx.debug.automanifest) { fwCtx.debug.println("Loaded auto manifest config from " + configSource); } } else { configs = new TreeMap(); } } autoInfo = findConfig(); if(isAuto() && fwCtx.debug.automanifest) { fwCtx.debug.println("Using auto manifest for bundlelocation " + location); } } /** * Check if manifest generation is enabled for this instance. */ public boolean isAuto() { return autoInfo != null; } /** * Delegate to original manifest. */ @Override public void clear() { mf.clear(); mainAttrs = null; } /** * Delegate to original manifest. */ @Override public Attributes getAttributes(String name) { return mf.getAttributes(name); } /** * Delegate to original manifest. */ @Override public Map getEntries() { return mf.getEntries(); } /** * Delegate to original manifest. */ @Override public void read(InputStream is) throws IOException { mf.read(is); mainAttrs = null; } /** * Delegate to original manifest. */ @Override public void write(OutputStream out) throws IOException { mf.write(out); } /** * Get the original manifest */ public Manifest getManifest() { return mf; } /** * Get the bundle location */ public String getLocation() { return location; } /** * AutoManifests are equal if both the original manifest * and the bundle location are equal. */ @Override public boolean equals(Object obj) { if(obj == null || !(obj instanceof AutoManifest)) { return false; } final AutoManifest af = (AutoManifest)obj; return mf.equals(af.mf) && location.equals(af.location); } /** * Hash code base on original manifest and loation */ @Override public int hashCode() { return mf.hashCode() + 17 * location.hashCode(); } /** * Get the main manifest attributes, possibly modified. */ @Override public Attributes getMainAttributes() { if(mainAttrs == null) { // Get the original attribs and modify them according to // autoInfo config (if present) mainAttrs = mf.getMainAttributes(); if(autoInfo != null) { // store a flag for debug purposes mainAttrs.putValue("Bundle-AutoManifest-config", configSource); for (final String key : autoInfo.headers.keySet()) { final String val = autoInfo.headers.get(key); if("[remove]".equals(val)) { mainAttrs.remove(new Attributes.Name(key)); } else if("[autoexport]".equals(val)) { final String exports = getExports(); if(fwCtx.debug.automanifest) { fwCtx.debug.println("Auto exports for " + location + ": " + exports); } if(exports.length() > 0) { mainAttrs.putValue(Constants.EXPORT_PACKAGE, exports); } else { mainAttrs.remove(new Attributes.Name(Constants.EXPORT_PACKAGE)); } } else { mainAttrs.putValue(key, val); } } } } return mainAttrs; } /** * Add a File for automatic package export consideration. */ public void addFile(File file) throws IOException { addFile(file.getAbsolutePath(), file); } /** * Add a File for automatic package export consideration. */ public void addFile(String prefix, File file) throws IOException { final String f = prefix.length() < file.getAbsolutePath().length() ? file.getAbsolutePath().substring(prefix.length() + 1) : file.getAbsolutePath(); if(f.endsWith(".jar")) { addZipFile(new ZipFile(file)); } else if(isValidFileName(f)) { addFileName(f); } else if(file.isDirectory()) { final String[] files = file.list(); for (final String file2 : files) { addFile(prefix, new File(file.getAbsolutePath(), file2)); } } } // used to avoid recreating a new hash table at each isValidFileName() call private final Hashtable fileProps = new Hashtable(); private boolean isValidFileName(String f) { if(autoInfo != null && autoInfo.fileNameFilter != null) { fileProps.put("file", f); return autoInfo.fileNameFilter.evaluate(fileProps, true); } else { return f.endsWith(".class"); } } /** * Add contents of a ZipFile for automatic package export consideration. */ public void addZipFile(ZipFile jar) { for(final Enumeration e = jar.entries(); e.hasMoreElements(); ) { final ZipEntry ze = e.nextElement(); final String f = ze.getName(); if(isValidFileName(f)) { addFileName(f); } } } /** * Add a string file name for automatic package export consideration. */ public void addFileName(String f) { // transform file path to package name f = f.replace('\\', '/'); // ..and strip last part final int ix = f.lastIndexOf("/"); if(ix != -1) { f = f.substring(0, ix); } f = f.replace('/', '.'); // check all export patterns if the file matches. // If so, add to packages set if(autoInfo != null) { final Hashtable props = new Hashtable(); props.put("pkg", f); if(autoInfo.exportFilter.evaluate(props, true)) { if(!packages.contains(f)) { packages.add(f); } } } // clearing mainAttrs will force rebuild of attribut set in getMainAttributes() mainAttrs = null; } /*** * Create Export-Package string from package set * The package set is created by addFileName() calls */ String getExports() { final StringBuffer sb = new StringBuffer(); for (final String pkg : packages) { if(sb.length() > 0) { sb.append(","); } sb.append(pkg); if(autoInfo.version != null) { sb.append(";"); sb.append(autoInfo.version); } } return sb.toString(); } private AutoInfo findConfig() { final Hashtable props = new Hashtable(); props.put("location", location); final Attributes attrs = mf.getMainAttributes(); for (final Object key : attrs.keySet()) { final Object val = attrs.getValue(key.toString()); props.put(key.toString(), val.toString()); } for (final String id : configs.keySet()) { final AutoInfo ai = configs.get(id); if(ai.filter.evaluate(props, true)) { return ai; } } return null; } private Map loadConfig(String urlS) { if(urlS != null && !"".equals(urlS)) { URL url = null; InputStream is = null; try { if(urlS.startsWith("!!")) { url = AutoManifest.class.getResource(urlS.substring(2)); } else { url = new URL(urlS); } is = url.openStream(); return loadConfigFromInputStream(is); } catch (final Exception e) { fwCtx.debug.printStackTrace("Failed to load autoimportexport conf from " + url, e); } finally { try { is.close(); } catch (final Exception ignored) { } } } return new HashMap(); } private Map loadConfigFromInputStream(InputStream is) throws IOException { final Properties props = new Properties(); props.load(is); final Map configMap = new TreeMap(); for (final Object object : props.keySet()) { final String key = (String) object; final int ix = key.indexOf("."); if(ix != -1) { final String id = key.substring(0, ix); final String pattern = (String)props.get(id + ".match.filter"); final String export = (String)props.get(id + ".export.filter"); String fileFilter = (String)props.get(id + ".export.file.filter"); final Map headers = new HashMap(); if(fileFilter == null) { fileFilter = "(file=*.class)"; } final String headerPre = id + ".header."; for (final Object object2 : props.keySet()) { final String key2 = (String) object2; final String val2 = (String) props.get(key2); if(key2.startsWith(headerPre)) { headers.put(key2.substring(headerPre.length()), val2); } } final AutoInfo ai = new AutoInfo(pattern, export, fileFilter, headers); ai.version = (String)props.get(id + ".export.version"); configMap.put(id, ai); } } return configMap; } /** * Helper structure to hold configuration info. */ static class AutoInfo { LDAPExpr filter; LDAPExpr exportFilter; LDAPExpr fileNameFilter; Map headers; String version; AutoInfo(String filter, String export, String nameFilter, Map headers) { try { this.filter = new LDAPExpr(filter); } catch (final Exception e) { throw new RuntimeException("Bad filter '" + filter + "': " +e); } try { this.fileNameFilter = new LDAPExpr(nameFilter); } catch (final Exception e) { throw new RuntimeException("Bad file name filter '" + nameFilter + "': " +e); } try { this.exportFilter = new LDAPExpr(export); } catch (final Exception e) { throw new RuntimeException("Bad export filter '" + export + "': " +e); } this.headers = headers; } @Override public String toString() { return "AutoInfo[" + "filter=" + filter + ", exportFilter="+ exportFilter + ", version=" + version + ", headers=" + headers + "]"; } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ServiceReferenceImpl.java0000644000175000017500000002735212346513664032100 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; import java.util.Vector; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceReference; /** * Implementation of the ServiceReference object. * * @see org.osgi.framework.ServiceReference * @author Jan Stein */ public class ServiceReferenceImpl implements ServiceReference { /** * Link to registration object for this reference. */ private final ServiceRegistrationImpl registration; /** * Construct a ServiceReference based on given ServiceRegistration. * * @param reg ServiceRegistration pointed to be this reference. */ ServiceReferenceImpl(ServiceRegistrationImpl reg) { registration = reg; } // // ServiceReference interface // /** * Get the value of a service's property. * * @see org.osgi.framework.ServiceReference#getProperty */ public Object getProperty(String key) { return cloneObject(registration.getProperty(key)); } /** * Get the list of key names for the service's properties. * * @see org.osgi.framework.ServiceReference#getPropertyKeys */ public String[] getPropertyKeys() { return registration.getProperties().keyArray(); } /** * Return the bundle which registered the service. * * @see org.osgi.framework.ServiceReference#getBundle */ public Bundle getBundle() { return registration.bundle; } /** * Test if ServiceReferences points to same service. * * @see org.osgi.framework.ServiceReference */ @Override public boolean equals(Object o) { if (o instanceof ServiceReferenceImpl) { final ServiceReferenceImpl that = (ServiceReferenceImpl)o; return registration == that.registration; } return false; } /** * Compare two ServiceReferences * * @see org.osgi.framework.ServiceReference */ public int compareTo(Object obj) { final ServiceReference that = (ServiceReference)obj; boolean sameFw = false; if (that instanceof ServiceReferenceImpl) { final ServiceReferenceImpl thatImpl = (ServiceReferenceImpl) that; sameFw = this.registration.fwCtx == thatImpl.registration.fwCtx; } if (!sameFw) { throw new IllegalArgumentException("Can not compare service references " +"belonging to different framework " +"instances (this=" +this +", other=" +that +")."); } final Object ro1 = this.getProperty(Constants.SERVICE_RANKING); final Object ro2 = that.getProperty(Constants.SERVICE_RANKING); final int r1 = (ro1 instanceof Integer) ? ((Integer)ro1).intValue() : 0; final int r2 = (ro2 instanceof Integer) ? ((Integer)ro2).intValue() : 0; if (r1 != r2) { // use ranking if ranking differs return r1 < r2 ? -1 : 1; } else { final Long id1 = (Long)this.getProperty(Constants.SERVICE_ID); final Long id2 = (Long)that.getProperty(Constants.SERVICE_ID); // otherwise compare using IDs, // is less than if it has a higher ID. return id2.compareTo(id1); } } /** * Return a hashcode for the service. * * @see org.osgi.framework.ServiceReference */ @Override public int hashCode() { return registration.hashCode(); } // // ServiceReference interface OSGI R2 // /** * Return the bundles that are using the service wrapped by this * ServiceReference, i.e., whose usage count for this service * is greater than zero. * * @return array of bundles whose usage count for the service wrapped by * this ServiceReference is greater than zero, or null if no * bundles currently are using this service * * @since 1.1 */ public Bundle[] getUsingBundles() { return registration.getUsingBundles(); } // // Package methods // /** * Get the service object. * * @param bundle requester of service. * @return Service requested or null in case of failure. */ S getService(final BundleImpl bundle) { bundle.fwCtx.perm.checkGetServicePerms(this); return registration.getService(bundle); } /** * Unget the service object. * * @param bundle Bundle who wants remove service. * @return True if service was used, otherwise false. */ boolean ungetService(BundleImpl bundle) { return registration.ungetService(bundle, true); } /** * Get all properties registered with this service. * * @return Dictionary containing properties or null * if service has been removed. */ PropertiesDictionary getProperties() { return registration.getProperties(); } // // Private methods // /** * Clone object. Handles all service property types * and does this recursively. * * @param bundle Object to clone. * @return Cloned object. */ Object cloneObject(Object val) { if (val instanceof Object []) { val = ((Object [])val).clone(); final int len = Array.getLength(val); if (len > 0 && Array.get(val, 0).getClass().isArray()) { for (int i = 0; i < len; i++) { Array.set(val, i, cloneObject(Array.get(val, i))); } } } else if (val instanceof boolean []) { val = ((boolean [])val).clone(); } else if (val instanceof byte []) { val = ((byte [])val).clone(); } else if (val instanceof char []) { val = ((char [])val).clone(); } else if (val instanceof double []) { val = ((double [])val).clone(); } else if (val instanceof float []) { val = ((float [])val).clone(); } else if (val instanceof int []) { val = ((int [])val).clone(); } else if (val instanceof long []) { val = ((long [])val).clone(); } else if (val instanceof short []) { val = ((short [])val).clone(); } else if (val instanceof Vector) { @SuppressWarnings({ "rawtypes", "unchecked" }) final Vector c = (Vector)((Vector)val).clone(); for (int i = 0; i < c.size(); i++) { c.setElementAt(cloneObject(c.elementAt(i)), i); } val = c; } return val; } public boolean isAssignableTo(Bundle bundle, String className) { final BundleImpl sBundle = registration.bundle; if (sBundle == null) { throw new IllegalStateException("Service is unregistered"); } final FrameworkContext fwCtx = sBundle.fwCtx; if (((BundleImpl)bundle).fwCtx != fwCtx) { throw new IllegalArgumentException("Bundle is not from same framework as service"); } // Check if bootdelegated if (fwCtx.isBootDelegated(className)) { return true; } final int pos = className.lastIndexOf('.'); if (pos != -1) { final String name = className.substring(0, pos); final Pkg p = fwCtx.resolver.getPkg(name); // Is package exported by a bundle if (p != null) { final BundlePackages rbp = sBundle.current().bpkgs; final BundlePackages pkgExporter = rbp.getProviderBundlePackages(name); List pkgProvider; if (pkgExporter == null) { // Package not imported by provide, is it required pkgProvider = rbp.getRequiredBundleGenerations(name); } else { pkgProvider = new ArrayList(1); pkgProvider.add(pkgExporter.bg); } final BundlePackages bb = ((BundleImpl)bundle).current().bpkgs; final BundlePackages bbp = bb.getProviderBundlePackages(name); List pkgConsumer; if (bbp == null) { // Package not imported by bundle, is it required pkgConsumer = bb.getRequiredBundleGenerations(name); } else { pkgConsumer = new ArrayList(1); pkgConsumer.add(bbp.bg); } if (pkgConsumer == null) { // NYI! Check dynamic import? if (bb.isExported(name)) { // If bundle only exports package, then return true if // bundle is provider. return pkgProvider!=null ? pkgProvider.contains(bb.bg) : true; } else { // If bundle doesn't import or export package, then return true and // assume that the bundle only uses reflection to access service. return true; } } else if (pkgProvider == null) { // Package not imported by registrar. E.g. proxy registration. final Object sService = registration.service; if (sService == null) { throw new IllegalStateException("Service is unregistered"); } if (p.providers.size() == 1) { // Only one version available, allow. return true; } else if (sService instanceof ServiceFactory) { // Factory, allow. return true; } else { // Use the classloader of bundle to load the class, then check // if the service's class is assignable. final ClassLoader bCL = bb.getClassLoader(); if (bCL!=null) { try { final Class bCls = bCL.loadClass(className); // NYI, Handle Service Factories. return bCls.isAssignableFrom(sService.getClass()); } catch (final Exception e) { // If we can not load, assume that we are just a proxy. return true; } } } // Fallback: Always OK when singleton provider of the package } else { // Package imported by both parties // Return true if we have same provider as service. for (final Object element : pkgProvider) { if (pkgConsumer.contains(element)) { return true; } } } } else { // Not a package under package control. System package? if (name.startsWith("java.") || sBundle == bundle) { return true; } else { // NYI! We have a private service, check if bundle can use it. // Now, allow it to handle reflection of service. return true; } } } return false; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/0000755000175000017500000000000012475375714027543 5ustar felixfelix././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/KFSecurityManager.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/KFSecurityManager.0000644000175000017500000000674612346513666033101 0ustar felixfelix/* * Copyright (c) 2009-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.security.AccessControlContext; import java.security.AccessController; import java.security.Permission; import java.util.List; import org.knopflerfish.framework.Debug; import org.knopflerfish.framework.FrameworkContext; public class KFSecurityManager extends SecurityManager implements ConditionalPermissionSecurityManager { private final ThreadLocal> postponementCheck = new ThreadLocal>(); @SuppressWarnings("unused") private final Debug debug; public KFSecurityManager(FrameworkContext fwCtx) { this.debug = fwCtx.debug; } /** * */ @Override public void checkPermission(Permission perm, Object context) { if (!(context instanceof AccessControlContext)) { throw new SecurityException("Context not an AccessControlContext"); } final PostponementCheck old = postponementCheck.get(); final PostponementCheck pc = new PostponementCheck((AccessControlContext) context, perm, old); postponementCheck.set(pc); try { AccessController.doPrivileged(pc); } finally { postponementCheck.set(old); } } /** * */ @Override public void checkPermission(Permission perm) { checkPermission(perm, getSecurityContext()); } /** * Is it possible to do postponement checks. * This is only possible if a checkPermission via * a ConditionalPermissionSecurityManager is in progress. * * @return true is postponement is available, otherwise false */ public boolean isPostponeAvailable() { return postponementCheck.get() != null; } /** * NYI! Think about security here! */ public void savePostponement(List postponement, Object debug) { final PostponementCheck pc = postponementCheck.get(); pc.savePostponement(postponement, debug); } } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PermissionInfoStorage.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PermissionInfoStor0000644000175000017500000003267012346513666033307 0ustar felixfelix/* * Copyright (c) 2006-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.security.AccessController; import java.security.PermissionCollection; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; import org.osgi.service.permissionadmin.PermissionInfo; import org.knopflerfish.framework.Debug; import org.knopflerfish.framework.FWProps; import org.knopflerfish.framework.FrameworkContext; import org.knopflerfish.framework.Util; class PermissionInfoStorage { final static String DEFAULTPERM = "(java.security.AllPermission)"; private PermissionInfo[] initialDefault = null; private final File permDir; private long lastPermFile; private final HashMap permissions = new HashMap(); private PermissionInfo[] defaultPermissions; private final HashMap> defaultInvalidateCallbacks = new HashMap>(); final private Debug debug; final boolean readOnly; /** * */ public PermissionInfoStorage(FrameworkContext ctx) { debug = ctx.debug; initialDefault = new PermissionInfo[] { new PermissionInfo(DEFAULTPERM) }; defaultPermissions = initialDefault; readOnly = ctx.props.getBooleanProperty(FWProps.READ_ONLY_PROP); permDir = Util.getFileStorage(ctx, "perms", !readOnly); if (permDir == null) { System.err.println("Property org.osgi.framework.dir not set," + "permission data will not be saved between sessions"); } else { load(); } } /** * Get the specified permissions to the bundle with the specified * location. * * @param location The location of the bundle. */ synchronized PermissionInfo[] get(String location, PermissionsWrapper callInvalidate) { final Element res = permissions.get(location); if (res != null) { if (callInvalidate != null) { if (res.invalidateCallback == null) { res.invalidateCallback = new ArrayList(2); } res.invalidateCallback.add(callInvalidate); } return res.pi; } return null; } /** * Get the default permissions. *

* These are the permissions granted to any bundle that does not have * permissions assigned to its location. * * @return the default permissions. */ synchronized PermissionInfo[] getDefault(PermissionsWrapper callInvalidate) { if (callInvalidate != null && callInvalidate.location != null) { ArrayList cil = defaultInvalidateCallbacks.get(callInvalidate.location); if (cil == null) { cil = new ArrayList(2); defaultInvalidateCallbacks.put(callInvalidate.location, cil); } cil.add(callInvalidate); } return defaultPermissions; } /** * Returns the bundle locations that have permissions assigned to them, that * is, bundle locations for which an entry exists in the permission table. * * @return The locations of bundles that have been assigned any permissions, * or null if the permission table is empty. */ synchronized String [] getKeys() { final int size = permissions.size(); if (size == 0) { return null; } else { final String [] res = new String [size]; int ix = 0; for (final String string : permissions.keySet()) { res[ix++] = string; } return res; } } /** * Assigns the specified permissions to the bundle with the specified * location. * * @param location The location of the bundle that will be assigned the * permissions. * @param permissions The permissions to be assigned, or {@code null} if * the specified location is to be removed from the permission table. */ synchronized void put(String location, PermissionInfo[] perms) { final Element old = permissions.put(location, new Element(perms)); save(location, perms); final ArrayList vpw = old != null ? old.invalidateCallback : defaultInvalidateCallbacks.remove(location); if (vpw != null) { for (final PermissionsWrapper permissionsWrapper : vpw) { permissionsWrapper.invalidate(); } } } /** * Sets the default permissions. * *

* These are the permissions granted to any bundle that does not have * permissions assigned to its location. * * @param permissions The default permissions, or {@code null} if the * default permissions are to be removed from the permission table. * @throws SecurityException If the caller does not have * {@code AllPermission}. */ synchronized void putDefault(PermissionInfo[] permissions) { if (permissions != null) { defaultPermissions = permissions; } else { defaultPermissions = initialDefault; } save(null, defaultPermissions); for (final ArrayList pws : defaultInvalidateCallbacks.values()) { for (final PermissionsWrapper pw : pws) { pw.invalidate(); } } defaultInvalidateCallbacks.clear(); } /** * Remove any specified permissions to the bundle with the specified * location. * * @param location The location of the bundle. */ synchronized void remove(String location) { final Element old = permissions.remove(location); save(location, null); if (old != null && old.invalidateCallback != null) { for (final PermissionsWrapper permissionsWrapper : old.invalidateCallback) { permissionsWrapper.invalidate(); } } } /** * Remove any reference to specified permission collection in the * callback tables. * * @param pc The permission collection to purge. */ synchronized void purgeCallback(PermissionCollection pc) { final PermissionsWrapper pw = (PermissionsWrapper)pc; final Element e = permissions.get(pw.location); if (e != null && e.invalidateCallback != null && e.invalidateCallback.remove(pw)) { if (e.invalidateCallback.isEmpty()) { e.invalidateCallback = null; } } else { final ArrayList cil = defaultInvalidateCallbacks.get(pw.location); if (cil != null && cil.remove(pw)) { if (cil.isEmpty()) { defaultInvalidateCallbacks.remove(pw); } } } } // // Private methods // /** * Save a permission array. */ private void save(final String location, final PermissionInfo [] perms) { if (permDir != null && !readOnly) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { File f; String loc; if (location != null) { if (lastPermFile % 20 == 0) { purge(); } f = new File(permDir, Long.toString(++lastPermFile)); loc = location; } else { // NYI! keep backups f = new File(permDir, "default"); loc = "defaultPermissions"; } BufferedWriter out = null; try { out = new BufferedWriter(new FileWriter(f)); int p; while ((p = loc.indexOf('\n')) != -1) { out.write(loc.substring(0, ++p) + " "); loc = loc.substring(p); } out.write(loc + "\n\n"); if (perms != null) { for (final PermissionInfo perm : perms) { out.write(perm.getEncoded() + "\n"); } } else { out.write("NULL\n"); } out.write("\n"); out.close(); } catch (final IOException e) { if (out != null) { try { out.close(); } catch (final IOException ignore) { } f.delete(); } debug.printStackTrace("NYI! Report error", e); } return null; } }); } } /** * Load all saved permission data. */ private void load() { final File[] files = PermUtil.getSortedFiles(permDir); for (final File file : files) { load(file); } try { lastPermFile = Long.parseLong(files[files.length - 1].getName()); } catch (final Exception e) { lastPermFile = -1; } } /** * Load saved permission data from named file. */ private void load(File fh) { BufferedReader in = null; final boolean isDefault = "default".equals(fh.getName()); try { in = new BufferedReader(new FileReader(fh)); final String loc = parseLocation(in); final ArrayList piv = new ArrayList(); // Read permissions int c = in.read(); while (c != -1) { final StringBuffer pe = new StringBuffer(); while (c != -1 && c != '\n') { pe.append((char) c); c = in.read(); } final String line = pe.toString(); if ("NULL".equals(line)) { // Clear any previous entries if (isDefault) { defaultPermissions = null; } else { permissions.remove(loc); } try { in.close(); } catch (final IOException ignore) { } return; } else if ("".equals(line)) { // Correct end with double NL break; } piv.add(new PermissionInfo(line)); c = in.read(); } if (c == -1) { throw new IOException("Premature EOF when parsing permission file: " + fh.getName()); } if (in.read() != -1) { throw new IOException("Garbage at end of file when parsing permission file: " + fh.getName()); } in.close(); final PermissionInfo[] pi = new PermissionInfo[piv.size()]; piv.toArray(pi); if (isDefault) { defaultPermissions = pi; } else { permissions.put(loc, new Element(pi)); } } catch (final IOException e) { if (in != null) { try { in.close(); } catch (final IOException ignore) { } } debug.printStackTrace("NYI! Report error", e); } } /** * Parse location data. */ private String parseLocation(Reader in) throws IOException { final StringBuffer loc = new StringBuffer(); int c; // Read location while ((c = in.read()) != -1) { final char cc = (char)c; if (cc == '\n') { c = in.read(); if (c != ' ') { break; } } loc.append(cc); } return loc.toString(); } /** * Purge old saved permission data. * Keep two latest version of permission data. */ private void purge() { final HashMap foundTwo = new HashMap(); final File[] files = PermUtil.getSortedFiles(permDir); for (int i = files.length - 1; i >= 0; i--) { String loc; BufferedReader in = null; try { in = new BufferedReader(new FileReader(files[i])); loc = parseLocation(in); } catch (final IOException ignore) { files[i].delete(); continue; } finally { if (in != null) { try { in.close(); } catch (final IOException ignore) { } } } final Boolean v = foundTwo.get(loc); if (v != null) { if (v.booleanValue()) { files[i].delete(); } else { foundTwo.put(loc, new Boolean(true)); } } else { foundTwo.put(loc, new Boolean(false)); } } } static class Element { PermissionInfo[] pi; ArrayList /* PermissionsWrapper */ invalidateCallback = null; Element(PermissionInfo[] pi) { this.pi = pi; } } } ././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermissionUpdateImpl.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermiss0000644000175000017500000000551312346513666033275 0ustar felixfelix/* * Copyright (c) 2009-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.util.ArrayList; import java.util.List; import org.osgi.service.condpermadmin.ConditionalPermissionInfo; import org.osgi.service.condpermadmin.ConditionalPermissionUpdate; /** * Framework service to administer Conditional Permissions. Conditional * Permissions can be added to, retrieved from, and removed from the framework. * */ public class ConditionalPermissionUpdateImpl implements ConditionalPermissionUpdate { private final ConditionalPermissionInfoStorage storage; private final ArrayList cpiTable; private final int parent; /** * */ ConditionalPermissionUpdateImpl(ConditionalPermissionInfoStorage cpis, ArrayList org, int generation) { storage = cpis; @SuppressWarnings({ "unchecked", "rawtypes" }) final ArrayList clone = (ArrayList) org.clone(); cpiTable = clone; parent = generation; } /** * */ public List getConditionalPermissionInfos() { return cpiTable; } /** * */ public boolean commit() { return storage.commitUpdate(cpiTable, parent); } } ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PermissionsWrapper.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PermissionsWrapper0000644000175000017500000003401012346513666033335 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.io.File; import java.io.FilePermission; import java.io.InputStream; import java.security.Permission; import java.security.PermissionCollection; import java.security.Permissions; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.NoSuchElementException; import java.util.PropertyPermission; import org.osgi.framework.AdminPermission; import org.osgi.framework.Bundle; import org.osgi.framework.CapabilityPermission; import org.osgi.framework.namespace.ExecutionEnvironmentNamespace; import org.osgi.service.condpermadmin.ConditionalPermissionInfo; import org.osgi.service.permissionadmin.PermissionInfo; import org.knopflerfish.framework.Debug; import org.knopflerfish.framework.FrameworkContext; /** * Wraps Permissions so that we can update it dynamically. * * @author Jan Stein, Philippe Laporte */ public class PermissionsWrapper extends PermissionCollection { private static final long serialVersionUID = 1L; String location; private final Bundle bundle; private final PermissionInfoStorage pinfos; private final ConditionalPermissionInfoStorage cpinfos; private PermissionCollection implicitPermissions; private PermissionCollection localPermissions; private volatile PermissionCollection systemPermissions; private File dataRoot; private boolean readOnly = false; private ArrayList condPermList = null; private ConditionalPermissionSecurityManager cpsm; final private FrameworkContext framework; final private Debug debug; /** * */ PermissionsWrapper(FrameworkContext fw, PermissionInfoStorage pis, ConditionalPermissionInfoStorage cpis, String loc, Bundle b, InputStream localPerms) { this.framework = fw; debug = fw.debug; pinfos = pis; cpinfos = cpis; location = loc; bundle = b; // If location is null, then we have a dummy bundle. // Used for ConditionalPermissionAdmin.getAccessControlerContext() if (loc != null) { final SecurityManager sm = System.getSecurityManager(); if (sm instanceof ConditionalPermissionSecurityManager) { cpsm = (ConditionalPermissionSecurityManager)sm; } dataRoot = fw.getDataStorage(b.getBundleId()); if (localPerms != null) { localPermissions = new PermissionInfoPermissions(fw, dataRoot, localPerms); } implicitPermissions = makeImplicitPermissionCollection(fw, b); } initCondPermList(); systemPermissions = makePermissionCollection(); } /** * */ @Override public void add(Permission permission) { final PermissionCollection p = getPerms(); if (p != null) { p.add(permission); } else { throw new RuntimeException("NYI! Using Conditional Permissions"); } } /** * */ @Override public Enumeration elements() { final PermissionCollection p = getPerms(); if (p == null) { throw new RuntimeException("NYI! Using Conditional Permissions 2"); } return new Enumeration() { private Enumeration implicitElements = implicitPermissions.elements(); private final Enumeration systemElements = p.elements(); public boolean hasMoreElements() { if (implicitElements != null) { if (implicitElements.hasMoreElements()) { return true; } implicitElements = null; } return systemElements.hasMoreElements(); } public Permission nextElement() { if (implicitElements != null) { try { return implicitElements.nextElement(); } catch (final NoSuchElementException _ignore) { } implicitElements = null; } return systemElements.nextElement(); } }; } /** * */ @Override public boolean implies(final Permission permission) { final String me = "PermissionWrapper.implies: "; if (implicitPermissions != null && implicitPermissions.implies(permission)) { if (debug.permissions) { debug.println(me + "Implicitly OK for, " + permission); } return true; } else if (localPermissions != null && !localPermissions.implies(permission)) { if (debug.permissions) { debug.println(me + "No localpermissions for, " + permission); } return false; } else { final PermissionCollection p = getPerms(); boolean res; if (p != null) { res = p.implies(permission); if (debug.permissions) { debug.println(me + (res ? "OK" : "No") + " framework permission for, " + permission); } } else { res = conditionalPermissionImplies(permission); if (debug.permissions) { debug.println(me + (res ? "OK" : "No") + " conditional permission for, " + permission); } } return res; } } /** * */ @Override public boolean isReadOnly() { return readOnly; } /** * */ @Override public void setReadOnly() { if (!readOnly) { readOnly = true; final PermissionCollection p = getPerms(); if (p != null) { p.setReadOnly(); } else { // TBD, Conditional permission already readonly? } } } /** * */ synchronized void invalidate() { systemPermissions = null; } /** * */ private PermissionCollection getPerms0() { if (systemPermissions == null) { final PermissionCollection p = makePermissionCollection(); if (readOnly && p != null) { p.setReadOnly(); } systemPermissions = p; } return systemPermissions; } /** * */ private PermissionCollection getPerms() { if (framework.props.isDoubleCheckedLockingSafe) { if (systemPermissions == null) { synchronized (this) { return getPerms0(); } } return systemPermissions; } else { synchronized (this) { return getPerms0(); } } } /** * */ private PermissionCollection makeImplicitPermissionCollection(FrameworkContext fw, Bundle b) { // NYI, perhaps we should optimize this collection. final Permissions pc = new Permissions(); if (dataRoot != null) { pc.add(new FilePermission(dataRoot.getPath(), "read,write")); pc.add(new FilePermission((new File(dataRoot, "-")).getPath(), "read,write,delete")); } final StringBuffer sb = new StringBuffer("(id="); sb.append(b.getBundleId()); sb.append(")"); pc.add(new AdminPermission(sb.toString(), AdminPermission.RESOURCE + "," + AdminPermission.METADATA + "," + AdminPermission.CLASS)); pc.add(new PropertyPermission("org.osgi.framework.*", "read")); pc.add(new CapabilityPermission(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE, CapabilityPermission.REQUIRE)); return pc; } /** * Create the permissionCollection assigned to the bundle. * The collection contains the configured permissions for the bundle location. * Build the permissionCollection based on a set PermissionInfo objects. All the * permissions that are available in the CLASSPATH are constructed and all the * bundle based permissions are constructed as UnresolvedPermissions. * * @return The permissions assigned to the bundle with the specified * location, or the default permissions if that bundle has not been assigned * any permissions. */ private PermissionCollection makePermissionCollection() { PermissionInfo[] pi = pinfos.get(location, this) ; final boolean useDefault = (pi == null); if (useDefault) { if (cpinfos != null && cpinfos.size() > 0) { return null; } pi = pinfos.getDefault(this); } return new PermissionInfoPermissions(framework, useDefault ? null : dataRoot, pi); } /** * */ private boolean conditionalPermissionImplies(Permission permission) { List postponement; if (cpsm != null && cpsm.isPostponeAvailable()) { postponement = new ArrayList(); } else { postponement = null; } String immediateAccess = null; // TBD, should condPermList by guard from changes!? for (final Object element : condPermList) { final ConditionalPermission cp = (ConditionalPermission)element; if (cp == null) { // Permission is already checked and is immutable and failed. continue; } if (debug.permissions) { debug.println("conditionalPermissionImplies: Check if " + cp + " implies " + permission + " for " + bundle); } if (cp.checkImmediateOk(permission, postponement == null)) { if (postponement != null) { postponement.add(cp); } if (cp.hasPostponed()) { if (debug.permissions) { debug.println("conditionalPermissionImplies: " + cp + " with postponement implies " + permission + " for " + bundle); } } else { if (debug.permissions) { debug.println("conditionalPermissionImplies: " + cp + " implies " + permission + " for " + bundle + ", end search"); } immediateAccess = cp.access; break; } } else { if (debug.permissions) { debug.println("conditionalPermissionImplies: " + cp + " does NOT imply " + permission + " for " + bundle); } } } if (postponement != null) { // Optimize superfluous int offset; if (immediateAccess == null) { immediateAccess = ConditionalPermissionInfo.DENY; offset = 1; } else { offset = 2; } for (int pos = postponement.size() - offset; pos >= 0; pos--) { if (postponement.get(pos).access == immediateAccess) { final Object pruned = postponement.remove(pos); if (debug.permissions) { debug.println("conditionalPermissionImplies: pruned, " + pruned + " for " + bundle); } } else { break; } } // If we only have deny, do deny if (immediateAccess == ConditionalPermissionInfo.DENY && postponement.size() < offset) { return false; } if (debug.permissions) { debug.println("conditionalPermissionImplies: postpone check of " + permission + " for " + bundle); } cpsm.savePostponement(postponement, debug); return true; } else { return immediateAccess == ConditionalPermissionInfo.ALLOW; } } /** * */ synchronized void updateChangedConditionalPermission(ConditionalPermissionInfoImpl cpi, int cpi_pos, int remove_pos, int expected_size) { final ConditionalPermission new_cp = cpi != null ? cpi .getConditionalPermission(bundle) : null; @SuppressWarnings("unused") ConditionalPermission old_cp; if (cpi_pos == remove_pos) { old_cp = condPermList.set(cpi_pos, new_cp); } else if (remove_pos == -1) { condPermList.add(cpi_pos, new_cp); old_cp = null; } else if (cpi_pos == -1) { old_cp = condPermList.remove(remove_pos); } else { // Case with different remove & insert position not used, yet throw new RuntimeException("NYI"); } if (expected_size != condPermList.size()) { debug.printStackTrace("ASSERT, table size differ, " + expected_size + " != " + condPermList.size(), new Throwable()); throw new RuntimeException("ASSERT ERROR"); } // TBD! How to optimize? if (new_cp != null || old_cp != null) { invalidate(); // } } /** * */ private void initCondPermList() { // cpinfos is locked when we are here. final ArrayList cpis = cpinfos.getAll(); condPermList = new ArrayList(cpis.size()); // TBD, perhaps we should go back to lazy instantiation. for (final ConditionalPermissionInfoImpl cpi : cpis) { if (debug.permissions) { debug.println("conditionalPermissionImplies: " + cpi + " Bundle#" + bundle.getBundleId()); } condPermList.add(cpi.getConditionalPermission(bundle)); } invalidate(); } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PermissionsHandle.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PermissionsHandle.0000644000175000017500000001233612346513666033175 0ustar felixfelix/* * Copyright (c) 2006-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.io.InputStream; import java.security.PermissionCollection; import java.security.Policy; import java.util.Hashtable; import java.util.Iterator; import org.osgi.framework.Bundle; import org.knopflerfish.framework.FrameworkContext; /** * */ public class PermissionsHandle { FrameworkContext framework; private final PermissionInfoStorage pinfos; private final ConditionalPermissionInfoStorage cpinfos; private final Hashtable pcCache = new Hashtable(); private final PermissionAdminImpl pa; private final ConditionalPermissionAdminImpl cpa; /** * */ public PermissionsHandle(FrameworkContext fw) { framework = fw; pinfos = new PermissionInfoStorage(fw); pa = new PermissionAdminImpl(pinfos); cpinfos = new ConditionalPermissionInfoStorage(this); cpa = new ConditionalPermissionAdminImpl(cpinfos, pinfos, fw); Policy.setPolicy(new FrameworkPolicy(Policy.getPolicy(), this)); } /** * Get PermissionAdmin service. * * @return PermissionAdmin service object. */ public PermissionAdminImpl getPermissionAdminService() { return pa; } /** * Get ConditionalPermissionAdmin service. * * @return ConditionalPermissionAdmin service object. */ public ConditionalPermissionAdminImpl getConditionalPermissionAdminService() { return cpa; } /** * Gets the permissionCollection assigned to the bundle with the specified id. * The collection contains the configured permissions for the bundle location * plus implicit granted permissions (i.e FilePermission for the data area). * * @param bid The bundle id whose permissions are to be returned. * * @return The permissions assigned to the bundle with the specified * location, or the default permissions if that bundle has not been assigned * any permissions or does not yet exist. */ public PermissionCollection getPermissionCollection(Long bid) { return pcCache.get(bid); } /** * Create the permissionCollection assigned to the bundle. * We return a permission wrapper so that we can change it dynamically. * * @param loc Location of bundle whose permissions are to be created. * @param b Bundle whose permissions are to be created. * @param localPerms New local permissions for the bundle. * * @return The permissions assigned to the bundle with the specified * location */ public PermissionCollection createPermissionCollection(String loc, Bundle b, InputStream localPerms) { final Long bid = new Long(b.getBundleId()); // Need to lock cond.perm. changes, when adding a new PermissionsWrapper PermissionsWrapper pc; synchronized (cpinfos) { pc = new PermissionsWrapper(framework, pinfos, cpinfos, loc, b, localPerms); pcCache.put(bid, pc); } return pc; } /** * Remove cached information about specified bundle. * * @param bid Bundle ID for bundle to be purged. * * @return True if we purged something, which means that we purged the last * permissionCollection not a zombie. */ public boolean purgePermissionCollection(Long bid, PermissionCollection pc) { pinfos.purgeCallback(pc); if (pcCache.get(bid) == pc) { pcCache.remove(bid); return true; } return false; } /** * Get iterator over all active PermissionWrappers. * * @return Iterator of PermissionWrappers */ Iterator getPermissionWrappers() { return pcCache.values().iterator(); } } ././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermissionInfoImpl.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermiss0000644000175000017500000003070712346513666033300 0ustar felixfelix/* * Copyright (c) 2008-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.security.PermissionCollection; import java.util.ArrayList; import java.util.Arrays; import org.osgi.framework.Bundle; import org.osgi.service.condpermadmin.Condition; import org.osgi.service.condpermadmin.ConditionInfo; import org.osgi.service.condpermadmin.ConditionalPermissionInfo; import org.osgi.service.permissionadmin.PermissionInfo; import org.knopflerfish.framework.Debug; import org.knopflerfish.framework.FrameworkContext; /** * A binding of a set of Conditions to a set of Permissions. * */ class ConditionalPermissionInfoImpl implements ConditionalPermissionInfo { private ConditionalPermissionInfoStorage cpis; final private ConditionInfo [] conditionInfos; final private PermissionInfo [] permissionInfos; final private String access; final private FrameworkContext framework; final private Debug debug; private String name; private PermissionCollection permissions; /** */ ConditionalPermissionInfoImpl(ConditionalPermissionInfoStorage cpis, String name, ConditionInfo[] conds, PermissionInfo[] perms, String access, FrameworkContext fw) { this.cpis = cpis; this.name = name; conditionInfos = conds; permissionInfos = perms; this.access = access; framework = fw; debug = fw.debug; permissions = null; } /** */ ConditionalPermissionInfoImpl(ConditionalPermissionInfoStorage cpis, String encoded, FrameworkContext fw) { this.cpis = cpis; framework = fw; debug = fw.debug; try { final char [] eca = encoded.toCharArray(); int pos = PermUtil.skipWhite(eca, 0); if ((eca[pos] == 'A' || eca[pos] == 'a') && (eca[pos+1] == 'L' || eca[pos+1] == 'l') && (eca[pos+2] == 'L' || eca[pos+2] == 'l') && (eca[pos+3] == 'O' || eca[pos+3] == 'o') && (eca[pos+4] == 'W' || eca[pos+4] == 'w') && eca[pos+5] == ' ') { pos += 6; access = ConditionalPermissionInfo.ALLOW; } else if ((eca[pos] == 'D' || eca[pos] == 'd') && (eca[pos+1] == 'E' || eca[pos+1] == 'e') && (eca[pos+2] == 'N' || eca[pos+2] == 'n') && (eca[pos+3] == 'Y' || eca[pos+3] == 'y') && eca[pos+4] == ' ') { pos += 5; access = ConditionalPermissionInfo.DENY; } else { throw new IllegalArgumentException("Access must be allow or deny"); } pos = PermUtil.skipWhite(eca, pos); if (eca[pos++] != '{') { throw new IllegalArgumentException("Missing open brace"); } final ArrayList cal = new ArrayList(); final ArrayList pal = new ArrayList(); boolean seenPermInfo = false; while (true) { pos = PermUtil.skipWhite(eca, pos); char c = eca[pos]; char ec; if (!seenPermInfo && c == '[') { ec = ']'; } else if (c == '(') { ec = ')'; seenPermInfo = true; } else if (c == '}') { pos++; break; } else { throw new IllegalArgumentException("Unexpected char '" + c + "' at pos " + pos); } final int start_pos = pos++; do { c = eca[pos]; if (c == '"') { pos = PermUtil.unquote(eca, pos, null); } else { pos++; } } while(c != ec); final String info = new String(eca, start_pos, pos - start_pos); if (c == ']') { cal.add(new ConditionInfo(info)); } else { pal.add(new PermissionInfo(info)); } } if (!seenPermInfo) { throw new IllegalArgumentException("Permissions must contain atleast one element"); } pos = PermUtil.endOfString(eca, pos, eca.length); if (pos != -1) { final StringBuffer buf = new StringBuffer(); pos = PermUtil.unquote(eca, pos, buf); name = buf.toString(); if ((pos = PermUtil.endOfString(eca, pos, eca.length)) != -1) { throw new IllegalArgumentException("Unexpected characters at end of string: " + new String(eca, pos, eca.length - pos)); } } else { name = null; } conditionInfos = cal.toArray(new ConditionInfo [cal.size()]); permissionInfos = pal.toArray(new PermissionInfo [pal.size()]); } catch (final ArrayIndexOutOfBoundsException e) { throw new IllegalArgumentException("Unexpected end of string"); } } // Interface ConditionalPermissionInfo /** * Returns the Condition Infos for the Conditions that must be satisfied to * enable the Permissions. * * @return The Condition Infos for the Conditions in this Conditional * Permission Info. */ public ConditionInfo[] getConditionInfos() { return conditionInfos; } /** * Returns the Permission Infos for the Permission in this Conditional * Permission Info. * * @return The Permission Infos for the Permission in this Conditional * Permission Info. */ public PermissionInfo[] getPermissionInfos() { return permissionInfos; } /** * Removes this Conditional Permission Info from the Conditional Permission * Admin. * * @throws SecurityException If the caller does not have * AllPermission. */ public void delete() { if (cpis == null) { throw new UnsupportedOperationException("Not in use"); } cpis.remove(this); } /** * Returns the name of this Conditional Permission Info. * * @return The name of this Conditional Permission Info. */ public String getName() { return name; } public String getAccessDecision() { return access; } public String getEncoded() { final StringBuffer res = new StringBuffer(access); res.append(" { "); if (conditionInfos != null) { for (final ConditionInfo conditionInfo : conditionInfos) { res.append(conditionInfo.getEncoded()); res.append(' '); } } if (permissionInfos != null) { for (final PermissionInfo permissionInfo : permissionInfos) { res.append(permissionInfo.getEncoded()); res.append(' '); } } res.append('}'); if (name != null) { res.append(' '); PermUtil.quote(name, res); } return res.toString(); } /** * Returns a string representation of this object. * */ @Override public String toString() { return getEncoded(); } /** * */ @Override public final boolean equals(Object obj) { if (obj == null) { return false; } if (obj == this) { return true; } final ConditionalPermissionInfo cpi = (ConditionalPermissionInfo)obj; if (name == null ? cpi.getName() != null : !name.equals(cpi.getName())) { return false; } // NYI, we should allow permuted arrays, also affects hashCode. if (!Arrays.equals(permissionInfos, cpi.getPermissionInfos())) { return false; } if (!Arrays.equals(conditionInfos, cpi.getConditionInfos())) { return false; } return access == cpi.getAccessDecision(); } /** * */ @Override public final int hashCode() { if (name != null) { return name.hashCode(); } final int res = conditionInfos != null && conditionInfos.length > 0 ? conditionInfos[0].hashCode() : 0; return res + permissionInfos[0].hashCode(); } // // Package methods // static final Class[] argClasses = new Class[] {Bundle.class, ConditionInfo.class}; /** * */ ConditionalPermission getConditionalPermission(Bundle bundle) { final String me = "ConditionalPermissionInfoImpl.getConditionalPermission: "; final ArrayList conds = new ArrayList(conditionInfos==null ? 0 :conditionInfos.length); if (conditionInfos != null) { for (final ConditionInfo conditionInfo : conditionInfos) { Class clazz; Condition c; try { clazz = Class.forName(conditionInfo.getType(), true, framework.getClassLoader(null)); Constructor cons = null; Method method = null; try { method = clazz.getMethod("getCondition", argClasses); if ((method.getModifiers() & Modifier.STATIC) == 0) { method = null; } } catch (final NoSuchMethodException ignore) { } if (method != null) { if (debug.permissions) { debug.println(me + "Invoke, " + method + " for bundle " + bundle); } c = (Condition) method.invoke(null, new Object[] { bundle, conditionInfo }); } else { try { cons = clazz.getConstructor(argClasses); } catch (final NoSuchMethodException ignore) { } if (cons != null) { if (debug.permissions) { debug.println(me + "Construct, " + cons + " for bundle " + bundle); } c = (Condition) cons.newInstance(new Object[] { bundle, conditionInfo }); } else { debug.println("NYI! Log faulty ConditionInfo object!?"); continue; } } if (!c.isMutable()) { if (!c.isPostponed() /* || debug.tck401compat */) { if (c.isSatisfied()) { if (debug.permissions) { debug.println(me + "Immutable condition ok, continue"); } continue; } else { if (debug.permissions) { debug.println(me + "Immutable condition NOT ok, abort"); } return null; } } } conds.add(c); } catch (final Throwable t) { debug.printStackTrace("NYI! Log failed Condition creation", t); return null; } } } final Condition[] conditions = conds.toArray(new Condition[conds.size()]); return new ConditionalPermission(conditions, getPermissions(), access, this); } /** * */ PermissionCollection getPermissions() { if (permissions == null) { permissions = new PermissionInfoPermissions(framework, null, permissionInfos); } return permissions; } /** * Set storage for this Conditional Permission Info. * */ void setPermissionInfoStorage(ConditionalPermissionInfoStorage storage) { cpis = storage; } /** * Set the name of this Conditional Permission Info. * */ void setName(String newName) { name = newName; } } ././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermissionAdminImpl.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermiss0000644000175000017500000003561212346513666033300 0ustar felixfelix/* * Copyright (c) 2008-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.io.File; import java.io.InputStream; import java.math.BigInteger; import java.net.URL; import java.security.AccessControlContext; import java.security.PermissionCollection; import java.security.Principal; import java.security.ProtectionDomain; import java.security.PublicKey; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Date; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.framework.Version; import org.osgi.service.condpermadmin.ConditionInfo; import org.osgi.service.condpermadmin.ConditionalPermissionAdmin; import org.osgi.service.condpermadmin.ConditionalPermissionInfo; import org.osgi.service.condpermadmin.ConditionalPermissionUpdate; import org.osgi.service.permissionadmin.PermissionInfo; import org.knopflerfish.framework.FrameworkContext; import org.knopflerfish.framework.Util; /** * Framework service to administer Conditional Permissions. Conditional * Permissions can be added to, retrieved from, and removed from the framework. * */ public class ConditionalPermissionAdminImpl implements ConditionalPermissionAdmin { public final static String SPEC_VERSION = "1.1.0"; private final ConditionalPermissionInfoStorage cpis; private final PermissionInfoStorage pis; final private FrameworkContext framework; /** * */ public ConditionalPermissionAdminImpl(ConditionalPermissionInfoStorage cpis, PermissionInfoStorage pis, FrameworkContext framework) { this.cpis = cpis; this.pis = pis; this.framework = framework; } // // Interface ConditionalPermissionAdmin // /** * Create a new Conditional Permission Info. * * The Conditional Permission Info will be given a unique, never reused * name. * * @param conds The Conditions that need to be satisfied to enable the * corresponding Permissions. * @param perms The Permissions that are enable when the corresponding * Conditions are satisfied. * @return The ConditionalPermissionInfo for the specified Conditions and * Permissions. * @throws SecurityException If the caller does not have * AllPermission. */ public ConditionalPermissionInfo addConditionalPermissionInfo(ConditionInfo conds[], PermissionInfo perms[]) { return cpis.put(null, conds, perms); } /** * Set or create a Conditional Permission Info with a specified name. * * If the specified name is {@code null}, a new Conditional * Permission Info must be created and will be given a unique, never reused * name. If there is currently no Conditional Permission Info with the * specified name, a new Conditional Permission Info must be created with * the specified name. Otherwise, the Conditional Permission Info with the * specified name must be updated with the specified Conditions and * Permissions. * * @param name The name of the Conditional Permission Info, or * {@code null}. * @param conds The Conditions that need to be satisfied to enable the * corresponding Permissions. * @param perms The Permissions that are enable when the corresponding * Conditions are satisfied. * @return The ConditionalPermissionInfo that for the specified name, * Conditions and Permissions. * @throws SecurityException If the caller does not have * AllPermission. */ public ConditionalPermissionInfo setConditionalPermissionInfo(String name, ConditionInfo conds[], PermissionInfo perms[]) { return cpis.put(name, conds, perms); } /** * Returns the Conditional Permission Infos that are currently managed by * Conditional Permission Admin. Calling * {@link ConditionalPermissionInfo#delete()} will remove the Conditional * Permission Info from Conditional Permission Admin. * * @return An enumeration of the Conditional Permission Infos that are * currently managed by Conditional Permission Admin. */ public Enumeration getConditionalPermissionInfos() { return cpis.getAllEnumeration(); } /** * Return the Conditional Permission Info with the specified name. * * @param name The name of the Conditional Permission Info to be returned. * @return The Conditional Permission Info with the specified name. */ public ConditionalPermissionInfo getConditionalPermissionInfo(String name) { return cpis.get(name); } /** * Returns the Access Control Context that corresponds to the specified * signers. * * @param signers The signers for which to return an Access Control Context. * @return An AccessControlContext that has the Permissions * associated with the signer. */ public AccessControlContext getAccessControlContext(String[] signers) { PermissionCollection perms; synchronized (cpis) { perms = new PermissionsWrapper(framework, pis, cpis, null, new DummyBundle(signers), null); } return new AccessControlContext(new ProtectionDomain[] {new ProtectionDomain(null, perms)}); } /** * * @see org.osgi.service.condpermadmin.ConditionalPermissionAdmin#newConditionalPermissionUpdate() */ public ConditionalPermissionUpdate newConditionalPermissionUpdate() { return cpis.getUpdate(); } /** * * @see org.osgi.service.condpermadmin.ConditionalPermissionAdmin#newConditionalPermissionInfo() */ public ConditionalPermissionInfo newConditionalPermissionInfo(String name, ConditionInfo conditions[], PermissionInfo permissions[], String access) { if (ConditionalPermissionInfo.ALLOW.equalsIgnoreCase(access)) { access = ConditionalPermissionInfo.ALLOW; } else if (ConditionalPermissionInfo.DENY.equalsIgnoreCase(access)) { access = ConditionalPermissionInfo.DENY; } else { throw new IllegalArgumentException("access must be " + ConditionalPermissionInfo.ALLOW + " or " + ConditionalPermissionInfo.DENY); } if (permissions == null || permissions.length == 0) { throw new IllegalArgumentException("permissions must contain atleast one element"); } return new ConditionalPermissionInfoImpl(cpis, name, conditions, permissions, access, framework); } /** * * @see org.osgi.service.condpermadmin.ConditionalPermissionAdmin#newConditionalPermissionInfo() */ public ConditionalPermissionInfo newConditionalPermissionInfo(String encoded) { return new ConditionalPermissionInfoImpl(cpis, encoded, framework); } /** * Dummy Bundle class only used for getAccessControlContext(). */ static class DummyBundle implements Bundle { private final HashMap> signerMap = new HashMap>(); DummyBundle(String [] signers) { for (final String signer : signers) { final String [] chain = Util.splitwords(signer, ";"); final ArrayList tmp = new ArrayList(chain.length); for (final String element : chain) { tmp.add(new X509Dummy(element)); } signerMap.put(tmp.get(0), tmp); } } public int getState() { return UNINSTALLED; } public void start() { start(0); } public void start(int options) { throw new IllegalStateException("Bundle is uninstalled"); } public void stop() { stop(0); } public void stop(int options) { throw new IllegalStateException("Bundle is uninstalled"); } public void update() { update(null); } public void update(final InputStream in) { throw new IllegalStateException("Bundle is uninstalled"); } public void uninstall() { throw new IllegalStateException("Bundle is uninstalled"); } public Dictionary getHeaders() { return getHeaders(null); } public long getBundleId() { return -1; } public String getLocation() { return ""; } public ServiceReference[] getRegisteredServices() { throw new IllegalStateException("Bundle is uninstalled"); } public ServiceReference[] getServicesInUse() { throw new IllegalStateException("Bundle is uninstalled"); } public boolean hasPermission(Object permission) { throw new IllegalStateException("Bundle is uninstalled"); } public BundleContext getBundleContext() { return null; } public URL getResource(String name) { throw new IllegalStateException("Bundle is uninstalled"); } public String getSymbolicName() { return null; } public long getLastModified() { return 0; } public Map> getSignerCertificates(int signersType) { @SuppressWarnings("unchecked") final Map> res = (Map>) signerMap.clone(); return res; } public Version getVersion() { return Version.emptyVersion; } public A adapt(Class type) { return null; } public File getDataFile(String filename) { throw new IllegalStateException("Bundle is uninstalled"); } public Enumeration findEntries(String path, String filePattern, boolean recurse) { throw new IllegalStateException("Bundle is uninstalled"); } public URL getEntry(String name) { throw new IllegalStateException("Bundle is uninstalled"); } public Enumeration getEntryPaths(String path) { throw new IllegalStateException("Bundle is uninstalled"); } public Dictionary getHeaders(String locale) { return new Hashtable(); } public Enumeration getResources(String name) { throw new IllegalStateException("Bundle is uninstalled"); } public Class loadClass(final String name) { throw new IllegalStateException("Bundle is uninstalled"); } public int compareTo(Bundle bundle) { return 0; } } /** * Dummy X509 class only used for getAccessControlContext(). */ static class X509Dummy extends X509Certificate { Principal subject; X509Dummy(String dn) { super(); subject = new PrincipalDummy(dn); } @Override public void checkValidity() { } @Override public void checkValidity(Date date) { } @Override public int getVersion() { return 1; } @Override public BigInteger getSerialNumber() { return null; } @Override public Principal getIssuerDN() { return null; } @Override public Principal getSubjectDN() { return subject; } @Override public Date getNotBefore() { return null; } @Override public Date getNotAfter() { return null; } @Override public byte[] getTBSCertificate() { return null; } @Override public byte[] getSignature() { return null; } @Override public String getSigAlgName() { return null; } @Override public String getSigAlgOID() { return null; } @Override public byte[] getSigAlgParams() { return null; } @Override public boolean[] getIssuerUniqueID() { return null; } @Override public boolean[] getSubjectUniqueID() { return null; } @Override public boolean[] getKeyUsage() { return null; } @Override public int getBasicConstraints() { return 0; } @Override public byte [] getEncoded() { return null; } @Override public PublicKey getPublicKey() { return null; } @Override public String toString() { return "X509Dummy, " + subject.getName(); } @Override public void verify(PublicKey k) { } @Override public void verify(PublicKey k, String p) { } public byte [] getExtensionValue(String oid) { return null; } public Set getCriticalExtensionOIDs() { return null; } public Set getNonCriticalExtensionOIDs() { return null; } public boolean hasUnsupportedCriticalExtension() { return false; } @Override public boolean equals(Object o) { return subject.equals(o); } @Override public int hashCode() { return subject.hashCode(); } } /** * Dummy Principal class only used for getAccessControlContext(). */ static class PrincipalDummy implements Principal { final private String name; PrincipalDummy(String dn) { name = dn; } public String getName() { return name; } } } ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PermissionInfoPermissions.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PermissionInfoPerm0000644000175000017500000001540412346513666033257 0ustar felixfelix/* * Copyright (c) 2009-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.io.BufferedReader; import java.io.File; import java.io.FilePermission; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.security.AllPermission; import java.security.Permission; import java.security.PermissionCollection; import java.security.Permissions; import java.security.UnresolvedPermission; import java.util.ArrayList; import java.util.Enumeration; import org.knopflerfish.framework.Debug; import org.knopflerfish.framework.FrameworkContext; import org.osgi.service.permissionadmin.PermissionInfo; /** * Local Permission handling, with lazy loading of permissions * * @author Jan Stein */ class PermissionInfoPermissions extends PermissionCollection { private static final long serialVersionUID = 1L; private Permissions pc ; volatile private PermissionInfo [] pinfo; private int unresolved; final private File dataRoot; final private FrameworkContext framework; final private Debug debug; static final Permission allPermission = new AllPermission(); /** * */ PermissionInfoPermissions(FrameworkContext fw, File root, InputStream ps) { framework = fw; debug = fw.debug; dataRoot = root; try { final BufferedReader dis = new BufferedReader(new InputStreamReader(ps)); String l; final ArrayList tmp = new ArrayList(); while ((l = dis.readLine()) != null) { l = l.trim(); if (l.startsWith("#") || l.startsWith("//") || l.length() == 0) { continue; } try { tmp.add(new PermissionInfo(l)); } catch (final Exception e) { // TODO, handle this error } } if (!tmp.isEmpty()) { pinfo = tmp.toArray(new PermissionInfo[tmp.size()]); } } catch (final IOException e) { // TODO, handle this error } finally { try { ps.close(); } catch (final IOException _ignore) { } } if (pinfo != null) { unresolved = pinfo.length; } else { unresolved = 0; pc = new Permissions(); } } /** * */ PermissionInfoPermissions(FrameworkContext fw, File root, PermissionInfo [] pinfo) { framework = fw; dataRoot = root; debug = fw.debug; if (pinfo != null) { this.pinfo = pinfo.clone(); unresolved = pinfo.length; } else { unresolved = 0; } if (unresolved == 0) { pc = new Permissions(); } } /** * */ @Override public void add(Permission permission) { throw new UnsupportedOperationException("Readonly"); } /** * */ @Override public Enumeration elements() { if (unresolved != 0) { resolve(); } return pc.elements(); } /** * */ @Override public boolean implies(final Permission permission) { if (unresolved != 0) { resolve(); } return pc.implies(permission); } /** * */ @Override public boolean isReadOnly() { return true; } /** * */ @Override public void setReadOnly() { } /** * */ synchronized private void resolve() { if (pinfo == null) { return; } if (pc == null) { pc = new Permissions(); } for (int i = 0; i < pinfo.length; i++) { if (pinfo[i] != null) { final Permission p = makePermission(pinfo[i]); if (p != null) { pc.add(p); unresolved--; pinfo[i] = null; } } else if (debug.permissions) { debug.println("makePermission: Failed to create permission " + pinfo[i]); } } if (unresolved == 0) { pinfo = null; } } /** * * @param pi PermissionInfo to enter into the PermissionCollection. * * @return */ private Permission makePermission(PermissionInfo pi) { final String t = pi.getType(); if ("java.security.AllPermission".equals(t)) { return allPermission; } final ClassLoader cl = framework.getClassLoader(t); if (cl == null) { return null; } final String a = pi.getActions(); String n = pi.getName(); try { final Class pc = Class.forName(t, true, cl); final Constructor c = pc.getConstructor(new Class[] { String.class, String.class }); if (FilePermission.class.equals(pc) && !"<>".equals(n)) { File f = new File(n); // NYI! How should we handle different separator chars. if (!f.isAbsolute()) { if (dataRoot == null) { return null; } f = new File(dataRoot, n); } n = f.getPath(); } return (Permission) c.newInstance(new Object[] { n, a }); } catch (final ClassNotFoundException ignore) { return new UnresolvedPermission(t, n, a, null); } catch (final NoSuchMethodException ignore) { } catch (final InstantiationException ignore) { } catch (final IllegalAccessException ignore) { } catch (final InvocationTargetException ignore) { } return null; } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PostponementCheck.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PostponementCheck.0000644000175000017500000001103712346513666033174 0ustar felixfelix/* * Copyright (c) 2009-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.security.AccessControlContext; import java.security.Permission; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Dictionary; import java.util.HashMap; import java.util.List; import org.osgi.service.condpermadmin.Condition; import org.osgi.service.condpermadmin.ConditionalPermissionInfo; import org.knopflerfish.framework.Debug; class PostponementCheck implements PrivilegedAction { private final AccessControlContext acc; private final Permission perm; private ArrayList> checkedClasses; private ArrayList> ppList = null; private Debug debug = null; /** * */ PostponementCheck(AccessControlContext acc, Permission perm, PostponementCheck previous) { this.acc = acc; this.perm = perm; checkedClasses = previous != null ? previous.getCheckedClasses() : null; } /** * */ ArrayList> getCheckedClasses() { if (checkedClasses != null) { @SuppressWarnings("unchecked") final ArrayList> res = (ArrayList>) checkedClasses.clone(); return res; } return null; } /** * */ public void savePostponement(List postponement, Object debug) { if (ppList == null) { ppList = new ArrayList>(2); this.debug = (Debug)debug; } ppList.add(postponement); } /** * */ public T run() { acc.checkPermission(perm); checkPostponements(); return null; } /** * */ private void checkPostponements() { if (ppList != null) { final HashMap, Dictionary> condDict = new HashMap, Dictionary>(); if (checkedClasses == null) { checkedClasses = new ArrayList>(); } // Loop through all bundle protection domains found on stack for (final List list : ppList) { // Loop through all matching ConditionalPermissions boolean deny = true; for (final Object name : list) { final ConditionalPermission cp = (ConditionalPermission)name; if (!cp.checkPostponedOk(condDict, checkedClasses)) { // ConditionPermissional didn't match, check next continue; } if (cp.access == ConditionalPermissionInfo.ALLOW) { // We allow, check next protection domain deny = false; } break; } if (deny) { // Denied if (debug.permissions) { debug.println("CHECK_POSTPONE: postponement failed"); } throw new SecurityException("Postponed conditions failed"); } } if (debug.permissions) { debug.println("CHECK_POSTPONE: postponement ok"); } } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PermUtil.java0000644000175000017500000001043012346513666032142 0ustar felixfelix/* * Copyright (c) 2006-2010, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.io.*; class PermUtil { /** */ public static StringBuffer quote(String str, StringBuffer out) { if (out == null) { out = new StringBuffer(); } out.append('"'); int len = str.length(); for (int i = 0; i < len; i++) { char c = str.charAt(i); switch (c) { case '"' : case '\\' : out.append('\\'); out.append(c); break; case '\r' : out.append("\\r"); break; case '\n' : out.append("\\n"); break; default : out.append(c); break; } } out.append('"'); return out; } /** */ public static int skipWhite(char [] ca, int pos) { while (Character.isWhitespace(ca[pos])) { pos++; } return pos; } /** */ public static int endOfString(char [] ca, int pos, int len) { while (pos < len && Character.isWhitespace(ca[pos])) { pos++; } return pos == len ? -1 : pos; } /** * */ public static int unquote(char [] ca, int pos, StringBuffer out) { if (ca[pos++] != '"') { throw new IllegalArgumentException("Input not a quoted string"); } while (ca[pos] != '"') { char c = ca[pos++]; if (c == '\\') { switch (ca[pos++]) { case '"' : c = '"'; break; case '\\' : c = '\\'; break; case 'n' : c = '\n'; break; case 'r' : c = '\r'; break; default : throw new IllegalArgumentException("Illegal escape char in quoted string: \\" + ca[pos-1]); } } if (out != null) { out.append(c); } } return pos + 1; } /** * Get data files sorted, first all nonnumeric * and then the numeric in ascending order. */ public static File[] getSortedFiles(File dir) { String[] files = dir.list(); File[] res = new File[files.length]; long[] lfiles = new long[files.length]; int lf = -1; int pos = 0; for (int i = 0; i < files.length; i++) { try { long fval = Long.parseLong(files[i]); int j; for (j = lf; j >= 0; j--) { if (fval > lfiles[j]) { break; } } if (j >= lf) { lfiles[++lf] = fval; } else { lf++; j++; System.arraycopy(lfiles, j, lfiles, j+1, lf-j); lfiles[j] = fval; } files[i] = null; } catch (NumberFormatException ignore) { res[pos++] = new File(dir, files[i]); } } for (int i = 0; i <= lf; i++) { res[pos++] = new File(dir, Long.toString(lfiles[i])); } return res; } } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermission.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermiss0000644000175000017500000001271712346513666033301 0ustar felixfelix/* * Copyright (c) 2008-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.security.Permission; import java.security.PermissionCollection; import java.util.ArrayList; import java.util.Dictionary; import java.util.Hashtable; import java.util.List; import java.util.Map; import org.osgi.service.condpermadmin.Condition; /** * A binding of a set of Conditions to a set of Permissions. * */ public class ConditionalPermission { private final ConditionalPermissionInfoImpl parent; private Condition [] conditions; final private PermissionCollection permissions; private List postponed = null; final String access; /** */ ConditionalPermission(Condition [] conds, PermissionCollection perms, String access, ConditionalPermissionInfoImpl cpi) { conditions = conds; permissions = perms; this.access = access; parent = cpi; } /** * Check immediate conditions and if asked save postponed conditions. * If conditions are fulfilled check permission is ok. * */ boolean checkImmediateOk(Permission perm, boolean checkPostponed) { if (conditions == null) { return false; } postponed = new ArrayList(1); for (int i = 0; i < conditions.length; i++) { final Condition c = conditions[i]; if (c == null) { // Immutable condition has been removed continue; } if (checkPostponed || !c.isPostponed()) { final boolean mutable = c.isMutable(); if (c.isSatisfied()) { if (!mutable) { // Mark always ok by clearing condition element. conditions[i] = null; } } else { if (!mutable) { // Mark always fail by clearing conditions. conditions = null; } postponed = null; return false; } } else { postponed.add(c); } } return permissions.implies(perm); } /** * Check postponed conditions are OK. * */ boolean checkPostponedOk(Map, Dictionary> condDict, List> checkedClasses) { if (conditions == null) { return false; } // Loop through all postponed Conditions for ConditionalPermissions for (final Condition c : postponed) { final Class cc = c.getClass(); if (checkedClasses.contains(cc)) { throw new SecurityException("Postponement condition check recursive for class: " + cc); } Dictionary d = condDict.get(cc); if (d == null) { d = new Hashtable(); condDict.put(cc, d); } checkedClasses.add(cc); try { final boolean m = c.isMutable(); if (c.isSatisfied(new Condition [] {c}, d)) { if (!m) { for (int i = 0; i < conditions.length; i++ ) { if (conditions[i] == c) { conditions[i] = null; break; } } } } else { if (!m) { conditions = null; } // ConditionPermissional didn't match return false; } } catch (final Throwable ignore) { // NYI, Log this failure // ConditionPermissional couldn't be evaluated, treat as fail // TBD should we do this even if we have a DENY CondPerm. return false; } finally { checkedClasses.remove(checkedClasses.size() - 1); } } return true; } /** * Check if we have saved any postponements in last * checkImmediateOk call. */ boolean hasPostponed() { return !postponed.isEmpty(); } /** * */ boolean isParent(ConditionalPermissionInfoImpl cpi) { return cpi == parent; } /** * */ @Override public String toString() { return "HASH: " + hashCode() + " INFO: " + parent.toString(); } } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PermissionAdminImpl.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/PermissionAdminImp0000644000175000017500000001230312346513666033231 0ustar felixfelix/* * Copyright (c) 2003-2010, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.security.AllPermission; import org.osgi.service.permissionadmin.*; /** * Implementation of the PermissionAdmin service. * * @see org.osgi.service.permissionadmin.PermissionAdmin * @author Jan Stein * @author Philippe Laporte */ public class PermissionAdminImpl implements PermissionAdmin { public final static String SPEC_VERSION = "1.2"; /** * AllPermission used for permission check. */ final private AllPermission ALL_PERMISSION = new AllPermission(); final private PermissionInfoStorage pinfos; public PermissionAdminImpl(PermissionInfoStorage pis) { pinfos = pis; } // // Interface PermissionAdmin // /** * Gets the permissions assigned to the bundle with the specified * location. * * @param location The location of the bundle whose permissions are to * be returned. * * @return The permissions assigned to the bundle with the specified * location, or null if that bundle has not been assigned any * permissions. */ public PermissionInfo[] getPermissions(String location) { PermissionInfo[] res = pinfos.get(location, null); return res != null ? (PermissionInfo[])res.clone() : null; } /** * Assigns the specified permissions to the bundle with the specified * location. * * @param location The location of the bundle that will be assigned the * permissions. * @param permissions The permissions to be assigned, or null if * the specified location is to be removed from the permission table. * @throws SecurityException If the caller does not have * AllPermission. */ public synchronized void setPermissions(String location, PermissionInfo[] perms) { SecurityManager sm = System.getSecurityManager(); if(null!=sm){ sm.checkPermission(ALL_PERMISSION); } if (perms != null) { pinfos.put(location, (PermissionInfo[])perms.clone()); } else { pinfos.remove(location); } } /** * Returns the bundle locations that have permissions assigned to them, that * is, bundle locations for which an entry exists in the permission table. * * @return The locations of bundles that have been assigned any permissions, * or null if the permission table is empty. */ public String[] getLocations() { return pinfos.getKeys(); } /** * Gets the default permissions. * *

These are the permissions granted to any bundle that does not * have permissions assigned to its location. * * @return The default permissions, or null if default * permissions have not been defined. */ public synchronized PermissionInfo[] getDefaultPermissions() { PermissionInfo[] res = pinfos.getDefault(null); return res != null ? (PermissionInfo[])res.clone() : null; } /** * Sets the default permissions. * *

* These are the permissions granted to any bundle that does not have * permissions assigned to its location. * * @param permissions The default permissions, or null if the * default permissions are to be removed from the permission table. * @throws SecurityException If the caller does not have * AllPermission. */ public synchronized void setDefaultPermissions(PermissionInfo[] perms) { SecurityManager sm = System.getSecurityManager(); if(null!=sm){ sm.checkPermission(ALL_PERMISSION); } if (perms != null) { perms = (PermissionInfo[])perms.clone(); } pinfos.putDefault(perms); } } ././@LongLink0000644000000000000000000000017400000000000011605 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermissionSecurityManager.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermiss0000644000175000017500000000363312346513666033276 0ustar felixfelix/* * Copyright (c) 2009, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.util.List; /** * Interface for SecurityManager that fully supports conditional permissions. */ public interface ConditionalPermissionSecurityManager { public boolean isPostponeAvailable(); public void savePostponement(List postponement, Object debug); } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/FrameworkPolicy.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/FrameworkPolicy.ja0000644000175000017500000001222012346513666033166 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.net.URL; import java.security.AccessController; import java.security.CodeSource; import java.security.Permission; import java.security.PermissionCollection; import java.security.Permissions; import java.security.Policy; import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.util.Enumeration; import org.knopflerfish.framework.BundleURLStreamHandler; /** * Implementation of a Permission Policy for Framework. * * Special handling for all protection domains that corresponds to a * bundle, for all other delegate to given default policy (normally * the policy file based policy implementation). * * @see java.security.Policy * @author Jan Stein, Philippe Laporte, Gunnar Ekolin */ class FrameworkPolicy extends Policy { /** The policy to delegate non-bundle permission requests to. */ private final Policy defaultPolicy; private final PermissionsHandle ph; /** */ FrameworkPolicy(Policy policy, PermissionsHandle ph) { this.defaultPolicy = policy; this.ph = ph; } // Delegate to the wrapped defaultPolicy for all non-bundle domains. @Override public PermissionCollection getPermissions(ProtectionDomain pd) { if (null==pd) return defaultPolicy.getPermissions(pd); final CodeSource cs = pd.getCodeSource(); if (null==cs) return defaultPolicy.getPermissions(pd); final URL u = cs.getLocation(); if (u != null && BundleURLStreamHandler.PROTOCOL.equals(u.getProtocol())) { return getPermissions(cs); } else { return defaultPolicy.getPermissions(pd); } } /** */ @Override public PermissionCollection getPermissions(CodeSource cs) { if (null==cs) { // Not a code source for a bundle, delegate to the default policy return defaultPolicy.getPermissions(cs); } final URL u = cs.getLocation(); if (u != null && BundleURLStreamHandler.PROTOCOL.equals(u.getProtocol())) { try { final Long id = new Long(BundleURLStreamHandler.getId(u.getHost())); //return getPermissions(id); final PermissionCollection pc = ph.getPermissionCollection(id); if (pc != null) { return copy(pc); } } catch (final NumberFormatException ignore) { } return new Permissions(); } else { return defaultPolicy.getPermissions(cs); } } private static PermissionCollection copy(PermissionCollection pc) { // TODO, provide a copy-on-write collection?! final Permissions pc2 = new Permissions(); for (final Enumeration e = pc.elements(); e.hasMoreElements();) { pc2.add(e.nextElement()); } return pc2; } /** */ @Override public boolean implies(final ProtectionDomain pd, final Permission p) { // NYI! Optimize here for framework.jar + bootclasses? final CodeSource cs = null != pd ? pd.getCodeSource() : null; final URL u = null != cs ? cs.getLocation() : null; if (u != null && BundleURLStreamHandler.PROTOCOL.equals(u.getProtocol())) { final PermissionCollection pc = getPermissions(cs); return (pc == null) ? false : pc.implies(p); } else { final Boolean res = AccessController.doPrivileged(new PrivilegedAction() { public Boolean run() { return new Boolean(defaultPolicy.implies(pd, p)); } }); return res.booleanValue(); } } /** */ @Override public void refresh() { // A bundle permissions is allways up to date, but we must // propagate to the wrapped defaultPolicy. defaultPolicy.refresh(); } } ././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermissionInfoStorage.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermiss0000644000175000017500000003677612346513666033314 0ustar felixfelix/* * Copyright (c) 2008-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.permissions; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Vector; import org.knopflerfish.framework.Debug; import org.knopflerfish.framework.FWProps; import org.knopflerfish.framework.Util; import org.osgi.service.condpermadmin.ConditionInfo; import org.osgi.service.condpermadmin.ConditionalPermissionInfo; import org.osgi.service.condpermadmin.ConditionalPermissionUpdate; import org.osgi.service.permissionadmin.PermissionInfo; class ConditionalPermissionInfoStorage { private final File condPermDir; private long lastFile; private ArrayList cpiTable = new ArrayList(); private final PermissionsHandle ph; private int generation = -1; final private Debug debug; final private boolean readOnly; /** * */ ConditionalPermissionInfoStorage(PermissionsHandle ph) { this.ph = ph; debug = ph.framework.debug; readOnly = ph.framework.props.getBooleanProperty(FWProps.READ_ONLY_PROP); condPermDir = Util.getFileStorage(ph.framework, "condperm", !readOnly); if (condPermDir == null) { System.err.println("Property org.osgi.framework.dir not set," + "conditional permission info will not be saved between sessions"); } else { load(); } } /** * Get the specified conditional permissions. * * @param name The name of the Conditional Permission Info to be returned. * @return The Conditional Permission Info with the specified name. */ synchronized ConditionalPermissionInfo get(String name) { final int i = find(name); if (i >= 0) { return cpiTable.get(i); } return null; } /** * Get an enumeration of copied conditional permission info table. * * @return Enumeration of Conditional Permission Info objects. */ synchronized Enumeration getAllEnumeration() { return (new Vector(cpiTable)).elements(); } /** * Get conditional permission info table. * Should be called from synchronized code. * * @return ArrayList of Conditional Permission Info objects. */ ArrayList getAll() { return cpiTable; } /** * Get a copy conditional permission info table. * * @return Enumeration of Conditional Permission Info objects. */ synchronized ConditionalPermissionUpdate getUpdate() { return new ConditionalPermissionUpdateImpl(this, cpiTable, generation); } /** * Add a new or updated an old specified conditional permission. * * @param name The name of the Conditional Permission Info to be changed. * @param conds The Conditions that need to be satisfied to enable the * corresponding Permissions. * @param perms The Permissions that are enable when the corresponding * Conditions are satisfied. * @return The ConditionalPermissionInfo object for the added * conditional permission. */ synchronized ConditionalPermissionInfo put(String name, ConditionInfo conds[], PermissionInfo perms[]) { int oldIx; if (name == null) { name = uniqueName(); oldIx = -1; } else if (name.equals("")) { throw new IllegalArgumentException("Name can not be an empty string"); } else { oldIx = find(name); } ConditionalPermissionInfoImpl old; final ConditionalPermissionInfoImpl res = new ConditionalPermissionInfoImpl(this, name, conds, perms, ConditionalPermissionInfo.ALLOW, ph.framework); if (oldIx >= 0) { old = cpiTable.set(oldIx, res); updateChangedConditionalPermission(res, oldIx, oldIx); } else { old = null; cpiTable.add(0, res); updateChangedConditionalPermission(res, 0, -1); } generation++; save(); if (debug.permissions) { debug.println("CondPermStorage set " + res); if (old != null) { debug.println("CondPermStorage replaced " + old); } } return res; } /** * Remove any specified conditional permission with the specified name. * * @param name The name of the Conditional Permission Info to be changed. */ synchronized void remove(ConditionalPermissionInfoImpl obj) { final int pos = cpiTable.indexOf(obj); if (debug.permissions) { debug.println("CondPermStorage remove " + obj + ", pos=" + pos); } if (pos >= 0) { cpiTable.remove(pos); updateChangedConditionalPermission(null, -1, pos); generation++; save(); if (debug.permissions) { debug.println("CondPermStorage removed " + obj); } } } /** * Commit a new cpi table. * * @param updatedTable The Conditional Permission Info to commit. * @param parentGen generation number of the active table that update is * based on. */ synchronized boolean commitUpdate(List updatedTable, int parentGen) { if (parentGen != generation) { return false; } final ArrayList checkTable = new ArrayList(updatedTable); final HashSet names = new HashSet(); int oi = 0; ConditionalPermissionInfoImpl ocpi = oi < cpiTable.size() ? cpiTable.get(oi) : null; final int [] update = new int[cpiTable.size() + checkTable.size()]; int ui = 0; String uniqueNameBase = Integer.toString(generation, Character.MAX_RADIX) + "_"; int nextRemove = update.length; int i = 0; for ( ; i < checkTable.size(); i++) { ConditionalPermissionInfoImpl cpi; try { cpi = (ConditionalPermissionInfoImpl)checkTable.get(i); } catch (final ClassCastException _) { throw new IllegalStateException("Illegal class of element in updated table, index=" + i); } if (cpi == null) { throw new IllegalStateException("Updated table contains null element, index=" + i); } final String name = cpi.getName(); if (name != null) { if (!names.add(name)) { throw new IllegalStateException("Updated table contains elements with same name, name=" + name); } while (name.startsWith(uniqueNameBase)) { uniqueNameBase += "_"; } } if (cpi == ocpi) { // Update doesn't differ check next ocpi = ++oi < cpiTable.size() ? cpiTable.get(oi) : null; } else { int removed = 0; for (int j = oi + 1; j < cpiTable.size(); j++) { if (cpiTable.get(j) == cpi) { // Found updated, further down the table, removed or moved intermediate. removed = j; break; } } if (removed != 0) { // remove intermediate objects while (oi++ < removed) { if (nextRemove > ui) { nextRemove = ui; } update[ui++] = -i - 1; } ocpi = oi < cpiTable.size() ? cpiTable.get(oi) : null; } else { // New element add it update[ui++] = i; } } } // remove trailing objects if (oi++ < cpiTable.size()) { if (nextRemove > ui) { nextRemove = ui; } do { update[ui++] = -i - 1; } while (oi++ < cpiTable.size()); } // If no updates just return if (ui == 0) { return true; } // Perform updates on caches and set null names final int NOP = Integer.MIN_VALUE; int nops = 0; int uniqueCounter = 0; for (int pui = 0; pui < ui; pui++) { int u = update[pui]; if (u >= 0) { // We have an insert, see if we find a matching remove to avoid array shuffling boolean remove = false; if (nextRemove < ui) { int rMatch = u + nextRemove - pui - nops; if (update[nextRemove] + 1 == -rMatch) { update[nextRemove] = NOP; nops++; while (++nextRemove < ui && update[nextRemove] >= 0) ; remove = true; } } final ConditionalPermissionInfoImpl cpi = (ConditionalPermissionInfoImpl)checkTable.get(u); if (cpi.getName() == null) { cpi.setName(uniqueNameBase + uniqueCounter++); } cpi.setPermissionInfoStorage(this); if (remove) { cpiTable.set(u, cpi); updateChangedConditionalPermission(cpi, u, u); } else { cpiTable.add(u, cpi); updateChangedConditionalPermission(cpi, u, -1); } } else if (u != NOP) { while (++nextRemove < ui && update[nextRemove] >= 0) ; u = -1 - u; cpiTable.remove(u); updateChangedConditionalPermission(null, -1, u); } else { nops--; } } generation++; save(); if (debug.permissions) { debug.println("CondPermStorage commited update, " + ui + " changes"); } return true; } /** * Get number of ConditionPermissionInfos stored. * * @return Number of ConditionPermissionInfos objects as an int. */ synchronized int size() { return cpiTable.size(); } // // Private methods // private int find(String name) { for (int i = 0; i < cpiTable.size(); i++) { if (((ConditionalPermissionInfo)cpiTable.get(i)).getName().equals(name)) { return i; } } return -1; } /** * Find a unique name. */ private String uniqueName() { String uniqueNameBase = Integer.toString(generation, Character.MAX_RADIX) + "_"; for (final Object element : cpiTable) { final String name = ((ConditionalPermissionInfoImpl)element).getName(); while (name.startsWith(uniqueNameBase)) { uniqueNameBase += "_"; } } return uniqueNameBase + "0"; } /** * Update cached information. */ private void updateChangedConditionalPermission(ConditionalPermissionInfoImpl cpi, int pos, int removePos) { for (final Iterator i = ph.getPermissionWrappers(); i .hasNext();) { i.next().updateChangedConditionalPermission(cpi, pos, removePos, cpiTable.size()); } } final static String END_MARKER = "END"; /** * Save a permission array. */ private void save() { if (debug.permissions) { debug.println("CondPermStorage save " + size() + " cpis, gen=" + generation); } if (condPermDir != null && !readOnly) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { purge(); final File f = new File(condPermDir, Long.toString(++lastFile)); BufferedWriter out = null; try { out = new BufferedWriter(new FileWriter(f)); out.write("# Save generation " + generation + " at: " + System.currentTimeMillis()); out.newLine(); for (final Object element : cpiTable) { out.write(((ConditionalPermissionInfoImpl)element).toString()); out.newLine(); } out.write(END_MARKER); out.newLine(); out.close(); } catch (final IOException e) { if (out != null) { try { out.close(); } catch (final IOException ignore) { } f.delete(); } debug.printStackTrace("NYI! Report error", e); } return null; } }); } } /** * Load all saved conditional permission data. */ private void load() { final File[] files = PermUtil.getSortedFiles(condPermDir); lastFile = -1; for (int i = files.length - 1; i >= 0; i--) { try { final long l = Long.parseLong(files[i].getName()); if (l > lastFile) { lastFile = l; } } catch (final Exception ignore) { // Ignore file that isn't a number continue; } if (load(files[i])) { break; } else { // Load failed, purge file files[i].delete(); } } } /** * Load saved conditional permission data from specified file. */ private boolean load(File fh) { BufferedReader in = null; final ArrayList loadTable = new ArrayList(); try { in = new BufferedReader(new FileReader(fh)); for (String l = in.readLine(); l != null; l = in.readLine()) { l = l.trim(); if (l.equals("") || l.startsWith("#")) { continue; } else if (l.equals(END_MARKER)) { in.close(); cpiTable = loadTable; return true; } else { final ConditionalPermissionInfoImpl res = new ConditionalPermissionInfoImpl(this, l, ph.framework); loadTable.add(res); } } in.close(); } catch (final Exception e) { if (in != null) { try { in.close(); } catch (final IOException ignore) { } } debug.printStackTrace("NYI! Report error", e); } return false; } /** * Prune unused data files in conditional permission directory. */ private void purge() { final File[] files = PermUtil.getSortedFiles(condPermDir); int okName = 0; for (int i = files.length - 1; i >= 0; i--) { try { Long.parseLong(files[i].getName()); if (++okName > 2) { files[i].delete(); } } catch (final Exception ignore) { // Ignore files which aren't a number. } } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleContextImpl.java0000644000175000017500000003121712346513666031434 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Dictionary; import java.util.List; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.BundleListener; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkListener; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; /** * Implementation of the BundleContext object. * * @see org.osgi.framework.BundleContext * @author Jan Stein * @author Philippe Laporte */ public class BundleContextImpl implements BundleContext { /** * Reference to bundleImpl for this context. */ final BundleImpl bundle; /** * Is bundle context valid. */ private boolean valid = true; /** * Create a BundleContext for specified bundle. */ public BundleContextImpl(BundleImpl bundle) { this.bundle = bundle; } // // BundleContext interface // /** * Retrieve the value of the named environment property. * * @see org.osgi.framework.BundleContext#getProperty */ public String getProperty(String key) { checkValid(); return bundle.fwCtx.props.getProperty(key); } /** * Install a bundle from location. * * @see org.osgi.framework.BundleContext#installBundle */ public Bundle installBundle(String location) throws BundleException { checkValid(); return bundle.fwCtx.bundles.install(location, null, bundle); } /** * Install a bundle from an InputStream. * * @see org.osgi.framework.BundleContext#installBundle */ public Bundle installBundle(String location, InputStream in) throws BundleException { try { checkValid(); return bundle.fwCtx.bundles.install(location, in, bundle); } finally { if (in != null) { try { in.close(); } catch (final IOException ignore) {} } } } /** * Retrieve the Bundle object for the calling bundle. * * @see org.osgi.framework.BundleContext#getBundle */ public Bundle getBundle() { checkValid(); return bundle; } /** * Retrieve the bundle that has the given unique identifier. * * @see org.osgi.framework.BundleContext#getBundle */ public Bundle getBundle(long id) { return bundle.fwCtx.bundleHooks.filterBundle(this, bundle.fwCtx.bundles.getBundle(id)); } /** * Retrieve a list of all installed bundles. * * @see org.osgi.framework.BundleContext#getBundles */ public Bundle[] getBundles() { @SuppressWarnings({ "unchecked", "rawtypes" }) final List bl = (List) bundle.fwCtx.bundles.getBundles(); bundle.fwCtx.bundleHooks.filterBundles(this, bl); return bl.toArray(new Bundle [bl.size()]); } /** * Add a service listener with a filter. * * @see org.osgi.framework.BundleContext#addServiceListener */ public void addServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException { checkValid(); bundle.fwCtx.listeners.addServiceListener(this, listener, filter); } /** * Add a service listener. * * @see org.osgi.framework.BundleContext#addServiceListener */ public void addServiceListener(ServiceListener listener) { checkValid(); try { bundle.fwCtx.listeners.addServiceListener(this, listener, null); } catch (final InvalidSyntaxException neverHappens) { } } /** * Remove a service listener. * * @see org.osgi.framework.BundleContext#removeServiceListener */ public void removeServiceListener(ServiceListener listener) { checkValid(); bundle.fwCtx.listeners.removeServiceListener(this, listener); } /** * Add a bundle listener. * * @see org.osgi.framework.BundleContext#addBundleListener */ public void addBundleListener(BundleListener listener) { checkValid(); bundle.fwCtx.listeners.addBundleListener(this, listener); } /** * Remove a bundle listener. * * @see org.osgi.framework.BundleContext#removeBundleListener */ public void removeBundleListener(BundleListener listener) { checkValid(); bundle.fwCtx.listeners.removeBundleListener(this, listener); } /** * Add a framework listener. * * @see org.osgi.framework.BundleContext#addFrameworkListener */ public void addFrameworkListener(FrameworkListener listener) { checkValid(); bundle.fwCtx.listeners.addFrameworkListener(this, listener); } /** * Remove a framework listener. * * @see org.osgi.framework.BundleContext#removeFrameworkListener */ public void removeFrameworkListener(FrameworkListener listener) { checkValid(); bundle.fwCtx.listeners.removeFrameworkListener(this, listener); } /** * Register a service with multiple names. * * @see org.osgi.framework.BundleContext#registerService */ public ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties) { checkValid(); final String [] classes = clazzes.clone(); return bundle.fwCtx.services.register(bundle, classes, service, properties); } /** * Register a service with a single name. * * @see org.osgi.framework.BundleContext#registerService */ public ServiceRegistration registerService(String clazz, Object service, Dictionary properties) { checkValid(); final String [] classes = new String [] { clazz }; return bundle.fwCtx.services.register(bundle, classes, service, properties); } /** * Get a list of service references. * * @see org.osgi.framework.BundleContext#getServiceReferences */ public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException { checkValid(); return bundle.fwCtx.services.get(clazz, filter, bundle); } /** * Get a list of service references. * * @see org.osgi.framework.BundleContext#getAllServiceReferences */ public ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException { checkValid(); return bundle.fwCtx.services.get(clazz, filter, null); } /** * Get a service reference. * * @see org.osgi.framework.BundleContext#getServiceReference */ public ServiceReference getServiceReference(String clazz) { checkValid(); return bundle.fwCtx.services.get(bundle, clazz); } /** * Get the service object. * * @see org.osgi.framework.BundleContext#getService */ public S getService(ServiceReference reference) { checkValid(); if(reference == null) { // Throw an NPE with a message to be really clear we do it // intentionally. // A better solution would be to throw IllegalArgumentException, // but the OSGi ref impl throws NPE, and we want to keep as // close as possible throw new NullPointerException("null ServiceReference is not valid input to getService()"); } final ServiceReferenceImpl sri = (ServiceReferenceImpl) reference; return sri.getService(bundle); } /** * Unget the service object. * * @see org.osgi.framework.BundleContext#ungetService */ public boolean ungetService(ServiceReference reference) { checkValid(); if(reference == null) { // Throw an NPE with a message to be really clear we do it // intentionally. // A better solution would be to throw IllegalArgumentException, // but the OSGi ref impl throws NPE, and we want to keep as // close as possible throw new NullPointerException("null ServiceReference is not valid input to ungetService()"); } return ((ServiceReferenceImpl)reference).ungetService(bundle); } /** * Creates a File object for a file in the persistent storage * area provided for the bundle. * * @see org.osgi.framework.BundleContext#getDataFile */ public File getDataFile(String filename) { checkValid(); final File dataRoot = bundle.getDataRoot(); if (dataRoot != null) { if (!dataRoot.exists()) { dataRoot.mkdirs(); } return new File(dataRoot, filename); } else { return null; } } /** * Constructs a Filter object. This filter object may be used * to match a {@link ServiceReference} or a Dictionary. * * @param filter the filter string. * @return the Filter object encapsulating the filter string. * @exception InvalidSyntaxException If the filter parameter contains * an invalid filter string which cannot be parsed. * * @since 1.1 */ public Filter createFilter(String filter) throws InvalidSyntaxException { checkValid(); return FrameworkUtil.createFilter(filter); } public ServiceRegistration registerService(Class clazz, S service, Dictionary properties) { @SuppressWarnings("unchecked") final ServiceRegistration res = (ServiceRegistration) registerService(clazz == null ? null : clazz.getName(),service,properties); return res; } public ServiceReference getServiceReference(Class clazz) { @SuppressWarnings("unchecked") final ServiceReference res = (ServiceReference) getServiceReference(clazz == null ? null : clazz.getName()); return res; } public Collection> getServiceReferences(Class clazz, String filter) throws InvalidSyntaxException { @SuppressWarnings("unchecked") final ServiceReference[] srs = (ServiceReference[]) getServiceReferences(clazz == null ? null : clazz.getName(), filter); if(srs == null) { @SuppressWarnings("unchecked") final Collection> res = Collections.EMPTY_LIST; return res; } else { return Arrays.asList(srs); } } public Bundle getBundle(String location) { return bundle.fwCtx.bundles.getBundle(location); } // // Package methods // /** * Invalidate this BundleContext. */ void invalidate() { valid = false; } /** * Is bundle still valid. * * @return true if valid. * @exception IllegalStateException, if bundle isn't active. */ boolean isValid() { return valid; } // // Private methods // /** * Check that the bundle is still valid. * * @return true if valid. * @exception IllegalStateException, if bundle isn't active. */ private void checkValid() { if (!valid) { throw new IllegalStateException("This bundle context is no longer valid"); } } } ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ServiceURLStreamHandlerFactory.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ServiceURLStreamHandlerFactory0000644000175000017500000002075612346513666033107 0ustar felixfelix/* * Copyright (c) 2003-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Vector; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.url.URLConstants; import org.osgi.service.url.URLStreamHandlerService; /** * Factory creating URLStreamHandlers from both built-in * handlers and OSGi-registered URLStreamHandlerServices. * * TODO: Handle separation between different frameworks. */ public class ServiceURLStreamHandlerFactory implements URLStreamHandlerFactory { Vector framework = new Vector(2); // // Special framework handlers // Hashtable handlers = new Hashtable(); // JVM classpath handlers. Initialized once at startup String[] jvmPkgs = null; // // OSGi URLStreamHandlerService wrappers // This map is not really necessary since the JVM // caches handlers anyway, but it just seems nice to have. // HashMap wrapMap = new HashMap(); // BundleURLStreamHandler bundleHandler; // Debug handle for fw which created this factory private Debug debug = null; ServiceURLStreamHandlerFactory() { // Initialize JVM classpath packages final String s = System.getProperty("java.protocol.handler.pkgs"); if (s != null) { jvmPkgs = Util.splitwords(s, "|"); for(int i = 0; i < jvmPkgs.length; i++) { jvmPkgs[i] = jvmPkgs[i].trim(); } } // Add framework protocols setURLStreamHandler(FWResourceURLStreamHandler.PROTOCOL, new FWResourceURLStreamHandler()); setURLStreamHandler(ReferenceURLStreamHandler.PROTOCOL, new ReferenceURLStreamHandler()); bundleHandler = new BundleURLStreamHandler(); setURLStreamHandler(BundleURLStreamHandler.PROTOCOL, bundleHandler); } /** * */ public URLStreamHandler createURLStreamHandler(String protocol) { Debug doDebug = debug; if (doDebug != null && !doDebug.url) { doDebug = null; } if (doDebug != null) { doDebug.println("createURLStreamHandler protocol=" + protocol); } // Check for // 1. JVM classpath handlers // 2. Framework built-in handlers // 2. OSGi-based handlers // 3. system handlers URLStreamHandler handler = getJVMClassPathHandler(protocol); if (handler != null) { if (doDebug != null) { doDebug.println("using JVMClassPath handler for " + protocol); } return handler; } handler = (URLStreamHandler)handlers.get(protocol); if (handler != null) { if (doDebug != null) { doDebug.println("using predefined handler for " + protocol); } return handler; } handler = getServiceHandler(protocol); if (handler != null) { if (doDebug != null) { doDebug.println("Using service URLHandler for " + protocol); } return handler; } if (doDebug != null) { doDebug.println("Using default URLHandler for " + protocol); } return null; } /** * Sets the handler for a named protocol. * *

* Any old handler for the specified protocol will be lost. *

* * @param protocol Protocol name. * @param handler Handler for the specified protocol name. */ void setURLStreamHandler(String protocol, URLStreamHandler handler) { handlers.put(protocol, handler); } /** * Add framework that uses this URLStreamHandlerFactory. * * @param fw Framework context for framework to add. */ void addFramework(FrameworkContext fw) { bundleHandler.addFramework(fw); synchronized (wrapMap) { if (debug == null) { debug = fw.debug; } framework.add(fw); } } /** * Remove framework that uses this URLStreamHandlerFactory. * * @param fw Framework context for framework to remove. */ void removeFramework(FrameworkContext fw) { bundleHandler.removeFramework(fw); synchronized (wrapMap) { for (Iterator> i = wrapMap.entrySet().iterator(); i.hasNext(); ) { Map.Entry e = i.next(); if ((e.getValue()).removeFramework(fw)) { i.remove(); } } framework.remove(fw); if (debug == fw.debug) { if (framework.isEmpty()) { debug = null; } else { debug = framework.get(0).debug; } } } } /** * */ private URLStreamHandler getServiceHandler(final String protocol) { try { final String filter = "(" + URLConstants.URL_HANDLER_PROTOCOL + "=" + protocol + ")"; @SuppressWarnings("unchecked") final Vector sfws = (Vector)framework.clone(); for (final FrameworkContext sfw : sfws) { @SuppressWarnings("unchecked") final ServiceReference[] srl = (ServiceReference[]) sfw.services .get(URLStreamHandlerService.class.getName(), filter, null); if (srl != null && srl.length > 0) { synchronized (wrapMap) { URLStreamHandlerWrapper wrapper = wrapMap.get(protocol); if (wrapper == null) { wrapper = new URLStreamHandlerWrapper(sfw, protocol); wrapMap.put(protocol, wrapper); } else { wrapper.addFramework(sfw); } return wrapper; } } } } catch (final InvalidSyntaxException e) { throw new RuntimeException("Failed to get service: " + e); } // no handler found return null; } /** * Check if there exists a JVM classpath handler for a protocol. */ private URLStreamHandler getJVMClassPathHandler(final String protocol) { Debug doDebug = debug; if (doDebug != null && !doDebug.url) { doDebug = null; } if (jvmPkgs != null) { for (final String jvmPkg : jvmPkgs) { final String className = jvmPkg + "." + protocol + ".Handler"; try { if (doDebug != null) { doDebug.println("JVMClassPath - trying URLHandler class=" + className); } final Class clazz = Class.forName(className); final URLStreamHandler handler = (URLStreamHandler)clazz.newInstance(); if (doDebug != null) { doDebug.println("JVMClassPath - created URLHandler class=" + className); } return handler; } catch (final Throwable t) { if (doDebug != null) { doDebug.println("JVMClassPath - no URLHandler class " + className); } } } } if (doDebug != null) { doDebug.println("JVMClassPath - no URLHandler for " + protocol); } return null; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Capabilities.java0000644000175000017500000000670012346513666030424 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; public class Capabilities { /** * List of registered capabilities indexed by name space. * The list is order in manifest order. */ private HashMap> namespaceCapabilties = new HashMap>(); List getCapabilities(String namespace) { return namespaceCapabilties.get(namespace); } void addCapabilities(Map> capabilities) { for (Entry> e : capabilities.entrySet()) { final String ns = e.getKey(); ArrayList bcl = namespaceCapabilties.get(ns); if (bcl == null) { bcl = new ArrayList(); namespaceCapabilties.put(ns, bcl); } bcl.addAll(e.getValue()); } } void removeCapabilities(Map> capabilities) { for (Entry> e : capabilities.entrySet()) { final String ns = e.getKey(); ArrayList bcl = namespaceCapabilties.get(ns); if (bcl != null) { int before = bcl.size(); bcl.removeAll(e.getValue()); if (bcl.isEmpty()) { namespaceCapabilties.remove(ns); } if (before != bcl.size() + e.getValue().size()) { throw new RuntimeException("Internal error, tried to remove unknown capabilities"); } } else { throw new RuntimeException("Internal error, tried to remove unknown name space with capabilities"); } } } Collection> getAll() { return namespaceCapabilties.values(); } } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/FWResourceURLStreamHandler.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/FWResourceURLStreamHandler.jav0000644000175000017500000000477212346513666032762 0ustar felixfelix/* * Copyright (c) 2014-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.IOException; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; /** * Framework resource URL handling, used for accessing framework * resources. * * Accepts URLs on the form *
 *  fwresource:file
 * 
* Where file is a valid framework resource path. * * TODO: Handle multiple frameworks in the same JVM correctly * when we have multiple classloaders. */ public class FWResourceURLStreamHandler extends URLStreamHandler { final public static String PROTOCOL = "fwresource"; final private ClassLoader classLoader; FWResourceURLStreamHandler() { this.classLoader = getClass().getClassLoader(); } /** * */ @Override protected URLConnection openConnection(URL u) throws IOException { final URL resourceUrl = classLoader.getResource(u.getPath()); return resourceUrl.openConnection(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleStorage.java0000644000175000017500000000646512346513666030601 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.InputStream; import java.util.List; /** * Interface for managing all bundles jar content. * * @author Jan Stein */ public interface BundleStorage { /** * Insert bundle into persistent storagedata. * * @param location Locaion of bundle to install. * @param is Inputstream containing bundle. * @return BundleArchive representing installed bundle. */ BundleArchive insertBundleJar(String location, InputStream is) throws Exception; /** * Insert a new jar file into persistent storagedata as an update * to an existing bundle archive. To commit this data a call to * replaceBundleArchive is needed. * * @param old BundleArchive to be replaced. * @param is Input-stream with bundle content. * @return Bundle archive object. */ BundleArchive updateBundleArchive(BundleArchive old, InputStream is) throws Exception; /** * Replace old bundle archive with a new updated bundle archive, that * was created with updateBundleArchive. * * @param oldBA BundleArchive to be replaced. * @param newBA BundleArchive with bundle content. * @return New bundle archive object. */ void replaceBundleArchive(BundleArchive oldBA, BundleArchive newBA) throws Exception; /** * Get all bundle archive objects. * * @return Private copy of a List with bundle id's. */ BundleArchive [] getAllBundleArchives(); /** * Get all bundles tagged to start at next launch of framework. * This list is sorted in suggest start order. * * @return Private copy of a List with bundle id's. */ List getStartOnLaunchBundles(); /** * Close this bundle storage and all bundles in it. */ void close(); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/RequireBundle.java0000644000175000017500000002033012346513666030574 0ustar felixfelix/* * Copyright (c) 2006-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Collections; import java.util.Map; import java.util.Map.Entry; import org.knopflerfish.framework.Util.HeaderEntry; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.VersionRange; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; class RequireBundle implements BundleRequirement, Comparable { // To maintain the creation order in the osgi.wiring.bundle name space. static private int requireBundleCount = 0; final int orderal = ++requireBundleCount; final BundlePackages requestor; final String name; final String visibility; final String resolution; final VersionRange bundleRange; BundlePackages bpkgs = null; final Map attributes; final Map directives; /** * A re-required bundle for fragment hosts. * @param parent The fragment require bundle object to re-require. * @param requestor The bundle packages of the fragment host that * re-requires a required bundle from one of its * fragments. */ RequireBundle(RequireBundle parent, BundlePackages requestor) { this.requestor = requestor; this.name = parent.name; this.visibility = parent.visibility; this.resolution = parent.resolution; this.bundleRange= parent.bundleRange; this.attributes = parent.attributes; this.directives = parent.directives; } /** * A require bundle requirement. * * @param requestor * The bundle packages of the fragment host that requires a bundle. * @param he * The parsed require bundle header. */ RequireBundle(final BundlePackages requestor, final HeaderEntry he) { this.requestor = requestor; this.name = he.getKey(); final Map dirs = he.getDirectives(); final String visibility = dirs.get(Constants.VISIBILITY_DIRECTIVE); if (visibility != null) { this.visibility = visibility.intern(); if (this.visibility!=Constants.VISIBILITY_PRIVATE && this.visibility!=Constants.VISIBILITY_REEXPORT ) { throw new IllegalArgumentException ("Invalid directive : '" +Constants.VISIBILITY_DIRECTIVE +":="+this.visibility +"' in manifest header '" +Constants.REQUIRE_BUNDLE +": " +this.name +"' of bundle with id " +this.requestor.bg.bundle.getBundleId() +" ("+this.requestor.bg.symbolicName+")" +". The value must be either '" +Constants.VISIBILITY_PRIVATE +"' or '" +Constants.VISIBILITY_REEXPORT +"'."); } } else { this.visibility = Constants.VISIBILITY_PRIVATE; } final String resolution = dirs.get(Constants.RESOLUTION_DIRECTIVE); if (resolution != null) { this.resolution = resolution.intern(); if (this.resolution!=Constants.RESOLUTION_MANDATORY && this.resolution!=Constants.RESOLUTION_OPTIONAL ) { throw new IllegalArgumentException ("Invalid directive : '" +Constants.RESOLUTION_DIRECTIVE +":="+this.resolution +"' in manifest header '" +Constants.REQUIRE_BUNDLE +": " +this.name +"' of bundle with id " +this.requestor.bg.bundle.getBundleId() +" ("+this.requestor.bg.symbolicName+")" +". The value must be either '" +Constants.RESOLUTION_MANDATORY +"' or '" +Constants.RESOLUTION_OPTIONAL +"'."); } } else { this.resolution = Constants.RESOLUTION_MANDATORY; } this.attributes = he.getAttributes(); final String range = (String) attributes.remove(Constants.BUNDLE_VERSION_ATTRIBUTE); if (range != null) { this.bundleRange = new VersionRange(range); } else { this.bundleRange = null; } final Filter filter = toFilter(); if (null!=filter) { dirs.put(Constants.FILTER_DIRECTIVE, filter.toString()); } this.directives = Collections.unmodifiableMap(dirs); } /** * Check if this object completely overlap specified RequireBundle. * * @return True if we overlap, otherwise false. */ boolean overlap(RequireBundle rb) { if (visibility.equals(Constants.VISIBILITY_REEXPORT) && !rb.visibility.equals(Constants.VISIBILITY_REEXPORT)) { return false; } if (resolution.equals(Constants.RESOLUTION_MANDATORY) && !rb.resolution.equals(Constants.RESOLUTION_MANDATORY)) { return false; } return bundleRange == null || !bundleRange.intersection(rb.bundleRange).isEmpty(); } // BundleRequirement method @Override public String getNamespace() { return BundleRevision.BUNDLE_NAMESPACE; } // BundleRequirement method @Override public Map getDirectives() { return directives; } private Filter toFilter() { final StringBuffer sb = new StringBuffer(80); boolean multipleConditions = false; sb.append('('); sb.append(BundleRevision.BUNDLE_NAMESPACE); sb.append('='); sb.append(name); sb.append(')'); if (bundleRange != null) { sb.append(bundleRange.toFilterString(Constants.BUNDLE_VERSION_ATTRIBUTE)); multipleConditions = true; } for (final Entry entry : attributes.entrySet()) { sb.append('('); sb.append(entry.getKey()); sb.append('='); sb.append(entry.getValue().toString()); sb.append(')'); multipleConditions = true; } if (multipleConditions) { sb.insert(0, "(&"); sb.append(')'); } try { return FrameworkUtil.createFilter(sb.toString()); } catch (final InvalidSyntaxException _ise) { throw new RuntimeException("Internal error, createFilter: '" +sb.toString() +"': " +_ise.getMessage()); } } // BundleRequirement method @SuppressWarnings("unchecked") @Override public Map getAttributes() { return Collections.EMPTY_MAP; } // BundleRequirement method @Override public BundleRevision getRevision() { return requestor.bg.bundleRevision; } @Override public BundleRevision getResource() { return requestor.bg.bundleRevision; } // BundleRequirement method @Override public boolean matches(BundleCapability capability) { if (BundleRevision.BUNDLE_NAMESPACE.equals(capability.getNamespace())) { return toFilter().matches(capability.getAttributes()); } return false; } @Override public int compareTo(RequireBundle o) { return this.orderal - o.orderal; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ExtensionContext.java0000644000175000017500000001212312346513666031350 0ustar felixfelix/* * Copyright (c) 2012-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Dictionary; import java.util.List; import org.osgi.framework.Bundle; import org.osgi.framework.ServiceRegistration; /** * Context that extension bundles are given to interact with the * Knopflerfish framework implementation. * * @author Gunnar Ekolin */ public class ExtensionContext { private final FrameworkContext fwCtx; @SuppressWarnings("unused") private final BundleGeneration ext; private Object activator = null; ExtensionContext(final FrameworkContext fwCtx, final BundleGeneration ext) { this.fwCtx = fwCtx; this.ext = ext; String extActivatorName = ext.archive.getAttribute("Extension-Activator"); extActivatorName = null!=extActivatorName ? extActivatorName.trim() : null; try { // Extension bundles uses the framework class loader... final Class c = getClass().getClassLoader().loadClass(extActivatorName); activator = c.newInstance(); final Method activateMethod = c.getMethod("activate", new Class[] { ExtensionContext.class }); activateMethod.invoke(activator, new Object[] { this } ); } catch (final Exception e) { activator = null; final String msg = "Failed to activate framework extension " +ext.symbolicName + ":" +ext.version; fwCtx.log(msg, e); } } /** * Register a service possibly implementing multiple interfaces. * * @see org.osgi.framework.BundleContext#registerService */ public ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties) { return fwCtx.services.register(fwCtx.systemBundle, clazzes, service, properties); } /** * @return the current bundle class loader for a given bundle. */ public ClassLoader getClassLoader(Bundle b) { final BundleImpl bi = (BundleImpl) b; return bi.getClassLoader(); } /** * @return the generation (bundle revision) that a given bundle * class loader belongs to. */ public int getGeneration(BundleClassLoader bcl) { return bcl.bpkgs.bg.generation; } /** * The list of bundle class loader listeners registered for this * extension context. */ private final List bclls = new ArrayList(); /** * Register a bundle class loader created listener. * * @param bcll the bundle class loader listener to register. */ public void addBundleClassLoaderListener(BundleClassLoaderListener bcll) { bclls.add(bcll); } /** * Called by the framework context when a bundle class * loader has been created. Will notify all registered listeners. * *

This is a synchronous call. * * @param bcl the newly created bundle class loader. */ void bundleClassLoaderCreated(final BundleClassLoader bcl) { for (final BundleClassLoaderListener bcll : bclls) { bcll.bundleClassLoaderCreated(bcl); } } /** * Called by the framework context when a bundle class loader has * been closed down. Will notify all registered listeners. * *

This is a synchronous call. * * @param bcl the closed down bundle class loader. */ void bundleClassLoaderClosed(final BundleClassLoader bcl) { for (final BundleClassLoaderListener bcll : bclls) { bcll.bundleClassLoaderClosed(bcl); } } } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleNameVersionCapability.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleNameVersionCapability.ja0000644000175000017500000000766712346513666033103 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.osgi.framework.Constants; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRevision; public class BundleNameVersionCapability implements BundleCapability { final BundleGeneration gen; final String namespace; BundleNameVersionCapability(BundleGeneration bundleGeneration, String namespace) { gen = bundleGeneration; this.namespace = namespace; } @Override public String getNamespace() { return namespace; } @Override public Map getDirectives() { if (gen.symbolicNameParameters != null) { return Collections.unmodifiableMap(gen.symbolicNameParameters.getDirectives()); } @SuppressWarnings("unchecked") Map res = Collections.EMPTY_MAP; return res; } @Override public Map getAttributes() { final Map res = new HashMap(); if (gen.symbolicNameParameters != null) { res.putAll(gen.symbolicNameParameters.getAttributes()); } if (gen.symbolicName != null) { res.put(namespace, gen.symbolicName); res.put(Constants.BUNDLE_VERSION_ATTRIBUTE, gen.version); } return Collections.unmodifiableMap(res); } @Override public BundleRevision getRevision() { return gen.bundleRevision; } @Override public BundleRevision getResource() { return gen.bundleRevision; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((gen == null) ? 0 : gen.hashCode()); result = prime * result + ((namespace == null) ? 0 : namespace.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; BundleNameVersionCapability other = (BundleNameVersionCapability) obj; if (!gen.equals(other.gen)) return false; if (!namespace.equals(other.namespace)) return false; return true; } @Override public String toString() { return "BundleNameVersionCapability[nameSpace=" + namespace + ", attributes=" + getAttributes() + ", directives=" + getDirectives() + ", revision=" + getRevision() + "]"; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleThread.java0000644000175000017500000002277712346513666030410 0ustar felixfelix/* * Copyright (c) 2010-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.lang.reflect.Method; import org.osgi.framework.Bundle; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleException; class BundleThread extends Thread { final private static int OP_IDLE = 0; final private static int OP_BUNDLE_EVENT = 1; final private static int OP_START = 2; final private static int OP_STOP = 3; final private static int KEEP_ALIVE = 1000; final static String ABORT_ACTION_STOP = "stop"; final static String ABORT_ACTION_MINPRIO = "minprio"; final static String ABORT_ACTION_IGNORE = "ignore"; final private FrameworkContext fwCtx; private long startStopTimeout = 0; final private Object lock = new Object(); volatile private BundleEvent be; volatile private BundleImpl bundle; volatile private int operation = OP_IDLE; volatile private Object res; volatile private boolean doRun; // Thread.stop() is not available in all Execution Environments... final static Method stopMethod = initStopSupported(); private static Method initStopSupported() { try { return Thread.class.getMethod("stop", (Class[]) null); } catch (final Throwable _t) { return null; } } static void checkWarnStopActionNotSupported(FrameworkContext fc) { final String s = fc.props.getProperty(FWProps.BUNDLETHREAD_ABORT); if (ABORT_ACTION_STOP.equals(s) && null==stopMethod) { System.err.println("WARNING: Bundle thread abort action stop was " +"requested but is not supported on this execution " +"environment; using 'minprio' as abort action."); } } BundleThread(FrameworkContext fc) { super(fc.threadGroup, "BundleThread waiting"); setDaemon(true); fwCtx = fc; doRun = true; // get bundlethread timeout property value String timeout = fwCtx.props.getProperty(FWProps.BUNDLETHREAD_TIMEOUT); if (timeout != null) { try { startStopTimeout = 1000 * Integer.parseInt(timeout); } catch (NumberFormatException nfe) { fwCtx.debug.println("Property " + FWProps.BUNDLETHREAD_TIMEOUT + " has a non integer value, ignoring"); } } start(); } /** * */ void quit() { doRun = false; interrupt(); } @Override public void run() { while (doRun) { synchronized (lock) { while (doRun && operation == OP_IDLE) { try { lock.wait(KEEP_ALIVE); if (operation != OP_IDLE) { break; } synchronized (fwCtx.bundleThreads) { if (fwCtx.bundleThreads.remove(this)) { return; } } } catch (final InterruptedException ie) { } } if (!doRun) { break; } Object tmpres = null; try { switch (operation) { case OP_BUNDLE_EVENT: setName("BundleChanged #" + be.getBundle().getBundleId()); fwCtx.listeners.bundleChanged(be); break; case OP_START: setName("BundleStart #" + bundle.getBundleId()); tmpres = bundle.start0(); break; case OP_STOP: setName("BundleStop #" + bundle.getBundleId()); tmpres = bundle.stop1(); break; } } catch (final Throwable t) { fwCtx.frameworkError(bundle, t); } operation = OP_IDLE; res = tmpres; } synchronized (fwCtx.resolver) { fwCtx.resolver.notifyAll(); } } } /** * Note! Must be called while holding packages lock. */ void bundleChanged(final BundleEvent be) { this.be = be; startAndWait((BundleImpl)be.getBundle(), OP_BUNDLE_EVENT); } /** * Note! Must be called while holding packages lock. */ BundleException callStart0(final BundleImpl b) { return (BundleException)startAndWait(b, OP_START); } /** * Note! Must be called while holding packages lock. */ BundleException callStop1(final BundleImpl b) { return (BundleException)startAndWait(b, OP_STOP); } /** * Note! Must be called while holding packages lock. */ private Object startAndWait(final BundleImpl b, final int op) { synchronized (lock) { res = Boolean.FALSE; bundle = b; operation = op; lock.notifyAll(); } // timeout for waiting on op to finish can be set for start/stop long left = 0; if (op == OP_START || op == OP_STOP) { b.aborted = null; // clear aborted status left = startStopTimeout; } boolean timeout = false; boolean uninstall = false; long waitUntil = Util.timeMillis() + left; do { try { fwCtx.resolver.wait(left); } catch (InterruptedException ie) { } // Abort start/stop operation if bundle has been uninstalled if ((op == OP_START || op == OP_STOP) && b.getState() == Bundle.UNINSTALLED) { uninstall = true; res = null; } else if (left > 0) { // we were waiting with a timeout left = waitUntil - Util.timeMillis(); // check time-out for Bundle.start and .stop if (left <= 0 && ((op == OP_START && b.getState() == Bundle.STARTING) || (op == OP_STOP && b.getState() == Bundle.STOPPING))) { timeout = true; res = null; } } } while (res == Boolean.FALSE); // if b.aborted is set, BundleThread has/will concluded start/stop if (b.aborted == null && (timeout || uninstall)) { // BundleThreda is still in BundleActivator.start/.stop, b.aborted = Boolean.TRUE; // signal to BundleThread that this // thread is acting on uninstall/time-out String opType = op == OP_START ? "start" : "stop"; String reason = timeout ? "Time-out during bundle " + opType + "()" : "Bundle uninstalled during " + opType + "()"; String s = fwCtx.props.getProperty(FWProps.BUNDLETHREAD_ABORT); if (s == null) { s = ABORT_ACTION_IGNORE; } fwCtx.debug.println("bundle thread aborted during " + opType + " of bundle #" + b.getBundleId() + ", abort action set to '" + s + "'"); if (timeout) { if (op == OP_START) { // set state, send events, do clean-up like when Bundle.start() // throws an exception // TODO: startFailed() calls BundleListener.bundleChanged and // should not be called with the packages lock as we do here b.startFailed(); } else { // STOP, like when Bundle.stop() returns/throws an exception b.bactivator = null; b.stop2(); } } quit(); // Check what abort action to use if (ABORT_ACTION_STOP.equalsIgnoreCase(s)) { if (null!=stopMethod) { try { stopMethod.invoke(this, (Object[]) null); } catch (final Throwable t) { fwCtx.debug.println("bundle thread abort action stop failed: " +t.getMessage()); setPriority(Thread.MIN_PRIORITY); } } else { setPriority(Thread.MIN_PRIORITY); } } else if (ABORT_ACTION_MINPRIO.equalsIgnoreCase(s)) { setPriority(Thread.MIN_PRIORITY); } res = new BundleException("Bundle#" + b.id + " " + opType + " failed", BundleException.STATECHANGE_ERROR, new Exception(reason)); b.resetBundleThread(); return res; } else { synchronized (fwCtx.bundleThreads) { fwCtx.bundleThreads.addFirst(this); if (op != operation) { // TODO! Handle when operation has changed. // i.e. uninstall during operation? } b.resetBundleThread(); return res; } } } boolean isExecutingBundleChanged() { return operation == OP_BUNDLE_EVENT; } } ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ServiceContentHandlerFactory.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ServiceContentHandlerFactory.j0000644000175000017500000001352412346513666033126 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.net.ContentHandler; import java.net.ContentHandlerFactory; import java.util.HashMap; import java.util.Map; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.url.URLConstants; /** * Factory creating ContentHandlers from both built-in * handlers and OSGi-registered ContentHandlers */ public class ServiceContentHandlerFactory implements ContentHandlerFactory { FrameworkContext framework; // JVM classpath handlers. Initialized once at startup String[] jvmPkgs = null; // String (mimetype) -> ContentHandlerWrapper Map wrapMap = new HashMap(); ServiceContentHandlerFactory(FrameworkContext fw) { this.framework = fw; // Initialize JVM classpath handlers final String s = framework.props.getProperty("java.content.handler.pkgs"); if (s != null && s.length() > 0) { jvmPkgs = Util.splitwords(s, "|"); for(int i = 0; i < jvmPkgs.length; i++) { jvmPkgs[i] = jvmPkgs[i].trim(); if(framework.debug.url) { framework.debug.println("JVMClassPathCH - jvmPkgs[" + i + "]=" + jvmPkgs[i]); } } } } public ContentHandler createContentHandler(String mimetype) { if(framework.debug.url) { framework.debug.println("createContentHandler protocol=" + mimetype); } ContentHandler handler = getJVMClassPathHandler(mimetype); if(handler != null) { if(framework.debug.url) { framework.debug.println("using JVMClassPath handler for " + mimetype); } return handler; } handler = getServiceHandler(mimetype); if(handler != null) { if(framework.debug.url) { framework.debug.println("Using service ContentHandler for " + mimetype + ", handler=" + handler); } return handler; } if(framework.debug.url) { framework.debug.println("Using default ContentHandler for " + mimetype); } // delegate to system handler return null; } ContentHandler getServiceHandler(String mimetype) { try { final String filter = "(" + URLConstants.URL_CONTENT_MIMETYPE + "=" + mimetype + ")"; //TODO true or false? @SuppressWarnings("unchecked") final ServiceReference[] srl = (ServiceReference[]) framework.services.get(ContentHandler.class.getName(), filter, null); if (srl != null && srl.length > 0) { ContentHandlerWrapper wrapper = wrapMap.get(mimetype); if (wrapper == null) { wrapper = new ContentHandlerWrapper(framework, mimetype); wrapMap.put(mimetype, wrapper); } return wrapper; } } catch (final InvalidSyntaxException e) { throw new RuntimeException("Failed to get service: " + e); } return null; } ContentHandler getJVMClassPathHandler(String mimetype) { if (jvmPkgs != null) { for (final String jvmPkg : jvmPkgs) { final String converted = convertMimetype(mimetype); final String className = jvmPkg + "." + converted + ".Handler"; try { if(framework.debug.url) { framework.debug.println("JVMClassPathCH - trying ContentHandler class=" + className); } final Class clazz = Class.forName(className); final ContentHandler handler = (ContentHandler)clazz.newInstance(); if(framework.debug.url) { framework.debug.println("JVMClassPathCH - created ContentHandler class=" + className); } return handler; } catch (final Throwable t) { if(framework.debug.url) { framework.debug.println("JVMClassPathCH - no ContentHandler class " + className); } } } } if(framework.debug.url) { framework.debug.println("JVMClassPath - no ContentHandler for " + mimetype); } return null; } // please check this one for correctness static String convertMimetype(String s) { final String bad = ".,:;*-"; for(int i = 0; i < bad.length(); i++) { s = s.replace(bad.charAt(i), '_'); } s = s.replace('/', '.'); return s; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ServiceHooks.java0000644000175000017500000003123312346513666030436 0ustar felixfelix/* * Copyright (c) 2009-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceReference; import org.osgi.framework.hooks.service.EventListenerHook; import org.osgi.framework.hooks.service.FindHook; import org.osgi.framework.hooks.service.ListenerHook; import org.osgi.framework.hooks.service.ListenerHook.ListenerInfo; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; /** * Handle all framework hooks, mostly dispatched from BundleImpl, Services * and ServiceListenerState * */ @SuppressWarnings("deprecation") class ServiceHooks { final private FrameworkContext fwCtx; ServiceTracker listenerHookTracker; boolean bOpen; ServiceHooks(FrameworkContext fwCtx) { this.fwCtx = fwCtx; } synchronized void open() { if(fwCtx.debug.hooks) { fwCtx.debug.println("opening hooks"); } listenerHookTracker = new ServiceTracker (fwCtx.systemBundle.bundleContext, ListenerHook.class, new ServiceTrackerCustomizer() { public ListenerHook addingService(ServiceReference reference) { final ListenerHook lh = fwCtx.systemBundle.bundleContext.getService(reference); try { Collection c = getServiceCollection(); @SuppressWarnings({ "rawtypes", "unchecked" }) final Collection li = (Collection) c; lh.added(li); } catch (final Exception e) { fwCtx.debug.printStackTrace("Failed to call listener hook #" + reference.getProperty(Constants.SERVICE_ID), e); } return lh; } public void modifiedService(ServiceReference reference, ListenerHook service) { // noop } public void removedService(ServiceReference reference, ListenerHook service) { fwCtx.systemBundle.bundleContext.ungetService(reference); } }); listenerHookTracker.open(); bOpen = true; } /** * */ synchronized void close() { listenerHookTracker.close(); listenerHookTracker = null; bOpen = false; } /** * */ synchronized public boolean isOpen() { return bOpen; } /** * */ void filterServiceReferences(BundleContextImpl bc, String service, String filter, boolean allServices, Collection> refs) { @SuppressWarnings({ "unchecked", "rawtypes" }) final List> srl = (List) fwCtx.services.get(FindHook.class.getName()); if (srl != null) { final RemoveOnlyCollection> filtered = new RemoveOnlyCollection>(refs); for (final ServiceRegistrationImpl fhr : srl) { final ServiceReferenceImpl sr = fhr.reference; final FindHook fh = sr.getService(fwCtx.systemBundle); if (fh != null) { try { fh.find(bc, service, filter, allServices, filtered); } catch (final Exception e) { fwCtx.frameworkError(bc, new BundleException("Failed to call find hook #" + sr.getProperty(Constants.SERVICE_ID), e)); } } } } } /** * */ void filterServiceEventReceivers(final ServiceEvent evt, final Collection receivers) { @SuppressWarnings({ "unchecked", "rawtypes" }) final List> eventHooks = (List) fwCtx.services.get(org.osgi.framework.hooks.service.EventHook.class.getName()); if (eventHooks != null) { final HashSet ctxs = new HashSet(); for (final ServiceListenerEntry sle : receivers) { ctxs.add(sle.getBundleContext()); } final int start_size = ctxs.size(); final RemoveOnlyCollection filtered = new RemoveOnlyCollection(ctxs); for (final ServiceRegistrationImpl sregi : eventHooks) { final ServiceReferenceImpl sr = sregi.reference; final org.osgi.framework.hooks.service.EventHook eh = sr.getService(fwCtx.systemBundle); if (eh != null) { try { eh.event(evt, filtered); } catch (final Exception e) { fwCtx.debug.printStackTrace("Failed to call event hook #" + sr.getProperty(Constants.SERVICE_ID), e); } } } // TODO, refactor this for speed!? if (start_size != ctxs.size()) { for (final Iterator ir = receivers.iterator(); ir.hasNext(); ) { if (!ctxs.contains(ir.next().getBundleContext())) { ir.remove(); } } } } @SuppressWarnings({ "rawtypes", "unchecked" }) final List> eventListenerHooks = (List) fwCtx.services.get(EventListenerHook.class.getName()); if (eventListenerHooks != null) { final HashMap> listeners = new HashMap>(); for (final ServiceListenerEntry sle : receivers) { if(!listeners.containsKey(sle.getBundleContext())) { listeners.put(sle.getBundleContext(), new ArrayList()); } listeners.get(sle.getBundleContext()).add(sle); } for(final Entry> e : listeners.entrySet()) { e.setValue(new RemoveOnlyCollection(e.getValue())); } final RemoveOnlyMap> filtered = new RemoveOnlyMap>(listeners); for(final ServiceRegistrationImpl sri : eventListenerHooks) { final EventListenerHook elh = sri.reference.getService(fwCtx.systemBundle); if(elh != null) { try { elh.event(evt, filtered); } catch(final Exception e) { fwCtx.debug.printStackTrace("Failed to call event hook #" + sri.reference.getProperty(Constants.SERVICE_ID), e); } } } receivers.clear(); for(final Collection li : listeners.values()) { @SuppressWarnings({ "rawtypes", "unchecked" }) final Collection sles = (Collection) li; receivers.addAll(sles); } } } /** * */ Collection getServiceCollection() { // TODO think about threads?! return Collections.unmodifiableSet(fwCtx.listeners.serviceListeners.serviceSet); } /** * */ void handleServiceListenerReg(ServiceListenerEntry sle) { if(!isOpen() || listenerHookTracker.size() == 0) { return; } final ServiceReference[] srl = listenerHookTracker.getServiceReferences(); final Set set = toImmutableSet((ListenerInfo) sle); if (srl!=null) { for (final ServiceReference sr : srl) { final ListenerHook lh = listenerHookTracker.getService(sr); try { lh.added(set); } catch (final Exception e) { fwCtx.debug.printStackTrace("Failed to call listener hook #" + sr.getProperty(Constants.SERVICE_ID), e); } } } } /** * */ void handleServiceListenerUnreg(ServiceListenerEntry sle) { if(isOpen()) { handleServiceListenerUnreg(toImmutableSet(sle)); } } /** * */ void handleServiceListenerUnreg(Collection set) { if(!isOpen() || listenerHookTracker.size() == 0) { return; } final ServiceReference[] srl = listenerHookTracker.getServiceReferences(); if (srl != null) { @SuppressWarnings({ "rawtypes", "unchecked" }) final Collection lis = (Collection) set; for (final ServiceReference sr : srl) { final ListenerHook lh = listenerHookTracker.getService(sr); try { lh.removed(lis); } catch (final Exception e) { fwCtx.debug .printStackTrace("Failed to call listener hook #" + sr.getProperty(Constants.SERVICE_ID), e); } } } } /** * */ static Set toImmutableSet(E obj) { Set set = new HashSet(); set.add(obj); set = Collections.unmodifiableSet(set); return set; } static class RemoveOnlyMap implements Map { final Map original; public RemoveOnlyMap(Map original) { this.original = original; } public void clear() { original.clear(); } public boolean containsKey(Object k) { return original.containsKey(k); } public boolean containsValue(Object v) { return original.containsValue(v); } public Set> entrySet() { return original.entrySet(); } public V get(Object k) { return original.get(k); } public boolean isEmpty() { return original.isEmpty(); } public Set keySet() { return original.keySet(); } public V put(Object k, Object v) { throw new UnsupportedOperationException("objects can only be removed"); } public void putAll(Map m) { throw new UnsupportedOperationException("objects can only be removed"); } public V remove(Object k) { return original.remove(k); } public int size() { return original.size(); } public Collection values() { return original.values(); } } /* void printSLE(String pre, Collection c, String post) { if(pre != null) { System.out.println(pre); System.out.flush(); } for(Object o : c) { ServiceListenerEntry sle = (ServiceListenerEntry)o; System.out.println("SLE: " + sle.listener.getClass().getName() + "@" + sle.getFilter()); System.out.flush(); } if(post != null) { System.out.println(post); System.out.flush(); } } void printSLE(String pre, Map m, String post) { System.out.println(pre); System.out.flush(); for(Object o : m.values()) { Collection c = (Collection)o; printSLE(null, c, null); } System.out.println(post); System.out.flush(); } */ } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/FrameworkWiringImpl.java0000644000175000017500000000605412346513666031774 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkListener; import org.osgi.framework.wiring.FrameworkWiring; public class FrameworkWiringImpl implements FrameworkWiring { private final FrameworkContext fwCtx; static final String SPEC_VERSION = "1.0"; FrameworkWiringImpl(FrameworkContext fwCtx) { this.fwCtx = fwCtx; } public Bundle getBundle() { return fwCtx.systemBundle; } public void refreshBundles(Collection bundles, FrameworkListener... listeners) { final Bundle[] bs = bundles != null ? bundles.toArray(new Bundle[bundles.size()]) : null; fwCtx.packageAdmin.refreshPackages(bs, listeners); } public boolean resolveBundles(Collection bundles) { final Bundle[] bs = bundles != null ? bundles.toArray(new Bundle[bundles.size()]) : null; return fwCtx.packageAdmin.resolveBundles(bs); } public Collection getRemovalPendingBundles() { Set res = new HashSet(); fwCtx.bundles.getRemovalPendingBundles(res); return res; } public Collection getDependencyClosure(Collection bundles) { final HashSet res = new HashSet(); for (Bundle b : bundles) { fwCtx.checkOurBundle(b); res.add(b); } fwCtx.resolver.closure(res); return res; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ImportPkg.java0000644000175000017500000003624112346513666027752 0ustar felixfelix/* * Copyright (c) 2005-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.Version; import org.osgi.framework.VersionRange; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.knopflerfish.framework.Util.HeaderEntry; /** * Data structure for import package definitions. * * @author Jan Stein, Gunnar Ekolin */ class ImportPkg implements BundleRequirement, Comparable { /** * The value of the resolution directive for dynamically imported packages. */ static final String RESOLUTION_DYNAMIC = "dynamic"; @SuppressWarnings("deprecation") private static final String PACKAGE_SPECIFICATION_VERSION = Constants.PACKAGE_SPECIFICATION_VERSION; // To maintain the creation order in the osgi.wiring.package name space. static private int importPkgCount = 0; final int orderal = ++importPkgCount; final String name; final BundlePackages bpkgs; final String resolution; final String bundleSymbolicName; final VersionRange packageRange; final VersionRange bundleRange; final Map attributes; final Map directives; final ImportPkg parent; // Link to pkg entry Pkg pkg = null; // Link to exporter ExportPkg provider = null; // Link to interal exporter ok to use ExportPkg internalOk = null; // Ordering of dynamic imports int dynId = 0; /** * Create an import package entry from manifest parser data. * * @param name the name of the package to be imported. * @param he the parsed import package statement. * @param b back link to the bundle revision owning this import declaration. * @param dynamic Set to true if this is a dynamic import package declaration. */ ImportPkg(final String name, final HeaderEntry he, final BundlePackages b, boolean dynamic) { this.bpkgs = b; this.name = name; if (name.startsWith("java.")) { throw new IllegalArgumentException("You can not import a java.* package"); } final Map dirs = he.getDirectives(); final String res = dirs.get(Constants.RESOLUTION_DIRECTIVE); if (dynamic) { if (res != null) { throw new IllegalArgumentException("Directives not supported for " + "Dynamic-Import, found " + Constants.RESOLUTION_DIRECTIVE + ":=" +res); } this.resolution = RESOLUTION_DYNAMIC; } else { if (res != null) { if (Constants.RESOLUTION_OPTIONAL.equals(res)) { this.resolution = Constants.RESOLUTION_OPTIONAL; } else if (Constants.RESOLUTION_MANDATORY.equals(res)) { this.resolution = Constants.RESOLUTION_MANDATORY; } else { throw new IllegalArgumentException("Directive " + Constants.RESOLUTION_DIRECTIVE + ", unexpected value: " + res); } } else { this.resolution = Constants.RESOLUTION_MANDATORY; } } this.bundleSymbolicName = (String) he.getAttributes() .remove(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE); final String versionStr = (String) he.getAttributes() .remove(Constants.VERSION_ATTRIBUTE); final String specVersionStr = (String) he.getAttributes() .remove(PACKAGE_SPECIFICATION_VERSION); if (specVersionStr != null) { this.packageRange = new VersionRange(specVersionStr); if (versionStr != null && !this.packageRange.equals(new VersionRange(versionStr))) { throw new IllegalArgumentException("Both " + Constants.VERSION_ATTRIBUTE + " and " + PACKAGE_SPECIFICATION_VERSION + " are specified, but differs"); } } else if (versionStr != null) { this.packageRange = new VersionRange(versionStr); } else { this.packageRange = null; } final String rangeStr = (String) he.getAttributes() .remove(Constants.BUNDLE_VERSION_ATTRIBUTE); if (rangeStr != null) { this.bundleRange = new VersionRange(rangeStr); } else { this.bundleRange = null; } this.attributes = Collections.unmodifiableMap(he.getAttributes()); final Filter filter = toFilter(); if (null!=filter) { dirs.put(Constants.FILTER_DIRECTIVE, filter.toString()); } this.directives = Collections.unmodifiableMap(dirs); this.parent = null; } /** * Create an import package entry with a new name from an import template. */ ImportPkg(ImportPkg ip, String name) { this.name = name; this.bpkgs = ip.bpkgs; this.resolution = ip.resolution; this.bundleSymbolicName = ip.bundleSymbolicName; this.packageRange = ip.packageRange; this.bundleRange = ip.bundleRange; this.attributes = ip.attributes; this.directives = ip.directives; this.parent = ip; } /** * Creates an import package entry with a new host bundle. */ ImportPkg(ImportPkg ip, BundlePackages bpkgs) { this.name = ip.name; this.bpkgs = bpkgs; this.resolution = ip.resolution; this.bundleSymbolicName = ip.bundleSymbolicName; this.packageRange = ip.packageRange; this.bundleRange = ip.bundleRange; this.attributes = ip.attributes; this.directives = ip.directives; this.parent = ip.parent; } /** * Create an import package entry. */ ImportPkg(ExportPkg p) { this.name = p.name; this.bpkgs = p.bpkgs; this.resolution = Constants.RESOLUTION_MANDATORY; this.bundleSymbolicName = null; if (p.version == Version.emptyVersion) { this.packageRange = null; } else { this.packageRange = new VersionRange(p.version.toString()); } this.bundleRange = null; this.attributes = p.attributes; // TODO, should we import unknown directives? final Map dirs = new HashMap(); final Filter filter = toFilter(); if (null!=filter) { dirs.put(Constants.FILTER_DIRECTIVE, filter.toString()); } this.directives = Collections.unmodifiableMap(dirs); this.parent = null; } /** * Attach this to a Pkg object which indicate that it is a valid importer. */ void attachPkg(Pkg p) { pkg = p; } /** * Detach this from a Pkg object which indicate that it is no longer valid. */ void detachPkg() { pkg = null; provider = null; } /** * Check if version fulfills import package constraints. * * @param ver Version to compare to. * @return Return 0 if equals, negative if this object is less than obj and * positive if this object is larger then obj. */ public boolean okPackageVersion(Version ver) { return packageRange == null || packageRange.includes(ver); } /** * Check that all package attributes match. * * @param ep Exported package. * @return True if okay, otherwise false. */ boolean checkAttributes(ExportPkg ep) { /* Mandatory attributes */ if (!checkMandatory(ep.mandatory)) { return false; } /* Predefined attributes */ if (!okPackageVersion(ep.version) || (bundleSymbolicName != null && !bundleSymbolicName.equals(ep.bpkgs.bg.symbolicName)) || (bundleRange != null && !bundleRange.includes(ep.bpkgs.bg.version))) { return false; } /* Other attributes */ for (final Entry entry : attributes.entrySet()) { final String a = (String) ep.attributes.get(entry.getKey()); if (a == null || !a.equals(entry.getValue())) { return false; } } return true; } /** * Check that we have import permission for exported package. * * @param ep Exported package. * @return True if okay, otherwise false. */ boolean checkPermission(ExportPkg ep) { return bpkgs.bg.bundle.fwCtx.perm.hasImportPackagePermission(bpkgs.bg.bundle, ep); } /** * Check that we can do an internal wire to the exported package. * * @return True if okay, otherwise false. */ boolean mustBeResolved() { return resolution == Constants.RESOLUTION_MANDATORY && internalOk == null; } /** * Check that we intersect specified ImportPkg. * * @param ip ImportPkg to check. * @return True if we overlap, otherwise false. */ boolean intersect(ImportPkg ip) { if (ip.bundleSymbolicName != null && bundleSymbolicName != null && !ip.bundleSymbolicName.equals(bundleSymbolicName)) { return false; } // Check that no other attributes conflict for (final Entry entry : attributes.entrySet()) { final String a = (String) ip.attributes.get(entry.getKey()); if (a != null && !a.equals(entry.getValue())) { return false; } } // Resolution doesn't need to be checked. // This is handle when resolving package. // If one import is mandatory then all must match. if (packageRange != null && packageRange.intersection(ip.packageRange).isEmpty()) { return false; } return bundleRange == null || !bundleRange.intersection(ip.bundleRange).isEmpty(); } /** * String describing package name and specification version, if specified. * * @return String. */ public String pkgString() { // NYI! More info? if (packageRange != null) { return name + ";" + Constants.VERSION_ATTRIBUTE + "=" + packageRange; } else { return name; } } /** * String describing this object. * * @return String. */ @Override public String toString() { return pkgString() + "(" + bpkgs.bg.bundle + ")"; } boolean isDynamic() { return resolution == RESOLUTION_DYNAMIC; } /** * Check that we have all mandatory attributes. * * @param mandatory Collection of mandatory attribute. * @return Return true if we have all mandatory attributes, otherwise false. */ private boolean checkMandatory(final Collection mandatory) { if (mandatory != null) { for (final String a : mandatory) { if (Constants.VERSION_ATTRIBUTE.equals(a)) { if (packageRange == null) { return false; } } else if (Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE.equals(a)) { if (bundleSymbolicName == null) { return false; } } else if (Constants.BUNDLE_VERSION_ATTRIBUTE.equals(a)) { if (bundleRange == null) { return false; } } else if (!attributes.containsKey(a)) { return false; } } } return true; } // BundleRequirement method @Override public String getNamespace() { return BundleRevision.PACKAGE_NAMESPACE; } // BundleRequirement method @Override public Map getDirectives() { return directives; } private Filter toFilter() { final StringBuffer sb = new StringBuffer(80); boolean multipleConditions = false; sb.append('('); sb.append(BundleRevision.PACKAGE_NAMESPACE); sb.append('='); sb.append(name); if (name.length()==0 || name.endsWith(".")) { // Dynamic import with wild-card. sb.append('*'); } sb.append(')'); if (packageRange != null) { sb.append(packageRange.toFilterString(Constants.VERSION_ATTRIBUTE)); multipleConditions = true; } if (bundleSymbolicName != null) { sb.append('('); sb.append(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE); sb.append('='); sb.append(bundleSymbolicName); sb.append(')'); multipleConditions |= true; } if (bundleRange != null) { sb.append(bundleRange.toFilterString(Constants.BUNDLE_VERSION_ATTRIBUTE)); multipleConditions = true; } for (final Entry entry : attributes.entrySet()) { sb.append('('); sb.append(entry.getKey()); sb.append('='); sb.append(entry.getValue().toString()); sb.append(')'); multipleConditions |= true; } if (multipleConditions) { sb.insert(0, "(&"); sb.append(')'); } try { return FrameworkUtil.createFilter(sb.toString()); } catch (final InvalidSyntaxException _ise) { // Should not happen... System.err.println("createFilter: '" +sb.toString() +"': " +_ise.getMessage()); return null; } } // BundleRequirement method @Override public Map getAttributes() { @SuppressWarnings("unchecked") final Map res = Collections.EMPTY_MAP; return res; } // BundleRequirement method @Override public BundleRevision getRevision() { return bpkgs.bg.bundleRevision; } @Override public BundleRevision getResource() { return bpkgs.bg.bundleRevision; } // BundleRequirement method @Override public boolean matches(BundleCapability capability) { if (BundleRevision.PACKAGE_NAMESPACE.equals(capability.getNamespace())) { return toFilter().matches(capability.getAttributes()); } return false; } /** * The default ordering is the order in which the {@code ImportPkg}-objects * has been created. I.e., the order they appeared in the {@code Import-Package} * header. * * @param o other object to compare with. * @return Less than zero, zero or greater than zero of this object is smaller * than, equals to or greater than {@code o}. */ @Override public int compareTo(ImportPkg o) { return this.orderal - o.orderal; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/WeavingHooks.java0000644000175000017500000003047712346513664030445 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.SortedMap; import org.osgi.framework.ServiceReference; import org.osgi.framework.hooks.weaving.WeavingException; import org.osgi.framework.hooks.weaving.WeavingHook; import org.osgi.framework.hooks.weaving.WovenClass; import org.osgi.framework.wiring.BundleWiring; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; class WeavingHooks { final private FrameworkContext fwCtx; ServiceTracker weavingHookTracker; WeavingHooks(FrameworkContext fwCtx) { this.fwCtx = fwCtx; } synchronized void open() { if (fwCtx.debug.hooks) { fwCtx.debug.println("Begin Tracking Weaving Hooks"); } weavingHookTracker = new ServiceTracker( fwCtx.systemBundle.bundleContext, WeavingHook.class, new ServiceTrackerCustomizer() { public TrackedWeavingHook addingService( ServiceReference reference) { return new TrackedWeavingHook( fwCtx.systemBundle.bundleContext .getService(reference), reference); } public void modifiedService(ServiceReference reference, TrackedWeavingHook service) { } public void removedService(ServiceReference reference, TrackedWeavingHook service) { } }); weavingHookTracker.open(); } synchronized void close() { weavingHookTracker.close(); weavingHookTracker = null; } synchronized public boolean isOpen() { return weavingHookTracker != null; } synchronized void callHooks(WovenClassImpl wc) throws Exception { if (!isOpen()) { return; } if (wc.isWeavingComplete()) { throw new RuntimeException("ERROR!!"); } try { final SortedMap, TrackedWeavingHook> hooks = weavingHookTracker .getTracked(); for (final TrackedWeavingHook twh : hooks.values()) { if (twh.isBlackListed()) continue; try { twh.weave(wc); } catch (final WeavingException we) { fwCtx.frameworkError(twh.reference.getBundle(), we); final ClassFormatError cfe = new ClassFormatError( "WeavingException thrown: " + we.getMessage() + " by hook " + twh.getClass().getName()); cfe.initCause(we); throw cfe; } catch (final Throwable t) { fwCtx.frameworkError(twh.reference.getBundle(), t); twh.blacklist(); final ClassFormatError cfe = new ClassFormatError("Exception throw: " + t + " while calling hook " + twh.getClass().getName()); cfe.initCause(t); throw cfe; } } } finally { wc.markAsComplete(); } } static class TrackedWeavingHook implements WeavingHook { final WeavingHook tracked; final ServiceReference reference; boolean blacklisted = false; TrackedWeavingHook(WeavingHook tracked, ServiceReference reference) { this.tracked = tracked; this.reference = reference; } public void weave(WovenClass wovenClass) { tracked.weave(wovenClass); } void blacklist() { blacklisted = true; } boolean isBlackListed() { return blacklisted; } } static class WovenClassImpl implements WovenClass { final BundleImpl bundle; final String name; byte[] current = null; boolean complete = false; Class c = null; final List dynamicImports = new DynamicImportList(this); WovenClassImpl(BundleImpl bundle, String name, byte[] initial) { this.bundle = bundle; this.name = name; this.current = initial; } public byte[] getBytes() { bundle.fwCtx.perm.checkWeaveAdminPerm(bundle); if (complete) { final byte[] r = new byte[current.length]; System.arraycopy(current, 0, r, 0, current.length); return r; } else { return current; } } public void setBytes(byte[] newBytes) { bundle.fwCtx.perm.checkWeaveAdminPerm(bundle); if (complete) throw new IllegalStateException( "Trying to call WovenClass.setBytes(byte[]) after weaving is complete"); if (newBytes == null) throw new NullPointerException( "Trying to call WovenClass.setBytes(byte[]) with null newBytes"); current = newBytes; } public List getDynamicImports() { return dynamicImports; } public boolean isWeavingComplete() { return complete; } public String getClassName() { return name; } public ProtectionDomain getProtectionDomain() { return c == null ? null : c.getProtectionDomain(); } public Class getDefinedClass() { return c; } public BundleWiring getBundleWiring() { return bundle.current().bundleRevision.getWiring(); } void markAsComplete() { complete = true; } void setDefinedClass(Class c) { markAsComplete(); this.c = c; } @Override public String toString() { return "WovenClass[" + name + ", " + toString(dynamicImports) + ", byte[" + current.length + "]=" + current + "]"; } String getDynamicImportsAsString() { final StringBuffer sb = new StringBuffer(); for (final String s : dynamicImports) { if (sb.length() > 0) { sb.append(", "); } sb.append(s); } return sb.toString(); } String toString(List sl) { final StringBuffer sb = new StringBuffer(); sb.append("("); for (final String s : sl) { if (sb.length() > 1) { sb.append(", "); } sb.append(s); } sb.append(")"); return sb.toString(); } public boolean hasAdditionalDynamicImports() { return !dynamicImports.isEmpty(); } } public static class DynamicImportList implements List { final private List org; final private WovenClassImpl parent; public DynamicImportList(WovenClassImpl parent) { this.parent = parent; this.org = new ArrayList(); } public DynamicImportList(WovenClassImpl parent, List subList) { this.parent = parent; org = subList; } @Override public boolean add(E elem) { checkChangeAllowed(); return org.add(elem); } @Override public void add(int index, E elem) { checkChangeAllowed(); org.add(index, elem); } @Override public boolean addAll(Collection elems) { checkChangeAllowed(); return org.addAll(elems); } @Override public boolean addAll(int index, Collection elems) { checkChangeAllowed(); return org.addAll(index, elems); } @Override public void clear() { checkChangeAllowed(); org.clear(); } @Override public boolean contains(Object elem) { return org.contains(elem); } @Override public boolean containsAll(Collection elems) { return org.containsAll(elems); } @Override public E get(int index) { return org.get(index); } @Override public int indexOf(Object elem) { return org.indexOf(elem); } @Override public boolean isEmpty() { return org.isEmpty(); } @Override public Iterator iterator() { return new DynamicListIterator(parent, org.listIterator()); } @Override public int lastIndexOf(Object elem) { return org.lastIndexOf(elem); } @Override public ListIterator listIterator() { return new DynamicListIterator(parent, org.listIterator()); } @Override public ListIterator listIterator(int index) { return new DynamicListIterator(parent, org.listIterator(index)); } @Override public E remove(int index) { checkChangeAllowed(); return org.remove(index); } @Override public boolean remove(Object elem) { checkChangeAllowed(); return org.remove(elem); } @Override public boolean removeAll(Collection elems) { checkChangeAllowed(); return org.removeAll(elems); } @Override public boolean retainAll(Collection elems) { checkChangeAllowed(); return org.removeAll(elems); } @Override public E set(int index, E elem) { checkChangeAllowed(); return org.set(index, elem); } @Override public int size() { return org.size(); } @Override public List subList(int from, int to) { return new DynamicImportList(parent, org.subList(from, to)); } @Override public Object[] toArray() { return org.toArray(); } @Override public T[] toArray(T[] a) { return org.toArray(a); } private void checkChangeAllowed() throws UnsupportedOperationException { if (parent.isWeavingComplete()) { throw new IllegalStateException("Parent WovenClass is frozen"); } parent.bundle.fwCtx.perm.checkWeaveAdminPerm(parent.bundle); } } public static class DynamicListIterator implements ListIterator { final private WovenClassImpl parent; final private ListIterator org; public DynamicListIterator(WovenClassImpl parent, ListIterator org) { this.parent = parent; this.org = org; } @Override public void add(E elem) { checkChangeAllowed(); org.add(elem); } @Override public boolean hasNext() { return org.hasNext(); } @Override public boolean hasPrevious() { return org.hasPrevious(); } @Override public E next() { return org.next(); } @Override public int nextIndex() { return org.nextIndex(); } @Override public E previous() { return org.previous(); } @Override public int previousIndex() { return org.previousIndex(); } @Override public void remove() { checkChangeAllowed(); org.remove(); } @Override public void set(E elem) { checkChangeAllowed(); org.set(elem); } private void checkChangeAllowed() throws UnsupportedOperationException { if (parent.isWeavingComplete()) { throw new IllegalStateException("Parent WovenClass is frozen"); } parent.bundle.fwCtx.perm.checkWeaveAdminPerm(parent.bundle); } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ReferenceURLStreamHandler.java0000644000175000017500000000607312346513666032771 0ustar felixfelix/* * Copyright (c) 2003-2004, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.*; import java.net.*; /** * Reference URL handling, used for accepting file: references. * * Accepts URLs on the form *

 *  reference:file URL]
 * 
* Where [file URL] is any valid file: URL. * *

* openConnection simply returns the URLConnection * created by removing the reference: prefix. *

* */ public class ReferenceURLStreamHandler extends URLStreamHandler { final public static String PROTOCOL = "reference"; ReferenceURLStreamHandler() { super(); } /** * * @throws IOException if the specified URL is not a reference to a * file: URL */ public URLConnection openConnection(URL url) throws IOException { URL actual = new URL(getActual(url)); if(!"file".equals(actual.getProtocol())) { throw new IOException("Only file: URLs are allowed as references, got " + url); } return actual.openConnection(); } /** * Get the actual URL string represented by the specified * reference: URL. * * @throws IllegalArgumentException if the specified URL does not * have a reference: protocol. */ protected static String getActual(URL u) { String s = u.toString(); if(!s.startsWith(PROTOCOL + ":")) { throw new IllegalArgumentException("URL " + u + " does not start with " + PROTOCOL + ":"); } return s.substring(PROTOCOL.length() + 1); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/ExportPkg.java0000644000175000017500000002733212346513666027762 0ustar felixfelix/* * Copyright (c) 2005-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.knopflerfish.framework.Util.HeaderEntry; import org.osgi.framework.Constants; import org.osgi.framework.Version; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRevision; /** * Data structure for export package definitions. * * @author Jan Stein, Gunnar Ekolin */ class ExportPkg implements BundleCapability, Comparable { // To maintain the creation order in the osgi.wiring.package name space. static private int exportPkgCount = 0; final int orderal = ++exportPkgCount; final String name; final BundlePackages bpkgs; final Set uses; final Set mandatory; final Set include; final Set exclude; final Version version; final Map attributes; boolean zombie = false; // Link to pkg entry Pkg pkg = null; /** * Create an export package entry. */ ExportPkg(final String name, final HeaderEntry he, final BundlePackages b) { this.bpkgs = b; this.name = name; if (name.startsWith("java.")) { throw new IllegalArgumentException("You can not export a java.* package"); } this.uses = Util.parseEnumeration(Constants.USES_DIRECTIVE, he .getDirectives().get(Constants.USES_DIRECTIVE)); this.mandatory = Util.parseEnumeration(Constants.MANDATORY_DIRECTIVE, he .getDirectives().get(Constants.MANDATORY_DIRECTIVE)); this.include = Util.parseEnumeration(Constants.INCLUDE_DIRECTIVE, he .getDirectives().get(Constants.INCLUDE_DIRECTIVE)); this.exclude = Util.parseEnumeration(Constants.EXCLUDE_DIRECTIVE, he .getDirectives().get(Constants.EXCLUDE_DIRECTIVE)); final String versionStr = (String) he.getAttributes() .remove(Constants.VERSION_ATTRIBUTE); @SuppressWarnings("deprecation") final String SPEC_VERSION = Constants.PACKAGE_SPECIFICATION_VERSION; final String specVersionStr = (String) he.getAttributes().remove(SPEC_VERSION); if (specVersionStr != null) { this.version = new Version(specVersionStr); if (versionStr != null && !this.version.equals(new Version(versionStr))) { throw new IllegalArgumentException("Both " + Constants.VERSION_ATTRIBUTE + " and " + SPEC_VERSION + " are specified, and differs"); } } else if (versionStr != null) { this.version = new Version(versionStr); } else { this.version = Version.emptyVersion; } if (he.getAttributes().containsKey(Constants.BUNDLE_VERSION_ATTRIBUTE)) { throw new IllegalArgumentException("Export definition illegally contains attribute, " + Constants.BUNDLE_VERSION_ATTRIBUTE); } if (he.getAttributes().containsKey(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)) { throw new IllegalArgumentException("Export definition illegally contains attribute, " + Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE); } this.attributes = Collections.unmodifiableMap(he.getAttributes()); } /** * Create an export package entry with a new name from an export template. * * @param ep The export template to create an export package entry for. * @param name The name of the export package entry created from the template. */ ExportPkg(ExportPkg ep, String name) { this.name = name; this.bpkgs = ep.bpkgs; this.uses = ep.uses; this.mandatory = ep.mandatory; this.include = ep.include; this.exclude = ep.exclude; this.version = ep.version; this.attributes = ep.attributes; } /** * Create a re-export package entry with a new bundle owner from an * existing export. * @param ep The ExportPkg to create a re-export package entry for. * @param b The BundlePackages that owns this re-exprot entry. */ ExportPkg(ExportPkg ep, BundlePackages b) { this.name = ep.name; this.bpkgs = b; this.uses = ep.uses; this.mandatory = ep.mandatory; this.include = ep.include; this.exclude = ep.exclude; this.version = ep.version; this.attributes = ep.attributes; } /** * Attach this to a Pkg object which indicate that it is exported. */ void attachPkg(Pkg p) { pkg = p; } /** * Detach this from a Pkg object which indicate that it is no longer exported. */ void detachPkg() { pkg = null; zombie = false; } /** * Checks if we are allowed to export this class according to * the filter rules. */ boolean checkFilter(String fullClassName) { String clazz = null; boolean ok = true; if (fullClassName != null) { if (include != null) { // assert fullClassName.startsWith(name) clazz = fullClassName.substring(name.length() + 1); for (final Iterator i = include.iterator(); i.hasNext(); ) { if (Util.filterMatch(i.next(), clazz)) { break; } if (!i.hasNext()) { ok = false; } } } if (ok && exclude != null) { if (clazz == null) { // assert fullClassName.startsWith(name) clazz = fullClassName.substring(name.length() + 1); } for (final String string : exclude) { if (Util.filterMatch(string, clazz)) { ok = false; break; } } } } return ok; } /** * Check if ExportPkg is provider of a package. * * @return True if pkg exports the package. */ boolean isProvider() { final Pkg p = pkg; if (p != null) { synchronized (p) { return p.providers.contains(this) || bpkgs.isRequired(); } } return false; } /** * Check if ExportPkg is exported from its bundle. A package is deemed to * be exported if its bundle is resolved and hasn't been replaced by a * conflicting import (see resolving process chapter in core spec.). * Bundle must also have export permission. * * @return True if pkg exports the package. */ boolean isExported() { final BundlePackages bp = bpkgs; if (checkPermission() && pkg != null && (bp.bg.bundle.isResolved() || zombie)) { final BundlePackages pbp = bp.getProviderBundlePackages(name); return pbp == null || pbp.bg.bundle == bpkgs.bg.bundle; } return false; } /** * Get active importers of a package. * * @param pkg Package. * @return List of bundles importing, null export is not active. */ List getPackageImporters() { final Pkg p = pkg; if (p != null) { final List res = new ArrayList(); synchronized (p) { for (final ImportPkg ip : p.importers) { if (ip.provider == this && ip.bpkgs != bpkgs) { res.add(ip); } } } return res; } return null; } /** * Check if we have export permissions. * * @return true if we have export permission */ boolean checkPermission() { return bpkgs.bg.bundle.fwCtx.perm.hasExportPackagePermission(this); } /** * Check if the name, version, attributes and directives are equal. * * @return true if all package information is equal, otherwise false. */ boolean pkgEquals(Object o) { if (this == o) { return true; } if (null == o) { return false; } final ExportPkg ep = (ExportPkg)o; return name.equals(ep.name) && version.equals(ep.version) && (uses == null ? ep.uses == null : uses.equals(ep.uses)) && (mandatory == null ? ep.mandatory == null : mandatory.equals(ep.mandatory)) && (include == null ? ep.include == null : include.equals(ep.include)) && (exclude == null ? ep.exclude == null : exclude.equals(ep.exclude)) && attributes.equals(ep.attributes); } /** * String describing package name and specification version, if specified. * * @return String. */ public String pkgString() { if (version != Version.emptyVersion) { return name + ";" + Constants.VERSION_ATTRIBUTE + "=" + version; } else { return name; } } /** * String describing this object. * * @return String. */ @Override public String toString() { final StringBuffer sb = new StringBuffer(pkgString()); sb.append(' '); if (zombie) { sb.append("Zombie"); } sb.append("Bundle"); sb.append(bpkgs.bundleGenInfo()); return sb.toString(); } @Override public String getNamespace() { return BundleRevision.PACKAGE_NAMESPACE; } @Override public Map getDirectives() { final Map res = new HashMap(1); if (uses!=null) { final StringBuffer sb = new StringBuffer(uses.size()*30); for (final String pkg : uses) { if (sb.length()>0) sb.append(','); sb.append(pkg); } res.put(Constants.USES_DIRECTIVE, sb.toString()); } return res; } @Override public Map getAttributes() { final Map res = new HashMap(4+attributes.size()); res.put(BundleRevision.PACKAGE_NAMESPACE, name); res.put(Constants.VERSION_ATTRIBUTE, version); res.put(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, bpkgs.bg.symbolicName); res.put(Constants.BUNDLE_VERSION_ATTRIBUTE, bpkgs.bg.version); res.putAll(attributes); return Collections.unmodifiableMap(res); } @Override public BundleRevision getRevision() { return bpkgs.bg.bundleRevision; } @Override public BundleRevision getResource() { return bpkgs.bg.bundleRevision; } /** * The default ordering is the order in which the {@code ExportPkg}-objects * has been created. I.e., the order they appeared in the {@code Export-Package} * header. * * @param o other object to compare with. * @return Less than zero, zero or greater than zero of this object is smaller * than, equals to or greater than {@code o}. */ @Override public int compareTo(ExportPkg o) { return this.orderal - o.orderal; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/FileArchive.java0000644000175000017500000000730212346513666030213 0ustar felixfelix/* * Copyright (c) 2009-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.IOException; import java.util.Enumeration; import java.util.Set; /** * Interface for managing bundle contents. * * @author Jan Stein */ public interface FileArchive { /** * Get a byte array containg the contents of named file from a bundle archive. * * @param component File to get. * @return Byte array with contents of file or null if file doesn't exist. * @exception IOException if failed to read jar entry. */ byte[] getClassBytes(String component) throws IOException; /** * Get a BundleResourceStream to named entry inside a bundle. Leading '/' is * stripped. * * @param component Entry to get reference to. * @param ix index of sub archives. A postive number is the classpath entry * index. 0 means look in the main bundle. * @return BundleResourceStream to entry or null if it doesn't exist. */ BundleResourceStream getBundleResourceStream(String component); /** * Returns an Enumeration of all the paths (String objects) to * entries within the bundle whose longest sub-path matches the supplied path * argument. * * @param name * @return */ Enumeration findResourcesPath(String path); /** * Check for native library in archive. * * @param path Name of native code file to get. * @return If native library exist return libname, otherwise null. */ String checkNativeLibrary(String path); /** * Get native code library filename. * * @param libNameKey Key for native lib to get. * @return A string with the path to the native library. */ String getNativeLibrary(String libNameKey); /** * Get BundleGeneration object for this archive. */ BundleGeneration getBundleGeneration(); /** * Get sub-archive id for this archive. */ int getSubId(); /** * Check if a file exists (or dir, if dirs is true). * * @param path * @param dirs * @return */ boolean exists(String path, boolean dirs); /** * List all entries for named directory. * * @param path * @return */ Set listDir(String path); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleWiringImpl.java0000644000175000017500000003106712346513666031252 0ustar felixfelix/* * Copyright (c) 2013-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeSet; import java.util.Vector; import org.osgi.framework.Bundle; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWire; import org.osgi.framework.wiring.BundleWiring; import org.osgi.resource.Capability; import org.osgi.resource.Requirement; import org.osgi.resource.Wire; public class BundleWiringImpl implements BundleWiring { final BundleRevisionImpl bundleRevision; BundleWiringImpl(BundleRevisionImpl br) { bundleRevision = br; } public Bundle getBundle() { return bundleRevision.getBundle(); } public boolean isCurrent() { return this == bundleRevision.getWiring() && bundleRevision.bundle.current() == bundleRevision.gen; } public boolean isInUse() { return this == bundleRevision.getWiring(); } public List getCapabilities(String namespace) { if (!isInUse()) { return null; } BundleGeneration gen = bundleRevision.getBundleGeneration(); final int ns = BundleRevisionImpl.whichNameSpaces(namespace); final ArrayList res = new ArrayList(); if ((ns & BundleRevisionImpl.NS_IDENTITY) != 0) { final BundleCapability bc = gen.getIdentityCapability(); if (bc != null) { res.add(bc); } } if (!gen.isFragment()) { if ((ns & BundleRevisionImpl.NS_BUNDLE) != 0) { final BundleCapability bc = gen.getBundleCapability(); if (bc != null) { res.add(bc); } } if ((ns & BundleRevisionImpl.NS_HOST) != 0) { final BundleCapability bc = gen.getHostCapability(); if (bc != null) { res.add(bc); } } if ((ns & BundleRevisionImpl.NS_PACKAGE) != 0) { for (ExportPkg ep : gen.bpkgs.getPackageCapabilities()) { if (ep.checkPermission()) { res.add(ep); } } } if ((ns & BundleRevisionImpl.NS_OTHER) != 0) { final Map> caps = gen.bpkgs.getOtherCapabilities(); Collection> clbc = null; if (null != namespace) { final List lbc = caps.get(namespace); if (lbc != null) { clbc = Collections.singleton(lbc); } } else { clbc = caps.values(); } if (null != clbc) { for (final List lbc : clbc) { for (final BundleCapabilityImpl bc : lbc) { if (bc.isEffectiveResolve() && bc.checkPermission()) { res.add(bc); } } } } } } return res; } public List getRequirements(String namespace) { if (!isInUse()) { return null; } BundleGeneration gen = bundleRevision.getBundleGeneration(); final int ns = BundleRevisionImpl.whichNameSpaces(namespace); final ArrayList res = new ArrayList(); if (gen.isFragment()) { if ((ns & BundleRevisionImpl.NS_HOST) != 0) { res.add(gen.fragment); } } else { if ((ns & BundleRevisionImpl.NS_BUNDLE) != 0) { for (final Iterator irb = gen.bpkgs.getRequire(); irb.hasNext(); ) { final RequireBundle rb = irb.next(); if (null != rb.bpkgs && rb.bpkgs.isRequiredBy(gen.bpkgs)) { res.add(rb); } } } if ((ns & BundleRevisionImpl.NS_PACKAGE) != 0) { res.addAll(gen.bpkgs.getPackageRequirements()); } if ((ns & (BundleRevisionImpl.NS_IDENTITY|BundleRevisionImpl.NS_OTHER)) != 0) { final Map> reqs = gen.getOtherRequirements(); Collection> clbr = null; if (null != namespace) { final List lbr = reqs.get(namespace); if (lbr != null) { clbr = Collections.singleton(lbr); } } else { clbr = reqs.values(); } if (null != clbr) { for (final List lbr : clbr) { for (final BundleRequirementImpl br : lbr) { if (br.isWired()) { res.add(br); } } } } } } return res; } public List getProvidedWires(String namespace) { if (!isInUse()) { return null; } BundleGeneration gen = bundleRevision.getBundleGeneration(); final int ns = BundleRevisionImpl.whichNameSpaces(namespace); final ArrayList res = new ArrayList(); if ((ns & BundleRevisionImpl.NS_BUNDLE) != 0) { final List reqBys = gen.bpkgs.getRequiredBy(); for (final BundlePackages bp : reqBys) { for (final Iterator irb = bp.getRequire(); irb.hasNext(); ) { final RequireBundle rb = irb.next(); if (rb.bpkgs == gen.bpkgs) { res.add(new BundleWireImpl(gen.getBundleCapability(), gen, rb, bp.bg)); } } } } if ((ns & BundleRevisionImpl.NS_HOST) != 0) { if (gen.isFragmentHost()) { @SuppressWarnings("unchecked") final Vector fix = (Vector)gen.fragments.clone(); for (final BundleGeneration fbg : fix) { res.add(new BundleWireImpl(gen.getHostCapability(), gen, fbg.fragment, fbg)); } } } if ((ns & BundleRevisionImpl.NS_PACKAGE) != 0) { for (final BundleCapability bc : gen.bpkgs.getPackageCapabilities()) { final ExportPkg ep = (ExportPkg)bc; final List ips = ep.getPackageImporters(); if (ips != null) { for (final ImportPkg ip : ips) { // Fetch the original for dynamic and fragment imports ImportPkg oip; if (ip.parent != null && ip.parent.bpkgs != ip.bpkgs) { oip = ip.parent; } else { oip = ip; } res.add(new BundleWireImpl(ep, gen, oip, ip.bpkgs.bg)); } } } } if ((ns & (BundleRevisionImpl.NS_IDENTITY|BundleRevisionImpl.NS_OTHER)) != 0) { List other = gen.getCapabilityWires(); if (other != null) { for (BundleWireImpl bw : other) { if (namespace == null || namespace.equals(bw.getCapability().getNamespace())) { res.add(bw); } } } } return res; } public List getRequiredWires(String namespace) { if (!isInUse()) { return null; } BundleGeneration gen = bundleRevision.getBundleGeneration(); final int ns = BundleRevisionImpl.whichNameSpaces(namespace); final ArrayList res = new ArrayList(); if ((ns & BundleRevisionImpl.NS_BUNDLE) != 0) { for (final Iterator irb = gen.bpkgs.getRequire(); irb.hasNext(); ) { final RequireBundle rb = irb.next(); if (null != rb.bpkgs && rb.bpkgs.isRequiredBy(gen.bpkgs)) { res.add(new BundleWireImpl(rb.bpkgs.bg.getBundleCapability(), rb.bpkgs.bg, rb, gen)); } } } if ((ns & BundleRevisionImpl.NS_HOST) != 0) { if (gen.isFragment()) { for (final BundleGeneration hbg : gen.getHosts()) { res.add(new BundleWireImpl(hbg.getHostCapability(), hbg, gen.fragment, gen)); } } } if ((ns & BundleRevisionImpl.NS_PACKAGE) != 0) { TreeSet dynamic = new TreeSet( new Comparator() { @Override public int compare(ImportPkg o1, ImportPkg o2) { return o1.dynId - o2.dynId; } }); for (final ImportPkg ip : gen.bpkgs.getPackageRequirements()) { ExportPkg ep = ip.provider; if (ep != null) { res.add(new BundleWireImpl(ep, ep.bpkgs.bg, ip, gen)); } else { // Must be dynamic import or fragment for (ImportPkg cip : gen.bpkgs.getActiveChildImports(ip)) { // Add dynamic imports in bind order if (ip.isDynamic()) { dynamic.add(cip); } else { res.add(new BundleWireImpl(cip.provider, cip.provider.bpkgs.bg, ip, gen)); } } } } for (ImportPkg cip : dynamic) { res.add(new BundleWireImpl(cip.provider, cip.provider.bpkgs.bg, cip.parent, gen)); } } if ((ns & (BundleRevisionImpl.NS_IDENTITY|BundleRevisionImpl.NS_OTHER)) != 0) { List other = gen.getRequirementWires(); if (other != null) { for (BundleWireImpl bw : other) { if (namespace == null || namespace.equals(bw.getRequirement().getNamespace())) { res.add(bw); } } } } return res; } public BundleRevision getRevision() { return bundleRevision; } public ClassLoader getClassLoader() { if (isInUse()) { return bundleRevision.getBundleGeneration().getClassLoader(); } return null; } public List findEntries(String path, String filePattern, int options) { BundleGeneration gen = bundleRevision.getBundleGeneration(); if (isInUse()) { return Collections.unmodifiableList(gen.bundle.secure.callFindEntries(gen, path, filePattern, (options & FINDENTRIES_RECURSE) != 0)); } return null; } public Collection listResources(String path, String filePattern, int options) { BundleGeneration gen = bundleRevision.getBundleGeneration(); if (!isInUse()) { return null; } @SuppressWarnings("unchecked") Collection res = Collections.EMPTY_SET; ClassLoader cl = gen.getClassLoader(); if (cl != null && cl instanceof BundleClassLoader) { BundleClassLoader bcl = (BundleClassLoader) gen.getClassLoader(); res = bcl.listResources(path, filePattern, options); } return res; } @SuppressWarnings("unchecked") @Override public List getResourceCapabilities(String namespace) { return (List)(List)getCapabilities(namespace); } @SuppressWarnings("unchecked") @Override public List getResourceRequirements(String namespace) { return (List)(List)getRequirements(namespace); } @SuppressWarnings("unchecked") @Override public List getProvidedResourceWires(String namespace) { return (List)(List)getProvidedWires(namespace); } @SuppressWarnings("unchecked") @Override public List getRequiredResourceWires(String namespace) { return (List)(List)getRequiredWires(namespace); } @Override public BundleRevision getResource() { return bundleRevision; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/SystemBundle.java0000644000175000017500000007601612346513666030460 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.Reader; import java.lang.reflect.Method; import java.net.URL; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.SortedSet; import java.util.TreeSet; import java.util.Vector; import org.osgi.framework.Bundle; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.FrameworkEvent; import org.osgi.framework.Version; import org.osgi.framework.VersionRange; import org.osgi.framework.launch.Framework; import org.osgi.framework.namespace.ExecutionEnvironmentNamespace; import org.osgi.framework.startlevel.FrameworkStartLevel; import org.osgi.framework.wiring.FrameworkWiring; /** * Implementation of the System Bundle object. * * @see org.osgi.framework.Bundle * @author Jan Stein * @author Philippe Laporte * @author Mats-Ola Persson */ public class SystemBundle extends BundleImpl implements Framework { /** * The file where we store the class path */ private final static String BOOT_CLASSPATH_FILE = "boot_cp"; /** * Export-Package string for system packages */ private String exportPackageString; /** * Provide-Capability string for the system bundle. */ private String provideCapabilityString; /** * The event to return to callers waiting in Framework.waitForStop() when the * framework has been stopped. */ volatile private FrameworkEvent stopEvent = null; /** * The thread that performs shutdown of this framework instance. */ private Thread shutdownThread = null; /** * Lock object */ private final Object lock = new Object(); /** * Marker that we need to restart JVM. */ boolean bootClassPathHasChanged; private FrameworkWiringImpl fwWiring; /** * Construct the System Bundle handle. * */ SystemBundle(FrameworkContext fw) { super(fw); } /** * Initialize this framework. * * @see org.osgi.framework.Framework#init */ @Override public void init() throws BundleException { secure.checkExecuteAdminPerm(this); synchronized (lock) { waitOnOperation(lock, "Framework.init", true); switch (state) { case INSTALLED: case RESOLVED: break; case STARTING: case ACTIVE: return; default: throw new IllegalStateException("INTERNAL ERROR, Illegal state, " + state); } doInit(); } } /** * Start this framework. * * @see org.osgi.framework.Framework#start */ @Override public void start(int options) throws BundleException { List bundlesToStart = null; synchronized (lock) { waitOnOperation(lock, "Framework.start", true); switch (state) { case INSTALLED: case RESOLVED: doInit(); // Fall through case STARTING: operation = ACTIVATING; break; case ACTIVE: return; default: throw new IllegalStateException("INTERNAL ERROR, Illegal state, " + state); } if (fwCtx.startLevelController == null) { bundlesToStart = fwCtx.storage.getStartOnLaunchBundles(); } } if (fwCtx.startLevelController != null) { // start level open is delayed to this point to // correctly work at restart fwCtx.startLevelController.open(); } else { // Start bundles according to their autostart setting. final Iterator i = bundlesToStart.iterator(); while (i.hasNext()) { final BundleImpl b = (BundleImpl)fwCtx.bundles.getBundle(i.next()); try { final int autostartSetting = b.current().archive.getAutostartSetting(); // Launch must not change the autostart setting of a bundle int option = Bundle.START_TRANSIENT; if (Bundle.START_ACTIVATION_POLICY == autostartSetting) { // Transient start according to the bundles activation policy. option |= Bundle.START_ACTIVATION_POLICY; } b.start(option); } catch (final BundleException be) { fwCtx.frameworkError(b, be); } } } synchronized (lock) { state = ACTIVE; operation = IDLE; lock.notifyAll(); fwCtx.listeners.frameworkEvent(new FrameworkEvent(FrameworkEvent.STARTED, this, null)); } } /** * */ @Override public FrameworkEvent waitForStop(long timeout) throws InterruptedException { synchronized (lock) { // Already stopped? if (((INSTALLED | RESOLVED) & state) == 0) { stopEvent = null; while (true) { final long st = Util.timeMillis(); try { lock.wait(timeout); if (stopEvent != null) { break; } } catch (final InterruptedException _) { } if (timeout > 0) { timeout = timeout - (Util.timeMillis() - st); if (timeout <= 0) { break; } } } if (stopEvent == null) { return new FrameworkEvent(FrameworkEvent.WAIT_TIMEDOUT, this, null); } } else if (stopEvent == null) { // Return this if stop or update have not been called and framework is // stopped. stopEvent = new FrameworkEvent(FrameworkEvent.STOPPED, this, null); } return stopEvent; } } /** * Stop this framework. * * @see org.osgi.framework.Framework#stop */ @Override public void stop(int options) throws BundleException { secure.checkExecuteAdminPerm(this); secure.callShutdown(this, false); } /** * Restart this framework. * * @see org.osgi.framework.Framework#update */ @Override public void update(InputStream in) throws BundleException { secure.checkLifecycleAdminPerm(this); if (in != null) { try { in.close(); } catch (final IOException ignore) { } } secure.callShutdown(this, true); } /** * Uninstall of framework are not allowed. * * @see org.osgi.framework.Framework#uninstall */ @Override public void uninstall() throws BundleException { secure.checkLifecycleAdminPerm(this); throw new BundleException("Uninstall of System bundle is not allowed", BundleException.INVALID_OPERATION); } /** * The system has all the permissions. * * @see org.osgi.framework.Bundle#hasPermission */ @Override public boolean hasPermission(Object permission) { return true; } /** * Get header data. * * @see org.osgi.framework.Bundle#getHeaders */ @Override public Dictionary getHeaders() { return getHeaders(null); } /** * Get header data. * * @see org.osgi.framework.Bundle#getHeaders */ @SuppressWarnings("deprecation") @Override public Dictionary getHeaders(String locale) { secure.checkMetadataAdminPerm(this); final Hashtable headers = new Hashtable(); headers.put(Constants.BUNDLE_SYMBOLICNAME, getSymbolicName()); headers.put(Constants.BUNDLE_NAME, location); headers.put(Constants.EXPORT_PACKAGE, exportPackageString); headers.put(Constants.BUNDLE_VERSION, getVersion().toString()); headers.put(Constants.BUNDLE_MANIFESTVERSION, "2"); headers.put(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT, fwCtx.props.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT)); headers.put("Bundle-Icon", "icon.png;size=32,icon64.png;size=64"); headers.put(Constants.BUNDLE_VENDOR, "Knopflerfish"); headers.put(Constants.BUNDLE_DESCRIPTION, "Knopflerfish System Bundle"); headers.put(Constants.PROVIDE_CAPABILITY, provideCapabilityString); return headers; } /** * Get bundle data. Get resources from bundle or fragment jars. * * @see org.osgi.framework.Bundle#findEntries */ @Override public Enumeration findEntries(String path, String filePattern, boolean recurse) { // TODO, What should system bundle return? return null; } /** * */ @Override public URL getEntry(String name) { if (secure.okResourceAdminPerm(this)) { return getClassLoader().getResource(name); } return null; } /** * */ @Override public Enumeration getEntryPaths(String path) { return null; } // Don't delegate to BundleImp since Bundle adaptations may not // apply to the SystemBundle. @Override @SuppressWarnings("unchecked") public A adapt(Class type) { secure.checkAdaptPerm(this, type); Object res = null; if (FrameworkWiring.class.equals(type)) { res = fwWiring; } else if (FrameworkStartLevel.class.equals(type)) { if (fwCtx.startLevelController != null) { res = fwCtx.startLevelController.frameworkStartLevel(this); } } else if (Framework.class.equals(type)) { res = this; } else { // TODO filter which adaptation we can do?! res = adaptSecure(type); } return (A) res; } // // Package method // /** * Get class loader for this bundle. * * @return System Bundle classloader. */ @Override ClassLoader getClassLoader() { return getClass().getClassLoader(); } /** * Set system bundle state to stopping */ void systemShuttingdown(final boolean restart) throws BundleException { } /** * Shutting down is done. */ void systemShuttingdownDone(final FrameworkEvent fe) { synchronized (lock) { if (state != INSTALLED) { state = RESOLVED; operation = IDLE; lock.notifyAll(); } stopEvent = fe; } } /** * Adds an bundle as an extension that will be included in the boot class path * on restart. * @throws BundleException Should not happened. */ void attachExtension(BundleGeneration extension) throws BundleException { if (extension.isBootClassPathExtension()) { // if we attach during startup, we assume that bundle is in BCP. if (getClassLoader() == null) { current().attachFragment(extension); } else { throw new UnsupportedOperationException( "Bootclasspath extension can not be dynamicly activated"); } } else { try { addClassPathURL(new URL("file:" + extension.archive.getJarLocation())); current().attachFragment(extension); handleExtensionActivator(extension); } catch (final Exception e) { throw new UnsupportedOperationException( "Framework extension could not be dynamicly activated, " + e); } } } /** * Reads all localization entries that affects this bundle (including its * host/fragments) * * @param locale locale == "" the bundle.properties will be read o/w it will * read the files as described in the spec. * @param localization_entries will append the new entries to this dictionary * @param baseName the basename for localization properties, null * will choose OSGi default */ void readLocalization(String locale, Hashtable localization_entries, String baseName) { @SuppressWarnings("unchecked") final Vector fragments = (Vector)current().fragments.clone(); if (fragments == null) { // NYI! read localization from framework. // There is no need for this now since it isn't used. return; } if (baseName == null) { baseName = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME; } if (!locale.equals("")) { locale = "_" + locale; } while (true) { final String l = baseName + locale + ".properties"; for (int i = fragments.size() - 1; i >= 0; i--) { final BundleGeneration bg = fragments.get(i); final Hashtable tmp = bg.archive.getLocalizationEntries(l); if (tmp != null) { localization_entries.putAll(tmp); return; } } final int pos = locale.lastIndexOf('_'); if (pos == -1) { break; } locale = locale.substring(0, pos); } } /** * */ void initSystemBundle() { bundleContext = new BundleContextImpl(this); final StringBuffer sp = new StringBuffer( fwCtx.props.getProperty(Constants.FRAMEWORK_SYSTEMPACKAGES)); if (sp.length() == 0) { // Try the system packages file addSysPackagesFromFile(sp, fwCtx.props.getProperty(FWProps.SYSTEM_PACKAGES_FILE_PROP), null); if (sp.length() == 0) { // Try the system packages base property. sp.append(fwCtx.props.getProperty(FWProps.SYSTEM_PACKAGES_BASE_PROP)); if (sp.length() == 0) { // use default set of packages. String jver = fwCtx.props.getProperty(FWProps.SYSTEM_PACKAGES_VERSION_PROP); Version jv; if (jver == null) { jv = new Version(FWProps.javaVersionMajor, FWProps.javaVersionMinor, 0); } else { try { jv = new Version(jver); } catch (IllegalArgumentException _ignore){ if (fwCtx.debug.framework) { fwCtx.debug.println("No built in list of Java packages to be exported " + "by the system bundle for JRE with version '" + jver + "', using the list for 1.7."); } jv = new Version(1,7,0); } } addSysPackagesFromFile(sp, "packages.txt", jv); } else { if (sp.charAt(sp.length() - 1) == ',') { sp.deleteCharAt(sp.length() - 1); } } addSysPackagesFromFile(sp, "exports", null); } } final String extraPkgs = fwCtx.props.getProperty(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA); if (extraPkgs.length() > 0) { sp.append(",").append(extraPkgs); } exportPackageString = sp.toString(); sp.setLength(0); sp.append(fwCtx.props.getProperty(Constants.FRAMEWORK_SYSTEMCAPABILITIES)); if (sp.length()==0) { // Derive osgi.ee capabilities from the EE header. addSysCapabilitiesFromEE(sp); } // Add in extra system capabilities final String epc = fwCtx.props.getProperty(Constants.FRAMEWORK_SYSTEMCAPABILITIES_EXTRA); if (epc.length()>0) { if (sp.length()>0) { sp.append(','); } sp.append(epc); } provideCapabilityString = sp.toString(); final BundleGeneration gen = new BundleGeneration(this, exportPackageString, provideCapabilityString); generations.add(gen); gen.bpkgs.registerPackages(); try { gen.bpkgs.resolvePackages(null); } catch (final BundleException _ignore) { // Shouldn't happend, hooks not active; } gen.setWired(); fwWiring = new FrameworkWiringImpl(fwCtx); } /** * */ void uninitSystemBundle() { bundleContext.invalidate(); bundleContext = null; if (!bootClassPathHasChanged) { for (final BundleGeneration bg : fwCtx.bundles.getFragmentBundles(current())) { if (bg.isBootClassPathExtension() && bg.bundle.extensionNeedsRestart()) { bootClassPathHasChanged = true; break; } } } } // // Private methods // /** * */ private void doInit() throws BundleException { state = STARTING; bootClassPathHasChanged = false; fwCtx.init(); } /** * Read a file with package names and add them to a stringbuffer. The file is * searched for in the current working directory, then on the class path. * Each line can have a java version guard at the end with format !VersionRange. * * @param sp Buffer to append the exports to. Same format as the * Export-Package manifest header. * @param sysPkgFile Name of the file to load packages to be exported from. * @param guard Version to test version guarded lines against. */ private void addSysPackagesFromFile(StringBuffer sp, String sysPkgFile, Version guard) { if (null == sysPkgFile || 0 == sysPkgFile.length()) { return; } if (fwCtx.debug.resolver) { fwCtx.debug.println("Will add system packages from file " + sysPkgFile); } URL url = null; final File f = new File(new File(sysPkgFile).getAbsolutePath()); if (!f.exists() || !f.isFile()) { url = SystemBundle.class.getResource(sysPkgFile); if (null == url) { url = SystemBundle.class.getResource("/" + sysPkgFile); } if (null == url) { if (fwCtx.debug.resolver) { fwCtx.debug.println("Could not add system bundle package exports from '" + sysPkgFile + "', file not found."); } } } BufferedReader in = null; try { Reader reader = null; String source = null; if (null == url) { reader = new FileReader(f); source = f.getAbsolutePath().toString(); } else { reader = new InputStreamReader(url.openStream()); source = url.toString(); } in = new BufferedReader(reader); if (fwCtx.debug.resolver) { fwCtx.debug.println("\treading from " + source); } String line; for (line = in.readLine(); line != null; line = in.readLine()) { line = line.trim(); if (line.length() > 0 && !line.startsWith("#")) { int idx = line.lastIndexOf('!'); if (idx != -1) { try { if (new VersionRange(line.substring(idx +1)).includes(guard)) { line = line.substring(0, idx); } else { // Not in version range skip. continue; } } catch (IllegalArgumentException _ignore) { } } if (sp.length() > 0) { sp.append(","); } sp.append(line); } } } catch (final IOException e) { throw new IllegalArgumentException("Failed to read " + sysPkgFile + ": " + e); } finally { try { in.close(); } catch (final Exception _ignore) { } } } /** * Create bundle capabilities in the {@code osgi.ee} name-space for all * execution environments that the framework supports. * * This method converts all BREEs defined using the framework environment * property {@code org.osgi.framework.executionenvironment} into * {@code osgi.ee}-capabilities. * *

A Bundle Required Execution Environment often on a from that matches: *

   * bree'  ::= n1 ( '-' v )? ( '/' n2 ( '-' v )? )?
   * 
* If it matches the BRWW will be transformed to an osgi.ee * capability with attributes as below: *
   *   osgi.ee = n1 ('/' n2 ) ; version:List<Version> = "v"
   *   osgi.ee = <ee name>
   * 
* If it does not match the {@code osgi.ee} attribute is set to the original * BREE value. * * BREE definitions for Java standard edition uses different names, "J2SE" and * "JavaSE" depending on the Java major version, but in * {@code osgi.ee}-capabilities the name shall be "JavaSE" independent of Java * release. * * @param sp string buffer with all framework provided capabilities to append * to. */ private void addSysCapabilitiesFromEE(StringBuffer sp) { final Map> eeNameVersions = new HashMap>(); @SuppressWarnings("deprecation") final String fwEE = fwCtx.props .getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT); if (fwEE!=null && fwEE.length()>0) { final String[] ees = Util.splitwords(fwEE, ","); for(final String ee : ees) { final String[] n1n2 = Util.splitwords(ee, "/"); switch (n1n2.length) { case 1: final String[] nv = Util.splitwords(ee, "-"); if (nv.length==2) { try { final Version v = new Version(nv[1]); addSysCapabilityEE(eeNameVersions, nv[0], v); } catch (final Exception e) { addSysCapabilityEE(eeNameVersions, ee, null); } } else { addSysCapabilityEE(eeNameVersions, ee, null); } break; case 2: final String[] n1v = Util.splitwords(n1n2[0], "-"); final String[] n2v = Util.splitwords(n1n2[1], "-"); try { final Version v1 = n1v.length==2 ? new Version(n1v[1]) : null; final Version v2 = n2v.length==2 ? new Version(n2v[1]) : null; final String n = n1v[0] +"/" +n2v[0]; if (v1 != null && v2 != null && v1.equals(v2)) { addSysCapabilityEE(eeNameVersions, n, v1); } else if (v1!=null && v2==null) { addSysCapabilityEE(eeNameVersions, n, v1); } else if (v1==null && v2!=null) { addSysCapabilityEE(eeNameVersions, n, v2); } else { addSysCapabilityEE(eeNameVersions, ee, null); } } catch (final Exception e) { addSysCapabilityEE(eeNameVersions, ee, null); } break; default: addSysCapabilityEE(eeNameVersions, ee, null); } } } addSysCapabilityForEE(sp, eeNameVersions); } private void addSysCapabilityEE(final Map> eeNameVersions, String name, final Version v) { if ("J2SE".equals(name)) { name = "JavaSE"; } SortedSet versions = eeNameVersions.get(name); if (versions==null) { versions = new TreeSet(); eeNameVersions.put(name, versions); } if (v !=null) { versions.add(v); } } private void addSysCapabilityForEE(final StringBuffer sb, final Map> eeNameVersions) { for (final Entry> entry : eeNameVersions .entrySet()) { if (sb.length() > 0) { sb.append(','); } sb.append(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE); sb.append(';'); sb.append(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE); sb.append('='); sb.append(entry.getKey()); if (!entry.getValue().isEmpty()) { sb.append(";version:List=\""); for (final Version v : entry.getValue()) { sb.append(v.toString()); sb.append(','); } sb.setCharAt(sb.length() - 1, '"'); } } } /** * This method start a thread that stop this Framework, stopping all started * bundles. * *

* If the framework is not started, this method does nothing. If the framework * is started, this method will: *

    *
  1. Set the state of the FrameworkContext to inactive.
  2. *
  3. Suspended all started bundles as described in the * {@link Bundle#stop(int)} method except that the persistent state of the * bundle will continue to be started. Reports any exceptions that occur * during stopping using FrameworkErrorEvents.
  4. *
  5. Disable event handling.
  6. *
*

* */ void shutdown(final boolean restart) { synchronized (lock) { boolean wasActive = false; switch (state) { case Bundle.INSTALLED: case Bundle.RESOLVED: shutdownDone(false); break; case Bundle.ACTIVE: wasActive = true; // Fall through case Bundle.STARTING: if (shutdownThread == null) { try { final boolean wa = wasActive; shutdownThread = new Thread(fwCtx.threadGroup, "Framework shutdown") { @Override public void run() { shutdown0(restart, wa); } }; shutdownThread.setDaemon(false); shutdownThread.start(); } catch (final Exception e) { systemShuttingdownDone(new FrameworkEvent(FrameworkEvent.ERROR, this, e)); } } break; case Bundle.STOPPING: // Shutdown already inprogress break; } } } /** * Stop this FrameworkContext, suspending all started contexts. This method * suspends all started contexts so that they can be automatically restarted * when this FrameworkContext is next launched. * *

* If the framework is not started, this method does nothing. If the framework * is started, this method will: *

    *
  1. Set the state of the FrameworkContext to inactive.
  2. *
  3. Stop all started bundles as described in the {@link Bundle#stop(int)} * method except that the persistent state of the bundle will continue to be * started. Reports any exceptions that occur during stopping using * FrameworkErrorEvents.
  4. *
  5. Disable event handling.
  6. *
*

* */ private void shutdown0(final boolean restart, final boolean wasActive) { try { synchronized (lock) { waitOnOperation(lock, "Framework." + (restart ? "update" : "stop"), true); operation = DEACTIVATING; state = STOPPING; } fwCtx.listeners.bundleChanged(new BundleEvent(BundleEvent.STOPPING, this)); if (wasActive) { stopAllBundles(); saveClasspaths(); } synchronized (lock) { fwCtx.uninit(); shutdownThread = null; shutdownDone(restart); } if (restart) { if (wasActive) { start(); } else { init(); } } } catch (final Exception e) { shutdownThread = null; systemShuttingdownDone(new FrameworkEvent(FrameworkEvent.ERROR, this, e)); } } /** * Tell system bundle shutdown finished. */ private void shutdownDone(boolean restart) { int t; if (bootClassPathHasChanged) { t = FrameworkEvent.STOPPED_BOOTCLASSPATH_MODIFIED; } else { t = restart ? FrameworkEvent.STOPPED_UPDATE : FrameworkEvent.STOPPED; } systemShuttingdownDone(new FrameworkEvent(t, this, null)); } /** * Stop and unresolve all bundles. */ private void stopAllBundles() { if (fwCtx.startLevelController != null) { fwCtx.startLevelController.shutdown(); } // Stop all active bundles, in reverse bundle ID order // The list will be empty when the start level service is in use. final List activeBundles = fwCtx.bundles.getActiveBundles(); for (int i = activeBundles.size() - 1; i >= 0; i--) { final BundleImpl b = activeBundles.get(i); try { if (((Bundle.ACTIVE | Bundle.STARTING) & b.getState()) != 0) { // Stop bundle without changing its autostart setting. b.stop(Bundle.STOP_TRANSIENT); } } catch (final BundleException be) { fwCtx.frameworkError(b, be); } } final List allBundles = fwCtx.bundles.getBundles(); // Set state to INSTALLED and purge any unrefreshed bundles for (final BundleImpl bundleImpl : allBundles) { final BundleImpl b = bundleImpl; if (b.getBundleId() != 0) { b.setStateInstalled(false); b.purge(); } } } private void saveClasspaths() { final StringBuffer bootClasspath = new StringBuffer(); for (final BundleGeneration bundleGeneration : fwCtx.bundles.getFragmentBundles(current())) { final BundleGeneration ebg = bundleGeneration; final String path = ebg.archive.getJarLocation(); if (ebg.isBootClassPathExtension()) { if (bootClasspath.length() > 0) { bootClasspath.append(File.pathSeparator); } bootClasspath.append(path); } } // Post processing to handle boot class extension try { final File bcpf = new File(Util.getFrameworkDir(fwCtx), BOOT_CLASSPATH_FILE); if (bootClasspath.length() > 0) { saveStringBuffer(bcpf, bootClasspath); } else { bcpf.delete(); } } catch (final IOException e) { if (fwCtx.debug.errors) { fwCtx.debug.println("Could not save classpath " + e); } } } private void saveStringBuffer(File f, StringBuffer content) throws IOException { PrintStream out = null; try { out = new PrintStream(new FileOutputStream(f)); out.println(content.toString()); } finally { if (out != null) { out.close(); } } } private void addClassPathURL(URL url) throws Exception { final ClassLoader cl = getClassLoader(); Method m = Util.getMethod(cl.getClass(), "addURL", new Class[] { URL.class }); if (m != null) { m.invoke(cl, new Object[] { url }); } else { throw new NoSuchMethodException("addURL"); } } /** * If the extension has an extension activator header process it. * * @param extension the extension bundle to process. */ private void handleExtensionActivator(final BundleGeneration extension) { String extActivatorName = extension.archive.getAttribute("Extension-Activator"); extActivatorName = null!=extActivatorName ? extActivatorName.trim() : null; if (null!=extActivatorName && extActivatorName.length()>0) { fwCtx.log("Activating extension: " + extension.symbolicName + ":" +extension.version + " using: " +extActivatorName); fwCtx.activateExtension(extension); } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/FrameworkContext.java0000644000175000017500000006152112346513666031337 0ustar felixfelix/* * Copyright (c) 2003-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.knopflerfish.framework.Util.HeaderEntry; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; import org.osgi.framework.FrameworkEvent; import org.osgi.framework.FrameworkListener; /** * This class contains references to all common data structures * inside the framework. * * @author Jan Stein, Erik Wistrand, Philippe Laporte, * Mats-Ola Persson, Gunnar Ekolin */ public class FrameworkContext { private static final String CONDITIONAL_PERMISSION_SECURITY_MANAGER = "org.knopflerfish.framework.permissions.ConditionalPermissionSecurityManager"; private static final String KF_SECURITY_MANAGER = "org.knopflerfish.framework.permissions.KFSecurityManager"; private static final String SECURE_PERMISSON_OPS = "org.knopflerfish.framework.SecurePermissionOps"; /** * Debug handle. */ public Debug debug; /** * All bundle in this framework. */ Bundles bundles; /** * All listeners in this framework. */ Listeners listeners; /** * All service hooks. */ ServiceHooks serviceHooks; /** * All bundle hooks. */ BundleHooks bundleHooks; /** * All resolver hooks. */ ResolverHooks resolverHooks; /** * All weaving hooks. */ WeavingHooks weavingHooks; /** * All capabilities, exported and imported packages in this framework. */ Resolver resolver; /** * All registered services in this framework. */ Services services; /** * PermissionOps handle. */ PermissionOps perm; /** * System bundle */ SystemBundle systemBundle; /** * Bundle Storage */ BundleStorage storage; /** * Bundle Validator */ List validator = null; /** * Private Bundle Data Storage */ FileTree dataStorage /*= null*/; /** * The start level controller. */ StartLevelController startLevelController; /** * Factory for handling service-based URLs */ ServiceURLStreamHandlerFactory urlStreamHandlerFactory; /** * Factory for handling service-based URL contents */ ServiceContentHandlerFactory contentHandlerFactory; /** * Patterns from the boot delegation property. */ ArrayList bootDelegationPatterns; boolean bootDelegationUsed /*= false*/; /** * The parent class loader for bundle classloaders. */ ClassLoader parentClassLoader; /** * All bundle in this framework. */ boolean firstInit = true; /** * Framework id. */ final int id; /** * Framework init count. */ int initCount = 0; /** * Framework properties. */ public FWProps props; /** * Framework Thread Group. */ public ThreadGroup threadGroup; /** * Threads for running listeners and activators */ LinkedList bundleThreads; /** * Package admin handle */ PackageAdminImpl packageAdmin = null; /** * Mode for BSN collision checks. */ String bsnversionMode; /** * Factory for handling service-based URLs */ volatile static ServiceURLStreamHandlerFactory systemUrlStreamHandlerFactory; /** * Factory for handling service-based URL contents */ volatile static ServiceContentHandlerFactory systemContentHandlerFactory; /** * JVM global lock. */ static Object globalFwLock = new Object(); /** * Id to use for next instance of KF framework. */ static int globalId = 0; /** * Reference counter for security manager. */ static int smUse = 0; static void setupURLStreamHandleFactory() { ServiceURLStreamHandlerFactory res = new ServiceURLStreamHandlerFactory(); try { URL.setURLStreamHandlerFactory(res); systemUrlStreamHandlerFactory = res; } catch (final Throwable e) { System.err.println("Cannot set global URL handlers, " +"continuing without OSGi service URL handler (" +e +")"); } } /** * Contruct a framework context * */ FrameworkContext(Map initProps) { synchronized (globalFwLock) { id = globalId++; } threadGroup = new ThreadGroup("FW#" + id); props = new FWProps(initProps, this); perm = new PermissionOps(); systemBundle = new SystemBundle(this); log("created"); } /** * Public method used by permissionshandling for fetching * the class loader used for named class. * */ public ClassLoader getClassLoader(String clazz) { if (clazz != null) { final int pos = clazz.lastIndexOf('.'); if (pos != -1) { final Pkg p = resolver.getPkg(clazz.substring(0, pos)); if (p != null) { final ExportPkg ep = p.getBestProvider(); if (ep != null) { return ep.bpkgs.bg.getClassLoader(); } } } } return systemBundle.getClassLoader(); } /** * Initialize the framework, see spec v4.2 sec 4.2.4 * */ void init() { log("initializing"); initCount++; if (firstInit && Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT .equals(props.getProperty(Constants.FRAMEWORK_STORAGE_CLEAN))) { deleteFWDir(); firstInit = false; } buildBootDelegationPatterns(); selectBootDelegationParentClassLoader(); if (setSecurityManager()) { perm = (PermissionOps) doNew(SECURE_PERMISSON_OPS); systemBundle.secure = perm; } perm.init(); final String v = props.getProperty(FWProps.VALIDATOR_PROP); if (!v.equalsIgnoreCase("none") && !v.equalsIgnoreCase("null")) { validator = new ArrayList(); for (int start = 0; start < v.length(); ) { int end = v.indexOf(',', start); if (end == -1) { end = v.length(); } final String vs = "org.knopflerfish.framework.validator." + v.substring(start, end).trim(); validator.add((Validator) doNew(vs)); start = end + 1; } } if (null == urlStreamHandlerFactory) { // Set up URL handlers before creating the storage // implementation, with the exception of the bundle: URL // handler, since this requires an intialized framework to work if (props.REGISTERSERVICEURLHANDLER) { // Check if we already have registered one if (systemUrlStreamHandlerFactory == null) { setupURLStreamHandleFactory(); } urlStreamHandlerFactory = systemUrlStreamHandlerFactory; if (systemContentHandlerFactory != null) { contentHandlerFactory = systemContentHandlerFactory; } else { contentHandlerFactory = new ServiceContentHandlerFactory(this); try { URLConnection.setContentHandlerFactory(contentHandlerFactory); systemContentHandlerFactory = contentHandlerFactory; } catch (final Throwable e) { debug.printStackTrace ("Cannot set global content handlers, " +"continuing without OSGi service content handler (" +e +")", e); } } } else { urlStreamHandlerFactory = new ServiceURLStreamHandlerFactory(); contentHandlerFactory = new ServiceContentHandlerFactory(this); } } props.props.put(Constants.FRAMEWORK_UUID, getUUID()); String bsnProp = props.getProperty(Constants.FRAMEWORK_BSNVERSION).trim().toLowerCase(); if (bsnProp.equals(Constants.FRAMEWORK_BSNVERSION_MANAGED) || bsnProp.equals(Constants.FRAMEWORK_BSNVERSION_MULTIPLE) || bsnProp.equals(Constants.FRAMEWORK_BSNVERSION_SINGLE)) { bsnversionMode = bsnProp; } else { bsnversionMode = Constants.FRAMEWORK_BSNVERSION_MANAGED; debug.println("Unknown property value: " + Constants.FRAMEWORK_BSNVERSION + " = " + bsnProp); } final String storageClass = "org.knopflerfish.framework.bundlestorage." + props.getProperty(FWProps.BUNDLESTORAGE_PROP) + ".BundleStorageImpl"; try { @SuppressWarnings("unchecked") final Class storageImpl = (Class) Class.forName(storageClass); final Constructor cons = storageImpl.getConstructor(new Class[] { FrameworkContext.class }); storage = cons.newInstance(new Object[] { this }); } catch (final Exception e) { Throwable cause = e; if (e instanceof InvocationTargetException) { // Use the nested exception as cause in this case. cause = ((InvocationTargetException)e).getTargetException(); } throw new RuntimeException("Failed to initialize storage " + storageClass, cause); } if (props.getBooleanProperty(FWProps.READ_ONLY_PROP)) { dataStorage = null; } else { dataStorage = Util.getFileStorage(this, "data"); } BundleThread.checkWarnStopActionNotSupported(this); bundleThreads = new LinkedList(); resolver = new Resolver(this); listeners = new Listeners(this, perm); services = new Services(this, perm); // Add this framework to the bundle URL handle urlStreamHandlerFactory.addFramework(this); serviceHooks = new ServiceHooks(this); bundleHooks = new BundleHooks(this); resolverHooks = new ResolverHooks(this); weavingHooks = new WeavingHooks(this); systemBundle.initSystemBundle(); bundles = new Bundles(this); serviceHooks.open(); resolverHooks.open(); weavingHooks.open(); perm.registerService(); packageAdmin = new PackageAdminImpl(this); @SuppressWarnings("deprecation") final String[] classes = new String [] { org.osgi.service.packageadmin.PackageAdmin.class.getName() }; services.register(systemBundle, classes, packageAdmin, null); registerStartLevel(); bundles.load(); log("inited"); log("Installed bundles:"); // Use the ordering in the bundle storage to get a sorted list of bundles. final BundleArchive [] allBAs = storage.getAllBundleArchives(); for (final BundleArchive ba : allBAs) { final Bundle b = bundles.getBundle(ba.getBundleLocation()); log(" #" +b.getBundleId() +" " +b.getSymbolicName() +":" +b.getVersion() +" location:" +b.getLocation()); } } private Object doNew(final String clazz) { try { final Class n = (Class) Class.forName(clazz); final Constructor nc = n.getConstructor(new Class[] { FrameworkContext.class }); return nc.newInstance(new Object[] { this }); } catch (final InvocationTargetException ite) { throw new RuntimeException(clazz + ", constructor failed with, " + ite.getTargetException(), ite); } catch (final NoSuchMethodException e) { // If no validator, probably stripped framework throw new RuntimeException(clazz + ", found no such class", e); } catch (final NoClassDefFoundError ncdfe) { // Validator uses class not supported by JVM ignore throw new RuntimeException(clazz + ", class not supported by JVM", ncdfe); } catch (final Exception e) { throw new RuntimeException(clazz + ", constructor failed", e); } } /** * Undo as much as possible of what init() does. * */ void uninit() { log("uninit"); startLevelController = null; systemBundle.uninitSystemBundle(); resolverHooks = null; if(props.REGISTERSERVICEURLHANDLER) { urlStreamHandlerFactory.removeFramework(this); // Since handlers can only be registered once, keep them in this // case. } else { urlStreamHandlerFactory = null; contentHandlerFactory = null; } bundles.clear(); bundles = null; services.clear(); services = null; listeners.clear(); listeners = null; resolver.clear(); resolver = null; synchronized (bundleThreads) { while (!bundleThreads.isEmpty()) { bundleThreads.remove(0).quit(); } } bundleThreads = null; dataStorage = null; storage.close(); storage = null; perm = new PermissionOps(); synchronized (globalFwLock) { if (--smUse == 0) { System.setSecurityManager(null); } } parentClassLoader = null; bootDelegationPatterns = null; } /** * Check and/or set security manager. * */ private boolean setSecurityManager() { synchronized (globalFwLock) { SecurityManager current = System.getSecurityManager(); final String osgiSecurity = props.getProperty(Constants.FRAMEWORK_SECURITY); if (osgiSecurity.length() > 0) { if (!Constants.FRAMEWORK_SECURITY_OSGI.equals(osgiSecurity)) { throw new SecurityException("Unknown OSGi security, " + osgiSecurity); } if (current == null) { final String POLICY_PROPERTY = "java.security.policy"; final String defaultPolicy = this.getClass().getResource("/framework.policy").toString(); final String policy = System.getProperty(POLICY_PROPERTY, defaultPolicy); if (debug.framework) { debug.println("Installing OSGi security manager, policy="+policy); } System.setProperty(POLICY_PROPERTY, policy); // Make sure policy is updated, required for some JVMs. java.security.Policy.getPolicy().refresh(); current = (SecurityManager) doNew(KF_SECURITY_MANAGER); System.setSecurityManager(current); smUse = 1; } else { Class cpsmc; try { cpsmc = Class.forName(CONDITIONAL_PERMISSION_SECURITY_MANAGER); } catch (ClassNotFoundException e) { throw new RuntimeException("Missing class", e); } if (cpsmc.isInstance(current)) { if (smUse == 0) { smUse = 2; } else { smUse++; } } else { throw new SecurityException("Incompatible security manager installed"); } } } return current != null; } } /** * Delete framework directory if it exists. * */ private void deleteFWDir() { final String d = Util.getFrameworkDir(this); final FileTree dir = (d != null) ? new FileTree(d) : null; if (dir != null) { if(dir.exists()) { log("deleting old framework directory."); final boolean bOK = dir.delete(); if(!bOK) { debug.println("Failed to remove existing fwdir " +dir.getAbsolutePath()); } } } } private String getUUID() { // We use a "pseudo" random UUID (Version 4). final String sid = Integer.toHexString(id * 65536 + initCount); final String baseUUID = "4e524769-3136-4b46-8000-00000000"; return baseUUID.substring(0, baseUUID.length() - sid.length()) + sid; } /** * Setup start level service, if enabled. * */ private void registerStartLevel() { if (props.getBooleanProperty(FWProps.STARTLEVEL_USE_PROP)) { if (debug.startlevel) { debug.println("[using startlevel service]"); } startLevelController = new StartLevelController(this); // restoreState just reads from persistent storage // open() needs to be called to actually do the work // This is done after framework has been launched. startLevelController.restoreState(); @SuppressWarnings("deprecation") final String [] clsName = new String [] { org.osgi.service.startlevel.StartLevel.class.getName() }; services.register(systemBundle, clsName, startLevelController, null); } } /** * Get private bundle data storage file handle. * */ public FileTree getDataStorage(long id) { if (dataStorage != null) { return new FileTree(dataStorage, Long.toString(id)); } return null; } /** * Check that bundle belongs to this framework instance. * */ void checkOurBundle(Bundle b) { if (b == null || !(b instanceof BundleImpl) || this != ((BundleImpl)b).fwCtx) { throw new IllegalArgumentException("Bundle does not belong to this framework: " + b); } } /** * Parse boot-delegation pattern property. * */ void buildBootDelegationPatterns() { final String bootDelegationString = props.getProperty(Constants.FRAMEWORK_BOOTDELEGATION); bootDelegationUsed = bootDelegationString.length() > 0; bootDelegationPatterns = new ArrayList(1); if (bootDelegationUsed) { try { for (final HeaderEntry he : Util .parseManifestHeader(Constants.FRAMEWORK_BOOTDELEGATION, bootDelegationString, true, true, false)) { final String key = he.getKey(); if (key.equals("*")) { bootDelegationPatterns = null; //in case funny person puts a * amongst other things break; } else if (key.endsWith(".*")) { bootDelegationPatterns.add(key.substring(0, key.length() - 1)); } else if (key.endsWith(".")) { frameworkError(systemBundle, new IllegalArgumentException (Constants.FRAMEWORK_BOOTDELEGATION +" entry ends with '.': " +key)); } else if (key.indexOf("*") != - 1) { frameworkError(systemBundle, new IllegalArgumentException (Constants.FRAMEWORK_BOOTDELEGATION +" entry contains a '*': " + key)); } else { bootDelegationPatterns.add(key); } } } catch (final IllegalArgumentException e) { debug.printStackTrace("Failed to parse " + Constants.FRAMEWORK_BOOTDELEGATION, e); } } } /** * Check if named resource is matched by the bootdelegation pattern * */ boolean isBootDelegatedResource(String name) { // Convert resource name to class name format, preserving the // package part of the path/name. final int pos = name.lastIndexOf('/'); return pos != -1 ? isBootDelegated(name.substring(0,pos).replace('/','.')+".X") : false; } /** * Check if named class is matched by the bootdelegation pattern * */ boolean isBootDelegated(String className){ if(!bootDelegationUsed){ return false; } if (bootDelegationPatterns == null) { return true; } final int pos = className.lastIndexOf('.'); if (pos != -1) { final String classPackage = className.substring(0, pos); for (final String ps : bootDelegationPatterns) { if ((ps.endsWith(".") && classPackage.regionMatches(0, ps, 0, ps.length() - 1)) || classPackage.equals(ps)) { return true; } } } return false; } /** * Select the parent class loader,to be used by bundle classloaders. * */ private void selectBootDelegationParentClassLoader() { final String s = props.getProperty(Constants.FRAMEWORK_BUNDLE_PARENT); if (Constants.FRAMEWORK_BUNDLE_PARENT_EXT.equals(s)) { parentClassLoader = ClassLoader.getSystemClassLoader(); if (parentClassLoader != null) { parentClassLoader = parentClassLoader.getParent(); } } else if (Constants.FRAMEWORK_BUNDLE_PARENT_APP.equals(s)) { parentClassLoader = ClassLoader.getSystemClassLoader(); } else if (Constants.FRAMEWORK_BUNDLE_PARENT_FRAMEWORK.equals(s)) { parentClassLoader = this.getClass().getClassLoader(); } else { parentClassLoader = Object.class.getClassLoader(); } // If bootclassloader, wrap it if (parentClassLoader == null) { parentClassLoader = new BCLoader(); } } /** * The list of active {@link ExtensionContext} instances for attached * extensions with an ExtensionActivator. */ private final List extCtxs = new ArrayList(); /** * Create a new {@link ExtensionContext} instances for the specified * extension. This will create an instance of the extension * activator class and call its activate-method of. * * @param extension the extension bundle to activate. */ void activateExtension(final BundleGeneration extension) { extCtxs.add( new ExtensionContext(this, extension) ); } /** * Inform all active extension contexts about a newly created bundle * class loader. * * @param bcl the new bundle class loader to inform about. */ void bundleClassLoaderCreated(final BundleClassLoader bcl) { for (final ExtensionContext extCtx : extCtxs) { extCtx.bundleClassLoaderCreated(bcl); } } /** * Inform all active extension contexts about a closed down bundle * class loader. * * @param bcl the closed down bundle class loader to inform about. */ void bundleClassLoaderClosed(final BundleClassLoader bcl) { for (final ExtensionContext extCtx : extCtxs) { extCtx.bundleClassLoaderClosed(bcl); } } /** * Convenience method for throwing framework error event. * * @param b Bundle which caused the error. * @param t Throwable generated. */ public void frameworkError(Bundle b, Throwable t, FrameworkListener... oneTimeListeners) { listeners.frameworkEvent(new FrameworkEvent(FrameworkEvent.ERROR, b, t), oneTimeListeners); } /** * Convenience method for throwing framework error event. * * @param bc BundleContext for bundle which caused the error. * @param t Throwable generated. */ public void frameworkError(BundleContextImpl bc, Throwable t, FrameworkListener... oneTimeListeners) { listeners.frameworkEvent(new FrameworkEvent(FrameworkEvent.ERROR, bc.bundle, t), oneTimeListeners); } /** * Convenience method for throwing framework info event. * * @param b Bundle which caused the throwable. * @param t Throwable generated. */ public void frameworkInfo(Bundle b, Throwable t, FrameworkListener... oneTimeListeners) { listeners.frameworkEvent(new FrameworkEvent(FrameworkEvent.INFO, b, t), oneTimeListeners); } /** * Convenience method for throwing framework warning event. * * @param b Bundle which caused the throwable. * @param t Throwable generated. */ public void frameworkWarning(Bundle b, Throwable t, FrameworkListener... oneTimeListeners) { listeners.frameworkEvent(new FrameworkEvent(FrameworkEvent.WARNING, b, t), oneTimeListeners); } /** * Convenience method for throwing framework warning event. * * @param b Bundle which caused the throwable. * @param t Throwable generated. */ public void frameworkWarning(BundleGeneration bg, Throwable t, FrameworkListener... oneTimeListeners) { frameworkWarning(bg.bundle, t, oneTimeListeners); } /** * Log message for debugging framework * */ void log(String msg) { if (debug.framework) { debug.println("Framework instance " +hashCode() +": " +msg); } } /** * Log message for debugging framework * */ void log(String msg, Throwable t) { if (debug.framework) { debug.printStackTrace("Framework instance " +hashCode() +": " +msg, t); } } /** * Wrapper class for BootClassLoader. * */ private static class BCLoader extends ClassLoader { protected BCLoader() { super(null); } } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/URLStreamHandlerWrapper.java0000644000175000017500000002367312346513666032520 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.IOException; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.util.ArrayList; import org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.osgi.service.url.URLConstants; import org.osgi.service.url.URLStreamHandlerService; import org.osgi.service.url.URLStreamHandlerSetter; /** * Wrapper which delegates an URL protocol to * OSGi URLStreamHandlerServices. * *

* Each instance of URLStreamHandlerWrapper tracks URLStreamHandlerServices * for a named protocol and selects the best from all available services. *

*/ public class URLStreamHandlerWrapper extends URLStreamHandler implements URLStreamHandlerSetter { ArrayList framework = new ArrayList(2); final String protocol; final String filter; final ServiceListener serviceListener; private ServiceReference best; private URLStreamHandlerService bestService; private FrameworkContext currentFw; URLStreamHandlerWrapper(final FrameworkContext fw, final String proto) { protocol = proto; filter = "(&(" + Constants.OBJECTCLASS + "=" + URLStreamHandlerService.class.getName() + ")" + "(" + URLConstants.URL_HANDLER_PROTOCOL + "=" + protocol + "))"; serviceListener = new ServiceListener() { synchronized public void serviceChanged(ServiceEvent evt) { @SuppressWarnings("unchecked") final ServiceReference ref = (ServiceReference) evt.getServiceReference(); final FrameworkContext fw = ((BundleImpl)ref.getBundle()).fwCtx; if (fw == currentFw) { switch (evt.getType()) { case ServiceEvent.MODIFIED: // fall through case ServiceEvent.REGISTERED: if (best != null && best.compareTo(ref) < 0) { best = ref; bestService = null; } break; case ServiceEvent.MODIFIED_ENDMATCH: // fall through case ServiceEvent.UNREGISTERING: if (best != null && best.equals(ref)) { best = null; bestService = null; } } } } }; framework.add(fw); try { fw.systemBundle.bundleContext.addServiceListener(serviceListener, filter); } catch (final InvalidSyntaxException e) { throw new IllegalArgumentException("Protocol name contains illegal characters: " + proto); } if (fw.debug.url) { fw.debug.println("created wrapper for " + protocol + ", filter=" + filter + ", " + toString()); } } /** * */ void addFramework(FrameworkContext fw) { try { fw.systemBundle.bundleContext.addServiceListener(serviceListener, filter); framework.add(fw); if (fw.debug.url) { fw.debug.println("created wrapper for " + protocol + ", filter=" + filter + ", " + toString()); } } catch (final InvalidSyntaxException _no) { } } /** * */ boolean removeFramework(FrameworkContext fw) { framework.remove(fw); return framework.isEmpty(); } /** * */ private URLStreamHandlerService getService() { FrameworkContext fw; if (framework.size() == 1) { fw = framework.get(0); } else { // Get current FrameworkContext throw new RuntimeException("NYI - walk stack to get framework"); } synchronized (serviceListener) { if (best == null) { try { @SuppressWarnings("unchecked") final ServiceReference[] refs = (ServiceReference[]) fw.systemBundle.bundleContext.getServiceReferences(URLStreamHandlerService.class.getName(), filter); if (refs != null) { // KF gives us highest ranked first. best = refs[0]; } } catch (final InvalidSyntaxException _no) { } } if (best == null) { throw new IllegalStateException("null: Lost service for protocol="+ protocol); } if (bestService == null) { bestService = fw.systemBundle.bundleContext.getService(best); } if (bestService == null) { throw new IllegalStateException("null: Lost service for protocol=" + protocol); } currentFw = fw; return bestService; } } /** * */ @Override public boolean equals(URL u1, URL u2) { return getService().equals(u1, u2); } /** * */ @Override protected int getDefaultPort() { return getService().getDefaultPort(); } /** * */ @Override protected InetAddress getHostAddress(URL u) { return getService().getHostAddress(u); } /** * */ @Override protected int hashCode(URL u) { return getService().hashCode(u); } /** * */ @Override protected boolean hostsEqual(URL u1, URL u2) { return getService().hostsEqual(u1, u2); } /** * */ @Override protected URLConnection openConnection(URL u) throws IOException { try { return getService().openConnection(u); } catch(final IllegalStateException e) { throw new MalformedURLException(e.getMessage()); } } /** * */ @Override protected void parseURL(URL u, String spec, int start, int limit) { getService().parseURL(this, u, spec, start, limit); } /** * */ @Override protected boolean sameFile(URL u1, URL u2) { return getService().sameFile(u1, u2); } /** * This method is deprecated, but wrap it in the same * way as JSDK1.4 wraps it. */ @Override public void setURL(URL u, String protocol, String host, int port, String file, String ref) { // parse host as "user:passwd@host" String authority = null; String userInfo = null; if (host != null && host.length() != 0) { authority = (port == -1) ? host : host + ":" + port; final int ix = host.lastIndexOf('@'); if (ix != -1) { userInfo = host.substring(0, ix); host = host.substring(ix+1); } } // Parse query part from file ending with '?' String path = null; String query = null; if (file != null) { final int ix = file.lastIndexOf('?'); if (ix != -1) { query = file.substring(ix + 1); path = file.substring(0, ix); } else { path = file; } } setURL(u, protocol, host, port, authority, userInfo, path, query, ref); } @Override public void setURL(URL u, String protocol, String host, int port, String authority, String userInfo, String path, String query, String ref) { super .setURL(u, protocol, host, port, authority, userInfo, path, query, ref); } @Override protected String toExternalForm(URL u) { return getService().toExternalForm(u); } @Override public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("URLStreamHandlerWrapper["); final ServiceReference ref = best; sb.append("protocol=" + protocol); // sb.append(", size=" + tracker.size()); if(ref != null) { sb.append(", id=" + ref.getProperty(Constants.SERVICE_ID)); sb.append(", rank=" + ref.getProperty(Constants.SERVICE_RANKING)); // ServiceReference[] srl = tracker.getServiceReferences(); // for(int i = 0; srl != null && i < srl.length; i++) { // sb.append(", {"); // sb.append("id=" + srl[i].getProperty(Constants.SERVICE_ID)); // sb.append(", rank=" + srl[i].getProperty(Constants.SERVICE_RANKING)); // String[] sa = (String[])srl[i].getProperty(URLConstants.URL_HANDLER_PROTOCOL); // sb.append(", proto="); // for(int j = 0; j < sa.length; j++) { // sb.append(sa[j]); // if(j < sa.length - 1) { // sb.append(", "); // } // } // sb.append("}"); // } } else { sb.append(" no service tracked"); } sb.append("]"); return sb.toString(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/PermissionOps.java0000644000175000017500000002314612346513666030650 0ustar felixfelix/* * Copyright (c) 2006-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.security.AccessControlContext; import java.security.ProtectionDomain; import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; import java.util.Vector; import org.osgi.framework.Bundle; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleException; import org.osgi.framework.FrameworkListener; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceReference; /** * This is a wrapper class for operations that requires some kind of security * checks or privileged operations. */ class PermissionOps { void init() { } void registerService() { } boolean checkPermissions() { return false; } // // Permission checks // boolean okClassAdminPerm(Bundle b) { return true; } void checkExecuteAdminPerm(Bundle b) { } void checkExtensionLifecycleAdminPerm(Bundle b) { } void checkExtensionLifecycleAdminPerm(Bundle b, Object checkContext) { } void checkLifecycleAdminPerm(Bundle b) { } void checkLifecycleAdminPerm(Bundle b, Object checkContext) { } void checkListenerAdminPerm(Bundle b) { } void checkMetadataAdminPerm(Bundle b) { } void checkResolveAdminPerm() { } void checkResourceAdminPerm(Bundle b) { } boolean okResourceAdminPerm(Bundle b) { return true; } void checkContextAdminPerm(Bundle b) { } void checkStartLevelAdminPerm() { } void checkGetProtectionDomain() { } void checkWeaveAdminPerm(Bundle b) { } // // Bundle permission checks // boolean okFragmentBundlePerm(BundleImpl b) { return true; } boolean okHostBundlePerm(BundleImpl b) { return true; } boolean okProvideBundlePerm(BundleImpl b) { return true; } boolean okRequireBundlePerm(BundleImpl b) { return true; } boolean okAllPerm(BundleImpl b) { return true; } // // Package permission checks // boolean hasExportPackagePermission(ExportPkg ep) { return true; } boolean hasImportPackagePermission(BundleImpl b, ExportPkg ep) { return true; } // // Service permission checks // void checkRegisterServicePerm(String clazz) { } void checkGetServicePerms(ServiceReference sr) { } boolean okGetServicePerms(ServiceReference sr) { return true; } void filterGetServicePermission(Set> srs) { } // // Capability and Requirement checks // boolean hasProvidePermission(BundleCapabilityImpl bc) { return true; } boolean hasRequirePermission(BundleRequirementImpl br) { return true; } boolean hasRequirePermission(BundleRequirementImpl br, BundleCapabilityImpl bc) { return true; } // // AdaptPermission checks //
void checkAdaptPerm(BundleImpl b, Class type) { } // // BundleArchive secure operations // BundleResourceStream callGetBundleResourceStream(final BundleArchive archive, final String name, final int ix) { return archive.getBundleResourceStream(name, ix); } Enumeration callFindResourcesPath(final BundleArchive archive, final String path) { return archive.findResourcesPath(path); } // // BundleClassLoader secure operations // Object callSearchFor(final BundleClassLoader cl, final String name, final String pkg, final String path, final BundleClassLoader.SearchAction action, final int options, final BundleClassLoader requestor, final HashSet visited) { return cl.searchFor(name, pkg, path, action, options, requestor, visited); } String callFindLibrary0(final BundleClassLoader cl, final String name) { return cl.findLibrary0(name); } // // BundleImpl secure operations // void callFinalizeActivation(final BundleImpl b) throws BundleException { b.finalizeActivation(); } BundleThread createBundleThread(final FrameworkContext fc) { return new BundleThread(fc); } void callUpdate0(final BundleImpl b, final InputStream in, final boolean wasActive) throws BundleException { b.update0(in, wasActive, null); } void callUninstall0(final BundleImpl b) { b.uninstall0(); } void callSetAutostartSetting(final BundleImpl b, final int setting) { b.setAutostartSetting0(setting); } HeaderDictionary callGetHeaders0(final BundleGeneration bg, final String locale) { return bg.getHeaders0(locale); } Vector callFindEntries(final BundleGeneration bg, final String path, final String filePattern, final boolean recurse) { return bg.findEntries(path, filePattern, recurse); } BundleClassLoader newBundleClassLoader(final BundleGeneration bg) throws BundleException { return new BundleClassLoader(bg); } Vector getBundleClassPathEntries(final BundleGeneration bg, final String name, final boolean onlyFirst) { return bg.getBundleClassPathEntries(name, onlyFirst); } AccessControlContext getAccessControlContext(BundleImpl bundle) { return null; } // // Bundles Secure operation // BundleImpl callInstall0(final Bundles bs, final String location, final InputStream in, final Bundle caller) throws BundleException { return bs.install0(location, in, null, caller); } // // Listeners Secure operations // void callBundleChanged(final FrameworkContext fwCtx, final BundleEvent evt) { fwCtx.listeners.bundleChanged(evt); } void callServiceChanged(final FrameworkContext fwCtx, final Collection receivers, final ServiceEvent evt, final Set matchBefore) { fwCtx.listeners.serviceChanged(receivers, evt, matchBefore); } // // PackageAdmin secure operations // void callRefreshPackages0(final PackageAdminImpl pa, final Bundle[] bundles, final FrameworkListener[] fl) { pa.refreshPackages0(bundles, fl); } // // ServiceRegisterationImpl secure operations // S callGetService(final ServiceRegistrationImpl sr, final Bundle b) { @SuppressWarnings("unchecked") final ServiceFactory srf = (ServiceFactory)sr.service; return srf.getService(b, sr); } void callUngetService(final ServiceRegistrationImpl sr, final Bundle b, final S instance) { @SuppressWarnings("unchecked") final ServiceFactory srf = (ServiceFactory)sr.service; srf.ungetService(b, sr, instance); } // // StartLevelController secure operations // void callSetStartLevel(final BundleImpl b, final int startlevel) { b.setStartLevel(startlevel); } void callSetInitialBundleStartLevel0(final StartLevelController slc, final int startlevel) { slc.setInitialBundleStartLevel0(startlevel, true); } // // SystemBundle secure operations // void callShutdown(final SystemBundle sb, final boolean restart) { sb.shutdown(restart); } // // Permissions package functionality // ProtectionDomain getProtectionDomain(final BundleGeneration bg) { return null; } /** * Get bundle URL using a bundle: spec and the BundleURLStreamHandler. * *

* Note:
* Creating bundle: URLs by the URL(String) constructor will only work if the * the fw URL handler is registered, which may be turned off. *

*/ URL getBundleURL(FrameworkContext fwCtx, String s) throws MalformedURLException { return new URL(null, s, fwCtx.urlStreamHandlerFactory.createURLStreamHandler(BundleURLStreamHandler.PROTOCOL)); } // // Privileged system calls // ClassLoader getClassLoaderOf(final Class c) { return c.getClassLoader(); } // // Cleaning // /** * Purge all cached information for specified bundle. */ void purge(BundleImpl b, ProtectionDomain pc) { } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/BundleClassLoaderListener.java0000644000175000017500000000422512346513666033067 0ustar felixfelix/* * Copyright (c) 2012, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; /** * Bundle class loader life cycle listener interface. * * @author Makewave AB, Gunnar Ekolin */ public interface BundleClassLoaderListener { /** * Synchronously called when a new bundle class loader has been * created. * * @param bcl the newly created bundle class loader. */ void bundleClassLoaderCreated(BundleClassLoader bcl); /** * Synchronously called when a bundle class loader has been * closed. * * @param bcl the closed down bundle class loader. */ void bundleClassLoaderClosed(BundleClassLoader bcl); } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/Queue.java0000644000175000017500000001101112346513666027106 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Vector; /** * The Queue class represents a first-in-first-out (FIFO) queue of * objects. * * @author Per Lundgren */ public class Queue extends Vector { private static final long serialVersionUID = 1L; private int m_nMaxSize = -1; private boolean queueClosed = false; // ==================== Queue ==================== /** ** Constructs an Queue with the specifies maximum size. ** ** @param size * maximum queue size. */ public Queue(int size) { m_nMaxSize = size; } // ==================== insert ==================== /** ** Inserts an item into the queue. If there are threads blocked on ** remove, one of them is unblocked. ** ** @param item * the item to be inserted. ** @exception IndexOutOfBoundsException * if maximum queue size is reached. */ public synchronized void insert(E item) throws IndexOutOfBoundsException { // Check if queue is full if (m_nMaxSize > 0 && size() >= m_nMaxSize) throw new IndexOutOfBoundsException("Queue full"); addElement(item); notify(); } // ==================== insertFirst ==================== /** ** Inserts an item first into the queue. If there are threads blocked on ** remove, one of them is unblocked. ** ** @param item * the item to be inserted. */ public synchronized void insertFirst(E item) { insertElementAt(item, 0); notify(); } // ==================== remove ==================== /** ** Removes and returns the first item in the queue. If the queue is empty, the * calling thread will block. ** ** @param timeout * timeout in seconds. ** @return The first item in the queue, or null if a timeout * occurred. To distinguish timeouts, null items should * not be inserted in the queue. */ public synchronized E removeWait(float timeout) { E obj = null; // If queue is empty wait for object to be inserted if (isEmpty() && !queueClosed) { try { if (timeout > 0) { wait(Math.round(timeout * 1000.0f)); } else wait(); } catch (final InterruptedException e) { } } if (queueClosed || isEmpty()) { return null; } obj = firstElement(); removeElementAt(0); return obj; } // ==================== remove ==================== /** ** Removes and returns the first object in the queue. Same as * remove(float timeout) but this function blocks forever. ** ** @return The first item in the queue. */ public E remove() { return removeWait(0); } // ==================== close ==================== /** ** Closes the queue, i.e. wakes up all threads blocking on a call to remove(). */ public synchronized void close() { queueClosed = true; notifyAll(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/HeaderDictionary.java0000644000175000017500000001042412346513666031247 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.Dictionary; import java.util.Enumeration; import java.util.Hashtable; import java.util.Map.Entry; import java.util.jar.Attributes; /** * Dictionary for Bundle Manifest headers. * * @author Jan Stein */ public class HeaderDictionary extends Dictionary implements Cloneable { private final Hashtable headers; /** * Create a dictionary from manifest attributes. */ public HeaderDictionary(Attributes in) { headers = new Hashtable(); for (final Entry e : in.entrySet()) { headers.put((Attributes.Name)e.getKey(), (String)e.getValue()); } } /** * Create a dictionary of an existing Hashtable. */ private HeaderDictionary(Hashtable t) { headers = t; } /** * Returns an enumeration of the values in this dictionary. */ @Override public Enumeration elements() { return headers.elements(); } /** * Returns the value to which the key is mapped in this dictionary. */ @Override public String get(Object key) { return headers.get(new Attributes.Name((String)key)); } /** * Tests if this dictionary maps no keys to value. */ @Override public boolean isEmpty() { return headers.isEmpty(); } /** * Returns an enumeration of the keys in this dictionary. */ @Override public Enumeration keys() { final Enumeration keys = headers.keys(); return new Enumeration() { public boolean hasMoreElements() { return keys.hasMoreElements(); } public String nextElement() { return keys.nextElement().toString(); } }; } /** * Maps the specified key to the specified value in this dictionary. */ @Override public String put(String key, String value) { return headers.put(new Attributes.Name(key), value); } /** * Removes the key (and its corresponding value) from this dictionary. */ @Override public String remove(Object key) { return headers.remove(new Attributes.Name((String)key)); } /** * Returns the number of entries (distinct keys) in this dictionary. */ @Override public int size() { return headers.size(); } /** * Clone */ @SuppressWarnings("unchecked") @Override public Object clone() { return new HeaderDictionary((Hashtable)headers.clone()); } @SuppressWarnings("unchecked") HeaderDictionary cloneHD() { return new HeaderDictionary((Hashtable)headers.clone()); } @Override public String toString() { return headers.toString(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/PackageAdminImpl.java0000644000175000017500000004100512346513666031156 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.TreeSet; import java.util.Vector; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.osgi.framework.FrameworkEvent; import org.osgi.framework.FrameworkListener; import org.osgi.framework.VersionRange; import org.osgi.service.packageadmin.ExportedPackage; import org.osgi.service.packageadmin.PackageAdmin; import org.osgi.service.packageadmin.RequiredBundle; /** * Framework service which allows bundle programmers to inspect the packages * exported in the framework and eagerly update or uninstall bundles. * * If present, there will only be a single instance of this service registered * in the framework. * *

* The term exported package (and the corresponding interface * {@link ExportedPackage}) refers to a package that has actually been exported * (as opposed to one that is available for export). * *

* Note that the information about exported packages returned by this service is * valid only until the next time {@link #refreshPackages} is called. If an * ExportedPackage becomes stale, (that is, the package it references has been * updated or removed as a result of calling PackageAdmin.refreshPackages()), * its getName() and getSpecificationVersion() continue to return their old * values, isRemovalPending() returns true, and getExportingBundle() and * getImportingBundles() return null. * * @see org.osgi.service.packageadmin.PackageAdmin * @author Jan Stein * @author Erik Wistrand * @author Robert Shelley * @author Philippe Laporte * @author Mats-Ola Persson */ @SuppressWarnings("deprecation") public class PackageAdminImpl implements PackageAdmin { final static String SPEC_VERSION = "1.2"; private final FrameworkContext fwCtx; volatile private Vector refreshSync = new Vector(1); PackageAdminImpl(FrameworkContext fw) { fwCtx = fw; } /** * Gets the packages exported by the specified bundle. * * @param bundle The bundle whose exported packages are to be returned, or * null if all the packages currently exported in the * framework are to be returned. If the specified bundle is the * system bundle (that is, the bundle with id 0), this method returns * all the packages on the system classpath whose name does not start * with "java.". In an environment where the exhaustive list of * packages on the system classpath is not known in advance, this * method will return all currently known packages on the system * classpath, that is, all packages on the system classpath that * contains one or more classes that have been loaded. * * @return The array of packages exported by the specified bundle, or * null if the specified bundle has not exported any * packages. */ public ExportedPackage[] getExportedPackages(Bundle bundle) { final ArrayList pkgs = new ArrayList(); if (bundle != null) { for (final Iterator i = ((BundleImpl)bundle).getExports(); i.hasNext();) { final ExportPkg ep = i.next(); if (ep.isExported()) { pkgs.add(new ExportedPackageImpl(ep)); } } } else { for (final BundleImpl b : fwCtx.bundles.getBundles()) { for (final Iterator i = b.getExports(); i.hasNext();) { final ExportPkg ep = i.next(); if (ep.isExported()) { pkgs.add(new ExportedPackageImpl(ep)); } } } } final int size = pkgs.size(); if (size > 0) { return pkgs.toArray(new ExportedPackage[size]); } else { return null; } } /** * Gets the exported packages for the specified package name. * * @param name The name of the exported packages to be returned. * * @return An array of the exported packages, or null if no * exported packages with the specified name exists. */ public ExportedPackage[] getExportedPackages(String name) { final Pkg pkg = fwCtx.resolver.getPkg(name); ExportedPackage[] res = null; if (pkg != null) { synchronized (pkg) { final int size = pkg.exporters.size(); if (size > 0) { res = new ExportedPackage[size]; final Iterator i = pkg.exporters.iterator(); for (int pos = 0; pos < size;) { res[pos++] = new ExportedPackageImpl(i.next()); } } } } return res; } /** * Gets the ExportedPackage with the specified package name. All exported * packages will be checked for the specified name. In an environment where * the exhaustive list of packages on the system classpath is not known in * advance, this method attempts to see if the named package is on the system * classpath. This means that this method may discover an ExportedPackage that * was not present in the list returned by getExportedPackages(). * * @param name The name of the exported package to be returned. * * @return The exported package with the specified name, or null if * no expored package with that name exists. */ public ExportedPackage getExportedPackage(String name) { final Pkg p = fwCtx.resolver.getPkg(name); if (p != null) { final ExportPkg ep = p.getBestProvider(); if (ep != null) { return new ExportedPackageImpl(ep); } } return null; } /** * Forces the update (replacement) or removal of packages exported by the * specified bundles. * * @see org.osgi.service.packageadmin.PackageAdmin#refreshPackages */ public void refreshPackages(final Bundle[] bundles) { refreshPackages(bundles, null); } void refreshPackages(final Bundle[] bundles, final FrameworkListener[] fl) { fwCtx.perm.checkResolveAdminPerm(); boolean restart = false; if (bundles != null) { for (int i = 0; i < bundles.length; i++) { fwCtx.checkOurBundle(bundles[i]); if (((BundleImpl)bundles[i]).extensionNeedsRestart()) { restart = true; break; } } } else { restart = fwCtx.bundles.checkExtensionBundleRestart(); } if (restart) { try { // will restart the framework. fwCtx.systemBundle.update(); } catch (final BundleException ignored) { /* this can't be happening. */ } return; } final PackageAdminImpl thisClass = this; synchronized (refreshSync) { final Thread t = new Thread(fwCtx.threadGroup, "RefreshPackages") { @Override public void run() { fwCtx.perm.callRefreshPackages0(thisClass, bundles, fl); } }; t.setDaemon(false); refreshSync.add(t); t.start(); // Wait for a refresh thread to start try { refreshSync.wait(500); } catch (final InterruptedException ignore) { } } } /** * */ void refreshPackages0(final Bundle[] bundles, final FrameworkListener...fl) { if (fwCtx.debug.resolver) { fwCtx.debug.println("PackageAdminImpl.refreshPackages() starting"); } final ArrayList startList = new ArrayList(); BundleImpl [] bi; synchronized (fwCtx.resolver) { final TreeSet zombies = fwCtx.resolver.getZombieAffected(bundles); bi = zombies.toArray(new BundleImpl[zombies.size()]); synchronized (refreshSync) { refreshSync.notifyAll(); } // Stop affected bundles and remove their classloaders // in reverse start order for (int bx = bi.length; bx-- > 0;) { if (bi[bx].state == Bundle.ACTIVE || bi[bx].state == Bundle.STARTING) { startList.add(0, bi[bx]); try { bi[bx].waitOnOperation(fwCtx.resolver, "PackageAdmin.refreshPackages", false); final Exception be = bi[bx].stop0(); if (be != null) { fwCtx.frameworkError(bi[bx], be); } } catch (final BundleException ignore) { // Wait failed, we will try again } } } // Update the affected bundle states in normal start order int startPos = startList.size() - 1; BundleImpl nextStart = startPos >= 0 ? startList.get(startPos) : null; for (int bx = bi.length; bx-- > 0;) { Exception be = null; switch (bi[bx].state) { case Bundle.STARTING: case Bundle.ACTIVE: // Bundle must stop before we can continue // We could hang forever here. while (true) { try { bi[bx].waitOnOperation(fwCtx.resolver, "PackageAdmin.refreshPackages", true); break; } catch (final BundleException we) { if (fwCtx.debug.resolver) { fwCtx.debug .println("PackageAdminImpl.refreshPackages() timeout on bundle stop, retry..."); } fwCtx.frameworkWarning(bi[bx], we); } } be = bi[bx].stop0(); if (be != null) { fwCtx.frameworkError(bi[bx], be); } if (nextStart != bi[bx]) { startList.add(startPos + 1, bi[bx]); } // Fall through... case Bundle.STOPPING: case Bundle.RESOLVED: bi[bx].setStateInstalled(true); if (bi[bx] == nextStart) { nextStart = --startPos >= 0 ? startList.get(startPos) : null; } // Fall through... case Bundle.INSTALLED: case Bundle.UNINSTALLED: break; } bi[bx].purge(); } } if (fwCtx.debug.resolver) { fwCtx.debug.println("PackageAdminImpl.refreshPackages() " + "all affected bundles now in state INSTALLED"); } // Restart previously active bundles in normal start order startBundles(startList); final FrameworkEvent fe = new FrameworkEvent(FrameworkEvent.PACKAGES_REFRESHED, fwCtx.systemBundle, null); fwCtx.listeners.frameworkEvent(fe, fl); refreshSync.remove(Thread.currentThread()); if (fwCtx.debug.resolver) { fwCtx.debug.println("PackageAdminImpl.refreshPackages() done."); } } /** * Start a list of bundles in order * * @param slist Bundles to start. */ private void startBundles(List slist) { // Sort in start order // Resolve first to avoid dead lock BundleImpl [] triggers = slist.toArray(new BundleImpl[slist.size()]); for (final BundleImpl rb : slist) { rb.getUpdatedState(triggers); } try { fwCtx.resolverHooks.endResolve(triggers); } catch (final BundleException be) { // TODO Fix correct bundle fwCtx.frameworkError(fwCtx.systemBundle, be); } for (final BundleImpl rb : slist) { if (rb.getState() == Bundle.RESOLVED) { try { rb.start(); } catch (final BundleException be) { fwCtx.frameworkError(rb, be); } } } } /** * */ public boolean resolveBundles(Bundle[] bundles) { fwCtx.perm.checkResolveAdminPerm(); synchronized (fwCtx.resolver) { fwCtx.resolverHooks.checkResolveBlocked(); List bl = new ArrayList(); boolean res = true; if (bundles != null) { for (final Bundle bundle : bundles) { if (bundle.getState() == Bundle.INSTALLED) { bl.add((BundleImpl)bundle); } else if (bundle.getState() == Bundle.UNINSTALLED) { res = false; } } } else { for (final BundleImpl bundle : fwCtx.bundles.getBundles()) { if (bundle.getState() == Bundle.INSTALLED) { bl.add(bundle); } } } if (!bl.isEmpty()) { final BundleImpl [] triggers = bl.toArray(new BundleImpl[bl.size()]); // TODO Resolve all at once, so that we can handle resolver abort correctly! for (final Bundle bundle : bl) { final BundleImpl b = (BundleImpl)bundle; if (b.getUpdatedState(triggers) == Bundle.INSTALLED) { res = false; } } try { fwCtx.resolverHooks.endResolve(triggers); } catch (BundleException be) { // TODO Fix correct bundle fwCtx.frameworkError(fwCtx.systemBundle, be); } } return res; } } public RequiredBundle[] getRequiredBundles(String symbolicName) { List bgs = fwCtx.bundles.getBundleGenerations(symbolicName); final ArrayList res = new ArrayList(); for (final BundleGeneration bg : bgs) { if ((bg.bundle.isResolved() || bg.bundle.getRequiredBy().size() > 0) && !bg.isFragment()) { res.add(new RequiredBundleImpl(bg.bpkgs)); } } final int s = res.size(); if (s > 0) { return res.toArray(new RequiredBundle[s]); } else { return null; } } public Bundle[] getBundles(String symbolicName, String versionRange) { final VersionRange vr = versionRange != null ? new VersionRange(versionRange.trim()) : null; final List bgs = fwCtx.bundles.getBundles(symbolicName, vr); final int size = bgs.size(); if (size > 0) { final Bundle[] res = new Bundle[size]; final Iterator i = bgs.iterator(); for (int pos = 0; pos < size;) { res[pos++] = i.next().bundle; } return res; } else { return null; } } public Bundle[] getFragments(Bundle bundle) { if (bundle == null) { return null; } final BundleGeneration bg = ((BundleImpl)bundle).current(); if (bg.isFragment()) { return null; } if (bg.isFragmentHost()) { @SuppressWarnings("unchecked") final Vector fix = (Vector) bg.fragments.clone(); final Bundle[] r = new Bundle[fix.size()]; for (int i = fix.size() - 1; i >= 0; i--) { r[i] = fix.get(i).bundle; } return r; } else { return null; } } public Bundle[] getHosts(Bundle bundle) { final BundleImpl b = (BundleImpl) bundle; if (b != null) { final Vector h = b.getHosts(false); if (h != null) { final Bundle[] r = new Bundle[h.size()]; int pos = 0; for (final BundleGeneration bg : h) { r[pos++] = bg.bundle; } return r; } } return null; } public Bundle getBundle(@SuppressWarnings("rawtypes") Class clazz) { final ClassLoader cl = clazz.getClassLoader(); if (cl instanceof BundleClassLoader) { return ((BundleClassLoader)cl).getBundle(); } else { return null; } } public int getBundleType(Bundle bundle) { final BundleGeneration bg = ((BundleImpl)bundle).current(); return bg.isFragment() && !bg.isExtension() ? BUNDLE_TYPE_FRAGMENT : 0; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/0000755000175000017500000000000012475375714030026 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/memory/0000755000175000017500000000000012475375714031336 5ustar felixfelix././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/memory/BundleArchiveImpl.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/memory/BundleArc0000644000175000017500000002417312346513666033124 0ustar felixfelix/* * Copyright (c) 2003-2013, Knopflerfish project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.bundlestorage.memory; import java.io.IOException; import java.io.InputStream; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import java.util.Properties; import java.util.StringTokenizer; import org.osgi.framework.Constants; import org.knopflerfish.framework.BundleArchive; import org.knopflerfish.framework.BundleGeneration; import org.knopflerfish.framework.BundleResourceStream; import org.knopflerfish.framework.FileArchive; import org.knopflerfish.framework.HeaderDictionary; /** * Managing bundle data. * * @author Jan Stein * @author Philippe Laporte */ class BundleArchiveImpl implements BundleArchive { private final Archive archive; private BundleGeneration bundleGeneration = null; private final long id; private final String location; private int autostartSetting = -1; // -> not started. private final BundleStorageImpl storage; private Archive[] archives; private int startLevel = -1; private long lastModified; private ArrayList failedPath = null; /** * Construct new bundle archive. * */ BundleArchiveImpl(BundleStorageImpl bundleStorage, InputStream is, String bundleLocation, long bundleId) throws Exception { archive = new Archive(this, is); storage = bundleStorage; id = bundleId; location = bundleLocation; setClassPath(); } /** * Construct new bundle archive in an existing bundle archive. * */ BundleArchiveImpl(BundleArchiveImpl old, InputStream is) throws Exception { location = old.location; storage = old.storage; id = old.id; autostartSetting = old.autostartSetting; archive = new Archive(this, is); setClassPath(); } /** * Get an attribute from the manifest of a bundle. * * @param key Name of attribute to get. * @return A string with result or null if the entry doesn't exists. */ public String getAttribute(String key) { return archive.getAttribute(key); } /** * Get a FileArchive handle to a named Jar file or directory within this * archive. * * @param path Name of Jar file or directory to get. * @return A FileArchive object representing new archive, null if not found. */ public FileArchive getFileArchive(String path) { for (Archive a : archives) { if (a.path.equals(path)) { return a; } } return null; } /** * returns the localization entries of this archive. */ public Hashtable getLocalizationEntries(String localeFile) { final BundleResourceStream is = archive.getBundleResourceStream(localeFile); if (is != null) { final Properties l = new Properties(); try { l.load(is); } catch (final IOException _ignore) { } try { is.close(); } catch (final IOException _ignore) { } @SuppressWarnings("rawtypes") final Hashtable ht = l; @SuppressWarnings("unchecked") final Hashtable res = ht; return res; } else { return null; } } /** * returns the raw unlocalized entries of this archive. */ public HeaderDictionary getUnlocalizedAttributes() { return new HeaderDictionary(archive.manifest.getMainAttributes()); } /** * Get bundle generation associated with this bundle archive. * * @return BundleGeneration object. */ public BundleGeneration getBundleGeneration() { return bundleGeneration; } /** * Set bundle generation associated with this bundle archive. * * @param BundleGeneration object. */ public void setBundleGeneration(BundleGeneration bg) { bundleGeneration = bg; } /** * Get bundle identifier for this bundle archive. * * @return Bundle identifier. */ public long getBundleId() { return id; } /** * Get bundle location for this bundle archive. * * @return Bundle location. */ public String getBundleLocation() { return location; } public int getStartLevel() { return startLevel; } public void setStartLevel(int level) { startLevel = level; } public long getLastModified() { return lastModified; } public void setLastModified(long timemillisecs) throws IOException { lastModified = timemillisecs; } /** * Get a byte array containg the contents of named file from a bundle archive. * * @param sub index of jar, 0 means the top level. * @param path Path to class file. * @return Byte array with contents of file or null if file doesn't exist. * @exception IOException if failed to read jar entry. */ public byte[] getClassBytes(Integer sub, String path) throws IOException { return archives[sub.intValue()].getClassBytes(path); } /** * Get an specific InputStream to named entry inside a bundle. Leading '/' is * stripped. * * @param component Entry to get reference to. * @param ix index of sub archives. A postive number is the classpath entry * index. -1 means look in the main bundle. * @return InputStream to entry or null if it doesn't exist. */ public BundleResourceStream getBundleResourceStream(String component, int ix) { if (component.startsWith("/")) { component = component.substring(1); } if (ix == -1) { return archive.getBundleResourceStream(component); } else { return archives[ix].getBundleResourceStream(component); } } /** * Get native library from JAR. * * @param libName Name of Jar file to get. * @return A string with path to native library. */ public String getNativeLibrary(String libName) { return null; } /** * Set autostart setting. * * @param setting the new autostart setting. */ public void setAutostartSetting(int setting) throws IOException { if (setting != autostartSetting) { autostartSetting = setting; } } /** * Get autostart setting. * * @return the autostart setting. */ public int getAutostartSetting() { return autostartSetting; } /** * Remove bundle archive from persistent storage. If we removed the active * revision also remove bundle status files. */ public void purge() { storage.removeArchive(this); } /** * Close archive for further access. It should still be possible to get * attributes. */ public void close() { } /** * Get a list with all classpath entries we failed to locate. * * @return A List with all failed classpath entries, null if no failures. */ public List getFailedClassPathEntries() { return failedPath; } /** * Resolve native code libraries. * * @return null if resolve ok, otherwise return an error message. */ public String resolveNativeCode() { if (getAttribute(Constants.BUNDLE_NATIVECODE) != null) { return "Native code not allowed by memory storage"; } return null; } // // Private methods // private void setClassPath() throws IOException { final String bcp = getAttribute(Constants.BUNDLE_CLASSPATH); if (bcp != null) { final ArrayList a = new ArrayList(); final StringTokenizer st = new StringTokenizer(bcp, ","); while (st.hasMoreTokens()) { final String path = st.nextToken().trim(); if (".".equals(path)) { a.add(archive); } else if (path.endsWith(".jar")) { try { a.add(archive.getSubArchive(path)); } catch (final IOException ioe) { if (failedPath == null) { failedPath = new ArrayList(1); } failedPath.add(path); } } else { if (archive.subDirs == null) { archive.subDirs = new ArrayList(1); } // NYI Check that it exists! archive.subDirs.add(path); } } archives = a.toArray(new Archive[a.size()]); } else { archives = new Archive[] { archive }; } } public Enumeration findResourcesPath(String path) { return archive.findResourcesPath(path); } public String getJarLocation() { return null; } /** * Return certificates for signed bundle, otherwise null. * * @return An array of certificates or null. */ public ArrayList> getCertificateChains(boolean onlyTrusted) { // TODO return null; } /** * Mark certificate chain as trusted. * */ public void trustCertificateChain(List trustedChain) { // TODO throw new RuntimeException("NYI"); } } ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/memory/BundleStorageImpl.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/memory/BundleSto0000644000175000017500000001412212346513666033155 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.bundlestorage.memory; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.knopflerfish.framework.BundleArchive; import org.knopflerfish.framework.BundleStorage; import org.knopflerfish.framework.FWProps; import org.knopflerfish.framework.FrameworkContext; /** * Storage of all bundles jar content. * * @author Jan Stein, Gunnar Ekolin */ public class BundleStorageImpl implements BundleStorage { /** * Next available bundle id. */ private long nextFreeId = 1; /** * Bundle id sorted list of all active bundle archives. */ private final ArrayList archives = new ArrayList(); /** * If we should check if bundles are signed */ final boolean checkSigned; /** * Create a container for all bundle data in this framework. * Try to restore all saved bundle archive state. * */ public BundleStorageImpl(FrameworkContext framework) { checkSigned = framework.props.getBooleanProperty(FWProps.BUNDLESTORAGE_CHECKSIGNED_PROP); } /** * Insert bundle into persistent storage * * @param location Location of bundle. * @param is Input stream with bundle content. * @return Bundle archive object. */ public BundleArchive insertBundleJar(String location, InputStream is) throws Exception { final long id = nextFreeId++; final BundleArchive ba = new BundleArchiveImpl(this, is, location, id); archives.add(ba); return ba; } /** * Insert a new jar file into persistent storagedata as an update * to an existing bundle archive. To commit this data a call to * replaceBundleArchive is needed. * * @param old BundleArchive to be replaced. * @param is Inputstrem with bundle content. * @return Bundle archive object. */ public BundleArchive updateBundleArchive(BundleArchive old, InputStream is) throws Exception { return new BundleArchiveImpl((BundleArchiveImpl)old, is); } /** * Replace old bundle archive with a new updated bundle archive, that * was created with updateBundleArchive. * * @param oldBA BundleArchive to be replaced. * @param newBA Inputstrem with bundle content. * @return New bundle archive object. */ public void replaceBundleArchive(BundleArchive oldBA, BundleArchive newBA) throws Exception { int pos; final long id = oldBA.getBundleId(); synchronized (archives) { pos = find(id); if (pos >= archives.size() || archives.get(pos) != oldBA) { throw new Exception("replaceBundleJar: Old bundle archive not found, pos=" + pos); } archives.set(pos, newBA); } } /** * Get all bundle archive objects. * * @return Private array of all BundleArchives. */ public BundleArchive [] getAllBundleArchives() { synchronized (archives) { return archives.toArray(new BundleArchive[archives.size()]); } } /** * Get all bundles to start at next launch of framework. * This list is sorted in increasing bundle id order. * * @return Private copy of a List with bundle id's. */ public List getStartOnLaunchBundles() { final ArrayList res = new ArrayList(); for (final BundleArchive ba : archives) { if (ba.getAutostartSetting()!=-1) { res.add(ba.getBundleLocation()); } } return res; } /** * Close bundle storage. * */ public void close() { for (final Iterator i = archives.iterator(); i.hasNext(); ) { final BundleArchive ba = i.next(); ba.close(); i.remove(); } } // // Package methods // /** * Remove bundle archive from archives list. * * @param id Bundle archive id to find. * @return true if element was removed. */ boolean removeArchive(BundleArchive ba) { synchronized (archives) { final int pos = find(ba.getBundleId()); if (archives.get(pos) == ba) { archives.remove(pos); return true; } else { return false; } } } // // Private methods // /** * Find posisition for BundleArchive with specified id * * @param id Bundle archive id to find. * @return String to write */ private int find(long id) { int lb = 0; int ub = archives.size(); int x = 0; while (lb != ub) { x = (lb + ub) / 2; final long xid = archives.get(x).getBundleId(); if (id <= xid) { ub = x; } else { lb = x+1; } } return lb; } } ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/memory/Archive.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/memory/Archive.j0000644000175000017500000002452012346513666033072 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.bundlestorage.memory; import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.StringTokenizer; import java.util.Vector; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import org.knopflerfish.framework.BundleGeneration; import org.knopflerfish.framework.BundleResourceStream; import org.knopflerfish.framework.FileArchive; /** * JAR file handling. * * @author Jan Stein * @author Philippe Laporte */ class Archive implements FileArchive { /** * */ final private BundleArchiveImpl ba; /** * Archives manifest */ Manifest manifest; /** * JAR Entry handle for file that contains current archive. If not null, it is * a sub jar instead. */ protected HashMap content; ArrayList subDirs/* = null */; final String path; /** * Create an Archive based on contents of an InputStream, get file object for * the stream and use it. Native code is not allowed. * * @param is Jar file data in an InputStream. */ @SuppressWarnings("resource") // The input stream, is, must not be closed here. Archive(BundleArchiveImpl ba, InputStream is) throws IOException { this.ba = ba; path = "."; final JarInputStream ji = new JarInputStream(is); manifest = ji.getManifest(); if (manifest == null) { throw new IOException("Bundle manifest is missing"); } content = loadJarStream(ji); } /** * Create a Sub-Archive based on a path to in an already existing Archive. The * new archive is saved in a subdirectory below local copy of the existing * Archive. * * @param a Parent Archive. * @param path Path of new Archive inside old Archive. * @exception FileNotFoundException if no such Jar file in archive. * @exception IOException if failed to read Jar file. */ Archive(Archive a, String path) throws IOException { ba = a.ba; this.path = path; if (null != path && path.length() > 0 && '/' == path.charAt(0)) { path = path.substring(1); } final byte[] bs = a.content.remove(path); if (bs != null) { final JarInputStream ji = new JarInputStream(new ByteArrayInputStream(bs)); content = loadJarStream(ji); } else { throw new FileNotFoundException("No such file: " + path); } } /** * Get bundle id for this archive. */ public BundleGeneration getBundleGeneration() { return ba.getBundleGeneration(); } /** * Get sub-archive id for this archive. */ public int getSubId() { return 0; } /** * Get an attribute from the manifest of the archive. * * @param key Name of attribute to get. * @return A string with result or null if the entry doesn't exists. */ String getAttribute(String key) { return manifest.getMainAttributes().getValue(key); } /** * Get a byte array containing the contents of named file from the archive. * * @param component File to get. * @return Byte array with contents of file or null if file doesn't exist. * @exception IOException if failed to read jar entry. */ public byte[] getClassBytes(String classFile) throws IOException { byte[] bytes; if ((bytes = content.remove(classFile)) == null) { if (subDirs == null) { return null; } final Iterator it = subDirs.iterator(); boolean found = false; while (it.hasNext()) { final String subDir = it.next(); bytes = content.remove(subDir + "/" + classFile); if (bytes != null) { found = true; break; } } if (!found) { return null; } } return bytes; } /** * Get an InputStream to named entry inside an Archive. * * @param component Entry to get reference to. * @return InputStream to entry or null if it doesn't exist. */ public BundleResourceStream getBundleResourceStream(String component) { if (component.startsWith("/")) { component = component.substring(1); } final byte[] b = content.get(component); if (b != null) { return new BundleResourceStream(new ByteArrayInputStream(b), b.length); } else { return null; } } // Known issues: see FrameworkTestSuite Frame068a and Frame211a. Seems like // the manifest // gets skipped (I guess in getNextJarEntry in loadJarStream) for some reason // investigate further later public Enumeration findResourcesPath(String path) { final Vector answer = new Vector(); // "normalize" + erroneous path check: be generous path = path.replace('\\', '/'); if (path.startsWith("/")) { path = path.substring(1); } if (!path.endsWith("/") /* in case bad argument */) { if (path.length() > 1) { path += "/"; } } final Iterator it = content.keySet().iterator(); while (it.hasNext()) { final String entry = it.next(); if (entry.startsWith(path)) { final String terminal = entry.substring(path.length()); final StringTokenizer st = new StringTokenizer(terminal, "/"); String entryPath; if (st.hasMoreTokens()) { entryPath = path + st.nextToken(); } else {// this should not happen even for "", or? entryPath = path; } if (!answer.contains(entryPath)) { answer.add(entryPath); } } } if (answer.size() == 0) { return null; } return answer.elements(); } /** * Get an Archive handle to a named Jar file within this archive. * * @param path Name of Jar file to get. * @return An Archive object representing new archive. * @exception FileNotFoundException if no such Jar file in archive. * @exception IOException if failed to read Jar file. */ Archive getSubArchive(String path) throws IOException { return new Archive(this, path); } /** * Check for native library in archive. * * @param path Name of native code file to get. * @return If native library exist return libname, otherwise null. */ public String checkNativeLibrary(String path) { return null; } /** * Get native code library filename. * * @param libNameKey Key for native lib to get. * @return A string with the path to the native library. */ public String getNativeLibrary(String libNameKey) { return null; } // // Private methods // /** * Loads all files in a JarInputStream and stores it in a HashMap. * * @param ji JarInputStream to read from. */ private HashMap loadJarStream(JarInputStream ji) throws IOException { final HashMap files = new HashMap(); JarEntry je; while ((je = ji.getNextJarEntry()) != null) { if (!je.isDirectory()) { int len = (int)je.getSize(); if (len == -1) { len = 8192; } byte[] b = new byte[len]; int pos = 0; do { if (pos == len) { len *= 2; final byte[] oldb = b; b = new byte[len]; System.arraycopy(oldb, 0, b, 0, oldb.length); } int n; while ((len - pos) > 0 && (n = ji.read(b, pos, len - pos)) > 0) { pos += n; } } while (ji.available() > 0); if (pos != b.length) { final byte[] oldb = b; b = new byte[pos]; System.arraycopy(oldb, 0, b, 0, pos); } files.put(je.getName(), b); } } return files; } @Override public boolean exists(String path, boolean onlyDirs) { if (path.equals("")) { return true; } if (onlyDirs) { if (!path.endsWith("/")) { path = path + "/"; } for (String k : content.keySet()) { if (k.startsWith(path)) { return true; } } return false; } else { return content.containsKey(path); } } @Override public Set listDir(String path) { Set res = new HashSet(); if (path.length() > 0 && !path.endsWith("/")) { path = path + "/"; } for (String k : content.keySet()) { String e = matchPath(path, k); if (e != null) { res.add(e); } } return res; } private String matchPath(String basePath, String path) { final int len = basePath.length(); if (path.length() > len && path.startsWith(basePath)) { int i = path.indexOf('/', len); if (i == -1) { return path.substring(len); } else { return path.substring(len, i + 1); } } return null; } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/0000755000175000017500000000000012475375714030745 5ustar felixfelix././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/BundleArchiveImpl.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/BundleArchi0000644000175000017500000003644312346513666033057 0ustar felixfelix/* * Copyright (c) 2003-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.bundlestorage.file; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import java.util.Properties; import org.knopflerfish.framework.BundleArchive; import org.knopflerfish.framework.BundleGeneration; import org.knopflerfish.framework.BundleResourceStream; import org.knopflerfish.framework.FileArchive; import org.knopflerfish.framework.FileTree; import org.knopflerfish.framework.HeaderDictionary; import org.knopflerfish.framework.bundlestorage.Util; /** * Interface for managing bundle data. * * @author Jan Stein * @author Erik Wistrand * @author Robert Shelley * @author Philippe Laporte * @author Mats-Ola Persson */ class BundleArchiveImpl implements BundleArchive { /** * Bundle status files */ private final static String LOCATION_FILE = "location"; private final static String REV_FILE = "revision"; private final static String AUTOSTART_FILE = "autostart"; private final static String STARTLEVEL_FILE = "startlevel"; private final static String LAST_MODIFIED_FILE = "lastModifed"; final BundleStorageImpl storage; private final Archive archive; private BundleGeneration bundleGeneration = null; private final long id; final private String location; private int autostartSetting = -1; // => not started. private final FileTree bundleDir; private ArrayList archives; private int startLevel = -1; private long lastModified = 0; private ArrayList> trustedCerts = null; private ArrayList> untrustedCerts = null; private boolean checkCerts = true; private ArrayList warnings = null; /** * Construct new bundle archive. * */ BundleArchiveImpl(BundleStorageImpl bundleStorage, FileTree dir, InputStream is, String bundleLocation, long bundleId) throws Exception { URL source = null; try { source = new URL(bundleLocation); } catch (final Exception e) { } bundleDir = dir; storage = bundleStorage; id = bundleId; location = bundleLocation; archive = new Archive(this, bundleDir, 0, is, source, location); putContent(LOCATION_FILE, location); } /** * Construct new bundle archive based on saved data. * */ BundleArchiveImpl(BundleStorageImpl bundleStorage, FileTree dir, long bundleId) throws Exception { bundleDir = dir; location = getContent(LOCATION_FILE); if (location == null || location.length() == 0) { throw new IOException("No bundle location information found"); } int rev = -1; String s = getContent(REV_FILE); if (s != null) { try { rev = Integer.parseInt(s); } catch (final NumberFormatException e) { } } s = getContent(STARTLEVEL_FILE); if (s != null) { try { startLevel = Integer.parseInt(s); } catch (final NumberFormatException e) { } } s = getContent(LAST_MODIFIED_FILE); if (s != null) { try { lastModified = Long.parseLong(s); } catch (final NumberFormatException ignore) {} } s = getContent(AUTOSTART_FILE); if (s != null) { try { autostartSetting = Integer.parseInt(s); } catch (final NumberFormatException ignore) {} } id = bundleId; storage = bundleStorage; archive = new Archive(this, bundleDir, rev, location); } /** * Construct new bundle archive in an existing bundle archive. * */ BundleArchiveImpl(BundleArchiveImpl old, InputStream is) throws Exception { bundleDir = old.bundleDir; location = old.location; storage = old.storage; id = old.id; autostartSetting = old.autostartSetting; final int rev = old.archive.getRevision() + 1; URL source = null; final boolean bReference = (is == null); if(bReference) { source = new URL(location); } archive = new Archive(this, bundleDir, rev, is, source, location); if(!bReference) { putContent(REV_FILE, Integer.toString(rev)); } } /** * Get an attribute from the manifest of a bundle. * * @param key Name of attribute to get. * @return A string with result or null if the entry doesn't exists. */ public String getAttribute(String key) { return archive.getAttribute(key); } /** * Get a FileArchive handle to a named Jar file or directory * within this archive. * * @param path Name of Jar file or directory to get. * @return A FileArchive object representing new archive, null if not found. * @exception IOException if we failed to get top of file archive. */ public FileArchive getFileArchive(String path) { if (".".equals(path)) { return archive; } if (archives == null) { archives = new ArrayList(); } try { final Archive a = new Archive(archive, path, archives.size() + 1); archives.add(a); return a; } catch (final IOException io) { // TBD, Where to log this return null; } } /** * returns the localization entries of this archive. */ public Hashtable getLocalizationEntries(String localeFile) { final BundleResourceStream aif = archive.getBundleResourceStream(localeFile); if (aif != null) { final Properties l = new Properties(); try { l.load(aif); } catch (final IOException _ignore) { } try { aif.close(); } catch (final IOException _ignore) { } @SuppressWarnings("rawtypes") final Hashtable ht = l; @SuppressWarnings("unchecked") final Hashtable res = ht; return res; } else { return null; } } /** * returns the raw unlocalized entries of this archive. */ public HeaderDictionary getUnlocalizedAttributes() { return new HeaderDictionary(archive.manifest.getMainAttributes()); } /** * Get bundle generation associated with this bundle archive. * * @return BundleGeneration object. */ public BundleGeneration getBundleGeneration() { return bundleGeneration; } /** * Set bundle generation associated with this bundle archive. * * @param BundleGeneration object. */ public void setBundleGeneration(BundleGeneration bg) { bundleGeneration = bg; if (warnings != null) { for (Exception w : warnings) { frameworkWarning(w); } warnings = null; } } /** * Get bundle identifier for this bundle archive. * * @return Bundle identifier. */ public long getBundleId() { return id; } /** * Get bundle location for this bundle archive. * * @return Bundle location. */ public String getBundleLocation() { return location; } /** * */ public int getStartLevel() { return startLevel; } /** * */ public void setStartLevel(int level) throws IOException { if (startLevel != level) { startLevel = level; putContent(STARTLEVEL_FILE, Integer.toString(startLevel)); } } /** * */ public long getLastModified() { return lastModified; } /** * */ public void setLastModified(long timemillisecs) throws IOException{ lastModified = timemillisecs; putContent(LAST_MODIFIED_FILE, Long.toString(timemillisecs)); } /** * Get a BundleResourceStream to named entry inside a bundle. * Leading '/' is stripped. * * @param component Entry to get reference to. * @param ix index of sub archives. A postive number is the classpath entry * index. 0 means look in the main bundle. * @return BundleResourceStream to entry or null if it doesn't exist. */ public BundleResourceStream getBundleResourceStream(String component, int ix) { if (component.startsWith("/")) { component = component.substring(1); } if (ix == 0) { return archive.getBundleResourceStream(component); } else { return archives.get(ix - 1).getBundleResourceStream(component); } } /** * Get autostart setting. * * @return the autostart setting. */ public int getAutostartSetting() { return autostartSetting; } /** * Set autostart setting. * * @param setting the new autostart setting. */ public void setAutostartSetting(int setting) throws IOException { if (setting != autostartSetting) { autostartSetting = setting; putContent(AUTOSTART_FILE, String.valueOf(autostartSetting)); } } /** */ public Enumeration findResourcesPath(String path) { return archive.findResourcesPath(path); } /** */ public String getJarLocation() { return archive.getPath(); } /** * Return certificates for signed bundle, otherwise null. * * @return An array of certificates or null. */ public ArrayList> getCertificateChains(boolean onlyTrusted) { if (checkCerts) { final Certificate [] c = archive.getCertificates(); checkCerts = false; if (c != null) { final ArrayList failed = new ArrayList(); untrustedCerts = Util.getCertificateChains(c, failed); if (!failed.isEmpty()) { // NYI, log Bundle archive has invalid certificates untrustedCerts = null; } } } ArrayList> res = trustedCerts; if (!onlyTrusted && untrustedCerts != null) { if (res == null) { res = untrustedCerts; } else { res = new ArrayList>(trustedCerts.size() + untrustedCerts.size()); res.addAll(trustedCerts); res.addAll(untrustedCerts); } } return res; } /** * Mark certificate chain as trusted. * */ public void trustCertificateChain(List trustedChain) { if (trustedCerts == null) { trustedCerts = new ArrayList>(untrustedCerts.size()); } trustedCerts.add(trustedChain); untrustedCerts.remove(trustedChain); if (untrustedCerts.isEmpty()) { untrustedCerts = null; } } /** * Remove bundle archive from persistent storage. If we removed * the active revision also remove bundle status files. */ public void purge() { close(); if (!storage.isReadOnly()) { if (storage.removeArchive(this)) { (new File(bundleDir, LOCATION_FILE)).delete(); (new File(bundleDir, AUTOSTART_FILE)).delete(); (new File(bundleDir, REV_FILE)).delete(); (new File(bundleDir, STARTLEVEL_FILE)).delete(); (new File(bundleDir, LAST_MODIFIED_FILE)).delete(); } archive.purge(); if (bundleDir.list().length == 0) { bundleDir.delete(); } } } /** * Close archive for further access. It should still be possible * to get attributes. */ public void close() { if (archives != null) { for (final Archive archive2 : archives) { archive2.close(); } archives = null; } archive.close(); } void frameworkWarning(Exception warn) { if (bundleGeneration != null) { storage.framework.frameworkWarning(bundleGeneration, warn); } else { if (warnings == null) { warnings = new ArrayList(); } warnings.add(warn); } } // // Private methods // /** * Statically check if a directory contains info that a bundle * is uninstalled. * *

* Uninstalled is marked via a startlevel of -2. If last modified * file is not available then the bundle is not complete. *

*/ static boolean isUninstalled(File dir) { String s = getContent(dir, LAST_MODIFIED_FILE); if (s == null || s.length() == 0) { return true; } s = getContent(dir, STARTLEVEL_FILE); int n = -1; try { n = Integer.parseInt(s); } catch (final Exception e) { } return n == -2; } /** * */ static String getContent(File dir, String f) { DataInputStream in = null; try { in = new DataInputStream(new FileInputStream(new File(dir, f))); return in.readUTF(); } catch (final IOException ignore) { } finally { if (in != null) { try { in.close(); } catch (final IOException ignore) { } } } return null; } // // Private methods // /** * Read content of file as a string. * * @param f File to read from * @return contents of the file as a single String */ private String getContent(String f) { DataInputStream in = null; try { in = new DataInputStream(new FileInputStream(new File(bundleDir, f))); return in.readUTF(); } catch (final IOException ignore) { } finally { if (in != null) { try { in.close(); } catch (final IOException ignore) { } } } return null; } /** * Write string to named file. * * @param f File to write too * @param contenet String to write * @exception IOException if we fail to save our string */ private void putContent(String f, String content) throws IOException { if (!storage.isReadOnly()) { DataOutputStream out = null; try { out = new DataOutputStream(new FileOutputStream(new File(bundleDir, f))); out.writeUTF(content); } finally { if (out != null) { out.close(); } } } } }//class ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/BundleStorageImpl.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/BundleStora0000644000175000017500000002553512346513666033121 0ustar felixfelix/* * Copyright (c) 2003-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.bundlestorage.file; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.osgi.framework.Constants; import org.knopflerfish.framework.BundleArchive; import org.knopflerfish.framework.BundleStorage; import org.knopflerfish.framework.FWProps; import org.knopflerfish.framework.FileTree; import org.knopflerfish.framework.FrameworkContext; import org.knopflerfish.framework.Util; /** * Storage of all bundles jar content. * * @author Jan Stein, Mats-Ola Persson, Gunnar Ekolin */ public class BundleStorageImpl implements BundleStorage { public final static String ALWAYS_UNPACK_PROP = "org.knopflerfish.framework.bundlestorage.file.always_unpack"; public final static String REFERENCE_PROP = "org.knopflerfish.framework.bundlestorage.file.reference"; public final static String TRUSTED_PROP = "org.knopflerfish.framework.bundlestorage.file.trusted"; public final static String UNPACK_PROP = "org.knopflerfish.framework.bundlestorage.file.unpack"; public final static String JAR_VERIFIER_BUG_PROP = "org.knopflerfish.framework.bundlestorage.file.jar_verifier_bug"; /** * Controls if we should try to unpack bundles with sub-jars and * native code. */ boolean alwaysUnpack; /** * Controls if file: URLs should be referenced only, not copied * to bundle storage dir */ boolean fileReference; /** * Controls if we should trust file storage to be secure. */ boolean trustedStorage; /** * Controls if we should try to unpack bundles with sub-jars and * native code. */ boolean unpack; /** * Optional OS-command to set executable permission on native code. */ String execPermCmd; /** * Is current OS a Windows OS. */ boolean isWindows; /** * Is JarVerifier bug present. */ boolean jarVerifierBug; /** * Top directory for storing all jar data for bundles. */ private FileTree bundlesDir; /** * Next available bundle id. */ private long nextFreeId = 1; /** * Bundle id sorted list of all active bundle archives. */ private final ArrayList archives = new ArrayList(); /** * Framework handle. * Package protected to allow BundleArchiveImpl to get framework. */ FrameworkContext framework; /** * If we should check if bundles are signed */ boolean checkSigned; /** * True if we shouldn't write any files. */ private boolean readOnly; /** * Create a container for all bundle data in this framework. * Try to restore all saved bundle archive state. * */ public BundleStorageImpl(FrameworkContext framework) { this.framework = framework; initProps(framework.props); // See if we have a storage directory bundlesDir = Util.getFileStorage(framework, "bs", !isReadOnly()); if (bundlesDir == null) { throw new RuntimeException("No bundle storage area available!"); } // Restore all saved bundles final String [] list = bundlesDir.list(); for (int i = 0; list != null && i < list.length; i++) { long id; try { id = Long.parseLong(list[i]); } catch (final NumberFormatException e) { continue; } if (id == 0) { System.err.println("Saved bundle with illegal id 0 is ignored."); } final int pos = find(id); if (pos < archives.size() && archives.get(pos).getBundleId() == id) { System.err.println("There are two bundle directories with id: " + id); break; } final FileTree dir = new FileTree(bundlesDir, list[i]); if (dir.isDirectory()) { try { final boolean bUninstalled = BundleArchiveImpl.isUninstalled(dir); if(bUninstalled) { // silently remove any bundle marked as uninstalled dir.delete(); } else { final BundleArchive ba = new BundleArchiveImpl(this, dir, id); archives.add(pos, ba); } if (id >= nextFreeId) { nextFreeId = id + 1; } } catch (final Exception e) { dir.delete(); System.err.println("Removed corrupt bundle dir (" + e.getMessage() + "): " + dir); } } } } /** * Insert bundle into persistent storage * * @param location Location of bundle. * @param is Inputstrem with bundle content. * @return Bundle archive object. */ public BundleArchive insertBundleJar(String location, InputStream is) throws Exception { final long id = nextFreeId++; final FileTree dir = isReadOnly() ? null : new FileTree(bundlesDir, String.valueOf(id)); if (dir != null) { if (dir.exists()) { // remove any old garbage dir.delete(); } dir.mkdir(); } try { final BundleArchive ba = new BundleArchiveImpl(this, dir, is, location, id); archives.add(ba); return ba; } catch (final Exception e) { if (dir != null) { dir.delete(); } throw e; } } /** * Insert a new jar file into persistent storagedata as an update * to an existing bundle archive. To commit this data a call to * replaceBundleArchive is needed. * * @param old BundleArchive to be replaced. * @param is Inputstrem with bundle content. * @return Bundle archive object. */ public BundleArchive updateBundleArchive(BundleArchive old, InputStream is) throws Exception { return new BundleArchiveImpl((BundleArchiveImpl)old, is); } /** * Replace old bundle archive with a new updated bundle archive, that * was created with updateBundleArchive. * * @param oldBA BundleArchive to be replaced. * @param newBA Inputstrem with bundle content. * @return New bundle archive object. */ public void replaceBundleArchive(BundleArchive oldBA, BundleArchive newBA) throws Exception { int pos; final long id = oldBA.getBundleId(); synchronized (archives) { pos = find(id); if (pos >= archives.size() || archives.get(pos) != oldBA) { throw new Exception("replaceBundleJar: Old bundle archive not found, pos=" + pos); } archives.set(pos, newBA); } } /** * Get all bundle archive objects. * * @return Private array of all BundleArchives. */ public BundleArchive [] getAllBundleArchives() { synchronized (archives) { return archives.toArray(new BundleArchive[archives.size()]); } } /** * Get all bundles to start at next launch of framework. * This list is sorted in increasing bundle id order. * * @return Private copy of a List with bundle id's. */ public List getStartOnLaunchBundles() { final ArrayList res = new ArrayList(); for (final BundleArchive ba : archives) { if (ba.getAutostartSetting()!=-1) { res.add(ba.getBundleLocation()); } } return res; } /** * Close bundle storage. * */ public void close() { for (final Iterator i = archives.iterator(); i.hasNext(); ) { final BundleArchive ba = i.next(); ba.close(); i.remove(); } framework = null; bundlesDir = null; } // // Package methods // boolean isReadOnly() { return readOnly; } /** * Remove bundle archive from archives list. * * @param id Bundle archive id to find. * @return true if element was removed. */ boolean removeArchive(BundleArchive ba) { synchronized (archives) { final int pos = find(ba.getBundleId()); if (pos < archives.size() && archives.get(pos) == ba) { archives.remove(pos); return true; } else { return false; } } } // // Private methods // /** * Initialize values for properties. * */ private void initProps(FWProps props) { props.setPropertyDefault(ALWAYS_UNPACK_PROP, FWProps.FALSE); props.setPropertyDefault(REFERENCE_PROP, FWProps.FALSE); props.setPropertyDefault(TRUSTED_PROP, FWProps.TRUE); props.setPropertyDefault(UNPACK_PROP, FWProps.TRUE); props.setPropertyDefault(JAR_VERIFIER_BUG_PROP, FWProps.FALSE); alwaysUnpack = props.getBooleanProperty(ALWAYS_UNPACK_PROP); fileReference = props.getBooleanProperty(REFERENCE_PROP); trustedStorage = props.getBooleanProperty(TRUSTED_PROP); unpack = props.getBooleanProperty(UNPACK_PROP); execPermCmd = props.getProperty(Constants.FRAMEWORK_EXECPERMISSION).trim(); checkSigned = props.getBooleanProperty(FWProps.BUNDLESTORAGE_CHECKSIGNED_PROP); isWindows = props.getProperty(Constants.FRAMEWORK_OS_NAME).startsWith("Windows"); jarVerifierBug = props.getBooleanProperty(JAR_VERIFIER_BUG_PROP); readOnly = props.getBooleanProperty(FWProps.READ_ONLY_PROP); } /** * Find posisition for BundleArchive with specified id * * @param id Bundle archive id to find. * @return String to write */ private int find(long id) { int lb = 0; int ub = archives.size() - 1; int x = 0; while (lb < ub) { x = (lb + ub) / 2; final long xid = archives.get(x).getBundleId(); if (id == xid) { return x; } else if (id < xid) { ub = x; } else { lb = x+1; } } if (lb < archives.size() && archives.get(lb).getBundleId() < id) { return lb + 1; } return lb; } } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/Archive.javaknopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/Archive.jav0000644000175000017500000012530412346513666033032 0ustar felixfelix/* * Copyright (c) 2003-2014, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.bundlestorage.file; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.URL; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.Vector; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.knopflerfish.framework.AutoManifest; import org.knopflerfish.framework.BundleGeneration; import org.knopflerfish.framework.BundleResourceStream; import org.knopflerfish.framework.FileArchive; import org.knopflerfish.framework.FileTree; import org.knopflerfish.framework.Util; import org.knopflerfish.framework.Util.HeaderEntry; import org.osgi.framework.Constants; /** * JAR file handling. * * @author Jan Stein * @author Philippe Laporte * @author Mats-Ola Persson * @author Gunnar Ekolin */ public class Archive implements FileArchive { /** * Base for filename used to store copy of archive. */ final private static String ARCHIVE = "jar"; /** * Directory base name to use for sub-archives. */ final private static String SUBDIR = "sub"; /** * File suffix for certificates. */ final private static String CERTS_SUFFIX = ".crt"; /** * Directory where JAR meta data are stored. */ final private static String META_INF_DIR = "META-INF/"; /** * Directory where optional bundle files are stored these need not be unpacked * locally. */ final private static String OSGI_OPT_DIR = "OSGI-OPT/"; /** * File handle for file that contains current archive. */ private FileTree file; /** * Set to true if above file is a reference outside framework storage. */ private boolean fileIsReference = false; /** * JAR file handle for file that contains current archive. */ private ZipFile jar; final private String location; /** * Certificates for this archive. */ private Certificate[] certs = null; /** * Archive's manifest */ Manifest manifest /* = null */; /** * JAR Entry handle for file that contains current archive. If not null, it is * a sub jar instead. */ private ZipEntry subJar /* = null */; /** * Is Archive closed. */ private boolean bClosed = false; /** * */ private Map nativeLibs; /** * */ private Map renameLibs; /** * */ final private BundleArchiveImpl ba; /** * */ final private int subId; /** * Create an Archive based on contents of an InputStream, the archive is saved * as local copy in the specified directory. * * @param ba BundleArchiveImpl for this archive. * @param dir Directory to save data in. * @param rev Revision of bundle content (used for updates). * @param is Jar file data in an InputStream. * @param url URL to use to CodeSource. * @param location Location for archive */ Archive(BundleArchiveImpl ba, File dir, int rev, InputStream is, URL source, String location) throws IOException { this.location = location; this.ba = ba; subId = 0; boolean isDirectory = false; final FileTree sourceFile; final FileTree bsFile = new FileTree(dir, ARCHIVE + rev); if (isReference(source)) { fileIsReference = true; sourceFile = new FileTree(getFile(source)); file = sourceFile; } else { sourceFile = isFile(source) ? new FileTree(getFile(source)) : null; file = bsFile; } if (sourceFile != null) { isDirectory = sourceFile.isDirectory(); if (isDirectory) { final File mfd = new File(sourceFile.getAbsolutePath(), META_INF_DIR); final File mf = new File(mfd, "MANIFEST.MF"); final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(mf)); try { manifest = new Manifest(bis); } finally { bis.close(); } } } BufferedInputStream bis = null; boolean doUnpack = false; JarInputStream ji = null; if (manifest == null) { bis = new BufferedInputStream(is); if (ba.storage.alwaysUnpack) { ji = new JarInputStream(bis, ba.storage.checkSigned); manifest = ji.getManifest(); doUnpack = true; } else if (ba.storage.unpack) { // Is 1000000 enough, Must be big enough to hold the MANIFEST.MF entry // Hope implement of BufferedInputStream allocates dynamicly. bis.mark(1000000); ji = new JarInputStream(bis, ba.storage.checkSigned); manifest = ji.getManifest(); // If manifest == null then, Manifest probably not first in JAR, should // we complain? // Now, try to use the jar anyway. Maybe the manifest is there. if (manifest == null || !needUnpack(manifest.getMainAttributes())) { bis.reset(); } else { doUnpack = true; } } if (doUnpack) { if (ba.storage.isReadOnly()) { throw new IOException("Bundle storage is read-only, no archive unpack."); } if (fileIsReference) { fileIsReference = false; file = bsFile; } file.mkdirs(); if (manifest == null) { if (ba.storage.checkSigned) { // TBD? Which exception to use? throw new IOException("MANIFEST.MF must be first in archive when using signatures."); } } else { final File f = new File(file, META_INF_DIR); f.mkdir(); final FileOutputStream fo = new FileOutputStream(new File(f, "MANIFEST.MF")); final BufferedOutputStream o = new BufferedOutputStream(fo); try { manifest.write(o); } finally { o.close(); } } boolean verify = ba.storage.checkSigned; int verifiedEntries = 0; while (processNextJarEntry(ji, verify, file)) { if (verify) { if (isArchiveSigned()) { verifiedEntries++; } else { verify = false; } } } if (verify) { checkCertificates(verifiedEntries); } jar = null; } } if (!doUnpack) { if (isDirectory) { if (!fileIsReference) { if (ba.storage.isReadOnly()) { throw new IOException("Bundle storage is read-only, unable to save archive."); } sourceFile.copyTo(file); } if (ba.storage.checkSigned) { // NYI! Verify signed directory } jar = null; } else { if (!fileIsReference) { loadFile(file, bis); } if (ba.storage.checkSigned) { processSignedJar(file); } jar = new ZipFile(file); } } if (manifest != null) { manifest = new AutoManifest(ba.storage.framework, manifest, location); } else { manifest = getManifest(); } checkManifest(); handleAutoManifest(); saveCertificates(); if (ji != null) { ji.close(); } else if (bis != null) { bis.close(); } } /** * Get the file path from an URL, handling the case where it's a * reference:file: URL */ String getFile(URL source) { final String sfile = source.getFile(); if (sfile.startsWith("file:")) { return sfile.substring(5); } else { return sfile; } } boolean isFile(URL source) { return source != null && "file".equals(source.getProtocol()); } /** * Check if an URL is a reference: URL or if we have global references on all * file: URLs */ boolean isReference(URL source) { return (source != null) && ("reference".equals(source.getProtocol()) || (ba.storage.fileReference && isFile(source))); } /** * Create an Archive based on contents of a saved archive in the specified * directory. Take lowest versioned archive and remove rest. * */ Archive(BundleArchiveImpl ba, File dir, int rev, String location) throws IOException { this.location = location; this.ba = ba; subId = 0; final String[] f = dir.list(); file = null; if (rev != -1) { file = new FileTree(dir, ARCHIVE + rev); } else { rev = Integer.MAX_VALUE; for (final String element : f) { if (element.startsWith(ARCHIVE)) { try { final int c = Integer.parseInt(element.substring(ARCHIVE.length())); if (c < rev) { rev = c; file = new FileTree(dir, element); } } catch (final NumberFormatException ignore) { } } } } for (final String element : f) { if (element.startsWith(ARCHIVE)) { try { final int c = Integer.parseInt(element.substring(ARCHIVE.length())); if (c != rev) { (new FileTree(dir, element)).delete(); } } catch (final NumberFormatException ignore) { } } if (element.startsWith(SUBDIR)) { try { final int c = Integer.parseInt(element.substring(SUBDIR.length())); if (c != rev) { (new FileTree(dir, element)).delete(); } } catch (final NumberFormatException ignore) { } } } if (file == null) { if (location != null) { try { final URL url = new URL(location); if (isReference(url)) { file = new FileTree(getFile(url)); } } catch (final Exception e) { throw new IOException("Bad file URL stored in referenced jar in: " + dir.getAbsolutePath() + ", location=" + location + ", e=" + e); } } if (file == null || !file.exists()) { throw new IOException("No saved jar file found in: " + dir.getAbsolutePath() + ", old location=" + location); } fileIsReference = true; } if (file.isDirectory()) { jar = null; } else { jar = new ZipFile(file); } if (ba.storage.checkSigned) { loadCertificates(); } if (manifest == null) { manifest = getManifest(); } handleAutoManifest(); } /** * Create a Sub-Archive based on a path to in an already existing Archive. The * new archive is saved in a subdirectory below local copy of the existing * Archive. * * @param a Parent Archive. * @param path Path of new Archive inside old Archive. * @exception FileNotFoundException if no such Jar file in archive. * @exception IOException if failed to read Jar file. */ Archive(Archive a, String path, int id) throws IOException { this.location = a.location; this.ba = a.ba; subId = id; if (a.jar != null) { jar = a.jar; // Try a directory first, make sure that path ends with "/" if (!path.endsWith("/")) { path += "/"; } subJar = jar.getEntry(path); if (subJar == null) { subJar = jar.getEntry(path.substring(0, path.length() - 1)); } if (subJar == null) { throw new IOException("No such JAR component: " + path); } file = a.file; } else { file = findFile(a.file, path); if (file.isDirectory()) { jar = null; } else { jar = new ZipFile(file); } } } /** * Show file name for archive, if zip show if it is sub archive. * * @return A string with result. */ @Override public String toString() { if (subJar != null) { return file.getAbsolutePath() + "(" + subJar.getName() + ")"; } else { return file.getAbsolutePath(); } } /** * Get revision number this archive. * * @return Archive revision number */ int getRevision() { try { return Integer.parseInt(file.getName().substring(ARCHIVE.length())); } catch (final NumberFormatException ignore) { // assert? return -1; } } /** * Get bundle id for this archive. */ public BundleGeneration getBundleGeneration() { return ba.getBundleGeneration(); } /** * Get sub-archive id for this archive. */ public int getSubId() { return subId; } /** * Get an attribute from the manifest of the archive. * * @param key Name of attribute to get. * @return A string with result or null if the entry doesn't exists. */ String getAttribute(String key) { final Attributes a = manifest.getMainAttributes(); if (a != null) { return a.getValue(key); } return null; } /** * Get a byte array containg the contents of named class file from the * archive. * * @param Class File to get. * @return Byte array with contents of class file or null if file doesn't * exist. * @exception IOException if failed to read jar entry. */ public byte[] getClassBytes(String classFile) throws IOException { if (bClosed) { return null; } final BundleResourceStream cif = getBundleResourceStream(classFile); if (cif != null) { byte[] bytes; final long ilen = cif.getContentLength(); if (ilen >= 0) { bytes = new byte[(int)ilen]; final DataInputStream dis = new DataInputStream(cif); dis.readFully(bytes); } else { bytes = new byte[0]; final byte[] tmp = new byte[8192]; try { int len; while ((len = cif.read(tmp)) > 0) { final byte[] oldbytes = bytes; bytes = new byte[oldbytes.length + len]; System.arraycopy(oldbytes, 0, bytes, 0, oldbytes.length); System.arraycopy(tmp, 0, bytes, oldbytes.length, len); } } catch (final EOFException ignore) { // On Pjava we somtimes get a mysterious EOF excpetion, // but everything seems okey. (SUN Bug 4040920) } } cif.close(); return bytes; } else { return null; } } /** * Get a BundleResourceStream to named entry inside an Archive. * * @param component Entry to get reference to. * @return BundleResourceStream to entry or null if it doesn't exist. */ @SuppressWarnings("resource") public BundleResourceStream getBundleResourceStream(String component) { if (bClosed) { return null; } if (component.startsWith("/")) { throw new RuntimeException("Assert! Path should never start with / here"); } ZipEntry ze; try { if (jar != null) { if (subJar != null) { if (subJar.isDirectory()) { ze = jar.getEntry(subJar.getName() + component); if (null != ze) { InputStream is = jar.getInputStream(ze); if (null != is) { return new BundleResourceStream(is, ze.getSize()); } else { // Workaround for directories given without trailing // "/"; they will not yield an input-stream. if (!component.endsWith("/")) { final ZipEntry ze2 = jar.getEntry(subJar.getName() + component + "/"); is = jar.getInputStream(ze2); } return new BundleResourceStream(is, ze.getSize()); } } } else { if (component.equals("")) { // Return a stream to the entire Jar. return new BundleResourceStream(jar.getInputStream(subJar), subJar.getSize()); } else { final JarInputStream ji = new JarInputStream(jar.getInputStream(subJar)); do { ze = ji.getNextJarEntry(); if (ze == null) { ji.close(); return null; } } while (!component.equals(ze.getName())); return new BundleResourceStream(ji, ze.getSize()); } } } else { if (component.equals("")) { // Return a stream to the entire Jar. final File f = new File(jar.getName()); return new BundleResourceStream(new FileInputStream(f), f.length()); } else { ze = jar.getEntry(component); if (null != ze) { InputStream is = jar.getInputStream(ze); if (null != is) { return new BundleResourceStream(is, ze.getSize()); } else { // Workaround for directories given without trailing // "/"; they will not yield an input-stream. if (!component.endsWith("/")) { final ZipEntry ze2 = jar.getEntry(component + "/"); is = jar.getInputStream(ze2); } return new BundleResourceStream(is, ze.getSize()); } } } } } else { final File f = findFile(file, component); return f.exists() ? new BundleResourceStream(new FileInputStream(f), f.length()) : null; } } catch (final IOException ignore) { } return null; } public Enumeration findResourcesPath(String path) { if (bClosed) { return null; } final Vector answer = new Vector(); if (jar != null) { ZipEntry entry; // "normalize" + erroneous path check: be generous path = path.replace('\\', '/'); if (path.startsWith("/")) { path = path.substring(1); } if (!path.endsWith("/")/* in case bad argument */) { if (path.length() > 1) { path += "/"; } } final Enumeration entries = jar.entries(); while (entries.hasMoreElements()) { entry = entries.nextElement(); final String name = entry.getName(); if (name.startsWith(path)) { int idx = name.lastIndexOf('/'); if (entry.isDirectory()) { idx = name.substring(0, idx).lastIndexOf('/'); } if (idx > 0) { if (name.substring(0, idx + 1).equals(path)) { answer.add(name); } } else if (path.equals("")) { answer.add(name); } } } } else { final File f = findFile(file, path); if (!f.exists()) { return null; } if (!f.isDirectory()) { return null; } final File[] files = f.listFiles(); final int length = files.length; for (int i = 0; i < length; i++) { String filePath = files[i].getPath(); filePath = filePath.substring(file.getPath().length() + 1); filePath = filePath.replace(File.separatorChar, '/'); if (files[i].isDirectory()) { filePath += "/"; } answer.add(filePath); } } if (answer.size() == 0) { return null; } return answer.elements(); } /** * Get a BundleResourceStream to named entry inside an Archive. * * @param component Entry to get reference to. * @return BundleResourceStream to entry or null if it doesn't exist. */ public Set listDir(String path) { if (bClosed) { return null; } if (path.startsWith("/")) { throw new RuntimeException("Assert! Path should never start with / here"); } try { if (jar != null) { if (path.length() > 0 && !path.endsWith("/")) { path = path + "/"; } if (subJar != null) { if (subJar.isDirectory()) { path = subJar.getName() + path; } else { final JarInputStream ji = new JarInputStream(jar.getInputStream(subJar)); return listZipDir(path, ji); } } Set res = new HashSet(); for (Enumeration ize = jar.entries(); ize.hasMoreElements(); ) { ZipEntry ze = ize.nextElement(); String e = matchPath(path, ze.getName()); if (e != null) { res.add(e); } } return res; } else { final File f = findFile(file, path); if (f.isDirectory()) { Set res = new HashSet(); for (File fl : f.listFiles()) { if (fl.isDirectory()) { res.add(fl.getName() + "/"); } else { res.add(fl.getName()); } } return res; } } } catch (final IOException ignore) { } return null; } private Set listZipDir(String path, final JarInputStream ji) { ZipEntry ze; HashSet res = new HashSet(); try { for (ze = ji.getNextJarEntry(); ze != null; ) { String e = matchPath(path, ze.getName()); if (e != null) { res.add(e); } } } catch (IOException ioe) { try { ji.close(); } catch (IOException _ignore) { } } return res; } private String matchPath(String basePath, String path) { final int len = basePath.length(); if (path.length() > len && path.startsWith(basePath)) { int i = path.indexOf('/', len); if (i == -1) { return path.substring(len); } else { return path.substring(len, i + 1); } } return null; } /** * Get a BundleResourceStream to named entry inside an Archive. * * @param component Entry to get reference to. * @return BundleResourceStream to entry or null if it doesn't exist. */ public boolean exists(String path, boolean onlyDirs) { if (bClosed) { return false; } if (path.startsWith("/")) { throw new RuntimeException("Assert! Path should never start with / here"); } if (path.equals("")) { return true; } ZipEntry ze; try { if (jar != null) { if (onlyDirs && !path.endsWith("/")) { path = path + "/"; } if (subJar != null) { if (subJar.isDirectory()) { path = subJar.getName() + path; ze = jar.getEntry(path); if (null != ze) { return ze.isDirectory() || !onlyDirs; } if (onlyDirs) { return checkMatch(path); } } else { final JarInputStream ji = new JarInputStream(jar.getInputStream(subJar)); try { String n; if (onlyDirs && !path.endsWith("/")) { path = path + "/"; } for (ze = ji.getNextJarEntry(); ze != null; ) { n = ze.getName(); if (onlyDirs) { if (n.startsWith(path)) { return true; } } else if (n.equals(path)) { return true; } } } finally { ji.close(); } } } else { ze = jar.getEntry(path); if (null != ze) { return ze.isDirectory() || !onlyDirs; } if (onlyDirs) { return checkMatch(path); } } } else { final File f = findFile(file, path); if (f.exists()) { return f.isDirectory() || !onlyDirs; } } } catch (final IOException ignore) { } return false; } private boolean checkMatch(String path) { ZipEntry ze; if (!path.endsWith("/")) { path = path + "/"; } for (Enumeration ize = jar.entries(); ize.hasMoreElements(); ) { ze = ize.nextElement(); String e = matchPath(path, ze.getName()); if (e != null) { return true; } } return false; } /** * Check for native library in archive. * * @param path Name of native code file to get. * @return If native library exist return libname, otherwise null. */ public String checkNativeLibrary(String path) { if (bClosed) { return null; // throw new IOException("Archive is closed"); } if (path.startsWith("/")) { path = path.substring(1); } File lib; if (jar != null) { lib = getSubFile(this, path); if (!lib.exists()) { (new File(lib.getParent())).mkdirs(); final ZipEntry ze = jar.getEntry(path); if (ze != null) { InputStream is = null; try { is = jar.getInputStream(ze); loadFile(lib, is); } catch (final IOException _ignore) { // TBD log this if (is != null) { try { is.close(); } catch (final IOException _ignore2) { } } return null; } } else { return null; } } } else { lib = findFile(file, path); if (!lib.exists()) { if (lib.getParent() != null) { final String libname = lib.getName(); final File[] list = lib.getParentFile().listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { final int pos = name.lastIndexOf(libname); return ((pos > 1) && (name.charAt(pos - 1) == '_')); } }); if (list.length > 0) { list[0].renameTo(lib); } else { return null; } } else { return null; } } } setPerm(lib); final String libstr = lib.getAbsolutePath(); final int sp = libstr.lastIndexOf(File.separatorChar); final String key = (sp != -1) ? libstr.substring(sp + 1) : libstr; if (nativeLibs == null) { nativeLibs = new HashMap(); renameLibs = new HashMap(); } // TBD, What to do if entry already exists? nativeLibs.put(key, libstr); return key; } /** * Get native code library filename. * * @param libNameKey Key for native lib to get. * @return A string with the path to the native library. */ public String getNativeLibrary(String libNameKey) { final String file = nativeLibs.get(libNameKey); if (file != null) { final File f = new File(file); if (f.isFile()) { return doRename(libNameKey, f); } } return null; } /** * Renaming to allow multiple versions of the lib when there are more than one * classloader for this bundle. E.g., after a bundle update. */ private String doRename(String key, File file1) { String val = file1.getAbsolutePath(); // TODO should we fail when we are readonly if (!ba.storage.isReadOnly() && renameLibs.containsKey(key)) { final File file2 = new File(renameLibs.get(key)); if (file1.renameTo(file2)) { val = file2.getAbsolutePath(); nativeLibs.put(key, val); } } final StringBuffer rename = new StringBuffer(val); final int index0 = val.lastIndexOf(File.separatorChar) + 1; final int index1 = val.indexOf("_", index0); if ((index1 > index0) && (index1 == val.length() - key.length() - 1)) { try { final int prefix = Integer.parseInt(val.substring(index0, index1)); rename.replace(index0, index1, Integer.toString(prefix + 1)); } catch (final Throwable t) { rename.insert(index0, "0_"); } } else { rename.insert(index0, "0_"); } renameLibs.put(key, rename.toString()); return val; } /** * */ private void setPerm(File f) { // No OS-cmd for setting permissions given. if (ba.storage.isReadOnly() || ba.storage.execPermCmd.length() == 0) { return; } final String abspath = f.getAbsolutePath(); final String[] execarray = Util.splitwords(ba.storage.execPermCmd); final String[] cmdarray; int start; // Windows systems need a "cmd /c" at the begin if (ba.storage.isWindows && !execarray[0].equalsIgnoreCase("cmd")) { cmdarray = new String[execarray.length + 2]; cmdarray[0] = "cmd"; cmdarray[1] = "/c"; start = 2; } else { cmdarray = new String[execarray.length]; start = 0; } for (int i = 0; i < execarray.length; i++) { cmdarray[i + start] = Util.replace(execarray[i], "${abspath}", abspath); } try { final Process p = Runtime.getRuntime().exec(cmdarray); final Thread ti = new InputGlobber(null, p.getInputStream()); final Thread te = new InputGlobber(cmdarray, p.getErrorStream()); ti.start(); te.start(); while (true) { try { p.waitFor(); break; } catch (final InterruptedException _ie) { _ie.printStackTrace(); } } while (true) { try { ti.join(); break; } catch (final InterruptedException _ie) { _ie.printStackTrace(); } } while (true) { try { te.join(); break; } catch (final InterruptedException _ie) { _ie.printStackTrace(); } } } catch (final IOException _ioe) { _ioe.printStackTrace(); } } // A thread class that consumes all data on an input stream and then // terminates. static class InputGlobber extends Thread { String[] cmd; final InputStream in; boolean copyToStdout; InputGlobber(String[] cmd, InputStream in) { this.cmd = cmd; this.in = in; copyToStdout = cmd != null; } @Override public void run() { final BufferedReader br = new BufferedReader(new InputStreamReader(in)); try { String line = br.readLine(); while (null != line) { if (null != cmd) { final StringBuffer sb = new StringBuffer(); for (final String element : cmd) { if (sb.length() > 0) sb.append(" "); sb.append(element); } // NYI! Log error System.err.println("Failed to execute: '" + sb.toString() + "':"); cmd = null; } if (copyToStdout) System.out.println(line); line = br.readLine(); } } catch (final IOException _ioe) { _ioe.printStackTrace(); } } } /** * Remove archive and any unpacked sub-archives. */ void purge() { close(); // Remove archive if not flagged as keep if (!fileIsReference) { file.delete(); } // Remove any cached sub files getSubFileTree(this).delete(); // Remove any saved certificates. removeCertificates(); } /** * Close archive and all open sub-archives. If close fails it is silently * ignored. */ void close() { bClosed = true; // Mark as closed to safely handle referenced files if (subJar == null && jar != null) { try { jar.close(); } catch (final IOException ignore) { } } } /** * Returns the path to this bundle. */ String getPath() { return file.getAbsolutePath(); } /** * Return certificates for signed bundle, otherwise null. * * @return An array of certificates or null. */ Certificate[] getCertificates() { return certs; } // // Private methods // /** * Check that we have a valid manifest. * * @exception IllegalArgumentException if we have a broken manifest. */ private void checkManifest() { final Attributes a = manifest.getMainAttributes(); Util.parseManifestHeader(Constants.EXPORT_PACKAGE, a.getValue(Constants.EXPORT_PACKAGE), false, true, false); Util.parseManifestHeader(Constants.IMPORT_PACKAGE, a.getValue(Constants.IMPORT_PACKAGE), false, true, false); // NYI, more checks? } /** * Check if we should unpack bundle, i.e has native code file or subjars. This * decision is based on minimizing the expected size. * * @return true if bundle needs to be unpacked. * @exception IllegalArgumentException if we have a broken manifest. */ private boolean needUnpack(Attributes a) { final List nc = Util .parseManifestHeader(Constants.BUNDLE_NATIVECODE, a.getValue(Constants.BUNDLE_NATIVECODE), false, false, false); final String bc = a.getValue(Constants.BUNDLE_CLASSPATH); return (bc != null && !bc.trim().equals(".")) || !nc.isEmpty(); } /** * Handle automanifest stuff. Archive manifest must be set. */ private void handleAutoManifest() throws IOException { // TBD Should we check this, should it not always be true! if (manifest instanceof AutoManifest) { final AutoManifest mf = (AutoManifest)manifest; if (mf.isAuto()) { if (jar != null) { mf.addZipFile(jar); } else if (file != null && file.isDirectory()) { mf.addFile(file.getAbsolutePath(), file); } } } } /** * Get file handle for file inside a directory structure. The path for the * file is always specified with a '/' separated path. * * @param root Directory structure to search. * @param path Path to file to find. * @return The File object for file path. */ private FileTree findFile(File root, String path) { return new FileTree(root, path.replace('/', File.separatorChar)); } /** * Get the manifest for this archive. * * @return The manifest for this Archive */ private AutoManifest getManifest() throws IOException { // TBD: Should recognize entry with lower case? final BundleResourceStream mi = getBundleResourceStream("META-INF/MANIFEST.MF"); if (mi != null) { return new AutoManifest(ba.storage.framework, new Manifest(mi), location); } else { throw new IOException("Manifest is missing"); } } /** * Get dir for unpacked components. * * @param archive Archive which contains the components. * @return FileTree for archives component cache directory. */ private FileTree getSubFileTree(Archive archive) { return new FileTree(archive.file.getParent(), SUBDIR + archive.file.getName().substring(ARCHIVE.length())); } /** * Get file for an unpacked component. * * @param archive Archive which contains the component. * @param path Name of the component to get. * @return File for components cache file. */ private File getSubFile(Archive archive, String path) { return new File(getSubFileTree(archive), path.replace('/', '-')); } /** * Loads a file from an InputStream and stores it in a file. * * @param output File to save data in, if null, discard output. * @param is InputStream to read from. */ private void loadFile(File output, InputStream is) throws IOException { if (ba.storage.isReadOnly()) { throw new IOException("Bundle storage is read-only, unable to save: " + output); } OutputStream os = null; try { if (output != null) { os = new FileOutputStream(output); } final byte[] buf = new byte[8192]; int n; try { while ((n = is.read(buf)) >= 0) { if (os != null) { os.write(buf, 0, n); } } } catch (final EOFException ignore) { // On Pjava we sometimes get a mysterious EOF exception, // but everything seems okey. (SUN Bug 4040920) } } catch (final IOException e) { if (os != null) { output.delete(); } throw e; } finally { if (os != null) { os.close(); } } } /** * Check if archive is signed */ private boolean isArchiveSigned() { return certs != null; } /** * */ private boolean processNextJarEntry(JarInputStream ji, boolean verify, File saveDir) throws IOException { JarEntry je; while ((je = ji.getNextJarEntry()) != null) { if (je.isDirectory()) { continue; } final String name = je.getName(); if (saveDir != null && !startsWithIgnoreCase(name, OSGI_OPT_DIR)) { final StringTokenizer st = new StringTokenizer(name, "/"); File f = new File(saveDir, st.nextToken()); while (st.hasMoreTokens()) { f.mkdir(); f = new File(f, st.nextToken()); } loadFile(f, ji); } else { // Read entry to update certificates. loadFile(null, ji); } ji.closeEntry(); if (startsWithIgnoreCase(name, META_INF_DIR)) { String sub = name.substring(META_INF_DIR.length()); if (sub.indexOf('/') == -1) { if (startsWithIgnoreCase(sub, "SIG-")) { continue; } int idx = sub.lastIndexOf('.'); if (idx != -1) { sub = sub.substring(idx + 1); if (sub.equalsIgnoreCase("DSA") || sub.equalsIgnoreCase("RSA") || sub.equalsIgnoreCase("SF")) { continue; } } } if (ba.storage.jarVerifierBug) { // There is a bug in Oracles java library. // JavaInputStream will verify files in // META-INF if they directly follow the META-INF // signature related files. if (certs == null) { certs = new Certificate[0]; verify = false; } else if (certs.length == 0) { verify = false; } } } if (verify) { final Certificate[] c = je.getCertificates(); if (c != null) { if (certs != null && certs.length > 0) { // TBD, perhaps we should allow permuted chains. if (!Arrays.equals(c, certs)) { certs = null; } } else { certs = c; } } else { certs = null; } } return true; } return false; } /** * Check if name start with prefix ignoring * case of letters. * * @param name String to check * @param prefix Prefix string, must be in upper case. * * @return true if name start with prefix, otherwise * false */ private boolean startsWithIgnoreCase(final String name, final String prefix) { if (name.length() >= prefix.length()) { for (int i = 0; i < prefix.length(); i++) { if (Character.toUpperCase(name.charAt(i)) != prefix.charAt(i)) { return false; } } return true; } return false; } /** * Go through jar file and check signatures. */ private void processSignedJar(File file) throws IOException { final FileInputStream fis = new FileInputStream(file); JarInputStream ji = null; try { final BufferedInputStream bis = new BufferedInputStream(fis); ji = new JarInputStream(bis); int count = 0; manifest = ji.getManifest(); while (processNextJarEntry(ji, true, null)) { if (isArchiveSigned()) { count++; } else { break; } } checkCertificates(count); } finally { if (ji != null) { ji.close(); } else { fis.close(); } } } /** * */ private void checkCertificates(int filesVerified) { if (filesVerified > 0) { Exception warn = null; if (certs != null) { if (certs.length > 0) { // TODO, check that we have all entries in .SF file return; } else { warn = new IOException("Only contained META-INF entries with no certs due to JRE bug. Entries found " + filesVerified); } } else { warn = new IOException("All entries in bundle not completly signed, scan aborted"); } certs = null; ba.frameworkWarning(warn); } } /** * */ private void saveCertificates() throws IOException { if (!ba.storage.isReadOnly()) { final File f = new File(getPath() + CERTS_SUFFIX); if (certs != null) { try { final FileOutputStream fos = new FileOutputStream(f); for (final Certificate cert : certs) { fos.write(cert.getEncoded()); } fos.close(); } catch (final CertificateEncodingException e) { ba.frameworkWarning(e); } } } } /** * TBD improve this. */ private void loadCertificates() throws IOException { final File f = new File(getPath() + CERTS_SUFFIX); if (f.canRead()) { try { final CertificateFactory cf = CertificateFactory.getInstance("X.509"); final FileInputStream fis = new FileInputStream(f); final Collection c = cf.generateCertificates(fis); // TBD, check if order is preserved if (c.size() > 0) { certs = new Certificate[c.size()]; certs = c.toArray(certs); } } catch (final CertificateException e) { ba.frameworkWarning(e); } } // TODO, load certificates from both trusted and untrusted storage!? } /** * */ private void removeCertificates() { final File f = new File(getPath() + CERTS_SUFFIX); f.delete(); } } knopflerfish-osgi-5.1.0/osgi/framework/src/org/knopflerfish/framework/bundlestorage/Util.java0000644000175000017500000000611712346513666031610 0ustar felixfelix/* * Copyright (c) 2009, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.framework.bundlestorage; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; /** * Interface for managing bundle contents. * * @author Jan Stein */ public class Util { /** * Take an array of X509 certificates and arrange them as a list * of chains. Certificates of unknown types and broken chains are * add returned in failed list. * */ public static ArrayList> getCertificateChains(Certificate[] c, ArrayList failed) { if (c == null) { return null; } final ArrayList> res = new ArrayList>(3); ArrayList chain = new ArrayList(3); int i = 0; while (i < c.length) { if (c[i] instanceof X509Certificate) { final X509Certificate cert = (X509Certificate) c[i++]; // TBD, can we use == and do we need to check uniqID? chain.add(cert); if (cert.getIssuerX500Principal().equals(cert.getSubjectX500Principal())) { res.add(chain); chain = new ArrayList(3); } } else { // Unsupported type if (!chain.isEmpty()) { failed.addAll(chain); chain.clear(); } failed.add(c[i++]); } } // Add remaining certs as failed failed.addAll(chain); return res; } } knopflerfish-osgi-5.1.0/osgi/framework/resources/0000755000175000017500000000000012475375720021132 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/resources/packages.txt0000644000175000017500000001454512346513670023455 0ustar felixfelixcom.apple.concurrent!1.7 com.apple.eawt com.apple.eawt.event!1.7 com.apple.eio com.apple.laf!1.7 com.apple.laf.resources!1.7 com.apple.resources!1.7 com.sun.java.swing.plaf.gtk!1.7 com.sun.java.swing.plaf.gtk.resources!1.7 com.sun.java.swing.plaf.motif!1.6 com.sun.java.swing.plaf.motif.resources!1.7 com.sun.java.swing.plaf.nimbus!1.7 com.sun.java.swing.plaf.windows!1.6 com.sun.java.swing.plaf.windows.resources!1.7 javafx.animation!1.7 javafx.application!1.7 javafx.beans!1.7 javafx.beans.binding!1.7 javafx.beans.property!1.7 javafx.beans.property.adapter!1.7 javafx.beans.value!1.7 javafx.collections!1.7 javafx.concurrent!1.7 javafx.embed.swing!1.7 javafx.embed.swt!1.7 javafx.event!1.7 javafx.fxml!1.7 javafx.geometry!1.7 javafx.scene!1.7 javafx.scene.canvas!1.7 javafx.scene.chart!1.7 javafx.scene.control!1.7 javafx.scene.control.cell!1.7 javafx.scene.effect!1.7 javafx.scene.image!1.7 javafx.scene.input!1.7 javafx.scene.layout!1.7 javafx.scene.media!1.7 javafx.scene.paint!1.7 javafx.scene.shape!1.7 javafx.scene.text!1.7 javafx.scene.transform!1.7 javafx.scene.web!1.7 javafx.stage!1.7 javafx.util!1.7 javafx.util.converter!1.7 javax.accessibility javax.activation!1.6 javax.activity!1.6 javax.annotation!1.6 javax.annotation.processing!1.6 javax.crypto javax.crypto.interfaces javax.crypto.spec javax.imageio javax.imageio.event javax.imageio.metadata javax.imageio.plugins.bmp!1.6 javax.imageio.plugins.jpeg javax.imageio.spi javax.imageio.stream javax.jws!1.6 javax.jws.soap!1.6 javax.lang.model!1.6 javax.lang.model.element!1.6 javax.lang.model.type!1.6 javax.lang.model.util!1.6 javax.management!1.6 javax.management.loading!1.6 javax.management.modelmbean!1.6 javax.management.monitor!1.6 javax.management.openmbean!1.6 javax.management.relation!1.6 javax.management.remote!1.6 javax.management.remote.rmi!1.6 javax.management.timer!1.6 javax.naming javax.naming.directory javax.naming.event javax.naming.ldap javax.naming.spi javax.net javax.net.ssl javax.print javax.print.attribute javax.print.attribute.standard javax.print.event javax.rmi javax.rmi.CORBA javax.rmi.ssl!1.6 javax.script!1.6 javax.security![1.4,1.6) javax.security.auth javax.security.auth.callback javax.security.auth.kerberos javax.security.auth.login javax.security.auth.spi javax.security.auth.x500 javax.security.cert javax.security.sasl!1.6 javax.smartcardio!1.6 javax.sound.midi javax.sound.midi.spi javax.sound.sampled javax.sound.sampled.spi javax.sql javax.sql.rowset!1.6 javax.sql.rowset.serial!1.6 javax.sql.rowset.spi!1.6 javax.swing javax.swing.beaninfo![1.4,1.6) javax.swing.beaninfo.images![1.4,1.6) javax.swing.border javax.swing.colorchooser javax.swing.event javax.swing.filechooser javax.swing.plaf javax.swing.plaf.basic javax.swing.plaf.basic.icons![1.5,1.6) javax.swing.plaf.metal javax.swing.plaf.metal.icons![1.4,1.6) javax.swing.plaf.metal.icons.ocean![1.5,1.6) javax.swing.plaf.metal.sounds![1.4,1.6) javax.swing.plaf.multi javax.swing.plaf.nimbus!1.7 javax.swing.plaf.synth!1.6 javax.swing.table javax.swing.text javax.swing.text.html javax.swing.text.html.icons![1.4,1.6) javax.swing.text.html.parser javax.swing.text.rtf javax.swing.text.rtf.charsets![1.4,1.6) javax.swing.tree javax.swing.undo javax.tools!1.6 javax.transaction javax.transaction.xa javax.xml!1.6 javax.xml.bind!1.6 javax.xml.bind.annotation!1.6 javax.xml.bind.annotation.adapters!1.6 javax.xml.bind.attachment!1.6 javax.xml.bind.helpers!1.6 javax.xml.bind.util!1.6 javax.xml.crypto!1.6 javax.xml.crypto.dom!1.6 javax.xml.crypto.dsig!1.6 javax.xml.crypto.dsig.dom!1.6 javax.xml.crypto.dsig.keyinfo!1.6 javax.xml.crypto.dsig.spec!1.6 javax.xml.datatype!1.6 javax.xml.namespace!1.6 javax.xml.parsers javax.xml.soap!1.6 javax.xml.stream!1.6 javax.xml.stream.events!1.6 javax.xml.stream.util!1.6 javax.xml.transform javax.xml.transform.dom javax.xml.transform.sax javax.xml.transform.stax!1.6 javax.xml.transform.stream javax.xml.validation!1.6 javax.xml.ws!1.6 javax.xml.ws.handler!1.6 javax.xml.ws.handler.soap!1.6 javax.xml.ws.http!1.6 javax.xml.ws.soap!1.6 javax.xml.ws.spi!1.6 javax.xml.ws.spi.http!1.7 javax.xml.ws.wsaddressing!1.7 javax.xml.xpath!1.6 netscape.javascript!1.7 org.apache.crimson.jaxp![1.4,1.5) org.apache.crimson.parser![1.4,1.5) org.apache.crimson.parser.resources![1.4,1.5) org.apache.crimson.tree![1.4,1.5) org.apache.crimson.tree.resources![1.4,1.5) org.apache.crimson.util![1.4,1.5) org.apache.xalan![1.4,1.5) org.apache.xalan.client![1.4,1.5) org.apache.xalan.extensions![1.4,1.5) org.apache.xalan.lib![1.4,1.5) org.apache.xalan.lib.sql![1.4,1.5) org.apache.xalan.processor![1.4,1.5) org.apache.xalan.res![1.4,1.5) org.apache.xalan.serialize![1.4,1.5) org.apache.xalan.templates![1.4,1.5) org.apache.xalan.trace![1.4,1.5) org.apache.xalan.transformer![1.4,1.5) org.apache.xalan.xslt![1.4,1.5) org.apache.xml.dtm![1.4,1.5) org.apache.xml.dtm.ref![1.4,1.5) org.apache.xml.dtm.ref.dom2dtm![1.4,1.5) org.apache.xml.dtm.ref.sax2dtm![1.4,1.5) org.apache.xml.utils![1.4,1.5) org.apache.xml.utils.res![1.4,1.5) org.apache.xpath![1.4,1.5) org.apache.xpath.axes![1.4,1.5) org.apache.xpath.compiler![1.4,1.5) org.apache.xpath.functions![1.4,1.5) org.apache.xpath.objects![1.4,1.5) org.apache.xpath.operations![1.4,1.5) org.apache.xpath.patterns![1.4,1.5) org.apache.xpath.res![1.4,1.5) org.ietf.jgss org.jcp.xml.dsig.internal!1.7 org.jcp.xml.dsig.internal.dom!1.7 org.omg.CORBA org.omg.CORBA.DynAnyPackage org.omg.CORBA.ORBPackage org.omg.CORBA.TypeCodePackage org.omg.CORBA.portable org.omg.CORBA_2_3 org.omg.CORBA_2_3.portable org.omg.CosNaming org.omg.CosNaming.NamingContextExtPackage org.omg.CosNaming.NamingContextPackage org.omg.Dynamic org.omg.DynamicAny org.omg.DynamicAny.DynAnyFactoryPackage org.omg.DynamicAny.DynAnyPackage org.omg.IOP org.omg.IOP.CodecFactoryPackage org.omg.IOP.CodecPackage org.omg.Messaging org.omg.PortableInterceptor org.omg.PortableInterceptor.ORBInitInfoPackage org.omg.PortableServer org.omg.PortableServer.CurrentPackage org.omg.PortableServer.POAManagerPackage org.omg.PortableServer.POAPackage org.omg.PortableServer.ServantLocatorPackage org.omg.PortableServer.portable org.omg.SendingContext org.omg.stub.java.rmi org.omg.stub.javax.management.remote.rmi!1.6 org.w3c.dom org.w3c.dom.bootstrap!1.6 org.w3c.dom.css org.w3c.dom.events org.w3c.dom.html org.w3c.dom.ls!1.6 org.w3c.dom.ranges!1.6 org.w3c.dom.stylesheets org.w3c.dom.traversal org.w3c.dom.views org.w3c.dom.xpath!1.6 org.xml.sax org.xml.sax.ext org.xml.sax.helpers sun.awt.shell!1.6 sunw.io sunw.util knopflerfish-osgi-5.1.0/osgi/framework/resources/icon.png0000644000175000017500000000172512346513670022570 0ustar felixfelixPNG  IHDR szzsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<RIDATXWKH+Y=tA#"bȈDĘ]4A2 (QHBJp#"s+nep)(FA\  Hrf.O危ԽU֭b5wd.Cq&p qKZ|p:_,hiiA4IyDP@ww7Ji{0w"I~?].Oţ( '&&H$B"lPtd f qChŸ̱1v^WGGG4 TUU1񧆽$^SSKjA\.^__$XYYi.,3rqqx$HUU D1ຮ$iOAyy9WWWyxxhO|xx`(4IRuvuu |~~?deeP/j`gg3H>.\.'AL$L&CJEQ,vttvzz*|aaH$"ڊwwwPBlVTJ`nL&c&: ~"lPG766MMMr8??x^=-’.ÒnD%ۊKz}} |~+{e`lmm5d*Hpmmsss->RJGK(B^__q||\ HrEy(Nr@y/۷IENDB`knopflerfish-osgi-5.1.0/osgi/framework/resources/META-INF/0000755000175000017500000000000012475375714022275 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/resources/META-INF/services/0000755000175000017500000000000012475375714024120 5ustar felixfelix././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootknopflerfish-osgi-5.1.0/osgi/framework/resources/META-INF/services/org.osgi.framework.launch.FrameworkFactoryknopflerfish-osgi-5.1.0/osgi/framework/resources/META-INF/services/org.osgi.framework.launch.Framewo0000644000175000017500000000006112346513670032423 0ustar felixfelixorg.knopflerfish.framework.FrameworkFactoryImpl knopflerfish-osgi-5.1.0/osgi/framework/resources/help.txt0000644000175000017500000000454612346513670022627 0ustar felixfelix Usage: java [properties] org.knopflerfish.framework.Main [options] or java [properties] -jar framework.jar [options] or java [properties] -jar framework_compact.jar [options] or ./kf2 [options] [-- [properties]] [--- [extra]] (*) Options: -exit Exit the JVM process -help Print this text and exit -version Print version and exit -jvminfo Print system and framework properties and exit -sleep SEC Sleep a while before next command. -xargs file Load more command line arguments from file, exit if file cannot be loaded. --xargs file Load more command line arguments from file, continue if file cannot be loaded (but print error) -create Create and initialize a new framework instance after a shutdown. The default is to reuse the old framework instance. -ff FF Specify the name of the FrameworkFactory to use when creating the framework instance. -init Start an empty platform (i.e., clear old presistent data). -launch Launch framework (i.e., start it). -shutdown mSEC Shutdown framework, timeout in milliseconds. -install URL Install a bundle -istart URL Install and start bundle according to activation policy. -start ID Start bundle (according to its activation policy) -start_e ID Start bundle eagerly (i.e., ignore its activation policy) -start_et ID Start bundle eagerly and transiently -start_pt ID Start bundle transiently according to policy -stop ID Stop bundle -stop_t ID Stop bundle transiently (i.e, non-persistent stop) -uninstall ID Uninstall a bundle -update ID Update a bundle -initlevel N Set initial start level for installed bundles -startlevel N Set the beginning start level of the Start Level service Extra: (Only applicable when using ./kf2) -java PATH Use this JVM (Default=java) The default directory used for storing bundle data is "fwdir". (*) Fully R5 compatible, enables support for bootclasspath extension bundles. Uses framwork.jar if available, otherwise framework_compact.jar. For extended help and list of all available system properties, see online documentation or visit: http://www.knopflerfish.org/releases/current/docs/bundledoc/framework/index.html knopflerfish-osgi-5.1.0/osgi/framework/resources/release0000644000175000017500000000000512346514550022461 0ustar felixfelix5.1.0knopflerfish-osgi-5.1.0/osgi/framework/resources/exports0000644000175000017500000000123412346515430022550 0ustar felixfelixorg.osgi.framework;version=1.7.0,org.osgi.framework.hooks.bundle;version=1.1.0,org.osgi.framework.hooks.resolver;version=1.0.0,org.osgi.framework.hooks.service;version=1.1.0,org.osgi.framework.hooks.weaving;version=1.0.0,org.osgi.framework.launch;version=1.1.0,org.osgi.framework.namespace;version=1.0.0,org.osgi.framework.startlevel;version=1.0.0,org.osgi.framework.wiring;version=1.1.0,org.osgi.resource;version=1.0.0,org.osgi.service.condpermadmin;version=1.1.1,org.osgi.service.packageadmin;version=1.2.0,org.osgi.service.permissionadmin;version=1.2.0,org.osgi.service.startlevel;version=1.1.0,org.osgi.service.url;version=1.0.0,org.osgi.util.tracker;version=1.5.1knopflerfish-osgi-5.1.0/osgi/framework/resources/kfsplash.gif0000644000175000017500000001326712346513670023440 0ustar felixfelixGIF89a!)!))))1!!)11119!11!19!99!9B)19)99)9B)BB)BJ19919B1BB1BJ1JJ9999BB9BJ9JJ9JR9RRBJRBRRBRZBZZJRRJRZJZZJZcJccRZZRZcRccRckZZZZccZckZkkZksckkckscsscs{kssks{k{{ss{s{{s{s{{{{{{{{ƽƽ,/H*\ȰÇ#JHEȱǏ CIɓ(S\ɲK* `P͛8sɳϟ@ JѣH}bI3ӧPJJΥ3jʵׯ76KٳeŢ]˶[jsB.n2e 5mܸY*Ejx`k(~ iL,Kb bnqqրC4ka|1ͺ5i7hQhq5 XZu֨z/` vYP\Bć Hɒ47I{:x%s1\4xk7S@  E@1PAOCO<!=0!N3BM ND0|XSPS{ OMAE #ltN6QN6ukK|UȮ):)7Z 6NͶE豈p0Mw#l.̓Fmv7x{qkqW,ZmM6_NLOoxiT4iZԤik<^~^=f@ T\<}6 OZ8 +7̚.)N/:Zц8!G9A #U{HP$tcDN7 [`6@e3p;x4kA*PXA6<N&ǚypMZs"*Ԅc`1Ț( k" " 6Tm#bXޤw@85 J b%2y` Y1tb$M3)2LO∓9D} ,̏w`v Z7"T5kB H&Fr@pìkzؤlAXi43@*#MLELgubuT#5 Z@hd]M  @orx.܉(v Dٓ3'Z'Z}*PMY@'ϹSSa6mzM>9j*ܹBv'VM=D'4"Is\/]4} >QxzpJ낏*]ӆZCqDU' w\p>//~VwEO(grbNϚc]b? &|d717Vg4fo>!Ma|S'@)g ho)g|V hZgD('+ }"84r9!M}Ӳ)8kUSp~=ARhC)n=H)7(yT(U4(OQE\VXG)3V Pv`-=b;1gXVe(Uo؆8q(.Qp+`de5ѧ"W++qxVb9B+F}3N`A)H)+([3Q^(,C瘈Qŋҁo;z☌٘V/=A<щ5QMe]:2s:v28z8ؘWVnk.((i@s%N3~Դ)l jS Ȃ=qPH;7BTIH)?W ;ኴXWnx")@Q;~Hx<?lcYVqYn?1(Uyikk5TQYvG?1h~k6ၦјWgy@sS* >ՙpf}>’91 U)?w0O 2zŚzفR7rYS`kiM=Abȝy1=87H~ u(U}X<iO9%Hx9멌VŐqpi9U xY~򇛲~e>F>z?eG28ǠQew>$s>HrD+iVx4@=ѶtT>Fj2zwaVv_iQ>T&0gPA᝵=rxɥ]%wnpv!vzuI)vMj (Y9a|Wvi)69mS'=js(bJq94HiJEڒ+zYq՜kD+l\Nsrjʤ<+m@JFiqaZ9?ImT PkAa26vҩ~XyF7oWid Aᢥ1?AKjjUo:%E<k@HƣbP`Bp-mdqE^|IaLP9*>cıW3'<,X81G51clX85pFq- XR6# gp`ɚɘG/lƻ2u|ƒqAǀp \ȇL"q<DZ TRƲ9H@\P`#50PL0L.6o`#)),8854G9KPl#,9 Ȝ\ټ͓\<7IJ=F\gnYn)hm0X6ap׼ZnjӢ bfR8B/XLN ROM#R9`k-b `>:*}5փ&m7,gP$n(%',c`^f LN,m"Mx6Ռڄʃom֨l\'2;E(qhPo 6Ç5prNp`su.$R4lV岽]n'c$"_ȿ[T5M^LnZ%KQ^~Ȟʾ>^~ھ>^~;knopflerfish-osgi-5.1.0/osgi/framework/resources/framework.policy0000644000175000017500000000006512346513670024344 0ustar felixfelixgrant { permission java.security.AllPermission; }; knopflerfish-osgi-5.1.0/osgi/framework/resources/automanifest.props0000644000175000017500000000071512346513670024714 0ustar felixfelix# # Configuration file for automatic manifest generation. # # See javadoc for org.knopflerfish.framework.AutoManifest for documentation # # Section that will set all bundles to export all of their # packages automatically, and dynamically import * 0.match.filter=(location=*) 0.export.filter=(pkg=*) 0.export.file.filter=(file=*.class) 0.header.DynamicImport-Package=* 0.header.Import-Package=[remove] 0.header.Export-Package=[autoexport] knopflerfish-osgi-5.1.0/osgi/framework/resources/icon64.png0000644000175000017500000000330612346513670022737 0ustar felixfelixPNG  IHDR@@iqsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<CIDATxMLMm*Ԧ_D@#@pCz!J`AoB(rďH"b01D SkC)>A۰l)ڲO&<;3;;+ 56 "U?DtJS#@D*I(@؀) jSXzNH T"$uFHDIJP0D(7@;>9s&h$Ap8( N3xMNNFNN2334.oZw^<|n ϟf۶mÍ7+E)ł .HHH z=jjjz Cel6߿ǡC0k,e (,,ݻQPPKNAɄk׮^~2hZY^E8qƱcǠ锽RRRPZZFtuuZQ?|pSo߾E^^^D_~ y%V^cӒ%KpU| XvmT***0228ydlQQFGG&| FQրPncٱcϑ!߿?GKK l6[ h4ذaۇK.˖-BłְFLeΝ;'CEE,_WWǘ~_& @gg'=z[Faq>}Byy,SS۷oHlܸ˛f\X01 ==Ϟ=8NȲ6 n["iii\˹|QQVZ/s ޹s-@^yvOO̙?B%ko@}l 78<<\.{eF{S^ff&~?777cƌ 5 ("BFF |>0`@__#͛\Nv\\jkkg;{^B+ŋ w(dee"­[$z<Y"˺\.i&.mmmVoh CG,^X͞=[vy3gϞe4D:~f?s W:\eVXϟ5!555~޼y4\SS#arsseEHbY `Ϟ=5ѣLHNN3(ro}> L:.tɋn:nûvpѤ="3}H_sLn"I%SKnopflerfish OSGi framework
This is the Knopflerfish framework. An OSGi Release 5 compliant framework. It supports all optional and deprecated framework services, Package Admin, Start Level, Conditional Permission Admin, Permission Admin, URL Handlers, Bundle Hook, Resolver Hook, Service Hook and Weaving Hook.

Contents

Knopflerfish framework.jar startup

This is a startup guide for the KF OSGi framework. Note that command-line startup of the framework is not specified by OSGi, and system integrators often need to create a wrapper script for FW startup.

The KF Main startup class is primarily intended to be used in scenarios where current working directory is same as the one containing framework.jar, the framework storage directory and configuration files. In these cases

java -jar framework.jar

...is often enough.

To use features that requires JVM restart, e.g. extension bundles, you can use our example shell start script "kf2". Open a terminal and type

./kf2

Note: the script requires a "sh" shell.

Other uses are possible, but require options and possibly some tweaking of the default startup files.

Initial start vs restart

Two cases of framework startup should be noted:

  1. Initial, bootstrap, startup
    An initial startup must contain enough options to install bundles allowing further management, using -install options. If no bundles are installed, an empty framework will be started but nothing can be done with it..
  2. Restart of previously initialized framework
    Any OSGi framework can remember its state from previous startup.
    In this case, startup options should only contains system properties and a -launch option for restarting the bundles, but not any -install options.

NB! Framework properties (-Fx=y) supplied at initial startup are saved as part of the framework state, and need not to be supplied again at framework restart. System properties (-Da=b) are not included in the framework state. Since the two different startup cases probably will use separate startup files, care must be taken so system properties are set correctly in both files, when so required.

It is up to a system integrator to decide when to use initial startup or restart. The Main KF class can help somewhat in doing this (see below) but might not be enough. In those cases, wrapper scripts, or modifications to Main.java are recommended.

Starting the framework

The framework can be started using the startup wrapper class

org.knopflerfish.framework.Main

This class is also set a Main-Class in framework.jar's manifest, meaning framework.jar can be started using

 java -jar framework.jar [options] OR ./kf2 [options]

The Main class supports a number of options, which can be displayed using:

java -jar framework.jar -help OR ./kf2 -help

Options can also be specified using the -xargs option, which specifies a .xargs text file containing lines of new options. Typically all options are specified in .xargs files. Combining .xargs files and command line options is possible. .xargs files can also use recursive .xargs files.

When the framework is started, it uses a file system directory for storing the state of all installed bundles, "fwdir". The default directory used for this is:

fwdir

in the current directory. The "fwdir" directory can also be set specifically using the org.osgi.framework.storage property. Note that moving "fwdir" also changes the location for searching for default .xargs files.

If no options are specified (any "-Fx=y", "-Da=b" or "-init" does not count as options in this case) an implicit

-xargs "default"

is added to the options. "default" means that the default .xargs (see below) is selected.

Starting the compact framework

There is a compact version of the framework available for system that has limited amount of resources (memory and storage). This version doesn't contain any support for security and certificates. The internal classes has also been name mangled to save resources.

The compact framework is started and controlled in the same way as the full version. The only difference is that the jar file is called framework_compact.jar.

Default selection of .xargs

If _no_ args are supplied (arguments of the form "-Fx=y", "-Da=b" or "-init" does not count in this case), or a name of "default" is given as -xargs argument, a default .xargs file will be searched for, by the following algorithm:

  1. If there exists a previous "fwdir" AND previous options does not contain "-init", use a file in "fwdir" named:
    fwprops.xargs
  2. If no fwdir exist, OR options contain an "-init", search for a file named:
    1. init_[osname].xargs
    2. init.xargs
    3. remote-init.xargs
    The search is performed in the following directories:
    1. fwdir
    2. The parent directory of fwdir (if any)
    3. The current working directory
    First match wins.
    The [osname]-part of the file name is the unified OS name as specified in Alias.java (see below). Case is important if the file system is case sensitive.
    OS aliases:
    • OS2
    • QNX
    • Windows95
    • Windows98
    • WindowsNT
    • WindowsCE
    • Windows2000
    • WindowsXP

The file fwdir/fwprops.xargs contains saved properties that is used when restarting a framework instance. It is written by the Knopflerfish framework on every startup (unless disabled by setting the property "org.knopflerfish.framework.write.restart.xargs" to false).

Using a HTTP proxy

The standard JVM system properties

  • http.proxyHost
  • http.proxyPort
  • http.nonProxyHosts

should be used to set proxy information. This will be global to all HTTP request from all bundles and the framework.

Additionally, the KF-specific system property

  • http.proxyAuth

can be set to a value on the form user:password

If set to non-empty, this will add the Proxy-Authorization header to bundle install http/https requests made from the framework, However, bundles using the URL class internally must explicitly set this header themselves.

Framework and System Properties

Both Framework and Java System properties are used to control the framework.

Framework properties are the standard properties listed in the OSGi specification (section 4.5.3 in r4.core) and proprietary properties for the Knopflerfish framework. Framework properties are also used for configuration of Knopflerfish bundles.

Framework properties are specified on the command line or in .xarg files using "-F". If you have more than one framework instance, each instance has its own set of Framework properties.

A framework property is accessed by using

org.osgi.framework.BundleContext.getProperty(String)
.

Java System properties are specified on the command line or in .xargs files using "-D". System properties are accessed using

java.lang.System.getProperty(String)
but
BundleContext.getProperty
can also be used as it will look for a System property if there is no matching Framework property.

Because of the different handling of Framework and System properties when the framework is restarted, it is recommended to use only Framework properties in .xargs files. If you do, and use the default init.xargs/props.xargs files, initial starts and restarts become conveniently short on the command line:

java -jar framework.jar -init  
(initial start)

java -jar framework.jar  
(restart)

Unfortunately, it is not always possible to avoid using Java System properties. For example, a bundle may include a class library that uses System properties for configuration. Also, properties that are read during start-up, before the framework has been initialized, need to be System properties, see KF System Properties.

OSGi Specified Framework Properties

OSGi Framework properties should be specified using "-F".

Name Description Value type Default value
org.osgi.framework.bootdelegation Set the boot delegation mask. A list of packages delegated from the framework to the parent classloader. The package specified can contain a wildcard at the end, which matches any sub-packages. String , ...
org.osgi.framework.bsnversion Allow installation of multiple bundles with the same bundle symbolic name or restrict this. The property can have the following values:
single A combination of equal bundle symbolic name and equal version is unique in the framework. Installing a second bundle with the same bundle symbolic name and version is an error.
multiple The combination of bundle symbolic name and version is not unique in the framework.
managed Using a Bundle Collision Hook to filter any non-colliding bundles.
String managed
org.osgi.framework.bundle.parent This property is used to specify what class loader is used for boot delegation. That is, java.* and the packages specified on the org.osgi.framework.bootdelegation. This property can have the following values: boot, app, ext or framework. String boot
org.osgi.framework.command.execpermission Specifies an optional OS specific command to set file permissions on a bundle's native code. This is required on some operating systems to use native libraries. For example, on a UNIX style OS you could have the following value: org.osgi.framework.command.execpermission="chmod +rx ${abspath}" The ${abspath} macro will be substituted for the actual file path. String -
org.osgi.framework.executionenvironment The current execution environment. There are no restriction on the execution environment if this property isn't set. String
org.osgi.framework.language The language used by the framework for the selection of native code. String Set based on default locale
org.osgi.framework.library.extensions A comma separated list of additional library file extensions that must be used when searching for native code. If not set, then only the library name returned by System.mapLibraryName(String) will be used. This list of extensions is needed for certain operating systems which allow more than one extension for native libraries. For example, the AIX operating system allows library extensions of .a and .so, but System.mapLibraryName(String) will only return names with the .a extension. String , ... -
org.osgi.framework.os.name The name of the operating system as used in the native code clause. String Set based on system property os.name
org.osgi.framework.os.version The version of the operating system as used in the native code clause. String Set based on system property os.version
org.osgi.framework.os.processor The name of the processor as used in the native code clause. Set based on system property os.arch
org.osgi.framework.security Specifies the type of security manager the framework must use. If not specified then the framework will not set the VM security manager. The following type is architected: osgi Enables a security manager that supports all security aspects of the OSGi Release 4 specifications (including postponed conditions). If specified, and there is a security manager that doesn't match already installed, then a SecurityException is thrown when the Framework is initialized. String -
org.osgi.framework.startlevel.beginning Specifies the beginning start level of the framework. Integer 1
org.osgi.framework.storage Where we store persistent data. On systems not supporting a current working directory, as Pocket PC, this path should be set to an explicit full path. Note: Knopflerfish 1.x and 2.x used the name "org.osgi.framework.dir" for this property. String ${currentWorkingDirectory}/fwdir
org.osgi.framework.storage.clean Specifies if and when the storage area for the framework should be cleaned. If no value is specified, the framework storage area will not be cleaned. The possible values is: onFirstInit - The framework storage area will be cleaned before the Framework bundle is initialized for the first time. Subsequent inits, starts or updates of the Framework bundle will not result in cleaning the framework storage area. String -
org.osgi.framework.system.packages Complete list of packages exported by the system bundle. If not set the framework will export all OSGi packages and all standard Java packages according to the version of the running JRE. See also "org.knopflerfish.framework.system.packages.base" and "org.osgi.framework.system.packages.extra" String , ... Default is based on other properties
org.osgi.framework.system.packages.extra Packages to add to the default list of packages exported by the system bundle. String , ... -
org.osgi.framework.trust.repositories This property is used to configure trust repositories for the framework. The value is path of files.The file paths are separated by the pathSeparator defined in the File class. Each file path should point to a JKS key store. The framework will use the key stores as trust repositories to authenticate certificates of trusted signers. The key stores must only be used as read-only trust repositories to access public keys. The keystore must not have a password. String : ... -
org.osgi.framework.windowsystem Provide the name of the current window system. This can be used by the native code clause. String -

Knopflerfish Specified System Properties

Knopflerfish System properties should be specified using "-D".

Name Description Value type Default value
org.knopflerfish.framework.main.verbosity Verbosity level of the Main class starting the framework. 0 means few messages. Specify on the command line in order to see messages from the very beginning. Integer 0

Knopflerfish Specified Framework Properties

The recommendation is to use "-F" for Knopflerfish Framework properties but "-D" should also work.

Name Description Value type Default value
org.knopflerfish.framework.all_signed If set to true, we require that all bundles that are installed are signed. Boolean True
org.knopflerfish.framework.automanifest Flag to enable automatic manifest generation. If true, bundle manifest can be modified by a special configuration file. See javadoc for org.knopflerfish.framework.AutoManifest class for details. Boolean False
org.knopflerfish.framework.automanifest.config Configuration URL for automatic manifest generation. Only valid if org.knopflerfish.framework.automanifest=true. An URL starting with "!!" followed by path is refer to a resource on the classloader that have loaded the framework. String !!/automanifest.props
org.knopflerfish.framework.bundlestorage Storage implementation for bundles [file, memory] String file
org.knopflerfish.framework.bundlestorage.file.always_unpack When using file bundle storage, bundle jars can be unpacked or copied as-is. Unpacking leads to faster restart and class loading but takes longer for initial startup. If set to true, unpack all bundle jars. Boolean False
org.knopflerfish.framework.bundlestorage.file.jar_verifier_bug There is a bug when using file bundle storage, certificate and Oracle JRE (Java 6). This bug causes the JarInputStream to miss picking up certificates for files under the "META-INF" directory if they directly follow the META-INF signature related files. This causes KF to mark the bundle as not completly signed. To ignore problem set property to true. Boolean False
org.knopflerfish.framework.bundlestorage.file.reference When using file bundle storage, file: URLs can optionally be referenced only, not copied to the persistent area. If set to true, file: URLs are referenced only. Note: Individual bundles can be reference installed by using URLs of the syntax: reference:file:<path> This works even if the global reference flag is not enabled. Boolean False
org.knopflerfish.framework.bundlestorage.file.trusted Are the bundles stored in the file bundle storage to be trusted, if not signed bundles will be checked every time they are read. Untrusted storage leads to slower restart and class loading. If set to true, trust bundles in bundle storage. Boolean True
org.knopflerfish.framework.bundlestorage.file.unpack Most JVM requires that we unpack the bundle to access internal jars and native code. Setting this to true will unpack the jar if it contains internal jars or native code. If set to true, unpack needed bundle jars. Boolean True
org.knopflerfish.framework.bundlethread.timeout Use this proprty to set a limit on how long the framework will wait for a bundle's activator to complete and return from the start and stop methods. If the time-out occurs, the framework will interrupt the BundleThread that is executing the start or stop method and then optionally stop it or lower its priority, see property org.knopflerfish.framework.bundlethread.abort. A BundleException is thrown to indicate that start/stop of the bundle failed. If set to a positive integer, the value is used as time-out in seconds. If set to 0, no time out is used and the framework will wait indefinitely for the activator's start and stop methods to complete. Integer 0
org.knopflerfish.framework.bundlethread.abort If a bundle's start or stop method time-out (see property org.knopflerfish.framework.bundlethread.timeout) or if the bundle gets uninstalled before the method has returned, this property defines how to manage the bundle's start/stop thread. Possible values are:
"stop" Calls the stop() method of the bundle's thread
"minprio" Sets a minium priority of the bundle's thred
"ignore" Do nothing
String ignore
org.knopflerfish.framework.debug.automanifest Print debug output for automatic manifest actions. Boolean False
org.knopflerfish.framework.debug.bundle_resource When security is enabled, print information about resource lookups that are rejected due to missing permissions for the calling bundle. Boolean False
org.knopflerfish.framework.debug.certficates Print debug information about certificate handling. Boolean False
org.knopflerfish.framework.debug.classloader Print debug information from classloader Boolean False
org.knopflerfish.framework.debug.errors Print all FrameworkEvents of type ERROR Boolean False
org.knopflerfish.framework.debug.framework Print debug information about life-cycle events for the current framework instance. Boolean False
org.knopflerfish.framework.debug.hooks Print debug information about when service hooks are used current framework instance. Boolean False
org.knopflerfish.framework.debug.ldap Print debug information about LDAP filters Boolean False
org.knopflerfish.framework.debug.resolver Print debug information about resolver operation. Boolean False
org.knopflerfish.framework.debug.patch Print debug information about class patching Boolean False
org.knopflerfish.framework.debug.permissions Print debug information about permission evaluation. Boolean False
org.knopflerfish.framework.debug.print_with_do_privileged Surround all debug print-operations originating from setting org.knopflerfish.debug.* properties with a doPrivileged() wrapper. Boolean True
org.knopflerfish.framework.debug.startlevel Print debug information about startlevel service Boolean False
org.knopflerfish.framework.debug.service_reference When security is enabled, print information about service reference lookups that are rejected due to missing permissions for calling bundle. Boolean False
org.knopflerfish.framework.debug.url Print debug information about URL services Boolean False
org.knopflerfish.framework.is_doublechecked_locking_safe Is it safe to use double-checked locking or not. It is safe if JSR 133 is included in the running JRE. I.e., for Java SE if version is 1.5 or higher. Boolean True if value of the system property java.version ≥ 1.5, False otherwise
org.knopflerfish.framework.ldap.nocache Disable LDAP caching for simple filters. LDAP caching speeds up framework filters considerably, but uses more memory. Boolean False
org.knopflerfish.framework.main.class.activation A comma-separated list of locations of bundles whose Main-Class (set in manifest) should be used as activator if no BundleActivator is specified. The Main-Class will be used as activator if and only if the jar file does not specify a Bundle-Activator header and the bundle's location(see Bundle.getLocation) is found in the comma-separated list (case-sensitive).
> java -jar framework.jar
    -Forg.knopflerfish.framework.main.class.activation=\ 
    file:/foo/bar.jar,http://foo.com/bar.jar ...
String -
org.knopflerfish.framework.main.verbosity Verbosity level of the Main class starting the framework. 0 means few messages. Specify as a System property on the command line in order to see messages from the very beginning. Integer 0
org.knopflerfish.framework.main.xargs.writesysprops Properties defined using -Fname=value in xargs-files are available for bundles using BundleContext.getProperty(name). This property controls weather such properties shall also be exported as system properties or not. Boolean False
org.knopflerfish.framework.listener.n_threads Number of threads used to deliver events to asynchronous listeners. If the value is 0 then we will revert to the old behaviour and call all listeners synchronously. Integer 1
org.knopflerfish.framework.patch If true AND once the classpatcher_all-N.N.N.jar bundle is installed and started, run time class patching will be enabled for all classes loaded afterwards. Boolean False
org.knopflerfish.framework.patch.configurl URL to class patch config file. Only used when class patching is enabled. This is used as a fallback if a bundle does not specify a Bundle-ClassPatcher-Config manifest header. "!!" is used to read resources from the system class path "!" can be used to read bundle resources. String !!/patches.props
org.knopflerfish.framework.patch.dumpclasses If true and class patching is enabled, dump all modified classes to a directory. Boolean False
org.knopflerfish.framework.patch.dumpclasses.dir If dumpclasses is enabled, specifies a directory where to dump modified classes String patchedclasses
org.knopflerfish.framework.readonly Controls if the framework should skip saving state changes permantly under framework directory. This means that if we are running with the default "file" bundle storage then new bundles must be installed as a referenced file URL (see property org.knopflerfish.framework.bundlestorage.file.reference). This also implies that no data storage will be available to bundles. Boolean False
org.knopflerfish.framework.service.conditionalpermissionadmin Controls if the framework should register the Conditional Permission Admin service. Boolean True
org.knopflerfish.framework.service.permissionadmin Controls if the framework should register the Permission Admin service. Boolean True
org.knopflerfish.framework.strictbootclassloading If set to true, use strict rules for loading classes from the boot class loader. If false, accept class loading from the boot class path from classes themselves on the boot class, but which incorrectly assumes they may access all of the boot classes on any class loader (such as the bundle class loader). Setting this to true will, for example, result in broken serialization on the Sun JVM if bootdelegation does not exposes sun.* classes Boolean False
org.knopflerfish.framework.system.packages.base An alternative to setting org.osgi.framework.system.packages. When this property is used the list of packages given will be appended with the default set of osgi-packages for the current framework and then used as the exports of the system bundle. String , ... -
org.knopflerfish.framework.system.packages.file File containing list of packages exported by the system bundle. String -
org.knopflerfish.framework.system.packages.version Name for selected exporting profile of system packages. String MAJOR.MINOR from system property "java.version"
org.knopflerfish.framework.usingwrapperscript If set to "true", KF will assume that it has been started with the "kf2" shell script, and that it will be restarted if KF exits with exit code = 200. Required to be able to use new KF2 features such as extension bundles. This flag is set to "true" by the "kf2" shell script. Boolean False
org.knopflerfish.framework.validator A list of which certificate validators to use. Currently available are JKSValidator and SelfSignedValidator. If no validator is to be used, set to "null" or "none". String JKSValidator if org.osgi.framework.trust.repositories Is set, otherwise none
org.knopflerfish.framework.validator.date Date to use when validating certificates. The date is specifed in the current locales short date format. If no date is specified use the current date and time. String -
org.knopflerfish.framework.validator.jks.ca_certs File name of java keystore used by JKSValidator. Used if org.osgi.framework.trust.repositories isn't set. String $JAVA_HOME/lib/security/cacerts
org.knopflerfish.framework.validator.jks.ca_certs_password Password to java keystore used by JKSValidator. String changeit
org.knopflerfish.framework.validator.jks.cert_provider Provider for CertificateFactory to use. String -
org.knopflerfish.framework.main.write.fwprops.xargs Property that tells the Knopflerfish Main if it shall write a fwprops.xargs file with all framework properties inside the framework directory on startup or not. Boolean True
org.knopflerfish.gosg.jars Semicolon separated list of base URLs for relative install commands URL;... URLs to the "jars" folder and all its sub-folders and fwresource:jars/
org.knopflerfish.startlevel.compat Set to true indicates startlevel compatibility mode. All bundles and current start level will be 1. Boolean True
org.knopflerfish.startlevel.use Use the Start Level service. If start level is not used then we do not create a non daemon thread that will keep a JVM with only daemon threads alive. Boolean True
org.knopflerfish.osgi.setcontextclassloader If set to "true", set the bundle startup thread's context class loader to the bundle's class loader. This is useful for checking if an external lib will work better with a wrapped startup. It doesn't set the context classloader for event callbacks. Note that setting the context classloader is not mandated by OSGi, and might introduce dependencies on the KF framework, so this flag should only be enabled for testing purposes. Boolean False
org.knopflerfish.servicereference.valid.during.unregistering If set to false, then the service reference can not be used to fetch an instance of the service during delivery and handling of the UNREGISTERING service event. The behaviour specified in the OSGi R4 v4.0.1 specification (and later), according to a clarification done by CPEG February 2008, is that it shall be possible to obtain a service instance during delivery of UNREGISTERING events thus this property now defaults to true.

Note that independent of this setting the service reference of an UNREGISTERING service will not be returned by any of the methods searching for service references provided by the BundleContext interface.

Boolean True
org.knopflerfish.osgi.registerserviceurlhandler Flag for installing OSGi service based URL handlers. Since the URL handler can only be installed once, there might be cased where some external entity (not OSGi) sets this. In this case, the OSGi handler can be disabled by setting Boolean True
knopflerfish-osgi-5.1.0/osgi/framework/TODO0000644000175000017500000000037412346513664017612 0ustar felixfelix-- I = Improvement M = Missing -- I Refactor Archive.java in bundlestorage when it come to searching for entries. I Refactor classloader to better handle recursive listEntries. I Check ResolveHooks and packages lock I More SystemBundle headers knopflerfish-osgi-5.1.0/osgi/framework/libs/0000755000175000017500000000000012475375720020051 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/framework/libs/asm-license.txt0000644000175000017500000000316112346513666023013 0ustar felixfelixThis is the Licence for the ASM library, from http://asm.ow2.org/ ---------------------------------------------------------------------- Copyright (c) 2000-2005 INRIA, France Telecom All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. knopflerfish-osgi-5.1.0/osgi/props.xargs0000644000175000017500000000650012346515370017327 0ustar felixfelix# # Common properties used by different init.xargs files # #-Forg.osgi.framework.storage=fwdir # The Service Platform ID should be used by bundles needing to # a unique ID for the platform itself -Forg.osgi.provisioning.spid=knopflerfish # Initial startup verbosity, 0 is low verbosity #-Forg.knopflerfish.framework.main.verbosity=0 # Security #-Forg.osgi.framework.security=osgi #-Forg.knopflerfish.framework.all_signed=false #-Forg.knopflerfish.framework.validator=JKSValidator # File storage properties #-Forg.knopflerfish.framework.bundlestorage.file.trusted=false #-Forg.knopflerfish.framework.bundlestorage.file.unpack=false #-Forg.knopflerfish.framework.bundlestorage.file.always_unpack=true -Forg.knopflerfish.framework.bundlestorage.file.reference=true # JKSValidator properties (JVM default if not set). #-Forg.knopflerfish.framework.validator.jks.ca_certs= #-Forg.knopflerfish.framework.validator.jks.ca_certs_password= # Avoid java verifier bug #-Forg.knopflerfish.framework.bundlestorage.file.jar_verifier_bug=true # Various debug flags #-Forg.knopflerfish.framework.debug.resolver=true -Forg.knopflerfish.framework.debug.errors=true #-Forg.knopflerfish.framework.debug.warnings=true #-Forg.knopflerfish.framework.debug.classloader=true #-Forg.knopflerfish.framework.debug.startlevel=true #-Forg.knopflerfish.framework.debug.ldap=true #-Forg.knopflerfish.framework.debug.service_reference=true #-Forg.knopflerfish.framework.debug.bundle_resource=true #-Forg.knopflerfish.framework.debug.permissions=true #-Forg.knopflerfish.framework.debug.lazy_activation=true #-Forg.knopflerfish.framework.debug.framework=true #-Forg.knopflerfish.framework.debug.certificates=true # Complete comma-separated list of packages exported by the system bundle # #-Forg.osgi.framework.system.packages= # Comma-separated list of packages exported by the system bundle. The # osgi packages provided by the framework will be added to this list. # Only used when org.osgi.framework.system.packages is not set. # #-Forg.knopflerfish.framework.system.packages.base=javax.swing,javax.swing.tree, javax.swing.table, javax.swing.plaf.metal, javax.swing.plaf.basic, javax.swing.plaf, javax.swing.filechooser, javax.swing.event, javax.swing.border, javax.accessibility # Comma-separated list of packages to be added to the set of packages # exported by the system bundle. # #-Forg.osgi.framework.system.packages.extra= # Comma-separated list of packages that must be loaded by system classloader # #-Forg.osgi.framework.bootdelegation=* # If set to true, use strict rules for loading classes from the boot # class loader. # If false, accept class loading from the boot class path from classes # themselves on the boot class. # Default is false # #-Forg.knopflerfish.framework.strictbootclassloading=false # If set to true, export all framework properties as system properties. # #-Forg.knopflerfish.framework.main.xargs.writesysprops=false # Web server properties -Forg.knopflerfish.http.dnslookup=false -Forg.osgi.service.http.port=8080 # Log service properties -Forg.knopflerfish.log.out=false -Forg.knopflerfish.log.level=info -Forg.knopflerfish.log.grabio=true -Forg.knopflerfish.log.file=true -Forg.knopflerfish.log.memory.size=250 #consoletelnet properties -Forg.knopflerfish.consoletelnet.user=admin -Forg.knopflerfish.consoletelnet.pwd=admin -Forg.knopflerfish.consoletelnet.port=2323 knopflerfish-osgi-5.1.0/osgi/minimal.xargs0000644000175000017500000000127612346515370017617 0ustar felixfelix-Dorg.knopflerfish.framework.main.verbosity=0 -Dorg.knopflerfish.gosg.jars=file:jars/ -Forg.knopflerfish.framework.debug.resolver=false -Forg.knopflerfish.framework.debug.errors=true -Forg.knopflerfish.framework.debug.classloader=false -Forg.osgi.framework.system.packages.extra= -Forg.knopflerfish.startlevel.use=true -init -install log/log_api-5.0.0.jar -install console/console_api-4.0.1.jar -istart cm/cm_api-5.0.1.jar -istart log/log-5.0.0.jar -istart console/console-4.0.1.jar -istart consoletty/consoletty-4.0.1.jar -istart frameworkcommands/frameworkcommands-4.0.1.jar -istart logcommands/logcommands-5.0.0.jar -istart useradmin/useradmin_api-4.1.1.jar -launch knopflerfish-osgi-5.1.0/osgi/test-restart1.xargs0000644000175000017500000000141212346515440020701 0ustar felixfelix# # Startup file for framework restart testing # # NOTE: The base URLs for bundles assumes that the current working # directory is the osgi-direcotry when this xargs-file is used. # # List of test IDs -Forg.knopflerfish.junit_runner.tests=RestartSetupTestSuite # true means "quit framework when all tests are run" -Forg.knopflerfish.junit_runner.quit=true # true means wait for complete framework start until run -Forg.knopflerfish.junit_runner.wait=true -Dorg.knopflerfish.gosg.jars=file:jars/;file:test_jars/ -init -initlevel 1 -istart junit/junit_all-3.8.1.kf4-001.jar # the test cases -initlevel 5 -istart restart_test/restart_test-1.0.0.jar # the test case runner bundle. -initlevel 20 -istart junit_runner/junit_runner_all-4.0.0.jar -startlevel 20 -launch knopflerfish-osgi-5.1.0/osgi/example_jars/0000755000175000017500000000000012475375714017600 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/example_jars/demo1/0000755000175000017500000000000012475375720020602 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/example_jars/cpaexample_caller/0000755000175000017500000000000012475375720023236 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/example_jars/cpaexample_user/0000755000175000017500000000000012475375720022752 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/example_jars/cpaexample_admin/0000755000175000017500000000000012475375720023064 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/example_jars/demo1client/0000755000175000017500000000000012475375720022001 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/example_jars/rxtx_echo/0000755000175000017500000000000012475375720021600 5ustar felixfelixknopflerfish-osgi-5.1.0/osgi/minimal.xargs.in0000644000175000017500000000120412346513674020220 0ustar felixfelix-Dorg.knopflerfish.framework.main.verbosity=0 -Dorg.knopflerfish.gosg.jars=$(GOSG_JARS) -Forg.knopflerfish.framework.debug.resolver=false -Forg.knopflerfish.framework.debug.errors=true -Forg.knopflerfish.framework.debug.classloader=false -Forg.osgi.framework.system.packages.extra= -Forg.knopflerfish.startlevel.use=true -init -install @log_api-N.N.N.jar@ -install @console_api-N.N.N.jar@ -istart @cm_api-N.N.N.jar@ -istart @log-N.N.N.jar@ -istart @console-N.N.N.jar@ -istart @consoletty-N.N.N.jar@ -istart @frameworkcommands-N.N.N.jar@ -istart @logcommands-N.N.N.jar@ -istart @useradmin_api-N.N.N.jar@ -launch knopflerfish-osgi-5.1.0/osgi/headless.xargs0000644000175000017500000000613412346515370017757 0ustar felixfelix# # Generated from template.xargs # Knopflerfish release 5.1.0 # # load common properties -xargs props.xargs # Semicolon seprated list of base URLs for searching (completing) # bundle URLs in "-install URL" command line options and in the console. -Forg.knopflerfish.gosg.jars=file:jars/ # Comma seprated list of OSGi Repository xml URLs for instantiating # RepositoryServices -Forg.knopflerfish.repository.xml.urls=file:jars/index.xml,http://www.knopflerfish.org/releases/current/osgi/jars/index.xml ## Basic KF bundles -initlevel 1 -install log/log_all-5.0.0.jar -install cm/cm_all-5.0.1.jar -install console/console_all-4.0.1.jar -install component/component_all-5.0.3.jar -install event/event_all-4.0.1.jar -install prefs/prefs_all-4.0.2.jar #-istart trayicon_fw/trayicon_fw-4.0.0.jar ## Some library bundles -initlevel 2 -install util/util-4.1.0.jar -install crimson/crimson-2.1.0.kf4-001.jar -install jsdk/jsdk_api-2.5.0.kf3-2.jar -install kxml/kxml-2.3.0.kf4-001.jar # The Bundle repo commands and desktop plugin -install repository_xml/repository_xml_all-1.0.2.jar -install repositorymanager/repositorymanager_all-1.2.0.jar #-install repository_desktop/repository_desktop_all-1.1.1.jar ## More basic KF bundles -initlevel 3 -install device/device_all-4.0.1.jar -install useradmin/useradmin_all-4.1.1.jar -initlevel 4 -install http/http_all-4.0.5.jar ## console command bundles -initlevel 5 -install frameworkcommands/frameworkcommands-4.0.1.jar -install logcommands/logcommands-5.0.0.jar -install cm_cmd/cm_cmd-5.0.1.jar -install repositorycommands/repositorycommands-1.1.1.jar -install scrcommands/scrcommands-4.0.1.jar -install consoletty/consoletty-4.0.1.jar -install consoletelnet/consoletelnet-4.0.1.jar -initlevel 6 #-install remotefw/remotefw_api-4.0.0.jar #-install desktop/desktop_all-5.0.1.jar -initlevel 7 -install httproot/httproot-4.0.0.jar -startlevel 7 # Start of these bundles are delayed since this makes start # order dependencies much easier -start log/log_all-5.0.0.jar -start crimson/crimson-2.1.0.kf4-001.jar -start cm/cm_all-5.0.1.jar -start console/console_all-4.0.1.jar -start component/component_all-5.0.3.jar -start event/event_all-4.0.1.jar -start prefs/prefs_all-4.0.2.jar -start device/device_all-4.0.1.jar -start useradmin/useradmin_all-4.1.1.jar -start repository_xml/repository_xml_all-1.0.2.jar -start repositorymanager/repositorymanager_all-1.2.0.jar #-start repository_desktop/repository_desktop_all-1.1.1.jar -start consoletty/consoletty-4.0.1.jar -start consoletelnet/consoletelnet-4.0.1.jar -start frameworkcommands/frameworkcommands-4.0.1.jar -start logcommands/logcommands-5.0.0.jar -start cm_cmd/cm_cmd-5.0.1.jar -start repositorycommands/repositorycommands-1.1.1.jar -start scrcommands/scrcommands-4.0.1.jar #-start desktop/desktop_all-5.0.1.jar -start http/http_all-4.0.5.jar -start httproot/httproot-4.0.0.jar # Uncomment the following line to add Resolver support # -istart http://repo2.maven.org/maven2/org/apache/felix/org.apache.felix.resolver/1.0.0/org.apache.felix.resolver-1.0.0.jar knopflerfish-osgi-5.1.0/ant/0000755000175000017500000000000012475375714014747 5ustar felixfelixknopflerfish-osgi-5.1.0/ant/android.xml0000644000175000017500000000772712346513674017122 0ustar felixfelix knopflerfish-osgi-5.1.0/ant/xargs.xml0000644000175000017500000001061112346513674016610 0ustar felixfelix knopflerfish-osgi-5.1.0/ant/lib/0000755000175000017500000000000012475375720015512 5ustar felixfelixknopflerfish-osgi-5.1.0/ant/bundle_junit.xml0000644000175000017500000000655012346513674020155 0ustar felixfelix knopflerfish-osgi-5.1.0/ant/bundlebuild_include.xml0000644000175000017500000000513112346513674021461 0ustar felixfelix knopflerfish-osgi-5.1.0/ant/build_example.xml0000644000175000017500000000725212346513674020305 0ustar felixfelix knopflerfish-osgi-5.1.0/ant/readme.txt0000644000175000017500000000662112346513674016746 0ustar felixfelixThis directory contains ant related code ant build files. Ant version 1.7 or higher is required. build_example.xml Example of bundle build.xml bundlebuild.xml ant build file to be imported by build.xml when building a bundle. bundlebuild_include.xml Left for backwards compatibility allowing older build-files to function without change. ant build file to be included (using an external entity) in build.xml. bundletasks.xml ant build file included by bundlebuild_include.xml Defines and compiles the bundle build tasks. html_template HTML templates for generated bundle docs src source code for bundle build task Note: As of Knopflerfish 2.0 all the properties used to specify the bundle manifest have been renamed. The new naming scheme gives three major advantages: 1 The properties can now be specified in a bundle manifest template file, named bundle.manifest, that may be created using the Knopflerfish Eclipse plug in while their values are still available for use in the ant build script. 2 You can now add any manifest header you like to the generated bundle manifest (previously there where only support for a fixed predefined set of manifest attributes). 3 Easy to remember mapping from ant property name to bundle manifest attribute name. To get the name of the ant property that corresponds to the manifest attribute named "Xy-Zz" simply add the prefix "bmfa." to it. E.g., Manifest Attribute name ant property name ======================= ================= Bundle-Name bmfa.Bundle-Name Bundle-SymbolicName bmfa.Bundle-SymbolicName Bundle-Version bmfa.Bundle-Version Bundle-Classpath bmfa.Bundle-Classpath and so on. The default prefix, "bmfa", is a short hand for Bundle ManiFest Attribute. To add a non-standard attribute to the generated manifest simple create a property with a name that starts with "bmfa." followed by the manifest attribute name. E.g., the property definition will add the attribute Main-Class: org.knopflerfish.Main to all the bundle manifests generated from the build file it was defined in. Another method to do this is to create a template bundle manifest file that contains the main section attribute definition you want. The template manifest file shall be named "bundle.manifest" and placed in the same directory as the build.xml file that shall use it. The format of the manifest template file is that of a normal manifest file with one exception: Line length must not obey the 72 characters per line requirement. The character encoding of the template manifest file is expected to be UTF-8, but you may specify another encoding in the build.xml file. The relaxed line length requirement makes it possible to format the template manifest file in a readable way. E.g., the Import-Package and Export-Package can be written with one package per line as in: Import-Service: org.knopflerfish.service.log.LogService, org.osgi.service.cm.ManagedService, org.osgi.service.cm.ManagedServiceFactory, org.osgi.service.cm.ConfigurationPlugin Export-Package: org.osgi.service.cm;version=1.2.0, org.knopflerfish.shared.cm;version=1.0 knopflerfish-osgi-5.1.0/ant/build.xml0000644000175000017500000000214212346513674016563 0ustar felixfelix knopflerfish-osgi-5.1.0/ant/console_interactions.xml0000644000175000017500000001612512346513674021716 0ustar felixfelix ogin: ${console.user} assword: ${console.pwd} ${cmd} knopflerfish-osgi-5.1.0/ant/src/0000755000175000017500000000000012475375714015536 5ustar felixfelixknopflerfish-osgi-5.1.0/ant/src/org/0000755000175000017500000000000012475375714016325 5ustar felixfelixknopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/0000755000175000017500000000000012475375714021017 5ustar felixfelixknopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/0000755000175000017500000000000012475375714021601 5ustar felixfelixknopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/0000755000175000017500000000000012475375714023405 5ustar felixfelixknopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/0000755000175000017500000000000012475375714024656 5ustar felixfelixknopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleLocator.java0000644000175000017500000007226612346513674030267 0ustar felixfelix/* * Copyright (c) 2008-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.SortedSet; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.PatternSet; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.ResourceCollection; import org.osgi.framework.Version; import org.knopflerfish.ant.taskdefs.bundle.BundleArchives.BundleArchive; /** * Determines a sub-set of bundles from a given file set. The resulting set of * bundles will only contain the highest version of each bundle in the original * file set. The resulting set of bundles may then be used in several ways. * *

* * An OSGi version specification used below is a string on the format * Major.Minor.Micro.Qualifier * where major, minor and micro are integers, and all parts of the version * except major are optional. See * {@link org.osgi.framework.Version#Version(java.lang.String) * org.osgi.framework.Version} for details. The version formatting used by Maven * 2 is also recognized, i.e., a '‑' between the micro and qualifier * fields: * Major.Minor.MicroQualifier. * *

* * Given a partial bundle name and a file set with bundles, this task may be * used to select the bundle with the highest version number and name that * matches. E.g., * *

 *   <bundle_locator bundleName="http" property="http.path">
 *     <fileset dir="${jars.dir}">
 *       <include name="**/*.jar"/>
 *     </fileset>
 *   </bundle_locator>
 * 
* * will set the project property http.path to the absolute path of the * highest version of the bundle named http within the given file set. * By setting the bundleName to http-1.N.N the task will * select the highest version of the http-bundle with the restriction * that the Major part of the version number of the selection must be exactly * 1. * *

* * The bundle locator task can also iterate over a path and replace all * non-existing file resources in it that either has a name ending with * -N.N.N.jar or that is the symbolic name of a bundle with the * corresponding bundle with the highest version of the matching bundle from the * given file set. Non-existing path entries that does not end in .jar * or .zip that does not match a symbolic bundle name will trigger a * build error if failOnMissingBundles is set to true. The * same applies to path entries ending with -N.N.N.jar that does not * yield a match. The search may be further restricted to specific versions by * replacing the N in the resource name with a specific version number. * *

 *   <bundle_locator classPathRef="bundle.path"
 *                   newClassPathId="bundle.path.Expanded"
 *                   failOnMissingBundles="true">
 *     <fileset dir="${jars.dir}">
 *       <include name="**/*.jar"/>
 *     </fileset>
 *   </bundle_locator>
 * 
* * this will build a new path added to the project with the id * bundle.path.Expanded. The new path will be a copy of the original, * bundle.path, but with all path elements with a name ending in * -N.N.N.jar replaced with the corresponding match or removed if no * match was found. * *

* * Another usage of the bundle locator task is to ensure that only the highest * version of a bundle is matched by a certain pattern set. * *

 *   <bundle_locator patternSetId="my.ps.exact">
 *     <fileset dir="${jars.dir}">
 *       <patternset refid="my.ps"/>
 *     </fileset>
 *   </bundle_locator>
 * 
* * Here the original pattern set my.ps is used to find bundles in the * directory jars.dir, if more than one version of a bundle matches * then only the one with the highest version will be selected. A new pattern * set based on the matches is created and saved in the project under the name * my.ps.exact. This pattern set will contain one include pattern for * each matching bundle. The value of the include pattern is the relative path * of that bundle (relative to the root directory of the file set that the * matching bundle originates from). * *

* * Finally this task may also be used to create a properties file suitable for * using as a replacement filter that will replace bundle names on the form * @name-N.N.N.jar@ or bundle symbolic names on the form * @bundleSymbolicName.jar@ with the relative path within the given * file set of the bundle with the given name and the highest version. * *

 *   <bundle_locator replacefilterfile="my.filter">
 *     <fileset dir="${jars.dir}">
 *       <patternset refid="my.ps"/>
 *     </fileset>
 *   </bundle_locator>
 * 
* * *

Parameters

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
bundleName * The name of the bundle to look for. There are several ways to specify the * bundle name. *
    *
  • If the bundle to locate is named like * name‑OSGi version spec.jar, then the value of the * bundleName-attribute may be specified as name. *
  • The symbolic name of the bundle. *
* * A property with name given by the value of the attribute property * with the location (absolute path) of the bundle as value is added to the * project. * *
No. No default value.
bundleNames * * A comma separated list of bundle names to look for. There are several ways to * specify the bundle name. *
    *
  • If a bundle to locate is named like * name‑OSGi version spec.jar, then the value of the * bundleName-attribute may be specified as name. *
  • The symbolic name of the bundle. *
* * The absolute path of the matching bundle will be stored in a project property * named bap.bundleName. * *

* * If the attribute property is set its value will be used as prefix * for the property names in stead of the default bap. * *

No. No default value.
property * The name of a project property to be assigned the location of the matching * bundle.Yes when bundleName is specified.
* No default value.
classPathRef * The reference name (id) of a path-structure to transform.No. No default value.
newClassPathId * The transformed path-structure will be added to the current project using * this name (id).Yes when classPathRef is specified.
* No default value.
patternSetId * Create a pattern set from the set of bundles that are selected by the nested * file set(s) and add it to the project using this name (id).No. No default value.
bundlePath * Specifies a bundle search path like the one specified in xargs files by the * framework property org.knopflerfish.gosg.jars. Path elements are * URLs separated by ';'. Setting this property will add a file set with an * includes set to ∗∗/∗.jar for each path element * that is defined as a file-URL.No. No default value.
baseDir * Path to directory to use as base-directory to complete relative * file URLs in the bundlePath. * No. Defaults to the empty string, i.e., the current * working directory.
failOnMissingBundles * * If an entry with a file name like bundleName-N.N.N.jar is * found on the classpath to transform and there is no matching bundle in the * file set then a build failure is triggered if this attribute is set to * true. Same applies if the given bundleName or one of the * given bundleNames does not yield a match. * * No.
* Defaults to true.
extendedReplaceFilter * * If set to true then the replace filter generated by the * replacefilter attribute will be extended with the following set of * replacements for each matching bundle. * * * * * * * * * * * * * * * * * * *
KeyValue
* @bundleName‑N.N.N.name@
* @Bundle‑SymbolicName.name@
* * The bundle symbolic name from the manifest. For bundles with manifest version * 1 (i.e., pre OSGi R4 bundles) the bundle name. * *
* @bundleName‑N.N.N.version@
* @Bundle‑SymbolicName.version@
* * The bundle version from the manifest. * *
* @bundleName‑N.N.N.location@
* @Bundle‑SymbolicName.location@
* * The absolute path of the bundle. * *
* *
No.
* Defaults to false.
replacefilterfile * * Creates a property file suitable for use as the replacefilterfile * argument in the replace-task. The generated file will contain two entries for * each matching bundle. * * * * * * * * * * *
KeyValue
* @bundleName‑N.N.N.jar@
* @Bundle‑SymbolicName.jar@
* * The relative path to the bundle from the root-directory of the file set that * the matching bundle originates from. * *
* *
No.
* No default value.
* *

Parameters specified as nested elements

*

fileset

* * (required)
*

* The jar files to match against must be specified as a fileset. *

* */ public class BundleLocator extends Task { private final static String PROPS_PREFIX = "bap."; private final List filesets = new ArrayList(); private BundleArchives bas; private String bundleName = null; private String bundleNames = null; private String property = null; private Reference classPathRef = null; private String newClassPathId = null; private String patternSetId = null; private boolean failOnMissingBundles = true; private File replacefilterfile = null; private boolean extendedReplaceFilter= false; private String bundlePath = null; private File baseDir = new File("."); public BundleLocator() { } public void setProperty(String s) { this.property = s; } public void setBundleName(String s) { this.bundleName = s; } public void setBundleNames(String s) { this.bundleNames = s; } public void addFileset(FileSet set) { filesets.add(set); } public void setClassPathRef(Reference r) { classPathRef = r; } public void setNewClassPathId(String s) { newClassPathId = s; } public void setPatternSetId(String s) { patternSetId = s; } public void setFailOnMissingBundles(boolean b) { failOnMissingBundles = b; } public void setExtendedReplaceFilter(boolean b) { extendedReplaceFilter = b; } public void setReplacefilterfile(File f) { replacefilterfile = f; } public void setBundlePath(String bundlePath) throws BuildException { this.bundlePath = bundlePath; log("bundlePath='" + bundlePath + "'.", Project.MSG_DEBUG); } public void setBaseDir(File f) { baseDir = f; } private URL getBaseURL() { try { return baseDir.toURI().toURL(); } catch (final MalformedURLException e) { throw new BuildException("Invalid baseDir, '" + baseDir + "'.", e); } } private void processBundlePath() { if (null!=bundlePath && 0true if a bundle version with wild-card is * part of the bundle name, false otherwise. */ static private boolean isBundleNameWithWildcardVersion(final String name) { final Pattern pattern = Pattern.compile ("^(.+)-(\\d+|N)(?:|\\.(\\d+|N)(?:|\\.(\\d+|N)(?:|\\.([-_0-9a-zA-Z]+))))(?:.jar|.zip)$"); final Matcher matcher = pattern.matcher(name); if (matcher.matches()) { for (int i=2; i<6; i++) { final String s = matcher.group(i); if ("N".equals(s)) { return true; } } } return false; } /** * Get the bundle archive for the given bundle name. * *
    *
  1. Remove any .jar or .zip suffix form the name. *
  2. If name is a bundle name prefix return the * highest version of that bundle. *
  3. If name is a symbolic bundle name return the * highest version of that bundle. *
  4. Try to find a bundle version as part if the bundle name, * use that version to select the bundle. *
* * @param name Name of the bundle to look for. May contain a version * suffix. * * @return null if no matching bundle archive was found. */ private BundleArchives.BundleArchive getBundleArchive(String name) { log("getBundleArchive("+name +")", Project.MSG_DEBUG); if (null==name || 0==name.length()) { return null; } if (name.endsWith(".jar")) { name = name.substring(0, name.length()-4); } if (name.endsWith(".zip")) { name = name.substring(0, name.length()-4); } if (name.endsWith("-N.N.N")) { name = name.substring(0, name.length()-6); } SortedSet baSet = bas.bnToBundleArchives.get(name); if (null==baSet) { baSet = bas.bsnToBundleArchives.get(BundleArchives.encodeBundleName(name)); } if (null!=baSet) { final BundleArchives.BundleArchive ba = baSet.last(); log("getBundleArchive("+name +")->"+ba, Project.MSG_VERBOSE); return ba; } final Pattern pattern = Pattern.compile ("^(.+)-(\\d+|N)(?:|\\.(\\d+|N)(?:|\\.(\\d+|N)(?:|\\.([-_0-9a-zA-Z]+))))$"); final Matcher matcher = pattern.matcher(name); if (matcher.matches()) { name = matcher.group(1); String version = ""; int level = -1; for (int i=2; i<6; i++) { final String s = matcher.group(i); if (null==s || "N".equals(s)) {// Done; break; } level++; if (version.length()>0) { version += "."; } version += s; } if (level<0) { return getBundleArchive(name, null, null); } else { final Version min = new Version(version); Version max = null; switch(level) { case 0: max = new Version(min.getMajor()+1, 0, 0,""); break; case 1: max = new Version(min.getMajor(), min.getMinor()+1, 0,""); break; case 2: max = new Version(min.getMajor(), min.getMinor(), min.getMicro()+1, ""); break; default: max = min; } return getBundleArchive(name, min, max); } } else { log("getBundleArchive(" +name +") no valid version found in the name.", Project.MSG_VERBOSE); } return null; } /** * Get the bundle archive with the highest version within the given * interval for the given bundle. * * @param name Name of the bundle to look for. Either the part of * the file name that comes before the file version or * the bundle symbolic name. * @param min The lowest acceptable version number (inclusive). * @param max The highest acceptable version number (exclusive). If * null the highest version of this bundle will be * selected. * @return null if no matching bundle archive was found. * */ private BundleArchives.BundleArchive getBundleArchive(final String name, Version min, final Version max) { SortedSet baSet = bas.bnToBundleArchives.get(name); if (null==baSet) { baSet = bas.bsnToBundleArchives.get(BundleArchives.encodeBundleName(name)); } BundleArchives.BundleArchive ba = null; if (null!=baSet) { if (null==max) { // Select highest available version ba = baSet.last(); } else { if (null==min) { min = Version.emptyVersion; } for (final Object element : baSet) { final BundleArchives.BundleArchive candBa = (BundleArchives.BundleArchive) element; if (candBa.version.compareTo(min)<0) { continue; } if (candBa.version.compareTo(max)>=0) { break; } ba = candBa; } } } log("getBundleArchive("+name +", " +min +", " +max +")->"+ba, Project.MSG_VERBOSE); return ba; } private void setProperty() { if (null!=property) { setProperty(bundleName, property); } else { throw new BuildException ("The attribute 'bundleName' requires 'property'"); } } private void setProperty(final String bn, final String propName) { log("Searching for a bundle with name '" +bn +"'.", Project.MSG_DEBUG); final BundleArchives.BundleArchive ba = getBundleArchive(bn); if (ba!=null) { getProject().setProperty(propName, ba.file.getAbsolutePath()); log(propName +" = " +ba.file, Project.MSG_VERBOSE); } else { final int logLevel = failOnMissingBundles ? Project.MSG_ERR : Project.MSG_INFO; log("No bundle with name '" +bn +"' found.", logLevel); log("Known bundles names: " +bas.getKnownNames(), logLevel); if (failOnMissingBundles) { throw new BuildException("No bundle with name '" +bn+"' found."); } } } private void setProperties() { final String prefix = null==property ? PROPS_PREFIX : property; final StringTokenizer st = new StringTokenizer(bundleNames, ","); while (st.hasMoreTokens()) { final String bn = st.nextToken().trim(); setProperty(bn, prefix +bn); } } private void transformPath() { final Path newPath = new Path(getProject()); log("Updating bundle paths in class path reference '" +classPathRef.getRefId() +"'.", Project.MSG_DEBUG); String[] pathElements = null; try { final Path path = (Path) classPathRef.getReferencedObject(); pathElements = path.list(); } catch (final BuildException e) { // Unsatisfied ref in the given path; can not expand. // Make the new path a reference to the old one. log("Unresolvable reference in '" +classPathRef.getRefId() +"' can not expand bundle names in it.", Project.MSG_WARN); newPath.setRefid(classPathRef); } if (null!=pathElements) { for (final String pathElement2 : pathElements) { final File pathElement = new File(pathElement2); boolean added = false; log("path element: "+pathElement, Project.MSG_DEBUG); if (!pathElement.exists()) { log("Found non existing path element: " +pathElement, Project.MSG_DEBUG); final String fileName = pathElement.getName(); final BundleArchives.BundleArchive ba = getBundleArchive(fileName); if (ba!=null) { final String filePath = ba.file.getAbsolutePath(); newPath.setPath(filePath); added = true; log(fileName +" => " +filePath, Project.MSG_VERBOSE); } else if (isBundleNameWithWildcardVersion(fileName)) { final int logLevel = failOnMissingBundles ? Project.MSG_ERR : Project.MSG_INFO; log("No match for '" +fileName +"' when expanding the path named '" +classPathRef.getRefId() +"'.", logLevel); log("Known bundles names: " +bas.getKnownNames(), logLevel); if (failOnMissingBundles) { throw new BuildException ("No bundle with name like '" +fileName+"' found."); } } else { log("No match for '" +fileName +"' when expanding the path named '" +classPathRef.getRefId() +"'.", Project.MSG_VERBOSE); } } if (!added) { newPath.setPath(pathElement.getAbsolutePath()); } } log(newClassPathId +" = " +newPath, Project.MSG_VERBOSE); } getProject().addReference(newClassPathId, newPath); } // end of transform path structure. private void createPatternSet() { final PatternSet patternSet = new PatternSet(); log("Creating a patternset for the bundles with id='" +patternSetId +"'.", Project.MSG_DEBUG); for (final Object element : bas.allBundleArchives) { final BundleArchives.BundleArchive ba = (BundleArchives.BundleArchive) element; patternSet.setIncludes(ba.relPath); log("Adding includes '" +ba.relPath +"'.", Project.MSG_DEBUG); } getProject().addReference(patternSetId, patternSet); } // end of create pattern set for bundles /** * Get the set of version patterns (partial versions) used in the * keys in replacement filters for the given version. * @param version The version to create patterns for. * @return Set of version patterns. */ private static String[] getVersionPatterns(Version version) { if (null==version) { return new String[]{"-N.N.N"}; } final String qualifier = version.getQualifier(); final boolean usesQualifier = null != qualifier && qualifier.length() > 0; final String[] res = new String[usesQualifier ? 5 : 4]; res[0] = "-N.N.N"; res[1] = "-" +version.getMajor() +".N.N"; res[2] = "-" +version.getMajor() +"." +version.getMinor() +".N"; res[3] = "-" +version.getMajor() +"." +version.getMinor() +"." +version.getMicro(); if (usesQualifier) { res[4] = "-" +version.getMajor() +"." +version.getMinor() +"." +version.getMicro() +"." +version.getQualifier(); } return res; } private void writeReplaceFilterFile() { final Properties props = new Properties(); for (final Object element : bas.allBundleArchives) { final BundleArchives.BundleArchive ba = (BundleArchives.BundleArchive) element; //Note: since the path is an URL we must ensure that '/' is used. final String relPath = ba.relPath.replace('\\','/'); final String[] versPatterns = getVersionPatterns(ba.version); if (null!=ba.bsn) { props.put("@" +ba.bsn +".jar@", relPath); if (extendedReplaceFilter) { props.put("@" +ba.bsn +".location@", ba.file.getAbsolutePath()); props.put("@" +ba.bsn +".name@", ba.bsn); props.put("@" +ba.bsn +".version@", ba.version.toString()); } for (final String versPattern : versPatterns) { final String prefix = "@" +ba.bsn +versPattern; props.put(prefix +".jar@", relPath); if (extendedReplaceFilter) { props.put(prefix +".location@", ba.file.getAbsolutePath()); props.put(prefix +".name@", ba.bsn); props.put(prefix +".version@", ba.version.toString()); } } } if (null!=ba.bundleName) { for (final String versPattern : versPatterns) { final String prefix = "@" +ba.bundleName +versPattern; props.put(prefix +".jar@", relPath); if (extendedReplaceFilter) { props.put(prefix +".location@", ba.file.getAbsolutePath()); if (null!=ba.bsn) { props.put(prefix +".name@", ba.bsn); } props.put(prefix +".version@", ba.version.toString()); } } } } OutputStream out = null; try { out= new FileOutputStream(replacefilterfile); props.store(out, "Bundle Version Expansion Mapping"); } catch (final IOException ioe) { log("Failed to write replacefilterfile, "+replacefilterfile +", reason: "+ioe, Project.MSG_ERR); throw new BuildException("Failed to write replacefilterfile",ioe); } finally { if (null!=out) { try { out.close(); } catch (final IOException _ioe) {} log("Created: "+replacefilterfile, Project.MSG_VERBOSE); } } } } knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleInfoTask.java0000644000175000017500000013605212346513674030374 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.Vector; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.types.resources.Restrict; import org.apache.tools.ant.types.resources.selectors.ResourceSelector; import org.apache.tools.ant.util.StringUtils; import org.osgi.framework.Constants; import org.osgi.framework.Version; import org.knopflerfish.ant.taskdefs.bundle.Util.HeaderEntry; /** * Task that analyzes sets of class files and jar files that will be * the contents of some bundle. The output is the set of packages to * be exported and imported by the bundle. Also tries to find any * class implementing org.osgi.framework.BundleActivator. * *

The set of files to analyze are specified as nested ant file sets.

* *

Parameters

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
importsName of property that will receive a comma-separated list * of all used packages. *

* If set to empty string, no property will be set. *

*

* Note: Some default packages are always added. These * defaults can be set using the defaultimports parameter. *

*
No.
Default value is ""
exportsName of property that will receive a comma-separated * list of all defined packages. *

* If set to empty string, no property will be set. *

*
No.
Default value is ""
activator * Name of property that will receive name of class which implements * org.osgi.framework.BundleActivator *

* If set to empty string, no property will be set. *

*

* If set to non-empty, and multiple activators are found, or * an activator not equal to any previous content in the named property * is found - a warning will be logged. *

*
No.
Default value is ""
stdimports * * Comma-separated list of package name prefixes for referenced * packages that shall not be included in the Import-Package * manifest attribute. * *

Example of packages to list in this attribute are *

    *
  • non-standard packages obtained via boot-delegation, *
  • packages exported by a required bundle, *
  • packages referenced to by code in nested jar-files that * are never used. *
* * The default value, "java.", is added to any given list * since packages starting with "java.*" shall never be * imported. They are always made available to the bundle by * delegation to the parent classloader. * *
* No.
* Default value is "java." *
defaultimports * Comma-separated list of packages that will be unconditionally * added to the derived set of packages that the bundle needs to * import. * * No.
* Default value is "" *
extraimports * Comma-separated list of package names that must be present * in the import list even though they are not explicitly * referenced from the bundles code. E.g., packages from which * all classes are loaded using reflection. * * No.
* Default value is "" *
importsOnly * If set to true then do not update Export-Package * manifest header. * No.
Default value is "false".
implicitImports * Flag for ensuring that each exported packages is included in the * import package list. * *

* If set to "true", the task will add all packages mentioned in * the property named by exports to the list of * imported packages in the property named by * imports if not already present. When this task * adds an import declaration for an exported package the import * entry will be given a version range starting with the version * from the export statement and up to the next major version * (exclusive). If some other version range is needed an * explicit import with that range should be added to the * bundle manifest template. * *

* This emulates the implicit import behavior present in OSGi R1-R3. *

*
* No.
* Default value is "true" *
serviceComponent * The value of the Service-Component manifest header. * *

If set to non-empty, leave the value of the activator * property untouched and do not complain if there are no class * that implements BundleActivator in the bundle. A bundle using * declarative services does not need a bundle activator but it * may have one anyhow.

* *
No.
Default value is ""
fragmentHost * The value of the Fragment-Host manifest header. * *

If set to non-empty (i.e., this is a fragment bundle), * leave the value of the activator property untouched and do * not complain if there are no class that implements * BundleActivator in the bundle.

* *
No.
Default value is ""
manifestVersion * The value of the Bundle-ManifestVersion manifest header. *

* If set to "2" and the uses attribute is also * true then a "uses" directive is computed and added * to each package in the Export-Package header generated by * this task. *

*
No.
Default value is "1" (pre OSGi R4 bundle).
uses * * If set to true then add / update uses * directive in the value of the Export-Package manifest header. *

* Note that uses-directives are not added for pre OSGi * R4 bundle. That is for bundle with manifestVersion * less than "2". *

*
No.
Default value is "true".
failOnExports * If an error is detected in the given export package header * and this attribute is set to true then a build * failure is trigger. * * No.
* Default value is "true" *
failOnImports * If an error is detected in the given import package header * and this attribute is set to true then a build * failure is trigger. * * No.
* Default value is "true" *
failOnActivator * If an error is detected in the given bundle activator header * and this attribute is set to true then a build * failure is trigger. * * No.
* Default value is "true" *
failOnClassPath * If a non-existing entry is detected in the given bundle * classpath header and this attribute is set to true * then a build failure is trigger. * * No.
* Default value is "true" *
addPackageinfoPackages * If set to true then add packages that contains * a packageinfo file, even if the package is empty. * * No.
* Default value is "false" *
* *

Parameters specified as nested elements

* * The set of provided packages (classes) is the union of the packages * found via <exports>, <exportsBundleClasspath> and * <impls>, <implsBundleClasspath> resource * collections. The import-package header is derived * (checked against) the set of provided packages. * *

exports

* * (optional)
* *

Nested <exports>-elements are filesets that will be * analyzed to determine the set of provided Java packages to be * exported by the bundle.

* *

Unsupported file types matched by the file set are ignored.

* *

exportsBundleClasspath

* * (optional)
* *

Nested <exportsBundleClasspath>-elements are instances of * {@link BundleClasspathTask} that will derive a list of file sets to * be analyzed to determine the set of provided Java packages to be * exported by the bundle.

* *

Unsupported file types matched by the file set are ignored.

* *

impls

* * (optional)
* *

Nested <impls>-elements are filesets that will be analyzed * to determine the set of private Java packages provided by the * bundle.

* *

Unsupported file types matched by the file set are ignored.

* *

implsBundleClasspath

* * (optional)
* *

Nested <implsBundleClasspath>-elements are instances of * {@link BundleClasspathTask} that will derive a list of file sets * are to be analyzed to determine the set of private Java packages * provided by the bundle.

* *

Unsupported file types matched by the file set are ignored.

* * *

Examples

* *

Check all imports and activator in implementation classes

* *

* This example assumes all implementation classes are in the package * test.impl.* *

* *
 *  <bundleinfo  activator = "bmfa.Bundle-Activator"
 *               imports   = "impl.import.package">
 *   <impls dir="classes" includes="test/impl/*"/>
 *  </bundleinfo>
 *  <echo message="imports   = ${impl.import.package}"/>
 *  <echo message="activator = ${bmfa.Bundle-Activator}"/>
 * 
* * *

Check all imports and exports in API classes

* *

* This example assumes all API classes are in the package * test.* *

* *
 *  <bundleinfo  exports  = "api.export.package"
 *               imports  = "api.import.package">
 *   <exports dir="classes" includes="test/*"/>
 *   <impls   dir="classes" includes="test/impl/*"/>
 *  </bundleinfo>
 *  <echo message="imports  = ${api.import.package}"/>
 *  <echo message="exports  = ${api.export.package}"/>
 * 
* */ public class BundleInfoTask extends Task { private final ArrayList implsResourceCollections = new ArrayList(); private final List exportsResourceCollections = new ArrayList(); private String importsProperty = ""; private String exportsProperty = ""; private String activatorProperty = ""; private String serviceComponent = ""; private String fragmentHost = ""; private Version manifestVersion = new Version("1"); private boolean bUses = true; private final Set stdImports = new TreeSet(); private boolean bPrintClasses = false; private boolean bImplicitImports = true; private boolean bSetActivator = true; private boolean bActivatorOptional = false; private boolean failOnExports = true; private boolean failOnImports = true; private boolean failOnActivator = true; private boolean failOnClassPath = true; private boolean bImportsOnly = false; private boolean addPackageinfoPackages = false; /** * The set of packages referenced by the included classes but not * provided by them. */ private final TreeSet importSet = new TreeSet(); /** * A set of packages used by the included classes but not * referenced from them. */ private final TreeSet extraImportSet = new TreeSet(); private final BundlePackagesInfo bpInfo = new BundlePackagesInfo(this); private final ClassAnalyserASM asmAnalyser = new ClassAnalyserASM(bpInfo, this); public BundleInfoTask() { setDefaultImports(""); setStdImports("java."); } /** * Set property receiving list of imported packages. */ public void setImports(String s) { this.importsProperty = s; } public void setPrintClasses(String s) { this.bPrintClasses = "true".equals(s); } public void setFailOnExports(boolean b) { this.failOnExports = b; } public void setFailOnImports(boolean b) { this.failOnImports = b; } public void setFailOnActivator(boolean b) { this.failOnActivator = b; } public void setFailOnClassPath(boolean b) { this.failOnClassPath = b; } public void setImplicitImports(String s) { this.bImplicitImports = "true".equals(s); } /** * Set default import set. * * @param packageList Comma-separated list of package names. */ public void setDefaultImports(String packageList) { importSet.clear(); if (null!=packageList) { packageList = packageList.trim(); if (0 v = StringUtils.split(packageList,','); for (final String pkg : v) { importSet.add(pkg.trim()); } } } } /** * Set the extra imports set. * * @param packageList Comma-separated list of package names. */ public void setExtraImports(String packageList) { extraImportSet.clear(); if (null!=packageList) { packageList = packageList.trim(); if (packageList.length()>0) { @SuppressWarnings("unchecked") final Vector v = StringUtils.split(packageList,','); for (final String pkg : v) { extraImportSet.add(pkg.trim()); } } } } /** * Set property receiving list of exported packages. */ public void setExports(String propName) { this.exportsProperty = propName; } /** * Set property receiving any BundleActivator class. */ public void setActivator(String propName) { this.activatorProperty = propName; } /** * Set name value of the Service-Component manifest header. */ public void setServiceComponent(String serviceComponent) { this.serviceComponent = serviceComponent; if (!BundleManifestTask.isPropertyValueEmpty(this.serviceComponent)) { // A bundle with service components may have an activator but it // is not recommended. bActivatorOptional = true; } } /** * Set value of the Fragment-Host manifest header. */ public void setFragmentHost(String fragmentHost) { this.fragmentHost = fragmentHost; if (!BundleManifestTask.isPropertyValueEmpty(this.fragmentHost)) { // A fragment bundle must not have an activator. bSetActivator = false; } } /** * Set value of the Bundle-ManifestVersion manifest header. */ public void setManifestVersion(String manifestVersion) { this.manifestVersion = new Version(manifestVersion); } /** * Shall uses directives be added to the Export-Package header or not. */ public void setUses(boolean uses) { this.bUses = uses; } /** * Set set of packages always imported. * * @param packageList Comma-separated list of package names. */ public void setStdImports(String packageList) { stdImports.clear(); stdImports.add("java."); @SuppressWarnings("unchecked") final Vector v = StringUtils.split(packageList,','); for (final String imp : v) { stdImports.add(imp.trim()); } } /** * Add a file set with classes that shall be exported. * * @param set The file set with exports to add. */ public void addConfiguredExports(FileSet set) { final Restrict restrict = new Restrict(); restrict.add(set); restrict.add(analyzeRestriction); exportsResourceCollections.add(restrict); } /** * Add file sets for classes exported from the bundle classpath. * * @param bcpt The bundle classpath that the bundle will have. */ public void addConfiguredExportsBundleClasspath(BundleClasspathTask bcpt) { for (final Object element : bcpt.getFileSets(failOnClassPath)) { final Restrict restrict = new Restrict(); restrict.add((ResourceCollection) element); restrict.add(analyzeRestriction); exportsResourceCollections.add(restrict); } } /** * Add a file set with classes that are private to the bundles. * * @param set The file set with private implementations to add. */ public void addConfiguredImpls(FileSet set) { final Restrict restrict = new Restrict(); restrict.add(set); restrict.add(analyzeRestriction); implsResourceCollections.add(restrict); } /** * Add file sets for private classes on the bundle classpath. * * @param bcpt The bundle classpath that the bundle will have. */ public void addConfiguredImplsBundleClasspath(BundleClasspathTask bcpt) { for (final Object element : bcpt.getFileSets(failOnClassPath)) { final Restrict restrict = new Restrict(); restrict.add((ResourceCollection) element); restrict.add(analyzeRestriction); implsResourceCollections.add(restrict); } } /** * If set to true then do not update Export-Package * manifest header. */ public void setImportsOnly(boolean importsOnly) { this.bImportsOnly = importsOnly; } /** * If set to true then add packages that contains * a packageinfo file, even if the package is empty. */ public void setAddPackageinfoPackages(boolean addPackageinfoPackages) { this.addPackageinfoPackages = addPackageinfoPackages; } // Implements Task /** * Analyze all resources in the exports and impls resource * collections to determine the set of Java packages provided by * this bundle. Update the given properties for export- and import * package accordingly. */ @Override public void execute() throws BuildException { if (0==exportsResourceCollections.size() && 0==implsResourceCollections.size()) { throw new BuildException("Neither exports nor impls specified", getLocation()); } // First analyze the exports resource collections for (final Object element : exportsResourceCollections) { final ResourceCollection rc = (ResourceCollection) element; for (@SuppressWarnings("unchecked") final Iterator rcIt = rc.iterator(); rcIt.hasNext();) { final Resource res = rcIt.next(); log("Exports resource: "+res, Project.MSG_DEBUG); analyze(res); } }// Scan done // Get the sub-set of the provided packages that are the exports set final Set providedExportSet = new TreeSet(bpInfo.getProvidedPackages()); final SortedSet manifestExportSet = getPredefinedExportSet(); if (null!=manifestExportSet) { // An Export-Package header was given it shall contain // precisely the provided export set of Java packages. if (!manifestExportSet.equals(providedExportSet)) { // Found export package mismatch log("Provided package to export: " +providedExportSet, Project.MSG_ERR); log("Given Export-Package header: " +manifestExportSet, Project.MSG_ERR); final StringBuffer msg = new StringBuffer(); final TreeSet tmp = new TreeSet(manifestExportSet); tmp.removeAll(providedExportSet); if (0 rcIt = rc.iterator(); rcIt.hasNext();) { final Resource res = rcIt.next(); log("Impl resource: "+res, Project.MSG_DEBUG); analyze(res); } }// Scan done // Get the set of packages provided by the bundle bpInfo.toJavaNames(); // Make package name in bpInfo '.' separated. log("All provided packages: " +bpInfo.getProvidedPackagesAsExportPackageValue(), Project.MSG_VERBOSE); // created importSet from the set of unprovided referenced packages final SortedSet unprovidedReferencedPackages = bpInfo.getUnprovidedReferencedPackages(); log("Un-provided referenced packages: " +unprovidedReferencedPackages, Project.MSG_DEBUG); // The set of referenced packages that matches one of the // stdImport patterns. final SortedSet ignoredReferencedPackages = new TreeSet(); // Remove all packages with names like "java.*" (full set of // patterns are given by the stdImports set). Such packages must // not be present in the importSet. for (final Iterator urpIt = unprovidedReferencedPackages.iterator(); urpIt.hasNext(); ) { final String pkgName = urpIt.next(); if (isStdImport(pkgName)) { urpIt.remove(); ignoredReferencedPackages.add(pkgName); } } log("Referenced packages to import: " +unprovidedReferencedPackages, Project.MSG_DEBUG); importSet.addAll(unprovidedReferencedPackages); final SortedSet unprovidedExtraImportSet = new TreeSet(extraImportSet); unprovidedExtraImportSet.removeAll(bpInfo.getProvidedPackages()); log("Un-provided extra packages to import: " +unprovidedExtraImportSet, Project.MSG_DEBUG); importSet.addAll(unprovidedExtraImportSet); // The set of packages that will be mentioned in the // Export-Package or the Import-Package header. final Set allImpExpPkgs = new TreeSet(providedExportSet); allImpExpPkgs.addAll(importSet); bpInfo.postProcessUsingMap(ignoredReferencedPackages, allImpExpPkgs); //log(bpInfo.toString(), Project.MSG_INFO); // Data collection done - write back properties final Project proj = getProject(); if(!"".equals(exportsProperty)) { // A property name for the Export-Package header value has been specified final String exportsVal = proj.getProperty(exportsProperty); if (BundleManifestTask.isPropertyValueEmpty(exportsVal)) { // No value given, shall it be derived? if (!bImportsOnly) { if (0==providedExportSet.size()) { proj.setProperty(exportsProperty, BundleManifestTask.BUNDLE_EMPTY_STRING); log("No packages exported, leaving '" +exportsProperty +"' empty.", Project.MSG_VERBOSE); } else { final String newExportsVal = buildExportPackagesValue(providedExportSet); log("Setting '" +exportsProperty +"' to '"+newExportsVal +"'", Project.MSG_VERBOSE); proj.setProperty(exportsProperty, newExportsVal); } } } else { // Export-Package given; add version and uses directives. final String newExportsVal = validateExportPackagesValue(exportsVal); if (!exportsVal.equals(newExportsVal)) { log("Updating \"" +exportsProperty +"\" to \""+newExportsVal +"\"", Project.MSG_VERBOSE); proj.setProperty(exportsProperty, newExportsVal); } } } if(!"".equals(importsProperty)) { String importsVal = proj.getProperty(importsProperty); if (BundleManifestTask.isPropertyValueEmpty(importsVal)) { // No Import-Package given; use derived value. if (0==importSet.size()) { log("No packages to import, leaving \"" +importsProperty +"\" empty.", Project.MSG_VERBOSE); proj.setProperty(importsProperty, BundleManifestTask.BUNDLE_EMPTY_STRING); } else { importsVal = toString(importSet, ","); log("Setting \"" +importsProperty +"\" to \""+importsVal +"\"", Project.MSG_VERBOSE); proj.setProperty(importsProperty, importsVal); } } else { // Import-Package given; check that all derived packages are // present and that there are no duplicated packages. final TreeSet givenImportSet = new TreeSet(); final List entries = Util.parseManifestHeader(Constants.IMPORT_PACKAGE, importsVal, false, true, false); for (final HeaderEntry entry : entries) { for (final String pkgName : entry.getKeys()) { if (!givenImportSet.add(pkgName)) { final String msg = "The package '" + pkgName + "' is mentioned twice in the given '" + Constants.IMPORT_PACKAGE + "' manifest " + "header: '" + importsVal + "'."; log(msg, Project.MSG_ERR); throw new BuildException(msg, getLocation()); } } } givenImportSet.removeAll(bpInfo.getProvidedPackages()); final TreeSet missingImports = new TreeSet(importSet); missingImports.removeAll(givenImportSet); if (0 extraImports = new TreeSet(givenImportSet); extraImports.removeAll(importSet); if (0 entries = Util.parseManifestHeader(Constants.IMPORT_PACKAGE, importsSpec, false, true, false); for (final HeaderEntry entry : entries) { for (final String pkgName : entry.getKeys()) { importSet.add(pkgName); } } } else { // Spec is empty, must remove the emtpy value marker for now. importsSpec = ""; } final StringBuffer sb = new StringBuffer(importsSpec); final String exportsSpec = proj.getProperty(exportsProperty); if (!BundleManifestTask.isPropertyValueEmpty(exportsSpec)) { final List entries = Util.parseManifestHeader(Constants.EXPORT_PACKAGE, exportsSpec, false, true, false); for (final HeaderEntry entry : entries) { for (String pkg : entry.getKeys()) { if (!importSet.contains(pkg)) { final String ver = (String) entry.getAttributes().get(Constants.VERSION_ATTRIBUTE); @SuppressWarnings("deprecation") final String sver = (String) entry.getAttributes().get(Constants.PACKAGE_SPECIFICATION_VERSION); if (null!=ver) { pkg += ";version=" +toDefaultVersionRange(ver); } else if (null!=sver) { pkg += ";specification-version=" +toDefaultVersionRange(sver); } else { pkg += ";version=" +toDefaultVersionRange(Version.emptyVersion.toString()); } log("implicitImport - adding: "+pkg, Project.MSG_DEBUG); if (0 0; } /** * Get the set of Java packages to export according to the given * Export-Package header. * * @return the set of Java packages to export or null if no * Export-Package header was given. */ private SortedSet getPredefinedExportSet() { if(!"".equals(exportsProperty)) { final String exportsVal = getProject().getProperty(exportsProperty); if (!BundleManifestTask.isPropertyValueEmpty(exportsVal)) { log("Found non-empty Export-Package attribute: '" +exportsVal +"'", Project.MSG_DEBUG); final TreeSet res = new TreeSet(); final List entries = Util.parseManifestHeader(Constants.EXPORT_PACKAGE, exportsVal, false, true, false); for (final HeaderEntry entry : entries) { res.addAll(entry.getKeys()); } return res; } } return null; } private void appendUsesDirective(final StringBuffer sb, final String pkgName) { if (doUses()) { final String sep = ","; final Set usesPkgs = bpInfo.getPackagesReferencedFromPackage(pkgName); if (null!=usesPkgs && 0 usesIt = usesPkgs.iterator(); usesIt.hasNext(); ) { final String usesPkg = usesIt.next(); sb.append(usesPkg); if (usesIt.hasNext()) { sb.append(sep); } } if (1 exportPackages) { final String sep = ","; final String versionPrefix = ";version="; final StringBuffer sb = new StringBuffer(); for(final String pkgName : exportPackages) { if (sb.length() > 0) { sb.append(sep); } sb.append(pkgName); final Version pkgVersion = bpInfo.getProvidedPackageVersion(pkgName); if (null!=pkgVersion) { sb.append(versionPrefix).append(pkgVersion); } appendUsesDirective(sb, pkgName); } return sb.toString(); } /** * Validate a given Export-Package header value. Check existing * version parameters, add missing package versions. Check uses * directives and add those that are missing. * * @param oldExportsVal the Export-Package value to validate and update. * @throws BuildException when conflicting version specifications * are found for a package. */ protected String validateExportPackagesValue(final String oldExportsVal) { final StringBuffer sb = new StringBuffer(); final String sep = ","; // TODO handle multiple keys per header entry (must not use destructive // operations on attributes and directives). final List entries = Util.parseManifestHeader(Constants.EXPORT_PACKAGE, oldExportsVal, true, true, false); for (final HeaderEntry entry : entries) { for (final String pkgName : entry.getKeys()) { if (!bpInfo.providesPackage(pkgName)) { final String msg = "The package '"+pkgName +"' is in the Export-Package" +" manifest header, but there is no class belonging to it." +" The following packages are provided: " +bpInfo.getProvidedPackages(); log(msg, Project.MSG_ERR ); if (failOnExports) { throw new BuildException(msg, getLocation()); } } if (sb.length()>0) { sb.append(sep); } sb.append(pkgName); // Add / check package version String versionKey = "version"; String versionStr = (String) entry.getAttributes().remove(versionKey); if (null==versionStr) { // Fallback to pre OSGi R4 name versionKey = "specification-version"; versionStr = (String) entry.getAttributes().remove(versionKey); } Version version = null; if (null!=versionStr) { try { version = new Version(versionStr); } catch (final Exception e) { final String msg = "Found invalid version value in given " +"Export-Package header for the package '" +pkgName +"': '"+versionStr +"'; Error: " +e.getMessage(); log(msg, Project.MSG_ERR ); throw new BuildException(msg, e); } } final Version curVersion = bpInfo.getProvidedPackageVersion(pkgName); if (null==version && null!=curVersion) { // Version is missing, add it version = curVersion; } else if (null!=version && null!=curVersion && !version.equals(curVersion)) { final String msg = "Found conflicting versions for the package '" +pkgName +"'. The Export-Package header says '" +version +"', but '" +bpInfo.getProvidedPackageVersionSource(pkgName) +" claims '" +curVersion +"'."; log(msg, Project.MSG_ERR ); throw new BuildException(msg); } if (null!=version) { // Finally insert version into the new Export-Package value sb.append(";").append(versionKey).append("=").append(version); } if (doUses()) { if (!entry.getDirectives().containsKey(Constants.USES_DIRECTIVE)) { appendUsesDirective(sb, pkgName); } else { // Validate the given uses directive. final Set usesPkgs = bpInfo.getPackagesReferencedFromPackage(pkgName); final String usesValue = entry.getDirectives().remove(Constants.USES_DIRECTIVE); final TreeSet uPkgsMan = new TreeSet (Arrays.asList(Util.splitwords(usesValue, ", \t", '"'))); final Set uPkgsMis = new TreeSet(usesPkgs); uPkgsMis.removeAll(uPkgsMan); if (0 uPkgsExtra = new TreeSet(uPkgsMan); uPkgsExtra.removeAll(usesPkgs); if (0 paramEntry : entry.getAttributes().entrySet()) { final String paramName = paramEntry.getKey(); final String paramValue = paramEntry.getValue().toString(); sb.append(";"); sb.append(paramName); sb.append("="); final boolean quoteNeeded = -1 " +sb.toString(), Project.MSG_VERBOSE); } } private void handleOneExportPackageLine(final String line) { if (!BundleManifestTask.BUNDLE_EMPTY_STRING.equals(line)) { final List entries = Util.parseManifestHeader(Constants.EXPORT_PACKAGE, line.trim(), false, true, false); for (final HeaderEntry entry : entries) { for (final String pkg : entry.getKeys()) { ePkgs.add(pkg); } } } } private void processPkgSrcsAvailable() { // If no srcDir then there are no source files in it. if (srcDir==null || !srcDir.exists()) { return; } final Project proj = getProject(); final TreeSet pkgNamesWithSource = new TreeSet(); boolean pkgSrcAvailable = false; for (final Object element : ePkgs) { final String pkg = (String) element; final FileSet fileSet = new FileSet(); fileSet.setProject(proj); fileSet.setDir(srcDir); final OrSelector orSelector = new OrSelector(); fileSet.add(orSelector); final FilenameSelector fnsJ = new FilenameSelector(); fnsJ.setName(pkg.replace('.', File.separatorChar) + File.separatorChar + "*.java"); orSelector.add(fnsJ); final FilenameSelector fnsP = new FilenameSelector(); fnsP.setName(pkg.replace('.', File.separatorChar) + File.separatorChar + "package.html"); orSelector.add(fnsP); log(" Package '" +pkg +"' has sources: " + fileSet.toString(), Project.MSG_DEBUG); if (fileSet.size() > 0) { pkgSrcAvailable |= true; pkgNamesWithSource.add(pkg); } } if (pkgSrcAvailable) { proj.setProperty(pkgSrcAvailPropertyName, "true"); log("Setting property '" +pkgSrcAvailPropertyName +"' -> 'true'", Project.MSG_VERBOSE); } if (pkgWithSourcePropertyName != null) { final StringBuffer sb = new StringBuffer(50*pkgNamesWithSource.size()); for (final Object element : pkgNamesWithSource) { if (sb.length()>0) { sb.append(","); } sb.append(element); } proj.setProperty(pkgWithSourcePropertyName, sb.toString()); log("Setting property '" +pkgWithSourcePropertyName +"' -> " + sb.toString(), Project.MSG_VERBOSE); } } } knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/HtmlFragment.java0000644000175000017500000000601112346513674030103 0ustar felixfelix/* * Copyright (c) 2010, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.File; /** *

An Html formated text fragment the the MakeHTMLTask can be * configured with.

* *

When $(name) is found in the document to be generated * that string will be replaced with the contents of the file given by * fromFile.

* *

When $(name_LINK) is found in the document to be * generated that string will be replaced with a link to the * fragment. The title of the link is given by * linkText.

* * @author Gunnar Ekolin */ public class HtmlFragment { private String name; private File fromFile; private String linkText; /** * @param name the name that is the substitution key for this fragment. */ public void setName(final String name) { this.name = name; } /** * @return the name of this fragment. */ public String getName() { return name; } /** * @param fromFile the file holding the substitution text. */ public void setFromFile(final File fromFile) { this.fromFile = fromFile; } /** * @return the file to load the fragment from. */ public File getFromFile() { return fromFile; } /** * @param linkText the clickable text of the link. */ public void setLinkText(final String linkText) { this.linkText = linkText; } /** * @return the link text. */ public String getLinkText() { return linkText; } } // HtmlFragment knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleHTMLExtractorTask.java0000644000175000017500000011465512346513674032146 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.ResourceCollection; import org.osgi.framework.Version; import org.osgi.framework.VersionRange; import org.knopflerfish.ant.taskdefs.bundle.BundleArchives.BundleArchive; /** * Task that analyzes a set of bundle jar files and builds HTML documentation * from these bundles. Also creates cross-references to bundle dependencies. * *

* All generated HTML will be stored in the directory specified with the * attribute outDir preserving the directory structure underneath * the files sets that are scanned for jar-files. * * E.g., a nested file set that selects * *

 * log / log - api.jar
 * 
* * will result in an HTML-file * *
 *  outDir/log/log-api.html
 * 
* * *

* The bundle analyzes is based on the attributes in the manifest. *

* *

Parameters

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
javadocRelPathRelative path (from outDir) to javadocs.No.
* Default value is "."
outDir * Directory to place resulting files in.No.
* Default value is "."
templateHTMLDir * Directory containing HTML template files. This directory must contain the * files: * *
 *    bundle_index.html
 *    bundle_list.html
 *    bundle_main.html
 *    bundle_info.html
 *    package_list.html
 *    style.css
 * 
* *
No.
* Default value is "."
systemPackageSet * Comma-separated set of packages which are system packages and thus globally * available. These are not cross-referenced.No.
* Default value is javax.swing, javax.accessibility, * javax.servlet, javax.xml,org.xml, org.w3c, java, com.sun
skipAttribSet * Comma-separated set of manifest attributes which shouldn't be printed.No.
* Default value is Manifest-Version, Ant-Version, * Bundle-Config, Created-By, Built-From
includeSourceFiles * Controls if Java source files shall be copied and linked into the HTML * structure.No.
* Default value "False"
includeSourceFileRepositoryLinks * Controls if links to the repository version of Java source files shall be * added to the HTML structure. The link target will be created from local file * names by replacing the path prefix that matches the property * rootDir by repositoryURL.No.
* Default value "False"
rootDir * The prefix of the source file absolute path to remove when creating a * repository URL for the source file. See * includeSourceFileRepositoryLinks for details.No.
* Default value ""
repositoryURL * The base URL to source file repository. See * includeSourceFileRepositoryLinks for details.No.
* Default value ""
listHeader * Heading to print at the top of the bundle list in the left frame of the page. * No.
* Default value is ""
* *

Parameters specified as nested elements

fileset

* * (required)
*

* Jar files to analyze must be selected by a nested file set. All jar file * selected by a nested file set will be analyzed. *

* *

Examples

* *
 * <bundlehtml templateHTMLDir    = "${ant.dir}/html_template"
 *                outDir             = "${release.dir}/docs"
 *                baseDir            = "${release.dir}/osgi"
 *                javadocRelPath     = "../javadoc"
 *   >
 *
 *     <fileset dir="${release.dir}/osgi/jars">
 *       <include name = "**/*.jar"/>
 *     </fileset>
 * 
* */ public class BundleHTMLExtractorTask extends Task { /** Last part of the javadoc URL for a class / interface. */ static final String HTML = ".html"; /** Last part of the javadoc URL for a package. */ static final String PACKAGE_SUMMARY_HTML = "/package-summary.html"; private BundleArchives bas; private final String listSeparator = "
\n"; private final String indexListHeader = "

${bundle.list.header}

"; private final String indexListRow = "${FILE.short}
\n"; private final String indexMainRow = "" + "${FILE.short}" + "${Bundle-Description}" + "\n"; private final String indexMainUnresolved = "\n \n${unresolvedRows}\n
Unresolved packages
\n"; private final String indexMainUnresolvedRow = " ${FILE.short}\n ${pkgs}\n"; private final String bundleRow = "${FILE.short}${what}\n"; private final String packageListRow = "${pkg}${providers}\n"; private final String missingRow = "${name}${version}\n"; private final String pkgHTML = "${namelink}"; private final String pkgHTMLversion = "${namelink} ${version}"; private final Map globalVars = new TreeMap(); /** * Mapping from package name to bundle archive that uses the package * containing one entry for each package that does not have any java doc. */ private final Map missingDocs = new TreeMap(); public BundleHTMLExtractorTask() { setListProps("Export-Package," + "Import-Package," + "Import-Service," + "Export-Service"); setSystemPackageSet("javax.swing," + "javax.accessibility," + "javax.servlet," + "javax.xml," + "org.xml," + "org.w3c," + "java," + "com.sun," + "com.apple.eawt"); setSkipAttribSet("Manifest-Version," + "Ant-Version," + "Bundle-Config," + "Created-By" // "Built-From", ); setAlwaysProps("Build-Date," + "Bundle-Activator," + "Bundle-Classpath," + "Bundle-ContactAddress," + "Bundle-Description," + "Bundle-License," + "Bundle-DocURL," + "Bundle-ManifestVersion," + "Bundle-Name," + "Bundle-SymbolicName," + "Bundle-Vendor," + "DynamicImport-Package," + "Export-Package," + "Import-Package," + "Provide-Capability," + "Require-Capability," + "Main-class"); } private boolean bCheckJavaDoc = true; public void setCheckJavaDoc(boolean b) { this.bCheckJavaDoc = b; } private File templateHTMLDir = new File("."); public void setTemplateHTMLDir(File f) { this.templateHTMLDir = f; if (!templateHTMLDir.exists()) { throw new BuildException("templateHTMLDir: " + f + " does not exist"); } if (!templateHTMLDir.isDirectory()) { throw new BuildException("templateHTMLDir: " + f + " is not a directory"); } } private boolean include_source_files = false; public void setIncludeSourceFiles(boolean b) { this.include_source_files = b; } private boolean includeSourceFileRepositoryLinks = false; public void setIncludeSourceFileRepositoryLinks(boolean b) { this.includeSourceFileRepositoryLinks = b; } private String rootDir = null; public void setRootDir(File f) { rootDir = f.getAbsolutePath() + File.separator; } private URL repositoryURL = null; public void setRepositoryURL(URL url) { repositoryURL = url; } File getBundleInfoTemplate() { return new File(templateHTMLDir, "bundle_info.html"); } File getBundleCSSTemplate() { return new File(templateHTMLDir, "style.css"); } File getBundleListTemplate() { return new File(templateHTMLDir, "bundle_list.html"); } File getPackageListTemplate() { return new File(templateHTMLDir, "package_list.html"); } File getBundleMainTemplate() { return new File(templateHTMLDir, "bundle_main.html"); } File getBundleIndexTemplate() { return new File(templateHTMLDir, "bundle_index.html"); } File getBundleHeaderTemplate() { return new File(templateHTMLDir, "bundle_header.html"); } private File outDir = new File("."); public void setOutDir(String s) { this.outDir = new File((new File(s)).getAbsolutePath()); } private String javadocRelPath = null; public void setJavadocRelPath(String s) { this.javadocRelPath = s; } private final List filesets = new ArrayList(); public void addFileset(FileSet set) { filesets.add(set); } Set listPropSet = new HashSet(); public void setListProps(String s) { listPropSet = Util.parseEnumeration("list props", s); } Set alwaysPropSet = new HashSet(); /** * Comma separated string with keys that shall have an empty default value. * * @param s */ public void setAlwaysProps(String s) { alwaysPropSet = Util.parseEnumeration("always props", s); } Set skipAttribSet = new HashSet(); public void setSkipAttribSet(String s) { skipAttribSet = Util.parseEnumeration("skip attributes set", s); } Set systemPackageSet = new HashSet(); public void setSystemPackageSet(String s) { systemPackageSet = Util.parseEnumeration("system packages", s); } private String listHeader = ""; public void setListHeader(String s) { listHeader = s; } // Implements Task @Override public void execute() throws BuildException { if (filesets.size() == 0) { throw new BuildException("No nested file sets specified"); } log("Loading bundle information:", Project.MSG_VERBOSE); bas = new BundleArchives(this, filesets, true); bas.doProviders(); log("Writing bundle jar docs pages.", Project.MSG_VERBOSE); try { for (final Entry> entry : bas.bsnToBundleArchives .entrySet()) { final Set bsnSet = entry.getValue(); // Sorted set with bundle archives, same BSN, different versions for (final Object element : bsnSet) { final BundleArchive ba = (BundleArchive) element; writeBundlePage(ba); } } final String mainPageTemplate = FileUtil.loadFile(getBundleMainTemplate().getAbsolutePath()); writeBundlesPage(new File(outDir, "main.html"), mainPageTemplate, indexMainRow, bas); final String menuPageTemplate = FileUtil.loadFile(getBundleListTemplate().getAbsolutePath()); writeBundlesPage(new File(outDir, "list.html"), menuPageTemplate, indexListRow, bas); final String pkgListPageTemplate = FileUtil.loadFile(getPackageListTemplate().getAbsolutePath()); writePkgListPage(new File(outDir, "package_list.html"), pkgListPageTemplate, packageListRow, bas); copyFile(getBundleIndexTemplate(), new File(outDir, "index.html")); copyFile(getBundleHeaderTemplate(), new File(outDir, "header.html")); copyFile(getBundleCSSTemplate(), new File(outDir, "style.css")); for (final Object element : missingDocs.keySet()) { final String name = (String) element; log("Missing javadoc for " + name, Project.MSG_WARN); } } catch (final IOException e) { throw new BuildException("Faild to write bundle jar docs: " + e, e); } } /** * Mapping from bundle archive to Map with variables and their expansion for * the that particular bundle archive. */ private final Map> ba2varMap = new HashMap>(); /** * Get the variable expansion map the the given bundle archive. * * @param ba * bundle archive to get variable expansions for. * @return Mapping form variable name to expansion. * @throws IOException * When outDir can not be made canonical. */ private Map getVarMap(final BundleArchive ba) throws IOException { Map res = ba2varMap.get(ba); if (null == res) { res = new HashMap(); ba2varMap.put(ba, res); // Populate the variable expansion map final String relPath = replace(ba.relPath, ".jar", ""); final String path = outDir.getCanonicalPath() + File.separator + relPath; res.put("html.file", path + HTML); res.put("html.uri", replace(relPath, "\\", "/") + HTML); res.put("src.dir", path + "/src"); res.put("src.uri", replace(relPath, "\\", "/") + "/src"); // relative path from the outDir to the bundle doc file for this bundle res.put("bundledoc", replace(relPath, "\\", "/") + HTML); res.put("FILE", ba.file.getName()); res.put("FILE.short", replace(ba.file.getName(), ".jar", "")); res.put("BYTES", String.valueOf(ba.file.length())); res.put("KBYTES", String.valueOf(ba.file.length() / 1024)); res.put("FILEINFO", ba.file.length() + " bytes" + (0 < ba.srcCount ? ", includes source" : "")); int sepIx = ba.relPath.indexOf(File.separator); String relPathUp = ""; while (sepIx > -1) { relPathUp += ".." + File.separator; ; sepIx = ba.relPath.indexOf(File.separator, sepIx + 1); } res.put("relpathup", relPathUp); res.put("jarRelPath", createRelPath(new File(path).getParentFile(), ba.file.getCanonicalPath())); res.put("javadocdir", javadocRelPath != null ? javadocRelPath : ""); // Manifest entries for (final Entry entry : ba.mainAttributes.entrySet()) { final String key = entry.getKey().toString(); String value = entry.getValue().toString(); // Special formatting of the value for some keys: if ("Export-Package".equals(key)) { value = getPackagesJavadocString(ba, relPathUp, ba.pkgExportMap, PACKAGE_SUMMARY_HTML); } else if ("Import-Package".equals(key)) { value = getPackagesJavadocString(ba, relPathUp, ba.pkgImportMap, PACKAGE_SUMMARY_HTML); } else if ("Import-Service".equals(key)) { value = getPackagesJavadocString(ba, relPathUp, ba.serviceImportMap, HTML); } else if ("Export-Service".equals(key)) { value = getPackagesJavadocString(ba, relPathUp, ba.serviceExportMap, HTML); } else if (listPropSet.contains(key)) { value = replace(value, ",", listSeparator); } res.put(key, value); } // Key that shall have an empty value if not set from some other data. for (final Object element : alwaysPropSet) { final String key = element.toString(); if (!res.containsKey(key)) { res.put(key, ""); } } } return res; } /** * Build a HTML formated string with one row for each class / package in the * given map. * * @param ba * The bundle archive that owns the package mapping to present. * @param relPathUp * relative path up from the directory where the file with the return * string will be written to the specified out directory. * @param map * Mapping from package name to package version. * @param linkSuffix * Suffix to add to the java doc link for the package. * @return String representation of the packages in the map. */ private String getPackagesJavadocString(final BundleArchive ba, final String relPathUp, final Map map, final String linkSuffix) { final StringBuffer sb = new StringBuffer(); for (final Entry entry : map.entrySet()) { final String name = entry.getKey(); final String version = entry.getValue().toString(); sb.append(getJavadocString(ba, relPathUp, name, version, linkSuffix)) .append("
\n"); } return sb.toString(); } /** * Builds a comma separated string with the package names in the set (linking * to javadoc). * * @param relPathUp * relative path up from the directory where the file with the return * string will be written to the specified out directory. * @param set * The package names to present links for. * @return Comma separated string with all the packages in the set. */ private String getPackagesJavadocString(final String relPathUp, final Set set) { final StringBuffer sb = new StringBuffer(); for (final String pkgName : set) { if (0 < sb.length()) { sb.append(", "); } sb.append(getPackageJavadocString(null, relPathUp, pkgName, "")); } return sb.toString(); } /** * Build a HTML formated string with links to the javadoc for one named * package. * * @param ba * The bundle archive that owns the package mapping to present. * @param relPathUp * relative path up from the directory where the file with the return * string will be written to the specified out directory. * @param map * Mapping from package name to package version. * @param linkSuffix * Suffix to add to the java doc link for the package. * @return String representation of the packages in the map. */ private String getPackageJavadocString(final BundleArchive ba, final String relPathUp, final String pkg, final String version) { return getJavadocString(ba, relPathUp, pkg, version, PACKAGE_SUMMARY_HTML); } /** * Build a HTML formated string (one row) for the given package / class. * * @param ba * The bundle archive that owns the package mapping to present. * @param relPathUp * relative path up from the directory where the file with the return * string will be written to the specified out directory. * @param pkg * The java package to present. * @param version * The version of the java package to present. * @param linkSuffix * Suffix to add to the java doc link for the package. Should be * {@link #HTML} for classes and {@link #PACKAGE_SUMMARY_HTML} when * pkg is a java package. * * @return HTML string representation of the package / class linking to local * Javadoc. */ private String getJavadocString(final BundleArchive ba, final String relPathUp, final String pkg, final String version, final String linkSuffix) { String row = (null == version || 0 == version.length()) ? pkgHTML : pkgHTMLversion; final String docFile = replace(pkg, ".", "/") + linkSuffix; final String docPath = relPathUp + javadocRelPath + "/index.html?" + docFile; final File f = new File(outDir + File.separator + javadocRelPath + File.separator + docFile); if (javadocRelPath != null && !"".equals(javadocRelPath)) { if (isSystemPackage(pkg)) { row = replace(row, "${namelink}", "${name}"); } else if ((bCheckJavaDoc && !f.exists())) { row = replace(row, "${namelink}", "${name}"); if (null != ba) { missingDocs.put(pkg, ba); } } else { row = replace(row, "${namelink}", "${name}"); } } else { row = replace(row, "${namelink}", "${name}"); } row = replace(row, "${name}", pkg); row = replace(row, "${version}", version); row = replace(row, "${javadoc}", docPath); return row; } private String stdReplace(final BundleArchive ba, final String template) throws IOException { String res = template; for (final Entry entry : globalVars.entrySet()) { res = replace(res, "${" + entry.getKey() + "}", entry.getValue().toString()); } final Map baVars = getVarMap(ba); for (final Entry entry : baVars.entrySet()) { res = replace(res, "${" + entry.getKey() + "}", entry.getValue().toString()); } return res; } /** * Replace ${MF.UNHANDLED} with one line for each manifest * attribute of bathat is not explicitly substituted in the * template string and this is not included in the set of manifest attributes * to be skipped. * * @param template * The template string to do the replacement in. * @param ba * The bundle archive to insert manifest attributes from. * @return the template string with ${MF.UNHANDLED} replaced. * @throws IOException */ private String mfaReplace(final String template, final BundleArchive ba) throws IOException { final Set handledSet = new TreeSet(); // The set of manifest attribute names in the bundle. final Set mfanSet = new TreeSet(); for (final Object element : ba.mainAttributes.keySet()) { final String mfan = element.toString(); mfanSet.add(mfan); if (-1 != template.indexOf("${" + mfan + "}")) { handledSet.add(mfan); } } // Build replacement string for ${MF.UNHANDLED} that shall contain one row // for // each manifest attribute not in the template and not in the skip set. final Map varMap = getVarMap(ba); final Set otherMfans = new TreeSet(mfanSet); otherMfans.removeAll(skipAttribSet); otherMfans.removeAll(handledSet); final StringBuffer mfOtherAttributes = new StringBuffer(); for (final String string : otherMfans) { final String key = string.toString(); String value = (String) varMap.get(key); // If value is a valid URL, present it as a link try { final URL url = new URL(value); value = "" + value + ""; } catch (final MalformedURLException mue) { } mfOtherAttributes.append("\n").append(" ").append(key) .append("\n").append(" ").append(value).append("\n") .append("\n"); } return replace(template, "${MF.UNHANDLED}", mfOtherAttributes.toString()); } /** * Replace ${depending.list} with one row for each bundle that * may import a package exported by ba. The row will contain the * bundle name and all the packages it may import. * * @param template * The template string to do the replacement in. * @param ba * The bundle archive to insert manifest attributes from. * @return the template string with ${depending.list} replaced. * @throws IOException */ private String dependingReplace(final String template, final BundleArchive ba) throws IOException { final Map varMap = getVarMap(ba); final String relPathUp = varMap.get("relpathup").toString(); // Build list of bundles depending on this bundle. final StringBuffer dependingList = new StringBuffer(); if (ba.pkgProvidedMap.size() == 0) { dependingList.append("None found"); } else { for (final Entry> entry : ba.pkgProvidedMap .entrySet()) { final BundleArchive dependentBa = entry.getKey(); final Set pkgs = entry.getValue(); String row = replace(bundleRow, "${what}", getPackagesJavadocString(relPathUp, pkgs)); row = replace(row, "${bundledoc}", relPathUp + getVarMap(dependentBa).get("html.uri")); row = stdReplace(dependentBa, row); dependingList.append(row); } } return replace(template, "${depending.list}", dependingList.toString()); } /** * Replace ${depends.list} with one row for each bundle that may * import a package exported by ba. The row will contain the * bundle name and all the packages it may import. * * @param template * The template string to do the replacement in. * @param ba * The bundle archive to insert manifest attributes from. * @return the template string with ${depends.list} replaced. * @throws IOException */ private String providersReplace(final String template, final BundleArchive ba) throws IOException { final Map varMap = getVarMap(ba); final String relPathUp = varMap.get("relpathup").toString(); // Build list of bundles that this bundle depends on, i.e., bundles that // provides pkgs to this one. final StringBuffer providersList = new StringBuffer(); if (ba.pkgProvidersMap.size() == 0 && ba.pkgUnprovidedMap.size() == 0) { providersList.append("None found"); } else { for (final Entry> entry : ba.pkgProvidersMap .entrySet()) { final BundleArchive providingBa = entry.getKey(); final Set pkgs = entry.getValue(); String row = replace(bundleRow, "${what}", getPackagesJavadocString(relPathUp, pkgs)); row = replace(row, "${bundledoc}", relPathUp + getVarMap(providingBa).get("html.uri")); row = stdReplace(providingBa, row); providersList.append(row); } boolean unresolvedHeadingInculded = false; for (final Entry entry : ba.pkgUnprovidedMap .entrySet()) { final String pkgName = entry.getKey().toString(); if (!isSystemPackage(pkgName)) { if (!unresolvedHeadingInculded) { String row = missingRow; row = replace(row, "${name}", "Unresolved"); row = replace(row, "${version}", ""); providersList.append(row); unresolvedHeadingInculded = true; } final Object versionRange = entry.getValue(); String row = missingRow; row = replace(row, "${name}", pkgName); row = replace(row, "${version}", versionRange.toString()); providersList.append(row); } } } return replace(template, "${depends.list}", providersList.toString()); } /** * Replace ${sources.list} with one row for each source file that * can be found. * * @param template * The template string to do the replacement in. * @param ba * The bundle archive to insert manifest attributes from. * @return the template string with ${sources.list} replaced. * @throws IOException */ private String sourcesReplace(final String template, final BundleArchive ba) throws IOException { final Map varMap = getVarMap(ba); final List srcList = new ArrayList(); final StringBuffer sb = new StringBuffer(); if (include_source_files) { log("including source files in jardoc", Project.MSG_VERBOSE); srcList .addAll(ba.extractSources(new File((String) varMap.get("src.dir")))); } else { log("includeSourceFiles is not set, skipping sources", Project.MSG_VERBOSE); } if (srcList.size() > 0) { sb.append("\n"); for (final Object element : srcList) { final String name = (String) element; final String uri = replace(ba.file.getName(), ".jar", "") + "/src/" + name; sb.append(" \n"); sb.append(" \n"); sb.append(" \n"); } sb.append("
\n"); sb.append(" " + name + "\n"); sb.append("
"); } else { // No source files extracted, shall we create links to SVN? if (includeSourceFileRepositoryLinks) { final Map srcRepositoryLinkMap = ba.getSrcRepositoryLinks(rootDir, repositoryURL); if (0 < srcRepositoryLinkMap.size()) { sb.append(""); for (final Entry entry : srcRepositoryLinkMap .entrySet()) { final String name = entry.getKey(); final String href = entry.getValue(); sb.append(" \n"); sb.append(" \n"); sb.append(" \n"); } sb.append("
\n"); sb.append(" " + name + "\n"); sb.append("
"); } } } if (0 == sb.length()) { sb.append("None found"); } return replace(template, "${sources.list}", sb.toString()); } private void writeBundlePage(final BundleArchive ba) throws IOException { final Map varMap = getVarMap(ba); final String template = FileUtil.load(getBundleInfoTemplate().getAbsolutePath()); String res = mfaReplace(template, ba); res = dependingReplace(res, ba); res = providersReplace(res, ba); res = sourcesReplace(res, ba); res = stdReplace(ba, res); final String outName = (String) varMap.get("html.file"); FileUtil.writeStringToFile(new File(outName), res); log("Wrote " + outName, Project.MSG_VERBOSE); } /** * Write the a page that lists all bundles. * * @param outFile * The file to write to. * @param template * The template to use for this file. * @param rowTemplate * Template to use for a bundle row in the listing. * @throws IOException */ private void writeBundlesPage(final File outFile, final String template, final String rowTemplate, final BundleArchives bas) throws IOException { final String listHeaderRow = (null != listHeader && listHeader.length() > 0) ? replace(indexListHeader, "${bundle.list.header}", listHeader) : listHeader; String html = replace(template, "${bundle.list.header}", listHeaderRow); final StringBuffer bundleList = new StringBuffer(); final StringBuffer unresolvedList = new StringBuffer(); // Build the list of bundles for (final Entry> entry : bas.bnToBundleArchives .entrySet()) { final Set bsnSet = entry.getValue(); // Sorted set with bundle archives, same BSN, different versions for (final BundleArchive ba : bsnSet) { bundleList.append(stdReplace(ba, rowTemplate)); if (0 < ba.pkgUnprovidedMap.size()) { // Build one row for each unprovided, non-system package final String urow = stdReplace(ba, indexMainUnresolvedRow); final StringBuffer sbUpkg = new StringBuffer(); for (final Entry uPkgEntry : ba.pkgUnprovidedMap .entrySet()) { final String pkgName = uPkgEntry.getKey(); if (isSystemPackage(pkgName)) { continue; } final String version = uPkgEntry.getValue().toString(); if (0 < sbUpkg.length()) { sbUpkg.append(",
\n "); } sbUpkg.append(getPackageJavadocString(ba, "../", pkgName, version)); if (ba.pkgImportOptional.contains(pkgName)) { sbUpkg.append(" optional"); } } if (0 < sbUpkg.length()) { unresolvedList.append(replace(urow, "${pkgs}", sbUpkg.toString())); } } } } html = replace(html, "${bundle.list}", bundleList.toString()); bundleList.setLength(0); if (0 < unresolvedList.length()) { final String unresolved = replace(indexMainUnresolved, "${unresolvedRows}", unresolvedList.toString()); html = replace(html, "${unresolved.list}", unresolved); unresolvedList.setLength(0); } html = replace(html, "${unresolved.list}", ""); FileUtil.writeStringToFile(outFile, html); log("wrote " + outFile, Project.MSG_VERBOSE); } /** * Write a page listing all the provided Java packages and the bundles that * provides each package. * * @param outFile * The file to write to. * @param template * The template to use for this file. * @param rowTemplate * Template to use for a bundle row in the listing. * * @throws IOException */ private void writePkgListPage(final File outFile, final String template, final String rowTemplate, final BundleArchives bas) throws IOException { final StringBuffer sb = new StringBuffer(); for (final Entry>> entry : bas.allExports .entrySet()) { final String pkg = entry.getKey().toString(); final Map> vpMap = entry.getValue(); for (final Entry> vpEntry : vpMap .entrySet()) { final String version = vpEntry.getKey().toString(); final Set providerBas = vpEntry.getValue(); final String row = replace(rowTemplate, "${pkg}", getPackageJavadocString(null, "", pkg, version)); final StringBuffer sbProviders = new StringBuffer(); for (final Object element : providerBas) { final BundleArchive provider = (BundleArchive) element; sbProviders.append(stdReplace(provider, indexListRow)); } sb.append(replace(row, "${providers}", sbProviders.toString())); } } FileUtil.writeStringToFile(outFile, replace(template, "${package.list}", sb.toString())); log("wrote " + outFile, Project.MSG_VERBOSE); } void copyFile(File templateFile, File outFile) throws IOException { final String src = FileUtil.loadFile(templateFile.getAbsolutePath()); FileUtil.writeStringToFile(outFile, src); log("copied " + outFile, Project.MSG_VERBOSE); } /** * Derive relative path from fromDir to the file given by * filePath. */ static String createRelPath(File fromDir, String filePath) { String res = ""; while (fromDir != null && !filePath.startsWith(fromDir.toString())) { if (res.length() > 0) { res += File.separator; } res += ".."; fromDir = fromDir.getParentFile(); } if (res.length() > 0) { res += File.separator; } res += filePath.substring(fromDir.toString().length() + 1); return res; } boolean isSystemPackage(String name) { for (final Object element : systemPackageSet) { final String prefix = (String) element; if (name.startsWith(prefix)) { return true; } } return false; } /** * A variant of {@link Util.replace(String,String,String)} that uses the empty * string as replacement for null values. * * @param src * The template string to do replace all matches in. * @param a * The math-string to be replaced. * @param b * The replacement string to use. * @return The template with all occurrences of a replaced by * b. */ String replace(String src, String a, String b) { return Util.replace(src, a, b == null ? "" : b); } } knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleManifestTask.java0000644000175000017500000011617412346513674031252 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map.Entry; import java.util.Set; import java.util.StringTokenizer; import java.util.Vector; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.Manifest; import org.apache.tools.ant.taskdefs.ManifestException; import org.apache.tools.ant.types.EnumeratedAttribute; import org.osgi.framework.Constants; import org.knopflerfish.ant.taskdefs.bundle.Util.HeaderEntry; /** * Extension of the standard Manifest task. *

* This task builds a manifest file from three different sources: *

    *
  1. A template manifest file. *
  2. Project properties with given prefix. *
  3. Nested attribute and section data. *
* It may also be used to create properties (with a given prefix) for * each main section attribute in the template manifest file. * *

Parameters

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
filethe manifest-file to create. * Yes if "attributePropertyPrefix" is empty, otherwise No.
encoding * The encoding used to read the existing manifest when updating.No, defaults to UTF-8 encoding.
mode * One of "update", "replace", "template" and "templateOnly" * default is "replace". *

* The "mode" determines which sources to use when creating the * resulting manifest: *

*
replace
Use properties and nested data. *
update
Use template, properties and nested data. *
template
Use template and nested data. *
templateOnly
Use template. *
*
No.
templateFilethe template manifest file to load.No.
attributePropertyPrefixIf set and a template file is given but no file * to write to export all attributes * from the main section of the template file as * properties. *

* If set and mode is one of "update", "replace" * then create main section attributes for all * project properties that starts with the prefix. *

* If set and "file" is given then export all attributes * written to the main section as properties. *

* The name of property that maps to a main * section attribute is the value of * "attributePropertyPrefix" followed by the * attribute name. The value is the attribute value. *

No.
kindThe kind of bundle that the manifest is for. *

* If given this string will be appended to the * following manifest attributes of the main section: *

    *
  • Bundle-Name *
  • Bundle-SymbolicName *
  • Bundle-UUID *
  • Bundle-Description *
  • Bundle-Category (only for kind="api"). *
* All main section manifest attribute starting * with "kind-" will be replaced with a main section * attribute without the prefix. E.g., if kind="api" * and there is an attribute named "api-Export-Package" * then it will be renamed to "Export-Package", overriding * any previous definition of "Export-Package". *
No.
allKindsA comma separated list specifying all kinds. *

* If given all main section attributes starting with * any of the kinds in allKinds will * be removed after the specified kind has been used to * override attributes. E.g., if kind="all" * and allKinds="api,all" and there is * an attribute named "api-Export-Package" * then that attribute will be removed from the * resulting manifest. *

No.
mainAttributesToSkipComma separated list with names of main section * attributes to weed out when writing the * manifest file. * No.
replaceEEminReplace the filter part of any osgi.ee requirement * for the OSGi/Minimum EE with the given value. * E.g., replaceEEmin="(&(osgi.ee=JavaSE)(version>=1.7))" * will replace any filter matching 'OSGi/Minimum' * in the osgi.ee name space with the given filter expression. * No.
verboseIf set to "true" then log the name of the * bundle activator together with the imported * and exported packagesNo.
* *

Nested elements

* *

attribute

*

One attribute for the manifest file. Those attributes that are * not nested into a section will be added to the "Main" section.

* * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
namethe name of the attribute.Yes
valuethe value of the attribute.Yes
* * *

section

*

A manifest section - you can nest attribute elements into sections.

* * * * * * * * * * * * *
AttributeDescriptionRequired
namethe name of the section.No, if omitted it will be assumed * to be the main section.
* *

Examples

* *

Build bundle manifest for the impl jar

* *
 *  <bundlemanifest mode="template"
 *                  kind="impl"
 *                  mainAttributesToSkip="Export-Package"
 *                  attributePropertyPrefix="bmfa."
 *                  templateFile="bundle.manifest"
 *                  verbose="true"
 *                  file="${outdir}/impl.mf">
 *     <attribute name="Build-Date"       value="${bundle.date}"/>
 *     <attribute name="Built-From"       value="${proj.dir}"/>
 *   </bundlemanifest>
 * 
* * *

Create properties for main section attributes in the template * manifest file

* *
 *   <bundlemanifest mode="template"
 *                   attributePropertyPrefix = "bmfa."
 *                   templateFile="bundle.manifest">
 *   </bundlemanifest>
 * 
* */ public class BundleManifestTask extends Task { /** * Default constructor. */ public BundleManifestTask() { super(); mode = new Mode(); mode.setValue("replace"); } /** * Helper class for bundle manifest's mode attribute. */ public static class Mode extends EnumeratedAttribute { /** * Get Allowed values for the mode attribute. * * @return a String array of the allowed values. */ @Override public String[] getValues() { return new String[] {"update", "replace", "template", "templateOnly"}; } } /** * The mode with which the manifest file is written */ private Mode mode; /** * The encoding of the manifest template file. */ private String encoding; /** * Comma separated list of names of attributes that must not be * present in the main section of the resulting manifest. */ private String mainAttributesToSkip; /** * The kind of bundle to generate manifest for. * If given this string will be appended to the following manifest * attributes of the main section: *
    *
  • Bundle-Name *
  • Bundle-SymbolicName *
  • Bundle-UUID *
*/ private String bundleKind; /** * All known kinds of bundles. Used to remove unused kind specific main * section manifest attributes. */ private final Set allBundleKinds = new HashSet(); /** * Prefix of project properties to add main section attributes for. * * For each property in the project with a name that starts with this * prefix a manifest attribute in the main section will be created. * The attribute name will be the property name without the prefix * and the attribute value will be the property value. */ private String attributePropertyPrefix; /** * The manifest template file. */ private File manifestTemplateFile; /** * The manifest file to create. */ private File manifestFile; /** * Holds explicit manifest data given in the build file. */ private final Manifest manifestNested = new Manifest(); /** * The encoding to use for reading in the manifest template file. * Default encoding is UTF-8. * * @param encoding the manifest template file encoding. */ public void setEncoding(String encoding) { this.encoding = encoding; } /** * The name of the template manifest file. * * @param f the template manifest file to load. */ public void setTemplateFile(File f) { manifestTemplateFile = f; } /** * The name of the manifest file to create. * * @param f the manifest file to write. */ public void setFile(File f) { manifestFile = f; } /** * Which sources to use when creating the resulting manifest. *
*
replace
Use properties and nested data. *
update
Use template, properties and nested data. *
template
Use template and nested data. *
templateOnly
Use template. *
* @param m the mode value one of - update, * replace, template and * templateOnly. */ public void setMode(Mode m) { mode = m; } /** * Comma separated list of attributes to skip from the main section. * @param s main section attributes to skip from out put. */ public void setMainAttributesToSkip(String s) { mainAttributesToSkip = s.trim(); } /** * Bundle kind, will be appended to some of the bundle specific * attributes in the main section. * @param s the kind of bundle that we are writing a manifest file for. */ public void setKind(String s) { bundleKind = s.trim(); } /** * Comma separated list of known bundle kinds. Any main section attribute * starting with one of the known kind values will be removed from the * resulting manifest after processing of kind specific overrides. * * @param s * Comma separated list of bundle kinds. */ public void setAllKinds(String s) { if (s != null && (s = s.trim()).length() > 0) { final StringTokenizer st = new StringTokenizer(s, ","); while (st.hasMoreTokens()) { final String kind = st.nextToken(); allBundleKinds.add(kind.trim()); } } else { allBundleKinds.clear(); } log("All bundle kinds " + allBundleKinds + ".", Project.MSG_DEBUG); } /** * The name of the OSGi/Minimum Execution Environment. */ private final String OSGI_MINIMUM_EE_NAME = "OSGi/Minimum"; /** * Replacement filter for the filter in required capabilities in the * osgi.ee name-space that requires the OSGi/Minimum EE. */ private String replaceEEmin; /** * Sets the replacement filter expression for required capabilities in the * osgi.ee name-space that requires the OSGi/Minimum EE. * * @param s */ public void setReplaceEEmin(String s) { if (s != null && (s = s.trim()).length() > 0) { replaceEEmin = s; log("replaceEEmin: '" + replaceEEmin + "'.", Project.MSG_DEBUG); } } /** * If set to true the bundle activator, export package and import * package list in the written manifest will be printed on the * console. */ private boolean verbose = false; /** * Set the verbosity of this task. * If set to true the bundle activator, export package and import * package list in the written manifest will be printed on the * console. * @param b verbose or not. */ public void setVerbose(boolean b) { verbose = b; } private void doVerbose(Manifest mf) { if (verbose) { final Manifest.Section ms = mf.getMainSection(); doVerbose( ms, "Bundle-Activator", "activator"); doVerbose( ms, "Export-Package", "exports"); doVerbose( ms, "Import-Package", "imports"); } } private void doVerbose(Manifest.Section ms, String attrName, String heading) { final Manifest.Attribute ma = ms.getAttribute(attrName); if (null!=ma) { final String val = ma.getValue(); if (!isPropertyValueEmpty(val)) { log( heading +" = "+val, Project.MSG_INFO); } } } /** * Set the prefix of project properties to add main section * attributes for. * * For each property in the project with a name that starts with this * prefix a manifest attribute in the main section will be created. * The attribute name will be the property name without the prefix * and the attribute value will be the property value. * * @param s the property names prefix to check for. */ public void setAttributePropertyPrefix( String s) { attributePropertyPrefix = s; } /** * If attributePropertyPrefix is set then iterate over * all properties and add attributes to the main section of * the given manifest for those properties that starts with the prefix. * * The name of the attribute will be the property name without the * prefix and the value will be the property value. * * @param mf The manifest to add the property based attributes to. */ private void addAttributesFromProperties(Manifest mf) { if (null!=attributePropertyPrefix) { final int prefixLength = attributePropertyPrefix.length(); final Project project = getProject(); final Manifest.Section mainS = mf.getMainSection(); @SuppressWarnings("unchecked") final Hashtable properties = project.getProperties(); for (final Enumeration pe = properties.keys(); pe.hasMoreElements();) { final String key = pe.nextElement(); if (key.startsWith(attributePropertyPrefix)) { final String attrName = key.substring(prefixLength); final String attrValue = (String) properties.get(key); if(!BUNDLE_EMPTY_STRING.equals(attrValue)) { Manifest.Attribute attr = mainS.getAttribute(attrName); if (null!=attr) { throw new BuildException ( "Can not add main section attribute for property '" +key+"' with value '"+attrValue+"' since a " +"main section attribute with that name exists: '" +attr.getName() +": "+attr.getValue() +"'.", getLocation()); } try { attr = new Manifest.Attribute(attrName, attrValue); mf.addConfiguredAttribute(attr); log("from propety '" +attrName +": "+attrValue+"'.", Project.MSG_VERBOSE); } catch (final ManifestException me) { throw new BuildException ( "Failed to add main section attribute for property '" +key+"' with value '"+attrValue+"'.\n"+me.getMessage(), me, getLocation()); } } } } } } /** * We must ensure that the case used in attribute names when they * are mapped to properties by * updatePropertiesFromMainSectionAttributeValues() are * the same as the one used in the build files, i.e., the one used * in the OSGi specification. If not it may happen that a we get two * properties defined for the same attribute (with different cases) * if this happens there will be an error when adding back the * properties to the generated manifest. Thus we need a list of all * OSGi specified attribute names in the case used in the * specification. */ private static final String[] osgiAttrNames = new String[]{ "Application-Icon", "Bundle-APIVendor", "Bundle-Activator", "Bundle-Category", "Bundle-Classpath", "Bundle-Config", "Bundle-ContactAddress", "Bundle-Copyright", "Bundle-Description", "Bundle-DocURL", "Bundle-Localization", "Bundle-ManifestVersion", "Bundle-Name", "Bundle-NativeCode", "Bundle-RequiredExecutionEnvironment", "Bundle-SubversionURL", "Bundle-SymbolicName", "Bundle-UUID", "Bundle-UpdateLocation", "Bundle-Vendor", "Bundle-Version", "DynamicImport-Package", "Export-Package", "Export-Service", "Fragment-Host", "Import-Package", "Import-Service", "Require-Bundle", "Service-Component", }; /** * Mapping from attribute key, all lower case, to attribute name * with case according to the OSGi specification. */ private static final Hashtable osgiAttrNamesMap = new Hashtable(); static { for (final String osgiAttrName : osgiAttrNames) { osgiAttrNamesMap.put(osgiAttrName.toLowerCase(), osgiAttrName); } } /** * If attributePropertyPrefix is set then iterate over * all attributes in the main section and set the value for * corresponding property to the value of that attribute. * * The name of the attribute will be the property name without the * prefix and the value will be the property value. */ private void updatePropertiesFromMainSectionAttributeValues(Manifest mf) { if (null!=attributePropertyPrefix) { final Project project = getProject(); final Manifest.Section mainS = mf.getMainSection(); for (@SuppressWarnings("unchecked") final Enumeration ae = mainS.getAttributeKeys(); ae.hasMoreElements();) { final String key = ae.nextElement(); final Manifest.Attribute attr = mainS.getAttribute(key); // Ensure that the default case is used for OSGi specified attributes final String propKey = attributePropertyPrefix + (osgiAttrNamesMap.containsKey(key) ? osgiAttrNamesMap.get(key) : attr.getName() ); final String propVal = attr.getValue(); log("setting '" +propKey +"'='"+propVal+"'.", Project.MSG_VERBOSE); project.setProperty(propKey,propVal); } } } /** * Replace all main section attributes that starts with the * specified prefix with an attribute without that prefix, * overriding any old definition. * @param mf The manifest to update * @param prefix The prefix to match on. */ private void overrideAttributes(Manifest mf, String prefix) { if (null!=prefix && 0 attrNames = new Vector(); for (@SuppressWarnings("unchecked") final Enumeration ae = mainS.getAttributeKeys(); ae.hasMoreElements();) { final String key = ae.nextElement(); final Manifest.Attribute attr = mainS.getAttribute(key); final String attrName = attr.getName(); if (attrName.startsWith(prefix)) { attrNames.add(attrName); } } /* Must do the modification in a separate loop since it modifies * the object that the enumeration above iterates over. */ for (final Object element : attrNames) { final String attrName = (String) element; final Manifest.Attribute attr = mainS.getAttribute(attrName); final String attrVal = attr.getValue(); mainS.removeAttribute(attrName); final String newAttrName = attrName.substring(prefixLength); mainS.removeAttribute(newAttrName); if (!isPropertyValueEmpty(attrVal)) { try { final Manifest.Attribute newAttr = new Manifest.Attribute(newAttrName,attrVal); mainS.addConfiguredAttribute(newAttr); log("Overriding '" +newAttrName +"' with value of '"+attrName+"'.", Project.MSG_VERBOSE); } catch (final ManifestException me) { throw new BuildException("overriding of '" +newAttrName +"' failed: "+me, me, getLocation()); } } } } } /** * Remove all kind specific main section attributes. * * @param mf The manifest to remove main section attributes from. */ private void removeAttributesForOtherKinds(Manifest mf) { if (allBundleKinds.size() > 0) { final Manifest.Section mainS = mf.getMainSection(); // Find all attributes to remove. final Vector attrNames = new Vector(); for (@SuppressWarnings("unchecked") final Enumeration ae = mainS.getAttributeKeys(); ae .hasMoreElements();) { final String key = ae.nextElement(); final Manifest.Attribute attr = mainS.getAttribute(key); final String attrName = attr.getName(); final int prefixEnd = attrName.indexOf('-'); if (prefixEnd > 0) { final String prefix = attrName.substring(0, prefixEnd); if (allBundleKinds.contains(prefix)) { attrNames.add(attrName); } } } // Remove the attributes; must be done outside the loop above since // removal modifies the collection that the loop iterates over. for (final String attrName : attrNames) { mainS.removeAttribute(attrName); log("Removing kind specific attribute '" + attrName + "'.", Project.MSG_VERBOSE); } } } /** * If the manifest contains a capability requirement on osgi.ee for the * OSGi/Minimum EE then replace the filter part of that requirement with the * given replacement value. * * @param mf * The manifest to replace in. */ private void replaceEEminmum(Manifest mf) { if (replaceEEmin != null) { final Manifest.Section mainS = mf.getMainSection(); final Manifest.Attribute attr = mainS.getAttribute(Constants.REQUIRE_CAPABILITY); if (attr != null) { final String reqCapValue = attr.getValue(); if (reqCapValue.contains(OSGI_MINIMUM_EE_NAME)) { log("Found '" + Constants.REQUIRE_CAPABILITY + "' attribute with requirement on '" + OSGI_MINIMUM_EE_NAME + "'.", Project.MSG_DEBUG); // Must replace... final List hes = Util.parseManifestHeader(Constants.REQUIRE_CAPABILITY, reqCapValue, true, true, false); for (final HeaderEntry he : hes) { log("Processing header entry '" + he.getKey() + "' with attributes " + he.getAttributes() + " and directives " + he.getDirectives() + ".", Project.MSG_DEBUG); for (final Entry directiveEntry : he .getDirectives().entrySet()) { if ("osgi.ee".equals(he.getKey()) && "filter".equals(directiveEntry.getKey()) && directiveEntry.getValue().contains(OSGI_MINIMUM_EE_NAME)) { log("Replacing filter '" + directiveEntry.getValue() + "' with '" + replaceEEmin + "' in '" + reqCapValue + "'.", Project.MSG_VERBOSE); directiveEntry.setValue(replaceEEmin); break; } } } attr.setValue(Util.toString(hes)); } } } } /** * Add a section to the manifest. * * @param section the manifest section to be added. * * @exception ManifestException if the section is not valid. */ public void addConfiguredSection(Manifest.Section section) throws ManifestException { manifestNested.addConfiguredSection(section); } /** * Special value used to indicate that a Manifest.Attribute with * this value shall be weeded out. I.e., not added to the manifest. * This value is used as the default value for properties that maps * to bundle manifest attributes via the attributePropertyPrefix. */ static protected final String BUNDLE_EMPTY_STRING = "[bundle.emptystring]"; /** * Check if a property value is empty or not. * * The value is empty if it is null, the empty string * or the special value BundleManifestTask.BUNDLE_EMPTY_STRING. * * @param pval The property value to check. * @return true if the value is empty. */ static protected boolean isPropertyValueEmpty( String pval ) { return null==pval || "".equals(pval) || BUNDLE_EMPTY_STRING.equals(pval); } /** * Add an attribute to the main section of the manifest. * Attributes with the value BUNDLE_EMPTY_STRING are not added. * * @param attribute the attribute to be added. * * @exception ManifestException if the attribute is not valid. */ public void addConfiguredAttribute(Manifest.Attribute attribute) throws ManifestException { if(BUNDLE_EMPTY_STRING.equals(attribute.getValue())) { return; } manifestNested.addConfiguredAttribute(attribute); } /** * Ensure that the named main section attribute ends with the * specified suffix. * @param mf The manifest object to work with. * @param attrName The name of the attribute to check / update. * @param suffix The required suffix. */ private void ensureAttrEndsWith(final Manifest mf, final String attrName, final String suffix){ final Manifest.Attribute attr = mf.getMainSection().getAttribute(attrName); if (null!=attr) { final String rhs = attr.getValue(); if (!rhs.endsWith(suffix)) { attr.setValue( rhs +suffix ); } } } /** * Ensure that the first value of the named main section attribute * ends with the specified suffix. * * @param mf The manifest object to work with. * @param attrName The name of the attribute to check / update. * @param suffix The required suffix. */ private void ensureAttrFirstValueEndsWith(final Manifest mf, final String attrName, final String suffix) { final Manifest.Attribute attr = mf.getMainSection().getAttribute(attrName); if (null != attr) { final String rhs = attr.getValue(); if (rhs != null && 0 < rhs.length()) { final int semiPos = rhs.indexOf(';'); if (0 < semiPos) { // Found manifest attribute with parameter(s) or directive(s) final String firstValue = rhs.substring(0, semiPos).trim(); if (!firstValue.endsWith(suffix)) { attr.setValue( firstValue + suffix + rhs.substring(semiPos)); } } else { if (!rhs.endsWith(suffix)) { attr.setValue( rhs +suffix ); } } } } } /** * Ensure that the named main section attribute have the given * value. * @param mf The manifest object to work with. * @param attrName The name of the attribute to check / update. * @param value The required attribute value. */ private void ensureAttrValue(Manifest mf, String attrName, String value){ Manifest.Attribute ma = mf.getMainSection().getAttribute(attrName); if (null==ma) { ma = new Manifest.Attribute(attrName,value); try { mf.getMainSection().addConfiguredAttribute(ma); } catch (final ManifestException me) { throw new BuildException("ensureAttrValue("+attrName+"," +value +") failed.", me, getLocation()); } } else { ma.setValue(value); } } private final static String DOC_URL_PREFIX = "http://www.knopflerfish.org/releases/current/"; private final static String SVN_URL_PREFIX = "https://www.knopflerfish.org/svn/knopflerfish.org/trunk/"; /** * If this is a distribution build (the * Knopflerfish-Version attribute is present) then use * the version number as replacement for: *
    *
  • the current-part of a Bundle-DocURL * value that start with {@link #DOC_URL_PREFIX}. *
  • the trunk-part of a Bundle-SubversionURL * value that start with {@link #SVN_URL_PREFIX}. *
*/ private void replaceTrunkWithVersion(Manifest mf) { final Manifest.Attribute kfVerAttr = mf.getMainSection().getAttribute("Knopflerfish-Version"); if (null!=kfVerAttr) { final String version = kfVerAttr.getValue(); final boolean isSnapshot = -1 knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/FileUtil.java0000644000175000017500000001242412346513674027235 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.URL; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Result; import javax.xml.transform.Source; 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.tools.ant.BuildException; import org.w3c.dom.Document; public class FileUtil { public static byte [] loadURL(URL url) throws IOException { final int bufSize = 1024 * 2; final byte [] buf = new byte[bufSize]; final ByteArrayOutputStream bout = new ByteArrayOutputStream(); final BufferedInputStream in = new BufferedInputStream(url.openStream()); int n; while ((n = in.read(buf)) > 0) { bout.write(buf, 0, n); } try { in.close(); } catch (final Exception ignored) { } return bout.toByteArray(); } public static String loadFile(String fname) throws IOException { final byte[] bytes = loadURL(new URL("file:" + fname)); return new String(bytes, "UTF-8"); } /** * Load entire contents of a file or URL into a string. */ public static String load(String fileOrURL) throws IOException { try { final URL url = new URL(fileOrURL); return new String(loadURL(url)); } catch (final Exception e) { return loadFile(fileOrURL); } } /** * Load an XML-formated file into a DOM-document. * * @param file The XML file to load. * @return DOM document. */ public static Document loadXML(final File file) { final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { final DocumentBuilder db = dbf.newDocumentBuilder(); return db.parse(file); } catch (final Exception e) { throw new BuildException("Failed to parse XML file '" +file +"': " +e, e); } } /** * Create an empty DOM-document. * * @param rootElement The name of the root element of the new document. * @return DOM document with a root element. */ public static Document createXML(final String rootElement) { final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { final DocumentBuilder db = dbf.newDocumentBuilder(); final Document res = db.newDocument(); res.appendChild(res.createElement(rootElement)); return res; } catch (final Exception e) { throw new BuildException("Failed to create new DOM-document:" +e, e); } } // Always write files using UTF-8. static void writeStringToFile(File outFile, String s) throws IOException { OutputStreamWriter writer = null; try { outFile.getParentFile().mkdirs(); final OutputStream out = new FileOutputStream(outFile); writer = new OutputStreamWriter(out, "UTF-8"); writer.write(s, 0, s.length()); // System.out.println("wrote " + outFile); } finally { try { writer.close(); } catch (final Exception ignored) { } } } public static void writeDocumentToFile(final File outFile, final Document doc) { final Source source = new DOMSource(doc); final Result result = new StreamResult(outFile); // Write the DOM document to the file Transformer xformer; try { xformer = TransformerFactory.newInstance().newTransformer(); xformer.transform(source, result); } catch (final Exception e) { throw new BuildException("Failed to write XML to '" + outFile +"', "+e, e); } } } knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/Bundle.java0000644000175000017500000006257612346513674026746 0ustar felixfelix/* * Copyright (c) 2005-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedSet; import java.util.jar.JarInputStream; import java.util.zip.ZipEntry; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.FileScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Jar; import org.apache.tools.ant.taskdefs.Manifest; import org.apache.tools.ant.taskdefs.ManifestException; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.ZipFileSet; import org.osgi.framework.Version; /** *

* An extension of the Jar task that builds an OSGi bundle. It can generate the * Bundle-Activator, Bundle-ClassPath and Import-Package manifest headers based * on the content specified in the task. *

* *

Parameters

* * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
fileThe bundle file to create.Yes
activator * The bundle activator class name. If set to "none" no Bundle-Activator * manifest header will be generated. If set to "auto" the bundle task will try * to find an activator in the included class files.No, default is "auto"
packageanalysis * Analyzes the class files of the bundle and the contents of the * exportpackage and importpackage nested elements. *
    *
  • none – no analysis is performed.
  • *
  • warn – a warning will be displayed for each referenced package not * found in the bundle or the importpackage nested elements.
  • *
  • auto – each referenced package not found in the bundle or the * importpackage nested elements will be added to the Import-Package * manifest header. Packages exported by the bundle will be added to the * Import-Package manifest header with a version range following the OSGi * versioning recommendation (if a package is incompatible with previous version * then the major number of the version must be incremented). E.g., if the * bundles exports version 1.0.2 the version range in the import will be * "[1.0.2,2)".
  • *
*
No, default is "warn"
* *

Nested elements

* *

classes

*

* The nested classes element specifies a ZipFileSet. The prefix attribute will be added to * the Bundle-ClassPath manifest header. The classes specified by the file set * will be included in the class analysis. *

* *

lib

*

* The nested lib element specifies a ZipFileSet. The locations of all files in the file set will * be added to the Bundle-ClassPath manifest header. All files of this file set * must be either zip or jar files. The classes available in the zip or jar * files will be included in the class analysis. *

* *

exportpackage

*

* The nested exportpackage element specifies the name and version of a * package to add to the Export-Package manifest header. If package analysis is * not turned off, a warning will be issued if the specified package cannot be * found in the bundle. When package analysis is turned on the version from the * packageinfo-file in the directory of the package is read and used as * the version of the exported package. In this case, if a version is specified * in the exportpackage element that version is compared with the one * from the packageinfo-file and if there is a mismatch a build error * will be issued. *

* *

importpackage

*

* The nested importpackage element specifies the name and version of a * package to add to the Import-Package manifest header. *

* *

standardpackage

*

* The nested standardpackage element specifies the name or prefix of a * package that should be excluded from the package analysis. It can be used to * avoid importing packages that are available in the underlying runtime * environment (i.e., via boot delegation). *

* *

Implicit file set

*

* The implicit fileset is specified by the baseDir attribute of the * bundle task and the nested include and exclude elements. *

*

* The implicit fileset of the bundle task will be included in the * class analysis and in the Bundle-ClassPath manifest header if needed. *

* *

Examples

* *
 * <bundle activator="auto"
 *         packageanalysis="auto"
 *         file="out/${ant.project.name}.jar">
 *
 *   <standardpackage name="javax.imageio"/>
 *
 *   <exportpackage name="se.weilenmann.bundle.test" version="1.0"/>
 *
 *   <manifest>
 *     <attribute name="Bundle-Name" value="testbundle"/>
 *     <attribute name="Bundle-Version" value="1.0"/>
 *     <attribute name="Bundle-Vendor" value="Kaspar Weilenmann"/>
 *   </manifest>
 *
 *   <classes dir="out/classes">
 *     <include name="se/weilenmann/bundle/test/**"/>
 *   </classes>
 *   <classes dir="out/classes" prefix="util">
 *     <include name="se/weilenmann/util/**"/>
 *   </classes>
 *   <classes src="osgi/jars/log/log_api.jar" prefix="log_api">
 *     <include name="**/*.class"/>
 *   </classes>
 *
 *   <lib dir="osgi/jars/cm" includes="cm_api.jar" prefix="osgi"/>
 *   <lib dir="lib/commons" includes="commons-logging.jar" prefix="commons"/>
 *
 * </bundle>
 * 
*

* Creates a bundle with the following manifest: *

* *

 * Manifest-Version: 1.0
 * Ant-Version: Apache Ant 1.6.2
 * Created-By: 1.4.2_02-b03 (Sun Microsystems Inc.)
 * Bundle-Name: testbundle
 * Bundle-Version: 1.0
 * Bundle-Vendor: Kaspar Weilenmann
 * Bundle-Activator: se.weilenmann.bundle.test.Activator
 * Bundle-ClassPath: .,util,log_api,osgi/cm_api.jar,commons/commons-loggi
 * ng.jar
 * Import-Package: se.weilenmann.bundle.test;specification-version=1.0,or
 * g.osgi.framework
 * Export-Package: se.weilenmann.bundle.test;specification-version=1.0
 * 
* * @author Kaspar Weilenmann */ public class Bundle extends Jar { // private fields private static final String BUNDLE_CLASS_PATH_KEY = "Bundle-ClassPath"; private static final String BUNDLE_ACTIVATOR_KEY = "Bundle-Activator"; private static final String IMPORT_PACKAGE_KEY = "Import-Package"; private static final String EXPORT_PACKAGE_KEY = "Export-Package"; private static final String ACTIVATOR_NONE = "none"; private static final String ACTIVATOR_AUTO = "auto"; private static final String PACKAGE_ANALYSIS_NONE = "none"; private static final String PACKAGE_ANALYSIS_WARN = "warn"; private static final String PACKAGE_ANALYSIS_AUTO = "auto"; private String activator = ACTIVATOR_AUTO; private String packageAnalysis = PACKAGE_ANALYSIS_WARN; private final Map importPackage = new HashMap(); private final Map exportPackage = new HashMap(); private final List libs = new ArrayList(); private final List classes = new ArrayList(); private File baseDir = null; private final List zipgroups = new ArrayList(); private final List srcFilesets = new ArrayList(); private final Manifest generatedManifest = new Manifest(); private final Set standardPackagePrefixes = new HashSet(); { standardPackagePrefixes.add("java."); } private final BundlePackagesInfo bpInfo = new BundlePackagesInfo(this); private final ClassAnalyserASM asmAnalyser = new ClassAnalyserASM(bpInfo, this); private void analyze() { if (activator == ACTIVATOR_AUTO || packageAnalysis != PACKAGE_ANALYSIS_NONE) { addZipGroups(); addImplicitFileset(); for (final FileSet fileset : srcFilesets) { for (@SuppressWarnings("unchecked") final Iterator fsIt = fileset.iterator(); fsIt.hasNext();) { final Resource res = fsIt.next(); analyze(res); } } // Scan done bpInfo.toJavaNames(); final Set publicPackages = exportPackage.keySet(); if (packageAnalysis != PACKAGE_ANALYSIS_NONE) { for (final String packageName : publicPackages) { if (!bpInfo.providesPackage(packageName)) { log("Exported package not provided by bundle: " + packageName, Project.MSG_WARN); } // The Version from the packageinfo-file or null final Version piVersion = bpInfo.getProvidedPackageVersion(packageName); if (null != piVersion) { final String epVersionS = exportPackage.get(packageName); if (null == epVersionS) { // Use the version form the packageinfo-file exportPackage.put(packageName, piVersion.toString()); } else { // Check that the versions match, if not trigger a build error try { final Version epVersion = Version.parseVersion(epVersionS); if (0 != epVersion.compareTo(piVersion)) { final String msg = "Multiple versions found for export of " + "the package '" + packageName + "'. The packageinfo file (" + bpInfo.getProvidedPackageVersionSource(packageName) + ") states '" + piVersion.toString() + "' but the element says '" + epVersion.toString() + "'."; log(msg, Project.MSG_ERR); throw new BuildException(msg); } } catch (final IllegalArgumentException iae) { final String msg = "Invalid version '" + epVersionS + "' in : " + iae.getMessage(); log(msg, Project.MSG_ERR); throw new BuildException(msg, iae); } } } } } final SortedSet privatePackages = bpInfo.getProvidedPackages(); privatePackages.removeAll(publicPackages); final SortedSet referencedPackages = bpInfo.getReferencedPackages(); referencedPackages.removeAll(privatePackages); for (final Object element : referencedPackages) { final String packageName = (String) element; if (!isStandardPackage(packageName) && !importPackage.containsKey(packageName)) { if (packageAnalysis == PACKAGE_ANALYSIS_AUTO) { final String version = exportPackage.get(packageName); try { importPackage.put(packageName, toImportRange(version)); } catch (final IllegalArgumentException iae) { final String msg = "Invalid version value, '" + version + "' for exported package \"" + packageName + "\" can not derive version range for auto-import. " + iae.getMessage(); log(msg, Project.MSG_ERR); throw new BuildException(msg, iae); } } else if (packageAnalysis == PACKAGE_ANALYSIS_WARN) { log("Referenced package not found in bundle or imports: " + packageName, Project.MSG_WARN); } } } } } /** * Analyze a resource by checking its suffix and delegate to * {@link #analyzeClass(Resource)}, {@link #analyzeJar(Resource)}, etc. * * @param res * The resource to be analyzed. */ protected void analyze(Resource res) throws BuildException { if (res.getName().endsWith(".class")) { analyzeClass(res); } else if (res.getName().endsWith(".jar")) { analyzeJar(res); } else if (res.getName().endsWith("/packageinfo")) { analyzePackageinfo(res); } else { // Just ignore all other files } } protected void analyzeJar(Resource res) throws BuildException { log("Analyze jar file " + res, Project.MSG_VERBOSE); try { final JarInputStream jarStream = new JarInputStream(res.getInputStream()); ZipEntry ze = jarStream.getNextEntry(); while (null != ze) { final String fileName = ze.getName(); if (fileName.endsWith(".class")) { log("Analyze jar class file " + fileName, Project.MSG_VERBOSE); asmAnalyser.analyseClass(jarStream, fileName); } ze = jarStream.getNextEntry(); } } catch (final Exception e) { e.printStackTrace(); throw new BuildException("Failed to analyze class-file " + res + ", exception=" + e, getLocation()); } } protected void analyzeClass(Resource res) throws BuildException { log("Analyze class file " + res, Project.MSG_VERBOSE); try { asmAnalyser.analyseClass(res.getInputStream(), res.toString()); } catch (final BuildException be) { throw be; } catch (final Exception e) { e.printStackTrace(); throw new BuildException("Failed to analyze class-file " + res + ", exception=" + e, getLocation()); } } protected void analyzePackageinfo(Resource res) throws BuildException { log("Analyze packageinfo file " + res, Project.MSG_VERBOSE); bpInfo.setPackageVersion(res); } private void addZipGroups() { for (int i = 0; i < zipgroups.size(); i++) { final FileSet fileset = zipgroups.get(i); final FileScanner fs = fileset.getDirectoryScanner(getProject()); final String[] files = fs.getIncludedFiles(); final File basedir = fs.getBasedir(); for (final String file : files) { final ZipFileSet zipfileset = new ZipFileSet(); zipfileset.setSrc(new File(basedir, file)); srcFilesets.add(zipfileset); } } } private void addImplicitFileset() { if (baseDir != null) { final FileSet fileset = (FileSet) getImplicitFileSet().clone(); fileset.setDir(baseDir); srcFilesets.add(fileset); } } private boolean isStandardPackage(String packageName) { for (final String prefix : standardPackagePrefixes) { if (packageName.startsWith(prefix)) { return true; } } return false; } private void handleActivator() throws ManifestException { if (activator == ACTIVATOR_NONE) { log("No BundleActivator set", Project.MSG_DEBUG); } else if (activator == ACTIVATOR_AUTO) { switch (bpInfo.countProvidedActivatorClasses()) { case 0: { log("No class implementing BundleActivator found", Project.MSG_INFO); break; } case 1: { activator = bpInfo.getActivatorClass(); break; } default: { log("More than one class implementing BundleActivator found: " + bpInfo.providedActivatorClassesAsString(), Project.MSG_WARN); break; } } } if (activator != ACTIVATOR_NONE && activator != ACTIVATOR_AUTO) { log("Bundle-Activator: " + activator, Project.MSG_INFO); generatedManifest .addConfiguredAttribute(createAttribute(BUNDLE_ACTIVATOR_KEY, activator)); } } private void handleClassPath() throws ManifestException { final StringBuffer value = new StringBuffer(); boolean rootIncluded = false; if (baseDir != null || classes.size() == 0) { value.append(".,"); rootIncluded = true; } Iterator i = classes.iterator(); while (i.hasNext()) { final ZipFileSet zipFileSet = i.next(); final String prefix = zipFileSet.getPrefix(getProject()); if (prefix.length() > 0) { value.append(prefix); value.append(','); } else if (!rootIncluded) { value.append(".,"); rootIncluded = true; } } i = libs.iterator(); while (i.hasNext()) { final ZipFileSet fileset = i.next(); if (fileset.getSrc(getProject()) == null) { final DirectoryScanner ds = fileset.getDirectoryScanner(getProject()); final String[] files = ds.getIncludedFiles(); if (files.length != 0) { zipgroups.add(fileset); final String prefix = fixPrefix(fileset.getPrefix(getProject())); for (final String file : files) { value.append(prefix.replace('\\', '/')); value.append(file.replace('\\', '/')); value.append(','); } } } } if (value.length() > 2) { generatedManifest .addConfiguredAttribute(createAttribute(BUNDLE_CLASS_PATH_KEY, value .substring(0, value.length() - 1))); } } private static String fixPrefix(String prefix) { if (prefix.length() > 0) { final char c = prefix.charAt(prefix.length() - 1); if (c != '/' && c != '\\') { prefix = prefix + "/"; } } return prefix; } private void addPackageHeader(String headerName, Map packageMap) throws ManifestException { final Iterator> i = packageMap.entrySet().iterator(); if (i.hasNext()) { final StringBuffer valueBuffer = new StringBuffer(); while (i.hasNext()) { final Entry entry = i.next(); final String name = entry.getKey(); String version = entry.getValue(); valueBuffer.append(name); if (version != null) { version = version.trim(); if (0 < version.length()) { valueBuffer.append(";version="); final boolean quotingNeeded = -1 != version.indexOf(',') && '"' != version.charAt(0); if (quotingNeeded) { valueBuffer.append('"'); } valueBuffer.append(version); if (quotingNeeded) { valueBuffer.append('"'); } } } valueBuffer.append(','); } valueBuffer.setLength(valueBuffer.length() - 1); final String value = valueBuffer.toString(); generatedManifest.addConfiguredAttribute(createAttribute(headerName, value)); log(headerName + ": " + value, Project.MSG_INFO); } } private static Manifest.Attribute createAttribute(String name, String value) { final Manifest.Attribute attribute = new Manifest.Attribute(); attribute.setName(name); attribute.setValue(value); return attribute; } /** * Given a precise version create a version range suitable for an import * package specification. Currently an input version of M.N.U.Q will result in * an output range "[M.N.U.Q, M+1)" following the version usage recommended by * OSGi (a package that is not backwards compatible must increment the major * number in its version number). * * @param version * an OSGi compatibel version on string form. * @return a quoted version range starting with the given version (inclusive) * ending with the next major version (exclusive). If the specified * version is null or an empty string a null * is returned. */ private static String toImportRange(final String version) throws IllegalArgumentException { if (null == version || 0 == version.length()) { return null; } final Version vStart = Version.parseVersion(version); final Version vEnd = new Version(vStart.getMajor() + 1, 0, 0, null); return "\"[" + vStart.toString() + "," + vEnd.toString() + ")\""; } // public methods public void setActivator(String activator) { if (ACTIVATOR_NONE.equalsIgnoreCase(activator)) { this.activator = ACTIVATOR_NONE; } else if (ACTIVATOR_AUTO.equalsIgnoreCase(activator)) { this.activator = ACTIVATOR_AUTO; } else { this.activator = activator; } } public void setPackageAnalysis(String packageAnalysis) { packageAnalysis = packageAnalysis.trim().toLowerCase(); if (PACKAGE_ANALYSIS_NONE.equals(packageAnalysis)) { this.packageAnalysis = PACKAGE_ANALYSIS_NONE; } else if (PACKAGE_ANALYSIS_WARN.equals(packageAnalysis)) { this.packageAnalysis = PACKAGE_ANALYSIS_WARN; } else if (PACKAGE_ANALYSIS_AUTO.equals(packageAnalysis)) { this.packageAnalysis = PACKAGE_ANALYSIS_AUTO; } else { throw new BuildException("Illegal value: " + packageAnalysis); } } public void addConfiguredStandardPackage(OSGiPackage osgiPackage) { final String name = osgiPackage.getName(); final String prefix = osgiPackage.getPrefix(); if (name != null && prefix == null) { bpInfo.addProvidedPackage(name); } else if (prefix != null && name == null) { standardPackagePrefixes.add(prefix); } else { throw new BuildException( "StandardPackage must have exactly one of the name and prefix attributes defined"); } } public void addConfiguredImportPackage(OSGiPackage osgiPackage) { final String name = osgiPackage.getName(); if (name == null) { throw new BuildException("ImportPackage must have a name"); } else if (osgiPackage.getPrefix() != null) { throw new BuildException("ImportPackage must not have a prefix attribute"); } else { importPackage.put(name, osgiPackage.getVersion()); } } public void addConfiguredExportPackage(OSGiPackage osgiPackage) { final String name = osgiPackage.getName(); if (name == null) { throw new BuildException("ExportPackage must have a name"); } else if (osgiPackage.getPrefix() != null) { throw new BuildException("ExportPackage must not have a prefix attribute"); } else { exportPackage.put(name, osgiPackage.getVersion()); } } public void addConfiguredLib(ZipFileSet fileset) { // TODO: handle refid if (fileset.getSrc(getProject()) == null) { addFileset(fileset); libs.add(fileset); } else { addClasses(fileset); } } public void addClasses(ZipFileSet fileset) { super.addZipfileset(fileset); srcFilesets.add(fileset); classes.add(fileset); } // extends Jar @Override public void execute() { try { handleClassPath(); analyze(); handleActivator(); addPackageHeader(IMPORT_PACKAGE_KEY, importPackage); addPackageHeader(EXPORT_PACKAGE_KEY, exportPackage); // TODO: better merge may be needed, currently overwrites // pre-existing headers addConfiguredManifest(generatedManifest); } catch (final ManifestException me) { throw new BuildException("Error merging manifest headers", me); } super.execute(); } @Override public void setBasedir(File baseDir) { super.setBasedir(baseDir); this.baseDir = baseDir; } @Override public void addZipGroupFileset(FileSet fileset) { super.addZipGroupFileset(fileset); zipgroups.add(fileset); } @Override public void addZipfileset(ZipFileSet fileset) { super.addZipfileset(fileset); } } // Bundle knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/MakeHTMLTask.java0000644000175000017500000006005412346513674027707 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.types.selectors.FilenameSelector; import org.apache.tools.ant.util.FileUtils; import org.osgi.framework.Version; import org.knopflerfish.ant.taskdefs.bundle.BundleArchives.BundleArchive; /** *

* This task is used when building distributions of Knopflerfish. * If you don't intend to create a new distribution type of * Knopflerfish then you're in the wrong place. *

* *

* Task that creates web sites given a template and a source file. * Currently used to create parts of the docs directory in the KF * distribution. It does this by simply replacing certain text strings with * others. For more information on which text strings this is please * check the source code. *

* *

* Here is a outline of how to use the task and a description * of different parameters and used system properties. *

* *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
* outdir * * What dir to put the actual the generated file * * Yes *
* tofile * * The relative path to where the generated file should be * copied. That is the actual location of the generated file * will be outdir/tofile * * Yes *
* template * * The file which describes what the page should look like * * Yes *
* title * * The page's title * * No, default is "" *
* description * * The page's description * * No, default is "" *
* disable * * Allows you to disable certain links. This attribute is very ad hoc. * It will use the properties htdocs.link.disabled.class * and htdocs.link.enabled.class. The task will then use the * values of these properties to generate the file. * * No *
* javadocRelPath * * Relative path (from outdir) to javadocs. * * ../../javadoc *
*

* Note: instead of using the attributes fromfile and * tofile one can use filesets. It will simply run through * and perform the task on all given files. *

* */ public class MakeHTMLTask extends Task { private final static String TIMESTAMP = new SimpleDateFormat("EE MMMM d yyyy, HH:mm:ss", Locale.ENGLISH) .format(new Date()); private final static String YEAR = new SimpleDateFormat("yyyy", Locale.ENGLISH).format(new Date()); private String projectName = ""; private boolean do_manpage = false; private String javadocRelPath = "../../javadoc"; /** * The source file */ private String fromFile; /** * Target directory, where everything will end up */ private File outdir; /** * The relative path to the target file from output dir */ private File toFile; /** * File's title */ private String title; /** * Description */ private String description; /** * Template file */ private File template; /** * Bundle list */ private String bundleList; private final ArrayList filesets = new ArrayList(); private String disable; private final Map fragments = new HashMap(); public void setFromfile(String s) { fromFile = s; } public void setTofile(String s) { toFile = new File(s); } public void setTitle(String title) { this.title = title; } @Override public void setDescription(String description) { this.description = description; } public void setOutdir(String s) { outdir = new File(s); } public void setTemplate(String template) { this.template = new File(template); } public void setBundleList(String bundleList) { this.bundleList = bundleList; } public void setManstyle(String manstyle) { this.do_manpage = true; } public void setDisable(String disabled) { this.disable = disabled; } public void setJavadocRelPath(String s) { this.javadocRelPath = s; } public void addFileset(FileSet fs) { filesets.add(fs); } public void addConfiguredHtmlFragment(HtmlFragment fragment) { final String name = fragment.getName(); if (name == null) { throw new BuildException("Nested HTML-fragments must have a name"); } if (null==fragment.getFromFile()) { throw new BuildException("Nested HTML-fragments must have a from file"); } fragments.put(name, fragment); } @Override public void execute() { final Project proj = getProject(); this.projectName = proj.getName(); if (template == null) { throw new BuildException("template must be set"); } if (title == null) { title = ""; } if (description == null) { description = ""; } if (filesets.isEmpty() && fromFile == null && toFile == null) { throw new BuildException("Need to specify tofile and fromfile or give a fileset"); } if (filesets.isEmpty()) { // log("Project base is: " + getProject().getBaseDir()); // log("Attempting to transform: " + fromFile); if (!FileUtils.isAbsolutePath(fromFile)) { fromFile = getProject().getBaseDir() + File.separator + fromFile; } transform(fromFile, toFile.toString()); } else { if (fromFile != null) { throw new BuildException("Can not specify fromfile when using filesets"); } if (toFile != null) { throw new BuildException("Can not specify tofile when using filesets"); } for (final Object element : filesets) { final FileSet fs = (FileSet) element; final DirectoryScanner ds = fs.getDirectoryScanner(getProject()); final String[] files = ds.getIncludedFiles(); for (final String file : files) { transform(new File(fs.getDir(getProject()), file).getAbsolutePath(), file); } } } } private void transform(String fromFile, String toFile) { if (fromFile == null) { throw new BuildException("fromfile must be set"); } if (toFile == null) { throw new BuildException("tofile must be set"); } try { final Project proj = getProject(); File tmp = new File(outdir, toFile).getParentFile(); if (!tmp.exists()) { if (tmp.exists() || !tmp.mkdirs()) { throw new IOException("Could not create " + tmp); } } tmp = new File(toFile); String pathToRoot = "."; while ((tmp = tmp.getParentFile()) != null) { pathToRoot = pathToRoot + "/.."; } // Compute the relative path from directory holding the toFile // to the javadoc direcotry. String pathToOutDir = ""; tmp = new File(outdir, toFile).getParentFile(); while ((tmp = tmp.getParentFile()) != null && tmp.equals(outdir)) { pathToOutDir = pathToOutDir + "../"; } final String pathToJavadocDir = pathToOutDir + javadocRelPath; String content = FileUtil.loadFile(template.toString()); content = Util.replace(content, "$(LINKS)", links()); content = Util.replace(content, "$(MAIN)", FileUtil.loadFile(fromFile)); for (final Object element : fragments.keySet()) { final String key = (String) element; final HtmlFragment frag = fragments.get(key); final String linkText = frag.getLinkText(); if (null!=linkText && 0" +linkText +""; content = Util.replace(content, "$("+key +"_LINK)", fragLink); } String fragCont = FileUtil.loadFile(frag.getFromFile().getPath()); if (null!=fragCont && 0\n" + fragCont; } content = Util.replace(content, "$("+key +")", fragCont); } content = Util.replace(content, "$(TITLE)", title); content = Util.replace(content, "$(DESC)", description); content = Util.replace(content, "$(TSTAMP)", TIMESTAMP); content = Util.replace(content, "$(YEAR)", YEAR); content = Util.replace(content, "$(USER)", System.getProperty("user.name")); content = Util.replace(content, "$(VERSION)", proj.getProperty("version")); content = Util.replace(content, "$(VERSION_PREV)", proj.getProperty("version.previous")); content = Util.replace(content, "$(KF_VERSION)", proj.getProperty("kf_version")); content = Util.replace(content, "$(BASE_VERSION)", proj.getProperty("base_version")); content = Util.replace(content, "$(BASE_URL)", proj.getProperty("base.url")); content = Util.replace(content, "$(DISTNAME)", proj.getProperty("distname")); content = Util.replace(content, "$(DISTRIB_NAME)", proj.getProperty("distrib.name")); content = Util.replace(content, "$(RELEASE_NAME)", proj.getProperty("release.name")); content = Util.replace(content, "$(RELEASE_DATE)", proj.getProperty("release.date")); content = Util.replace(content, "$(MESSAGE)", proj.getProperty("release")); content = Util.replace(content, "$(BUNDLE_LIST)", bundleList); content = Util.replace(content, "$(ROOT)", pathToRoot); content = Util.replace(content, "$(JAVADOC)", proj.getProperty("JAVADOC")); content = Util.replace(content, "$(CLASS_NAVIGATION)", proj.getProperty("css_navigation_enabled")); content = Util.replace(content, "$(SVN_REPO_URL)", proj.getProperty("svn.repo.url")); content = Util.replace(content, "$(SVN_TAG)",proj.getProperty("svn.tag")); content = Util.replace(content, "$(JAVADOCPATH)", pathToJavadocDir); content = Util.replace(content, "$(JAVADOCLINK)", pathToJavadocDir + "/index.html?"); // Used for bundle_doc generation if (do_manpage) { content = Util.replace(content, "$(BUNDLE_NAME)", this.projectName); content = Util.replace(content, "$(BUNDLE_VERSION)", proj.getProperty("bmfa.Bundle-Version")); final BundleArchives bas = getBundleArchives(); // Create links to jardoc for bundles built from this project content = Util.replace(content, "$(BUNDLE_JARDOCS)", basToString(bas)); content = Util.replace(content, "$(BUNDLE_EXPORT_PACKAGE)", getExportPkgs(bas, pathToJavadocDir)); // Replce H1-H3 headers to man page style, if manpage style content = Util.replace(content, "

"); } else if (type.equals("link")) { final String name = proj.getProperty(LINK_NAME + i); final String url = proj.getProperty(LINK_URL + i); if (name == null) { throw new BuildException("Name not set for htdocs.link.url." + i); } String cssClass = null; if (disable != null && disable.equals(id)) { cssClass = getProject().getProperty(CSS_CLASS_DISABLED); } else { cssClass = getProject().getProperty(CSS_CLASS_ENABLED); } buf.append("" + name + "
\n"); } else { throw new BuildException("Do not recognize type " + type); } } return buf.toString(); } /** * Loads the bundle archives built from this project. *

* The jar files to analyze is determined from: *

    *
  • The project property named jarfile. This is used to create * a file set with dir set to the directory part of the property value that * selects the file named by the file name part of the property value.
  • *
  • The project properties jars.dir and * jardir.name (set by all projects based on * bundlebuild.xml. The file set derived from these properties * will have its dir-property set to the value jars.dir and an * includes pattern of the form * ${jardir.name}/**/*.jar. *
  • The file set with id docbuild.jarfiles. *
* * @return bundle archives object holding the bundle archives selected by the * file sets described above or null if no file set was defined. */ private BundleArchives getBundleArchives() { final List fileSets = new ArrayList(); final Project proj = getProject(); // File set for bundlebuild.xml properties final String jarsDir = proj.getProperty("jars.dir"); if (null != jarsDir && 0 < jarsDir.length()) { final File file = new File(jarsDir); if (file.exists()) { final FileSet fileSet = new FileSet(); fileSet.setProject(proj); fileSet.setDir(file); final FilenameSelector fns = new FilenameSelector(); fns.setName(proj.getProperty("jardir.name") + "/**/*.jar"); fileSet.add(fns); fileSet.setExcludes("**/*-source.jar,**/*-javadoc.jar"); fileSets.add(fileSet); log("Found build results (bundlebuild): " + fileSet, Project.MSG_DEBUG); } } // File set for jarfile-property (e.g., framework.jar) final String jarfile = proj.getProperty("jarfile"); if (null!=jarfile && 0${version}${providers}\n"; /** The table heading for the list of exported packages. */ private static final String packageListHeading = "\n \n"; /** The table footer for the list of exported packages. */ private static final String packageListFooter = "
PackageVersionProviders
\n"; /** * Return HTML-formated String with one exported package per line, linking the * package name to its javadoc (if present). * * @param bas * Bundle archives object that holds the set of packages and the * exporters. * @param pathToJavadocDir * Relative path from the file we are generating to the javadoc * directory. * @return HTML string with all exported packages. */ private String getExportPkgs(final BundleArchives bas, final String pathToJavadocDir) { final StringBuffer res = new StringBuffer(); if (null != bas) { final boolean javadocPresent = pathToJavadocDir != null && 0>> pkgEntry: bas.allExports.entrySet()) { final String pkg = pkgEntry.getKey().toString(); final Map> verToProvides = pkgEntry.getValue(); final String docFile = replace(pkg, ".", "/") +BundleHTMLExtractorTask.PACKAGE_SUMMARY_HTML; final String docPath = pathToJavadocDir +"/index.html?" +docFile; final File f = new File(outdir +File.separator +pathToJavadocDir.replace('/', File.separatorChar) +File.separator +docFile.replace('/', File.separatorChar)); for (final Entry> vtpEntry : verToProvides.entrySet()) { final String version = vtpEntry.getKey().toString(); final Set providers = vtpEntry.getValue(); String row = packageListRow; if(javadocPresent) { if (!f.exists()) { row = replace(row, "${namelink}", "${name}"); } else { row = replace(row, "${namelink}", "${name}"); } } else { row = replace(row, "${namelink}", "${name}"); } row = replace(row, "${name}", pkg); row = replace(row, "${version}", version.toString()); row = replace(row, "${javadoc}", docPath); row = replace(row, "${providers}", providersToString(providers)); res.append(row); } } } if (0\n"); } res.append(providerToString(ba)); } } return res.toString(); } private String providersToString(final Set providers) { final StringBuffer res = new StringBuffer(); for (final BundleArchive ba : providers) { if (0 < res.length()) { res.append(", "); } res.append(providerToString(ba)); } return res.toString(); } private static final String packageListProviderTemplate = "${bundle.name.short}"; private String providerToString(final BundleArchive ba) { final String relPath = replace(ba.relPath, ".jar", ""); final String htmlURI = replace(relPath, "\\", "/") + BundleHTMLExtractorTask.HTML; final String bundleShortName = replace(ba.file.getName(), ".jar", ""); String provider = replace(packageListProviderTemplate, "${bundledoc.uri}", htmlURI); provider = replace(provider, "${bundle.name.short}", bundleShortName); return provider; } } knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/Util.java0000644000175000017500000006376112346513674026447 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.osgi.framework.Version; public class Util { // Type names used for types OSGi attributes in manifest headers. private static final String DOUBLE_TYPE = "Double"; private static final String LONG_TYPE = "Long"; private static final String LIST_TYPE = "List"; private static final String STRING_TYPE = "String"; private static final String VERSION_TYPE = "Version"; /** * Parse strings of format: * * ENTRY (, ENTRY)* * * @param d Directive being parsed * @param s String to parse * @return A HashSet with enumeration or null if enumeration string was null. * @exception IllegalArgumentException If syntax error in input string. */ public static Set parseEnumeration(String d, String s) { final HashSet result = new HashSet(); if (s != null) { final AttributeTokenizer at = new AttributeTokenizer(s); do { final String key = at.getKey(true); if (key == null) { throw new IllegalArgumentException("Directive " + d + ", unexpected character at: " + at.getRest()); } if (!at.getEntryEnd()) { throw new IllegalArgumentException("Directive " + d + ", expected end of entry at: " + at.getRest()); } result.add(key); } while (!at.getEnd()); return result; } else { return null; } } /** * Parse manifest header values on format: *
   * ENTRY (',' ENTRY)*
   * ENTRY = key (';' key)* (';' PARAM)*
   * PARAM = attribute (':' TYPE)? '=' value
   * PARAM = directive ':=' value
   * TYPE = SCALAR | LIST
   * SCALAR = 'String' | 'Version' | 'Long' | 'Double'
   * LIST = 'List<' SCALAR '>'
   * 
* * The default attribute value type is 'String'. For list values the 'List' * and its following '<' are treated as separate tokens to comply with the * OSGi TCK. * * The parse result is one {@link HeaderEntry}-instance for each entry. * If {@code single} is true then the entry only contains one key that can be * accesses by calling {@link HeaderEntry#getKey()}. * * If {@code unique} is true the attribute values in the map are scalars * otherwise the values from different attribute definitions with the same * name are wrapped in a {@code List}. * * @param a Name of attribute being parsed, for error messages. * @param s String to parse. * @param single If true, only allow one key per ENTRY. * @param unique Only allow unique attributes for each ENTRY. * @param single_entry If true, only allow one ENTRY in {@code s}. * * @return List of {@link HeaderEntry}-object, one per entry in {@code s}. * * @exception IllegalArgumentException If syntax error in input string. */ public static List parseManifestHeader(String a, String s, boolean single, boolean unique, boolean single_entry) { final List res = new ArrayList(); if (s != null) { final AttributeTokenizer at = new AttributeTokenizer(s); do { final HeaderEntry he = new HeaderEntry(a, single); String key = at.getKey(single); if (key == null) { final String msg = "Definition, " + a + ", expected key at: " + at.getRest() + ". Key values are terminated " + "by a ';' or a ',' and may not " + "contain unquoted ':', '=' if multiple keys are allowed."; throw new IllegalArgumentException(msg); } he.keys.add(key); if (!single) { while ((key = at.getKey(false)) != null) { he.keys.add(key); } } String param; while ((param = at.getParam()) != null) { final boolean is_directive = at.isDirective(); if (is_directive) { if (he.directives.containsKey(param)) { final String msg = "Definition, " + a + ", duplicate directive: " + param; throw new IllegalArgumentException(msg); } final String valueStr = at.getValue(false); if (valueStr == null) { final String msg = "Definition, " + a + ", expected value for " + " directive " + param + " at: " + at.getRest(); throw new IllegalArgumentException(msg); } he.directives.put(param, valueStr); } else { // Attribute definition with optional type final Object old = he.attributes.get(param); if (old != null && unique) { final String msg = "Definition, " + a + ", duplicate attribute: " + param; throw new IllegalArgumentException(msg); } final String paramType = at.getParamType(); final boolean keepEscape = paramType != null && paramType.startsWith("List"); final String valueStr = at.getValue(keepEscape); if (valueStr == null) { final String msg = "Definition, " + a + ", expected value for " + " attribute " + param + " at: " + at.getRest(); throw new IllegalArgumentException(msg); } final Object value = toValue(a, param, paramType, valueStr); if (unique) { he.attributes.put(param, value); } else { @SuppressWarnings("unchecked") List oldValues = (List) old; if (oldValues == null) { oldValues = new ArrayList(); he.attributes.put(param, oldValues); } oldValues.add(value); } } } if (at.getEntryEnd()) { res.add(he); } else { throw new IllegalArgumentException("Definition, " + a + ", expected end of entry at: " + at.getRest()); } if (single_entry && !at.getEnd()) { throw new IllegalArgumentException("Definition, " + a + ", expected end of single entry at: " + at.getRest()); } } while (!at.getEnd()); } return res; } /** * Convert an attribute value from string to the requested type. * * The types supported are described in * {@link #parseEntries(String, String, boolean, boolean, boolean)}. * * @param a Name of attribute being parsed, for error messages. * @param p Name of parameter to assign the value to, for error messages. * @param type the type to convert to. * @param value the value to convert. * @return attribute value converted to the desired type. */ private static Object toValue(String a, String param, String type, String value) { Object res; type = type == null ? STRING_TYPE : type.intern(); if (STRING_TYPE == type) { res = value; } else if (LONG_TYPE == type) { try { res = new Long(value.trim()); } catch (final Exception e) { throw (IllegalArgumentException) new IllegalArgumentException("Definition, " +a +", expected value of type Long but found '" +value +"' for attribute '" +param + "'.").initCause(e); } } else if (DOUBLE_TYPE == type) { try { res = new Double(value.trim()); } catch (final Exception e) { throw (IllegalArgumentException) new IllegalArgumentException("Definition, " +a +", expected value of type Double but found '" +value +"' for attribute '" +param + "'.").initCause(e); } } else if (VERSION_TYPE == type) { try { res = new Version(value); } catch (final Exception e) { throw (IllegalArgumentException) new IllegalArgumentException("Definition, " +a +", expected value of type Version but found '" +value +"' for attribute '" +param + "'.").initCause(e); } } else if (type.startsWith(LIST_TYPE)) { String elemType = type.substring(LIST_TYPE.length()).trim(); // Let "List" without any "" default to "List" if (elemType.length()>0) { if ('<' != elemType.charAt(0) || elemType.charAt(elemType.length() - 1) != '>') { throw new IllegalArgumentException ("Definition, " + a + ", expected List type definition '" + type + "' for attribute '" + param + "'."); } elemType = elemType.substring(1, elemType.length() - 1).trim().intern(); } // The default element type is STRING. if (elemType.length()==0) { elemType = STRING_TYPE; } try { final List elements = splitWords(value, ',', STRING_TYPE!=elemType); final List l = new ArrayList(elements.size()); for (final String elem : elements) { l.add(toValue(a, param, elemType, elem)); } res = l; } catch (final Exception e) { throw (IllegalArgumentException) new IllegalArgumentException ("Definition, " + a + ", expected '" + type + "' value but found '" + value + "' for attribute '" + param + "'.").initCause(e); } } else { throw new IllegalArgumentException("Definition, " +a +", unknown type '" +type +"' for attribute '" +param + "'."); } return res; } /** * Default whitespace string for splitwords(). Value is " \t\n\r") */ protected static String WHITESPACE = " \t\n\r"; /** * Default citation char for splitwords(). Value is '"' */ protected static char CITCHAR = '"'; /** * Utility method to split a string into words separated by whitespace. * *

* Equivalent to splitwords(s, WHITESPACE) *

*/ public static String[] splitwords(String s) { return splitwords(s, WHITESPACE); } /** * Utility method to split a string into words separated by whitespace. * *

* Equivalent to splitwords(s, WHITESPACE, CITCHAR) *

*/ public static String[] splitwords(String s, String whiteSpace) { return splitwords(s, whiteSpace, CITCHAR); } /** * Split a string into words separated by whitespace. *

* Citation chars may be used to group words with embedded whitespace. *

* * @param s String to split. * @param whiteSpace whitespace to use for splitting. Any of the characters in * the whiteSpace string are considered whitespace between words and * will be removed from the result. If no words are found, return an * array of length zero. * @param citChar Citation character used for grouping words with embedded * whitespace. Typically '"' */ public static String[] splitwords(String s, String whiteSpace, char citChar) { boolean bCit = false; // true when inside citation chars. final Vector v = new Vector(); // (String) individual words after splitting StringBuffer buf = new StringBuffer(); int i = 0; while (i < s.length()) { final char c = s.charAt(i); if (bCit || whiteSpace.indexOf(c) == -1) { // Build up word until we breaks on either a citation char or whitespace if (c == citChar) { bCit = !bCit; } else { if (buf == null) { buf = new StringBuffer(); } buf.append(c); } i++; } else { // found whitespace or end of citation, append word if we have one if (buf != null) { v.addElement(buf.toString()); buf = null; } // and skip whitespace so we start clean on a word or citation char while ((i < s.length()) && (-1 != whiteSpace.indexOf(s.charAt(i)))) { i++; } } } // Add possible remaining word if (buf != null) { v.addElement(buf.toString()); } // Copy back into an array final String[] r = new String[v.size()]; v.copyInto(r); return r; } /** * Split a string into words separated by a separator char. * * If the separator char shall be part of a word it must be escaped with a * '\' (\u005C). One level of escaping is consumed by this method. * * @param s String to split. * @param sepChar separator char to split on. * @param trim trim whitespace from the words if {@code true}. * * @return List with the words of the specified string. */ public static List splitWords(String s, char sepChar, boolean trim) { final List res = new ArrayList(); final StringBuffer buf = new StringBuffer(); int pos = 0; final int length = s.length(); boolean esc = false; int end = 0; for (; pos < length; pos++) { if (esc) { esc = false; buf.append(s.charAt(pos)); end = buf.length(); } else { final char c = s.charAt(pos); if (c == '\\') { esc = true; } else if (c == sepChar) { // trim trailing whitespace. if (trim) { buf.setLength(end); } res.add(buf.toString()); buf.setLength(0); end = 0; } else if (Character.isWhitespace(c)) { if (buf.length()>0 || !trim) { buf.append(c); } } else { buf.append(c); end = buf.length(); } } } if (esc) { throw new IllegalArgumentException("Value ends on escape character"); } // The last element. if (trim) { buf.setLength(end); } res.add(buf.toString()); return res; } /** * Replace all occurrences of a substring with another string. * *

* The returned string will shrink or grow as necessary depending on the * lengths of v1 and v2. *

* *

* Implementation note: This method avoids using the standard String * manipulation methods to increase execution speed. Using the * replace method does however include two new operations in * the case when matches are found. *

* * * @param s * Source string. * @param v1 * String to be replaced with v2. * @param v2 * String replacing v1. * @return Modified string. If any of the input strings are null, the * source string s will be returned unmodified. If * v1.length == 0, v1.equals(v2) or no occurrences * of v1 is found, also return s unmodified. */ public static String replace(final String s, final String v1, final String v2) { // return quick when nothing to do if (s == null || v1 == null || v2 == null || v1.length() == 0 || v1.equals(v2)) { return s; } int ix = 0; final int v1Len = v1.length(); int n = 0; // count number of occurances to be able to correctly size // the resulting output char array while (-1 != (ix = s.indexOf(v1, ix))) { n++; ix += v1Len; } // No occurances at all, just return source string if (n == 0) { return s; } // Set up an output char array of correct size int start = 0; final int v2Len = v2.length(); final char[] r = new char[s.length() + n * (v2Len - v1Len)]; int rPos = 0; // for each occurance, copy v2 where v1 used to be while (-1 != (ix = s.indexOf(v1, start))) { while (start < ix) { r[rPos++] = s.charAt(start++); } for (int j = 0; j < v2Len; j++) { r[rPos++] = v2.charAt(j); } start += v1Len; } // ...and add all remaining chars ix = s.length(); while (start < ix) { r[rPos++] = s.charAt(start++); } // ..ouch. this hurts. return new String(r); } /** * Class for tokenize an attribute string. */ static class AttributeTokenizer { final String s; int length; int pos = 0; AttributeTokenizer(final String input) { s = input; length = s.length(); } // get word (non-whitespace chars) up to the next non-quoted // ',', ';' or ':', '=' if not valueWord is set String getWord(boolean keepEscapse, boolean valueWord) { skipWhite(); boolean backslash = false; boolean quote = false; final StringBuffer val = new StringBuffer(); int end = 0; loop: for (; pos < length; pos++) { if (backslash) { backslash = false; if (keepEscapse) { val.append('\\'); } val.append(s.charAt(pos)); end = val.length(); } else { final char c = s.charAt(pos); switch (c) { case '"': quote = !quote; end = val.length(); break; case '\\': backslash = true; break; case ':': case ',': case ';': case '=': if (!quote && !(valueWord && (c==':' || c=='='))) { break loop; } // Fall through default: val.append(c); if (!Character.isWhitespace(c)) { end = val.length(); } break; } } } if (quote || backslash || end == 0) { return null; } val.setLength(end); return val.toString(); } String getKey(boolean singleKey) { if (pos >= length) { return null; } final int save = pos; if (s.charAt(pos) == ';') { pos++; } final String res = getWord(false, singleKey); if (res != null) { if (pos == length) { return res; } final char c = s.charAt(pos); if (c == ';' || c == ',') { return res; } } pos = save; return null; } String getParam() { if (pos == length || s.charAt(pos) != ';') { return null; } final int save = pos++; final String res = getWord(false, false); if (res != null) { if (pos < length && s.charAt(pos) == '=') { // Untyped parameter return res; } if (pos < length && s.charAt(pos) == ':') { // Typed parameter or directive return res; } } pos = save; return null; } boolean isDirective() { if (pos + 1 < length && s.charAt(pos) == ':' && s.charAt(pos + 1) == '=') { pos++; return true; } else { return false; } } String getParamType() { if (pos == length || s.charAt(pos) != ':') { return null; } final int save = pos++; final String res = getWord(false, false); if (res != null) { if (pos < length && s.charAt(pos) == '=') { return res; } } pos = save; return null; } String getValue() { return getValue(false); } String getValue(boolean keepEscapes) { if (s.charAt(pos) != '=') { return null; } final int save = pos++; skipWhite(); final String val = getWord(keepEscapes, true); if (val == null) { pos = save; return null; } return val; } boolean getEntryEnd() { final int save = pos; skipWhite(); if (pos == length) { return true; } else if (s.charAt(pos) == ',') { pos++; return true; } else { pos = save; return false; } } boolean getEnd() { final int save = pos; skipWhite(); if (pos == length) { return true; } else { pos = save; return false; } } String getRest() { final String res = s.substring(pos).trim(); return res.length() == 0 ? "" : res; } private void skipWhite() { for (; pos < length; pos++) { if (!Character.isWhitespace(s.charAt(pos))) { break; } } } } /** * A class that holds the parse result for one entry of a manifest header * following the general OSGi manifest header syntax. See * {@link #parseManifestHeader(String, String, boolean, boolean, boolean)} for * details on the syntax. */ public static class HeaderEntry { final String headerName; final boolean singleKey; final List keys = new ArrayList(); final Map attributes = new HashMap(); final Map directives = new HashMap(); /** * @param singleKey */ HeaderEntry(String headerName, boolean singleKey) { this.headerName = headerName; this.singleKey = singleKey; } public String getKey() { if (singleKey) { return keys.get(0); } throw new IllegalArgumentException("Requesting single key for multi key header clause"); } public List getKeys() { return keys; } public Map getAttributes() { return attributes; } public Map getDirectives() { return directives; } } /** * Convert a list of {@link HeaderEntry}-objects into a valid manifest header * value. * * @param hes * The list of header entries to make a string of. * @return Manifest value that follows the generic OSGi manifest syntax. */ public static String toString(List hes) { final StringBuffer sb = new StringBuffer(); for (final HeaderEntry he : hes) { if (sb.length() > 0) { sb.append(", "); } sb.append(he.getKey()); parametersToString(sb, "=", he.getAttributes()); parametersToString(sb, ":=", he.getDirectives()); } return sb.toString(); } /** * A pattern matching chars that needs to be quoted when quoting a parameter * value. */ static final Pattern QUOTE_PATTERN = Pattern.compile("\""); /** * A pattern matching OSGis syntax terminal called extended. An * extended terminal does not need to be quoted when used as the * value of a parameter. The set of allowed characters in extended * terminals are a..z, A..Z, 0..9, '_', '-' and '.'. */ static final Pattern EXTENDED_PATTERN = Pattern.compile("[a-zA-Z0-9_\\-.]+"); /** * Convert a map with manifest entry parameters into a well formed manifest * parameter string. * * @param sb * String buffer to append result to. * @param sep * Separator between the key and the value of a parameter. * @param parameters * The map with parameters to process. */ private static void parametersToString(final StringBuffer sb, final String sep, final Map parameters) { for (final Entry attribEntry : parameters.entrySet()) { sb.append("; "); sb.append(attribEntry.getKey()); sb.append(sep); String value = attribEntry.getValue().toString(); final boolean needsQuoting = !EXTENDED_PATTERN.matcher(value).matches(); if (needsQuoting) { sb.append('"'); final Matcher matcher = QUOTE_PATTERN.matcher(value); value = matcher.replaceAll("\\\\\""); } sb.append(value); if (needsQuoting) { sb.append('"'); } } } } knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/ByteFormatterTask.java0000644000175000017500000001616412346513674031137 0ustar felixfelix/* * Copyright (c) 2008-2010, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.File; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; /** * Sets a property to a formatted value in ki, Mi, Gi, Ti, Pi, Ei, Zi * and Yi with an optional unit. * * Here ki is short for kibi, (a contraction of kilo * binary) see http://en.wikipedia.org/wiki/Kibibyte * for a detailed explanation.

* *

Parameters

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
property * The name of the property to assign the formatted value to.Yes.
binaryPrefixURLAn URL pointing to a page explaining the binary * unit suffixes. * http://en.wikipedia.org/wiki/Binary_prefix#IEC_standard_prefixes *
unitThe unit to append to the formatted value. E.g., byte * No, default is the empty string.
sepThe string placed between the number and the * unit. * No, default is the HTML non-breaking space, "&nbsp;".
valueThe value to format. * One of value and file must be given.
fileThe file whose size is the value to format. * One of value and file must be given.
* *

Nested elements

* * Not applicable. * *

Examples

* *

Format a value as bytes

* *
 *  <byteformatter value="9093663"
 *                    property="myFormatedFilesize"
 *                    unit="B" />
 * 
* * *

Format the size of the file archive.jar appending the * unit B

* *
 *  <byteformatter file="archive.jar"
 *                    property="archive.size"
 *                    unit="B" />
 * 
* * * */ public class ByteFormatterTask extends Task { /** * Default constructor. */ public ByteFormatterTask() { super(); } private String property; /** * The name of the property to save the formatted value to. * * @param property the name of the property to set. */ public void setProperty(String property) { this.property = property; } private String unit = ""; /** * The unit to append to the formatted value. * * @param unit the unit text to append to the formatted value. */ public void setUnit(String unit) { this.unit = unit; } private String binaryPrefixURL = "http://en.wikipedia.org/wiki/Binary_prefix#IEC_standard_prefixes"; /** * The URL that explains binary prefixes. * * @param url The url to let the binary prefix point to. */ public void setBinaryPrefixURL(String url) { this.binaryPrefixURL = url; } private String sep = " "; /** * The separator between the numeral and the prefixed unit. * * @param sep the separator string. */ public void setSep(String sep) { this.sep = sep; } private long value; /** * Set the value to format. * * @param value the value to format */ public void setValue(long value) { this.value = value; } /** * Set the file to get the size of as the the value to format. * * @param file the file to return a formatted file size for. */ public void setFile(final File file) { this.value = file.length(); } static final long step = 1024; /** * Performs the requested formatting. * * @throws BuildException if the manifest cannot be written. */ public void execute() { String formatedValue = ""; String[] suffixes = new String[]{ "", "Ki","Mi", "Gi","Ti","Pi", "Ei","Zi","Yi"}; if (binaryPrefixURL!=null && binaryPrefixURL.length()>0) { for (int i=0; i0) { suffixes[i] = "" +suffixes[i] + ""; } } } int ix = 0; long factor = 1; while(value/factor>step && ixnull if this visitor * is not interested in visiting this default value. The 'name' * parameters passed to the methods of this annotation visitor are * ignored. Moreover, exactly one visit method must be called on this * annotation visitor, followed by visitEnd. */ public AnnotationVisitor visitAnnotationDefault() { return null; } /* * Visits an annotation of this method. * * @param desc the class descriptor of the annotation class. * @param visible true if the annotation is visible at runtime. * @return a visitor to visit the annotation values, or null if * this visitor is not interested in visiting this annotation. */ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { return null; } /* * Visits an annotation of a parameter this method. * * @param parameter the parameter index. * @param desc the class descriptor of the annotation class. * @param visible true if the annotation is visible at runtime. * @return a visitor to visit the annotation values, or null if * this visitor is not interested in visiting this annotation. */ public AnnotationVisitor visitParameterAnnotation( int parameter, String desc, boolean visible) { return null; } /* * Visits a non standard attribute of this method. * * @param attr an attribute. */ public void visitAttribute(Attribute attr) { } /* * Starts the visit of the method's code, if any (i.e. non abstract method). */ public void visitCode() { ca.task.log(" method '" +methodName +"'.", Project.MSG_DEBUG); } /* * Visits the current state of the local variables and operand stack * elements. This method must(*) be called just before any * instruction i that follows an unconditional branch instruction * such as GOTO or THROW, that is the target of a jump instruction, or that * starts an exception handler block. The visited types must describe the * values of the local variables and of the operand stack elements just * before i is executed.

(*) this is mandatory only * for classes whose version is greater than or equal to * {@link Opcodes#V1_6 V1_6}.

Packed frames are basically * "deltas" from the state of the previous frame (very first frame is * implicitly defined by the method's parameters and access flags):
    *
  • {@link Opcodes#F_SAME} representing frame with exactly the same * locals as the previous frame and with the empty stack.
  • {@link Opcodes#F_SAME1} * representing frame with exactly the same locals as the previous frame and * with single value on the stack (nStack is 1 and * stack[0] contains value for the type of the stack item).
  • *
  • {@link Opcodes#F_APPEND} representing frame with current locals are * the same as the locals in the previous frame, except that additional * locals are defined (nLocal is 1, 2 or 3 and * local elements contains values representing added types).
  • *
  • {@link Opcodes#F_CHOP} representing frame with current locals are * the same as the locals in the previous frame, except that the last 1-3 * locals are absent and with the empty stack (nLocals is 1, * 2 or 3).
  • {@link Opcodes#F_FULL} representing complete frame * data.
* * @param type the type of this stack map frame. Must be * {@link Opcodes#F_NEW} for expanded frames, or * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed * frames. * @param nLocal the number of local variables in the visited frame. * @param local the local variable types in this frame. This array must not * be modified. Primitive types are represented by * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, * {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or * {@link Opcodes#UNINITIALIZED_THIS} (long and double are * represented by a single element). Reference types are represented * by String objects (representing internal names), and uninitialized * types by Label objects (this label designates the NEW instruction * that created this uninitialized value). * @param nStack the number of operand stack elements in the visited frame. * @param stack the operand stack types in this frame. This array must not * be modified. Its content has the same format as the "local" array. */ public void visitFrame( int type, int nLocal, Object[] local, int nStack, Object[] stack) { } // ------------------------------------------------------------------------- // Normal instructions // ------------------------------------------------------------------------- /* * Visits a zero operand instruction. * * @param opcode the opcode of the instruction to be visited. This opcode is * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, * ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, * FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD, * DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, * DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, * DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP, IADD, LADD, FADD, * DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, * FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, * LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, * I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, * I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, * FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, * MONITORENTER, or MONITOREXIT. */ public void visitInsn(int opcode) { } /* * Visits an instruction with a single int operand. * * @param opcode the opcode of the instruction to be visited. This opcode is * either BIPUSH, SIPUSH or NEWARRAY. * @param operand the operand of the instruction to be visited.
When * opcode is BIPUSH, operand value should be between Byte.MIN_VALUE * and Byte.MAX_VALUE.
When opcode is SIPUSH, operand value * should be between Short.MIN_VALUE and Short.MAX_VALUE.
When * opcode is NEWARRAY, operand value should be one of * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. */ public void visitIntInsn(int opcode, int operand) { } /* * Visits a local variable instruction. A local variable instruction is an * instruction that loads or stores the value of a local variable. * * @param opcode the opcode of the local variable instruction to be visited. * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, * LSTORE, FSTORE, DSTORE, ASTORE or RET. * @param var the operand of the instruction to be visited. This operand is * the index of a local variable. */ public void visitVarInsn(int opcode, int var) { } /* * Visits a type instruction. A type instruction is an instruction that * takes the internal name of a class as parameter. * * @param opcode the opcode of the type instruction to be visited. This * opcode is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. * @param type the operand of the instruction to be visited. This operand * must be the internal name of an object or array class (see {@link * Type#getInternalName() getInternalName}). */ public void visitTypeInsn(int opcode, String type) { ca.addReferencedType(Type.getObjectType(type)); } /* * Visits a field instruction. A field instruction is an instruction that * loads or stores the value of a field of an object. * * @param opcode the opcode of the type instruction to be visited. This * opcode is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. * @param owner the internal name of the field's owner class (see {@link * Type#getInternalName() getInternalName}). * @param name the field's name. * @param desc the field's descriptor (see {@link Type Type}). */ public void visitFieldInsn(int opcode, String owner, String name, String desc) { ca.addReferencedType(Type.getObjectType(owner)); ca.addReferencedType(Type.getType(desc)); } /* * Visits a method instruction. A method instruction is an instruction that * invokes a method. * * @param opcode the opcode of the type instruction to be visited. This * opcode is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, * INVOKEINTERFACE or INVOKEDYNAMIC. * @param owner the internal name of the method's owner class (see {@link * Type#getInternalName() getInternalName}) * or {@link org.objectweb.asm.Opcodes#INVOKEDYNAMIC_OWNER}. * @param name the method's name. * @param desc the method's descriptor (see {@link Type Type}). */ public void visitMethodInsn(int opcode, String owner, String name, String desc) { ca.addReferencedType(Type.getObjectType(owner)); Type[] argTypes = Type.getArgumentTypes(desc); for (int i=0; argTypes!=null && i.class constants, for classes whose version is 49.0 or * more). */ public void visitLdcInsn(Object cst) { } /* * Visits an IINC instruction. * * @param var index of the local variable to be incremented. * @param increment amount to increment the local variable by. */ public void visitIincInsn(int var, int increment) { } /* * Visits a TABLESWITCH instruction. * * @param min the minimum key value. * @param max the maximum key value. * @param dflt beginning of the default handler block. * @param labels beginnings of the handler blocks. labels[i] is * the beginning of the handler block for the min + i key. */ public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) { } /* * Visits a LOOKUPSWITCH instruction. * * @param dflt beginning of the default handler block. * @param keys the values of the keys. * @param labels beginnings of the handler blocks. labels[i] is * the beginning of the handler block for the keys[i] key. */ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { } /* * Visits a MULTIANEWARRAY instruction. * * @param desc an array type descriptor (see {@link Type Type}). * @param dims number of dimensions of the array to allocate. */ public void visitMultiANewArrayInsn(String desc, int dims) { ca.addReferencedType(Type.getType(desc)); } // ------------------------------------------------------------------------- // Exceptions table entries, debug information, max stack and max locals // ------------------------------------------------------------------------- /* * Visits a try catch block. * * @param start beginning of the exception handler's scope (inclusive). * @param end end of the exception handler's scope (exclusive). * @param handler beginning of the exception handler's code. * @param type internal name of the type of exceptions handled by the * handler, or null to catch any exceptions (for "finally" * blocks). * @throws IllegalArgumentException if one of the labels has already been * visited by this visitor (by the {@link #visitLabel visitLabel} * method). */ public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { if (null!=type) { ca.addReferencedType(Type.getObjectType(type)); } } /* * Visits a local variable declaration. * * @param name the name of a local variable. * @param desc the type descriptor of this local variable. * @param signature the type signature of this local variable. May be * null if the local variable type does not use generic * types. * @param start the first instruction corresponding to the scope of this * local variable (inclusive). * @param end the last instruction corresponding to the scope of this local * variable (exclusive). * @param index the local variable's index. * @throws IllegalArgumentException if one of the labels has not already * been visited by this visitor (by the * {@link #visitLabel visitLabel} method). */ public void visitLocalVariable( String name, String desc, String signature, Label start, Label end, int index) { ca.addReferencedType(Type.getType(desc)); } /* * Visits a line number declaration. * * @param line a line number. This number refers to the source file from * which the class was compiled. * @param start the first instruction corresponding to this line number. * @throws IllegalArgumentException if start has not already been * visited by this visitor (by the {@link #visitLabel visitLabel} * method). */ public void visitLineNumber(int line, Label start) { } /* * Visits the maximum stack size and the maximum number of local variables * of the method. * * @param maxStack maximum stack size of the method. * @param maxLocals maximum number of local variables for the method. */ public void visitMaxs(int maxStack, int maxLocals) { } /* * Visits the end of the method. This method, which is the last one to be * called, is used to inform the visitor that all the annotations and * attributes of the method have been visited. */ public void visitEnd() { } } knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/OSGiPackage.java0000644000175000017500000000425612346513674027601 0ustar felixfelix/* * Copyright (c) 2005, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; /** * @author Kaspar Weilenmann <kaspar@weilenmann.se> */ public class OSGiPackage { // private fields private String name = null; private String version = null; private String prefix = null; // public methods public String getName() { return name; } public void setName(String name) { this.name = name; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } } // OSGiPackage knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleArchives.java0000644000175000017500000011267312346513674030425 0ustar felixfelix/* * Copyright (c) 2010-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; 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.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.types.resources.FileResource; import org.osgi.framework.Constants; import org.osgi.framework.Version; import org.osgi.framework.VersionRange; import org.knopflerfish.ant.taskdefs.bundle.Util.HeaderEntry; /** * A class that analyzes all bundle jar files given by a list of resource * collections (file sets). * */ public class BundleArchives { // This constant is missing from org.osgi.framework.Constants public static final String BUNDLE_BLUEPRINT = "Bundle-Blueprint"; public static final String BUNDLE_LICENSE = "Bundle-License"; public static final String SERVICE_COMPONENT = "Service-Component"; /** Path prefix for source files included into the bundle archive. */ public static final String SRC_PREFIX = "OSGI-OPT/src"; /** * The ant task that is using this helper class. Used for logging etc. */ private final Task task; /** * Map from bundle name (the bundles file without version and ".jar" suffixes) * to a sorted set of a bundle archive object with details about the bundle . * The set will contain more than one element when more than one version of * the bundle has been found. */ final Map> bnToBundleArchives = new TreeMap>(); /** * Map from bundle symbolic name to a sorted set of a bundle archive object * with details about the bundle. The set will contain more than one element * when more than one version of the bundle has been found. */ final Map> bsnToBundleArchives = new TreeMap>(); /** * Set with all bundle archives specified by the given resource collections. */ final SortedSet allBundleArchives = new TreeSet(); /** * Set with all packages exported from some bundle in this collection of * bundle archives. The key in the map is the package name, the value is a map * from package version to a set of bundle archives that exports that version * of the package. * *

* A call to {@link #doProviders()} must be made to compute this mapping. *

*/ final SortedMap>> allExports = new TreeMap>>(); /** * Traverse the given list of resource collections and create * BundleArchive-objects for all bundle jars found. * * @param task * The task that uses this class, used for logging and project * access. * @param resourceCollections * The collection of resource collections selecting the bundle * archives to load. */ public BundleArchives(final Task task, final List resourceCollections) { this(task, resourceCollections, false); } /** * Traverse the given list of resource collections and create * BundleArchive-objects for all bundle jars found. * * @param task * The task that uses this class, used for logging and project * access. * @param resourceCollections * The collection of resource collections selecting the bundle * archives to load. * @param parseExportImport * If true then the created bundle archive objects will * parse the import / export package / service headers. */ public BundleArchives(final Task task, final List resourceCollections, final boolean parseExportImport) { this.task = task; if (resourceCollections.size() == 0) { task.log("BundleArchives called without any bundle archives to analyse", Project.MSG_ERR); throw new BuildException("No resource collections specified"); } try { for (final ResourceCollection rc : resourceCollections) { // Ignore file sets with a non existing root directory. if (rc instanceof FileSet) { final FileSet fs = (FileSet) rc; final File fsRootDir = fs.getDir(task.getProject()); if (!fsRootDir.exists()) { task.log("Skipping nested file set rooted at '" + fsRootDir + "' since that directory does not exist.", Project.MSG_WARN); continue; } try { if (fs.size() < 1) { task.log("Skipping nested file set rooted at '" + fsRootDir + "' since that file set is empty.", Project.MSG_VERBOSE); continue; } } catch (final Exception e) { task.log("Skipping nested file set rooted at '" + fsRootDir + "' since size computation throws exception.", e, Project.MSG_VERBOSE); continue; } } for (@SuppressWarnings("unchecked") final Iterator rcIt = rc.iterator(); rcIt.hasNext();) { final Resource res = rcIt.next(); if (res.getName().endsWith(".jar")) { task.log("Adding bundle: " + res, Project.MSG_VERBOSE); try { final BundleArchive ba = new BundleArchive(task, (FileResource) res, parseExportImport); allBundleArchives.add(ba); addToMap(bnToBundleArchives, ba.bundleName, ba); addToMap(bsnToBundleArchives, ba.bsn, ba); } catch (final Exception e) { final String msg = "Failed to analyze bundle archive: " + res + "; reason: " + e; task.log(msg); throw new BuildException(msg, e); } } } }// Scan done } catch (final BuildException be) { throw be; } catch (final Exception e) { final String msg = "Failed to analyze bundle archives: " + e; task.log(msg); throw new BuildException(msg, e); } } SortedSet getKnownNames() { final TreeSet knownNames = new TreeSet(bnToBundleArchives.keySet()); knownNames.addAll(bsnToBundleArchives.keySet()); return knownNames; } /** * Computes the global allExports mapping and the * pkgProvidersMap for all bundle archives. */ void doProviders() { // First build the allExports structure. allExports.clear(); for (final BundleArchive ba : allBundleArchives) { // Clear bundle archive maps holding results from this analysis ba.pkgProvidersMap.clear(); ba.pkgUnprovidedMap.clear(); ba.pkgProvidedMap.clear(); for (final Entry eE : ba.pkgExportMap.entrySet()) { final String pkgName = eE.getKey(); final Version pkgVersion = eE.getValue(); SortedMap> versions = allExports.get(pkgName); if (null == versions) { versions = new TreeMap>(); allExports.put(pkgName, versions); } SortedSet exporters = versions.get(pkgVersion); if (null == exporters) { exporters = new TreeSet(); versions.put(pkgVersion, exporters); } exporters.add(ba); } } // For each bundle build the pkgProvidersMap for (final BundleArchive ba : allBundleArchives) { for (final Entry iE : ba.pkgImportMap.entrySet()) { final String pkgName = iE.getKey(); final VersionRange range = iE.getValue(); final SortedMap> versions = allExports.get(pkgName); if (null != versions) { for (final Entry> vE : versions.entrySet()) { final Version pkgVersion = vE.getKey(); if (range.includes(pkgVersion)) { final SortedSet providers = vE.getValue(); for (final BundleArchive provider : providers) { // The package pkgName may be imported by ba from provider, // update ba's providers map SortedSet pkgNames = ba.pkgProvidersMap .get(provider); if (null == pkgNames) { pkgNames = new TreeSet(); ba.pkgProvidersMap.put(provider, pkgNames); } pkgNames.add(pkgName); // Non self exported package, add to pkgCtProvidersMap if (!ba.pkgExportMap.containsKey(pkgName)) { SortedSet pkgNamesCt = ba.pkgCtProvidersMap .get(provider); if (null == pkgNamesCt) { pkgNamesCt = new TreeSet(); ba.pkgCtProvidersMap.put(provider, pkgNamesCt); } pkgNamesCt.add(pkgName); } // The package pkgName is provided (exported) by // provider to ba, update provider.pkgProvidedMap to // reflect this. SortedSet pkgNamesProvidedToBa = provider.pkgProvidedMap .get(ba); if (null == pkgNamesProvidedToBa) { pkgNamesProvidedToBa = new TreeSet(); provider.pkgProvidedMap.put(ba, pkgNamesProvidedToBa); } pkgNamesProvidedToBa.add(pkgName); } } } } else { ba.pkgUnprovidedMap.put(pkgName, range); task.log(ba + " importing no provider for package " + pkgName + " " + range, Project.MSG_DEBUG); } } } } /** * Format the OSGi version as Maven 2 does in versioned file names. */ static private String toMavenVersion(final Version version) { final StringBuffer sb = new StringBuffer(40); sb.append(String.valueOf(version.getMajor())).append("."); sb.append(String.valueOf(version.getMinor())).append("."); sb.append(String.valueOf(version.getMicro())); final String qualifier = version.getQualifier(); if (0 < qualifier.length()) { sb.append("-").append(qualifier); } return sb.toString(); } /** * Add a bundle archive to a map using the given key. The values of the map * are sorted sets of bundle archives. */ private void addToMap(final Map> map, final String key, final BundleArchive ba) { if (null == key) { return; } SortedSet bas = map.get(key); if (null == bas) { bas = new TreeSet(); map.put(key, bas); task.log("Found bundle '" + key + "'.", Project.MSG_DEBUG); } if (bas.add(ba)) { task.log("Found bundle '" + key + "' '" + ba.version + "'.", Project.MSG_DEBUG); } } static String encodeBundleName(final String bundleName) { String name = bundleName; if (null != name) { name = name.replace(':', '.'); name = name.replace(' ', '_'); } return name; } /** * A BundleArchive-object describes one bundle with data derived from its file * name and manifest. */ static class BundleArchive implements Comparable { /** Task that uses this class, for logging. */ final Task task; /** File object referencing the bundle jar. */ final File file; /** The relative path from the root of the file set holding the bundle. */ final String relPath; /** The name of the bundle file without version and ".jar" suffix. */ final String bundleName; /** The name of the project that the bundle belongs to. */ final String projectName; // The manifest attributes and some parsed values final Attributes mainAttributes; final String manifestVersion; final String bsn; final Version version; final String name; /** Mapping from exported package name to its version. */ final Map pkgExportMap; /** Mapping from imported package name to its version range constraint. */ final Map pkgImportMap; /** Set with names of imported packages that are optional. */ final Set pkgImportOptional = new TreeSet(); /** * Collection of bundles that provides packages that this bundle are * importing. The mapping key is a bundle archive and the value is the set * of package names that the bundle archive may provide to this bundle. * *

* Initially empty, to fill in this map call {@link #doProviders()}. *

*/ final Map> pkgProvidersMap = new TreeMap>(); /** * Collection of bundles that provides packages that this bundle needs * access to at compile time. I.e., packages that the bundle is importing * but not exporting. The mapping key is a bundle archive and the value is * the set of package names that the bundle archive may provide to this * bundle. * *

* Initially empty, to fill in this map call {@link #doProviders()}. *

*/ final Map> pkgCtProvidersMap = new TreeMap>(); /** * Collection of bundles that this bundle provides packages to, i.e., * bundles importing the exports of this bundle. The mapping key is a bundle * archive and the value is the set of package names that the bundle archive * may import from this bundle. * *

* Initially empty, to fill in this map call {@link #doProviders()}. *

*/ final Map> pkgProvidedMap = new TreeMap>(); /** * Sub set of the entries in the imported packages map for which there are * no matching exporter. Mapping from package name to its version range * constraint. * *

* Initially empty, to fill in this map call {@link #doProviders()}. *

*/ final Map pkgUnprovidedMap = new TreeMap(); /** Mapping from exported service name to its version. */ final Map serviceExportMap; /** Mapping from imported service name to its version range constraint. */ final Map serviceImportMap; /** Number of source files inside the bundle archive. */ final int srcCount; /** * Create a bundle archive object for the given bundle jar file. * * @param task * The task that uses this class, used for logging and project * access. * @param resource * The bundle jar file to create a bundle archive object for. * @param parseExportImport * If true then populate the pkgExportMap, * pkgImportMap, pkgImportOptional set with data parsed from the * import / export package manifest attributes. */ @SuppressWarnings("deprecation") public BundleArchive(final Task task, final FileResource resource, final boolean parseExportImport) throws IOException { this.task = task; this.file = resource.getFile(); this.relPath = resource.getName(); // Get data from the bundles manifest and contents final JarFile bundle = new JarFile(file); try { final Manifest manifest = bundle.getManifest(); this.mainAttributes = manifest.getMainAttributes(); this.manifestVersion = deriveBundleManifestVersion(); this.bsn = deriveBundleSymbolicName(); this.version = deriveBundleVersion(); this.name = mainAttributes.getValue(Constants.BUNDLE_NAME); int count = 0; for (final Enumeration e = bundle.entries(); e.hasMoreElements();) { final ZipEntry entry = e.nextElement(); if (entry.getName().startsWith(SRC_PREFIX)) { count++; } } srcCount = count; } finally { if (null != bundle) { try { bundle.close(); } catch (final IOException _ioe) { } } } // Derive bundle name, bn, from the file name and the manifest version. // The file name format is "-.jar" String bn = null; final String fileName = file.getName(); final String versionSuffix = "-" +this.version.toString() +".jar"; if (fileName.endsWith(versionSuffix)) { // Simple case when Version.toString() returns the version // string in the file name. bn = fileName.substring(0, fileName.length() -versionSuffix.length()); } else { // Try to find a valid version in the file name that matches // the one in the manifest int ix = fileName.lastIndexOf('-'); while (0Bundle-SymbolicName attribute is missing use the * Bundle-Name but replace all ':' with '.' and all ' ' with * '_' in the returned value. * */ private String deriveBundleSymbolicName() { String name = mainAttributes.getValue(Constants.BUNDLE_SYMBOLICNAME); if (null == name) { if ("1".equals(manifestVersion)) { name = mainAttributes.getValue(Constants.BUNDLE_NAME); } } else { // Remove any directive from the name final int semiPos = name.indexOf(";"); if (-1 < semiPos) { name = name.substring(0, semiPos); } name = name.trim(); } return BundleArchives.encodeBundleName(name); } /** * Get the bundle version from the manifest. */ private Version deriveBundleVersion() throws NumberFormatException { final String versionS = mainAttributes.getValue(Constants.BUNDLE_VERSION); if (null == versionS) { return Version.emptyVersion; } try { return new Version(versionS); } catch (final NumberFormatException nfe) { if ("1".equals(manifestVersion)) { // Pre OSGi R4 bundle with non-standard version format; use // the default version. return Version.emptyVersion; } final String msg = "Invalid bundle version '" + versionS + "' found in " + file + ": " + nfe; task.log(msg, Project.MSG_ERR); throw new BuildException(msg, nfe); } catch (final IllegalArgumentException iae) { if ("1".equals(manifestVersion)) { // Pre OSGi R4 bundle with non-standard version format; use // the default version. return Version.emptyVersion; } final String msg = "Invalid bundle version '" + versionS + "' found in " + file + ": " + iae; task.log(msg, Project.MSG_ERR); throw new BuildException(msg, iae); } } /** * Parse import/export package/service headers. * * @param s * The name the header to parse. * @param range * if versions shall be parsed as ranges or not. * @param optionals * Optional Set to add packages that are marked with the directive * resolution:=optional to. * * @param valueType * The desired type of the value in the returned Mapping. Supported * types are {@link Version} and {@link VersionRange}. * * @return Mapping from package/service name to version/version range. */ @SuppressWarnings("deprecation") private Map parseNames(String s, boolean range, Set optionals, Class valueType) { final TreeMap res = new TreeMap(); final String v = mainAttributes.getValue(s); final List entries = Util.parseManifestHeader(s, v, false, true, false); for (final HeaderEntry entry : entries) { String versionS = (String) entry.attributes.get(Constants.VERSION_ATTRIBUTE); // Fall back to "specification-version" for pre OSGi R4 bundles. if (null == versionS) { versionS = (String) entry.attributes .get(Constants.PACKAGE_SPECIFICATION_VERSION); } if (null == versionS) { versionS = "0"; // The default version } if (valueType.equals(Version.class)) { @SuppressWarnings("unchecked") final V version = (V) new Version(versionS); for (final String key : entry.getKeys()) { res.put(key, version); } } else if (valueType.equals(VersionRange.class)) { @SuppressWarnings("unchecked") final V versionRange = (V) new VersionRange(versionS); for (final String key : entry.getKeys()) { res.put(key, versionRange); } } if (entry.directives.containsKey(Constants.RESOLUTION_DIRECTIVE) && Constants.RESOLUTION_OPTIONAL.equals(entry.directives .get(Constants.RESOLUTION_DIRECTIVE))) { optionals.addAll(entry.getKeys()); } } return res; } public String getBundleDescription() { final String res = mainAttributes.getValue(Constants.BUNDLE_DESCRIPTION); return null == res ? res : res.trim(); } public List getBundleLicense() { String value = mainAttributes.getValue(BundleArchives.BUNDLE_LICENSE); if (null != value) { value = value.trim(); } try { return Util.parseManifestHeader(BundleArchives.BUNDLE_LICENSE, value, true, true, false); } catch (final Exception e) { final String msg = "Failed to parse " + BundleArchives.BUNDLE_LICENSE + " manifest header '" + value + "' in " + file + ": " + e; throw new BuildException(msg, e); } } /** * @return true if this bundle includes Declarative Services * Components, false otherwise. */ public boolean isSCBundle() { return null != mainAttributes.getValue(BundleArchives.SERVICE_COMPONENT); } /** * @return true if this bundle includes blueprint components, * false otherwise. */ public boolean isBlueprintBundle() { // TODO: If header not present the default pattern, // "OSGI-INF/blueprint/*.xml" should be checked. return null != mainAttributes.getValue(BundleArchives.BUNDLE_BLUEPRINT); } /** * @return true if this bundle includes a bundle activator, * false otherwise. */ public boolean isActivatorBundle() { return null != mainAttributes.getValue(Constants.BUNDLE_ACTIVATOR); } /** * @return true if this bundle is an API only bundle. I.e. if * it exports packages but does not have a bundle activator, service * component or blueprint component. activator, false * otherwise. */ public boolean isAPIBundle() { return 0 < pkgExportMap.size() && !isActivatorBundle() && !isSCBundle() && !isBlueprintBundle(); } /** * Extract source from inside the bundle to the given destination directory. * If bundle does not contain any source files try to copy source files from * the bundles src-directory (derived from the Built-From * manifest attribute. * * @param destDir * The directory to extract the source files to. * @return List with one entry for each extracted file. The value is the * path relative to destDir. * @throws IOException */ public List extractSources(File destDir) throws IOException { final List res = new ArrayList(); final JarFile jarFile = new JarFile(file); for (final Enumeration e = jarFile.entries(); e.hasMoreElements();) { final ZipEntry entry = e.nextElement(); if (entry.getName().startsWith(SRC_PREFIX)) { if (0 == res.size()) { destDir.mkdirs(); } if (entry.isDirectory()) { makeDir(destDir, entry, SRC_PREFIX); } else { copyEntry(destDir, jarFile, entry, SRC_PREFIX); res.add(Util.replace(entry.getName(), SRC_PREFIX + "/", "")); } } } if (0 == res.size()) { // Check if we can copy source from original pos final String sourceDir = mainAttributes.getValue("Built-From"); if (sourceDir != null && !"".equals(sourceDir)) { final File src = new File(sourceDir, "src"); res.addAll(copyTree(src, destDir, src.toString() + File.separator, ".java")); } } return res; } private static void makeDir(final File destDir, final ZipEntry entry, final String prefix) throws IOException { final File d = new File(destDir, Util.replace(entry.getName(), prefix, "")); d.mkdirs(); } private static void copyEntry(File destDir, ZipFile file, ZipEntry entry, String prefix) throws IOException { final File destFile = new File(destDir, Util.replace(entry.getName(), prefix, "")); final File dir = destFile.getParentFile(); if (!dir.exists()) { dir.mkdirs(); } copyStream(new BufferedInputStream(file.getInputStream(entry)), new BufferedOutputStream(new FileOutputStream(destFile))); } private static void copyStream(final InputStream is, final OutputStream os) throws IOException { final byte[] buf = new byte[1024]; BufferedInputStream in = null; BufferedOutputStream out = null; try { in = new BufferedInputStream(is); out = new BufferedOutputStream(os); int n; while ((n = in.read(buf)) > 0) { out.write(buf, 0, n); } } finally { try { in.close(); } catch (final Exception ignored) { } try { out.close(); } catch (final Exception ignored) { } } } private static List copyTree(File dest, File src, String prefix, String suffix) throws IOException { final List res = new ArrayList(); if (src.isDirectory()) { if (!dest.exists()) { dest.mkdirs(); } final String[] files = src.list(); for (final String file2 : files) { res.addAll(copyTree(new File(dest, file2), new File(src, file2), prefix, suffix)); } } else if (src.isFile()) { if (src.getName().endsWith(suffix)) { copyStream(new FileInputStream(src), new FileOutputStream(dest)); res.add(Util.replace(Util.replace(src.getAbsolutePath(), prefix, ""), "\\", "/")); } } return res; } /** * Build a mapping holding one entry for each source file found in the * SVN-repository for the bundle. The repository URL of a source file is the * repoUrl followed by the part of the file path that remains when the * pathPrefix has been removed. * * @param pathPrefix * The path of source files to include must start with this value. * @param repoURL * The URL to the SVN repository. * * @return Mapping where the key is the name (path) of the source file and * the value the repository URL to it. * @throws IOException */ public Map getSrcRepositoryLinks(final String pathPrefix, final URL repoURL) throws IOException { final Map res = new TreeMap(); // Check if we can locate a source tree based on the // "Built-From" header. final String rootDir = mainAttributes.getValue("Built-From"); if (null != rootDir && 0 < rootDir.length()) { final File src = new File(rootDir, "src"); if (src.isDirectory()) { res.putAll(srcRepositoryLinks(pathPrefix, repoURL, src, src.getAbsolutePath() + File.separator)); } else { task.log( "No src sub-directory in 'Built-From' location, " + src.getAbsolutePath() + ", can not locate source files.", Project.MSG_VERBOSE); } } else { task.log("No 'Built-From' manifest header in bundle, " + "can not locate source files.", Project.MSG_VERBOSE); } return res; } private Map srcRepositoryLinks(final String pathPrefix, final URL repoURL, final File src, final String prefix) throws IOException { final Map res = new TreeMap(); if (src.isDirectory()) { final String[] files = src.list(); for (final String file2 : files) { res.putAll(srcRepositoryLinks(pathPrefix, repoURL, new File(src, file2), prefix)); } } else if (src.isFile()) { final String path = src.getAbsolutePath(); if (src.getName().endsWith(".java")) { final String bundlePath = Util.replace(path, prefix, ""); if (path.startsWith(pathPrefix)) { final String repoPath = Util.replace(path, pathPrefix, "").replace( File.separatorChar, '/'); final String href = new URL(repoURL, repoPath).toString(); res.put(bundlePath, href); task.log("Found Java source file in repository, " + path + " with href '" + href + "'.", Project.MSG_VERBOSE); } else { task.log("Skipping non-repository Java source file, " + path + ".", Project.MSG_DEBUG); } } else { task.log("Skipping non-Java source file, " + path + ".", Project.MSG_DEBUG); } } return res; } } // class BundleArchive } knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/ClassAnalyserASM.java0000644000175000017500000002632312346513674030630 0ustar felixfelix/* * Copyright (c) 2003-2010, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Type; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; /** * Visitor implementation that populates a BundlePackagesInfo object * with data about the given class. */ public class ClassAnalyserASM implements ClassVisitor { /** * The name of the bundle activator interface on internal form. */ final static private String BUNDLE_ACTIVATOR = "org/osgi/framework/BundleActivator"; // The BundlePackagesInfo object to populate with data. final BundlePackagesInfo bpInfo; // The task using this object to provide logging functionality. final Task task; // The package of the current class. String currentPackage = null; // The File of the current class. File currentClassFile = null; public ClassAnalyserASM(final BundlePackagesInfo bpInfo, final Task task) { this.bpInfo = bpInfo; this.task = task; } public synchronized void analyseClass(File clsFile) { FileInputStream fis = null; try { fis = new FileInputStream(clsFile); analyseClass(fis, clsFile.toString()); } catch (Exception e) { e.printStackTrace(); } finally { if (null!=fis) { try { fis.close(); } catch (Exception _ec) {} } } } public synchronized void analyseClass(InputStream clsIn, String fileName) { try { ClassReader cr = new ClassReader(clsIn); currentClassFile = new File(fileName); cr.accept(this, 0); } catch (Exception e) { e.printStackTrace(); } } protected void addReferencedType(final Type type) { switch (type.getSort()) { case Type.OBJECT: bpInfo.addReferencedClass(currentPackage, type.getInternalName()); break; case Type.ARRAY: addReferencedType(type.getElementType()); break; default: } } /* * Visits the header of the class. * * @param version the class version. * @param access the class's access flags (see {@link Opcodes}). This * parameter also indicates if the class is deprecated. * @param name the internal name of the class (see * {@link Type#getInternalName() getInternalName}). * @param signature the signature of this class. May be null if * the class is not a generic one, and does not extend or implement * generic classes or interfaces. * @param superName the internal of name of the super class (see * {@link Type#getInternalName() getInternalName}). For interfaces, * the super class is {@link Object}. May be null, but * only for the {@link Object} class. * @param interfaces the internal names of the class's interfaces (see * {@link Type#getInternalName() getInternalName}). May be * null. */ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { task.log("Analysing class '" +name +"'.", Project.MSG_VERBOSE); currentPackage = bpInfo.addProvidedClass(name); if (null!=superName) { addReferencedType(Type.getObjectType(superName)); } for(int i = 0; i < interfaces.length; i++) { addReferencedType(Type.getObjectType(interfaces[i])); if (BUNDLE_ACTIVATOR.equals(interfaces[i])) { bpInfo.addProvidedActivatorClass(name); } } } /* * Visits the source of the class. * * @param source the name of the source file from which the class was * compiled. May be null. * @param debug additional debug information to compute the correspondence * between source and compiled elements of the class. May be * null. */ public void visitSource(String source, String debug) { } /* * Visits the enclosing class of the class. This method must be called only * if the class has an enclosing class. * * @param owner internal name of the enclosing class of the class. * @param name the name of the method that contains the class, or * null if the class is not enclosed in a method of its * enclosing class. * @param desc the descriptor of the method that contains the class, or * null if the class is not enclosed in a method of its * enclosing class. */ public void visitOuterClass(String owner, String name, String desc) { } /* * Visits an annotation of the class. * * @param desc the class descriptor of the annotation class. * @param visible true if the annotation is visible at runtime. * @return a visitor to visit the annotation values, or null if * this visitor is not interested in visiting this annotation. */ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { return null; } /* * Visits a non standard attribute of the class. * * @param attr an attribute. */ public void visitAttribute(Attribute attr) { } /* * Visits information about an inner class. This inner class is not * necessarily a member of the class being visited. * * @param name the internal name of an inner class (see * {@link Type#getInternalName() getInternalName}). * @param outerName the internal name of the class to which the inner class * belongs (see {@link Type#getInternalName() getInternalName}). May * be null for not member classes. * @param innerName the (simple) name of the inner class inside its * enclosing class. May be null for anonymous inner * classes. * @param access the access flags of the inner class as originally declared * in the enclosing class. */ public void visitInnerClass(String name, String outerName, String innerName, int access) { } /* * Visits a field of the class. * * @param access the field's access flags (see {@link Opcodes}). This * parameter also indicates if the field is synthetic and/or * deprecated. * @param name the field's name. * @param desc the field's descriptor (see {@link Type Type}). * @param signature the field's signature. May be null if the * field's type does not use generic types. * @param value the field's initial value. This parameter, which may be * null if the field does not have an initial value, must * be an {@link Integer}, a {@link Float}, a {@link Long}, a * {@link Double} or a {@link String} (for int, * float, long or String fields * respectively). This parameter is only used for static fields. * Its value is ignored for non static fields, which must be * initialized through bytecode instructions in constructors or * methods. * @return a visitor to visit field annotations and attributes, or * null if this class visitor is not interested in * visiting these annotations and attributes. */ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { addReferencedType(Type.getType(desc)); return null; } /* * Visits a method of the class. This method must return a new * {@link MethodVisitor} instance (or null) each time it is * called, i.e., it should not return a previously returned visitor. * * @param access the method's access flags (see {@link Opcodes}). This * parameter also indicates if the method is synthetic and/or * deprecated. * @param name the method's name. * @param desc the method's descriptor (see {@link Type Type}). * @param signature the method's signature. May be null if the * method parameters, return type and exceptions do not use generic * types. * @param exceptions the internal names of the method's exception classes * (see {@link Type#getInternalName() getInternalName}). May be * null. * @return an object to visit the byte code of the method, or null * if this class visitor is not interested in visiting the code of * this method. */ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { Type[] argTypes = Type.getArgumentTypes(desc); for (int i=0; argTypes!=null && i * This task is used when building bundle user documentation for a * Knopflerfish release, it builds the navigation frame listing * bundles with user documentation. If you don't intend to create a * new distribution type of Knopflerfish then you're in the wrong * place. *

* *

* Here is a outline of how to use the task and a description * of different parameters and used system properties. *

* *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
* outdir * * Where to put the generated file (directory). * * Yes *
* tofile * * The relative path to where the generated file should be * copied. That is the actual location of the generated file * will be outdir/tofile. * * Yes *
* template * * The file which describes what the page should look like. * * Yes *
* title * * The title to use on the generated page. * * Yes *
* docdir * * The directory with one sub-directory for each user documentation * link to create. Defaults to outdir. * *

All sub-directories of docdir will result in a link * on the generated navigation page. The link will belong to the * default category, have a title set to the name of the * sub-directory and a link path pointing to the file * "index.html" inside the sub-directory. The default link properties * may be overridden by specifying other values in a * properties file named doc.properties in the * sub-directory.

* *

The following keys in the properties file are used:

* *
* *
category
*
The name of the category to present the link under.
* *
The link text.
*
title
* *
linkPath
*
The path that the link points to. The default is a relative * path pointing to the file index.html inside the * sub-directory holding the properties file.
* *
linkRef
*
A reference part to append to the generated link. I.e., this will * make a link that points a named anchor on the linked page. * *
sortKey
*
String to use when sorting links. Default is the value of * the title key.
* *
depth
*
Nesting depth of link presentation. Default is 1. Must * be one or greater.
* *
* *

It is possible to generate more than one link from the same * doc.properties file. To do this insert a * linkCount key with the number of links to create as * its value. Then for each link add all the keys defined above * with the link number followed by a '.' as key-prefix. Link * number prefixes starts with 0 and must be strictly smaller * than the value of linkCount. If there is no category * value with a link number prefix the un-prefixed category value * will be used. I.e., if all links belongs to the same category * it suffices to write the category name once.

* *
* Yes *
* defaultcategory * * The name of the category to place links under when not specified * in the doc-subdirectory. * * No, defaults to "bundle". *
*/ public class BundleUserDocNavigateTask extends Task { public static final String DOC_PROPS_FILE_NAME = "doc.properties"; /** * Target directory, where everything will end up */ private File outDir; public void setOutdir(File f) { outDir = f; if (null==docDir) { docDir = f; } } /** * The relative path to the target file from output dir */ private String toFileName; public void setTofile(String s) { toFileName = s; } /** * Template file */ private File template; public void setTemplate(File f) { template = f; } /** * The title of the generated page */ private String pageTitle; public void setTitle(String s) { pageTitle = s; } /** * The directory to analyze sub-directories in. */ private File docDir; public void setDocdir(File f) { docDir = f; } /** * The default category name */ private String defaultCategory = "bundle"; public void setDefaultcategory(String s) { defaultCategory = s; } // Mapping from category name to sorted set with link data. private final Map> categories = new HashMap>(); // Insert a link data item to a category in the categories map private void add(final String category, final LinkData ld) { SortedSet lds = categories.get(category); if (null==lds) { lds = new TreeSet(); categories.put(category, lds); } lds.add(ld); } // Build a html-string with links to the lds in the set. private String links(final Set lds) { final StringBuffer sb = new StringBuffer(1024); for (final LinkData ld : lds) { sb.append("

"); sb.append(" 0) { sb.append("#").append(ld.linkRef); } sb.append("\">"); sb.append(ld.title); sb.append("
\n"); } return sb.toString(); } // The data needed to create a document link in a category. static class LinkData implements Comparable { String title; String linkPath; String linkRef; String sortKey; int depth = 1; public LinkData(final String title, final String linkPath) { this.title = title; this.sortKey = title.toLowerCase(); this.linkPath = linkPath; } @Override public int compareTo(LinkData other) { return sortKey.compareTo(other.sortKey); } } private String fillLinkData(final Properties docProps, final String prefix, final LinkData ld) { ld.title = docProps.getProperty(prefix +"title", ld.title); ld.sortKey = docProps.getProperty(prefix +"sortKey", ld.title); ld.linkPath = docProps.getProperty(prefix +"linkPath", ld.linkPath); ld.linkRef = docProps.getProperty(prefix +"linkRef", ld.linkRef); final String sd = docProps.getProperty(prefix +"depth"); if (null!=sd && 0> entry : categories.entrySet()) { final String category = entry.getKey(); final Set lds = entry.getValue(); final String ldHtml = links(lds); if (0 * *

Parameters

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
templateAntFile * Path to a template ant file for creating Maven 2 repositories. * Yes.
No default value.
outDir * Directory to write generated files to. I.e., the intermediate * build file and the dependency management file. * Yes.
No default value.
buildFile * Name of the intermediate ant build file that this task creates. * Yes.
No default value.
dependencyManagementFile * Name of the XML file with a * <dependencyManagement>-element describing all the * artifacts that will be created by the generated build file. The * file is written to the outDir by this task, then * copied to the directory for the default group id by the * generated intermediate build file. * No.
No default value.
version * Value of the version attribute on the root element of the * dependency management file. * No.
No default value.
product * Value to put into the product attribute on the root element of the * dependency management file. * No.
Knopflerfish
repoDir * The path to the root of the maven 2 repository to update with * the artefacts identified by this task. * Yes.
No default value.
groupId * Maven group id to use for bundles, for which a group id can not * be derived from the bundles symbolic name. * No.
Default 'org.knopflerfish'.
settingsFile * The maven settings.xml file to use when loading pom-files. * No.
No default value.
* *

Parameters specified as nested elements

*

fileset

* * (required)
*

* All jar files selected by the fileset will be included. *

* *

Examples

* *
 * <bundlemvnant templateAntFile  = "${ant.dir}/ant_templates/toMvn.xml"
 *                  repoDir          = "${distrib.mvn.repo.dir}"
 *                  outDir           = "${root.out.dir}"
 *                  buildFile        = "toMvn.xml"
 *   >
 *
 *     <fileset dir="${release.dir}/osgi/jars">
 *       <include name = "**/*.jar"/>
 *     </fileset>
 * 
* */ public class BundleMvnAntTask extends Task { private BundleArchives bas; public BundleMvnAntTask() { } private String groupId = "org.knopflerfish"; public void setGroupId(final String s) { this.groupId = s; } private File templateAntFile; public void setTemplateAntFile(File f) { templateAntFile = f; if(!templateAntFile.exists()) { throw new BuildException("templateAntFile: " + f + " does not exist"); } if(!templateAntFile.isFile()) { throw new BuildException("templateAntFile: " + f + " is not a file"); } } private File outDir; public void setOutDir(File f) { outDir = f; } private String buildFileName; private File buildFile; public void setBuildFile(String f) { if(null==f || 0==f.length()) { throw new BuildException("The attribute 'buildFile' must be non-null."); } buildFileName = f; } private String dependencyManagementFileName; private File dependencyManagementFile; public void setDependencyManagementFile(String f) { if(null==f || 0==f.length()) { throw new BuildException("The attribute 'dependencyManagementFile' must be non-null."); } dependencyManagementFileName = f; } private String version = "0.0.0"; public void setVersion(final String s) { this.version = s; } private String product = "Knopflerfish"; public void setProduct(final String s) { this.product = s; } private File repoDir; public void setRepoDir(File f) { repoDir = f; } private File settingsFile; public void setSettingsFile(File f) { if(null!=f && f.exists() && !f.canRead()) { throw new BuildException("settingsFile: " + f + " exists but is not readable"); } settingsFile = f; } private final List rcs = new ArrayList(); public void addFileSet(FileSet fs) { rcs.add(fs); } // Implements Task @Override public void execute() throws BuildException { if (null==outDir) { throw new BuildException("Mandatory attribute 'outDir' missing."); } outDir.mkdirs(); if (null==buildFileName) { throw new BuildException("Mandatory attribute 'buildFile' missing."); } buildFile = new File(outDir,buildFileName); if (null==dependencyManagementFileName) { throw new BuildException("Mandatory attribute 'dependencyManagementFile' missing."); } dependencyManagementFile = new File(outDir, dependencyManagementFileName); if (null==repoDir) { throw new BuildException("Mandatory attribute 'repoDir' missing."); } log("Loading bundle information:", Project.MSG_VERBOSE); bas = new BundleArchives(this, rcs, true); bas.doProviders(); try { writeBuildFile(); writeDependencyManagementFile(); } catch (final Exception e) { final String msg = "Failed to create ant build file: " +e; log(msg, Project.MSG_ERR); throw new BuildException(msg, e); } } private void writeBuildFile() throws IOException { log("Creating build file: " + buildFile, Project.MSG_VERBOSE); final String prefix1 = " "; final String prefix2 = prefix1 + " "; final Document doc = FileUtil.loadXML(templateAntFile); final Element project = doc.getDocumentElement(); setPropertyValue(project,"group.id", groupId); setPropertyLocation(project,"ant.dir", getProject().getProperty("ant.dir")); setPropertyLocation(project,"out.dir", outDir.getAbsolutePath()); setPropertyLocation(project,"mvn2.repo.dir", repoDir.getAbsolutePath()); // Path to the dependency managment file that this task will write. setPropertyLocation(project, "dependency.management.file", dependencyManagementFile.getAbsolutePath()); // Path to the dependency managment file in the repository File depMgmtRepoFile = new File(repoDir, groupId.replace('.', File.separatorChar)); depMgmtRepoFile = new File(depMgmtRepoFile, dependencyManagementFile.getName()); setPropertyLocation(project, "dependency.management.repo.file", depMgmtRepoFile.getAbsolutePath()); final StringBuffer targetNames = new StringBuffer(2048); for (final Entry> entry : bas.bsnToBundleArchives.entrySet()) { final SortedSet bsnSet = entry.getValue(); // Sorted set with bundle archives, same bsn, different versions for (final BundleArchive ba : bsnSet) { final String targetName = ba.bsn + "-" + ba.version; targetNames.append(",").append(targetName); final Comment comment = doc.createComment(ba.relPath); final Element target = doc.createElement("target"); target.setAttribute("name", targetName); final Element mvnDeployBundle = doc.createElement("mvn_deploy_bundle"); target.appendChild(doc.createTextNode("\n"+prefix2)); target.appendChild(mvnDeployBundle); mvnDeployBundle.setAttribute("projDirName", ba.projectName); addMavenCoordinates(mvnDeployBundle, ba); mvnDeployBundle.setAttribute("artifactName", ba.name); mvnDeployBundle.setAttribute("artifactBundle", ba.file.getAbsolutePath()); mvnDeployBundle.setAttribute("packing", "jar"); // Optional attributes final String description = ba.getBundleDescription(); if (null != description) { mvnDeployBundle.setAttribute("description", description); } if (null!=settingsFile) { mvnDeployBundle.setAttribute("settingsFile", settingsFile.getAbsolutePath()); } addLicense(mvnDeployBundle, ba, prefix2); addDependencies(mvnDeployBundle, ba, prefix2); addSourceAttachment(mvnDeployBundle, ba, prefix2); addJavadocAttachment(mvnDeployBundle, ba, prefix2); // Put the end of the target-element on a separate line target.appendChild(doc.createTextNode("\n"+prefix1)); project.appendChild(doc.createTextNode("\n"+prefix1)); project.appendChild(comment); project.appendChild(doc.createTextNode("\n"+prefix1)); project.appendChild(target); project.appendChild(doc.createTextNode("\n"+prefix1)); } } setTargetAttr(project, "all", "depends", "init" +targetNames.toString()); FileUtil.writeDocumentToFile(buildFile, doc); log("wrote " + buildFile, Project.MSG_VERBOSE); } private void writeDependencyManagementFile() throws IOException { if (null==dependencyManagementFile) { return; } log("Creating dependency management file: " + dependencyManagementFile, Project.MSG_VERBOSE); final String prefix1 = " "; final String prefix2 = prefix1 + " "; final String prefix3 = prefix2 + " "; final Document doc = FileUtil.createXML("KF"); final Element root = doc.getDocumentElement(); // Create and add the xml-stylesheet instruction final ProcessingInstruction pi = doc.createProcessingInstruction("xml-stylesheet", "type='text/xsl' href='mvn_dep_mgmt.xsl'"); doc.insertBefore(pi, root); root.setAttribute("version", version); root.setAttribute("product", product); root.appendChild(doc.createTextNode("\n")); final Element dm = doc.createElement("dependencyManagement"); root.appendChild(dm); // Element hodling extra presentation data for each bundle artifact final Element bundles = doc.createElement("bundles"); root.appendChild(doc.createTextNode("\n")); root.appendChild(bundles); dm.appendChild(doc.createTextNode("\n"+prefix1)); final Element dependencies = doc.createElement("dependencies"); dm.appendChild(dependencies); for (final Entry> entry : bas.bsnToBundleArchives.entrySet()) { final SortedSet bsnSet = entry.getValue(); // Sorted set with bundle archives, same bsn, different versions for (final BundleArchive ba : bsnSet) { dependencies.appendChild(doc.createTextNode("\n\n" +prefix2)); dependencies.appendChild(doc.createComment(ba.relPath)); dependencies.appendChild(doc.createTextNode("\n" +prefix2)); final Element dependency = doc.createElement("dependency"); dependencies.appendChild(dependency); // Dummy element to read mvn coordinates from final Element coordinateEl = doc.createElement("dummy"); addMavenCoordinates(coordinateEl, ba); addMavenCoordinates(coordinateEl, dependency, prefix3); dependency.appendChild(doc.createTextNode("\n" +prefix2)); // Bundle metadata for xsl rendering final Element bundle = doc.createElement("bundle"); bundles.appendChild(doc.createTextNode("\n" +prefix2)); bundles.appendChild(bundle); bundle.appendChild(doc.createTextNode("\n" +prefix3)); final Element name = doc.createElement("name"); bundle.appendChild(name); name.appendChild(doc.createTextNode(ba.name)); log("name: " +ba.name, Project.MSG_VERBOSE); String description = ba.getBundleDescription(); log("description: " +description, Project.MSG_VERBOSE); if (null==description) { description = ""; } bundle.appendChild(doc.createTextNode("\n" +prefix3)); final Element descrEl = doc.createElement("description"); bundle.appendChild(descrEl); descrEl.appendChild(doc.createTextNode(description)); addMavenCoordinates(coordinateEl, bundle, prefix3); bundle.appendChild(doc.createTextNode("\n" +prefix3)); String mvnPath = getMavenPath(coordinateEl); final String groupIdPath = groupId.replace('.','/'); if (mvnPath.startsWith(groupIdPath)) { mvnPath = mvnPath.substring(groupIdPath.length()+1); } else { // Add one "../" to mvnPath for each level in the groupId mvnPath = "../" +mvnPath; int sPos = groupIdPath.indexOf('/'); while (-1.", Project.MSG_DEBUG); property.setAttribute("value", value); found = true; break; } } if (!found) { throw new BuildException("No in XML document " +el); } } /** * Set the location of the named ant property. The property must exist and be * a child of the specified element. * * @param elem * The element owning the property element to update * @param name * The name of the property to set location of. * @param location * The new location value. */ private void setPropertyLocation(final Element el, final String name, final String location) { final NodeList propertyNL = el.getElementsByTagName("property"); boolean found = false; for (int i = 0; i.", Project.MSG_DEBUG); property.setAttribute("location", location); found = true; break; } } if (!found) { throw new BuildException("No in XML document " +el); } } /** * Set an attribute on the named target element. The target element must exist * and be a child of the project-element. * * @param el * The element owning the target element to be updated. * @param name * The name of the target-element to set an attribute for. * @param attrName * The name of the attribute to set. * @param attrValue * The new attribute value. */ private void setTargetAttr(final Element el, final String name, final String attrName, final String attrValue) { final NodeList propertyNL = el.getElementsByTagName("target"); boolean found = false; for (int i = 0; i.", Project.MSG_DEBUG); target.setAttribute(attrName, attrValue); found = true; break; } } if (!found) { throw new BuildException("No in XML document " +el); } } /** * Add Maven coordinates as attributes for group id, artifact id and * version to the given element. * * @param el * The element to add Maven coordinates to. * @param ba * The bundle archive to defining the coordinates. */ private void addMavenCoordinates(final Element el, final BundleArchive ba) { final int ix = ba.bsn.lastIndexOf('.'); final String aId = -1==ix ? ba.bsn : ba.bsn.substring(ix+1); final String gId = -1==ix ? (String) groupId : ba.bsn.substring(0,ix); final Version v = ba.version; if (null!=gId) { el.setAttribute("groupId", gId); } el.setAttribute("artifactId", aId); el.setAttribute("version", v.toString()); } /** * Add Maven coordinates specified as attributes on the first * element as child elements to the second element. * * @param ela * The element with Maven coordinates as attributes. * @param elc * The element to add Maven coordinates as childe nodes to. */ private void addMavenCoordinates(final Element ela, final Element elc, final String prefix) { final Document doc = elc.getOwnerDocument(); elc.appendChild(doc.createTextNode("\n" +prefix)); final Element groupId = doc.createElement("groupId"); elc.appendChild(groupId); groupId.appendChild(doc.createTextNode(ela.getAttribute("groupId"))); elc.appendChild(doc.createTextNode("\n" +prefix)); final Element artifactId = doc.createElement("artifactId"); elc.appendChild(artifactId); artifactId.appendChild(doc.createTextNode(ela.getAttribute("artifactId"))); elc.appendChild(doc.createTextNode("\n" +prefix)); final Element version = doc.createElement("version"); elc.appendChild(version); version.appendChild(doc.createTextNode(ela.getAttribute("version"))); } /** * Build the relative path to the bundle represented by the given * maven coordinates. * * @param ela * An element with Maven coordinates as attributes. * * @return relative path from the root of the maven2 repository to * the bundle represented by the spceified coordinates. */ private String getMavenPath(final Element ela) { final String path = ela.getAttribute("groupId").replace('.','/') +"/" +ela.getAttribute("artifactId") +"/" +ela.getAttribute("version") +"/" +ela.getAttribute("artifactId") +"-" +ela.getAttribute("version") +".jar"; return path; } /** * Add licenses element for the given bundle to the string buffer. * * @param el * element to add the license element to. * @param ba * The bundle archive to defining the coordinates. * @param prefix * Whitespace to added before the owning element. */ private void addLicense(final Element el, final BundleArchive ba, final String prefix) { final Element licenses = el.getOwnerDocument().createElement("licenses"); final String prefix1 = prefix + " "; final String prefix2 = prefix1 + " "; el.appendChild(el.getOwnerDocument().createTextNode("\n"+prefix1)); el.appendChild(licenses); el.appendChild(el.getOwnerDocument().createTextNode("\n"+prefix)); boolean addDefault = true; final List licenseEntries = ba.getBundleLicense(); for (final HeaderEntry licenseEntry : licenseEntries) { addDefault = false; final Element license = el.getOwnerDocument().createElement("license"); license.setAttribute("name", licenseEntry.getKey()); licenses.appendChild(el.getOwnerDocument().createTextNode("\n"+prefix2)); licenses.appendChild(license); if (licenseEntry.getAttributes().containsKey("description")) { license.setAttribute("comments", licenseEntry.getAttributes().get("description").toString()); } if (licenseEntry.getAttributes().containsKey("link")) { license.setAttribute("url", licenseEntry.getAttributes().get("link").toString()); } } if (addDefault) { final Element license = el.getOwnerDocument().createElement("license"); license.setAttribute("name", "<>"); licenses.appendChild(el.getOwnerDocument().createTextNode("\n"+prefix2)); licenses.appendChild(license); } licenses.appendChild(el.getOwnerDocument().createTextNode("\n"+prefix1)); } /** * Add dependencies element for the given bundle to the string buffer. * * @param el * element to add the dependencies to. * @param ba * The bundle archive to defining the coordinates. * @param prefix * Whitespace to add before the new element. */ private void addDependencies(Element el, BundleArchive ba, String prefix) { final Element dependencies = el.getOwnerDocument().createElement("dependencies"); final String prefix1 = prefix + " "; final String prefix2 = prefix1 + " "; el.appendChild(el.getOwnerDocument().createTextNode("\n"+prefix1)); el.appendChild(dependencies); el.appendChild(el.getOwnerDocument().createTextNode("\n"+prefix)); for (final Entry> depEntry : selectCtDeps(ba).entrySet()) { final BundleArchives.BundleArchive depBa = depEntry.getKey(); final SortedSet pkgNames = depEntry.getValue(); dependencies.appendChild(el.getOwnerDocument().createTextNode("\n"+prefix2)); dependencies.appendChild(el.getOwnerDocument().createComment(pkgNames.toString())); final Element dependency = el.getOwnerDocument().createElement("dependency"); addMavenCoordinates(dependency, depBa); if (pkgNames.contains("org.osgi.framework")) { dependency.setAttribute("scope", "provided"); } dependencies.appendChild(el.getOwnerDocument().createTextNode("\n"+prefix2)); dependencies.appendChild(dependency); dependencies.appendChild(el.getOwnerDocument().createTextNode("\n")); } dependencies.appendChild(el.getOwnerDocument().createTextNode("\n"+prefix1)); if (0> selectCtDeps(final BundleArchives.BundleArchive ba) { log("Selecting dependencies for : "+ba, Project.MSG_VERBOSE); // The total set of packages that are provided by the dependencies. final TreeSet pkgs = new TreeSet(); // The sub-set of the dependency entries that are API-bundles. final List>> depsApi = new ArrayList>>(); // The sub-set of the dependency entries that are not API-bundles. final List>> depsNonApi = new ArrayList>>(); // The resulting collection of dependencies final Map> res = new TreeMap>(); // Group providing bundles in to API-bundles and non-API-bundles // and the set of packages provided by all providers. for (final Entry> ctPEntry : ba.pkgCtProvidersMap.entrySet()) { final BundleArchive ctBa = ctPEntry.getKey(); final SortedSet ctPkgs = ctPEntry.getValue(); if (ctBa.isAPIBundle()) { log(" APIbundle: "+ctBa +" provides "+ctPkgs, Project.MSG_DEBUG); depsApi.add(ctPEntry); } else { log(" NonAPIbundle: "+ctBa +" provides "+ctPkgs, Project.MSG_DEBUG); depsNonApi.add(ctPEntry); } pkgs.addAll(ctPkgs); } log(" Provided imported packages: "+pkgs, Project.MSG_VERBOSE); final Comparator>> cmp = new ProvidesEntrySetComparator(); Collections.sort(depsApi, cmp); Collections.sort(depsNonApi, cmp); selectProviders(res, pkgs, depsApi); selectProviders(res, pkgs, depsNonApi); return res; } /** * Add providing bundles from the deps list that * provides at least one of the packages in pkgs. Try * to avoid having multiple providers of the same package. * * @param res The selected providers to make dependencies of. * @param pkgs The set of packages that shall be provided by the * providers added to res. * @param deps Provider bundles that are dependency candidates. */ private void selectProviders(final Map> res, final Set pkgs, final List>> deps) { // Iterate over dependency candidates that exports packages, // Add bundles that contributes at least one package to res. for (final Iterator>> itDeps = deps.iterator(); 0> entry = itDeps.next(); final BundleArchives.BundleArchive ba = entry.getKey(); final SortedSet pPkgs = entry.getValue(); log(" Trying provider: " +ba +": exporting " +pPkgs + " looking for: " +pkgs, Project.MSG_DEBUG); if (pkgs.removeAll(pPkgs)) { // entry provides needed packages, add its bundle to the result. log(" Selecting provider: " + ba + " exporting "+pPkgs, Project.MSG_VERBOSE); // Remove any provider that will not provide any unique // package after the addition of ba. for (final Iterator>> itRes = res.entrySet().iterator(); itRes.hasNext();) { final Entry> resEntry = itRes.next(); final BundleArchives.BundleArchive resBa = resEntry.getKey(); final SortedSet resPkgs = resEntry.getValue(); if (pPkgs.containsAll(resPkgs)) { log(" Removing redundant provider: "+resBa, Project.MSG_VERBOSE); itRes.remove(); } } res.put(ba, pPkgs); } } } /** * Add attachement element for the source artifact if present. * *
   * <attach file="${basedir}/target/my-project-1.0-sources.jar"
   *            type="jar"
   *            classifier="sources">
   * 
* * @param el * element to add the attachment to. * @param ba * The bundle archive to add a source artifact for. * @param prefix * Whitespace to add before the new element. */ private void addSourceAttachment(final Element el, final BundleArchive ba, final String prefix) { String sourcePath = ba.file.getAbsolutePath(); // Remove ".jar" suffix. sourcePath = sourcePath.substring(0,sourcePath.length()-4); sourcePath = sourcePath +"-source.jar"; final File sourceFile = new File(sourcePath); if (sourceFile.exists()) { final Document doc = el.getOwnerDocument(); final String prefix1 = prefix + " "; final String prefix2 = prefix1 + " "; final Element sourceAttachment = doc.createElement("source-attachment"); el.appendChild(doc.createTextNode("\n"+prefix1)); el.appendChild(sourceAttachment); el.appendChild(doc.createTextNode("\n"+prefix)); final Element attach = doc.createElement("attach"); sourceAttachment.appendChild(doc.createTextNode("\n"+prefix2)); sourceAttachment.appendChild(attach); sourceAttachment.appendChild(doc.createTextNode("\n"+prefix1)); attach.setAttribute("file", sourcePath); attach.setAttribute("type", "jar"); attach.setAttribute("classifier", "sources"); } } /** * Add attachement element for the javadoc artifact if present. * *
   *  <attach file="${basedir}/target/my-project-1.0-javadoc.jar"
   *             type="jar"
   *             classifier="javadoc"/>
   * 
* * @param el * element to add the attachment to. * @param ba * The bundle archive to add a source artifact for. * @param prefix * Whitespace to add before the new element. */ private void addJavadocAttachment(final Element el, final BundleArchive ba, final String prefix) { String javadocPath = ba.file.getAbsolutePath(); // Remove ".jar" suffix. javadocPath = javadocPath.substring(0, javadocPath.length()-4); javadocPath = javadocPath +"-javadoc.jar"; final File javadocFile = new File(javadocPath); if (javadocFile.exists()) { final Document doc = el.getOwnerDocument(); final String prefix1 = prefix + " "; final String prefix2 = prefix1 + " "; final Element javadocAttachment = doc.createElement("javadoc-attachment"); el.appendChild(doc.createTextNode("\n"+prefix1)); el.appendChild(javadocAttachment); el.appendChild(doc.createTextNode("\n"+prefix)); final Element attach = doc.createElement("attach"); javadocAttachment.appendChild(doc.createTextNode("\n"+prefix2)); javadocAttachment.appendChild(attach); javadocAttachment.appendChild(doc.createTextNode("\n"+prefix1)); attach.setAttribute("file", javadocPath); attach.setAttribute("type", "jar"); attach.setAttribute("classifier", "javadoc"); } } /** * Sort map entries that consists of a bundle archive as key and a * set as value in increasing order based on the size of the set and * if equal the natural order of the bundle archives. */ static class ProvidesEntrySetComparator implements Comparator>> { @Override public int compare(Entry> o1, Entry> o2) { final int res = o1.getValue().size() - o2.getValue().size(); return 0!=res ? res : o1.getKey().compareTo(o2.getKey()); } @Override public boolean equals(Object obj) { return this==obj; } } static String replace(String src, String a, String b) { return Util.replace(src, a, b == null ? "" : b); } } knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleClasspathTask.java0000644000175000017500000003001712346513674031415 0ustar felixfelix/* * Copyright (c) 2006-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.ZipFileSet; /** * Task that translates the value of the OSGi specified manifest * header Bundle-Classpath into either a file set or pattern * suitable for use as the includes attribute in a file set that will * find all classes and jars that the framework may use given the * specified Bundle-Classpath manifest attribute. * *

This task may also be used as a nested element in the bundle * info task. In that case it will be used to generate a list of file * sets, one for each entry in the given bundle classpath. If the * excludes attribute is given the file sets will use that as exclude * pattern otherwise the includes attribute is used as includes * pattern. If the bundle classpath entry is a jar-file then a * ZipFileSet will be created for it with the jar-file as source and * the excludes (or includes) attribute as excludes (includes) * pattern.

* *

Parameters

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
BundleClasspathThe bundle class path to convert into an includes * pattern. *

* If unset, set to empty string, or set to the special empty * value [bundle.emptystring] the default bundle * classpath, "." will be used. *

*

* Note: The current value of this property will be overwritten * by the derived pattern. *

*
No.
Default value is "."
propertyNameName of property that will receive the resulting * pattern. * Yes.
No default value.
dirThe directory to use as root directory in the * created fileset. * Yes.
No default value.
filesetIdId of a file set with include patterns based on * the given BundleClasspath and base directory given * by dir. If dir is not given or * non-existing then an empty file set is created. * No.
No default value.
includesIncludes pattern to apply to each file set created * from the entries in the bundle classpath when building a list * of file sets. * At least one of includes and excludes must be * given when building a list of file sets from the bundle * classpath.
* No default value.
excludesExcludes pattern to apply to each file set created * from the entires in the bundle classpath when building a list * of file sets. Note: This attribute is only used when the * <bundleclasspath> is used as a nested element inside a * <bundleinfo> element. * At least one of includes and excludes must be * given when building a list of file sets from the bundle * classpath.
* No default value.
* *

Examples

* The table below shows how different bundle class path entries are * translated int patterns. * * * * * * * * *
EntryPattern
.**/*.class
rxtxrxtx/**/*.class
/rxtxrxtx/**/*.class
required.jarrequired.jar
xx/required.jarxx/required.jar
/xx/required.jarxx/required.jar
*/ public class BundleClasspathTask extends Task { private File dir; private String filesetId; private String bundleClasspath = "."; private String propertyName; private String includes = null; private String excludes = null; public BundleClasspathTask() { } /** * Set bundle class path to create a pattern for. */ public void setBundleClasspath(String s) { this.bundleClasspath = (BundleManifestTask.BUNDLE_EMPTY_STRING.equals(s)) ? "." : s; log("bundleClasspath="+bundleClasspath, Project.MSG_DEBUG); } /** * Set property receiving the bundle class path pattern. */ public void setPropertyName(String s) { this.propertyName = s; log("propertyName="+propertyName, Project.MSG_DEBUG); } /** * Set property receiving the file set root directory. */ public void setDir(File f) { this.dir = f; log("dir="+dir, Project.MSG_DEBUG); } /** * Set property receiving the file set id. */ public void setFilesetId(String s) { this.filesetId = s; log("filesetId="+filesetId, Project.MSG_DEBUG); } /** * Set the includes pattern to use in the collection of file sets * returned by {@link #getFileSets(boolean)}. */ public void setIncludes(String s) { this.includes = s; log("includes="+this.includes, Project.MSG_DEBUG); } /** * Set the excludes pattern to use in the collection of file sets * returned by {@link #getFileSets(boolean)}. */ public void setExcludes(String s) { this.excludes = s; log("excludes="+this.excludes, Project.MSG_DEBUG); } /** * Get a collection of file sets selecting all classes in the bundle * class path that matches the given pattern. * * @return A list with file sets, one file set for each entry on the * bundle class path. If the entry is for a Jar/Zip file * then its list item will be a zip file set. */ public List getFileSets(boolean failOnClassPath) { final List res = new ArrayList(); final Project proj = getProject(); if (dir==null) { throw new BuildException("The dir attribute (root of the bundle " +"class path) is required."); } else if (!dir.exists()) { log("Bundle class path root dir '" +dir +"' does not exist, returning empty list of file sets.", Project.MSG_VERBOSE); return res; } if (null==bundleClasspath || 0==bundleClasspath.length() ) { // Use the default bundle class path bundleClasspath = "."; } // Convert path entries to file sets. final StringTokenizer st = new StringTokenizer(bundleClasspath, ","); while (st.hasMoreTokens()) { String entry = st.nextToken().trim(); if (entry.startsWith("/")) { // Entry is a relative path, must not start with a '/', fix it. entry = entry.substring(1); } FileSet fileSet = null; final File src= new File(dir, entry); // Bundle class path entries are either directories or jar/zip-files! if (src.isDirectory()) { fileSet = new FileSet(); fileSet.setDir(src); fileSet.setProject(getProject()); } else if (src.exists()) { fileSet = new ZipFileSet(); ((ZipFileSet) fileSet).setSrc(src); } else { final StringBuffer msg = new StringBuffer(); msg.append("The following entry in the Bundle-ClassPath") .append(" header doesn't exist in the bundle: ") .append(entry) .append("."); if (failOnClassPath) { log(msg.toString(), Project.MSG_ERR); throw new BuildException(msg.toString(), getLocation()); } else { log(msg.toString(), Project.MSG_WARN); continue; } } fileSet.setProject(proj); if (null!=includes) { fileSet.setIncludes(includes); } if (null!=excludes) { fileSet.setExcludes(excludes); } res.add(fileSet); log("Added FileSet with root '" +src +"', includes: '" +includes +"', excludes: '" +excludes +"'.", Project.MSG_DEBUG); } return res; } // Implements Task // @Override public void execute() throws BuildException { if ( (null==propertyName || 0==propertyName.length()) && (null==filesetId || 0==filesetId.length()) ) { throw new BuildException ("Either propertyName or filesetId must be given."); } if (null!=filesetId && dir==null) { throw new BuildException ("dir is required when filesetId is given."); } if (null==bundleClasspath || 0==bundleClasspath.length() ) { bundleClasspath = "."; } final StringBuffer sb = new StringBuffer(100); // Convert path entries to patterns. final StringTokenizer st = new StringTokenizer(bundleClasspath, ","); while (st.hasMoreTokens()) { String entry = st.nextToken().trim(); if (entry.startsWith("/")) { // Entry is a relative path, must not start with a '/', fix it. entry = entry.substring(1); } if (".".equals(entry)) { sb.append("**/*.class"); } else if (entry.endsWith(".jar")) { sb.append(entry); } else { sb.append(entry + "/**/*.class"); } if (st.hasMoreTokens()) { sb.append(","); } } final Project proj = getProject(); // Conversion done - write back properties if (null!=propertyName) { proj.setProperty(propertyName, sb.toString()); log("Converted \"" +bundleClasspath +"\" to pattern \"" +sb.toString() +"\"", Project.MSG_VERBOSE); } if (null!=filesetId) { final FileSet fileSet = new FileSet(); fileSet.setProject(proj); if (dir.exists()) { fileSet.setDir(dir); fileSet.setIncludes(sb.toString()); } else { log("Bundle class path root dir '" +dir +"' does not exist, returning empty file set.", Project.MSG_DEBUG); fileSet.setDir(new File(".")); fileSet.setExcludes("**/*"); } proj.addReference(filesetId, fileSet); log("Converted bundle class path \"" +bundleClasspath +"\" to file set with id '" +filesetId +"' and files \"" +fileSet +"\"", Project.MSG_VERBOSE); } } } knopflerfish-osgi-5.1.0/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundlePackagesInfo.java0000644000175000017500000005625112346513674031212 0ustar felixfelix/* * Copyright (c) 2003-2013, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.ant.taskdefs.bundle; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.Resource; import org.osgi.framework.Version; /** * Class that holds the results of the Java package analysis of all * classes in a bundle. *

* Class and package names should use either '/' or '.' as separator * between package levels during build up phase. When all classes * packages have been added, make a call to {@link #toJavaNames()} to * convert all class / packages names using the internal Java * representation with '/' as separator to their non-internal * representation with '.' as separator. * Mixing of separator kinds is not supported! *

*

* When all classes have been added, before using the package using * map a call to {@link #postProcessUsingMap(Set,Set)} should be done. *

*/ public class BundlePackagesInfo { /** * Get package name of class string representation. * * @param className A fully qualified class name. * @return The Java package name that the named class belongs * to. Will return the empty string if the named class does * not belong to any package. */ public static String packageName(final String className) { String s = className.trim(); int ix = s.lastIndexOf('/'); if(ix == -1) { ix = s.lastIndexOf('.'); } if (ix != -1) { s = s.substring(0, ix); } else { s = ""; } return s; } // The task using this object to provide logging functionality. final Task task; public BundlePackagesInfo(final Task task) { this.task = task; } /** * The set of classes provided by the bundle. * The elements of the set are the fully qualified class name. */ private final SortedSet/**/ providedClasses = new TreeSet(); /** * Adds a named class to the set of classes provided by this * bundle. * * This method also adds the package of the class to the set of * provided packages. It also add a reference to the class from its * own package. * * @param className the name of the class to add. * @return the name of the Java package that the given class belongs * to. */ public String addProvidedClass(final String className) { final String pkgName = packageName(className); providedClasses.add(className); addProvidedPackage(pkgName); addReferencedClass(pkgName, className); task.log("Added provided class '" +className +"'.", Project.MSG_DEBUG); return pkgName; } /** * Checks if a named class is provided by this bundle. * @param className the name of the class to check for. * @return true if the given class is in the set of * classes provided by this bundle, false * otherwise. */ public boolean providesClass(final String className) { return providedClasses.contains(className); } /** * The sub set of the provided classes that implements the interface * {@link org.osgi.framework.BundleActivator}. */ private final SortedSet/**/ activatorClasses = new TreeSet(); /** * Adds a named class to the set of classes that implements the * interface {@link org.osgi.framework.BundleActivator}. * * @param className the name of the activator class to add. */ public void addProvidedActivatorClass(final String className) { activatorClasses.add(className); providedClasses.add(className); task.log("Added provided BundleActivator class '" +className +"'.", Project.MSG_DEBUG); } /** * Gets the cardinality of the set of provided bundle activator * classes. * * @return Number of elements in the set of provided bundle * activator classes. */ public int countProvidedActivatorClasses() { return activatorClasses.size(); } /** * Checks if a named class is in the set of provided activator classes. * @param className the name of the activator class to check for. * @return true if the given class is in the set of * provided activator classes, false otherwise. */ public boolean providesActivatorClass(final String className) { return activatorClasses.contains(className); } /** * Return the set of provided activator classes as string suitable * for use in messages. * @return The provided set of activator classes as a string. */ public String providedActivatorClassesAsString() { return activatorClasses.toString(); } /** * Get the bundle activator from the set of provided bundle * activator classes. * @return The one and only activator class when the size of the set * of provided bundle activator classes is one, * otherwise null. */ public String getActivatorClass() { return 1== activatorClasses.size() ? activatorClasses.iterator().next() : (String) null; } /** * The set of packages that are provided by the classes in the * bundle. */ private final SortedSet/**/ providedPackages = new TreeSet(); /** * Adds a named package to the set of packages provided by this * bundle. * @param packageName the name of the Java package to add. */ public void addProvidedPackage(final String packageName) { if(packageName == null || "".equals(packageName)) { return; } providedPackages.add(packageName); } /** * Checks if a named Java package is provided by this bundle. * * @param packageName the name of the package to check for. * @return true if the given package is in the set of * packages provided by this bundle, false * otherwise. */ public boolean providesPackage(final String packageName) { return providedPackages.contains(packageName); } /** * Get a copy of the set of provided Java packages. * * This method may be called before {@link #toJavaNames()}. * * @return A copy of the set of provided Java packages. */ public SortedSet getProvidedPackages() { final TreeSet res = new TreeSet(providedPackages); toJavaNames(res); // Ensure that '.' is used as package separator return res; } /** * Get the provided packages formatted as the value of an * Export-Package-manifest attribute with package versions. * * @return OSGi Export-Package header value. */ public String getProvidedPackagesAsExportPackageValue() { final StringBuffer res = new StringBuffer(255); for (final Iterator ppIt = providedPackages.iterator(); ppIt.hasNext();) { final String pPkg = ppIt.next(); res.append(pPkg); final Version pPkgVersion = getProvidedPackageVersion(pPkg); if (null!=pPkgVersion) { res.append(";version=").append(pPkgVersion); } if (ppIt.hasNext()) { res.append(", "); } } return res.toString(); } /** * Gets the cardinality of the set of provided Java packages. * * @return Number of elements in the set of provided packages. */ public int countProvidedPackages() { return providedPackages.size(); } /** * Mapping from the package name of a provided package to its * version as given by the packageinfo-file if present. */ private final Map packageToVersion = new HashMap(); /** * Get the version of a provided package as defined by the * packageinfo-file in the package-directory. * * @param pkgName The package to get the version of. * * @return The package version or null if not defined. */ public Version getProvidedPackageVersion(final String pkgName) { return packageToVersion.get(pkgName); } /** * Mapping from the package name of a provided package to the * absolute path of the packageinfo-file that was used * to determine the package version. */ private final Map packageToInfofile = new HashMap(); /** * Get the path of the file that the version of a provided package * was found in. * * @param pkgName The version-ed package to get the version source of. * * @return The path of the packageinfo-file that the * version was read from. */ public String getProvidedPackageVersionSource(final String pkgName) { return packageToInfofile.get(pkgName); } /** * Read the version from a packageinfo-file given a * resource-object. * * @param res Resource encapsulating a packageinfo-file. * * @return The version or null if no valid version was * found. */ private Version getVersion(final Resource res) { BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(res.getInputStream())); String line = br.readLine(); while (null!=line) { if (line.startsWith("version ")) { final Version version = new Version(line.substring(7).trim()); return version; } line = br.readLine(); } } catch (final Throwable t) { final String msg = "Failed to get version from '" +res.toString() +"'; " +t.getMessage(); throw new BuildException(msg, t); } return null; } /** * Try to assign a version to the Java that the given * packageinfo-file resides in. This code assumes that * the resource has been created in such a way that * res.getName() returns a relative path to the * packageinfo-file that starts in its package * root. I.e., the path is the Java package that the * packageinfo-file provides data for. * * @param res Resource encapsulating a packageinfo-file. * @return The package name or null if no valid version was * found. */ public String setPackageVersion(final Resource res) { // The relative path to packageinfo-file starting from the root of // its classpath. Allways using forward slash as separator char. final String pkgInfoPath = res.getName().replace(File.separatorChar, '/'); // 12 = "/packageinfo".lenght() final String pkgName = pkgInfoPath.substring(0, pkgInfoPath.length()-12); // Currently registered path for version providing packageinfo // file, if any. final String curPkgInfoPath = packageToInfofile.get(pkgName); if (null==curPkgInfoPath || !curPkgInfoPath.equals(pkgInfoPath)) { final Version newVersion = getVersion(res); if (null!=newVersion) { final Version curVersion = getProvidedPackageVersion(pkgName); if (null==curVersion) { packageToVersion.put(pkgName, newVersion); packageToInfofile.put(pkgName, pkgInfoPath); task.log("Package version for '" +pkgName +"' set to " +newVersion +" based on data from '" +pkgInfoPath +"'.", Project.MSG_VERBOSE); return pkgName; } else if (!newVersion.equals(curVersion)) { // May happen when the classes of a package are in two // different directories on the class path. throw new BuildException("Conflicting versions for '" +pkgName +"' previous '" +curVersion +"' from '" +curPkgInfoPath +"', new '" +newVersion +"' in '" +pkgInfoPath +"'."); } } } return null; } /** * The set of classes that are referenced from the provided classes. * I.e., classes that are used somehow by the provided classes. */ private final SortedSet referencedClasses = new TreeSet(); /** * The set of Java packages that are referenced from the provided * classes. */ private final SortedSet referencedPackages = new TreeSet(); /** * Get a copy of the set of referenced Java classes. * * @return A copy of the set of referenced Java packages. */ public SortedSet getReferencedClasses() { return new TreeSet(referencedClasses); } /** * Get a the set of Java packages that are referenced by this bundle * but not provided by it. * * @return The set of un-provided referenced Java packages. */ public SortedSet/**/ getUnprovidedReferencedPackages() { final SortedSet res = new TreeSet(referencedPackages); res.removeAll(providedPackages); return res; } /** * Get a copy of the set of Java packages that are referenced by * this bundle. * * @return The set of referenced Java packages. */ public SortedSet getReferencedPackages() { return new TreeSet(referencedPackages); } /** * A mapping from a provided Java package name to the set of Java * package names referenced by the classes in that provided package. */ private final Map> packageToReferencedPackages = new HashMap>(); /** * Add a reference to a named class from some class in the * referencing Java package. * * If the given referenced class is an inner class, then we also add * a reference for its outer class. This is not really needed for * static inner classes, but there is no way to detect that on this * level. * * @param referencingPackage The Java package of the class having a * reference to className. * @param referencedClass Fully qualified name of the referenced * class. */ public void addReferencedClass(final String referencingPackage, final String referencedClass) { if(null==referencedClass || 0==referencedClass.length()) { return; } final String referencedPackage = packageName(referencedClass); if("".equals(referencedPackage)) { // Referenced class is in the default package; skip it. return; } referencedClasses.add(referencedClass); final int dollarIdx = referencedClass.indexOf('$'); if (-1 using = (SortedSet) packageToReferencedPackages.get(referencingPackage); if (null==using) { using = new TreeSet(); packageToReferencedPackages.put(referencingPackage, using); } using.add(referencedPackage); } task.log("Added reference to class '" +referencedClass +"' from the package '" +referencingPackage +"'.", Project.MSG_DEBUG); } /** * Post process the package to referenced packages map. * *
    *
  1. Remove all self references. *
  2. Remove all references to "java.*". *
  3. Remove all packages in the remove from referenced set are removed from * all referenced sets. *
  4. Retain all packages in the retain in referenced set. I.e., the * referenced sets will only contain packages present in this set. *
* * @param removeFromReferencedSets * Packages to remove * @param retainInReferencedSets * Packages to retain. */ public void postProcessUsingMap(Set removeFromReferencedSets, Set retainInReferencedSets) { for (final Entry> entry : packageToReferencedPackages.entrySet()) { final Set using = entry.getValue(); using.remove(entry.getKey()); using.removeAll(removeFromReferencedSets); using.retainAll(retainInReferencedSets); } } /** * Get a the set of Java packages that are referenced by the * given Java package. * * @param packageName The name of the Java package to get * referenced Java packages for. * @return The set of referenced Java packages. */ public SortedSet getPackagesReferencedFromPackage(final String packageName) { return (SortedSet) packageToReferencedPackages.get(packageName); } /** * Replaces all '/' in class and package names with '.' in all the * collections that this class is holding. */ public void toJavaNames() { toJavaNames(providedClasses); toJavaNames(providedPackages); toJavaNames(activatorClasses); toJavaNames(referencedClasses); toJavaNames(referencedPackages); toJavaNames(packageToReferencedPackages); toJavaNames(packageToVersion); toJavaNames(packageToInfofile); } /** * Replaces all '/' in class and package names with '.' in the * elements of the given set. * * @param set the set of names to process. */ private void toJavaNames(SortedSet set) { final TreeSet tmpSet = new TreeSet(); for (final String item : set) { tmpSet.add(item.replace('/', '.')); } set.clear(); set.addAll(tmpSet); tmpSet.clear(); } /** * Replaces all '/' in class and package names with '.' in the keys of the * given map. If the value is a sorted set of strings call * {@link #toJavaNames(SortedSet)} on it. * * @param map * the map of with keys to process. */ private void toJavaNames(Map map) { final HashMap tmpMap = new HashMap(); for (final Entry entry : map.entrySet()) { final String key = entry.getKey(); final V value = entry.getValue(); if (value instanceof SortedSet) { @SuppressWarnings("unchecked") final SortedSet set = (SortedSet) value; toJavaNames(set); } tmpMap.put(key.replace('/', '.'), value); } map.clear(); map.putAll(tmpMap); tmpMap.clear(); } @Override public boolean equals(Object other) { if (!(other instanceof BundlePackagesInfo)) { return false; } final BundlePackagesInfo otherBpInfo = (BundlePackagesInfo) other; if (!providedPackages.equals(otherBpInfo.providedPackages)) { System.out.println("Diff for provided packages: mine=" +providedPackages +", other=" +otherBpInfo.providedPackages); return false; } if (!providedClasses.equals(otherBpInfo.providedClasses)) { System.out.println("Diff for provided classes: mine=" +providedClasses +", other=" +otherBpInfo.providedClasses); return false; } if (!activatorClasses.equals(otherBpInfo.activatorClasses)) { System.out.println("Diff for activator classes: mine=" +activatorClasses +", other=" +otherBpInfo.activatorClasses); return false; } if (!referencedPackages.equals(otherBpInfo.referencedPackages)) { System.out.println("Diff for referenced packages: mine=" +referencedPackages +", other=" +otherBpInfo.referencedPackages); final SortedSet all = new TreeSet(referencedPackages); all.addAll(otherBpInfo.referencedPackages); final SortedSet tmp = new TreeSet(all); tmp.removeAll(referencedPackages); System.out.println(" Other extra referenced packages: " +tmp); tmp.addAll(all); tmp.removeAll(otherBpInfo.referencedPackages); System.out.println(" My extra referenced packages: " +tmp); return false; } if (!referencedClasses.equals(otherBpInfo.referencedClasses)) { System.out.println("Diff for referenced classes: mine=" +referencedClasses +", other=" +otherBpInfo.referencedClasses); final SortedSet all = new TreeSet(referencedClasses); all.addAll(otherBpInfo.referencedClasses); final SortedSet tmp = new TreeSet(all); tmp.removeAll(referencedClasses); System.out.println(" Other extra referenced classes: " +tmp); tmp.addAll(all); tmp.removeAll(otherBpInfo.referencedClasses); System.out.println(" My extra referenced classes: " +tmp); return false; } return true; } @Override public String toString() { final StringBuffer res = new StringBuffer(200); res.append("BundlePackagesInfo:\n\t"); res.append("Provided packages: ["); for (final Iterator ppIt = providedPackages.iterator(); ppIt.hasNext();) { final String pPkg = ppIt.next(); res.append(pPkg); final Version pPkgVersion = getProvidedPackageVersion(pPkg); if (null!=pPkgVersion) { res.append(";version=").append(pPkgVersion); } if (ppIt.hasNext()) { res.append(", "); } } res.append("]\n\t"); res.append("Provided classes: ").append(providedClasses).append("\n\t"); res.append("Provided Activators: ").append(activatorClasses).append("\n\t"); res.append("Referenced packages: ").append(referencedPackages).append("\n\t"); res.append("Referenced classes: ").append(referencedClasses).append("\n\t"); res.append("Using map: ").append(packageToReferencedPackages).append("\n"); return res.toString(); } } knopflerfish-osgi-5.1.0/ant/ant_templates/0000755000175000017500000000000012475375714017607 5ustar felixfelixknopflerfish-osgi-5.1.0/ant/ant_templates/mvn_repo.xml0000644000175000017500000001603312346513674022155 0ustar felixfelix knopflerfish-osgi-5.1.0/ant/bundlebuild.xml0000644000175000017500000013403512346513674017764 0ustar felixfelix knopflerfish-osgi-5.1.0/ant/docbuild_include.xml0000644000175000017500000000345712346513674020766 0ustar felixfelix knopflerfish-osgi-5.1.0/ant/html_template/0000755000175000017500000000000012475375714017606 5ustar felixfelixknopflerfish-osgi-5.1.0/ant/html_template/style.css0000644000175000017500000000645412346513674021465 0ustar felixfelixBODY { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:11px; color:000000; text-align:left; font-weight:normal; background:#fff; } TD { font-family: Verdana, Arial, Helvetica, sans-serif; text-align:left; vertical-align:top; font-size:11px; } TD A { color:000000; text-decoration:none font-size:11px; } .mfheader { font-family: Verdana, Arial, Helvetica, sans-serif; text-align:left; vertical-align:top; font-size:11px; font-weight:bold; /* background: #805362; */ color: #fff; padding-top: 4px; padding-bottom: 4px; /* text-align: center; */ border-style: solid; border-color: #999999; background-color: #dedede; border-width: 1px; color: #444444; padding-left: 10px; } TH { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:11px; color:000000; text-align:left; vertical-align:top; font-weight:bold } TD A { color:000000; text-decoration:none font-size:11px; } PRE { font-family: Courier New, Courier; font-size:11px; color:000000; text-align:left; font-weight:normal; } H1 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:19px; font-weight:bold; /* background: #dddddd; */ } H3 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:13px; font-weight:bold; background: #805362; color: #fff; padding: 2px 0px 2px 3px; } H4 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:11px; font-weight:bold; background: #805362; color: #fff; padding: 2px 0px 2px 10px; border-style: solid; border-color: #999999; background-color: #dedede; border-width: 1px; color: #444444; } H5 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:9px; font-weight:bold; background: #805362; color: #fff; padding: 2px 0px 2px 3px; } H6 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:7px; font-weight:bold } TD.menu { color: #ffffff; font-size:9px; font-weight:bold; text-align:left; } A.top { float: right; text-decoration: none; font-weight: bold; } A, A:visited, A:selected, A:active { color:000000; text-decoration: none; font-weight: bold; } A:hover { text-decoration: underline; } li.A:visited, li.A:selected, li.A:active { text-decoration: none; font-weight: bold; } li.A:hover { text-decoration: underline; } .small { font-size:9px; } .medium { font-size:13px; } .big { font-size:17px; } .ghosted { color: #888888; } .framed { border-type: solid; border-top: 1px solid; border-left: 1px solid; border-bottom: 1px solid; border-right: 1px solid; background:#eeeeee; border-color:#000000; padding-left: 2; padding-top: 2; padding-bottom: 2; padding-right: 2; text-decoration:none; font-size: 11px; } .boxed { border-type: solid; border-top: 1px solid; border-left: 1px solid; border-bottom: 1px solid; border-right: 1px solid; background:#E7DBAD; border-color:#000000; padding-left: 2; padding-top: 1; padding-bottom: 2; padding-right: 2; text-decoration:none; float: left; } dt { font-weight:bold; margin-bottom: 5px; } dd { margin-bottom: 5px; } knopflerfish-osgi-5.1.0/ant/html_template/package_list.html0000644000175000017500000000200112346513674023107 0ustar felixfelix Knopflerfish Bundle Packages
${package.list}
PackageProvider(s)
knopflerfish-osgi-5.1.0/ant/html_template/bundle_main.html0000644000175000017500000000203312346513674022743 0ustar felixfelix Knopflerfish - Bundle Jar Documentation

Bundle Jar Documentation

This section contains information on all bundle jar files included in this distribution of Knopflerfish.

Select the bundles from the bundle list to the left to view detailed bundle information, including manifest headers, bundle dependencies and derived javadoc links based on imported and exported packages.

${unresolved.list}

Bundle Jars Listing

${bundle.list}

knopflerfish-osgi-5.1.0/ant/html_template/mvn_dep_mgmt.xsl0000644000175000017500000001434312346513674023013 0ustar felixfelix <xsl:value-of select="@product"/> <xsl:value-of select="@version"/> Maven Artifacts

  Maven Artifacts

This page contains a listing of all bundles (artifacts) in the maven2 repository that belongs to   .

You may copy the Maven <dependy> elements from this file and paste them into the <dependencyManagement>-element of the settings.xml-file or the top-level pom-file for a collection of projects that uses this Knopflerfish version.

Bundle Description Group id Artifact id Version

   
knopflerfish-osgi-5.1.0/ant/html_template/bundle_list.html0000644000175000017500000000207212346513674022775 0ustar felixfelix ${bundle.list.header} Knopflerfish Documentation
Bundle Jar Documentation
Bundle Packages

${bundle.list}
knopflerfish-osgi-5.1.0/ant/html_template/bundledoc.html0000644000175000017500000000170112346513674022426 0ustar felixfelix Bundle User Documentation - $(BUNDLE_NAME), v$(BUNDLE_VERSION)
Bundle: $(BUNDLE_NAME)
Version $(BUNDLE_VERSION)
$(MAIN)

Bundle Jar docs

$(BUNDLE_JARDOCS)

Exported Packages

$(BUNDLE_EXPORT_PACKAGE)
knopflerfish-osgi-5.1.0/ant/html_template/bundle_index.html0000644000175000017500000000237712346513674023141 0ustar felixfelix Knopflerfish - Bundle Jar Documentation knopflerfish-osgi-5.1.0/ant/html_template/bundle_header.html0000644000175000017500000000400712346513674023252 0ustar felixfelix knopflerfish-osgi-5.1.0/ant/html_template/bundle_info.html0000644000175000017500000000554312346513674022763 0ustar felixfelix ${FILE}

${FILE}

download (${FILEINFO})

${MF.UNHANDLED}
OSGi manifest attributes
Bundle-Name ${Bundle-Name}
Bundle-SymbolicName ${Bundle-SymbolicName}
Bundle-Version ${Bundle-Version}
Bundle-Description ${Bundle-Description}
Bundle-Vendor ${Bundle-Vendor}
Bundle-ContactAddress ${Bundle-ContactAddress}
Bundle-License ${Bundle-License}
Bundle-DocURL ${Bundle-DocURL}
Bundle-ManifestVersion ${Bundle-ManifestVersion}
Bundle-Activator ${Bundle-Activator}
Bundle-Classpath ${Bundle-Classpath}
Export-Package ${Export-Package}
Import-Package ${Import-Package}
Dynamic-ImportPackage ${DynamicImport-Package}
Provide-Capability ${Provide-Capability}
Require-Capability ${Require-Capability}
Other manifest attributes

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

${depends.list}

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

${depending.list}

Bundle source

Here are links to the source files of this bundle. ${sources.list} knopflerfish-osgi-5.1.0/ant/html_template/bundledoc_ext.html0000644000175000017500000000116312346513674023310 0ustar felixfelix Bundle User Documentation - $(TITLE) $(MAIN) knopflerfish-osgi-5.1.0/ant/html_template/frameworkdoc.html0000644000175000017500000000161112346513674023152 0ustar felixfelix Knopflerfish Framework Documentation version $(BUNDLE_VERSION)
Knopflerfish Framework
Version $(BUNDLE_VERSION)
$(MAIN)

Exported Packages

$(BUNDLE_EXPORT_PACKAGE)
knopflerfish-osgi-5.1.0/ant/xsl/0000755000175000017500000000000012475375714015555 5ustar felixfelixknopflerfish-osgi-5.1.0/ant/xsl/repository2html.xsl0000644000175000017500000001003412346513674021465 0ustar felixfelix <xsl:value-of select="@name"/>

Increment:

LinkVersionDoc/SrcBytesDescription
doc / src
knopflerfish-osgi-5.1.0/ant/bundletasks.xml0000644000175000017500000002632412346513674020013 0ustar felixfelix ]]> ]]> knopflerfish-osgi-5.1.0/kf_32x32.gif0000644000175000017500000000246012346513620016102 0ustar felixfelixGIF89a !)!))))1)11119!19!99!9B)9B)BB1BJ1JJ9JJ9JRBRRBRZJZZJZcRccRckZckZkkckscsscs{ks{k{{s{s{{ƽ, HPpÆJ`E 3 FC^ĈQ .0A@Gc`!TH0%D@ vphiC*Z0ب  =G*DѣF ?j(X>+Zx@P D:@(*2wa@Z, N ~rl^ & 60 p7 =PH]%1AʩhB1@Nsp}-ޡ3/ Knopflerfish OSGi, version 5.1.0 - Release Notes

Release Notes Knopflerfish 5.1.0 (OSGi R5)

Maintenance release of Knopflerfish 5 available from http://www.knopflerfish.org/releases/5.1.0. Released 2014-06-13.

Knopflerfish 5 is an implementation of the "OSGi Service Platform Release 5". It contains all services specified in the "Core Specification" and most of the non Enterprise Edition related services specified in the "Compendium Specification".

The Release Notes include all new features & changes for Knopflerfish 5.1.0 compared to the release of Knopflerfish 5.0.0.

Knopflerfish Framework - OSGi Core Specification

Framework 7.1.2
Fixed framework restart problem introduced in 7.1.0.
Relaxed "org.knopflerfish.framework.validator.date" parsing, so that it tries short US locale pattern if default locale parsing fails.
Framework 7.1.1
Fixed exception when doing BundleWiring.listResources on root directory.
Framework 7.1.0
Added new URL protocol "fwresource" to access resources from the framework classloader.
The start class org.knopflerfish.framework.Main now tries to load xargs as a framework resource if the file is not found. This means that we together with the new fwresource protocol can create a single jar that contains the framework, all jars and xargs files that needs to start a complete application.
Added property "org.knopflerfish.framework.readonly", that puts framework in a read only mode. This means that framework will not write any files in "fwdir". This means that if we are running with the default "file" bundle storage then new bundles must be installed as a referenced file URL. This also implies that no data storage will be available to bundles.
Framework 7.0.2
Fixed bug that caused IndexOutOfBoundsException when updating large collections of ConditionalPermissionInfos using ConditionalPermissionUpdate.
Added property "org.knopflerfish.framework.validator.date" to framework for testing certification validation with different dates.

OSGi Compendium Specification

UserAdmin 4.1.1
Now contains and imports/exports org.knopflerfish.service.log in order to be self-contained.
Changed to use the OSGi defined Bundle-Icon instead of Application-Icon.
KF-XML-Metatype 5.0.1
Fixed bug in handling of designate-element that could cause configurations to be created, deleted or overwritten unintentionally. Refactored handling of standardized OSGi metatype xml and legacy proprietary meta type xml into separate classes.
CM 5.0.1
Improved the persistent storage of CM data, made it more robust and fault resilient.
HTTP-Server 4.0.5
Fixed another bug in the handling of chunked transfer encoding in the Request implementation. The last chunk (with size 0) is not followed by any chunk-data and thus there is no CRLF to consume.
HTTP-Server 4.0.4
Fixed another bug in the handling of chunked transfer encoding in the Request implementation. A chunk contianing a charter followed by a new line char was not correctly un-chunked.
HTTP-Server 4.0.3
Fixed a bug in the handling of chunked transfer encoding in the Request implementation. An extra CR-LF was incorrectly added to the end of the decoded data, causing problems when transfering binary data like a zip-file.
Prefs 4.0.2
Added bundle icon.
Repository XML 1.0.2
Fixed a bug in RequirementImpl and did some clean up.
Repository XML 1.0.1
Fixed a bug in CapabilityImpl.
SCR(component) 5.0.3
Fixed missed factory component check in previous version. This miss caused following error:

java.lang.IllegalStateException: Internal error! Factory component only created with newInstance

SCR(component) 5.0.2
Fixed a bug that caused factory components to be falsely created or missed being created when we use target filters.
SCR(component) 5.0.1
Fixed a bug that caused problems when adding a CM configuration with a target filter to an unsatisfied component.

Knopflerfish Services

CM Desktop 5.0.2
Add requirement for the Meta Type Service.
KF Resource Analyzer Extensions 1.0.1
Added proper handling of Bundle-License according to osgi.identity namepsace.
Repository Commands 1.1.1
Bug fixes and some refactorings.
Repository Commands 1.1.0
Added [-r] flag to install command that tries to automatically find and install dependencies along with the specified bundle by using new methods in Repository Manager.
Repository Desktop 1.1.1
The dialogue now gives information about exactly what will be installed when asking if a Resolver should be used.
Repository Desktop 1.1.0
Added support for new methods in Repository Manager to use a Resolver service when available.
Repository Manager 1.2.0
Added install and resolverAvailable methods to RepositoryManager interface. Embedded Resolver and Repository APIs.
Repository Manager 1.1.0
Added support for Resolver services and added RepositoryManager.findResolution method.
KF-XML-Metatype 5.0.2
Only build an "all" variant. This makes it possible to correctly install CM-Desktop using the Repository Desktop with the Felix resolver.

Misc, start scripts, build system etc

init.xargs
Added commented out line to install Resolver reference implementation.
knopflerfish-osgi-5.1.0/fish200x300.gif0000644000175000017500000002240112346513620016424 0ustar felixfelixGIF89a,!)!))))1)11119!11!19!99!9B)99)9B)BB)BJ19B1BB1BJ1JJ9BJ9JJ9JRBJRBRRBRZJRZJZZJZcRZcRccRckZckZkkZkscckckkckscsscs{kssks{k{{k{s{{s{ss{{{{{ƽƽ,,H*\ȰÇ#J0/jqǎ ? Irɒ(OLr˖ƔYp@ YN4 J&PC͹gRJBe*ի33͊&ׯ^nqٲhzV[k5hjNx潫/߿{ xˆ +>lҺEU㡔Zv|y2ϞCw͹dr9ZѯU˾smڮFogA6}Hڨ'bMVF&H*eS~I6m Y"j&#)pY(lyhv)!_zZp*Z!FGhbUnzyicj*t 29驝Ϊ_ށ(M jH6 ҵ{^.[f2*ZI*!d$ _9Nӣ& xV br{!r;j~:. pPr(,Žvȁ*y0{K~;V3z3mS;!))slp.J:mY*Dj3mU#Dۓv}lMBƌ7vUS]V)G~򄜂(|ʭMZNA+m^,֢dSXCrHX+5\TQ;YkR1|mK6&AqΑv5(\)ҕ+TBxBP(0A3r҂9yu51eA < F©ɰ*Pz .f!P+`a ]bl$Z #@R\M4:;SA $*\a[N` kT6D0Be205s` 8x~ `|`~J 4"@|(Ѐ@|` A@P4 .@̀2X0r `'PHA{ 8`x&ȝjh %8 J7unD\°$ |/|! H0``X࿰-|AP($ v#_T {Z AGw^ T B y cлȋh-pB@,^ cp~ij X!"Ђ @ – V_1P$ LAk[`8 4 U@;pU lHp5>tve@`$WL[bPNJ4x{;7p;0F7}=q7zF0>0pI~F`7AjXvwwB3(>3E`n9,P1pA@m<@xjX32]p{Ie 2  `xz70_= %&l.@AxjTsgn3XXel9azg!&`)pNm'!l&JP&|{&Fqh ƊA5wDyZ 𧊖UaCw8Xv0vx{B r1o0ކ 0utXW` 8(=0~F(PDy @oh8w  )PXJ`mFa,I3}!ew(z kFw{O@+3b`4N }Fp4pC{V%`j[14pJncP9PqW; @}QOk!FЙ))p8 bkWБuhj}4Pb>ӈ3{&xޖJ00]^Px?@h P<}z'l%KNPȷJ `e60WАu@@U1J vWj t` $u A醤X0r1JP3=Z3 Pp0>*Viף)  iZ $M#=!$c).e֧?-8QC&hK:.`EszUPq5Wyfq#ea0`!0l^CFO8\\UU9Q R]HUkYcuGE&F~0n_̖J%3N#V[UwaRؤSn4\34kF>[UY$TQV<@X85fd\4VE#TZ9bcI"؂6*!4]iuTHTϤj&[ bլGڮb2eR{ïY*NޥfP\U[9JK{,Uy5<Ie.dwBPUư"H6R,;=5c*NQJZbLXvVwfN/fJ+Yf:jw[3"U%HF/81yTq 0,QmE4QYRk[~M5pX}l):P|AkDQX qK̈GJS`z(pŒA&}"PyQ!,vije7dۮUVT3p*x{D]=W00uj۰szYITҳ!M,6|{@\Q\8:mlvN$`w(LX{?݄,02MÌԴeeIwѹwd#mDecK5f^q3ɕPb!ݡmO!}jOv. FnnFlm1p< j3\v]Bpb\ Wi\p<@z[7g͍Іn!]LFq}&apN,:0[@2,#0! ޶ gQU]dQ; lwG=8):lXA k d\LLblb^w;e\+u5ۉ}HwU miD̊k>t~0`z<Pn߽Ñmn6tӺ$^]۔e:~+$y+TsUA9b߸AQ 9n*`҇L.a7 ڊ?xt`BQjMܦ_N(%mk`= 0h pLQK&:Z&m=B<ˎС.b9uEbB`cRFA8a7 ^߹/}K)պP+9DBW%6ʅ,m *ܼzm.f%Ec@13 @ Z*FOv-CryT䡟vΌ?S󚂐KQ`Xa$83)$ESC ,FuOX@`bZŰ* + uAcd/#$U:C 4iI\H(P#ˬ[sݽr8i5Z)^YO՛@a"`B^($|0R Hnρ=F-fȕ>H&uI_7&'6_|]aqe34`B/|QVM;U%z+7u[׻$8 +O Ѡ/C( k/{PfwziY~>F r@"TB;@QD d 0d0RQXKY x@<ė te `\EժJS/ŝ~Ŵii AR*< LY' ⇤&ChؙQ{:1H.bJ)|$<ٵo`1e= H?@3PJHF/KP¢х'1By""(   y2q9e@;|!H JITك)s"@ |P-T (P0 3P0lf@e%Qє+XH@?+ԣ)D|M@6 ,1b"wduAN1la0e#'RLYJ+vjQҐ SPU@C()p2脛Ҕ:.Rb-A\X IAqƷȢ S BZp(BcPe4q/0=|2P@@4`)5 3@lOkT YXʱ G=h @&#X`c*.Dkj=&>$`y^R rM})QM;Z2= D>dbBuAf!(HsqLdr"^86r75niE2}UOwI$ɺ3\k0758 ،k ,dabXEqLV$k*m%_xGs\*u(+Ox. Vur{;T0ʀy`)6c)Yys|Cǎ60Ŝiav0LfaQ96ČNpfrrc>ʠt$ߴB8a|+ؖu zӄ^`\K:׿&!]}WԠouuzS Պf]os.M1}qi䖌 ?ocB,^;2\vq7^:;q5x)\،,}A774;f|o}߰f9NlSoK o5GMS|Ţ}a]:yA8d=K7:k|.7*en#aTk}'umLGӉkWkx8AhRڣoJiRPznrC{WKӃzk]=\vgv_W~SogF[ wHǏaS־}Mgsw3+6?+@g<83S%Fsd;@bu¨k4B5÷$ӽ3@=60D–;DRLB3K*S6*F DEDY LE"=04F9 CkLl;+Ei2 ACk>ϫ4(< T%tC#ƒEs6G{3[G*5ÄABXl+d šl54FHDAJEE{GJ=dƸl=~6[Ź|@$,ʞ6koD3L,ML.,CļJ漽T7 tGBLO/䔦= OJ&NɕTNdΑ乤̃ HO۬kI$3ˁtH3GeDPOo4\8<(A, TBJrĸ|Od$Y6D,DDŽsBĽ+Hͼ4\dPPE4RttF,̟ƿ#KP ;knopflerfish-osgi-5.1.0/docs/0000755000175000017500000000000012475375720015112 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/css/0000755000175000017500000000000012475375714015705 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/css/knopflerfish.css0000644000175000017500000002100612346515440021075 0ustar felixfelix BODY { background: #ccc; font-size: 16px; } #main { width: 1000; background: #fff; border: 1px solid #000; margin: 0px auto; font-family: Lucida Grande, Tahoma, Verdana, Helvetica, sans-serif; font-size: 0.8125em; padding: 0px 0px 0px 0px; } #mainblock { margin-left: 210px; padding-right: 15px; font-family: "Lucida Grande", Tahoma, Lucida Sans, Verdana, Helvetica, sans-serif; /* font-size: 12.8px; font-size: 10pt; font-size: 0.8em; */ } #mainblock_obr { margin: 20px 10px 20px 10px; font-family: Helvetica, sans-serif; font-size: 12px; } #header { background: #0B2229; margin-bottom: 20px; height: 90px; margin: 0px; padding: 0px; border: 0px; } #header_logo { /* padding: 7px 0px 0px 15px; */ padding: 7px 0 0 15px; float:left; } #header_centerbox { background: #0B2229; height: 75px; width: 400px; float:left; text-align: center; margin: 0px; border: 0px; } .header_centerinfo_top { font-size: 1em; color: #cccccc; margin: 10px 0px 0px 40px; } .header_centerinfo_bottom { font-size: 1.5em; color: #cccccc; margin: 7px 0px 0px 60px; font-weight: bold; } #header_rightinfo { background: #0B2229; font-size: 10px; color: #cccccc; padding-top: 10px; padding-right: 20px; text-align: right; margin-left: 0px; height: 65px; border-style: none; margin: 0px; border: 0px; } #header_fade { height: 15px; border: 0px; margin: 0px 0px -4px 0px; margin: 0px; padding:0px; border-style: none; background-image: url('../images/fadeout_15.png'); background-size: 15px; background-repeat: repeat-x; clear:both; overflow: hidden; /* To prevent IE to add an extra 1px at the bottom */ } #leftmenu { margin-left: 10px; width: 180px; float:left; margin-top: 12px; /* background: #f4d6ea; */ } DL.leftmenu2,leftmenu2_last { margin: 6px 0px 6px 0px; padding: 6px 0px 6px 0px; border-style: solid; border-color: #802060; border-width: 0px 0px 1px 0px; } DL.leftmenu2_last { border-width: 0px 0px 0px 0px; } DT.leftmenu2 { /* font-family: Lucida Grande, Helvetica, sans-serif; */ /*font-size: 0.8em; */ font-weight: bold; padding: 0px 0px 0px 0px; margin: 0px 0px 0px 0px; } DD.leftmenu2 { /* font-family: Lucida Grande, Tahoma, Helvetica, sans-serif; */ /* font-size: 0.8em; */ padding: 0px 0px 0px 12px; margin: 0px 0px 0px 0px; background-repeat: no-repeat; background-position: 0 .5em; } DD.leftmenu3 { font-family: Lucida Grande, Tahoma,Helvetica, sans-serif; font-size: 12px; padding: 0px 0px 0px 24px; margin: 0px 0px 0px 0px; background-image: url('/images/slash_small.jpg'); background-repeat: no-repeat; background-position: 0 .5em; } DD.leftmenu4 { font-family: Lucida Grande, Tahoma,Helvetica, sans-serif; font-size: 12px; padding: 0px 0px 0px 32px; margin: 0px 0px 0px 0px; background-image: url('/images/slash_small.jpg'); background-repeat: no-repeat; background-position: 0 .5em; } #footer { clear:both; border-style: solid; border-color: #802060; border-width: 1px 0px 0px 0px; margin: 20px 15px 15px 15px; } #copyright { margin-left: 200px; font-size:10px; color: #000; text-align: right; padding: 5px 10px 0px 0px; } H1, H1.kf { font-family: Helvetica Neue, Helvetica, Verdana, Arial, Helvetica, sans-serif; font-size: 2em; font-weight:bold; border-style: solid; border-color: #802060; border-width: 0px 0px 1px 0px; padding-bottom: 2px; margin: 1.4em 0 0.6em 0; color: #444444; } H2, H2.kf, H2.filled { font-family: Helvetica Neue; Helvetics, Lucida Grande, Verdana, Arial, Helvetica, sans-serif; font-size: 1.6em; font-weight:bold; color: #444444; padding: 0px; margin: 1.4em 0 0.8em 0; margin: 0.8em 0 0.2em 0; } H2.filled { background-image: url('../images/shortfadeout_20px.png'); border-style: solid; border-color: #ccc; border-width: 1px 0px 1px 0px; background-repeat: repeat-x; padding: 3px 0px 3px 6px; } /* H2 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:18px; font-weight:bold; border-style: solid; border-color: #802060; border-width: 0px 0px 2px 0px; padding-bottom: 2px; } */ H3 { font-family: Lucida Grande, Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size:1.1em; font-weight:bold; background: #805362; color: #ffffff; border-style: solid; border-style: solid; border-color: #000000; border-width: 1px; padding-top: 2px; padding-bottom: 2px; padding-left: 8px; } H3.kf { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:14px; font-weight:bold; background: #805362; color: #ffffff; border-style: solid; border-color: #000000; border-width: 1px; padding-top: 2px; padding-bottom: 2px; padding-left: 8px; color: #444444; border-style: solid; border-color: #ccc #fff #ccc #fff; border-width: 1px; border-width: 1px 0px 1px 0px; background-image: url('../images/shortfadeout_20px.png'); background-repeat: repeat-x; } .navigation_enabled { text-decoration: none; color: #000000; } .nav2_enabled { text-decoration: none; color: #ffffff; } .navigation_enabled:hover { text-decoration: underline; color: #cc3399; } .navigation_disabled { text-decoration: none; font-weight: bold; color: #802060; } .navigation_disabled:visited { text-decoration: none; font-weight: bold; color: #802060; } A.navigation_disabled:hover { text-decoration: none; } A { color: #802060; } PRE { font-family: Monaco, Courier New, Courier; font-size:12px; color:#000000; text-align:left; font-weight:normal; } PRE.code { border-style: solid; border-color: #ddddff; border-width: 1px; background-color: #f7F7FF; padding: 5px 0px 5px 6px; } pre.shell { border-style: solid; border-color: #d0d0d0; border-width: 1px; background-color: #f7f7f7; padding: 5px 0px 5px 6px; } TH { text-align: left; font-family: Lucida Grande, Tahoma,Helvetica, sans-serif; font-size: 14px; } TH.fancy { text-align: center; font-family: Lucida Grande, Tahoma,Helvetica, sans-serif; font-size: 12px; } TD { font-family: Lucida Grande, Tahoma,Helvetica, sans-serif; font-size: 12px; vertical-align: top; } TABLE.fancy { border-collapse: collapse; } TR.fancy { background: #C9C9C9; border-bottom: 2px solid #A3A3A3; border-top: 2px solid #A3A3A3; } TD.fancy { padding: 2px 4px 2px 4px; } TD.fancy_row { background: #C9C9C9; border-bottom: 2px solid #A3A3A3; border-top: 2px solid #A3A3A3; } #release_notes dt { font-weight: bold; } #release_notes dd { margin-bottom: 10px; } .release_notes dt { font-weight: bold; } .release_notes dd { margin-bottom: 10px; } .kf dt { font-weight: bold; } .kf dd { margin-bottom: 10px; } table.kf { border-width: 1px; border-color: #666666; border-collapse: collapse; background-color: #ffffff; border-style: solid; } table.kf th { font-weight: bold; font-size:12px; text-align:center; border-width: 1px; padding: 5px; border-style: solid; border-color: #999999; background-color: #dedede; } table.kf td { border-style: solid; border-width: 1px; padding: 5px; border-color: #999999; background-color: #ffffff; } table.kf td.subhead { font-weight: bold; background: #eeeeee; } table.kf td.kfpro { color: #888888; background-color: #ffffff; /* background-image: url('../images/knopflerfish_pro.png');*/ background-repeat: no-repeat; background-position: center center; } code { font-family: Monaco, Courier; font-size: 0.8125em; } tt { font-family: Monaco, Courier; font-size: 0.8125em; } .note_group { margin: 1.5em 0 0.5em 0; } .note_name { font-weight: bold; color:#333333; } .note_item { display: list-item; margin: 0.5em 0 0.5em 2em; } p { margin-top: 0.5em; margin-bottom: 0.5em; }knopflerfish-osgi-5.1.0/docs/css/kf_man.css0000644000175000017500000000417412346515440017645 0ustar felixfelixBODY { /* font-size:12px; */ font-family: Lucida Grande, Tahoma, Helvetica, Arial, sans-serif; font-size: 16px; } .mainblock { background: #fff; /* font-size:12px; */ font-size: 0.8125em; } .manpage { font-family: Lucida Grande, Tahoma, Helvetica, Arial, sans-serif; /* font-size:12px; */ } H1.man { font-family: Helvetica, Arial, sans-serif; font-size: 2em; font-weight:bold; margin-left: 0; border-style: none; } H2.man { font-family: Lucida Grande, Verdana, Helvetica, Arial, sans-serif; font-size: 1.3em; font-weight:bold; border-style: solid; color: #444444; border-style: solid; border-color: #ccc; border-width: 1px 0px 1px 0px; background-image: url('../images/shortfadeout_20px.png'); background-repeat: repeat-x; padding: 3px 0px 2px 8px; margin: 1.4em 0 0.8em 0; } H3.man { font-family: Lucida Grande, Verdana, Helvetica, Arial, sans-serif; font-size: 1.1em; font-weight:bold; background: #fff; color: #000; border-style: solid; border-color: #805362; border-width: 0px 0px 0px 0px; padding: 0; } .userdoc_hdr_left { font-weight: bold; float:left; } #man_leftmenu A { color: #000; text-decoration: none; } #man_leftmenu A:hover { color: #805362; text-decoration: underline; font-weight: bold; } .userdoc_hdr_right { font-weight: bold; text-align: right; } .abstract { font-style: italic; } table.man { border-width: 1px; border-color: #666666; border-collapse: collapse; } table table.man_inner { border-style: hidden; border-collapse: collapse; } table table.man_inner td { border-style: hidden; padding: 4px; } table.man th { font-size:12px; border-width: 1px; padding: 6px; border-style: solid; border-color: #666666; background-color: #fafff5; color: #444444; } table.man td { border-width: 1px; padding: 6px; border-style: solid; border-color: #666666; background-color: #ffffff; } knopflerfish-osgi-5.1.0/docs/installing.html0000644000175000017500000001605112346515440020137 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - Installing Knopflerfish

Installing Knopflerfish

Installation instructions for the complete framework

You need at least Java 1.4 to install the framework.

The Knopflerfish OSGi framework should be installed by simply running the distribution jar file, either by double-clicking on the distribution file, or by the command:
    > java -jar knopflerfish_osgi_sdk_<version>.jar
This will open an installation wizard for selection installation directory and which components to install.
OSGi framework runtime files
The execution environment, including the Knopflerfish OSGi framework and bundles
Java sources and build environment
Installs all java source code files and a build system for rebuilding Knopflerfish locally form the supplied source files.
Knopflerfish Documentation
The Knopflerfish user and developer documentation.

If you don't need the wizard, installation can also be done in batch mode, by entering the command:

    > java -jar knopflerfish_osgi_sdk_<version>.jar -batch -silent
...or by simply unpacking the jar file manually. (WinZip is also capable of unpacking .jar files)

After successfully installing Knopflerfish you may move on to starting the framework.

Installation instructions for the tiny, remotely loading framework

  1. Unzip the distribution zip file
  2. Execute framework_compact.jar
        > cd knopflerfish.org/osgi
        > java -jar framework_compact.jar
    
All bundles defined in remote-init.xargs will be loaded over the net.

Please see the next section for setting and configuring Knopflerfish run time options using .xargs files.

knopflerfish-osgi-5.1.0/docs/examples/0000755000175000017500000000000012475375714016733 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/0000755000175000017500000000000012475375714017476 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/user/0000755000175000017500000000000012475375714020454 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/user/build.xml0000644000175000017500000000204212346515440022260 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/examples/cpa/user/bundle.manifest0000644000175000017500000000102012346515440023433 0ustar felixfelixManifest-Version: 1.0 Bundle-Version: 1.0.0 Bundle-Name: CPA service example Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.knopflerfish.cpaexample.user Bundle-Category: example Bundle-Description: Condition Permission Admin service example Bundle-Vendor: Knopflerfish Bundle-ContactAddress: http://www.knopflerfish.org Bundle-DocURL: http://www.knopflerfish.org/releases/current/docs/bundledoc /index.html Bundle-SubversionURL: https://www.knopflerfish.org/svn/knopflerfish.org/trunk /osgi/bundles_examples/cpa/user/ knopflerfish-osgi-5.1.0/docs/examples/cpa/user/src/0000755000175000017500000000000012475375714021243 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/user/src/org/0000755000175000017500000000000012475375714022032 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/user/src/org/knopflerfish/0000755000175000017500000000000012475375714024524 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/user/src/org/knopflerfish/cpaexample/0000755000175000017500000000000012475375714026643 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/user/src/org/knopflerfish/cpaexample/service/0000755000175000017500000000000012475375714030303 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/user/src/org/knopflerfish/cpaexample/service/user/0000755000175000017500000000000012475375714031261 5ustar felixfelix././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/docs/examples/cpa/user/src/org/knopflerfish/cpaexample/service/user/UserService.javaknopflerfish-osgi-5.1.0/docs/examples/cpa/user/src/org/knopflerfish/cpaexample/service/user/UserServ0000644000175000017500000000453412346515440032755 0ustar felixfelixpackage org.knopflerfish.cpaexample.service.user; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.security.AccessController; import java.security.PrivilegedAction; import org.osgi.service.log.LogService; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.ServiceReference; // Separate activator, interface and implementation classes // should be used but to keep the number of source files // to a minimum, only one class is used in this example public class UserService implements BundleActivator { private static String fileName = "/tmp/osgiuser"; private BundleContext bc; public void start(BundleContext bc) throws BundleException { this.bc = bc; bc.registerService(UserService.class.getName(), this, null); } public void stop(BundleContext context) { } public void login(final String name) { final File f = new File(fileName); AccessController.doPrivileged(new PrivilegedAction() { public Object run() { if (f.exists()) { throw new IllegalStateException("User already logged in"); } try { OutputStream os = new FileOutputStream(f); os.write(name.getBytes("UTF-8")); os.close(); log(LogService.LOG_INFO, "User " + name + " logged in"); } catch (IOException ioe) { log(LogService.LOG_WARNING, "Problem logging user in: " + ioe); } return null; } }); } public void logout() { final File f = new File(fileName); AccessController.doPrivileged(new PrivilegedAction() { public Object run() { if (!f.exists()) { throw new IllegalStateException("No user logged in"); } f.delete(); log(LogService.LOG_INFO, "User logged out"); return null; } }); } private void log(int level, String message) { ServiceReference sRef = bc.getServiceReference(LogService.class.getName()); if (sRef != null) { LogService log = (LogService) bc.getService(sRef); if (log != null) { log.log(level, message); } bc.ungetService(sRef); } } } knopflerfish-osgi-5.1.0/docs/examples/cpa/user/resources/0000755000175000017500000000000012475375714022466 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/user/resources/OSGI-INF/0000755000175000017500000000000012475375714023641 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/user/resources/OSGI-INF/permissions.perm0000644000175000017500000000073612346515440027074 0ustar felixfelix(org.osgi.framework.PackagePermission "org.osgi.framework" "import") (org.osgi.framework.PackagePermission "org.osgi.service.log" "import") (org.osgi.framework.ServicePermission "org.osgi.service.log.LogService" "get") (java.io.FilePermission "/tmp/osgiuser" "read,write,delete") (org.osgi.framework.PackagePermission "com.makewave.cpaexample.service.user" "exportonly") (org.osgi.framework.ServicePermission "com.makewave.cpaexample.service.user.UserService" "register") knopflerfish-osgi-5.1.0/docs/examples/cpa/build.xml0000644000175000017500000000152312346515440021305 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/examples/cpa/init.xargs0000644000175000017500000000164312346515440021500 0ustar felixfelix# # Generated from bundles_examples/cpa/init.xargs.in # Knopflerfish release 5.1.0 # # load common properties -xargs props.xargs # Semicolon seprated list of base URLs for searching (completing) # bundle URLs in "-install URL" command line options and in the console. -Forg.knopflerfish.gosg.jars=file:jars/;file:examples_jars/ # CPA admin bundle, started before anything else -initlevel 1 -istart cpaexample_admin/cpaexample_admin-1.0.0.jar -launch # basic KF bundles -initlevel 2 -install cm/cm_api-5.0.1.jar -istart log/log_all-5.0.0.jar -istart console/console_all-4.0.1.jar -istart consoletty/consoletty-4.0.1.jar -istart frameworkcommands/frameworkcommands-4.0.1.jar -istart logcommands/logcommands-5.0.0.jar # bundle to test and test bundle -initlevel 3 -install file:/opt/kf/totest/cpaexample_user/cpaexample_user_all-1.0.0.jar -install file:/opt/kf/totest/cpaexample_caller/cpaexample_caller-1.0.0.jar -startlevel 3knopflerfish-osgi-5.1.0/docs/examples/cpa/caller/0000755000175000017500000000000012475375714020740 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/caller/build.xml0000644000175000017500000000175512346515440022556 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/examples/cpa/caller/bundle.manifest0000644000175000017500000000102212346515440023721 0ustar felixfelixManifest-Version: 1.0 Bundle-Version: 1.0.0 Bundle-Name: CPA caller example Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.knopflerfish.cpaexample.caller Bundle-Category: example Bundle-Description: Condition Permission Admin caller example Bundle-Vendor: Knopflerfish Bundle-ContactAddress: http://www.knopflerfish.org Bundle-DocURL: http://www.knopflerfish.org/releases/current/docs/bundledoc /index.html Bundle-SubversionURL: https://www.knopflerfish.org/svn/knopflerfish.org/trunk /osgi/bundles_examples/cpa/caller/ knopflerfish-osgi-5.1.0/docs/examples/cpa/caller/src/0000755000175000017500000000000012475375714021527 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/caller/src/org/0000755000175000017500000000000012475375714022316 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/caller/src/org/knopflerfish/0000755000175000017500000000000012475375714025010 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/caller/src/org/knopflerfish/cpaexample/0000755000175000017500000000000012475375714027127 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/caller/src/org/knopflerfish/cpaexample/bundle/0000755000175000017500000000000012475375714030400 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/caller/src/org/knopflerfish/cpaexample/bundle/caller/0000755000175000017500000000000012475375714031642 5ustar felixfelix././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/docs/examples/cpa/caller/src/org/knopflerfish/cpaexample/bundle/caller/CallerActivator.javaknopflerfish-osgi-5.1.0/docs/examples/cpa/caller/src/org/knopflerfish/cpaexample/bundle/caller/Calle0000644000175000017500000000177412346515440032603 0ustar felixfelixpackage org.knopflerfish.cpaexample.bundle.caller; import java.io.IOException; import org.knopflerfish.cpaexample.service.user.UserService; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; public class CallerActivator implements BundleActivator { public void start(BundleContext bc) throws IOException { ServiceReference sRef = bc.getServiceReference(UserService.class.getName()); if (sRef != null) { UserService us = (UserService) bc.getService(sRef); if (us != null) { us.login("joek"); } bc.ungetService(sRef); } } public void stop(BundleContext bc) throws IOException { ServiceReference sRef = bc.getServiceReference(UserService.class.getName()); if (sRef != null) { UserService us = (UserService) bc.getService(sRef); if (us != null) { us.logout(); } bc.ungetService(sRef); } } } knopflerfish-osgi-5.1.0/docs/examples/cpa/caller/resources/0000755000175000017500000000000012475375714022752 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/caller/resources/OSGI-INF/0000755000175000017500000000000012475375714024125 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/caller/resources/OSGI-INF/permissions.perm0000644000175000017500000000037712346515440027361 0ustar felixfelix(org.osgi.framework.PackagePermission "org.osgi.framework" "import") (org.osgi.framework.PackagePermission "com.makewave.cpaexample.service.user" "import") (org.osgi.framework.ServicePermission "com.makewave.cpaexample.service.user.UserService" "get") knopflerfish-osgi-5.1.0/docs/examples/cpa/admin/0000755000175000017500000000000012475375714020566 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/admin/build.xml0000644000175000017500000000166612346515440022405 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/examples/cpa/admin/bundle.manifest0000644000175000017500000000101012346515440023544 0ustar felixfelixManifest-Version: 1.0 Bundle-Version: 1.0.0 Bundle-Name: CPA admin example Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.knopflerfish.cpaexample.admin Bundle-Category: example Bundle-Description: Condition Permission Admin example Bundle-Vendor: Knopflerfish Bundle-ContactAddress: http://www.knopflerfish.org Bundle-DocURL: http://www.knopflerfish.org/releases/current/docs/bundledoc /index.html Bundle-SubversionURL: https://www.knopflerfish.org/svn/knopflerfish.org/trunk /osgi/bundles_examples/cpa/admin/ knopflerfish-osgi-5.1.0/docs/examples/cpa/admin/src/0000755000175000017500000000000012475375714021355 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/admin/src/org/0000755000175000017500000000000012475375714022144 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/admin/src/org/knopflerfish/0000755000175000017500000000000012475375714024636 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/admin/src/org/knopflerfish/cpaexample/0000755000175000017500000000000012475375714026755 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/admin/src/org/knopflerfish/cpaexample/bundle/0000755000175000017500000000000012475375714030226 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/examples/cpa/admin/src/org/knopflerfish/cpaexample/bundle/admin/0000755000175000017500000000000012475375714031316 5ustar felixfelix././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/docs/examples/cpa/admin/src/org/knopflerfish/cpaexample/bundle/admin/AdminActivator.javaknopflerfish-osgi-5.1.0/docs/examples/cpa/admin/src/org/knopflerfish/cpaexample/bundle/admin/AdminAc0000644000175000017500000000477612346515440032540 0ustar felixfelixpackage org.knopflerfish.cpaexample.bundle.admin; import java.util.List; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.ServiceReference; import org.osgi.service.condpermadmin.ConditionalPermissionAdmin; import org.osgi.service.condpermadmin.ConditionalPermissionInfo; import org.osgi.service.condpermadmin.ConditionalPermissionUpdate; public class AdminActivator implements BundleActivator { /* // initial version, for tested bundles without local permission private static final String[] ENCODED_PINFO = { "allow { [org.osgi.service.condpermadmin.BundleLocationCondition \"file:jars/*\"] (java.security.AllPermission) } \"allToTrusted\"", "allow { [org.osgi.service.condpermadmin.BundleLocationCondition \"file:/opt/kf/totest/*\"] (org.osgi.framework.PackagePermission \"*\" \"import\") } \"importToTested\"" }; */ // final version, for tested bundles that use local permissions private static final String[] ENCODED_PINFO = { "allow { [org.osgi.service.condpermadmin.BundleLocationCondition \"file:jars/*\"] (java.security.AllPermission) } \"allToTrusted\"", "allow { [org.osgi.service.condpermadmin.BundleLocationCondition \"file:/opt/kf/totest/cpaexample_user*\"] (java.security.AllPermission) } \"allToUser\"", "allow { [org.osgi.service.condpermadmin.BundleLocationCondition \"file:/opt/kf/totest/cpaexample_caller*\"] (java.security.AllPermission) } \"allToCaller\"" }; public void start(BundleContext bc) throws BundleException { ServiceReference sRef = bc.getServiceReference(ConditionalPermissionAdmin.class.getName()); if (sRef != null) { ConditionalPermissionAdmin cpa = (ConditionalPermissionAdmin) bc.getService(sRef); installPolicies(cpa, ENCODED_PINFO); } else { throw new BundleException("Bundle CPA-test can not start, There is no " + "ConditinalPermissionAdmin service"); } } public void stop(BundleContext context) { } void installPolicies(ConditionalPermissionAdmin cpa, String[] pInfos) { ConditionalPermissionUpdate cpu = cpa.newConditionalPermissionUpdate(); List piList = cpu.getConditionalPermissionInfos(); for (int i = 0; i < pInfos.length; i++) { String pInfo = pInfos[i]; ConditionalPermissionInfo cpi = cpa.newConditionalPermissionInfo(pInfo); piList.add(cpi); } cpu.commit(); } } knopflerfish-osgi-5.1.0/docs/examples/cpa/init.xargs.in0000644000175000017500000000151712346515440022105 0ustar felixfelix# # Generated from bundles_examples/cpa/init.xargs.in # Knopflerfish release $(VERSION) # # load common properties -xargs props.xargs # Semicolon seprated list of base URLs for searching (completing) # bundle URLs in "-install URL" command line options and in the console. -Forg.knopflerfish.gosg.jars=file:jars/;file:examples_jars/ # CPA admin bundle, started before anything else -initlevel 1 -istart @cpaexample_admin-N.N.N.jar@ -launch # basic KF bundles -initlevel 2 -install @cm_api-N.N.N.jar@ -istart @log_all-N.N.N.jar@ -istart @console_all-N.N.N.jar@ -istart @consoletty-N.N.N.jar@ -istart @frameworkcommands-N.N.N.jar@ -istart @logcommands-N.N.N.jar@ # bundle to test and test bundle -initlevel 3 -install file:/opt/kf/totest/@cpaexample_user_all-N.N.N.jar@ -install file:/opt/kf/totest/@cpaexample_caller-N.N.N.jar@ -startlevel 3knopflerfish-osgi-5.1.0/docs/examples/cpa/props.xargs0000644000175000017500000000055412346515440021700 0ustar felixfelix# Initial startup verbosity, 0 is low verbosity #-Forg.knopflerfish.framework.main.verbosity=0 # Log -Forg.knopflerfish.log.level=info # Security -Forg.osgi.framework.security=osgi -Forg.knopflerfish.framework.service.permissionadmin=false # Various debug flags -Forg.knopflerfish.framework.debug.errors=true -Forg.knopflerfish.framework.debug.permissions=true knopflerfish-osgi-5.1.0/docs/android_dalvik_tutorial.html0000644000175000017500000002663612346515440022702 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - running on Android / Dalvik

Knopflerfish Android / Dalvik Tutorial

Contents

  1. Setting up the environment
  2. Building Dalvik dex files
  3. Creating a Dalvik KF run-time
  4. Installing KF on the Android Emulator
  5. Running KF under Dalvik
  6. Android projects

Setting up the Environment

To run Knopflerfish on the Android/Dalvik VM you need the Android SDK. This SDK contains the necessary tool to convert and pack Java classes and JAR files to the DEX format used by Dalvik.

The KF ant build system has built-in support for dexifying JAR files using the tools from the Android SDK.

This guide assumes the SDK for Android 4.0 API level 15 is used.

Building Dalvik dex files

The KF ant build system has support to create the necessary dex files for the framework and all the bundles. For any bundle, the framework, or the whole KF distribution dex versions can be built by specifying ANDROID_HOME to the build target.

 > ant -DANDROID_HOME=>path to android sdk top directory  <

It is recommended you build the dex files on a clean distribution.

The generated dex files are places in the bundle's JAR file as classes.dex directly in the root. The Java class files are still kept in the JAR file. This means the same bundle can run on a normal JVM as well as with Dalvik without any modifications. From a size perspective this is of course not optimal to include both Java classes and classes.dex. A bundle get roughly twice as large after dexifying it. Future KF releases may have support to create pure dex version of bundles.

After building or dexifying KF the push the necessary files to the emulator, typically using adb. There is since KF 3.3 an android tool included to simplify this process, see next section.

Creating a Dalvik KF run-time

The KF distribution contains a simple build tool to create and install KF on an Android emulator. It is located in the tools/android directory.

After specifying After stepping into this directory run ant and specify where the Android SDK is installed:

 > cd tools/android
 > ant setup -DANDROID_HOME=/Users/knopflerfish/bin/android-sdk-mac_x86/  
  
Specifying ANDROID_HOME is only necessary the first time you run ant. The location is stored in the android.properties file located in the same directory. You can run the setup target again, pointing at another location if needed.
 > ant setup -DANDROID_HOME=/bin/android-sdk
  

There is a small template xargs file included. This contains a very basic set of bundles. Feel free to modify or add additional xargs files.

The build will create the run time in:

  > out/dalvik
  

Installing KF on the Android/Dalvik Emulator

The build.xml file includes an install target. This will install the created KF run time on the emulator using the adb tools. For this to function the Android emulator must be running of course.

  > ant install
  
The files are installed in /data/kf-3.3.0 by default on the emulator.

Running KF under Dalvik

To launch KF under Dalvik you need to start Dalvik in the emulator. This is typically done by starting a shell on the emulator:

  > adb shell
  root@android:/ #   
  root@android:/ # cd /data/kf-3.3.0/                                          
  root@android:/data/kf-3.3.0 # 
  root@android:/data/kf-3.3.0 # ls
  dalvik.xargs
  framework.jar
  jars
  props.xargs
  root@android:/data/kf-3.3.0 # 
The next step is to launch KF. This is done as usual, but using the dalvikvm instead.
  root@android:/data/kf-3.3.0 # dalvikvm -classpath framework.jar \
  org.knopflerfish.framework.Main -xargs dalvik.xargs
Now KF is running under the dalvik VM! The ttyconsole bundle is included in the dalvik.xargs. In the emulator shell window you can interact with the KF framework just as you are used to:
 > lsb
   id  level/state name
   --------------------
    0  0/active    System Bundle            1  1/active    Log Service
    2  1/active    cm                       3  1/active    Console
    4  1/active    Event-Admin              5  2/resolved  util-LIB
    6  2/resolved  JSDK-API                 7  4/active    HTTP-Server
    8  5/active    FW-Commands-IMPL         9  5/active    LogCommands-IMPL
   10  5/active    CM-Commands-IMPL        11  5/active    TTY-Console-IMPL
   12  7/active    HTTP-root-IMPL       
 >     
To verify we are successfully running the KF HTTP server use the browser in Android emulator and connect to the KF HTTP server running on port 8080:

httproot on
  Android

Note on Running KF under Dalvik

The framework will create .dexopt files that lives side-by-side with the jar files. This can cause a problem if your bundles lives in a read-only directory and have the property (which is default):

  -Forg.knopflerfish.framework.bundlestorage.file.reference=true
  
You then need to set the property to false, so that the bundle jars are copied into the "fwdir".

Android Projects

The latest version of KF added the apk directory to tools/android. Here you can find two Android projects that can be used to build an Android .apk containing Knopflerfish, see the README.txt file in the projects directory for more information.

Android
  application

These projects are built using a combination of KF and the Android ant tasks. Bundles that you include in your .apk will be dexified as described above and DEX files for framework.jar and Java classes included in the projects will be automatically created by the build system.

knopflerfish-osgi-5.1.0/docs/programming.html0000644000175000017500000013064212346515440020320 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - Develop OSGi bundles

Programming Knopflerfish

Contents

  1. Using Eclipse to create bundles
  2. Using Ant to create bundles
  3. Using Maven to build bundles
  4. The BundleActivator
  5. OSGi Service tutorial
  6. Bundle data access
  7. Win32 tips
  8. Optimizing startup time, memory or disk usage
  9. Details on the included ant build system
  10. Using the Subversion repository

Using Eclipse to create bundles

See the Knopflerfish Eclipse Plugin documentation on the Knopferfish web site.

Using Ant to create bundles

Prerequisites

Creating a new bundle

New bundles can be created using the included ant build system. Naturally, you can create bundles manually, but this requires some knowledge about the OSGi manifest format.

knopflerfish refers to the unpacked knopflerfish directory, typically knopflerfish.org

Using the included ant build system to create a new bundle

1. Create a directory for the new bundle
> cd knopflerfish/osgi/bundles
> mkdir mybundle
      
2. Copy the ant bundle build template
> cp knopflerfish/ant/build_example.xml build.xml
      
3. Change the project name in the build.xml file

Set the impl.pattern and api.pattern properties to the packages that contains implementation and API code.

Depending on where you have put your new bundle, you might have to modify the path to bundlebuild.xml in the <import file="${proj.dir}/../../../ant/bundlebuild.xml"/> element at the end of the build-file.

For details on bundle generation, see knopflerfish/ant/bundlebuild.xml

<project name="mybundle" default="all">
...
<property name  = "impl.pattern"
          value = "example/mybundle/impl/**"/>
..
<property name  = "api.pattern"
          value = "example/mybundle/*"/>

      
4. Create the java source code in src directory.
> mkdir -p src/example/mybundle/impl
      
Example BundleActivator: src/examples/mybundle/impl/Activator.java
package example.mybundle.impl;

import org.osgi.framework.BundleActivator;

public class Activator implements BundleActivator {
  ...
  public void start(BundleContext bc) {
    ...
  }
  public void stop(BundleContext bc) {
    ...
  }
      

5. Compile the bundle.

The ant build system will automatically find the BundleActivator, imports and exports and generate a bundle manifest file.

The resulting file will be generated to knopflerfish/osgi/jars/mybundle/mybundle.jar

Intermediate build results will be placed in knopflerfish/osgi/out/mybundle

> ant
      

6. Install the bundle.

This can be done either by using the text console, dragging the bundle using the Swing desktop UI or by modifying the framework startup file init.xargs

Using the console to install and start the bundle.
> install file:jars/mybundle/mybundle.jar
> start mybundle.jar
      
Drag a bundle into the Desktop UI to install and start the bundle.
7. Using ant commands and telnet console to install/start/stop/update bundles.

The ant build has support for communicating to a running framework and install, start, stop, update and uninstall bundles.

Given that the consoletelnet bundle is running, you can simply use these built-in targets to handle the life cycle of the bundle.

The properties console.host, console.port, console.user and console.pwd controls the details of the console connection.

Note: requires netcomponents.jar in $ANT_HOME/lib. Needs to be separately downloaded from http://www.savarese.org/oro/downloads

> ant install
to install the compiled bundle. Similarly, type
> ant start
to start the bundle. Type
> ant -projecthelp
to see all available targets.
top

Using Maven to build bundles

Prerequisites

Knopflerfish Releases Repository

To simplify building bundles that depends on OSGi or Knopflerfish APIs with Maven Knopflerfish offers a Maven 2 repository with all released artifacts (framework and bundles). This Maven2 repository id called "Knopflerfish Releases Repository" and can be found at
http://www.knopflerfish.org/maven2/
It contains all artifacts from Knopflerfish release builds starting with 2.3.3, 2.4, 3.0, 3.1, ...

To make it easy to find artifacts that belongs to the same Knopflerfish release the repository contains an xml-document for each release that lists all artifacts with group id, artifact id and version. These documents are located in
http://www.knopflerfish.org/maven2/org/knopflerfish/
and are named like KF-VERSION_dependencyManagement.xml.
E.g., the file with URL http://www.knopflerfish.org/maven2/org/knopflerfish/KF-3.1.0_dependencyManagement.xml will list all artifacts from the Knopflerfish 3.1 release.

Each nightly build and release build (as of Knopflerfish 3.2) will also have a build specific Maven2 repository that contains exactly those artifacts that belongs to the build. The URL of these repositories are on the form
http://www.knopflerfish.org/snapshots/current_trunk/maven2/
http://www.knopflerfish.org/releases/3.2.0/maven2/

A sample POM file for building a simple bundle

Here is a sample POM-file that may be used to build a simple bundle. Following Maven conventions the source code of the bundle should be in the subdirectory named src/main/java, resources should be in src/main/resources.
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>

  <groupId>org.knopflerfish.examples</groupId> 
  <artifactId>example1</artifactId> 
  <version>1.0</version> 
  <packaging>bundle</packaging>

  <name>Example 1</name>
  <description>A bundle that exports a package.</description>

  <properties>
    <bundle.namespace>${pom.groupId}.${pom.artifactId}</bundle.namespace>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Export-Package>${bundle.namespace}</Export-Package>
            <Private-Package>!${bundle.namespace}</Private-Package>
          </instructions>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <repositories>
    <repository>
      <releases>
        <enabled>true</enabled>
        <updatePolicy>never</updatePolicy>
        <checksumPolicy>fail</checksumPolicy>
      </releases>
      <snapshots>
        <enabled>false</enabled>
        <updatePolicy>never</updatePolicy>
        <checksumPolicy>fail</checksumPolicy>
      </snapshots>
      <id>Knopflerfish</id>
      <name>Knopflerfish Releases Repository</name>
      <url>http://www.knopflerfish.org/maven2</url>
      <layout>default</layout>
    </repository>
  </repositories>
  <dependencyManagement>
    <dependencies> 
      <!-- KF 3.1.0 -->

      <!--framework.jar-->
      <dependency>
        <groupId>org.knopflerfish</groupId>
        <artifactId>framework</artifactId>
        <version>5.1.6</version>
      </dependency>

      <!--log/log_api-3.0.5.jar-->
      <dependency>
        <groupId>org.knopflerfish</groupId>
        <artifactId>log-API</artifactId>
        <version>3.0.5</version>
      </dependency>

      <!--cm/cm_api-3.0.1.jar-->
      <dependency>
        <groupId>org.knopflerfish.bundle</groupId>
        <artifactId>cm-API</artifactId>
        <version>3.0.1</version>
      </dependency>

    </dependencies> 
  </dependencyManagement>
</project>
Note: The <repository>-element is normally placed in the top-level parent POM or in the settings-file. In this example it has been added to the bundles POM-file to keep it all in one file. The same applies to the <dependencyManagement>-element.

Coding Style guides

When writing OSGi bundles, all normal java guidelines apply, but some things might be worth noting. The list below is intended to give some hints on writing stable bundles, but feel free to use your own judgment.

The BundleActivator

The BundleActivator can be considered your application's main class. A bundle which is expected to start, register or use other service, must have a BundleActivator implementation and a reference to the BundleActivator's class name in its manifest file.
Naming the BundleActivator
Preferably name the BundleActivator class Activator. This makes it easy to find for other developers.
public class Activator implements BundleActivator {
  ...
}
Use package names

Do use normal package name conventions. One convention is to suffix the implementation parts of bundle with .impl

However, the implementation parts can theoretically have any package name you want, since the framework keeps separate name spaces for separate bundles.

// This is the not exported implementation part of a bundle
package com.acme.osgi.test.impl;

// from the bundle's API part
import com.acme.osgi.test.TestService;

public class Activator implements BundleActivator {
  TestService testService = ...
  ...
}
Store the BundleContext
You can use a static BundleContext in the Activator class.
There is really no need for passing around bc by parameter to all internal classes. The same trick should be used for other singular common objects as the log service tracker.
// Static bundle context
public class Activator implements BundleActivator {

   static BundleContext bc;

   public void start(BundleContext bc) {
     Activator.bc = bc;
     ...
   }

   public void stop(BundleContext bc) {
     Activator.bc = null; // allow for garbage collection
     ...
   }
}
Automatic cleanup of services
There is no need to unregister services in the stop() method. This is done automatically by the framework.
However, static variables should be nulled to allow for garbage collection.
public void stop(BundleContext bc) {
  Activator.bc = null;
}
No automatic cleanup of memory, threads, windows etc
Do deallocate any other resources as threads or (gah!) Swing windows. They are not stopped or closed automatically.
// Cleanup up resources in stop method
public void stop(BundleContext bc) {
  Activator.bc = null;
  if(window != null) {
    window.setVisible(false);
    window = null;
  }
}
Beware of re-using service object
Beware of re-using an object for multiple service registrations.
If you register a public class with one or more public methods, these public methods will become available to all other bundles if they have get permission on the service. Instead, make sure you only implement public methods which are members of the registered service's interface.

A more compact method than multiple interfaces, is to use anonymous inner classes.

Common mistake of re-using the activator as service implementation:
import org.osgi.framework.BundleActivator;
import org.osgi.service.cm.ManagesService;

public class Activator
       implements BundleActivator, ManagedService {

  // implements BundleActivator
  public void start(BundleContext bc) {

    Hashtable props = new Hashtable();
    props.put("service.pid", "myfantasticpid");

    // We can register ourselves as a ManagedService,
    // This is formally OK, but a service
    // that can get this service (as a ManagedService),
    // can also call start() and stop() using
    // reflection trickery or casting. Which hardly
    // was the intention of the bundle programmer.
    bc.registerService(ManagedService.class.getName(),
                       this, props);

  }

  // implements BundleActivator
  public void stop(BundleContext bc) {
    ...
  }

  // implements ManagedService
  // should be avoided.
  public void updated(Dictionary conf) {
    ...
  }
}
Better variant, using anonymous inner class:
public class Activator implements BundleActivator {

  public void start(BundleContext bc) {

    Hashtable props = new Hashtable();
    props.put("service.pid", "myfantasticpid");

    ManagedService mg = new ManagedService() {
      public void updated(Dictionary conf) {
        ...
      }
    };

    // BundleActivator methods now hidden
    // from outside access.
    bc.registerService(ManagedService.class.getName(),
                       mg, props);

  }
  ...
}


Spawning a startup thread
Do not hang in the Activator. Spawn a new thread if the bundle is not completely event-driven.

Nothing about threads is really specified or forbidden in the OSGi spec, so there is currently no need for any special, external thread service.

  public void start(BundleContext bc) {
    new Thread("longTaskName") {
      { start(); } // I like instance initializer blocks ;)
      public void run() {
         ...long operation
      }
    };
  }
Setting the context classloader

Many external libraries, like most JNDI lookup services requires a correctly set thread context classloader. If this is not set, ClassNotFoundException, or similar might be thrown even if you have included all necessary libs.

To fix this, simple spawn a new thread in the activator and do the work from that thread. If you use the lib in any callback methods from the framework, as ServiceListener or BundleListener you should do a similar trick inside of these listeners.

It is not recommended to set the context class loader persistently on the startup thread, since that thread might not be unique for your bundle. Effects might vary depending on OSGi vendor. If you don't spawn a new thread, you must reset the context class loader before returning.

public class Activator implements BundleActivator {
   public void start(BundleContext bc) {

     final ClassLoader classLoader =
        getClass().getClassLoader();

     Thread thread = new Thread() {
       public void run() {
         Thread.currentThread()
           .setContextClassLoader(classLoader);
         ...
         // do any work that uses the context
         // class loader, like :
         context.lookup("QueueConnectionFactory");
       }
     };

     thread.start();
   }
Thanks to Rob Evans for this example.
top

Using services

This is short introduction to service usage, to learn more about it read the service tutorial.

Track all services!

Be prepared that services might not exists, or suddenly disappear.

Use the ServiceTracker if you are interested in using a single service.

  ServiceTracker logTracker =
    new ServiceTracker(bc,
                       LogService.class.getName(),
                       null);
  logTracker.open();

  // this might throw a NullPointerException
  // if the log is not available
  (LogService)logTracker
    .getService().log(LogService.LOG_INFO,
                      "Hello log");

Track service using ServiceListener
If you really need to act on multiple service appearing and disappearing, a ServiceListener is preferred.

Act on every http service that appears and disappears.
  ...
  ServiceListener listener = new ServiceListener() {
    public void serviceChanged(ServiceEvent ev) {
     ServiceReference sr = ev.getServiceReference();

      switch(ev.getType()) {
        case ServiceEvent.REGISTERED:
          ...
          break;
        case ServiceEvent.UNREGISTERING:
          ...
         break;
      }
    }
  };

  String filter =
   "(objectclass=" + HttpService.class.getName() + ")";

  try {
    bc.addServiceListener(listener, filter);

    // get all already registered services.
    ServiceReference[] srl =
      bc.getServiceReferences(null, filter);

    for(int i = 0; srl != null && i < srl.length; i++) {
      listener.serviceChanged(
          new ServiceEvent(ServiceEvent.REGISTERED,
          srl[i]));
    }
  } catch (Exception e) {
     log.error("Failed to set up listener for http",
               e);
  }
top

Bundle data access

Access bundle data as streams
You can access bundle data using the getResourceAsStream method
// Get the bundle's manifest file using the
// bundle class loader
InputStream in =
  getClass()
   .getResourceAsStream("/META-INF/MANIFEST.MF");
..
Access bundle data as URLs
You can access bundle data using the bundle: URL syntax.
 // Get the bundle's raw manifest file using an URL
 // Syntax: (jar number represents internal jars,
 // where 0 is the top level jar)
 //  "bundle://<bundle id>:<jar number><path>"
 String s =
   "bundle://" + bc.getBundle().getBundleId() + ":0" +
   "/META-INF/MANIFEST.MF";

 URL url = new URL(s);

 InputStream in = url.openStream();

 ..
Bundles must be refreshed after an update
Bundle update does not automatically release all wired capabilities (exported packages).

This means that a bundle that has a wire from a provided capability (e.g., exported package) to another bundle requiring that capability needs to be explicitly refreshed before that capability (e.g., classes in the exported package) is released.

If you happen to have exported the package that your BundleActivator resides in, this could mean that the "old" class will be used and not the newly installed one.

Both the console and desktop provides means of calling refresh:

Console:

 > /framework refresh

Desktop:
Bundles -> Refresh bundle packages
or CTRL + R
or press the refresh link in the wiring displayer on a capability that is pending removal on refresh.

Both of these methods uses the org.osgi.wiring.FrameworkWiring API to refresh bundles:

  // refresh all bundles
  frameworkWiring.refreshBundles(null)
top

Win32 tips

Using the Java Media framework
The Java Media Framework 2.1 is tricky to install. If you fail to install properly it may still work, but start very slowly.
  1. Install all the .dlls and jars in the JRE runtime ext/ directory.
    Common installation directory:
    C:\Program Files\JavaSoft\JRE\1.3\lib\ext\
        
  2. This is not enough, copy the file jmutils.dll to the JRE runtime bin/ directory.
    Common installation directory:
    C:\Program Files\JavaSoft\JRE\1.3\bin\
        

Details on the included ant build system

Properties and elements used in bundlebuild_include.xml
Name Description
Files and directories
topdir Must be set to the top directory of build. This should be the same directory where framework.jar is located.
ant.dir Directory containing ant build files.
Default is "${topdir}/../ant"
src.dir Directory where all bundle source is located.
Default is "src"
resources.dir Directory where all bundle data is located. This directory will be copied into the root of the bundle jar file, without the directory name itself.
Default is "resources"
bundle.build.api If "true", build ${jar.api} bundle jar.
Default is "true"
bundle.build.lib If "true", build ${jar.lib} bundle jar.
Default is "false"
bundle.build.impl If "true", build ${jar.impl} bundle jar.
Default is "true"
bundle.build.all If "true", build ${jar.all} bundle jar.
Default is "true"
jar.all Location and name of jar file containing both API and implementation code
Default is ${jardir}/${ant.project.name}${all.suffix}.jar
api.all Location of jar file containing API code
impl.all Location of jar file containing implementation code
all.suffix Suffix string for the ${all.jar} output file
Default is _all-${bundle.version}
Bundle manifest attributes
bundle.name Name of bundle. Will be stored in manifest as "Bundle-Name".
Default value is ${ant.project.name}
bundle.version Version of bundle. Will be stored in manifest as "Bundle-Version".
Default value is "current"
bundle.vendor Vendor of bundle. Will be stored in manifest as "Bundle-Vendor".
Default value is "Knopflerfish"
bundle.apivendor Vendor of a bundle's API. Will be stored in manifest as "Bundle-APIVendor".
Default value is "[bundle.emptystring]"
bundle.description Description of bundle. Will be stored in manifest as "Bundle-Description"
Default value is empty
bundle.icon Optional URL to bundle icon, used by the desktop. Will be stored in manifest as "Application-Icon".
Default value is empty
bundle.classpath Bundle classpath. Will be stored in manifest as "Bundle-Classpath".
Default value is "."
bundle.docurl Bundle doc URL. Will be stored in manifest as "Bundle-DocURL".
Default value is "http://www.knopflerfish.org"
bundle.contactaddress Bundle contact address. Will be stored in manifest as "Bundle-ContactAddress".
Default value is "http://www.knopflerfish.org"
bundle.activator Class name of bundle activator. Will be stored in manifest as "Bundle-Activator".
Default value is automatically derived from bundle classes in impl code.
import.package Comma-separated list of packages. Will be stored in manifest as "Import-Package".
Default value is automatically derived from bundle classes in impl code
export.package Comma-separated list of packages. Will be stored in manifest as "Export-Package".
Default value is automatically derived from bundle classes in API code
dynamicimport.package Comma-separated list of dynamic import packages. Will be stored in manifest as "DynamicImport-Package".
Default value is empty
bundle.nativecode Comma-separated list of native code specifications. Will be stored in manifest as "Bundle-NativeCode".
Default value is empty
import.service Optional comma-separated list of service class names. Will be stored in manifest as "Import-Service".
export.service Optional comma-separated list of service class names. Will be stored in manifest as "Import-Package".
bundle.uuid Optional "Universally Unique ID" for a bundle. Will be stored in manifest as "Bundle-UUID".
Default is org.knopflerfish:${bundle.name}:${bundle.version}
bundle.symbolicname Optional ID used by the Eclipse OSGi framework. Will be stored in manifest as "Bundle-SymbolicName".
Default is ${bundle.uuid}
Note: If any of the manifest attributes above are set to the special value "[bundle.emptystring]", that attribute will not be present at all in the manifest, not even as a zero-length string.
Flow control
do.bundle.custom.pre If set, run the target bundle.custom.pre. Default is unset
do.bundle.custom.post If set, run the target bundle.custom.post. Default is unset
Build control
api.pattern Path pattern string that must match all Java packages that are part of the bundle's API (i.e., that shall be exported). Note that this pattern must not only match all packages in the source tree, but also all packages that shall be exported from the bundle class path (i.e., in nested jars).

The "API"-variant of the bundle will only contain classes that is the result of compiling those java-source files that matches this pattern from the source tree.

impl.pattern Path pattern string that must match all private (implementation specific) Java packages in the source tree that shall be included in the bundle but not exported.

The "IMPL"-variant of the bundle will contain classes that is the result of compiling those java-source files that matches any of the impl.pattern and impl-api.pattern.

impl-api.pattern Path pattern string that must match all Java packages in the source tree and on the bundle class path that shall be included in and exported from the "IMPL" variant of the the bundle but not in the "API"-variant of the bundle. Typically used when the implementation part of the bundle needs to export implementation specific Java packages that is not part of the bundles API.
all.pattern Path pattern string that must match additional private (implementation specific) Java packages in the source tree that shall be included in the all-variant of the bundle but not exported.

The "ALL"-variant of the bundle will contain classes that matches any of the api.pattern, impl.pattern, impl-api.pattern, all.pattern and all-api.pattern.

all-api.pattern Path pattern string that must match additional Java packages that shall be included in and exported from the "ALL" variant of the the bundle but not in the "API"-variant or "IMPL"-variant of the bundle. Typically used to make a self contained "ALL"-variant of the bundle that exports all Java-packages that the "IMPL"-variant needs.

The "ALL"-variant of the bundle will export classes in packages that are matched by one of api.pattern, impl-api.pattern and all-api.pattern. It will contain all classes that are matched by any of api.pattern, impl-api.pattern, impl-pattern, all-api.pattern and all.pattern.

bundle.compile.EE The bundle Execution Environment to use when compiling. The value is the id of a path that will be used as boot class path during the compilation.

Predefined values: ee.minimum, ee.foundation.
Default is unset.

bundleinfo.failOnExports If set, verify that the given Export-Package manifest header is valid. If not valid the build will fail.
Default is true.
bundleinfo.failOnImports If set, verify that the given Import-Package manifest header is valid. If not valid the build will fail.
Default is true.
bundleinfo.failOnActivator If set, verify that the given Bundle-Activator manifest header is valid. E.g., that the class is included in the bundle archive and that it implements org.osgi.framework.BundleActivator. If not valid the build will fail.
Default is true.
bundleinfo.failOnClassPath If set, verify that the given Bundle-Classpath manifest header is valid. E.g., that all files, directories in it existis inside the bundle archive. If not valid the build will fail.
Default is true.
Other elements
Path element bundle.compile.path

This path is used to make other bundles and JAR-files that the bundle depends on availble to the compiler during the compilation of the bundle.

Example - make the log API available during compilation:

 <path id = "bundle.compile.path">
   <pathelement location="log_api-N.N.N.jar"/>
 </path>

The N.N.N notation in the file name tells the build system to look for and use the highest version available in the directory tree starting at ${jars.dir}. It is possible to ask for the highest version available with a fixed major revision by writing a pathelement like log_api-2.N.N.jar.

Special pre and post target

If you need special handling of the bundle build process, you can add the special targets bundle.custom.pre or bundle.custom.post. These will be run just before and just after the standard bundle build.
Example of pre target - copying a file
<!-- set do.bundle.custom.pre to anything to trigger pre target -->
<property name="do.bundle.custom.pre" value=""/>
<target name="bundle.custom.pre">
   <copy file  = "myfile"  todir = "resources"/>
  </target>

Example of post target - a custom manifest attribute
<!-- set do.bundle.custom.post to anything to trigger post target -->
<property name="do.bundle.custom.post" value=""/>

<target name="bundle.custom.post">
  <jar jarfile  = "${impl.jar}"  update   = "true">
   <manifest>
    <attribute name = "myattribyte"       value = "myvalue"/>
   </manifest>
  </jar>
</target>

Optimizing startup time, memory or disk usage

The Knopflerfish framework can be started in either disk-optimizing or memory-optimizing modes. This is useful for systems with lower memory or small or slow disks. It also affects the startup time for the framework.

The following apply:
  1. If you need quick startup, remember that initial startup is always much slower than a restart, so a avoid deleting the fwdir bundle storage directory, if possible.
  2. Jar unpacking to disk costs time and disk space. When you have a slow write-disk (as flash mem) this is really notable.

    As a solution, memory can be used as bundle storage instead of disk. Just start with

         -Dorg.knopflerfish.framework.bundlestorage=memory
    

    This has the side-effect of not making the bundles persistent, so the 1) case does no longer apply. Also, this means that the one part of OSGi compliance is lost.

  3. Jar-files inside of bundles tend to take longer time than unpacked class files. This is related to 2) since they must be extracted from the bundle to be accessed.

    A work-around is to manually unpack a lib jar file and add it to a bundle (instead of referencing the .jar from Bundle-Classpath)

knopflerfish-osgi-5.1.0/docs/testing.html0000644000175000017500000001400712346515440017447 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - Testing

Testing Knopflerfish

Knopflerfish includes a Junit based test suite that tests the framework and bundles. Developers can use this test suite to test and verify Knopflerfish on specific target environments, e.g. some combination of processor, operating system, and JVM.

The easiest way to run the test suite is to run one of the two test suite targets from the top level ant build file located in the osgi directory. E.g.

> cd osgi
> ant run-kf-tests
  

The two test targets available are:
run-kf-tests
Builds then executes the KF test suite.
run-kf-tests-secure
Builds then executes the KF test suite with security enabled.

A developer may add new test bundles to the test suite, or defined their own stand-alone test suites. The bundle documentation for the JUnit bundle describes this in detail.

Please note that passing the Knopflerfish test suite is no claim for OSGi compliance. It is a Knopflerfish specific test suite only.

knopflerfish-osgi-5.1.0/docs/tutorials.html0000644000175000017500000001363612346515440020027 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - Tutorials

Knopflerfish OSGi Tutorials

This page contains links to tutorials and guides on how to use OSGi frameworks and the KF OSGi distribution.

OSGi tutorial v2
A Step by Step Introduction to OSGi Programming Based on the Knopflerfish OSGi Framework.

The tutorial includes examples src code located at
docs/tutorials/kf_osgi_tutorial/example_source

The OSGi Service Tutorial
The complete survival guide for handling OSGi services
Running Knopflerfish OSGi with Security
A very short tutorial to get started with OSGi security and permissions using Knopflerfish.
Running Knopflerfish on Android / Dalvik
An introduction on how to run Knopflerfish on Android / Dalvik
knopflerfish-osgi-5.1.0/docs/bundledoc/0000755000175000017500000000000012475375714017054 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/device/0000755000175000017500000000000012475375714020313 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/device/index.html0000644000175000017500000000643412346515434022307 0ustar felixfelix Bundle User Documentation - device, v4.0.1
Bundle: device
Version 4.0.1

Device Manager

The Device Manager bundle implements the OSGi Device Access Model.

Description

The Device Manager matches and attaches drivers to devices. With the help of one or more DriverLocator services it can dynamically install and start drivers on demand.

These concepts are used in the Device Manager documentation.

Device
A service that mirrors a physical device.
Idle Device
A Device that no Driver service is attached to.
Device Manager
A framework component that looks for registration and unregistration of devices and finds a driver for a device.
Driver
Is called by the Device Manager to check for matches and carry out attachment.
Driver Locator
A service that downloads suitable drivers.
Driver Selector
A service to break ties in case multiple drivers return the same (best) match value.

Device Access Model

The device access model is a part of the OSGi service platform specification. It splits responsibilities for device management into several parts. The device manager is the motor in this process and it is supplied with the framework. There must never be more than one device manager installed.

Knopflerfish includes a basic driver locator bundle, basicdriverlocator.

Bundle Jar docs

device_all-4.0.1
device_api-4.0.1
device-4.0.1

Exported Packages

PackageVersionProviders
org.osgi.service.device1.1.0device_all-4.0.1, device_api-4.0.1
knopflerfish-osgi-5.1.0/docs/bundledoc/sslj2sp/0000755000175000017500000000000012475375714020454 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/sslj2sp/index.html0000644000175000017500000001043212346515432022437 0ustar felixfelix Bundle User Documentation - sslj2sp, v4.0.0
Bundle: sslj2sp
Version 4.0.0

SSL Provider — Using the Java 2 Security Architecture.

The sslj2sp bundle registers one or several SslServerSocketFactory objects as OSGi services. These services can be used by other bundles to establish secure TCP connections. For example, to implement HTTPS, look at the documentation of your HTTP Service bundle to see if it will support the use of such services.

Java Secure Socket Extension (JSSE)

This bundle relies on the presence of Sun's Java™ Secure Socket Extensions (JSSE); more specifically, jsse.jar must be available on the system class-path. This is always the case when using Sun's Java™ Platform Standard Edition, v1.4+. To read more about this see the JSSE Reference Guide for Java Platform Standard Edition 1.4 or 7.

To create your customized SSL certificate, see section "Creating a Keystore to Use with JSSE". NOTE: This material is owned by Sun Microsystems, please refer to their terms and conditions. You can use the Configuration Manager to tell the sslj2sp bundle what SslServerSocketFactory service(s) to create, see section Configuration Manager. If nothing is specified, a default configuration will be used.

Configuration

The sslj2sp bundle may be configured using the OSGi Configuration Manager (CM). It accepts factory configurations with the factory PID
  org.knopflerfish.bundle.ssl.j2sp
If no configuration is available in CM, a default configuration with values equals to the defaults described below will be used.

Properties with a name [none] can not be configured in the current implementation.

Name Description Value type Default value
[none] SSL protocol to use. String TLSv1
[none] Keystore type String JKS
keystore This property represents a keystore, which must be created as described in section "JSSE". The sslj2sp will interpret the value for this property as follows:
  • assume that the keystore has been stored to the CM as an array of bytes (byte[]).
  • assume that the value is the name of the keystore file on the local file system.
If none of these assumptions lead to a valid key manager, the bundle will log a warning and use the default.
String or byte[] [internal]
keystorepass The password for the store (plain text). String [internal]
[none] Keymanager type. String SunX509

Bundle Jar docs

sslj2sp-4.0.0

Exported Packages

No exported packages.
knopflerfish-osgi-5.1.0/docs/bundledoc/xalan/0000755000175000017500000000000012475375714020157 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/xalan/index.html0000644000175000017500000000567112346515432022153 0ustar felixfelix Bundle User Documentation - xalan, v2.7.1.kf3_01
Bundle: xalan
Version 2.7.1.kf3_01

Xalan XML transfomer

Bundle version of the Xalan XML transformer

Xalan XML transformer bundle

This is a bundlified version of Xalan-Java.

It will register itself as an OSGi service using the OSGi XML util bundle.

See also

OSGi XML util bundle
Xerces XML Parser bundle

Bundle Jar docs

xalan-2.7.1.kf3_01

Exported Packages

PackageVersionProviders
javax.xml.transform1.3.0.selectFirstxalan-2.7.1.kf3_01
javax.xml.transform.dom1.3.0.selectFirstxalan-2.7.1.kf3_01
javax.xml.transform.sax1.3.0.selectFirstxalan-2.7.1.kf3_01
javax.xml.transform.stream1.3.0.selectFirstxalan-2.7.1.kf3_01
org.apache.xalan0.0.0xalan-2.7.1.kf3_01
org.apache.xalan.processor0.0.0xalan-2.7.1.kf3_01
org.apache.xpath.jaxp0.0.0xalan-2.7.1.kf3_01
knopflerfish-osgi-5.1.0/docs/bundledoc/xerces/0000755000175000017500000000000012475375714020345 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/xerces/index.html0000644000175000017500000002541512346515432022337 0ustar felixfelix Bundle User Documentation - xerces, v2.10.1.kf5
Bundle: xerces
Version 2.10.1.kf5

Xerces XML parses

Bundle version of the Xerces XML parser

Xerces XML parser bundle

This is a bundlified version of Xerces2-Java XML parser.

It will register itself as an OSGi service using the OSGi XML util bundle.

See also

OSGi XML util bundle
Xalan XML Transformer bundle

Bundle Jar docs

xerces-2.10.1.kf5

Exported Packages

PackageVersionProviders
javax.xml1.3.0xerces-2.10.1.kf5
javax.xml.datatype1.3.0xerces-2.10.1.kf5
javax.xml.namespace1.3.0xerces-2.10.1.kf5
javax.xml.parsers1.3.0xerces-2.10.1.kf5
javax.xml.transform1.3.0xerces-2.10.1.kf5
javax.xml.transform.dom1.3.0xerces-2.10.1.kf5
javax.xml.transform.sax1.3.0xerces-2.10.1.kf5
javax.xml.transform.stream1.3.0xerces-2.10.1.kf5
javax.xml.validation1.3.0xerces-2.10.1.kf5
javax.xml.xpath1.3.0xerces-2.10.1.kf5
org.apache.html.dom0.0.0xerces-2.10.1.kf5
org.apache.wml0.0.0xerces-2.10.1.kf5
org.apache.wml.dom0.0.0xerces-2.10.1.kf5
org.apache.xerces.dom0.0.0xerces-2.10.1.kf5
org.apache.xerces.dom.events0.0.0xerces-2.10.1.kf5
org.apache.xerces.dom3.as0.0.0xerces-2.10.1.kf5
org.apache.xerces.jaxp0.0.0xerces-2.10.1.kf5
org.apache.xerces.jaxp.datatype0.0.0xerces-2.10.1.kf5
org.apache.xerces.jaxp.validation0.0.0xerces-2.10.1.kf5
org.apache.xerces.parsers0.0.0xerces-2.10.1.kf5
org.apache.xerces.util0.0.0xerces-2.10.1.kf5
org.apache.xerces.xinclude0.0.0xerces-2.10.1.kf5
org.apache.xerces.xni0.0.0xerces-2.10.1.kf5
org.apache.xerces.xni.grammars0.0.0xerces-2.10.1.kf5
org.apache.xerces.xni.parser0.0.0xerces-2.10.1.kf5
org.apache.xerces.xpointer0.0.0xerces-2.10.1.kf5
org.apache.xerces.xs0.0.0xerces-2.10.1.kf5
org.apache.xerces.xs.datatypes0.0.0xerces-2.10.1.kf5
org.apache.xml.resolver1.2.0xerces-2.10.1.kf5
org.apache.xml.resolver.apps1.2.0xerces-2.10.1.kf5
org.apache.xml.resolver.helpers1.2.0xerces-2.10.1.kf5
org.apache.xml.resolver.readers1.2.0xerces-2.10.1.kf5
org.apache.xml.resolver.tools1.2.0xerces-2.10.1.kf5
org.apache.xml.serialize0.0.0xerces-2.10.1.kf5
org.apache.xml.serializer1.0.0xerces-2.10.1.kf5
org.osgi.util.xml1.0.1xerces-2.10.1.kf5
org.w3c.dom3.0.0xerces-2.10.1.kf5
org.w3c.dom.bootstrap3.0.0xerces-2.10.1.kf5
org.w3c.dom.css3.0.0xerces-2.10.1.kf5
org.w3c.dom.events3.0.0xerces-2.10.1.kf5
org.w3c.dom.html3.0.0xerces-2.10.1.kf5
org.w3c.dom.ls3.0.0xerces-2.10.1.kf5
org.w3c.dom.ranges3.0.0xerces-2.10.1.kf5
org.w3c.dom.stylesheets3.0.0xerces-2.10.1.kf5
org.w3c.dom.traversal3.0.0xerces-2.10.1.kf5
org.w3c.dom.views3.0.0xerces-2.10.1.kf5
org.w3c.dom.xpath3.0.0xerces-2.10.1.kf5
org.xml.sax2.0.2xerces-2.10.1.kf5
org.xml.sax.ext2.0.2xerces-2.10.1.kf5
org.xml.sax.helpers2.0.2xerces-2.10.1.kf5
knopflerfish-osgi-5.1.0/docs/bundledoc/junit/0000755000175000017500000000000012475375714020205 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/junit/index.html0000644000175000017500000002132412346515436022176 0ustar felixfelix Bundle User Documentation - junit, v3.8.1.kf4-001
Bundle: junit
Version 3.8.1.kf4-001

JUnit on OSGI

Bundles to support JUnit testing on a running framework.

There are three bundles involved:

junit
bundle exporting the junit.framework.* classes as well as allowing remote connection to test suites in a running framework via http. This bundle also exports a JUnitService to allow other bundles in the framework access to bundles.
junit_runner
a bundle which automatically finds and runs bundles in a framework. This bundle does not require any http connection, just the junit bundle. See junit_runner/readme.txt for more info.
examples
some small test cases using junit

Requirements:

The junit bundle does not require any other bundles (as of revision 737) but can use the HTTP server and the KF console to make test access easier.
  • - optionally http server (used dynically by the server part)
  • - optionally KF console (used dynamically by the server part)
  • - XML parser (used by the client part)

Background

JUnit allows developers to write unit tests by writing classes implementing junit.framework.Test, e.g TestCase, TestSuite etc.

A typical test looks like

 class MyTest extends junit.framework.TestCase {
   public void runTest() {
     ... do some work
     assertTrue(someflag)
   }
 }
As long as these test do not depend on a running framework, they are easy to run using normal tools, but when they depend on the framework, the standard test running tools become insufficient.

Thus, the junit bundle allows remote access to test cases running on a framework, from any normal test tool running on a developer machine.

How it works

  1. Bundle developers write tests for a bundle B just as any other JUnit tests. The tests simply extends TestCase or TestSuite.
  2. The bundle developer register these tests as-is into the OSGi framework, with a service.pid property giving the name of the test. This should normally be the same name as the test. Typically all tests from a bundle is grouped into a TestSuite.

    Example: register a test suite into the framework.

          TestSuite suite = new TestSuite("example1");
    
          suite.addTest(new MyTest());
          Hashtable props = new Hashtable();
          props.put("service.pid", suite.getName());
        
          bc.registerService(Test.class.getName(), suite, props);
    
  3. The junit bundle, when started, registers a servlet in the OSGi web server, if the web server exists. This servlet then allows remote running of the registered test cases. The servlet is available at
          http://:/junit?id=
    
    where == value of the service.pid property exported in 2)

    The only interface that registered tests need to implement is junit.framework.Test

    The junit bundle thus accesses the tests via BundleContext.getService() and needs ServicePermission, if FW security is active.

    Note how *only* step 2) is extra work compared to writing standard JUnit tests.

  4. When actual testing is desired, a single client test class is used on the development machine (which doesn't need to run the framework!)

    The client class name is:

         org.knopflerfish.service.junit.client.JUnitClient
    
    The target host and test id is passed to the client as a system property "suite.url"

    This client test class extends TestSuite and act as a proxy to the actual test, and can thus be passed to any test runner, as

    junit.swingui.TestRunner or junit.textui.TestRunner

    as well as Ant's "junit" task.

    Example: Using the Swing TestRunner

        > java "-Dsuite.url=http://localhost:8080/junit?id=example1" \
           junit.swingui.TestRunner \
           org.knopflerfish.service.junit.client.JUnitClient
    
    This will run the test with id "example1" on localhost:8080

    Note that the class path must be set fo find both junit.jar and the junit_all-1.0.0.jar bundle.

  5. Testing can also be done without using the servlet. The easiest approach is then to use the junit_runner bundle, and provide it with a list of test IDs to run. XML formatted results will then be written to file.
  6. If you are using the KF console, the junit bundle registers a set of commands to list and run test cases.
        > enter junit
        junit> help
        Available junit commands:
         list [-help]  - List available tests
         run [-help] [-out #file#]  - Run a test and dump XML results 
                                          to a file or console.
    
Note1:

The servlet is also capable of exporting the test results as plain HTML. In this case, the client proxy isn't needed. Just point your browser at

   http://:/junit
and you'll get a list of available tests. From this list you can select suites and individual tests to run. The result will be presented as HTML. Note2:
The junit_runner/resource directory contains som XSLT style sheets which may be useful for formatting XML test results to HTML.

Monitoring test case execution

JUnit TestListeners may be used to monitor test case execution.

The junit-bundle will look up all services registered under the class junit.framework.TestListener in the running framework and add them to the TestResult as listeners.

Example: register a test listener into the framework.

      TestListener listener = new MyTestListener();

      bc.registerService(TestListener.class.getName(), listener, null);

JUnit support in bundlebuild.xml

As a convenience, the ant/bundlebuild.xml script contains support for using the JUnit client.

Example: run the swing Test runner from Ant

   > ant -Dtest.id=example1 junit_ext
Example: run Ant's junit task
   > ant -Dtest.id=example1 junit_ant
Tip: Bundles can be installed using the telnet console. The telnet console is installed by the default init.xargs. In this case a bundle can be installed and started by
   > ant install start
The following Ant properties are set as default in bundlebuild.xml:
  http.host              localhost
  http.port              8080
  junit.runner.class     junit.swingui.TestRunner
  junit.formatter        plain
  junit.outfile          junit

Known issues

  • TestSuites are "flattened" by the client proxy, so the tree structure in the Swing runner might look a bit different compared from tests run locally.
  • Proxied tests cannot (yet) be individually re-run. The entire client proxy must be re-run

Bundle Jar docs

junit_all-3.8.1.kf4-001

Exported Packages

PackageVersionProviders
junit.framework3.8.1junit_all-3.8.1.kf4-001
org.knopflerfish.service.junit1.0.0junit_all-3.8.1.kf4-001
knopflerfish-osgi-5.1.0/docs/bundledoc/prefs/0000755000175000017500000000000012475375714020173 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/prefs/index.html0000644000175000017500000000505512346515434022165 0ustar felixfelix Bundle User Documentation - prefs, v4.0.2
Bundle: prefs
Version 4.0.2

Preferences

The prefs bundle implements the OSGi Preferences service that provides easy to use persistent storage of bundle data.

Description

With Preferences, bundles can store data persistently. Data is stored as named values in a tree structure where each node can have any number of key-value pairs. For example, Preferences can be used by a bundle to store application and user settings. A bundle typically uses a number of preferences tree roots, one for system settings and one for each user's settings.

This component implements the OSGi Preferences service.

Note that preferences are tied to a bundle. The OSGi service provides no way for a bundle to access the preferences of another bundle. Once fetched though, it is possible for one bundle to share its preferences with other bundles.

Bundle Jar docs

prefs_all-4.0.2
prefs_api-4.0.2

Exported Packages

PackageVersionProviders
org.osgi.service.prefs1.1.1prefs_all-4.0.2, prefs_api-4.0.2
knopflerfish-osgi-5.1.0/docs/bundledoc/scrcommands/0000755000175000017500000000000012475375714021365 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/scrcommands/index.html0000644000175000017500000001160212346515434023352 0ustar felixfelix Bundle User Documentation - scrcommands, v4.0.1
Bundle: scrcommands
Version 4.0.1

ScrCommands

Service Component Runtime (SCR) console commands to view dynamic and static state of components and enable or disable them.

Description

The scrcommands bundle publishes one command group called scr.

This command group currently works with SCR that provides the org.apache.felix.scr.ScrService service.

Scr - Scr Commands

The group contains the following commands:

  • disable [-help] <component> ...
  • enable [-help] <component> ...
  • list [-help] [-i] [-l] [-n] [-r] [<bundle>] ...
  • show [-help] [-b] [-f] [-n] [-r] [<component>] ...

disable

The disable command is used to disable selected component(s).

  disable [-help] <component> ...

Parameters:

-help
Display command help text.
<component>
Name or id of component.

enable

The enable command is used to enable selected component(s).

  enable [-help] <component> ...

Parameters:

-help
Display command help text.
<component>
Name or id of component.

list

The list command is used to list information about components for selected bundles. Components are shown in bundle id order if no order parameter is given.

  list [-help] [-i] [-l] [-n] [-r] [<bundle>] ...

Parameters:

-help
Display command help text.
-i
List components in ID order.
-l
Show long version of information, that includes information about properties, services provided and referenced.
-n
List components in name order",
-r
List components in reverse order",
<bundle>
Name or id of bundle. If no value is given or a "*", list entries from all bundles.

show

The show command is used to show information about components. Components are shown in component id order if no order parameter is given. With the -f parameter will show more information than the list command, it will show some, static information about the component.

  show [-help] [-b] [-f] [-n] [-r] [<component>] ...

Parameters:

-help
Display command help text.
-b
List components in bundle ID order.
-f
Show full version of information, that includes static information about the component.
-n
List components in name order",
-r
List components in reverse order",
<component>
Name or id of component. If no value is given, show all components registered.

Examples

List all components for all bundles.

scr> list
ID State        BID Name
 0 ACTIVE        19 scrCommandGroup
 1 REGISTERED    25 componentE_test.E1
 2 FACTORY       25 componentE_test.E2

Show full inforamtion about scrCommandGroup component.

scr> show -f scrCommandGroup
ID State        BID Name
 0 ACTIVE        19 scrCommandGroup
   > Service: org.knopflerfish.service.console.CommandGroup
   > Satisfied reference:   org.apache.felix.scr.ScrService [1..1], static bind
   > Property groupName = scr
   > Delayed component, default enabled, config policy = optional

See Also

Console

Bundle Jar docs

scrcommands-4.0.1

Exported Packages

No exported packages.
knopflerfish-osgi-5.1.0/docs/bundledoc/dirdeployer/0000755000175000017500000000000012475375714021376 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/dirdeployer/dirdeployer.xml0000644000175000017500000000173012346515440024430 0ustar felixfelix ./load org.knopflerfish.fileinstall true 1000 false 8 knopflerfish-osgi-5.1.0/docs/bundledoc/dirdeployer/index.html0000644000175000017500000002033112346515440023357 0ustar felixfelix Bundle User Documentation - dirdeployer, v4.0.1
Bundle: dirdeployer
Version 4.0.1

Directory Deployer

A bundle which scans file system directories for files that it can install, update or uninstall. The directory deployer bundle handles both bundle files and configuration files. When a file is updated the bundle / configuration will be updated and when a file is removed from the scanned directory the bundle / configuration will be removed.

This is a quite useful tool for handle bundle and configuration deployment without using any console. Just copy the file that should be installed to the deploy directory, and the directory deployer will find and activate them. When the files are removed, they are uninstalled.

Deploy method

The procedure for scanning and deploying is as follows:

  1. Check if any new files have appeared or if any already deployed files has been replaced with newer files.
  2. New files are installed into the framework.
    At the end of the scan any bundle that was installed will be started according to its activation policy. Any fragment that was installed will be attached to its host (be resolving it).
  3. Updated files (newer than a previously deployed bundle) are not installed again, instead, the installed bundle or configuration is updated from the new file.
  4. Check if there are bundles or configurations installed by the directory deployer that does not correspond to a file found during the directory scan. If any such bundle or configuration is found uninstall it.
  5. If any bundle update was performed during the scan, perform a refresh bundles operation for them using the in the framework wiring API.
  6. Start newly installed bundles that can be started, resolve newly installed fragments. Note that there will only be one start / resolve attempt made for each bundle after an install or update.
  7. Sleep a while
  8. Repeat from 1.

Deployable File Types

The Directory Deployer supports deploying of bundles and configurations:
  • *.jar Bundle jar files.
  • *.xml OSGi CM configurations stored in XML-files using the DTD cm_data.dtd.

A sample XML-file with a configuration for the Directory Deployer bundle itself can be downloaded here.

To create a CM configuration from scratch one may use the CM-tab in Knopflerfish desktop, it presents a simple GUI based on configuration meta type descriptions provided by configurable bundles. The CM-tab is not visible in the Desktop when starting with the default set of bundles, to activate it one must install and start three more bundles from the Knopflerfish distribution: metatype (OSGi Metatyp APIs), kf_metatype_all (Knopflerfish Metatyp Service implementation) and cm_desktop (the CM-tab desktop plug in itself).

To save an existing CM configuration as cm_data XML one may use the CM-tab in the Knopflerfish desktop, it provides an Export... button that will export the current configuration as a cm_data XML file. It is also possible to use the Knopflerfish console command configuration export. See CM Commands for details. Avoid writing cm_data XML files by hand since the parser for the cm_data XML documents is written for machine generated documents so it does not give usable error messages when something in the XML-document is wrong.

Configuration

See metatype.xml for specification using CM. The same properties as defined by CM are also read as default values from framework properties. Thus, the bundle can be both configured by CM and using system properties.

You can set the deployment directory in metatype.xml in the bundle's resource directory (defaults to ./load). A relative deployment directory path is relative to the directory from which the framework is started.

The table below describes the framework properties that may be used to set the default values for the directory deployer configuration.
Name Description Type Default
org.knopflerfish.fileinstall.dir Set the directories that should be scanned.

The value should be a comma-separated list of directory paths.

String ./load
org.knopflerfish.fileinstall.poll Poll interval in milliseconds between directory scans. Must be at least 100 ms. long 1000
org.knopflerfish.fileinstall.use.initial.startlevel

When this property is true the Directory Deployer will not set any start level for bundles it installs thus those bundles will belong to the default start level (i.e., the current initial start level according to the Framework Start Level API).

When this property is false the Directory Deployer will assign the start level given by org.knopflerfish.fileinstall.startlevel to the bundles it installs.

boolean true
org.knopflerfish.fileinstall.startlevel Bundle start level to assign to all newly installed bundles. Note that you must set org.knopflerfish.fileinstall.startlevel to false for this property to have an effect. int The initial bundle start level as returned by the StartLevel-API.
org.knopflerfish.fileinstall.uninstallOnStop If true then the directory deployer will uninstall all bundles and configurations that it has installed when it stops. boolean true

Bundle Jar docs

dirdeployer_all-4.0.1
dirdeployer_api-4.0.1

Exported Packages

PackageVersionProviders
org.knopflerfish.service.dirdeployer0.0.0dirdeployer_all-4.0.1, dirdeployer_api-4.0.1
org.knopflerfish.shared.cm1.1.0dirdeployer_all-4.0.1
knopflerfish-osgi-5.1.0/docs/bundledoc/repositorycommands/0000755000175000017500000000000012475375714023015 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/repositorycommands/index.html0000644000175000017500000001550012346515436025005 0ustar felixfelix Bundle User Documentation - repositorycommands, v1.1.1
Bundle: repositorycommands
Version 1.1.1

Repository Commands

The Knopflerfish repository manager console bundle

Description

The Repository commands bundle includes a set of commands through which the Knopflerfish Repository Manager can be controlled. This includes bundle search and install, repository management (add, remove, ordering, enable and disable).

Repository Command Group

Available repository commands:
  add [-help] [-r #rank#] <url> - Add a XML based repository.
  bundle [-help] [-l] [<symbolicname> [<versionRange>]] - List bundle resources.
  disable [-help] <repository> ... - Disable selected repository.
  enable [-help] <repository> ... - Enable selected repository.
  install [-help] [-s] <symbolicname> [<versionRange>] - Install bundle resource.
  list [-help] [-l] [<repository>] - List repositories.
  rank [-help] <rank> <repository> ... - Change repository ranking.
  show [-help] [-t] <namespace> [<filter>] - Show all capabilities and requirements for selected resources.

add

Add a XML based repository.

add [-help] [-r #rank#] <url>

Parameters:

-help
Display command help text.
-r #rank#
Set rank explicitly.
<url>
URL for repository file.

bundle

List bundle resources. List all bundles that matches <symbolicname> and <versionRange>. Mark with a '*' in the first column if a bundle is installed.

bundle [-help] [-l] [<symbolicname> [<versionRange>]]

Parameters:

-help
Display command help text.
-l
Verbose output.
<symbolicname>
Bundle symbolic name to match.
<versionRange>
Optional bundle version range.

disable

Disable selected repository. Disables a repository so that it won't be used when searching for resources.

disable [-help] <repository> ...

Parameters:

-help
Display command help text.
<repository>
Wildcard name or id of repository.

enable

Enable selected repository. Enables a repository so that it will be used when searching for resources.

enable [-help] <repository> ...

Parameters:

-help
Display command help text.
<repository>
Wildcard name or id of repository.

install

Install bundle resource. Installs first bundle resource that matches <symbolicname> and optional <versionRange>.

install [-help] [-s] [<symbolicname< [<versionRange<]]

Parameters:

-help
Display command help text.
-s
Persistently start bundle according to activation policy.
<symbolicname>
Bundle symbolic name to match.
<versionRange>
Optional bundle version range.

list

List repositories. Mark with a '*' in the first column if a repository is enabled.

list [-help] [-l] <repository>

Parameters:

-help
Display command help text.
-l
Verbose output.
<repository>
Wildcard name or id of repository.

rank

Change repository ranking. The rank is used to can change the order in which repositories are searched. Repository with highest ranking is searched first.

rank [-help] <rank> <repository> ...

Parameters:

-help
Display command help text.
<rank>
New rank of repository, must be an integer.
<repository>
Wildcard name or id of repository.

show

Show all capabilities and requirements for selected resources.

show [-help] [-t] <namespace< [<filter<]

Parameters:

-help
Display command help text.
-t
Terse output, only show namespace attribute.
<namespace>
Which namespace to search.
<filter>
OSGi filter expression for selecting resources.

Examples

List all repository available.

repository> list
E  Id Rank  Description
------------------------
*  15    0  XML repository from URL: file:jars/index.xml

List bundles with a symbolic name starting with "org.knopflerfish.bundle.repository" that are available from the repository.

repository> b org.knopflerfish.bundle.repository*
I Bundle resource
- --------------------
  org.knopflerfish.bundle.repository.index, version=1.0.0
* org.knopflerfish.bundle.repository-API, version=1.0.0
* org.knopflerfish.bundle.repository_desktop, version=1.0.0
* org.knopflerfish.bundle.repository.xml, version=1.0.0
  org.knopflerfish.bundle.repository.xml-API, version=1.0.0
* org.knopflerfish.bundle.repositorycommands-IMPL, version=1.0.0
* org.knopflerfish.bundle.repositorymanager, version=1.0.0
  org.knopflerfish.bundle.repositorymanager-API, version=1.0.0

See Also

Console

Bundle Jar docs

repositorycommands-1.1.1

Exported Packages

No exported packages.
knopflerfish-osgi-5.1.0/docs/bundledoc/trayicon_fw/0000755000175000017500000000000012475375714021400 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/trayicon_fw/index.html0000644000175000017500000000331612346515436023372 0ustar felixfelix Bundle User Documentation - trayicon_fw, v4.0.0
Bundle: trayicon_fw
Version 4.0.0

Framework tray icon.

A simple trayicon supporting start level change and framework shutdown.

Description

This bundle adds an icon representing the framework to the system tray for a desktop. See the Java-doc for java.awt.SystemTray for the definition of what the system tray is on different window systems. The standard java.awt.SystemTray and java.awt.TrayIcon classes was added in Java™ 6 thus this bundle will only be fully functional on Java™ 6 and later.

The Tray Icon offers two operations:

  • Change start level.
  • Stop the framework.

Bundle Jar docs

trayicon_fw-4.0.0

Exported Packages

No exported packages.
knopflerfish-osgi-5.1.0/docs/bundledoc/log/0000755000175000017500000000000012475375714017635 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/log/index.html0000644000175000017500000001100012346515430021606 0ustar felixfelix Bundle User Documentation - log, v5.0.0
Bundle: log
Version 5.0.0

Log

OSGi Log service implementation.

Description

This bundle provides a log-service and a log-reader-service according to the OSGi Compendium specification. It also exports a managed service implementing both org.osgi.service.cm.ManagedService and org.knopflerfish.service.log.LogConfig to allow for configuration of the log service.

Console commands for interacting with the log service are provided by the bundle logcommands.

Configuration properties

Name Description Value type Default value
org.knopflerfish.log.out Print new log entries on System.out when set to "true". boolean false
org.knopflerfish.log.grabio If true grab all text printed on System.out and System.err and add it to the log. boolean false
org.knopflerfish.log.level The default log level. All log records that are of lesser severity than this level will be skipped when writing to the log file and not keept in memory. Case insensitive String, one of "INFO", "DEBUG", "WARNING", "ERROR", "DEFAULT". INFO
org.knopflerfish.log.file If true write log entries to file. Only entires with the severity given by org.knopflerfish.log.level or higher are written. boolean false
org.knopflerfish.log.file.dir The path to the directory to write the cyclic file log to. If empty or not given the data directory of the log-bundles will be used. String
org.knopflerfish.log.memory.size Number of log records to keep in memeory. Integer 250
org.knopflerfish.log.timestamp.pattern The pattern to use when formatting the timestamp of a log entry. The value of this property must follow the rules of a pattern as defined by the class java.text.SimpleDateFormat. String yyyyMMdd HH:mm:ss

See Also

Logcommands

Bundle Jar docs

log_all-5.0.0
log_api-5.0.0
log-5.0.0

Exported Packages

PackageVersionProviders
org.knopflerfish.service.log1.2.0log_all-5.0.0, log_api-5.0.0
org.osgi.service.log1.3.0log_all-5.0.0, log_api-5.0.0
knopflerfish-osgi-5.1.0/docs/bundledoc/cm_desktop/0000755000175000017500000000000012475375714021204 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/cm_desktop/images/0000755000175000017500000000000012475375714022451 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/cm_desktop/images/cm_desktop.png0000644000175000017500000016650412346515436025315 0ustar felixfelixPNG  IHDR"2 AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATxO^IH((ǥh8BR;bEC(#$Dffw$|>{Μ9ٳ3{M>&L´ivK;ɕI6j(3.<+P>,B1BV 9Y2q"Wype)/1O|qC7/''+\ 9Y\bb1o)XrKY8yRxy•UU\i*+)/1O|qC7/''+\ 9Y\bb1o)XrKY8yRxy•UU\iJ~<\UUuO˖-o+N4ɓ'o@SHƍ|X \Ȏ sǺIq78ħ|1dM~J%_q'Wy㇤~61r|q{2ǐ-=$7.|Q8,E 8]8Ib)N|Hta4Y'yr0~HzW~HmS,54>qXq1ig~XtïKicYq"W?.OP"ta4*Sz(7MJ#^)eroƍ)C~5-aOn(.մI8?}* *!Wp!ׄf |)?aHa\SG|!CedI&uMeJgi S:JgqnV!WKXn`L~(Keˏeq)>~˯/(LtJK/p,>)c~\醛Gq "GŮʄWr~”',H+5}D܄UCҕOrO>CU^?!p k+.nʋK<.dOmx!W` ;F(_o7ţx\_~9@."C 1p}6hȐhD> [ǎ 8~ԁ%S ">%Wno%l嗳N:t"?z  9*S% -` Hf,x՟x\qy'VXe( IOETX M"˓,ɁO:]|../R ?Pq…tII#NūxUK:$d\)_)(ɐsǏ *!4:9Jfdb(6¶e7[_oeAJv؏gӉצMk[S,&&MYGe< ."mXky]L[CɏKSuK|~ &>ÏL:SCraHOnuZtE'nZ8=W:y#?|qWypX7W^x&W}R<<\YqUxɋ7toO©!f_M="[ـW;#}n/~i>7>Y׶"_?{ӯ~^~KhSؘ9Mh|8>LɏW~W=/uU~Y[V^sm[|6et6b0?ZjiUM['jZ6ݻ!. /Yޢ={yq֤7}+I'ּY<(Y ¯]i\҅GW,&" caDӥm:?cWcT[ul5N({/3q_V\rKr"Cq^J!x#/q~WU( mFa*ACmZuf6ǟEf,Y)&M8)t$<\d#ok\\\xJ@9diR Nzx#Gd#\dU'^SO:em?%J_SisIʐA%/$.N~Sax ?r Ҹg qp! GECi߆iibKyiSp>5y5ԫMiӳݗEOɃ߰&4eL%uM W\oa&\ă4x\~ PA`v`pFX1v`GƦ*x s4񫿪+-ĩ $ >/&n4Q,ndKҨ1cm[UuӚ-KSEhzP9:vlÆ| U*\yOGȟ"=t'2C6e,҄#~W8?&’ 0|:Ӏ_u'Cʯ0d\dxLK<|ïrC \1ΒI>U%8) 0!? ^Qͫ?q nZۈ2۟qv^pYR6=gޟ8~K0?.QIC0}I}#9Egs+t:qunZlamZH[X͒X5:eJb@$0S/Iul EB56jZ~@SpA^+|_4 Sp]d`d)dRt@u#AF9%]$CeÕW:ƏlՑsKrHQ#qS2D䇔7KArU_G8M҇r#|4xUߐ,c"=G2+xoߦ5 681AfJ?Ym׵5?iO2жZن'`='.i?zqN>} MK/H,P'm$k415-[&5+_c0A&7ɿj]t rM 4O(!2E\9 pM<7h2)r!dt" ^2E&e03i2s!Y\"Wyt.&& >GXWjd\O>'BxIӍt⠴_p<\҇8UOE~)LyIbUq= #mI|Ey-kS'}ة`b`^iƽ w>`qFHgǕ!$}V](1ш؈-$nڤ~8t뒻q&%]J׷{&nDr-޵s(G'Bq Fd ļ ~яt.HQy/?qz, ^t啎.ҍ<ȗ\#qWN GH'q~遜X%<ȣM0P. 7ΏLolj$޶Oߴ M[|3ɶs c&l#S}Kc)IgE+^n, ^7 }51>kO7C~E?_ƿM}Qj:,@t0j߾ i;޺td͒0[&گ'}n- . H:d rРyG$o70krF?u|۴ne#|2~I NCXqLDC*8UAEqtO,8 *'_ߘU>҃0Uۑ&~Rڕ|dIqxE8ƈ0\V G9ȉTy W?KX/[|j~1źwh -cw~̾izf*ִ6lHWgW[7?U{wP[cͅsO꿊SS%8x/A I¸ q)\q \'^O(M|n,8xŇ_<cq8JΪQex*NzW۟s7xAV+7ū|qlS~Zeʂksi b-rK-a $ hF!/U^;Ȋu"r) ƌ`~MVWec۷562%W ~"H'*WE> _tP>Td_rz< ?z#> 9COeU&<j鈋Me)U}" & WL~$C8O>oL&Œ85EzObWB }w"{[Io|e[o9<ƌj?Ѯz 6nE7#xu?"^/y|s_ wK$P17-& jCOeXuZu_L Ĝ &$ď|*7='Gz' zdap۶mkSMI^mg[ׅiRA RetִipTH<q!=U~)xOQq~.ʋ,tnU~Q6D~.:!<)>\xȕN"* ^t1zGy3.r!G ]Ny K՟4oa8#kץuj9F٪[Y֍mFW6|6jkަ}x-98)O.۠o}E>Eť/7Hţ|JG~I%GqūJl\>k:_}J~uo" AhժU-me˖!t9??qbbRg;&6͛F~;vl,tKa@>[ynƍ y%K&uraqȤ,H/x '8O=UQç2)K~.T!Y0rȀ_qOIK:~E7Eq]alUOx#Pɏ'%YQQK-oTD>;}o6qRM~oO')5%7wn8! L0Nt aKy !nKwNdʕ> \=#D~qUsG*M +"!\TO#/~Q7A"L<#mui,d.2 KHqȢOAԕtSz{{D>˜%p}-g?`A?Џwn(,&L)u%0K ɐ¯U'A'.rѓ 4\ɫ1K>"̅ҝ|?F \%a8.(Ȁp)87Ã<%4',9+}'6TgS%xd" ?\+&d+\ʂum 4iO\oƴۿ919qBPs+4?k.>ۚ4)ʑ|’#!瞟NGA@zd#CYyP9t'^r׊ @\HA.SDQ&NQ2Џ|ȁ:W:.D<8NBG\ʒ<ax!/.yLɐ!՗Z Fj_o8k =Oi '>>|͢*00VKp/wu\L<1tOUd/q8d@ˁ$D5&qqCCi$, /ª. ãAqECoI'Wđ&/=Txq'p_*q(OyUHtBD >W% ^#=>F92?#8#8@ GpGpG B :#8#FxxpGpG B`E_~eHӧ=c6y޳W_}>o%|Qர rՊx'sζ+b;l׶E]xܿb=8҈e],G俫:te]z/Kx^xgZVYe[-&8#8#0!Px CM"K[=l212O;4[kr0^ziț6;8kHG1Z16|\y[ sҷn;>21[o*'':'/ ooqȏ!8#8܊@o=裶kw>ok9ӭ[7{⨊>으/[oW\=7d;3;`7|sQco?ҥK\GpGk(osuY6tP jއ~YUF׾⋢բ| 1Fa-bk+c;'pBH'|UWtIh_,pGp"[Y|ꩧ2enmy3<3͛7̛4h瞶2ءj:uJ jǖ"V ^q"1_Xرc.!ھSO_~9wsnS^ /Ȱu:X˖v%pGp4wuWZ")"c/؊f5?xq [[lmF1{u\kxn /dfȈ` Š]4+Vy; b?ŘLt;-2֬ "=IЪj*>VY;a}駓T,d)N#8#C`&c1+[?.B;ꨣlϭe׶m4l O:.+_|-o&n%kŠ /،30!b#pGp Jz_~6~x-aVlːE~aVqsK0|_oMB/Rcw^h\o!CtV*4=# Ñ?X"+_8#8@1J2!DZjɞ8qbXAlB<۬K.d[n +ml>K=_a󹝫zƷ [ha+R8w!/ [~cLʊpGprh# ޘ|)GH)'Oj2J77L6x- b\ &/qtU'<#8#sm’,VMoVBVC+l"^^URV%q#8#0!P6Wu#8#8@1X,;#8#0#|^uGpGp!b1<pGp7;#8#P 7!鎀#8#87WpGpbX !OwGpG`>F`}{>xUp3f?gYa.pGpZ4i]ve9sic >ڶmk -P ?VvGp: ?ہu!d۴ic]vm#8#Ѐ_O>=~f7l!ƍg:t(i#8#BrcɓZBn@*#8#0`Erc/N#8#S+b\'x"lԨQ\vegϞlzmVv%zg28q6bou9\1]Pm}:C#8#0/ /G}dM6֣GkٲLUc\*h,"lM638#aobVAo}ٹ$xO8ᄰ*.S0uUFKqGpwy0mʔ)[oE.u1_X ۷=SqTA`+d,Rٺuk{gSNxb62}u1uGp]wݙ:mڴQ7ؽk;cY<3KWtGۨQ]vKھ$wDC\6t9#8#0"ЫW/3f+en(gy&<>yS!ޘ߶LJ؈y8#8#P9J_~-h,bn$U>&M%wGp/ lrP#b9 :o6,5w9,5:#8;2q]scq.A>|x?Y*ڎ#8#04iR01\pJqc,s6mŠ"gGpGBckZ  QXZ qix>?SRUqGp9 n9b9h50^o`UpuGpG#Pi+9#8#T7+KsGpG`B2uM:iMM-:9#8#@UrtyֺUXurvTrcT m6jXD2ՍD#8#Рjl[:&Fc F7TSWFˁ~q8eʔ♝pGpKMb .PӻGTэŹ˰<1Pͤn]e~3i.8#8@`q6rhvƦMEh7?Kk,'[-ҥUWo98#8s)S?O><][h^T97B԰x3=w bd9e'GpGpq'/-MQ sJA3/pvgVH_e4O6zFteSr/]x/#S~}fVn\]ۨrp lllllRґ 6tS;s"mgwɶZke-}gV_d{ʕ[~%)QΝ;8S~}' fey7ߜoѾQO1c^H8sj. 6.H^+-ҵz@;t`.3B -d+R@/n;v ƦcLMל矷? :e<묳lV_(_.Q0h%XmV:thWD噒HHD%)RLz*J;Co^z,ݲj l6be]죏>~]w Nrz拝vi&뙣˥⥗^j'NRڵk>(w^u&M>}|`[oնj+K-cQu^qD+e|puin^7YQF]e^-3_drJg_׶"eAq]S~GqD]tQ(\b6*1Llg&%D--+PqT>7 /c?G+﮻66=c묳uԩMEo]qp}O뮻>"wM61s}][{o+: ׿N9# '^֭[7`h#G'Gy-əaÆ;)W]uU;sm5IF2{s,bXgMrJё>yLJzx"UW]d[nN㏶뮻:sOcewWalA&ri*?_Uwj׬:³;wܑm0\_ܦsH…\ͪ\`r-}yˊCu*Knv6p`maWyg<b}|/?N?>t]ᇘgo!4ivR.ȍI.%裏k&ĕ#&K+}w_siiѢEp4gr~]6X߾}2,q!&^zΰ}Ǔ-afK.q)iv 'C=;\:B_x8FpfQ6$&}+LJ ( b_./a/^|<-m}1cƄ\L+/믿nK,9~LҥK2Kёc {キᄊ +v-+3ep$?O1dR]2O=pV-z*<)yXWgɅ0͍UA0N`$Ķ=$yO`VpS"/軜]-WMK'lj>?9,"pa1/L 9\*j,Tjds.@d/:蠃^ =4.ٛW_=I<02`|wA("+a<󌭿abgk;vl39#]X&U1!Rڠ3<3L_}=ֶmrUwZNg?üA[IZ>˸Uoy(&C"^m[VƖ}a5s6MzM~nRlѷʕi\<-xO.T"_ypC 'HUE =+H% jժUy3knLL"Oșp:C #bb8#PV0A.n.pU9ASM i2a qTJ!F?:-R8}bE`82uZ7Ï#"yre`$SOvip.g*G8̅RQcE!LL$L<gKJ!#P"b bD"["Vy c#>P Ų 0j1ug%7VX 8_Cl9ϊR>c1blO3a0r.R>lQ OtIR.CďϘcYg !dqU- xOJɋa6U)T"rS`{4uX9ԕt >č (՞R) BucpwURb'V8Gǖًᕥ{^aIl͋)+B+W?KsdNl8%֧~E?L֬[z؄Z޴n$f?V9*}aLӯ7rKQ9#j#TYiv`ኅX,4 31IoY0+ *Im$\)pxA]ybX=za1 $cvlM.Vy;'|67<ss"^2hO2y)cЀqWJՑsoʋn[.&>9Z aV?.ߚy4q䁦T r3xEC>~w1] ᕥ{8x%+ư>GB\\ cnv;_u%'~Ė1cJSj S?aUΘne?M-+GB41֑e/++-Î#PcRJK(#ooog} "aDB^<*6r-Δq\ۙeEVXsAa0`XBm]xNĄC4u1Nzp3PTF*!xDdJ:egs]v@`cV7C;5VYzvb$ęR:+)lmjq!c&L0V9kV dW"wܸqabF:2V(.mNFQ]N+b8RL?bcK]βrl㰒[W ?p9^v\*ޕUI]#0/!n lE!lw?o-}4[GlV1P&jɛY015-^7 #+xZgՠHB |ԡRA,,? /X-y ; |g-KՍJQ}DGUEXWc_r*,P$_%ʪWV\}9G(X]GYS<9+|¢Ҕ[V\>0@OJw%e D#&3QG8S!xҜ&T5+e- #*૫*1V'$+[ آ<o"smN{1@Su˝ڙbY4/71y|"66DC9 ꜜd7kj[VəQ-X [YKΕеk޶sraqpZoPޜaVx>-lh*clVTsU ѥ~66E)4|!~ᤔ <[" uѾjZWp+u^8#83)嗉 %\k,RyiIڷ Qp>r`Œo͋:9#8@`Ņt66E)b)(5 ֭ZB;3h#8#4 x)M떶`iv$[$g|3n,B`lڤڶneN^riZ#8#0eC̊b"j8-eYmǺGpG`G`}oek8#8|}pGpGȏGpGp{jY뮻{@GpGp49rdf$pGpG`~D`TOqPneQ#^gGpGplb6.8#8# ƢwGpGpd:E@IDATOpGpGpc#8#8@^8e6mZ^egWˆ#UJXf9(r%woS~}mT"=#8#hPN;d_|mɶ.[la뮻}V_d>6`YnD{̖\rG}ʯOޜudQ̱,O<3w7|3S|}#0ozW_}"=#8@F lS^>%.W^ٖ[n3?mԩֽ{\ur%zڨĬ3UBKm }*f=kE]4Dgヨ|ն~{xY{X=pG`@Ũ|MٳgSo믿C 'x=\r%zڨĬ3UBV("KBűRɪ?ҥK!VOsGG(yvvaa˱_~vGibp bٸql>n7d;vmvC)CK._޶rK{rxui*[xЍ7hjߞ{8׶~:+\uU2rz-y睃LEiW4afՑ^F ØMyet ᕙ!̪e]f/y睡}|IˊC&u2;lm}~vG2,.P>}J9CΫYgeW\qErYe!~͚5 1 7rzftI'7ʑ|8#0kاzJZo‡rH|GBI=}=sv3kF }F7RJW6SsC8'yb@?j#VE A7C c27G /\*&+U>V2cI[]_0dHؔ:>x:SœGhVg8#P:wuW-Z")"c.VW\1 +?+U23L?CH_.cF)[lWiӦap:G Ã?b87'sbA1yJg+c /( (_vSGd+8T9F?ʎXJyqD:BI)Tj ,xn) 6 Vc,18kw1|9@ؔ:>0`v@+Pȓ5w8#P?f2F駁U,°OY(FmQ08V%Sȶ:C̮](VuN-S0+)<@Xa9}ELyȖR-Y y@ޅ* A09FOXZV8Z,ǜeuCz.7~۷9g9/A"q1cƄV!C8#|N#8Gfy\V{!<~0AŰ]AV/g8vUZAv->nҬ[ #[ܔ0.cuTÏ[/_~%`Rx8ŷXmr>La:.%I&rf.:򉡿 BxeWXSf!C XsıU ~aP믿εYZRe"RKs{bGbjyӺG|>pD+`Ø*M+y<#ùad@uaGp PȖ+!g&`)ͅl3+'iB&g8 qWJՑ6̸_}2KVIVZipn 7md+K6ԕo/r^UR) CnxL|Vn.3GXe<ꨣZ, S0ă 6PVڹX χy۝ _Q:IlxJSj S?߿VJ1k1Gn$e? cW:88?A;0~c2˕AGp !()x$d;عYIh׮]*R YiOG(f%7c[H & .`!X1\ nR^]ڐ2Y=ztYu$^eCLUGlRm 2 H1GW^i8$eÏo^ md{WRVZO;#̌@&,b,mRP^zi2d}= -Pp>WF2|u/lk$Wzeշ~|O,/_>cH<4e? d Q%ۻ i#8m,fɎe[|%-{Gi/%4$vf?X4/71G({z^8#8@zzơ#8#8L8$8#8# X:#8#̄3A#8#8BE!#8#8L8$8#8# fwUD`u5YYvGp6[ݻw/5 07627?R.3T+gH7o\o=Ar-W*O>nݺ濵GpG6#Fo&3Zj Ƃ⥗^j'NR۵kzXǤIO>[o.[oruTW\qEo6\s|yU1+a, V'> / \SWpGs… ƽ-h,R7>O޽{۹[1dM3;찃|Xʛ3'pBXe]__9Q]ty01ҝGpG8>#:q6X߾}mv{/'vԨQvG2,q7pÐveK/dwyjOx;0[r%_~vG?Gڵ^ [=P;rx:,+j _|/y8bn% F\.[護޲w٨bB0*wQ~Xc5W^!:| 6HwI!*7e6mW~ѣG=*S, [~;}trI)>ys S6GpX]Y5yiw ߅^h}uٮ\AdZ0|KkB!bz0.9+(#~y{ f{gy_}馛2h뭷?ӟ`d-*& ǘcR᪪WLuY'Dr袋rֿޣG\|F$[U=v*VY߹54B'|Z_^[_dO_a[~/ TmVe^lnYqtNg->Hs9QL<2W+Dgoa{ oP>{;Gࡇ ],erVi֙EYӖ #`X( %VX!xyEb.]l-Z[ pVy*,DxdyXV^x("V5 Apԏt :zɖV875j߇~xzCA0 f.njYidG>;v}rd_ ]k_[lC aQ!S=H@,VxʚS麹hrMjVQP^Q^œ_*)G#w5pS}[bGQcm$dtRtc=fk_X{m* vmPtU3ԟZWLALνrV맞z*<*9{ ?`V(7Vc p1c<ΊCu*KnvH5 _ns7i)_f 6/(2 ya3!vG0xe!>O`V9B^dw9T,Xsj1ZpJxxf_2S?rN"x:eUbyb"1 RLfܤ19HL>&^!7UO䉮Ĥ`d oic %J'},"JcT ojx •J[ L>~a@n|X]uvmQP٬`BV{l6$}'_ Tс7VYXѮ,aJe /΀ ;"7ƀX1LdՖKf:'v(_%O!IP2 aa s|%^#P`ډ@kwڑfH:;QC[Ҳ)_FHz#Cb 1x/Ye!~l}{/gOؔ:>'Af }\YƅqGJxx4?aKOg՟qT.|l刘tVIc]vJ 75&*ئt͍MO:CɭFCLxc?c: ׺ukEBx+P{w}M0!U^NvH ͓>$?.+` :8=)dЯy睰ůB:3V#\ܕx`1p(rO?$:+v'ߜ -t"Ϋ28 1чBg}2XN:gYMdK]M9x`]ʗUG#edQ;*TfVZY|cU#|kdKU4V!Չ3#TND&;'\C)g̋Q|.7x#QN9ヷ9YZ蜻p.GV\GDB< 1$w XAdY+7bLӯ7rĹayj#TY1.XaE?5U`.Ǧ*Es*˙`m&VS8'Juslq-78'%VN҄Lf\"g0Q:r3U nVy{COά[GC7~[' 4VB41֑e/+uU9AǕ|ϢQҩIGZd m R]a;'[J}x<Ҭ|:J[[lU-c֙B-/>nܸ0bF:JyiYFlu*x΍RFWv9+P|%y`J~b}_*=rA,b͋m`oK]IYepζfIቅM@&יX9+k`)>ZAnAYMtZ[ϬYHG>.+WǬ┧r EdVzeշ~¨Й,}byϝg̳tˊˇF:/"Jw%eO%H8*X,1oPpcP EyY4/71n Ԍ{fcZ6t!t<#.Z̞ފctGpRh5?1|aB0GpG6|:^B,|!79η0up) 9#8s9BJucQH;W" |g!z߂+ѕvG=KbH9_EN_noqGp\Q8#8<dzGpG  ]]#">,E鹏&GocHW;#-x,R{῞ ڪ$io7[5iMM7B! 9Йi-X9@K8Wfov68yםK.SO9-ǵ;"kgQ~ԚTiUMjլiP|xpʛoYKk?k=v߳Oxd(mhpLb(cJ8V5MϓVWr\U- h_}nrsOuY5d|ANE]d29+ƢoUʞ.vqv'OCF,1yfKmK/{v4WWc, E&k[omN 6憂xP2ejx`pqÆldLJn+ƍg|I04 7кtT ɥZ_)ƣ\?mzZߪ=gNb'mylC#;rv c6Rry?~vd(P\V;찰د_?;#Tu%/o[nt7u]gjc-X/bdM\@޵^k'pBGm& [.^zΠN|:JtĹ/`F+/}vUWvI'7嫕fVn{gY8 Ňy2vu xumn]- ?q/yCTr`S͆zmlmm.\ZA-! c+om֫W/kѢEG!P}۹uA7iWKK-۴)$C۔el¯i?7 q,Է- Bt!mGy~acyCe!1!5v嗇s`D>뮻xp8SV8v0'cǎU0 w饗mgyƸ^x}GA'7gW7 Htb;x)$$$AdЗ$ш TeE." *H$ s~ o߾ff>cݷSvB鷖KotQc'7o^5+m" e_[q.?CSw+wܡ^0b1n2C1Nə+9{^;GҐyQ&k/PH^<ϗ>@͝;W<|{/]y/sE]r-f?f>aeyoUVٕ}i}qK+o(W~|y51Y?`iDEXg'yCڈ8pn<ūէI-?K̏{lsmDZ6^E7H @p zzڴiB|Pa6B1ChѢ'oj`VZJYʔ)? _`=#O>YVE;d̙2n2oݮ޺&.g'L Z|z߿_j׮,vޯϺM{UuaB ^p ԫX%lylݺCZ:_kIfq{5YA٪z[6B!{LD+_zڔ)SeX1VZJB=o(5kOp&=k/(Ba<{11˚=bj{սx隼2{V/|VC\~ypBo'RZeN K._Jz|N5'pU˃7ߜGXjԨvQN+>㼶p>GzJ>I:0C !o'O~u7u1&_lW" &xb۶me_~YUUIY Fwӆ-RdQɕ'P]`20uƆ4k,wC^Ah( ^SX):ꫯIpE;^B;vh[w0|21sUdvaI" ֚% *eT#EM4e1ׂ3؏JM+:qw nq˧BIe ~!p(xNmounꂂȋ/&`X4~+' ]j_}p1k1ӴUVr%VN)RR/^2Sg_P?#NCDu oK/|a[8F~'b*ThxյpW2focw Cu ~tA/[ߟx $Ak2dkTRE5k^0d eˬRvQ[Z@yWZUM:.8ruw "=~\8(&N?2nvBƹ]ӹF\J$عnts w-uvs,BA2_3ie ~O#,9b2ș3gR!i(.KTgɒE & -11fp-I2JxSDQ0e-!Te}- OA3TX0+._BeTHަVy'|`V+u^[p~0ٳgj%h СC1z|EV#N?~\_*0t:򢌱5K}( ^pN&UPB7O>Ű2@yX֠AeaS|nXBx1 ^H1k;~AnXh^#.ɡyu8qAN,{UXpߕ/%)~ȋ2^n*x;0d W/P X^50,r`o\;V!|@Qg^mwi=PbE* ʸ޼yzΒ,rIk&~j{'n~kuv;u~u:;1vs*"]׭~<5v"~l~mp.{D[(Z 7$<`ð5-pOX/^loVQYtV^2C0c k?:{[NmzhqB:,gϞ5fSue0Zϸu`Uކe- 3'NK95FȮ;KTq 7BCPeP+hyWX ÕjO1[3KNc tD9=BɂwECY4|/[]=L*ʈPk.^K_-'3g| KD}]Wt]-F^pd, / X +u]GtlݮD Li_b8k0~kH8kD(=A,]+^^>ZV{߆ߵqQX8ʢ$D׋-nǏW~=_l N5i*3fe*~Z_@mZwZg 7)}<8yǩ-g#˔.!ǎeKߜ5>#fX7zr%j&w Q)7VA@}]aź˰a8S>h~J+Xjtp'>Nu@{rb^GɩYcIByFypňenC2P\Q`'( Fcp2VcBFXׁ.z_y;]'v/1ּ Y\ p vq.|7Gjk]z?޸k Fzm[ۏԹXY0xc_f&U/IyoTt_o*ӹ_3`†&\6^L61%[ʪuʑqn=xȑC-Hn;ùa}s ֐O^ >l)sf ߖ"^Ga!vXDaCp.Bx xưzjeQiKG9Xz)y衇\Hp"^e8q` OG]KG<`B8A}14sQ0߂=@v"uX}䜓ow FC+XBVux֏n~:_emSԹ eP1x 'o>N^ )(Fp"E o2%elῄ%0QaiuB n"~ɫpS …~,$nAP䰤n[ʢ]aԊ"*$FP*1T O.q,0|v=~P?`ofLX2 ?qkr18pR6,&W(vpد`wCZuEz)VwÅ+@9.ciۚF32xf8k*1 =٨Ʋ62JƍԐ' 3ZYb m^JҮ]kcf۵k|2CBDscp+a #HV(N"AQė@p[_Ca_xJ,P-G<ļ4u^mA'_kÝkO`u:Tgݏ߆ߵ?-V.RvbH4Ic{5\)n1M1|X~-u6)Q1Pyie1'M6)?hX.cAaR&`pXu+5?gꕟiK N쒈d]޺5*$!a7kDdntHVp!,IchSD)V CbU"hL)]t@K"(X>z˴C ΍alJ?/TϜ-Qz-AlqCb_9Khb^vMdݺu7ּys-`2V)ckVFȒ%-[uŠ^(j8l`: B >WTVMm]A+ a5=ZկJ%+oa$BtR]mi&Y~+WΔ7ސݻnjduQڵ=z&%2e(u]&xݹ|q bE0Ci/5O4={RJTwj235 u>}nݺ&bŊI*UhD>ԟH޻R,_R|yy套^n zT܉9l;N.\ {EB g}x#Yھ}]6d$(3(h7/,Æ 3%?~R']t1v=S HPxFJ&KL п/򆪧xSwJ; VΝ+P(B _paz!駟VT\Y>S3_ ߣ>*/Yq? >NmϞ~!LڴiD~{ny1 tR Α[~kc w:Ctկ__3tܼy]?((x>ۏV3 IYKE}bpN4Iz)5k֔o])zȑ#eFK.)E/2j97n.C'NP-[TuY tu6hm-ZP_|E56xɛ7l޼Y+<7fϞ3k,w17sL\hbeՏڵky ,+>YZĵ&[ yך\_]^ߠAxbi֬:G^ukyنS$@A1<>d@IDAT#ýiW'|R~Gzx>쳒>}z:y>%Ke)-k$weqΝ_~ CX4H|Xêk SyIޫ2aMRJf{@-WmJ X: Cxˁ\(߿_0i^l@qrٹH) @ @> @ ?ƍ? 'N\zτ`J4UС h8y?Lj!hp}:ݧt{78UxZtV9k8c 5l ަW:&~MMB?d aÆjvPX uC޷rcO~} IVq'Nנ^נo+/F0 n+'^d WL#p&ߝ}d[g ^wzS~~{U@CeFHb(<;<~LJ6ԓG$_4kjon^8]ἶwJ|7:Ȇ|֭W}| QSA+X CH\ Uc"n/KLáN@, \ȟ(p][Dl#?T@"D{<ƽ+he2W3"0b+BdP>!Լ5D_( GDbw y" u@D{ֽ+heF=۶1[뤥رC?ؐUWGp78^~CW?IRHKĔOL4]A+XKڵK)0LpP뚏^<?BO#Zk. F -=#|hܻVU|Z #1<蕀 1l iY{u|;T~3H %LLDc '75Rx-9$Y&'ː C(wdZIHHH"Ab$N   HTD$@$@$@$ T#Au @ '    H HHH9tc믿I.ʳ{0ŘHHH H:iSt~~0پs\t9aŎ D/tM[_ҽŗlP_vv8q┬\^_E8sG~Sy=3/IHHHSYl߾4jH t/sΕʯ-"i+^']$+WӋUBgg(?m.RqU$͛4RHHHx*nt}Ú%JQҒ2LND[}os)R}ԭ[W,X Nqܷo_TKRR%]̟?ߕ#GrI f^5aq ֦MP`XY˫+l88zCشiStQ^KwU~pA~ ɪʅo߁2_S\וuj 0 _eqʔ)ra9s*THFݻԫWO)d(LNqȼw^ywx2{liذ 0@ a; z+ׯWu<̆:ɄLEaÆƍcƌ1bgڴiaJCA[lRnݚ\v]14f7ڳؿ(ozW(Ba3n2f͚EKo9~ꌈQHHH*7V,-ZP *͞=dΜYd" PNqZΝ;+ 㭷*C cǎ!;dҲeKٿBn޼Y:7VŪU*y- %K" M(]v5eCq, 矑,3Cdew׭?#SyElN[$  #;C:dʔIͬlQV|)~:uhcXFm.ك<۷oWByɄ#FȥK5zU7ricM5K6yj#d}2_(V$UהO] AsƟ7J@$@$@OWYDDXXb* `h;?X.1cUVX9,ͮ]p®G+a%̔1ܔ>\zM*V,䗋:%1]eHHHH0Weʔ 6$ k׮5uUL:U`]oB|&MݻU!3g ?;u@SN%+%5݄Uqr 54oZGwUɞ-/{"m[ڷG(̝G!Zetedk$@$@$@qI $e{j]E̔D8ÿ~5jԐcʤI$GH,h 4:7Nf*jR>ڕR׺ŬVZPD1_ի-rn0|ҿٳx􎍳={ c׬rEI{ɲ/J]oi&Ey%3%   K 1.\PMē`Á?!3qڵS_yjV]Dwڞ={V`U,XSk'O(ws< __iٶ)Wf6p-I$_5ӿC͙+rR AgH"):AAtOQ̮/؀!n$3gN92C*aܩYl\a9"+tEK^|El٪  H.]dɒ~٘JM40Z)g̔rHBRzU/S2HHHH (ݺuK(KPrwLT%X1 o]BȞ$@$@$@$ DEYԍqQ1 @8 $H gHHHH !PYLN @dPY WJ$@$@$@ AbBFvHHH"CbdV   H q֬Y+-q(z̋t)夀$@$@$-TE:`D|/y0Vfnݺ4vHHPYtqXX. Ӊ1ޥ3[   $TX q#| `@$@$@$D\X_;Ud9HH > Ĥxe3*:s G,ن"  H$1,o^HΝO˧~*ϟOVbϞ=2l0y't钬ZJ^u9uTy@$@$@$N }dTS\UeD*mԨ,YD*V(Cgy<7vCä6mڨfcǫ<O߿)Qk=? @>eРARlYyׂTSY vm믿ӧOرcՙY1cƨc(͛7WJ$"r!O=lذAϒ%ݻWo.UTQeK4nd< JӲطo_?~KRR%]̟?߬رc|)ERCMApC۶meƍ8Bad   k;#ŋٳgKÆ erR޽k}g)M>}L)P~ĈRD /2Y^=OyiӦf^Δ)S2sL)T5l^!68цJa{7EұcGYlL0A#G(cbS`Aɘ1R0U,N F$@$@Y77mڤwyr7SF:ͫ|7'  ;_eZѣaEVlbf_>c1XE)/B}L^  p#,ǰe˖!f,m2i$t |۶mRjU"&&x=pw.X&&2 ̝;WMdQTSr?fb6K-K31 q @Y>`d{ǯ<Λ7ԯ__uBu#HHH 錡k(pBڵ+h׮Z瞓g'E^0,;wn]wYPBy8;a T~_ac,YΞ=fY:$PΚ5kYf~YN$@$@ K(7D7K HaK@r)O@cv^._yL#  p&,vEJ,\2b]~7ġXcdud+HHTu֯_[ifA;&L'y imڴ *u_tuQ[/9=*=zP26mT;],"k._aҶC7Y[p;pP&kjqRNmA   #,N2E>,3gΔB ɨQT{z)k޼y)+/^\fϞ- 6!l+ҲeKٶm̙3Grʅhǀ6+ׯW <̇v:ɋLEaÆƍU_ƌcδi\eL8JCy[lRnj/+׮+]{Q*E(cMRVƬY-O10 _eqJEEJICٳg̙3K,Y@j)N йsgea[eȐ!r1Ӳ!CYx1%KJLtd;v˕b~eܼy:t&/2XjU%+]eKFcK(K,Q$|9vZ< \4×Fdd E#ޖ ˷]?CN98HH %C V0_|JN: f ~ү_?yBgo$ѣ|P~R4/y1T>bt苗yɁ ?ժU#w46W,$klԀ'Gdҿ>PT\IV)4,0t4   x',Fn}'7?}M+VLa) {P>]w%3f̐7xõ ֌^rʉ%kv% UJ)c)}:zTTYyLj3a>䗋Z%1]eHHHH0Weʔ 6$ k׮5uUL:U`] իբ 4RJ O7$Qw&MݻU3g <'͠(tsԩddf~*N7*t;~x97mHrafc8P%$N2,ӿC͙+rR AgH"):AAtG@Df^lPuș3u`q3Ud-[FUٸ{aXϐ^Mj"&&]|El٪  H.]Ԓ8~:M40Z)g̔rHBRzUS2HHHH (ݺuK(KPrwL%Xw1n]&Ȟ$@$@$@$ DEYԍqQ1 @8 pNl8i.   H0T섲;$@$@$@$NTIu @`'!   pNHHHgC 5kJK"+7:uy9) Dhc;X#Ķ~^1է٪([.'  'Tx >Ǭx1+,#  (%lyump֟VSe   H" .I,f֯ȝ*[L$@$bRY|}#lAu $T۷o/ÇO$sɿoyO?;ؿL0A.^p?,o_Ə/۷ow,H   ,۷OvޝR bp ʸʚC5%KHŊeС3Ϥ8'6wMz-gϞ 8}ŲuVY\Rn69qDHDe$ H Au'@9X8"m믿ӧOرcO>ʌ3R)(^ʜ[T}ԭ[W,X`[oIեuw#GLQSo:(Α#G`\ ˗O W%(w}wVu-}_ηk.9Qܒ xT+/^\Yb6l(\rEU@-[V-$9sfɒ%(P@7n,ZBX~ʚ={vUZSM~gȐdɒjB].\tI]SxR/Ul֬JKGǏѣGd`*p#+]H裏K￯#uuhl}> @P_pe~}EnٲC> Cр?ۡTzH4/Plpϑ#L 04 1 CXdҤIĉ䐪U ~UĂ^\ # ED@SNqM~a041"B-K3q^x6pϟ_ׯBu#HHH 錡k(pBڵ+h׮`{N<3N ӧO/sE}E !Sָ@?s挒x Xbf'RBۘeNmq:tH͂vf׉4mHHH uBaht "| ^ZSNq^Ǔ(x͇YE"`ZF~I$@$@JSYSkwݸY3>pd8+$ H|x(r, @T#ٯ}ݻ#D8ac$@$@$@!TaAd!w4-V8-aIHH#>[oIեu9vW*U$+W~ɉ'L [С+WN?rJ9rXBO.u֕ eC$@$@$@$;|)SÇe̙RP!5j)}޽|g޽{O>f+"-[m۶ɜ9s$W\* ի'7o4m,kb   J P}WYlܸ 6LY[h!ׯWLw)K.Ua ?(/={<2d0K,DB%s̒%K)PW_@=UL$@$@$@i@!d 8)5kRF k.3fZzoW_}U.\`N zrSK $:@ _e T…UҖ-[,/Zږ(QB>O~hN zrSK $:@T+z &9sFN<)ӦMXK.^Zw TR.Slذ!CDɍH㬔HHH !OZYt'+UV8a + سgOnk-bextMA$@$@$V OdYйsgOe˪ ,XB'};wn8ȑ#G4,ț,k    #,*n|\ڕD{"EأxL$@$@$@$#R= #I15I84 @@',HHHH m0tDw{ _Q   $*a6^vm"%  H@%099@e1J1I&1&!  HTYL3~ @PY DVA$@$@$@JbYHHH@b    HTT̲_$@$@$@$ Ѯb֬Yі-ۻzt)޻AIHH l, e*ʔ)ԪU cCQ\n]keu$@$@$,K.̙S)Ǯe   H"@e1E]vM`]̖-[)2 $$qGWNF-k& Oi^Y%ҥKA#Gȉ'*˩3'8 Oن#k! HA+- 6$ sJJŋcǎҪU+;d֭sԾ}{>|[r¾j*yԩS~a={<2qD9zhtٳG &/$2HHH@T'wN ˶|7bIpʆ~o۶M;ٸq/_>K'Pd/,8|x/_\nfٻwe׮]ҨQ#dbO6mdɒ%DckIHH 5<' 4Hʖ-+Y Xq72]VJ**6T%Km߾]T Mf.ԧO:2d;tPi޼`#GyꩧL _*7 @jZG)+VӧKݺue}@!͚5HzyC(6m: [7&M$Ǐ^:u*ÒUBu>/ymb?P<(nϟ_04QڶmJXu9nIHHRpU{-S мybxĈ9sf?zwY Θ1C7n/͛W֯_/-ŊH%cƌ/,NZfkgc  We1{Jŧ@j ,9|PdIiРZ0zرr-~Iݱce˖~]l޼Y:$;wK CXŋMЭ}"/[A1+Q@у|YfUB m EjժkeQ6u=iU{OM0=+ݾ$ɓ'}5SMlu%  ;OE{fc ꀇm EYWv ysX[[l… _~Emape(P>u^Y}(<뮻oNVPMV )4Bc &ZYE Ek,gi&I>KW,5sHH C#w2eD}M4QFK;wNΜ9&p!D̂tҪ% kc |1>3I_ `Uq7|SՍ33YvrJDŽ OzY2)4O>˗Oo V'xBM:\wA/ytHklu%  7bP0!$aܸqZj)El a+\:PSkHϞ=+P0s smORh<:~?m:yj?M AO0RU88uu%'tYF-d/c  H+:a@>V+O@a/~NCnM7C "j%Q D^WoMNm嗮qK$@$@$Ds:)b@8-ԯXlc,P  X"@e1e!   #0tLq _J8$@$@$@$NTI3Juatڵr(6W2 $"nV% D}Am @'b @4PYeA$@$@$@qJb8M$@$@$@ @e1 )Ά7k֬~;DLd,GԩSϊIHH PY3fț)S&U0;(֭ sHH8<ҥ9sJ"EP $@$@$@I,&k׮)blFx[e   H" .I,f֯ȝ*[L$@$,y7"Cl#Õ /C﹣طo|xԮ][j֬iٳG>C9utQM2C$@$@$J&*W4fO8v%5R"&iF,Ym6 вJS%JȼyR&1C͛-2ȑCz)ٰaCd #HH8Ob߾}e„ K*UYf}v㏥N:ҰaCYhyaPo\ȑ#a=c 3ŋpK8@$L>]]mƍOqK$@$@$LSYܻw1B2g,ϗ,YHΝƍ͚-*Æ SB ɘ1cTZ'gyF6m$ǎSǰd̘,ϝp4%;v(_Cri)VW`AuN$@$@i8GfN$G++uֲf/:'NP[x9yJGV'  Y̟? hid.{'J\\[:@Y^TXQ3b Fq dDq$@$@i@G^ J׮]?a(@0Y5;wNUe\J,+W_)xa3d e˖ueYҸ&K._y,@$@$@i]' 3RI4Qp'2eʤk91 G l5ܡPi(˒7 =T9gIHHH `aef CHHHH ,FnPڵkիj!mV XHHH $qHHHH  lHHH8=qHHHAb4(    STQl   *Ѡ6HHHH N p6tYf 4:uY+ !*qx-ZjQa 󹃢nݺ0HHH PY.]:ə3)R$]8 `@$@$@$Dbٻv-[9Se   Hъ IDAT" .I,f֯ȝ*[L$@$,yȝ4[L$@$V-Z$6lR%p%Yjrԩ5=E   P<}'W\%Jl.ժU3beIX-rKťTR?H^$W\&P͊w OeqРARlYy̲&L0cmIX1򤵡,Y޽{eRJCMVZ}  p": =rHYbL>]֭+ ,P+'N41H AެY3P㏥N:ҰaCеG|Pʕ+'ח+W$9v옠J*Iʕ_~r 3[nzu裏GM^%kBj['  qU{-Փ˼yiӦ,3eMӧk׮djP$٣5 'J#w26rlY3 @|pUgϮ@Xt (ݺضm[ygdɒҠA`رc[n͛O?رC/_.-[Kڵer!ٹs,]TVPAxbS!tkUOV+N9|9E87%Z Z> iBC;cd9HH > PYFIHHH *$l$h<" DHҍP*]v\z5B-j> $@$@$@I,&=U@$@$@$@ @hPf$@$@$@$,鉣$@$@$@$ TAm @'b @4PYeA$@$@$@qJ͚5+Cu)bb  7TfʔIjժE1u\+#  &@e1_t$gΜRH8>vE>p- @*I,fڵkʺ-[9lHHHpK٣+rl#ǖ5 'WatRPt9"'NS˗/ c pe$@$@K ZǢEdÆ ܹsRJsEرjJٺuk@2o^ @_jrԩ%/\ ׿2dYp~[?^onsɿoyO?d˄   ?T+Xoo!9 ϶mモ7J}da35P)7LƁ"/P<6o\)yuXt?3ŋ_fMYrvm),Ǎ5%KHŊeС3Ϙf;wMz-gϞɶ6<   HXgb-]VJ*1 $e˖^{-bmRq fɒEݫ,UTIw}W?q<`?,_}̞=[y_ӧeرJg3fY;P"xc<   ,~ҡC)WT^] C߾}eĉu*|AUOuHc=zTz6mTY y4i`WrL:URۦMP`XٺLYG}6#,;#G+VU ,r׋4(n΅"v,qS^=|)EJ$ǻLƍ> Y<HHH x*lR Ι3GreK; 2ȼy_5\A ͛W֯_ e˖)wV]*p-ZT  *?I1{qK  '"{B JՍ-v˸sN5Yfs Kb~2ohBڱZq^{)SL… {Hl=;D  %bPJ,s@/mĈ꡿cY|R:1vڲyf9tP a%@ʚ5`3*9% VŪUJ̙5jY͞=FDRh`)/!ڀO< !XO~gΜQ/vp=">t(wy@'|"?#]t1BB}( kH$~qHHRKSYuZ{abA۩1<0/hf)Vڇ7t v. .4 P~wu̘1Cʕ+zV7#bt'Xh1) Ve`Eg9r֭[+V ܹʊɓ'K}Zao!&U |ެQoVڊu A,iː=$[{xL$@$@Td ֭04=$~GɦMrjy,1EBOaZ"Zƒ̙f2|Ǻ|62+cV%X0V͆ ^z=.]ZMZW޽@Yp)&Qܨo˻paE6 \3~w"ϟ_/|^Den13^k|lm }b  @:cF5T/ft֠-2 zVK%&4x .4>aXGd CsVǁ[(K@[@"Ç ~X:nqM<ĮY&0eHHH uOdCIbF1~~օDVqRQjp:sV'?Vk\r'  p'9 ^)7eFʔ(mmIHH \,$!   $; }N.Kc @3"pA0TŦr2dN/ V   $TX֭d    hb4(    STQl   *Ѡ6HHHH N PYGI{wUq;iMgni-.JJRY Q)f.AhR!HeJ-nP.iY)jkdid_l3>3ϼϝ{= ~=  P%L  @H {~'=i': @A[2v튕y@Jbo{VV]Vv>}|q- @ X"4Gyyyʕ+aLeKB@Eh*[mR3 @8 q.]Ǭ0&J HO>> `/r~e1}6}t;{l! Z*-[vdVR`p7… n3иq^0+aK U -6̛7/#Kj,KŊرcvAkժU܋C& @);}v8p5iڶmkNt~[zUZoaԨQv7ݻMSL4ꫯZO?nݺ`{-INN-^T^OeYfپ}7\[ {P]wթSf̘a{챚5k bU^m*[|˟={vjŋ6bk޼/8D=vÆ %l=y!X,ƒ^!5 d@`lٲ.9z5hO?|}._SN?ډ'|&L`r y%*S``Vػwoצ2%/Olv -1jVQ3*T몙CKd-\ #^RJ\d^X)(Ԇz7nlիWGs4W)"@ ̢'Nh;vcs=,Jswq{&LuJjrC3z<-]Ժvjoh8ҥKzy-xQd?YOUf;/WВyƍc[n)S+3V}vż6VM,k?R @f 5rJ7#cYzLKuu 'O}sժUkiWc\RʕjO=7팎>sRL7|Z @p  G)VGlPt-fgg$jb(z%K}@Z 2tН`\!2G}M4nJ =ۢq% @f $YaǨG?$@@ ]$ѯϗ&q E@@B ,+= kt۶muBѣ\yzfQ  brNiUJ$! %!P @@ !qt@( ŒP @@ !qt@( ŒP @@ !qt@( ŒP @@ zb^^]tʕ+^9U͛R>Vx;t;vΞ=UZݺuqVReD@ ,Y&NhH܀$O<9%ut*9x?޺ux(ܳgVZ+J  `,Cg_Çߞ0PP5 $ XL$=@F]CB@ srrlذa֤Iٳر#_}cƌy̙3m۶ַo_۵k_f6p@wO:%:5ߢE kٲ;6_(?~=ׯ_?[jzСb w}׍;z-{]:ud֭VA@,*`믿/Kھ} BϿ͚5N}mզɦQF?>m=zy|ŋmĈּys߿w~|A4vQ?_c3gիW}ҥ?L:(XԦd~T $#3XTg[:ulȐ!WթM3fpo{ݻweʖ-k6lpAX |~^6nh 5k~tՕ(߫['LvMvvM649sZ@E!X,;A d@`ѦM# *@ܹs]`ұcG{,ȑ#.}~vڹc&.Rgyʔ)N32ζի۷~%YP3zN2?*KB@,6mԲrm2E+ɕ+WgxhŮ:WV-w~5Ù(߻W^nvrȑ=y3rIYgK3j ?Ԭ… -/+rٺu[ܹ5l0E=Yf+!Fs̙3dLcF 3#>} d'NnV۹sm)mVP;f'{$JɖKT  P:b)S`27Ά^(m-Ck 7z[b%}Ƙ֭[~DDu6 x*=䓶ekt%\v{xu:P۠%_,X`UT)X,-~d?Ӣt@^ {pn6qD&m8}ըQ#tǚT*jyjժEm3Q~ԋ=C/ZzN׮]mҤIoob阴[{iJsUhkM@1a¯ӎ.j+-K]/SUvm״K>J5^O]CB@ $ U>u?aHzRܼyswGFuy7!! c^’m7fh\rIһO@(pbŊO !  @ F+  ,N  @Xr'  b4 E`1,w~" ,N  @Xr'  b4 E`1,w~" ,N  @Xr'  b4 E`1,w~" ,N  @Xr'  b4 E`1,w~" ,N  @Xr'  b4 E`1,w~" ,N  @Xr'  b4 E`1,w~" ,N  @Xr'  b4 E`1,w~" lsٲer  Prrrd])>  'EWO@@xf  1[ӯu-IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/cm_desktop/images/lib.png0000644000175000017500000000270712346515436023725 0ustar felixfelixPNG  IHDR szzsBIT|d pHYs : :dJtEXtSoftwarewww.inkscape.org< tEXtTitlePackage[ktEXtAuthorJakub Steiner/"tEXtSourcehttp://jimmac.musichall.cz/iItEXtCopyrightPublic Domain http://creativecommons.org/licenses/publicdomain/YIDATX[lU]eA@#Fo 41/˓F_45!UP$>IPvmgvZXM#/ɟ_˙sÍuC Xs6npV*.JgQEF,mhDYhsCdWe#5)4^ EUT/.Nj/((1h%hKF+5,eU>\{]m^mժ-5V{Lc.ZAU5 v v**%1F@Aˆƶ,,B$O?8Z \6m؝@o*"ӥU c޶_U̇sec|c!60Sڬһ8ռmXRj"1k7N/^Smūֽi$- /*`@*s%.=k%j$;ϭpG{>oň] vbĉ"NI^H(E9e@9,C` q$CBq$Xo-aWX t7W*V.x`KdQarcU"sLN{RVo@߂2`L>>.6Wq+kmg v\ Ai9˶ЀmQLʶ3X -t{@DL7e|"R % Da9@@DzL~˜Y@l̢^p&ۮ~{?zQ`Ȍtmn:vt&tԗvc >ֽͩȍjEEl2DNߊ7@1&U`B!aN9ώ~J[n&߂zA\IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/cm_desktop/images/cm_desktop_300.png0000644000175000017500000011013612346515436025665 0ustar felixfelixPNG  IHDR,!g AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  7iTXtXML:com.adobe.xmp 72 72 5 1 2 3\@IDATxieuj\}Ӥ,F Qe˟D"&l)b&4ˇ HA/Y"%%" A 6h|uUwuޛyɓyd{W=ԥ>Zª:r^L'V^=iӒwDvG<-$GܘwHVȵ )7q)wbdf+/6( Iq%OO&?GqhO떮ϣIڤh%O[~z<-M۸е>Mi5Wu;~{' go[fmy;{=9[tk ]G~)#ŷ46m6>]>)KIqѦK;46-yZqk}\fR&e\8NMi/xZݪoxGWx/}ݺ-ۺ_vUwkwx; 6T'wk~{\Q~tsw]toz={vrk邔4[ڊFҶ-mΥ ?)O97创<ېm/4t-m{yN/)G\qRTtuiwwn.|;St߁>=ݟ}Ou7.^Wz!2\#L,cԩsI|Sf?O{ݧ9L%@o!{%|gHxx-` Ah? w&r`#1gl [A{Dm8Q]|vMZs[5Uƅ:s8ss6n}snۺ;xՃ\-6ukp`ӆl%/4vƒwn]SEo;[}tOُMp__V!vfCmeZ58t}DG![v [ڸ<('Ewˬ˿fl%tƵ$DFޡwv=3Wߞ}/nXk9<h Vvu,^:A'M}aOi5Um+^CNL)yyEmIԳp2 .ۦĆ?oRVT3'rյ='ԕ|'$u{L$ʃ]?|~wMrZ[_nnݞ=u7ԾGM r2ۼm:=OZ,8-$z}XrmN^ʘ֫ 3rUgd*- ]QzX*֕NxT-x<} cZ1^B&˵Aw:,"*/!w*)hBܱ I^'8 ckϨWO4}n򥅏61yJӍ]W;8|Pw&Y13E!;YvgI;F\K^Gyu&OWJ]<ย) JZJ:z:ЀzA],&:յ\xh~&^5GVfxqqqr[ fe\NxTD##NiD|fqjz$/i5?C:u-,gʫG6K@_[fTZ3J4pk` /Pl{ZЉ@e~׮]uYg5fFhl<$g}ؤ) e W?!"WLDf84pfjMקB` /}i]0ww[ֲ믯 L_Wv/+}n |;'许=evO׽O?]MoeX'?xk<,[@s誜yV~{H 7InpIsR<9Odɐ((ʫ_nyKz+W'ק$/WWʯWJ݌,%У9-um8׮ k9u/Ьl@=2oy~ʖDdĦx\ݍ7}`^סY?"W]uUh(9ίV x[~u]tEꫯ-su?W5nnzz;s*oQ<裏V&OJ鼷uAg`BFZSWm۶U;v2k^Z W0zիƞ۾s=TЃ \rIݶco\P*SDe] {3d:ǻ}{Oot}{+0^u?я;z| `O=T>eUϠA+]b))KZVx# W0C}zoVsi!G$xvo{:;CC{k^S=;{Qwv' d<.| Gƕ@| jp`yz͘ +G?ڙ2\*X$!G>Y0/ś P x;2s40@C=C8v-T{Wn(|gɛ"x_5@CS.`TX`84ph.l8aU.0:R@ `df~Jp's3y12:%xB?Z5E+51LSF "{% 4pi q, PH!`8TB WhCo{CL[Jɟ7|#C{840h`k}!"y u Z'=oy-m9mrRnlw84r5c})'V >u{۴=xuJp40h[6\s+}p/R@.GdMeW| _-p:C[{ǜ9eu 0H[c/-PA@pi y晊;y.cbfo|NTf'̽d{VNrN -.LC X ]K,8IV[s>Z$j=Hπ-7HY]n Yu B+BK [.r 8خ5 oxCg%b:[olRЇ>T*s׾MЭzd$;N%X[CyN^we_kϱ "вݛ/nn9/l-X ozpbet|Q+- ^gñaa! WpݼM3+s\M5H5h`G9<1 Bh:g m^HӤv+ɛ!Ji> 7Du4KhNPljqL+L;pPA"UA+W hK<򘽄- Zr–;}}YvahopnA ׀E .ig배;ֿw9}o%>' e4x ֚5#bmX$9ϱ4)M_s2ZG/ l͹+IƗ^e8*r@(ʳN1NJ'c d[X}wua6r?^\rz0R5vt'/6O ы?qyK]nbB;jlE*g)LM3j! Y! QҏjOTntv1Ripw_ylSer1a=eqM>B&w“P5*l=ԻѺru[/*[p9/K7ll\kk+eA;T/DMB2B?%9*1m@ߖt(ks-:Tޥ tTk!x;hg/+O=S9Bխ9#8xE3%!7YW5R(-@kjǖqwg5_0.4l+@FQg-+|ԳQTw]wc̦ 7$wyG9<=hRYo /\P.u>vֽ]/ԯ}Gmwx͚HZN+Ṳ#'l:{{Oy0vw6]}=YyVY _0.b{˗~R޹w{gs9RS"'ט6x^η%*[ʣm}@Sn+oMdWoXМжϨΣ6N}8a5OF7ݳ>}+_-hxGY~iC,'m^+6T3Z 7}XOw>Px{ٽkwDB,R뮻*@|Շ- <:@|#) |u]oP>qE]2 k_ >G? X[~dcXb|= ~uy-O>Ly3W˞w mAo>yfr|ߑw3sCkBtUW󩧞Z?L{ B/fE&m?*_S>96up Ȼkʇu*63ݠ|TN M,>~v>\w/˃;:eG/q3|+Kc-|Nj_Sy_]K/+:o4tӀy'Κe>MQh\ZXDF:?+Znj H3u^ #dӴ_; WI `us}+] G k Xt~׏>H)n_TYUwOn)׮ (_kʋ\+O^zx.zZ=+zjT` !0=Theviˋ13l%-WoF^}e6 q]Ud$ticm+Fd+@`l@BGȤ;79`FA{ =XtDo\}y͑iӦ*Pw߽ÛWFK> []@h|}I]i@ݔ7эQxR'Cs0{ud+Nu+ʾA3LNư@~wx4` >T0b I'#΂v$۸"Bw8@C22_ҁ՗1{zHd.Bݛ1NyuRRPG^Ic w"ݒg Y9}Ev[o/`eW,%~oîҥᷲr H< &Ե)9[>묍x #Me~azBC[l-F9] śV'ü猶1u({Ev2^^@7μ$ L6oK9 Xw5y-o 4/L@Um=?[(Iއ\eSVXmkw7Kt]sN侣5^뵵mCEo}Űlv&92t<l9ƢꔔvՎ}>ڝmswE/Ê TۣrwW<:#&N..EKreIgujw.^eH9u 5X_w `7U:r0͹4@Sz&CG^{m^ RxG3Bed:wx?Oyc!EɋTxK/ lkNI i=#A(OB)_-s&t'q%r&XS޵`^JJ{>\x>@*OrGCw\Qٵ,2YJTo |:4_Sڻ%\Yi rZ~CKmǒΓWjiR<#G$OGۓO?}\׾ l7:C,阮M5'-OA< _[~BdS;i)Ƿrݕ_mXWaNXLȐ8eX reR&.8d&!HS*1C-SĿ ]Pª& 4,i&n\L5|13 »柡WF5M@ő[k`+Awn8iw,Pʮcёa7K"P sgڤYUChFWӨ^usՖO]e.o}CwEYA `'uTĹj3絣sOIqɏ_x siWBh_~Օ_\Hd#5%29NMã?Y('Q\WFiIT΁"U3a=S"sUV՘KJS%Sz]3HIs/wD4;Nk"kyfg&bN2d)/Lj -"gk4H*Q׈e;ursgTШDCX6 hWa!iS8aH\O m'}8#c Ž-$uHN+oԏlISԛZ#Fġe364a[AmoIx*C^!4*yz[i-OӦ9䣛y+sGrc:^dO|[K ӡUeB9kpW10X oħ.xA=MZ˹\9k ] YF"])'i.DV/Dty*ϠS'#Ag/CHtp0l~BRFyGpK3Ϙl޲c@g&ެ"/9 >J*$Gȑxx?+eė!8W9,pWo _VӑrQ.9Fx!^H}ԉlo}~:Fۋ3\^]V"x\hun :8})C{`As3([@v-4<"{lɝX1dC)f' >0l3*ra?P+Jm0R>sİ #U쎶|o^d2_%qh_x ґ7M||ktyyZf߀TW~A[VϛtڇLz׻I:gG`坡&to2Cnt:U:/v $ 锌n 6f CT< B)/yrlO>Iu- ?i-_)-<@oz.CbK-Oq_e ,h] _ Lұ!^2KOۉCjϠS}m1`xB: vsPZ/s(>|Y9Kצ.GimhM{D/׎mH>qsqOGڤzw\hy:y\2%qR1N&aҀ~a&|fJEBǶswX4+Z01SdNz'饄RjRzrwl(>MSI\x,m~6~84Ѥ>,hy[PI \YK@ji×Q#$_h`^cn#8~uΓW|{d3%RU-,zW,e"Y2*N#N{̗ [O̕x'a[Ƥ\k?<1+~9:nI_g&wL!>J/2):|FU=#I~, i.:I' A6_|'GZ_LJ:Q=[:D>8WŔ/g1<<;}zUnÜ|YI{Z䩐's&r<9H)!?cə'p{&M9`-iyLe|Ķ'rY'0R,%`9IXBʟ'x@y $.h! ӏ?} Y?xW[5q7_ֿcW 4x7/l;/|r<~Y|=,ɑ] #:>$baB<`կ~.8a , @0fiӵ@xG{V{oe:Z.PC/}^€8Xܲ-P9u +/K~@%KסnY=?,|xOVd4ɛrN~oY y nQ9# >8 t` X8`u34Va:F؈#X @*z{Y-IndƬGGf/$2fhqIt^ RS4T#ԫ/z#gk+CS]d14}@8tb͝Rtu>뱟.7a ҩ[G{ xm-W{ҙz_nӡ$>ؾ}*i???|9nhA-A9S@@{ҤQF ТKS[cKAa<#΂7@ ùװ;"H?T9V[Pkt~:!#>\l1,^fthv>ƹìKC ޼F@~j8x.MYҢh6F?Uoڞ/;Υ\%beG [-LJ"d:L ؝\[B°5xUp.,38?T-j@йΫpLo\.tXUP`(#P'ʌ$pH@:s?6vN6?ѧ>ux?Ƈ՝qkড\:lL;ћK|t Hy px9`4IF\T8=US?iohՉq3^^īѦϨgnv&%/3.zHȮ~[G''eQ717Tj;Iҵ-lUh-n:75m||@@M[][G~ՙ~&5_˸)RuhĮA48OSF4h8҂Υ*GH^|Ek?Ȁst:#|@w|kOixѣ#2pYK# tN3ݚ@AGuEF:"/c !4ݹyM@9#^EGWCCN  >Z?92L~a࡝ 3(Sنbh/COzk@F( _,䑗nx>`hGV|#mM`>Df L.rdd0^~nkk2*/FK??o_Km'z~Xq) ^A6/.5@mIZ{Lc#OFb5 :}@#H /0tH c1&~xo]:2D3zhS57?3fyu45>dcOGz huBE}Ork_-~oOv^%ZѯАWN. Jg#PK۠1:xy!2n<#4@z4ozUG<[A;*IIgQAK[d S1[sJJuבd =vҩ \fSs.WS ]dAǰą:A ]ZHoqtGYRix*'egGJs.9 jb<;|ÍhãR̔ZPQ<>'qo0uؠ6๒CtG΁W\Yݻ^|3R0 tt׌ -x / ӣ12yMǹ"sB[n⒧Mk M-e78oJZ>su76װ#}mo=ZK4jyw.RՈhb`)Z ^Kf۶mk z)a:E7P'C;G\c{;QFg{t;@jLөiyEωC/O\sQ̥9^\Nt x)Bg{2ĕ ԉtlhדL|UcxM_H~:ZU7f[)*GQ gSljUveՖ=ɚ|uצ/y P vyq=[4\`5,3+lT(-1ڣs<Bc[^xqZrwo W0;=ySN)]_S:ȵ7s) G/|2-S&} /<_~/7}۴ixm0Uv[P\sl\نuR_}䢋.,źǻukCigKSE [ QRorzІ$2W%;AŪt6nz,v?!hwH'DDrKg`NvGOho֬E+‪2W*쑭ʣxʎZMXb1k#y~WY$tX:/v{o%$G } Ƶ:HW> @MgչGpW((v'i0|tZ"e{/^uKVFSԕ'@4 WGnQ___bLdeu0YG.u\xsޔOF:'_G#Gx[neiǑGt"K(#~P [lt6aJ7c{+ 8i!UXپ}{5|`cP_'F`XbT|+H^Fi_:u.% M ?yV>7þyo>nsڨt nj=L<ɠ|qs \fxCVuszxf ;Z^= +C-dZB@Uy_ߵz(ݎ/zr;/yԁj>pժ _n@IDAT~{a⨬/{JzD'?A] ($a4иS3(0xHxL:ӹБAeut)(qC~ qqS4J6oVȫQUb-*_zwϺM0x{˦n d A~A,N/f,` Mq{ {r;T:7wk7US#œX|Ng´@;4@[ *Z?ȿt0f7[>mO,ئ#hu}~l)GkqsۍHI/@ Ͷ'tɫȑ'У%ч)nGn2br@ڔp .xЁ*{\C>:Sڍedyu(zSGm&-|Fجze蒎͖/dؐ6'|907Cڅ]sfѧ^XtSc6pKhFOSX%2RQ!-CƤS3i @"FXnbIՔ(/ASk:x2Fh()bЫ#~9ʯ\xSGt͓ M,'@⶿oMgo}[6>\Z)YJ\V#wG]h ꁖ1/-y|M?۱[{rnt?{k+.Ztg׸sX#0]:5y0ԷC<fHtH?_C/޹QڋO㥝OjOD6:Qt5Z4dLὪ֙LK7Ci9/wVY:t'r-H"G (; Kv/~ ܰ ꐰ9r졢K#S21 JkZi *V'Qp 4B UiΥiK*CwտĀhuVvSzW~Fu;:e # ݡcmr?i/@ɀ<@P>[[d>ȒU@s(HBP ¤ =!OX^QKM~ )5r[$|uM߿w1?'훺 JG%{n+ :?aک}8kDJgq#upDn;_8Xꍧ/u K)yw:D>u'밌P'vy-诂|S\s=nVtK&}xlc<ҍ#Khkﴽk!q@ 2#S>O2Sc$tj2I6x+· 1TN +uq=__ZSm)6 vҹmɋgGŐ[!urT&:m| 4~9'KxO'/<7/<`A:OVIm>:sT~^fvh«R8Mz[firG#=]?Wcӈ*|unޑw|8yԣ8|G%E Ϥ 9N맷'sQFJyaF(M%(M:F%+ÀUmɪ~q#+09Q%-0?v!t&i]BdJ9 -s>yBk餉7tFon'D>|fqfyu't!f؏}-ϒ5;F5f^NZć&6ιpű'ǖbR\seڡ-o!.Gq‰GT}I\]#N}HF1`E *dd2Ξ|cd;^1-y &r띝H<\Bk Y<+3~>+<6MU:"Sx~#]&w'ie~&az\' `+S' ?b^<Ve2L>dJ|KhZrg{',Vԁ͊P][R>li#p\^ h-!F??^n{zcO#Xڀz!A>~[JZ1=`4 ሂ2F*+ T\=ih/׊XlJBI7_GGC*okR~ _.Vfg%1ς m@r>)hyȪl>22̧D(3 &0'CCWFw_BHǧ2DJ[<8ӿC2uq&k]BU%0$@NGwA!t˜Q+E9!Fm4`0\~)J <ʤ2QNۼR k(P0eHj*~QzdpL%7}p>44xPGhhd) ̾tBC'H;\6$AnS.m r< q&DB !:Wڄ 9s4k;$q) vot?k{'txkw?׎D~d3Pf? Ȓ,9q12QpF ubp tTކ}H!;HOœ*O JTN~+ڹ%NO ,|e/)KI)K:]Tk|זӉN3!%Ud I2|ʌSQs|* mG7ӧ>oM7ҥoN <'B?}#qҥ-3t{DŽ@و<tz +AQ[F9w wZzHR~h i>BՆ'N:6F@2`ޞ+ӵ +t]-OdHn=Q$^9eQ6dGۙC?O> 2f6/dzUO/I}Ez/D.}hȨqXn+>I`IVCm+tU`RH9ɛѶ;Ii# v"|헛2#kͤM3(msil+ 溭H קI1L??2 xkɳ|2)@s}9-΁$o~3Okimtb41}xK&I&X}Jx^LZ#O#<@=Q(d%zg1^C]]/4' NRB.%|2fj):^u2<ڥBmhiK]1`frqaE/-kRۦ(کJ\@~<kd@-? #u<d\.<{1`iD1`v..Цo%-2TȐ%Úлv,v=[>phSm,󮻻(OHOkd ,VD%Ljg0 h 7pM`uX]0x=:֔r*?ҕmR[~,\[ޖfm`ۿm+!uxwXM`;D 4403[(V[{aŘ$Y!4XcѣG,6oYW?. x_Yse!)iG12`Ui޲*/^{k{׬fBx4  !a<bѡ, Yi`+Sl'?zYzzKc5B<+|-&[7(w淘zTw-u?'+ *_.XF@k1 XN MC624tb< ,-1v_,=+V׃GnmYmޡ2V7;`ٝuݹ_/Ϻ׿.C40h@,,D:Yx |ɖsG^<5hT ()}t|PYx>NA+Ms $xC%ޒ#B;t<p_"N~%,`a!'\|nMݺK`0]wM_zAwk^Y@xbЅ3 4p44,Uf'EDcOl)VQyF/,4?9<LY<F\ XXcFbù$ V46 Ccu !&$o&sǤo$=*ÓG[\5]JA?o@<׀g`Xȃ牡8V vy-eP A *,%_z =3׶1]_>ś243onVԈϠAx/!O7 ]r*|8 eϠ^Po?!P6AV((hm߾^C[8 O.ET @Y@>Xi Tc?`eogޯ3Dd^ |Ch "[{RRhael' `Շ X: Tb0^?+J}Q@3F_z2{ 84^OX1P<\݀Hp~<\j~~4P+e`L'cR*s)=]Hky0h`40^8x/g=_|蒞#BCb4lz_w {R& { Po x}Xu[q~H_}~.(X ܱهAV*`^S>Żllř. Jwb @N^h/o,v( FyF0>M8C>xZ mW' >:xY;_8}wvu׾U&XAD D 7OI2\4h/|}5{n n}n`XiX{ &i/>;7d&L& ׼;o]wDֆЎt'1dJwd V"4d>2 &>C|#@#}ppR~8ЫkL+ׄ? e ! Vٍų3sXmY'{2?yVÚcJe 0Z@'4mޜ' ~Ф*&ڵFLڷy\a)34\hvcfz'JOߞO8sf2-$ieQB4 c3'f^P\d殼ِ֤~pYʠ,^ ʼZ98zk`zޏk UeUYn:A0Pc] \sMwW@ Sdowtx g/{L .N!נA&k HZ=, Ǹ1{Oߌ%+MBn>rk]e(sny·TyMq71بZ޴`xyJVti6p40htj-O9{ ê ~L`弼@c6g:iȹ(dܛa6@@֕AA4`>ݼzB95)әm ֈMr#*e(Hn9/+Aj>X45n8!m{5/%fXI'Ӹ2z-1yO Ȣd,h"hmJyPA! X=Ec!< Zc=G9]|07vO>q\V xY.,!Ȣ>y eCz5t'CC40h`qgtp옷d2Fxyx . lĚ,GN.}Ȃ s& v)Ty}LJ$ky~-+uzfr^ve>Xaݚ'7qANZ50~A^X( !790`[ym9pAF+|`xS ^Õ^0zX-];ҁE EZ/YGbp^0@0B葅L#~ ~?1,!;k1 >$F/('ә]eSR:ΉvUŊ8'/SO5,eUɓo}YP7=vXKG`Az!p"',$+lq0CC gCVV;pNk}q#,1cEҹ̱#fJY q"A'"O$t>l{EV#K6mϢZ7hmofP#lQ0V# ys !0Ԝ{v*aQk+n8kwz􏜐'㇤~e2+5gy)D3g#oooSN )'dh\SVwoȑ# i8 5RŇgv(?|Ć/RaR_9DoV#\Ve[L\8L1P !您I!/c%*Ґn|7vGf_S6dFUEOM}.zlݽ}܋$ԓW(fC`8^86&#nح| C2kGك؇Wׅ@!05],e~ 1,}bdFIvmVBrD9,cmYQUް" @!0?),shTC2{MtQzl2'g)7yK-;{oU< 8Y8V[&yfѣܯ6xPu/X.K=*| 5Н|3w֡d=&/^e7??e 樬'ӿmIֳUT}>aQWTIb!ŚOa26aΈ5P gYů'Nh/ NT}zjX7lIm8ޖ_Jx衇MAq,ئ^>nHj5>l`Oav[-UT}v_&noj9Lz$bǷ^{6DNRvR_hC80OlNmYJk f~k|AyīY"n̐z*"AF3ۜU&=yK|7eCo?Q^Uĸ?U(B~ M҅y-8U( mjŵ0$ b3Ҡ'hz׫T3`c; JZŅ@!0;!#iypJf-g4V\y+ %B0?c;sbG];mSs 9|A})abb掯DxnF`m],4H^P#Ф't怎5Թ^l1Yt5g rXF9: 'Ͱ nV8HNy\{?LNݼPAYn(p71X`H U&bP6{aEj)xQTBTʮB`a$5MasTVVx)7O.!w 'M] s;ZຼCPDNX!݆B!IoNglv˳h׳ֿkAz!0sX֨y饆Ze Baq2&$%NL(ǁ>.-ĩCIOT:2&,fl`B[[fl,{ @11L  #5Jo_sEYdt) %aG}Զ6?NmY!/H5[o~nt>䓭 o>[~aԩSmvm?-gZ( (, G-Y*=#%HȊw{k8uCXj=E`U6Lgܿks;Se}KY]siÊ} ?zڰoyye\)_᳽T弶LUl̡~FO>dSEHu_@R7pCS?~?QTڠᄊ%ǜUe"b 6}㎹窱hz$ hCUyFlD`T%ݳ#{*fzyl*[\c uѭg8HEC(<@STґi ʖMTա٩9CJ?寻FY*C`#+{FVH znJatMEZkcV!!6%dI}r@\:Z2#\(2䍘90NCHTO(/٩7} R_J46\rKRYH<*Fl7L{mYB`ng`($X( N\K97df#0ǁX#?ItMH+3)T 15d5,ۋm6 4وϬM A=\("Tq!0wwsk Xq>I5!!^zʉSFz+#-eZ.Bu(!$'VBICpӎy/stYV)&"VH(PEP.=:a8}7_9*HHzZ2ݼq쌊z(,im+֎XBɗCK@;ڨP!',lݦ^QeBun%9Ө3vw>붯/ g#eedBTʮBBjA[B4m+b*>oyə[ٛn+(.E`! Y\)B\Ӷ0ouܫIٟ`F&-аB`Z+@ki;Be >u Bwq*iQMX+F#pL~bСa[)+p-Np>5ړno"MԶ2P_n!(-ˌӯg}?Q殖z}9!X%CzoۍY9q#<G|aO 7t4_x6ծ/7b;w{o뮻B`W/;9B\8y+9l#+S92BhҔ5߅dka㴆`-$%OH&}kʣ|PN\,agNWUkVpo˂ B0HCLYC^CPB<*Rp0uM$t ԡrMg}$<lF#x.j(yBq+b )&8[6#!9y%qF9kEV~Qt6Ƶ?Nc؀<3]{+"}pQ+9(MsnOVp~4 y[v~=m_D+8SMSv2{8d-(Z~ `:.>aű5jBZkQ Q=r ½23dBh2 FI[sݤY*..gř)Neu3:ܛʽrf fu幏qovbJΟ>dm!zCgB?iӴYe B`%d'h NJ2-ܶϞl0SG{'{g"*df~&黓}lկVYf VBܷhIDAT0s;=:;^ݪwRGNԒ!oœc}E IE1 2' B$4X]: VlF$) 9ýgPFXFXNoMfd @t5Znqzd2'pN8P{!o=쳍 7@X@3j8 HU= Q^TW4VB`a! 9$eG-~C4ll#5d\FVY%ihWO 7[s(GTG&~,B,iF%?CYW N~JZB<ґtAJ  N>Ȱ:3AZ!2ݟ:P𓲳ưPq}d> U"8=U(s yGpVq nͨ Ŷ#1FC(铍ۅ ;Ӗ(D6T( GLD + H!DRK8C)%]P?:[6eZQ z-F B` w ?@2ΣWyT2CTb}wFiTnIy@o#A:{*FOXZ؍4fɛn60ح=ru]@e^^.\BfWJ!P@-ʒB@*(6"[%@!0" Uv!PlEX(K B`EXBX?Y'ZEYPcQe}e[8j{|Yu>n%@!2^O?_3ad+:* B`z_kM>j ȯu+( #UW]PIRW+{T@! D^3e_!IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/cm_desktop/images/frag.png0000644000175000017500000000301212346515436024064 0ustar felixfelixPNG  IHDR szzsBIT|d pHYs : :dJtEXtSoftwarewww.inkscape.org<tEXtTitleGeneric Script(tEXtAuthorJakub Steiner/!tEXtSourcehttp://jimmac.musichall.czif^ItEXtCopyrightPublic Domain http://creativecommons.org/licenses/publicdomain/YIDATXŗOhW?3N_0QSbFCKmi^^z,{/1= \EH bOl2&͒dwvvdv{3|ykhe~Qu@֟}QJMDkR 5Zk<ϫVJxxW_W*gϞv_۷Z#D)a5} àz۫,uݟaRD>G)mxW#PPbYVC5A?Y[@U}A+'Z7TE>n&9Pq7 rr)inua)= af,hvM,Ah9sÇ7uYSК9011A2ȑ#LMM͛]wle/pde errwʯq?hootvvr5v@PAJZ.B:u qի6d\k]/.`ee0XYYѣ P)@'MlBpAڰm-FFFӧOOW lܱUn``)%5 !x%===8q>666H$8pÇ\ ;ҟT,X>hkkc{{!NJ>|xcxx |/^I<|rl6KOODu2 RJB200'aPR(x-RabǏyB! B#pBݎ!lUgϞݻw lhs;TX Oղ_PJzoOu IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/cm_desktop/images/cm_desktop_systembundle_300.png0000644000175000017500000006263112346515436030471 0ustar felixfelixPNG  IHDR,!g AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  7iTXtXML:com.adobe.xmp 72 72 5 1 2 3\@IDATx۳nGU7gBE*k#rC!섃e^UZeYZE%1!HH)$`@ 9w~zڽ~:zV2ֳfѣG{v?Ͼz ?;\f}Cov1v}GVē}a6llF%Z[>ٶ6G}:t0%' :57m 2+Ы:uYEu,7Dr-IM:z7ԺDtGl~kG?78㌟ڸ0?ól` & ^hOU|kyՍپC=܀kﷴZ0j[j̽;OOԁYg5=?;{kߵBO;%iTqYJ"x_6)7/h{9ϣ[+=yBo,ҖK]K.%O;|w1@>w}ol#Vhi{f??|;ߑ@ P5|xWO}S<8Z?JIcFYMaSycܯUflvzl==Hm/:;'4ّٝ>8{u7{Kyܾ5deǷo_ǼZ7FӶzUZym0`D~ p+?a@ILǷi?{܀2.|u-aο>e\#EtƀZהWn>÷SuiRnL'})rZ@Gvߞ^g珿3o}\Gd;#Xg'eN;sLGqɴ/BxWdUtL31qZʦLdZ׾^h 2Xm f}$dɽ4՗(WX*^lۍҍDX,Cj]O[M|yyI ڍ҅zңcb6;3mv0;3fv3hkm [}O£j O"`gL:V[ ayb<)bxycO|[Bx/yf.BԀ;9+2t[>lXKs9}ꌃGg{gOzSf}=fJl܉;%8h-;1mo{2XO?}CP@4@ Mgr?VEO'/BЎW/{[%땖zhvC?sJÛ#;,?~v ^֙ӆ7,7;sӆGiz/m]y-S4_zyǺؾ~]mr#M9^ɶ*@2cthJK!>Sf 1'dyU/مֱm|cI?U׍mK~ =؈4me3i7luc=;֛>fsv{Y(ygm+ t{ MMI }ʏCIڧvutJS~:ǯGat;טf6:y<2o=LkV==:}}|Nji k&5_Vu1֞Ɓ > XTLy}rJC*wm4f+khk¢O]ҍwYN5EWm]95,bE3c@B܇؀t$ ̲]!yH ][o~ X9f7e;rH7 -,q=i|Wb|m:ٗʩo -N{<$t=hen喙ӟA47ӳCKK-ݦX| ހ-`4GuS+W h?mBW4P`eC{ň*WӬ7̓gĖנf)@ OHi!OoB `ăIHLO;8m L1,_tTu=oЀ1*)Km #&aG2Z > c!L(7xc%r~Px+#)MG@&-!}_^ʄ ;|Lm,>OqyXIh$^O>Oi/m/g\Oki4D/MI=veB}A0`˸H*| "KC|+JXҹ 0O8p$-18]~rл(SU5uGѭG3UKf p:2=Kq9tSyhg\ݽ7ٹ0Uň|ЎqITݺ`٨ ,X$րyBY{QNƀNc]qA4ZF1GYFq4EZ'S.w,K)#H p ?z{~iW <">czB!M©ig[la>n󹐾X,{#xt@မNowa L}H~lNv1>t9WG7og&>v^\ٖ҇^&鶳hCz5(?ynӯBNA^+fm,ZTމ0;b Fkz:0jw X =#d\l30%Al ZjecS*@0~m z2W_}uc@3p=,#@XN{FhbxpFnìgdAy/m>7?eyMOO}S- Í>}CN9;hm2Mڢ}s[I6Z@W^ye 2>=GNF#^ӹ~qT 3΢# fGڱӛ@C99DOm7Cv4GS:cS/y(`M'۠!6Xc2C`d8 :`k`S4Ai;ٟ7L!(.y0 oiim3RzQ#:62q%axdM:LlLߜ//5 P #@HTܕ,W`u]׌PX,{W:zȘdorj0"x0"` [^=]c׏KחhFm'POtM@~쵯}mk }~;w6ٜFecZzԷ ۣ_CB[Ryz>caH:1&3̫`'j8Y`80w" c>-oPN QP ]Fn#GC#Pe0dZ(Ȑ4ubPE$ Lx,x@G aXoз_E6C҇N^3%e/kO2{SscoR'}h{rh 0ti2HTD_|q3(mdPte;Cb<Od<" YFx_#Sф2dms|ԅ֕YeQ ~VV\Z*v8G04 xRVש_v`~e}>4>bFnkxƶtm%P~@Ox[df¦+F塩_N}YBhP<uN<Uye K>h H'{eLL{ ̞tmNo+N}d' }_xO6rH=>u2,)2WN4BҔ3Ѡ_aoG,ƼФ\@ɏ.}DڕG_I Nt=2?n Xq}΍H :U{3<=xi qׄ#R|t2}Yd4 O⹮UO˵/^6e cW/|s_2Ie7C7?z4]HY0g+^6let\O:x|~@E{%WڳQxU^i4pj425*6\{Q0k:nZ]%s`"fFk+#c[iO[x P =ySOC3o^;S&ynx+g/g_ϣG-9M,k㈼nTqߗǀwK;+cܫ+kFz>8i.W[ \Hoż]-kX[e]JXo]jo㭗2y<xK_^l4(Wvy}4>ӆ׼p׏_H[P[ {S^O[\51V :> 4J o| ~ycaΛ!Hy4'XQh'Ta7 >nfva= n6h)λlG:5`q=G1!sLDD3>`yRǨ i4k[PV˥>ys*10yZ\dR{x1H&-)7j;e7{\Sk<;Dd14 8c6|bb[daEixdȦ9z_" gn,UY{5ojmީU9'ӳ;\? 2|RY >ޒ1⸌7@Hc%(K՝^HYqi$qRmo,&4o olΩ #u`ivU :s11Jい4v +cZfe3ގx]y;w3{+_6nX3h^z+L<z܈L;a~휶Ki:g%+ 2>w 1ǗsS&RxPtHң#>~>x*6(28-eէ/'}fSY_?Hpp=]ONpp<0} ^:WhO]vYACǁȤOpCI;<[VcͩMgþ6J u5iiᐳN4{ ȎCkW9 lRl_}5mJ`FV LȘrfx:`bdAw|À7h ia1\ODZ5Qۿ}{;n#y##j:6@g E0rO:#RCY {" CuNxF`Gfh pX __/{l@/.d2vKS+kryz81|tc A&_PdVƊqf^ @t0ƪ:h 촍. Č#A~Ӏ7ﴱ)o E l@e CR 1'7 PkH0@ ==۫k<W,3ƒ2:GAx!O2 OA2< VtӍmc ̡Hy:h:L Q<2C30OYԁ֓?}8LNM' vHyNChUgty;Yc,ڃ|Qq“ydJkg y0y<3 : |zS! 4ė`7$Az xª|'py=ɀ:~K X#( oIH9%4qn݋Wt#-w>cF݌|SWd '-Xьk }ʉU/ 1"qN[YtL@@I<3Hg]@i`{4~AsD A@i4(M*5[qILH8I^CdOzהq׳^䧞ymȂw՗M^6,}_⥁S0cM EAPHq|.lU:LG#G_/0BF*ۇōS'udOY!4fl'U=q|jXS&qW~]E/)KR^]Սˇ&˜86}!X tX$.]cq:{bN߀Gx /MEmAH}x.xgJ;+oM+gʠr?'4)O7)xړuN_OY||- UmV'h#2ҥ2Iw*Е,]G%p(}-R ⹒/m}#-h c]O!$F=3a4 z3>q[g %0rђ]6wZxy+GRCagG|lg%vD' >.qѻş\З8S/Ze?aSYnT?GFQp*>^>ɝMGZ .?JCƐqu9O_h RBppSd;m؁_OW@ 7sv,^,{!ؒ/0c~ 821BF cveP^%xHx0\ix>|ԧ ;k:#ԥ-:G9r;uw-]ەOв4Gr/qnz?8{[<'ސo[[k#/<%ph*4PDfyP<||ܼP>:q/ڨ,X\1J[рqieCgΣ` `6 2~| *K2vOs@ r20nW ~eg8ӠW\6œvh8 f yh_xVOx.ɓ @@Ihx&GF|툸Uu3Z+&d7 ##Qi7o@0A! EOk3xz`3?v ,dvk]ё3wNgu:C)8_ΐүq r8'Bi`+Ȍ!vf8yY'{On| D 0"^2P* Cg,@2*rHeC̼FsO L)W "Csx7@w2Q#fYԉLdpxg/G tN/W@0rM =UNJI?Wҿ^:`"+  k<[tEh*wP6{aW28 ,LM|Я6d(3q|x<6k>ME1fx />FD&eCNm`69ypʐYE:# x^cdJF촓|x^(O@oK6mS'tuЉ0|Sk/@+0iۘ|L~x/>I<}8}Qu-ؿᶯL cGPW$KV5`lK>pcx,Bxpg707zc*=OC~ϣ2ЌӔh=c÷ϛ˅~J>}'ߋmӄv .[)JY }5X[9c/kQՓSS XD<N~O/ާO^x߯+2k%Sw'2ԀE=!kӀ!wV?|T>1yycuJ߇n8jX]޼|dC?%Itދ K]TzSi8([Yq~{4/؏q`oJ_|6WGk+e EP`Exo0>>i'=ez;4oz4LDY/>Mm]zu[1X+224B{Mi;z_ھ` : ᛾TN| zyJSm#5|=ЗumLsh=Oq+߇qebސ{7oeWK f8B*\+BƼ^`h0 4L>^ ) `#c%E/~'=䕦#th ޲'[֢J^*i{S}@.'ݸ~zwJHC\}vNƫq53;[o5ݘP˃MU#0!ABWܦAkր%V8&Ͱ Vg^Ȇ/l6O5gq}@EԆyAӸ?> @סi|C-udՀ6q s~f'@rԘuZEIٌZƀ2VW؆Ьw?Rƹ|38`9͘n7h)ϳ +h^S"¦iz+ao M=ʡ#ch7A:%Y嵶qjp{B>*FIl 0o ƅfj c`1:WʩEW2JO4r()>$+:1hގt I]@N;^:[}h ~h^x-:1/--uO]3Lu:S2dNU h_O":[)~/ZăEF~_a4@8wwdžqc2~9ΛCa?m+U0Su xg%td5NW͑1Rǁ8f jt̀i@10M),ȔξNS# SFK~\ͤG40!qyx)OOf t | |<"^:/|t@ GG@"FM=,ݔ=~C'\}vyP *2ƀ>!qӍq윝sx?VWB?vi֣`_dg{ ʀ|'CJFhtWعf;ˣEGqU&}F @]u/(ߏQiO6 sO3ޛē~=4) nM=fҏXt:nL<^c^٠< Nׯ;)c.q1>ռ oh7eqU%B0Uf~+%WǤoF# =?&\\IhT;bʶ}h>iG,yyۙRbpekZl5rl_LݒQ S-ϸ<3kǘNϓ)iI qwJ4P XɛE&EC@^Ee`P("um^SV^d6X1@֯5Ęcġ[F =JͼhG?Uм.bJ;x+oێ=~ {lbB1~t1|Y,;,MyH}CY< j;X4l@.#F֋rx7pF D# 2$rs1e"G\vo[;㺝RiȌ\}@բprTѡlYֺS )hy눎ЯoSXn!ڢU4P@dKA{FրxTGę&Z!a*؉3 ,kMQzs@p⥁j H3,=XX; sZ4Q4Pؘ2+Bay×TT԰߂znUCi`iCՇw}A#Y0=GGd(zFZcZDJ. i U XO3In\bqvg=YmBO<<zh>>nuQ|-5~{Ҝ_ˆZY˦Taѡ¦[lLk[yGV dWv3~_-GSc;v^n*ؒ? 5iҏ `CGIeA%pbXW_}u(h}M> ,?U΃p8me\nkg? fi*ϊOFU4X9wKjy%4C*/]ƿ ٮyh "~əx^/̷ZЇvY|K L %r@m+eYy\`ȯNfؗ}zu׵6xZFЕJEw@,,ۄi*x1E1FSi~ox4S=ޓ2}[[7-oyK5^c@i4oi gҽ*0o@1>{xrl4 _?:thնf}e9)LZ4/+|՚VV+ <57,WֆҰ 5p]ӨxVƖ9Ouыv/ߋ/ `y,9~+~ǂV M+#}nH{!")!9K 5X/X%xV֖`v(O@i`X,Ɯ) g'Ou߭d^ bԑQ>xɝmWwUSi`w5XZ5 >ĔHY7zK{[O2P( M )?{95qt >@!k3Zezyi} 9ժL^86mx 2U( V<,.pyk_+F8|gc;wGͯ8?կO^`kkd>pFw^G/  4Z6m%)8~c!n 4]~s뭷60X@̯(S3-%v5- <6R`u\+  %dܼ/TīXv n}mwzL|CAk_Z&<.^vvȞܮ:NW%IY9vd(ޑtfv2rGvy5 SA{_ސtv/{2tp;,h.!c=Dcg7}|[2 ^vijO@SN~KZk[*J`G4g/Ϩ}q@$ZSm2BrSu%ioK؀'KP( ,[B4cϞ~<)&ɟ>OyAZʜlMW}8;m}i474 @a܉)r/)2UWNe]ū4PY 7ub> ^\ш S6q^zЯBఖvE]OJX %n>V()SAF6qͲFQomo뮻 /e}>&Oz%dhHm}(Z _M_Wgd78p6^ٟYs`wdhHU. ,tllLS^;>w7M!:W( VmIDAT@x67tS;+G>[+bZ 92bσ>hQԧ>5{ ^Bw َ^ntn9ucR5yVy{p)ڽ_5J/ t'./c6 -_]|+馛g~j7馛0&V( _7GU7iʀ)+I8~#Mh{pykohki4`ZyKHtD>}Yr2'nR&W8oiB8_ÔsVyVF*^X| ̳U[M(>S`x?UHES( z y'a`%Qf<*3Frk%ϼu0}b*[ƬhLM{*PxoؖLB.M\'y H˺>-K^W/^fzé^ֵ4PXl oXa˸8zx6xNvn bd^ك4[}C#]Vc| )ZyG)^KW+5y-gdy9@iI;<;}^g?;5xeATV}z4= @$a1dF}| qNdmEl4 r']p{⁕}PR,"ZE?W]󇇳h! Vw Lp?P|aeG`|s ~ #`Ûu.cXԡጡoXL֤L)c:~LUy`~_e{/y[F@ϊ(ȬU=9i gh5-kc7W( I 4{޿l}»dq1׬$G'˒7 SHxB ^x)KZKK/ hj,"/Ou- _]8(/VsCx:?f0H" )^>=ѥ!=JfjCS4P[`#N+L970] %mcxY@2W( ش~Aǁ/W'6U|Lv;,m?vh^$_;F iͳUkX)3 <7`'drJO{o 8SxС@Ł 4Ae<w @ :/ik6ꜙ%HV( vWˠe}+%)b2n$yh4*_cch 0oّqƐgO]h1߻`6ǺH3M$ik^r32lT֢+ q39Pc֖x! 3nS% xxFwxXqe,!9c=ȷ2<~[@b p^6gK7SV'y+&`ȑ0Wד4(Q4P g zB.!'e<2x 71`7tyG*/H x2xs|r>ꑾ^_L)ȩ h`YqP}k800ܣd4 oM/28֣xV_>'+V4Py QX')IVְ0{arϣs")#3BuW(  q-Ůɾ Jciͩjf*475gjZq`Sy\/^L_yY#faS[}i4`^٩W*B2b ʧbS"n6zs~\⥁k`U>?GR `1Z Y1 `.y(sN4=ҁ]. V  2O,+J;kޖIrٍPvy`brV0L#g 2\xX GOBꔦF^xD\(eMMq=u_( z{k_ukCir/nDW^ye; y_smyGcl u_/S_.pMx #PUZr/{:RzsdH.7"nv}ٙo=/x76 袋o O]⥁@lͳ5,U3\`#|:~[7bJxW<@fz(˞ ފ|xOo~sbx: sn{b꨼}i@+<:!i䴮Xj1omv:S4P] z h%A&2{wHL)fiiK_\|,iW,yUC˾Ig W!pC<[$|p%o"+U`e*?:W@i`40ew,L T4 % gA[aҬ[G@P=A<8Ņ-?,M;AF("荏xY@i`w47}1ͳb̮LW&MZx;G:>3tI `aPOE K@i`g5aįsx|5,xH@>z:i_ 7y-a7)= C`~#7ȽQ+ N[mq_,7%Ĉϻ>>+iA_eLGJ{O^e&WV՚U( YqH85'7'h7|oX#JR^+4PX */l<6+ɀf&2W6g k}i4m^T+hLtS0#\h>h>۾䫷/yWebJr@i`ok4Lp&6:r뭷|ﭛ`{4v;͡N`0*qoг> *>JogyhkǧBi44*-캖J{@=8mbm9xJo) .yU!a?ʳr~9+(5?og yeNL'on@w54)V4PxtkwBҕEw.(;<|-47S3:KǕ3*`LB9Cȃ:@0onXYKXv٣-tœ&^4P{UG5@b'"}Y1 L,xB@YWJ<Zj@OL-*S4P`_җ"~YF0~i=@-yKhxN^> h+/JB+PSr㽡P( -  ,e&_X؁ -y 0T2B18'>.\B#X0V4PS80XnV ɛ.Mi7r uuYQeּuM@i`Ohm#VV0Sʽ(\( @?Cm\+ xV^~Vx/vL\( 0*J@i4x(Z>)J `M(K@IIT( LhkB1\( , OJ@i`BX@i`4Px}RJ(PL%J듒4P@քb*4PX< `-^D &Sɥik$* &4P5J. OX'%Qi40 Tri4x(Z>)J `M(K@IIT( LhkB1\( , OJ@i`BX@i`4Px}RJ(PL%J듒4P@քb*4PX< `-^D &Sɥik$* &4P5J. OX'%Qi40 Tri4x(Z>)J `M(K@IIT( LhkB1\( , OJ@i`BX@i`4Px}RJ(PL%J듒4P@քb*4PX< `-^D &Sɥik$* &4P5J. OX'%Qi40 Tri4x(Z>)J `M(K@IIT( LhkB1\( , OJ@i`BX@i`4Px}RJ(PL%J듒4P@քb*4PX< `-^D &Sɥik$* &4P5J. OX'%Qi40 Tri4x(Z>)J=R F@i`q4ڷo_8p`ϒ8"$cQ .'A}7{ #\X@ 4:xaC=԰駟ހ{irHcTf|n>f5|jvi`A5\M8DVIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/cm_desktop/images/cm_desktop_systembundle.png0000644000175000017500000013443712346515436030113 0ustar felixfelixPNG  IHDR"2 AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATx5S([K,.Ⲹ+n"ŭԾ?͛^yd2sOF*4߰a61b3lN:9mAhe y)0l=U!ҋխ+W=i䑯´2LW]9~)(Q-h+[Y~ՓJ+L+StE?E*G ʨOuBGQ¢2jS]И VtK.7Uu\?t3+ra#(-kѨIoT]m4vIWZ5&it,BLhگz6Ԣj?j Zp Zh7;u8VNtF!5l~HŽoNC 9iᇷJI#QS7OUMF9j맕Uo1w5$wqO xge8h7_T_85k t&/$m|}°oW72 ZqIZ[5_Tu_GVDC}[c'pqA+BU..~BHS9|+?8a}釼~5yFRWIˢP^'Y''G5A!SxJQzY*AYG IzEW/ !՟&3e)+OE[<YS%#gI/ҲHGGˈRiòITo\/+;-#->W91É&Vz㬲瑡AA#QtTN:[mY]zGZOIiꋤ4'WēF9L;Cy*4gIi6)$4A;cCIV E ¹{:w`<0`vx%SW`Gx,cկ{POD a^mH|" a8ʇe4#]mq$7,Q"W=x!xYKu-(//bBYa<^.!S|+˨Z!CP&y/K 'QK%]mS9/nt0iOOEn56v'o?/o{{JS-0Uh\zn_q~gGtƵҹo8xK(9JS9ݗJ'T0]+UO{;m6yZ!i"M8 zРA޽{]iqd(]J%]$IW(ʆaXVu,է e !#~p>ZŸVbGxT_l5eܸ-_Nw[ѽ?P(%eT_p xJ 로UJ&!IiS>eU4]B U9Geև +TBS!t" ?Cȷ*L!}t+Ǯ#ʣL=O'Y*&]D]408S/qBTBx>BɣUV/P>(#>G:OrPD' _ կ/\<\,!yJ e(0]ׄ=I.Hi\#kawoMкnIa[Ɉ#[[j7InJ{XN>}j6wg=0&",>=@S!<ʸ!_qB-+OuaF^Yyz>%gTa>q 0$LXH!J̖|^{(GSRV!&}W^+y[<~$~ "K2^ G\2i#T/qI(ْCdOeHBY\ OK&yC>AÇWf_>V[0wFZ{7_,v^]˕p+"> ~5X I؉Gׄ?q&tMh 7|j#cQ-4*`"Z57:y'ȃt2ȓе(J2 tB)-l LkU&QK.XB^Rʆ}'~U0]q#Wq ע04&6鄎r>2Zi &$-K%Ƶ:O/x e 0PTeBŧ<'> oiDe eMF]>>74:[xwFW&b4'ĐrQ<'"Wxd+ܰ`q~JZiq9!0_xYizk߂T•8vqɣ*O)\+-.'!+/˵TYhl؀nݺ2!R㉋yr; ;/Ǚҭ?m7Vc#CvlɚIxkv2\J8ܥ4G=I#|qg0#E"H~O Lnf@X2$OYyCYHqM0eOJȖLP;&Ry /iayzQ|\M(-և JU?aR9ʥ ]2$OxT5t|P9.&JJȒLBP' ˊ0]W< LJtL/ccӽMqg]K"Y<ν{Nn~|ߵ5w*,>R?4oZ UNrGD ؀ƽB*om7DH)`LGzCI&!4?P|Ic:Rx K8i QrC5Q?UHD PZnP:l\aY)(%_<ɑl &t`MQCaO^yCi C~%[!e'_.UVW\/%NT?!?r!E}xUVe0']T7jiЅt?*/Y 를UP*MuM/ QzX|6&R2H|^hlc6ܕ/߽n*{w?|WC\q~@M։9+R{x_уJ':t# ttmܡЈ?Z#/a馛}0dM&`^@w 0,*oi7vJ/#TBH@ӔGz}'2+9Bs-lMO \|$K2T'']25Iv2 I+R*/ q& %B>q9n7la6)ԗxrpS/[3t? ƙ-5GePʻ+F pMήW}]]Εa1,q"/u<iar Q>LǓBQUO'~VPXK\r}5dQA;Bʻ+FaSx\@˄N&dʯLyMRPFg:Hed#8\3xi7BR*|I#/.[i|$~BUyBxţ|\*#~GgJ_Lxt4H$(_[OD!^­ʌ~mH}]1wÇa#u] k62&xb?Qs˸G! p`нk;p'=0 ECFxGWJC^?y_-HHpƕO(՟\C PϬ?H|PWNt.rb"(өgҘpIf,xxJf ƠD\MƔ'rJnjyȓ~!K"O_| IŽ2A '^F2<%ʧH}"SezT6s-\+$S^yҝ0别J,ʄyGz,aXגA0dԆ ʐQF|$Y^2OS 8FHP'|<!=̓a<,G$0OH% Z2C.PԆxT<2S-LzU_S1* jdw̨J@u.i:tNZ؉䅊KV('#/$Qa^<. I.!|@W^X B;Cta$40R]']:ëk'ODaC ۆ |嚸\BK s-9ŸVY !&$ 9 P0_eC!2df SpK80 q 1~4N됮_ğVY!td!G<^T>?̗xPa . SpK*{+؎2^aׄ>ST_eIW ʆ3i*'=kGzHS^)hP?U'yqlG\LBeεG\ʓ|B y"%[iȀ5KG8OWYU4Ei*Mׄ!ODBްNeK {3O74_S4hb| H@ȣ Dɍ4⤫|()%'o?Zuғd$çt%6UodyKYPHԖ0$Zƈ'il% Ǥ0Οw x?I2C9ieIoA YOKqkl^[0$Rgx LR,P$yqCQGHzHII e2y+$M2v%o'sXX3!Vą~P\x8eԧu'/yxr>#$xREaaRZi4(Ixv74x+!`!`pZm!`! X!`!`@ f,ӑ G)}02 C0 Ct.+Efew=Z+_o˺g(//aG}M5TnrK.d^ʿdbp>sFz(~?7`סZL!`!`,^z' 䮽/­P6l3SOEyڝzw .첼"u[љg;\sl#C0 C0+=;w_|gu[feQGz^rniܼ;gw,{|:n_l3<}SaWXaG^-"ݻw={-QomVt3KꫯFWy~ڹ˻_~9Kd3 C0 CHB|AE[}?[yµ^3wG=y_nzꩣM6oܧ~c(=)24Ӹ}ywǺ^zy֥Zq/!F?.hC[,9O4D.}Y73:M8Q 3nwGρ6㎎dM܂ .=\r;* a}u׹om6nW? o]SO>YgwM7yvW_}gP :yhbHڙ׉,0 C0:6|svG"Wd ƞ={%;{0X M I]gC-p70]tQmαpg0H8|[nOAv5׸0$7Sx:Yf܅^L?ǃ6xcoXR/1O9qNC?x#婤^|EΤ~˰kC0 C;` ]HE2dELxM2d?_C9ĭjş~)*WsEW 4h믿5Fx0  . {: K$b b zX^fYƢCޱ"ċ11X+>>}D.vEiDg7lC(MO[z(^J@fo ,,g9 dN?c(rp˜I>t^p/#^ݰIrΤ:-0 C0:*ˡ#i'dÓ/6W$n89$o_þ8L0A<_C9O>ybF$jO\x㏻?0Vds1nEq;oTOZle-C}ճ2m/|Woy~WżKoZk]%"uuulh?-1-0wyקO$VMW23< 22,>sW]u[c5gYfX?p?(<;\V//۔eLϺgq4lj)I5\1-e/_KS-E2ei=ީZX|Qy>#r{_ Uҕ/h0G/ix~ov;kivpʓw98X,K﫯rn_|Ln=H#~`xnf_:^|({;|;f}vǷ) l<.s9|z|r7mccE1ewG0(W_}u/v 4(SimN6zk6ϗ8Hr0)+WYxG!Dٲ ЍW>q޸)&1<뮻Ye&+n;&F:xy4u:K/0 :VrgwEG\X>VaX5?Vݻwƽ솲G uY{&eƷ~{j9"tMlX?uܔSN)ҕf)0(~O?4Ø6ȗ9!+(d<ސf5+۬qmb,e/VX5fOV9ikx€ꖥK^x!Y二,P8 G|G{^CE^{m~}>?{oJ[yf6ۊ|K|_TGtWO'{oUx8&tR׵kW/:ms! \н;ރP<wq#,u9im.aZõn~Ȫv&=Ȇ򒟇w]vu0K&yE6 4.&K.~,1KjW֘l #KVR!8u%_e+s" gax@a𱉚st&z|[g#+` 0(v<:,{Q'SȲ3u*oo{W^kA}/;BB>{ U9i\Ցq=z2X[ruN|ayY{7X*سg0@FLxX l r``BYm ?g>Wa@P6rXrTw))A>acၦ;":>,3q8`b-8gI]M=;c)iImPtBRQxgKqf/hHL߆剧a\V,:)+x="/^*0 ~:7m~.[aբ` )Wdr4]][>w4o-e믿/-i#} 9|s=͘cYwsT^!Ğ"C%qq:|YT1XbG[9ɏ":@u)JIf 7߹W.<| S?=~zjL8'p}ˣ:cxm &sj CB -C W qR_~^8$ ڸN;y&M2Aʱt+; {hf# jdg⛹^*şsR^' Ӳ|EY2זм#C*z_e$]Cg=>FJoi@GBmߔ@z T NGNo8u&Ƀ !x9̓ɂC=C'1+F e,5|Үq#)MuYǟf9WqfUC^2?U~B$_~7<+ڈWCĀDu qIm>ZfZ!`@ 0FNC7KMC0 C0 lXr C0 C0cq~k!`!`!`!0V#`\q?lii!` F@>ӗW39o馛7|gU5 C0 w}a9(e0NRͅ^6 C0 B`&%~"b'/\Y, Us1s=37TSX_nݺy>\zn߄F'>㏻z֪Sc9-"nymf*àC}VKye ?6tZRZʣe'3sNB=ɩbO<-2nj.kǧ'閔JHźF[z8-0 wq{G|$-T23<!i&cur&pnю!CYf}grk;3-cQmD&P>xvyRP=qGædAҽoK-gs=xꩧF*'E#I}Thlg4p ӓtKJ˪O\B|KjQUٕVZɱ+%\]y啩rhyAI';0w뭷L|0~ov;;찃//^_j.2_6xc&<͏=XT@o\&|~TceW2iנA<՟f]!ēHz箽H>_~#Ø}}a2!K< U6'|]wҐEYu)LwmoXm20ǎ6yiέ6۸>CtCt'閔F,o.ied8IK+>Vc/Vsݻw' ~b)'XLu饗Z:Wgw b˸LSO=宿z|7[wP}ȻA䍋]w՝p Q>y!t~z c8(`Iu~]AKv[0<_aܓO>xV[m~'w;g">M76ln׏=,禜rh2Xs7wm7@c-t[o$M6+3u%wl_$vy, >۝/+imB1nO)⛽hvr=虤v!,޸dHe8p qwO?]vY? AGr*CLomG'>}n&*#.tx$裏=/,⡇ [{~>#@{. @Hr;Om2$$Ol_TGtK_.tb,VdI'u]vrSx&[c;b,O&wKjΝ#fQ:=\旌0020Fٳ%?/QU7XvC?%! @;kHe610oW|$/I27]w/͗bX!]}[RccɊb9r¦A;MyR,1B8.v=X1L 1-8I|'e)s"žy@%o^E =<\/ܘ a 𔡭Jx 1XSx' 4bEמ! y_ XgO6':3O,eŠN)| 2s4 ' PV=CYmUۜU>|Qb5iiY¤>ƒwRp 0w !St\.x8Lj +.IQ'qc2"̄} ƴ<" 1/Rd}Gyd+kQ-buG-Em\c&a&p&%EHJD|D"K"<腁"^oY(+LQ?ToxpAXj7KQ.%}AS8[ٮ }aEHu}XKDҘ:C"vry<tYڥԳ;+F#բ~& /UQxeՙAjł, E Mg5SqL/Xa阢4./Ze7m}lYa$!`F^VdrOX.C'U$̞+&4$\IX2`L,{d TW[n&@`vm`{0YzivJ兜L1ӌ9Eǥa+A%e<1qLJ#= ? h+ߘ!"G/a mRE)|s:=5f@IDATK,c=q=NP8ЀqGEud{'xym &峏C'#]sKGCN$ Ⱦ` cWyzprl@<]J=^_x!+a:)2YW/=Ɨ^E80X2枆p[jXzR!oF^Ri10oo0\bw_f7rĽu{sj' "?@w< _SJy45Xbioqo*A,yNc%?-_~ 3ȽB}!bqL^N 1QV~f1Q} q(D%#qx^V`֓t .k"mť]OYd W_}_M ǶV qۄ-k!GL# 'aE?9ٜ4 QeXB@D$$:^,CrYtpHY!ma-$ <9E }aكє#mOkYT7j$J^*JkcƾTXP\=JjWRZHx(IP^Z9c$ݒ@4c;?Y[Lx0)KbpHp^_/@ʄqt|5cXe?ySfcccR1^_[cf,Ca;$lYm\*8k,Ǵ^mUٳS4۪]V!`!`yYzFQe4!͐+'͠S[y/ ԧrȁ=YF!`!`$!/> ,C5-Cxb:hb C0 C# 3[8j¤J;HpﴤDoKLEC0 C` !R4oлPbbQ.M S0 C0Q/8kb%M5C0 C0 1cw0 C0 vLIC0 C0 f,ܭVC0 C0p BiS0 C0 Cm~%龶j1 C0 ChVi@(,*Y6 C0 C0۳[!`!`Xl7]e!`![!`!`Xl7]e!`!48l07bĈG!Vw}~GZ/B2/_?#GtC8ۺF٦Fʮ7$Iz!06#:@XguܒK.=1_b '!Cox5$?vSM5gyrY 0}ns~lsԫKv#Hvm~'GmxѺb>GB -クvm!жDij{}uS0I橧\pBb1Am_~~6/$7xȫ[ꪫF"0ň$]zk7x`뺷z߇|y42 C/޽{)Gd^z饵 6 M?6/c=6騣r/;su#7|M9me!@={wws>s=}}A_: 7L3_~{.j+˻N;ͭJ9*dOwSgw^;<$":^r%#`/rG+Ydw5Hlnob-y(?\(.,*C{ 72iu)q>GFXf曉z}$Oا/&Yx 쳏kΘ۬ql0Mgu{ꩧ_lwW{":bܡ#/"oވB^{]uUn & #1 3%[n~駟,q  _>}"G}o筷>s7DEyD9ͭ8>a8_ãce;w{: ,;gem5Vm8Ov\ϴ6ϺgeCiq\&+:'</h^jBp<_?|k^~,汴1R"!`t@6|s3E.Ȉ~{FȬY00ahL7t>m5=^<86d,ѽ{ww)ƺRKE+cTTGt!s1Mx'^xa_ksM6Ϗ  ^ǯ07|㦘b b@{dƒхGe5(i!9 Ym iPHc!W/'W/ PѾMi HznݺEc(EjiȓNܹLl$6 xZeeg=xbi(_zjFV<[K+C91R=_~yko];`Q~7$-lʒbU;^ d|3Yc/6ԯ9/6v-luԩjz#~p>իozC$C9H7ܽ{nr\ꪫr5cKTxO<9c4r@ |O=T^{jG/}޽ ɮ<z1,Hs-#m1%RU"7[ 2,+tGygҫ*Cϴ jݪ~6ݻwIj "xȪs=C+l%ksx8`G6!w`(<;찃cǟ, $스||a:Zmn)ps={"|2xYxQ wMu*E3CG@T{06[Jk៉e9ַ9H7*hWQrՄ_~z\pAorxYgK.mKGGK//Qp*DRXw8%VMv3>l43 b-ܮ6`| Hko=/9Hu5:lT՞E<L*(?ߏ d^s58$P1P y-wy <  X`\zl_A?쯫T#7t*#Vp0# EW^!Nb0bxrSUxx' (>jSM5>H=KIJƌ6N,7^92%:^k5;Ncc8my(kFX )x~(VE8RIsP޼ϏU-C eAFO=T,n/יϷ8-$Q ~Uy8,Oǫy\}E|ao)2,Y*W4E|Gパa 0r8OWmSx7mvmD]b.pQ+>0[hfUd,^V8(֊Gz[ʚc8 ';oMMx~_xQX m_IyETq4֒f&YI҄GR@ytO!:$͛YBząa=d%"H (]HAFu.K~);+?%0C] f e+#}[įNcWx x+okՎf7ޮ1u]+cJohV7w7+n^m1/6y n[@0Y̢xY K2B!o `y ܐjig[`Rc&y/Oxe6 񶍉z9&: fF`L1ysw3cnm5/6yjOP'h&1&,&=et~a( m>pu0l} żTX~V_h/!9^AyϡZlj,<GDL,dzecVW÷5µZ]1J|ෂ1ش?-C yQ|^=6|I7vliPޕm2 C0 C0ꄀu!`!0c#0 C0 :!`b41!`!`tDX숽jm2 C0 CNX' M!`!`{M;[n^T6 C0 db.DХK |]c!` W_}f,x[;?!`!PA9"dbĻA!`!P숢?9l\ʢE 4!`!`4)ELcqذa5mB w۪į )0 C0H'x3 6viI,XyqpįU`!`m@HMK7+۸_O?77 C03>`w%4%xͮTQq#O=Ý{ylo!`U PԞ(d,qnyuzw|nwws>s=ݏ?K/ 74Lw}:,SO믿-"X> ef1N8׻woKsdI|oWuI'G}]qnfsw}w o!` @ Xꪫܷ~n&7S>;Rc]vq箻rwy8pu]>|c@[tE{">Ge,@[lXc=rHfm|Iňkia0 G,_y//U1!`@uZC+R_O?䮻:DwyFAgѽC s_#,}>Q<{=|OfyfC&%YOyYz]߾}[^{!`!`A ϞE[_ve+s5p eKU>9Nb7q뭷V`oO<[$p ώzr,OJnСn%p묳HT=:Ĕ"zp"S;ST;}|ᇣt!`@S&#xSN%`PL<ģq`!8M) 'XeO!#^]Cqx>x y/j)KЄN(/1%!` /VXaqhU$L:餩ҌD0jx (r;4iFgid!`cnjV+Ɓ!`!`Ԋ@Q{ŒZ!`!`t` ݁iUd!`@!`buIByGb*Ra!`@ -Bf,AxYf&1 C0 Y=k2 C0 CXM!`!`3;jZ C0 Cf,Da!`@GEŎڳ.C0 C0ꀀm-[n_qi輎h7ntk!`?Xl}tX`3wj8C0 C}#`b;N: 'M5TPUyРAl C0 C`f,¢F齋?~ѹ=(l C0 C`ve&fޯua8lM!`@DvoQc0lI5 Ch2t~~isϹ~_+jo~aۭJo߾Q~#A1 C0 hs՗_~>t}]}nYfqO>fi#@y=3`ZG*m6!` i~G>6|sW#p-{?AҤA C c ,ØtdhE*@Q@@)"i3̹瞲oۜ}]r.?;k-<aǬ/jԨuCH?5ÿ͛7>}]ԬYqUk.V:+^@(t0iСCmƌ#֭[W,7nlÆ m>}=իg'N{Νkm۶%Kx DE1hZCʎ;Li׮]ds^7  M E jﷅ 6olE!CٳgmѢE=w}+:~ʕx9\_ԩccƌq "H)C}z+VئML`ӤINy=>m% ),~+z+_Zʅ 5Ly^ݻ9 =A%J%KZJ{o?^ djٶm~t9 Ç)g˲]zΑ6  HڳA^X yQxTѢh tUV6Oh[__n&u=?,VRƎ/{'D[xE@ 7){OX _~ed/½vJ dZQo= ђe˖5-@QWzwfm@ ֭3 in9sL]vu V5kG⋮v ۢwFɽ@MSzhKB)AxVѣ|Mz]^9iu @nRE1ٳ?iӦٳM;Z:k,M4Wq̙I{gիsB}\߰chB=#5j(B}/mܸqy=>rdm@=f޽n9E@-zgiJ:K=b??]QHOF}Uб.{ REXZG7BiIv3_@sdyڼ:9@LHoVUV&\gF]ClZF]yl z@HSLMA  *4,kM, w@B'@X -z8^BZ6YCZEA@ ,Ehu%4m  nY z@@DZ  @ 3sy  @^yX@@ ~<@@ /żq,   \  Yhuֵ'x"ȑ#w : Hٳx9{GQFֺuk[xq䜷v͛7/_D>GvM7YzYfv__l„ f6uT;L^y衇lG쮻rzkРi|ƍjfr'Ol͝;ڶmkK, o~G_&\;׀ +2,VF [puFagϞuڱcGڵkWƍ={֭[70-Pܺ{N:>kQٳGV~}[h~W_}Յ;'Lhڴ^zu8qWJ{gGs<>2ڵkom]v)o ϟ  ~R~z鮸 wС,=x*)V-_ZjY/\Oz'7nlݻwwO5kX˖-]1ox8*%J0ݳvʔ))YUTɽޞ SECX̄;5  @ʰ<5bŊ.l}ǾZ>VZc=I#[4<^K2yz)b֭sC]w \zNmݾNVϥz ׿ kQ/OR@@?)bI4y7$ްf͚`{|^x!W^{Z>}6F*-[̖.]j ݺu3EDzz77UV)  +2,sCsqޜ?/ܰa1Za:e]eynx׿24_\(ZbV/,zep}d~6m_4:zc/y؎ C eXPݴiBe:g֮]۴pdԨQYԴaÆnZsW5kG}"o;X?z$ רUͽzۻH-/{n{?~YZ^L+^i  @iMӐoM Xr1.7T{ah{ey6/`Fo|gJg-ZmQ{/"OvC@K.֯_pC. q]tqsw?y?~;Ic5ԭ;~x7 aٳgGzVS]7|8zu7Tѽ9y-1_wTa; aWsؽ{w7̬9>|xDgĈְaC]s-[9zU8MQHw׃{|۶m݂Vر{cw9ձnܸ͚5jjeu/$FF? RAn{Fڡȗx@C@@ iXM[t:Ai~ƛgʊw"z+W}U j˨E1OtҾ{}b5ƻ_WsJ[TW-  0E+D!_Ihoxnߐ՛X-9|iooۋ/y #FIz@U4,jю`z-N[@@ BVy1@Z[o6DP~}۲e)=z4iL-\1@@ a1PNL\{zd!h x|+ $ ,& FC@Y jtn8mC@(xbS  Zbho G@ ^XԀ V[G@@`5t{   Яr-)',$J/~o~! ō7j*aSzk+W_z q]:,IDAT @~ aяR_iQbN:.  yPHo^ӘI h* ,7O|oCT\łq &y"0ŋm.: y7'+̗|M5jHx>ʥKڦMVV-[uLx @@ Hڳ8i$5k6bW[. =fڵԥJ:d}|N:e 6{ړO>i~i`Snc?b@(~DҞE]{)vՅv̙3 &L`_Z*U,N !',\r%v4hql߾Y&6`M!󩧞rnyy_v{_ :ӧOѣGs;v ީ9r̙ㆩcvHFYƍmذayuΘ1yw֭[)  @: v+W4 2*T`|?mrJùWs};vѣG#v{nS>kXf͚l2+So[lNUpVZeE6YE-_ݴ}9u>VF [pu ={6r7^x  _y"eX6mRK/d{vmؾ}سgO۳gGlͶo>VXœ]խ~۞p?=rHD!Ls)~aآ 6ܹ [+6h˳_Ds+ǻɞ&@@y"{ *ixkq^/ԩS#SܦM۶mybٻUVFX~ԯU* jk׮m ,\wtJ-Cy¬z =++Vts&?cg;@@ )âiO>ֽ{wכw饗:1cƘ$F. L*zBG9s{u8 i 9Y]ۗ_~/V^uA={^\o^@@Xy"0wN:mnN:֥K2e~ZrqRWs=4w*Z~}۰a{Lts^nL%|޵9z[zPfܜL]w}g/iTtB(pw͍>  @<;,zNwRJY˖-ݜE*Za/́<E~ u{:n' Wv?5_0ٜxi8Qs ժUKt G@΋@E?-ףe4ߑU[ouCYMoq@ <XXo-돒U !Y @8ׂ/<@ RXtnuq;ѿ,S@UqZ@@e S~l=ߒ !, @@Hb Z a1n B@G>  i'@XL[B@@`5t -?}# *=[nIÿ́ŔDCŭe˖5@P((nܸW[ k"EXrZj0Z oMyO!,QJ}Ν;g],]t  @#'QJ}@5  @ ؑ#GLt̙By]ܢ8}t'@@ Iŋ7o[<#~nfիuٶlْcw۷:W_}+>wﶅ f|uWR%ח[oJ8@B I&o-Z0 n߾=6x`_vZۺu}'N|={j֬ &iӦ}>su(|6.z]vnEvAy@@`扤aQM޽=cѣG[ \adC7ꍼl>խ[מx≼,$gm\PK/ԩ9/ $7O$ֻ )O:5Y zYm͚5nٳmƌak۶͙3}?sLAg/9?vi+/ 0u{ܹs,Ye{N>|GvM7kh֬IOt}>tP>} кcǎyO[.]r֣GxEӧ]|Ů7?6;to[Kunzu4ibzg\ANّ7  :E]7Pÿ*C q=j~}׿Sz#O ^M8>37wgu;vѣG#(f׮]oTC5w5zsޏ7zx #'>0eˬL2 Mnc<>YUZյɫ_C?ծ]ǀ ddk16RAsvg gxy"^RYw_zL^?/(iƶmۖpŭ‹zǷ}(dhѢ37+5jjʆ fcǎu'/.Zƚ>hRk>VX1r?j+EAS.^@@ w~]gqXT?m S2f_ /ybzʝ>;G%\KyF^`ie֨Q__t>qD԰+>EI!?@@lH{Zs6md7:u긅SL1 yBsaZ9^S# j|8WW[oY"\@@ 4II￷-Zz}]ڵkm֭'?;}7vYYfCu jǎ;/?OxL:om\P /Xvy@@oHݻc=ig=z롻#'znݺ{nݺO$jkw}>}Lְ8)H6Ky8C@@ O~뮻W^6uuqРAV^=k߾Ym={͘16l`m۶9sgΜi_5h4 Yϛ7/r_~ f{ܹs,Y9{mO֖>n&w]͚5sIm 駟.]XʕGyEGY|?^oK/֭[ۖ-[L=jҤi+g>w h@ty qXvم 24jW~a_MAߎ<%\&Nh}URŞ}YѣG#(f׮]oTC8u]Fora[nn{7zx #L-Sm'U޽2p@?Bc&sN{'D槪Us=\5+_+KA@'6WaQI9 U{qR # Jr RJ.Ulڴ ' {=2eʸs( ;믿n:t6m5\N֖bŊ]U{wdۼ} 5U`V(UW]SS#\Bwޙi:GڵkCܰaCד`TT\~}ن Y ^פs_% &^7@m6kx|yoPxݕW^z=5Q=o^Ix5ZjeÆ cFim޹ 5]h5}P"dE^}Xb~ƫ{pW W  s?gQadI'POe`Osqo~cVr.v?ox[שS,FTm  kEjWm)؛">|xj j?S@@O 6OxǾi&DDl* aZX1eӐɓ'}?\7j-P8*Q7Zܢ(ɊΣv妤j|5|gLGl&]!Whݻ9z޳0ez\bE?E-ӦMsUp9j ;# @(bDHU5|Fcn~BV5:,EWUZMG-رCUF+͝S/o4_ovͶ-U[4O=sx%6F>ޮ.p wwڮrS~Xxָqc֫ڊ-jzES;kcyE@)')iҥKC%7'Npz."RtiahL/_}zԴG3Y[ҲeF'ۖm|bʕ.lרQ#Y5d_h1Gû  N@kN(=00W \O^ '{^BYb9 :Ní-/$z$k0&(y7 @H9 YWj@@ ~a1 d@CgSZ^Z^旦(@H;bݒ Ru<'Q ֈ)E?JikIA@`bԁ TG@@ A(S  RbHoF@ ,L  @HX 7\v/&# @ v-<;a1%QPxqkٲ%1n -B@  7nV¢/کH"V\9VZz5  @([SS~lsΙzK.f-9   ?.~l%fͦ9  F~Da̙3y=c%ӧO'dN=!۠s  y'C/^ߟZ&Md}ZNl̘1qyw<+27|Fe?r=A9Ratҥi&;pժU֭k;wvssp*vE@B!jҤI6c [~}O" 0k׮-鼇2|N:e 6{ړO>i~iΝӃv GoHڳ(ݻc=̙3'7L0k[jUT))NrP>6C .7O$YLfCZFq6l0;rHm>}=իgǎsyw\֭MC^1f>m]ƟޤڮA۷ook֬N?YfK!]ל9sxlP d#@@ʰ 6\ސ!CLCҋ-_vmw_d>kf͚l2+S/Z5l…ֱcG1b={m1 ^QҐիmܹeo{M]mP}'?px5yd7'W^*Uؔ)S"ۣh^JkNvLny47r   y"eXToܸq3΃ '7OxM7esN'֢E\;vC}ZjdFJŊ?ڴi}^TN SN,ضmEԹ5y"WaQjyִ֭iSa_.NU_jzڴi6{l+[l;)Z-^ÇjVc*UZl,U,7v b4Q= !'  %@O!,QJ}H   sP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @ @a17f# AP@@ Ő8 !@X B:@@ Czh6  a1e@@B*@X 鍣  @Ţ+y饗?@@ 9x9TXSp  CHϢ  0g  $z^Bͧ:IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/cm_desktop/index.html0000644000175000017500000001272112346515436023176 0ustar felixfelix Bundle User Documentation - cm_desktop, v5.0.2
Bundle: cm_desktop
Version 5.0.2

The Knopflerfish Desktop CM plug-in

The Knopflerfish OSGi Desktop CM plug-in provides a bundle detail view for managing OSGi configurations.

Description

The Knopflerfish OSGi Desktop CM plug-in provides a bundle detail view for managing OSGi configurations. It support common operations as create, update and delete for CM configurations. It can also import and export configurations using the cm_data.dtd XML document format.

The CM-desktop view

The view presents configurations with associated metatype information for the selected bundle. In the top part of the view there will be two selectors, selecting which PID (configuration) to show. The upper selector selects amongst PIDs with accompanying metatype data (OCD, Object Class Definition) defining the set of properties (AD Attribute Definitions) that may be configured for the PID. The second selector selects Factory PIDs (configurations). For more information on metatype see chapter 105 in the OSGi Compendium Specification.

The main part of the view shows one configuration with inputs for all the properties defined for it in its metatype description. On top there are controls for the CRUD-operations and if it is a factory PID that was selected there will be a drop down for selecting the instance of the factory PID to view and work with.

A configuration instance can be targeted to a specific bundle by appending the actual PID with a target specification. It is possible to target configuration instances on

  • Bundle symbolic name.
  • Bundles symbolic name and version.
  • Bundles symbolic name, version and location.
Controls for selecting the target level are available in the upper par of the main view.

Special presentations

If the system bundle is the selected bundle then this displayer will show the union of all PIDs defined by metatype information in all installed bundles.

If the CM bundle is selected and the kf-metatype bundle is the provider of the MetaTypeService then this view will show all configurations present in CM. In this case metatype information is generated from the actual configuration data so it will not be as precise as the one obtained from metatype information in a bundle.

If no bundle is selected (or a bundle without any meta type information) then the view will display a page that informs about these special presentations, a list of all bundles with meta type information and an Import... button that will present a dialog for importing cm_data.dtd XML documents.

The CM-desktop dependencies

The CM-Desktop needs the metatype API and an implementation of the MetaTypeService to work. These are provided by the metatype-bundle and the kf_metatype bundle.

Configuration properties

The CM-Desktop bundles does not support any properties for configuration.

Bundle Jar docs

cm_desktop_all-5.0.2
cm_desktop-5.0.2

Exported Packages

PackageVersionProviders
org.knopflerfish.shared.cm1.1.0cm_desktop_all-5.0.2
knopflerfish-osgi-5.1.0/docs/bundledoc/repository_xml/0000755000175000017500000000000012475375714022153 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/repository_xml/images/0000755000175000017500000000000012475375714023420 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/repository_xml/images/repository_details_displayer_300.png0000644000175000017500000013507012346515436032510 0ustar felixfelixPNG  IHDR,c AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  7iTXtXML:com.adobe.xmp 72 72 5 1 2 3\@IDATxi^Gu7>Fkl˖<l ` 8 0%Pd I [7ɇ[2/IKRIIQ͇@$Lf3O6`m0`6eɶlYӑ>먵< h^z^^ݻ>cv;'gggMLLů=zJ1terrm)ABe˖,GT,[ ߤkCȗ:{> oAum߯?f߅< /+k׮-V T{-Wpl4 64ֆ*J~oiK#ݷ-yihL>Uf}k[>yMצE5u.y_Qh32_&3?u^6_ҋgK֑ih6OZ$!ʵ gOg^v=| 4Sr /*Yv_.V&/ܿ\2ui9wz?wkYyvi{Q^L(ܳpvٺCs;LNxکĒO6J:Z^7(-]I2(}ݠt?d6>Ku m;n~9 <=#*+ʹgSƏ=+ug'M 2q򒮟Mi6(|g[\ҵ4vX-Mν/QtKT^̖Ok/|)1j|Ѳqy p[\tKx+ǧuerرegQ6m>|6;<߽;gK9MeAf7(mО!--]zLs_??;|ܷytr y5q.?iɼӖk[|I$hʊ߲Xm˿_Y͔s^W`FW\Q֯ c3e"[|"63rUِ65B@&m]gamhyG&鄰P;rܗEhy/Ƥlry+(c>[R6[^{pg9pP1MG&b|y;n+;&b\M,rLǸ2hL+Ǝs/RY^>5epLpgx8.q3>t:L kG淼[$/I7eUug;^&m%MToGm7h^6lƒ*ǎ5V̧L b@ŎCYzEEWg:#]cӾt l(1i`DWnm(MTfXzf^Ft Aiqٳlk+-ֶ}5O^g5Cg*<&ʡXd}>su]XޝK#}aͺrt9LX>#Geqo߁&hbb t+U۹O/֯ RʅyBG5LyDcܲeKY>'?~{zퟅɭvn/ЈU9&6Jws^ܲf͚@\( PyL p.: x}pqܹLxK/O+5b:5`Z x'ZzuY{{Sn2f {tgfY.KuDv4ƍUW]U> Y>GpqcdI۲ &zueh.m &Ot!>ʧ1iӦ)sR,u}{yv 5q[ls/kԕpꐉxehe(X8ݱcG{˺u8Vcw^|:>yϫKbu`c"@={?s eISʀav,aGi~~ǫy\@I_5'* ZhS^WUP뮻꘸+d[&2p5T c]vY7 1CKo~L|D/}.s}e/k3o|M@' G%پնfb/zы&p0VV-걟͐M{WFx3dbO_d4lڊ?#>sX?[fZ?}~TRm֚eNc0[@ot/x Q*~*+dc@ @:~fpۼ!0 CvV(#WR|s\`\ƌΛҗtMUV6ƌc xǛ33|w/yrƞ1-Ҵ=࡭ щ1MZQ񬴙G.^XG>Wxڅ7:B.^@N藛o)\4^ЗyYt+Xn[t)ӵ6&θ: 0t8: (3Xh3\q tp2 =p;yF3Vb~^j@D_ 8V^ƭ'cVIF 5n ST~|.~ f䑏*(è |چ^ ~f5Q0FKr&STȃizH[.ה#'tori~X~~lk<%^L~LGXhˢmx?o1?l A1c0[20` E2Q3F?`€ 6;% zs2J~06qf0a@=^{mQ7ג^ICe6Ӆ,rŝ+02|y dy+z PO=QL깚NGx/Y h}ץ]TƟ҇cM*@, X8x?kEUe/:8@GzF8YbfoDK7Pr4 0O'tR T>M3er!RNym<餫ە|Bօ42e>=>$#HKymue\:Z^O^bO!:Ɍj6ki>ts x<6O椙_҃hO m?\^'8#~/<ɩ5SV.v/{Pӎ/C#4oY͎/ [ۧyj__ĥ~ |4[0o+oVgu=`@^>Vp͆'.<4 xYf􎇕>atҳ\^Ѵim]Ֆ;]?2}m<]Yn5ʡx@tot-#D9,tX7 @l`_z68˃'F e!W'Js,@(:QX>224Vyy|cůKڏg&ߖx.qy m-6/_6#\<2\liޖ&Kʊ{V34}cnx7tت|ٓܛ\t+^Xn% L,<: P{QWH^AO &u+Z?IÛ& OВܤ{m2y6dLy}3Y7Y?r2І6oX<{ ӞHt.xnua5CK yi`WW<\Ͷgl)/+.,=g[9o:PnR6 &^D\^dtt>VG39~x ʹ+LRvEX5/Tvk~ bg"~ొ/oo":r׏ ~j Aȳ'i g_{˚: S OGw9ԭhW՚PH)kX" eL#/NO#i_@[BkT=rR_=aۜm{v>QC c ε5W{=PG:)6ϟNf,Φh3O@o8>I[ ⟬C8 YWOrd=mw͐ixe\^Ɠ6뒧-mJR>tSKkַW040j=\q˒S\1L@@@}bٟY=h[67(Ecw~wooS?S^17畏D&g1` _uyXԁ̂Ճ=S`f2x;YoF=V]8 ۿ]wϩi`ICpM#IvuYSvF5㹵Z#ʲyUb0ڬb ʐǓD^0Hx >nuH7+j7ޖ>rIg3K,4dz^[6S d><2HYt ]+~?ީ: b??=e1D{J[?Oeg~gʻ2{o+u=1 @GTl,l<3mL',u:o3$W_]c{G'؆H=G=6 oxCՇx 7Ac1+uQXN8鮓Ze7tAJ\|y%3sPLgf a\5>'>񉺁eppˬoV7 Ѯ߁{޺<Yנg is$HKmLT=:KD\Ry}X6؃a@[y@ޞP,1(^=SW~>@B')xː-ՁCƟG%>c|@//^@mPwc\ \y+g _f t o& /<rcwzV<8eȯe3F-Ӏ\7ҵ7E>rґpý13xڍ6ݒTi[iWNO tWs{=/ƙr3_vM؟L D3CX:[pt0PSP@2 : Aj3qFL=??[w la@4ϠQ2c~~<@"D< *c$z501k0 f}23ArVgLdVq Mb),xXٿ'%".!=4p4/>0;˥[;DN0[ xlx\9%.f ˇ|y5 72<<3Y ŒlxȌe''+` FI nmd:@z _X@H'iZƩCċLG@;zP^@hdh[& ?a}5(1(lD;(m۶HIGMB._Lg4$ 0JiY/]9b<HK5(G[x֒<,^ 0w>] F^Y>OztB!8`u$;yd^K䉷2d^޻T6/K'rd4SVϾ)à -o,?(m4 `1l,\Y~C,cu2J7-0>Ȑ`_g0 T֍N\he֕r(֛[tT h|t2,ti2 >2&=<}d_,mҶ,G8Y ,io0Zrc\OJ,9zi@l&$ ܸ6=sOH@4?X{lj{OrKA6 n۞>rAۀΦ6 xfYmSƾ~6(!m!D/|d;ԗeRA!yhEе6|eoci$mo{[o!IGJ<p'0Mwϼ!&gx|a:7ۻbzE9wS9 Xo@/ :Owju]В8bu87䞱;4h!O@څMv\ҟ+*jw(-f(o㟜ذ N^Q..s#Pҋ"F?6mk@ߒSYd%ˣ+׿YO{@1 # {08DڵmDRf7[>:( DO7zF H< ;u$ 3L 9@L︃3Hb0's4R7 I N>pQN <t\(8x0`+781ÓEo3\¡VQN2y2]`h/I!m?f\{1sң68SUu|TFL>48 # |?Xx?brVQ,#6fvދAkO#4 1~h<fseFaU~ر2 3 }Zp[cmiG5tH<3gt+Gx O(q8J椬y?4bu9~{A=o!͠69(s "/=y~mHz4<][<yʶi y/ޯ7Z~YwCxQZʩx+!hm`{,ϘCwT1xTxV6=m0RqYr~ߩ :d6W?p/u9^i7|SNz'Ȃ_JFp.#D$&F2:@6Ei =s}oXn2 G?*GacnLz=,i0>r[8u$ccWT>@@ L 6p1*@61 {b7C+8 o;Ra\|I 4H;3Řddj=e rv,=@R d ;!e3~GFr%K _$+ͪGS  FS\# iޛvVOw:m?s?W=O}t B_oF4X񽏗q}ӆ{˙+-I1HF`0*^̯Vc7@,#@k ̀(/><Fɘ6F0y $:d0ݛ͑uWÃfhm /`&OȀV $|W\UZ,,",OKu'*Ot萑e ͫN?~EFgmF7ȣ#yCz(U35c eĎ492S8@od c.%FOP'Htwgexphz~W~ ዧ%ghx1O]tj0@tPZ҈1Ϡ`Ђ>7[AOS2-_r}Km~ɲyM~:Cז$,.KK!ӳq4amx+{zXO5 @FOe @- Z6?e:BX8@ dZIJݣ[zKӏ'ٞѤ,Ζ:`-CZzСn9ԥK]ޥAýUt9ٽbٷ#b{R2BKeKA_IR'j)\-5=M(gy≚zW hM 6 LF}_}(YWfM=C$ P /:{b&lC25@-.%1<`Bg{)|ā3]=|#uxDN}CMxS'*#`qn @ 'eE | Y, u'%Kv~i~ O*?!-'XWLw6#IMof2 idg)87=9ɛKKkt}ri`IG ?؞,ז ]o2Px3 "u<*< ,}> 14h3b Y<' rrh{z R/@>3si#:<Ȏ3L W@pn2h2b4&M۵P>I_jG%]p?ʡSrwUc.Ko>2vkQMԥUPFsbc}^ Z=}! 16D3v1d<q@bH5fH|!sr%a*e C 93-8AS#IϺ۲@4齠S78 :D9 ^O x])/ W@^X&eӓ2&&&_:tuKsެ[ԃV){eW(A6|dHWu~} {\Yδ% «?A8г.L5^kއgcuO#ei@  8il1:`5`pϸ ^|0 d (냆K/!DWޘ \ |y21 3ҀO !O.J>3?`@N9@-&qOLO@X@>zIyk7msE7>g16@=tsqP>'yrRs}#';]t:]2t4KBq[kop AueG^ xL 9D2P nB N`03]n. _0 hY r`FBNĻ2KϺI&|^y_+dBMh$IhW6#;Q'e]<QzO<^[TP.+Y$Cd&+Y2ݫLFxhȑS8 :yV%ȋ'cd$OF0~Ҿ d{(e0D>%[*\f%byMA eȮi7=؀~S|2&e8cٲu8>2cd.0saٹs{BVT׺u*'vK>)h }Ax=fY!sNmKaQz;+O~u/5qM#Ag>_%+~/('@8KځZ#0ѿ:R{zhOr˲3࣌ Vȴz_n=^3L֝ygne^LC~Ps/,@IDATt6h:=dm>Rwʹ2M>SR+'$m^->((xf^޷Wv[.x!-S1soIx}\5Ћ::780| nCÇʡx#aժylA=Zg[x~5 hLys/]pL,+`үrO^xG.XfpVx guI Jtv#̽]Ѳ|E' ʍOS;8^r,v7ӁxD:Zu,[>Yv~+:1֜ Za{|}l,Xv|wk[i.w*tsԺUvLmG/fXJ 5cw2_-D;;slؼl橭3 B^`L ^y.8@/wjX2Ԁ2l3:aT32(gCh%`t2~[FM[ەs-Yf{E>W;~>tD^rkU>&\I ڞcd FկT?J@ &OC^O\ C/c3.=Y'kHg{Ԧ~dvt|ֻ{>Ҳ~Y[>s_~rI39۔{&pCWsrOTJ]Jnö?˸v]yY׿X;5=ttv!wҢ'k@u-՗uIk5eJw3LO/oB8!ǂSZZɜĠN }={^؂ѻr|ZL?*=j}~;љ _^nuGy}+,oxkd2`u/^g ƿc=5׆Cevk8hF|y %Ɩ(^8p 34N)k?71ٽ"־Fp[/qrS ~G"}Um]HYfw!|J ǂ~|t?'2p!Uw)L[zGQ} _m uTy莨kcBK %tH玕LUt 1Aog8TT a{zxfe3Y,@g o<.-A PHc 1@qS6`'ʶ/=mrLdz7%8}x`rz"^QƊFmV9ÆcF(w@ C\?AN7DC+Ȧ:̄n}]xk|ҟBEY?CrFgu.W_q^YK/~{K֗SᄈrϬ*3Kk}betXl98,2E\>0{{0b}]0γ55H>T>O| 0*&G㫢sGʱKw0+v3SQt ~ys(N@'Uf oUb_1hMɭ`Э %XRF)xu`vyuEX|cjk gV+ 2~,0o & 95xmk[,GO0L齬.E,rG,O/u+Khc#2/{a^!>=eẇ5U}{IUN& Z`8< qhCѴ_ʀM^K PpA[K]7%2U.1!Ůr6 +yBv([\gT$%.< *%d W4{%6'C]xvV3bu}r;^x ,^`6m3l Ae<@Ũ߶m[es;gCE&.^ `nX =p6%'+rfGԡL =o -Y4y{E? '-xJ8=a5W٩Hg }<3Et]Mg >1 \[.[f@zHuw3pԇoW둮.O4;N.^?ߥt+Fedd gQ9rue.i8E6ꟙg{Xdncal kk":,ikI3"wݲ6^I~c?}3`"q.ic{*ZDu)l`ਃ?PY6bzfrl70w&y} ;|0,%9b𵇃GK ,ҤAkoE02OO54ޑ`'C+Cx,x</i[^YWK%-yOًIyޓ%d_6/%Kh1㸚 C> N]U~O}w+sgwHmqSͷ\nw3أݧcDػLݳ:@ڻOc?u"?:[.7!f38p06{wT~kT̒_—i?ZSw?T {GRo;?ׄ-QՒ _җ˽-in8-}ky<~0g}˻c9-V8w}OFWG/GC yB՛EAG? KG dٺ<`T&ϫi7et}6ZϿrӦtӗGd/~!8MoSK ַYnDʚ<ڷ-U-O(ʧsޝtGz0y7iUniWUϺ2ޚ|vW% С^Ydo-uaBBjnVtپ֩OY56_< eTKyYy76?y.-;,ii 7vv\dð>TqLQM8s eOTx˖&G 7qh)hh6O)aw|t /&>9'ϼa⏏O<1hY/"O(2U?eYY - ɶ|y|+ۖiy=w<2nI?x /&]=/^$U]>lkR߲'x7V x_}]ny[Zw%_ՓtrD6 # \ح7 Ҏ)ѻ٤Md PR f<Y_TA^H%xnhГ?ˡq;6f.}_pxJo۫f˶gv],GqZ K}|<2&es~=֍X4 `e#Ve-j <rIS ` 4Œn- Ε?Kt0%0crPC9lv;mBHB =!&X{U?^K* (>|U*<#rtY'vȮ$.dyK_:Ok?E$2 }HUez~ti`)X`a(<߷g]c 1nia3=߽ b h}kUzdY6%-`0 cYlx+ +6ս°m`s[+ \ nWz(dR{#a6ԗ" L6</rOO>$oΆeсOJ|iD?(-shj Z!,>t>*0|+0(υA+ˋx@p5<8-9gէK ?OO= /DxZ0no(x+YP8 5Lj7OG>T?/iBz|~t#']hF#) y2OZaym(4pX`śVbTbČW6o(3X{ 'c(Xxvρ@y2% x0Z'Щa lʼn; X>x[bPYv@ ϐ)V8T.Fy^'J(BV2[UW - a$?t9 # 8pJ4Z]uՕtOMMUPR'ف!CRoCPw4~zKY<}X$n@ |i#ٲ.{^)x4{FKOAwNN'3gZ/+ayG/?n_fQ%k%fZڌ2d{!#pe m҉gJՍg<둟kʗiAЧWZ`U3O+נxz)>&}KiI/KG-Ŀ'Loeȴɺ*eF~.ilguAFꩄ#G:B*!E>LeY|Ve~ʲ-}yWIy>0L׎,iɳ;[z ,}KwmϷ-ty.v'~_ mۚ6yEϓ&4]Jo˷MoY6ѴOʱ1F╜r^=BfD/,ڲc#­ƋΗ+Uc|頥[lѓij_j "nAQ6קғ6W79hqud]?<ԅ6TjqOtái\j'˱R+|3|th_82srC7ks6{26-S<O/-9d5m*;&M)# zgط1 ,н/ŁF炳Z6!)u4h lI10^h9n& PQz87a_r 7}+L5yM4Gk0 ꢓہFN5$?7m3:eHK6p]c By))CLN[>gjמ`OM^@LYp>)s'7JˑA?uzgMB$[ ;F c^N0iҋq0Uguڮo< O^,Oaihw=2]xϢ_o?f Ǝv7c|gUM7T;``F;ޑht:$ t,t"Aʘңr /ԧx<kc8 H ^0pǃ,Dopm cp 1҉tm4PNẀW`e Bq@]1Y)`EetB/7c-Hc`U>C'#CVlڐrƩ KOAk'To,pg()_ 9s,"4XPOr&rOeէ d>~mg]OQAYz>WLK~6ѥѲ^PWơz~zFyq\'c / ݜUǪ2+d7FM^:Ȕ:Vsw}k“֐:ze徻˞Z7سl{M>|-MK&MxҸKoi23,V.˜5T_O.`-iImSjdHYX *Irf<|й M2߽_z/Sj~bg1,=y-vm˷AotAeO%mN̂Q,MҠ]7m:'-mD -(y|s2wϣDmXf :]Yt9XNX^AA!ekSMLe2h+oߤ?t_,?~TOV=,+Ř:x0 { =`݉OwlOСѨÚ߲UȢ~ڻ^r>$O)iv#u O2l~?#L@c AU}mhxK$R2~ժxZP+5WΖ^ s`6ct~gWŒQ:0mz$t}CxIDH_iOqSiNy<]"+ۻ`N}telȖd߰ !q \j*V9ArUe@RmsB o.` G:]oNޞi'ׯy̘̳ʺ 3E˪1MOO2e(S 1.K gc5lV@ Hwo XO+nx1x@NO>l Y%A{ 2, ֶg*/R34'Ld@5F/^Sue 'Q~փJ^92K^C6@+0[~tQW2Z  H}&8 y#E>kn:i4m% /2hG~23OW~=:)S[Kwh:@ڄ,_ƒ :wE~ !LT) (7tC3b^1el| = ;Ygc,hKRG 9S.P`*q.`2߇>q::8< 5x'+92T2ye<@ ,tT0u>y _H*&3.^{ú+<lʓ86ڢF(CCOsB񲄤lqa_!ëOGԣ)!΀0H C,ޤ8(*.k+%P/Yt퓗yN@HZ0?.={!fxUsi!qHu}]_ haooL@ )y>{[DKzt$xfxR0xqW M/G<2#Ixe X*8S$q礙4z }:^XVxX}˶H&0[^44d0╘bxsȷwmKHL3^-szx撀1^eX5I0kޮy^BBi=>9>8Co*=+4 HRuxuYvS@0z_`@}_m|}UzZ7"x65#, ȔXa8y| aL!?4}5¤߶lk<r-{ȣ,~Hz0ʴJ}h;#b|~0`? ?VoE&B'C:aޅGNh.nӟ~}A(ea4,_Z12 F2 K̘@<}O(@n Ԋy/͗ːP*AYxj>.hSy+&Ɋ? H5|1fg!VGCO~ Kg2 k(\!+['Ngh% O1.v, >muc'GO,<]. ܇bx&|Z`Aֱc]:mǎk^MͲjkgj y Gx&# ׀ I3,yf<i "$<)C $/#oRvC9"i`hȃ"*7p OFi@DheϼYyV BU>:g>M[ق:фBꉯ~T|EcAi?6 N̶aNXEfXSgʊX8S):S & 6L{L $2msm<_ANX-`yp arf{@әNTas퉟a1Z<yhn:5/a"vv'+ONI|<0Oz  -xWdN6&ZւV u2EK8U'k׎CP( ȵ3\ңhCoA\h(VZS^tyeG2_PȔ-=23:!2OhrfSORͱ ++|꠿HېkᑢYiݐ%K ㅏDmO@ @J$O0*`B޲{OP]IxZ`Nҹ!W9g),e4aN9({O: ϐVLZ2*y&>Ls)4=AkY_6!8rZ:hN iC|80 `fx^/c2M=ΐl%T Y2 Q.P6d07#axR'[LK PrdR$02Q_ø'jOj?&.bu[c^pIH햶K<?xա {@ݫ~CO3~[`xY@:̋ƻv+7Ww^&efP1NŸ P8cheK@XW]@+!<6xS@C-[6WFI=93l^ 5!?/1O`i%RhCJڃ.` 0uϙ|I~ϱX2RN ?q5| g\tzKIxZ`A';|y]:_5UPtjSus}5-mkO2!;n3x x)/%0HJ\#ၹܘ<< tf >nx?p@H+x'<^d*Oky'Y:}#i)OP9xQYdc15t_h_:a~Hӻ9i皏ԣ s!ʚĽ8-0綆(Iwwks{q#ci!|9qϓp# ᣎ6ϪҀ# Aޞ!1LޔdMw߷ɐ.޷ħcݧwEM_9-@2G`>y;f Q(WyQxCФ}ϝ^u'e 3圼хǰ!u|ux%OO''O\y76TI776@<>5\-0'`X(+KgeM 3q~T}u8 />O)!W<tz>"A/yB+ihD;˒40/eoFyE+/q`;h;3ʋFW6/C|q?*.WwauUi3+ `3! ~"[@mCiEɎ*[6 vn3&OS /ï _!G,< ;:Rj`1xGN^r2 0WFx@D@8%FyV _y`xpJ3C8ԗ! FƻuEC>u(7PG( Qb۰/ {sOO` ɫ/yimk`\Vcø-nn|<%c0*b20Ka(DǘQk:yzgq+ Nhxy !pޡxS}  匬MddxSWh瞗Az!R)N@z:Jww˞v~Gs&: 5 X}30x.K0mCBLjx! x!y!^41a& Ρ'?ko B녔Zq8¸;._cxߐG6۵<) G*TIXy K` :Wscl<"{鮇tj ( !?qhB)۰z/>yeBO#:'!^vJ92<w);e'l$s'O>, ;COȐ랶WV1֎/9+gb2;ti0`鍺xv-BIDATgpoz+y L\rtii33da6+jBS0ɥ($n@~YFd<@FOCakg'q1\h"-z 2?gh&sDrhCi4MA!va9E\)}DS^'GNWsf:|p8g:1Z VJjDg26d.|4@󩧞(02̃>Xn+XJX3+?cL 5:g8! xNM2 x I=ٽ,XxV1 ǔd9 >cMÖ 4*X>F)ؼJIK1|yF/18OfC&HLJ#Y/9592T?i.md0;0  Cr|>աdT&Z>Б-ۘ/xia{W_>i}FiWbhdK.\ѠמdG>Ц%M^z,4Ȝ]%$,^ [F]m 0Qj'ukW:^Gz`$ i֡\'KXW>Vr,{ ~$# z& H'܎qW ^ц_Ѻ}#Pu\li0LkOK04^,/`1z?<}sQ̴M7; _lih'aq[@+޼p\i=zq[ oQ07G 1a2`qGY1F|IJ`i^Oq VrLΌ$?63]< V CYu3)/=<4"ݵH}́F:<|CƤ=,tg]EËU0qԵE\?uws+J\n\Vܢ,HĨV&oO[R^͈b4 1nGHb\" ֺg%ijIh&Ze3ň0{THyVxyxھ\L*ŖD&P[M_EK5P#'2_+/h0 6m)4dd~l :̈́u| ?>.:`1#<ٿ@mFW}fǧ<ŅhRv~rrZ}I1 /p&N>Sx.5g?(~ ~ >.%Vq R0P@/}S,W6 ~GL$9jh-tX p2j_4u SNU&KWC'|װ~T?km DhGo7J[6trz~v /ymkю }~oF?LYV2 :Z d(9%^R(r02^ _ 4lǐ| {uƛXneI>dn`tc5rz~3Cv1Vk+eս2ɦm>&@?Xg6Q(ٟ6;y/ F'k(+:~-7kkW37-Ǎ S:EIrZ ⥳6 4$#tʳ-O<dx "R1>D'B3a #ʙEya $q& \4JyL܅.dy2EK:Z;IOZnk!!g {I-X,f3{zf1FTUMF"HNOi^! 40@/xr/W=q=]_or/wrҷݧ2G*F ݇usO}XׯZU6o*bÜmHŐ,M3  ` _:  h:^y< cB < 9ko0zt5j[$?ȥLgeF!?G1bx`<**!Z TdELJoorHSI^C]`Hv$׭ogmluRVc !^}Ȗqg3ia\S>~ІOq_N/} XsNC _t_ٽ@پmO嵯gӑf`PJ o]S4-NVs-CƏ"S@g { dcƁȀG@\`y$@Gvy|N&ZSGI9$saDu&>!7UT#BV S\g QOA9@[=p"Cv־\[k/ikkZ90n!]ŋdG [6Ec;9Nٯk){l) 1lId`B , Q&.|0$/6%^Y9Lw<}GBT&CzY=Cp$X_3x{:VCe`pV4sQBi@JWW|8iWs|3py tJ |d%$\^-0'`*.FHA)I ͵4;i rF_ޡ.'MzS>K,wxqBg3CaIzz8@3nL~X Hy Y <Cs@aΙ \.=S =hԑ%]pY`ʤKhPP'Xm7}iZ`N:yF9 1( M>Ox=ڽ<=o0tFwx!F@:A^ʟz2>W/ohq}s1mxèO҇gÓH";!CF: _rZ$q6tQ;#2Co t|%-P#?OHzzM>]{C~|.X*!$@ԩP4bNSy ( AC )4n'5z[lm@k\̑qe!xrx}b=P"@;6QKOgy+ϰa>| WIW6 VIՋ\!SgS;o.ԟ>W2Z<-لе9E>:xN@A;ߜ'Mғ{ k9':MzE4MIxy}*wz?ysȟ{|ߞ(ͩr_ Pp;hQ-Non{0(F(4>)-* ďs`.R)PR{NđF:hc@oF;싡-xLnsk|Rxjl`/~塇jrP6=X"ͥ??Њ5BzO(<> ڇF.+Qzv_i*XOqX bgHôK}Xe<^~^2 LB?Jd9F;X{Ij](;\f l/G! zy=Ȕ3ʒeȞm8BF~WMP~g ڇX@aѷz^:C"@r{:4Vô>}HOzO!!rG;..74@[x] Ib Dޜ:0p񀒇Ё%V=PlPxtpHn# z1^^Ch2e(U*+Zr7ꦡ4~|L=oz[CO=^͑0HƷ|x{nV?}f:.FM&Qv9xa\~ZF13q}Z.ru<=mʈqCӧqqIsi5O0()`Jp~@)s9a'`D `-|yN@To| :yKx#:%MC] cr-p޶(yi+4_}?*_ylgwxrRν<(Y0 Jqy(>1Z4Krxvx]EpO~q$-@_1:Se~|ӵw>twYbYʿ֯ %D2S* g _$\ H^s3 ?Jk+fhUrQ2i7d) ËJ<7T~;*?HU>YRxOeg@C ;C0O=nX{aőauh ztLu3z/Xu HWᬠ/mD_j@J{JsP8yOYܫ~u'{T,mȭ tZ^5&/Z 4J3?v:SаUk+AC G~@MRt)@Tʦg *%rPRS.F-B&2]A}GD/x2Go$sKIx I`$1'0 дz Фھv)/*AvA -z_BG9)mOM^wtߗ~7H3^`xuٲG6u.B18qŖcɇ\+Gz'OG Ee ϔ՗2K!8I{: #o[i  o2O,t/G- Sc8hPg/9 { >i}|#{#ee8o)# ݸkyWgKz)K嬌ȆNέ!cȔȓ{u?\aH{:=kC7ק LΓ[ܤ;E}JVw6yy6C?[:c}qz)syƵ͸̗N_-p Ry1C¤ 00J3g >νCܛg>kH{4eX[t0m)8s |La W`"l Bo<6LL0νvIs/& e0VcoY_?޾V8|^ O [-nW>7y:WW~ڻ%O_<('aEqxe0WJ%/65 YF窷-(?+qYS{V:jNRO"y|"ғ/^NgarhkOc+:S>}ZS<#CBozӛ>~`N?,׬} y{<w{}W}+=>3^+ g쥱GT`[!<p*a3ϔ:@4K.i< ymS󍞠 *yQy߫R3 Ҁ fx ƓbP;&c7Q]jVo (k6Q4a:ns궺|+F`J/h!1==~f>1o~⼼eڔ'ַ+wt>|:b=`t (ݶۦ]vWe\]{r՘Ū Ku9y`{o7ki}]m~輸uZ_<ʞCOzUjWv+7];]8RmbC$_;0cK_ϪZcuӲ%!Ӯ&ͦ)rR+Ч,6>#m7@kOqs+Sy0i,8DV/b|{cO**eZVЫpy{Ό<& 6eS?]eKʳ֯,?{ύUO*rUO1?{ѝ(yeT!kM ӔXlyS_|},S{.ly]D;ӆ)&UgO}=h}ǾZ]~WX1j#9.ꑳ8u˿sV3yӦC҇e^ :lkXo =]݆e4rݑꙝ_T7q/Y1+[nJ2eZg!^=QCG+Fk֖e5{mʦ^# c7W'{nO]_7zGKuM7\ϟn qA+ǩxa(OFyCq;6I 8XHYZZ簎,?t|.e{xY\9tzU{/;h`5SZY~s?~}xXvZRl/ //&W 9]Z^=ty74 lyjpo.W\]~j[?M7]W.[f@1py埾ܲ[j;0]:- ͜kڶ"I׆uǝ\ôtI hs7%ZR+T X5Sˊ^SfǼ ]= Lyg@n}vV}m^V;^ok?y C^Vݛ+V[V[v-{kDj&;sc7Y~uXlv}d4T7*7gu}o+*ʷ? *@.k Y|@L\䝜'-X-0] y:tNO)TV,YYUH>#27zO-Q#oN OPvmuȶƵhwCMoNb)Mo˗orӫ-?S'fhZݰ{ֺ}uֲ?}f&UVWʡ%w?]6m":t9zO?m/LVle }V-&am l<ᜇG*PUd];s~tX?h}֯_XQ? *93Ǩ n=O?s|۳eeS-^LĒ{e˻~d9zxGַվVijX&:swǖyUp>rϖrε}O7/,yk{nV/]i!m>Oؖ`߾]ުoa gFOAě^י]i'z4[Ŕs5cx^WN/,߄M9÷x8YЪʱç˞u5gZ[;î6A_GJ7odskkGX)tƲ:~d9L|\Vy 1 -Q; &LE*yC?$?xR_!_Mʦן@_kN-*(<=Ҁv<}lA+5xO}S^}?׍6 =Ͼg!o3Su_D9R"xKňqE!@H9(wl߫*4CW@v ^>'/˽ Q~{_|WVd©Jw~LI+>),eqҗ=V:JJ{imC}k4Dˢ1&BZMEG9֩n(`8MAz>k.iQOYDž>Ohq>4ãOCuWąF;(R>N{s9D֗O нә-bߧIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/repository_xml/images/repository_details_displayer.png0000644000175000017500000034001612346515436032124 0ustar felixfelixPNG  IHDR_| AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATxUATE@EE%F޻11&*j51DKcSlc%&EE7aO{)\"nMMMnXC0NRlqgøpG/~Zx 4<+ Wp)<JG ^)LW)95K _J)y6sM)Czѳ /w6{ST7tU{,YRWKpC/\o?,R'\8k6xii[jL6m~V3vl2WARn n{ܩ2Ͻ*X NxW~Gq'>n(Qﳠx6mw'n!,0˝'xNI2|%׼4/x(.|_zUU|S>Y7')^dWip ?q+$x3^n{*Ji%J}ʟx;OKJ6yi'^P\( ɮ0#zny&*\GS\/*-/w'ޟWi=R]_~>zo /V҈I_|uUZ_Oͽmݺ%5G2{ު(PTr+,+VQҴāࣴ\ixxHŃS?#/~%wdqMI^oUǗ<^/ڠ [G7pm6ΝW)DZҩ8a'N+{GV]s!^*/J dp (%WMMq# ?;-@*>U+ Ƞi4=n#m?+N6y2e랫W'0ɭxA>{u]xpJ~5{%\ [Nf+Iy _ȟX=b֧l]ҽWf-ci[}#ӏGXHC\HY^@q6>eu^}MZ(܄لl^kz ! f=n~!0v܅0OCrŒ=3-Oux'oa\rSjO]'ɻX*?￿ r}Tݡn6xnG^oUʏSn!OHWܒ]W!Eyum*QTJEX3?0hÞ֣˪20g?> }+ت;>e\n"/'M<}Rq:v`+uGxbKV#r$+CQ>(}* x\OpϚ5+#VBvֲu;{}6VnrETozD~иް+-f9?U*dB_?p,).n ^S񸊐GqU6G0+?"SMrpĕ?nW~->)<#-JE~)-^'_-\4-R\%'m7?⑖p?`ILI G] {Abs삣bOm}Fimu)vx6v{xowXxno/Uc.JއlܴRo Aѻ&uǿhQ^=$Կ'h E(ڪkikcc}am۶6a1kΈa!no+ OL³~>i;nWL |ÃJJQ9J|KT?%ٸ"J+"^j܄/GJ~*?z6zV|R|$ʩ0O /SNz]NS'u%>| .`OWHaQŸ4[&tFk <;XnA5f ^&k7'+?߬S|~;rO슿<AmOm[) sL7ٮfuAXk ;nޞ:3˽TlƧie>zբrWa؉w/?|Ү6tj֡?=9Į;&[ymj{n;M9Қٝ Oږ Wョ(,Ծq;v`ĻpzW 0 p\ S8\ sMAm>0N+**@`)lkte-[.sL4y53Ø0x_yTO"?9/k*OpDNxzYS \i_U\wJ܋WHe%_O6UvҐ?*O?ʓx㗖ɇX[+e ÷O 6mLYXky6Om1N>|ࡇOC_5 *7T6)ܓ7B'DqIW<eUI|IǏqUZA8w)'A*&}# nQ. .auWx8$~z G~HxᦜiR?T4.aP*?-'ϟ81u}E?1ƏdmBn[۳7\dϒ)bE[e jtˎ=nhgi[X:[,o-B\H;v1#ӧ/oco;¦Ͷ<>,ٽv<$5BHM]vϭ6ʾ^|e b-zndu>h|vs6,3~Rfc %*}7:Mj^G{7A{FG Pru_}5xkղ&t6wC@G&tZp˵ Smn|งrc.ݽKLBƃGFdGjQ^䡌RfUry)"FtF80Pr? OyYGi%#_?4_#~O\N8y4& mb8"6 ^TxÏ-D)?WVa$/㇟I~=$P>+/U:S:]%+W=;_WJ:H?*nŁ)FxTf#xʏdϟC}PU}^a#G^~wc3gm櫇|oZ^yݦ7lռ|ƞz=BX0>z}2u5LK6ִ/=m8?ַs[f=`k}}[cY6GO>VkSIP 3>9.t.>}Yu;:+IJL`,[ku}iv y/F`73~vh6aV`umq jmOېia{㍎o֦ϜF]~OXr׻LS[H' unܧqp&LuU]WuA%Wp+sş{qK? l?Rɾ4GN/#M6!W]fĉш6|86 q.ƂO&m!xiݺj~LNg?Ƕr[k~emeL!M /X!ؕO׷[=v8NV۰ d[+{3.;혋muڨI{rM &,b;{;6`G+޲w~vS77>xEmtbkmE0w3w.e{}50DSGY ~?}twɿ!XA|kyx8P0,al۶mhkl'4I#+w]ZsM:56V %M1~=i)lM>(;vh-o:ZְnkagR>Ced >?d_qI|pJnx@ ^qWđ[aizG\WF=Tdax\i$X }֮]TN|zb_|><\%:7ۖ,q\f>N=sw?;F^w;;pR>5-Cg>H`S2ms΄mтA{s&fpYv`63Ȃz焏p.bX?oO৶Ŀ̀p҇{ɕ1~\By Ji a'n= ICÏ;|ɟ+?HWC8nה e-4qUKW*L:%tK\(qA+UzC.!d'aKfq)).鸇WO?%D)-~ȟ0OƏ+iRXe&?+_Wx/DI+&x+yQ^7G~ '#_ v]lZWŎu~I밺6/lfjz:F){RP DE_>R&*w) _#ʃpܒe7?&HK^GZd~Iͨi/!T^%?,`߿?ҭG-_;'*>\ERy +!Lܧa"*al#KQ/S>aE8(⭸EVp$9|V3ee YU FX*GZvM:ɡ#n >M#LD~J(xH&=?)/^U>< ǟIN#wB$S˽޻4LR]n([܄jFmg@ypҶO~K姸\'4UҪ<# *xWH4U?;otpGpGpӧuQ_z)GpGpGnp<:묳#8K=\rI2xW"8# "od#зo_;zG_׊^E0y$GpeY,C8RQ,c ?ܐ 3H:u괔wGp#ИHCG` B'L`_~ejWUW]VXa%HJpGh~@?+pDnĈ.g ;vM2^{mk߾}8#,fVZi\ 9t\8G,7~;#8_M5:K/FK-%vGp(,:kjq6lc+bm4wg8K3f(*f<pGXF(,FyڤI3ϴSO=> ⋶{Ƽwa#8#8#,!lѷ[[}26̶~8cp!,`^{wm쳏;,C'l 7;4f ; Gq=vK/dgq6{x?dj?]wu'O7X`8#8#|(sϵM66t.'|tA6|裏> ~꫅|>{E]d_=~7.dA ̄;<{gY>l;餓쪫mfP:tPV~uGL>F۳3i?pfXUb̘17rvh̙S*z4MJFVR=\^gQq)Os@^)UR╪;^ʡ_r;G}z6hР8/0=(ĉ= _Qm 80q9f`[npP/&#l%[V\qEҥ⧴/߶w}7|v1(_G((4o[ .[D2xr/ޜ7 0sۜt]w{mo_&Y^zZ;W.>Ӽ\j2S[ТRavUEc@8ߡZfX.F`5P_OCK E-kvh{ؠ+&:3gΌ;0]0b_7 J|ӧG޽{?^QQXcBΝ;G$0##8 l`Rv-EfQl`O 2d8 ;替_fy鷾E鉋#,grǷɤoN3Ef_~9J-C&B?[ď(ů}A%~`׿ܭZyjy8##@{"  gL={F3li!rp|DZѣGTr):? z#nݺřXȇzHI^Y +oȗwtQ9E_~ѬSNA_~yok; :Ts#<3n-+:#^$?׮a։OxaÚr"%^?O ᄏ=+op_QFEyV{.i<ܟ}{챱lmcB䙀/1?@[z֭[~ž NC0ϥGƇGWٗz7Һ'Tw?G1e]_Lz z}u>|0PYL8; Pv?l0Gt ~#t^yƀO9{@Eꨣ[NcjRB[π3äK/Itؾ:E?mڴ(;D|.Ur1C+W,\( H:cͫX8;- rR}7R],wy'>/'7(YU2P  unj>llGX '^#;3 YbF[."姫+_!W޳oȻ!.-u ݎ@c#PG->S#OM#FoQѡa>0?MAqc fp1s /k#,Mǽhԩ> 08%EQc11+I$)bFц1*S"i 1W\ + aцVCȕb`Or3&)#iY8Yfmf#@n:c(rRiRbn̉zxfULiޕeFE]˔puy3(~"3PC&垙 4~W7ݐ|\#И,yl' ꫧw% lb 9h.#:q ,|v %L&N<[bD(Hy9#: ]Q6 s=-fsK"lV颸̖@cj.`6tCqPa;C riJt8uCQg_W('mح[c+_|ўx я~TG@C~p:#,,Ս,w4*u(\#[g5izzvY~rhvah57!J`~l4`@6'Jwy1 ox }{K/4Ӎ$&h?stVoSOafrH݂H9{ GpGp ς+<^o]N\o^]]w^N^VNOvOufpl҂q #(]tI 0*|w(h+q9ѐc.~ctN t]78腭0gNF!2eJ|hLl8g᠃*SJNʇDq |ٳJtJ`&!on #ϛnI KrDe;{/fWpHЛoiw_Tg}Zj@>8=N: AcQJN)Ń8H)fR(ꥈ2] >VB~i0՚@|NRlyݘ!IfGN#8#8> uPr?;\pkIfkf߬c{**o4hs9Q9TP9,K c]šJ Q֭lPz0 ]ٱ=K2[oElf?;B0 P-pDEN hR91N Nꫯ{cGE\eFEN#8#86 ujH0Oz0 ΀?SAVϡxȢbb"ԣG8r$83 l6pFQGm arHEAgC]vUpnfQ7n\TK#),e>1K*G1:r)0zc6hBRv)bq\; s#8#8, M97 @ۃ`z`:i&B35n%Lfͮ|F -"`,:J,[ZfXl˂/<Џ3&d&lB(~Ln oя5>'x?FtPP̫32 g W_ȿ3$zTBt.azqv?@~g}b犎 ?:'"vmuWGpGpe:OmTY?OٟSg f8=;P%"Q6m_WTGfǜ<3^Yr)_>:nyW r8*3<gzmGqD l9};FܱFN1V5Nӟ&:!g `⃛.8vt".f(7g= ҳk3GpGp}ۨTA ̈6^y- ,cǎ5LwJ`3d|YC"L4)q,[}vB1g2c۷oo("!?#|̎*%g|1AcX,F):c|/rTY̡bň,rfdٓe\p#8#8B?zA^Ctַ J8YlxzED!G#K`f\(JNBrf4xA3?^}՜^n9rs=7r#$`:Țf_~$qf?OFƜRa#Iy.lU]ǖDʗcB6fDuiQ!PGndWv+?cFY+5d,ak;HŠ#63s \asr ̎Mw1el$Zsd]NuN̤r!%BM)Ejf؆r 5\O<"ϑ2}~yEe6kI 'Q4_sեƐy8" u6teU-NmNf$`?'GX+?y@z5:6VGM&lL9'Вv vO9B D 1]s;jԨx$8N;@IDATv6%5w]jʲ8oG`iD i,8@#"Lt8 B6!К"?<.ާcЯ_xIL,g_Wq8 F;vXㄩĶȻK|;9(Hq8&СwcO{W<0cĹ+:tB-*1*t78%)UŞq( HOLyƬ"OTId }kbڳ6Y&gr=Z6 d袋[o?N;4RquYgr3 b,6yZ)32ǻ@:P9<_GBꪺ/KXK8G , x]Pj낒[SO.|U_}0c |;(<Z_v/(AIeƌȕ'ׅ0_LXӈG x1<1RG‚X yE%, &uAa k_׺0R_+ bN?pY h;arHA~–u#|CAѽ{OPzΈ ?F˖*{@R8{.v Ku`a|GyȎaB`B۪Bg-dgϹ+r08f. A Na1p+vꔓ[_U )bρ8x{ [U5gǀ%)Y' /,Y\e;I7A N œ8#xTs6Nt,@p]?m  ]doRW19)EEU-D VaD%80bÎR)V ŞC9YC(%H0r& 3x ffcA,VȨ?Ls:d];v:3cYEa4?w]wŎ~#I'I;a>Ds7x#,@])m} Sm=q;9#,)E)0ʝ7[ɾ[af$_[[MD*~:!]a宬O6,͒x3XG*kSpꩧ80; WTR5( Աbq7k6HG᛽olW=?kVd;YTffr;#O }@"pDYf1bn5Nć균MwexN34t2dyr)eQM[6خ >4W%DZ(hIi!!+]ae> _G &8]Q\F%f[`cӭ[7Tr1O}L&(Cv>K+#̼39¢SLRn˒:;"$@tH齥:ġ>q bTI)<cscugGWXc@<,4[G#LJWوG˃>&#+)(rlE}, >mGED/pa@!.it%\;>ewJdBC /?1(O(SȕhhQSlYxʹBd˥앙*FiDP1aJCxVNQ)LGW2F|[D^Ş qʅ3[vZm}QBم;/s+W$ˏrx?!uzC=d![[Q *w1ybtYgN{f:PFezH)ܧg؈:?GX4u ЌQm6hbؚ6=Mcݺ̌JUvDߠA֌l056dˉ0(ӊ(ؘ0.gQH2~ٌ&;~(oCLA1јa1ʡl'ec^.WFQeů/aϴ6kӅUlt]XayϨLҼ5+<0bB"*Wr+pصb aW 0vb5[*yG}ofˈ=:^i{i_b^(@AGqb;c۷vظ<+%f}fKf d~,eV773jÌʶfgUpbe3J`փ"r*ń}9Kr;j] B!H>Rʫ[ixT~ǿ)kr2Vs@9^8#4dʵ C^0Iץkk6-Pkrl΁<;Gm3!>7E'L(RH+;m|cP1%R?DhRWm'RLR9_ +fiY*% <ģ\KW-)_w;#8@wPn0^@a&CGe3U`WN$jlw&"e{Ef rϥ\xLGpGX4yGaRMzSv閆MG)K`[L{.؞#8#8@,n4i#8#8#4 h#8#8#t!y#8#8@ ,k8  sXTRзF)3qGpGp|#ֈ(\Q!m*g ߯#, p7qP6C[o5fs!,tOp~]:. pG4i|}F9)#8\ve6k|oZ[*)H5Uaח^z|q#9i$e,)/+ӏ{a+R<5C8 NAsC㗗)|Q?/;4#8@t(F۴iO\ҏ,N?lV|A`'|rSb[HrňѕN8q~2epҍ;6wqQ.pѩZ:t~gyNj[oFˇN+('wmO4-wc`LLazۘ1c c6hР$oq^z-ꫯgyfAڱO?ݺuPQy8!rwy/ˍQN9j֕K/F\sn:S KN}C^ʳ{>?ρomG;w]7n <8/;sGXhh6WوG˃>&#+)(jxu=*(*_=F裏6F臛JqQLYPjs]r%Q?xc;C=GXOPL(N(tR^}HУ"dJGeᆲNB-k/12P>{+JN\ DHn;+ Q0bGD Ï0Q>}b?<>T)'&^K۫W/c7ߴ.^”]8(>sq% *Wxd23tM7@!Re)&hrÇ2RoQ,}/%(to喂uclrеkעb`kOGe}{]X3fk5Y;7]|Ŷꪫؿ mh޽coq"SẹhprGXh nj;Z+ۘ[ٔږ6b {6 q{,oF:snjʃ藿|Qfj/ !CbD<>b'gŢ%$ #:ui_`1葒ڝ-"z/jCC IQwyBFw=1@}vmmҤI19#,4KG Qd3f\5cmFZl+qBO>G27#cZ)]}qT=K뭷^Zҭ@T3(0ck)RJ˚Y܉Q?:W4OβifṊg3jkvL]@ۏb7mF)|tHH_0aG1Z}u9ޣ$C].MpF!S6fLXlĢP^Y\0*Ry?3PiT^)FfkR*ךkUS^0h,,J%S{SAf=Re˻gsEֈ(Ns\Y,3+q0m: V)qG3NyŒ]0RŇT&8lۙÃ,w]0OB^'t.p %ݗ[ې?0Ge#Pvv!zf)UlP0c oLFE%V:ly4~9LS`bP%xID:U\eK(c,d&H5>-G)|Y6lOrLwߒBbD'E67G9 Fpe14k0 M*FtXK]T Es&1~P,33Ad{Dw:"x֔y1cq3kR<pG`F:Z#{֩C{qEZ g ne+cgG=׿Q:QXx{kFX< A(d 3O6ꛣ+Cldr- (c]JKL>[M ('ʊJNi JcQbelKTI%⓽/V&V-O6}J^,}&Ũb2U, <"lI&y %YVpG@wP0^@1AGe|ů[\7Af{$pg3CνiSFpGXhf "V6 8&ck5E11`@'@AES;#86X!9@s Mdb?6G#8#!0hY+pGpGp"x#8#8#",AleǶr#8#8#4`A}(UѸW#8#8#4>bD'%ej8Rqqw߭,r#P&N#tkE,JD&jVw8lK/oC2n$G<Ķ,%e#8#Xh%ӈ6m)SqvY,HLo5|?':[8(Yj&nL~Ekh M|`M-O65ESMѣGSv#8# ,A2Agz (tZj_"20`϶jE.g׋/X_dΠ@SaT| 7cvN872gg8#8ͅ@`3M!8 ?bs=mV 7B+>8:h4ǣ>jx3ӥK; )tw>ewcSLi o_ƌScذa9B:²euG?O(6le8㢟85\ OWpkVsxg})(gMVu$R^tEַo_[c5G?Q\"<8s̪Z+G1|?hugzKǾJ.:#8C:@>}z01rH{y6rD{d|e2Łhݻw7|믿}GvgI'dW]uUM匸(G(ECc9.q!.1q?q=A%28hiyWQG D.ɔȏ e([<^cd1:1qW $ZYJ^zٝw͐ºRx Sv:쫯{{=w}cʓ}v$_fn馂t 0jݺuև(UGK>t΋e˖U|G:{>ĆK[ԘC8#P@: ;t+lc>oeSj[ڈ3''EEx7lРAv9تj8r-/Jɓ;8돟,M@A( XcA&Xb'jcر"@wie}2ٻ3vsw̻3Y [o@믿^kbs9GF$i_%V8:t.B`Hb6lUDZzww}n}+`ۮ]V*կJ /XIz`D`FZjW{f%$Zy\{Y֭Ki\xQ>j(AݻiF:w$n3sq;w I+3nA>|uwW6`B}VyՆ&˪vcB@@ hyⅧ_z+J\JKd׾e^-K [9MqԩY4\7ÇkgM7\y[V=JoyZ(I GH0Ì_~YJJJ("Kv_='h1wٳRU)%z>c}!!Дcnwi'[2f6 J٬aN٩S'Ktqv>: E(Nm )Kg @@N#PAD4fY(c-H鲥/{]zJ^KkM9G6PԤ%sq Q;z_m7ngoZ;  ~ɘ1c䬳+& Oeb8 ~!拋^hگj?cS.`OhmJ;}#}z0=;/E]tXkmJ +_g^{Zy^{:9AYBa J^ܠeL_@ y "0@haB[W,+?JFdijJrrH*EAeƔ+/He̐1!lmwO8.({UW]*ҵ$m EP.B1&Ji+`xCW^>q}ـ1ƌ-$&m*Z{GGi1L?&i Sfyk`n( ^-7t̛7O m?vs^-pԗ|h?=0fe+|Ү /&fO4}ٺh_y1Wz%>Ph<`e>s0g$<[-yn#Nl5F2=>;vB܇%4\7xIċ. QwrL;K$| "t]Id.r˙g"a3Mh!W{Ȕ 4EČFF7BHh˓O> SL90P~ED4hw|\}a~CzwvЦ]ivs{?uf쓂/y6debLr- ^ QF\L:sďw1b.3jnrM@E@1ș d.ީyRȑ#3JCQLKi3$3k̫y2/?;<g?W_8SZ21JcҔƦTQZjg.4ΫQ/ڙ_9#ڗR3n2S?DRJIc>6%ŋv9Ǘ$}ᚣ&q(fqzy00u2(34Ql]<3k>y) :T( j sy:Җ@ }G^P&<( QK2|{G~lq~cɜx83IҦmYZ@.R]߮JZaJ䓟0'A\|:!vDڃ*#6\lkI:F&_4-D+z/wĐ?/h@#u2MF< &Ik ؔ/LТZӴu2樫q(fqڴ^GsΪ!H}= w7+D/wD:VR>o76\sc=z(_peXL$5"]Q{a\U_;$SJ_y|i@@ [! ^9a\m;v%iS'/7r4׫sDa{t E ( H3tt !rcSc>-Lp%k.G4 F@ B=s>)8"4`ce=_>sw}^Or++.O#2Hn4GޑDs#˭RO߾*9x1YD;le`sP_@ P8\ 3+cE >q&P!r|76D~IKҖ@( P@FDBnjn.. & 6Vhk@ N $j:Љ@@ Ժp}h\@ @@"P6bgg9']v٥Gv@ @@0D >G}Xl0gD_@ @@ P+4!&?B4x㍢6I撨MnKӆhYIZ4iKsw'|o废m@8I KҦOZnHT\-ͧ̇ u& & /r-rgΪӆhY[n⋱IS_OL|͕/}SMKu&j 6N:ɥ^ݥKQf'l~E |mժ}9wyga#vAoU%u!mz+k8 @@6>0hg`\ִ PM,oewoD>Hw߼2Iev{,qCشW_ucigwqcջsO?Hy'\9rީvذaDҦd_@@ 0 X@vvo'͓qϮ7&0h6j+yꩧo?}ww}'/m۶ʇrH<̑}G -ܢl4ۮ];9s9rg_WvjL&XF׻cMf،C#M:(u} j4WDl_ge1hҥ2'qD=vI|Kq=.>\ m?Yύ+W5qslҤIr駟.7|9iaLG ' ]w\HK٘'H&:L%Z>ӬSNь"!B\&NuNCѾ" ?O?s̩dBy^xa~zG]}!fU~Ȑ?1FmNX6ab3q5i8Ƶ=N_~tNr>\0!(5A}WQ.j@(#7.FYmfbvou65@@ PDfEM!-Z/-ZY ʔ%?th ?h:&5=P6\ C L5f 00Sh1zcWsA_/o}\N9N4ړM_~`Xa8#dС\VC Bmxb:0mg}+`e3\羾i|z ?-0'Xfmchi/e%3W8Ew.Fպuk=GUcF-( 4Hl裏V9UW]%GDAī xg>>"j!淹n4@@  Ռ5PZH"ZQYɮ}KyYLU"7l)̗6TԩS5cd30h11ԡCs*ÇL I[oZm(\*..֧IdP  ~۔kmӣGs[V3_bBb/s/z̧/ W=v a5%$ZFuKYIUGqr C0Bh`500aohB20y|:vWoj=ffE ao߾}46p1 ( ӏf9 eRY\tR4x+)+/#%ˊF e#FX01}΍Hh!uf?LhG)*_Jۦqi{ʥT XOƌƊɼyfOJZDĘQh"Ov\mO[g:,&+B&?9쳳 >&V]t6E#zqv2RΝ ( ߿fz&ӦwR.N ` 7ܐ,/vmyfƄ./^wOܗ9$@IDAT{Yg}!Znt59v6@D`"&~aRTRhBōus" 52"hTL8ZP>"T"v8c$t¨D M$}{6ŴA; 3^gϞ:L|Dgս{wm⁓1p7\˙g )uZڄ;j<0I^S.G_sI|Ɨ|a8FKoa@$yK.D Pc&0`Ms̆:ŪW^YiE mzӎxD믵y~K<l|1,Ӛ 17etymO\;S;LnIn#}M?@b3DvxL s/WI jV=*? VYdՇ4U)VbPr B1g/ʮ2+Hva:&|fq ' :믿W`)3cDd5; Ǿ4 M:C5])+|>7GV0#?#J:;C6%MN ڋ@9bĈ;Ҽ͑fw~6 T0N4OŲtJ5c_]߮B}ܳ G4> VmP\`h'v5Ae&qF`|}1-iۛVII:3vTwܢeθ~7-!DM>Ik{;N>f5}Dƪ'Ů0o 94ʤAxZa!(|}xNlΪo -6V5!v⃉P@Yc_#2Kse՚.O72HD_`vJ6a~78g,JI3vqϬh;@@~"\'>01e"Da`|L+okDQa;=3W됥5Zh( Ʒ EmZn h1AĤ`YķaM&fj1 aaFT! lZ@T=R tygߌkVA a*-5^xop`d~Zs#:v<{@ "PTƬ |'F>5Se@.a|ݱ][zL"!@x#L\Pv߷b [oi$^̊0·f/>ڤW9gPMgʵIl06SoVY`(Ä 4I1m?< Yخ0@!':00DbŽ{a??f.bh̋0.S!4 ;b̌ TMg?| QXA1 adV906{Ig㘶vpl "`W@@@ O4𱳇IaY~\g38Ce" La`va?xim,s USP"%!Ȩ|u&/?|̏铉fY5!-1'ݦ]^8/5?ط?/E;BmRJhD5(Ls]֓O>+D”(.+ hьCUA" ]>6$V屉h?vIoa*̾Y)0GVI v{t)?u;NG 2Ϙ9W:uX|x> &M%[nf]W/5I6&=2=|:tyJ֑i7\Gz1 zwdeC@HM6/FҤqCy2k=fhAzk(3 5֙>ح}cZX(pril$[P]&f*[򌲯, [MiL_p裏M I~W K;iC$HS_I!!^7|ޤǚjoօtزZ2PaB@a$@@ PA`IejE PZ4k*-K&Mq*H#K9=M ~$vqåz/!Zp-ԗ&m\öͷ|j_~M7Zn!'#5%~ayΫB @(iТKSX-]B6JZ6(s6)S"iҴf4WB}!ڵ}u'jgsFR661oCnߵُBi81qVTg" εQb' 'c g阰kr4 iڈ@'sf|?i,/);EKd iצH=xxoKbmJ٣Ҫe3 ^Fb]Kth Zm|gzGϟ//؈lvR &L?X~eڌe:u6O 6m+V)m2/T4w\!vEfW˃>8@eovu&w}'ƃ0&bP<3kRcV}nw}:-ww=\vh0q퍎!5%7}OHa&o{'~i6o9Ly~#3v%dY5Bγ0ń][ zYf'4aQ8tM;[5s{шI o߾?Y?s3̅/S'Pt7wm.Xb7@@@ Z5 0i4kFP1qsY+%d%ѧ,Y@+Yڔe-vWx ĝes&Z`F f:y>쳵sG0'K*v̙SvGvT&}B<$P! `oj   j袋0v曵Υ^m Ɗ;e|^($.B_rds&v16tWMpa  2D,\駟IL3(OsÀ9 Q>L@@ P_UAS4,RaBKZH"RPRe Ժ\)H~N0.b%g f^0 \}Gm#~0ӟV0|y`m!q!م+Vd/X?1#[3e"PbGp`%]馛U | lbÅL<wal @@>!M]h|2riPf*lhse")UOVժ@ci\t"o |3R9/m(L&jbC,B<Ӷ VNMVf88$m/Bċ\KwR+!a S/]M T0NDx2@a/&k[{q7?+mƴ'<"63V̂BK Sgk@ ZyVpg5Ѷ78#fŇ`axk/%GƔ0G}~v2o0U2ĹO޵^WXblR . Jd2s0~A=> x_oPX +Y>ulھ`XB:nQE j&EoziL1A3:PJ)Uv>Jor3A@3,K$Y`:ǧ&GuvЃ7zvsM8~eʧY3eri.(!hK@HIKq2E -ׅ/0s=LwyI0š>&k[{qͥy@dHD*40ik0! L/mNva6a`68S <7~W-BM[`tUWemɰY0L4:"VfP ;duU>BBg'Jy;'∶ 'DG}T+ .(L}VL?hlN ڑDQp/ MH'5ڤ1ԋgZ.jgmeJgoˮl2zTosټGW'#hSR S3y %͛$MCv e^]SM0Ø!V((PLֶv/\rCN2c+n9.f 8)a\b!s7rh75DE{uUnA (Xcla[wfYŁ p"fAU6L}`>@aQ+yo g'@]O>a+Ы{nٙL> 0w",y"Vwq6QL$"|P̅ 3*Dɢu*\F D9;|hD1zG} BkCqee~eI]&b>iHq!^N,2_|5u0o>󥚪'#P 60TIVF,Fs`7xj $SO;}]=L}LYAB(1D~ 3GY'Q h^S~8@YAM-0h.?B.' TZılΜ9Eme!:$ ٖPڍ00]vRͷ<)|+n&BBDY)JWLYQ +I@@ P0AM~¾Tklpj[vqG[М`l6v#>?t]w&~iy@ m b`6B?*b4k oQ曂VoveW Ѳt$M}i&ۗ;O>${ -IIiʔ):&{mOZM{BDRbve?P+c|y ۿIxzC1SE`K.ě7@Ak4 ;$w}2a„6 n93iC-R^|/MJs|'.ӣjޚ./fgΜ7ܹp 9{;띺I^(m=v#Lv@&V .'[6l$(3?.>GY6lο?<a/6x3@G AF56ӏ]ʹ7ސfq)5Z:uC`vSO=UؐkMc9wy뮻 7ܠw dw6sQ25o˨QS`!L-zw̩>btjh | Ǝ+^{NW]uU6/6"L>vFiP/fC /*M @ATAT>|v<*Q1Cw}e 6ЎsO=T6 Nl|{ウ Nn0&m۶r!4LgazѸèa;s9sgv͇~x֌{Lxn2k֬l|b&a(WWYGuT0v&%K8e겏0 ~>lrfÏ~cDaø׿}f̰sLo/x}I'U2aN}cM m y3vxa/Q 1bm0Dރ>Xx=/mhC lyP0^cLdz>v |tnMP [ ޾}{=]tAi!IϪuVXQ kXb,_\xY L6G>|rL1_^D@ ƊHN6i$D}7߬q &0#F\wuZp!-ecOM0z0)~f)SN 2 ;Y\&NuLCѾ" ?O?s̑K/^xa~UJ`}F`Ve'S?L9w=hD2VFxԙqXɴIA50@hA8;> Lb||S5}uaueyvxa/:9{h uUvUM*]3f1"mLo}8EB0V(\yb|̊!ennݲуD+2D L 1c< @AL!fTnѺTf-,5)3Kdμ2nfHc_|_8.lFZ~C=$I/6' 6Kh#g&ךb;a`!7ڃPK0M_~`wGNvD%lVHB~bvs5/w}WjPdᄇ *f_zd}}&9q~=hHV{MvQLL Uڴicng)"Tan Wt<`̘ĵ݅#qbڜč\7\OG}hΝ;WkǬтl>i1?yȳ+Jp()pP~msS(x~"aDPVP` D۸ϼXBf0P@ m "fVJu\JKd׾H*sKUB̒cCÇ׎kѰwx뭷j {X7Dd (I6mj0+ m0x(dվ:njF4\ތS?X3hsQLLO H-=JꕋJ`4>|O\]N1 6i׹\a!}H\6v 31~(0¬h_xJZj(#^{ya4<  sOmӲ}A>@@#PA!Āe2}v,].Rl W_ϑeE4ZN8~JLl}!٧Os"d/h'w.Jۦqy)м\cǎY1aY)d!4!W_c8CcWPEi0ԩo4묂Uc=Vゐ-M>|䪋INz`c9VҦϷ]b>K[,tynVhu)tB}@@ P}*TQU6;{Dmp50G@h;">q}p\=0h1 Bx@ya0ktMZA:cP8VD!f릝>|"/Vf$m7SŔ=2|A \L^@@ P0 &#4KhFsMd-dV4*U{ +GD.51߁ 'H,cgIc rjÄ&pu#I&O5hdhaƃ@B F ӽ{w'1‡wW_'isac1b;qml|)ꫯ&X++M׶p/ GH1jtVӄ&gZ`drlr^" T$Dܩώ*}*MD2hqd&loq >%|RQ]SV$`L\{Ua /0ʌpƪs!1 0p0,X ;.`!fI:.VD0vN;_D$T϶++Iz"Ϡ,YPȜǬa#V0w}&s/W~@ E $œyGw9$I\tyl8EXlcuH1e]cgVL>!Pg\`(&f0)GmڒBNL8(ݔ A%Zn4=C&)#m$e4/SۏαJj:i|F gĴ20W>S^WZZs(v8I(\KSKTw.zkﺝUv(h3ь]7K:4}9+<ֺ c 0 5Blbn0rwHiW7-Mq5к@u CL3/ :q6LiH?O1'm]p\w=O?-D$=1wC@]Ko+:wk1eV&_i& ׾\#{ŎBl'wݔfr1'Gkτ{@s s8n=.*S9`h}.lEқpO..]s+]'ϦD6=$XTp1c&\ﺯ|u^0Chg3o9meC4ŔeŒﺯ^_zpKqEkX/6= M WEp;裏֑(D)IWپSk]w.rt>!wU-Ə:͜0{ɸƙ4ilO:2~F_\zW(5/= dE&:{v7ϩ2C@Dଗw [Cbl Qpg B#>%wc'OZ^ ND5h 'xN/zKfg8'\1帮tO]uLG+}yDɆEO4n^{naQuQuM!]K㚦q0&IfKW>1q͓S<rх;d\/2F<\e3.oזV[9Os>qd52\ YBY9@i7L:X~sw>9\v=h+}'o!Q!*? ?/E;B= *v鍦 @}Gc=Vi_sca1}AH*"J@u]g`4@h G։h$~ a{K>DfW?Q&+SDf쩂fM?'{lĉ0fu/Wz̞\xbJtWzd׸3øCh?=WҦ׍sg_yG}}g|\so\ %jKq qˊQ|8㺞OMyG>q='|}v 8 LI맹)~k<ϮrsSǍX}>zIEQI&ϒ-T_|y"&ِPf߱cj?,4e Ô.0+ Cnl9܁ 0h p^~aI&8 c~y癪gG}bH~!xu{h]qN~_z׸#؄Ù~qu/W\a7ʹiD1U2`"u_[ҌC.u; (+\{+=k~9u>u9{~Pg\xE]caipJe3OzޙthқuXǟ}GV=dtd#)Jh$M7^!.cVHdȯ5uІ@@ P"fxana^h918CF``дa2QH`os s d.]tXE40Xт!ң>}~ b^Y ̩ﺯ|uL(6c.AfԩLV+eu_hh]x 7m}};}>|f } 3o3Ɠq^M⒔oڂIggvƙ4&H^s@ƍ7&i\{~ަ$N Ҹi܇S߭ygkq=k @riR6 6wLYF4Ve2cacjSҨa37äQlv+T +HC2ҰˏpR¨<6D*zc,__9MZ_}I7>_2I:yMҶ|( e>QP vB_0L X1{AĄKL P. q $m:ϗFg]I07{|}廮?N4 s2SJi ϒ<uz}u%zӶgkW}㎳#cGa ,U.KiӻqӇ;@{ogx]e30ѶrW'84+u/] LX=CMԡ_W$b^DT⛷wW^5]Mߡ>ʼnk<ϮJoaMtp߫8-䧟cҕҠ]ծ@ڶȩ'͚VM}++t򙭪_[vI-ղN˻ iV&}/+o eb Uo67lU }F97kQ2)yJ3nrjYm+S2s-{թ3?#Q`h`xq$NY 0dFȀrKvT6Ջ2Fʇq 4ҧm+}ܸ%(Mr믝>O˹}rgW9mK>kcEW4M;ʓ*#5gڑy ܸ48QN\zW||v=|woY,q4U)ҥ+deӌ2R;?6iaIjwSdmװZ RiUѲJ\2+i]y=*lZ[YYD=nL)[Aq4[)TvD I>Ü.3eS3(LEB٥6FH ȊQrir[i|if6is4I?J=*5h=ڮzR1HkU*~H' :H٬+1E2RJ~Uj̪/EEije/j2QJǵZG?_=FҰUI4>ӥH.E-ڢƤ¾JKVN;LVˤvR6tDި\I;<0 * dKH^U7|c(Q魚3w)\ @@ ?jU]lleJxYz/)jSB-h_]eFs !tel-߶[UJšq~UJKs}v2L}{J̮cSsϕӕ/IjzäRj5l | RgU-(lQfJ#7ac-oQv?j ߎ8*jRYZZXƯh޴7|cL}|_jS@~Ԫ Plvr-?],-yPqq3I~63x`1ߧMSQ2"b R|˱%&CZ]+2[W"x5^=v5^I(0 "PAcM /@iѴX iݪZP7țj1/h&ep)PQ|F9{Ϊ2`2˕y+gٟF\(shsu+k3+dݴJ@J&!{ E *-2? ŪS\MQkŌ*iT]eMjwח̒&A*E]ِQF*,'L59V  &ms+Gv#:R΋t' G.kEj_P6MIy߄]~&n[}9ٳnl,FL괄oM->IW_}U}rAs;"g \NꡇJ(fcWgD8T} m KT_Sʦ{ fʊ+U eң*ˤf=+T7vi?ߔCd*5mucΓTLWa]v]#yj|cˏ{ktՃsL@`{1}C; 5\w1bO?<N:IXDW뎾MY_)hm/T!Xz -b0%DƓ݉+vye3[v&dѧnPm wոD@J"*MoUOsO7汿 7mBўֿ9007tf0{8Ǐ¼3F?x5jf@ of͔_zz7`$ӌ&L!L#/ĉjS+_9R`d]mcgTΝ;{'ݕW^)h1յ[;of_fm_Q-Z-',N2Eέ\۲/,W]uwW@ۙ=zkt65La䙟q#ۘU*|2$;ݭ[,>$C(>r$sR@@{PvzH[۷LP(M7H?[z`ך#HۖJk[_c~iƷVA u&mbBE@:Tr /o_9ڇc :K(z_Gog~n弞:=Q)DGW׹K+V5<_|[ڵܿa`6Q2,L#LLMhbaq}0I;6HÀf&LDF6Calm%ն_WZӌTs pV\u!|Z83x:θ ҎLaôfڴkf!Mùsʶn)xk[.] ZzVX9@ڵnL}!`j%˞Oaa)R웖ʊ/fWjsBҊQUJsh! o´#ԩbV3tPAh4W/b|mb-E*0^uc:s)i{Bڎ@U;]jU+B 5@j hzʊ8&Z{6ip"iL*G4@Ŵ}6 Z%sPs̑>[}bo_Ç6*Q\Ld҄c@#Pt@ H/\;h2s@ (hT1 j߾6 qՁ25s׿U`Fs`"W~W:50'&YhZmjFmmv ?rghM8L!W]h]}l`tj  ]uF1oz`s.>q֍#̆0';=|B-^|ź߬@0Ya9B i#3wph׾utٛϜo \2i1 P(RbP<\O>G@ P@ CCSő ȠU!"w-~xΞ-=ZL6 M:i9ƍb ci4]GW~W5ƈ f+GwܡM[&7mvf+O|\f(ZY;s9B~67cH~1E9}Kp %H|xޙm5?(\HB#~ԥ@4.gǜF) s->ݻWb M:G8bf"_]2Fz[8|r\'@@`GՍ˾Tk羺|k!y csΣrk Z㕅G 2}0|aoD_@ %hG|ףj⻯.2ҡ"`l}ϟ?ʇX&͚Mo曂Vϲ9_h'6DJґ4}N6Iݾ4 P5G6^6)M c]Bހ@@ C MB怰j|p3(&]6rr1iC,6a8JS_quO0w&]5=DҰ,`IDb³{!5>kޫm$m+aٍN\s5ʋ~I>e]=@]B AF5Ql!$Z]6ou- Tխ'k2 7dȐJPCb>rQGņ3 OxG6MInq-uw ]@vޚ8&P e@@Di߬ɸg4qœhY1v熈wkwӗ;"aR9JyLƍoeq\P6=3:5m)4 հ1MlG8C=44Ѿʂu}76~i9/1}>΀l.cqx8/K12rc&v:_׺ٝwީЖ^xAcJ bcرkG>V|Ag:={م& XA9ctD29pV6=o߼HX@@ j ha0X|L6G>|rL1_^!@dMFm?صO?9 $iaLG ' ]w\HKlRoOMW\q6@HaWJS`Jah̪MԇŽ0}uE0lD`xmʻ =bÍ J/ìN|~m]q1,0Ԍuf_&V2rv,;vp:  8r뭷 UBk+#RQXC HBuGÂr}nfbv%4{qIq;n^̼|g @@( @7̊ZK[\_Zn#35)3KiF./BkTٴM.uCgCC\p6πf.Lk1lv<0_l/:s=I00q2tP].!fڦQl>l0ƹ%mW̲`mr˾obA(QGaN1Jq5jfM0iUvMJ]r%Z` B+eD?m:ݠAj >裦 }dpUWi(\Ac{ތ9eGIo߼wg9( G >hDaF#hT׊ʥLv^ˊdiaK=gtQ%N73)4ɘ.С9Çk ͤF6 {` <@^;Vr&=`fѣR6n8Xg'U2Ԯ~9З)UqEI01eL6M V> ;@@ j#Zsʘqge9Rl˞2pҧҨ*=!!L scc>}0ш4#&# x4=mƍu˅D{ [G1&Ev1cYgSۄ'itm9*,(n5|qQL3h%-Vaz4¾bʄ vAoT0̑tܹR#Cl׫W/1mz3>ߜk^%  PA!(ЖK_`ҤQ35zbfH,!L #q}֭f1 ' +{GۺZχKȅ^nyi*ꌝh'V10;q>{챇^ȣHg4c۬'cJ!V" _~Y _&ǸW~wvvuX@@ j tюbsMd-dV4*U{ 7͉,ԬJك(-t¤}ٲWIk.<1a}ЈhN( 溉oOҦɓ'k -=2DE0x ={j\\{ݵ Nƌĕ\sS ˙g"̫)u&}ڄ=j<0KZSa)kpgHل uaK jCθ6#P.5A>Tp`|}1-iI+_,yIM߮y̱$_F6~6ߚ u@ej4&34lBe>hx}OBs1]ywܡd9k&߮5jPJ@`@`M LXÜ rC# YAca+|sO<8>p_y1Dm؏ L 50+;{uZh_fF_]/ :j]^PhQƧiY^bċan5)@>]>mN8*1g gr0070!iO=TmbdsäFylO?}b7 Q&]s5#p!fp'ʖ2 @X.H4W., Z7 Z  ' 3ghqЬc}׉6O]9R_+b%B` >&N<Ĭh/+:K{ԥ3@@ PӠЀ@@ ?\@`c9la14hc)?]"̎W]u^=xל D|n>+>v`^"8$_mmw|0IbSnMoq=M]u@,]ˉ% u5r]w}MEhѪr)ZnV=GZwsXMۉ;;S]3'd6@XW& X Ti @@ P( 25>G%o ,1TE@@2fWijkCDA` {~I {}VإICy\y% y@YU$Y8 #`(*1y sYsΊit͂p AD4k={Mo޼Ѫs޻ow[U]]-|6Chd 7ܰVZ0 'kSĕ%yVPEy!P >F|XCqC4^{+Z%?Ƴ| N0}k us8N}[lQѼ( n2J \?PN|t;rq5I3B}gf檫*'own;3|p3x`7 O_|s@yOLC(E/U(eڴiB!k(/Ҁ1<)AQsΩS/)'_h]H[=B/P#-mԣG~|k+Q%/&a"i l&d=Yc^Lr7ڋbD8H_|>!?0ZBysAyB]X[]>RKz.i%E@PE@hx*P *_sv˙V0sie_̘Č6}Šw\/\jXQSHq@fL"_Ct #AdNrtꩧ:2c,<]tENa4Fr2"#$(k,XX_פ{V~G S^u?.~P9((# F{X)FY0i':~6ra(Ȉqs1Q䉖JџI^eTA't \-}ĒgC=$]e+?}>/1G>'l|I?ߕ\ UE@P!PEU%B~?s-dj,5{v2?-mafYb:ulgVm:K8>_Ud\'M&hf%,XأABߛ'YC{QH#\zwYguj׵օ#NHW wH^rz-4o( &GUUSLB`h+2%]B>C9=>׽{wF';*Ji\>{cVE+.c_FQ!}\B7}ZRzNPE@P@E~;3snYؘE N;oL\m,ja],>4Xv)1~n\H1 aD,2p|Ȑ!ޕn^?|!agUOҦnj>#W7yݞJ;T"nAI ~D(&XioB(ZQ|8è 9)!"r[o9qq}d-tYo 6&uyK=~WsdVO*"(@k1!X-ڴoc |fV0?Jiwfw -~*vh0{Ɋ).&qtM΍xa2_Vu#{ba&r .BiԳgO n$w/iF9J4d((OR]Zk-'x<&){*Ü2ϯ҃ROClsI;w{q͉0bQFy}l\K{.u_PE@P)T\Kd@uW3˵kk:`Z,igZصZ2Yuj n t"r)fvVN%?Ct뭷Ir>[OD _A] eǁ{qBd$QAț''_E@PEha. sLK_`3[`4Sti1+;tYu-ӷ6GBL͝;*BYτD*7xbN5\&gV],7B! PfOƥ(S"N}BY\]Jg^%'&NY͛>]%,u4"(oWp_e DLE@Q@،2C#"!(#wqan)oE)k"h粙ç+"(eAd> CYjs&LV3,y*RIPj#emnHPE@m"P¿Mh֊"("(@E@6ʙ"("("`"`jƊ"("(@E"sX & K?>a)2jJ"("("pTD ~;>[}H‡J8&j\UE@HF58X! -6%]vmlvݬɽ.K0 '+]^j%Zs +T_XƳgvϨN' _<~ˊ+LZ]z>*DCGCb|U(_k|0CN~aÊvѼ2ICwyGsXD 3"t Bosg1vX}?_Uw9ͫ5ֿ_}aMoCeW\z?n> oY*#G43'OVku"‘O?a+_QJ,,R&X$_p1n>sϙnɜxn͋U})/OBS.6 R妰N*pW7>KkgOW\q{~bVZ,fUW5\pA19y :xs:2/?I"V fm mH'kk'&>t߭[7C!C / ~߷o_ӳg&vΝ +V*]^zaDx>3 E%}Q믿n~{od05]x磀:i@E\A5/$0lk>֏ӗ^zlkرfewA@*2b>1_~衇^7wm>޽{;w}nL^HE=#8}~E5aN;;̼ ;p8~74sxݜ.,(pb͊,i嗻mhֱk,X{キ+__T.M`q9lL a(6|0s1fΜ9/ [(fmVP~!,7o %\R'|Bm.1'}]Kh8sCQ2!CǍg6tSWU^p{ aL})kWtk:묳=c]7]sL ~Y,/3{t̙38À+2+1pL4ܿ"_rOr›RA"#| :+ @H񿿘gL[qb./{t]wuXy9w6^np|GO'/Wy+lN;i<=fww<#AD#TzRL: QHk(/<^oV>ڝ?^\zu0z.avE~oeIO>ҿWg;tIw 0Ew纏b[Y9.Gy] [?Z7Q9J~Ɔ"eC>!)zŖJ2uיo |!UOzp xn0o[q󌺝s<`6e˖ѷ ʣ]y0O%fp`][\/+>0W]uS\L޸ BE.bgYCŇa9C(E`/U(ݴiӜB(ZP^cxcN}xY.!䇕'Z/)'Œ6ZV%ǔ!!FåRH[n09_'Gv!0p>쳝pE{am#r䝧qyLҷq]w>d(yw#b8$]LsBC_"%ży4(xm{W`r-Xb\aqĉFˆe'HьDvtt)Fk, x]tq *FB$,ۋ.ՃťTJJ}B'ϯC7'/y u 7Ѝ^`:&qmsw=JiSPO*Ÿ1l헥=yK^kT5 ԶCOE-͌KL?8A.*CËVoP򗿸6L!AKƪǑ| 1,:{ꩧ:{yJMO|P`<Ќ5 MK(?LF`{ܨu\\^=#8OzQ\]BiB | ch|gDmx12!( 0K/'CTJǏlQ.!,#Js(6(O>F~M;\D6O?M_aR͇^>*lBm'-]û/J`q}(˽48ORߋ8T$ڮqy?'81b!'+.ß' ??7/*2"@e#Du%ҟL͒wNf V4˵mc:u`V-ɋ/0 /X9/*Ȯa$/2>HYv$(:'%2.=`# bɯ>N⋵U+wPJ]P9''t˽l`"髪gFBhB\nˑwZQأ b_裀@GkKXXBFޢRH;u$IjmCk%(!gͮkuYY;uQbvsH }\pw+ᄄ2O:Fx,̑%#ҷr&/H{H諯r}M"ȣ/Dc 63FfB_;餓n[nf 1X ;)Oɛ(6}(Dh Irl^Yʈky<}{ϼ?Fq;synใW\,TdD |Ko̹5fbcj-4;YS 3irYus _˕TA \7\H ^C,&3#=,,[i)S8|y#&HR7͛W)5P]xA*X;H${`fTQrR9N7J<#e9\QȄD3OEvm7g1g$pb8R"O1ҷxH >D`4 >jQq`1pp_蜟W>VrR~9ih0!- "!WX$/C0&9Qb1/B}[^OV8yR\>Š^E)3?K9/D ӶnFΈQGx-?+u}h g~'0V> Vx,Xk򛅻}/Sx_ o>:؏W 1*؏UNAZ\Zk(Iv筕`UPwO^1Wzֹ&'@U~؅,>~Pcc܁X ւ `'[:rV:{'x(;cb2׾R>ىsn?G?z:؆,XmIlUܳZ\?fя#VAv?qyH^KLxj[ xD hR{Dj7'ϮO{8S :iBϒ[./+Rv)[ֳ[2!FZC VY,XwOn~}#fW5   w[׮L׮ؾiiUchthCd%5>ྃ+4O3{޾< >X!|nk,~^fi<M,DI#,nDXp*gRkmX|t~QFȴ G6e!=XM5dH痴D 5+mJXrPZ<wFW9 i}0d#}OUpXͱQ(P)ek6ky~Y7O~ڸؿ/~R0iz$rO~Ylŷ!ɓm:@8º t2Tn 7 К,mߟfj.0- +;tYu-ӷ6}Cǰ6yf%:1w"ȔB<1' 3.˖ 4Źuw`qzI]P>nO夆ȳ6-rcGm-HBHGCÁ1 2;lYVocz욨p܄CDKg>u PfOhϥ(SOXR%Ur`BۗB(q!\+5o7oo?65iizh|5ʭFCټQ<\Kl\K7& B4f7!qAaA!V$⎐J;1+"("Wa)2Z<zAPE@PE@Pr#PEIl! *sL .u("("(G"A(XY*Ӕrk-qR?lvm>13("(eC"A%$jժֹհgK/>}-آޜF;vYve띯fl3rH0sᇛ/Sgyݻkw}nL^MDO*"(@ȈA? @H񿿘gL$]v,f7=X1[>S'GagZo9,Z]!o,b+9ӊwOw)z#8l3s)ԩSbl_>EC5o&[m裏vozu ѡbr7pIQOHi $aMKՙ6;<3W\ќ{oΝ-ͪqI|ҏB _\:,C?A.IniF?;0Ev{m`yӓ uSRE@PGb~,^{3fT3ڌ_eޝ0T iLD}8pꪫBZ}|,\pdsNzJ Ipʼncʇo5ڨG.JGwEkzO>1{챇K_R38}o6#WIsimAׅ^I˖-S>WtAoaϽ3gtجŬvh񄷓7=e+)"(@#PEjȈVD۶[δM+f%foʹ |`&L`?|%:.5?I򗿘} ~コ&:pW_m6lbzNxL3E]F<@3j(/!2Bϑb̘1Jj|_{5wuMKgd7BquA)DPGO0ڳ( &R62qD'oFfV0]tNad;;3LFsim/1G>,l|R7_"("pTD`F%ҟL͒wNf V4˵mc:u`V-ɋ/ C %B욷~ ,kF\aQZwuZn$k(pVDn<1,YX>;~]k] nҭ[7/JWA)uC[ 䫯$fDnr TVZiisKWƊ ";i<IO(wرS dPM5)[FPX;u$yKje"(" TD@Ǣ%4єH͢f^L?v37XɴjƼ‡E@ .B"l9v RDA馛>Ȝ|nw)5P]db85 dUWuͨ@)4>" .R~ NqmW_05;! ` 6oz[L@PE@P(5CXB-ڴoc |fV0?Eiwfw-TC q#  Ds=B# O8“X} s믛oJ,<}pJ={(О6!.O0G `LyIZkqpak=| ɜz0]w7oS}rxCmqQ-Ij>Gݨ|\CDzL( V1F(oz?[g s}&^g!-YʈṂCF/혵V(cܹm+㚑"(M)%2Gۺڵ5w0-3j[m,:B NSN9nuʉ|tJWFD.7H.?hڔx$b/wc~aPqkBq.)Dzr- RM﷉?[GePFJwZiK)svs}J?=# (/ OFP_V@.kᮻ߈u)7`-9+De`]A s|U9³ϼRۅOU瞇 #PSc"3 e$^˂ ( Ke9d=lʂ@IQ K׿ ʵOqR];+c'RL{5g)mAϧr9aG VNݷѬ v'5$ȓFrF*Чmׯ> >I#u}{-WVQ ָP«*-p jU V*ղ5k(X%~&lRu_~+]$>1acB]^d:fϞI=T>pƅ7w'a >?˛оJ"(H 7t+"F"໏ݛvP|xPF;R| YǴX\e A;cE>eЅqaKyBc 1u PЎ ɓ'樣*ŅFB3N;vA`ΈP9W: ENʧ|/Yf9(rE`/B5&9z+" cikm,W`V+߬Yj&@)M * LdNGźhvecz! { Fv@8W6օȭ-ŝNP l.AByfiF8>}ޢea=gb^ ?E@P*@U.Z"(C $ l\S0x`Gp<&ɢu=xq 8yXQ8O'|ҹd @ mEz!޸W^yōH;  gdq~}rʍT5 I!Fn(_TRE@HG@ߖi E@P bu3p,D"1kO[!DAhBB(XʹQS^z' !R8&d'.|턵L|yV,ћ;X NcE@P`0UɋWIPF3sb)̈́-?>X噼>cN-e"! ؀PpҀ;Kom)|"Sr?}ԏ ظ e0Cr4"( 7QFʷQ|#z7U#_ac-n>yyBIP@HRQb8/i*Ԕx.OY%Z_>z*qePRE@ȇ@E&n!賕rDsv9c(nE@5!@Nb:1\l lLE@P~-TdJB>>, G Kk5vO4 &n3!W)/O,eǥ!]|xR ,a's YԫK)Oi<ӔA)VPE Q`I,|Xڶm~ #ˏr=D:33p@sUWW %own;3|p3x`7 Or?{ERvBXP\M欤wBѺ" gC8Cu pbGźii=z#:m%ʣ%$L$ [S!G,{챇K/38}o6WJi<0(y]xᅮJ39s(,% eF!MG!K,uAkzE@PE@ȇ@EXB on9Ӷ f7Z5Ӧs\*X#4Β:Ab} ~C Άn8=W_}[Re{ꩧnD0,<# x5j˖!A ]`njLFz}5)/]v,6TZ xIbwC"'ro6ʂNL8 m[K.r)rvw[MLFsim}E\?q>#U((Ld%b.s},>zZIPE@PE@Aўk'Sdݳii 3sөc;3kyk!_:a2$"=BLfɌY 0Vm([H|$k(p/# iKn<묳Nֺ8@Jj)\nK*C@$4ʂQUU84[%64>" s((dQ])C:n܃xwOcǎNQGY=KIPE@P((\Bs13֘YfO-̤fɢC3pm~_8! +0܋BIC IJZOSLqi#a"m棏>ruC`7o^)롺eq Ҧ#%Dy0:M{cfnD9)4>" .R~o'R6pa$gy6!|ʅkyw|4"("[E"Ad5CX[i2`&~Xe>ڴ}{;ϖu:X8{g@`bwa4#<՗=0q믿8DYx~4ٳsBO;u0G `a.)B$er71#`bqmn=`·iJ뮻)=(UI>~9iiWoFr6df[yFLE@PE"@UDt[w5\cŒvU&ԺІBS{\HpQ}SN1[rt>L܅ #FH)%OB`' OӧO7u'qA!nݺ&BD}vLfDa$!.'tLAO* k3?tɽixM\sY"P{C$lnV7Wk,#?D9mS%U4+"(@yhasLysae/0x-XLxY\֘fo !Νkp Ϭh qHA)s7 >+BbX\bDa[Fg[kq .m"s(}%yLp wtYx㳔 )P}X@v%>:k,*ƻ>˖色ȇn7!z凌E@PR~#}7R[.E-W_}8Y ;6 ZYۘ=&*܏@r}B H %|QxAYJ~DRŘ<*9y0EB .iP,-Pd%=sz79$:R!D_FPpcdP~J܋gXx'fϞ]‡[ڈ$ʚ.)(MW\p_Q$@'dM;G(BCPF;R~RL5 0iҤSBϕ_G~k[.wXg < eO`$=Vf%QtIya\Eǥ5gF p=d)n((k%ΚNzBP C b*UTjەR(hZɓ' 7N_Eӓecc?1R-neY@(@sC"@sEUE) 0rHg G f!7ݒ@D׿v W_ _B g- Lp5s}gd+Ţ|]w~.<5Rh]EcוO\5;2At( Yi\5F `:D8+,2? Dth]i8fb<ōQ;Ε˨q\[)CtK+$zY0dMW*z"4*5TW9QEy p B.^x'83Y_By.BW^Jz&^\qi!>-2H-%pRӦMsʆK'B+ѡ2_x| n(Ѻσީ] !p $*w}nJIbB~q ń5w!qrccpymN8(qRtXPQe-P`ѕE_GRE27əjݜ%qsΕ=ϽXѓde hzθ`Gȍ|e+ҢQYI1B0'I ~[ YIz*@ELցIq_V` 6=0(o߱IĂsVUUNZL[Y6"$/)cc s&bMg^uC3gt}3p]oF:PFuݵ #4QJ n?ƅbP*15Epc/(KeM'eVP~TdD/ 0Xx[0RUb&1|ːs)M4/ܕpAE0`@4Ih),qa.=cu( K܇|QG9k~y+s7|(w? EK!OTBeaڎ&#CYӕŸޣ(MV/ )f!/XA`-&~SL)?MN*Xʆa"CBSxg2,_'x`] `-kPJ^y˓>ُcZ+YTbW ` VH+X䂝HX.Xg_~1eM/YeX`]T _`+!EcΓ y. g~ ޓwk;W|H_WGR<עU vidA+ͥZҽD(Q׏㎳RWpח[d1k"7W_-kGVp?dJ~}#*2"*Ĩ} #&;^z/E;vl2X߼ P6#3͊Za__> ?\:k(C=ũ&=jĤP4ϰ:KѺpw* ~Ϭo0ӱO^i3ۑI}Ȏ 9pE d u!-:eM[)eo$ⰦD5yw%oa5;*WJK 6̹pev!+ˑzX/ 1 xīGa@$-iڊ8\uUNq!> K&At;&g!C"!ªOǢ;LCXG5i>\pd cU+w?{.$AQ>|Cqq6"iZi+QS&~:{Z3D҇ 68],wڒQ-~yK'OQ0kC=&FC<0ia9& xL24jCVQ<ۼl,̟w"(@G <!#d%z Pc|~QK3cS=on۷Vrq̢*Xkc c zY/K16a=U\>b܃yWYwnBP<Ќ5ʭhD.ƌ\0ߧmܨu\\^=@x)T qu$Fu!bK=Cm)!N8+JT ,(i2 D(!Q" (9eg(|1w,m>&22SlҤI.2\Ly9'[95|KUE@PC"YFoK25K=;03,1:3s6WYVͿK Xq'"<!Bf%VĪ%YDD_Fsp`'>.XYV(T/ݖR#T+bZ҆Y0"IDJ+T*˒>Jk0=OF˶v[) rYP $[Ueka_iϛob+)"(@"P1 *9єH͢f^L?v37XɴjƼ‡uj`nfЂ; B"VhZ9Ճ.BۼX𣝄PCUW]յ7>IyYo(lDiJ@ZyqXqbČ Y㓋+1GgNCm#VPE@Pʏ@Eqʍn֦};_3˴a0M߷73;lY2dQ@!ʞ{Y'-',18]l,berw=L\RkC0oJ,<ងpe7 &!1%6 (bA4 T|qa!2A(VR0]wpTғxn דf~ JAԃ8Bg$9cJ!xbC#FԊ7o+"(@ P1E!nfktlXδikڴne:a?ԩ1.$Cu6VN9(>G8+,#t"D .%Oӧ;)=(2I7%o.xPHE{T\ I,< Fĵ#)> CXit%)5kOJG0 _>.?\h{׹!CR~Sa=yd7QBzQNpF EzS/2TY"D oz%9[E@PE@h8Za5:Be/ K,3ΰo;ivri[]0wZo-lJ$"䙕 LKF M!@u&24kg7oF*YbDa[Fg[gqI Jm1O*QJVw<2GE\kRHi4D4Ba?d c B,[~2'"u`ԑ>N$$\Ҩ{iuE@PETH)F  .E-#.|NVʝ[ Ƭz +ܷ1=zvMT?n"|Ep⣏|C(q)J𔃘Ph"-yɫQR{7sb׃g#ȍB?7}\>z^PE@Pʇ@+/2",e( qBf޴se;0;C-eNxSB*)"("(M W,C`4;cE@PE@PT*2Y8 M("("(E@­)"("(MUF;("GJ{KF"-MXrk,^\i>"(1Td ~Ąa o'!Q?ưE@u";bt)L#z)e(Z&vE{,Aָ`eu%E@PC"#oD|y>lY<'905.yA9+" B1e{׊7a޽]V&3t-uUX[(fݻw7XyG{.Y1w~#߽]}W5AyL:՝?guB,ɪj;bq|DvX.O^X ׿g5v%E@PA"Y? [Ei^{?NOX5556Gy[ٵ>P{tMOt Շh^jG>'mRi׆ IWrҖ6k]ߜ6 2$iEofm`e| BhMW!1C= أмۆU_|oѼ|JHhz("P~*2"G&<`ct_3S-~⪊ ?_ެ+&u]q߾}!NaO{7GvFi,~\"o>+N;xGOO<}e7<z1t>c`0PRbA}r<}ђ.X XZ~>`"_.\fih7x&G=.\(Y&aMLՙ6;]Š +9sMuu.X]NY=ѭo%U+ mֆ2 K_ftD >jGinP ~qQpj (^,N;9 n[;^x!XYfy ! 'N<'4K,qϤ+u+J'/ϧ&\rv?%cv '&A0 @bE0ŗ7>33p@sUW};Ç,|t;W &"C 1Gȃ/U(n5 h]CyeG .lq^x I5?f5,fe?n>BL*bPyO_ x;J+d."{pҁ;:MtHF"s= Sj9>||%N:$fňϯ"(@ P XG '<,i5Kiۡ'f%zReηF|`&L`z)'`mK _w}%o<:\p+ȫE.9k ?(4ikz& ?:0$t'g aC܆(O|^Fs<;1ixO(+2e] 9Q/*"_N˳NNX q=bOfRӻg'f%Svfnצ*|Xh ,d\= 1i!kVU=J md E@K#\zwaO~]}\6r#?iC R"y֒6͂WUU+(V\!()iE GpZ(,!H2ǃ|WΝ =D!,%ݠA. 2_V&aFPwc/-?I.y!@"B(B!ʛ>GS9'}зhGPߊWr# ~TյVgSMQE9!P9d,$an֦};_3˴a M߷73;WD†kCB#,P[ q@,&.c }i'0V_&!@ݧmQpO"i'.޸<0i 4L|~%u]\zW徎{s$Zo\G蜗XUy &{<|_~SbȏQ#FԊZ7}__*"Cblaõh"X?Y][ӱ}bI;ӪƮ-кІP&|&m" ԝr)E  a$BO2B'JrM#Yx>}ڃ" FU3a&BDgab!qqEan$‡P]DdچB~rX4vG4L|~I裏p MJmQP|E87/(r{m:.'FZ~X(-?s(P nJ@q|yE@PE@?-\`*B'XMXbp5^~ ؉OK󻂙LU2}maw! *BYτd9Lel+#2:XDIJ׳dO!D7}<5"("$#'n" Bf7!6q7A;;vKYޔzJ"("(@SB*+ȍQq+Î;֎|T$Cc$nE@PE@PET5%!a? [E*i_l9^{?ΖLjjj?lVk'ЏЪUZ d^2}1[lE=s2&رcͲ.[|5giz턒-fvۙ^z+qW"~W`o?nț(=Dɓ ?hțo6wiXc3*t]woѰ9c}[ֺ'kZ7"4K*be!cT~yfԹ.M$.f7믿yNJɱpܷo_s! Q#GagZo9,Z]!o, N+ޑOz9sdgԩNcA63NBѺ:C͛onpGK6n``j%Cu2+HQx wh…Em&ĴK]i3>PZ{=3W\ќ{Ν;[nX uʚK.1mYeU^ 2+6ƈaxl׮{}`Vd:ӥKV[͹BTJIXJ=?#]tyꩧUwҤIp;駟^9 wA%?뮻)X1@qb;M9 <_<+s{WF]0p@sI'9޹e]V+y^z #1B_t);Ļ.g{׹0叚'_yDLִ{n\eQGꫯ.'ypWګ>_;o>etun""E/n~njjfTU̻Y_G"L"/(F( I^{e=ڹ*.ߴ>V(|M >ls7NYӮ:F~Zs ʅ̙3ok㏿]fG8vm Pl$Iq*}! /8AVy` xsW:KRy6~7tS;y;SyG]}QbP|A7;n8'#ds=Nł`e+W_? u Hx@㢼e>&xʻ$ҡ0"η%Jqu #/)\0HxǢmޓ(Irw)ygw(hBϟ?_۬7"4[*J`l߾in9Ӷ f7Z5Ӧs/(X.&L^|찮RceP_(コ&:p$,>჉MO!|2pQFl ݥ`nj,L^1~]/G ЧP~\]4qrPԱH'A8(eD]&Nw|WXaP&A(; (m(5-Zkl'ʫ[_l!bލK˹'t`I>YO:O3orN=@;31!iR?"F,:,7"4b8e˖(eMOE!Ъ,ca$ ~?s-dj,5{v2?-mafYb:ulgVm:R2_:%Bo{&LJZbyr%^B[vYx5'# iĐ1n<||20U+4PZt[J]$P9X@KmL檪*!E)K{J[@W$Aִ/ی0S}!/QBF;up@x@AnbՔ4-||)lkhFp .xJ~ruq{ Bq`YY(鍻Z\k$hyDxCeB/w^(9=YnC>/Ht>as%͋<L/c,Y#p1ka׵%zѢEX(?nIcuI/x( }qQ8&<G^8F (|{umw0=oOY'T{)N@z1A#a#dH)O?B+/6>B'IIaA!MIʏD˻ O6J(].zLPbLV$ LI1#fE4f~c)f Ulڴ1,6dAb_{l3b_}2&~}a 3&<$fXVb&9f3wvLFv312˺mc~coX}b3}s05c='3!A1Žnw8Fx XbELԗcƒ3z~p.yw^A0Fbflyb!Cر11Bh$L%V_k߾L83>C<zh3_g9%jk^1#lF~xA2ll fI<k$zb~c5_N"ÞIfc,c%.+l9N=w-'{BPQ: G?>F،q{*!\g ޒGK6W"G1G3F1ڏ=;nB,jأgDvA<X,ém<Q׻%aCGwŊx`a➸}Y!5 rT\A˝Ɩs/H An gz>D$qX g-sz1dr^Y$[{;Yxv?"cl$ -گ"(e;qtF{!IRt#<NWM*)6{9_եkVJ9'ܤK>P7'c'yL'UL4BY$K~KwJN*p(~/1/f܋TOdR?A87{wdm'|ƭm9fQ*%E@P+詏L8@aCP@Q@ LAS9FMPFzbU&R+)(oV)ur8}׭"(։@`UgK*l)r:"!+nO%E@PE@.9)h"("("*WE@PE@PJ aa`_Rr E@PE@PE UVw}MNrXjժ']?}RReԑwVPE@PE@P @%ExPBaEl!W>1wnE@PE@PE `jժu n=DU;i |}d!Ǭroc[~a0aBN6JYX8 1JIxe"J(c'jC~!~:W,;~l$fp\X,nʔ)QjE@PE@H6mH=(D`.Oa)a$c)?#vȣ>* Bg%2^*mCMr_k?f׍W~lz'UElR4h 6mTn-Zoa=CXk]v{/]txΝexп"("dp}XB?JBŊK|GzYb} 6LS*G}d?ЮE/Ա+_|pr'KǎM_}һwoy衇dʕv}GzU-nVi֬=_q's5]@)=("(D 'B ~,ʇ.I6a#VLrI'doV@aO?]:"/ @D`/U/1 N(s 6` W]uB7br r |( r2maڰ%1b7ȯ*~73V(F3=k%^-~~7ߴ!O^LacI J!CRkbzgl> A͚5οufLR^{U \uGPE@P@NG pR#Ԩ]ZQV 7#WȔipQouBj^zx뮻Ά? TX ؄&`U'gw :p >h-_nw$~tmY/}o7\ZIF@ꫯwa}9 , KA'MqP QFx&N( &nl/bwɞ2~ 7tDz=7QۢX96(qxcƌx7]v+!;"WG<;}w2(kp >̻lHv>Y88RRE@.9:BPk/ X`H6m,'Hzy2obiҸh3fHZX pD腣Ç8d"V_~BrTre'@QHF7s'a4ɷ8 ;ߦ3G8@Nrj2c̙V[/hD^E͝ 0cZE6lPQ D6^P!vƒw~Y9JuBaF5j ~r5X%0\PmM4Sҙ[>OgL_dygB C?E@PȉGJByʸId .\F^^tj UCǸ-BB!B* $8AW3*O&MJT!F?Reܸqr饗Z“nAsqB 3.,(K Vn7r/>Ck qi=cs5P^56(xzHjE()Kx#!O;G,ةS'v64| "akSΡX3w(ƽpDx"Iխ[779L=۷{`E|2kGA=g!v\5yB7Q">yuz|P/2{TxPr9aom>/d1))"Pȉ"9!4feɯnV.*/cfbW7ڵؽe @ӯ_bm9 K /e4#:.e;q\ _m%8FQx"~Rهd@1NhOېO0KK,((H<~< !xƒpAbq2Bšss̀a׵}G(UD_qKq]hB1,0JF`g/ aq$!a}^yPj,@Xcu`?(|MpmwJr/P`I>. 7-4;W΋sB\I o CY;bE~=O?Oyח_~ٶu2.S Y~\?<x L[Nu 7ܘ{vA=pg2?DX[oe1"7IIP@#@h /N^5y5^~-)W' +JTVBB(;<zںyQa#o',wxߣ4m4%" /RڈB۷Iɮ :O%۶mk$HvaAݱ |Xr\.̽Z3hK}z50K[#4{JjůˀEglb% #7E_@Ӯ*wqG\H>g~(@(XIGG*^owLl#.䢐k¼ JҢ3@xQ ~c1R'8OEXa<8EOJ"e*f{Xb@XPYz0k l'60 1miִM Hly*H I'VKIdxqO?4'!|!`AE%gYuǼM9Go<x;s"fp/ɳSNaGr(;1 ?XH _"4 ]JgH-a _y61xA2l>\,;JDXa*Lxy۹}{ڕ-Ot[#\cF!EDm~ dnN!FymF9<}A}|sc>"$'˛ Bs} ^\9Byˈe'0]Ib㷝~OP2_Rt&O\\HCӰIeYƄm^bΗ3/ҵ[+#o%JVDw!*v&裏Nh9sפ ㉗5Am}( x O4mIu'DE.L ԾǼr/RŦ|F[B45R;Бqm,rv"CX :th $g϶5] B7G(^<!WL ޸fΜ960 0!F|aw !悢<kEw}b 060,AF ֣tnL hyA`M2Kz'mD.ԱE `]v!^Ñ;.ns*Ex !j(80"%k A `<$'aKu0>^Br!q^_ ~( 9B1!!?h3c Jx$dUںU@9;#,QVy+G3F5BPl8}1Hb2Gء+3D%, H1$@8~KogL2&R%/jaC³ qܓ(@F@}u"c(I&/c" O;Mγ(*Y^UE`C@)Ê"#୎Sшsi]ySE WDd%zcU"~suE@PE@PEL"EZl!^W2X2y7tҊ"("(@zPş 5]ͽ0?L0l6u)G+ ߩJ(c'jCW/sqxyǦ4)"(@F '8?񛬒ˇ C-g*GN+>v]ڕH; ~|Rs*mCMr_1c[jxǏM6XmѢ]l[liVʬn<7=|p{vg*r-^OC""("d(.A5׭[⧮Vw>ӧ] XԭdZ|d=- j|*%+($7x,Y"/r|tҹLQE@Pȉ"@h˿x OH&MgۄaVرcG:kJ*'t=oI^Y8i>#9B[N zWĻHo-v AԼF{CvQxfgvuNaMwms OV}v<©X5h^6nҥs<+HϮ0N&vs_8;g+(HAY 7ExX}s=zť=\.:Jo݆P]s5[|gVBX";e ^>+Dzw^^^c=lqѣG;СC%E@PE89SXY!˿ ~d>s 9S~=Mf^,C>KB,҃pugȑ#mSZ:Yab#.gu<Vq-}_|Ų>ȇ~(O?' Ȉ#? %Cq2e P85/ڀ1<^uUv>t ۠믿ؼ8-As!Mx{1>|C(ڜx^9^ ێT~7믿nH x pZyDŽ{W ߨm~{z7!O^tA +v6L'Hwm(W^)-?36S XE@PE D`(# /5jKZܥe 2}N|3rLH(%k7lG@ٳx> X@7𑈸\o/\ ~tmY/}oxCV\)}XPW_yٱkX_{;6l Z*Oм4|I4OA"L`iQLܗ_~ ;wή^~C tMrAY axܹnxFibѦM2?#*qR*Ϗ;ڸq  .8?.xPQ|wrλ-3y6v(<_(()"(@IPk/ X`H6m,'Hzy2obiҸ~f̘a%G7v6ddV_Q~j׮]“[CQ ($#BzƃUK޹zӍ0oZ! Qм96>(_LX3gδ*~%!ȫQ BC2vXh>ؖo_n^zV"NC=T.\((~"|, tbkUQ}KFX%E@PE@.9QQyʬyfH5rAer2v|)X[΄"ܯzR~A g%"Xõ($\Fzo>p\XS%o( mI/ªH%h.(Cu <+QcS0pw9*ecK}wBɰ! !ן;}(㕆6g϶~+P yfq=,bI2xƩļQ~kNKٚONj:Q|#+Kt-ᦴKD"-2Nt):M) ȏ{ӕ{7lRY֬1ap_]vkp=}BX: % ON· O& Eu,\ұgJN*p(3tm:Ǽr/aPoԐ!C+IF -"x/_|zXu+#j Q—b13I a~JL*~H(g9s"(OP} 9?o|_{؅駟'33Fnʻ;:1{~XX"URQ+@d]@@!Lxq "L Ea+0OD Aaq%,'|!W@ |. \2 # W_msk~kyf(_Xۄf`JHNP-E怵5Lw(9ELzǣ/PuVOԿ<]K߬swuB,HZŻロP;>Nq?)f 1%E@Pr@N\LDPE`[Bu;*qoD$^m*(}z .B3ybT%sڠ$Cɍе_O8VIɅ`~p'd\9b!pu(@6Iՠl0}*"-# 5{՛"A4+9#1j6e;QfͲX;VJ܆f?%ԈdY npǝ#;u _$5K G?ѵQN5wN9K=HV+@F SȜVBs VLw׭"(edDz,X)ɪ~4>Asx$2AW7J_A}^Z{A}1E@P2@7LFC @G?V"4So)^5&p抰QO?;t˃/\(96ٸa)J tA7֊ 3f̈Wٚ0ҼRESE@9KFGEE95>ď59%wGNY`\Y% e2^*mLv_I]umlJ?_tb4Q2U6Ϥ8Fo*"lyrp>Xy~<c[p}*z} 6,i\jIxX$DQU%E@PE@>91!cw}E2i򼤡AӧO>Va59*B$]}׸k[9lR; "%߶>T8ceɫ*/Pοb'e1<\:꛴wBm2^xмm>o.yV#xcQ( ?G<ǻ ێ}Gay_MݯAY % =aSԶLlݷ8#!;am>Wa5?N x"("d{̔=3F^M0!f2c ,ojcƎ_b/I싯Ů?؇C tD #&.fgbF}A8fBbF03ebF2uM;cFKc$n%+.f)3|p(1#L1S"fmǢdVcbkժU|+WƎ;))g5ぁ͢:1#/^l P\GN/8☩]yxv-\hf7| b'fE]3#1ŌLjQ1#4&}>k`hG_[ožk4ؘY56tv63tglܰsf?w΅DtLYƘ3lbFQғ{Q1s6C߽D㊀"(@I; 'A(0xG6LȬ+SV]IV EY?ThԨQ2zh1Bu6uޝn뮓>SN41X a9yHD\ӿymªU4ejc'zGy㏷gwy<$Xd{䡇#ĊFb;x5yʱD}9+`ׅ+Qt0q -Fy{V۳N;ޣ(7Fzȑ#/x` jb3G(2V@GXdb*ׯX[ 1 mxq@g٥l'^"q˪;{*p? OH/\*uf Q/tQR5ǓQ>asAC&sϵ+j&aCPV $˯k#Xd(+ϩOwt/lܰsdT|.I(ɔdcyE@PE@@#@h X۷k.jHZR O**WZթ,TZMk& t"\ver衇&/lMBC.:\Z,wx5Ӵi"e $#vxPH}Bt*Z %!!DsqޖTIUI}E}MX:ckиaa=}DK)"(@d]@!L?DBfеɎQbpzJ쒌)%K҆@FعDQv?a[߂PH[4k*WJaċ%6N RrY|0ٺ9Q-0n E64}ܺ]w-^/9gBPJ3滣)@F࣏>p⣎:ʮxM(y4.8!uԑSN9^ lle~Gkfa7gO#cǎr뭷İJ:-0`چG<*"ļ) xҳgO[+w|S7+ȳ *|̓W?tW@H"rά~{AxO?dE^2D_M L69pwqG("W^JaE`A 'Ch-_Jn征p~WE#pHX B.%jgv6j[aB%=ջ^SJje\ ʔ)VD,gq :# O<>s]XQ-\R@]GɁP$bզD3VJnOxKZK L?7xyE  Q^E)v7|]\:w/?pk׽A?)]tA]e  #,YVP!r̞ 1˼" VLGxcQE "s*KX!۪U+P>B,qaO5E 1"|p=%Q bM; c CQB!5@jݺP[PrA()|xᘒ"l{$4w 2NZ5/N +JJ䃏 Șqeҽsc9'Um{Rg(#9'{{#@SDY@Ї=\U>AO`jY:dgnc5WsyIZXQ9a'l*QM(Ye}Y.} <"x6I-Ò]=`1@dS|nKf&"']6̺b[e,/ܱc{g}%WNS/QNK!Š\mQ&<*>jeXډoB{1̙3m|=a!4{ȬM%͓U  Xpcmᛸsk* VÜRYf9ꪫlbr޹r-,x.x(ќtb2Gs qdcm)wJIP=r8p߮jUX4*HjUeC)_UHE[#&w+1I&W>˃/J8ᅓRs*m8M6s5n޶68x`+2>$"B90I}Pz/X_e++BXo`r!a->D20`!4gK.Ҿ}{’|zrw^GOV87xU"PLZ^/Oti9aȹۂtW^W\qM&|;&Eij1IJ"!P$oN?tDlЄdeRrU9{zyUc&\(&e&T//GU4Ν o>HF`JƒkZ!9Ri'T@t6r5n*<ƶ.$*"ո'1g/$3|Ϡ}=4^:ǰ#$&ZT>iv$:SRt+v|HhH$[w,XY+k-Zd2^AϏ4'/׃/`R?K\E`[B SH3g#0nT}WC׮]c9F/^, ~Ա\aZl_Vल%x7rxpqlK-waXx?ob?SuKTn d$Q ySk7[uˆ7K]5ᝐsGr(ϱ(\ﲾO2˭7+sM4> OCPP$F99L>4*s.Et P>l1uT328iTA8tKˡ&5nn]ZuUM\@^uD=} qXNH'.* wa !{7}29N:$ld<}V`KZ4o$毖UFR@WX%kU/.?XpG%#6,X,5(β2͘]'G'%aeE` ^1VXJy;װ5xbo.{8ŹG̅)* WL\[ .zvQV!m۶7ȕ+JhOGq2Ǡ Ägc?>kYf_Gm=}(3Wc8"(C Ϲc{t{|%*W7?BLuL1W6m$UTukYzJPݻ[਄ {Y,wuǒ4k~1X%̑“*p-Ba:d>G9杫khHx &!:4(> &n, ý~yip߃DxD'(s ;D((|E lAߕD J̥> >E@PE 3Kmڋ"(!*Fv_)I(^2A+"-,T*"("(>B%nP E@PE@P@1E (3UE@PE@P(PPI:tD\mL"@:uؤZ;վE@PE@Hb@:"NN@SP~WW}E@PE@PdD >VGKM~/-wDPE@P҆@1E daWMN)\'r3'\rV:Ǐ')S{J˖-Evm7ꫯ96m~Rn]e]m d.Ӟ |GwJѕW^i?3ϴ6/_|Qz!M6ލs V{ֻKP>_z%u]-7tlذ^Es9;'_-^xkN4h {+c{WrT{^ҤIu͘3gvmx<}Yԩ0dI~g?$;ߧL"Q,K|⺣("U(E@P"5-?Ԯ][>#o^o/2d5 䪠T\z-LT?!ݻwJ*'|ʋ3I~2?7,_<r7g}fT;uO2p= ;c 0$g`=tҢ7E@P"W;L+"K2)TiƆmֆ0o&}ٳgc A tQ>CAx'gkQUf+Vg9bP֭6,:X?Vh""ɗfnXQE@ X y睭M8 qN'䇜?6!>}z 3@P:uE9>;N. ɸnP#6ƍeQ &oUHȋxꩧlOPE X:"([-Ŀ rGˀd@5a?sM ^nlI0>ln$ wY8X汄1&&P RٳU|I5k=CɓmLʧWE@H*h()'p¶0 C8ꨣlUgyF.bA+Cl4k~u]rWm<: tUWÇD)φУ0^R\>8L *'ApYgwa"(AIЊ~F3w Qyw4nҼ*E҄*EMYoJ򣨸;??_6lXF~~W% ?sB9MJx@dxILɢ$N:2iϟo+"(@4A]C8'[ʁ;N{B=JٺJ 1oTaڛ<6I'Iڛҹ[Rp j#daATRJP5'XO"G.a{.}f,i] ^iShW6]@U(5Umg ȬUfOvVR|бNnM|\|хRhSN^{ݖ%lժ~-ӎ@. u("lIJ1΂4R|̠)>ٖK4.x|0|\-_'E*N^2_vXGv4 ` rK;%U`I6n$ `bv慅/k$9>r KSSOa"w^KW{_* ɕG[iu_,("JYZ,\F0wnV$)]ЂxeIׇSdEM_#רbddޢr^eu R>9^?~|oz &0H79zxda~JVa%$[| /YDXSN9EA uʙqoLZ|jr/*w("(@FD@%cժ!7_<'*F_zsDkmeB=ZgݘTd}TIygfjM|7zvҮU}[d6m?duqSČnHust+}\u1&/[*˶{_ZvdX'RafȆgػ%r~J*Xu˕3I!()pߣ2ϏS"("l+&=fĺZ֓z6T鎥_,tI+MRNY.G(O9R,Yc$B9in;4˜ZD\*}{6,q+y@3g.Ʉ5dup6cUEV6UyGv}r2E/U>~_P^oV 0 2aSbKFwa䃼 /8_Y=BNzo=+2)sW%9satq/ҙ~QE@PE`F +@ZUe*(hа?yIF(/ e,̕$fe٩u\B'YP,Z'|?[yyӳtm@f/^'6nKMM&D'sA|8Jn8iZymu|)WYcL@]e߶J%lV#-/s,5Iѓb贺 a,S)(#($Z% 3;w]V$]r Sg%r}/gq3J)=}=;'.(a%E@PE@P"gQp_Ԩ}fFO^*0:һ{KlG\;Z%>B~xp9]e}M%E/RE@PE`A aߐ5Kuk59Bj<@fpOD3vmN{X%>Zݗ 7IyV6`%_j1o/Zxu L3^U+7ށT4 D8/M*_+*]-MWI߮Gd<nҡ}ee|:aҧ)~_=O & *_ioB9@Qn6KmOn| j+wfksbBW&?ĜI<-]$G=:KeȘզ|hUYe,.4ނpJYS \p> k3 }ءr_JU&s{RjҢ/*"("P("DxNzQ*mO,Y9Zon%Em`%Tv8%nտL {E. lY,Ff,n?؅61T)ZRg׶ /uw<dкҤ roYlT[Df䯗k^Iy >bF+I/_!uI][HÆ FQX*wP;ҩ,ZD{_=iR̛;Gnv;d))"("#P"E ( ~6Rl/\RRz]֚UyQlCLlzhKڵk"{OoU cY/ĞCnss o+˓M4ۛ6'+{õa[nտ|0'[L\#k)Y 5b9[jW+wl/dc. sOCu>S7o^d؂[˿aÆE{DëvfW^S9C&/`㔁SO=U40ϝ" 0uTyYgyV("#P"E 5@^~'H(;1NH/BxOF52 2v"ih/\V CքT["#~#,.F1y{{iӦRc0 exIݧsi7FO#~G,G?@Xa%9/$S X&X.{-7 vi dт"T0 3~J9ʞ"(6@^h ~߸q,,PϢqȺs 5ߥM,7%rAZrCs&_'gӗ#$]\+ M{4 {իWs6[ -J%0C.th_W֯_qQҢx_Uyk2JgCN>|w{OZ%`?Luv| ;S2](]`AOQ2oi;Ez!_}U(ݺuў{ǭ Z߾}K.7ߡ#F$|^,]vp 2|XatGPE@!5yI^WΪ&嫶Ifs6eNƭ,Ǿyzί1J@fR`V9eTzvl$#'Η/~Y sMX+mujK54Zlpρd|Lk 5B= W]u +sʰa/7\  }coW^E>ꨣ_~#e]&]ti+֑PE@P<d\ ZeWk(Ij'ٳ=63CO{hH` Ѱ˕ɴy+7%DcwtY!ل4uP 760N:{[edʕj>q~]w(5"@YMPxSwfo? !9"wJ}v}m}++ytAqe]kx.(H^t_C!뮓c9Ʈq>yK?cwC=Tn{[o;w}),,pO6Ma(PRE@P!MzMtuʵ Gb5[FrM q|Rz9~RfҮU=oVl+o*9\1~gCٮH QaД)SᅲFa"A/3ރ &Pƍ۰LP>S !WVM=\{%م̞"~%z(F Zlp{<diԨPe*RIn},^2s-~mR/ / ԫW϶":Ey͚59͹;aa璍E@P6%RK !1X^yAeeJDד}~^yӹY9پ^52o|7j`ZիȪFٱE5ҶIMO$<~>VE,~~U"0 lj'h…xcP&&5x䒋/)ㄍv/7d/&Á^c?ɯ9s>&UF Ar%l"LE ]yG:v(oU<@+I(i|gJE:thHB ^B* H }ع"("'WZli]iN8Kq'꾧ڏkz.SV c"٣{5e)WL?d"k׬9'jT2l{}((N3;@D&ڷ+$ТLti:5@N n` E8}FZj%lv.EzBPE"P8묳x/J G'Q+dJJޗ=gE@P@BE ,h(֎k()"(eYP-寤("5X*gv 0`dY@("("UN>nLa*^t5 GU tފ"("(@YATn֍{IO(VAIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/repository_xml/images/repository_settings_300.png0000644000175000017500000002672712346515436030657 0ustar felixfelixPNG  IHDR,j l AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  7iTXtXML:com.adobe.xmp 72 72 5 1 2 3\ IDATxyeE~3ӳ03,3 LkHИh\ M$L~Jb\("Q(.hXqazަէOw޷0UNU}_=Um"rH*())I ӡԧ\}_r sS]*!=ɇyps'͖:_٤|Q!0T[f&鴌M h Ť"N9:в~H4 u84|奥%2:2,c.KK#ɹoX~hc?0(UR_|*4vtUc*):~8q Uq$]$qrJ \B@J17ROf3:q'F844$+V:uꔟ$eee9QFɪMinnI酦O0skZMd?"5 ryJeڑ#`M29oϑU+ɘ#Ҵc 7U<1M# 3% #('2::)u H)s~ȸ_]}ˇJ<`W[jʑmǹCvݜHX=%Kx(;=9s'UVI'1!KZ eSw˙a]ag?ukh] ^,*C4!VҵGpeѺiIc/6ἓȠ!,ZRroT\Ňtnxuu^4?O*sm,HJ~̣i\qdr<̻./1cv_ 3Ɉ3nĚPVipdu +Iz{QjR}Rچ+des))w7AʒQyಕdyi7z[e %Ke'GuZG>"]R߸L'd{464:O)%nV:%WT^Ums=-uR]c-<6LyM&)b|dBi?[өzT^lO:ԥu _Ζ|Tk ISܵNk}BݩVw=I Mqi5iQk< Z_5&t ֬QyC<]o=m+~>mf XukXA>Auea^1S밞kuQ 1vUV3Q6uJVowhUo/zGO9)2ڟdw DZ4֋{㖌ckQ/d3ěBci{L:Vu'G^(%MYXOTNPFi^Zuh^yIr*j]uZ됎rաOLɫ=\}H 9TK:鰌ʔ ֥`\6. :Hʄi׺jF@hYh9uT&l eQ\Gw0{h(tnՃ7ϤOI˻ɘ'w%_1Muhf #ܜS_䇺 4qv\ZTzk' X% ع|-4hYhyn(l:'P^IK.zUI+MRA;Qp:^d2kTNcsѯg/', q{"U2O n\}NLf.vtlO8uxJ?Aۙ!6GMNtġlfTNؗPeIxϑRUsK4 V;#ʦݦBk׳''.|coZu# C` G^w`G)2+zeSY"j՚C q9W:G +wbz$ς!`dG@p(ry A_d9vV2< rO3yK$h3O: A ul@kC`> _nj cOk$>lx^qN:S`1L`!G4559_}ccch;`\^XniC` 2L%;I N JJ vWW^arv (=opf3OzIY 2w޳~}ZuÎ*KyO?uB2wF//k>CT:ɓ'}LoiC` -@߽]`ozwhyMѣ&8avxz'7w׮]_σyyk^#<8|;t|HַzJrȧm q\HX ?sw+Y}_/}K%%ظ[l7CUW]6m$d ^rĽVAT@c̙?7sҀ Gyy7ݻw~?0 vVW +ȿo+<ٱ3-m۶yv9$ۢMuDV)#a!@ [nN7F@wH{L iI~noh8ˀ`K/%` $ظ"y^Š1d"Ѧ\\cƜN_|E?!Ynv-?t}-[̷A]tbh8 M4i r",Ee!#ݼ#bv}|w܁ |C\! OD oqR8SY5͗!ԡqeQ'iL՗OXYpfE\ҹN<ΐ3 AIРs}+(ZF[^rTFb ĕ ox?_z&]w)xYv%Dc}1Ґ~$OٗÛ$@Ґ8D\Ф?Rzu6))H 2px^7oѮ{y/nȸptD ,?w,Zt>0ϙ̕7M~hY8Zmn^9jv^{KtTB󉳅MlǔF A}D׿U><%!8z{=q}.!= Yfܰa' zL<oyH cgOA,|ro2]:z Aт}bS=B%.I[xZɒ'}BΝ;}!G}G7: uG'K&@nً7K17\Øte-q뮻媫wݎ_B3*Wz-k:̝ca;F%\"gԏ}c򖷼ş:s‚.2wt6ټcĹ7 ~ R#׶5Ƹ1|`9b|P0jH&ͣ[Κ@8zeʕ|XJB,. \DA<ۡ/x*,۸wφ' &>&5F_]N`B_,4?}A?G 4{xa"|`r#da/LDmy~u­vHۄ>#n9+ mRHF0LxK,1{(l?/?`?ؿo7 O,9`o}ŁQc!$5'DT@1xw(u0x@a,胔IS_=Ȁvȡ>g-?y|X&.BLՋc>o~DaEWX~ 8W̩܉չnv?/eru{]vQ\鹍]$ O@1IX.iX<_G,?|Y%, WpB|Wysm+_\!j"7z W2o$ uM:/bFބn| _{Y,nf!Gv߼ϵ?!S}f ^`/?_.G?O=a ʜt`)@h~C0rE /<3oh/&g'?^0w y>xY.O,!+yɶ_i>۸{e;/p_7/?+P/X<9,7f C`"auuwM{G78ϡH>O7y8|+|?Q: !`@^,8pw >ϒ ?æs5+<4(r2܂!`"aqϡQ3k%,ywdEZg0 ld%,HEq4|]bl!/s3Z }UNqz| !`@V8ٞ)N40 ){_[TƮ C"x g* //g\3C`q#Sِ#XN+ FV!26 $r",*W^U5=G g*IaV䌨Bd!A,Qn!`#Bi Ca^SnDh.C(*FXEה@!0*$0VQ5冀!PH 2 "`UTxM!`#Bi Ca^SnDh.C(*FXEה@!0*$0VQ5冀!PH 2 "`UTxM!`#Bi Ca^SnDh.C(*FXEה@!0*$0VQ5冀!PH 2 "`UTxM!`#Bi Ca^SnDh.C(*FXEה@!0*$0VQ5冀!PH 2 "`UTxM!`#Bi Ca^SnDh.C(*FXEה@!0*$0VQ5冀!PH 2 "."((VSiyCX%%`*Z C OJKK%}iRoA 𰌏gT8!`?"CV訷oh4aATT:r9qℑUkC`#9f͜&,9ijjK C`"y$yAXtWт!`,|pP¼!LHBa-Fc,h捇ܜA T1:j }`s!FX!^py 5isGF`!nяBrRkL&hΜ9#cx$#O92HBc ۟9Lj(p32G^m_z,qz)p^ . V͛7ǖK,iňetkk'+V|oٲeR]]-kֳ*\0NO"̆ %XoG}Y6/,6nBaL|قV6|A#w{D ڷos=կ~{&m۶yoӚ5k! !k@7^JZG ?ry{|{O?\{~ Oʍ7=1mX㨂%2}E^:yOfKK;vL֯_/AزeٳGV^}] 6xUf`LJv8nz< i e| Zr)F5Ԁ:S* >A@~X:~rK%.H"1/a}AĘIKx#1a$IR)1cay!!(^טK=\P2EGjNonu^i,2Š"b׋Lj3XJ?B܋Y0 @š-< EV0 "#0^TgEn!pU%UU2O,ꆀ!P&8dts}ˣ;IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/repository_xml/images/repository_add_300.png0000644000175000017500000007217612346515436027546 0ustar felixfelixPNG  IHDR,$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+ pHYs  7iTXtXML:com.adobe.xmp 72 72 5 1 2 3\@IDATx Wőkf~3} ȩry}hl4k$&1$nkQD.Eaa_M =?~303z~RI )))k.͕N:IZZZ 0 (tmݺUpg}&٨E*-- ,,??_֮]+={Bs#ŷfOK. z怷ag6mșgiIFr VSҼB[n-ZZSu]:t / gffʗ6_~ScUpC'UCGpFS#Νkaǹ=>u8 kfu]/#X_$Fe w0q!x9LUs8O>zW \}YkH`ue{?TԄ*{C!߿7˖-[dرrq&#AUܬ{\$yyNUIO_ajLNp\,ol_0ezgLxlRV\)uΜ9;T!¶o.?wlܸ^n۶M.]*#el:t!ҩ8Qv[#tpUȝlw^iҤI!={yer:B?NuR}U "xӦM|r~f (guViܸ g5w6 +zLVV|ͶJJ d̘1mqU1c ;SR]B#+&Mg9외'X;wL?Ѵ\M'{6=E۷O.rѣFO0!i?)! :|Z@8 @PCGKZzH9,p 2ydAp2 nn Due#8nF8yO*JO؟D]tѴ+4mǎ[8M{Æ f(?яl T)&Bwy׾5SOɬY,eʔ)Fle1p7|Q\yCU~_=𪫮 /;C,Yb ΍{- ߴiS({ANEy'9&,MK/+x]w4]y ϶Q80ӟdBe}Q_j5:w^8!dXY"O.+qaB"d bee*t8oܤYn ZVpt(q{ϋ0g*>xi=-Nzq4WXaZMvQNfꃺBL{}md>S'|Ofկ~UhLHCnF袋XI$ЫW/#\pAŔ>fL~r@oE;|~m{{oI$0FEb|Mźtb }2h 24ߦSmk6%# =I?7LlRzd"5`pz!c08 SU.p$!a>qQI2|!dkT9`!ԟx/ G19s!BƧ`x)|$-Z0,f0Ǵ G{G"tʀ@~8w\ҠMm<2^'h.ʳj\6L;1V4);v4, IbZjE64Q+W7MhhsAi=+qa ;x>}Xݻ+Fkq!swgi<{WE~@4mzhc5 ,kxC)uE_^viӦلZ [L>FGLQiV2+;,[3MxfA025xah|[9٧p%֑P۶mk)i޽mt)`))'gB3t i 9 dQ>: aN" s8BS%WU9N+VF8{xyE'y:O yxL3Y$x.<,L.BByOqqtr3:5+rјXff߿ȉ~m"+yL㍉L*;4F]*2cf,SY~)#? f (h)Z64G=C4C3w"\#/{|ChA/+YS^5G>;%\_M~& :y^|~2v0`5)_m<_xc`rqp{X觨VR@YBcF_` @'GKǧ#/^l@ރtc\$?<\Gfpфqr9>uD@YQZJ58lR+[i^:ʌkiR)ܻM6*:Ic?e:H()Zt YZE˅Y"Ah:]q~U ^@zM ahewqک@L+'h7tG^Pާ '$yGЪ"d*=dvKq $tK<;Og8OIaqxE65O'ӐxGA!'m~†t03 񞇇Q*= wwY4c{314E ~zs7/ M„WRZP&k>Z'L q#RseՂ2K+wC}2eI-2oIqg.j̍rJV3bCf}e曳ewr~4];TI,;]>-:NNQV}E3O&]ƤP+˻d2]|4&cO9QZTQg[7xUȥʚ9efA&ʆl~\\x "JMS ˬHYÚ023EWfv2=e%4\*cfgd@qa4x~eMOqgYN7u8U& (D; Ӷ ^k?yB#<}<8xy2;=.Y8a\!c BOL /ҳG-S(,G?|(ļ5C?5ا/T UC+vyLNTZ9Zh_aXUD- p沫Vx8 v;K;Ca]4sbIx\z <6;顦!`f\nꝆ3ٳU>3MKwɒIƷ0|̈  B 5,40gmq~xZdyeٕPYj&e)4@.j+ N/hT<$h>|l{HPZS/v#@0ġ}8ߔI9D2#SF4$܉@csvz4RAp篣v wJRuN'[ms泵M5:u*NI'uZ[DW,]5 miieo߶[RUP-5#C\[&*T3x8YGմ|0MiwvbG)ٲKq6&d-n!L7OvIzS,%%=SW׹)WXN]d=RRڵi-UȖJ-W_QִyiRcwHNni\g+iTd\Il&m^,U.ŅuzSP&M I͔&m@Atmer2Q\%Y~V2swowd~vY#[T 9{TM}d+̦9j.xt,ЩҝK}4nT9e˦;uԲobMdȤ RD O| seJwҬes)QĆxF_;ř8Jv[tR$?wkYVjFCm#ْ["Mt8`Tjd< mvm!?0^!tcpsAY$s A?eo'sŊ(SZJQEk,[;ʦ|[i#Ua-Ut|CB,2ħ!4"< ùw!ȐHD?g[>g.OoǙCx =PhbOEhW&~y{䣹˥q'I2u ؾ-$5,_4K^}c4BvY'Ck۾Nf,NVrK~jwr7Ri-zɣ˖g /}" 9g:Sޔ4Je CJ.j 5iv' CxZ&69 :JTpeR3[g)H52o|GL2I~f_9s7,~K[+)tk%?Mʥ2cL^&ŹEwrҨ,WV/Ң4+#vpX%hGEJ?4zXN  efٱJޜ>K֫M(7_:?UΙ4DȒɢ}MI>;d_iKԞک*M7dK py;Jd rҨHf&A D2:)tjG< >Kt-_)yZo8UJ9SN2iXtD1Z"o9_efW txUIS5pOZ|40taqX  ~\-K5,[o=&+7J٦2mGkr.iٽq6LH[r;Gz6˖w_{En-#WK~yl` 9_o6m(6r$gutm^ kW$ggV K4f+/JRWbB95to8L5S:t!Ε;u] '^O:udk1:m-Pm)&벾re'ɞ%Sߒ{K=*Ȕ_F]&G]-/N{`>襶 cʷs2c]t+#WinYThw7'g#O%,'n*Tɩϖ:ʂO[NJ̔7!c/\Fi&"ϼ1UZv>NEH3)SN.%9:h),WT٫C)C =fʄ3NEZR".\tKs^^{Cw!ǣfMe#伳'KV y? `{2$5-l,ד-N&L-R޶NpiCabÆ1_O$Mtpб!Ă'}@Pq^?A hP7`5;y6 36Z3h6UtR؅m=GRn=M%U{xA;%΅ .l4F"( 9mhx/NT+-](yycZYidvPcd t&eHFͤSһB]cnshڡr~|:%+l\Z(PsK;:(V@fNKfS-[+]vINӞ2&_Q4SﴺNS͟-,ѪP:!sWͭY1rP]hB󘞼m[jͥѶUxr/#)MT (cpY].AJ[Ϯ]tN^fn({sUhYOFkT-OT5'k!UC\YdX-#/8_tn,{}&l[oHjV-̑=`/5NzHfFe:Ζye}i7'KgHz; -WW$Da~qfniܬ}ɲ ;IWIY\6oϖ2]`(Q(Eb^)(%ŦfX;_ܾ_qFV[3M>. L9I6.-,ڬVSòr\֬-["m -uZSaTA)'g{gcY{9w9W/ճOo8&yZOZEIQFlZ<ٲ%?]w6CXHz:_.,i'Eu#o-{mңH3世UcPE#;B^׼C&WJKWauWMdeN;4ոꉩ]t Iw% ]Z꠬ԌZ/TaXFF:j{J b5cHb/]W erwyWdm6;T4hz5"scpwP[Sb-%] T\#yJOjz]澿Z:9N:%.7oW>|vO8 ~}0O?1&,73!Esxq\S׃THR['>w8N4L/3B / \<݂94xpN{5eKa[w9rƤ2qҙjW:MN[*iMUHT>\^m(ϓOsu P|jz#6e[toe2@G͗j{j_2s^|8]5('W& U{YIO&TԤS/G,Wlh){26:X[v}w.[ٵcqudĈ2J_QȀ҈Y*mW *?G6|i}t)[7neҫ]S))P{ݲa6igڮFK-Z;Y'iDJt|ܛ!Y,y-ҶQSiԬJe -nhNUm+y)gM9qY3If)HIj$MɨqHͥcHW_GwSTbo/Z(M٪`?!E;r:5]kV[],M͛Jz,yG>gjg:E[x-*ꥨɡQ-MeI?ey~dϓ=ʘ>U{˲iYK!ٖ-Ly鰩F|)mIvˤ̑ɤad?Ե^">Nt-gy]Ҩx2vPis'{{_K2hD_) $cfi?4޲p+NKiLZ*˦g3&K'*߳2{sI]H8 .U DWPhlH={-{ SKiSWu:@y-rorBޓwx% #PU:`p~]hB[ iMK }.C6k[T SZAvѩWdnjZ)jjN-kB^˧BD9iқ\ͻ4CFT/;H^>oD? #5O}EfLVQ4jZZ5aN"j{wRkRZhbm=\ؚжPZ65'Oh4UTޕS>}CqlY mPݰ>]O̓'%:_+m/Cc&rٖƺTކ1PAnU&ڋڴR2uνURqGX!TЊx/@?+.xxxi ):v}a'4yƁG8i 5`o)a|S!c tTT֮K71LoF4aӬtҍBD DyUlCI73U4t)+/SuPQ"UARhm aֹJUb_QQ~@J "x5l1JbVٶVT aѲ}YZ6Xq\JOo6/ms" mqt5F L`:hce :VFXkң*XtРmwUj"źuBW+O-P>P{_]SͳPmiJ6oQZ#i+D;^f(y+Ҫ y-TSn۩ Ub(Zݻ֤Vn|eIjWzoމzכ`Vp_ Cap<0yž:U(mph]| ]XbiVJGz[NչR9CJ66{$6z\j%(eU6Fq/Fc2id0\$ B3{`]: #;ßBIVQ'"X!iS(rWWI}= _q/!Tk#VR '#8|"'gʣUMh@;)@gvi?xq|>_m^tUЪwx=P:-y6_N|9 G`aB` | Mp2gikܪcڶ/䋑FR}>V2tk98 HȶJF J5%shPU831#?3!Lxd, ƽ(OK,[sUaءq(Њxং^*ѩU©rZU€c.ʥ?.\rw/Xp2 [$UOāu_=mذV JGnӰ.-+TB}ā|b%Fylg΢N0m+PG8P_H׾&Ç7.Ԟ ѯSΝ"@Ђie )_uYUx"\q.9~`FvPHwB6n/|+MkM=ϐ0txDzNf I^N7ivxq!pC 6+8PW߿wUZ#XS>|RnͰ;2x O"CwV{/_}kk22:~ëᔑrsqˆs^9_C xM~+9OGZ:ҰaÄަpСC+ljlXd}5?HF>$x]bZ‡c3|A9l|#"M\ .9OWXeG0D;y/}]{aРAC+V{gñm<{1ե^j" Cwp@twޙi??_^Əo#wvOs>Ϟ=dO阯_Hf}_/_R~omQ9C>xħtH$<<\8AaI'E(!k]'ImtW^yW_?^uU/@>.qˇ@Cf͚ede%ַzr-*~vѴi_6)U78PWybjVMq# t.j]lk#:3BZ^pvp ru{3fu>;?tbV<]qr[^hJGӑy!'O=~&իW `>p DkD+/B˅>"}d@.okSq4 3HN !x˛/k,\OItEPN1ܴiQ+g3AգG7a)7+V81MC!86ZDgZw}@LI`_}OXE%O1:@C3FϜ9>Тh+98hOhXS7:Go6hr<0" |.1/#)l>HCx]HXt*B2H dڇnK?pZxgƀbEG{;4A'Es_jZ wam"8q>feeU b~wІ¡U".,*mH<^ʈ'5H0L:>`4Q&6˔ǁ|C1r 7hM!NIq8W ΌBc2}m$:Ǔ^8tbrԊ BާD9n|˽kd #-2 VYE)C9^kMV.wNUhsm \q:I=:+îJz &0x"M !:2Un"*4Zwh\x΄A`E3`#Bb57M4 mF@:6aZh|uFʵ+O@`8΅#.;F3&AŴ<1cG(=Zƍgxf ~ q8|-/ >` ZBx~:^xWȤIs5jF70>霧zmY@736ڵ]xfagNb_if:%,2ˊ!{!tC}q4m‘i 1x~;t!dVFhAt'xŒeEؒ4uY&0H%o"{8lEש~ ¡"pOhCOH2!PO9Ѵy'@-q#s`itZ1  #|j!Sá<0R[-aw;؇|t(@G":(+]h 'NmLģ!Рxttf¢El L`p}1BBς s'`Iy=q!ûLϘґ plc@Gеzj\7p9YT@B~ylN%//-IDATЀ cxV=E+rth?31 (81U)#32ѸR`y()qr01#-uG0)IkOGZ:/QVCf~# u:0' x^G;n3%{,8'vp{=q~w/<>ё7>MIFh7#X1$i8^{jgCVDg!úv)tl ǴdzCfy߄DI qx<p!l4#d"Tn6, FDaHW&&1ִ<|āc7Dz+ ),)Q5`R#"|.9Bjjq>8PARaXCeZ}4(G T`q%vEG8V9p4V&,*tY! KFl}q@p\}? v(gra)b^ zl?PIIOځx|m2?r"=eDӂ ʽ?'8Sl#.<>/#@āeD89sU.ט^~|`^R?9Xc_%a؞Wcҟ%㻺dV8@]Afl|n:̟'S _Lc1&ʗ0pI&/8)c65$3.ʑ]WyDx#DuЮU(k7#9SBϓ'OSbu]'7o6T} ?>S|\ū9{YuYuAk3ٸ.ol8|89á8Nja \,/ *n9"4/b# V|?^j b뒉uHz:}7׉)~! cO!H|ϮU&hUC">~]wU| $}]8h ]]1/#8p,sϵd_#G`x+>\x;`١Q!PS[G1|!QLsbt믷X,?o߾B "o]8E8P@YU7n=ڲLa!{^\X7xc~E]dYYYrw?nqB ".>v L|J6GfE߶m[ 똠x|#Q`zkq~ $" .Ȁ0*kW,gbC\āK.6m!-.D`!oЪ\s8 ~<0`@YGEFs.xwxx~o˥ܻ =|Y_yFD8p@E샡\rl).${v߁?yg9"4X 4":"D8XdGsZ((@ācXX"q @ā ͡%M$sYV"q @ā@b+Oz)yuǞ ^Aʢ"аB?6a(d?86yyxb9@āXhNNj@T^rʔ)SUU8q*%4;窫2j޽r= җ^z,]To.3f̰ö"|U#DM&ѡCڋdcWӨ:,Yx\~ҡC{}'cfD"DH3\ql̵^+w7ިxԃ>(<|ߕ]QTя~lXXE8P0ꫯ͛g >@T%v-C86!-$\p^$i7Բ +{f'"\<v0mC-dC >1b0rpEjzc;#?oUa+~ቅs1fڍJxXW.N& _ y'o@=;x|W̞ WCG:QHmq;!BjŊa 49=n+baMocsfHJE-afj=5VB]XQ|Ӟr)5H_>{T]3 d =[sZn]ux eޓիWo^6vzPUӑŧ™ r9m5=hLtMX Tx &ӦM3EC{u3v +o˞Ouqt#M߳gOPYC%,/YvPEd!h0Py2 aUIX)_qtus4]" 5̈́IyxGt;suchV ǑГHSiZϛ>K{C5YT,q}֬Y7OF{ù= IxĴUm9pҁo429餓l?]b݄`q*ܹsޔ@;ra^-pJj*3gi{}W2I(bZܡf<3rRy) }ɘPT.EO#:gʕrw -W^iFH`A06HƑ;CVX X&>: ~Li_A-o!wכaE]%SN5x*y}N5Iʯ&%V,Ex$<1hf?oLfjY /W`:Ζ5 ^6,M{VܨSE )aIJj5hX8 =pjqNW(i#wM~sΑvfð=dĿ/ШL^um_=g\NjB7C5tgR}*4zк[dĈP ՜;~iym]t`nCghUCAp8h<0ՠ\8Yg"2e<63}Ewۿ/ht.҇~hZ!Ҍ9һ3bjoCYOdIz{x3fLal套^2Q6ꎺtgo솤?s%n*Lh@wt3gԭj/>y64nNͧa |Urxa!-ZdL|]:Nw.Ơ3qDcB;tkW  /o&ËdP/iƋ6^>)0^F*8A"_;lS,N8a@@u=s6v&ѣu]D} :o4,q/ͩ} = sa:4/;8*p5,:7䝻vԏBgXAXQOÇ7Y,[)  .wyǶ{b9cC@^du,=왢ɳ8m\N =hN;Sq{C 3 ^sn8x:σa>j30Mk`VY J!14 .H$ G]D#b9:7/pcRt{#9hꊩGhN:/vC5 :4`Z#20^t+ PF^5K`/x΂e]Vq fp?QgƱNLmfHۈ1?!;X0gPXT8 aa`JC(+ #84(OZ]u "xLz@=4 |vo]BC XdeN ?/r)0M'xol^e@0`J֮]+k:RO|G(34_ 픥>J]uM`QN^2ַe }4xzt:eL"h8͈mtmj.9nXb@ѬtfEnfӶiq Z9`$&_:&00H_U';6w|774`”xyp 斪~FF#DױcD4TVlM55Ũ\p{4ʪ+|h 4L63mEbQbA+-gax_cdtN88X Nl|I |.l =`uA@PvLN>Z/ UcP<2qR|1~Ƃi[׆kM'3ЎkMG@mx&/~y9St-KF#xE,_ܘU(Bw:+jOXu;+8{.y0޼1G8j8H^: qṀA3 m!dTIOeAmt(GylEcp$t*x;vt4];C:aK]D_x9s58J%4ć |Q8?3S/:"FR8?uC;p: xBcO7}`-Z,+l" AEbc;o+jz@eBb79$n?M-NV'E5+6. ε0SO' 8q @mr B1X psŒWrXɉVmVI+@ā8P]oَ y[$BE"Rٟ¡mƞD ufo?8"W Rhb>4['r{,hPW ,˻Va>Qqȁ؟'BmAa,g~qD8q9à>B/p&waB殉%∞#D8P{2mNHѮ_6a2);8j_ā)*l*^ģOXLMs$,Xٛ#%v/Kf鋽h\ΑG~ā^Yi%".$.!Dr>,p9VXTh[xF(!DMZъ\ājd]x"D.\1>?TC ,LG"D(@{JwH ]`{E~āB,9‡ذda& #cpI:t`dp!CaC8=0<:! >1HõFOu,>y]̓;`KؐW0o!qma \o๪* , 1TT=҇pS^usd;3ߞ|I92-B >::B+_}2R4j9OCh~<)%^G-zrÆ r'lz6&B:7n5QuΜ94i EX>J&_oo2+D`юyhY* ) ׋.8( ژbכD?G ; ڝ _#$FQF(J8 B>CZp'3pv5hֱB!Ec"(NސGS_bhJ4RqOc-O~Ӆ`jPO #D?p/ktt\G&КPhB!YxYP CGb*F }ʔ)f!-0W^yM|!oݴ5E׾5pwq'ZliiI7*+ /`<^z6 !|K]p&SkR-: $C/"p~6 l M"Z>)1҈1Sl)8!HcuGg}l), f7LSA @GtfpjX#>AZ 3hr!Ih JC"Ш!xHC|qpVA{A~d:>xK/0{CCy2H Tp|p\G8ħNS.v=푋g>JF] 4 ʹ 4b!h11ĀH˔ 5|NniPt(Z7DB.4<hzl3b1B7{ƮM!,32O9S耡'AGh!:xg$qSFda!):GMœ{Ǔ;'|ux _B<2qDӢCӂ.HO\ OCLAi0# ~🋺uSW\܇F\D{5M\~14idNCa$Q1ڗzNE_Q\hF<5TBBёCGEΣ s9@QUrlfrvp  B[̆ `g)~ <Ԗ]U.]n?96fcv6ϬVw;՚u_Y>7 .IɅ3ƀqpWv@ZSf'y`gf&oՏk뵴|#;芳 D<z~$d]§!6ն,%1RN dP  ?~lk>M~8G8F3öfAqY a- 9&777scnťL"(ZBs|O:Ly*> HRNx˧-\SΥo_";NO6ye)v|Ǒ}{[剟QU|dŁ0,#1V#|Td́Q^S +0kCgur'E#=o,pbyN~ܾ:)Q$W*DK?o }e@l<62nםVX`5B}I8+3" DÁK9|g~|IǦO㓾,p#?++|zEii0>LCpm.m"тKC Pݗ} 8FޅuTF)* 0m(\`OK}ٟQYMѺCOz:yc<7ۖ>Nh슯)kqeybً%'$HWj}VH5߷Snp>Nc{wS l !愉Imϒ.П뙳 ۷m}Meۀ$zئc|_:4â 5 2 1 m @IDATxEM.I $L(! &*E" (MD">JEE@ET@zo{&-R(Aғy;7'><-M8'yΜ9333gf&MTYT*pDRqjcPN敝vDzUOiT䗛O\JJy;_uUէ^XLaM'.jxѯ^S/GsZ&Շ0|R5RގW]Uj#9-CrS>K^)oGW뜖I!L~k?~|SNe%,`J[ ͜93%M/+[Džt->MşƯxx!m^i>WVWrǟ^KP9ţ!>n+x+uu/I?,+>~ghU HbֵxqW\nZnd)\H<~M6#aP} M}S-}w*V0Wt->OWW<6_NkKJ+uӺO%KyB2>'ݻRK-eK/-b1Lpi=X>}4Qx*}'sy$0x/2\|y$Eď )JӴyz)߬,_<$R}^l9_?MrVD'#Eiď )JӴyz)߬,_<3~۳y+N_?MrVDz><]F$?MWRߟu2iSڳm_vʵd/˟S+"=Y.?M#~\HWaܸqܱͩcڰalQٳg Q^dElVqDKe["OeI入Yf]2^aLyʧ'iUX6«<+]J4?ԒN|1-2qkj;l#ߔO7݆/Ri5UlIa4 )ǟ&yyqyas/7(tP4i+$UIa4 yya&JZkG# FzӥKc_2ՠGU6Og-eyi9GWz O㐡^pE S,.Y^Oӊ'u%GaJGꖍ:On6MdV[3ֺ$o6ǜ>Q(WqM\Z {hj+i<~HW(նćJJtiyr"Uxʋ?Ǹ=ztzW]ڌ3lʔ)0,xycƌ)7 QXqoԨQ冤F%9iYk*5?&yt#MM"꒏S~ʊ4m_pK&SڬxϏrV*䈟k(2N\#S<)#[M!J&!IaSwSx*tJ+mi\^\C s3/6b /acCA8nΝ7^y <\S<+X̜C}5ǟgm{>곳E |BU֞U,||b9y, /OpkJϬdU5JV)^u9m@z/ aqVɟ&=)cV#Ps RPW7^yʃ EJe#^yA!kNˁ_airJ(SKe'<+^>hJ'92 KZ㇈Sʁ+Ky%/ˣk\!GpOxZ/ xDJK|*xO+ >Vp%[r|)䥲 L |ʃ8fdTUp%>}|gh;SJC[n=;tR?Ri=[~߰pCv]ےjF47moc}}!{;p6Ηz;o &C=hW7ַu0&6fθ v؀gF7o-ҳM%-R_ܬ5}m͗ iSxM۳R6a6䅧lۊy SN¬Jx _5ak\g+ziC<'P>i5qUn3Ho[ħ4|k?$/_?`f^:qMa8Ҧu4-GZ$ʒ\#{˟Z@~+kS` G^|*KӦHY>++Niq8U&!GSX*&WJk\RAJ|C*Na\+,CyqTFr+$;0CZaK~ygZcN6śO/Dt a}5<Aa׹>pYhVX{I64 ݵl"y}8mTmX.qj Tn*Q8*k|/l׊SzJ儗8(Nc? S>/0 #̒ε²J6]ҺNfPWa^[xSa<2}kS e5iM Rm֫Wk eb+٠3'߶q/}aKn-93!@'xބ ~~js=I9wW|^$.;K,_,\x!C(w"x! 5 \~C?BW<)O?,ȖLPZv; &RzK-^p]+^.D|\ūN(, J?n^:!KzpɐL\~iģ|tvkœȁ$pa0O~| 7$? W!mRXN/N֭k7s`{?®{I󹞶&ٌ\Fp۴o4zS$‡ (a`u^454ZS\G5lmvc[}m>S{GweN?77Js܀ih0sUkޤBQYi`!fxwKC0#$:~u 1jk\ܶ]ه9MUoƙK4-T;xTAkF]vHdH&.}W|WptYQ'W޿aP-(?qM`cuSwv{ᑗboo-LGdvRV_f3_6kÞ{!AbA{F5԰ ԏ_g=̖~ o`1ݭCjov4n!*_]FP) ̜WlcmuuāOrYX8wuQ_zθ~^e 6/}u}ş[!l?)va)n#GsC|"?h3~xX=l%eY&4[)@YFc@yfeY,ƆR\zOrR56%t~,>R"SqW>l˒ʂ+2u^(^iUS^?q_ă#nJ*gel4*#'NCYږ?Yz W\ҒFq?q_w\M/q'PzgI"!#_WҪ\~\aĈ2FaFn<ǂ]q'x|L)r:S\R%t Sp/qS0U6\TT6eLŇ : ,Ҥq*%?$Y$\yeNQAßi$3?&Ldyċ/O2kMS*_\_qS~!'%#CqNi:*%4i~#?.ʃkIVG2 W^ixxyiL ?YK|Sl>}{^Mqn!EPuϚ wƬ664Mo?]0[[ɚ9-ݯa[y(|r'a5&\?o/ \!}%4L /\ʦ_H+ JK^6m*WE+)_8% 7cf Vޑ?F5E}m07{*guG*kzRN*<18m7:MY?kfB;U\кI7a?A|ʏ_׊|\ʒ%%[qȀH&ג%9*'<ů+ aiNaJr(LʏH7S q"%[aȀW=-N>ŋ_i W aJv0]㊇8aKy<)̸b^LxW܎w &F{;MPO?pu_b? 'Ͽ?jS%ݩx+mGz)D)܎^]S7U= Op~o5j\ J'\ 1{C S<7_Zyf,y2SxStDVJp'7%<O=ă7aP<8#,l4&_!/ڀn#8*38#8 _~cG|GֳgϸV,b+?M<ٖXbGpF¿0 # 0~xO/YjO>/*8#8-Go+-S:@;!, h'N,=&L`+u޽MrD qGp%\2WdKsc+Gw0r%>l_;#8_ZtK<@{Q܂SC/#8#2:⊶KDžonOjYmk_~m$8ԩS+(b"pGp^j.;餓c?pASO7͘V[me\s|+g8#8#,MznM6[+޳A{ڝwn&u]wg;q]ewq1@^?8 {gOV[ͦOUGY`cYql7:89#8#8_ kvZ:G۞{iC;f? /Pgoֿ{βC=^z饸 '`s3&da>=~=cq_JHKYN9;ꨣ좋.68h@0_ѣuGL2ņg- 뮸}iKĨQ_6p*ٍ"4ƌ0L Cd?{ Okq)g^ƱP^+_j|Em@5<~aG *r+uU'|2g#[WL6-uGDH#-E*t5[y*3%(/;8E;h#G,swjr=s0%}7iSO.)?~ĺt'|A6™gF:5uҥ]dvBvY-<Eҽ/z6ҶW  ~ 8 EÂs=g&G)G }Zew=haƋY3E#^|/~ GX>x-le=x`ڲFEF17@g2AAdGQBbeꫯ6l4 }(1NG矏q T+|Pyף0|q+gL$P>S\x3p-k0:.p*OZW:l ?iҤXve\b>WX?.ltq <ʹC (du%PҲ[ 2cYP QfVp PriSjS0ؑspz̻=j;iR2h+Ʈ FPY /}mF0C '|$]uv(/uj4`(CΝ޼$yEh}<%.qTq'Gp`з$c?x",{ 7c`' `FOiP`PxgI\12ePޕysr:Qr2XS\(]J/|xwщIu[|`|+RbӺ,׳g8U^)OOB9n햲TW_I ʻW̹/;v?_{B1Caj m3-n|);3Yb[."&W?ʕw[l| JH~Ghd̔((JtJau<0A>^2:# G1 B.k *#.Mǵhĉ>/0uB0W}(0ǔPD1IDØ) |txؠ@*+R^q FËw8jrҠe)OֿfDt0(7.6))Z432E{W4Zp?̐HWxX&ģͫD/ B¯GKJ<3 U-y6Tۑ@~s ,z1BUSY.lzYB$,x1Ӝ6|~8A`"hR(apGFFbQ*N F] <3Qkz+?v[l,hmgERHj_x9#Йap-"\C1ka\ԒjbTm@=yy#6h<:#vHE 0w~P_}k s(B"t<p瓠3Bk]ӈ.F#<_;_PpAs^nGXhf$ٸ2xގ@ld׎@T9^S>sFaafeauV 8#8#8 >_cvYĺNa+~f{OX7]N 'Nd ;:}UK̩6nQD.]"Jy ҍ(*9#8#,Dڴ&4eڬt]:: )0vĘF͘iYXSv`kZ ["ڎ=OHg4JCA@a@q hJt8GQg _e~'vq-0SO=e>?,!_6#8 6 ۦ={tǽ:qÏ1̒=365̜XWkKF9#x㍨lzYp=#*qtUBGt bzkT G׾G{1kll@~7=𨣎:4BԏS-IE8@ M(EDنSk#F99YѕW^ixȫ%G0GpGp@'OnTbܩn?ad|Zk ?l_SPNO5{78*/{WSOJ(GYwqԞ9%Q*c"k; (5!'0q3ҍ#<bFf%#뵔9>|ox<誫2nFsKp(© OL:Et>R#BO?M8#8#!Ȩ~+@~?c վTb`_+a"ҥKs -Ң[0 N!%=KӠ2bꫯFS,O ~x9gsBZʙ*ɘ)a*"Zjv,F(^+ѹIP]vן/v<Cp\?#8#8‰@0r9w0>QnsBh_!VtIL{VXa$r6&/oxFQ_{hڳ;R"?f?}Utt]wݨ83&*䥑z),e91'Fѩ:jE6dXcrRvb=EÆ k|2dqGpG`CӤi3~0?l,{`I=S &?MkCm 6,TE)GYeH^Yx{DQFş{PnH2b/8sm1 l!zf)ZNl<\qPr-̀r` 91j3vZ~GH55 v-i/YLy ;=CQ0Ժ[W۔._|kE0l6(mm"!oos!dvFJ0#䂋ͯV&$ "&&Cc۶(˓}U#pN&Woi<3'Ga1S L/&m9Ckjn!z; ?xQPA=Ǧ K;Bl|%D>s޿2;}饗Mb 1#m/WmruYgA-{CC[#uG`Bwg?Ɣ:e mY>auweAne ٠uHXIfzx"YfLN~G@F֏qh#)lOm= a^VGpKF!6@dpf @k~PEtfxGL0CǏCYLF/)<_Oٳg\$L| nb'q )cH"p9 L}'Z&Lvyx9quU wޙ|!fPG@Ow_S:WTQtHO'LǬ"OH@6pøss1 Z7dݘVwkX('w}׎?xOf@ :XPffhi[ˠkCP:@N'Gp+aq})(ܥ2[zKAq*Jaaz?a)U vaK),ޯ\Ag' P.ԩSǨKaFKF2Hf),/ 1>Q"p:s#orE`X i)Uח_~y) @ŰN8\v1.Q g;Uq{w|sörR*x 8 x atiRVLIcXZTJ"݃`Z |QV'-CPfe 7)+Rʻ1Y&ݒ75k Wf,i 33Na#(W0ax1>vIwߚ(=B@k|p@k_fmΨtXV02yy)qla?xZʌyABe\NJtM7k7O(ǰ@ XT '^|(?af Ja{(KIԏӐ2Z¡,|G u.c%:g~A-E2݃N+bx.GDŽ|6ϱF*&(s9'^ax]̢z ?I뮫,i ܔPܑv+*ѯ&•m0AԮةUS? Hey#8$l L]ACھދ ]d"y1)"ޥՈ9Ңɛo9w57BؘsJ8 1J7=C5DCAkqPd瀑3] AtB.#R`R{]g ;StIM=eIYKݍ7̈́c=FpLLf?L <8hSJ~-ф}BvzlpgqXL[IAcCp(/;JW_- F=yJN /GV~e;iY%fP&Tc5p`)*K-u}&=PE֬fNe#uo%2"_ɯtPi?y\S"0lIYT>8z(o?.Km%3ILx65 z뭱 }k|X{Qn[`b<7Ͽa,f4T1+9_ePQy2:Ï~51f MMϫ26ӔG}t|ٶ YYa1ayJ'zx+WKx xUʯ7-S-8"S݌=FəZ΋y?|1ZS,@1 ;?TN=[1"j8ڤ-U5̒ s<ԗ{ɢ0(w!s&J3:S0{.++mfq.qGQ-c ʛ$ eR0}քF`-8-Q0sJIA`C^KWQ=@hyW+C^|[Ȭvh?1~2EYRyeSL[@g #SPq#:YyERe7ذ;mN)?OMpE"Pe\yUWη8F1KS)J6#F=>`fP><(-QIiE><"eƁ<*Q-uVE2j;BRJfGWIo ЀcV']{`\<,LGzzc쩗s }fw?0[iLEayWQQj8?*'L^tE1 ?xQ@-jPVi"|\z8m˴' R&:N:آCD":&7[|xȲE%u-m+SVʯV1kv#7X\,º6.j vcg3MdZb"qO=T]uPn`k1YFy(%avdbFق3Ϝ ـZʄYe3^U$Nd'E [6]9/ q(L5ç.bz? |'If0SaiX@Y ʕRQ]¯]pCErT+ 3P:]2YKJ/ʯ%=]5:a`!Rk[i|(zΓߞac=olGpGVZdڵKa(Ȕ[o4)>|467%~1[o}Žb4{1~=jeBYKSlۂ*)t*E'_Z1I˙WjZʟu1'RQYO2jm-ʯ^SwGp6WQb0?0ACR**y&t:?ƣIZ^ Mi!PTOlGpGh5hեr#8#8#&&0GpGpGc" Ǽ/^*GpGpGMh~b}u cGvr-ۤ2.pGpGpD]~DE-]zpwGp5q0El{{o]R~Gf8#F]LzPQQ쏏x87ޘ׿OK5eʪ"Wo-yWag}|[qyi#UtW-hg4VX\rx4q//?Sȑ#cqt ^`o#8@D]~]Sc99C I_wߝE;}@֔!+boԓ_=V bki-M|Z0ͦ'uKIڣO:kIy~>|mV_}uӞ7x'oV8y?qe8#@]4n3 =yd2eJG~ڴi]wm6xV]zꩧHšg{a^r>lVv5״O>9 \p 7~_ǔw=?)vF/²y>ggw7|㦛njH0s1]SIJQGE8?iM0Ae7OѣG?<5Vt^8|W=zGy,G#<2iK۠Ab'Gp vQ1g$_>jo7:!D%uFڮ2;Zfz'|{Α8{lv:r`tM7ٮM>( (M j6jԨL<^rhJG\ybZmcP"ס/i$̢6ZTJ:S kb-rd+ d,o|glĈ% Rg78Hs)t"㏶Ə!*Y#gwرU_(,Y>; %If u0'}PcG1󎅪]'D~Q 80#xOvW)P+JP DpG`"o$߾v8~{i{,a{-e>o ;#/>v._~9KL>3 dJ JV^sV$9P5ǚzƽbqlG!lo0{^1*t2M]AlAtYQP+[QnmqOЉЁ39 of:T8#,xŸnP4>m5̘iMSgؠcKt_̖Fl.>èd k7E|xEaӑ@(@,M)tGeN7la':4ec7vM/eA:Z[E9 ޫ/>F z5J'GpvهEA}hfm&4Ŭi$qm{16urCb(a[O,f{S }a=-Y7ϼpY3?qN /u(33UEv_~yь$`@@KYQmgN+aÆ byh7גKQk-)qGhm_ fwM)㿰!t:kMJX78#nG(PD`w FP`t0bl;3Ө\-e¬2%N:,FlixAUs[aç.Ǡ`~? fk FL$$5R&0h Q(7T ^* 'LYO}Һ~LDXh"J:%ԬPF%7["|(f*o5bQ]茠NlpŶjLzx'U"}V0qBa'=#@zLUʪ0Qzf9www c1J> L{M)/&w,2>;f摎#8vS-#XȆmݭw^0564ZggFî8rbvyKE0fꢋ.K0Z%2Yp|Ok)#g($aajr6||h)38-cdW}5 (JuAQ8Ӣ]<;hj0z)2񾦳AJ_ zK !G/t6jK'R^"䠠CGʺ,c7}gmTYuQT"|H}7h8J]s# :@ ;q0,܎핁5ƳCCfYȠcIǍ6^Kz?s3L`o|Qi "e*f(h\u' ?ۯ2#`eo9Y=8#`"> ۠FarT+/fJ6o 3dJ|,c:21vyő1*%NFlK-yl;7/q,Jtr#@'Eم8i˥oJ99#8 6WS،,Llm$RuGpGO 4ߵkxj,'rH~T7i8.%qގ>x Xkʐ)~{auɯLD^wu4ߖSyn-fe듍%raQT~{WXarGpG .&=2Agzs(t܍߶fx[]嬬z*Qj.@{a^rocV[me?hc.pGpvǤBg$_ÏST>oڒK.i]ew9^oeE߶-8=s4=c;찃M<9 teYƎ?rje馛l]wewc&Li/Bkj6jԨL< 4(Z{k<Оx c7tX?<Kˉyu_|2;EQM4,#)$uQy:,p m喳qdpJ1[ߊ&.처Z}D{A3O>$qڴiu[F+գ>gqF4:c_$?*#8#0h7|~)SϿg cO4ܞ{e 3Jc oֿCG!9C^lr)vQGE]1@ E;afsNlnzk;OSL(H(tN^xᅨ#G?QTQ(JcJGeСRNAk,x2p >cƌN;Mb{I'U9  P qM[<znW$ɟ"Lp |[o-(K{aǏ|Mmbꓽw$\fzˏO.]b=OQ-G%|P)駟mΝ~.qz.ⶠq#8O(׉{,a{-e>o ;#/>vf/+bz-GA^f/~a{WTǍ%X"ά暅A;sjYp'?dDiy7Gy$-u-%g4vVCN^`H.*%aNGϞ=k{j$yQy0`@lK䩎c5ȃ>x`3ZkRK-e T-I]Zf4?W_}1_K+,jAeǭ^zHꖖN?e2S/Knjs^jRV GpjB]~Fȋŏ۴0c5Ma_6Z-}1[w/=3?0*0"3D9aF ̞!=f0o)nƠy`2)Nb++&?#8vQQPZ FQ6{,z.a]C1ֳ[OdSl=7 $0FP2a1Gΰfj `G3<3Oa |&#iT#FYȋijk*s}>|ܡlA^<|R LW#FGվ+N(G(2R&0(_2yף"EZRY.Oc '[g6+2vJS~-iEmTr(‡ jH> +vm\Y8x/3*>zXmF8Ž>134j!FiQb K{,@}'Qw$u[$yo6lXO 8#!h72lߖze S{XcS؛KZ| L?咏qg\ )1۷o4!i$\;dZE+vF(L̘T0`W^9c`3S(Ju9c` ;`^ ag"CU侦AQ zK 05ot6jEE :Tk}TT;c-=+#.jQQߍ6(d\[Pt!.(ƌspy9`{RN/#T2 >PH&Uedv6KdepG!>2mJaĨϗˆW)(cǖHu)pFtϝϔn]7?S֧KW\=w?]jj^X0x y6FKa*&ye 8<ɋ$@BҠ ťPh)ЖzKK]WO[*-P, qw?onsI$=+眝M. GW%R:7_@?0FlmQ3^bLx&|x~϶j_^7= E3jyڑ?9ʳl|jtS/|kVolӟ:;N;ͭ ܭ,%ѐ+r|\g), :ѐQFf/WR8888opGS9vIKV B ߘ+ Dt`W= 2"ȏ˗/wh&`D+?@O~w4sfs( U8 `b+'0/d{Fk#fS6Y剣ҒHo.ҢmJC|leBZ@@@@Ͳ1F2F#q4[e^8]npfsK2g&`0m@88q N0f=;Q@#ǚyG1q4D'֡x)p'h~4dv/Y 1?Z ؗ9}wm =Ј}Miwle *p p p p p p p p p@h9 l%̆46tI(C" +B= {6Y4)Ťaa >.?\wZ&mQ~_S@g({NFO{IchʇB+$o>u'('N$7\rg9w= o888888;E}z6m8~*s;14Dq 4Hy䑬)Bf4G]wNl 7W\VS_闆aO̅OtDWwTǎw~7ܷo_W3~C!ol3fpq-Qh~h4"q=Zh)//pQQŞy;v޻kYg(B@r)ȝwޙ7nO:{lr mذAdNm-SLW_N$-[u7 'Z,W_}uWH6p p p p p ph-?|h9)9Wճ돣X4Gu;}\y.wߕOWㄹvTwPO8w©l~رPvƓ2kD6zhV'J_G8_ߙ5}_uFuu5E93-ؼhD?u< XG?PkN.B;bQ?I (&c&ߴ|Yt6yLH._/Oę}{_1 ޟ\đ Llx [nŭ +s/@)VAۯ_?f"@!8888884=G-pvKdRٶD'o9vL2i%ȣ-{&׿u⋝4BZrLg9昬 92%AN1ɇqV .ry^V7la7iںu` g/+gfeǞM1BqpR[u(}wV:tp2iӦ3sӧ +Dƍs+9Gq_W4? ^&hyi$`C>Ϸ[]->V.\ǁjG%WqE5RUQ#'!5EleNV^/zvWے%K *h11ٳe„ N`bịePVVdgP)ξSx 0ok6v^'aa.K^W믿6rq4Ó( |UG~KLDS-&h@Y6~ 3L>`&zVc~>*&L=zDB" sY~{}4VoedGH2̣HfZ*vSOM=ݲ+=$ Cu 1m,*10}AgLQ4gg^wZhz!'h힣#Fo Ⱥu2Jaڕ;-qƴyv=dCH40If#I>EqZg: /4DWx<C\~_F}t&dx}b_9YƙE0!@5jKн>:?h"7gb{o`d1_V䗏X>8lMM/|~|;;?kE{HxrYLzH8λAeҾo,-K[˴KUPX-[b)/J >ZG0Ǔ?ϖ #L|ƹDdLgpS hM_z%gAȇ&̊--K0Çw510\{ps}xPg\ǟlm9Ü f0a6 ۜ0 {2WrPz}IxQh|΅yeҋ}k_N;i 7)?DS}dyGV&?;"O܁ze}'f͒+V== 7tS&M/JoҽO?66ܟs9Oމ/| n)xה}!Xh66l<9][ҾU*SV*ɧnGC'njM\b'&^t*0%IVoo}>4B$ ^nr7 |G:.ť wlv6Vmoz 3 <[ [t_ 2xR(klCrI~MC6F4x_Em3M~DyK.~PO_h~@2}wYp!6[Nb lj|'[?ns< կ[ou |Q).JG88PFQ!"<]2RU]Jjڊdҧa3UWZgvm *7_M죉c3*N:.!0 T7tph>=*J$z}rWgSOC4 N@0a$h;| ċo Yl&|A/t3L\J:hęU̱?vVXae ``?O=bVs饗:'βAr7(;XzDz~ڭs1'3L q$]|8gxʳh}~a+30?WJC>䛯!}dzׯ7_DI&eHws^D 'H#2'͑ly;o(}b |5}tM.#`GA#ج̄!-I++%0(sioٹmR>ÁпLWG| @6AL%?qȘa:&>h1aou0 M/|lgG+"kh&Ej_ fXCY}\ m_6@hkhT9gNc‚P{׺3!p<p+ėTgmN*O<h/<48nެ>o~H$%߻r=,.[ 8@9@p ziHcރItvwOa +ht ;,ǏM:|=n5>[=6Ǖ8LX@7ͿEL X0E>| ;D}Kw5һW7w;y\YEE+eC]=IV ^,k7Uʈ=Nn6\CPCB}(ؗ9,v+k0E)VhmJkdby%BֲnֽƟ^{M8kOv3f̐zHXi Q\ ɛOIyp)rACmh97kSћo}|ؚ1@,wM̀+p pYq ʝ/Q7l%Ҷu+i۪Lڶl)-K7CK:MG.^Hi!dΜ92a5j;14Dqq q٠ ɛ\ixmpZoC/TF| ?䩧r'b0@@@@@@@lڼUZj³cG^ڵJOJ*JejS$-[/[NX~n(nSYc]wVUcscl̙3kӯ{7>[|i66P{V}6}BͿݛBo888?q/r=s_B+jg޲qvY);%}AZ{j9r@y٩Ҿ]k!߭|E?cǎ͜i[oS~zyᇝWNd[u͓_]> 3aYgriĈ2eYts G;&kG^ 0`Ny 3|E9嘲cy桃 ~7GL wynm!shz?x6|0GГxWf_7ڇ=Z.wᰙ>ڙL6-MЂ!<3p-Y 1,)#ri2e84Ֆ̉ GВMQhXYPp^.0[!"-2Rok6\VUg!]~Nj')W4}D[ 0@uV/X^}Oړs!>YO;5`cF7 nV$`w^ol3'3?u뮻 L ovuo<SNb?ϸ[Ŋ'Jݻ Ŋ&GC hO*Ї gVaeIdx%<|\3\hR.u/J6jS#%29k,ZRjkjնt|^]ڴj|)' , +a CP8<\'N3Gi |fKMJ@YF+r=96~Z륗^vмbRtgx]H!m1qGԙOˮ:~ӾzʿG^v&gyk3HQ( _W{}V$ X58œ~(VXo}[~; 3ba&%ccV!80b;έB8p p p@@\,ԡ꫹l=*Eۨk&7=ʳzW Gxt4 q023n1g`c*¿ipŃM|h 7MbŴ'0Ya\{p2a6@ Τ2'[[!!00aʇ^ L0M|rdo\#O=?+gf tdyx "b1@-;Z~6:#N~lO?teF> ?򑏸ogRYL [g?s+h x۵k&(ƍԇ h֕=qIO~DEÿl9YaTVWJ.3Ok);tpX|@9@jRP m&pH;X6lJE`a;{|l}@yUWrݶQc|hb7EQI2U&)x@˾&#6xxVM4eqx@`f;(θ{_|E'(" ؤϟ'~jyl!|@xBsXƊB?Bs ̻P@(o=+:e}`,1A?|0oaE |Fo2!ԣVZPx0=I >NVXe`@|yډ'l-|_S40x4}pO<8||2h icԿ<`iOR#Td!Q/|1:෕ӗG |> . I'3lɷl>hM:m t+A&8 qt>4!4@ĵ}Z^dow\}Cp|6 OGhT" |I2C(e5g&흷<͏6qKL>V<{#Uɛn LYl:l\eU`f^LX5D8P. p R@,&ـw8O[ͼ2 ɔG?`_fJQ>&ZZ6*7ͼ({~flQ+G?M+m5$Mp (}#EbP\7n,]ɚ e~N3/BE'~!4"\SśdvT<}6N e@?L1serwв0ۙ Cg$$ !=~&10<ͬ (hQ}1!v4MbBݰ~l,_'gµիW = ԙͼaOڿ9?| jY@'S+Wk@@{&Cr'QfPw`i"9pן%L4hnG_q` #- ex88880aCȁ E懪8fX66753:|:@I4Iٳ3p dn+a4N:iX4p p p8[I#ZK.q8jP0BP7;cݮ=%7ޒ^} _p.5gJ%>E{=WR1x[3hXϪ@a@@@qw?ޭ[7w>*p0l?/~r;D_; -k`[ }b҃o_~n?|x[Ś_2s=Z3Yo Q\4 ɛOIy?ĉ3M]oS{vN/^|7W|q$\S8Se9W^qJDOO֝;wnRvo瞓~ o;lHhfA#qR7̛7o`s;14Dq 4Hy䑬)Bf4G]wݥ.Ojz_=hNWXӧ\wu9[ä`̘1jNlPhl4NƼN4Vof~wW_NWA|G0Jt=L4'M-[o}[Vt.ŤtBc/ L,jZʞy;vlFQ\NS9;mN9?-\UzTٌ#,}7',/ ڃawqPH~|ZY5?qRծ^xAM#Hf?g/\'smy8^:,w<L6q| #8 s}L.ze2#6qhy 7ܐ)_8%cǎN' Mnwy0X8PV\I`N0#6Y9ҢmuUW|Cѣ >8>]EA?- z+S~@v}G$Ɠhg!Gfȑ П' )I8??-(v:h5=\? c6&Dx9I"Q6me]&7|#F8~_/؅r!Hc @@&.h'Q/6AV<>*M768c+/U ~[OeG@DOuڅ/7War`;Go0SSN&4$%lI]vNS5$> h ph@s^.LrGɤwhlylҌi}1rA~ svXKql5k8|XGacZzVbn"$,)/KOo6Y9v?p' ^Tz:W~0v"Ї͖@󋭮fRWF+= hBE6Y&fik @M?ioqb"h 6=nZZި p ػhA @2iflXSZl+Ӧ/U RKiߪ߹V.hn@fA͊T1`|3k3Y0MkhlSCget6nذ-.p%^lYh ٴaԪUk΢ҦuTO8(ؘp{K<[w6"P3~ qGcAC>4aӊ`j*9/7MΘ߰ ?+]XC!?Ima\|scKf|w+++LxF'>+͇>!'LaFOd ?yǍ'L^x0o&uh/6xz7pp0+nh62hҟĘaѰ' Q2ʾ8g \ יC[+kf 75luťZ qVWo~lpSVW\L@7 7+5?97Dy74?h`| 0M@~۷׷HUv)Q┬X@>L>p?*W53ZMp hx&9 SCM#@9f\Hw4pr1M} ڂ0J?#­F:('t$/Z^xD$B[vZx LY&A&@ npSچ^ kv7E}ښ_G\-.݆E9k+W ]bB\IO@@94{x&M;F< 22$!߽Wj,e ^B|6_VaflhN s4د7&`*hMgb g30$VO _d)LM~[<xҳuX:/(?$4&]`uYخϻHYC-ߞ7[\C5|배])籶5O|>nh?䋟|~o+(PPa"7R[Bmmˣ̰1㮾,nrZ&g#x&3ԄLHPA˧LSaX q2EBo\ m \{?21OPx L:8S6ظ @S5 +?N>xlIyNTIofq.,WK7_vov?l!v%. n/˷VBZr{VծI'opY>Fq+&(PΰC>UM(CO82/ L8WmeC% &YCR4{98Zrmy  ewxBgcY~O&gɏA2vPh_0&b<qbmX_Njg8>hrfݯ}kYxF~AGS) 4PG&ە 6]2h҈#[٤+|[}Q|V.o>|ertX:W [ZWnᢎq~_o8F3| o+B7#.qԏA v>h#q Y2Άiӂf&~3"sfpL٫j N*p̸Od~g3 mn"ܳG _Lu >q{ɉkg>V?hrs]y'ybU;\xd.=Yk+p p#)!% W0aӝď0K,nV–F=),14pNji\!J.v0e 3z,L>?_?yY,~5;jWIE]ZV[~pZ6 0\ZY|,__~(caK3֯o=Vowk]X=vOYpo4Zo[cH'EfWhۭ–׏4NsYh6>~VZq2NgrW8!8#7:d?G>穎xo-/68UpC2Zw!pX?/N| h2k-Ik }~ N3pXB ^؄CI RUn Ϙru9Oc{<f?/ h}׾l qꔙsN 򻄽Y4MѦo{)0D+R:(V(QlPӴ뵁l*FpfEף6>|H|(k8'lXL0'p``\>Y"pehO~+R.O&Ԟ$gTm4_CZDpl_CR yއe+SvV/[8WCek䱇c.ط>7S}<;ETi;92_z۹2u*^D5%ŗˬg=Nq~78x>Kh>߮[h\GrvYخ'׵I/pP77n51$AD,0K o.jKw67{`ܜuyCHFa37м2 &L=GQGGcvHxi[yx}Cq݃ЊG5VВ.o0A* +kq+ !/%og\}q|Jj__ǪU\?,LÀ0gq9p5u7on~HtȐxi^ը7p`.j_' ?Ppn$ 4˾j1ry i-:BQ'壼Bc01|>K^KKWɜ eٚRY\9꒣3h y-ۧ"̖|5ŭ4oW)25z*_W۞5$~l룩ceKKqڶT- ˖ΐCJnjMyeY,۪8Tl^!Y&>*'4A@PTtLIEN v﷟t€NE%yLRAŦ2sBigfL{w,zw=z{XL{1~3-oyaKɖdI*Gwf̙Z~zh?`Vg8-XݓPp֟+-7SO=՝2rH|nv'\#!$c D] iرcnpaE>. 1p~L\<+q01,{1Apfb-%fbj#{A{_`+N %m?{3<#n 4>fE`q$ur?I}aiI|be:}X\ƌ۟6٧ik W޽9'O+ԬD9 Auٜ Q q?uZXg3a{8>ؗue҉#ebW-6 uF+y?0d5V_r=oB=~VNێUn UW">лxO8Xﭜs22WW^Z.]}^Y+'I:A+*jY'\-#zLڸPXbW_X5 jzEgHI$C{^UkhU&L,C}f kO]ϊMҌ~p.?x|fy-!x`ayaq\)k`aKaeMLF~8DݪǏwJ\dRVK{x]ܕ#2PHWVni'4&V}g~o^E㥺F3y[UXrlQ">=IV ^,k7Uʈ=ߛ uI O[W(UǼ8H43Ge#h< Gy+K=VS(>e|-e92}\L.{S~xl@5z.H7ً+V '3cw]NqW{RRD9yi2]OymvKyifXiÇw欔u8͜HЧ5CCoR[hk]]5es˳+e踋#;9k9=]QH1䬱GH+S<㺧pJy{e2+dd N*UG,i{Ny>4'*X R,h&xSw ݲ wkY[62ɉGCu8y<4CtBv+BTu휑i<2;d!3+:>2ig/Hϲ*Y<yչ]+]r3}ȉ_%e#/.JFN<[TJ 9+et].`|o~~&&{GY>G7@ nѬz/)>1I4!p:bq\_'ڲe˜Џ'$Lˢ@?q,EytzjRTGy+t \mJg5|c D]zߺ7,=rԬR{-i!HM n[f`"j:@*-I_rzImj-'"z󡭡yfJ&W\x\~vVzSЧR6DGם #k!/XmS'xBHjm("EquuʼƑz #oHcϐFvs^W"`!,xXf!\1BڨM V~nkŎ>,eKk̀U{&BZPS[!E]ݦˤwfɚHג4wTNxE5k#=~fWpi *w\xQYcJey}ٿl<ʳ2wp&&/V#m=ye^r֙|tүM| eYAw厓.U]XE3ޔ3GުSO^"^"[`!R<ܹUNzV}kg-յq夻ɩd]ɋ.5]<(Ι.o!{k917۰eXұDǩ S$4K.՗}Rw.Zm϶E˓ ig_${a8dȅGI9dae[3K`{bϖ] p3IygW-0@Jy[^ýV?WVpͦF_ !}#n1꫅Iua6I .)l-;B7+`n |r 9;3!`C0?k[R 'gIcןLz޵-!.տ7M~.Yr>ym+[䷗Iuj5tX5Z,C޹]J>qҦ.1cOlm5nTKjW`g)=rTMe8ˆ/m0 UH =p;&zbp';ז~Tf=ό>U1?'.,*p[2Oݕ&Z?In˥[fRTo7֕J.>('[Z0R>tJ$ro_Z)]5Z޼q2{TKqdD_͎fc昨U33;dJgN匿*ծT @MRkJK{]=%p-.2Cr5t4]rTMvm2yWd1}ȓyXDEuRZN9\Y7\R 3ag_%ctŠF#VOy|j{9Ӥ\NL69Bz()M&w?ǵF+N{o{Dx\1Z1|̅r⒍ğʃGuEowQg~]];Ӊy/!~BXrye5[ͼW68vM?[Z)!TXr9Oɀv9G'ן}Ww ^ϳ^[y-ZW{^㞼>i1,Ǎ_O&ȔWf}+#p#f`LNKCgo%-)>J eAۢt'ђo4{%Zo\y8ġV^"/>#[%'3h''!OKC6m*Zҗ(#*Үj+_QU*ktBVźL5VoC2%Uj[7(Tu}aѕRTz- I/VZ>[jE|c+gVJZ<[׵RaPM*4ć5:XQh2J!ly>Ѷ3Fp(k}a"̘*^x\|=b6cGV.$]H+U6T9^>-tz__LKk]}TaZL]!ϦwI*kPV,:|9t_Բz:@(zSfϙ)mfHQqҳ,v nlgïH[u<2q&m9=I-\Hic7/ =9Yklv-Jz,| -ɤt5I@IDATkd˨j&B79/= 5'P\VڶT~TTqlٺCUT-_K'DZUn[!82zDwU7/~֑TBߪTk_`}6He5jWw}d=.w V/RP#l#XB5n4ɕ_6SP(@v`.);e-11T(TG/e3e ͲCH;װ$mK|eGm|W?}ڤ;))ǧ-s䱗HїG[ h4zkt9amx Fzi/S7t+>{t6PҙH/V!pWXFm<ؤuZ_*m뻭q5];G s>HʻMzR ,++,^4-fC i}L[ RWPtozңZfNurS{u»ژu9 =/Gzh_پUj۫i+u9*[ʤ٣_6b (VHcK U{e*𥶵grE*K.'$AZYp Y*5x[¡ҫVDTMTJU/ ukKNNg$u)qK&98\"˥jf/1R5{G/mWLu7-m E:}[Dt8=zhR?xR/vB/! ڕ鉡cK;餰NVKh&,eIP} "VmI0aIMuk~ⴼ]; 6c6L>fI#y o>c@0,/}knZ5m6Ȩ@ (ǟ0T^f[/ymB=7`LnM?yei[+)en[2%JZ][e#JUeP]);R.KӌV3o^Zֻ ֩ՕcU]wTmrֺT۰e+2gVl^lj=R'R7mY+3/rNRN"WS]M-5EWpM{LO\^T ?_VlS N\#[5myؿ'Z5嵺r2 o<:^VWy7eeZY4olU6:3-NtK#0?3' f[~[\'>ρg#^ݥ ejsVKʢū#q]&}!Vom*,PZ3aB8-}m1~F*WU:|w٪UZ5muCnvә"-SbLuWh^MaSt`TzRJkNffj]ptOW tS-Юwtvh[jG -I,t](IqIظ\Ԗ:]b٦v杵4ຑ._|pY|U͚6mU빯]z_CtRZF] J*,ı1zpU]lbU@*SHǧͰ4MV΢`mP&9p0 XֶQ"keykB ׮cy 2(N€Yɢw6IA㤛jUFˤu9J)s,6*'|B^y|?tj\g.-g>XxywG_9ᤁ2TZ82!_7ekǞ.C%xIVzz"k)E*רIu#s:JUNF`R/+7)81Y8iM49N.cBPW3\&BS}@&h\ CϸTVW2\5/?V:>Lu.s^y@\*׾%םɄd)ĨzչG':szҥp9gt3`0:c&d2+taܜr'gȓ/Ε+*'"q-JBX3M=M+ wS*!c.U?&yHtr2ߚ^a`mqcO#<)M4=:9nҬr;m_*!LxAy3wQ9~Dkfm.4@,*Q(מiҠ8ai\oeOn_'(}ܓ5,q]D888:Geu}Ei]Fvt=U&3g-EKV:V-Heۥ";SN[qQu`1âֻ$T.a'c{Q KvpԪpji /?wߥ'.; x-$T;V?>.\:~єCm]Ƹv ypSE~Z5X/:$GWS:HKf+͔NQ5V}VuV(3C_Ċ\%nibmfd0 *fW|\q=`#n&,wG_ i&:>l!3( ]NN$UT[:ęԴ1W^''wjpErh0q\ZE++W{~o8åB5Х:yA2L]Zʜpjsȧ(mFrEZ*r…hU jzF*c*[tӮFWd[r}ڣfMu:2uw.um\v0]I߯2֩[Ĺݠґ2K q§2et/-Sږ m(G|zXÞtZݗR :\gL=z}}ns=vӓo 't/Qk nft O=Bx ,p7Ɔq1 fj,P>pʁ&I9ZUUF-#uPi:9#nW'v'^f$a+iSZ`]?EKj1rTqH.PT-{tu33brnaفhPv>>XCIjr-6+٠ɐ*̆!iM*鷔\:Tpա8?*?ro]TqՆ`z Ӕ x~u߿lfg#G^~}U 5W,0*U"j΋K}6oWO pMӯB\ֽJv8KI^pרiJMqTJRv8u ;t᧼igK)}p4KG[&emV?a pc-R}PPDxIE'|<~XtrV8.I:y)IEX+㴍uuVVRҽśBQm~UWkYKsSʺdzTi(O j+GY9UYO޹=<'pڮWyv],?e)c|?VqRp}50|QţhG+׿z뭙{o&ۚm8@%L|cچvTS'YQzlQMjJnWՃ.,aE5~W]{6x_l~Z o1L݀;>4.Rz:uLKJcߕңtSݬn-2&_uD깪tVvT_j01Mtu0mYQZ \¸ 5uZzw'[[Rj¦WEPcrEMyRwYJmb5yYU$}FXT(ADA* bVp]״ kX(U׀a1kk#|.DA i$ȫ/rr8τߖ#mX# *_T>k,-oCY;VWRW=GZ_'[4$luV4i}|S E&~ZS?1su}^l{swkdU(NZ5m+-_ B5"8ߪxCЦY[g"$o_) ^?}7kg e) yqfm[Utz%~ؠI8pZtJr{O2m_ߢ7N[~%')Wk : :Qlt:A4嗠C7?DϩL,  LJҶ F3r!E띬qQ0#X)Е\$~ l*7[6>= {a7kjL 03F|¿:HY|XC|xucW&Wy^?䃔~9FlQXU~\8|E9S~Z8QZ4=f|[i#D>il5*e'MTuO5^c /~>iz+)_M5i'U'ϗ"fow9P7TF/|My(4l&Cȁb5gΜ‚?`\#-ĉCu a*?p@ra~JC7fEӅ/P !͈I=Y{l~;Sկwt$u0)ۭ7Dt˜Q;go/k~(x'^r&P^֢m@ 4lT6>F?!TiUP@H4QV0_|xp=tz.S/|.cF9~B,݆.;8c⧭O07٠kW]_ρ )i/l5USz ߾}ʺ r+zpT NN=Tr7(SLf͚?.mVnT^8B[\s[cF@^JVM*vLҥ̛}'Xն]~`37NR |Qp6u=X=PAe లT4}tjJ[:e!:3^&E6u.q2tǿ6ʠS,JZ\IlaeΝ^GA b?M5H^cWdnW$ӆyndJEu ?g?CsJQZ-yOӆӄeklYg|W[M6=j<ڦ\ˎiEq"hO` YQ͇Gd0M2ax%:#}yvllrEErWN{YdkHC{ ~p];-XVa0Yk` P"TI?MlGOҬH9@޽kNe&!P߬ҏ;OR;,.Wo!v|vțP?_~ &ʢEzZ!`@}SQ}ba̘1ұcG^X̛7Oڷo'/ߩS'2d LNbaw}_< |A],t.IT_!`آ{yU-Z$^zina~r98ufT4i: [00#n-B vllJ܂.!`T(dw~ڴiN?tӧO<̡84BAƂ_^r%q2kn)odF#t]w?/O<.pOvfΜB0BOZQP.?;gۙg鿕+WFK[\%ׅ4dܸqÈ#q&FjKG0 ]>h'+mdy7cꪫHyNJw̒|SOE&'4)X0 C0 D o ?|k֬q?ߑ͔E2j|0G /woT}08wqҲeKA_~2~xlNy;dt PI|L4}t߿vmBZxvӽ{wC9$2]rYg|x09rDytPRNA)\(^cddb뻖o儷GՅt"icGnݏkLGq2{2a%sf=XaƏ?Xk9ꨣ\:o` .|=##QI/Lp>"S<#](I$|,!`!`aC!(jع{5Z+ _/+Vג h:i'n?/b-駟=؃$rW*XhEpt!(yP ${.bs&Ltz:Htmiڴ(D?ky;C1_oGԛaTBocqXN-#C0 C0r@^~,X asp`zY[Nui*ȼҴqYTT7۶D[iԨQ 0J͚5]3fɤ 2G@\#>ޥQBMwh0 @^|Qtm%, בuO6LTI-fFٻj(/hp"IF=\ 7LUà Xpqؖ8D&܊ l&Q.]D^\B/>nA:` Lu=G:K^a˫iN׹A O-u:^{$nn: gϔ7k|eq4|7@1Ogq?-OU>Z暔x0);|/Ro]'BЉ~F`θJ3]󦔫z+?!`\~\Bpmn疲UzҸa#)(n ԖFue)Km,GqDz?{&CbC(&Mmr^#ߤ.D$iΜ9bK97(ܮ];77._u09xvr F@\pnB0mC'!SLӮhėĹ.]c=ʽɺaFӟ=CΫѭ[79bBdQxh\mo&7"p~1qP_qHIhUy(<ҕO:2/CEژ(U3t&լYa&әS{8od!`d@A`C3ۜicYe!.Ju\Lx7K֮[) f" ϒ۷k*h"ggRº&\SL3V@hQQ>/[d w(&b.t.h㐴 $~`K2Ud:;FW("3O.0<|-Y?RdBR> F4HjgtT#nt%M{=#~yeCyVΥS=sAyK>uU{P 6ھ! DE{Ao^~ BCF6[ZC ;s}Ǝ')}t~k1:zGy$1$~wnb- p4 I:o7Ukɚ%t:(I}\K PdWetWه dY}3AꂂoT'}6U}X.xWubHe0;3̱Xlst ÚΕ-ww)k(DB)a J:"z%#P!A_IkrA\֕!`nB* g:v0 Cf"s%F= z((]lvqn W& ipჍ"| $.% dlu#PQmg bŠEx ZHJ;7\E+C`C)eStj_c[vX/A݈2d쫯Vf3 gIL>gKBX)%e[\m C0>9U6 Cw"|\pSaN ±6[bҬB&3(PL'$&u+ yOZ,GLŪO"J}t8z[o!PȋR~#p +'U=L"Cz#@,XQ;t2dɫn3XtWO9 R._=.6D@'|f?#|=ꘈ7.?[k-;(ɻa(L'P:JMٜOZlxZZC0 @ p>0A c1i+l+U??~XYy_EWX7uky d lФQ姦+Sgk!`%ȋKEQ'T ~LVnH"8ncd<2yp3Q6e6SqXwr _a䥗^r[ji,>r-3fL*l֣ "{,jG7ԙ54SEYsۻ("ɁDٳ[ӦMs5@d>}ȣy[⋣7tVՁ|Jq2GdFӈ wuHOɁ,su&E P&\(^(: Yr87>Qe>.\'˸q4k#FLQOh)N&Lt.G}3m$otjQQДP/ Q1ؕvJ Tj˳~ɣ&LHC0 C0@~,(9L@dA~(#?)s dB;a_*ߨ4pqI˖-"b5ǻdgvy'vاcHZP dӧKJtP xvCH~[Xm$2]rYgq ;s9NqG1G4A!J9p]xK/uAH7`Rr[B:ܡ1#G5w&ҟtI2{2a%&?(L"#QGPxSVd/\ʖ 6,uRDE/#C0 C0* (~, 6z zזkd֜%Na W)ЫMCb̧~:+}:~p^9yP B鈿bM` O]HGB >ܱetCG(?(O儰98Wn-^'ݺ4 dbiڸ,*Z*͛ ߺe f͚0QILLJXxR5;כּ)$2[#q+7m۶-ͯk c~WrU/ޖ.#ѣGL$(JҁJg=g"whI QQn:[nQ&)O8!`!+ܣEE˼EkeWɡ˺2")^]FL)Q/\xqJAG?…7 &xg}6SRw-[N7nY "XHiʔ)n(K,q U~_WA$\P*-'P&`P;OgAÄJL \Ȅ>:YLH:">je1tpm9ӄű >BXIl0auV&Ѯ&E]$<󌛓aėWynٌOr(\9IV43RUd29 C-f0 )@)W,_6_oH М[֖gdYIᏻ),m.#8OVb_w&P27 ?Q ygGtD9s-2闈=q$g/&bY+[" iI ?I! FՅpo&曝o~Y6lY)8L|yIKL{,||&@zeS_0ҁ+xT$qPv+l+0"?%WCNJ/k>ma9ʕkd¸YvJfȂųmgA Q<Ϥ0k oMF%b+fK(ٌWE==GsBP;W)!&ȪU?˂@Aו]ZgT➄! ,Cُ^Y}ұ<ԨQ#uŪ l;3`bkvˁuY2,!`T<9UV!` +(,Ȅ?7(b& <tdT޸sL4u:|A9<ࢱ䔩13ZX6 J@J݊4(9W'I| ~*hdT'L)Neg;9Vl5!`!` onU6| a@AӖVC_^-!P'W!!`϶8yo\}e⮆ >p& V}C0 C0 C ?E'. =[zEx}z=?3!\ƥ놀!P}6듰& ҔX MZ'ٮSх* 84vIiӦ9VTYXbד!n$y^6XY*[|y*M2Qs;*3p3ΐ_#CWbS)/ʰCO?4MXI;=xFeSuW *?+Tg{ٲerW$+tIL0=yW믿b$dM\9tPի|ʶԖuIEF R%UIfȋOQhPY9? /U?.3f̈F&OgY?-V¼X7(y6e6c1_|/*7F_~饗dy/'ˮ:Fan׮_g}VZxf۞Qɱ+͛7~:[6YGIƭY)e~GrAɈ#mIBoѶmrg * =Vh_%KnW>+{'=z]0QFIlZTW`j%!=l믻}ǎϖKXsܸq{z(|/BmJU 7ߜ뮻 ?k?܆#$[dmuhʺG"'1㾽XoFNjoO> [ozꩲ;|ti0ak\}t"|uYn~ʕ>w s}n뗙?ʼy\ٗ^z0c=GXWXg}b a'jyӫ)ue^"Sg.Jݸ ;wva/~gϞr'qs9G%26@IDATIeիx÷I&r%rkɑGd> Nj']vE.\̙3[nOZQN9OHdg} gy;xAEK[VL iXQLQOMG0 ]>hWgvI7p^hW]u /V{7̪q.xfX9SK c0*z1RrE n~#Gq0dS+y:Q̞=}kժU2>sw=#Æ s*O>]z-nʔ)}qN@:SOɭt 1Pj@[Lǻ#mڴEL"~iӦLtl#Gʾu (<ÌQGŋG˥yϨ 7!/&ʬYxhF~6Sɨ2v)TQi@"(_WR:x9U/.ӱ.tQQ`A!gaÆnF_aI0< /@Z @ i*1dŚA4r(nRFN7kuǼ࣬\Q29C0* O'}g?cOkǠ[`_L1d"2 GZr粕q3$Qs˙??W󠡰&u7jp`zY[Nui*ȼҴqYTT7۶j~0+XqPj֬ʘ1c/)1,b;8wRx|wEo|0ƥzY_|\ax#3#tclB0cBf\yp)ͻ<3//FPqԩa :]F@&s7eޢjիee.|&I~+87*hSyB^:}K0xGѦG4uTǗ =w_1lX^Ņ#uc8 L\Quy*~~%퍕Q\R.xO}>醽sY$\g CbgenIIjQ9UAfFv1 eK7.|3H׿ՕKN &q&O焈l]0X# v~ \I 1*\" 1P)[Dt Lf׷o(yQQ5luaݕljbz2qͥ eҷ*SjE/RT1p:YЗ0᧮7x 7ܙ(L1AQ&Zs p5I2d txvin/8? Lu~D\`oa MLœ S&\̷7>Qpz z㖆0F!`Twpenl8カw[Rh?<Ӵ|ygw.#\G4sߐwwR%rꫯN3׎o2hР1Z7I aF(Rb^؟rE&,V .!lիW_//h$Ah΂H-ku߇ /Yqq`:Bם %K!\[B ?Q >$r n($21aM^(D#^ U0cgDY+[bx4 yY19I! ^f‹M7Bᛟ6lY,G&%:OISK7zW޲Oa++og5ޕ碶|orrA3y(JI]L\OI匒1F3t/F"ڟšdzXre0uܬ`J./`,i}٫kt.+k2~~XsMQ2[B2 [&CF^LE-Iiܡxඓ.t.hl_X?O`%IB`K/$e$IS^ZopClw(>D$FqT|c CϷ|F{^-ݫmdPYC1a!SmkTX0'#S2Z[ut@FrM@Id ! դy`KvzAו]ZgT➄!IY`1-~Lʢ7 I4 30 NW=ɶl;3`BۗE=ZYy+_wʾL|+e2!P_ [U+(,Ȅ{JKACRNwwI&Nǃ>(|p\^gPFɓ'W?MbC0 C0bȹOy $L{AI921Ȩz"ꉄIm!`5 >75VVC0 C0 Cpo7!`!`!P07U0 C0 Cȋ?QM1q$-IHTV32 C0 C0 #ɏ(lQ! ˩U(=z]0 C0 C0r@^\zPuq,,-_<&wɎw!_}Uvʙ{993Dl&mӥ!|꧟~\Q ,NX2;Sd(?D\dkܹra[o-۷_~9w={O>ٝ6mŠ~ӧDTСCW^zjwXۤIKR9dz#t2p b ^x e]d…)`֭[OZQN9OHdg} gy;V\Y/oY19.aEqƥ#FpǙ~Z*# pZ裏vu~,on+W]u 6o\0Rq2g(][hAt޸W׬Y#ĉϹ瞫Ilk!`@ț~rJ f"5PN#ʻ7*~-8wqҲeKA_~2~xlNy;dt PH|L4}t߿vmBZxvӽ{wy塇rId嬳r?)QJ߬YRQHx饗^s5m P^%xGՅ$CicGnݏkQΝ]z,ٴv]f_&Ld. Ա+?|7rI <輁) Η_~s=B{1dN'g\[P&89nE۶imoLb5C0 C0bȋO(joР4lP5J5F~_[V%sYs8-,_|!&LYf O^qҷo_<Nkי:dE Ad=Le/vJeZ5/~ܩZn,6^%x%IU?r:nm-v*ܱcGfmEzu xniһwoCmIe vd$g\[pq_әѶtynj+w!`!PVO},儰r98Wn-^'ݺ4 dbiڸ,*Z*͛m[~4jԨŠRRftWƌ&j*u.n /Vj0ΩSuqId5@G8|mۖ׵ą&b~WI(JQkmY<=z0{vdiI0̅EG)nip\{ ӕJډ9NLmA&?:#F!`!`XQQQ}/S.իII]ueذI4 NXŋvы:u,@t<ȟpW3VS:L<ָqcg2d;/+2e zSVQu ڸĨ;O&E`ۻʟk9NLm(\pA)R*0 C0 C yQQkժj٠~iX7d[I_~4ܢl&koK>FXH4sL@1c`ᦳV\a~a1*?#8Ȅ>9Lĵ't&Zy܃t<eN;%+..N LuG4mT}Q7s28L|y5-,Y:OtɬeG]\[pvɯD F!`!`)osK٪A=iܰ7kujKDٲT]pxJK.H8Ri3<|ċQX\;4U&u!b'LsD\r&Pqڵ&zCvɅ?(U {|Lr3/H94i$׮hė/Kmc)ro3ɜI$mAW_Bw2ed!`@y(,e$Q&ڢa]ʕkd¸YvJ^@,X#\{NJw} B0%I:jϲpP(us}x'!\K( ,Dɇ'/('<܄!^ꢣ'ٖmg&LhPEp%ȜNβˤ!`@~;rEcDCRNwЕE˒< SƬB{l%)o풛!!`T%LJa@^ T.ZkTQ,0-o풛;'!`T%Մ Ao'$!Q}8b5 as=kX*:o[krCXAڥS;0 @^~&?гE4,1Qz!`F5 657vG` M]ʋYjLe5Cl CQȠcǿ0[|y*MΊw!_}UVyʛ{993Dl&mӥ!|꧟~\Q ,NX2;3 ]'9Iͪw[|UyUɓsi.x~/w+7ps?L2?UiU J 6 E#X(9xeƌ1r{ޒ[?| Xydb7|3ٔMڌ\|K|@+2^˜1qO>̜93U;kp/dD1?ٳ{ªruʏ/ilҥ[c,mvɦ>el:IW^ysIz]mspwMz-3s.eiKcUP豎в@g@sޓ=zH׮]]0QFIT>'ttVO|(DW_}̚5ˍR'̤\k%cR44 @tt /P: 袋W_դyiC'|YR&e$(Β@5B /~^=|KdE.M&va}/~'O6M{K>}JIeƺ7t6iD.T8^{59#'pX뮻'xBvegL1 vv-Zvǧ&\(^rg'Ùgɩ\2^+&GՅ$#Q(tuE0FK/kQ6n;`R*;e#\` ǔܺhΝ;Xi+dL{n">GuK\A LigpFI{ ُ9qmop?r݊mӦ*`h Ur:uILT_|L0A2#% W~:+}?kYqСCQ(4Tؾ/)]k$a:*x2|p'/#bȑꌵ ?0UOvfc ˠOQIU?:X;L"s`yh(;vtVVUc3ݻ!:ɜIθ㾦3K'B>:<7[mU:|CIcwcm ٻߡ\W>l>h׮˫׸4v+42yᛏ:+,O<_2*IڎtyF>vX6Q+, CB />qsp`zY[Nui*ȼҴqYTT7۶X +JJXΔƌ([jbXڰRiwNSO"A@>IU fM۶mS׵ą&b~WE@)^z--K]GT9G&r3GI0Q2E<(V_kӥ8XmFqxr5m (MƍV`ذanRGxG㎩cI{w'zgxqk?Ex`e|Kuõ裏J,X*`I {E<}%CCTb煈 HiQ2erYx|]Jڿ8tu;]PW IS[S p hN: SX >xqap vh+m21Tz,`2d`=⧮@qy.L]o'9U dNJ锇l0cL{c5'g` .p)NT~ܢ0XO(>%%h^;3レĶ RO-G&! >裮?2s28L|y5- G)N8쨶k ?3J@~%:0jsz0{ؿ/avyӆ܏V|yoZ1JL ,<5\d b ׮D2%:ZZac&0 @~*osK٪A=iܰ7kujKDٲ&~ rU#(VO1k&bya r%,Lp^#߄Id3gōK97t<?]&%#O  oT]J3!!bZdÊ&M q^rpM{1eUm&3ə-żP!]:(FUᇫv O=:U WI-D"JGyC qyA3qɓ5(G1_q‚DhF⢈gmo!`UY>|hːV\#͒VJu@ȂųmgA Q@-Z3)aGJ"M.J&|e㍒嗏HyjmɖPL j.(qHZ+tP6:$ $iȜNp[a[`[33" A2upmiYĕk0{0%܉% #CHa>QnjWcipMzz3{yhldha<@llK>|0qo: p ?ٔci M@'?w't ;N='D%ak _*TuSn1Yp PJ.3*➄Q=X̱Cُ^Y}fM܄*%ŗ%L6e!:kQ+Dtr-X&EmJ"8J?K`OGU)*K]ypn8V7M^Cr0d5 ?LjOFpӁCI< WeZYA\!rcUBgwJ1QUQ."Vd;,t3⚵KBɮ]j C:!s3|2t?dEˠTtV^ȵ P%2BnD҉g*eQLXdB'ٵ|K-!`T'W'LVC0~VkIJ*.fnRn\Kn2.!P0*byAMpjۼV"vf`:H]!\Kv[jC_Zd4 r!h6`B7/*W!@f][ek"!%7RCJE' !>ʆ×H12 C JIͧ"okMխΆ!PEg# =[ "\D%*+V!`!`!) EPQQP|T;Bga{NV<2y%H6e6I>O?M]rSVNM_i!`@ yQ)S-°،dD2%g̘Q"[rw+ a^,ofO6e6c1_|Ev&rm߮hu+D+0 C065bbǥBǒ>(?D\dχv|_N%?qϞ=OvM&￿駟.})'93tPիW*\×\rI*GLyNN8AVXu]Od839rzuˊQu! +*7.v1b;΄hժU)L.G}3m$qoxorUWIQQP͛˽ޛ*:%M=JG ^wm7hРv0 C0 xcG駟d͚5;2HF/HJ/2;NZl)(7xOƏ͞=)hw <؝c"iQ@/O.n-\s9NqG1G.R(ʬYRQHx饗^s5m P^%xGՅ$C)tq6ܹKsI'N"}ʄ(P{XGu"+:v=@\~r=m(De˴ϊ!crWʾ+> 3ek!`!`"JEW ?νgHFkeeZ2wA-Y'-v]| 0a~ZcW\!}u?SjL2"Ek{迋/)\>l7#aeEuȑr |n>_WRRܺuk(^k꺿.~tQi)( 6t7#s`yh'| ;vtf9k/X!F({v8EFbXJiӦ2xVZޙһtN=T)..vF0 C0 k+}rBXo+X^n]u2oa4m@-Ͷ-QVlԨQ 0P%1c8סVZ-V\(ab5I:u$2ddR&8`ߴmVw[%.D0+"tP`۲EyD3zha"*К6j͇%#%+* w@9$-  O8CϏ0 C0 eŷ.*^-Z+ֈ]J^֭/_I6lwH:`'ŋSJ=N: {XKǃ Q}LIݵle:uWcܸqc7yȐ!w<.}uF@LȒ%KRJqy]NEyG;aҹd XPC<[:f!`!Pȋ?.`Ƃޠ~iX7d[I_~4ܢl&koKҊ>8J!+2c)(w{.<%n='-nTFJ"ȋIL.]_|܃t<eyvKHEᓩ.XQq q./I`9QJ&;t"Cናd놀!`!`Tg ~\Bpcn疲UzҸa#)(n {ԖFue)qxIK.H8Ri3<ċV\;4"y|D&&bC(7qr dn׮0,D"NnGQ02.DaB0mCĞ-Z3/_xd4ikW4HaKڗ^zå6}ǜPo[C0 C0jeuC *$QtQ°o`YvJ^$,XQ+zcHز F<1BÈ 1iPF!`TEч1{7= ʰSd2U ;ù>Gcǎuϔ>WE zz#<"ɵ焵GI\AB5i^GV -/ ^_W:wiQه{µpbz>8xEه/\k0 NW=ɶl;3`BGQ{(*3 C0 C"s%]D=(_tP*)Qy7:>|qYrz52ʋv!/=/d![r#*釃h9d.ʫt[kctiT6TMNC!Q?Aճ&&UR_ÄTcvSmUwқ)N[[M |,!dT4 ( СR5!Pȋ? db⮆ >p@*c$E@?j-P JX=3)KKg@ w*}g;-  1 E'. =[zH_* Ǽ ! 3s?ϳ+WO?TgM!`Tqx';JWB~gxǂϢB,AluWqn\V(ba_~Y^{E`%޲ʷqMIWnOł mEIʸόel뭷v|a-3Eg-~G!$.^e#LnuXN>s;I(ux9RG üyoĉnA$2Ӱ_Vqf1aÆ6`iH>{・}2sL->~pSLB!|0u^_1cƸuDN:$wS> q/\zn ;~$-XmuHבiwJ/_Vtr׵`;xFl1bQ?L!Ts׮]ݻp+T,<>|Y-<ڙH|tb% C (Ǚ~U ]yO+c.R&e[3, a^1VlMڴ&/*UnB3ïG2`9 WWE{dƌ{ 'X{uY{iEz~a~?r-N?rW?O˖-s< UCӑaUb\ +.q㎡G?es 3<Ω #رz4ӉEP=P_-Z:g(Ma8G^0n\=(pv HOgϞry;^{ν(S?>(;h6¿;H~oW賦ϡ*z.[]QWYU^[#+0/UPW ?jsJRרQRX^? Bay@c;Ni8Ǐg.bw#GʓO>){NZyrm9E-%O){駝e\رqnXrGQXtt+Z%M}F= FUWf?J3#wX}gH<۟kk鼴nZE9,>}t7NEcE@}U8+-q&9ò<|ʂ#**% N^c[C86j9, %?D\;wvaέ%w?c:iӦ C۸#~ҧOy4ox;tPիSZo,{%Ʉ 7\1b.y'pV x_kF:SO>!920zitbT]+hP&F(L(&O=i3|stk'\j6;@b10~xw d%{nH_F$P7zhǗ2<}*l3-`އ^~RmٮhW~[-W-s=fʾ{!Pțϋޚ5kecg3ena_(c'̑KF!;)(7xՏٳr4x`}ex?LV;xcdhߖz& ֳ:u4>sS9as PqP 5iŚO_Ս i4*QZGZڨsB\P92aGEaB9A娣r|!`F\~]d Bޤi}VZɻN}GCFjxV>3Kȷ~9B?2_uw1 :wyueU>c-С}3BA|:<mOs+}ۤr ) F %F5T~Vc{E;! [q>Ry@#Sr~@2Xh,~X]K.(%EՑ4>}2aࠤ`-Ǻ[{204>X{!:tprȃ8hРRXC#8ĢdB>}pGXGQŅoK:?ЍR8F?KK7b:p )^& /~T9mڴq >A($D˦mu%a\{aWsh-E,Xo$iQzp S/OGN lO畎"S;;gP~Ku\cԃv&l_TzF( :(좼1bUFL(Hqp?_a~Deq$x5@IDAT]8AF5sC1sz{:R_Xx@a98Wn-^'ݺ4 dbiڸ,*Z*͛m[XPp 㢡-P80&%&=b?|JI$2>Q` P~Ӷmq Vk&¯[)^z--K]GT9$`1RZFm`Pt0ҧ$GCE_E&\wzP,^XSOc_z饔Wp/ 8eޢjիee.&I~+8VF#UpI,vY&/ 3.XPle:ukKRC Ic :7m\ԝ']~+~%%6퍕w%-/=ʳE0IGLfG>"0jEc=Uv\?6L|y]Z|ܠ<㊓2+c t~L8?#GDGa<(+NuxFƏ]vmZ>zx˚;^Mg4<;t& ]c\Ծs-~'_em9-șo4_8gU2*Z"XQ!t^l5j̜>NVDj,2JL Gڲ!| ;3E);x9kt(XWEw "`8J#ȑ#ml,L%M6B?m." rJPQ2/c&;qAyFI $p rM7Y8y\hG}aKZ\=PES..CGM}Ld& L}9}L9ǖ9&7< s9׿"~,Q+#i{.R;%{y3Ҧ'/-w? 3Lm64ʌ{ǖg8=5oeHT7jf?E5$I,|\KyfyRki#2~pijcN&_QE4sX&)J&Q\)puAqC煜$VHB6AʅLsDsϽ<؇6EϽ&]T^=*mgscǥwU3"P(IhB^ / 8e2/1<|/W4DC] WD?;P^>_])ԗusI ?O(.Ÿ !Cߝs[g(U+T4>ŀw~+X)UI>(CxwW)][ʇŽ2i~lßJ"G}~⺿]>*@A@|U-TE">aşNw[U}"~)n}\\}uu飮9E@XErmTZRPWPi Nw3 ~.~ˏ^KE*! Uj E@>IkY)gw}~C9O8J..WϢb((,E}|[1Ꭸ>;sAL%UV N]"hPqi eKE@P (D@gR?csW&P."("(@UA`yJT7sL+V%_sSĬsq'ʨF\K4eǥ!|_\Yf ;alD5j]-φʺ 4A СC^+SWyߎŋH[Ft\`;iSlOEI.+#M(U(YYƞ7H]Q??Rg{GKB\| .Yeʫ06aYYMzwno')s|ꩧV[me:H^\?_W .n9W~o=|(ChHwݝOΥOe1Gya|ꚶ4=\w}[nwGfOc>[nQ" ѓ"P(KsA 5W  ?W*tE:uTaa^ V[|AA /]v*s̱nN;EV⪫֭[kC=T>`ʐ+(znDk/"O>50j+ypOfMgVڎQGyDn%\"leMW&(@B(~^=|gG#ʐam$p%g}dWM7Tfcx=#8žghe=XѣG<̡wyGsOY`o,]{&ӫ*CɸZ_^x xe„  6*o,ZQQPz7-k\ve2i${OlRL1)m믿^v[iѢgf8裭7:*`C;Nt6mC? {2NW=:(=BrW믿n??í5/F 7kV ?;vbgsFz)W\q0zųr)we\'puYVvr7;n0!~=OQۋ?L.-X`ܓ~a"&\kJXUW~>mvmrnenJ{UF!͚50 ~(2mr"TcGC //&L7FʘqӤ˕F9$?^hBA;31@Q$-/l'Nyq{zkJ>(({(ȅRA%}Ik/Ҁ12^p>|J׫LvEu! P1;1?F[oMχb8Jĥa{>.￿+:v=@\|r mQi7pCqoF9 fرV_ǿmۦG u]N?H'*3({ !#"=Sr-i@fmd-.{oy饗l?sbPy;2Z%em @P,wu|2yd[_O?*uuޑN]yxDžev Q(7 ޟ|[WרtÄ+W.*ޱtH]<tN9cEC1`,saf6]&(@C( ?(; ?ǒiԸ4jLQ[.%/Ζ#{=, /H>jXq|' ﯿo6[:1nL:ƥ ;V]ad/s2z#SZg+.oں2!cPk쨦?t.nE!P ?/)}2q yLk܅K̗wj/]vn/[m\jhh[P8P`tkSD9%/_a!>bJ҄h!p8W ;狕+ X9W ?]},XLj̀ewI#..X ^0IVl{xPX|d|餦!'klϢwU&,\,I+'Q{fXU1g1;Cw^˻8G(ǾU#dp|G]mR#Iܸa|sK߽+p)ϻ4n";K )" H"Oڄ ˗TW_&:08+:ơ'fwFLq~wm6]Qj@Q~^nfJIC?gԫ@~<(*~ԔҳG٨&QfDMp\; n^jB8L/ )1QE "5ud#>|p-ryq<y73M (|(~f#>XEafėץyԩ_4.XUKJ #R`r^/ |!|g##1'I(t:ӧM:tϬgUōL%HΊcB'I3y3\m F &Ft'M*ɷo?b.c,لd.aPڳ)a>nnyǥ3uGfy>}Cjvie(ܟ(L'՗ wxLEz<?޽|k2@qOpҦE)@5D('c 60/(;5*9rTߗ}%' rt{ŋK#0nQNm?90tFA2s̎quХKTKMc^܁yg'0CY^q8}Y{-L}#0<0f~@`^6u5K3~9FIE3V|0#ӹqX`>F vYBQ|F 8OJFL2l6=mm y%t}>w6}#zE Le#48M<(E 4a330fό8#@BSey,Xo޼2RtZj& dҺǞL哋2aa8i k 2ӺUM(r5aT,jF\Ġ\c`]>h;vU !CqubD9iy3i!q]+Ɩhi>̹bO0Yz ]\awOgwܳl:"+Q ~`śg<0p՝9.%XӋEǦS%X+_E@PVuHܾ7}ݖo$Kgz9%(PP v˺fXфF7\auǶ>9&7)X>C٧$P11BPZ3,&LC(_qu6 -w\0(WY.m+6ItbR㰎gk-+xSl>f&%E@P@~>Ɵ?!@#t%t<:+| (UPTru("P(Ob"V0t+|-Wn2\("(A(Qz#rUE@PE@P\P?W4"("("Hr錻 j,-VPE@PE@kEg,;w]=>c;9u("("(1Ьb~Bs9-J=r:!8&JVPE@PE@P` m ka8x㉊Y}yzaϬI]⟽;_-~A^ fE1q'fUT a^^1KS\ |_IYYf ;alVfl[XTmijE@PE@~vmL#3yUcH0W,H?WZ&os=J,V¼XJ%rIXh/];%r]yUy&~],]&z'͛7Zj%W^ye+/RawQX koٿ\nSO:t^zK㟀"("87zX|@ڵ˜+^{Ot":u`a^ V]Xwޱ޽{ە}4U:C䣏>=Sh{ƒ:H|Ɉr>Gmڴ|sQG]s"("P "Rp2~Y93lp#9*_X2~Ǿ85~ܩL zIKUQt(`f-l4iӡkFg:4U]wՎ@]~J%HLڴ0Q7p@' >13Ji:VViFw6h#yg˔}u]g珄2́G;}_@4|x Lg˾_FK3l׳<_gRRE@(EGyG9!,'dzFĜt.Z*t\G-!c',u5Iec=Z4iRFae+.ppdOɉi{n<(aBard,v7Ln 2Q:fҗ׵̅0P:Qzkm>uq<1na"7DQLcͷ(:J>i/&:2w=mZ\Pxqe1[Cx:t„j\x^B(#Ȍ2.=S1h%݌\tExDM~e:{Sl<]ϧB1#3裏hE@PNS Ƞ<98iWcf6{\N]tk(>OgyƦu(dz DGb,IΰpQO߾Ik5F.RM7dYo5;ש$3e͜7+" P4BHƍYI.5֖& Ӡ~׉ (7,Iݺu+֝C kn:X1b0a9弋|iȑcdž l!dn߾ -_u"ޮ];;1#*;፪Ygec6D8Q[ L(5?dė( å6}ǭP+?-f2{+DOM8/<&u꟦Id^ڌ2F8FpzWB3X((XM[,f⺵37kx9&&l򁄰wqJߕ¿Fo65I&d1dEORWMDlFvsx m!__0>~`vrQGYw!ڄ9r-%,'aeL$,/O܎pw7$ÿP\ҢϷcA6lEQYq/x+oF^Ov1ӹpztUmm9u p0aw yr-D~}HE]ϹvD&/σ}~aD,{w }\p̨!#tj%Bw;?ȽSE`B`\J3|ϰ?Jk>dnYW7㦛5̇lݱQk%Jmˌk-Ǹ`1ٳg%w$]ÖKCKĹ1W7zk9NYJ/Lp튢J_s>fETTδ_IWtD \ Сҍr;=w!/%.5؎1ޥOT%_uF8y5,;:r䌒<ǏY ½ǭÁ<Ͱ!B @A: 3w-/IfF ,1M "(wAK ܏# $/^۶7m!1`b2nY(GksI<(X$K'ܲgD ZF'7 LөCDzN]\eP) IȉZFQ BϨp/Õ!B gn "8ZP%KXxGd ª;u(5 lU "P"c @!CcT-?BO=V|FF|׳l.·4(1]O>8J7 W/EoHG`E^ `{I.]B:*nex JuFDLǙ  wx#0B5}tyg2 *S쥗^O6ͣ("()(KEK ?1U h$:j(bId9{VKtʓGaO:Tvi'ac=.qywyGsO9×U2;Ll2ꫲ~Y!b!31Q֞x x3fgذavJaJqk#r:f|M7/2xuauJ믗m.t'[77(_ltE窫*s̪9={vf'w. } =+vƍeq$AD~$|uE@PE@0yf`]#駟1x>\ts]Q"e0~2{`\dFiꚁQ'sfIO ?0:"1G1Jvm";sSOeEqA٨U5QzVWJ.sfI cdIRRDjBcrEi5VGa_"xrO?݆,M'&c45F&܊"Q:vh'b&^$l}іEЇQ$l\olf =DN]|Ȇ/K{w '\qҴ+P[u.Efއl,cӸe&_b.rq[sҼCIeQekkrS>"j#P4Xp?I&RcQc]jb׭-MɧAKs9GpS#B'~w n:XqP.S.+2wo%Niȑu {97t<}Bԝ|7Di׮@4d(|Yge6Diݺu"uG&Ӯhc _^ҚIJ0m[\!W~[:x! a- Gφ +u 3G,*B*垟\xQo:Ǽ =\YWvyԋaD7Pgpln4*SE0VhiGX_uŏ"p?p 0OFa0Lq|p|Dn.]GLZJcc>2B+(a8=q<~YsE@(&WecE)X(¢(ښXyYCY~Ey=X!{q_#4c QbUoxT߿ 2ZI<}"O8JqAZU !LCJ`n2QYї-*/!og}VX%EγqK tpb"0#֘E@(&ˉDpü* o9[Q֝bVZy+@B!VsL uK&’:3^,.wC.<]זUw=\ᛆ\޴e皎Sqi"TY4 ^|lp 隌c&uw^"g#⽣c 'FÊf.<|Q|5F AVᛆ\BŃZڨsY x9E@P @/KÂ%"fȓ+Ltf+߷2\+CC(:6[I J qAUnLZuŋѣ3QX+ZV'&_ي3_Y4"(@a(ڤ]y~>H)+)V,0*KW"2y[oX\%mbY.vKVYxrSO>:a1WJ_HeIP nE@PVE;7zX|~܊rKf5.]4*Ja^ 7Z25@1+Sb&$R%E@PE@(E1cw}&1SeȰY]zF%쳏@ahb"|e<.ox3{5xcA/ Q6^}UCC9$~yy'q, ?.>L>'puuG(I |">wT4n huVTf#dcM( ?鷑 $Lt.p6{mloZ& w}bSڴʌ-#HNRIF5Jj$a6mڄ/"("~(&OobK?S?ϼ^nx.᷃}? ] fRZ`^Z^F KP`L(́ ?;0998r T#<ɟF wI5Fi jxAJY=0m۶̙z衁 f5#!3QiӦ}d}y&BF8MG70qW&lqu!Q>,kY&833#0tp2q=-&uE$m&NyBW^y%OfUР_~p{J6=Iuxe+7HS6Qs-K. LD] LtH޻`oF61IsYq8"("7o_Q\z`w~{YQR0c]PKF_$.k/'.>, ?h 1ʳFeO?]Z?3K 3>Xqau#t]n6;qOG |!d"Advav5SN9Ŏn,>^ (v)za‘_WrϏt: W帺asUQtQ6b-"( &ht(tr2-cY >#*#P_~]3gδ#1n4iN(lh.nZw8Jz^X4}'_^_~9<*SE@P!PX..T0KRc2)]Tv鸎,[ZCNX$4k,'M-*S"xWXۂ-Z]ꫯ`VyLK{uA1+E:r1 /]FwAIɯ>jL򗮏WS+abS]ڨmL\>Vhݦi͛gp;K6MQ?d ?\aRIFҵpGɞ+rE1J"("Pf؉f" ^{o*KՐ~$Ԑ~ L-sʔ)% ?8eX+&/'+#ݫWZ2 2$*(eroa}dz %6l#,Nz)XEŸXXLfn@6rN.6KIVl{cw=K{Eɑ빊ntFI&=Iײø+2â"J"("P2iE۹`WI\4\, ̒zȏǘ ~Ԕҳjc"R D 9˥ #~u,dBOL Rj/E 2K$&g;ډ;I>(DBb w( `zs'&ۊ/a]z$0Mҟ _^;ﴝ:OLN^dzenNrkwm<Kdp::늀"("@~KnXsoF6n$JHEv_4iH$g\?^xsΑnݺg~w}CbC(}) *]r id9r] :,(6:ܾ}{!:J>Dkc휆lad%=.,uWڶ!by%, < 3۶?fė/Km[\!W~4H|Vnҳt϶ͅ9Ѫ))"(@a,yeI((aXo<3RtZ8I2~pijcN& M2/<}Ʉ_h }&2IiYeCf䡢.80L4X^ĊN\]PRi7! _0'\!q|]+62+n%[IFҵ8+qϲF\Wy1 d#:LWRE@P F>裒^{N J i?CMV^e]?߸[n>5P6Q'?{µp1z1l2BkT0 |ōZN\0(=7sYvC֨rki^it"("[)slDtP*ɤqA ]%-?ІRR2UR"l$]K^*£ o%޿u,pgpad #,f͏2QҖx=q# [FEƏoGh$}Z4=-qTR@EEϊ 2UvZ" g#Z*&Q!x-KeG5Cn&nI;*mOZYc#yxɣx݋|rͥ,Foƪ&V"'PC=XTt̫ath|Aы"B(K ("P` &O>i|ypŠJ@glΤI߬)%Ҭ~ml}y%"PP*ʤ($nîͼ("ztLYm\/V_}u9ꨣʭ7l }o5И|W>#~w馛UW]eg<*9l&SO=e1I}uaTѥKk'=ԛp.:uQذjeK^ج:"`*QRO\Uu\\9Xi7$ifoֶN;d;=:m(^fڵ^u9s.M:ܤ'?veyU30"P(JX0*f͕+n~Vy-_cE@PVyPqA%q~L,VŅ^hCtr-VyDq'ZVaEG EɄ-X}P˺I>*^_㎳J".<p@.X.amU2xp D٩+Vj"AD n/xrK{ΖRT"N !"0!W\aז!k_ucT38C^(V?GG#Ou(+ESǍg?dlsEFeE?XwE@XCJ&X!۶m[;}Uޓkr dPtM:bg$"43,k` : _$Y׃0de0K/.$ܓ|Y(N,>[9,IAs#"g7_ߎOhUqNIPVkeR_~m֒~%j֖zuj~#&O?)36ZH?ii2"RB\8 _QU܄P4Är%=mʞD5,Qp%]9Vp5'{X\9ի?<(QW',;e#d cL}OU!ߦʐAP"Rr-\&M df2fs"e\*fԔfl S)`ɹ0`B-WRa駟7ްֻF\%m`C)qTYt[NKOwUK:sϱ$jtv(\3f'#c*̊D<[d>#̨-rMaS.4vXzI'$\p ߯{.y1ځ坑(V[meۍԑE2 sܯ2;99mRRX}kr0cjd,QtԬ5PHm]Q Gu+V'|`+ "_}~vȔ( {iO.u%m\yi3lprVl*7l9 8'3.. q" 1QzPdAT\Gs`=C?|kǥ<¾Xc?.6Le @ID^}Ä(J*:,+K=8’ݭ[7$[g(Å.:ܾ_\k&gyuAq:C9>Eecu`sWGܳ>kFwyv4nO~0Jg裏ma%E@Xy([>RF)u֗1f"qLԐ%5~[KpMFAb1hs"2y-X*k/fX\%m\Zr"[TVXӂvm+pSA>ܛ(X<L 35}8\EEV ->njO:&RNҼᠣ"[J`\a7nNN>b9Er;uTk|<8NI /w5T5GG>Z]TE`eBȂ/#d؈pRiѲ̘9O-X,kQC>hwIMti:q3BЮ\`i|H.]'Ua뭷L:eڴio /o,QXk0)*XH~C oqah쳏eM&W&laiC fb'ʅODJՇhL"X Sn\$/#sgybzXIIPE"PP([Cn&L)Hzu\㏱nudy2(.J& ˡb',OIJ5lg=(AD@Y4DKE}gvXS&Qܱ3&a5Cy}P݈ýXU _$^.(ǵz֮];+9sO,#M9QxcT>Dpa=K`:y-||i EQge("Tc9qH.6˯}, 64n;KVPW~m=A-]&5k6IcIuL$Ʋ.#KWX sޑ?\$kS9LX942Ql^PQΙT/s~]]-n)iR宅*6J;ԞWRBmҴ0G)9qx)' 4u1nN2^~DXè6wuFw!sOO\="("T F@Ss+JДoWIbE@PVN 2i7j JPE@PE@X7oՃBk("("|ԎS^5RE@PE@PVMjGMKKN>#M>M"vrtUm]*/E@PE@PrE / ?>YYQ\aB7o^&Mx+E@PE@PVR`2+G/uўZ E@PE@(yMu1 'rR*NB8APE@PV. FPE@PE@ʟ'NTp_JդZE@PE@(Zk nn><4"PHV[m5TR;K/jpҤI^%_PE`#P;E@j۶L2Er挞f($.,'>e>s!Q^u]WƌDÆ eM6nAu9_̝Gm_Gɓ{7߼p)oE@P^lYd4jH+)U| .C 6m7|#:Ȇ"nѢE_~EѣG E@PV<5Q=VguV n6MDדO>Y[o=aΝ;loȑ˚k)m~6͛ois{1po.C㏷6,.ߓO>)njʎVL0As|ꩧZAiy>Ӳ[.rYdgdxtIn|'rFm$͛7]v%ӱ"(@`1WƊ"A׬HX!½/]T{ok?sw!2#w}?PfΜi]\x:K8vy .  3;SVYZlɇkǏZ G}T6l3> [o1yލxrt+?K⺣("Pj6("(XqIAyiӦ;Xe}ҽ{w[}?`{撠׭[ZQv'_!"H}ݲ6H:uK@Hp mᅲ+B.[.>*dknGC#J7(znM褼k3B]f̘Q]o[Pj@myE@Ry` v `Ň*]v߸q2>WQ( t2CAq؋c( 4nNٳqD.h׷$K6xcP=s]ˢE@(. ,]PA7.6[nUqC)۸_ƸߠLCFXQqY}#ӥ9M(n%j7>·sq<)"F  Ŋy >ME@PUPΊ"T;O'gϞSOɮjxYgsɹ . ,}=P뻏<w;t _~eXڱlwv,-({!I0)7W*N:N<`cǎAY|Ǖ~7Ґ^PE 7R+DPRV :T=zQly93EwryI~1ZnmXz O>֏ks ʺG\\dəP(8>1I(=D*XNk?E@P"Pcv-,Y!﮻sUqЊU({wT%Gvf| s<2@j2rLPJMPFjɦ.m-0k_c7˪!,]LJk,KɢZ'~YQr0.DZ0B"1T,m u_,XiWIPE@XGYNO=_F-*l]')_pdyQ=\2UvزtjFuR`4[pL:OzZߡU8~8cը՚M_&e|PY%ơG~6T  cG 0yTaW |ŒE'V⨣[nM>Lo_Z.#&Γ$<~\r{r3m@E@PE@X%IᏲrn&d6ɋ̤E(ݳ5!mtQ|{^*,2fs6uNZfڍj-s//S^6+]KS>~69{/3JHe {2o:A#k\pf"\NMicoz[/3r,i0 #SʁOBV%b PXԇ85jG`:}b|sWnE@PE@5-L5kFw.Z7ߦ,u/8Y7di,uSy2y|c5fmkՐ6FruƢ/4]]_ڤ 3Cvj#?9ZʡlI3U6ݬ:̫;Zf \#ײzvMϒ}]zC9}mrk˴_ʬ%,fιiIt]Zٯr0oeN6bww2/5V/#͚5+Scz3Fn]*O_Cj0E@PE@PVB ٤QR UP M̤ě?q)Yl~\d΂R?u8a[e덚˸i eef-N&2ZS8{ W\~}?eRH}BˌEΖ:R׬YSƏa&7ěcyJ,1Lre'Hdi`&lBKzu䜳ΰSX͚1]N;L[㎳dF?勇NVs3O#"("(E`DSP?~x !6em֓ƪsa7nPG6nX.:tĭd[dV䧩R⮓TxuR~e lbayg؟H%ҸIS)1QzJn2{ K튧ͳ}'_?wt.APyE@PE@Tҋ>dm&-)cxgw ;Zei-q'/-]&7LF˕a9z:#ujk MG!dv4FM1+\6?,km(% ;5/wI=ls!;~.#Myg{w${*Gcou/u.ckWK׭(7 /[}2uܹ U̚)K)g(O~E8or>Bu2"("(8 j?VmXy36Z"k Kvgr\Y|cF‹/8+?QQ{lӮU7_wsiXU#&Ε{ SVZXt٢3 R(~.mzujm֒%d%Ҽy2sw"gKOf4b鯵z#yR`x2icRk_}rg~pA ֒[NFZHxLj*5c5o @ԙ wdm;Nn*}3a9\ctה)Ye-+@eY$˱fᤢӵ)wXMtߦoO>Yׯҭ"("(*9)(Qʐ'Nɫ?N&m9&De)snx3d͍Xkwn&vJ] ~pfQK%夨K|mjP5T_`x rKw%;-o.\OZ5Z5X&XӔ7,X̞.K e6KFG~!L'25kw-5]i#S"Cx&m FSժzUӎ2i; VV_L5& %"mD)/NuՅ{sc}nX+TˎYpVŚ?/Z!## o^S7cFt!- ̙sjG]T   PjBH8" 9P.ej^qg)/BYiZԳL2+ FRqzVG@|0:nzl瞿e%EKxo*U210p!"MqH  QweeŅt/A|B a=5FB^?RWչ)4o޼Bbp9l=D>؞p 1\sgfѣGqc$7ǎ+ZzGoEDA@j~{ /8( za`=r iurZ{+8~.*q/R?Ga B38~&NX޽ Z76IEQ`S_-h2pJɠ_B\|O 6.IY]fq,d;[t2=pT9$Pa̘1zTD?+#g~ pTiw+  ?\gŹǗ."39In30ڮ^R^V~U:%/=5Es_O9YуM~FN^,ʄf.ͮx^^n?V`5[▥fN'z6xurUQ#ÚСC]g}e2f=;>+%d?9tAOG]FҤaP>Gtr ׫.]`ǎ_uDѩS'|w:nz63b{FDD8P||i&tQ7bٳZY5  Rn?='ť'ıe5{ =av4 :BEۅXyM86 gt*uy%i˃kf8ȑ#ؿ?l>}Z-uDž M.zjaaaӖkZl3j2ǁsNxݻ+cW*}~Ĭ.{qScwaX&;?7$gNoKCc4l0HSJ-;[͞ ?w[o 3;߅3fh՜iӦT|7:u6l;onٳm5!C ::1112e &Me$  1(\%wsڬػB[|:"2:gG?mt$k7d?w d5>u/f_~VҿtR]:M3H19s&}D#iii:֭[{`޼yٳ1aƅﱣqFAvc}qq@@  PXk\Uk܌@:8uj<; ^u;)G9GxXRSui<%j?_)SDē%tVpQ޽)cDU $2s6 ))IO7iDO"8# 8@csBkZhf)GQ>z^ONNy'$rK,AVVANF[ɽJޛL-4=u_~+WTLocժUXf tZ~+YC\XX=;gw2sT  NE?#[SΑT"zXo/?ɑLOFuL:h䉣iYzo:֧+L6 E%<wzb}p{S2zcCVGQBm۶M.v,F|µ>0G\!B>,"L~rr1XY]fq_wZ wGj<~MH ROY +㹘UAh9@*dӧOᅬm⣏>ҝ}jrw*T{* -ZfA1UYyu1OMDC /Mu$ f%jA?tdGHylGr{q>3e~UGr:# K.Ʃuza( zj*g/~kD_>BJ<6ƲxgX|9֮];r/צ+O  njL JIJF`Xz'Qtn7nCE$TGN{r'xyy,]u\%Gbb(ZViӦD4_^Uo dvoܛAyn\, 5A r;wN9^IϞ=;NyOpҊOhhimyqW  `%۫v(a;ո#YY .R!Q)u9um\Yq-qGh7 bϽ\h2=EFF"..NyN=7rb|?{Q}K'.Vqq`tԵrL֊ ><77>%2ۤ:ZSZ ۫qzK %W^A/2jjd{Ǚ[PP뭟 ª46AOƺ05w~OOG&qgai)X>k,p1kc"sGc?!xL*>J]!v@t YO2Sj)oX72[Ba̜^=s;b`,x-ܡmzKx!i0t9IUM1G+^STzFz'bxdCT{2q xORϴeX6lz&a{᣼x =g>()l>p1?o|`D'r*_Fp7yg~Ĵ^X{! C銘[քcnLxiݻ kc'd,Sd?#\YI;ӵVl}CT=ߠ;PƅX9/ qcSϠƤ=# 'KyD5z˭frO^ʑN"VIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/repository_xml/images/repository_settings.png0000644000175000017500000007327512346515436030275 0ustar felixfelixPNG  IHDRG(% AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATxU߭.RQ*{{_X11E1hԨXQ@ ]@zggw칻w޳3zw̼w9L99ܐcGZg9990p,+*__r ӯ/o&Y|T|u˴t˥\Co>3L?]k#Dzé<';_¼u3Z~C ;UXX8r\CKJJnv {B6tc'.-qqv]\cm݆ uMklvqg\84v֦l'U4nlvg\jZېSְj:f~e݆'۪O zW9EEE*++tzB=U*WfI_9˛oS*G^8x/8uǕ_?y]\?///9+WF6E#7LFM7Pl˚ /!-tml}0V>}?<tEx$1̺VP$9ۃ8r #-t ef[ٮʻѣor-[VጣX TCCeA9򢺙/Oyp<)!\eLySi Zu>ljZUUuRW2%7^U@Sx}D'՝1g=u7N/O~/$W%R|jV?yp5|1u*K,_ ԩSh獡;r\^oKֿBGOV|auY}K6..L)O?^1E9՗c48NikZ_Mŕ|q2.W8q2|paߤr<䓊m\őmOyq2qqE?M|&'up/ov΍rC/#c[nyV:um硶i ^Q՜VWod_.ͳ|u` v@kWfu]#.qi[k~6bMSA?ҋ|pQN>2?OQ?2:Q_\Z\|ӏ+¾K>W7?4v,zMŅYV|XIpq8&F0j+?XˆͤI0DXYC ?([kӦMPcAUO83>%*K0/eBz|gۢi8 tr~8Ƴh^Sy: ?u# a8ȟPW ֓r,+<XA_|:|Z9]ngrmؾLƍf-6Ժ<R_:b瞶uNwXw_(guNg cY?d>r[2mʹl96omʔ)6aAl⒳w̲_v}˝Vfs'M97;hq[O8n|1?C0Lci8 a_\2d08LgZxp er/aQ2cz88^ERO y: ?u#e3ϲ(F Ǵ8|:1|5,L s,Y.6cFZϺuA?/@OnV6>?a(nڏ !s>;uч,܌3+ppL ,[8qJ]Y\P/O|rMyȅ0v֕q(Pa:x3~q,W_e)Y2>>sx3~qh[S:p}cY;ijlh֮Cwc0ӡշml'Te0s/~eÇv w/ivygUcrȒѲ(xca|EE| ;|6dM[g,j[ m\ѱ<ϲ8Cyzok;=ܾ}as޷]UNuq{o;<8rmdg?9'Wy GTqQHsX yq^`qzBXW_ ,ʲϨiga|B=A9az؞02<)?lf<ǡ >`]k=n[t- \P,қ6kUy.X!#ndc̿^λ`^sӖv>rl'>\h9E5,u'?ElA#lny.Ⱦpx?_m~?mzϞ~N>t +tȑ_cO_hg- >ܵ-=Gr-cnSצk[iաuھJݭ<U6e=~t|lVJ6׬ݎز7߶NڡGcWlg跫0cH_+e{OV^ ]ϞQS)mi ?kc]=sgmXN\7uתv;XV"ؔn;YEo{ؑe}FMN9|+_mo?}ik;zmׯrDޫJ||1[%3??l郗gMx)_A&Q" yEc_|(Å28f^cua0>=8^t1[F)`810jm 4 d0tCXNBt:|ea943~x0 '|će1)<By2:P.,77%拖:񌣏LGic=nL e/*c=H i82t̋Pҙp0Ci8fS7 )<By2:Pe M_u%ʿ!(O-ə>r~ekц-启xxרZ kۏ+G;t7իh>@Sû[׍w揲h{<[5#=v-+*v/O lǏ+Wv猡2죢R r"'+6VX^^bJg̘WV\dKo/Lk{xP?;6(;z`{j=dg;!VXwKNU:}`єBٰssWi3!94۠l={Iv]}JmU2ֻٮڈNޱjk'_?|vq Op ~ yNlձ]#e]{w ;p.Vб~7}Ҿ;nu͝ccO[b'\aX۰hmFvAK^--[y{큧>{؉gmlKz^|qrֿmM}9{8c'kt-SC׿U ! `[=?SqA&GN(L t8FaH Ґ7cY} =ކ^%xc^tL,3'A8Lgc>h<"۸P,/̫xF1nje1Ә8Gr!S!.Wc9-/:$ʱد+…` qQنc'lk>ԉ͂<&!:Ճtbq 8ƅttt̋c0P.ԁcE<^|QYs:G}=;p18aèƼa耣5#rE\x ˋA0'f~rZ8'P^RlV+mUUɫAm`f-򼯰"ieV]:_vyyudYx_vYysr.r}Z9; y 鸅u/,r#`U6s2N kƘQLΡ:L%,vD-.xÖ,2WLE\Μwm䣕pq k0Zv[ph7 2 :>~ =!/ø5TO~¡: c"_Xo".1Cʣ^ȅz6 È ˃>֟,~\>! ⩃:֏2,l-dW_%y mR޽ q^\? @W'y.LE q8Fᠯx᏶u>G0JV9c"uVBڠM\ݎ@Zt3z^.kUZuk;{؎vİNm6>Nۻ6\uutӏr"֫S+3\Zur`RZZgwrvߴ1en׆pvp9.~)^Ϝgt.[3%ʊz>[\]Q:p}~|虶Cj#M{tjyzk^68p,X0urVą:e~z!YW|_8-p<\tg:0/e4Ci!t^waȅ!?d ?dG:6!aaz&#ʱ©+|#{2F3>u~ v[O ~pAYeK̲y>ʺ=hOqJ7p֧n}LnuY>\m !ޕ?|**ݥa[%_dϽ3&m>ϟtV}kGg|?F2W,+-4{ŏm¥l|6y-sUurP}qSf6(:ҍt^>fK/fwhN-eN9xlf7ʫ~L[^TdK~ӳ3FފN/i V]亸ys_UC*Z6(t6/K9]ZW&\Wb}ۚۀ*Iw<݁c6.<1匟l3fOf. l9󭬠uPFZMؗ 0tjA9򼯼~qHCeG?.>G:uG^Ƈk>eX♗dVW GvCeqǼʂ?qxMO9!]_'F< ~c}^o}׎˖- Y շx}tQ/UV5NT8aƅ>E:;WJWe:b(^c:|rP?⩋:X&|dL<⩃aç>yB g|8ԋ𼈆Q/>Q?}։Q"qt߸rɘmb:|}|tD'!ޱ^~3ܜyVi;;bkQwCvcZCP9 Ew?Sj8Gݪg߀F/bLE>aۀ]f?o_?q_>p۷U{mhn{Aav\75H g%5F|]yU 9nx8km6ֵy; 6_q#V]_T+wQ/fcl=ކjk6 Wj{̮ }&[n^^?mϓڻ/9mT1cpxp]k[usS1b߱uY^gnڂ__/u<[k0^Q}ϙ={Z>b8p"ܔΝ-]֡C޼`^6Ql,Ѕp]02QFuCҰNU?Gb!C}ÓaBӡi| emB77 -tCy!sy)rEy3/cS>Y?t ӣun?aa2Cә__-dF28ùqW R[=$k6p9r Ȉ[&:+mhP>ejڽ*q#&a> nb+rk Z9~M |7}ͭg)wӶ-"Vݴ4f yŞ~o ?XC7\ZVڍt0?b}؁je/p/č` wREԹwOB?Uq}rNyeN/`:pqڳn=ɶZtXA+禲yL]z99W| Un[P\^EZaW>%ifyak\w>X ?ܿ5yn'>fLza?=R~̭M2L<Rw}SxuT*VHʱ?x">y^̋<RYڱ15CѺR_Br rQǏ} y'?q2>^;la?Cy稣<|:ʱ?H1ٟz8e# 1қS̜9սQJ8ܜf h8Q'1> Q' , a#bGCǺg};u8=ԍByAwL0C`. }p;„8 pˋc1/S'aa:Ez}Nre1ldyt3/ ֏eRԋ8ևqHcaG:NyC >򳾈G9p{ Bd k ~dr xB8/c pʅ 0ucXgpԕ3}tf0#a>gEpLGyr,.QxfpNCzXOM1 |̃88 D18<ćʆeRX/Gpc G0?DZԩ+[H/ȑ}87C|L e2)|u^ntVZ`$4xnOihw7\rl|^WH0CXYAnCt -GLc?Gb8qE<alN+*S18?HS7ؖG*8έ8rCd笏ttɇzREyga8չi׾lt{ xnя 1 e51+Yo[l;#>tq6 ?\4O@GǴT>Dۅ88}D4k3!+ɋa?0L20OHL'?ADrW&!ø0=.<ވG٨Lg0 >~ub{ҩ[p믿n>=SVPPĝawۿm:ud^x{챾z=~8o}ǿ|K.裏M6s y!{.={K.ħm֮j;蠃k|]veb ߿s1`_y5_s{5*XD@D@Diz3^\cٳ >&Md˗/_Wv),}EEE^NC=4# gꘪ]䫯jx Xy>z| m[v0'Z/jlmR @[_atN 1>''0Q_Cae1nݺxqy/K;s1oۻ[5Z8PP6˜3[oy9vW}g>ݢ, lH@N 95Hc= hz|37Əogqx>k}ȏK]ꋖT_Xkο޺ꘪ]z ' .#G[o_zC_] q`՘I?ٖDFiŝ@x> v͆nXt7ڎ;chv{0B0tڷo_#^x?#JP#֧O?;':ծ;s`ΝP|0oCC+dad`]sh3ڎ6pVU,Fa_\\G0 7+" c#OmL{{xJea;y4E Q'.Xl9!"MND@D@Deq_uU6|BS1;rNV[z^Y0S0&S.Ufx}1aX_g ʑ9pر+g,ߘv lLRu'0,0wvq;`H .|bFyw gyYZdQLEC04EvY{SO=ϣŰ)6\`CVaN(۱ =cvl 9Ux{Gr" " " "0ͭ9^dجŋmڴi[6xAT-L)GX1,:,@ŇMhjI.nZZڇ]D@D@D@D S=km뿶OJÈx_n3f̰n-SdMǬ!/|/44>kZWɋ@ `P1%8‚8 豛7|c}}Qn#A0FR(iuv&~5G=pMv>M^#Hl?WGe<}Ja2eUzRMaDq>~yIq%Ɉ45'|վ?RI"V8_N?t~)kQڌ)LŗꚚGR9^" "}Lu^J5Ďt1'Nh? F?u'G}?F=Cl}oM=b!10t+?G`|BĆ]g}I뇑ɿvE5ei3fL"v[{W|ܹ?kڷ6~jA#y?'_SIk#" "0;,s9OeV\~+m [^SgW/pϔ R#kUq~_6GϽ[V[FyC`*[o*_U\-ׅۅ~-T`_o-: 5&Y6aޤ}5g 0 v/ְay`4 E?=-hCk;:ִlLKmv39n8s2>kWaeͲZ~w_찣N>ȊKo֜>쫺ˎm yZ˚q F+~+m-GuTݞ{cKS~.~J >uĪ 7oFc+/R"zkT4rC_AT0Bwa0a e c?T7\aeȣ~ruŏ0<@zC7F.vatI~ 5\ZaD۽Z]uLj%k+C5L F`a]Q]l|<8&al@2|pEիFƹ6{TC1Fp1>t.֭[7;j|*}6Ԙw 'Q7dQ3E@#Y9xٌ 8 y<,SѐͳlFPL0*\Ĺ.0Σ>Y}E@D@y1 TTTꌢחZV[1ڸwVVe5rԄ=)rf#Ax÷@u)LÃtszL5CRA#d` [D$x8 ab3 O?ݾ5TøѲ~q f` ĮJ?#=_>t@fu0b0RةS'_1oXw#| z3΋6mn0 \+aTb2tbd`+Fԝ6U&88Q2 \wj*?S;vGzu+Fs>}5R&&/6fEYXD@DyXx0>UC3.{~[.p3b ٯ.\v2c,{jmf6{b/kV״5m40]k &oSj馛z)LaC/vuxæFI81ElҤIU ^u},0S-l1 uS6ahl1-* EF NLoJ ݋|rmqZA~~]tyn/Yiv[x48Lm4*a:@Cax ÆYO2I9AiJ0vi6:b!&b- PϔX_]$xZ8TpN/t0RxA` F02q>}qy1ƨ¸Q[-'|RC/0҃k*F— 52fNdc>Fʄx!O^GCdG e:]𒲮rkڵmm۶ZFaL*5IDAT3z!y??:t YsyZKqֆ7 .`u0x]Bׯ_?PC$lumQT0 Ft9/je30m讻0z흱<`a `MWea_*kX-a7Li?O ~ac #RЁu#KdG3k֤tf:9akvNjjE#0umA_}&euf#16\NX )X㆑SO=j -F1.Y8xF1x  R]v$d<È0:QL ވcmMa*mV#C%41} ё 즇8qa;iq F:5 aZca{~b VC;΍n)F0ӥ:69n p,cK顏e0K7ܐ 3gi0$u\ јq6a%lFw ufP" " ".pĘ #mӮ;&<1gua(`fOYi}ۀ$gLfcAopM``dKtx@qv1a:ZpM0 kXuH5G4C~GQier*_R< F`xčLf={[n۲{{.]gEzeö>Fz)؉qX5G8z*Qu, θ9xma؄*_aTUINQH#>ky#);Dk ŷvD@D@D@D34pcM<> ,` vde%~Q1> :ݼK(T￿E-aYg*," >ҲV!l#.èB" " " -L+|:d mè17+ a4'<;]ϯ0 X[!̃ȉ4?8'ր vs ;a?ݘ&.LIa^ƏT $@3MKt5SaH.cJT!mDuXD@D@D@D@D Yqj mBu-([YK7ң''" " " " "l8J5*3q8iqu,t>ōT 0үxdhvQt+n`\xqsG2>EGF2a>P+'" " " " "м4;jOacw9s]wQ_ip>a)tprw_$ŋ$@2FmT'V#裏ql=zhzs0 |'G`{TɊH0fcin(-ZdvZ q._;1W?QkJTw-]4UE@D@D@D@D@LG\sMQb1b}w5@Yk+)SԈG=zԈyꫯ^{[lQ+|~iH>faat.8 {74h]|5pOu _}-YD\qQao ˜Qʠ@$88p=N9]&+,,?n8;agmni=QvmW+7p9MT@ Zb6Pҥ&v;cjmDL}k4:#lŊ5;wluvwꩧ2ڶmk/΍3Ʈꪸ$ʼn4#9 /mرcmm5cZkNjX#4{ZV6 t:d馛,ïXtk:]-ŠG Q~W_Ђ W." '4!F&Ǫ*[wcaaS|t;`W#<2֘б@ $8 Ǐ>}{Ú#D? 뭷]O;xh錪1MBWQQa?G }XS# P/FD@D@D@D@D@/D9f ?|{c "wFeluA^{m47,9tvwRm_PP?l0D@D@D@D@D@ZG0 fovМ9sQ7KJJ;x{~_N2$RKR~;0 i(," " " " -@֌#& 5a-??ފim]w?KI''̝;׎=X{뭷UÇuֈ裏TTt " " " " -@B;`{衇_77bz5N8-ˆӐ!CRFtߝ.c=G(,Y9J#󆱂]n>m6_~uHP0/uʌj;|' ;=S(^D@D@D@D@DHqnڌ3w-JyϞ=oO>ٰǪ?ޘ!r-ް~@6V"E@D@D@D@D@=DG0Hƌ`i¶1Quxu8Nҭw[ru]׿~ " " " " " ͗@"ݻ߅k6l3z^{ TKW_}s9w}iJG" " " " " -@6:wl'_K5m:ʆ7w8c瞋6hqh"{oხؘ3lD@D@D@D@D@DqnTwR5@" " " " " " 22AQ:D@D@D@D@D@=&3Znai嶯)3&dQǎG].ED@D@D@D@D@MɌ#`8Mj.0J4:&5.e]QI)mED@D@D@D@D@OI.((QF}gcƌI&Yiii)56h ;϶&?PS8B0=\ +d5I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$@~bjd=ܓqR(" " " " -@΂ *Zjvue]n." " " " ,\0-QƑ&Cac,hj!" " " " C@k432Y" " " " " C@QpVfF@Q30UWD@D@D@D@Dq8j*" " " " "8jfꊀ4GUZE@D@D@D@D@GͬT]! qJ@3# 㨙u+" " " " "8d5Wihfd5SuE@D@D@D@D@*" " " " " ͌fa@q8\UD@D@D@D@Dq:Lh2432Y" " " " " C qJG`޼y6c 3gX"LT۶mgϞ֧O޽{FZ/c5DcpO2%%9W_}el <غu2ZŸ~ɦLY=kk {zg)Rސ8j-ɊdԩSW^gToKSr5=3DiLsoH!$+" " "Qg϶fTgKVV`NFP+Sҙސ8j-ɊdҥKTR?Q (u0[[$VRRI̘=xju)5*Xρz)YD@D@D16y{x1]wu[L0˄O=)՗2c2,:fA? /nŋbMuifК)]D@D@DQ `Mc=vm?٦On\sMFہ:WVVQu)ɩ+AiIzX_zIM N8oO-¾{׿e:u=s [v2y]d{q.)ɉ4 hl+rs3;i꞊C&Xuo(w.9P_z*VO"wϓ'Ocڠ6]*?ӭ{f*9XMa {Q3fL ~adK/|mԨQU2u>묳쪫ʋ_v7ֈ[SN[:孏ܹsSn|ou՗N)I1je]f]vuzm;Bxސ"7H({tl~9X@b1p뭷_*-.(&~2%%9F!)> e)bCInLrm.vy W_:`}#Ȼh"{/,wm(/Su_孏ga+WFOjxfc>˔c׶Na!>}XϞ=NMò24Ձڢ8va[ZAANWɣM0걉àA }:v6XϷM7ݴF_ >QԹIX( Hh<ƹ?Pe5С ˗/#B?79<ڵkg뭷Z4x1]lĈC %wW,Nb6cF#soח({è9aGds0`@10;U,i7|saÆQΝ;{.gMLsO2%%9fAf<f t^)s5?_&‡#G#TGyd7Ћ"L㊺ң1>F?㎱0Sعb#ՃOh̴/ܯg ZBXQKEAD@D@D^kUC ˇ~X@MFtS>c;K.0UVar}m`N:կ!|郞taT}_g[+0(oϫ7X pº~ۖ,Yl°뮻Mf#1.a_1۷oߪvӚރ@ v0 ʏ12viwyw}PJ7rدk.]o^kX0BW_:6h]}ǔki> pl(_~"vuXk{;at]w7]g}iimڴ`S;Qx7}o*(" " "$vgf|Q:m <0;&4/L/rv95(ZV6x^paS)}֬Yl2?X 5E+Vڶm6:bZ>޽{4i3ɽ!An0С'`a8܅pSg`bJ-šg)'~71Zb  @1dc.2^pwvL ï~~ٜzU ـzh/L=)it_O2&)jĔݏJLb9Q:%Gt#@fGs?1PЅ48ң2q1nVuԿ&JXSszwh%@ {:uobҵ*cp1u$5x픶qq9>$Gc @b޶XE.$m1fq2sgYrG @@i^#@ @ + 9J#@ @tj @YQVJ @$GW @ HR @(- 9*ݽG @@V@rG @@iQ8 @8 @J HJw @ e @ PZ@rT{5 @(+% @ݫq @d$GY)q @^#@ @ + 9J#@ @bSG @m\/v @ @@0ZV[s"IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/repository_xml/index.html0000644000175000017500000000745412346515436024154 0ustar felixfelix Bundle User Documentation - repository_xml, v1.0.2
Bundle: repository_xml
Version 1.0.2

Repository XML

The Knopflerfish OSGi Repository XML bundle provides Repository services based on the contents of XML documents using the OSGi specified schema http://www.osgi.org/xmlns/repository/v1.0.0.

Description

The Knopflerfish OSGi Repository XML bundle creates Repository services that reflects the contents of XML documents following the OSGi specified schema: http://www.osgi.org/xmlns/repository/v1.0.0.

Configuration

The XML documents to parse and present as Repository services can be configured in several ways:

  • Using framework (system) properties.
  • Using CM configuration.
  • Using the org.knopflerfish.service.repository.XmlBackedRepositoryFactory registered by the bundle.

Configuration properties

The Repository XML bundle supports the following framework properties for configuration:

Name Description Value type Default value
org.knopflerfish.repository.xml.urls Comma separated list of OSGi Repository XML URLs for instantiating Repository Services from. String

Configuration via Configuration Management

The Repository XML bundle uses a factory PID to configure repository services. Each factory PID configuration instance corresponds to one XML file for which one Repository service will be created.

The factory PID is org.knopflerfish.repository.xml.MSF.

Name Description Value type Default value
url URL pointing to the location of an OSGi Repository XML file to instantiate a Repository Service from. String

Bundle Jar docs

repository_xml_all-1.0.2
repository_xml_api-1.0.2

Exported Packages

PackageVersionProviders
org.knopflerfish.service.repository1.0.0repository_xml_all-1.0.2, repository_xml_api-1.0.2
knopflerfish-osgi-5.1.0/docs/bundledoc/consoletty/0000755000175000017500000000000012475375714021257 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/consoletty/index.html0000644000175000017500000000335212346515432023245 0ustar felixfelix Bundle User Documentation - consoletty, v4.0.1
Bundle: consoletty
Version 4.0.1

Console TTY

This bundle provides a console session on standard input for the JRE.

Description

The Console TTY bundle provides a tty console session on top of System.in and System.out (the standard input / output of the JVM).

This bundle is typically used during development.

Configuration using the Configuration Manager

The tty console bundle accepts a configuration with the PID
  org.knopflerfish.bundle.consoletty.ConsoleTty
and with the following properties:
nonblocking
Use non-blocking tty access. Some JVM-OS combinations cannot handle blocking access to standard input.

Bundle Jar docs

consoletty-4.0.1

Exported Packages

No exported packages.
knopflerfish-osgi-5.1.0/docs/bundledoc/crimson/0000755000175000017500000000000012475375714020526 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/crimson/index.html0000644000175000017500000000540612346515432022516 0ustar felixfelix Bundle User Documentation - crimson, v2.1.0.kf4-001
Bundle: crimson
Version 2.1.0.kf4-001

Crimson XML parser

The Crimson XML parser

Crimson-XML

The Crimson-XML bundle is a wrapper for the Crimson XML parser and is primary older Java versions that does not provide built-in XML parsing.

xTo enable the Java 6 parsers the Crimson XML parser bundle must not be installed, or started. This is easiest done by commenting out the Crimson XML bundle in the init.xargs file.

Bundle Jar docs

crimson-2.1.0.kf4-001

Exported Packages

PackageVersionProviders
javax.xml.parsers1.2.0crimson-2.1.0.kf4-001
org.apache.crimson.jaxp0.0.0crimson-2.1.0.kf4-001
org.w3c.dom2.0.0crimson-2.1.0.kf4-001
org.xml.sax2.0.0crimson-2.1.0.kf4-001
org.xml.sax.ext1.0.0crimson-2.1.0.kf4-001
org.xml.sax.helpers2.0.0crimson-2.1.0.kf4-001
knopflerfish-osgi-5.1.0/docs/bundledoc/serial/0000755000175000017500000000000012475375714020333 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/serial/index.html0000644000175000017500000000620712346515436022327 0ustar felixfelix Bundle User Documentation - Serial Communication

Serial port communicaton using javax.comm

This section covers bundles for handling serial ports using the javax.comm API

Bundles

serialport
Bundle that wraps serial ports in the OSGi Device API.
comm-win32
Implementation for windows platforms using Sun's COMM 2.0 release. Note that this bundles contains code with license from Sun, for details, see comm-win32/resources/COMM2.0_license.txt
comm-linux
Implementation for x86 linux platforms using the RXTX library. Note that this bundles contains code with license from Sun AND is licensed under GPL. For details, see comm-linux/resources/COMM2.0_license.txt comm-linux/resources/rxtx-license.txt The RXTX source is available at http://users.frii.com/jarvi/rxtx/

Bundle Jar docs

comm-linux_all-3.0.0
comm-win32_all-3.0.0
serialportdevice_all-4.0.0
serialportdevice_api-4.0.0

Exported Packages

PackageVersionProviders
gnu.io2.0.0comm-linux_all-3.0.0
javax.comm2.0.0comm-linux_all-3.0.0, comm-win32_all-3.0.0
org.knopflerfish.service.serial0.0.0serialportdevice_all-4.0.0, serialportdevice_api-4.0.0
knopflerfish-osgi-5.1.0/docs/bundledoc/event/0000755000175000017500000000000012475375714020175 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/event/index.html0000644000175000017500000000773312346515430022170 0ustar felixfelix Bundle User Documentation - event, v4.0.1
Bundle: event
Version 4.0.1

The Knopflerfish Event Admin Service

The Knopflerfish OSGi Event Admin Service is an implementation of the Event Admin Service specified in the OSGi compendium specification.

Description

The Knopflerfish OSGi Event Admin Service is an implementation of the Event Admin Service in the OSGi Service Compendium that provides parallel delivery of events posted by different threads.

Configuration properties

Name Description Type Default
org.knopflerfish.eventadmin.timeout The timeout in milliseconds to apply to calls to the handleEvent(Event) of individual event handlers. The value 0 means no timeout. long ≥ 0 0
org.knopflerfish.eventadmin.timewarning When set to a value > 0 then measure the time of each call to the handleEvent(Event) of event handlers. If the call lasts longer than the value of this property then log this event handler delivery call and its duration in the OSGi log using a log entry with severity ERROR.

Time warnings are only supported when the event handler call timeout described above is unset (i.e., set to 0).

long ≥ 0 0
org.knopflerfish.eventadmin.queuehandler.multiple If multiple event delivery queues should be used or not. If set to true each thread calling the EventAdmin.postEvent()-method will be assigned its own queue for delivering its events. boolean true
org.knopflerfish.eventadmin.queuehandler.timeout The timeout (milliseconds) before an event delivering queue that has nothing to do is disposed. That is if there has been no events for the queue to deliver for more than this number of milliseconds then the queue will be terminated. If the thread posts another event later on a new delivery queue instance will be created.

This timeout is only in use when multiple even delivery queues are enabled.

long ≥ 0 1100

Bundle Jar docs

event_all-4.0.1
event_api-4.0.1

Exported Packages

PackageVersionProviders
org.osgi.service.event1.3.0event_all-4.0.1, event_api-4.0.1
knopflerfish-osgi-5.1.0/docs/bundledoc/component/0000755000175000017500000000000012475375714021056 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/component/index.html0000644000175000017500000000475712346515432023056 0ustar felixfelix Bundle User Documentation - component, v5.0.3
Bundle: component
Version 5.0.3

SCR

Implementation of the Service Component Runtime.
I.e., the extender that processes bundles using Declarative Services.

Bundle Jar docs

component_all-5.0.3
component_api-5.0.3

Exported Packages

PackageVersionProviders
org.apache.felix.scr1.6.0component_all-5.0.3, component_api-5.0.3
org.osgi.service.component1.2.1component_all-5.0.3, component_api-5.0.3
knopflerfish-osgi-5.1.0/docs/bundledoc/console/0000755000175000017500000000000012475375714020516 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/console/index.html0000644000175000017500000003030512346515432022502 0ustar felixfelix Bundle User Documentation - console, v4.0.1
Bundle: console
Version 4.0.1

Console

The Knopflerfish console bundle

Description

Introduction

The user's guide contains information about the console interfaces, the command group concept and reference documentation for the console's built in commands.

Terminology

Terms, acronyms and syntax of console commands.
command group
A set of commands exported to the console from some bundle.
EOF
End Of File, close of console input.
session
What you are in when communicating with the console
session group
The command group for the console built in commands.

Syntax Elements

[]
Delimiters for optional parts of a command and optional parameters.
|
To indicate alternate parameters.
...
More parameters, same type as the previous one.
#value#
Parameter to a flag.
" "
Double quotes. Used to contain parameters that have blanks in them.
Command parameter to be replaced with data.

Console Interfaces

The console bundle is not very useful on its own; it needs other bundles to supply the commands and also at least one bundle supplying a user interface. The console uses the CommandGroup service of the command supplying bundles to access commands. A console user interface bundle uses the ConsoleService service of the console bundle to execute commands ordered by the user.

The console bundle actually has some built in commands that can be used for administrative tasks, that is, managing the user session. These are the commands in the command group session.

The following bundles implement user interfaces: consoletty Basic tty console, available in the terminal window where the platform is started. consoletelnet Basic telnet console, listens on a port using the telnet protocol.

General Command Structure and Behavior

The general command format is built of:
  [ ...] [ ...]
First is the command group (all commands must belong to a command group), then the command. After the command is zero, one or more flags with possible additional parameters and finally zero, one or more parameters. See chapter [2]Terminology on page 1 for explanations of delimiters.

Note: To avoid having negative numbers interpreted as flags, negative numbers are to be written with double hyphens (as --n).

At start-up, the console is in the initial state. When entering a command the command line must begin with the command group's name, as described above. However, the session can enter a group with the session enter command. After entering a command group, commands of that group are executed without the group name as prefix. The session leave command leaves the current group and the session is back in its initial state.

Commands from other groups than the current group can be executed by prefixing the command with a slash ("/"). For example, the following would execute the shutdown command from the framework command group, regardless of the session's current group. /framework shutdown

Normally, command groups and commands may be shortened as long as they are unambiguously identifiable. As an example, in command group session, the command alias may be shortened to a as it is the only command that starts with the letter a.

Session Commands

This is the command group for the console's built in administrative commands. It contains commands for managing a session.

All of the session commands have aliases to make them quick to enter regardless of the current command group. For example, /session help has the alias help. In all the examples below, the alias versions of the session commands are used.

The commands in the session command group are:

     * alias [] [] ...
     * enter 
     * help
     * leave
     * prompt 
     * quit
     * save
     * unalias 

Command Details

Detailed description of all session commands in alphabetical order.

alias

To set or show aliases.
  alias [] [] ...

   The command without any parameters prints a list of all existing
   aliases:
  > alias
  start = /framework start
  install = /framework install
  prompt = /session prompt
  lsb = /framework bundles
  fw = /session enter framework
  log = /log show
  help = /session help
  quit = /session quit
  lss = /framework services
  alias = /session alias
  unalias = /session unalias
  enter = /session enter
  stop = /framework stop
  bundles = /framework bundles
  leave = /session leave
  >
With parameters it sets an alias to the specified value. If the alias exists, the old value is replaced with the new. With one parameter the value of that alias is shown.

enter

Enter a command group, in effect automatically prefix all commands with the name of the command group. This makes it possible to use the short names of the group's commands.
  enter 
The result is that the prompter is prefixed with the command group and all the commands in the command group are available in short form. Example: Entering a command group
  > enter framework
  framework> help
  Available framework commands:
    bundles [-help] [-1] [-i] [-l] [] ... - List bundles
    call [-help]   [] ...
      - Call a method in a registered service
    headers [-help]  ... - Show bundle header values
    package [-help]  ... - Show java package information
    install [-help] [-s]  ... - Install one or more bundles
    services [-help] [-i] [-l] [-r] [-s] [-u] [] ...
      - List registered services
    start [-help]  ... - Start one or more bundles
    stop [-help]  ... - Stop one or more bundles
    shutdown [-help] [] - Shutdown framework
    uninstall [-help] >bundle> ... - Uninstall one or more bundles
    update [-help] [-r]  ... - Update one or more bundles
It is only possible to be in one command group at a given moment. By adding a slash ("/") to the group name, commands in other gruops can be accessed.

help

Show help information about commands and command groups.
  help [ | all]
Lists the commands available in the specified command group, each with a short description. If no command group is specified, help for the current group is displayed. In the initial state, or if the parameter all is supplied, help shows the available command groups. Example: Display available command groups
  > help
  Available command groups:
  session - Session commands built into the console
  logconfig - Configuration commands for the log.
  log - Log commands
  framework - Framework commands
  >
Note that this list can be longer as any installed bundle can export its own commands.

leave

Leave a command group, that is, go back to the initial state (no current command group).
  leave
Example: Leave the current command group
  framework> leave
  >
Note that leave only goes to the initial state, it does not go to the previous command group, if any.

prompt

Set the command prompter.
  prompt 
If the command group is to be visible in the prompt, a percent character ("%") should be included in the prompt string. At printout, the % character will be replaced by the command group name. Example: Changing the prompter
  > prompt "%test >"
  test >
  enter framework
  frameworktest >

quit

Exit the session.
  quit
The console exits and loses contact with standard in.

save

This command saves the current aliases to persistent memory. The aliases are read next time the platform is started. save

unalias

This command removes an alias.
  unalias
Example: Creating and removing an alias
  > alias more less
  > unalias more

Interface consoletty

The consoletty bundle allows local console access to the platform without the use of the http server.

If the platform starts the consoletty, it will use the text window the platform was started from.

Interface consoletcp

To allow remote console access to the platform without the use of the http server, the consoletcp bundle listens to a port on the platform. See [[3]1] information regarding the port number. Depending on configuration, the TCP console will require that the user logs in before creating a console session. See [[4]1] for more information. The user name/password authentication method is used for authentication. The Input Path is set to "tcp" and the Auhtentication Method is set to "passwd". The commands and their formats are the same as for the consoletty. To access it in a simple way, use telnet. Example: Using telnet and consoletcp
> telnet demo.gatespace.se 8999
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
> help
Available command groups:
session - Session commands built into the console
osgilog - Log commands
messenger - Messenger route configuration commands.
logconfig - Configuration commands for the log.
framework - Framework commands

>

Environmental influences

Due to the fact that console windows may be opened in many different environments that have different capabilities, the console may seem to behave different. One example is the occurence of a "command history" in some environments. This capability is however supplied by the window manager "locally", the console does not have any command history capability.

Bundle Jar docs

console_all-4.0.1
console_api-4.0.1
console-4.0.1

Exported Packages

PackageVersionProviders
org.knopflerfish.service.console2.1.2console_all-4.0.1, console_api-4.0.1
knopflerfish-osgi-5.1.0/docs/bundledoc/bundledoc_list.html0000644000175000017500000001266412346515440022732 0ustar felixfelix

Knopflerfish OSGi 5.1.0

knopflerfish-osgi-5.1.0/docs/bundledoc/frameworkcommands/0000755000175000017500000000000012475375714022573 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/frameworkcommands/index.html0000644000175000017500000001141412346515430024555 0ustar felixfelix Bundle User Documentation - frameworkcommands, v4.0.1
Bundle: frameworkcommands
Version 4.0.1

Framework Commands

The Knopflerfish framework console bundle

Description

The Framework commands bundle includes a rich set of commands through which the Knopflerfish framework can be controlled. This includes bundle management (install, start, stop etc), OSGi service information, to package and permission management.

Framework Command Group

The console command group is framework

The available commands are:

Available framework commands:
  addpermission [-help] -b #bundle# | -d | -l #location# <type> [<name> [<actions>]] - Add permissions to bundle
  bundlelevel [-help] <level> [<bundle>] ... - Set startlevel(s) for bundles
  bundles [-help] [-1] [-i] [-l] [-s] [-t] [<bundle>] ... - List bundles
  call [-help] [-f #filter#] <interface> <method> [<args>] ... - Call a method with zero or more java.lang.String
  capability [-help] [-d] [-i] [-l] [-r] [-p] [<bundle>] ... - Show information about active capablities in the current wiring for a bundle
  cd [-help] [-reset] [-a] [<base URL>] ... - Shows or sets the base URLs used to complete bundle location
  certificates [-help] [ -i ] <bundle> ... - List certificates for bundles
  closure [-help] <bundle> - Display the closure for a bundle
  condpermission [-help] [<name>] ... - Get conditional permissions
  deletepermission [-help] [-r] -b #bundle# | -d | -l #location# <type> <name> <actions> - Delete permissions from a bundle
  findbundles [-help] <symbolic name> - Find bundles with a given symbolic name
  frominstall [-help] <url> [<location>] - Install a bundle with a specific location from an URL
  fromupdate [-help] <bundle> <url> - Update a bundle from a specific URL
  headers [-help] [-i] [-l #locale#] <bundle> ... - Show bundle header values
  install [-help] [-s] <location> ... - Install one or more bundles
  meminfo [-help] [-gc] [-b | -m] - Display java memory information, in kilobytes
  package [-help] [-l] -b | -p [<selection>] ... - Show java package information
  pending [-help] [-i] [-l] - Show the bundles that have non-current, in use bune.dle wirings
  permissions [-help] [-d] [<selection>] ... - Show permission information
  property [-help] [-s] [-f] [<property>] ... - Lists Framework and System properties with values.
  refresh [-help] [<bundle>] ... - Refresh all exported java packages belong to specified bundle
  resolve [-help] [<bundle>] ... - Resolve one or more bundles
  services [-help] [-i] [-l] [-sid #id#] [-f #filter#] [-r] [-u] [<bundle>] ... - List registered services
  setcondpermission [-help] [-name #name] <conditional_permission_info>... - Set conditional permission
  showstate [-help] [<pid>] ... - Show the state of a service, if the service provides state information
  shutdown [-help] [-r] - Shutdown framework
  start [-help] [-t] [-e] <bundle> ... - Persistently start one or more bundles according to their 
  startlevel [-help] [<level>] - Shows or sets the global startlevel
  stop [-help] [-t] <bundle> ... - Persitently stop one or more bundles
  threads [-help] [-a] [-s] [<name>] ... - Display threads within this framework
  uninstall [-help] <bundle> ... - Uninstall one or more bundles
  update [-help] <bundle> ... - Update one or more bundles
  wiring [-help] [-i] [-l] [-r] [-p] [<bundle>] ... - Show information about active wires in the current wiring for a bundle

See Also

Console

Bundle Jar docs

frameworkcommands-4.0.1

Exported Packages

No exported packages.
knopflerfish-osgi-5.1.0/docs/bundledoc/util/0000755000175000017500000000000012475375714020031 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/util/index.html0000644000175000017500000001336512346515430022022 0ustar felixfelix Bundle User Documentation - util, v4.1.0
Bundle: util
Version 4.1.0

Util

Library of miscellaneous utility classes.

Content

Native Executable

The bundle activator utility class ExecutableBundleActivator can be used if you need to package an executable binary in your bundle that should be extracted and started when the bundle starts.

Depending on your needs you can either write your own bundle activator that extends ExecutableBundleActivator or use it directly without writing any Java code at all. If you use it directly, all you need to do is to add custom headers to your manifest that controls the behavior of ExecutableBundleActivator.

The following are the required headers for a simple example.

 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-SymbolicName: org.knopflerfish.bundle.ebaexample
 Bundle-Activator: org.knopflerfish.util.framework.ExecutableBundleActivator
 Import-Package = org.knopflerfish.util.framework,org.osgi.framework
 Bundle-Start-Executable: notepad.exe ; processor=x86 ; osname=WindowsXP

In this case there is only one custom header, Bundle-Start-Executable. It declares that if the native environment matches OS = Windows XP and processor architecture = x86, the resource named notepad.exe should be extracted from the bundle, written to the local file system and launched using java.lang.Runtime.exec() when the bundle is started.

The exec:ed process will be terminated when the bundle stops. If the process is terminated, the bundle will be stopped (this is the default behavior).

Complete list of custom headers for this utility class:

Bundle-Start-Executable
List of native environments (OS, processor, etc) and native executables for those environments. If there is a match for the current native environment, the executable is copied to the local file system and started in the start method of ExecutableBundleActivator. The syntax for this header is the same as for the OSGi specified Bundle-NativeCode header but instead of naming a shared library you name a native executable. The Bundle-NativeCode header is described in the core OSGi specification chapter 3.9.
Bundle-Start-Executable-Args
Arguments (separated with spaces) for the bundle start executable.
Bundle-Stop-Executable
Similar to Bundle-Start-Executable but the executable is launched when the bundle stops.
Bundle-Stop-Executable-Args
Arguments (separated with spaces) for the bundle stop executable.
Bundle-Extract-Files
List of extra resources (separated with comma) that should be copied from the bundle jar file to the local file system.
Bundle-Start-Executable-Exit-Means-Bundle-Stop
Set this to false if you do not want the bundle to be stopped when the process that was launched in start() is terminated.

In many cases you want to write your own activator that extends ExecutableBundleActivator. You can then for example override logging which is on and to stdout by default. Also, you need to write your own activator if you want your bundle to do more than starting a native executable.

Files that are extracted (executables and other resources) are written to the bundle's persistent storage area. Cleanup of the files takes place when the bundle is uninstalled.

Bundle Jar docs

util-4.1.0

Exported Packages

PackageVersionProviders
org.knopflerfish.util1.1.0util-4.1.0
org.knopflerfish.util.framework1.0.0util-4.1.0
org.knopflerfish.util.sort1.0.0util-4.1.0
org.knopflerfish.util.workerthread1.0.0util-4.1.0
knopflerfish-osgi-5.1.0/docs/bundledoc/framework/0000755000175000017500000000000012475375714021051 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/framework/index.html0000644000175000017500000012332312346515430023036 0ustar felixfelix Knopflerfish Framework Documentation version 7.1.2
Knopflerfish Framework
Version 7.1.2

Knopflerfish OSGi framework

This is the Knopflerfish framework. An OSGi Release 5 compliant framework. It supports all optional and deprecated framework services, Package Admin, Start Level, Conditional Permission Admin, Permission Admin, URL Handlers, Bundle Hook, Resolver Hook, Service Hook and Weaving Hook.

Contents

  1. Knopflerfish framework.jar startup
  2. Initial start vs restart
  3. Starting the framework
  4. Starting the compact framework
  5. Default selection of .xargs
  6. Using a HTTP proxy
  7. Framework and System Properties
  8. OSGi Specified Framework Properties
  9. Knopflerfish Specified System Properties
  10. Knopflerfish Specified Framework Properties

Knopflerfish framework.jar startup

This is a startup guide for the KF OSGi framework. Note that command-line startup of the framework is not specified by OSGi, and system integrators often need to create a wrapper script for FW startup.

The KF Main startup class is primarily intended to be used in scenarios where current working directory is same as the one containing framework.jar, the framework storage directory and configuration files. In these cases

java -jar framework.jar

...is often enough.

To use features that requires JVM restart, e.g. extension bundles, you can use our example shell start script "kf2". Open a terminal and type

./kf2

Note: the script requires a "sh" shell.

Other uses are possible, but require options and possibly some tweaking of the default startup files.

Initial start vs restart

Two cases of framework startup should be noted:

  1. Initial, bootstrap, startup
    An initial startup must contain enough options to install bundles allowing further management, using -install options. If no bundles are installed, an empty framework will be started but nothing can be done with it..
  2. Restart of previously initialized framework
    Any OSGi framework can remember its state from previous startup.
    In this case, startup options should only contains system properties and a -launch option for restarting the bundles, but not any -install options.

NB! Framework properties (-Fx=y) supplied at initial startup are saved as part of the framework state, and need not to be supplied again at framework restart. System properties (-Da=b) are not included in the framework state. Since the two different startup cases probably will use separate startup files, care must be taken so system properties are set correctly in both files, when so required.

It is up to a system integrator to decide when to use initial startup or restart. The Main KF class can help somewhat in doing this (see below) but might not be enough. In those cases, wrapper scripts, or modifications to Main.java are recommended.

Starting the framework

The framework can be started using the startup wrapper class

org.knopflerfish.framework.Main

This class is also set a Main-Class in framework.jar's manifest, meaning framework.jar can be started using

 java -jar framework.jar [options] OR ./kf2 [options]

The Main class supports a number of options, which can be displayed using:

java -jar framework.jar -help OR ./kf2 -help

Options can also be specified using the -xargs option, which specifies a .xargs text file containing lines of new options. Typically all options are specified in .xargs files. Combining .xargs files and command line options is possible. .xargs files can also use recursive .xargs files.

When the framework is started, it uses a file system directory for storing the state of all installed bundles, "fwdir". The default directory used for this is:

fwdir

in the current directory. The "fwdir" directory can also be set specifically using the org.osgi.framework.storage property. Note that moving "fwdir" also changes the location for searching for default .xargs files.

If no options are specified (any "-Fx=y", "-Da=b" or "-init" does not count as options in this case) an implicit

-xargs "default"

is added to the options. "default" means that the default .xargs (see below) is selected.

Starting the compact framework

There is a compact version of the framework available for system that has limited amount of resources (memory and storage). This version doesn't contain any support for security and certificates. The internal classes has also been name mangled to save resources.

The compact framework is started and controlled in the same way as the full version. The only difference is that the jar file is called framework_compact.jar.

Default selection of .xargs

If _no_ args are supplied (arguments of the form "-Fx=y", "-Da=b" or "-init" does not count in this case), or a name of "default" is given as -xargs argument, a default .xargs file will be searched for, by the following algorithm:

  1. If there exists a previous "fwdir" AND previous options does not contain "-init", use a file in "fwdir" named:
    fwprops.xargs
  2. If no fwdir exist, OR options contain an "-init", search for a file named:
    1. init_[osname].xargs
    2. init.xargs
    3. remote-init.xargs
    The search is performed in the following directories:
    1. fwdir
    2. The parent directory of fwdir (if any)
    3. The current working directory
    First match wins.
    The [osname]-part of the file name is the unified OS name as specified in Alias.java (see below). Case is important if the file system is case sensitive.
    OS aliases:
    • OS2
    • QNX
    • Windows95
    • Windows98
    • WindowsNT
    • WindowsCE
    • Windows2000
    • WindowsXP

The file fwdir/fwprops.xargs contains saved properties that is used when restarting a framework instance. It is written by the Knopflerfish framework on every startup (unless disabled by setting the property "org.knopflerfish.framework.write.restart.xargs" to false).

Using a HTTP proxy

The standard JVM system properties

  • http.proxyHost
  • http.proxyPort
  • http.nonProxyHosts

should be used to set proxy information. This will be global to all HTTP request from all bundles and the framework.

Additionally, the KF-specific system property

  • http.proxyAuth

can be set to a value on the form user:password

If set to non-empty, this will add the Proxy-Authorization header to bundle install http/https requests made from the framework, However, bundles using the URL class internally must explicitly set this header themselves.

Framework and System Properties

Both Framework and Java System properties are used to control the framework.

Framework properties are the standard properties listed in the OSGi specification (section 4.5.3 in r4.core) and proprietary properties for the Knopflerfish framework. Framework properties are also used for configuration of Knopflerfish bundles.

Framework properties are specified on the command line or in .xarg files using "-F". If you have more than one framework instance, each instance has its own set of Framework properties.

A framework property is accessed by using

org.osgi.framework.BundleContext.getProperty(String)
.

Java System properties are specified on the command line or in .xargs files using "-D". System properties are accessed using

java.lang.System.getProperty(String)
but
BundleContext.getProperty
can also be used as it will look for a System property if there is no matching Framework property.

Because of the different handling of Framework and System properties when the framework is restarted, it is recommended to use only Framework properties in .xargs files. If you do, and use the default init.xargs/props.xargs files, initial starts and restarts become conveniently short on the command line:

java -jar framework.jar -init  
(initial start)

java -jar framework.jar  
(restart)

Unfortunately, it is not always possible to avoid using Java System properties. For example, a bundle may include a class library that uses System properties for configuration. Also, properties that are read during start-up, before the framework has been initialized, need to be System properties, see KF System Properties.

OSGi Specified Framework Properties

OSGi Framework properties should be specified using "-F".

Name Description Value type Default value
org.osgi.framework.bootdelegation Set the boot delegation mask. A list of packages delegated from the framework to the parent classloader. The package specified can contain a wildcard at the end, which matches any sub-packages. String , ...
org.osgi.framework.bsnversion Allow installation of multiple bundles with the same bundle symbolic name or restrict this. The property can have the following values:
single A combination of equal bundle symbolic name and equal version is unique in the framework. Installing a second bundle with the same bundle symbolic name and version is an error.
multiple The combination of bundle symbolic name and version is not unique in the framework.
managed Using a Bundle Collision Hook to filter any non-colliding bundles.
String managed
org.osgi.framework.bundle.parent This property is used to specify what class loader is used for boot delegation. That is, java.* and the packages specified on the org.osgi.framework.bootdelegation. This property can have the following values: boot, app, ext or framework. String boot
org.osgi.framework.command.execpermission Specifies an optional OS specific command to set file permissions on a bundle's native code. This is required on some operating systems to use native libraries. For example, on a UNIX style OS you could have the following value: org.osgi.framework.command.execpermission="chmod +rx ${abspath}" The ${abspath} macro will be substituted for the actual file path. String -
org.osgi.framework.executionenvironment The current execution environment. There are no restriction on the execution environment if this property isn't set. String
org.osgi.framework.language The language used by the framework for the selection of native code. String Set based on default locale
org.osgi.framework.library.extensions A comma separated list of additional library file extensions that must be used when searching for native code. If not set, then only the library name returned by System.mapLibraryName(String) will be used. This list of extensions is needed for certain operating systems which allow more than one extension for native libraries. For example, the AIX operating system allows library extensions of .a and .so, but System.mapLibraryName(String) will only return names with the .a extension. String , ... -
org.osgi.framework.os.name The name of the operating system as used in the native code clause. String Set based on system property os.name
org.osgi.framework.os.version The version of the operating system as used in the native code clause. String Set based on system property os.version
org.osgi.framework.os.processor The name of the processor as used in the native code clause. Set based on system property os.arch
org.osgi.framework.security Specifies the type of security manager the framework must use. If not specified then the framework will not set the VM security manager. The following type is architected: osgi Enables a security manager that supports all security aspects of the OSGi Release 4 specifications (including postponed conditions). If specified, and there is a security manager that doesn't match already installed, then a SecurityException is thrown when the Framework is initialized. String -
org.osgi.framework.startlevel.beginning Specifies the beginning start level of the framework. Integer 1
org.osgi.framework.storage Where we store persistent data. On systems not supporting a current working directory, as Pocket PC, this path should be set to an explicit full path. Note: Knopflerfish 1.x and 2.x used the name "org.osgi.framework.dir" for this property. String ${currentWorkingDirectory}/fwdir
org.osgi.framework.storage.clean Specifies if and when the storage area for the framework should be cleaned. If no value is specified, the framework storage area will not be cleaned. The possible values is: onFirstInit - The framework storage area will be cleaned before the Framework bundle is initialized for the first time. Subsequent inits, starts or updates of the Framework bundle will not result in cleaning the framework storage area. String -
org.osgi.framework.system.packages Complete list of packages exported by the system bundle. If not set the framework will export all OSGi packages and all standard Java packages according to the version of the running JRE. See also "org.knopflerfish.framework.system.packages.base" and "org.osgi.framework.system.packages.extra" String , ... Default is based on other properties
org.osgi.framework.system.packages.extra Packages to add to the default list of packages exported by the system bundle. String , ... -
org.osgi.framework.trust.repositories This property is used to configure trust repositories for the framework. The value is path of files.The file paths are separated by the pathSeparator defined in the File class. Each file path should point to a JKS key store. The framework will use the key stores as trust repositories to authenticate certificates of trusted signers. The key stores must only be used as read-only trust repositories to access public keys. The keystore must not have a password. String : ... -
org.osgi.framework.windowsystem Provide the name of the current window system. This can be used by the native code clause. String -

Knopflerfish Specified System Properties

Knopflerfish System properties should be specified using "-D".

Name Description Value type Default value
org.knopflerfish.framework.main.verbosity Verbosity level of the Main class starting the framework. 0 means few messages. Specify on the command line in order to see messages from the very beginning. Integer 0

Knopflerfish Specified Framework Properties

The recommendation is to use "-F" for Knopflerfish Framework properties but "-D" should also work.

Name Description Value type Default value
org.knopflerfish.framework.all_signed If set to true, we require that all bundles that are installed are signed. Boolean True
org.knopflerfish.framework.automanifest Flag to enable automatic manifest generation. If true, bundle manifest can be modified by a special configuration file. See javadoc for org.knopflerfish.framework.AutoManifest class for details. Boolean False
org.knopflerfish.framework.automanifest.config Configuration URL for automatic manifest generation. Only valid if org.knopflerfish.framework.automanifest=true. An URL starting with "!!" followed by path is refer to a resource on the classloader that have loaded the framework. String !!/automanifest.props
org.knopflerfish.framework.bundlestorage Storage implementation for bundles [file, memory] String file
org.knopflerfish.framework.bundlestorage.file.always_unpack When using file bundle storage, bundle jars can be unpacked or copied as-is. Unpacking leads to faster restart and class loading but takes longer for initial startup. If set to true, unpack all bundle jars. Boolean False
org.knopflerfish.framework.bundlestorage.file.jar_verifier_bug There is a bug when using file bundle storage, certificate and Oracle JRE (Java 6). This bug causes the JarInputStream to miss picking up certificates for files under the "META-INF" directory if they directly follow the META-INF signature related files. This causes KF to mark the bundle as not completly signed. To ignore problem set property to true. Boolean False
org.knopflerfish.framework.bundlestorage.file.reference When using file bundle storage, file: URLs can optionally be referenced only, not copied to the persistent area. If set to true, file: URLs are referenced only. Note: Individual bundles can be reference installed by using URLs of the syntax: reference:file:<path> This works even if the global reference flag is not enabled. Boolean False
org.knopflerfish.framework.bundlestorage.file.trusted Are the bundles stored in the file bundle storage to be trusted, if not signed bundles will be checked every time they are read. Untrusted storage leads to slower restart and class loading. If set to true, trust bundles in bundle storage. Boolean True
org.knopflerfish.framework.bundlestorage.file.unpack Most JVM requires that we unpack the bundle to access internal jars and native code. Setting this to true will unpack the jar if it contains internal jars or native code. If set to true, unpack needed bundle jars. Boolean True
org.knopflerfish.framework.bundlethread.timeout Use this proprty to set a limit on how long the framework will wait for a bundle's activator to complete and return from the start and stop methods. If the time-out occurs, the framework will interrupt the BundleThread that is executing the start or stop method and then optionally stop it or lower its priority, see property org.knopflerfish.framework.bundlethread.abort. A BundleException is thrown to indicate that start/stop of the bundle failed. If set to a positive integer, the value is used as time-out in seconds. If set to 0, no time out is used and the framework will wait indefinitely for the activator's start and stop methods to complete. Integer 0
org.knopflerfish.framework.bundlethread.abort If a bundle's start or stop method time-out (see property org.knopflerfish.framework.bundlethread.timeout) or if the bundle gets uninstalled before the method has returned, this property defines how to manage the bundle's start/stop thread. Possible values are:
"stop" Calls the stop() method of the bundle's thread
"minprio" Sets a minium priority of the bundle's thred
"ignore" Do nothing
String ignore
org.knopflerfish.framework.debug.automanifest Print debug output for automatic manifest actions. Boolean False
org.knopflerfish.framework.debug.bundle_resource When security is enabled, print information about resource lookups that are rejected due to missing permissions for the calling bundle. Boolean False
org.knopflerfish.framework.debug.certficates Print debug information about certificate handling. Boolean False
org.knopflerfish.framework.debug.classloader Print debug information from classloader Boolean False
org.knopflerfish.framework.debug.errors Print all FrameworkEvents of type ERROR Boolean False
org.knopflerfish.framework.debug.framework Print debug information about life-cycle events for the current framework instance. Boolean False
org.knopflerfish.framework.debug.hooks Print debug information about when service hooks are used current framework instance. Boolean False
org.knopflerfish.framework.debug.ldap Print debug information about LDAP filters Boolean False
org.knopflerfish.framework.debug.resolver Print debug information about resolver operation. Boolean False
org.knopflerfish.framework.debug.patch Print debug information about class patching Boolean False
org.knopflerfish.framework.debug.permissions Print debug information about permission evaluation. Boolean False
org.knopflerfish.framework.debug.print_with_do_privileged Surround all debug print-operations originating from setting org.knopflerfish.debug.* properties with a doPrivileged() wrapper. Boolean True
org.knopflerfish.framework.debug.startlevel Print debug information about startlevel service Boolean False
org.knopflerfish.framework.debug.service_reference When security is enabled, print information about service reference lookups that are rejected due to missing permissions for calling bundle. Boolean False
org.knopflerfish.framework.debug.url Print debug information about URL services Boolean False
org.knopflerfish.framework.is_doublechecked_locking_safe Is it safe to use double-checked locking or not. It is safe if JSR 133 is included in the running JRE. I.e., for Java SE if version is 1.5 or higher. Boolean True if value of the system property java.version ≥ 1.5, False otherwise
org.knopflerfish.framework.ldap.nocache Disable LDAP caching for simple filters. LDAP caching speeds up framework filters considerably, but uses more memory. Boolean False
org.knopflerfish.framework.main.class.activation A comma-separated list of locations of bundles whose Main-Class (set in manifest) should be used as activator if no BundleActivator is specified. The Main-Class will be used as activator if and only if the jar file does not specify a Bundle-Activator header and the bundle's location(see Bundle.getLocation) is found in the comma-separated list (case-sensitive).
> java -jar framework.jar
    -Forg.knopflerfish.framework.main.class.activation=\ 
    file:/foo/bar.jar,http://foo.com/bar.jar ...
String -
org.knopflerfish.framework.main.verbosity Verbosity level of the Main class starting the framework. 0 means few messages. Specify as a System property on the command line in order to see messages from the very beginning. Integer 0
org.knopflerfish.framework.main.xargs.writesysprops Properties defined using -Fname=value in xargs-files are available for bundles using BundleContext.getProperty(name). This property controls weather such properties shall also be exported as system properties or not. Boolean False
org.knopflerfish.framework.listener.n_threads Number of threads used to deliver events to asynchronous listeners. If the value is 0 then we will revert to the old behaviour and call all listeners synchronously. Integer 1
org.knopflerfish.framework.patch If true AND once the classpatcher_all-N.N.N.jar bundle is installed and started, run time class patching will be enabled for all classes loaded afterwards. Boolean False
org.knopflerfish.framework.patch.configurl URL to class patch config file. Only used when class patching is enabled. This is used as a fallback if a bundle does not specify a Bundle-ClassPatcher-Config manifest header. "!!" is used to read resources from the system class path "!" can be used to read bundle resources. String !!/patches.props
org.knopflerfish.framework.patch.dumpclasses If true and class patching is enabled, dump all modified classes to a directory. Boolean False
org.knopflerfish.framework.patch.dumpclasses.dir If dumpclasses is enabled, specifies a directory where to dump modified classes String patchedclasses
org.knopflerfish.framework.readonly Controls if the framework should skip saving state changes permantly under framework directory. This means that if we are running with the default "file" bundle storage then new bundles must be installed as a referenced file URL (see property org.knopflerfish.framework.bundlestorage.file.reference). This also implies that no data storage will be available to bundles. Boolean False
org.knopflerfish.framework.service.conditionalpermissionadmin Controls if the framework should register the Conditional Permission Admin service. Boolean True
org.knopflerfish.framework.service.permissionadmin Controls if the framework should register the Permission Admin service. Boolean True
org.knopflerfish.framework.strictbootclassloading If set to true, use strict rules for loading classes from the boot class loader. If false, accept class loading from the boot class path from classes themselves on the boot class, but which incorrectly assumes they may access all of the boot classes on any class loader (such as the bundle class loader). Setting this to true will, for example, result in broken serialization on the Sun JVM if bootdelegation does not exposes sun.* classes Boolean False
org.knopflerfish.framework.system.packages.base An alternative to setting org.osgi.framework.system.packages. When this property is used the list of packages given will be appended with the default set of osgi-packages for the current framework and then used as the exports of the system bundle. String , ... -
org.knopflerfish.framework.system.packages.file File containing list of packages exported by the system bundle. String -
org.knopflerfish.framework.system.packages.version Name for selected exporting profile of system packages. String MAJOR.MINOR from system property "java.version"
org.knopflerfish.framework.usingwrapperscript If set to "true", KF will assume that it has been started with the "kf2" shell script, and that it will be restarted if KF exits with exit code = 200. Required to be able to use new KF2 features such as extension bundles. This flag is set to "true" by the "kf2" shell script. Boolean False
org.knopflerfish.framework.validator A list of which certificate validators to use. Currently available are JKSValidator and SelfSignedValidator. If no validator is to be used, set to "null" or "none". String JKSValidator if org.osgi.framework.trust.repositories Is set, otherwise none
org.knopflerfish.framework.validator.date Date to use when validating certificates. The date is specifed in the current locales short date format. If no date is specified use the current date and time. String -
org.knopflerfish.framework.validator.jks.ca_certs File name of java keystore used by JKSValidator. Used if org.osgi.framework.trust.repositories isn't set. String $JAVA_HOME/lib/security/cacerts
org.knopflerfish.framework.validator.jks.ca_certs_password Password to java keystore used by JKSValidator. String changeit
org.knopflerfish.framework.validator.jks.cert_provider Provider for CertificateFactory to use. String -
org.knopflerfish.framework.main.write.fwprops.xargs Property that tells the Knopflerfish Main if it shall write a fwprops.xargs file with all framework properties inside the framework directory on startup or not. Boolean True
org.knopflerfish.gosg.jars Semicolon separated list of base URLs for relative install commands URL;... URLs to the "jars" folder and all its sub-folders and fwresource:jars/
org.knopflerfish.startlevel.compat Set to true indicates startlevel compatibility mode. All bundles and current start level will be 1. Boolean True
org.knopflerfish.startlevel.use Use the Start Level service. If start level is not used then we do not create a non daemon thread that will keep a JVM with only daemon threads alive. Boolean True
org.knopflerfish.osgi.setcontextclassloader If set to "true", set the bundle startup thread's context class loader to the bundle's class loader. This is useful for checking if an external lib will work better with a wrapped startup. It doesn't set the context classloader for event callbacks. Note that setting the context classloader is not mandated by OSGi, and might introduce dependencies on the KF framework, so this flag should only be enabled for testing purposes. Boolean False
org.knopflerfish.servicereference.valid.during.unregistering If set to false, then the service reference can not be used to fetch an instance of the service during delivery and handling of the UNREGISTERING service event. The behaviour specified in the OSGi R4 v4.0.1 specification (and later), according to a clarification done by CPEG February 2008, is that it shall be possible to obtain a service instance during delivery of UNREGISTERING events thus this property now defaults to true.

Note that independent of this setting the service reference of an UNREGISTERING service will not be returned by any of the methods searching for service references provided by the BundleContext interface.

Boolean True
org.knopflerfish.osgi.registerserviceurlhandler Flag for installing OSGi service based URL handlers. Since the URL handler can only be installed once, there might be cased where some external entity (not OSGi) sets this. In this case, the OSGi handler can be disabled by setting Boolean True

Exported Packages

PackageVersionProviders
org.osgi.framework1.7.0framework
org.osgi.framework.hooks.bundle1.1.0framework
org.osgi.framework.hooks.resolver1.0.0framework
org.osgi.framework.hooks.service1.1.0framework
org.osgi.framework.hooks.weaving1.0.0framework
org.osgi.framework.launch1.1.0framework
org.osgi.framework.namespace1.0.0framework
org.osgi.framework.startlevel1.0.0framework
org.osgi.framework.wiring1.1.0framework
org.osgi.resource1.0.0framework
org.osgi.service.condpermadmin1.1.1framework
org.osgi.service.packageadmin1.2.0framework
org.osgi.service.permissionadmin1.2.0framework
org.osgi.service.startlevel1.1.0framework
org.osgi.service.url1.0.0framework
org.osgi.util.tracker1.5.1framework
knopflerfish-osgi-5.1.0/docs/bundledoc/consoletelnet/0000755000175000017500000000000012475375714021732 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/consoletelnet/index.html0000644000175000017500000000530312346515434023720 0ustar felixfelix Bundle User Documentation - consoletelnet, v4.0.1
Bundle: consoletelnet
Version 4.0.1

Console Telnet

This bundle provides a telnet server that acts as a user interface to the KF console

Description

The Console Telnet bundle is a telnet server that makes Knopflerfish console commands available to the end user. Any telnet client can be used to connect to it.

This bundle is typically used during development.

Configuration properties

Name Description Value type Default value
org.knopflerfish.consoletelnet.user User login name for remote access. String admin
org.knopflerfish.consoletelnet.pwd Password for the user login name configured using the property org.knopflerfish.consoletelnet.user described above. String admin
org.knopflerfish.consoletelnet.port Port number that the telnet server will listen on. int 23
org.knopflerfish.consoletelnet.host Host (IP interface name) to open the telnet server socket on. An empty string means all available interfaces. String
org.knopflerfish.consoletelnet.busywait If set to true use a busy-loop polling for characters from the input stream. If false the reading thread will hang on the read-operation until data becomes available. boolean false

Bundle Jar docs

consoletelnet-4.0.1

Exported Packages

No exported packages.
knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/0000755000175000017500000000000012475375714021416 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/0000755000175000017500000000000012475375714022663 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/player_eject.png0000644000175000017500000000133112346515432026023 0ustar felixfelixPNG  IHDRĴl;sBIT|dtEXtSoftwarewww.inkscape.org<kIDAT8ŕKSaǿy6;cg+'Sb2Ӥ lePi:B/##ۂ*Pu#bM&n;Ӆ.* >|%fNlGbEI9`"tޖg[^3 62sޅC}/_y~~ :Tw 9tb8]zz|9 j<ƫU ŕF(1orť/j*#+T*}{ rdPz=+Ͱw""Z4pwֵĄF]"D3Y O?bT]7X9QȲlVDG2L^2$mg` PӴGP%L&]Xs TvCl6340{>e\uX^4x(v!㚚03_6 P)ڜBXD͖ؼϹnXf42Lk*U?\>|DIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/httpconsole_login.png0000644000175000017500000000600012346515432027105 0ustar felixfelixPNG  IHDRТ-tEXtCreation Time$.2tIME%tg pHYsod ~IDATxmlG璴| v8VT"u.abJvQ#E.%j5b)U|uXI>Dl"w܋w)ٝ}vw<38*Ȱ)l<ka@gz{{]6d  >mM ` B.}K^@qlޙh6VgT6FW)swpl;ϱNUݔ\vz z7y&llg#9=t?0a4t7SlaahX]Gs|c?l?;s'.UB\>ghA[0U;Y d_ˌN聜j[H\xsg(i,ubu@]H#l._b]YrKRUV8̵kf>\ Իtۄ3Z:'y_{}@k!t6(Nc^EZum6O٘Aeז^86Mavxۤ8.|ї0 L5ِOAZ,8c+ m( A$ٙк%֟/XҶܵ6/IZU?!P6,+;sOȡ٤eu44yjYK+ڏIwg}Ҕ.#mѪ]pͼa]3ĜOhd%݄%H͎i%M5ީB8mgٙuԕ0#*w4UMwg&r ɕ@e"ӕȶrX,.!Z6xGG9&#۬gjibY(LE`e^whv-,$r31ӴDVh?9XUA5v6ݍC,lf䘩Z^Sgx 6I2 j`AP(jS6J@3,BQሕ͇?S:M =Ej,VCgxB^>f@Q@6H dq``S5@6HS '?ODA@6H d49gҴ)n@Qlif} b3"zk>_'wòov>޼3,psZQWO~G5k|Dǝ}{ ģ}w!4-6˪1=?/vS(ÛDȆU1UɄd A3UU3׷زPlVj a%ly3Kw\6'2-7?m7#jd0Q#l5K;o,&I|Y݈!2BV+-IEP_dhƺa_K'y]c뵝G˗KblK&|+)6K!5!7dC2;^龮\<@+_iwhK!FEn.ڥ{bJDyVl3V-W9UA>oG}tL-5Թʭm -ghG6 Y(+JsiO|k/{s[WˊN?a%l}nzN8Kʾ7>ѯ3O~AhpVXTAsͣa D7[~_/}Wz[Զ{O>W{nf9&Ý>79 1ab& Do _l}s%>y.xk፲9hm6YϬޤ)uoYM1@6Ck@s7µҴ(S6X챇&nT&vo2\9FwOwn w<=r|h' ; 4H/4 @6H d4 @6H B¶  4l@i l@i l@i3a@z^x} ze/re9iZ3n=nޘÝdb?/j(m)$!?P8U%'XQC@$jy#Eq{;頔I!2mwWf|0wʪcEo< Ͷ5ۺ$'1}p^Z8 !?9${oqLOV Xdϯ՞J.NJFnO5>uٸYV,*|?z=R录3i_lp3`I}-ؖeXA]] C~![D Q鱗4t]0R߲vd&?{J-40MycH!R(MCi=+^bژT@UtCGHJZ[e@U6!DRRRC}_P\z]ױ-1 ])FT}sItv.tVS7*}[鷿t cJ`\u<\M^]=$]tv%NP0?}pwEt .Q8r޶M2{R(!@iSc}\jX{`ӎ^ֿfb{VdL7Wnq>7ZuQˢ003e ަ/twt !0)2ތ#v̙͟2ãDAT7Ey-+ɳ5mh>vh<`!D60g  YO2rt6'Z[/? mpy^q+|@VZ̴ Ri " >@IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/info.png0000644000175000017500000000226412346515432024316 0ustar felixfelixPNG  IHDRĴl;bKGDC pHYs  tIME / ={HAIDAT8˝]lUw|NgnRU[PJ!i@DjjR#} AM !$1`ԄBb4F%>!Ceq@;ͽ%EB9a,!$Ι-?E#Na7nZص[4,A/HeEsשFNx]íoتԃD`q\~IÇ7E#낷صi-ejqpsBŌOdϣmZPicHfpkamM)#~mPb6xĒK>TlNyA D9߱p+WoòM)1 !eA %JHRRDР)*M|Pq|xs]gl[CA 1 !VN5N1̙.l8.f_%J yN7尢+D fEt(~" GUPGKY:נޮ`C7-F5:=3k8U1"c'y Վu9ʖ&i=ۻCuɹS3/ S}Ŭ^4*X"q}QVs\<GNYgFG߷ی6ṳ̏1*lJSͪlmT:ri98؜9C KAu?\ sm"/L-.c[cшyG*p{r(lAU Li@LO ;c7HT}^oqrrw\}H:A$n3(rg"h !Bdȉd3!Hh2eёC6}6[G,s3JsL}5y$cs~5$r=[% `3f]#l`stWL,~ǣ,&LfK鼷~*J|Muu776)]$F/4(&%< N&T9+2TgU Y?#brţb.maT/%kmb} (vY)?pWxяYC 856%uٜ " ,W9RSj-iA{^Ʀ܅`.5=Pmn|E SĿXǛxC%FAx2s\ +,^&|#:ɥRl:Ku& c !˫Z:Kw&J2۸P,u%׹x^so \sj)KO *-߽-Z+p'Jj[͟$b6!bB0pNl{gb-[Db©Z(g9cr)9uDYp7P&Iﳙ4#4^M|̇WF>cy(=oODqM,YhxD*mD1n^"]l5 -}Sr R3܌K4QtkSW":߮\Aݻr6ںBBM HtjkRi?wCvLfv?-e79z{jZX&ʔ3+ =p :1@h0>QL|a7a+5FQ?qK]06ś{?z%9KpWJCUHƚ qFUX+!4^hB|u4PFxCe/OTC/Sf~h).8E8eF@߅"`{áNбsoCvfrf-p}9b1N%}%}]ggɳ9eT{T V$I%Z&j .I Ѫ0ŏ U  91*.GsIx.pИhDW! VhJ DUL|d@E,ޥQT])7%"ޒOEL 8: cW*9y%D!SВ BQpDҋF5]M,I0yaA/"{:GʳsB_9mۢ4aY紦:8N  =]%MLVMYe=dg} s`a?`0š8*TMD=UbPrBjq!TH9@+hq`Z+ZWD%d 2y&x_ؽs@<{Uuu(Y|ѣ (:a~E0GW=P9Yэ' bimZǑ Uh/[Ր){>}q^{8їцG#:$FJhK~(qD2!HV\/SEۻ {֞F$|5ɱO)K7JME\“𲐃%P41tFE BA*g#짙4I!gkD8xybZ97'˅~%lG7Sr1/t]{|wtbD4Fɶ,٪}8) 燸e|KG[֫W1$ ɮ;Y 7IJF8[)(N"R1H^ R /n@A&x/8&1>DiiYxk֩>FV-!~<9cJٷ3>R=cA;܇}Нu%=0S$̐>|)>4LE*hQtNJnFa@`C9h  a~>c12v>9 fkC? >,%ل4DeFd`eH XGix6oH%$Jmh&a'6=11"-& E^JJZLEt=u&ϊa4 ,Uɖbk(r):|*ծ6`T_25R4pGGY/ɕDQTH;ίB O+ɗ(¿ƒ2r ?l]W"گ)|+!Q*$$Jz87,Ew=ڋVQ# `NHpxIWnR0}1QYjL:,Y S/-pͮl\t.+!< <FG^Pc<qDP"˭`UkH 8S.4hxhIDȨw1`^HXA!AXTϨ%n"q;^eVj߃>ά{ˤ4Qr Desԡ; ;7\3ΩLhfKsJME^aAb%9fP*ݳGLJ'.gGZ9Xx`"t% i-&E:D?   _*.NYĜPN!XY<=l&`M z?wE.*9:F#/U WW0,ig:a( 8҄/^e00Ӻ"F>_OírFJ+bFx+xgjցAAAA       Iiu:t'i8^]tjDPW./S$)534bG+<#V)xGu8 Cwp"؝+>:1tOC24>MYr--MNۋ WKž 4ӿgm:xYȉV3])^p-$2|ajKziAe6!m 4B$\yrc(gO%4I*gM/pfO!ﰮEAVxI(CPS}ΐD}6ѶW-D skaaY!AWpx=ZT@m2}P)c`@+q*VLsZxDuܛ8r"YaPV2wy,U>A$:7'On p7m+ A*3* =tѺ%Q D"T&!Us[y! !Tl7oh5%P z4\!GEX"2}TT XeʺuJ9Rn`r$}#:y/?B d-]8aw_ZS`hn O{N;6u: ³$R8Ә.kn^]*B֜Nt }@i nMUg 0Q3[zt乚^#YA}PE]4F(FnZ _z_RѻTCј~(Wb"+ iNZk͛~1zc90[sOik[#A,ȁWQ0|:8ΪwZ!oҠW@^?#:g.'ܙ?hƕ&F֥p OmXUdv8ǯD\ds#8 W-4ݹK5KhkӁuhLf  __]lҵW{*3[=w?4^W]o-~: %I5܋k9z?x[N-M`ZLl{A.#t7CB& H=*q:m@2 ܹ]So-%4@A p7~a(mv#A!&Ji] YbC!}VYF)<$4hSUUa? ]x&> P5[cM UP* GoY͸F6c 3y8tIR ]Zc-z,} \/ilXo+f%B&y MJ|SaAKI(%pXm[ b G> wu}|- H͸= U6`U*$xL{XnCӘpGZ#@j:סy褩Cr"TMLLVQ!&9jJҸX;Bj.q^w<)U7>a8܎Vo6Ss9:|tr0""Od F-wΙ?6b@j],G;G&j nF-x~NO}V*nlQ~R@ѸONvKXr:}SfNMJEhO9%b-( fKx!cixxɸ0ܕ5kyU$G_/60hAօͱ=~zTshU2=%{^+T8_RGr΍,]ʄ8xPG^w mC?WrxН)tYϜ. "&B -XMB(ϡk/Voi&\Ц#BᾕUH]QDEC,3e(]B;gh oH@ Q0ZF͢_zHlɍ]d>̿ap髅sPTvʃp>>E͑ ~M+7lXq T7/f:0;i|WRi%0N\?q& f?hA4A\{~X#V!70skIoV67 {rZ*9'7q+ҥ 1QY_3GqN8!`}AOĄQsI׳xNJ=A5ǕXHQ~qh%A.>!ܚ"ZlL#KM{𔾅;b&_ncq z}fJ,ݲ @LfzQw%S&ϋ+`sϝ#SOLO} \2A)[ dQiGul^ ިrm, i-Rn]5 곬_6)t {to0nh qLHG?Qm++G *+#*V#X1bEŊ+*^QqĈ##*FDT F *"V FI t}%> ߭_)Dc y (za\cݹkC:ϳ˯F_0QUU][3̯(jFs]]R#ihFqUM^5 PќmRKIԕt*HJw]_k:ބAZDyނalJaԻQtl+/b^GtgH64^|'v<l>n-%(ϾiOFkS76B^]9z]o ~5\0R>orU2΀0~?A{CXPRGX!?R 6g>6>S[%YrA+ %+BŐw$!o ps fRŸKb1̦eSǂINGa#DjM.cAgڊ0.X+w?nnkll5Ywo?ߤn+y)gT i^i))61!s TȤqrQb UM4lFE]N(uu!E̤E.h:#b (95zx )=Qz71V#F}Y!SWSz# @bˍ+a@J.Bs#$Ӂ$-  ;JRzGmɘFU*]B:þDtr鋛Y2t7a3:aL@`s.$Zʃ'XN٘0Qe} %'E;at79a(VniۨgmJ+YYQ<&Ri¾Dju73#&*z+Y+wTT7ۗ'Wtr鉛I7݀NF_M'-)}l*' [l:>-KpvbkNѩ>;(w9\$IGlCc4K,vʌ_{UΡD%.>{G$jJiWeauΪ?g;k/֙~[գp%SNBIv,L@o(Q AdVr1N~ ct! 7~Pӽg]r!; ̈́{C6k<{Q'4X,鹮R9qob c@)[԰fDL+78ֈ5F^qF93(X+A^(z Tz;[y\?,tk3c(z7[ ";_Y> +FF[Ԍ)G;cxl8V/: 6$qf77鬠ca eYxy #?LT'7I10͇6o֔rkஒHh[]ؚݶ&ufCZoT0oAnΙuD.vfw,xA $ k i>t1ĵ4[+>3QjVM-*5"&=&InH0:KǙrUt^P0 ]XAO 3`ti3rj l9}9ט,AYTwIĠomJЌTo$A3RN2.J2.J4slIM7TBL \ 4Ӟ'8eda`K$ 7$+ĕR.ftyu/ K+o=1GP 0'GL3~ Eh`J]΀:MB78v#f!O/1ӠxE"1( xԋe=!k=y9ڔR]R@3"\%0Y^z[LL1H?^7ѐR;hE)ы6Nz&EÐVCSJuF4#IЌEIf.J4sru"+Өàd|:.}3U\Y%d@lӷ6BF͈73x#| ʦu|t*5zvM#%E^YUoQ/0Q@3o ?{q}FRf(36rUrM:yvlvޖtqӨ۠u m9 n5I7|FPf(TLՆ.su4Yb%ҼÉǽODZJiUC3_!`N^fZQh(R0h`тҨGFͼY,C-@KUbk'% ֥.9$hڃRڲHfN=/-/sIЌTo$A3RN2.J2.J4Vf*LUhF@3RIoܧ 9Őo|+SHuD{ts'b3 eX ^XcVdr RJPI 蝗${,M|ǣqzP(0:).6˱HA3q?;rdi嗠""Csp9H)3TӳHc7:1iSALqAL+OIu끭XR Q-ƀhOB Cffz4#ubixv4qO|AOajVq*l)AamJ;bjsf`qCgԆ$#9ѝVx7'RA3e(̰%Wz;fC`eUҚws u4#@abbO,Ч^YedV錦GĤbT:G[!\v2tJW!{x5U!m6)f5h-E {)'pަfJPJ Wo*|C>2`:"r%(6mkGtRH)(]<|rBHcƇPh؃MUQ$X{gLGP 0 'kˣQ}BMA3fVj`Q/PQ=rPm0V H_&]/9Lˀ6 * DrU铒O0_MCEDMij<G hUVjWVF@S6|CB&y}@ |eTc`\9e]U6X=Y w5PaJ= )Ca.1^ , 8Se!T"-)eebwRU@CtiR $kav- PfR쉏2.RsZsn NzWOfzރfHp#uzBvW8>)|;V텆rL$ɕy.W3+zO%a08ʅ|5K:B·n/?9Ag11Qf2.?Huc3%\7¶ei*%vGT6pZQou{I*$Wn/ hC~;A ,Vk[6rsq3h`irȽ4t̏ k‰8 [Qq[ҊʹKbγdXD^Β_NPAՇ@U]}-tJ{Ί+#+""*VD@D *+"VD@D X1Q"Qq!$np3Ä>| A y;|lkX[ZQ8r|[wy/]b8uﳝ|q KrAq \FҬip9ݷF p|*~ՋԦ]@s[aW2d#Ž--o=Q'F:+aiCE"bb b1Z-pBŃ{޽D q+uKQF^WT>Ѩ+ٺ"5?rs}5Wt]g&̥f3ChG~?}<;nxaPG̠g q:YGH3 P-::pq_7if:4e Īy0bYe!HЅU?&47t+3SzۤK.W"jϟQW=8JcCM0 =PLc@{4{X3i4f d _a/9ē mZ8,X}E: +jt4Ut[h 4 [P^u9ucaZuVi ͮE1}}* ]2@}y$%id\nEȥvh>LL3S7dϖ4U9EvyEo0ޢYj04=x]94ߜXФӡ~R8`QNܥFa0suNM#s~=Csn|6dlGZ征KG>X ֨?0rgk1Z$ըkHPncEc+x\ECs(۔6R61)ĄT dʼnD]^Q E (5;?~lEH/3oY0`=Nt4QG@/[_K\MysX\ɨQ"_МMSH1-RkA ]Ds;#ӃL<'j3/<0IiI3?R}l]B!}kcwfϏ"Q7;nrD!Kak6 \.o=NP =A b~cJOg2o@ NsJaI"Wuۗ:{RP*3ffє%5 뻞Ve 85ܙ[ [)CZU>2 {cȳM1>r_I34Ci -iH͆OIgO$5F'&htRjQFުہV0IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/lib.png0000644000175000017500000000205312346515432024125 0ustar felixfelixPNG  IHDR szzsBIT|dIDATX_U?ffgXf(1$D YT z,Y7 %*Tԥ e383߽=uVs9f1;Z/?x3 k<;KF-rYyƎD`ߖ%~:skRmDQ ?LL P: u/qъ}sWu jMe+:[-C ug&NpQӂтL'-d{]8ׅFsE˶T+]$]ݶzBX +(%DP 5/.OOrSNj˯zA3bUxa^2,濻'ݳz/,Yp.\dEv"_}E\x& lUDod͕b~EИyjDcb^) uq"^EJ/8;93  ݿ=7tǍ*b`_wCbQuQDy4F5v3ΈĶ.o(x~OVp v7mtc nF|:|mgw fL%8v^ݒ&JLB H6d%(m u!7܌6~̭Wbd/85:SL?Tnm \ 5ےϖYŅS(Зp"3ɹ/,њ8g(xFrR}/kOtgΧMMۓ#`PM86m~ב֌Kt#P(x1"xZF4eai"%ӟypw|ak*BPh$>7ݎ8]{1<040"v̄6+l;Z!Ϙ;[OWm~P@[f"kUs zDke{*K?;nw±ZFJĮ; N%4|WEPTOE(勢1$E1_]~>J0ۓ|os{l<*eNM'493 Okd_87t}eb-|u`;>DAi~,f/&@ѓ`a<Y*ͺoa>3@>?W^/-$S`WVS5b]G346$Ԁ=Δ1!v5k|S"i. S]|U! &=FT''NaժU{o荎=g!=@g'tDbYձxq+Gc"irgMY{GD Vԯ`N=oHH5/YĹ <۶ˮCcLH_+(DGO|~;viM]s'Yp7TjŰ?ͺƘLa6D;IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/httpconsole_openfile.png0000644000175000017500000000324012346515432027601 0ustar felixfelixPNG  IHDREytEXtCreation Time+ #tIME+ pHYsodPLTEDiɷ̶7b_5щ5Yŋ7[8b[6]7ӂ^e776e6_]f56Lo#ӺuZjKӤzfFq'_ې:fٱhTef778_7vX҇55_66furyfff:dc[kllee9db[ ,1uˀЏ__͆[]__ͪy'IDATx횋v6`ˋKps YH I ^Ӧް{tf$ '6^A |I:HĊ+VX/+#*?擇'4p +/855"5C<>W5yU~'cuØ1+ǘ7X&ZnjzԬ ^71iahWXk*!>QSe6sgr秸tWv"1S^f1+|(Zٞ'_zЀ*Ӓfk^qCYɊP™Wͱ0l1`q5JVj/d;)Q;jEMna>p +uX(AJc pHV qT8r:o`ŝf6 Q؜udzfѠe F)A ]O*/n>Y9-|1ѧj45|y9Xh_MO 徿Y*eFg۟7ZQ"`i.-zX6`9ɖ`pndt^ 0*m1T3nra5%h&4wN/c0Zlȫ"akۮNuz[3K*׼Pֱ.%yMm2ZǺShߊu.vyMCSȟz!RЃk?0+~t[~;n&ςx @t۰;D? ڬH*>RLDX kHtBυ,pdx#NBL3j~BG>f'thr^:1 ƚaVMj8Ilc|a ?1 9~;sXS}fM~JS)N :XbŊw 5I(IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/player_play.png0000644000175000017500000000170112346515432025677 0ustar felixfelixPNG  IHDRĴl;sBIT|dtEXtSoftwarewww.inkscape.org<SIDAT8kW﹓.*mMK*B!l ZcԂ A.k[jbZ&IVmA+S)Mdv̎s|}{;xQVeѲ9;+5Numy}--jxC8OLm|;Ύ?4}1 k6n{fLxm :M[Ů6)n彔GzoƄ?*kV)M4ے U2Mw}7caMn !F(ŸdšPɏ%IJ`f(1}.YOv7mlzm^LfAQ A'lk*sSiYX ۶8fE`i6[>4 20;Bp2 ! @DQ~ِe*##GL̀2HB@ BdY5g[cZ 6o*HWj, $A.=7<}{v E \UUUA%d<|D"$]ֲӆ!ର( =Bki#cMݡ={`y _*Ggԓ,Yr;:^"~?X8'({7Dcc ٢HX @`jirva?8;R*MIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/bundle-active.png0000644000175000017500000000476612346515432026116 0ustar felixfelixPNG  IHDR szzsBIT|d pHYs : :dJtEXtSoftwarewww.inkscape.org<tEXtAuthorJakub Steiner/"tEXtSourcehttp://jimmac.musichall.cz/iItEXtCopyrightPublic Domain http://creativecommons.org/licenses/publicdomain/YIDATXkpU{}}?ț{ I )!B"JZ[XE::v):V+b:**by1nrߏs= .˙9{^k9ǵ:;W Nmjnfc'K19r%A9}=@Ej"uB99V&n_Cu7dD hMVIVl}r-w_ꚭ/ޚWo\e-OL[j2p@Llus+\q[W+VT:lGUciKx஺"d:{?ѴtUٳL\XHF4.<,9hG._8Ou<=o_o?w, d@2xB7[mB)ΏE&6:8Fcn:ɰ7p 15ƽ~S{wa3AJRcq8B߀c@!1! `"U0x> 9D3pte>yP 6 :s Qr]ބpFA'sOc3+Z["tJya^n@ ((ѓ ""(Hs8Noq6+Ձ.gUU R\(""1bX/g0B(DɀNgieu~0?ʲTJ@!#p9*_{{"\lM ۇ B(-VgpU:llV3bIPB;vy47՟UTwo?3ϵb;:wo+~9mwfZm.q{ҹv DubZ$|>Xl׮7yc_6ϭoyd&,ȉJ |"BP;:V\`uvѴCthM$7B>J ˉ׻=5ƼB;(!PU AC حypV(Z)4GE: lk1Off¨847 RUcF :,f . A8xC >QpEQv\ .Zot mp9tHHq |{& [nnNbpO+ǒXh~ j>tQ@08X%hi= )䧲"knbM,V^ L6+bKI_YHGtz߭˷:&'T" $&ň֣'FvW.{oDc*0Y\DQ@Iq.>cm6 `cLX{kVܼB T'@Re>x~p wOh ܶbDberEEX(`Z&!I\ 022˕5_ 7 s !?FEIl,@PUok<<^^_RIt j4ƒ$/"J.ˁl@ǂr' DODBχ%ex 5iY?y%T>Q4@  @ F#c"A2jE3CSmm{r6o?rU\dB0` #GOSJ5YQұXp03F+ YqW_v!GIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/openurl.png0000644000175000017500000000244712346515432025052 0ustar felixfelixPNG  IHDRĴl;bKGD pHYs B(xtIME+!{U͵IDAT8˵YlTew-tiBvJJ* U}D|2"D#hET JCL{ܹsg|䟜/'/'; OGc`A$IQPߎ ʋ+-=$XUϣrO 1ɯWcwߡ/}ρ:qwf\scK|5}ρǣ~m :TWMwgon*2ȪpG[K#%ȲGWpwڭ/>2 M땕:4V!G彏!I @dGWB M2:㻀αy48z[ZB(8@U!k&HDZgGbA$@Ue{h&)=T\Gu ilO$صGk8}ugD2eѳut"6mNuӴXȟIsdhx}G.rY =AY|>O$s~2VLT:MZ)R){wq}Ǻ*>GS\0-LvVI@OK*!vrud7v&s҆-PIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/bundle.png0000644000175000017500000000476012346515432024637 0ustar felixfelixPNG  IHDR szzsBIT|d IDATXW{pT}w7yE$$AbH@N;2"J;LǶZ"j*NV4(L l޻;gBcX̜s~߽7aKVl @i'L.fc|& GL7v{8׏| h7?P˷:̴iix1Ax)6b%+߿d6m6l²{d|6dy]G4M{yJNMd#Y{_Q}f^mke\W[ԾϦ㑩?Vn0ӻ~E&B«Xc=U9L 7M[;a =۠&TYMncfO<|/)-l{ćsB9؂tl޲NY  ;y2[QSR񝏠\%Qή]F|(&1"1 "KMDG'(큤C":{˙n'`ČTT:Â45[hp'?$ʊː˻]M^`ժG9E.6ݻYRl2(!70TSC5ȳgە^/qʍju>;if~Ն9o.*;wF܌y hXUUgFz$uIV@/_>{{6,_aYU20P=n_վnm]'X8MS/50"Q(c`p"@@n3YɚI ڶnۺA~e^o fWT;j}8pQ B\JB;=ĸIFA`H3R U`6(EJ">}eb@JxF1 E ,Vk0U%#))QEVQVѨnUUBx"|KQ{ͣeUd4jOq.s 򺥖c[] Jwǐn[P^u^UE I:yϤzG 0xȒ1de~ ~cG_\t Ҍ[DA^v O*! a=wF'GKfܷe5AfR# 2qјgܷ|q:.WǘcXpRA \89*]5V$*bjуIuE82xwq[p޹,8qⵈ9ڨKq:xJ(c!tu0;Ǡ)JKʶRIR@Et"tR-Ὣ`/́XCGqPqA%*i9QPLwbzh0F=0{]ftzg^V>Ga6QR1ȢJ{@bDPe Ѱ4FĨxT‚ ܚn[+ R+$>oNg 8~&TAn^*6#t|b6 +ۆL#v>K۾șf,z( kVeU((g%e5Yqq:=;[~dޭ 746DqL:q;:.O4,\XQF̞}(~imy3Y|)GfzzdWݱ6-Y/+Z{ wfxa!|P -\n-#k$JFM~y Dr @_OKSVnYo88$ΞޮfU,o5"ɢs_--_oi:~DcJ"64ѥoQP5dfgp>ATMJhUAv! &]=.)v' @ruKeNFE-Q-3 PAh72-8Hb pfZž(e2FO5K|ͥdߗMe"z8 USIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/httpconsole_ppc2003_3.png0000644000175000017500000004446212346515432027324 0ustar felixfelixPNG  IHDR@ ftIMEtjb0 pHYs  ~HIDATx]/|Jמ"Dň DQX@XQqE+"VD"⊈+ Db"Q$!߽< p3ggS\4xh9 (JK=?KlE43B͒&1;=<_ؠA/ufbD# OGJ:v@vmАVWZfB,aXLaZ$&FGA$XN1P(c loHmr\ar-[@V}e 9GZôE1tZUvo$ވ<*K'&bX 70qls\meFދ)6b׫:Eqo/;Dm c7m?E| Bk1Q'#G$n zGdcFPV"/|Sy+z ZiE| VǝF飳 95,uK 9oV%b&H38(kνH*25 @3U3sȢaǟ25 Q0Ԯ 'l#[X"5E u1+Z9GjUBVG2_v 6ߐ6LE3]Gr/WKl^-AE)wf(<ۘ#el'd"WoѭiE⾛;MF6,ɻ+x=tVv`Q^vpm(~el&ֵG4 o" {f$ܜ]lyhPY?gE"JJ !`3tq`UW:lveDWY ?WnC|ȦX& Wӽ O9"h& wC6~h8]C?Cf+v2aKmjHBle:ҞoT8@en5K B(k+u'Z_+X9e Smry*7.];-m>1<`gH8B2 IFJ2k5>{KK7t ׾0p:_NwdOJC%9_:9}~7aj0infanXmnkMؚ0V]ܻ#+*o ~=H.*֯Y4fvq *%yʹ ]vMy&qw$%j?+R*k]Z]wQL;8qv=uǓ+3s6aw{H xuH9;Uйt<X8+ewr52S*M{lҽ[A8?+ٷls5cF/Kg0rL32ױCف|}Cz./gJHRTAc} =cENj2θ_􍥸Jz`to1Ʒ"ims>kgy3l: %<<=3b3q7PGw$)gڿRIˢ]9m6%Yn Uڬ*P1^w2k ~-}sðXfhJQǸokwۧyoV\A{o?"wlf5=q`v"FkRi?wEf,ɾ+~v~M9z{NZX&+)fVxl`=֯m~i BΜ)c%f9NK*B_!+U|+(_%Ulfl\sk /0 wѪ'\KO_o 1Bc==tτ]R'henk1po[c 4x+/V,?hHA +j7| ?zy 1v7 uB7}W eY?'@(igw'25-3~"f]pE9Ż9$H$AҨ$4T{L#92 Eq {ǭSK?+t6/(qƀ H>RmL%^߁Nj]%e0Fsj*6cK=ɭP3ۇIIDB8{5% 6OLG|tEk EzĢ; 'cC38 6kͽTeLU::Xr+-KGc,rA# {Zok8l4 zC[OG=eR`:텾u2`ӛ;?|D> ++%܇LA- /(,\oQ0wSZ `Ï|ZxC/GdM-S`kz~h..8XeF``Ҋ;Ɍej*ALn԰86/=,HfxD΅2$űpIx .pИޔ)LU5|)R fKd&xHڹw϶Lo~ԫmR .w/ѿS6$IVL|7۽}Ʋˇ{mueٶ}W $)p t>\~ouor39H T_,H.bPwһT.KI>qgߺ$gY1rTgRKV7N@yNoLrI$F$=[ V:Xi)(0::1uX' < QNkj ]4)b?s~-Nُv~cDJS²=1LO?}\5. Z싣@VTwNofS62溡Imrx[q|% BNI7g#FӁi^Rrg#ל.!x! PH3Jbg,l=z"4nqc_3W t$bW+>z'nXR?D܇O&W^65 &S&{>ya<`أ-wcj#؀Š8.ڒ4 piBg8JZl=22Udȹ;seHGQIritȨ Kxv^r sG-Cjڑ 8'J=V9?EHdFS(-Aϱ)s ܍E_Fs`߭c,:iD3ʶ,XlY>|Xe m /#zvhKz^B᭬$N7JFXJ(N6E ) Q}[*5Qb4dC3aڑ)-H'= o-ZڇȪ ʓ !}0"Ճ?&*,KrAqҔ:Uj a])X,mhDn,op IW@&٠lH"Aڐ'6ln^͆>J Z08yX wGNn-/PQ(%ax}O;uE`FNXJaxS-#h? ҩDDHHzI2bj1SevfF~V!t]e[bnKP@82T8̀mMJjA4!܂Nkd HI yϝuPMȗQ#C7%&S0~E~E7"BkBڹfYN 8b y ytt:@:;K{aD! a!kh.GBR>_nF͋ᠣӝ;];YQcͮ4:(ֆ!H)%M@\nZ G¬Ikt IKwȎ0 r +mkvO'ƃs]mcWc)A,d*C|?woT(sLussu)‚+NqK6h {&}hR>BӪl{(HXҭ3#HEtD%ZU\Y5 cc)ie53 ʣ?[of VAS3mEdId,ccp>RP ~ew#̒n}D(,˂:%x?!? !'t=14" $=l ʱ?HÞKmNE+D#E>&ٻZF.<"b"@\1""QQQQQX"1⊈D""bwf n23g{ua,'9"C#:@t%ڟk2TЈ4?mAc& l3V減A8}Dфzz OxwKpAHBCy"O~xԡQ n4֡M q^Sr`/F{`*4b:M{_!mHDERo~IR0@|j:-b#4%QPQzehF[8튕 BPhŇB MD;'+B\&Bh/+0]*Sg{xw`ū#ٶtP26Zˁ}4(|3^nVPthɇnψwOCE&$q]UUCo6sZD.&Ŏ:Fc4 L0&)a'$<@N$@TTUaWp6}E3axZXyXQTq2Tt븢VŜm`bBGrZ>{!K÷fPRh2+3誮5(s83Z 40KY& /XYJ Ӕxqd(tTP zў*.T•695?ƕP:/f aIU+ ]*0q۠I-d{PjIe&311nV&6B&Xd3n<;͙#=Qppdɳ q%^JVS4b2si-6,/.CYne2UbZp9ͪ,.wUU5 d˕SPy'd% ך._rվ С4&+9C\:IZ'гEC VA!%+r3z. UXhg xYpmEL̓Wh>}Lpg[o|#y' ] wz;pjg4rA:]oDP}o/zl^ڰ=ŽwsAmU!N !$[B))k/pED{>;Ž:+JWgE';BҳyA?Bȵ8NZN23CTcum\{)"O u 3l7FM<ΰc .T28'%؄E{J[uh"iWjfc(.\a3\M>l2$.<=^}~Iw63# ƞȡڟyQ7({ʞnCs!tplІXLY[n;ٞśH\lEtDO> MsWN^!U08K[M<Ùa1ѐ):P/ᱛ8CO^A\h^ oRCTa;o9dCO9lɇïB ~^˝$fKj@;%b6)2K\)<亗TzZ*;Md愿~;ēnqtgsz5, cH'ȉ3&7cIl"8iif7̴$n5Co\3ն., f$ ,z/bn,H2,405T%|,\*6񧶻7Z` ͜ j*vHKɨdF"V+ &֫rkvL:DqA1ޖݣ|'8# TeZ{.Doj2Fa~44]œ{& #wzZZe_T֕ѓWս4xZz Ti񠧨u '(;SG'TL8Fʍs r*=9ic/USZE!ы/.=VZkgyy VΗfNP6Z{o7U~^W~_KMQZ+VaJ#.EAZR !ZwzucB,yY,3 7Rg@vt  h념zU>q 0,龓ubR=ȇXᯫh%Q˟oWqg!hvze:74;6U9p/U !} Ua p2}UuyA&r8+81q'O:Nl&2I)*^ͪ HAoWB: ;@^kt'(Dp9kC˲&ЦyPW1ߋ(Phx Kvמ, |Ǯ; TP8+zv4fkc{`TH(rhHw[RM"yZSPi[  w$^X? t:OΊ)z+in\[PCM%HY ^y(/԰WIbEQ/ܥR&{:kB7> N*(h~/w zE̶m{jm `d(ړ;,>Wl;rn;qJ=7ʝc^vYj){2oL%Qї[߅Mz̬{ >[Z;C?ܙ3RAS)b6ts&Y2ZG0]Lf3 n"K*(*<*,B,K%s ݼ1#g]lZU&.~[i6 ,B?Z)+F1?-deVg+W ‡>0n7DQ \\lK9۱PO!]&kkVx on8Z̬E!fkh=T%EAdF޻~o?[,)m$qYGZnpOr-OlngWY3`dߏ־_ RLGp;aYB_4G}az4~6PBT8^L[ajΈ͍6C imPm8֡-by03n|~b-ݒ.6 Zz߅L=M@NReA.{6' Ӛ0M ʧ3>!blV)X^6e.A̙;u'&<{of4d3۸n+&˲;w$ ]1u$ɳ7q|F D{`Qح̥ {O OJ\0Uv%`n'/cy6d!e?F4f_Aa\% 6ˡNQƧtѥ{"Vd_]M!Hx}.B,Y`s\ ]!䒂nѷP؅@ @dy)5d&Q@QIi_sFz2 hކS濥-t_j84YQd{n~Bƞjt71g.u7e8Lwޟ]wv{z(+i= Ḣ.I'fR) DHyC+7Y77I3c>r)9@5[kfvѮnpaCOvc|Z lZh0ް`'{wznPRyz!E/ p& [0I)wxꗎfæV|&lq89].ƻ̆Fdr:hc-՜v&mЄ)܅I*;*OBqV-NO9>GSkqM5)L 955β,6(r٦ ܵ,sh ҊR{4 hbZN9`/l刢u-8-W~0SY糭[T0OS"cT;qzd 2k݊u KiѯσShd?=>M8=V^l6{Ԭ^c[|x9}= c]s!> NXY -[ߝ뗔.DwoWCg8릫qk"k r:iP9rLIe, *4GeU.N֡xtS.8jzKJ#Bxįߖ"-tp%K^S-H].-qzVc(FfIILWcfTE-J{'iߒYI@"A"Ho#2nA[ Bsa 3jrx=6*y% F;eO@Msdx1Я['R pjz{v8E'뱳QB_"T]€GH9S]92G~>[[(D-)4Gr̰\ Sw{\uԫ ;$tE= &LE?灄}5]$K{~Oe Z|bvqP~D\,t8QK?ΜXysfvLGjs3GAk[|: CU Qo;?6hlF-Zzm57G/noHQ:o462O?]w ;ny3HND)Iglr8A4(լ%??:_|Z:MKkfhXCn؎@2c2]=1v\rd0i 3ҵHB#, x$苎!;@Q 05Ӧ5ݰ4<}8l{i{6f w%Vn&0&䂽O~;VK @HRLZPUkh [nѼ.:aDC >>?~Ehc q(mDY.ܚ))'q]+0#`f7`$+5L6ҝwЉ3]+" Ċ+"*@T V V VD@TD<"񈈊 DDĊĈ D;/&NK _r;x!aлObrhrLP\6UuY3cs'v([ QS\,O^"uG}-*Pf*aE1Ϻl}Apd;ѢNL 孨\穙'A41&9xtɤrKw =8В+fA ֢K8gsa( @'B⤒^3ML:eAlQ^GCIiw$I*lV%)/2M2pG+Ϥ>"om:~@) )WrJ^+)h&QCfI6=eM-}e|A3rcX,K($R~@K21(_=^n /(rAXV4:Mu-D )W"0@z-"X^_gh~1uAk ?+BHR{rOAZ,b{O8N@ùe¯:Nr ;^<Қ'O:[*: Q["=1ub$q=n 0GSgUsD8m n K'Ȟa &;/BtAXSoZ娾p!$[C\D\ _I[^ E1QQfB]84O:W;8H֕SM\l&3nB6{0(X'-U9fS\e~ӝ(:T/_B:x3S8tԥlbLf%;ʁ vֽΰ<11,uE) \>uPvbGB0,0n{+RU26IH"evxDq|96ueqdR54 cŠ-BL*m魳edK.M3>RZWvsLYe313Y61X )INoxlݍNkj*jA+[ ۠QW5V34WtI *[`(p%jIqH:V~tRnz ;"S'^xݜu/ jAڅŋJsPK2X=`"Jzcc(px?;&`Yr,2kTTնѠ1@"?s>DйDwwDԵ&D WrLbQh,H8p2CjI!4 ʳHNڵ^ $6? *%h.)J'؄g`({@-pRKm}j4EE.twoZzHNv4S"Dž. ,D+ { R$BQJ|?I4gIfJ*1L}5ba({@-l4vM)EE*vZ+:a9&<)ZdzYU3)c#!CjYBB/=$ NZ lV)C⍕RVɫRP W \Md \ W+-TS| Ft J\WNۡ-.Z wI6IL?~WL]@Emջ!b.&%D_a eZ:tfz׹xlB?6W tɍbֺ[Tj.9Cs5LXthz¿U̇i=ڃkOhIŽ߸0 zL|A=5uCS}Mk%Ommͅu0jxLrweAP=Gmz'{.v|qNN{G.e~sK?!.gW0Gҕ%j_5Ǚ_5x*w{n]._E z.i:F*c25r_5~$z[7rqNٴd\Ck ~tUެ8tN?O4"'!tno#I.`&GΊ~*yM֗eE[g$ںL"k38):fXx9xYw?5 pSh1:sޏuUHCICʄkйxL @Κz(bFH(l53 Wչ}VکS]Sh2qϚ:13X`LЂ[AS`P1* m$R7z§r'aW&䢪+ 뱩g F-7x'ҌS:vCig9þ/}؀>Y]s*uϖw]\ٱIxLCst Mr+'%Qfo%q3'w%P(ׄl78M%^:U8d6{Х}"xOZmknMzYfrBn3ؑx> DA8>X%p| MrA]5]%M^fU%Nr;NFSt)ٙ2 *UQ)_QH+4Eֳ_ܳ](9vTCWg?}3:c/9$u##j,ncPY\ʣ1jl^CX4V>9S ;pc&|{GG]KD/ߑ7qpĸՇC|;qdWjesKT;h w{3> Tbrmd?/D6cpKTcb6Q4UU!iuSkI .n`W 3Z~& 0sKT(͵c_ )Za)c{"U,\SZꀤcs!";Z= E]e\Q25 PSLn& 4M h#A. QK7Mc>.FsHV4Ї7|YNF:n&K_Ʃ2R4+E :|R/5"7tzhF\ \\ohV4Wvʩ.5S +t3c#1 %p, Q + rM94@l,]|[cYՏRPlӏ\\/,=o%c6x=̔=x9<mv<A+&2[U 8#P8NwqKv I]f:v<'ncbĎv1 !)F4pmSCRv/9$_@sH ;Tv!)\Q+* \ڝZ \(\hV3VZ1V(J6{ Q~Y.-V=+jGtz0Cq7*ooajc \hQ3 M'SsƤ}|[vs'9͘SH`(a/e+&q,y< z&(sCڪ\Yv;XXQ +d'R[hX2gh? 'ă'p^dNHG#LO[:{#g0V+ dP>7?3!=xm|srPID*doPX թZ5=%WÐNIr ҿ,K6~hBz)I҂srO(3V>X*_qu2U 㷾9c:~@7wr>;=Đ 9Mѷ( J.p_Bf<<6k$zB(<|{>}߅8gvm/Z'cC|Jqu|emiwNR_b\6yІ\;rqK(mhS#]&ں7@`h+B%ceyŒFÝ$Fe1qjc>R%c<2q 8t庺uFYKX!<]59SU SYqL3=jXTQMqkLhC8É&sQ%M@`^wr!*kc*Ŏ$% xkC;)~}vީ&1VެY5 gIcӼ,^IRVTR'K?>;1x<)m>;^<]4_\\\\\Mp.\htl6>K_,d{z<*^6>1Ș6f4CeҗXgF>Ujξhso6YE8A[bTp(!5ۖ<}5]n8&<B~&zj+<tiɐ cڟ5335fD{/iL?i)PǴw}vryq+j?ٓOy;޴^#aޘ I3~ZwHY4 p޿\>l#ӱp6<]˛. bzT&!nxג{Nw L~ޜuewCCWмcJ&mH!f ThXwig|ͫ&QPk B6H}[u-LiE\L0_ROcZFN+DPtP^liMXkhN0M[ iyG/3y$.d&"Yf4)/sH} ϏTU[ș,N`(zGF^m\‘6E1ul;1i fX.*yô_ ]9aRmi;]؟k(BiX.1Jn"9枋u `<{aYN0W4C#{{A[s3GN4ܰ?mvVڞ=hUN3g97x,GŠX"n(&K]!8ǐ8w۔_FmpFGQUab)a54iaߴz'Ҙ*YrTcPJ|Ǵ.tI||t2h[+Sy-~Hf1AR(اN#{yiW +u:K߈4jyiWOq Nh* XOh mw!T43M؉$cLnOؽN'H)5ݟރ8gydӗu=CW8 a+]'{uZGe|ڮWvG^oJCիk_;'PCIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/view-refresh.png0000644000175000017500000000252412346515432025770 0ustar felixfelixPNG  IHDRĴl;sBIT|dtEXtSoftwarewww.inkscape.org<IDAT8iLg;3;K9[kEh&1iOM&415iZ$54iGb53LNUxO&3E,kÓ]zCM/ >5+5nmJ_;$ nB8,!Xd1 CH `"wĴUtyh*K1C!vò)B0cK`e)N,MZ.j\귊Ԥx iNl.HH01HK97rŢ.jHc,ҎGH^V@s>⪦1ǸqFO;Jkdl9ƀnL)@VZPv>,}\Gyd\5Bi^߉ հNITɰHll͜3nӖ)?FU4/],a}@8qܝ01kr08Đȁ-=])nJXb\d"CUzm)c5;_ft/EĴyϋW 3tǾg'NƐ֐8'k+z"0g4C5&8߱im˺,7`"0/M.R]MG e/$"0Ƥ FﺸqQʝ%իOMQ2ScaC0L ]qC=81raa"gu~s=}5)++ZZp:UFLߟ}6uE$ }͛ /PDFn%! !F\GPѢ1&́D a7oEcD0Ț)i\r`IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/document-open.png0000644000175000017500000000162712346515432026142 0ustar felixfelixPNG  IHDRĴl;sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAT8OhU?ofv6Y"h6 EP=GdLsVxEAD̩g(Bjm͡lCI7ݝy{nwӨI1}˲R9sp&4MۻKg~snb,.~q|雥)`ι 63(rTPUN^<ʅIӴ?03TU'".]41'8sw\|`jTUpΑ)W5@FDx)wP!:-H"0r /T5h2cD*B.XDbW'܎_Y뵗;vg,hB|JQtwf3#rcs9׾|ͣClV{zbKGd[6XDKcffV_P{kQua+Uu0H؏ԠEW#:f a:^p# @P@nP#/F7B^ïrP{Q&;+1UD{[zEGy+GT'W"`lw+Z[}?l\;NQYм k1 PVv88n<l$:XDbj[bl6ύz`(@0Sm_#8y寫׫F=+̤Xrݫ Opa,2=eY\n0yT6WwaIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/images/go-home.png0000644000175000017500000000163012346515432024712 0ustar felixfelixPNG  IHDRĴl;bKGD pHYs B(xtIME #oUO%IDAT8˥oE:m@]Dm!U4@(4R/ *j-YU"_S`TH' :R/=B9A5B\ ]MDHݝ7yoVp69~9 mޚczǶ<ѾM~-v׸8'a< ѝ;xmqQuAֽ{ d]󇁋 0BgmJ)/EjNG?'.0tF.biǢm`1\ǡGl~^<Ω6WRm+="uѶل]dp'}##J&iZy03]|:d!Hǁn6Af/y ļuRrusxFLEڄо3LΟò@k eYdealrt~ho300]n>,0;O٥gg.-͝[O?dO7׿E>BG>vJ:Й3oĥ`|i˓ A1FoZ0ȿ~p5~hH$0M00MTnߛl؈H)IU QC)R c<dK;(r4[4QOE+M6ֈI&A)&b{RTm-" |0F=JEet(B)җ'KMwP! ڝ lؚX<%خaOG?ifV(\&?IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/httpconsole/index.html0000644000175000017500000001631712346515432023411 0ustar felixfelix Bundle User Documentation - httpconsole, v4.0.1
Bundle: httpconsole
Version 4.0.1

Http Console

The Knopflerfish HTTP/HTML OSGi console is a small servlet that can be run on any OSGi platform with an installed HTTP server. It has been designed for use on devices with a small screen like mobile phones and pocket PC devices.

Description

HTTP console on pocketPC 2003
Image 1: HTTP console on pocketPC 2003

The Knopflerfish HTTP/HTML OSGi console is a small servlet that can be run on any OSGi platform with an installed HTTP server.

When started, the servlet registers at /servlet/console and allows access to the standard framework functions as bundle installation (both from URLs and using browser file upload), start, stop, update and uninstall. Additionally, detail info on a bundle such as state, manifest and services can be displayed.

Optionally, the HTTP console can request a login/pwd before enabling access. See configuration for details.

The HTTP console has been tested on Knopflerfish, Eclipse 3.0 and Oscar. It also runs well on Pocket PC (tested using KF on the IBM J9 VM).

The main screen lists all installed bundles. One or more bundles can be selected by marking the check box on the left. After selecting bundles, the operations available as toolbar icons can be performed.

Source is available via KF subversion


Usage

Toolbar

Open a local file
Image 2: Result after starting a bundle

Image 3: Open a local file

The toolbar display a set of command icons. When an icon is selected, the command will be performed. Any command result or errors will be displayed to the right of the bundle list.

Reload view Reload page
Install bundle from file Ask for a local bundle file, upload the file and install the bundle
Install bundle from URL Ask for a bundle URL and install this bundle
Start selected bundles Start selected bundles
Stop selected bundles Stop selected bundles
Update selected bundles Update selected bundles
Uninstall selected bundles Uninstall selected bundles
Show info for selected bundles Info about selected bundles. If no bundle is selected, show framework info
Show help Show help page


Bundle icons

Login screen
Image 4: Login screen

Each bundle is displayed using an icon, the bundle's name and the bundle description. If a bundle's icon is clicked, the bundle is selected, and the bundle info page is displayed.

Bundle with activator
Started bundle with activator
Bundle without activator
Started bundle without activator

Configuration using Framework Properties

The HTTP console can be configured using system properties:

Name Description Value type Default value
org.knopflerfish.httpconsole.alias Alias for servlet registration. If set to '/', the http root will used for the console. String /servlet/console
org.knopflerfish.httpconsole.filter Filter string for matching HttpServices. This can be used to only show the console in some registered HttpServices. String (objectclass=org.osgi.service.http.HttpService)
org.knopflerfish.httpconsole.requirelogin If true, require login, using name and password. boolean false
org.knopflerfish.httpconsole.user User name required for login. String admin
org.knopflerfish.httpconsole.pwd User password required for login. String admin
org.knopflerfish.httpconsole.expirationtime Expiration time for login sessions, in seconds. After this time, the user will be logged out. int (seconds) 600

Bundle Jar docs

httpconsole_all-4.0.1

Exported Packages

No exported packages.
knopflerfish-osgi-5.1.0/docs/bundledoc/bundledoc_main.html0000644000175000017500000000223412346515440022673 0ustar felixfelix Knopflerfish - Framework and Bundle User Documentation

Framework and Bundle Documentation for Users and Developers

This section contains user's documentation on the framework and bundles included in this Knopflerfish distribution.

Use the list to the left to select documentation. The list is sectioned in Framework and Extension Bundles, Knopflerfish OSGi bundles and Knopflerfish Bundles.

At the top left there are links that navigates back to the other sections of the Knopflerfish documentation.

knopflerfish-osgi-5.1.0/docs/bundledoc/kxml/0000755000175000017500000000000012475375714020027 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/kxml/index.html0000644000175000017500000000665012346515432022021 0ustar felixfelix Bundle User Documentation - kxml, v2.3.0.kf4-001
Bundle: kxml
Version 2.3.0.kf4-001

kXML 2 XML parser

kXML - a lightweight low-footprint XML parser.

kXML 2

The kXML XML parser is a lighweight, low-footprint XML parser. It provides basic XML parse functionality which may be well enough for many siutations despite the limitations kXML has compared to a more full-featured parser.

See Also

Xalan, Xerces and the kXML 2 project on Sourceforge

Bundle Jar docs

kxml-2.3.0.kf4-001

Exported Packages

PackageVersionProviders
org.kxml2.io0.0.0kxml-2.3.0.kf4-001
org.kxml2.kdom0.0.0kxml-2.3.0.kf4-001
org.kxml2.wap0.0.0kxml-2.3.0.kf4-001
org.kxml2.wap.syncml0.0.0kxml-2.3.0.kf4-001
org.kxml2.wap.wml0.0.0kxml-2.3.0.kf4-001
org.kxml2.wap.wv0.0.0kxml-2.3.0.kf4-001
org.xmlpull.v11.1.3.1kxml-2.3.0.kf4-001
knopflerfish-osgi-5.1.0/docs/bundledoc/index.html0000644000175000017500000000247612346515440021047 0ustar felixfelix Knopflerfish - Framework and Bundle User Documentation knopflerfish-osgi-5.1.0/docs/bundledoc/consoletcp/0000755000175000017500000000000012475375714021225 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/consoletcp/index.html0000644000175000017500000000573212346515434023221 0ustar felixfelix Bundle User Documentation - consoletcp, v5.0.0
Bundle: consoletcp
Version 5.0.0

Console TCP

This bundle provides a tcp server that acts as a user interface to the KF console

Description

The Console TCP bundle is a tcp server that makes Knopflerfish console commands available to the end user. Any tcp client can be used to connect to it.

This bundle is typically used during development.

Configuration using the Configuration Manager

The tcp console bundle accepts a configuration with the PID
  org.knopflerfish.bundle.consoletcp.ConsoleTcp
and with the following properties:
host
Host name (IP address) of the interface to listen for tcp connections to the console on.
port
Port to listen for tcp connections to the console on.
um
If set to true User Management is required. I.e., if there is no UserAdmin service in the system login will be denied. When set to false and there is no UserAdmin service then the default user/password will be used.
requiredGroup
When UserAdmin is used the user must belong to this group to be allowed to log in.
forbiddenGroup
When UserAdmin is used the user must NOT belong to this group to be allowed to log in.
useTimeout
Enable/disable setting of SO_TIMEOUT for the client socket.
exitOnLogout
Indicates if the session should be closed if the user logs out. If this is not set to true, the session will be kept open, but no Authorization object will be present and hence the user will have no special rights.
defaultUser
The only user name that is accepted when no UserAdmin service is available.
defaultPassword
The password to accept when no UserAdmin service is available.

Bundle Jar docs

consoletcp_all-5.0.0
consoletcp-5.0.0

Exported Packages

No exported packages.
knopflerfish-osgi-5.1.0/docs/bundledoc/logcommands/0000755000175000017500000000000012475375714021357 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/logcommands/index.html0000644000175000017500000002743512346515432023355 0ustar felixfelix Bundle User Documentation - logcommands, v5.0.0
Bundle: logcommands
Version 5.0.0

Logcommands

Log service console commands to view log entries and configure the log-service.

Description

The logcommands bundle publishes two command groups:
  • log - Log commands
  • logconfig - Configuration commands for the log
The log command group consists of a single command show that interacts directly with the log service to get and display available log entries. The logconfig command group offers commands for configuring a log service implementation. E.g., number of log entries to keep in memory, if entries should be printed to standard out or not, if entries are to be saved to a file or not.

Log - Log commands

The log command group consists of a single command, show, that interacts directly with the log-reader service to get and display available log entries.

The group contains the following command:

  • show [-help] [-f] [-h #hours#] [-l #level#] [-n #count#] [-s] [<bundle>] ...

This command group works with any OSGi compliant log-service implementation.

show

The show command is used to show selected log entries that are available from the log service, i.e., held in memory.

Entries will be ordered with the most recent entry first. If no bundle argument is supplied, log entries from all bundles are considered.

  show [-help] [-f] [-h #hours#] [-l #level#] [-n #count#] [-s] [<bundle>] ...

Parameters:

-help
Display command help text.
-f
Show only entries for events from the framework.
-h #hours#
Show only entries since #hours# back. Note that 'hours' is a float so that smaller time than one hour is possible.
-l #level#
Show only entries with minimum #level# of one of error, warning, info or debug.
-n #count#
Show at most #count# entries, that is, the #count# most recent entries that fulfills the selection criteria.
-s
Show the stack trace for exceptions.
<bundle>
Name or id of bundle. The value "*" may be used to list entries from all bundles except the framework itself.

Examples

Show log error entries.

  log> show -l error
  07/06 15:16:41 ERROR #19, messenger -
  Failed to load configuration / java.io.FileNotFoundException:
  /demo/gatespace/bin/host.conf
  (No such file or directory)
  07/06 15:16:41 ERROR FRAMEWORK -
  FrameworkError: org.osgi.framework.BundleException:
  Bundle.start: BundleActivator start failed
  07/06 15:16:41 ERROR #18, authentication -
  Failed to read KeyStore / java.net.MalformedURLException:
  null: java.lang.NullPointerException: 

Logconfig - Configuration commands for the log

The logconfig command group offers commands for configuring a log service implementation.

This command group only works with log service implementations that publishes a org.knopflerfish.service.log.LogConfig.

The group contains the following commands:

  • memory [-help] [<int>]
  • setlevel [-help] <level> [<bundle>] ...
  • showlevel [-help] [<bundle>] ...
  • out [-help] [-on | -off]
  • file [-help] [-on | -off [-size #size#] [-gen #gen#] [-flush | -noflush]
  • timestamp [-help] [<pattern>]

memory

The memory command is used to control the number of log entries that are held in memory.

If the command is given without any parameters the current maximum number of log entries is shown.

Show and set the number of log entries in memory.

  memory [-help] [<int>]
Parameters:
-help
Display command help text.
<int>
The maximum number of log entries held in memory.

setlevel

The setlevel command is used to control what log entries are actually written to the log. There is one default log level and in addition each bundle can have its own setting. A log level may also be set giving a bundle short name in which case all bundles with this name will be logged at the given level. The default level is used for bundles without log levels of their own.

Entries with a severity level higher or the same as the current default level will be logged. For example, with the default level set to warning, entries with level warning or error will be logged.

The severity order of the levels is:

  • ERROR
  • Warning
  • info
  • debug

Set log level.

  setlevel [-help] <level> [<bundle>] ...
Parameters:
-help
Display command help text.
<level>
The new log level. One of error, warning, info, debug or default.
<bundle>
URL, short name, or id of bundle. A URL or bundle id must be used if wanting to set the log level of one specific bundle. When supplying a bundle short name all bundles with this name will be logged at the given level. If no bundle is given the default log level is set.

showlevel

The showlevel command lists the default log level and the levels for the specified bundles, or for all bundles if no bundle is specified (only bundles with a level different from the default level are listed).

The output has columns for bundle id, log level and bundle name. A "*" in the id column indicates the default level, and a "-" in the same column indicates that the log level was set with a bundle short name or that the bundle is not yet installed. The bundle name column may contain a bundle short name or if the log level of a bundle not yet installed is set the bundle location will be displayed instead.

Show current log levels.

  showlevel [-help] [<bundle>] ...
Parameters:
-help
Display command help text.
<bundle>
URL, bundle short name or id. Shows level for a specific bundle if a bundle id or location is given. When supplying a bundle short name the log level for all bundles with this name will be displayed.
Example: Default and bundle log levels

  logconfig> setlevel warning console
  logconfig> showlevel
  *  debug    (default)
  2  Warning  console
  -  Warning  console   (default)

out

Enables printout of all log entries on standard out. The entries are written to the log as well.

The out command is disabled if no valid configuration has been received, that is, the Configuration Management(CM) component has not generated a configuration or the CM component is not available. See [1] for further description of the configuration procedure.

If the command is given without parameters the present setting is shown.

  out [-help] [-on | -off]
Parameters:
-help
Display command help text.
-on
Turns on writing of log entries to standard out.
-off
Turns off writing of log entries to standard out.

file

This command controls the writing of log entries to file, the size of log files, how many generations of log files to keep and whether each log entry should be flushed to file.

The file command is disabled if no valid configuration has been received, that is, the Configuration Management(CM) component has not generated a configuration or the CM component is not available. See [1] for further description of the configuration procedure.

If the command is given without parameters the present setting is shown.

Note that a change in log file size does not take effect until the present log file has been filled and a new is started.

Configures the writing of log entries to file.

  file [-help] [-on | -off [-size #size#] [-gen #gen#] [-flush | -noflush] 
Parameters:
-help
Display command help text.
-on
Turns on writing of log entries to file.
-off
Turns off writing of log entries to file. 1
-size #size#
Sets the maximum size (in characters) of a log file.
-gen #gen#
Sets the number of log file generations that are kept.
-flush
Turns on log file flushing after each log entry.
-noflush
Turns off log file flushing after each log entry.

timestamp

The timestamp command shows or sets the formatting pattern for the time-stamp in a log entry. This formatting pattern applies to log entries written to the file log and to the console when out has been activated. It does not apply to output of the log-command.

When called without an argument it prints the current formatting pattern.

  timestamp [-help] [<pattern>]
Parameters:
-help
Display command help text.
<pattern>
The new time-stamp formatting pattern. The pattern follows the rules for time formatting patterns defined by the java.text.SimpleDateFormat-class. The default pattern is "yyyyMMdd HH:mm:ss".
Example: Extend the time-stamp format to include milliseconds, then call without argument to check that the new pattern was applied.

  logconfig> timestamp 'yyyyMMdd HH:mm:ss.SSS'
  logconfig> timestamp
    time stamp pattern: 'yyyyMMdd HH:mm:ss.SSS'.

Examples

Turn on writing to standard out

      logconfig> out -on
    

Turn on flushing of buffers after each log entry.

      logconfig> file -flush
    

See Also

Log

Bundle Jar docs

logcommands-5.0.0

Exported Packages

No exported packages.
knopflerfish-osgi-5.1.0/docs/bundledoc/cm/0000755000175000017500000000000012475375714017453 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/cm/index.html0000644000175000017500000001462412346515430021443 0ustar felixfelix Bundle User Documentation - cm, v5.0.1
Bundle: cm
Version 5.0.1

Configuration Management

The Configuration Management bundle implements the OSGi defined org.orgi.service.cm package, a uniform way to manage bundle configurations.

Description

The Configuration Management bundle is designed to be a uniform way to handle bundle configuration. It contains the ManagedService interfaces to be implemented by bundles that need configuration data, and the ConfigurationAdmin service to be used by management bundles that modify configuration data.

The ConfigurationAdmin interface is the main interface to the Configuration Management component. It is the interface that is registered as a service in the Service Registry and it has methods for creating, retrieving, and listing configurations. The implementation of this interface is responsible for the persistent storage of configurations, and listens for registrations of ManagedServices and ManagedServiceFactories in the Service Registry and passes out configuration data, if available, when they appear.

The cm_commands, bundle provides a console command group to Configuration Management.

The Preference Service, is an alternative method for storing configuration data but it lacks the administrative functions the Configuration Management bundle provides.

Configuration data as XML files

The Knopflerfish CM implementation provides a legacy XML DTD, cm_data.dtd, that specifies one format for storing configurations as XML-documents. The Java package org.knopflerfish.shared.cm contains helper classes for writing and reading this XML format.

The cm_data XML-format is used by the import and export commands provided by the cm_commands console command bundle. It is also supported by the Directory Deployer bundle and by the Desktop plug-in bundle named CM-Desktop.

Limitations that are not specified cm_data.dtd:

  • The mode attribute on configurations and factory configurations is deprecated and not used. If present in the XML-document set the value to "new" for ordinary configuration and "update" for factory configuration instances.
  • Properties with a value of type array must have an element type that is either a primitive value or one of the types defined by the TYPE entity. Make sure that the length attribute on the array element is correct, otherwise the parsing will fail with strange error messages.
  • Properties with a value of type Vector must have all element of the same type and that type must be one of the types defined by the TYPE entity. Make sure that the length attribute on the array element is correct, otherwise the parsing will fail with strange error messages.

Configuration properties

Name Description Value type Default value
com.gatespace.bundle.cm.store Path to a directory that CM will use for its persistent storage. The default location when this property is un-set or empty is a sub-directory named cm_store in the bundles data-directory. This means that all configurations are lost when the framework is restarted with the -init option present (i.e., the framework property org.osgi.framework.storage.clean set to true).

Set this to a path pointing to some writable directory outside the frameworks cache directory (fwdir) if configuration data are to survive -init restarts.

String

See Also

cm_commands, prefs,

Bundle Jar docs

cm_all-5.0.1
cm_api-5.0.1
cm-5.0.1

Exported Packages

PackageVersionProviders
org.knopflerfish.shared.cm1.1.0cm_all-5.0.1, cm-5.0.1
org.osgi.service.cm1.5.0cm_all-5.0.1, cm_api-5.0.1
knopflerfish-osgi-5.1.0/docs/bundledoc/cm/cm_data.dtd0000644000175000017500000001147712346515430021536 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/bundledoc/xml/0000755000175000017500000000000012475375714017654 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/xml/index.html0000644000175000017500000000356612346515432021651 0ustar felixfelix Bundle User Documentation - xml, v4.0.0
Bundle: xml
Version 4.0.0

OSGi defined XML parser serive

An OSGi defined XML parser utlility service.

OSGi XML

The OSGi xml bundle is a utility bundle that allows any JAXP complient XML Parser and XML Transformer to register themselves as an OSGi parser and OSGI transformer.

Knopflerfish includes xalan and xerces bundles that have been wrapped as XML parsers and transformers using this util bundle.

See Also

Xalan Xerces

Bundle Jar docs

xml-4.0.0

Exported Packages

PackageVersionProviders
org.osgi.util.xml1.0.1xml-4.0.0
knopflerfish-osgi-5.1.0/docs/bundledoc/xml_index/0000755000175000017500000000000012475375714021043 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/xml_index/index.html0000644000175000017500000000315412346515432023031 0ustar felixfelix Bundle User Documentation - XML parsers in Knopflerfish

XML parsers in Knopflerfish

An overview of XML parsers in Knopflerfish

XML Parsers

There are several XML parsers included in Knopflerfish, serving different purposes.

The kXML parser is a light-weight, low foot-print xml parser that provides all the basic parse functionality, but has limitations compared to a more full featured parser. x

A more full featured parser is Xerces2 from Apache. Knopflerfish includes xerces, a bundlified version of Xerces 2.10.1. Alongside with xerces is also the xalan, a bundlified version of Xalan-Java, version 2.7.1.

There is also the Crimson-XML bundle which is primarily used in older version of Java that does not provide built-in XML, as well as for backwards compatibility.

knopflerfish-osgi-5.1.0/docs/bundledoc/repository_desktop/0000755000175000017500000000000012475375714023024 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/repository_desktop/images/0000755000175000017500000000000012475375714024271 5ustar felixfelix././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/docs/bundledoc/repository_desktop/images/repository_details_displayer_300.pngknopflerfish-osgi-5.1.0/docs/bundledoc/repository_desktop/images/repository_details_displayer_300.pn0000644000175000017500000013507012346515436033212 0ustar felixfelixPNG  IHDR,c AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  7iTXtXML:com.adobe.xmp 72 72 5 1 2 3\@IDATxi^Gu7>Fkl˖<l ` 8 0%Pd I [7ɇ[2/IKRIIQ͇@$Lf3O6`m0`6eɶlYӑ>먵< h^z^^ݻ>cv;'gggMLLů=zJ1terrm)ABe˖,GT,[ ߤkCȗ:{> oAum߯?f߅< /+k׮-V T{-Wpl4 64ֆ*J~oiK#ݷ-yihL>Uf}k[>yMצE5u.y_Qh32_&3?u^6_ҋgK֑ih6OZ$!ʵ gOg^v=| 4Sr /*Yv_.V&/ܿ\2ui9wz?wkYyvi{Q^L(ܳpvٺCs;LNxکĒO6J:Z^7(-]I2(}ݠt?d6>Ku m;n~9 <=#*+ʹgSƏ=+ug'M 2q򒮟Mi6(|g[\ҵ4vX-Mν/QtKT^̖Ok/|)1j|Ѳqy p[\tKx+ǧuerرegQ6m>|6;<߽;gK9MeAf7(mО!--]zLs_??;|ܷytr y5q.?iɼӖk[|I$hʊ߲Xm˿_Y͔s^W`FW\Q֯ c3e"[|"63rUِ65B@&m]gamhyG&鄰P;rܗEhy/Ƥlry+(c>[R6[^{pg9pP1MG&b|y;n+;&b\M,rLǸ2hL+Ǝs/RY^>5epLpgx8.q3>t:L kG淼[$/I7eUug;^&m%MToGm7h^6lƒ*ǎ5V̧L b@ŎCYzEEWg:#]cӾt l(1i`DWnm(MTfXzf^Ft Aiqٳlk+-ֶ}5O^g5Cg*<&ʡXd}>su]XޝK#}aͺrt9LX>#Geqo߁&hbb t+U۹O/֯ RʅyBG5LyDcܲeKY>'?~{zퟅɭvn/ЈU9&6Jws^ܲf͚@\( PyL p.: x}pqܹLxK/O+5b:5`Z x'ZzuY{{Sn2f {tgfY.KuDv4ƍUW]U> Y>GpqcdI۲ &zueh.m &Ot!>ʧ1iӦ)sR,u}{yv 5q[ls/kԕpꐉxehe(X8ݱcG{˺u8Vcw^|:>yϫKbu`c"@={?s eISʀav,aGi~~ǫy\@I_5'* ZhS^WUP뮻꘸+d[&2p5T c]vY7 1CKo~L|D/}.s}e/k3o|M@' G%پնfb/zы&p0VV-걟͐M{WFx3dbO_d4lڊ?#>sX?[fZ?}~TRm֚eNc0[@ot/x Q*~*+dc@ @:~fpۼ!0 CvV(#WR|s\`\ƌΛҗtMUV6ƌc xǛ33|w/yrƞ1-Ҵ=࡭ щ1MZQ񬴙G.^XG>Wxڅ7:B.^@N藛o)\4^ЗyYt+Xn[t)ӵ6&θ: 0t8: (3Xh3\q tp2 =p;yF3Vb~^j@D_ 8V^ƭ'cVIF 5n ST~|.~ f䑏*(è |چ^ ~f5Q0FKr&STȃizH[.ה#'tori~X~~lk<%^L~LGXhˢmx?o1?l A1c0[20` E2Q3F?`€ 6;% zs2J~06qf0a@=^{mQ7ג^ICe6Ӆ,rŝ+02|y dy+z PO=QL깚NGx/Y h}ץ]TƟ҇cM*@, X8x?kEUe/:8@GzF8YbfoDK7Pr4 0O'tR T>M3er!RNym<餫ە|Bօ42e>=>$#HKymue\:Z^O^bO!:Ɍj6ki>ts x<6O椙_҃hO m?\^'8#~/<ɩ5SV.v/{Pӎ/C#4oY͎/ [ۧyj__ĥ~ |4[0o+oVgu=`@^>Vp͆'.<4 xYf􎇕>atҳ\^Ѵim]Ֆ;]?2}m<]Yn5ʡx@tot-#D9,tX7 @l`_z68˃'F e!W'Js,@(:QX>224Vyy|cůKڏg&ߖx.qy m-6/_6#\<2\liޖ&Kʊ{V34}cnx7tت|ٓܛ\t+^Xn% L,<: P{QWH^AO &u+Z?IÛ& OВܤ{m2y6dLy}3Y7Y?r2І6oX<{ ӞHt.xnua5CK yi`WW<\Ͷgl)/+.,=g[9o:PnR6 &^D\^dtt>VG39~x ʹ+LRvEX5/Tvk~ bg"~ొ/oo":r׏ ~j Aȳ'i g_{˚: S OGw9ԭhW՚PH)kX" eL#/NO#i_@[BkT=rR_=aۜm{v>QC c ε5W{=PG:)6ϟNf,Φh3O@o8>I[ ⟬C8 YWOrd=mw͐ixe\^Ɠ6뒧-mJR>tSKkַW040j=\q˒S\1L@@@}bٟY=h[67(Ecw~wooS?S^17畏D&g1` _uyXԁ̂Ճ=S`f2x;YoF=V]8 ۿ]wϩi`ICpM#IvuYSvF5㹵Z#ʲyUb0ڬb ʐǓD^0Hx >nuH7+j7ޖ>rIg3K,4dz^[6S d><2HYt ]+~?ީ: b??=e1D{J[?Oeg~gʻ2{o+u=1 @GTl,l<3mL',u:o3$W_]c{G'؆H=G=6 oxCՇx 7Ac1+uQXN8鮓Ze7tAJ\|y%3sPLgf a\5>'>񉺁eppˬoV7 Ѯ߁{޺<Yנg is$HKmLT=:KD\Ry}X6؃a@[y@ޞP,1(^=SW~>@B')xː-ՁCƟG%>c|@//^@mPwc\ \y+g _f t o& /<rcwzV<8eȯe3F-Ӏ\7ҵ7E>rґpý13xڍ6ݒTi[iWNO tWs{=/ƙr3_vM؟L D3CX:[pt0PSP@2 : Aj3qFL=??[w la@4ϠQ2c~~<@"D< *c$z501k0 f}23ArVgLdVq Mb),xXٿ'%".!=4p4/>0;˥[;DN0[ xlx\9%.f ˇ|y5 72<<3Y ŒlxȌe''+` FI nmd:@z _X@H'iZƩCċLG@;zP^@hdh[& ?a}5(1(lD;(m۶HIGMB._Lg4$ 0JiY/]9b<HK5(G[x֒<,^ 0w>] F^Y>OztB!8`u$;yd^K䉷2d^޻T6/K'rd4SVϾ)à -o,?(m4 `1l,\Y~C,cu2J7-0>Ȑ`_g0 T֍N\he֕r(֛[tT h|t2,ti2 >2&=<}d_,mҶ,G8Y ,io0Zrc\OJ,9zi@l&$ ܸ6=sOH@4?X{lj{OrKA6 n۞>rAۀΦ6 xfYmSƾ~6(!m!D/|d;ԗeRA!yhEе6|eoci$mo{[o!IGJ<p'0Mwϼ!&gx|a:7ۻbzE9wS9 Xo@/ :Owju]В8bu87䞱;4h!O@څMv\ҟ+*jw(-f(o㟜ذ N^Q..s#Pҋ"F?6mk@ߒSYd%ˣ+׿YO{@1 # {08DڵmDRf7[>:( DO7zF H< ;u$ 3L 9@L︃3Hb0's4R7 I N>pQN <t\(8x0`+781ÓEo3\¡VQN2y2]`h/I!m?f\{1sң68SUu|TFL>48 # |?Xx?brVQ,#6fvދAkO#4 1~h<fseFaU~ر2 3 }Zp[cmiG5tH<3gt+Gx O(q8J椬y?4bu9~{A=o!͠69(s "/=y~mHz4<][<yʶi y/ޯ7Z~YwCxQZʩx+!hm`{,ϘCwT1xTxV6=m0RqYr~ߩ :d6W?p/u9^i7|SNz'Ȃ_JFp.#D$&F2:@6Ei =s}oXn2 G?*GacnLz=,i0>r[8u$ccWT>@@ L 6p1*@61 {b7C+8 o;Ra\|I 4H;3Řddj=e rv,=@R d ;!e3~GFr%K _$+ͪGS  FS\# iޛvVOw:m?s?W=O}t B_oF4X񽏗q}ӆ{˙+-I1HF`0*^̯Vc7@,#@k ̀(/><Fɘ6F0y $:d0ݛ͑uWÃfhm /`&OȀV $|W\UZ,,",OKu'*Ot萑e ͫN?~EFgmF7ȣ#yCz(U35c eĎ492S8@od c.%FOP'Htwgexphz~W~ ዧ%ghx1O]tj0@tPZ҈1Ϡ`Ђ>7[AOS2-_r}Km~ɲyM~:Cז$,.KK!ӳq4amx+{zXO5 @FOe @- Z6?e:BX8@ dZIJݣ[zKӏ'ٞѤ,Ζ:`-CZzСn9ԥK]ޥAýUt9ٽbٷ#b{R2BKeKA_IR'j)\-5=M(gy≚zW hM 6 LF}_}(YWfM=C$ P /:{b&lC25@-.%1<`Bg{)|ā3]=|#uxDN}CMxS'*#`qn @ 'eE | Y, u'%Kv~i~ O*?!-'XWLw6#IMof2 idg)87=9ɛKKkt}ri`IG ?؞,ז ]o2Px3 "u<*< ,}> 14h3b Y<' rrh{z R/@>3si#:<Ȏ3L W@pn2h2b4&M۵P>I_jG%]p?ʡSrwUc.Ko>2vkQMԥUPFsbc}^ Z=}! 16D3v1d<q@bH5fH|!sr%a*e C 93-8AS#IϺ۲@4齠S78 :D9 ^O x])/ W@^X&eӓ2&&&_:tuKsެ[ԃV){eW(A6|dHWu~} {\Yδ% «?A8г.L5^kއgcuO#ei@  8il1:`5`pϸ ^|0 d (냆K/!DWޘ \ |y21 3ҀO !O.J>3?`@N9@-&qOLO@X@>zIyk7msE7>g16@=tsqP>'yrRs}#';]t:]2t4KBq[kop AueG^ xL 9D2P nB N`03]n. _0 hY r`FBNĻ2KϺI&|^y_+dBMh$IhW6#;Q'e]<QzO<^[TP.+Y$Cd&+Y2ݫLFxhȑS8 :yV%ȋ'cd$OF0~Ҿ d{(e0D>%[*\f%byMA eȮi7=؀~S|2&e8cٲu8>2cd.0saٹs{BVT׺u*'vK>)h }Ax=fY!sNmKaQz;+O~u/5qM#Ag>_%+~/('@8KځZ#0ѿ:R{zhOr˲3࣌ Vȴz_n=^3L֝ygne^LC~Ps/,@IDATt6h:=dm>Rwʹ2M>SR+'$m^->((xf^޷Wv[.x!-S1soIx}\5Ћ::780| nCÇʡx#aժylA=Zg[x~5 hLys/]pL,+`үrO^xG.XfpVx guI Jtv#̽]Ѳ|E' ʍOS;8^r,v7ӁxD:Zu,[>Yv~+:1֜ Za{|}l,Xv|wk[i.w*tsԺUvLmG/fXJ 5cw2_-D;;slؼl橭3 B^`L ^y.8@/wjX2Ԁ2l3:aT32(gCh%`t2~[FM[ەs-Yf{E>W;~>tD^rkU>&\I ڞcd FկT?J@ &OC^O\ C/c3.=Y'kHg{Ԧ~dvt|ֻ{>Ҳ~Y[>s_~rI39۔{&pCWsrOTJ]Jnö?˸v]yY׿X;5=ttv!wҢ'k@u-՗uIk5eJw3LO/oB8!ǂSZZɜĠN }={^؂ѻr|ZL?*=j}~;љ _^nuGy}+,oxkd2`u/^g ƿc=5׆Cevk8hF|y %Ɩ(^8p 34N)k?71ٽ"־Fp[/qrS ~G"}Um]HYfw!|J ǂ~|t?'2p!Uw)L[zGQ} _m uTy莨kcBK %tH玕LUt 1Aog8TT a{zxfe3Y,@g o<.-A PHc 1@qS6`'ʶ/=mrLdz7%8}x`rz"^QƊFmV9ÆcF(w@ C\?AN7DC+Ȧ:̄n}]xk|ҟBEY?CrFgu.W_q^YK/~{K֗SᄈrϬ*3Kk}betXl98,2E\>0{{0b}]0γ55H>T>O| 0*&G㫢sGʱKw0+v3SQt ~ys(N@'Uf oUb_1hMɭ`Э %XRF)xu`vyuEX|cjk gV+ 2~,0o & 95xmk[,GO0L齬.E,rG,O/u+Khc#2/{a^!>=eẇ5U}{IUN& Z`8< qhCѴ_ʀM^K PpA[K]7%2U.1!Ůr6 +yBv([\gT$%.< *%d W4{%6'C]xvV3bu}r;^x ,^`6m3l Ae<@Ũ߶m[es;gCE&.^ `nX =p6%'+rfGԡL =o -Y4y{E? '-xJ8=a5W٩Hg }<3Et]Mg >1 \[.[f@zHuw3pԇoW둮.O4;N.^?ߥt+Fedd gQ9rue.i8E6ꟙg{Xdncal kk":,ikI3"wݲ6^I~c?}3`"q.ic{*ZDu)l`ਃ?PY6bzfrl70w&y} ;|0,%9b𵇃GK ,ҤAkoE02OO54ޑ`'C+Cx,x</i[^YWK%-yOًIyޓ%d_6/%Kh1㸚 C> N]U~O}w+sgwHmqSͷ\nw3أݧcDػLݳ:@ڻOc?u"?:[.7!f38p06{wT~kT̒_—i?ZSw?T {GRo;?ׄ-QՒ _җ˽-in8-}ky<~0g}˻c9-V8w}OFWG/GC yB՛EAG? KG dٺ<`T&ϫi7et}6ZϿrӦtӗGd/~!8MoSK ַYnDʚ<ڷ-U-O(ʧsޝtGz0y7iUniWUϺ2ޚ|vW% С^Ydo-uaBBjnVtپ֩OY56_< eTKyYy76?y.-;,ii 7vv\dð>TqLQM8s eOTx˖&G 7qh)hh6O)aw|t /&>9'ϼa⏏O<1hY/"O(2U?eYY - ɶ|y|+ۖiy=w<2nI?x /&]=/^$U]>lkR߲'x7V x_}]ny[Zw%_ՓtrD6 # \ح7 Ҏ)ѻ٤Md PR f<Y_TA^H%xnhГ?ˡq;6f.}_pxJo۫f˶gv],GqZ K}|<2&es~=֍X4 `e#Ve-j <rIS ` 4Œn- Ε?Kt0%0crPC9lv;mBHB =!&X{U?^K* (>|U*<#rtY'vȮ$.dyK_:Ok?E$2 }HUez~ti`)X`a(<߷g]c 1nia3=߽ b h}kUzdY6%-`0 cYlx+ +6ս°m`s[+ \ nWz(dR{#a6ԗ" L6</rOO>$oΆeсOJ|iD?(-shj Z!,>t>*0|+0(υA+ˋx@p5<8-9gէK ?OO= /DxZ0no(x+YP8 5Lj7OG>T?/iBz|~t#']hF#) y2OZaym(4pX`śVbTbČW6o(3X{ 'c(Xxvρ@y2% x0Z'Щa lʼn; X>x[bPYv@ ϐ)V8T.Fy^'J(BV2[UW - a$?t9 # 8pJ4Z]uՕtOMMUPR'ف!CRoCPw4~zKY<}X$n@ |i#ٲ.{^)x4{FKOAwNN'3gZ/+ayG/?n_fQ%k%fZڌ2d{!#pe m҉gJՍg<둟kʗiAЧWZ`U3O+נxz)>&}KiI/KG-Ŀ'Loeȴɺ*eF~.ilguAFꩄ#G:B*!E>LeY|Ve~ʲ-}yWIy>0L׎,iɳ;[z ,}KwmϷ-ty.v'~_ mۚ6yEϓ&4]Jo˷MoY6ѴOʱ1F╜r^=BfD/,ڲc#­ƋΗ+Uc|頥[lѓij_j "nAQ6קғ6W79hqud]?<ԅ6TjqOtái\j'˱R+|3|th_82srC7ks6{26-S<O/-9d5m*;&M)# zgط1 ,н/ŁF炳Z6!)u4h lI10^h9n& PQz87a_r 7}+L5yM4Gk0 ꢓہFN5$?7m3:eHK6p]c By))CLN[>gjמ`OM^@LYp>)s'7JˑA?uzgMB$[ ;F c^N0iҋq0Uguڮo< O^,Oaihw=2]xϢ_o?f Ǝv7c|gUM7T;``F;ޑht:$ t,t"Aʘңr /ԧx<kc8 H ^0pǃ,Dopm cp 1҉tm4PNẀW`e Bq@]1Y)`EetB/7c-Hc`U>C'#CVlڐrƩ KOAk'To,pg()_ 9s,"4XPOr&rOeէ d>~mg]OQAYz>WLK~6ѥѲ^PWơz~zFyq\'c / ݜUǪ2+d7FM^:Ȕ:Vsw}k“֐:ze徻˞Z7سl{M>|-MK&MxҸKoi23,V.˜5T_O.`-iImSjdHYX *Irf<|й M2߽_z/Sj~bg1,=y-vm˷AotAeO%mN̂Q,MҠ]7m:'-mD -(y|s2wϣDmXf :]Yt9XNX^AA!ekSMLe2h+oߤ?t_,?~TOV=,+Ř:x0 { =`݉OwlOСѨÚ߲UȢ~ڻ^r>$O)iv#u O2l~?#L@c AU}mhxK$R2~ժxZP+5WΖ^ s`6ct~gWŒQ:0mz$t}CxIDH_iOqSiNy<]"+ۻ`N}telȖd߰ !q \j*V9ArUe@RmsB o.` G:]oNޞi'ׯy̘̳ʺ 3E˪1MOO2e(S 1.K gc5lV@ Hwo XO+nx1x@NO>l Y%A{ 2, ֶg*/R34'Ld@5F/^Sue 'Q~փJ^92K^C6@+0[~tQW2Z  H}&8 y#E>kn:i4m% /2hG~23OW~=:)S[Kwh:@ڄ,_ƒ :wE~ !LT) (7tC3b^1el| = ;Ygc,hKRG 9S.P`*q.`2߇>q::8< 5x'+92T2ye<@ ,tT0u>y _H*&3.^{ú+<lʓ86ڢF(CCOsB񲄤lqa_!ëOGԣ)!΀0H C,ޤ8(*.k+%P/Yt퓗yN@HZ0?.={!fxUsi!qHu}]_ haooL@ )y>{[DKzt$xfxR0xqW M/G<2#Ixe X*8S$q礙4z }:^XVxX}˶H&0[^44d0╘bxsȷwmKHL3^-szx撀1^eX5I0kޮy^BBi=>9>8Co*=+4 HRuxuYvS@0z_`@}_m|}UzZ7"x65#, ȔXa8y| aL!?4}5¤߶lk<r-{ȣ,~Hz0ʴJ}h;#b|~0`? ?VoE&B'C:aޅGNh.nӟ~}A(ea4,_Z12 F2 K̘@<}O(@n Ԋy/͗ːP*AYxj>.hSy+&Ɋ? H5|1fg!VGCO~ Kg2 k(\!+['Ngh% O1.v, >muc'GO,<]. ܇bx&|Z`Aֱc]:mǎk^MͲjkgj y Gx&# ׀ I3,yf<i "$<)C $/#oRvC9"i`hȃ"*7p OFi@DheϼYyV BU>:g>M[ق:фBꉯ~T|EcAi?6 N̶aNXEfXSgʊX8S):S & 6L{L $2msm<_ANX-`yp arf{@әNTas퉟a1Z<yhn:5/a"vv'+ONI|<0Oz  -xWdN6&ZւV u2EK8U'k׎CP( ȵ3\ңhCoA\h(VZS^tyeG2_PȔ-=23:!2OhrfSORͱ ++|꠿HېkᑢYiݐ%K ㅏDmO@ @J$O0*`B޲{OP]IxZ`Nҹ!W9g),e4aN9({O: ϐVLZ2*y&>Ls)4=AkY_6!8rZ:hN iC|80 `fx^/c2M=ΐl%T Y2 Q.P6d07#axR'[LK PrdR$02Q_ø'jOj?&.bu[c^pIH햶K<?xա {@ݫ~CO3~[`xY@:̋ƻv+7Ww^&efP1NŸ P8cheK@XW]@+!<6xS@C-[6WFI=93l^ 5!?/1O`i%RhCJڃ.` 0uϙ|I~ϱX2RN ?q5| g\tzKIxZ`A';|y]:_5UPtjSus}5-mkO2!;n3x x)/%0HJ\#ၹܘ<< tf >nx?p@H+x'<^d*Oky'Y:}#i)OP9xQYdc15t_h_:a~Hӻ9i皏ԣ s!ʚĽ8-0綆(Iwwks{q#ci!|9qϓp# ᣎ6ϪҀ# Aޞ!1LޔdMw߷ɐ.޷ħcݧwEM_9-@2G`>y;f Q(WyQxCФ}ϝ^u'e 3圼хǰ!u|ux%OO''O\y76TI776@<>5\-0'`X(+KgeM 3q~T}u8 />O)!W<tz>"A/yB+ihD;˒40/eoFyE+/q`;h;3ʋFW6/C|q?*.WwauUi3+ `3! ~"[@mCiEɎ*[6 vn3&OS /ï _!G,< ;:Rj`1xGN^r2 0WFx@D@8%FyV _y`xpJ3C8ԗ! FƻuEC>u(7PG( Qb۰/ {sOO` ɫ/yimk`\Vcø-nn|<%c0*b20Ka(DǘQk:yzgq+ Nhxy !pޡxS}  匬MddxSWh瞗Az!R)N@z:Jww˞v~Gs&: 5 X}30x.K0mCBLjx! x!y!^41a& Ρ'?ko B녔Zq8¸;._cxߐG6۵<) G*TIXy K` :Wscl<"{鮇tj ( !?qhB)۰z/>yeBO#:'!^vJ92<w);e'l$s'O>, ;COȐ랶WV1֎/9+gb2;ti0`鍺xv-BIDATgpoz+y L\rtii33da6+jBS0ɥ($n@~YFd<@FOCakg'q1\h"-z 2?gh&sDrhCi4MA!va9E\)}DS^'GNWsf:|p8g:1Z VJjDg26d.|4@󩧞(02̃>Xn+XJX3+?cL 5:g8! xNM2 x I=ٽ,XxV1 ǔd9 >cMÖ 4*X>F)ؼJIK1|yF/18OfC&HLJ#Y/9592T?i.md0;0  Cr|>աdT&Z>Б-ۘ/xia{W_>i}FiWbhdK.\ѠמdG>Ц%M^z,4Ȝ]%$,^ [F]m 0Qj'ukW:^Gz`$ i֡\'KXW>Vr,{ ~$# z& H'܎qW ^ц_Ѻ}#Pu\li0LkOK04^,/`1z?<}sQ̴M7; _lih'aq[@+޼p\i=zq[ oQ07G 1a2`qGY1F|IJ`i^Oq VrLΌ$?63]< V CYu3)/=<4"ݵH}́F:<|CƤ=,tg]EËU0qԵE\?uws+J\n\Vܢ,HĨV&oO[R^͈b4 1nGHb\" ֺg%ijIh&Ze3ň0{THyVxyxھ\L*ŖD&P[M_EK5P#'2_+/h0 6m)4dd~l :̈́u| ?>.:`1#<ٿ@mFW}fǧ<ŅhRv~rrZ}I1 /p&N>Sx.5g?(~ ~ >.%Vq R0P@/}S,W6 ~GL$9jh-tX p2j_4u SNU&KWC'|װ~T?km DhGo7J[6trz~v /ymkю }~oF?LYV2 :Z d(9%^R(r02^ _ 4lǐ| {uƛXneI>dn`tc5rz~3Cv1Vk+eս2ɦm>&@?Xg6Q(ٟ6;y/ F'k(+:~-7kkW37-Ǎ S:EIrZ ⥳6 4$#tʳ-O<dx "R1>D'B3a #ʙEya $q& \4JyL܅.dy2EK:Z;IOZnk!!g {I-X,f3{zf1FTUMF"HNOi^! 40@/xr/W=q=]_or/wrҷݧ2G*F ݇usO}XׯZU6o*bÜmHŐ,M3  ` _:  h:^y< cB < 9ko0zt5j[$?ȥLgeF!?G1bx`<**!Z TdELJoorHSI^C]`Hv$׭ogmluRVc !^}Ȗqg3ia\S>~ІOq_N/} XsNC _t_ٽ@پmO嵯gӑf`PJ o]S4-NVs-CƏ"S@g { dcƁȀG@\`y$@Gvy|N&ZSGI9$saDu&>!7UT#BV S\g QOA9@[=p"Cv־\[k/ikkZ90n!]ŋdG [6Ec;9Nٯk){l) 1lId`B , Q&.|0$/6%^Y9Lw<}GBT&CzY=Cp$X_3x{:VCe`pV4sQBi@JWW|8iWs|3py tJ |d%$\^-0'`*.FHA)I ͵4;i rF_ޡ.'MzS>K,wxqBg3CaIzz8@3nL~X Hy Y <Cs@aΙ \.=S =hԑ%]pY`ʤKhPP'Xm7}iZ`N:yF9 1( M>Ox=ڽ<=o0tFwx!F@:A^ʟz2>W/ohq}s1mxèO҇gÓH";!CF: _rZ$q6tQ;#2Co t|%-P#?OHzzM>]{C~|.X*!$@ԩP4bNSy ( AC )4n'5z[lm@k\̑qe!xrx}b=P"@;6QKOgy+ϰa>| WIW6 VIՋ\!SgS;o.ԟ>W2Z<-لе9E>:xN@A;ߜ'Mғ{ k9':MzE4MIxy}*wz?ysȟ{|ߞ(ͩr_ Pp;hQ-Non{0(F(4>)-* ďs`.R)PR{NđF:hc@oF;싡-xLnsk|Rxjl`/~塇jrP6=X"ͥ??Њ5BzO(<> ڇF.+Qzv_i*XOqX bgHôK}Xe<^~^2 LB?Jd9F;X{Ij](;\f l/G! zy=Ȕ3ʒeȞm8BF~WMP~g ڇX@aѷz^:C"@r{:4Vô>}HOzO!!rG;..74@[x] Ib Dޜ:0p񀒇Ё%V=PlPxtpHn# z1^^Ch2e(U*+Zr7ꦡ4~|L=oz[CO=^͑0HƷ|x{nV?}f:.FM&Qv9xa\~ZF13q}Z.ru<=mʈqCӧqqIsi5O0()`Jp~@)s9a'`D `-|yN@To| :yKx#:%MC] cr-p޶(yi+4_}?*_ylgwxrRν<(Y0 Jqy(>1Z4Krxvx]EpO~q$-@_1:Se~|ӵw>twYbYʿ֯ %D2S* g _$\ H^s3 ?Jk+fhUrQ2i7d) ËJ<7T~;*?HU>YRxOeg@C ;C0O=nX{aőauh ztLu3z/Xu HWᬠ/mD_j@J{JsP8yOYܫ~u'{T,mȭ tZ^5&/Z 4J3?v:SаUk+AC G~@MRt)@Tʦg *%rPRS.F-B&2]A}GD/x2Go$sKIx I`$1'0 дz Фھv)/*AvA -z_BG9)mOM^wtߗ~7H3^`xuٲG6u.B18qŖcɇ\+Gz'OG Ee ϔ՗2K!8I{: #o[i  o2O,t/G- Sc8hPg/9 { >i}|#{#ee8o)# ݸkyWgKz)K嬌ȆNέ!cȔȓ{u?\aH{:=kC7ק LΓ[ܤ;E}JVw6yy6C?[:c}qz)syƵ͸̗N_-p Ry1C¤ 00J3g >νCܛg>kH{4eX[t0m)8s |La W`"l Bo<6LL0νvIs/& e0VcoY_?޾V8|^ O [-nW>7y:WW~ڻ%O_<('aEqxe0WJ%/65 YF窷-(?+qYS{V:jNRO"y|"ғ/^NgarhkOc+:S>}ZS<#CBozӛ>~`N?,׬} y{<w{}W}+=>3^+ g쥱GT`[!<p*a3ϔ:@4K.i< ymS󍞠 *yQy߫R3 Ҁ fx ƓbP;&c7Q]jVo (k6Q4a:ns궺|+F`J/h!1==~f>1o~⼼eڔ'ַ+wt>|:b=`t (ݶۦ]vWe\]{r՘Ū Ku9y`{o7ki}]m~輸uZ_<ʞCOzUjWv+7];]8RmbC$_;0cK_ϪZcuӲ%!Ӯ&ͦ)rR+Ч,6>#m7@kOqs+Sy0i,8DV/b|{cO**eZVЫpy{Ό<& 6eS?]eKʳ֯,?{ύUO*rUO1?{ѝ(yeT!kM ӔXlyS_|},S{.ly]D;ӆ)&UgO}=h}ǾZ]~WX1j#9.ꑳ8u˿sV3yӦC҇e^ :lkXo =]݆e4rݑꙝ_T7q/Y1+[nJ2eZg!^=QCG+Fk֖e5{mʦ^# c7W'{nO]_7zGKuM7\ϟn qA+ǩxa(OFyCq;6I 8XHYZZ簎,?t|.e{xY\9tzU{/;h`5SZY~s?~}xXvZRl/ //&W 9]Z^=ty74 lyjpo.W\]~j[?M7]W.[f@1py埾ܲ[j;0]:- ͜kڶ"I׆uǝ\ôtI hs7%ZR+T X5Sˊ^SfǼ ]= Lyg@n}vV}m^V;^ok?y C^Vݛ+V[V[v-{kDj&;sc7Y~uXlv}d4T7*7gu}o+*ʷ? *@.k Y|@L\䝜'-X-0] y:tNO)TV,YYUH>#27zO-Q#oN OPvmuȶƵhwCMoNb)Mo˗orӫ-?S'fhZݰ{ֺ}uֲ?}f&UVWʡ%w?]6m":t9zO?m/LVle }V-&am l<ᜇG*PUd];s~tX?h}֯_XQ? *93Ǩ n=O?s|۳eeS-^LĒ{e˻~d9zxGַվVijX&:swǖyUp>rϖrε}O7/,yk{nV/]i!m>Oؖ`߾]ުoa gFOAě^י]i'z4[Ŕs5cx^WN/,߄M9÷x8YЪʱç˞u5gZ[;î6A_GJ7odskkGX)tƲ:~d9L|\Vy 1 -Q; &LE*yC?$?xR_!_Mʦן@_kN-*(<=Ҁv<}lA+5xO}S^}?׍6 =Ͼg!o3Su_D9R"xKňqE!@H9(wl߫*4CW@v ^>'/˽ Q~{_|WVd©Jw~LI+>),eqҗ=V:JJ{imC}k4Dˢ1&BZMEG9֩n(`8MAz>k.iQOYDž>Ohq>4ãOCuWąF;(R>N{s9D֗O нә-bߧIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/repository_desktop/images/repository_details_displayer.png0000644000175000017500000034001612346515436032775 0ustar felixfelixPNG  IHDR_| AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATxUATE@EE%F޻11&*j51DKcSlc%&EE7aO{)\"nMMMnXC0NRlqgøpG/~Zx 4<+ Wp)<JG ^)LW)95K _J)y6sM)Czѳ /w6{ST7tU{,YRWKpC/\o?,R'\8k6xii[jL6m~V3vl2WARn n{ܩ2Ͻ*X NxW~Gq'>n(Qﳠx6mw'n!,0˝'xNI2|%׼4/x(.|_zUU|S>Y7')^dWip ?q+$x3^n{*Ji%J}ʟx;OKJ6yi'^P\( ɮ0#zny&*\GS\/*-/w'ޟWi=R]_~>zo /V҈I_|uUZ_Oͽmݺ%5G2{ު(PTr+,+VQҴāࣴ\ixxHŃS?#/~%wdqMI^oUǗ<^/ڠ [G7pm6ΝW)DZҩ8a'N+{GV]s!^*/J dp (%WMMq# ?;-@*>U+ Ƞi4=n#m?+N6y2e랫W'0ɭxA>{u]xpJ~5{%\ [Nf+Iy _ȟX=b֧l]ҽWf-ci[}#ӏGXHC\HY^@q6>eu^}MZ(܄لl^kz ! f=n~!0v܅0OCrŒ=3-Oux'oa\rSjO]'ɻX*?￿ r}Tݡn6xnG^oUʏSn!OHWܒ]W!Eyum*QTJEX3?0hÞ֣˪20g?> }+ت;>e\n"/'M<}Rq:v`+uGxbKV#r$+CQ>(}* x\OpϚ5+#VBvֲu;{}6VnrETozD~иް+-f9?U*dB_?p,).n ^S񸊐GqU6G0+?"SMrpĕ?nW~->)<#-JE~)-^'_-\4-R\%'m7?⑖p?`ILI G] {Abs삣bOm}Fimu)vx6v{xowXxno/Uc.JއlܴRo Aѻ&uǿhQ^=$Կ'h E(ڪkikcc}am۶6a1kΈa!no+ OL³~>i;nWL |ÃJJQ9J|KT?%ٸ"J+"^j܄/GJ~*?z6zV|R|$ʩ0O /SNz]NS'u%>| .`OWHaQŸ4[&tFk <;XnA5f ^&k7'+?߬S|~;rO슿<AmOm[) sL7ٮfuAXk ;nޞ:3˽TlƧie>zբrWa؉w/?|Ү6tj֡?=9Į;&[ymj{n;M9Қٝ Oږ Wョ(,Ծq;v`ĻpzW 0 p\ S8\ sMAm>0N+**@`)lkte-[.sL4y53Ø0x_yTO"?9/k*OpDNxzYS \i_U\wJ܋WHe%_O6UvҐ?*O?ʓx㗖ɇX[+e ÷O 6mLYXky6Om1N>|ࡇOC_5 *7T6)ܓ7B'DqIW<eUI|IǏqUZA8w)'A*&}# nQ. .auWx8$~z G~HxᦜiR?T4.aP*?-'ϟ81u}E?1ƏdmBn[۳7\dϒ)bE[e jtˎ=nhgi[X:[,o-B\H;v1#ӧ/oco;¦Ͷ<>,ٽv<$5BHM]vϭ6ʾ^|e b-zndu>h|vs6,3~Rfc %*}7:Mj^G{7A{FG Pru_}5xkղ&t6wC@G&tZp˵ Smn|งrc.ݽKLBƃGFdGjQ^䡌RfUry)"FtF80Pr? OyYGi%#_?4_#~O\N8y4& mb8"6 ^TxÏ-D)?WVa$/㇟I~=$P>+/U:S:]%+W=;_WJ:H?*nŁ)FxTf#xʏdϟC}PU}^a#G^~wc3gm櫇|oZ^yݦ7lռ|ƞz=BX0>z}2u5LK6ִ/=m8?ַs[f=`k}}[cY6GO>VkSIP 3>9.t.>}Yu;:+IJL`,[ku}iv y/F`73~vh6aV`umq jmOېia{㍎o֦ϜF]~OXr׻LS[H' unܧqp&LuU]WuA%Wp+sş{qK? l?Rɾ4GN/#M6!W]fĉш6|86 q.ƂO&m!xiݺj~LNg?Ƕr[k~emeL!M /X!ؕO׷[=v8NV۰ d[+{3.;혋muڨI{rM &,b;{;6`G+޲w~vS77>xEmtbkmE0w3w.e{}50DSGY ~?}twɿ!XA|kyx8P0,al۶mhkl'4I#+w]ZsM:56V %M1~=i)lM>(;vh-o:ZְnkagR>Ced >?d_qI|pJnx@ ^qWđ[aizG\WF=Tdax\i$X }֮]TN|zb_|><\%:7ۖ,q\f>N=sw?;F^w;;pR>5-Cg>H`S2ms΄mтA{s&fpYv`63Ȃz焏p.bX?oO৶Ŀ̀p҇{ɕ1~\By Ji a'n= ICÏ;|ɟ+?HWC8nה e-4qUKW*L:%tK\(qA+UzC.!d'aKfq)).鸇WO?%D)-~ȟ0OƏ+iRXe&?+_Wx/DI+&x+yQ^7G~ '#_ v]lZWŎu~I밺6/lfjz:F){RP DE_>R&*w) _#ʃpܒe7?&HK^GZd~Iͨi/!T^%?,`߿?ҭG-_;'*>\ERy +!Lܧa"*al#KQ/S>aE8(⭸EVp$9|V3ee YU FX*GZvM:ɡ#n >M#LD~J(xH&=?)/^U>< ǟIN#wB$S˽޻4LR]n([܄jFmg@ypҶO~K姸\'4UҪ<# *xWH4U?;otpGpGpӧuQ_z)GpGpGnp<:묳#8K=\rI2xW"8# "od#зo_;zG_׊^E0y$GpeY,C8RQ,c ?ܐ 3H:u괔wGp#ИHCG` B'L`_~ejWUW]VXa%HJpGh~@?+pDnĈ.g ;vM2^{mk߾}8#,fVZi\ 9t\8G,7~;#8_M5:K/FK-%vGp(,:kjq6lc+bm4wg8K3f(*f<pGXF(,FyڤI3ϴSO=> ⋶{Ƽwa#8#8#,!lѷ[[}26̶~8cp!,`^{wm쳏;,C'l 7;4f ; Gq=vK/dgq6{x?dj?]wu'O7X`8#8#|(sϵM66t.'|tA6|裏> ~꫅|>{E]d_=~7.dA ̄;<{gY>l;餓쪫mfP:tPV~uGL>F۳3i?pfXUb̘17rvh̙S*z4MJFVR=\^gQq)Os@^)UR╪;^ʡ_r;G}z6hР8/0=(ĉ= _Qm 80q9f`[npP/&#l%[V\qEҥ⧴/߶w}7|v1(_G((4o[ .[D2xr/ޜ7 0sۜt]w{mo_&Y^zZ;W.>Ӽ\j2S[ТRavUEc@8ߡZfX.F`5P_OCK E-kvh{ؠ+&:3gΌ;0]0b_7 J|ӧG޽{?^QQXcBΝ;G$0##8 l`Rv-EfQl`O 2d8 ;替_fy鷾E鉋#,grǷɤoN3Ef_~9J-C&B?[ď(ů}A%~`׿ܭZyjy8##@{"  gL={F3li!rp|DZѣGTr):? z#nݺřXȇzHI^Y +oȗwtQ9E_~ѬSNA_~yok; :Ts#<3n-+:#^$?׮a։OxaÚr"%^?O ᄏ=+op_QFEyV{.i<ܟ}{챱lmcB䙀/1?@[z֭[~ž NC0ϥGƇGWٗz7Һ'Tw?G1e]_Lz z}u>|0PYL8; Pv?l0Gt ~#t^yƀO9{@Eꨣ[NcjRB[π3äK/Itؾ:E?mڴ(;D|.Ur1C+W,\( H:cͫX8;- rR}7R],wy'>/'7(YU2P  unj>llGX '^#;3 YbF[."姫+_!W޳oȻ!.-u ݎ@c#PG->S#OM#FoQѡa>0?MAqc fp1s /k#,Mǽhԩ> 08%EQc11+I$)bFц1*S"i 1W\ + aцVCȕb`Or3&)#iY8Yfmf#@n:c(rRiRbn̉zxfULiޕeFE]˔puy3(~"3PC&垙 4~W7ݐ|\#И,yl' ꫧw% lb 9h.#:q ,|v %L&N<[bD(Hy9#: ]Q6 s=-fsK"lV颸̖@cj.`6tCqPa;C riJt8uCQg_W('mح[c+_|ўx я~TG@C~p:#,,Ս,w4*u(\#[g5izzvY~rhvah57!J`~l4`@6'Jwy1 ox }{K/4Ӎ$&h?stVoSOafrH݂H9{ GpGp ς+<^o]N\o^]]w^N^VNOvOufpl҂q #(]tI 0*|w(h+q9ѐc.~ctN t]78腭0gNF!2eJ|hLl8g᠃*SJNʇDq |ٳJtJ`&!on #ϛnI KrDe;{/fWpHЛoiw_Tg}Zj@>8=N: AcQJN)Ń8H)fR(ꥈ2] >VB~i0՚@|NRlyݘ!IfGN#8#8> uPr?;\pkIfkf߬c{**o4hs9Q9TP9,K c]šJ Q֭lPz0 ]ٱ=K2[oElf?;B0 P-pDEN hR91N Nꫯ{cGE\eFEN#8#86 ujH0Oz0 ΀?SAVϡxȢbb"ԣG8r$83 l6pFQGm arHEAgC]vUpnfQ7n\TK#),e>1K*G1:r)0zc6hBRv)bq\; s#8#8, M97 @ۃ`z`:i&B35n%Lfͮ|F -"`,:J,[ZfXl˂/<Џ3&d&lB(~Ln oя5>'x?FtPP̫32 g W_ȿ3$zTBt.azqv?@~g}b犎 ?:'"vmuWGpGpe:OmTY?OٟSg f8=;P%"Q6m_WTGfǜ<3^Yr)_>:nyW r8*3<gzmGqD l9};FܱFN1V5Nӟ&:!g `⃛.8vt".f(7g= ҳk3GpGp}ۨTA ̈6^y- ,cǎ5LwJ`3d|YC"L4)q,[}vB1g2c۷oo("!?#|̎*%g|1AcX,F):c|/rTY̡bň,rfdٓe\p#8#8B?zA^Ctַ J8YlxzED!G#K`f\(JNBrf4xA3?^}՜^n9rs=7r#$`:Țf_~$qf?OFƜRa#Iy.lU]ǖDʗcB6fDuiQ!PGndWv+?cFY+5d,ak;HŠ#63s \asr ̎Mw1el$Zsd]NuN̤r!%BM)Ejf؆r 5\O<"ϑ2}~yEe6kI 'Q4_sեƐy8" u6teU-NmNf$`?'GX+?y@z5:6VGM&lL9'Вv vO9B D 1]s;jԨx$8N;@IDATv6%5w]jʲ8oG`iD i,8@#"Lt8 B6!К"?<.ާcЯ_xIL,g_Wq8 F;vXㄩĶȻK|;9(Hq8&СwcO{W<0cĹ+:tB-*1*t78%)UŞq( HOLyƬ"OTId }kbڳ6Y&gr=Z6 d袋[o?N;4RquYgr3 b,6yZ)32ǻ@:P9<_GBꪺ/KXK8G , x]Pj낒[SO.|U_}0c |;(<Z_v/(AIeƌȕ'ׅ0_LXӈG x1<1RG‚X yE%, &uAa k_׺0R_+ bN?pY h;arHA~–u#|CAѽ{OPzΈ ?F˖*{@R8{.v Ku`a|GyȎaB`B۪Bg-dgϹ+r08f. A Na1p+vꔓ[_U )bρ8x{ [U5gǀ%)Y' /,Y\e;I7A N œ8#xTs6Nt,@p]?m  ]doRW19)EEU-D VaD%80bÎR)V ŞC9YC(%H0r& 3x ffcA,VȨ?Ls:d];v:3cYEa4?w]wŎ~#I'I;a>Ds7x#,@])m} Sm=q;9#,)E)0ʝ7[ɾ[af$_[[MD*~:!]a宬O6,͒x3XG*kSpꩧ80; WTR5( Աbq7k6HG᛽olW=?kVd;YTffr;#O }@"pDYf1bn5Nć균MwexN34t2dyr)eQM[6خ >4W%DZ(hIi!!+]ae> _G &8]Q\F%f[`cӭ[7Tr1O}L&(Cv>K+#̼39¢SLRn˒:;"$@tH齥:ġ>q bTI)<cscugGWXc@<,4[G#LJWوG˃>&#+)(rlE}, >mGED/pa@!.it%\;>ewJdBC /?1(O(SȕhhQSlYxʹBd˥앙*FiDP1aJCxVNQ)LGW2F|[D^Ş qʅ3[vZm}QBم;/s+W$ˏrx?!uzC=d![[Q *w1ybtYgN{f:PFezH)ܧg؈:?GX4u ЌQm6hbؚ6=Mcݺ̌JUvDߠA֌l056dˉ0(ӊ(ؘ0.gQH2~ٌ&;~(oCLA1јa1ʡl'ec^.WFQeů/aϴ6kӅUlt]XayϨLҼ5+<0bB"*Wr+pصb aW 0vb5[*yG}ofˈ=:^i{i_b^(@AGqb;c۷vظ<+%f}fKf d~,eV773jÌʶfgUpbe3J`փ"r*ń}9Kr;j] B!H>Rʫ[ixT~ǿ)kr2Vs@9^8#4dʵ C^0Iץkk6-Pkrl΁<;Gm3!>7E'L(RH+;m|cP1%R?DhRWm'RLR9_ +fiY*% <ģ\KW-)_w;#8@wPn0^@a&CGe3U`WN$jlw&"e{Ef rϥ\xLGpGX4yGaRMzSv閆MG)K`[L{.؞#8#8@,n4i#8#8#4 h#8#8#t!y#8#8@ ,k8  sXTRзF)3qGpGp|#ֈ(\Q!m*g ߯#, p7qP6C[o5fs!,tOp~]:. pG4i|}F9)#8\ve6k|oZ[*)H5Uaח^z|q#9i$e,)/+ӏ{a+R<5C8 NAsC㗗)|Q?/;4#8@t(F۴iO\ҏ,N?lV|A`'|rSb[HrňѕN8q~2epҍ;6wqQ.pѩZ:t~gyNj[oFˇN+('wmO4-wc`LLazۘ1c c6hР$oq^z-ꫯgyfAڱO?ݺuPQy8!rwy/ˍQN9j֕K/F\sn:S KN}C^ʳ{>?ρomG;w]7n <8/;sGXhh6WوG˃>&#+)(jxu=*(*_=F裏6F臛JqQLYPjs]r%Q?xc;C=GXOPL(N(tR^}HУ"dJGeᆲNB-k/12P>{+JN\ DHn;+ Q0bGD Ï0Q>}b?<>T)'&^K۫W/c7ߴ.^”]8(>sq% *Wxd23tM7@!Re)&hrÇ2RoQ,}/%(to喂uclrеkעb`kOGe}{]X3fk5Y;7]|Ŷꪫؿ mh޽coq"SẹhprGXh nj;Z+ۘ[ٔږ6b {6 q{,oF:snjʃ藿|Qfj/ !CbD<>b'gŢ%$ #:ui_`1葒ڝ-"z/jCC IQwyBFw=1@}vmmҤI19#,4KG Qd3f\5cmFZl+qBO>G27#cZ)]}qT=K뭷^Zҭ@T3(0ck)RJ˚Y܉Q?:W4OβifṊg3jkvL]@ۏb7mF)|tHH_0aG1Z}u9ޣ$C].MpF!S6fLXlĢP^Y\0*Ry?3PiT^)FfkR*ךkUS^0h,,J%S{SAf=Re˻gsEֈ(Ns\Y,3+q0m: V)qG3NyŒ]0RŇT&8lۙÃ,w]0OB^'t.p %ݗ[ې?0Ge#Pvv!zf)UlP0c oLFE%V:ly4~9LS`bP%xID:U\eK(c,d&H5>-G)|Y6lOrLwߒBbD'E67G9 Fpe14k0 M*FtXK]T Es&1~P,33Ad{Dw:"x֔y1cq3kR<pG`F:Z#{֩C{qEZ g ne+cgG=׿Q:QXx{kFX< A(d 3O6ꛣ+Cldr- (c]JKL>[M ('ʊJNi JcQbelKTI%⓽/V&V-O6}J^,}&Ũb2U, <"lI&y %YVpG@wP0^@1AGe|ů[\7Af{$pg3CνiSFpGXhf "V6 8&ck5E11`@'@AES;#86X!9@s Mdb?6G#8#!0hY+pGpGp"x#8#8#",AleǶr#8#8#4`A}(UѸW#8#8#4>bD'%ej8Rqqw߭,r#P&N#tkE,JD&jVw8lK/oC2n$G<Ķ,%e#8#Xh%ӈ6m)SqvY,HLo5|?':[8(Yj&nL~Ekh M|`M-O65ESMѣGSv#8# ,A2Agz (tZj_"20`϶jE.g׋/X_dΠ@SaT| 7cvN872gg8#8ͅ@`3M!8 ?bs=mV 7B+>8:h4ǣ>jx3ӥK; )tw>ewcSLi o_ƌScذa9B:²euG?O(6le8㢟85\ OWpkVsxg})(gMVu$R^tEַo_[c5G?Q\"<8s̪Z+G1|?hugzKǾJ.:#8C:@>}z01rH{y6rD{d|e2Łhݻw7|믿}GvgI'dW]uUM匸(G(ECc9.q!.1q?q=A%28hiyWQG D.ɔȏ e([<^cd1:1qW $ZYJ^zٝw͐ºRx Sv:쫯{{=w}cʓ}v$_fn馂t 0jݺuև(UGK>t΋e˖U|G:{>ĆK[ԘC8#P@: ;t+lc>oeSj[ڈ3''EEx7lРAv9تj8r-/Jɓ;8돟,M@A( XcA&Xb'jcر"@wie}2ٻ3vsw̻3Y [o@믿^kbs9GF$i_%V8:t.B`Hb6lUDZzww}n}+`ۮ]V*կJ /XIz`D`FZjW{f%$Zy\{Y֭Ki\xQ>j(AݻiF:w$n3sq;w I+3nA>|uwW6`B}VyՆ&˪vcB@@ hyⅧ_z+J\JKd׾e^-K [9MqԩY4\7ÇkgM7\y[V=JoyZ(I GH0Ì_~YJJJ("Kv_='h1wٳRU)%z>c}!!Дcnwi'[2f6 J٬aN٩S'Ktqv>: E(Nm )Kg @@N#PAD4fY(c-H鲥/{]zJ^KkM9G6PԤ%sq Q;z_m7ngoZ;  ~ɘ1c䬳+& Oeb8 ~!拋^hگj?cS.`OhmJ;}#}z0=;/E]tXkmJ +_g^{Zy^{:9AYBa J^ܠeL_@ y "0@haB[W,+?JFdijJrrH*EAeƔ+/He̐1!lmwO8.({UW]*ҵ$m EP.B1&Ji+`xCW^>q}ـ1ƌ-$&m*Z{GGi1L?&i Sfyk`n( ^-7t̛7O m?vs^-pԗ|h?=0fe+|Ү /&fO4}ٺh_y1Wz%>Ph<`e>s0g$<[-yn#Nl5F2=>;vB܇%4\7xIċ. QwrL;K$| "t]Id.r˙g"a3Mh!W{Ȕ 4EČFF7BHh˓O> SL90P~ED4hw|\}a~CzwvЦ]ivs{?uf쓂/y6debLr- ^ QF\L:sďw1b.3jnrM@E@1ș d.ީyRȑ#3JCQLKi3$3k̫y2/?;<g?W_8SZ21JcҔƦTQZjg.4ΫQ/ڙ_9#ڗR3n2S?DRJIc>6%ŋv9Ǘ$}ᚣ&q(fqzy00u2(34Ql]<3k>y) :T( j sy:Җ@ }G^P&<( QK2|{G~lq~cɜx83IҦmYZ@.R]߮JZaJ䓟0'A\|:!vDڃ*#6\lkI:F&_4-D+z/wĐ?/h@#u2MF< &Ik ؔ/LТZӴu2樫q(fqڴ^GsΪ!H}= w7+D/wD:VR>o76\sc=z(_peXL$5"]Q{a\U_;$SJ_y|i@@ [! ^9a\m;v%iS'/7r4׫sDa{t E ( H3tt !rcSc>-Lp%k.G4 F@ B=s>)8"4`ce=_>sw}^Or++.O#2Hn4GޑDs#˭RO߾*9x1YD;le`sP_@ P8\ 3+cE >q&P!r|76D~IKҖ@( P@FDBnjn.. & 6Vhk@ N $j:Љ@@ Ժp}h\@ @@"P6bgg9']v٥Gv@ @@0D >G}Xl0gD_@ @@ P+4!&?B4x㍢6I撨MnKӆhYIZ4iKsw'|o废m@8I KҦOZnHT\-ͧ̇ u& & /r-rgΪӆhY[n⋱IS_OL|͕/}SMKu&j 6N:ɥ^ݥKQf'l~E |mժ}9wyga#vAoU%u!mz+k8 @@6>0hg`\ִ PM,oewoD>Hw߼2Iev{,qCشW_ucigwqcջsO?Hy'\9rީvذaDҦd_@@ 0 X@vvo'͓qϮ7&0h6j+yꩧo?}ww}'/m۶ʇrH<̑}G -ܢl4ۮ];9s9rg_WvjL&XF׻cMf،C#M:(u} j4WDl_ge1hҥ2'qD=vI|Kq=.>\ m?Yύ+W5qslҤIr駟.7|9iaLG ' ]w\HK٘'H&:L%Z>ӬSNь"!B\&NuNCѾ" ?O?s̩dBy^xa~zG]}!fU~Ȑ?1FmNX6ab3q5i8Ƶ=N_~tNr>\0!(5A}WQ.j@(#7.FYmfbvou65@@ PDfEM!-Z/-ZY ʔ%?th ?h:&5=P6\ C L5f 00Sh1zcWsA_/o}\N9N4ړM_~`Xa8#dС\VC Bmxb:0mg}+`e3\羾i|z ?-0'Xfmchi/e%3W8Ew.Fպuk=GUcF-( 4Hl裏V9UW]%GDAī xg>>"j!淹n4@@  Ռ5PZH"ZQYɮ}KyYLU"7l)̗6TԩS5cd30h11ԡCs*ÇL I[oZm(\*..֧IdP  ~۔kmӣGs[V3_bBb/s/z̧/ W=v a5%$ZFuKYIUGqr C0Bh`500aohB20y|:vWoj=ffE ao߾}46p1 ( ӏf9 eRY\tR4x+)+/#%ˊF e#FX01}΍Hh!uf?LhG)*_Jۦqi{ʥT XOƌƊɼyfOJZDĘQh"Ov\mO[g:,&+B&?9쳳 >&V]t6E#zqv2RΝ ( ߿fz&ӦwR.N ` 7ܐ,/vmyfƄ./^wOܗ9$@IDAT{Yg}!Znt59v6@D`"&~aRTRhBōus" 52"hTL8ZP>"T"v8c$t¨D M$}{6ŴA; 3^gϞ:L|Dgս{wm⁓1p7\˙g )uZڄ;j<0I^S.G_sI|Ɨ|a8FKoa@$yK.D Pc&0`Ms̆:ŪW^YiE mzӎxD믵y~K<l|1,Ӛ 17etymO\;S;LnIn#}M?@b3DvxL s/WI jV=*? VYdՇ4U)VbPr B1g/ʮ2+Hva:&|fq ' :믿W`)3cDd5; Ǿ4 M:C5])+|>7GV0#?#J:;C6%MN ڋ@9bĈ;Ҽ͑fw~6 T0N4OŲtJ5c_]߮B}ܳ G4> VmP\`h'v5Ae&qF`|}1-iۛVII:3vTwܢeθ~7-!DM>Ik{;N>f5}Dƪ'Ů0o 94ʤAxZa!(|}xNlΪo -6V5!v⃉P@Yc_#2Kse՚.O72HD_`vJ6a~78g,JI3vqϬh;@@~"\'>01e"Da`|L+okDQa;=3W됥5Zh( Ʒ EmZn h1AĤ`YķaM&fj1 aaFT! lZ@T=R tygߌkVA a*-5^xop`d~Zs#:v<{@ "PTƬ |'F>5Se@.a|ݱ][zL"!@x#L\Pv߷b [oi$^̊0·f/>ڤW9gPMgʵIl06SoVY`(Ä 4I1m?< Yخ0@!':00DbŽ{a??f.bh̋0.S!4 ;b̌ TMg?| QXA1 adV906{Ig㘶vpl "`W@@@ O4𱳇IaY~\g38Ce" La`va?xim,s USP"%!Ȩ|u&/?|̏铉fY5!-1'ݦ]^8/5?ط?/E;BmRJhD5(Ls]֓O>+D”(.+ hьCUA" ]>6$V屉h?vIoa*̾Y)0GVI v{t)?u;NG 2Ϙ9W:uX|x> &M%[nf]W/5I6&=2=|:tyJ֑i7\Gz1 zwdeC@HM6/FҤqCy2k=fhAzk(3 5֙>ح}cZX(pril$[P]&f*[򌲯, [MiL_p裏M I~W K;iC$HS_I!!^7|ޤǚjoօtزZ2PaB@a$@@ PA`IejE PZ4k*-K&Mq*H#K9=M ~$vqåz/!Zp-ԗ&m\öͷ|j_~M7Zn!'#5%~ayΫB @(iТKSX-]B6JZ6(s6)S"iҴf4WB}!ڵ}u'jgsFR661oCnߵُBi81qVTg" εQb' 'c g阰kr4 iڈ@'sf|?i,/);EKd iצH=xxoKbmJ٣Ҫe3 ^Fb]Kth Zm|gzGϟ//؈lvR &L?X~eڌe:u6O 6m+V)m2/T4w\!vEfW˃>8@eovu&w}'ƃ0&bP<3kRcV}nw}:-ww=\vh0q퍎!5%7}OHa&o{'~i6o9Ly~#3v%dY5Bγ0ń][ zYf'4aQ8tM;[5s{шI o߾?Y?s3̅/S'Pt7wm.Xb7@@@ Z5 0i4kFP1qsY+%d%ѧ,Y@+Yڔe-vWx ĝes&Z`F f:y>쳵sG0'K*v̙SvGvT&}B<$P! `oj   j袋0v曵Υ^m Ɗ;e|^($.B_rds&v16tWMpa  2D,\駟IL3(OsÀ9 Q>L@@ P_UAS4,RaBKZH"RPRe Ժ\)H~N0.b%g f^0 \}Gm#~0ӟV0|y`m!q!م+Vd/X?1#[3e"PbGp`%]馛U | lbÅL<wal @@>!M]h|2riPf*lhse")UOVժ@ci\t"o |3R9/m(L&jbC,B<Ӷ VNMVf88$m/Bċ\KwR+!a S/]M T0NDx2@a/&k[{q7?+mƴ'<"63V̂BK Sgk@ ZyVpg5Ѷ78#fŇ`axk/%GƔ0G}~v2o0U2ĹO޵^WXblR . Jd2s0~A=> x_oPX +Y>ulھ`XB:nQE j&EoziL1A3:PJ)Uv>Jor3A@3,K$Y`:ǧ&GuvЃ7zvsM8~eʧY3eri.(!hK@HIKq2E -ׅ/0s=LwyI0š>&k[{qͥy@dHD*40ik0! L/mNva6a`68S <7~W-BM[`tUWemɰY0L4:"VfP ;duU>BBg'Jy;'∶ 'DG}T+ .(L}VL?hlN ڑDQp/ MH'5ڤ1ԋgZ.jgmeJgoˮl2zTosټGW'#hSR S3y %͛$MCv e^]SM0Ø!V((PLֶv/\rCN2c+n9.f 8)a\b!s7rh75DE{uUnA (Xcla[wfYŁ p"fAU6L}`>@aQ+yo g'@]O>a+Ы{nٙL> 0w",y"Vwq6QL$"|P̅ 3*Dɢu*\F D9;|hD1zG} BkCqee~eI]&b>iHq!^N,2_|5u0o>󥚪'#P 60TIVF,Fs`7xj $SO;}]=L}LYAB(1D~ 3GY'Q h^S~8@YAM-0h.?B.' TZılΜ9Eme!:$ ٖPڍ00]vRͷ<)|+n&BBDY)JWLYQ +I@@ P0AM~¾Tklpj[vqG[М`l6v#>?t]w&~iy@ m b`6B?*b4k oQ曂VoveW Ѳt$M}i&ۗ;O>${ -IIiʔ):&{mOZM{BDRbve?P+c|y ۿIxzC1SE`K.ě7@Ak4 ;$w}2a„6 n93iC-R^|/MJs|'.ӣjޚ./fgΜ7ܹp 9{;띺I^(m=v#Lv@&V .'[6l$(3?.>GY6lο?<a/6x3@G AF56ӏ]ʹ7ސfq)5Z:uC`vSO=UؐkMc9wy뮻 7ܠw dw6sQ25o˨QS`!L-zw̩>btjh | Ǝ+^{NW]uU6/6"L>vFiP/fC /*M @ATAT>|v<*Q1Cw}e 6ЎsO=T6 Nl|{ウ Nn0&m۶r!4LgazѸèa;s9sgv͇~x֌{Lxn2k֬l|b&a(WWYGuT0v&%K8e겏0 ~>lrfÏ~cDaø׿}f̰sLo/x}I'U2aN}cM m y3vxa/Q 1bm0Dރ>Xx=/mhC lyP0^cLdz>v |tnMP [ ޾}{=]tAi!IϪuVXQ kXb,_\xY L6G>|rL1_^D@ ƊHN6i$D}7߬q &0#F\wuZp!-ecOM0z0)~f)SN 2 ;Y\&NuLCѾ" ?O?s̑K/^xa~UJ`}F`Ve'S?L9w=hD2VFxԙqXɴIA50@hA8;> Lb||S5}uaueyvxa/:9{h uUvUM*]3f1"mLo}8EB0V(\yb|̊!ennݲуD+2D L 1c< @AL!fTnѺTf-,5)3Kdμ2nfHc_|_8.lFZ~C=$I/6' 6Kh#g&ךb;a`!7ڃPK0M_~`wGNvD%lVHB~bvs5/w}WjPdᄇ *f_zd}}&9q~=hHV{MvQLL Uڴicng)"Tan Wt<`̘ĵ݅#qbڜč\7\OG}hΝ;WkǬтl>i1?yȳ+Jp()pP~msS(x~"aDPVP` D۸ϼXBf0P@ m "fVJu\JKd׾H*sKUB̒cCÇ׎kѰwx뭷j {X7Dd (I6mj0+ m0x(dվ:njF4\ތS?X3hsQLLO H-=JꕋJ`4>|O\]N1 6i׹\a!}H\6v 31~(0¬h_xJZj(#^{ya4<  sOmӲ}A>@@#PA!Āe2}v,].Rl W_ϑeE4ZN8~JLl}!٧Os"d/h'w.Jۦqy)м\cǎY1aY)d!4!W_c8CcWPEi0ԩo4묂Uc=Vゐ-M>|䪋INz`c9VҦϷ]b>K[,tynVhu)tB}@@ P}*TQU6;{Dmp50G@h;">q}p\=0h1 Bx@ya0ktMZA:cP8VD!f릝>|"/Vf$m7SŔ=2|A \L^@@ P0 &#4KhFsMd-dV4*U{ +GD.51߁ 'H,cgIc rjÄ&pu#I&O5hdhaƃ@B F ӽ{w'1‡wW_'isac1b;qml|)ꫯ&X++M׶p/ GH1jtVӄ&gZ`drlr^" T$Dܩώ*}*MD2hqd&loq >%|RQ]SV$`L\{Ua /0ʌpƪs!1 0p0,X ;.`!fI:.VD0vN;_D$T϶++Iz"Ϡ,YPȜǬa#V0w}&s/W~@ E $œyGw9$I\tyl8EXlcuH1e]cgVL>!Pg\`(&f0)GmڒBNL8(ݔ A%Zn4=C&)#m$e4/SۏαJj:i|F gĴ20W>S^WZZs(v8I(\KSKTw.zkﺝUv(h3ь]7K:4}9+<ֺ c 0 5Blbn0rwHiW7-Mq5к@u CL3/ :q6LiH?O1'm]p\w=O?-D$=1wC@]Ko+:wk1eV&_i& ׾\#{ŎBl'wݔfr1'Gkτ{@s s8n=.*S9`h}.lEқpO..]s+]'ϦD6=$XTp1c&\ﺯ|u^0Chg3o9meC4ŔeŒﺯ^_zpKqEkX/6= M WEp;裏֑(D)IWپSk]w.rt>!wU-Ə:͜0{ɸƙ4ilO:2~F_\zW(5/= dE&:{v7ϩ2C@Dଗw [Cbl Qpg B#>%wc'OZ^ ND5h 'xN/zKfg8'\1帮tO]uLG+}yDɆEO4n^{naQuQuM!]K㚦q0&IfKW>1q͓S<rх;d\/2F<\e3.oזV[9Os>qd52\ YBY9@i7L:X~sw>9\v=h+}'o!Q!*? ?/E;B= *v鍦 @}Gc=Vi_sca1}AH*"J@u]g`4@h G։h$~ a{K>DfW?Q&+SDf쩂fM?'{lĉ0fu/Wz̞\xbJtWzd׸3øCh?=WҦ׍sg_yG}}g|\so\ %jKq qˊQ|8㺞OMyG>q='|}v 8 LI맹)~k<ϮrsSǍX}>zIEQI&ϒ-T_|y"&ِPf߱cj?,4e Ô.0+ Cnl9܁ 0h p^~aI&8 c~y癪gG}bH~!xu{h]qN~_z׸#؄Ù~qu/W\a7ʹiD1U2`"u_[ҌC.u; (+\{+=k~9u>u9{~Pg\xE]caipJe3OzޙthқuXǟ}GV=dtd#)Jh$M7^!.cVHdȯ5uІ@@ P"fxana^h918CF``дa2QH`os s d.]tXE40Xт!ң>}~ b^Y ̩ﺯ|uL(6c.AfԩLV+eu_hh]x 7m}};}>|f } 3o3Ɠq^M⒔oڂIggvƙ4&H^s@ƍ7&i\{~ަ$N Ҹi܇S߭ygkq=k @riR6 6wLYF4Ve2cacjSҨa37äQlv+T +HC2ҰˏpR¨<6D*zc,__9MZ_}I7>_2I:yMҶ|( e>QP vB_0L X1{AĄKL P. q $m:ϗFg]I07{|}廮?N4 s2SJi ϒ<uz}u%zӶgkW}㎳#cGa ,U.KiӻqӇ;@{ogx]e30ѶrW'84+u/] LX=CMԡ_W$b^DT⛷wW^5]Mߡ>ʼnk<ϮJoaMtp߫8-䧟cҕҠ]ծ@ڶȩ'͚VM}++t򙭪_[vI-ղN˻ iV&}/+o eb Uo67lU }F97kQ2)yJ3nrjYm+S2s-{թ3?#Q`h`xq$NY 0dFȀrKvT6Ջ2Fʇq 4ҧm+}ܸ%(Mr믝>O˹}rgW9mK>kcEW4M;ʓ*#5gڑy ܸ48QN\zW||v=|woY,q4U)ҥ+deӌ2R;?6iaIjwSdmװZ RiUѲJ\2+i]y=*lZ[YYD=nL)[Aq4[)TvD I>Ü.3eS3(LEB٥6FH ȊQrir[i|if6is4I?J=*5h=ڮzR1HkU*~H' :H٬+1E2RJ~Uj̪/EEije/j2QJǵZG?_=FҰUI4>ӥH.E-ڢƤ¾JKVN;LVˤvR6tDި\I;<0 * dKH^U7|c(Q魚3w)\ @@ ?jU]lleJxYz/)jSB-h_]eFs !tel-߶[UJšq~UJKs}v2L}{J̮cSsϕӕ/IjzäRj5l | RgU-(lQfJ#7ac-oQv?j ߎ8*jRYZZXƯh޴7|cL}|_jS@~Ԫ Plvr-?],-yPqq3I~63x`1ߧMSQ2"b R|˱%&CZ]+2[W"x5^=v5^I(0 "PAcM /@iѴX iݪZP7țj1/h&ep)PQ|F9{Ϊ2`2˕y+gٟF\(shsu+k3+dݴJ@J&!{ E *-2? ŪS\MQkŌ*iT]eMjwח̒&A*E]ِQF*,'L59V  &ms+Gv#:R΋t' G.kEj_P6MIy߄]~&n[}9ٳnl,FL괄oM->IW_}U}rAs;"g \NꡇJ(fcWgD8T} m KT_Sʦ{ fʊ+U eң*ˤf=+T7vi?ߔCd*5mucΓTLWa]v]#yj|cˏ{ktՃsL@`{1}C; 5\w1bO?<N:IXDW뎾MY_)hm/T!Xz -b0%DƓ݉+vye3[v&dѧnPm wոD@J"*MoUOsO7汿 7mBўֿ9007tf0{8Ǐ¼3F?x5jf@ of͔_zz7`$ӌ&L!L#/ĉjS+_9R`d]mcgTΝ;{'ݕW^)h1յ[;of_fm_Q-Z-',N2Eέ\۲/,W]uwW@ۙ=zkt65La䙟q#ۘU*|2$;ݭ[,>$C(>r$sR@@{PvzH[۷LP(M7H?[z`ך#HۖJk[_c~iƷVA u&mbBE@:Tr /o_9ڇc :K(z_Gog~n弞:=Q)DGW׹K+V5<_|[ڵܿa`6Q2,L#LLMhbaq}0I;6HÀf&LDF6Calm%ն_WZӌTs pV\u!|Z83x:θ ҎLaôfڴkf!Mùsʶn)xk[.] ZzVX9@ڵnL}!`j%˞Oaa)R웖ʊ/fWjsBҊQUJsh! o´#ԩbV3tPAh4W/b|mb-E*0^uc:s)i{Bڎ@U;]jU+B 5@j hzʊ8&Z{6ip"iL*G4@Ŵ}6 Z%sPs̑>[}bo_Ç6*Q\Ld҄c@#Pt@ H/\;h2s@ (hT1 j߾6 qՁ25s׿U`Fs`"W~W:50'&YhZmjFmmv ?rghM8L!W]h]}l`tj  ]uF1oz`s.>q֍#̆0';=|B-^|ź߬@0Ya9B i#3wph׾utٛϜo \2i1 P(RbP<\O>G@ P@ CCSő ȠU!"w-~xΞ-=ZL6 M:i9ƍb ci4]GW~W5ƈ f+GwܡM[&7mvf+O|\f(ZY;s9B~67cH~1E9}Kp %H|xޙm5?(\HB#~ԥ@4.gǜF) s->ݻWb M:G8bf"_]2Fz[8|r\'@@`GՍ˾Tk羺|k!y csΣrk Z㕅G 2}0|aoD_@ %hG|ףj⻯.2ҡ"`l}ϟ?ʇX&͚Mo曂Vϲ9_h'6DJґ4}N6Iݾ4 P5G6^6)M c]Bހ@@ C MB怰j|p3(&]6rr1iC,6a8JS_quO0w&]5=DҰ,`IDb³{!5>kޫm$m+aٍN\s5ʋ~I>e]=@]B AF5Ql!$Z]6ou- Tխ'k2 7dȐJPCb>rQGņ3 OxG6MInq-uw ]@vޚ8&P e@@Di߬ɸg4qœhY1v熈wkwӗ;"aR9JyLƍoeq\P6=3:5m)4 հ1MlG8C=44Ѿʂu}76~i9/1}>΀l.cqx8/K12rc&v:_׺ٝwީЖ^xAcJ bcرkG>V|Ag:={م& XA9ctD29pV6=o߼HX@@ j ha0X|L6G>|rL1_^!@dMFm?صO?9 $iaLG ' ]w\HKlRoOMW\q6@HaWJS`Jah̪MԇŽ0}uE0lD`xmʻ =bÍ J/ìN|~m]q1,0Ԍuf_&V2rv,;vp:  8r뭷 UBk+#RQXC HBuGÂr}nfbv%4{qIq;n^̼|g @@( @7̊ZK[\_Zn#35)3KiF./BkTٴM.uCgCC\p6πf.Lk1lv<0_l/:s=I00q2tP].!fڦQl>l0ƹ%mW̲`mr˾obA(QGaN1Jq5jfM0iUvMJ]r%Z` B+eD?m:ݠAj >裦 }dpUWi(\Ac{ތ9eGIo߼wg9( G >hDaF#hT׊ʥLv^ˊdiaK=gtQ%N73)4ɘ.С9Çk ͤF6 {` <@^;Vr&=`fѣR6n8Xg'U2Ԯ~9З)UqEI01eL6M V> ;@@ j#Zsʘqge9Rl˞2pҧҨ*=!!L scc>}0ш4#&# x4=mƍu˅D{ [G1&Ev1cYgSۄ'itm9*,(n5|qQL3h%-Vaz4¾bʄ vAoT0̑tܹR#Cl׫W/1mz3>ߜk^%  PA!(ЖK_`ҤQ35zbfH,!L #q}֭f1 ' +{GۺZχKȅ^nyi*ꌝh'V10;q>{챇^ȣHg4c۬'cJ!V" _~Y _&ǸW~wvvuX@@ j tюbsMd-dV4*U{ 7͉,ԬJك(-t¤}ٲWIk.<1a}ЈhN( 溉oOҦɓ'k -=2DE0x ={j\\{ݵ Nƌĕ\sS ˙g"̫)u&}ڄ=j<0KZSa)kpgHل uaK jCθ6#P.5A>Tp`|}1-iI+_,yIM߮y̱$_F6~6ߚ u@ej4&34lBe>hx}OBs1]ywܡd9k&߮5jPJ@`@`M LXÜ rC# YAca+|sO<8>p_y1Dm؏ L 50+;{uZh_fF_]/ :j]^PhQƧiY^bċan5)@>]>mN8*1g gr0070!iO=TmbdsäFylO?}b7 Q&]s5#p!fp'ʖ2 @X.H4W., Z7 Z  ' 3ghqЬc}׉6O]9R_+b%B` >&N<Ĭh/+:K{ԥ3@@ PӠЀ@@ ?\@`c9la14hc)?]"̎W]u^=xל D|n>+>v`^"8$_mmw|0IbSnMoq=M]u@,]ˉ% u5r]w}MEhѪr)ZnV=GZwsXMۉ;;S]3'd6@XW& X Ti @@ P( 25>G%o ,1TE@@2fWijkCDA` {~I {}VإICy\y% y@YU$Y8 #`(*1y sYsΊit͂p AD4k={Mo޼Ѫs޻ow[U]]-|6Chd 7ܰVZ0 'kSĕ%yVPEy!P >F|XCqC4^{+Z%?Ƴ| N0}k us8N}[lQѼ( n2J \?PN|t;rq5I3B}gf檫*'own;3|p3x`7 O_|s@yOLC(E/U(eڴiB!k(/Ҁ1<)AQsΩS/)'_h]H[=B/P#-mԣG~|k+Q%/&a"i l&d=Yc^Lr7ڋbD8H_|>!?0ZBysAyB]X[]>RKz.i%E@PE@hx*P *_sv˙V0sie_̘Č6}Šw\/\jXQSHq@fL"_Ct #AdNrtꩧ:2c,<]tENa4Fr2"#$(k,XX_פ{V~G S^u?.~P9((# F{X)FY0i':~6ra(Ȉqs1Q䉖JџI^eTA't \-}ĒgC=$]e+?}>/1G>'l|I?ߕ\ UE@P!PEU%B~?s-dj,5{v2?-mafYb:ulgVm:K8>_Ud\'M&hf%,XأABߛ'YC{QH#\zwYguj׵օ#NHW wH^rz-4o( &GUUSLB`h+2%]B>C9=>׽{wF';*Ji\>{cVE+.c_FQ!}\B7}ZRzNPE@P@E~;3snYؘE N;oL\m,ja],>4Xv)1~n\H1 aD,2p|Ȑ!ޕn^?|!agUOҦnj>#W7yݞJ;T"nAI ~D(&XioB(ZQ|8è 9)!"r[o9qq}d-tYo 6&uyK=~WsdVO*"(@k1!X-ڴoc |fV0?Jiwfw -~*vh0{Ɋ).&qtM΍xa2_Vu#{ba&r .BiԳgO n$w/iF9J4d((OR]Zk-'x<&){*Ü2ϯ҃ROClsI;w{q͉0bQFy}l\K{.u_PE@P)T\Kd@uW3˵kk:`Z,igZصZ2Yuj n t"r)fvVN%?Ct뭷Ir>[OD _A] eǁ{qBd$QAț''_E@PEha. sLK_`3[`4Sti1+;tYu-ӷ6GBL͝;*BYτD*7xbN5\&gV],7B! PfOƥ(S"N}BY\]Jg^%'&NY͛>]%,u4"(oWp_e DLE@Q@،2C#"!(#wqan)oE)k"h粙ç+"(eAd> CYjs&LV3,y*RIPj#emnHPE@m"P¿Mh֊"("(@E@6ʙ"("("`"`jƊ"("(@E"sX & K?>a)2jJ"("("pTD ~;>[}H‡J8&j\UE@HF58X! -6%]vmlvݬɽ.K0 '+]^j%Zs +T_XƳgvϨN' _<~ˊ+LZ]z>*DCGCb|U(_k|0CN~aÊvѼ2ICwyGsXD 3"t Bosg1vX}?_Uw9ͫ5ֿ_}aMoCeW\z?n> oY*#G43'OVku"‘O?a+_QJ,,R&X$_p1n>sϙnɜxn͋U})/OBS.6 R妰N*pW7>KkgOW\q{~bVZ,fUW5\pA19y :xs:2/?I"V fm mH'kk'&>t߭[7C!C / ~߷o_ӳg&vΝ +V*]^zaDx>3 E%}Q믿n~{od05]x磀:i@E\A5/$0lk>֏ӗ^zlkرfewA@*2b>1_~衇^7wm>޽{;w}nL^HE=#8}~E5aN;;̼ ;p8~74sxݜ.,(pb͊,i嗻mhֱk,X{キ+__T.M`q9lL a(6|0s1fΜ9/ [(fmVP~!,7o %\R'|Bm.1'}]Kh8sCQ2!CǍg6tSWU^p{ aL})kWtk:묳=c]7]sL ~Y,/3{t̙38À+2+1pL4ܿ"_rOr›RA"#| :+ @H񿿘gL[qb./{t]wuXy9w6^np|GO'/Wy+lN;i<=fww<#AD#TzRL: QHk(/<^oV>ڝ?^\zu0z.avE~oeIO>ҿWg;tIw 0Ew纏b[Y9.Gy] [?Z7Q9J~Ɔ"eC>!)zŖJ2uיo |!UOzp xn0o[q󌺝s<`6e˖ѷ ʣ]y0O%fp`][\/+>0W]uS\L޸ BE.bgYCŇa9C(E`/U(ݴiӜB(ZP^cxcN}xY.!䇕'Z/)'Œ6ZV%ǔ!!FåRH[n09_'Gv!0p>쳝pE{am#r䝧qyLҷq]w>d(yw#b8$]LsBC_"%ży4(xm{W`r-Xb\aqĉFˆe'HьDvtt)Fk, x]tq *FB$,ۋ.ՃťTJJ}B'ϯC7'/y u 7Ѝ^`:&qmsw=JiSPO*Ÿ1l헥=yK^kT5 ԶCOE-͌KL?8A.*CËVoP򗿸6L!AKƪǑ| 1,:{ꩧ:{yJMO|P`<Ќ5 MK(?LF`{ܨu\\^=#8OzQ\]BiB | ch|gDmx12!( 0K/'CTJǏlQ.!,#Js(6(O>F~M;\D6O?M_aR͇^>*lBm'-]û/J`q}(˽48ORߋ8T$ڮqy?'81b!'+.ß' ??7/*2"@e#Du%ҟL͒wNf V4˵mc:u`V-ɋ/0 /X9/*Ȯa$/2>HYv$(:'%2.=`# bɯ>N⋵U+wPJ]P9''t˽l`"髪gFBhB\nˑwZQأ b_裀@GkKXXBFޢRH;u$IjmCk%(!gͮkuYY;uQbvsH }\pw+ᄄ2O:Fx,̑%#ҷr&/H{H諯r}M"ȣ/Dc 63FfB_;餓n[nf 1X ;)Oɛ(6}(Dh Irl^Yʈky<}{ϼ?Fq;synใW\,TdD |Ko̹5fbcj-4;YS 3irYus _˕TA \7\H ^C,&3#=,,[i)S8|y#&HR7͛W)5P]xA*X;H${`fTQrR9N7J<#e9\QȄD3OEvm7g1g$pb8R"O1ҷxH >D`4 >jQq`1pp_蜟W>VrR~9ih0!- "!WX$/C0&9Qb1/B}[^OV8yR\>Š^E)3?K9/D ӶnFΈQGx-?+u}h g~'0V> Vx,Xk򛅻}/Sx_ o>:؏W 1*؏UNAZ\Zk(Iv筕`UPwO^1Wzֹ&'@U~؅,>~Pcc܁X ւ `'[:rV:{'x(;cb2׾R>ىsn?G?z:؆,XmIlUܳZ\?fя#VAv?qyH^KLxj[ xD hR{Dj7'ϮO{8S :iBϒ[./+Rv)[ֳ[2!FZC VY,XwOn~}#fW5   w[׮L׮ؾiiUchthCd%5>ྃ+4O3{޾< >X!|nk,~^fi<M,DI#,nDXp*gRkmX|t~QFȴ G6e!=XM5dH痴D 5+mJXrPZ<wFW9 i}0d#}OUpXͱQ(P)ek6ky~Y7O~ڸؿ/~R0iz$rO~Ylŷ!ɓm:@8º t2Tn 7 К,mߟfj.0- +;tYu-ӷ6}Cǰ6yf%:1w"ȔB<1' 3.˖ 4Źuw`qzI]P>nO夆ȳ6-rcGm-HBHGCÁ1 2;lYVocz욨p܄CDKg>u PfOhϥ(SOXR%Ur`BۗB(q!\+5o7oo?65iizh|5ʭFCټQ<\Kl\K7& B4f7!qAaA!V$⎐J;1+"("Wa)2Z<zAPE@PE@Pr#PEIl! *sL .u("("(G"A(XY*Ӕrk-qR?lvm>13("(eC"A%$jժֹհgK/>}-آޜF;vYve띯fl3rH0sᇛ/Sgyݻkw}nL^MDO*"(@ȈA? @H񿿘gL$]v,f7=X1[>S'GagZo9,Z]!o,b+9ӊwOw)z#8l3s)ԩSbl_>EC5o&[m裏vozu ѡbr7pIQOHi $aMKՙ6;<3W\ќ{oΝ-ͪqI|ҏB _\:,C?A.IniF?;0Ev{m`yӓ uSRE@PGb~,^{3fT3ڌ_eޝ0T iLD}8pꪫBZ}|,\pdsNzJ Ipʼncʇo5ڨG.JGwEkzO>1{챇K_R38}o6#WIsimAׅ^I˖-S>WtAoaϽ3gtجŬvh񄷓7=e+)"(@#PEjȈVD۶[δM+f%foʹ |`&L`?|%:.5?I򗿘} ~コ&:pW_m6lbzNxL3E]F<@3j(/!2Bϑb̘1Jj|_{5wuMKgd7BquA)DPGO0ڳ( &R62qD'oFfV0]tNad;;3LFsim/1G>,l|R7_"("pTD`F%ҟL͒wNf V4˵mc:u`V-ɋ/ C %B욷~ ,kF\aQZwuZn$k(pVDn<1,YX>;~]k] nҭ[7/JWA)uC[ 䫯$fDnr TVZiisKWƊ ";i<IO(wرS dPM5)[FPX;u$yKje"(" TD@Ǣ%4єH͢f^L?v37XɴjƼ‡E@ .B"l9v RDA馛>Ȝ|nw)5P]db85 dUWuͨ@)4>" .R~ NqmW_05;! ` 6oz[L@PE@P(5CXB-ڴoc |fV0?Eiwfw-TC q#  Ds=B# O8“X} s믛oJ,<}pJ={(О6!.O0G `LyIZkqpak=| ɜz0]w7oS}rxCmqQ-Ij>Gݨ|\CDzL( V1F(oz?[g s}&^g!-YʈṂCF/혵V(cܹm+㚑"(M)%2Gۺڵ5w0-3j[m,:B NSN9nuʉ|tJWFD.7H.?hڔx$b/wc~aPqkBq.)Dzr- RM﷉?[GePFJwZiK)svs}J?=# (/ OFP_V@.kᮻ߈u)7`-9+De`]A s|U9³ϼRۅOU瞇 #PSc"3 e$^˂ ( Ke9d=lʂ@IQ K׿ ʵOqR];+c'RL{5g)mAϧr9aG VNݷѬ v'5$ȓFrF*Чmׯ> >I#u}{-WVQ ָP«*-p jU V*ղ5k(X%~&lRu_~+]$>1acB]^d:fϞI=T>pƅ7w'a >?˛оJ"(H 7t+"F"໏ݛvP|xPF;R| YǴX\e A;cE>eЅqaKyBc 1u PЎ ɓ'樣*ŅFB3N;vA`ΈP9W: ENʧ|/Yf9(rE`/B5&9z+" cikm,W`V+߬Yj&@)M * LdNGźhvecz! { Fv@8W6օȭ-ŝNP l.AByfiF8>}ޢea=gb^ ?E@P*@U.Z"(C $ l\S0x`Gp<&ɢu=xq 8yXQ8O'|ҹd @ mEz!޸W^yōH;  gdq~}rʍT5 I!Fn(_TRE@HG@ߖi E@P bu3p,D"1kO[!DAhBB(XʹQS^z' !R8&d'.|턵L|yV,ћ;X NcE@P`0UɋWIPF3sb)̈́-?>X噼>cN-e"! ؀PpҀ;Kom)|"Sr?}ԏ ظ e0Cr4"( 7QFʷQ|#z7U#_ac-n>yyBIP@HRQb8/i*Ԕx.OY%Z_>z*qePRE@ȇ@E&n!賕rDsv9c(nE@5!@Nb:1\l lLE@P~-TdJB>>, G Kk5vO4 &n3!W)/O,eǥ!]|xR ,a's YԫK)Oi<ӔA)VPE Q`I,|Xڶm~ #ˏr=D:33p@sUWW %own;3|p3x`7 Or?{ERvBXP\M欤wBѺ" gC8Cu pbGźii=z#:m%ʣ%$L$ [S!G,{챇K/38}o6WJi<0(y]xᅮJ39s(,% eF!MG!K,uAkzE@PE@ȇ@EXB on9Ӷ f7Z5Ӧs\*X#4Β:Ab} ~C Άn8=W_}[Re{ꩧnD0,<# x5j˖!A ]`njLFz}5)/]v,6TZ xIbwC"'ro6ʂNL8 m[K.r)rvw[MLFsim}E\?q>#U((Ld%b.s},>zZIPE@PE@Aўk'Sdݳii 3sөc;3kyk!_:a2$"=BLfɌY 0Vm([H|$k(p/# iKn<묳Nֺ8@Jj)\nK*C@$4ʂQUU84[%64>" s((dQ])C:n܃xwOcǎNQGY=KIPE@P((\Bs13֘YfO-̤fɢC3pm~_8! +0܋BIC IJZOSLqi#a"m棏>ruC`7o^)롺eq Ҧ#%Dy0:M{cfnD9)4>" .R~o'R6pa$gy6!|ʅkyw|4"("[E"Ad5CX[i2`&~Xe>ڴ}{;ϖu:X8{g@`bwa4#<՗=0q믿8DYx~4ٳsBO;u0G `a.)B$er71#`bqmn=`·iJ뮻)=(UI>~9iiWoFr6df[yFLE@PE"@UDt[w5\cŒvU&ԺІBS{\HpQ}SN1[rt>L܅ #FH)%OB`' OӧO7u'qA!nݺ&BD}vLfDa$!.'tLAO* k3?tɽixM\sY"P{C$lnV7Wk,#?D9mS%U4+"(@yhasLysae/0x-XLxY\֘fo !Νkp Ϭh qHA)s7 >+BbX\bDa[Fg[kq .m"s(}%yLp wtYx㳔 )P}X@v%>:k,*ƻ>˖色ȇn7!z凌E@PR~#}7R[.E-W_}8Y ;6 ZYۘ=&*܏@r}B H %|QxAYJ~DRŘ<*9y0EB .iP,-Pd%=sz79$:R!D_FPpcdP~J܋gXx'fϞ]‡[ڈ$ʚ.)(MW\p_Q$@'dM;G(BCPF;R~RL5 0iҤSBϕ_G~k[.wXg < eO`$=Vf%QtIya\Eǥ5gF p=d)n((k%ΚNzBP C b*UTjەR(hZɓ' 7N_Eӓecc?1R-neY@(@sC"@sEUE) 0rHg G f!7ݒ@D׿v W_ _B g- Lp5s}gd+Ţ|]w~.<5Rh]EcוO\5;2At( Yi\5F `:D8+,2? Dth]i8fb<ōQ;Ε˨q\[)CtK+$zY0dMW*z"4*5TW9QEy p B.^x'83Y_By.BW^Jz&^\qi!>-2H-%pRӦMsʆK'B+ѡ2_x| n(Ѻσީ] !p $*w}nJIbB~q ń5w!qrccpymN8(qRtXPQe-P`ѕE_GRE27əjݜ%qsΕ=ϽXѓde hzθ`Gȍ|e+ҢQYI1B0'I ~[ YIz*@ELցIq_V` 6=0(o߱IĂsVUUNZL[Y6"$/)cc s&bMg^uC3gt}3p]oF:PFuݵ #4QJ n?ƅbP*15Epc/(KeM'eVP~TdD/ 0Xx[0RUb&1|ːs)M4/ܕpAE0`@4Ih),qa.=cu( K܇|QG9k~y+s7|(w? EK!OTBeaڎ&#CYӕŸޣ(MV/ )f!/XA`-&~SL)?MN*Xʆa"CBSxg2,_'x`] `-kPJ^y˓>ُcZ+YTbW ` VH+X䂝HX.Xg_~1eM/YeX`]T _`+!EcΓ y. g~ ޓwk;W|H_WGR<עU vidA+ͥZҽD(Q׏㎳RWpח[d1k"7W_-kGVp?dJ~}#*2"*Ĩ} #&;^z/E;vl2X߼ P6#3͊Za__> ?\:k(C=ũ&=jĤP4ϰ:KѺpw* ~Ϭo0ӱO^i3ۑI}Ȏ 9pE d u!-:eM[)eo$ⰦD5yw%oa5;*WJK 6̹pev!+ˑzX/ 1 xīGa@$-iڊ8\uUNq!> K&At;&g!C"!ªOǢ;LCXG5i>\pd cU+w?{.$AQ>|Cqq6"iZi+QS&~:{Z3D҇ 68],wڒQ-~yK'OQ0kC=&FC<0ia9& xL24jCVQ<ۼl,̟w"(@G <!#d%z Pc|~QK3cS=on۷Vrq̢*Xkc c zY/K16a=U\>b܃yWYwnBP<Ќ5ʭhD.ƌ\0ߧmܨu\\^=@x)T qu$Fu!bK=Cm)!N8+JT ,(i2 D(!Q" (9eg(|1w,m>&22SlҤI.2\Ly9'[95|KUE@PC"YFoK25K=;03,1:3s6WYVͿK Xq'"<!Bf%VĪ%YDD_Fsp`'>.XYV(T/ݖR#T+bZ҆Y0"IDJ+T*˒>Jk0=OF˶v[) rYP $[Ueka_iϛob+)"(@"P1 *9єH͢f^L?v37XɴjƼ‡uj`nfЂ; B"VhZ9Ճ.BۼX𣝄PCUW]յ7>IyYo(lDiJ@ZyqXqbČ Y㓋+1GgNCm#VPE@Pʏ@Eqʍn֦};_3˴a0M߷73;lY2dQ@!ʞ{Y'-',18]l,berw=L\RkC0oJ,<ងpe7 &!1%6 (bA4 T|qa!2A(VR0]wpTғxn דf~ JAԃ8Bg$9cJ!xbC#FԊ7o+"(@ P1E!nfktlXδikڴne:a?ԩ1.$Cu6VN9(>G8+,#t"D .%Oӧ;)=(2I7%o.xPHE{T\ I,< Fĵ#)> CXit%)5kOJG0 _>.?\h{׹!CR~Sa=yd7QBzQNpF EzS/2TY"D oz%9[E@PE@h8Za5:Be/ K,3ΰo;ivri[]0wZo-lJ$"䙕 LKF M!@u&24kg7oF*YbDa[Fg[gqI Jm1O*QJVw<2GE\kRHi4D4Ba?d c B,[~2'"u`ԑ>N$$\Ҩ{iuE@PETH)F  .E-#.|NVʝ[ Ƭz +ܷ1=zvMT?n"|Ep⣏|C(q)J𔃘Ph"-yɫQR{7sb׃g#ȍB?7}\>z^PE@Pʇ@+/2",e( qBf޴se;0;C-eNxSB*)"("(M W,C`4;cE@PE@PT*2Y8 M("("(E@­)"("(MUF;("GJ{KF"-MXrk,^\i>"(1Td ~Ąa o'!Q?ưE@u";bt)L#z)e(Z&vE{,Aָ`eu%E@PC"#oD|y>lY<'905.yA9+" B1e{׊7a޽]V&3t-uUX[(fݻw7XyG{.Y1w~#߽]}W5AyL:՝?guB,ɪj;bq|DvX.O^X ׿g5v%E@PA"Y? [Ei^{?NOX5556Gy[ٵ>P{tMOt Շh^jG>'mRi׆ IWrҖ6k]ߜ6 2$iEofm`e| BhMW!1C= أмۆU_|oѼ|JHhz("P~*2"G&<`ct_3S-~⪊ ?_ެ+&u]q߾}!NaO{7GvFi,~\"o>+N;xGOO<}e7<z1t>c`0PRbA}r<}ђ.X XZ~>`"_.\fih7x&G=.\(Y&aMLՙ6;]Š +9sMuu.X]NY=ѭo%U+ mֆ2 K_ftD >jGinP ~qQpj (^,N;9 n[;^x!XYfy ! 'N<'4K,qϤ+u+J'/ϧ&\rv?%cv '&A0 @bE0ŗ7>33p@sUW};Ç,|t;W &"C 1Gȃ/U(n5 h]CyeG .lq^x I5?f5,fe?n>BL*bPyO_ x;J+d."{pҁ;:MtHF"s= Sj9>||%N:$fňϯ"(@ P XG '<,i5Kiۡ'f%zReηF|`&L`z)'`mK _w}%o<:\p+ȫE.9k ?(4ikz& ?:0$t'g aC܆(O|^Fs<;1ixO(+2e] 9Q/*"_N˳NNX q=bOfRӻg'f%Svfnצ*|Xh ,d\= 1i!kVU=J md E@K#\zwaO~]}\6r#?iC R"y֒6͂WUU+(V\!()iE GpZ(,!H2ǃ|WΝ =D!,%ݠA. 2_V&aFPwc/-?I.y!@"B(B!ʛ>GS9'}зhGPߊWr# ~TյVgSMQE9!P9d,$an֦};_3˴a M߷73;WD†kCB#,P[ q@,&.c }i'0V_&!@ݧmQpO"i'.޸<0i 4L|~%u]\zW徎{s$Zo\G蜗XUy &{<|_~SbȏQ#FԊZ7}__*"Cblaõh"X?Y][ӱ}bI;ӪƮ-кІP&|&m" ԝr)E  a$BO2B'JrM#Yx>}ڃ" FU3a&BDgab!qqEan$‡P]DdچB~rX4vG4L|~I裏p MJmQP|E87/(r{m:.'FZ~X(-?s(P nJ@q|yE@PE@?-\`*B'XMXbp5^~ ؉OK󻂙LU2}maw! *BYτd9Lel+#2:XDIJ׳dO!D7}<5"("$#'n" Bf7!6q7A;;vKYޔzJ"("(@SB*+ȍQq+Î;֎|T$Cc$nE@PE@PET5%!a? [E*i_l9^{?ΖLjjj?lVk'ЏЪUZ d^2}1[lE=s2&رcͲ.[|5giz턒-fvۙ^z+qW"~W`o?nț(=Dɓ ?hțo6wiXc3*t]woѰ9c}[ֺ'kZ7"4K*be!cT~yfԹ.M$.f7믿yNJɱpܷo_s! Q#GagZo9,Z]!o, N+ޑOz9sdgԩNcA63NBѺ:C͛onpGK6n``j%Cu2+HQx wh…Em&ĴK]i3>PZ{=3W\ќ{Ν;[nX uʚK.1mYeU^ 2+6ƈaxl׮{}`Vd:ӥKV[͹BTJIXJ=?#]tyꩧUwҤIp;駟^9 wA%?뮻)X1@qb;M9 <_<+s{WF]0p@sI'9޹e]V+y^z #1B_t);Ļ.g{׹0叚'_yDLִ{n\eQGꫯ.'ypWګ>_;o>etun""E/n~njjfTU̻Y_G"L"/(F( I^{e=ڹ*.ߴ>V(|M >ls7NYӮ:F~Zs ʅ̙3ok㏿]fG8vm Pl$Iq*}! /8AVy` xsW:KRy6~7tS;y;SyG]}QbP|A7;n8'#ds=Nł`e+W_? u Hx@㢼e>&xʻ$ҡ0"η%Jqu #/)\0HxǢmޓ(Irw)ygw(hBϟ?_۬7"4[*J`l߾in9Ӷ f7Z5Ӧs/(X.&L^|찮RceP_(コ&:p$,>჉MO!|2pQFl ݥ`nj,L^1~]/G ЧP~\]4qrPԱH'A8(eD]&Nw|WXaP&A(; (m(5-Zkl'ʫ[_l!bލK˹'t`I>YO:O3orN=@;31!iR?"F,:,7"4b8e˖(eMOE!Ъ,ca$ ~?s-dj,5{v2?-mafYb:ulgVm:R2_:%Bo{&LJZbyr%^B[vYx5'# iĐ1n<||20U+4PZt[J]$P9X@KmL檪*!E)K{J[@W$Aִ/ی0S}!/QBF;up@x@AnbՔ4-||)lkhFp .xJ~ruq{ Bq`YY(鍻Z\k$hyDxCeB/w^(9=YnC>/Ht>as%͋<L/c,Y#p1ka׵%zѢEX(?nIcuI/x( }qQ8&<G^8F (|{umw0=oOY'T{)N@z1A#a#dH)O?B+/6>B'IIaA!MIʏD˻ O6J(].zLPbLV$ LI1#fE4f~c)f Ulڴ1,6dAb_{l3b_}2&~}a 3&<$fXVb&9f3wvLFv312˺mc~coX}b3}s05c='3!A1Žnw8Fx XbELԗcƒ3z~p.yw^A0Fbflyb!Cر11Bh$L%V_k߾L83>C<zh3_g9%jk^1#lF~xA2ll fI<k$zb~c5_N"ÞIfc,c%.+l9N=w-'{BPQ: G?>F،q{*!\g ޒGK6W"G1G3F1ڏ=;nB,jأgDvA<X,ém<Q׻%aCGwŊx`a➸}Y!5 rT\A˝Ɩs/H An gz>D$qX g-sz1dr^Y$[{;Yxv?"cl$ -گ"(e;qtF{!IRt#<NWM*)6{9_եkVJ9'ܤK>P7'c'yL'UL4BY$K~KwJN*p(~/1/f܋TOdR?A87{wdm'|ƭm9fQ*%E@P+詏L8@aCP@Q@ LAS9FMPFzbU&R+)(oV)ur8}׭"(։@`UgK*l)r:"!+nO%E@PE@.9)h"("("*WE@PE@PJ aa`_Rr E@PE@PE UVw}MNrXjժ']?}RReԑwVPE@PE@P @%ExPBaEl!W>1wnE@PE@PE `jժu n=DU;i |}d!Ǭroc[~a0aBN6JYX8 1JIxe"J(c'jC~!~:W,;~l$fp\X,nʔ)QjE@PE@H6mH=(D`.Oa)a$c)?#vȣ>* Bg%2^*mCMr_k?f׍W~lz'UElR4h 6mTn-Zoa=CXk]v{/]txΝexп"("dp}XB?JBŊK|GzYb} 6LS*G}d?ЮE/Ա+_|pr'KǎM_}һwoy衇dʕv}GzU-nVi֬=_q's5]@)=("(D 'B ~,ʇ.I6a#VLrI'doV@aO?]:"/ @D`/U/1 N(s 6` W]uB7br r |( r2maڰ%1b7ȯ*~73V(F3=k%^-~~7ߴ!O^LacI J!CRkbzgl> A͚5οufLR^{U \uGPE@P@NG pR#Ԩ]ZQV 7#WȔipQouBj^zx뮻Ά? TX ؄&`U'gw :p >h-_nw$~tmY/}o7\ZIF@ꫯwa}9 , KA'MqP QFx&N( &nl/bwɞ2~ 7tDz=7QۢX96(qxcƌx7]v+!;"WG<;}w2(kp >̻lHv>Y88RRE@.9:BPk/ X`H6m,'Hzy2obiҸh3fHZX pD腣Ç8d"V_~BrTre'@QHF7s'a4ɷ8 ;ߦ3G8@Nrj2c̙V[/hD^E͝ 0cZE6lPQ D6^P!vƒw~Y9JuBaF5j ~r5X%0\PmM4Sҙ[>OgL_dygB C?E@PȉGJByʸId .\F^^tj UCǸ-BB!B* $8AW3*O&MJT!F?Reܸqr饗Z“nAsqB 3.,(K Vn7r/>Ck qi=cs5P^56(xzHjE()Kx#!O;G,ةS'v64| "akSΡX3w(ƽpDx"Iխ[779L=۷{`E|2kGA=g!v\5yB7Q">yuz|P/2{TxPr9aom>/d1))"Pȉ"9!4feɯnV.*/cfbW7ڵؽe @ӯ_bm9 K /e4#:.e;q\ _m%8FQx"~Rهd@1NhOېO0KK,((H<~< !xƒpAbq2Bšss̀a׵}G(UD_qKq]hB1,0JF`g/ aq$!a}^yPj,@Xcu`?(|MpmwJr/P`I>. 7-4;W΋sB\I o CY;bE~=O?Oyח_~ٶu2.S Y~\?<x L[Nu 7ܘ{vA=pg2?DX[oe1"7IIP@#@h /N^5y5^~-)W' +JTVBB(;<zںyQa#o',wxߣ4m4%" /RڈB۷Iɮ :O%۶mk$HvaAݱ |Xr\.̽Z3hK}z50K[#4{JjůˀEglb% #7E_@Ӯ*wqG\H>g~(@(XIGG*^owLl#.䢐k¼ JҢ3@xQ ~c1R'8OEXa<8EOJ"e*f{Xb@XPYz0k l'60 1miִM Hly*H I'VKIdxqO?4'!|!`AE%gYuǼM9Go<x;s"fp/ɳSNaGr(;1 ?XH _"4 ]JgH-a _y61xA2l>\,;JDXa*Lxy۹}{ڕ-Ot[#\cF!EDm~ dnN!FymF9<}A}|sc>"$'˛ Bs} ^\9Byˈe'0]Ib㷝~OP2_Rt&O\\HCӰIeYƄm^bΗ3/ҵ[+#o%JVDw!*v&裏Nh9sפ ㉗5Am}( x O4mIu'DE.L ԾǼr/RŦ|F[B45R;Бqm,rv"CX :th $g϶5] B7G(^<!WL ޸fΜ960 0!F|aw !悢<kEw}b 060,AF ֣tnL hyA`M2Kz'mD.ԱE `]v!^Ñ;.ns*Ex !j(80"%k A `<$'aKu0>^Br!q^_ ~( 9B1!!?h3c Jx$dUںU@9;#,QVy+G3F5BPl8}1Hb2Gء+3D%, H1$@8~KogL2&R%/jaC³ qܓ(@F@}u"c(I&/c" O;Mγ(*Y^UE`C@)Ê"#୎Sшsi]ySE WDd%zcU"~suE@PE@PEL"EZl!^W2X2y7tҊ"("(@zPş 5]ͽ0?L0l6u)G+ ߩJ(c'jCW/sqxyǦ4)"(@F '8?񛬒ˇ C-g*GN+>v]ڕH; ~|Rs*mCMr_1c[jxǏM6XmѢ]l[liVʬn<7=|p{vg*r-^OC""("d(.A5׭[⧮Vw>ӧ] XԭdZ|d=- j|*%+($7x,Y"/r|tҹLQE@Pȉ"@h˿x OH&MgۄaVرcG:kJ*'t=oI^Y8i>#9B[N zWĻHo-v AԼF{CvQxfgvuNaMwms OV}v<©X5h^6nҥs<+HϮ0N&vs_8;g+(HAY 7ExX}s=zť=\.:Jo݆P]s5[|gVBX";e ^>+Dzw^^^c=lqѣG;СC%E@PE89SXY!˿ ~d>s 9S~=Mf^,C>KB,҃pugȑ#mSZ:Yab#.gu<Vq-}_|Ų>ȇ~(O?' Ȉ#? %Cq2e P85/ڀ1<^uUv>t ۠믿ؼ8-As!Mx{1>|C(ڜx^9^ ێT~7믿nH x pZyDŽ{W ߨm~{z7!O^tA +v6L'Hwm(W^)-?36S XE@PE D`(# /5jKZܥe 2}N|3rLH(%k7lG@ٳx> X@7𑈸\o/\ ~tmY/}oxCV\)}XPW_yٱkX_{;6l Z*Oм4|I4OA"L`iQLܗ_~ ;wή^~C tMrAY axܹnxFibѦM2?#*qR*Ϗ;ڸq  .8?.xPQ|wrλ-3y6v(<_(()"(@IPk/ X`H6m,'Hzy2obiҸ~f̘a%G7v6ddV_Q~j׮]“[CQ ($#BzƃUK޹zӍ0oZ! Qм96>(_LX3gδ*~%!ȫQ BC2vXh>ؖo_n^zV"NC=T.\((~"|, tbkUQ}KFX%E@PE@.9QQyʬyfH5rAer2v|)X[΄"ܯzR~A g%"Xõ($\Fzo>p\XS%o( mI/ªH%h.(Cu <+QcS0pw9*ecK}wBɰ! !ן;}(㕆6g϶~+P yfq=,bI2xƩļQ~kNKٚONj:Q|#+Kt-ᦴKD"-2Nt):M) ȏ{ӕ{7lRY֬1ap_]vkp=}BX: % ON· O& Eu,\ұgJN*p(3tm:Ǽr/aPoԐ!C+IF -"x/_|zXu+#j Q—b13I a~JL*~H(g9s"(OP} 9?o|_{؅駟'33Fnʻ;:1{~XX"URQ+@d]@@!Lxq "L Ea+0OD Aaq%,'|!W@ |. \2 # W_msk~kyf(_Xۄf`JHNP-E怵5Lw(9ELzǣ/PuVOԿ<]K߬swuB,HZŻロP;>Nq?)f 1%E@Pr@N\LDPE`[Bu;*qoD$^m*(}z .B3ybT%sڠ$Cɍе_O8VIɅ`~p'd\9b!pu(@6Iՠl0}*"-# 5{՛"A4+9#1j6e;QfͲX;VJ܆f?%ԈdY npǝ#;u _$5K G?ѵQN5wN9K=HV+@F SȜVBs VLw׭"(edDz,X)ɪ~4>Asx$2AW7J_A}^Z{A}1E@P2@7LFC @G?V"4So)^5&p抰QO?;t˃/\(96ٸa)J tA7֊ 3f̈Wٚ0ҼRESE@9KFGEE95>ď59%wGNY`\Y% e2^*mLv_I]umlJ?_tb4Q2U6Ϥ8Fo*"lyrp>Xy~<c[p}*z} 6,i\jIxX$DQU%E@PE@>91!cw}E2i򼤡AӧO>Va59*B$]}׸k[9lR; "%߶>T8ceɫ*/Pοb'e1<\:꛴wBm2^xмm>o.yV#xcQ( ?G<ǻ ێ}Gay_MݯAY % =aSԶLlݷ8#!;am>Wa5?N x"("d{̔=3F^M0!f2c ,ojcƎ_b/I싯Ů?؇C tD #&.fgbF}A8fBbF03ebF2uM;cFKc$n%+.f)3|p(1#L1S"fmǢdVcbkժU|+WƎ;))g5ぁ͢:1#/^l P\GN/8☩]yxv-\hf7| b'fE]3#1ŌLjQ1#4&}>k`hG_[ožk4ؘY56tv63tglܰsf?w΅DtLYƘ3lbFQғ{Q1s6C߽D㊀"(@I; 'A(0xG6LȬ+SV]IV EY?ThԨQ2zh1Bu6uޝn뮓>SN41X a9yHD\ӿymªU4ejc'zGy㏷gwy<$Xd{䡇#ĊFb;x5yʱD}9+`ׅ+Qt0q -Fy{V۳N;ޣ(7Fzȑ#/x` jb3G(2V@GXdb*ׯX[ 1 mxq@g٥l'^"q˪;{*p? OH/\*uf Q/tQR5ǓQ>asAC&sϵ+j&aCPV $˯k#Xd(+ϩOwt/lܰsdT|.I(ɔdcyE@PE@@#@h X۷k.jHZR O**WZթ,TZMk& t"\ver衇&/lMBC.:\Z,wx5Ӵi"e $#vxPH}Bt*Z %!!DsqޖTIUI}E}MX:ckиaa=}DK)"(@d]@!L?DBfеɎQbpzJ쒌)%K҆@FعDQv?a[߂PH[4k*WJaċ%6N RrY|0ٺ9Q-0n E64}ܺ]w-^/9gBPJ3滣)@F࣏>p⣎:ʮxM(y4.8!uԑSN9^ lle~Gkfa7gO#cǎr뭷İJ:-0`چG<*"ļ) xҳgO[+w|S7+ȳ *|̓W?tW@H"rά~{AxO?dE^2D_M L69pwqG("W^JaE`A 'Ch-_Jn征p~WE#pHX B.%jgv6j[aB%=ջ^SJje\ ʔ)VD,gq :# O<>s]XQ-\R@]GɁP$bզD3VJnOxKZK L?7xyE  Q^E)v7|]\:w/?pk׽A?)]tA]e  #,YVP!r̞ 1˼" VLGxcQE "s*KX!۪U+P>B,qaO5E 1"|p=%Q bM; c CQB!5@jݺP[PrA()|xᘒ"l{$4w 2NZ5/N +JJ䃏 Șqeҽsc9'Um{Rg(#9'{{#@SDY@Ї=\U>AO`jY:dgnc5WsyIZXQ9a'l*QM(Ye}Y.} <"x6I-Ò]=`1@dS|nKf&"']6̺b[e,/ܱc{g}%WNS/QNK!Š\mQ&<*>jeXډoB{1̙3m|=a!4{ȬM%͓U  Xpcmᛸsk* VÜRYf9ꪫlbr޹r-,x.x(ќtb2Gs qdcm)wJIP=r8p߮jUX4*HjUeC)_UHE[#&w+1I&W>˃/J8ᅓRs*m8M6s5n޶68x`+2>$"B90I}Pz/X_e++BXo`r!a->D20`!4gK.Ҿ}{’|zrw^GOV87xU"PLZ^/Oti9aȹۂtW^W\qM&|;&Eij1IJ"!P$oN?tDlЄdeRrU9{zyUc&\(&e&T//GU4Ν o>HF`JƒkZ!9Ri'T@t6r5n*<ƶ.$*"ո'1g/$3|Ϡ}=4^:ǰ#$&ZT>iv$:SRt+v|HhH$[w,XY+k-Zd2^AϏ4'/׃/`R?K\E`[B SH3g#0nT}WC׮]c9F/^, ~Ա\aZl_Vल%x7rxpqlK-waXx?ob?SuKTn d$Q ySk7[uˆ7K]5ᝐsGr(ϱ(\ﲾO2˭7+sM4> OCPP$F99L>4*s.Et P>l1uT328iTA8tKˡ&5nn]ZuUM\@^uD=} qXNH'.* wa !{7}29N:$ld<}V`KZ4o$毖UFR@WX%kU/.?XpG%#6,X,5(β2͘]'G'%aeE` ^1VXJy;װ5xbo.{8ŹG̅)* WL\[ .zvQV!m۶7ȕ+JhOGq2Ǡ Ägc?>kYf_Gm=}(3Wc8"(C Ϲc{t{|%*W7?BLuL1W6m$UTukYzJPݻ[਄ {Y,wuǒ4k~1X%̑“*p-Ba:d>G9杫khHx &!:4(> &n, ý~yip߃DxD'(s ;D((|E lAߕD J̥> >E@PE 3Kmڋ"(!*Fv_)I(^2A+"-,T*"("(>B%nP E@PE@P@1E (3UE@PE@P(PPI:tD\mL"@:uؤZ;վE@PE@Hb@:"NN@SP~WW}E@PE@PdD >VGKM~/-wDPE@P҆@1E daWMN)\'r3'\rV:Ǐ')S{J˖-Evm7ꫯ96m~Rn]e]m d.Ӟ |GwJѕW^i?3ϴ6/_|Qz!M6ލs V{ֻKP>_z%u]-7tlذ^Es9;'_-^xkN4h {+c{WrT{^ҤIu͘3gvmx<}Yԩ0dI~g?$;ߧL"Q,K|⺣("U(E@P"5-?Ԯ][>#o^o/2d5 䪠T\z-LT?!ݻwJ*'|ʋ3I~2?7,_<r7g}fT;uO2p= ;c 0$g`=tҢ7E@P"W;L+"K2)TiƆmֆ0o&}ٳgc A tQ>CAx'gkQUf+Vg9bP֭6,:X?Vh""ɗfnXQE@ X y睭M8 qN'䇜?6!>}z 3@P:uE9>;N. ɸnP#6ƍeQ &oUHȋxꩧlOPE X:"([-Ŀ rGˀd@5a?sM ^nlI0>ln$ wY8X汄1&&P RٳU|I5k=CɓmLʧWE@H*h()'p¶0 C8ꨣlUgyF.bA+Cl4k~u]rWm<: tUWÇD)φУ0^R\>8L *'ApYgwa"(AIЊ~F3w Qyw4nҼ*E҄*EMYoJ򣨸;??_6lXF~~W% ?sB9MJx@dxILɢ$N:2iϟo+"(@4A]C8'[ʁ;N{B=JٺJ 1oTaڛ<6I'Iڛҹ[Rp j#daATRJP5'XO"G.a{.}f,i] ^iShW6]@U(5Umg ȬUfOvVR|бNnM|\|хRhSN^{ݖ%lժ~-ӎ@. u("lIJ1΂4R|̠)>ٖK4.x|0|\-_'E*N^2_vXGv4 ` rK;%U`I6n$ `bv慅/k$9>r KSSOa"w^KW{_* ɕG[iu_,("JYZ,\F0wnV$)]ЂxeIׇSdEM_#רbddޢr^eu R>9^?~|oz &0H79zxda~JVa%$[| /YDXSN9EA uʙqoLZ|jr/*w("(@FD@%cժ!7_<'*F_zsDkmeB=ZgݘTd}TIygfjM|7zvҮU}[d6m?duqSČnHust+}\u1&/[*˶{_ZvdX'RafȆgػ%r~J*Xu˕3I!()pߣ2ϏS"("l+&=fĺZ֓z6T鎥_,tI+MRNY.G(O9R,Yc$B9in;4˜ZD\*}{6,q+y@3g.Ʉ5dup6cUEV6UyGv}r2E/U>~_P^oV 0 2aSbKFwa䃼 /8_Y=BNzo=+2)sW%9satq/ҙ~QE@PE`F +@ZUe*(hа?yIF(/ e,̕$fe٩u\B'YP,Z'|?[yyӳtm@f/^'6nKMM&D'sA|8Jn8iZymu|)WYcL@]e߶J%lV#-/s,5Iѓb贺 a,S)(#($Z% 3;w]V$]r Sg%r}/gq3J)=}=;'.(a%E@PE@P"gQp_Ԩ}fFO^*0:һ{KlG\;Z%>B~xp9]e}M%E/RE@PE`A aߐ5Kuk59Bj<@fpOD3vmN{X%>Zݗ 7IyV6`%_j1o/Zxu L3^U+7ށT4 D8/M*_+*]-MWI߮Gd<nҡ}ee|:aҧ)~_=O & *_ioB9@Qn6KmOn| j+wfksbBW&?ĜI<-]$G=:KeȘզ|hUYe,.4ނpJYS \p> k3 }ءr_JU&s{RjҢ/*"("P("DxNzQ*mO,Y9Zon%Em`%Tv8%nտL {E. lY,Ff,n?؅61T)ZRg׶ /uw<dкҤ roYlT[Df䯗k^Iy >bF+I/_!uI][HÆ FQX*wP;ҩ,ZD{_=iR̛;Gnv;d))"("#P"E ( ~6Rl/\RRz]֚UyQlCLlzhKڵk"{OoU cY/ĞCnss o+˓M4ۛ6'+{õa[nտ|0'[L\#k)Y 5b9[jW+wl/dc. sOCu>S7o^d؂[˿aÆE{DëvfW^S9C&/`㔁SO=U40ϝ" 0uTyYgyV("#P"E 5@^~'H(;1NH/BxOF52 2v"ih/\V CքT["#~#,.F1y{{iӦRc0 exIݧsi7FO#~G,G?@Xa%9/$S X&X.{-7 vi dт"T0 3~J9ʞ"(6@^h ~߸q,,PϢqȺs 5ߥM,7%rAZrCs&_'gӗ#$]\+ M{4 {իWs6[ -J%0C.th_W֯_qQҢx_Uyk2JgCN>|w{OZ%`?Luv| ;S2](]`AOQ2oi;Ez!_}U(ݺuў{ǭ Z߾}K.7ߡ#F$|^,]vp 2|XatGPE@!5yI^WΪ&嫶Ifs6eNƭ,Ǿyzί1J@fR`V9eTzvl$#'Η/~Y sMX+mujK54Zlpρd|Lk 5B= W]u +sʰa/7\  }coW^E>ꨣ_~#e]&]ti+֑PE@P<d\ ZeWk(Ij'ٳ=63CO{hH` Ѱ˕ɴy+7%DcwtY!ل4uP 760N:{[edʕj>q~]w(5"@YMPxSwfo? !9"wJ}v}m}++ytAqe]kx.(H^t_C!뮓c9Ʈq>yK?cwC=Tn{[o;w}),,pO6Ma(PRE@P!MzMtuʵ Gb5[FrM q|Rz9~RfҮU=oVl+o*9\1~gCٮH QaД)SᅲFa"A/3ރ &Pƍ۰LP>S !WVM=\{%م̞"~%z(F Zlp{<diԨPe*RIn},^2s-~mR/ / ԫW϶":Ey͚59͹;aa璍E@P6%RK !1X^yAeeJDד}~^yӹY9پ^52o|7j`ZիȪFٱE5ҶIMO$<~>VE,~~U"0 lj'h…xcP&&5x䒋/)ㄍv/7d/&Á^c?ɯ9s>&UF Ar%l"LE ]yG:v(oU<@+I(i|gJE:thHB ^B* H }ع"("'WZli]iN8Kq'꾧ڏkz.SV c"٣{5e)WL?d"k׬9'jT2l{}((N3;@D&ڷ+$ТLti:5@N n` E8}FZj%lv.EzBPE"P8묳x/J G'Q+dJJޗ=gE@P@BE ,h(֎k()"(eYP-寤("5X*gv 0`dY@("("UN>nLa*^t5 GU tފ"("(@YATn֍{IO(VAIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/repository_desktop/images/repository_settings_300.png0000644000175000017500000002672712346515436031530 0ustar felixfelixPNG  IHDR,j l AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  7iTXtXML:com.adobe.xmp 72 72 5 1 2 3\ IDATxyeE~3ӳ03,3 LkHИh\ M$L~Jb\("Q(.hXqazަէOw޷0UNU}_=Um"rH*())I ӡԧ\}_r sS]*!=ɇyps'͖:_٤|Q!0T[f&鴌M h Ť"N9:в~H4 u84|奥%2:2,c.KK#ɹoX~hc?0(UR_|*4vtUc*):~8q Uq$]$qrJ \B@J17ROf3:q'F844$+V:uꔟ$eee9QFɪMinnI酦O0skZMd?"5 ryJeڑ#`M29oϑU+ɘ#Ҵc 7U<1M# 3% #('2::)u H)s~ȸ_]}ˇJ<`W[jʑmǹCvݜHX=%Kx(;=9s'UVI'1!KZ eSw˙a]ag?ukh] ^,*C4!VҵGpeѺiIc/6ἓȠ!,ZRroT\Ňtnxuu^4?O*sm,HJ~̣i\qdr<̻./1cv_ 3Ɉ3nĚPVipdu +Iz{QjR}Rچ+des))w7AʒQyಕdyi7z[e %Ke'GuZG>"]R߸L'd{464:O)%nV:%WT^Ums=-uR]c-<6LyM&)b|dBi?[өzT^lO:ԥu _Ζ|Tk ISܵNk}BݩVw=I Mqi5iQk< Z_5&t ֬QyC<]o=m+~>mf XukXA>Auea^1S밞kuQ 1vUV3Q6uJVowhUo/zGO9)2ڟdw DZ4֋{㖌ckQ/d3ěBci{L:Vu'G^(%MYXOTNPFi^Zuh^yIr*j]uZ됎rաOLɫ=\}H 9TK:鰌ʔ ֥`\6. :Hʄi׺jF@hYh9uT&l eQ\Gw0{h(tnՃ7ϤOI˻ɘ'w%_1Muhf #ܜS_䇺 4qv\ZTzk' X% ع|-4hYhyn(l:'P^IK.zUI+MRA;Qp:^d2kTNcsѯg/', q{"U2O n\}NLf.vtlO8uxJ?Aۙ!6GMNtġlfTNؗPeIxϑRUsK4 V;#ʦݦBk׳''.|coZu# C` G^w`G)2+zeSY"j՚C q9W:G +wbz$ς!`dG@p(ry A_d9vV2< rO3yK$h3O: A ul@kC`> _nj cOk$>lx^qN:S`1L`!G4559_}ccch;`\^XniC` 2L%;I N JJ vWW^arv (=opf3OzIY 2w޳~}ZuÎ*KyO?uB2wF//k>CT:ɓ'}LoiC` -@߽]`ozwhyMѣ&8avxz'7w׮]_σyyk^#<8|;t|HַzJrȧm q\HX ?sw+Y}_/}K%%ظ[l7CUW]6m$d ^rĽVAT@c̙?7sҀ Gyy7ݻw~?0 vVW +ȿo+<ٱ3-m۶yv9$ۢMuDV)#a!@ [nN7F@wH{L iI~noh8ˀ`K/%` $ظ"y^Š1d"Ѧ\\cƜN_|E?!Ynv-?t}-[̷A]tbh8 M4i r",Ee!#ݼ#bv}|w܁ |C\! OD oqR8SY5͗!ԡqeQ'iL՗OXYpfE\ҹN<ΐ3 AIРs}+(ZF[^rTFb ĕ ox?_z&]w)xYv%Dc}1Ґ~$OٗÛ$@Ґ8D\Ф?Rzu6))H 2px^7oѮ{y/nȸptD ,?w,Zt>0ϙ̕7M~hY8Zmn^9jv^{KtTB󉳅MlǔF A}D׿U><%!8z{=q}.!= Yfܰa' zL<oyH cgOA,|ro2]:z Aт}bS=B%.I[xZɒ'}BΝ;}!G}G7: uG'K&@nً7K17\Øte-q뮻媫wݎ_B3*Wz-k:̝ca;F%\"gԏ}c򖷼ş:s‚.2wt6ټcĹ7 ~ R#׶5Ƹ1|`9b|P0jH&ͣ[Κ@8zeʕ|XJB,. \DA<ۡ/x*,۸wφ' &>&5F_]N`B_,4?}A?G 4{xa"|`r#da/LDmy~u­vHۄ>#n9+ mRHF0LxK,1{(l?/?`?ؿo7 O,9`o}ŁQc!$5'DT@1xw(u0x@a,胔IS_=Ȁvȡ>g-?y|X&.BLՋc>o~DaEWX~ 8W̩܉չnv?/eru{]vQ\鹍]$ O@1IX.iX<_G,?|Y%, WpB|Wysm+_\!j"7z W2o$ uM:/bFބn| _{Y,nf!Gv߼ϵ?!S}f ^`/?_.G?O=a ʜt`)@h~C0rE /<3oh/&g'?^0w y>xY.O,!+yɶ_i>۸{e;/p_7/?+P/X<9,7f C`"auuwM{G78ϡH>O7y8|+|?Q: !`@^,8pw >ϒ ?æs5+<4(r2܂!`"aqϡQ3k%,ywdEZg0 ld%,HEq4|]bl!/s3Z }UNqz| !`@V8ٞ)N40 ){_[TƮ C"x g* //g\3C`q#Sِ#XN+ FV!26 $r",*W^U5=G g*IaV䌨Bd!A,Qn!`#Bi Ca^SnDh.C(*FXEה@!0*$0VQ5冀!PH 2 "`UTxM!`#Bi Ca^SnDh.C(*FXEה@!0*$0VQ5冀!PH 2 "`UTxM!`#Bi Ca^SnDh.C(*FXEה@!0*$0VQ5冀!PH 2 "`UTxM!`#Bi Ca^SnDh.C(*FXEה@!0*$0VQ5冀!PH 2 "`UTxM!`#Bi Ca^SnDh.C(*FXEה@!0*$0VQ5冀!PH 2 "."((VSiyCX%%`*Z C OJKK%}iRoA 𰌏gT8!`?"CV訷oh4aATT:r9qℑUkC`#9f͜&,9ijjK C`"y$yAXtWт!`,|pP¼!LHBa-Fc,h捇ܜA T1:j }`s!FX!^py 5isGF`!nяBrRkL&hΜ9#cx$#O92HBc ۟9Lj(p32G^m_z,qz)p^ . V͛7ǖK,iňetkk'+V|oٲeR]]-kֳ*\0NO"̆ %XoG}Y6/,6nBaL|قV6|A#w{D ڷos=կ~{&m۶yoӚ5k! !k@7^JZG ?ry{|{O?\{~ Oʍ7=1mX㨂%2}E^:yOfKK;vL֯_/AزeٳGV^}] 6xUf`LJv8nz< i e| Zr)F5Ԁ:S* >A@~X:~rK%.H"1/a}AĘIKx#1a$IR)1cay!!(^טK=\P2EGjNonu^i,2Š"b׋Lj3XJ?B܋Y0 @š-< EV0 "#0^TgEn!pU%UU2O,ꆀ!P&8dts}ˣ;IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/repository_desktop/images/repository_add_300.png0000644000175000017500000007217612346515436030417 0ustar felixfelixPNG  IHDR,$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+ pHYs  7iTXtXML:com.adobe.xmp 72 72 5 1 2 3\@IDATx Wőkf~3} ȩry}hl4k$&1$nkQD.Eaa_M =?~303z~RI )))k.͕N:IZZZ 0 (tmݺUpg}&٨E*-- ,,??_֮]+={Bs#ŷfOK. z怷ag6mșgiIFr VSҼB[n-ZZSu]:t / gffʗ6_~ScUpC'UCGpFS#Νkaǹ=>u8 kfu]/#X_$Fe w0q!x9LUs8O>zW \}YkH`ue{?TԄ*{C!߿7˖-[dرrq&#AUܬ{\$yyNUIO_ajLNp\,ol_0ezgLxlRV\)uΜ9;T!¶o.?wlܸ^n۶M.]*#el:t!ҩ8Qv[#tpUȝlw^iҤI!={yer:B?NuR}U "xӦM|r~f (guViܸ g5w6 +zLVV|ͶJJ d̘1mqU1c ;SR]B#+&Mg9외'X;wL?Ѵ\M'{6=E۷O.rѣFO0!i?)! :|Z@8 @PCGKZzH9,p 2ydAp2 nn Due#8nF8yO*JO؟D]tѴ+4mǎ[8M{Æ f(?яl T)&Bwy׾5SOɬY,eʔ)Fle1p7|Q\yCU~_=𪫮 /;C,Yb ΍{- ߴiS({ANEy'9&,MK/+x]w4]y ϶Q80ӟdBe}Q_j5:w^8!dXY"O.+qaB"d bee*t8oܤYn ZVpt(q{ϋ0g*>xi=-Nzq4WXaZMvQNfꃺBL{}md>S'|Ofկ~UhLHCnF袋XI$ЫW/#\pAŔ>fL~r@oE;|~m{{oI$0FEb|Mźtb }2h 24ߦSmk6%# =I?7LlRzd"5`pz!c08 SU.p$!a>qQI2|!dkT9`!ԟx/ G19s!BƧ`x)|$-Z0,f0Ǵ G{G"tʀ@~8w\ҠMm<2^'h.ʳj\6L;1V4);v4, IbZjE64Q+W7MhhsAi=+qa ;x>}Xݻ+Fkq!swgi<{WE~@4mzhc5 ,kxC)uE_^viӦلZ [L>FGLQiV2+;,[3MxfA025xah|[9٧p%֑P۶mk)i޽mt)`))'gB3t i 9 dQ>: aN" s8BS%WU9N+VF8{xyE'y:O yxL3Y$x.<,L.BByOqqtr3:5+rјXff߿ȉ~m"+yL㍉L*;4F]*2cf,SY~)#? f (h)Z64G=C4C3w"\#/{|ChA/+YS^5G>;%\_M~& :y^|~2v0`5)_m<_xc`rqp{X觨VR@YBcF_` @'GKǧ#/^l@ރtc\$?<\Gfpфqr9>uD@YQZJ58lR+[i^:ʌkiR)ܻM6*:Ic?e:H()Zt YZE˅Y"Ah:]q~U ^@zM ahewqک@L+'h7tG^Pާ '$yGЪ"d*=dvKq $tK<;Og8OIaqxE65O'ӐxGA!'m~†t03 񞇇Q*= wwY4c{314E ~zs7/ M„WRZP&k>Z'L q#RseՂ2K+wC}2eI-2oIqg.j̍rJV3bCf}e曳ewr~4];TI,;]>-:NNQV}E3O&]ƤP+˻d2]|4&cO9QZTQg[7xUȥʚ9efA&ʆl~\\x "JMS ˬHYÚ023EWfv2=e%4\*cfgd@qa4x~eMOqgYN7u8U& (D; Ӷ ^k?yB#<}<8xy2;=.Y8a\!c BOL /ҳG-S(,G?|(ļ5C?5ا/T UC+vyLNTZ9Zh_aXUD- p沫Vx8 v;K;Ca]4sbIx\z <6;顦!`f\nꝆ3ٳU>3MKwɒIƷ0|̈  B 5,40gmq~xZdyeٕPYj&e)4@.j+ N/hT<$h>|l{HPZS/v#@0ġ}8ߔI9D2#SF4$܉@csvz4RAp篣v wJRuN'[ms泵M5:u*NI'uZ[DW,]5 miieo߶[RUP-5#C\[&*T3x8YGմ|0MiwvbG)ٲKq6&d-n!L7OvIzS,%%=SW׹)WXN]d=RRڵi-UȖJ-W_QִyiRcwHNni\g+iTd\Il&m^,U.ŅuzSP&M I͔&m@Atmer2Q\%Y~V2swowd~vY#[T 9{TM}d+̦9j.xt,ЩҝK}4nT9e˦;uԲobMdȤ RD O| seJwҬes)QĆxF_;ř8Jv[tR$?wkYVjFCm#ْ["Mt8`Tjd< mvm!?0^!tcpsAY$s A?eo'sŊ(SZJQEk,[;ʦ|[i#Ua-Ut|CB,2ħ!4"< ùw!ȐHD?g[>g.OoǙCx =PhbOEhW&~y{䣹˥q'I2u ؾ-$5,_4K^}c4BvY'Ck۾Nf,NVrK~jwr7Ri-zɣ˖g /}" 9g:Sޔ4Je CJ.j 5iv' CxZ&69 :JTpeR3[g)H52o|GL2I~f_9s7,~K[+)tk%?Mʥ2cL^&ŹEwrҨ,WV/Ң4+#vpX%hGEJ?4zXN  efٱJޜ>K֫M(7_:?UΙ4DȒɢ}MI>;d_iKԞک*M7dK py;Jd rҨHf&A D2:)tjG< >Kt-_)yZo8UJ9SN2iXtD1Z"o9_efW txUIS5pOZ|40taqX  ~\-K5,[o=&+7J٦2mGkr.iٽq6LH[r;Gz6˖w_{En-#WK~yl` 9_o6m(6r$gutm^ kW$ggV K4f+/JRWbB95to8L5S:t!Ε;u] '^O:udk1:m-Pm)&벾re'ɞ%Sߒ{K=*Ȕ_F]&G]-/N{`>襶 cʷs2c]t+#WinYThw7'g#O%,'n*Tɩϖ:ʂO[NJ̔7!c/\Fi&"ϼ1UZv>NEH3)SN.%9:h),WT٫C)C =fʄ3NEZR".\tKs^^{Cw!ǣfMe#伳'KV y? `{2$5-l,ד-N&L-R޶NpiCabÆ1_O$Mtpб!Ă'}@Pq^?A hP7`5;y6 36Z3h6UtR؅m=GRn=M%U{xA;%΅ .l4F"( 9mhx/NT+-](yycZYidvPcd t&eHFͤSһB]cnshڡr~|:%+l\Z(PsK;:(V@fNKfS-[+]vINӞ2&_Q4SﴺNS͟-,ѪP:!sWͭY1rP]hB󘞼m[jͥѶUxr/#)MT (cpY].AJ[Ϯ]tN^fn({sUhYOFkT-OT5'k!UC\YdX-#/8_tn,{}&l[oHjV-̑=`/5NzHfFe:Ζye}i7'KgHz; -WW$Da~qfniܬ}ɲ ;IWIY\6oϖ2]`(Q(Eb^)(%ŦfX;_ܾ_qFV[3M>. L9I6.-,ڬVSòr\֬-["m -uZSaTA)'g{gcY{9w9W/ճOo8&yZOZEIQFlZ<ٲ%?]w6CXHz:_.,i'Eu#o-{mңH3世UcPE#;B^׼C&WJKWauWMdeN;4ոꉩ]t Iw% ]Z꠬ԌZ/TaXFF:j{J b5cHb/]W erwyWdm6;T4hz5"scpwP[Sb-%] T\#yJOjz]澿Z:9N:%.7oW>|vO8 ~}0O?1&,73!Esxq\S׃THR['>w8N4L/3B / \<݂94xpN{5eKa[w9rƤ2qҙjW:MN[*iMUHT>\^m(ϓOsu P|jz#6e[toe2@G͗j{j_2s^|8]5('W& U{YIO&TԤS/G,Wlh){26:X[v}w.[ٵcqudĈ2J_QȀ҈Y*mW *?G6|i}t)[7neҫ]S))P{ݲa6igڮFK-Z;Y'iDJt|ܛ!Y,y-ҶQSiԬJe -nhNUm+y)gM9qY3If)HIj$MɨqHͥcHW_GwSTbo/Z(M٪`?!E;r:5]kV[],M͛Jz,yG>gjg:E[x-*ꥨɡQ-MeI?ey~dϓ=ʘ>U{˲iYK!ٖ-Ly鰩F|)mIvˤ̑ɤad?Ե^">Nt-gy]Ҩx2vPis'{{_K2hD_) $cfi?4޲p+NKiLZ*˦g3&K'*߳2{sI]H8 .U DWPhlH={-{ SKiSWu:@y-rorBޓwx% #PU:`p~]hB[ iMK }.C6k[T SZAvѩWdnjZ)jjN-kB^˧BD9iқ\ͻ4CFT/;H^>oD? #5O}EfLVQ4jZZ5aN"j{wRkRZhbm=\ؚжPZ65'Oh4UTޕS>}CqlY mPݰ>]O̓'%:_+m/Cc&rٖƺTކ1PAnU&ڋڴR2uνURqGX!TЊx/@?+.xxxi ):v}a'4yƁG8i 5`o)a|S!c tTT֮K71LoF4aӬtҍBD DyUlCI73U4t)+/SuPQ"UARhm aֹJUb_QQ~@J "x5l1JbVٶVT aѲ}YZ6Xq\JOo6/ms" mqt5F L`:hce :VFXkң*XtРmwUj"źuBW+O-P>P{_]SͳPmiJ6oQZ#i+D;^f(y+Ҫ y-TSn۩ Ub(Zݻ֤Vn|eIjWzoމzכ`Vp_ Cap<0yž:U(mph]| ]XbiVJGz[NչR9CJ66{$6z\j%(eU6Fq/Fc2id0\$ B3{`]: #;ßBIVQ'"X!iS(rWWI}= _q/!Tk#VR '#8|"'gʣUMh@;)@gvi?xq|>_m^tUЪwx=P:-y6_N|9 G`aB` | Mp2gikܪcڶ/䋑FR}>V2tk98 HȶJF J5%shPU831#?3!Lxd, ƽ(OK,[sUaءq(Њxং^*ѩU©rZU€c.ʥ?.\rw/Xp2 [$UOāu_=mذV JGnӰ.-+TB}ā|b%Fylg΢N0m+PG8P_H׾&Ç7.Ԟ ѯSΝ"@Ђie )_uYUx"\q.9~`FvPHwB6n/|+MkM=ϐ0txDzNf I^N7ivxq!pC 6+8PW߿wUZ#XS>|RnͰ;2x O"CwV{/_}kk22:~ëᔑrsqˆs^9_C xM~+9OGZ:ҰaÄަpСC+ljlXd}5?HF>$x]bZ‡c3|A9l|#"M\ .9OWXeG0D;y/}]{aРAC+V{gñm<{1ե^j" Cwp@twޙi??_^Əo#wvOs>Ϟ=dO阯_Hf}_/_R~omQ9C>xħtH$<<\8AaI'E(!k]'ImtW^yW_?^uU/@>.qˇ@Cf͚ede%ַzr-*~vѴi_6)U78PWybjVMq# t.j]lk#:3BZ^pvp ru{3fu>;?tbV<]qr[^hJGӑy!'O=~&իW `>p DkD+/B˅>"}d@.okSq4 3HN !x˛/k,\OItEPN1ܴiQ+g3AգG7a)7+V81MC!86ZDgZw}@LI`_}OXE%O1:@C3FϜ9>Тh+98hOhXS7:Go6hr<0" |.1/#)l>HCx]HXt*B2H dڇnK?pZxgƀbEG{;4A'Es_jZ wam"8q>feeU b~wІ¡U".,*mH<^ʈ'5H0L:>`4Q&6˔ǁ|C1r 7hM!NIq8W ΌBc2}m$:Ǔ^8tbrԊ BާD9n|˽kd #-2 VYE)C9^kMV.wNUhsm \q:I=:+îJz &0x"M !:2Un"*4Zwh\x΄A`E3`#Bb57M4 mF@:6aZh|uFʵ+O@`8΅#.;F3&AŴ<1cG(=Zƍgxf ~ q8|-/ >` ZBx~:^xWȤIs5jF70>霧zmY@736ڵ]xfagNb_if:%,2ˊ!{!tC}q4m‘i 1x~;t!dVFhAt'xŒeEؒ4uY&0H%o"{8lEש~ ¡"pOhCOH2!PO9Ѵy'@-q#s`itZ1  #|j!Sá<0R[-aw;؇|t(@G":(+]h 'NmLģ!Рxttf¢El L`p}1BBς s'`Iy=q!ûLϘґ plc@Gеzj\7p9YT@B~ylN%//-IDATЀ cxV=E+rth?31 (81U)#32ѸR`y()qr01#-uG0)IkOGZ:/QVCf~# u:0' x^G;n3%{,8'vp{=q~w/<>ё7>MIFh7#X1$i8^{jgCVDg!úv)tl ǴdzCfy߄DI qx<p!l4#d"Tn6, FDaHW&&1ִ<|āc7Dz+ ),)Q5`R#"|.9Bjjq>8PARaXCeZ}4(G T`q%vEG8V9p4V&,*tY! KFl}q@p\}? v(gra)b^ zl?PIIOځx|m2?r"=eDӂ ʽ?'8Sl#.<>/#@āeD89sU.ט^~|`^R?9Xc_%a؞Wcҟ%㻺dV8@]Afl|n:̟'S _Lc1&ʗ0pI&/8)c65$3.ʑ]WyDx#DuЮU(k7#9SBϓ'OSbu]'7o6T} ?>S|\ū9{YuYuAk3ٸ.ol8|89á8Nja \,/ *n9"4/b# V|?^j b뒉uHz:}7׉)~! cO!H|ϮU&hUC">~]wU| $}]8h ]]1/#8p,sϵd_#G`x+>\x;`١Q!PS[G1|!QLsbt믷X,?o߾B "o]8E8P@YU7n=ڲLa!{^\X7xc~E]dYYYrw?nqB ".>v L|J6GfE߶m[ 똠x|#Q`zkq~ $" .Ȁ0*kW,gbC\āK.6m!-.D`!oЪ\s8 ~<0`@YGEFs.xwxx~o˥ܻ =|Y_yFD8p@E샡\rl).${v߁?yg9"4X 4":"D8XdGsZ((@ācXX"q @ā ͡%M$sYV"q @ā@b+Oz)yuǞ ^Aʢ"аB?6a(d?86yyxb9@āXhNNj@T^rʔ)SUU8q*%4;窫2j޽r= җ^z,]To.3f̰ö"|U#DM&ѡCڋdcWӨ:,Yx\~ҡC{}'cfD"DH3\ql̵^+w7ިxԃ>(<|ߕ]QTя~lXXE8P0ꫯ͛g >@T%v-C86!-$\p^$i7Բ +{f'"\<v0mC-dC >1b0rpEjzc;#?oUa+~ቅs1fڍJxXW.N& _ y'o@=;x|W̞ WCG:QHmq;!BjŊa 49=n+baMocsfHJE-afj=5VB]XQ|Ӟr)5H_>{T]3 d =[sZn]ux eޓիWo^6vzPUӑŧ™ r9m5=hLtMX Tx &ӦM3EC{u3v +o˞Ouqt#M߳gOPYC%,/YvPEd!h0Py2 aUIX)_qtus4]" 5̈́IyxGt;suchV ǑГHSiZϛ>K{C5YT,q}֬Y7OF{ù= IxĴUm9pҁo429餓l?]b݄`q*ܹsޔ@;ra^-pJj*3gi{}W2I(bZܡf<3rRy) }ɘPT.EO#:gʕrw -W^iFH`A06HƑ;CVX X&>: ~Li_A-o!wכaE]%SN5x*y}N5Iʯ&%V,Ex$<1hf?oLfjY /W`:Ζ5 ^6,M{VܨSE )aIJj5hX8 =pjqNW(i#wM~sΑvfð=dĿ/ШL^um_=g\NjB7C5tgR}*4zк[dĈP ՜;~iym]t`nCghUCAp8h<0ՠ\8Yg"2e<63}Ewۿ/ht.҇~hZ!Ҍ9һ3bjoCYOdIz{x3fLal套^2Q6ꎺtgo솤?s%n*Lh@wt3gԭj/>y64nNͧa |Urxa!-ZdL|]:Nw.Ơ3qDcB;tkW  /o&ËdP/iƋ6^>)0^F*8A"_;lS,N8a@@u=s6v&ѣu]D} :o4,q/ͩ} = sa:4/;8*p5,:7䝻vԏBgXAXQOÇ7Y,[)  .wyǶ{b9cC@^du,=왢ɳ8m\N =hN;Sq{C 3 ^sn8x:σa>j30Mk`VY J!14 .H$ G]D#b9:7/pcRt{#9hꊩGhN:/vC5 :4`Z#20^t+ PF^5K`/x΂e]Vq fp?QgƱNLmfHۈ1?!;X0gPXT8 aa`JC(+ #84(OZ]u "xLz@=4 |vo]BC XdeN ?/r)0M'xol^e@0`J֮]+k:RO|G(34_ 픥>J]uM`QN^2ַe }4xzt:eL"h8͈mtmj.9nXb@ѬtfEnfӶiq Z9`$&_:&00H_U';6w|774`”xyp 斪~FF#DױcD4TVlM55Ũ\p{4ʪ+|h 4L63mEbQbA+-gax_cdtN88X Nl|I |.l =`uA@PvLN>Z/ UcP<2qR|1~Ƃi[׆kM'3ЎkMG@mx&/~y9St-KF#xE,_ܘU(Bw:+jOXu;+8{.y0޼1G8j8H^: qṀA3 m!dTIOeAmt(GylEcp$t*x;vt4];C:aK]D_x9s58J%4ć |Q8?3S/:"FR8?uC;p: xBcO7}`-Z,+l" AEbc;o+jz@eBb79$n?M-NV'E5+6. ε0SO' 8q @mr B1X psŒWrXɉVmVI+@ā8P]oَ y[$BE"Rٟ¡mƞD ufo?8"W Rhb>4['r{,hPW ,˻Va>Qqȁ؟'BmAa,g~qD8q9à>B/p&waB殉%∞#D8P{2mNHѮ_6a2);8j_ā)*l*^ģOXLMs$,Xٛ#%v/Kf鋽h\ΑG~ā^Yi%".$.!Dr>,p9VXTh[xF(!DMZъ\ājd]x"D.\1>?TC ,LG"D(@{JwH ]`{E~āB,9‡ذda& #cpI:t`dp!CaC8=0<:! >1HõFOu,>y]̓;`KؐW0o!qma \o๪* , 1TT=҇pS^usd;3ߞ|I92-B >::B+_}2R4j9OCh~<)%^G-zrÆ r'lz6&B:7n5QuΜ94i EX>J&_oo2+D`юyhY* ) ׋.8( ژbכD?G ; ڝ _#$FQF(J8 B>CZp'3pv5hֱB!Ec"(NސGS_bhJ4RqOc-O~Ӆ`jPO #D?p/ktt\G&КPhB!YxYP CGb*F }ʔ)f!-0W^yM|!oݴ5E׾5pwq'ZliiI7*+ /`<^z6 !|K]p&SkR-: $C/"p~6 l M"Z>)1҈1Sl)8!HcuGg}l), f7LSA @GtfpjX#>AZ 3hr!Ih JC"Ш!xHC|qpVA{A~d:>xK/0{CCy2H Tp|p\G8ħNS.v=푋g>JF] 4 ʹ 4b!h11ĀH˔ 5|NniPt(Z7DB.4<hzl3b1B7{ƮM!,32O9S耡'AGh!:xg$qSFda!):GMœ{Ǔ;'|ux _B<2qDӢCӂ.HO\ OCLAi0# ~🋺uSW\܇F\D{5M\~14idNCa$Q1ڗzNE_Q\hF<5TBBёCGEΣ s9@QUrlfrvp  B[̆ `g)~ <Ԗ]U.]n?96fcv6ϬVw;՚u_Y>7 .IɅ3ƀqpWv@ZSf'y`gf&oՏk뵴|#;芳 D<z~$d]§!6ն,%1RN dP  ?~lk>M~8G8F3öfAqY a- 9&777scnťL"(ZBs|O:Ly*> HRNx˧-\SΥo_";NO6ye)v|Ǒ}{[剟QU|dŁ0,#1V#|Td́Q^S +0kCgur'E#=o,pbyN~ܾ:)Q$W*DK?o }e@l<62nםVX`5B}I8+3" DÁK9|g~|IǦO㓾,p#?++|zEii0>LCpm.m"тKC Pݗ} 8FޅuTF)* 0m(\`OK}ٟQYMѺCOz:yc<7ۖ>Nh슯)kqeybً%'$HWj}VH5߷Snp>Nc{wS l !愉Imϒ.П뙳 ۷m}Meۀ$zئc|_:4â 5 2 1 m @IDATxEM.I $L(! &*E" (MD">JEE@ET@zo{&-R(Aғy;7'><-M8'yΜ9333gf&MTYT*pDRqjcPN敝vDzUOiT䗛O\JJy;_uUէ^XLaM'.jxѯ^S/GsZ&Շ0|R5RގW]Uj#9-CrS>K^)oGW뜖I!L~k?~|SNe%,`J[ ͜93%M/+[Džt->MşƯxx!m^i>WVWrǟ^KP9ţ!>n+x+uu/I?,+>~ghU HbֵxqW\nZnd)\H<~M6#aP} M}S-}w*V0Wt->OWW<6_NkKJ+uӺO%KyB2>'ݻRK-eK/-b1Lpi=X>}4Qx*}'sy$0x/2\|y$Eď )JӴyz)߬,_<$R}^l9_?MrVD'#Eiď )JӴyz)߬,_<3~۳y+N_?MrVDz><]F$?MWRߟu2iSڳm_vʵd/˟S+"=Y.?M#~\HWaܸqܱͩcڰalQٳg Q^dElVqDKe["OeI入Yf]2^aLyʧ'iUX6«<+]J4?ԒN|1-2qkj;l#ߔO7݆/Ri5UlIa4 )ǟ&yyqyas/7(tP4i+$UIa4 yya&JZkG# FzӥKc_2ՠGU6Og-eyi9GWz O㐡^pE S,.Y^Oӊ'u%GaJGꖍ:On6MdV[3ֺ$o6ǜ>Q(WqM\Z {hj+i<~HW(նćJJtiyr"Uxʋ?Ǹ=ztzW]ڌ3lʔ)0,xycƌ)7 QXqoԨQ冤F%9iYk*5?&yt#MM"꒏S~ʊ4m_pK&SڬxϏrV*䈟k(2N\#S<)#[M!J&!IaSwSx*tJ+mi\^\C s3/6b /acCA8nΝ7^y <\S<+X̜C}5ǟgm{>곳E |BU֞U,||b9y, /OpkJϬdU5JV)^u9m@z/ aqVɟ&=)cV#Ps RPW7^yʃ EJe#^yA!kNˁ_airJ(SKe'<+^>hJ'92 KZ㇈Sʁ+Ky%/ˣk\!GpOxZ/ xDJK|*xO+ >Vp%[r|)䥲 L |ʃ8fdTUp%>}|gh;SJC[n=;tR?Ri=[~߰pCv]ےjF47moc}}!{;p6Ηz;o &C=hW7ַu0&6fθ v؀gF7o-ҳM%-R_ܬ5}m͗ iSxM۳R6a6䅧lۊy SN¬Jx _5ak\g+ziC<'P>i5qUn3Ho[ħ4|k?$/_?`f^:qMa8Ҧu4-GZ$ʒ\#{˟Z@~+kS` G^|*KӦHY>++Niq8U&!GSX*&WJk\RAJ|C*Na\+,CyqTFr+$;0CZaK~ygZcN6śO/Dt a}5<Aa׹>pYhVX{I64 ݵl"y}8mTmX.qj Tn*Q8*k|/l׊SzJ儗8(Nc? S>/0 #̒ε²J6]ҺNfPWa^[xSa<2}kS e5iM Rm֫Wk eb+٠3'߶q/}aKn-93!@'xބ ~~js=I9wW|^$.;K,_,\x!C(w"x! 5 \~C?BW<)O?,ȖLPZv; &RzK-^p]+^.D|\ūN(, J?n^:!KzpɐL\~iģ|tvkœȁ$pa0O~| 7$? W!mRXN/N֭k7s`{?®{I󹞶&ٌ\Fp۴o4zS$‡ (a`u^454ZS\G5lmvc[}m>S{GweN?77Js܀ih0sUkޤBQYi`!fxwKC0#$:~u 1jk\ܶ]ه9MUoƙK4-T;xTAkF]vHdH&.}W|WptYQ'W޿aP-(?qM`cuSwv{ᑗboo-LGdvRV_f3_6kÞ{!AbA{F5԰ ԏ_g=̖~ o`1ݭCjov4n!*_]FP) ̜WlcmuuāOrYX8wuQ_zθ~^e 6/}u}ş[!l?)va)n#GsC|"?h3~xX=l%eY&4[)@YFc@yfeY,ƆR\zOrR56%t~,>R"SqW>l˒ʂ+2u^(^iUS^?q_ă#nJ*gel4*#'NCYږ?Yz W\ҒFq?q_w\M/q'PzgI"!#_WҪ\~\aĈ2FaFn<ǂ]q'x|L)r:S\R%t Sp/qS0U6\TT6eLŇ : ,Ҥq*%?$Y$\yeNQAßi$3?&Ldyċ/O2kMS*_\_qS~!'%#CqNi:*%4i~#?.ʃkIVG2 W^ixxyiL ?YK|Sl>}{^Mqn!EPuϚ wƬ664Mo?]0[[ɚ9-ݯa[y(|r'a5&\?o/ \!}%4L /\ʦ_H+ JK^6m*WE+)_8% 7cf Vޑ?F5E}m07{*guG*kzRN*<18m7:MY?kfB;U\кI7a?A|ʏ_׊|\ʒ%%[qȀH&ג%9*'<ů+ aiNaJr(LʏH7S q"%[aȀW=-N>ŋ_i W aJv0]㊇8aKy<)̸b^LxW܎w &F{;MPO?pu_b? 'Ͽ?jS%ݩx+mGz)D)܎^]S7U= Op~o5j\ J'\ 1{C S<7_Zyf,y2SxStDVJp'7%<O=ă7aP<8#,l4&_!/ڀn#8*38#8 _~cG|GֳgϸV,b+?M<ٖXbGpF¿0 # 0~xO/YjO>/*8#8-Go+-S:@;!, h'N,=&L`+u޽MrD qGp%\2WdKsc+Gw0r%>l_;#8_ZtK<@{Q܂SC/#8#2:⊶KDžonOjYmk_~m$8ԩS+(b"pGp^j.;餓c?pASO7͘V[me\s|+g8#8#,MznM6[+޳A{ڝwn&u]wg;q]ewq1@^?8 {gOV[ͦOUGY`cYql7:89#8#8_ kvZ:G۞{iC;f? /Pgoֿ{βC=^z饸 '`s3&da>=~=cq_JHKYN9;ꨣ좋.68h@0_ѣuGL2ņg- 뮸}iKĨQ_6p*ٍ"4ƌ0L Cd?{ Okq)g^ƱP^+_j|Em@5<~aG *r+uU'|2g#[WL6-uGDH#-E*t5[y*3%(/;8E;h#G,swjr=s0%}7iSO.)?~ĺt'|A6™gF:5uҥ]dvBvY-<Eҽ/z6ҶW  ~ 8 EÂs=g&G)G }Zew=haƋY3E#^|/~ GX>x-le=x`ڲFEF17@g2AAdGQBbeꫯ6l4 }(1NG矏q T+|Pyף0|q+gL$P>S\x3p-k0:.p*OZW:l ?iҤXve\b>WX?.ltq <ʹC (du%PҲ[ 2cYP QfVp PriSjS0ؑspz̻=j;iR2h+Ʈ FPY /}mF0C '|$]uv(/uj4`(CΝ޼$yEh}<%.qTq'Gp`з$c?x",{ 7c`' `FOiP`PxgI\12ePޕysr:Qr2XS\(]J/|xwщIu[|`|+RbӺ,׳g8U^)OOB9n햲TW_I ʻW̹/;v?_{B1Caj m3-n|);3Yb[."&W?ʕw[l| JH~Ghd̔((JtJau<0A>^2:# G1 B.k *#.Mǵhĉ>/0uB0W}(0ǔPD1IDØ) |txؠ@*+R^q FËw8jrҠe)OֿfDt0(7.6))Z432E{W4Zp?̐HWxX&ģͫD/ B¯GKJ<3 U-y6Tۑ@~s ,z1BUSY.lzYB$,x1Ӝ6|~8A`"hR(apGFFbQ*N F] <3Qkz+?v[l,hmgERHj_x9#Йap-"\C1ka\ԒjbTm@=yy#6h<:#vHE 0w~P_}k s(B"t<p瓠3Bk]ӈ.F#<_;_PpAs^nGXhf$ٸ2xގ@ld׎@T9^S>sFaafeauV 8#8#8 >_cvYĺNa+~f{OX7]N 'Nd ;:}UK̩6nQD.]"Jy ҍ(*9#8#,Dڴ&4eڬt]:: )0vĘF͘iYXSv`kZ ["ڎ=OHg4JCA@a@q hJt8GQg _e~'vq-0SO=e>?,!_6#8 6 ۦ={tǽ:qÏ1̒=365̜XWkKF9#x㍨lzYp=#*qtUBGt bzkT G׾G{1kll@~7=𨣎:4BԏS-IE8@ M(EDنSk#F99YѕW^ixȫ%G0GpGp@'OnTbܩn?ad|Zk ?l_SPNO5{78*/{WSOJ(GYwqԞ9%Q*c"k; (5!'0q3ҍ#<bFf%#뵔9>|ox<誫2nFsKp(© OL:Et>R#BO?M8#8#!Ȩ~+@~?c վTb`_+a"ҥKs -Ң[0 N!%=KӠ2bꫯFS,O ~x9gsBZʙ*ɘ)a*"Zjv,F(^+ѹIP]vן/v<Cp\?#8#8‰@0r9w0>QnsBh_!VtIL{VXa$r6&/oxFQ_{hڳ;R"?f?}Utt]wݨ83&*䥑z),e91'Fѩ:jE6dXcrRvb=EÆ k|2dqGpG`CӤi3~0?l,{`I=S &?MkCm 6,TE)GYeH^Yx{DQFş{PnH2b/8sm1 l!zf)ZNl<\qPr-̀r` 91j3vZ~GH55 v-i/YLy ;=CQ0Ժ[W۔._|kE0l6(mm"!oos!dvFJ0#䂋ͯV&$ "&&Cc۶(˓}U#pN&Woi<3'Ga1S L/&m9Ckjn!z; ?xQPA=Ǧ K;Bl|%D>s޿2;}饗Mb 1#m/WmruYgA-{CC[#uG`Bwg?Ɣ:e mY>auweAne ٠uHXIfzx"YfLN~G@F֏qh#)lOm= a^VGpKF!6@dpf @k~PEtfxGL0CǏCYLF/)<_Oٳg\$L| nb'q )cH"p9 L}'Z&Lvyx9quU wޙ|!fPG@Ow_S:WTQtHO'LǬ"OH@6pøss1 Z7dݘVwkX('w}׎?xOf@ :XPffhi[ˠkCP:@N'Gp+aq})(ܥ2[zKAq*Jaaz?a)U vaK),ޯ\Ag' P.ԩSǨKaFKF2Hf),/ 1>Q"p:s#orE`X i)Uח_~y) @ŰN8\v1.Q g;Uq{w|sörR*x 8 x atiRVLIcXZTJ"݃`Z |QV'-CPfe 7)+Rʻ1Y&ݒ75k Wf,i 33Na#(W0ax1>vIwߚ(=B@k|p@k_fmΨtXV02yy)qla?xZʌyABe\NJtM7k7O(ǰ@ XT '^|(?af Ja{(KIԏӐ2Z¡,|G u.c%:g~A-E2݃N+bx.GDŽ|6ϱF*&(s9'^ax]̢z ?I뮫,i ܔPܑv+*ѯ&•m0AԮةUS? Hey#8$l L]ACھދ ]d"y1)"ޥՈ9Ңɛo9w57BؘsJ8 1J7=C5DCAkqPd瀑3] AtB.#R`R{]g ;StIM=eIYKݍ7̈́c=FpLLf?L <8hSJ~-ф}BvzlpgqXL[IAcCp(/;JW_- F=yJN /GV~e;iY%fP&Tc5p`)*K-u}&=PE֬fNe#uo%2"_ɯtPi?y\S"0lIYT>8z(o?.Km%3ILx65 z뭱 }k|X{Qn[`b<7Ͽa,f4T1+9_ePQy2:Ï~51f MMϫ26ӔG}t|ٶ YYa1ayJ'zx+WKx xUʯ7-S-8"S݌=FəZ΋y?|1ZS,@1 ;?TN=[1"j8ڤ-U5̒ s<ԗ{ɢ0(w!s&J3:S0{.++mfq.qGQ-c ʛ$ eR0}քF`-8-Q0sJIA`C^KWQ=@hyW+C^|[Ȭvh?1~2EYRyeSL[@g #SPq#:YyERe7ذ;mN)?OMpE"Pe\yUWη8F1KS)J6#F=>`fP><(-QIiE><"eƁ<*Q-uVE2j;BRJfGWIo ЀcV']{`\<,LGzzc쩗s }fw?0[iLEayWQQj8?*'L^tE1 ?xQ@-jPVi"|\z8m˴' R&:N:آCD":&7[|xȲE%u-m+SVʯV1kv#7X\,º6.j vcg3MdZb"qO=T]uPn`k1YFy(%avdbFق3Ϝ ـZʄYe3^U$Nd'E [6]9/ q(L5ç.bz? |'If0SaiX@Y ʕRQ]¯]pCErT+ 3P:]2YKJ/ʯ%=]5:a`!Rk[i|(zΓߞac=olGpGVZdڵKa(Ȕ[o4)>|467%~1[o}Žb4{1~=jeBYKSlۂ*)t*E'_Z1I˙WjZʟu1'RQYO2jm-ʯ^SwGp6WQb0?0ACR**y&t:?ƣIZ^ Mi!PTOlGpGh5hեr#8#8#&&0GpGpGc" Ǽ/^*GpGpGMh~b}u cGvr-ۤ2.pGpGpD]~DE-]zpwGp5q0El{{o]R~Gf8#F]LzPQQ쏏x87ޘ׿OK5eʪ"Wo-yWag}|[qyi#UtW-hg4VX\rx4q//?Sȑ#cqt ^`o#8@D]~]Sc99C I_wߝE;}@֔!+boԓ_=V bki-M|Z0ͦ'uKIڣO:kIy~>|mV_}uӞ7x'oV8y?qe8#@]4n3 =yd2eJG~ڴi]wm6xV]zꩧHšg{a^r>lVv5״O>9 \p 7~_ǔw=?)vF/²y>ggw7|㦛njH0s1]SIJQGE8?iM0Ae7OѣG?<5Vt^8|W=zGy,G#<2iK۠Ab'Gp vQ1g$_>jo7:!D%uFڮ2;Zfz'|{Α8{lv:r`tM7ٮM>( (M j6jԨL<^rhJG\ybZmcP"ס/i$̢6ZTJ:S kb-rd+ d,o|glĈ% Rg78Hs)t"㏶Ə!*Y#gwرU_(,Y>; %If u0'}PcG1󎅪]'D~Q 80#xOvW)P+JP DpG`"o$߾v8~{i{,a{-e>o ;#/>v._~9KL>3 dJ JV^sV$9P5ǚzƽbqlG!lo0{^1*t2M]AlAtYQP+[QnmqOЉЁ39 of:T8#,xŸnP4>m5̘iMSgؠcKt_̖Fl.>èd k7E|xEaӑ@(@,M)tGeN7la':4ec7vM/eA:Z[E9 ޫ/>F z5J'GpvهEA}hfm&4Ŭi$qm{16urCb(a[O,f{S }a=-Y7ϼpY3?qN /u(33UEv_~yь$`@@KYQmgN+aÆ byh7גKQk-)qGhm_ fwM)㿰!t:kMJX78#nG(PD`w FP`t0bl;3Ө\-e¬2%N:,FlixAUs[aç.Ǡ`~? fk FL$$5R&0h Q(7T ^* 'LYO}Һ~LDXh"J:%ԬPF%7["|(f*o5bQ]茠NlpŶjLzx'U"}V0qBa'=#@zLUʪ0Qzf9www c1J> L{M)/&w,2>;f摎#8vS-#XȆmݭw^0564ZggFî8rbvyKE0fꢋ.K0Z%2Yp|Ok)#g($aajr6||h)38-cdW}5 (JuAQ8Ӣ]<;hj0z)2񾦳AJ_ zK !G/t6jK'R^"䠠CGʺ,c7}gmTYuQT"|H}7h8J]s# :@ ;q0,܎핁5ƳCCfYȠcIǍ6^Kz?s3L`o|Qi "e*f(h\u' ?ۯ2#`eo9Y=8#`"> ۠FarT+/fJ6o 3dJ|,c:21vyő1*%NFlK-yl;7/q,Jtr#@'Eم8i˥oJ99#8 6WS،,Llm$RuGpGO 4ߵkxj,'rH~T7i8.%qގ>x Xkʐ)~{auɯLD^wu4ߖSyn-fe듍%raQT~{WXarGpG .&=2Agzs(t܍߶fx[]嬬z*Qj.@{a^rocV[me?hc.pGpvǤBg$_ÏST>oڒK.i]ew9^oeE߶-8=s4=c;찃M<9 teYƎ?rje馛l]wewc&Li/Bkj6jԨL< 4(Z{k<Оx c7tX?<Kˉyu_|2;EQM4,#)$uQy:,p m喳qdpJ1[ߊ&.처Z}D{A3O>$qڴiu[F+գ>gqF4:c_$?*#8#0h7|~)SϿg cO4ܞ{e 3Jc oֿCG!9C^lr)vQGE]1@ E;afsNlnzk;OSL(H(tN^xᅨ#G?QTQ(JcJGeСRNAk,x2p >cƌN;Mb{I'U9  P qM[<znW$ɟ"Lp |[o-(K{aǏ|Mmbꓽw$\fzˏO.]b=OQ-G%|P)駟mΝ~.qz.ⶠq#8O(׉{,a{-e>o ;#/>vf/+bz-GA^f/~a{WTǍ%X"ά暅A;sjYp'?dDiy7Gy$-u-%g4vVCN^`H.*%aNGϞ=k{j$yQy0`@lK䩎c5ȃ>x`3ZkRK-e T-I]Zf4?W_}1_K+,jAeǭ^zHꖖN?e2S/Knjs^jRV GpjB]~Fȋŏ۴0c5Ma_6Z-}1[w/=3?0*0"3D9aF ̞!=f0o)nƠy`2)Nb++&?#8vQQPZ FQ6{,z.a]C1ֳ[OdSl=7 $0FP2a1Gΰfj `G3<3Oa |&#iT#FYȋijk*s}>|ܡlA^<|R LW#FGվ+N(G(2R&0(_2yף"EZRY.Oc '[g6+2vJS~-iEmTr(‡ jH> +vm\Y8x/3*>zXmF8Ž>134j!FiQb K{,@}'Qw$u[$yo6lXO 8#!h72lߖze S{XcS؛KZ| L?咏qg\ )1۷o4!i$\;dZE+vF(L̘T0`W^9c`3S(Ju9c` ;`^ ag"CU侦AQ zK 05ot6jEE :Tk}TT;c-=+#.jQQߍ6(d\[Pt!.(ƌspy9`{RN/#T2 >PH&Uedv6KdepG!>2mJaĨϗˆW)(cǖHu)pFtϝϔn]7?S֧KW\=w?]jj^X0x y6FKa*&ye 8<ɋ$@BҠ ťPh)ЖzKK]WO[*-P, qw?onsI$=+眝M. GW%R:7_@?0FlmQ3^bLx&|x~϶j_^7= E3jyڑ?9ʳl|jtS/|kVolӟ:;N;ͭ ܭ,%ѐ+r|\g), :ѐQFf/WR8888opGS9vIKV B ߘ+ Dt`W= 2"ȏ˗/wh&`D+?@O~w4sfs( U8 `b+'0/d{Fk#fS6Y剣ҒHo.ҢmJC|leBZ@@@@Ͳ1F2F#q4[e^8]npfsK2g&`0m@88q N0f=;Q@#ǚyG1q4D'֡x)p'h~4dv/Y 1?Z ؗ9}wm =Ј}Miwle *p p p p p p p p p@h9 l%̆46tI(C" +B= {6Y4)Ťaa >.?\wZ&mQ~_S@g({NFO{IchʇB+$o>u'('N$7\rg9w= o888888;E}z6m8~*s;14Dq 4Hy䑬)Bf4G]wNl 7W\VS_闆aO̅OtDWwTǎw~7ܷo_W3~C!ol3fpq-Qh~h4"q=Zh)//pQQŞy;v޻kYg(B@r)ȝwޙ7nO:{lr mذAdNm-SLW_N$-[u7 'Z,W_}uWH6p p p p p ph-?|h9)9Wճ돣X4Gu;}\y.wߕOWㄹvTwPO8w©l~رPvƓ2kD6zhV'J_G8_ߙ5}_uFuu5E93-ؼhD?u< XG?PkN.B;bQ?I (&c&ߴ|Yt6yLH._/Oę}{_1 ޟ\đ Llx [nŭ +s/@)VAۯ_?f"@!8888884=G-pvKdRٶD'o9vL2i%ȣ-{&׿u⋝4BZrLg9昬 92%AN1ɇqV .ry^V7la7iںu` g/+gfeǞM1BqpR[u(}wV:tp2iӦ3sӧ +Dƍs+9Gq_W4? ^&hyi$`C>Ϸ[]->V.\ǁjG%WqE5RUQ#'!5EleNV^/zvWے%K *h11ٳe„ N`bịePVVdgP)ξSx 0ok6v^'aa.K^W믿6rq4Ó( |UG~KLDS-&h@Y6~ 3L>`&zVc~>*&L=zDB" sY~{}4VoedGH2̣HfZ*vSOM=ݲ+=$ Cu 1m,*10}AgLQ4gg^wZhz!'h힣#Fo Ⱥu2Jaڕ;-qƴyv=dCH40If#I>EqZg: /4DWx<C\~_F}t&dx}b_9YƙE0!@5jKн>:?h"7gb{o`d1_V䗏X>8lMM/|~|;;?kE{HxrYLzH8λAeҾo,-K[˴KUPX-[b)/J >ZG0Ǔ?ϖ #L|ƹDdLgpS hM_z%gAȇ&̊--K0Çw510\{ps}xPg\ǟlm9Ü f0a6 ۜ0 {2WrPz}IxQh|΅yeҋ}k_N;i 7)?DS}dyGV&?;"O܁ze}'f͒+V== 7tS&M/JoҽO?66ܟs9Oމ/| n)xה}!Xh66l<9][ҾU*SV*ɧnGC'njM\b'&^t*0%IVoo}>4B$ ^nr7 |G:.ť wlv6Vmoz 3 <[ [t_ 2xR(klCrI~MC6F4x_Em3M~DyK.~PO_h~@2}wYp!6[Nb lj|'[?ns< կ[ou |Q).JG88PFQ!"<]2RU]Jjڊdҧa3UWZgvm *7_M죉c3*N:.!0 T7tph>=*J$z}rWgSOC4 N@0a$h;| ċo Yl&|A/t3L\J:hęU̱?vVXae ``?O=bVs饗:'βAr7(;XzDz~ڭs1'3L q$]|8gxʳh}~a+30?WJC>䛯!}dzׯ7_DI&eHws^D 'H#2'͑ly;o(}b |5}tM.#`GA#ج̄!-I++%0(sioٹmR>ÁпLWG| @6AL%?qȘa:&>h1aou0 M/|lgG+"kh&Ej_ fXCY}\ m_6@hkhT9gNc‚P{׺3!p<p+ėTgmN*O<h/<48nެ>o~H$%߻r=,.[ 8@9@p ziHcރItvwOa +ht ;,ǏM:|=n5>[=6Ǖ8LX@7ͿEL X0E>| ;D}Kw5һW7w;y\YEE+eC]=IV ^,k7Uʈ=Nn6\CPCB}(ؗ9,v+k0E)VhmJkdby%BֲnֽƟ^{M8kOv3f̐zHXi Q\ ɛOIyp)rACmh97kSћo}|ؚ1@,wM̀+p pYq ʝ/Q7l%Ҷu+i۪Lڶl)-K7CK:MG.^Hi!dΜ92a5j;14Dqq q٠ ɛ\ixmpZoC/TF| ?䩧r'b0@@@@@@@lڼUZj³cG^ڵJOJ*JejS$-[/[NX~n(nSYc]wVUcscl̙3kӯ{7>[|i66P{V}6}BͿݛBo888?q/r=s_B+jg޲qvY);%}AZ{j9r@y٩Ҿ]k!߭|E?cǎ͜i[oS~zyᇝWNd[u͓_]> 3aYgriĈ2eYts G;&kG^ 0`Ny 3|E9嘲cy桃 ~7GL wynm!shz?x6|0GГxWf_7ڇ=Z.wᰙ>ڙL6-MЂ!<3p-Y 1,)#ri2e84Ֆ̉ GВMQhXYPp^.0[!"-2Rok6\VUg!]~Nj')W4}D[ 0@uV/X^}Oړs!>YO;5`cF7 nV$`w^ol3'3?u뮻 L ovuo<SNb?ϸ[Ŋ'Jݻ Ŋ&GC hO*Ї gVaeIdx%<|\3\hR.u/J6jS#%29k,ZRjkjնt|^]ڴj|)' , +a CP8<\'N3Gi |fKMJ@YF+r=96~Z륗^vмbRtgx]H!m1qGԙOˮ:~ӾzʿG^v&gyk3HQ( _W{}V$ X58œ~(VXo}[~; 3ba&%ccV!80b;έB8p p p@@\,ԡ꫹l=*Eۨk&7=ʳzW Gxt4 q023n1g`c*¿ipŃM|h 7MbŴ'0Ya\{p2a6@ Τ2'[[!!00aʇ^ L0M|rdo\#O=?+gf tdyx "b1@-;Z~6:#N~lO?teF> ?򑏸ogRYL [g?s+h x۵k&(ƍԇ h֕=qIO~DEÿl9YaTVWJ.3Ok);tpX|@9@jRP m&pH;X6lJE`a;{|l}@yUWrݶQc|hb7EQI2U&)x@˾&#6xxVM4eqx@`f;(θ{_|E'(" ؤϟ'~jyl!|@xBsXƊB?Bs ̻P@(o=+:e}`,1A?|0oaE |Fo2!ԣVZPx0=I >NVXe`@|yډ'l-|_S40x4}pO<8||2h icԿ<`iOR#Td!Q/|1:෕ӗG |> . I'3lɷl>hM:m t+A&8 qt>4!4@ĵ}Z^dow\}Cp|6 OGhT" |I2C(e5g&흷<͏6qKL>V<{#Uɛn LYl:l\eU`f^LX5D8P. p R@,&ـw8O[ͼ2 ɔG?`_fJQ>&ZZ6*7ͼ({~flQ+G?M+m5$Mp (}#EbP\7n,]ɚ e~N3/BE'~!4"\SśdvT<}6N e@?L1serwв0ۙ Cg$$ !=~&10<ͬ (hQ}1!v4MbBݰ~l,_'gµիW = ԙͼaOڿ9?| jY@'S+Wk@@{&Cr'QfPw`i"9pן%L4hnG_q` #- ex88880aCȁ E懪8fX66753:|:@I4Iٳ3p dn+a4N:iX4p p p8[I#ZK.q8jP0BP7;cݮ=%7ޒ^} _p.5gJ%>E{=WR1x[3hXϪ@a@@@qw?ޭ[7w>*p0l?/~r;D_; -k`[ }b҃o_~n?|x[Ś_2s=Z3Yo Q\4 ɛOIy?ĉ3M]oS{vN/^|7W|q$\S8Se9W^qJDOO֝;wnRvo瞓~ o;lHhfA#qR7̛7o`s;14Dq 4Hy䑬)Bf4G]wݥ.Ojz_=hNWXӧ\wu9[ä`̘1jNlPhl4NƼN4Vof~wW_NWA|G0Jt=L4'M-[o}[Vt.ŤtBc/ L,jZʞy;vlFQ\NS9;mN9?-\UzTٌ#,}7',/ ڃawqPH~|ZY5?qRծ^xAM#Hf?g/\'smy8^:,w<L6q| #8 s}L.ze2#6qhy 7ܐ)_8%cǎN' Mnwy0X8PV\I`N0#6Y9ҢmuUW|Cѣ >8>]EA?- z+S~@v}G$Ɠhg!Gfȑ П' )I8??-(v:h5=\? c6&Dx9I"Q6me]&7|#F8~_/؅r!Hc @@&.h'Q/6AV<>*M768c+/U ~[OeG@DOuڅ/7War`;Go0SSN&4$%lI]vNS5$> h ph@s^.LrGɤwhlylҌi}1rA~ svXKql5k8|XGacZzVbn"$,)/KOo6Y9v?p' ^Tz:W~0v"Ї͖@󋭮fRWF+= hBE6Y&fik @M?ioqb"h 6=nZZި p ػhA @2iflXSZl+Ӧ/U RKiߪ߹V.hn@fA͊T1`|3k3Y0MkhlSCget6nذ-.p%^lYh ٴaԪUk΢ҦuTO8(ؘp{K<[w6"P3~ qGcAC>4aӊ`j*9/7MΘ߰ ?+]XC!?Ima\|scKf|w+++LxF'>+͇>!'LaFOd ?yǍ'L^x0o&uh/6xz7pp0+nh62hҟĘaѰ' Q2ʾ8g \ יC[+kf 75luťZ qVWo~lpSVW\L@7 7+5?97Dy74?h`| 0M@~۷׷HUv)Q┬X@>L>p?*W53ZMp hx&9 SCM#@9f\Hw4pr1M} ڂ0J?#­F:('t$/Z^xD$B[vZx LY&A&@ npSچ^ kv7E}ښ_G\-.݆E9k+W ]bB\IO@@94{x&M;F< 22$!߽Wj,e ^B|6_VaflhN s4د7&`*hMgb g30$VO _d)LM~[<xҳuX:/(?$4&]`uYخϻHYC-ߞ7[\C5|배])籶5O|>nh?䋟|~o+(PPa"7R[Bmmˣ̰1㮾,nrZ&g#x&3ԄLHPA˧LSaX q2EBo\ m \{?21OPx L:8S6ظ @S5 +?N>xlIyNTIofq.,WK7_vov?l!v%. n/˷VBZr{VծI'opY>Fq+&(PΰC>UM(CO82/ L8WmeC% &YCR4{98Zrmy  ewxBgcY~O&gɏA2vPh_0&b<qbmX_Njg8>hrfݯ}kYxF~AGS) 4PG&ە 6]2h҈#[٤+|[}Q|V.o>|ertX:W [ZWnᢎq~_o8F3| o+B7#.qԏA v>h#q Y2Άiӂf&~3"sfpL٫j N*p̸Od~g3 mn"ܳG _Lu >q{ɉkg>V?hrs]y'ybU;\xd.=Yk+p p#)!% W0aӝď0K,nV–F=),14pNji\!J.v0e 3z,L>?_?yY,~5;jWIE]ZV[~pZ6 0\ZY|,__~(caK3֯o=Vowk]X=vOYpo4Zo[cH'EfWhۭ–׏4NsYh6>~VZq2NgrW8!8#7:d?G>穎xo-/68UpC2Zw!pX?/N| h2k-Ik }~ N3pXB ^؄CI RUn Ϙru9Oc{<f?/ h}׾l qꔙsN 򻄽Y4MѦo{)0D+R:(V(QlPӴ뵁l*FpfEף6>|H|(k8'lXL0'p``\>Y"pehO~+R.O&Ԟ$gTm4_CZDpl_CR yއe+SvV/[8WCek䱇c.ط>7S}<;ETi;92_z۹2u*^D5%ŗˬg=Nq~78x>Kh>߮[h\GrvYخ'׵I/pP77n51$AD,0K o.jKw67{`ܜuyCHFa37м2 &L=GQGGcvHxi[yx}Cq݃ЊG5VВ.o0A* +kq+ !/%og\}q|Jj__ǪU\?,LÀ0gq9p5u7on~HtȐxi^ը7p`.j_' ?Ppn$ 4˾j1ry i-:BQ'壼Bc01|>K^KKWɜ eٚRY\9꒣3h y-ۧ"̖|5ŭ4oW)25z*_W۞5$~l룩ceKKqڶT- ˖ΐCJnjMyeY,۪8Tl^!Y&>*'4A@PTtLIEN v﷟t€NE%yLRAŦ2sBigfL{w,zw=z{XL{1~3-oyaKɖdI*Gwf̙Z~zh?`Vg8-XݓPp֟+-7SO=՝2rH|nv'\#!$c D] iرcnpaE>. 1p~L\<+q01,{1Apfb-%fbj#{A{_`+N %m?{3<#n 4>fE`q$ur?I}aiI|be:}X\ƌ۟6٧ik W޽9'O+ԬD9 Auٜ Q q?uZXg3a{8>ؗue҉#ebW-6 uF+y?0d5V_r=oB=~VNێUn UW">лxO8Xﭜs22WW^Z.]}^Y+'I:A+*jY'\-#zLڸPXbW_X5 jzEgHI$C{^UkhU&L,C}f kO]ϊMҌ~p.?x|fy-!x`ayaq\)k`aKaeMLF~8DݪǏwJ\dRVK{x]ܕ#2PHWVni'4&V}g~o^E㥺F3y[UXrlQ">=IV ^,k7Uʈ=ߛ uI O[W(UǼ8H43Ge#h< Gy+K=VS(>e|-e92}\L.{S~xl@5z.H7ً+V '3cw]NqW{RRD9yi2]OymvKyifXiÇw欔u8͜HЧ5CCoR[hk]]5es˳+e踋#;9k9=]QH1䬱GH+S<㺧pJy{e2+dd N*UG,i{Ny>4'*X R,h&xSw ݲ wkY[62ɉGCu8y<4CtBv+BTu휑i<2;d!3+:>2ig/Hϲ*Y<yչ]+]r3}ȉ_%e#/.JFN<[TJ 9+et].`|o~~&&{GY>G7@ nѬz/)>1I4!p:bq\_'ڲe˜Џ'$Lˢ@?q,EytzjRTGy+t \mJg5|c D]zߺ7,=rԬR{-i!HM n[f`"j:@*-I_rzImj-'"z󡭡yfJ&W\x\~vVzSЧR6DGם #k!/XmS'xBHjm("EquuʼƑz #oHcϐFvs^W"`!,xXf!\1BڨM V~nkŎ>,eKk̀U{&BZPS[!E]ݦˤwfɚHג4wTNxE5k#=~fWpi *w\xQYcJey}ٿl<ʳ2wp&&/V#m=ye^r֙|tүM| eYAw厓.U]XE3ޔ3GުSO^"^"[`!R<ܹUNzV}kg-յq夻ɩd]ɋ.5]<(Ι.o!{k917۰eXұDǩ S$4K.՗}Rw.Zm϶E˓ ig_${a8dȅGI9dae[3K`{bϖ] p3IygW-0@Jy[^ýV?WVpͦF_ !}#n1꫅Iua6I .)l-;B7+`n |r 9;3!`C0?k[R 'gIcןLz޵-!.տ7M~.Yr>ym+[䷗Iuj5tX5Z,C޹]J>qҦ.1cOlm5nTKjW`g)=rTMe8ˆ/m0 UH =p;&zbp';ז~Tf=ό>U1?'.,*p[2Oݕ&Z?In˥[fRTo7֕J.>('[Z0R>tJ$ro_Z)]5Z޼q2{TKqdD_͎fc昨U33;dJgN匿*ծT @MRkJK{]=%p-.2Cr5t4]rTMvm2yWd1}ȓyXDEuRZN9\Y7\R 3ag_%ctŠF#VOy|j{9Ӥ\NL69Bz()M&w?ǵF+N{o{Dx\1Z1|̅r⒍ğʃGuEowQg~]];Ӊy/!~BXrye5[ͼW68vM?[Z)!TXr9Oɀv9G'ן}Ww ^ϳ^[y-ZW{^㞼>i1,Ǎ_O&ȔWf}+#p#f`LNKCgo%-)>J eAۢt'ђo4{%Zo\y8ġV^"/>#[%'3h''!OKC6m*Zҗ(#*Үj+_QU*ktBVźL5VoC2%Uj[7(Tu}aѕRTz- I/VZ>[jE|c+gVJZ<[׵RaPM*4ć5:XQh2J!ly>Ѷ3Fp(k}a"̘*^x\|=b6cGV.$]H+U6T9^>-tz__LKk]}TaZL]!ϦwI*kPV,:|9t_Բz:@(zSfϙ)mfHQqҳ,v nlgïH[u<2q&m9=I-\Hic7/ =9Yklv-Jz,| -ɤt5I@IDATkd˨j&B79/= 5'P\VڶT~TTqlٺCUT-_K'DZUn[!82zDwU7/~֑TBߪTk_`}6He5jWw}d=.w V/RP#l#XB5n4ɕ_6SP(@v`.);e-11T(TG/e3e ͲCH;װ$mK|eGm|W?}ڤ;))ǧ-s䱗HїG[ h4zkt9amx Fzi/S7t+>{t6PҙH/V!pWXFm<ؤuZ_*m뻭q5];G s>HʻMzR ,++,^4-fC i}L[ RWPtozңZfNurS{u»ژu9 =/Gzh_پUj۫i+u9*[ʤ٣_6b (VHcK U{e*𥶵grE*K.'$AZYp Y*5x[¡ҫVDTMTJU/ ukKNNg$u)qK&98\"˥jf/1R5{G/mWLu7-m E:}[Dt8=zhR?xR/vB/! ڕ鉡cK;餰NVKh&,eIP} "VmI0aIMuk~ⴼ]; 6c6L>fI#y o>c@0,/}knZ5m6Ȩ@ (ǟ0T^f[/ymB=7`LnM?yei[+)en[2%JZ][e#JUeP]);R.KӌV3o^Zֻ ֩ՕcU]wTmrֺT۰e+2gVl^lj=R'R7mY+3/rNRN"WS]M-5EWpM{LO\^T ?_VlS N\#[5myؿ'Z5嵺r2 o<:^VWy7eeZY4olU6:3-NtK#0?3' f[~[\'>ρg#^ݥ ejsVKʢū#q]&}!Vom*,PZ3aB8-}m1~F*WU:|w٪UZ5muCnvә"-SbLuWh^MaSt`TzRJkNffj]ptOW tS-Юwtvh[jG -I,t](IqIظ\Ԗ:]b٦v杵4ຑ._|pY|U͚6mU빯]z_CtRZF] J*,ı1zpU]lbU@*SHǧͰ4MV΢`mP&9p0 XֶQ"keykB ׮cy 2(N€Yɢw6IA㤛jUFˤu9J)s,6*'|B^y|?tj\g.-g>XxywG_9ᤁ2TZ82!_7ekǞ.C%xIVzz"k)E*רIu#s:JUNF`R/+7)81Y8iM49N.cBPW3\&BS}@&h\ CϸTVW2\5/?V:>Lu.s^y@\*׾%םɄd)ĨzչG':szҥp9gt3`0:c&d2+taܜr'gȓ/Ε+*'"q-JBX3M=M+ wS*!c.U?&yHtr2ߚ^a`mqcO#<)M4=:9nҬr;m_*!LxAy3wQ9~Dkfm.4@,*Q(מiҠ8ai\oeOn_'(}ܓ5,q]D888:Geu}Ei]Fvt=U&3g-EKV:V-Heۥ";SN[qQu`1âֻ$T.a'c{Q KvpԪpji /?wߥ'.; x-$T;V?>.\:~єCm]Ƹv ypSE~Z5X/:$GWS:HKf+͔NQ5V}VuV(3C_Ċ\%nibmfd0 *fW|\q=`#n&,wG_ i&:>l!3( ]NN$UT[:ęԴ1W^''wjpErh0q\ZE++W{~o8åB5Х:yA2L]Zʜpjsȧ(mFrEZ*r…hU jzF*c*[tӮFWd[r}ڣfMu:2uw.um\v0]I߯2֩[Ĺݠґ2K q§2et/-Sږ m(G|zXÞtZݗR :\gL=z}}ns=vӓo 't/Qk nft O=Bx ,p7Ɔq1 fj,P>pʁ&I9ZUUF-#uPi:9#nW'v'^f$a+iSZ`]?EKj1rTqH.PT-{tu33brnaفhPv>>XCIjr-6+٠ɐ*̆!iM*鷔\:Tpա8?*?ro]TqՆ`z Ӕ x~u߿lfg#G^~}U 5W,0*U"j΋K}6oWO pMӯB\ֽJv8KI^pרiJMqTJRv8u ;t᧼igK)}p4KG[&emV?a pc-R}PPDxIE'|<~XtrV8.I:y)IEX+㴍uuVVRҽśBQm~UWkYKsSʺdzTi(O j+GY9UYO޹=<'pڮWyv],?e)c|?VqRp}50|QţhG+׿z뭙{o&ۚm8@%L|cچvTS'YQzlQMjJnWՃ.,aE5~W]{6x_l~Z o1L݀;>4.Rz:uLKJcߕңtSݬn-2&_uD깪tVvT_j01Mtu0mYQZ \¸ 5uZzw'[[Rj¦WEPcrEMyRwYJmb5yYU$}FXT(ADA* bVp]״ kX(U׀a1kk#|.DA i$ȫ/rr8τߖ#mX# *_T>k,-oCY;VWRW=GZ_'[4$luV4i}|S E&~ZS?1su}^l{swkdU(NZ5m+-_ B5"8ߪxCЦY[g"$o_) ^?}7kg e) yqfm[Utz%~ؠI8pZtJr{O2m_ߢ7N[~%')Wk : :Qlt:A4嗠C7?DϩL,  LJҶ F3r!E띬qQ0#X)Е\$~ l*7[6>= {a7kjL 03F|¿:HY|XC|xucW&Wy^?䃔~9FlQXU~\8|E9S~Z8QZ4=f|[i#D>il5*e'MTuO5^c /~>iz+)_M5i'U'ϗ"fow9P7TF/|My(4l&Cȁb5gΜ‚?`\#-ĉCu a*?p@ra~JC7fEӅ/P !͈I=Y{l~;Sկwt$u0)ۭ7Dt˜Q;go/k~(x'^r&P^֢m@ 4lT6>F?!TiUP@H4QV0_|xp=tz.S/|.cF9~B,݆.;8c⧭O07٠kW]_ρ )i/l5USz ߾}ʺ r+zpT NN=Tr7(SLf͚?.mVnT^8B[\s[cF@^JVM*vLҥ̛}'Xն]~`37NR |Qp6u=X=PAe లT4}tjJ[:e!:3^&E6u.q2tǿ6ʠS,JZ\IlaeΝ^GA b?M5H^cWdnW$ӆyndJEu ?g?CsJQZ-yOӆӄeklYg|W[M6=j<ڦ\ˎiEq"hO` YQ͇Gd0M2ax%:#}yvllrEErWN{YdkHC{ ~p];-XVa0Yk` P"TI?MlGOҬH9@޽kNe&!P߬ҏ;OR;,.Wo!v|vțP?_~ &ʢEzZ!`@}SQ}ba̘1ұcG^X̛7Oڷo'/ߩS'2d LNbaw}_< |A],t.IT_!`آ{yU-Z$^zina~r98ufT4i: [00#n-B vllJ܂.!`T(dw~ڴiN?tӧO<̡84BAƂ_^r%q2kn)odF#t]w?/O<.pOvfΜB0BOZQP.?;gۙg鿕+WFK[\%ׅ4dܸqÈ#q&FjKG0 ]>h'+mdy7cꪫHyNJw̒|SOE&'4)X0 C0 D o ?|k֬q?ߑ͔E2j|0G /woT}08wqҲeKA_~2~xlNy;dt PI|L4}t߿vmBZxvӽ{wC9$2]rYg|x09rDytPRNA)\(^cddb뻖o儷GՅt"icGnݏkLGq2{2a%sf=XaƏ?Xk9ꨣ\:o` .|=##QI/Lp>"S<#](I$|,!`!`aC!(jع{5Z+ _/+Vג h:i'n?/b-駟=؃$rW*XhEpt!(yP ${.bs&Ltz:Htmiڴ(D?ky;C1_oGԛaTBocqXN-#C0 C0r@^~,X asp`zY[Nui*ȼҴqYTT7۶D[iԨQ 0J͚5]3fɤ 2G@\#>ޥQBMwh0 @^|Qtm%, בuO6LTI-fFٻj(/hp"IF=\ 7LUà Xpqؖ8D&܊ l&Q.]D^\B/>nA:` Lu=G:K^a˫iN׹A O-u:^{$nn: gϔ7k|eq4|7@1Ogq?-OU>Z暔x0);|/Ro]'BЉ~F`θJ3]󦔫z+?!`\~\Bpmn疲UzҸa#)(n ԖFue)Km,GqDz?{&CbC(&Mmr^#ߤ.D$iΜ9bK97(ܮ];77._u09xvr F@\pnB0mC'!SLӮhėĹ.]c=ʽɺaFӟ=CΫѭ[79bBdQxh\mo&7"p~1qP_qHIhUy(<ҕO:2/CEژ(U3t&լYa&әS{8od!`d@A`C3ۜicYe!.Ju\Lx7K֮[) f" ϒ۷k*h"ggRº&\SL3V@hQQ>/[d w(&b.t.h㐴 $~`K2Ud:;FW("3O.0<|-Y?RdBR> F4HjgtT#nt%M{=#~yeCyVΥS=sAyK>uU{P 6ھ! DE{Ao^~ BCF6[ZC ;s}Ǝ')}t~k1:zGy$1$~wnb- p4 I:o7Ukɚ%t:(I}\K PdWetWه dY}3AꂂoT'}6U}X.xWubHe0;3̱Xlst ÚΕ-ww)k(DB)a J:"z%#P!A_IkrA\֕!`nB* g:v0 Cf"s%F= z((]lvqn W& ipჍ"| $.% dlu#PQmg bŠEx ZHJ;7\E+C`C)eStj_c[vX/A݈2d쫯Vf3 gIL>gKBX)%e[\m C0>9U6 Cw"|\pSaN ±6[bҬB&3(PL'$&u+ yOZ,GLŪO"J}t8z[o!PȋR~#p +'U=L"Cz#@,XQ;t2dɫn3XtWO9 R._=.6D@'|f?#|=ꘈ7.?[k-;(ɻa(L'P:JMٜOZlxZZC0 @ p>0A c1i+l+U??~XYy_EWX7uky d lФQ姦+Sgk!`%ȋKEQ'T ~LVnH"8ncd<2yp3Q6e6SqXwr _a䥗^r[ji,>r-3fL*l֣ "{,jG7ԙ54SEYsۻ("ɁDٳ[ӦMs5@d>}ȣy[⋣7tVՁ|Jq2GdFӈ wuHOɁ,su&E P&\(^(: Yr87>Qe>.\'˸q4k#FLQOh)N&Lt.G}3m$otjQQДP/ Q1ؕvJ Tj˳~ɣ&LHC0 C0@~,(9L@dA~(#?)s dB;a_*ߨ4pqI˖-"b5ǻdgvy'vاcHZP dӧKJtP xvCH~[Xm$2]rYgq ;s9NqG1G4A!J9p]xK/uAH7`Rr[B:ܡ1#G5w&ҟtI2{2a%&?(L"#QGPxSVd/\ʖ 6,uRDE/#C0 C0* (~, 6z zזkd֜%Na W)ЫMCb̧~:+}:~p^9yP B鈿bM` O]HGB >ܱetCG(?(O儰98Wn-^'ݺ4 dbiڸ,*Z*͛ ߺe f͚0QILLJXxR5;כּ)$2[#q+7m۶-ͯk c~WrU/ޖ.#ѣGL$(JҁJg=g"whI QQn:[nQ&)O8!`!+ܣEE˼EkeWɡ˺2")^]FL)Q/\xqJAG?…7 &xg}6SRw-[N7nY "XHiʔ)n(K,q U~_WA$\P*-'P&`P;OgAÄJL \Ȅ>:YLH:">je1tpm9ӄű >BXIl0auV&Ѯ&E]$<󌛓aėWynٌOr(\9IV43RUd29 C-f0 )@)W,_6_oH М[֖gdYIᏻ),m.#8OVb_w&P27 ?Q ygGtD9s-2闈=q$g/&bY+[" iI ?I! FՅpo&曝o~Y6lY)8L|yIKL{,||&@zeS_0ҁ+xT$qPv+l+0"?%WCNJ/k>ma9ʕkd¸YvJfȂųmgA Q<Ϥ0k oMF%b+fK(ٌWE==GsBP;W)!&ȪU?˂@Aו]ZgT➄! ,Cُ^Y}ұ<ԨQ#uŪ l;3`bkvˁuY2,!`T<9UV!` +(,Ȅ?7(b& <tdT޸sL4u:|A9<ࢱ䔩13ZX6 J@J݊4(9W'I| ~*hdT'L)Neg;9Vl5!`!` onU6| a@AӖVC_^-!P'W!!`϶8yo\}e⮆ >p& V}C0 C0 C ?E'. =[zEx}z=?3!\ƥ놀!P}6듰& ҔX MZ'ٮSх* 84vIiӦ9VTYXbד!n$y^6XY*[|y*M2Qs;*3p3ΐ_#CWbS)/ʰCO?4MXI;=xFeSuW *?+Tg{ٲerW$+tIL0=yW믿b$dM\9tPի|ʶԖuIEF R%UIfȋOQhPY9? /U?.3f̈F&OgY?-V¼X7(y6e6c1_|/*7F_~饗dy/'ˮ:Fan׮_g}VZxf۞Qɱ+͛7~:[6YGIƭY)e~GrAɈ#mIBoѶmrg * =Vh_%KnW>+{'=z]0QFIlZTW`j%!=l믻}ǎϖKXsܸq{z(|/BmJU 7ߜ뮻 ?k?܆#$[dmuhʺG"'1㾽XoFNjoO> [ozꩲ;|ti0ak\}t"|uYn~ʕ>w s}n뗙?ʼy\ٗ^z0c=GXWXg}b a'jyӫ)ue^"Sg.Jݸ ;wva/~gϞr'qs9G%26@IDATIeիx÷I&r%rkɑGd> Nj']vE.\̙3[nOZQN9OHdg} gy;xAEK[VL iXQLQOMG0 ]>hWgvI7p^hW]u /V{7̪q.xfX9SK c0*z1RrE n~#Gq0dS+y:Q̞=}kժU2>sw=#Æ s*O>]z-nʔ)}qN@:SOɭt 1Pj@[Lǻ#mڴEL"~iӦLtl#Gʾu (<ÌQGŋG˥yϨ 7!/&ʬYxhF~6Sɨ2v)TQi@"(_WR:x9U/.ӱ.tQQ`A!gaÆnF_aI0< /@Z @ i*1dŚA4r(nRFN7kuǼ࣬\Q29C0* O'}g?cOkǠ[`_L1d"2 GZr粕q3$Qs˙??W󠡰&u7jp`zY[Nui*ȼҴqYTT7۶j~0+XqPj֬ʘ1c/)1,b;8wRx|wEo|0ƥzY_|\ax#3#tclB0cBf\yp)ͻ<3//FPqԩa :]F@&s7eޢjիee.|&I~+87*hSyB^:}K0xGѦG4uTǗ =w_1lX^Ņ#uc8 L\Quy*~~%퍕Q\R.xO}>醽sY$\g CbgenIIjQ9UAfFv1 eK7.|3H׿ՕKN &q&O焈l]0X# v~ \I 1*\" 1P)[Dt Lf׷o(yQQ5luaݕljbz2qͥ eҷ*SjE/RT1p:YЗ0᧮7x 7ܙ(L1AQ&Zs p5I2d txvin/8? Lu~D\`oa MLœ S&\̷7>Qpz z㖆0F!`Twpenl8カw[Rh?<Ӵ|ygw.#\G4sߐwwR%rꫯN3׎o2hР1Z7I aF(Rb^؟rE&,V .!lիW_//h$Ah΂H-ku߇ /Yqq`:Bם %K!\[B ?Q >$r n($21aM^(D#^ U0cgDY+[bx4 yY19I! ^f‹M7Bᛟ6lY,G&%:OISK7zW޲Oa++og5ޕ碶|orrA3y(JI]L\OI匒1F3t/F"ڟšdzXre0uܬ`J./`,i}٫kt.+k2~~XsMQ2[B2 [&CF^LE-Iiܡxඓ.t.hl_X?O`%IB`K/$e$IS^ZopClw(>D$FqT|c CϷ|F{^-ݫmdPYC1a!SmkTX0'#S2Z[ut@FrM@Id ! դy`KvzAו]ZgT➄!IY`1-~Lʢ7 I4 30 NW=ɶl;3`BۗE=ZYy+_wʾL|+e2!P_ [U+(,Ȅ{JKACRNwwI&Nǃ>(|p\^gPFɓ'W?MbC0 C0bȹOy $L{AI921Ȩz"ꉄIm!`5 >75VVC0 C0 Cpo7!`!`!P07U0 C0 Cȋ?QM1q$-IHTV32 C0 C0 #ɏ(lQ! ˩U(=z]0 C0 C0r@^\zPuq,,-_<&wɎw!_}Uvʙ{993Dl&mӥ!|꧟~\Q ,NX2;Sd(?D\dkܹra[o-۷_~9w={O>ٝ6mŠ~ӧDTСCW^zjwXۤIKR9dz#t2p b ^x e]d…)`֭[OZQN9OHdg} gy;V\Y/oY19.aEqƥ#FpǙ~Z*# pZ裏vu~,on+W]u 6o\0Rq2g(][hAt޸W׬Y#ĉϹ瞫Ilk!`@ț~rJ f"5PN#ʻ7*~-8wqҲeKA_~2~xlNy;dt PH|L4}t߿vmBZxvӽ{wy塇rId嬳r?)QJ߬YRQHx饗^s5m P^%xGՅ$CicGnݏkQΝ]z,ٴv]f_&Ld. Ա+?|7rI <輁) Η_~s=B{1dN'g\[P&89nE۶imoLb5C0 C0bȋO(joР4lP5J5F~_[V%sYs8-,_|!&LYf O^qҷo_<Nkי:dE Ad=Le/vJeZ5/~ܩZn,6^%x%IU?r:nm-v*ܱcGfmEzu xniһwoCmIe vd$g\[pq_әѶtynj+w!`!PVO},儰r98Wn-^'ݺ4 dbiڸ,*Z*͛m[~4jԨŠRRftWƌ&j*u.n /Vj0ΩSuqId5@G8|mۖ׵ą&b~WI(JQkmY<=z0{vdiI0̅EG)nip\{ ӕJډ9NLmA&?:#F!`!`XQQQ}/S.իII]ueذI4 NXŋvы:u,@t<ȟpW3VS:L<ָqcg2d;/+2e zSVQu ڸĨ;O&E`ۻʟk9NLm(\pA)R*0 C0 C yQQkժj٠~iX7d[I_~4ܢl&koK>FXH4sL@1c`ᦳV\a~a1*?#8Ȅ>9Lĵ't&Zy܃t<eN;%+..N LuG4mT}Q7s28L|y5-,Y:OtɬeG]\[pvɯD F!`!`)osK٪A=iܰ7kujKDٲT]pxJK.H8Ri3<|ċQX\;4U&u!b'LsD\r&Pqڵ&zCvɅ?(U {|Lr3/H94i$׮hė/Kmc)ro3ɜI$mAW_Bw2ed!`@y(,e$Q&ڢa]ʕkd¸YvJ^@,X#\{NJw} B0%I:jϲpP(us}x'!\K( ,Dɇ'/('<܄!^ꢣ'ٖmg&LhPEp%ȜNβˤ!`@~;rEcDCRNwЕE˒< SƬB{l%)o풛!!`T%LJa@^ T.ZkTQ,0-o풛;'!`T%Մ Ao'$!Q}8b5 as=kX*:o[krCXAڥS;0 @^~&?гE4,1Qz!`F5 657vG` M]ʋYjLe5Cl CQȠcǿ0[|y*MΊw!_}UVyʛ{993Dl&mӥ!|꧟~\Q ,NX2;3 ]'9Iͪw[|UyUɓsi.x~/w+7ps?L2?UiU J 6 E#X(9xeƌ1r{ޒ[?| Xydb7|3ٔMڌ\|K|@+2^˜1qO>̜93U;kp/dD1?ٳ{ªruʏ/ilҥ[c,mvɦ>el:IW^ysIz]mspwMz-3s.eiKcUP豎в@g@sޓ=zH׮]]0QFIT>'ttVO|(DW_}̚5ˍR'̤\k%cR44 @tt /P: 袋W_դyiC'|YR&e$(Β@5B /~^=|KdE.M&va}/~'O6M{K>}JIeƺ7t6iD.T8^{59#'pX뮻'xBvegL1 vv-Zvǧ&\(^rg'Ùgɩ\2^+&GՅ$#Q(tuE0FK/kQ6n;`R*;e#\` ǔܺhΝ;Xi+dL{n">GuK\A LigpFI{ ُ9qmop?r݊mӦ*`h Ur:uILT_|L0A2#% W~:+}?kYqСCQ(4Tؾ/)]k$a:*x2|p'/#bȑꌵ ?0UOvfc ˠOQIU?:X;L"s`yh(;vtVVUc3ݻ!:ɜIθ㾦3K'B>:<7[mU:|CIcwcm ٻߡ\W>l>h׮˫׸4v+42yᛏ:+,O<_2*IڎtyF>vX6Q+, CB />qsp`zY[Nui*ȼҴqYTT7۶X +JJXΔƌ([jbXڰRiwNSO"A@>IU fM۶mS׵ą&b~WE@)^z--K]GT9G&r3GI0Q2E<(V_kӥ8XmFqxr5m (MƍV`ذanRGxG㎩cI{w'zgxqk?Ex`e|Kuõ裏J,X*`I {E<}%CCTb煈 HiQ2erYx|]Jڿ8tu;]PW IS[S p hN: SX >xqap vh+m21Tz,`2d`=⧮@qy.L]o'9U dNJ锇l0cL{c5'g` .p)NT~ܢ0XO(>%%h^;3レĶ RO-G&! >裮?2s28L|y5- G)N8쨶k ?3J@~%:0jsz0{ؿ/avyӆ܏V|yoZ1JL ,<5\d b ׮D2%:ZZac&0 @~*osK٪A=iܰ7kujKDٲ&~ rU#(VO1k&bya r%,Lp^#߄Id3gōK97t<?]&%#O  oT]J3!!bZdÊ&M q^rpM{1eUm&3ə-żP!]:(FUᇫv O=:U WI-D"JGyC qyA3qɓ5(G1_q‚DhF⢈gmo!`UY>|hːV\#͒VJu@ȂųmgA Q@-Z3)aGJ"M.J&|e㍒嗏HyjmɖPL j.(qHZ+tP6:$ $iȜNp[a[`[33" A2upmiYĕk0{0%܉% #CHa>QnjWcipMzz3{yhldha<@llK>|0qo: p ?ٔci M@'?w't ;N='D%ak _*TuSn1Yp PJ.3*➄Q=X̱Cُ^Y}fM܄*%ŗ%L6e!:kQ+Dtr-X&EmJ"8J?K`OGU)*K]ypn8V7M^Cr0d5 ?LjOFpӁCI< WeZYA\!rcUBgwJ1QUQ."Vd;,t3⚵KBɮ]j C:!s3|2t?dEˠTtV^ȵ P%2BnD҉g*eQLXdB'ٵ|K-!`T'W'LVC0~VkIJ*.fnRn\Kn2.!P0*byAMpjۼV"vf`:H]!\Kv[jC_Zd4 r!h6`B7/*W!@f][ek"!%7RCJE' !>ʆ×H12 C JIͧ"okMխΆ!PEg# =[ "\D%*+V!`!`!) EPQQP|T;Bga{NV<2y%H6e6I>O?M]rSVNM_i!`@ yQ)S-°،dD2%g̘Q"[rw+ a^,ofO6e6c1_|Ev&rm߮hu+D+0 C065bbǥBǒ>(?D\dχv|_N%?qϞ=OvM&￿駟.})'93tPիW*\×\rI*GLyNN8AVXu]Od839rzuˊQu! +*7.v1b;΄hժU)L.G}3m$qoxorUWIQQP͛˽ޛ*:%M=JG ^wm7hРv0 C0 xcG駟d͚5;2HF/HJ/2;NZl)(7xOƏ͞=)hw <؝c"iQ@/O.n-\s9NqG1G.R(ʬYRQHx饗^s5m P^%xGՅ$C)tq6ܹKsI'N"}ʄ(P{XGu"+:v=@\~r=m(De˴ϊ!crWʾ+> 3ek!`!`"JEW ?νgHFkeeZ2wA-Y'-v]| 0a~ZcW\!}u?SjL2"Ek{迋/)\>l7#aeEuȑr |n>_WRRܺuk(^k꺿.~tQi)( 6t7#s`yh'| ;vtf9k/X!F({v8EFbXJiӦ2xVZޙһtN=T)..vF0 C0 k+}rBXo+X^n]u2oa4m@-Ͷ-QVlԨQ 0P%1c8סVZ-V\(ab5I:u$2ddR&8`ߴmVw[%.D0+"tP`۲EyD3zha"*К6j͇%#%+* w@9$-  O8CϏ0 C0 eŷ.*^-Z+ֈ]J^֭/_I6lwH:`'ŋSJ=N: {XKǃ Q}LIݵle:uWcܸqc7yȐ!w<.}uF@LȒ%KRJqy]NEyG;aҹd XPC<[:f!`!Pȋ?.`Ƃޠ~iX7d[I_~4ܢl&koKҊ>8J!+2c)(w{.<%n='-nTFJ"ȋIL.]_|܃t<eyvKHEᓩ.XQq q./I`9QJ&;t"Cናd놀!`!`Tg ~\Bpcn疲UzҸa#)(n {ԖFue)qxIK.H8Ri3<ċV\;4"y|D&&bC(7qr dn׮0,D"NnGQ02.DaB0mCĞ-Z3/_xd4ikW4HaKڗ^zå6}ǜPo[C0 C0jeuC *$QtQ°o`YvJ^$,XQ+zcHز F<1BÈ 1iPF!`TEч1{7= ʰSd2U ;ù>Gcǎuϔ>WE zz#<"ɵ焵GI\AB5i^GV -/ ^_W:wiQه{µpbz>8xEه/\k0 NW=ɶl;3`BGQ{(*3 C0 C"s%]D=(_tP*)Qy7:>|qYrz52ʋv!/=/d![r#*釃h9d.ʫt[kctiT6TMNC!Q?Aճ&&UR_ÄTcvSmUwқ)N[[M |,!dT4 ( СR5!Pȋ? db⮆ >p@*c$E@?j-P JX=3)KKg@ w*}g;-  1 E'. =[zH_* Ǽ ! 3s?ϳ+WO?TgM!`Tqx';JWB~gxǂϢB,AluWqn\V(ba_~Y^{E`%޲ʷqMIWnOł mEIʸόel뭷v|a-3Eg-~G!$.^e#LnuXN>s;I(ux9RG üyoĉnA$2Ӱ_Vqf1aÆ6`iH>{・}2sL->~pSLB!|0u^_1cƸuDN:$wS> q/\zn ;~$-XmuHבiwJ/_Vtr׵`;xFl1bQ?L!Ts׮]ݻp+T,<>|Y-<ڙH|tb% C (Ǚ~U ]yO+c.R&e[3, a^1VlMڴ&/*UnB3ïG2`9 WWE{dƌ{ 'X{uY{iEz~a~?r-N?rW?O˖-s< UCӑaUb\ +.q㎡G?es 3<Ω #رz4ӉEP=P_-Z:g(Ma8G^0n\=(pv HOgϞry;^{ν(S?>(;h6¿;H~oW賦ϡ*z.[]QWYU^[#+0/UPW ?jsJRרQRX^? Bay@c;Ni8Ǐg.bw#GʓO>){NZyrm9E-%O){駝e\رqnXrGQXtt+Z%M}F= FUWf?J3#wX}gH<۟kk鼴nZE9,>}t7NEcE@}U8+-q&9ò<|ʂ#**% N^c[C86j9, %?D\;wvaέ%w?c:iӦ C۸#~ҧOy4ox;tPիSZo,{%Ʉ 7\1b.y'pV x_kF:SO>!920zitbT]+hP&F(L(&O=i3|stk'\j6;@b10~xw d%{nH_F$P7zhǗ2<}*l3-`އ^~RmٮhW~[-W-s=fʾ{!Pțϋޚ5kecg3ena_(c'̑KF!;)(7xՏٳr4x`}ex?LV;xcdhߖz& ֳ:u4>sS9as PqP 5iŚO_Ս i4*QZGZڨsB\P92aGEaB9A娣r|!`F\~]d Bޤi}VZɻN}GCFjxV>3Kȷ~9B?2_uw1 :wyueU>c-С}3BA|:<mOs+}ۤr ) F %F5T~Vc{E;! [q>Ry@#Sr~@2Xh,~X]K.(%EՑ4>}2aࠤ`-Ǻ[{204>X{!:tprȃ8hРRXC#8ĢdB>}pGXGQŅoK:?ЍR8F?KK7b:p )^& /~T9mڴq >A($D˦mu%a\{aWsh-E,Xo$iQzp S/OGN lO畎"S;;gP~Ku\cԃv&l_TzF( :(좼1bUFL(Hqp?_a~Deq$x5@IDAT]8AF5sC1sz{:R_Xx@a98Wn-^'ݺ4 dbiڸ,*Z*͛m[XPp 㢡-P80&%&=b?|JI$2>Q` P~Ӷmq Vk&¯[)^z--K]GT9$`1RZFm`Pt0ҧ$GCE_E&\wzP,^XSOc_z饔Wp/ 8eޢjիee.&I~+8VF#UpI,vY&/ 3.XPle:ukKRC Ic :7m\ԝ']~+~%%6퍕w%-/=ʳE0IGLfG>"0jEc=Uv\?6L|y]Z|ܠ<㊓2+c t~L8?#GDGa<(+NuxFƏ]vmZ>zx˚;^Mg4<;t& ]c\Ծs-~'_em9-șo4_8gU2*Z"XQ!t^l5j̜>NVDj,2JL Gڲ!| ;3E);x9kt(XWEw "`8J#ȑ#ml,L%M6B?m." rJPQ2/c&;qAyFI $p rM7Y8y\hG}aKZ\=PES..CGM}Ld& L}9}L9ǖ9&7< s9׿"~,Q+#i{.R;%{y3Ҧ'/-w? 3Lm64ʌ{ǖg8=5oeHT7jf?E5$I,|\KyfyRki#2~pijcN&_QE4sX&)J&Q\)puAqC煜$VHB6AʅLsDsϽ<؇6EϽ&]T^=*mgscǥwU3"P(IhB^ / 8e2/1<|/W4DC] WD?;P^>_])ԗusI ?O(.Ÿ !Cߝs[g(U+T4>ŀw~+X)UI>(CxwW)][ʇŽ2i~lßJ"G}~⺿]>*@A@|U-TE">aşNw[U}"~)n}\\}uu飮9E@XErmTZRPWPi Nw3 ~.~ˏ^KE*! Uj E@>IkY)gw}~C9O8J..WϢb((,E}|[1Ꭸ>;sAL%UV N]"hPqi eKE@P (D@gR?csW&P."("(@UA`yJT7sL+V%_sSĬsq'ʨF\K4eǥ!|_\Yf ;alD5j]-φʺ 4A СC^+SWyߎŋH[Ft\`;iSlOEI.+#M(U(YYƞ7H]Q??Rg{GKB\| .Yeʫ06aYYMzwno')s|ꩧV[me:H^\?_W .n9W~o=|(ChHwݝOΥOe1Gya|ꚶ4=\w}[nwGfOc>[nQ" ѓ"P(KsA 5W  ?W*tE:uTaa^ V[|AA /]v*s̱nN;EV⪫֭[kC=T>`ʐ+(znDk/"O>50j+ypOfMgVڎQGyDn%\"leMW&(@B(~^=|gG#ʐam$p%g}dWM7Tfcx=#8žghe=XѣG<̡wyGsOY`o,]{&ӫ*CɸZ_^x xe„  6*o,ZQQPz7-k\ve2i${OlRL1)m믿^v[iѢgf8裭7:*`C;Nt6mC? {2NW=:(=BrW믿n??í5/F 7kV ?;vbgsFz)W\q0zųr)we\'puYVvr7;n0!~=OQۋ?L.-X`ܓ~a"&\kJXUW~>mvmrnenJ{UF!͚50 ~(2mr"TcGC //&L7FʘqӤ˕F9$?^hBA;31@Q$-/l'Nyq{zkJ>(({(ȅRA%}Ik/Ҁ12^p>|J׫LvEu! P1;1?F[oMχb8Jĥa{>.￿+:v=@\|r mQi7pCqoF9 fرV_ǿmۦG u]N?H'*3({ !#"=Sr-i@fmd-.{oy饗l?sbPy;2Z%em @P,wu|2yd[_O?*uuޑN]yxDžev Q(7 ޟ|[WרtÄ+W.*ޱtH]<tN9cEC1`,saf6]&(@C( ?(; ?ǒiԸ4jLQ[.%/Ζ#{=, /H>jXq|' ﯿo6[:1nL:ƥ ;V]ad/s2z#SZg+.oں2!cPk쨦?t.nE!P ?/)}2q yLk܅K̗wj/]vn/[m\jhh[P8P`tkSD9%/_a!>bJ҄h!p8W ;狕+ X9W ?]},XLj̀ewI#..X ^0IVl{xPX|d|餦!'klϢwU&,\,I+'Q{fXU1g1;Cw^˻8G(ǾU#dp|G]mR#Iܸa|sK߽+p)ϻ4n";K )" H"Oڄ ˗TW_&:08+:ơ'fwFLq~wm6]Qj@Q~^nfJIC?gԫ@~<(*~ԔҳG٨&QfDMp\; n^jB8L/ )1QE "5ud#>|p-ryq<y73M (|(~f#>XEafėץyԩ_4.XUKJ #R`r^/ |!|g##1'I(t:ӧM:tϬgUōL%HΊcB'I3y3\m F &Ft'M*ɷo?b.c,لd.aPڳ)a>nnyǥ3uGfy>}Cjvie(ܟ(L'՗ wxLEz<?޽|k2@qOpҦE)@5D('c 60/(;5*9rTߗ}%' rt{ŋK#0nQNm?90tFA2s̎quХKTKMc^܁yg'0CY^q8}Y{-L}#0<0f~@`^6u5K3~9FIE3V|0#ӹqX`>F vYBQ|F 8OJFL2l6=mm y%t}>w6}#zE Le#48M<(E 4a330fό8#@BSey,Xo޼2RtZj& dҺǞL哋2aa8i k 2ӺUM(r5aT,jF\Ġ\c`]>h;vU !CqubD9iy3i!q]+Ɩhi>̹bO0Yz ]\awOgwܳl:"+Q ~`śg<0p՝9.%XӋEǦS%X+_E@PVuHܾ7}ݖo$Kgz9%(PP v˺fXфF7\auǶ>9&7)X>C٧$P11BPZ3,&LC(_qu6 -w\0(WY.m+6ItbR㰎gk-+xSl>f&%E@P@~>Ɵ?!@#t%t<:+| (UPTru("P(Ob"V0t+|-Wn2\("(A(Qz#rUE@PE@P\P?W4"("("Hr錻 j,-VPE@PE@kEg,;w]=>c;9u("("(1Ьb~Bs9-J=r:!8&JVPE@PE@P` m ka8x㉊Y}yzaϬI]⟽;_-~A^ fE1q'fUT a^^1KS\ |_IYYf ;alVfl[XTmijE@PE@~vmL#3yUcH0W,H?WZ&os=J,V¼XJ%rIXh/];%r]yUy&~],]&z'͛7Zj%W^ye+/RawQX koٿ\nSO:t^zK㟀"("87zX|@ڵ˜+^{Ot":u`a^ V]Xwޱ޽{ە}4U:C䣏>=Sh{ƒ:H|Ɉr>Gmڴ|sQG]s"("P "Rp2~Y93lp#9*_X2~Ǿ85~ܩL zIKUQt(`f-l4iӡkFg:4U]wՎ@]~J%HLڴ0Q7p@' >13Ji:VViFw6h#yg˔}u]g珄2́G;}_@4|x Lg˾_FK3l׳<_gRRE@(EGyG9!,'dzFĜt.Z*t\G-!c',u5Iec=Z4iRFae+.ppdOɉi{n<(aBard,v7Ln 2Q:fҗ׵̅0P:Qzkm>uq<1na"7DQLcͷ(:J>i/&:2w=mZ\Pxqe1[Cx:t„j\x^B(#Ȍ2.=S1h%݌\tExDM~e:{Sl<]ϧB1#3裏hE@PNS Ƞ<98iWcf6{\N]tk(>OgyƦu(dz DGb,IΰpQO߾Ik5F.RM7dYo5;ש$3e͜7+" P4BHƍYI.5֖& Ӡ~׉ (7,Iݺu+֝C kn:X1b0a9弋|iȑcdž l!dn߾ -_u"ޮ];;1#*;፪Ygec6D8Q[ L(5?dė( å6}ǭP+?-f2{+DOM8/<&u꟦Id^ڌ2F8FpzWB3X((XM[,f⺵37kx9&&l򁄰wqJߕ¿Fo65I&d1dEORWMDlFvsx m!__0>~`vrQGYw!ڄ9r-%,'aeL$,/O܎pw7$ÿP\ҢϷcA6lEQYq/x+oF^Ov1ӹpztUmm9u p0aw yr-D~}HE]ϹvD&/σ}~aD,{w }\p̨!#tj%Bw;?ȽSE`B`\J3|ϰ?Jk>dnYW7㦛5̇lݱQk%Jmˌk-Ǹ`1ٳg%w$]ÖKCKĹ1W7zk9NYJ/Lp튢J_s>fETTδ_IWtD \ Сҍr;=w!/%.5؎1ޥOT%_uF8y5,;:r䌒<ǏY ½ǭÁ<Ͱ!B @A: 3w-/IfF ,1M "(wAK ܏# $/^۶7m!1`b2nY(GksI<(X$K'ܲgD ZF'7 LөCDzN]\eP) IȉZFQ BϨp/Õ!B gn "8ZP%KXxGd ª;u(5 lU "P"c @!CcT-?BO=V|FF|׳l.·4(1]O>8J7 W/EoHG`E^ `{I.]B:*nex JuFDLǙ  wx#0B5}tyg2 *S쥗^O6ͣ("()(KEK ?1U h$:j(bId9{VKtʓGaO:Tvi'ac=.qywyGsO9×U2;Ll2ꫲ~Y!b!31Q֞x x3fgذavJaJqk#r:f|M7/2xuauJ믗m.t'[77(_ltE窫*s̪9={vf'w. } =+vƍeq$AD~$|uE@PE@0yf`]#駟1x>\ts]Q"e0~2{`\dFiꚁQ'sfIO ?0:"1G1Jvm";sSOeEqA٨U5QzVWJ.sfI cdIRRDjBcrEi5VGa_"xrO?݆,M'&c45F&܊"Q:vh'b&^$l}іEЇQ$l\olf =DN]|Ȇ/K{w '\qҴ+P[u.Efއl,cӸe&_b.rq[sҼCIeQekkrS>"j#P4Xp?I&RcQc]jb׭-MɧAKs9GpS#B'~w n:XqP.S.+2wo%Niȑu {97t<}Bԝ|7Di׮@4d(|Yge6Diݺu"uG&Ӯhc _^ҚIJ0m[\!W~[:x! a- Gφ +u 3G,*B*垟\xQo:Ǽ =\YWvyԋaD7Pgpln4*SE0VhiGX_uŏ"p?p 0OFa0Lq|p|Dn.]GLZJcc>2B+(a8=q<~YsE@(&WecE)X(¢(ښXyYCY~Ey=X!{q_#4c QbUoxT߿ 2ZI<}"O8JqAZU !LCJ`n2QYї-*/!og}VX%EγqK tpb"0#֘E@(&ˉDpü* o9[Q֝bVZy+@B!VsL uK&’:3^,.wC.<]זUw=\ᛆ\޴e皎Sqi"TY4 ^|lp 隌c&uw^"g#⽣c 'FÊf.<|Q|5F AVᛆ\BŃZڨsY x9E@P @/KÂ%"fȓ+Ltf+߷2\+CC(:6[I J qAUnLZuŋѣ3QX+ZV'&_ي3_Y4"(@a(ڤ]y~>H)+)V,0*KW"2y[oX\%mbY.vKVYxrSO>:a1WJ_HeIP nE@PVE;7zX|~܊rKf5.]4*Ja^ 7Z25@1+Sb&$R%E@PE@(E1cw}&1SeȰY]zF%쳏@ahb"|e<.ox3{5xcA/ Q6^}UCC9$~yy'q, ?.>L>'puuG(I |">wT4n huVTf#dcM( ?鷑 $Lt.p6{mloZ& w}bSڴʌ-#HNRIF5Jj$a6mڄ/"("~(&OobK?S?ϼ^nx.᷃}? ] fRZ`^Z^F KP`L(́ ?;0998r T#<ɟF wI5Fi jxAJY=0m۶̙z衁 f5#!3QiӦ}d}y&BF8MG70qW&lqu!Q>,kY&833#0tp2q=-&uE$m&NyBW^y%OfUР_~p{J6=Iuxe+7HS6Qs-K. LD] LtH޻`oF61IsYq8"("7o_Q\z`w~{YQR0c]PKF_$.k/'.>, ?h 1ʳFeO?]Z?3K 3>Xqau#t]n6;qOG |!d"Advav5SN9Ŏn,>^ (v)za‘_WrϏt: W帺asUQtQ6b-"( &ht(tr2-cY >#*#P_~]3gδ#1n4iN(lh.nZw8Jz^X4}'_^_~9<*SE@P!PX..T0KRc2)]Tv鸎,[ZCNX$4k,'M-*S"xWXۂ-Z]ꫯ`VyLK{uA1+E:r1 /]FwAIɯ>jL򗮏WS+abS]ڨmL\>Vhݦi͛gp;K6MQ?d ?\aRIFҵpGɞ+rE1J"("Pf؉f" ^{o*KՐ~$Ԑ~ L-sʔ)% ?8eX+&/'+#ݫWZ2 2$*(eroa}dz %6l#,Nz)XEŸXXLfn@6rN.6KIVl{cw=K{Eɑ빊ntFI&=Iײø+2â"J"("P2iE۹`WI\4\, ̒zȏǘ ~Ԕҳjc"R D 9˥ #~u,dBOL Rj/E 2K$&g;ډ;I>(DBb w( `zs'&ۊ/a]z$0Mҟ _^;ﴝ:OLN^dzenNrkwm<Kdp::늀"("@~KnXsoF6n$JHEv_4iH$g\?^xsΑnݺg~w}CbC(}) *]r id9r] :,(6:ܾ}{!:J>Dkc휆lad%=.,uWڶ!by%, < 3۶?fė/Km[\!W~4H|Vnҳt϶ͅ9Ѫ))"(@a,yeI((aXo<3RtZ8I2~pijcN& M2/<}Ʉ_h }&2IiYeCf䡢.80L4X^ĊN\]PRi7! _0'\!q|]+62+n%[IFҵ8+qϲF\Wy1 d#:LWRE@P F>裒^{N J i?CMV^e]?߸[n>5P6Q'?{µp1z1l2BkT0 |ōZN\0(=7sYvC֨rki^it"("[)slDtP*ɤqA ]%-?ІRR2UR"l$]K^*£ o%޿u,pgpad #,f͏2QҖx=q# [FEƏoGh$}Z4=-qTR@EEϊ 2UvZ" g#Z*&Q!x-KeG5Cn&nI;*mOZYc#yxɣx݋|rͥ,Foƪ&V"'PC=XTt̫ath|Aы"B(K ("P` &O>i|ypŠJ@glΤI߬)%Ҭ~ml}y%"PP*ʤ($nîͼ("ztLYm\/V_}u9ꨣʭ7l }o5И|W>#~w馛UW]eg<*9l&SO=e1I}uaTѥKk'=ԛp.:uQذjeK^ج:"`*QRO\Uu\\9Xi7$ifoֶN;d;=:m(^fڵ^u9s.M:ܤ'?veyU30"P(JX0*f͕+n~Vy-_cE@PVyPqA%q~L,VŅ^hCtr-VyDq'ZVaEG EɄ-X}P˺I>*^_㎳J".<p@.X.amU2xp D٩+Vj"AD n/xrK{ΖRT"N !"0!W\aז!k_ucT38C^(V?GG#Ou(+ESǍg?dlsEFeE?XwE@XCJ&X!۶m[;}Uޓkr dPtM:bg$"43,k` : _$Y׃0de0K/.$ܓ|Y(N,>[9,IAs#"g7_ߎOhUqNIPVkeR_~m֒~%j֖zuj~#&O?)36ZH?ii2"RB\8 _QU܄P4Är%=mʞD5,Qp%]9Vp5'{X\9ի?<(QW',;e#d cL}OU!ߦʐAP"Rr-\&M df2fs"e\*fԔfl S)`ɹ0`B-WRa駟7ްֻF\%m`C)qTYt[NKOwUK:sϱ$jtv(\3f'#c*̊D<[d>#̨-rMaS.4vXzI'$\p ߯{.y1ځ坑(V[meۍԑE2 sܯ2;99mRRX}kr0cjd,QtԬ5PHm]Q Gu+V'|`+ "_}~vȔ( {iO.u%m\yi3lprVl*7l9 8'3.. q" 1QzPdAT\Gs`=C?|kǥ<¾Xc?.6Le @ID^}Ä(J*:,+K=8’ݭ[7$[g(Å.:ܾ_\k&gyuAq:C9>Eecu`sWGܳ>kFwyv4nO~0Jg裏ma%E@Xy([>RF)u֗1f"qLԐ%5~[KpMFAb1hs"2y-X*k/fX\%m\Zr"[TVXӂvm+pSA>ܛ(X<L 35}8\EEV ->njO:&RNҼᠣ"[J`\a7nNN>b9Er;uTk|<8NI /w5T5GG>Z]TE`eBȂ/#d؈pRiѲ̘9O-X,kQC>hwIMti:q3BЮ\`i|H.]'Ua뭷L:eڴio /o,QXk0)*XH~C oqah쳏eM&W&laiC fb'ʅODJՇhL"X Sn\$/#sgybzXIIPE"PP([Cn&L)Hzu\㏱nudy2(.J& ˡb',OIJ5lg=(AD@Y4DKE}gvXS&Qܱ3&a5Cy}P݈ýXU _$^.(ǵz֮];+9sO,#M9QxcT>Dpa=K`:y-||i EQge("Tc9qH.6˯}, 64n;KVPW~m=A-]&5k6IcIuL$Ʋ.#KWX sޑ?\$kS9LX942Ql^PQΙT/s~]]-n)iR宅*6J;ԞWRBmҴ0G)9qx)' 4u1nN2^~DXè6wuFw!sOO\="("T F@Ss+JДoWIbE@PVN 2i7j JPE@PE@X7oՃBk("("|ԎS^5RE@PE@PVMjGMKKN>#M>M"vrtUm]*/E@PE@PrE / ?>YYQ\aB7o^&Mx+E@PE@PVR`2+G/uўZ E@PE@(yMu1 'rR*NB8APE@PV. FPE@PE@ʟ'NTp_JդZE@PE@(Zk nn><4"PHV[m5TR;K/jpҤI^%_PE`#P;E@j۶L2Er挞f($.,'>e>s!Q^u]WƌDÆ eM6nAu9_̝Gm_Gɓ{7߼p)oE@P^lYd4jH+)U| .C 6m7|#:Ȇ"nѢE_~EѣG E@PV<5Q=VguV n6MDדO>Y[o=aΝ;loȑ˚k)m~6͛ois{1po.C㏷6,.ߓO>)njʎVL0As|ꩧZAiy>Ӳ[.rYdgdxtIn|'rFm$͛7]v%ӱ"(@`1WƊ"A׬HX!½/]T{ok?sw!2#w}?PfΜi]\x:K8vy .  3;SVYZlɇkǏZ G}T6l3> [o1yލxrt+?K⺣("Pj6("(XqIAyiӦ;Xe}ҽ{w[}?`{撠׭[ZQv'_!"H}ݲ6H:uK@Hp mᅲ+B.[.>*dknGC#J7(znM褼k3B]f̘Q]o[Pj@myE@Ry` v `Ň*]v߸q2>WQ( t2CAq؋c( 4nNٳqD.h׷$K6xcP=s]ˢE@(. ,]PA7.6[nUqC)۸_ƸߠLCFXQqY}#ӥ9M(n%j7>·sq<)"F  Ŋy >ME@PUPΊ"T;O'gϞSOɮjxYgsɹ . ,}=P뻏<w;t _~eXڱlwv,-({!I0)7W*N:N<`cǎAY|Ǖ~7Ґ^PE 7R+DPRV :T=zQly93EwryI~1ZnmXz O>֏ks ʺG\\dəP(8>1I(=D*XNk?E@P"Pcv-,Y!﮻sUqЊU({wT%Gvf| s<2@j2rLPJMPFjɦ.m-0k_c7˪!,]LJk,KɢZ'~YQr0.DZ0B"1T,m u_,XiWIPE@XGYNO=_F-*l]')_pdyQ=\2UvزtjFuR`4[pL:OzZߡU8~8cը՚M_&e|PY%ơG~6T  cG 0yTaW |ŒE'V⨣[nM>Lo_Z.#&Γ$<~\r{r3m@E@PE@X%IᏲrn&d6ɋ̤E(ݳ5!mtQ|{^*,2fs6uNZfڍj-s//S^6+]KS>~69{/3JHe {2o:A#k\pf"\NMicoz[/3r,i0 #SʁOBV%b PXԇ85jG`:}b|sWnE@PE@5-L5kFw.Z7ߦ,u/8Y7di,uSy2y|c5fmkՐ6FruƢ/4]]_ڤ 3Cvj#?9ZʡlI3U6ݬ:̫;Zf \#ײzvMϒ}]zC9}mrk˴_ʬ%,fιiIt]Zٯr0oeN6bww2/5V/#͚5+Scz3Fn]*O_Cj0E@PE@PVB ٤QR UP M̤ě?q)Yl~\d΂R?u8a[e덚˸i eef-N&2ZS8{ W\~}?eRH}BˌEΖ:R׬YSƏa&7ěcyJ,1Lre'Hdi`&lBKzu䜳ΰSX͚1]N;L[㎳dF?勇NVs3O#"("(E`DSP?~x !6em֓ƪsa7nPG6nX.:tĭd[dV䧩R⮓TxuR~e lbayg؟H%ҸIS)1QzJn2{ K튧ͳ}'_?wt.APyE@PE@Tҋ>dm&-)cxgw ;Zei-q'/-]&7LF˕a9z:#ujk MG!dv4FM1+\6?,km(% ;5/wI=ls!;~.#Myg{w${*Gcou/u.ckWK׭(7 /[}2uܹ U̚)K)g(O~E8or>Bu2"("(8 j?VmXy36Z"k Kvgr\Y|cF‹/8+?QQ{lӮU7_wsiXU#&Ε{ SVZXt٢3 R(~.mzujm֒%d%Ҽy2sw"gKOf4b鯵z#yR`x2icRk_}rg~pA ֒[NFZHxLj*5c5o @ԙ wdm;Nn*}3a9\ctה)Ye-+@eY$˱fᤢӵ)wXMtߦoO>Yׯҭ"("(*9)(Qʐ'Nɫ?N&m9&De)snx3d͍Xkwn&vJ] ~pfQK%夨K|mjP5T_`x rKw%;-o.\OZ5Z5X&XӔ7,X̞.K e6KFG~!L'25kw-5]i#S"Cx&m FSժzUӎ2i; VV_L5& %"mD)/NuՅ{sc}nX+TˎYpVŚ?/Z!## o^S7cFt!- ̙sjG]T   PjBH8" 9P.ej^qg)/BYiZԳL2+ FRqzVG@|0:nzl瞿e%EKxo*U210p!"MqH  QweeŅt/A|B a=5FB^?RWչ)4o޼Bbp9l=D>؞p 1\sgfѣGqc$7ǎ+ZzGoEDA@j~{ /8( za`=r iurZ{+8~.*q/R?Ga B38~&NX޽ Z76IEQ`S_-h2pJɠ_B\|O 6.IY]fq,d;[t2=pT9$Pa̘1zTD?+#g~ pTiw+  ?\gŹǗ."39In30ڮ^R^V~U:%/=5Es_O9YуM~FN^,ʄf.ͮx^^n?V`5[▥fN'z6xurUQ#ÚСC]g}e2f=;>+%d?9tAOG]FҤaP>Gtr ׫.]`ǎ_uDѩS'|w:nz63b{FDD8P||i&tQ7bٳZY5  Rn?='ť'ıe5{ =av4 :BEۅXyM86 gt*uy%i˃kf8ȑ#ؿ?l>}Z-uDž M.zjaaaӖkZl3j2ǁsNxݻ+cW*}~Ĭ.{qScwaX&;?7$gNoKCc4l0HSJ-;[͞ ?w[o 3;߅3fh՜iӦT|7:u6l;onٳm5!C ::1112e &Me$  1(\%wsڬػB[|:"2:gG?mt$k7d?w d5>u/f_~VҿtR]:M3H19s&}D#iii:֭[{`޼yٳ1aƅﱣqFAvc}qq@@  PXk\Uk܌@:8uj<; ^u;)G9GxXRSui<%j?_)SDē%tVpQ޽)cDU $2s6 ))IO7iDO"8# 8@csBkZhf)GQ>z^ONNy'$rK,AVVANF[ɽJޛL-4=u_~+WTLocժUXf tZ~+YC\XX=;gw2sT  NE?#[SΑT"zXo/?ɑLOFuL:h䉣iYzo:֧+L6 E%<wzb}p{S2zcCVGQBm۶M.v,F|µ>0G\!B>,"L~rr1XY]fq_wZ wGj<~MH ROY +㹘UAh9@*dӧOᅬm⣏>ҝ}jrw*T{* -ZfA1UYyu1OMDC /Mu$ f%jA?tdGHylGr{q>3e~UGr:# K.Ʃuza( zj*g/~kD_>BJ<6ƲxgX|9֮];r/צ+O  njL JIJF`Xz'Qtn7nCE$TGN{r'xyy,]u\%Gbb(ZViӦD4_^Uo dvoܛAyn\, 5A r;wN9^IϞ=;NyOpҊOhhimyqW  `%۫v(a;ո#YY .R!Q)u9um\Yq-qGh7 bϽ\h2=EFF"..NyN=7rb|?{Q}K'.Vqq`tԵrL֊ ><77>%2ۤ:ZSZ ۫qzK %W^A/2jjd{Ǚ[PP뭟 ª46AOƺ05w~OOG&qgai)X>k,p1kc"sGc?!xL*>J]!v@t YO2Sj)oX72[Ba̜^=s;b`,x-ܡmzKx!i0t9IUM1G+^STzFz'bxdCT{2q xORϴeX6lz&a{᣼x =g>()l>p1?o|`D'r*_Fp7yg~Ĵ^X{! C銘[քcnLxiݻ kc'd,Sd?#\YI;ӵVl}CT=ߠ;PƅX9/ qcSϠƤ=# 'KyD5z˭frO^ʑN"VIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/repository_desktop/images/repository_settings.png0000644000175000017500000007327512346515436031146 0ustar felixfelixPNG  IHDRG(% AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATxU߭.RQ*{{_X11E1hԨXQ@ ]@zggw칻w޳3zw̼w9L99ܐcGZg9990p,+*__r ӯ/o&Y|T|u˴t˥\Co>3L?]k#Dzé<';_¼u3Z~C ;UXX8r\CKJJnv {B6tc'.-qqv]\cm݆ uMklvqg\84v֦l'U4nlvg\jZېSְj:f~e݆'۪O zW9EEE*++tzB=U*WfI_9˛oS*G^8x/8uǕ_?y]\?///9+WF6E#7LFM7Pl˚ /!-tml}0V>}?<tEx$1̺VP$9ۃ8r #-t ef[ٮʻѣor-[VጣX TCCeA9򢺙/Oyp<)!\eLySi Zu>ljZUUuRW2%7^U@Sx}D'՝1g=u7N/O~/$W%R|jV?yp5|1u*K,_ ԩSh獡;r\^oKֿBGOV|auY}K6..L)O?^1E9՗c48NikZ_Mŕ|q2.W8q2|paߤr<䓊m\őmOyq2qqE?M|&'up/ov΍rC/#c[nyV:um硶i ^Q՜VWod_.ͳ|u` v@kWfu]#.qi[k~6bMSA?ҋ|pQN>2?OQ?2:Q_\Z\|ӏ+¾K>W7?4v,zMŅYV|XIpq8&F0j+?XˆͤI0DXYC ?([kӦMPcAUO83>%*K0/eBz|gۢi8 tr~8Ƴh^Sy: ?u# a8ȟPW ֓r,+<XA_|:|Z9]ngrmؾLƍf-6Ժ<R_:b瞶uNwXw_(guNg cY?d>r[2mʹl96omʔ)6aAl⒳w̲_v}˝Vfs'M97;hq[O8n|1?C0Lci8 a_\2d08LgZxp er/aQ2cz88^ERO y: ?u#e3ϲ(F Ǵ8|:1|5,L s,Y.6cFZϺuA?/@OnV6>?a(nڏ !s>;uч,܌3+ppL ,[8qJ]Y\P/O|rMyȅ0v֕q(Pa:x3~q,W_e)Y2>>sx3~qh[S:p}cY;ijlh֮Cwc0ӡշml'Te0s/~eÇv w/ivygUcrȒѲ(xca|EE| ;|6dM[g,j[ m\ѱ<ϲ8Cyzok;=ܾ}as޷]UNuq{o;<8rmdg?9'Wy GTqQHsX yq^`qzBXW_ ,ʲϨiga|B=A9az؞02<)?lf<ǡ >`]k=n[t- \P,қ6kUy.X!#ndc̿^λ`^sӖv>rl'>\h9E5,u'?ElA#lny.Ⱦpx?_m~?mzϞ~N>t +tȑ_cO_hg- >ܵ-=Gr-cnSצk[iաuھJݭ<U6e=~t|lVJ6׬ݎز7߶NڡGcWlg跫0cH_+e{OV^ ]ϞQS)mi ?kc]=sgmXN\7uתv;XV"ؔn;YEo{ؑe}FMN9|+_mo?}ik;zmׯrDޫJ||1[%3??l郗gMx)_A&Q" yEc_|(Å28f^cua0>=8^t1[F)`810jm 4 d0tCXNBt:|ea943~x0 '|će1)<By2:P.,77%拖:񌣏LGic=nL e/*c=H i82t̋Pҙp0Ci8fS7 )<By2:Pe M_u%ʿ!(O-ə>r~ekц-启xxרZ kۏ+G;t7իh>@Sû[׍w揲h{<[5#=v-+*v/O lǏ+Wv猡2죢R r"'+6VX^^bJg̘WV\dKo/Lk{xP?;6(;z`{j=dg;!VXwKNU:}`єBٰssWi3!94۠l={Iv]}JmU2ֻٮڈNޱjk'_?|vq Op ~ yNlձ]#e]{w ;p.Vб~7}Ҿ;nu͝ccO[b'\aX۰hmFvAK^--[y{큧>{؉gmlKz^|qrֿmM}9{8c'kt-SC׿U ! `[=?SqA&GN(L t8FaH Ґ7cY} =ކ^%xc^tL,3'A8Lgc>h<"۸P,/̫xF1nje1Ә8Gr!S!.Wc9-/:$ʱد+…` qQنc'lk>ԉ͂<&!:Ճtbq 8ƅttt̋c0P.ԁcE<^|QYs:G}=;p18aèƼa耣5#rE\x ˋA0'f~rZ8'P^RlV+mUUɫAm`f-򼯰"ieV]:_vyyudYx_vYysr.r}Z9; y 鸅u/,r#`U6s2N kƘQLΡ:L%,vD-.xÖ,2WLE\Μwm䣕pq k0Zv[ph7 2 :>~ =!/ø5TO~¡: c"_Xo".1Cʣ^ȅz6 È ˃>֟,~\>! ⩃:֏2,l-dW_%y mR޽ q^\? @W'y.LE q8Fᠯx᏶u>G0JV9c"uVBڠM\ݎ@Zt3z^.kUZuk;{؎vİNm6>Nۻ6\uutӏr"֫S+3\Zur`RZZgwrvߴ1en׆pvp9.~)^Ϝgt.[3%ʊz>[\]Q:p}~|虶Cj#M{tjyzk^68p,X0urVą:e~z!YW|_8-p<\tg:0/e4Ci!t^waȅ!?d ?dG:6!aaz&#ʱ©+|#{2F3>u~ v[O ~pAYeK̲y>ʺ=hOqJ7p֧n}LnuY>\m !ޕ?|**ݥa[%_dϽ3&m>ϟtV}kGg|?F2W,+-4{ŏm¥l|6y-sUurP}qSf6(:ҍt^>fK/fwhN-eN9xlf7ʫ~L[^TdK~ӳ3FފN/i V]亸ys_UC*Z6(t6/K9]ZW&\Wb}ۚۀ*Iw<݁c6.<1匟l3fOf. l9󭬠uPFZMؗ 0tjA9򼯼~qHCeG?.>G:uG^Ƈk>eX♗dVW GvCeqǼʂ?qxMO9!]_'F< ~c}^o}׎˖- Y շx}tQ/UV5NT8aƅ>E:;WJWe:b(^c:|rP?⩋:X&|dL<⩃aç>yB g|8ԋ𼈆Q/>Q?}։Q"qt߸rɘmb:|}|tD'!ޱ^~3ܜyVi;;bkQwCvcZCP9 Ew?Sj8Gݪg߀F/bLE>aۀ]f?o_?q_>p۷U{mhn{Aav\75H g%5F|]yU 9nx8km6ֵy; 6_q#V]_T+wQ/fcl=ކjk6 Wj{̮ }&[n^^?mϓڻ/9mT1cpxp]k[usS1b߱uY^gnڂ__/u<[k0^Q}ϙ={Z>b8p"ܔΝ-]֡C޼`^6Ql,Ѕp]02QFuCҰNU?Gb!C}ÓaBӡi| emB77 -tCy!sy)rEy3/cS>Y?t ӣun?aa2Cә__-dF28ùqW R[=$k6p9r Ȉ[&:+mhP>ejڽ*q#&a> nb+rk Z9~M |7}ͭg)wӶ-"Vݴ4f yŞ~o ?XC7\ZVڍt0?b}؁je/p/č` wREԹwOB?Uq}rNyeN/`:pqڳn=ɶZtXA+禲yL]z99W| Un[P\^EZaW>%ifyak\w>X ?ܿ5yn'>fLza?=R~̭M2L<Rw}SxuT*VHʱ?x">y^̋<RYڱ15CѺR_Br rQǏ} y'?q2>^;la?Cy稣<|:ʱ?H1ٟz8e# 1қS̜9սQJ8ܜf h8Q'1> Q' , a#bGCǺg};u8=ԍByAwL0C`. }p;„8 pˋc1/S'aa:Ez}Nre1ldyt3/ ֏eRԋ8ևqHcaG:NyC >򳾈G9p{ Bd k ~dr xB8/c pʅ 0ucXgpԕ3}tf0#a>gEpLGyr,.QxfpNCzXOM1 |̃88 D18<ćʆeRX/Gpc G0?DZԩ+[H/ȑ}87C|L e2)|u^ntVZ`$4xnOihw7\rl|^WH0CXYAnCt -GLc?Gb8qE<alN+*S18?HS7ؖG*8έ8rCd笏ttɇzREyga8չi׾lt{ xnя 1 e51+Yo[l;#>tq6 ?\4O@GǴT>Dۅ88}D4k3!+ɋa?0L20OHL'?ADrW&!ø0=.<ވG٨Lg0 >~ub{ҩ[p믿n>=SVPPĝawۿm:ud^x{챾z=~8o}ǿ|K.裏M6s y!{.={K.ħm֮j;蠃k|]veb ߿s1`_y5_s{5*XD@D@Diz3^\cٳ >&Md˗/_Wv),}EEE^NC=4# gꘪ]䫯jx Xy>z| m[v0'Z/jlmR @[_atN 1>''0Q_Cae1nݺxqy/K;s1oۻ[5Z8PP6˜3[oy9vW}g>ݢ, lH@N 95Hc= hz|37Əogqx>k}ȏK]ꋖT_Xkο޺ꘪ]z ' .#G[o_zC_] q`՘I?ٖDFiŝ@x> v͆nXt7ڎ;chv{0B0tڷo_#^x?#JP#֧O?;':ծ;s`ΝP|0oCC+dad`]sh3ڎ6pVU,Fa_\\G0 7+" c#OmL{{xJea;y4E Q'.Xl9!"MND@D@Deq_uU6|BS1;rNV[z^Y0S0&S.Ufx}1aX_g ʑ9pر+g,ߘv lLRu'0,0wvq;`H .|bFyw gyYZdQLEC04EvY{SO=ϣŰ)6\`CVaN(۱ =cvl 9Ux{Gr" " " "0ͭ9^dجŋmڴi[6xAT-L)GX1,:,@ŇMhjI.nZZڇ]D@D@D@D S=km뿶OJÈx_n3f̰n-SdMǬ!/|/44>kZWɋ@ `P1%8‚8 豛7|c}}Qn#A0FR(iuv&~5G=pMv>M^#Hl?WGe<}Ja2eUzRMaDq>~yIq%Ɉ45'|վ?RI"V8_N?t~)kQڌ)LŗꚚGR9^" "}Lu^J5Ďt1'Nh? F?u'G}?F=Cl}oM=b!10t+?G`|BĆ]g}I뇑ɿvE5ei3fL"v[{W|ܹ?kڷ6~jA#y?'_SIk#" "0;,s9OeV\~+m [^SgW/pϔ R#kUq~_6GϽ[V[FyC`*[o*_U\-ׅۅ~-T`_o-: 5&Y6aޤ}5g 0 v/ְay`4 E?=-hCk;:ִlLKmv39n8s2>kWaeͲZ~w_찣N>ȊKo֜>쫺ˎm yZ˚q F+~+m-GuTݞ{cKS~.~J >uĪ 7oFc+/R"zkT4rC_AT0Bwa0a e c?T7\aeȣ~ruŏ0<@zC7F.vatI~ 5\ZaD۽Z]uLj%k+C5L F`a]Q]l|<8&al@2|pEիFƹ6{TC1Fp1>t.֭[7;j|*}6Ԙw 'Q7dQ3E@#Y9xٌ 8 y<,SѐͳlFPL0*\Ĺ.0Σ>Y}E@D@y1 TTTꌢחZV[1ڸwVVe5rԄ=)rf#Ax÷@u)LÃtszL5CRA#d` [D$x8 ab3 O?ݾ5TøѲ~q f` ĮJ?#=_>t@fu0b0RةS'_1oXw#| z3΋6mn0 \+aTb2tbd`+Fԝ6U&88Q2 \wj*?S;vGzu+Fs>}5R&&/6fEYXD@DyXx0>UC3.{~[.p3b ٯ.\v2c,{jmf6{b/kV״5m40]k &oSj馛z)LaC/vuxæFI81ElҤIU ^u},0S-l1 uS6ahl1-* EF NLoJ ݋|rmqZA~~]tyn/Yiv[x48Lm4*a:@Cax ÆYO2I9AiJ0vi6:b!&b- PϔX_]$xZ8TpN/t0RxA` F02q>}qy1ƨ¸Q[-'|RC/0҃k*F— 52fNdc>Fʄx!O^GCdG e:]𒲮rkڵmm۶ZFaL*5IDAT3z!y??:t YsyZKqֆ7 .`u0x]Bׯ_?PC$lumQT0 Ft9/je30m讻0z흱<`a `MWea_*kX-a7Li?O ~ac #RЁu#KdG3k֤tf:9akvNjjE#0umA_}&euf#16\NX )X㆑SO=j -F1.Y8xF1x  R]v$d<È0:QL ވcmMa*mV#C%41} ё 즇8qa;iq F:5 aZca{~b VC;΍n)F0ӥ:69n p,cK顏e0K7ܐ 3gi0$u\ јq6a%lFw ufP" " ".pĘ #mӮ;&<1gua(`fOYi}ۀ$gLfcAopM``dKtx@qv1a:ZpM0 kXuH5G4C~GQier*_R< F`xčLf={[n۲{{.]gEzeö>Fz)؉qX5G8z*Qu, θ9xma؄*_aTUINQH#>ky#);Dk ŷvD@D@D@D34pcM<> ,` vde%~Q1> :ݼK(T￿E-aYg*," >ҲV!l#.èB" " " -L+|:d mè17+ a4'<;]ϯ0 X[!̃ȉ4?8'ր vs ;a?ݘ&.LIa^ƏT $@3MKt5SaH.cJT!mDuXD@D@D@D@D Yqj mBu-([YK7ң''" " " " "l8J5*3q8iqu,t>ōT 0үxdhvQt+n`\xqsG2>EGF2a>P+'" " " " "м4;jOacw9s]wQ_ip>a)tprw_$ŋ$@2FmT'V#裏ql=zhzs0 |'G`{TɊH0fcin(-ZdvZ q._;1W?QkJTw-]4UE@D@D@D@D@LG\sMQb1b}w5@Yk+)SԈG=zԈyꫯ^{[lQ+|~iH>faat.8 {74h]|5pOu _}-YD\qQao ˜Qʠ@$88p=N9]&+,,?n8;agmni=QvmW+7p9MT@ Zb6Pҥ&v;cjmDL}k4:#lŊ5;wluvwꩧ2ڶmk/΍3Ʈꪸ$ʼn4#9 /mرcmm5cZkNjX#4{ZV6 t:d馛,ïXtk:]-ŠG Q~W_Ђ W." '4!F&Ǫ*[wcaaS|t;`W#<2֘б@ $8 Ǐ>}{Ú#D? 뭷]O;xh錪1MBWQQa?G }XS# P/FD@D@D@D@D@/D9f ?|{c "wFeluA^{m47,9tvwRm_PP?l0D@D@D@D@D@ZG0 fovМ9sQ7KJJ;x{~_N2$RKR~;0 i(," " " " -@֌#& 5a-??ފim]w?KI''̝;׎=X{뭷UÇuֈ裏TTt " " " " -@B;`{衇_77bz5N8-ˆӐ!CRFtߝ.c=G(,Y9J#󆱂]n>m6_~uHP0/uʌj;|' ;=S(^D@D@D@D@DHqnڌ3w-JyϞ=oO>ٰǪ?ޘ!r-ް~@6V"E@D@D@D@D@=DG0Hƌ`i¶1Quxu8Nҭw[ru]׿~ " " " " " ͗@"ݻ߅k6l3z^{ TKW_}s9w}iJG" " " " " -@6:wl'_K5m:ʆ7w8c瞋6hqh"{oხؘ3lD@D@D@D@D@DqnTwR5@" " " " " " 22AQ:D@D@D@D@D@=&3Znai嶯)3&dQǎG].ED@D@D@D@D@MɌ#`8Mj.0J4:&5.e]QI)mED@D@D@D@D@OI.((QF}gcƌI&Yiii)56h ;϶&?PS8B0=\ +d5I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$t*"" " " " "M2I_e$@~bjd=ܓqR(" " " " -@΂ *Zjvue]n." " " " ,\0-QƑ&Cac,hj!" " " " C@k432Y" " " " " C@QpVfF@Q30UWD@D@D@D@Dq8j*" " " " "8jfꊀ4GUZE@D@D@D@D@GͬT]! qJ@3# 㨙u+" " " " "8d5Wihfd5SuE@D@D@D@D@*" " " " " ͌fa@q8\UD@D@D@D@Dq:Lh2432Y" " " " " C qJG`޼y6c 3gX"LT۶mgϞ֧O޽{FZ/c5DcpO2%%9W_}el <غu2ZŸ~ɦLY=kk {zg)Rސ8j-ɊdԩSW^gToKSr5=3DiLsoH!$+" " "Qg϶fTgKVV`NFP+Sҙސ8j-ɊdҥKTR?Q (u0[[$VRRI̘=xju)5*Xρz)YD@D@D16y{x1]wu[L0˄O=)՗2c2,:fA? /nŋbMuifК)]D@D@DQ `Mc=vm?٦On\sMFہ:WVVQu)ɩ+AiIzX_zIM N8oO-¾{׿e:u=s [v2y]d{q.)ɉ4 hl+rs3;i꞊C&Xuo(w.9P_z*VO"wϓ'Ocڠ6]*?ӭ{f*9XMa {Q3fL ~adK/|mԨQU2u>묳쪫ʋ_v7ֈ[SN[:孏ܹsSn|ou՗N)I1je]f]vuzm;Bxސ"7H({tl~9X@b1p뭷_*-.(&~2%%9F!)> e)bCInLrm.vy W_:`}#Ȼh"{/,wm(/Su_孏ga+WFOjxfc>˔c׶Na!>}XϞ=NMò24Ձڢ8va[ZAANWɣM0걉àA }:v6XϷM7ݴF_ >QԹIX( Hh<ƹ?Pe5С ˗/#B?79<ڵkg뭷Z4x1]lĈC %wW,Nb6cF#soח({è9aGds0`@10;U,i7|saÆQΝ;{.gMLsO2%%9fAf<f t^)s5?_&‡#G#TGyd7Ћ"L㊺ң1>F?㎱0Sعb#ՃOh̴/ܯg ZBXQKEAD@D@D^kUC ˇ~X@MFtS>c;K.0UVar}m`N:կ!|郞taT}_g[+0(oϫ7X pº~ۖ,Yl°뮻Mf#1.a_1۷oߪvӚރ@ v0 ʏ12viwyw}PJ7rدk.]o^kX0BW_:6h]}ǔki> pl(_~"vuXk{;at]w7]g}iimڴ`S;Qx7}o*(" " "$vgf|Q:m <0;&4/L/rv95(ZV6x^paS)}֬Yl2?X 5E+Vڶm6:bZ>޽{4i3ɽ!An0С'`a8܅pSg`bJ-šg)'~71Zb  @1dc.2^pwvL ï~~ٜzU ـzh/L=)it_O2&)jĔݏJLb9Q:%Gt#@fGs?1PЅ48ң2q1nVuԿ&JXSszwh%@ {:uobҵ*cp1u$5x픶qq9>$Gc @b޶XE.$m1fq2sgYrG @@i^#@ @ + 9J#@ @tj @YQVJ @$GW @ HR @(- 9*ݽG @@V@rG @@iQ8 @8 @J HJw @ e @ PZ@rT{5 @(+% @ݫq @d$GY)q @^#@ @ + 9J#@ @bSG @m\/v @ @@0ZV[s"IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/repository_desktop/index.html0000644000175000017500000001077412346515436025024 0ustar felixfelix Bundle User Documentation - repository_desktop, v1.1.1
Bundle: repository_desktop
Version 1.1.1

The Knopflerfish Desktop Repository plug-in

The Knopflerfish OSGi Desktop Repository plug-in provides a bundle detail view for interacting with the OSGi repository and resolver services.

Description

The Knopflerfish OSGi Desktop Repository plug-in provides a bundle detail view for working with OSGi repositories. It support common operations like browsing repositories and installing a bundle from a repository. Future versions of this plugin will also work with OSGi resolver services to be able not only to install the selected bundle but also all its dependencies that are needed for the selected bundle to be fully functional.

The Repository-desktop view

The view presents a tree view of all resources that are down-loadable bundles in the configured repositories. The tree supports a number of different ways to sort the bundles. The drop-down on the left in the tool-bar below the bundle tree can be used to change the sort order.

The main part of the view (to the right of the bundle tree) shows details for the selected bundle. Here you can see the download URL, the size and a SHA-256 checksum for the bundle. You can also see all capabilities that the bundle provides and requires.

The Repository-desktop view tool-bar

The tool.bar below the bundle tree on the left of the repository view provides buttons to:

  • Change sort order in the bundle tree.
  • Rebuild the view with data from the available set of repository services.
  • Install the selected bundle.
  • Install and start the selected bundle.
  • Show a settings window to configure repositories.

The settings window

In the settings window you can configure the rank of a repository. The repositories are searched for resources in rank order, highest rank first.

It is also possible to enable or disable a repository. A disabled repository is not searched when searching for bundle resources. Note that the enable / disable state only applies to the current "session".

The settings dialog also provides an "Add..." button to define new XML-based repositories.

Configuration properties

The Repository-Desktop bundle does not support any properties for configuration.

Bundle Jar docs

repository_desktop_all-1.1.1

Exported Packages

No exported packages.
knopflerfish-osgi-5.1.0/docs/bundledoc/bundledoc_hdr.html0000644000175000017500000000305612346515440022527 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/bundledoc/soap/0000755000175000017500000000000012475375714020016 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/soap/index.html0000644000175000017500000000276412346515436022016 0ustar felixfelix Bundle User Documentation - Web Services / SOAP

SOAP and WebServices in Knopflerfish

There are no SOAP implementations in Knopflerfish 4 since they have been made obsolete by the compendium service Remote Service Admin (RSA).

The Knopflerfish 3 versions of Axis 1, kSOAP and Axis2 are availble from the latest Knopflerfish 3 download page and can be used together with Knopflerfish 4. Individual Knopflerfish 3 bundles can be downloaded from this page.

Information on available RSA implementations can be found on the OSGi Specification Implementations Wikipedia page.

knopflerfish-osgi-5.1.0/docs/bundledoc/cm_cmd/0000755000175000017500000000000012475375714020276 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/cm_cmd/index.html0000644000175000017500000001307712346515432022271 0ustar felixfelix Bundle User Documentation - cm_cmd, v5.0.1
Bundle: cm_cmd
Version 5.0.1

CM Commands

Console command group for Configuration Management

Description

The CM Commands bundle provides the configuration console command group. The command group defines a set of console commands available for interacting with the Configuration Manager. The list below gives a short description of what the commands do, for complete details on parameters, use help on each command in the console.

The Knopflerfish CM implementation provides a legacy XML DTD, cm_data.dtd, that specifies one format for storing configurations as XML-documents. The Java package org.knopflerfish.shared.cm contains helper classes for writing and reading this XML format.

The import and export commands works with XML-documents following the cm_data.dtd. See cm for a description of this format.

Available configuration commands:
  create [-help] [-f] <pid> [<template>] - Create a configuration and open it for editing.
  current [-help] [-t] - Show the currently open configuration.
  delete [-help] <selection> - Delete an existing configuration.
  edit [-help] <selection> - Edit an existing configuration.
  export [-help] <file>] [<selection>] ... - Export configurations in xml format to file.
  import [-help] <url> - Import configuration data from xml file at url.
  list [-help] [<selection>] ... - List the PIDs of existing configurations.
  save [-help] [-force] - Save the currently open configuration in the CM.
  set [-help] <property> <value> [<type>] - Set a property in the currently open configuration.
  show [-help]  [-t] [<selection>] ... - Show the saved versions of configurations.
  unset [-help] <property> - Remove a property from the currently open configuration.

Examples

The following lists the PIDs of all configurations in CM, then shows the configuration properties of the second configuration in the output of list (using the list index on the beginning of the line).

configuration> list
Available configurations:
[0] org.knopflerfish.bundle.consoletelnet.TelnetServer
[1] org.knopflerfish.bundle.consoletelnet.TelnetServer|org.knopflerfish.bundle.consoletelnet-IMPL
[2] org.knopflerfish.bundle.http.factory.HttpServer.2
configuration> show 1
[1] org.knopflerfish.bundle.consoletelnet.TelnetServer|org.knopflerfish.bundle.consoletelnet-IMPL
 location: file:jars/consoletelnet/consoletelnet-4.0.1.jar
 change count: 11
 properties:
  busywait= false
  defaultPassword= admin
  defaultUser= admin
  forbiddenGroup= 
  host= localhost
  port= 2321
  requiredGroup= 
  service.pid= org.knopflerfish.bundle.consoletelnet.TelnetServer|org.knopflerfish.bundle.consoletelnet-IMPL
  um= false
configuration> 

Now create a new targeted configuration that will use [1] above as template to initialize its properties. Then we change the port property and saves the edited configuration.

configuration> create 'org.knopflerfish.bundle.consoletelnet.TelnetServer|org.knopflerfish.bundle.consoletelnet-IMPL|file:jars/consoletelnet/consoletelnet-4.0.1.jar' 1
configuration> current -t
[-] org.knopflerfish.bundle.consoletelnet.TelnetServer|org.knopflerfish.bundle.consoletelnet-IMPL|file:jars/consoletelnet/consoletelnet-4.0.1.jar
 location: -
 change count: 1
 properties:
  busywait:Boolean= false
  defaultPassword:String= admin
  defaultUser:String= admin
  forbiddenGroup:String= 
  host:String= localhost
  port:Short= 2321
  requiredGroup:String= 
  service.pid:String= org.knopflerfish.bundle.consoletelnet.TelnetServer|org.knopflerfish.bundle.consoletelnet-IMPL|file:jars/consoletelnet/consoletelnet-4.0.1.jar
  um:Boolean= false
configuration> set port 2322
configuration> save
configuration> l
Available configurations:
[0] org.knopflerfish.bundle.consoletelnet.TelnetServer
[1] org.knopflerfish.bundle.consoletelnet.TelnetServer|org.knopflerfish.bundle.consoletelnet-IMPL
[2] org.knopflerfish.bundle.consoletelnet.TelnetServer|org.knopflerfish.bundle.consoletelnet-IMPL|file:jars/consoletelnet/consoletelnet-4.0.1.jar
[3] org.knopflerfish.bundle.http.factory.HttpServer.2
configuration> 

See Also

CM - Configuration Management

Bundle Jar docs

cm_cmd-5.0.1

Exported Packages

No exported packages.
knopflerfish-osgi-5.1.0/docs/bundledoc/http/0000755000175000017500000000000012475375714020033 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/http/index.html0000644000175000017500000002624512346515432022027 0ustar felixfelix Bundle User Documentation - http, v4.0.5
Bundle: http
Version 4.0.5

Http server

Small footprint OSGi HTTP server implementation for embedded use. The HTTP server allows bundles to register resources as servlets, web pages, images or multimedia into a web server running on the framework.

Usage

The HTTP bundle can be configured by both CM or System properties

As soon as the http bundle gets a valid configuration it creates and registers an HttpService instance into the framework.

To use HTTPS a bundle providing a SslServerSocketFactory must be installed. E.g., SSL Provider — J2SP.

Note: If the server fails to bind to a port, an HttpService will still be registered, but the service property "port" will not be present!

Console Commands

The HTTP server has the built-in console command group http. The command group shows information about configuration, servlet and resource registrations, as well as transaction status of the HTTP server.
Usage: list [-help] [-c] [-r] [-t] [-l]
  List all the configured HTTP servers
  -c  Show configuration info
  -r  Show all registrations, servlets and resources
  -t  Show info on transactions
  -l  List in long format, same as supplying -c -r -t, providing extensive details

Configuration using Framework Properties

Name Description Type Default
org.knopflerfish.http.enabled If true, the bundle will start to listen in the http port. boolean true
org.knopflerfish.http.secure.enabled If true, the bundle will start to listen in the https port. Note: This functionality requires that the bundle is able to obtain a SslServerSocketFactory service instance from the frameworks service registry. boolean true
org.osgi.service.http.port Port number that the HTTP server will listen for http-requests on. int 80
org.osgi.service.http.secure.port Port number that the HTTP server will listen for https-requests on. int 443
org.osgi.service.http.hostname Host (IP interface name) to open the HTTP server socket on. An empty string means all available interfaces. String
org.knopflerfish.http.mime.props URL to properties file defining MIME type mappings. The key in the properties file is the file name extension and the value is the associated MIME type. String
org.knopflerfish.http.dnslookup This boolean property decides if the server will use DNS lookup when a servlet calls the HttpServletRequest.getRemoteHost method. In some environments DNS lookup will cause the current transaction to hang for a long period of time. boolean false
org.knopflerfish.http.response.buffer.size.default This integer property decides the default buffer size in bytes for an HTTP response. If a servlet or publisher does not exceed this buffer, the server will calculate and send the content length header in the response. If the buffer is exceeded the servlet or publisher need to set the content length header explicitly. The content length header is required for persistent connections. If the content length is unknown the server will send a connection close header. The buffer size can be set runtime by the servlet using the HttpResponse.setBufferSize() method. int 16384
org.knopflerfish.http.connection.max This integer property decides the maximum number of concurrent connections to the HTTP server. int 50
org.knopflerfish.http.connection.timeout This integer property decides the timeout in seconds for a persistent connection to the HTTP server. int 30
org.knopflerfish.http.session.timeout.default This integer property decides the default timeout in seconds for an HTTP session. int 1200
org.knopflerfish.http.encoding.default The default character encoding to use for text in the HTTP response. String ISO-8859-1
org.knopflerfish.http.req.client.auth If client authentication shall be required or not when using https. boolean false
org.knopflerfish.http.trace.enabled If the TRACE method shall be enabled or not boolean false
org.knopflerfish.http.limit.requestline Defines the maximum length of an HTTP request line. This limit is also applied for HTTP header lines. When exceeding this limit a 413 response is returned - Request Entity Too Large. int 8090
org.knopflerfish.http.limit.requestheaders Defines the maximum number of headers accepted per request. When exceeding this limit a 413 response is returned - Request Entity Too Large. int 100
org.knopflerfish.http.limit.postsize Defines the maximum content size for a POST request. A value of -1 indicates there is no limit. This is also the default behaviour. When exceeding this limit a 413 response is returned - Request Entity Too Large. int -1

Configuration using the Configuration Manager

The http bundle accepts Factory configurations on the PID
  org.knopflerfish.bundle.http.factory.HttpServer
..with the following properties:
http.enabled
If true, the bundle will start to listen in the http port.
https.enabled
If true, the bundle will start to listen in the https port. Note: This functionality requires that the bundle is able to obtain a SslServerSocketFactory service instance from the frameworks service registry.
port.http (Integer)
This integer property decides the default port for the server instance. The default port is 8080.
port.https (Integer)
This integer property decides the default port for HTTPS requests to the server instance. The default port is 8443.
host (String)
This string property decides the default hostname for the server instance. If the server is running on a multihomed machine this property will be used to decide which network interface the server will listen to. If this property is not set the server will listen to all network interfaces. The default is to listen to all network interfaces.
mime.map (Vector of String[2])
This property is a vector of arrays defining MIME type mappings. Each entry in the vector is an array with two elements where the first is the file name extension and the second is the associated MIME type. By default the most common file types are defined.
session.timeout.default (Integer)
This integer property decides the default timeout in seconds for an HTTP session. The default is 1200 seconds.
connection.timeout (Integer)
This integer property decides the timeout in seconds for a persistent connection to the HTTP server. The default is 30 seconds.
connection.max (Integer)
This integer property decides the maximum number of concurrent connections to the HTTP server. The default is 50.
dns.lookup (Boolean)
This boolean property decides if the server will use DNS lookup when a servlet calls the HttpServletRequest.getRemoteHost method. In some environments DNS lookup will cause the current transaction to hang for a long period of time. The default is to do DNS lookup.
response.buffer.size.default (Integer)
This integer property decides the default buffer size in bytes for an HTTP response. If a servlet or publisher does not exceed this buffer, the server will calculate and send the content length header in the response. If the buffer is exceeded the servlet or publisher need to set the content length header explicitly. The content length header is required for persistent connections. If the content length is unknown the server will send a connection close header. The buffer size can be set runtime by the servlet using the HttpResponse.setBufferSize() method. The default is 16384 bytes.

Bundle Jar docs

http_all-4.0.5
http_api-4.0.5
http-4.0.5

Exported Packages

PackageVersionProviders
org.knopflerfish.service.log1.2.0http_all-4.0.5
org.osgi.service.http1.2.1http_all-4.0.5, http_api-4.0.5
knopflerfish-osgi-5.1.0/docs/bundledoc/desktop/0000755000175000017500000000000012475375714020525 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/desktop/images/0000755000175000017500000000000012475375714021772 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/bundledoc/desktop/images/scr_active.png0000644000175000017500000000445212346515434024617 0ustar felixfelixPNG  IHDR*& pHYs  iTXtXML:com.adobe.xmp 5 2 1 m IDATX ilTUu:R -| %h KQ,( X#(KURQQ c I t2ڙtsn&Йi| z{==$xD0 AGz;>{{~dѠ$t_}9ߧ$2l@ Oc+ĹȞ8{>;p8<.aϣE ´n ص8B2G /  Rۉ߯b$[ߑ!z>|TvK N JTZ%,fMݟx$DxXm~%D~j4v 3vY_$=&dQۃ}_ŽQ@Y{KH"H%_n"+'AدEu:d9dI'|ːJ/iz-3B2eੂ'qw` j;Qv',nSJ`'`bPJ4IJ5f`?QՁ`4J'~IK+?/5 }! /t"zXn2vnx)):?KL6.?EF"7,Ӌ ,&ېHr'dp K.!k5c#Ƒc%bt Q ?yK׍hXQ##=r\c"XY5RnCر8ʉJ/ċ $o2/p2T/9`dd/p(AMLv**m.TK3z (?~5c_4dU*9yB3Kez}Ad;n4  RѩX]2c7p.v#H{9OλLVe5w: T۩U-{$M1,iX uؾu*f0g.uʴqx|uZ\V7DaaasoGbǶP}[z$2tL,Gts(G=qH%: &qAcZ;6:(Ê]CCAgh[Š,% upq0`߃hUDG[ 4 'I٢~;!?hQy4N ~Q97L.7 jlEmM-rE fPP/JOO.@pF-E4ؚcG56-jnmii`3grJFK".l^nRЏ5%/Q7jKy5ISsjjjPUUS'Oxq1N|:ҖS^"!Px(BxY۔Pp7ou ÁrEl6Ѐ+VhQ̠FNyV9u8CK_.AuJSRRXl,: +R1G?Q ^V-7"ENyp!|'$D ZwAZ]Y}Ѭi@GySMفǛ`>6oڌM!z<9+lrr(%g1t[:lٴYYY1%RT̓10+/ )B㏝7oJw]Is8eCp> ł¸hܞq^uM&S%t q . 4_wAr_$#P/B5F怪IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/desktop/images/lib.png0000644000175000017500000000310412346515434023234 0ustar felixfelixPNG  IHDR#!SR pHYs  iTXtXML:com.adobe.xmp 5 2 1 m IDATX WoE퇽xSIE[/Qz \AWnH!$TZVℊj+@M+wwvfmz`${w~~ͬSsR焇?G~a[~'~;P3o]߷D#Lm-$3#! [F{$ V(˂av,A?FB"]iJsXYZ2d Dr \?G5m>G]qf`L^CO{E-XK& p&: +)(Z7IE&{GFJS@F^yх6kI2"7qR,(Z2Jx9aw9|w¡iDZ{)A&qm=8FLđrDfe[&2k6Q# E!ںFƎ?L-SqGy%uKFb,CgCŧoo27z(2UOJj6z-׫# ;'ܤ:4GxC}krU@X/x$R"aI3th&jZVtVcvlB~XlMcåhOCTK[굥Uwf2,loWn}^1N/ڧiZ}t{]D#}a)/<>HB̚~&=r+Mm4 83L2Lj}xwjxW.0pr2A*>0D<`y810F]|\>IRY=ݕW5&lJ]CdukK&mckkwogJ4i)1'^x |˨V KAAUOg?K.$؜Ak,`Q,2N! ׸ԱxW#F0IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/desktop/images/desktop_icons.png0000644000175000017500000016753312346515434025353 0ustar felixfelixPNG  IHDRG AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATx]`UE>=!;DUT뮽Wuv-k[]W]{ANT"5@ Bzo?߼}/量́ig|{;bY12/?r+m5o;Cw9sCJJJ6q`(GW(Eaz|&qNm4_dRuNvK}{ʽ!A{[C;RXXh1;D7B9)5_ʳ˔|x I>zq7/\W6r_h%y|uE"Cʐz CD9C .HT%H:\K "Kʀ+|c'D^ 旰䓰+~I YR\4C Hp b̤PQQJΝ;S)66VI>ץK֭~W?ȳO%2'~Wʁ+$IqW|p?+#OdzEȔt D^ITs$xDB@ vnz~ۚCtj/tⅳh` ͠} hT>@^_ď 8t nP*+/ %/2RY;J;ᩤ'+"W5SϡQъ/>V9T/QU %aK$םEg'AWBj!^HvوZ<:N^s7ׁN6Vg(<~HOD^~+D#< \t?a)[ꤻ>38 C6~ K\PG,]G:',/H~2? p!qp<)CO#ely {9 %m2${{ J[XV.efSlR^MelD\eya]Dt#κf_t6UJLF8z !?OLC^y%+?R"H~CXQwi;ku 6U&\Hb88yrp9"&}xArSHl%WH8q_pu~lq#z~K]tB:y$] F§tI:2@G!_K^HxDmPċ|UQw:|W?Ҟ"*K۷4~d8'sy誐vYM!4o2`LucSJikm2<7VIݥ$UGCmOK#C>ᅿ_AtWH8q_pu~KyGHN'$~twsI% oGCjk׮y+R+^4RdLU^޽< $yXƌ|9pE!z$,#/y ȑ+ ]6ڋ8iE|R<"q"KdH\$ 0\'z_~L$K\)E.%7!_75 4>+}=o M@gI>Ϥя_}LZFy&J<w͐&Dl7\P*ZM?U3:0JVH \&AI׽]5 uҋHy WHXŕt.;X^pjF!v*-XL L=zP<\$A>Y{ދr$ aCnr{FI i'FK"NFy:ANWº_CEi ?xR"~:<B:x=W?vᅋ.D#e ⥮R.` jN9t+~\5iȄ iX_`iʷ#"Ko'^Gā?iPj%āO!m>W 4\K!;wTWT(xztċl #M?\K}DOuuI|£A"ϞW+~݅ @?PO:#Ce ' u\u ? u Y!<y] "H = X\_*k ?Ҥ"K/uEI]`D&D9tᗼ<AnP''aƒ4!IΫ)K!A `04ؑK)d3 1&WA0Ƥ٠4 @E{rA lclPAA"`IսiA `h6›MR3 *))vL9,g}6o#:];I5 'ʘA*Rq7|3mݺURe@B`S9u/BhEma-83" 򇁇ώ #on钋.W') @eL|V7$ FW\qEqFu&΋=Ͱzv3|8kSNtqǵ}#M ~ iWQU=? 8:<ۚ) ,Gt衇a`T` @x a46o2.*cQ #PXTHK.fƾJJKhާӤIS|p*Jݾ&AS{RJ4je8`4#fk\r扸jAQ|00)*/޻m#_F*( [Ihb ۲e ͜9SRSS駟&>_~\ັp0KS..w4ʪE)=éW(*-M9]4cypj'>.5ƍ4uʑj fߣGO18C#ƌ-;wRn~!M:cP ،2-bWz"wq`pQhgad8'xДs<  x7ѣGS޽ݘ駟/s1i{뭷?[zWyq;4 WZZJ ʋ6u*z ڽ};ٳ~۰ҲiԠ="B(!&zwdڔi2 GVHsx,XGJJJ靏.Թ[ŗҧ/ٟK7n$ \~WTW9ϟ\+/JgRŃ{Ue"rZWϿ`)7mcS^믿޽*77̙C7p=C2d?HGq3֮]KW^ye$ zcr i9JVD1@[VRNƁrI1W[dh5EYG9%U`T_JY G!^sBԗPLB/^h򘈺׀Dey"3>mP2*2ï]ƶ1.b}xK9rhoJ了ȂhW4& |q{4l0 zwAHKK 6нKDbsJJ ^.2UZ?O ,xf4#ANCWԲ%ZQNqAaSNu?S ?bcxXWE5`!UB")2"k_}:2oѻM/Q1f1,lJAB"WPQa>î{㧪{<&\*c=`‚**.b*bQͯ/,(ecQŴ?+HϴuFړrr da&8Nxȑjs_ܟ|iժUjdff-<ΝKW_}*s&d'HzcR`E B`𑔒ҋ|բ% $_%-UuKݺwSTuz?}F죓?!i+0[+֮ZC?t9=飴}V:ѿFǝy󏧨xÕY?oACyxտ:t( <&OL˖-#|>bU38,YKS @S|%_1{C8] V i~]J1D!lX2(q "K((WӖn)4܆ɹD &J{CZ QGLSC,-_=<>NvQޝ\ C:s4Jy>0Cطs/g鈣gЙ_@GOoOUx$o}_J充B06^(gϞ8%K!A4tà ЛoCJHs>D.B]ruܻB._YF;` =6UyuzvpWD}.yz+u4+S{9d1ыC|A l4xUWZrM0ѭH_cSBC0k׮nF,>ߌ1xve+j 7T-ytRJ*$Jȣԝy.:wJm{ UFͬ>MQU߷Vڕkhw+D2zbۣ.b5zߛcDjѣ:wnoؼwvPܹZ%|ϓ~Q7P /}] 7-ؐga?}#o*X@T^\zF:H;}cAkڪ[Tc#9l5Cra:.RuX[ή#V۶m͛6CϑDzD@ z|KOD\ *(mEҌ.q {{$2xׁdލhX8z!H=!iSv3]h4Ώ>*^^!2My+%D{﬽"`{&xha\}KrGGe'( t> OzDӗ.&+,;we3~]gtQ#jí*˱=xv񫪰g^Է^P{E@L f:~:G}~auvһwﮌ ?&SU<(w dpTO=7R/A^Jɘ sZktQFE*V9z(uMipks<%wotҔtֱ0půH쟅Nk=MJUV1]:4&xD!ˣ2}te`"xE}VI>`@Kt77i {CP>8̙CTLD|6.~i/4eKݒ"i޲5ÿQԩKO g!C3=kt?Iƚ%~4&R!Y]&%(ӟG~Ôtȟq!A. +BP xzX* yNsL.[ڢ;h!t̸nWJ/Ic_(>oF}DݗUхWx|J#fRD|/"%J莋SqA7p, w^p:aU7&NCL8,XSN{Gg5?19=Fх8AaLى>v ߗ|~ h&Rav2ko=@=.|$NF:$''G}cA8{:ش]1qR 0ao'0#g7b7!0L(F( L(.BGw PfLFWl%ʡd"(' (K/v2#_:>p xCEeL ]xEa?^xɱ5ITorjҍ?BGw@z@p4GOgb}C3pK4/c]mHl/(cr=ܣUQ7z"ǟBސ+oCFղF-!ZB{E_ϜI M3h]ft MkؽZW4A `h Ƙ4= `0Ƙ `01&M0 cLK%מ7cU(A"P>sw8jڴiA?p;>?~<3٘>.rgΘ1C׿9* ٳҕWfHlc 6" ^K!իWSFFߟvmImL^əgIYYYt9/B+Wl1Lj_~ֱI|=?wj`||Sd{$jcׇNp&^d2` В8p;ﭭ?ꪫ~'s /Ϻю?j:=o37<]s? z׿;gH,6t 枞(!)wqjN!̛vl =|*|뭷)*dŋIH#?.] #6ľ\ۜaʁ1B=o ع瞫s'*v썣o uB8g!o1 ϼvz\i(3oVEvϚ5Km|r5Ofe 6om>28ZУ_PO\W/_?hBؤ͛70znxz>̆dPs{3}G?D-Xl#co0XSLq 1{NaoY֭[w>C#VZe>7xAcИ u!X64t!#0@磯[:7D#LqjBoXIxeA.YdG4hO( GzsQ[h#ij =>v Ћ xzlԄ_⁻n4҄;bPU 6lm/lHFS aPHHq?t}V}̙3iܹj/z.NG}tdIv-f'*[%Acc.ZX3 N0$/,Ykj\>>b% e]z;︍>P= |N:Hq׭[XQرqX_~}7z0x;-8b(n%͟r HiAԌ*[♆x'{}l}\{{k9a5.-a)[-2+sB}:,#T}^cB$D> DMhU0 qF&I^'&LW,=^ZkS7:lFrĉn0$wa!_w<~.Ѐb~?OB6rCJ2ݘr6؞3F0i+!Nu}K==h׻Gc0 KFbe믿 +$JXi5 |BrcXg| *fX c|u}Q oxɐV AO}-a7|=ą m %⦛nRb\mf*|%^hKm V? `mS[/fŢ|6|p5"/*r5TwO='wzcao߮( ]@ᗞ14{(u+qEx@]yQEǃ|Թ-ک7E/6cx5t} OKq8%u" :`( 0(2H#nǞ%s&QKp"r}тշ?ӌw.|Ǫ9.Za] 3ݷ^;r RBR҃{ᔺy;mOJM)$:2sJ)DMDqEՕ4iHu(ڟSF,oM=|8cr+&2]]<س3AzQiiPhS2#<Wߧu%w)22"ZU1]],' LKɉ)7;1x=hl0*i\5\-03qϧXyԫn 4}t}.G=FF@mM~O~s1КǪ@JW5<4I~Jtt5 jqF.\PtUĒAPEEw6To9"é(3IKvPSEe<SF%ʅ3F>CF-] ko,njTs aҳŸO.Ѧ6NFuࠀ@v=jV٣+З0= )>.vPDX1uMHwdʩ(*).n+]yyL8rs)mvz;0gt8Z70g3 ɦi4yғ* ?6"UUU[B[WAuKOxrT8`8虠z5wٽ+s#Q\lgѭϽ9ɣ`t870gT@b Pc(}oRyi%uVea*)! ^a qCdQj,nMˋF^]oQ15hcE+@+B x|D}n*D5O7J!.RHǯK< o9|=߽{ (m;oK@IDAT_SRUH;wQˎhiFq `xFԜ 6d|hW>KCYV$2ߤh gx>mb]iͣN; ўхх Ϩ3INN%QVVyM0~2iy sTҰa}>gҕFVY`Vo.FuhːE[_lx血3+׮ɼIO(waT_»HjuRǂcڸq#t> `tHbtJ@Pх 6&dwKJNF#wƩ^eH\E߲뾲R͛A鬳΢uD;x!`tQ60h3ltQ IzV9qڱ#p2$ bxxUY%<9ۥDFĐ`.N2̵i&^b\w @U;raZ,gt- Mo1l, r(9HhuiL0n ]E*-p+OKK-kccc‹/JE!g.qiX@ݹLt[/~^ṂDټ)'M>Bzv\>:C HsC?䖛.\cI#Lj{ {u <Ύ?#_kƉy@0mmt{(.0kLPMhyt=‘*~Rzt|QyHOϺ`ұkg1a0Vb1h%}(3Aa1CR^^0_||<-!b9~s+y酗ڦ?]V],H7Eӷ6-`|0111!.,1;廙tLuǟBwU^xE}L*袭_E檯.W L#/w;&ưի]%`tatE_,XocHF̷ F\FoeG]Kcb$n .@ٷ2.|é5ڣ.z5Wk(Քa0 MGch$ 1&0 #`I14 @G Xڭox5l?5‘999A%m@lj_}}oA;06m0Y)^{- *ntgۈ#h…nK.ЃxToO }7 |駪G/@=.])$ 0amٲ jԨQjS/ Bߩ].OM7D={TFCBH?AW]um~~>y?Og<$KG <؎?xO2:;}t ?3 9I/1Dg侜={6u]uhΜ9uZ#ƤO>tw#@CGgWWW /Px%mÆ pblR3@ܹ3رzŃV%=:BOK.Uw4Mۓ1饗* ]^xJƭJr0XNT|GF ̛&`tovU]܋\nS0s%^`P0J9GyaDx9ˣ{NMC?'飏>f1_8{<)Xu=o^%7r C~[-RaIyUaZׯVZep7J bc}aanfw,?۹s*{*^8NJU#O{?aԋa~9**N? {k1=h-R6tǗd!]s/7n7?w%m4 ]z@;ecH{b A/ :H "c;m~ ujxB?UOdė{BenK⹅޹,_UzlhT--,t096pC7¡ZEMt+aSOs=p 0D_0Kla֗ٳGØ`/ȓ\Oj/Up泖,Y^H C^ Hqxn`WMǜ"04PCb1GlLc "豪B[ۂzk `ۀLaB+1Q09;MSwD)I qĨț+wΚ5k| +\7=L W"x)@KxF.n>/u;e N]cb+xG½dȅV׏gL`LG @Z0 )|0]yj.zmL`0ъ+^uFatxP_WL0 H*zd\ `?yM\xk pj%>ʼnodz$RϏꄉcǺWaŨk׮^g=oG C o{OkLc8\Zd4`/ƍ# 35*0QK13k,7#tURRBW\q;=!8k[\ەҼ !7l 2s)#.+ikt+Y87b|ژ[V0cX|G|ѵRrf(awwA<^,1!ʶ{~M!L tk a[& C00 iXmŁ!1"E aԥ-)I[c6 !`n8ے1iKMA Ww9F\@O A `h:Ƙ4C# `0tx1 `04cL`0:<ƘtK`01&MH0 cL:%`0 MGch$ 1&0 #`I14 @G  @0Ƥ A#`I A]P@Qq Ṕ_PBa!ԣ{gK}>i0/g _J)SQfҾWOS!A0Ƥ1J1i>JݑEQqcgF4 Б0Ƥ#ih}6nJ(*26lѼE쇵i& `>nd_nطoCChԨC!ϗ?hZ|8~ y4ͩ;)7'Rd><*6~?v"JxsrG_=p3ьrqqD~T](?aj Ro>k45A.1/`ʠ J25l]DfҤq}oMםG}zpCsG5?qLPW.Էw2)/5 C)=^[xE^iĎ1&V5S5gbLI@ΣǞz"""SRѕN>*-!s"WDڗfSbx'تP%TZ^Bg߯Yac Λ7N;4;nPZ[/~1Yl4bcbi7 r2$.ZAӧMtD))).Dwڡu HetaG9l6c9&x3MC\@9]3X}TDŽkH'I7.99nv4ad(UgRRIÆO?zJ# x}֏c"[;؆T_6x XI{w<"еk2o{%Jq1'CHH(̥N?z4n^UAΙ+W =ntQ pM";.˘pτW/B/Ֆ,`Eܨ(K\\q,aGR1}(csKڶ:d!}ϛ9տ9t;oy- /Ba]PKJ47Rvv8pC=Ν; /P0AQt: TQVK|y-(F|۶myf^nFJ] 5s_4u<Ƅ'}=Dxr;wݻSNNYL# 2+\FĵyȑaAN0&[S*CNK.~&q282-u<Ƅ'y*đ6tTXg*++cLoN:z։0zޓI-N:xfĵ//u5"!쪚56oL;vai&heU0F|Gc"[NnN)cь X_+ȡnzݰRӶQrr<ߑIƍ p(VZOKKsK^|!]uU@{O>s_xB.\kWBC%BISƀ@r-1a$Od^q;oy55hݸƌ@y?.0ΝKs.E:% _~t75W_㮀х s_x.j!hcRRRKP {cyl8c\#$\q'UDFd$fb#ka`"+xM. ?w VCUPC|^w՟aDS螻c= :5m:I6&xԭ[OlZ~* rZbxW\@j05`{3r}lX[}k-;G00,CPa xZC*szEK 7z"/Zuoo"p4jtQw|mZ@a!>l=? qǜ*WyW|फUEœ?-=ft 澨G[.\1A5S?_.zEΐ@/w"$^]ԁYhV8$肷jy~!)хO0 ES!QҘ3I|[U` `j h|M!A c36 1& SA c36 @|ۀ/  og7t/-lzI'$͟?_}얒J8cڴi>mΝ裏(??zdᆪ_~m=TX 3 ~mԆV&::ڱt;~LdZh;eСC|` ŋixF;ޮl> ѣUx}Ϫ4iիixe츬+W7|Sֽ{wjy?o$uYf [rrbGz{{V0W^yEׯ_z:kٮ [K=Ӗ|sgS`aGu*5k,멧rDZ^w!ϤI[nőm„ mN1cN:-~H[llm-9,6֝wi=sM7d5o=V͎GKXjz5Ż"XpAtֿo7VXOE^*J ,fs9n3s33g9S{''='(in\s5֭[+l;ξynj+|N^~&:4aӤ$QrUyVYm!yԮ];c)tʨJC}}̂ô}KKwp9͈QL6z!8FyF;wzor#fkbhPܐּ:rHz-)SP .d Mg͚5j4ˋnN}[ @/wؔvn^?2f *+,;nJizJͷcǎQeiU3AgY-q֬Y27>|{k`yO'0%`aCmrSIMM{X#)#H+Xꫪ &<{p={l>}2qO٣5eJYj]|ʤu8ӧU 14i!tZ3g$;h ZbgQAj-0k꫕E'|B]w4/LEx3+z4zhbMwܹnFeE -X@-U!.];Ҏ;\1CyW_}eVU/-HtF1p~jӪD`,{hXbjp;&K@cunVBϰ |aC\fX=Jц?\Cpc]+W*_˥^4pT8T2MhĢvMm*[#{N E>O 벱9O5赁/XؚPf7on6a:{GU9i9 8&%hÆ ӷ=Eyׯ:yqFШ>S1b ҕW^4ZkMF(_A^nlkϳ}haeZ{3P6mT1h`C۶m} }U8+㎮ e rWA;< D'mM~aΰ8z?>|X9ۭm*:~Z{;F/M6]?3scuh-G"̻hDFqGV u-orrroVLҒ{vS EQƠE@@P{`qhgzYm./|LzR$0Co#0JLh`B\ ,4> $\PU{WYa@~pX+lӪDu] iГ&4p77e'<_qPqC(.ϣ'UF$[ yH'q A adOiPODP ܹ2(yf=TV?a^7Y֬h we=KaP?0njmG!W4g(7ҹ3}oU1 !Y:FM{ҸWUb̈́t"W)AFS'L b3Xph4D7hJ3.~B'%RN/2¨nZjIZm8DO>E1atH*ErGԏ8/Z)`sY< S~WzZ:J4:xڣʌ(xOxa\]x%4gn&Rt ج B>'QB|/ hH!HqI*>DE9Mf@nZo7@Τ^8fJ3ٵ {n_j8GOpǴ\ڷ2ڴvӭ7pe|w%ÏSVQB-r4)Τb#S&l 3~:NixQQJhL@Xh4`V. &DwM\q8Fө8']G*Pqn%H0:6;ߘm\Ip C  P1PbTWD xX [V$eg8*~RV eg'o=Ëy Nx!/yfI"L^XaO>-홬|SE7cK t,eA׬q>e3~U0p1XHT}:FF+wz!C9y}G5Orx*pÑ#K, Wf7lX{b&:xm%AF˦0Ng'SÎ]WӞ /Uk3f- &.VZ(^T 6_}4v?JDVY5RA‚(46I&xx h/!Hp|&X㹋(H2MwbU1!XMLdNm1I 4lh?_e][\xa<>%wז"c-D5+1vjj(_$,tR/ba}f8Izi],yLII^>}y&rC`(qԹc+;8( ,xᣯՉ?/d#\|w< SټtJB:eQ|AHPPԋPgr6[gϮvٷG-F=DRh#y5Kh~3h(y<˯,Lnx;*#t,5J ,X`;LdX c<;MIR/^kӜ=he^f>WI5 P:Î) Qz (;°Ӗ[gɊIZvTAbxϒ%U+H.$<Ǘjs*W6&0%2v$ \J0gxaܡs-1 7]h ;*;hΝpB{X`r @ ]n4*k PvEEEya;ZQ%ŒewW8N[ .9#xh0f;1;P/=MJ w^ڽ{7:tGeҮ]駟&ݤjG{rn]6 I2nAƍZjY?" =,x}]=W94?2@sk> :ڴiC_|Xuúk_\O?63ׯOzVZuxehɒ%yn+V]F̚5KдiSRءо[T!$))IH%#'' ,޷oKtwW4z{#tcݺurM vRvvv {n6auVzG+U̞=;#6LW9C )#Lnv;w&9}3|&'']lU2رcyyyða5Yo1cƨ\A~@IDATlpWӖ-[0_r%;z}O.WVgXӝw?ַ}>rHz-4ezF!W$.w׆Jl-L;ww!oо}{O}},G}HzЪU#r\x&{UZ9= r3T=M `7p74sLjA!06A/~͚5SNUW]aգN:ѯj ^}UըyFF k}ݧT_4P5aeU 4i0(d_| 45_]]7?|Q03&OL?%jg~-/l Kv[`?l-s]hjh8q2AD# +BYq=нk }Y%``w iѢQBE"Ax_~EU[{衇hԨQJ%ߩnݺg *'oΜ9*ux!/͛7WvjP@9Ċ֕]suF;wU\}]<޳dwucAw饗ugi_b%l޼Yeg}Tf6>S1bda~ch /zw\soB[Z^*#Lmۦ MgϞ^-ێ l .8آgJ޿3o-4p1 zGI ] &(ͤ[n /^8сT =Ç0 A_CSގ@Y[/F(|yթSDzj+  `# xo["3G@P?sk6Z@+Rfp{aHʗ+wX`2F ?`Ѧ=W;OMPb:"W|r/qFCw|_ 6X0`^@` ~ywtsoB*/8 4 ʮ]*'(~ f>x;s (ѓ ;Lm 6 &}!m0*%Fv }#/ շ1sX9"ٓ~=9u펖@۷o'IcҚ!Eː㬌ṻwu<ք!XYV wGA:^HT  iB"F.#W|rLjAP|M0ڶm[KA%ԋ/\u-"Xg۸*Ma#C#z7W_}EZh ثe=G͠qa0$;6<ACAϡ0\vg4gP~{ vh?fJ}VuT<d|ǀ~ uQ!@'ڛ5(=g曪<.Y}szmr4 'Æ SqUj' F䭷Rmf̘U0"!i Il+OCDc 1*zaл/_J(0jr%z'P {ɺW!8rss &=tQ72aŁ#BƷBoSwa $k;b9%#? EM4vhhغ7B!ԅU:BۅƁ4p@U@#T0O&{"<ϧ7ӦMS>(9o] 0LbMާ1iR;⽭:;7zdywwUϽ 񕇂f04w׸.ʯoOLpT&/˸m묡5L, K WsDAtֿ%8#O~U::]}7i|qߚ _EqT/e74ܕ/_^hg,|w_(ώ BV{0%$ P9abG(  P(〯p  &AMA@A@ r! PD5yGA&6pȅ @yaRA@D! A@IyPwA@lab\ &AMA@A@ r! PD5yGA&6pȅ @yaRA@ oJk֮SMx`މ/?Yi>W|GWL0;[R}he"IL.CW44К1A/?a>8|xa­԰aC,‹T-&:vO h?)<,R 2Ar _KG=c2q,&:px h4bv_~hQqI#\Fm1$@Dxa /lyaXa XۧLHbR@aaBGI鯺H}%{ X9™_;Y^X -L8pP!7Q_  "ڴ~ ^JSԮK"%6.Q4žt]鋏АzRb7\hJqĦ<8`I O o9 <#}XU!9n5.,,&UuGxaanш9+NO`jؘwMcGNӹCzR˶/>ZJ#8M"9FKXKPn^gQfV 6`ȅc D ȋX#a{3$8L }i_X"&@P96Jb) [^Vl+< &-RS˨԰Qѧ=-[E'й%܅-Xz¥m:|f/f&SFӍ4b0V,Hrx vQ!4~h_mmd0oKU~.hBn^oPmUn*.ɧ-X3_BhOXvsESv 5t&%vUrpGfvT̘8K8ˁ/4U+ab1\g2w۴:ޱ?u8s?-{(8Vp0/r[7DN3KH6`ڂ!W0;1=~^2ԧ e ~1G7Sڿi' ڰwVkv=xԒEѕ#GP҉X{S!K'-w^R [ +LM_M93K(9(ڰK [[n~g}#X>M+'̂V=.L Yh$Xƅ,LSc;ѝ_ZaFK}c**QB)԰y̡OEN"o=A'O'1Ab%Ha;>FxaabD7lPGs_K ~6JuXEP.;rJza,L>XV%D<Ͻ`6sVb^*ō={ gs[Է`[n2'kSv|B)Wh7ShGJ#AADIY^8Bj /lq70QTVN{N :{}CsGV->lu^\͟?.2/ި9AO,d~+hGTH?o\B~ m]sY:Gk/P 8ZjE#1.UqWxaa 4u^Q)쓟ަn9:0eqґ0`ּ}XO\y=f^)-q4a~>~޲)m^ryyKhP-k61 ?WHV<-&lr7/^Eg!,'EEy}LP+ ) %//KGr CXc4WҶcsyX,h߫ߡ#әoIAQo/^^BkXDЀ(?fbg`=W<9[]iΝ4iTNN8ȕ  %@XhX7DxiZnO]C?ʀ ᅗUbp-&:jAQ*Thʸx|VY% ׾ 9rX{9ۧ^~=@@99\ ,QʼS'nf*jH Ϟ /<(V(NxGFloY6/kuXcᄑ{n:tef]vO?M7MIUؼ%(bvU9d4xhYgQ6pBxQ.*%-&pGbS3lsm}6@G{﹗ӕ B 8ZjSʘY8]斣GxwOx^ZxaaI hЋh`Z1 k,|ztt48Lh#Br#ߔeF , q ?\DA4`aaa4p@z|tzMWggg䳲uy@~/bQg‹00rrrTo8%%TU3߁ eX]?f͜E͚5sP:E8<<԰j KN?mᅇ@!,Ȇ&`Q*xAe} DFW26; #1 [00񖃲'UnxGM oЪܰȋ ZU. @" $*$ao%=A@&T$A@#.  PE`~y'˲\Z!s96mD֭[GG}DÇDupoҤI:-\/:qℊm۶jh97Ae3T͸qVZ6b(ѣG[o]z ghc-[FK,!C:th?&ߪ2ZnP35kkfq1z޳ĵa/;/G9BM2E-صkW%Px %\,_ < VOpPy5殽Z;}:5mڔK{>ڷoO]tQf4o#!Cl`j*zG̙3sNgٱcGKˎ=JzU1QA-x`)04$K/UmtTmx(T5jD/JS ~ߖ8q#ƍ7*a <㐧8!67on1B4zhPޖuoWE6>CCciM(h̙S *,:az4qDB!J/fAoKs5qA1wy Yp4m4 SΝ}e-=0Ifb-? v,3X];~~<7ow!uo; W^&^VC:幷-/[oejժpCb >)&֭.׿'6qtbٳ^0M<ĝ!= A;7NXBŵo>U_yqOc6 7mZ<u S r8 ?ڵk?x>p@`C+/S=rM:2 +:۴J ӕ&}gp-zzL]&< 2tuTʔo@;UƯ;|az8H''L 2>h(_a~>y$qSEx; _1#A,ܹv/85s9Kd۶m!f`p.]j`S+ ߳? H@FÞ4Q)5!mV6Ќ3$>XmYcO:eICx`'8YGЩS'eԘX?V \Kݰona<᫻:I: S6C3bEɻ^ r?lL LW 5@a.X@ٍ@Gz~!a+lzP~M6$S0ż́7[o.rY?Ca-䢋.~X0z'0J,QwOp2t/S4!Ԡ>wHzoK/aGdn_WS HԿ7xy'!wy;UU7`  o6}駖pr3o t1zKG7|sIl8]p=HHh(!g_Đ6TjTl>xF"OH8Eٞ8v]z9pfU X/8:E eC0E}TbѨE3_| #L*#kzE S -[3eRf͸[:誎+:{ܫautv9 ͡34j%ԲeK<2"30aBǎOPVvV68ķ;w,""իGujס`JKOuI^T/'8J'4Z.T~R3eK ڬaQZZzƒSFF(0Z[ eK ųbbIo6;7V*__WH,`,ڄЬX+_sH k8'$ WRvEt$ ؾ.{."n̦\4NrWXϰ\s=穩)o## >(\ssVt u* g!RN:E'O'NPMhذaefZn=hK(++~7MWZ xVTT#Mi(>D33ALw!ڳs/5OlŒ6WQYԏDA1*>3 U-<̌\xD~5P#_埿 \T HV/}VWb(uN~飺4~@z~"Parq k| PW0nz͖h z(agn,4qDj׮=͛7>37nM|}ͷqF=)VB 帑Pf.{`_֫j\@vFJϔ50qxf a#N0J*sl L[NJ;>d9uVOoZ:u#қ.Mȭ>GCo6֯_Fw{ 3O?A]hĈg^dNtUW3<>SҫJVR h61 N&h!4@l,fffQF:;h'g~@c{-0ÛLE,bNٹ\3yTT\W#H#  Z0d̓üww$E޽XCC3+,pmP :ƎmV߿?]tхtЄ h/ FnSTt$z$M R\Rl"4rs)n DFTx4DZiIebVOT*)n,!Dht̿ [< {&POCh+nAfn¹01RP4EY+PGaFFkL>DSڌi :!>a`\Y[(fcYbщ syqdU2&6]1h"kڶ֭Rd&--DtF_(/.`g}-E*_4%! a) y/TB toڷ@W\q;חТEƿ/ZpSڵf͚C]wݥ~M\6uE*!|.xϸS ZF l"idRFj8m_vj׾ kۅG{+Gs} AZb|Qx!B6/l04gww̬sբvy'6ۓz&80d31H 'MQ ~Uz)v:uD?u+o͓_o^);pC@DF'C˂t/dm$h&ɕ.4'*N%q}KQT,W.MϤ**st3)9_o /K\t:6<gsJC2py!ܒH*6(%vbb"Aۘ={6ܹS|Ih(;U}jV<Ç$FLd\f 5;2[c5PJX{| קb69JeRp֭[)hƌJ4lؐk5f}&]~~XLSNS\yN&p88ILd4dNmC¨YBsa嗴t<ڻuPrݲC[ޞ̟?_$}/ /WM<¡ [C9KRjЈUgN_5JvO_mwR-.yl!%> c?TB!pxJfMӧO'ǟP C soI}6B\[D[N=&R!brreϼ`w-kЉz0 Mß&%Aw/z) _bm²* Ô DDPdd$ }mɅ- [ r&P;ZG$q`*X[Kcg SxD(7gc8PK8@i %L,IBO|Z"@gL A>Bsiy,5z\;6]=1/V b֞P/#6 JpcK׎fAŽzp;@i %Ljת&?r );N*H>T ĢӔSTڮYuᅱ sy[W9BZ&'͗50 Gz!-lmxSGz5@i+-[ny@is$Qc:om~EalLlI?Ms%j4(,' ;AcT`HБǧG3z0B 9#ΐ1G}Mp`)y`EݺtEhmM@aaDJe(a ݳGoe~eI,پ|b׸_FY`AӅ^躔SeN^ h=Fs]B*)nuPWaWGl{{lߗ`"" k{èž}w1Q:y/]L?MDFJ1 Bqr J9}J cNـI/=q4k,7԰ re z-1z* 5חDO-:^rSNʅkNi+όON>'(m G{P6Ԅ*v!K`49oQ /o<5=q9gر6[+RG'g/80 fH=|j%8m20AсݠAuiBzRK/utBe^(w0IE;>BOH/=/20f|(`Fa7ԤI¤F!/RwѣQ'z J W#G00qO-^ؓ`6aD ϠpD‹ C)L1^ȅBxQx8*2 q  TwDTwJA@0"L ɂ &՝A@ /y/iXu˯@A h/>Lb^}מDqFy}v̕W^is`/\/Bbb"mVdGUIÇ?z)dO$0wFί|OԪU+2dHBJY]q9ЦMhԺukuu>"=Bܛ4i+I`_ѣyx#1W^ O<7oaWup/xƗ^zJh/cYeM (dwަK.޿oW4^g_ОQE:t'aGswo2ܱ0!ސͷ ,7ĦGyq,<>X&eyx`b e׿er;ƍڷoobeB`M801B۷sG[X/4w ]]ΐ#Kn+ٝa\ )J{ァzCe{ 7PBBqU7Մg͜9ЋFUV_4@0_##]+iӦmq94ӧO'Ǎ&ٳ>3FW4 &We?\ ##C=Z|9$zjzR#G oK.uرex8ydeckIƮK|,_}팟^DzS!V**ȧ2L/0kM:n6֭G߆z܆OpD/:~x+(b-R dyC)Lz;խ[]ܖ'/=C{}J&q v뮻7.[3?屼ѠUgF ?<h4"""hʕ.饗3LD־ oΝ瞵 ɟw}n&:=~Ě Uz|X cWm( a5\n⧳2Q`~lѢ-[Lr%:M̥&5xF>x&9>pR*%dyq30~v7In,Ϲ ,JvZ}Kz6s=Uwߙx?T6‘]/ wq٫F积pm֒myXk&"IDAT?`wZ?&3ZL@(QQQ'eўGY#2wy`%/6ԹsguaQw_is;# !du4g1vpAUXvobH=7 bm\}lrOEN<| 0ZޖEI,ѓ'>s * shLkV\cGH Ac n)b1Rjҁ;-``hXUyZ/MؾaÆ~zabXWVb>tpc}c ''SeB4n-0L> _۸E@ը#0[\۲*>c=F~-|*k5 -_{0ྵ0Ag$<6,Aœ w;k[B( ?+ f̒]"$=HX8Q^~e~8`GO>"cl첮c$bmH8{,٤7P7ZF ;Mxgy]]\AZ_e0d̩p;{RQQbcc @`vlC a 7)SX3f(@jTvfw;k[0PM ]h9h!B*:&'༃ۓwi;2 `" `R5!?pP܀_=voFj  .;,9@Ad]*BmB3JôN*|T60nFeJu5.=)Qar:t25ksϞ= s˼5 ~S;tz<ǜ`Bn޼YjwE_SoJ >t`rM 嗪3R'˟iz.!P C%iZ{rD 0⮬{̃`OJ~zO_u+oM cwm;|YH3tPyӘ]}>ש|&=$gqP^r&Dt| $_U\챨J~祲]mʢ#~2}o[S;]GtW @.-_>70J\ H yA`Q;Qr-A@0"L Ɍ &ՓokA@ CC2#@D@IZC! P P=aR=&AP01;$3 TODTOIA@0"L Ɍ &ՓokA@ CC2#@D@IZC!PW ɥg22s)4$5Oz* Ph^5^3پ}?Q$6nC1|Oɢ䓧S$'@ @wdME&(u JX:tmAf 8|)dя+)hұsA  2EGӎ]77ZzgrSnH0DŽd=QT|[ kRޭieC-%hÔC Sx 9":VL_؏4WaSS3?(;k7a-IH>qN$'yrppuҋ+T>^xKxaF5h M20pji@J{w{ѹҪ(V= E'S(#+W :n'(Lmv]Tj>խCI4h@'9 籦FcFZm肋L&j!J, u BKGGJ9 ԋrVI/|u2 &-P^^!gRbuWQt퓐ިЂ&HS?(("HaQEQ Qh 5@Hܻwwor{sg);9sΔ H?#(sw>klɡ"s[wNi}i"ܽ?.*/kz5d!H2hE.kr`JU*ZQ8b(=T]] p U0uHN^H iR,5 B%""6<ٞ}K`¼ _JY{<Ϣ"#Sfq_t=((c`Z%?J*0r!*+|R0.v-̗ g?@|KZ& ul׌26MSC q1#з/Ͽs:g@v0K?S"t8xEHk&ՓFO/NxSb8k"MZ&,-h#ёÚNk)Ql #ئFA@F yOQA>Q^WI!%~[Ep!E /BZ3A$kTQQœPJrAzlKI TRTĦ&L d2rk,PdXMel.+cB@9}, / V0w |IUh7]CłLfYL}bV5aSNhҔN܅23ӦPǶ UA-[F{hN͚JTts){~c+%rK: Կ £0(P¤@"x.LCV3RӬ{y~C@NmܒMKnq,uh]CF{ :,76ed̙$LyiB]t)ND9lfPkz B. 7v:VEH 9y49I͚&RJV4|iTZVIUH .9MF Eпmܼ;Rj"㣩bxW:wͣutܾ^}.aFikjS(QH.|cP!/)aqS& 2wPeU5U⎫rsKhB9֯DW]6̲d#9f^L]:6)Bˮ(68ǵ6x%/-^'v{CI;OB֖(1L*6s)i"WPȢ< 6,nˋ5Gh<)NU<ś"0EYm#`6+MI0}z#څ7SF?I/ ڼ~iׁy?=¬ &1aR%aN[N&m|,}uN-DZjP^Aع[,;KOyfl^;b +XhQZZO^΋3 2ߦ<;(%%N?83|: f :(vTL⛲`rJX@ I(.YT{Q!0/ԼW&&zxA> 9~0e^T{093#|#oP44Rd'|XB0bx {g ^BJ=bxMRT:(3j!$d[׎+DeռW+p|A;,!tV[nM7Qzz:M:Êj@mwqBظ(>=**MdB5)Eî[K3ƍ9k\֎,zT>+OLOf!x%aa 4#)abD^ o xv Hvg?Єg1Tnvt;^bZzCie<)!8~:3ԽJJJxiv1ayoϙ$u<+KXFȟT<_g55=FT@"v xt d Q !1qao۶i~Ri,L ;&|׸ Ǟ: D8B0''Т9":XW<%<<"DT'L@ ._ c+^x iaɏl4h `•@˖gPlW,:Ah"oHStDw}(uLܮ͆.c RQX !66V\`{ݹć?~Xv|#" }y+/<]xKv"{N,WpCڵ,^`/.ۀ=/T0]@o'L0|NyQ (^ :'xQg@cE&$uNH,ŋAY#/3v*B@!h(a҈P( %L iB@!ЈP¤3WM!P4J4= B`ONu\_PJJ <ث o6zԵkW裏l7b׺^Gk,Yo$ŦSΝAC?'S9C:-sVu4aQp€о@~"?Ps1$#6Y|$K/w}G111t'7nD=a]誫3s28yYPxM .?KGu}4 l deZ(7xեKkՊyt)C=1Gɸ$n鮱W)S M袋4f?mD ~nРAwWP oy _崪x's9Zf4Z~~C:O?;SO=n} ѻ[9VZ%o~z;> ];QTTpš_o{ V]h|iw}/k7|ֻwoYT'M1BٳG?i/C#5}tw[o~WbFvs-?,z6yd֭=sPx7|(QA3|sw}nF?F'8#N&pgmvЖMF~;aF9ѝwI9B{3gy%N{UW5h%<;@} (3}_O-[M,9=zІ dlaxӚ7oN<$|ak۶-]~t!w:vO<#?Ο?/(̙3iPZZL2^k.:~AxYi|ɢ!B-ãû{?ki37#4② 5&G Rzz:]ve Ttyqʌ3s.z3f {=?~ ȿXϪn$s6[I Ah0KrZFޟ뮻FIźYauYvIdu|Ns犧V8s]^i+L֬YCo8Z}6lج?.:tx8A0hhhpҊ&NNn?a/!@Qp>ٲe˄v9 *:&I(3Fa۷o'qԩ˪P(>{6mDdžf1+ WSSSoB+*o 4<(IU-`4YBMtHb_gŊk[=g qs}caRqvYsNH_=dl7N3ưÌntOٳY;!@ZS$u #;bg'UF2:LV€ꫯ ~aSee k=AYL1a.F +iM> IV HM`E{fQFŶ#,G-bZfqxÔ+o}f^w\a4119y˗/I=`,3^v--Zarz NN hCNI>d:2 :ghվWK.#̡ _XA@`=ZaUs0iӷKB4<&Hf"|d eˆGM{y}0*~-PB#r9:'?Be,49cAV?F@20Nhrh i@3(;6P`e6;1}QR0Y*..&^F,4t0i`oFrO#꯾JLm_3+60~ĪR,ḅ,X0b$2/))Z<X|atRg l"T v6%qv!Uߨ 8H IJ\0i`ӏ/ BmGõ^A_p A!֊J-C) o2v/C&4O>Ľ.o2>+ be VqaQhu!ع[t(m Y{E\r; s"VMf ڋUc?m`S ̥X!믛WM#J1PB 0o"+ `FĿ|*}Ǩ'T ψ~ٵKMVN~D6.2jG5Dlcfucy,aaKOi<So⑖87#WB ;JC朵Ӫ5d^们&ll9m2m_u޴j!ؑ/̱46\fd,؍3 <`{qvy3U^%q2 _y0oc<_f8۱Y|_,3\VsLc"&Q0o)R(BhaPO}JRD!P((5 # }YB@!ЈP¤1SE!P %LzB@!hD(a҈P(&B^W!P4"0iDTEQ(B `eBW!P(\ G"硧gRDxؑ[sB@! $#8 8(P/U( #8^rIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/desktop/images/frag.png0000644000175000017500000000301212346515434023403 0ustar felixfelixPNG  IHDR szzsBIT|d pHYs : :dJtEXtSoftwarewww.inkscape.org<tEXtTitleGeneric Script(tEXtAuthorJakub Steiner/!tEXtSourcehttp://jimmac.musichall.czif^ItEXtCopyrightPublic Domain http://creativecommons.org/licenses/publicdomain/YIDATXŗOhW?3N_0QSbFCKmi^^z,{/1= \EH bOl2&͒dwvvdv{3|ykhe~Qu@֟}QJMDkR 5Zk<ϫVJxxW_W*gϞv_۷Z#D)a5} àz۫,uݟaRD>G)mxW#PPbYVC5A?Y[@U}A+'Z7TE>n&9Pq7 rr)inua)= af,hvM,Ah9sÇ7uYSК9011A2ȑ#LMM͛]wle/pde errwʯq?hootvvr5v@PAJZ.B:u qի6d\k]/.`ee0XYYѣ P)@'MlBpAڰm-FFFӧOOW lܱUn``)%5 !x%===8q>666H$8pÇ\ ;ҟT,X>hkkc{{!NJ>|xcxx |/^I<|rl6KOODu2 RJB200'aPR(x-RabǏyB! B#pBݎ!lUgϞݻw lhs;TX Oղ_PJzoOu IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/desktop/images/lib_resolved.png0000644000175000017500000001016612346515434025145 0ustar felixfelixPNG  IHDR$"7Y{ AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  iTXtXML:com.adobe.xmp 5 2 1 m IDATX ͗MLA-P^4D"\j('c7Lc0@xZZ]LXBw}=gqsGPR _Cf5MR},쨽m;M}ue nzn b`:`Ci/}11348M[dJ"o+%A~(T$$>ef f)&x 6 kU(zCTEb.Bb(Ntk!} U'w fRJkW>yB6'L~.SK~Q.Ɂboݝ<$[V6ޤ@Me#wAhMyG_"p A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATxt]u5CoI"ElnI%qlIt'/JJ֟%r+%R"EHJg=<@DwfisfsK$pfGGǝ]]]i0b10W#Ҋrb̐gnC/SKNXXT4C , j'x82+(䤊ŏJ+NE3pb̠v?2m##Ҋ3a$1C+6?+8SO3D߯/T_iӥ_:Yae?P0>LSZwҒŘAgӦKѬ1koo's&/02=Ue P:h#_Sjۅ_tz Ta qUר{l`QrsHO`)3/?s[1OQmq?VIgsrrkmmL-0f6"7Q}asz9Q54_G?_t8YYYknn`S3)I}_v:]cՇ)8Lg!jO淵ҊvV:jOok8jWNǴt}z OҁI23'G c=Tcw&PA=?A|Nz.>AN'ߧ>cOߧ KyI@EퟜInƖ}ǑWd`̘ Fxo׷b<7^vS*i&yUPQ{oT? tvaTm5r͎=Y?Id܉#v54F6>A$N'ߧ>ce y ptBMEO2_:}Ø hߍv9(,)CP>z,N7^McH`i(rjW.ckՙJSzd"Op2%_pO$?~*}W2'<+˴Uρ~~,)S'EX q;|F$?6,=P~%O(wØ#G`0eeeAeeCwQ塠(H|(?Ǐ~a<|.Շ8H@xaaz:3+p%Ukb1=1A@C[=CUN#&Mч>lۋ_qøR_zX2֣ Ot)z-l;ѣQ#Ze xgd,[&a9D]ؿq)!Rd=ԁQG!|k_:0eRfTA6h[><òzf|8y$؊?^Ξs(iӲS݂0/{?ÙWc&qEDR0#< ۛhއw] >@|,M(]K`^_R7j * :}yb ) e+> )'L/æ%3X`a:1,S?h1yWq']azd+> OtzL2 < S:2.:&pqIG胰`L@ʲVABf{,}v >={9N"S#  Z'yxerӧV^ T:H`[+&~)ÇqE#\`#-X|_֧ UéqdiE'*W^:^Y4]&姃t“,?H`䡥1VLK?_U >.%pMt*^lpEkι~Kg| {tp ?ـ<gP=)?)቟ʃ.:շėi}u䤺+/xiLO|d#Ң/E'8R"h4rn: ,6mp'LS& wL81%]Cޙo>{>bӃ@|S*XQy2bKt3VYMa׏0 LrK|$_pYg_`E~(+guJBzxδoO}$Wcɕ'~aZt%:7XL}.=6oW|GV].fDGȶIlwacm];VOٚx::;m߽ aN{qL2y~2ZNv}<K;!Ӕ9 _-|fW`Vq3וq3u/oFVPj(2~ChJ%|{թ%USOͱztJiGU1#c#ADW=X.w.&ytX|}˂ηC]lTkh1=l͛daćқiQpѳ̯' Yvkq(@;N_ N yv%"w}.:ݵ(cOܻK\\yN'|a=?ثS=$[ _dNp*룯%!xHlȃt GD#+ =dB0䣠p >_K'&|%oOi3~!b™'~~y _U,wHX&}ڿ~3j'G~cR$O nQǏw{Q9[!gl:ʏ@9<'^ W,0U4yCLׯ1f nLc҉V#1!Orŏ>~py3_x?WZp/>e2|̇+XaXA0ɏ?Mo60ύ<]E)-blCkkqx~sG /פހ7U̱6 7z 'QN>ug"΀2䛃uexmlm(4[a66u:uq5gl;lѴ |kMXl$εJd[~Ͽμ7_877^>kwA#Wgn3]ql^aųS?Ҧk1 شo-^xv&gx#.?7R,Dyga¾V: |9j%g̨/{[0ኙUg J+ֶx/]WNFfWPvɹxYFd&n26۸w-^z~14n oskceԏEokb0l nJ>p%6xobw1l8u/f'"ߋ?ygo`ǍSo~mwλ6̪Bxk Xaw8 :cӊC+Yގ':^#L'Ɯy ^2ݮ万8ӢSYt4{WmouX#^;9^}W~~$;#x6O*Je#KS+ J3߁$Ʋd0VX2 1'c∗cZ:X&{ .,cǓ !9eJ'.bҪi_X IG>X,2GA,y\eLL Ƙx *c^b,rh2Spd>d,j޷IgvFv,KvlujF!mMjoEöB}-(; W,&8 ^qg\}'ı}Xďqǯc 汸Qp}xw7ϹsF 鰗J`<ͣ.=6ᅡg%"&ږζV::ޜ:YY5u\\g2<7wv8]hq-r48XQrFDڒ.z#^[o[OLݦovb߶坋%6Խ,:;Y[ ;;1ubfw>c, $[ g<`ps&y.8C]xPqz'>n|6m§4j36ΣLp_DMN< x vf1ZūkpaRq+\CY_Ggc}뎩Ncea׋QuU8sdh; < eӯ=+Oam?"a8 XcԌnm x9kß ߸%V> >440bGcc)vLҡkmkʗ^FkqֆO0}LwK1|UG'Mq#̾h[%[g0y!ʦ\>'k0]mul%Þ +/uyX\?ۘvɵeD9KCO`٦Ig6 -E[&ja޹磨}3au΍R,\{98X( 1fyֹ=VSZ ƴ?zZe>{g̋' $e0ޱ-;+V{mWs *.C(\ķ 44ˈ2<Ӄ'>k0H/ZƬ__)/|tP+̓Nyń,UpbFa8+YAy*'~҄$3;O 'D/ZE̫嗓&,~8TQlR|.ٕn9e_uUk2Ξ0睍RնשּׁG[qɔ Ǭ+FX|صi"a){uf .5oۋ&z%K`196&4.Zl7}HdwXDsph+O|Ѹ7a1vxIJLBݯGU#1zPZif7N4^y|)Y3SlҊ\Yܐ(n^h{ĮCM(}kW >?ą4fcn6zDg;: >le.m6am\pn]sgJnm3(DW^F]w,hc];-W%pyi!OmnKQfmeյc\U֌#S5&,t }US.4^m97:[f&#{|h9'b=[k:-1 ~RTlɿq130mh0!/;6]1ea-JPj%eFRU\qxkx:_va%ƍ*Tg9ƞt3k,'PP5#s\}I+_ #cѦ.BfˍnX)؇e`9|\LJ>,Up״oM>iOGyvJ|{r0-7˃'tAH7 .6 zL3 T.ɋi3A0Ne,ާ,LƔ뗋$~1”J^KmkL3ySʔ\~zHO4IIɺHgE퟼FegIvm G5druӼ sœKz UKblQZ. ޙYͮ"L@ >]#ж{fD_gN V_o^؇۰QnXNOrFδ`^k3ۛH'N/yFD8| ۗy!]l'+mo!0m߁UmPc`=UiK:,93'Mτ}2m3:3) p6wee)ڠN]Ma̅gVsr͠hvE緳u+niBmmn cějvJ&;t*(3.6f'v #-#K\Q'mK{Җ\U{o]-W6L$Z63͈UF`#ԯLBn+j7y֤~hcfSL.3x,o]{taVOyUAՓ˲,fS̄ ?gm=qMSSF!3 /1܋O+$%7ҋel={Tr&SD˼ҾL(/oIicb/)ÕA#C-^4g:9CׯfO-yM6kD7<B8lp&K⪲cʏ|#-2@Az㒷x2&i+zщϗ<!cOX`üCL)[ w4rdWN%.3:=$orT36cqsM.C"q Ry(! a]himFI|xdi-}fTc۶Mq4[>)[ڳ(;-4kz杆k1iN3y578CmQ0:|~Cqo,rƶOgح%I[_ckHCK['dzANYMN*}3-g߿\CXkSs#F&q[2ΪTwD!C4how}\^:$S3-˜1Q G4*}ק#- _sOy_0: \<ē1ҙa,< +L|yVI?Œ'炶ml̘?ٕ Q'c5&̇+OźV3O|VN4a<8U׿{S'S*466w al Y&]|9ӪJF“3\eϼty_t+dV4-c.^Fi O%\4%a X3Y.ފ#Or:4iTe#IqO ßl/0ڟ&cH s u 3kweºU7#5/b㶒;V,v+6 f fF2,Z8k¨c%}Mڠ8)zUdz|cxPiM@y7^GURnN볒8"W??ꬾV<̲r_V8VsZ❧¦,Lh^dXvFcs+wa&6L^NHCxuNԷnhup:?ՙqN(缭W /N+Us敡u3xy3ؼs^:5wHsÇ;,ϖ2h܋smEbdl}4kkNv|+ڼG~d)s0}V>2G%+pڱ͈9Յ>K_Wn%oq0w/iڥ%uZKm/*,t,(uRP?azچ' ?Vħu/l`Ê7͖_UA>캄?XpfY>挨9 N3:vՎVcˁ:tdaKtTWM!;)] k?qGQe`֙eeap⭘,׽]ݴrѪJG|0 ۩ hyA>LHƼtQ _Ir??s}맶 Lg\GpEKҤQڿgɫbߖ3f vDqq s'xgʯƖ?ȇc| x!jF<%9U兯X 'ț%LV9cvI*&&^2t*#>⡴O}=ϓ~01fLы/eԋ!O0W,T%pT ؽyƪGee+>ؗliUϹi}Qr7*lyaQ.gb }=3.c/u֭|̹vi,y=٦ɝ/ᡕl״X;PKh4W7{Խ}Hmz]zMyInl̽uq52ܵnUf53buqM9z>jaZp}]]q\%KTY}y(e@Z6 h2gҮXrdM9|yaJ{!'u=h5i۾LKO'?& tR1|x0=t>3/9⵨k2ff|ؿA"e34v@٭w JJJ0VWW;v{,zFA1qS2)HA25##~`'QƢqOtuݘWӄd3Ln{fv.lv-CoH:Nso";f"pl}%CEow94ddѲ-%|q]W2YspZ<۾ݗcliʘ8fxfڻ_RMMؾ>=y\rH~vmD暂6sŸB;,ӱf]E%''˸4'^8}(('YN9v8D5ۦM gMQ%"Y>>7|#]i`;՜.ٳv-uCnSYf,N,6'RRO"=}V\{Y sX%7/9N\vi|z^&[QW+hQ9]S9:ੇ^r[VDnxE߽Ne=ϛrYe[X5PX6ۯi8ԉvɲ>H[sv]RF} -NOE$Oꐇ,ՙqPe2ČTFNYQ2^M|EFلq?/e7QoDhC*vdwڙ6f^=+<"?#E+=qE#|Wʳ*wA^,s0%g|{p,. ߶07aԇ_ǰ[m Ck[subϡn'Sr{I6K|]i6|e^~$Z^Eec^}d쮻oc‚ })hف0^W6L2c iZGL˓ўOAmz5m-T_1&,[_{')vR%1axj`L}ãn~=y~ڧ0/^IG)&Ҍ+̋ 姉C O4rpF<}.c|$˼{gG~UrF9Ji_xe;Iw~ڧcZz.^ˤc∖/y`A4qēpR|3e 'H#A#.c|$oΝ;գFd#@1o>0HN4i;:Ktg2n`WUIg %p\A?r |c OHTNC\YN|N ~)\/aG03.ʳϼ(͘G}< >ǧӲc&i z__.~AZ~LW<ڟV89%ӧkwĞvx0QNn^ȧ*msؿ `*ԟ)o]$؃;PO^K?,9]s{l/5DWcN'xim@[ɶˆ@ڟ< !yFO+$)Ġ >D2g+ o%ήx &C S`tSM複`Kx(&|\_p|OKع|T^t[eśi1-=DJ_2A8ʫLX@x F QG>~;#\%\41}&:Cg܃å{|\_&T&KpID5NHo.\떯&GJ%˙VV>.it]1-8tWbPS?R?U? +/Sq'ocńS7ɼ_|tL`GUEZݧeput*/O>auwa<}>:o%өxqYfg_2R8G8DŽGO+$CI;0˓q}_0|O*Z£OZ'jg~:U_ ˳,|-Ӷ Ct;3SRD ={-};s{-ZpTKC1f /xSO2\W_ %'g^epQ]x CX3i|z|8 Q,Y @d" D,Y @d),I0G,Y @d" D,Y @dTz ,<#? ̜9#ӟ?<'wu'BH" D,Y i'x7|OJ~+_y?41o޼-|+W3%I.(eRD " D,Y @dNr(3K}*q)cv1UhNE|q*x8'ǾO8]ѷ"{GdYСC\hjjd)iY @d>(,,Duu5Ǝ#Fd'N+7oFUUUCI"Jif͚\ƙFމ={S%ah2ѣ ǖȶoCf.yQ-  '7XtGur 6 lM6Ũw/fb?HF=A}}Xߟ@^^#t&~̘183QYYyZ)Y @d>öm3Lʡdrw$fٳ1ydp H9t6466LG1?M8҅\dm>(qF[s Λ[2e1^m(äqv]:O-@Ƃ r6>PH=؞l|9<;{ȺN-u64c8\ߌϚB ޳CCWi > ?Fa6+]tx:9 C0bZ`5j>UHxd" D4[/ly>{OC2ʨ:c gHI[[s'>J%%%IB0}- yn{!j4fU]Јa%6[]uhim`:x $̰|:=:ͱ~6f8otPTT)ͳٿ1etJg =#;v8i1g9+IR˓ɏm3=Tt89kJ#ͩz>ވ@a/oދ{ʳ}rlr6ŤɣqE3QwV_n~mv;ތ60xgKaruvO`;Њ CgMv;Lևb,ػw/:묏Ev$4@d" YO=T4SRTT -,#r$`?z =&tf`Y3ܑ@NBUY-5v(ĦP;xMʩ;`17-/ųƺjl{o_"uG܁o\?=C 2d.oeL>I.smhhp6&#G83I~!yY)[;&9k E:S=BV:az5m=oBÂ5/oqE_Ǐj7rc /^\k{3w$ L>Q_3 "ÄTzI> <d FOx/~"*R2@d>3LàʰnfaCppбa:LFRpȻbΔL`S=fZo5ǀKf^Y}5, Oė<'(24Nc m?u*;[o8h-G:6,+Ȋ7߲zRh-KyML$g%ik:Ӂdq_lKONԅaǡ&gV9SQ!gh\{g{ߡF \1 +3sI+صv[]`mh{kP^Q>ڒ@iL6(V1pYxѷp :&OE^菦?|:{ OoiNGVJQQfPrsNWBƃKiTv }? /_7t@xےds.?s?e]I&Eڇ,:Ĭ=܃_~٭sT=a„0c8s ,=ك~> 68m )Y @dOLG^ڱ@CP ™JRٛvsN q t5;0~b܆ͶĴ$b75;MWXeh_f3F[h3:[MtzbanW_M]8x3~:ELO>Fsf<6g"]!%䭽?ej J1TyI!=|Z<\߆Bl߂ێ(TYtzMt<4˖aX&TUwmi<{㟽cp@IDATL+6lߋѵ-k͏wb()*@Yi FCcs"C#/oFM#75 /m9Ȳݸa$`_(-sJa!PżF-Z :DŽ4/sķv.B@I3(da, ,^>h0h)__/Ƃ }k_O~smnyn y:6[ouruڴiXbۧC[nQ&v^&u{"v//}K=wy |_vp⦪6a%" D,YCY/b4>P C3r7tzW΂-cC*L!)Y29g?0ckރcԈ? '8G',X%t徜SBS?ƿknذ?0^s5߹vT圭}Wmśxg|דׁȷ~;~r9,gvS?6X1E,Y X??8~}ßٟ8rwfPe pL}}͢T$!|C6wیץu^vZ䌉#1 )KۑBs[ـgv+alV|;_ߊfVZVUmhNA2ew9xȍwaG]Cʙ*<ɖRf'Nw;9`j x K|%W^g*1J: A?]Hg6RVflmSGY^lMu(IMRҙ 'fzۛf?—` ?לI5hlG9[E5*ޏz{p0ٽ:tAIW qsl9j~JGPv|>s3̜B[Rh ͤ0!X[>ZNԢj.:v XR]14\^ė|Y·r\u͙ pOd.~/"/\s➱7bΜ9?Ӟ%t~Ν떾?c04FriyPg7CFn.MLE׃%RROxL4~TT3 t:x(?<}[G> `y:v`;E9igRAn;ՠ#ъE5=6q}aٛ.rp.?-@{[6; [lɃn]N~s7lT|I;u" h Z[ "_.þ(!@:dc*'G']Hgf%̃lmYϮdOt"N2mT,%Q^VTPڲ-v*0gK0anNc+K'ÔJEs&`}2#IQ1wZkW~u$+Y#0uLZ8ھ˘-+o tzzl6Ǿ>ë ֆCM a^\}t*=xmހ3 {qaߊ-U7!x05Hgf*xL3Fm7={ PZqϡ%"g҉¿0pUbr9K/>{A)H\f巜w7x}`C[,{9.6Cdiv|8&ln99jGEy`ɮ_ QP2ayc[1k0[j{̬aMg4":<7]`h8J h5@qو[lfxsO!'ȷB[.XR(ŨۻJ#Mb!47oc+1ܹӖyv;lߜܙS0oD{hIة6^f}D6fLAz[zNPPee6x!OGXq(xӇr|Yt8Nw\qvYP.Qg7gy𺓣F #LmVNСI:eHGP:_)S}=x_@OOgg:_x*?=ć" D,/r(9P t$l\-]b#G WJOP69c嫤#*\~60iqMZ7ȥ{ HӲt|uՏ:Fz:}B*{iW~a9NP^eosqќpɧdgGxG܁?]Ry'`|^h9jKOۭ-lkNE#= d>Yse3\JQ;JH+/IZO|}Q:~e3G!,e d埼ԔˤIʕ ܳ@8k8q"<+U<).;3\H~OpI=MABz]PgZw};a:ȟg}V(,Y @dAZ~jLf^> Y:A9R).yo!LNt[pq9oڃ}M h谙|Fa̟6NmGcK-̶O7b6k+b|Cߏ[w1ml$Ad/TN~jL.珳t6|L2h$rWqP5./-ysp% e%Evx mT)Z?XGwu 3Y8W==Qچ~*Wo} f}uZ||h-Z:>"|:?c;Z$gC jCNaWwg' qs:sF~9+AS<|`a<8?gS> Z yECs4PZ O <6, Tž| }C7(>g<#%IiU5 Ig$cHG? )'O`t昦CijAdGt ATy:A  m W.\wJK]2?V<řꑗ<ko gA\́9g[ZZdT 4Q) p_NPO$n9ۺ{b' .3eVHNJH렩n5*7:ƺ|)KQ8¦g ܯݰ+S'~X {'yigA;ܷH''ې(9a<8HGMMM.c_0 Sz;zNyN+Q,Y @dOWrJہXaHJ[jF%QD6o03'`כـmsl3mGͱAb>f3 kjhD%)4zTz t,KE,X`ie3L %CḑZ^'\҉ u*{Hy;ďfNETʾqсcP:Ƕl2gp_3\:,Ω4GԟL ΔR\ѤHz8Cz"eYʛOHx:8l ϳWADk/5З^1a„vw:&ApUƽөNX?==ki]u~ӬqS 1t@0\Awyy.[P=uMȶO ]Hvuvi0Җ߸;,+cZT:?g2L`A"3:~Pb1 a NX AaΔq 3sQ93eal^8Fl}xt&ypv9pϥՠ䔌 sH2Gkr&6?6E,Y sgnpUʡ c۸p4EwX>e\[\| sgTD5RKs\+'F(ycP^]cI| aazpvOc+:xy'.B |X^NbΨgUTfȄnq>)zfTn%K,q3ۚf ]B¥m:}kCXW.<]<uU~zgZDWQ# D,Y ^q-{9hoPit ;ա?=88婆< KNeg;G/AH+>C d`Nv^$ac)MpU#HǔNn,\~f}ē|*zɐL.2V=>Ja_-kN`@Lu'uŪWGW>?Y``U:|Y" D,Y`h-ՙMl9%V-5Lt8䏁>yӬg2|3nP` :'20=fK#ЦCKL3M2c,az죌?zPw^YޟmOg{ ]xT> I ^t(" XgXPA ]A!ԄB:ɛYn6f7ds6sww9e9,[*S~=`TݷUA@A !q~s^?ļ<054!@|j!ZElSrC[l|>kxƱ##>7B 3eM0A@AC-! &"nϋ=X^fH## )@A@@&BXOA@A@A9EA@A@A@# 2IA@A@A@ǀ2P *   =xcAړV   ̙3ɴlK/$   Y"0ydNc"3I   @GI-&B/^A\fC:ټ/7A@A@ȫ̫=#|@*X|MBi( yY6$w4P OG\  PpBYp^\rh)A&>A@A@p:B((edҚ rUA@ʼ/*A@ȇhͤGGA@򸂀 p{КIA@A@5gInA@B\]-t7os)_A@pgRSSˋhѢTpl?N&B9ٔvR]dA@@@>EtO[پ2yQ&ooo!FQ2  ʔJLLq>2 )B# ,XH  pxL|5!I???.ÃDLeI9|2cb"|,dxE1XɌcD#GA(cbbJ1 ;]Z+m袏dn;wxa^ Mɩ&uL 6s N: Oi  .TBS J& ev qdd$EEE񍰰0*^8k3t&-YJA@8q,#5IA@  O8ҥKK*U "MkE]R* X"(2IzA@l 7LdR'ŵJ]&"  WO3QL $ v"gvk{+Wv[   R:tV<>. dYd 8kz;H2A@A@(?1Z5%VC .pKʕ޽{)KQAQ$I>A@A`!-%Ȥqpd<ᖄkTZ~ȑtqGj̍g:A !ȏ@CAHA@l!L2zܒP㏹N&j!CT$\yRqTJD2q|M5ۧup#-גj 5*:-삀  @B2'O薄ɓ9y彝uy0s|Tn]JLLd"o@!,j1orVX>8s4;vJyY i${}1.4 ko*qpZJjE(1%_CU#YT. MӁv:\c;Ѿ{ח+n0Uc j ):6Z4N/jFa7ڼ/7A@A "PJ7v+By]wQCO\=z44{lhԩuڕV^Mv_t@h$L`x t%ժ"(Q17ltQk&<3W:,NhBtʕ+Ͼ{QBBլQKmDZa-VK%KtV|r1kʔ)CM8T֥K A@A@oرGWr˖-0wߥÇLQQQdFtR5j=sNZ|9jՊI%O8&L01hBT8in ڿJ~E )~q='xZM5-C{P*B*QXf̰/+X{WMURJE}Txqڰa˜ܹsԽ{wq^pp0ߓC@Gf/×2PiL\ F^mP䧈 gz{yzܤ  &EdD\cG33?_]J< *H3MQ"P|\򣍣xp,T78R Ss3nݟ}71|"3Dԛi>QIU2I͊ū>I t=*լZd/   T"K.qPRgJ&ZӧӓO>I=z#H#Zjo%!oޢG}t}̙| ̟k@AD7SR(u:Rv}Wk֧GܾR#.Qx"OKKemeRl-U5 ROO^#VZfڼe٠vzhS8:N$ y(b%ԬjL*ǂ   ?"""/ ~z^{ャE4Ç󭯿~W y"dȑҡDD ߅ uڴi|,!)@HjYl'XKKj}'œ'X:bPpv]gJbd"}.׏Z4oAU+W"!Ըq3enIX@jWEm})qf;YX8HWR"TbY&tDA@A@GڵkV3ۺg5PN:t(?O?MW^eGUKh,ao}͚5 #gy|A}*{'" 0Jh-n$*^|6Ey)ss+y+}գu=nÊ*=zuёPBL.EkІMd2c .|^ʵ(msjP"_VK  `jMlݳ|E(7nO?@&!Ŋc$}HLByy>ƿɓ'sy r+ ;|$CI Ʌ@ё7HAIؽpޔ) B,"u%K(")b Q }UhQ6@ı+ѢktJL-CfX(br1o Ϩ7Z,a*d^{nW=+ |G(NOf>I|&}ԳgO?=S˚5k!UP `: ;uyVK>3)M6l=V,hثu(irDWAO5p *\$[icLtejٴ>=z$w'd@$rĉp>^bknݺ)sKO<!kѢ>-$zҥynɒ%ih/I5dxTR%>x"=cʼ"O "ؚ￟-^z%7W^yE?裏xV'OPթA\'۪EA@@]^GmVrҥlm ˾}/9`Lf"9CC`.aύ+Q g"jLSQӵ {\h\gV'}ry^u0Ac[ʅYzH,1S2e,e5hyj۶-`ڵ4h ڰa_~TN6/Ej\>SpӦMJ*dȋl:t 9rݻ7с8H|QN5sl M:KrRH'EV]o~w|V}Ɂ  Fw[v%_aÆ,53a0V@!zH@0\`1E,U?Stߤ6V] o CmŵU Ej|*I12~smϊZ !alk;vi*|҃}Μ9AܰF0HJk|SL( _%+O8d6i҄1H+~Yf,H*%d(h]8ʄ@Yg,GA@wA;Bwt1N0K`O .Rj`?խCI9X G(QrBB .%·`BoI9gmHlD ;h`:|.}]W7g"n~l"$ab w?梖Ku*,DDdR gΜH0#5~uK{hy•yƠ8pJSbJ o0r}t2駾Mj*D;w4o RfQ4L-~I\y(%XwN Xh?ƍS`` ͚5F@`A` ?ȑ#G؇{KS,H(H Lv/z?M-Hkivj>}XC O_s;8N,=5w\3/[A@Jh%ŋst?~GD @ `.`K/O ftr<H1h`òX~BiR~H(0q)EǧWTd!P̏VJ>hhQJHLkQrqJc,,?BKh"&^}՘g%huXL>{=J"G2L ~:t(ka^ˆ$##~ d=VZa"֖`:h?l Ο?lE  [6@&Mu*X"bp`. 1ǎ#q@0۵{Mzoz'7ל!C}~B&52&7DYsծBaTd E?LiL +FiԾayz&f\'p=_A$XeIy>s,o #^qhA^~bRye67(,e|w}fђFEEejiݺ5c]ڪO畽  PpkBf@[9dj׮ !4qs `0AF|9tw4p@1;N%5e`;u<)[&X\viKԮiTܟ .eCEÊ'Q aԽC>oVɗ79FsZ9w/ j""&]!VtA@:nM(EUVŊѣG@`dNf09x蠉L"/̨N}B|gMCƿ)[&H\zas԰V%VQ~#f9J.\T8 IŃ|hL6!fs 3fرcyvyPA@A y Z1@AІիWus5O8[.p= 4Gɔ|,a %ʠ4j)H#setxGq*J\l yA}^~%k(ϴeoF4 qz  /Pw4`+WMAT 2كƼ:|w 'WGH=҉~=, #!%e*| T D"+8kjAg;# " }ϔ:~o9- @^A _JK `2s7=4ձ|,˹$$S|R< Ax@@mߌhtztW0z,B)IE8'%Q9SkG9"r. {"rNGdKL8}|ۗShͪ4M$q8{e\E-WIMQ!lyW*e=ѥ2k$S7Q͈뎱.  Z*˕%ׯ5'cgH[f0jYE SR3(3e oqqUBl0UFlڄRjЙ˱C*H"4@(a 3r-o   5sgBӧO… )<{9g۷/GIt.OvqV}]j֬d?UZN9-w!A o `x¼ڇ 9AG$sԸqc5LAqXXٓ~΂YO h1h6mD5hqRS6ɑ:dX(':%k׮sfm̃٨Q诿+RNhʕtўt̾9<@Vk  5d\x?F fKт ?>թSI&vŊ(\0kѸz*5jԈBCC [lI citͫsA@ȧ8P /￟a ._9ݻ]ꋴh"zZ0s;<}/Ж\iWdZmIq.whQ|\ )TƲ # sG wDZ |{zf{{yyyeuٛN{Kaw:A #pg Kvن &)}Q.I&` 3}1EI8wgSɢeo;|ڸN-O +Wp2qD|"Lbp۫W/6KpB-^ts7Ϛ`٬DYZCmItd~IhK1?Rh&̸Xblҭ.X>uzcR!46ch]Rxq4`lIio:]}c^9@)-ߟ͢@*'eùc 4ڷ3𛀙 e,Y#""s-|4~x1ìѣG >ҥKur{h'1 fQ`gFuݘEsjՊguz }ѢE9<>I8[-E0\554f0g췩Kke~P`;CڴaZS=h?OW, 3NF ΃)?ŏʽzuǀr2/ZgK]s4A0SLT@X,X@!!! ?3|W "ZqDM ~ f(fV1 `^>, @m~|(%;pLN>5x0с_K[Фk￟#0  v׮]Yj:?! |0`hCs$>pفw؁HBH:.}c^9@ %?SOGf0Yҡ1C:ѣ.֭ `YU}Qڰajp_~W@IZ}tr[(a`2F$X~=F&Ԉn5-~wA0:P7`cYkl-V׿KӒ@0VO;ugju~%␁~B<;y8|@/po3g>T|O65{Jk^iẄa=%9@ka`:0Ё A` xcm_|b6?~]8f~H)S0^$A dr) vT 2a3,z-\3ZHi/4g7808}5Tf+u>E;f$j9}b|gw'Oӑ׬6e@M_)u[ө ǩh단ZO]Tv<64ݞA.6>?R~xw)Kh+LH~"=H2g>g|)C7C蒃̷1\"y26'KcYyA{^oh7!aM8o; )fҀ>N?,am# hD~r.6k3T[3q&h.k^yG Ф`M$n-?eʔ1}F,僖` IDG[M)[+-x'1Q0 3˳k[{Y7{kxHcg<{9w낀 |r:CDsG콳Jl}7ֶm[l utHB=Bꫦ"g͚3 P/20):A+ b! 1:qB+Y `zN#0-Àrw6<rًFo]hT#S|a6tjY-=3#A5Ÿ-P>XiA B )v2( oӛ殘iw9?]v}x=[Wj XsY j/c{0YsF&w[diՇ{"-7X3h4ԄQ)fQIжCYä%2<\x[Vb+]N.z F(f&a ?BkS<"r L jQ¹DG~m-~4Yfmm*)e6kOТ|Nkm&r09xjg+], ;j?&*}JmTCytDѝz{cQזZT˖HϡT-?Sy\X2I< XFCn,~^l۶+"?.?a""n13J;c& 3Zc809,HQ ~;(~PjRT-&ԠAZ5607<f0B 13 .LwhOD/ \eMr9՟Uդ]5b)*Y-AKYL5 +DLZ7%j(biϟڹ50eEymkSB Xn$,8h'+L΂[)}NnH܂ VL$T)g (Y#S2u 0IrNlv{敾=O/ @VPb3D_} ZJ (p#'|"C_ g$:{\$k\NB ?)[փ`@<9-TgV>_!aںldo9t<5_"hP]"Ƀd% X7^ѧ(D KllT*[?Q)[(ͽX- Hm$k\:hiDl[rLauS@SA@S@PXnÒY'B\Nfi_HAh'K,i)KmE@ GO,NyNWy솗 Jmn-"^SUN=RMm&k^%ܠ龳sr]]7s3b,˝sׂVA@A@HG Hh - /òi\e+aƛ2 dLns:]XbN}E R* պkh_iۿZLx`fjKp+$ϒef|%# AA"btq=-ZA@rfHh;"ƵZPP k**RcBXC`M:X BQa MoO Z}~  ]5E &X ~0߿?, 'X >Y Nʓ|8A@(\CY0`A"-4ZkҥKiɒ%|wK!СC9ڵkaÆb5jKB!(ݷo7PEo߾eN/ K 4e@?,ZԩC*U k.cEdC>}8=b( :D<ԐSڵyi1c:A@r{Z$*rM7CQ,a@ΰ;Ig"vRIX'M0-GYz( ,={аa8s/>8b.DS1sRR;Ν$w}ca&]˴i݁VebbLϜ9^A6!`x¼iB(sA@~exmH& XoKh?whFi`ڭ[7^kkbY% D*hdԩSG~QΝ K.ի;d%aR–4i҄ X> ˁA7n8^Zl嶊{ .F q]Cib.  8& c|٨{[n]~WB-" ~fKty[n @FT_N#F`E=z4Uqᬵ ~*0ᚑ0XJ3X͙3t&˗: 0n ~^@bfJ]aZJƍ 6oޜ6m);`2" rO?{mɓEDAB^%Aa†<Q\7ޠX=8T֒9C !lQQQx*M ;2eʐѯ~05'12x`Pd$炀  B(ݤ 8 @fI|}}MdR߷D&=Kqf"0vD-H6# G< A@A@A@ !c^A@A@A@B(HGH3A@A@A@p7ćz,G*`bE襡}2(`JE7I#A@A@1nO(υWӿ訫Pgxx(%'yy+䅝: O^|Gy!8q"9)_z+eQ-BiעE JII!hD{ML*/_lO i+ pD7F0Yn׬UլBVVV2o5ԾfTת1Ϋ{Ց"7U%)2&ny3~"臅6eh(&6^{USE*itSc#Ъi]{r\K]t)-YvJׯ]vѩS{ùXfǏO?M;wRJOTV-j۶-޽;C1vx4|pӽS:uxLh)5 oNX իs<ٰvq8 jF(44e˖&1=PVHHk۶lblF;orTR%<#ʀfO>Q?3:4ڞ H9A"Դ@17(6:VSޠXڢẺ-by,DPuXN{ q)&ȕmZ"a5>1֬C_~{+?RJUF(G;vwWnsI.p k {MdجY36IL6@@`2ZjU}gl. bF9qnݚ=ҡX6 f-d(>[ѣnjCw?-^TBLxϜ9ڵkGSN%ߺu+M0zy.$Zj`cذaڑNo4ǫVTeŃkH#G|c hAA A>Q'S\\mذ Տɋ_|': _|9?ߒ}СC3?/0g(CAD ypLvpR\A RKT-fTfRjL)i@mľ)diՏFJj:WӒʗȤ (8Q2%(1)bn$QeUO-Z)7 :u1@(=O GхkTDyE6R>]T%ioHe˖$4C-b-ٳd7gڶmgxX 2eBzOlǎ8;orZ_+B==\-MX;2 4dSXXu֍֭[Gk֬!֌\ ! &ZABb o~իWeʔa @@A֭;%=O``eKG `ڪtҜbhѷdڵLUDHH(,(Ϛ M7Rۭ֞ h'@n#TSo)2LI[8E (1!Qʹ'P|:F%$4 ~X/Qi832uA |oy\gsα*&aR_XBSS A `^^BC %~AL :_4&P>V6@(XSX1ypsAsY%R>7?jhDF1hE=A[?ꅖЖ2&1}駬4 ( h3EseGcyr,3g,a>JCLFn3iSDFl2S&Vqt#!hp~C^iwC "FɳtA:un*B >οתV.K|O HQY1WX K'  y@2-MM&GP:>DW pcoyW5q:h"OJ2&?3TdI[űFZ/B#sWhw4tI6VLk>{ #X 2f%:-D!H:''? |Q7|i( s-|& Ղ~6:___=zNfqo~MFївôږtޝI,;2a ID>}:mܸx;ӱ֞:A@ ,fUbI E+y2WUft5ՖLj),W=APdON"(uU$EAyT|Ѭp"ʌh 5B.XU9p"k:$?oWˆx+WR*Hd:oJ5+9f/o"?$9#F.]'Ǐ熂$SO7ofꫯ&{}4\ '5@QhÈA;<~a1cKhǗ_~X`LWB UV8z̥DHHCMG|V0GF[[C ѯ JaB@,A#0$zԨQ6[{vke GMA@@VkUy(4g_B/h-}Ew4OM6SaӗB)L' NYͫ7@t8t~qa=eLЧ<)!B1x"kb"͓ьiq :aR mLr"0.FSR]^DDGYkU3)fV}ݜ!0E.{K}X`R4 Y%Yǻ 6*,fG`L@S [fϕ8.I'@N#^<ÿ<+{_R1 E"A)qH!J7^Q겧"jciIqQ5g}} %#.[("Aয়TM xĕX*U0,ݫЃ6wbh}ȧi*EtʓKW:5iԻG{4XJeE5w\ eN$*TUK]GYdgx6|fKD@,2:ov4 |A&QGGY  `nO(=yM5럠`Ii?(FlDTȍH$:Y.x]r45_VvS)?݈Of-U1uҺi S--@-iϾcjT^=zD(RR!e*hOժQ*U(M%K4D9oy.A-?|(a&##Og D][6܍O3c^zni ?nO(5U䔛*0ؚG~toԢ^+Zs5ZEjyKQ=CT8ע鿐/Qb;U2d` Խs dRAjt9Pa!!U})(Pa*-F՚1tt${N:C&d `6o̍t1 Gn 9E "КF ڻsMKu5U-zP?% 21c;KRrScץi?NwlD%c$`pfWP8A}zXױC3ZxJ[ dB4ї.]Q cT<$y+-vTT)lc% 7r   `J@L(?}FJP:Qݩ^[rd E)Yt9qYᜢ4*莊pV5߬TOeP!TZe`9sn*R"_7ch5 KG   Pp{B*UQOVզ խqկܐ<<i䑖HejƻfD3Z.MGFİrR#r+%)\B7TZ$pvb=ʐ"d*r1H=wQΆ6~+Pf Kl'fOY1i^!yP([06Jb̓G(xA@@NRx(&%&S\L-Sw%iþlBڿ}$eLxŞ۷op^*tiڲ$yAj jիG2-VŊL/.6V@6VfDp@ս ڵ˘)_~3Gƾs7prTp ˜h"Ma`kIWbV_~=@0XhK`-³gҼyx=zЊ+L̊zj,` `F1#ڵkMkLۗvɄFXkMB.^CM2}y'yR}V;tڠXCbّ w}khż4 ޯ~Du~ԅeR[̞=o'҇SŊ/˺  `Ow~"15bړ>I&]P"27<3|/plkTDC $D-.Dzs+OǺоT`e|aydc2ehӖtؙLIeĥ\ or5 z]"7寿P? mH^x%IFcɯ}Jp>Lew2֗Բj*С0/N8i7l{#4=c8饗yw8b:MVm2j(\ٳgD+WHh&"@$… YM Іb7k|û5%!xWYύ?A@'ʖv+)&%'?۷;-xeF%&{7~`Vq>fiѣGݴ^(FoՅiLTa b/t?C%m=?Kۋ+j"ƍ5ߡlٲ%kt]'O6mڰv;ʷjذ!uz?ן~i&{<خUmۖvm2|Skš4iƒ}}&WT9 т۷˗_~ @~{HtR~Ɛ֬mٲEC7%(ؼU_F|vVCcHȑ#3VvM'{%Қ5kT(|ll,_/]4F>4{d˗/+ 'i*0M^:$B4%D'/r\ô?nz(忛yAC+ߒs"Zp?tL(b8&;Mjզ:aEbZ" \ +0j%ڵSҘ1ch֭4aOe";rH^:}7L,/\fHPB^Ruϒ%Kjժ<7nk`bMi89C4? I} $ Baaa C0+ԩ_qZH*C3-xxlLԬYӔɒʗ_ /^Hxw`sر=J@X{>s_gϞ)e^wB ZNDMIe616/5t7w>nbrY:L0?i<;*Й\꙾ČsԵx|>(Z oF4rX-΍@ҠYnkjT6f˖-cM=_Iq7!A* SL9sUbj =cϪe"k믿N^Zmz M&c\>q{,ހ)5eo, ?"x c cʕIݼy3TBs 2a!y6mNvE ,p 0ם>}:On@~!,J\g <,{A@-QǛOx#G͒j=[̎0~<Ǐʛoa,:QZ(IEjQỊOŹH#;osnM  aݻwo6UvrƌL `1p r uPuBJ({G\Fb8;|.,1fD㏬6>2;avܺukzM*W XO[*ԁv'ts\ &~+7 3\bs+@,nj /"@~G % AC$-I(6 HFѱ!aʃ]wѤ&QgAvDӶZw2A`I$R. o&\ZZ_yaoIo"w?45j|͚5cm UB@a _ r 7|gbY !gh>}\_vm6K#aP !D 5!,D4X@ @ٱcG|L˗/Om6C =hE?~?GkRZyKe2XkY2R@>xoQvhh(Bm;L1ɀ4""A9kl,݇06A@ nO(/]˛r`TϚ9tp8` X 9ZgA·쯿t%ƥv/G.'R2S.` d:i[EojCdѣG)ܹsY*Zk ]>XK?@7|p `@@sGO% m"wjYhO5N=ljۥK 2 Q~v.iAڷoϓ0,믿G}4cWg -6`1i2"t-<",4ځFbeiB "Qt4 Q7IDE~A@x5 ~%Ϛ^2vT|aLTY9鷜o!9 %pBTz" D ZLg)fҀ>3&`V-|OY5U4~sAT|am=C:Dh, jJ['hy*?UVN#4.d @eaOYR:Ŋː/xA]xq 0AwX&e%;bJ .~!.f} A\ 8[.G;h?SR/gϧ-z5CQYzVGHG=boaqE7A5iIA$@ޚyDO?Xޒ8|Ke5S| i{$ ݞAr >"炀 PPpd<ք"pv̳=2:HJ=h̫cFߗsM AVlI2,03JMIUt^iLߜ/Y&B#?R;!Ԝ3IWA:#ܚP,EĹg*w(W(9:}][1 4ؗ(ZDEPJ7sh]z.RxpA@A@ &-!0Ab ۝@￟&MD "G yH La5#6L;7}cˤߌhα[,  =D8Dl?4 Z|ǖ=]쳏<&7zӜſeE:R-8;;A@A@p?ܚPnh %5ԅw"A$UK#nF5LHit^-oBpg\DA@JCE+B&K9(Q-7P矼|͚5AQU뭷Zv|-CG\Y wEO>$?A@@ _J;7C jD73XdL"5?tM8wb={/PcuVXꫯbm +v|饗^>֭FAAUدsU \A@\A`ҥdڵ+_}:us=4tPnڵkaÆrJ^ܸQF죎Ŏ[lItǏt95ʰ`hǚ}-[p#Fpڴw<{!0yd:rk+Ar  P^gA@!иqca`}޽L@*!*T*VڵSҘ1ch֭4a@{aY& fPo^Zj`.kذaI&|믿MԬ1+^NA@A BK@K5 n/l2>22-ZDw}7͞=z!nިQ8 WuF֭5kְ X@IDAT_1e'RN/^KLv̙PmΝ1EOfS]hWhS˦H0rhk-FUkuuA@A@py6+P/^J* |t0蹝ҩS'_ߋ UV˩L2|4gҥ s{׊/NӉkYA!;gԺuk80jA@yP^ryfիGǎ#~ <볂D{t+H/{B 5;0/7 fߜ3gbmzGΜ(J 2haÆOd+I4̉|ޛe☭b Ke_J,)lAg<^I⦆8¹k9:3.=+"(@ws(އXs'Q%W8Z%#d a- _ueر9O;ID;+=dᕐ?yvRXہ9:q^Q;O>W1Gn#?hD)$B1_U>3Ds: GZWPjݺ.&.g϶^J!h0suBx9qχ}\8+"("Ć@#,i"ᢋ.KZBtN/G8-QM>iļN;.܍K|v-n ψ>^z-G@f͚vm;]ve#H_m{EeϚ~hAgdi!k@4Hv^(G3/ں G^fNCTqMII1cz-3q¼/'N"˅){uA-[PE@P9K;B 1@&W^h͛g574ltrH/\0+(]~i<'qqΒS1_ ψ8Q䀵تU+Kx*vblj #hX 2!lsV3 hvrʖ8u:YEk׮ry"Xw ˿ ̗_~{#ֹd>&2u{^PE@PE "{X? M"3dP(¼J[oh^6l`;h?15jqy.qk1?i}pOT"#?毺qh v-1SMwy'=0am=e„ ?h1Ѣ7k\8pD pĄK.9(la[k/Ӗó)sR]wMݻ]2fҥ /Xm3Բe,<8裏bŊB("("(@G@ eo "("("(9C@ epӧE@PE@PE@((,M@PE@PE@PE g(n"("("(E%E ("("(" %9MRE@PE@PE#7@PE@PE@P!2gS"+v%l*"("%Pm}FP|@BBB>ˑfGG`8wv5iӦ4"( 'Pּ*"Xo˖VsÆ e˖97n;###+… g]yO>ꫯ6*}>/ЮƎ!ToYF.?{";KOOK.þ'N#8b+O>tY?|9=xqfE@P#+2rP2?/ʓϽ8=?h5s=''xp 2rȘ  -S\pÿk6?0+7l-^8Zn0ٱcĢImZEÇ:g%;C+믿F,ƍ7(Gyd|g,|Ah?;"("C(gZ(iRV)WM,VS_W 0tPiҤ+VL8v2giٲ\yr'K5;kt 7߸ӞvVO?zI?\Zj%t%+Ǐ]wytMrO=s16|֭-)PrJbѴiS)YiF~駽 * BXv̜9Sya]ztE."Pz-Z:uX5hРy[^\.U f۶m:uIyȊlA1XsJf+GgikfͲZvqFZjnݺ˖-[oU^xzQP€@!Sf,T`h,#,ez+5:P@0ԩywzN4I>_$%%?,bևԮ]v! -N>=kۼy%G'G![n=zN:]ZXR%_lX4OHLL/q2ay3iBwx޽{ҥK3zhAsh٨7_D3qcvJ2e`*Sul,9fs=Ƽ[nƍ̟dbY}뭷sNs A&&/\ЂA&/_nǼ/SGH ?M_,W_}%5NI2uwit!ʡAD<Ÿޚ:u\bRqŊvnv,C+N] h%f\dbΊSPL]2#xL}g54z8bO?-z%m @ohuǴ_uɻm-L-=f.UV7&lefNI SB@ lޢo&[͜jH*%ciۡLD-OUTL:'=T\KʖLeKFe$6}CTPE0S e5z<v?Fn$3ٹu$&JI{WaX Œ%X$$⼘؞arK#zKFFa=?:$1a&h:Y l3H%Fb>ӞN:ժUKg~$ZQx"N4gC s?pj:TO"@p {sGT adp9p@{Vep3W/B J@< D˟7;;TݭD gDG}:hy]z-YAR|ykɼC<`# FK$! sC " ڢhEz^EG?N ^ Ե{w/mdrw$h))){YqT.JiZQ!ј1ϗ +%晲|m&˜ӿ߀hE@PE@P,^CrҕhDJZ<]Y^FZ7!?#*ի㇓ISe]ϙ&BRA_uFnjRrykm'h-d^f4-Wa +9S%Sɞcˆ1GNct3j)VL rҶpPULMGPE@PE HB,1$%;TXNN8Y2x4dr?ddZZRa/2pj`hB6)P!eR,#O"7<)v2oByOak[$T%9S?|I,f̝{Ȥ#4!{Ȣ4a֞0~暩rH2ud7/o\(- `"V /[2= .Gaɓ'a6%KljPuQy˖-.'B_+v 8by|qnvq#E P M^],Go%Qoʬ;YKvf&ڏz>sq7&K/V-X㎐HiRjYiؠBXNV [Bdj9iX4W,14.׻~B|]JV#&W5_Xuqf^x%EaIK/4j^zxw#{Av)=zXgdy>WXYfrQG@Rc"7Z<>͋8q" $h$EW6Å 5gL\6of$ڭ4n43.&7H44{v% IYGx/5o):[I)GMlZ% &}! gceьfg33~EL=ۢYs]?xdY`Z>wY4ilI_)Kj:*!h7< @ a2./@ho_vC,sΕ3gAa=[䧟~"7y<}u:?crAEJ?(Hi3;=׵xıWz(XA.299I-Z.یG]f.U윬LskqNvm!˖ *wֵMRfe)ob֢\، d㨧b4\$hrK:փl!-]Fa ,%1fm]>V۶Ļ7_7[.OWNmʟ3D7VAKaìof2elRC9$]V\O2,j\n]-idƌBG]vs[ڪU+=}B}=`: kB6Ǐo#zj; OK۶m=ЄJ(a.n$+93mxT-N:d4^1rHiӦˆci.LXƤgϞY՛֊<%riw,v,axXo#gu|YfYj/׵k׬͛7K#)}ޏSN9e(^lz뭖{GXP ORHB٬I} ǎS'ʴST):Oh7o. Ֆcrg_LI9['H%%rҭk 9fҡCCi׶tDzѿԬQŎH^[T LD9xjӖl/'*B 9sXpuYs@4-\LP.]jWZeϙ7)0Y d3BaZ,O_0馛ego]~y?k׮m y⇠zm|l{4jj"vs='}%,^! , &?n547n, Z44hLFi{W w$;V:vW{2'p TR%+afYmbL[>cu)}b/rBy*W{/qsE@ڏ@:9reݳʲf:Ҧa>}2Sfv3X]GT4>v30:ʏH~g[hb Rq+N1cu`^ĸŧEFv~W߿ :4C!wK;d$/,v[֓lݺuֹ;@@ hW _ȇ3=s䪫ё`ASJ 'Ϸ,@JJ=S 4.ۣ^SŔTT/m&rg[Б2LLOܹz=m1E$캻piD{g9&h}Q#wO홠.l~M]`zvl{<犀"Pxa.cIuP-$tP-MN:N~u|9q] vѵ%^iSM5O 7[7yKBjeRR@LzNFp2b88p`Vt]`7pp{Y&cj$裏Z,4)=,68gjդyv#ӂEzVEFG2](sSO^{5C3$ ,1$2$ \tE}9"L8QS4\Y6P$}ژ#39d0믿g;<qdE"Ph(4=3v9fDLT;jcd3pLY(]DNI* ujڧ!b^;ۼٸ2#ɩDkʼcth !,[Xv[o%w&]tA0iqr!dKb:5Ĝg!`zډ a.$^2d~ڴiӬ6˙/lӦ5*W3I0_EÈ1##Úv@ġiAa0>3[<: }X8!y=nѢEY\xG05;)ٳg5'2,mdwG&GvʣaE`#Ph~q׭. eʔ0Y95I!+nd?yBh"6u<3qFm=#<6̡LN12N[RrqcVPh>Gy~D2 ;04GhxX''tؙ-=XVt ;G(TP 1 O>.>=a?tүO?&˖Kuɝ{Qbՙb y ytqµ8t+_N^kL^qǺ˺Zo<#I\$/S~F5ms@FĜAo$wI`J,42hy]z-92O 36@s*t@Y2;G+Z\A3W k~zKfAu`{OrVau,МVX1jrpD.ⵕ9ٕXJ;i#즩E vr6V@KqGb嫍Yr|ǣͺ[$)1j&;>YZt9JFMk<#r]G7V H{#)_+&Lq˥y)n\As{▆F3ʕ9 $z;t!T)xDkoif㸈-'^/$XJۛXG,hE@(xxBɈً|$plݼì()%dmhlݺSvn3XALص/d9_12k,k)%.l-x~sv u߶$T'IzM̚;m׍(ׯmkZ $Fs2ZWz(@>G-UE@(xB AL)Q\6nJ2%IJDl9g5kL;E3i`cZLeu 4jgL"TjZZ\ .u bS=Zop;–\`Y>u^2Bo^ٵ+ˢ7,# ƌv[fqIlÚK2MEPE@PE #P %ﺫΑ| 73frw-[ً7ޕgułMSlgySmv]T /ʪE%YP@-&Ҏ+̧ 6R8Tai`: E@PE@P@'tn˻_Ni'iFc<,:;N u,5ר-;2C ~zwۭ_3Zop$<5@.yxnK+DwPEPE@PE` P(zn#zrvAk&sm+ơHbΟ,4~ː(Wm?II\<'N`01W2Q*D "(>ǿ{cmS"X˰d-/Œwf.nk:.|n.n.hHgvUxg"pX\yU>MnȕߛW{/ BiqAGwl|j]N%J=j#۵kWyǥrf @ @%i t [}w2zhY&_XO>v=?ro[|X6!ZܛIT UQa 1\p W.Z<ŋ0,[˒sÆ cz4'P{ӌRn+YX0<v=LoX>co~8qDGs_3iϛF^g{grRo^sZ9IWxW/ThNX.q\f"ޝx ,D7ސ;/b=[U/8䓭O>(46#e"~']vsz"?씐N/tcKPbIwsر2sL;=(w~wy~5 c~WHZM+'gP;w9)gZ& 7BCwvAR<]$wTn h1otT{viKICYfv!aÆYS~2el2KꫯQF8}g7|NsdrΜ9YO馛 w{>|4m.!ӦM|".W^i 2k={!";vˆC=zDkԨvI&rGʠA5Lx>YF3aeҥ\tERB9SST~?ǰ.k֋GXYmvȑb5kִc3(ΰ|-˫? |;ivU,Z({s7|ӚuSW_}kTGaA^a qBX`kŊ&OK&zCp5"Nu]g;۷r-7V&MKUf9KcrS!:uX3ӧۼ̣i߾!.zH*t|7nh@}ݺur1Yc ЅOM+S:EL 2ƭriӦY2-:hg͚%&L3g0|}'pB[_h,p+X͒Yq@^ 1t1~<҂x1zm-7?/篿ޣmUVhڤ-3!=(M{[?BnDžu{ի< }Ƌg>a8~A !(V~ܞ|ɽ}WAm2 [W^7ImS:ďgXAD|Aipo7(3f̰-<1Uw7rJ|AmoݾNKXgxx & z(T&مc#> *Ah"tPT^]~W߿%r<s9UW]ek:X1}G |֭[S:oGy/0JNggm;3G=Ygs=g˂hP~YNWq1bq1=Ըqc0`%p'tҡȠ=FOEm{h 7Aܳ\<(>7kn裏IO9/302Uݹs}Ү];ҹtx9+;5?\kHPwv ZKLy'ufLC?";a™VV-k@"0 c _%9(҄ +"PU~!o1'ts#tT: &N㮹=+8gẢGܞPuK!,%m\Eq[oY+;SGy#d2LZjEn 9.ޠg1O݇Ňv D:D59ac4Ꞷڑ?/9u: ,*:hvcM;(dΟ&r 9B=Q7hC ؼ9MFHu9⦆+.kZڒ@3,Π|B u1`2ţRJau΀{ K@v."m@н"(X0c=c͡H4tD\'3l+:;-&&شumv{XAaaI.H^4~4IǥP5EI"qړos,0 3щ'Axϰxi g}&hp&hI3kG0Oǚw9~ Dk6ϗ2>k," h%bO:g8l^s5,+s1qxq` fFs!D~vW4p#yC=v-sfϟo1o%d0e42w84d;L6(}Ň $q6|ZLC׋#$X= a!u9e}Bx2Ly3{679-(4AhT1f^4&auo3as==E O,G*742'  3 כvP'TdHc Ӗ D.*؛v6 /]|~O_KW.57"S,YbxJ<*n#Gz~Af!KstaHdž$bF48sXyH"V,up MsȄa҈_0{$g#v 4{?qDz>i&Hߋg:¢ ߔHv=G;%(<<h[vū&(Π| 1t]Sd{I)a zGxWDa^8SUCCFܝﶞ*@1iGG*/$(ܿ W\)&',+:AdpAlgK|޸MgˉĒH$ܦ)?{N'a׽y :fq׼]>(kfM0@ !\, (L0;D'q{?zs05 wLnIτx!\ qm6Bz9͟Y=W#@%:}oD^Wyv7Ћia9ƣ/A/{,̥}n xO/cÕ59!*Gp:L,X˚HGX%8ǽ47:3Ipߎ 8aޖJF?h{'Cn"|ȵ)b6<1]3Q+" n%9C(78{Uqȿuϙ=i yl b_~zsFeͥ $#KyBVNZXbG)NO=^$f_̂("("A xv'@~=ի}{qA,1TbaƳM4L3q-_sox]Ax_ { xR{yYi*"NĀ!sÄo a[ԩS4nIAO0'+4(@aC@j(Jt4!۷tgZ k!#Ní5Ǚ{B7A=CK i, pBj1S?`1k֓A.Ɖ |X[ǻC{Ј5l\cpfw:8ib'Һz',x1y̧mڴ]ƅiӲ|.{pssf1+o^A~7?|0:pTG7)XQ׵/9@|gY/ d„ mӑN!.]Grg0; N37&;wryb»W==VE #P %\'t xr8M dM'kCXDAœ=:G9]0,z9[od䨣QQ͟pDzzU3 &.B"@g @/Wī>CJH@fl'{lذj!S|.RO:` /H~fc)Ē஻كIq᷀` Ҁ=&X@`]rqY"D^(/ߚNjPzb7 ̣fno" 1=Y%ٳg\h|Yߌ^`iD=}C4!ēL;& ʜLi\2"(b`X0RM~7VꫯZaaz8JF}s16 :Et*[vȤ?tfP֜ϲhO}ع6? G[B+H|(`}9k, G3IGXmB-;,c [L)1D;GY.N,( C/aMd>9o/Z<^C"wY'["]%(\WQE #PP]\Q]~0sq1 cFDęs,: .Efc4[WnP9Z8S7sySQH?]ڼ( 0 $y' ya~YDj7 =) #ehū3M:@ hGu{e0 0Xƻ|=uֶ1$F'+&G̳D+Ơ )b-?9r{3x, +pyf{qJavuĐ)C,ݺԏk+6= ~҄aUT~%6tuu1PxTSN=<[Ga -d-{vհ"G @!Fzd4H!J&#!T0aDhs4g-4yK:8L 7h0'ġ7s4OXcP_9LPi\,%Z oLHb1契I #f?k)B YAr6 Id# BYwe>$SGN.RXˏi1X'L};lz7yy0u& SK:¼IoN}b0 -Zd-Dق+ /C^!<+m`$ /4k׮.% 0F-$XYcbpsFE@(,XBɈWX*C˱S9眳8"@uE M?f2L`OmtNŇ𪫮T6;M9?o5Mbc%C8<-g<"Hiɗ!#h!N?\g2!MhЎG+{|`M6Ѷ f"3i #=P^"Y/ZK`_n4~wa^$m'Lh+&a0_<:J$ "|iC,!ִd'@`yىC*"N_› :So=VE@AЉ˜Bn1>h DBS5pn~nA1fn2 98ҩ21'DJ<9"խi)q/'V~F#uLta!h&fvO5hǔ0GJ޸b9Fs&Ļ6ZaKĒ7 RDŊXP񠛓:sxE PBwj̊"+D>#w}ggYx˛o)}˗,[9N.t>c$Oj,H/""\pAx]K_fX -ְa(xwMb -}7短5=饗1Ih8g'Ha"lHa1+"&_%A`Kx 9QF / knrqH?sr]w ?t)RpfO?]>#"ʺhr"tq$}&o~!23gδfʕN>|4`QG>:aũ{E@ؿr⭩)"ph֬L3m"N8.={m۶ҥ\tEvSO=U~1$͛7Yme…t[tcV&/HOnw5ؠrmpΚ5vLYȰ۽{wKnv9윶?ޯ]%(tB]!?p,Ƴ>+/ȃ>hŹqFkWti]n5z!K1-HƏ=VGN9Z^̏333mG"}w ĞzU2h!B'1CGm8,jih!V`XHmv/˓O>W܇ ;N'L rNnoVnF1cL6E0v L${Vh c[,vj _JC  0@y% @+=/wl`_Z6(-Hӌ|9?*pBi+huY9b{m밢-8pw}r9WrƍG0%B r)yi$''[- !{뭷_,W_}˫u-sKgGmJp/lsC=c:e˖Xkj;A D)jժph*20 2B;Μv[ D td.(Aqd7AB=X9BT֠|q- klu rv8wqcAv݋$|;BfX%<$#0G#bŊ} + u""3ryᒾq$Jʍ}ϵ1)"4ё219ERJ B4rHʕ>:ҹFC74h`ҺuL:h}F4%%vj퍐hI-3]Pe14mR$q sYxv_vuLD_~bp-A6 GT:WgN5ILv!Z s0ay :ֺES{K`+x`0=_+X `0 Cq"gB9eIJI VߋJJ2hIYMhĊ"' ?B@!ZL>cns-[h*L͞D(_tIl': qx0Ud&t`sK 9EsDx2?_HmqA.4$xvxD hz Vҋm\w:A_JCQ7hi(u_}KI-&o~4k\SN9ᨬ̙D6l̐R R܌!J)*>URV`î[A .U,̗-ۤSVY"(E:pX0G+^v .$02ɽ8 #tu`B&Q"ҏ%_<4X9JrJ&Iq![Yvi6xtn *Kx"BA(_7#+Uzuk%rcK֍d_dArINPҠqSydۖҺECs,wpcY~\S0#ٹcܡO+"hqr"똢} "KYtv;O3Nj4!Ϻ ɂ^V@NP3yil5!׬UC*W(Hme%hybh<ŤBZRd,']7j.KW7%}CTPE0S ~hO9[KbR1Jٕ`?Fl$X$bJy d 3 ^j[4m~ȭ&zsHHsPdsUNPx#D {toGN0nʦTndC:JN9 VʵR!HBF3}b VcUR'ItI2ULxדA`q$TCkE%sv)i'13햔iȤbvǣX:'ɒQߊToCuғZoyjɏ@SE@PE0 ~D Ր1'KV0/Tmw{OcxcOfz4:i]o6X@Yo9c /T-\ҥKnݺv=?FFR߉]Dz^ܹsOMcTE@_BވˇƜuwgi՚RRR:YJkdց N+˔˭l'+̣(4ؿREPEp!`fla{Ði;!.=C^F*/%?#t(9KLN^SZ5o &L *ebV\I9~ڛ_ߦk%.-d^*5~mϗ5hRRHRD)Y\**JrBbrPZK!eo%uzcV1jIڶX|u*6Y|jY\h?VYf2yd6l., L2EZl)O<=qA3g=+Ok5q6XظY!j.?~|HHy+,9?]~ŊҫW/2_2e}6Dַo_'7xb?lϧMf ?LS{!5  m Gy 4^[z%`ضm[kl{7Ϳ+"s=]?JNE@P|@$k>6Tye¤3hBYYRjҲjJvb^>ТRzE,6)PԬvT(&2"|bX3bG|>Fnv}BL-ZܩTo]\d̐];ʮ[̞m݋.\n7˜zo}}T9CO!mH4*qlٰ*̐ Z"׻wo;?O>a4}t93Mo| k֬`i>lK@ 륗^ʡtI}Ym|^?vҳgOS7,cZ-(]}hz|9ỏC|ƲeZ78AS[oYSXa:ҥ=Ds ќ8q׾cǎ$$BZ;TyxLI-2S~z6(0!?`G\x6"x:u^|oĊ΍fϞm@B(!*淪 ؁#u޹νS13Ýs=|@ВxA m%GY"2)0uB☣#Ln)!h2_s5a & c'0lP dmԩf(ZPhSyk׮<3Wnڎza:S(3g4mf(S!~8edu0?Z hjZ7h><M>X:q8@°aB8ck7WKVmdS{P9kJ֯_E>tz4iX;t@0ײ#I{oJ?jI{3;WGON֬X(G^Zp$w&WvѴ]œ;PXgyБ潃) #'}zmE6~xɆ8Ѧa^!xGC Ȏ`}ȭxbB?%%EWÙڢ{[OX ;*˿Hzڟi>5Nh{ǒMk%5P|Eٜn0?Sp^K!p89OzBIKN-[S|F3%ߥ1-YjZLR~ᢅ2-A /A9e--bCk4YzSo^a=.# jF'I7m485zNz.nf\eƤdut8=KG7|SX{=#'p\xa]j ?x؞1cYF֭+wY#fqEe+&`)QWE\$C!8 ȪJ'Azʳ#?ME)59<;vʯKVɨ7ޕvb%}0\oޢ 2D.H|r{XǸi_eƜ2/B LKJ,a`;vyk@xN;4Ve ,Zoy睗godԨQ2x`3H>;9!?1Pyٲef#F\~iQ{rGʕ+eܹҷo_yM5Xi '|"C5X&١CqKZd֬Y z+C|I'd2͛ / y'?4eW9/m-lӦI2@z)sP>W]u/VZɣ>*vLQhC!p8 9EmMt(ժV2&G#f=&[rYn 9P*1nu2LzARX<;/6dTّk@nJyҥҫW/4h@n&5d̙cLK XLG&qIC=$+V0D.3y4ϴ_].\(ݻwW+jۍ``S= $"~k?xC|,xnFK/de1E Dˊimm(|N>dsvf :uc̜93fn!p8"A(RZ,rʙ#ڐN |e25䬳ΒyLU p8EHD|qW r A9qDCNt0mJ,ɃY whեe˖f#Hv*^L]@p˗{͜E4bkD̡Ib/Gn:C|W7'E^`C!p:O' ͥMwCUVqa"9 B;Ɇ%sqz<)~駁z;SL<4&;INL0s /RcN<6m*l^!ƍTLjO?t䧟~2nl .@ڷoo"84s7 e'Olh [|7.^X,X9׋ͧ Ğ9NC!@%Aø &!(@"!h7<7p8cnujUU80`FC)0矗~ېC,Gpdr )qЕW^iLd)ek2$߻woys+qc5Dl\L@1aj%#p僖98 Y$VHV\r#\B aذa!<1/W|@F`Fӆf s )M11#'}zk ~73c'#8B|,M]%MG&PsaC!PTpC!pdU1ŵZl'.p8#X:@l:qgC!EHC魐w8C!p8}#gC`"8~qp8C!O/|`ݺu 9a >ڴiuY ,o3e+`ǎk 5+'N<2=!"Gu7Zޟ3gYs!?ܬ_N0X S~}iҤTRń?īW~6Ȭqp!.q2|p$-vlYh7hy"cǎ~GSO?^Lߟ-^:& k=KU+vmWO-?4<]<[ G47_L^MKG_ؾ(!8AQ;Eo%H˰ƕMMӐLMR @j(#;v? 8Y`. ^zH.\(=zx{l~$;۶m?߬fO7:=WPY}Ȑ!s9ro,3DQzJ{a1+¸1bD$;.C em<[x e <#CHx@>Ko:yBSN5ĝAx%3nYAC=T6ooVE2k126yd"7|Ӽxf's*0gw-v,͑>[ JeW,51┝sqM )l3A.C$x(r_Xd>lݑ o&Ȍ"6'e>XgUoJf=j+C!?yeٲe쳍EY҇6рq1cƘqQe<:}V2g:uY})f-E] ;hYt}f};/RAoܸzr8 yM]pB\e޷< ϝ;W^x_Mj^m5k*^{m^$]|@IDAT=K!@vG dX1wyYB5ʼ1fxrf;?澡|c(/@x'w-2b w(CRꫯ_^NJsxzWOJDN1ANh/FhB2Bs:}V{?d&n~xe?EwC!ӏȪ/Si(rmI4$ckjyO>iHkQEVv2}kN,Y"tz uhXL'ԩ1<~\* +w1X6̘|J^/:Vse/rB*+ҘEI߾}w1d |?ظYr|g h'(GToݷLڂ0l~ &&&f[˝;641̿4͛7OZjeqq YtDz! "Zaac ݭ[֬T L ¢ys f͚I2em۶ `!Rƻ (eR|y9,`ѡCsQFYKΠ";^S9[C 7v'; ߵpo"W"IG)+DZ%"u撻E>Y"[5˙"gqEg |%rʾ)ܞϘsƣjVogP3ˌ W2^G6&;4YG\ #?̘GXsȈm]xWOʐZ >;SE#ҼH3q8 7.%5Sā"uʘ;r8 O؂\xq?:aׯe2ǘ,YRMf۝y晆0'1b+.]NftŵzA tt /c)7aC<*):!=W{u5c5j[M,cܾ$t$16ۦI{BY fNq ۷7AfGh.(D{s@_~1vm~gs_B05h 3wn2`ϼh;瘁?LD7n=ǻsŊ|asNc m79wW qneƌ4^OJJ2[l1NMGqFΠVbԮ][.31sF|ûm.# (2C? ݾ=̨ A8:gwq,,ъBUx}%+3av.t:G1a׵:bK" ,B?UHs3\aoLJ?Z;g߉>"/2A^TvkjR_{ϤUoeJ'#4մټ5=pNGD.2u$ӡ,]ƣ|wǐN~)d btl t80lq̯bnOO?dNAp ~+\O`- &tx0e$# d%8kD 2:#^M:;BB':YZo1-JBǺƼ1z*ܟ-fcӶ&b6Igpa֬Y~FRE**fB|6ڍ֐FhD[n1W }^_Y{iB<IhF+d`4Ç7!>B̘w" X癁:a,,Yeo&&A&ϟJ RŊ%H"(QGW ăʩvYNn޷?ZQ7:ֆMk-I:!sO?iX*Ydv(S"5;|} ,lzѿ_L0dTrFJ!TzcHw(oj?hHm;į3cśJ;BBG4=Qpy2rQ]BMU,4+B[͞4@nF󱇬QY+vsP# +hE0^36kQkt1)޽{g38ÁƌqԩIDίChNSeBNěNOlAN)X!4`c=5ILs gZA-;9{Ӷu{0p$@j,aA.>ӐBάVZ:"ʳ 1.3`?߬,~ &`1䐁7H}DLJQ6ޫ38OKyߺun`tZm(sGr2́fׯok\C1b74Z@,.M)9hԟXXUe`1( 1 (<*阇%J$Hh3WC&LZ}i?ta">zjN7?~aTٽy<>!+WX rQꬦF8^S SMgsTCP.kb "E{J=V]үVQI}%w3~(&N%!ϿҜʐvJBj~ҹ)! uY_$Bh%Ca:o%5JPM6@GbC:2R K;3THlH dHGC:2R`HG#y̑1vsRB!vLٴbµbίjHM@ͱ: iG*r=q6 odӎS|ANgH4ESz |mB}T)~a1#B#9d$m#<;q K2=5,OHJsqᇇtZh޷UT18Ԫ n}N3n6.Ys{UĝWI{T;!%5!kըtp%`)i qd$-ȃw.nHƼ(j-oE,,̳9љf':~nMS.'yKɑ9 0'_C!vK]r,XN|#6Exe8'C!FeF(X82tC)!p8C!p8,$M^ :r5)WMw}'YG)vڴ7 !=y!_|Ktc+^{;f9{ Ԯ][tUy衇"Gj֬)VU{U#\}!Ppk& [jUk҂1ݓO>ٔ SN$>nٲŘ\^2?<1[30)F}7d5C贷on4xv0FNy5ͤsȘ2b∹W^i-j_K@pda ȝp<ӆp2X_y$gaڔWnpA٩Sz˴hI/Hh_H>jHGm=: *Tl8`DFs5 2 R6WGK)_9ï QF y WR xND`)J{w83°%׻9^4ܾC!(Wڍ3Dg':^Mlٲ& jժżjcȆ$&&!+ `JN($0ZE[xѴ0bXG%"p4^ /=@]0e0#Bk ~? D-6mHŅ8tpN'YGv>a۷7 -(f^ei2e!A(+C3O6?g>(D-* MfczlAş <:՟2T;ϳ 8G "/-:w(խ[ w&>$3$; {PZ$ܯC!(\u]w %8A#Vﭷ 07/P%yb~F-& ''f[I[Kqr}etJcGc>hʡi+yAAÆd0Ĥ:ibG! h1s5\A>>쳍)-ږA`f 79:4됪:\by1XrC;7n_|1B{;v(ۘZ! >1FiM8S:x}Ekggpd “20gѠدw}X XVAmfv:;klGx17J/n!p@j:d-:pmV7 TѪXautX?O78ġSKV\iHs9tz1}H583o/70OZ4L֓2hpD|T:*Yz,Xc\94Lc. q‰&h备c=s34ZK_ īY' 6s) @c'8ҁ3Cu=hm!D.hG|Gh G~8 ~i|6p1oY uBzi ּ7݂y"(nBnwsrfGrSN4T>r_i t@Co>kX`jS$}҅3l2Īnp۲=Oy7/( DG}#EޥXn&pܑ̓b]Ym۰ߓ-ۤ\J^/B\"WtnEI] 9.OТʉ_,25ELRG4`!h٢%(<:^qn  ,H Z܈nh!<h $yƪnp'yʫy}C w0r'1Y*ժ] ߫d R{+\&];MF%ӝ웜].EN:vt7ssǃڹy~\dF5i2p!C 3 h(YJ-_'%KHe굎Pf' TkٕC|.sɏz>uDި|}ȥ/l."`M aыl]}:2E؞ Y'so,])I:=RmJɒek|N{as.0p^@^TI[?[Z^RNjU-)!u_1Ǿ*!p8C (27'ʺM[KhO$鼙D%%K?͗'wrC/_ϖ]G.p;F[!o ҨNeZ!Qʔ I\RT)]LNN^!vep8C!/ _X**UHtrG4YHIÚڍ; LP{AfKꎝry^&~NXP2gNm=QnPQ5YJ%ɥbi-x-ٙ]vl]+ɉ$^9σ®]i!4Aho*`H"=ӯEivɬ ͍mi7 Mgh4$;S?oj=;Gsns_v*o+ERGUnm^%B췽6u+C'y4si"] de&ʡjJ㎔PRrTǣ$DYٶ#U e1)Zʍ) ۥ|ZJ6߸~ۥRe/5.v+ܷŸ(ekrz,%ʖWbYF]Η,I_xUhZߦ@l[PlKIۖnP(XgUoJf=j+rw&'SrWҌWSț*V#uk-_-sN^zճ~nkP{-hEBCyYD]lݾK.0%TtzY ?]btjSTu)RBØ_ 2gLK Zv+McK#իugwܹSv+iܣZ={vް?yy\D 7\(rS"=1Gz^|;[q]fL"ѭȓ)BYZ䈋d޿|fsȈ,iYDӖ\p ip3U="{4SkOov?.%5Sā"`S_tٹ֯WMisH"OPKrsJۂvT5+׊3aޞnk/>'^Au+_tț6hޤi6du}p3VzVʜ^#Z{֯6/g'=.(o{/De{.ߖ{ivxJ=.@^|kݕ4Hɜkd{d1_PBJ!%L%IJ"qVZi %֤n^ϥk` xpRdd'δJ&7fl R6ɖ-j^a;vnCrHvr!EYO) |IIH(U8HV~~Z*.:ŃK $3m۶͘YTvݺu8%%h2197nԯ_,lCɊ+ ˌ֠.\(ݻw oҾM^rn%ZXn0_k[o߾jRhD7n(3ӵkW2dtE~$n*D=EĆ%g~L |mYj={QpґD3c7V])%rs"|Tzgp:Gټ6÷@C?PPAt_\.7(w*qzCcBrqZ.L,ۈriS{*+?E>-0EZz"AmWx -.ЁGX{VLV-ԗ<GPAe~BH#1C'5\F-׀"&d>W]p33?+\Hzu$MQOP2fŤIjR.9Q,NDݰMVQ;aX$٦;thT w2uk\@mduɭbf`YCɄD)\UIh6I~ m$#t:V)=+MvQr7k=zg}V|A:t7Z^#UiG2~93G>5m:gxF#'Dٲzx/]S:h[6cS 74'uPd}O eӉn?xlF):v픞Fp:bg~ul?M!rO)Al) =lI{zIu qՙvk,|Su|6jeO ÂZf5?zϯ^+/ڠW}OK>8zf?;*䥻D/Rbx):{엟_hyZ=I?tN}7o)2zWұc;Qͤ­,q?[䐪*e\)ҏbƲifyƑOe"Õ{b<͚'}/=P4*pV@&b8[rXƲu_J(R3\UR-J?Tc$.RL5{Bt'Q8}$WvI*()+v2w1cLDg !}YIٲ$ ժUy:V^]Zli6.HLL4:u'W09 &`4֡]jKimā#6hT!k׮5P3CYu6J3IdMOG1~뭴7"KV@pC !WEzdH"SDdjecg%Ȧg" ҿ%֨6%~)h5①]\ 7%RԆ~p{td# 6;ћw~PAe%]ZX3*}ނnx)\_OU^+%K%IŃJ*ԓ;|zL0s&˨JdݺriFC|xc[d%Ic.)[Fz)|)9ebL~c<|+<|4k{g:o:uUewȎuK$yw)|V[v3URHnW;H7v'7)L O3# M^/~0uױ`ɼԩ/z͊a񲒠ks֤Ng뎭=OM˄W0Am=]{Ň颱[k%R2){xaַ穙q *wPYgթxk1$L+rR{}ނnޫJӗ)AMzB85C7^Ԛ`qٲ=MUb4\-[oWԮ,̓W u㾖:Ke !ݕGhB0 j$NW,tc!-:\2hY;Y6lI?x;'Jɪ+K2rZR(U,QL]YZ$mٱNfjKBR8*d($saERU ڴ#'}zmo&$. 98覄:,ˎ0x۴iUZ5;YE0kJB̩Pt=pQROTcU;Z]_񵐒3'(P";6_=Wޝ%PƋ_0)X.lw>V[r}t]KRSTM]GT;vM6ֆSG8ש)p+6XuN#:nznٞ <]?+>: F%5:EM{{fe}ԆhC1l+#4*x;;~id'̶}fumtb0o?2sLӟrG~[*}t~OL7&%V$];TcYZpdĦlIѯ^ )RtNedJj9+V+T& Ú8)C1)[:BX\Bp:'-QjL%꺒IڱܕV19qv&d.\ؽA\pٽEf5eixRB.P䶈Ӝ-^6/ŏL>T2T9Ɍ@#d2G履ϼwIeUC/5O?744 9:|_Tm:gá~qâ;s2Et_pq_z~a~q3Nj_ g3kdo)eyK1=2Q2|\Q( eNjX_3GGܚv\#))[QM*ULvUU¼L%boV"r_J:[}5k4c9FquSBVJ=+=][ =L߳{Z /J})Ue fx:EZL%WK?@̜g+;1+:h0wup/)ae2Z.AUҰQCIؒ=LUܶe4W[n{?,_t?Fr֙jN8?#-~ b]v2n{9Yl gN@QDH?Z/3g.4݆8LRȦ2h*KmWShaqߖ&ϗQF;Z.cƎD{"n'Wv|QG*Co(= V.5\TƺdIuNd)4}R"iJ,3{m4_$-Zܹs_7xyIV"W^1ǐK+B:w,5k֔o=& ׭[׬61H>iݺf\ ӧO*ݻwEN=TICffh{ҬY3A޶m[㑛 *Iɀz=}1/#'0aׯ7mu饗!"\rf ")"]tT\ nlݺUb]Ͻq'}/38#RV[7nlr{/J˖-Ƴ@\#DDIe$'"+٥f {ocB  2ছn23E fϞ-6]~zwy0xbUqGjҤI$ n5'/"M6P/ ?z{1}ٳ!MAD > $QNn!p =,$[H҉RBi}2i2{AHرkGh'L`C{mO sG[}ԩSg=Z4hxTP!dv}` X/裏22 A 億}ŽE v2yG}y!3!pE2O&,d ShH.U6)=h:.;v_Qo+*IJ֐YAϲ߼Es3}хE;2";r aK6 eERjE]R=E=o03&l>Nt fVg%e˖5Q XZY#DšrhaW ZdɈs!"',x wюő03޴iS 40@ z뭈Ư4GKHƬY $ )D6P)SUVBz)Ӂ\Ҙ-h  -7#A1b11ŤS[̼Yچ"v  h9~i`Jz=6s ʇ4ԕ?ќryرc6P'M +B &јbffw;"@'|th^9f*WPa:RunMi/rw~kz>gIeBժi=! Zp[>Fp5a֏y*S!8GA6i S>#LW_5[0H?o9͠ [H &^{!>x≆bj=G=Fixҩg9[_Q\X6 dZ4|8܁C+0eڞk,WrYdPX@3`ed`[o58x?8b~'NA%Os p.~Z ' |vY`1&ry7F>ğYg*# jFͷ,?X0/8\ =V"6%tSȯh蜃s?ls>7a'yA'MVh(㹎hs"7 "`5$- 4ݜ@B57J[ˎp=A߲gpƄ*F$&k=bnXJtR i2E\7l^l8|PqbR y{-.1;%u]%vOy3\ v.V3x:U'~tANNF+oV l9\߱cGmјZsUs^xay-9!\>;B%R8"E(Hg~p8wv8˼f7D:\!Uo+/@a@46ODo.x=uC! rڗ(2,:G&B(ϻv#njz֌%=9 6+;&ٹu8I&nd7UAڭ Jer5F@nt;C!P4i?"#M!p8C!p8P#]6C!(l)ONC!#AȸpC!P#ɓyA,`?p@| K{og;IoyYٳMX>:ˮrJyǤ_~2}%cڙ`#++V0a ot]r&+٦M>޻$G^p8#E-]M@L <׭[7bիWѣGǼ.'Yh~ԨQfwֳb-/e1b%"KTdDzR,)t]y_ڝGzDꫯr~ᇑoфex$Dvhl2_NC!@#|5|YtӉC!P4~f- VZh!sΕ_ݼoY7ojJqscҥKW\!;w5kn񇅍֭kֆD+$|nZX6rOM$gӦM!ڙ>ԃ}O?ڵk墋.tNMM>Lڷo/IY;8S#8B~ꪫL \r%&jg!Ǐ7?TDe:tp uօ4{=i֬)SFڶm+_}10<XǑvFJ*%͛77y]C!p"} 4S#>^%֣SO=U>{Xh~$hC:ӦMYU]m=ZDĉ_>}] }7(/Έgg>W_vUCVz% 2榛n2ݶm̙3G֬Yc׭[g!BrrnܸqR~}p٤QvmF:u҈(3`Իwo$Ö^{M#(olٲE+ʕ3\pÌﶍ׆^|wҩS.!p8d"|X3ꉩѡ*~躿_G/_*'PEQ7m]ZWWWwVwm+VtHH2^^MI&! 3y[~Sv_ ou_ 'd ,&5"yvu„ n9IA~~ߕ1,5k̝[ctx.^{_ C0 i(uyǟ\w?@1|QGCotL) !6D ΢4-&X/ӷo_9rd2%c.=;S`]/'a6̺L AY }hu4k̜3`$]0Ӎ (BH"[a֚?ĭQX1C~'ұ c=hЯ^m1ӣϽI1;3yV9[𙣾Tb|^1e]ej_?y>kz+;:ay-~AIꫝ&}vS ra%s}> ]{NC?o,={tڴ~;xKFرcM&H۷~M&, 6ӱcryp/~Cˈc*2sCso^ħrD8zsoB"1 |{$E*'T%wUv0-ߑ Fi1oUXRy,u.!`QdL(1ل1;|Yg%4d@l.d M~\J*a-e\tE?!B O>/"q/CDŽ fbC B`nŏ2hC'3tàx! b)wRc0&ÖCv,Fm嘁x &Ֆt9C0 qPI/-S?# MLAbdKkk9L{EOط5;NL4igJ#xn~/]/kS |1=*R "fzy ߋ!Q_r!n2jwu QXhj ?~TlSEB7-+m61jI$FȲT4mT4L~ү ˭;tG/wL4&!`@tSRox =./,eLgYc񉩹kLgZ]"5KF'qFMX}.c8eL ;`D!q]gScJܯ&sXIjDb]'jf^}u9ݾ$i;wN hLE1%Չ4~'XoΩ&7G1 әgkDQ;T5 +f:><.Լ,_>kOMbq‡g Y2񌩶"֘~6ը1 8E}D;{8WRH|^SȤwt@S\7ը'E=Ǖi$X!:ӁvL58w^ɌK?Q%,1p_׃'D&UIN2tY]IQxt͕w.U$Ý.UEt,Mާ1h̺hwuHzjrrV,Tepvl!PGkq6R|G;0~c<ɘsG*0̈YQYXfg3ԼuP![!ng"`g l:OY/>^g֙ yJ VSK0sb_ ӧڒ 9lh%|>A**+h)X8MP* q&"(E1\χtaג / 4Xabkm}B]ƛg_z&u/Q4:$U=94Aa-fwAӨ2Sr }@*T :sΧ2_ƶ`_ Zi\ !ꉶKd5l%Y9HUv8}= _cC0 C WdL(}3%O($iOjA)FhTZgcA@#+%L*$9#|cWeA>T4Vva' Kv]|g˄T#H o~g"rQwd? N{!9tjrk/:S8=@Ls`Lym C0 C0j'PR}Uu0BTE>M&Ek1@ӆ%L /JskOZ$Ab0 -%>h8D#Ҡ}'||dUA%K&-)Au e#Ƿ`JZU$VjF|+>nzۈlҕ,sh)œ<0'>+2+xAR|<l_&u$ 9BH}0E=ٶ@S_24gS?C0 C0 ڋ@Ƅh>;Z fnv3m25ޮ];$"?Z58 Q .=&h6nF/1c9M|0%7#&EԁmCm6M\&)bׁSmoVW&4fV͐7WvR/[H7=MUFA<$,,M&bך @Cz&Nh1E%?mDK;9Φ=`&;dW0 C0 CÑ9hl\|Yv-^63g04}|NCˇd!Ɛ 4Maɢ-uc}^; D0CK,O!~~dXUd媌T<+H-RݒD%-ڹDۧhyƃtqSw׵mΝ&x 4[{_^&3)ĻqCS-6̵cMtoUʰ{ C0 Cv"]XxHp-[dJ$Ioe/KRaMS䪌T )EK@!7AKM/\fclS8m8;GH?kG@E%nU)6d Rr~C0OdlZm3Y4R6npH Gu _#Fp į L{><t 0@>eoBɬz.ʲ< CGD9'ʨkyY]"o@:uL@ԵI!7`L1 @JV6bt Z|x1aK]5Ys$ r/(,wDoIBSo~Ø0g7UT!`,f Cq\_4Q$ܷv;&5iӦ}e]bW+]:CM b曲v9QeIv^z%4-x?Wm坂⻎K^ L2nh[4ݻww}w$3@%$9j0a>l0P.w;Kzyy77Ž{С{f#'?q!`T #n2 C"bMnk"h{-Du_743Lm hD=5['N(G} / \e(Ο?ߟv[,-aݝ}ם6s0K`n I~衇\T*W`R, 4rH5j#r>4\s;>W6 #A0G+/Lnps|xx;&)vCyv|AG\H7}twX yg9iTl0 CRlv!`u  ipt:c:GB0|p7ؿꪫ0 A`P& m`٧3fZ/I'N,qa/AG}֛ei+bP0EENI;Vnz}q{[o%~["% .Ičk? h!'OvZjLY aiu29M׼ҙ,ZpP!柬L;g!#q!`[vaQ"P~v(HpxKrƎ4=+F>AG2(^H(Z, /;촟[`}:)dilG+sLQz)G,:G !<bG0LNǘ,`̲Xh! d!,́:PnXx7fF׎ C0CL^R!PDHS_}U70'X D7h2^9L 74Trx 9~pq߾} /L>餓o%*zMi"A;UWԹd,BGgOvAwsO9蠃.ip rgHLTe|vɓGc93ZkA2eJ8 whcWV8殘{˄U0 C <"E? '.{jv0 C ܹsvR BCB0S=w>9e* ħ%AX1ʏ1qdpF.]4܇$}4-}e'sYKE)ӟh9?d7QL&@#${3lܧNp\, CX#Xp.߷G#Z \҉l-ٮ!`yWFi >\IeRչ_ 5l2`[D $*\0 C#`0 C)w&!`C0 CVLV+!`#[R!`!`!`~6וjsdيBiNm,ФjY C0 C0 CXl0rʔYRָIsd%ҡ} h 诤,_\Р2HC"S 2F5GzCwO< 4h,#8gk 0gytr[%7Gh}i5=! 5]6裎еCXSd5_/qt4 MvΧmiiLNɓVg)"oUȀ-c2<١ҬءOLi`룏|}\}gݫl^2yrY6LF {"lAZV=ZWun7B9~LiԤLP4n$[sΧ+E,/Q4#R{,O.c.aCwX߸RW>FNBT嵷5U&&J.E G>C%X1/,_["|*l2WիWK޽enR"*YZfTγ?<駟.y,sڵD&M$gvD5qrKppUV뮻r*k Oμ^ۧߺlŷNgZ?嶟+W5tj%8;,cQ\JYwkʽǾ`]/Z^>+B9ï_nYM6[6ڴ75Yi~S:}]}.ml,دpe B76j)STS$*1~`[κxJw?{xuY! @MreHl/7_h9#  I}$X{ӂ d䅲pE"ޕ}|. gϞ=e̙+{lY^O/حq>aeK(!'t#O7 V7tOkhUL3@32B3f~3'[7AypYXP({q oT94WX|%OuPXIefMKUeK.o~LU;賱k{ +͓Mڶ=:m{٢G;֝Z,2mvl>&pHP俊t<@?|ENNdcD?oī3R&,O-r!=jI__Ck(r"U^G \Dh*fpˣs]@<>Wd$Z?P3D8]u̥"B^T[2V䩷LyH;W佯d]$Ƥ ekG*O= /('V4wi1d]g{={w4Hܕb~}g.ͳ[w>=jOKMzUOr|7d6gwR[#>n{R1Zz'+V;2Xgd%|\wE.R3Qʹt΀T~WO頫[lյ|!o-;+Y2~_PmVKwTWJ. )ת9.jCE]"= ; isSL|o|O֟B"]m<( D៬w-[47~VMڞ+/Y} pL[1crkmTl?%{y쵭XB%:|/ᾌz=;,&{@28: UȻ_6 Yk"W+rLvDýa4}Lhk4b,hPT~CT^LTƃŷ ƺH>o!`RO jg\/jRfmw饗f\aH#7>|wekH[2<߷d1c8# MC[o嶋-^zi1D0&_]#G:RZ/xbY-Шg/Xp\>~~v}쳓Z;Ͼ!=NIVWW6֋'&cNZ54Hc7+sΝ; 7 'yWܖlj "Tus_~~u m]>C q8&ZWA<,}o\z3[Z,gzNJ_Sd.w*Twd8bj>:KMC{\dӪ\OV3wN<̶U{ϝ2:}uɴ-h([prDdS;g8_X?qzxNgb 쳨 esIզ`eD!ٶ}}Qd!Tu&8_/eO+<,o&jr|ףk[Y8Du( X?1tDSҩ8yv`{vީec)r~~cT}Sf͘f̭d]^~WR<( -XV–˨ʘo_$ ƿ @CYcSǗlRY]ƙb)jL{^N|li=fG :nvRZ ZeiXcͩ#ky 2u: %D%PODO;UuRAsF_d>Ao >}qtQD{uxDͤi(kO>d4|!5UݒAG%~KRPv$̊)Ž&3_Fs ]tqモnAN1b#q/-ZC9DngOLj4ϗ[o5߫* E>\J\{HS-P~ȃjGdjw2_50A뱹?Hr4R%1&QuHSDro//E+>J7Dt{<lnf#QGl{og ZJ1IQ4{OOEn,_[?i M?%{yi 1:$Y$˨.ٳզ`] ֛u6"ٶ O/s~ ߏz']]Xj͝ѯ!'w\wux(V|ݏa,[IN@lq|Њl4}{wVkPŊ'vl%vJ^{9x^ҹңW5wJ6I7eS&0]>tߺ22_d=eM:M_N-NV5 &tw,7ǝN4C.8Zf'[u?LvPoeΌYP:>պuHMj@n]ˇdFi9y'SNq#΃>(<#B:ԹsH[4pHLa{WK&MYLYi_0F|D!Hu?Q4^yYgԩX}衇N;mH? K`Qm LOUEN?L$vaھv]qdSf?=^fƨ%'S]^oD~Mr돧wny$6[fxw-w]'{wN]ڮC( [nt[F|񜚖7OQu%7w,X:å<J7yeUieС:#    y&&~B-ڤnݺ9EDC[uCS^y%}Q~#$;LC6 bN2C%]]3LFBӵI[u$6 Z&X}چ/ɘ<7f~s.ɽ*p[%p~cTmՑΓ%r{Z\>Y?]~x {0璼ReoHIA * 7opi-3!ۓ=l؄#L2 %p$"La 0sGٍ?򇺈N:[\悃_WȦ[LWK8iR~,Gw|vCORݴfŁFu滟1G \Eyc<NWk5~*\7DEN!/YIak7wL~NZn/+<}KiӮ#+WKN(ПH35n_RvK%VTJK=,@%q1m37;u@d]`٩PMT&ORMy_f֭ M !B H_޵]*I g*he*(BhaL놦 k&R2IhbԴ41Ãuv].d]{{έZ99>#y}>LiM>?m|B2~ u)]_2^t_&7չ5ˊ.#*pq2kfGyB ÞKGh<ꁼR2.5)$ﷹ|gr٬ӺC]536W8cm[6D^z-K)>[uQJ'ءMl7տ cZJ}H]c%˼?D1,[ZO^-E Ru$dRbi[;ju ټCyd1RZ`)_cds>6QN6_n%<[_%*XybZR )I6#Xgm|qa%֭;;>h{0wbTz<{E~}IBXNzWܲ5h-}!$eђilf#Y g92;j6d:#m6i4i٢z>ri"3n4cDm+@b]AQ^v/'}"Wȴq?Kq4oXԤ8N$9_f-+!dݶG(e:yY} S|ɫ2ewRѿG|3ퟆҼY 9SyHA>->Kfp3)~K`b;@]Dd^2IZ?~kFlթNiAIf2L.UY?rj&vUI#4DZ^zcMCڵm)̟TݠEҾuGiڙ5nݺUDnv:SPˤXdU凾c.VɎ7.H^xI)\4T׍V.Ө͂j/jWuQi 4RZNڿ!ݫȑo;TIvrgٹnG]8Hϗݎy/A;u6˜y?_&'8%dRX+!`!`$\u6nG,%[tj#S/e%J&)'T"-5D#?6҅Oe檕TU|0gZ&eL$3JS]b(0I.[dIQCY8}yrġʦ63O<ͲdB^;}kb nj#,R?n|v^~"d̸qdvH$U.)3!`$ܦo8i|1'GDZ %y+s WݻȧHN[j!Go;d"?PNgROX:IpQgʾ' ݯ˫/='SLeK<gNh}Fry'kQ9夃йR|gƻ˘/?R#r]_K^[ |e.w.|`}F l{r߾}d?Xzg"}u׹?R%Љz^Zz- pTfX¨2 ޷n E=C%CNZ٭[7rbIs'Y巿Mui `.]RhǏϪ`eI_T6,˖m]Ri CMIB{=RL Rm8豙;bUO{R{ SIkcz. IA\Q N˸qkZ82#"YSGFRݫS>&~6JK&ݷ:Xv߶ |,/B˗/>حUٳgO^&${9'|"?\|yaf%ɓN:ɑ5>'M$7tOI}Yo2 ޷뮻DZ\ xF^|E駟\\ve3N; >5J&O/;O,Xm҄: p0 :@|W@۶D.&_ʟ-!'_~5AnkKǮX0!?I'c%0:ujGvU<+dBm7M&Ze"ZKR! >[Zk\dycrǯ++ b)Zș=};Cd9w*68SzJ_ҠATnsǏ?; N6}r衇 +27 wSM[l!^|x7ߔNX_|N8&믿C9vX1cprE̙nfw#zaʗ^zI{9m!v}F+}&r<ҽ{wׯwqh"9#4Buw}7SC&1>h":iv駓O>YC%%%YF ב}c5y Y8֯5꯬Af|R>vO#g|.BŬ*@R' ( !NK.ĕ_XX͛.\莙L`kG= I5k#>gq=sM6I3qDG$z%/si1P`~1ǸޝwC=ʇBFĢ=w}\"CL>]k/iٲKG=0ITq6rZ̥Kij /r}Gq#&_dȐ!&~??~<;{}_~w}!k0.WXU}[nh#s,0\-kH)Ss:q "-.dR$?ṣ?SU>hy}npL/W:&z#`ap[nryp_P&&p݅Q2 iC0 P趙̚=WgvitV5?4h)!KVɂy+pYL/~q2 rϽDg2,ְnT wW9 sa XUO)ǨD eɚR;ݲߥoO9ϩ'(Nμ IO@rD'*Sgf9K/4*i_ W_}%Çw㪫r@( ܣAC=uDk| |뭷m=b6 {gԙgYA[BNѣ㑈 h_Ww "ꫯ:bI'(QLUEvW8KziҤ@\hGڑAG}$4vDɤ=0nĈ`u9nYm֮ a*9&ݐK "3U:urrUT82 :H(l E "D D${TjlpLU]3 Cd3Q'}( |KܮH~4'Ҁ}9Z6, lÖ^W7 !P]T\jH'kmK9iiBtѰXc!rj!X 4.imI9nIfk0[L_~e}@|@ d/=СC>!L 'z]vu,wܹǐe4J]RW^yřBn!8SwQ:h1HǑthMf͚rdV ji!FzdMC6A|1'9JR'Q%;V1DTHy>D Mfu^po2-{ÜI-D0A#]C 5(svk.cyڱ!`D ws녆_l۳v.A$_})S\S`u0aai? 'zc_H_qRE e dȉʠYH}ktm2k&>J0tĞỖ+f}F$7Ǚ~GkuJ43h0EKO?$],4+K:&|&b~21!D?uY(4 }C<va=$Xp:- bK} } f`4m>h sOc~{J!/dI/+-Ė +V1p܂JÏ4V#g/W'jW*5 CHI䰞^! Eꇇv.3QRR$jNJ~URƒk)2isgFSNȬ5k5 󢛒d} ]u\AcѴY,uT " G}5o i۶΃lۈ0~sΑ'x‘&Ǔ 79-Q, 7/nA+: 5yI DۗLRXn|%L 4'8U5@ A3RE1)E;3u~ǠIOGLCMG-SQyeqThhK2L=#$t!>ɅFC f#B|o6<nU'UoG^Zf7ZHzsOE٦2ndast&-Ws>''oG'l"p:Xj} <<( l'nMt77wܠ>S j5wʈLero-<}YeU$1%ِI>l%Wdr8I%{.hsE&)354&JrA&)?Yʶ3 C <|4nH9yQ2dn\Mf[VV*];U52O:y]MXyǟ Gy5ʧ\ yd3hjd+g"VSh"ǕʠfJM{/Κ|LO:˪kǚng:O(f )CI󁨰vc5[(:w&JL/"] I~?:4]e $ Б@g1hD62f}vZ4T 9-5A&}%BM!`UE^Jؠa^H eo4`O4ί v91j)oJb}-bUKby',*K(v!`!`zA(= t`?7o$ϼ.P.w\._5';n >$)Dl}jV'UƎ C0 CXO+Br' CZs ޖvSXT L'񅁐_j}߯lJ-Kk/3f[z:[zsT_h>"%߮q;쐶Il}fAyOxl2MA06 -̤?LKcdU>LO~#gU|e`}ޠO̠C]Ԝ2U%,E?cu]'?>2!XȚuL4ɭ;1Ou20a„D! Ycy`}iHl;UB`^omKN5y+-Y&#=D1ȌٲO|~7ZLy*K 0@b Kٱ!`Q6 L-Vkk}Dcc.~Lӭ݈{9'|"?\|N>-[B9c W˛oww< ot5u,*8q[rs ڃ+ݺuKXȟa`,X@5J&OHꞭ: pK>ωE3|%$A$N%t{l0 ZH0 mƙ=Sk6О`*xm9$qw`tڴinϖC=TX/+L 4"|;<4V_|E8IΎ>h^^z)[oXnn&ێȣ>*ݻwwzw8H}G ~]wuh0߷rK{aI 7~s`U('pӬC~Or$w h뮤m9VqС.-N:ii'B4hK_. dreɛdep\U$F}i=oGG¶!`l @(_p0@<޼y… e˜^{5ѣ3e֬YΌ3pf{n"$M!DW^ /;<AOMAß2`kG?[nEF4=#3a}5;#SLΝ; MdR$oVx~xwSw971~[nG_XLoV׿10m-~{<>}tF|AγU\hժۥ j(,Qa{S.sƄIǎU`_~IL5 C  odfm&?\zc_ W_}%ÇwR%  1mEcӯ_ȚM690#0bkvm[o.2!93Z^r>?izA$8Df;uoh?#U-= h!tP$$rхdC2w}w,YݹN;ɝwޙ,ȶe8_r;x s., gdž!`Ci!`"ˮD'8M6 ZX|`u`am#8"a9r#^cܹsٸP}D eGǗ3h" *y>D -hhX <`^{PADD J~'Y.A2VAs 9;vl[d}qH$HS(BMi:!8bEsEVhh_KDy{4e\^iN8ɢ1wЛva9$pfΜY!<L?̌iS'0>/6D嬳J0WWeޛ\g}+$kW>hD /l]a@6mDK9;4@9g]ho ~OTӼ+\:Lh/B/ٳ&m>ꨣ䦛na.ȁ|J~Wwh0s淸u.ڨ7R|/ݹ/x*M'As3  ~hxyG0 =z{f!NRj0KTHeqg9&W ;ipvllA =H}rrTz/0fR fƈ@b28837Jv}|378_|1Jeƕz~h8AY8ewڇȞ{Ng{c?G3tQ[̈&03͠(31?ڇ$i6w 7 qLSs!ᶑguaAi\0 "P߫gJ';V ep=H6Yu`&T`~.Y^cF0 L0ObKۘBՠZ4 )F;f)ɤK;remת֍wek27[ J*z&u4JO*a2ɤ")U>ɮEu>Ysh++L#d䝬 ՅeGi5 @eΌjW2cÏ#+\.ֲ1r<(eaRd!￿!I@f/0B&HffM7uSZA:dQq$_Z_yeғ7ZrꈉZn/l|QXu4LJ0a*3?͌}9ܦ yM \eFXǔIbZZoInu[Sy$5&+0?N(q' YSudLl̦/qf`@ O~:袋C27PtSAH@a=(O ?q6y#% r4|0E0DbzB.rgr]bV Wb;YHlCR!h $0D-h+O>ۢ6/a0b9ځF:A{JWp>~AË@ѠQ7"4"@I hK!A&=i6 v _ۇlBЎ҇U|L`=YݒO|owȯ}?餓9f}$pU3a!`!vJ þ|h+s-$BVH{H  G"HQ_H0ZIgCY 'ҡU?B;.ۼȯrW<1{e9֞! ̃vg|E3 ;Ofh4ɄkՋ'AYz̽鬿m6!L Of`V-$B(cR BFS'XEc>7R}iZ:C0 C0*N(k ~m%_&{=rkB B:'`5cuX)f ,,ZK·c5$vo!*j 0O wY3 ZV]?L=PEd'Hh ѻwo uó4 sp"ǾQxiT }Zl3qwMYUc]ab!`ƁQ*UzC(+h#mk5-:'~Qa1D{?&KolL{2T B _|4'#  H|(5 -櫬&-LT6=A p6m[X=x/AZ3B۽I^ÉFpZLLͯQtxd.L.3ā⑍kϢ0 C0 DAuf^&H ~sh=BQ4>CJ Aa`9"zA6ཹ܇A|1m$k.bڋI)$b ~衇\2VY!M|֛g>h߄bL \ W^qmnO4`m:>s@h).*ZLĜ.@f]2Ϫ<Ƶiۮ{ ž{g>>sQ/cz)\|N5Z6Z%ƛ +b $JhU%yU.&C*ED$p YeFGBZqxQ Yv U]H·# =gW-3 (n4 C0 \*2zhahV/S# Hg~h.\E~E3>UYL:*LΔH1"i"l?ǖ RmEEJ`db} uIdX?i!`aOLqe"B`'k@]Cmd@ 08Z[UGk$v>AK C0:[ \T9$CO!G4g0 C GC Pf1 C"IAA:wVeC0'vbbd=)di C0 C0 C0* ` C0uA C0 AsE!h0 C 9mt9YC0 ~3012E4"e Cb1Yچh} .eCؾ!`@9!I~;¿)AD X"%Kc@-G iRYY_{V=C0 ڀ u:d_{:ѩ'SǯL]7 C A8!`!P #2Lt!`1VZUjl5 C0 ФIܖ{PF0 څѣkW6!`!P/0BY/e2;|k!`!`Twlv!`ŋY C0 C^!`P֫!`!`!Psy 圹sGe˖CAH^6<>y ~Bďw8Ӏ7IC]vrQJ۶moUCj݆@6hP信fjVz'&O  eˍW>V@Jmcke^g<ҭݏʤ4&K HMZˮ!ZS)}38Zc~j-g̘1՚en!`!P r))=K7^~,Jbǟ? ee9 orhоj;Ȫպ,1)ҫg/)X^ txKٰ***JJJj+0 C0juP:FilҶt!j&C;$}'-Z]ړ2~m$ oUAf]PMuzFM.Z ,U++TqvBq@.|Ztϗ[R-hKiШ/VzlRu2)։FٯiUS5XZC0 C>} j-27 C0 jCJj ͈ *?L]gҺC5Ywߔ+~BǸh4VI~5Ֆ_ii4j@'Wdϳe[ϮIl ;LoK,߇k;JJ5#IE8K;,Ey/oGtB`4jFVk t3?JTqwi+N6M5|$ )c*۵k״[C0 C]yBvGRY]^= O7l/G{ծϿ}GM\.3dafu Kc9@- |hJUSITe>157w<}Wt>'A*] X%u=\ܻq'%Xciܚok}+1,S8bҰY%l)zdtoYTrti|&b9sLYj#=!`B@KP׎l('ˍAv7˱\(q̘?NV/s~㡒8_VZ,sfU~XSPH'Q^{Ey0 C0 TyBIP3k6D{{Obg'ʔoLm87f,3QHB*Q925ѠI%4Р3SH"2Seh$sǷ~u9>={{e2kU&[/ʏkIzQ͖5!19%7֛!@O ږsjK,BYfl5K g 㒤̚94xT.[Syh@IDATVBV]* ϩF2#H|SzN/YVϝRV<ӽٳk!FVBl.(yPg):[f󪫮… ߁46 @ NQ&@N g(TTTn̘7Q6~g]WJ˳HMdǮd$Lw}77ILTO+MV ?z\dL@oKRdYXihy[eOseAjNi]7/x ֘yrxFY`{ X;{Z2t#;wnɑ#TNv,4J (O/2Z@ -!h1UL2'O͢?#˜HHH"A JEAA՜oPJTGv&.I pG$eɓ2۟C̹mˮ2p۲{6Oϟ/u ނ^XB^i'crmR(o!j29.EΩg.ɓs'\ `YfͅWIHH# JCC-sL=QV-Y*gm edut-y1-;@/,zegh紆"S9h=-73t63VDϜfl 6,&XzuLa"$@$@$@A JyFiPN9+̜${..AloI[Jԭcw[z/I<o6`xHHH@ D-q^urSѹuҠƗ˦MdÆ pQjd6Z Qٳjβ(3:ᛋitTgsXhi~Yv|yE'NH<HHHHx2Z{S[:Ԩ%+r霋֭[eݺuxbykRl@ y?P ZIL^|'{ZeH|nm\ϛ @pXXEiMΜV=JՓd?|a퍛6o&>|X֬]#}+"Y' OB#z [ +4CNi"++'|$@$@$@$7^̑#dɚY8B% L]/_S"?)?9rD=NoM2T¾Xo< & 9 ={Yz^ j7Q_zow%} @Hxrһ[g>*ːbGe CǺ?<$e˖M>U V]Xo3U 9琝;wJCI[D02   Hq -Pm ڵjU쏇P:˕/'=zDGa҃" 9 $&(3e$3gYW\MTϜ9RMn3OI{JB`fO>d"oU-ZA~Z:|P6 ql^"yˎ;d޽r񈧱l2A=冄5UVu$@$@$y窫|BB ͛Wwj >Ρ 0뮻}}:Iae`K7K,q{6xXX +5+ͣBysKʽ?ԇ +-HŊ[oU>">:{1'p>IHH B'6m2eh%M"Jai#III^8Q~Oi-*Ze /X$,={ BXoph+u|ނ% ,4 ڵ+ꦔ0q@ ]}9P nd掙j*X91d +HMIMemuEIҥeҤIr 7~D(}T#PRM/:ɠE<-Hc!-1zq2,R 3W``FL$ %CavHBY.#-M"Տt ;_nGj*Oj*o ,L_0b``](ԩ,/8z ZA`z L)u(nΜ9uVܹsH B2F`kT'^xqɞ=o*'<}LW_}?}p3%Jt4O.޽{̥Jnv];Hظ `ϝ;Wf͚% ֫G݄:+SFuRF s ȑ#m \q}2{eOt>Q믿 ]%VZ!Y |TPTÁ7_;7TPcz0hO:oԦ9s\Ҵ@4-  8&<0t`oƈJ:ty|뭷t+VЃNoޯ,Y"q$Re'+WdHʕG="2;<r]BPP1 19ӧOKwޑ'Nhny- y_w  & qЀ`?R HabL[<h|ĹTp#P;r\6jH~m] > 80ǰwEҰaCׯ)>"h9؍oH;LPpƍiӦI^k׮zS0ّu H`S?t=(.>HV(#ҁS/C<^{G@3"-ZGyDmeÀVZOFo۶u̧lҤָ@ͩB҄ 0ԸxjB9L`\ݞC6l0yȲ8?N}Iar :t;ss7n&heƌ9c=?\ 3\ +_|w&MGS&a<)e9cy'eN:Iqe" Mڐ 딮S}nᰃLQH % `׌@eǹ3`ibk"S6,4vvo`pjGnKw-5081q\1{#ͲtznEY6^[Rdԩ.cuA[r-]_eH>,C}4Lم#;wj3/3/ &1?O0#>|ޯyPb"| -+oCG Ȗ-[|Bt Bk a0W̸UN-_c:c Y]tkڵ&HGnO-vU!T۷odٳ(s07òC(Zf Ν[-h>s&\TôG${W?mq .FK.Lx@C0`9T&|0J . ٭[7Px.qſ.@ lÔ)Sd͚5]aԎ>x&wg}b@+O:7~_)Əuӝ[gm֮>c:nϛ7OիӋk³ABV ^: PxT&%^t Z}8ACم ep iS +GXhu8LVeX`A=sЂ:&) αh4ʕKwA8hD0fК" 47tA0+tq®Iћ?Wxá NaP^~pŘ ," $ΡĹ;.\:׿b;y@E3^{Mا՘m9e.[fbOpPͯ?w.]4 0939G!`>sg%9Vdɒ%Y ovhVm):`<E 6ha{xw}Fߏtڑykh;Kw<^ ވAY@P.hֱHsY63o H//h0g\NJ$贚YUOBF0"ǭ x:D`H;t#%5t1>ؼD4N-BmD˃wr彲*%8#Xc.qsFGu9F/̿1m5qCe<sm)aa qtryLFI L\st`bA. P&`z{Lhh_6]wݥMA[9?oV&n3M~=;FNaps >uXp%SxԩSS6#o5.9E]C3SBs߿iA.$eՎ>(͟~i&.ȃD<o1 .R`kXr9=Ec64E8El:%Vˆ^P#Fjr!93>ܭ@&=?0"c P?~;z>px` Ύqkwt1^8Q03sRbE;V2P}CQZ,\3Yf2h`

B<96 6i%+V}feVe4~d{vq |oRu: ,$]Ach90a)44XnK iC3o.{Bt֏K6гhWk)b}c`m-ε@K/5>&sޒ-̈`-PNCz /jaoQ+GYajs&,W#0hqGX LU2ą / ]È̻a\h8*Cʁaǎu ,-,zD@Vlc} ?P5V(9`3jH?wvm߉awt({ C< fW8)gmn9DД!iիWUV4x}p.s83a" "h^p{~~` nP5aaw&a!(nsy `?r4`UooM^`c|3J<8a ~9B|Ͽ(H݇)9! a+I` f[NqClР1A 8t)H`1hf{Ɣ.izLJ6JA H.ywvs^}Uل6{'P^"}xVvވ1L˂s,xv@;x[_'NjX (l:.`U#|p=q<ӥa9>TX!;@ZEqm.c`w a6Fv&6耠3=>eƇK#FǑ\a&MA(M?`VNF^3.CQM,兽b1AԷo_]ЂEa:f09O/JG|@ 5 >Ц_$97ϊ?t v҈}l6lBqpӎ`Pʂ0mN 8©X;EVXt,{~,k Ȏ8Zg@/JH /:fR?ツÇ7A*mQG|hI3 BÜ!^etaơyHޮ2рQ39̡AvԘ WUp aB+L0z܅1a+ BS;H^32!K um\,;1tvLyL>hT;cL5ڍs̠4$:n1Co!>YM01 Np{;[OA:,0ↀsz[ &n;!ܷ;\)ުx+yuxKש>/aw`|L)!o>)Uڽ7~ܖΟݳh w("/7/u1F M hI Brw=̩N:nC^`>c{FD80g0fQNcqHq4a.Ehu0QZ8h|z:@3 xqut \2#bٵ}&V >ӦxϙwOk>HVHqyނwv׍`Pbd򓚏dz&:;Lb{By'@R<.?x8/ 7\ o9%3$D14:`.k\h윛 pƾ.H\4%{e ?̦P@ 4h֊B p0ut#ܲ^DfaΌ ěC2/ xybhϴ4xN$54p*Ѿ€ h z澆i5}(Dg 3E%:)]HOJşm20_ Gv,`ab͢1'ƍCA|/ } (`Ve51,V0sm$>b~C}aIB7e(U'"Z0<πq3__+Y1D s 0?4TYA2ϻ@>s#@#VHZf1{垕O%x򤦲Ϣr [XH8Ε@0?ݻw׋ÂƂ c6a4<~*'/rc] G޽t$@$@$k,sWyҊ'56F$@$ cX  TI`ӦM2m4)PlٲEvܙ*B @<1+sݮStě$@$@$@$@$@$6 >˂wҢE&xHHHHHH4s'BҟIHHHHH4h)!L? DxN$@$@$@$@$@$ x V&(PHHHHHH, ͤ9{@O$@$@$@$@$@$@F3iWy$@$@$@$@$@$@Vs <eϞ=}      Pۆ\(oܹ3ѐ -!CxyJseIn2$} ҼYSɐ!6K/GIJ>4>:2fɓ/Cܛ7ou%sECGe7oWaӧOˤIe׮RNM喊ނǟVKbWKreB_Ou7HR%%O\R~]O` '?UqR+&|({/IUq_uTji3䖊7ɔSe\ ul|I=, @!LC YʝM[o+={X2gάO>S DGk-)?Y+*cǎQHdRZH)^ױcZbGɮ_2u@={\d9r)RX\uU#KΜ9v2rX<*˖Η3SzfϑAH+ѣ>tHYj?p@6(G'kyht:-M0f̐Q;d[zi.i=2lrXQ^+[lL*'F_ WMioϩ O?fΚ-(p+xb~ڧ]jNȚ%z      S߿_R'Oɟ?"I4_|9xw_KsIVM UnU-'W]]D~w>n)/_MZo{m/[ϣ5,~yOC;Hի-_Mp%L&)߻ȀO>/&J~8P1eܹrYv 7wGsJq*e]#FwyC՞R@sKի#}+哅 ܳ:Y]V%Gm_ZU %`6[o'iب'\s*pBlv݊g\W9PsWڶl v̜D;WYt@UO$@$@$@$@$`E&rBv z/: t[@0vu6lI A7_"qNLimRۃ8B+xJ"STB.@t\ød;֪nt,8MzN(t$@$@$@$@$@ YriJ49B.R϶!؇e˖jQbkdpg)Seǎco̅ohdhHڍw?Vy`s熍ҲUkirg3ym|9b;8ze$P(c^dv4xB_V|K.s"ƷsN_-K?N0$@$@$$(:M.Z&}4@:,/IGyJ}\5{ 4DrRGs)ΡCGdAi?=]']>=,~ĺ8"{.9cdr>b˯ /I];#v ~xz{قܱKJ)^f^~)dڟn| N]˖_w9sf,';uR2|1jR=Maڋ# @HߠTf\uA-St;3UnWx;jMeKyO?At cAҷ>i8` n`^:xѷ?_>YpjzNe0;? WG&5#LݻOk /_M'kגx[B 6c sʙ3gy3d鮄IDP^l MÝw6)S&#94:n\F Uv%爑w^ ˧'XeO;fn,/-Z4k@@.G Lө!O:$o~g-_@n)=#op|ܝ7;nڴioR#dMk/>$@$@$@)K nb^~FGg*N㰟bΝ^w6i$/wKIRQA|xɲ{W^|Yk_9BNϮ -Pվ;Ҹ3fIÆ #\;J/g,YoNƟ> _zuYףǫz%]_ۥ`R%K[o')6ũ|a";f9s䐢JXʙ3*-Z^ xZFvYs"0{+i֬oUy\|ȧ -zD|N!kr=rLI-Yy5kw "iAk7lؤyUL̝; 8X Jۯ_,T@ZPxbĉYI5˯ul#7vv<";]nʕ ={n:SzGlmS&(gΜjnXYÏݳ|JYGAһ2t-hhq+GāzEp2ur%^dHA+SZ~ilNŮN$@$@$XU9s2PuBv/Ν;ˁMyGʕ^ B$Zn#e4 L˫E<ܔ!|X k'y ϨJ 6yH+_4ʗ5kq7y4B^4eBmK'Nr^HHH V,A۶m{83j%J2F?{Ȑ!JR L^r]aJw~N2UvةOUsb4&sv~"y=ܖ!3qAsKk.,_Iԋ]ٲe&X5.<2ay7vHsA0ڹh8cYPR֬Y-Wu^IHHȧ8ZLJIUԖOi^UtiDtՑD/C4K42N    XDxjzB S!Lb` Jʅr٥2D?D*$    !>?֓,**AZEk$@$@$@$@$@$@iʴY,5 Me M(IDATf$@$@$@$@$@$6 a#d$@$@$@$@$@$6 PLR @(P @$@2m;KM$@$@$@$@$@a@6BF@$@$@$@$@$@iʴY,5 Me M(f$@$@$@$@$@$6 a#d$@$@$@$@$@$6 PLR @ }*mv) @%L|. С#yҳd$@$@$@$@$@$@!hBdsNyqdYy5      4JRhb H&PΞ=W8@noPO,y $@$@$@$@$@$@i@2|/$K,i N$@$@$@$@$@$@2H"> HU^ɄHHHHHH@ $#c:dȐdxHHHHHHxΝ;[5      !pA}(!ԓt鳆HHHHHHP&Pe1$@$@$@$@$@$O(PSm0/$@$@$@$@$@$@<&ĉ%}zʬ`8IHHHHH VΟ?/ZJ\2-r65/˅d9sfX"`? V̍@yBXS:9ltiZArXsw1]t3gNɔE$@$@$@$@$@$WΜM/@U~F&'wj"\('' ֵJG]ː!@K5u @\8q@r'8f'5?)_!n#ZԔB?-g 9 9 @b (ݲh{ҥqOٶL^VBܒ 8Hf9Ҿ0yrmN:M      "`'%(4yG6;BrE`WD 3C$@$@$@$@$@$HNK&PWPEVDsʛ$@$@$@$@$@$@qENC% @ v(cI @"HniDɼ @Z#`'EUC $@$@$@$@$@$PLKͲ @ DUSF0HHHHHH d Q.'     HAF^ҥh' @ M!%Ԣ+Vf7HHHHHH 2Xf0eZ,E      '9_,  ) @&FJ$@$@$@$@$@$@1%ѣb"#     HoIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/desktop/images/desktop_details.png0000644000175000017500000031017412346515434025654 0ustar felixfelixPNG  IHDR9xnhiCCPICC ProfilexՙgTM׮'300 a9g9gAErI% AQQ@D4y@E(A9=(w|Vw߽jWuU_]Ny# 3ʇH @`=ll,ݖ^Tf'0yDyɞQ^!B+<2 l5֔Hi_z=754;8GD!!!z^P 3?FgVx_ pO Dk}*<چ. kXGzƆSBh-1oC#XVF9Z֍Aa uܪk"_eC@Hb`>Wҿsl5WYoXot6=gIfZHk{@Jd5°xu'I587?ZM[(J BiQ(UJM5M-fi 0C>{a0 Ӄ3 S%h_]|AOv_@F- ok2#x_P & x [( 9솟SuH dc(gA5n>9xF8fX  !f B$Bڐd A. b2tjB54MBA@P,B@8 v!}TDQE4""z/E$@#YHi*itE"#|d9ي||EN!0(fJ~bMQ(/T *UB5:QOQcYO4ͅD;~8t:]n@wK #Qb\0lL=3yYbT$V kFcӰEZlv;]xq 8c+.UqqttttttttZЍӭx->/zzzz5z[$B+c dF!. D"QKt%Fs#f3oDFAiIGMG']'=!M1100z0d,ala|ɸ$d”TK!ɩ ={f$ !] EbF dQ.S(,dE',%,YFY"fX_`fca`cd[fdeadgG5QMԷ( [8R.)N g&5!.~ ^Ennp"{S<<<<'yL2jm§W7o_ǿ* *("P/V/*+xRCpVWhPPА0peQgt&OfDkDňb:bbb1Ag%J%O$ʒg$RjRRR/ zұ5c222)2M2ӲByd)˝{#O7OoWPR(Qxx[ms>++u(+(G*)OQ9RjڭVWKT]]Y=ZFF'MQM<ʴFh)y+[QO\/PVoZ_N?RA@A!0ӰψlhTl4b,`g\c=s磯qO~Z~'&u M.Y] v i %v  O P81iYEj1b1cbcKbWe7^">#>}{HOHN;w t`G`bjxIRU2>9(q\or&?lr&!-2eF##G2ee|%£99}ʹ0Bɫ:t|'h)|5i"|}'.pWLW 8 <$C * BD}Gg7$$]>ޒ$"1葜 btkV*;zsԟ\_nsI}O+xOXCFTZ,@D䀴Luª"yz&5C` wnm N]{' qF-&fyŬ¬}ml;*9);pu r#Ni |8|9ECC4 ""m\=cb=b5 Mt)y:e-0gdˌݙY)٧V}rC 'O,//ypz̏s2e^K.4U>8wZƼ򅺮k"Mn4d567͵PZUoJ}NgS;ZǞ{u]]k?}tǬg1g' WZY$Ԡr/"IFPGuL}g+O ;+L]fg %UTg]N!.7 4E!0N]TJLSRW2KI9Vymm}@ETuq>MF-#8F}mD6&zqf Y#ml{u2My<=xB^>|qA!iaUO">Gbb]bfW컵EAL"OJYԬi-=G&2VHG5rsC;zDɁS3 E:% \-}z[sl .vW}&Hך^;RJk7X v6Gd߼v;#mw{N. j<215|ݧxzY/z6$u~;4ѪwG|(g3y?S_;ff2/Zt^Z[Q.k^[]99 @8M9n*:U bqܸHc:sCwnA=!aaSV2 +Ic)yi̊3NmJTUT٨khi*jIkhHHx!ʰHhxdنێ&Plnت K:lst2tpv3d[W<(MCsw <Lny9l#5R:0*NjK<}516xr}JØ4t#ə,YG\cyǫO<>9O)P-t+J.,9=WzVwYVyuyDń TlU_յb7R4moU;Kw:5u~O}`}aw}\O |x*šͯN;8agש͹g+BkŴD0KB1Z^3`CA < s?pGQpy@|XCj!k(~ 6FFףg0&2놽p/ptF׎'_(P'q$‘-c>:Svy'Z#f vI\_IbLT6YGNrmފ&JRk*j jW44OjNԉӍ 077 256ojkQbyi{Ca9;==QƾK{=7=>yyew"“#Ea-bw+`mFC*[Z挈́rsϻBdqATbҺseg**/Sz+I764{fSۮ/tۼ't@_ry1ޟx':Ͱξ/ C9P@#ϐ$vd61FBAW+L.5V#qttntux~7=ދB'<&J,IDR.y&X7dcUf>?)Q,,Xs-m}fsppTsqrN4a@ !/a]PQ^A q}u RZRm2Gdf**(*?WiQ=ᬩ%ͯCE! f M/|1]4GXP,ٶ[i[[ۗ8\suzBqihwG:O9/b6Y!a%"ŢbrE}OpN.)RɇsG3ٳJ*q)ӎeS.]JVo|UbLtMbmrwuv>~ѓܓ[#O7^izO4Y4Ǭ|鷉e?lO[E_X7xuF&7)_d&Q4ɬd?~lC7˶Hq,LKo~ie/~c4nء6f+%7-zϟⷖE-oEݡ-Ndv>ΧްyTV*ժR>] A@A@A &?s8mHyXCVE[B%R\RTB9Jbh}@ɥNZRSPzz҉s+s&3 e3JPf޳ʡ#G鼳[RSljLchמ`9F]i N-/ PG+MNS !AIBA QH fh_W SeatF`qЏ҂EKh*Lrrb RRR\1R4_CsRY_yfs:ТEi᏿_k60IL-64W2#`+[ϤZq>Sa¥Ӣen6NlIӵAG}Ev;Q񲦕JuO>9 V9/\OwKFv3z+iقHPh  $(A={XEm:Z]*UX^1 o$sI(DߴC]*,Bʏ0LYeIЖ-ە[Kp@$hnܮ̬I\d5UTjתJUT,V[~Fa53kP 4.YEkTZ @#D~J_%]DwG{Ҭ_\bza fSP*%W54>ӉYtm".A@ \ʖ-C֠Ri%dLPI_*2^:\jʮ *_5nG3%%뷨8fR5KO/E礪U\iXʔɠ&kPzF)JINUy[n)Y$U\tcfB|&&A@Hx&uڷ!o@%ӽ?HsO7ԍ޸4o7ƌM)ݥ'QA-1gKcx yA@Jrv>RJVy:7JLٴc~]mFNʡ;wyܾk?K*SŊۤ/ëѴg/kAnAJ}N@xlʦ'_F KU,'MoىcD9[ʬ4y^Qwѐ1s&}Tqښ[ђbT5RTA@UW+b͗간%RY|1<ᘒ=rQ`^,)êm[2HQҗ)dzs9Gٔg|hf.EˤSgISHt@asnÿe2xAkЈ9P}_-3C  @P&rŲt`BƆ%ǡ\ !)\扰+dHʗMS)^R19`RY{GY-!G=IE/Ʃr%~y,ҧ&4?;8Yw @_tsVU:"׃oЩ>L,D'  T]-gAS M0'9,ٶg\T3Kjr&H.q-{S:3;X$3& Ȗ;)p5kT׎Ϙ4kV/O4984Jk>Pn1>G&[vy,ɩr&^ w\Ko`73./Get4'g_J0H&=xyr6r2/y?Fuj—:XBV,뾣 9@柴TPyP*rlU >ssӯ3j؂N[c=7*O `GA@0dg5+&>_MIרV4$9I ڴi;ͬCjL`ujeT>`1%R_ k{>Za+Yײ<۝f2b|ZࡃT"٠SOK&v6:̜Y2ߍIN.Y5]w>wA@7qեM6 PI0`[c7nLGQzhɒ%Trͤ!@!b6uWӭJÆ 37LB={TL5l8 #^k_ℎ@?sjѢuYk(oӧOWv֍&Mpo1g7|S;8i_zsҝwީv5v+ r]t6m{gAvjǎy4|z7ùՏ/}0q [N1:vOT &>9p«g{s'?Ϙ1CSOشXzgΜI۷WsW֭;iӦM*W:9眣v|!Ft1pjVdz衇"2\9n85Ɵq[A;~lmySN_w]Eq۶m$f2/+Pnc~V6jkxԫv$D/?IK*Sxk\D;adT<(bװOʽ{g瞫6X>_ zQɴf8Ӌ7Nώ0l{{]79Sn DW`"4^м8~"#P+^Dt#dɼ9NAg0ř3n&2dX4=}Rň>~~}v^j;YpZֺSjӯZ`O+/ < D7pZ%tm?~$'GJF> *G' pWH ]$V鏕+JA;Yxu0Tmm6:;gd}RkZGv2vmU__*⃼HtަJz77 6o鶵tRw_\?WmαvODL&'EvbbW\aܥSx{n#̤XGs)0~^+9|ھc:p'S%v$0fN_y?V5%J([n:up_n]u񡺴aƀ:t(!.vYo V?:=/T¤u';{^ahuzaatoF0x~O^ M8,J5M!}5s,W TqƩ范h?k?3xw+RZ/Mڵɓ'clnw~ߩ=bd`wfJ/VfM:Sx{n~VܹS jG{LyGTt +} b脇4;Xb?Ho`QriN+ i|b[ 1Xp]w&rQ)ީ-SbŊk.`a ' (9`HQ/83 SwyjqK]zJE t¡{*p\y7zx 0)PQA*4 "ν M6W=[Kc?N:\h_YWڕFm 9L TBzd1]1kʸR(oLcwܕ*UKddds;aԏwhQ$dիG`!lBw 1nq ;,;Vv#pqF<+wV?* t@fpPxᄃ0 SuYm /!En",\֍4vbǾ+SO)"< eeeW_}ٿtA W::Z:=tZ)]@qk>;AlbAM ctLjTr~82sҤJh毮'k8ӧu[^g;X&ϡ!4j̋#CTb0Т\p-ܯŘs^qC E+Z ܓP ?' Z֩]dgg+uE,Ds=LJ{8iANuݬ?p7g畎5<  >vEݹ{8;PoŦ$X+Y}\~veEpiSn+^g/zŹcǓ)qYc'.4aj2jPh'RPebW0'j.vQ/έ}!+ru aq9} 4`p[p.pZBc ڌIm4.h:Ү4ENrjO^wk#\L&Ǿ9i Fzz\H9X b]/i6ȱ<:ڦbxɟ3O46jG!6!r!"jD~nN`!O'vȩ< ڦXϧL" FpI=\bǓv+uuS9vQ'fҦ^uL&tEX}?VSv5C$uuS9vQ'fҦ^un.o+  @#t8/^le_0-9?C.}^z%uAɘ1c~ӯ+9g@l &۷ou˓O>W}" =ԲeK[ Cqz,;fZˡG꒻h>"X7ޠUVW)B}`~>)1A@w}ԱcGV ͛7)D@0 TtQMϚ5xv%;uD|AXqC4~xڼybΰ=6SϞ=>B IDATc  TRA@&СC]kFe]r%[oA#I46Q*UpWҥU[vVZq(m۶bЛoY>|8-\ B'|2=zV^6*T@} P >S 6nJݺuS*7N'F 6Tisg}6-ZȌz}zGW_M'ts=f8Cf뮻>ݜWģ?Ngq$n*0 с%6}@iܹtת1T3 P*.xG+}6A鳑$/&gÆ BM<իG.! WAnѢ]y啄^x\ȶk׎N8&VL{_bJyF37PSf;K/TҔ)SLzk֬QtpWȑ#fxÊ+hر믓!JÇHiyiӦf%BJٺ7 WQF+O?<_^5ZƳ:+`SFPe+Yd3ZAl8jQBGL޽{Uí]zz:i' 1+څ/WR+~W o$, &nH._߿R$eΝ<Hx`yz衇gl qٳgRG>Ϙ1^|EϺ` |wբŋSVV͙3JʕSU͛7WS.{x}ڠAu Y-]TiNZkѮP۶mS'Ι1T5KӧO&MW_}3(Au6,Avvv@X9fP[Ӫgiڵ!/2kƍ"͟?VNۃrō7I&))Җ-[fJ֯_}g'OL;mڴI&'<}3Y>A 2PfffXiFDݴiӀH?VmnSVV 4֭[gQdNxIjNr~;Aeo5/ř80YZU+}0ش&$9pxU.{i &Z,ԬYS Hsp6ܰZoM7nTRRR3]ĞDy>+}6QڲC Iw0:8\`gnP't1+8OM%O?H .଎n8(Gi 3.0RISO=e Z4[1$8*,w$6+ ixcsX;- \A3\`bŊJ j04LTp&jǎEx8kP?PM?!₧ϒ`>qS PL`rѣ{D:FlX"s-XBU駟V!ӧ5kL'pfV:wL#G$XOSg Z={Z6J*6`x@4p,ᬈc) oX؃]A˞^QCrV5jԠ믿$w8 `80w8k؂.${8W\cɻKJ>ڶ$ `E:X9:zx 8c-V(R~;o8Rj/t"q \~p``+Nm8VP!&}6Ԗ#A@`O Rh >8/*}6Ir(@Q!`A#NA@A@xEj_:S(㎊$iJ=!oyHݖ uuS9vQ'fҦ^uD]M#!   x29eʗJBR!X%%5,G'!fTNȈۚ9T5,eJ2(-ЉǟB @1bgui@ׁνS҆U3:q`U8[?OHqmKjyN]ڿ'j5Ho?=/}EQ)MtpSiߣ1mݰkTt^^uW;Ӹ }.O?~zklx х,v5}ѲqX'/4Ð{Q yxue>2h'u3{Kt=F0?XԈh[\z*M|qH9;~`g %S+O+T)Me}O6S8͍%KC[Mbfok\^ %*Dp`l0;a1~vmjhS_mdz)uSu"E{S iМW~еoSR,uA%a=u&-;Lp촢=VaSjf9ug&f4uW~Np/ K聟Afp9u ifq_ǃԵ8q)+xccU`ZdJW՞»-[B>3[T&tI% uTlIQ=>WQVd֫@+lwJ޷;FuYM.h$@h{n4_C3&J,Bs;Rf-QWZ:WFC+qy JSݓ+S3W]FU ;ɛV^n Y38vLK3έGO \}FLNA״mwck&<5)qRv[֠E,*጑MϬIq2go5mδtFjWT}7hZ~_{v>=F-զJ'4z\jg>Zy9@Ө-{3-7=4dpɿ)Ʀ}Fqw1b|nȗ&GwgQ9=b+ 'u}(h~L#[wț>i.al(r+^~Tޕ]MWs9޴v7Ok1=%_qg[Z:EGuML*E7Rv ! M_t ~.A%38G4M D`G]\Up[f4B%=1uW =hSknn s uCuTQ̲[|,?s~3έ1߭Gr)q!k U˶+g9gB퇐4\}O{zm,:~< ^i?'gcefF(~Fee^ף-ɛGzR~I%WZ~0)a.ʬ_FtVZԳu`_)( 09sjXTRݝԶ[C*LD'NR:|0GlV64C_JtйW4hZVN]F4Zb;5>z@JKSWH :շ:0`5ڴvڟM{v򕖕k~;븁7Z:YVXDcSva;գ#hX8^5}pJGrr)՞!ѰJ#z1iQJ :kש\G'͟r ypNscF4ڍ갹E᤮O ̧VMA V u;PN*COJ9GiT'-,Vҡ^S{Jj o:{ "-ZU 갫 Au-XZ&(;K>셛[A/^ 9oHͭreUU]9Cޤ>}{<6R0gPF ԋOmkZ!mqV/#a kjj#3ر㺬qJǫjhi}6믟Ro;VD:UV,dT.][ [g4D0e +`u@~wR%蝱suB&*&@,aŎVE~2 kv4$XJaw/DWPc3vy?Ϣ;<I%8waUk9-pp3ԴtdsM(pxQ?:՟MD!Dzջ[xp zܾ}TXpw1`;wۣ> 2S^;Dx;v c&HgŔ[/{x;,AZ+`X0#P :7~ry)wBuZRA0f*]tvJÃ3tA] `: AzXz2ٝ` N?KMuTV:+_Y˚)uXr'/f Mը[AtJ&XOƊP:ezaB-m9^X gǖ*@]LLFPC=Ϸ$"jS嵐p!<jLA`ΫPVԘOeI6S;'ZPg3%B ̩9l8ᠾ '՟[Sw)b\t}+5_:1?z킽p_k;"O=;Ĉ xrc]"̽`Zے*j5n`+HëD)Zs$p#{a 7«"Le6ȫ+0NH4gFՍ%X贪Yz=l(@[jeX V67&= `/97=fW>~y;6']yv&Fyxdȝ4w0wT^,&9 ؗ'x҆luKx8޽:c~& ENUCsDZ. pYn9ጝPszqB償nN|{Zwk`ؕ)|E50C`8lO.'Ўfy5aP*~^Kgz ?; Ex鐊V 67Ϩ Dް\TqªpA^x4zx' n o:S.n'`]iY'ڳuĴ8Naa#u !S,&ܨ[>U)X ,eR 9hG~a :W kh?8cSP$&kF q鹸u<Չ09T[BGeY3Bτ$(S(nn1UPpW8G ( %>RE[Ǧ͉.  @SW!Q0RzĎ'"vW&v(s&(O̴M%nꒉ i   @B =z+ Q".큷qv$yA@cƌ~MZmٳVZLӁ'q fzތzj&1Rwz믧_|1Rr_ͅ2؉iٿ;GX 8N?t;yZ.?6m/jժE7xc_2,r)Cި7xC1+(٫D;vJw}75lؐz- -Bgy&=Q W?I3^?Q~o߾TtmVxOٲe6uT;wn%:/2ߑo8yd:t(p žcǎOYftR^|S#x뮻_*WIζmt)_M;w:K/~-c*03WZ F[nnݺQff&7.Ҥ%~ #38jԨv \xr9Dž '|2~60Z裏tt[999J *I=8g=5PY.;tj'\s 9K.qD{z^&MRcf^ׯWs W^]egϞTbE:SUtQVx ?|Mկ7olk?4!9KMg}6-ZH'pԻnu5X823eyܰ7x^XB(/^z%2e ,YEQΫz#ztzޮhy ۶mp7tX1Fytg;Q,9_OXu%w ^dC@ne f ,U¼P54h`1{lp V#1x3x7xQj"2) .0< lTRŘ?ʏ[ٷoqi<[lQaцQ6!6?|?xCH=|ʕja mK.!Zȑ#M2ʋ1cf6#ȃn[m$%%َ9cf/TΚ(3!*<oeffD@]+ tFDVE4n&ckYfxs̘3gz`_wVغՅnLYtyny97,+9N6֩SG׬i,Y^έ~ꅥkh3M6煅Cݮh!52fΜ͚5k̲ ^߸ʲ? .q@#xbZt)q'WgPHtjpP;z衇APBsݢE 矩]vfJ(A˗W;V(K fUF=Z#͛7O&A:fR;* IDAT|/*>V'ri܊+= gWSRR?_?7SLo{{*/xzz:iH=Xyxb)jL,SFFF.5h7H%C2>9~xzu*(M /T_oڴ)@c HbBf\غ$zncK$rʘWM Kx^XBr4ީYYYAnVpks~+7Zhϋ%aFKEq*C"8G&端R5*RT΀ťÂT;gUA7ĆM0n6ej3wZBҰ|cU5'w`Ggݭ`1`wPnĈ +R+ZU^GU,hխO-Q`兺f<8Cxa֭[ 9JvPΩ~7?s8c.҈v`yu-8\$67}YujkzBׇSYKR4 :m4vF P uljT.-198}SX`kO/(`EJTq(;07`:wnͰ k}܍7I%;~:e /9?_zwo~_L΄tyMhӦ"n1i;0¢5릁B0@*;y,R}%v)X{cSNcKA˫'N4yaY$ u X{jꩫq+hc) gwO|`:0 ?:8A hժRK;v,رC-8&x#6& `Pj3?믿N0Di5i҄z):|8wwW?Ԯ]LObCB`(ib@b F\zz`-OABPq딇~8@e;s 0 `vEO,d! ەvıHԒ~3ԡ1v0qM+X]-Q.L,nya>5Nb|J䂽 Q?S/PuD[4R}f`Xs-= is p~>x@cD\`;qFR ~:O)JL;'N_~ƀ]Y;Jny|t\WB&E?83Wc"qxzG!(Hopp$ڇ$ 4TDhZXxd49#X*ɉ4NQ^+~ƝB0 P0Y!e% E(LN+l|_S5h H֬Vj eϟ=X^aal&%kYjow/Q`0S/k׮U}`V`Xo댰Ɔp jp e]9Oqa";]E zE,%㔌]Y͠ 9q~yIs q?@PҀ#XlM(ьKYoxXj+fyt ٩]jhY`0vjeYEUƖ*%{^y h{ K)qҩMيҫSz,5PG W|A(IeX]B +VK{ֻ7t6+HNau_Z 'Pp*LpO: yp۽<߃ǽ/0)3.vCz 9u,Ɂ vZ߃zE% O|ʫW|xx'VVɯ  TmP3זۊQ^녺3OHʉ %̗ܸA GܩnC-,H   D^Hǎ'SqCw'3\JR"]nJneΤ]%ĭW]|A@A@A pdrpêU]x,T,-m~Q3n-: X(Ⱦjm};E8D/D w.xhlQ] N.~Q 8vJw}[ou>M6_,xq_x-n-ƸI]p= REHLH)(Ⱦjm}Ȁ%9k۷Wcu3^.W\q=^$ w٭JժU (I"KDl\7ߘ7 넂vPſm:riiǑWDy&G{[|'OLC Y_'&SX?U *cq6IBASNtmn>Íeʔ B 9;O?MW=\u SB knh$ {?RhXq'eZ'%|͘1g=}γ:+bG\$'N=!Q샂iܸ_(">TfpwmfϞ= 7I&m%$. ߶m[ojvgas} IJGCиFjo?3 M7@+4|pZp,60Z裏m,¤MX|?8Wڗo ,Cq95\(`.KXh!i>{z^8q[n޽T]9>fO۫,AEq#P'0Eݾ}UVu 4xK(՜RjU6lmݺUaIƍIu+s<|_z2e np޽{5z(?|Mu_&SڗhY۱S҉Aim/LHݫj 0ӧ]ރ#o\ &<0x\om,*6I1p3OƢETqkqڵ ^5 רQ#c̙5kTx?p 2\= mx0a?nHd/]3ϟŔqm}+~p=/FN;eVj /`T~w<ԻԳ 烮7Xn vc?W\ ` IcM.]wC_~ȑ#M2۠A}f1#yЧJ*euT>i{U]/nmy_9_Ec\|Ůc,Pxt*hWysB+>P!TիJ)5_xec6ଋi]9.O(`}Yb Am-%%% Ӹ:tpdڴiۃg7:߫M9KNj_G&G ,LSřq@"дiS@Fĺ `mGGo֭iX,A/=Lt8駟.`e Ki{,W;NuЀ_l ahƍD)7-D z/ H`s41X֦MEW0:PiS^;PQ&LcS_CN;|,@i`37=OO90ր%^x)X_J+hׯWhveQ!Ng`l&#A\ jB."%`p08ýپi&M詧Ç4F p@c54@r58 ǎK;vP (sZĞS0?#jVӒz# 90I`ԩA/<5nsnj u{n߸^q6In;,& uW:ug-ftԉn6Uɿ{*SL1CAm*alĥp'OCw}ԱcGu s=pha9\|UW)ӂ h+wofaew:zx5`̯[R^(9B=Q4c F믿VQiFE炎(/iɒ%4h M~q!&qƂed0Fbݻwjgtv-qcfp&|{iӆ@ 8 Qڹ̂)o;#^y>|8-\PIp_KW^{-}Gf|6jBba`߾}J,pGٳ'SO=&Md|_0Z* 6nJݺuL7n\@)SM к%X:9{ck)S^mϻfpR 9ܞ6~5ר .5)HQڵk+&L =UnJE< c!ڔp T/`5vv^xC }o>p[9 {^" F;~ 1ԇ~s%|NNzaj?'ZzHʜƱ LH[OnhJ3xB7X]Y}"o\煴 &<0zNl*U`Ѱ[xIRF'N4OUٌ-Z8A.p[;O&K t͘?*O駟n;jp}v7aĭּ6bD?xGѣg^)7wYŒ3^laa,ZHB]4h`1{lpVx1LN3lf ^zƫIvjdHKK3Xz5ϩ])b,hv r4ӧvV\0e K.{AqHEN7֭[~ ;8WCq_^F``@ 4q=.遹Ӂ|Բ_~CXoRX bqF^0QZa# BGw& IDAT ,f^`m5xJ'B*yx>t"kvsfu/C~%t=/Vsp0R?I+hڕP1ޭ^9^X6Hf0w7삵y!/_N87M$]-ݜ9GCf{w`" u1^a[uD#A]M(+&yLVXAz~RZFvPgN<;I3lXPkժP;vP s0+U5MI&SOÇU41^ ?71/n<ʲ]tщ!<}wiF7tpګ]"yY&_hlh$8P&nqx A!8XY# Uq:08gTQՁ[*{kN;tʋ7҂$n@W؝[9 {Fz`1~0gpch{a:p~LN&V]b~5JMxybvgׯP[E58c"L ݻ7A mwq6,`P`A 'tcj mĹLlpB1:?ϸ#4.9P?`|#7ŢXdlqش<0OpI]{+WaB\m-%-ܥFF;c unVI=<6 Cc0߬g9k)SH]Y `5mnZVS^ݰJ A8 5Ν;ȑ#M5G+mr LalXFY<(Ƽqm녩WSW+M7TWʿ. Mvniad9OʡGkMi;Ƹф^qxMؤn -?ig/IBC PawgYۀ=wN]vvW ZKP A2Ϋڕ.S{iʿlCC놝[Z~hr7k6x S8NԁSx&'kO. 6Ǐ'܉Ee9+y?q#CTxR"A@A@A@(.ɔC\yb4zxKI!\;ح_ح̙D?1Ӗ6K&4+   09\l%S ^z,XhŒq ;VZ V]3 ޏ &tdDWW|{(;-wHsk~LJʕ<]~6mD}knƸdUV`qN,`EMzf 72M=:|&6E"A@pĉaYJ8p@ڵ+}.z+-}WpOrҿ+"Ybq,țED@oL }Tpy.iٲq)_vZ~%SzgɱfV/ye˪hԩA/ \ ɨ]Nn#}9]vMӧO'r6m'Xfxl^ {  uZXyz M<.'vK;ˌesUs: >.քXw4%Zf̘Z0BԳ:+؁Qd^"' LޢʌCk%HGJ!nDejAQB۷oznq p=(Ç Ґ!CԽ<|&{ &Cp8l_wuۋ UpKah֭ԭ[7̤qƙo2n7ZkԨv3P :~Wȩ~5%3Ay@[wӀX^ڋ%G @n;>*lDanKK }|yxN4I5~7tFAj2~T>/R8e6ڹygϞTbE!>V޽whh5S0Sh;*?LTGSn>-=/!<*m۶Uye:D6:0!mucdn`=A7! }5O?m%ԩcu]ĉ5k֨ԙ 0?|3'x [3anC33 f8d\vm35FZZ믿3N;4JuS_|aCc޽K{ HW_}դ|4h]`cXb`m`k0fm8 )c s<۶m3X]И?*}nnqKn% Vxոۖg.n ,5ʕ+Uf S.]w_~ȑ#M2ʋqc9vkcQB$eoSWj֬i,Y$_.Y`A!sK.m,ZH@<`M%-Fzm`α!n#yB5jd̜96GIuW7$9Nvx?9ɿ GIN@֭SY5k"W;A̛7ORܹpV=zC̃-^X\[?$BK.4E ǩi{=-++̙TXp>E͛7'&@R!б}H)[q4O)X-VEG]ް!:[׊S$mJGɳESS{]{8#m?vn.EQ<7=m~ۢ`:교t+ܩ|2~;~@zLc?MX& HG޽;̛V\Uga{^EX@-3oxp*W@8~ɧxϝ;w ӕퟖ*HTGPC,ib%èXzB[Fic'}$4طЈ}K0 eC>G}w~o~Tz9瞣?T]8 5m4#\f*zgroJo.6PBk%h !ZpEW6H "E@| Q5",A5tE}/441`;{R~703͞= gfmUh1Zۥڥoԩոo< &Th68#UQV_ ;3g4"]17| 0KݍPa0f{ݖAlq=0,f͚ DJd7oxm丕Xot[Yt00T`a7Ё ?\9sٖQFa *JlZpyEĈnxx&c1=rwXİm6tmp8 ,6 `D̯tjnR1\PZ|ņ)^cvSS9f5?YqIy/Fj4zKHw[ap?`ܢ `<0Gs2!Ƥyn*yg gw`Q^Mjnil Ì:>j00n8˛ӧ?XߡU0Gie#a0gcٜhaشA\!m$`57\b8p'|8U:O{> `Wccem80 ڕ JicXUT6ZX]a B37o'k6Gn;퀚.bBqn~kNRk5Xexf^lW+lwqY0i`#cq,X\D3UT\IN1|m>\Q_7vv:cyi+TH1(s5Rlzr-hQai ƿw2r>;E"n(p3.bZwh5~ tD7pO2ԉ KXJ B8ly¾6_[[mVh9Ŷέକ8U۴^& :2aQ ꦏ6,ֹE6l7Q񻈑xMڈ3 Wafn?jT dn|ߧzgەMәtP.S ,p!N4ff õm|G}+8k%mӐTQ2zFHe[Q ])*!DXztuvU VNZY_n5mrr.     u13\7A ;wM[mRT΄~9cONo5P          CmLq%9H9 `u%sl5bn%Mmӿm3%Kt1μM oښ5YW5a a a a a a a a a a a`1|O^}[fѷeKS~M00f=rX}Fp8,ʂ5|Ǜ:st1Mht)a@E*~=/~{״!o,rTy|M.ʞ naKR F/%f+G/y饗} 5xYuUu Yiԡ`,?Ā-`LF_}cOQFx.hXc*Av0:Z<\/B#UoE [=s0qFN;/qf7z9ji 7T7_s1epܲp9û[⨹F^B#];N_14/.is=W wuA-ܲYn[]'SoxKgtU>~5טM74_˺*A/x[8S k!8EOiup6K(e+7'pyGĉQ7bg}7K 睴Y`h)n0o}6F+M'tqh>#oLq({w\r%孷jz)t2eJCzKgMl3FHro wf,'4X vJaZ6X[n:fa!6"Ҳih1GxJ2_eƍˤSfG}t0`=ɂ}<,3eƎ]py 2d2ex6|LT^4.\Cհx^ve3*gW^yEåĀKxw${3q=Z>,UL8MQ3|*L9Xgyf&J,>h)nn[ 4PJUcB /ci6M׷zK% L6虨5q_0xꨣ̎;\74acx=("QM‹W ;|)T:/( pd0-YyO<~'O?K ́}0,[CЈl_ҝ-}3φhԟA i2{l3k,# ￯*c}y)j]뎗@ӧȦ\tE c[X+pY|[i&L0BYz 4ʊԊ_c,f;E&_BmtҤI:0֗]vY^V?W*F 6aciю^6A6ad\rIm*"_o `<6.d#gI)(`a>4I/Ll,2YD@6ImU7^{x FGX0+]7¡dalVlW#, enSG.4~IA}``Μ9{-b^|EV=_V_w6deHM疫8^%lݴQU`՟BcKYi3"Գqtז2\&F>PGP6pҢw_|i ⻆MJ Z.$b`_2uKeNb@?vEuI2,jfyn, eciMп5I67l`YK,b~£__㕋o覗.-yN/HEV&ƀ1~lV\sM ϛW\YgLThUT˭ڥ{u’q𶰡,4X v:+SIn8ҌX#l`GAecͰlJ; jLp*=(9na⯊.a10w\+uwQ[,K3/A-{`Z I{0 ` No ?%3f0nx `nG}TUh0Dԡbz_lVZm#oV bďLsc *HgT,X@hgXpwڍڴ{yꄥuz7Ks^w_ MT  !W\q-`<`lmͣl-0Uv69 __ 7wp ^{Ue \bp'|.yK|;jV=qR f/&|q.qъ/nuz~  C} CW',EV7ke̱ykw12BaҖovtM s9!|X00>zhwY=*lG[vi) IDAT#1u>ʅr)`c-v2bd;Fۅ6K1*(k'*tMg?<Ь+:j=’!Ԭ%K/f_M|O0xEbo~"C4ToO!\+},\:c𓄏SN9%ںwm7sI'EL?GZh!h/=vi {7_e}+o>Aig~¹^X5ہ ~㎼MwP)/}{ƥyӪBSW|#isߑG ?9<Ds,$'NL/}hĀeDٷlqh̓kUZtS5O/ܼ+fM7'p [o֠!4CpmՁka[o+[[ pM|gr饗 Z7<-#G}K7k<3sN8<#=ܳqP 7LHHM1MݰSV1\s5c=4_~YiTZfE5p@-*Ily +hǿ>82by /9w}G }،Ԁ{オoKls6\')SC},~y>?޺ArO ~ aNТ-Oٜ B(+0vXugeVJhCS6 7p[Bl'imV:7.|f 폋/ذBߗ7Ҍ Q_ܲ }tuuQ^3r_tEAe)Ao1g& ._7utD+43f0™gY!F M @{9C駟Y1̓FHb_zL<9ς&FX~'n(fьJBy!ᄏ]>[66/1輻8ǎq_7x}#٪c?#F6A4XtxG?AU'p.ݺG=L}XcǶ~fFF@+O;hgh~cV8̙3u~FJXr-Wݮcƌ!GTet@:G zo~nr>* C}Yգr\#+uaA;{𝂃>X՝8SH@:_UJzВK.ٔjfy4u8WÂ/V5d*y7tDӦIPFMufhVkEeWbnb"p9M6\YI<.R@92h}iql, _=B7Y[ꫯaT A-3($ /ʲ,~{)g0%mwPёz:cB_\Ǡ 10L"Xcc@M?7nY~3\VE68L~ pؗ6ee"12g@PUbyFZ-6HXHż}llƴ=ec<*7tNx"eA1] nP52owqF5,XmМ BeW68l9 'Z{[In`32`P6sކ2R* * s& 刁t{Z@npr\k6= hhIl_kLE`qB.x7`1*n<Xª ~OeɝN2 *jp޽) #n[z9\(Ev:o{^'8[<)UIbۦDRUoF,o<ǧ"]Hq_3tX[~٘e?{񑓉+sNД[?/ p>De߫M1ޠ=ve=3;Tb>U'H@/1:iW2ʳw+0>[*bYx|n`UG ͈/ 1a5pl2 zG}Mk~}BtP' VsIeKHHHz o5昅GD`G1Q*2E;Ak@enkS10PN-%000000000000Bfm̴\ËSN;VSJ*;^m66#YD#;𶫭Yu5!]M·~hzAS_ba/6 C_~YN$ES}Fbar>ZN߳4gVJn;M-m8uag}i^Ŵ¹VҴaѷwQyzCjIPE xfUW5\_ia`1Lz>z15> ĉ9Zf`yDŽpV6s -xar)ׄKw:_1mPw.x77 >Fa#:/x rI'ł76b}g^z˜ft`;b`m@K~qi[LMhڸxe" 0Jx:uy4jS:9#nM)w7Z_ӳW]uQ5\ҩ>s=:.Y?~|~#1:~ / AݹlTRGa_}sꩧV6pCR\x_Y yH?P[qG1ZzZ_\r%: wym'{6 nixӽxwq[L=УIxןyyF`p@5-B߯ Hc&2P9qu)3?!mz)͓O> [n^}ճ<\/q|gG{a@oN8#7}GB68 WI1Չ,~ʮ>g*;YntE{7eʔﱾy(~xw7V4g<0'mV:. c^]Z ͩKh2l̈́F '4~;tzM7--zsU#@BkI-L/XCqjk)K!vAT\22Yeoq&9WĀZ .\L8kK ܁lyQáL2dҙ3_[^{ャ3Q d@dsU=ft(rvwk~( z{fDzqD=dB:FC&RLNd0DE%EwC^ZwT7ˠɆ/{D*wX,]P?<@m"j 9> SzOdJ&HF7g9xf<ddtI4nm 9}ִ\ L66 /$;Fś]w5;ס@=tfeXZy60H!3p9v .țTgiJR7ߜ0|ZO8c<'?} 9=S{{U&da9C_ԗ|!Ql_Zu]ߘ&τۘ 7HM" PSXE , "fBcYI+tN6= gf"ɄKg3C^@3f{J(1`fFZkY>,/袌A O4b8oӗlVdMYt"\,7E§t fc<ә8|̦Nl|j_u*#/o lW[m5t-nrn_nn[pmr|ci~8s#^W_gϦ^9{S|sjY{ѬKS͢3 _|j},}iJn&.uGΨe|/B(*kX[cɳ#69O1<7]4AW$8F&asaT=cnG@M ěEY$K,Ƈ_<jk.6ĬYp3ky#!=PM`̨7N0ίQIPBudpuND=yV3(ڀlU/Ю >&>G98:#zXqU90 2j_\`YX}Ϊ1ŗP_!pn7z\1cE0\,ԥ5ߜZ=,V :(- .hPYcMlc)"wqf̙z\_~U&`;>6ͺצMpj:L"Tɩ/sK^XI]0+:)w٭<3S_p6EHF$-b0HcH _~n軛ldkIX`$&6mY,OW~#+}Ƹe]2`;sQ7bzـ27n㡗}s9Șk*F0Wb}JASk'D27 iľ̤H &,+k"0"1X*,B2Uq8ZQӳy`~g4=]uoJyQN6% LDe\γ}1Y=߱eˏSacäI V,pHnG' =駟iW\qngBY`*` ,Qf E+<3,@Viܸq*u;&DsyΦGUfHk7ӧOM{S8e_esfX9[v `5~bA}iybܹ:ס42Zi͢ wGQSiJ}Z) V>}G`ap]I6 ߵ8wɮKs1~&Q;W /~b\rH]-OdpbeG|"$`1L;?4rWsͨY!8G>(U54,x[9h'4% 8V!rNDQba&]8H˨;.oOd]$roi0ӦMS &LsWS o nAeyW_UCJKk~Z=C`R1gäZO+XY`rs!t c Q MBu[VX\ &#? 87پϯElА}NzJ;_;`HC(ރy_!bdУ=B8y[0"Ć<6czĩRO'IGYVv:mtM ]t fF=~p,ar GO9A= _/xX;b_J jyCزx4gqiM}6N,Lrm>czRmb!'6Koz&H4000000Пy:jbѠJL2O9r⦟^ Ιa a a a a a a a a a a_0 Γʹ\Ë:N;VSJ*;^m66#YD#;𶫭Yu5!]M6_z%MgKt G// L\괒k~V8EtDb:vk;(tX~xf[LXӪRVS&b?O7~s u{NWsJ*:sz+Ae'YbZUơ裏>*NԿͧL?ܰ`C:Ц=Z f෿:+z!hS/fSO8n6pɄ!vڕc^{48BJww?@}-yxfwl G'w}:Nq$K$ & \xHuN7!enen{ス/Aş.C=doyxA>877x{GziN Vڙ=߮klB1PY8ƹ9kSl_#\ IDATYZn>pu5Hr㏫GxK曫:W`;ƐW U!o&~3s饗czA5S-ve)y:f̘1橧I:k1nix믯uaH|yNpZk-袋8 __f-lHIxF`AW_]7ر<{Dh)SK.$jusq mK(h> K#0%ʼV"Tx̦$g6-4>ǓXp N0<8qw!n)iPB<MYh*4@m+eTl쏍lh7G Hgq(P_馛rAGlcN;w>gûwm_1!*]{v!p tS j1GYDJvJ6~<72@d"*D-/*aUW]?s#vXd"u933Q'dʃ,o9d&,n㑶e2d3g̾/e~Mr&d4][ĀKxs^fe2Y L& ͽlD5'DH2~,*c=VZEѓd)*Qك>!=QήLرcGpSenL&L2[,\N~Ks޹tazEL1JYgA1g~' 71zA.c}ޥPQzup9gUWh1XknC4_= pӀ.M!lech}TTu.nCs,V z\o?Oi<cOPۮo$9O:Uw/ ٳͬYҙΠTdp6p8w'6PfvZN8\@駟n±8tPJ7 3}t=# <,b@en%ޤx uEv=hH *]|IM4@e]PP茴d#/r7'4'EJבqr&*~Pno!)82Ik{'hdWg_|ecM@~Hѵf랙-l:a=D?Y!zPwկ~Ua-":>}7<x4Ǖ<ڼC4_} 8 tu .1;K>ly\:U?_lh0NPgdp9dMs= vm*nf"9UdSO Kpq+D7~b@3q1i&,@aCe#ȣXtc8 T,XqUE&; m ͼkڦvCZ"E Y"r7|S7SR i^fMwp_?CE I`U㡶jtpec ,%\R+O6M飘﹬Nn?w-\^\Q@Y#GoUpn^Ut1F0yb)H 8r-4۴|4Ue2V< s ]c˦Wk'7^+[o䰓Dd1 brգ5\Su m=980XD Jy-p wOlnr'/*mgn "gԭSYz=|[4HݚS)jN*Ae4L=2V'!43@O:G>˞[d6od5V`Yklw|a<!{,[@.޹uMa1i@a!ď#A1-`z[2ڊ\pQw,|+6RV8 #4mJsqԪ$*p{ァ`dj/B3^U}v[ 1zG^sWTSXb@z"q@{נI1(c9G\@-ml#Ƶese1p,,\X*u3LbXIæײ41ol֜BP1cywtC]<Bc8šMWb^Lԝӫ1|ß/},N0QqdB3nUڲݗW&8_B殻Z%18\be$+H`@UU1"ī,.Q[AEr(Tۗ B .]6S,,FE%3X8QbLfK!cΐLxfALڜbyc=V3 ;GpOݫ CLŸHm`r^}U \Yuln`CKy-Ny"T!ktP oqR'70ޗ3!zM7ei`f%nn) l7/y1 />P&87پ]UVƊ>be}޾''ack'eҚˀi|ב-ZWU&L~*AZu~_E*Bp3g"RLf)@)*LMf&BMy! jByR,- ;m#69nG4ykKA7pZsݺRGg!ny:UJptщbY1j4cϡ4T{aՍCB#XPb;MScEşlXF4ck'SX|ᆵL\!o% #VW% N R ! TBAv g)cƉ TBB>@_hwذݺRG\`(JsއY1UMf9 ,~bq h*{ 'V^}!|ԭW]vPN>e SMNH)L a >HuHeMMy睍hh9|J^zQG cNJnO?}f> ΙkC-Q_X8tgݔ]?M^eݴy7.&.>+``B_wަ^C?k̦njc/N pZZk-8 cCǗ ia}1Ծ{{qgby?w}G%nnFE-m*:h{歷6^r%͙ginuO :eʔK(SCuxqoXY2fSOiMbxn0/0isOsk0Hg > ` /bCacCc4.b*nYaMh\-?F1l#}P__C{>- '`yeO&"eä́/=c,zGMYr-+o X&} LO/f&{)3*'hĀ6DBmKpz!Ic5*Lve^TkV[oㄗ([ك>ijH.M t&SND6`v]wcT}/2,` O܋iX&VίJ^$flz2Q{dSdqsK}2s(O>CL&L&'jMhm#gOm!j&*p3ߴ)}{yK٭ުm#܃m:hg/lvq_fܺ뮻f'xbd3'DrcfN͜93fNfb]uUuHڷmXљf8+L|hi(E51AOgQh44V]eqce.-y,6qXwCi–si_C9UU|4dHbٖnvg"Ǝ@O'3 6Tl\pi}?u1!q1hôAΊaQ`3 ePu+kcچqnu^Їۗ^>-GU*Veؾ+^C3z_ W$]fDL7M.tziK0r胨5,`) utIH0 ni4GwEK 0(lpr|5u`K{ϙ3GuChwn%]0v+0q1> ˹/|t*cE1}1[V{ a|㪍keip^u\S|v[=+~ zX9PĤp'V{)-TAPvm+?&3,10^ח_~yUidǎOuƨp L>aceJTlPUby"@q =Hc&:$>KN?t](&N,fQe[=er-=V7|o€DDT G@ClƌwQF*8da0/,櫎}ey,6qXX]ys1«۷G+ַɤ[L|4wښ }H]/kw7hx@Leʄ;긗U9"uluͤ™,tu0`>JsNt- ;1йoC?O21P9LVd _+x.?,<8< j_`/0 B62zH겱~D& I={Y0( m#*kgb&/eQrʓ0bXR&aUn7܇J8LZo%"a0(⛾.jMԹt< V_zȄǤdɢ%H&\7esk1kx@W ٰ E .g(Bܜ &ҋKg|t|W^y%:?s&q2Q]Ml\&L7M-kc.biN@0'~s]Iv>rڊ6J{6si#7L3qi="RM:3/~10E۞6]ۮoLqc]?7XY+ ?ھ[$z[}S;[Gy҅pcm[z7YXx>־d`!\W5K XrwU-yyAΡ6)b0z-*>.植Q,ojwtz^ml,^ԡWyTVhjKtPu$6*(B}1\+-orZ,IHHHHHh;SiVN[O-0+czV XOL0 s9jݰj9G{_غA3yO0v)|@@@@@@@@@@@``m1fcrI/tXJ8>[M)Cx.}Soیd]$3DSۮfLHH00000000000Яnr\gU }p.u?p^N;|!$ $ bW'Ҧm;vBaf$jO*sh5# `;VҴMih4 ;ȳcӁEn|8*e튥vA1*N~7MLSr)F#9D^˾pzGJ}7g؞} IDAT cwb-W]uUBME DItٕ QhcBş83niőywG^{j6@Y뮻Nm/*}uoa +i`_=ӈes 'GyL8ш/e,b{oڅq`iƍgߏ ^ύx'7K,rX^L|n}QnM^jӵ =Hߚܒy\tEF3{k?a1i>)b4;}ln&[z뭷܏o E|k;`3_\|ź9B=_Zv$^4W/ULHSOdr}we߃GqX]enauzvXz饳Sf g"뮻\E-eY&9d?I3{g89Lt3eqhk=XT2K/Tp)N7n,wτCF/E& 6ٗL6qD }^_y͋?[VٔdJ&-K,=-pH3Qկ~mvs?ܸtxW3{z_?hY?;33h2@c=mt2mkU_^.{oC}}xs+`N6'7%#83xϷ:ӟ s*[y啛r_;ec2bO~1:M'yY(q(m~e+sRK-=Su~|kX9”vuCu$ 7ܠѓ[XZ!ve$ɩ3JZٳ -OwީZh!SY oV!n|I' /\H1x [gu= ^;J 2e~fmfvm7C&4iA˴lOР^$\x5^dE,l\E6yٸ#}K$J;'"Q履~Z%7+E״l._nTiO7tBtE]qb~;6n\"Hyl7eG|T,4G⋪&#}e?~H$RِVo|xy X=1… R ~;Uڦ08 "Rw 39` u2w:,m*O~e0'UiW`3yd#*kV6#֪IlV1]ʙ$9] l˜9s̒K.Y\7<5g[.SXljvѓl֥,bY""2Xq /P7F;d` 7>L>]|th%v΀+BcmX%b@P(Ζ # no?_x &4&Θ1CU`ؤ×.~a裏h;YUib:s 蜯6RKX'? e6"n䬟2xF=8.{;8c0HtXG'TaPe$2)~/>WP]CD+ZEJD|k_SF)7AlPkz wM8pO>d]8q"{+8{Z@_'=X#["tB)𵀩oMXlr-J> e>1-Yfh>ņT F ;i}u> tGe <,`Ӑ'xdlpJcg0/C>DpsY !\m9Նcb4.J{Iϟc3>:k귍Tem4̈́Ѱ7پwXx|MGmf{v 4޻iqn̙zS!$:,֡3I'h⪌Bsghhç"}7bHד0ŠjXU)«u5'hֺCI@v58V7[jqjӵH.uX.~3v4wFJ1:OJ|t~[wKK6ꊥK[vx?u>ibso?њ[I-[Ͼ1jS,|[ 8]|[۶9a5 "EcNdPb2Z1\(bZp0n* b)?EkO_5n8IņQˈEnbn; Rn a7''Mh7OJ[b=wbbx-69u& v*X?*g&HHoQQO0D9{ZAhv2GM,OHHHHHHHHHH) l6fڌsL.Ea??sĝK5TbltOtѿڦf$Kb$?y'v5kf?k@@@@@@@@@@ b  :/[z>Q^z%6a a a ak~a@cr \ocV᫦% $ c. >l5nNJ؍!i5~?)ۦMΛo7T;F=16duVK.$!} p⋫,~:f,Z̍-yN9Ca40BUlߢv`$ G0>Vs-LuYGߊ1"un椓N%ٳo8 9)0Mqy\wۀܿ*rӪ2U| »L-WUz!&ZGoy[5iy睗;(kG^-pD ^{et\wH7M,XMW0G:~/h+J[՝k8SO=`n~m1~Aa m;3C_p`cnB1Aڭw,~$Mr-NBv=^ёgl<&` 7u<̣~饗/.0}ݪ}>gtf=~`?5J(]^[_y'| r7VpX)K,'qYSɿ⋺@~kvas5hX}ȏpni 3Û|gGyL8ш35Jpևh"3Nc`ۊ ڗtיk {I2oAItʔ) 1rp 7\bc=ּ[:6.3I pk7zA-3GGb 袋VX!'K< we|]f&+s856/-w~Zk--Аkxm5ЇMNz\tE&7AկtzG\  U3dAfAW^A Ns5  ~,cPd\pW4ʍ˚Yf*Ϝ9s-P>{7r!:`3~:2C~L'UC8i'p- $em!T8/X4B CXڿ/}oycǎ DYԴH8?\%/u~9# (&POh2s-ٳg7kiK_0Pc*O<$̿{\uU T6GlFKDcP" ZBl'O܀@|h@Z@,zoY'~,s>K/O>D7'0&L0 ,Hx|,j!NGi>6:MOB OxA/NJ!:~I?>y}z /4pj^/އ>W2׾6 i}6{-oǀ]ܸ0| !3oraY}>b;lB`\BK>SO=e&M/ce]'fmf8fWK\*bi1fC̓qW/ ߷`{m U,ԩS5y;ncNA᪹\kasj7 +X.z͑ tL12i 9ꪫ~bh&UPA]( X_baQ Ԟz]m|A=wZp0.>CK׍_Q1}εv9S`#|P7/z XX0vcE|q|/g-we:sL=k|א ^{5exϨY3fU 4*ʠ8T}Fh[~kMj=cqz@ яL0 )a$E`s&78.R*iA*׿` RH`]wU  ܰ)[TbH`B͂ S%~ A=m])N gn]yAs!yN}7Ծei0kY߯32^̚kYz+ዉRb~鱼X2b\T A 2k3/BW+xjgypv&(E4P[] At_i@& ~,1IO%#r"|ӕc:&ۭgH"#:)éܲڷ,]7 {#l=3 QP馛x^uQ_'Z6**>cFg;0ry_y<T`.`̝9o7H0"[BeE5 '駟M`<'|6nC{j kMX;p@+OxB=Z`#76E >gN-m]n1YgN\=zR&C| WsGxzԛ;UPz>P{R>Ҷ#)N gv]v4S=SS_;e oYn>FG6Lk\˦iӦBktHs+i7͇k7_~bZgY0qىUVYE׹0P`"yͦ3[ne E4-!((VơPXS=sPyig3A1 $Eҕw&K7urE&C( a׿f=ixC6%.Q$J< g '!n֧!? }VaPqfkm臢Ͷ]ڗ [FGJtXD[97hL<7颡 mXLSQL*>1܇ZP>"YDYܙDr]3_J}ګmW7 l;Mח}57 ܫB( h ¢*l.t>n>ݾkOGMkXpfkvqk_UL7 4P\3U* _-!~oC<6JD*~lxi   S)T Ұͫk j˥r' tDE~aU.Ahh4;ҭLT4|ks9~aK2:K0G' Rl6KrxsIijJZpKtѿڦf$Kb$?y'v5kf?k@@@@@@@@@@ b :;䥗^x H8k@Gzp0y~ynWO;o{_V%p}eI#MK./h*V &q1RqTLN~]&74첋Z{M6L0Amn_r%MaҋF $5ctm5dM{~6vltmk%lܹܩk~꫱rqSg^b{óuooBu(v _f6۱|V|<#b 7WXa-ުI}af͗ey뭷˄뮻N}h!/V2V[m8BSʪ{.bKęͮ6嶓6lf}0!d2>e\pA^{e^uoz\xH8mxd256 IDAT`ܸqp?˖]vVįJN6+ ꭘ{ٴf2d2exƶ ozLoP/;C?iO袋jqm")^Vܙ}heCf+Eޔy[V& Lٗgɦ..iGpq=R&lUẄ́[mƻ> [eU2ѷնl@3ϲen&?rW쯡'~꫱rZ=1:/ :'O1q6ʟݛݸ{.z9ocmPWy+D_ˆ~(*V0ud~I& Ee:'1N3&-M⽛KSK/txRKeO=>p~7(]k;6Okv衇\œcۓcu'ۆBAzmP+/2vKWʹ~Gs (j pքz䒟t@C-P)N=Pvf=cs \yO>1hS5υ^X9`+RcUIjwq*{a"r#i12͞= iJ" R77 Umo TЕ.ypcS5WC L/E@m+Pu^ v62л{׫X~}}X\k:Y 8<:s1vm)ž0gΜiDbP[\ե DB'_ZbҌц^[K[A dX'(@Y9:w͹XZ{g ,t9O!K*ٙ3gW7>~__%$7w佈_^־b3q37.1/~{V{.s` Bëd@,ʠ 0*0-BF(0kY D s'jepW4~,Ḉ0&4YD&>.0ewuWsYg:λhU-51*Kb:y\VTX8˙&xЙM0`A0;yˡJ#B&/$+x᝜궣<α|!XMע'~e$ul\BB3taeHDmɩ?;: v﹎/y{O"~ExY}5;Q&h1l֠ hX{|G痨ecov҆2'e]XT/},AY˾Ëچo(cd4`aH*-^~Ag݁D޵ \.^{5:&;3Uvٿh+=xZ7ȷ e y" PMQQS5_꿟jQ>C)z$CV7| xEu{*}}/AVTJ̷d! PU߅h2,щS-tVk챶5 ^Y>IӆrׅB%uUtd'3 `9A .W,qBMa{[ʗu\TWc~PMs:P7~OX¯W1#<ޱsP n/G;|KSe:y9VDDDDDA@r0(Ps?9?H1WΙ2zQ Y@@@@@@@@@@(R`33fc^$hXbI4mbJ..~So2g]ÙvjS[d-\@& $ $ $ $ $ $ $ $ $ $ " 9ba˔(05l #}0iߗbe,ZKx[H^P8R5^Ir)C 0@eWIqCϝoZ9ozł~/>g8)`$FcphM9ꫵ^[c K(X4tAB/ZQϔ)S8u}яR@PXbo3, /7e0Ɗ+W/b)+ᄏ9bx9Oҭ:T7LRw~{E H*_ +ʸIz<ۻL",b~_믿 QG^wZNDr2C=%Ϥ4tPCC.ȉ~#s]w5~{s-W${z^h R_l lK3^3<9A_̄ҹ].bb|xwp[^x:Yl q̂]/oRiIMyMᘖ;PmV檫2ma=a> GeWS<1rT:-*cor;<#I&_,dnҵHix뀅L?Z.o|C~iM7E!M{!b&}We wyg~L^z%3k,s'QFO:\|ٻyL)o=F>_E㈟xuƉvy])jw|SE3Nl>@qAb1vE]c8uN}pq d}<# eSV~[K.\S ѬFI*۳Ow%i$JXYJ+dc$30$-vIJ0"&m}6~AO^X] +WMjTn0?:axw7wyT-nXE)u:+n'O6nu$:_GyNub&=+JkVFb-V!v(E~&R,7c7p^~7"ڧGU4+Wghs. 뮻oE; 0yUw}O}aR3n8MaA!U8x#dН&%,;+s;YT^z,0I+W$sK/jLOj}Q/`72_qϛū;NtM! A(߆x&D.@xb|X@Y3)y(Ů?΍͜ćPAo9ST{rZzw͌3ZVExRXY6R=37 n.:OKԧ#]uQjTJO,: ER[FeyL$ơT]DMӟ}Yyܽ %eA4zuB{%ѬUଇMbR&ܫY~ o|/,GU5970! |EQCc2 5fΜiy](uRHuHwu&UYŽ 媨=Wy^6l&C0럵scP|JcJ:pw0_?$휣#3N #g,jί cP.S^ùC|N}WTjYp~'?d,@"u XgaPJEb2& t?Jä\T `Hl-"J?d"`D/S0A+ EmTŹ .ㅨpD5sϤ/VXALDXlAQ{(($,$^~||vp8$>~n?p#կ~oGkgV^+kE@bhXHcׇZ=uS|u7̝oFz^^4&<[] jeD֊ʹ`)ek y:ic|IMٵ͛oiEs(HTxu`EbimAxo(敜r|D~uňuAY̝,GxM|7}mMΨ>t‡/uvh^Y:3&V}=Rvqb~n&O8u<ca-7m9A"? fTFB oC{C9Ame-a,6Jkٮ`IVBW68$eQMq+gbCMqXxY>EiSD((((08s _BJX]wUm*7fTUT%K(PE|)Ng 9S&\v*}(((((((((((; lvfsLËQѳ]LڥpEo^,^R8NmjxՕź HDDDDDDDDDDDA@"G,: bRzF?ܼoѳ 50>8~0%( XSg}v<F}-y^#6G:cy\'Ǖi蹓B]"7P{8oZo,,׾'ID_|q?~nu]eiԩc&{!7xWW-bY=$[2g} &Mj;h/휕w?sWWbz!} Orʔ)YtM/.1[/|N3KU|rQ׼ CU4G~|^†:Gޚl/yܡgߞ7ېq{WqM&ggr2LL2ٸNs)hVV݌î=3K?{;x#>Qt'W{&,t_={vfV~1Ƣ`=hw'wu:9*^<@^{iVpM;I,pH5XY S @}CRKwqG$J1-;9,r[n9vvS=n!NK/|ALE._lN=lCy8̖[ni$PX]v,b裏6oltW3l+ '`V_}uKDJ<ԇI:>`uu]WŽT~DžZk-->uvmGEKh[@ :=MߡofQ[P;~fWvdچܲ>Ϸ_[nE'|C펀4oyG^c41z[ r^{rqh[1_ J8O",CܸD"Bsxtdfepo vwW[:"Ѭw-¯Q3f̰>",$r{؃>ΌfZɈ DB!+]p?Kk{ャDL0[+>-,܁:qj.LRgbVn)+v+v+;(Vv4\* >+/+9MY]vY+;+I^΢ҒɿF(8G8qɬgeY>'*nV9N;M#+(J0o1:*be!lů+,h?+[i:ԋL0,H-s 8~x+~֬Y.Zzpu#nf=P3ڿL2.~ҧ}IAϲgq?͈߮+c)XF֡K}#ZК]Yޕ˧sY~iӇ^w|:m ~-jN *RuYюƍ1Xa^~rƠW7"wmEA *oGdI4* (`! @t'l/kZE]T',``|Hu/;|a&DdR0[c@׍7؊SxfΜ=3i˭H ,Gn . eNJ'{WD"9,X@y5]P,xV[M'e]"'C*7>tB{tywz20nNe'N~ĘO[&ӦM>OW~D{QGeЙy #NRT?+moe7VJ盼ѦqkwU$>[귋/ #O^BNumjֳr˾-h[1JDX`Vvsܣ 8xNOP["~~r͠W7-grdP^Zw IDAT/4zK.x.}!1h?>}grms9r!+AU; l^ed%+e"q-nDpjky *wT|=tZQ\L" Xlm_}zxZMFv9~!`u$>$2}M7Rx .F'?rUDTdl6d!TP{';bUѦxP!V.Na~a#dNcx>s%fˮ9 a#Yۼ rP=SIo"(rΜ9z oO*6> wb9beHcn:A5 $UhBRU4 rVFn䰴9E+&gQ`.9,J]eóTt7tɈ1 m+vIuh턾E|4s1gεS}O S{)wю䌪⟋ynT/lXUA">fx@$AbY?ά"##,r%Ah뷲SR%mvm7{O^w:iSyǐyv>66M?߮^2<d?8g VgyE@ ߜXxmP\W4{N恳D]Ri4C펲4FڴK2>R%&ⴛP>ӨE>~;NۜK#Mf$JHHHHHHHH uWΙ2z7YH& $ $ $ $ $ $ $ $ $ $ tN̘yvrQ' P9o z_.VS^,^R8NmjxՕź HDDDDDDDDDDDA@"G,:DG{|8) Q`,P?7/|y0kCQRk\d^x!U%a uWśգ@m%ALl6X[U7 D8lzpF$yA>Io[x_Y6GhS~{$zVqU:I۴iv&![dEy]A'H3f0zAg/Hb#} .׃HzO3{̔0;9o gTB`=břHu]Tf~ 60xk4 ,$ =\kLnzN N#S=髮*?8٩i4W_5H>} g+V[meAe]b-oK.i<,up fW7xQG 9?, 혬rw\nRwun'|RiZS?橧LE41 hvy?<#cO$qjX{„ ԇ8UF&_׵8|cZԟbzн:}Nܢ6-CaO9OS+V2LvoEbbe"^G /^^zi+T{jIyb%Q">er@ʲZYTO)#-i4hOYePZrĉVUO≊sNNW'nQ|f$MxH;li13g(ɢЖ7xٿ6v﷋/(Xɧ\@ Qrv+{9Z|]|븓%܅|_ZKjYNXюyøq㲱nC=TM|h sY@Ecl +Sg*~믿nE^'tLj, HəDJeb340a&ҐIV_Rٗ_~9HU\UفoDҢ0+$!}De3s왉_n圝YzDptewΏ{ Ov64N~0dAΨ"f1YmլE]Ԋ1K/TY`4{ǴXAvg ЖI$q]9 peaD?VviӬ|գ_7EyYI^6d7|EILȧn;]xAQ|:ciFhu TA"nAMz;}w[ϢvCp瀍qV4DQG=l Kby+a ^YߴFT6twQ[64wc=@$sF)؆lS,XS/+LpgsgˮF[2x"..:૑qپ 2@ZUTn+^v{-\QUa;ꫯփ"a2r>2⨳z9) U0HU?'M'1H]6WPUD32y4rA]i,~"Yv+OE4VE9Wkk.֤/=+z .O\QdYxS@n|Ӷo괨m&Oy.@us7L50Zp1 0bP[˧Ekx1zEl@-*pm\.lЯ90r0^{m0jg1?4d2X3EL3sVx0{+aO\]i8M_9"]0|+%JY?78"5z#^0{EteZ$!rk j]ͰFG' ǰFօ!% 7ܠ7]QѺ4VE~V嵛sv0.֤#g@35\S1 A!u9:m#tr`BHMQ1_ Oo>c@ԩgQ݅>UΨ?~cFh ׷ܷ(*5\qs7tSTjNc}]N:>MW2ie"dj=sAy`>(}#wj|WH"*6}%m؍շd d'#LJ2qx: w>+hV24wE4szTT;CD||G 1Dk7rM$A5 'i_ՏU֊uJN,;L\ߗsd}gƇ?sPŮEuZFRK8,jE{]7:i/c;(72(jwOSկ"lrhr wek"0E2+a{ %S-P@$ GѧʅZ(a% )$6gQ0O?݈`G-ŏExA0qv Dŕ'x4S7Iǁ6$,,2f#Q>}zR8ᬳRg(Wc ь~~X]<@C;YbOL{'oT@YX᫖zZnOvoD_&̶Ӟn6AB*;w;9u#<^cByA'ڌO 㞜24_jp9d2g+*]) U'AcFcxY*;q`ZMcIk::qUO'U8-7xCmcuekN N`i֟*"tz1ƣ5vgI49c:ZJ}π*⋫e˷Cz xFJG8*SW\Qe:묣 L"?`'pBʾ K|*P ]@[c^x/긐C#~ zy\UƥN6mqYde_} }7ŷ<]#SE] MG86fٙ_2|`{d TM  LRG8Y 6xfj RgSL8}w]v11'GqYͩjOZlp 9g(7u_x3%>Z#8oYkƛ!?, >C/v;\|YQʲgչCovӐd?橧La"P_9o P9bхg &C{q*LRkQ9r5DhPh>KCZ;=2qzwTD|pL:u~]&m*rv“)c5EqJUx[#:[oUE\{6h󱱲l\6lc%:C 5Cܸ:V|7  mVt3"DBfedEάtѡpX$[@T5\c{OM8aeo|ا, ],,e"?~g䥗^Zp2t5LLkǥ 4ũ؈rLLޭLܭXY4b {>r-V30ʲZYQCߗL4ZUz+mO;4ͣK+,ٖp.чDȊ>3Zi+;vWrB=:[9Y&8~x+^D.Zzpu?Quv>%VfbQ̙@vp(78{ovN>=CDp[tEⳭ]Pzև^*5XQ%:.Rצ\kQ"DkA+'NJƍ|XBEXZ0@/\1.rNr&DƳ bڻۊtD;HO/! SƄ#}dI5 [aJY,fX :2{̆+}Hju2)d+Ҝ9sf/|YzD keNJ({WD"9eeVM..BO4g!ٝv#"Yv4HN"ION6͊η<]= >[D:}C6&7|M$lEG~?. S]vQGUƚ XQ2)PkS.[~;߱n XY АhzK1\ .P6M˙azT9Gl~8F#\ueїE툃3f̨|cbZeWD7ls9@sٕ4^yM[NweJ.5 IDAT}E-SUYT Tn{^v}ʀZϠ E:M>؄.njvyg=ֽjtGE*BL dGl&C.`W득hd2Wm!5 ׆?#C'G2[ ^@K^eiBcjUy[Y2.?ch 88CUhx1zB:u]rAȹKt;0@u9NO0:Xa,rJ]$zsg"r=x`Ąsn"R}Sp۽r2aR-*P2rE3["g}֠ 9"UD{EvѰ&kƮEl}ѳGDpGdDЁpnPAq ?eyHHY_ }NSic}_#*ԍQ/qG9.{!]t8?:|U?~7}x38m]Z*iXXCuY; Է')ʗ`5M&tg kXqM$6> Xi߯+/K&Vԭ B_P>&G7&U[ir FH&>n = wZsJ"Kꪫ!^7.RG5_ޜr)FԜ￯@_T>Rr Ǣ9 ~!M7dw_}毓/oE>h?'>[gkx_ux[Yx2_ ]tOFAZw}:vˮ~ac,~ oY E 4*{[ Q-P,,$ ,E%] WIjDHN1A$s[o+8rDyy'JX$-֞6ȁLq BZhӪPD&Kew4t ܳÔ^x'e\"A }ς7 (j!M.#e9-` uXc2PqFCvsM6b'.E׫g)XS򶢺r_4. |q ǖ*W9}As"B_~Y*:wA]kz.JbDb OfEYm&zp΄]BkY")- RJde7]@\]4ȷ2p(Yse-w"  B]mH!;,HB`ePH|Ꝍ5uy\VVw%0._܃gˉXSmeuW^QDkwNеo;UAk ,1Q Q Q Q`lSu]ջ;r%Rh@@  Z%n<vΔI?WoͣOFm1"AsoJislSv)7ߥvѿ릗9KδSzu%k5Q Q Q Q Q Q Q Q Q Q Q`)PT >#[ołDD>s/mF.ZW1ՄD@ ^xGU231*ԍ_oOm!|ᇣh{KmQ@̩ \!}j1:J=,rx ۯFLsO;[/sn9P O+% /Dѣkm2+'X+q/ /Z#&Xhš ?VxY^ι4iRg] ×NpG3#P :=PoW2}ʔ)Y|p?h+^br@}&`6tSsaO/묳|8nwݜp E(G%xjƏ~bwbTqo>dxm@eG_u>:Inz?;ǔ$:A Sq ଢ଼N{^vu. l*b<@sAe9CP8|饗"8 "' ٳgg&-p[=#<'i> ‰]wݥq97`K?Y{~yآ@Mۡƹk Y5\c&O\8qf7z_:ji 7Tƿ ձmh < =4Рqp,*w #p2ơk1};y\>)_;|=/Y0sͽ wy#Z@f͚e&"i-W_} }eۨgl*[o|:ꪫ2[mZ>d2?|Z8@je9&De]jxv;1O>rp#jXO q7y6!9fUWՅ{an*jc;G_SWw]68a@. m=6S?([lŔzO>\rIsgf U~u]WvYf7T4V=q6k,C:[oUzתևC^D2~mFj}NZ KPF3p#TO.-2 Ȥ$:Va9M6 Sm^Xh˷"Y2x;mA,RXaZv?F[2i$!w.]-_ wVza^n~/kV$VT{ァN8 Ӷ>#Yipy&+(Kp]]1fy&gEnߊI&XV&ֵ7|SE=AW Yqg%.3dcMUh|?.%W\pacϷH"ni13gs+;8Yo=7unfO"'^zi+r-VV:5ciT=q%~c퟼6>!S[$AC͊v7._*}J4I:B3׿pBBzMNNي($H.c NiHؐyN!Jy?-?aXIB -4B"䗏]v4=XT)֗\rI }|vx/ ;"3kƩ#",쀅3W_{XbdgHQ+Lv&gB9@̈́GZP;6fl3d aA* 'LNQAW:F視Z3eu@K]`zU1>8$(n!!RwZuk86 MT%}O2]-EMNbjPE>74/߇VCU:q7bW4 8CUvx1zB:Bflj/rX"E5E EN;_Hza NF>+?a!/(\\&LD矏Jw\W[m5tq*>- 7ܠ ooQyx=;pWvbOaVؙb7Oy+}f"ʄs,B(D^_Ux3.|cKo y鮢f],>fCk~xP(;M>wvi2 Sguo3. vBtb se'Y 53(͆êcF 5MzjH)9}vW:O sNC )ؽt@`RB<j.,p`C/}'j TP({it;ꁉ!u"vPx3g4.  ;VN(/r^KA9\M;0>߯}&&,R1qjwͪ֩ҠZӳ  H馛FI|E/Z⩝d]Z`c hvz1˂-:ɓ+ ߢ~k:=Ӿ"wX\WGw)Z´&iVTO}"&Og`1nu|PGEu^~4ʕOrŽ<ʮ=fZ]+D\`&z㪒NҫqZ9oя~]o1~3ߜVF^xa9_&)k, J3]LF >co}o`}Q&M,d4QZJ}΀'ql I=Cx/ZSLɢ~~FVKvR>@?ņ?pfM75vֺ{묳|A7n"\eaӭN~c4x7qK`L۳,`62^|Kz2.u^iEf"ah8$ 9b5qDs]wL ^zon"/CHѯj&/0 wχzdh 60W\qE?={{ǼJn#R~Q\dK| (/=s~pu [,?)S &:{WǡzihqfW>9<n( +0cll͢jw[ifFYapmC5Xìz%Ǖ%c[.OQ`Gb}%Q4P c`D.Uj^{e߁ 1yGtq>iI+߮<̓A-I5^Y]uU!Yk?_InbTvmG'|RO USO=NPK,J|uPLBuX=cO0Xso19c?.jh6Q7#^Q{w8`G o a #|ʓBԍtn.S!w(wdT{Z͵^ZgQ[)GfmtESʩB#ᢋ.RzL%עvL~Y2 rbc?ah3 :|J$cV1 `k=NOJIN;:=)HoQ'N ;0,n;8s}! IǷm &y'4z,|.'lzL X8Ua &.r{?,矯gX4 ._s 7i;`qH 𡺄 \ԙ d %*MѮ+k/MTX~Pzex…S ^{5n tܸqRw9F|Zݠ <=;8qŻI'7ό:bH;V#(yDzj+Y0csG>؜~&8Kp kEE3m4]tI`B&;aJ瘊ՋP&c A=4*b1@¤ ;E8r.kEUFd駟nahB -4B烴8c3萏K.$;"P5`' PWT4c$+ _~ר~SD;t?1Wimn}[#^y[~Hy晹}fBX`g/qsBiuJAn;o%+6Wp1ǘN;niKTGhA9`g 2ҎQ }* kE>[ QNP, #e2?(BzA]h;Pc0'$!Xa R2`$m>︮jgU]&ਊ|EH%a &!֔HH Z$m.9cʃ{&L$1vѿj{ ѱ[ߥD]KNCrm?ԮZ4xK!?wUV^y\n]# k7x7lz@3gQhΜ9fu-[ ""xXؠ:}Yt\ Ё$ f7G}'1w^j.pc|uP%rf L@,p`P1*&d@C=/{F^ASU# CMf̜9SU(XEusvpuھѿj{͓ nM4Wp˚~wWN%Mug5k#馛_A?w˞]UetkG`–E MhcE WUmqe bhwa,rh"._A?}7Vu;Lv(P)b $AP{W<Rց2>lY`VQ߰"ubCGc0J- ̊p.݌zpYQ9+;5V$odgJ?/V >|o"ar7|Rw>ԭKΕ[|ݐN^렛?&Pzq[ΊXlKeg4P75.ʾѭ;?< C-k#NJ`kciS1\#.X'Zgbm0칈};H^Y>D^,zH Ѕb88)Ki(b+J DTLP.F;Wn^C'[~]xU|: X\fk G(>vTL ҩ?w1I# "G )SF+S?03u2kup5(k/r`)(QzXX=D zC3eMoRMHHHHHHHHHHm1"AsIislSv)7ߥvѿ릗9KδSzu%k5Q Q Q Q Q Q Q Q Q Q Q`)\BxeOP3~iRDDpHZP̭S.R@tLcy/G1n|zy)+w֡H[7nC7f{_t$"ֲ9*AĔYgu v?$^9pGᄏ8p⋫oU{$B_,B>n,S?`_{rCǥ5cb O~}^dE̎;h.σCe 6Dʸ/;C6[Bˇ0q 1ɇ&'vWIEs6mPFx?c?pBИO~L4M< q \C"l1iIUI1n|zE~piPxy\!N~}^T&KnYȇoy+N28%-}͊qDXh({ȷ)g[y<}dEXcٳ |XhƷ:sx}ኍ[O\ *ze}cb+UT,*6$t>lN(YV@W$ h}ȹ30,5/O[iӬ`e<ߛ=W$# s_a1ýA[4r-gYLs1a''l/+;SV$vEU}2jMruϢkgΜa6 "i†q堬^Y~OJ \"ӉrQEiS-ˁ .=ЭN):J@F,Cx(2Y ʆ q䨬Bc s׺c~.*W] /ϗ/=]MTiEJ-B1*< 'Ȳ>~woSnj圔v%R"+~#ꤨ\<7.иXTp&# ?Jwܡr.-:@ɢ 6 Gi뭷V^o:&^Az,_{5 +hEjL~M0Z5 _ 3>(008V9}tU'Es9ˉX(Am;Lٲ&yG{Y6tS;ff@=AYW_m8)6SᕜiEdMojrfdb8u or.5DTv_ɮFC7I>"?UCQuY:T̋>x]utڹ/ϗ1ۉwD^ӪYtٸ7y*j;Awy4kj|I%*p1\0;jkdqlUx~!\]X\P\ؠ_[9:Xc.HL_A) 8& FR&SgY`dX 7bN.[Lr"OPm7M2"Q2(( -9餓5iva~,BMRhx\HDz"g gd֠.E ӈ$V7X։j#,-uӫ< uD _QfY8k1\DX'_69>ˆ LYA^[?Eu[94n1wv{˒rPkmI[e0:tMf}J&0L9FEVLM6<  tr)d#}Uӆ:2t&p"ꊊ3_Ji"yc"JSҚ[]XY$_FT!] }BԃCQ4cae7j4mds{g,.tӸ쾛F;~b+L0 @fAw;:FF|Ec<0-lkEc~.{d^*JMY-/t19VUX`HT5 uuwA WUhN-|qˏ3-#R(,LhCf S.G cw kJ7L; Fȶ40`i$ueZVaQ0@Ơ`w.Ii "g:2,w&cQX_MndYd"vz!P&C¢X2:UGY}uO0" q}EN#mN O6Y,$R=1]c|T7[7Yjp֫+Yu5H"eb&aSG9Ϳ/+0&_xھa -k 8Xg4~vOxkeWQ{:&5LPѴ_kQ{VWQqЛD?wM:uDxQyy6۬ ?WS3i?X{0 ٕ;SV*c9s?NgӧO^w饗2 T}}j緢"z8q~)U+T{A'+RXVVR_={@ӟԊ+mO#̤oF\U ;q{U{g*Wr~b4"!`85'>| N$qHD (5ɋc̃Qc"#8@0w+Nkt=T5j12c(|.Ơ|^-?{)'N6o8Օ:eu>1_RaUEj`EVk+Wt{+];@n &`Oul^Οu\*"D}͚5>J$?x-@b_I\hדS'Lไ}͝;CRzòeaS:c nX ,}nӦM k˖-^rWi|ưQ[˗/wHwRu+^M[Ϋ_p^J9)x ~nemwΛR?$go-.cPWa}u}*w}ř#ȿo|KCD$9pQ7cE]?}M6qjk׮u#՟>}W u/5U0AuiPUu@0̙lB@Bu_g ʧo1J6IDAT3R,7 l\/;ĝ*됶RaUE qk˞2zjbF+&Fz҈͜9ӫz꩝/q#FX'ULzӈ *lc ^TX'^ IQw N[v,]` gD2حK`{#:,?dtn DgtAMaگ- &!yB74|a2{ldj; ?\& y]\7&{ociyy+fRwCXƋ@ 6x86wJ|UQ@,`Aa}γC/aƠ|J:GJ,,/^Pk,+5:$[~>,rLTu2wS42Xa.1p|# X_w9y0abUb4ԩS֭[LLA&߳@ZbEӧ&ϔ; ze\#S):F.{=XܰE=8S({&L6w [0w?I{a$1´k9 (3*駦M?۶m2eJ :oDذ0P_oa8С_nᐪ*,B>R[Ʒ^א\b3* *4"E] \pxE!c2Lu k6.C !ϔ : x7PU`5}jgpY:ybd'*1T=i@9*70c jܹO_D,7n.]UpJխSF0Fb.HO,N ~me]v5#-@3(1m fWl-=E/aF EjpB-r>7s]b⊔xep&TnX:Ou,:(Uy7貳WL)/"iT}۝ްg\ Jh1<#``i |S %9yqG#fs'M)$TSY3O>RC MJ}w:OU3Ʒl@v9_`Gm,Eu0d\*Tnu7󜲮f3Qfw҂L_#Gj\:L}qQ28{qW JXo3IN@^xˊD9TT{}Y*?leC;4$ ek{oE5H\eR@%߸^w$<}tq4vo̴22$(nPV{յh {?:O\~W)Vа6q}eIOPoZ 3I4>@eKXXڸI0Xn\1"DWTTy?Eeuȯmͫ 2Lʲ*rmU*TUߪ#يϷݺy_5~q )ᦨ_ˍj4 i-sN*l#nPV/UQ/S-r ޭk ӑexNm7~EN3,Yě)Zq!0HWT†.rJ1[fwm$sӰ7ڄ2zHθ4F?'{&zM÷~ vsU8S#ahLM3;)^;h07`efQ}xQNvd^f 81vi-TElf/w&vPjf &vefe}Q_Y0n OzIs F@\6ጉPe.f޵wc^1f@D Kp-Z(}ï4ƇvE70z8]!!2ƴSC޻yMƓS XFF|XuƥHt݄re}"ɉs⺁ƂʽQ7 1 ;/ 4u3x >͛7Wfw?ꫯQO9iswO>qis$Pij.;sJ3fL2Zϣ@\pl-]9sHrl^b M9#2 KLt`qڶ ~}I7AD8Uku??;23;DES"NfUz Ng:Hȟ>=/8plrA,l>s3|8O7\l_|ReerfoFϞ}FDjsMW_~gԡ3<\vcՒ\y<=!Y1EQ? |MT{ wƔlZ;k^ %*뇋ocLh+tQGeh Ǽ:җ?ɋ-L`]NgƘl :wew뭷q1'g;إJOYZG/BJrmʕ_SK UMKrn6!#;vt=%&؏cg *g+߲eSks^zX#AA4w\i e\ .. &p 9!5dsw3^lynӦM> Vp1ٟ4.|8Ӛ5k_|;i[~#Gʇ?Q5~c I BEJØK'Bmjd>h.ޔEYxW[`矵$9~CRTz/ધڲlX16[:ޥbqãCkF;dC=-*k!Oɏᾪa &5(h׆z5Ƅ׸RI,zF򫯾7ϳ`SqϢFp&]q nUPGo]ٵ|ߢ|~mY*뽕 yrߵkɀ#$tc#os {:kÔr qd߶/#@"D_PDEy,‘G7,:B4 iy Ϟ=Kܐ23PbU: /s~SN9%~tjW)H͵3RW<@G۟6mj۶mnʔ)!ڮ^SB`XBҊ$N7[rTiO-$(_Nn~{$,{'+[HU?v]ZT>Hv)fبI?@U.)v9͡iXCNJ+Fx&6~C)7A3E꠶n: cJ H&GL>&p ^=,;wIS˜~ƍ^UUɓj~Jse&kDiZǜjW)7);~xC1'(Ĥ ?<[o9"7^&nRS!dO yV}%Hvުʽ T~RnDE 7r(? /&i~:WQ*~(Ӎ:Lxek"69,=~pUF +P :0P3pIBJG^.3Rn3ܾNs8, P7,@8X,+1E%;F'}9 ID1 ^ cM "DXq 7ȗA)LxejW)7+,1s+Xz衇)Ҝ7IrJRǰŽPo 3?5bp2=W9Er uU{?NRIGc+b N>GeI9C-?ufσaH6*~( v|9e]D:\u A(f~QHqn2>~YoR4N1658(G&rj͗Aa).ߖ@ ^+q9W~mOXjâZL1^E!;Vԋ8Mjoe5S)sS,[Px/;Se6~(-Rk(W7-{rr%L q@jqi!@EwN1FZe&TsY2UϤIz30z=o&ƫ=4ynr&/2:+* Cn$~(d[إ'5hW-rD! pK,qX8#p;yE[! A@P;husjWB@! B@A`֬YǗ$"! B@! xGźxϐ/B@! p#Epr/B@! -rH!! B@!0h3 ! B@C@+ReH! B@ 7Z w+B@! B`"gTB@! Í9]ʽB@! 8"UB@! p#Epr/B@! -rH!! B@!0h3 ! B@C@+ReH! B@ 7Z w+B@! B`"gTB@! Í9]ʽB@! 8"UB@! p#Epr/B@! -rH!! B@!0eÍr/B@!  f/s/o_{10SFB@! >XాCuÇr,B@! @!f[9IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/desktop/images/desktop_graph.png0000644000175000017500000065662312346515434025344 0ustar felixfelixPNG  IHDR `mhiCCPICC ProfilexՙgTM׮'300 a9g9gAErI% AQQ@D4y@E(A9=(w|Vw߽jWuU_]Ny# 3ʇH @`=ll,ݖ^Tf'0yDyɞQ^!B+<2 l5֔Hi_z=754;8GD!!!z^P 3?FgVx_ pO Dk}*<چ. kXGzƆSBh-1oC#XVF9Z֍Aa uܪk"_eC@Hb`>Wҿsl5WYoXot6=gIfZHk{@Jd5°xu'I587?ZM[(J BiQ(UJM5M-fi 0C>{a0 Ӄ3 S%h_]|AOv_@F- ok2#x_P & x [( 9솟SuH dc(gA5n>9xF8fX  !f B$Bڐd A. b2tjB54MBA@P,B@8 v!}TDQE4""z/E$@#YHi*itE"#|d9ي||EN!0(fJ~bMQ(/T *UB5:QOQcYO4ͅD;~8t:]n@wK #Qb\0lL=3yYbT$V kFcӰEZlv;]xq 8c+.UqqttttttttZЍӭx->/zzzz5z[$B+c dF!. D"QKt%Fs#f3oDFAiIGMG']'=!M1100z0d,ala|ɸ$d”TK!ɩ ={f$ !] EbF dQ.S(,dE',%,YFY"fX_`fca`cd[fdeadgG5QMԷ( [8R.)N g&5!.~ ^Ennp"{S<<<<'yL2jm§W7o_ǿ* *("P/V/*+xRCpVWhPPА0peQgt&OfDkDňb:bbb1Ag%J%O$ʒg$RjRRR/ zұ5c222)2M2ӲByd)˝{#O7OoWPR(Qxx[ms>++u(+(G*)OQ9RjڭVWKT]]Y=ZFF'MQM<ʴFh)y+[QO\/PVoZ_N?RA@A!0ӰψlhTl4b,`g\c=s磯qO~Z~'&u M.Y] v i %v  O P81iYEj1b1cbcKbWe7^">#>}{HOHN;w t`G`bjxIRU2>9(q\or&?lr&!-2eF##G2ee|%£99}ʹ0Bɫ:t|'h)|5i"|}'.pWLW 8 <$C * BD}Gg7$$]>ޒ$"1葜 btkV*;zsԟ\_nsI}O+xOXCFTZ,@D䀴Luª"yz&5C` wnm N]{' qF-&fyŬ¬}ml;*9);pu r#Ni |8|9ECC4 ""m\=cb=b5 Mt)y:e-0gdˌݙY)٧V}rC 'O,//ypz̏s2e^K.4U>8wZƼ򅺮k"Mn4d567͵PZUoJ}NgS;ZǞ{u]]k?}tǬg1g' WZY$Ԡr/"IFPGuL}g+O ;+L]fg %UTg]N!.7 4E!0N]TJLSRW2KI9Vymm}@ETuq>MF-#8F}mD6&zqf Y#ml{u2My<=xB^>|qA!iaUO">Gbb]bfW컵EAL"OJYԬi-=G&2VHG5rsC;zDɁS3 E:% \-}z[sl .vW}&Hך^;RJk7X v6Gd߼v;#mw{N. j<215|ݧxzY/z6$u~;4ѪwG|(g3y?S_;ff2/Zt^Z[Q.k^[]99 @8M9n*:U bqܸHc:sCwnA=!aaSV2 +Ic)yi̊3NmJTUT٨khi*jIkhHHx!ʰHhxdنێ&Plnت K:lst2tpv3d[W<(MCsw <Lny9l#5R:0*NjK<}516xr}JØ4t#ə,YG\cyǫO<>9O)P-t+J.,9=WzVwYVyuyDń TlU_յb7R4moU;Kw:5u~O}`}aw}\O |x*šͯN;8agש͹g+BkŴD0KB1Z^3`CA < s?pGQpy@|XCj!k(~ 6FFףg0&2놽p/ptF׎'_(P'q$‘-c>:Svy'Z#f vI\_IbLT6YGNrmފ&JRk*j jW44OjNԉӍ 077 256ojkQbyi{Ca9;==QƾK{=7=>yyew"“#Ea-bw+`mFC*[Z挈́rsϻBdqATbҺseg**/Sz+I764{fSۮ/tۼ't@_ry1ޟx':Ͱξ/ C9P@#ϐ$vd61FBAW+L.5V#qttntux~7=ދB'<&J,IDR.y&X7dcUf>?)Q,,Xs-m}fsppTsqrN4a@ !/a]PQ^A q}u RZRm2Gdf**(*?WiQ=ᬩ%ͯCE! f M/|1]4GXP,ٶ[i[[ۗ8\suzBqihwG:O9/b6Y!a%"ŢbrE}OpN.)RɇsG3ٳJ*q)ӎeS.]JVo|UbLtMbmrwuv>~ѓܓ[#O7^izO4Y4Ǭ|鷉e?lO[E_X7xuF&7)_d&Q4ɬd?~lC7˶Hq,LKo~ie/~c4nء6f+%7-zϟⷖE-oEݡ-Ndv>ΧQUUKjr$$$D$$B@! +ݎ+ AlK, A줜ani a2B y9΂XK,qF}-+C l e,c,)DfdYŋc)7B`pӁlfQX:v(! f#tJ& %9^SXG֋4uL˃Ld壡)Wj K~hh}}J|7VB볩 5Фgӿ dk"& Ymz*ҫV}_v !0 er%k[GEnS 7>J) o\ǻ7̓' % K(M6z+^nH'W;qtVl.AvBV\>/uB;ۀOoz/=Z;׮Gv>ljK:Něo4um b ͍;csqNL8=+ =c\5Iw-! 8* l`Gzz*&FRO/]zTrRϛ8)`]ZZcQT\$H\&禒3]t^NNH 9O;% NGrr g덅~ l !lm_@nK} AxWqg$3\=,tKn|.𿇇"WN=15o}\h;UmBuף$IP--&/ى4g/WÒ[ça u,UA:f!Gri8mk+)_^@kǕ*`5z[wecf?a5|\6xW@;-:G!{UXn[zލ^d^9yJr9KbyĐd8C (N=+PA:]B@!piRwp؝3e5ɤ0jH8tR@(34uC}ҏp _j{rIb14A8.,e g{~! f#QyEhB\ eஇ <3lX#qtwCMA!~y6-f`{:zJe%Xuٍ^d*~y6̉+< Mu'd ;3] cN{KߙJC%fN3ЁU$ub}~%Œ+~3 )t#qx- f\p}r ?dkxu7cM>wwvGƶm:M?AaP@X^ g=L3! @U6F vI\y:xG-K=op9rʠWR'uc;B3OK?T9Ov 'g0e wjPqca{& ~v[m +Eq=m`1 ѢO-bWPtt'qXJ 23sg86;`xqpq#$Cދm'+nOXad*! ?J ߟӓ;^YO_Z= tjt#x_;Ȣë~pG+:n7,C۟qVr9tz'™4! *<[ XQP|~\G!TL퓯ՒJzld>SUB)<%Tgx^LEԇƎ>2*ڽwAiDʼnpiCiWv۩ >tu9L}gNX*r[?~l|/݁{$OҸ}Gfm4z҄Z@xҮZT67V6x[uR yۼH>p}|Nk89s# l I%U[#W7hg?@W^/?>qipMܭlКcaF2ߦ5 ZNee}b?mlcpjM0c._ 7ePA=PDpe `U[nlws5rȪyx'|r8:cC5+A79'h=nZ &};",;JI:XV;|-EuOw+CWa x/IhV}ͤg)ChsS-%Zh8qt}n+Vv/LH륅*MG_'w}퇸$Mql%A R23tp5u=2}bb>_]܆t?㛿c\oίñBkU(OvM0l ! f-ic@8xΖu,96kG!T3HkBJN7C_#3ԽdƓ3GNKڤXXt'˱_a5%f+BSw? ~2r:)_TT4y,d9U|?Z-xɧN,^']( I:Xdn^,l\FNVUثr`g:z?DzRSjƨh_ʏ'gNU4jh5F 5ò;xE+`;x殿Ƿ./sl\t4x6&?}p}.=g{ncr|N<_u|*YEzފ9z(~c`].ɭRl(ƦX̼:cAI5%iB@$03Fq&,a%C0* h\&ܪ'ȳLn7뾂oVօ߸d)};(un]5|NX&8\{qMe{>A܁ 6'3 ׯǯ~2~J,||߸+`jLYťڂ擽ÛWHTZx6S~4N҄{3~l6r/ kB'$ >+5gH>Ö&\lY|^`|=+5҄`񱏮f;'1-14؀^<߼C|%c4Wtͱ??~a#mN&<)8Pjن#u@]k>qnS)5 x}hD-xi?fܸ}z/Fwo/:[pZ@{i<{P56i7,HHN\Z8r/ %PFDJbBJ<}ȋMYL}:YƦ&4Nmà wcޏQpjGQvi<-Ь(.#wl4sErK3׈o Wໟl![5?*JV`Xt`;vht}".AK;Cnp*Q*d?#RB ZLka'1ݜ8{:gEP9\ î\W3gq?(}++ QKnO'g֚O|p~w:9aA3mIx 2B5w7*}BmxٗAr7BN/< ENhjSVdaYΜVRARxlxwx#p:ˮЪTB.XW㮛Vןյz%KO|/?_؏Ǟz8g߅QoMI@}_ǐz+!U8fg ;VqŠwЂqEnGl ;g u ʽٍ3?K $?_$D{2v_OKp}kg>jSpϭzꏿW'k(UFE6P8`)_<{?>,,WǑ2+}cKh_XG2kk=T7>:OVF"M!4uuuĝ]Xa nlᴺF && x>6dj =K`F\HL3i6. w:젰 e_|&#p:Z H'(yI;+Y(PTaL:7FhS`ROq #Vzvq6B5Qh#]omxK<)46ČqfwFUW,=TȤ0hf[|w{ɲ5NnB?7휑鳡ѥSQO\ SlM qPPOc`1Biw7x迱48hlvxRf6UlyB@D)Mmm ɖ :y2*'EA=WfRO=%W~'[YKܨr,԰}3O( @ :pA)Ėj -Zsa7OR WN>؉";Irb ?(Y%cLK6&[3~}.Rr@LgK)B@! ΞݧK)|)4! @D Jn꫺_"H^վW/Uɫڗ^U! y'@1!&'W:f~wB!0m`O6Ծg(eB@J- .&rP![nާ'B@! B"ic@.*E! B@! f-1Dp! B@! fQ@f(B@! B J%)!B@! flrNF ) ! B@=4Zp=Q$b<瓻Fee+555  //%"14dE'\ 0-bp!A\{`ժ9_(l ! B@ɚ [JJ2oܤLyާL+Vؿ*ĵ>iq=}X-_{wooݶ|F H}}>_v;`ҥnyeC! B@OV$X(R?ު(IxkP[ۅ\uU922&a7m۪ԋDTTGf7W*i]@8^{툲nne+t*ײv3bo-[N(' ?S񙸑l! B@sL`F G44("]֭c'N*~T\sV(=<Ε E:t,3O( nj YceiJ<׿W1Eb +#7T_x(e/۔XwrzG on_ ȱc7TD^͙O(Ee>8|ϊz+׿yWɫB@! OU&x_]sh%>ܚRVoH僑s9 ( HSObx2ax<reb7bv_?'e M~۷{snBlS|+~vYV/|q?|@pۺ$%xR9:ÚҏgOW^9O?|[GG##B@! 3"Gnn\je|kO[3{䓻_ƮU8MmWK(+J.OROv1gNƄ%>2!%eT%&Z i= Of>?݉ ݅sXS/;U! B@w3R@Ti8cѢ)s!_x(|Ee71iyy>`9;O܉ݠqL[jSz'ν3Ρc6wLb0nV T_ZX{qHzzlTqB@! @.Xnܧ꫇LVlv@# R0 ly}V4S IDATi/vkkrۢ۫ +JV+%?yxܵv⩧;/!W.<-+_*>xeC=>ݫ*[FiIF @H+^{(\yB@! B`:+ lq8z9x饃 :8Ѯe q+W^YNAϟV_mεKL gzᅯMCDZ!ݴ^y_w)ncE$co?EPXM=/{5;TMmvϚ35sne[! B@7+ ?ѝ}ۗ,t y`]>uQ(,(>E5쎤6VF8֣s2J媻þbwwqY{1K%HG_? 6p2*8Z SwlaCe+ yB@! gI`1 `y2?dJ; K=&E}I…FEI$pY$jQR~8UjjJPne]lyvK&fٽԼ\EB@! xDlQ\WO/^[QWץԸFHIILۯW8MolY5qAJI9ݖ啭 =t|n֬)Q2`q};/%sgjh_zi)>!"vE V|^ƁV%/= >YI_P*l|_3,Z{M^[=ک J{R'~/'M! B@_fM'}u+xJҥAvnn`c'ށȑ?n+ \׿~KN*JܹJ^"f~>S+ѕ􇕎 +56qr0 S[}$'R?R. S(\|7RmkcN?}MQD817FW5z?˗['?ymª1<\,1+K?B@! 珀`wY3Ipa [WBJg bnXlO+PSl v϶qb1:@\]>iʶB@! E`FK>VMqJ..Uec#0;ԾP9Sw} "&B@! .J B@! D0efIiqфB@! f$" ! B@h! hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIy! B@!0 2 IDB@! B@hIysKf^ ! B@;sו$IB@!p #`{<{'UʋO@H! ( xDsOPǷD?/cMG! B@| |y3 8^5jXvq&#B@L@P:?&,ZKC! Q@.a.$h )[! QM@^yH h{Z CAR-29O! B`D!09=: <B@! .\$!b\`CYXB@! ( =tDFb,b"BNB@! 8 5&ht8K pT=<B@! .6\l#"]py_n(@T057Y?T{o,N1@!灀̸Trv81N V]B@*7SK̥yg]?;A")9M:˂k}>-8whb#fiFΆ=hFi[xq} 3mm ?߅,m'- 9ccZgj 5Ս"-F0Q@s 4)Ơ0G~ ii?@?e]{39,OZ|lk ^/-$Q4b*;,pDryԝS]mݓy^=>þ>-^ݢ(MM.\{M}+QD@(LyNkHB@YJKS>H!Zǔ8 [VBk~p'$NwGa}.Y\EO`wZvl$D9.&޷7!?ב#& /<1ln֣]^h9:+ 2+M>#+yAx큞ܵ l->[ݭd4KM;ؕ b]^h4qt^ a~A0677E,95: xbO H L|Zy*! @h99.df`YaL(c)t#Ckrr&us` &biSF+A=TȽpfs t|] }=05bq E3pr,0~S)Rz`NN䤐c?UCs?R&azMP >+I<18jGݨ`oҿ'ye36՟-n1b Dfft`bW|ҤӤ-ȾZY1URB{ztMIbr S.WpC5xĘsKJ@Aws:pְG~/ݤ4dG(Jh&+7nY4nkE%z3twH^c I lw[5Xx){t%jZ7sm&vD\;#(H?V,aK/Y%KFC=eu;cJ6v3wAǐ3m`>ϕWfd ;c)}EF@#$gE9wV1FInځ&J#/f(vy1t~N/dƐkбNݮ _Ohg?7trD:2 xGZn}m9D`! Jn)Z`{I +DXiq<$#ؒ@CV:'h"R$حQg$-,_oHiigy3'n6[x>g9n먭]ĩ|iK:VjldPxchV6C#pwa 0 2=#9@gVP(v“3 !RS} xeMH+iG<؏td09.gIZ[IP%_6۱'J B BkؒZ? :^-QFOA* v"-?!Dv,.w7RW,]9oie41T99F-V6V/o9')I0Q̌edL);EE@j8D I@_6*>/8ro! {"p114S3P~! ?vD[Iƪ6Xt&+-NؔB#8{O\=Xv5֛Ɠ1'#^Ru&7m[42Թ p۽"e^63H.N#ɋ?s]H[#c劥/*AemVn8̛>َ2lyjjHu=b݆yf“R@xGЋ[vNSHf==iGbZҙB<]wY1v^Nq,=rF F$TX-1+ ZLm U'bb+ֶ'25hGٲB4U?>wN>_xwh{0$Fÿik8҆5+W;ˮ iѹq i{ VA~E<៙8Pøx8mH6\1d ̧ˉ^)^&Y$4_CN0x )]QIFzo1~B@sF',MGyZCqrt"+ U'!_݉J\uDZeH E2Wy{E^LkǪhp:꺌\2)iU}l(/Yvǐe`4zX^ "_|1H+2H˩ ɬ?4H)5i*`-V(hwwď`-GGtwiY%&.VPJ;q%¨Q=RB2Cф_׍shR})eiJv@%>_Dc:Nd®ww$'À'6(~fp`ԍRJEJ}tļr1ٸ(_|Q(BǁPVx`ė^vYOJLk< hA%!6qxu3|?冡>lٺٙ9-T2)a%E$iTǢk&El6a JYB%\tj(>Nd&c`ͺr,/ʓƪE c֢r3V9cTOW7 rs(&K\.'qmF|ZlBVn6XEsJ'd[IIQE>]PڂE |J[Qg_x"/K!/n C0Nm8ax$<11Hcs59*DM4 f41tn!K\b/W?3SwӟgpdD2Opom >F1!=?ӣÛoaj);ccZ45)-h y/d67۰WW VQtuRN3-xqz薬P&ʵT\04RB*II[:78xЈM̨3M]v,Nib)z,x* wM)Ih(˕3H}-RCz6dBekP"g<&RdK W$-2`hFSQʤn7ԿaXV}5m_M\Jz!8*ܬGBVP_CzB0cLCXInb4O-+1t/PM2H94$$?7p#'`טuN:oPL>JU;O=7{Xw-' )7.0+Iܹ|vqqމ[pQaybوX@"F%'~P$/ IDAT-Ee}ˏnX>(/)"wlݠY)Jc܋wߍpXz* AhZkQ^ǵ?4*ry*,-;Hj].^nHEY3݇ dqKIlT/#R?Aq%}:.]GM\:BC p| en>5G[)%䒴Z8wwCowbii!JuR&fzI:*5j~(%eƞq*tEPv2+ګPQ2Wmxn՛`1#V߃^حPxjlS#) N7-C[mmx+H1 uu1l*a- n }hr+lDۻpBKhJB}{ (w ܻw@r^HD#>\+)/y+p0:5v 5Pqs !>PA6Xzl(J_^-禵i6w Å՗)[xDDN ~h*pA⒕hBW_'ͭC .7N)\GXYeo4&Kc,WN,[TZ7ҹm@Y1XS^ GjAi%j p<~J0Y=*2+خw3jO5a.Y(𽯡Ch):)1jx1J1}ݎ#:On@>DrB?]:-abgԾaZѠGdf b~Dcк|! =Qr'%kR8X3LW;5>U߷(p1 [^G_WG[c*poYˣZ4<+ d sK@sSz4 :ozW!p <^ v2)xbMΥ&y^ZMq^ZLJ7kBr'5*މX#2m\HYu8@3l Qx/2GZA-Wd dER<8u;Db+a؉UUhjiIAŴwe!eF֒'vk]{P]ԷT]3#0>z&^9'Du;,45C da?vs ícԎt}hd░[Wބ3u \6ׅ8Ic֎6R&As+״c Jϳ66ĘXD\2cQKu4x;Ci(=of;+5Zb<ǎ!z·sZd}vdRB%a=eKv;E<1_:o,2 kGa8}`/!&(TGr(>-W4OcSF=HJrc2GD"OC^ 1 %ۄ%epr41t)BpNX"bh<;wϟ4d-'%<='B0j|:勐( rO1jv#7Â|xY3ysJ@)N,Zw)H_MAZe1&8x\72Dc0%!%S<;׉lȍ)!W@_W452ϥi'JPM.Vf*T8HKBa>H9Xd-=9hmh@JeHvZOIn` -YOTO$9/1_G TD \sK /%㬬VQ)Nr/+,*;2nbh.*E?Y)̛OɮD \9 HlE}m=bCۙ>6 dJƸDJێ"<68+[7ĒSč,H1d!%TWoDcحQ 瓫F][[ YPDcl0{~a;v` B}V3&n: txh GZ;}B+ci)ۙ.]6{JJӁSބ>/&Q:+eeN,X<"Ǥ!;'oN;DDWA϶&;:ZB )jNg˭d-hK 9imF |j ;e8?'woVgpz% 68vBȡFF*7h`/O&t *mP~ CqВb6m! HoCfƔ wIyd Y9+ܜ)ek0*YDʇ^ż.Cu&UPaa:}eaFko"($H!ZJM Mlw:XxNpzˑ[Tt7`{fz{UK7CݿSq2[$Ky1)l1TN::w2oþ}&FJ;N%ǐRerlh)@|j<{K3CiXPmY֡!dҚN16>[ߢρEs;K$3y7?~QB?1o O(&A^/8;{1>4?}5IuY<(H%ID繪%8>XC' _~@``rZQG1})+4d*ǐ_?<׮1$S Vζ)57b`Sds;xlqf\ZJ1 Adc+H^n<=<5IC:h]Jٸ]:j`%Q$c}Y )hM.Sp޸1bqHg}ѸR0hr7%Ol1T:^~]0-zLBo4SW;Ps16Drms!T-V~s]i \d@*LX6#EOT)גaIRlNt85(hllJ!6AD;[&*g)Y驴[C.Z6ڛKw0iv0lOȄ"#?L J-71=d[!0@|oBUPMq-idy҅EEiƆXU7܎!_p+L}#e2P b')ՍO͛Dukc`ezSM%ƩH?):$ܲI =73ʼn:|>u mE/fj;5ό(S}en텿r+4n=pҧ9M~8]Zp"{9H>Fd(F K!B@I 9كZPF+Vppa-Mblxy@ ju8mIOK%i# ͡TGsc/'_3JtC٧uӭpݠ\$Ekdbm:P+eV˲RqޛK1F'7Xxez9\@i͍݆淀;&ͥbKҰV{{Q6SkMJp띷 ՞hƀՁ"_/ٵw'J~I_RK9]|iK.=ۏΣAe+HrVJu )u唖qvsEǰy^4:Ȧ89H%6V"Cwq) hYb'Ր>OWG-#5cf_2U7MJ\vOI_8sύ,'z,|ڽp,) dA9OVR셅(SkUuuG=Ց~߶ME-u0eͅ 9e5׹),t"5g9҅%3^BEyPD~iKt҄\v82ض;oקiRg !-D?- PSc7[C 9@9I'18 Xz LttQX#?MVqjX -ڔSoiFX"]P4JOɫ)tN Ρ 5k^PPr2M;ѻo2LzII+.R\,&:KtɍH4SMe,)ŁnRL1p3ֿH3(V4f(оmmJ M`Q5˗H+>THeF6 x]Q1^qiz>{Y5iiv51.]*v/t'^m.J]i۾= {o@";@ H2U%"O3}O,R !hC?ӱ z[G50[<μF>XӯXXSwYZt/2[fqI蕽,xtWVU Uih&]- #S:#' fCf=Q ZD½4A#cQyYk'ո:4Qpn< l8MJ>\P#tQs6BŵJ-.=J^po\]VSg r"I#o _95H3&0n5#`smoi,Pª_MjR3D2f~!6`z>8Hn+lSSUt`sSX@IDqj1J2Uť]uGUT] Sva;\MֻGMָ 5M.^[&4rCdh<4ʠ9WA썛Ú~5/StfEe^ dDQ:YZgLn\LZ[k 8>}*H˲{4? ܣ;rk'F*|)2<00 ">w4k#ƷGH Sǜu}Alc I2ܞ(Xv`m UU" TfƑ]qMs?cm=} ɽFPY%pk(annV04x>f.[fװ=1hz&g_xYbHd-mz_8ФZ2uuMԬOBz\,Ǐ!8piFҍ&}~r[cy4-E45YVW.(Grrjh9]KK-Sߟ<8 |f lMbɊ+eE~S3/6M:룿Ó0 .8C%d>2u$RM+@ eh}*ͨ㸽cCN|}jL7+/PC{^÷juX'P128va 1vaZ|hMA{]!NZ Z"S8۟(\A}ݣ~$a4(~:&*, M߭7),)܌;O>PW'Uj(B&+k((l 0hq\&9glxbݾv$*yغ&'z=T}D?`@k+Tȝ|&8)}oF0ipj:UAkxkPm Wiɞ^BאƇ1p&[]5q}177چz-(ZeJ^Ie$oiwiݽtF Q 33G?xW[Ag?F.f5rIT}jOy';/? IDAT*uwuk ,5Hf`۲dj7g},jp$'#ig5y#}rrKTb+he٧p (tؒNSICF552ͩ>Tk:hQ( tObGvf ZH1M :NtH 7 vNC_4'h|u^SiT8SjSv]{e ϝKC0mYƦB$Dek"6Rƭ[8g_ &Yzq$~ <צ >TQ.×yFړ~.5T"JkXϺ*1=LjV[y*-.AlS*QT{Y0Lx@7A7<8{ĉTg)졾6sJ9G%&ˑns)wuSV>E9>u@jR3훁 z{}$ &Gy_ҋBV;7:d٦24 ]]Rof*Y>VvZtgjA3K O)΂qԚ_;/X;'kE\iZC) S _J6d&Sޅc^X^|sxtb *Jk|g,ϲj>y(b9rgѽআ& Ѓ6- c*,Ta)uek`2Ao5ӈ0NӶr.)UB!-5PIvNIv4=;$ 9AOyJ:7pa30 l4)K@j[3`ہ@v:}\%'TktԢ_~Zjϛ*hX.w)NWf1"+THpihutXV $ek6DՃu39lcӭ6`Q|<WN[# r8|1G?-γz>#j}_-D`X&D.r"x)Sƚ(d*il0e'nxIk:O4L\]fУ]q>pS[_ o O%hMpqI}̰C5Rz2{<)7]~C׋lN @k$AmMg2Ccߖp?/TG̷֗8mOG$kN]C]q⸳Օ<=kh㇝x Q'k}gaѓj 2Cece^ϝQk+TGS ܲL?>u=N K+2M_ lA˚qx_T?6*;W!~A%pyʜȱ}df>^}}S{Ajܩg[,?($fIOgWf 5zȧn!Ev7c̭?w>棕55_8 BɅU1)。j)hI9%|T޽JϏáicpU[L˚ΚmRV^Vլv 1 =Xh4m=7~ա TOv?r?*]^VRQɣ,?3*Yfk)̶ YP;⮻\IH;Շ%!<˘3'MƼt(@ :/HWZMC4Vo.>]+ YFUNaҌA:8c٧swwVAY82~TlOo22Uv!AϙZgO7Py2]CTMS:f1x#T*#;7^SkX߄2FΛ!(݇R1APQhckj`ib[7gJGC)Է żYJmm(<֙WU~T6}Gg܋ ~=i i/x!|IпIeW襁6컶Y~V J*=5@Yٶd,jymH￟s~nڼ4q@ M%V9]с6\NܜJpHqnRqڜjCu*"ΨxtQwBļ 6"6_j#-; *@Ƃ}Mu]C*9M`MTMe/R%r/b;VSR`QQッ0]"F{YR,(=}] WG^ i-NLBy4o .KU5%C~eM2I=UEk%#+ܒ Ɔ!;7, *W9VǼdx'm US~BJQ*7x} 8G׿7J6 ҧ$yqk(]݁RG6 .I3sApXegz Xb cby!aCtwphX@& L[-cD{6?<#NXq]J,klpH9p,r}O`c*C%p~Tr l7Q5{lqqt4ΞކhٜYCkF6BБEN@vw~/^X mtЌ:؏JA.{j "z>?@v5UqQ٘ZXVVIq品|g`/R5sn~%Ǩ WkSr|]FFB11$xmHYjR3?ic("SWUɽ!벃KN |fŵr56=@,2ǿ5` .so2z)u.}==:,<8gxO㻝:{`d@}`-9"LYvL9d̗pNҊQUdX%MlGi'6?wpCMDjA讈*;p:S7XS=p*'"UX =$-j[(H I|RjE8+&稪Qyƶz 7RF!,v_ YحYenDN]˚\0k#PS)snqN2cq/3g|l 0Ct4^ 1qlfQ ȫSNAg#` g4k؄s\ڞ.bO_`mnu|fk8ۣ?"@霞VQXOth>̔<^CIp2`"Fe(lmǬ]&iEc l k`D@Vty/iCwC@>jT}A/I~wRVH |˿UAu|pJzKMkO:K@j3`׮xЏC?2'&뺵*~SrRd?Q(Rk2V ɣPWGt*V!x4@4>zwЬmzG5O\(UnQ/ U\&sS 7#oÞrG\V;!.K}(T ]q  ۔ G_ir BJbZ#D<W|.F!{>jAdDvmui-rl[8r^Z>ܪ[[UGF-lSg^9#oKzDa#a*RQU^OgW>VO+WW[],){MkLσYޠ㈛%NolN^ldkb bVʐ-~}ѲN@۬aէt]*TDfT>]4A@U!Wf3ְqUtt&kZ EoKa]%\^&%/hs 9c5a<@0cip{J>U_T~~^9gtϘ#齴<1}řO ~&|/5/wkTz[Y cT{R3 |QyZ`\cfCRYk秴Lw3JNNMvxğJ\5˔7k9T|a\.w@Ԁ,80jK?8\$y ah~N&@Fi9z0S gsO y2#5E >';F$=8sN*G#!(64O* K(SQMPY*Aq 738Ivՠ3faQe) -T$mccS3=jޛ {ngg'Z U 4SA IDATihJIE`Y8wal'b u4u!>{Vq:گUh A _]3HfsPvfu.x: bb_w>8P˯y~8,Ь/_w B ?r}\C2yAN9$ dZÜ rBpJ*##فI-nhZPBQ1njX(#y_l=|kb͂/fv2Jf! o˧5n(\c~ۏ24G۫I&u:w_xO՟;Bz5@#mɎ̂i`H L ˛B_٘;v˻@LH7j,аF6uS2GܲGt&S6 x~3#Y\Uٟ#&jt N0j I{pGWtX ./Ū'U3z,A6) `@?irB[X[GvgUr>WN& e鱱;b]q f馃7RA' Nzֻ[1%.RgU['ʊP(|QzM(>KV *3Ӯ;EE(22,ߓ4tܾȯzTD} o_J=sJNV57FԨ"~NkLpΧ@gf Kim4Ƨ:pl6s] o@uJQGNIE`/JXza5TҹOSy ڼ UڢKsT?}(Pdr`(M\T Cw֐J$/"nnơ"M@$њf?%?黐=̞c{Ykn<"BT[r xب]C!AjUPD#vնUr #`dtt 7!vp! 8 LUz%Ǐ:~MM5,zT#k {j})auNQ$2T(f4CT!}_+S0/j/gDVY>hJ؎=7x|Sn%5 3nڿwD?犦aBS/M7 u1{tglѨʽ>Pe8[dǺUqB)Bϱy_ mSXZB*`@MM*k'ԄݾuJڻzPe(h2l,/L rrq$8a)oTy(G-:z l}p+1ϳ$ nU5rew_GT3xj]3zajO pMܵ!>8I[{zt 7|Ƞ:fSt@h>r #zo&pgkzg;Z~=~-XҳB `&Α'/ YV_Vi:Sk{ǚ31cM4o?8[TЍ3 WV֩L2)s \/*jsP6dUcOPhqoREC*VpZԬ / E,ԑVuUhk48\;ࡼ:JKWuw5 i[! zA 5m;'[o)"UYOYjYT,Viت csP=:9u\w?џ%O߭ᗆAnjpTE$1=/}o 7pRCg 77t*?\?S3o XŴ[O5?9q= w* =١LuSaEJ^.@8$7/αu7Gҥ^y|8pEO;p@v %ڕ9Woohf%"c̭8gL2~|BtG0"R:Փܔ8Y H+as/YD>KT/FqDqPȈ{-SLy慈"ckJ/" < B} ͯhp|Lb\v]L*T0e576$~ ;z)V1W6)Cǩe]SMMAmDjon??rT'K59,1Xy5GTDø '>ͻ4 -&C>j˿$瑲 f6isxN~w|3ݰQ}5;Zizhb%F$Ŭ4bz'LeKNM8pr2v\SnerwzctGzh#SJǩ/Nh@ ǐ қ? ּ`qfo-/*67  rΞay*4;8>7kcAs.&W5J[my+EN{ b:UVL>`e{m (Qwmozwǃ ] 22|,j ңP]s*6`{hϦU`8jZ鯱)O^EߓM*ژS 5.( cʇ5>z_[}־57+is@\${x$#$z9kkLvzG2,e7:gz; NZV )F-2sְ׵tܤZGsL72+M(;}Z2I.@nSUr9niqL<9*&5.kt4F8νaG]Q'?TBTvW ZO8_VK(ormnƥ8M*xEd3wu%+O3&g߱zcQN[^[oQd.|۴:{gLc7thH Zu[@IYjR3ݛ+WD FX8s7e׼`KPsEs%"l^sK?,i [ G4գXtN~2i`|49Ctz^^ ;lWzsy|e'Iӻӛ`jRÅ<͂⼜/J> u#?=(xp+ FvϑYRΞ{ {\2/BPZBu]h KL8Հ7sfp!>lZwr'8}\8a Sn8WTuM1z`d:f oi>tlPg nJ##ڎnn!m7PB5дҠEYsLw4ǪF-}:s.ӓZt}|U5G̸@T1ɻ3*/|zZCPW-<TAGãMds?]8L3p=CTklLl}OxSU{j-)Qʞ Kpʨ~Ϗ|"UKƣEZ[_TZUA&?pm{ jjO\Q~m'XQk'pʺ&gC _ld?CV~^`Bd/^5:= ~cFVS! !a9!zWf=7RM?x!Sʞ&۔ >Szaj3`UgfҨm_FqG.kT"Ҁ}I~Q:ZQZ͓pϕN @6 68\6P ?%܏(VLio4y ,Fa_@ */+Ԃ"&_HujKPTJt![ Ԏ2kJK "W\41QI 0Ǐ;T.տ_nQ'Pbs+Sc`goѥ#B_SOjd6CeDZ~72uq-R 6}<\鿽NߜN2~!1NcӪ%=9+/]UOۇzz9 ȲeC𙃉y&}ЯpkU`S{2ְk j0O0_鯑 j`CHŝu/[ְFH?_1CN˅kU 0܉-M3+`^Y;Ew*WTB@--mG ~mtLu)\vXͺB>$xw{ݻHA-ejU͵VC^GՍrS(g9%bB x@/lNH­Î$X; @Âz02 {B5I3xWpxP{u0+ZST8l` {~J8?M%vVP '2Nye:;:25 |3FSᇚ䏃 ١/N |]f?X}8 0-=8 1k2wd~2|Gqor@nj=ܢ8@EX(4Uq2t '&K+oEKTwA)(?`A2qU%czȩjj$q7DEqR rXJɾ§HDd:}L v!2]*Zq821^8Af~Ֆ4꯻ gs4gbhMi3u@},f9C&uk}B={u.K!MĈv y}5 <kryC~b+F8;D6/ۈ*[ W |nxpYC0<iCȶj'TVS1P'G{qҖOi}݅`%=L)yʋְKgk9t~z[dmJ0"?ԭΕ$O۷T/ʁ`4ZGw*[X7{AgZiV:|e92]?GGT55EǬ#;fAv`ٷ0 >1wQ!D>l#'HkFAUbccKk(ܭ=;2i=|@YO+(˟ē&ut7y-#p2s{Ee{ @+W>{]#kv͖䒲 f[9=7]CIQ=xt]ݖ H!2>#~yyH#ٮW#HOG4h9|:d ol(U3iƁ7YF :d*T j u,f-4 "^. {ey\5uBˤ5?r r8{ [JBQխ`~t2ǿq`2FP6ZP~!ԝ(pNׯ RUѳڪ]_kDm>s}_@މ%} xHygqU/O _I 7ıם ,CF%ѝ[w^F4i&k4*D&@漂 ">>kg-k^NHQ1n_W3?`< PJp)z7ͥ`j~(3R7RlD]nV({|:p2/Մ.-[3't!|"U?̭ I=4 ֑/X:}NS:,փͱUא:ߊz`544rT֊!*]=jN] Y^ "'C[oLS)$43C'e[ 5-0Ǐ_{1q^IPx-TLJ594{J SR>RȞL s]C4KN䔥f 5H«,c#+id͟~MaidzDeYɨ#!s],zG:djE{FgݜzВ\M]͊,hgK&ẉ3:F6g*Z !,e$#`X}[aع!ի*GxD[2'k8jb!8\'3.S9,zTpB}j}S*w3TG*9.ߺйȜ_S@th 9gp+z\}Ԗ 5a bfJ[Vjnh~_W<',~ҡsl;h#sdt$;O2qvߓNge][pVBCWGC&0e`l0iW3Xնʚ_hp-ۻ cŭ5?&|&U)$taS(g9{zoC-f#ZPLT1inVѧUv.T8=d_vaH%(6ZÉ8,lVfLSy&mumSkOEgA{)qkޫC̀<:hM+T1Ϝ9{Jnu!\fMrޫ]ۈD^yY%lHU9vBOSiU.A>enôsSOŐRHW;pc&X'mR3o Ylǧu:ɯFPun+i J0=mC*51k,KJfUb"GT=E:4 4!P^E=~IS4B?&ZW7meo!J&4f 89Bi IDAT"Td zcGIy:X Dk8fn ^vmI}, 4S_Aj~}K`{Iv1'朾ĖַpW!6ůa=QRt 箏ɤb: N v9>ӯ|Nw?{nGr7/ >wuk~F'0; C=ּSͰ2*Snf=T2uc}? 21eַwƆB?j~dvE&w6J 1 B kԃ0oɞ7g%C5;acFiX_Bl J{Ɓa%ﻗ[/n$ x ==KÞўcW38&~3ݼq HN|=OH)7>If.i[i072fAM q\?|VџPhf$Olռ@$e8#JM+ 7!TgOK=m ( hvSGNDL?LhFXRGʟU[բg%y؛{zĐ*W&@qG8|@<h?oO-A6id((" {suCMOWyϡ>-$q}R*s7]MG"|??65 | 3zUd!QoSi)K@j3pЖޯ?Rm~,(( 1;rC#jrzNrndyҶiJ @].4(7T:pWӡz;'6R#pF~!^>WC-86UG_M[W+ȋՌr2֥M&;| 3ߝԆ/]?Y?L6a:|A>g/MO+l)Tkf:C FC6pu\]X @ \ODSx骝_ZFuħ0:zVWG[8\VOxu.j]&h$KZr!LOfA(inz+ 48l! 5Mv\SJʚӟkz>饰y,?W ߽/nz4܋_q2*u͠<`**VN%ĺ֪S&z O-i LAa C\CX`tV#̟EcprH'wxd ~߼RsUxI I޺y'h+PkMvíG{`rjnGkZ`BpG-wy{*_ZzT\f>Ӭ ?9.پJKESf<s(_34JSstKs#rT;ﷹȶ:nBl` /ĸNۅ^ҀYQ^o䛴Z3kksZm {4瓧N |g#T 4@M'v߄r8TUTN zuaE/TJecn kDL+4 2ETe4q'o*OAz4sE^fVV)nm y ps PR%3<#eܚkU8(L2U) Mn=Y hz,ϣ#ڻIq藷ba#D;*A-;l育dgu{=W~{0M.}ΙUhv}iǁ6,CEkS8ח&jU8 A4@3Ga*&@]#뼅o0-Ts=K1=.gO7#l}c=]U4d{TG2Οs~a7EE2#l}dpcOO2gʁ{c>SDc*u7:^TթyWd{M\y&p9ۿkEAkCjtjSHCiWچQS{>|f챽{:=9{i58o%٪x i{i;Ռ2vk qĂq﷨>_(7{ ۜ}^U<4(؞S=2خmM)I+j}FU%y*}rjfk~|ǧ/s6SZπ?BJ^$p¼RϿk\j^4>ݺz{)[oElVՠSI>|72gnC^pQ qϢ23H3"לj PF s:VO)v`Pqs~Sk\D#GG\ ]=ȝ>R K{3)Idz{B4-@.;@.inkMۯ`Húg9f~߹f&ޫ4\0$A{HbK!.3Җgb~E˞̈Ȱ y/{ (RRH 199۬FaZ$j}{ # 76i}3A) X0`x߃ kb'Hg;ZBhoϱ{MfrLj,>7+@Eg+@cLm#CƩm ʇҽ9lwBTnJ[Ϋ=Y󳿼E ;~dY ggM}̏1`T:gMOϩU#| ^mo(d9y1Nd9m?S =8p\!7Oz)%}l#Ǭ866* Z Mܺ;&iŽ6f6/>ڨslk6ݢ'Yd>\TXO2vt+9|oC_/q?.څYmoK|}G7oBC8# z r7Pcu>0 8ɦŋ,p[uttBJ8G dZzDĬs"L*49^4[夁XuT׽@, lxA~'ܓar' n qS͋eν] N5suV983%wəX g` l&}"Ts HNJvU ѕ~Z_.׶+d((g?#j?Ümړ5U@>u+ɩߣ=q#⫎7͏{ 0GԐC#>x冊좙|Y;F9x̞<%!c#sn¢"V(w $N\YǭTξ]V􇠿aiU*Cd;ڦ?VkD9y YP͌ӛ}Y=ۛr0ZܜW^wӓv9v9M}s;ps[ Ȃ4"8U51-7Yj-p>k@ªϜ1Aj٥|QfA(4y?F;3<9 Չ/=|[8 Q46O&W31cj{w:48yGH/J̣ҙn0G+@HqB>rŗ/unMug.9lZ赛/ 9re,~^'rAE,I6}i̹v]}Byhы?G/113.4q@|~#4lX֒ Z$^dV쬲PȊoQ̇rqбkaϟVEֶF2^ (Ul4K8gɰ qHV) 8LfGTJ͠nZ"98TKo*\~|eev8T(ҋ 4A@tԃGhA38cFkQU'XY7dר,m$0 rc zgB䵠ƚr :k +}[5F)ym*/!`Qdy[ bdCa&&,$rJG* 88etAs`&EFěy~[s}q7 ] ;#Xy9MA*7߬oJ>B`Za1de3OL%1&Z6 $65PO`tE|_U &yM#DPr|+Z+[~hE O)ܳ5imEBg系7y$I:l̎uxLas\ʎ&M}k랙l- oqFgHc1`y]5G >>jkjnaոlRXDUa9D toDOt^{:_-t@-〙cVtL(݆ٚ8AK1A-=^ H GI(gOr86$}m3y*O pٚp] 1f>G?UT&^"z.96 jycAM<4 g.7mHT9љr뷴r嚊ev5뗚>һ sS#yBp,U"ú=T>.|8D߷}#tUd9;F1pqMvv;S{&Jul֓Uw5^aM\@\':Lpm 1WP9[B#:|^~ @"˵ࣦ{x=(/s˱ˤGfim-P־а[9J$SF63P;m:UZzS1N˱ ]o{,_i-xberiu 64bT\Fue%@cNMNT]%3XJp gSqzv 5\ PٰluXp,1[UB%M i*Չ%8b @GEaR瀌!j6k8/~{FKk,_P5Zw}촓 wi]STb/6>%$c"_V? IT*?lw~ J;ԤL":q5F+ IDATݞ7d~цɘF LҎ$e o">4E eusM5,Fd&$ h%'QStRLE+EGKV *ɹމl mϙNϡaCr153 _7AB&ն\C ]z* ;)eۼ3bOˈ5ɨ}k~~SU§\cUH Swk$E'Hev.GDBW%q@/.gm <~)LU|XRR*wghܸ{|$BFר2 6OMr6lY/o@IoxV;kcWu덏1w N`ğz Mr0<~ohӍUQCR,S'hQ6A ?ZPӹ˻ 礈ґAAً-jTN,szH8ۿ41Q@1NuӷA5)'um>~ MEEqڿ{pى*Md(UŬ{?C (gC4 %c;b8ee8OcFzD`2L]?Aiˇ3[/7i|xՎr \j[4`@dXfցƓszA5!A㚊ۦmpJNNCwxG VwVRܻ8G=DxkUW_UE'zḺv4Dz#dgS7] `T^vYcժaLp=$ݗ9aodЌ~sUN5q iB_Gu}ڥd%/ ' c ]" Ռ27`OW' ;uXAU%,/J I̯}h\T<[hնݹJfY0\AuƮ]O9S̗Iʯ5U(/]G5;@{5v)۲1iٵG?nn &ZdG;O蓿Yaˋر-ÇO[5U9o*r4&9J\ʓwѣN4Ep.7_YyTW:}jԔʁ7iXL60@vVT#YV-:ăl(**}GXQ!HXVk jj?@MWDmjqt;WnO/k:10-Z)M̙Cbt1JczkG.>zQy]|q,VqhF _/sxcV/-(ovo%AIno[ƩO =@D1S~]z)xV~>({\a2Α& Ϡ'Oq¬wb}u6`0 *Ix4/q+)*]~ꄀ,>Sdί];Ϟ2j x1xtti`jj1}2wY k$:{ 9[[uSi g!g9M@BU2z4z9w;Y66Ap mUM/3>Sbwo˻ C\5H^'h U$ o5TT1Vv7WB!~|P/C >lsKW~#&$ aਥژ:Z ?GG<$2ξ?s9m콏gPstmq d䕗8s5?;TIyW?$B0Xqhww k] `%> u~z%zCű Yf9SSZ1KR@voYbf iي$R ^7@kQB_vՍP6JVA8;K/_"[~Gb'kFdh5=++(b؜˨v &:kl]mj0831%9E;8_ ? /dma3oؼ0(W*fAxu[aE0~@gpe5''ݺTm6ͭpB{LMC9< 4W װc:?R@wsEPjDK A*)e~qpN_imWEv:hm9Nt:ӧY^aނ폟=1 ^ LgF8PHRTgQ:[`r1Ec\0ύ1l rgÎeO3zxH\>;Sf%)hc>{6*)878?>p/77G >?*)Mq-U}8Y^~+_(H#JYt @&#,pҒ՛ae^zשdhaL"T%|oaQ;_Y4͗W*іK')F k&ˉLhE!㽟)a2d]]Z򵲸_m 8i5yUNc >,+ Jb[I?h&J-ā&rK2w#׹J3pw+ VUhbtbWk"[Y K-et6df6 _QKN*LaK'M%mƆc ae&^uB,N|Iǥ$/_!;Qc%pf MȠ͙gG8YwzBST5g6  t c6UNS= ܳ= | yC,mInl;>9Ts #QX[X{j&pǚoGɄEyvڠ>D3?9,R1[<12&AH\)->gxDsT6b[RxY 5R-Q9hTJk8n\?g5D"̺ѴUG&+tہtT&f+H3nF$-ݨ̜;׶~ '͜MJ(%htA7Nj,o|.Lm Q2SGR Ez#;X.|EccoaߛEAzbF9K Nc^X6`&fno δ{Tފ1\Bß_Vڲc;z?2^m3zBMp 4-D! ƄPtbVoKEjBhgij=p\uТeui<1͈epnNF|>*?\%X ySv\B܄9 ++0:QUɄ9nPsĂ]>9M^m|q ⺘U7Jb 7?T.AS' >f^GZ ޢ*՞8}Lz1cD ݵ%9oրJ?@JaQqJjy~︯#-O7`G7`NUàS<檉7)wmH?Kձ${x9 *&cD07_=7Vmu52#u<=TfЍ?ןkM3MSY= _ʗ:_Wҗ:<!w+JYE\*Q&Լ&f*3YZ'TQ|TT "Pf7}kB7K_cL=ñrYae3m9jΝt%boaG7?IVm~0ۅf3g-1afj!r4Sp7,%RgFOOZ[@ч)Y#kL}qKxo )CЊ v~a \Ko@DaJz.XR߄L#xh{Uqh cǢs(..vr!ȄygiF\S  LاPrؠZt#V6 jn9@eސe`a +=\kTޗ*l7 q9W>@ su}5cs5-c? FGܪzĉ~ЖONz4|D0ϾTT_L[1>: _N>P_?Q]Q6XoT[lkS TN#Q>5?k8.]ãjFVSs6+j<"5TsKbfeEVqMVz8@pB T-pVgL`lgʜ~K,w: ̫ymw*Ϳ8k"?Ckuy[f4E,[9V[ , \8UfA.޹T+Jg%(~USj(k_[$ƌ¬BVwq 5xMsd&$EoTr|lN/jaΦ9anwH&",T4?ڲ]p}Q:E 7~ݭlɸ&s>PwiI42A/||ERS33xVtf4꫶$!|jZ1|ѮLV!9hz:nWY#3W'qlPc׾q(}^$m~v&&ZZr#丣U%-)7*u2ā&UM)FEgG8.#Tkk]'؂Hρ}& h6M34!I𩤶_ h,hGNdl]|_@kIftrOP(b9y9\a:.Kêju S۠@WRu&GqMB)q+/U>M/KNY`zxjKbAsuva9U1/48vlOB3m~B&:rC@ŭ4*U$*yxP;sM[4 ,5πǷZڹ71*W XXK|Pۡ.>&v`XV دLgswv\/vw /kNIU@"WX+$ޏ)51_E̎]WZA? |왫/ @L%>!Sꂅ-9v~D[>%GףiډI0hThZC@`NFiZ!F0TS_4ڦt c?{ZTutK'|n=v %t @*˭}ߣQ gT0W j9gJg>Ȕ y9ҿAlHH0B~ϻ{ꍩ|j5w~ޭo? j|?Hf@$9dz-O{ `f+J S{@* KZVRkK5I%ctQ5:~zZN7j'p;TWWt' 0NA cfe3f\XyS}RMg$+. YvW È5q`o2auJh/ wSmX>v1}L=$i06UW(te}1LU-Rypk,7#SAd~d GJ|;?JG,JBjioURhU?]gK^ ǀZTMc8]{MNKN>ض{ ФWܠe2cgT_@[J%Ry& 3*O6ɹ҉&I\PVKUTs3.eg都&r 0Җ3WI^8s5R581JzG@N2usب?/N֠ &hכs\33Rx ^# %|B^,l?՞kZ1qFX[$i&2_3s x{jxz/HƗ\2td-hH[|# {dy1/Π[Ε/}߻33a9d}9N# B}gj_Gwaꔯ_G[\#=HŘidP:k72]cB/DT';UrR4'>,!Ä݀>%jRsY3/H+JBbQDy{rZQt *ǹ"9ICdhrVUG?! ~fYG3Mҕ9MbP_Om":M݌a&چzRu,>/MOI3& hUyE!ubiƊ $ѩl=ƆeMXUa ʱ˷ gyωS&mU>~ttR 뇸:ǖgzsI)v} Vգ1|@n\҅o0WT1W}uV0K[l o$XK/1@j )HQ="Y5^!&*UY \6g( >bjG3厞K`gz_x=[r߹WLSsծoaF4n@0JYdtnFM.}WL& ٻ6˗ým-f!us XRSÎQW%$pknZE>i+4F E_<.Kp 3M: Hãg)g+'&S  5+n$S mmt< gTM1jGwP3M2ٷ IDATQ2c4d W@S*jgO7T{jTͧΨHþ-ך ncQ2ukl-(j2ΥYZB6#oNZ2C wR[97eM* xBqA\n'+ۀAwtfp;ƣ1:̪ۆU>=C^O3& KFaդĠ}<8fcQ2 q$/M=j&De3WYUw{UHb9w6זyӂ1i4W8WZ(2W]@ϟp?Y|P_H|~#p(SIv-MͅJq@|~h#t9y iUSLFN޾GKsJp'}xxB8]S]2v<2d @fG5DP7v5DSke4I53r͍O*#:k(MXw$M["J2ug|Ji]J%h$I0[=jK L"2[6zt[++ٰT2Eͺ;4B1H^R( ';J?y\3T]ܫL4] o[Oy9GE5&ǷTYдClcf#+c3WL2ٔt#? XBƮ}̭\W aT!bO:ND!nr T^_c}otq$UM5ى 27d>olH  ]=A cM$s9ݢtX&X3Z@/JeΙmֈ^Gͤy(g]f!MmmjÄS*ɞ }e:#K1( 'hIz\ ._fݓs*m'zՁ/>UMVR9(֎1+Y A@1*ӡ? Jj9֤'SO؜Hӯ|`N9))sf`vJ5M_B'A.~#@tCl(ip|`?="N{m/WyJU"м')Wlǫ,;Zf  Ky:-UKN)3?>g[5U)Ҟl/ks:}W9q«ay jQN}WwVTGgG1kQJ0`  @ścSNv[P߂F@=yy:ZWۏ;taBTI:!Q!氟*QFuaZF`hcT6Κ[-↙KM@~Ǔgs'wy2粒Q_ZQf_ȸZJj$TuoPKT<ğ;8{sY?V]3̄)MJ~0`,"Q[3Y-@7nU˜7>37Sػs5Giݟv ŕZt-;/*_ҶMGI[_~V /9WHXJqYAPk~*;W+:WcmT,ypJa+=BO@S`${C!14kd21x/>?p[FJd4}5Ul|KVQ.QxٜDcxʎPam>$Ru{x;MyPT82;U l2*^1P=0ya2Vo&fu#Z@ٰ#7jL}:$Ui ͧօJTYLkzAO7aۅYlyAriV'{LL#fGSbJBiq1"yP^Zs3`~Dk* L}Ǭ' g.hM-adF5RQvm[y:?= udUrf@`DtU͚uo}4]|[oDU4n]Ҫ DKldbJIYysB|_wOԹ;WC?Ef]'2*G{O&_f|~(#?} 7Un)<LۼBn蝽rܻ>hvCaQNLP%o~GW[S9~94׹VE_꫱pa(%^[ԿU*Ԉ$,yzо7WѲˊ:_~7ή\M~[WNҮ16W~V5<ת8-I9tVR<qFO|^s eenVo|%:믹#p&[l~,WQͥjUMFz`F$fftD*kj8TXp6FhnU ˜#E}4T>DdAEs -464WW Lpb0./k5_ydeq>ıɠaak^ݣ ']Z`Ϫ@D8am*/Ar"~v~lVoDC4WNQ.׮Z9c`3+vQr"xI&1hp8,BM7ntWwX;_\b͖?29'asK] BnRtUCwTWK1oL !J|j[ <𦩝4WJ j:t3WWj4ڡM$-=qKa\=2f0)5 0Z|*UJK+*nϜA-jg \W''$~;Wߞ7#FF XR|2w꯱6p#a`XF#)Oɡcy8Viy`t؂YϒbC Hb1Quc)Xz ;,SCwS}*=h|n₱_kz5]5[S.׼$g>W vtxc4{ᇵkf{6@־P%hL۟C6Nf&Fh'~)'a8y~$h2;IUڊꍔ!qV;8ڌg3nvCRhA3&~| !P;%\ѮrUy\]_ICG`[#X{@\؀S?"נvJ $bw] sIw9_M3%ɫ6Gns.9<ԧ9zJ&GW0<7DPgvkwYՋ˕-n@l[d(Ǟ].cMAW2nbΟ݂1- =k۰أaO<}7T @ aEahFx2_z:"È}jp)jΠE`LY TNdX{ 24o0 Sl1SW*J90ʊsç1E.*,Yh3\{δʰ,ʻ5OM- * Cwn}T筱}#V )*loijPQ{v(8Ɖ$#E\_R??$M0+. ZJa,ʉ3s,شW~;շ~ ~heGjJ@Od YyNZPE]u}}8u&34Ϣ= /Ьwƞ|ˠiWzTJ| o/} 9 dUxXgY2.)ӕ$=fEy|0vțxG8XDS)Vgg<ugNx"QV:cJwvҹ$4{^L3l5:pTId<(p0u`}d$ bpJBʐ @0R5y֑=F|Ԑ P2Vܜ,}$lg/U=F|̲~44gk?nsdLGyY[hW'G߸mB˱p&Sܟ8ޜt;Î̉I1rj13Sf#G'0QHL&^4ˋS `xo݆,uV1'~~7$,HMeNFFUR5m } M@Y\ld2ʦ̞'x|;/Nb zFj#ditȇQqolŬ1pX&DŇyHGS'U8KR}Y5JXb+9{ KnGꉳLx諭Gʐ ϙ858:V![.yInP-=] vK>4sӭB@Dh8#sqs*3?=-pD]%h=IBypb` pVK>C[d|Aa@ȲfRh]|o|#Gn|Fnt0Ru6UIټvjUYGuhR+:h\0[6PNٽ,/:Vc7j/7GۚSۜsCaFZu7Q}LpL3 uu+8s4A$k JTJI).hXv> GT ,]c**Ӱe=T`_ .9{4 Wg% j utwS)& QZ2019( #ط.p"|=5lPɦm6[+5&F5gz%'oT"^Y>٩*u+=ȱcl}oYý5 i?;>Z_e?NM<7[w^[[.꒵7ks?l4p!ȌfU41VNf $xx_)+[a~)8G(/ȿt^Oo$HYiyrnN]@o@`>2ٰkefgkQjZי_V&Fn\!47|v9x壚ds  54ed٧,X ٣Z{' &}dR [!vnvɍQmW1ܧ2^Q>Uq~t g4F36ԩ48NLt{.[[O˚[UȲ*!J !CRe"m~Ww!ݪ!zP~^֫ ؿ*܌\=xYۄE0ֵbmtjí& {w7ս)<f!L.,@u /.nwz\eP1&Pv?z{dǏ*ݫuC^񢹪v-m;s=pΖP8OUpy/$+*gdpFboeܬmh#CBf<=;d3A$πG?}n>P7[gW]h ]RtX8IܥGԊNZRύ> jj0Dʕk*~zf1&; FPa?NłC w둟@,ƺa:y;mmSs~ҭBs^e_?^M%|%}SdAƨX:B#r;KOXǾ$q,6(a/QiJ*`L;TM}>Sp[n;Ɠ>3:r} kK3{*+41N!T_Syw^* :Տ?yI'08D",Q ΑYxٜ#`eu5\!zuvμfA/{n}*UN? \aj]UR>c{\}0G*J5QwTٹΘRH0;=su@^gQ@E=[_k`d4iiWm<FZPb /5hۯK#; },l&td&7zS8}lU|oѓe`@3@*5G5#dG5n /}\UOz9D@ų9Z3֬Iiysd|B5Uv]8C,wLN+ilH;=(.d ]`R\я IDATV;5tU(юSpJ cԙ2&=ZbEEbVU~w珝?}Oۋ%p8fX5UMpEn @ÎKrQ-;9cdATö"y0h2@&|O>vyvC v6{njbA+K?ڹj\y_'޽\ vP>JU* :lL^9LU5tH,3+\E3f5Mbg?pxix'{YύaR:8 +fP/#Fϫ>!٥lBmɂ7tO,Kp0FWր##8mfyTg|> f =V٠AwinFd5Q,):[AxyS('٠ӣXjT~՛* `&pHTM)mBYSЈM$L$@$5kُ>xJ2#-Ф,}!ТM . ج,/RQ:|SqNl9:! ܼE߇G P0D`3G]Fpet{=uB@x1k?%+TS=( ptnz^CNu"Ք_Â8FlapT4ʖO빆E|G9Ei:9LhtkK>~uU6hr55-)Ogsu)#1_qn/k%P>@B2{ݹd}[MTT+w Hsu>KuM}2`Z^4J읫.6_~W.^еIGd4f|iW|v>lza>f׊[|#p#00_?ٍlhȣ2j$Su\ ӀN5ړ^q[ܢV-.|S:ݔꕕEZǨFK@3  44/ Ӿ׹jU8Vߠwt*H5)KsW F.aIg.=j\Q3&))xtZ^h:?o12kej[~Od@e؝tyPp ,>; 5$'w\`୷T}i2 u+0k`|СXƆ )8G<[llY]sMg?${: v:W<@ _׋Ns>N- ;ڦդN =AF^_?U}$anl743>i=] ҧXI*ZC΍ \QҔKO.j+UyFZj USL©vDvȣ;s.:un|zѡ~߭BqXLY:?1ߊ.g|έW BYݲs|~`#SF]ljgۚhqN<gloG0F?rp? Ȉg&fHIeW\\ #<9c6b~!MܻEd7!ۛ$0=T5B8J_ekwﵕ8]#<Yck+#jwUM|0W:#}Z)Q_YJ714SoٚpYq䙍lfX[G7%vu} иzIIgԓA򷲴T"05?Xk{:qD_98U^V?%k葷*A\N7A* h峓XT[+[cY,\3R0U?b恭ou6_Lj=jNOVi3sa軯9tM ]Nh^*pGD wVF~\]L4 Q9o muџuEzީWw$s&2WKtŌ{niIUcJ/O5#ϸ1;W-͂PjqlNAA|5g~Qm3Ch2Mgl! ٫TAH_G`D WT8QN}[d$e8MFxm6媶DvϘH C0Ԕ8NafI52Ep@ ȡ,1G"A[evUW$~lV6a kT$(@ UNw=N]Rea LN)$Cr7U$*䷩iGⱋk닇4Us 1rD z t P~uBge_yn:QKUӊ6u-OAͻ5ElpQ<=Yg f!KcD ;WUC\8ka \^Qsup̡D쪔 }zC[Bka>Jsk޹l(6 JÔ{ >,Xؼ~E$=|ǎުZw4K=D0n5'sL}9 zW#c "CǸ " Civ^Xq@|ursp1;Jfftϳ N T0p{GǹI8?4y' ΤZ .TD,ʄe-qjfB2 HC)|ؔ~34ABYQyՆa- [G>MS8E`g+Sx|GAM%qkQ`MTEGqGe':(^$4Re'Ǻ5iڵ,-+)$E|؜M&}#c2*N FOw?tO4ދpqkAXV kPhVW<9-_'óWwq>"/i7:״|3%,r|󷒞lugx%) T_\#$D̨\?Ŀ܌fiiy tyOS\IדfTB 16qc2>0"+ Q7\`:BOEK[Pf"=;V hi7z\rZ;:bڸRE ԇui]Kb_^GdewB֨.hr¬ HBpF,NC҈kodKZ}A/oSRHQ,| * G'ZP;飉9.lqn61=+Ĩ7h8ᘪy?~\"Ͷ&q~A"L)?M8{4)rY@<[]%p(kD_I!opRјZ=ιN|fI@BTXg>*QPQ<z^Ky^V5kkGffvP HEŞڂx#c}ADa-1kc+o6#7Sv!o{"97>>if5eO?#"Ts;;)G.;fƆ%zh3. > T s2+dW jmlmK B&@Yp*'+TS֑J:lc ]Q+yHq|#Tc0g)]b Mfb8k?6=<)Ify/TA8B_&?}![uri|^n;N YT`$~v3m?*'zm89'Lfm$n_nj.#l r e_xSlQHc}Ωho{;)Ҕ% 0d]1}s]mgJ.qmH;^!*nzlPK%3pΐq&69e)Az28dk(\Nm tqm+ k57{kudjVɘLkGVt(W ridؔ]JE*YT+OG~N<$c/n\RY]u蚚8n E >[>Y|G` mk}4+fVG >xX }cdH6|` o|" GG\~x d-b/ 88n!UYG&vBZe'%~ k{34hFGJH&OЪqѱ#j*܌ ٠;z\ʲb,yQ B![6U)pr !s"FFJzpnq=]<@ߌRiD_EAYnZ󖶛.dѩ2WQ?;M'E#u)yR3o{Q{1@ CgZN٨L [9yEXnnsΐ}۪ԁE &_=^uS (eo }WnKRc9/6h /U3.KZ kUYǻVs=mIPiHxE@{ƳQl KEd N2Wkp= uKٹrtA%cH.Ɏc! v5@%/'SV&Gb 9J*/j 4958R e.TMpl7i<3ń3YS1K%Tg-b[Ot薟> jClSRV ?Y }|W lXyQ~ S'y(piodUe)doFf}ϐb`qc[ ~m ɜˇ?=r?RR}YnfG(`)݀AĎ5q^ϘG.wNW5Iekrq6.sH)gI!y|EAgb, y>) ydǢ45y%#3Z9εkݥJ ըj{ߐuɳJQd$T lgy"ZM - rnʫ#IQbTIw|иsg#i}KJvCy'f[\q䢿k#W8~Tdr&̓qPh2|;@.#̢: Bat*!$qΟݙŶHaNt=#@snj% %t2)Z(9Nvy/ocnlXNXE(6{!C_(vϷ%üdȇ*"}'MW{]AjHΙR+qh]=I']`mlpK ttUȃ~ȶڶyR>OHJ7S mP z8 VN5]5Pbk/JgKgO+?`yE6>f" r3y}}{]4Җg9V׈竻-9,QoַO-IbǼlZ4(񂸯~"rlt]OԟsWϽv!YV~qfRM򇏷$y}dJܒnsI1EgxM5&&5~NZ>DyBU91KUe>AA 7QŕCUG|-osH<5B.G@ @nG >Ԙ| d'r?K܏zf, A~)+ʗd='{g%گ~>LA|Ut? NAA\-d[jaeu?`.a62 hZF&RS|HRoIE O QJzim$hnY@3U _,?̒(I5hYr5y7 sG_vDJHS~?~r/ jXծ4\|4sN\'0Ur\fvMK86gZsg @P/u r53O@̖O|')7oȣ~ IDATdP gmY6hjCǣDׁ< uGa\*IeyO^RV'65,_JF676'%%5{i% nyrTZ{\ s<~ap5l-kU H3֧IY䓕(6UUj򿄢Zq*:rNʐQ}1PPL*sHG}umHX0e0E75ݔVU +nF`~"\cCoù >&dx [6F#aYo˗ioq<Ath?jqO7C*7g=^ /sfsl|)&5P+ϖ'OKU ~Pc 2 *:{$D:V*xdViɠlmiQyGխ_t3: a@FsnVa_v vYv*ao/7fJ{G1 di"m)DZ<wcp2]]203#8aFi\5m)>G\S8&%hsڶp ڀBPcn9(l/=Bf*9ywdeѻk5cz{$CgvPiHYY *5zLOq:'>B3>ЏӉ4,u' 9I7?'el@ *0B~zP$-6pNeR2rg#lm:aο!55r};Q{J}l{ıJu;=!@G/JKÇ]}̮J쬔A7 rD:}lNP4sJF13h *ȋ˷l27!ARO58_~z?ogIi9Kpqr^T2\/u yPP ېrz\ >{=q:tJ$2~9  ^;I,h<>mkSe1 B^ /T^A3_<b4<$48guEL=IԮbwL*6SH[Çe>g|24$63f?ʵ[]Hj_)D񮞈/#0"[_1x 6?Xǿo1ew3LMI7aY?CA.n UNsp˼sbmp17ŵ/)7QqJy8?1q hG~ulAB峓eui5r՘~5ǵNxtQJ̍}rQP0Qli%]>l3oޞIVW5\v0v4_?2ڱȷOʆJss6pHLEzOS])S *d`h.T$p} wgۀX#K VP sȜr*_!$J,a ;TܦݗVF]dE~^FhtNSP/^zLǛ\?W Işu$.+ۚ>+ :q{'GDp}萪 et`Y` `[|#p,/5z)ZNSV_ӌR)X07 Y8xy@r[1=2(ӓ8` "땁=l*#2 ;[1T09+ Y%`D @|{zH3Bv^%윤U gLEXY͉E)"8Ho ;~i2B*,C+YmRpq$0s$˝/8[L?Ln$OddrjCmd56(f%VHfy$C^O]팏%'OҍFE1V[V y"K; Jfh[q^-IoO] a.8>ٙ_۰$YF~tjۗ(YcK 쥔,z8,KiM鱾V+&&gĭ0M|D~)">%L̬TC$7C+,3ax\^~n󲲻b>]uR)ߐM]i LT.^JQw惛|o=$2 0zף 8T S6*s4]-V%xpG05iU< @eKHklgnu H1NhY @RRn>8vu&0@ć{ؒSBա)Lc!);2ˍ}ǁtk!*˄f~/,$/-4R*C6P+j K|ӕE ^[oyAAO9OarM6|7E Z 8eEԟ9 7dY'/.t0bOeW&PV]kl? };Ez钴nOAiО|̡W <]}3˯!^IVV%d|*woӓfL➧ےlmTEQ4{?suР% EX<whѦRy\ B x dӂ FG/%FY-V|RXRЎ]MݔS.UK'sЪ˭r7Iq[Hi n8\I`G{îM0G5_0x!)K+dQ"=>dgnLYu+6r< 5/d| ͐ 49/WlfJPtdn;Gj.*g3dPQK DSf7פQ Jչ+p)[fhl>'3gdqY)ڡUFGXQўQR$ ^9w,w0}9NWnTT){bi;$- ~17L-\U):iz[Hoɰ`SΉ%C)WI1F8Z)*> b]ۖi!]b8RhpIf(Kĭ0qz~ա!)DVz'&"k3smnU\w; 4)Q@Xez>m?Ϯkt_9$ U"m'A*Ɉ zPg1eO ,&i}g9ė+~P we|3, u*T_J` bf1q.sdf$ TlIL68ȻDx6gy^:ti_Xbԩ]OHNI~~DyI4LLC?{I2ϟ*EGpbӤl-"800ss}rԮ:-U6̸ ̐eCVhY x &yst Q]NIYy)P(2,{{B,r $%w|{3(qNk SΓ3bbFXvwiB&~N{нT(Vc$JNjɷDF_l k1DhPWEz̗s7Ȓڋ5H~Q_CEXb(˫%[\>$$K+^!s$` jC<+-$_qIE̐o0x.C vQ[an <.K:i?yy`" Y~}9cml0! 8l2m,99 UU{sBn5(eKGs!a *bPoZM~5G#CF@OH&UyxWƟ??ImtN p" Ĕ šAp2MҘL, D%rgjʥ,Fjt>'3d+C}}B鐤:I! =2sCвݲ$-QH-`8":^ݰm1j<9 {EȠ*4J+?ߗZ;΃͔:XLJ䃦vA!!ti1W *AOqt ;7z][$Ҝ-ߌZ$IhJN~:PyDς?ɣ8 [8zfc~ fe?P»n?<(7sxw3Z1yp}&/-O# ږpd Vߤ z"Юgvu* #LQe%ڶBǨ>;| -/'?Ho^ZIqm;ڣ6KqQsٲBJ/O(SY Ib1gHߐvH`'ds gd%σ[994Z9pZ$ɑμn@55K' A+_͜pS/G)}@vMJCT$ueXnb?>x Uے Wcm RT;I<[ug`(X~l\C)7;"m2WQI%/4.k%^DqAYGm2:a:~zJGgc3Y 8jgM 0IDƙ@nXRFÕq yUy}+c_yeq^,~gȼn۞j<"hqogt$ƿ [O?G4sQ|D67-Fm6W{PxHk/~(] (S+4bej,v:wPu:̴|NB"Ux39ozeڐov'h#>+|] lfˬdyIԬTN1.y8+ 8wLAyɳ$wZ_~(>*Jkh ??MH4ֽCӱCeJp5C'$TJ6 K^*_ib8c S3C0~| ʻ Uckʡ z@z;:N+ez]'nT\'}=GW&7/W!X7?pݩwH@ظH$JKX#W6FAUC8w+'Q10!)/aV8[69KZSW 9"iRbejJF FV q0paRȃ6+AI+ a[$GPͿm``dB9Lx!|nЈ09ͿJA`)|"!1lC0w8d)t0gG\iS4#yZkR~:4)SUR(@hVPT)ǧ'(Wy[a0*`@yWy'l8!?MH)UK6堚P^TNCnYHq{aK.IVܸ:EE#+CK1s¼֥u 5zղҲ'?Ki!X}S2ww1Fl;8M@퇙B, [ieE'!'%Q e~816' IDAT:މw}J8J%癘x|`]%nOdTU$(5@g߱aGև3 de#d10{! IHԳ!v J r=4V+Fϫc 5L٨V8a p2&^fVˬD dCXXuE/M qLeyK jQ *ͮl@w?oaSQN +]ZZ-7HRK!j:/ ogU*'AL'4Ա4COzMh{'!,$__[%)(/%5Ƌ.q/:<|sc<(<&TxqcІ|醮ۛ\$ _c'd|aIMPu@A;~SYEn e"dX %z⦔oU#o?{>xfQ+J:@D;.ǎ@UK85.V$Jy].]1KE Mv¾: d!P; aI#<^*ҲRai!Ibɢ{M#3s8)EVprX.XM "iJ$&+yH*RgEX%gkdǿ-jYw)JHiUш1Ўl̲AeEJ-RXzA%{$ga&SȗK"Boc9Tx?7CMCm'%`rK8CLNH J#}[Z[ 6i_1LBbtCuw;lk,sڪ*]ȢX~m$5&g3O>56;&hcT@?c#<|>4?^6d+@!Iv/A¢|ɡɻM)Yy"p={{b6 S|mD}Ŧ4TGWbO !(lIQDp2&VsVEw̥WQ ޚ`YyH@BU5TP7vƘ Pjo%3 >b׻ӸGz)#D 2W2ċRu2n7JbuvD6MKKp !h|KVfxex`kR]nڪXG#KT:Rሔ(6Z*8U J,sۻȉRF_.jjWh{vɊFQ4Zg4M~=Em"i|y>8*Dsσ{r{*&e|f/(]ZɀObi6ȫbfHF&B6~VdenҐHr,m$<*?5y;8Qťa^Z$}mq9}+xm!PqL5Py#u·=~&IԘCh2h!!;jƤ ><V37wM&/cYff,2Tn.H_s#Gi"GgMIaJ ?::HcInL PQ.|B, @kAND4M*븦FFi! p\ )T]v,>;Tl\Bz}H* |h%5c_STG?Ho.x 27WHČL']`=vJ 8kQRpT|u Yurr-1Yhlh!cnB`ḂsKJ :CY}o } %DܯMڊ?Ǥh<b;RX(Cs8UzpKlRYaᏜx!W"U麗mMjy'P>iy%v'n9|cQ\ , Z^CXgf$d a2> Ȭg2xF@ّY ZBe& -zӏ2.HryaNO4Պ-/< 㟄 W+%-EUUƨZsr 5YT9eiGe_~+T#̪^V`eA9HȺ{qvTM `xUogݸ@Vai}"Qq:uP^)C2w]/ɦvq{-W3%?%~S]Fc雟 b%HYom1Wj|Բgciz1PZFYx k0W#YY^c(%٢Хx`㣨S=9Fdꋫ_H 'L]1x*a0 sTx_BW,gZ׽xI~|ѣ$9=:I/fgɓyOO eT&G&JJ4D4Ц':ьRqnXU]^+1~$qG/׭{[*ޮfY٤qf|3*-d7BII4dLLJY~Ó獪Z4,f$;8^!s&BeBy{YT \DA[|riHzD&>rN2;&iC¥bUds®W-!SV_ kT?C 0MX؁RM"L0rM(v߳Ks=/TޒۂSusWǕAwtRYI@^eɻ<2qqUh?Q1d9'L >1;vgn <4;Q<@~r鲥_9#.j^ `/ =1Sj/ε:j)4"0ILV%΍˛!HN{Y@ӪDyh,?is8, ;0O\mLk夶ȸ>ۆbB"pͺ%e1 H8?FG' B7/v9p!/d[>" @k% Tr+v{nat _)aI=/ʞy e=R^!&rE3[Z譧rȼz҄듢Tٯ~q}yv㼊'G7Ѐ2yKsh8bnhz  F$Zq?ZN-* aE mN2FohuL.#* 7ITJbWּkr*[%~7,,byѻDvd}ڣfwf:-y8f:k =yGNE@?6*dmU<`"81o sHD`x9WSsB4ىaaU].O0tJֺ%TM㒙-yщz7DY;:~@QU 6%LPUGi +fa!"[6F rAfոqDYTDкsͯ9MZ1IJa I#ssT12v J? Fv㺤AEt/NQy0h L6e"TQX$r^䯣Bκv9Z\km5~ V&1lLo$z9~).ڔ-"7|r XU2i gՐ4uu7BI!Dhax0QyJhOAˌ06?c7J\/ r)ylqe=LTTKNQ-r'f)JJKuV YA^"`KA2֖aO\?\sYQsؤ<1GOb S,FHMee2>4!sǶ¸(}E{MJc nTtK@hK*p: OSM$p!k\ {V2q)N11 bw\=N)1z9K+l"?howG 2jUiRT|׈;,ʏ>K?L]y)s~-ڌ۽'x$#W^..fU Xidϛw}F0Av\3dg\]GZLFYJK߇/B.69sR~?UBYNL.Ϊ6LY[GQo:i"jЛ?OC3H,+e ؽRr qԗB0-B+4ftԮF3dS>pj?eC? z9 5RBPsiaP82ÐW>T*4LU9Hun]Mpӗ G<ne >#cZpqr*k܄ ~lqhZPFPp'l\u~dHr:Z~7B׊eζVU*їզ{T$7ޔK_zVRd :wJL)b ؎9]}hY}}fAP/2k,LmsgS2 ^9LJm33 &~)Ǣ1Q~IhW+ӭW~pªRLy_,Jo rbSbτwG2 \h[3w gMdSS V{šJktAHڳdf  d3cA/#zTQ "$1JE*]A~m>_Y|ݯt>=Mɲx`Et/)iC;UR iok_~Z}@ Z6_z, ñXqi7`` i;Т!#u]x}3(gCIlrٙ3h|h%ypu_`zHngW-jW2@*=-z+4U~9Il]%xmq­W۶oĞlGv·ϕ9ՉQN'GUt8BܽwW k %fv2G2C{h;]L|rK/ g ?ܾB. %ۓqw^:Z2L0% @,r"7+W,1u*u]@Æ%\BĻ]rsvB>c&ңGRTYr|"ժ-Ԫ K$TGFļNe"UjmЛbbyqNld]TF&+4 a@Ka6Xn,l2+8k?Tl JDlI&YY!i$BnϷI-| R!MP  liIdbR|'V*SoIJu7_Q]_?Я@Bt1>v1l\>Tu#-ΕhK?F eꎚ^^4 Ac 0]nwqqyLfٹFVLݽ<$^ *5 g7STIݥfB@N}|TxLek~aCj9/̀l\/p0B{[ۨYvmlPp>cv+:hc#AWyC.TT‚ŃLʢʘKWvܒ{.S~?'쿏^㘵`P7|= ߟz&dё r%U.7)%?oG`xCO.?ww[D$A0'0(rvwo꾳縡gfVOtp\ʲJ93gss@p~@R*l- 9=;<ϳ̭3'vO,b*ϥM3z^Ci Tʝه?;wȕ!e9 LDzUw|a|K4`?/ - iT4ӞP_6`53_pNـG-_3쩝I9ܱV|XJ4ˁrڶ}8(Ra<28Uޫf| <<$T:?>Y }*_15 $_$p[b2* c1eT[4b^qk0׾>'fP~1hHiТpZP܏2j0Xo:M)5Ps`,U*;!h혉عqpKNK+gJB_\d~fu RGȽя3Rxd'5'Nj8>.ͩ{?7?⛠>b`~Ձ^&<Y!Ngk[kRUPuWl2LԢ7* 邽5cO\79g  FGϐ>!՟EMQKIwA킔1̶fxUY-j` n2yyuEj@5YָC2*K SH%ۤWrt9rZ5st*¤n>"u"TU#ec[2GVaW.2AŨުp⊉z4Pݵ,ڇVǃ|qzˤ]"~[2KC&&7SlPJ,>$F"F $88ӫWhʣ/sHя@w0P hn.BL:PFy)Wϥれ[e@ uv3N6m/,i 𖗋)9'gTM("hW !~̜ͼH\ymi 8NN:eM_IPbD+4[gKvD M`чY?k}`wlFs Qj?'I ds JRw]@V7H1eM^I縼r 2U z%֡+q>$]gKMKo*L~A>z䐗cwC!J/ 9H#Ynk,5\3:ukbNQc FnQas|h5ݤb"8 z ^m%&yS M?JLK<Ke7Ip͢T{{sJbbz,Dz \OoQx 59:UO,ZOAb&/ȇkbg'y6W l`GYڱU3yNZ>]cNVy&? 4I97?P(U50  @\@#DAU,@aP˖#ȑ9}V>8$2n-RL+H;]藁 Jd+1[FK+5:,2fOOqsNÁ/96{/+z ]*6 F:b,M`3#jnKxhT{qV7^ـDIADr K c}/)!A24$L%60̲rO1T&yU m [QLē6 C꜄VïO86057{(g;{sVN5X{tO(:P]@q^%u4$oQaVHVQ#Wה{?A2J H1 ʟ63759~ ĎvRLGADOHM)c7Ip{ek]|*m7>~'T~I tm J=dS]U+ȺLO+D M&&\9`砬x ŨFhfz*& Qi]Y)9wa>B>6% ,@L8*ELfjqb!] IKKmԝEW^}t#c_WRX^(umunU5R.՚+ꨣf4K,'C&~_}FVF)7DmGtP>)f>⟍f3FAez"coh RUL7@A pAqIלm_TԦn@Nr̲Z݋yF0fTU躝ꞹ\ҖacTZV 6P|?QoK?=EQAK H|T$}nK9I*/Mmt'o)~9(<vDb9$ |s(D!:4RqY @P;"RH_$S0O<9p攒BqS|n<

m.G] dekƥalVXIsakڄbz ιxf["={ ,UST4i;pOی+ o*f`5*03nd5QG?yPLI 9XQڙ^%T[tN^T d03rgqV>b):t?8o5q`fA[~|FaUH#_>aL<{b(uIɻI,4ZR*uT!Dbs2WE;CkҦT84`wK I-,dV(X 6M̃?\?)>1G$=Ҩ!|1Ɩ䯤~DV =-/~yenr#ZfRtsAX%Pt)7vю@8ku|wYǿ;!*M149% m>s6p98%E uT ee؊*!/3 y9cr !ۈZ,,EûMJ:V- Hyd)-~~/2/Uݸj/KeMݱoICԤ^VnuK5_DecV=6,fԺJM/\kg[;Wzj&sf sXid]NfC#I:'57|턈$^FG^Wů,8"F>QR7os;p0 (JG'rGS<p3}db{xAK֗ E)[T 6kVJr@syV'۬͝AiK*)Su˝k ~!\!:ȟcp3RTMWDCʯRepuC`,lPu_4|pS!!'G}z6T#8{@AT7X/n(]AַY\EiWIdX] IDAT@qDoeL#{BLGC΅֡C}E< 3y~imypB3.GE <ǗjT.V=,vz_d !DeQ9M{enU'^N*Ӿ9ȊT t|䷜M[y3(BJe XAχ4B>2U~?6*ApN sWqHl;P LVLs#)R= <=,$_97GB6U;D.V@MfxF hU_eYnr# Z)K჈pЬipLJ, Goqt8ւ+ d,r[摒2416F*_ Of4t /ёA-_de',YɡBqM@8NsK؁,OMHE0 '4;6)-LrѨ" TVjS?yºxpNKRCmR-)UG_"ieUcDHLmu`_TjP ܑ$ǐee gB $ФEaYYZHiA<{D\^2]ޒ@fiPayZ)"8#!i&uZ=`E4ۯ\ B2,p*Gccr}5Rⴘ (ojT)jS('&9:_SkmHFӌo54=,1`?N=Gdܝ&xA tHDp۝% +"՜I>ɔq\Ũ٘SyG";%6ԇLk no_ +uk+@4]{?(y*1K%I=/!*aNKcksF 7GFu̒Ȇ?\`doGV#7?,+N~ .HkMmb8BF%áaHt;.aXڿIc~y:A9~Be:V'TEJl"A 1}s&c#򐀢Q+Tg 򝲶,uFeK(Yg>Cy@!p6Ʃ'nYEFf!YEي9Da,GX.~E#{z7ߟ9 @#/7I#Dt_H}o8d9253a<7?tDo Z/T3d(П Y$Ny.aT#S9Eud&c$r<|@T7%݄ZNFo`@pX^x@|BkF{?i16s 8; Z%h6>[ؠA YgV#5NOjE_6q"QQ' 1Ev 2H&>L]o[E "EFy6)Ջqj͐aڞu~ky(t 2t]yВ#YRGp`G*7]B4B ؊CT;yJPǁ]CklbJ**KLP4&dqZh<8헒Md%N,&JSd 89b(8,t fzGChDzY󂾠 UD/_N\9:J>Ty1]K שf6 k))D;]kM\<`t"QW QQ1z09p6I)ZFO6S3թ=g^0l"VJ&3Y%yux8tPW C[ߋ9ɬ#7s9SF"S,ɿSr@9 ٶß "^`$,_ݗu:g;Ro DbALPq^*zU6OKd8_3kي9 A׻T@hPpl,Na{[eE)]^fzgjL>7 ųq=tR;` x,c~@{ɿ&$5rY]|]ϴIAdu> ftySnF+ӿm7$2+x&=w:e,yYݭO:S}%*HOH7Gi3v t ʎr 0FUF=o"~*b-"ra3Ir{[5>+"ݾӬxNux+kpBB@5#覚|4jN_VSuqѳu* umKT 7U/]woi|ks>˭c"8O O3<0H7;i0;TwHZ]6Bl&9D2F č2w.Ǐw='Y!W1H`LhЉ>@Ƙ0+Yn~#w'v 9Xg aYD6jzb` 雿4+@ʹL4,t*GhΝhyOdirJ뀮Pp!%/1[]BҰפT!\f %d8=/ȓdj [H89gIc W:^P.O=n6ס_KkUio%%m _uUiRdO 2z%eBሌ]w)1\Yϓ֭r4TIZfǧzɮVx,G}:g_  xgk^5 Yv4JUig3A(5TL5~X菦31Zg0!ݓ6zx:Hg#cRj:hU+Տ8S˹y_5$>[~yqA:?&>^]bxLٺ->}#ۧT.+UmK悄\~MNþ}Gޓ_sM~SI\CC?e^Ps)  :J AEo?[n{]RRhB e\7 ◞`Bke16_a  3*]IޮN#{`X,Ld5;.5O%gWsQ(DK%! E'.O K7r$0+< Ҧ4]qN+6@0磟AB5l>|Ga*@8]@<kI5z]_Vp3\FCa^gGG>K(0B/:}kf_n4Cu=+V56I NH6x>Anʣ p0|:`\.J. jHdEѰ t-BilzJnkK'6[FM aTAXGHb=݄]l[&81AV-5TwſR /ŹCPL뫃̼݁ӾN`Q_VBU $lq'.Wy#$O;- [fe;ә eJ) \zh>w1dߥz6,Ǧ3ǿ?t||A 1$Av ސC̱17ef2Xr~}?9Dp漬EX]&1E=y LИ3OpJ|kp4/JlUԣ`2rq+ ΕV\TܴFjkьV y֊?*DF*96Gճ2@W4\'TR*lLwa| }1|)Tzo"g~zȲ%/vbb%Z=kG$.SRVp>6Q)Z SAI ЇZ _8445G޽ wpCԢvOP*6W91L>*}RwJ#2W87BM,Q9S翟D3igB?HpaؤUA<+ZYzu5IgDջ @<4`lzq:SXW#%0kNA%1"i!i;@MXY*y:$+J xWUE1~~ KK`ɿ3"FГ֓w='9PB41,{s\J8gm"wOqBp7DEp[&Q,dzjM6V^Y15NAb۸NB%{yNb9d ''^D|yhc~9}AFdQޡ|\s,gȍ #2!٭lJ:-<gNXbF1@ O}D3kT[>(_~%mgψ/[eఎN\1d Э:'8h/} m.СڹH\܌DO^u %pBbWFWG`!@@88 d0*j7}i'mp''W<>(x&,lD,iʗc8WZ3A+{eE0NBApHrwFV 2M-qNY{Ąv}p a?(Hۦ.Xabd_WOm?PU8W~'KdX뷵> 꺀L!`,s r%m[ߙ5<[,ӭ>`*Le_!YhG0׌(#-q~Zq$ +8锪J#C!˘ ņ*uNͿrG.rucY/N q-AaΥI!c;XfTF﵏i:2(npV6*6mC$hZ(Q ׾b}9693 g,I|0'd8y(Y]whlx6jÚH-_&Ge18'Vh(}C<UlX;I/i\@Nl +=* S:c;8Pd֫UEi3ܸ ï!o% ._3V 𾃙(cmG8O椃|6[$XOpqxqL?CQEv=ge} gs&6;PqjzB!PyZJBMDzØ[Eߏ"-ԯ-Vp@v~z鐮%>B^8dN*f1){_"=NwH)uͭrRodxO:<$!P~nʈKHܐQRX?os~(ܖ!4za/eQ嗯殩ܼ?&< k_UeF"e +/Υ lfpdp[veN2= ַHnzxhRgWr'Nb+dBb/IᄚOxY0dY)(i8:,u8s}.@J c8j&^=l ҸgJoo"YMgd |a\18us]^>d xK_*:eZ]RMo %|]UElq yK;z8캑w0`erP,v+A~Q^2ZU28T) K8y^ez;2B ZP R<*Iy*@ ;t~1(O9>{3]q=T,.I瓮Id#噰ޔcMzw࡬D;vmn@>m'3{՜4-3)4VNǪ$ii*⬔j2/ eh; Œy2懢mq8<ʙ %;iN1(.$g:>!)noˤRay)$LZ.^ҹ b4sÓSX_K?sD?z A |Ʀq[p-Ͳsɍi:v SY EɌ՟"(PasǵdϮ7f'by8źKW`!1JUJM7vPRR :,U IDATEF՛=7BE +Gmljvd/Qv\rr~Y|yC<_ 8HpL6òmv[$0 lV䔯VQzipB T< ;~_ewmK^8|W*_ `/PnStlݕ1Y{45$:!Wnil)'r`E`#8~s8H:|LR oNO@9wbTWhZ1`La;(ky O\&l ]=1FXt6M#B] ʝ3D4^8thP*պ B,,[ψc]&iSuԐ+M o[o-n`7n#g0'yl2Ob פb*렊U8V$k ju*sp0IOy2+TM%^;p>zez_i4 ?7krRT&x]Tq)돍*fh x^2nKTGₜ^4=mjH ]E;ؤrr3X3vHv28 kaK|h{J!㌼8`8prYNGQhH#QLqb}r(dPC3?N&y+%4!{@d 1󄀱QUw c=A:2='tgpPRZ*LH}\KĤPc:?vse/%MϤ%?Vts˟H$[ t]@ Ux67~'.}NfrNsRP+2;;/^̢rdF9(Q= QT )344,gHTo5R0(@2IׯnTF7ָ*ϣh8e*-ۤ%EpIַlÒs6-ˍ@n')r u6f8Ağ&͂rɍ|byv?b'l~LvU 0ܐ_i,6:>*cDLK Z!C]E˼ mzqC E4qyq<#RN@bR,GJ:2Nbl'(g!픋(_YPQYB@qDZ|PMxۥJ*F9/"q ӨOOME2;:%Ó բ,_ڴqpy9@Qp=$HIh' R  . }8PH=7ҙFk8I+ @< NN9lbf}Rq. @Uz>(Za4YT?w=˜Dφ?4էd@,>'pq%#%9mfydM*0 Fh\#}vҜ>I. &1s9)oqfk署Y'u5<9$p-2'Vsgw2\O?$ЩYOP n_E[K^FF$rF<q!_eR{4t Tr#(|#̄mnJ4x qHsP{ Sdu]2脃j8,,Yq}!R0ZQ6!ǸxRU,F{@B7jW(>%ϏIEcύM9T^Ff^:2a9Gd0pH4'PJ''-˗_]zfaȑ90SbNeNb)b~QU|`#aQL0  \ mmhc( 뜔!ޡN7sJuN [<,Il˻>[{ch D\&Ur6mrr##0p3TBlj`dj(r΁8>d1BLMg1ő1w7+Ci* 4B;8)v`nS [cY\C؜Xjz,٥Q ]NtHN$2MMæQZ7|Rit/4=JpVOAfDavpP J7uq5DQP6:2;4!ˁ9dkn`HQ9y)\+1',[^B fu<)6TQF#q(k 86H D:'dV{7X^?=.2[   DJ5:+Ŝ+>~3cҶ:) >Pe Ӛ`_>-Q:~n3.TWFW7?8`o5/R\W.qէ34'lz}۞cjdLPai)Y5􆄮=osj='<m~-#m~j ۯ@a:9ӸZoQ }r==d6<<2efۚ{1g/2 %ͦ&zCNB=1ڠb"NWb&jqTjoݹ ]@ QΡ POC#CK-2@wS+ ܦaȣfvpW\Ɖ\Kw0+rYyhǔBI'͹.lU攏&JdmxA^Q ]sA2L*d5;ctkuþVro"(4AV{7`'HSw?8Gr7GdG0;T[FO Z~SkCX+#گU~B*cz`y*d ʲ/ @/ Ȳ ><ML̔b~ +H0uĈX!wI=?'i;7AÏ5y²i~%4Ss޿Hlsz@&gȍ#ׇ}{͍ Z: ='C#bVP͍FIߪLQ-[]0gʝ80F'#i"(g%~Y}@Lݤ"Өp;d [k<[+IH1b 4NMHncJSFzl8*m74',Cs27Дǃ)k8k l>9{ї58_oݼ,m W3@Bk_FlnJ $VمBS]&ɒ͝MdLiBEͶk( <0..SEe.(Lp=b+p!9A%':(h("ix4+[7ga+ S-(=~7 -\G_!xNy?$ TJ;G UA>ЂlYRL(=΀\du|Rm-fU1IZOy?t}-W~ o裾='2'*}䕅!hSt}C5:΁I@ؘf Ϝd_#q2׃Tu5Q q2>,.crȽ΍כoSmP݊S$vn#MnE2GpT@T4j|%Rc$c6(C^tf\[Prk^/@Y)=65)Q* e>$N, 8>F ܺ1*V WBd"wo^kvQ|U 3_ 5$7~O6+|:<$T5R{k5*ρM0M>Dg^{YYݰԸQM(> 8w#[4(Y BooCu՟뜧y8H626]TY. dlCNd|/M̉enhlh]Z"2HI scU Vt>1ȴ:ڐU6Ht:(F*ǃ@$ݼ 7|CZ/m :Q*2둈%0=V:\`wSrs~kLz"Gds #]5JCi1jYF^7g/dl9(~)-kY9[앢ɜT]-c]Rv!IIfg%0לǮ88$! m2"0C3:l9I A5}XO.@v:E$iOr/s###gHטHj(Y5&b(羓xegVcL@$E*nk,Q ئ*.ڛ }SՇ6de[$BeR pfӧ7ۏToKT=CHJ@+ /ĶC>ņ+$nv{s.2+?(ĸ._4n:CN+aW2z~IJZOGҡ'U?ҁ4F$m+}4Fjp%# Ҡ$,n|ua7R|픦rRRrx4&, Fk, 1V |PځN#PFX@j@u:$/ؐm"B[Dbe/R%n A4[ .7U.s Nʭ]J" $O llgw'ƥ@֧]K}\8w,8?ۀ2P53T>j'7O~GS<-ӓ3m<Bw8U$u9i؜cN)$:G\ _v[2A!1'U>-} iAR J{C=1r\鎅`TP֨lƓ/m< A.9>0s#<.$T?(2sΣt=dtEJrSԟ>E(bb֛ ?>i<+߱?+MѡQfRU Z$:O?gDԫl (ɯ?&0)ӲVNZU%a;4 4A.p,qhrGLg"0`T=-{GzV=7!sH {R`3뼋ECM3*˾W8ޞH~@d.tr|S*^ow M+e^g P vGM)]ߥ^*] G5kI.v5$d9羉)҃4 ,3Ye7#1x\且Akbޒ%Tn&^03F(9L-I.*`椱Ts}1}lhs˟ܒGE AAQϰ$JGeNz62-g9׿d`VêZCxAը9P;x8ז3%kp+WBj55RdҁE!X:|@}kS X:9ˍ@xc>΍6Q}ޙ )>%ق-JkbƔڊQƟZ&aPFWl ؔQ112xhnZh?N47͠$rV5D8#٭Nb|K_K/VTPg\#}[19CYUƤA*B':McB`e ţ *d'dg2$>)0>ϫ(FiWFW?§I}hu_=.x|.×ӤT1G* QZ'02CvjKsUKA%UWIZ~}h5DOJұEh 2zZ8ٜZd-Cjx)÷rtjt_ vK՟G upĵ޹a9}ґsU^Z1yʹjcM3 f|zA@&TuWK>lud)[Ux@:/sln]8`mg뉉Lfmp8Ix I{0'#=D򤅹Nb?a!5" KYIyurKOT($L¦v`@Nuxv0^LRCo:O]deiJqB),**HG$wnG pevq6 [ɛ{(h6RZ}ddm8my(6kJ2.{@3䊗й*]oE|$E;ڣIPe(em* 257/5q'%GI)6ŭo@V]x؄0&Mӽ;]f.' |@#B0TQS-JL@ޢ/k\?F˚u1]2'3s7ZQh E*ˠ,,!O64> 89>,m ~%#ݜ,ɇ?G(Wj䨴Pq90V`qE\E *k4㘥֏{ v /!lϳ|G[NTºײ0U_o?r?3qoO m*Pس>-,kg h4^oBD"4۬|'A5Wlӥ L 'XD8,u*U(K6*R wըV[1sԓݜ$k@g QTR$[gKץ社a1 2Sͣs@/dag_N_]=V`EyY?sYG;#4g^7R5YW:osnNC׀{fdk$;wF 7GG s3$VpΑ%̜;+KK(%W@lD潇RuVNV pm$:%ut7ORTaY0A% _ Ȩ\j GnT-_ds(^GI,{HYHF9hՒޒ)HrFs6p5} up׷`y xW7e*f39Ia[d,8ѷ0e0[RQ$3܃|%__Nd =ǁR6]T5:j*{@vcc):@VQt\1=?:-|DeHQY{ŏL{LI}V5Y¹&9Ԇs-n"T,RE?Kͯ޼vlhlgqU@fHj5A9Z*bigf IDAT,mUӀ=xoX\g,_@Z $<ܚJig)y"?j$E",$9if}r'#0Jjkk1tm,K A`uTpqt0Urߖdƪ1*?Ȍ!P2W9782VT_^Ǒd|9Gnr#`B=Ɏ۝FHD$Tp:fF ‚^uK V:k=RoT7磇PK߆֛|`jvNZmw' "ɺs2cƶihfTBtΆ YUR WÓgF2_RV1üÉ.#a|y7vMByܧz><ftUzvpq lʼnuT+'҂<6(OfB>DAp(l*cr XNs9yqMeQo KZzEnH| V搚&)8oj߄Phrq5oLqXc?TιYTs1 aR*BNMRRX|AQ:s [ܐj*a($ݲ >n][O"oMKRD9ˆ:j6B$WG{h&$f[*KQb8wAqXmsnr#4dWɈ:D9?Shr#'}L 6LTBhS|@4QS036C:&\s]쐅{D*pbtF͔NU&g $+_Jmcs@[p^lFqqH2Um$' [\oHlDՉ@JM7˛{RQ)e|ӹdXm?3˫gvY3HE|ڀ*<"$1q*L] PSЫvo3$l~%˿:<y% t;sOj}3rwmY ޣ0.;|?tݗM4]:lȩQr]}֮n tX  H($,ؒ%O猗{ǙLbX9ǒؒZ@HX oVFuF7h~Uw}w[h[ƯέYo_SHC_EKF$ 4 c bw2V%pNVY*$HOJK5 P|Rb=0ړMVv`T 0m2^m!kǬ)@"@w:wKWA;7d;egsR?Oݠ%B mlcOAyUfEZw;їIiLEo),(BYdVX;==1!*Fن_PfFt|Hc"<ޫiqOC vlUH#|0v1ID(dj;TBv!F1iJ7Fmwt>!#q֙a 5k ڃF{}A`pCöo]7qx#s`l3o)zk GZL}D X#a`G97mf:s;| ;cEUW^A0k?iǻF[=H#R1$oj[,y5~0O 8WeϿ=})&$7fNZW P7)4_ٓv(qOmښ_gSfa[[-EұZWQk=w*1zinQjOk5DKZ]M =dD 4*@}mS~T KpEQ,Ǻ9Gsf2@{M2=iW[ĜosRcxC0ƙ2.t%;d 3zhoT>qy;'ɗ,x_}VO1?uf6,en7 x=eé5m62D&5 ~OV'2yQ0 Y={OYkhgL| Dh *1#;(p``s1#~$]úIL)F A8`V@&YD κn̤kG:ھzbQUD$:VVU$wr=* q|D)W@Mv9Øa 0^w /obb>ǺFֵX&ůcnU1ӧL" lP˜'hR& !'Z;]2jY63FhΜd&-#|f1 9G {SC㇋Y_]|+S>eUhF2d}rhoMLx`T]Yˍ8>c$(Wim͓v*N'[h{RI_?sbx![>K9:b<Gy= g3AdR>nl2ٜ+SW`NeNdlsUj_hSq +x Ir=65'>yF/]Cu*ŸX"LxTYKuj3/WOY=)kt4/k&Y4'gmnlSD~IgU -ry$J0EUְn #"h;:៴v,2} oRX2xMFKe"A[PW612طi<ΑtCsd$NV9J 4=dWuH#لyb>crzɧH&@^ NE"h*XQ%]cļ+t&G}mJU I6d'cX_l`7|){ځOQ <L$/AՋ8Asf2/$}bHڒWOif߳7Q}.Yb*LǕ ٣AQk"tp`.]L}9l&(U"<=gǼ-ɽ\o!:UDVIXANкh32 D4')`=/w#/2vu9jݷc5~7=A;yϼuU4K}fEr&b;\A-@#HN+YhKUom} f6٠d}hރOc29R=nZ*ghI%8)aA艣7Њ"QG`֓+'v\Es1E!v^z~r((^=8zsG/|*&m;5i<.6`Om:쯈k%;$2`Ji&Ob:7'MYq^g'y7&TKP g$5\%'d+Gju9< Tr@E_b6Ђ34rS[%I(hzg=HCrAt2Z*$0&/`_ 2ܣfș=!s`d) U|!>X?q?~5 n?b˝vS'0g*4 %"]+ߵ][qnP'?d[Hy]Z,'(.4N$ZuVД I(p`@*9amn%!}{l{R"$U>I{`2̵jvb0&e6^}n\EVb߃$_R ߭b{\?iG^ LǪBci6c/B떺a+*:6͒*1~_dhd^Ki<\ `6 uN^Znv!QM;F"n5NRfJle5?vЌNH1 ,uV{]PWIRdٙYGh>^Oj0Sp/Ɉ̨D߆SmDs ֹi?}n g瞒U|MB*N3j&]D<+҂F F{W{Ƽ9s._dudr`?CQLT m3sR $ vuw9"r|g85Z͎G㢞JAWd{\m4 8eLNlj"dSSM"#H6) 4 kL[`v$(# EWliK{.vTةw% el?$cE FqE@BOGx([$3U|x́ӀIF >h5 ̂丽îcm)$ Y+wsݨZ7H;GݗY]D|’|yA cXațB. ڐpjt gĦ!!W"(\?"}[Yy庢4~Gv 'pr^Lc4Oo~۶z93  [kWvĤn5S o\(KPU{ġ -h@ǃN02>*h}|tXk9<ʁ,Z6kۛ+`S7ه>4ߕ=PUCax>uX֥mCKžMg=W;l ?Z{UMIzw i |6}m)>hwFb8ggД 4Q`OD&;+.fЦloowQl<ԿfQ)gn*$}rʖ9 JO2rPl֭n /[koˆsvvC8;zF1˩na%/\c&3&Ts!B^4ZwYƒ=H CܵցvZmUlvSڃge$h&q;g}l3n=w` #-xb4'ٹP7s'bv .(>  ?,Ps2S. #Cݏ=>cU^s{j@Vc*f{@ƚxAWWD{!-av9&QtsfƩ[Y6JxGiQ2QSDЂ$L/[7{L;bWV>~J]hcڈDvݥ "{MbB5Ŝ@ [1tV&vϢ%cnc;{ħ-̑ph}]z햭@pߩE+obOzjA`5GKzW"u5'guCπ57obB2f폥sǬG-yq|-cj(ZT_q@K})<(@H y;N ='fTqW(O'rɉIQf^ t4ÿ}}}kݶq&$DO w IDAT#VUڳ~Ɖ /9IxJ 4 tU6<H3,7F-_y[B } r.ze Ю8Ij[[,mcM3ykL A=O lgWvk)=y 9]K*GS3ExBs }$(=*0*z4mbO_^vBe Kԭ[~(!֡b$}#?f/~spQ-YHwo Iພ(Vq͚f^U'ooRۡ댤oZ`GzSNDxg?U '@$)&wGB'.T_#&ܰH7m&{^s$&'`B o}MHmfCG}gϰۮ]_} _|nGufYWt!!$є,˧\8yۑa74$ƉmA%1|a'!} |pPCj _a&S0\ۘsR-|uF-[ӄ3Z`Mn}%EB&T)O60Rd >9{^%"T)+RT1NK;0Bc , W >ߣ^K j ּm5[EGذh LD-XS{~zGl,I{wҝ=ʻW~l2ظrmXڋ n6#o;g[u&@v&~]t|>Os=g/_%;?Ǚi*Yon@g>' [?sv!i*@fr0eI[M6GRֻmQ̈́~<=H &ؾ & F ?:FOh)I2DV!j/0qR6i P:|-ЬXmO/lh&XQʽy>яG={n싟:I'>I >M飶uF v\o X h/!|n~ŌvM ް8vlLneoaIP <*L}Kd_߱2e|dq6&\͕ W[[=1T*Hdˏ;Դ}K_D_V̭uo;Ϲ_~g{ejH'IA3>(z K'< l^F1nLy$o6l`;HLx>~ǎ g޵DX GDk&S}vo}qX JU@fDSg3j c6Ik`c9te>XYrkr&50WV2H,y%ξc_@EY@,I?&4-ʳ#GX/'gٟ ۷o}sgߟ//k 'I"mF*R6Z2^ZNHa}5is݈Q bWcgŃu}s6o+h`4oDp9'$M|~WjI񜍺;)'m@=a48Ә?6I> hX5Euo=S |o0ЊɶmfOY̼0cGNmYez ;[/oy!t -3 %~<ˍ;wFC!0R8!0 HɂFnh@jF* ά)K`V"x~4R1ii[]@#ٰ +GGGYh{W-<~B(>U јRy!tzzҶ:&=aL_gib߉c~N>6˶7hy$6W74O5QvFolxx/HyqL& p@q#_dź s'"ĜICyL@9` s GUzJ Y++-}=|[Tt-h@MiLnJMr'2SW|@T˞Jp E`ƙ@m1}sUTC!Ṵμf %;@AݺwЙC)bb4:GdKrnu(bU\{'Zhug!J`r҃Y43t3L%Yss&.lsY%_FcFր[~$`]b'|+>6jzEwh;u!HepgWPcU{.B۞{l< CU: 1K3SI Z$"0?er%[.',up0[4,sOㅖv,Ҏ8 ,š/5/!{|Wo}vۺ:;}544?ݢLoZ[&BYɤxImM$ׂ6m)?{ת~\Q>IvOP\01a[ aʶ]Za> `#1p>P|.H;W9>I*il8 FS\+Иw{؆=ű4Y=Rhe3HMO *vJQplT~Ӏܪ#!Swb.U(KG^CfA |p؏ʊa-{.3hn{HRFp1'])$| iH35LkKp 9 'C\XҀ,-3Z:)^Fb3.a`RD+ӗ1'vy]?akf;ۻwov38ӫ??#QF_̆JD9#!> .vkHl$;NG} (Tc~_XPYj;"Q i^$<E}ABj( 24H2|(G iyH"9Hx): iRSx0 P[@ܵ"& 砜2MxWI~#NlᅪLXer N:GfZ]G$kBMM.ξkaw݇ua6Ib=Š5xSU9e'iDɽV©5KW ;ܗ-H*eAIaeTmSI`+Cu%ׅM01P'RLb}m۶?;uS}3z^z%k_J+Pr%P x ٖ@HrpnoBb!p±.#v/wyM1RNDy_z@}!-O_@d`v'*+gz;%7G,9px2wJH*.GcNPxTw ~} )Eاn@&c)B`{vV4(z(~CrNٲq}`Mx>SID\;qX 3EtUjԖ/=8dqxENxW'i#>i%12wϚ_>" m[0&I@2ެ/ۆ7.}<8/GYˑ/|\sZ-1<[KL\0M1E]#ɋ~8-y@ClZ ?U.%m"5>x HpM2R EGCJ9A2㚣+5%SVjy(i|)Jk[{'liiuZ奼 xO_?ӶP6ϐ j̾%EK.N5w>H,ayHZ<1D, 5Ȥ^tq_:hCH?X_uM69 H@Dv݁EZ*=Yֱy+ @<AU}!i9$pPݎckfoGr4Ѫٶ%+;,'s9"ս9oѾmck;1㹇ͼP]-&Є1Ś`}ݶ3> 5e5%b$hys)p|^xࣲ]VP?+>k?p3ԴLxזOTɿ# Kǟ e"!@Eḳ8m\ɼjz¼)n Q2׮e#i_ɗ*(O ?ʕO>hO4ϩE%uӿ%̪pdxW/>/QV{n%NoH[ڐv8rD4KP\bu xsX s䙇@doxȒ.)֎t@Z?z%sH"bw5k<ԗ'޲!xl.׾֣ϐcN(x i%kO|4^Ң)Ƶ#ڡy$wX 0/oXpCg1L:NaV^m^bi|6BpIy'_ 1=@c_˿5ݎ=0X'tK$@!ӑ7=akW^ar-D(CÑr>Cuf]4$yтں%ks"WQOfUi<ȽϷ%\?XU#P\i^XiGݽ2 46XCܾjUtPSe84jI?/9vr4*Gl[^pv_Ñyv"z`h nxU#$duI~U̎WDuQzW]l9G<F@BhE?ɇäJL $ΡJWDR (Y L-3mp6H)O>ÈGv!S/u8;[&D ?PpƟ+ZKeFIS@\nAh)| @亀A?=y'OYF4غ"l3$VU&h%Z$fHQ2b^)"Z3z\A{c f.M:tVk~֏w;nL [퉇pO*h*no:fg=Ѽ'WH[Aj8Q %P Yc`Ϙ;!|ē L ^O3+G͎ahu(B6:ШFd@%whl]gdCfuwd;S$y;yp@rjj>C@.oBi0ECi#?~޳ө5qV#ڗ}NYsO:::3.֯ʯZ͙ykL=_̜4hI L aGQԊ\\"=k@fGf +L4LMg5olt^'Y?drIikR$\~BiwYԅ wt嗗zp !OcKM#$o#Y?ݞ#w,Axtae,v ˯c _#'߶)h6mf=xaֆcjs@5ۼ4%A A@%PCVcf"jȱ2=c|B#=MoO Y46G @K0# Ahpͭ$$qq%u z>ct.ȘVZ Gf@(ALy"f1R@=/8}$Z\w^l|G׏ZZ^Ik*!' g*I$̤#UPtJzhjy$ry>._l+_Cl>"| WոN緯=kn9_?d0IˬGfA0AИ0 mȔJ[bo5'Fo)c^v:YI%=ۜD;uWaAZ/>V8חHZkogoCP:f-Kx%8V~6,]׺L&V Gm'ܵgY:*jhL^q\T{^5q3ߐÄzC~L\`,GOXM &|OXLxh#ɂC)W5$ XOW-ݢJT"BPR͗Ĩ5}tkz V&yey7@mJ|k=TMp?Z,l(H+YzG>KrԺJK\DzW9lm[/-sv ɜ 2ʤ,{gEصpݝa1 N/Xj>!}l]sB執jE~KIOFQU#鹒ybEշP!] t@EhPqoƒ4#qGf,SZzm,RZ[$63W[$$Pa3  YoW g+"IoR&-2Qko߀%zGmfJZ|Gp]r}+ cͣh}.*P%vD) N # B@ WuhLGƧp WG;Ӏ`c{wH%4Fu*a捨zyYNRp6'."ʑ˂~cfLno,] IDAT-l4L!0!x0طb/SOc7<>ϛ` t$s eT+h$K!ɯ qUİTVgmOoYF],zLR #$nf ,R` ?F@_E-=h~ I-}c*1u%<('&"JB_6!G.l2$/TH #/Gk_@4Tmg*'`%#tSLލy R&3 +kz+VjeyowL/q>(DvpklDy&< Zxi ?gOľ[?Q ̎{'S6"8Cz@0 ^mdP)gU17gd|YS9 NC2-CHKIXo}i!MYm_K$!'+ >4>GZ}36v^Ku0ъfHZ=XmjrBԵ4wvv΀SB/~OOӝ;s㨯h^:|U6G7iDŗD2vu# sAdb~4ҞeΝ3v' `ݜȶ 6nd"mM\?ݰ 3̕TP&[ "RHf Fqo";/tϊn}ѲI#'s?O D ETZW1i ̹截9],{kO]TpY{@asJY YrZI`C }hG&k aim\&c{z gő~r$UuG//xؾ`H/p \p-35Wg~2V$KPmK/o,6mej_Ihsi9'aY VFV*w.3`er%ӖAzȓ!{TY_p V{xmԃ)=z# %I\6DsOt@± iDK `a\zL\ )mW|=&T b=* q3✨L\@ hא9dOvV*`R֖бEs b6HbLiC2ٮvw]8hc<,YDn>iv6,N4 e˴R="`|(X">g}72j2er0|A2rW?o!^d/_%PwbC3UQY{4*vou~E(Y@Z@O洿-(nZ#UKHVBE)b3=0`aSz3)Tp ,+.aգ 1.0 /*۵uZT0ɼL2:K#! fT)JvDX] Қo2yQN+>sb_<,l6Da["{!ThC䣴.]LM׷#muMw|H[̾_yʒ"_iV+:pHlߑՆD㶡.i}mDêw1޽4U"h!"t ?q L$%i\E2o-)E=z$P'g&N{ "MVd c6S3 hd2!!4PfV.! 4}%W! v1.!Ȃ̵K91EO(؍K|k$p 5ϑ's-mɍAb t] :io8$ړL< ڪ\=7~d1ETp?Z͒|FBHw\NDnQN z*ZF&9wiI;W5eDw 0EaX n[>A\׿.J^6x;+yr@?@2<@)ݙ}>|x~}6"t4 sR hKFǣqqŖNDҘ q2Ҭ,t$u%ƔH@^N $D$e-\1Ŝ\.SR4~d0 } @p1bʖa8cF4II̘I}׾i}7ZhFsLLr#uua|}U`y[˅zX@C٠q\#kYL_S/gP@iCA"c"=0Jzdz{\Yfz=e(#$0"w}Ai Ěs< G>"&>u>aiBNNٔ2N>rS@א6K YwO*>8I#y Nqg:LGH}z % 0aL"/Zj2A̜!a" ̓%U&(rWWj-JB \k0W&';NkSڎͮM|'w9+Lo%W h'Lz@B9 lm5q/X,}Ej& i3^agՖW/`jE2[sE#ɡBBBQrl#,iLH}W0QٌuS,,Ĭ"jUbX`R9m!R43B&s2ݮ:_ KjcZP x^m )xEʿWi νhLE)ה@G ƕ8f=W՘h &GV J5ksJry{#ڡ9 _t- -]fE&'BʄKZgxu vNLja(NEU$@He%6gE:q Q2I(]qn 6A%[LJ?4_84^R3rL/a;LTvݏ-3\32گoN ᫋@Ą_騲sNS5fA J7wYlz" 'AaJjYK@Rݻy.E(q1| )bm\I #VzU]?h#sRqʬ#F?twQ0&"g*qpR_8cSaP&C$Φ804t@ ~k-(٪Y'x (`U;zⲴhmqM̜H?~,B$7Jxf<0S;ĬRTmo&9R/c5D%N'#Y<=\ T\Ԑ=~SB= A%X NiWF `)&Z1. IW С@u ٱhw",@>)ʂ;˂Q=?ɸh@3"r #@Fub֌J F k]AZitO楏W~-몥l۳O7(/4Yd&hF`#AJ>}!CKSDGh$FpUe>6F'#UX]s㸃SKm:eV7=쯃e҄P/-!M^ !vSC / ?J Գ_tZK] I@v!Dz_e6y2 ǫ_$0j>G2ݯ@Xz5JfО9-ͻg|UBXnB=nA2>'.eƔO!ILK>{BQ4NI>]Uy[. ZȒe 8FoojLgS%M,_&{ >$;3T:d62Yg[_c000azDʒ +%7GWI]9'-YXФ=GEtsU W *N<E3Lhd2C})~82U=.χԿT(0 ]ׄҐH◣=7ZLqvRR$'"Q kY[Lp'SFt5guZ0Ҁ@ 8%EWo&XK>P%"!tmA6VbŁ=0ί:BDTP& ̶b/S%ʤ9_$mJmZ1 Ő/OPڮ#3fGDV wռӇ{ گ{GJKn]kh$lȌiWk =;{҆{+lVY=Y_bMggq[R@!}:GMw൴[/Yd!yc_L$/ KǼJX9k 00 ̯49^9D71BD⸣ !!Sw0oxfS"X a~*q|GfrYe,Ϊ!aT!"U1]غ¢߷0!{Yu˜ @nj*pܼ=#kmC*$h0͋+/2s,HƪاB~gfDy!b_>8_KJF&RBG~ @vr];ԇ?koPM?e-?&*|=SN)8 ϿuV)>LGi;V ƫ:lf$\ "AM2oeW20͂wb#HR6 3 -^`^ w(ɕ.b7P%랫 U;e>--ݢ} ϔ4ʏq?/D0ra\: C}mD<:op10*礭A|n-HLiw  `Itna,#C䗹]$ME(J&K%1dmeBtNb9>kC:/Jf8m!@t Tj1.YrtIVv IDAT"^E-KFZ ڟD uf03w3s˽F8 :N-bʨL (d)A¤OD 5'ՖB K $9g{ :4BLdpq>.@J0 Mrp@\IՌO$jpAxɚ\E7N+J4>ڦ$ОlK3z@p14r|4:b5p w4>gFQ0=QYaTpױjϐLЬ)ZHVj/*|#q͟p%~g,y8gC7O9ED%~ G]Hq}x^h)=1+gk~d 9g4cNWᅃW!};f9(|8Y-|mB 1̗c\ bQC&(0|2ˮ?0;~ kL"Q J '$?n?Ϙ Yױu(]E ie:}WΆH:1>apYi]>->i?-W/—CmQ+&Bbh%&Dq'bbb^M6{+ fIKLQ fRMr Ӌk|Ri'N!&Q~$muɏ |q7Ċ"ZUZ>qW/Y%\]BI!H8ƃcC1-4^fsu;Ÿ";A@QjZ2kO^_,9]~1bԦoHS/6){F,N$ &Q(&Zj:bIr'2!"1MT"P`<7ֲ].:Υ{ž1ƙ!nRa%?LICw^ Ρ?4*'Eёm)?4Ʃ )6)-ϵ!QK!wu6id&̙6zUFs>J%9jfې*NʯF₩%q\6NI<uyzBq۩t @Ϫ?qIȼ*(Wm *LAc5 $[lt&a&< &=)V#i~Q0 Qi W[ n,h4)5v}8 Iޅ8|?ܒ?arL$}^3Ұ>^їHbNbԦ9ĂCYI6-nЎI9&،Y츾Yj@|`" 8aY8+e};&s\oEIaIXeZnHaD4kPsQ-hxGsEcEճ iɛˑHSq}8wZlװ,3b T1ZLa*y}W JMs~l][RP6V$8#19890-#ş_2CQ1^Tpc21TobD s/JI6:-4ѡ>Pxy/E]sYɖt9|20ERADqEu.4E?M7'!I69M̉" Gr$NŲP!(͕ssʃ&I59n O;c JE R&yDϚjT1OdYQL S#b /}W@jkb`@AFRH.R\C`hqG0{.T;~:|][Y~V}vJ!*Z&Vʧ'źYmdǹ~"'+i4i>?O9GOjsؒҁDfǶ40A4SݻɵOjha}D3Fmq%h%XTLJjm$z^ܒ|4* ͯ$iܹzIsiʢNWVnI4&:]a{Ivru` "&1G$J$[䵵}a{_}˿ceYN-}-DQbs " :T~[1SU{ι'>'}_Jk߽,הO: h\\v0YXVkgT5>Cj L93W_mfesO2[I^d*QK3]R d2w`X+f~cB3uL&&w ۶XLK?'1x ߐտYkK#*?x0|\_: Ne ُ ^olO$O^*# S}9a58A&|טQΟfW7;꾕"l#r Sp>|,|K`T_ ; onn8_t`c߈@"*N&}]}Өn. MVR:`A?p|V?fc线g{(x|h>J/;9Wfî7ɔ93Lb_rJen9Y3?47ѹ0[}AM~j J|;XXlKNj8.H)YVږєa.},xIL]\%1[Xߓ<ږ`twlI<P'#y5WAcLڶ\ =s) H\UЄfDHGV {@mM%0G?4w:f*iYRb}w3@;S$٭lymxG׫C>B@e6" ;~yn!PE!7ȣθPcbsVyN_<4dhBH?EsSՐxfP+׀w{bӰRzjCB>>L8ZD 7z?;v ٘(V?}$̏ͿLһʓguaw$Ճڏ=/ga)sVV|fT 8*y>0=XL_|r7<ҷlg&Z!*Uneɶ=L^P}۽<ysU@dEw˙eġlIO iqikTF6|??W>?`|k}>vCAPqS#:_NFt\;nmjyÖ́Vt#0f$q37{p +,e_  _ᏒC5ye%^YdhLθܓIlX8y năPpa4oއ dSl+M׶:w|^?EK4%ݰ`%$=vJ^ޜu%ǜu݆9>߂;P-9?fʂ@@ =u4Ʌ_&_k*$t&m>y:{摛a(L,oNz'J졮##^^' O\-ƾ,B.m-4>@ES1mhZF/`SkDrVWCs:7D.K шdZֿW #H?*V.d7b|}̆)̗Zf,Rj}ᣬHV_T{bh^N5ΆGvD*<҄GMj_MVj6m@V ޅ~!WYijsp"rP|(! G}Wp6[G3AwK^5?O:>U}|gntɆ4M ldnTҖsh3E\}zLXlʙyuDU7X8x&ɐfk3ЊДB贮6gZH 1Kʇ>E՚gK5Hj}y9}5\aZkQ1k :Xjw ߎvG{Ӹ4 ~\NewWF+ֽh1qjyQڂ>w~6.mS:Mb)0szake90S%b@1)c~}>_[ޛ{6symPڑ$j\kzX߻vV~ΡT1s -I8g OFM8I1fvceMJXUnjC73} y,̘L`I ]Ydζo6 D.of=U%mػ5frR*;F鲒W޺1R=~%H0eH~O--wx)U[ABG0JăA @*T{7eYXS/=XNdBZAˈ=9nԍ}T ճApqI:hRڗI'n?w#kp F}s3E+̜8G(*QVlM3OR;bE@ә6rѹxl?M_q cv+Rԉ<]&^ cL5:rc10Cs|%,nv#fDy/4}SנLg!sK87|88h8Xط΁B{C}}fܝg+'ͽSxr4}Z̯8N}AMQ+i:l[q [HG/jjuoV^@| j΅}5#0"3ӷ)S9#kIc]8O+}O$2n&'֔1wщN?0=sv&ƌty?_DHh)XG{k޵{[8ϣ-d[|-h7 prEj[gR<fwgp" IDATV3ApyV.Yy{z ƓY1h6G a Ȱ]睼(_͑Q戎2DQt)̘9Nez6ۥy#FY_Ʒ \:@GQ mQin;~ ^ H)qS&&Ӧ- +C?&6:CWهVy*y_wp0n>?4E otrceώ42v6oR3z̋@?ïʈ񐑐,CX{ #Ne׺aj5+$2)X)g+T>ygC$ _[\_M\z2@fA`mۿDC[7wKTAڼ#Q6SmHT`xݝҩ۳ D]8&7RdBQl"05}F$?J&&EyZsDPWԇ2d%U-W`fαئPթ qui1ךиU|)xdoFa˴Z1M\.Kto0Vr(5Vjgۧu:[YI7i yYYnejO1F,W@4[r6wy"9o>`E&Sdߵ|lyb?A-Fe)$V y5InA2eK?[ MIZe֨9vQϺXFNpu뢚g.s(5P{nXCHN!2CZoOW~y@o}Fpo@?zrвII+5# 3M[#rw~wYn*C>x1}zQc`Z5/o{ eCL~h_wd]Ծ<2Ԓ|Pm [0{Dg9`ý98%0rsɅ&Wl6iOLw!Ut^Tb֧44E ) AhA\ ,;v9ui{${oz6z՛Gw9 GmR3^9 =xͻ<*^bk Pl,#dg1'rw֔mS J k$bS)LIDa(01 'TJti)QyhX/KͶd`xQaf\* UU"&mRk 2/e HD`HM6z_d[!׬$$3r< qٚm2]A˽řNER"L|GAdLK 㴅|1ޘ| F[hDJ 4 ̶qF&sp4ƴ=<6P%/qm&|߫Ž\MicWKVe-n(=ɧC']h!1 n 0 9V^k` y#z MYy]H`b9 gx8lS$h+Y'R)FtH[/?5 6J ?)$Pl;|ޗ-~dU;.)D1A:dzg욏vh ^LQBe:uFk>h[ԙvd#N OTR"i~-tk羗~ c< IꥧB:䖻9l }zϬu6 *L T{Se1:3Yxh~r`H9.g*/}4B D8NԊ40R1ߟX?_~]O9g,1~;;0P5"Y-ޗY JdDMzk0OMj~jaiSkA3Cc|kN3dyhiLJ&YfiA,d~2$ZUO`0DBNH_6 جwNw]~Ld,_~ $jW|ЯB. wꪅ: !mh㻶T{꠽8^4{q}\װv 3 |٨'#&oF|F= RKR]unn>òD55T Bi^Q1N0l#STEfMjpNZ!?ezܧCo͹Q5# vף&ZrqٛiH6a 1<jؤi)松Gʷ{2jfhG& o3j, өYuIs] tYٱ\&>@͘OZc^ ^vf=M)qdE1.,jdV~l>ۨ`E=džæyLs9<\ Nm' $p)_ /y=:i7tNfH1}:d@R6ΓtLj$s;rf ^dbk5\\ͮlE:|nuo)L9CXAB&Vts'ߕEL?Π1^lSW̎˗Y1iUV7t0@ꨣ22h2jZĬK{So"!z[ s As|B&%yo_2j.9v#wɌ>e !TT OKdGtq:hx"&$2GDx }y hNt":%4v h۬u*ock &XR @Y,zh9@RhjּeL˨BWrD|gd@=c 6-+0Ӛ p }CxDD3QY'A3"xH/p̒]3v&e+ d;\xX"! [kF{搚DnasBdM:=ki*dZĊD hxvRRhfsqTC"a8jdy7jLpD:w.R_}xy&ؾnPG kMOem̦N¨yWOQh4*st~&PoYޫ~~WT4'oͺ{;7uK7/~-1oM?C;Q_ Îڃ)p6˞ߡ;)ʦY藠̄vH F_Ҭ!S/LXxi f_鿌t-KmPM% ˒B0b!g)d5}5R; 8pDߜwȳo-YN8gbĺ_ݝ}y3϶?Pt0Netla0.h7Jtp,f37y/ZMLuT6)5H(WZlak> Ju<:s+M5DcI Sث PdQAȈp{:'˱LJ6C,%aDl1o!(1thT[H;y_!m4j=0rPRcq#2ERƜt~_g챎iу1SMYo-)an4bL(#y,(%LxY=QZsL7.(26{a~Ż&tɬA  ۜgh}7*;-MȪ0:W?3jUb%_ˊv^#!1/KdNHDh?qc:uq,d[h8Ԯ|0EV2\0اCege }F{y6??[6.3],7.HeIFZ9MMHCLi|bHsb7?~Ƨ0l4#qjhc(R!@5/Yo/ l*E"2[^%$g5Uӗ(tl|$AZf|V1jTUS4eG*@&{xBD$K08p14φ3Wa\F:Z57.p7@ɠr'- lJ4]5aFRؠP`xL7Ma;յlɅW܀5t&ۜ_ɖ/poG& U':WXg&Hگ"FZ*,Ӣ,LTHa.a (CU̪q3-> #E}IJc2 X'`n%'fi̔iJA%4#2,14L L2VӴiy9v<$mO,AG{`9'qKLiu\k&ɤӤ!$ǽg:7`"H~^`"L6@AU,Gc ۘ;e g}Wb읙`nL J4C#6Z$]a|,|c( bO&fX,uD?>0-S?!`8Ǩ RpLA{'Li4V+:suy5h_IAѾ,Wx&p[$.)/PK*WΧDrdj d=AQƐ.M^h .nD{y ~BS(RF?`Rg>)^3? IVKK^Z&`3B/]3Zbx{6|dHˤScOMK$ Cٖ_؟S" k7 J'蛁CfQFE\=K_1D}ߠm (Y3R-šzEy{i3s9iP-xIڭf>gevdʸ%-}0*#wmKϸJ@<)c t6"(u%5Ic>}{[bPx*Sm;۩Y,r":&_E>{ ai1&ժNiTQ54e-33򫔹n_WAi{up"ؗqN`tƄ`siJ}uqڃS~8X0Aj=P^ɶrzk}zǾcԱ?mz8pGʹ#hT5O OS2-ٷ? o_kkב.WZS2m8& 4Jfj1VIDMقe!#$H*5(J0`5"FkŵS3Ӯ!kISGj=wfK9;!Cq$̐lUGSnj8dZ_t&`! jVJ30)RUIMF.| @n4a)R:fVEV<~{]B^5. Xo'k~+|B~[1eYo=p渊_Cmdy'j WĨ/V}mQe4gU$P)0ڹVBߙu_v41w!-a9Qݏzҽ:@ķ0Ǻ?B!N?4SɦwNitB3"0A? >h5i1a !]`nYȶ{)I滌ZKIrM _ $0@FL3J025p(FsO.׾\{y2doqӷȏ%V!jH1LKOKGȚmb"Y`CoM0uႌ|3#<*8?CHwk2]A:Q$:wS ,kQU8*3F&CMq2M"`\gTۘ^->0sM, Ln } O0:J͐ uC\CTb?hJ`o=C񔀈>lFWgL* >#Yh* PLlߵ;v<6J]Y|X߭G$ji %۶\S\T'M9/P)ɱ=k~+gI>/OBbw$%SSnj\ f_?xo5!1pVl:7"%?/XU\ʣb?!5QZCӓ>|(xWiڟGi&2DJ& Q  A,0h3zz/zM!5 q a 5)x{#j w@sV#4eEDbq0j?{ D8qjc<>946E.g#N`ȈM$]dyr<ږXo\_>m?$ZD1mw)VyIT釷BR%g242jNZ~پZ7Ǿ&pTSq=,$2V EnWGRm)HߓÉwW^ (X[Ʌ$J<-=1.ȴŁfӢuLAсt:7riϐ>kC k^ccCa6hpKDBHQg ?ĿF\:}Gh֮4etl WAHG5ԦL f'`[y^sZ7c/W۬ዝ=߽&K$ӷ ݁y2> 9V .`.'@1t jԲyUuZ x~RMHD}B] jpFh *pUhݜ'&\ ~Fl&ۆaq"My7 ѻ/l`Nh}έX? عĄ/CS I3+32oŠ_?r  3֧jy{c"+.| =}bz͌|٤Csȗ1Z-ĆȠ |`-"k<9)k>Fa.qҾpBހB5N56= -QZ0 z[%jOI$x։{6WۨoЏg ,hU[7 I\dʒYyhzѻ8/|Qjm$ (-A X8&YEgcnX$#HV%īѴ*̹x^M]]M4VV2i43Ynem>MŞ3Hmk KGܲo}N N|xx:pAGJھ\ $vw9[97— /+ЁE+"4=EYI RleijL~fRE8.Za]f.Ⱦ4Yg r^:^ g0mDtn (pȜV(@S_6`dp6~Wh4Yu`WP#Xcf ~.2ld}zVv0ҙә[ U.&?wd@+}M6P9~M?oN0[Cz4$K\~ݯwM-԰ddz%+il̾AnAv _r  4_牅pdrecE2E% _u'ZOC6ٳu`-?Z۫Ol|溊aϾ_|0X̮g.c%3,-~c0H!] dۥ(T.>ɬ+]kOф-S-ĸm*2ER2THlbTDn /Yx6TVpó~*jF!c@Rҙlv[V\ߍhԷ?9zvAS=Z:C<}>7 ̗Rl|!7@\U|d "Xy~@]PC@ɼ>+Q1bxd)l?[hvw,Z@~P&>8 Ad$ aOͰ"!H[d5( uמ]恏GOiWwOCh$2R~#3Cv664~G+`$>i`fkuk7w3|FI;nʔZi2m@يO% .Sh@ DѤK*L"_jQUG@ Q]!tpHBWEШgzz'7.'2:a-Z[QVҹ~7%3l+њPͱ&hgK+YP>Ε ah>4;&M=C>LO[ aa,__Ä?~n=V5Wmﰛ/hJyv)@ŤѦ]4dŴ߷ !x&I>2L?b)h#5$3wrj7B%^:nFpɬ-d̺/~2 Qi h:6D2#շ٬ 0 V}P%SֻUQLM0Nwgc~^n Q$v%?^m p> MUDt.˙p$^,M]mR{ls^D8{-`gؗIK ?@OdT>vw.{|@ EZ @=t[+ `BCKbEh1UW2'Yݺ"<Ȍ d Ioz[t1Kٷ6㝼<&PềW̛.moʴj(-42e1|6GLw]GDfm[hk3]'`tFsHSC2"&<R 1Cڽuip/Y7 I 5!jx0D.x5FjP D edLƅg|l-dz6;igǢ㬨),-(<xOr k6X\E_M+] [ѱb_v (GG*}u@' VR9MFDmgy'?]5&ޙj.L:UYr:x٥aą^ĥ~I>όWCTI-XQS+HzFp{GhHeeۀ`t&6fj_x55 Y֧NsvIwd|'uL!9>II.H ʅoMv_S| %pfUzv%@o+O?}+wAN뛯~ϾE(q+DJGG"0ˌ+=OmA N49c&U6 LIi2Ppc܄ɛm6i%n_?ɻ Y,̕xnDf?d[h8Uw6˟"+@uc;ȁÃ*$ڄ%B`RTbF>#5z e-Ɣu|B'g b]l^<9bZN $كØ@=㽸hmB0qwSS L-M]*”ӨbՆAu{TP!U[GC{ {=QIL(w2fH_@h 9KFmNL 5?,GfY=#% 4aYc\&jSu>ЖX@^ MfT vI8&\ Y"ZWw/dnL`{L}EG+apyd+,YZ5s=g(Wy+e m7s)@ƒ~+yƁw= ! 뒟]k`b 1^|UJq,7e|?r@tT '`) \{oh@߶jN̐''8uPrN2襟9EY_1#:~^n?ag3)oğ O}gC)|,elҚ~a—H¼Ϳ3}Q .LЂ,|S񂗱Z!1hm l)u6K jip2ݣz+5 ,z#m Ag L xl6^CYEVS"z$PK_=ѱv"}q6NqXs/ 1h"wK_|JU+18ica8VO?6?c۹8k{?/b޳i9fcunc_5Ȗk֕sLL&y.I=l!KB-+&`fa}\>̩etׇC_/E 1%:T{9;p؞W) 5NK Ik2؉d#(iwhNK֛@=as0"K3{jM<\mN}NZU•S!bGEه֝+cHge9&I9:~%AKqU >xƤ^.#|8Y8dx$sA7G9#p(9RW5]Ƙ,~.r5<42Z/2~8~y8OוX;\?kHP=o̩m"c@zEd)&̫(l>0dm?.YOIMB󼜏vx5<Z45T-'/K;dOنtw}QqVGmNh Y`?%HA ?|~;)K0?͕{g$k<$`{Y04?aK540)?-bv q8svɔ/_]~+>) zKYpeQޏcvG~S0wK&ޠj?{Y)ڎrޑgOda+wx֑]G6̕4ΥCH0 #/#Y͚4ES y:v^lI\8W?۬*5L06? sy2$ D/-Er, <[@܋j%{:盬?FK5TK2(niD{Kabim}[7[=>-sz9S_}*db тave: kAAyA JxfHuo_<8Bu:"3T4RT׺DFg8 vY%aJJ}Za;aQ?7cfZ;BCвt0RBP0.gct0W=+S/(Hch[(H&x M 3:[=h 8Y48UGt%.ʼ)!ԕtd~ZE2yߧ#4=L,{Vdc$堿̂n+Y/yy>89s͜gd92?dͱYPXR|{L&:o@!Pd_MIXj,8A>gsbޒo<swlkksr=#MOg$>Mg J:O4|_Gbu"BަCrDGfkٞV0g(Cp=sќEn 걳wuwٵkŷcq*ЩQv0[OdԻhf[1*3Wl=r U'>=(SHD\$H$(Dj~Y"77ߛM7v0Zðf3E[sG6aJ~vFq&|Cj(4M-Iڐ*/2: 58ٱPz{ϟ`tstg<>CJN),b\eN -d J,j ,<jCdZm,;XKYFRj7s,QNv ƨG/|C_[SkunLd8ea!ฐV^@(0Fby9$cؐgf/Sq]d0e&dpc<ç>le֓wv*YeOڏѯ7Z eܘԿb )x:l򜚇(galm(cld/6BC8eIEOT2E3*Pcjead !WAt!#oNt6P*26lOJ51Ν5/4v; i;g:ˉ`9jz}wK-WC4=-BSb]Kp:8`oԁ|o74 I9N?LR߿롬{zTK_DYLSsqصGm\ ̶laYZSr3Mf^_FR s"]| 0&D*翍Wƻ^eR һY~£3hVKX]FK jDLpxE]u*d{_@[IjC戶ق܏eBrL/I6&li*'~o3oNPLVǷDG_9`zOM; !l6EH ۊS:Mi@ղlpS>Qr%8AojF3 zH=njyM;1BCu#N aeu6^3L%_A @s2d"pQȔʋȄɧ9L2 Q4P/:ˠp+|dTop~kf;j ΂=6jZ0Ygn xMu?3V-^,fo.¦ٯ3Iӝ [X&HhH`uj/;u&,RTkabX1Y$36KWd JwkH7t4%M}\HWɾcbM]yn.%OsDm]7dbzJZ(^D\KVL+єQ hw I)q {nY}{x~'5·W}RFq/a􆿛mIqˇȁJϽw#"7e4~>ƚ{8z2ߗ_QbE8sEmi/$ @+~jNu˄=@,@aP ou̧:6O>%mg9| 1Ζ ,7̰RSP$]ILZ>*ugh}j~+DIKވ@rCeUs߉zNt 9/Ow| įL LZڱw)j cN]ְEg[X޾TDc3Im94(GIW9ĮNy&JDp*䴅}6Q4YjO brA(Rk⧨h]&mbl,xї(@4&R^րgkezp80KG5L˰ǜMS A@2 cn֩jDnc0DP1TbU(hY;S{l=dH皮04&DX_dg?q.FdL&B"ձEW\LDm|~ߝmϽ51>Yړh\FHɋ$,^]F}C~{+ 3ۀЀxw5NU ^Viy$2eߐS4¤AI]\J&,(g ڌpiչ#sh8pp;,.X4A6a͋19*tqݿ  x]vڷy%K] 6M;ش~8=LfX~X̍k?-TQo%썱yRyBӦu )̃Uy w?҉)=}Nuѱ$xTw}6%;~'*e?=u}ο3ҝ"~6Q0STwΚ]}zh55C6Wg[Z.c*Od|=%ƂLrٶ7TIO7022iM;TRL72AJ>F35%J8:U? -$^&[BӐelEi}V q?#B<{r=Q!  SdU:@%fDc-9~f/ kre0L"1/ cR2.Π&MsaS˷O4229w'C2{gBm6 @dԶKp'(sCε2E{I8lcVYza$㹆 㬏?a${hN[{^@Q&Ǘ̖恁 hJdP"gXH-+iH~.9WfD3Z4OJc˧ukLv0-%[:`2\\YkHJ^z)ǰm9#wX&O{^!v >BK5z[@+rUjILx(WZC|6 AMHe`?#TZO۬' P~_gDL{oe-ʙ~hRv4LtvKofhIpP&>?f2:lϢ_f}3,U, vL E$ _ƶL]XZ$ ،,ywfvgdtlSb~~oQ7ON}O@u @J;9RY L"lr0iO SY{l%ͻg":~PGQmJwO~ (tC\D"slZ\WƜd$a&qYLGL?u. :i*r"SmԂ< MaO'Y?p3*KVh@:LiڮX/F R c.뢄/7'7}!+,W4x)9)+-G|9osL>jk&BzRs=}H} ÈՊyfݬm/ofKVc3r?޵!jFBͰ]Ŧ; V:*1 ErNx|-\暐.X^l5wZCL-S~}~#]=6,lYm_|%3R#b98_X#Zkm' :SO,w>ξϴo{~YGဋ7 Y&6TT\g O}ݸ:tѦ-Q&Cnzo95ksLd4P,B*yi9/֭Lg%2=#tE1,35Nj&yC(jOUn5?y~ʿfEmsp"KS:+rz'pL/U2/edyV{ɸ $a,2-skͿ_E RL]oxY5CS:k&俾k;@ڎ)5A|5ı^j}n8 V4c4Ȝ2޼OgA7lF[S_LRϼ{0;>KBǖk4#_Ȗ}yf-r$IMdr*LM>ژx2ægP$ "o!k{2JjVt*ZAͼZ|=dV)sUp^c_[T:_@f?eac\|$~HMwvV:gCBMZMRŸmGGAy:xg>X->,(RC@%Xhrɬ> a4Bk*ѦZ>’50)L hZ}Мጭ?,ө󀣫 0|LJ|{ʙ3M̜8PX$ P+flqqⶽ󂜶@ĺPFjDwr9gdٕa۵LДNݺMy{٭1$G\[&ezkŶ8_ ~F\J߭" |\M{H~: I\|_s<֐Hgy 8V6}NHu&GA|?ɶ'[ 0]G#w,QfwnD̀/Jo>`txk+){7O?~XM,ڼf"Qf0z'L&XӦ!C%0 A "'$t7Xӈ#&M|g|;R yڷftT~?T=3)033mgmZ"]l+u4J~(2M̕w-r|,?%BmފyA7(Hv8&2>_0 }|=w=jMh RPۍ7ZZ-` 76@M9̇z"xZrVpOI)aoS:p% -?D|u*XLma`=Ԥ9G$aidy GfVRv`:>ۼ9NHg\I"`]LZہaw5])2meuDGsmW)]kt|LvU~8eHO`YQ$J :$]}/]44t|$w =rN5FUfycJfҝLG.y`SE2j 6Їɦ kH!7אyEy;ZȲՒIӬ*1 DjG{3 '2*+:yWerVkϾ*^zsh(_8pvo{&?Sj ]x{a߸:Gͱ\|vO_?<`ҔٽlYg6n7ۚn>j־YYp$_=p_MN1[2 U4a2IM8zuYĩ\&: =K-? ƲNj#'HFy8Ah>I>eܸtf<ywrq*qd2{*-'ϠV"W2E*jHnΞ`8=PAx ~48_7A!70עsg~S=;k5E Z`N?ݽ Hg2Ew1n% ?s>k]¼gv@V@T/Eݕoj2-R!˘u̘u${1%uK&%yf+zORKJd&1RsJWH*K vC4޴KUeU־ލn4 $DZ4)L_`^ y1gHHF(Y-4bFݵY2sfEfEdf5;+##>˥ 8[.Nm-$+iBƏo46  ~`hH߭r9 h^ZI"ͷ 2&0i?umF]Q^" B=D=ͽLpox>|Ac5ؒєg1FJj zDXr OƪwZhfYtǮX>L.=uȡ?k}.2&ˡU$|hTKǕBꆴ<ӄu߬;20z#/_%i0C3OX7b%n 7CpݫZ`1x|kLBo ̱4"ar@g'j[}ڐD3E  6%GLcϴ>es<L. N_ ,艣z+Zl4'^@A;V>t, V0uZT7qbc%7B 5 WɂVf5YӲ0N{=7eP,l"Tbro_M߂O~еmvПD,O`;pFCP#4) F!ӦV#jP̜i,6a#LJ%i+HoPFÊWM6n0q#VodɇT>72q҄`<5^cLR}Kv5"UP9nHpa-?KHꔉjPV7Vt~iDHPF$ ) hТpiefM!^A%NG`N[QB Q!p}]_5[pa>EBm?bƎ4/!G秚 n#c;Lж7ljcte6Z>ӿ1rnϹɟto>^w.0g~; e~U"~iDk(5cB#I[>L_Qb^V4 B;Fbjs/ꁋ/z9ʂ3֎o!l2!D!iBZG'؆AhK"4'-)=er˦C:ZuU IDATG~Uf+BƁppJHfCL/xaz^º2$!^0=$p,jCQsZǦG?>`lu8F#0 D X]W~_Ӧk/CnSׯ:t+Ltװ@w:67'* cL΋CG)VQw )dizM $ҭ?`AQN &yږ2&_3[j-j(aBS5*6@wheO}@h.J0c0O"!%u1JMc R:H׿Aڟ>\GWaS{{CSfL ӾM]Ѻtk*MWqN˟8^huRs%ipB=ԉoO6ys\k~fp& bmxX˻3 8,iH|L. {m5;}EZ%Kh  aʲ4h^r.RtgJ !Mmءv xᴪ~Ȳ3UPmRѥyJk%0-f)˹"EDVxľ #!2"QiaM+gpG5 AE]OaV> o4)rAoʄIJwlcVfca1? Ӷ*1_>ߐit#q}W%c?! պhߘ S!7Ւܜm"-`A@4Q~g`K[+VC9wܳ9S`lws1eƃV/v>To[0wy^W/W QmE#?.$hP4@ʈT=F1FZiHŨɕ ‚ ?Tý /;UoYuDj y+ TI~ia#uf^|\NnHLEp#m%w/ ˕|:9(fD;=koƴVN^BibE<< AWd4vI{ф|z%+ȷ%K7]3S$ !*E̱y̯%<=lxY"YdbR~ |\҈H[NDZ mIUYI˓8КgUR^i>B8~B.jl crÞnN;_/i9ݰi-wݪ̞FW]eϕj|F+Z-)@ݢ,huV#]82㴎9 68#l !}?p'_b=Y ["'@_XYF8>F*=Y]q}\|,hP=bN(X40896 M9P|Vo1%pӊ;#B~8).*KxK{4h5Z)E34<}3!=nh⻬_lQǑ}@&SI3&MZ (n'~$ZU☬%Q>ihܸ10[&Tx3#כT׊!<-о,C4T#m>a9UQgM2U/ { کn|<ۗG\>xp0fҧ!0`7S-{Z@X>7%Xo^h.^*}LB)S̥x9F,1ӯn0J?w}-~L vi<>dO6?6oƊacc?~y'ܱҊR84)֑* >$QZoSX=z;9̯SV&qjF0 DwS7eFEݽQƄnw D'ےِq󵬽RC:.Μw@۽d) Z;ҌlbͰ̶ڝy]VT C{/E^hF%WJؔ1Oi^cwƁ7ˎVi}~1A<߀/r)$0k+؍fxmjѪ+yWu;6]@N. hFYւᛵB,F0$}6s}h0o Vm<(KԆxӧߝjHVW`>YaSmeV TQhvJr׆}q>hn*XJ0w%=!bbRgFh !v?$s'!_Y}C9iF !,*J&]W-mT(ܑDԕYK< ~i{LH`iT|.E Kht)hBnz*B!򹷸(k984c~}UQ4䵹ݫ\KS5MwJ%h^r(lwpX IKI>\<C_Mұ%V;t u`֩^̰)H,&O&(@0/XҨ}b%jLisG#%viĞq3KXY7^2{z+k~Wj?7q-_GWܻ*9'4q%jOH;L ј/^=D1}/H8';] ;r9هdS++ IYy 6liNV$IxehwiͭiNo$ۍJalZӆL6h^2TbM;;+C=rwoF 4Ix5Q[fs͝=0K@XVN ^bM*=ڊmB8cTDWՌȊb,%.yV/ɮ@(8 A[6V0LdG|5أj{PҷT?@S:!ҿ/}I:ա\ +j v͡ԃ /%\ ?H耹,iRq^%0-]1@oI7r其VH3q>Y+fKWk=/OuZoEWl~GԨK0]yכ~ mJY&$1 7fk"Z5]WM5?#}Q!pG/i kOXhµa ۠Ǘh4 zؤiba4 Sc҂$b!?owƁ5!B0^z~EB u v\(hOE=*@yQM;;VnLoLeK\4[ЁFW"p1!n؆jۀKF  U{r-?a04^# l6 3' Rڪ F)?e` H=ge (+A,ڨa\9YOJwl[ao󌞓~!hBx弴 K xJoR'"x)We M@T* 6f,b|s-մ-Ov&V;ZCyIk { !G/{wLN9bE݇x}e S%UygZz`C۴> ,hyh<<1s߫~Z/!T0xs5eP؀#iYt{sACZ@3 NfZi9^~]U LS{ݼ4I`?.՝+*2~5|y8T]Lpn@Ԟ#@hԻNMI7RZ_0Cjk` xl@|Q2a[/WkIrrNm4¤kY&iγ8vg[SfsJ9JE#@ΝwXMɇhAo*LHND"PЅ|I"Z2/  ?n\aaуgHٖogEaL(<쪸\r[N拡N@fYώB:h=cs<`Ǧ;VY=XcKahٹ/̇rfASԇ'VvA14j$eh@Ss#x!I>Fx,_sWpl[es8t@nem\|U*zn.KI#X ۍLn*~q440A a6ދҐX1i(7-̥Weá$ў8Pv$𘺘FZͳXP|!+Ԅo5JvX(M~}{@y'MWA2? ōHKLP?^N/bx΂=L$0i5ߙ v^sME8@K߮V ˼fBa|Ӧa&+T7TS8/m9i#FsNY+X [͊?+ukIf%taT7+a_ U½Jxܠmܫ:񇦇ߒU+.3!@Cӊ611B BbBvKGH)*(k%\P*gEUJ; *&ahD QN0ჰ5G?.+UZK ``0q7$xPk|0ߧ(]~UsO:^\=$0=Tӌ\}I.5t$$zX3O?!-) LT;vv/m+=M B}$'~,ȑ0g{2VxJ=`C&?(?s3{SNQwH?ٿe2VQ$4B변Wt[Vfv>/  i44Gl!6@, h8W W`8h'F<ʪL}:)CY 4%nˁ3pه $vx1> |04 uY{KWq>dL˼ W01C@T9 ^II *Άv'}@F%~7y_teM@Hơ(ӮЬPiEwگ QY|H5eo0/N،U|k5aI6|{΂׭_y`+ S=cϞBFj}G0f/rbЊIj _SvX#rk@X-| 7.4T4w{?m1چ[Cf&/ZQמЪ[~ ceJ$PcݧN`?v)O<,ʓ=Tbѱ΢\7A |,߭ ~sӬ[YuwgB{0B~n 5Seqkk.6һMvXOYhݪ˚Q3ZDC``|+4j-\,C's 3.̟c̽ƦٽJ; %0(C*ʲ<ʒTjwz08.Fj~z8 /*,A!c@& 93@AZluѮL$ .2b? L :Fn;':rf:JZeeejfT x"Z&H @Q:hP=W<ۥkҰ ݡ5WQD'.l*M5v,K+,9~,K dZTi0aMiٛ|QrNєtGQDm5sha ~v'o#-Ur>ilyhc %` IDAT|Ɩe^iG)?t) |T*BBsIƦfngG()z.~57,b>o]q^i>n6$(MˌFPhzgc`jjmuӣ픳2q4%ujTm;;?b׎=3cgDB q#Si^it]?R[:mOi7ۼ*_I/|Ɓ@x/`j$:*v*G!dCZ΂<#nDS"Aa+g̞#0$ cLÊjuk*|H߼0K +^\ y˙Q}T|M+Ȕۓ{XR΍HAA0Dn)\nǮoU?8KmĊ.߸MO7W?T~+YUiB))GXMr@*ooK {`~4@BT0T҂Ks{f?ª9eR'J|nYnnE9 ع+p‰{x|ŗaSQp?dA~W-4{?-#6@xDMx4׫~v#&pXXkUՃ/ ]!93/%55z@'LX6 [_넠voK7ҽ}ksYq^gQ6l‡vW>u<H#x2j7@#sK2I~\҅s=bӧgZH-.5Ei?w k0qpWwͧ~-H֌Y9?K֩UHӠJ@X#f)&{e3BF ޷>N>&{}_q&.-$qƁ)>\W_ՕfAp߭= nq|:G)=7:g/` 0 Ha%wʨ(ɮ]ȥgsFi27HaH'> N˹LWVQ @UlXqetGNNȿEiGEt-/ 9UyERě D/f:<$A[97":*'̯͊j 0#Kzb d Ԏ49IҾaI' ?giʷ<<҂`qV;|N< JB7FEfuV1(CK%y3{8@;q"RiZIЦ: AAl>kh''.Е(JU*岠23{ؼhI]Bۘ?qXGH{51&hсhE{_Ѯԭr͞Px~tݑ}7 ƞٵdc״3/VikRy߬Ցv0sHC<=*cOZ[; MעQ<·2Byʢm8IDt|m3l>ZWp?D ڽsgƁ-8ЕW0 𑀼f@x\+vل슁 "s}c YtW(SݺpI G+a^>Sۯ)ޔi VSQ\H\ @k@sS[E gYZЇ`>%Zk[ ϊrIg\5*#Byo$ @6HI0=Ru,t}' {eb߄M*#&xS@، lȇv(ۥm8Dlh$=eU99?kzO4Ym Xs?N &g 3E"g,zt@hD#qVsZ|lgnZLd7W"4GNM7y}ճ}|;[ 4,i94l͆fmwYfBoBkmTҾ1}k{JCS} qh%T<䟘EE#;*mI3)ҍ̞qs')Dz|]K~JxُVUY9\MN Ȋvfh-!5lveJ€4 C>vBϸ=c`|KvY㾟JjfWн>Tp n~!M }G`%^ͪ>N|lKU;*^Yry>7[64{Ϲ[县\x}5qj5?[C2|B`j9f_ shsvBqөq?GTϬV6YЪ.r {#̾` 1#:GS%M<f;+LDcD]&0(Ǡ<[QsBf)$iZصY-֨Z,ž=\t[2S3SriS؛S2a@c ^EU^ڇpwLU0u%Ѿ*V USTc0p%vhkٔXfcDf^gu_h5p;&clݘ'8h+9/hʚ_ewhl>1|~N#J1-ZT@Ci*B˥47'=su ֠P(Sc0t Z,W,!=Y )I0d9eNyMx~UZWUY 4tN`p}KDɏpF\snL&8IG>KÜ/Ciu;뎾"j7哂v9;)fǖBFZv-sNJܪ=!OqPț;kɯLȾEI盍 Oæ%Egn *].}(wm,K:xnwN97̫68q9bq=;onϝ<6~eR>۠cұy֐-nZ7\+TRp[{!Y 46FlBY>WTUe 1UG@Ptgq̖ՠ6Ag9\D+|$Z-a*Cy}3-QZ!-#.c3Ld|`3ʰb5ߒ\Ϙq oj AUmAjGK ~=IpFߩ$)W:$q(ߠ+]'|A`4UcvIm`.Fdq؄҂xO?$;u/|jF(/Y/n"9@9a܋M^ ²ыrݲ@ 7iSo*Q0h""!m"Z )*騇gj>\]mB B)x  imTeF ʻӣ@!,͞xnstcox/f{`UO=y/JiF.<,[E7riD`v"m+By-Oר=SjWSD@K;V,ۆ26fiWW 4?n}aƁZٕ|$Xe&(VISc&M$ ֡hSD^ nzKR]j%Lao3b%z a)@*>%i%@R]2U¢U:'0$įڔ&7#qDTT(P:Ҥtn=Um(v虪t܎1cVFpjq'Vr/"PAd7rQTdLHi+ݴz~Oб\_hXgUZ^"GdӌzK֫llWB' <fd 䍒x)Fb dDj2s<~:4Ԧb`Nk^P~: F,)1myeQًiILmU>$(6"Rq☧{tj(me1,Xl+ʆ$rO0nċa1c faF&XcQ?wv4^~7̥݃w[d;xEs`tW:|n9qHA[nynPG?mY{ZK#oKPU;"j[?QTTfa> =Y|f!ZsĵSȘW YVK}8@0مo,>{_ $sfb#p6؄f"<λm_ƀt,CY6ܜa(aAd?a`BKim;@ʦvYvՋGQ%8/ "`z*ZDJO+lԫUM̭J@]Kcm;ޣM 3ҖskXxg鬺#-7v-JKbݤ&t𺄝V ` !֌&" `̅S0Cq-K:V&hdּx&ABp6[j|׹NEF ,R,E*U@7c01Y,(6h6{btVŗ; f!F 9 d9fUL(]IIK! c*/0o@#LLS_hx垡JeI)43z'r,}߸^VԵ6+ͨ4fk;/=[.nNi>'gV#)MYGAï&Z$³yQVQwKKBYGgՖsy ՌZs@^/ܛL= ,/s,T>khU^b[vDN.i-u^{6,*r ;a@? *o)y5"gs_cвLږSV ^PԨ JZ-`ij+ "_I@*[ k0*hGS`J~+Y#@4C*B 'F$[?VD))wQ`JI2Zlׄ #MiժM-!H) 2*>`ݤ>aT;9뤝oR4j_`(c̫B0i9 sq& r̂#.<.a[+&0HpI?GsZ2>x!*N!ْIm,h4⼢ F$3CkJUG2'tJ%˧F?XEϛMH =#w+ טxnuMJpVڔF˵EY~iiQq@6jVNVݻV]Q8fDۦ0=xCMCF?Χ{iE^/?&Ķ7Jt?֜8q zFωˮre\hÆ4!9WR!$gb@⊹ @L_zx $7Srvez,Q 6eU@Ey@:r]rת9MZeD4"c[m<*!}<̲:sqGg# Tqzʴ[*Be"tVnIBO2%Xkm$?N#Kj@@寿R-;zG4! p@z c$)NApۿ$#@h5O;lus,>Apե9 o]@=(&iHcĖVd Q.kDdFy0CЁ]R;AMz;Bg=]eG?wp/?/{Ƚvg*ASpw>nL^iw5yT?jHWVe iȑ}/;gvgTR!sIey;1ɪƁ(PSjLg3dY8 LDאL.Jlx#ewm|[;MO7'| "0c%^e e8тr|ܵn (krTI$ <~UJ?BUGQBBߘP$@ XH+PE}n^0bEx@ xw1,(ւ24AK3p@Nh4 6CA:eV֒|8#~!ǷʄpN:o]1*ݬE`$BU+)VeUX}I)ÿxC과E4>!Icܺ"'Ȁ|h#D'koƚw/<@Yhpus~NfFce¨.iXT MѶ4D?T4Ey8sAڄ%s":]ecimLh.Iѷ rz큨c;OOtzU.L/ȵ, x/h^[$sXH]/hG YhFkOԖ)[MZ,J?i8<wQV9CV@80p"AYAw4G1,i̬R&H?v` ر.@,8dK0m/M0ez`XUȕIy_ׄT"'~QhC }a2 Q2xm L{z_Ha蠻pCnn&o\N'%xP~+Ͻ+ƪ;šWavilIZ/+G" Vb?5m_"c1c&>ۖ;@Ɓ$0&רyFH%tVL= Ƨn|d^T K IDAT " .t!l\Jz>#ti5*!&RZ5,2HgQ/愯2 Њg*(Zv{G2A'ʣZ$UEzjE[0 /+i-`nb67v!$Hf>Vs7Bk9$РI$X8W>j&UB8(nU@{VVL G)m…U#)J7o2=q$egs浙vm|Y냟ޚB$3SߎD, gq)J}#B̈́ɴhc!x/rօp}#Zc[} М#m74Хg]^SVmYxi}X+ce섻|=n])?^|ЃRa+bOÔnV`jyNF{$!Jp Q:g(-u;HGٍ|M [y9 P P[Yg?. XeoaWPW\Gȯtۥ!w4PYNMoF$^ipdB{Ѹ`5>p6j:˓J/3\ud.fh/1G#ыnQ>Ձs9>W$xg}Oidni%6c#I|D>!3[ۖxmٺ-{cȝٛ5g}TxKibcO|-c`ѠH|R~$6eB؂ a+QmX#mG%dC& sf$4]{LmK&/AfV- &j[c "{|2eE 0?S Hq$-#5,l4!65̈́J C9aR}|7-a}VU\&dQܤehd1gVnL/} GП@ 8M@;q \n}/5]ӪN_~ӔGw6B!9>6]wi]t\UyQn&6嵕 e=dG5Ϙg8Kx=# u]VyW2*!+r@繎XS2 ('g%7% 94`iVY @ó*QHa:ԉta7ҷ,6쫫WИ(S,*\4Ϝq.n{]!.HIBuA84uuIY؛QioRB K@>X雎'E:aWquL zXVJ޽>s-ۊ9kCi>?듄,K*iu$`^tCG(7$4$D)rx0^&TaUD?WW {y SL91o/(OڨBfJU`_<1ͅ #D(4h'B|v͊C8!aoI}2b\6̼JyULϡ-UbB90#m~zex8H'79MH sg>FZ6{32\A/N+-B,ryٛ~E69 Sss"G<8SVl 4{݈:22di9{fAiX5gJf4"u$#"p};xTNJc:ݮ -`UAUntP}srt þ<=Z5`SE`juv{&h\ ǝv:uhjVU\:UW~{4>kSjc6`Rw]WVF"~n4 mC~U@zf7kt@Z}J=V%Q(B  @0>&6Nf3Vz/#ycſfchרKZO|Ax0WB:*6xO[;~(HƴhʧKfv3E@sh=B(sX yϱ6Ȥ : !*GsIoԙQƁhk(Q&θ܈vmϗVdG4s2G I3_2+KIy_©']J=w?46?q6)HO 7EFf86r F| @Cw&5- 84$"5p=$h] R8x 5E 0'0ebQZBp&{*nXw!!\wmlK]49#pܡqC;[mV;ih i /~!NZ+VU<]WC65|4&NJm , p&' x[YD ޔsB@#RJI)iڡ&77@a2}yII)h*`n9v"/Zڃp0EA!m|^[54%\h1|̪sVERf;=ć͸YwUե|t.{/b|{X0F2?v$h~>: ўi([Vr=nнU7|3y,D~FC_k*|(?Kf_v *5#mϲ6U1IC==@a2d88  ğC#Gy񤌯dٶM +re;f>Xhp}8-Kr֎;2i@Ĵ$–G!A[/[6NW"5#xVM`AǛFF]vB4ʅlIUW UEǀ~Lr]y 6ӨuOޚ MƁzm\QQLhLP;N9Ƀ | jQٛeԩlw* jRhZkE^ppǢ @3K¼rKk$9:J"Km!rC6^|ժ-]ʕ>6AUe! O{E+ cVE+]v(iv2#=-+H#߷PCB'G미E_ S\$ܿa]skQƁw@cfwMd-oveoaC7| P|~^BPh~ȯ x8("h:[R h(!ߌQ{<3P!9"` 39H@Y M]9@ JtnӍ4&lUj;d`7¬nJ}P6y\fN{ -*#SxZMmh$fJX[tF` R{V|$( [0?Щ:8Bj04Y}߼A|몤}EӦp427mUq*9 WOe9,fyQUؒ12D9IDE㝀cڕ6 h:LHRpc *xgPim#0})eR6;Ȝ@xc2E`<ہЪ;gp)"b }[W>$>4Icإ梆BBCO9&TFL{ޢZ)]QV,G{G&S$(@ƁozNu4_%Y{ L(6ۗeR~)@~|E5k< /ەvd: o/l6[qUm%$6,A1WT.ecHTi*C޼<:0!Oϸ1> H;c{ߊ](C}~5*_ {"IPў{1kY Xْsbi ~; LpIQ_rzB]e~^5rF3"ȇQkJ· Л .~A͖Jeb2F!5!MEV R@ G+˜ fXhqj Y6q>:`\1ND1ٻS⟁ l ?V"*{ٛ0ll+m g3+ HHC(;aCS5&lyZY[p?.=;>ˏ ]?m:2d1Э7^~5ՄLRc/́X'=OO+f \o9+@# ɉze"ltʻJt!e[u  8>_U]G68;U67sGF UDOyF@(cn./+|26Qi1 e؊4|-4jYi"s!!Ku1Ը}w^Imf pҙ.YϽnk|%! D7Ə?U<.ڲ/ ՠGzT 5wgܹ-/iA٭@p.8qƏte7{˛րնڣ'{[w%v?(Lh+Z-DϪę`j'P դNU 0N1 YgbYL[wr!^YIdtjKY` zmLh=wFP4LlфlYxV:s̮MhM9*Ο1C{& ~*yCfxA31R#Tư_Vehh !1cCa!JnYfk  {tcNj &Z\G0hj!㏾S&!TUPI99bhGѤ1)fN5C8TWERg IDATHy"3ܒ];NjI=z|7 L[f_=+>=heˎ3S9C]K/0SS;咡n9IƐ0phf?ȄZ0^WR~mDRv&Ƞ]+mW]XC_IH{[?p/>Y:&h`ezrWcv-ksԋOŵֿp{OB@C[{Mg?Nk84ׄ'俪k{?5SCS_Y@IK=_Mexs]5Bù~983?G)׭fU;{RGLxOiw߯ ){tʚW}wrr&$NHnBo1LP@ѯS[V[/+S} ]xk[!{db'H %0#@";7{Ve:-c5Y `6XB<J72١h h$`AMLB\DwJrUih7 Ai|e'}j ڌ&ڦp#F{2_: I9ׄ0v8b>nt[(qj5+(XZ}:B]}xnru9alNXgB1j$!iC,pAӈ'1h?X\u};4ZBrٗ3/@]; erL[y?{ξu|VwBIh(45=.@ I-doc̪@yeޜGՙYheE 3͌*ih &]`a@'̢t+6ffGbʤmJ7]D u}+Ϛ@³_-?ft& &Q˄R~ ʅOGU/:dQnʩӞWmmlC!q{d^;7:%2DB 6t~ rُ/@T' [ r>/܂L^PW}\ڀ>]Z~wGB!ģR_43O P+6Rn,QD/g>1{ m9ފ[^r?=_s%yƆơo=*Hiw幗iE߂ v< zҶ~Oym\$O =gu`OOuL@V7dJ&(E-ԴC雅 Lp*O\VbޗuUgڻnuK}XE`Hfe /$ e2!b2 ̘m Xo^յWuuTnK{u瞍ƂPlFdwʩ!Ub$5V x,l1 Y?ʸB2^ քw{w9yb4,Wao!~*բ,Nx#w0֊~Tt w6\'$#jl®*r-YĂDCnz{I}_դV?r;vemF& ̥h!jBkwc/mT;vTyK3f8f#'Uqc4C\䎛,,8;;~I1֍ "vݵ<Ҿm9qݙeOV$oGc"a)+kyRyn,+ms|~`Ta Su V 2+T)1کdMUYRx6ogt[ӈUςdD2H(A KewXo$0@#mo.ٷ(DU:Q@ fϳ^!<`!+S}ggb&>KՇ߼j\z<*!biimJR  oOh9~Zј{Bݣaa%:t{w|GrۯcW~/8ý}Н BѰFywmz{5]^GbB_6"w.vؿeO]12f 19]<_R[hf!Pd㗾)#Ft9؅ B%c=6G UE`dXNR n=pDZ11R oϝYry̺< +]61x!$K)q$#6(}J W]\TzzSB!,'3$2z\"Gy.j}k͉A2*j6i?A6 ˑ*&XmGsd6paB:O"~j4AduJ"#ЦP^f8T`vA:~+dݿzPrAbQDs_^3 _sj7nyvB,RIj E&ӈz)C`H36;o^?{_7ե,&=P5@miPMyDA t3 񼴵};yB}JX7b] mM׍&>ټZޒ[w/r{@s(W ȩ1\T!B/] M"5aEA`uܐ:SFƵ=7w c;޷⾹\x27\<~Q2Q.;ք|ĩ]I4nݏܳkb&\.or`XgRK ұͯߥ:kFxol@U5BhJoƤ.{%7 >=_ [8}?.0:L߳߄aquc{N7&91Nx $5{,ȕ/>7-^ KHbL5-YPh/U'慫~9WGGFLqUqPb5Ó6 uIqpWSՊy|~g`:3q&mziN`(aC>zU}+o;YNNCnX)?.IkҸ*'LU^TKLpmJ ;څ~rS2Bgq_V=r`?.od绿+~}@(>8!7i\״4Q&tdLnxSߕ;C+.ᒷ׼!뜠yB%.&V~*Ev4T7ӕ`"0_y^9m&p7Ŏ˗n'C`!}'~D*DﹺA7`("3|,vάrX.FqΚrtvm *Yy׬ Dȏ܍W8}Cނ38gDl?Qa ndiC5E iA iEЅ$2%z3+G,)^oT#Cxݕ | ۊZwo™gpLP+ B %-rpwJCXTAB&;KbQflN SAp,"7f*n? 1#uqbd^~^?cݯ:no@#jߨDalODR F`K]7ug32f:tH`RL^h?Ӂ{=PWK|cf18f&Q㋩1d>?ӡI5-*6/8\H1鄿yW[ &3NP]Α.oBU^*}'COf ![SOach.81*,]| ~2# cqw>`>ojLM%4B>.>ڤ*9D]GOQG@b~UiEuc!aX}$̾$QO棾!ԳBX8SAwLdB0D22f2lh`՝?;ft!c=$\խ-R;ߋ4q%՟1vy9tG#d|Syʛl^}% oƀzIBTGT;W҉J۹9vRCIzEi" ` z ,AnFH@@:.0uV:*hӗQZUm,0rn!t((n^LSD>$4x&+1%hvdh#K3#C`i)8uDt?m&CrU>;cADuVGjx:q_Qc,\=L"޸Md q>ۼފ/SaIWe 0vxʐ5MhI)U᤯8L&"ٰ?)Au#.x"p* crXPjRi0!A0 dfc.t9͹Z.9v*RuҲr̅~2U(acm%[]<Ͼg PQB l$٥!p#&tKH_u?L|4JI1:BxT%="o4!fϟmzʝ3 "S+^Z#F+kJ V_{9kѦK(eByԫjHɷRtY#(YI,7oZMC")xGA:?ӅvU]-ELW5>kiLBu#D}Y=/*,qvl^(%!C'}. BP7t٩TI 8@oLHaNCmoG?[ L|kRI:.JAr>{ "C[|{]+\4Oɾ~HRF4x@P?]3ߴ(bU7eC]+cݼſSCFU[np*K#-YOS}f6/8l3 0 ?.`K#.XI d:H0"4'2WU➺S8djN)^Odx2Q# AL (,Q;Rʷ? 0P, )dU1+C3ۼp5Y C*Vb媒5=NQ*U za ~ `:?41̡<#k}fSj+32zp9Tq[qЭzgvi (N'-gT [#+<0 eyH"!Ѻj"|y6f.0#q ruxA2w9 ݸXJC>*X78`slRlV'4C3/w~6/7agCiLQBI8:~`Н"&I 1X>(0o8x/Fc.zby20!PpWF/fezk}{# @C"|H6">R O ֥ ;@y|Ȋ Z+ l/RCXJU46V2ƺyHX8GqaLwPKAE8\ #Wz>ۼCvm3 ЊVܭ.w$i\A;?uQ4D璁oȠ؝~gPBGST7e$IFjMtǫcъ`JK^vZ9뮤,U࢑)m|G@60_nYk& *g532 J09H%h]Iy)5&@^8 k%c,d9/(0_1Fk*)$e-w~6/8tl3 )$5TpoP: n8'bvoyD :[ IDATG O1;^ԜP] T)pw7܎EխY Jo<,I&s2ghߟ"e}D0n٥!`Wܤ13Dr7V=mc,ʹy6 lȹ0-q-e!HB( !Fz KOOe慢m_ C` 0%zd@(,wU|(a(eF L ޣ$" 18V^_ yCv#T2〤!I*mL>!h琨i\BK&E r0&qPěTB}|l0 hE>*c6210stqUc0P ŸS{@O+l^(f!`L@`J6 ErdBcZT:x++OqP=)cTXW%q0Vh&W6"fpvB\^^W~Jqĺ/TRʣyW0i~׀ C 8I q;{r 'J!ѶTjl@}=CLrI+¡>k^dv6 '*%Ʉ|n"嘾c0O n5!`)OPTr9$Ʀŗ0PO{GJ|Yc!p!0^$QQB T wt fR!`ޤl r ( C0|) 9d`B,%S]xQKDn%Z˖\~Z!`ESJ1U &4($!!cBo!wF*:YxJ]/n!`\6 Ƞ! xЩ nv}x:fd!0}LY.YnWt3¨ƀ2 C@Rh]SSJUj~E8W.Ά!`Ӄ$ S%OYA|OV~ˁi%ACeo9:a[/[苅lVi,0 C0 C8 4#%:΄㗑aebf䧵+y{yOdI.ޛEĂ)26T8ŋrt< VSJΊ2We7 C0 CF¹lFo*iKq`uiZz[0^d w>p:o$fRC\- \K% <NY9q;ۄ3Y"#C0 C0 C#E Z!`!`!0'Ω+)aߪڦkzY0$*F͑DI {25"þ d_WHQ0k -DMxzͫ̾!`!`pfSKmUD}KІQKQL(c:C_ǘH\Ur*sac@< -vg{+cU ֓FQxvk< SkWj'C0 C0 C,Jn@@kRBeC=uD k%4p5p;7<Tr#Rݼ@R'HӒe`$$)cO }GJj1+\~Ūہ>&0)u <'L!@Vԓ&U~+E#SG$D]9DzhUB1#gsGwBYv}Rŏ"{ ` zNɚ{4`;@INdhsot%_N!`!`%AmkcKV7Eyk~j[2N>0_VHCC "677gݺuj*q/?yR,sCrȻX&s2x5긼km%rB 2LY᧹^="0O8٩\PU5 JAR҇'-uaidgeh;+[%>G}T v>0EGK wnhysZ1<!A0/Mf0 A݌BF!`!`B$2y\~wItK]k~NVv?-Y%R@_WLF@/|2uT~sUs57*?|Z>_O[5WBU ^t<(?r{x?#c?DʃKGZ%q8_rh/~Q> +n!`!p(`Q<$TmqyoE ]Yٲz^?gkrY9y> ύrwJWW8p@<׷S}^o6s2'1"{ xLѿR/!HW.=}C2Tn0%(EHmmM^P852nd4? hMYg__-Cj}mˆC<&_*g_况77/|a$IY0|ꯞMٽ{:uFjeѢEڏӧ@bҫu87 Y\!`!` +)?+ִ̟7WG|{ o ˇCwg3(3gy'd[-_\mۦ-/moӴ{W#ǎS9"Ur$d9{1yIG&kS{ɦ~Qj޷0`( t┨,wv[6ԧB*宇䁵e-oyks ٸWF։**P\fUI]]2o'NDԓ,SoKh_ޡA9x_1qِDBm@ C0 C0 ˄@A+KqlxiDf[BQ/.(Ւ¥+F n]ϪM6=#,X@+J֭[CnAnvX~*HNbG/nHBٸ󴼰i4iuWVH_% hs]/? )K棧W?vG+]B-ǽotEd'ǯ#yU-I!r"csx79c} ~R!~CFUoG/OWUD&Ҥ_/4TSSLUHxbYzuAݍ$ g«0 C0 C#P`@]LwHCxP% 47>q1=Dusq#q2PoQgx|K$ \q|HӐc! ۉ[׵ɷ}#WTu@#?(Qb,D_Β?Wuʦ䥧>#}+0F!`!`Ն@Aǟ{rl|_Al%rsD oCH+\n߾]v;}FΈqџVlzzz_ziiÇk^vZ^f2ٰuty9ӗ>m!Ak. ={X"8'ܐښp]RDX*WqB݄$+f0;tʙa}]jM'@{d?|QsK#Wl8;w~\gΜ{T[t~h'B 3Lk0 C0 C"Pm7/Ge+e2 gdݺ[MB?}_}?T%j_sbPYuQ5mhMMxש!:x2w\s޽{,zy-ٴ=.a:)`v“K:9,Ț +쓣:%2)i/`s]46Hoah7X:׋U:bndóma iRR6c䯾߅CL>@݊;feͲj?Ғy?.{Py j0{l FD|=)$]|szt|c) 2l##r5qye^uCFl#Omh.ϣ"ׇ`4`o筭A-ꏴL /U 磌qT֖͎ɇ޾Hmr{X~烷g  g?&hO_9,H+Cګ?{T @et+|o|Y}ʕzM;1ej y}Xt01, <ih~zf=OPH5"NjO} ȔM19F|سgcd(p8I+clP";!`!`ƢpDEQHk+˖͓YU];P U1O([U,}C \% w)hTzx m= H:# 腴%Z]臻X8 5Hr@n0U@4fOyB0h' A7&l{zH|BQ#uya®eX2KiDcX41 ~.c:"ѥk\0,a<%5{44c1]rtjXP!,ML ƕs; `p>D3^aTjeЊ;6&A4@B9q8.[<`J%2b;ڸ4TqSOO4OEXe+/I@<y6 C0 C0.W%Zd㦛nRfc횃.yIW(鼦53 bWzs"e!8}+3gNwܩܡC8E=U,k!Kt~hh woܨRJBE9{ 2Xr#oCN]z7>>}eqWu' N9Ӈv0 C0 C0.%孤/e-C0 C0 Cj ZUf͚M?n @H%N-IGd޼y2ɳ8\!; {<$1z}]^OHyTvxϟϩڎxwE0J@6/0ƯE5C*&>7".jqx U娒ZjWCCMIlr`e^D>y꼾aH^?rB[y*ذ8F,rbH-`C0 C0 CMF`Bce.XŦbS СCު\L9sVFŮS0Uio[bt KX;ѱSq':I4aNwN-5#^|GgR2T$ط{$sARF:pAHf<\ B&T잗iQ"/pVj؋lNk}ecF!`!`8_[2]:W<\/ZHw^Ubn`_/IDATH&o>*ay4xbrY+ gUREM8E?>.("’I6(P+zJQHn.n!`!`T@88MKorɁUUZ?IΏ$<\TS]sM E#UE Fd-91Dl^jX¤W] 2QJ5 ݣ^pQ% eR C0 C0 I,/IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/desktop/images/bundle.png0000644000175000017500000000504512346515434023745 0ustar felixfelixPNG  IHDR szzsBIT|d pHYs : :dJtEXtSoftwarewww.inkscape.org<tEXtTitleSystem Applications|{3tEXtAuthorJakub Steiner/"tEXtSourcehttp://jimmac.musichall.cz/iItEXtCopyrightPublic Domain http://creativecommons.org/licenses/publicdomain/YIDATX{pTǿqᄈ]D#<#%tZصP}?}tLGV[Jc;}R@B0<,l$n?7(3{=^"6S. %Ȧ׶47mg/6XKe(z.N^8'@%"$,q8KJ:_i3`eg 026,We\p8C2i/)<\Qn47h98*mYe3q\i@nZJKKJsΩBV 0{洒Wl^Rl20g"P^dq=]b2:$-͍#™P# 78"%J'U&T{uzhӚ{mY\Id&!sB,&=?um?_ uGpS% SO˖H?lB]`llFl0oWv{Ԭs*l4`!apr@4+ģIdR*(% ys@9w|e嫞f=*SJ&j7 fsnh2p8l``yd+ ʊw]nK\n]9gig$d>†yEJ #dX,KjiՏV[o{ykVgZ@X>Hl1m:7^ͺB|.fK^X[ 7p7IS_RG[}c>#u|Lpq5X+T2XHiڹt H4u71udYUx d @@O9y\r3"!Id)6OL2dn_ [ˇ"]aG7̑*BˍiS*J$X,@ +Ȍv ?&_w| HIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/desktop/images/bundle_active.png0000644000175000017500000001746112346515434025305 0ustar felixfelixPNG  IHDR((mhiCCPICC ProfilexՙgTM׮'300 a9g9gAErI% AQQ@D4y@E(A9=(w|Vw߽jWuU_]Ny# 3ʇH @`=ll,ݖ^Tf'0yDyɞQ^!B+<2 l5֔Hi_z=754;8GD!!!z^P 3?FgVx_ pO Dk}*<چ. kXGzƆSBh-1oC#XVF9Z֍Aa uܪk"_eC@Hb`>Wҿsl5WYoXot6=gIfZHk{@Jd5°xu'I587?ZM[(J BiQ(UJM5M-fi 0C>{a0 Ӄ3 S%h_]|AOv_@F- ok2#x_P & x [( 9솟SuH dc(gA5n>9xF8fX  !f B$Bڐd A. b2tjB54MBA@P,B@8 v!}TDQE4""z/E$@#YHi*itE"#|d9ي||EN!0(fJ~bMQ(/T *UB5:QOQcYO4ͅD;~8t:]n@wK #Qb\0lL=3yYbT$V kFcӰEZlv;]xq 8c+.UqqttttttttZЍӭx->/zzzz5z[$B+c dF!. D"QKt%Fs#f3oDFAiIGMG']'=!M1100z0d,ala|ɸ$d”TK!ɩ ={f$ !] EbF dQ.S(,dE',%,YFY"fX_`fca`cd[fdeadgG5QMԷ( [8R.)N g&5!.~ ^Ennp"{S<<<<'yL2jm§W7o_ǿ* *("P/V/*+xRCpVWhPPА0peQgt&OfDkDňb:bbb1Ag%J%O$ʒg$RjRRR/ zұ5c222)2M2ӲByd)˝{#O7OoWPR(Qxx[ms>++u(+(G*)OQ9RjڭVWKT]]Y=ZFF'MQM<ʴFh)y+[QO\/PVoZ_N?RA@A!0ӰψlhTl4b,`g\c=s磯qO~Z~'&u M.Y] v i %v  O P81iYEj1b1cbcKbWe7^">#>}{HOHN;w t`G`bjxIRU2>9(q\or&?lr&!-2eF##G2ee|%£99}ʹ0Bɫ:t|'h)|5i"|}'.pWLW 8 <$C * BD}Gg7$$]>ޒ$"1葜 btkV*;zsԟ\_nsI}O+xOXCFTZ,@D䀴Luª"yz&5C` wnm N]{' qF-&fyŬ¬}ml;*9);pu r#Ni |8|9ECC4 ""m\=cb=b5 Mt)y:e-0gdˌݙY)٧V}rC 'O,//ypz̏s2e^K.4U>8wZƼ򅺮k"Mn4d567͵PZUoJ}NgS;ZǞ{u]]k?}tǬg1g' WZY$Ԡr/"IFPGuL}g+O ;+L]fg %UTg]N!.7 4E!0N]TJLSRW2KI9Vymm}@ETuq>MF-#8F}mD6&zqf Y#ml{u2My<=xB^>|qA!iaUO">Gbb]bfW컵EAL"OJYԬi-=G&2VHG5rsC;zDɁS3 E:% \-}z[sl .vW}&Hך^;RJk7X v6Gd߼v;#mw{N. j<215|ݧxzY/z6$u~;4ѪwG|(g3y?S_;ff2/Zt^Z[Q.k^[]99 @8M9n*:U bqܸHc:sCwnA=!aaSV2 +Ic)yi̊3NmJTUT٨khi*jIkhHHx!ʰHhxdنێ&Plnت K:lst2tpv3d[W<(MCsw <Lny9l#5R:0*NjK<}516xr}JØ4t#ə,YG\cyǫO<>9O)P-t+J.,9=WzVwYVyuyDń TlU_յb7R4moU;Kw:5u~O}`}aw}\O |x*šͯN;8agש͹g+BkŴD0KB1Z^3`CA < s?pGQpy@|XCj!k(~ 6FFףg0&2놽p/ptF׎'_(P'q$‘-c>:Svy'Z#f vI\_IbLT6YGNrmފ&JRk*j jW44OjNԉӍ 077 256ojkQbyi{Ca9;==QƾK{=7=>yyew"“#Ea-bw+`mFC*[Z挈́rsϻBdqATbҺseg**/Sz+I764{fSۮ/tۼ't@_ry1ޟx':Ͱξ/ C9P@#ϐ$vd61FBAW+L.5V#qttntux~7=ދB'<&J,IDR.y&X7dcUf>?)Q,,Xs-m}fsppTsqrN4a@ !/a]PQ^A q}u RZRm2Gdf**(*?WiQ=ᬩ%ͯCE! f M/|1]4GXP,ٶ[i[[ۗ8\suzBqihwG:O9/b6Y!a%"ŢbrE}OpN.)RɇsG3ٳJ*q)ӎeS.]JVo|UbLtMbmrwuv>~ѓܓ[#O7^izO4Y4Ǭ|鷉e?lO[E_X7xuF&7)_d&Q4ɬd?~lC7˶Hq,LKo~ie/~c4nء6f+%7-zϟⷖE-oEݡ-Ndv>Χ9ϹDwvcpR,Uo /M=>(i/^LTw7n5 S`1~G%s.(TZtj[9 $lJR!ZC{g½8O?OlrQ O.Л_pcDhN\.@uZ#VӍ^:;OqLktm,UGa<Ҍ]}U5ip8N I^1F&|r ֘0#c.67a_[ Y%E&_~{$_k՘79-qU .^ො9;S  ٝZHcV3KhMPSi!Og8яcJ }iiX2.WRkA z@af&a<0("1d~; 3~{~//$?]-t;kANҕ~{19j%4p_905:+u\Ji1k)5;9`DH)a-"46}JLMN7:>YV8SJ :H|&TUȜAL / 3anuUpɎ@MUɩYA&ۙdx' ;uЎ),Df9 ;ØK2U8Y< \w6hx@ZG˳ (^.Ue(+-BA~vT-03>«߁RDF9s!902ꁁ܀uJ0c]M-nvr$LIjLfL.r.-o.(tSBNs6nAaA ymA>:6Jrq ?xy۾?7yy˄CCp. y %ɃH'K&6JmۇUE9i 9; xĦJ7j1Ed$|/3vYpOi4֨Up 8j_svB#ds`H0NJ ,1z+HkFd*ˋA>p6bpp!DV{P "sHxgCkɽ'N.l33=;Ɯ#Y@8KfQQ^'4[=TLXt((xrr2kDbJWJ KYN}?cBO`#υE 6mn 0fh5@ nftvvӨG[ ѭgNI =JeV351P*S F1⟈+݋şBCZ.DEkiN+mEfMTODF۷,K4BuN'z>󬸍,ԤK/>_ Q]ݶOp+BIa kfb^n"&TGKJ8CP5a2p,()@z矂/cCml`0+hᤩA1H6}}0vtwG$ȇXFoQZcJ%޼ƭ /vipֈɹv܁#-[ⷤ' b-X ̈97f7T2or9͗hZؼ:"Z o?.W$)r^;w<OTtSDgammm_JJaa!Z[[SW3_Jb)V/Yք  &6'Szmʼzg'dIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/desktop/images/scr_resolved.png0000644000175000017500000000433112346515434025163 0ustar felixfelixPNG  IHDR('} pHYs  iTXtXML:com.adobe.xmp 5 2 1 m IDATX YlUu:LKBR4B$,Ac&.E`TdU^lL^H!RXEHP ID%Ř ݡLgڙv:772ƒ7.?~Wu 㢾SД,(Q|=%IFd fS(GO!vmRA''<řsQ6g6vXl^5€ᰄCXY "Q,7 . IDwrBP U9ШUX0w&/؇Y(Y!8r ^* j zFX/,6u:բ$ h46me_0 v?WiYӪ|A xwG-rrtׂ>8GA*m݃֎/8QZ^I dKF@׏C_D[M"A2Z.V#ߨGY5P♅xq||~'S^l&[ÔZМ:?h(+̇Q3@PX xeL :|ݯظ& ,xq;rhȏm>b> :M&f8=~4 bzwi b~6?)5 &"1&amTV7.wYrT.? Z .oh!#财nW- ?~AOA[>ƭD0hFE<0篘`9Ӣ rpLaI-R0- U< gBw/90V,Dղy(.#I} kIZl xl0 p[onGgb[<=vVIlFon"c jiiAuuXFXQ0={!귣Rld%•+B,FPXiNY.,S5f]e:f*4<0?߈}uہ Ȑ H/+} @lAWWW)ex6r0Ę4z{{O-**B}}243YOp.DQx{ Ht+a@iI~&<'t-4o E#al}B#)Ą. M[ $Ij `OO0©k \2 ʚ^[4dtt^dK2 b}H$ERG UIH$̰2%k!JmAKZrLܥSNk$ DO>"W 1;::Dwd G&?]r1Zi;G2B>/e-^X2Qб=*fs[91ز\-Z$`Sfziz0> ;]2lܔ䄛Wck2a^om 㕬[3 g)QgϦ'm?k0S$&ޫwهܽ"m?fܞe8IENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/desktop/images/scr.png0000644000175000017500000000431512346515434023262 0ustar felixfelixPNG  IHDR&%. pHYs  iTXtXML:com.adobe.xmp 5 2 1 m IDATX klUv[-H% 6A DA(`L~*DU+6ZID%@}n=4[޽;w9s@3݁L.Xc5_𷸕 ~S :cٲPXRw6 zτ4-ɳP0>:h4j͟X(@=V|Z893ǣ  !TǪgW`6I(1~ЉiWSD-%C X THDMb:EpS:'bRge0XSY^/JDvG6uCt2taǖuHKSKc@?91]^\ienL-,l2!Ͼ#O-%ObSEp e8&d٭(ȷifj4?%?}g3á/Z _'/D%BMFg0ل,حipd`An41ۋϿWU /*tEGݙsB{O͂۫.#oR ы"22lx1xP[*).eVT |i ts+DIQ.A MW] 9`Duȴ3tl9 yj):]C"7 }vFlAnv:6uBBsҝl-%x6'dqFnq<ʂ/W3IZWBڳPrB4Lđ0lϡ؏hlqdH9`qF^3+HiP#HQȝdkbS Ȝ#PތtlZ"yl}:.7ۏ,͸ʛ hDW o)L>/t-J8SGQ:Zʆ];7n1Ϗ1cZࡹ蠎pƮ[ A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs  7iTXtXML:com.adobe.xmp 72 72 5 1 2 3\@IDATxU}n0'n͌4F9ZeKVZX'XXf ?k`$1ccleɊF{r4s_tW߹ӷodߚoթSҿN.))щMLLŮ8t]*4JŊڱtHBH=у|&S7%w 9>Nc/ %g- qY^y&I9!h. ^%0!J OJ5TUTTزe4Pٵ55VVV k``z{{_mmmt҈NҠhI#cz4?bYCÄ>!s!d7_y69'&Q+*.ҒI0#i5VJ|Nf%%6k=VSSke11>fCêJ #^[V['}~thE[UY IxD*oaE%VQ^ $7 0MX߀YeEYA> x< Yo*;XYOytdFFƭ\tc eq!y:ʤiswf.g5w\h]mZ:F){Xٖ߰-XUU&FmC|:k@ wYoU/:[th@,FR`cGؠUئumxdTٸ8i%uX[jNv[Iyظu 8589f+֮k#caUXڲJK֮lhNٚZդ-*keU ,Ikټj:zGe0(3g%39 ,CH҈[F_F@gF"F+VQ qG=3`fae>򌛫 ok4ә hV#s۝kG[Nkhl uj‹E i))+iA 7`> 5Ćl҄Jnu7Ȑܱ.޾jJ cv ڋO?neX^bUZy ;q54؁{nV^5j)+)2۽km`ʆZT fߴaj;-qIҴNsj+ThxOu3j öjJ:f~Ҁ+KVXkjҚkW[Ij NjmUv>uI7*Q;췉R!5f5auƫmD#J sPaM .hR\-_Z]iZQ*Ͳ*jÊ#ՔvXSS'+eݚvOYe6n u}iڨ$ek*n+H*ViA@@-Y,lhj6 i[qKTZ*Wh3uGy]g>f2j3d1e?5[yvޝsҸi:ByAfB'\?n 1m <Wcs~u.Xbļb~?)rF2y_cH>HÅ>]1c֠R,c|r*xP!>.u \$Gz@CV$Y !Ȣ`P@2 (ZE ZU \$[l'MIDBfQ$ ib|![Yt^rJ ^1%@=:KiUPHW:8 =SC (L+V 6 ej7Nv{,&]Ѵ̞q;//l6U+Nr::PUɘmKٷ_A۾\AAq. vB!/ \̡k.Y4d)4U&V,u>%*[/Y)*hh]*S٪ -U}LrKڲ$^O:n~7_fWȘh^N& 5ږΓHbdY9YW*-7h[ytGSnh}׾->T+++'Ap.K/ُ~#{l޽v.cqkkwV\'k=ao5 EpP[nںeva9-o_u&hEرP[aE+Wc1>k_x6L8l{ÅV Ť+:"ZI:bgCh8K3FI٣>4ItRw@Ov4BѹJyl@9A&> 4bGL'B3u }mB f =E|;wq"`L 馛4^)gy&䙴{5LNOzJb䄲t0f,MuކKg- 5 iH +aUJ ]QNMqNJl6ه p?BpYsu}6>uEGӐ}J/:%4hӷ޶zzZSfhV%:OڔQХnrjmU%]懏WoKF΁N8*퓴Ȭ"cvʣ{촦*K &WcʷGHd+@IL\; "7l/bh+h?YƖkC$@EAK~PhZO?t?  z(H>;S9ꃁ >E\Ɔ-7C?u]r%hMhM9!?i[qҡSni- !ZU'\ z/Ik 3:'C^ʉ3~B"LzHŒՕ!ZI#$Ik d $_y 髃DH#)@E2@s1/\=@<:ɧwq<ݘLW嗀!Wl%kJ# aG^qF`8L|GNBb% r::t>иHq!]/^ G~]NKy9='i|GKq 8Ifr -> %%@{#-;ݹFzgkf;a\:s'dgJA;9lq8E5J|z%LʳPJ nkG\ U΁i.B\d ;Z4OM=ˊe7W(:%[Y=_imYyjP2-P!÷WXEp^A>CO^%ˏˢӧ@x>*ϵ>L'/xբ. {c+~wO5԰rüH׳s)\ %t%NIoaĩ6^< MAً@ni`LҀW'<2WIlh!q3/ pJлE,*81:͙ɮ\(WJ 5g1X<,4ўѰM`W`:@ {r..rC24,Y($GY2y-3G'N;նm%vT'I+b XbЖG[ԽIgߤ4\W8L%[5})<}dk:,6&pf #>ԽNҝ^IHWc Y#)=Q?l^9Uҳ< %ЦңJuznէOK5=iD(2?{]1 ;bj˷ǂ`9 @s?c:\cEt\:K =!ΰhԊ(fcKdqHF:ו}Z: }y.3>L 'tNaPIO3mgpqW>g1txU9-z݃]мL|&k8e&t[I~&hCΩV=0d:w\Hǔࡃzϱ6GGOfXL6?#q3:4l羐B]cތNKqL Ax*~΀Qٷ+6.(xzW8>;zxy:^S:)zQ dmfWƖWSj~kRG0sH䕜|(%?`w8<\f*$3|.g! ~iq_x4Ӂ{@O;=?tiT6I6>:zmuNrހE'eؿ \k֭]D޴$^^'?#)A{Qgڵ{vS-[*H`ȏ<UV:pi[]%B_M9`I;ƶ̳τ8y7h~vK~BR/~4!ŸB d)o3L'= nSBLCIpQ9s]ƜV}*[l u3Xk&V6;uL ?Ci}=bvjmAX=Y&tjNb`"YN4b^˜8=XX$@c.gO*9V/B8Ŵ%h'.Gc=Pߜz7Wo ^hh~ykX07J@7>Q0h^ Z.&%tb9KM:`\vZu^VaeFx™噂pO:a~c'u*fCݻ0:1b {Іasv:h\hY\9o - 8nu?x=]ۀSJ`Mt,pmkko/~qu]]8|ݳ[s>du 6T͟{;Oڀ,.i3VR6_3NqM7_lVZ.n=@hS^h\[n%l8x4&*Rgf;B[Pȇ"мbB L/yO 0~K_ sѦqn:#.fdYZi^iu6WVK­jSW4_?jO6UMWʧ/L ] S55zSIdc "#8򐜩0/HfhJ [ FiShs,go|cЮC.Y 2f7l,_ljk}!fF֫ClˬO69۞-+.5eM-PVv˂z:36G3Z2C70Vqhgrb\T ϥQ/cL<{gƿVms..+`y{Č܏i>e1м`"3̤Z AZ6C1H* ƖۮGi3/;e:F&%f{٬XA[;%Lqd' y_Ё+"@_2WF"wvlW#(3%VQBzO&$>&muۡ(P;nyɐMBޓd6c^[̰,ؖEauuL2eeGNfLnCnz)',"0UuuY0 i? K<Jӧ>){;4 ggQ״~tt#eEx`Qʖcv]@cɮ]BD (`8?xgiiʄLtS4*ӖA\8ϗ m҂[XhW\qE(p>JҸo|=BT&DSaQ$ t Fôu~74PE?9;[TVZn}cYCm%[r i~`vv_zܞ]uu֥MkO}VH⽥^khd_[n}l\mMXM)/=;NjHǧё#Qg^|cS+[8 Ax mPҮ!m&Ȏc5L=X҄vK+e2LHkPSfln[2 XO*Jknn# D8h@h< ʣ|dbAHӢhLW0ZP>vp!\ B>ixY&U,5:}x\pDr2rn9w&fиvŽڣZ*ױ1Km^f֤cPU\mR t HI9ܸFCE% `,gi>SILi0 67V*PaCVFa*9|_i~Ww8,o&y~K"9 tV'+'[%8]0}3πPLI%\@+|5_^юK࿌dh m)HΉv 1(2;p9/5.l1wN4 쬤1g!>;+_-oX&ЦZ hZس0+6+3mECw.I~ y1xޏ+mrXlssf9E8Ĩ93ί8WAձ0KqImf.^L~~.Lۿչ\5a @v8`3J8Οy\4׼5uWIIɔ^92"C6q=M_|8u%raTc\'fHA-"h'S:N}v' x翳G)z<3h>D25iG 괙?k1l2g~%~|p%0/ x%ee!)ٛҒJ{O/'_YDkGB#,--#Z,i>_ѹi|Ֆ/|Q?}49B/lWaU=ph,a%y_ f3K4 qn(d>8akej {@15Dh{~2=61 qlaKgqK`AŪҞOӆ4$;<2`<`-gsSҡijevs{Fd{k{C}5jgχI3CҫRc/#%Yp__7)"!:0[VX׿`q@c#d:7N7{pe%L aE5@\׽u}`ÔAmAHB|G_lb_bKVs7{\@%yq-YS֩F׫crJL_V+&W@k"{p5{ۏ@ؚɞ"R8:HݒgUO-9~#P] i @ a x6IL칣óIt#/W*Z aa Z ;~b1 C= 9+D^Д2b\]6X|O%@dyiXDNkoCb<|#64+4W6qnz}U:Cꋎbw,yOBQK S)ybC>K'>pD ѹ!~hc  ;^N XgJv=:PaJl@#$] pEN@}3 4 HWq0?xq niJ [Y/{aON١3:4Zee`Yw}zUw鴆J+6v;\/A띲Nۿ{b ɊK+ Ak+oHv_Oȝ ]Z<\+`coY~tp~8^q~dcM7&2ya۹%?h3pZq^SewP%/9<\v[v55a%j XUoT:aԞxl]w U#SmX˾r2LQ.OYY]yٰs&F]UZڥ~:OI,Z_t<GY/ʯJ4h8|8zu5 c +x/'>"u@c @ ;D8v'4# ' L_ Cn bM ^"s@Hdkĸ]w᛭#680F4.|gs\6"'ӑ-+W,ڰ~۽kߒCh?<:yJyxxQiB^G!;mAB+h #bBkómzd+tw_0ӧlL3ۉ=pMqEsss^: m@R rEp71#o{*|d._ ,Hê__  t Zaѿ{nhXY a~6Tէfl`Z4o7xqSԥVQIzBئ:Q&iÚ6o;zC,hv>5c ǹ\ye-4:3+hqj3բ.@=iF\&qybǡA!Ï"@! {ɐA &P@Z܅/T`yCAPHt5h .R $j>f 'LɳZec_>jFw~cajT@cZ >ˌ?L<<|W$yLp+ǙX uǨ cv{8^Z~*bb"4+VY@uu 0.VS˃=9C/rSq6;ߘ ? fMbcda$Sѱ 0hʹ,:'y.V6s~X+0=XpBͪK.Vޘ&wjţ |x bd1Zنyhyz{ n;Cpx#?ia:~0n>b: `s?.\rJ`NŁtMNKC"3/` X33}F& 4i"yc?& Р5=(`CK 0S3-Fh| ~!2$2yR^tg563WN F3ݜG4F~: /L_I" Lq1L@,phlPYG\[ ^π0% x8.ٔt턲ٱcOTc < GvѸӜ̙H4<0w q8W(|@&ˉ2bT zNք9m6a|(5}s%MwȻrP0sXS/|easXb!<8f%\3IOzn %%3`!G\Wgg.bv6xŚ%ʖGdG|/xJP+|pw̚=H:ȠɌ7d t0@pܻd;c4ϓ|?}f|\b7~^~u&8,B]LYٯ.d\>g [h> VqzCRց}:txC |˳2d|>Wr?{dd3&laiӈ~o*N2ķ|@o=)x!$?'t[g9ϑ݂ɧIىSvt4yfx,}7?n I /+[+~2j{laq{.\x؁O#=vЍæȏv@^XOxK 2rO~@3+ӄŸRҰ5h:_zV5.;:oZ(O>zvW7)N%)NW}C+_3Uȷlhq풀Y>!ytNoz<{wuv]/uO8|9EyЎIph 2_]uNH\#/qO~x?xԁd4J`^GYTk':nִWl=JP۝7r4xFR91`OؘN-K9K$ *V7\muk/ +u׼)Ъkn7gj Mԋ8g^^Bfq8# Px6z50ZEz"0%P%AG\^5tlAf68ݝ~lW{W.X$IeP|HXۻ®&a4uqyBve]}ִ<|)et[6kHq-+Vȩ6.mK1 ZnZU _ijpbQ4'6T5j:ZdtLtL4%EzLЖbB:@3bDc ͍<V~flɣ.*G(6_gǞJ>2^{ĆXӵ $/+g856V`tp:Wհmpؿ$׽)[ ?`ʊ&27vB]q@IDATm(v63zE9:*  {C:r˿KRbW l 3`s֬U{qGe'[lU$R)ʇMpRSEyh@Th5T|xk7ZTJJ1uV#c$$>y#HAm^t(V,:> ΉQ>2N>;#rפ~LI7#UDlp:`q , X<t );rְb!KTi tY_wUZY646d{^ ُ#;u{uVH}bOOqUpl,W.GrZR#+uNrljiu4ӊ;~;}f\0p92ˁC8?|=eA8q3PrޱI ?ipuyAx4A_s@Kvʈb6:v.xtb}.FtiI~K9PA' ַ6R#XZ82N_B/yRQQPePl|P|?D}{ g0ϢrSqAYM?I l +\Tzw: reXxdƙ7ɰ%ted~w~'hQF4x ڌoxBM0b΋aGGi-eiv&3hGtDNMGS@Cr7ZmppHm )wOGT*:rh4ӡ:.hM@CFK\kh ,А>[ Dm@gʒ'.hl ]l9!.X/Q>I͊Ȇ;Z#ø\]C)'M .~:\ QϿ-֕z"mϛѝL2fQAo@5cЌ:/a( x4H27211XPIQG&o) xm5r!/4hgj8~%NsLx1iOt"d8t2 "y{Ïqx2Fy|fe>H?qrbT2ۯγˁ8nǏ|1ؿR\SB 陷 4T:m\ydDcs`_ bTi@Jrڵ^L <_XT4ЁP0)$qōids` nVkFw3Fp@'a@efRv@g|MSn!iO33eA]!@3 Pa:4'%3PJ4PC̴&F9 /u IJ=a8q2yq= ?l9gaK}\@ʧ1+V GFXW/P:QaNOht2h|#/ZJD#eH :3eGAdhJAN>Α4g`eL/Z-`y'e{)GFz@Q` @nʝ)yv@@f/ȠKF @s2la|<&sɚy۰T:|Hà\· ZTv.8fm!哫 3]kfx\2A,lꗋxl1||ø'0hO&MYݶ2yL3m6? %cF2R L󫇻8>3kfb=ßL>O%ՙ9ZTLc7(’% SgSc_cQPtt;\YDMclE cCÏ S= th 2rԌL~Tþ 0#.+ndƅط䓩ȺZ?bcZԔr#4Ûgo&׸ ^q , ْ5WxB ,7CՀKlݚ>ʛ9ͅէ,'X_Ct(NȻ j9Fwl^t2:+ ӟt0`7 XPrYv3S-xg#+i: 2]8S[n 9Vi!8yraK,kd0`8Pp\Z{f 8xȋqząx駃R:ߑP,s)խE5TUG(~g!zUsŗN(TL-0+D?"t, t2@΄̀vʒH{   5CG' ΊlV 8&Y\ XD.@ @عGX`eF?AC #`GڀD9"'rN 7򑟸r)gy0Tȃ2q)cObrK=iZ;_K 56{lK>v>,u|JNc|lcC}ApW5I-󐇆Ogx6ϧ {&p1[JP!BbB_ʸ9=*4,GcX^}݂3ܚ ۶99+߅FcC5Vp|QVBqyQ^1Z&t{.K P2vhP3uf: vhh Lab'4ׅ_qcf wó;4-~?8O؟le0/'l@ `ʋ=_'e^1M;A"h,#vYe۶z$F>ШeZ ֲ߰:k$=OtE7ӆǦ)Zݠu ߴO[u/,QǕ1: >A>f wJ@~fwur,o=}3 7Μ>0#Gx}UyGlҺ[mȣspLKN!RV^:0U}7%S#Xϩ<o0MX(NJSΩl `sPnw@hW1˝sP__e=pϦR@Xm `1EL :XT\)acBFs6=EwNΕb'徘i$|4IWnh!}Nj%6hLN&¨ǜ.zчMW8ۙ tT4,M^]{m l/Zb<7m~wW\.M˓<|Xӆ{xg#V N5:;/{|򓟴t| Т +sOܘ>&B{L3xOo$#Ҽ'粸l3]@1N#?4r:dSLɂLgyN֑(_y'&fT?ТX϶iVSŎhQ0$vLG=r4E#~62d{&o([/_ϼf_{s,D/8蚵utSKvZ+%:S}l0|oֱ$Nvt鿱Y\HOXڪ)5I wE: M.OegMeU>rИ AgʀΎp>я;wc+p05d:ƮqL9~S 7={ôhҤlds%-1L$/ć^]%~Xq7o'džh-b3 Zjn'v.VaU?.:[46l={;0a 1%˼ a㉇ MT[o @t<513O0⳱2pMfpc_3V. uA5?| U(\yb^$gA7Ƌ# #:fŪ~?岹9gDaD' 97~ )i|i4/7yl4tM?<KOӟIS.n dF?g#W 4l;e>\q|kj94N mń.oz9_\N$%-V.cE/a/La%#=4pgr^q:̌;K+q.I#c^\3~΋[8 !1]}Æ6^qf  v WYN^a/aD??^\11V---AcTƦq-pXHM! ߪeI ʖG44<^L(g6D"7<سFX(6rR.nqO_# ^,и\n4< ,hg( P&Ûip\d~우zGPeԻST#1'SiA #ܝ_g01?bVoG9p]/ڴ6SJkoi1J r/Q6^0öAp. , RYfSAr4H言??#J8XB:б#&:=SS /D'm-oyK΀X6nPlBL'#H= h#L.((_\ "vH"$S6ʔS kʌ.y!e٨ka HGSִ ŇuJ^ l|+aEӟ`[fBfzcжF}ֵB ͎c;Hcz3:OlP CR'wM@$,, fQuҴUM'(:į]_w"I5dgN% :N5E錌4j{:)? @8@px:Zlh tv 3h4t.ҥӠ-#8i:ivuZ:,;`Q.P<ك<|+y<(Gh({ʃ8'аT~깮Q<0@øoD xpyAt2cf(ą/e=Sddi! zd#o^NhrÀT J*}󥉠 JKR) gPD3'ʵMr%U*_O'ا4@xQ) r(ZUt2mZ7OY7%WjFҶRCLҘ[ 0uSͶ %8i57iEYh&{5޹@2t.7 |.~>8w\z$S.z|8@C7#Z~C 0iq0 4<)7pS\y+?W灗^ ,<f@&`y$`4?=yw:Et1sݓZSLl2xkFToJw0y(<!Jr=,<3azIL5w0[#bGPxXi4ޠw?k֬"B{X+Wbai͸l4n^veL7ʏi0 `ǡE#*J$Ӆ!ήgU .h Fn툀9ezhX"Rr 5KeE&F6|g2F;& LnQmXZ6a(=nò)S%η4c97I9ta`hA,R2>PSar9nSPa r48FJYh8MÍIܹA9p@\į ;= l\6m⣮L' FF\f :u2" -#52++Zih21>IʥWT" x1-@w"pw*293|saاߟ&ͽӤEIdh7e@YPoL }VcU_nsu6NqP4Գ!s"D]Ggw(eTGާ&5P᧿d;kU~0Wi~ĹMXŎcǻ.3{FOylB~ؘpeFwLd:Xo%MOwKD}Tړ%#e:gia/f2 Ei~;SJ;c` 9jcZJt,rϘ}Ǻ+Zلw{y:YKRt,x}+:Wx]bf,-b>+v_?!+oUMV^֥e\;Ab[7S5 QH&P:isssкHpc >z ~67SÌiUvVq ZͶOuH %/^c>MX$tyعv vn׳5.6JSZl 'o>2W4&4W\9<ѽzeu2:`pͪڵȫkIǵe8bM pa:صWv??^d&ʼn hJh\ć?M9Ł8Le>ՐvO˭*R+A ء~F]%@hN=Ys_^thvfPvSWtV:T؀SxizޞQki.'_HKTJPYTDDsd=ݩ}dȱ$}:; •;"`\!6v辳c\WJW6sN v׮:UofGH3_`A)?xk]{BQ|}c 9!1'3c{piyk˪sımhhX8! ~b4=#_Rrͅe5~]X6nz;{A|©u굓AsQ@1Tоk]!HY<ߦp5{|4xy;@J eM/ SfZPZ=|7An~r"ib?a. |ʃǪK=Sf0 *YQOx6j2=;d=%qgC^ xT^"\jb(;!ώJSV* L{0F(۷;ﳣigw AG1MO--YVh5ƐCh[,nbʓiG'N| -gl*GGL(k7 U{C98UejǖD('&|1rZg]vL#LW}ChnA=N,xTʻz lW-dD\Z⏆w,4e` 25WCs}LvsZkd^i.PYxlt Venbgt'#iG5(_tcfW0b.O 脳XfGRx|3/ԶkiGs0SOIwܬqDkUZ IDy@?ZPlb^ P|j{*ב8|e;#ޤU>V`׮eãca^Yji1M/;wD^ ӎ*DN_•?!ݻAMeqXuYs8@jJtݵL{,FMu_/˖,>P>,WycYbn>0Wl Ej6Z\ &N&`k-N7-Ή*D$:S ]2nLFx6zX:)5S#nh0gyA[4g~u=_u_i5菖6oI_ci[Cf;b_|w~3͛~|-/\Q^kumɔ$ig//ߌzMFL!ԙiH'fP4- go FV1n4|K'A4jFfOq~^|BMϒi築uԍe~>Xjtޘ9CI qd4TXłxmjgo bo53ψ- 4bWB{'bb{ŎI㣪̞\wu#jpXlS3*|| yO ݌?O^CF :3Ԣ9 Ir:JbOhZvj,^A[fuel( 7k{Bl Z~,G},|zn|$0ўF- [bh3N-Xu,je˅csw=Ab׵B4i#xӶ1v{sfNe&;yy Xҩ ($3<ӢSGtH:8xÓxH0?+h$ځ2s VYg5BϸIɟ ݱqwg)wdfL/`VT5,Ϩ#EܡѪ* azLz!~f?3+eס Cԭ<%mbف2x^5ʣ4u0H>a3϶l ouF~z]qn_[KeԋGk{nJ^l X4YOAF&۴>gnWHi|'v~nyt ;3Lim5^Y&Q: fT&eGٙmŻyadKY:d"95/ -}@2 im &LheUY`='`jK{]zW꠯nC¤$%Ҁ,ЦƓp{[ȫ|/KT}O: `%OgK_ji67fY!w"Nk%pʯsiWgցuN&^?T>VfQHG>Zϯzիj??׿5ܡhd׿ST݋6Qhm(o dcz 01t#3v[vwеH>3R?im?7$=#MYՁr::N6tL[\gDaUcjDh1B: iRC'u :ԉ8U?iԹY4t#/ih*Qܛ-M'!W@SӁu6 "yOVҙm xǫH_piN,dpq4 6`wu* ~{WeDȇ=v>O< 0%c m}UWm`^:Cʦ!ON[u |h;6@ˁ^NRF%0K_>/Ϊ_LAk<:QبgԈ,+42hy6v## =1-g zkkojz++TIpXЇW_];  &Fub:) "@ o+P/@-_rhrdu˻8t>J>'iu=I7yV6XSt{9Wͫv$v 7 ]vְbeY꼶iPoF6g^#VvN{=Z Pاb͠cgL 4xkT %Z*ZRHږE=T:{5/D+;MK%oztE#h=6OgG걛J1VeqP2R5 5\:i5qgyj蜴…_xsvce5˟߾$ޅd?i g$h~>:`4>4ꍱ+fCn]kjZo/C;ַ֩:H_կ~2ѭ mkx6vb՗5h@fjodA[ٟe>sKv >"ent,-yx1;䳴å3|I5t^.v|iA;SV e6b\Zxs4|XC4Ƨ6 h5Fߪ єop$AOe|6E<- ohPyP1RMyh*+^Gj?M;Jv iA8I3 /.uw ,;XN<n~韍Dt&pNF?p4e2Le:oڮ8nM q\3}6_EFpF13^r%q+= FN V6-,fZtҰ9eYxQ[SuPS-*0تU`pypؔS'˴vho(ŻqO~n:Yl`Ri=}`UPJak۷8Wz2>TaeNiW5}RkE &R9NuQX^1Fh&d`ӯQy8"'g@ <+ouX yK/¢{Q' VF#C6ئ0*y͌Ϭ2|;=-O:2RxwqKP\ {czR<B>NhWTw !˩r'׶':ݘ 7INR>Rs7,>-Bٞ1k̲켳Bk'9fIf9,\rVT|H49SYgkLM&E>3Rh0lzho DuE( J7 ю ֙g౵q{꺕 U4IDATB`g @8O[֍ @}3f4;RO^8twY zӋ^Z uYhᣰ1l%BGtm|":ԡhEMDi앿 |ayytH*P(fEusOX7~ =40rq`)1H5)SfZ\„wmOmEJyDe:ߺ01BGxT-.4^3M Ĥ#x]ry{O⬓l)!åq`([t#O]B@oq}x5`puX3/W} 0$<}j_0NpD+W;S&>ǴkO _W#@09O߮ew/y̛7+4t04m ޚZ;]ܽa>8@l>CA\iYqhyumKqЛ>he4:{ڼy|$@hLK UsȲp %>Au8Q!ʳCy$LF]8̑hӧ)PHEXHY6}t" S4". 3~{:lUt6ՌH7|7FWZ i ]Ǫ(*03{{X(!Eh\sB&3g?E.|];?r9w в;gb]m4  W,<H|]>Ba~XC9D A} ރgfE vV_Vl6F@漆g'tc6/CS M1m/yǜP_7ʞ_6 @[>r3 {W*vD 053SBWW^W[n0+}uٰqSʷ>Wnv,HE*  p,DO^fT2Ҟm&k<Gcu7SA w&V=[7Xqh I_ԯ{Y!e*tLђAWW~Tls]7hL_+gy4 -mV^"mF:U&qu_לߌ4@7HVGԲE')O\fEY'#>:Ґ0>gQtoXiч{Cm]t|! 7Cg5bgڑ6tX}$v=>udeˢ)x"dQNG[.<|?Q~yKW\tyٱ婪ƶk_>'rʬL׎jߦkcf7qhH;ퟢ5BXڀƽ|`i3'PC^X}#^M6ҼQ:5 . M񙺾PzHֺѹ3cUʗ-s{|<4lEgG2e9'֑V]mi/~8DSk֙,[o;3n /)ZwnZ;\b^ykʻuCg7cqvѽ;QLcX^O@Y~zf ?rG{k׮SHeڦ}iZrZ>&R;-n܉ְ2y85]AyViSFer`F] 3_|QQVGz[5|ޚ8 .AXgE2 ϩE IwpnD4Oލp~cV&,ǟn<' ['wpdy\ FֵFF XIXe./),> k[6)1߳̋3&WzȬ2^cZlGS,k{jlJ91dtn(Owo/oz2)H_?]hja HX_En//ԅwa pIij-(q wk\tx}}ヴA37>l-M|:}J ?P5>kxsTy TfY(r4~ϕMn,f.*%Wuww?ӳS+t߫ m`xLh.ֻh>~6Jg&8{Jk!Ki)GqP O"{o׫6y //ȽUlO; w{w ݫ_:M< 84R#]NjcIrng8@c}Х֗*9c@ʵzL#k,5'M͓eSϟ??+z;k1˂i0/eyjv4ht ,58)f͜];˟韔w;*0\Ȉ|h ӡG c;bzE77',t1Ҽ qJZ]qǫf_}|NI`LXh_؇' /쌑oG6^2N@ )5)è?5+*p F79x4MVࢩdO2ZUnL@̗B~4S*(-FGWy4$eNOn3=.Nf MFL?t%L0G>@MZa,@'L߻N"M!Vf1M X#XTNdΆ'evyRN[~+03^V>û]3kn$B&P4 oLZy*/7Cozӛ"{XnT; 7XV67q^l?Yіc}eRk׮u2Vs_.SUijG }qI~ڮ7`Z$ qyqpm{Kp~Fg @FhQsccl2M^ht8:iipS׶_F^}{ndp,pTu[$|٢7p۝oݴS$!Chѩmx%:8ahMZu+ViMڠ\y啕g% M/A-QVL6镇f!_ZANY7#L? tl(F#֐ƭxdTcUQ7TJkt|{HC5(9Z[gА;- Pkl?'?€]L3+Ɯ@IZjT<kv Ho] UΤCge4\o-ٹNvў .ik>tkiwܖ9j}lvQɨi~@UG0: ubu@vt@T0ӫp0 ҡ!ynď4#_tiI_.^:x@aNQ6y%H ':h6çW m-F~1ZdDa8rh*ev+(h]6L9;i a'OCy8ag˶If6\8e̼N>i=m~wuFv~H7,a >߮Иh5:XtZ*0РU)Vt@Bɥ4ΫSw<`сiHJa=?dtvu|~s`-4i$L m#,~Qa]:`ry^Hh)~3дA:r)]9uoRmm%;Kn];x:r,@?vl:v 08b$ ;BP,kvnM^:i`pBm:p4O?-t $g= Xj@>>{y<7%`z>/h&NvJND >ek}ixӵ1[$F}e]$ԙ81yhtci%?C>3GLtg A?nv;;|]=w^;DL0 ;k':?p?⫌㹬iuɰ o;iG:􆻗kBg8= hsm,\J~\:q3r@4w94i|EjV , n %$wܓٮgK t4 7ձ'Ɔz0wO _.uS+e9iޚ aa`=)ZS>bxt?#eSc5`k bEpXP0h>pjr,5{y8>&vN#Yԝ|[C@h4eu%=J Û׉c,(«_&WWSg"LWQ&)s#/,ϾgG]-xYҮ֏OGgi00;\vl[^s[7|@o;tY2kM{ƂO5O0[T B!{t$p5Ss rAx e#?,aY2YfO^]?eyѰ@xIpٿob`yˢY̙9eFߢO9˜eY˼ʢqh~e R?Uv7 =d;MgLYo\7<Ǿ3*xAlu<˱%*:s= <8) ʶdկz۷ˬ%k..qʅ ʫ_rVfOoCK/|KZn+?%YXoܼ`KwkY,o+w+/XsiBdek,rWMbjQ :6:q`-빞- `ih-Z)XxIyËOgsT(0~6 W\qM<1@yUo+ g{DɃ=6VG73r>H5դJC6'n]j̹嵫c<͈u0qZ`.O?N{{^'X3.tS_*+?weŲeUmo~O=eıv:n|/iĚ9g?+˛ztc'>qߔm7?ϖU+VY#͞/or..AˀC@5GW p9v$p:$pR# -([r%B{8\>+\}M=߷:|?T}OwC!KW]UkdãM)˕o~hW6 ,RK+ K|7hh\OI@cC`Iz׻~8d;/~HRHsg+P^S/%/~IJ0Cbڑ:2S}ŏW wa|wAy쁇ˋ_|7qVS;^r]߫6ܯr/(Wg_xyW^u嫪>=|svĶI9?a䗍=KmK:p?4 ?!~=tkaƵۨNJ2bM?]-8;?3o "7eg7|r&o4^.U+הI| S=3g`U?PGxp R2;a-Mӵ_"y-+N>I#i2Ly/]yϰg8q2?9ϰNd= vVoF;Nv\ɛ׺DۡPir;3h&1<ep,(x;fW^YKm.2Vw<~2, oqȣ 6W>ibɯe/qvP*\\4F$@N>8N^|qk92`PFXЈt0UL'}XV?ʯJ~gOzͼg˫xQrMq]⤜\qIϳfn%`W4;]1Ƒhij]n~ЀJ^϶ i|>9/҈`ɛ2ix.O+/`$;bSg7axfҧ| /\ρɳp$ ?β/:BmG2Xgʴ!xwMxAIqXU~YΕc% NKS*:E"o-vU!*\ÐN8A. @wE#NԕpqZy m8\xuz}_DyOuN8_ .gv< r ˈ|2EַUyP2i销0jfK2|oNMNSt#&h#CK-ཆ?W4`!?\@ ACuftd48iڃgm$)Y/2~ꞼӏLt4.~h$WOIt3zNɮw3U9CS;Ο{&gmYVB[\?2j;}Qx7 ~͔YdN6y!ԣ>ݎﳜt:mρ]xҖ廓j}eyM E3tF#?: )@`eѡEP|ĕFaa`r`>;0~1q^U9 ALM5sΡl q$^ko|:tO?yH留{ _#&[8-:ݤh dn L@&DuL bW7qsd0 V\#gXE" CÇ{Tpd`ɱpO[+(hs({!H"eU<oG"O~5)PgҎY9 5nO7kxeut\z hk)94N7-UE O9JُMt`ƩO|;_sN]Enٶ31}D(`?y53\XctњxXC+T>hg#3^Ci$)n&'|n-\nGڴFy8ix{~= tJ@ܘ-94{.|:0ף*S:~oXpA]idՏ2.jpQboK TOWY7s'ZKmH>]<і@ӦX5Oh3~ͯY hw{O [Rא4箙*5zkOZ깞F.m xAu8Ƕ #cGP ;imO-~ †_h{Hʷ'K'SZdyF0ul{}[pFgͫgЁfo eƌqhN:kI3; >\盆:QBwߓ@O9 \;|8ؽ'x-VgͦD{fl6e)zxl 26=TFt֟>c'.m x:Q5;όMcNfwfv2y;AJ[|'dnlhaxD!I'`e9Y0)+1{c GB.>Pl_@՚ :t}wY+*p͙\;mzFo/vɯ 3lӟ>A,ZxfE[o}1euˣHbrҤx3/^`0螲>6ΎM@ oil\r;wV0;'6"OWo]^YQYRK$cNS1uo̹a12pL`p܉evIױiX=|xJgʈkt:E ձ;zb ^!9jz=4+[QfģQ혉{MLbx 99hqƌfVVLEw(Ο?hL sBOxbǽp22{<{ݱMMmuU6kvTfiaudX?LUuN6 9JM$ŵzO 9vQhe՘M񱛣OT )y%?zpϚ>:g@iٳjGg9|vPS5kMbqU'4u>'9Zp?iΤ VZS[p~rg|Ծ!2_0?,^ ʵ35+n^1ZʕUʀ+M hh{j{@$r!VUXd\i/4@׭[̪yM<ˋYc#٨/e!<%ޜJ5gݒ愧',q T+xeTQr jޟSvU9fh=[6Wn 5 8$BNm%]X,?^ʹ=tPGèJ++l[?/u1+.?4-NRyN<3<)}06h@1),}Ѭ=cU^i,4ltIl3i׺@\Cw\@l;,ʛT_5b=sʩ*RZ愢=~\O!heڌ9s`K]tON7yΏFڜ)ĀF3sn3('i\O:4uq2~vvhK`ҧt\aMCk8wgW~.&6p'<[cT?^cÆ&)B{ˆSQ7 ^ܞzIJ2ֵ#>Dk6zIH`uB}k_]ɢG'z8bsg};矿~: MzI'-k~0(xHLqqxghqOwz$ГOlkwJo4mouSh81;)9?&M>'Kd$Г-[|*P^,XWʬ9gMث7}8zc旹.H/zDe–شa} %/}q==D[Md;&ք8h|_\$Г&]عK ~qo/"ZnP-ٳE~~X]R2I'O 4'ps8J #s-KNG,eQ~<+UO= <$@?&4;z}񆐕;ޫ&F/lZWRuxIS54,Fb5~NOneva`n>̇=lzמzI`<$@WL>V?0t4'E48tx0գٓ@O= ';3ZC-UaM݁nK[oN=z  DJbw̑ctIENDB`knopflerfish-osgi-5.1.0/docs/bundledoc/desktop/index.html0000644000175000017500000004014212346515434022513 0ustar felixfelix Bundle User Documentation - desktop, v5.0.1

knopflerfish-osgi-5.1.0/docs/license.html0000644000175000017500000001541712346515440017422 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - Knopflerfish Open Source License

Knopflerfish License

The Knopflerfish OSGi service platform is available under a BSD 3-Clause License

A notice with third party licenses is available in a separate NOTICE.txt file.

Knopflerfish License

Copyright (c) 2003-2014, KNOPFLERFISH project
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following
conditions are met:

- Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above
  copyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials
  provided with the distribution.

- Neither the name of the KNOPFLERFISH project nor the names of its
  contributors may be used to endorse or promote products derived
  from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.

knopflerfish-osgi-5.1.0/docs/osgi_service_tutorial.html0000644000175000017500000006446512346515440022413 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - OSGi Service Tutorial

OSGi Service Tutorial

Contents

  1. What is a service?
  2. What is a service factory?
  3. What can services be used for?
  4. How are services accessed??
  5. Releasing services
  6. Best practices for accessing services
  7. The white-board model

What is a service?

An OSGi service is a java object instance, registered into an OSGi framework with a set of properties. Any java object can be registered as a service, but typically it implements a well-known interface.

The OSGi R3 specification, chapter 4.10 is highly recommended reading. Also, the javadoc for BundleContext contains lot of information.

The client of a service is always an OSGi bundle, i.e. a piece of java code possible to start via the BundleActivator interface.

Each bundle may register zero or more services. Each bundle may also use zero or more services. There exists no limit on the number of services, more than the ones given by memory limits or java security permissions.

Both publishing/registering and usage of services can be restricted by using java security permissions.

Registering a very simple object as a service
Long i = new Long(20); Hashtable props = new Hashtable(); props.put("description", "This an long value"); bc.registerService(Long.class.getName(), i, props);

Note: a service can also be registered as several interfaces. In this case, the object must implement all of the interfaces.

What is a service factory?

An OSGi service factory is a special class ServiceFactory, which can create individual instances of service objects for different bundles.

Sometimes a service needs to be differently configured depending on which bundle uses the service. For example, the log service needs to be able to print the logging bundle's id, otherwise the log would be hard to read.

A service factory is registered in exactly the same way as a normal service, using registerService, the only difference is an indirection step before the actual service object is handed out.

The client using the service need not, and should not, care if a service is generated by a factory or by a plain object.

A simple service factory example
class LongFactory implements ServiceFactory { public Object getService(Bundle bundle, ServiceRegistration reg) { // each bundle gets a Long with it's own id return new Long(bundle.getBundleId()); } void ungetService(Bundle bundle, ServiceRegistration reg, Object service) { // nothing needed in this case } } ServiceFactory factory = new LongFactory(); bc.registerService(Long.class.getName(), factory, new Hashtable());

Note: The framework will cache generated service objects. Thus, at most one service can be generated per client bundle.

What can services be used for?

The service concept is a very general-purpose tool, but some examples are:

  • Export functionality from a bundle to other bundles
  • Import functionality from other bundles
  • Register listeners for events from other bundles
  • Expose external devices, such as UPnP devices or even hardware, to other OSGi bundles. See the Device and UPnP APIs
  • Expose java code running in OSGI to an external network, e.g. via the UPnP or SOAP protocols.
  • Bundle configuration, using the Configuration Manager

Generally, services is the preferred method bundles should use to communicate between each other.

How are services accessed?

Services are always accessed via ServiceReferences, which uniquely points to a service object.
To access a service, the following procedure must always be used (possibly wrapped by utility code):
  1. Get a ServiceReference
  2. Get the service object from the reference, using BundleContext.getService()
ServiceReference are typically retrieved by:
  1. Explicit usage of BundleContext.getService()
    This returns either the highest ranked service of the given class, or null
  2. Explicit usage of BundleContext.getServices()
    This return the complete set of matching services, or null
  3. Callback from a ServiceListener
  4. Using the utility class ServiceTracker

All cases, except the first, allow the client to specify a set of properties that the service must fulfill. These properties are specified using LDAP filters. Zero or more service references can match a given filter.

A typical filter contains a class name and a set of properties. The example below matches a Http service having a "port" property equal to 80.

An LDAP filter string
(&(objectclass=org.osgi.service.http.HttpService)(port=80))

As soon as a ServiceReference is available, the service object can be accessed using a cast:

  HttpService http = (HttpService)bc.getService(sr);

After this, the service object can be accessed as any other java object. Actually, it is a fully normal java object, more exact, it is the same object as the bundle registering the service created.

Releasing services

As soon as the service isn't needed anymore, the client should release the service by calling the BundleContext.ungetService() method.

  bc.ungetService(sr);

All services are automatically released when the client bundles stops. No special service cleanup is needed in BundleActivator.stop().

Note that service should only be released when really unused. Some services may keep a state for each using bundle, and releasing the service will release this state, which may, or may not, be the intention. Each service documentation must be consulted. An example of this is the HttpService, which will remove all servlets and resources from itself when a client releases the HttpService.

Some special words are needed when using service listeners. A listener will get a ServiceEvent.UNREGISTERING event when a service is in the process of being unregistering from the framework.

While in this UNREGISTERING listener, the getService() call should not be expected to return a valid service object. In fact, the expected value is null, even if the spec is a bit vague on this. The OSGi reference implementation does however return null in this case.

Note: It's fully possible for a client to hold on to a service object via a variable, even after the exporting bundle has been stopped. The client shouldn't expect the service to work in this case and this also blocks any garbage collection. Thus, don't forget to null variables holding services when the service is released.

Best practices for accessing OSGi services

OSGi services must always be considered volatile, and may disappear or become unusable at any time.

Suggested practices:

  • Always expect RuntimeException when calling a service
    A service may fail at any time, similar to RMI based code. The recommended exception an unusable service should throw is IllegalStateException This does not mean that a try/catch block should be made on each service call, rather that the code must be prepared to handle such exceptions on a higher level.
  • Use the white-board model
    If possible, construct your code so users of your bundle functionality can participate by registering services, instead of getting services. It's much easier to register a service, than to get it. Thus, if you want to make life easier for clients, go for the white-board model.
  • Use listeners
    ServiceListener and ServiceTracker provide various levels of automation for getting services.
  • Use the declarative ServiceBinder
    The ServiceBinder by Cervantes/Hall provide a framework for cases where it's possible to declare service dependencies in XML.
Consider the bad-styled, but common, code:
Bad code example
01: ServiceReference sr = bc.getServiceReference(HttpService.class.getName()); 02: HttpService http = (HttpService)bc.getService(sr); 03: http.registerServlet(....)
Three things can fail, one for each line!
  1. The ServiceReference can be null if no HttpService is registered, resulting in NullPointerException on line 2.
  2. The http service object cannot be get, due to missing permissions, possible timing issues if the http unregisters between lines 1 and 2, causing NullPointerException on line 3.
  3. The http service may have become unusable, resulting in any RuntimeException subclass, most likely IllegalStateException on line 3.

Additionally, the code above does not handle the case where more than one service is registered and actions should be taken on each of them.

The NPE problems can be naively avoided by adding conditionals:

01: ServiceReference sr  =  bc.getServiceReference(HttpService.class.getName());
02: if(sr != null) {
03:   HttpService http = (HttpService)bc.getService(sr);
04:   if(http != null) {
05:     http.registerServlet(....)
06:   }
07: }

This approach quickly becomes very cumbersome, and also creates an undesirable start order problem, since the HttpService must be available when the code is run.

By using a service listener, the code can avoid the first ServiceReference null problem:

Using a service listener
01: ServiceListener sl = new ServiceListener() { 02: public void ServiceChanged(ServiceEvent ev) { 03: ServiceReference sr = ev.getServiceReference(); 04: switch(ev.getType()) { 05: case ServiceEvent.REGISTERED: 06: { 07: HttpService http = (HttpService)bc.getService(sr); 08: http.registerServlet(...); 09: } 10: break; 11: default: 12: break; 13: } 14: } 15: }; 16: 17: String filter = "(objectclass=" + HttpService.class.getName() + ")"; 18: try { 19: bc.addServiceListener(sl, filter); 20: } catch (InvalidSyntaxException e) { 21: e.printStackTrace(); 22: }

The possible RuntimeException when actually calling the service (line 8) is handled by the framework event delivery code, so if no special handling is needed in the client code, nothing needs to be done.

There's still one problem -- if all HttpServices already had been registered, the listener above would not be called until the HttpServices were restarted. A small trick solves this: Manually construct REGISTERED ServiceEvents and call the listener:

Construct ServiceEvents - contd. from above
18: try { 19: bc.addServiceListener(sl, filter); 20: ServiceReference[] srl = bc.getServiceReferences(null, filter); 21: for(int i = 0; srl != null && i < srl.length; i++) { 22: sl.serviceChanged(new ServiceEvent(ServiceEvent.REGISTRED, 23: srl[i])); 24: } 25: } catch (InvalidSyntaxException e) { 26: e.printStackTrace(); 27: }

Now the number of lines has grown from three to 25+. Which may be OK if this is a one-time operation. But if continuous use of a service is intended, it's easier to use a ServiceTracker:

ServiceTracker example
01: ServiceTracker logTracker = new ServiceTracker(bc, LogService.class.getName(), null); 02: logTracker.open(); 03: ((LogService)logTracker.getService()).doLog(...);

The tracker guarantees to hold all currently available services, but may naturally return null if no services are available. This is often OK, since the code need to be prepared for RuntimeException anyway.

The down-side of this approach is the continuous and annoying usage of casting to get the desired object. Wrapping this in a single utility method can ease usage a bit:

01: ServiceTracker logTracker;
02:
03: void init() {
04:   logTracker = new ServiceTracker(bc, LogService.class.getName(), null);
05: }
06:
07: LogService getLog() {
08:   return (LogService)logTracker.getService();
09: }
10: 
11: void test() {
12:   getLog().doLog(...);
13: }

The white-board model

"Don't call getService(), call registerService() instead!"

Consider the HttpService case. All clients must constantly monitor the framework in some way to add its servlet(s) to the web server. This requires at least the amount of code exemplified above, and even this doesn't completely guard against timing problems.

Additionally, the Http service must provide special methods for adding and removing servlets, and maintain an internal list of added servlets. This adds complexity both to the API and to the internal server code.

This is a very common scenario -- some kind of callbacks/listeners are needed and the server needs to keep track of all available listeners.

The OSGi framework already provides exactly this functionality.

Thus, an alternative and better approach is to let the client register its servlets into the framework, and let the http server use this list instead.

Servlet client
01: class MyServlet extends HttpServlet { 02: ... 03: } 04: 05: HttpServlet servlet = new MyServlet(); 06: Hashtable props = new Hashtable(); 07: props.put("alias", "/servlets/foo"); // desired http alias 08: ServiceRegistration reg = 09: bc.registerService(HttpServlet.class.getName(), servlet, props);

The client needn't do anything more. If the servlet should be removed, it is simply unregistered from the framework.

10: reg.unregister();

The new, improved http server would monitor the framework for all services being HttpServlets, and use the "alias" property to set the alias.

Below is a minimalistic wrapper for the existing http service: (a complete class doing this can be found in the Http Console example code.

HttpService wrapper
void open() { httpTracker = new ServiceTracker(bc, HttpService.class.getName(), null); httpTracker.open(); ServiceListener sl = new ServiceListener() { public void serviceChanged(ServiceEvent ev) { ServiceReference sr = ev.getServiceReference(); switch(ev.getType()) { case ServiceEvent.REGISTERED: { registerServlet(sr); } break; case ServiceEvent.UNREGISTERING: { unregisterServlet(sr); } break; } } }; String filter = "(objectclass=" + HttpServlet.class.getName() + ")"; try { bc.addServiceListener(sl, filter); ServiceReference[] srl = bc.getServiceReferences(null, filter); for(int i = 0; srl != null && i < srl.length; i++) { sl.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, srl[i])); } } catch (InvalidSyntaxException e) { e.printStackTrace(); } } void registerServlet(ServiceReference sr) { HttpServlet servlet = (HttpServlet)bc.getService(sr); String alias = (String)sr.getProperty("alias"); Object[] httplist = httpTracker.getServices(); for(int i = 0; httplist != null && i < httplist.length; i++) { HttpService http = (HttpService)httplist[i]; try { Hashtable props = new Hashtable(); http.registerServlet(alias, servlet, props, null); } catch (Exception e) { e.printStackTrace(); } } } void unregisterServlet(ServiceReference sr) { String alias = (String)sr.getProperty("alias"); Object[] httplist = httpTracker.getServices(); for(int i = 0; httplist != null && i < httplist.length; i++) { HttpService http = (HttpService)httplist[i]; try { http.unregister(alias); } catch (Exception e) { e.printStackTrace(); } bc.ungetService(sr); } }

$Rev: 3482 $, $Author: cl $
knopflerfish-osgi-5.1.0/docs/images/0000755000175000017500000000000012475375714016362 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/images/android_app.png0000644000175000017500000005465112346515440021350 0ustar felixfelixPNG  IHDR} 7 iCCPICC ProfileHǭwXSTZ RBH.5 FH %@PEւEZYlؕE**ʺX&}77s̙3gΝ;۹I& @8OJHLb" \^/22cy 5[-5  9˂|'@3'jR rNF9 qB'& 2˕@rV>/ QAEb {\>乐m E_͔Q\n(EQ\I&w6Lr3 6 yP H͢%NY /4du).BQ#yA=iD?*ʐRZh 3X>=Șęׂ>IE gAb1!C1<lb ΐP2"d*4HeQ8@NcmbE|n@PL*@  A`p- Űl 2CxJ <" tjGsD<?U qO<:nH_[oCWCaů#z3D?Iwa :/#㿯H rv;]ĚN`X+vL?T08olTcXl O4:Ck߬`Ma_G"m^008xq?~g(e8jX+֒BʓotvdT&cR`yv6,G{' ?{~Lř0/} Ӿ˸} wX;O&@~mxr #pPb@"+Y`.X A1X փ l^p4fp A;N ^> BBF SqDo$ GD$ICĈ ,ARن""GSEt!=34TCqꇆ144 A ХJF)2zD_0&fbnTLNJ2ۇ5x zO8g,~<9|wޅt.AiBBpp݄D"I4'ݞHL'!7O;$IdM"Ee6eerMQͩ^j:uzzVIIH]iHiR J]Jh4+6&ݡft_z=^K?MHPS((W*+_U~BQ1USRRrHJ*ELUZzTjCA-B-KDmE$u3@uR30110v025tbm}54giVjdbL3&\<ȼ~=uPMoyםNAN ^/ymgDe-_]\].\z\M\]\oiE]p'/povqOO[ ݞ'OL1᱗kW7;{wק瑯/߷_WR#yX@p@Q@[z`l`E `9'C!a!kBnq87eEs62e /ܵ(c.~$~IR >)BBie˶,ǗpZqŷ"~ѥb/%K?;\ԕm\Vm^M\-^}sϚ]jN\[hݻ3_,_eulCgyxyF7~Vܨ_[&}7ۢx筢o6.Nܞ鎸qFN]QԺݽ왺}o}g/>5כr;##EHaCgcbcУ-MMG~mgas1cS/=>xDISihw:3ϴ ;{\йΟuţ.5\v\zwߏ_q1U\;wsI7:n޼}kdy}7 >({_y+Q{y_>}{SӲgj;>o i1EKˁ?ze%u|SVwߵG?|~CG폻>}:9󳁙_H_ʿZ~m`ࠄ+*hj*ov¼%*F s C؅;fXM!S~͏h.NCh0 || M_adPN&/Dxߪ"m% ̍ n`w pHYs%%IR$tIME  ٓ>X IDATxy\gfwF@ASD<<,,MK-.3-3ov]eޚ- 8T\vwvf>?FM^?^e]f~>χ'5Nkժޮ];јA``lv|I)j-Z c/{5OIII׮]kժ5vآ";ӢEpOOO777OOψM/Lj???FC)--8.,,,--MQB{pppqq:`0\mr`e>FNU"!0)kWoyu]B•>!޵M\w8n޽W\U3g(:DDDQJvq.]:n8Yok9k9BO'n(# O^Li/^UBAbf:.L|z;66666裏{> 8Ƽeôz?愘r9|^s1=&Z !hcL !smx9z~-ִ+i !Z(_j3Ha鑿&\2Sӗv6`H!g>/yIo=h c_ǜ{}Qw4iͧlQBZ쥤3GҽM*J⛃h.ظzwE\~ߒruCw\]x:]߲8ìϗS1-3Ro3sw*1@M/7̃QvZ rwTs<#pƱK r5 Vx!?v5=Iߠi秛O؏r%mqj6mڤJdZEQ eYe?[wU$۷m۶Whhb:t(۶mٳZbEQ"8p>#L6mĈU, IҀ6os-YD!?a- 4hEʨjyykܸ3gΝqܦM:tPXX/B2gΜ|؊+իw.]I'Nd2qWp@%]BHaaaOOOy溺ZJ._1_PJM&Ӻu(ǭ^2Eٳ /н{wJ($lb;dY.)))))QEGEY-Kqq$I6iii111OdZEQtWGlO>W^ nǩ֭[JO\rytժԇ8^neG |'&M~+))IQKQwGI);w:Jp_5!K._}!cǎCw[o曛6mrqqq$QJET[RJ333=<<l4EQl׮]V<==ׯ_2bYnzǕ/WwHs-]x~)((hȐ!oرc^^^=!_U|'G͟?bܼ7VaÆ͛oݺ.i4ӧOj*..NQMfddS-4ld2<óF̙3՞gIAg֭{7sI&}ᇃƯTv4h?b 6Bv/B~Bd7n!k׮]t!=z>>u:ٳ6m|Ç[?5k֤ɓ'wM- h4ӦM9rV'OLNN^lٚ5kBCC}̙݊3 8~\pnQ֬Y3cƌӧBMS~͚5n?!!A흓ӦM~#a,k4(((OIIIOO'PJSRR.^xʕ~錱ݻ_pAf͚-\?P'N8N8pO?tjc))))+)))9~8=z4;;{呑;v5 ./ҥK 2PzD>>>/NOS}ݾ}ʕ+G(۹s}ٕ+WB#G6mڜ?ޱ{Y=WIΝKyE)ٙz0qw;t~Ԡ&M{{~w޻v"<~zoo\y~G#8{T:Rzۢ{UtQw^_޹sSN5h@^_vFiԨ˗ !G^hї_~k~\& զ:;qDllz;88sڵ={Ç !sussHHH_1*.T_߽ >>>Fu}ݺu [5]R|U(TwՅsZ@nWE)t{󼫫<7Ca(ʘ#E.4K ?[w郣P9hbb"@%w @%ݿLT-REQ\Lŵ+{..@A00ƐHd%\wPwu:DVN_=j$URN'"vu:cLvor+WPJy?~VZve<2--M->w܂ *RzaÆ9+59sXV=$%%%UW/T˺{s7q+W8ns!''wRqR,(;ͱOn[:pRr֭qqqǪ5̱FO322x߾}+\]]՞wsܹ`0$''KF/[ny[?1x3fhZ.5?]DV(2)IRN9L&YO:)e.\\Μ93o޼M6iZΟ??իWkZ׬Y`cǎ;w?uZ/\oڴISSSu֥B _W29KLL?sEQ֮]`?C- ,՗uֳgϾj˖-3 /vr/_8niiiVZb`Xddڱcnw|I^^z.^`ÇV"1_Z $%wވ#GftwرN:Æ ;v^WNzzٳ'Mjժzk„ ٳg uÇ{5jɓZ+WM6q ._^}͞=uܸqlV_ZO:oVm۶ō3棏>y_x77S qƄ1c̞=;++O> 0@eO׏1bܸq۷o߹sgddd޽)ܽ{V}뭷Zl裏>\<1c|YYY!/YMUoUppŋ:ԭ[;wq޽.\ؼysQQdRo߾z}ݻw߇1z]vHԻw#Fԯ_?$$ʕ+jZlY~~ծZA ^߽{Q|||{[:wl6jgU_v:2kذak4h /m6oooBt8nÆ ֭S%++KѣG[[*Һu 69rT{߿G1]G"ɌD"K%n?+WѣG?nټy5j԰a֬Yʜ.ӳ"S1OӦMSgՇ˲ܯ_Yf=3...rhO>+FZboLQg}vڴi=zp<̙JÔxtA$%wn衇RSS6mJnݺbtw~x͚5|v?DGGyo;w8.///%% ŋ-K^/_裏:TBHv8u2ŏҶmۍ7LkFFFZVFm۶oO>e>(2p-[:tHBwH+٢w={SO9e9-- )H3#ț6mڭWV`YԩӬY3OO޽{o-Z T%44VZ-ZZh1l0ئMիW{yyM}n$iSLYd$IV~9s1յo߾ݺu+.ޕJH$߅Rwmo߾_~ zN<sV1FѿBnWrTgvT2 |4C  !QQQ_cV;qD_|ݾ}{e;jLs禤 gzyy)hl6hy>11N*"A$Ih4xu"-:th.]4ib2~mY[n]XXؠAL;jjɒ%YYY!(:t̙1ހ~H$V0Od lѨl6:JӕhZJ)j AԑVEEE`0v_D 5]W8QZ-6JL$I}lvXY]R`p,@utV?$I0o]a"1$D"w4$un~~~%V!*|~Pwj Y"uʙX1CCCE9$xȚ&?lEQ*^>jxWH]$#(E9D"H$:fjh5:3K_}W8sww4T@'Zr* ۊT;Pmn8Ewr|H$@e˭.4//2E'nnnx]w[ ߫wRݻtеݕ8HdKt:.gLNIY0rrުhB4}]]vi[Rf֭zVXDV*j]fͫ:o޼K.裂T~qJibbbϞ=ccc;vh N:jԨĤ$~Ō믃׷o_'y̙6hԩ&MYtرcZ]Q\|ҥK^qUHB"U65:"Ųy - IDAT&,[_~Ǐ[n |̙3fX,Iz!77uVY5Mttt~u˗ !AAAf\ꍕ+WwȐ!z^EB,?5kzݻwoBH@@!$--۱!H$N":ZΝ۷o zGʜnڴi\\܈#G$1JrWI;hx !eP͸mu2##c֭(/bTTzVU-Zvʔ)O/֭[v;DNu,tRv󗮮7oH$Be0gΜT^o4Ϟ=(Vl<'&&ɓhZYX*8++VܮoV+IBHÆ ޽> $Y'uoܩSƍL3g*QXXX~}&Ooh"**3331 bwyg…νwvn96TW$tO>ܹsΝK9{lFԳUSPPPM&S lWWWAR^[ZZhm6`P7$ͭ1EFiih} ;q cƌٳgCBB ޯjL裏2u{ w;%&Cְqjܝt|j/ڶmO?~ٲejX'N/^8RzduSN?d2z2=gFDVFQ.]Ts7qď?XeJ-[lْc]x_~1+~T~qJibb-[>WFFFddZJ۷ooX~siڏ?wtoO?4~_xqСiiie~ GFb\&UqoXlٲ{ӧ_~ܹs۵kuVTUaqW~CΘ11hѢ~_ꫯZj]`#^{9s 8p=z믊۷l69snݺF9s̚5cǎk׮PŽuDH$_.߹s;hY*b}}}-mwc"##GBZ;EQLJJСC ͛70`O?tΝ;l6U)"I̓1 иZ/322l"ǏxbVܦtyL[̞{ vl6k.!!a޽ٳ]bbb RfT?հ ;t@".T[E9s椦zxY///EQʜ&Ȳ\~dwwwO8~Wl6(b׮]7nܨnp9B( ]]],YҩS'Q}||իf͚CFDD\x1""xo{|H$E*Qw7sLEQ,KQo3ƞ}#G4o޼cǎ-ZP7hժUQQQPP ӧO k۶m֭m6(SLEI& 4b,D&r~<_ڳg-#0vcN%^-KNՏrtUJE]NG%tGP -c$@imUfP' %N/?«=~ O )6Frh2B| 8$㪠JwMz>55UEBj۶mXdIј(yyy!!!mݺyA oUW[{:YM\dJHYʲ?Dxi !{lEvvWǘB9[`eڻ[Kkϛ%BDQ/VhWkfYƋj!d D%]{5ӪlXgM=[MFoh\aUY|<ׅ=z"dZ\xBظF-̴ߜ7#rYfݪ3D7ie۶m5kk׮FuaM4ٰaC=6l0eʔ-PkҤ^yfEDD{9sf@@{dddTTic7޻wopp7!q8qVmҤIƍ^aF7qdZՅkvgZiگXd)=]  l8Nhr)!^w~,x'h9-0F(g K /I.6[-<#gu /I. zޠX:zWSJk;_[>BR+2 )}tSK%7aپ0z :E"U;(o@SE-ݻرC]c|(e9͹w\n~SeXm0\(Vdس9)"p0v`|V~ G )j ȌLkLƆ)HdL :[lem8o%U\JQ?ti ..:E".H$Hj],uBZm6[JJ퍣4mJ qe8#8J)!7rWq׬BR+ +ٿ~a-r'G+"3D"Wr蜞>w\z͈#82͔Ҭ,[ 8n޼yO<3<|fΜyW$&&:c tdoI2K,ȉEvv̳Ok,{ wؾ- Iw }&)%d[#?rll.w 饃~?TfNGnT~ܗbRw }9K΢B}b_jCjg3rD(6`}.k)G{_"ќln>g E>-2opΛq^yy3V:3ӄe˖=zRPYV) .Yn]TT԰ag_G=88αNT28F;?38"Ԯ\3J9]\,^9l.~2-K.k:7?ׅwTuDJ6o~V g:~RsDyJ?kݻ"__sRSwHsu,&ʹK96$~=(~,b.~d[J$G3TQQCG}U˄\;D)!ߗX)>T][&+&Qqn9op}{JRמ+*'z{Zߏ=zŽ{M0YfEEE6lp =3 .l'O|뭷6l(JTTTll… O>o 0`ӦMт teǎ{7BBBvҥK{NHHxW7nVRW?2hɦ$:D׏>nEPӫc&7Kn!uԔgSrl򘆮FGh劇Ց6f滋q̔mUl\gpSxxAElA7 zU<ɓ>z`04k֬{>`n222ڵkȲ`N7yK.c=2zI)8qC(ӧO߳gh|>S0`ҥѾф:Ccuo4pk1_m0]cD{RR.zfZqnl;j9"+SǏq{p{F VQ)Bɴʭt]s]I-Y9Z"6=Go8ڲIn!дRj+#0sri%2*1wˮ|帑&+:;fR`]5w-W")7UR\4ܱXKsʾ\L4ټ{m+F r;̶\*}BR*)>o:kW' ~K#,}VBdO J|ts<5{j[wc ̈́ۿ/n߾Y4h^y͖;ζ~#FWޅ ͛GozݠABHnoZՍKJJ!| !~m^6l(IR^Ν;ŋ?-[\vs=uꔧdh43gΜ;wce{L$iyK9?/K9fR\ޙBqzsBo6sO*&5vcQBfY'9gfWoޟhl"+׋Cyhń˥򇭽 !N uoszބ^lCK(kB)76ĭVYwY<Ӯ;{"ԃ0e{^1Y=I3>rMCJ-=˖dƻQ[Ϡ?1O7A=j{ڴkǓ c4rӎڟCyW7[0%>PC0?M#7sJzposL2!TzdEs/[r$}A{nNʓbBkgs=y!_e'qKEQ:6ѣGLL( }RG#*o8,e6Sn\-Û _f3ݼ$&Z5Zn**TPiԃ\<BY)ēB!Ps*H@-v[%\PV*b<{XZJĭ6|?cx~3?yM}WOOyƇ_1GLm|8* h4Ywj,I w8fՕPs5S\wN8cԩky2`h~=񹱳`DI${"3Zȍ"$)9D"]"xr%"N@ Pwu.9O' /zRh`BD"hD 劋zlͭϟO&,~Yhnw(&x}ѣG^ \|'E{AX,7nX]]ω~SShhhb+++,'St%YYY s,%%%.\HdUUgff0gss[vr8Fŋ~ɓ'~lZn8w˗/斖v~.@ b988|zmOMMmookcccPhzz: Bjt:|>F3,IܠTU}uY )"˲jzy:_!hy‚v;w3mJ@IIdO|!DKKٳg;G!,++MիW@*nt:]_p޽{_QQ6F7)@nݺחwH>|XXXxErW2z( PwHRo߾vZmz ^~OxΌ^oFMS[o& ͙3gr=~8ivs`_XX~&)3:@?~/n$E"a߯+Wttt7$ Mo+Sl6j(ʻw~D&ωrw:RUUِ$;2:??0ȾIENDB`knopflerfish-osgi-5.1.0/docs/images/mem_256.gif0000644000175000017500000001662312346515440020220 0ustar felixfelixGIF89a7Z86| ccc ))77%%##66HHZZDDVVggwwhhuu '%-,1/86?=$$++44;;   $$--##22>>22NJCAXUAAHHDDKKWVSS\\b_dbcchgkkqovu}ut{{AAJJRR\\ccllaajjss{{tt{{ 3$+=3;&39DNBJS\whclwHZckgks{| «óĻȷɾø, H!\pa>~ #FOŅ.j,qǎ52’HqE.Œp&M#o<ʞ[5hshQG{sN;vaU>R]&LR X#{$ z\ iTQ3@յ "H;BA픒d ޡ,'J-cD;zd1@MAC?&P?ȼpb]P+͹@=?Lcq{R?:ʎ Pc^we@dY?@DX c@sA g_I@,Nt2x^OC ;C͈ C 6Cxx ݆!!JA S= VS+ddgJnԥF]`-$KġvDFeT_^K%jfnV5 ,@=Fڐg5.Ԝ1\,P%ryZ48M1S\ ^}5P?㠣9A|@8)hCCcC^c8d8LjBc[vB6P5kAgJ$@ @`ʷB0 SmDj $NC PnfOh@A'qMRY \n3 L(0jOvMp U #Tj\?jC=怞@%vG~cOXoC[b@xPJubS'Hcc6[-AG݉߉Q #(] g+NtQ A'Y)و41g[pDOvf-T#(MyDggZ҄O{vGEdDBщZ?J :r=qhLD?Ew%quL%6] NC'1=M=T&eTK)LJ)*:Oꤩ%G$ԧ SU^ XC"֍uISLPz^zKVfNJz,kTƺSVP6ԯEBlW٨,u#d/"Y9i*h$ڳ֣hgV˒•lawxv\z\<[:tIs R nERRn`c{U^W.PNjZռot^Ľ))nA[YNW%yVWu ίG\~ox'L GL#%NKLz/<`L8s?L"H&'Nre,*3Vβ.sYƟ]}jx-`w"ެݯYgNg\2cq\g{Nh]Pi G7̦.:FpuiMSxhڶu%߆ڴ}Fܺn#f~%6ɰGSށ H &HR}mNy$|l9G ,^܂>zf̄4]-o3@Xlرw!~6QQ߅Ԡ7k^8vk50 X}f(XO2W9S~''㘡1s={ JA+[#p~WvM^ui7$k&B0oxI3/d8@$v{pw@ 4I<#3{^zobwPg@=ܝQf"5 & .(ذ8 ׭ &@.. Ɏ.c 08N d0+@Mb01@98 N@ ؎ F`7_gpL.`F Z(MҨpn C`2`)2`ҟ 7װp3N cG`::ܐ=THR*cP !N: m\.Yp^ ?;ϳbP8} JTE: 7eQ :b@W=K0^ 9( ]!8}ܽP"nJPc` t -F` *E*@#.0" *F-S`/S<1Cλ_o8-'1$q(W FP#x'#BSq_324X!\LBФ?|Nlg93f:bx_|V)cI-3ΘQkS^ZT~P729m_LG\3kʤi'\.̜qE#CF_ҥM3l^X ɔ~ ;T0#+oղ}Jp4o'x|<X=~ZN6f>d? ƶ,V]|pP3ڴuFdAv:ꠧηMN;~vm㖻mzno槞; pG0xpf5֤+>S%Vxw/{zLId>x>?-AԚ95A*[ߺ/kǜ5&I*#{gH6息a&8/ܠ:"(+߫w x,$R93$SBpZBv9|VU]|T\[)EIу\4bpxLD!'rP0 x+,K*t8گA<>kSY;dF,H$XIf"HPPV(%V m#@G*0 8Y.Oq[l_]16nY\-e-wL%d3(%52ϒ&@hlg lZaRjPI%9Cg?O}#%hAxT ;PD)zQ^tH{ڳv "cx@ "̄pSθ^j"DXAOM@Lu.Yc KZZ 0-VäR=p@zϞ Sr7 xumQA4H_Tl$4@LTHfOх"FON-5=5%u@dftEӃf/I\rwJz՘ؔ(P2}iG9dҕui/]gIƒ%WRU_nA@[`\mLgrxj%֭{=Qgg%T䚑y)2p\o!W ϵU2iWUa࣫AP!+Ri-!tfC4TTR7-Qw>DaZaAEV]!Ձ\EUٗumU,0E;knopflerfish-osgi-5.1.0/docs/images/desktop_info_manifest_200.png0000644000175000017500000003635112346515440024020 0ustar felixfelixPNG  IHDRhRtEXtCreation Time tIME $ pHYsttk$d$[DDI$ūy5ȶiٱcb, Q]]UWޫ." Ss$IY"T*\&b5(]lR;!I{YQ˲b*Bx"$S{I*~_ܶ|9%2# :GR2r%bTiJb*+et&<E1$Ly*7@M"I$AP-gQCg2# $|Ve5QW˗KVDTpQj#}>,NF^!he)12,%ch%(ҕl z ƦI5Dqj"ttҤg!L$ Fñd@Y 3v˗t6{0GfԔ#8} PeNjB*M"р f`t&1Bd<55o.S()I:N&*R0Z6.XI{"!3B+x[1=R BIY5liil̎74GqJMs&`(TSnX+OS*9"fѨ M]ܴiGÂ4'd(jg&Q! s4cBD&+b%YMZBrN\[ŭ-#= Eo{soap5MDuyco_?Τ;; \q'+O.++Glmmf嶿צ/z#MJ>ϛd~C۬iPzt԰{btۿ=<԰w>wO)ў˫WR˲H477+Jc/O VUToXWݱX^ǚio[uCPz\%ʶ)ZtHQn٭6u|vX X, &.477׃@dL˗/wtt|gUTaYDpBYYk2{AT^cllg [\sĨ3˗\(g5l\ $f|XZ[W`zϗ H!IfѽԫV̖Nklt~ÿo߾?S~ڵV¨vC2`zunFՊݰs+Nܽ/gg,Lbw!M[%TV?)9"ђ?(+/[lnDYV0x%L2Q)u'U媪| J&Q sUׅSQ-'oTK D EEB4=ʏp Z]d:JJCF2Yv:xR6ʲDRD6m!Z]d΋X 1;#f]Ukŧt0Avlڶ܏7{ucs>ǟO0RJ\I5wl2p—fhҰtO.6ded՝}eJ*1Ek#F_%:.[6 ]~;:~fRx䉵wVYM{3?{gjKq?m8˒*Ïؾh1[D}}=]]]/́X,hD$d2z<V O$ B۶mr6m֯_A{챞,ItZCI,*SϮ;@ZxGLVdrj3k6PE Zi&+7,Ud($&; GliUjCckc狍+Y)t|imhL)qwKyCJ-g[{oc+++TW?tl67n=zܹs7oPٳ---NUU(:/_FOj5p7|z=E4|@ck2RaԘ[7j)K[UKٳn7@QMX|GUu ϓ`?W,?}l6#bޮ׫o#fS 6=#fHuUY*# Ew$ds}EMb6R74Zn' F٩xXɤ&5Z!ڵkr1 mGX],ˢ499 %IP8Fj]`8.F!V7 Y!.oׄISO kT/Z<ȹ1RFB;a5=d"-hE*Y~ [_5P4-g ~'{wС7UK# |b#&%2iM G1"" ;" bMݟw_(sXUuCC z~cǎcǎ-ͦ3anԏ޽W^\4;]c>Uzvm5Uvjq(n7zk5zqcV&F`"Usm*ЬVO?/i?B9U Vr/,xF/^?:",//Wr@ =<6ġ2saŊ(nw1ma֭[K% 54l(\,|1rׯ/1>ˋ=rvvvQ\xx<\ oSzAתUag @%xr/\ LÇ!QnynV7@>S9+ފN1EdGO|B1󚛛Hߕ4AOL ^o&8N?;;ci4Z9N7O9;MrxݗJ1f(@>ڎ.ÁdHCvc$ࡢ3XRqyG<q!DX i"ɣ ذaCm:-X څLƍ : }TDx)u}|hG}^~SNa`/Z 妧8[zݭw+4rՇԬ|1y}P} Ϲs={0͟X۷ *m3PҘeeeK@VG [0ߺu_pΝ{%$LBĆ] eS]yNwb\D#|QB[DGlٲ㇖ X,̃-߁e2l:(j/ԁjfLSEpW_AaQ6hrTp+;@SecuOIJQ+FrV/ͶZ% 0;Jb0iDw_pK1-A. 9G_\xѣ%la xwӔ>l 1㡇ڴi=jUXtZ:**[BBxXL+_K͛7+g(+[f>As+mS^qa_EYèJ% A+raXꉑVnK}UL UWĵY|gʣ|UQEmBQ,E;R 1j4IӉɉ[&q&'s4&ǐeIr>9ɤDsbF\ *JM7٫6j5*^!9<^}}^xfA4ۗyB$ \J)1Bۘ{OVᔈ(~:zڕC4VE|(&xcg\t?Ac%owg_,dV !hGq,yWbR_ W>_ûOLV78N_v?zɼ-)ZRFB 'L iT*U5x;*=_ӍwIXe,ﭷR*X$+A8&F?x j=SqĽ+4W^YwoNXQ _G9uiY[0jBɋ3mG">UjJ.1ElMk $V<<@oQ @w>6X﬽E LۋFvtxGОW__hQ"pQQQgϞ! PTq)(7Y`SÔ/; /\@Ff$d2S Z ӑrI[M#R1/\Q}B$kggK-I5S$=aاɪt0\WWwlid`׮]P7yǩO<'Λt/}$-(or={^&vVUu;XO>Se` 15 ?X(O`vۃu+BϏ1LhI_. )v;2Xj+g_S?>?!R\5>Omlii)//ɡ\};vB` C GtaPc"#4=";vRE%0ɉYAAACCC111իWf3gΐĐGyVӑRPr Bz&ߤj4fS,755-]+^ /_q&11>4X&EFF0<'BB"qꚚG}a3666$$Q4:n7 pxH$qeWw'9m>lѢǡRV'V7ߟחyw Y|@Lzm )ѕNn9Ov Z!W#d:DRyL{،K.mذˮ[KKK284ډdGzL롱Dd`x C3ɐS5ý>L&Ç92Qu4Wf_eL,5ˌV\&<\? /880AFFFQQQRRRkk+@I"h x"::6oތg>IO}I*oAAADD1pi*9 /'{zQ`>LTZoNeGIF`Յ%gTtk<N܂6}a$,==m N)(x"y0(< T<J"scP-VHυL=4aNpj %BU (9h` ]6z?D[WxI ; Fp;+L `xfPQ`(. M*MC ϊg(~'PJh]غu+z$@Fn`@e`d7nH/+;N  `UTTོP4rE0]•jti_'&;@?j"H@͊*2KW΍NOHP4'09##DQM  ùDw} 1| 0?Y_@̯r+Yz5 h D"'ġ` 0ZXs\_5 J1U9AP ۨbt'h" lt( W $3Gꕱ1Tf~gȥIxJxC; X  s pk֬AL8x @P9+aQXX3''g``Aɖ-[u] d^`X50Lh!vps5Xe-Cܖ;M@JD9C ό[mvWʳSC~ŒJjCƢVkYM82WwT,vpA9K|9ϟ:Fl5F] pKCC壛!5111EEE2 W"GЇ;Ɔa&Ӄ`7p@ Q?YB$<#뢆+LNiGJFŊ@*F*{Jמy~/ "q;*€PUpX)BÎ-w_ QbU_~@L>s,Q=2a|$ R9<P[KM[L"K!݅S"?R箴h @Cic#806,NVChP(ZO܋{|, xlAw0F&M;GuwNKRtZp 赼}!j/,& @04h55C=T-[tfЪķkgO>)((x7'2 BBr{` ##,n79|@GgQ:NL~}ΝۓP@!3Ǥ8,fN i1.0,Fߟ v s =|ܫ oj#t&{|}Yy[_cm6Ȧ)aSSK"*+{ ={ȴ؀Cg/33%ږ*C+D.;d߭曊D"ċw] )> nz;+" T- "ޔMtx䗵1䅓 ao3 D܇qJl{;& P EEE$ acccTTtUTT,Xpp}tt4N \i&2{'S:&xvD%11QM-p*0DuVT*,K<h4 R`jmmrt͸!$$1#^"Ѐ_qd2GFFP %d6%yxPQG vZDDDuu5^cj/sqӉ h6,+ O.^eeeQ\PGCCFF:c);&4Oĵ-Xq,Mf$d2mڸ\dOBaau(/oE4 xU `FM-F$@9Y-pp8$z'icvI"16na/\׻IW°2?V#|r/3icky{ N5eIOOw $r|8/քg$~-矣_Ȼ{4 ?L2wLvpIIIhx*3gΠE( C]v!N<"/?ׇ)q-GЦT*46lbGUdǛ*'x:('N|p YUUСݻwh}`fX/vg'O ߛBˁThXlEp1Xp (rLM,P~|ɯ#AFn0xa-۷uVV[[+96R0j@+"J{=U\ۘ '[/NI۵Z-4u]0 Õ[l4␥l){4vtt"BF<Hz|}e?j6[mp;w,//lPXҧV}w^46:cX$FǂBPkJCsпb 4!JB6X Rf ŀΣrrr<_N q,2bF[@[IJ}Y]DZ(oIi߯sC@Aᢘunn.n5PCU0޸^s-pL$Yr4yN%3Y䎥&7W{iq `&[k37wK/I)Q"mRW*#GRۍ.`)(mOZ i mRԀcڲ!ő*IQ|X]g4%R|,Eіڝsߜ{Ν; !`Z`'̚0 !v"? /PťK4h?+>$8@4&q>*/ ƙ +y6R9x9tYYX`^nC&QYSSEpAa߁A {|m\v3g?o߾՟صkp,oM^Z(12*}P믿k:CMOOCZuyw b:؅sĽfp ݫ6W/nT O?x (fAf_~C}G}ꫯko6a`~`/"ܢ`-T _w/%M: o3!2qO^=S0ʊʓtn]$$A:BD'Y*Tɘ"S3f!> g;s^n,DmdžSxB* $)6EIHD;*.J=Mű6|Qn;iPB|g寔% c<%8?C3!a@JEId9DGEI:Yd,*g"4ssvOXrqIPH!2 䪰HdOVT34RYDF]Y~3db_ `B_8j(X2t6&%}pO ^#fD)BYYCAX9xDLS$,Dbebehf419Kssit 2̀oxMI?W}O4y.7 Fc;[v?676@8RX`\I$Ro`FJE*BVt|>0-7J[m绬|R,V}dRDVT",ZXN{Ob)2F#EBOWg%s??w^K浂}c?;K:ONCr$s:a퐤HJfR:fsȩ^d*Kg0L!2.̗ǒjeb/,#-ٌ_U坥YRj?~R4ΞxŖ|tB߼bdCŸ׏s#5_^۾1h_/*4˚GXqa!MLl-+%E}n-koiuc+Rǧ2hL&fSZOc6 RUUx߳HDWNJmֶkWL+g2?WZoUY.z"じ_tJZ 㚢(9r~9$=%"IM&?,JK*20`:EIL  9^__W]]50006{%rF"W#KaAB~P+(0X,il)44zXc[Zp g\C3dJDQr**,E;Ĕb1t R8:ǂiOK֒jIQn. cǎ-fHolo٬ w hl6Q O>9w/fȗH$D"  ji|!dr:]6[+۳ipp_F`0w;5D$;+ hb]NG̸}!&ZZ\jd?`4,`8 j-}{̙sanqk U`T$ #Al0Q\ӛ7{ZMWW7lP(ߜB0|~)--T* lĘ˽9ۇc1L~ǕH$ao%d8p84dž`TƗA]^7fOB /d''[[? wܔ{|" ظv$c02^rD"=' ;K͝(g*FX Ax^>ƘoG ͬ7OT.GB)wed=CprzD&0d P< t:ԃMV__t@ZU•+m@hP=pH$CZٳP8,M(}5]6:ihh$20!PYiB?~`C[Z.!`XBsj認`^Ë6˻6lb !`񉉋:d᱗lqkjUSt۷(@ H$t:ý0VM&cMM1 ns8(V!h1.z_f3vr @H$ڹǾީ5޽OCKWH$j6)h4ZWW0Y,fWRbh L٩)LLL D"rw}uR}KU]M&=|CKR9"vav  ;^GQbeew*citF\.Ϡl?֎lo@T}Ŗ~H$‹tP_SZҀ=`6/0opf =ڀ4 ^b 4fށrpk%. t<КkW|e~yJjqgK"CJ!_.`C K@ KD2j|d2Wu=6bwp+[˴`^N$P,72r6,,h:)/D4:d1kFc}Wf#|o]}r.,4>d#=近0/^ .**s-p6Oztwzܼo . ?Ge4`NK$do~sŋWvnp"~Tbuu5u`KZuf/rG GQb>o c&wڡTgn&MS:F,֢D"iwI e^̗D-Zfz:* fD#Vcu .$E!.Bx#Sjy IrQO2KĖYr#PCCcMb8K,<# $($2O: 4wD}˭2<[DZ[޵^hzU] /O XIENDB`knopflerfish-osgi-5.1.0/docs/images/knopfleri.jpg0000644000175000017500000000640312346515440021045 0ustar felixfelixJFIFHHC   &-(0/,(,+28H=25D6+,>U?DJLPQP0F18Kk^J;'_Bb?Һ J!=CsʛJR((BԢIϕeHPGRkԯ{ƴ^;FTd7+m ~kMBZVgN*>4IoƄ}WگVKP[;P6{ڰK++ԯL:dr++e j\<&}ˁvWv̀7{̽{tyOd`H̝dQEG ׿7j̡Ys@`o[yFG 2 YI`B?:I1eU[f+xr|3P%J;mNS4v+lQ#SÖ&MH$ep9rN;ڮmn4K!$c?:͋++T0HJʔMqnɭjW +t_ji %bXIZjm$Q4Ѣw>$pہ$2OΪJە"@F?׊9bԫD4`>5 [/Fs*'캍*(yd1O^JRh[XLf&9uUҬo*%ۂ# >g\Y..KIS7`vQӚ &gYny0g\k[E驉&eXϧ9RCt(,6c:{[cf-H- ('<~|V)8)U2AHʩW:_%P2\3=3gz}[{K}:gZo/,`V[˫uR0~\-zAr &[hb-P{`A|l{{rL!k-Yi/6Gfh'~>$~F6ҷ\[rH cp?Vi{Z,݉Fݬ"ɴ*AǕdFSnYu~-wDlI+qvmU>UB ,|q)<AbɌy'*7FBPbPYA̔}DI<4y)s[ /u/)sQzJi~Lb\Q̑;z(@` ݿEb (>},$nj34VF3#<ɪ[}.ٮdF)c˻:LGS?QV n`W(C[bIaHI3!a,j g*M" kR> 5$1'v+c51u]u4i,l3p# nh`''Φiz&lWD.#&Y;2O g*I@Q B:OA~Iyp[X˩}@:sP.Ke2N̾jNV/[\WO8 #1>pWRlTIo\v27;`}? l>گæԵ{(3;*9ҹfZL"CX=Э-9SĔ}[oG"bqkazLMגw[=3>d|'^|\_u5jϘ[MA9џGK2Z`dz欈tmBg|̒~ R(5I 9_ⱂ rb{[AKj(^ $G 0dƧ q[["m-N]>}B2w>hW,P٥휛Wu2lR8 <ʨe0X 5qVc8P4Ooqoorѩ;'9jQdaӘ;® b7w2w'VmaKeH\w:#gi^§7=zeS? *IiSVDcEE`VT!JRJRJRJRJRZ.!i #Dã/}(9`B mԖvJkڨe (i̦r]2خwhjvpBw۝+ d6d=wtY|#77cwowW" , ޛߕ ^xރ[~᫫ 8䐓~떯`寫]ަ +9 o|N *} g=ڇ}߯P>}ݣϾ胟=Aן_־|_ǽ5|{罙o `>IL'@/ ç } ]A cta)0$&QL|&RQ)[bD2qeĢ(~UHG3QV]:汎}"@1N$H)sc$*r$19GJѓOר"qihDY0+T딮PkViJ(Ee, bė2s`7 jZ̦6nJ374)NrzL50jjl8iiFT'7i~ӝڌg=YN{v'@ Ok6thCyЇr3B7 QshD/ @ҖzSdKgOӡNq:RVSEs*Ӂt/ŧQ"#g;ϩ;jTs 8(Jֲ*6`0TU0mLJWlTxŪHjϺ~3| ,TSJ^RiѽvaWuu6(@*@AhA+Z*&J[kL lkjS,hTq [Ƶ-6 KܩH_K\W.p+ٹ*֣`l~+ AKf^mi|̷sݚtRUg3@Xj<2}o%K5e)F 2^ Cؾ&mj.nicRzV p5 ,f+L"HN&;PL*[Xβ|e*@5cX%D}Ռ6Yks99v3#|9xBzmhE7:|N4-iFW~47=N[Ӄִ1MK6V@,MV8Z7@c¸5뚢׹6\jV *Pba'4u_ifW#;̯V6iV<7nת{ݺ.w5@z.qr}Էn>5^ݏ-jB֡:i>~6qW@֪,kx\_xN)r4))W񗻜͹w GlO;Ums6-b ?TWnLJH:Óۛ*`ߩquR%;ַmf;l`r@j]fe>aZIO|u;folWvc]]N*v)@ ּzַ~/؎x7Ry^7Mշ慎OU6X^5OW\(@ @~00Hc^ eU*͕riwy6TX]ٵy۵MU50X6@6p7p+Vgmw\[_'x3_×g{x|sYgq|v'zO?yTRXFzfi!|v]5vuz7QPvWgk-v'r}^}57pS8jW8Uz'ܵrxMLVZM>er6ceMHaMa%{zfLwnEv  `ZNhE#bXx}ȁ؉?nȋmo(Hf}\ʸ،8OHϔf6jihXjhhḎxhxߨXx6@h%xȋxhXhh6ƐOi_~`# ŸL_uR1넅'7Tr5xõ07{(wqh1Irk lyrē򕅄HWX2gBMAh v/4+\]w_ox6(vZWuq\v)p̥AyvSWvrYY5m)I8PwWux4~((V'kgY4XyzE9~@%v]a(薀ؘFrYӧ,uRWeP͹Ƀ ɕPˉi-lՉtHZEy v!y%ɉΙfu_Us9z=UǚS7YLJיalhdBv80ٖ3VI$ vYyחx)8WY}|wXwIs逦Xş2NV|YgiuXXy9BU"t\lO͗8yTqX}c*kY1i^k``Pn:q1֔ɇ陾_Fڒ駫ȤNgVT,٧o+Va 8AZzXV@ f fث؏(HȺMڬ*i zj fqz&kZ') V J`8 ljsp ڭRʯ j;o9Z8iVGqjbڕ w1RʮK=&irY9aE'sa1]ۮ*:4vIyWWIE>I!ŗ6K5H LUP;WYت:E+?w9%(}IX,8wQ7:'Y]Yy8Z/p;,˩k T[KtGG9swX':뷫{|P:r˹Rj'tڃ$;v*؆yU"ˀk 8ۻx[\5[Dk ظ*W}{⛾@x]x-r[Icy+ڲˉ:K__WNYg;G:eP;9{ vJf(^[\>xaT2z;[y)&! _~)*)Y/=ɱI,LJ[roWlYlz|~djܭдŊȌLȐ:lȑ|gɔ\gL*aLClHJܐ kʧLkFkìsK\5I+f8| v5ZX<霿E]EN{q[&^{T?HxQˢj -{1TEHϭ(z [$m}! "LEvțW{x6J[V"LQKk 9kn`RHh]h +o@9N5]7ʸ?cfMl[!ǥm d -5Y+=<|Dn, ՗|[+X׺,Ǽ{tKɌsjׄlE z,yނ,ʇ=\ɘ }fiilܸ ]r),\rݑq,ѢL.ʫom.ݕ@9J\3ۛ'[|Z iM~͓_/m#({+,.u<:W^8/>sy0p9%m+ݴf«#Ԧ9x,xYH6=3--=wx3=ԝκ/~7m]䈽MU}Wێ #0NԞnr=]ۿ;}\l 7x-A<{Z7i Rw.xLڢz©wL shMr){.lUG]Dʶ.Z <%ѵo fnH>S-<1.~:Ƙ~oNM!#<>@ߪ/}mHGϏIPox}$~%~Xn_gC-7B}ްN0\3[nj--oΞ9G}o -f76[~nMЀ/`%=怽(ϴr^ڌi;lpgͭ>N+w$-Є[ن>ו~}A6,}p [|v)πXoԚ u`A \+p$ȠAC0Px6|XI)U А0"|PJ([ʼِ&͜A|L.IyRF.mSLPuڜ*+UV*d8T @b0U]9wl_y&kM;㛁%f pUY3*M?+'D1f #&՗}wBӵkO*V9G'AN5fׁ.>'tvCΜZ+䆺 pcp@l :pA *AOh2ڨbpC7<0=$CKP%K/ŕNTTs .`OEA1s XR0  YУ6I(rJ*J,rK.K0sL24L4,3b>lAN< S;̳?O=u AtQD=B%TF+K5tRI1O3EtSOKTPMmTTEu5TXq057[p.ٌ RW5_1ء$?gvaZŶY]2\-P\%!_-ܳؕYߤJ]ftqrQ3vʫM=}3{5FIbp6^[ iWac?V_ ^:F+kbַ:%9fu2}ضx;z&E 7N+.(kЊ;O/$1׆%1ݼ6RJljJ4*i6pֺo+2_Z֛僳F 禿 6 5_i:nΣZp|s؟3p]Фc1Mw/Z׆cɍ0$>xriMǝyAF/:.#q5绽gu}&u=|wwc~gz_LɎzLCќ<,!|0 mmǯ`MKZx=9W'iHg@I3 Bq}ʠŭGl@(ZW3b @ Nbp..Z. bv!_CTV3F옋pG:bb&@R$d! yHD&R\b[9ŪUL$ŪJfU&7iIPj2R$%?*ORd RJRR{O$}3g }-tOèF?ICf(XSCSZCzR,0MlbC0&q!fHb==!g¸k]TT {ػE/=K8HrʏЙϙ7kU2vP=êtw̝u Na^fx~ӿC=p<rI(M;D199A'?H*b@ 5*by"!:s!j:˗Y*j1-w z`YlSsΨc3d[Bs6 @ ਕ{n+AC#* æ/tCq#*Z7˙[7b-;,bDA5$;BΪAb;8/78B \?+DMLBM-KDXWL|aE[D{];⪺k(PQ1䦮E_B΁CVl ,5.\;lžK|>t+>[II J(HH?X$ի\2[]LT`%@D5@SN=V(]HdOERm2tZR,tDۄfKR yTrgt9ٚ:}Zڰ)4 }P՜ў[m#e:CcZuås[t z\ßuRk-)Ƴ=* e;ƍ\6Ze!L8ǻmN9JJtHb#?HimV\+T+2k=]V@L<,\GF Vai3R=_M_JLUZJUW%N_V[Ew];kVF _%VLF]@TfUhue_-}&L r Xuݵ5u̯Eh^I^&[mޝ SWVڸ~Q5Pmd ╢$-ퟺ*3FۺΑj̸?[FtIUcO5dKnb`cq/=VEULiS%y]*D[T[ȥZ5YX=U(.-ENȀ 6.8ea\ 'lգ$4ճ`sLK;6=="6nhaI-^( =iNiF >U}iU2@i7U`=*h?-jfj%SK4VujahnhfIRgO~MT-ތDkEdgפf5l\l!*6eovtd5N]6bQN.~b!ZCnvO0^=5d,[R7tFP 6e mu7Z-# ]tP;%[ RnIpyo.eH&QnnNf^\Nde:!mr4D*A hRwQnMVn&H>ԋ.J%oz{ɡ!>TijYi4Os5_sFBr iߙi;9sWs<G)i0r5+&@gBoK2&,vqLߐ&M;FOkZu=qVWFn=OB3rR/)lQ;^=A<;}4Wl[IiJ(لv*ƹ-!?01)HGuV;pD lQ]^&`OMXgfpV*n[}De2oRPC=-xN^xAۗYو/Eodxm{5mE:'xMMжmmd-s.7F%w4[E$zj\md hiqG|fxG> t! {ܚg؀o"ڶrsf1o'|\t\1t^iafs|?iD}/}?}O}_}؏}Gǁ}}}}~}ן}?/~_~7}o~G~׎~~~~~w}?O_o<(h „ 2l`8dР! (L G&x@Ҥɒ'WD@eK/]œ)SȘ:m&P?o%ҜJ2])T8Y'֡V^ְYj%UlٴdׂG3Z "ѿ&0#V|xcƐ#>;0ƙ!oǢ%lzdhҪOOn]Ԭ_^ @-b̠14i i3]0U8=niٌJ6<⣒?r*r~|Fߟ?}=tWdotم{g \Yf~0}gs:f]Yg"ad0Ş5چ3mH r@ğK'TDo GyXjU}t9ar%'`[efGJfUW~nyߠXv(x˹9rfMIh& y_b(\*ѢhzS EtDeKZyh^ub)jEGiJldNҥw`ً.+lzb$fez&**j~)M6oI ".l& y槺n{䘾V0v\B(!O{ֽ{,Wfԥh6j~NLi0@L& .*WPrk -`^; VY:4c-$lq+u_Kιfy޹8!s> qEɝypC4A-Htxko$ҚsĦJܦ秎;j}g9tȗЕ*L}浢 Ulsj,OS $L%Y_ݫrL1٨MKة 5Dni40tCu/$&.- @  ՐLBDjpg̚P)8шf\K8?E,Lc6֧QJQ"iTDd"2*CR+KIHN)d8)홬\֪ |U ^r垮'5qA'"_A#/ e2SA BiRּ&6mr&8)q<':өuL OJny39ܧ?P39@zPhy:t(EЊ* EG#ZPbt'IK P4%e)@)RnT%GkR4iCwQ F5)AaS4UiPSҢ>U4խ*6`q()ֱf=XֵgU[*Wuvk׽U|Zd*P X*&`#֙Jde3jVle9 JiSZ46!-h? ۿvmZ` ۛb^FkQHͬo5m.xq^׮x )ʕUs^.׽X{Ҫe 2VVܕy׻W >f+`痽l/uÆ 0Xd;aջ/~+R&ZyLW/ok8;FrxO%>2{X#n[c.+XEѼe-I r4RLf.,he0g]/y#GYb1g,iOzė3 CgZâtZW099*NN:{ўs^ mAoԄ-LjF'ɍ6 /Sʛ{N/ʋwMd, Ӷni5V9֍km*o}lwnizO{ ~l(ؕ?LFCΫjyܲku;6-*VwǍMD;L6xZ}e'|y?Q׼~k) t `8_g7Eo\ 6\ݪ W7G۟=Oͦ|;/Sֿ>s0@`/.DH/=o@Ͽ ` & .5 >*`R2V Zif r ~EH^ Z@@;knopflerfish-osgi-5.1.0/docs/images/desktop_timeline.png0000644000175000017500000003147512346515440022426 0ustar felixfelixPNG  IHDR&} tEXtCreation Time cLYtIME8(V pHYsttk$2IDATxyPw}}x/N=PE3xnƸ٨fJvlܔNT*UNerԩbBD !a<~KoO8S}b|Gߵ@Ax X< =`(7xc x _)jNeڰ˰kz9;AGthee|kׯuUVqT{uB}}h"|G-:$͙3z37-(rQ/N[wzKVrH8HӦ ]\xg9lm4t-Nkڰ垐Lمoڂ yBtjx%[ zU:XԤKγK, @T 0>q{lj3O@Ӳ;lܸʕ+~i =i >/^og5j %--z]o^f.sbgP(PP%RotZ2{*Gt6p足p)#ڭU*F&"Dʠr|6RbJɝ"Mh-"Esqnq{ܸqcMT#設mjja~1~3@z/2"^t'A;Po(hm1 ZP(U<).r{=>..N"\ta~BKJJ"+m6=w\nQ;ɲ,ZD;'/8`0q>\c8*EݔMעz$w(0&`it 2ACnllDbŊO?t۶m"(55e*- JR&zҥeee[no]rsN;'*iRRR,Kbbٳg#A5FFivR R iCW|W&β2~6O`R76Tܪ`q`B9ֱQչ{ǏgggLDap†T9Ƥ$ǃ( sA o^^^])JiAщVF'`R Ԟs㳘zG2zϠYzC VDۉx{<*E;N6p,^fo}KILh*7ߠ ̜?C鴴4ۍŨ^Gz8L&+**O+TtV'EUg8p{(`R~`g^_|Ȥ2%+͸P&"DFHYI$GV.P6{̟͠>vn߾]WWaÆʻrGkFړek|l&iW^pU0hrչqlܯ<7yh*Tiͅ^:yk 8* ׬Y3d尋9ڰk :h ?{LWf+[[?$-}y22< ̟N4}Nr2$)y]vDA ˲ǎ}Qrrr_ AVg-H))4K7 ƛMg8HD_c0;ݻ݋~~xo޼a75| r̗ o"o]0.jC\ɼMkW.[n4ǚJݾ};*B!:k@emQ~ʔĤQ2}? 7Fjҍei1ŧܴ>GbtH3@ tqvZ(^,3)N) E!!.koo,k4SN Peqnw )D,#$I>ʕ+Β$w>~"î.\~Yi٫V>3H;~ "UjEFO_?)4 HbK9455D&<vZR㸘>4A4-cǎٳZ(w{~{~9{NybꮹC%L2uW6nx#G:{sǎc 0L`fFzիWcH)wjpZ0͍4}8V[oavIl+7HЁ 0}3=3羸\qZkSrNJ?<|<)dZ#Gl.mzzzx17̽t T {Cyspį|gz… Z699l*//M2L---(@1I 3R[\6WP"?L&KJ"(ieUD,~ŋix0\paMMMtSmNGeckkkdۈ`c20)^' &J5wv"AA}9E XS')xbNpxTNXH$/_v8MѶIp/X,(`cbiL=le8&N_Jb8fM=ܮ{Gc) Eg\\\UU*E#kT*:Gرc|M@|,:By$R#80}[gPZx\h6[ɹl2T-n۶6[nȠ=a*1J rR1c 繾 S$"PQ2BxGE ldΜ9C6 q:0Aɰ WDbwkso^yQ=/"%='HRd5ʑP:A&`ju2 h%)S;;>H"') #('Xd(F?t$ғ("2ZM(Mv A>z!ˣ\%0Tj#E:w%y)PxH JOD1P]$QdD0\PferB߅kLx WH[ eb"!8C`|$wޥ:C[qmъ ?pܠ)>*ǔSm$I`z绖h ~ݪOǁ,)rNKe=ݎ[ڬj'njf2ГKmݺ54L[MQdB1;{^nnvffFSNݼiѠB*T>;Myyyk֬AQ?w\'wuwުŜ5?\9+?K8z… (L& Cjjj[[ &ٳg;wFM2L^oH55/+`ڬ2,)-+~ʪ沲^X(j(.qϗJ .lhh@a݄bMQyDOhu{mҬ]sg7.4JZ:u|>1둒W-ƾc Ez-fݛPR8M2r>+{MdwukijYS$}?^XySVhAfNw@P޶;IN# (-I}^K4-N.CdtqvSd%y4aʠF0CI%9\/P#*;1B$"zB >mf ڵk Qލ `: 1xE- TjzD>ܜGwNJ#^kLS*6m Bp&5(ٻ۠|'!O$ VĢPEZ.۵ZZǶevw:;;s;sg}ƙ;7wwEZT, U[I y?ri ?g2s95eunq~/UxIr2ZK 'u{9er2ErW\.?p 'U4)KV4{y \KnuS):gjkkZ>HTORu۝IJMJl: ^xp$웁K ^)j}^*@y`.J,)ܵ|;tk<3}7qrڂUKS"=ecc#UONHh%xú_^;m_]qeYiAv$߈$Kd~3lGX^.֟"HS*;j^< u+V娕J˒J79:'V夤Q)MMM|e,w2w1߸jl9q,\jrrpX:@< K*ͯ~B}4zCg/t-^$\.^snwD :.>r!_ެ!-U'V=<F$==M$::vtc$%%ZB!4ommyr~n\g^25U3Ҷ9+SGވeNуw!f֯_|9Hbiߨs9S/ϟ@GnGG !ҥD"INV^i9iSc`0ݻ慈xBsҥ4~lذA߸qcATPRGET99vӸ~n|Rkkkz*KF/LD{ÏTY͚-cjQQ|9`AF2!&a*??KDu c  WcccCCJ'$X0d,@ ci!c s]5vu1˨p.RRXY5kys'kƎ;z&ͅ###>vOLLЌb%gG=/v9i }sÏgIaCCC}}}ffkjj8,@| S=/^d)_vn5O-/U{; OL4Veee-;v800O[BHbP:`6c6աL]qcݱo:|?\HTJlii Y%ёsm[Yt?C$թw߫ (|4}X޶Nk|wQkt^I<~ M%I7yO[2iIz͛öȮ 7)vY{z\nJU7%e??tzidMm60Mp$C#:l uh4٬?Ix>P[&NIe㶉'$ԉTO:̶NNG`=]=%["ST*8%!@fZɺׯ{Iy(^NeWGQFuOD uRqM]e-@;#7Lk^8ךY uxJ%OzZn,޴\ |+P?:]{J])zt@B -a֝i_o[=$Y҄uv]W5O~3lGXP $:RC]Le.IV]$ MdkӻV夤/W=\>:x8M(++_xw. |imR(eY>wgO?KZV.Wtɬ A;`%MT@_W=iBŏ}z:G׭⵹M=vG4nfy<s现-Ѽl(;`hZ~떪~uWY^l;a1b|sWBqn!N*fdd={J[AA+Vq9~Zo48DS?)’իWryzFڶ6ge؍X&>7x6o,KKK\J$ J~:ZNSHk.\߯h6;*(%1T@u:up.cBeq] ut⚮\rJPNzKJJal&E;-'~әFQ&ԅ$.vznTD9v!\7HGIIIkx<.,Y%wܹgvZ<|hd ՏbF\YY#Qx BvAcbt$jkkQ: 1ۿ??%8yYqyfѷk~Kl6[E$'+, RX,m\~aE$'+,GHYJVuٲe999iii/C0-d)b*4344D%?>W^Y䐜0BD"n߶m[KKKqS[[[EI;U̩^zI=r~kmm-?SSSEuuuRVoM= C{{;.($$'C2矧FΎP@XWOZ-  Wv~"^UUoZY}\sWzL`PP: źyރVWWs+H]]]?YQB]SS<_@ۓRRR."Dc{겲͛7R*BR u&j9i~˅ m >̃ '峝h m%X8q1rhLM\.JT#!6)$` D>Z釷tYTh]YŲzR_ZCtN7 )GBl|+r`%[{O*g0R5$}Zeх1K0X_5ꚛ-aƭY&deff"f SH A!@ $:1P ˄:DU&q~a:oEdC'7g4n7?bwc'"kby$j42>>NO?{݄9R)<YsޓOSTYYYT8~Ys P~* _i C u3r433qN@,:+GN=9q5!vճ>)))x HCaJ>V.l8Țs={ns F' FUWW744455+++Ybx BvҸ _樭MOOGno`.q4ϗX}4G“38@ X;K I ˑ{pѪUT*U@4w“M6QGYQQ!d,h$`q>~BRiif)qOFT]]Bɯܾ}#G Nذa0qƹz٢hz٢hqPP @BH uBBKYJts$qE>wv'&&hbNSHSo;AvXܩ>\PP@3555Ǐ;(6m/LXJ+)2/i,A^T{Iw $jtS`ZX(Y?$-32-kΡy3n5圙gyf6=3O kss^u(d7<`HKK;pIaFFFrr2ui=WC!;ᩞh4?~. **ntN" Ƹ\Bvy[u_Vkaa_~9TH-P\j"K(w FihXץi~X(dJ5" 3yyySSS.nDIII>uZk~zK8TQQaf,K.A%GƒL5Po nHej,+700Po <]c]mX,f=Y? P6bK*RbbsW%\ G%bPƒ^X`-|+wJvRz]c;C%gggWWW y%)J{OB|888 K֝A~ettȑ#)))111III׮]#Aus5k֐>666FDDP`0dy$BחymHHHSSNG JOOҼ⏎޽{G]fyO ˄{dff/,,<{,ਫ਼z>99-i47vtt.2kѽԦwb`QR:PibbF`E4t"eiYV!b2 (;wH >Γ'Oy***❩[xju{{;YK,r$===YYYj>|57oXAxCCCL:UŠ>88X\' S|izj~{r$=JZ^2o杬[PgZɐ޽b8Kjjjؚtm"ftmmcPe Gg:?Nƅ$nxܺú>ywu#R]]늂pΝ;Y@odyMV^ 2LKKcs|||ffVh4Hr;v(//W2=ҨSNL%Vc)"" 78g0R$5(kkZr!!!Q >q+ɋn |\g%f Zڵɾ2Lcé-K޳[ Irrr,\KxX2;#d3Yފ++WH/ǘO4*66vllL&5Bh4knsss:$rvv̌lf?~HzҸqF[[IL$Y^^N `yy憆&ƌؘpuuueeeҩ[cիW b)))R 9===>>NyrdHȇPZZe%bxx… TlҌ wGbrcdd$55z۶m6mڵv߳~R򰜒C}ݎiiWtGʄÇtgCCWnFjAwnMM }0.SSS*ACgggSPPp̙ׯ_ ׹o߾ӧO?wnyTʕ+}FϞ=۴iSOO \BBtdd#Da111*G`4ذ0ϟ?>}vWF)..&SI {J++**Z;wŋӔ$ ѤmSդnZv֭֭#d P GF̓2U ~ hNBW^?y|ҥ 6lN_)ȄW2MMMqZwѧOk5)bHGπWeW%C}a2-;o{V5;&&&QK {J񇺑L(f|(^dH|ZUp 4vtXb=(x6Iy5[@9qѣkRs@']f4ACe:CCvi:Kn6SdTHD`.r@ —DU?DJLPQP0o/,;e/""" """ """ """ ktsbF2L.@q\y nHGoO72[ \٤#=.벿#IC Ns})i|bV9/"{)qi$j F %t<R6=1NjfF>m;;}F>k:_d`ǫ<_-OIrnzhKydeѰJ&ofoc>7OC^8+71;|*~"viq/a;BOR=:*ceeOh}r呧X7*IP[uQ>Mpmߑizb>j2蝳?E,f2T-R؆f1\\ZpRcVEcLx54U)C[E'h?UxehU8s6^㙬s}VcM(GJ O89i*YgUH'`(EUqlڍ`pXׇ;*6~4!|i^DYW-JvP4v OuEa5]=7s#'{`(t~6I˝!k+r5ǧ׎3TOvmb) lcsf vk /-|' p0Ѷq=T~ԭC#z|'OS(ovE/4*99xt+447~PI{‘)UcZfYVVlWOJ>.Uؗ=pe ƫi9]eE5#YsƚO(&u;|W*Z;5$Al(LkABhPE褗Us>&q$i'UO&Q~NI)ҞdяƐ5hRHkXJ<`"G>C$:pz(}ODP}^`YaÃٸ ~w:)')="tt\׼$|ېY|wє*8ZIaҾxq vݷ#~ZjH!-tm2LoBܶ6J̌s~oqv7G6iq8kNW*o+l2!%Nw=\ \薦e 1?5OzzvX-ԍei#=F<~R&w1%/ 7Fe3[uKr֫N sŨ|+1K8i^Dä n:Up6Iט=82ӌ{}V5ev?=ڸif-[OKV &2C{Ipۛy9pϐϒf.Y },M2G3w2FC~9_'Ub'f\%-- Wk+Aqp?\szja*FB'!p91=v[ZK6C*CsۛwALC˲G˳z` 䉁˭LdWp_oI 5`A~jv*Mf|{Y҈""" (N2ۚm {HOI9AeeV5uJ:*_&g-_ugTDͱV% 1Neň7sE-T4{I#=+w qެ$09$yD[D5|meb7. >Ugk[rX׽}{ 8to#FFA|@$oyP|M]]FHL֗k7kv2-ЀH%XKv ?5bǹq4篹^mbʚ=^;QlA$8#Aޥz/Uw$tAl,$s;\rbgVN+Ջ~OC ܻ53DрNI4 .sZ>+ p$ßTc^0G7u7ߤg ,%z:'=>OLJ!i9w(̞tL۱A` "" "" 4!iphKK|zgX憻\sq;rD1<@{*X$Q1㳜Gr:zV9J79P~@~~[=BH1BIiOZHe}ǯ^厤 % `ppVx7:^ W9цÐw^r0^EA17<sY v?liyQ^I`2_Gz۠.P`rܭiq|~%PDDD@DDD@DDA" """ """ *YxJ9ll| m '<@iT{X~+$awFRXT|Ien>Ji"ͱv^qia=R͏Wa\MiP643;P-C0}vS)8""" """ """ """ ""Եj[Zl<2I'`vڨՎG4HA\z斝`O}xZPF0`0* c^8I=j" .-JjC7d߮qi8';/EA $!LoƘ0ð_|:rY|k @ AH^@T/@ H4 D D@ zMH4 D D@ zM̎:RSGu99===P@ (D @hn[޹KzuGQûx0)Itڿx5dpF%'޼=Z}  PL &S$f&O2?Pi2t-2Y l,hhWZ )--}=}|;9J64h.X NE BhashP !tu ._ߥ/V+n4VARh褀"#] Zk4|Oϩ6Zi4B܂Z[+[[oxOx"-  ΋DY,IH @+zh*J!&Z}D&#뺺hd2N|@ cDUWf>27AJ/4a 9owHwTJ:p8ӑ+ؘ8Ֆ-vMQf3֍{ߴDE5AנAWEN]=:jN6m"$^=GjϘ6Mx>;V'2UΝfώyScǥbѶmC \<9QSRJ/.ee8uR邃ǏO0bIE/:ԩ+WN 9EO7df^ܰ`9{676VuDjUovu8r̝L|WWslcĄEnGFjrr?t ڰÇOb”4I "yUHGO'%Հ2eww9"#:<&qׯ \1A'-- p͚[FhD;?;;ljj)qI dhLw!]2 EvqG]t- ]N]WPwd HT sfb ,u2Z #_NsAn ƈfF6{``8SOaB10˵h wd<%RiBFÇkš81D2 3"Q|'cȲTñ86Μ,]zK,6.^|C rH۵]/''k֭ڽ%Ҥ^zi) ;rժ3j!.n: Y޵‰`ap[oEEmtnü R7߼W*EWtvs{9 ~H[ք~\Qbi* 4k4oPb₂L&kLSQ8goFbō8՜9'gώOKV\,$q$ QQM dKbw073bHd=줢"SWpmҥcɮ@xR1S8ydž#\46vkAFhHd\oss{BrM),R=뚚~pq\ؘI*+Zݭ FWOxx$64 z}̪O>} nEނ*XT/g,=t/4yH>z(R 3r3FԎ]_ͯR, MZ}ϏR*s&ς^_d h݇4A뿑Hf2hի7o6;;t,۷DjO>! X\&ߟ&ii*fo @:"×/m9iq%##< >ܹs1slU|>G]<j%qX[~Ny R[_UӐ!IˈCX"ghJ/_tO#B3hX`JkxF =7#~fF,1j &a%#" 󲏇̀>sHWG'lZCh9";9Rwܩ2v>nP}/ lD]%0P&1Bpg=^w- I4碗2$?'I *$NZ-0h^X,Y3_?f3ږ:ylή]?kw_"Q 0\6gۉ6%%OAJ'OVnl6a@fFc;׽ ŷni@( Z3x01חPpLh>>ˇxCC 0С^nlVX յ.`VZ[B!Ϗg2YF 8i8; < ǭdoYZZEpAZ*MfǂN0 t2 vwX|qd鱻ʋo0KÁ.]c~oȑ'B~^^ƺu_R_߸~IAIM #uCw©{HNN9St/xʼnnw QQa755Ϙ1 J;IIOۗЦʶm(8{dK(J@B'My l6#tkm5AV\a I<$ԍ"~ 9F+b񬮾C0fN խ0`0CFӧM #AaZ[Z, UU:iK~ X0] d?yxvqNl2-)KZ]"$D4ʾ |ɤ#-U|~@h uW8vTl`__?6_2o^ ޶7k32RU |* h٬Y!^~ϊ/ 3g#̅%K>i|ٳ\\\bT$Ҕ)6lXo^7r䫤uq.XOfw&@rTgg/VcJB:X : Ʀ0I!6G+)S0; cX)0HQppHB{s\4lHލ_SS=}~dsh ᮮ8+A|[:P$$ۙLhhjxG%'_& =~|hj,99rh2ofȗ(NsG#!Ѫ_&d6{؆(_ä\DH¤0j҄'PS:3$=,b"MB+S@َ">N:.ם0sW^;ZsTXm%/ڬbbV{kUiPhǿiCuU, 73EʕLVD^ʛ 1iot넌n՚Y!ssZ1c_TsNarTVy@tI7ûG6`اg@Pk6_i[8 / FcQ쑗 >fɸI9Ѹ&A"]\ŭhm:g_*DR~ eƼhc4Fi[45jSY2qYL"}Ź\z;Ӈ '*f| 4~ Ţ4~e2=-UL啦 r/z_N;>}q#Ͷ`Xȉ'cB? d4hޢtT1(huTwf4-UL HT F-AЗJ#Z&+1GC .xG=W,l7*r|ER)?:EԲ%#(ϧ5/dv?.^^b {bb}zAiҶT1)'KOj\m 㗌C FcS&ӕ|`űYzq}R3\]4 #i6ҶT1 psvxEiF"ϟUKEu XCWwf]Zg\7Ri;(pxJ5HBF\]*9_pA^!40J5m߬9U34Ooq-kX<~Fc3U(s|P%盢hJ Q\ 1=T%wՃ˓JREETi24G0"9Ƥ󮯊YE"S;h4UڐӐL~3j}zk|ѹA ֨Uڜ**B|cNx,jλWn\И˔awUFAتUNJg0W5]2<Ņ4#hhI%=Y =U2{sg 3os8l*,/7^L3k>=z2hМE)UڐJiWeun5n3>MTM[%*Azw:?dl.AXULlv^\iAcflߟ ld4b(T?Tn#7jwʏBMUВ*&D&e\4O˭r:ln>TE%P4ul6P~4<|{mmۗdպСílhуl~als&⦦ZZ7ksl^2ɏ'S)?SY1[ń痔5=ß|Wο*w^u^MVUy j+sL|)2r|J PMkVA%v6m 2ƜP4Sù\nf[IOmJC ۈr Sd_Gj]74[4-zR]6ۃCDSYrbE/1CY3m=syOqU'L͛~Lñ޶ٍvpB4K1Uy^mYN^s,edBW g4~Ui.PdЎL?Se)0M[u:K*5Ok~DoWkzli_e3VZ-xĆY;Wj4V ^ǧLD54{CfL jL&7LW <SfݶmM]䙬d7tVM]?c~T&\sLfɴBjaݺ .fOx]eӦz_qEc 4v--gud,ZZ^Zǧɶ|K.(֞C;8=c{jk7-Xcݺxt.wagֵF-|LV<;y{W)Lu8xO,uR/J8VtٮpB(Gc)`O_f#L"_D}㑼ÿRf{UI.?H4%?W'~y,d/D26-4K]0A֭M9 EX;q"v(iiSZ jՅBiՔNt O 0vr8VVDP^,Z[?zXmiuc; joG6lJ0v1$fA%QP.W ȃ˴ [,p8@%M5jVg<1Jg2yrRZܷ{ժ`𗁀v27le2LJWe֯ *ǁ` RG":<IS\LH4!O._CCULAĘl@ XCB7ܰ8|BHs!>th~X`[tP0V}7p&<;9.ђ;g/Oz뇹\F9EcfsNgM>sj4?zY_ŤO(˃)>S&C<_L><>Ǔ} `jЁ/~qc]S#~i6'io8X4KV~'A'~31 HK2w.W)٢F\'9?b4.% PEBjQas7b" RCE$3`*h B\ :e3t*GR~UW5 P^/hR+eZ1Sz0c0SlNJF+}P63H <KVKOr6j rY[С ҽ\F=Tt%3G7a.蛡քw 94mҁTU,n|yxz1AW@Xp گڏtO?Bkkn]MWWÊqR>>EY rit{&N`!3hhǎf- 2QmBW?rX|L}b堜U8 6rLv[˖zY,,'Z6.3 \@KÅB|9n]ߺؘtorjȝwdWX|&Sb ʉ > ,F,ϚKEU1D L~)KW>HF *Ix))Og> NO"(K p"R> llf.;ButypZyϞ^J<8#1R:%l'ic߾nH^{-߾ⴛL2ѥyHѽ5״Rmww ҋd} }I&eТxg`K߾rݻcGˋ/*Z%rB׿uG~v )oŋ?Wl ݻ3|ed{::gvs}dr(n >t_O7mpwQq] 0 2"2XeIbɛ,uڜ$N9N|b;Nk%nisZǮ}a[M4"۲/$k"`a`vf~޽tipw}w=&(^GPNb^f8~9Q)ʀr=5o)wsFY,?w5iG=b~믇5[VfdO.jko̽=YCCζmo{hH;{]+&s /$^PѪN6H8T߄#54A(s l_pv/Q3@s3fgofX`9.(4**ã4.twq$X MӸ7(YSc$^]Mb6kNLIɖC΀e@'ý30%%Z#p :C1w˼B[,EѨchltp;Ʀp- lw8iS1/i+11B1b`hQNx).e0]便]W7:b9;pC!4c"Lwh\jQq3`+i1(LX2yGF 2ҒGO-`z!2?bV[͓mwHB<{&/zodZ֘JO[b9K %%kc@_ vуR@`  tW ɤhzVF븴t a,ΦǻY!r; iD,kTuJOpI|YVg#.x@3^9pu< ́2a`%B23`S8_bKJC˗[Dy|@CtUpc.Q>ιuu-2E[ƖhzpP5, d_[dV@An_ÃuF1A}^ooGmm*tRn*)1j"9 FBt бYj/3Fxҋ́ݫW_(*+i hc*jl[0^?߳:W1&Nҥ5L~a^9IEE-?LNџsK2?$a{rsixSb_1 ݫߟ?i Rߐ ׈m#.v.A,s盻wwr̳74G߁jd bVUe$B$? b;A0M('H}̅wLRJ#I z#D f8'=24Hyx t9j/XW0ވ߂;@$<OUQt*qqp$$bS rUFPC%%ŋ.bRz19=9j؇ܵtl u%o<[4r~ 5]/7򙒒:t~m^?xbѾ}y)%o~%%o|X~ @~ neYٓO=5b >MVMJsI":3Ut{EK&j,xC4TfFpmmx>pJ+ G8qEPp*UMx "&D5,^}QSy᧦F"vLH$,ԹSuDFL~v#qd~TUEL j$`.+шŠH}OA%VPjLX**O4@>B"n}Y,s %IA i* L`1,U&~S,v~t)c.WYZZX{mXLe**߃E&#]LqQ̄A2W9Zzk)֦ K<"/hhݻ' ;  J 0A!A f2S *87O}27w֩S55@Mj1f耤ӧd!0z';<--US/ayZ{7E+쏑[ Wv0}EAMmQvY`˙lGL}N=< "3@a<o$1%o-~i3--;;{}ZZ]G7l3OO/' UI5uq͚^\OvE| omމ 4|V7 6+OMil7Ďy%mm.bZ#RVAH"| z<|Md 0C"13dRxuEVqc'C֯/fsoPN; СhCݫVȑ^VM?zf{ܻwrsխ!jf؝wa)v@s4\pe05x ~}i^VɁXt/9WB@R NP{Ϟ.`zV/j|(900N03eFeeTz%޳loD]׭+J)TΎ&"5.1y(lK$*OS4X`@0x%dqvgd(7}>fŒY\Xk{>'\Nn\mAU\F^ȓ?1A 78'UKxDG*F|2w= }WquY#UQJ7>g窠{i\ä;F/^ ^=Π~*HRREkkMM/EE_~?{2By1!$upV"Z~BX~SfRjb/k7*3Ɨ;[1&b9fErj\כeFc]B:rH~Bjlt,[6[bcJ$o0{8쫯w-_^(d bxXH 2,X4z7)*ȀzA:Lz4N2&32 ;(2v+ X 32Gᴴ,M(/E4?7+@[cuLE1'/cKM5~hD[ɨ<8WX+*6I_NIOq*9Q*s:'A/QYvxx[vl?FƲUH dYiL;S&cD1tSՋ>$,rɴD+2^hVn4k:#&ӳ5:s'w0v:o *պݏ)1L55>RM8r| ܔ/۹~UX~wѨy0;343Ir~MZmKpi*Mʔb2,W$ė MJF s4z#Y.iim(Dw7) _'eht_fi.>߽pQy8\rm>1;IQiLF"`njcFơܦ(L[D2 7&_ -zJdڞD̤HI2ͫ[(iaEaGlQԌ'_( v?h6Tm{i$IyuUU?z>0HeB קfn33IL(I2"6ф"Vۘ sqj4=Bk1eYJU-FcMuHH83_Zg;@@(h.'))3{<eYYKM|Iy g >]\w0ht|plzfMF"CCO*J(+5{I[{#7O%岊h[ۗ5ZE"ƴ֬理 ^ݩw%eZxomkII[93'p׿ H OU_[|{22'sI)-_Ɨ9L|%^o[n:9xᅢ6MkE`>E4}fVU9.TXxb-E%S~8ޯ;ۇW$ZK@`}45?:*MWWU$ Mb#Ȣ3Ί8;cGgt8*>uYag<>u]ed bH!$JwWWu_&e ::}n_nusW墨1a}gFOT\+?~V+)*-Z@vnX7??9Q(dK? -j J5/MyZ]&gq񖆆[a2HQ W]]Gesaչ;7FѳGHSPд :mm볳BI=M^[ۚh2 7V"wuuWfv;;ߩ{~;3sqMyZ.?_}-fYǃA>ߣ:41]ύ5c`B"mɲ6hS 0RD4H߁r-\e͑H…-ix6U;u҄xj&S |.X̙/sq LQs欞1! j56| &Y_[篷^9==y+btW V*P 8G"K@@V9o9L=(Jk,,[,Jyn0xeP@h/…ϭ[o9q⃄s֮߾Л\՘A4P[{rfrqiJ>2p 5/4fLN EC0@ \vzp!8\.cN `` LUɄ`6O,-Afx23sFUdJr Ceӹ R(4_SN={%vtSU<00D6yH--55h4vAݿ%I!aKK|Ri=i]g燔wolj:n{ ]]rrUGo*EEu$ݷgxz FV@338L X^n_0T8C+M+&L0wuɤ(U8E WcmzGv_A'O (xq`m8yBi|=e1&<Ն32>!{kEQrʗ7pEp%)iV-wr[i4E)U>ZΥln5YW_۵5*{JdZFfӂdB(+S\R #G^)/OpϞ[S͟64l4ip^o޽OXE/qV5 eŤxI+ܿ+mcG3T&_8jk $^#8=+˼|njz[&1cOѽO66Jf,H=_X T[KɚmB@ 0ϪR@po,ڸ=Boi 8$OCNV.jz:5\~y&tohTA> mIUg%[6WJA⋦9srD|L*O-Ƞw@ݓ'p,n0F ks+*9P+,  b|PeWBɠ)NWд})HlX]3Qh_1hʔ&)?)S êiӲ}E[o/$)҃өx,4=hQ9N= AD8(BÈi%?ў=,/rfwJ:VkT@AfLve/K3<^[]ʰNyC!pW.R(RrpoFWall/7PtǽnwXa@UX?A bĜ9Ob1~Lu}Mͺ\]Xx[v?|劊_UU=pTTw]t:g49)aܤIKv91(8W^9/ e3' $m(ɰZ=vL#0(lW0`z犢eu *ij)[` T UD1AZ |Ph^(t P=ý}(*c1R/Fc1zh-:O\NBΧޖ*s)7#KaqȀU>Ewb}P<8n6MbAU(8N;x`XTPHpzCٞ QxHt?X,{^,{~ ɘC;;![2V`΄ _TR("4A+A`OV,UtVnzC/HT~a zGDED%% %O7S9'O/|N.Z8|u4ݮӭ^ 6J z('r\E4:~fC~rE)g$S=^K X>,{La0K& 5\y_k.CeYw7%QgTݤ~ nktI#* SE ix``;:t60OuJ偡:-M)<_R}m0v.-  J p ʲP>ÜtX24G(1 ↸A(;[[u\BKz(Vύw7 OD`t'MдŐ~p֨RH6HUr%yrD  MKl XJCKpy`0`hk[_Tۓ'o<ͲY eǐ}}fj8 Őv:gY5oB%M@&YU`#틬;w`r\B Tn6fOK`I]]#E+cB MC6 v(x)X,+ӣ:R>#CZiJdw{0*Ha`Np,ijz1 ]Fc%&>/S!Ӏ7E~e`vs;z(*XIo5V^a@KsP'$ +F:pz@ѢHf-hudM~H.G)^MV`Aoc9E X\#/ہJ/*A?ې隋4 . )F 2agBr.Huזb d9a hžQz%\!M qlj(;h Sb ~M;8(i{(LBzӂ4XׂH3M`傈r>$Fc/Y҉ A! .N/K&RIwFՈ8{.!&<8@pAH`L~d<|E$  I@@@0 $ i 4 B!Ma&0@H` I@@@0 $ i #F n=Zmy'dL%s^ཙ3_Z/ D@@0p".WC$dN޽s֖?myuu#і-]INJ>L ]\|Gm]ٳ]H]K7\m1!oxO~=aJYc-My+ۧɓp̅Dn@jvW8PL#=c&bLf|p^cw_p3Ǧqhzz@#YY7쨛Cpf;"w5 f^`@qjO"aKKquu1 jRG#tR(< AsP+]"+ 9A0l]fcU %%q3L&^4.|a]XTC.|6ʜq:1jKl͕ /k\8)I9}fJjː"~X y*+rȈOì2m`"Ԫ AW/Z$v:}+8sv%󇪪M' " ^ǎt2ͺ_{ x?Q /7jts >r<.٬FuJBPL7 ]LSv?=>0pi8]Mfq斖ckz.*ڌ^E1;s8nw jabdz 4^oZҾ>&6i2e2͛fYR[k@Eؼ^AGZ Żb+p U[;oΝ;/^h2޽ >_J{+wZ4AaPE"-N䎟Djs/v3C&Q;Aɤº7vati7΅9k0w5:vH_ɣNN+ sZ vtuمBGd"m6knt,Xؘ9s7o:h6s~ނ?qڇ : L D0va8`HIB J sDN_|?6m74T ^juF!xyWÓJ豤z1yN9.?\zƧO~A L&%7SB5J!RB{xCLrxX;5/Zhr:4E X hdhfϞT$h"{4e40)5uz D,XCVx2hdD)ְG1HL!܊PGvqs2YzfS#B90߇@# I=ybfOLpyHRcBp_0_4L<ͷټhf" VTJv?}}nTI /r{{hT1Ù)qM&%$ BEJqRw!L b?Zz`0 ezRRCC^ZO.UDT*fQ pz\.zuB 1'dj:EE8,xw:PPheQIQd0(D\h eEĽcx?88-=޻1>3N4 Ix *g۶]r55}YQ1tTmO~x " &I7ٯsO񓟴F%& z._Fovi={ lgA<$Blr23'lpmtskuҌ ܀[\c{Qؖ_EYYׯ7ѝ83CԈ1II Vm*qt6lm8g"Ο7`rx/_|.yNv -w=:{vw_@bǎiw*߱˨eˬ7@!_gA<,^$%E o2]O4-e0M&ʕ}ѡP*?V8c2e.[)@yJ%mkZ̙7AеT*F%%@`a{{Vnnu0k͚aJ7o.XXr P7t&%٬fZpt5;pXvЦ^/gݺF dwpvLoݺd߾"]H=7i_zdǎ۵S_oy[Z?㎝ߟ zLRILcqXT96ݳ)3s 71Bj ɠ@qX)ZX(s᰿ onl^ԅ%2kjzBiS3t^s8Bەロ7Cn?T\WҌuͺTl͞y<*6T6r$LB:[u8K ے8 |A/6Pz` b i^LtcܬC"?ψWŋ1 T8929SŊ{|V*ȑGKJRǙcܳ&g̱`DdR=h_Hg{6}0=l'r s2&ώL+&>MM?KmdM[P֯?_X;)q9˗9H.$=/ބ^ĨҺqa/]zn򺎎٬H$77[?ٺ1qvvq߮:i4;**ZZk ǏxE٩7c+*K(rmi1ddArrXag0kMΰaLDL6[ Ď~P8qDSw7-i nGosx mmmm3[ތb]k-ݲ`:yx{Hq3#O3?x\Hj [򗥷{wdZcs,MGH󛺼Ϯ\lݺ!VTVw}{s?c'rfoz]]q)u'"y78g+`c׮{݀w,oL}죙QAD3%eotHLdzAS ⁀D "H4 D "H4 D "H4 D "H4 D "H4 D "H4 @ROH łlf!UX*A7ǡB!q8HggKfY+KV읏OwXԚLJV62ߘuNGąQ;fF"s4YZ*5Uiz& GY 4l@z\$i,RVfDb W,2Չ=8hؘc_61tw; PW;'8d1&B~Ns'A>,ȊBd$% |IBX If I T WZZ\"lX4*_ F3,+0apXlx,L \w,98/ IA4iÓϟC~9s?{EӶK+VW tڱ}tz"'6 6:7 n?R~j)''nIy')[|vx(QUW3۶{f`i` D%g]~KM55uR>!ykThcR*@V׷;^0 fQ‰0TlHj=[GBB!dNOF#Wv(+.N]W7x]vnj-mkT1--LutLE7,z}F>==ӟ@4} !;%],ATB#knU,p ߣJ%#cӺ)۰m*FE׷RuECrECZ:5f&/'qB'=z~2vhD`=q ؖUGEu`z4*==\zw|J&lFKs /{Fq-GFյI, ðaM*(ZӻQLޝ_?-b[Ow }!!pGj(U$## +N(%JVI-LܐI,Іjl1 **vHMOe n5R_$4]hOc#FQR.(Rh@*SSC@MuuIF3uGRr6cYMJNJMe IjjZ:ifQ40히Em}} C3C6@Q" SLl*)lDD`dF餭! Raʢ';x{z=م7x˗Y-G//oG,_A|#K%KeX*CG0 FQGXQ8zt[14JJ?K$CIp._Zw&;rI/2a{dJdQ-v+^UY]oj{V_|wo;游OO:13!7t||kYМ]C0gyy3eg K}SZZ_qccuVJʳjHRqxmk|yy_hϞ9iiO>ZZajbAօ :w, n6f4>sf͉Y+D]wec62 » 5 cݯI۠{xҤp Tx5<<6&fر'N,+h`J 6d7gn6fug'BC{VIu'Y1m# " b^ 0n )ineWZ.n Aj?0 .:7eۺc++hY'Yh ۘѴR.FvuI1 9[xv/n0aȑYO4MMc 8򡱱t??}}F)!~c̫-yA'YWG}R[GTEdjn »u \3%9 XR=5Z_ai$L1CBef\NwZК,`i ۘKf¥]uRL"1:» |=O _ai sÝt(߬>XgUҖDL2%ef%G|5֭?` ?`izy?mVX@C7-,)y} ,M^ &HK;vt齾>'0/ ؑt|#h$3ԩoCǦNY={. N0 Bh|y^xO,7惾 8*6݅K\sWw>~|%'ի_KxV5)]"JwG̝{m͚%yl0=w).>YPpds…6Yӥ*+Akr='o/&iDLN;Of&?p{듙hx.p[II->zt k"MɶS>$QzV֔MNboU%a˖>;ׯ[%tx\1shҦ41wi-[|Udݺ ?ʲewH}?|֭ o[1!e߾y&\YPSlMGfgOxRI7=r;c?ӤXGt6lYL\5C^=Dm>2<9SI)wLJhT>Kd r|4 *캫;mOJ2M*~{Ӌ:Fc|Y;ztXuuĞ+=.4'++**`/Y2VZ2| YQ,EMo_oޜH0U*sYPk|ŎEVxbgfO|Eܲe֬IaeY֎%܏ 7߇'㊻:Oeei3H5gK8+5x֬> \雚[$*~X+qnq4Ȫ*N7mJ6&d[#QVt4Os"4$7w+\p.whOAEWY7߷ ㊻:ϢE7"tQyy1_yNڻ7zӦWL8v:xr׮>8mH}YvXG|kkڶmYYUMJ W(#$m$lisbbfә9ruEkG{:\93;t{n=s'gj6^|A1c7nqƌp74 ۶/XQKDA & "h & "h &E/Lvw,O-Ig~_a}L+^zCWWFRb (F&ӄ>;*)|_2)_2YHTԼi<MyUU(*]ntUVs;;:^$&_hl$yb4bQ(b ROJ?kO984Ɋt[з 9`ߞ@@4@ -;IENDB`knopflerfish-osgi-5.1.0/docs/images/desktop_info_manifest_200.gif0000644000175000017500000001543712346515440024003 0ustar felixfelixGIF89a===>E/>dgw ,_8: L#97_-T \{--bE.e[0I~Ùh^i<.*Pbj3 w+Af.eZy!At7p}褗o>du+@NRt9O 4D I$bQ>{T3fB|<_4A!EC% F@0 gH8 s@ H"?܄& PHE!"J\.z` MEz@HpPl#:FCHc(G| !BL"F:|pG=vv(G1"X@9!:|dr)IMڡ|!-'AnҖ%"؎G<]j*Q E x@q5{x `FDKBrXC!Q;3P$B<\!p ̂"|Y1=:#.XH[h7p5pt/wBaAڃzH{ϛӦ3`Ÿc: CntwDl *`դю0b ^ʰG9I2RAXժ\Z^"lsQrv =֦Z3&P 'EXDaZc-c?VAnrtwE'Nwd x;V7cٕb ֖ϵe xWZmaBX .G:`VP p9x5c'c9a*`{p3=^ r"ӳg(\d@AfP?=D1|H):v3F5f n4Q@$?GkkcA \ !_ 5 䣣h+ n1/YT8+ͩy0Y)ci=<2ɽs|w"&YCF櫉k/M[rЮZup@!3YϽͦoǽby"kXQ*6M(#%..4wsæ.oAbWi!#'l`R j E#H s ۿĘ_1O͹w7frLh"@ޱo|ux'D 2A" \@6:*Yp *? V{u>o!x7[`E0c/@ J@8j  Z`\w3@ӑrXnΑ~k򱘂f!Un`h&  `5U,΃}e1Q" `@̭V``zv +GwG5:4;f+%g\H0 tG:š-{~c\UME|s Чne{shccFSfPQV um1Oz N Ogpf;vuTk9CfcVdOEN}V>ՀfH`juN `O#+Tp7`sSHF2]zS{7}v'2T5g1zX1gf_?1Z%D܅1&:z(2wB8k|U?٣<cGDT#v3S>փCNe&n5tg=H>UO}tP jphB ^fEVxX DVՠzhy dyj`h w1w9$97p6W3ՠpƊw2@=;Gvgnh{ mA`UWFxް ِyh>8Ts,  iSS^ܠ5a+ z+=9]k匞SKEKwTjU # pH#YSA1,t`>` 02(Y>|Uj[^f_)9 kTcX0` 0CiHyJّL1# p| o oQ3P5 M'Gby惍]ti G)@ Ͱٗ#  tOؐ $ u$24 \G,5}ru9a@P ˀC@WܰQY acyg` ulBŃ2ISe\݆i`;YMz#9P& :GUT?&fsePc8PjjwJ p  pӂ\#c8Fuؘ4z 0m0lP| 2&NgN=95p5(2jBYhCV!cws5fڑ` ЭZ ګ@@b%h$G17=`$g<@VKODOf OSOn۪ɧZ h@dЄܰX(+ c `OQVO~@4~j~9aiKszpD[F{H{:Nܐ>ƕa˒Gyc(ˏͺF Hõ{ԵǬzB݆TWt[SCĚTA# )JI2JYMd_Akp%9烷 NLτt0M(d M  DN^jbυA1(Qt5 QhQu 0Rzct)gGk1m1z]VrhU U ]U JVfVQV 1Z1PV#2|UdqjsSdԃgfڃCcJ1YPY5YUjSc|Z\7Є=7u KuKXK$a;+A5~UVj&0a@':>7U\\ ]GX9Kx9|~Ko1Ů7bAI(qik'#f_Gȣ#_ǃ<5Kr䧈1Bw@S`ms&gx1V? V5́LsǶ@oo,kT]cݧ[Ԛ%AY`r6rEm5@1Ч`uXu9SSf Ѫx'x4J`}{ Ipmx(phoFg5ؖ3f،؎ؐf 0 ,QHu,n Cp: uڨڪզڮښ 0ڛ/h @Zvı Z3]}ZȽ̭5`[$]K r I=]-FpI" q q ~rwF`'^n e l15j-ܢ(1 >$^&MveJTk9=lǻ1:@ @;A^ A.B>dڦdW C`k f@s,'" b>a,<#֠z0j!  @͒ +L~3~5V4脚If 0o&z *wn nrCi <@&lNj&je h^)pT ԓ Pْ@ټ0 0z>^~ Yn `Bn~EP3#B^~F'_,bm oӀ``  wXffɸ"?$_&(*)30p,vf+Kݻx˷߿ LÈ+^̸ǐ#KLd:gmTzX3ӧ>Zװc˞M۸sͻ Nȓ+_μУ+ k>twV  zP~}i˟OϿ(h& 6F(ᄿ|*f!zQ9Lv,0(4h8<@)DiH& Lb!TFyc`)dihlp)tix|a#蠄J&jh(ꨠPyeYniy覜v駠*ꨤjꩨO<(~ƕ᪭묵ڊzc2Q6KЂ#)zb+k覫n̻ʼ)ȡK202"q2+JAۢJ,r$(,xJ9,:+7+36Lu‡00OdxETn !s0-dmhO*\JilM;we,pW,SO "X5PPx rڔWngyM=yf?e@O;+hxeu& < ^g ?`h?ȹ?sυf>; ɏc ?fb!ڇi?И9~ofכTznU:QZAAY? g8t`rX8ǓI@pba P~#0 !cc `R - 'G Pc`a8$$p&c# A(  izKF8#@G JWG Yu; u(@,Ѥ0h&x7a: Q\4?TE"aX!8$3P L%F1򃌪 ef:S\oW*G:#5D\{(V%?rZ{ yH ,(?.Q}hb Ea <<?|+:cPePxx(9*(i<4{hGPh|60?` eb4Qd|'b* V;(5cUhEQP%9PTJժZXSq_IɚV*ћv@rj c\Nql^QXC @@K"t? .L?!T@c12  6ۄjq  Љ r)E,$Gv4!"rg*~.m"7 K RQ,eiY4MzE1͜y`}z&:7Yk}Z W1ȕz[א`x? @II Jb, E8fJ vWYIqr ZS*b4 Ae Jmb9!?yʅx.9X=;H@eaLeK9xγ>y4* +4 뗿@:tC@a҈(:r!s $v& ` ALQ>/jE$8ZzS؅9eY[_vαRiڵN"ڣgi1 e bz׺5~Nț@ZA8wt+MKczj4(8";Z9G@N6ppJ*!tPR:TZVzXZ\ڥ^`b:dZfzhjlڦnpr:tZP L-jѧ~:Zzڨ:Zzک (:ڪ:Zꪥzګ:Z꧹ڤǺڬ:Ӛzʧ zJ:Zzj~:aZZʨߺZ:[{{꺧گ*+J ۱ ͺڧ۲. )˭)3Kk.k0?{2˱"[F{HJ ˲j1*+PW;D(:^Kf{hj˴z*a۶Yr Xks˲tۮ]K5{[C{ʶ|˷u Kn{@K; ;e˺x[{} c[ۻzK7R4k]~ɋ˳> {؛k;g۽˯盾껾Hkk;{jʪZ\|<${ <\| "<$\&|(*,.02z8:<>@Bl3(a(;.>]cr< Ӄ(g:- 1-p2} @>@ =h*@kP nኚ*0$;볩YˬČ5Ì.(ヂ6@my`DFާb֪g4@W~0,wMj۲ШdNhh**~m P`mkzΛW{-^.>.^1^^Ý>(ޒ<ր @ P ߋ @ `g(l .n(6/;_~ܽ.4^E/IoLR?xb`҆b?c:1֥@ G=žz؈ *_O1_(P6o 8ƪA+žM (ؿ?nf!6p /˳K9 ,O?D/oMmZ"(ZǞg\dC?~I"Y$>hZ: X⁁Yx} 6pĆdDYn:uk6  "ÚS4c!ܹXy_9‡ Ɗ%3Lq˔-kgE&]iԩUfk؟&4H{aÇ'V1X'.|.an_>, @TF&vݻ)k֐݀6hs\ 02lLt2"|3!B 3pC;f6H",(r()Ų(.-b0xѤ/K'"4)g<1d{c9F?K0|,L4TsM6tSFL6uKԙO@RZ(٠6QLFyAQRRL3tSN;L|sTRK5TT7QN EVԈF́G 8O{W`?PS5XdUvY8AqYhAqT FysAgXpw\r,YtUw]v](Zx3r^|v_mC: 6:D)jGO>xb+%~xc;p`CV7ju.Vye[5ccyfk#d.އ~Kez`hV76vi!y^kjht넵j6l}P{mvm{nn{oo|pfdW|qwqƩ+r3|s;sC}tK7tSW}u[wuc}vkvs׽~$cw~x73B~ywy}=(z~{{>b{<|}k~u |ןS؟Y~$`e?uD| d`@Fm_@P`e#$ai!WBP`8C3G2d+C$&Q5 XBaSbrт|E1GxF4QkdcF8QscxGA~3@JbFdhCPYFq 1BnNMe :(b<R9)JG:!}PT;):! E6](O4(bD5RTJuTUzjuU]WVrզ ]eOVTI5jTE"Dh@_.k_|__{b[ؿvmehY5f'XВd%Xkm)Qx=QK} 0|\~*F.^1yu8&\HrFnu+\es+]Z7iMv׼ek8(46 fcV̌"p0T/?!@BXR PT@gD<@PEPk@,bx&Fx5ٍG\x2eL;Nd!CyTU#/mL)>c'fVFcF߾I(-M +`:ZxIH0>9t -я泟-hBV44H{zҠ1MM\~|F7f5#<[X` L07klslcYu!~4rU1aƳY_<y7zt`~w]rԻŷnx#Mmp~'Mkk0ZNvqrds_|ўv娎i*v<|7%$s <@H(|>9I׹1ڙ|<]e:ґtZѽ>t _{of]qƒyno{Wr|'sZ:;}azfy.?9v=G#MCDsfB3{GY?S?c?;?t=ԿԽR(⓾;4`󻸻 TA<>[VHg196y9ȇ ȅX*A(#/.h|J%A <!$B#,$TB&tB(£ "<$\(˜!C0C,D-B6l'|78=8c ļ@@C;{C3`=HdAIj@jLT 9MA RMp )@pnF`H(/Uȇx ÚE(SLUlWY[]CE`<TTEVtEXEZE\E^g4Ehi,FkDl\F b2>Kĸg#>DbkGfSGyd}_I!9]B6EXBc*@{rhAA`IE*rJ똈 'HHHI4I\ȌȎ/|ɒ<ɔ䘜ȊIəʚ4J\sH$HT8Ȅ,6)Ծʇ,qn*Ӡ1Kܹl˷˹˳KK, LdKd?ur@LJJQP:`ȱ֨r<3A؂u8J8̙!M,#ԔdM ؔT|l;<\M|5LlN'4[B\H9<[tp<F`/p8(ݬ ,O͘IϝNO |dD|NMXNLNbW KuW/U W؀(Ў P= PFPP}MP5QQ= =-R#u%ί넼d2BJ@:d#$,!(+./R+-,%-CS1eS2R3S59#S?%͔N[Nm;P7Ixd"|E}xјQTFuBTJOjGeHJ EUMT TR?U[@mPlH+ф [HuT;M0T a-cd̀emVVbiłjVVaVcEUVf WYEG &w $%}P'E6wt@̇uHzp=g|W~- ؃p-P~md} =X؅WXMW{WxMB|| \(thMYX{8(ݘٚ׌%Y ZY=ڤ=ڢقڒ]WjהtYٖeR^W_[ttQ)|X JƉU][Zh۷[Z[MV]2 [۾[5Y[EWC%QX< \=W]PυOU]u%]M0]ح'ٕZe_\˭N}RVjd]\@sUޭ}^MHK܍^X==_S B-C\TWp̀Mu3}EM"_u^;M[]Z ^~` nAa! N3`zM_Vaaӕaa&Ra!\URma}!^bEm ϠbԘbӰ Y4a0fb1&'V׀b( (*`8~ 9 **bM0cAF2Nc0d19N q<& EbG DvϠcdOnB >.Q&0RS~QSUƌ4^66SFRvd[WX6\RKXHHO/ e!e3f4Fk5dMc4~dp.I͈bWFoeIgsd=vgZnde{n g6[%fN"jAdTm>v.hrece kgse g]hbYL= QgN hjnimFl>gua尞bFhuzbVhbTvm֌Wcf.h_Vg:?chj:jQl5a3qll(c1j.rnu6b$NFg.FVgue6fpYV6fmwkal40[m .&A.kd3d&ll;AgnX^hefiiߦmN~mmVmc VoVvn]R~Ln鉆oT^gGnmnogpخnFpai6nofg ov.g W pmdIq i>G q#7QJ~Rўo_ypnrq q0c)??Aqnr{p߮냮tk2_kz-0s0hfA?mLn b6Oi7?OK5t16i@t2gYnNM?!toUIuX`VYu\'Z]u`^wa?vl^iQVbsd~ hfSj%vvo_Oq/^n~vwgee 7w*O.l[w_ kU rnSgv?o_BipZ?f6xPxC[fnx5 emGY 퐯Zw$A6ya/zo4zz%yzWz_B_zoz/{y?$IO{{ Wz&w_{{{{RR|x|ğHn7Q ("~r~P%p|aO7|`hJ)G* }8w a`& '}wl8*++"Cz* ~[aG◟g/"?~_%Wɗ¬r^2,j-Ҳ ~+/K2l!Ĉ'R,ְJ E0"+f(1Ư"ʔ*WNqƎY$˜?{{tQJ2m)ԨR)'GTPN9wC~π#N/=< Pz{0(\K֭+ըy-(pb*`†+1dɢ+ BD &/39rk32QrKNzXױg}[7D>тI+N7Xu䢳kΪWn5زgӮm6ܺ a_H  `PbB@}~gh . $ii +rL sDφuaD(.r?%BED!Ғ1*QJxXiŕW`EYhŖ[pEr$Q- : S @I3Tff>l tډ|J C8DԚ*ނ E@K1(@)M+r)ܐ]gQvJ+P ݮP*RUy[e{aG&rp-qT H `ز81KXηYn*ʣ(( DF3w0H0Dq(/K?:p'  +0LHݬYdu%k |$2L[39i^ޘ'-0v{&.Ɍ2 ::?.QOͭXk:&0lCi8ClDFgSv/]ywWrIl&2ܤ޾}lC6,vFDDs4|;Zj҃s -N̎3L}?w%zS;؎%: @!*鸝A Md~ h P t %A Z!/cz v@# JȐ^o-͇b8ސ9$YOT>9WRR`v3ɢuũ؏sBw-%raUP (,p% ~fD F7±rG=qTS}5/ I"B0p? B$L`H$&5ICH\@)YҲ>b@g!g@ЙYH7$FD_*Jh} LaD2LhJĦ͡! A S%,gYIVuiuvƓCbK8[mEb+&.=&KoA+< w~Е.u]rw`PM0t ni͋^x76e|a{8&on Q抑q&LWuaTWl :D`CX u*${ bjqĤc!McE__)nYCH%Ox`l YL\Bs4 do*f1k9791urPJVn9` RId˜؂4 D+[ ^pfsƮHh?fzӼAmi93RVI~\d|0ڱEѪX8)iMlc#fQlxG e7{!Ϧ޶Bp6XWVNutʆչɅ;t6H ` Npn<q<@`*zdke>>n0R8MGsU9g17y-aIqRwQ2F'z^,)}Fu.}GN>Hr+r/1i'ypZƣUÝ~OaZk#:~E'1ٚ<7ѓY|Sɫ^?N^[4t:4A"⢂%9sY>D |~pGnS{~Oc Pu|woYcX[jIuceL_JQ]ٳُeh`-tƁ,9?@f\ZV M`zC\ ])EvL * ꡞ-_`&a_-[A% ,Q?X&`X xde!_ " a0_㜏JN E5]߯x6"#>5=G!xC%e+„e@-(⇙b)T>ű"i+)ي!@H01 ID2NA⻈K+>5"-25zV6 c"6!"!9ҡdQQacxxb}وVV dV$Q؜0 b9.9cB"C.UDc>>'[D HH$IF`dIJ :/BbBcӹOYOFrFO%RBBڌcR&eP>eS^%VnRRE#=f%XDTPrd?eXZjV%=peDt%rP$]>XzF[QZ[%`*J[&Se=s_潥13F^^v]U2 a^&f`f&8&h2cdPReg&kj8A":.ZL0~Ŧn_9Q"M.q!4v?¦s>gNl&aN&)!vcvu`qr_nǭa.gVgHg`gfv] '꽟;_$ vQg_Z&cZ}"}BgJ'`yg.vg(i aawcN)FVf]Y'Dʧ 0nn("ₚ^ho_$&R 㓆^$$Ĩjڎ :Rhbw!bҙiFIBg.fXhw6J!i|,)*TM ]^:ik(v%]ڞJhiZz皺(C](kb(FIz{bj Vͪ*~}j*xDTeΨj 'ި.k%ҨVR8*^+TT,tv+,C&bkgBjQ2+SX++QCPD&~ Β2R,PC.²A&,&fZ:?|BDVɮŞӥsv,ȆClZ,VlVnlޡhkˊlQUR'yf\&ffЂ,J,"-V>%$kAmJmf&%`x-fN-:F#-Xۺm^,lڭ?T-ɦm6qB'*̎;\.fn.v~.膮FnBnRZ.Ʈ.jn,jNn..ήVloݮ)>/F"/&mv[f/.~/ote:$EU(on//+g܊焎&^/o4_0go{CO_koGpE/C-sWp=0 װ 0׃p&6QmFݓf&!Z'p&1)h g!2"B0{A C1pϒ;p1-jy2b3y"+b~m~m C0J0  !pB91292$;<1qh shגqңcw2!r"/؝:,/Cd}MA2031Mh2p2y*-wwh1^s1IJX2]t-s.ow` ,=۳Ri<˳=/@>C? F 4f#i+O)>"Fi7c>B!jt3!j(D$H.0 @MBK LӴMtAN/KLHIH4sm X30/-SpJteE_E` FayFc<(^5ffg,FpqBI(:2g o[-s{u}G~GXHH8RXvd6gcgҌiFFHȋLqG:5dWKəɚɛ\ t ʞlw 74w<۔ʤTʥ¸J|m!nbIv'B#pp pl (7Pw7x Y h ,m|DkISwEv{4CC$JcFi}Mu=NNR5m UT1TUU?# m VC7=?\a{nZ)M^\UpՕY5A<^I>E֣ S);j-oq>"p1I"<|1rVjh~g}VhmXCgf"=2t-_#Vw#w)~n|LWu]Wv5D%#Ax?"׋zB? 4xaB 6tbA'&p0fdH#I$n?*c~csG^ztCP!BӁ 7x˛?>PuErGL=d,c&~$]brک[phlͩkĶz`)H+=d$|e cBв C 93I4Ea1 ƹ9302(J[)dpA!tdȴ 0@G:8lIbxG;M5ܱʯ<Ģ5@CgC"_P ?j3&sPETͮ4 \@3DŽM6PtSX/wA;Y'tjUSFK_MXcV\\|xARŽXk]r&tT\MdZIxr76!%r)M nnZwu^X_~VbaŴ7W4O{]~9vU-._+1 MM(q6x(qMhY\z9ha6hfi}ЩBDž S.s^?4iUz>J睝EpZuھt[)^yBMeP+tNU-[K[z|G׍Nr!EFٽiiy)8^j^9ꭗtT{u/m/ v 2W\_/ǻ>؟E; Sg>D T荂#!o2 O ğAK6bP!A Ѥ@qx yý4D\F"* ڎ(*d#OEV)$IRGCq2X JfT0F5эeDPe"Ql(>X!ƺ0vT"D13bE:bJRDb&+I=vd"H&-BR#Q()Bx䔤)M]^ H_ G9LqLKLgRqt%WBdĚЄe5M6SĦ8@J{]YZKwɘA9Ͽ)NiVқLf>BKN8kRS&@EvFYOПf@I*n#?:~(-K_GLT ]!3}hPGrJlTe-M2h3 KOjU]9E,OuCEflʐm%fӱE^VD+`SbX'L^dZ]`9˶†{cBZSl(+XGl_ٺ;@pX0'Th(3-βE%tmضy݌liuٖ-zkWmz[0B\)۶ Q̪4u$U_p׻^xwvα.o`'ڵQ8$M%Gq<@y`K>u旵5pBvA_ח[bwrcf̗\T ،RƚCW?H.ٯrg'fu7jp K;"0A(i3,'81hmI<0BPGgѪJpj WK H`ejmrhMj N,   "N }n h cbNƎaP 0 )ݐJ"j %[f oa@0(9 Q "?JK ܸBqʘ 30`fqGXaQiqlp"yoQ }1J>LѨRO4F1~@Gr\ "`Hőuӱ9q˱qt QQnwocBC60`֡rfa 6q2#;#Cr$K$S2hX%amd#=$E$M%U'_2&52(k(q(w%R?"2N"s"4A|@,6 f%5!@ qmR,},-Ւ--R../Dz,2-3..2,//s0#3? 9K9lA!4a`XʡX# @&4G4O35W5_36g66I4QS5Y}#d6mS4S77as9s33u39!9t`l5_ "(la ܦ;3œSs<>?@;s36D5sa\.4aaB1TG498CATDImN4SwE?49^DFF3FoEGtGA$(3\!~gFD96da!brIS JJq 4tJJtL5IK>8H I(6 bT P;!xgH_&OOLPP;UeO uP P2Sm<5RCRISCS94Ի.SȵjN}0V Ec a(akx4X/bXX5: aYYuZkZ [b[[YMS\-a\X׵[]UZBCO&b0W, m(j+/246@@ hfA !$-"@ VAQ)Auj(b1V 4c=dAdId&eWv^_e/6c7c?6dGdOvgYf~fAffohuVeVz6o`k,֭3~u.bXaȡA$ad $*~c9ammvnnvooFpMpnn 6op%&rgtrr7sswsM mlâk.ip a ^V.a1a@ "yyzzkwy1{wz!7]w{|7}WH!i0nJ1Q OQ7RJI W.*;naNk؁%A)sf0x|a;xKxO7mRp%W{D,lpQ΀WP֦`]7ְ8`  ?e#hmCxƌMSǸ b8//RrX+Z_U+Ď#.Bi-Ԃ-c`.2,6Y/<Ab-NeBYq^yqv~_)Р떫O4Υ" ݚww)΀/ ;*d7w7Ι,Y.9::"8>^cÜ#F=y7'a3\p\tX.ynIَ$NDOdZdQԷcPQZ\gmZ%SqPy::Bڠ~9:NYEX%\%毟eXeۤ[YqZ"yaxy/K?: `Fa%c &zxԵ-&sLmb`cJFcz\oe[i?uU+h&iiXץjk-[]jX&+F9X/rƦT,z{]3;I#s[qξBxwm&w*\Ëyg9|c(x~GMV"\3~,q\<~.td|scT}^|5UX<4<ǯۚGkwMįʭʫ'E"ţ\+?B$ʜͷeּ|զ\|$΃\ ;b ]3Ћh 'z$3t0|?= =a_n?$attxB]MENOCk[]ld}̙Z?tY׼O٭m ꘃP{]w: C?}ؽf wM ǰV.VqϭŎd ޣD/mj۝=^,ڝ0xՉ~ ʗ혧MkV!k=?/x8^Hz>1'Yllg^ x>E=!=֛z}N^#>)ɞJ1m<^|.T!}î:.1~q5Τ}F 6>֏]ggjy_ oӷ޹NNZG;w=guCyD͗\H ZOzAV}Mht_a-֝Eϧ}@ W0!A \p`BN$xƌ%d1ȍ#Kz$)$Ȍ+M| 3Auٴ)R{<  8L:} 5ԩTZ5֭P?{K9>xaZն4ː-ڸt!e2oĻ|ɗ+B5TK:Y󦿜;{ :Ѥe{ :ѤK=d;VxqBt>P_ڶ/]{-m7ƒkTrǍUlĶz͘4MɓCPF*= ?ۧ:cw(wat"s'}e!|IFz{Gb&bX~*\c X5Ha>[zMZ^fqcRNIeڈVF) z$$F(mΗ$NUfmޖzg}b颟/ Yt.8&d٣t)GhZjv&ą7ZutvJjښz|jh.Y'Oj+Ljk7isz" mҒ^Kzj+b n~n\i):魺KT֋o/Q/" q,q*<͂,( +1ߒr%r̂,ʟ\;s0 44cs?J(sNKRN>/ţƧ13 L0=uf:$FrF2-3p 6M8Q'θx1MO>M7{-+16+̠14zOL^?dpǞ 3JMGq(.ط{|.}S (o}Z@ /À CzߢGXm}0R1a?Tpp `(@0 ! *H!E<—-K!,aS T,d a9QpkyEQCPw 3BP?*1>[Q8 !vϬ+`x08&Nlcibb[f3\P! H_u#Nlj\Pĥ)>`3YɄD?=r{&{?OQXΗҜ8c>!tD O&,R;>/ |@?<ҠL0G_ʑ|Tjn!|o+V`ΥA Z:Ӥt$Ij1 k< i6aΆ3Qԩ/]ܱ#ڥ)!1_as] 9aT-hOI.T :Wl $cuEJve/jvg? Њv-iOZЪfem8}sR = fW ic$$=Q*wms ] $huWZ/+T V x0]ՂMf7tr}w x.`l  Ko{/|v gW (  \Ղ^lr*x< y, d"+YHn(@f',k'.~bn4 xd ϲŴpg" @ zЄ.gC+z}F4 iE#:ё-kzo#i *sq@@ J@jK֟>~KiC? mrW~x'~ x-&t(Hh~Vfe`׀U}wP (RQ-6eaqgS_l`-H`l1(38.48h;_92`l`S&xz~eU#ȄD~Q%Uք PPhSWSD~q5WuWwW|WpkȆmoq(sHuhwk Ňp%WtUfWu [_+{舏(Hhȉ艟(Hh/*NJ芯(HhJp%p hLjɨȌ(Hh׈٨\LV)VhbS%@(Hhȏ)0R# yA%` a`ypɑz i")y]ً1"@b(b#(8 #$AA)CIEiE GɔMCOIUiQ SiB*^ɒ9w#7B&lQAr34-'mJIvX {|w_I7Vaء o3qsIpəv陂Yz2#(>R^b)3I?ie[imIYLU$_r&њ7& <)) a9НYiI ypTiY(yT29y婝əy a乛  2b ɟoG/ &z*ؙ :%JyA)*!*&J#z/z$:2>zj8IʊYzГxIAG1#a`2ڥaHu\*k@:m:.ʦ%*J 6ǤOY")*qVpuZujBd3y\4znA.ʩz/ |-jZJ_h ҖXfzx } jJ˺z*-t*6J* zSjz ڬsz wj*Ǫ݊&گ^ ; :LX83١2YjʯfJ ?[-+E Kߪʰ + ) p: )ArzrA57 I L 鵦Iۨ&1ѨO *S+{z@ &@ 0axKy{ڶnvpk{K+ ;ZqX`˺˺a`@ @kK +˻Kɫۻ[K;tXb a˽ + 狾+kr%a Kk[櫾YLl 8B,L k[ !,#L%l'Q+-/ 1, E3l79;=? A,CLVEIKMO+Q]ڬw-˴ݜ߲7.,ۤMө詾ꞎ˫ӛjm*`=Nۖ ܼ>-rogmnNԿ^վ>Ҏںl Nڊ ^|>.v--ذ==  oޗNэ]On>M~ޅ/2_ܤ/О~,$/+&# O 4}Yo VNC^^o?*~%~9?=Q|t?:oîS/'>!i<|<z=ofox=/no\Ƽ/O|\ɯO/oٯOt.ǯ/LY~3`l.K=>QD-^ĘQF=~RH%MDRJ-]SL D!M=}TPEETR6 L!SU^ŚUV]~u3ίe͞EVZmF UԷuśW^XW`… FX?YdϭYfΝ=khҥMF14YZ&lMN펺_[M3R,Zrͫ>αU&i#v>wxڶջPٿ7vo{7-"R̯@)RpA&Loi p?t =$+E:B8K/CcwG t QH#I$F&wdI)l/H"SrH qK[0iE5k#KHDR O3H>':p4LR9I=%kR@J{A/˔MQGM<)J;U}Dɼ>TG-;lQ<_ US%sP_a\Ti5@+/E]mYqHvn]M7] kەE^ϝ_QAH}R ?JVBSuYL"R(1 iꝜBA\b竍D\:ޮ2 RseX%a)gpɻd-zκWWTtb8E*zPXBц~ZdXEc|cbvRB)!DCe*gNteU oI l_K`+X&Q(y&Ĕ9)gPdI,Rӛ_c79ΫDgtӝYg9Oz*Ŝg>GrO}ӟ9PE?Ps h;Qs4/QRpi>Rn%ENRRn-^S n5inSm=~TmEEjLTfnljTJժ6*U-_Q:eތdEkĚVlm+WRkuūWh},ԲXEyX찍,Y~o,.Y*mm>ZҪ鱥E[NZ֦emv9Cnu[ַnp;\׸Enr\6׹υnt;]V׺nv]v׻] J;^׼Eozջ^׽o|O־} Iz_o_ l!pI{`npI[>/rЁ9<$ 1HLb%'NqGVblcHb/Q,*0$nLrK(W9%S+x_[+ f2L".s/eost=hBЇFthF7яt%=iJWҗt5iNwӟuExFUjVկue=kZַuuk^׿v=lbFvlf7^53{ jWvmnww=nrFwսnvw=ozwmx>pGxp7x%>qWx5qwyE>r'GyUr/ye>s7yus?zЅ>tGGzҕt7];knopflerfish-osgi-5.1.0/docs/images/install_options.png0000644000175000017500000011533212346515440022303 0ustar felixfelixPNG  IHDR,]iCCPICC ProfilexYgT۲f99sV!% DAQPAPADL(*" ("(5x6D % B'y#zH`|`tAwRDF"44|w"X_ PId&A`tD%q<a!V۾aA>>s΅|6#Bv|@amKyYY̅l"b1 IV&""h?zQ̶}FЯG9"XmqF" zw_0hd[f1^ 9p Z0!Ă(d FI('E`ȌpdN8hg?2k$oD65FF3 ۶.#p?kַcL̜h9"ZB2$ h.ZTxhc~qjNw{  M@#bȺț+A6 l\{ocv"ez"/f=ЄༀOyFև޾a ;@yr@ `̀5p`/?H Fx 2@6@18*@Wup@`̃EAH#BB8$@Z!dA'AP2 A)t ݂@ h A`L`nXU`]va8Np)\ _p/ e@QXP|(I JerCP\T uՊF &Q h,MFK"qjvD{#ѩSt3=B/71$ F1Ÿ`1lL "  3bY"Xe ݇==Ƕabaq8;NQp1lIe}nFx7|~?_ר訄Ԩ|SR PMS "M!A(%\%<$LUmөK{bD}b,(F|A\"H$)ttAzMZa1I)iLKE+DK60>.2=#,5}(aZG 8aC,*w(FF}FoLL"LLALyLW˘2OXYLYBXYbfeea:ĺɦ˖V;ݐ=8MWh1[x398899s9s䂹ĸqUqq-spsGp^a )3ȫ[{#K!;ɋ|\|&||E   , Z & R :!-",",|PHHȄ(IT[4RRtdvʮ]w bbbebⰸxi U0J1Idd~RݤKwKo(ʄȜe5/*MNL[LnD$o$&"UA\WsEFEKŃJJQJW=˕TTlTbTTTTSRQE]R=XV}VCDW;M~M9I-YIm>mv[:3tt/~֓ыk[WOo3@2:2|mooTghhϸcbnrd̔颙YY9[ 1(VK̲rJ*56.~e#biskkc[fN.ٮ۞þCøccKN+Γ..).-n87'n˻ wޣ'{Ϩ{{Cxx:{zS)e/SrEo}>:>E>s3~~~s% U[Wo8ԇC=Co1u'?ȎT,\2 EG0!a_hة8x a }b93IFIykOKHJM9 z eMd23_{sfkwVzֻi8>x?G>dfO<އ=Rzd|3ǰŽ>^S@_Tв\[أQBI ‰-'O;~*Գ2r>蜹Z]Wl5W WTa>w:}A¥.nTUOt^Rt6+-W%gk y^n~ʍBMMPsb̀--OojoUom-uߝweۺt-mw.#tuutvHѭ*o*6)5=Q|ԯ<<2:T!]##Ϭ=u}>gl!/{6>}E57O*Mޝ2{kvק>>\3g47qO?~noeqk׭oؗ+|o_Y~#J*jOݿͬůK7vmnoNlnmEP(; a??U#5+R; @h]SH d @DLwauQ\T\nt ʌ 솜(2'_`0QClSq^cҝ2 *PPݣެ1Ţ[wOΐHisi9vΙƅɕ͍oqwR1/!o^v_z??84&eXس𑈡Ѩ詘x86$4+%)0!#̑g~99L{(9_qB"GKO֝U| *cw]V_c{imcޫ9 mVn775߬ou]{f2T\b~8A:CNá#V]~Wzvӭrfgyf?} [d˗Ŋ_'//|>#oaU{υ_k"-[̭-h֒vH1AM >bBբh; Q"n$f f&a+0I$OTjkҌ2zr G*TYR# jjZkk^kb0n8dj|$4Bʒ ezܦǶɮʾ!1UMj7fwj=/P|8}V}݂4BH!?C?EtDދj{-l|^BBb`>dT4t ~xZR>=ԝs/F^#uG?>6q|]Y,[bq"4S/˱W\8R*|ㅍjÚKj.?TO qzȍcM71-<[~O7;yjwyvg\zksCCаH^h;ExK8M1<;?|B󧋟K,&|5k^ z?V(sWMVab`E"MO*<C%O0Eh\(>0N'Y ggb^fUg g/U"3 _8&#d/ ,$:EXu~~׃hl K W _h)GǏ&%f$K&%ϥt^HN0/\; C99Yy3d?x,Sg/ԞQ:r{si3iv[:ot!bM%Ra]+?Rݿothjbs6su ?tzCy}Z:,>rtڋqWo0OC3sSÿ~Wo lwoiL*p M7/"ؐpP(tATtPTx !< IAR*zVaZXֆ](\ 3(*8:z@K)$ L,3cs8 \8 7OPQ%QxфGdDa,R }"YiDh*hht1%tYnl"l~DFN.]$Ey^mH|yf4O EEފ^&$!P∤YjAY搬"Ei\WjSŚGru3(2,7}qyU+5 Kk[=u{o{<|CM#+{Tpdȍ#9b|bǣk~%ۥ\JLߝq;++s^?r>lTl0G=;![^/Nr8;A9!zEafђ]Ib{5%x$6%_KKC<&,O!^1A)^9Y%Y5S-O. $qCS0bVAKX+vk)}[(W:vkƝv/S"%k pň;Q[1q= ԉIRSmӇfex{PPe.:/Q s%2'Nm8{X}Esj/^y[_y-bV;)BWvi_*nՓ?\ojjhnjrnϺX=z=z+siлg1C/^zV~7Y0uK6?H͚~Z0Y ׆oYKHqGʧՋ?a5mWmnn l?O^nQi?ZFlZڨB ?Wl c{mЙ}L<\ pHYs   IDATx|O$!! !a62DuW{֪[{+%C@7a ?cmks=|=s˗o5֭[---իgUUUe˖_~{\|p= ¸ui'۩ÒF*SIV=* (gg[*,i39O,gUJX b!JD-& t4jnM8O< -mҥ5-E3g;wnhH[li:t/qf6m[.4nptjEEE_…ּy}Z}Ue[ǎk%;k:[~UR%-%keP[GJKg[6oe,a#k0ݦcVw0+2rI~UnV1N\UiV^z2ՓK6AʻYmQ:JkҬg"-_ԕׅƦMO+~YІUQbi+0ݺUo`eAiK?ZH(͒TY4hC|چpÔo_~ӟ^M>>sk׮]PRYYY6k,+//Mnh4kѣC\Eٌ3,??rrr ģڴiSM;JKKf͚|W4xuMۄ)se6cp[Za BGB1+t d=3V c~ F bKtxkܢ5 Ӥ\NΔiKf}fb ҷūI&V&Vڼڌe־M )́,zmE66iTZieV̵wyMl9Em0;F yFOb'LE]ڦ\f͚7(PƍjG ͋Dd+~ZM7xUϳfEJ 6O [NָQào/mժU֣Grss{`VXXiѢEVPP`Ų2d9Yڴm.\0cB. eA{ʕA!V:oڰ֖y3>O.#o׆u۸5̴ulʵVPLtlM6ZJk֢XhKWڑ'cCC|Uy ~v+϶ʭbSmObzXfVFL=nbM륁ڰv-\02dn*%y˖ ;g62;,gEYUZM=؆jgmZ¶`H)_s֫F{wRKoJ'gs6goVjM?Vg6 &GfROUU[-IeO zVld$&QVXbe*& l~E۷o7۸vPiM[Xv-a:Ѫ +e+f+j26^yӺsR?(Crfmފ5ָf.+lOB nC}***QFA6kۺqƶqSEפI`Tjx B~9m4 ҡIaIHjh{{i;;#qVM6FZkUZz]l]Z`RVec?Ǧ|27Nlעhpmm)cGejwl!6xw>Ti96YA+)+JteqhN`X۰|lVUlzu>{ЉC˶͎v[eI/#:24"ॵpx+ CqKFeAU1FYV+ijz|J+lʊT禲֖*\*W,]c[Q8m.hͲԼY3unS[1c{oJȮM{Znkì{^ָIZfZؚKm6qfW)E)`jZʖ-fgS>[ic-sYam,+b</#'ofʳ-gcﲗ ]"7״A࿠P>(&i4P6(qapt,Q)FKamd [X֦a6vLӹ>>ʅ,EW}-ԶM}GlFiBUʊVQY:wjxVz mR[6VXaKknM5?o5JY#+nT=)Me 6\d lg_Z+kaRkޠ26Yb4r`GM%lȘ : mI__/]f9YVN^hsKm5ֱmz5WjJyַm]ve"hmVZ DeT<(!CHxK:C^:T׸AN*Mn֪@oejZd 54L [BC֢Swֶ͚<ɖ3ߔfe9e h!|ְq3 gKɭ\ɵ dl q e1g4TjS4aѴuRΦPfdtktYC[eY6-mᬩ6t[l`l7qU/޽{XV,bMQ*m;u܎,,k9VVجIөe֭]s[ԖiL4?[6tmJϵ٪9SmC=krd՗jg$zYrMb[YYh3|s=oE)3g%!Þ YZhcT)&4 L P^ra__Y%~N1\*İCid}UNVP6de%,&3IS$Vt7\2$*ϴz②`y`G6q|Ͳ:K[J,5Fb%oUŷd!OxCJ[Kl"_ oEigFaLm~"9oU^N"U%V1vnu> PA%&)[(2/Q6 y~u ?<Ƥ;sGR2j$t3<<+/k˶rr<. I6w8גWL:/FN ZCCp=ݭ o=\/ѥ{%:?"/ueK8&P-jJE$PQ} %R`Ztv'*L} %I ȣQa($^/(|wu]Ec|II %b ̜9;S~} \"q(qzZ2^ޞzK#zN#Y>Lx#qx{o -ǿE&rb+v.c"#-vv}wنߡhůگ۹Mk+ҡŋm0kdis+?/%^F#{@Y. q]Ca'Ƽ?\~@#;Ax.1xxe^Fx;8^\WOspOsZ@y4F;9|orӜ^q1 iKr<|O?#;ϋ׉2Oz8C]eGoFٖ%E5kP)Zpz:et{b{gi'S]Sa6Nҹp6`@pXo}YA]tG-Yse ՓqƏZWuc hIsFOgC^B e/s"m:!)I1F}p\\#o㒇x\?< w~$#`dٹw9:Pӆ|˂<у.@Z2+YEoM%gt"D}cR {mnn97v?R[lwɏl֬K/[ZTptyvub8۩'^,J˭}~_a] PnJa!747H|(q,¤81od-5N#sVף0ʥ8FJ ;ڽݭ^:x{{͚wv r54Q6gw?]_d- #f8,Ӧ}tӮk܍'{%\W; intsl"9}6n4cMueE>N8K'ԷVELs[RZnoge4Vot0 -q =1<N; 8h8+9jӝgt\\#/&.FN|N"p9cz$C\W=F̛됌i.c]Yz1׆tW'RT=KZ>>o׆jf%`ޖ]J 9sكwj{QvQGjSwC{gtxk[!M:Q {_lK|f=e&ش`:֧KvAڃ:-vy֢EQPXZLkr$ŞvX `l% Us4<:KBtc8W?op=?yc| ڒd j?n2^<~qM7װ.Xk֙[M3gzeڗ|ڴnke5{khz`'+*ns2mլ:RנpESө=xǟmt<[uX|P80Z bϒvwjHN_7Ū^O,$ V0dVg̣L=D,ZxW5 Ecu awTo4Jiy?q2PH{r5ȖξEsZ"oؠ֧,-xMjNO޹=NQxٞ^[8N+?2XΙj3XGrU*%>VZdY[y9?^/  =WìR&PѮBmJb ""{y\*dʵL~;ud<5jsk[VJinΞ tli:'66Wz̎>KDttZs^6kֻWϼV+>۱۪/ԃR Ya!!DJ1rr5sʿy>nce@cNq9q~❆BߕɝtK> NCGCA5{&"P?q/E\?CN0MqupvmrByfJaII͝4S:9̖įktm\60Ԧ%g(c9ZST[.XjO÷C208^W~^tyF֐__"Qs]>Vi} 'ۚke;D66ݡ:|v]wXnp;m񖯣u^'ohtU8Q yvظI[3Ͻzh3 mxx;ڜ Os=dw֦GmG>ۑD! `9tvV\^znȓ@ 5r87p.BGPNKFĕ~0QO,uű|bivY^{ J|# :I"u 6a~,5kVǣ>oC'xo]xP /+7m]!tc҃|(`Քyϡ'b d꬜FPus-VTSNUwaE[H f\V* r?ެX@whe/7 IDATgWZ[R|q7 GYA&rejMrmvY=5]oív/vZ-DǍǟzN;求ǎof-8GL-ux-o8a#Ga= I 7|Gv4ҕ̧ .[`:PVhA\2{@Z隌lƺYL׼M3ݘ%F z:E . zZ_u_ +AWhȢ1BrѓqSdV%7 )O4:lB(Zh5PUDžL iʘdrкeVe(bÊKڶ_֦][͟ ڈ2[dB}Y/i|^& WkpZ\tu(끕{ųNi:AԪ0XYF6ՙ[6ftY$ f _<4 B fsMkZ4oEw⤄մ OUzoPoPNZ'xRXnc;N?d=v.M\.ics}g}eeaIov`EGh?K6hmVBv|9g|ּˮc]YSMCd{ d?kdխ楱@WXH(ޮ5Pb._7WUY"VY-m?|5dɊŖˊc"@q:[RjK}Csu2c&%G9^huwYl.iΫa ~`9x7# JH&v. 5u-ӖZweJ23-8^ӎPP0tER^zcf"Yyz[t9z6\9=!/g6&AY2Dc~kNFʖʼ++WfR`ڎ崲>|A4γ.L [b[ĉvXP3O;d=X˞~!U?=tɭP_8S*l6Oh݋ 6p ;}I !. Ј?xl~gKpuA@4縍#GԙMZyL 7? 7Jw ԅbt9)_Ϸ|z kWFQZeOw5ՉY7p;^btY.]lCG?zA[kqf5^^ nVf]TAAη_ET5OQV!"G7 G[e9Ž?P RҍκAFꝶIXBZjOnW͑jUhNX]h4ityBxogQi{];o#~{P=Blۗ u^T7 ctM!}vA`!BzavW[IRuap/p٥g{hCYK]u_zinϼš߮ڏ.04pѩ5P-KSO9ٞ>04qn] a-fryg#]pY\n=r$vOU(elպu, c߳|f͛9>\PDۭKo3gU{nbd;K/죫NX.ŻxpCR)lמd^+/~/KkvI6+, CP7)6,"a;HQ3us/*xEO?ݚ5kZ#պqʕACd5 s9R N~GAVpnjN>ZypV4r ɕ---\ÏVq2p݌}V{[?;د#2.8\Fqd 򀩟O?,YPuċC7:b\8_I>`:#¢8_ kGrۢ7ZOFB9p7޲[d:thƸK1CWg1criS M5sα?(sO=>wb`s ?̐m}z5L69+֣.V_ h/7Nʅ/;3[&~ݭ>OdtaPl燹>b=uЧ;@`>vutR]@JN}؟w>13}L7Sj{m G?"V9),/ub7rX1 b/s4نasG&gX}w漏fδϻ~|uMz tu3N;UyD( nl!um֪0"eV2~Q5z\*LI?Z/\%/s9vm{rtRr"p E{jc?|O$dkX 7"KkVJ1_ꮐ; w]|y ,),`$x\ t*n&?bX[mH}0[CxZw޻MVl:˴c6pu=pAj.9yT:Yۨ8+i.P&0Xjd8rrV+,}Y3u|+_f{uncWgY&-Zj-5m"kuyq`u^axՄRy t%?s~p]»P{8J_E;֡ΟE F:_,*͘a<>A_P݁xGq=KoڜޒP>! wBJ̱_pz5!?o\]yܧosfQ[ڂ;:I{oXG) M.]:LHDKT^xyoN:KkP#|b'M [[zk-hl# eb۳/ےN Yr]S_:'X9Fݢؤg N7!Voي65S7AM[o_7.:JzU̼|Dπ8-ag> pP@<]N<%y.r\Ig)бc6g(vwG n=Í:,5,u.80~9gkjR w>DD-\ϸqui0~JrzJT#\itT?Z7 2})n" .]::05Ai~ZˡG.ק xD㎔k3\ ¬|ہ{˟n V$+F$8_Rڷjfr_b}uvh00s4ZK>4(CFh2q̜9|ǝa5л4tKhoOخ& —<-d}l.]&Nj?tsn.'E:|3&ȂK&`1aެjyw4XX4~]wbSJ󃏇kOK[~45M^Ф%",\d5f]bgj h̞@_jB!ڋѣuMRK. vϟoY{$&H4aCsg3$u~k ׫ T/,iC*1/4š_ELvK+hYnA1qRm/pܗ t9+5]}Ym5i e%L;Rk>񸽷Aiײ$)횅}k2^T KQ wjV =Ge/תNl*<ݲE,+YָcG[ ڠsHt.׿*&k< l^`ٗk)lgZ4ժߪZf]g%bo* g)Pn˼^@&ҢrrT{|]ԁ4OCdg0WK.rYuK.uYikr tX_]cfӲm/WhXX>>TᲊHԙɗPi aKcYO-4*m)\:C8N.-/s|N#`÷(9zr5!^=]m!; V(s?khtcLzF!~ t)>7t}w7ޤBfҁn}wy9BljA:e_Hg\b 'dk㫱ڢPd,>nA|niѭSR3 Qܓ=UJ<)ʊ"Cڱzغ:K_ċ<(9G=7[vnV^OXN+,~x¼嚰Eyc!`\ė!G~ҙJspqq y`Ky x<./ g= G?R-?v񗡠tM5)RS~Qϖi}lWLF`%WѠGx`2 孩u?ewʂpz:|CxzqmRݍGQ{~mqt䅲oiq\ FY 3ζӴ3w]sF׾Ay3\o=z\XǛNm ҆qeݯoIf5s O;l\C=fڝ\JxN+,odXhǍtoH'LxN26aG84D!!yKWH/V 8)$jĊe:/v]ҽ^BK/idZVҗ)42~/Wq/]1z٤;8Ϟx\'t^.n2[~dx Gyz]Ӕ=?9 Jlm]vu.l֔%&M'MVK;[IMt'v7ho:|9䔏R]]߲ X{g};d}>-CwRֺt@3\\/7/]0݊54C|ug:ma7 8<pK%nx^91A t.eR]a%{~/ˉ:_/i܏ 7+ܨm >ZМ/>4cεca9^/ f̘e-} loȳ|<{uN@g3JX~{ڔ1ˮ&cC:^wW{o[GM/-~| u_VXFL!n{ChZr7\Qv<$a<%/ Ã!_&/ܸ q. W n BFy' .'\dA<]Ep\Q4w -򠴙I,h^n| iA?j {ytjϰtj[QCY(tw+~.S]oPVsW k~k>B`uяޱ.\G^xN wȚY.5rYrW Giޘy<'yC(p IDAT^a/;7tp?\Ax:ysk<9B7v:ov|E7{:uN&8q*4p(tiYt\ZC# 3V^oJ5wv58xJkNĎja'(̮Ӻ?o+9RV 4+1eIvBCg~iYر]jx,MEzEY"B_8 cazp7nT.dy t; tw< '+z9͸nN;M>/?t|OwJ/aˏp)˕)xwI5?wq΋U 0u^f2Nqi @CݣX/etUC4K$ǟl'WW^yN:buɖZ{CEFk~wgKXx}4A!zw`#x:aoL<=0a =1?|xp$4px~|Jyr>qq~^Fr;΃y!%/q0y.N%<x<~=8;ie?Ow8Ǒ <)Bۘ\,pޠ/Z}ke!r, u$9pVsN9bWX[bرGi g>mB pĢ5 >w&),,(Qxw>7dmat<4oɮ!8yqr-\Ҽp8<8 x<:xZmyHX&y}!i;]A$ӆfL9}äQ+pu%?Q6"ʥF)NFvhܨ r;mKi] ,i_bgk+"#G@S.-IB9B)g_5N+,(@C7QRH#=n4vy޸OtNN1ӝ. ybxđ+~\q>ӈ:Azw|b?\^ziO>cMk\Fd=iilձ>lwppZ-Yaw=-0*) mtNXlo]WnΟg딇y(>XҦY+WugY,d[hS{kߢ^g]lPt؅ ٫Z0hʄ@DK%ظur\SFЇ_;юp+־gz1 ¬9H8xwkKK!XnQ@Nvk<:NJVg17:-e*>W^Yc8@j^4w_]6SL֋τ~O]R@J) i L>us) $?,؊#ttrn$HcqGu\^bd\;=/pr~|qLy'@m8Nt&' F1~mwļgc$Z >1D @,WL %/,) 4nx _;J4x;JW~GF8dt@_-JOI^agZ犩6EQ:\ʭ3QǧUѕtH'%x8F owG8ЁGz8m\uBQqNissu+9wnAltԿRFtuDK?%ڇ۞x~_|E"8G9sL1NIG@:4(N@С(>]ƌʁJa %ZaFǢݬsx6nha:8VwM8^{5ȳ=ukG][{vmηNwu]֫WБgy&( &ڟ}Yt^,ݻې!Cer](믿k;e[o V>E0U~g%EGӝ(|AZaaa҇ {Q,ХXA(\)J E |r{Gꫯ ](mXo1rDf#WU ~uCM$XWW_}up^yбJp AG$XZ:2¢q-C"V(L]DFo>tZVπuAp8?ʄnE>b[{Pe >@PHeVZ'tRy :tŋE:Ca9f8 z-Qn zQO E[nņnǏr2f7]c($ב@:СCB@qPNtn+ÀGʕ+Cat=y۶mC(*a1GXEXkXF ט hQ6VSO?  {'B^,!/ʐaf?` =ʀ''Eq"\]vaSOXQ^ԗ2B#aϟ"h7) $HSߊ31+!tZYGI%TZZ:*ʈ/aLFF,,s:Ptp Xj(*p^Q0Յ"r}^ #4MʼnB+)) ʈ:+)8XxXS(:b#) $PdlE 3({A wq)HI %m%w<8Ɵ7% $J~?4Q(:=$=Om8ΏuqIsF8qb'RRSHI YAa%G֕+ORJ.U#Q#'%$:RO(%R%/QX2q)J) $?PVL3IRHI۔7(+8_m2@JfʊEf&.!YyyŚ7᡻ 'y$Rr=8p 3($6aPBQ0Xg:9P@–pWp# [JS]Nq`"{#芑N-x@x4JF'/E H'6@?cvgI:byz,nox|矷Ν;^9Nlqb6e|۞) ءŠ;ߚkdzο免kn:+lHƛ/ 98jS(PHt8ZM\J< CS ұQc3 @!,/KI,6P,Q셄&y8塐3QF=eDw1FK@:$j}OՅ\\Q=6SW,aGxwdI8) Q%h(:>u;".ΠB q_X'yš"ANJCAq'Lp 'DPW a)(9Nt⋍ Qԓפ3G82QOP!?яB~Q^n ^u߱<{P+i)|8pŊՅuH9R,=AeF+B$+#[kf(N#2@1y:;gGQxt>?'?p kci@(|Pt(;.(N4Jϩ>{(h?,Yg0A؂7O~qC:eDPgyf͉~xP`UX>C b ^wyp`"1>.;2B S.ՊQ5Jw]4Q?) ZCB:> XXt": vH#L:ʁC,'|1XMt(4N&Q຅ytd~tR,, 4( M,>}p)%ÐBQteB<[8 )!*y@^Q(>'gqʘ2-Jty k?_tT,)䔏2deHvv  œM捏RbiAqСCщPn1ˉ8ȃE8Ax~‎xY.8 T sG~ʥ0Cqxeyi:|iHeyWN˲!ve2CFYƒ.ӁqIw6A{OY?Nxhj}2$oZ8 짣^s sQTÂb;+-tX8v<5})VEX"tf{ًǢɢE CgO JV4 ,d5: ZX1dȐt(sĉ%%%a>tXBL$k?8(uʆ6uFA.(?`1+G ys-xEaչKra[llAb&$/Y@K^# eDyY-V[ tȓءt"0l@[UAiӐЉh(_~9t\:( %+`,JseC^ڄ t62$c q:$aexwᬶg+#<:Qb_}h(&@t>loUhaE1$Ҍ竨326JSEXV΍lXeJ{ > N{,hR>"?G] w s=/˰g.g0댢x ԛmV~Mv*& ԿE |-ENV.k+G:`NvNpҐbR˃e`p }:+s-+!=lʂP+Q@ٚ V DP"C!B'Yr[:5c>eAwjb%PL"!~Q@ԉ4XdZԟ!&`!J8 l%|XC|?f%~ V%uc8u%F Շx'[l⇅ŇNBy̗?oH$$t`+p}NIå{ECJaGf8Eԭ[7꫃bޅe?MJ K4ѱQ:?pcʰ %6t06KxbHA/?%xAȇEFXY(\?V?0̂_ꏥGiPҡNM|ICv 7 ⱚQ\8Xe\}ـr>U2~ˡ([E\1;]!L-eׇrpl!ד4Ky~) >Ѕ 7;JKI[RXM814b;=0~=.o{ U8xx\ 77]cyk;-?2#1=_E#ƉqST9) %𵆄(&O G KO2M-/zc'td9 IDATI.?Fs_hieElzFPYnpc\CA%0,Nő ?FL!h`3: *:4H7"ko_V򬪮<.yߓݛos}?l68%(xy}:SGYɳ.y<(f<>KDX<?Zy*m9Q# ^ago*C."|kAH=nzeX s>mǷl!+D=JQV6<{`*yVH䓑)lpJ#z$\xAY</K L<|!E>YR|uQW߃tSVKh'S&pO"0`r*k\ d~='m3Lsnp/.k\^Ñ9}swzҫ#z 4:y y[DuG,~h>#zݓH"6Ix;*) Ay)(N;j_9c+qx_Q5#dO!g;QJ=)"djWiѦ:!?nB#zF؆NI߈nB?/0+ODF>z;G&2|ɇ=ɔ/.GVԥ AMN =6HXa'wqpB3ؽD0o:>qCI9ccGG>v5m՝3!M:Cv;nԖLA`܄`q‰nE0pi7U^KFݡE&#"m\L2?HEX}IWפ@"0q"$S$)J"@dn"L!Pg*@"06IXc㓹@"0HšB$IX-jܐa#|8!xۨ3# 6&S1 ˓y6m{͆ /zn\n<iדl"s$ƒݶ=ǻ^u1Ŗ )o}2;dJc Աe\8 tw-b(e#^8fE^h6yq8mr VFxF;,-`~V޵ [j #Y$*~kJбE,%C&%o:y#25ʳVpzQ1>2t7w^]cxE2;U6N=6յ>mO"0x"A)˗Vt5v.u,SlW?.~g>S Y2png9kBq$ab}WM-˙:]`uQHv衇VրfwU:<ȺF<-ù-rgTٱN W]uU]OˏjDlU*6K-sYزVcuTֲE__kZс~D1z[X`ȪG*vXȓo}ħW\1,[p-kLTG`cX0rsg}CYTXAYT HB{Ds~⧺uT`e=.x饗VOH3ϬH%-Wc!@5!"ræ",\.䒪3d\IqgG?*E@a_=)es+_1tI87TYʛɐ8 YR81EP(9~.ɜs/V=أ:%嘢)drG.Ӊ }@re&G#?$2A,1pLLs3Q=b@vmL/+O7E?c">8!'}{+vAFpO}nW3O"0E8s8:gA)PR8gQJLÈP5U;Nԇ:qpImR8)(mwQ9Bm#s=?!QDEe"0jC9>=L]tQ<,oU }D+9(bs~9HkIi:"(DG.k~”<I=Sʣ>,m0BDƒ$=Z0$S1C:Q! s-"8ga8g|w.dpvHD#+є 4D NiXypf|Q"BQǤw;ATA,D\٦6~:)CsٵME>jCd "d+a~m.f:jqX;D?9'd1ÍYچ*($S 1 5m9A;q@yHSű2 !*+9'|m(#?ڊct|ui1"~D ,%kvD_7'@$aufJ~Hߔ$"!)*HE _|Sz"t@V`D $~M@"!IXD_7'@$aufJ~Hߔ$"!)*HE _|Sz"t@V`D $~M@"!IXD_7'@$aufJ~Hߔ$"!)*HE _|Sz"t@V`D $~M@"!IXD_7'@$aufJ~Hߔ$"!)*HE _|Sz"t@V`D $~M@"!IXD_7'@$aufJ~Hߔ$"!)*HE _|Sz"t@V`D $~M@"!IXD_7'@$aufJ~Hߔ$"!)*HE _|Sz"t@V`D $~M@"!IXD_7'@$aufJ~Hߔ$"!)*HE _|Sz"t@V`D $~M@"!IXD_7'@$aufJ~Hߔ$"!)*HE _|Sz"t@V`D $~M@"!IXD_7'@$aufJ~Hߔ$"!)*HE _|Sz"t@V`D $~M@"!IXD_7'@$aufJ~Hߔ$"!)*HE _|Sz"t@V`D $~M@"!IXD_7'@$aufJ~Hߔ$"!)*HE _|Sz"t@V`D $~M@"!IXD_7'@$aufJ~ӯɕb0=|f͚IL;FS &4~9OΉ贱u'?d1Ν[IbڵL2@z gs'PRj۷f͚M"9sT}Rb6͞=_yu٨8Ih 1~6ie f#{m޼yp:-GshA( e˖g<=q?Ou9F}<:<&Hq@vۭ.eݺuN;q{」4na=d[>jR!UVkrK#՟UtXzu}ؘ#ɝjf5gj]7!©rmOz?$)ӢO44gk*/fjGփs?n|amkM{k*ops.:;P NWWZ.r5ז-v2SV9h|DISO=sGk֮)/jt+;cJˏ\_D[o0L_b N;5Q}`=gWU 0GB?84;TbFSe-\T~GHXirvH,Y:FeAl ;}ɾza;]Cf8n}[X顇cjOBZi~ߖ9>+mζkȧ*vZ7Wmٶ[o}Ux9؊>4Cwx\m[o]ˍ?Li{щɒmT1tp$ O(/zыʃ`GOS䮦s0y2o&}Z-‚.Bwpv$A7g0i866kqd?kYu(saMsM7W==6SmclUe+˭o)eh.n4ڔվ60ޭZ/4sif+7&{\]8U[~-NEN l<(|s)?Oɝ3u]W8Jz DSt3HFW]WN}ڄ61'`pǎچR}ݫl}/zr}CM;n|[gUG[򑏔{|ؐ/dniz112ilm<)kiOXšխs.h#!F')"z0'솏YY`x>Զ$3]oc3c y3hcO1pZt7Xt1RB*]U (wc# osD$wEm G{|Qc: `s@#d=d" WxUfo "￿|lv)A88'zOC㩍uMiOX0]D)ě#DMUȑFszي\ES)UW$0V~rM&p)i,;x2F;7%CVXl>(XHm ӗC{CO= j ladŽ S3)L;X7<;c+bl;F~}9SI3g&S}Xp(Qhm1j:^&co k Hqq@Tm qm F$9v@X1LG <TJHo}l԰a,.ld1dYX1r6vSc}&ʛ˛׌ĝqM @"1AVb9V@D /1nkİډ@"!"+de!GY̍$NQ@"01D< Y ?p6?2lIENDB`knopflerfish-osgi-5.1.0/docs/images/desktop_list.gif0000644000175000017500000002423212346515440021545 0ustar felixfelixGIF89a Pppp, PH*\ȰÇ#JHŋ3jȱǏ Iɓ(S\d-cʜIS˚8st sϟ2oJԤТH$H`ӧPJJիXʵׯUKlTfӪ͊v۷OkvtօX~[,YkE]x;f,91~/c֫y3Ξ>9-Cǥ`K͙׮҆z_\}4V¯&_k7ĕ:OOVvۂ{/:僇?g'P=a矀j5xy%j*iRetI aqֆ(br_':gaE!W%0R ,2{ &l-8Vct"I[z(%U=jIO S(&cf)hcGeVvUݭi%IWuI&n=8 Yfj朔!k9|cv(i[扨1ߍ<>zJߖVhR&^*%롙F#0)Ƃ%: 9BVh-S*쬦"ʧw&;ذ;%F'`Y)(grۧl 2& l ۰ 1Gz[Q[ %<:21^|z΍XrGּ7X>ܢ%-]P;4itCvjIMgGvqrõiMbǍz-HOf?x+x4y_yC砇.褗n騧)1.nw#?3?H̋L}(qo-.HćN~$җ?<2?Ez;XS  XA Rp` ~4a(~/,!GЅ LN2aNy 6O^(@EqX IյˢsNoP IF3rщc˸?(юs D|\F+cA4Rbԡ(A>Ҋ7$FCjҏE9!R e!?NId!UVφd'!Zk$o=K1%gчeyLPDI_tH<`)MB^d0=M:Rӥ$IGfbT%+C @tr&'Uo/Y?*uq֤3ER>ta,&;GzZ4u (Eg)Ň*3(RVԠDA$4%ԗct;kOԛл)H?2Ai+OkʐOMj"wTR]%kJR´(LղՂF4MLwj՝ۤRiB6&j=(>"R7D/:M׹Z.J Iloxk¶p#DJbD-CXZ~]/H>*U5;[8 T,}ʼN=?<?:[y'i;ҭҸGV1 W'Ik}TUtgTLFfŗv^}]exWdR(g<K·=>R phuR[{7|JQx؅z UzㆫRwOhZ}0Z\ËʧzUv$O(͘|ȇNTi|t~|h~߸yxkȈE}H{׏qvf Y}vm6fhl8lgHWEUfT(kyvN5gLJe^ݤ$XPX[1[9cƑXw榓7tImip9h?yHi:FLٔENRYP9Vy(QXXaHWqHUy؆%v[ m5beggV_>)WwQv8Ue_;'DEsyɒ`D]5 rʢhkIjÛ{dgJP%;MTj|hɘf}ɠI(<NA)n96R fK[{4βxHIƫ ˚@ >gϸKK-|[?p1 ݓC `mnG[,NΎ~q>=ר*x+̜$fE*c.3hi#/|Q}~==  e[;R|uvȣ#j?co|\iȵ+C˸,nߜsS~ ,У\{Kʖo>?: 7#˝O69że~ކ.Ta_W j:q`J|Ё>F'ߎN>_i[>#PQ0cvnlH.dÆ %J$ +QG!$YIb i0"Ux0M#-)2AsB%~vn޽6-ݦ̟ʼd˯'Nݷ쎳wn޽N6ǥu{|"2܋ͧ/$; ;)1 *C8?{j DST:V[ _Q7bdqFsԱ1t 9!4H$TrI`bI(rJ*SBK,rK.K0K4L4 L5t.لsN:N5BUtE3QG#RIJ3͒RMA?OQGճTS RQRUZU5LMYY}7sPN,a1}uCViet,5UkuMnϔ5\l$QkUKWg[HKgcWw{w^yWJ7_ _zmx\wb;}8ax-U]Wތ׵wr7cnst]!fS9bI [[Z;Ιgfh?误Yi~9f:ItU`hvP:f~?zu>Ŏˢ{X9 ^!E{{enYfzη'vDM:sO'SS[]%U7 rb#Y}g-.}IUP$< }hx`=FRy:cM)B~B1 EX,uFÒׯv]ɣVNV4SʐIUyQiYh d/Y찥2(&5Qgk *9щ Ky۝Hx+nR#F%{+\0ens\FWUt{]fWEnw]p%oyQB$5'j]X󮷨lozseDo߳%){KDZI9iG)e愌l:س V X 1-Ƕ+2à4=mF1}1 Jgi%)Ҽ/u+r YAMjG^RR& U N[hԭ=YM!,KY}L/WuҪF;Z+_5O˖<0&q }YρqY}ؽuM+GiNk@lY=_Id󍵆6[fB:d^Y?ħ~;`b'ɾuluB۷v$j_[Qmp&w3ns[nagϺe죇{ٴNۓZśTҀ݋X/I4:QcՑf uilq|˖/'K|0!]{;J95rSjNpղΓX9"bCc>fkZHG'DVVrP3gϪ!ܤ7)f2;*\UU迏yy? sNcNT]:wzˮtsvVvOs{2}vӛw,ҡN1NƧ#84n?Vd=rLY]:GG5HW}ݝ;گ6~o! mCS/8; :_<گo&S Hˮ< s 9[&pr1+ @k >9+MAQӾ={)\^p+81'+=x뽟BР|{B1Į<;K+By1k; <~R[kC?[E3+ĴŤFA3YEb2$-K 4t,h)$Ex*=&ŴCĔ-ij& G5ķ#EkŽBV\6nbQ`&J_S4 ¶Ä2oGKv\fT% 3@HbH6HHHIq3H |3{{pXsd9|O5P,85 %ΝÜQ!;mڒHsNʼ'l A˪仐rQ }Q3|Ԛ/EM;>(ktG#(.DAz*QcIP.5ʹ>{L|5œsJSL5l͙D]DѼ,eU=> (dM̌:ǰDgԥQKMDAcƤ{FM]ԒdFt-NC=TGcU,W|DSl=(<,TT 3Z>ؚtD苹6}E@\R5Q}2 UL! #yё%CLΗ3Y+ R3_O6x_=5W7=?p`#{M`` ` ` ` ` ```aa.a>aNa^an~`aaaaaaFaa b!b".b#>b$6Nb&nb'~b(b)&%b+b,b-$b.b0c1c2`/.c4Nc5^c63nc8c9c:7cc@dAva?dC>dDNd .dEndG~d:fdHdJ/dKdMd$~`dPeQeR.eS>eTNeU^eVneW~eXeYeZe[e\\;knopflerfish-osgi-5.1.0/docs/images/knopflerfish-top.jpg0000644000175000017500000000140112346515440022337 0ustar felixfelixJFIFHHC     C  T" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?+eQEa"(AEWo^]]n&_}{ 0M@5::bL&jybT>27V ƯwqqytE^ B?l NG}ɑZ2C[}ov~q[d}I !xlMo\f_(`0$Ǝ!Cd"pXD*{eYQr$lkJˎj}'.;kPo1A !ͼco1YȾhChHEEeP EQ8? <X*jTUEk˜zH&,$$!s:EuQ_4e<957ٍ& ZtR"L՜"| d34:\9餧40 `D}]D&˺GL"ښQݏ.#[E>2IS -~\q穀2=%yrIEƸPe0 "gXrRJqk'\`9dA/˥1Dˉԥݞ90cm6S;ܲҨ%ѱTꭘF҇L]{SP#{6Eݾ5ɽ76eXksW q8ugDtpDUNdt95Eh0>$#QgFTεDQc ҍĸ> U##?DƚZ4dsؒ L]81YK&Yoև`2ɫ5X c &s8nYEHJ2_}Vs/lQ݂kw$N?੨^g[GٸN10tq ^T0uzP U.#en˼\A;FTP9{^`0"<% < MQ!!1XE!ZkF{)+ӦNӞymݚ׈4s-S,OtU$1ͼ3S{ȳwwEGd9i !"$,1y&]c36/?sfqVNĉiY93Μ%YE_mZ17mk5tMx'uH݃DH<1,V?_U{Eq0cC>,7s^F/hJ_}rײ|#$ h|^ nBtOإQHCiÑGWQPXF >+au7$e . c1޻ ѹ9sV6tq?P<{uLx6զk we8}Mə mf.z<åǎm]D6*yO-|a¼'|-^8U?o{$.r<Ƶ3QnqT:f~!'KCpH+z];Tm+j3+'?P6d`043u1N%PuNI۬-tR/ ||Ko[csw\a0 ƍD1dCH2-2Ӎu^ ߢ1\Wn`ܯL#&C,kNTdT iZs<>a;)4Ѩ2Z#"52*56MXPX~gVMNDzivV}#di/ W+nQX1-ٛ+6?@L_S+NifN]Րt[w+LG6L}𕇻y#`! @v"#+**u/ &k:&ѻvl4xi5,:lHK"BxǼ^9*()`(c W>0D冹#Ge7s }'E{Kfܿ6n shZw{P)`\v!DY؋dA ? {:_;#m4ǰo}{%4+߶1  gV,m2\[C2BCT Z po^\:6Wv"`^ĸHC a81cXl%5}!1MC:]lme#jSeR sDQh >0N񡸿l$;=W*:Qɦ"*U1ypTɈä'3:a/ɝ8:500pnd"͢6&5jN;׳҇[iawegTCԈ|>ÌteQeC5~.oyb|P ͏Nک}}H[ zh$_w?0-!Mmn cr+L ue 㷻~Zؼ)fn*{$nYc]8;5]I"@/)g=0g;AoG ĸ@Wo dFa>7g/ΰJ)"JꚄ 5'h8sg30bk ]BT%#3ffH.7g{s 9왽tTQ]v YtG4/&d6[8fȈNLOٔlIVVqIIn֒838̊,8+1]d#κ.%`CE9:!TwR]tUR}zUU{^78Mԟzgo'[6dYzC|Mɡ-ȧ|rѕCH]u0vqte]]~KNsȿ=;)(\Z9*]0gn95RӻW@÷*̲w l0*ܥ1h?drςGv= S' 2be׊VFI_O)d@xIxOF;cJ~#Qqn.C1˟|>7׻Owp)W*Z15N7ٰsve_ʇ65[/< e|P'G%,Ӡ޼[5#T,WEZ:MjOnEU4ר # ӺwRrF2ɇ?keoCnY̳tn["*@ r Wxv0M/+.JK.,8E$ c@egB;TǨe-8&@Kcra^Vld0 iNqCgSgԊ) :tz`^3+u`_tWϴYlo;#rz$Αbv+T!x<x|b>Ox?{ҝGr>ړph'-ցms<$Ct%Jvr,{?s8n-uNkc7% #$ #~qr΁-nwf#/XH\$p$yfWYVKȸ`5.蔬 Kmz ~N;P(p!IE,@xERGW#K$~"@uۥF=460r,Ϝ2QQjб R#*W"3ߢ19H4O51f:`XyjqWx8LՓ;6t7~]-hb|^`Z~;Ă^=Cyw]?`/;PuVbJ2ā ~쇘 ~زyH wM[Y~%Hq~M-&iG.$@]fw  _wv~d`EsW]f*}"b2S>˯wIJkXBiӧŲm{i:~܍So \h5^abnj=~r>:{o^p7]:$`q=Yhi<⭖'kddHAɐA۴YvF|5˚kyKKp,gYGNdg}D=kliS5,?by^̈;)) #a= 9]#dRC7/Iegϝ@9S3pЄLB8\:yˆ+\Veu0? S1 ;\HHVˊ:U%Or<㆚b0,Op8.4~N80XK(ĵw0)(S lݾ#NpdbWUǎlvtlbbUܬO0X*^Ϫ§_YapWk(kL6/g4 <κM$DQv#J>0råeGl*V]h[mzuuuʟl9[ɧϝ3%O$}D^Q,uIR!Ńę<%dѡC'&^7>ﺭ\ZX7PוdYD{BrBH6E1&`5EB@ ؽ Lr|2v9ciSȡ&Liu4)Jm{gΘGcǎ _P#Jd_bi2%"Z1S lhL:9XyKe*r& )0Y*rѥ:D3o򤫇_^(Oصˌ/ssюvXIA1mr>ybX0TޔdMi/E5E=׋֝K若iF "SJF[Y2QՐɬOFx.4w .*[ҪslHtWut0~cA1\l3}o?) ׬ȕcCR\x Aݕ>HWL8󈻋1S.CoRX2d}oxK2 oaUɓnjjUK W;á%nmHUV^YC?\r+gd:/tre-ښy"X֟ -,ր,c~y!y\>01o]A'K|UDn++K@`v;+2 =C Ms\)2ycDɤdr.@`JݘL׉L;#UbӝmR>f3q5W]~nF#٪U?-`yiwEɧߠ(sPhIPk!Qx́uhΒu߫7hyŲ-1Y8L ;qC穒bG08̓ʶc2.`RR;/ HCqg|ċٶm>ضKNq]|߷.e>,߾#(Zz&H4rƟG:*{.apI}Qݛ% w./bP𣖸1# pʞ9gT3 t@JSyytGGvpuf[Iw'M/;aj徧++ko[Lwt/eC~kʦvۜydwR#h 4-v]dgbC )wfkwceS\ -h$PL獇6 1˲lAy2aE, 1O5j\2; ) jzqŽagqQWijyvƣ}Cl|O/hܘ19>/ئ@=|̙aÆMvVV>3ߞ:{Ü[~w]nGx諎T(:y@F6R{ V.Kj[Wo{WL(9/y}}s뱴 e/}q )A%ƓЫ2H:"#iitKeɇ|ka|ac6fn}/v_B^,p9XY` b|`% -X,i4>R3cah_ꫯ]]]d&':!WaOkX E,=  /P}kw%x8 xIL-P(Յ3 M ˎ ise|oNJmfU6iI3ݦܵPXiޙ'|YS4?al bZbCc{^|yEe 7LZUʉמY\V8eþmϿ#y[7ֲҦ,*nLmB"}{6M]^v شIabdx$ SK1;Ι=oGo2&N|fG_k|7];/LZ/|}Z!\*\M:qU*zd ]$lݚ5+*j?urBļJC0?7@YQ+4_'ST \^~T[0gcz◿2m d,_98'oIa=/h71'9+]X\%luE-;i+E 8bXoJpFYe;e rp$rtN-i$9g}'eLG13u 'r%aQ#F̎V +vWWgaҠs`XvE&26K߶,;2TjWKeJ2tN 7+V8~oY3j1E(.Y*l(*xjjg$жtN-i$9'kM7sݘF|8.HrT* -5_]|vjW(Vli(wɨAVLo}VpdHYAd˖ ApGe75[DVwܷ8oPjPzhǚ504ukKˬ.}ü٩.V*]sNy'ia<]e ܤI"7n[M_\RKJyw޹sgz4cv:'SPBs}Mm2O)$6 EFeD"Q)RDZZnb9}Z߹3UQ#A 3g Ec1(gtKI9K!'fڵo>NDì9 d7S,[0d*RJT.Y%zU !P#HPEEI癭Sh/f }Ҝ4d Z'P8J}>pKh)kUJ}z`djc)'SBɌKTCC.` P`\@D8f'5m6ېirCn!_S|CcP2"bEyKق;gλnfx t)\b%|6ʝ0 /u6qgq}Kӌhx.$%DDr(V\cP2K!RWҢ(MDf]()R\&QɥcS[* t$(b;rI(Eaɮg~),jEx,8\;ҺjmF&, ΧNָ綬͙${g~Wm#@VaaQ$hֱf!LptIKK}V2G@i '\t2\@arM1J1G8*a&\@(p )NXiwI<"$ۚ2nӬY0pRvWޱmm6biX*}ÂNpCÛl=;mBqǙɊܹ r(C8J7’M7Ҡ4rG:4'2TxZbya!ORX &s餗&kinUqdQ]K@IQep`<RؔKDʁD34ucCKMca $mshS[ZXSvC=r IR4ÒN[6m(`z1}h>{9my`W]A{ٵkWO3q R\B96]馏c=S(r5VTT.i&)jr*CݹOP pHV"Vi")X{?CSrJxD꫋dG1쉔 ?@/ (,C"zTRcHqp< acT*]?8ԫ,GIw` larY25ieǮ\W:,8#w+"){B  dUkqȸ^HիhֱF"""IxgM.ѡP( @!e|`_}ohDTRE`{αa*E2.l9[KVլ-zCKc͟?U]V0 s:h34ڒfYbbYccÜB0?_usQWJ_MJbW;Bq=X5aw _{bs[d2YJJJVݼ歷ުhjj:qDsssIiGڗ5U(WpwΑԒFrPd ޓܺ.înpod>PmmnxpBγD1a q8;t埮t$۷CYva Z[[u:]^2B߳"!Va?— mjI#9fgs2 uOG|n:`I2X؈y)APJpFYe;} LdK%xk};=XV{u]ڤVSmH"ޞx=34jLb2 E%w=jd>jxlӖ}:y9+0, R""h}}ygjlUXDD$k@Q?ڮ\N'a@$xIEoXݶz GI04 ?_V-٦T*SmHna0n㏧ڐ F"""Yd*RJT.Y%2W A_퀚(*y xWݼ,tDDbOӊXJ8~`\<E52%YI g! 1lʑ {CO$3^l88C=s [zfEzOOd~3x:wpYNSM!KLr@;@mL%Q^PI$LsZRUP#H]Gi~6RYP[*GJ\M ~4<@V |/j2]SūNs ($>.ɠD(̘lR 9Lb1*NQ)A}7*ɮ|'VØȼO @d'H(gNW S9b/M4t{𬁆S}^~$M#d*f I5qN0s$3#6+3ьmRCqw!Mr.TYʖ›y -*>z,^#%8)>J|G|' 7IfVCb1;<*ϋʓ"CӚtu $ZF&M[]UWѭ J~ہ6 Y\Tv`0d _e3")rIIr/A |kVr h'd7YEPO@@n-cdmG/Fx F4&~&(3ؾ}{Lq1Zq[ : oTGF l'%9Ѭv ]: qM#+k V~@ )%U#B,>#r}T ܦi q(zɀ@dɿ09RYt5+'1WSHfv\DSj*&&A_4Y>R tJ5#x*lJUf9'a *хH439`K@ɪ+*AnA9'?z GLx+GqNʖ;ʥ4(BA dcTנ?^yJ[#̑2~f9-12Ţ!-N@0Zh'lB-; 0=D}g?o_\.-/sWUU8m׀| lx kɕul{'/S⵮dV?1\nQhzrZa9Ad8f׻@ќ&򘍤v^o\H I` kɶ[϶ a>ڪCn:ܔm5G>_CCv*"hr٘ڲHJ9cҊ4xr/޺Uy+,Y\v7lwb0Cv]vȾᦦ)A31,**|>m(l@~sgˏƶ;vd;H%PAa_MP̩U hEB=yoi>oX}v:V*4ESM#{poazz_vXW^ȷ UȎm?؎>^du˽N𱎳y*3f7g{̍ nl&7lxj|M)+C?Ȍ}))uQ9^-^O.9 iYdW5&43=30b+:ppמ۟|_&٧s|0497?ySSS}}}555.'/_{V7 I2RO~;U4ApSvHk[ﵷ?=&_-eM `wO&Kev94L&d4چ{qkJ{+tޏ=fC 7yؓpHyoMr_ g錂c1钇N21_5T< U骚` `L=d4BsQV0ћ~ʼkwtoⶩo)04m#;~laK/|y}S_<-c!5^C#a-X% JNgCQCswl`ƲFwahd"Մ6T$AsHhILV.qepij @hB>i_Za򊺊O| Ӟqi b3YVYͰ ̯O|p]09]l+[՘AuaK+鋦)a;c$g=&K^NMTTٛ7n\g3sG?>5leI !֏3عs+83]L5\u/D,AT=Кd+IClvǃܿrŒ_iBwM匎>UV69toq7\i_bv aҪIيx$J9?,ZPr>d2Wkuv?oq!?=22?pt=W9Pՠ~ޭe̸oh2NL[A!LE^se+0vldSC_lnZz6mx#MQG;:^x]ٯ^(łꆕmu IZ& 3g [O:ٓZ649 DSw#͖6*dD}f,hdʣ2d2=4k-cdmG/4iґdNsӦM{kG{)Q̼w> Fdvzͫd 77Ow9vC*iqI6H ?;*t-k`'8|Bע+*C޹Q Vb_q 83inle+eٵ%sssq=<<``uBP>L  0N0rIK]E6?:q hZK+ۊ 1c{)d`nɜPG,{E+omln6`)L?jn+jrr??9^~K\:?۽{sϏma;̓90%`V(+ȩ2$8ef~TZl5fi3-G{U&DahjKp" r.3'A HMh2wiɭ[niLsss!5~oCljذa~p?j]+Z;F{9b`q<|Gg"0UoW@ 2NCAMF fHYd" FD *D */4I$;Ϲ/g-MʬdzƖ7)R|-6^48*J+okҁ@|G{n}k]#18;{?׊#=wӑǿ@={vؑuV.m-v؈#uiĐ!fXI' ygH8"MM83>4o-v2݂UZ+`S29FY])tp2Xw'.<VYyִV.Y-8= sV^z39vtgo}8рq0%fT54Yf<zl] Q  ,S9e/nϷmyNgH\ȟ$ȩЊsRx3KD 4)`MS`"8ط-(B9J9(f9qH,˅ ,R]Ueq$4C4E&D}qm}?϶Z*K/`kWZ^; /ĩ xZ]_4Di5idLxP!3WF}Ƹ'S"~\&S[l*}Dz36 .=ﱵ:W\\~}g :0yk+{UWQ Xfq iFuȇ-pa6;X,4w}'fgk8)tK>2ꭉs *doAyl8?A60HI%9(MLDļlP)U] H0Cuof5miَ354޳Wl?8!8J([:0JKޟj,)."q0qd PMkLX!D; w&PNT;Iw'fiAx78g{ATEԑuaDF#:n"-m/lKC[zߒV˫͉TtRIɩwܪ׽nɤˆ8lt$Z*Ɯ(Ctx}v6iE~$gQ9d=׻klH5ljݻwVVV?ޜWU3Jx6LciXa֧azT*%/>Ij.9+nZ@ Oɞ[܈IdCaذa˖-c}ԩS CN*}j#+0 Z>cwӝߝ;.~0sBNKOb[F(7 ʹSƏ)Hx [IFqѢE"FOfF{⬾6q/@@.N83 ܉`Tfψ>jh{O XRߓngdyz)T*2{ qUSQ\INet8$_ @~؂5 -;ò X+c! Aۑcfpo}aق-l#X0TRk*NT(42Z&SHrT|0 GQ)!Z a0+bkdĹ [ث4͉gGo"$a7ױ@Kҥ́Aa$~1:n+oU}x?ٔKfL+ !h2 +RGֆǘKߠ & C )[Kjt\[c@0ї]Y*fz@Nؚ+7~c*;bg0GPv_Htb on_ ;gcʵ*'.~gG|@ϮGVMC>y?ƄΞNU>Mfs')C (4G# 3.p^hiFz S[I(g C ^h CUA}Kú /5PԆ+Q A>HX $xohd~ZI!M :t?l A<`'bLJg4%Ɛ]d_zH7p !AO(hx6aϵM0RٸiW|Bh2418Sv@HlVz| L:VxV|, >AB#Hj|N?A3 sqM40lK*2 ᐳ T=0 ^oÐ>|pE@ )[܈Id!eˈ0NA& NMF&DUݠu a%H(CA:"Iu؄[K`^:VY117v'YHH79y쾅O12r%<['D'ߖmsm\6 fB#6 b,Τ6b$C r.ˉ*iZڮ79}VxVa+e/8C<[]XEc35ばΤ989gWk=`R!-?:ƴa7~&&8gN_\9XdrИp,#(fa;M[m*vjWaDw>pKj mw8;Cd)/MVtZMz‚8.T97/s~9>;Nf&iu}"%A:K d8?48vj%o[eȓbr&<3q$&УF6s&cɔkJ$v-i%)d*u$YY۶vj~ي3(YId>) @R vMƜ{hiZَbNgƶ*ó1fy= QB1`5Y_zSp\WϞqY;P$NAVd2O WVqkSsw" 1;lA@R#^MkwVv_IRKR.hDGvtWgWn)Ӝ/ݼ]~dтSv4ӠVi 7V -gls$s撐rQza;?4Mjfϙ[WWGWF<} ,,=Dɜ]H~~Qi,[ˡ3'~U%y yӤ䑆Qc)Ւd8M7O!J,x왥ZrN pdd}A7A27$lϡ6M?$iܧ 5Cn^>MAfr0v2̍P/p mmm&yߗd?,^@F'&bܻAAm&)ԙF̏2i~r!6 mErD&Gr F]њGťk˓|XcD9k>H{N ^#QiݷON7MyODjwlz󫪪~SZR8} Huft4662TVU=oh+/q<Ŋ7P!q߭߰+g_s5555v0r&8+賡&Hj)`+Y >_!\9,bd̹U9f|=S2iguLq'w4:[O(mS$"Ѫt{ҽnKSNÌh&$XJ)AI)W͟EEm“FN6LEeHHjk>_Νi [w:a:%딲4eP!qjyK/6s̊v&d2]r%uuuvbʇN\?pF̿(&(hs)gIX> x𗼾D5',ĢP]ذ.[ ZJVSht tkG̙TmֺNP^hQ0e>nv ~ytNwD,2;}SMMLH~=(W9'z;)SuRnS^E#&AP1i/w}g-AR$hm벚iLx5k;s^njOƬU*d[2ҥwesf_ ˏWma *ә%'1x|ix (&&9a!MpnBŜm}Vk,)7jdQVNӎJ5+# YZlkhjnЛ6"u|>%)7,p6MEE OŎ= W*_MayguW=T*f޼;i1hhL,* ai\aӹs mii_囫L*$jx_p ]7&fwG ̙5X- 5"dEG]rW);C3̜ll3رC|_V2~"NT"dt1Z]Ue@v)gt֕ryc ЯDdz>J}GkL`ANq Qh4#G>qdFu̹$u5y&%Xj 0nw9^LİLȠ@W!"M6(lJ 1wdefMIw9Z}xYɤf찴8j^:%1?&wt#Ͻ(tsn8ˤfz ( ].\&F:M1B.uuu9cǍ.vV8v&V(y>z)dOAAwCXE11 4R(2. eRFPpId3Ԫ MS{{M]EQK.-STef>Q3;BJ\шI9zy``]j-Flni>ӟIm8F"6)&[Ʉ˳sV hX,_|r99vP!@zهroVab R}\чQD EQ609㸔9Ur12BNew'QTy_wNw; Bá |08",*qt]eGegpdtցqEE@| wjztw:*|JU?_W59WX QBR%1H1x`(t|zg".v\\L"Οb}o]9Bmfv>G'Iru73Ǥ9yvۭ-W/|Oē!@r2ο-޻ۜE[Zt!}4sWܸ~dh/wEj%RH.E|@4{-3V\$ lђ Ғ2YáNӬT}-Y5 xFEaL3Nk<}f-Z9;(pַ` 'ή+y7/?"0"qdFQԉ3adEKhonlid'T0VeN8a\;/r$wQHAS4N ϴ5u:[31*fL>z}x]گv޲li]]~ufҠsu'ν\uݹsO>j Bo/adr\DSrVa節9dSRZr yprO ̷몳ƪ6ĩ\dMO&e*j> =n%ކg\.W^_g!ڴiSGr2On@ wNx6o1DX9'Y\bR[/TuHp`6qfYڇ]ds4tjuGk] w&nKɶ-Rj[JMӌDxTP&%FHnCԏo][w^+\P!cZg31}屧)Qī [vXfl6[iym^|jmJU%~'7?vrMّ˱i|߅:[Y'dlFղ OaD LFxd*&մ_m4Q5խMR]5+[(C 3\Nsٓ;R2DT rD828Ё\e '+r34_Pa|4b>kok66|.nqߡo܂)7m8}siOA:}!3  ^V X dm)9VZfb?;k$]E%,7V_֘n3[$ ,&8rZZ0T&N7=y-if :Ђ؝%5͵k~ĵ==T&;ht{<{/yT.sN:`H"X j pq︲_yͪNH 8asG]Ȱ}r^pZ~E~@ `l\Nf6rdɖlAOsf(iX&К~D1BJ>'8Y{OT wvC!q&%%tW_s)eR%sG0g>33QƽNo~}{"RܶcURhq{M<˱W #:=b` bT*.|}AG^$La4 2g1;Dv7/Cjpwsqj߶;;N?w j p4?ao.<;ܾ}sG.!_h|nv](!dA飼oxtM:%QI%kYk- "$c>=9+ )UQ~槟wg*].ׁt! 58 իW_|YRM:$)V ѐ]%ڲ;aץ: ki$#qw8-W]0oJ &4 Z,RRR =ZXXh>tVAz! 5p ]TS/LYyy9qt;v|ð;y\.kO9Y*Mp>xqq`(XeoX_0ں_n/((ܽ{wcc#>l6dzm\BbQɂH{Ւj7lJ2T]S8_-SިQk֬⢧j5fݕڰ !omU^~OQTo>|?2 R))4t7fr=O,[{s5 o8. rrrz a) V&$|=_;5\wqŲjժ~aP!l] .1Kq 0t} CH<شi;| 'd r2AN?'ܜ,IMCTq Mo d0U)T?!7' V SKg]OE&S!v4߷ho}UȄaB 6FlC!?k{˽k- 22!BIm Tdd"cw(wm 0,(@6a]y#{ õ8[BSȤAPj#=v`$u]0~3&KQTr qBz?#.5|4}E1O}ݻhUcL+Wwkg͜wyA9`&gaB*HWE"^$nwy Zhmlj0 o7?i6AwyA9ćSmx~_PRkl z?į fcWۭPȦMq@:_%&IK$tPFP&-f=EQܯIR.'|I6C4'OaFDB7A<jcA;0!Aa pq$M/d1.`T 4'&o.KKp $  6R-sfOUR9ƌdH107.KN̝}E6 !@ 'qiY IgAp2 r2AN?c`GazWw}~D`fx=`MhA߇}d2 yl+Ξ;ZMG, co{7U9`䈴! 09YK>ibnNA^nlMmVҒGjd `ǾvYDc F>za?;jX,jZt3gNO2_qݵ:RRRq:ުokH̦n滼B]u1tH R$G[Q zvgw:6%2 (8P4fo1Je6{zzJKee&l2DEX9'{~{#,ֻvKRõ[܏WiH$tGJRϿ5ЌDE zۭql~h6?YA FPa~< e űc&c.1 |0yl#T_ȯޫ.)OJN)-ݏmy+ݚXr](y))5n,KΘ,` 4V5UJ=a\raL5p@ C{7;}65!!@5vtӋ -$W N=gK *.\N!w8\v쬫KMMv9ZZᙗ*jgܺYA$ߧ5~/<ɒhP~ɐTlִ,<[V" |sII'X^TAO"{?K_Gq9)jY>=/K֥&]"9&1IftoygVTVgMqݙdܜ2 Mc8~DOݾhwnz< Y/+("PdY͏x FӪU(զ Eb1䵻ɪk64y5ӳ,H! uG2u\ߨ#:\f1>5pHs7lkll .SsCj06>p_ZZE8AdE3U5ө6 ϾRWpՑ°a8`ƻbyi ~+ke}fk mdYkwڥ]\%S4TnKV.Pɜvǩ:&Zr.%p{xud2L6i{c=TD *GgQGa=y}Xo.>讀xE+(R@JK4=s9SvK/iچδ~>}7o̼3ˌ\K}˹sߜi{mr/x@2pDb,?: å(sHngc6$J` EdU].`4m|oUT[eFJcv%,j=c+>y~M'*o$zj9THNZbm.\xxV~@d!FGY5YNgyWUgSXLf9Dj=.6f!Q}YcSSW'; 3d FGY.{]abR,jws[j,1S Qwdr7PX7߱Wo|i}>/-#R\Yc dym'=h44v?5ْo$ ;9Hb,~`]Mm;?hh6tɠTTq CBwW/-:zjuqq̙3=x&ȄEr7_)(JKMyMOfmpI 2 @)&mٲ*;;;==iiSYUXTVFO} ^@(&f]VVLlQQr7aC2`P>w9(ĵ5d`X Ld=m&Up1B5$ ~cw?=@hjAM ?dCM ?dCM dRj-,uQdPɺ\L8RHM o!`¹.}};pqoÃaЖiz(<$JA |cHK(< o Koæа_I@\qy;JsqXd#j}eԁ =z}gط þP1TN$/PyRї4@OAULp2]dAtfo@ƵyMWふfY A;y(  mMIc| fCEKrH!dOo: =lK {Tr9yq&õ0428}wZ?0p aY2A&bѧ95h8 r'xbCCF{eЙ;7#+ץftK1MG ͛BI`_ scj^(=2+5Y2pn# 3ĩdb QGCEE2Fϓ@(_YWrA9>-2_( |7bj2FGqS&|.&PIj2&j2`JPQ¥úwIy0MWNj`{ 蝞>_zc ^P /?Ov̗^ْy+5}$w`BM0n{\`WܠT*uO7V^P IC|[nHW-="]uw'ᕞn-Lh ?dCM ?dCM ?dCM Tr &5cmMW3z[4T9ooK%''&iZM  \nJD؅کP3INT|Q;\%hnvuh0r:}_ aΟo[`Udܚ:~b\r}voMX,c|Ltk|xIt^6t>+oQG׮_8w㡢c Iq{b%+Pt%<}D:^ Eq5KjU5iǶc%g>ŹI:J}L ǫeMZj-:bk3_ v0z[/_:Mf*kzʔN;󄪨o;6IG)9䥠:xcm1F.$Z-hIbjBZf*+9%qt2M\&;1t=k2'IOMu]?C'NKag[ڝncw:::jjjRSSIos'k~^30r/0?|]&@)&E?jLڮh=ok3U4Ekl9:4Vbu9DWwKm ˖k;^{^f|k"@r۾0r/Rj2f&2.UˡaJ>dL]m윘EzpdT[NڢR_^wp--ΝJ2sɽd!5&z/Tz#}鉖?{SsV!>{s"hB_׼_ ݧZk։K/l%!0InJLxfrq];ci%tf5wt88Q)-:NYM/R[Wm:"ܒF#i<ƺ,Y  ^N l}<`7 8v$m0>m[[iNnF}M!=vMuW_USUSe+u}[5E4V\GF쎜~p{z&K)@޲w7}IׯXqno u*X(j2fЀ@FLK]2FI#MPW>7Sb6(~46T[=rc'Ϟ9v0޴퍁[H;ӈ0ai҆ΜE7885ھm[(\hq8ΆBSi(3*,(]V٤o!4dyrZn*(Sfv9@E.d)g=QVJQCdX 'E" CwX,; }}ypۛGU$XpøGۿ9kl}(ϯv&uv|f߯yn]ws_o_k[f_d &1|5I#M7+z/f1-Ǧ'e8vX` O[BCZ)jx ^ann';ttw+KHʄ!<m3X$(p㟕ĩ1 Q" DI:B$bL_瀿g MUŅ%7|gBN2, "4 ~իn}-!?<׃⌇Z堞#m{f7nSO&K\@Pj{pv/ạ@,{Xԟ`[x-Mzi2!WaiU7<ljRC.|B /<.|ĩ3m6WUdK|5=7!jwU4s|f4 _wKلL*8F`r/"~*B@8%&Òb.!ibxLѷDWGÎemEMa!;jd0-$E:j2W~v w8mDn݄'Xd,?j!Af ޹ѳh\> .i?+t8Anә?ΙޠEDYL8E9/ЃBd̀Q#?$F`M%qltL8 S+Z_('6Y`2I_Mʦ{_}_{eN$d42㌙gYtfsIYzݲz޽{ܹwwYPWĄ4 !L wzkH tLbM.|abXfd&ZiE"0L.NIZk2;w?l)t]YCV"t~Eeibu cҫolFan駟6ڑL0b]Uv֍iEӸ?yez|v-uFt2O!~ E+]n@f3sp(QeKO#~I MirڊV7&Ug|{7) 2θ&t+ޠ?++K SphT?= LXCN9qV{'%MSO@#0x LoX/x@τg}hu?31,%,0xG0ͻh'.ez]4&0dƣ0ǿJtvHhP1%6mĔ񺔌{SIZ,@ɢDm$ZKMW%j)rIFClR}K5dJP>-XW$FLEfVnSB*?ڨ啋3=Hj[>z)JtՌycޟ,UM&yc 0."IZJMAbVDnSwԻ.ԉ]EJj$ZK)%/FJո1O5ydPdo,KY5U)]̘ZJJ,U;=1ʕjL|2LF)mgNcFSH2JEqS0`p^[ۯ\Y?)$DsbZHҦ#=. T3:$TB̙g3d =f#K}9b~w gׅ._5{d&+}[rn؉pꙬze~hH8LPLzlTw2Bo%x2@< LO&'ēdd2x2@< LO&'ēdd2x2@< LO&'Kfh|пUkktJZtWodcQGs+PN sG`5gŅb5yT,GQq(<YY(/{afvtzvA׮ȫkwu{Ɣ=mܸʈ;rT&mܘxa ^azU-ql|z׎W?35~Ǖ OZZ臯?ɗW>>9{s{ƍ^Oٸ􌒖GjOɏ15#S6;'{ck?qBR%(SpL݇/>~W_N'\הb=ҵU.l{/C=:M8R- Pٳsm1a5gT(˿_IVwA2vbfJ~ډ\?]mO\ոx+)qVߠ)8K/?0nlgR#ڸ (*:9gtUxfjD$7RzmS{MɆyz&ۍόmIi=ü%71=yޓaۍdכLO&'ēdd2x2@< LO&'ēdd2x2@< LO&'ēd3|~Tjm{lx-4s/O=߉iFNd?ԶǑ*\\-hp:'c4؇ QcVYǙ>k_6WϪ?mk-{o4#_gIvk^=:41sn{2SjDYuR3Op~XdS`(]k3mg͊/zk}4T/5b:mzf=iێ=Uv Y{zUk?7fzvFRfW mNytQV|zuf ؽwhR.]if E&kebĈmzR[8̔0d;۶S[7g7?'goܿuYv}LɪK42?\vkdKyGs%QH (Ugɞ j⭍f{J҇b2 ݇/>~W_Nf"-%PUd->3>kD $#6jp[Xdd2x2@< LO&'ēdd2x2@< LO&'ēdd2x2@< LO&לHs&X2 `XIJo-0d&&ӜLLr=Yta{gaēdd2x2@< L3cO/!oQ`GXYOO&'ēdd2x2@T&.`/2_8>j./76J?:z@v@0}_ד}]Yd2x2@< LO&wпg'#^d}}}=L[&/OԫD`ϟ4=1yx'[yYyC֧w&!Ny`;mRm\Iয়/kN>IENDB`knopflerfish-osgi-5.1.0/docs/images/desktop_open_bundle.png0000644000175000017500000006017512346515440023111 0ustar felixfelixPNG  IHDR5,bwtEXtCreation Time #tIME4َ pHYsttk$_IDATx tTEǫ^tN IW AD"2x^Dg /l3's&訠"p#H0EH" KgnVB$Dw4uV}Pvq2߷6(.~{icfl"4$"Zh:ڍUr h՟:a{`;3tu_uhnMF)U)>Qqֳ$K=M4KHzl>oS_Q . P2ThH15UjnS}mj,8(OTG.+ĿD/EQ&)ꮈдlis!䲩pKj!_}biHej*FbB4]ad ͥYX\.7ň8 .E؊Cjznwf+֓'QR5K]ݥhrzJ*nhF#SU5\H$*dYTDEոt}G=$CK:Wɤ3B`+?-L̼E'oMQiYn BDK7MՈP[頖b$oE=w5bU}]xI,iIT+izh57"DRYޭ;g4;`kgKm'KeEdpL$, gT} 0hЗx 'sU튣IsTɭ&)^W%}H%^CNbnSj;>!KP Iޘ2A;pmCՈ{w{(7o)rcv!Yb%MTn\hl߿wQ 4~E9O&DL_SaCܗ@@ũU(n& T4I F͡{%H%JRԠ`YS.)޳gEyqTtDL$hTɤˡInM<|L(UOE88wꄥu+Mt+`_w~PӰ#Vl ]})w &w,\.Q~>If٤[H\mCh1'BvwCrJl>G>Wl))T vVTTo B({]5V5wݺyr0: 6Sh ;~ր!)^=5.}M {6r[ݵzok/jg=eM=Yb~[ݚ$[3(XSVy`H7'Z 2ZRn/(8=`yV(,,.(,^iٸD W%jؐa3o@I̝R_z4JLuv8{cs~[?.*4i'ҬM՟ cnrD3xW72-ߌReM쉡boY.c~DVvv+sӧM[;&gd.޾y̥.E6]L}mcį7!48dz?e{V4ɐ1Lj8fs$<ܺwj[Uк>t=θ~Hށ!I3|3'$ĘЎ~g1k۞~aOlIcBFkr4=|m~8a]Cu+"E[zY 2vaADbsṾ ߧIIQeb+Xmjlž9/~ZD-MٝN0ebU:RScm:f nn*={:ijA5z'ǰ~!/ KHJ [[T𡔐t7o] {5c][$Y- yl/AVf =qt˪Y[\u!C8ܐz|=N^M;oXwkοԱϯ\ȨsҧgzH[^H 3oڍk'gSt %ĵFEbU5>֡ߎDHŘO`?;yZfBwI 4mԞa# O6|~[Wٛ]vB(¢s2/ꦄ0zMA.~izhc^49cfA_8en @ 61']ksyLVdI$ƶ.T†_Β9#٢(ٰѴ Y I &O/OKoIL/(d{~[TVV(&TƬAqq(xNٲE83akj:UNӯ8\v#>uW1(djiݠj⺣O/шoErvcܫ[N~{2@ѓ<nÀ_!yMcGFӲ [~ix]O#<lo("SUvmGg/*{?!w̺ 3RB(ID.5Ӷ ?Mt8VM53T|iSSm6LrYiQD"}%&bB_lۊzBgxT>PY7O6m6;{/D/ 0*t~;"A햯wPݭi#ްpWUS1aQƄh@_oYätN&M?kt nC]$ [_xvSBn|«!9Eo`3h%x(o"]8$۬g΋y&#sZFFvs%y+7m v~-*,L!-w;40 ^v3[ѭφ08nNѩGJǤ=6HmTuс(8ZGl.- ȅ0,?.a.ax&}G΢}ӞN|q84ZG$quqc KD#-hC{oBc!5㰓\ $>,6Cw$!/Sb$|xĵߔ<2*(&QTIBAAp=Qh@ƬpVPXth)Igg-TP"$=3TYҗb6*/z`F7|nǝ|_=}Yvx\F%݄OoqиQze֔>ϫу |!Q+nX度 r^;ёoTV&͘#矫IQn޽q򎰖xmOo.>:jɑQ8*v )Ϸp¿8dUCӵ4aD1[r=p㓐/WAR6wD›{u; ''bhEY6[T?aAJc!͉Wli4r*O*L鍜8Xtv]9oO[>_'[w zٿ[g0;?ֿ-'-U/}RZo;T}y zw؁Mg}E˛'y}LV3fSC?}L`6|8ǻ/:fǔW8U.3Yn_?&LܔtbK7Sɸ 'Ƌ݅l5f/LTYSܘQI SI$58cvy>ǻV }(KR+=z18';r_>[SAj>׊Sq"[ITSuRUȥV lQ,RU69ViEUe](j[ }ޞxm }RUuAD=[}fNJM/sz`'Sܰ,gug+p:6[FRDW)BJakrJcu^E( wWj['S(@i%#\7hE䮣w+2U.=NoFI_ E5JU\,DEKSZG.ճSaa"W <^7wQ8U{4}5$6D [RDI3|kt>C\|ZLc'cw?AèF:Rh eЧ~OVڌhmt/E_JEb*0Ӈ4hoN }2nzW{.5W[:O'S )"^kOZ.枛ӺڅJwٺN <|pXUô˺~}]aqrO!>s[m^TFWY@ZŞ-_~bJ~Ө;&\L.giFFvlEZ{t 5TF9bJ|S :? jj:.pDpnCRRaHuR|q JY!@Z@ilSw6wnƠ bTpb0WD;*uo=7m 4!%TJUQxEWU~[!@|7gC/_ſsJ׏tt yDHx%T5Q]={vfw%pά{tWfճq\PYtg䡇eAHHHHb;t]U{+TQ]Iwus6 nIg']WTTXx%j;yK2 3222P-8q*{U&\>[ս9O3NQNp`fKr'Y_8MjҌ찓?aľV|IR?C\33V }֞C߼W[_鿓K&8{`N[ZΝUmqlɧ5^'svf*A~es#ު'秞bGt[:ٹu:ŀ~۾]}8&CCT h[)e> nKQDpnv>'`"D`X;/r U8iЀW6[k*[ˠS{T_ BO"e1Nԧ>~r~j>w/:o)D Åy{$ yKb:w;5Q6(~!.jNQ"nr~wEB{-e g=/?g{^~"&𵂂k/W>Yqr:gzJ_ 8JO1h9 ugQ|gYrvӬ  K~0@nn F1)=u$Ԙ y65.O!o1 ./T;!ZDv7(8AI0댯eqXڼO޼g-Ƨ ew=۴?`,n͒)oR BXdwT]8o 8|~6>'uAYM\?=9=yS: j'1vݙA% ("K ^xPdK h9ZϻRvF}՗7ͱwwY|n\_a3vCv^{8a_ѣY1*7\pV+$LJ) O,?_1 'R;C!a$jlĉ `"?aywmޘulʬ|S7LƐʠ vۭu}]:`wܶDN +ٮK|(o;c4b kfo%_\=p O$y]7Oȝ.{_D"L<+q"ۖ;kk=Gxe9c먛4F`?̈F@n:@>ԗy ژOWs>i]՜g*OU59I'5v⅌6Q:R3?'^DO0#dT)$8IO H*?|xvKi/A>6~yت3ܸj5%MηR`˓ٱƟb'eErrSxɇ#I?{{l! 8^w|߷/[VxR؈$(KUrâ߀nvu2|`C' mg#߉3 u92rD]8qrQPo/O>iK E$J%k?:t5 ne˦YF"DNU(@m'wI$Pq?M  oqJ@F8Ohڪ*R\'$E$x\g`#)'K)1^E".I-IO# U!T̞,))|Z%v(y<>!r[-w!ƚ%ş?w'O:X#wA?x׃yڥEfO,="wANi4DH"m A$>!  >!  >!  >! H9;nN5JR#၆rAd }=8SA\&WEݴF"ZI.}"Ή}^Gn 49NKD8n*e 2Gƴ[75E9?M)(1> 0ßnRtMnXDGBB>@~pu~W@ [^Fk *TKͼ Q#r "/Wr-0.PdYV׫hg^XaưqyKN#7"ah.@9k$hinj[1tEuwwn"Hfx<]]4{ݫ CFFFJ+!S6qnJ X!_p澦(),Mz˃ϣ'P\4Ilٲ;߸q233TZM<>9!J0,x?pŲhU@%C{g:'/M+M`2-mr޾qƘ -QG;\pt}c7]>x'QZRIQ%!)q AQ"]t{ɵfl[_wBi߾}0z~"Œih˗̞eM̜9C$ZrQ>Zp C{*mj }.[޷ԩSDXQ%U-ԁW/^Z3'v:{c>Ľ;@qB$yȶ~q@zp ۽d̞k 0@'@pPk---&Siݗ'y<Yj\_8 B>})+A `̆ нVz=Dqۿm[˗?AM\PHsrfK}ukO3 ŋ):Ӵi^o2m}Ui ޭ*[Dwmii1N/{맘}YҮjW3'FQT*gI/nmm-JT8!ȄE= |aR!77l63 ?Z}.*xnmjZnht4o;K M$m%b?].ǶnL u4D C |GP`qO.'l6ɤPOݕCp ;_~m(_aOz})r2g>w7Vyh?1 >Ok\;^;B $tc<^U ^^s/ i?W7s]u{FӧOdH#=\)j#LRXdc&,H#~L(dO"Nс'kN.qT@ᯌ+_A/nnkh8tYnKq]F5 cy30DqoD6T0(Q21'D6mVU_ڷSkKW3ívKmp;qR*տyg&…7fee.†u4 Fk~DLXO'k{'O£t%0u}c%%?jkVaq1Ƀ~rY<Ŀ?_{EE7gK/?fܤ[ /.xB(ȦO m˝_EXrlOY% TJeZYR,;mmM|gE♈4\de#5/shᒪ7S9[X HZ!> ['3Z[[.^P__i-**\|Y/qp!J04@WGnjd"Nም3n'Mqqƌeel07<֐ffѣGWZ5׏8!ȍXViiGyH sRZmn^nNhdِops\3RS| AȦOqQ6!wA5in,@IPd"7ؽㅘg.*LXdGH 1t HOcDPAO>?Pd\q I{=v;/ D$wGxN6?w^4}>r!=J޷IsO޷ :*)w7ƶ0cG'~cƐ4"QՉ  FDjSӤF&᳊aV;)|bħ?DJVGLLq~yzIQ( oC'7SPȨC$eHRB0LX;'E3O1 7IRȓdBl7ܜE?XAٻ6?<Q(iHtN\'vu3;=;M=ɤL;Nu8Nqvڊ[6Nޤx= i !) ~@]w~ۧ2,Kii-3Z-y=Axyb{=7.+ʧW̆esKepDͅ{oy͆P!dS~*Lr?M_Sz_ss8ecdf,P!\8˅s{Y~3)!16a/zO5|ls%Z!f% 'i hQ^I*X`\?!$ޔ{.F)Kc\`^@n|Dv!5泔Y;En>e1韟>V͒Qkjd.6, ZɧK0qe)Ь? Syu͹sU_riZ)c ך9 ڑ|(-SŘs@,,-h (0SN0?OE'"h Z|-B>!r|  Z|-;w|x$j?e֔o3N+s ˷t,-*^͏޺h`< L|bڦ=能a-m;˲8}L/~+\oa0?T˧'{h.+;^ͨ=0a[畔-+ ޝbo"E1IZ>I%8 ׽?(uʅti1Q~a&̱v:'U^}آ+֭0|*;;GJE1qj(,7#D4pJ$do~io>2~>򕍆ǏoJU754En-jޕıi<8B80X^90sn}|GSˢ{3[׼re9˲l0?Ի˞<ٗ6|o)S?ywO5K'wY׏_ēh^=dXh4,z8@w}q4V^Nʳ|p]i$'X|Hu׈O2=y^ȹ ]j/OǤ#=2'))ЭADqWe0~J%$I hhjؒ$Nbʃ2'i<R3ĩu0sLu?852`),SʻSIy^e+Г{|w%^ 5GDF-3ް|J8MDib&FzKLME TK n山OӡQ'\wx>arú }Nˎ6$[Lz?ۏ5{B-ZW[ ;K}V~}\S-/4] Hl: [2cX-=̮RJDJWZejd4!7"_L\[iKuܹc9ثk9x*DBZS,茭 N+>{+*"PIdY}dM=tu4S尒[ÔL=Ct=RNJ}>٬l6)z 5faR2?6VO{O:͞1`q.Wr:vx&Y,fj`R3j<򧣑&1 yrw<[RZW{<^H$UyXP$\&̧~n{&r}+|>sCɤ" pQ3nzީTIEvf1g07թOVjUEJB2 Z.6eI|RNFqS P`Z|-B>!@OE'h1g/,?_NE_(3` ?)4QPvzM2eŎ>qs L tΤ)/|w0?'֟]]@\6X4Oez4M3xٔݥt C0`(t4}Cvo%{j=1> t ?E-P9,-s (0h Z|-B>!@OEȧ`~.@!r6:z|XiPWzU} /?3es2-ϻPOO||Mj3{m7n\s9]|Y+i(Pjp/|e[p9"h (0SN0?OEK dg3Xț?30k_w@baXV@i=>}G5p£%6[-&Q0i^꫾JWHSm' v 4O\21gq5q|>'{C0$:#MӱO^]YH|; IRfNFR$|,oΧ($@l㱘((u)ҽV5Oɪ*  b1A(h5n>qp@O+œOe˹p$9^$%6i1j7DC=Gew%10";pp(N?#ENG,7 QoN|zwN:+IRUatVj`׍t). J'Dz8{bH^($pD..$~lEeiYڿ-\:?ww[I:PρP_/}7~B3O@&'r^8MnC]!*oTZD@ ߵ}øv}'%M|V=w\G%_rWNl-l&liLc Jzk _|GI(#JEg#oiܲU@|}/yk?Q |xI%1MLzg"s s/MsD;1Q.mٝMDQD{Oi ?:p;N"GH+,p1,k2~bzGzGtS=ɤ9qeO '%dXx?++n\[P_R@fa`AԜdp28t8޶@y[뫡~jk$'mhbpR< 1~Ss55 ˔1 XT$,L&c6m65BqFOϊ z;sMWXVVWI&Jzr*?L|t;Y/S_j)Rdo*XvpX6rB^gNuz\0u"g$al^Řm#H,sXY5=D+$IqϦ .[HPpX<uxfpSS]]=PH9C,KZ6E,f֡AOǣ}q;E!Hz\Al l, >H)&m҇52kޤ3?CLiK3 i'݄\&B̓y26~$z c' j[k4BKI=߮'񳍧>E9s'=b-% pdIQ Ld"Oq_Lx瞷;o]bUiw{tS-Utu=ߴ_RZr L}d2gV0ݟ~]Q}hrm˚ Zvd[zluC(c!ieDQ>}ԩI:EF%;&'^ݑybUYm}Kʆ2r_<.&|u`H{hxxDMmq7>DӉrTo:χQݿnҼee[ YYlVòl%9l/-zG#})%RhOFXVRyk}}f@}}rLNg`FQ5LEQXVz=vٻʖrmVՄÒ䬫]>6 DDQVzL<' :UbXv~o\q$l6Dd6(Z8hOZϫá`I`‘l6(0)/XP`z>-OW \sa _6;BO?^HY{yFkvO39g_rj>9z|Lcf_O2ٷs9#97_$T,ٮOs~f~&?If*+uEqDjO >q)՜uMeYO8{ 7`Qh0+7y{aYFI~,Ow\#*Jyl>c[G`-,R q@'#)/XzP`S^; '# }=>E~Ri=Q_7 7v i=B/V}Zft}߻mcw;wqR/RPV܌|Ea@\Cs }=B@'# }=B@'#)/8>n>%c}굆cv+cx >󕶶ֹ=`62C%>u?̙9YLǾΗy edJv) (9>Ъ;QΧLLb,5>%uf% ]d!CvWnE$y7lz}i֧h8di~r+ReVbVPHLDGn瓑#F$V |bܔlSr4$N:#s<30t|&ZX{=ovmx G{R(%F(t)5Aq\XB_ٛ7uMMg+O*=+{q.M{v3Ou aV=9L=N3/_d0NO\r+JɤLSR½oo_\_hh6u˓tuJO3^yx)KeƜk&r)Tx.K0)X$]`)]TPWW Y&8~cmn6&'xRb\DYhdP-:y:qxC_hʮlXUj䔴~c`A4듑aL&Ci,].y;{}sB&]<9.mS㤶*"%:92KF+^{jKcMSD-hq|.@iy1NfLfVV,;ޱs|a:Lx'ۥ)U/+ ukWhYذumvd\#Ԑ0 c0d2-`i<[8nd)ܴں|\.*, q@̙.t0$yoKYRd qJsIɈ$ScOLFI*mohlknq9+kWOm?䨋~tG x{:0,NRݥE>Qӟl[:?hTvB5 ׮ו&:,z cͦ9~W{$2R "P4t'#c(Z-mm}1RUninqJNgکs#A0j>:S_y2Q.{iߧXf\GD\YYmvw)g-+ynGvy Kq O>Q.QFA<^aS ˳YTJ +uFt:M&,HLj͟p~#b>k%ϟ vK# } ] P`z>O&'ޘsDI#Z J}R4+S@i&wif U(OZ>M7=*2&q qI`}z>OGS^p|.@Oy>OGz>OG P`S^p|.@OGz>OG Чd,󕶶ֹ=`62L!s L}xY7ZoMm3^IsN(x`48>ާ _}ROmRm{NIN8v=wٓ]dJ1ex>ZzEH#NY^JC6rf|2ǰ O͕IntS^OK 娜N(">E>O]}K`p4T*` wS2/yt:yR n{4Ȋd3&2ϢfaE8G[n^q?ԧ5d)OC%O)P:$fH2#Qaeð&x^W8L(z8\+;jyU>#F{T]o5 BI Ymw|w)NdbLZJݢɽݑ\&f)s곥r:4Wmx]QCl !)n{xknz0}|>?y,Gi֧c{=LɎ!%%CZu> ?IAſƧPr$ 5d(ʹ$o`M.ntB95N[t#J?;{&>ϟUTBHUZYAY&W#3OFX1p/wqSv)L;EzezS!!`v3;Qf3n:uFKy>J>wzeϛ]6e^b=JJ{gGq{w-kmZ Ȳm( $PETR )` r 0|0BIar`s1;qÖdjwJ϶4ϬvgV;=g<@RˊU((rFDJ%QČs¼HtLsQU\wFW,hXF$*yN3$9Vb>s箹ϛ~jEO߈|TlDq\8( b'3*n8bƎv;v%% hQPj'A@<,7acik\D˦dI I6,QUSB'EYb{Uƕgۚc <"" OǓ=ON=lخ;--ӄ)xdud!A2a|WXܼvIKV\@֨(=2Qnf8ƤWYq~Pg>A! :kXmM>pPԤ)?ճ k"f|D? ֮oi86r۬[<\"?SQ3L9aRSq<)^j$Nt{{FDp^y#Сrnz}݆x٫2#Oީybqx[-b˗վX4ZN]OC&ح,+/ϔ+G:̴P.D $tq:3qIpr'/y;{g鮡ݴ3 JL܍$Y='O>d=jyf/S(23潷KuR=s\ A՛KJ{~^ a }BӭCϞPYr|Q;p'C>O*& KnP ƐBuHMRKH-r\`n87WrH<9ѝFytbk<Ϥ/h)qrՅ>?P k2S\2K'Oy+e|b`8 "E>>h+w.g! 8.Ib63 <{6a~L[?3h;8{篽ɦѫEc|slE}CrX(ƙt-w^YXN0j $8IfxW~Hy3{|V'/QՈO#{>޵iQٱP(08ֳ?9~誵?x@t}~qXhNjQ IoH)ż*#(o@e3B~ԧ{(cB^wQ^/HW%'it9&O>ڞF-kkZzF<ް ziĮncYYǖb ,*E歌C9*Ǥ~V`Ňs#M˥lԵ %A~tdD+[OmhZѶ) ;`0v{'Oll,[Z97811K:( Qb33#s`f.r`Oxaz;qiiVC)sȻ[{w{||VWDŽe+/Y 8`ZyvO.Է 2kyLHyj誇oi ꍮ ToO,[M[t,>g }-Tvik w4յb `n^;\ιX\~{o~x,=o͢-܃v 3@!ឫyh{w>8}{N 1NO#m>/^v+i,v9ϟ6]>DәUe#ay׍Ac}-.:8ӡ0Xv)}:-bsiT6L in>!QhULڭ.JU7XGgH*r8U?mhF'fDxMiDzEc}Wrކ(]k@~`F@3S̏0?0mS 6F_QW2I9DL ^q3" `q>x?8]=k ť)I=qۦhÅFWF+'=}7lԞDqɿ!$%3:.Ϙ5*#ufto(biϱ8/w1G0o.>Oru*BjE+<2rn@4B Ļ7% Ŧ}rZ0$7Hm9Vi) yW?˕οK4f>WsSGER >"j XAoXwi5QKRx !ޓ ۃ4\!G)IQ"e,Aȷ?r`_MJ#}mA1%QQ|+剹Q)AHQX^u\C ֳYSC*DBKiT#})[),UkM)vW48S8luT7wPr'v ^LٳHj57G5@Jaٿ|?_wٯutHA{p=88Ntz#(:-%j}J? ȵ!U]ٳXj@11>IeIn$K26d~;P6)G W ^(W T>=uڝ!XDI]*PW9IqhZ89-8"q;H2Bmc:hD?U(jQL^:”PH֒pJ仅uU~f_ 09X~t lxS.g!|S)8cB{Oi^ȧQAZfiWw*)8J%O*W]wJ>}Cx*"V@ ,ԴALU ,q{񣅜W\;OkIgd[uLf9R+4I{5`PqO )bAlob]erL\i:Ňs5DcTM>hB4P$S86=u)աO4Ew=1HRfuG_wz5lAb@8OHRcNZ}[*QU+tŞJj\*P JTQ;OG\P Q䵡IENDB`knopflerfish-osgi-5.1.0/docs/images/desktop_on_eclipse.png0000644000175000017500000020333012346515440022727 0ustar felixfelixPNG  IHDRSqqtEXtCreation Time9ػtIME pHYsttk$VIDATx T3pDCLP|`dQ|ҬMԵ.fV&!Do/V#)-!-Qys=sp@laڟۏ%nnz:zNG]BP( BxoNV96knrf'd6;α' "V8-JRRSƯ!<葢P( BPCa9+ ^2]\:9dRi,Jb|I_~ؿyx MT?YIez[(jB, RRǃ7 BP( 1*boqߑOȎ D0[%W[#~QWs'X͆}lͽccKab)/0,v'dq8ժ&QV,`C"q) BP(ɸ](Z6$ +Fo_L"$M_2@?P^ qf{Ͼ:ʒ,ad%v$R5c##mˍ457?/o1LEEyOE/}VؤphlQX`[>|xlȠNjH'آG$.߳_`OM A=KJdo ,3~Z+b՚? G~}/fd{ޑ( BP( `CanSBzEQy, yeUgXo6#FƏJTعDdQg({2'BGHF e5C degZ^Q4;7yܹ81?5kYv7e'g*wA v<9kV'<5'$ [g:tIRw"ǹp7| SӅw]| rtWջ.TҀg:Fc0Htp_1][<B.&9(кCI7y3 k`ov Yh'vV~Ke]L949e;{cZ6R y\w^K``D&+$7-gKMg( BP٢ң I"u@C>2V@&v܆ہ9F\t:5Z,laq!>x@-|:y֢2n T"C{ "]\w"Vkn~>Vdg@Y01>>sҊZ^/i_"⨕X<{/JLƢ;_zYԮY|O: (3 BPH>=,PF]H̱F8ʦ [Ӎ;'1>Y c_tӟ^#ӦDz}5ڻ>觚_oYBv^0ߜ{W/ESYЧk }U[_0bosOܳm񁎡'[WsQ*bH$UCŅ;#obRB#{Ց\h)䦫~WV]nlO͹A?Syj/Wn =px>&`{O(] vWOaPPt( BCm!} \-'[dC vQ'iW?n3vPu'xNx12DDtL{i8B(Wnn`pa\H}cbssS?pϯu*Q. :.yf2x@RbQ^͝D$~E^kIn}WU5jYHO鈤- 9Ӎh 9M2/^nO '3}ª=3)SbACkk:h݆w/,_.0 n[~Z5݅zfүI>VT犽G!u ];]l Őwo0vwO!R @P( ^G#IX(EuN|Lu, }NEF4FbseA݈^JH8I>r36䃝8wwfCH$<ǺH#'MZ,KsNHJ~@`ɓFcJzX%ōEAE`0"9=.퉣(@m rltA]+}\FkLE7͔a SyfΣΕɖ957k]g$ n_S6یOPT7T#ևdtotSDp釯J*zGM38aֹ1XJ}{{-.Ok݋NJ{0єA-rwO1 BP(BD#^1 n/X (/i_v(g#Jx-v1x'' .XgW D.utGoNq鋏8"QT*P?66h2oajԚښݹ+eg+-^_Po_XG!ǰڧ}bDyQCϮ<C?Vr.4bxw-h *]z%p?)#E)1<_[uGD Vv?ZT|+l0dH_P $ުtD6L<;.^;z.c CC 4^AS1qعi ×o[@4WnX zuOz#4V8>n`pYP) J75\k2z ၈:{ BFm:Ȁw*~zyuQ qh=Lz -%. S(w.>//?kN,`4֢g'NJI.-/Ϛo2ee.**9%7JCl ت²Q'Bu1*bz=hJ,GIQbzI74ǷFaP~vO{a+b'=NM+?6!jw:[iRa:u O'g _h67dV^?2iIO܂Pl5<:&M6a9X?}mҦkO|}Ω1-j(?^x%3N˩oV]^0u/٭?{5XS\]Q|EWY+ڰb3C64MC{l.R"OޝjvQ+Mɇzk umw><ײG-{ u\@{X $ל;ߖXm$(|h IO --s3@foJh 1Nkq8xݣy"4ެ =40<ӹ'ﭤG4\R*>9R@uZ1|(jݚ") 0Ui8_"_VTF$ ܿEyJO(4Yg_~*6`THXnuw _y#8!Z,R`!Ǒ",/PqPNinXmVoMjobyզ }7؆_c&/ wӰźyÓHM(:|DsvMnDri1-6ZxSx1* !6`8KK9.sboE&gXw-/̋O} O79,*Q@TMSu'B7ToXǡ5=L;_* y8U@Dz>,*:ˡ<ɹ A~q)Zl-[VW[K_T0R_TRwE^+/M1@  Đtzh7 h& SZm2vb͉nIfj'm-Zͭu1#e[[V@J) >fmh\L6}ߊްВ[9:*zB\>۰ T JXY ĦzД l&6I*4}Ŋ4&^h=ieުf|!u+LdT>~LPiBqY&<1@|@*14bQ( _ybMk 5sCwafA#Kcg3`\@E# L) L WR$) @ }da_%%кm wH)1? ڻmKv q 5ͺ}i URy @_SrƏCy![&)g s'ώ7k}8в 薥Y '=ѽWZKN2*Q՚5J?P:gÓ:2z+ R[uIS;RM$^ߺw]N  k+6pdHεLG\~,?#МA6kpןYd7*p=d,>=% b@Q^_M `&q,:.gZ5Ձ@߳gWm6f93; {m}fЎeϽ^1|xnX אFWO*b PV& 4tʴ{\8ěgQT$9#W2X? E  KQ iXЅ7v/|m.̝tvj4-<`@Ɇ&';mUƯREź7W]w]_W x{eY~"8Ytn6hU`HH)A3|z1_ 9AhFK9=2IOJ?῾fL|8]4t:I.\u9CE7ZEEEϼ0gWZ5wS~ƪgGy+=PY ūGQ8@{T p$|Ih&P(%)*9 |UVVZȰlxq*@hJc9˫-//8]Ϋ'f$|[o61 Ax<;Y+$J0h|2}%0_":sV.}#nj?~۷o_䲗W=gfXb|?{HݽD[ދEG i$ J&\P_PVFJnDS&zt5{L~[[By!XP?"/E)aIviqS6D8Z~0 qNߩSvn9==}ҤIvz_ y763p @ZZK@X9<+\u镹׏*((ظqcNNI`m۶W"+gvH2MJ4{BaY1)!Zwz&5VRt Ʊ U~Riʰ?Ԑ?YyZ 㣨[x* V+m9ee\n˕E15 yn&機^?x ._by]V2ܩ&7eٌ.S'wKW֧y} X6}t^,O^x+jdA @\"Ou=''$N-Lk=66VԘ+R AU/Gcze,E*shYCfX46AN"_G3t؏r` Fs{WQb}*t CkhwBcaaYJuqhFn9R=QDvfw б_@RV1`|a3a[ˏ92घq:uyÆ#3ftѣGwgp8*++m=:~Xw%?X*߮T}dyjO,ٸ\rWksɽ_(dwIocF L&ߘ[[O-B( [K3G3._=C l6vsm'R$54N=i$>x~RPePHv/ ~u>###+++4 ӧOuqCiJ5 -&t֕xc~%ohhA-;0 +*+~1[o6oٕExg+.]Dm0h`U+?|ґgðA|З۩H2DD2tpB7oq=8#k1Fd{L=[+Ts;I%U\xo ٙ|ŷCx/@R6lФ7022Gư8\}~?'M'p{]3]&J*WciYHkPE_86$YzЀ?pðĖ٘kcE -y@AT+p#W~ + 2%)٪y$ϥske m\s 8ѽW-cy^uR.V~?{wz͓mhTx[lh3sE-Mv 9ʋGHy% KC =+^Jv[Z)eO $=6ul6Р|un@kY0|`Pn`d-==Y=Vեc>|2@aw|z}ыqQLUC;Gܧ~:OeB2{v! 1>0r t4ޙ@GQ{{t& "9yGy939PEp]DHuN魺k{UIDw'sVww떽UцBGn3!d$@"VGknހ+fB  1 D*^/[}6G[@ @]8l' Q؝6bGcz_Uai|YFDm9@ EP]<_S.n3!$$0gozInD^=]_?ܿ/A:׆@зg;n Șb%mdqzy?Ubp @ !1lgu 7?vem_NqQ:3'w7:DD V^/e۾_~w|]f"_{w\@ &lvy˔/V:\uݍ<Ҥ{m/li;j qh  ^7Xi IFOC7EoB~Ign dtZ>ҝ"*~PK'zk9ZL:欐@P4s cǪ@5gjUUrmd'$BB盳oxo"JK >蕊zx: H DȀsO~m @ ѡZTtCP.|@)1ʲq,}\k`PB`i>E3ip&qmN1feLh(8f0?dj._'ČY 2n3s iiXL,cܸL8KSbб% g_8|W[ܓk=F zrk;)1e E!-t?mŘ8T@2lvӊCg2&p߻*[j}jrVMÍd){HsN_nw4LI&Wk5"'w(\D|pص M1zJFyT $R$5UqsNL%W3& 8:\T*"јc_bz}ϡkOzeeD{_v+hhhHJTYٺ?vNCϮ^AW_@6p3J8PۓNՆ ђA8hE(N,(\-M# %Q<}ݺL((,l2 aΖȴspWA?G~GcJўO^,}pSD_p:[ӵNߢ`|ɊjAd/,*yˇ?GvUIѫ;vbDzx3Woӓ{7;@%??5P rc?Eɰ5)FM)yknk^ow'l (_hU7U;l`XV@S>KTkkt'snYĂ Ȅ8U/ux6oPjrZnG[\ʜ/.%WJg/O,H2Ex( Aۭ73]kp,2%"K 7 zyRJN3'Ƙ;-;qrCIC ZQTaFtw;=tG0`@c@Ix䫫KekiIMgwyX+*{ JWH$bS|O\?E4(c>ROMuwit)I7G"U!V|g?u~ [GW5͆ *pI[̞PfiWuu5+w|Fz@4ULU8+Wk&I&"f{N#jr '岐_" ABڽ䲔(õO?UR;aJbr|欶Sq|ނzlU]զOkT.P#c)f+_n(!z9]QCI:ht1Z eՠB ANQQzɲz#=\q4`:_}E: ~9gUWSs_nE ~Wp/Ο@775쓧.Ī5u~iKI8 )IhB&ȤR&Z3W&pDpq4 ?p^Zd'[ :Sn=.衇zn|kSK}W<$R3ű(kx Gl硏xxOp-w/ԏ EN:ޢERQI[I!AFj YꊋxyE I{<^F+_gn0rxbA.G;A*ȰJTB`p 2@2rJ0\CS쩻 /Q`6>xQNrսd0͍ʵGV>7_ߐ(J=D9P\qgwC?p%] vⱆ2ie-2 1)Ǥ6(왼wrL 6 }|0Ř_8/y F>.EfKQE k:|c9(91NU~W(7YxfJM @QȤp#0pޕ$AghKMo+-E8Bz1-z8ozx|K so=d7k#*;CàG<ܦw=֠@ DNQ)%)T* ( q)8iBqTFuulP>LYӔ)Sz&Ӓp71dZ O˥$V  w:h~%L1t:;_K}`w?\-= fjML-QVKӉɩjzCqM} @" L foMSE)T2 Nf'XݹݶdBz1>BIPxظjM;h㝃 8 LH7DAbB\K?>>>p\B6GCQ EQ 9hmmBtnd?9q2mb RT*GȔ_Sp骓-MըTTFږ9.-PqcTsvK*v˻/TpK,,[P\S;J쨨JΚ@zjNWw rWe/+-޼y;rW\kb¦ǎ!a|G b|@ CAW3NjBibRufN~uظBPH$}l]vw;1*}A$0c1eWRdeD[]LpKD,_bs46M8 95U=?c̃<===N۬ K`e ^] ?!dH*jf!^{cYd eɺimYޡ\(zt~{w}g_[vqƛ k Ќ*/b: 8?` s驁q$vWUjb;M$Xj7o޽{ի9O{Yf_uџ XǙq,g\Kq++]^c/ueχ²}{?Y4MsN>{Z3c^d4ԕTy*NQΝ/iXtyGvں]vyt"wouvu]Nc7'gA$.`/bAՇ3]w_v:] պ烳gVTT?___700pOSSUUnl Vz=%e{ph!7o7]ݻ}t"+x/s %v`/xmh<|a媕GC@oooSSCuvv|od@\*nm۾};/^lW_n3 LÇV?{1 V,}akƁBgz2`/]E_۶m۹sgss3EQVzp6ɇ+|}~ݎ2$ f|[{zh#+):;[6nT.xǏ߾};wK†iMkVve֭mmmf·;f·'O w|t `Nɨ%VVVT 3Xc.@r;v;5U۟ƒ@M[B{i +NWYYDYBa)VŇ6A>LYp5ʪ石BH!W¯6+ !N $Fz<-]gw jߔ UUX?J:uP5(sd WQea6YH\FNdyXKM5iTd:V ]g08y|= oq5ɨ (ti4r0_P#OUNpW@ɂ"W?NP"PD 0j}I + CgXfI+=)FcI}T>( $\XGWV"#@q"CRKQVII$TV6&:v1)U \f)Ě⒬9Od;B$V&B9+RNw@L y/,gnbWW8 _ wU)cjɧɭᩔ@H=-.r6=/U#r·@zRd)2-w5n;SW5 5āAT9:|k5. ~,ӧI&R=۪ ~-'3Ifn\=425 soJ0Kmjߣ%#pR@d XˇQ,@.*,ëjbBrUR.;uͨRb1jnrr30 W3nlO/B[$~@?w!9WrKVQ H$o~dJde* "Fܩe5jǡCTW}~5jw~CeQi%%NRuV9iIVL)"N$GI$lrPLɟuařW:* U2 _IRY/G*-%`05)̳9)RO~ Bx$ӊ? 'ɌzA/ K>/T/<Ǫ\I"ʨ|:%&V5)EodT WX[esq^H zcDI@#Ml~Hik+Υi9l?$(hS]FL5[ !A[ā^xQI qέ?}W4ƿs?̘]q^#FR8P*'>nS33jT 5昘rh9b9rBb 1%E asHI#Yppj4>|@ @@=]n]wEs ni|6R.pvr$ѽO@Y#(9xHVD{H@P|,G,AN (ڢ$#Bsǒ^޿ה l Mn>சcraQ:r}e Q|$fd&{*=xk۩cڅŧO;URbEb#~11 6ӵEƾMj%ZB@ &֜R$ai}^1/wP oɵYjk aaE}qܾq /oLYoztggՄ U,?=9KyV[p~3P$B}iT`wOݳuieMw&e„&lf"N9i~<;Ei;+܅\{ + є:eRK,}gZۦe\yKk,ѳ?bk71@{w᭧Caf z;΂nыI2$ͣ^ðwDO9)ߥyں5V;1y@#KW,\Gr G&B=ϟ*q~~v$s{d /`/ nMS&޿^IpEi 9}2/MM9۾ˮy&Ǘ;,([3g4oֿ{;C}Uc|:g5{d˺ҖFQԬQ㓬o`;TxIMueA ilq^pjrhk{s];\[kmfCK_^Z@0< FĨo[Z,T)B{(с?EA% ڪ+>cw)ўG|,ˆB7mX$HWVWFߩӵ G}p(tPn:}O-]ae,+V if1L̍l^g'9JhuɃ-_TXX\TWim6wVbl K_^iGnaXٗ*AV-lGrBTNziq_$ zDܸqq7HI€ Lym2wqߺjwf[rhW0 uTW2L Eh[-&d4R Vǎqrq2O;9<<447I+ w y;"pi&9d2a&U^,1z$kؒ IbQ굍5` #_06{t_tom۟z^}WG1ziCLZd7PX䙜(v5q Mk "Ke>0_b56  \v[Ak`Pse㨀͛n_XQ{t՝hmɲ-GI !{8q!.-v8KK=]zhwa:P`)BHH(ICn !qqllj3#B9HWw~?is^N7=3SZjY Z_qnr=aˑ29bh}/m#rs`پwϞx k?yUJPrIjXF>ה<{E)1DWIM8a.f=o`p=h__d*//ϵqL鞛l446=ǰ~^UcUye`b%99ynRiJe၃jFaƁE&"_//ZP |':qݒJQGrMGGx3~TVU˧e/Tl6 ;UVڲBЄ >3%555{jo.?rIs}]/s>;?vqvn1e-V,ܮʚ\[S_@R;W^ l浮bmNN萊RaS~rT1o42W={;׶-^8}v17`YVLB-+dZs+ m=?rO̬]ÇsmAQUi7_6C##Sx8.]|`<FnwHx<&>&"ЄG\3øf'~%FvC$w Ɲ[ՒojBy4&׺2w yP`B߼jj))1,;;;{[,r_<~{D{{覮\겏_{sOٲRQ1b|"bt"&'0DO\陉Co޶ܾVO2𗲀O-ᑺd -/!(Y樸so([kM  k־w^x歝{Wv65Jt:_|EBxM7555a?WyWcC?coXYnQ&Gt*^3s3Α?XMxJ;_ 45nOQNυB xw9;X]|j |XRRec2˗/KUZX١cֻW556FM>) +ωjFrI{PT $7oh4fY,i>u9r 9r/3˶t|٩e)+x^r;yMz1g˵k_ϘJFqBW,/)r %{c6} xGR$Tw!$t q%KK ?QsN"j&Lb]0_=0M$$P i+DB#4^ittҮ{TҍF ߟ4LvPSHWC4gLQY>S?Q҂L◐[K㩾息Y/}W~;z@On%W_^+6ƭI8T'3ЎL\Ks9 jJNh2iڒ_aJhIcRa~KWGuJBӸ/yQlvgID՟:Z'8$ |6bz__2s$s>g_ !}Ih#'NI!%ϒ Kw-T >@>2fّ}jr>*s{Q ^c&Q% I,S"ƚ>k rBuӟTz/oZ&=O0!F9%!7C2JHf\\ʋwjV~?ǯ#7ǭ_yɺ#GG&ekW ~i%%D4QGR S1MJ}‘ ;:D-]4$L,*Kҽe?*G:2˜m(ZŽ^'~ɻLI(^ku{? q zZ߆ iF`2&ae2M:;:鱸r3q5(()}j(.ʚ#Jw g?s}hοQ~ -7 ~<,%!)@ჯ8/'zOA+PU۫GVY& >IZIX<v_T7MUDGfPD%[DLb' |&; iI7?IɁ@I## 9h[m^By4G4e.|mDǹeLJѕ%m"@$ NXôfR͈/QI"Q3:疩/J}q4O)VH$ N/ Ei$a4Bg'eHM""4FgAt+ΨY"[π !#4NH̹1eDb tI4ESKC@D$Baz%RHɠVm/SqMT &|]!Bҝ@$)H$qB|F"B"d Ƀ 8T($H("i#GN U@/2 , !sH!C.Xh`Dv_uHS @w:W۪նesRPgS?[R&C5*@B; # Cd^.<6Zt!Р`l|BՔLNwמwv h4ypKro) Kшa9=JjTO/읹rM]kĸ'A g^0ߵaeY1[MyVsК_;8aT*<%/e) 3KJm+xb&@Cԇ^i3 (ѷo@QdG~ f~_;nX,~Wa[&>?sa%LNNlWs۷XL]0𗲀/>#R5[a[{mlxnuzF/=w{,X;_]WnbB()5?~=#Zm)v?zٝ{>z=퇏]׬wnfv隘744޻G?|jҫ6p/~4M*X/e)>8f+m֒otD#5 V<#ǿn[mCNɿ SRvM[M2 ӗм/p̨ u!^Nh[wV#o>zuSF#_fok#seo]{>/ͺ]?{LM Z(RoQX]R\iX*!?L4G :vU#uD,WE=F[eESF%yhP^`5OuKJo^TSn^-Z?{wGtҜFdaY^0@0GlUȺ=T6٭&!&l]E]0,cY%4iYJH4~ʦ==^_\R(X¨_}pG(*S?Hӥ1z$ˋ>&=S&ċ.ui.ǮjF!/dpbdX[gݼyΠNn;7Q >F!Rǣ/_(1>:3j WZˬEa~wJ&&coEk_ؾQnMs\(p*J6 u>[ݱu}`k M:u{L]/lj.;3Y'j6PhƵ'}S;jHPk|>.x|N(lqtDAIQa+ZFQ?Vۼa=S7!DN?زmʊlwK/ ^timt43UcgeE~Mp'.*( j5(}d?311KsfK#8f źҖկFGGYu8}}}CDpCxHպ|Xy?'kj,Z>*E6KAo+4v{OpHjmXo+[c_l8JTaUS՝YKp7\@_?z&*ZﭩS10QWN?m5k4jQNy;vݰ$?oݾi";/ ^4bY` X%sr`kARdkj7h>rx 2ddՌīX)sDKEv!n6p<`f W8swcEN ̛[*#ְ~ڞܳ{$au~VRv;G׿gz4} μؙo~'?r\eEċR.ө @NÑ 52#E(v8@1ꉎ#Z5\4,8"Hhi"Rr }^UznU[  u}w_C#B'YFϾ;Mp ^"GO$Iݯ~cm6:/ ^4jmn:z P>G Q‚^aq,ϲJ%_ ^ Q=#~XU=ji89uygyUhd٩s^]]7i5m퟼uh:]<{7r*[l==>qUTuMMM*ԝ$Cc0TNz1+^OڼACGEDeD([XSR"&IӅBh4x֯__XX)EċF%gF%$9U_i9\$z/ LZqU$#^)(d7pZXW^!D"XSSn\ymWEDG2뿟7*j C_j4nm^龺~9waYVNP\.t6)EċFUS#;K"bEQ4[lrv"*C F%o3j~*"+l23'ǜ Zȶm6::*ӻgΒ-O:7:KW9G:RءG|aP]t{niƍϻwx xNY5rf2 JYIk8=ٺN[Æ&FőhX`%UX_P b4g&E,l@0Rpe|]O ?Jj-8:%v|qI?$M ecz'_]/UtwaKLb,KIЈ֨kܶß*𸣢a(Le~N'"F\-LLLȶԤwd d4VkdE|M;ww^r9B>TuKu.gx+UG??}֕+݉a>Oy}Z@ٔP6Tw*l74-(!R=/yއo®n!^tAcXGu|gYԌIi"ш$0y4[-8@P8Mo~\.WccÇ%%o:jxo^[[_~eyG#nM.=ċ.享xɳұqsb8N~ A n!\ ?P***v)(`YvVx{gH$$> A"F;B`@v-]/J!Xݺe/vVQX!cCC𯾵]Q5T?v,,=2Vcutt']ǔdeًLzc35@B /%T,SWb !Tw.p),^ĞSϧ}!Y0'Q`6?L8.*2wNzph?CI~  EY3$\B.$w̅iI愖6cJYi{6~/RZ霅O7( JxG?qII&7V%?>&3K~- '9RgS$^y@8#9ʖM$P0C- <~^Tg-劦e\A3OfSLs3R'5z5NwT3=:S ^1yZ$E1ړq7 WM=0gfx[Gh˙'?P4gi72f G.JA䘽4.ɴ|tڿb TRK䧤0`bHA&XΜŦd9Ib0{$gyb[#GBCo\|f&AZbT­FK~=s?h̎TLL,o3]lK[|z(2w[\v@4H$ I*zUoWO&w {q~iE ^Ѣec?N[v0IPKmI[="3(!uϷH]0VhfptоKǽOQP_S?^{1L|2`4 B0|to]܇!¯/5t!FOV{mAHi6Aݰ"@NNؾo۱;es4S YK@ʀ,/Kyvlksz_<¾'y'%=7$7@,122SXX(ﲿ遟UmodF2],Γ{ۓ,aZt:5A4T4+t:l1]vxo~jsdoP+s ;PSp2]}) (o !5 4%F|7u.H(ZĈF]v#I'C?xͫW>[_~-% R-~~: t$w'H&Wg+M&#N`Hy7S'<^6Al@CM=|MpΒ^7:ZuU.MQVԅ'XY<~ȩӭ5.h."TWmM>l9eMh Mh_R ~{JLիWo[z}I0Lz$Ƣ1.TVssoYk~ܒhZ544IJlDɣ\:)ubAEi5j"Ikj/c-vXtp/Pj5p^3a .*УJG(ڗ@2n@ O1yw~8ܳHݴȪ3a/?h_ 2UCRceUEG"z$M{^t:() _/ kE OcغóG"Hw(kL{OWO:NH+o8z*S*IGr䒂U*HL!J1Gj !Z(5'%-\s"о5@ P dyUF9%!H򂘈%?{[חnz ]H$> ~0\zY$t`{l̫,s߼vN($QB߼gˏVXZ>-j*-vً]$H ƐDEW%(DI8%LW(kAR@ݼ߽c^I!DjNJ #E5kQRЙ7TP[o.MqctYT7}91_|)C&j DB*DMN(ɉ9ROO-\.z:Epl2M}) RYP$`V'" <ϩh cb_ a}n{}8??ddĎ-P]S)c\z=ܪy]]]Vk63]lVDsyE.wc#bYs $ It @jQ޵$5(6hm4:]p 6ZW-,UZKl`s"?h4Eɛl;=EՊZ\ uP|$"aXWLE6$IAh\E,>7UKY ^1~'l6\ɟ3p)a +**>o޽A[,ǍԖ_NNe˖D"j89u߭]貙,r(J!$5;7$zwK\Ep`2}) +#yQ`)Oy.ʒLVo޼((Rc:ݝFN}Z\3kgwwB./wNx-ಸz Hi1 19<>Pq3^rW"`w6+W_K>~YߋE)KvkJHBqg 4}-Q$ f_kR]}ڄJ_ dʒ5ʚ̴S?F9}e~yݙٗf_XeA@+O-ɡR)/W&NKWYuIx4{b:˗)u]t]`߀egvgv2M~y鞞~zٞ~7tUE QJB[IНLIӧ%J+.UMU e[.*3'REKa(7$;uba3]E]orQ,|!Ndge_d]1DZU5PV: =x6yE,r1 _BVyEQ737@ 7╧AΕeL~#kʥoTG]PL0V跎ikUaBVTR.wnr@+] ^GVᔏ U{49l=lE1ZBVt5g@o"PN oT5vj?KJ몪;پ*5++iBvd2KAӱ `C-,HJTlymPȮ'4O"M%!V'9X\!#E޿\Wɽ4 _ "2I?Ko RVys0k _<}L^lʥ JG\OQEZlͽ@Vڬ;O┏{ ֦$v&`1!c Rx2, dlA@()SD\Rs!!/] :b %`+0#SZPzҺJSZE6rdA`6f=W%i.%|@A`Ke`d&ӯEH) [u ȕDp=<a]SU'X ,=2AΏ96 ("HXb_l׀h'\H_^ vN'үlIȞͧ1&aΎ@}m:nt@ċ-W-G&v06>Qr|…S`0ҿo8|`]%F!^lA؂x<~Q }Z0N𣇞|[gU+3˧gf*oώ>ox<͆ b ;w9=炱?|Ǻ~Ou9--h,;<&arrm7}-v\ 3ċ-[/cef5<+]){ Gw7tWې ~S{x螻:;|U3LFυf&#'N7o^j96+7_xot-B؂x2NE%q :JJzL[dU`U76{ZUpm->3SSS8b  dU^ `2h;'GOJcW} 9}/}nhhlǖh|4ƣPo|Fw΂/ ^lALEF|BJw %U1\qᏏ\hfs:WQִbzקFz] ,yfg:cm6D"X,622f͚r{fM[/ ^˞+g}WvEjSΥ$X ŋz{_zK$o^i_za%M<ƶꖶ؞|ܼjѾʮKV ߽gwXhSYċ-Ԏ㊔XMRԋC;v_WѵEw\^W?oe w/rk푶1e "?%Ù'(4 P5Y7IMP2m3zN *%U2WgUB?` ᮜp[t@hErUd֠ms #8$Yz`02e.^JFyu?o M4CJPT\" vjdY4{żzghxe2J髢iy0ednR!\Ӕ]Poe䝯lI2䒄A'^/-Q0ë% *UЇpwtک?Iʽcg;:VkxGyJńtzyjgʀwسax&cZejhIZk6d;7t+0 @Ay_ `= h Og0dk.O-}AI mmsB+ٶ0-'V:Ϛ!Fzƶt 'skٳdx{iI#݀̒LIi%6 기IsnBB/k^Ssr:kZTV:ea|TOPN+'#q2)liu7bJFM$LDm6YE2oHt@9r$VZ9UUB[ ߐhg־o)@  APD >w?z`QG{WgGm`N]mvn}n7i b J"c;(q9K}>©Ph0߷}KNc>[/ ^lAU{!}7DCe,B`% '~CO>-۳y33|E[a>;>86n*ċ-[R g#?U֬#`1L&h7پ=9m;֭~ioii MGcX,1a m{[oRx!^lA؂xt4}%Pa/J u6ii~L LPJ%GIm[j^TvܔB(a/>;获NjR3w'Q\gFHB' 0gl,;2NlM|.SbIb/P ċF#sHH>fFsl١9{WԨ~=zuC֮9wRַ vj ۝}}}׮]+--e79+zޭ۟[B*ݬ|" $vxzVBl#KF.1`dN|/BlБ|` CfA1ES.bXhf#wW4}U9A[2fTWUQ>zUj_O}ݸyˆ->cnw%yq|" .!^Us$+Ld7/ 7(~f[ݞ:;SGdOًwO%O{{ Jw@h[n;sW6_g>5u-KMY/ _Dtbi J^l10&>;j}9>dni8w9g}d\u<6b\~iȖ <ƾ)/)+ٿh4.\'ȭ6 :[/ _dAt5*7ݟrm -aưz1o+ފvʩ$?)"LLSV6p|>;cIh6͌ߕʊo/pT5iZ=;oރ^Nit`ܬ_N<^f,,Yd .O(2IF~xJ~6JyEr B?͐:X, ,?3s̾G4͞23c.V3 ZO׍S *F^q8&TW9ϟiup‹,Y/eE0#EjzjSP+w Ry~c^644y˸V?onvvilmZRhS51j\fv1|" I7p٬{NmJEy#S]i= woy{Ƙ*^c}_u._&Ұ87_w3+./ _dA  Gxhڲ"^?dffZՍv{}:o_% *,hR C^Y^u]M[ә>źSc " E "@U9jDEoxy-|{bmu95cg>]/e;zAc|ꉼ<ۗj/ _dA \D'+JfZha0lQQfRS]z*-0.-z['JFgff|ZE[om // _dAJ><3h_GWw24x:G7(C<<5EEE}}}_X5 J^y/_6L999J7.!_dAȂ|xwJ<6$ @0Dhy-Id636ÔYVooFwyloҙrƎU\\\oFL#Z:fJEeggY,SnYjBȂ|J[ȭ_}xxKJ"&O{YÌS9si+z* 7Ly+=ƌ7Q:bsNI3[?=ejSRRž'Y/ _ |L}UsN1JDj^(t^|[8ś d@\:`-_}s} G5Uu왿]UJ;5}@M;p?խy_N]fϞ^WM " E+8})+ΫPZОd=%)uʬ Z7plh1mRnEO5{qE[dx=ze_WZhG^9}C=]F_wY/ _ +YFӇZEϐaV3%%T;]K,5b;??r zM3J}wvwzfI'?sS(݈4|" ğPhx#&^mXw!kJ[w .VvצV̂%V둃Veo~aԇI|" ?:W9edV:^9ۊʻ64H:,x䴅h ~lŞ?.0Mjn޽bɩ[k)}477\TSShCCEEnJ&E,W\MuT[o%EADHXʬxo^RRR[[{I&C3k5Z݈#l6֭[^?^^^k]|" 8K  T* XeeeWfyPӦM=|P.a?OfUNdN)Y/ _ʊUg~222V\Ңj%GZ^Y8vNo[7!_dAȂ|SZUUUuwQY/ _ $ya&2/ _dA [BȂ|$AӔH$Fwk9Bb$a: 9avH\P_rl20 O̾% CK<JV‰S 0g9oU"@wzev!B% F+՜;q$ҵ dn e}&Eȇ@Td^n*/NJ$Ts_VOR #gy5S| ‘EvV+$b0oĀêAIb wVU[Yo h|טTeD"RM."[O_X^T$.MR)MɟWȩ&R&p::?@{4ϔfdGDM$)x.bK4%[< SƋ g~.V!W!8.T(YZp=ǧOB%sTRv0qP$M{ Ev; ܐé6$7*e J-ۨdNIX35< ž, gaN-uD"*({?K 5?D)8A4j"xHe,y} ]S;V}.pb2*R@QUK-s2G.\UU˼6;W 7$ZrXQ%0enœL߳l(^65DvQp%B1Tf#wUX-}2S< Bc*JDBwwK'ZMZIC$1(!#u秼ʯ\N%"D"v92+,0L@<vOB߈ħ)V<2?0e6DfKH#0 D䟱<:u##Ԗ@K"_E"" r]|+Ncp mGJOV739&Oq;}qLPx"h@~䜡x 8"c:a )gM) J@ɜOS$"*j_f.^#Us$+Ldn@Ks:=KW#E + Q[@@%RV.͑# = [  5h1(6g ]@x{ռ? ŧS|^dţ_8%)t!h3G?9uxw͜^?w E0=s1g9r; t w{Ϡ+t-Z؜k1 Z#= jBґ@x;|^Ek|^/W_xBx8ou{Xn%ʸ} 1 IGZ`[6]XW]+-$@@` %&t+ Eӷ/.{ ]]+PN`v3̓ 4G^ V{޿ vj}8fk܊dm%^@=") g/nsowȾk@"n.sܱ<!V[_i~9a߰kE@~14|-_r4ƿ&`0j޹7"fī(Kx+;gbg+F& 2c'\9Eea_9n_gU /O^_]U[S]? TAABZ}sY/ _ ۫Q{-4r}/~@ɽ^~vϿoOGg{zGl,'{ןӚMC6[rOh_yi{7!_dAȂ|)%).1C1fdoZ=.K| YeWѪ_,ƑW;xj xpԧ1|Ӧۇ\13p}34{=H |" s̒[?Q:V~afPZb &5Dn?y#0h,}OϝX,viգGW nz)zwp ?‚5O~W[q|" 꾥tqDz/vina*(bTkW7n:ظnښs.h}`w{ApwڵRv㍍Ͼڹ+_ݺ+Zma,Yx8x!@l<0g!D!x)ʪ1dS4*-o62ywEWS,cFuUcWV?޷x܍l1s8z.f]bХ9/N/ _dAb{C!tp)CG4736nv{L)=g/=aܫ_f h?-(*a|RS-mݹen>q;گ-ym\}j[/ _dAb'G>\7QkzZ),öϺOؒ-7?zR`[Ϻ'Ǔ&[Ʌ8w9g}d\u<6b\~iHicߔUr_vi4.]qvwV\S]-KMY/ _izA%Lؒ-x  }w'@nTgǻugMmMKji4ԣu }Ru84mUAq(+VYtHv CW|w;~Ɋڵ_*ʑ?>KV?ʥ ݭIZqcO·OJJ63ͱeZcZZuoR塏ɚ77Nv7;mAɞ#Lɛ8m-yeUխ{}WJŘcߓţ?{kۭx|0^xEW6o"K߁/pƀȥ5DLm-)#ckmwx`xFj[o^+%U7maAݴ<.**]|V ^;]aݜk6HWsRO[^E]EyǏ|Gws]}=|t}ǏxY e-W<]-UU ]0H" WK9S+gOƫT%[H |~%y|gyn͇`]9+W-th(:n} Kz=>U _kw***ݿɆZ:/t['D'0{oTpsZC8M۾Eǘ[0ǰ|}꓉?/r8.ZGQB^J=p0X2h\X<{F~anw8gݓW/Y/~(J?}]s|+;?3f-8\|kfmnm%쳿 /c1^xY Sxl7kwO|ZYk L+5bd^6т1-1ËpG ]0M1C'>i} hG^oo~,N# ,%/OHyϿneu߻oڴi.\dǶ+nzf^M` 8k^SSS~AAYYY;7 1^xY U *w$oib,R XgQ1ޖ iP6Q+툂۰߃1E( PG[]Q苴ǘN E8Fj"&l#~p|L?h&@g@t#~hBt:IUPRTiyRixN+yRed8{ylRIII^^SexY e-W41||W;֦C&~jW7Q_mdXW}-V_4~6FlQ &֊5qVQ]KEGh*s]c(OlI0CQfج,]/BܹsVY[_zM U˻ݣm({.,flS'_rE˹{B.Nx1=/ka2w<ᭃ3~1em/rAA5n(}m9)1У7DY6ov."cE؋Z}X0&;Jix3YQ6Z.:a okSxcNMV\dh/KX bი Y5nnQL=ް`yeOLqy-IKٷЫvT]G>7e֬Y{UU].W41^xY MF%fsdlshx%p3 -eúZZ9f48˃x\=2<w!\ż*fNJ0xWHQSvZ>HrGzw մ~Ib0: 'vb}tG?+/+]{' Jmܠr7-ӟ[zߧuuLo'??ߺZ/kabs)zi;ıSP[LXПFD/dn0l wdޅ8$'* 7(ы97Gb}Sˁ b?6[[HM^nn=T[;k 3}~S\P=wt ɕ[{ق]ZlBk/_rO~Ǎ^NdZ/katGţXJ gN#7/3.2Ɛ2-2POMV1H͎xojojY piY|Fq#kgs6U4=yyNS4;vD&{P(dqaKpw>YVdċG)7o^kkk{{77o={v&c/kaip=5aT'T&ܲ¢tw(㟋2$L'f~_,a"Mk׾˵ ,x,YR3uZ0̩liiټys}}}? ㎙3gN,Z N:*Imc,vkSU\oVQ](q" -U/C/<%\VXa"M@۾}8ݻnX&CmQ#raam|>_AA8Ye-dx:+o [quyƤMm>Y#LG_rOOT\@yo#ed2I!77w˖-Ov:%%%fVU3g|O 5(f;Z/k[ո_s+~/(Ր,IA);C]v:rJ65nvj_|s7(<݁$KEYAw]az#`m\qW/<`9s%t@iF g ?0M>H E =@lq]C]tks%u@ pt 痀u8G5ovU+viOIW6o"#&x*j^_V BgEz `mv}#mG+ݪ5['jW5X5 @X[@w^sQ $dIںv>D<О6?2(MXaFm@k =O($> fPahLXr(ZA,5', WGa6$@XE'N\6UP;$uݕ-8ʺ<#5q'=Vz>_P!YblۧӑS_qch-j1$V ,fs8fGفV(`0!@P[p͆kU1e^*1/) ȃ7QB`& DV n+yUH:sDEye?M%}O ݞy7 ;f) !^'˃~yD.&ʦBaJ47[`vyU?$@! EH,Bd Y"$@! EH,Bd \LN7;H81sF(ıI HCn'--lj4=Sb~ <&ϐxqNXc8F*IΡ"OZd"hK#ۧ|MmZѫt׆-D}>d9f1#_Q)4c4m¾GL݈zdr"jyEJSx}%A9LNgȲ`(lP68c%%}v9È޻a_ƩGrRQ3Wc>F#}юN!$7bX=6E>Ƭ4Y=K6L&ѧ^>(s6'ڬz{wRp dv1n&fzg?V!8Ly%2cЍǩt-ѣڎ~Ѽݞ݌ǼwKeK$/0}ҭ5\ɝe&EoplL9MpR3ݑsLxq&2S /O(Z|=1!%$)0־hʟiKԨ61E<򳿞:/w㊻%\x!20$zromI&2S/'I  3F VAd Y"$@! EH,BXUH:Yh"U%r1 EH,Bd Y"$@! EH,BXMTÔ^U?ڟc*w]]s<1i\[ԊMAEK:)BBFb(cFF*a)!!DQhB)%;I<{r3{w8{#sk^י ;sn~^ք%dI˭gjz꧖)ShڦKN`xg1+;yljCFF6H'@*v K;% .(5+m锦T )FSF*N >˞TfRiIMFܢSCрIٵne}NáB#Aƺf60RFh 525V ,\k:RViϸkPNm*/ʴCĶI4%"3 Ҕ{WPwQdduhM19#>k3 DϤE! FRJy1/S$UOsZ}Dp ;VC R+:-9!n(QPJs anڛT2 e/{笜VpŒS*ZM@C-<'ϪīٍEL iם i3L=(eށge.4Ո!D("N:瞽<~95}>7Vɗ7'=h(D#wa9R^$U}F,3T>yK*oƴ-%z,NozC8Ȑ!q#eɴ%tPϤn>Ԝ~X*Q{vd)#VEʴ5'Eo4%N``GCXgM19U2d/h!iԊLlQr/j-QkiZQ3zsmTI7*qP[U}?n7.+5҃xP4 ĎI;nsPRў%HF6'Ieu-z!{<$kcde}+Nȥ@b@lTXҿ P)=aQ#h3ǤMhFm'> G6 '_W'^J{㳟r.."kJImMC]<?w=wJ$Ѹ*R.`IZJ.3US%Q'ދTZ6,'m;XjV"6IA)T>Y$7|o{ l}gBUwt~h gI]4PSܻ۽ [/Vr1{jEˇDbJz⧨ 8Gu-h]k8 Po#}]k9C*lkl_ҚqZ?&6χu^k"KMTmO5m:d뇇w”_,##6 >Z ĸ`X IwQ-($=chRӇ+X֤\O Vp\RF?Fn(#wCTsm2EnegGl>&)H|#|_vb%eP6e%١zu e/{6xj8&&:dndJͻQqN&rT=.m 㓮fޟz]x s4;{r*1naO[ER.NKb(XWWk2<+uwT򤇢K}4MC"Re״oZ^TI0tkF/*NK/+x/O_jeyC=ō{t~iA V` ĮX튚,[h_3 ͈tWxMaFk"[)ބ1F4${ja{sh{8xAO5`<ViDMe]vH16WD6@^?nT7թ8*t-Ő 6+ٛcrF|fIMB5ۉW.%&e=wR(AA{jAjEuq]%v1' % JRh_d5vY>}/<Y9H hIZM@C-p1{JݨQF:~yO =8ȴ3wZqVMCQ2Ld" x٫O^<㗷Osc|{3i.pbݡJ>{C+eO^Eyg2A#}) ۴} Q+ECʄ Ȑ!q#eɴ%tPOڑ֙];aDEA*4Fv{i<hh4lx]#3&'J'7sቧ_ =͓h|X:\kwy@#Wl,RʙʴCĶI4%"q)NQA;ҩ"iMO)ĘgRB! FRD 2EJB\E;wG zjAjEuq]%v1' % JRh_d5vY>}/<Y9Hj(%i5U !I*bvFBu='HZ nDy3_n<ύէw%̈́vOtx6 rw*Qh]FRٓWQhvPp_ 7H6-`DKqc7!^qpdȐ2dZB:' ḪQU"^pߎ  tbLXCzR=ASKoxN V |44uAήP%߹ӯ|酇|`yzyxxuZm>o|}ϼ/{쥧 ՚>tҳ{wδh2y-_7K_j!iԊLlQr*=5DE#5 #Ӄ"3>34c9C'~f@Wx8GUZ!5uZbsBP$F Jyf?C5 {ypi5 qUT@eUJ̞4?*f7j=0)_wޓze02F̣zr!dPT#j F:i,{?SX}z'_Lj  UAVyYVL)xEZm׾V8_Ԫ<.= g`fњqݻs .UW{o#-2h !)eڮɲ5CЌHGZp@n&^hMiL@LvG;NwZV(*l,R292-+bmMm+~ foʽS_ZH3<;Hu+^ޤ36@Lj_DݮQ=`$eNp) /S$UOsZ}Dp ;VC Rk/.愸DAI*+@vS ZS~*nkAxIj0p!:̫=i~V%^Un(z`RH#'I˞adڍG;-8+CtɦF&2NGtY<'/탧NĽ481xFCAP%J ȡ'I<3bQ͑n*Lj왔=W&hE /H()z"Ў3k]%*uȀR@'1ʴ5'Eo4%N+fiwOlx]#3&'J'7sቧ_ =͓h|X:@Wx8GUZ!5uZbsBP$F Jvf?C5 {ypi5$f \*}2*%fOUW5Hǯ;I=AҲgv#zQNp9]i(5BQDz#A={ɋyw)|n>/qo&|5N {óP;TG@{6rhIҫ(Xf4;Tsy/6"${&e& #h!C:6F4i5J 頞H7#- `ZWx;2T4Љi2b IMI/!ӊCyӥ: xgo Ǎ<_/_zꊰh^CHx*=+JNlιqL;ގ&עu=$!! zHkѝN?Ȏ/w͓}28{`FB7#4̓ڽک>YvXN!B!d< B!dFp@!BȌB!!B!3 B!Bfg@˨{FRiIiAK > d)?Zv bF`+GQu?j>y kx@8?v#/2xkxڗ\LR POtޭN,ȵU]SmNȞTfRiIMFܢSCрIٵne bKV^  Z~ ޚ#V0Ժ+'Zl#^4uMg~]PVښ#ԴoZ^TI0t#8#f*NK/+ݭ~/O_m0Wx'cdMCAA`8ggAb5Oj$ /}Tzj FjFHUD`C%g}ghs [O$x\Hu0[c0ˌh#qnT{!Z;ɤIDn!]ӭP%zl @h5͔Q^Dhu& m~k՟_EP8OJңp|nVk}Gѽ;GڛR٘ *vC#{߂o#-2h !)eڮɲ5CЌHGZp@n&^hMiL@LvG;NwZV(*l,R292-+bmMm+~ foʽS_4!U19p6+ٛcrF|fIMB5ۉW.%&e=wR(AA{jAjuŜ7((I%nT{ۡzB^foz?g崚AZpR"}2*%fOUW5Hǯ;I=AҲgv#zQNp9]i(5BQDz#A={ɋyw)|n>/qo&|5N {óP;TG@{6rhIҫ(Xf4;Tsy/6"ڰ:mhh_02#ncL#VtC;:kgT?u=#>HE(.֐qOДb;=ށF!675›8crdxq;|GOb[s͇>Ym&;>Ym?p@!Bn~pp'/viև\B!|_?67zP~_F7JKKM zvsޝ.e "f4 /zįm 3/FuSaͫ]<\W7v#/2xkxڗ\LR POtޭN,ȵU]Smr6sߛ_Jqr Ie&4$n-:e^? ]v(?Zv !voIܵ1nVAt|V0Ժ+'Zl#^4uMg$Y>} o.(5Gik'68a~?׌^) Uv_+ݭ~/O_jeyC=ōޝ#MprkS^GFZdЂC4S5˴]Qe+k. b&*lhwMDp+E]ޛ0hxdO9vv.m6y3ɵ,p 4rA* ߼qxxg8#?󛟛ϛ'o@jSyY&gWeR M) pŏ$Mwu6j(4H(^ޤ36@LjJDݮQ=`$eNp)1/S$UOsZ}D0Ԛ:-9!n(QPJ滝ߞ\:wW*jM7!eO 'sVN$9 h BtPW)1{JݨQF:~yO =8ȴ3wZqVMCQ2Ld"Cc?;kɣ瞽<~YE7'=h(D#waYKedO^Eyg2A#}) U޷mN`MG /H()z"Ў3k]%*uȀR@'1ʴ5'Eo4%N+fiw࣡pH wv&Θ*ܸy$\7~SWk^CHx*=+JNlιqL;ގ&עu=$!!Cy+o￿;p}pxS9C?p]w`j !B!Yn"!B!'b]A!BcGM<!B!-0B!29\B!2# B!dFp@!BȌB!!B!3//{1JB!/箽u鵟:e!B!{ g_{B!)/\zKkL!B!28wtg9'B!dM!B!d8g@ !B\B!2# B!dFv+K!B !B!3 B!BfAy!B!.zցB!2 ~tjjrܙb9p3gkNrz>>Y:C8v7 !BH~ZdMZy[nx͛WПOu?uvb!Bf},Z #9/~N,hLCьۇ}c߼SW̔*}KX=@|&t88䣣;>~ͭeT<$9fйޠIENDB`knopflerfish-osgi-5.1.0/docs/images/tray.gif0000644000175000017500000001555712346515440020032 0ustar felixfelixGIF89a  1351&%3- <4,+$-0+#=:0.%34(677W l4z5W))T6<@77]54z6@;5]W6bU^^1^4^41c6'^W^4zD@ DD-wA hB,GGIFFUE\ZYAFVSBYYWOZc[b\Atz]c`qHJc_ggdMjgTplUyvXiiikj{isuqod{ygwww]5]]]SAA{YlTp`[srwwZ]^k5Z^^cvw^_›bǗcÄ341*:*4W]X4d0]V3z w-pX|d]W{Y0&&32)'6 22+12>@F7{.G2o#^WHHZJ`WbrQOp^sl~v{,Kirnpfwiip]_etyhnuWjzʄ08ɊOÔsdzYɶfQwRxkƍʵʁ̪ƍծȧЩⲄ׮Ϭع܃ªºмΜҜɟ܃۝̣ѩͤζӦڴъƭ٫۵,H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ Nȓ+_μУKNسkνO[Ͼ˟#e~ϿJ}U<& 6 X@h2(ᄓ jH ynH"d&"*X rB:/:ј%Hc"rD*!L6P&TZYFY!]zy%aj9eem !EakT_^5dm{Խ]tG`vzޮ;޲w;N6ie|'? 6|LЧK (~~#2"zo?r\-tl݋N&w6ҎMhqMQuĿ{2!GHB]+ OC'5 oH+`D+jU(^lL>F&`wOؒ,l a".*i"бs`M)58A o[ ~#m4JRX%ZR0 GxZ<0?PH @B1Y39HJLEIGٔR9TY<V铨 0][9=Shjlٖnpr9tɖZ =4 A)d9\4\И9YyЙ9Yyy=Y P З^9Y[7)BR3Amyșʹٜ9ѹyؙٝ⩝ɓP{ Еy ) ٟɛU65p:Zz  ": z @(*)j,ɓP bI ;JP:QHVQR:TZVzXZ\ڥ^ʥ) ajjcZg1ړ@ٗzpb)] w 8zLjtw :Zzک*:Zze qښFz| נI*ڨ:Zz㙭czڭ޺ۊ♫8 ) y i߰ 6 0ڣʬitbzs[{ ۰ʰ) zI9"9ɫw:_9گd)usl#0 4[ʠ *3[ ѐzD[۝ P0 20K`d[y{g"`l۶E ʀk۶l[:P&CpGI+֐۸00+ *+ ^kf0f*;SjKu+ kv[p&{/` * @{ ۸5P20-6 0 ۸@_{:S;; E@E4˾[@ 䠻66 0*K`G @"N ,10|l ` Ұ1|pp.< k[9Sۺ۾n[|&`@;`P 6J; 9 ހ lP^@ dܩ˰׫#`  0:{86`Ұ+P0ǂ@CL|@  P ~ `4 ɓ*:Wg\P`eLܰ@_j_ P``0L[Ks<ak  p"<Ĝ—/ "\>P>ڮڰ۲=۴]۶}۸ۺۼ۰ E@b wm yx0z 'p`jo0 ImЄ=є V ߚ 0ڶў`-9  -nҪ} %P Pқ ќџ 8በb 0dP6N :% T N`@< \Ep  PEP zy -l`͟fP]ךtN {= З]ʒ˟:"+N MPћ}陎 ^̦N0aP & 4ڼ&~⺀ Z*: 07^TP -Jv^@ V.PU~ිJ^~yy  ݽ}gP0ƊƴI?_7$p?'ooZb`5c/ q- B-s/NOV+0pN Ő_^+lz|Ao#' ?ux#`bF!E$Yf)UdҥJy{D,;ٳg̙>_ *K4.eZ3-QB]EhU2YjmI#qDÃ^-D:\9ZTR2m!k[4iܠIh$?rJ!Cz1ƌ05ɦBǨbN9;6y=DSSutuVv}`T Ғ$0.kdo0mImۚ2wܣ)S6X Re{gڢT;Hpըs\ZGu 0 w+*×6DSTQEX$ygò*Xˤ IVĐa4>:2&e+@oDK-kӤ4EDsM6t3E5ߔs6Nw~L$i$)"u| xuP$EM FP^@?`ʋ7ڨqH vm2V]]в7=(p no4CǃJ{/h79;M wbH )2{͕F'6~풮Ud0%2u~ q{ ʢ0Cʘ cm 3,.{Gɤ:} y"7q~|' "G70:]b]d&)j?w+ 9cRsC m4=;mvֻ"桺B>oz)K0Mo .qoEv  v2(DKhc+#QAˊ|~pM\Bhkk?cX4*Gr6RDâ),9= /旹97?fIO`)_رh7om/ePmۼǣ ş=BMƺi<&a6UxX޽u԰mc,vXGEB!;uĆ 'UNrlT;MR4A|s݋͞~`,Wyy,ojiiiY4; l2{tr ք) -7R-|q]t;]*s,4Ugy?eT~rnjO~2ގ2e/LbLa"]4;H|LaY\{WoǛW7J mOr$B]t 3FeK9_Ʌ:ۓs<cRGl/H!w09{&+JBXgCli-c $tLP05U_T.}oPĉwssl;%+ԑ{*o5 };\G7Ppmr?O<"[ 6|o/ n|'݊c]:۬߾ڋua >X `%+Y槷|ܜ:}]|ߧdir#魄Ybeܸ:i~"$uc$gvK?erl+ 7?8@nm1arŕNx[;}VbړÆ3eT~2R{}Ĵ+OhL"FA\6O 峴BAihhL ?#ELGO/t |P@ƌ1<\r\@ӏJFqg=1Iht޶n&>;syBQB_2WSazNِw{ȭ]/}{i6_݃ 94UqC{WBCG'Xv-2)?8zӅ.sF._"?咋=ʺoAףKg=>lt՚Q !c:@S;˦J/"K*&6L]YGUo F_ HZC;f ` VeW#ae7X^[4#(*XᯇZy5 @USwᦥ5Wf->6)hvӑFK+p2}KEĕ~iY߻?]ؘ0b9tk#-x8L~Bu3SJX:Ԣb R H*+B[Vf/eIBJH=OsTɱeYeQDgv֑[EznrDKz7>ƍq9J7 =r-ufVn VݿwƟ/RSAҔKF*?w!;*̫wLУm8dT`-( E”UG=U/^CQGǸc v`̉~^WYO=p>+7~]-zMTL. `7|?y_~ywh;WG:Lv,YOt35Mm0Qy`coD nH+`-61Q_=~ rK'ݡSfαϽ˗;Zɜ]&ɖzNI\e2_lc‡02ç-:[g份9pvۣ>G^nq -&wavyݶ $31sLSsW q 7,V3I|w3,ORǛMߟA&W.snaB?3ߘf\S}c'~)u{w{ER}4nYo3rs-FF! a䎍?sʎ6gXFL3=U;Pv|R×2cf`ft^؈ FR&F@6 f2112G.)/Q](BF*xhZ6N/x'7,V{ 1EE+Sh`5 J~NFdZV Vա]Ew(!/Z.Zdz1SV hZ!ln2HA1to똠L`@ƴXO1~=`:A/ Z.7)2igA3DM1"Gh@ hސ=DfSԨFǣ!j{@7%3$qߑ VC1dO,tD?Dng΀WA#xzc);8=, [ZkxYp8OFnLӽ%&º }⑏Dz:*YU AOp=B# aeh/Z\@XZ@0@t{ E䦛n渹hSp|C\p'ZD `4QD @(`!D+ !Z@ D+TԡgK|F*ϖ0[hL~s犚h=vt9?]{uǙ{Y-DI0tcM?Zpg$>`f!by1ސcR~GBcqFg?55<݌]8DPE/ص+t \ kg= 7"T+#,fvSSSnwO{/2fL0m=ڵ (^xWLQ-kFmzh{#5XD 7RmOy?kh=9{j7͡nNϘ|ʕ+=wBaA~Wњ94wۆwFR^6޷=ty%8p7iC'چ]rvhY}w.bҤA # vtNj/!5Ξdf$udT 3ϼO|Dlogdش=JȮ3fr10,U3Ʊx1W-^x^x^(Y-{lTbhcH4}|\ .sd9^>[@_^~(H8B1 9f2eġ*y:;IqIFFSafO{6\,:'5|&^cIII@4dY4M Ȓ4t(]֮]lIy̛'6 )UOdY&11$HLLncXu0e9`Lseܹlٲ%FN[>&[ɜ}i;k;@gINVЏi)F`$LZZrדּ(6`Ԣ!Z@ D+h!Z@ D+‹Dx*@ x]}vtX46F/A$~=HIko=D~{̚^&j^ jѺ=^^Y1O3smm$P|vfM/Cu~)0أe h76l;Kzױh)TֻٷNeR[ض_{;ߺ=:79Nnso .[SB|(<&K/liRlܴ_,{$ֵpTfRL珿u*=-.}M[8%MKcCi2)t]GefOOW829slm͛9„Dpe06[wwͦ1~|&'Ӷs׾zbǖ3Es륶 yyZU{:)`o!\܁d$1:v|+c RHgo?ɞq)0Rd츏cW0 ?V>3nw*t> ]'{^qZiS&q啗sy I;qyy?/=JfM/t[,Grʕ+YhamYHe[{m^n.5:DJJ &lQvc*7kn`,ZH)ªil޼=6Ji=o<ݎ8tih%Ib|G IMp-Wд M;zTu RF)l֮]ihɓ{GrOul7ܷĆX&NdlI CڰʖjR q;^T5j $SO>IP_X4˖!#R )#R%46aq yDz{IsI:C-m$X)/ߎnڵe['{ƒxm-X Az[҉ MV`[8T@ɸsH/>'3s/մs`لo$P<==ŋcXXljLEQ83iii4M222Dm  eddpE:,̾}(++CUUE- I,:lQ+A!Z@ D+h!Z@ D+h!Z@ D+hÇa-Ț5žolR[k?1Pg?eVj8RRӒ0q8줧'qm/es j?樉xQk!ڡ`mdVxuC^t݋cj J. &mȲQUI-%2:FCd/XYUjUXde!˽_d#;Jh Em ƶі Z%>Af}6hŠl߁X LS͌NO/$55}v`ePS37\ax\BqQue|FtxX0e4n},ۂljV|cZCF^HEE2ͤ3kd`qrzd+{'q%oHbHߧzt8̳n)S&a؉6n*;i)he"vf,˴w22R)-Daa1nw;NLSF8+#m ї9z-zf_2!Ƕ #5ᐊ"IN&HNfԨ| g{3ubiz`89S6lr/Ciӄ`aplQA/B`E+%ai@ h@ F2C(4ikkӉ0 Ȳb!11t4M&lذa\~̜رc)--j&cXp8K#0uZ+())S_3<+D;r"??$aUUU (h#to,y IDAT`;GA8 2?HC(͆b0 \.n;0$rqix<TU%77^5xZŁw+2 }ƞ>G#= ^YA@UՀpرc6m} 7nbxB}M7Mo8c"޴IMSM=i$Rwp*bkk+Vۍa 뷮/I&1wܘ'Ɯ&oc=nUfݧsÇϘp0uT:(i躎$IȲC DU0IV|HD+IEEE_bF0z<@8_hÅ![X$NTTT=eMӰZSPP@aaCXi2zX͆ncX` ZUMII!%%EԆ@fDB@V  B@V  B@V (Zi?H5GB{:n'pD `Ob0a/#՗yXi@=h\kF;.Hb?Rp \ G<BVB7\$<֞7Zpi>p/OHxOd2>p#yr#q úǫ Gzy˃YhzTxk1yвf`-GRTCǜ*Mң7}Ʋ`aOFLtzJ;%>%#uS}biG{W:ٲW>jُXK+h!Z@0:;M@0D@ f5fofQ*Ht˾M6l3P#7f$p&%vOg#+ojqFr 40tYQtלyBzI>,mvLcuC/sv&Z!G!骛$ [A6'&}5g fO(fӖT8nS0rspې0ӰI:'%++4Ad+-<-81[|OM};d RBQ3ɟ-*KfV.---444( TUUwq]?<&&D wk o/_ ^Y31vxdI$\{VZMڸTV ᥭcg)L&+JgGuq\<,~VpwBhJvV&:EحV[ZHJJc&+bpYQrY 9C>hƞQD+7'Kߡr֖V5#Sy/YrߝSPP ~R(N/eR*g/8qxuWsϡ;}7 7iꟴpV2uqL4L>Wo$%ocǍ3NǑFS 40xn \_!'N,̃-Gb"f҈l%{д lc+^\Yw/Ҳφc J?7'c9&WXŋD QH&U5'$zX83?}GqxǻS|Qw#ӼsO?p8HHH 11E%T4ʽPwˇ܊%! &6ݻwzD K;PRu+?<`a0vl ǝx2Eg +8x$ j2ư7vKo͚5^UUD w !7o+'N?a2m\.yǒDU^W^y*^|EGԝpEQN&;>3D9Yy{I>Nu aӒ$qƱfN9ڄD vDŠ9GOvov fCa6>b{DL'))SN9m۶`녺D /X:2f^LF$IMZf#4~?}cQFh"V\ɼyXjB]Ę6̜PoAbP6'IMM IM%9O<dzb Z[[D x e“Y vڅ|L:cg˪ 9XCu"xx;vPa4Z xIENDB`knopflerfish-osgi-5.1.0/docs/images/desktop_info_services.png0000644000175000017500000012711712346515440023455 0ustar felixfelixPNG  IHDR1#tEXtCreation Time '2tIMEj\s pHYsttk$IDATx xEߪLɝ"$$ȱhH9h<@\ՀAx\Xc .#Q0p5uYBDA+YkWTWWUd[ը+ `0 ,|t=Xl~9Wj>I0;L2O0KҾdˆ@SGׁM3n6Z'_MWDŰ[lMdhkpKѷ# ~GDDZ:wd`H2 Yc6 sRQnb0 VHh$ !dJ'â$zGTٽ+͎Dȶ!˨&#[pP,ާ < vM1&iLFCvI!=B1 oEeO㌛s*DȲG`it"PUac"9\x [&{}dߌ/4vPghL2S5H%_B:vgIEt8!ope `0$Q;1dY@D[sTףk""VѽkLRd*+B˳&#ly*ܲy<ϹӲss1n6TYr# Enl2^%W;g).Dt;F[O/u;u|4(xh:C4ט.c0 qm0z;WntW ɮ/{׶OX"+$K6(ڨDk[!cRY&De5 ŧ0nO}a#%bP+dYZE2$N3=tDmyޗUш .ܺAUlP%Q%1(ԈσT%=K!v_`U77zD*KMɰIKuQL?k`0kGٹ-|&7ڵ&IUV a"A 55]Y_^}ᝫb$OHWCiTDckfʢ*Æm M.|79,+D_ ш yؼ.Ҽv.e`ÞC z" `C!NE*‚c A@**c$ *1D\_kҝ:l8"4$p`:@8H=ǘ?{$LRT_?jͩ|}%%QK3Ҷ =0 f4a@28DEeY!⠎-IlII*=TŹX#G$$[R_AæI&ILYV5X3eztpD6t%5Q'YɼWDTDR\R_`o^`0 !ˢ@"QP]!THe*솄)t$ MR4.jޡگwi0NŜbkN'} %~DigT= qBxsOW09%7b[<A9gs֭^deyymA4zl?t}w?;^yaxN)c5|c~{-N /f?N\AJvyOЎZtˮO&o1uiK|+`0fd/2Me0,*h;t#gW6jmMa͵.]8UdH,[UZmü]~8*HwY,59.**_ٳgde]l~-94 O署e;zJ1ӟ뚫st幽yJ7|S+-l8I/V1DwkAU=0PѼ Vɽ?Xg*$gl:-SQv .iq 2չ+ `\?3L" D]U*]'2BMQ4Oc5Im%ٶUs-5Q$t#3v{jָǒh>uXU6. 'Ymmm^~Aւ-9SssrVHo|~AANʁHQ;C@dњIIc,Mτ \=ܼEwIW_]+[зWP1?ՕLH?ɧ>`u0b!g qhP$Rތ,;aooDD!cWƕ425K\ a,ᐍU QhB  IDiƪ- @H3Bқ?}]5HNO:M{7uk#ҌεDNTc/<֓s&(ãEGd9i9 !"$,1y&]b323 m)?{vEfvڔ)22􌕙_l[xAzk"&N]O{HׇD<54F?^UF=?cï|sYwn Jv-oJ]r(auQPZX4ނ ^7!:+{QHCiݞKWݞ_PF >+nq5$2)E[b&mwc{duĦbȿxD+-Mg6%'pmɑK3,yåˎu=G^6*а \{[ذepP宅zge8U3W*9Ă_R]jя~n\BWym hfL1SU$X'm6li=F=Cٱw<6.vwɫ}Z~ q=Qi hD#x68t#:GW@÷h [m׫/шGEM5A'T*2Un4ىZFB hT W@c[ʍ #Esf"ԢfoYx=q^Qeas_WE_?U>lKCJ[/-~u`s!z鵧xs ӾjH۵!cְ沰Tr Z(.A2^I™Nxvnd蘱vOLwzҙߞ4q:w󟤯9Gz#'!4N8>v:Bm"؁N{8֫GJ; NAl Yp"査8|ux+4}/ %6{5@RR*=yqɤ1CŃ88agV ]CisGWYyF!yͅa@]sch3RVY/DFǨwǎHґFtt;h j%ƍERHXTÉA#bd+/ i@:xᶍfF\NEJ%G}d,y8Tb$W7#t8J;doցPE+v1dd[Yss"#O_0%=f[ꕙ%%9+srrkZܿ)C?헲wjPW8 Y&CŎ@̃NK I7f@Hy/}Ps[?>ťk[[̩p^=~@_dtͮ_K `0 GV 4be80}}IVTE%CFRt_S8vtmE@Gpܫ %^\@@@R`C*HD4UhAO(UDWj (` .prm α?3ɰdvwdO\gf/Ηtbv޴e o3;}}'>dM7kRs {/|Ge^i<~k󜋗.?1w/mڦ[+_,Eeݜ*f΢KY@"uW fY[tc LM7rSj/]H,m9ewRҽ&1;?ONI>@&q6;ghtwL!v$ꑒP̼gاjR}ʵKVw։ûg>]j43g2}Tkk+?Ylq/rQcƠkc5{zVa5_& riw^%\:]t͋HvX6㶙7WznUg| Pv_U=Z^IvTǕE>a=C<*#aT.|{qE+W4ı~m\[{7m!?z 99-cl1FY7?XhP\Rۖ pnQ$9%1 n+_ vf!-Q.yz(qLX 97/f+^d7txy43 vota*3{6S YLq\ޣO'1LSSb#:l{uW_X3fޙ?\aU8 }F{x{IָJK#9GΊ]Ůb],/yi%Ż__">{>ds|"m3,ks%[˳<_vѓ߻ dd0v98s5g/XH.8t/NG%-8&MS v!☵,IɌ.ܖfnɤzm,E[-7*z~eN*7GA#J㲦}y9˹XXg!I"N7cӷ%_.V{ībCY Q7I$}id,[`7/2^.-3,Pab(|U8b y64n69FXȆDF @-GOo9F]^doCn*3IC[h0y@@7ƀMKh_BtkgAwK# [("T-9y]T\<fu7_Z$9̧x]tPͣQ2=>::C&"e@.ޯ/ 5G6?fxi3hOF`v\ I\f+s2oĊ՛jje4n\`Fuר<HiZ,'R%D +:kFi9I9JKL!ÿG.SIu=_sz V>{9gBcExx r-g2One/d&\URO7'KWEKaXjoPO9NE -aXBv#Wjf 6>Y,Dv/%)Tq zDNY>o|D$Ղl_Qǯ5Druy6xuЂ_~^ٓ0|=8zV02YB#@@&025Ʀ7]pפ?ޤ5of'βGg/PQQf)$hYQЫ#@e!y<>iPcitOFӉNO{ַUVYH qDGbYRBkKNgdѬZ~g~23 (>*K3 c*#|QIrg4CdwEޗ4M߿qtڷ THOHHHKH>#.y˖OϖqH驺Ʊ_;tQJ|j#O/,'?ԈZHFH ͔32!(Ow&xŵlU/ iQ29:fH|4ePOnx 3م۶7:TVrrq'{oٺ]HjfLFXRRH>#sȢt?Θ,M KyQw[t⥅zМ?p8nqdԧ]?&U>SEEQC!Cr;uBcΛ+8wbMev a|ABW&-Sh0̼KWVɽ233K7X޵Kj%ǧʣ %[z\ SQ̓O&G?%~Q~'`̿1:i,UR唩A}:-x94 Fƌӿի /]dțAoyþrR_X)˲)OM뚬OLHy kg͜FSU3Clkd9&p;g@ SwJˡШŞ!#XFѲUP+ WXs`OJj9)OY@bx09[Vx+׮ٳ{S;F $8^"J$WE.{gZr(sҤ;ȏt(iOڿba*ggm\dGWoD+ڳKcx iѾFkXhiߥf,*Z3G6"˔0eLf@Hr?4]4=[x=[-y?Iapy`c*u*2}%ujrۄ`uR{)4ƲqJKduڌODH?wߨ +=ψEPTDwȓ QHe2hs 28?S@ )2"]ٖ-;~u-8gC^6rvٺ;K1& .zɚG~̮ǪڿSʆsg5d/:m|i/=ҥ>mSꝴʄôoQurcc@F؟8GMի<ۯ_6 &r@FB@lr4͹bR&dSJ z8I]=vqc+mcdSy`П ">|1ɚ?@DrNi!H OK1 ZvU0W&{@LXiϧh'SOΓ'.Ȩ ^6|:jPR53w ɦ޲BL+)1\v5-dMeYsߖawȦ7kAYoK>߱wjYCFf˩e55F D/3!!l )dKڝpѫ)]Lвs]ѵC_^2` V~85LЂFy ~ Б=eΓO/ng87^F٩-y/.):pdwy^ A{ Ds 6Ք}nCRMEo@e09;.(}u@z:5͚9R}:omڲ9#mt}Nmf۽`S_9ϗnZ,,z5` :[V}H#c4̑&];0S< cE<3ksi6M۳f&[_3d.dxP,r4-^p-d[W}#iF3?-^*{ǀn4^69Dcmpڄss/7\@ |Rx1bqDt QkJ" ,|ŽU,:^&+-?M*cW JCѨQ™c;@4յ8: y[%S/\ms, 'J5D&m䝧C6 >F0z.S%$ f ko}Uν[3=\\j<DZ,aOU^ž7T@eI3odXqB *Y)[_q}D]^E1~TY`7)?spu,V |pMkܒϭ?`x\ou`21E$ [z $B&+- ADF>[BUMLRg/1YeՕ-)H{dGTcT$ quI/Ӕqk6/U1EJ-Z'[0wS<ၳ,0B>l߱wfXNObBTW+wjX95" 2Z#.Q|)wŖ([E=)kEuU}4]) PkyVjbE@0{pf|կ;Y@ęCe\o(NMad׶_}X2J^޵"ISʸ*EX&1|š&1-L`yArUg\*0lh)כ773â IJ#=TzVQ QlOU@޺?ɤ7̠8Y> 8c=Bϊxa1UBBʁhӯH7sui_Ӊ/?q|՚5`o.SZ&Mi2-D֛0g Vq<>otR͉YK]m'.To>-SiZNJ`6ac ;",|j?1Lֹ|αA };6䓆XDj pt.Tzy\ $Hq9now大\xrÅ삌 VdȲFT!!ު_ vhouˀ$g̝7" Em5TSyaE (J鬌SuC;V SskΒn-̛jMX'nP@kUWZű:DۚʵĐ (q/O[ S^~p.X-%x+Kp#`9j3Ne' qNWYңȓɤRQDq|({7l^v{#["/rVgRhMb4P`xHAS^mx<]ݾGN[gTNe&A ⤢en7y^)e4>,\/^4 ;;>{?ΆHg0_h)`w D `!Kp#hW]?X1?D0d3(dTրEХ.t 9IQ ^'J$RPH%^ٙ[)FA~ 5ݿO ߕi"ԟoEm$%]]=-\;rk~\ _ӟ^xiDZbC6$ /*D wt;ܲt=cm¡Ȉ[|};382ș-91"/Y&1ELkL@|ke2Tх, W#|(&ZXHy@Hq8`+2СOx]5'HTKH臯Q0G$*sCAbILG'J93^[RAQ֋0AӅ1T\.Juvٚz)1ITp=5TRal\Hy]rg,X T 탣}@,XT`?=?8ؖR0$jpbєjػ/7#D>A<+ xju4]RV Ms ɉ1FJr %r2LHBqz1doW2w~}MwQ1>9_w?RW؄!C̾Ҍ2#']#+1yTyᕘt{ *҅5Η %~bzk><]w,9R4wa{g˕ȔT` kʚZrBP* ^\e(g1݁G %e Z ؄!dbD],=A^3@|R sqƗ/7]?w5$Tt`]BGuQa?4!L&L)W+K9.33tYdS6A/r҆8*baXx2ߵk/<e,+)v祏z6|G(p`@ u,9AE`(a<NJ˩fgU/XӋ.+MCҬAN|xKHFjSƍNӶ)ޚ[d_2%.4R]8^yB7z<^_OINEx-P1M@&Fԍ]Z͉-;m; L@p,rdZ/7,@0c.YzǟNGa^++}=yk>vRGN$ 1>Z' C Ĉ7)pMhui%?7y`c清q: 8`@ lV;?kXJ!APDyNyqH}ӒM:]Qz@T*0 h9ic33kROPyXQ`@#6a!ד sjʞ|܅'_?֘ Z \, H#9$=1n$ 41LWUTT8qѪ\KB3tYeeżyh ԉ*_؄!$rn(!hIqwPc[ IG<2gkq߫?/,_1۷oiȑ#ǒ"_$&LwQd^vW_чyy%y*9M@"!d![-]غc皸8㤁5IzRTm۶&A=Z-lI״(XH$+lMV+Td{p"& @ yd[>answ}ïq3ÀhVVb0LX7GN~L팋 `JJdAQQ p&\ idy2u\7ZT?d5 b4l2Q`ZP6 htED'3fr8rlқ?Nl=㄁< F1RMdHOId]( _{?=.n8ct޹GQyKoٲe˒o;& I8 !H aXh=p ,?]=] =mR衄6v)KBxL$/-z汣t4dY3~Cսw~;3_{E?!e@mpcq/}q$3rM0Q;+DE QD+ykio:y? 8M0qcrD`#Q8%,5,J M.*$6EҪ3ˁa M0CF$SbAblKvd%Z.Z'L& d!W}*9Yti嗓M uyq<.QXh,'P;1b@8BO,ɡ^\n ۇVƸ dSCQ^-4 (T4vl7qD@,u2q/'I3+YnD>KMLLK"匤'"H좓SJ6e@MbSJkh%#yєB"QKESPKI,wNM<}~h2M<4{r-DSfot, tYJ߲Һ:@JBKHLLiR&a4)mP\~)PrC>?|Vi9jv 6-?Ο56ùWP+J[O@ g+ӯ{>sq8}9s񋅏'YS4KLFcl; I(?vJ۫:E]GXg-8`ݞQv.MϞx%Co]je4cFYx@Fħąk~8˲xn".?}F ׵ΰf,QY?q>F@Q& B;= J?a>^ỿeXOPDcc 1,ð,F&ckp D E{ٷLV[mN3 ug<;r~]ˢEۨ2#Q z Zo Mk980\]' { Fk-a wlQeð%}A;ŧjͦ:/0731oܸNozg=>;>tER'HL/ggOVX>9=MlJ,vKUEK r2D%Ad+jʷioc|~|=]l_blFkrF  m$I^y׾qळi0t^ty%5 nwy'ۻ.iinZ)AA?Lku<ޞwMu69`&ϗUi!'٣bfL% )FƦ=]hlĝ4 r|ؖ84@E `KJQ <ðk^d2 a&t67}eSH_U6۸Zaz^tUߙ_Kf )-EtZ O3KMǏ>uXW2 #C,ookUxt|wbz(vp #V[De@"qa!D)\qr$ٱt *l}WBdQ&X,6m?l^MRfsi$s>/DӔFlUU7nۼ{Zfjj*-5}w(D 8Oj8 pzҐ$qn`Zj]OGpDWZ{뙚pfk\iu8jjӈ OP39<s@b$)*GD#g!eՏ Mvr<}/͜Kz)E3VkVT/WTT="f9wW B80+ur1A2(e+e%F44>s蝆ц qYXV߿׏Xf#ɚsH -[W Yr*4iۻw!GLrō-mm8qph__6䚖Vc{tls=??bcno~pmZ$wsp`V0n.=/(2"ef4hTYni4:-ei&&FZ֦Ќi4OPdE/jqXq<f8d3GcișҰ֟2C2e!dLd;Zc6[6.k FKtæ 7 ,h9{Lo-k=Ƨm{v;Mz˾Gy\flk)e3k#z\eC4uZ E`$ƇYbڏt<2D: t$CFEe„쥺"q@"$&?EαtbZ6$!#]Kx+%m'!X>pI_:DUd͎a`fX. 7om `?~u쯿r}r|32?Iz{ܹ]WgŒr۰97256TCxf :-x$(.D#O#1 Q" DiIa q!nrt;nPAz`QJi&`asMxG'3T1Oz`ѧ{y9Ĉ^X7<q8{kS&`sbhbYX izC;!b!}enwڥ-j Źe6aE,.“uXvĹAzFKgjE@ /~c8!!8M$ٙ6mw h4L+|5p|Oc,x@i80+:Jx#Sypf*cGNL9Apg!f`OAt:seU^|iFo *ʕnMN0'Xx龾W^y%Cǵ4zc[νu|G/s=c5ӋmI"Tea=s,eO;|[V@14t{}S0Rp{Drz[Si2m۶\.`pxdޏ쎾e{藗u+mQ{IJp[GlPSU:y96}HP|g{KexcmM˜N֎uWZ8%xfYAqBdQ-z @ƨKaZ3~cGeK}TG-xyy5IJm Xupiw wQiJxRVqFii?^庯+1qlXzz=BՙqS聙 71=9QKPKEt&[顁3˷m-'"xEkk(zp|(;ǿrp"P0ȅq,0,.^g买 cC%wKआh/ xٹv#I4; }@g2O[M7Nygp|0 -_:q<`1.y. y8H?1!39wg^ZiŲ. !!iAKD$QN R1檊+ElR8! 8l𢕐:VwvgvN&j9g)+-"3j d-wmh Iriiw_2[ZElL⢢y#|{|Ҭ' L "xIƱ g- Df{޽w=lj/.ÉK!q!:q @walv}ɁZ޾vcOKT!L e?/zjtzy2d^4˹g]WS_}-6Us Ab$ìW.Af߾}>رc֭r/oSJZ׹g+WiZ+G2>ٶu#MKbcp2]j{(RWf:4V NdއgǦC\P=>08e46PF8]{)-[>DϥY$Fњ ]KQ466\Ӷr>M1=k^ZQa0KS JaZ4meXXva:MκD8*~lN@(!Z 1ñYKx*R@( <ٞ^´X@(  6M`6[ؖ'Omh2,Ο60@jME[-,Uv)ϛ|Ap% ME&d{-Rd&;5Р@[VnC<"0Iԁ,zN]f@W3D1 xMWiQ?*ֳpTgNnKmMMVKj)Z+mj۴"0Iry2!-N\F+.?H1Jdigx,ZE|:*U^onZl*y2Br8ǟPop*$%F˓%ӦhL0]@\M6^t|ȸ9İ**"n wT _<+w\nmhMЯ篎m'O* t GMkPd]]õ0 olZ؂ށڬWdiB%(?9?d,9"3FA?߻pCZFD444*4|WoO3VkF**4w޽RazрZpLfRyu<{F' Ov{\O<'~+U/ Υ{~;777<<\]]W?svh[w2?wEQ4@Y.09R4yO'j^,ҺR\o@>]pSF=^r5+J Bz Ly}ԛW~ȘY=5vjZc۾}՟7pW\5z@mjlD2$Oy7߾m/tW3ӬqoU$"T|ᗏLo|2Ig|6rE/zr,s@E)gs{e^'I2pryts۪ %%T nDk7.9ݧ{Mx-%&*ҷsD˲7!%LgeN?1-P`4[JWZhh=_2R[USѴiBV߲}7!ﴽ~4:ܾBFe@p (Hu֢_ ̜+vW;wm EfNT,bfKxKKeM%7YGZС%Φ'd`((Dq~k:DFӍ sa}|na'{N~XMae@p (H5Vl7MQAP*),Y8gz_:|}ErLOO'Ե-?k,vўY[\^bBMyfmMEm7ߠ&Sa˱K%Gih XwfajbZk}ݷiZ333xVjjv_8=&Ȉ4N-|*?yAM/)0LN})Uf3F Hղ0kQa~scϧ0辻9)GF{2w}kR1ϚXZfs:,n?vi&ߟ?`B4,#xM͢3㇜4_p]R!NQjn*+k5-MiƛvWYt[B Q* Pj"\~i͓_}~7#woY+T?#oꑧW5iZò% -quF5¼ޟڲuw}-$~f@vRk {+oNdDA۾yࢻu:FO>a Z$w/P,eY7rȨG:5jU|A2 m<9[Jq{kMNQg8 M~oܿmǶ-;A>GcBWRSʫkj'`Ukv1驁ap:wusۉS+)J ٧ Fa b4N_PB\-bV"]ǯ>taU.@%X%ڑ!=?"* tZwE·3y* xI f0{Ia iyN|˻O 5?;PXUk,?0}y5k/jUkK[Khnr&uUmm*<m(4t.c,) Li[ZZBU|"|®[J1GB凙{4;19$rcȐP(N[-DZdY\TmSg]EiZew}>ycG Dzc)C=fK}}xVhpsWͺ^drwuՁ A fi8MI/kQ%PqXעٔEkI M/ ]3HpE\OM o.fCd GQP&{|E8Xf}~^ep+ʊ'Om_hlL;(<ߪgyu:!/ }3uucVqt\|uGwF簾֑YquYA" !!It:-骤~So}[U Mx[B̨ 6yf;Vزhۏl5Kf˂2gqxW|=a#GQ2KE6)xZ s%Om^lm#(SF !n֘TA=gg͇Nr\~vb}u Q_3Ol!'@]Bi`pJ-74:r ~a'343!pVC=a]SS6FYLS]]`_+I]>$e jVf@^b*j'ҴR!`0W7}w/İ0 c"{dyaY&6N#߄08w~9lcjU"H v-o\}# "ɢ=x-}?}ⵁa(0q9p9Y A>oKmWZ\Hms>H}g-K-exys D ]\A~qgvYjK,x?M# g(=C\zRlk־---lmmUTޡ-v@f 8@:dQp_ڶy/~ߋvZ9,A1 |殫5vǎ,;pAK.-..n?`KD`$˟C 4&f&BnX'޷ >rΟl2LrDt:ݶmۺ8r)ue ==q@I"0K 1.G ,Q}̝cM2~ҟEqnp<3f 8%@uaH|TJ/愑 ̘y>|뻟Yf 93 պu|PnCf0Y+J6_RK9%%F3 W}DH7@ֵoG6WIC s眴6Ƥ?iM(EB} Rr7,g- p0%9o(L4N(|Wv[ݷ@mF(utpy*GM;:ѥ;oFrmUd$T{fD j) b]0:YM|l[gܟfB{zj{U#? ^&&&z{{kjj" /hM$Iݭ|o:p&'J&.Fۂ~OG{שcΓgOUVj7^}c+e^"˲Ozp(BTZWjX qCL8<8pȮS#eBnchD@!Y@|,4h&\k--sD`@A"8WlO7r6KJ6>qfA'`. P8d5Ņ[T{/^d"^QTxy=s)oؠ}>/foN 2?oxϻ{>|eWf"_p?CYJ٢^ؾd=V >qiIyM5>jbXv*G><1Z$ GAWx1rܩʹOΌV{ "0PsEt?=N$;!%[-b=E,A(Eh2!ld/z3;naۢ/Q^dg756YK݇}TiiyYc[@=.=RU%y@PX$NM]xW 94bYnݞ~\d]w2 IE_ j6F30,xC Z^~e#C뗔ϩccc~qe C:#۫A$I:-h#%% ٱc/ߴFGGiֵ,)qVz(8 NEєVi,!qqv另HٗҰ_O!͹"4'SSSßv|9pYE~G;Oٯ8-f,WU.ӦWn˭Vw +Z s^ANNPh9@tdJ SpvG dݢ6cQ!bl~`,"J sȔ)iِIGpW&0CQ& zo}z{pƹ81fоF Ei&8fy?,hJÝ_?|bxh57M6sa"wN$I w^4(tZ":ȨHajPC^b,l nbOKt'M;O< P,dֲ7R[)l]TY-Es{o_a]5GA !}ImI㢦Σ^C\q-aMz;;nخj OiFǹS"w& 4cQZ4HĸXd2 鴈iA֨A4{QCBJ\+fe2c7Ӿ2 YVCԉ"4G}EdJn4fX:i& M܋nڙM7~RfdބhDFXwYՌpm~fq14hWjH-@6(  Aĭ.4 u@cpx@% Mֶ`wD(PwOXz:t&txoYΝ;% rw.t:V7.gOIkA1l1,:"0'@dR^R]UQzᐖ J3㨯zo6VT<S0b%K.pC޾aۑ”" 386_}`0FĝI\EΑ:ƢX57eY9" 3vɱp3/R2a?{%Eu[~LtO"B1k4jV]9M4lhY#ql4q##2 0 3~ci4Ϫ~gN[ݯjW^Zl˙߽ng5S;cs:8QSdz=sNpg2_S|x/悒ڋL1{3-bψ&H l޼yjjJxeΆ8%%KAsp;e(sdtRsϱ{75援})D"0!3h".X,za)IüLJlXc}#NT$KS! %}݇fgf\.x9eXК*D,w D`@F)d%d>tZmW,l>U~m=FskǟD! O~ t~ydhxxvv"qs òlJف"0> csd ꚻs˯5s#)6W/W3c}oS@U-4q].'cȪR xO YAYJ5Y˼&'@ܛo`25YL l׻op#&=k4h0^#?r/AJYϜ9Cd[[ۢE.[б^YpN(;e!%S8D`BY4O/@RM&PYY}v۽w^e˖5/YR^Ré<8/kY'n|4 "0Q@J_L ?J[ @QܥVm۶.Bٞlpz۷n\箝 EL Ҩw}8^___UUEƿ~/FK]M<|_p`D  D @8ԮɂZ[nUڊ&/7WiEsWGfճ80f 8 4'#Ѡ'8 G38_ h4ZSӨk!#~sqx,J`u.gzE$/BԿb5PK6C uԀW H nlJ$N&M$Ao[ 7ZO` ED 8eɇ)_%h)@_*[6IcL9@Q5#}@Ē:e-Yz…t(仦8#E %DEea((iS\z%<bI¬h3bFN+DQM:HlhCҦĺ+|;'"bFf+ $ vl=P+EQ<9}gg"@N輭:nv24$(d*5[ժt!GC?:^L"DuUNj[AbZ*4G(JPQ-[ӢXEKIt-XA Q9<:%Ѻ( E)ԂĢ"*!F,8&_˒v .%1"VmU2K[Bz[DyɈ -~$YF4F)XA)⅓y }]tD-VYBo6u?%$Ah2}NO& 9D7_ꠚC(T'xHwtX&mRKRaJGRypdz1P`2lD~<iWtU@S@;Y֔6Ur%.f}(aCf#E:"oakbdNRHT%ɴdA?T/숖HdPx$xN?yR55AnR Z 'Rx}c~&̓%ˌ̯FTG?]$k,tBt0\qh$NDy ɛ+ ZR[/B͇er9K*QC<9+2[Q) 0M@&xM&h)qC>a91)C 1qM^&PUL Qs !~y%Mf'jPKmyAԭ'y@< XΟD!ENi46oKʐ<2Et(R30%H`sGd $2Uh_d*'DpɑpQ~dAŃ h2!t$/GDGRcC(ʪQ A4@ *,B̒w^U%0C- @ p8n1}c#z1pCVmۣC] iD [zt}4,h2 [D.';ǗyHikPp -,g\ҕ&ɱp4@\dNf#21:5ij̶ ,+l\0^_6d [uP|s{y!4h(x|۷OO!]+dJ8H\0|Mi{/˾ .q5&P\3 @",X 4١؀Si+ Y^dx9߯^}HW+Igaˬ9WP-U:-J':OYPPd-,.8Hb] ]nyoy] -f azԮɄ3Rk*>Ae%˕16=yŴ)1g>냏_c_ E;Ⱥ˕Wu5 ,p? tyWtXoGHjIz5ٔF9kd,#s8r=om޼2܊?K\[7Xԟ>p`yQ8|%|;;nEY<OR1YhhNTż'NEH+G̥^Jd.oeFz#IX_ j?tQWi,-bwg]{͟@6f nX\,_kݿ/3^?9cszmC}=9eq@su<Ž^s:x19~B߽7niEU۷ $a(-8shOs+S&0lQ 5} 5cuƜ ǜsvr,!u@gl?<:ZAgсӧ֙>99vZY*ϻsgڻ9ƥU%漅?zSc\QFDQi9#2{d{>|1SŒ9C,Ŏw,Sg@ C|&vԢ,*kkAVIۧmsd>ָ`a]mB1 r9Yih;쬩Z';<Ώ U啥 ǻ>:k$I~knP~M/3p4J =}_iY*Mj} DE 5NS^Kk4w4;=C'N}qQmmDtm7:[PPT`j2{Poόt=,c w+]iCN' îXyբrrr8[ kknY<>Yh`Z[2Lϧ<(-p w)mBXH&@Q&*6)2JCęQKeq-?>=}ȁ=4^ZZ^FFX V7-L8b-+ .P3Y&F)L&wf{јܜ}vSZCkEEm.fiQMiZ3>>t:/lwJRd?þo$Mc!o?P-=~n^()X72A:Z $i2V[OqLbp==J-s zKnNHU%FP <=n<"pӤEYH93O蟝tTcg=YDh0Co_QPXl٦wY֡v\d@ 5C'WPkU%@$"MaX1aXPeE ̠NTj4Z2h5cWXnQ4b0494pg( ?,8NòanO;yeϸ [kh1L?áݯ6VUM48fnzp3?;\|k~pI*R./}v]n-_=R1yISSUPBk0"M&kㄣ:.2A=n3hi E`${3ǺXb<#DiIH.8O%l-,nM:ٌFSks54/rknDY4ԇuJKCscg7>ݱgxS+7lvo|י=p{'+//x7pNoxr%ys WCHh VDK,$ԥZ˷3CR`wYOEcs%jBHQ42,A"Í NGk(ݡQ[Rp}?/˒,l]L তM$ fN<6 !$i贝f0)M 6A!!@Bccbl##X-^V۽{wg47wߞviwEȵ#\>NgfdV~ZKd˻uԜAFUsH>kf{}y睵D:z{ijW^~{7\7}p\%!h+\WVfcQ5667k]Wn>;>z+ceK陖 #_Cek"^][:Hjt]bߝW;06\vw뇗XښH&lXs~{݇=Zc|VjWɜBuʁ= _10nr᧩u׭:SX,n+2{fd }U\-ܪMb2Թ%K~uXbr&LlF;7Nfu퓯5fMSk/jitЍ0/YҚbt}CSsۂ؁컴o>g|3oš!֩!.8rKw4t׎ &^b~cc|+tNOjOSSguOzK/ IR --09h낮#Oo~͚5&_;W t FNxed1l .f_r^҃/ƯL9wneKV,;-83+PbۚN3zLcmu&Y놘*.&[ټVxRM>\c_oDi[O?:sI%lmk?iLnzIukjeؿЃVZy6-v.85W~儦-nH`a!PɔdLxs̤'lh~6}MsCk,N1*UO[8U\tu@f=ۘLl/ٟJ0T\LxQL*Us|.[~̯dΓ~W {gk>0!f2D>f,WxHM0p7 ?ӻWW.;5L>觜Xht <5:Gѻ !{a袰ϥ|SX-Ic؅;wu}ͤ-i뉶Tm.r3G_07}=ٛѕ9xf\͚bJ2ŷs7f[˂Ml :|WȲZvFx{"O'2Zj"?~̚d"hjllMoL#sE| _`&:6gv< cŌW+LĹSٳ +)u ϿE8򉉏z`dDK։eƯS0NTY/k>ւ^.)64Muٟwl1Ubm7}xcOڬ|:JcBlVBsǐYm|,6u6C7OI=%mɓ~dtt.wGޘ8}G~m;md̠ǓX"7n.LJ-З-ssٶ욢v2laQMs#3{fmf*Dkļjlݙ-J w^sd{sm^K},C|N򅫖1.5䴩ѩ3gG=Wߴpia͊SV$]vw\fm{G\z 4g@&!^WO$=7ˎ [V ^]4ٮBlev)\?2]m$Ot%&kQ3[mi.-]ҷ͋/ۗvu'fx!zĉc_I&suz衾k>3֭}^v`C qbS7ݥjTmd&uƦijK0sn%b6s9ӟAkQt%|TP>x{'#]흅l):3˖.#]Xt߮GO<]7=x6t Lg'Ne2XlF+KU+Gg]LtH4Vʼn56%z]-WgU'l~b^j+(s^dOܼ+~[OsƩG_jkkk V[neppP);zԶ:T0߈Ü ƻ+;iu<5>szF[[k&&3Z;~o?:~wի__wnC0Ě}z.^Gmk{>^ia[W:}⩁ώT`Aw5{W]ڽ{NzꑓH5[yU淵=wٯ}ܬ:Uo뮻TWZсׯo||-OONE6cbgGvײKUWDd+YzOj Q}1VYFR]j/\^Ṷţkʪwx&j|NYp n=Vʯe?̏P8*yb2sēM#&Poֵ˯}nFeû_]i6Օ찥0 @=b2#&PeoJcahhкUFf_#H\׮03gJaWN^h+&'P?@pɬ-ϙ5*OM\[e,[ T%q*G]VҺE~&may2vkʌ8u5\!򭏘׶Lyݵᶰ@[.׭.ݹ7}S~9Ϙv2aCD55Q7![&gα+{µVIEζ{U@=/C[W`dT}?^*Z-`\XHEWU. skMʹZT]^\mUt Nɵ@qxzdGL1zd3r%$Sfo Fg<`pY1 Ml+\8gLw Ep=@;w5w5O~*ZOrW2k:eqA6n+g+9('ʄ?N6P#?|\ϲE 酬gTz͍iY'9dAoAS' ?& zF8՚Y s⪖"ϨZ:aUK)ʻzz&붮5CT{njYח8qMi'(?hY,lNdq-( _LY^ K[e,"Oj^-,LLIZsRw_70gǖ :=~a}yd_#BQCǖrd擙/&&gӥ9>Ib2L'{ˆHJGL1zdGL1zdGL1zdGL1zdGL1zdŘkIi?✙joVrMyU4J{LzV^I&hLbTJf)S&ے63d嫅|L_\v/Tm-r0~hĶskwWDfoZM8F;]]ͭk&:7YE麉Df";x gCJ 57kqKUi’2i`ώ-uz,C'm/5 vjQ%Ll{if}uMl^Urwk(٘L dhBY΃lqN[TtxC[˰dL<՞K]zGU%'`u+O/X,R*Z:~0RL/fVH۫ZWiE5+[Z'2oܼxmp~̬h:V Jfʋ|AenQ gCUuJG^Y|9K~S%nb2Uہ]/=1Ϙ̋`O*"`3yS?U -MQD/1zdGL1zdGL1zdGL1zdGL1zdGL1zdd+UW dCCzXFdPI7L0`f,DJjʵׯ`Êʳ*]˶۷pʵIsX'<2U +^̸1؄MsQD%I`_ɱӨSԠdA%A"vȈ:Ȩc:l믚 DYbTE[#nhhP0:,Ok8 l:d+Gfa =.T<.L@A$#r' 'D..m ? ;#X<(GPH\|"p`Rvɺ1.< '@ $ǧ1J;r4' lէ$ JċZTGT/,tğ&^ܳ"NN+RɎ12Xn8zCDLv~1Bdx"w;᠇~^AV DmJ70+ BLF<rNT-i⦫>q|;L)To}gj"DeT:פrlII<0@Eoo%CQ/( l`˵dG~Ap#NRr W $qn@.P P.xJ@<, C"1EhiM@*ZX̢.z` H2hL6O.ԝY|cD x$\:%?<^BC09KFn!v ¬rl^6B4]LT"p*dD4}%S..D0L,\o^b&P{2[a&'$JI2nm^R+qhP9g s $æ і.Rd1iG GtN_:Ra1! wJT.+'PhRESn:&}ʪVծz` X GZϋk<^28$&iHCZ`[$$ 5Bo]'IKQĔ`Gmzð6a jB>8DOaywLOeƩqlSߐKbI(> v8 tKAѷm p-}M]w]z{GePlII.ּ[zNiإ z@g z{IIN)D L&!E.pkU1A1_UwhLߪ#@I׾9/ a쌽'le*G4Ҭ>HSDQ骧~T`vZ&iUA?7?L¿M8οWvi%H'q [RWYg*'zer~edUqtpX5 sX|~5/='.4?ZBIDJGYHgYJqZZU s[XS410 ^C4Ih[0vEvUvD\UL\]E Vw] 34j7Qwe+%M5M%z_U__UU&7 C77f```NOxpab"m s z{W-Q1a4֊5 ΰc=Fw!{?{d~X ɐ 0_΀eZeD(ы'fdff0 5 q6gҷg}g׸8@ rGjgiiѰi(jeuakFkvk j C)!bllmFm{ $)#ynFnːnא7n&b6y8:foגP pPGgHWVD0qwq :$r֌2Av`Ly\-r17s)Qps9wjX5Gt5EtOuP l@VMe1[4f'\}xRhz !p<0wT[ۥ4LM#xԘjexx ɕ10CMhN`x`2zJjX ~s4rh\BVY9 UG[YWQLgUS45ᡝ|u=%ymG9bu'ewV|"IɞK%%4z 'rHb D (WfzH8|XXŝh)=X4Hv @ [sG)FuITKU8MXȘ2J\`5b0 ;j]ߧ0qwy9ߵ@s b P$0_Ex[(DbM $0c 3@&FaЊcVhɨ| +@ce_Ede[6^J'2f 8P_ Z_P g(e`6P h8 6heIĺ^X`Ͱ(jpVժ^6@k )ji}IV"l`#`fk&>zjna776{ 9p0]"۱G|KTJ JRSZgI٧jJZcںyO4lC;bKf:EK [{' է;X R9bwEx ~BDhKHNS501ʿ[~ĴK%Y f71YKSgջ]RsLHzaseV;%C4uSMx'y\NNx7y áIUbL1LV\bH6N;[!uV(I)(ƍ(YjH:~,TqJ[vY^2{L$)WLȴ{} ;ɔ\ɖ|"˝aO)=yt|xE@r B}2P.pɂIIU+FWJ6xL/KY3aikME101[yp"2ZJմ}ӆ\W4E.BL`z" h81H8lf7 Ny:lʷ;i9L\A:aLqV v,IL^Dw}n"Y+t ҃*'i7]f? 9\6|LNeE ?j)D-A0"MLB>qdd͢Wl'SUt>Z,>(@"+zהE˞Hu0g-TG11NqS`ҚeHcawkЄDJnvaa6LJ35 G`4 Ʉ̙·KТힳJgLL#ķ7 3- 7ڜ'`tc+Kś" q1-Tl}]1G \9 Zl!]1)~\, -LASMz|t}{3n;:HG(=_O=$^֠ZL[V؆o?Ak-~vWssyt@â}W9)^s4IXulBZŠٜ}*E \F <`4[]ud ] k@4G88n~ʍ܅ xJwl;^ƴ -dlN`,ɕ]UM(1+M./h.>u5/3uԜ.뿒fn{gΞU=9L.\{{xW6Qr68n^F3K2o 4+d0t/آs˟.$Y+1ؚ!=}b8]n 7NCMQsNC8awrH/ܹ~0N(OcOQ2Hyw=LvJz:O ˴H|E9xOO">WѦ]_">yH.BwtY;eȮinf̢Dޅca_S͇_[cΩ]55ob4M"KH8Bly8.\?]8_zG|O^g*ΧR&ʑ /WA .dC%NXE5nѣ{I2I"O,XM9uO!T2У$a&SQNZժÕ';uWyK"[Yiծe[qΥ[]y۷.ïRث/fU-v% 6$gP\&]雖]~$fBWd)RN;rLbzpSTSMJ%tΆuVZkV\su[04B-U5'ֲh 3&vۍ@}_sHiYQηw8n"VQ>A@Fq7 `1^+"r-+-  n⃑oap@ven}.>,;ƅB6(6p`@DG$DGMf0Q piȻk1iRTWƴV;uɮ>V` _R`S!RAS6s,AQ\|ed5R&kxn2_sԛ{t+ax}vkvs_WCRj;uWjh-g/NIK,[CÖ]7}z[]*`6hV }c<<sT hwmrf9d ,,+=xONcSHvp6AOм3iJsm {JԖPy_T"m?ۆDwS@Q[ 9s[$0moqG<*(Z`67<2=]T`aLWCA&89V& vd%-yILf2Wd';YDZ{d)MyJTRde+]JXRe-myK\R'v#-iNVe71 )AJPheS)Jd O,Y;ensKm ^pt2pݦ ۈFNX2w7>WeY8/A}_IG>kJF-\/q@|^'X 4P@48 =^0T7;rw#&qmYyWsR'Q;嗬>cܴHhsL@< Z!n 0نxJd!F^0MYkfs&iP׶}Aqe]Eh$VgZIJb./zYK-2D(U@Y^T3@m#͐O'٬n;Fq0T }C2fl e߀ʓY۫ (':Oӌ٬QǐDgan .{) "]/}HA ژEkF8|֡fCdhXڻ(p t>ćgA\\J_ĉ1M~r\+gy]r\3$犓*G}s]C'zэ~t']KgCMzխ~ug꟎~#Z'{= 3O%i]B'&ߩw@nqoLx璏-_y̋甗/w:?y͟_SSBmF{^Sayy~ᄃ~_|3o*PpS W?y/?Gϟ~_?k;)ڞ?>[S>?S@L@{@ @|@ ̿ T>̃?K> D{3±TAs>=l;?2<@+2{C8 0ó:??ě<ÜC,;AT?$BۓT`IDNtĤ{Ģ ;knopflerfish-osgi-5.1.0/docs/images/desktop_open_bundle.gif0000644000175000017500000010005612346515440023063 0ustar felixfelixGIF89a51111=RBBVBTB@BJ0aLU^j[Cgff T@qZsZ=Z#f0g2wKƐʇXɭ2ޭ޵޳?kkcǭ`EMr]sz{{U|{9X~՜{{sws{{oމm{V1g5sB{JkZ{ƌƌΌƌƌΔfąʌʌʔΔΌֽΥƜƥΠνҽΔ֠|ĥżݳƽένƽ˭ҽީ6Z\ }n9Cy -Vē2rϛCwN}uأk߳Oӫ_Ͼ{/~wӿ_? (x`P VEA4 DJ1Sx^X$J,b0(c4hc8ިcykzcGNis< 06S 4 l @ .p-nЃ/n@ \`'LVO4 (pn@=b|"QD<D$:qOTbA |Td 9+r`9~q,cF2f $ ֑Bc@=L !8HA~p|9 ЅC𑐼 Wvs@h@@(G)RR{Z*QJ©d%*])K ђQ%.mKr-KX4&/è]P|Δ 4xE0oTd5>NSYMrb:*|tsluG-@H hUTOC7"@ϑ9}Pg@?C Pbg 0i&|yxx2:0e%$I&dzSzV:;=Gb@PPXK;{)pM}&Pg$}`a@X`ge`wI(d Rg0i'~gO{&hcJ})(H~hP6awZ(n !|i2 ikX!(}pȈ((S؈bȉ88X((1艽(1ȊȋSd5Rf6#lF{ep>5pJb2u}v&7\gM([xv}$wwtRio$[X(Mha~DŽG(;| Z0"mRf_[8(/(1)3,s(/Ib0钇r;@@Ay?K=ɔOIHJ TC/U)N7dbeRh`imY/yp rvy9lp%PRv$ԈI!Rc@@X$`@7M@}-0u|g IS!َh߷ߗT`Y~ `雇RfI +!h_7+{ǜ򒢲/iHYi9Ҟ칔iA NyBi))Sٗ395 uI *J})5٠!%HP761I71lb0HC"^>5H'}30SW@gv~ k S)~|R$ P|HJ~S:~vPS@ IgM)ufN~@u.} 8 N'))z.R.=ꨓZ)j=jZJ=ʪB:zZ:z*Zڬš%hl:'DP`Yf)P`tCb0J(f efefmqg G|gI w MWwe ~RTuǃwzN~* @|)ש٩LPx˱68:볩 j)KI˴H+L+>۴TkO+zN۵V_KV˵dka˵g ci+*(ߵB`]:e/ 7J$`sU"H)PkPgyK "|U@RPP+T !˚kk)@-M|%1rpN+ K $?# ;8bm]{[H{۽[盵ߛ,N#/+.1N-n4^7^;.3~01>87Gn*~B:nNR.DD~W^I^?Q@~c`hCYg.fFAtnc.9p^e_ pL5 oAnqN^|^~n 9~N閎难1>8`Nz>骞NwꦾN>wn굾E~k.얞. 2!NH> ˎ^>N0n^.~!.>a oOo.o o "?~ O-N^6?-/^5Lwl^[|vrܕp_pUwKnLjG7Zڐ\E}TꑸΌy~Psћhqĭ"CB5N:N7ԥiW}p@ 4@TpA"/)Ȧ,! jC={FSD)F!B JƥZSos=btI(rJ*R4PrK.DRz)Bo"Lȅt Nth|DRN4{!T2$rQFuQH#M8*RKQSM $d(NT@;RH qNC52s"(8pϟtYfuYh4,jC>S T8OB e]xWYH^|Յ81<[qTP4oϤ2a ƅh+b3R:c " dbg2)@tRDwoUU9gh H< XC ssBRߋշpiɡ> Q hY56lӖcAv +i\ fXx( 6% vaW<Dl|Ɣ% WjOrP#cZ7Fu (նvsϏ=~;o ; TFX iGfA`FhBpDG$saz?>EG\2CoiJ"F41Q2̣rb-ՕmUR?(1&7ljswc9y;@2V})n8h1A `Bh6@ `d,K#s|gyE3-_[3`T9HV A&R1a<JUgE|;Y B/ju1ɐ_[hAc4B٘P6Z1@ 86ݴlyg=g[j hmo[UZRm4 pD!4\,ifD!2Fڱ<02i1*Nr]/րq8k?]YU&M 8Q#JmYwǍVu+7Z 16q&dHCﱈ( gpg%C>>eľZo;%),x5v *{@{{ p@bs_?㆒Y@Ҙ4v g|}:yQfѝo. sO / u:ZxZ=p =x"Ck_;^OB .?4Ƽ\0xp0:{%GQ(?Ah ?'?_Z_QՠsHv_i]? zPn [`.9(6)vpO8%",8[=g?(qd.1+^`i؅ I6߰.3?8 и p %pBXBhBxB&¶#$B.B,B0,/$*BC6(4C54lC4C;\C9C:C87t=C1B=CB ;4>dD@C0 1²0?:SxPth1= 1K e2B ;?q4([\E\E^]F],F_ Fd$cTFa4f\FgLhdFiFk|FllFnFoFm nbT]$ A2}?_j:A,1Y?2ӯKD=AT?Bt $tt1@һI|B@8w dJ̬@XNlL,+5aAJvJ]ITǒ9JOsϨQKkL |lY LO"v̟$Qt"BR =$6Y J1dd5H픥03?E;-R`!Ɋ\PΛμ̸$MLT/]M $)R|8+.%PS4=B'9]QS<H,.ey7mS{tR2 eR"5;a%O$|< O3 HM$ТZLS]1ʺTNLR"MX=U|UUZXU^MLWLc4fe o ""$>%7`&F ĕcb\z@txt23&J6nL&KNcOF} ӭb9!$z8:)ڃBa+6\^8\.~tdddi80edi޶慏-̿`-a VU`qv`Yx<A6a EqHFfM3hْ033h0biNJ 溦Th_f;#>bq>pX:_ޓ^S^F-1b@9#*"N;#hhVh JŬeR`9g0 vP>< _O:=8xpg~g ߙ?GdFN뵞i:dk cmksm>akaeaTxþ1x2]H(;ldT&\z%ϖiJkj36hX~0jFoǝ#˹xk · =23 {L3@akETG6n rQzcR_lV0(ivȄ_h?x1`Ȯ6is>d-.N?O2tArܑr*?t)q3ݞ푠Qj@z`c:4'7w0OgFmS؊ufFtZGPN,Dl_^v\4gw0?00(P2d;C=O>upGoE ]]\}x^h7:rx 3}psP?hgq0ЅvVΡ_gxxxxxxywO)ƈ^ql8fv=tpwe7XȖ'e}p\/zzzzzzzzz?y/)mTݞrh^N?1O؁8H"UGw`n@xz|̟z|}|'}/{úhRmr{a'4G?N(ARO4SlX1̥~/GP?Տw,mn6r6^1>x真eHs̘>Ĩ8GyicǍ!CCc4Z'/F!gN18'< tТ>5tSI29hUPr+ذbǒ-k,ڴjײm-ܸrҵ㤭h"CVJZ8Xcwb9>|Ó7G9c DwTɍc|<;U%H3itj-z5kUНJ}uؓ6}gǓ/oJeK9bՕUpFi>4gc%p@ t6hRL$Srĸ;rv6QzcW@V>QUVA5%*po$W}'>'|9 d`=a! If+,%'6U=.8U:d"U䩦j7*/! S3ӻ6S*0 ;lV%bW`Ym{ foE a8o젇=F? G}==HU\u"yZ0ivz9w|ѷ%~+~<ǚln 'P !}!6g)޺6.b*b&4L*0X+J.UKش ^&6;tw1y|[GMR>$<=6^*h_ 'g0؁G? [~'́H+85Bo*T ?@vL p (|={ 7Ay0X#zC&kTIIBݿ8:+NȝO`H\Ҩ-rO𒥊x nv6Lz8 X9.p3z>1p 4t3䥺H0HVb՚b< !#Nzjk9zCmg~;ƈW R֝RzU"b3MMuڭTk ;YzФʼnQa׽/~;%e7t Q7d^!| s,ٕ0w]Y7PC4\{&,e` ľI0߈qNӭʊLM6kPU,yH"#*M(L@ i2L#1.4SSuV1-C9q;=m&C@DC*b`L:.v˥i< ,洚C-ǙGoedz27T2Zi <'H`+7s|=9C2SNwN"~BL^r[vP1+g9^ݣ+ߪ>*#^ p+j-USs/勣41t{^{u^_9avAӵR,޸ ֕%k)u| _ߋTAG & z*ߥܢ)NU\ʄAW!Fa Rmza .!ZgtOOPje]Ǝ-2!]ݢS ՗X=}rqPOQŽ! x^49,Ԃߌ#`[ f&EtCy_i{`yLuKW&֢-뭡!^,,^#ΓR"miaU;a->#4va>nتHl/z @A:?>` .2q頰X}BY ?,/=,onᒁ/&*- vyajPxl҆AC?Cl-F/ ׍1:"ASz<zD> A?8/\m 0C@R% GҪpҾ:m2Cvp?N=90A&.Wm _Z斾-m[jB CC?D=9813<@@.R'B6+^0,: )+n!{ C?1C;808 L( l8(~!]r,-0YJp =1?%9h&w  hH$BSX1,_WRnI/CSF:.63X{Dv1nb2J =C@ 8l T1 ̤Z/kk.@Wg%Զ @t9DgrEA -C@ iz3tJwQc& z @ T7W{ ;@8 =xC[ mBٞtB5@[~KN,m@ 7x7xX& db#6 @ xBo׊5k{2EbueGl 5 79$ p Pk_C 1~h_s K.*,@6a@9dn{p AbR#!Oh3,*47y^go@>퓾[(U{]7k(iqϪf* 4Ӛoz63oOd0i*a#B7#d? 4xaB 6tbD)VxcF9v$xĖ.[4E : r4Z&i7<:svÙh|AeNFt^Ui+-[G<5{mZkٶub3gC.M,Y&U9b4'W&1VRVZt޿4bIҵnhѣI6}51g=re˗s 3e;ӷPDmj\QP Oy?6YM}{v۹w/Cf_xoRMvZuy#1q۟ vҌ3f\D(j.5Ի,7Sn(oD c 2z'(p3Bm=:3h!d(*ȌRlv/ "uc+z:0q\ 񊍯2{)2,O/N@JI=45]hB =t\ǔ.7_mO/Կ }u%cmF)%lOG=W4@~PAL@+x#Yt44t$.T+,yH#4.9C 8ص~\77|1]h #Y 7} kT2ьgDFэl:ұm'j܈2 3h`ԣ#!JN2$%5IN^'IiM .m]Q%F&xqA:iBv,YL:GJ,,YMk~/ 8gʙ^c]wMs R.v2FoyN{ffbM ۇB0G\3z V)P3r&T8E. SƊ}1\DZP=;xޔY(mX!M xPB+Y:3l _RmP=BpB8xyW{hdF&uΣÕ;JT ڀb L.JY>,cg9.|@״/k;3.'T \aoyӖ`q113 m[RNBHl v$L]jy͚5W#=* D$H:jEÅZPJ !]DLw>E:8ץHj UUrEVr@.0 =F$J;x ɮ.c/]ښ>^pD&|X( qbJd v[r%{7~хBf!+[i( $Qc4G>!:=f-u1BcҢˉu!n+35sD@ B(1QD(L c #$ H`<Jjy֐" C(D8(.HTbF1QPHx6@J@ WanZl{ŏ'B\X)Md(1] S 85 .؉btS잨dI:(bO# Q_|rt!uݑShr%.q a[%3qMJ!^쯇=K" )[x=~EǨo$("!*TTml !"x:UPHX\#88aҠ#^=J}ojk#ll/Rn( Nx0iiz 3fxN#A(`NNl (AJ# "bg8cߧ/#a*A|px !x r -F\F)P6",@lJ@L|0@ #bOB1mdbtG0# T.aa.n6N"*,QtrTv uR1QGF4ݴSiᾂ(g ƶSS~ 5d~Iq`hU4KR&v!LV 0:OXOS*Hi"Ҏ(U[U[[Õ\ǵ[]@)Cf5Z_ V@cʎ5_U__u__`` az+ 4۵V @V(Fh2c7Vc3en$b'].tCGe2[Zv{XtP'ㆊHdGuBؤ\GxWN`tChFtLuvA@P6\d:恌jkju%k~iάB7 w*7mնmmnae@plMUjg+wd~lhdma-o66Koc+c-i+li&q<ֺRhhfm`GuF{w1V's H'oGY\wsGxg*B]vApFg)S^~fsL&me_X*nv3y Zᇅ7p~4:}CaH"|ǔwt/H 8*: a<Y6'@s7ьe2WbRh} 7pya'v!X+y7&0RgHcWxViڤ]2gQlUV4{&Hp>k h`H`|E&jo71c'ntrabOzei#lew;c6x6`k` #lo,.L7P7dH&/¼+*@+t3LIgD5m,7)a f xmjfsxG4υ#(p7X4Llz9yy]\ۈID"VTK-8~ 'is"ȆȌlz@ɘ. pDN)%_h8aͮ`,(6, A.Cm>x5)MŽڵJv"Fh/h&ML!<Rmru56GcX'W.z&'׀M؈ؐE!-ڦڮ-V 7iBXmW~r"֍MFAMazVăb$[7<4.8.<@NN.`o]n11Ɨ4nir! *ANN19G9et۵$1+:;Let|ԎF!- %9uakHZe))}g1Z,'Δن8o>/ pxXm$7j5izX'xf;Jv9WQ<C<ʕ!nׂ oR!G+xdW(q}0FOv˚uOq(r[E|.iQsg6C8*AP.#а#O My{؂{&@3jU1ˡ%ez$|PT]0s͹7`Giz|{ȈR'{*0 P %}3Z<]UZx"ڍQtr K 0)ޱtHl4s=|:6l!1<+{ ճ=m>6U*کҟ3tjHia[!1Yn1 y3oݿz[rm|^7a}ubiQ됥(qVK)ycĜt`*ȀzHqclv3֑^8rϖwӗxAz`" \@"{ˆwv?\L4قTu'rxwa=,tX~Mu7OVޥ=~b| wt"c|#I|XAxhf6٥Hh;qq5XzpeqmC"F_got۫}{f{]Yfo_Va|K^b=wpB cCi%1ƍ;z2ȑ$K<2ʕ,[| 3̙sL1-[:TA$5*V(ֿGjSN:լ[̡h@ E"Sâ U,Ug/{U48rW3\-o][=7E\ezgj8FhԎQK ٞ>6@Hfɕa~Д>g~ J[2b^B_NڜLnTB{pf -0 l~gzSv(9[k^!cw&{Ih n8 6؃ԡrwAjxbZEPsjpدLp6^-=g6Xu+;)LrtQ e¸QBgZkоt.SirBwSH*Vi" 6%D vQ_LQ?+-H&گr=ջtb xʆK/Sxgq3o8 㷁oyOirͲt$|O)rgF)hx$s$r.bUvj{[CbʲlMsu*5|P\O_ ʲ(ƒ.Q;S8ѬyzSF> kT-[%E?j!UߨORx,(ED:.% MZ'pD>ƖP6kbD4irb&5D)[bƗ NSJd &P ׶RZzE q|DI1NZ]$)p_kxH/R*#3P-[5#=ђdٲD*|6k|xAMQ:JUr|4VF3'd#6u!h2],bBBt Rl%Qxt#;$nL1IOy.s*VzkݿhIsCDhqmQ~6fȀn6=tc$ْ9q"KURVRőtwGQl$(:u 0bo6QRQszaT7|ӉtMcnw[S22(-)c<_ؓbT+omlΈPI;8 p8t VZ$Lձ$XXÁPЀN@zՃ Y!8Xrq]ns ]R7}nt[]:ٕv;򂗻yŋ]/{7.ы_7.0`CU{+l_ [x ~# 'XpMݥb”KAjF'  tYLȵU$1KN#d%CTn|e)k9\2e/9]& f49gnf8yjg:Yrsl$9B%v1JJ>JH -TiA%} ԣCQv{C5[$j*5DjX:5Y=kzܞ l^Zn5lg ڢu`_ײVKl\"~V ^A HPv@zʥc5Vo`74[g{&&N 'x9pG")~q+89q;#3>ꐧ+?y[ήǼ)uOZULRNBȀJ\_ڐ9ldՎ jBM:+:BCXZg^q6~sW/!Z {۷}s<݄r; Ns)>%͹4qQH >NC yV{ 56hYX?+U|zc{v{q]~ٽCǗk˖r3sw2Fl(8E|lj2kWs@(j8\4jӠSHUhWY[XKf$cgYd+6YP06=n vteui dQ.8w{'}}}Gr{~.}xt'sv}WqȉWh+r(|G}G `xȋ苺(  ;RQBي{NzDtUZ*Y_ʥ^ʥ`*`e:]d*P !ʄHAWcJT+ >PP @ sHpp G > [&@Lj2@SGqpmڦ򐪪ڦʪJZꪸڦp !EOHd<,_) h` ` p A< $ͳ7ח褝"R*C6h **J0!@ j o7e ^69A v0 @uux  P 5 p>``ocDp!2k_uwEvEF jG봳ʴD+0 0#L_WzVJУP` @:%~8X#G,[fY3jxU#:KKqS6*z򐴫!mʹJJpIRHL:B`@8ꝥ uCX>1+3* x{mR˸9ް+񰫬j  ﻫ;s(  @p 0*>F%@VT)+K1K ӻ'L%طA4\K૸:|@,C5Ä["ۦj k kQLKŧlw7sɺYGF:Өz ݠ ECCܒDz' ԛ4;ܟd-ElDFlIɎɔJ|[ Q<˱ ˫;Q\ U{#wn?UP_i ` ߐ 3 FwuCSU< zۼ\zKP 8Ġ˽\ĘċɤL)N˻ʲLڹQ -йl ̐,?1w:e7g@  ~<'Q9L& 4(#ʒ\D}ɕLH=D|ɛxW]ƮlY!\]-˯\кZm {D[UcJ5r`͐`tp foK+梼;<9{NJ ϠOmԌ; KM}7 ՠ֠0 :m mаڼ=Ѳu Ht3Q@א@UU ] 0 0 Q^RnQ XWQ\W^e֝'%'EEX` Cj(л&\A蚒gDא(襒S0lIrQhp .^nꫮ ]P|10n]]e hW@*dcUzjvvFg2/ܥ3nPJ闾9} p . = ;[88TK$ : i )  $0Eb1|g EjQ R/SX#bdxc=>P0]>=s:CVL?'??GԉRJƧZjϪWL]ZPoOq ʪP=nNp+Ӹ&d Фzz N݊/}}C5baO`66aaOb'b(?bo%V/]#OmW#uo-//͇H6E&hjZgy|&f/<g9g˴waK t@R-[ .o|w"Fz)vqb-vDȒ-Yz4 |h dؓO9ٳ(-DutCSԪWofjW^vU'ؠb~] \q}jk,[i=߻U,Т%V68^&fGL`B[|x2̔Ml=$̘&QΞdhd83f#3YzCˣ77Nۻ+v߳Oz?4?^_\H~0L(BFShDH^6(Tm%^6nMD~KΖ,R|++ʆk@2pzK)) ѹ„tKÖ5t4;TXUdYsRSIœ=b@8tH4ۛB r{-R׾ГaX1^Q!R&-ULK@+W௠m_quGa48ʂ#skcxl4rLIe@U fty'2(efK{ld-؞ƍ@4ަ[uhИZ7]UٱEvT}EM3׵SV`OOcSwd`Qd2p'r/J Rw}+-T˄U~xw!؄~`? p@r4$@ef`j`28 r"ܠ*ӝ+Q3AT*7qС#`6́phCP7asCC!kC$L<XD"8YbE!qEHC,VZL86qLx6Qo,C<ш=h'w*B&~Ld&1KvR'5I~hYwB'DPI0:vp'Rru%VA&C|;1?9MjVӚf6Mnvӛg89NrӜD'6s!~d?Oy“=yړ8%h?=09{LdKe$K[Ҳv UPypq qrtԤ'EiJUR4 (iLeS4j;!ycOSUE*Rԣ6UF@U&t`,~]%EqKRMZ:])|iGҐwk^Wql`X# y`c%>vc1kYrG5:HL`11U[z# C&֔\FPآep#Owߕ:4qwp|;狏c9G ok[g \K8s4m8;bCz8,q˹?{3?S? <"Akێ>isj2u *ذŒ@2h⻦ $D>c8&>ۻ볳ı4<t? D>B>B 3B,E@DBY7zCq7y *[ 7gYj2(34DC7l[^\>l8upihFkXhlFpFkiPg$k|F>ng 77Y<9(RwT0G y{s D0p[+EEd;^D;@ňt>:H=..o GgkAgFqDB$ClFitFphp{ IVt44*+s2m4Պ۩vJ/fb[۫7&Ȭ8ЁʯØĒ$i[lKLK˹F˸T˷K| tďrk;-ѓ2xњ-4N{7N\IEwɰIh+S8MCӤS@8N|MYؤMٌݼބMٜMޜNMqJq:t2֋C):GLwòZ)T)KaLQD+D009 h.8ЄOPpyxrdGM6IeTѓjmA2Z!͙eQɁQy|U쉜*l:X6@4!M6#%R E#UR" &]R(MR'eR*}$]:0ц 9>?!23!4U`S3:S+JS8]S9m7e$7S:S'<MdbZץaԝ؏uc5}-FGV߁]}FEf 5܀=v\AcB^b9d0ی]1}@iK fg/9] e}۸ZYŏRe5I^_%$J1UAf+Mefp`U͘eZӒ] b% ~5!Ce5Rt^]66~} hgh}N7^  NYVd`=aO1v\f1fJ)a5bߥVD^iMb۷)iaY`A e^g`gI9/jkj6kN>k.kVkkn븮~k.뾦k&>lVl.lflþƖllVl>Цl>m.m4*)mَ٦خ))ߖnVn&nmmnnN^Fn.o6~no.nܦovoNno6onnovNo6poon&n n Goop&_Oq*@ !'"7#G$W%g&w'()*+,-./PX1'172G3W4g5w6789:;<=>?@'A7BGCWDgEw8W;knopflerfish-osgi-5.1.0/docs/images/desktop_info_packages.png0000644000175000017500000012370212346515440023404 0ustar felixfelixPNG  IHDR1#tEXtCreation Time DMtIME:F pHYsttk$@IDATx xEߪLɝ"$$ȱhH9h<@\ՀAx\Xc .#Q0p5uYBDA+YkWTWWUd[ը+ `0 ,|t=Xl~9Wj>I0;L2O0KҾdˆ@SGׁM3n6Z'_MWDŰ[lMdhkpKѷ# ~GDDZ:wd`H2 Yc6 sRQnb0 VHh$ !dJ'â$zGTٽ+͎Dȶ!˨&#[pP,ާ < vM1&iLFCvI!=B1 oEeO㌛s*DȲG`it"PUac"9\x [&{}dߌ/4vPghL2S5H%_B:vgIEt8!ope `0$Q;1dY@D[sTףk""VѽkLRd*+B˳&#ly*ܲy<ϹӲss1n6TYr# Enl2^%W;g).Dt;F[O/u;u|4(xh:C4ט.c0 qm0z;WntW ɮ/{׶OX"+$K6(ڨDk[!cRY&De5 ŧ0nO}a#%bP+dYZE2$N3=tDmyޗUш .ܺAUlP%Q%1(ԈσT%=K!v_`U77zD*KMɰIKuQL?k`0kGٹ-|&7ڵ&IUV a"A 55]Y_^}ᝫb$OHWCiTDckfʢ*Æm M.|79,+D_ ш yؼ.Ҽv.e`ÞC z" `C!NE*‚c A@**c$ *1D\_kҝ:l8"4$p`:@8H=ǘ?{$LRT_?jͩ|}%%QK3Ҷ =0 f4a@28DEeY!⠎-IlII*=TŹX#G$$[R_AæI&ILYV5X3eztpD6t%5Q'YɼWDTDR\R_`o^`0 !ˢ@"QP]!THe*솄)t$ MR4.jޡگwi0NŜbkN'} %~DigT= qBxsOW09%7b[<A9gs֭^deyymA4zl?t}w?;^yaxN)c5|c~{-N /f?N\AJvyOЎZtˮO&o1uiK|+`0fd/2Me0,*h;t#gW6jmMa͵.]8UdH,[UZmü]~8*HwY,59.**_ٳgde]l~-94 O署e;zJ1ӟ뚫st幽yJ7|S+-l8I/V1DwkAU=0PѼ Vɽ?Xg*$gl:-SQv .iq 2չ+ `\?3L" D]U*]'2BMQ4Oc5Im%ٶUs-5Q$t#3v{jָǒh>uXU6. 'Ymmm^~Aւ-9SssrVHo|~AANʁHQ;C@dњIIc,Mτ \=ܼEwIW_]+[зWP1?ՕLH?ɧ>`u0b!g qhP$Rތ,;aooDD!cWƕ425K\ a,ᐍU QhB  IDiƪ- @H3Bқ?}]5HNO:M{7uk#ҌεDNTc/<֓s&(ãEGd9i9 !"$,1y&]b323 m)?{vEfvڔ)22􌕙_l[xAzk"&N]O{HׇD<54F?^UF=?cï|sYwn Jv-oJ]r(auQPZX4ނ ^7!:+{QHCiݞKWݞ_PF >+nq5$2)E[b&mwc{duĦbȿxD+-Mg6%'pmɑK3,yåˎu=G^6*а \{[ذepP宅zge8U3W*9Ă_R]jя~n\BWym hfL1SU$X'm6li=F=Cٱw<6.vwɫ}Z~ q=Qi hD#x68t#:GW@÷h [m׫/шGEM5A'T*2Un4ىZFB hT W@c[ʍ #Esf"ԢfoYx=q^Qeas_WE_?U>lKCJ[/-~u`s!z鵧xs ӾjH۵!cְ沰Tr Z(.A2^I™Nxvnd蘱vOLwzҙߞ4q:w󟤯9Gz#'!4N8>v:Bm"؁N{8֫GJ; NAl Yp"査8|ux+4}/ %6{5@RR*=yqɤ1CŃ88agV ]CisGWYyF!yͅa@]sch3RVY/DFǨwǎHґFtt;h j%ƍERHXTÉA#bd+/ i@:xᶍfF\NEJ%G}d,y8Tb$W7#t8J;doցPE+v1dd[Yss"#O_0%=f[ꕙ%%9+srrkZܿ)C?헲wjPW8 Y&CŎ@̃NK I7f@Hy/}Ps[?>ťk[[̩p^=~@_dtͮ_K `0 GV 4be80}}IVTE%CFRt_S8vtmE@Gpܫ %/q@yUUǟmΥ+o=/l&3K[sWK=4hҲ9TKwSyYs6u\2- }m~3ɓ5)l\ۙõ7Nw> gbτя-Zy3Şdiz$HYk_ U^866?z=E__H֟9+@ksؽmI+H +> ђlleO&䟛]Cxqns}Rƍ ̇L`>d2E2:Z ^Ad2 8,6:\%w>uM:4;G]akh^Hٖ*lجL/(-1ч6Ly~4,O_KHbkF\+SR0=wQ^^L;0PY F=)0@<nMzRUbA N}O=:45SSQ?*DK:ĸ]ƕ=ꢿ5O-1tjK yj7Q;ˇ_ZC>h! z%+H#΃~ANJC&_h$dC&02|ufod7OX{ٕCW0ʆ֚]Nr#@ ~R6. L/?ڹo5F{EdQ!lMe꾩<;~x^h0{7+Gci1cif@\Nw=Hqf^A,x&[j/v󫖍Mg^amVnW,zJ:Z+fY6ݙdty'aþӿ__Hڱ_Pϸ,%''F\Wu2bzs|~R#FGyL&'G[xU^{9U婪9O,HHpX,NV+yiqoyAXp_ #8}euO/X]]GX dizVtUyL\8,ϑ'o5, aHr:?Ο_4h@jiq75kRR31t&$$Xֶے/8~Bٚu4k/]w߻bŊ9 _Z<7Ȋ.%=P}5q/ !!]U^$'|K3 JyJ(!xW$?ّں0}I!Cjj]?:sC^WJCaIIIɒD gdQ%oVr #Μ=M=]Kƌ?>//񒧖>UW%?t*CIhe4i1q2Li<#TIoo5AMn3_T{,ETaU k~="hdqjVY'Of?m DS3!g2RRRXFCEVCb4Ahm\-[tۮK./Z#FÆ +,,)^vRT}AJ\J/fX4Ni Yk>^SGSbh_twO5Nt<XFk!ٟa6v#GDgȚ2R&Yd!۶mggf'FP=?$yL5Iŋf/9 x4TNv0h XzQɗ"#C;IKLd9L&AS'79d8s׾3 ch< d-Hijj2}m{9g=򐅎0*JȄPګ2m?q,C3EMlV!/!>/N?)}.6ox wA{k/SzB!5jJRM=ez~4*^CV O6p`)ߋ+<(±X)ٳ>CŒ@7 Rx[ޘ1pRެޑ|$2gdK 6aɠ;qYVCMkz=MV ٩+믤q5Ybu1(ǰdn`vω $e-Yd]夤迌~1#@/usH/`[‰d]jL2gV Q6UXa씱/#(Fcf;+辰@ >56ze2g2̿cv5 C&hGSc MQ-CKKͮ t])}u;t1. dXve%A0Ѕu>[+9>̥GohvG=pɵCfHVf>YY9}mV*O{%9ֻgzf޽@[0(@wNmu~TN};7هf']SSr:)ꙗ4O|ߟW/)s]=s}b*Zf+~xɨkqm,߼Q-=d4LLj^{ISyNA ^*=niI)=ུjCsi:6l_J.c--tIR>VЩs|6yi+]6־{nőj-TiZy$Yjv;L漻N|K%ڬ2o/]ƛ-_^9wO83|-C\l;[|=R#wwyLKK#K9alhjf9xa˯zrOwMٍ_}[f_c=35^jO7Ɔ7zNF֏o%iv˷0 唔~RcKYϞ=:gy,T&vR e?m쨇fdfLIqTB+O/NKdY$򁱍1I0@0d’dvfrn6dj섙BJ 196dBL p d[[Vm3clY6Ė+CZzwk$MF4[./u&'K6ogHN A ? ܮP*TCX0)Cc~s\(* P=^]/ɹx)6?ݾHKK^l}F_BLkޫ=bu~#?{;?nih2s?B}/ p (`߾lC9Qe!U87{KHç#!~W J0.!jMI$O3REg!shd<Ͽ nTZ&OTF ga\vQAl"sNms, 'J4D&mgCݝ6 >fA?zxq*1 fLo}Uν[[Z2=\\mXŰgj}RuG={aߛ~*ST`왷 2I !LE^Фs˸o.ϬCw?*]}M[;y +[O_9vo”ﭦO\ou`41E$ Lz dO Haj'|h-!ܪfRRg/)EiɎ//_.S>ΆKE%i`I/x nas45'giOS.t~bɞ@)Vb?\hNҪ?آzYg/hـ;S9*$~Sxi$&Du׾V⬙.4g/9,bWbNի-R   ??P,wM@U0֞Ċ`Vᬄj^wwz7  /ĕCi\'l*IMaɆOw̯&N_oNLNG0 )U.YjkZP4N؞GMHݾj>ɤ7$%~cQq(zRIU8YIfdD, "USMqME ^txAN };6Œ'8xD0H& D'+3HKIWnFK4^)4k5LP,';Ǡ>ã'&dVl+%H:2'YD|QW%)ԀxgvIي¢b J㿵~ڒ `),5(=| 0jj]54~}kQLk >L6I f) u9UEvx`0LP|C.cc.^av]b Ot9OϽʿ$f AȓeS8Z`I%DZVN+\δ]Yj }}n;K ::CJBWG"Q FSQQqJP6 uPp:,uÍ֨98C>N,Nys@"$O_~-;H<|hWWp~r s ٮ=8*qe^=ΰ~Xm20QS`2_9vdwĄϖN4yHD'CĨR( & pYWI rD"% T蕝kYnM50 {&nrHDy}#kr=L(++;E >=O-]eZ4$)8i}e#wݿ,Å{K0K=UWnrO,!5מ:|M@]m0}UQGo[۶Bɾ_o.a\`GG]m2ᗽfoJJ 7=`dL˓ b6qB4Hr)1ÈQ'r) q]>+#W?>2k\Tq< ٴ1s룀mc/9[\T~̥gN=/w'xvTKp._~9V)0r0̷/xǑ sj\-nVILdRT#Lv^vxs1 z:/>$t s:|֣.[s/ 0&y*:CIA+o,H+&%}*ASտ~p/h?K1Ӆ'N,`g4(* xK- 5R>jpaf2ۻ4#Фx|yV\f+'e{-@BBcJR m"AnGoBɲ 2yz,Ukx3oaHH 'p݅CVaso iVD冱$/4߾rdju&t-l 25n2۔q˄0 2,JHIYwqIBC"#9Vl=>K{<4eLlv: t:\8H]UV_j-X;;lv $S0W8jT8Pz(TU@Fԍ%~{dSJ>^K` E(1 ˲*x?6X}Kpǻ=FG]TĸԴ۲AlmL]QaȺK_$B4 OV H4M\.G[~qw|p< '6b<'Xa, xy x.kWtXXⴸtVm|z XbvL8/.NX!d D'"^9RHsZs^@gu޻ԸlKa||qzfPT*0 h9yq93 r^-(F 2)ד SZz'_?֘Z \, H#9$?9nҭ$ 741+WWVV:uИ:Y] ) C HD1BDҒyV(yeW^TzlGb2vIcDŽłHJ rc騣Ѵ~ί9 KsPI0DBT o۰|qۮݟkxZZ[%w?MJrFR;jp&=A6*t!HWa5ggJ(^@Y0N6 6OSsn+q< (Z,ٌa(f'83!ьy=6(ԁU8ʹa I1<:.rכm/.*1 ۶m(f1ZaJ( HoLL̬\.۰Ưha=e7£ROAdŬ_7Q@>p#χ213feZo{~~VHX l|)@q2 -)-ƐweF$/: M,C8 ͑z&"57]S%1^4@G}g0UTJTg)DsGPܬk/r&KLrd#^UHH)bCJV]À4y N5ʼ5 : 2\uVr+1&|NSĘErEd^ ʹ/{̟%}(O1yjMd)3/g6eԘ;$i%" -԰]@ɼ&Kx'8p$k^nzvMWѮ%+2}SJFvv (W6O2EG2B^]ѯj~S,pdF⍙EK~"2 v֙$,%șE` d9?>F_sg:+mt 2΢dzk<5fmE#K*h2E3Yh2E3: D2dd9h2 z2@pC-ŀahFf?K@ Q BA:?vRdܒCFF >HBMK)Oq9i}9 bE9KU@&P1aK1r$ٱt *lm0Ai A4@Iʑ!̪ h2!S xW id#f2.aba14q=r֥Mkش_?md6BPDHL~cِicg-L KMr9>TiC'Sal/ɴXCu^=a/v:%GYLSN<*~#Z˴EiqVM q u}ޏ?J!I>aL۫8Evpa!7*+QB_l}w-d@#`v(K}xS//0|ͫV,AjЛ7g lX}Mqe1 SQ4 ߃42~5f.D,,4x¦2]O F),}H݄Oaգۿi6OVxuu3,ð,:F5x*Ͽ p`1|G/A7қfo>rH5i1'Xjkd]ں ȶFŀ6"dcg(~5D]?#͍_*'uo'joϜm%I2fh /;F6C RkPIISS]N͎γgJK[[`/uB2~~Mxõp[#Y_k< HEh2!39h5톗˯fkewO+\^P_xcY9{o߸ᅗ_*STp|zoOЩLCC!iL uzn6p q  MɮsT%Uu6G4$kɀd&ߺ{]}fb-"[;7HEh kW 3-F˪J,n~39 >G@_OIp5fpZK[qɍENxp.4Zsp8OoӂN ! HdXf)0m>^EduBRߵ?XfG*?Z'{:HEh2{ٍT*Ą[khPaa }?iЏԛ?9 xrN:ooϋZo"[x(_C7۲<aNSaO"xQPe$I̠P*jVC5:R Z @7:ҙ>#g*//Ep`Mo<,eND0rFMɱ! "-z#VH-м@,U0ag6O\# ujKjJouk3gC!aP [\qv#g?s_x\2ݍL}gjwOyF_p`Zh]dсC.{uU)A1 Ѭ^O8J%hZPc$"ID,i*t)Mֺh~gQMhjỐy߾64qiRh-2'xBf =ӝiA՚ZTV[Mxzz|U 3Ů³(CD ?qUd-3ϰwk'qt)<0RD))/+SckxD{e9e&6§4]붿ic80]W7Β5k/_Z9  gc=Y] ,;xqs^kl^ZxiiYIq{3Hh27uu_h4 wtRk0U{g9{Sm455EL,2mRU JJJ<E&SN {CT03r#>:Vռ{.mVTpQdtoK%]|7ծroTs9P=VBCb<a*8x:sO-E%He]N7w64Xo,м,4G:.ӽW`4-[<p?ggΒΆ8K% A?V|Y#p`:(sXç4Epc#ч77[GN7Դ7:mMko.4kTbhU4 )\ȍՆS5d8l EHu\ZKo~XTUVk)AH@0oi,}؎*L(H Y DZjvGka,pı69t,B\ nr2PaNa =pZ@dSZ#ΕWl t_e ~:󉊞@ūk E?߾Ƒʲ"Q(E֑q,0,B^k่ cÈ%̏5A~DeNA(`Gn?^,E,Bܣ^>Bkib?O2m^7~}^{z4ÇB¸63k#A2>Â>^zFLR )Zj`Uhq<+flqN[nԱZ,}=wm&Sa$9AYK p( NC|AqNq 1 ֶdM#XʱAfμ3@.08uڎ;ze /^|Ϻ{% Wɴ;~eE+?㿲 ]9?C!G2YVPcc+?Bc۶yP$C0S#ĢH猑tl $Nk8%Y=lڲdYB5@ee;h>x+Z.-/qsnFOKlY~qsB!H Ɇiݥ=K ]ž^=n-Хm8KBx?Lĉ$ďؖlKHǎ"U$h$?f}WݟޙRa8pq|mןח/^(c)VR+҇NYOvsTJ0?=Npڍ X=sd2n߼~h聀44KɢݻU@@YfYCGhdyh2M<p{RFe%JͯP M$ ]ίTZ@)@ B%Pc@> @1}tz$o5PS>_R9LJnWxXJ@A=깯z,QII̳8-3%KhsU%ȋ< @rJ^AH2z)AdAȖ*I2-g?h8YyU&_IrN5KgoX Q:e'( 4송R5戔&Kb N_b5K䔹;ArfLI6>Yd鲙nC4 }@.X8@iױ*D8SNA{$>P+l»џ2h X N{L > TGrH,;O )!~Qi'1 NKzXL,N*jO13k PV K gY^-d#ae0!Q+ m- @$˓i,r h2uC1'>9&P`@8,ZZ\ )GP(d== F60?&EK+!TvP(] vZ4,/NкtdD.inFr҆zQrcJ'k?~"̆VK #rF}W8uO/w_GV(:yoKC}scCU,+-(sBirs$2Nf2ϩN,_Q-%H&]Dbq,)n:{)esI P&FYxk>Aex0Xb'| dR@165I/7>4Bg~wkW@#@8Y&Hd!&k+I[iIS[L(P?d'x+,nd,mQa!Xy~Ta!彣_M;K,C؇( )TVZR tͥ]# wݹY^  Z[@j(㞘zͥŸVB?ynmm?Pscs+I@&|w6899_UU%?uoປwNZltl)!J7`'|7Hu5P~s P&س2Թ̈h*/-v6\8q3g{G qǞUualr,HdՌJd0Dv {vc8J7na ڍL /ګ19_b Lzsqhs֭{~,i:09~NWwl75$ˠ1#DCHhw@UE je9ui=9mtS"*0KLUXl`4SiLjrI ?a(4͌G/^<[^gDv*ݲŠvuϵwj mk/ɓOyǸމJNpaC#;k3,YObPew /t:[x@'.N=*!ϚH=L`ʊ DDt#^Xcjd `Yy80]S_tX4;<<:0WXJ|5~ẖ;!eMkEю06wV;30[+~˜UI/\Rްa~nڶ;sg_pSTOX!Qt@u2_#τK54Yks5zk"I6s?TSỷsN4.Fse bѶc48nܽ~76Yʥ+:;aG;W\`C4-LX î[U1Y,"__[[kf߷eM,Ü<~re7t]kZn= *d&`$i6^#zzG6ǪZ~|jTK}-WW~بg%15gEɘ'Ph&r eE3zV-Yl8"28KKoy55K(8M ˖7Ξ4ɠDEh0T!q (pNIeKf202~jw7L-.s 1pDA8jˡGǾZtvyiaYD1s|_4^.x=r$ ^Æp8 0DE 0(q$L$uiTRd24ctI 1Ez=Ɠ83qDqB~۟|$ VЀc~Cҡ'Lc 8fvjh?zvukӶ\zNPa௞~/ݴyۿAՄn.ZCELﶹ\uF\х< qÁic,1@YLȨC=" :&ěu/+&42;Ko~kr#E|V}aSo۷nڎ0X@SFG|]Ϯ[gpю{?xeeF܈Ln<@}@ ui֕MEAn8VH=`5(atI$ c\rpRHJ2,C\L4+ݠţo^:x6 1, };jx#O/w\DV4r虧IɎ T0631?e`1|Urą2 ]E_YQxX²Eǧv#.C fq8p@i{ @pHgJH ꒐bi"痨ޒT :<<_VVvqia[e pf. ]56o^SSTE#<)-.S5m[N:#7#i2۬KZg޴8ޞ.}[SSS<7|"AJka~4YM$#Sj9 '8lꖻ ~9Q9[&QCtP@5/_./' )IΙ2%mh2kp9 /Q&+).:oZ?egxxff$P0q 0, ,bÈeO: gf\fNuQh0Xk B*Q:wt5hYA*eG=q3L1 q|A1.2G78"0awmTwh%ٖ␘7$!dC7>Ζv7%Х? myfNסJBYπHIǎmm˶8U4%yF?<߽3|n|n>UU,-"ϢO~{,֪o?5=8R(k !P&rd˃w?= xɠT{?L+ -fZM]IM=5oݚm$ 4n[/755>|^R{ A&@ZEPT-K_m^iO:b;OuB+ ܹs'+:xkkj85D`Đ,A޾i;ochZsach4Jmjzkww7||S Ԙ %DNih[V\XKaj/޷岊|zz{?G T:Á8ŋ䟟\Bjs 4 Q!2CDl[-3@ɓE{غ7z1l6|A a (dr'3@dhN{ݦ"WQfpɘi $@oM+?P$58iM>KL' sxD~_(E^%.k.&&S;GKY`8Naθb VH>p0@ϓ)Jg8d `a×c>'4Ib'mԀc OhE<Ȳ !^egaq0O@HĄ.&eÉ*3tVMD@&J@[ ,@HFBWP7pf "A!P"܃ȶsOo%-/Lu b_ Hdfny)`ހ/dMVO!|d xWY}< mgEMVnp A @Pdʜ;nk'9Zn5E]U{&E諧BNd[>o+xG{&އR[- G!A|M ߒ˓6_ &=?o&*\ȶL @YNj%^C5LJ8/193673RypI0@B!TQE:bzpzS,|'`x'sM|.f ȓȎYsTBD-f&I .17ò19dG|B+"DAm*3>5sTFdn:{rdR]`8xc*H8ȄϤMX)yX&$ᩚ7KAd9 DZ'28\( d&K3| @@ &,u.%7d]gӏw-kj/ًm%e%v5KmZA/SfS?*?Jšڢ\"0} &ti5`-x݁?~#%]W^^&r*+QyϞflwߵhR(; 3 D H=CO>3pU+^˷&Yws5( 0 dgq 2^s]$eh̜hY,g|>0kt4" %?MÛ}{Wݳ;fm8xUU S0E!9Կ^|m+xE)f:{ޤ lm߲ }q \PZT ;N٭]hk -\gFL"vܐ&sNL=ÆRG=?{b{swSC/Η# &i LNNUTTMGO_yfpMAH=:slЏڊF6F$4$*W؃~OgG꺦#Nj޼VZ ~hz*Tc 5uEPP"0#@(K|u+rYh2 !Zg*.C RLYwxZO?onPӞJ=!)JGt6gv?c~Տ?oۤ(0&rf$_/6V|!: L3=֥ES$D&*2 yu444'Zi+,zrY"0} I*JZBUXo߰ꉎn_(̈rG%we~ȣ1nلkfT8Tlg{w߇<?p?K ˳/XQ+ ÚKG5ӦnRg5+|^xIֶVg =cwXRa+ҲcGs3ON6g6@D`\凈ԈOŪX9"P/$[1r ÙE%0aK,4KKus8T45eْ_prԳ5݇;?Zvƿ{cC>8 4RlX\>0qx3f#.XjkD8>Dj6yݾ=uSO ZnH8i<>#RDC84E=sd7 d\4*3Ag]ڐ~aajꫛ.f4ikWXu5Uj3󎶶kpM-ܟtӚ?Z$A赤FCn3gOs'748,fNT4º[HwGg JdN됗$4Qi"^|]V$ sdf eŶjLdʏTABCjHm+G7(>Ij~g:#8hUAtZ Q =KkG.^ܰFF(U5(p鴕yH n2FAi4 | 3pM"s%k B'3tTO\$ptكj źeٰ"v\uf:;``UkCrni+TaP +STQ%Ϡ/3t;p0mP_HT-[l7X1cH \5?Zg:@f 7f- W.a|is>k@B=>=}HB@Qˍ* 1,LuUK$54N ?aq,iJ͞_?_f7}K9Ctiݔ볰^dωfϋ="^hI Ռ8l+14E * jh|ZSƁ "0#@f0~ڦdSmtK@Bي otCSe$gnܶ*D1g߱aӆk6!̏GSúʂe ]O[_}-aϨtwt~뱇˕sXǍWTC:=%g`(H-!pL1!4AS !-zS#Zu8Ԉb.)pȞU 3ł@U/f?FM1 (I窩"}Yh2bhL3T  St}[6lQ=3]'붯5"dB#z4Rt]Gݻw(ﯥj0ǝC*G`HRz-!F "| ~&=BPgcx@!AaKZ,o/8>=SzckM@Z#:u߿7^h׮]"{fROnjf=ӮޞSQBa  "p 0g2 ES4NWD}_:OIm){.`6{ɚ5+V\^99#K^_5x 3D ܐ&cٲ^7 F=%Z;؇\3 vi hkn J]I0Ƚ SRR⚞)4O<||ttU"0#@ ],]lW׋/8{Mӵ5nlK8Ue==PUl1]i;N.Xz1NӴRaOz,%5_"0#@3G.4D@\S9H4֭[].oGe#Wq\^g/XaB?BY5 bhчX45YGڏD D`&\~2J ]8^PP754:?>>:Rz@R_Ysb`93=pǑ/裩0ESRS(hpBD  s  dtZ+V;`Ϲ ~8*8V KB߾ʲBQ @):(*WD`z@D$88zh7_a>NjpҚ|&%NL!`pWv&\*`!GMƲB[+,jgΣܦtY>g<=9AHHH2B]d ,B 6І})Gv)&@!!$i\!:VqlY=K|?o^bW?[_K3/z=9=4~;1"^8FtT(P}P" و9,.1V$`%ӆ[I]4HB/4n =#0`&!#LL,f۴iQdܜC`0F`f򩈙 lI.%x% 4) v,h֭B"ԎWs  &H DȚ @Mrp煈K?B ˼@Z5&Pdꃚ 4-ۆ6#%N iZ|fWiJ}MYTIeߔ,1nz&ٺ^OfjS NSdj)ҏdOZ!Bt樲PveH*%Se<$'hn8 2 .C2%H'4BỮZS>TuIBJIP&&9䲆xfL3$HeѯX->i%!fv=YhjvHd:Fb)=ޔOE3Yg)<3}^~U(.-n`qE,C+TEPź)r%.%--H5%kPg(ʚ@[C~!QCUM[Sޢ|cB1ĚC)Gɺ'M,51wpc& e} KSyՎ&s7;|zw&c<+y/W 1Duom~~Tx j2I[ !Tb.P;Z@Fk5&Pdꃚ @}Pj2eRMv=Ǩ@e=ct e6<3y5TsA2Is֦ v[QVbvh`i&=4->De%כ)V+bZ5gxl\&Sx[(k_v  dᕏo_WP7Y8"^@yyc~02d{O>1M-]jw{uPcd\{۩s'{JKu1VjzQ~Z- T]fѱщg^}wd/Zø~cO>܆gΗSS:ݓ.ϸ;66]QQ!Nqk}?~DW57l~6FQګ 0h&?|<%-`h7Vڬ\ϲ~龜j?9x7/S M!#,&Td>g~GO{J[a+78b/CqB^0/:jylUis:$<Co׮‹^|x񌍜-굷 l* gj4d-,&.c.|5&-vڐo1WxHI>eD&?i;9VG|PKXzv^tϽw=~vU%yWSO Q{i9/ /x)awւ^!北Y2G5,~j:dU Z{Gz#A]Nw 74͟S[UP@,z7/[9=ԹoX 700ەgo+=9`ЫZi\я[rpr{Lf˖{׼xop"o6=CW+KW|$Iu]aG~M7ar : 2>P;Ljuj 9ɚVwFh2i \%-vwO4֔![ (d(ICjc^:peiyr rf`q[YѰfFo*pMt(j]v%϶I0,Kn/nQ:ZGmvMmW [b>MFFF7zh7J H ?͋:i 1⯉ v+RlEV;lΦW"I53NC5Aʧ|8&b?ԉ=ʨX+*1 r=+tz^TlLh׃8"\@}Zhܒ`xvwjj1qr]:{|cg%]!B솲װ¢b9>>.f9}{|kW! =HE~Zr/kŖROKd&0 +vy,VeEH3 *7u:=Maξko/(s#(XD ܽ@cf>sG{}WzoS_c, {~Zo^6*J:guٱpA R,"_=_lZfխ}m@.D`>hxPl1",g'$FC5늿팧.eb-8ޤuLRx[am cC41`(,_v[n{wgu:]NWn=x_lw[rL0#懅z$#,gF'$F[5^Q~aYm99yj%TU ?k ܀@WC;2_.J|m|ջw}te|h^߾h6Dkx5Y?sjtK,=*L؂C/)⒐џz$$J[5b.TTV :gG1xI>y·.' nxct{Bg&kgGΕ̢a014\c2sauSq󐡬ok7pσvR;^́yC#^**tr;$?WK,{ZqW͸z/MHBĹ/bmK2i:b['.(du%96F\,zhc} "XD_2# 783IH&U4W؍G8R NߏNٙg~f}}R4Fl^(OOwjV~ѾH~%ogW_y# -Zsӯ-rP˗+;!?ꉶz`n;}_ zk埾׬^vD˧?ܗ¢!j{z^w5د:U3EuN{.]h<鬷Wָjw+rwY2 <%pwara7]q;kd?nc)}=k6Nkx^|,ɮ^>֡.Z1d0[ kǎ?wlG*|RT*Jk]ݵj=!\*3;|q^?r>{SG_~Mu4 kTl'!E5dVS>_ /œŎEn.urk@%9al}z VGQPۑ%'HN.Yn-_6/?#?9۷|q_X\JW;wO?rm7SmL2?GYv?nݺG׮PH2sr0~kܩ"B:ugcCbGdHkXK)vQ"+6a{rrv6^#e:'s?}C2^*铿8Yx;|˲t61owuU<3j/?TCH&|h@O,K܌Uⷾ'w~Wu Y=xr44';'NQe365a2(&Ll5>1ڳVvcM7VvMMqO\q+zkOOk˖-v-\^rIߑÇ}LЀpL<,Z0 Yz`Cv\fBuo{6rx=ի'P4 \St65+-]\*vgMשn`}`ln7_OLS#tu9n:5ES$S5Ni @C?t##6-'&?ȷR -!aG:.1of*JyGngb=ҩ#%@؞]:Sze}rwBb:9Yό  1%g+GN`9yd摓GN`^g;g̦ъ$\وIԇk+ߣSiЏWq#ЄE 8# dΥjBGmC{%\وiiTwP2uMRBW6v\QC2l 4?3V1CM۫7X(l|>'f~61W4q-u6d)5~dEk;9~:MɧG{j ܕķCV!eW/awww],,ScesTNNvQg`oz.q;Ȭ>[)xwsS((C%t^ec %3besRsY;cNT7}:E gv*dSxN 8SrHkK>pcNj#LF!CmDz6R08E@?t##6-ݸ~Ţ.6Ds,Y#跒z斺p-cLV#oej4bwК0(to71gm:uރd2*t-m2's_LGs-n Y!udLyhⳕ#'0 OdYm25l%#'0 yd摓GN`9yd摓'~}x-r߼ׇOu ;'/䳕޼jg&v0'\O6<\Ov~ dddM, #'0 36F7,-@WAFLNRSR2>ZaZP`JQROC&&O5-5OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO," 4ZVejZVejZsTTW*[fYFej~S~8}Yucr't#]=g-}Yuf4wGS egbf%Lqt#=>V]J"K5uk],Yֈ9/jW~k뺲=Q#EmYu(C)n^W*3!@s.l~:^ENyךRQW/,w6^ux%YuJzs* $NK<{ Ytߛ+MUt款g9m ayUo 1z^o˩EDs[V9N1FR+4fZczNBYhu_uVQlRszZ>;~85Z4@,>+#؎,*tgd N.+5~<~ja.f{:(}KC[_Ξ-tr=vdo3e |wq1YMrͯ}@?}>nG^1; },!41 "A0@2B#$3P v.xo] v.xo] v.x ^zuaZ0E+v.xo] 1ḿU߶9BT_sQqr[ȭGZgWaeG+X!]\&<;.q4*jĢZI;}AФNc+B)uFφI9{Zs:הԼi J ! 1 XuiPHM?u~V!KJr+Y3n0& ,V#BHB=1LmEjܿ1Waە5LjțZtmggcekbE_vW4nm/1n}_KKV${cT4SbhMи6}plB gϴ. h\>и6}plB gϴ. h\>и6}plBYv² e ˴.h\+.pWϴ. h\>и6}plB g"D"YtS?s#覤|P+.:k%?k#YthT벻&*US)`>ɩ*dBtx^n`BO4iMA~ ]e>ٖbCx7tn-{mMS'NQ>e>4ΤJ{BD\a ?*(s]0,֘ݛ~e'\Bw5)5ZR' K<$M Y[GBry!092R~ 3(+.L**MfdSK&S\VTWvF+= ˠxuS;NI5S^ {49 izuc 𑃡!掵Q9IBXz@0kmU1*AL ϩ<% hUF:+e1W$[6C-S*hdaAEP+.ټyjebQE5zhLM|\9Ջf QvcUC{ /E.kO2r͢cJ8[25]jV]cc5?Z(@֊gxaPJK!濤"{-% tӼ+я: )'ݐ+.MJ"QinH Ίfi{y)STU"~DRzw.J@^ \=+.9f*)khtovWaqMx/Te5:]+_FL^fl= ˠ 6gk?F3(!L^!Av -̠ >191z Xyk1,3jЬ?[L(W1Ey(M1VqÄjfX MUǖ*JeUXLSZ)yToS7e0sM74 UL"U+[!"S0- ¼iP4aeE/j'0Zv=DRY)qW <0+)C0-ʳPYCbw\"l?0QE-& ;4_U'Mg :SNE[+a? ^"CBcA 3_ai)AZz1bqD'\Jl 9'A;lstB?9mpdQ&o^h BH]%C8 5L/c;2PyGQC"Zzki2@jmq7oݿQ&8r"b4( t(lB!Y\ME&G3v:Ŕer5\(3Nz,2j8`ΰ'c 76G"k*JJTkN귀KJq[{~Ki̶;E7&7^Ex?60ćI^FrDo+ h@BZ)0Zs'n&dXh )Awgo-s6k2uaJ[xPAf7qW]C3mIt=!`k gÃZ] `C?05&Ҩ:'EPs Q%̥,hك[h)=㵅5ϕF7w.2C> =!q㟙8 > ! (hEF(HZTB@E@ gj@H6[?N!X ـN{~M#ppD>wo E_ME-/F0t' B@2>H:~6q2$:<%-ӆ"ś:GS QJ^  Xcq & N~YEA 22$ 6[|{ƕ fϝYwL$i@gB R~)y)scA~̝7Gx'c'ˈ {`[37$YP cj+=@z5Yi0kOXq Qh*_o=(j:vhmL$ BuzRрu;0a&IОAi |ʕ0Ry+L YLv4,ءMBBF, Hx&Å|BcsA:uC8e:gY`0ݿHJGyW d%Mi=Ca=Z<ù A@XM`,~\@D)J~=f"sb-g)g5 O "P:&=@#h zuI=B\( X Eo~AxWd$N9MkEw I[cľhJ‚ T+U z D 30 @wˈlFoGRd n,:1] k gA0 !C7\ J8HjXg>HMβZn Z]C'BS` HhA=~T=M!h 8i1J 0l!m4@, 5 Kb4/ wKyu [0P}R]3v㲀`q̀gi 69S-@NC2 & f^R@c ̶L~q3JsPbs^$ÖġlLAQ(XE*fPèJhu t%,&|Q([&AH]0 U~&|Z|@"ψ@=f!HKf_NXH##(3N!{Zq$w UvB]wa81)r0[>ڊ&4aԜF hksp h`@Xج#H`̠EJ`(шLIi Pa4JLnp F .LbK{. [!r4A1,@2iXe{AAA#SG!'}zhi`|ciDGߪpBK}|w;=OЫNQIq `}3h@d@ BAP30vE,j 8 p"oyCPn1c*Y Ǹ)vZyNA]Θw8pe% !ah&x4;C) QYtCjo}I-NäZw?_gkT!x %Bics< Ƌ%ÎAE a0A(6Cj5~ 7f=0a:@vDPz\#@/^CeMQY K(,dH0!/9I8Bxs>h46~3( @gY Emc 4zqfq"2{B$pY'0qgJ/R:@=`C LB' ~|bN?Q"hؼу2"i@ oEF1`Pu-<@H0"r^;ëdK:?x;uY^d̈́9r"WFota >AB22 @8k0UTb m*]րzHKH+k_a(@2Z_iP/x_{F7W 7duoe73J·QdMV3l,Xl]ҷ!_\^DO_"KL'qZ,,RW,ca`pb0rh<{HM)N@E_QXSbXc`PibPt1@}M, 3MR=$XYuPlTYSN~j`88#|'%0!fZ_+21CGqR'*Cϧ>0r)夔&X@ 22"NҸ! RL4r (1 0Q`!4u¢MdS[kP^Nb OI E=o x? ٌS0s CQ'? %*$]t!Y'ۯa>Ȓ6.#篶%52IEbOb֓%p&L;Sl3$1 @PJPL!*Aڅ̓(1"{)n&A7r~JSBsp2Gx! >%(8~%a#}!0 v-5k3RmER0)Q6 )tS,xE&8(}x 9q@U*$@ X{GGae~!dh.5]"#i&x:AX |T^#Q  %DpuO~ۯ98rC V[8!`7'2ZP hv`PkX1"Hl̩'!`o䷨RU8(V儥Y M)1WKu4ZK[;&j%5LsY F]Dj1V/'P8ZtE|@eoGB}Ail0UД!B/^$s!_l6(>\dE[f>rB$$+D!BI.@'~w>@S| ێnn=HޮuAo smˮ'?5$ML#|TES '|ĐDrIc$yaBVJŬ)d rN\8 #.4/yb:Mj2K2"%gq)pdz%2)%!E `xeXk5 =#ZMu y1Veׯ5QUNi0߇ ,=Ɉ }ΨB|0^%LYOd?8М`$)As{V8__?GY6ࠄf;gNF$>?re 橳&@HH8ADcdk@Iu^hӆ/x,Q+<7x PI 6K92 㤾HBL5K5&J}D1โ^%*k9&rjCdz` I|xZJl$XNe) H7åy`&U2|d $w}j%VD/}p!V;UOǘq.D Id5aMFG{O?A9j5^.%Y C읹 T)>pZ&!Y4w.D[zlt7ʐpp6EuFQlc""cG\#Jga">h 6NrD(/'8v_ s3`^\@Q R>R Cu}J* pnqAWUmx_ta}?9 Z0$B*u^w&I6d 7:eW~3VK"u2E *᜛v"~EQY7`匃IѲw^!}0AX i5(˫<ᥑ G*peTU“퍠2dxk@i䅷(oLe Ng~ӟ62U;A({k*G)NW>=旋q]'6Y6@2z0+ $\8uX,LOԪYTfFE8{@اB>BpՒ%vDtKqT :B9&jc0vZK4Y 59bqdkdbQ $B9]s :D}K?qp;kmV~j*MFJ\~CBu] ďkc0pBS7}aRla#`osH ^)iHF"88/,(#$&C`@XtL`ơN>īudֈkfGqg[8231pV2 uC&r ֊ߌ2s$$81ts _|E$-F|AMG hGRg`Z-4—_~,02kOcO pD'ތK=9;0WALqj]aJbR )ǯ֝ʼn\uC*k^S G(A}>~M-ψ% %,{"O )^{t''AY*rTI\!փ|Vd͏BĒAsRˋS(&B/LY?ǣVt`d 6T?8a 67byE15gx;i:=!cAff`%TIÔ\\1f)Pk!<[_侊ؖ\@+3T5/!C%3[FǩHv<|I{,-z^s Aղ/7U\O~rNz$mw{y~ !HnO2d6\|Fid,jI#hN{220)Q E?h $=8YD#JOˊ;78  ߩ1X'ӎ/&B֟18EVõF޸4Q.~&G'm/`+\n[|0i#u?} '62SAi}~Fm mk^9~xB OX$DHNLV@N U/!b܁7\~CD"pݠ%IDwdta&|9>ʃA/{!*VHρ!ʁG6 V"rdm0b%HR{#Y3b(.o&xKW>Z$dBK_*"b}EF'RF8vTWu2_ #`HHǙ>&ebvKŴ h5!w5ͻp)cQmtdǞ9)C #g\OCiu'fUCsu ΞqD ra#5r. tc#SzR"ʐ"^zI&(řuߜ8 狘6c_ *Xώpd AL G,'q!&2B]b1i>DUZg;%%&" S `Yr|؆GK_FHp{t-Єt"aOq@Om(XXzl觓;įbu:!+" 3nH$ 0 diƍUŖ ;Ƒ$cOT 1tL.% A9Gn?sϟm)7syiPތ| qa=Ӈ$ b #̏ńw''[iNV%v$~f(h 2Ǽ(a effzFBp0 &&|>i0@Y*s)TN[k#g7Z;oQ?gۯ( #&<8X}1~A1&b!ȑ_|VeHl!GU0K>DE/w?D qл̇4.#EP 1B,!ɊGJ!UH+ >>:}7;o2AOp% WE"(B!c+vqA!aaDG&H{I[~4#>'"FKLLrLVLLG*2}&c"dC9\Fn'`F2 23{3d>]|9~.~X>5QTxAA?ӂmsBB;  w 8,.j*W1XXSqx9 DDD$BRI2P66maJ"HJI]z'*m!*]/=##$"#%CVQ6Dk9\\܂|Fۓ7lWTU(VxȬCb→RR҄Y*k*ݪhU=$fojJj1j7fեԃ+?kjj\)Y9ŧuAkT_STN']q *=Y(Z}5HcL>CaሑU9cE}ƭ&hsܦަWL̔u [HXDY4@0qjKa0z+`ejuꭵuM͸mm]ݲqbm$GW++NN'FwܿǙ9йRpי]cw޳[]w-GǺg璗Y9o}<)>'}?i"@; 7`:P?0p>$|JUP\Ghc9,8#'|O`dDzhZȹ(h(zwtC 8=.N+(n51=a{z$2>5{ijDĔwuxhKLJKK6NH[\Y%ԏ687 6557ޑs.mmYjhC{O;l::;=hjn~ʣ^NJkT5 ibSӧ=, >wxї>/? y5?7: M[Ʒ#\#S34zv_01X8q<+?7OM LZNY޹scQ G*|m[^Y]^[\V|SuzFo6C77#<<=Atc?cpy`!Y(EP%HEd'j4<&$qO $ϠKrdc%+3RXRY߳հ_}')?B`XnA)[ '[5NŋJ5j!Zڜ:v {MrwY[YٚrPtTr),JN`d~|A!aJQ6.1^q1I8|I2F3] ̈ԣgUd7?1)ӂgrmu=}n z#?~ȝtܘ7c032W[]]|ļ̷|gauڣ%KH*E"#(142F Ӈ!pt:tӄ| i*S'9ى"`yz{ՉCSč3;7?%$ƉnvMKzBUNKo{BPU٭zROQP+^NgQOK?ɠ𛱮IiYVK](^{6ms;8ObtU-c߯5`,,b^9Ռss4los0I<)>Ӳ792E:*qL=x9N^=pzlCxvSQs7Z\*Sfz1򛗻+>UJU\ >Rszۍ77nJjnU@}' aHAE#5)u?UZBkгcL f˂uaq4ӵzW !hH8VmǑq>:z:Wj< Mo!"ci NzΨx)5و|$J4 K$k.Ű-Bԣ&yV-?4~q)M7YX_:tk9w~ez5wkILi+?.nf?o 6ɭ 1c`РAneLAOaaS҂`{|x8]dx T dVJNJոX np~ Gp#CX gX8ٳqqj$L&5|@Rɏ1Its%%%!66VP)8gHV?DEE?G ,iɲ  dּ|a%M9inngCZ))qf(a.W&//2of&QEi&NaX$ ̌CL~{ @k39+筜G9q*-o(p0)OpfjD rKЊ#6z O;d*84pRRDKaUlv?_c!EYYY89S𶵈I2Oи|:˻38(rjؘ)TȴVCͬ%cueS10 턱쎩ԝ q2\pc .%fP~[3,v=+Lq8Ґdpj\/' No<Ë.笜jCa6r+c\ӕ TdwpZ\S3f~u'2.%+5sʆ%Y',t%4NnN-aaa*ĩ+adi-  tZr/땍SL`e2f2aӉq2 ' C8]j g:~O21FFM)Ԣj&`!60\d$\8A&2/e 'Ӥ;%2c 0 2Zp-,sHCPYÒ2d@2gIIr3Lš*tSq5N5N± T@握۝rDK=*f4#P*Џ %RYq<'dA%NIƧ;twg(p)#{j2+3fe.=fS8XÌԆ)dc<20g t`W^:}P`"'RǘY{9,^Xf[+|_ٹ^ϪL>lH4=8šW ֮]k꥝(}NjWv_zmUjv2L/i1ڮpXiOa:_׸_YmJ>@w &޹g cKo#fZnHn[f25#<0q[xɇJ򇸚Z{wKx|;5]ߞ棹_ك +;| 7a\p,ohNCg|p맆]=JJz^u֩z/^(΀4fΜ _^ee)=|xĬ *M܀a2ʛ4i8bE ~dh|0o5(lDT9s+Wl-CCVJC?anƌNvԭ$i?zD-I _0/Z)NӚvx4u~PL_^$-q?råmbjmM;zXJoGyU-Voލj:{ܓ|~ RQPR}rz)(XE}ɫ30nD"cfOAP]} euftaxBRTg󥔴db Ӡ[Q sE&Mwᵿ3ohhBcfN&CVlQC7XxRl|z KeQ`4KtVךU>ةֆ?XчkC~(kA>#ɷ# .COkZ:c0][<+] R:dNdXJX2%;[NsZgƚO8?0]~韹\.>ĉS # mYqYìŚ^$59΃>uV F&ڎH>WWB_//[}EHO!Kk< u(َ03fDgY|~4iiirɴ|qVH/x+ڏqi'nM|g%/bDFWYSf ECYՉǜKƲ/J|| GFĉ'h'2$~h0箭AHI(_uƍJ޺C+=vw}gWыҔJc(G?ɨp؁*qU!8<+IF`9Ú';<ϝ|@tE?ߔH\#RL;G/}wy:ۖamE:/Ʀ}kCYCz@Mӄϝ@ ,C&a48Oq9W^:sWݑ:贬_ͯsv92 \:k?-U`w":cI>||x[5IQg_϶3F$aF>i1)o(}ʺM۰̐M2Q#PRVY1&5)MY66 86d&xNfV-OSyɊX8J٭iixg`({_5js+I Pz+ {kD ~~JP_3:)|ȼX:/ƛ75U{#rK[QPфfѷ^:H53'N3=g~nTD.Ptᰗ%%%?dNdb}r0xLaִƳMMm,h=|Z0wB2/jC((Y:sm4j~U>J}Oѝ\<dS5W :c3511+Fg_6V_h+/D|E:F=YJ}"dZXO4::80g)H>a"ۚQQ-J樭oD ,'QO$JQq0 koI.MbM!y C;|GV-ʤ(mEN%/2 c%Smj>M`ܬ,ˤ;MiX7%%9Ö́ڭ%j&e^S]c͋~66RlA@I%%Oe^sX#2xYavgگE`҉E8LU|WV*A ߉Z6)qH&䇦Od簼Y֌TOL:a&+1Uʐ8 "4J}،ŮJRy\KsۉӰV惸Tਹ2/ANVdFVHc5 ZM?~ɴ,͍5-M|*VeϚNίaVQG;G3214&[E$D!&OyLE}׊Y8B*!ة.)y_cVk>au7K=6p-NJҡv\4uRQ2 d2c>7rQVqe4x}V䃍4 dsVN: שGZt8hȰ,/5Z[8hA4yҒ~ħna9. ,i6LSӏn0ڟi?vhع6iarNPjiKu1hǩr,#=tCWHI y`d*ۣFjVZ&bδqXJԷ dX$R3fݟy˂W+X`gZHdR2 uH㘞v&e#HV) fkDȾ?L!{-/C f,q/12i8U` !QK }#'1&13GbHm O&T$67o^[ÖzVNV1.tC_ƧBiC2+q8K[hXӬg,YTg[,KD[82wftoW0A GUkgp~? OHnn]wͩ7n0$_)5"{Ê've/#;T/jè.Ճ^fg/M({pξ.5){P+D +CPjrbTZZ6B}11#uU5NwptD%dw45gŜd҅kl!<) ;D7lABҕF06 #s~2h a̷^'g'oMp8t;Gx.S4k.`y?wdR~9V38g~8]:]ŵ i]Θ~~xgmZNjkn@[C-JD/YNPW"p_}F!h\&LLQU)Ŀ;6aMSG|ot<6)qi(m]d"s {[U wo@rM9昆U>FJHacg={hi21,RM [ʇΓKxndA1odVV̋XO\FH$$-('cHUt94N ޝ|8q}]8z(Y?HcR׉xѷ(m"D!(ꃅ3fu, +,>UuP4̴[l1ʓU#iJZ3pLD>hP(fOĆ-ȯiCqhERFbQ%./"9ː{$5Z&vwi,XydT~?&@p뗰(\G'aǎ~2ktSgLEyCcDG|Vƭ0G;0#Λ;YNg5Q[;0~A҄+K/"d8m\q $+։/=H Gm#YRtnlp>/tqM_>I9yjXx(*el/d=t0!#Y7CE)%7R4ljEwx|P)S*dL((xO@ y'p5Ǚ?kӰNIa9qsC;7RVEC}Xhޫqic1H8nG]Z507Pm'GH3{3;vO?)ONNН'W} X3.,ݮ Q'0sa6T⬣cNxiXh`:l,1xcZQ*%J:5T.[ڨninYל>%V+(ۺBU|LFi>D1C_*f9xoPLʴ4cY]C% C:/V}G#3\IIIQi6V[a}Da` OHs Xô:5NYG9n~t;4{(**R2|FO6UuTz3-: \VAr\,Pudkzڏ_N-ZV? [wT @zFyFQ1{P$Ƅa~ ;lh Tʊj.THp20V/9uz]ךgv62vi;~2Mλ'L_ujƙt\ǸV+;0 1veq &;;+V޽{RQ5҉+ 1++Zq:#/:t+q!#NZ!<\6LOAiH):oV%a#!aX4J?%Iw9&NC# Go#S 4҃~ڟhgUӟc.3z!5=]h8uY;p:-5k'~G,yEyƬDpDJV,;xkEhخFFikKl/݉:\@F9cU+1#2+N>ذ“q5j?/hhgc3WDZN^9ac8:}h0#H Vܴ{btC8GH$k8c;eldX-1fn+qNY 8G\ p/attk;# 4PZ3. 2駟(90MkTFa:̛qZ tLMxwAQZ;[鮽|0ܱa'gyqL8V֋Nۊ&;B8Ǹng0Ṁ ]V;3@c.augI?l.{*ۙ2)  :n=L&@R0k 7= \z饝޽`20% 9k/Ҡ1k 6 z*.%t@_Q(@/S0k/Ԡ3+ f+LìLPP(`(k 2 2A :Ca־k(05 w?̕kE?c  7 ㆁC#CCE; 4E3(pedQYM†Q0g2І- IDATYM†Q0g2ІYM†Q ,Z@5oD~qn$;3lKz&CO(0` 3b'9`ػ~xnٺɽFj ,KΨ';}٩{hغuzgU|vvfYL|? a,)aQz`{{L6mzI%Gt.q ×,Yo;,H ѣGפ1}CJSJŤ|F3W"^X/BZ1mPMXpz6̙3q 7`ƌ`oߎy7ğgZ}UnJC+3:鮓z(oP ~}j'vTFapBNa#S?|{+^bV&Lx|~/;oN;4./>o6>s<9rՀͷf@c_;Ww.aӖLd p#(H GC`le=*f|h۶m3g|Ix㍈imছn}݇FR]r%ΝI&aݺuk& ۩Y\_}ƍo8п{8spw`J3/ T݋UJN: o"SpCKVFЌ/M' HF12_7#0+ O?C#1ط%5 rsd&$QmR8̟r^ymݦC\.p{,zʟ؇~X .?NgyF54axD2fR~E6}oEJx"12*#C㖼\DՠhjI*sW4T`DjG8\Yue444`ѢE { *#,, ֑J({W á?ͻwVK.DqYٙjf%2_QP]]BBB.R6Hf_Ƣ;Qo3 wӓ=Uʊ᜕ FDyAs-QQQ㏕ƘCù+Rz?կ&a,nQ@/pAMbXǶ-_ c_xx_إ"M(+)DmWM|5@[9LYY/9CfᮻRFH4j)JtҥJ󟊑|4XڵVtd` BCCCZTTR|jpQHMnAM4tjzWJ$2.7@PpiȘpiG٨҆<'|v &o^(T(mVUUU O"eK]6lAkz"F꺱*aT%+Yq3PV.h3b6L9j~k Zj(Dra)3>*ߑ2gA bOa98\>çnIЗҐJr SVy'D+.j9ïVS]#*1Bj)Go U-Iݫ%h(McUPLڏ]͙z-4<1+4g`Ư9+CvE(R7ڐ[E!1™vѰN89\2+7Gddd5ŋ79eVz׆a0rhJ dD'NԘ:qFrΚAS%puaàI+;֬]s+--FY#4{ dسg[>{9,T:@.^Ǭ\_吗@C QK8'ʮn-t4<k:w(Ѫ3(XG\׎T`Q"D:ǖd b:[W yY3Y~`e]6;r).%#Ϲܹ2+Inf՘pJͬnҮСknB LԉApzd#nZQgY9t=ctGÆ#kbԥ/9瞃UW9 ꡰ9UXT2N- ;S'9)2͛Un=1;x7 M||bjrsk֎,b?S%{9;=)4uIzR_P7y J;m b+u `z;VJ$7S4T_V\dT)gO:N a1aX+\)U=gՌ`~~*vnnI\z xf=4/B[.ŵbISLd.5 s?fTsꢋkk]5B|m#w##M›:RkW1+ SNUs/dNī]hػ;*Bdaj?cՑj^=;O=J!C 1uHnbVg`Asa/i?~ɠ cc:jQo~{Е4֊EShL8RĵYؘr4dT??\pu:s p{9НTKQԒUf׊ԉ],&:=e~⧞|ʜ]tLxJG+3ynmP1ubFˬgwo6摇Al4wexҘ)@F%jECcBMC0Yvl{bM9`EkڼSww)n2+wR]pq{=l{?OOv@3lV̙ԞOcgR~58(`PMSCY5;(`PMSCYz<$init@;p[՚Ogay1``x򾊿?&OŸ:͌.]~|T=pcq%dV~_nDn8j9o޼^O8\z=gs.6\2W0EKk R zT/M2~ m7`ʆKu`3[y7Ѝ/}աpv<\鏛W;OD9јz0+/R|ss8h_\l?窱v{{RݿO.J 7Lνg/b8gߵ)GHP>\\ 'Gy鏪2k?W">' U[VN]i>,g/8L&]./m2eG)?VW;x7|6_Wu,~Gt o<{r\y$Jܮҵ#[̚77+@dfΤyxnoW^5x^ fܿ6?Tl{<"+ϼ3^%ySOT"y: 扛?2 ,GP`0.)\,aqx;⥏O 󧟤r QYyur moi?X:G'oO.Q4kT^rÜY*3袋?W{_p3yZy!5_Fg^uU 3-2"j(o0mœ>>\y.:zg폇ފcO=0Y0uYY߇R0Ϳn ~ش\ﴣϕZA FNJܢ=HM.f;Z./]-~S%{k۞(*-P9gᗋ~p͞po =eb-Οgdoċ˞Ɲ?aBla}1w0fx?5og_Wq'&/wΝr܋|Foْi(#Q2n2_~n$ܴW2z2)S<~)N=Tu3_‹nQQk /b:7%/婠q)UV\83pcpͯLwּ H+k{'l0c_Vtt\s/p%b'ALnMDKkG Ι)hb#xЙR_BI9+;cH.+iv7<ܻvvǝrv7iӧi;T}ThN8A1~#58s3|Γ[>q谮u3P1+ 18" qLtfd8ƙxPXӏFNxjz_n׸`h\*8}Gцa4]{̛vTexj=Eͷ&}hJrvUpڮKܠ9s9\=M5;1?s?,$Yg&5n8T?∎$]gi ?{`|Ek4S2˚Dkpv+7|r:,a2낏HJdžډIi8zMzXS_=L,Uipk}P{ PsOL Fe&ݓ!8/!!)F=qnowpf.H^![$}MMMkdqr+s˟;89軣6/I-fݑ~{ F~I58^J:\zr_ĸ2I a ͅ @^qҮ~).hE9֙䗎Ya~q{}?#\rJ!W~gG0w';.78tC=d#йs*7@ذy2K!06'NT2-ܢ;⧛x8g J-#%t*}(@K+a8TZuer/;ixnW0Qǟ}z 3^jO.Q:=Cp{x;EגyG%2DPSW J!uU i=Mģpr!n_t4T\ן|Rir0錦F 3dɓ'K;ܺȟ+vBٕ򈿾0\re2]Wi[d8m9݁p/X"""Բ nsAC%kWfK Ąy)lIK07 f240jڀP0TɦaV %14P0u@UɌk fuMb(0(`u@UɌk fuMb(0(`u@UɌk t5!STVʩ$_ ]-+ux/CM%i|Gؔ?m1?_?¯͸q+Յ`0;P '&yY_栰 Cb+%oa'oxȑi8wGE:#ε_^>ضPnGjL8v7ڃZ^^qJ9s{[>']mẘMHζ&0%[wybGb҄Q懭IE5|Aزm7f͘؉<,qQsNaC.7"3lL*,IŰdB͌ 'pdtSέ226ǟ~>rÌ#qidfFyAiHPh'`mʖUExtzDژG_FksfN?nQ㰯cN:(Osz8YID᪦&7mniD؛mi@s[\*vn(I"$ S~ WbGƥ(!nJjPQU#cB]?:h4G ;B$e0e5/C.2,c"vUc)+ASc풖WILErp.Q["ur{bܞXYUaBSlG o1}TT4( Ġ@lQ*\P/讬;V_:KvÒaxޛ=J* VWIؘ>䐘ڋvfd^kȘri^͉ $qے1j<_ LAT' dF\sImjcX[|`9%) Y[㆟'+~qmsLmX֤#VʯŒVMk(v< - :'kxNun֕Vۍ}%jjHPeQ6(Ccn ńg0=UzKEҔd2O¨Dk ˊ.(n]rE-{G-jK2+zhCqc0(,ur7e WLS.qmٶ"hQ_ o(?r$'>qQfxBBb#ی6>(ZYS&6磩.A4< /w:)1ߥ8]aťHJcf#;k 27oBJY@3V._9m;,_Zj fpDm[>%x ##SN>NjZ aHDaA.8N=b,m-D#",H8"c?)J\dfdajS0ͲVZSS^GLU3b̟y2^Y>}]SPh\V+v~3^c]8rty4-2iqCyE-v,RtMKOvԓs/,偪AJ*s޻wo)Jjh KR*DGGw8x9)kjQ_0'WÇ)a ԉ+_zzIN>EEeV⸴W Q.bӶ<4PNUHȚvŞ l"PYQ)C`=ڎE!*m1;S*Zjì.h9)!5CΈLƜc1f6||S,YlEG.]ʧP6z&;a\ I*:6Ȇf˰Xz^7\+9)w?E!pv4/x*hdgTu];:4ZIDAT`5 lE&N_\tZWxxWm&Hgjeɒ%8 GN$vZd9/y3$22_|=lڴve)ýNYU V^w~ WCkmLtR"s^ʆD%r8](WT |ESgN3I:P3R qcFb9vxʤF-47Ff`Zh vzunab6?3Nߢ"u7)+gOE&e* JJ]Nko|)2Dk܈ ]Igzv"ܠD IDMa-̗s( ccq. CE;TBR1a N?y`hBJTLt"K RB K#Lޜ&hp~[e5/v܉mغu+nfDFNרTŬi$ҕҒ"ʥnGcđ"^AsdYTYt_ȉr2&E\l;v(F~?O. ͘Q`\2nh4Y3%UYRM%*ڙNܣ5Y# V[d9@!INM7${Q+԰X70@tgtiR"BBuXȱE iIK1uHn`[@AaavXNvnNKl;(44.^kVa#Ϙ)N-$4H6-Xeu[6!+{'c"L2 pE}m*S0u5^AAAXtŨ]ez/a/~믻ގ0]ZH;o?Ƨ0iH,42 7P|8.} 'c={؇""vj| >Cp}z֬Y7o {E3bs1j'[E!&Mnrc矯_r%0a /Jwۅ0gy&qbXjYݩO3f V\Rs9xŔY>e9s)))Ŭ}HqqqؘOvNvO>d*icPaVꤓNƒ>؉>z9+_wىQY}=^*w&p嗫r ?6l~AcŊ8مh[Ie߾}8c/p9ܯَ͎$wؑh=>Uk J<#x 7'T~AaVށD ].HK~E٣p[ /<#~uMn zb̯ Bx2=x*G#կpUWaj8inkx6_|})Jf˖-xOwlsU#=TgG4NۛpwH{1?FA8Merey0۽{EFۅ^hi&[m .l.[۱cJnۼysիdz[~~ ?^d&RMnTp (s6/-(LJ9YǷ]ve'SU>9_*?&eewd֗Rʕaӧ&TufddQ𤇔;C)2k|vF?msPxW_}gV 1 s88 H')SZtAt5ͮ:@mtRZ>wr/Uɵ74O?j[joEfjcy wJ!ˡn8硆;O>U]"Y)lP|ս y ?c )|7G#G79x ·uWSS]pŨ 7w|gם:v ׵/uX}%AaVV5\z \( :UNʩ^kLjc\"'Ma5k׮. t8SNQ JM&icgġRZx4`RmN֣3zpE56u7*Hǟ}u:R|NGI6t\kxWv}M ;gSܜQcl]v{t]cgq_2gunܧj|b?cl(;]wp 6 >\om(S f)Lc|7}OS'Gcc>{ R`kf6C^l-l7:FxgXO :zūr<{ YMfnWԠr 6(4 CﳃU;O[·Ͽ0u9zc@N䫈!"1}ve&b  աN)b#(Oe䢵3Ê7bqWVP9r'BS'bk$+)IohBEU9 u8أ 5TWҵ%uOŰؙW M-Etl"~}?KI֩0M^XȈ%]dZ@ NQ&52`9mG~a ǰ(l۲|iRIIV׬f(/-GXx[Ze~*Z$yBc466#7L y)$NOf_JR ?;On+ _":ߊJ\L|72פtfI)zn+V_JӐ=](CcnG|1a|zRKIUHVK6ii#乆Ũ",mU,&aPXn^ *d  BUuS2u8 2i˪mG!fN?p!&5k}YOI5n.T G̘>C;;}xt4K]xIؾcl7 턾m>U#&L'/ MHD7JzګŒG(`gtI,bQiٛ+¬"-yFH"`rT=sN_ Q xxFS'@Yɕ.FFSmLs :29uV,})9Z̸=u^ì{u8zeL,kxk:ƼZ:ҦY;m۶O>YgQvcqIS'.I'^>"[O7_N4)FMhiGll8D0¼Fɨ*8gOn&ٸWǞ{N.KILg˜vdH<xO (v03u#LtK_x<ꭷ\ \t =smKK32ғoܵr  ˓k=+e(pP0S$8?=7#}IENDB`knopflerfish-osgi-5.1.0/docs/images/knopflerfish-small.gif0000644000175000017500000000565412346515440022650 0ustar felixfelixGIF89ad1!!!!!!))!)!)!)))1!1!1)1119)91999B1B9B9!BBBJ9J9L?RBZBZJZJ!cJcJ!kR!sR!cR)kZ)sZ!{c){k)JJBJJJRNNsb5c)k)k)s1ZZZccckkksZsss{{{s)s1{1Bs1{19s{119B199Z99JJ99sƔ9Ɯ9ƜBƥJƥRƭJƵJƵΜBΥBΥJΥRέBέJέRέcεJεsνR֥B֭B֭J֭RֽsֽcޭBޭJ޵J޵cRΔքJJJRZRRΔZcֵsJJRJRZkRk{RZք֔֜ksޭ޽c{JJRRZRZckZckޜޥsksRRRZckZcs{Zcksckscks{ks{!,d1 Hn_‡#JH1b>y^E֯Ǐ C7VYqɲZ-۷ltu|ɳC})ekڬWϧS4F@agӯ.5-E'a`7if]Zcg5vʧpÅǯ\9f 3MNT0qݻܹ .SN8$*c6RIJ̅^8ZkLF ;#6@Ë<3 V4bO=CMAZ?I+d)XF;. #R0H#daN=cRɬyp"4ܒ+ :,>ď;(&1!C:83)>k"Ij5-b,֨SAPc2J.; Oa㨒=3hNY)hE v4N:! %";%+bba ++1+ JK01=BVvkB!iȎ kPZ ӗpE6fъW$ ԓFuc't#` iH1)@\E(P 8`B")~Y5$b 9qg.@!19!)hD0`?A ZBIDJ:N&8C._a &pdSn אa@*p@${n5:,M ֐TKpCQ1&C j 4,10 `  æ0yj7 w\t ԚJhv(30q1A)8PB A"f(8,iXX\@`@8.Dk[ VH@9HF"¯(\'@@|P]Cqp j`]d0%ThXLoWp:0V`ZDA@,O</ax3LHΓ-yOL)8 B? M (@<"k8:1;bsPD H)DA C#8 ! ഇEFcRh&2[p-xo(pT u0Y" >8DO_Xz:O4 `E1LшD+GU+* 7a.b%ưh |i ?qY&]2V0ẓhp*<.&QHD wAAqhOv@} !|丅Eo0 - ?~a yA5`d8 t#R0@]#@L0N8v@AG hw(N0: 2@XwAs;knopflerfish-osgi-5.1.0/docs/images/desktop_drop_view.gif0000644000175000017500000015511012346515440022570 0ustar felixfelixGIF89a1#%- .G!9B+)&N* )9J+X^BGLF6ZjWl_e_Xf{v^({NsZ{Zskcusm|yysHlZW3?Z[{sskkwookoskZskr{{{ZRkƵRk!_:k=}7a_Ul됚{튻ʐafuw؈ƌŽƔΐƌʐΌ̌ΔƌƥΠ֜男ù̷ν˻V `3{( 16gBqJ~R{J{Z^ވk䙃91BuТH*4(ӧNj*դVJzi׬X lY9{ƍTX+/\݋]v,8p_„^>n8ʓ/K6fϝ-1g1 $j#\2ʼ2. #-|39:s<sCQmʫTSmFj`HCt bAEeTRjo[vx]x]u^T ~w?/.G799❋.9[m9֬.nܬ_Fߞ|;G|C7gߺ[o}؇_}]ehMETH_+P2h@B2_ڴ>Qml3о`U5 W``"A rP|`AY!=xB [3! Q(Bp. c ;sNPCgqS@*kڇE.ϋ[b(F0eL#׈F6эg|c(:f̣=Qp8H#9ϑ 0$&-MN򓛔d' G|) )HfD%)UiXn2%gRkw?/5H &@` YWjP ׾>/lj Ӝ7)sS48N*38өOys?O4'= τ%'AoN4 m(BiNԢ5;˹N4iJQ s,ŧKe SԦ/=)Niә47iLӠT6'?JΞsL==ЎTM*AJUϣQgVV*P%UvnLx<׼O_aW֮rX& ɁhR´oEn~g\yٴ5"lSéYѪմ$mjmQԂ=gk՚vgiY{NЪ6íoavĽqakNEֹ9+V7Хtj׺nwK^Moyѻx;Wo~{ 0,N03?!0TAlK2aC0iGG8Hg#b8F?NX T@0h1iHr_s'{%L&o^*KyVβ}<-;|e-w5t׼1Gmse0KdͼIcʞ}AtC%H ۀT,R ժfu_YCxD)bG0G Ŧ@PվE[.״mJm \r{fWMtǵ%5owk#o{qev4pE7|8'W\1qFwUrCsZ/;]i>)=zC+0X8h3i3<& ClpD)@AlG0NčA?0؟0h7ܶ*? vfZSO~kl.xV~Oxv_wǶ>w<n՞%lAr;7ngS՛=A*{}핻{~l}hFI _r5=Q?Tk>UïOwTGrsV_ J4M0ӯ?L3 Շ}'#L-3vgPfme{xnwZZyyep7Pzv[-ygyǁȂWy(xx*8ZŃ[ ŁwwZ%FQHwOLVEowT؄􄊗QxE8[eElGg[gh[|wexF.e6lcz؆%yh|Xy tsWp~6MˤXgWPWPb8@l2Vcl?B`w6Ev @ z0  kv{Z 0IcxаgRȋ6XW`PW?hW ??o`O(Qeō8UV3hLx'y7Wb1ܦyƵ$NH\8YX9U!SfɑiR7 ɃVx ŃHy ُ5wXz^uP&T09U4U69>Vjv~&5L1,+tWv,0kÉf1Uc#`x#? Pp 0p`vIP\@@ pIPQvYTxT$ Ap @ @n P PV@ 9\"ōp6Ԑ)ِؒɐ2(&xPX>y_pHeyY}R^yiUEh\9 -ywؙi9(h؃9xpx[q5\jw9UiSaj?Hpb('&ub`uvXX#ua-@pH İM Pm A vKE pq gnS5PwEJnh ' $PR !@7 !YNEyN|Pb ?xQvwkXP }w Y圮wTג•Z+ YI[:ꪲ(sȩwyYyG:Z*?/kDY2ڔ6kaGb*apl/VWŢ,JdN8 p 0 HED @ uZsu ``@ oހR౩а` 0 "$K a&kWM)5np HE?;$M`pvUHހOH)ۍ b` jl۶npr;t[v{xz|۷~;[jsUa2@Z2pvR`b#ZklW0-@b5`'Dpxp @ bpd&  & 0*Egp p`IDp B=`P  @`:L i_SU1; $p)TtYZ  K Zy֐ ݻh&|(*,.0',UPDɺ32PWpjK 00@ *tYfx p P5 kW 0%Iװ EP p +Tٻ `:~ P`Ȃy 8'`hHp oW@ u 7 Ț +\!Pțp sy  ׀7@vyyܱRAEFHZ5ؼEی^<|tZ欶M_3nkmlk ,}- ~\5\R3M(v `057pjKw5ODm HpĀ ~0 e5 _p ( ԒiYkuetQ Q_ gO-PT@svMA+<@ \ps-N$@WSQ`N e౟pLS @cmAA;b7ڨ-; ;:Mt^v~xz|~r5j*zXm0k^O~''`l(*c  a#7`7j  (7z0l (% P +շ~T foctN l`PpB 0Pq Bv blMH` [-5k0\ .o= zP Pc   ~ĎʞozC7!? _!o%$'O024?6_8:<>@BD?F_HJLk+0MJ`v%;lX+P/ї{;Yj-*֠:D5 `m 8M 4kpwzp ?P `X9 Q{0Nt 9ؒm p4 @s2P `s ʒ ػj2mQK| Y}ޮ Iu m* O <2?_?_Oo8#Xp 'LȠAߚ5LȐQfo#!J40D! D  FJ `F 0h&Pp5n~HuTx|ÏLbB7nBH5l:Sƕ vB[uS'Du+Th\`߸V uX(G&|a a iNK,Zlo'^qɕ/gsO^uٵowŏ.E8(R-\Fr1t3d\SW}ue`P͐io\{w^H䩻RyQ~/~x+}o>{7Q@PAGXX"+!ubXЅ5 uB6P2"q8DЇEiDNl"+pbE0vgcTbxF3kTcF7scxG;qxD" HB1$>QK $vO pHD29ALz𒚤d&=Ov$e(9yJOTe'YJX򕥜e,MyKR(mYKP/1cӗ,2U*3̄f3LiFٴ6L⠒9'9rӜd':ݹwSg=OzӞ'>ShAPt'$oH!}$D%* vP3 ``r%iGMZRT)eJ]RT1LmZST9N}St?%jPZTUIeRҡQTjRfRVUrU_VJV^UkZֳUp]k\:Ԏ4'GQ@v`A2aX>㰊EbXFle){Yflg9YφmiI{̚Vej]ZؾVmjYV-ow2ַ.q[\WM.s\F5tKR׳Mpk5p0fR8j{٦Uo{^׽o}{_W,%رF,kd Xee7p+< X‘_;A;),9 +e`e]k83NkL8ݱ{ c7&rq,d#?l"?YGN2l+Q c'93L1+S,f6^VsLc12l>e3mhBڿn,h:ѓtmiDczє..'03>mjw6iKŎԟǨGmԱ>C k*CϷ6SdȚ>,=X;~v Z7nloC;QMmY؟>vMs{ۤnb{~F\k l3w}3| 6k[^qZzo89lS"uʭp\^ۼ9qBG·s":җmGSz-8ī.ՉKpo+d]#_g:۱a}[]pu{u/^`Wz-XFo {P|yƊ{d^]ҷݸ=Q77UoW=) N?;OgHpq7_;G}';}?_ޗO +@5 =˻r۷Ld;lB[6=^#;7s#5#3+4K5.,/={Bi/23A Bu9L:b;'L,3d> >$:: ęC@B*?=b$B\C:JTH3%4cCg:F\+C[AS%E<#87@W1[LDRK8JE2F;c=CGcAYЃNhDaC?d,:G:5NCC=SD܄4DMM,{BQ 1 LwAtj,%E+ESL$O4eNw=S_LWc"|SWS F`JDOa;E CQWŭ#9yRøF͠ZlȄuXs^EWg%l<ًL_-.KT=:GX MɜaGȍR;KnΠ(6r4TA:OtGDǫR)5UDBcҋE]+Yҝ@,Y TRF>P3@{m[uMc6ŦϢ5tɼEYMӯ,4RPRn[Zs1V>&L-XLTqݼMXbPe={\#֦FFdEÝ75B-]5,jdMވ;R֍B]BC$1S,gM OJ-ťJTL[_D=Z>=Eݲ ߆}\`}U]\TuTfݗR@=Vaf;$V[r\J0w -bLͭNH ].UDm{IY޳&5"е C}C `*5݇YMY#9apF%U9eJ ndNÍD=5'`9.;IGs5-ͫC>HBf ܯ2$f;W}U) bmTX0 ]LE^`13cUTEe`Էcǥen=Ί=G7=- &b*VK%,M.UGWQ%UYZ`2u_t<$P;QR2_8$N,<(E{nDlLuX [dgZ_V^`*YV]]#VjmejKH[%{j%]pi&MF=M4eMܳ[J>U>i+^eM,-Sfz6^vԢ.߲TQ$ݥ%VL3q:|B^KPPva@FA.iwS] ]jW[a}F }Z6];^tLlm͞``v>G:$hCJي -m^0۬8LZM抝=>YR>U=Nֲ,ېX˿Ījtd>fpA\EDo ZŽncƯƦUKY?Vj8UYiTa4l%lbߦlA.:f,C\l%{`dU5:̀] )D]Wnؽ6HwǾthihd] bU΅fY|g[kn̓ -n/Tvy`VWl^ G$&Ym]/hSk<`rt>fv0Ҙ,mb׿qSi uMMew\gMm8Vlan?Nmf#UKțu^#nԌ~c|4$7Lg)X$Xxxxx'y/y7oyWyGyygy7zOyxyzwWz_z_zzzzygzzOy'/{zw_{{{{zG{{jX8ʧ|̧|||_/}'o9·}|ڷֿ}}w}ݯ}W?}?7~g?~G~ח|TI~ /?O_og>-nƖeϒ ,H2LÈ'\("E3F܈cF):DJArd*KLYK+gl)I9cy&OAii3gѡ:Q"ũT)ӟ>6-*5jլB:KPqٲSAUmNv԰) $GeN&N`A "^7`{`-" ϐ298҄-&c˦W_,Еmf-0ͩGW2Ïދy1qƙA..}v=vڻ^\xlL]>VLǿ? 8 x * : J89f+؅ ]en &"C%^A)g(Aʡ]Hc_3gB?c{Ex#CJf#MZybsWXcBM$gё|IA!m&q9'uƹG y깧z@suW^1gw-tfI'pKФ ^ee&Q1娬Fݧؐ1*`.۫5Jwn%":铦Fjg){~i8b o%g'z-;-! 骋n 0rx)Mc"`ņ*j$DҢm QiP`ƒ1dQze(dVL+sId1\1Bh,-kJ#B b8-ûY&A =4Em ȱ4M!Jz=#膅 0G*y1V*E(e"[ 9_¶v2stDcw^?%QByvy)R6Yb=3kj}:ꩫI;:ʕa5M~'u+4_Yln-xDŜ7݌{h܏7kY .ɣmڇ,8fʾ9n|ܠq@f2)b$ ᘽ BȡM !0o4#{ p=-ktUUQjPCÒ`JYK +5T}[Wr\%J>1,6(b@"53&x^$TsܴS$䔏zhlf$ ~f3dHp s@?~G"` n*!}GPݥ[7!?eOAÛ#|Bsl"^ܲJQZ;̻0p\`? ^,#BU$r^׽8 fg쁴4'>1*"Vs0EΎqW-g76HуOS|wLUT ރWp2B*C1sD)o&+ h ϝ |g{F-Au-ЏD': H{yRScK}?t"V^Ӫ-)fT0hQR$ &y y:kފ-nHYOVP]e)KVCdhEQks R!(L`go<{0 - }~W2宯l,q5Q@j:Wu1zG=|dV,DIh^s&4! xFdݰ5u&t˚Q '[o$:fN Ah<׹".kG*<˦$zn;-9;n:?#$hPSK,&= H}\H8- 롧Z @Cv*5m"i"tQ~k]1x3z@,V>9l7IK]֍"zD9s|Lw{߂`{?%Ԃ0$A 8~0DmvBiXwAN(WO3|yQ5eE )pvtml",?4P!yܳ5P۬h`8JMQ[\W.zY]MBWP R'9^䀿_iݹ_"5T$ I/t Dª@ `c6NB)C35P1~M3 .>p,P B Œ)Eو4IT6y _!R0 b<ʾ솊@m`yeaN#5 0aIA%PJT+>[T"(IȈQ5A;RʍZi5`=5p40P54;N ґץ<%O&AmM>YʓE1ӛysؾ5[ܱ]Ec܃U#N_@1ZOBMVĝQv#]v+A#Re#1WO Q\W+A\Y^1"Y r7$A̜ 8R͐`H%_ Y4' MQh,%(EP,%NvgMP!CFA|Y9je2CO]Z!AlB3$-ƙ85C&8 tF't2G .ՔuO r4mJ8E'J&_m@Kd 2~&~'.]#)\d7ΡQRf Hq& 1n%,Jn.fQ6_m{(C1hC1DbC46DC1:>=~ z`8q^vQmLń5~6fԀ Li 7f8V\~SIQMe4D iCXEԱ>2uA9&xĝv'8]*QigsEԆI֓FrK H^)n^v|"&"LV(Fx5[)(Mf͠ gd $'J2! Ʈd LlLv*VW~+I T Ȁ+V I ^*ꍢ+O**Y!Ʈޯ-k&&rꓑ/wF &V1z0P^nk`Ei&!tjCubpֲiKano=FYNl 0 ϰ p 0 00p1'+1/713qIO_^G&h# $貓9q1ϱ11q1i#lz,ZRLc4|T: ʼ-r&g2'o'w2((2))2**2++g,rԲ-2..2//r0.-1'2/337-3G4O35W5_36g6o37w733jJA.C3s39g3:s-C3<3::29+s+223@=r<߳A@-+92#4Dr=#BtBtAg4Fo=ktGsG2EI4HI4JK4LLL4MߴMtM4NNAu-qN-RWqRDR7S?uRS35TWUGT75So5RsuW_5U7T+uRs?3Z225[?5UuV[/U5Ycu[u[_S5RK5\X]C_u^W/b7\;6c?d@64\~_fg?pgc6hchwvifvjgvkhwvl{l6imvn6n˶kn6l6qqvq#q r77s?7m'k?pQ6uvwvw7wwyx7zw3\|ЊJw}[|327w8'+8/7z= e'.n8jxQcrzknxZx8xA 39,QK{x$1 y2oB? )8e?8_9go9w3C2ظ8/9spwГb-~UJEzǑ#B>$ͺK ,D`T':^#7_;#?`WG:c3g:{S:zw:sz::z#yGbZ.|\Mhy~A乞, @Cjl;|;Sf̐;_{;;{{;oŻ{{뻽|˻eH38yv0 Xy)✝fZmJӗ0{)CHѴDԨhBZpOrb <|&  #};}3}+:۠긙~,.Εsf=F_|ϳ.z@OT=^F9LYqL/[ nG ?>g>b'/uye=9׈w|aa u1y>}ۯSI֢3HEN%H$CToMao?;l shךE#(*v@?ijd gd >SG@Lp!-@5,*h:մygN;yhP5ƣJ;iPj\F53 v|װK&39mZkٶuQZБ"ͻrZd,TF5‚Q:=LkDKtX@b%cCW\+全n zOdwwTWƩoM͘4؍ ܴFm?ԳoC/En9v޿vZyG)$MKK0Rd~>f.1"⪪*J,+=S9 pڏ=DH+$G|" ӡ#"Σrk7*ʫ mB"&LjGzd*9裨P%y\J2(Co@5M8O#|L723\j/L&ݖP)$sT菱f 1(jBrO43* ,P U 9V5uZĻ)nX 9£ s#\D2Ui,Bc.՞MNe\pi pq?l϶AxLLsydH)8N֒ZM\u3RE=5 %;k%f:כ&#ɫd< pP ]m\St՜ٜ0:Ӓ9 e4 .`?ѧ}㚔WvzwHBk4Wgx#:-+>?$N{ ivJ<\vZ!D.m -Mf7הL-JpA! 4='5+IA> jbZ|5OwJL@UzoYՐ0'` !ݚ߃?bxkupG"s9rh&Dqsr0r,lłZ B:yE):*2$XY@&) txļ 0Aet_Cj1>% .x^BR ' /G3)Nh?P~ (PG;2'"D-DQT<g*LdT@lm: 6[6ص8N "XG U.!qГr VȬyWR(x26)xXq\GI|6@ T ~P  XGB]׼Ѯ}+FHnp[ ~\0"+ 8mns].$ s{`=@\a]WzK𾷼nu]PWYm/zJw]׿ծ~ Ʈk`zeo Q1I]S>T? F ?ȹ} vz\/&Ӌԧ Y#YPC:J&z((ڶ7 B&i5=#=@ B6 G?ґBI_9iOCҟ5=jSGVO]jVC:կt Ri+_XChC7:Ι(}M7zϥOYOET~s:m^vSJ1MkJSNxc .xll{A @0G\k}MF[v yCz -hA^oz!= y'x\^"D2 b3RW_⏅W!|/?~_}iķc}G?oG#]Z=k$Cdž,  Hz I ),)D:.Pc̨gbB !/a&j !@ AB (`keA  d@ZV@ak .< UO ; {pе<(FRpR80 0^/t좂 `H+fɢ/4"n:!8qa!'Aj/` 1 Q! @  тB "#j]i0`N!\nfEp g`G6fMu\꩒&P*` ia J BJa!! xbpQ1 [ >AMQq Mb)OV|@*/@̱elV c ǘ1 R` xڨq,z"!( s D #am&̜(,i,R--CHX&w'&XR()C317F*E!8E/Oq8|l lzm r *B 5z* /ӂ .3a@<K6 _v'`kũkkwq Ȗ5wRk8T(IbcdQ4imHAvU?VU6fhU{eMwucvW7g?7u_Wu_V]7uowiӢhmwwumvese.~&"lY99 b.S' Uqp#UUM.$@U(! ?piy"XOrz{-L|q&ar3.s-vDsxhixAxdEtOekWe]t_E#_8dc8xkuwE5քqwGfqFVksB*KWTkFJ2K6 k}R_o lTyp&b)f<[nJ~ YA$AH^uypq ׊73$S!: K5w9=XHIwuVfwTOXGvB gAxxtIuCv'~w;8'xyeQ8f9(z1% N3L(#: #Ĉ ʁX(*$ax iEk vQ[ar 9-4p'b=TnGY+9Ey+sOgٕsYwy3ce8wywEyw7s{mw8k ky81q47 qQ) (ȅq$3|.׈D7O 0wiv]UM ]9`\sԕϹ-jM" {0j<󘀅XyB-Uؼyׂ闞װIp&&7N5 \!ЯG ̛Qb`p?'&*&55U st٩wU_X = #>g]Q. PYUBJ_-!&!}TCo<;u ͟C~7q"+RdDgK83gG `:z2ȑ$K<2=Klٳ/” ̝tgО|ڤᲬIz8vm+l֐Q`݅ Y3"u><ɖQ6)i6 gSұڝP˛?>=JR,i+GswЃ;.f_cYf&(Y=&e*J`M`JkVmn%1_ ,] 9DNDYFc!1Q4Q'^-e]v?T]tO)dSAd2HeVRyV %‡"}t8%b>~v& .XX6g#IkgtN'cw!٠Wj[ZU̦RAEG棢&ǣsE1 TQIcTuxC5%u19娺IE)[bB<3~Ev&gb$](z X`؊vWIZlZߥ^oyzQq7KpJBլ`1p?GTHLy rVv]$^_`z!Xez;!g՚gl.҅\B]ҼHbU re8\q"-RZSIdvNTϝIv~Z&^ZP”Xf fڬT-9҇N'8Ig޷%:ѿոhHU3!i>53+,St?U%lĪ2^.+RV?{:{^3c(p̤oWPz7=z; W^6I0<@X ck^?dZ'IGėnKr[a UlYסM8 ( :f2|!bCa0l䈑h$`C|1 NЁԑXv8mƻK8djyZpк'L+E% <cy 9*ɦ6Rt9EGa$L%d$L*x7S%U6Xl%[k_+~RG R!d+GnK'#e0 <"4 2$Ī%em]2&oc~YɂInK-=rh UαJ#3~Ũ2[z%~$.JC1xƈ]GY$P H)i"Kp+C<Ӝttr e4c|4HԞV@RP[hcfY\GÌ"@+59LL=3F'Dxhuθm0 .+^DJVs׫imUˮv? ZkQ=[WvVhU0bo6P{=_߷&oq;Rpx,1tBSWŬlmU ]R tp_1`6+zZ2tTjɦn`ά/ *\)'Jc!+=CBϗu1 a䪔26d) ħa2K%+5Id^[sSQqVy;ֶ?❊\Te4u輫P?q c=&Y̦I-N~73d5e(vt8@vG4eh7{x\QwZ tI d|/ X0p# '8.\]q?_ lӌǽXY>B6⤕OBK;od/q_Vm޶9PXR'lyk|Z:-oc{ٿ.vlOOFeJw~tZ1R{O{p.wǑCp\ݫŶeMdTɴgp/ogaqC=7|ui!e?r4G>iχG6@`L~u*0~gW~7*~"~%8z&~w+ jT5sOӆ@V ?0X>w#x|LR"xȗ"mK>vCjPa$Dkek,87v8-07"[7p^}c&(hhq]~Zh#Qd[sd5E"jw4h2o#ER;R>CQ^&DwF4zg-m4;DQ? P}Zvosbuiz}3"uc}s؁rYWvueG%U*GR]9҈Pr--P6uՌWyuk(#2pq8q츎vziۨyYՇLKဪtXwdo#X~d7!pgr8}rA&9iqؐ'zYt׏K6a̘8aR"8Ux}5X#lvꈑkhr+[WqLyAz(Ց,U8T_):ceiiQk)UWw{Y;4;Bogr$yir q!Hَ`qv(ah"6YyH48ucWaWgq"SyIq(9u2bwiu#\=6{1O#AIOs ]kXo ~'ؔLy 협6&i\wd+j`2dՉ'81"RoYPY\x%I]f8JzHqمߥ2J˖O]WfV,fa*z?jz:yZtOGS{ԟ@ymOxtvR8i߆iwnj82]r{DUyL٘:淁:p*rZ~!Gzj'_g1V`(nyn!y,׃]7 oNK*Pex8&Y HdqFU6nZR ( vYci퓫h*t~4%D"eoG@?6 >ʋXJoD9z Z%֒*0i80||4~cDX7fxtǚ-GCgb'aT)3^wyzi%0xĠ`AuJvIgאG ۱K/td &M[**sX.Hb:: HC.n*jv\CwⶢU.^jp    b3awxkb{yk} "{5# _` _[P~lprK0!*w JwJktnȴ\VSsti[ZKp~|@kL7͛ K0+K[{ݛ 뽔B Z]5 8vkǛn!XmzJ(MLW\úz  D"5l79;=?аOPB_]Bp^F&*L0V§BKjfwL-KRhCD4(JjVJVr2fgL0-H{5z@DL@zL@ ~N~ @LȎ|A~ʢLEPGEZYȏL<ɕ|əɝɡ<ʥ#+wQ%  _Garxj*¬qʍL~P + }@EOPPp~Y@BPFL@Z%ݾFPK <-]%@[h9N|HΓ9;Jyٻ Ő @m [Z\­E S]ApY_֭D@`-CP^^GB0 4e-TmX\`ꢰ"QgⓝaD֙ !EԦ { l0 Ӡ yNJxmq>@`Ӑ y|.Gp㼜 AHCB˒[Y~rN^w{.'gyy*@') tG 0(p0 0%!P%0 ӐH mG`Ȟ.֎€H nH-I|ҭP,YPsEpɾ>~پN%qdeC\D!k¨@0Nd"`P P}0 S=Э4 )-1?59= Ӑ]DуM@`F_B[,n.4o8%>BP:șXZoInLpqs p 9K\ ܆o/"=G@ݍu=F_[K?OXn#~("j9~ e6WHt鼠#_l_|+A -[ ybĉØQF=~$ "TD]z RL5="$"Ey C`ɒe,[ҤMUf$9T>ūTGk!ʕ*m!F*r{8JY2Fጉ?v1q䍂++2!7,GѠ%|7XC8.xJdO 9-cP#Oy@PI5"#易2*)!T,oQ>TM= ̵dB29 /F+!1#;^'`G' )̲IylY6cdqZ#`M5 0øTM5KnR`ǠxyK.̬mB &`!!P(K/( r:- WMxR )CޥC٫^kO,wH^zJod"gW 7i&2H'鮃h(V\h]9HZh])Ap+5ksz&\ SDAHxabeNgOřn=', MA-!b,'s.GBp G\*v/ ݶu3AU9"Ug~PƏ=i>lRM$詧ꍌK/tvO߂89+xA~ |B|IUWg?IBh@'@ƊGGp @H_';f"_n!݄Wޓ7= iN =M\Ɏ7Z?d^GU: ݎVRy^pQ"8A qIpI "MX3qmԎǫ`c'OPX`tO!<9jd/Y-o94oX1dR q,ahVֱr&6$ -NޫµK]{ "5%8-`A V`prի}L-c)^,0mMoS4g)yCuRL| HR0$La79rqp\ s,. W> 3GѦD+k dRK}^l`())!xcAbSꔧ>계jx a>G'|0RbSeOGzv 5ٻNRTG$&P[k`7 [ož7aSF?LЃ9ɺ$e3 =vV&(ϩT'x F>Lk^fYUq nZ n=\_9[*T1< 2Cֵ?Rj4ooʈ&hܐ4C/[R$~BDש#oU{ ס-YqV4//p%C:JW@k& crQϴ*t:a NOjt;ϸ|19/_FfXk${I<<S<ڞU6( %!U!6-n\ܶͲҭ%0?h]oMc؏g֞GE*&u%1-SF]͙s S38.RwzuIQ.۱SnUq\dy7r5)T+r{ьCK޲XFe8'WȺa%:$k]Û4ή>mo}12G{R[r6W%ndYhÌo1JyN#Sۃދa%Ɵ_j<ݶ+Zh(k'ӰEe-|⯇9˵^ESQCqIXa js#O6,g6cD>? ft?}OŤY=wBWnoױY΂"m QkRlDI+oZYY?|}l~2t, "4#̈p8U;g8 8>*!c3<=(ÚCvˇ1C0p)rPk<$>> tV빉[/4 >3mB$:Aړz1AQ=F$òA9:˜>?dVT#3,M+Q"RCT{<ٛq)K bLC75̣&P\*1Y*"CW$r\7@Ō2.I=+GjܨSxC:ȈZ~i6z++xT# DH\Hk8%,337w+JytCG0F G=̗T \ 4#tɪ@G)x'vȞD7y$Gzt+{l8ZY;,;U3%F=`Ed;q=?t=3d/Z%ʯL*UJ K81˽,L[7 $x S,kjnAF#LM KcýD&,Lhᒚ̹=Y3IȠ02 ~)(ңc<î`&CKKTZɂlNLL\"*Aɲ5"*2*PDœ̔&"lP״?CPa/4"f,T,A4AܙZl:ɐz?E|Ǵ\\DM!5sJdKl3͑"L/!W *ט1˝(B+ŢF(D F<(G*%8ȇ~UP.Ba@N%˜,958VUՍ@Op9P1BkD[KBHyHN$<6dJ.RP4gVhՁe̦WH9bPuBG(ssMWtUWuȁwWxz{WvuvWw؀5XuW-X=؅u؆X؇X{׋،W؍؎=Ws؄e{BC֔U)RRYDL <ٜٚٛٙٞYYڡڢ ڠM@=ZMڥ5Z}ڨuکZZڬڭٮmگ ZL;5۳ IMЋMz[}[ۻۼ$[۾ܿܺ \\=\5E\UƅǕ\ʝĵu\}>DY%%HZ (ܤӋs} aܕ]]ڥ]u]^M] ^%]^^܍^^^}[0El5_PYyq )ߺ_M:`_ !`8`66&. M `]M_  (laFaaaa$aa"v!nb..fM&T/u003F4V5f6v789:;<=c<ȱ56A&d_Av+f``GnH_wdLMdNNOeO&PLeSTfRneU~XvYSeVZXdsTT-a&fu &43a͋$h~䤼kc UOt!bfa]BՋ.s `6gtvW㉤M !v]^v~~dpT4Qd_8R-ah6xpxhhhh6FNiVf>i镮iiii6iЍ_NNAfV4\Ozŵ `h-M~=kk6k&kֆ.fkkkk뻎kkl&VN.^FnlƆllk qfEyI* Hp=ȈƆlhkknmnVn6l~nnn6~nnn޶n6o.Y`vj~& Vo|v`@hp9xxp / gv /l go n'n/qqgqV>7o qgfA /B@T"oYm[v[p?`f>gnpk/?ql_qqq'70q1/65s<ލ=Y!"٫g< $Hm9r.tNgs9w<4/u:8Os>_q;WsSsXO3uRpYB$[ `<"_e:r9}NFw xgwH0r~trnNOsPwQqTuU?un]u\owuutw[WuZOw{wz/suobh"?\z!x0"7vѤd8cHdHWX c{[ot-rOWy'/ Oy=ouwy|sg_3snj9jX;`hڇ>>Է?֗>؆w}-CwZ$`MQۼxwl|/nv/w~yqyͿw}oϧ|u0 mk.E.^z%ˑhA(q"Ŋ/b̨ HCa$I&mLr%˔ jApaÇ-o̹eA :)t"-Tb-b`/sϒ/qɮzlɄXpu*9rD\s;-^r-pu50Ë˥ 9dē%,w7wv6/:ԫ 4_ήoonm:6گm^ ok&[ٟYâ`ppc(~(H/r=S$ IO\0~ 4)^{7_} bH^}Af(TW %5TRV\}2k5pWGh3Z_~$i~j1b@e\MeY9i7iBsnlMXWaٙ~ɤn 'W hrsB(s&*gy\ULucuOqQDY<AE|1%E]uaCAJ|8D10aVjGdA ӫjB-vAnBTT R\bI CT@3)uaSZ+"!a"'x!t`#M\*.#@(6SA-` `@5pDl ,Alaq@J|3s+):@`X1XXF;X`ػ+ 5/rdDG: }ZzL2L{X'(f (;QMdKaQc,Fs9!b#؀*,QUGxB C!xDx? -hAP*fM!VhC/2O5pl’%8qI:ER`KFF1@ (< 2aJ=\9(jQN{Dxg1C7g!"I%2/_n5Ӛ )JMS$x `́Epe^iaslق qGq>Ac7 A.y`U UY*:* T[׹5N:ժ^FSW`\ 3tTY\eG;:R[l0/z ZQjCIpzeN4CFNd)#THކ0mK1Ahikx\^u3T oWH*llb -[U}O>{CA=_4fUޖl,vsߨЅ&;ۙӨnkˋfӴ{ixM\8@ 1%3cC<n=w}J`_c8o|{ֺ/:12Y[Vl]XY/V:iյN#{ A=b=*E0d79Bd==݋aQ!T֋}0XTO3*gϛdmOJmo]aL4j5c5 7¡8Zc6bcUp] l:R(R)^%ċEN04`C< B  AF$$\X-YzZH[ [ D&YzbeTc:,C⾨TdQddT"gK4R'IWm^pR@N3zUMRc&V>eV:U7ޟUbJ( u8;>c6 aA[A<MUAg ȀSW,T暰TdlRaRff>ۊvY4Rh (rjRfԛu[u 6YvrdDdWxR̃ :2( $hID*$ƙGܭƋ2k ҳ&)IkV+IJѭӉ墊aLt@+*V xN$Hu!iJ嫔EOI;vjmjVp>g6sj(8*Os2h!Ql-e A 30)@?,ڬȊA✭,^Ά,ОЦΩQ VQ郊&ZtZBE*8lj]-2&%!%iŢ(Ėj8hᏦ#u,ǿE()A0HC<(B6@nNT^$Fn*1()>>1!AY0xVyhrQёliѭlj(imߚoB.Rtq)X*N?un"1`NCp. 0dl`.\/-*E04+WD/`Kl&krOop-&1r61N,suC*mpU)[D>0zb?8+}2D20-3Fs--6/ KX ;L6oCEaO%o9sr O(*.T:9r9n&. 0&3Exn01|fB@A#4DWDAOm+"ae-C+X0I3ItJ+$AKѱuՙ3%4:M3;]'K[(#1)3Ee*3*_( 8ŃY)EK44Aj;TAU_5VU[5VE0 0()]B]\)X3 Ol o2Nw/O#a&,.Pϳ(=+5.Rq@OJ߰$L_Mט_vppO]N'r/:'76(k<;d'V)'aJzojK,pyyK^Z#IV o5i n ?iz$q7r w89+6a/u51Q[=#uEj:fzcxkx6!m]H)os`8q4׸3s J'dWeow]fCuxox+DZ7ָ@֖[08g C7~xǸbv״b[GwPO7u 9[v^t3yUlJh2L ifFa8~#ۋx w;봚ao1hQ˹:6R7Q3 |ʍW`i9{;'>>d L*:m%̆N ߽}sþ߃z?78Ỽy~<叽 2f!._{ؚ掴Q'}{޿O;O׾R^=cn/~|^ B%@7`A&TaCDbE 1fԸcć?&dE' ʕ+U`JIRf*{89tٳT(d:ƓR^jj֮\z,U_ZvkZjۢ:M+ݹZٽ[o߽ T8S-SΌYΜ/K,s婆-wNZ-@Μ5,*hF :^DWH 'ʼngמ<ǐw.rh,UbΗ>iϦ\iF뮙0e.>Tx1k[n[F9FU F[c;IZan#Jm\ZtR<6A}pHLj k$Q|*L;o칿p{gXFa plqWwCrH$դ'Lu3X@i!SI{\Ғ`jx*Մbyc0 (gk QBi]*Ul)p"j3)І7D $X>j䟝H`O %%?ErHb^V(-e47.&0i' F AHbDH&6C t#ɤ*Z(QvD E-?&)QIuqe c*aKYRW W|EDu jFч'ACѤQ8Ke.g- 9fN\$J! 28t1f|4mv1dv /"/9>u^.ISOm6k&!7ivck1Cg2Ts!IW7x180Ѕv`|mTe+4- aZǏg( B hN!~~n40 X,@ˬ66AWH$ѹD .<#@MmkvK>wsxuŕ(v@ ul}ȦV2qh!vr BjL0/7?HM.OHk \kð}뛫BpeH,?P~((t3 P> !h MBht[;υ>=Kwӣ~37'WPiﻤD2|8A6g6T~@c P .|]r}{/G\|ySִ5EDw Δ;P~ӹ<'ʾ],&mA`>@=ă 0'0@&,\(B;Z<ӟ.`}S>ďO . w"Htw؍xb(&h͘nlFKo Ni<(I@( &'o_Pdh lu}Pp p P E%̿X v"t-x@bϸOL(@M " @ OH @0 P1' 2q?1iKqOQ@a1fv% rl))``qa@qW*RM A "& @ @ `R  ̡q 2!R!#("1#7rZd/-()v:~Ć˄YَKL!AA&"@ a cI"0"` *r+ R,2-Ւ-/O a2.o..2/''104p'1Vy:: Yl̋D$!^+5aAa O !&/o@/)\6A6i36!7w7S!#OS锓99:uRNJ'\r:@lLd46+K. mƠB J^`ma! 3p8#E<91/.*`4B'B/4C7C?4DGDDsEEFe[(&^/6s>1?)֑@7N05(  A B@ * A0!/&q&` EQ 3F/HM NNOOKOPP4<Q!URRP>a2gjEPsSBƔL oЄ .6a@<*(쓪Ҏ'dm1Є .aJ@hl{&Z(u`k@_9rXN 6I.ṁ ٚ-y1ٞyy=-Suі&`(~M 5ќN!a)t!/#NZN֥ashڦ7uZ$)u/6c5mʣ We@ u8Yz~ڬɬ/DU'ӖR)JMݫtwP  $o8{;?;:E;]{z%foٸ}k xDpW![@A̫ ZیMA!ۃ!5;ᄰ)Z b1 F;bYgho?;XaiHg$;Xĩ+ꍤ}>.;*re`yqkAMX@"ɨĽ7&z*Q,>v_+zTd.R־U>&+c޸<L6(}||g>J>&uۛD X3 );K+ihv$Z#[ -{ciݞfJ"͖Edi&:<2LP>pff0RWrǃgܧa3@4_t>S#_YZf&?()lȊ'^MM܌S%\~ط1x kb!۬~I o LXÇ#JHCjȱlj 1dɑ1nlhGrJR⟊%{_2&ʔСB=K*U˫Xjʵׯ`Ê\%șE 0AGV=I/ʅ;VHS&w1c|3^YX`ɕ381~#~/ɗd޴=UH!lQ{lwm:3+_μ]>CK5n႑BW?C8iϒ .]/y1{ؽɠG5XMQ(kI' S%R]rBv`*aewu}}a XWVM6ĤOQٔT""z✌6@u3jg#f馜vJQj34!P lfڪp R`魸tdbGvݩkleyF8K䓓u8#heSTufih\ukr *MQ'RmPKP ekߘ+ w85jRJ+qL- s)Xn(2XIX( PRFRC!,,L7tLp, 5 +?H!n6qdw((iul{)p(*p)۵RoK{܄LZHl7n)ڨ`WN )pEԴUT 鞎|tވ;:J<ē<ӏ>>3Jy>*+qAlZ(M/v24~rC-#O[8"2Po dCf6XX"_su$>J(U훒dEzfk_WD hxXx93ŔStb0RZ# GFB& \ x1`d&*;Hp\47{*X?.l6`@ ' y<g)ʑ$`v=Et#BԾ'NOWPt! ^`Fc.0)"BnQiLa:S4U5|MA>!"<*'x ^1='BY.#@(`aSA-` `jTApuC^Yַ5HώxDQ KmOD}|l Yn7rmnv{Voz7u(ƪ. AG/ ~.i {A @0ǰyvQ7Ax2&8A Z(nqkmGtǻݳwE[ )][ %"t Fu%8C?1xHx Z*̋EOzӣ^gd{;-q^t OO;fd%u)# {/~&J+l5 h-3 V>{!@ 7 0 ʐx{GXS` ȀhCQfXaH1!rINc<†jH}n8:k(o؆t(pxqgPOt0~]EQV[0Vl(0 X3 cP!%P/0 30  I XrH`<ȉhhC'e< EƒPʸx،(ȌXHȄ'(ר xو希`x ਌xHHxX^d\< [h ;L!/y8}vH)>/kpm(ه"wH4hpiF`YpY X`xҵ)@N0d"`P P}0 6pd2 B9EyKٔO%0UyYs?u]I [v"#鰀jI>LPw?ZYh5)'&~x0,ĀPpP@ P'R  :˳> BKF+E- V{X+ -z7t<07LjeKjj;ݚ 㐶3-v۶S@lxzbX^8b( 44(2Q~H~sY pOPpA06xG`ZB@  M0OpvBťc\Ɨpi1ES[7!aKJΰz\G~@<%7BK7+ɨp@pW<1D,M܀0 @/(\p\<ý{,Up>O|<ȳݿ!lҊ' +қҥ p4,]ӈmҊ˿鸓Xʼ}/E "^=`Gbܭ?-c^D-D1LeiY0Crr0 H /Љh<u"'(n蛓!<^R5OI+m'ӦѾ=ܩ^.N>>ˠٰ㥽77E]M-۾^گ*;@-^(PF yk=M-)ޣ@#K:#"6ٍ1Q"+K]E{~]UB|  ` `ur' /Ep,,K7 @`P0®@4/1;5Q0._A P_BOQ@85M0AOG46_3eh/[O^v)BT~Yҧ{}3:R͜#BX-kxmoeT@)Kz^79iA2 IL Ls|~I jrnQ҄]oOd_5ɯ/ο]?4P"tu!yٲg*[Pa2qF|`Ar n<a2r16ر E;1!GOrTJ ]RƐɑE 0A?QNZU!RD!Cd9O>iծeۖ-1$MN! _m]4(5J )" #P&CK*&@H,2qiBE]TlG L̪H$b4J ZeJ,wض.m /Ӕ7EQK!!~/UdA;"DJ [ b N9i 6j^:["@l8ɓTH:V^¯'zw}zzge|4a(C(!f.J rߡ~//_'~X@9P\'7 BP6Az0#AM H$:s٧^>A" 8&e*$UPS 3& &T eOPcx)WEbh hpF4Qi:űAsc}hG}V&޲h٨PTU^UVjVUcjYjVUie+Zխrk\:׶޵x^W5*\ {X*5,bXƖuV';Yf6^,gY~ֳlhJǦ6--e[Z̲VleU ږꭌV%`;7Ensk27ΕnuYڶU-û+^AUxH/}Ż^zw-w^U x f}V 8}a ` 7X*_7#^5L`&x0\Xp4LJqNx,? d`c!E>+R~2-S|d-C9]\e3oi3f+9qvL:{{&2URzFJAcR~VGCB_Zё4>R:ԗA'?5Wݟ!5G[ۚ!޵7*^n־NP7Zka#عN6ml`谛 i_[گ6mg[vl񴁑Rulf;vUf3zsvAMia[iQ^~T1Mvû.x }'ԝ,0 ^Jܔ$dQtCАTO0ϗN1m0voRH8}Ƌd5mt*qMFeZaHmIK b~">b]QOرSY=&+[LeWfU\]̕d׶ՖtO5c4OeG[ [/Y-X1·=ٍMoYT`CvfUMرmmk^mEkfmܻخmjmk?W)a9g:aid(çCmK=LjtUi(bL=vKn@tjMYQ5djU KU=&b6@V9Ek1[o7a.hNdcwisdwptci6̲p^&c^mg7T n,x6v)Twq f~^Ks6gYtMeXu[|W\W#~$[_UfN%nTkvbkV'OHL1YxfH%j!7Dܾ].,o8wfP2Z:psWn:f&'e31q2w6/H.i$X$LS3][N\ΈMI^NL>n۾m6EV Z60nIOcv!WucnEdse,pj"vn6nwmq/vsOȭtUwwѩVww %rz }s|m~umpxKf/xMtOx~mxGx8 h * : B8Fx!Z!z! V\W@9䠨b+",ʘb/h#5x9A8$D Y$G*i$I6QB9UJi%Wj%Xz]9ey&h&vᆜsIxڙ}瞁9J(衍2袑*:VJ)Z饝r馡j:J*ꩭꪱ:J+ښ뭽>Nj1f{",:,J;-Z{-j-z-;.{.骻. ,+/󲠂l/| # 3o ,l?0#L|\qw,-or44=38g\3C}4ME;ݲ#C]WkMV{=F<6QC\mml=7u}7y7}7 >8~8+8;8K>9v@;knopflerfish-osgi-5.1.0/docs/images/shortfadeout_20px.png0000644000175000017500000000021712346515440022435 0ustar felixfelixPNG  IHDR pHYs  AIDAT81 0CQSurH{I0#𑙦I<"t\U:ܪ @o\Yo v5%qIENDB`knopflerfish-osgi-5.1.0/docs/images/dalvik_httproot.png0000644000175000017500000027574112346515440022312 0ustar felixfelixPNG  IHDRXx?e siCCPICC ProfilexՖgT'a9$!KL 30q2k@D+ QQ ,*fdPŀꏻ[To}uu]PA",@?UX?x rlN) k0;5OsS8@t7g9a*I{3R(#(K \<ϼEEn[ tAcz Pl!Tgsxh,|n>X6'%R~o9l7^|t%`׸A";k9$%kI#7_IqٮK,H\ق ZQ~K#t\bAgǺ-qt۷0n vx<Ǘ/#2A`Jp'D-1EB?a0C#jmD.1xJM!ΐIZ$;R0)TJj ]%=!#ɪdkrr9\J>IN"HPt).U4NJ JjRTNj MP%$R!$/Z(!$F4[Dm 1[lX9bS4qq$oI%4%$y%H ͅơm]H$$Y񒅒'${$'$̥B2*.H &EO?K+J;IGKonq)i'Y!& GYFNWn\ArS`]@ =eW'JJJJƕiqʗ_2NDF)1⩒Rң2EQIV֡6^HԈدѥ1MYsLKFUD]}WI9ӫ ZVփ,c (NCtC-͆ԍ"u}50N4>bDdI[S]Si]3&7zX,|-YtX|Z6X[[EZUZgJ2;׭֛۬?Xڤڜ62eˎ,ScU 3#tPq`;T;aޣ>Kaձ&6xuzS˽}Z}a_/߽O4~iV@r+4  :!9xW퐴PUuaaEa+VlXq+\.<.%q4bj}+GVY_5Zkuk$Vt-{HldXY?=Ŋps^qh1o/o _0l/yR-<NiIDMMwvOiC3B3Ngg3tgfg#G%gs UQ;6m4[9a[my5lkkb^nO? ovgq?l7^kfqaIΎRΘ=,w܍=aOmxQv^߽MŌQb^rh?iRҖ2e*++*WN?xCAGUSfua/[QGkkk;)UקՏ_u뉖FzcIp2#8}4t3gig s^:Zm[Ϟ7<_ӦVqA®y.e_jO\]Xʊ+w;w\z+]N]]oasM[-a˞V[z{[]w|εxpcyhq쓂bOK)L|XsљYl/_>K/#P_LY {ppB%5; yyKoU[J@!jM>ͽS ́/GPE>cn3Լla&C pHYs   IDATx]Gu?~vMZUEr66&Ԁ! BB ! -T0nrozV]ݕ9ww۷퍴wfN3s73ݦkYv)~#$ǎI_9ϒrQ!m'GG&̜!v쒖̳Ζ1cHwAٸq45eFjx_4F?24 {c"Ӻ@{@MIrL2E:bN8*.--c?(CG]zeLkt|9͘cPy:pYzvƭ; 4{4sA:6|L@)cƴ^ٰawNP!ݐٷ_5U9m:ѐxAQo<X.ؑ#rCJGk ab۽v|m,S=Kv#Yʞ_)Kپ}%s pMcL- YH 4<L Zd5keڜ%2a\<}m94(wu'˙;'[ntgɤq{d|W-q2SZ;vTֶ6=$uvȎ;eԩ"r0+P0r֚'5[˒ò|ӦNi'zBZ,L#hA =UCw˼s9Cھw8]xrwJ9t%2c:>˻e"h ܮ3e'9ҊO}2vXױH͜9SzzzO:;;/4M6l&^.gere,3K6{BZmY/}2+g;9y2wP-}R9eblo=VJ؉VCJ &ye`pP7kd۽XqƔ dshH740LAֱnz2ٱ[cۉTۦۅt& #nhxWt\ɘrmwY)+νH_~}r֙ ϓUVK^ٺ^4KPڽOA]ҳm'ַs>$'P6o['O=1( -Yy2ibriu34Q.\ٿ{j~r-!砜~Ri~?){A}YcMtRٱGL.&БF+?B hx灖Al>L9]˗D=+,#0?Hl9ܶBʱNieuX3WM'?d1qۂ qix<4j܎ۅsJۤ=gm.9唅z~jwlߵGN>L*wV߁쑅+1rmɴ]2} oDn2s>La7R&AADxan 1/؊-ɓe!}vX b˰iL+>Q7glY<8 !k|D7CP?΅@ hakCd֌<498&ADOݴ^-%㧴=v4e*LDae8N*Ӂd7VKVhрg>8uL7Vv.}~fx@+ o߁9瞦u#XjA9xڰxHD uqE,ØpٷxMG $qNLGs'նaA0):ёqJ{qixၧၖ-[(?h1 sy09a*j8?!h::,81555&=լ8'>S蜃z 5'Zyz 8ϤL$EҒisNhx@Y9)2Bjbp op'&ZD٘#၆[X5斧͆x?H 4<@ 4<@'-tD6$5<@ 4<@CR>h၆hx၆8hX'ԝ a 4<@ 4<~ᄆhx၆hxFubِ@ 4<@ U G4pN@ 4<@q'bF Bhp 4<@ 4kN_V6*eJR8.4{zd)Hr =yݸLk(.|$L)2ʒ2Z9Ӽ霦;,wZx?PG롭S;:;18gIi9\h[F2J_ĕH:eTU#-:9WeJ QBrh HI XZN^J_E%5'kyL yjGnC=wM^gr)  dZ.Cgj<)߱i36<|@Y'*(fݷAU&^s:pi5eu9c4׺,4Z>pňfCFs,Y6ECm6 L$cC]5czc@f\&/s^tC; @PH Y!L{er\1@ Tʯiݕ/q<w44>n2qjxe.ǁa۬YYh繜d{=j%y?xn>:.B:$&|FxA%ynrMB(8eZ`178ss>W8*̜4/b)R̮ev8O iu[Y+26W2ztOm)pވFigPAoE:&#IjQ{9LoXJ 㺨"HeFjX㸹?J,k3KM_jLҢt6JKmV9., ɫ#{L)}j^wtD앾Ce$.'pZr (hUC!Uj-a)m yyqˎi8Sr:sKney4w\x/{Xyhj"}I"W5|1Pw+qi4hhqK9^ +P89AٰNS $ u#BcaiDII)_QQ@XP-%U298/*eWvcWB=)D+o˯1xyEֲ(23#(r5mF$*-*2CQGDO &vf*]7v '0xX12d&>+VFTP[3x3B`])DdvS,VDYa;,WU!#rS,-w@l?V:;j?kpu,@0W]UCj(s8UXd֝D[2>hC=/u\1Ivn%yιp= LͭHBɊȓ_u tE0'FBڡ8_L8)1u,TݢdYD5JRZeFO*VxC'I5 th1-0i'UE;1ʪHeˁ>Q$H"KD;PeVhY@}(Z_4Vy Rm 5,F1'1cZdɲm.lN|h? ̓ :4~TWExx"]]aim0m'50-pSOtyN.Zv9iHxz:MΓrqTQIM{iYƲ;rkH\S._F[>ty-&m IW¢U@\_jp1Y%):lChV9Eɉ]*'演 f4z#G ^Gi9@UZs%(vY>Ic)f#'ꫥjuXb qa)ٍ\(ov>¸L\5 g*+0g XK>AxLDdxRRǔmpP2)7{"3#/,W"Y+[nrmnR:]~ǀoj+aY՚_mQzWI)GVi}lyj-Ӥ8/;;y ?shPҔجc竖SB5\gfב 8`."4rCň$.DB7HܮP sM)Y9ޤ󠑣7Dd2Sßi.9B'ru ^Ѯ`%Dܶ(e?/vSl[I2Ry3h99q@ߍ쒃ȕW>K^WXD j D`S9^yC*0=o3Ncvlbon9q(Q<]b`r(LsϷC~FyBc)VVH0 ! &-@(~0}R&œT8&0&o Z(mQR|b9C-0{j%KV":rڍQ0̃@"ڭIIS;,x2ݻ#.(ݺ =f0oDS3Bc&DΦeAmץtaS030arg!iNI f}dҔIpfRY<ÿ#C1csArF[.hL hؐmKCzg9la@>P׎0tIAYuOD<>zMM؞c2~80aL?1F+qh@MvG8i29NZGh`^Dk RR|arvy=Y_RR=FZcT-BF#qj]e F=OIVS/Ѡ\ıxNxqܵrltBdT:f8u:UenDxQnXHˈ)Iv/Zqm 1'<}ޮϽl3kR,{lc +D((rX:!J2k%YP-S&Ov xMNVsUϹ?XNW=/q6\EGQIpb:C?Fzy2yD "/ -xw)?;wE'o} JܵK9,ԧ>'6n;.y+o\|3={><[bNOKO('!`܇7g>Y93-j|řX'Xce8ƑvS̸ՅTΘ1An՜'!ȃΝt2?E@7}lL?UCh.2u 2 okkȵbE{i8辯Wfc7H% qeb=婅KXEb(⼞xq̫ܻYG_̝UiH|yND0hM:i9(x3m(:繮kk qjHQ#zZH2y2\-O]L<̥s\sRSyJ붤::>tk3nGf-Gb{)2T <DŽl+9T8zNEۜ3by̲kkˈ4PlUm("|}W SaF U;oEUWeqU?3t*S䎤*gt:iLƪi'/w ly.[bu+>/_\+|رS6m('>IqEqM떯|2ed W<29S`S䬳QՕ~{ҋsE/je/;4(EK?yҗ\q3Ε؎ gd[nяo~\uՕrʻdS[2nG&KC۸~PV8Cn6l'۶m /6*[_>a9Sn`&8D?0##PF̀ Aj'z A!#[c4a|ݏoo姀)SIu%p"O?UX;+r:.׆`wc[ ()#%t8>ͿL\i<$YwI/> m)ӨFL~FP^P7:o;-+Yk2<9s~pt՜:2!9`#'G*:Ȩ\O<2Har l}`[)/ g~OhKykЪJ5ڔ%|T@U k&rbm6MJz re!9Mct Kth^gyG{B5gӑ|&^^oQ3sʕ~_j1>{!z(j@QWE4zp%Z ?Տ˼f!rHWB_}<ú|X}f b֮]'/| UsdUQW=* > O.B`rb\}պr2q$nvC'ϻ`]ٲeX&/k(wyI(}'N>dy^)\r1Ζ_ N>E%޽Wj`@lÆ l綾^7͒%޽{t$ci\%:_Xdyk䓐oF@yn+r)?phq,R׬[+g}tvtʪU5&#*FN8o6ֶ{u{gĸ҉ݓdɒ%:X9`auUftO<]Ҍ@Ç+Y܎e soDhIt (HnRXVT#Jk9$L)N%U!UsTg-0!)=QrpS$tO=Th"HFyTau[]aeU/ y.ZEe j1PILI=,sXse2кDJ2.>wT_Z}XsN? ˨-M?u >#cұLKe.F̻F 8MԃF+I#KF1I)TFA5$L+47Q `rXy;#H|758(څlݢapM<ʔR-qV3p?ŖUT{voA5n=2+O &;}w }JJg r "NQ93qg:$w3vx VzL~a zjٻ%?flXiy}fyū˯Tlޤ_mr $|7oѕ#8J8D|!>mlkrk$4"mpX1f@vmy'5ؚ͝7WWh7ϭ1SЭ&l-Ŷf|/a44wQ˖%i-y=D|{Ryqsh.OmkN$siRGqd ,R ֥;$.&N5kgK^ vg~p^"`eøY[*ZaץVy<ܽGY9:OC1K.dNi\ )-)$DMy#]O*7Ak[pX?8αGET'HeJၴCK`NIp_ȍC1a̹Rjp, !6 hfXc8NA NI`9R胂it E/z>:[\srwqn/vodLjuX`gٰ/X[X=ͩݲxoA &Vc7"/yU+;?pSZ}X/\rnÊ93y&8~mrW-?|;7ah.clkMԕ!-];wj@rEla|i zk+?ɏ/yni}P3;qp{+ޕ+;OXBv?n]zGez>V#M7Y..G28yGN9TևA HSpsl.ysa{(%Jb*L{Ƈ;p[u= K'Vzv' ,WƏCtV<,6o۲MN=}tw+ʜ9uۣ'6SZۚބ,G:W#]E#&Wf(0G)cRex^V+&,Fe"ADN9"Hd(YRGO)Y (5mik)ݙ!(5.ji,WxrBK !9 ֽʋ2,)^[ֆT֠A#~}R.d*ƄB-(_ڎ0~I!%IdNeP1GLQRF.!hGS3 L{ЮlbE:E xl>V^ [(񦦷r[o8=U:/ЇF7- =cGSD0&Exe2q$|+o`0%+ν@͙I+,@v8o8 }d>SV{C@2F'?Eysg=xcu zv|`ݯ[ hW[/գ[v 7mڌmfo @mۤ@\v%_/zUܹs45s<}K.H6n${DW[5#;?Jr+æ[$ʒ}) -WظU؏|@1 w [~=ink?yVf͚%,E6WؖÃ˟>V+(,=:%&{=NyMO:<% <J'o*e(kuO>eS&z1@#|%E,]8hS5V^M((򼜺RBqMs^o8«YfGexNz so Y"}!9HUFy EvCov9lޒ6q6r ? w2`?5Epz.ss~U(;\z?Xq `u1ZL|U we:*,B=vܾ҃xvXmx(.ۏjl1˖MdKu~lguEm8u~oժqPblGb%#x[wDN:i&sϻP;k+><GݵnVY0`o}2}Doۃf!B0r=+7Fl=!NY΂m83a 7<6lmƙ*[7Ni'^D) zM`qS d2/#0~@ pܢ䯹ޮV@ d{;aYV#Ў8T7:dga>S8/QtG.HuCV%j S5HzS=J1ZCH^ WL\ >HQUQ.fANk)4fn[h)Kir򲴝) b9]~  TV"*:&)B؂2emF*j\rULG`q'8c QX,PP,3$QH賝4mm2s-Hlex>hK+8GLBUBX]x.ۯWX6;˯BS䶖wK:32L'A1k4 RmÂ-t0ZS,3e3Xz9 6y F^ʭ2?H"ܼu\| P\M ?d;DߺX` tè[,*,N.RApey<J[k= sђ%82?#كc;i-WQ'& >`ـ,z Wmp䘱$aH9˩+1-*L|;k8 gn\UrӥPdMռK\>8eJ ި Zưc4H[ĪLo%^-`b,KvK4t'Zx D;'mR@s5NeLgX$uGJT/P+&J[ VކVmxq("Hnݰp7ob~l.MSmskHa#.~(Һ|J2IK*=(a-F)Er3tcKEnqv.T6t8(K %4~ *;c,4p7AAȜ,^.t`!5cYUMl&<7hbRExq{őn(VNYr㊹aaE j8t:KztNYp`&5$5a|yG`"P#-kԬfV"R\BV$ Td02YHtODc ZAy1򺮌QUtTQRB}D?&M⟰ IDATr Z q45pƀl(<@&KM..?#5S#.Ia-R&(:֥Zgvbemqg $vD|,Z3"lFIɾ@.bHAurLc$%f$#!Lcp-a,}BV^[`j\}*vT8ԓ5z=oMBZv#I'hz&g &03d&1t(uuup?99g԰Mȟm)Pg%hx=@H/cFQsIiҜdlW֒Kz1` cJVyʦPws*2IPT荱E|Y6yZM\J.ܤT^KpnN'=f_< 49å"oVAE&dFJÅ4>m1pU)&*[UK BQ]9H\My(0Oe|. G>\NJW,ˮNirJ2qwizJ^8M5(1|/| agu:3=F2<<ʹ]<:óƁ*0x||V@e%IQjFF@!'ϙِdž)I䰃fGԤd'uerf p+TG`(ғI?!o`NB@O tA($1/ e06$>u:er~lwݞ;-s,Ur8zG#IHy# Vrq&$Iis*3me rkl37*J>`RI2P'0ͦ-"fDk `@6&-0^\WdWW,H`Vუ1٥L(HWLD`4Fbe®J!(XC?BzN)%g}b+1Uv@Ca4X?\HeDJ[E#0,Y/WtdbS/oЪA ,VU| HY2ɉC `G#9ꃓۄ3fLU̮ZqfVeyr&SJ80-Jyee9 )(Ŗ[<`N3U% }JNrwbvҼ/ H\A[ PicZlHQ`oO\Jx=ƁrQ|jz: )}\Fmq Y0EYT)/X$:DI%/ LRV( >U?V>R,+^l[\]0#$W>] ]9i@.7G7δV&kX&WͬqI (Z+]?a8"z6Q,R6 i 3J^Gn"]e\he7Y5YWIAȊI'Qbz)ׄ1#StLsiq82 "2g1ț#*hvTyn܁s\mj5$^RsJeǎ!Ki0tm4bI}9 =]):hQwPtRx9Ry)~xtIUr0:JETD,3\-.I-&#GW}LE9%]_ mt0愧uJz"IjTpMB"Uans-r6f ԴqHW*_3Jk ȋ>[g-ʦm9*p)@q(%R*N(gBA>TA:8iQ?ہ('yTA N9/jW1ƈ}Xef94e@WPfEԡ^~S9 ĸNP;ąPTcCLENqx`,'i*嬁^&Qy2 $e8xOeTl551Q5IPSxꆁ54><"}PB?N+"{Q{r*@8A>WpQTd2Szkym5b˙$Jm>NY /ęJ*Ey''[a* |P/=bBJl>4)(44h\V:M#q5Ņsw5-)({lJ-3lm>&e$l5*>RiyCӆ`l i|R{ƛMBuజ 2eb!מm7;cF ns.kàrD^WC'[=UYdb?:3UVu^ s.?-9Ui X5K`CsPиeN^KmP kJqL#d¼ H/5Eb܇>u D;iXeV; 3NYʙ^r@;Wa8q*&BU 6 TD)3``NZd?hLB%)/8UْgEQ6Ԧ|9;G{^*Ƶ g)2+ȼyI%5QQfcD rǼ\NaCQilv3.975vK486hi.1 N#YUDŅ/~>X{^ BX`阋]I'U3;v 'əg.{6느F'x;Szp[~&'$>+`v3Sr+媫NO[a`RY':t7+I 6n s 53/{[|K.L2ȑ!(~O;[~1Wh%A[0/X>O ,߾A"HiC=`?DM7|/j}U^&'U `7}Zb]2qjhFȼmPB E TDZq&p@:Dgxדoo9FR@ Iqr~%M̃-Ę?klLFl驆MNeJ|B:NWF6Fl*s;KrwaGp->^Fxe^!י2*_83yZDijFuQ,(B_qG^:yg?]NŢvzmXQwwrYgu;f3( ' \(S}|ǷˌYkcc%>An툥Lp̍WZed㦍mksC?eʔ)xuR2!?~Ô| eбE֮Y/c 1JbΚ&R  :~+_y-^7ʩ*8YAVϡ%A1xw&$W^ue/3vŃ{/}M͟p> QB긴K|7VV4\F>/Ro;'2Aۣ>*;wDP5_ʳLن|k_O^a?iF|ԯx}}߳rLEтbƌro .<H~=2}:>)gxPqp0fo|X>8P_ضSM 3>NȃxWb'^l͗c_t2ۺ[lCg5L< >/nGT!~`ˀxXaL7Crŕ˲eK?y=A.ږGC;M]zC˻Cx$?-P^W ^z띲biWZ//{@^Wȋ_"퓟V9e׼7yGd\zl?lOJe /?w7(+$mY 2aB`V.-V* z"fު3lUIai0;Cm Sl}v@7)N)ΗZV^6ӻ˥塣]Z6P#47-<'f==PNlO(8iIiC1ys较|ټy~>gC>x7anqjAafyK^(ϼ Sϳo3g>S?xMm K<ϹG^JkU% ̟/{޴i|st}Vec:CLel&{b:,]vNW?/O~||AU/ZL. H=becHs=y tx5 ){hB`;V[6m*}57A׿MxPߢ\!b \HZ#*w3y_ε/kˢ ߾Fy;@>O3.{t$ _5Pc~SO=~Yl!x9t!7}=k%O6m9XzƏC;r- u߅*>"Pⴵo6 ${VV.@W3Vفg~zy/>w?< _kY!F3M.Dxk҅ǟx\.9?<ߛ=1a 82Qo"[lߍ 俿M<ʟ{eFu< =غj bBmD06IC;vlqxB9˗,Ã?4MasFO>J?-c\]ٻw/, YSZ :FLd , 6ʝߪO$eyj}j{J6 gy,_~*87PQÃs;˃<$?\|EmvO:XL"]p!| !Ih_ٟ_|[7avFPTU/T y衇OxZzuJ\(fΒN? Aҏw o!V/>~+m+cȫ4Ν3W>,b|b, GZSmc"d=_>@|ڏ\Zy]*`k>ۿeZ/bug`__/!p""$-Xrx. :b*rǺ\AA7!Y!2`nҢCZ(#͍U%U*fQ]oXZIRjn}[zze>:qt,Rӂ8^Ǚ+1R޿Nu}%.Tݸ49ָ0X#Jr0Nceٲe`Oߖ9P=-4#-A]iҤI3ua7g HtHI|cv=gՃ Yt)^7v(>Ùe ֢X*QU}WxUu?<.Yb\z٥˛fgwnV`ߗ>Em٢JU:yEcB%IZ[t[o\ʴCaR&ڜ[̚5M{剧XUcٌs9kPuE`0XHΩx_zy.#.Fq;VwtE,rj"^#]% W׭_KlA'ѶU֥c-җX`ygFGo8p@mޫyp~z]^n7.{L~[ڵB9WKK :L.>]yγt <M*'/;YnO_/l-BgݦL݃3a?X?c7-}+:u"лPf9[կɟbo|nSލoWk钥A׃=q2}GRZ@4nHEYGL,_GTx=1 귨R*?R}4Km][:Fc`z-YI*)-W|:si}?_?* IDAT^p>tXX/+pȚ5ktCa V> gy~{ŊrU®gU~e85$8vr>}gMԭ<\`8ى/D-Bߵ{'y_i$]QZs!x;v,;dy UVkg 0'X=)JQ.$% %bl5`ULԁ~Jdrq"2S֭yOU>jguL ~pwgݶjmPr_ksΑq؝;|s_+D`qTOO=$.Ny-_9s^痾.}sяns/YO~kƌxПo,, `ߺm !|[g\2 RxX.nҨuƛ2s\wu|72[,!5=4] Q஻`u޼я|LSӟg7Ϛ6`t`5sK;T? F01Avĉo}:{=7XM3L\E'>%'*z _G0H4oٸwq\Uaݢ{ vK;/{0MbȻTOO\Cs杄6ak/zp9׼Rټi3P]%zի{[?O8-H>m{~j>/2лsK W*T/k[=[R .:f bWޗ)X6BHӘ:$W7eY͚eTOV K)[lYW>O}SMz"Z\*)k%?bѧ>d,#a\/!{m^3bǹD{Yb|%/~1$wmݘCX%\e4>g^c; !V9SNY@9dkP373|)x̙Ȍ +F zc'Gt!UWBF07Q8g! 1C/\'MDࢨ BpJ:$vU!WBwnNp4heZ6}bJ 2VvCod>?S\Ts u~!e:WaޱC;'tRݾt1GcţN0[UQxbtEADOl\ڝpU ._ӻ:0 #UBEX^-8 TO/[l0 Y"tIȵSzjƍG iWǺeJ"e*77[Q5:PS[+<\urđx#tk#/-Bff'ܯYoE[nYb~O>z9j$67ޚG5<ܼ}Q׉I6.i0+NǷmjQ7o_-)s'<9/U![[gSgJ y}T'f3FAxhzF< !fgXF*Gշ5_{m6Lp\)jĈ }Ֆ\r-7FxW~ ^؎'x3#GSܼ ›$`b k`e8[?܁{@`Hi݈0FJO.[ ]fhua i ."> $='o*"tѩ %T ̛([$Q88lbvڔi:1{a}Y`ш3c Ҩc& {`AuX G dEJMOșg4+޻#tR=Q Ņ :~sp9 3na9./G޻K` EȉmѢ%׊ܱg - et^D5BۈC^Oe.Anί>-Y}=;nGc/݊n(U2.35n:We$.ǽ3]4R!9@No#G߉cJq92]YESX'LwFTD#\s8/k:A@PVGJYZ,A^Gח;а`N`upmF+S0X|(?,aX "y ' GzC7ҖsBtxכs}38NM3=L??sTYt)|l(#SAF( gM6u҈s7#\Ms݇{ɞyY]e9pxV++3ݯ2i㚁NDb+8/bs>\E'U@Ig/;#l(t.*I\s*\wg;bmܭ[s0Vވpht&ϛ&.rf6M/7xv lٲ]-ACzu#tݒi0;1qXFyH4ExJ` km420NE Izell[^7MI8wңWmDy'(QfSapDACySuw6*W"?  4x#Ep(ׄ{e:cL,5^p#@O4p |84hM@ u &_cd]MӛQ}$F[c7Dqr$B{7SƉ°~ a r"~uM7;gpD(E,#BwEBpD%l,p?V@Y/Aغ}I(igIZ˱_fnWޔɂɡsk 7z[t ٍ'ۀBaxO/\K 1j0BR~v׃&we@4#~u2|垟E6gt5|Pa4~)zM8pD`^86Z.m ްV|I,`Lcp];ʤh9N>N4ؘZ!q0(RF *#=+u OCMuw\;* ˻֋rrRոJA7Q21xMsAo v 3L]@m{ցL\S*# \aRL6a_Tb|oF &e6c=yk5XDs:]D~M *cN8k?t*!h?,!"t.r$R٦҅b4#"Du_:!pt*v^zsq C %y`' G~#6_br'sOPQl'~you93!ZNB(BeKA,<%|#̡~(ϒkͣzx$t鵢|>lsŤkSՑXՂr1+>b\=.?'%tLh%R-hDh;RWeqX\}ޮ BX7r|lѴ .>ԛ n $a7R$Un# ([݁Z~omnG!DžFHBUpQG\\qg+m`eL5":~5&bip93}[? !<1 =+Kw,J)ߎ_z= JՁ04#OBVH0{bv%D6L]A9! R &d wKa KtLPKw}3BĠփ Yu N(Z $_*`:kƉM؈zm _aYeۺFL3 Gdm02 ~}"WöpVDZVpAHq0p+S=5 N4#@(.鉶Q0In5 1(Sc(#Ma,Deٽ=X6rOZlցLXAJ;,C,3w~j$f RtpUoݞ#gýU5 EWak+\>݅vXouIbx7,O !u&lfJz=WcFJA9H1 qxuj'-#+rx7='t' ļapάC<:8U>J5o|# <ƓAVDN/tNIhSdhP8p|b'9 $˧gGȒ 9NAIԋtH 돺fB:wOif^_' N=F&nCشB|">x~%r~q;.fRY;Zb?*w,XlX(X`zC=%Y7mϞPt{ +<W =R"aBֱGY6ʴ{p<41buEqir h=ԭg@ ]F]3xA*&L sozH=By c<!]/h`qm`|K>>#_R6|7wOY> i:Yj6i0mkDŽ<`0Z+ۋmh(P~Z#~%0}%e7%MD$07!k=Ž wЉhe'zb$#B͍ Xǎo!:P9~9\h=a'd`q8lAzWO{*֦xq @XX vFk4oT7L~watv&zǺ o3$2f^3F3gwco%(7{q_ p6-9>NnCqtE!!sy aL .c(=X&3+vޞK1? p;0yh׸#*ZM;FW#^yU}Ej>x x x x x $`9n^3@ ja a l#NӠ[?׀׀׀׀nh` >FKyZn{>ր7XC.nl 'UȲ;<K|C_|yxg3E3P5kk}NjL|m霙zݺ>Iwր7:c]{ @-9dIh#!ۈ}wM֠\ZU naՈP* a\=%!ouxz^x ƣgN}_Qo`f ;(,mq?ы5wM&bsdhd˘q#j+VncW]5uŏ"~j?^^ԀXi7M¢1K_,.bpT//S)K̐?zVd GȺ;u0̈́5%俺%rZ6TD`zߓ0pzOh%IC(^t,)ԳO /DYR[[+;vlw!Wyߏe˥Dur=$ f)ey&OOw{Ⱦ+<\}yGֳߠ5=X]B"O2u<Bތmf"R=$K.G2&|"|rg>-/>|/~;oC+cLYר{ J3}!뿯[:1qn'`H _xKuя'L)1@#]7qDfHZO*8r\ IDATz钑)+͒s_OYrɔ_NJ?yg.fϑc׿?HyyO _<_e@N4#>x x x x K x6K&L:Xf?prm;rdgg5? 2"˅ȦL׀׀׀^р7wIɒFW ^߅e]xˬI's^Z!6fraOc ?a'7X僼DBä M z?rY6Y>o޶SZ``QbPx'j[,^ _k3z҆/&ȕ=W= \555η)N$||皯% wE~7raɽM>r7ː|FduX{gfxF8avΫ](DM翺Q뒠KuEWB4r3@A[ ʰE., "rǭȑȆrIXs|[Ά?.sQ]m~Ty2d`g_WkɺM2H7|kkkk`iXL32OW<4Z4E潍7Ղ0C%FǢ5&lBIǬ_/8\laādRBQXAxx0춉Q/53k]&E@sV [%w?#%źd6lJtD9 ت=t6X̜,۸Ja +J}`Rh'o YWOףO< T4GcR0#'˖<׀׀׀o`Sҝ&IAzkKSot}}}2fh@$˻ʋN_M=rMuVce"x|2Vm&/{|o9X_ܖOS-Ek֬{BPЊrټelٲY*GTJVVN{MYn| c|+.=‹2 G8nz]d8sm2KNlڼIo!ӭ-S-^,mX;$֯B9CcR]:6# 8@ -,=64K0{o58P/!:R&j-p FAtzj[ur׿[dܹr'h9l5WK7n,lnRѺerxF yf >sGWoWvL̚--#$ R7Ȓ%e2jH9c4C ݉S?r*yaFO›8^br-yIYif]N~~MSOu7̅䜳 >OWi@a! saeV}ȿ(.xx F0fϞ+ nӟ䫗]TnȾ[ߓ[~c)++UEKY8ތ n7$ЦGaaaY+ <[Oׯ;:Wq]j+5z33:[a=KK#Ma0* ²i'PDYNosC/&( =L #ΝB٤^4{1 O{,M!ysi83/dkkkkiXM:Iyt=ޓOr4=#K/˓O=-0F,`,, jmmC1?}U>b8P-[kS83'M(?{sG? ޞ!7lbbn!z%.zlIA^>oQT`CNxhxl޼Ev]7')Z֮'Dbc${ ^0g!:Ȇ1e6U oM&ˑG!3C9t55@&iR>a.#Za*i 4(2f 1]c߲|9mAw v9]M-^B2߂Fs/^_H. AUET}JD 7V}‰T] ^14ݷ߻fiƆU;W TץB7DN*xgޙ5K=@ Xzŗ=*Zݗ=FGs-ܯDѼ i =+'x D\fLMIս]/Lq;>T:˗4P(7f<34*<N8?W9J,#ұSbJ:MyX 㢮mu |Riqqظy5dE`B[]9쐃P;kˆܵJo)/bOAO:D),fz.[>YRe˗C'R:|ݹ\`|5555o4 }r3FoC5'l~>tr/~zhr(9lDX3s`\w=ty4-#F㵿r_#:*Co-_Iv,[{ܩgykh|>'w` @.C~7‹.=$rTco ผ-YCHeY&y r ~,o-|%_ k>'2 oh-Nliا>Un0­\fQC+pSi^THpÎi_\fO ,9eO,֛Sr`铥8017^EYr6 1zd(Ζj!1{zW`5d P|[G7O҈-Ih. Y`8[GOL h#>Z#ukѓ!q/RrM$=7LҰڒ D*zM3 ]ęV;FPȆ9VZb= g4TM&X. ha`42$c.[W9G~?3kʯͻGM͟^"z>"daLy q`,leǃkz&gxY'zVf/kOf3^[~azgeǓ&zG?mW*Eg,g!(z1\Dc'jx:iF @pzlqrJ/>Ƙ%Z|r3;2#m=.rOr߅O"CHư ϓ)=R ?clg(+G0h)7`C|^ ?j ?OTţ%ٝCuで %$mQ[k*k@4)0+=u_wc5K$B';l8YCx j, a>;ZY 0&,$ C Ä]D zy'``8olĈa=I5}#Ʌ^?8JnNV/a~:jEy"z&{sĚٿ b~ ɇKiq;Fv ћ~U.J9Cq?|˔Îŗƕ~q"MyF5uE_m"0B7zS*}jang,z6m$5 67Jw,>(grC8/M~%$:L6DlñX4ϕf~o`&h -ևQ)}Zy7"XLCa0B|gNiT1{M[%g9Z~IP'<1CH{ Cbp^&yYåGSlU#k 咕.#4rq^dC'߯?]" _[bji8, o86V,юXg:\nypycYYxya0N8p,ac(?`z(A\2<-p~8ؼ=)7҈KFXap: g˘ӱe -K#;0\wib` q&[y,0p:L'6p^8mq,L5yƏXzjXV]sm~N[*0VNŻxxuG/lo8ƍM' Kw.Mf4zJt;3[~w1zo }1N^_&Owr`rNwFp,x$B`Norpz ˑ(Odfɐ(00n8re4CwtsTܯX.B$w;V>gkX{_q8FSc-1d }PZu IvrwuER%Duܯ&.u'Nje)D钳$rrkw|2$t2eSK]qIk_fRt/~)KGC~r܎rw0X`Ф4KL\t QqN*ljHӜ ӝ&I;nNBMwzRXiJQCp-cr:38' I~v}:i*?L]8}}5R%Q$r-nrs2BO}:II(}Z_rMi٪sڋ?&\~I$4GR>u *s]>$ aH((uxGBҁE.>? x YْnwR@8[]2&.cmnM%.]G8A7 J)*k ! SpeDb 0:1t@>YpJIr"H=&oy/8$Eĉ[(,3reHO^iZ? {J(%R@] /(G\񎃓Y]k\ɗ׮<%]h)S槈GK32~O)el9l?= 0Jؙ L?I IDAT rD>Hiʁ:^Sa)aɏ5D1);WF}|ja0\.6@X@iwNK/a'42[ja68qdndv4LwZ5wІc]hNJRcpФZIl jvz}`;?| 1zR1hqQi8*evr8vtF%Z0 Qj_uei&+gf ?`X_bnz2>Z^lYOڂH`p~vý'tik 86h%&ڸ9&eo_޲ 8qFM*ЉYZN$QV70th`^Nq'~ 0 FTKsk'3Ҥn, i)ԅ@i YŢbe@gXA=Z[!/I@)mٹ٪| tnX֋S09}T'A99g^47JcC hc% ~$0d@v#*5Dmd>3]{G}'*bZjS˞O\isQV_$-! P=(][ۥqs0$8 uOġQɽh]MRS!iSN$QV],l iڅrj@8ADk'N2#g,`90ih+?4wM;NߔYqJm:@W@,^Kiè:x;Tf]ȳ(w8yG@mB 9Xt2;Y:bLO# mS@1%bu4TP(lgFspauCu$"uܘ+;_uڕ_hX8$K )ْe Rn* 9:$I# w6KɘBhIj qb2)<FE (w!nz$8H3=)4#Y7+B~7P)*Whzӂv`HH6#8D;=e)M D]9.}̏lW\Nq@φhrp0/>feq2ц!rdNBޘ!HR)PѠbڄZf?*2#-BU>HO )L`$23ϕ쨨<,P4zo,u,fϠ;P-j$?(9Y4mmB#SǷ"|hX%xq.R+Mpf.nXEÆQ_$; xD2Z{fK4ʀQqcpBi"5[jdqQ!@4`țq{T1FɗQ^kuR-U)9Ri<ȳnXxhV';PidR`_a^f 5DjVS3!}T9l6'PkȲh"9xxޫ;f*r ;)/Õ/cw?"GL>}M)ЦʥiS#RU20itԁk V!Y%9> Kͨll$T4pgBon2`V$L2ED10(>/TV'WM"k여;1u$H0A@r%-.?h NxE\v>* DQX?LmC'<%;4hEh;G&5‡o`vpOC0)L͑4,`d㓘 z܌C&s,@ p@\Y C'VʜfIɰb,9—Jɥ2tpLٱ|xr5 .P˭刯,'rR%奃,Wmi?~]*7.[^ 4KPX\(0`<lxMNI2h ;6R*F/ϐGM-R>BdmrΗ?&ndtrݍߖByWeҗϐ%rJy[3Y9GVˏҔ~3]x9k /,Ttd7~U2qRq qz)Q& X8p,:_ e2<ǥ7~q #'z n2R;Zyw/Jz 9ޱ\")Xz;c8KZVA]e1s;k #vSV{dޒÆ4w~-xZdCj~IN2xlT^6JW˜)3ӎHNc;LرŒOŕ|9ҹK$ޮ8Jο<ٶzT ?_$EҰ^Ω2q2O #dR1fʌgˊI,Ԙ:aY{FH\7FKtvSX\%]C?(WJ?M M@5ruPi:m7/Ye"K'3sr8xw'G:1ܮNN>i<׎1G~f`ݔN.6$<5HAr5,ՇVjA@ksd{\QԜi$kLlŪ;>Հ7si#i\7'.I矤K7۫TNRda 47Iy2ppIJ{'g)DA4wKS/[lO%G{\?Ǟ\9`(LcbP5$|^vAddW5i5dȁGOTfPP=M%e20ic?NfȰ2JY>wJCzΖҏIQ@^avoVv5R6RZ|U=[$ 0Ĉߞ . 3:ɦa ͵$~4=:|\T8@=z. i;HNiR@G*CG :ZQ!͇4BX ػ}C[f+o6 umri'籬m"[:YFT[6J@l%hܿNJcYw|Du teqLHW.'lRF%H]ėYi``E-jVsTW?WpvԵp/ϥYGɨqy~>cq9\2e' |iõI,]Lz{ӎksF+sSkOTq>Ѐ7cYFKF҂BM͓ epIɴ AiC5d/$,mQGˮ5իD*CJ%HjKee % uT d h `aGd(1GV"9q:-Y6\]X"%(cXJm&\gecy\ dۚ-֊l6`,# F *;⠑R1rJ>; c. ,IM2hHtPXj,I\|/#] 2i\>Y nX/HyiTwU}tHmtYή7ʄ4Rh&*,feI%{ ܁2d Ҽ b'߸0j*ʑwJ-MgȚˡ,KbW Ec3ʉȫEX?Nr`@!4s6mlVWU'Q ˺߶VvJUaJAhjLek.o-r,b/VAY1} *G=+g-1dyE˴4b5#Kf=4l*!e"i dp=ٙrAIGH0(WWN̡ayqԂ4.(UJ kpaHljq"׉9eF'WhvpV9ԍ OZ?q/L OFX"Em‡}HEٟ 6 ˀKy=F7H, :e;W R%1ymRU6~aXUrb_K@ A371 ?uRd$<n|2|p4ݨ|ا+7ʢg+~dٲ` J&*q\Sj2kT{Mސ˖[$\ dʭkfI3^2T1 P,~e";aaZA6h,=Ix oaVLtiaPlA`S,CG - KnyV bxlhD.~y,[2IrgfjY8Eꚤf}s' {bP`RɁV2Bjc4Ce+ FoS )( cN'[_Z-i_f`uXN@4/Aya8Y9.tCXN4 f5Jv2  L$If 3 0eN3 L֎j!u9 D@;䤧! [5%g%ӣ{T@O"2& 6Z15Ѐ7ތeAO蚺 ^ՅiC#tuEi<ɑ),iyEh;2O;o!/즼55 C $]uU1M΍2}t3gwyrl,˴bˇE=YeݍI~uW ۛ0`N*<[xs+%  @&NI9,WZ1` KgEޒVxr@񗒃30lYj†JF-0i6 e{M+ @VY6ߞC+F .5G<\ROSc>xM9/\rf!H+,i9U+B[G,M"nI[(bms&B.De&],`9I V!}zA̤hxN'Af#8)( eP&. ``>l2+yZˀ"ڎ pE1F51O,w23uxQfǏ!xqW3%`;O"ĤC?PrX6,/>^S3j79L(˾뱗7uk+}d> o{b,%pٸw0e$-2GYpQT$"xs26G Ӳ4},.OX#I8@ |NyĜ *3Z)84N@KC|(kHvg#  ^,L41 o~Z $vƞ Qr!hzVdk`g:V%uDGlldLZ"l/]!2(dH›ԈpME|,%h)ŝʜIʅ\x;Lʅ0ն mP9%)kKoh^-d_m.$: e2R#U o_'>4w؀AzB,kԿS26#m4" <_< "Iokـ ` v8h55<m dURp _Q%lJ GjȞ O?K ,@ ,6 C]X!#9)1Q@+ltG7Vf#ӣ29ci[Ŕi>g1hdeB2?Tfe ]dѵdFpGV98ӗc,q`3"!u}?*CPցߎxН q}ا>U?F9QFϞDvf$I(o#Rc!ӻ haw4`9"+{~{4AĸN\D!7_sVh@T#uF0<| A:!AX:bY83l W2dNx"b X]k+{zfcQC%ܼIgꦧ8 [faK[Yllc1bVa,LlY5iX{gazF0,6J/:ƻ'p /6rƱev <ĵ^ 6vWD'j1ֆA/ IDATM΅Ke) |kkkkk q 7wP1(qSH':7}u39'Wb!>t=G{[7o~DݭW0m[_#x.o,߽]OkkRރOӋ5555h??zSSͽ/x{{ }'55555kX} k x5y x x x x x ~Zkzz^^^^^^wր7Z׀׀׀׀׀~o`]+kkkkkk5 ֨555555kX} k x5y x x x x x ~Zkzz^^^^^^wր7Z׀׀׀׀׀~o`]+kkkkkk5 ֨555555k uL:5 0 A`L^! N+gp;[:tG+|OO+I~ݝtoOtu{/;sq{8'ʳ fwe]% ֨ݪf,u_]:O|זٵZ>xyX}㹻tLF{1Dq ^^ xV$`l:d. *JF/L1C t@7(ꐬ,A a\4x\AKK>;;[IFOiI.5$==]Ҕa2/233# 8oiTÑ.eaz'|0N8MDa S[[d}{כƃa:omm,&/LFy֟H+g ~o7a{^^}ump\.]''gyF͛<9X2}: A6Cuu|P<^O_\)F>G2 buF;oVz3Zk YfO?-͚5m4&0KX3|^,W]u̞=[׿M7ݤ rۃră W_-fϊH:@ujNOa /?O6po!>L̎;"_Ky3g"/קak:a_~ה] ºyr%ȢEȌxXcwԩZG}H_y'K/UMަ8ƛw{q?ApmL?:v6>FpU 555y:k0Q @Ic<쳊e93οܡO>dyx`OwuWd2k^peL@oAՇ>pa~J}QhXr[.⥠[:,5r/^IXg|bpY{7y?G2j(YYdVL;k֬Q+s9G, *DԸxę1szNV^-_䲯\.qIMmc>F k-Yp毄As嗫^|E?.--']t PXb'r 'ދrͷ-+WTغ^+P?j)TXK3|m&4_\ =Lkk׀_"|ugg?̟?_inذAޕ:ǁ=@`ė3N?]<@L)rȤCt 0 0^z[88:T'^'S?rzI8>30bRI|ѢEXO3ΐ[_}gnE'^O~*֭[bL45e 3fvi2pNx4Q !9)?SN9%G0d?qٸq׿ks|S֖VyᇥX6o,7m>[ƍx4\hjLyaCoȉ'(!1c;dh=ZI{[to/xݨ. &4eNMDeֈ'l̙ʛޛ\ueKdٖlՋlޓ!0! HCz  x>H2_&$$v}_eY%/Ւlw^|,mwnyu:uT{TSop,nj# C]]mXhՍ)Fd_z2Sw.WYG >O}*d(~)|{v {d [m{{e /@gsss/HXi@` whX+Uz)6!TW*AॄB3g ?#@ZX8|2ȇ >χ6f=br!iYPd_TTdǼyT޾G?^\&t\>Pd'{eOh/}ߨqd|7j6_hݗm|cc`ѽ@ KH%p$Zotn\ L>QEţL ee>,9rds^ްp^E'::F>r+_ k56-ڄլDC8P{ ,[Lևi]zWD`|EEߓR:{l℆6VX&M\O)wEϝ=o k4,MW8` _Ÿr/x\G__'O2>lx'B} oM0m`g?:.9 o}Y/ hL8A@YP(L~gmaV~MnLVZ^Z˶ee 5l<_5qL `ѢvX~G/[. o OO"Y}+W0kCG#ӟMI8ǂկ~5|+G1mm´m2S>P>O5`1ˏ);@Ͽa kl~~qbaʻ@ ~,}΀<㥭MkخEbTo߿N:iu1Cz8tA_UWWknB]!G/=3s 7m~,4 իm|_z0Epگ3cDcxG텃qNC*TwF)3rRbp`Afmg -6%}{_`Zqo<6nhJ o}GG>‡>L>czxASB?⟆?9kjxP3Sఖ-74PX(yg Vqƅ$cqA`(m]0|#?>9S<FXxhӧ\)__ǍJg?%;C=jQϿφ__ o}{÷'?)ߐ$j/O~Vʮ]ŋC?~R7'˜1c h1FV r~CM򥯄'X~eSX ؅ ei*kX?ca7Ǝkaaʔ)Y,˿˪˟PfQ ' |P=R,l#Gؑ)g?Y~Y!qS^^&LN57t)f7ojgdX|Y_ XxqJ/Z|}ߌ c߷;-eB=Ibd[ /LVg y//;<A|A׻~$Ak̴/k SX|+Fz>A;d!@*N)zd]%[(Jn~_axwX),> Fx#0EmRjmbZѣG4=bS1LbS=H>#"FHhkku&̬&|$bcJ +)PŒ3… b(S_#ݒ=ubgϜ((2`UUY_xq/?oȄ bʮ8;v,<ȣF տ%Y3kS}6mX>ƘzOmGK!|eoMܡ"(aBw£^#ƛb:uh3Jmݘc-ڹ̪{p3khsRR--k|vb˞]{8ֲJ2@TgM TUVe뇨/K5> C/J-Z ?[ c#05K~Ai4+ʿ#kj-oyo|Hօ HhU&Nh_r҇Z=ј#x9Jt7M+R؃~ #F02=N [ZZ{ވKu1 M`}l۶toYX^V/[n@YXg.[j몰\m%`rXG-e%CpAp=JAs? o[y._C奺K]cK%JJuu9sc0{lV8{ .kxg ŗe?7 zN490Ziۿ tc2>"@[xJ@R4CBWso /jV K_ O}Sf{K/dJ5G9SO,D<0VV$ rdI ?/ӡd)(i'(h1/1!v2OP7"}/ iSgu_h GGqʏ2,@dX ,~Y"|VӓK˽z6)2byk_@i-7co6'CW{W:mM2FP/& ç?1Eeޜjs!aN-F? kYS4Āݒ5n#?ꟅtqL}sB".Zh,G  ¸aa'5xxkS}|Y s%.PE  n$)N}r|' [пEklG iphSl7wZ?=)]=-+HC*TwVCܘ(JKTxFsxm䝭4d8Mፏx~b,\~ Y@>(sz% ZLaaM~,Gq_*B+PLX+h<䱢P@)+[b\I X ȇeMިsN`A_1V K]- gRO@GX?~8r,)4ꋌt\Д).hJ+g}e'S^`D|kn s\SvQoL|G{{ So`aWU޴I>5OtIdr#5}J9xi>y70'ȍ&n.~65M7,Z9}e46f$+ǟGK<<%[ݛ6eƂ&rvRƤ3/ySfya wL cA< 5v|d`X?xR^C4W{ Ȓ~MMgUEW}ߘ^1JƿqLKsH9a㦍zYzZ.K{9YUhXwθ5j7]d_Cfqeg;/ ?:Ұ`;z,!_o04^F_+_Ze]W282 &.y4I>NK|+"}q8߾SIZvZeptN_N==i I}}p^1L|yg|9;Mx2Luy2/מy%diH%JK Xw^7]"d/HO򉯝y>?8Ocq||iL=.I~L4S H֝wZڏb@c䴙R H%I u #=M%p$ʧmnϔO*TR ;H-XN_5$V5@*TnR -b"@*TR H%K X4sv*v܍SQxˬ86gO#ly1e)c,$gL3h)a*TnR)I>Ǹ|W~lHFqto}m˶Ku2ͯ\ =t~zx>.] .j}XĠDCwػS/_M#"Ν|[.g'/^ )/ֶ ߎm+uYԕiP*khV:ygLע蔬'ˊᛆTR ܬE7+;pym{ `CY@ȝYFp4ߠ"Hl$ţEm98g v͗ssr ı|z6f|cJ IDAT<=KU˶!lA`pl5wc@ Z.jnM>@unl dk65\Cv1}9ża ql7B=r7+[q{9/iPgb:4Ӧ9EuFx *]&M JCB[ yɌ k]lXХ2X4d8xTR ܨRu{ }ݤӬR m۶0upD۲tiO5Uc/6jDQ8'+ԬY3 ?Mhl۶=̛7[ÂE5zN[50} kkkmϼŋon)Ss.)fkڴiϢByEyD2u SH $H f̘a0oڴޔSdYN7a?o磏<iA/ ,L2I֓v)t ܻoo5{V8|{ eeeI@9mTA7S[*Y5|PYrdi,k\]g4qRYwf^2xRSJ"YN2 @jDw 3$,fL7bT/_? 3Lt%o}56J @*@:Ex{-`H PpDɳƈ3gu 'NXnPؒf1 /5CX JFgi g?l)hap,]WV^jSXP҇+W4!,jE@ `=hA jʐ|˖.3K!5֧1_ * ÃnbC(`d| )8YCe:sՔ%!fگ’CT/+j"K`xCYmuؚ'5[B#햧X EN + Y2"D|[{2)G<.kʲCc"%N,Ud_0N` c|V zgP99WžLS{}|sxfUb#l( MkAbQʣ·C>g璦' TR \9Zz@gCA@3}cRf.oPZ A e|(Poyeسz%`iN,v&yy<9c>.6Nw^647=${?b q~ofqcl_e= _T|Ocq@7^ٖpq9iuO86r_N}D瞧lΓ-mW8)i I#8-_C8ȇ*mF٦w~L{=Hϝޏq>/eFUw~|8:/?z\|s~-^Ï{x"q`=?ҏ=fvIZÑSqџ_)ǃ'>N'pM^3N<<sܵ=vԲy\#y~)+dc/UO =yi8ro?M|%y8]cc=t?rؙ3|gءmrqŀgw^d?n=8hp(>s(&ܯ>oذQ~2_(w6|w$\0V=ji^WП:u*Gǎ AyYv+eA;<_E[pg9ԧ@QQBx?!iϞVIls׆jˣuA>ŸG>ɐNT)? O+ ۴tdh@>`J|7 ځ2ƇC<)S>8^/'Ǹ& ^ȕR(NbFDn3䰖:~|],[gϙw{";g?HuVsފSYC!I@~M9 Nf7l`>Րmao8`!+cE_s"ʦ.f&f2PtM{kuڬ9x\AyܶYlyl?( p 4&=`[N8O1{ ؾC"yn ӦN \7]|`ԁ9ʊD{pȊC waszVtv]Xx?vɊ܈a6j9&,.}ȕv+a+kl;Ҩ/J<"ت2*+ K82%cWbm }. 3 k)ٓ`(// &?Q&+ 48r,}W[{@>G#<*+*MPKƖ\ 'xG>Ǯ]L3J~.PW*n(7v:`Œs^jc߉g9^C,m?:m6oڢ{0|Q}% ㅠ!mwBb[+ӦkFM=G[ymX hwvp8)zP[9fW2$dry!CthoT<1ǞmDl=Qٛtv@.ڨ;y1>g;spy^@UUU&O^A+CBG'TdvgU,wK "K<|GhYMP0-ۯPTf͞i^yVTV?:7x4x;ŃcYؘ;w+xy@/]ፕ?QWu>(zeWv8PBLA)2s7'C?wyO[4 Xgn ;-Ku L)E<]"qσ@Z6@'{1ƶ=Xr%|Gp=@ :3}Du`oQijњט5T;Eh)`(p1GFfbF;zԜEҽNb2S?JM?g9TQQa5&ȘC!M  -}z Nh  }YiYƊgl`@sȄ=;L0 M^FH3./'e7L̰so:(`U^((gG~.yڽӶAHu/X@w%jCt)Zg7s=gJ/< r~9s=B\c ZFZ$%D:\=ef%6Nf@k=QMJ(iv<0^ĪDe0srs ח:4KP77k3iՅ2( P84q c\Ch#y98 ۶m3`-TIhQ:ԓi~}yO=#V$,9iA@!i\P7,_hg3ƛ~d5^S_ c[n19@O@MyrOHxϫ1&,(,%n+*znv< qz@!⊕U,NȂ<3)i<4!7%CR& ~Eu@zu!VN@ӥi:4@4X${{\&ofMceL),@<׾. c(a`=J:ٓZ@vȆ7ڔ!ko3ckAxl'.ڔfd\Q.nٲUuf/0HL8R+~9#ԗtˁ|dGy״p]}̽F*) IDATn) >ߌƊߧ0vJn9//bڪEO5P/~ƂKyh*|z5 ״z0 K}*\ 9[e= <(ᅒ:SL3<\O#ǽhk0>fz61\%P ԃҭrnFEΌ*'XaXM C7?y@0u^1_>ҀWZ1]\8Z紁O[x($Xa\ͤ]1L9wSށڜ'ڒoO<2u%6ÔŔ)%~+7[q514Q^|{]yڵ77{ ^Zɲ@ϵ?Iy|X T{֦PX: s,fz1yEyٜř`5(15t~A+8Ӑ9Cɲ>I^/'ϑ+#e%y]Oޯ=ݘfgӋP2:{Z=D=/iކzKw^^|id{-OyKtzh}QHHL^'i,Su'`]7' |صswhmo |% k7QL,xCOv8dGXL,e4?9X5,ϭ4N5 j ၃- 4혯52U֮]k@`A3\ :lL,eJ|ցeODp[ ͚5kFiÛWօ*-nk/ÅҚ#KnY5K>1th!kSZ'p2d\W\ߘs{8pL9֯㣟C=i:/kgǼ'y庺O=>;Pc2o>2ӍqZ\.qb:Γu|8-y&ou^H=ԧX):a*)N_`_)ϼK62zP2TW2F hQ '@/^|iذqYrXtUGR:aT>UTl_\z,ua,Z֙[=@ WQA _ek/Xl͔`kn$Iq Ljâ eoXՊ/X妳$ZEEjSP몚*K e,DhjIǬRs]9V輲nm/ni5oU&k"@ iI5}ٔ+1>MfgXp:x1CuJ?>2i-ʦ,HIX=I;w2`n|zsxH@# eE_ $R;XwP^"4,ױE2;gq+>(,jcǘ>tTR H%0 A&ALua1l0vasLY^^nGv|+T5U|yŔrhpSBtRYxbs>KHV~Ys=aLnd@(@FiX ja" G>=v]CdYs0:.Ǟ||]8AXX]O"?N(z-lupŊpTR H%pHJ5(H0s#>\Ł<"80 4840"k>\QidpbLu/<}/PV5#SsRҰŁi=LOK4.@*TR V):Y\k,O{Wit%y^@ӓ4N7F=(V'/?Ϗۯ9z9qyJ'8~TR H%* U"#PI8chqLK'iu|>P$IV*>,1@*TR ܔE7%4s*TR H%JH֫er0@6en,PqiINPύ;!崌T.`$c<ʊ)8c:Oɸli1ͫ{q<<< XL14w4_/O'uLz=ޏKltNh< dzܯtɜ{]{uH<1?wzxN{sϓS H֭m?4q;++ (i<<.ɇx755]UFU=kxoի\><@æۍ+ f'dH%{h:{u]>1?γ]'4~-S'(Wڰ9N<#Uqx8d`s$.~^عH{xO#5I:NӲwt9m+[\B eC@sG:쐀+liNS H^Ї.m!S[[kCQ(>Κ?*NvS=ǀ(+WN7)ͅ (u|A!Xt,"?kmr17E2eQeMx?՘cP"ּ&<Ƞ,h}߾}VGڌk5  .e8J<&PBly8?XNnN_kNI8,{Q|h+' 6]]& _-?Z @1 g 8{l;PguE?|2 |ị{,rgu9 '#'ڀ1@1Fxbt8%~ז[-8%J#lG&xؗK{œs,1?)]θ#AF93ڶ~lhF]o.62& y:rkȀ ؐh)*y[*~qS&`D%eɲex˯ <6|ϵq:^f<>]~K^ 7Oڵ+_sL;1TVTl6Ҷ4H%p%[/[Α$R 'l f˖-`UL=[!CkBEim38A~B+2m6S`mh[C+!*'(ܙfZY8<}CYYm>sR0güljs*&R(Z @sL 8=rTqZ嗌-1tQJ([ﮡRx_gF… amaƴᰬ !lݺU MƦiӦ;O1wbnS ];wM|l#+r:$@se܀1C|mu7ryVk˺u싙yBcn)={ (#ܷ>ǖG8?}D;w4@z͚=˼s}-qv h[98{Oy*wӅ!)Sj5 s@)D~=}p9nz)`$_v(xa 9cݺu ߭~a<. 4T3:; 6Pʼn0 ?r)nOHoHoCFd޺%M5_hѦ \lo6 @uG' FpN3ox=GQ N4q[ܐ%(R^N^hom7w^R)r{裼;vX;礤|bXliMojyGT:5m~Mb^٩Jhh4Њeb̙a zr"jXؖh"k/tƖ1rQ UR MXFIQOje`a=(…Gǁ+_N 3-mDzEQҿLtaiBŰ@u"yfuEJ} p`޴q%@fN tmP;"@̖K(pd8d<>,d'HwΜYe`f%DdPa9/Yo޲95%}'@k3JgժYvBpXPMlB c6Ň*/+75o|{5Ev䉺2FauôltLb@uaVj"ۖf#ɽbيaN ȼL:zi<<02IC*TG)=r\^`uxljmXrn7 npxԧCxMAsR$`yȣ7yڀ.@ So8V,\(Ù<7fİδu0^jMKeʉ5LXK̬)A:)뒔$]MM)mTbSS6@Yǎ֬|XZZ‘cGL'N[$WC,5eN< ҥˬ.Lk2Ӗy:/e\=&#(Y%Qr@2i@zӦMFAWG[MO1]L>@S0k!Rr@eY[r,(k@k[LȔJ!rԫ_螝0n3Nw{G='(6giH%JH`O?-Qy3uSoy*pIi䤣S(eBI0("L硔6(oP_&HIQhLɠOxR:#:~ڀ2NXgĞZ&Y$#h.8 ]X3(@ ҩ#J8,Si#ʹ  E])ȟR'͂e<*Қ, ,䯨0 h@ȕ(~[fZ)(wY#uV.v 2hnjdFu+mvP/gl0ig~e  ?Xo,kLk*䅞@]sʠ_8R +UV!@rLY(V㴁L.2f<+Hӿ!GMVoyrLfӇS?d@?Sx#8 9,vAϔ(S>V~ i!1]] 0>{W?}Y{]w[͑37wk@qxc&)q9HEVUVϪD_ .n&$ hɣ׿zOWה H*>YzLU``ҝӒvyOg+b:2r˵2?zKȔ4߯y6[iWV<$fw2.K\{=p.9|Ə#1+<"wLyGx>?z`O/mLcy\/r{V|qqqcLn2b8x/;yIS =HS\QsVFd,?yyb!Y~:[xt?4~=WJ @*TQI 5I_c]Ŵk8{_'%$ik?Ol!Flirq|~(ic*TR d@ 垏E9pY1V|SImˋ5;}o_7|\ǡ? @41/(xN!'yG{q_m"?޳e4FCNjz^GNR H%0x /{FYe|Ͼd(iQ"gȑ&>P4cE=#N>d&})#Oi~/>e;xxwjg8{ķ#m[G58#;>Im!È%M8ő)mg.ʸ+@`x"񙅣E/!ּ`uD?B/Cq_|QNVgP*^x?߰nW\(8G \;Bn…c<}#7{|KUW߬۶PSuiES $Cn:/oomDyf͚e# :,$Vߪ_#3t|;0/xY('#g0wp 9Cs-f8RtaMozkZP{2@bh8/ꅀgwBN,1%pm\R@' P1TR )A!`P t<(k=6EA`+**2[C$5 a=ƻE[`ae;OYN-{(lCm[œ/X >da9q7rLň(5r0aaCd< `A{38d#k/bþ'S2ft3kTYMj2@epd6e;|ɇ}Cg9.Itԕ2&yk^\Sl_*TR +`+{3EI;>O,c `@I Bɏ=Ɣ2(V%׾hاuZAȴ{ְPcZ KVѲ 2}YXdRYYe_Mnl>s.2^xl^kT*#C4ÊE`#uև;/ຢ)B Z~dM6L=`Box49rJ[W&=ǎknŲ~utԁXySFѲ39=s49֬[ZEC=([rkXq͔$6]U961fe'`XVQfjnӡN߮p7כv9J OV9ap^SM:Hʏ5/?~Z͛7Ϯ1_nYv{ (uw_3!ۙRDe`tcm||ʾdlԛ.䥬 6 lhV)٨p:I=TKG큞z@Q>@ⵟ(2 z~9G~ԙiZd(xk#:sN9ĸeOvy9/[IqeǓ_B6;NƤ_b<(x[ܾBd6̍Gw<C}JX2q1EXtw-VZ{VXk֊Z7YFy ~PT>eB5t\Ӈ6ni|Ux`mkgAVi7A/%ezխ2j0+_i>iV,BNK ɾaS|I ]v}F;@#)O?Ø㞲=m#3Vh'K4H%Jf$]얛׺ W6(UB%Dص{wXt)Zl~]gN1e4zFhj58:46r>GEn6jzp1q  S˝@pI_Og{W<}\8v)L6*̬. ; ·s[CGkWVZ"P!ZqrVƝ[`kNi+2_ۡ~زek5`̷헲޽gWe1? Y:E#C֐:uF_ aǎaf,҂:d5E  pl2=(s^tŦ?#ǴNk^(._Ek6Қ5/+ j%0 3M۶n`ֲ`7 xc֝J˗^z),]-[bcdߐ'mgQf֜lYܿo>-G lN8DmNP|8aЪ8?2yYvǎӧMk_yŬ/rehL6_ ^'+];lK Q>q+ւb;[W.x3B92p$;pTrڢ/"Hs,r,l\h3Q.Ɨ&OK,1YCGvN_hZ^XQx߷?TVe\.Y8F 2_* 0W[m5`GG)>&7`}]XbXoY֭nrqt)%c֭fZly צ dR H%p+$[!ŻugVͲh Rq_ts#W/( KV̖)!6Jdh1a|}'0Dho’uhQA(5)qԨv}t[Z:N֬qxB?܀is!AV`i'2G}DT tEBD3CȚ&d>kDCp۹sK|>9oĐ}@9D(+/zemq6#?=,04n\Ioݱ—tPF=7:d@4w=r#7xV9_Nli1]sx!#-#=y&5i_X& &>`yq"b?dƃѭ *.?7xtbsh7ڋ )q==G#[6yt~XX >^k(ei~$/ӁXzD\r\yP|t4&t }8@1Z8,m.G g{rhʊ6GnsZOܸ|vXFHY}b{ͼ7r%a2K,QmXgqϵc'l= pHDȢ2A)6v[hulq=k€8=[yy{O;$M/*+*k͛6d54*++ oLLy/HlZ Z_mxܿZڷoY68LiVXQ(=mԩ@ZX+Ɩ86oVWS6YVV}C1ȋ/JA5f=g33*m<Oim[ZE;$J@DBaLXY7U7"J~DCq_m"`E}\yyp4 N?{{o<|h_07^qLǎ\WDfvp??(LĀh\ 8\ nns'gOZo֖22o__C+AOgR^'*:}3x=uW"*?E_mnʎ1.._+<6ڮݘٳ;uֆ\I=}vs'?< gaSf #.z/#!'6Ig015{Y%.ڳ+;?X?^9!0tR'w1gX)_$^Z_pwk~_؟N6JW=^bix ^:7o8SeL`vcd2%`:_t r_caf]. 3|ŗPwbFBɗ=`?<#Ǘכ>Nixă/pj  ' qP+B,\!:w:Q%`D'ȗ%xyR+v!"51܂t>:D]#.<׽2tf+ &a@p"T\q]G uR/1Y6ӄz_R?l']@|ga2mA8q?zghh [atܹ7&Y/Cԇ-~p&M=U\#`RKkK`L"pACO,"Dϲ|~{<6џ?TXۇl;~,׈+ڀ/>3ãAy#g65u=vEOB4Ywwj83<* Q֣pSf__0EL5TR|Ţݽ7/LXjv]-i|]E.d6?p!\#}?M>">:V&g0$muTp 827jb'5)!‹D^Â*"xe\vcԅ7?~(r?g">#T`/?-&“cGUM(ćYv3R\f?\/b !>48\a/`kX<್֟[o~mU0kut+'):Qm;\("۠ |/+`ry .:w\,0%!uA "/G^;*P4?my,#n?fh+]aƬZA`)n%ãĵps> )D#<0D]|F(,8uI˗?<.^V'0lsZR 8O_SC)Bp"~8?6Ffzĉq^{ulp ٷ';ޕfv.&-=zćm&B{|yOd?hOCt[ש߇E^I>pG EKڞk>cs.:5<'qosOs`+ldzCwPP~d Ao#qa,t{$|n2Õ`/;g> ,+u`8/s%6?,B=Gl)˽qp_–0irQGg#˽QLhSLځ{{{hx_qN>T_n|ObU\ s9SeQXwND$>$1x! 凂۷=#`S IDATj)rݯ^uϟל?ҋ-^ڜg{"lLs, CƴBц=e~ ,\T]==Y 1'qt/|'",& AxY_ekK+zw??y9Gָg%x"X d –?I|1obSvUb83^+t/;=|va]vMO/;f(! {:ǖk'UWTur8BW|/F=˶8맔"O{JŠIyY!ks={=h6i[mKڂ!]=CM$1x(bJ_v=״/鎂m2|I%Nl< xMX혈m!Eq󧏕ڎe>asurߧźӯkgZ6S~<(o<=cVI׹1O:8?xNJH/]|}MOow}[)Fqc[Xr|c+[+{9_ܟΛގNj_/~Q~WoyoTOzmXn綮B> ['a{Abc:8^+󧷷?_KS|,>]lW*_M[k{|t=:V/Zp+~o+Ju(S*_}RmߧYX[*O}[9o{׵QLqZ9ޱxoXJ[ٛDZOeR6*WL}}>h| @=֝"p.]"x4 CLgxhCB ӕ̶~ug;*f/2 "5eVȃ5^Ν"5!ӇYz}xە.k2^D@D@^ W:ka=hI'W8 H`mٷ1U >ȸ-ַu" " +S!)nWlMogv"" " Y'  5 :  5 :  5 :  5 :  5 :  5 :=9-dbN," " /@YY˪Z`X/˪NEV' ♾^-,,zU@\=yh5 {`4\f" v3G ֱwܻeRu`~ժIjjkMC/WK a-*>駏}̛ޟގKoS,Fؗ.Sj}/xL>=S/>Z|ʆt]uqf^*˨E1cUufV @#ldBUu6ʦ" " " ! X ~_4e1ޒr7okf;vXւMLLXsssd  [jhlɉwuNZMMMOM[Ou۵{TXuww{)788쨯yqjkmG}ۺyك Fٞkt[:::l2==쟙khhXzGGG֭[~۵k3q87ud||<|/޾uƟ' [}i8ھٹ&dmo^l箝c=HO.\6sXY|4tffglG'&I_Ge_. ·IR%ܜ]|t3ۍ VQYa§ s{2ć?~Db:=j={w^sݼuvvvZm]z]/^֖p~[)b'O"ߕW~΍y575!u熋}A`EQ._qw #Gh[|p׮/CꫯBhqa10;wl몮y+/+w;X gNkZ&&쫯;cUGZV0~ ~OmjrVYtOawܵY.GFK2 Dg߽ *]]somc΅WQ-/Z[{[>yZMnȺ.*$Y rD@+G%SE@I`jj*]]'pBtr/T&pm|bܺvvoRccCtHn ixp8x~N>mw]eGdι:K.{Ժ l xRyEy5{ E؁׊ڹӞ… Nuuwi4x.^|`C< BmҺ:‹kFm?E`;}x,TZ?9"|~]Lo!s!<:6 ۑÇC`sY;qDfՇ!zCDtޡݽgP?˧|;}w7|ho |!%F=xa0{&2cXΎv^?zϱ> gddԺu'į =a08Al B:豣g |8Ţaۣ|{W` 8af ޼;q~{…S{t-α{dJx Qs~$gBبzѵw СCA:y۸5x21|P{o%Sfe"i6D E@oriĸï#%؈@J! @XŀҴ8#  4^; i7qPyFE@D '/r6Y|̔aj_CnKX}J" " "Iƚcu勛>=ZJ, o?.]>U>N88 S䉀;}#>~Eo@ o b=VU@Xv ' ‘nBN lk~m X/6  o@h쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9 7 쵉,9ڿh?m%V(+[<[U>XeV^^n~"8| ɴU)rYJ~7D@D@D@XB!cƪklaa>I-" " " FUVVZ___ąŅ /u]Tp%OID@D@D@D}puVXWWg! ݅*" ׀UK ַqil˲yRyl|aV{RuUT-[)B?x^7_<)E*Xa|]1~( g5İ7QVQU b0;c }sĚ%"ĵ1K_"A!S[Ƕ}nvb<߯3n>W1VMg8'{¬ͤNDRp}*^ ϓGhʓͭhM sz19TVܬ2:;\Y۠(nQCoJzOG|Ǽcݹkn6;=*>*Bo ʚA }w@YX+- .#r8q6Ms*L[<[/Strw.Uv@@euLX}ԆڧOdK~Gx vֶc}r>0ID04`O}QzxX[彷.>U;y'o7qhWjާld]=yx'غ!Hมܷ+,+#zcdd qakik|}Ǧä .ۑx~]W^9uξ57@C{:>5dcYSӶ04 FٶAxxXbѽ.sjIDAT UD@D@6AC"lgjk{F|]"nĈ{C>&tSg?Wk^W/"8= Wv7ht]{w~vVXv!y<<~IC{+]T촟?Źo, %Es 2W45uVpOBe[+[=Wܿ~h;jJp6m vm7OO(.-rqōrx:em>cn^k׮훷|hZ[=vM;vyٽϾ.ȎG] W.gMCI~u>"o>Soy󀽥L q!8vl@D'.P" " ">yO?I&OMO^~`vt ު;]x8kpԄk/tĭ].Z5߯Y_]_촆>1 O+kt7L Q 31鉞gw>gwwؽ ϓC-MpLlĨAjҚ|,m^W@XS3j'OÃw낻[}HEWnˈ{~ho[s]e:}Ezp\h=>Dxq;tiMM>N<Ö_zwؖ yhlܧ(Ǐ~&KBʓ$+ճ45Q\.RZ[" " "P@Ogww$x}(A{^oi$=8قW/~U#d=OMOO!Hbo^{]U|X'Y 3C颍Tpgy:ùO]Ҁ.5j1Y60 >M9OZl㮢LeFxzoߴ _][f־r2=4?7g0/ __eux[lpͷPPd3t;vÏ^uZ|XР`ID@D@D`# Ur !Nxo f+} eҗ4 1D͍˟-_>ዏ~al]xP2΅  vQRAT?f>DTH?[IA\W 9+`ylu=$FތCE+KV6@9 /~vX] VV5UUK577Bi&nȌoi!M : jt6\ x왙Iml ܅n[Kv>/8p1n,>k}8YM5ׄƷ2Fzw666xU{Z<Ȑm>91]@~W+x.ao%!" " [#8\>i#|)ODR>=;#O{={= c[(uU8D5z >&f X[ZH=C=Q"PR, 5tJr&F}^?7.O?:KW Gܯ$xOID@D@Cn=ؠ~Gd_ g_YYUm}?X$#2x )Y)ll{vwZDl>x`puą^^=v r07$ҼBRN3ܹ?n7N,Lys ,NNBqWǟ~ꞙ$cgگcnАAx=Nk }VSc_'q] TL=p)NR_B|ngSIq0?хD^=nY|z1_htj+97U8;̹Ga_3Vpnބ)"" "   ,UXFc\$a}#g}=a.ձQƒ<<$.j1, ?Mu9c|DcqXفMMmlriŁKV]]0rC<vHքǙ5Uj}gr˪C dؗcJ|1bKo܃ڔsl}vO?c:@/,]D al_|\7[oa M\o2u4TQ?}!_~i}t. ]Ij_Fרcm{N8G?tjµ̴EuUNJs 8X&kM]~w;.L{Blyo>ߔ#KՋ!?A5_=&19鳥|u&\LD-n9Rc,qzscDzyG?є0ێ-*#" " %@Mr0}vt/Ix !n^ذhCox?k^Fq8+JW9}|fjUªkxnE=/κg 4ǘY0CK̔icXkҟYϛMJ+nŭoF~&J&_v%xU[EY+| _yRF <J 0Cz8*Yt=k5щK_w=&=co,Ac,P>Z>:_g54/DAWg4{\݄%`ٜ*6R4nj3׺Jhg Y!9s1W4DHF" " }s|zgE$>!>,::ܒ{^jaTڈ|.Lflrβ+ND_N1l.T)%wֹu.77D@D@D@DHQUQZ'/QZS`Q3n7$" " " E"bHCC,*cMǪ.%D@D@D@DL`z:=XsamDV , ב8uuvvJݷ1ҧ^74˪}AZ%ҙx"C%"NJj]E  e뿋@u" " " ]h!%\aƒ"J8'Hi"F;cHRKܘRʖ.3y1H*O<1%O4$ḥ;knopflerfish-osgi-5.1.0/docs/images/desktop_info_manifest_400.gif0000644000175000017500000006354512346515440024010 0ustar felixfelixGIF89a !"5>HERZejWKfzfpzqqkkp}Z{ssw{{{{{ss{{{RmR~iq{|Yess{vBb{w}yŜȮ{{{ƌΌ8r?[X{~q׷ƖƠƥΘΜʫΥųȯʻɽΔ˧֔Υαα֥֥֭֜֜ز֭ޥƽֵֽ޽Z-ڃ-֌9ތBڔ5ڗ>#5uRܗMܠRL{cމmܞp䢉_USWخ{ؽxuޭꮕֽཞˣکԚ޽εֵֽ޽˲ӵֽͽ޷ֵν, iC(Q$\!Ç#B("ŋ3bܨ#ǏC)$ɓ&S\R%—/y1)&x͚5o~ JѣH*]ʴӧPJJjWf]+֯Zr5ٱgˢ]-YcDóy@B *tCL<+֑ƐKvL9rɖ3c|9fMӨS^ͺ: 6(;tm;nMn۽w=[xpő&`Eˌ]f6P|3宾=㻗뿿??߀(`z}|W!{v[1ɔ2nQҀ&d#Ad_Ŧy2pwxBIC&iH.dP2)SFI&ז%z^ _)dflo [bX'ݹy'*:(,[!J@p8K@A $L`F1>Ȩ B |7U 睧C`*h6G+[`㬺@l>[f{ڂ䞋+?rnn;/ڛ/oK/)RH M`)P -bC[H1#+ Pd@ >$Du0Kk'"tB%`B'jM1stF ;X j ڪ'PQk\uӆfln[ wk]wt-7`vdJC "ܘwq7Hiͨ4w2ʜ`-xpAn`F?q<0Ct'iSXB.XqFyG" 4щ 4 tqBK̑ :Z؀sZy?>>o־wwp~XPB`@I%:)J;nGPFdĩ' %;Y$,8 rd(Ah0Nt!Mz0<Rl&b'F2ƀ AfxA t|{@0 4b@,pD.L! BL$"F2򑎌$$')JR$&7Nr>A6 @(3T%|=@tL"@fU듯z)<9uK=74iP˨c?{^}w_{/|{7·}O?Ǿow_6{~g~ݿz+_~w~zڇ{ذzU@f90} 7 8{a|G}X aܗ78 P 'z z( ׂ/ȂG7{8{{+|;7'~ط~է}ڐLȄ{O|Q{N'G~7|ZHDž %W J(P L#I~z귅`uX{ׇ {W8 PzdIzPPz8'G7舣p舅XXr~zzz{8cHH<ȉzH8^(8H8O{'Pf7 I @ ( Ї S7`PP} `a}aP0 {` 0 `|(8 {L{HX 7h{DŽGXԨ|L8~8؁X{h~( Η7 6X|w{\xއ:iY9{GiKɋȅ@ɔ[{h۵z}(p0 `ӠTzy }X {i^~r)k9 J`t(dY>{|>镼!+IDžY~: {8yU9)H"8|C3I8؉zȩ~E}d~'g8  {kه ׎IY{`ː@ 7aI$ \z`昀թdz(͉'ȓ4G[$z(e)|Xɛ9}W9裭9;c~'m G 0 P}P @ ` `' ǐ` e @ P ЦeЦVʥIХ72ڤ_i)}(}:7ynf½ýnf{K+{嫾۾˽ +cо˽ k{{ҿ[< ˀ)Mْh}&*x}99~ַ|=XGx@z2 f<>@BN<Ȅ\Ȇ|ȈB Iw[P`0H 0JOYw:{z PʥV}G }ڣ#;Pڡ̧K*Ȋ˼˾Fl RpK`A,[̤aIP_H}IH0ǥ/A܇ @EP O{ VR6) 1˕ơ݁~n = PXR\HH0Hİ^Kʬƒjj 4ј-n7D󩸄*: 3pCKF @&[.8ܳ(\7v:pB\R ?#HZ(H8CJ,; .ҊRzB;PvtǗ[5I&8ͼČ4<4qOJ6iukycbe#bnf[n.&{oo [q.ƘdD %K5;sC}tÑ.  +X"1Ô19nv;r~x݅/xܑxo~y磇~z㥯z~xKo3` V6ӯ7't<~MW.~rCis_ !zC c]1`M;`>>/=9gAC 40C)h8DgqCP;a}C QC$bCklPX0L,C x v~ (: W, n0 qhqxC9ⱎz9=$d 9HC&x4hp;S ((yAVtZQz0adEj1s{TX5pl@;)HA"q#yLdӘ &3Le>dyxatBGEcOɎ: HK@s#0"CW'pN,VE1F469{"`( J(q&1yaf4˴Fdvը"oH S(75n*t`baGN `"X@jYCPD A}`s &m a X,zfȷd&Tlka-Xs1D@Ba8*@]/#z_!@P , מs c!`mnD1<N %a `vox XX<`qp6`9P܁k0qTVWճN~;-n/1k=',\n kc8zO899@3sJD@d@B9<:  p0ѣ(=8؁!1ڵsܡ*$@5AӡkPB!,:e+(S(+=3i`I;ЃAK 5"`',.5MB pzy=p^XE,`/R3Vza)![CSˆ.4k#áˡӰ`:ʱS4EP!3,]1B:)B)$),\?>XB8(`ӭ*k' E0AECy&J8C$.[D t. sDfTC)y3 t F^_ZR0%#TıWPEӡňEb `/1?Sf"Hx(`XGb rDϑ.cDPڮ$`D= GںtC(abԁj0b {JJJ KK,Kb@cvF,-JԳq$MjȫPTg<&@r7Uk<|70`P8FR`Qec{ÂU͂?`T̟80c0/9Ҭ=XD /8`0sͷK=>$>mD+ZRNO FM92HsULc0Q&0{=`LS ;rS& 8p8>pPiTS,͊M X ` zpKB%SˆUT{ ÈR 39%>Z>uA } k@(&=EE.}M`]W͜=d9c@, {,XsX'0'0c,$X~DN'9P<@T#Vk8cܬ,0<`(t0kn= 5O2 V9,(SbXSi\P30=+SUU@a"> }"r;[DW8&:&H=c ``~8^^cӷPWAE b p``g0c`॓ @òs&T%FUzp<`}T`+aS^ `+X @"P`.`Jֺ4,as@2A)@c"4 a2 09c\>$D<](Uz8."Ȫ(j:>6Rj*D-À=ԃ=q~d]FðXֹȟL]`Sgbbޑ4{=']e'@INec H&d嵇=,c 'f>fe@֪`=V@80c<F @ j8v}R|e/,o*(]Y- ғ8#M]Ye0Qnv%jf`)-b/Vڴ s%8Ej,GC=jk6|! 1֐zڭꜴk,A`ĆR Zxn(Ё/6m3%_"~8HNc4@e+͋{8ܠ(XӤMn RkN8]wYH mcȇݫFmc(bV U>p+8gYbx@\   _>\l:jdDpOMMLFT{^Fmb~mqjݶn 5xX*·(yXV{ r6Ѹ6ry${1+){1%|q@/r:/3&quRr> }Mn,*<8 *"8d1Bs< t(2r?ft."U/ J-€&nI_D. q*y7.`.L<)A+©M{((1#c=h[ uQȬIV (ܷLm)/=v0 (7@.| /xvp"Zg/wق©)!X+I/Ȇ-"nh4 A/WS'FVu S80g8]8]v]'p1,xL z^a x’s`v(cc0/4,)n{zcl7.xУQCT~ 8&W_z~ ,l E {اPB8Bc ,AwrjE(BH0H0Pg,iI$sƝ{PwU}WSpAӴg&=0~oV{͂_؇,h „ 2%rE$ i=!B1"#C 9j8L d9 %Ll0cZsW.ݼzeH/VĉL@mcf[I!O_X;"# "C)uxQK܃CXѣҠ1x48n9S(ű 0J@X*GwwV 0@xOCDADuD Dzh2@Yw?éŖ[՜ s 8"=D`i$AbPBH0ahNlR w#ן0HTR=ψqL% ^hTrqX"sMC2$fWc Lc0Djhvd3z!GIxݣ=8!5Gw@(ŤE8C9x Z(7 @Mp4C qkrc5Nc 0`=?xpc@8A1 0?r`]Z1:)N̉GYIJ)@pܓ3E1 taW!X`80(3!YjiSS^+H`*JS1%}b-5l<@\tDLa@TXP@̪ I*@ vvz=tZ3.k;ƆȊwUfNbs:S7F]-{앗,C |5HH+M p(LrIlB7,,%N+8`p弈5,,'p%c PǀAfnHI[+7\X |b, 6m15c%01b< G 3 11F8pE N  .xqNi()e1xz87N0,; su;/S۳3LL &(n%[hk@^p@ =ng 8\p5 2*`]"Ce 6 @mi8#*?xA390 ]]Ƞ&BVڟT1Z)8A1Ј =ɽ8G5<1$iKPCܑ@CA8Ak A4ʡ8G{@@x@3cG3dKdL(Q#ݧ=J*Q=\AM OɁL}e?LYaAi>D)Do٥1l"m?thh]_92 4Hj쁂0CxA>QF?ƀd4M0h&S#:֦|k;[ujD!DsBG @8AI2`5 SH4.LhG> CC3܃%Ad|dxoK A99mK>UV<&ѕ]U>(^&hjk4g{8: =B$"M0H3`RGdkfU(x]0 s^SlJTl0UF5pgx%MMspR$%s쁡.]2N:\,\g>^!b|QAT(L)H:Ek+AU01Lݩ}Y)p -@RR-B0TixsC0Ð0Ph34h4eHt )$vCIfsQN4>A bC:=g< ?lLE ]]EYZm*S^C0Ŕ~.^^sA݃ljjݟ&#!?|8-1!]B|{Anu`naNxnCU9o~_q`UmyC R@VHiCLDP隬 /.eo)iEVT \"g=,9" X%"YjUJ9,a/TiiA蟑`0L,y`u@$u=(uZ*0OgKNUvY`PXñuR(lXqWZ^I03aUc-pH#Yx _?51AáX@3Ԥ3<Xc2\б)\ڜ5=td眃?xI^=@(KU kaT- rR6!\1mpe=CeTFC>5DŁ= 0C0JeN?$"KrI#Ce(A]=U noXQ`-GfǮ?ȃ M85T0Sa5L#= ^ @ŜQ1(4`e]BY`=%g3 BXȚЃ%nf\3V)TP` i^?P]׊ttxGgF!O5'AP gsr?LUdP W0X1LJ[E肕1Eٓ$ PtRP0@ C-50A23<Ć!f}9e1jDz?ؐ} aN*"&)?5RO+ǯ@t MoB @UAP%5ƿʏ1 X# نPl@X$1(!<5t2#Uq% Ņ @r1tq9s6ET@ E?ٓP0hp,@} @+D8t7CMe AY^|@&V8YCϹ7f"=x.Fqz2 Xդre@ @ztCC5ĝ5yq 4` r58P:b.SM?hQPHjё3<Kst5A0tL A2z?/@5?OS  @M8aeK/,'{4cd'<`6C@jBD5Ie <΃VC Z:<8EqNyT;t}zapm{|4G1#G;ȡ4__0ǿdqiXPYe}MiQEYS=tj/uXCA3D=>R' *& CX@pA>ȧ< #L9}B}y0O\î=0‚axIal\ĩ`ƪ`H$#L(רp+ukhy$x-yҳ #1)hLX 0`d!pF1A k r5^9 O> { h&0@a0!@ `va:kU8850qZ/g b p4D}aA&1_yRG))T y Q l v,̃4ut0 o8$׈-8$`a5 A@+$<$qUh-0p%,W4h%X0]V!l:&c# n!<wP<̌O ~Z΁ (C M < ФP ` 6gćqBD6E -&2eܧ0P|j \Jj:i`즐2M RQbTbpBp]!: JFb` ̀ VK|qA̠͢1`SL LAaLV|1q CMaaq!cJaAڑ!')#+4#)R"r"RF$I"%QR%Y:azlax 6o(ͦ Ib `  ٺb+)*R++R++˒+R+R--,R,-۲@30V/ρ00*r aaS2`L3R!V`Sږ)aARVRh5]6_s5g6i5/%ZS6s7[j` v`+n6e6e8kx8u+f5K` T:9c?a3S;9CuV) hN @2!2!'903Bc2I!ln`8@A4ASv@AB#6I` ?;CJ2C7B;;n 2Ota(3S>_:6S!?Wl- .e,GHHH+i@@II4JI3VLKTKK+i ! 02S2y'߳8 lJG+6 a?< ?A3I3k j  <UQQMP PQ'uR<P5URS)5Q7T=QU*tVVVZU_Ucb a J@ EA3:^fbpy@HVΡm0A)fD\ ]pu]5]5}P^5^U]ݵ]^^^_U__ӧV=aaA !bBm8@HU ̠xc;&% E@  \ra Nk"!g ANNas   kkkVlllj6mvmmvll6jiŻdOuhVoHkV`aWWX/$McC`&b/Q#" Ө,@"aIOiLF3Cs x L|.xxyWyyK` zWzz j~7{sk dBG&ZB$ ΁6 >`  xt>=F aq!S2'%1 ` 478 =A?8;8 LUXY8G]xgxIkXQwXQxq=u8hf^BV"DI/r m~>Ҍ!A! !ZNڞOs>:;3x3R1C8=X@ R؏X؃Y8 P S8 V ْ+iؒ3x7 6CEyAy9;y?x~2M%$ pI0Z B DO   A*EJ`=r&6CbAL ᜻!YݹJxA9k׹2!2 ڠS2 LzE q#{u'zB֠!W-EMbQ4&T%XB4I ^[F`@0Qa aZ`+ڰpa 9D?9GYK ~zp`qG6L{#8dO4s{W?:!ddk,G8D8 6>־.XQ"F䋶.eFȊ @  r>z"ObC[y P@igxaF!`aJA`! haSaJ[29ڡ4d;2Z2UQ {Wz1|*%!\A!4`a ) Y--Ao@`a  Ab : j@ fa{ P ˛N P`5Kk[? E|d[1|czq|OTC|bYL7;XFa'AAH# Lḡh^ `j96&q P@ ȹ?  @ A  y! Ƽ qJAk!ͱ\| < ]#%]9};cE]b@" L_@ FzS ! `πrh} ah.9A ҽؼ \::!\  ` . ޿  Õ ^ETԡ#)W>O̱2)I 6V>A |]c u׭&C^ 5ft1a a_c!?!@> Lq9z!d :|d!D\2mԦ-VpY5 iC8 ۴mb&Laֿ;z0 A2ʕ׌cR@xa`b6s=416p'J0,|Ef*֫YvՊTbԌ=ڳf:+[l鶥[hk^jL5ă *p1AĎ)7aCcn3Ș=g{~,Nh^;ٵ{;reqZ z=EkUj}A[>{e҃ep[eƏm\Yf ._YdmvP' ~UtjaNHa^aB )P %@1GbP(b%c2RhTDl1Š+@JC$,+@$|RNSdQx_A-PAUYDՈ9ٗq9PR9&BTMYIMݷ͖mJYByI_IexW 5I IiV饚f馞v ꧕Vj)6uR: 뫮R2b ^kZ* K릻rî챠>,[M0hfv nrꞻn~K֋@ pLpp /p? qOLq_0 THp$S - <Ő|rr21 s2L:-33B #|2A?t'C=MWZSS!gݳL,YMs*n']wpM4]| r2nXk,x?yONy_yoyz袏Nzm ,pP<(A .E75<; ஻X:{q,PJX,@Vo}~f Nt H,E+@ 5M,@MSSX\P < +2`pC ظ%ayKh,PpPP`Zg v`zr *`,,@ @Y\0<$qM goLl8å00,$P 8$2` VYP1P hB^ aa`1Q@E'YaT@ $ 0c`d1IȡȂG -o\~t0 rcp> b4@0@@!Cb=. b1 L2 0'iaP@`@ ItqI!7ōVi\c( [EoӜTrR4v Ԡ uD]bF'`uLmS=uTUoyԍa)dcǓ9@1`9O(X\؁# 7BH%Hh@% @: BaebVȅ U?Ԟ&YHF\@,(R @89@WbCLaRLVI%~8@ a;S[!Pd[?Bn|80}5@x<4¡Hk|KESp+ /h,T^"~umLцbl4Ƅp-\[]9PC(ޖmX\c#gG-Rm$?Jɍ'w_\ H@ǸOw ;O"Ac4 84A9 wF&0e(RB5a<`X($A bv`Y Ї'@-@I1޶Œ*Oׇ@p[=w`VjϟYVʸ,[PYYx"j*yF'{ 58t5|fA,= rߌs<6nrܼ1r+ܨ>Ԅ/|QZk|㷌*9򐋜tYOSt__\1+.Z|<p{S:я>gMLoEKݖ%W%8. ًBfvruzF.1`ע+MiJOnkwsAam9Iʤ H@00pBlPhMR}K8ġ|"mPShptq%FxlE)،xMqJΰ(P ?Ukh]TK\6v^YJ^?U 0Rb^d$([EÃZ'IJcAUzM4IWfx?_/kiDNMslI|#aIS`kN)YLFVRH(vΥCemE 9$@KyiHa [ jtE8zV )@qDsw`_Xh>VHvhYB 6yLIĒ=r a` F5_ٌ__V aw%B5Ԍn@pPZ,Z pbS pa*ڡn'Y89$c^P zG 9:9 ,V(j;x8w(c<>zaUȕ0 \ʥwa:YPCȠs8er0@9y=p@q ËJ KW:nsJꨟujUJTJT IGJ;eʪsЪU QN)=D>a=3JEW:s1ꬢs*sIe׊ي8­ *Jj犮骮ʮ *JJg0PsP گ*Kk{ ˰Kk˱!" #k% c ~W9/0ˬ2в5{0렦\096۳Ϛ-; |%9F{:^oO[IX3\Ys`d%$E %bn`mpmq;u+t yw~kz}+| ;K˸븒kK ˹[k;K; < [kKbPۻk;{˼Kۼ ыK+٫ӫ߻K +ݻ11K[ ˿ۿ;, | [l|\L#<\&,(;knopflerfish-osgi-5.1.0/docs/images/desktop_details.png0000644000175000017500000002714512346515440022244 0ustar felixfelixPNG  IHDR(tEXtCreation Time  PtIME]G+ pHYsttk$-IDATxkmWUk)@% >֨!|k/7HZBBBBiL&|eZ" )>-s˵:wc1ߏ=~=g1ƚkǯ73 ’Yn *P wZCyKs[A6ZWZ/jm _sqP2$)Ӣxy 'l"keVQ^kb\r5lHbXk}<0YH>q+.&&?{U^{DI](>{'S%DtE2])Hj Q ]uFW:(X32ڷ»nAz"Z J]<CϺS,dqB \J{xQov]t;'04ȢK>[wp`ku)oRܒP vQV>Gt1t{GA4+ 1ש ^4D3c -Wc2/l|N[Aګ_r{^K~{ðk7n_o~>v_r=㹍ω'HWE4IQDM|@s|=^{gl|-29bGMN49Ÿl*]uE$аxU·e .Xu«F'ALYѝeF9edi5o7syl Qmc猀h,$l@%Xkxs?CC+tUDZjACc(A;4AHnj^wYFs* RAنn,jT? rTpS/֤£yNJʶx`ݎxw]e<6 EV!,0[)lݱit)/AB]gR&ai\=8|ᣓ uźMWCɃT$-M1Dy2}  FGJ(R)mj]C "a,0+t@Jˍ|[fU0ҘFw+0m:zb +{jvX%2Íjڛ2|Yamۧ4p֨\4,a3K*7V/ 3>0r>,wYctcb-%{lܞOjz$!WT?4Ph .A~ S_2: pP,Ih<ħ}ԼJ^'ZK() sϘα:B}HBڐ$,Y0;N>ݧ:u=[:/rK_˯#?=LC kW/x:3bgXO^O P6VcfSΣMA+b-ַucn9iA+fl r_|~[}Dc(A;Zs8Qvvv)H$ xve&ySrnbo{(ƃF.Fޔ`:yRcf9ʸhh%? cNSغc#J0ҁJ Vncd &Pv[1@Iw;(dy:yAYZF%Hc԰ȇ;*R${ƜroՓӕltqd㔀x $TkxinVUE >}ʡ#y(?1n~<5ax ~E g;sxNp5) ͮ:{J8 jel\b~2blu e㕬\@TK%g> IAC롽S1JQV% i-A 5-@cL̵~hIh36nq mo{XOe[IqWT-3P.(6)"^sjLsprenx* __imLletnS{|sm]`E-Nr2ةS*wAxT:`$X[ɼ=GM1TgMlQ`FI~PDrW$MmA(=Y%Jo!ix!{wТ`ʩdPp'=Th-4۪N~mއ7&fTE \iБfk_z cDM"z/_Uǭd(Z -|K@ UlT:ѝ$u?Hbnz(.s!'enʼn1ifQ _1PP %T?t&KhRT~(ADh %pP wCsDA(xSΩ_H-`>6]\\!)H~ɢ5>uE9>aM@`tm|vWKn%l, z P ( |IS ɻ\Lf i$HvSI([)ί%| )sW:lVV? U Zبx_>= ~hp6Y 5{ N ʤlTVNiCIMl? sܘ$xuW?ie'"Yy/@̯*-N Ru]?h6cMdaM1p(څq:BD2o)i1h2xFQCC P5,qHIQA1 C 9Cur[U{ . T,yX^Ju-}\϶ٞSN7 iRo |, ^^b2nϫ (֧%0Uz完I`pa%S94hْx}ǾIh4;#b 2 Q>F EVpvW$L0Qۮ:A)7_+,N:J]:rnVU~2p S:wϸn!Z4oj[|ڷVǾH!obYj,6#`3:)%bۉy,4^w*F?*W¾eFЏ[V0\IȯE)өʡ#W?5\~OV j۸@p>dOB"1p' z/OV'C B iҥT? bX??vGglU?t>ccн޽~hhRT~(ADh %pP wVcsM?Иp4GYϓH'-LzN}ܕKtV4ӌ !m Vt|72pI -=X]FuAR5jA ]/8C} +ݩ/a[b 1Y¤]ձ/tRk|mĿ*RYtp c';5V?#@)FQp!zqEEső%-s^_{4PI4R.v.;6xݦ M)t#:[JƖ&'lP~k02iVQKƶü药輪U:fأ+JJ@ECfYfh -AUcE/ KCj@)^*XYTGrZ%6gwG-;v ?}2uc,4 -sta̰?]F|P7H'v}'ؖW7$jZ? -@D$7rMA,| G.<5;?38}jq캛~hhRT~(ADh %pP wb3%X96 mt#5G6Yl*cI ޱ|pe3OI!(v+n X)}'R>d ,ifa*9 =U"e*g@nI؍m'5 (s(FaGe ۭ+? =P :FrGٶO؊#Ⱥחz1(!gv{c|VZJ15/mU~2zE͑zobYoba5 '?@:g&r*9X(k(x%'YQH:H-#%axb==l樀4^?w*(?)4C4$r̠]nmFl*MBLƬ43R8L4n~#!f !.ەA9%|.pЕtKBu |N>Aݦ(SobC$)%SB`Cp~(AF%IW]4)U]T? "4ACc(A;kc(\=^ʑMt6geU!# >kB]II/жS^峛|Ay/߉x 7&o9{2ʌ2x\Ley6gt!Y=/4017MEj30[ׁ%Sʌ-&/]ϰ1]UD, > -$̥hh3pw @/0j> 0*B0Uݬ1tj  1ɤŦ'G7+ eC6t o%B%['JYnW9UE19|reO.9–]r3*_TztH[?`Oaq圐퇻 "-;DV$4:0מL-wPl_ ߐ^M@+j.dKy ߌ+´wa*LEyXsgA(qAĦw?n1L50~>mAK/<:,1t{{oUB*IQB3z/O@zAj.9\[ 4A@CYS[QaU)LmUZ](Sk1)$D-a>{zk뇖4qڂӯ@AB97F)[n_EIL QcWI([g p.93&~h!?:|BHbj^/kyH!cg PiD١}*nn3 OoaM:^lk}^[?45i 3Pd,XTQCpZc+DB[?A[* %U61[~ͫרE/$-PIv=gxIa3SLik]ZWܬZJkuyWJP Ϲu? }쌗@I' M~he9ul*+*AUG nlI^[Pwvn߬TEft \Fp[- At xWnmQ!VjsëN9BBNJB2Xil1؈#rE4jZQ1[z˕F YQA_U|/=Qެ`jV$iq 86ѱ]DF xIB]#3=>AƶR˸DMBj=jD &aiY]=AAK~M8$]uѤVuQP JA@C;vA7ٵ$8ʹ} 5XܐT_1DedžKIi<8 :@P/lGr5GtՋ%#H5] #}CpvRopKBN kTFmj] _WuXWBYamۧM8lلn"|7x1:?"U ^f(?`g 4^PʒNgZ,@󻜅VBˎ:,# Uꇖ6Xa[|hcpQ-VJd<_t'rXK3bJ'>-`M1$Cd%!IؘLJd£|?ﱱ~vomoxT?JHWE4)U]T? "4ACc(A;r܅) T&%ZYU W! QES+큯cHCy[sFcϛ((H(ꭆ\Ni.-AqT$z7~lQ•LMCct[) {ݥ #n; u}q~dP> (Syl1z\1>%-gejfכ~g3Ay[g5bhz|/ʺYamۧmw|.OOe]*4¤&U\cr>BC';#\2sHc;1.n&!)vIss]tX%]+Bj\\+cbrXco iq>9c@BIX#4@JdgC1T? bX?n8rѭٹlU?t7~űnZ=rGVu?~o~8qx5D?݇x%X2~4{yǏm|xN8A*I]MjU s;/񕻿7~+^uGYAX1 W*>a }P %'}P#/9h %y䇏vMc[kchu7"(Ȼb(Mf3[<wW$nİC[OOOug=5Q U@r.p!oj/O>P?g[ޱbMF]tg`gI(lvyo'JA,II6ʄbVF3^+7y|`oyvˍS~Piu/>Ʒ0Z򱪜`U3ʕiP߄6QS}߻ρao}N LeI>OQ@4^qcО@]5LTv+%p2:A\7 oеeizֳJ;O?VDRd"}1Ol2^tAS@Bc* :9=Qfn)29'0oV21#Ego̿|]ïqSh~(oPpY"~Pz&1ooU!K n9}Q)ckQ΁L("Gwwwn~ϭ';[ܖAqQ RIENDB`knopflerfish-osgi-5.1.0/docs/images/knopflerfish_red140pxl.gif0000644000175000017500000000110612346515440023331 0ustar felixfelixGIF89a HHfg)*WWuv89!, @`2hl)B&l<&.A`b`P RI"@pPZu[0E70nBb y(%]DZDsreJ gV[cC KzQ|k7/ z#R-D   7Cx,|V]'orJ*|c'RckccJr)z.)Vg,tC&`A @H5 hP@G.}(k3 (Òdpa 8>dB'Rlb2 &V8@b &D u180AFpy]tS*Zy 3 x됪#k DV"%@XBf}&l 6p˂(*pWҟ;xZک{@Dh NJk=Ke4*a!}BN=E;knopflerfish-osgi-5.1.0/docs/images/knopflerfish_red200pxl.gif0000644000175000017500000000146612346515440023337 0ustar felixfelixGIF89a HHfg)*89WWuv!,@ dihlp,ܸI7E <x(.NG`` J?`tGz :n"4 =Rvo }J#)U;W}i,2(8 XE( 0[82 eu;"7 on@fh oN  "k8a7E$$NW?Wu t l  tم= d$/ %sKL`x_`L&R pbN`L@bF%0|cApLp gk9րi]}!r- I%o"g@5NarLM*P}M9zH&dE>gQF<@ 6E`b{;D&x`p#ecpN@R!p y&uȆK7ߐpy% z"8 }<sC \}$xW=Y]8@,bnTX1^8٘W_&t{@19*XNj&;knopflerfish-osgi-5.1.0/docs/images/lib_installed.gif0000644000175000017500000000276612346515440021656 0ustar felixfelixGIF89a%"BsB{B{NRVc&_)Z!c)c1c!c)c)k.m1c1s!c)Z)c)k)s1c1k1s)c)k1c1k)s1k1{9k9k9k9k9s9sBkZsJsZ{JsBsJ{R{N9s9{BsB{J{JRZ1s9s9{B{BBJ{J){1s1{9s9BsB{!{9{B{BB1=)4RRZZJRRZJJRRRZZZJRZBJR)1ZZRZJRZ9R1JRZJZBJRRBJRJRc{cc{cccckcckksccksssZcckkss{{cckkksss{Zccckks{{{ZZccckkkkksssss{{{{{֜ƭƽ!,%" H*\p;y #TwV'w% /2`@Ä5Fe[]FO]g85Yr̛Ogb:Tnʨ ٳhٜ)Kƴ< C$Š]N aFcv*1! Ab`1ҁ$lް)J,k͊aq>`0Ca^Ӛ"*z 4V!Č/TiP!SJhC 4i<}?tID+臎&zvKV}% %bAKիC(\F `D_@r ^d" #`, /B 0dl #7$}BK/0"L/1B 9xQpI$%BG,B\1TTR 'r|BK.N\`BtI&$)&2CB\1&PI8ro1<`2e h&tR 'P\`DLոD\BDީ" @z40Bz  @Iul҈ <$0ɩ,ӈ #x$ 0r %E‹-M#>.}rKEB"C=(P" x!.Tt8KR:)` 8qGb9"$P?۰pCr Ȝ=+ D3ss)BTWm;knopflerfish-osgi-5.1.0/docs/images/knopflerfish.jpg0000644000175000017500000002765012346515440021555 0ustar felixfelixJFIFHHC     C  T" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?16Q:4V \)(Š(%˞E2\ + Di5׸Q\dtSqȦQXJ#NqIRSpxyD(QsL)W< + D^Ea(s.9@(Q-;QXaQH(((( \e}O,eQ\#.yih%؎s.yQ-;Q\ƺ6XJ 6(yD˜ˎGJ}QWQ[,BVgqǯg/|;p.@ǘ NzWA5-G)nL=Er.߉{OXH7Mh7m?c^V# >!Rtja򶮏A-9f9a2pjB3ICڟ%&ײ⒋[Kuh;%+sJZ4(yDڒˎEa(hMSqȧXJ GE+.9)+ D(yDQEdՆQE ( ( (7(O!;˞GZeIMu"EMu)V'b:)̸SkQ4(QRT\r:V EW~ǥy_|IIZxϝ7xA:wfrIHTok^hO`nvּՇ4miM:7p.7>>YW5ꞯOwg0 )sm2I9#`UԌWuVdoiR4WvHĶv ~>x[_$S)k4_>W?fR}ExW?~Ӟ)P"2Ayr3A]WwO~>y+7¼٪ |o"ru"^Cᯈ?ܾS?¯ ]ggJ|_ֿfq̶v/|N)C j!GV}E|7Cƒ𧈾#4;myeNG&MgM-8fPʧ]{k?}OR2⳼5oxo<%?SpkėIQץj yiNdLV\RW,EVi(aQ@Q@Q@˶5Rܔvarr;j/M--nW.I:~"E`%UӜZeo(M+SiB{yDoqȮW@6(% k9+ Di؎V\r:RV{Q\ e%HFx4\V5FJ/LI\cTG6’yq VS[]joTr|;7>2K5ޏ{ಙܦ]GQxI-&u$o8({% 2k<1O_nc/54=̣!ѳ2@=Gjrbe}/]N?(<{࿊kWErJޛ3!RU7P  :q~+>Zѵ}6%t:(2Q5NEV[ ((( E%(9qae :<(o'ǽMykc9#пKض7(DZK4)QJ_ʾYNfZ}Ԣ],ΪVwj},3*/z΃'Rt_hbv?}׮y#UZZE8 ~{Rm Nc|~#ʟ_z$R2ɿz;77CG$bh\20YNA~1CVy73 < {A4Z$NbVI?<`?tҾ&*]c^(e1ڟAӱyDF r4|6?Bї|Lʃ~/G)xKOU]oFLmAtOQ6|Uz|zMoMbOHh4ﱵ,3 Gv'~hb~#ޮhqyc#  w?kH4˳[Hh1GZ்eU}>)|+SMĻ}GUOᢋ_F|Bn4tʩs09}^ 6P Ehc䐪0^TjI'kOB+d"G:B R#a7>v\zSblNJ]t]ZI r@mB晃A4"|8NrVջ&aC#'E_CQ7 (/"%ȧ9P]i.~=F5}jɏGn1Z0ToTLgy"[ˁ(vZV[_GZxRlqEɌOն$ښZtaq>rO H̡֓NN+{][MnI?[%"_5LEy#i5V )䲌|dd qZlHwНI:mhӲӷZiM Wl~:ǁXq]\$ 2s {d-B!rHqII'ښ0$}^~3Z|ѴՏl_'†CstEA¼KG|4z|A,euTg \gkľ<۷am$eeR9JE?|)񆊺]߆xJb+ҧO-1/z5}}6R惱>|Z4MWVn}+\cܔXt봒phhnaKyVHP  :cVxJIJYZ+- E>L?eωW↿!r &@A|_spv麾jH|h*^>,zE%< )Of8׭Au]Z̒E"He# :;׍5g~htq}Q\EQ@`ⒿeNU5=>3m [OW1g@A7J>5.2qRjp5 m.9xF}<Y>2y &+Юmⱅ>ӱdY:ӵ[R2:26;YHߖuo&9}k{2֦Q~u_[~coS7֬#- /:j4mپ8'(q"GY Sy[Q[K/-T"y_ޑ- 9/m/?5K^@xf1`8ڭ Z;i_O^IXw"RxMPIk?ZOQ|7-*w HMLO?/w`Z䷖դpiLf1'W/v;o޸ 褎ֺѩEݴ]"KcK5x?ឯp {pybquc~!"]?ֆؽ|L;۰{`p8{O O ݾCrֶ,㴈$e9rFiVJ1}vA[s> ~ƺW7bo<Õ3^ᯅG-tHw Lѫ,r{WPі]j9H$#ּu9ʬrvvzkDCHheh~Gِ#}${V*.?uc C5:)]~iZZ&=bI$avS#%%Ny$JI][UszRcIzd'Ґ evsO !`sQ#\5;;}?Uk^Js|`0s3e PT'֛<jM2mֿ%I &8TihLF;dUs}.d3=:x곒%nUm8y;9-SbW^G4tہM_ܺ29 ⒩fnkwXYEԗ a$uo,C+QNi$9]<B!'-O\,NvwE+;9})Z]8oz$EcU/_>0+g*A.fwana V5Z5 z+JPm=B ng#S>~Eo+t86ڑ -)HxBM/M&AI m>KeڨTY [}̘JcC*8|;壜4h+q9>[,j-n_>3|?g |҃lGP^'mw5>'F~]:`Pzd^cpb60_$5y6"kb}AK^ko)M<|M^XVc; 99yǃQE~)c<%.K9JmԜ0rc~!WD.JGG ;hPQNBmm] 1a zIk/et'[8]%-D[yIlV`<6!f]H=I壪ka*)h]BX@P*F.@)a8)\5JT9o.!94+::zUy.O>&/qvyqmi{i鮅]EQxRڒ7 t86';+mS[I7șKЎ8 CԜc) :HA?Jsz?Jc9/'t餩B;_Čl"evleN7+/^Xdcұ%)Vڻ-yW(Vˍ͞ie73yi 1*}5#d`J2R[׭mR* 0bv?r~)Z%H'wtzq־a~c[rYGɯ'*|ӒcgMkyߋͼF( m%OIIm#OӵLPYDH7\VV-=Yu$Ԓ+t|#7n:],wz|- gx L\};_bwR?+:KQ4+9S\FB7U<NJ?-eh^f}O[e^amۛDb4}} Υb!@ GVLyע%71$ztsȦrL&_IA^Mu0u$5,rW5:]5}6hl^ 0G8 oNH]c2.*M*4j_d{h|M0!fzZ:nz]/F#+koZT颒赽kbӍ4Ry'Ҟ'^OkgI}b%-WS:(K^S'F5h}yRV2IIf=OqSNI?7?h@*QK VRo˪N.sEvPoAѬZs&qZрc5^hհ«?b8vVz(N&=Ȼ$pV/?-k_X[XcbTgڽcVl) HmQd\/ u){7{h/{gʚ5h2@"O<׈Xu5[Z`yt2@r~b0O}{RvG(NB#\?{W<7-Z"J*}޾Fsz$6dWa\`~@ ^¥ֵ"K<#p~7J9s]QV5Zy#]Jl$vp.N5^'s3rWkO#tt穫ιW9_ ⚿E{MIֻHmm[{hUF%W*P+%{5il o5_({zNJ-Ƚfz|rd~ppy`2 sIxI], ˒zz)Ǟ5"N?"Pb0T`ITZfoi1J30J$v<Tc\u976*+MG!Dh7RcDNWs~u㍽>㌱ t\PTMm6Ӆ`k¯X,j˴WcGE}|${c9d[ssܚug^mzԕ#dGE+.)+Q()S%#SkQ)0+ D<)V\t J\sRQ_iRM¤SO? EQB$ (Q\)%5׸%mQXJ%pNJˎGJJQG%:'Yۗ!<;k;㵥+]K\?i> c$r e[m9ZGj~$uJ|LK[4 gcqo轫Ѵ[ψrE_5k:I Z~|!,um⹼=,[qWygo7d.%Na>8E׽+ۥ_O^s=z\QD/o8_HP ^9uYW"׽F%-9>{(ܷ=c`9yK=u+Te[_w~}^dDJĂ-9}i*Jkq^cdJgԵwD(,ۻ 9AM!/:d~qս>\w귛7M(['% [(cn*`!*FhiFM{]\F0̋c辟Ҹ?e]vnqdOt_ޭucSFС}Ǟ6@m+\6h[R4Sқm{_[dPF–(QE(2%HFx4\VĢ+ DS \i܎R40N#E6JL(ǔ+8Š(((@k.9ڒˎGJQv(yD˜˃>3%#i!fI %T`*.)+phϭǏ-{mZO xq/$[sS_nboL W_m*>̐Qo"Iz|e^K9-4 onvI8׎}J,mc#$ = y/-G]˼eOE4۵omһd=*9׸׫d(Q^[HVŵ`\?Q.y{;_F }LV/z]RkeOsלWski6Vjn]\sӁҬ\r۽NG|5|?m 1>B@}jE(B%N aLe#>3#(;gE^`T0ikQ(Q0 IH@"KN( ()tXJ GE)C(knopflerfish-osgi-5.1.0/docs/images/desktop_set_startlevel.gif0000644000175000017500000014604312346515440023637 0ustar felixfelixGIF89a1#  *5 =p.22mJ0ObV\]Srnos^|SyyshhXoZckuskkkssck?Kge{xw{P.Z5p1q1DɈ/[ÔUΜƥ9VƵRcosk{{{{{{{{+\iG_:%LNieXYr%",hYߙh*nF hB:h^*)j)zjbZj:j i+ji&+쮾 "K&F V'~nƶ.{n뮹okK֋L&ݎkFzqEeqx1xu>@VP A0,4l8<@-DmH'03-1N?qTCmWY5\k^w [m6_jl}6Ts<G1R7c~sy.:ǡ>榧Ɜ:~^/O|'3|GW<[|oڃ߽c_~/_<o_? o$H` L8`2ҕxs$L! 7FBp0t! g֐/ cЇ8C"qA,b oOޤ)FVbH.b_1fLcH6ot)[Tc<9HAb4dHEV4?&IJZV&/0 e:0 HP\Gr3v)P< oY\2%0G_Ǭb0LbRt)fS,a2yMkr۬&J-B[:ɩNtdO|@IԠ hBs, (PrVDIэ^MG-Q!G;jҕ$IA:ҙƴ"eJs S8F(8HjIY L YPZԣUlSʃ`"ƊD gMZSLh@- o\^z@mou8X$EL:)Ec+R6ͬa)KXd#kY‚,iE{ZrvMdeX-nw{ַ .oK\w-.r{5KFWl6Jђjwȶ~ w[W/|Ɨ޽o}K߉ηo1a[HpQ l`+FP vXVU(G8p DFf61gxqn?e&L#n&%cZV[ߦ\h6YPLd*?W f.Oy[β e5ev0mNR׿}쟡AS'h;-C :5bh@WЗV493iHӋ~t;=O:Ԏ=bW(sF#ԣ5mj\#v{kbTŮiy-Aq* p?6hK^𵳽:"pILbF(@A?V| Ux P7uE)>d_$syWs o/׆x$'q̄Nq'!׸I\*KYAVMHp<+\Gg |Ѓp\~yJG,CF:CnksX'ν#hӒub\˳D2ic={Y]I}og>C}hnay~ۥOG4W>B%gGxW$s7q$TvMg~H8Āu(@ubdup׀7f=W~֔rWEW}ܤ'E-EDs+(_GL0s&ׁ/s787GUUU7yDh4IbnwVbtuJAo oE |sfc) }s Nd>R VW7fH`|t yx8Ipst {8}xsp>p>XpGv8|phr(|Wɗ(Nwȋ&c3y7fwYT XqIF~(~"hTK7M؇|(tXrI]*WuS'8xd؇6.XBgzFTQh9Oz@!6I {J(Gb/{=02S` v0|@|Ƿ1R@ssC|Y7^0|נ uG9 IED8w@-@ 0s  G J Ԡ 5x@w#З$~ @f X(~؎Wv||ÙHO)LH~YL{?L@K/IhxZǛ盗@~6DU'FLu،~8r)X}q }aPz z8[WSQ\8I_o(68{ScE@PvP`] f3\  0*Ě(H ] VXTBQТ/$:p! ` ?PQid) 0 p?@ x`LNJBthX] gJvHuE'8иv6'ib޷'qbjvgzJ48F ?ЂHrxD㨐*HZ"w遙Zrۗw8VGH8xYYg~nG8 zIcp `V_:cw1h( `P0 m\p|pt d薘8@IԀ g>p81 аp[` 1J @S- 8d,k 97"4!KIs ; "{A\۵^`bK6f{hjl۶npet[v{x{p7pppmʷcJ U&V_wm0j$T6FPѐ UG  8}p GP qp1.XZK_% 2k2S"@A6 б1xh+Ba`8a` z*``ݫ UA˻+ "<$\&yTɪBEzzZˊn&J)`98:pJ׹h``81R 0kWY*"D?pkh,ɫ mz]8!@|:VbܚD*-=0N\41q`0|JC=HգօOMڦپ EeU@ tLDU@ .jz̗i0pf} ԣ,r p`n]T̾{@B>D^F~H/1L?^~_O//O1/"N%$ӊAQP 01NW!8?)a>fe׽1=`Wo^mHE\h&.#]pp P>viSI;KX` հɤG;IDօ.2}@I h^0j.c $`x]F@Օ hs@Im@i{'2/?_O/?_Oݟ/?_2?.Ogʨ)æ@j\H lX!xb†lH“ Qc?1mȐ #8dSe")JQ@0 Q44`R 0`E0@@lؐIM~K51$@?H ⦍ʗQ1_x5WLe UF3bl\f! Ӓa8ҖeE=Y·V4ܩtn1dɔ{wŇ'?|yէg}{ǧ?~}wǘIJ @+pJ:( A$\0 B =B; 4p 6জ XwQ+{J)lꪟ2‚"2jj.2;C PHM4e55d n 4" 53O\kÍ T5Dsm 8R4͑;EHs7M 2$ҽūR4 I@?O@jV[suW]{W_>G=+e+6e݄/W&QG?(~d%` bPD)kdcH'QscxGy0a> O&ԞAЂ2u(C# цJ}C*yJTiEIzR @ P40uiHR2(MsZӘ>Pw*ԛզDE*Szԧ*UR)T ԪRըZM*VՁ ;kYPkYŪ0nM+ZWeXzW֕z+\³m`:*]l`jW{Ŭc-XRֳr,`NԦv=Pj{ /mm{[n@mmk[ַ%ps=nq.ҍns\6.v>75.y{]oq+7坯s[7Eo|[K`ؿo{kw o+ 6o1a w0 ,81m]ƷS8:g88c;&3~"Kf2LdyO~uc!C9T6r,d.wR&lf$GWFs 7YWl9Ǚys\g6o<eB#:7eDL'>ǹ̽]z:ͱ7!l69A*~Mы>=sv+~갧S}~|9?|3~1G_cqW~X^?6^gz'!_У<3S<4@=C?9v#?>EK;2 8{:5#<2 6Ķ˶09 c6>77;+>c573$BA/DÊD:J/<23Dhk=#=3Dot+>5ɣÚS2@* 7h>1C-BWDmDLĻc6WłñOd`F|ot0E3Fo|k;{7|<2k#,EC#2c4GB$|.4?yL@IIt\G},]D=S5tӬ4;F>9$dAdȜ 0cA$M싽´d,ɘޜEDK|d78lccKCcnlΩ[:<}LHԱ ]yLԳwL+@,DŽ}¿O$>-ܽ.M,@πB El;LJ,ɖڣFET=UD TM)BJ?LjSDsJ$ϯS:<\S2 7LI<={KJtB%SS,k40'sAķпt50MmG\OQU-;rdUrlG,TV}UZe@}lU˿tGX͕<dOI,֮J_L05HFY,:0Ʋt+m#/T2\?ϦN`9@T!MU]I|%I[ڔD.4oX;K=DO=2 W;}AX ĩ5>t:—YXW|[<@ SXv4nuHГ4XTD#όTdRRҋ56SO2&dWH˼ sKRKcЛuP՚՛]˻tT ̼ݒY2<$^=Y-DJS\T$أV:j֣sػPU2l5T<62;ȉ2[+Bu;ݶ9YL-IB LsK4I:%ۡ|ީcTMES4Oۛx|hD[dAFIDCAzKλQ-DUN5^EK̡6YP7l]%bYZEU@=3Z ]R{W"OԠsJFXE^Zfψ`@$b^d}ܯEFnR u\f-%d]Mm@b>$]U?$ ՓarHiL^Q t@^FG]beDLiZH=M%#HA֬_>MJ6t>7EtYSYP~"Xv.W&|@nq] dSEv (FMu.\m.E8uCnNJ-s6pG|M.nqKkrEq/f狝7%;1`1^_7;%=PNpowSbý'7؄&@A-DLa^InAhtWnV?Qs o?kĪl_Qw>;T u?qH'@51Tr7G'X~EV ?gn>.grɞ LF Aqʞ=[FP36DHp@ 8@qRt8pa")rȎ!R38OL2Ɗ-X WseNI~eTGjE)3iK8}PE=ŲǓESNeZWc݊vP[1caA S|`qǎ!OlYʖ+c2ɏG{L:iє3n4ҩ7ӆZץ7vඁٷć4m¥# }7qGgwnn>;hαw^{σ;zۦ=x6[mŶހqOjXЀ,?!j!v8$"xb-"1-h7ˆ#1֨"&(#*($Iָ:٣JiM*飕WNYR^%`H["^I%eK>&QPb)gsi'l癀9"o1abh`B:Rzbr:z:z⺫U@S[8œR* iuU6ˬ&l:{zKݪem-ВK.~[nb.// 0\0+0 ;0K1[\1k1{B2^`%%DKU5RKUWAdQN)sS3trYBU>2Gռ43vmTL*'`P'-uV PL t.G=OvHV|C>tpA8 8+8K8W[9k9蟋9鞗飛:ꬫ:˞:N> +.s_ckJWixO}U|P^u}^/}Y}w,3m-k?p4`3@@.T8R0D +A jЁCAN#jPgjԢ NeR ՟JM]UӬRu6Ka1d%pt 1$0:-;%"3 yv5aŦ5k7ζrĶ$XgB! ,⟐ Ev$h"/[1q~jf{VP30^2 CHcEZO`eAJ]ʕ^%ْX Y1 X `` Ƙ =9$=j @8LA]āIC4@!CՔkD=),@V(?xd?@ܟkAQ͍t HWX|RQ-AD= ^NbAH&B mbѷM @QhEԔ ѣ? + qH b٢)/ٔ/^"+` c6e !ಭ -zc66 FD)`[عahcWI֡qaF$N["A>!*^>?71 \ڏLtB[Tb&Z@0`' F dL~"=AzZPa2\X#b zRR,Z@0BSJ.3f7+ ce6OXeў .n R SZ&% ^\]]6A?@__FAѩ$]QT2]#(ǵ>.>>6?d 24BY1X]! Л$!pF.x7ԦD$M^}^M eW<ᅚuKr$P$.N'NbĩL$U)iOWbPZT2Rv3c{ޢ"2eV~6"3rH+'/]%0g1P~|b2؀25P (*1Ugg1hR[푠]\6ެ8F?d`%c z2\mw*drA @3X!#`gb^*.]d!DR53[PdC5xC7PGZ&.~XYY>!iNZu6MwLJ'J0%޼t`IV\j @YS~b^IVT6hhVQe.Vcb(ve1JeReQEe{N#bT2L}ꈚhe?jeb2^-+eR`fZZ ܡAAeeffr\S_aUZ2|)3)83k.3D!?t5T5AoF Y͖OpQ!y眽kC|Q@դCT`w'BNjlPZWDADJi+RWeHЎ-**-Yf*&h2bj*(h{\j^*jj&("ъ/~j/" >n#^f_2#;d&1d 6)?AZICA@i`@Haen?,">P5 yˊP2TcZKT$=Jpvb%DN' ` ]0w(L -Z0'ҔʧRXjZfӆVhF(|*mjgoR*y`"Z4ڭ6`2m`? ]9%1Q2,NE]]O`EVNXaFH A6)#hZE]Bli>0~n7֮oE<ڨ?e=Boe`X<~D0rc%jڤK)rݙ PPVђRҶmF&ZJm*kUn(*h^WVr:P"Вm";!/g&Ò&bS*G*kY²ZҢ6iAG`h3̎V1mui.~i3!сE 1?j%f7@nm>rlkeV` ce;FFԘJ3x(*=;h5j~WWR**C/0Zt2P[ h%J4Gk"0I*F)[*J-#mUF-(gr*h6'$CpX6rc,, 6-`rS'2ѳL=eDDhэIAXuOA-)hyVAXuYXOj>tɮA3"""_O\L\֗VA%]5sMXglo %^1zP-#+r *)kW= Qr+Fk8QYr:uy .DEu!I)Ūwww3gݾ C=4IRH.V>_w]L+&%ROe%g}N H.u+9@28ִqoڦw9hdYNQh3n%rW0R߲SkFz0F0^i bFiKUCvCOxnA000T9+h7墳qBҷzI~+Us{Q,#_f^"NVZDHu1bVI,k-8Jm +'P6k㞡pz@-:WfHә 33Ξ&^|yWTJA/1(jnE8>-ykuZ(Qo(|x!NvHE#@4#iO R\wwc++c7S[z#6﻾AN%^ۗ:dsRqI^\x[ָa‘$zd7ԗ|ĵVg s&{(S! }Go;Z{YD1ȹ{C#u &<&O6EAttO@Tt#AT7ɰ =0" O&='xtܛgxVt!Ě; g,%>>5|su*;c0<}ze==S} ~~tFb0c#4|;sᓽ3SZ-%Z k?Z)Ze?؋[tRZ)Ɍ@bF;k~#{ 7?<D 9 4XP A -$<0‡%2tptQGx썙 $X#3e;ySʞ)g2b}vhgː>#*dO2jѢ>y"}TU^&ٴkLHj=UlYe=WTrlwj)O@ߪ}[0ݫN3Q8[kP–cJѹZEvde?6l}ѵ׳e6lݴs;"q7rOtnG'N9vڛg.w㧋Oy 'o̅ EׯOLIoXh(x~a!XEy9ޯp־ nA[5G,SūǹԱUTnm-nVirםKU[^;梋UmD1hKQmuVKkX~垛ޛT%J_j%-5ߜ=EU_]emuߝ}x^0 6هpzǟ髧ߞq|7zϷ?___~~Ǹ T@>d`)!\P>q)`r hvP= >H ͕B1 gXC6asxC<k?<"%Ј5uX(^QV" j>\aE,Q@F7q[w|\r C 9"5>"UG>$)YIK^Ԥ#IOn(IYJS2u`11 iTq0YLN e2Lg> jFQA?9$M:Tu;zӞħ:yc 2kBPe[:2tQhBA: BAр~vvd%6jj$%(0. iYST3)шfԠiAejteO#TE! d*QSIER3HޤFr^wl:ֵkZ!)׺m$v,DS>R:6-@=VKc)TVuŬh)jv}*g! XCn51pz掯|]'9ܼFҸlEp[;*cjيuuQWKîJUbAβ.c ņnfKFתЏ&sT@dL$~myur 7< Rm[k9~S _/T&qKwn([cwxYݯ?c7G2(S+_2@Qc/k*6y[^[m}s|Z3ŜuqË9wְlGEA p2{~qja on}pM S2 Zþk1{6׽on;cQα~uw?V:p_׾BAFjR#|iI h2XvM\HԨ}Fxf9Kۛs+z-nrfhy:&&pX-x~F@ Ofїp0G$`'#0$pѐ!q[SvD$!I?T N'̎#7`'8 M`³mz$ P]Kn’d6(:(f7{nTY:';o}whSG6mEǯ*3 [hqNӛ>JWJܑg yG;=WbnaQw~<7O&(^׾k<G?!.+[ Xz_/^ B `zݘKl>. @.  & ㈀j"N!J/ s0JA<+$x @ O   ZoN @b/킀(,"遶! ڐ` & 0 P uCNdK8%MH@`` ( `@ n/jH@ @)3H@kB6 `mo{H ?Ap!9`8& ?ᠬ hGpk 1"ϑ ` @!@`hq@@@&} !1' N'+(`mR gj#9GO $.㲙J` 2 ` ` v@H+wr`Lt1A%`r    ` `),QA445U(]6@S112MR:ɚH/;$. L.#(jq10 ap1/Sa3} "  PQ!! 6hS A4t@@ A<== :SFgtw:@ s<6BXb1`j1Mr1P낀63j tQK!Naaa00 ƴ&TL-qNNtM H IIFQ:I;w#"Ɋ %T 2$ Ή0?!)`ȯ& X@H`XTr`gSUK.qUe5Pn5WwW!Xu*S0=uQU]s./R Bt+0h-,@5T@H @Q5K 5! T@*D * @Hjh"bE2v8cAVdq %j_5 =Abt]vFGO/'G L%Ƴr-t&61V -p[Q>5U!i@NN @Tn5o5LdMv%S) N nnV4voo}֪ _$6itKwul;u^'ꈔtP& `AU @ls8ha A4A(!l6*6H!X˘rPW4ymmWi=vSl iott6GSsj ͐ē8u wɖITV)ntDsTf>TT>AAa!XY H>X[EMU`V hE rww 8]]LuJqz@\op tWxWJT @^A%Ӊ@X>a `8 r {"؎X tΪR-xD񤘔ii|MjB󰶁X&vISwAywNፗRm9 A4`$^VHO 4nJ"`9L! vJgXIo TlJu`M(U n `@\  kW1O GUEU3Ԧ޴XL*\!~av5NV:ב) 0 8ڣA"0@ u~iVR;u3q*" -kwt~?d%IA Z`* A.BTCN:Y![׺z!:g9ZQ^C"G.A=erIg$l%8>W @!c)Z`\@չ,(8g3JB[I8t8'ۺ;Lx^7P2ΘwJ1W-I&^FY@ U+h&۾GdjnFٜ7-˘3 luUZ5!pIerSMlǕ xʆ9H! ;`ћm(@NAǹHaͩ;wũ[ÿ<1λH~I{Ql1US3jN{kWՏU\B\Y!h M̪ҜYӃl#8 .w _=6 Y^N[Upp@@JՇ˻?%o tGYHj`h X{L0ٿwɃ7Ɨ g*˫smيWGxbSʶX͐LX]z}+!Ryy*^^S))3| @ ]Un u:z+u*jG]^AjH\a`4IۛBoA U^<;]Wy}ϛ d[’u˓eFF/!:G#:]%7>0J+5yzCRO^- \)U?[O.7ipID%:[v).mڈGI+-]gJ} 8}% u6Rȳ,LѠA :|1ĉ+Zឍ;z##Cz,)r#ʓ&;41̙4kڼCP)ǒlתt6˶.yd޽(Wҽ1,8Ō;F\Pa¿ ̕{SAQ.|aլ[e .ޖ]ܼ{ <8S OTj֭]6KlyV~]ݎ˧m>C$%Sud^nh0zA xwvG ^qQH] ~b"*dOYq̽qhЕYIy8x%ރ Ƶ`ǂ=unNNMBIeV^PdHuVy5P4a<֓kԡihH xy&hxҶׁ7JSOovt6 .Z)ni%F5_TT`.rschcf)DlƊ(ZJB]y zFAg†kF:k2 9[Fjn-oMDe@j'hSP֚ao^6ثoDfhCB  xfpOL1QFTQ|"gF`AP6=hl5s{_*%،Mìm~N;%-bF6ʏmOOO=}_nNN7b-s)XߡC=W"Bρ ]e"Mjg !}ˣϒU=/5/\/{ݩ3U!٭֧< 3a^2ؘԑ4!cn׿ p`e5]KZ!;bab2(Jq0LqJ8A`c sZEOHr@Pr+`81(W8j? t0Z`Vh]l#k2`:6Ш*:#!xBI}T"rGłlqxGo|*.vov\a!BRP܈+c*3U*pwaKl:-5Qg8ћ:g<-0 s>ӟ(= σ3eB PAP^T hD=ZQn4(GғjԤ$)K?Ғt0miL]:ӗԦU~aRճ^e ZVg5WZWcի\U0cT;:UTSkYukf){ճ-dK;͢]-hWZɂ5,]]SΒRrLu-nZViuk٦ngRurc[jv~.xk[FaR48>)5}AuێwMy^v-~^/xuk^k8?X}~*M~$rRTbx 1C6l 4/ 7!gxn2LOuT]՟!\~^]b8a1n%sVٞ,U\=0`&[/N2Y#yps-.a59.K:8J DU̐@$3\8Ccg]A=~eB׺ς3 "?}/.YKMr5wx4,jp4>}iͥ_Ms;DNpga浼_>V[.!؛phѷ'|@.FqMlyKjv:4Ebao]\7m^zG~L؍\W}x< 0p8Llzկ_&0F>nu+ yBQUsZ޿wR[>j[\Ag} o]&k{;KZ8/bGJ@P]g=ҏkW}[z~[p'_iWB5E7dG Ó\ctGn}Ux/ySg^':k蜗|nz"+Q4W{zQ@@`E  pz@D DPh%(h؀8~vg|_ |J C} b @栁 ؀0r7OPnfj fb6f׃xG}dtfosB`EWyX8]~a^z02#pAA@Ut0 E`t0KTgAoG%nrHvzȇ~ hUFMh|+'FėvN P%q8Pw{؇H2S3&[:cCRȋ{V~BFx~Yx\yy8P%*)Re.2&_XCFH`  p E ` HT8瘎؎X%@AF|'C K9|gW|F u" Fpzȏu%w~UaHHy뇒.W8g}^S.b2"BwpKАwX At@@+Dk0 q;"o@DlHa@ @::Dy[˹АΙ lO=:\BKϛTSa:_G! D0Ӡ0 'E@!;{8U4*hF:.5 "+kEp7NG$HQt |, 0 !<%!i9{kjJB U ,$|4ľSOhj8p jQP&Ö5# X`Z \UsM0ʿi'P%T\g]ą;;#ZqP `."ɒLɖɚɨ(>b@;قKI%,|əɝ7,̍!I7[q6 D@bP P_'rŒ\׼(3!b67:WМL<3 YA,RKtFP؜pD% ] O%`3l{8ovDXb  3ME1elCjTK` /@#@ 7͍A=E}I=>8#2AxG@TBMFJ4JhaXBGqpp @ m,"z }ׁ=\M0o8i l=q0P|׀-؃֧Ш1\ӤӀq@-t`UM>M۶m%h_ͶI\ t[%]tpם9]IN@q@ڌ%Mގ"XՙÝu=m CPИ1ӈa*u\LW]X)jD ) ^ +TpTw qL z:m-PGBNS.sӗzM1 \_^a7c.TN z\5fމdݲ&,1@ɳnL1yC`dP[1h ofL V8p \hЧ.{ p00@ \I,C~n^ p@vn~ 00@튪[A{>.SN nN^NLS þlx^>^́jo#> 0U#po -3 $*؞@܎&NCAF#U15o9h[^:E$GZŅ{ޓRA.C47&j?qo-qO:\?7V::q8_:u;/O@Q,7lC-5s72̂(/4DO+s72S?M ?;..=752O7xHğ0Jo*p34Bsx \m.cRn7o4!_T MNp q@)Q4 6dPB^HѡF+zrDXQJ-]("F5męSFw0RPE;DRM>UTU^ZT>9~{!SșkB8bʠ&'qg]!.I~Ri]'?t0ͽ"LUzbZhҥMFT 丆~r#ځSvLZ𜠉|q͝?]R.13Lvcc6 ھ;]}hJ޼{ǟ_$/~-3&h7/B 'p(0C 7䐥RXC@G쪟(BK-zP_1PFo1G3h;v 1I%$F&2ʨV b(g !7[q ғ2M5kpM7߄:ֶΟ(Qh-D1-8%>' E4Q CKr/ 7,0E4S4TQN-'.GADrT[o T\wU/gݓR1w+^620Zks/n;PȂ6^U]wUoŁO!ǬMWQv8AK7t#xS<'c<'4y40=يWrb_.e <gveYOjh6C:ifi:jj:kk7Ny_8+ ޖ |0didd b'l\r#1r;s?'}tEG=tAg[?}uegkǽw=xC\x̉r| ,Os m%eP{goe(Oܔ懊_@;h@ЀD`A*P`@RB8A 6C^8Q @(7-P2"FN7Kђx%tIF;c` #2K5*#1ٹ0-,GZT4~F@7c@ H $9JW80o$v٭H0Q#HC )d2*i0r(H9xt&(IQKXv./_*SFҜMaӚÏb#RohUp x& rIJ @^CэFuUUY*UZ8$QJ^nVd8YEa VO-iHؑ2*,,eˠpu\fNߨYcjvg1̞ Y}8aCpd+۩*8@lU-VҏvڨFli+.N0b675j>9xU8&g V~-MbEǦ/JXbnm<{:B.= fCLNU0iuz` r,͑Mzɇ& 7_0%2PH[ \G <,1ja5Zrf)}hD{t TX!mSS&4Au+#,Su4Pm! :L 0% A ٪vHִS׶][V 浯͊avff\q bAXKk჆x%.‎xm)`-5Ggi< mmu9 aPTQQW  ~B0!, Onm mG0`=V@6E"D $CB'ёt;e!I{ӟsꙁk}w@,pu x@׀W ή4Lq_ϧS/G ­Gq ziQG8ea;pG~#WC&V tfrpwȐ>n$!(B MxЃrJ,A ^(rOJȾw۾&뾬Ӑ>>@s;@{|~3!d`3%jlPB2[%,:H8=8A;>334Y=K“=#߫O)LAryʊ.!`?!!C[>p!7K  чz"8/"%@$5yȿ B/ 0C453TF[68D$:042-GD5l6Ļ,i<3d(O*WEXTz\E9S3^_FEb FcF"F= B]l9A=B'49#\#nl)od—rBʹ×L車`ʺ0$:ZK2 04٢* 1.0~{Ȫxzi# y8@'qG#Gz4!Ǥc~w\1:PG}~ RОR4E LE( U*ig RObdLc\JdʧʦLfitQ%b=ӳg/ʈC)FƴAǷBk#@B{0YG 7{-&@Z ,,Hi8ce.G˕54LL ˥:%KMqBI4L&@L '}ɻ@ZE<3ڠtJJJ^dJ|N=!dFKkt4Ke0Fi$4p89,9 T[ {>2`YS{4@&8P<|L Y(|@ePX{i`("nӐ|7!xPZ  H mQ4Q@Ż)/ex9#0)IN+RR.RNSө,S m!8M& iP8%,P0CI |(+@ w+&xVKGw+ע5m٣#LT&W 5HOC`xCK3Ed16v cZC2Mc2FѸF +}Z[(=Lc'L>bBa33%Z[^)~Te,V_OaX_%pվG_eX.R05 =vcXdeg~Yif#x7e^sˁUhNvZU9=ZEEO&J3U6ʨʱ쯎r }=$>Ke\he*FK_F˜ fӚK+S9-L.Os&7c&YQ-8ShJA0hP 2ZlѝDxn.jJ@|7hM4ŀV3iQ^ƮhX֨ROjeLύh il'e咮b`&$tc:O]tET yx"Q1hIB(pN;V&aΖwl}0Bp+Xm_ 0(t}aA"h;V4$LJ^#ˇTFbJNXAenoVl:o\>&KBȆyTپ X#8 f1$||2.8~Nem w2f^`Wpֻ 䃝'2!!UE%Qc[,ʡ|=hTnA4$K,)7l)T&ssu 7CX}=c{x  Hi䠐yY#+p4/̘]s12'C=4Y6.R+9E*"E$dSʱ=3)\WWF).lĦ[o^͜aSx0D U5f8 ;S8`n0Rs y(3Wve pbq?F7f!Βanrޥes:@VEk =h'e%r[v,o%a/!Ix&wY! .i8P:iA '5sF?qg:y~>3=R9X":+ @L"ݟk8{lx3\r{gۏ|ݹBi:(:cKÌ{Y.8>"m/:@'d||&:X|d}twӨwJWV4 ^9P"q% % (;K_{ZlmplOmuR,ek¦tlԨ.(:rk[Phj?c# hp1PԐTnOP߳ϒ=SL 4\E!Dǿ2G#9mJ Wy2%H.mY3dN'}֤OKC-2iң13hԪ9b:S+ի\Ife,˒5чgZd#,L0JǾ~,x~"dȐ#C,y2} ;f8 2Ҧ'#V$ȑ{_Î=8խe>C(ZzޡCG .}&  [PAԧW%8e?YRl˧ǒ5= e |JzH`%S#uY EN2X4`9m1AT0ql!D#+V6 I63Hј;RFnQ$p;DCB%cB$c) sʕWRJ)]rMclhZ[sݵ׷ڛGq';PAQ92>˦ܲ{iLy[-Ak︃ t'GCx>Ѿn%]va-裓^BoE+& 76{7{/247>yԃԾV) l9__[mvOkɜL?w=6 mOPĥ.o]K=q^`2I Cu@0":%uvf=cL$SVwrLywj+Tdz yS"AzQ,)S /T[]ptDžBYܒ?d0]hoseKq|d`H'J1N`q~y/`hKb2AR$ ~"Csf;eOY tX3? jH?""D "rdAaq =&gzq#ǜ(k~QRImɚ s2$`0<] !yK{ Gr v`(A Ju;’(֘4Cr,щGZ.dO.Ƨu2k'>Y:w]Ί%تU&485ivA46)֗^-6s͕M ̲WnԜRB&Em9Hz.0}l)[G2)l`_g55@+_?㗽c 9:k>4!PMֳ;de;*e5ѭӫZIN!MWzϗv6p1m9̡djѦ*hR[| Pֶx!m{[ nN{[uH&D*(:5M9" 4=3Y(f˫Y1]^~[=>SK 3S h%g5\5哑N ] {\ pjWH'S.u%cX\]1G-ˏf6Z8]Θqhi{OۧԴŏs;w-C.Ǣy?\ Bn)M1!>胓.KMeq.RNE;* ށ?ӽL?{aSʼ )PJ]eQ-R^ YWE_F(7%`\_2@~_ ` HMMIcut ޹JrߑI   B]έ  xJl NaJ! C܈A)Ei Z eH2a ^ u(QeĘT9`b`4i!_a_AL]Ne$o%^9''zb(b"Fb]+MSNq cI"IU4^ 㦅ZuZQ/"a\*2M5c5^Zu9)VM E0˱-9ǩ)/\;Z;225*N^lc?J5`SEb7& a/⦝=";86ǹ&)jdD? ]i\I6Ƞ])N$=GBM*c=Z2$=>䧅F=bU2uQ:eP!۱$d2 aeL*$C#:"8Gz0cPcF.YQ!>\BJ:8TDv`uPDL_Gœp9&vbbVPbb6: %dNfe!6""5@] 5TCd~uN)4tHlB,)!\ҕA 0, A4C54P 'q'r*'s:'P#ž% 1ĦD<=m8VnNHm X_Ё(~A^C7|5<8A0Ai6?g~gPghh b$ l&D܌IW\0ا"Aa$g383hE?&hsidv_aNF CDmɬg3f_l|H>p0@lCGā()T \ZR?^)>,7`ҩi)àb"j**>J*”Ю[*$)Lc5K [ZHI6A0@~*LC0@0 4tD,y(A4V* ,@ax6&,k>kNk^+~f붊P~k"jkVh+pҩ$L>.v%ˋRA ",dCG>BD(A4|Z)6SmAɞlʮl~Qlmm.Fmqہ )fD mFDyƮjq\,ABC>4k(laAς4Aϒ-c .*:V4(AA>dCH.b.h.*~Q2ƹ*n*ntqxL2`@vmv<2ؐ ccȲ>,/6t~<2:A{ #k+;/J0,*b1l/JD<@C<@z.֮` 맘Cd*H<܃4FPq 4MobA౭ر4O1L2tA|> 0!+3,2<0h*q+C,22.{+0'p 1#s2/N) "BC6!!c (NM&ýIA>2@ )=L40|ђ lb.4=4AwA#B3CDK4EE{F{rtHHtp ߇!UZd<0s3>>nNhLf !B%L!Pn,@z846A1HtA93H1mWu?uYuZu[u5]w].^u!5252`?hQѡ٢ޝ)lDB/U{_oȥ Ay2HC@*&`&h!d>Cs]..A+A㲮j4n46Ac+voopq'r7s@t{t{ku7GkwHw77QK& A<Hj/@zƶlSU|J.C? PB:-l!罙gy'fvM>b:^㛉羕'k [8k8{8o'F[n'۸ye`Lmpxf%2p8N_O ScHJ@ x,' h ƔkMFq:uA|n*KL9Nùӹ9_:YȖNNeݾ A"w`#6_)!hJЁ4D4&|(C@[ .o Xdzĸ:=zz3Ƥ;mV,^U^, jD 1yf:|[ q\XP4!V'{<{c¼X֤u;ytiHep;NLF"B_A8lB TB% @{P |.c:C˿|ϼa"=N5ϣͳJɕ# kn`=c3_QȿH$TB!C41v3ڳ}>==# {_? aϠKzLs(w^ ^uh( 5wiF3dGQ~~{Q3+P^g_f7iDeD؇>Wo,0+ $'dÜz+c?@(?&TaC!FD8 #J\\bȃA(S4DDe.;tsϒkYgϔ= gQF%JGIOF:jUWfgX#,LѠAŹ#)`Ѹ#`H#oޑ @(YH~ <٩\eur䃔AC$lbƎ;{?+t#6L hR^$:e8VysCLAroTXl7%EƷsWFd#9u?[//4DN@%Tzl&vꩨ)ğQLQY 7j К" z"88N!",ŷ##Kj r#32ʬ\rAdVB.It߆+8S=f; .c!(.2jR*JQF5ڴӧ.tI;)μ0C8';ġB<_ +jG "2UX Zv!y6i9ۨݖZ{- 3+ 6t-8y7x܁ .*PCk@`Ⴏ5Xy&b 8cs9c6* cIMZu7^ J_CYX'8+sT!U[Ku!*91ݍ-^Y^7Uj_k&DN[=q tPFHȵn'λ[oU[BkP~R_^T1ϼnXj-I/--3qyWްe|_7N"(O]wz\F[݉/xĹ^qb78Ƀě^{ڮma/|a[]18I뎍{x@ҝ5b^L8 &uЭޤ /םAmdQZW4 C\u^IlGI(+ F!h<P%ZdҾ6q՛af |6ANUsT >LDʾ$gC0qEJxX4ltB(%:`]V;EWuB HI*s>3,(ktQ)s>i̓$dJYKQ ϤB9}`k# B'd'(T@TZd^A%ke3rehx&hOr'\:rN4fKR$4OT>f$Y"<Jj&lh~UPTEiχ&T2B9*\ }Bb k>glm4J/S?ݤeL֓=?~&;]N,TNyBZ.VtER Րf Y-rf!Vwuuaucwv[vmu[7  !uowk7xwU7tw}WxwxymWuZ11nz wz{l&l7|w|ͷ||7}w}ݷ}}|uXp9~####F`7Go0`` RTVnaВ`A؁! $-58؃ADN5֎_ uˁxA8xxxu8c{{ט{*{LXM︎x8 M  |P9">T  J`A t8 T@ *aD aJ `f`:&GO9W_9ytkph7Y%3DʸA9Źٚ9y!ᙜyٞٚy 陠y㹜9z1*zX) ˴~]*OL@F$EH:αD~v5EatatR)9( Er`   AZ0A4LvĚ9ZZګĚJ#"ALġz{ٛ ڛ[  37a?9د;W{C;={+z'ZHzw{[F({*D[d踇B;fymm#~n1b&9 b xu` Tha  $X|  \GA4nG<Xer Y[<[g]\asƩ9kg< {' ȥIƑܰ|8{{ۢ'3aqNu0P\ߤ~Bt5/(ýG `qXA}{}=귽$;8zkٯ͞>ܱi=ϞÝўپ~5Z۸{1Z̻i(rIz,H^i(_ҌC[m N;wE^3Ma~sz5&~ ` b]o8S@r`5 M\D` x?1a?@aB(Dpcޚڧ~{}ޛ> (k֭? عsw.$ȹ+`ๆH$qbā ZxQ#Dٽ+_I}ʖ&O dϖ=KFnO:SgТDɴPLs.NLzVb0I%Kfsm ܛqYy\ 裐BwJ>1w]?SD z\|NV4PjЂjBxсfk V4DZtlHĒr/e[n*i(?Y"YIQS\FlTQ.|%nie2_%VUVŘD˓9od_SD`MA8dK,0!2CDSʥ峄\(% rH%[a0L8s=ӑrQDTNIzlD2l|kav}Kvg -|im7$mJ+R6J$J*oQf!9d2C&|cXս4.R_ի 9崑 D9eLI 9q6tv=@DDJ2c=[a]D[lCπVH`6W!T:B2S.x Aʐ ܆6J@ 4!J Z JmAqZIgȅ_KuW%x uKt\& 6V]$QGѸT /;#x BD6&% BBH8) n9S?*C4$"E2@5DSZ?zkHB8hԃ,Qz2+qKVRG+I{ XU1#Lc2|=KaF%0]iwLoY%<`b2Μe5an̥nz\HZ!l(9t\݊T7y=E.2@5 GH :&&JRR$>}HC0>viB LBjXv:#:MS>*þ:QN'5%$dÛӴX:VYUd-&YŪVcGT V•w[:ֽuHhFQ׸5v-+_:Mh5aiH-iZ2bq([B"[ W]Ʈ)ƥuvpc:ho52 P~_kk}DPp\+oZMr CqZRsr n5jQEQ׾"}e4mg':#h6wix;}q[*HZp Yo,-s`vD6OGQ耜;P9w A?eaև=@ZІ>t#|BC]xFhGWіn7-hlDzҚ4 hK:ѥ.=3ΤC5I`PX~H+;Q Z^AlJv|KodFIl}41(!<nvT?! $MS]ǹӭuއ*oY FRF2֯ dOWoȠ~'($ZA:Wg~8h$؁ ؁#X' FT;$36{$C.d3;TtuK儧R(fTv T ad= `~Pb=#cmnuXEvHz|xx+8X 1&iQccDl5bUTc6DNT:Lw0JkB%|K\T>>Њ芰8Xx؋XxxSƘΈ?)xЈҘܸި=H>@JHwP8adHEo17Rh95:9r3ʦM./f:=S9)D;styx7ql<btGswlK1B+)EddFM[6y8y:<>ٓ@BD9FYHyJLNٔPJ)QYTyVX8ɔwD PI6YwahyjIi9kFdٓsrmwɖtEx{ yiMA)fIm `m`9Yyٙ)y[fɗptYyPwOiɛÙI89 hl iЉi̹9ٛg⩛;ٝᩞyyYd2Zg5z ڠ:Zjz "$ڡ&%':+,0*yV7VZh cfdzjڦq olJwjrZsxyڧʧ ꧳#$:Z-)kZD=G4#xzXG2;*f_D&*)FhkJz RSZNal:.7ǬꬤxP8Vzܪ͚.He㺭ڭ纮xʮz:暯*:Zzj[j[bk͊^T,H",XEda<$+DH"*[*DP ul+..hDz`E@ l:Ð3lJs;9銬Ζ1"Z\۵^`b;d[f{hjl۶npr;t[v{xz|۷~;J&K{۸;[{۹;[{ۺ;[{F> ;[{țʻۼ;[{؛ڻ۽;[5gT۾;[{[JŊ#ſ<\| 3ɾ <\| Q<$\&|(*,\F+ 1l5,7 93;@B=,GE\?lMPR<,~A%[K<],8 _\\@lhc\NlTrT~,^\N4-l1 ,,\L3NLm]G2M- m3c a=,Mݥm y,偮n森уϊ᦮ʍ˞~^3*¾nd[MD >݌Nԍ1.P-㓾8fNGN%<-oݱ ڹ \&(_~.0/ 68,p>.D_oJ>]LRo/SX?Y^U_?dMej kpq_vӓw|_Μ]˰?tnO 0Ia_ovl?mK4<}bL u9+sDq޽Əo?E ׮NL۟&(/_}n#o*#HP dC%NXE5nG!E$YRroXh ” |$Dh`͚r:\'OwڼYTќC4iBQFMRR>TVTbUHN2=:*ٶ\Ǣ]y_'0L*L ئi.|('j/,{sٱE:5郔^]4f ӑ)ۦ=:sۓJ<\qɕ/gyGmذtXo{c^=kNhlWo-jlۉԿr{n@ 4@T%XR̺RkM5* i:k.[;K40C3P qZ {J YTƪ:l1 ұGbt'+1!PCtI(rʂkpb93K* sL24L43\ǘ9\NZz-4PDUtQF{1G+RL3tNPtTRK5TTMSuUXcuֽ\ AEuW^{WSdN`5Xd-sUPTYhvZ<v[n[[-պB5\tM5\l'S]xw^US:,uw_~Av_ 6j͑\Ea#ءU%mub3ָ_vuxcCYZ6ݑSVye^PcyRmbsyCYze dVziTzj ݪz5fP?zl^0[F*=ѢRGុ/ҿf;#v{q><$0"?8\pKYߐ|X;! RAV:1..s7Ԩ_87~拜gr}җ>9_y:s`yw0 G#| |Q]i&5f|2@8L8'B2l(4k#j'Gĭ͍{ԣ WG$x|Lf""O7#\;F2r*dGFc+\_nObRĈ>70(9~<+IJXj${e-mDe/f˗$f̈b&S$Lhʔf5Yn&lFnSj&-yNtj8Kg;݉&Mg=NSl5~T˩8zPh; [BлxΠhEK6ԢIyJuT#- &I$ YFW.t]nyk^We/zݻ.64Mc$>Я2_ؿ& ,`8VpG-\a SXp9a#1E\bX&fq[b3~qelcX9.VS4;d$GL rlZ!ۓ,/W/6Y$Ur-Yj!,e  d<΃V c$π% -Ć! 2GgXu2<F Zӣf.+ӂ5]M+CճKfZ:X K{d]fԭ+}KŚf6l=˺nT_f;ۦ/mp[&w=ns>ww`@-09mz[7]o[' ^p\ gp?\-^q_\=q\!'M^r\)g]ra6\9}s\A'Ѝ^t]Igҝt?]Qԭ^u_]Yֽu]a'^v]ig~ e`w]y~7 ^gx?^|/x_^<φɇ/Mӧ]Ozث^QO{^<}{^wz_{GOxח~ X@?~_g~O?__? @ܿ<@LT@\@|@@s@?  ? t < A$A@ADA lAlAtDA <B"<($DB%lB&|%B)tB$B)B%B**B(B0*B24B,4,<.0T6|C1t8dC3C4:C9TC.B=C8C;9,=<4D>LD= D;,FC@4DGEC?IDNBF$DJ MDDOE+>DEVl% ;knopflerfish-osgi-5.1.0/docs/images/remote_framework.png0000644000175000017500000002533012346515440022430 0ustar felixfelixPNG  IHDRpbKGD pHYs  tIME  "3 IDATxy|Tǿw-{&;I Av ;kڷWBmm}U.˫ZDV+ QAق,Bu3LdL68g>ss~yιsϑ^5b` q⽦$)>+(!,w~TIQ0u2Ȁ~~@?M.< `ɟ`'&cPm0)10D qɅ4\TG~MG Zu X}t$ $31W˱۩8YS$ݝ{ܑA9Z7.g`'jxMJan̟-4U1Į\~$Um3pKfa$6 G*\%WKx&.3F>f^=܉ĢIW)yԧMaəȍ)p~[_8\ǴSR̷c$^g.y$Z]ά;x;(:(Ο}$uR/^Y:MU1.c֖a$ft=bk;*}c+̟KBnlpSY&'FeT[0Myj=!cI [l )`*yu{ 7nl8HNn DɵoKhR04zk3 y;Ǿp|,_YΓ}IIʺV; Sto}¦۵@5 XP*[WtK;6}X71mUqIV2e~r:<.7skwHoNM'g>Ihs%&X],[ՙ:)'SydIRyj=FrF;S:}6ޓFS᭏StGe"|e9_tIv)ԃH@uc@5oHB^>нٺ=9#-7BxH2_T|9F!gx; zvxZCO퉰44P4tbQzu{ӋpMg;P+3cL ]W>h;u8`CLcu-mb^W>h&&t9k^ʂt=_˂q :?eʿT.Jv+nf?<Ʋ.)O |Btx\!@?Pk'; .zӡ1}-R޲j Q6o= (ȘЂQrxl-_,I0u wQ.nF6?IS^VnGx$&XYс>+8Z 5ʡ.}X;mkKUq =_8}ԘҽM/./]=[qo>Mnui4<|+Վ?!bK+pL\{MOا C@9*ς#N=ԁ"3|<3}okIAOk>%SU#Ȓ"a og8T% *!Yz)cJ2Z$M <߽~>WGvznw{{Owǒo^ o}Fٸ\ ~_~ IS]cڶ=z=:֢慶}j& ?/\<*2IS"!2VmYd^kJttQOut}߷aQ%v`p}߆&X 6G"a*c@V"~UM~QmG W4&c=>Ч޸ #1˱mKwFobv K}տ_F=?pzD>|fjh?~ïa^3#oD ^cm61Q܀zSҩrq]تonv0{ӖTxf׫3{|O_GAmgN2jMﯻk/7$g&Z?H?e>/7z0pbOK^013TȺJ4qމN',Toxx/cʃN;v C'&f4}t^=h돷q,vhz̛߃uKH*L hww`&;C$Fo2OT;$)`U$IS;V4'I ab} ]oOl!0 ~CMhW.w.t~/]4;Hp _|,gJZG?u*[j0'36ѶoSvGv c5h=+܉3F3ә߾l#JV q2 |/={LL>$<h^ \#Xl Cuţ%p\_wcԤdHy-i}'|'~4r><' dc &Eΐh%Y mUT %`[X] i7?0/HwMpxӗzpACK3 5F4z`K7?0>plQ* OnoG-Øp[L5}zhd<0AVBu͎i(׶,y/76: 5!ЧUT(ZX ڏvu3z&/$CL, 綪*}TE4H0n8@U X#Cd~a** (1A4H%A=-Eii1Wn C_$ 52+:&nL),!ĈQ B ⁹CvGLu$YuxG3]ekh5Uۺ=j[o<҇;߼D&hD˶xƻDB(Ghy ʃÅն?;՝ch>"S5:@3GNE9D$"oSKg)†Kx:D+|QϐDZGb(7X%<؃=wAŠ  z4ap 5E?;v9P> ĻO@3#m{ /GTQ[#i{vwyewD:ppA"wi@fgB0  @Vp!@0E++O+.|>C(r˭0-@r@W^^0]|vQA?( u(gQ0j8b J a B@V  #u(/g|w@0\Ebf|wKmk˅ɯ0ga`8vc̹b7lsNJX9s(If>nww@q3IH,PiA1wyݔsbRzGBerF?<ཌ]0D[_I/ؽRD<|rԭ,Ά+Wr5ushT -ҷNi**߷&hl,oo[XOpEtM;2u& ,`ٲeL8Mx/~ҿAnnzݻ7`۱r]C8]]?}Я;`J0vᗷP{nFTUEQdYf̘1t7<8ӆNP߳7_¤IjP!6 1/#5޲d8:Opd0*$ g_']9tu2ir[ߴ#;{Ϙ1Gc@a$xXGc= F2^\|\|fr in' RSS͍y ƒfo}upc$·[Žҝ|SEAЧ3apL2qhD; ~9mIFFS'͞Mxb5|adxIJJ"%%!2ibD-@Ef͚G'Me\W_CHzx"2$%%Dbb"v,! ]{`'+3~;; ګ5DX^ jz}~^]g|ʯ-9WK y&uo%ΚO?C?dYD!A/]hyŌR\X4*<9zT\|l^_'apOf#)leA|l,D N:o6Sdrى%u31- v;_gwbifg$d,8<_Qi"t,Hmi^QlNwDW&=ŁHh\g'//kZټe O-\H7K Ʋ Fa|޿ٴy;f^Djr2-6e[H(;),3ok~?555xw|۫A{ю?D;˂$}TgoxcSFfI_rT7Lw1ղ)}}0ƛo>mG`u>ku/{s9!GOW_$ju.sw/=F͡zfM/tw,syrrJ-ZtX{x$z,Qvx67'jj"%%UIHֲkNv_˴N71yR&N$c/8+Hh܍Z.ϥNArNŞŚ5k4 MӘ1W/u[)c Ѯ 3eYА JROp:-sʒ)+k"--YN$;ۉS"[sq`_2O>#}I =G޽M<Z2e29Hlá֛2γL,3ngb,̛;KF耂"{j9th'wsY̜>f8, C*Z˾79P]!+[\73AXG N=iz 'x)\Ȑ装`atlaf!Z@0@V  B@V  #!E茶͆((Tǃ"-- *&l\.555z躎i0͋inZZZebHNN&''"\.'o]e ]}tv_>Tu'4zZ#R#Ikp@/ "D̟?~ӉDujkkZ$&&b 33x<=/nDr]"V;tH<$Bʲ̬Y(//IBBv0(//0 dY Ǝ+^·|Ea…\ 4MC4LӤEQzX,Nٳ{ Bq_[YYaPPP@rr2餧(+ hFAAA,KQ@ B@ B@ =V7p9QƽEBFC2`x p Їh2 sb֍ݧTDx+|{w!pn[΋t"T`{}< '%=r9S= #iZґ޸20ĴGGzy˃YhZr\$kZX‘HP~>gwTbZSB5Sqog4bZóړz;]jw jQ`8{vȧ-@0\=i@ D+ikn%$ѾaQ2p6}-RFbx\mna}U4} W7)NxB.O>(O>-VLcϿK/E5FnQH5IÖqI`͞cmS62d`U'Lbʘ|9œl>~HNv$f搙a Ḫ=eV`3?r:LW4ɣ4RjjQBqvӎfJ\!F'#:M-$$&%0sTj2&eQv ,j݆,ˌ/$oIZWv\zŔyjL/bHCENNxPGBRR%@bLXN[‰Sst]~fh8ܸ[i4{g_U\P9ފ2Ѥ#?;S(NnH`ZsIcuK}p<˖DRZg|<Ŋ$I~ڊEXXmXT0@e Ec`Zvca֝>/-:[MN}}455QQyO ~10@9_ ud RB6Q3ɛ~>K搑Css3(BVV{xNw>MRvBjO7,CE7Y0$ +_~+8G sǎ&TV ᧥=c)l&KΜxxGXz‹`hJVfe!HnP; qml&.} g'f\.6!SyﳯXrw/^) Ź9OD0u</~9s)A-'-jҊgN8ɒɧ|ͤN`Q83q4 L$_"We8N>a;!2sdzeHLDQTUC,p.;Q5>-cO<}6}86,,=؈^b/ FaL*k(JHD $Iaq$;J?}Gqy׿ӯ<aɈ53Oeמ8HLLDl $ΤbW1+aIHc„ $''GLoϞ=~*a;iS)ݶ^x00;N>Y8@ +dz|.^UVqP@pP__jrr1ntc6~>*܂rWt5bW_˗Gm&޼k?aEM'))N;۷3|ꄺWx,FSH3H/H&Mm`m$!-} Qk+G_XkԨQ,Z+W2w\}rrrD6̜P;oI"PϧHMMc'̸qXb.KJNANNʆ _{nTUeݺuL6f_n`>TEMCu >^`رBUvÂ֮IENDB`knopflerfish-osgi-5.1.0/docs/images/bundle_active.gif0000644000175000017500000000270612346515440021647 0ustar felixfelixGIF89a'"!)!!!)))!#&#)1)1111!9B1J)9J)BJBR1Z)JR1JR!Js)RZ-R^1Zc-^o9999B99RRBBBBJBJBBJJJJRJRRRRZRZZRcs9{A9csBRZBRcBcsJccRccZcZcccckkckskkckssssss{s{Rk!B{9R1ZBZ9c{RcJc9k{Bk{9kRs{9sRsksZss{{{{{s{J{{{kJJ{{kRs{csRw^gksބ{ΈŐ҉ks!s)s1kksBk{!s{{)΄){ք%)!1119999BBBޥJJJޥRRRZZckkkss{քքތ猵电Ƶֽ便ƽνƵƵƽƽƽޥ!,'" H*\ȰÇ c/@L$‰"*X7hhE_┷ 2 -l6 !R &?P>)A⚉I*,CYNyP0gi>0 (,,r>tF7\p.҉%\[0 OؙraN?$"&r)铥2>ޠbH!\z "$M;pM8#4\:< 9U,Bo8c 7l5#mlA8ps1܈q3 no[!si S0: gjë5.:1YlPi2 uj,rK0;knopflerfish-osgi-5.1.0/docs/images/time_256.gif0000644000175000017500000001621412346515440020374 0ustar felixfelixGIF89aLSsk44b==ysvq&}0,XU#hJxESSoddu   ##&%..!!##)),,88>>2144;;##"" ,,8800  EECCKK__SS\\BBEEIIQQQQ[[]]ooccmmjj}}ss{{cckkkkqqtt||yy.?""))66'##66%%PdwkNLURHHUUggttDD]]iivv 6(9&9$SFVfyBTexöȺû¬ŷƺ,_ H*\ȰÇ#JHŁ2jȱG}Ir$(SL=~-cr\)S˚8sćOgx>Y >("5ytӔ<~T*u#ժbx+[F kUR׵[ǎl }9:ջT-YH­*ףC 2KVrP&qb6pRh)I"åղO̙n3h3]JRhu<'Dgo48q Յ[U{ȘUv5p#|#/2d݃O:Re |[p?>g@3vPL"jܷpgud1O`{KbAJo\g W?iTWUcg|`ar= @z8b3.lXbqǂC7 *4ǣgfto hta)1 G}@)N_zgx3I)T"! l^I*~dbph:LF83&ևOm4HlqF&j['0O/cR+IzIz'"L[#-ď<`j,98IP~$+?txֆlO/ ~s4{N[&FƮۑ83$Yo1F (NqX!fI jm1hλ5fS7k4^$*-} A),E!A3 ۤ=P 55sh%sFbq;PI1ts5"SO{ t9XT2J(k l#p0,ΜIt0sd:Gw(#dvs"=>XYo1ǰ Ї)ɈyOȓ}DCDإ~TÃx G/D!&x܀C!ugDYJC"t<Øȣ1f2C+')u.zt7cJ1Dt%P? kp>?h/d Ii <\c!i:NO1C 76bˆ^)C%Ѱ&hfclXHCb VPV,$K-0D t$<: Id7M6>Q2gdBܔ&2Q |5jJLJ=(AHCJR{ yF0oi+K :"nhVF$t<.1=P01pH5aM Cs ! (f, ."CFJ@u$C:{ $YL'k2vXl<ɽPC!! j?x", > "(Y!u&!eG~Mn j -<2w$Bv5D#pX[fqLlr!ƚz`V);^j%&Q|E;u#(Ԓ>#91RP]As+~;"1ˌcGԡ|#s1["!Qa!=]@ .GA N ,a,4Rn$Z="_bƙ=ڎܑ- ҈c\y#yEONFyc7KZҍ9b,AWbdX;sqF[*Ϻ&3_w7FʼJ@n-:dAġ~ms25804 'P5|h1$pT>XW#`)*\EG'.#vod궉\%tD:Y(F cu:1#hHye؂I:Z^۽*xw("O@+i{?Lqs?sGҒu>%᯾gf6@_~h"MQPPb%ل(Ba`}$e{e&ܽ3v0q%E@c,ǽzTߤwdyr(#˫VVA ~#a;-~wEtY E n X`)%h}ka{%qz,HGxF"pw$! 5(P1 @pkGD7~,7 U(l0(օ,[@q2sDa  = %AHZ D s;SJv aga|j/-qpʄ!  "y1arABx(Ad0 aowjx[ C ^0heH 06G׸W*^▃:!W ͘K06sHe^$aQX H`)`/Hb4M #ixX#mQX IF`E`A *R,  4 t8I{,0LP o#ؓa0[(:fg vBw D4`YHe q2فdјpUٙ 9yi隴Iٛ9yiȹɛ@ԙAly]7X{Y%9vsPf(x0\& R9H]Ra!w7ީ !z *%J+j'# ٢s9<ɣ> 5j&  h,:.ZyD*SpI꥗k!jNqPZVJ;vzxfIGr=sj#RJZ{/y$Z_z2JZMҥzQ L:jJ*dꪣnjqqoʥʫzmk uJo"ZJ:ʀڣʪ:M:ؚ Z@`Azs Az> @*S04 H!YP<`J@ $ 9̠0T6K6P$ AH@b A$ۀ_% c@=5pzH3$dy#! /?&(ڲ4$K5='1PHkCŪ?Z7?HxPGRp8;PA$`Rw(^{`<4p[@- 7y1W@@.P   -0 G"2F9! ㋷EQ0bG x{W<@[{HkQ+rҰx\;(  G0^;GPKQ 鋴Mp}=Hp8@EpJ <G K`L#PA0=PK T\JN{  E W0ً^4$2[w@ %ص~\F HKKH+pƐa `PgTAJ}KP pL %;PH@ 5!HȰp xHK 55 9V`@% ^pY@`XH@@G|uHRf$FZw;^Gp5 \% 4F/ @k|]^[AFq L 0% %u \0%#p  @MP0^Gqҿxk] ;@H H$(P >=vF 1/ +6C H p]`PEpH{}\Վ0 GQP,=K9:`Bp 錳֐3+u)^+$1%Eɋق3PM˿[Ҡ;.-ν׋}A $ Btې]WpN ;]CQ@ HېC0<W  c:Q@B$fϫOM-Fq^0K1, i^ = B Cy{]Q0G K,(PG 8@pFP`p[ \ :ݐ+m}H0 ]BP9-pWpGPM0NPOI8H뉤؋;H p+9$K]D|K{K$1p0$A L'P;PD\YH=`!@徥-1708 ڎ;%[, .F4P( ?e/PHk @`t,xu ,!/ fjPk S`[x õ^>Ŋ POǠ\Ϫ͑lB` :nN NQ9q̀%0Dp -\}X 'P=09a ME0  qfOص<$;O3/^ %!0LO O<`[ 3 ^!ѳ͏\O s;{-D c[? .DHoC%NoڕW!)Y"I&-^qdcʔ(u5Ar0$ZtG%Q&z9NtzDž+:tגHFt:VaYe6Wqϭٻcֵ˷\c ׽uOซJfƎBfK9g#cy*素&*3i`Q԰cvLiͼ챿M*/)D l0Ō2ᖬT-W#3-+sN$K(O.3!?a/]CNH&4 R>%]RLqC=bI7"NP#M0+4.LT)N:OCCZ4C]hאm25Kb{e VXDWT<-4L[nU4WU{UpNJUfs|6[sZWv|7\mQZQFYom̀zM(q'ݗچz|qVւM֌ݘݎ=ڋ ӔSZȖ}Mǚ2gdT>Kc_s.ig{>Ki"tdzdxoiECtPA50&A.[f驤j.66&z.E)yś%_;ħ%oifr2Ghs&rEsA7|baU'}tYdo><ޝ]__f֙z=ݛ'wQ7C˕htГ={nw_?|Gop}{+C@ 0Y3ׯ*s( s`2H 1<|!"3+ eCZ;a9BiuH s(!_h0%z?$TEq7OC }-d aH ϋRc];knopflerfish-osgi-5.1.0/docs/images/legend.gif0000644000175000017500000000322712346515440020300 0ustar felixfelixGIF89al@1551541W4z5W54W54z^^1^4^W]55^؄441]]1zzʃ1WzzȚȹب!(,l@QH*\ȰÇ#JHŋ3jȱǏ ~IK4Q dR˘!ϟ@{41@781shѣ5QA'j*`S&(H2jΝ(^ʶ=@*W/q 0:|+< 7X=nu[lA 0eZ&H4f!&À厰V'$ĶF+1䬔n,,]j[}Su u8ޗ!c}!7 {-Zⳓ[xLs1ھm}7i}9ߗPԠ$tUv,5}uTxeKy@^Pv-SxEI$AUۉ@FT uE8'@)DiH&L6PF)T:Db`LYViPO.Q|SIpa"_s(^GQ_@PTa:fh2rxeugi(6kjNEiZХ:|\l}aZsysA)"D+:ܯgggw欞ڪntWr\8X,6K ZzQ؅ +J,:()&tI5":Yc7j'x,0,4l4_\Rm dc>Eיp tN=q`WG˙l6TtpET5Xk럺hh4^kBx؇nd[mvwviuïʫGx7|-Vl(bGxnZkh\UFy<;غi?\hstz֩!N*o'-, WoN;knopflerfish-osgi-5.1.0/docs/images/desktop_info_manifest.png0000644000175000017500000013025412346515440023434 0ustar felixfelixPNG  IHDR1#tEXtCreation Time tIME 9')q pHYsttk$*IDATx tUǿ{YΞGI2hH.h\@0ǁQP\f^p@<`hu: (9y "`uwխwoUo !d>[ݪt׿* uJ=p8p&s^15%_ϔ;|F5&&b6-m&LMbI?]%3#_MQw9kJ+_ h4_MWD兰;ǹ t`w:q=m?㛢;YDn`,Y_7DApy(Dq8\-d"+26eI,GXT$j:j2n/)=f2ɨ I5$0DQM!ꮈuB׍D#nDC***p8?,ʟ97*TX*[jTUEk˜EhF\_J(8szx訫s2n[PvmkM0[b2Uf_%tҥSpT$hzwjp8G@6HZc]TFS&ǨGMDTѥG׈LRbwL^Ob3i#XݢG9R:!-?'FC%p8w 9/d(0*Η\aD;n/?W֞ kNӜ3*01ƪ(^㺌p8ad^>ѯ6AXC \HM;V(Ld]L,Z1d )PU,js5 O\?RiiGmNe5bA$zW+o2VLq8eY4a72ςgVfKI]prٰ*b~Yܶ!&ߡ[xdJS+steyl;|I}7ZXsßo.P~.I߯mSt{|lCOlOy*2rM8uю!m{ꌋ׮Wy nOnK@aUp8ԃa2d ĭ2뜯y¨ ckȩ):>b"lو*$i29 H_-i h2K4&ׇ.sŶKOfs~Aٶ99 91srs/IgL~AAn~iiVO2٫5\c "s$~yyn7H3_}u6soWn5;GZ[\xS$616{6g >UGC/vZޛ:/=θ/`}5_?fnϼg.QLhp8ΕD!Nc '1fG !&D4$S5(T!fuלD]6MWucoּF|k0b(G^xL#ϏJYa2,|]uwY2mPvggf̤+32frs)װ(I84$"ow<># #mtl#P8}eɷ+w$ ||3MR|3wܭts#_9p|EsTUێU^h]%u#p"z&MwO}3?!2U/†ϸ%Uqa3TZ:/Go81qwJ#oN #tpڹioZE,Xϯyp_PQ~iu?%|$k9~=-y/*p8s}!dr5%*)BT(5P=rG0K5k|c&Y:/9 >J]FXjx &܌@K W6{,N`!4";[t\Q(DD~ϟ'|š _f+K\%;?e?/}|pܵ}UF<6ѽ}SmCBS Δ5dV]mLS߬-TR-  #|t‹]CsW4p8Z>dCd[2~Fub}Wn`ܯH#f?7-jh TSn4qRNFBtMAW+ђP@ c-=PvX,nc` |j03#8^e^| >E~$lFT(^? 6E?Al߀+OےXfNU|Sw+G6LyB=vJq%qu!)=at@l1t "ϥwN$z*2^jeS_N#G:ݾ/;q `ߡAw y Hlg?Xqܷk'N-TyJ[צA9QBܟ_+>^WKׁtn _|& ùh*Qeb<S-B0i^LlKNy¸#zm,)D!$,{=W,&- 2YMddEYψ0!ٌy.e~ @WX VHc1uGuSGU!.B 89`K;$.Or踫>0gb:rFCxl"Ć=nSC%g] Ovp )qCƍA7;D>D(;w ƹlFUHH :'SEZ+wb^罟<ӿo J77ẘcn #ݮ*oZ#l~Zk).]3~h/|Nu28ҮBrTq8;J달:d**FF* O$)tcL̈pF@R#naR TƱhq 3vl+=W.:1ɦ"&U1$Lɨô;Ƙi}INis2Pis1iiVuʜ9HDײKO(N#2439[U[!͋A0o~TkvM;DBGZ` .ZUT~#cČM9˗fef-ۼ97M4׈*D-l9Sީ,U#=VW"k((ߺ%zYnqIAgm^4b^WGj;&Ց)]RRbaz-u`S ػ߿;3TB,4Xt{r >Se(zs's"@oczߋb8;빛}(!DEn⛛g CwsZT_8u U43Uvoٻ9\{d/GO/EU"侅53B@©j%k;Ub/֒^]oX.~AjC-NW(rmH b 8bUO!՚_Pp$ĤO=fJzqYY쌼̬%w3CLSF`),ݩxg'ɛڽg}/'cQiaowU&σ?=8ӏMp*-ӬGRwl.Txx_g^,xo+ 4($鎤4U0;J^W: D+d'dlQW0 AQEEQQ_@w >T0S@`8:}UW/u~UyzΕNT~za|fWsnȒw'{NtŦ8kRc {/x2>/qdQiiִGqˇo4lӹ˕/&ޒ }f̢ꋾY@"wWLeYrc LM7~rħ^ҷUn's3{Mbbw~__.}L5PNThtwL]./QTb>,595'g[d[']Zr$'w!$8{+sGez;8=~%'#Y޼EC~_ѝƠGc9S@eN E]RC3oVw_eD%\:]dHv_6}[՛o$_b5]WdobrGJ+qeEu7AH{\=3F")ɻؽ~Ŋv׏fqpöSg✛3&@sghzV%%m <EBIP<ch:B܁`g¼ ﱐ@c 40 }$yyq0[%xIo<YIxtϦ Sy)9Gp U4=a[ʍ,]vv\٭W'1L0:_yȃ̺]G=+> gb!/X~w;g;{Bfo둜#kgŮbW|1Tx<[Sv8ĚݯG_/ :-)ŚL;,m60Oy9 vDXe/\܌]O@,ϗ/=p.śKJ #$iøO8Uqrha UUvp{R_>ñL=Ñ\$p$K^H#0rۜ eMA.C&X1kY!\xm]āۭ /ܬ'I)}AJIx}3q+LѮϯId_8脳1iL洏7/c9QRl$)٤nc\8ӪϟÒxRlhJ8i/oEX ^S*\٬ǓG@iYͦtWcTYj'<~ZИm(_s ECzx1 sK=x^Vvy9qnn ]"kk5[ nɋ 4q;F|QQE Nd/d-O]f |~m&(?HiĚ,'R%Ĩ +6kfi:K9JKL!#G.SM:R/ҮXo& 9A]t&:_8TQqAOf LiA+4υ[%eDkx^`xoPa_qfMF cxT e1.k~q%h诨-evbaCKL4lRBZMe:wbGTdF|>%P~!hȫt޲:wJ]5@A~s ߳؁'qo%!/4d2! |>calf wNzD&-p5h[~s|2MGU\8lv%ڸ.fW~d2!So]lv]g"D廢/vݢgAGdt2@TH yH=k~[^&p3#jw(8•i, >fO%?9'SW .o'M֘8kJWkN<-U˚Z^w@>6+d髋1m*B-mr <"#ة (9S OFIǏ߰a\Q7Dc6Mn*sJH# (2ɿ^UEKa[\QYӥCFgV&~2U8AN=sRPl6W09xꪫJKK׬Y˹9#@q/[%K7Gi-1ٙ9iɏQUb!:5πXFYYi>mAѫ[2QkV7t Oa>ڷ,5o-Qt8ׯ{#gY,QeJB˲nj%o3Rn$ 9|ILh.Qܵk9zn[;~ۡC3~8,]0TڰdKki'EUe ΥRieA㔞P 5V~Y;*VψEpTDɓ 1He2b4h`(Nn!S.eE-[vd:q>5lڽߤt$%%cMz.\ 05XU~iǫ*p:SƆAsU`gd/zR)NZre"a7 Z:жɱL OqWӧWDxH #o!ENmm!-[ȏ<=,tQT]v)2|3T uyPU`x,9K}KOSOwJߵK͛0H]ڋШquکoDx&O_= C}*Њ(Ӹ@FJg4~}p,VJdyP$u>ܚ9t22_˕|$윜2ga9d}=:8aɠ-qYVCMkz=MVM ٩+믤q5Ybu1(ǰdxr-e4>'&HeтٕU2fZZ{cl%0@?^P_'b mZ՘diNĊgq[q0DlfV%c-Sƾ\$ƏO2r|2TS[izpLd%D&x&I[_iS7)OuBA2;zt'kZdQ=)gtآ-8_.6 @&X1fW4>g_0>qaON`+O]/QA39f0t:SR53'wFdSo]lvm!]V.+ }mRϲ,{J\Tqٻ1d7ǵKNwE_ػE{AódW3!f /3!h!l#)dK֝p1)]Lдs]ٱՔ}^KRIAo@w;/ɽޯk9U..9Y=Rmo}6yn{m51>-狷}_pm6[_؄6f-H/$sfLؔ.!k6հRSM鱛\U[>搇j7>U| /Щ(K{/n(3CDۂM;<~R伻o64S_W_Ow"9)|@NJ<jm-\S[iZy$YjvdrkJ$'-2<3bv|KKyqoӝE3g;dq/ _&%[c=%^OU>~#Snbhoa))O&䥢g\<~3Ϋ;$$ QyC * 8uvqdggvΞ=ΎswdfYQ@x ļNҝG[ FH:MI'}tWߪwoxN)twy,;a@b Iǐ'߃u/f0&JiHHHn2gh_[Tw%_t4\HIl2˘ f < x,U,&bR"r~s^Q$UOu_>sRc?: xAW 400ޞ.rjo=quغ pWsUmH9Lt yހ(9p~ƳMNQ@hq<b6\K F.#@j8y\QxMt 1kJ ,rŽV,6Z&*+?M*PIJCѨQ™c'H4յ8;ik%[/\ms, 'J5D&m]v >0z.S% f,kn}Uν[뛳=\\jZq,bة?|Ww)*8wI˦2I aLE^Ьs٭˸omnߢAw?,˛}E[;}`ü,^3 t`բk̒ϭ#?`x\ou`2qE4 Yz $J&*+ AdF>GBxTMLRw/9Uiʖ;}BQI1Q*XDxO8ƺl͗i85 un b%ùdz͛=gurIֵxL?)%? PO{?{ݧǓ0JjgOu& Lƶ[@]%͠.>vK(w3Ybr9,z=0@T`I^n9CeZӍzUb{z$rՖy8UL&鸦%uaO$ JնVR\ƻ RD~D"SlK~+Wﷴzu2TlȐn R5ΜWm?7ൊc# nN.qp W\}ߏS=LLi9/ڄ'mq5.g w sPo!!4hG#T]fc3xwĦcȓY}$AȥDByu{;73…feY\&(XFc1|'N} I6ͥIA{G$9myh/j5(]piaQ1Rߚ?mA9Ug^Ve5gܳ7|ukQTWk "j>e]pʕ+ xC)O w97z.s%n}IV<Tz y,K*U A(dR !qũW닲>\ɶ֋9sSLa` Ę7_:YkLMT?J$qh4{ߩPiKo AQzs LӄRcR]k9{VOx$%}}}EfͶYCUu5a:Q,{s`&6CL&Zt"B? Cp. e\p8Oؓy|BFxo CӧF dMWn{vpʷ}-pw( 0 H/vC\.A.}!%p8n}ߓot5D+B 0L8~nM~I⨘Q(< =/aBK%e[7&<}5c[:fLCf0J!O In jQ]:ABurD"% T앝n[mJ30 0qSCb|% 뾽=L(l E >ǶOk.ȶhppwwsϙ]%q&zOz6l' ِj"[QD+^w˲CfnEUJX<3#"0bӋ_#2eS1~/\ &fF\&C]0r pō!8‡B%J9@*gh^<2aZ $`L4ܵJ)+Ď|Zk˳htwwLoۊs:k?Beφ>Gi}_iii3^FưxssT^+;o@~/Мn}_bF*3 <(@!ujhst ׌Eu 5G>#3B P 2Tzly\Sٛ= K NHhV.%8F`1= $BWN.A,b8\o׀5Lu&dCfʪ;-NgφB4r@]+ׯ(`[uK/p\h?y١MݵkO<_9d*%# {Q/8>J(VfopZ^5r MUDJ-O&J5r3fY>[AQ֋0AӅ1T\.Jwrۛz)1) Tp=9־tRal\Hro,\8Жҡ#0$2%KAFdSR~jpbєn8/5#Xd>A<+ xju6;RV˂ys M qFZjờ %r2LXB zQToW2wz{Nu1115[=w?RW؄!C̼Ҵ2-']Ś<*vռJNNvy}| p 3 5;r\R)7?s=IdJ*M2HeM-mr\P(JSR\j.'SwU/Qhsss2cҢ1DI l2>b.O$`y >98h˗.՟= W:8`I)]L <ਰ戰[&Mum&{ӥpitcvA/v28*aXdYǎܹx劋]+jvŏz1|G(p`@ s,5I E`(a<NJ˩d'U2.)M%KCҬAN|xKXj̆ \.Ӿ)ޖW옷ͱ.Z' C {Oz4fV8;x?H =mOmHXhIDL&ӲeiiiyyyǏ/,,4%'ja%ŽL әhbQCk4 䏎UσF l=17QgsV$e#yci볷8k՟X {m۶4}aciii/BA:d2Y x& @ ykoݾsMBq`WsK^TNuT*ݺukSSZd$jZ[)hH$˷M6TdGp<& @ ydgZ<~vt}ïq#jX, go|1LKL2Cl2̓ /qؖ⢂!Ѹy橎b- C ȈL岵+q8\e`@o؄!z'$2QLc֬y\xMuQ?{gGu#!F}ecl06`֦"(Ȇ,6)l%[&@y9RlXlmXktHs= ̶gFX37_{spYQn_7:dڬoh2 R`մ|'= \S PICX dBz)s," O- CqI?猗M9S%? g euHhJ]&^`ZYc3c@r&lXH1HǪ\[Q-MYbLő~0gDMQPiA"+5'S̲%;ոFj Κ- ݶ0&=`I9Edr](&4GVjkMŁ59F|В9ZLIXg3 Y+5Woj rkRٺo~0j(˩ %*׻(5D_DDN6 P9aWNR+-$̔҈̎L_jV9TQ@,~(QR#2s.,wm%$|v2(]"#T^\ph%N&{&]:1ܥZTʥ6)|O鼤}SHJCh s#Rs9M5YTRjN ʖ&g h2 rd=9Dg@~9s~榶2WU^VVY& "U B|q֘fEsl|kQ%pGX E䱍kWgY{O'*l(,ᢗO wju]A= =>8p_1xז5VӃV0{%šk/)qa8^ {dpcgxVxX(dy0 ŭF.@ъ& G";=#8g]Mބ80SY{$tuxt5[**  =;sCE:L60O4Ɇ&}OzBJ!:v|#?}]A&2NB`xjjZ,0?@ωeծR(I0_ 4bٱsNU4>?3Юll!c<}%+$'j)@Є&itl`"f!m_7o|ZUmߠӛĜAmUME>#I7l7{QOX|!بv9& >@z-hlu:)E,kֵGj 2w_5!=F!Z Ο2kR #0XPh256c]|ZsQ1i`Yn.[!b%WHSC_mO 4-]2z8>=xط躞zl7 3բ'e2u:*\(W8q[64mшpqU?yfw!aڈz},z`tTŕV\I44gKJS!Mf6mڴw]_MRj-e>Fuz֛\F6,^iyMS&o P[Se6t$}cba;z 'rG1(GaNc񀞞DLtT<cV,`3W$#2k" M =ghpfff3Ř??}LK)C3++e˲kJJ~r<1LE"Bxz CbpLb((tpLRlrYFG_;T. [mc& !`X f@Ni3k *٬bp M~ޮ.m0X{~l_XkoL< uܺ_Gp?όmظ~;n,_E/HQMzFA3)A76n<7tU.#G,H '"8DN_ i#]&NhJY$TI1O0gA\җ&4[nn03~jX^pt˦ F <7bt8 t}{G>{X? LF۾UUUy?.3ov{Pi"F\ec" Ǜ zE`$&DBυ9b2 D $fq—ʄ :!/MLImDB%^@;hB4W3^ap0|7ܾGׇxm~rz;N<Kzر/ ڗ:\frbЈUW[AR: a3HqQ#D5F!B$(=ɱA">OF}%n=$ъ&k_׿ݵdDt58~Iބ"9?h@6c,гݸ ̈́% M&BI_@F} jJlE_eOoK;(XcD+ۿTUV036.=qQm0,Ž}ԇ k0m+믻چ+tF )+qd5 @KeKy766fնvwYg}:iAx4&80#ԗ8уQ<<쥛ֻO9r<`/)G922)wKy˪ "H͢Tg4ݚz |А&ٺuv]ܶ|M.z$~GYn *cA)xB#ZK7/\e gwԭS8:`2m2W  0MfQu ݆<$9 Vo+ =.DДl+n|QMZ;oj-3A`^-m6{Z?_`G"Y(^dBtC< yC3~]nRcyN\J4 bi&9 7wٙu+zeلTƓd!ٗhv)+`2x$i 9GCvo8|I?<8J_OOOϩ]3ےuP` 68R6KeV.K0 wf 1U^,lHa͑²-밤f4gwoZ&oMhޯdLwZZZVZfmze2rPZ|(VŶw0\07,^|V=cM9NA2-07XK=VPȴUĹ#Y **ipG_]챊/?aRqbA8Xk*x*++w >]vme8tz  Fy[O i08ǑLzF][6]MӴªh8Y*`ѐb+y֒r!,?풤@L7:9Tw9^ߵkWgg'EQV?vGl %U)`4vn۰g?q, tuwm-u_fT#qRU,@$^!Y{' /D,QuRStɐХEmmm#Ww ^VW?yg]kV$IR/%9=%:h$,Ne5BH|02yQAEm=II >q&d=xEIꅣ:II|iđ$Һz.%;wTZ, :ּ&_}+!KhDwDDɧ]tqFdyŹ+NL)&N"g2tDprIJ"H2UMFSWorw~=&CӞS)+Eq21k7R՛]Sh4l۴>rrhbďWhu8G,jB'7K[B1*Gmju?}3vܔϿӍW6Lx\Bi)0 ,8@2q/Z@}xK,U?u-b!J e?(N9 '  XpdټKD<=-된XYEVIT,R O'2\/\{' BIO# ~`<Cr☓kodR 5:AR'K[DzqkI(\d-g'Nz$QH .Q 3(H3ۓ(~~U`dI?#8ddJ)J^`\Nxиˋ6%f:p k9ceɋ*\\\Y:!-Kl+i5'OLXAk,{Indž_|b|XHI4 #*QߤHT2Ib_Dj kao1 Mh/FUs7xHT I Kδ>1}Hp/"LƖF{J,H#_&VWSqDkg y+`҄.C4D\0&"~,":NQI%/dvkp,U-iEI\2j":)XK @蔒SYpcpsN}qy Di1UaŅW1J8eCM /H# NB/C uq< ]OӀK]J d%9D1@J1@,d0Ȗ $*\PfEXM'+%^K? ķ1sׯTs%ƍ_l"vdH} } QZ'yo5_V`'P|2dX46:GkSZ(`q4>NAȱ`0\X"c$T>*_L8 %ڰ\qҫd-<|6WXzrh)d VCH*Nz-rJ qPR\k5>'=\]jX]WRU%&:Ν4.s؋{QVԒҢe SdP2Nf4)-ʟDH"e҂0dɺ)HBʈ@)SqD[Ie;H ,ƸCpP`vI1bY9*+y/^hܷjpJ :F':lz<Ώ?{Pٟٴ U;Sd10VLi4O޷/gEEos}0D veb[5ʞT߆ 䖩'q~:Adx}8caXfE, B;7uFkCaa#_>+<ӏv޲n]يEצ3 72-0E!N$kxfH^Ԉ?d$Τ[Za'|@ke>FF,o}nk=PW^[_Z'4owut蹷Stuz:DfÍ}a ~(Ô'|O`Ӻf :\z; 30 5]Oο'sOZ P2/!@ CM /Fi0y QvЛ||sA?Ydw4ѨYY gNhk9:N?WZRG Gd\Oz*=gx\QZؾ7ߪj"=ՌztԔI , ߌz|\[WyNy}qjlusXϻ$Bî Δ.}~n,+Y&(޽eݾN_(d&|늟>{QMrlbQZIC"B'~Ё' ;۟zh[a?wYfZ XA2⥴PɠUe-cF$ɹaI7XZSUXH(C޼nòxkAum3}=ۿ[ YR4"ƼUy̖wisr{EFmSF+K6v~Zu[{#^< Z :5ɂ>ԟP$,N#'k^V)ʨu:jv9gl.?ujjmZiXĄ u"ϑO9 ٹ^2Φ)F|ʖ7Y7pYUDf^[S-3Uk&Ͻ޳yuL8|X/'_q/__ݨZZ @ATTl MQɠQ:.F''Osrgv1a_lMđv{Y lA:]yl6ۖ-[o--\u:L(tn_1Đ0p6=ʑ5&f{꟞p}1lwMo?~J RGҦ_}eQLLLnC`ફ7Bܙ -  *pZ=|tuQqQiʤ ujQn7P4 h|tGiH.LiK.Zg]-c8opuux:ȺU6ֱlxfr`=ἱaW6_彰@W/ ot}3w2- (*xg}5]k0h;:# ko$%obCCf#2h^(6LZp49h(,k8~/?xsovz}Б=*P(lZ7Kp ]aOjftu)2\Β;C_捕F$gGBgyn@S'ތ.tw ڳgfɼOrZ $ה7"H"')3zYRQY5v#ș0))^jѥl0GƆz'3]Vd5m;_VCt6%tWHb#C|]8p@iy @0 DbѾ,(jK'8쭚JJJZz>e-ry# =9zfٚꢆ iGQd[7?qrEcF3MVKe;¢pw@ζ!Z Ċ@QOV0g8^ژ%4$˲-:Oh;oS Ɲ%k7">ˢ`BAim2+utkҥ5\.r[gw%3Z $t@r'+sg~?Ej8Xfv=ep =YWx,lpFk(dHN_wQTyUϤtB^ A "eXce䨫3 a}#8κꬠD# !!It:m+ՏtU~Two{-|fLMn޼ns}}>u7-ⶣG:KY2wP:p@cYa/ _NQ*J`!zkw 1D6 cCiA AՔzԍKW`С+{bOO Z4AEEE:~Y}csö˯A}/*-u;"(h4b/4YIq:GחC@>pܿ`ij,)(icɁ# "}[Z-Wmi.,\Qyouu'v3&SACc2cv`G@"_M.UWU>/;:8;L&JE_|3y& n[j+EF!,˚m/reeeSSӡC-ee׾*X4i5Y[[ڼ?ӞbSahb%hƙCOy F:޹s''wt7&11@ 8@ٽw)ytYU>`_\V+Aܟ.Q߬f' D`3d^}w?9fM:Njsr ټm۶x@jCr4{ ޴nXRj+ruĝtLp @<96v d]v ,=FVN|1k+)]>Mr'yѹ$W @GA ?99 fHNDF;K|F$@޺bRFYT'`jth+M1Y.itFKfd 1!8('̌EEcN(L06,3V-bL/u%ې f&;tNV$ljM|xPuݕBK %[E*VflQμYji'cޡ)J6.b,'R2%y[=cQ6[dďIK2@gE5Vn>ӭbϘ@ٓ$SҌSTR-McG €@"y\EE qU]gbwbր{$ D@/Er4[ @6mN@)1wy&מyWI-o"o+xG{&އR[- G! VXO&|}w#j% $~<7U{#3u$ L:dKiّ*1Pl#wM=2~RjB:Wގ wN ){‘|DbfĤTNZɛ !cd$KwS3E!KGR?dK5\J$rGLrnhϫX6?EF %IӉ\$#޿%ا\V˚TAf-0~D# oD + DdzHL;s6-;n"D#[ (':]/œ757y" Ht2ލ1  7?kdj2 )bR.Fnji="4}rŜNXZ%J?җ詉i3Z_+u'C [r%[Hq868=:L漋J M->gZ=d#k=rn2X=<`@R fGwYcoQ,>L3d(Qo"ٻQd.vyڜ sխȦKr170㵐+ %2O?_x dtM 1o61Y-0fO4_TYLZxnE`xOs\(IXYmH"b',6i @bfUdgSuY'oDY4\&&FJK<9dHOAHLLoJdR׌S:ˏ$3gƊR($Cd3oLcÌ':ԟILi[d@6-4&d1ms!9h2-x @@9AhN@ȍ.ΜZX_P_j.JK+,*ڴ^¬zpq%bJmQ.>@0'MQs`BvllҮQ>uk>C?ߵvr;O|45UbFPE={}yjBIm,@Y;ӈw)^2cލ T>û};ohiBC /Mz9]6h]9xBȅJ8rN^]yIvq a/]~d溺IH3)1,*(<ScЏoBt U 1D A1{fLrC!M {Hx?\7LܧA_M55\@ia]X-wWG|A~*g>5  u]=un ɶ@O()  Bj󱲙 duf`X_Zi$T'w554?}d6?0t;\799WUUe9~=u_-$IJݬlo:x%ͥ&D*TZ^WgGcҮ#gO7ߴ\^^o!Thk J 1<+,C@! MF#TiC~5i[O똧_K=pU< C8A|v?a'~g^p{=?^Ko ZnܯW T#5=Օk&S>N` }}gt`#n_l_Q$QȨG%&'_9? L6Wnܬ>29<-")## xˇ1J! MVUOvt{%Ke+.[#ǘҺ *J !@%~vw~CA ^T4<{ŽenY~cej҅jaꦴFC흞/0)y[%N`ܿbFϝ;U>ə ,u˲D`@s)V"t6ri0,BqTn `.&kn`y[,z QS:.ed5w`._=}?Tkׯ뿽76T80LyZ-k+&tAa/wkXxZkQ "QÊMnhGaZ*s1ेGz JnHدjnVL@K >rd+LLJ}^>zP+n^C``K:fj:)[W]sYڮG:|>મ_~kB=Zq$uJ&Cy'N|q ͵JE8蠶\<ٻť%EWok%)φzZ(-U&ҘےenNHLuuW/WTX ˸]O)51xyej(_pY}_QwZkôN^Qj83Z_:yBɅ K+-s||llth&1sMӲ"NsEɘN thDjy " dnO LOO|:=;obl<7y5@4"ԘT[R_Y\bq:v{.7CCCyju PoZZHq8AӐA.)* ##GZmeZ5KZ<&ACäA Y"0#@,4|ӣoۋp}%-7ί1 ͅV̷ԙ(J0Ap1 iQU*k֮ټ;ʹcc~"wO$Iw_(4j"HnJPCnVc,lT!!-ZaN5D`FHYh2sInh.RԴi4ږhVMl߾mXW{yFChjX[T]Ta?}'V^st9]Ӹ[{R9_o=%Y-~k(5I`* x$Chbƒ4,2V4jDjTA?W!LKF!s21s_,٠fBqԖ+֬ K| ܾ\ic{=;i?Ư|7!#9wģSyk={w}ʙXhЫmmCkTciR$AR{ >/ɻAPA:[/@hXݼR|t `xwJ!,hE }U MF.^甎uGcHc@|k ڵKd]eFcҡ:a99bU(ԇ&`q¿Op` "fLnYE%jD M`@MiuyEؙQqg{o;5:l)[jٲ˫'۰{qlC9@f @'T!@4rdַu\tz`0pDR7V}4xÑ.1PWp-}ٲ2c?y)Nm|33 D`FDAQ;)aQ_fL޺bNFjN1&듘ciIU$L1_)2vɱxѢ3]]/b1aϯ]yu[u/V4bc6KsJ𭪮~%!t Ixxx#p`Ϡ:g9:;:̺Ό>xq}8#; >jLxD@ȃNAOU]]JS}_V}^@h/ @4Zb#H8[FrOl8zܑ11hj?GA>ɅP쐳(񫐄pkȢRUF1IݢPnB+ Dkط^! dkֶk:4<7h}`sp(szn"y9B.cc&,܁GBPoU@Ru >H(|R>|+.iشx$VL&`1S)h5=^o3W Ͽ˺@=/l|cCC4<Y1 ˲ DG#^؉ve1HjK2{5C K.o_ SU4lm] HfW+GIFB2d.ӂE o̧ AS[s2&d=l|Fy?{szj+iV/^w)+x/{w`9sys=yY&#o_5 =s3gu\8z`d @ @F.k .VmğpEUw:0ś6mz{_͛7g¼'-?V{!Ir^լ=w׭|g/7,b h ^ڂ6(/|4/!kOxK̥I`ѹKټqFqʤlۅ1J>[mzPGJe:aMW108%H(uiV1pt<ɥ%y|M+80" @ph=& n_^m-M jchhzRǑMz hqx >WsG 8p2&c@L ɓr] u h b2 @}` @,ŚfU"Ry2mTZSwP^lE {^+ 4mS4k5½E8BpFMy2UTAޙu58/Y,/8&J~LF-$iwU*1m{ВH&]=κ4e9/$1Y` &pqRTRB`Bv2%Hj"H%vΟ2^?q!*6=/gIB9*dNu*;;ܡ@L ,}]Ledԕ9qL Qi Ƞ>ѱʽ\` Cx2(ic:rG7ˈ"(C{q \\CBd$Ӆ@ƒKdQj./XyH28!Lxч2:m_7p %%嵊m &@|oYfʇx;B b,ȗ3֞O&.18bP4Gf-q{91wHN-ʹGFo/<^BT$CJ vT +-Rj\ʇ AI3v~"2cصma5 l18UXNbɅI7iWkQ"3z15$U ^Jcv<1;L qtdc#aA'_Bckqx!xIȎ@LU,rT Q8'vQ8+dv5J)>Ԕ'HTy kkf%HW)ھ`d HܥA @ K@{N5(U/I5Vtu2#7w<⭐ I3c7m%i(q~OGH_!]u_$l޳:h3}Ӛ+;{egv? Ő+EOXkț.Gv@CSN!]p%@Rx?/'tDnT/^8bڏCn3p@b" I4@ $:p'׬BoDK!DC!&3]=޼ |v=.jt#7Kb':p²K1~Bp (ŷj.1Bw_whH 9<xt0IP쪫JY#[ӳw.?dN_{{{h|q2B.]7|Hy7yb m^~z5R[ t71No!bB/0NXɱb%35Ʃ=? F$ǹKaUap}uo{oH󨹟;KL-$Dy3ÿZBO57Ԕ!e7~BӆW~IJE Ws,(y&=h=b?d3c`!m{"Q/m.oo.Mc9–8ed.W7/MR`OjlyO )_p@"3Si8|7'.-[tEve/8H(S*f:S9N0e슥' Eh V5\ɷN/z:\㌒xlF =4hmy<,w=P_`&HϺ/6|`yi+啦jf폾~D[Տ/-|{m6>xF4t1,ð,"ںK$7)5@Ԯ[?Jw׽5x޹emW>ug"bqb?~vrihLM5Ʉ&W[\u;6P>5D|ۦs<t΍~ |+lLށ?tkGJN>F\nӯeuZYyB^_swz=wWhV,p 0]afp#%8m0ڬk6P}]uVNGv;V"cӗ.XX׮&1097w<}1䦙:-֜ԉ&mt"0=.֋nJ&gP>s=eXG,k=20mqÙϚY@@}Xm-"+ h)&++)j"iN`ΝJϚU |BӉW==],M'M_s^0{wȿ@- hfXb5-þDisNFdx}AWMssJ'd2i3*='Z|qRD0J?=}Us2M D#}vu4LŪm&p4YLK?{w\G}|wYu18rQh-dp3L)I:q;mʑaLKC$aд8bZLOlDdi:֬{;wYO]B*n{] ,/ +K |Z\+Ki;wOQ#r0K- F&#O޾g7yY=  wr_]Xk&&&FFF }}}oE^:bn#\ 3FhmB('iT2)df'+^q}]= 9klO`(!i>v!9F9/l1BR&bx^堝4sqlug|bl8˻=7_~YO*R}g~_e};xvoU7ܚO 3=CЬF ahx[ku飧Q4c*Fh#Z5WΡ=}ƆNh{=4;~-dc.墜q ᤸ87;mjzg~mU뾶j!#x6%X.:=7C]`uடzTF8tC,f~￟?Ul].Wrh$'=ZeGEhɼ^o?16r00' x~ś BZ&|w0FΆtFƆ]ܯo--}?i/Ĩ@E#|[R 7.0`DHV^e^r񙜓s:_| |E䗦&NѠBz+*C202)h`b WN&#ӳy }};юVHyV|3^YNzY7ZryUlώЍ0Buun;;(bYD"%w(Ww'6\wwiusgz^<r,zio  _RH(U!El?ryi[83 @0'[X[>3b _~vrqcOj2G{wF4z̒++S5Huk8xҥ #O$x-UV%N v577˫HqfMÃF/9Y8:Jޠ$y ɺ魥G$DqB* wK @DQXP~)KTkb0PZ&k#4Y%S"ZwEl5fyJ|R s4855㳃r!b񁾾pŭx^{jd88W|Y5yˎttKQ\yExNQYY9< 4xxEy7y61sNgxb#B5ya)#/3R8K#UJ)kŌN,*nO }W\f%rGrs&Q+,t-L^GEs#m0nUƅc\*1VJ$Xω >v0N S0?6>\p:mq-rpм+W^t }馹[~Py0aA%<1㥇e) r,%%Oҗ0銪vWW޻ALPԷrupZhtOT"w'h Id󮩤4hQ)mf3;f-~[7>;|4q04'fJ91$RS(~WR!*hlτkt*U]T¥]_d*!a !B;!\(HkiQ.k")QjtV$|7YŤu{(C5iVZY옓I*[O/%7BJsBBƋg-iQm֚UUT(J-M+S MEE199k׎KkSo@%e6!K)Ŕ2ՊfƸ\9`1mUD^6fTE<sPhɒ%޲ejjk_|ë4dB8;)_|gwJԟ̤ei2SPsf.:Gdg}7[P?N&֫߶mUjdBP,%h;FNф FKYDnFdP8Z+[?8$Ėy>lU&]¬7r2-W_q*+)9;{ĺ}EEEVhG^w˖-蕖 %eNTUC2aHT_ô ҫ"~a:t/[C;N6*{a՛oBBzeu8f̍lbdx k:O๶-/}乱3X4R1v=Kw]?.Wol{y`7a2!BۂUP(mzr}QTZ&z#;rs}Gv F?m?v)y28f c rxf<9Ç*(' dS!'E.|([e]Fy#}uvVPz2!'r2!'5NrڔT66SWw(F5S )e70C''Sfl#s֔_ڤ)JeQ͔B2"|4,3 i*ڹ"0iMY픃Q6+Lch]mrFҋmF/|ۥVڽkfIg0'Scjz&E<;jVmS;wEO]IܮnHͪHF#n^S]J#OCMJwQij`0tX䇥\f 49]29kT@zl%!'r2!'r2!'^gKr}֣aa.:"ToFXnO(qUoJF J-aR r0!y2"}!UH!keXK#AiIlV6JBj;.TC1Bk2z&敍f,L&lT 0|6ʔ E5I6iLZtu9z'g8F&4ɧ I>ʣ"lm@c( u\_vV*fSE+iG;"hG-IjѦI5-"Mwd3IbLSk!eq%J7.2ر#}G;taNFL!̔YgpPd]O&/͙L0qux'r2Lr Û7j g+X9X9X9X9X9X9X9X9X9X9X9 s—y7rkyi"fJwFi޴s$iD>#6s/L ĽW>:",L$ْ)Nbw6IffLAv6 ^iYV*K5UpI Q{GecRBO$ШYmF[4?ՐtG@MhPgqe[?͐M )?z[* Eñm+׭]2.R+kjW7A2oh3"8yJ4vyH@Sv֔ >OS dL&/CfYہZ8ҷkx4iCGOΓ|j:G)兩|i;nۻ90DoA DrrVr!75|dۢ/ Š( 2IsAM;_GX&;LROOG4&mf<|n319 _u&K;q+`)H&?b@O{6v.\UfuK%/}UAp,uaV6kvKh2VXK9KsԤWHaFTJrk5X+w\O65|}H60y`3n|flOJ s/?K |>a(ۍdM&'ēdd2x2@< LO&'ēdd2x2@< LO&'ēdd2xՙl8*bm{lp-8s^_@N\ 4^j`+SLS9ryquLm{-{r/OdDK9Z=1WЏ0o4+Y5HV;xoڼ<|xۮ7Z(޶qF_g6[VxEu.ssn{L]R먗Xsx3"3/Eq,(7^li|cK6uV5k|í{@#JҹYwg2.lm۱PRF6OyZkƚû]#Tw5@fY;AMfcdGԹ =^8jE0;WIWSqf ^LwcĈ*mPjLDƾO.E`]g]}k^7g|nܞծi*_mn܂SdKFQ:Fy <| (Ug=;^֓[[uj/qJju>MQOoy_d&KY3,Ɉr&kGdS0ت[M$#+ēdd2x2@< LO&'ēdd2x2@< LO&'ēdd2x2@< L:-GхL\^bd0yVlkdh3*IcI'. , x2@< LO&'ēU|fItUe3ݺq><z&"+dd2x2@< LO&d_[?)<d?\^~WӋd0-ң㯖ףguW@0sWFp |@< LO&'ēh$zL!8y'z:]/~yxߞ4F碳7C{؁爽r-Sӻ&!Ny`;פI\Inկ2?`IENDB`knopflerfish-osgi-5.1.0/docs/images/desktop_info_log.png0000644000175000017500000012465512346515440022417 0ustar felixfelixPNG  IHDR1#tEXtCreation Time  QAtIME :\ pHYsttk$+IDATx xEߪLɝpG$$ȱh4 .] 4(±au,Q@ȠV$!!\3W=WBȂ\It\MMM~m\Jܴ=m6ۦ"rrsW, lܬefXЌxb$N,(U*ύGV_,neK6*Ū ?^]ͯ$?,/T~/IWik?9K4=aCs[֧vmQK[5 xvG=Zm֭-V7- o|0 qp02tVt0"rj`|Ij+F.Ζk&? U##tsBv>Ѷ{73f :STC ^MSi31{گ{GJ2wd^Mc#ʩDu`0k ƚ\N:MEQhB  IDiƪ- @HZ3B7~HkNY\6MWuּF|k0b(^z_אJIxg?IY搦a2,|]t#'/-=j2[a!gz<ؔKϖSy vϓ;{}DaA|u4T,nUQ8dcï}wIoN /N.(h8v50S'*@c@h_ aQGl: ƺ^yd/M'S !"v/CGμ#v1]`wJ"\w;wB 6kw4÷mZyY.Ep/F]g*N~sh:r9;{lrY`0 E:JTU{QD%аGpR#F׈>gӸ~щ84H+yqJɩFiI#bx &܄DKKG! 6%)fAOYM4IYC&%vs˳C{ܚ9{:|O!_~(3JG:ƿpjә hEI!29ږEn?RcǺhknS;_2*p8i~nZM*_u=Xc^ㆭٙ*3||i3x,O@Hh+:.:T(j3_j6(:sۘ&:DX'mli]G>Gٱyؤ{^]1 F2!F$m8?+[4KʭUݗi'pТ&˚**7UCVO-g EX#!rJMA4ֈHM u-:)Xrraa{U^^^VFor'',bsʾKtJ GLyePZAtڌmOZ Yv(z 8+fkV`0*_e4a߃>[3g k;V<8=7LQB/Ovɵ0ƍMqKsrSǦ˜:HRƥX,]b"Fck7LKwL}_Ç !2,xUȩҎq<ӳ9 GpAձ5bc6t1>8RrޕȤHrbcĂiaY۝2b~`*y76ޫMdS*xpTɈä#jl1:+*2y5[rV,**.Z)VffvaEyþ_qOaF2u8NT7y{>FGvbjôپS$ ]ׂ=l#wʯgO]ΰیWDR1T|B']$}Rɓg.{%nIc]8P;5]{uষ~ewo {>1n5՛`0Y`Mz๋3۟xC&!zaFMglufF |x]aG>13K%{cF{g+~UbC9Q.M&ll-.::mqSӊ2df,ʹ͛uyyփ?f4 (ˏJb ]S,"|ۺKacuШA"{G_W8Oup"}+ulj{cx愀Z 6'ޝB]]i++O315x! /_=m@`yW>1=fp+J0xÑM9y qKv!.E]Y/ Μ: Ճ?6Uvoջ๘ `xdU I/GӗڗdEUY2$~53B@©j%k;U/:^hX.~Q#,Av,4.yTDe ~2Eя55t*bqce95%%VT\Lٖ[^~kLTJ\]OjDokBtO^OҎ#Щ&puRGc2fJ<;O7vvv>*xdvoc,| ixOb =da>޹GQ{|f_$D I E!P$Rj RoH zQoh['PoE+@#/y#kIdy*?3ϊWB p >kKޠF Zl5壘#ߖϜ־Xc˓B悥]2==![^;?h닢iSHQo^)lU4M*nI}GUءO\0[@'._?"][TK67*Zɗy|܄K2 .ͽ^Y]7i=#ΈS࿰k\ҍ :ɑfVp0;}<7n/m= $'YcB;\O{k^tQ‚\bld)" r,cO D!)B~. քiqa " qb%I'YYx\?Ývin=sy0]/*.p<'<_cO~nWIn4ЕLM=)vB L ڎ (a2Ζg(aZḪPwIۚY)=Wk8V9:gφ n=4^Gu^e-~"%Zr#~Y.﫥˛" k4pa2)YJ`ȕ+,t8T *L 8q3(Νr\:u W\TiƁAp$$fߦ dXIcQJ.q:?KkyW/+xgD B)p!!*3xX!*;ߞ]yKɲywJ+̺\.yu .*2.?( yD&_EiѤ IW kf?O܁-GOnXW./i26m!wk9%]mK48+ &5 ӭÙ!, Mh h}3I;W4(")Ѧ&zAFZqچSטOƱz_ۖo[ESpmB$BX9EZ 1+$ '.tF]ngzzaɈ 㝾K4'Yp˝'iM$ _ol8xp!@4ĩɲs;jܸ @Ў&#o勲riVL|krClq[!͸i׎u(akIL`k2*#Gb̋dS7c_鳔VKK߱Ȓq{jlJJXҷdY2DbLj7%;.BmC~8&s;ם棖M7U'Cа.'|KK?bSKW-.e6|;E=YeW|00 1/dc :Nm&g_4=dȐ:߿OwP(d5A.*B-[*f$'O6㧒߲>}ƍ+**:xX˿=iջKJ.&/J eUbI dRL7L*<ƦD**Y(F2;1fSα19`Q_,EA[;]m>gL222&N0=𖭟/Bvg iՍ~eueee=i[AAAg?WW<+˩Ys#ɿգv*%R"=J!Δ4.MQepY] tӿ{e%HURnS2-~Fl[EE`U2CGwЍy`B) x))bc[N4_lC YF3"_iRC}yZ dL=Qu4W""+*͙=+U*ﺫO%>vL* tМ28iwRdD(Fji&bu k:N?htB"O',H>D=a ۭkd]q9N*dÈA"hXD8]%U-'as;K鯷,ZR%ʄ2Ux(1~I:ggЉmhk蝩mZ_@ASv"}dYdXFǂϻx<׿_70)a DN'ҷ첤=Қ~0//'>;G|ϥH^O 0zq]O"oT֘$}3!h/E5DۄK~4M{cLSNMF+}i'%DP?ƛoWJt:'[\Ȳ2!r>`OX8bp?SdA,EL˒.۲e{}ݚ%#]{}"iiiҚjRHܹs85Yk*q2%OV4EUd:rRNEM]9Y-rZQ䡽Zd?(IZ30U4}H 7,3.( 瓱,k{'CDxA"W8#ijj{ek%yIYzĥ=zd|g4*/uoO>O5}dI87^D98S.U۝0|u]F,+:CǵQlI*\Sf`E*y 1 2dNk AqJCN-KY߼68ѣԿPnxn$5B6TJP#K~H2Нџq_pKzq#nJGa`|%,lIU?P} i`'sʭq; -6Itc RߌuyY$ (pH0qEDɺ5ɘ˳=Hjca3L4;Q.A(ApzOVS@X>@rT h q%'$MRFǂϻd3v k˱1eLޔDL1tGYӝ LQ:ajF\f uT|nmL0Mē@Rlo,|)hɮ-ͷO>z&l7}n Ǽ"3doYf ۃ.Nqt 8 Cϟe3UaH 6~I3cYl/V4blOM &+qtddp~͟n&_Iv ڧL]{5F/&mKdM<?&t')72~4C:ı!#{o{않q< =vWD6t](]c ڇa IHɿT&fvnnH#Fr *_ViXmvL3ϧU ڡ,6x))ArhqjP{e6%(ʋ7Y!}2gGFu%Mii^KUL).y:((TnA kQy,lE)39d zXUUw*zuQR+qG-j+铛'tZנۣ/ C2{_++w<h&"/Y)s{j'wK@7+b GmqHOWf^lj:8|Mq]/XZ2vpoy\ToX6jكu]. +pͫ^"h@rD̚#п6Zae rWwu's~UWZBkCADŽ7pOgE(zބCSi~OisǘEr~sK r8qdlXuhv8҈9{?9Jp9{twNmu;novC3V>ΰa7 qteJV3wd1~ֆ͔;B#{ǒ1I,(xa98>t:l /~y34?r3̱ *+JmjKR[*USdA,n{Ӷ4{g 3cۭ(:` %@L,V{zy/1TU*۫"߁WwƙhB-\<<dBai*~O5)Y9 zc~ 0Z-O`ݕ':UyfF0UpAMC&J/x%w=pn {6?=N"WQU%hvnke7n&rɽU)#^DHNsUʂ Eԍ7?^zoqdkZK6E5wcVL(5k+>X$.>}Vo xtxP}}S[̓ATǬmsD-ԂKT y9ΟmoSM@?/` @ڨΞ6ږ UvմTټ,2igϞܟ^2)P~K?R0,0 Qyf$KtVnmc fD2$[tX$F~^I*}"@]xUþM]<$){Jt!L*<#@͛ve#=,N8*RH7n%A >|) , ]W^@dSƊOayqZUGT,EķKiu͟5{!K( x--t9ܵ5' :K=7)=[淛PD"^JTPؘ3>Ғ?>PRxّpY险yKZ}wEUW?[nxzM#"$(ږ l$N"6d&"M7[y:yVp32Kmg@tՏbV$rIJB UXmF71dOz/P``Mb„kƐOVZ>1L*E"f&ւW./6 T"0hJ8}chR,p 7lMcI],KL,Eы/+SH.3-s 9W eZ')|Mm̻sάh%rPgs X2J$pժU x'Yӈ)Ya;U{rv#_($=sV[ECIcvƲ@!;Q)nw9sC>!+a6a2XPڣNR1}V륺WfKMy mvNĉ~@- .MY BQQQﯕ JmŲP !!a%ILp6%5ڻzW/Hț9;/SP%O&+rr*^r֜!LM*9dI2TDdnhJ pq7\|,Iqm$bq #akQ?q7(NV+eRul9"SϊĤTeɔI -܀FH ,@`T4ENSgn2H~-,ts{׎ "d)Ԓ,$bj&K^tx%>ξo~鶇o!').ZJQT7:UvgX?e)j ^kbLqDŽ#|2t I7J\a(׬ˤ8AdT,qL&Jηv.y ]+p@A`D"`02SbK8r#Q{gO17ڎ1OڻhF2W"\֮^%ڂRTz7-ϛo;=+V.ߴ>iT*4w/^;&r?2 ;LqמکOdYaaEXJ,@b$#O_FCs"r5B5$$F0!VL َ$I-ءk8!erld*m mfgb,"`#_50nP0)AezfkN& ^zO/3=sݫ6n0<4[~n|u/HW6`7V׿ z{۷OV/, 羱xOwM}}W8ӑ/ 9PxaoM Ĕu!؎=cDIBldbX!*M!WYn^:٬ dPu,_?ݳ8;[;[z Pba- Jf \ n/$V)K@,͍׾=p W8" Yυ'm'08Ux0LvA*_`Gҹ" Խ z'd<L lr<*EvӑTXD^&]A9) VN/B9EK,X07sv!f˵/6~S/a*xb$55MmkCzZbM=K44MQ^.&k2h7v~1jގmrYqC!^' " 3+6ٚ/}J=Πh!-PB*T #HqTh" s>Y>3j-6&rLmO,y&cs '/ E, }BDN)UWIRL&92K]]F`NE2eA_HVݸk^aY))1,+'p5g0Npī킉Z :/5*5&j_>cFH빁q'c *-^$6> RT:I 24G 0F\ur^N\.X,I(HaaOd[ILo,|mR`lڴbpƎNy%jynN@Kt_;.d{;x:=#EqGD O1v"wVA% 36ۦ7Q",J?*vnVn[Է^0um6MS^n"\4#K}IQYFu쥇3uw6  f(iŠe,74NFE(F:dmv{N17 ( $ba3?CM6`_ַc"'8F O%.{+F Ix`$hrT O>zB kBB" Qa3~P#DBHV`C`[#2E$&O*a>?uU X@`v~yaY?Øa4p88W@wut6dON<%HT.s$[x8h+d*,NXqd@y9] u,d>!c{ǿsCĬ ܣ(Fxc ם8B@Cc'ifF?0\V:r􃳭?e ޽GQy3[,ٲvBpBBCl` lwݥ]^{n-pzP¶K), < o'i;-ْŭWc,[#YIr<;Ww|Kh(ǝH[nӲ3 xb||>(6[źu[xLS<pp K?2|lʟRd,ư,W,jǦ<ޮK֖t?z^f"Ze˖1zFQ\RYhDJU[:V@cA0ޥ*lw / ~wwj.Z0ٳIN@ft8zH$r21/7O ׫=ޜTdZ7o,w)X~uJ0%8ʚ{Z.Ep">|}MyF5}&!3бoMXθŐÚIboL!/,#snh'L9hr"[]#w) <"XOhCǾ5a9#wd&[LE#-Mq)#rj~*KWLz[}.rMcI4}:J> KQhzS¸>IzWLV7Q9gM艊IVH9@vXSd -%Kq#ly>9GԒڍ5ᮦո bBJ!jD؄!}愇0ҿt{!L8t.!Pj9j*X=rcoJDFq6V$ɞ}q!QA +K2"W_ڡ3<*IW!?Db*O ܻt2>t =5%jTF$NY&fh[#u7їs!2`~=t#'NR]|dGȝDvMaϱ[% H$>aNbqQxkp %95# )$d%pa%M#8L$*cNdLuD:bjƓNgv-˝ƊY$:F)*(xd_MrNJet2_9]]6#,!C:&ˑ7BԒȅK/ފZsly!t Nde˵Ni+*KgJN51nƐVq_lQ[}HD>$6_B"2%F,L V@4v_]{_&Bd$YV]bd*wfa]q ,wfRC;&lii9" r2 I~ yYTlGWTJ+ 9,U8j";qiq;90rb9|+4-S"ݑ3]Fm58Dg^<#KF ]mdZ5}c[Mjo8`f?'In3|(vSԋuI"KMyLaLcKL\f27'K !&r2Y4cfصa5І?;&I|7(Y P܃?ۊ篙ܻ!?$i>h%ZXwwuްTM39ZOߢ5mW똜R9cwJ :j?ub+<ͣ{tuM:Oj ܯ;XZ`?1"^JE*R\n|GZΞP65pDY֒"\gaWlgk 5C=hˈ#ĭJ EPm`/i^}K nTh<{ٖ}]>?sזy #*hUĠ#&`ߺ(8;&У*+C H]Fdf}k> 3\`/7^#]3'O>j+_:Jx!-]C T&K.f`֠(jn1뺬a%;lnQi}w724P\375Ta/:O[Xn-T) % Gá>GŋgKjL rl:S-e-_Ti5/e%u+Z konw0jr +Ԫ ÌEr ^~55v KTjn#{|UV!zz::T}]GwdFZ- E'%tyF  qK4w|Pz?][]Wk|g͵s[ut3 ?vx痮Y76_f]-0k,lwT,UJ6<\0N܅SVWM ?t=n=NG} ߫t4G%+Ҕ.,n((n0j޿o_ _~`0 BBVlTL!&J1q`j6q<֒=rlQ,(m[9MoJh%Z ?Lj#s:.#r?ؽ4 VSWGSOQ!{/ךL|hֆ4g vޞUWn#iAQ`lQ2UNHYV**VVk:jUfհ*(Q*)!*@τ?@NLXɬDRi~e*棷_n߽m5իG R7wرgs}#v{ܞZcw}?~l."kmq[XY -&eb.8^V)YRPB;cD-hD$Z :+I(h3s$thˈLT]\PUr˟\.~B}zpguϜibH tO-zwsG}TfsNbqm(X%EhӪU eA1,Q0U)(<+4}R)999UZa£yBۥ<ֹ ֓?GDoߞ ܕ`Zj Jkag[G`HAs+re oK|rX&TԐ;=TFn8vMLj0-LJ81O(f1$٠K]i D6mr:Nڊ^V\R(s~7v[\ Eр23υYX_Sh=tT]6KÊ& tĄ?)hsj1hSY90k5:}ќovݽy}D% s{qhJ09sJn9x߲VR p62h4!| h>';E hj=×/ e 65go.Wīs Кo\;j+_tw;!U>WU^ի*dӿ[ZJ$Oi9Zq pbu?lUCcӓ;?ni*R W-1D2bg1W}sȋ.}A PYFEOH$%%%yyy.nki2#{0lBjʾg>q*ZLN+O-4Ec Ű>k륭K~rժKFT*N25B'Ҙ3a„ 68΢"9sfLhp0CS>hq|NzKu%x8SX:ګ# ͧ(J̊@H]zd5kԐ$h)%v<(QĕὫ/]cژadںڥIMMR A15gqS,{7i%0Q vLiS:L-ޯ"o ptMJOӷ[M5'B|@I.W: p411>{ kƴ @DdCq0@B!_hȗ_Oyf6BWtP3b2AL <1 &01x(9K"3PaBD`1,!؉0&chJ\)|g, ]ˠ, (ތ *(IDb޹`t|%wrOd7W.x6g, 5HE"H-R?/" i7 &N$ Fw{[C*Я{l  1Ӄol3GlyЊ|B3Ͻ@ zɼO< "Mp®3Q. z,@ľqhX~,v_$ 4:]&:KUB'znؔEa{øC]]x;s' QR犬 F(XLs0V!8 ),|Ac3<(e)4j9 Tw v^B' jp~0BW#t1YT"$p+ۖ-O ALW/tb dƒkpm}濅@1 qM"-s2b2h' ɉF A5pA'S(Y^W|\%~vtCz mX\@ |?"c2-jarR6;1=%GT)qZ-c?>v3$%;yѼkίA TXR/.~m׾Ʀσ00 AM1Y=XעsNnZM3VtͦS1=vfr{J.=m[o;gwz͆ib 5wWE~1;M9wHz;Dj~2_,~}=o/Z\PQQᏹ' {h%g! ^hMt1͖5_!ZBߩ0*.u e>p暖s7&M8\MD$4W\Бo)ﵸo}u>~vinSJ'.7͝;]iFã+4BN>ɼ/Ʋe+V\j0%>^9<@ߨБ|)v>?0J n^&_-:zCJ%sYE!)S2NiIf\uۅ3IIO28֎^(GfWڵ8L ddu4ww|SҐ}UݺuoJJ=hNv?]L!X@,V[O!55?nnؚ;Hz@(1Ʋ?X-YLR痗\vJBG\#gWߑ|~As\4G]/Ԑ@ƸXqmӫ:$F5צ+ zVs'ΌmjqȚuM-vjʹIq6C#D (AK:ٞrY+r}X'F" CN_v͛ ̓q6c-ݽ &F!D,4Ne|~EW`Ο{߬Z.FQX5 p1 sD_kϟ_TTM7 ӧO= {dVA |{ ^ځ"A (߅Ak|])dAމS9!KLaX^"iDu[NkUj(yZjuw&&2b/^ WR^KtMO'ȸkG^w{sŋg&iOrBoXHլ/rP23-Q_OϚ:es{:CrdWO!)a \G}}ifzeoqMnKkgOz@(d%%[p{ǎ|2W\Nāߧu\Ѓq(~{Acs1D o6 59!KLY\ԥ)3jkGvIiqqۍ6DTs[lZ险8N76 Mwj4IeG$ɱ.mJzu3:S]3 !-eBRւΚI$%KBe95r鈲QBSkNjkk`'$MVm`낣l^R9hC/G\Љq+MD1Y~N"I;3$3g*cnv^FFN+ -[JKʿn7$dݰzIQ ͨW)*Z۪2&i2Fvewnț6CJb_H~\fҲqC/SeN?wLz@(1?s /(2>{Edi S`$ˤ;MkM`;Usg&]VKggGG&1Ĝq=U+eBξsM5}иj Z/Z IyOe.RRJ7V._޺t!}&vvv)S2%gO5QA `X7QK>c}Twu&CQ)Fdr,-t׎KB 78]Rjlk+(JkNd2"8#רi0ckM8gZg:wbj]-Omq꫷XHFSI3){u F^7LE_}t:rE PAt ~8J|Ɛ>! @G^"0 356#I'I ׬+ݎb2TFJC^QלyCH*X'X7)A,B 1ԟ8Eē(Gi|é/B\ٹ +'eemAGt,EIiL-EIoni{ƛ'/U%\pgO+;Zo\; A A(&R?2hD.ǹkȝ.'(e7I0e%A]6$cJ$"R&q;Y2jdQҠW.9gB,ZxDJ)⛏7~`yAƍfGNU7!.kFvӹS?h[+bX;pҪ>m)))QRj 8ꀡ`ZD3qdycMJIgsmsI?1-IBJ1;BFaH Hi?)ה$rDRMĸnk9}r8/PI7Xx=w8cXpi?wmfz u!+=>)%WaC$On>Q-7}СCBWBF`A.r(XHװ ,2czX|f?%u?VjRҌ2.p9Z.ֵح]tLNGmg:2OxuUWQ}> `"CPp}3OP'!b@xeY :o$q eh|A6`J̆%:.QYꤨ (A8۠]mr]hnmV[CI٤Ω{b-gA9~/dfP!1Pᅰ>aKVۖ뉺YrASH1*a^r\[<iT$0i))MS(Xuk;\Ch*܂b۵ ¶.7G%Naf4}$٨W}<۸_{ڳ*}P.'{ dfP!ǾjW/496KQ81s'\9Ȱcr^pLXA%~H `t]Nf6=}ܬ"Ac64EBEyFdpkNJxz<*!=lUż;̐d*ΙQZ.˞TIڻp"ɏ j 07ڑڭ/n/K]sV*8Z3'_rC*UR10S(ޱK{Χ=@h&b~CEta74gQ _homoVxX/oOӆ^c\+zm= kP!tԙɷvO<dUVq]!KQuE6ж;u LVJDmm͙-ӈF|J$Hhʸ?ėWR)1 z{KǕAwfY  p_|՞jժ+ɓ'>|?^}Mn_ J#z4$` ~Wɹ9o?wqrMzX,>E!R"_s5 ,„FaVuE~vvvYYYUUUyyfeyIvl,4A;w=k2֬;:}E[oY.-:'`[)ý;_4 G3 FMWyn^n@t(77wÆ lZ~ *++ Cً~: j` 555?¶ngYYΝ;ڐrF֗^eoT `,V4oZm4e /,we*ulkzF6zZ]o]jj T@ L0',lϞOBP>y?4T*B!?[: FMNQTe7?N!zZĹq].BQ׊ :ll P(߲q}RX!e2Z棧б3VeXrc=uAF1iblr] _boZ8;V@ L\pGecd܃ {pr2AN=92id43gA,AoNSA_ sk?%ttLdb:G#}6PLOF)ڰkc=d.FZ9ܿ&R#">bE[ r]j^ I6H}KcOi?/ ?W~)i| $B~2=yj8`.'&KV*2 (g]/|4}1OݻHTiDKnf5Ϟ529`E'g1BU@OxE8PB:6*|$okBQao~04?:AQq]^@&='C51T;lev$}ބ?02a'ڈƄ[^;sz_q:="f>qz}J=Wə$u1ɤ~t¬B(J$6' jvY!@Px'bp]"R C1Ѡ^Y(fץdOs28B.ia(RYvzcY9U*Ggͼ6?/ 2hļ9SC!f5($dd=6-aN:{ dpr2AN=cǰ<swypOx^e+]p0_T  '1":Iax|nSqdW YN$]0#?]trτ T1J&IcuD'`POcD~lP1/8=UIJ5Ы u}X%C|$9s[ɰ~@z$Ē*. 2:pI6c?%9&.[ pDr͗#$KKeŒ+ r24D\__ۻOjb1aXQv-]p~\ojv!1~~S,f1I堅 u Hm[H&e\~J|}fM&\..;ys*ܷNU~ɒ0I֠J}^%ƏHKgH< ΞG'XB,,hƁ&&?(M:ħɹ.h50}PcuZV T*Zt==='N4iCbЧt0.'u$J^xZoo#kp\GΞuyHkv{De٢N$ˆתݛR ;PG$jUlLTfU]} ku (ɾ:S(\tV^O5(j}ܚgԶpv(J$(L1;^JM"D|ގӎ˒ä9PGTWnzɭG3 #:d6iuŗ /v=r;7O[8끵tP >7B!BD m]G{?Y-[^ ?4S_\Dj1f$Q[s3ڳd"4uPd[c{ÉMJz%&OF#jPi47{W;~)'x  @zg[/+-vW5&'uuSl)+-?s>gJo :=>ܜRU]gZfްzWqʴ7??lLŠRɂnD*E$RĖc-HO]M2Kés'[vU G.֣/X.*ŋ͘ Pg5pجVbO=9Y\^dr% !)q[ B:= Z# MSaG|پXp[oN/cH}F2?7%Pd敏.Vթ+,*S(&BP፧/^im'ͫ+ "Q+36s 듻jt\˯].! BǟUAuv x^ &OγԉxYGm)Icg "Bٍw~T÷CBAI32/VeۦK^qJpQ*7U9>/eK ͓+ᖆ=SrMID Hv"ݡ=2j`A+W/ReN6uܽ `V Nj5%˰4(4(M>Ja)yD:Tn?]εn;lv%߹a(hT}V.2gAyVukBO!;  F<B>D*S͚Wu\,(! I]|IoްjjK+ e*):_rY(W4Lv=I$TP(kkwqL&o |Xtu5}REHaP5{~y$"RT4Ņ-&O5WJM- 9] 6bק9SO8I?<̜67+>y̹ 充yzX.GPBҒR>R}+.b.1_YKmHsSxُO+s jd5kVRfjz^455;{g?~;͸.) Cxtŋ~}X<FXVk# x.J2bČ+L+JI,?_}xK0 O¼,0Ve\"c.^1jLw_߉#NM(l϶=+."˦G,sGJ Wx qW\V@ L,g}T* uttTUU-?㞻o AEN_r;:_Ql[o6bDIZ;g=8J!Dȳ'ciLv{]Nۢ@?g`0(e<@EM($l+dxFF0jT-ޝGQyUUWWIw}_1.Q2# ଺*<젎x88:aD$B I:79cfBNtRUovUխK3IV5ıhJ."0^ahaё*0$P`6~pr?]^Tjjj$pE=[rg 6^O˛DyKyѨ,Ci(aE#0\D'5D%N{%΄%F"$uP(R"M&,$ y(=w&BOoO*D&Ud줸kd6%qzo7?NZpco+ ?tA?a`۷o߲e$IJ/)Sck4j:g-Ͷ̌d  GIaX;,iz4]0*![Y|~OI *0$PfD=&%'+=79;+`21dyU6Hۜ(љ#X͛BWzᦎNHL\Jv!eo_@i T KRSR.Qi9!*: ?F߰doVR S([bҢEKr[ -?8w9*0TP㣖Lv㊒ڳh4L&y"gS=jO|T5Z & r$IYJJJ3{Uhk떻 T إl'|MhQ^xuIzMgz7Nf mk !'_G'J0Tt rDfDQX/I:Q}}w~@z2ٚ5k{?MLΛQz٦ÿ6nhwXKIU:n7ВHO291e_##LT`(GE.e 'eOw\,~Ӫz{$53Bғj66{{z<.QQrڜ@g DN*`|Փt&FLMMyTꥫ-wfƜC$bT]2'ݦV2Mc 8T EQ%J3g4MYYٜ9s/=RT`Bޅ[d).*M qQd$jd'~bCƻeę9ğ7#+rJb/›i`osaF /32T+=Y2|n# 3ȩd (ȡ2BU@0oU[r9?-:MdA~P)n0yt~Sדa5:>ț:u2/LK'Pz2'DD/7/$^0 MV^CzOEAr_@c (/+dK>go 9 d+tГ= y}d+nP4MNksݓ5J a =ijLjx'?GGnV:Zk8@y @y @y @yԓUvQ^\3:)ŦyY%[W:pR}Կ?yV^[|b-)!!%)Q0J@lj$wfRZIJDV%\b S:@iiY8x`f7/[xPoO8j/1-6S0 "e&DV2\)i~hitA۟6t_7DYzAN1r۟+e /\tD;@Pz2/ jabm%ߵ77)?W.ONQ$5MG̜YǖsV#};|LX}O[X,QղLffVBUϡD!9$wO8[Bɤ#Z$%g'zݎG53ZOoHN֮e-9!g =ݾl$͍gtl~n-ƄdѸ܎_~pF~N3uz}=WY__&Orlϟ=Vp嵫u7,b!-J!LrţI4szC).3fD EDonؚmMns9DDp,1pl$e>-u}kn[4[֤b^I'ҧћREm?W +o3ٗH7Q]^n.DQhPn^yuo8.vuv|][ͫH*@l[<¹P| 9IlYAw8zlǘMi.#)ŔSRXo=}?o>~nnQ-^'oQ)G$7mӧO$X>;y)dS!-&z/׸||Ҍ$k%?yKfgńUח%$!4C(Z=;>O?$Mu%QVqv iu*Zz2ْ9)e :0gI;$wk=%9,p:ӂ3}wVn-s --m u[.khָ:kĬQ3hQu& ۟ʹYj9<5*?{G\bwRioɪgL.o^!>,H`*,Yz4'+AX֠Z]_]zN?';;jmq}ʾ7..!>/,I}]89..B}\Y.&/4FE[$,zBP&I. Dnvm'չsmƾTRr+yU/;KB!=dd<"RQO"e C,k봬VaԶF͖:V:[W5+DU`)[]*m)}x{'IVA{),wߟVаEQƠjukiknNYtXxVC+"zgN"b^G+_Ushɞ/t}Aw/qt,E0; Nkfp204tvڔG dZB!) ii/"凬%yҽvZ{w}?#߬`D#=}]O{nj_XIID"O~؏;{uk6m"'Ё0SkL~_GJh2G9O5ɺy|=WZJI%SI^( K~SOsLHdL)DŽJ@K'2ũk:P*$uEsJY"kx$;=7a޵_ILif ;}vm7ޖN?w׷F/nD˖]916)JC2)͇.P"$D V,i.?[2 6á9,+%R6`3 ǧy?)ag(?^ufμڶ9e5RF*|"LBb"q⭧gnϿ?Vg<362>>ʪ{uZO?'K\Ё`* ~]r+]}Fv4?~͟ %BB˯, ELumӼ]_ĖL*]&߀@dY僒3Lzƺ_9sl >:O <)XѽL9yD￟f)q3VlU2od(υ㧴Xіn+%ؔSwBم<$h_9)O 74mn=x?jn*E>LI@[Y9 >NJߡwR[ؙp~缎7`Su5/Y&Β+?Rd)!;<*2׿[4\L 2k}P/!ȝ4VY9??WF[B2ϥ{vcfUB+j۫SP]<q={_x1Y+&z^-Mw,kooW7QDpeMԜ,Fv1d4)cʯ҂Ҹf*#6n[+lkmlyִBmZL՚"47j}jM2,8M,r=CT# aM|JʴزToogrraaŽk+|uJ L Hii׭QK/Pg>+% R/̟?/m|~|~aZ"P@%xzG:̣fg9GiW$@YPH% e%ؔJjr` ishFheڒMWk y5ͮNH?+ ~Q۩hw¦myɃ 5\ N~M򼔐 /*abӦM©3/|EW޳\q7"`Ё`pȧ+~#r.zjgb9_NMo*륕5j.(iRGZP77L.6e]hRv>jUi(u1n<ۑ}8-!4e+ՊYd47zW!L&'+ %-5~n:#Ihg!H bWﯩǟ;?VၣUe7yݝF9G"O,Ё`EJ󳗿dd}R&%&mRՔB1{, 6$GJ. g ˘-(TwaGŚƦnkSiBu6~fl7!TB)|Z7nC?|wALD"g}W(Q!X}q==±WZ'/U s+ɮ֎tttlW:|#):m$dJ6'TX*B.WҩA.P#-+ SjuYlvfS|i%W ̸FB=5#4oV+G&J89?>JO$쯘UVc}RJ& RB&W-}L@`39<96><ůw4ڼzy^ZyuOLLر=Zؾ(R`9.1Ƅ~n{x}?]P51>[c,0-fQؾBxl!BrxV{dF]ɘ @sG#͵U?y& A7ynꪍT2.~>YzٷV4ͧw577}RVoH,;::?9ԕdB`2Ҍ|' 鑑OiiAzX<o`P*?c$BQ^1J$ r2E ڭW_qߊTT9u|ݜorGPh˖-ǎzRZZ9y℮ +@P,~%3.(XVhUIc]塪Y^7H?8pUV(z[@MLN}ogNviK.[55̱,`ץ/ uLBB%<|@JeNJ`UJzD]Ľn\Jt0BP_}S;ԏH]yjiGv37_u+! ,'TVTw_>]sa)0z>u Xl>:k6K?%_W6oxӄ2Ѻҏm* %X]?Q۲N|Qwy>ȹf믻( +_^fXT׭x'ύO& ItyFM$۸YGBW6}āLA=z{}mYk4%wNu&(T:H%'~#|(14lߑOIo(^ pPvlMx>(xj7U7-'S`&~CNi.z([e]F3`Czw cҭ^ p1۵wn x9x9L76SzziڥRZWWT֐t]VݝZ2Ӑ7<6w/,P ߕ*q&7V*5@2 s0%q2Ԣ@{*їp-Rr2;l!GW,ꤩ֕FVBҪ遛Wr!y%{ut{hujyra € oz&[ʌ:;pڒ4cVߌiu菻)'c-_Is4 N_{VS=mN4& 4Θdwi`zZյ2P?pJhQb:j_=x%;Z푦hj.wovy˅V2ūצjvq3dC<,Ő8ݪjn+WN`U',^əN$֙Խ=S}Nσq8VISY\ sPsQ[-2q1\nh>xQOb4%M5 "oۣזFXr.P ߠgt"K;ٗU'yrYI(f"o4ͤ|d'd5Ӑ\2P(t;e'S^I >OՁ dVr ;c@ ߭=dCN=dCN=dCN=dCN=dCN=dCN=dCN=dCN=dCN=dCN=d޳I?ʂݨ0ӝ.\7SW+3Vb[WG3#"hfv/@!2ɤ7➞cҏ[RUV;\4+ݒAqqw:ii3_(Þfh"Y}֮7]iE)ԍٮTsD޳8shwa<'ٮ$X9!xf4U:Z,:?ӐL{NͳPw/or. 'ͤo82eh"ܽ{K2eӕt~ڒ+Lߢi ڕV̺EuiYL;gvڴo!VSLCi!`2/Pڻ}Czw $>wᓖd}K߬s^Q^X`;lȺZAê/*Mc]b0s2~e\53ɌՀAND|*\|̯][2EDbZ8%/ 4+i=,im $j4Č^`/Ō^Evi3Zd:KҶN3}1xr>Y ٌ5~1'+{ft^`͟f^q!!"9bH0*q2r2!'r2!'r2!'r2!'r2!'r2!'r2fE* pG]Pl섾 o ip7 0&Jt,DءuR_WթzyNO99USNId2x2@< LO&'ēd3bqlm{lp-8s^_@J\ 4^j`/SLS}f}yLm{%{r/OdDs{==iv~sG~pY&:/Ѩf\Y[M4hulҪݧplezڻxk⺮Y=NIMΪd@;|~?\ɪ,♈ dD@V1xL$#j3&X{Jd2x2@< LO&'ēdd2x2@< LO&'ēdd2x2@< LO&'+dItaG٫d8  LO&'ēdM4qv~=R_&{},oމ&d߿z}++/Gpx^g?^)ͽ>-v)bOyK<$i?9y+{?}7|F|n~u-0.124IKFHSHVlw|fy@WK\Vb{b>ƢC̬Wϵ^ܲHֶX­iͲb˺tԺgԼrS\hmu}VTYiuadcxyäʪӰܸɳźҹԻؿüúćƚ¢ˤ̫ûͰĠŮΪ˳λδԩѸ͈ʝݕيۛϢܠܸܡ,H*\ȰÇ#JPJ2(P cx@dP8%@ `@܉ O U Q*MjӧJСj 눯`KvhY˶%L2iBxaX# 2`a( )`lΟ@.aҧȧFjU֮!J/[6nj[7޾~7CǍ*$4L! x0S)2%ԏS2 Y iY""!x'r!$o7pCER1S-wsy%XԙeZحvٕxoFHH^{9QF490G `@L%Q 4dB0Ap!p 5"%rUEW185x9OXC4JBAE8Vɥf馚t駠n"ꨤrbꩨꪬ ˫*무-뮼뮸+k6F+VkfQ;P2",!P!J7tͅSr)t#N7~ %Lr & 7<  &̰ > 50C8 C*BTl 78<,ğlsl칗"^x(r DG)>p/BH lhglpm7mx|߀.nxx9؋㐛 [ ؠb `砃8㬃Ӭ5+3{M8Ξ촣=z駏r:ʦ%:;p ;+{ ^3| @?<8pJ,GN &һ'"ʂ@:ɟ2 Uuz:5+} w0yY`7PQA "^%HmT70o∡ gH8̡w@!8NHL&:PqF-Rc2hL6p#9mcG>aHBhlxp;d tc&טl8<yqsd>>Fl +HLցn"(L lx` TqkL2d!M@u1ppaȇЀ`ԃ 44}lP |QmnS:OҠC-j&ۘp@"gF`kOA]0?8kSU*F3!g`ш2vVfW5(~B2b70kNwXV? Q%d#́ *ȁNBP)XS%NGra2r"0i!omc8[^vyı\k#m!Ap̃#>!}`#&爍qv)61=nE,Իg9 ke1q>L)tAm,^)sSD #K=e8jǮu"lh6:׹$6 0i^(QFtž>pA pfbØ0>Xycixp8p*I|XG7P"GN<m^dr/ۭ<>GR#H=Xw ycs/$ms@v>j@3Q7A\)&Fb̠5BXE6xEU7Xwòr'y0ۍH:>܈yBG#IQҨƽ[TCu8R`4eNuW[݌ʀ< R<,ÏXF>}F1QK||xF>;}j1Yu=mFpX=@o|C| Zfm 67ͣtJP̀ ><*η.(f2ٲm5*3zC`q|bbGv_@)6tQm:y&. q88`O5FfSt`S]R`JM969J@D}o|KeVH`~UH.IP7=:VF`lsDsG`UF kuYKIhkd RGłEJGepk7y' Vp\ߔ|dT 熔 0gy|xm h5fJS' cc4Wb"oo.hoRׂeo@|; |nx`nuvp&p(rbW.0?[8Plb 6}` `elM pFb(g(gF ` \͈E\\[^ͥnf_GaPY`v`ft&pkh4TFJFl6uF_"H P7p(8$rc Rv Qvxu %ne-{$me`{Ƿl\v|5i}Fb Gu`*cHF`VYa@`EaIGpdYfyhiـn-?P-@Z"35>2%ClTa?0e6rna G`٘阵 K@QZHvց tFXc&I`IUb Y mptH3 ~i/P`9q zJCL?Pp =@5 e F 0iYPYF=t @FCGzKp ``'n 6p 䔲s9k*OY @}<@e`~ 0 }yzF9@<ТZ М9=ni?[ְ01?028]8J0cfDȍ$fRO c9 /Wid :`Wp9m8 J0g|t 5~8j'2  كjIYojJtH8o@؈u;llpF 50~d VP lG% KW CF&p p uL;yT0&` DbFzg` *nD נA5 J=0H`=%s0. G oIGuGyݧFM ٮcZ3KdqzkQ]x`p ,e|zF/n9|edpWYLjj4p6 kYeof` pq$a зP Clě]` >^Fhd╎J{ip b @ @9ѩkěva5_Vrsvd8si* @Pɺ=A@fdp yFIut 釱P+Kl?&:[4w pA^p Dcؽep((q{{dMJp PgGRgTm} yFGҠ}UGUQfƄ=ֺ0eg䏧#Ϡ Rw`j`y@ ~ ʬ ʗ= -Vutʤ2 vo` WGΐ FGo nF" ؃APYH JǶUB`)'ZuYu`LS\F Ŵg }H2xbr`D` R`0_i ets 0 N<0lFӦ^` tܖ薗?[5]d.` * - dG?F`lHC}ZM:m"hSeaY3ILr3G g䕰_FƸuu;wFf ؂@ 9݅ ReFop (._ `]fTخ{G ( nIDL6^ iUscMnDŌc ޤM]M\ڊ gTY;I\ay[kZJt@Iݗ`J׈VnqS6uftlޫ-sH IŌe5\B ع -tp\%r$ ߆߈\\`%h UY&t^ơaMT26 +yͲUb.:nlm$%ʄdܒppfܤVT4qH9XjH6$×F#i#Z=0 W{Q\?Ψs\ovdtpt6GRׅ>=  G.dG=Cސ㺩a .~d PMht`@&a<8~z @Y:pFH@]H<~9P MtzdxVFb>KPŦ0KG1idLk b= e <2)nJ\Tݐ=pIhmN_^pV @ J_Ya릅tHFWf WmX9GHspXZ\^sb?d_Aد~NTR ip`Hx4Dp,z|99>64~Xp`]@Pto?5-@@ٓnԌhHh}i]ﵯJf@ ݐ@ 2?-Zt?__Cwڿ-NX@ Я*o@?@ u P?K[n$XAv*DxpC BdؐB+:H0cǁAHnTdK1eΤYM9utSA((~4tF?@-IhYhWaŎ%[Yiծ kFxX]y_nrfcȑ%#Ķõu&];i[n\iԨ <A*Tjܹu{bč%ɕ/|*8pѥO융$ٍ[W7v-&N|D$>Q=B'xvףȞtZ@(k>aBIpA2@xQzFagCdA(A8ĹD A&HтeAC9)ぴQDeIaT>Y P.CNKP!%OF MػO>2MźP9E^9qC0f?a$MAQjF8#E>vC&!Zpl,OAG1ea٩8FTFQ0mF%Dp GdQ.fs{Ɣ6O!dGKGZEzi{n.Rg]Wv}껰uO.ULCXCCH5QOPKQt^ŗK0a^.9AFbvGkA^Y~zBQH;CP՗DLJQdJՑqz@-09>^|A=]]'Kr{C}ۏG9$C;)=1y͗fr_'S,ADL, <#Ԁ5 "nPNSqf+ )̸3/pqCm(&Ew^7:3RZYPa <‡uS).^>ѐ},bù nP"  1g7 (a`Y (AcBh T@(YȖEYQnEIVR$q%qc85T1櫋кI,03*SvC;͕JT|i2I :E\I!BFZ6QmN čp N]Z6\3sfa-R0ST*Nz?ў]"%Trq;UMx3k`պְyL7XN 4le-{YfVlg=YІVe`ԦVemk]ZVmmm{[ֵ;knopflerfish-osgi-5.1.0/docs/images/osgi-knopflerfish.gif0000644000175000017500000002513312346515440022473 0ustar felixfelixGIF89ai    *#5- .(#&-992-1:<<>8H>:JJ=0O,6Q+@T.Dc;AS=N\>Lm9VwLGJPRJMSVHVeHVoJRyJ`pG`~]M?aRPVZVgaRZ^accchf]ue`U\oReuVZRh]fo\eeiqskoisfcuzZkftwtb{skvvsuzyiws{{{~~}myk{RiZo^sasksko{h}wxs}wzʥưƵƭñƯΥέƫҵƽƵεƵӽƵƽýӽƽֽ!,i H*\Cuo@%j(5kiÓ(S\ys <8kղV/`͐UK(Uq'MTYիX Nj?y#*MR8Ƌq|iJ_Uڛ)<~D+*QzG;T-?sȂ3NJ4qP!s~ gK`CUFk j\PMm#*O.]B.?K/*;uuJgDZt7eTT6mҴw\_đ[[G8)8y4,m^]1G(pԂ7"m~(*d?# /iX(qJtY(`GSra(iX\s[{!b"_)f<J({J~`G]mG+s)KJKz^`Xp MGq+HQ=Zf)?T(\^X( yLŪ.9z8bXQp'VS~XDGU(Juu7ւGɖow1*}b6!_1apZ zXJWQ0֡(J BJzGD^8oX$\ECfGתY\}٣N-z db).frh ^L@;p 1I sptׅjE![i葍@ЋrV fcW!G{R)j~ D 3`A=C3mҀD4jԇժX*eG,|W8Tp& 3MGN1H0 3aGcqwMx^*E*V, i.YnU>٠c}qLg 3BxG2)MDHᄒmU&),, -CzP%!)=*|ƠZP_@"XuS_,pD0<""qkA6$ ۂ\L@=xa m(@4?aX{C+:%( T(8@(@&XGx>pX !p@hC"8r9BMD*^-^S5C+H[at%$p P|`@ V H a` pL3e%! j5*',R*8?k@ {5F@g%pC_L.B,ޚC+JB+- 9F @ F`ȹKpK5+<f,` "Cc>eZ{(v@Y/Ns.ݖ8ԴGQ;3;?p}>a#)&`UGKL`?{v?/F;yfP@pzPDIvĒ  P $q$'5ydp7@:Ё7}&`#'9`=f,t4F {_F#gF8Qyr`;3'% W2u0:Z+vCFɷ1:P=PP0#P??<9567K eǠ#8u3z(<@ `u`z%w\2ЌH% @Wz:!xx3؄:yO+05hf4d0`=А%#;6;2_H7 ]]`]01 '0_S@φ"A=,:;NG^d1gU@U=5=U`; tvcp+S8%;@ tRpV@ @ R(`߈ByFUt3Rёɀ dQ?Wb O087EQ@`B{C`pTp1fIUЕen@6`Wi(TS^`O!yXt1 PWpOpVgv` ܹCJt?7l0 ^L(44dQE\kc `a0a PĹyAp?t1tc!P  d=F#RC` z X@cQOHPuP8B@GZ{$3`v Kf``P``uBpL~7@,@W>A P ,'3/Kp  ^Z |0 0SuCLŃN7-'NPp@ekg ;Je `D  " &$c)sVHtA^MP PBpbՓBJ0 [dy(0QQvP P [ g:fໆ UwH Du$~BԎ}N {LY%D P lp` p ~7M`D-tI_$` f 0 Zg`Qw@S[ :%, *|Ƃ` A pFx7(>OwxM p hfK00p /|:$vpHCF $ .!V Z@n; f0U˼ld E P?F-FPX!Ѐ.I @Pїp<` WkPc0h@/;mG(`EP e M6{8S;F `5H~$.` Jy@h-  k i@eQ  Kp Q`b y m n0S Ri$, KKpV! Da {V ǰ DPO1 r]t6 K1Gt"0cQ gk k[]xmT : SMw0i@{ O  `teE 6 p pD0;M` ]$px slaCF Qpf{gap~0 f=`ih0" `Km "xOpXP _ .pM0C0- X] C ;` k @T[!%ͻfg  =fАdjJil  u`@> p)a ڐ/Kn8EAS@W\ ࠖS0 n (Up҂\ż׎p]]ƞ O`݃ae@%"[णH  0GSwP'] @ ׾ 0 Uޙczf* /n` Sќp o f3=@e 7Pw 3 i)p Đ ] ٰ\IJOa4F((о`q)6 0 kpݚOTnFOg Sh V%Fv bذ!A !=`$C hvla# \رR?uٓYMѲċa䈑%XaK 1McD)R*Ų4+#If%qPb*(i Jh XgoI|&S$}D %(A 'iQՌf)AUN%Æ ^a9!X`8_H(Ԑo4 Xp_ C:=TPqZh x lXC I{kǞi,a$brQ|Kw)ljdGdƘō5 I`Ӏ0A% 8!\4B,8O ; p@(+4p@a^ H@22Hj JD`"/G(/bD0"i *\#!B|1  D̂np Z?āl'B r@]t!M$MUcXg6Pa+@AW@@n.@RJZB4&n_qcTAѪܰ1d %t04@ >-*vQYP/r%x PL!" ""a'7^A30xZ @kgH,| U AAc΄|25l @42T49G?LC /ְ#+݀_n؎&pFg!2Bia Fg (AYʀ $=*PDKبFp8( P#? hC'ߋ: 6H` ]8B^p%h n c Q]T8z Bы?(.R< d.;)rGb p\`8NLK&x4;ݑg G?eXrjVVף{Qrٓ%Ɋ˅g Fga"[bKQA_L$r/E:DcJĂ x1Ts Pih!*"% P -Au H-PD g D'>щN4( : C`Q `&`hGo'z94hz wPup؁YQqhP|pca F I X*pE8CKғh089OB) m(s ɹ  K LIB_u{X;p;RhuHʨp @i e8 $N IB HHP!?) 0@#{]0|p:pÉ%aȆwXװp"ІN9b;bCwE(p)K(*`Q[IXNu:Á0A`9JG\uXԁȀ(P}|x7xV b4p=}Ȇ+Fi0oZ@!u _!mh;6Q*@XEiu!?g [Y79"[` 82{x, +Ȝ``epZEh ,ˇ XX7(D_X4`)*k$ H́{1hzz5({2ж:A7?O7uH4x -p=FXTਵ$xȇ\jzLQ+(Lኡ s<(784P^n{sp h4 %xCl ,;#MȆTlX {0 !7x/*`KXE;C10N pH{pp@"q8vP=JhT j5+bC㹂5pll86- |0UK{plPe;x@4pT@+7`*ԯOZG0*|:'[=H|hІj(_zzb(L6lNQ|:_PatxPClD+nXp^,q @Fp/OyKHa+prȈ5ȅj/МLRΤ~:uQ PKt7}:;# ;dp;r˅FZ7ǣ2ЁX(tF}T Y ^ ux FP:)=q0Mp)pTXDpHXHЕb3}Zp`),u`C`)21K%%HDz1(=D B$<(x؂1Bۨp9ȓ 'SȣxJ,ʥ4(ȁ(m )\-]{hqHu am<(X* 2Ȁ+]ސ5(NCpbT`2YmPX #- K,Â(x H}Dc^B]\% 4 YX`$!%Oi+_ ƨq:{^'*;;xѲNH+ZCоX}O`>}Ka`X^@GH*`Ye*XqBЫ⑅hȆ: H;b)`6B`2",b8H>:JJ=0O,6Q+@T.Dc;AS=N\>Lm9VwLGJPRJMSVHVeHVoJRyJ`pG`~]M?aRPVZVgaRZ^accchf]ue`U\oReuVZRh]fo\eeiqskoisfcuzZkftwtb{skvvsuzyiws{{{~~}myk{RiZo^sasksko{h}wxs}wzʥưƵƭñƯΥέƫҵƽƵεƵӽƵƽýӽƽֽ!,i H*\Cuo@%j(5kiÓ(S\ys <8kղV/`͐UK(Uq'MTYիX Nj?y#*MR8Ƌq|iJ_Uڛ)<~D+*QzG;T-?sȂ3NJ4qP!s~ gK`CUFk j\PMm#*O.]B.?K/*;uuJgDZt7eTT6mҴw\_đ[[G8)8y4,m^]1G(pԂ7"m~(*d?# /iX(qJtY(`GSra(iX\s[{!b"_)f<J({J~`G]mG+s)KJKz^`Xp MGq+HQ=Zf)?T(\^X( yLŪ.9z8bXQp'VS~XDGU(Juu7ւGɖow1*}b6!_1apZ zXJWQ0֡(J BJzGD^8oX$\ECfGתY\}٣N-z db).frh ^L@;p 1I sptׅjE![i葍@ЋrV fcW!G{R)j~ D 3`A=C3mҀD4jԇժX*eG,|W8Tp& 3MGN1H0 3aGcqwMx^*E*V, i.YnU>٠c}qLg 3BxG2)MDHᄒmU&),, -CzP%!)=*|ƠZP_@"XuS_,pD0<""qkA6$ ۂ\L@=xa m(@4?aX{C+:%( T(8@(@&XGx>pX !p@hC"8r9BMD*^-^S5C+H[at%$p P|`@ V H a` pL3e%! j5*',R*8?k@ {5F@g%pC_L.B,ޚC+JB+- 9F @ F`ȹKpK5+<f,` "Cc>eZ{(v@Y/Ns.ݖ8ԴGQ;3;?p}>a#)&`UGKL`?{v?/F;yfP@pzPDIvĒ  P $q$'5ydp7@:Ё7}&`#'9`=f,t4F {_F#gF8Qyr`;3'% W2u0:Z+vCFɷ1:P=PP0#P??<9567K eǠ#8u3z(<@ `u`z%w\2ЌH% @Wz:!xx3؄:yO+05hf4d0`=А%#;6;2_H7 ]]`]01 '0_S@φ"A=,:;NG^d1gU@U=5=U`; tvcp+S8%;@ tRpV@ @ R(`߈ByFUt3Rёɀ dQ?Wb O087EQ@`B{C`pTp1fIUЕen@6`Wi(TS^`O!yXt1 PWpOpVgv` ܹCJt?7l0 ^L(44dQE\kc `a0a PĹyAp?t1tc!P  d=F#RC` z X@cQOHPuP8B@GZ{$3`v Kf``P``uBpL~7@,@W>A P ,'3/Kp  ^Z |0 0SuCLŃN7-'NPp@ekg ;Je `D  " &$c)sVHtA^MP PBpbՓBJ0 [dy(0QQvP P [ g:fໆ UwH Du$~BԎ}N {LY%D P lp` p ~7M`D-tI_$` f 0 Zg`Qw@S[ :%, *|Ƃ` A pFx7(>OwxM p hfK00p /|:$vpHCF $ .!V Z@n; f0U˼ld E P?F-FPX!Ѐ.I @Pїp<` WkPc0h@/;mG(`EP e M6{8S;F `5H~$.` Jy@h-  k i@eQ  Kp Q`b y m n0S Ri$, KKpV! Da {V ǰ DPO1 r]t6 K1Gt"0cQ gk k[]xmT : SMw0i@{ O  `teE 6 p pD0;M` ]$px slaCF Qpf{gap~0 f=`ih0" `Km "xOpXP _ .pM0C0- X] C ;` k @T[!%ͻfg  =fАdjJil  u`@> p)a ڐ/Kn8EAS@W\ ࠖS0 n (Up҂\ż׎p]]ƞ O`݃ae@%"[णH  0GSwP'] @ ׾ 0 Uޙczf* /n` Sќp o f3=@e 7Pw 3 i)p Đ ] ٰ\IJOa4F((о`q)6 0 kpݚOTnFOg Sh V%Fv bذ!A !=`$C hvla# \رR?uٓYMѲċa䈑%XaK 1McD)R*Ų4+#If%qPb*(i Jh XgoI|&S$}D %(A 'iQՌf)AUN%Æ ^a9!X`8_H(Ԑo4 Xp_ C:=TPqZh x lXC I{kǞi,a$brQ|Kw)ljdGdƘō5 I`Ӏ0A% 8!\4B,8O ; p@(+4p@a^ H@22Hj JD`"/G(/bD0"i *\#!B|1  D̂np Z?āl'B r@]t!M$MUcXg6Pa+@AW@@n.@RJZB4&n_qcTAѪܰ1d %t04@ >-*vQYP/r%x PL!" ""a'7^A30xZ @kgH,| U AAc΄|25l @42T49G?LC /ְ#+݀_n؎&pFg!2Bia Fg (AYʀ $=*PDKبFp8( P#? hC'ߋ: 6H` ]8B^p%h n c Q]T8z Bы?(.R< d.;)rGb p\`8NLK&x4;ݑg G?eXrjVVף{Qrٓ%Ɋ˅g Fga"[bKQA_L$r/E:DcJĂ x1Ts Pih!*"% P -Au H-PD g D'>щN4( : C`Q `&`hGo'z94hz wPup؁YQqhP|pca F I X*pE8CKғh089OB) m(s ɹ  K LIB_u{X;p;RhuHʨp @i e8 $N IB HHP!?) 0@#{]0|p:pÉ%aȆwXװp"ІN9b;bCwE(p)K(*`Q[IXNu:Á0A`9JG\uXԁȀ(P}|x7xV b4p=}Ȇ+Fi0oZ@!u _!mh;6Q*@XEiu!?g [Y79"[` 82{x, +Ȝ``epZEh ,ˇ XX7(D_X4`)*k$ H́{1hzz5({2ж:A7?O7uH4x -p=FXTਵ$xȇ\jzLQ+(Lኡ s<(784P^n{sp h4 %xCl ,;#MȆTlX {0 !7x/*`KXE;C10N pH{pp@"q8vP=JhT j5+bC㹂5pll86- |0UK{plPe;x@4pT@+7`*ԯOZG0*|:'[=H|hІj(_zzb(L6lNQ|:_PatxPClD+nXp^,q @Fp/OyKHa+prȈ5ȅj/МLRΤ~:uQ PKt7}:;# ;dp;r˅FZ7ǣ2ЁX(tF}T Y ^ ux FP:)=q0Mp)pTXDpHXHЕb3}Zp`),u`C`)21K%%HDz1(=D B$<(x؂1Bۨp9ȓ 'SȣxJ,ʥ4(ȁ(m )\-]{hqHu am<(X* 2Ȁ+]ސ5(NCpbT`2YmPX #- K,Â(x H}Dc^B]\% 4 YX`$!%Oi+_ ƨq:{^'*;;xѲNH+ZCоX}O`>}Ka`X^@GH*`Ye*XqBЫ⑅hȆ: H;b)`6B`2",buΜpS_JTU  `0~ H?lw.@e#m ʨGMDDԑ{d/Ȋ!Ryg=Mrk8Te<Ϲe$"cj|F d(0"JJ).Dt;F[O/۴|4(xh:C4ט.c0 q}3,xkպU&U?ڼsSJdJEQ ?!ꑅL1nAT[øX| X+$:9^CɲHDe!Ifz۰Wi^!FTE#vlJiCDUƠP#>R/IV$,m~󗑲ocTjTaO_#n7T'`0׏Z@?Lk") =D"$;X]?Һkb$\OH{IkUDckfʢ*Æm/~9,+D_ ш y쏮Ҽr!g0a! q#Z0!a"aAQŨ  CCX1P} L2Hc6bGbh`8j0Fcל;k wY&)OU%d>ْƨ~y[C FRkY|1 "ɲUEqPǖ$stR\ ^#Fv[RSAæI&ILYV5X3eztpD6t%S'YǓy $..*" //0`0 CEԃEdBTH eS4H@h]}&\4k0ZŜbF'} %9>ǻ_SU/ FC?]lK-[TY<}Ғ{GⰑJ?Cm{ku' wI١m+-[%=!軭;r) :j޵]tBc×VR pMo`07.92_2d&4Pa2YT$U$hwFhȿIÚk)nW4o.DM4Yb+/2یyDpNŇU0X,VkR\TTޞsm٘ aUf962D<1jo{wq*FLyo+]mv8|**滪_iaIz O-RrF_.!~XA [.ĘQ!cZӶUF-ᏌRo4>uk1N\f\9nc6w`0CwIDH J48_AFCSӘ}MR[0ru6oD\KM5I> H]i5nAvDh,O]6||}ٱKIVUU%/?ckRlk~Ɯl ٹ99˗$?:/??'siQ$}!X Lh^eBmFmnX^uŒ__z -ѽKPծs>U:#At;HkV3-؏C,LLq13ؐzׅ#%;21WTxW`0 Ƶc lABDBThH"jL3VmQB֒D^sȊiӴ'[ft%t{ir?&o㝭F'QtDfiC"Lwi+?#3s%-N0!=-5#3{&ٙ4sWM\o <]Cyip8Q)q`eGڇˋ[YP'!kߝo❹C %;C *UsreWھlwr?@g{a1C6 Sb/養20\C/.0 qsEN 8UUoFT_qDhX-w8__mD3Ii\@}8)vT[S1G,(ĢLz- щ&_cfBMc\"T?g%:RR"-sU!ߙ;e!f{7;fJZ)(6 ` fQ/ܦ8tv`:8ny\ g9uۏ{yٱ.ںȋF=>Ʌ/1š_e涇cvk\5+%FM^mϟ?t  t&RбsET[ 뤚L-  ;_~w|o˿ _?`HTC&%ш$3޲MnDG h=r#zUe1>ɲ&9JEMՐ>?]ֈCAS*5"R*hfzK1^i7ac`(p/tOWTYجg|iї0O]J0eKZϟ 3hWp {Yyߕ@5s@0ʿ_i?a>S3;qՇНVofm+LJK|kXlq:Py}9@6MO9\v6H YBj!륿 얗_<[1ϊ 1qߎm4hݟB -XOcy_|;Yڊͽ;~2l3[;7Fdh7O[ 1<<֥u7[ `0n$*b<I##aҜQJt SN¸#|m$*cNCIiŞu^W*H- 2M_M0qgZZ #~kfv69%/갨=?d'"D`"FckOMw1vסRsL*~ѣR6ے RfLI",* SR,˔ska }ƿvwU|nPYD{j05HWpVЁ.aBJ'/v|2FT+{d~ޕJz[p۠u,Zu-YG3$6#䥩mcL# "+7_n!l}t^3wl\N7ܠ1ծW޹_lxvyb^%v?i9"o8]]hL`O[ t&@i4+siy+a>(s'ۈ̕,Èt Q8|'#&/FrѼQD=}o[a}Wc2+ߩ}1Y Z,SfFG6wBZZeUK33 s2nْ ^ԊmM<սgr>^5֭7\/ \(=V-a5xu9I mkACNK3tIh{fCHy/}U[yC¸?xxLxn_WE O8}A\T=ё^[jtt9Fpa<5C3ZW<]Wb2 qU}$ T=L_j_UQdɐ'NE#D/!]۩"}%Б4rs`'58f`Įt.1v"*|}M)*G~4[,yv{~\TTQdI^ u\p&I_*MAqtsN%O|xW'g~tO^ۢC&х3ڍN {d;ɘMp"%,rw$/T|X4Y9*0ងzTɂ}0 7O8]3ò[ F;^WnB!ʂ8*.숮++ 8ⱲQXDQafdg֝0x̀D`""Artw]JwWuW'~OիWynZEݸ哚#*Mʡ}g>*L]|~殔 NsOH{&7oBjlŤ!HdؼQ* [l%0 \< {a1gx^&nLfV'6\vx`я)b؝;USRӧ_hY֓J3U2)=S}o˳SgL8@"?u7n+m/bךּ=s>~]𝯨сQkҙӿ.O jϾS?}iBXtru.FelG߬\cj=ndNJU>tQ5[N evٴbՋ#ۂis'57VfH̛ b(p${b_/WREޣ"4G #u4*d$7ͩYWٴjU.)奃]Z;lW gMX=nꗿy-g>R$("Tcـ8 t8y4' X!=|Ԣ3ss2NMvsǽʃ,]ʯ??4w>Sh#Ա\~wO|x@/}Uss^qwfj;%rүH#kgĮbW|1 s9dĆ=o_%뗏}PWz3-8.Iu`bG v\Daurzw{?2%[1wH}͡﴿c7% #$ #^{.Ug@874]>5K~>uX,,ϤϹRSfMx^.C;1kx"3o sm;tbr4vy!&c r4VC5DC5 Ԕ_ (xHMldB$vH{^FyAnT"2+ukTd<I>zp X+dS3IWۙq~hnH@;6> fe. %[L]ˆ]{nW@]Ӗ1i.b2!&_1YN^ {Ȭkd bͻAB^MUmu۝:z}c18irQW;@rn=|H H| aG}O1&FLّn&ud&OK X׌:rẗ́%63yzc2;I.EZ63飴Yx.PLi4h[QW`/qۥFԽcXv?I4 4,hM:$.5rE~ɳrf>2 LЫY6>Y2ĘEg^J9eX<3.@odL鈶tSSgtOTu2ʢJ2 $^whܜ!-cﱻ<3ȣ~Ažok}g+1YB%@@L`?dCL`ncal̊v%K~1vŝi2/i]dw)߾E?R}G[L7q{k+6$& >A]Dmӗ.=nJ;P?b2ӌ]x{%Dd|VνYsq׍9"dgͪUdgN6>u8xx 3";gGדplԊ( +ד܎3h}IUY٥E>"}W?))vɫ$4M?Ԃ!0ZNmf1ԟԊ_[j՛/?*N{G'pew-%|9) YB/ˊY֟DNuGO;㡵()dFQ#Q9tJXPv z $`eRf:9X֟D-wM+GLcc202Ȼ {'dd<(2kXME*)`#͕9EA/*)Ӛu3LN YSg)Ef*P,0|,3'vt(ro֜m?' E1=).KSUR$d]\S'o>Ih.rs :4.vPXʁL"`fLY$OWȳƛ[9>*((:uc[$r r5)E{07QGL3XEK I?NԤ+^ufK7b1ygU&ORbdǏ/--]s>0|q<ϓ(=Y2ֻ:Iθ)PXRhqDafua?Xg$mדIjj#*]7lyL|Fl##aLHt`k4UeƝ@MPNl l))& u ryaӦO>1qcG#IaIl#er RcGooR46v~EĠ4u?{>XB-«!Y6>>ܴqsG|~2H)]Y˪cy8uw0ZW<,|-~!aYea2e͍\:lP+T`dСx a%15@rR7YSrڈ<ŒꔟU!c>,p|C @^ u\#)Yͭ "eY2i1R&d,Y +w A2|~q~nL]I넂d(P EfEO` 'O0l&mn(d/}DlɒwƏRd{Ʌ|E_$&fr`޴1'j%`d3nZbwi=nwE|CKFg20';Egj>H [64m!}IUY٥E.ƝÝ{6zԸWOl|j 1+BՁW_[͗ОH@v Sd|FOC8CL;z]FI%oWL7>Hfk&S /Og?٦/,$KKKkkk>ݷWyIq+U}RCsCEJLO zYaYYY>?s߬9۶|t@M<ճjME+4uzVYv$;dFh.((:uc[{DnԄV$Q<u՚zMHg G1B^RXT^8з YOT/O{DGLֳϙ3gε>R }%S*)3,")$:B <5f3 '8CUJc>&3DG0gDRRU8h]B,*-;oede&%F3¼t=5:&^Z}%iqةpe-5p~tI zQ]AUTУO={y鰲yr9vװ#l!K )"M%_j+YT'Zu*:y8%(4'Agk2 rbw֟O~BsJƒJL^~[]VHo?C;~k mop],mn|}aÆUˣNԬ`< M332ԉOlǭ;sNv7ug#(Zz%H4qL F#FSPeLwGuoe~7?97nԉy;u*s¤a\)^.̬'~\X`ТH2bYXtm?3ZI_E" ”q68iq/DAZxжiko 4-v lq,4CMIg,"ZxAJ[{*tg l% _lfUCx rס?mKO2)^ÿ=\^x777?~l^؉k'zÂ{v>x#;8|ԊTk S8=l3՝(1(P EC^\FWhoLS".57nB&Չ%NaeVO(;R WkI JL]Gs,yB"JQA]=^_rr0zys*;=-1)A3nZ-˜{5(+eE2sfgwiTÍG͹;oK5-x"kɃ$evoqJ59͓DaYa8ba)&@Tg2'NfQc[o^gYޙQ u:f$.K-H YWk dCH.An#kY W, `#P\޵b}ьc{\i/IKW(3/[FW_tOPrZb2 :F3aQҞ7sz&-YZ]U{hfM{pHۋ+Td9;X+^y`bGm`!C_?5u}NnӦݭ{e?frLz$G}5e}#:=&1iQPV1_ZZԯPfd_T>&]fRvWE1YS}pҀfAǙj93u_>{|ɢ [d(H´vJr.JVZsG4A׬aY#J8}'N48,{iݰ: 9|t˙ūO=W˖(]&Hv;;h|6?6[ZpL``Px tl;7sӗ& K24g?/]yݭy .֦f2#ZwFѺk!bEu0/8[LF=鰋=y9y˪əc]}',ZQRZ'''&G~Bi!ƍwFͱګtA&2 hj3 pAo0: sMͅ 5>vɣHq,osvv9Lx ) Pz L@cq>ŋLf6(j>N&&{LJ @4b2Xa(:yg{ 7NdA-b˶>b||a#JZ[[G>7o;7}ۭ4u7`׾yq44͢eWnӉaٿo_ _zM0?`&v /)r/ "\#TRB< hCo$KssC&pg+.*)P0U:jb6|n6Fn1'LGzjV\0Jd_;յ(PBP`ϛZ5\AOQh.~X_mz:yun' ^8 5@QXh<#%qMB!p,$M(m&<*~'ϜTɄ25:S7n !t)ObS^`Tmur74. ހ}Konܼjf@#`fԔWW۸hcѭ L΢}]wR5-l57mͽJ\(E7 u}yXd6 N %ٕ*a{ӣ K??9)"L> Gq4GN M[pƣ&.8Vp=P4 u: 0R׫|yxI?@Xuv@ #?ygw\>dmY`Qs;v̟'[؈: IPAjbx36SYtE2~HGHrvJ8Iz)?+Yd<;XJq $&wiu5F1 jnČ(A>z :* (z{{V+C1=c=0ZSg>}* dJK> 0sMQrM@H HCWDJ‰{U- 5%?#H E%2 ^asi(*^yy;4:70滴3:dh-SZF'ˌ$)$ "7yș87T54I|XȄov~yVb%% .@.SD!+Jp4C0?D슩*"ÔV@S-'"ҚQƠ8VPUM3]0K*J (.fbZ 7Zʛs8y`lb)`]'[_K sh}sﮪZ^7Y}|ҥQ 4\r%Np@O x^#Θ{+1~0ObB3E4.L Arm^g\Zc##_8Vcޮ uJ^Lzkz?w3@-7]ȱ!4tdэ{Q02c-l+5]뾵j !:9@ @ɤti *'Vdܒp1Ow!Q)FQSյՖu~/I1 x^$HyO|[hҵ ' cNS^i  ˮ3C˯ [Cc>P-⽅)2NyL& L7;;WfGDЫ4)K-ov%) DAHb K)'<{Ds,eAfr`28P];YA}oo{ݯ}1Z:n1SA(IIs~'m4N S{{Es^}]L^Ӕ3.9 &ъQeWV+n8O_Ѐ 0⽅ u3P^<]+,:*(IrGI!Ji򘉂6ܟѲ##Iޘ \*/+}uNWny-Wӑ"I`@s~r@HkJԲ,f/))iBQQxC544q [@!)gkWl0khooo eF6(nWuLEіeo7,~{^'?Z12`|).Φ)s﯌ytP lx_prrr}1I!-dއXV @ LLG˽A%;[f˙lV'&?|?AX1gGL<`8[nS ù6@Ԃb2޴yH_xwE1PL%hhV伅3%p,h J=鲭% K~~e稂ŊyUƒ~)L@VR]UFǃB4Ou5HT$gWJ/zh`d; gw$?ƄM\DA"M H4DI=.aA{7WY6%EU(apr䛗Dkcv%,h:d$ mFgǀ@ W,(0?GJ"+x]H( }"n\Y3fcEN@ '.S6"0f~F ElN옃hәi5,116.剝J1hr"P!sE 13 :=3Q)]B Q0: !)z)LqDk^RʰK$-:*} @N_2(Kr^qa.ADЂxLޟ(QJ|9yD!"^L5J.!D$ O@RN>s mr]J$.Wc9JLƣ|;< !s 81R>b]A Za1 U JILdH"":ЙH:5GL FQ+UD{{|S(3ٯuGiwZb2d9Q3}JDC1jl$FecRy>\fQv)by#2>o-.Ѹ e2ɱF1p`/$,) j 2,J @҈b2(BdLz%1Ŕd dc!$ZƓny@ZgvJDC3IPRc;$7Jִc"Or\IA:J {)9\< Gq4d'2)|&1$bRLHQdEq"9-qM sO;E4ɦAzG%)cx y2~^i$M׶ى݌`(p@[ȃz.!߯E1LM;woWZsuMZm&7FZђbyP&[)ٓ g[Km9&IF}fߪ1YٓLWmx+Wg[nfFVXBzPr=]!K/rF@AW_WG@eU4Cookg;ZB,ko'NbbvԞ7LՅV%WES$xF\L޸e~լ#hbYymQPi-,R.&|=“/4vqnkhk҇_}6k@QDNV{ǚ%ju M?\ZU;.;?֩]G.:.J!*P*{[6&`$I%cD<չ'4&J7T :G4̈U7*\ѡ2S]}UWZ/:[N^ZS&wsKgYzmR!&ݟ L=ZKA -%#**y &f9a,tT .ɼ-Z8ZB5%Ci{~BZeh̜cp4̙;E:Ӓ\sUX >7՞gӮ|Yg}h^^$&\Z`g''Z}ڵv@o~Mmvys@(%'-P8(]j%n7q~?d5/e2wO3OoBB%Cs %<%T8zS]^(HեQPFlQWNK!UKu TW4gfw'5@%TŔqeAvW22QѠuIQA贌Qn[ܪgOqP9?&!z:%',K /q},Jgaϳ;w>+o$d=Y oXw}Se^3-VXN?|Ŏ=֬[Sb˒N2ܧ/,_2>}aH9~'.H_9tީd~WUbX=zeFVД|&zX8b24ѩ^Ψ&,7}Ź,ɒiǎœ6fu?9ǜ*'y,Frx%5|qXgqOGi} F4__߮x״O#?ԣKu,EJ$qHha$Y?hI8W7-[41eTvVW ET/ki)©4CӌJ? 1a&VYZM@ϐ>\XX3QMo"fb?q#Yfwڵc~|)l%s}y%5'Faλ':9r?}8XK,dGIZh,|Eɬ(}u1K|NHy+\JdRSt/,38N ; '$%rHj|[2GCK'&<%>'R.R^V0X}ސS@t|E:;?zuV`|*eI Re/^P9puwݓϦ&Nzd?cٞ}8m;iZƥtiiYI܏&}ЄwUm h4L;:3+tG'11JtB$)E9Sb&%dTJJJ#f﩯N|v6>{b?p_M;t:U⚫nYVI7]|MZ%քъr7Kδ+p$5v5*o>n XBo>GHŒh wW8:n~X,!.7y757wK&oAk 'l}ZǞؙ$܄i@SPN۰a':im?bݣV;ܑB&ȱTB:\LFfYNY9M.{YwsyvƔ-R:[. i0hZ2JMd-edAzD+xmg/]o:qɏUR4z܁LrMwBJ CfYH9Ҽ@~ENz>8̿;{myۑNP>;@& /dk}-WUdiz||_X,yrGSH ΅xUG>Z>py7/G?d 7an@9r֭^w <#ʶz\u!13o oHyt F!m )eN۲eKkk+0g.\hogBOp+qE%A^TioY,U3S1 p8 9Ļ(M)fTsfoɟyU뉎N/q)=?|Bʅg)(r]dZ7mڔߡγt]ֵ(F"V()%T.EKC)Tbы¯.rehPښ0~hnv In0x241>h qz /#C# L,إ,3eLMf^N>)8=-O;W6X+T,'H|K& A32'Kd'), %R&: M&@Yfx*b$qL|B YxР.IL2{<A?Y0H3~"|YBwEw# P O9z,z0~Ģ2ی9_JH9_]"C cC?d(w)|5r 'lwB ڿ;d(\D9@A֢@hƓm =ɂW> eIEQBw#2%CŷpJ?v+ DY"܊EĜ#> dɐPm7:W %[B9ѱgsrW#<^/w3^toBeFmY@лa(Z>?dtFzJBvu3r%nfqrq2I!6fJ;cpq͉Y3J B%yz\(1{EJdA!79V# D<$ fb̲ral#X 2^9YmT\[R/)#Fww=27Rr,(f(}ո$vRhXbB+FڲHIW%x~' ^қ!Id< M9!r!'jH;;P:d)(]⿻Z]ח0O7r2K@3J}[ڒZ a *G=Jϸ.=c˜nn(V{71$!!@앭*U[1URU;}{OݧѾM017 By~V& h\vM H$ >V}W{ҳvIflý=o[j+7IҦLˠ29 ԛdzQ>6,j7pQDrr0)gV54;g4G&v6 yVhDac'D++ViժUqEG6?!K @Fe+C_, 'Մ=~3۸,4_:rMzVxlH,F"12%Sn^UZwL6֘V7Ɗ1EkpP=^*C}VOғIj X?pCn>* I۟-mq'&,?^ ^u .O +&0a9A.L`D&Xev{WfԴ$br"D1Q(m8A'uJvtt64j Nҥ'ϱ$qNߒsl)W(ڸ!wִO,e†[،EuEU?!IrrvmJ:*蒲L& N{Gmmmՠ2$XgJb,x)o\xtd) m'p #MSL" )2s^dJ>qɜ驩I5)"C,#GJ˾쏎6d>ZQSc9HiWcWr Q*DӂegvgP(8SSӧZkӧm6=eҊS֞3rB], b&8&v:o&J.Y "0dIqW,t)K%"J$t:u*݌Tj*9X9;6ۺ:,铳,%U.A~o_Sz}~_CRyR59q)X$ U+tvkHI,iΘ25#U|M4a`0lM~|n dЙ@|hy e0dR$IKqL (Dp:ò1:M\R4ͥGZMHESɳrr 1A8ܫ?4I|:Xtk[[?v[c?OST~!B,"D ˍO31l6"T^ooo?rn"0& D('P"1? Fhʗ^a0 3*UN #S)uLL(F+D1%: Rb`ׁD"pg(qNaqm~z>$]cP~C8 Y$MZ,q㰶u4^_bTΝn7wt.]d[AMR#M&+vƤzR*.rrr&0=>c],D)dHJ"Qqrex*$1U7ސ+m6R7+"1{?c~F#7ڛCKelǂCk^[NfT}jcOmk||$Fҁ&>`htdӳ9ZѮON%)pIIqN E)E rDIa qnd%{MK^gϺ\n\Ww߲:ۀ8=Z}YHy R"suSI AO?q0ݻwoٲd`MxjypV %4D"Qː6:.5]f46X|R0rz^0|Xu_t[[[^`b+'O';wZퟖ S(»Gx6맯D}H@jTF); "4@N_X7z0pIK^0<ϺхNgٶ]=&Rgh:8E8Ʒwv,a<>X*ag~@$kCׯl߾}/0a&Zca)EƂ F"4Y)^S L&SdMɪzU|Q"~aζkh=DgMz~C)ԥWnYWQyrjN{4-hV+Re`&eK8gi$ЄCȰa!p eu INi08N_b9U{]#i\zߵfטiʜT%>Px#q>Cn7GyR4ԥWfLvTP ii %[[:sP5z%?˲,(A6(ņ^@$fHҠ/}0b$'4YAri"p#x*LњNfj?Zae-ZRq1nq 뚄&׬YcXMٳs(yfє0WOr#e 30aW?+%Kr:uxߢը/o=lJ9wI--a2M UL1z,1 A ۩bNJĢ$]Qٷ1'`X ]jVk$X~Gb2:;%B9izYNU\}N03W?:zj\%I2 Kg#&<WZV?VWhXxoTr A3pa)?xȻp}PC=Y&Ý>ĸh"%sr òe%rZsփX{NHmGmdؕn|J$ O&#v77ZO9{݇bOEPc0w9h"4/\8}F.%syӃrl H ugR dw2nwh8av96"g08W$fudE?[i4mnhݻR 0&55 ^5}uVWW NRρPg "pdh5mퟶ2"J)a8&s9!1gb} NjgMYfsgRB!'p|w'QyUUݕN$$!AKPVaq8xr *8:ތ8 1::#"c$H8!$W;}ձzts~UW0Mc&{CY 7'vGJ+Μ9h&Mt?l]eZA{Fz4$ gio fsɩs!XGGNgų}ѝk.˅.^ ~soK* [ $yE&;7Qx^>{BG=X.x4_reyyX{Ai3w:,i wv{^~e,ɣ#efq9Rp L6zTƟ^7*$Br%.dz#/'PSy i 16o|xV$%e2>VkV530 |{LHmVԥ$P)jߎ<8.^$# RH`˖-B_H]^`L =d҃L =d҃L =dS䩗A&? \⹩ixЀz<4d%q3ܪ$&dCYIL\9z@G]A<'k]9W/蓁FD'CS[v_i4E\v"I{Ѵ8ׅ.{(6ѲSWwԀlM6QBg2s8'$5s9֍Vt6(Q4ϲV`pU78FD7w? Y̆gk./`($z&C=\"V]`OĿlɠ?#MS&%.1qBS)6)vL&S\Hx z?KJX7RάVSeY%E, 괪s 6W  D@5va1j1@r $̜1IUR$>mꕙ)ap?lbKq0f\Ų\݊#d =1%1f rc(  gc5)KxA >`A& p$00]6];w&ňlEU kH]WOP@w`<Ct4].oc;T(Uwuo @lp/ zХKߘԥ ;BauYۏ^(ص*. ~2z&Gp=斶.nĬc11*P5sFbg:z&ƹL VLu0!AFp$ \^A& h  RƟoj$ A$<%Ν=58/hu.2_{;/8$ƒF3A aK!vC)uALA ШUjUTE.+-5p ][, co.li,@ӧ@}2<2SՖq9y9I͞$'%$SK6l|Rųy{T C%u@ d4n3 ju:hljj:zĉcfS\ 2YCs"Mm^o'Pշ~mxI*^||H]D'U4ayXQJI«ŞM1vZZ` :vOpaWQ_ "벛9cFd2a>R91) A Xݏ?wAPTY rbt!(, |H.~usݿvqIdfjXe9a'] ඗3IW"d<` n9) 3GLCM9uv#E]wW<꼻\9zy9\ڤ! umZ߾N3-y dgTU&! +;,.zܲΤ?Y 5y^_K{"--M\xϔ9+^{VLԻ5^ľSA?aeZ2A4(%ӳAQEv^uU:cGR s!wk(KKf% ݍolڴvSϷy?ۼ>=-E$CȣPReTxɳYnjv{ռ^FsN,oݰ`+]~?lQ,j n3IZk1 8!eknY~\}U?@,[9!cE!Dj4f$A3BwJQtjz0-Ojj߶ .! ,uUٸu " L{b'jOH6Ə}gZE M-MIT^@' Sxo+!l_*GKgCG<'f/uS[WSN:mܘ1ϛ7Knϡ'5M(HclJ1c!$QֻϜ9m)g30<@ ɘ7&O!Fs-be6+fR@w D)!_yݧ6_W0:I3͡hd~q"#5ݑ3tm…߹h1 AEIgCgv~JqUZ9Vk6?:+b!Y|VjkWXt!?W[[_Y4%׭F/٣R@Ə˗,KYVNfE4Vۗy-J |$J&M3b_ ,7m&bjpYn[?:_hiIR#~CEEQǎtٸ QR!Ge}Qf&r,./$i…*nj-0l@ Rjrwv0LNN6 &I;ӧ~!.&uIC$2h\`љ^ +t:Cx^۽`hV2II7^\S_prҨ{hjll9cdO eɲ2Rx pl[RR$Pg[ YBck҃NrC^OccCC}MGbLfdKR&M(q!gRVQ2-(b FVh׬Y}2d%!2YK^qUUWogCVؿ)\U|39DP&IRZmv"3 #}y01sV(0UJe E#-%FWR$YYLzڢVՕڗJ(ePm%3'kLL|#,D بDrH b 4~U__PRrpJFdAG8bGcˣ=|~S9i3LFxmo=%;jaŸ_Q0S!@`n{ź9sg/G dEv3(~'^hԨij%E)iRTιg,KeT$X 5#'T !EcgtȢ?4MVq?hoeeŌW_w'2d(!2c޸膼t<8obf(Ýn\hA֜E j*Qkʒnə[uяlvKӯxoec2~~t٭r8Bm?lYPp+Q& QI` L$8ɇҪJ" 6(h.dc6d7(Su}D0v͈l< bA @B׭6mmT@"ј@ r|=j%=s3'-eвzcn ҡc=ЦرGA"cLF:몭a23 rj%!A HXuUoE՗HP>T1-N^裏ʪbg~3?`ԥH)Q2Y+FZE<=j_GRΜ<_6f!#ڲeK[RQ*F52[SwVBcX*\%))&7sDz!V?PEp}؛fo R )cO1c+ӛ[|:']@B%,Wyxw.ݲK|vB.̓r@) }%t., Im@nl-r m- rbrlj$ımݚcGQpȞQ2t[E #F-.esf:SWoOEhM+uw:[i"Z<ֿl |1}:8FP'5IhFEKJʥꎝpۋ.6**pEdk:ISK]3u:{/ds[m,;#a=$ۖq^%D!9ϕ*ʊ3R; y, @ ]IKK3z˫NhjM^egDX.ٛ |0 = j#1*Z @lԕu:#^\p65YWU~x~O]t>gٽ }Q1881ŋ_y^qW2+Z @lurȵ)bjnR ~CJjgrݽJjt76QehJ ~2 Ld]O~ddvޫKJYy%%s1$Ew:-&lP4DPp&DKϟgYj})‚EJE􆧿qXK[3"@#@4'mܸ޽[~`ysm>q8s}_8wAQ0Ik!:n%''S 2,q<r޿nmC̗B@ Ld钒|asf0h5Csqb=QŅo>uKT L1@='j[N([rR!0*U_MHܻ cnY Z 0 Oi&i"WuPWBN†JǒFJȜ @ mH ^DBK( ;T.=Jq 6bN2/dCN0a$CN4%9VCL%kP$Sߖ+6 _ax Xu8NJxrԵE*TNkCa#̨'a ' ?BG暑C*!|hZb5j{j"7qC6l t {H"P\+1cE)Lbdmn ;N?<-_,<5SPPrxPuk-ϴ=dpMslrB6?*~g^&jK5t'jFK칙yE~plI,{fXl>9%u ́e\IQgOko;>8ae/ ~ҶOyъpҳYz555ʋzϝhl5o8Sz`L`!@%'$?f`g`3[-dmWc^?'8M(-G Zb6 soGͭo=Z޲ʅ/y&SS]3'>m%Y罎^[V(B3¯}o? b05j-i-Rk6/VzԨnh<@~!ک%'-]k 3w;%o]64C:%npoaI5 ]-)6-\zuJoN]z];hQt{&W9ooޟ>ÚL5%OsJ,|}F_w{jacLǓ) $wt0.iR׏tSQNVYOrAh0s)0cϞY6(?JˬCUG>LOeݴn6=qkf -ޚb"cR2z%IyaᢛfϙGd2e_()*Jֺ F?bW=\yugʜJoza?DGY`LvN!7&rlQb8^4,˜oJKNS$9tvfٵY9S(kA4ǡkvFK%53hQ7bYr9źYNKQTɡ$]ijݾz}Wǭmj5===^t5%S?rQǐA4COwf-R K&.Ic'kߨ%Q}{oO{lͶW+dz.?ӔrBΠxAHKI2ҒL͝oKߐ̛iLI$J! -&tp/epp./ڞxD]LR}gv6}veּ(sCzFt8ruY}n\$ #!ذY.l[D7*(4'7zRM833ATNi9Nխ?Zr9V=%-/t^YK]w?۲c V;.g[>:T?ə&0M fC4%Ig\Pa1*D0B1PWNV9Wgay4uY|urF*J5vk~ Dd;NKЈrbIɦC' MzVm۶͛7KKL;WC#?wW*{{[P5zbK#D 0at:@RӳJ GcCmK%Dӡ%I [92_oKr|Z>kyTΚUk0&8 ONg~^E;sϟ ٴiSks27@IrBxe+dd^/zS>w䔱mP0c*<4+G~D0<r2Y lʹw7/Tb%I\'_Iv|ogSNHzOtecgF9Jj.4A(ސFGDݺ]lxtJ `zƚv倯+J,ru5f9$_K =FG2elV;wd"Ds%LމɣĞT`%^uۻ9{{>q؁`]H Ҹ2ƍpAiTU6-r (DӺi$-PH0c0wvlng=fy͟ݷ~tZμ{ovL޿L8禦yk{77_{YԸqHqrԐ[nZ/tt=ɦ V<:{z##fuܴl2{MS@Ǐ=edcٓAŔ]<==g& _&Y J!^5}va؏f5քPo>Ŧ%_9LzzJ.'[<kEtbJ7 yuc:L+2udttבK.Xk[ӏ7w*6+\8urٺ[SQ+>ݻv=#feҥKG5U'Ͽ=l;mfG75tI )wa.;nӜ zk^6k^cni\o/XfmlEho  &0Bou:b5_Xo@U-5c<79ؐ.|zSfQ\~y]G^%=fke7|)1sb:ϛ YtѺ`[o=qℹw}.Y~ՑU_~\yqoEWLd2ϼr}-3۸C@b~gz?OiDrvftFocnrdzsk Va1g 3..AX):Q_9P# vjW]\G,9w5{ZcʸZ=쒁w?>wa߼T[1jnh0&rB!?i҅s_y7gKZȗӧfϞ7”a&pO_Z;mhh;w{&[Ύ+[۞E鮮 3=@'3w)Ԏg>v׭ܿ<ׁ3{% $L>~O~薿?6S\[RX㬦\\g.xBfyfq8s"{ D%x3Q 5(BW!~E]1ZάZعSy]}f|,_b姌1XC:3+Ә3&NJN^ےT]Y[ ]l.=u?|qߋ%g3lb֣\o>\j\ُ3H6(e 3x-X;{cJ c4%,pf[5 Bϯ6j#pI!hbUc2gΜ37O?PMɆtPJg( bt Y:oL?SL&4os޺EBEm#NZ4:C<vt kTl#!E!5ΤS үz{azXql-XOˮ}e43^>+%͹@g`5H,[֛]$HbƜyϟ|w}-#G:4]2+N)Y`&dY˔X0 ĉgN{튮ĥe_OM,\0>>u掎K- ܝsmt &d ҍ WSN5 fd<|6.PO``~I"Wz12ڸ8wY7'3Ξ}_|_d2_獦txvujjkIՏ=X_x+tI&,t \VvvhS4j4Ϯ!|w S6{X<'Z'g5=]&ٿOw.>UuNfIӃ+WR@Kϱl ̨36-c)"]L25Y?{>X(4Oۿ G練577[nxxvs͢ypmF2e2[oaْtѯwo *9r[QUal+t7LNfYx#wzC_|wW\~K_|>tt LܳLۘmMSE+kf?7T2Lt̨0Z Ȧg"]jÃwt,ώ njQ@Z;xTnZ_j8to'ػsA8;N8OXohFNqݺgaP7#'PI\/@?r2ftP/o]r! X;xѭka^^w糡]kO9~d'׷Zv.'UU]Dʴ [+B[ )NxT%@9XC93 W4gTbz])\2THU%XiWa{NJ앁[x7\! Go_orR_.l+-oöKWڽG3>Տ,\Xgp5<෥<&rpk2.q*R?+ I^E޶QP=~@%{E]22*9O?|pɄXKKX)fU.soKʻYRom@"g 8w|2E1>ruk'(N9u2e=-cmCVY𙛾n='<>ȵҐ ,!fG*.mbτJJy&ǯτEh{`'ϥ6K훭]?}uޝ{ rdtn1 ޜ,k:6:DB@E\8Dý#'Џ @?r2#'/r_ IZۜ+QJ}r] ?|D ү@ (THqaP$'>Z Xnm+rT.CS?@T)6F Q_鷙U6$@Q5c%: o7io/oB2`a?-+yol6tv[m﨩wSqZL\^1T98w>XB\f{ Μ^MM\7V ?V]mYQ]srN ˔w>x%ըh:t.+q;Z [o_ ?CDyJ9OCz1LXq9Y_;#Nh^uөPsjP3!p'䡖̤Z$I0rkhJ=xᨧf*[ FRoPReQv,mЪ5 VXo(OP;hY,bNd (]ƯH.NP%-y*[F(S_g Uq^Ck;.RzB5SΕ~͌"?y [fáqض Ks>F >CWw)?ZﷱpddvpKPC_4+ i=XB2%(pbid'J]kpd`þKdFwdk~߼9Ym\36ԕzzy^.EBCET@|BI3jc FN9~dGN9~dGN9~dGN9~dGN9~dGN8'[)w*j`9syq|MUڞH DNd##c%Lofɉ^%-J_?cTɶ'jy~P2µ,kYAbn`=>_2UuUET)3fWT䐒=Fq^mw^BHK_TodO-! Rds:(ˮײpךeZq 2po]uɕE~D}b)Ma9̖1 v#Xkw2Ҝ•ݣ>+7vLTs2I޾ f*/U"AN6Q,'&1?-/"kZ~8[c8g%r^}1r4?s9𨾐]04)IENDB`knopflerfish-osgi-5.1.0/docs/images/desktop_info_manifest_400.png0000644000175000017500000012707112346515440024022 0ustar felixfelixPNG  IHDR eywtEXtCreation Time tIME $@Qo pHYsttk$IDATxyp՝F3Odɒe-c& [! d+E*^[#nA0C‘0 l e[eY#i943=3}ocØ,M{{ۿc'>c)vL&@2E0DZAa37Ņ_`p[^GFAU>zh٭o ;*,F4I-vNzAF޴B— 8-#]@LmO3K+IfT+3̿V4m1SYEtCeIy;!b gQȊ`H(\25iM Pi"/&4RexIaH)e"I:c 4IK:ݺ_!6ƩA:q$*Flynލ!ƽX=eg*@tKHA蒢gc.E QeNørQ`\'c#0%&`uršqT<,J2/ʼZofC^X7ҍ Ng0a8Y*o±ؐ.qUͽ2IMiΦ_\B+qnsjޘ;W7Ṋ}+ݾɓΎڕ4 \i{HZZ/i uVl&^p6zl(埉nDb+ɐݿq sZ#N{O[X|Б)IDYD^TP5i.JdNPPM)W+#unaDU l{@)LW hexX[$b~-OOϯ}bSZq3jlmU.ۤ9ơG*"V%dQd#5=ۡ:&Q_-67v$M+:wB]4֬]lz^V~Ǫ{n l=27j1fKVԛ|ǿADf %!<2p܌נ RmSl٘71Ő$TAI+&I\UcmMBgI&* $>5f]~t!SFjnoq'^_!BWIl-+p1ʌ/\_R}{V1L2PogWݤ3-$L6[WY)\H$t?A`('O76UU犉*ZgQxN[/ jbE:iۡON}}OϕwL'G6mzd;ڈ{^VVn=6rU׵\t+D/bYjeq ,լj5saI)]+yq70T3HP+]=·ܕ( ajdȸ2CB3 $+`x-NΑHËvRg, 2 4^Srmm ]Ա=tmrZd3tBVĻͫo8T|Z5wfN:QkW8΁xsDK$[VGVm`>1zE掬x+!Vۧ!TUf()h`fzD8X-)]壱#`c\+߃ywdž}@G7_^4DE2ك?:vl 677,M*u5pEٳ`GGB8|ScAᑓ6=p<ݝ,IRMuRSil%}}SKxjpt:sjG,OLLzq eK ֯}|ٜiǏ~kksyEojjI$S߻NxL& |4E?b{o?~/Cԑ6zό֭bpp~xe|^c2 ?EښSbz o}`⼘hmzso !)"_`%Iߋ0/޼qZ~sYe73?@@7e~}pD:= -aTkohm1-6=3ϾX|6 Vsy|zh?|Anqjrzw2_|~oeep@, [Ov@' iZh8 =\n1D5ǰAۼ0kiZ 垵~n&  (\^T{{k0 탃#ʢʼnp۱gdY(>^ؒevb7Av$l6Gm^mkuWl{鵫Trlys,6Jد}}<;Nlv5WN$TW_M!WUU%YB΍>QQu]w: W4]ytU}M'NBHB "ddEy(33ʼ3ƣ3DED@EeMBYBBKg=]:ń }}nݺ[uW߯wb\.wCzl-X,w5uf2\RF)<-88XP&LiIbE;U&Y &تd٥@ -9!<Ķ6.B` eCUѵ"v`-*,, ׌;SC}wjuԩp ϿU]]{!Ju萝77]Iq!*B6pVK{/_͒WA0&Riee%xνbyyc|"zڵn#uuu{쩨Q!!!;vhllNLLtewy'==}ȑ贰[ZZ6 8PSSTPPb8l2o.6ڻ q޳ @7 3w:RB!6Hg /=5 13cݺu\蠲z؆ ֬YRؿ[ouyP@VV Z5 SNtZt~?^p!677޽C@hԩׯ_W*Hy@8p4F(ٳW\m庁c="kO+W҇4EIDҤYEsdBgGCw+ $֯{>O'SNg=W8ŗ]Zi2[KR},n6zȩS'M6y!}_S()͞5]&0TJs.[;(!ʼzȁQFE#<HAX`D R))))HS=zŊ8'⠉-Z}Q&\V;v,|7{!E(zTEs:  S,dt]9Y|||QQ{̸}U6o_0@JtEY ѓVuMLҩ\_ž+0YL\j_߈!C4!" bɓ ZUAVpx ]UUժU.]2e "; skג)}SO=u- p8_{8v׮] (#T|D<̾} pɁʃփ*..F6lҥKApDBN> e h)]O>;:x_pfRDXd 2Q)*{}ڦ;&K/%wjhnPPρ ;$Y74' "[ZmhCcK/X%nTŸO  (I1cbmq_ E L:H8q?07sݸx"4NnܹsQh ?A4ș={68 ]|Cʚф`L|bDQte"A[CX>]A;}9EM!N"omVL[|+pVEMpuP,(ʧ|//@sx"nt!,V>|E'+%?4 wEXA|No= v/S",['/É6F߯yo?mVS Uq y=kHKKj]j2q1CAb_J%#"bf~-P$YW[WI3.jo?) UE>݂$$I=W^p:4e7<9>@RxANtD€ԇ_ Ve ͌JiZGX>xNtZ4Qܒ"?I9{[i-b~7pmv+K:ε4`ՓtSs|[m!G̴ۭI,͢)MtjwlamvSyU-6{7xbkH?:JJPB!RJ LIPP"?>31Ω#Xh57&1.5j:~Ҏ9^>nz`YG >d8% 6I=nQ`Ww7 •MF:cf#B.-6s=H$,([Y :RJݧ[**jx-ulkӯ'qVy sMtHs[ؗj2^-xNtKb[|I"}\:O VkZN?@}^Hpr)e!,t{ w68U6a At,Lqmi91ƎH5sbNY|p*W>gJL:1r}_*̸Y[Pƍät̵n@c4ɴӞcll}j؜I&*OYj?E`K-cҽDRNITCe2tJ cjm E 3!3RH0|ډ%/>y|oZI|)puG8LRU+='2oΙaRσ>#ǶJg0 P2gs{H֨TfQv5"B1Tdo,UUKFNw-qI-vE4õ#pI^t 7l޼t  7l`0. ?tNBzϞ= =zW_}e2^yHڵk>L>5//o֬Y͛ׯ__hQtt}k^ /W@ZZ֭[ɓ'{OZbŦM0rP :$[l!B"t] .K:H<;ݺ *1_'` MՍQBNj*a"Y]FV̢C8 cnW!HVbǓ)5i+ ˥5-H.$ C;z2f3,Z)uv%ia o@TH:Hjmm%B8>!Z `dNF( eZ_noHEk3M3IAP4 2D9Ի٢˗/cH'&&Θ1DŮG}ԝ@m@ .\6lO<9sLVN租~ꫯJ8>dɒ%O޸qY73Al͵9"`0Uܖzxo>`ĤC+S n9\͐o|R^VWM7 K诐 N, 'Ⱦz8P r4* X ЫI_r4$nWohd{)f!@ƌ M ,fH?~Qd\\… A_p} &4sY<;Mq{{3n ؼr hҙuP,KLL\.Z` bC6N4IPkp vl6$OqH?H$ˆ)a`9`O`+D|4mǎ΁C2 ̊:0ȗ0 ˳tu%[eU7.);Qk(:'Ssv-9epl(h eJE05BZ붮 ju>6*p|L:eWg9ҿojn_5uk5$~w0<|L۷x@Uo9VE|7n:bgkCBk nχFhkjNݓߊE4-t1QMҩ/?.jϾ 0j( ,"(fbY>^?R,W-fKMp_s'Aeag^Kd3;sy9<0b-lρYYY$BIw~Y#XbEDD͓}Ӫ qɅB& , .$Con<ݐ=~_wσs]ՋX ZQnԪ됸s~lDž{+++rU77ں&R !!!7nLMM H\PP`O`zQ3ߓpu_R8/ G'_VVF,.N$޽ۮPw/ͅu+b3zqYAx޻K/g#ᘛ-1zh5JAOy *V;͓渹\V{d7f=4BbV:>΂ Ri/Ԥ] i }ӕ+W_}Ukkkotw\($=2ɤ4z*˕:<ӃuyM|!ǫ4fVwgmә\ZL6ZW-6=XsS&6;S]V?~NgDPN5]TU| sss/qdVQl;e5Gx($T CҬfcsj} 1=43f6_lm):YkJdLY@~  G2iBMb4i|3~5m^;efbZ J(I@ =ztdddEEeRR#Rd^UMbZdFvtxiclFݪ=7ΚUMtjmRi|BMЇ>}tGGGphXIPk|XXXNNδi hlTVxWq(^^^SL={6֭% Q떃'^GJR}Ң8N,zؘ| 3XC #8P)))zZub,]444/KPB@+d0Veff&$$TB y҃B*iGgbDx_V'4 {SzPê V,;*ǭ]VwN(Lr~'&^ۖn8GIwt:IßhoEN*zu) G?;ZD0|ӎOՅ|#G F)J寿^QQyy={rСC\󻉓&ڵk]vƁ ԿΜ9il74H$ǎ8q"(OOO"C'n,Dq_LS,YϟGA.#o>\VV.lhh0A *eΜ9dGNlf_s$6lO?ܹsŊ?FUK]fMNNtW_]zҥKw7`0\]]>Ǐw>}#ȏ>pBXd2\nLAA?kkk۴izyyy^^#?fthĉ`d%ħE(Ua|Ta-Xp@4`7A@[lAӡ-[dA3fmg϶4E- [7~ ٥I;B1//Asރ\%R,RY4AS-V PNtP`Z\.Zg,6BR<̂&$pIx2u62Ϗdu~1##n#FjuO TׯN p2xXG z 1Ɓ;b2Mp UUSN'EYz^<;B"΃aI]p;pv֭;zR< Է%Dgc6mڹs,Y04Ă % goК됐q ʷ~d%X4Y___t(#F@g^w1Lֆb\ 6ĉ"&e,(XñchtHTۙKGsLMMݻ7==&Si'MLxl֓O>i% %-^pGs K#٠aaa$P!NmRA-v$NKgGҢB$L<X M&L AIӶAUPb(x"gthp4JtP/IpQwyP^xQ*x 7v@DBs Qq)4ay͘1ch$DEPM80. Y):G]ަK0Ps mۆ # P*D{p(w$hhPɺ^ѣV*2Q=xB%zFCCu]]E[jq_BppTڼgφQ&{ymD㻵ZMHH,aVZ5qD:Mk׮/#Aš0Q~-„A#o"Ḡ|;ug{QmF $Pl%N+"~3" (xZAa"%&&MrT'VجTM[ 7[f&2i\NLe,*Q# m!f9ڞ "L`F%_oa.!BDs+e @APFz`R(zԮ P*t(PDBr =* Ao &M00`̘)pqT:κV}}P(Ttt @@ʱcǞfG xXx1:тi3N8gPf9))iٲer<-- ,())-++s_>5TVVEDD瓬CՇzɣGΛ7?)--r bGd0w76Ru""}tɘ1cP 7nϞ=d2@*U&lvOտ P>fc0>hrr2*Pس>Oq -͆3f(,,,..FpRRRz-bcG k?P4f7;=X+0FjjMu~.eKs:FցQ2tBN3a l6+*6tjNR(}m:,U:o F!WMFKd+-"zZۥT*h4~U^^gm̉WjN"y=Tjɩ3|0bpYO+c}ILB TU&Wzr|`!o/3d]N<.aLu۪(9)3>fD}kNRkc jP/^2|#o#QO?StQ+K9R ?:$Op5z5E۳#yHo0nC^݇ןa64>k>ݿWiӦ/>ΝS՝W!ԴtRb+0**J&yҧzʞ7]re2fe\on;P8cD̪Eq..l+wPѾB޾FLO=  h%1קg3w\E6 8fVj}v~.ەޡV]'%(Vf&)W뒙ɞ$IMKkJ2ܴK p8B/hf=yD Dzf7|cR5,Y'H+VrPxD2w?88r׮]AAAJ277WReggo۶-''9̙3gʕzQc2O:$;E]BۤlnZWGY*TVj5s|>uITPpy& Y$NIKI:%[U+gi ' `U_onyVA~nۄirtP`?J#VT! R`u!AQ%9>:gLJj3X'zQlm}k+߷G[bWKMM1m޼֪UqLJJ:qV$6lڲe ϟ9s&<Ço߾ݞkرcU՝#tt: jH 8U,=ʛ)c4 Y<[{gUe AFY%APP!M:f]lu[]ZjޮwUlTBsH*M42E$y 7AJGD-L]CWhnk6i>Ao}6[LWW ~~~(7n ׯ_\\G!!!`ܹsp ~;''ƧgH'l/a~.ifsihT7w=ddrbBgϻ3O ڳ9{.Q;\^~qYyh[hZLZ ;[vpp{k+j,+q5JN3“*9e}n|||3vۯ2M>ÛၒOHLȠOw~I.n/shSOjhhlGSY{ֶ-"[$Zɽu:;g'GIUrرc}oo'Jr,ZK"߯{7/6qV1nV}/Ro`*vZmC,ԖW4*dP E5Uy.]tNV8_Ue%.hpk=^:ϓIMM;V۷$E͹ I5 K*TnMx545jʔ)pkY)7;;;-KUT8㏏1b͚5R pwsjU:)`145y9uwT*++LN}CY@DG߳gf[S:tvvqfpoc6&jhhHJJb|[|pBCED/zK۩86 ز6} jq8xMM^~ (]iu6X^1V;d`[>FJ-?ڽ{Uv+ ]_3gҩǏ=zSyg_QCJ<"n_u1J[m'\#zV7W9🍮?qR[-v_cK"ӧO $JSWIr$Xs9ζ,Z?8qbΝ;v8aWZǨ9(iϞzvbnƬee--w>|搖.p_Ot=۬q.mrRN;v޽ %Nm,O>3kuSSlVM゛9k}zY#Ezxz;iXyyy?h+,QӧOOOOw,7m;`~rdlXvllez{s`G ٽ{ 6|Г]"_XX0t!8:n…d9r755da-[۷/A+rA;.X@(t`1Ԉ*~׃-3~VX;W|ܸq\m۶%$$\DWJoSsϜz[N]X nÇOjX׮]iEǡ/3e1fG}$!]9fyꫯSgϞDU"Q?,3f(B&vFF h #w{ܥKX8i$ooSN rJ8Zad7ڂ,d؊lL(QQ{g͚%^Fcn¼M*)pttP\I@ i5P/D*a|a1{||fbty)Ȇ'&&*7 a]nB nn!!?i2hp1dÅAU82\b&L{ygpȩL`Æ A \P33ML]ikp Yy+Hł%L6$9R8"MDeu_D~뮻$.*)/u]AhK iS%AZѤijUöy{\"z^$u14oF3uu`/23nɒ%Ud@.`.z]uu27#&!c8شiKU?< 1Xk9;n\۫#gT%nNY׹riկҼu$n~=ZUjl-mr B!n0"/Қ/r^p -dVDo 4m„ T dXE>W OvǷ zAIxy[8z(o5ITRֆIvZ_몕t\nAmb!Pd:wW^22R0`h&<oW@1KC k3g,yhE5}'~7pQ2??_S>}z>} &PՃ>|rjCy\W\LߟcSZMq;(!J m|}}Q_=<oGneSYR2@s`g-99kɺO(^m݄0lT18t@*1Y_{5I~[5fҤI@omn ߮wrt7Z -M Q}GWR5@>=47o0EyÊ}7ݳS3n !"Ҷ牽=;2!rEj?? &;xנ9nxt8|txBLUbM`O+tqqOsId%h光 ۺv;$nk -t{&uά`-`}ӂO?ʨTOح8ذ`Eqde`49|9Dj۴w7VTdXsҊġh>_cNJhga}4ٛY[`. ۂ(\-Ro-`T߭٠77ZV7og}@ݻ a2 nəwaIR#F9sE><>>g*DXٻ(tR'v! D@HPPy"ЧxTpPą °`0!tҝNK/]ړfFw8E.uweubCbd2H$₼@Ib\{MMM`>j%F`ËpJԨ|kkk}[!bBBIMuB 1NT^-&"# V}t!SdF}=(w(>V?Zk5566\p mSbT4ְ#5^$Zb M&KeK%6u&dqBu~9[W T|Rq٭Kjyb$Gc -jdfxL6q9,Faŋ3|ڵkg͚.9s&GII u(Zr%(۷#zAAN"h4hS@r<)))J$bBHWG׃/l6;v qx3??" kɒ%uVO L4K D[ 0`ĉS0/d5St%wa_7C dr%GՒ$)e"+44[ .4UGlD"H+x6KH1ۭކ:<ؠ繄7$=^ilpW%\t).|`۶m p|-֬Y,?jˠ_\%쓦2i3m~ΊrCM#E5ZeP)&Y,J]mA=I]c:Wd=fӺp"h˖-6BhV^kyvaw8D0}VRKsSoh]].+Cu;22צY] ;}>jnn.|]"n6Ig=]`vY2,[qjZl^cL\6hm3?TmpXٳju^^^tt4yNNN;rG8z;#4o<.E|%VQvKS䄐n!RAxz}]իRU;oEH4eʔ{Ag^v$%W(hcoy.smyŚl-rT*EBYlm2鏗2A|LPnuwɎ?T*6.|NB .BE&cDSGcx,IW'iX˒2,prձ{NU>iv+5O т´E&'Ei I~bk "' PJS · … m[JܟbVo;1^!9.24="7)*";,N߄搒C;ޝ>}( 铖#i} :}bW]'DXcU:I`ե^4[%nl̏l;@Qc]hp8ei~sxhf?IKofXzSUUe0zoAiӦaJ y۬ s_v>RbZcXB&;٬ ?zLqvۺp!/Ђ|ޓjTI igQ _2u)^9PuJlUeq m/+V%LLA͟w nI@ss5n5222lb6]`7 C w>09rd fN׻wȎN_z4K.Q{wn;T,ۡCd"N'd2̙3mEj@׷IR_|>j~\'Ǐׯ@ .K$8l65qNo޳gjV>nG]Xx+rQ#d*))INNF@:H:縅oqq1;.y "#섵4Q.X¢,ЅO?5@XQQRСC9gʕo.(,,\~==z+zX9ƀ\UU#0@t;-t #@X 7n99jq ߏQ۶mΝZXXi& VG1 =n#Cwhh̻wNNN0ϳg>G8p Hp„ Hyʔ)KQRqq1EDFj>} @ii)r۱n:G0<}L$pT0#ءC"͛Q4sYjF&F־ vIjp[\8*pOw֧V*/\-B_Wapw͚5SNɓ'cWۙoC?_payy9g nSn;̛7"I͞=9£f̘c@"z uƎ@=Hڵk1̀n޽ϠKG2dRҤSS֠Pov\\X O.xd, )_ èQoYlЌ >TSO=zp 0ws% WgeሾA-׉^vJJ #5i,C.t$nyX~ܹs7loѫB!P:'d$/ 1ʀlAȜ;#S.=FC͆6 lKR"0pիWp8b |ll,kϟ?[W p|>_DPW=GF`1H'P( ̙3QcDumݺGAtT Ej\x1%!`عsN0H6 ),jԖޕEYYYeDA1%wL1K#Ų/}g]i\i徤"* "̰ͰDf~(055y}^ͦ5` 5oDEEAS  h#G"~@ΝshEȃBY&22rEH(.1EϏ _l Gd[n޼y-PyOFAbRPp6`:SNmCMڠ|`!ADtt4* )sݵkW&5 ,--^8n'iCP@BCC} 2Ig dSBBrK]pOmm-mXӈ&lEi&e1RLLj GM0 ooo[u:ȷ/-mLXg+qr*4Ʌ*ژEnJR,ִ髐6ARR+W<(Ypȑ{lقFtǍFۼtOf2zuEtۅ¯hrP^M\'x4WwDX2|xDPRI ?/,uʋ%ߥ(w2TەEEUtZ}B//HS^~-4 J.O6q\.W*VX/P֩`+[a{޽;wYϿ>=+2hР09B Gal Z^e' N1#.Ί`3o}i߾}[k56mv1tzŢqŕFUriMݝŲ+եJKJ|l䳇{=JSJsiB<&F+b6ʰ j1HpNNҚ*oUҒH6eY"Xk׮,Z(11̚5d$ ݻwKJJ ~曷~bW^hɡQСC|$%JTGk ˂a6spG2Onq\-X%Vcgg3)S颴0ln~F}[_tg|HR՟S=O<܅wXۄow%,LzC3UW[UNѠ`rKڠR zu1˗?v,-- @w+1W(lvi[yISI G߱SW`-~٧;PXgf#UݿaVT[??,X`Hۈ^ t25T7(Z*m'[9I告nwEr׺Ѳ ͆ Zrfvvm۶?qŋ6mj>l~ڵk-pW_}ԣ׮];w3-n=`ZOg¢bNt:nPu1pB׮]w=k,.**`1inL@.W?js-պgB_5KFf񹜲J[s6y'_z%![ss{;b6{.Ғo ,u~-_|ٲe4y@}}=:o{ NzwE"QEEEhh_]]rJ ɯ:lذǏ^{CIR\gP8i$R$;pܹso޼P(֯_bxL#GdE9=[68deξO]n zxx|FɕN`Πj|jms(z쇯ܖEP@7Tz55Md0tUj۷oO<F ,3FVhN6MqH[d ᭂO16m^ӤΟ?yDQ/FjOe֭mX Պ+@RuÇy>E`ㄸ82lE:Az΃'h~ׯ_g٨G} κsI^W_EoMzB9ϯ½jkkVعe*xA`tZ=[!!!sƌ^^^` n 9sV(DeQNee%~k,4rss!eӅ.*c @ۼys>ÜHbHizڂ oMeGuVȴ:8D@'O?uvּ0T\Kr-czl(SڵkrI3g?gEEE0 GG,H/D|=G!1qV@@S`傝 Dvh<$G  a}C!"[@Vh{0333#(MS8 AǨ>Q&"wAx yyH! JOR>dSN(@,޽{Q&( .r 2"7uvvƬmf>N3I1wբ:PBg+&l٫󩄼2 NNNx`շ oޫ."qYƲ/]m-Eœ-֭[ mwCC$ⲳUrEs) IFl… tԈCd" 9K:88|~qq1 BPr|͚5ih"e0aw}!(fƍ-WWW {=P!4}*<ՁA XkΜ9P޽)OY@Ov CP ,Ok Ayd>=D_Y ѡqDOVPoOspot$ؒ7zx\%~ko lm;3 J}C~XXիWђ^/.5ix/vG: w(f@8 Z<cp^4)lxW[cC4 CW! 1eccCru"!L.]ဝ'5jhk̘1 #}1"õPp;z{P^tt4UzָKI^jFZG9i0 NW!b|8/bnoA}ݰ%'GgcˑܹO?Ç/A7/e,іGѬuyi<տH$9sq+ vrݳgJJIIi~H/9czjjzz:鵫hw0]֭[P%2ynLh?Kd_x]C ,]V<p]W100L}1FUUx ?5ͣGȄgbu&t4(iZft[i?cƌ[n!ΫɌaÆ=hT*@mii)<==t:D"=z$$$dff3ݻ8o߾~0V]TTԹs .xxxY&&&t~#HRƍ`cΟ?O^/]ҥKdvqkc\uvXAA\CRRRpp0hjjjhh(c222oGmW(x'߼ySTA򕵵L*Rj$2O&cHj@ݳgڮZ6lu˗/:4666... dVA$첳+++|p4GBgp; !TΜ9B!@0uÆ q,n^As0`['''Xk 0D'NرcG>0-//ONN,_|֭p`??B,X  ̙ٳO:oP;y$"({Fa5CAlN5%ZV+Zݟ>{h$ 7FGGGC" 4@DD '`WWWѣGOU_`'"~d@x.fD8A+++I>"ÙWY(0ay 5Bޕ@GQ뮪^IoI; FC !aG9o\}st<y0aތ *!f*YdPo$dO:ݝtWwu."CɩTW׭{]v-x-p-`0O6ހqn"Ip999pwa?0YYY`\w;##Ch@4,I`ʄ.m/̺lHHLk]űȫVVaO1*G 44!q9" <8@dSEQy"_C8%,Lz$1 > q24Mx> ^(p  B0#]~!HspͦT "O36N.W[8x E PۻRا"n`!c"BŒxe 82z!.V4vU?UwS.$&D({g'T`j3"uH= \ށI窏Q㈫y.Ȏ!e@.%xҮ>o@96 Wd 'DgXL2\\ya2t&Ž~](BgFbNo}`&1K" LB*BHV>0Rf%FH@^A=r"PCq;_ .^t[~`YTP8 4M<~q;}^,W6,|Xƒc˟OV(:#1雎޾.#GQƒ@X y(GTmg.T(%qI$G;Ϝ)+uӁ|?6&}Z[$.߻/46<̴Ϗ=u۪{nO\tk.&ϗe#Cl-/ΜJbS L%!>]cTpl#뒊e0cd9{R/YV b e6`|_VK$ɢZJ\mQJ%)2!tiMV ҬG8| 1Wf؝ Gyy+_G'%-S"_OTmm鳥=V̓K觍56?u" ƎF 3;(%&&w/z)˳AMF):'i+D{6_lBQM)";7)L-joU| a$,дwdUq'Ҡ7#j|½0GwPC>JvIQuv)i0%1MDgKeǎ,(AEܱ"28чcJZGMeWcGvI);C|CnV+3Ѭ+z'ҧ&4 .[tTXTJB&$.g)ڜ, MQو=0}h;Z )$|UMM<{v&m^[6'1:2LS&55Ոn6'\]== -m]*dx^8H2*B1)!-ǚzT,ȶ[6"Xsk"33]"TA ,\f W$"n[guyx3f.F(T€x?e;QDRj0f84.=p}vpKJ/3lų/l\:́qUhd?1M1AU_TW׃JOK^ Ðla\wS QXBam^1Ϡ"w;:;'AzI5ƪTcf9V."OkIq9=}4M1JU& *6"hRэ]RY9y E~Co[(LEw]"kD+"1 n\)aN_޴ip88.Oݓc$bZjmkq:Bjp)g-Ͻde]]cv###&૊ʚysgCuIS8Jr9|5--23Ү |/TH$NJiФwCXFϻa2!Mv/25G& >71Zѱ9 [4rr7¯_lu9ĀgdUUUK1HS#z%|7mc03͏ KG2P*匜#7lxh߾-..>yͿlii8www|ձ!Hfffmm reep׭w7ԩɟ=pٹ^poͯ..͙yld2h7K7[i/!?bGf|DQtZEugGW8 x^ (Zmo408 ǝŋ!D_6ɞF䩳2,\):zށӋ3(.Z'N; DBF%*fr\NLɜe+E*)"(X$ɛj,0 s5.4>vɥKlٲpW^y9 a(H0iՆ%9k%boRSS _;'hmm䓏}÷裏N> D&D L!{{)ߞ;wvd1ɂKc'ά\MӪȼظ RD~( >wz .t "ÉvSo27\*osQp|@4RB@Gg5+nf_zY6j+8Rxv~2#ap8RnDa}9\gSnfB*9>eȵY_2z_}UCo4$"R#w*mNڱcGQQQm %hZ3RPjw 9i6{zzzxFXOill\T'%%GDD[,1Z8+kmAIxݶr/:"!!pw=V4J=;7wO22Azj!T ,_t]˥R):Zfyo˕w߽ʱNvu٦ϰΝw!0d껾[ekimx0M",CP 4}?i' 99.]k^>p$|&]±:V~hu4Ӎ1,&1#2AZOhuEE?r[G>pժU Ety<`Cy}ٻt7/"(b\&1L̘1399柙sQq\и l* 4; 4m-Hh{8<]j͛âijɸU^Ǥ?iccuu5wQQQL&L&(I]]CEEĐ@(#L SF^p߿R,miieLmիupbhh$zsdޤK1U YSvӦH۲hA]=6fR-I SVZF;ӝ]q 7~ZSF(eHME_Gښ;֩rk[i5ڼwMU%;FU5Y(+)(++/\c@]]ݜv==*6Ձ q4 ~GLi&j^m.uPh'bV\:7 eT"ȭofDQPҨolU-s|?͞~>h7G j(IbLhipzRg5=-gį9ݕ+WTUU @e(--pnu:9x {2ҲL!aRycxox'):]JSM;. vNrr%{^ C^ҏ)8iawL, ѕZ;zw}I ;O$xu o늾nd캚6I2TYtQ^#^ҠmթU o|ek֒v0њ#i^@JүN'F#ՔGF$ "@y}ot*FsEo"SJ{TFYjhFitd%6Ex4/j|_ 8y?3Ygω~>jjjqA{Οp6}nh%TLL<{SR&sΜ ߤӨ㢁mmSXXġ!&8}4UU-}+V,+(^ޞjm=)((D__ۋ277-)a355A6[&䐐|nMHnn.II;ε$$$8&]ja1[Zz3gxxk^vjTQQ D;;;,'oGu]]]57oF8+&&ԩ3?K"&&7nDa% WU>,**&''DQQ)8հe4 P:&77& KGhHzzVGGf22244G $Ott<[P ?G[~obuRFF&&FPOq8=9ԖHNH@Zz6HʣV )~فF@@0;\_/1ں#I;<8|Kmm_߉k/ 7܈I _}} >j>d1ջ E@@0m𘰚9a :J <pp0 ʕCCéӉѨOWBy<^qq 9/7oߎgpn~ p?ax䬩;wkw8%`߾ݪjjWHOIp qVTL̝{bb[ZZ:;nތ\hNєGDDἹ4?ĕP699tp  $^|-;;GII06LNNb8/DnhkWWSgq'}wM vewF`--V~~ [ZZUTT9@?CI\JJ:j8add(sr4K4*ӧp8JII)`m]];p ȯv5>xd;22cF 'dg::ڣq5̙077Oaâ<$.^Z+*w!$'a6uuup*/^^ccx{{ik\ mK;8!?(F("3>PAzF77ի~{D탈Bx#vKJAq2 ĶNbG"22&&666 ᛓCZZfEE%(qO}|VEED$|ч*ⲡeeeͳBswwM>BNJUᨦx΂2H7 Ѐޱckee5R.w3&$$p ${[F8 _0[3>w%ƍ[[ GW\F:6::M  kٲm%%xK)L2 hpD؄))H3<1jkhh@p"B0{LXxctLT!jDˠ4v܎Aq##;;D@. #<WHD''{;;{AI~N_-y)dee׭[7߂ \ SQ ]18 0$@d(ШKSjmmŐ-.Z :::@A@va6aJj*O Qh`"![ll< CCV\w Hx* f=<+222Yvz1;fXXSt O,yCNN+9xB'555Dl| .%x>ka1F;::׬VPP8u,n3g ꢢb[̱ XN/ (+hR?p٬mڴ u6N=svvTUUAWH55UYYpOW{Q5:_}uUZZ:(|FFrojjj >+ww3Xyyw&^gٶӺ:.>|f!P= ֭[cnnD(R6ޱc" 4o6---YpX✶0 KMM߽{'zLuĵ Aߺ|>R[˅q޽*++=O>jVQQ޽j;ӛN6 1;iaWZZ&"uss^PTTj5j"3sqqoT_’RZb)b,qOC}_R!6lX "#׮] ё 61CKɫ^455@j.F$z ckf! Px==!@vedx p8}}}&FF5!PXAQNxYY灹Y``ƍC2 U`,~KNNekkkuApuf6Ub aVVVF*. kx'.]<5-h1>.SQQqjjƉxG@@0%|IํTOS^ob8>e`MJ 1*i*ESTjJOycAԢ`C1/!0}c{[3Όxpc&|?;wwν|s,# fA3` DA "X h,A4 AK %fp VggWi}}}:1apr||b~~kkkښmhh|HGGf,//yTy2߯Y\\`3 Mo!UU_ܷGxq~ygj46>e2M!&'\>}&7{ _X^^IO߁2ʇr q6c'(foll>8ٽwƦm(?SSS2Vɓ"""BBOOS|uuezz:22ayqRZZq} ͛_GGG21%%ѿ;wJЬ$DDn655GDk_hBB|ff:z=U+-v%hRRkuBZZ*,+0L7o.7O>JLLD> ;ٿWa4dee5 PVvQk@ C{{'rÙZ GFF`wtte;\nƙɌv WoB.nG-f{78@<{TĉĀX:\xa߿see52DO>c4%%Ǐ/m^iii^~"{AeB)ܻWy:tagϝ;"C[ }RR9 Ց`hPSSݻ|'Ʈ]k替&rrv4?)(F?!}-䩾~݆|JJ++uFa[[ۙ::QE>rsZ"#q挑YZZJEE\^XxAzxwе#GB|\*N>19]oQp 7n:{ֈ),,,g.d^QiF n Z)X=bH'6ijb etO4..tQvMH3dnGz(f,*|KL웗2qQJnAlxN&&&veA4I"x{a8P͡ H_3$S $Ji23#}SйYrtDs+_lC'O)td.&ƶbww/& Ҙ낸`eXhzzzz#qN0SSmmttJޒ1Kq]vk׈^ۙC7>nNBU5f,V BOOo~A{8# Cz߽ (++p$' (4.55x y?"v=kWl&Prr"# BK̓&>{.5!e }p^ޞW_vzKKKh 9 nDc>ovU5A|%np)(8oa(A9k1Itp`l,U6j,-ubff.;{FL3X<}}(3*(z0, ) nؑb2tkT K<22y^(7_~CAHȵfޝ.h2nòZz{{ Q>99y3"D&v!'G) 7xȱ7w``t)"A3` DA "X h,A4 AK %fA38U U_GK q VFRQQmA4u ¦83ݻwyAOo A "X hGϰFRavmAx y Vjw2~[))0g]Y}ݚ~AaI_gu\9gX h,A4SCz. )X_iZo{%Cw2Kƫ{8o{%`a ¦CwA4 $MMJoB7mAx)h=lhPA_5kPqLom*˳c*zvL倬m[H J<;Sj\Z}or|^MTtrKQ#XۇJzbSk*z{u@Ԡf0B(vVIENDB`knopflerfish-osgi-5.1.0/docs/images/makewave_logo.png0000644000175000017500000000250512346515440021677 0ustar felixfelixPNG  IHDR} Q\sBIT|d pHYsyyMUtEXtSoftwarewww.inkscape.org<IDATXU h`[np-GJʋrv=x/ދrcgc9A|9EdloE5Ia>!%$/t?uL^;17j,mRr\ٸ=b9rv~/VF^q?sk*  >܅+ ij}_jm:&M{ WjVZlBα Y.9TjVcP1<WQ=W8V*g`u aw >t?>8z6G 0sN;Ut<^F7?tNWgY̵GUn^tv":_Ξa||Uζyiž!l,{&/CID9vF+ 8ߞn84ZlE4hwEFuϔYX"!N Yt:m&|pj.v7rg?-';,׾*>_s'p]|%73CdY 4W §[=b0ިm-z߰)XsrUSOZCJʑ~drv@D,f_Hכ$}pK5I jcy|_\MҭjwnJؐU)|˲"*lIQovvy\H%)]j H:[§QȽ2N̝kjmyp"vŗ2;M,4X=s :$2Plaû7jqPE_#ڴOu=6~Gcd$IENDB`knopflerfish-osgi-5.1.0/docs/images/bundle_installed.gif0000644000175000017500000000270112346515440022346 0ustar felixfelixGIF89a("!!!!!!))1)1!9B1J9V)9J)BJ)JR)RZ1JR9RR1RZ%Nk1Zc-^o9cs!B{9c{1ZBBBJBBJJJZZRZe kckms)s)s1{ABRZFR^Fck9k{Bk{Rs{9sRcccc]mvpuukss{{RRp9RBZJc9kZsJ{{k{JJ{{k{{Rs祜scsRcZck{ցsk{֜ޥƥ筭sBkk{!ƌBs{{)΄)΄1{քބޜ9!))!11199999JZޔBcs{BBޥJޥRRBJRJJRRZZckkkss{քڈ猵电Ƶֽ掠ƭƽƽνƵƽƽƽ!,(" H*\ȰÇѥQxl vQCl0T '$84hxd4 5hJA$Xz)Lbn\7ky f .T>d?~eafDȈi8͙5!̚$PHNx{ݳjl S=՜f>ys?Z Ϟ~fݍNu~,lT[@!.:-R- 1=h;!hR'S*-BC[?M,0 q9?Ɛ0,В!$:G@1,C>/"@HI$҉!#h7Q$c 9QNy̹ 2 =@.4bS;6i( &?c:&OC6Ls sk&S &rf /È23J7GR4> r)2 +".pcJqD8>$r'Xr,3 c.1s !pb+(( ]:jN(`-(س4hFȣ7RSN5Քc;|LG|h6Mh8o6. H7S8í5Z0AoB8 MӅMBw1(,c;knopflerfish-osgi-5.1.0/docs/images/desktop_icons.gif0000644000175000017500000002552612346515440021714 0ustar felixfelixGIF89a&!!!!))1)19N!!)))111999!9B)=J)JR5NRFBBJJJZZVh s9{A?nG~-RZ/[oBR^PXZ9g{Hl~S"_%c-gA^;m>wNcccempdyv{}s{e{%^-c,l-o9q5tGxH3t={FB;J53TTRX``c}PVWPicwoeo^pYgsoFR`cmsks{{}y{ckk ms{ہ s!s-BNփ&ÉD)1)<51;ޥJޥRJBJOZRcs{Ƶkckks{քքތƽֽΙƵƽƽƽνƥ,& H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJի?ʵ+M^ZSǦ̶ c2tT-\ǖ=w`=Ǔ/oĨ ^ġ/|QdCaؑS /?G<_ Ek//|MJ4DR Dm$sB+=xc@s 1p؁SXk͵=vgS>DL; RS5RPSLQE\H4]aJ$JllŸL*p=>c`p;N0@e: ĺkT7xW~ywy;MLDl_ED4[BД=5Cz;|"(3G;zeC G?ص检LRu w}OBP.|X@xJсA@$(C[-FD'BQT"ۡE.z)*d a(C:(D,#H̠)Arl E(C~8e1A&{Tp-b Ox؀)a@ (ɔIM΀(IiJT,@L"HBR`  Re6yH106MF0/|FE%e<@uӝ'=O}ӟ(AjZ &7pDS)!M6Ȏ!Za86(gZ`Y91@yD NuBCX1Ғ4+Gc:ӚB3P)m94', wkJ Sz(E$h z%jo( w~` KYpSi]k[ƕ s]ڔ+UsBE2 p> CxRS':Q$/(\h^B\es b Lq a+[3mo\C{_- $N@R <{)x`V& QP+ր<(A`K.``^../ `8m(GD!r _/|x5D#8*ND9Zi6vFP·\傜"РLj2`7 YLv;B9@^2$A4R(# Md;ь@m#=JT0}37B25Ђ(p!Z@$f:R I8a Mp 9@AX{cь4*ώ-3g ZN$Cd+ ̦ =r>,x V0Bن,$ [@B "3bL`j= g816|*) s٭}8 ~/*琁Z#hPC Tif(=86S@A k(NYSd`>N|9ЅNt#*pԚ e!0Vx2.}bуQxc7A v}}{[ C^y<X ^y}1{\<_|pz'~9\'h;U c˧ ocF h^@?0?@%h1Wҿ%@xa!Www<H ؀!Px8؁ "8$X&x(*,؂.025787G@C(EXG>A!K5XÄWTY[^ȅQ؅e(?HiLVȅ_[QXvxoXA؅ax`:(xh98:ᇄhwȈ8xx(hh;1Fa{艚8ȊHH8cuh苲?(؊XB8((ոɘ舤88aȋHx(xxqdB|Dzr|؆X )T8؂ )#i8@XEȒN8294Y6y8:<ٓ>@B9DYFyHJLٔNPR9TYVyXZ\ٕ^ `Amqq~digy~za fy.#p]1QxAe\q\q1" RX!AUA '0~aiyƁ{aSQ&)iN!!""B"&"".#2Ҝ582;B2=@2 r b$""!l$I#y#ҩ#er&Q&k&or+sR'w'{')(Y((((O%SR%W"Y%%)c ⟆((+,B,Ƃ,,-Ң+.j-1-+Br2*r***2+"\HѢ2b!01c,)11å $ c2f:K/D0/r/.70S0G]:2%c1d2gm^7!7dc66j6Yos8J7j7O7{34Es4I%M4Q35U*6Z7z<:;6C;;sc>>S6*AZAA_TDGDZFOESTEWE[y^gbKDFFm$NG-B14CUPCG=t>|4D$;FgԱjnI1K4JtJJJ|Eq䴿DFQLDH$lL4I@lKaԴ4N[P4OtOOO5PN{P~PQ;MtMV-QTNNP|PP+QSSS?TCU_SU$&R*UZRI@V4eSC$UWZKaY}W5XW%U Z$ZnR7+WteWxЛE{^U\ ]ɵ\uYL] ^;^quH5[E%_V_5e=` `6aF *b%(b0_s_s_`V``+#\'WCOeSv U6 ffjBfcfeFg}a>f}f@&gEGVId`FdRw<iFijjOhƥvjRjVzg\g 2Q 0ս i]=7KN޾H Y۹ yW]egnpr>t^v~xz|~>^~舞芾anmwAkQ!a)rw!I)!i뢙Uћy9QSaN99$ $##<$I$ Hž3# ):))aJI(y(((M2br))񀢟O )D)FJ.Iz.L.O.RzT"ZGZ.J.M.K+:Z=$"/S1s46/~3;&# -tj3{*}3 2iJlj*Si3?47.:8Ӫ7꩖H!~7 8㪈?7ʚ<<<=J=:S˪<< =:=jҼ߫*LAA![BB @@[:A*BKB{B> +OT0;G3kG7C9KI}Ta'kFFF!  $XA .dp $Rpb/\I$5k9M-2dv$JuҥKLv7 SQ@%RȑÅJG4׸)R&-9epGp&^nɓ%BL3W%̵eܸԪWnIؐd͢Uڷqg̭{7޾.|8ϱ_#b$H&ȒrرyɓG 8,sz}ϗ/W5! 5Q| z3mn޾ >l<_骻..;/Ȉ) "sC8-@" qvl(vk'ZzF<%VFlB )mܯSg_qƕjR="4c*,HPb,@'A<GNd%a!'T.ʫK</ND15|39PϮR9&B2XB3ȃ!4l~P?}DēN !sBS*J-TSN?4QKUUWcZص J @ $hbCPEeCFee%rdC ~VU*k)vn w<c]x^| җ߂me$+ Ê#7(7hRGdgNI 8:dI69 U.e&k9Kv矃ziሣ7(̍2,%n)0}ta'M4y&kʋXepoS_熣(B "#3`B*01zA9Qm/(K?=[g]pםw߁sGɁ +`6H-h]"fsivԣpfDT?̇>}ҋwd_X@0 `C!#L FeР64A/hiJvh2jЃc`L!A &ݐ!'L!VB403H?  r ̠G$K @ P2aVA f0F0p4%cu\F7Qt$@=s H0/m$b=?V€HoIDvBAJS !+AWKh Nv.`*1xGĕJ40iLd&Vt&4MУHxv*ԦDqӜlH:ivފ1Oq{O VB>ThE fThGQfԣ#%iIMzRT+eiK]RT3iMmzST;)IB%$Qki!AũR{+*J2S͠UՁLիakYբfeZmWUfUD+XjWΕqj]ֲʕ Y fj]*`jXR},`kנ.v_cؼb+bI6qjk"m`:[ےϨw`'["-j=[ m_\ܦ6`EYmZ;]Jֲnm V=+]5[ݮ |k\֭m/V)^kߧ^mMlQu~r%` gXp=aX#&qM|bX+fq]bX3qm|cX;q}c YC&N!"*]I8nä zec%}r 2HyF7ٕ}= P@?u8BD#zmBω@9,}LtЅ>tFkІhpzç0&C2Dd | #MC:8YjX˚ֶƵVձj}\Zq<}C@j]ġQ#/ F (:(A8 bbQp |67Սv;ֳ]K;8o-ozlA v%6guP Zz`B Q 8! SpŒc @F+H\y-yb< 7vcGi.:4}tB@{_$ c;P`"XR0v!( QeM,0@z/xg!/y%^}{_;>񋯻#VEBT6B̠:tA V9) h2d8R/Bnd??}᭏}3>B?s>>۾˦ ;%h&)P!Ȃ6X=Ѓ98H7؂ VHp djaSPc;+@"@ @ @A$;0ATA ܹ<l|X"P)*0)A":0.P$p2Pp6؂[Z|x{{v1v``X:B/C1$C3DC5dC7|8C-/ C.C(3L5l79l$0&. '(@ Ă-P2H8|FȀaNa^2+2-#),2Ƥ6{8:~aB4IKô2I#JKbK"Π^b5d#ec6*c60-.bѷ~7838S8s8Da~;[h85+KkxDC:c:::C~ʳ<<<=3=S=L:;U#KR.?3?S?s?? cN?K0`tA ~n.Dz^E`F[)cLelFB|i$ey_ ahdTFftFhjlhuH  0 P  ri邤ihecѨIIh$& uΜpS_JTU  `0~ H?lw.@e#m ʨGMDDԑ{d/Ȋ!Ryg=Mrk8Te<Ϲe$"cj|F d(0"JJ).Dt;F[O/۴|4(xh:C4ט.c0 q}3,xkպU&U?ڼsSJdJEQ ?!ꑅL1nAT[øX| X+$:9^CɲHDe!Ifz۰Wi^!FTE#vlJiCDUƠP#>R/IV$,m~󗑲ocTjTaO_#n7T'`0׏Z@?Lk") =D"$;X]?Һkb$\OH{IkUDckfʢ*Æm/~9,+D_ ш y쏮Ҽr!g0a! q#Z0!a"aAQŨ  CCX1P} L2Hc6bGbh`8j0Fcל;k wY&)OU%d>ْƨ~y[C FRkY|1 "ɲUEqPǖ$stR\ ^#Fv[RSAæI&ILYV5X3eztpD6t%S'YǓy $..*" //0`0 CEԃEdBTH eS4H@h]}&\4k0ZŜbF'} %9>ǻ_SU/ FC?]lK-[TY<}Ғ{GⰑJ?Cm{ku' wI١m+-[%=!軭;r) :j޵]tBc×VR pMo`07.92_2d&4Pa2YT$U$hwFhȿIÚk)nW4o.DM4Yb+/2یyDpNŇU0X,VkR\TTޞsm٘ aUf962D<1jo{wq*FLyo+]mv8|**滪_iaIz O-RrF_.!~XA [.ĘQ!cZӶUF-ᏌRo4>uk1N\f\9nc6w`0CwIDH J48_AFCSӘ}MR[0ru6oD\KM5I> H]i5nAvDh,O]6||}ٱKIVUU%/?ckRlk~Ɯl ٹ99˗$?:/??'siQ$}!X Lh^eBmFmnX^uŒ__z -ѽKPծs>U:#At;HkV3-؏C,LLq13ؐzׅ#%;21WTxW`0 Ƶc lABDBThH"jL3VmQB֒D^sȊiӴ'[ft%t{ir?&o㝭F'QtDfiC"Lwi+?#3s%-N0!=-5#3{&ٙ4sWM\o <]Cyip8Q)q`eGڇˋ[YP'!kߝo❹C %;C *UsreWھlwr?@g{a1C6 Sb/養20\C/.0 qsEN 8UUoFT_qDhX-w8__mD3Ii\@}8)vT[S1G,(ĢLz- щ&_cfBMc\"T?g%:RR"-sU!ߙ;e!f{7;fJZ)(6 ` fQ/ܦ8tv`:8ny\ g9uۏ{yٱ.ںȋF=>Ʌ/1š_e涇cvk\5+%FM^mϟ?t  t&RбsET[ 뤚L-  ;_~w|o˿ _?`HTC&%ш$3޲MnDG h=r#zUe1>ɲ&9JEMՐ>?]ֈCAS*5"R*hfzK1^i7ac`(p/tOWTYجg|iї0O]J0eKZϟ 3hWp {Yyߕ@5s@0ʿ_i?a>S3;qՇНVofm+LJK|kXlq:Py}9@6MO9\v6H YBj!륿 얗_<[1ϊ 1qߎm4hݟB -XOcy_|;Yڊͽ;~2l3[;7Fdh7O[ 1<<֥u7[ `0n$*b<I##aҜQJt SN¸#|m$*cNCIiŞu^W*H- 2M_M0qgZZ #~kfv69%/갨=?d'"D`"FckOMw1vסRsL*~ѣR6ے RfLI",* SR,˔ska }ƿvwU|nPYD{j05HWpVЁ.aBJ'/v|2FT+{d~ޕJz[p۠u,Zu-YG3$6#䥩mcL# "+7_n!l}t^3wl\N7ܠ1ծW޹_lxvyb^%v?i9"o8]]hL`O[ t&@i4+siy+a>(s'ۈ̕,Èt Q8|'#&/FrѼQD=}o[a}Wc2+ߩ}1Y Z,SfFG6wBZZeUK33 s2nْ ^ԊmM<սgr>^5֭7\/ \(=V-a5xu9I mkACNK3tIh{fCHy/}U[yC¸?xxLxn_WE O8}A\T=ё^[jtt9Fpa<5C3ZW<]Wb2 qU}$ T=L_j_UQdɐ'NE#D/!]۩"}%Б4rs`'58f`Įt.1v"*|}M)*G~4[,yv{~\TTQdI^ u\p&I_*MAqtsN%O|xW'g~tO^ۢC&х3ڍN {d;ɘMp"%,rw$/T|X4Y9*0ងzTɂ}0 7O8]3ò[ F3Jx۲Y@@E4N@iGa[>"MPZF9Fԃ2 责CQE*vdZVURTիWz[w~B['M2 ]骯`zϩ*iv**=M9\#ԣئ{V e= w罻>{o+KfP e߯E@0c=\8 sm1 sL\M7`U<:S6$b[d0qTAJ|9|m8)2asksRj'IK:ġ]_>5q]ߚ԰-7/|隷VsR>?K]U[3f{;|1lk$}|Eaa᚝;Q$#\' 9rUb‚οK=>˷郧JF@d @K!6}^=!8B EDQP!aBcah\'Ns0^أ6\3Qž-nADr<+lf+L\MWu&h0Dq Rwr5TӚ4Mq<\؇s {ֆi8FTf6{.5{YS3M&>StTiپ[%z7e;K_]rUX` $$c=?-30CՋk!J#N'c~eo'驮r/Ē0 )ܢy%*3X. s<5__yfsaXwx<yYbX d535-vl>x_ pD8ș,òn5MtkȽ^e.qO .DO ptNM<6lM!4\4;ϋ;r/M*JJe4)fL(,@yETk'c_s馭vQmV).ܛ0d vМeb#VpZI)g7:#;#qkfɈ k 4'UpǛ-4d?s-HNT]s9xRLŅMkYW~ 7q3/[0oF5r+\0Rdrj~.^yl[OMC=hߢ߾̸6v a&##t#6$KG礷nm&דSѲ={xsŊk}T'OUxfnJry^v7M e9n *AFطou%k9K+)ӧ^$lo@׬rA)GJlf֓t3Lxo>jh_m]ԴԔ"˚J F#I*8p ~57^ɲD1<&qd&ǤIhA5V Jĩ;ٲ5n ɗ+Emsk$a) sv2J s_$fʶd*?~ +4x7j.\Dd~F)ęU7~%"<#+D:\^*)/RO:ԹZ)Ỏ+#죍rlsd?uXLʸ6@2II9?s$ƌӿիK\2*E.rR>)K{Ý;:ykr~FzwYRSMȃr XCRPhɔLЗi e!T BD#4cHuGg_eeei_??}|+(Q᠈&Rt(=:@lqߜii)sol"yR o>t`SwyW`g9bI a3:j J=#QNx)Wi2M9e$*YKהW5K5DLc$꣬Y_ MW S028#~0gp\Y3Ѯ ОqAFٸaMղ^8E&+ A<˲>O DW__oq [GJO}QmR:tQ$҈Tܫխ >{D K /ɒY $ ۰twTdŜT5 >)i"{tƥP.cΈbF,7+µAųd 3d]3z և͟dğ]$ȨP;v׷7i&z^xٜig6*יb_~UڳVB⳺eff__cH@!QDw ߓwWw+Jwkj[}[+ځamHg{/۳JfFF_x﭂:Qu}G9ez&c|^׍Zwi)De-lu͕4c2$6 *O0qOжЎmݺYϽTu1 .lq2i7+QTz'?;'HNB M3IK $GLtoۖ4w !3VFG7fJ7YGi܀ȕFE"{tƥP)DtstF\d4bA_ hgWBA$7%B7o3lI>..P;C9mQ[#o~A^n>gvv}f.Yݺd]nMk<| ogu='++7'OXTFi-ӹ3s\17,xiD*.?d@PX/ȄT*^9蚌\jz`OzE*7 ^~eY;S60\yi̫J&x|ʷJ9gc i{!ן f_ity{񂂑p` Mw4;2|?d@짨T:Ld~Kx0Du~5lG;w8̤:nuWiX)5eLq76wu>cG+uܐ9%%.W>KV1164НHol֜eY2;P?aӝ[ .Af${ԃY>Yp,;N_~OwtC޹GUyH;WwNBHb!A^"N2LԎkjEqb]UPA䡁 !Iw:yoKd0:N=Ws{c7Ilʌ噷ξ$ ǍscuEA7cyvO>kT~?,WsZ-08qedOh4Wr̙KoM3ɲ>dӮQn<<汇/08Y6%BWe|>$4Gc]YCz[C(fI0 Y1r zear['ֽg1[3 FAYy6б$픿dov6h8kvf2 bZsYKkCлM;=~ufAk}ڰ||{QgO]Q#D0 5O*|o<2gt`(zJwxBoyWt쩵54<ʒ3P4jhXZol=1,Bxp}Zl*>pSœ{MKD:J1盭zF p/N`]ODS(4ImTЪE%lkeH|$Pk Ue6Z 3qBd/aUWzgrM u:yxfz~SAFRuq 腎 X G,{cA+ ȵg vjbOK=&`tT)7u缧M !DXe\乑9^QagH!OV]" 令E]OO [JʝNARsTji8i b6gZܦwM z΅)'4JQbv-4-"5+*!i4Az殘dUG}tٳk:xи[~U(f8jF!V=J]sMYnH#!Ǻ `貍,/Nˋw!<ӑ# 05EٮIgpЉ#NUeXtpp` d/h iXb=|wDpňTZnA80Ni̼}ur̂_>88HӴ{x+g@:y2^___Zeʓ]C_,RX/_į"wdI:CR?J!.{҄xb2dU MxlÛ%$2c6Aع;x$Qçi ᄈf0"CUD*[Ӽ`n4` 8Τr+,bآh0Z>o=}}e8M0qzk|^O$T˿D@Wp wINu˲5Ho39'bVw.aa uJݺZE4U$&u뚺4Ja 08nT@&R abcMvlk nsع]j  pA⡾>ۊVT2pکKp'[.hD][dݪpKkf,Z$} )0RLsm>8y+JQԣK92&7&˜'yd(HhTBD9FTkӑi z󭵷UgSF5}]e>ˋ8{CϖsT9@4`x~d7+ KZo^ꓛC/n9ܴiX7uU_D1d ))++Cam++++̩CM@HK6I߱@{OG[} AK&ܺdЉH8֭LkVTjZH#Z{u\_Lb:bɱZ(`9ba/aFd}Ǻe7s:G@\m(..XdXW<Unؐr 2UMüjDQ`DR?vxK`fm~&1l+*4SA\Ba 06DQ镑,;xmڍ PY^Wg^IV˯9A?ɯTyGm=~PR*{P0qIJ.}Ȋ3mm7nSBavV|oH3¨Bx"HAOid Mc, (r:uV$ŒBp]P>M #"򶍂y *aS,Ds% +M.[VD .B~/e]tm;ͺUU1LNRhWbѢE,`ǻeA[ַPtϿ]Vqf#*Ǻ )Dy2=]ɑeB" LB^0:2~!@e (X HxߞSh60$| |<I(ȆgP QŘcb8Q4Zwc pܼ[\$vV-P[ Oz!yr?̄ybAN(yq[34X-EUc݈"I " 8}eϐlT!pTt-*/?* '&4Cܱ] | Ab8*BP"tbύP.K2X?t`.1 {$% mf97~wZEa&vt*%a8Tc^Ƕ 4W IEO6`GۚzU I(H(ZB!D0C>0vr2 .;GF H<߼yl(+/l"|LJ1yrkiޕ]vv₝mO8*zCQ,O+dq5!pd=/wY`[ؗ&,-MB&!m˶d]s(JUGe64_w%Kr+**;dTpCddd?][17u8}f+HV~Ν o, ƲSE:5h?WYܰlk7rYY>'.ǍT))i^S3vw%-@yf߿~e˪kVK.]4Qt?D |w㺕K۷%%EBۅ5=?z(wHѮZh--eF4&Cgm]'O ðK*VݴiSkk`.ȴ\lo Ql&&](N‚~<0%v?܇@rsK.E {4f.IXRRRPP@ \\PwZx n))>ώ-_]8j(MX֍7>r$My\K<V\zݺյs_Ort2G%t=:sF 7֭[ū!wyC% @ ***_'E.@BL2Cs Lmh t3g^.B;E?8z Ii@It z I$m,F;$W5ΰB"f^LCǭL:)پgIȌ5kRD OʙDj1%bҤA&!o :CDwtEt@'LVi+rYql2i8WlvN8KSRɢ2Ǵ.#{}X02Apby yJYtɕ-*A95μB$93ĽTvĜNTѓ&s3!aDiaĜ6xo32j _ Ue-bfl*3v`Nq\Or3 ,{qp)$J[DW~ߴ *7@q( IvJPQ1-j^b `LO7L 2(: LO6dd`Α~jsO%xG)]x2U M_ԩ Q@P\&vj5pų:NOQ𳭫k]^A/Q$N!":Gr*/ˍGV26V*U@ )FwMY/zÏ7޽bq2&iIQ1ҏkXyT=I8C'U &^,f"$5x/Ghk|q;::E56nٳ';on?t0ro*03t5+h\e%<[~uhj=s\]Rrܩl͆Z|>rK~qL2$2I8^Tept9c|槬M5gu"(":SV,^x7iPt]ã|זQx^EG7ѰW^^z>u:M T܉⻇z}j3YƌVŬ)"p\Ooôi6-.(NE"e%&ɴ0>?yy$鰨ؐoH{vnr@A5xઍ_]_`O5_?ẅ?Y瀐UNb9+hB_ӷy$.ng-]bk\Z,EQUvf";V G5̨եyq=XRV_Rg`ݣwZ\gJ^"zw?&!*] n/ALRvwr{~lc06?EIBk^* . gl=tߨ֬_I+젍#Y{Pq*kH4%K9e3G|j+VVϷbڿ\.98Y>У?M"*p},jN%2)~^0hY CSjJ xFhEbh5Ѫ9hP^LͬMu $O)w@ *Jr}DQ͋7WD&3 oFLyo]to#?|˕zb"}:z64G vO<(ro*0>TY AGouAAPDz-KQfT*&Hi! C4aX5a{7RX!];mk46Jd5*EyzgHBkD/Ukq5-g?"b![R{Tj=I)*ѻFmGbA pD)]"$x+`,~Ҫi~w׾Gwt$'#m IE)PbOmа:}J:ucqtv8>|{/wW݃)wa8_rK̔fK;=>gSO.ID>{3}#C=ޱ%ڻj{[sW D L&Y^7 FQFgS~xwqsg>nRË,.RE=E`nweO8?" !s9s vj{sђ eeɽ5,Z`GrolrRxѢ--o2[s*"XMb`₡qy Ya^`Af6Ni9vҝa'*C˖2_Gjtro55H&4?L&ٰa:~bVTݰ.)ZjޣG/`AP!'+-pb2JhQH)C(+LkGHw/_U_{r:|% Su<,bL(}f-$x`c[Y2,kdZ#w#9e9:B]D,cAv`陬Wd,~A549cOIҐ#>X3L&eԻw,]vc`$r/ْg^˳r +8v]+:w=H&␭ˌ Y|^n0}Dj P b4&+5߷P*bj  p2{S־:)IyfAaonQ*`, @1KMƎi74{B0/(5rD޲췯ԙVL?nX,vbWCO"OGX.=[ݾKZˣ8䤤w}҄ @PU1PсM&S\s N)}n!ɼn @#'͝v@гmj~Ss/xOwióFd1@}c''̉1P(&"_`@)ߘ}qpN.o2t-N|BͰO%1“>sf JnJ5  pX|ڻ3`Ygo} q|Bʰ*#dߢN!՜E P!} N@>cDoiޏL>K>o 2c>5OX;XstyWRڂ˿25Đ5s4W /Qx&ilx'"drw @kjYF &KhR~z@Log>.Q$ Cq p슅 '~|uaRw2g}1.nt8!O\b2@ܠ,f۞wWW K1 ʠ0x² .K>W ` dAL00#-~u DY|= 1[:AU  Fhx/ :dP 0Q8{½E仗b2H*wI$Zs)d~򃪗 ދ &wij0&#B^DSI<5vߏ UpC2@BYb2@Ue&N۶wcjJ&)&CM42 n7GF:~ٶ,_wOϼ8inܹsUUU=&+xU2)]]].'@?4>z}|#_N1eX==hqq5UUܼѣ-X̜\+`syƲ^~U*׬;-':;;]rMLvNҒOSMreQ<9s~7 taNi3t =)G;kqj`@l'+ٔVw8e?x_z;zlWI/1ugf#Sr>A 4wesE"x2  vAHَ͝W\YYM,$ ?u 'H"ũy?ն ԵffI [Mg[W-9f̼j^!Q~e?>w0d&3'Vϝqսj/eFBaX,/9Dij/uoӄ@Ff~8%r N/J:Zŋt}{H_˴0>=@)+|9} &ф>Lƀb(&Nc4.E:͈F9ayzn9Q^}[2̩'23%>Fs8P=[LFg9OKji4>s- ]&~6e~^Veャ ;{!r|4[M[U__W)-+[ǭ5\{շ7XJQTwkA d )f]7wJ7yxRBC3gWϑ|>>k`?s3+1>6W=2N6?.@4MO$Vb2Yer-F`o72/75bY!Z1{l*-iѦvNoi/?$CRQV'iߒ$MTouѤ^=p$m6G3GBѥ|W2 fwT]$/Xp톔b$$e+@ 4mw`"ϽHRqP2ςl|v)@ݑAn{jaDJht.(_RaBr}qԈ'=yy5)!8VVXPM3-'-M^zM7: Yi:~ijr>s")β܌׍0@RO獸~LZyݺXq̬3翟6alwk@ 4}ov.o%B̠?H dyY<_/)RȤJ/kjRS' F'^;5prfi1wtZ9=% mVzw"uB=4}ohNRDJv'j:Z/NokY0E7bzttt1 eLBdP3G|2{*!]@-lR1ɤ8NB|MIRS %MDӨdB m3, H,rj)J{:t[;M|͏] ~llj<+]>&-Cb ɲ2'KkfV5 %~0̚t:PAb ه8KxŐ=31$P}:#/ЫlC:Ev;JOK%)M)vYemSOekeXuYDBH,x?R;QF?.;֑^xdA <:(WӴYŚg8jW"qpeϿ6g.idj  DU dد~֖iIL@8WH i3Q<ĝ6$Rd$J%%YFP.E&S,M6=mG˔t٬RM -/*Λv te𯫺#'99 뾁GgDZ]<eFw@au@WPT   EjzɴݝN砫U*U_}W 5v1X0Gk_ܛo#].Շu_=v|qSFF@ˆBǑJk dJK f͜mJ!#ƶ)'A刐)ňҝ=ܢ<0n`5n؏3I~7,]2UhsG՞?9_R/Ejq«[۷o'LL5qyi~E1q}@0tdV)jjW6Tfd[dlB Zk[}\L5}&+gRK/:qjIIZuVuh":Z%EEE;!sk2P!cWTPܕpEe5'gǻ,7]qbPQ? C0i>3g+zƔA껺#Z ˮWi_nZ$h4\MJM2|uΝ;,B^ބ?_Uό-lhjf㵿oiG('rG"A r)ˎ؞}N+C,Hŀ.'<1 Gd 0/Q~ wZs*hϵ:)&Fd,^ z-A-)&-[p8؅斏X u̸WɷX3g}b Y@`h'Lh)Ԋ⢑lzW\Ԡ׍)$~vTwor,kS'Zc5,0Hj))MS$/xطieJሦB-x^RSlDlT h~8FϷ낯VYT~mܯyyst`=@23cqNu ukh8NqW42,j9W27lPq0C=[x ^b,{ɠ'p9{M$IQ`dJTQbvX"&ns3ξX̻K L錌k @SK3{7ON67A F;ZQm%SK bkߔJ0 $xpUT !|l Z%=x)Hᘈ5졦f: 6F!o.Q᮹vIE?]O25zC P7|| kP!t̹-|do}۶mO~s_؄_ߦV.ݐP | zSkvF0۞34ۚ3["DHJ#r2uK i¹WiQ_fTJ=Ϟ=t¢b2!5uuV=kʕ555JrGϭoiٝw$hX v*9+3gWWTV=Q.ˤ׉b( I1ZJ.wgi̻U* B,˂>ÌCXO-[`G"A !`b.> &;ds26899Ç?/avۿ.d#-:' c[ҩL|;ԛt#rEz{uYӑuֱiq/++3 t!˯uu9Kv҂ Vm~u+-_vRUk daAܵ3};FдZW_vTcoE UjkkiZvMNbCCf%jA#9?o{4ٳ$|4~iZT$_b0t=E\uc&' [}jfp\aX~~~S'Mlk8B0B{7<.R-cﭮh>}o_pJ]8cl^bSO=uA0#dXIu)2r2Ĕ߲pȏ#L+V@ ! ¸.ƍຼ9 'd܃ {pr2AN=dLj?M AYP'778@PTCPߜ,Z9,Oq/v=NH~߁= T"SQ4A@KQV/j#D]c(&;P"6P!ץEPҵ1J[8~p߬GYx.־ oLIcag # d|'CWY\[!9I6YjRq]dUC16~#GWю4нKF A1OVxr{w0VK9Ӹ./ 1 Vdr'$\}@Ğ~܋͸.2ǁFֱq^V)3J'|N 8AAs2"a+ K& += 38F6}Gٳ~QӍ_^W.*+I3G'zqJ\]=P#L2Id0L"9Y P7,,Y"9|""&%!9$P Ye%hfz U6ŜftiNaI7^[6U.i*d =d d yU*̾&' 4f`vy$IY-& ! Ǧef0'K H29 'c:HG=wx{^e+]w0_샕T  'q"2#† @qή$ t ͢'[Z 9TDNɸ.( ڵwO>fL&\N\.;ΪS+V'K[*zd;"mH>8C* a`HFNV}lT_\XnNvhcƁnsMf˹.X5pF=X,fYRjN}i&> }Rw-rLBȕ}nw_}Cx A_{z¹r]^c/nQqP[1_rDEuyjZhl6T*OȵoX2_97G{ K_zEZRfyǙ- dwD"k!/Х_@o-i ^88=x.Is "0M{|x0ri&`4. j;]Ǟ[pCBd !^'HR$IQHTyG9ے;pQLE#U=RŸѼ_̝mm|~bB]&B] km>p_,oEĢB^ jਁ8Tk^zOihh0?:H ^d-ݽ/~veU>3۶[^ ŅUj2߬.ux===.}7.U R/?&sA]H*E)fZ&X>ڳ'g:.n$VN4~TC!gop:Oe:{ fׯ_W\nXiD"'rt;Ly ]^]7a/z,Q CO7-;[yuN2[}(2 bZס+UYb$wzڳ[}~US h I "q 5=O,2\U5pI[Wlmii.! $#j0߿&+uW/rLvMsUz4VvϘ<_pt?v;m4#nގ]M$EnA_kTglfzfg:l^b%z/J{X)!ZܠVez=.]_`Xh\)u;]Ǐ4UZiN)/ 8K-jjtw|f,!1uE{>*ʟNQd.{<WW0+EN*Enl FS}R^vM)|4ќ^"U[f3lj:7Ea;fmUހV.RgA[!S[vv:I&dI"Ie9=.LQQ헚Whj*BJ jA LDB\$?dlL"HRwQig;GN%" WQ\GYu\qgt}fayXqDqtFP/oyG낁"fg BMmNa4j5}%7#[l8Vq|m+SҒnW[[kkKc3P)*l nw;H.bd!GJ0kn_%d;`0z,kllܿs 2FG}WWWCcw-7<6$Q7OUOh eHԥ'$\.)l6iOkN͌e*JB#^p<g1bue:E6g̚d)z O8 ?,Z%t@F2pL&'vpsT%P'=~{~/ss2hhy\%PתmW^M-,ZuˏgsH.vN2kV)6baƠg}>j4Z1h5-C5t K8{FC9FMDBqZKy"#8:,iyw>?mx^dQH5-!7fX2,yQҟ}צ+f/^A( 𤱎t42fW=m{V8orum]*~^x6---V=~,iݶSބlަT&Q^0hY CSjJ z;/ъĨ':5jUsѠ&x2Ifm)2JPQ¥~hE5/rcyӺ9k{pK%褈Lr͗Ƃ;yeOFwy8tt31'Czgcǎ[(⢂X[A8hjMLQ3^e)"4Cg' ϒK]'b~,=,8駟"#8jKm 'dӧgF"}-'LjHV۲lٲ%9K+tnhZƧf]ښNJEQ=~ 5ܽ$-5UC-0 kPr>0pZ{&+<U@}=Te9 eA&D 20s3ӆgۚ3s亚cNsA&ހW9^5&'3ZE [F^ 0 Ɋ >nofhi|k5bMvrtIZy44[tɠTTq CBwW-)=|йsjuYYYQQT67CL(^$w󕂢מYqM74~)!&A{ #>d7}IOKJJf͜T~M =_ò)@p(eVvjaf4dJ|mmѰVX0v/钗 #r>*77733iiSUXTNVO20CQzM֏f[zܭ11r7aC2`P>w9(ĵ5d`D Ld=l"Up1B5$ ~cw?=@hjAM ?dCM ?dCM dRj-,uQdPɺ\ȆL8RHMl!`¹.}};pqoCaЖhz(<"J! |0cHFJ8< o KoΡæа_I@\qy;JsqXb#j}eԁ ?z}gط þP1TN$/pyRї4@NAULp2]bAtfo@ƵyMWふf覆XA;y8 mMIc| fCEKrH!dOo: =lKB {Tr9yq&õ0428}wZŇ>0p Y2A&bѧ95h8 r'xbCCF{eЙ;7#+ץftK1MG͛I`_s`j^8=2+5Y2pn# 3̩df QGCEE2Fϓ@8_YWr!9?-2_0( |7Qbj2FGqS&|.&PIj2&j2PJPQ¥úwIy0MDV^ʚj`{ "sL˘ ^P /?Ov̗^9ˏ4}$w`BM0oꅗ `WܠT*ki>*w{`CM0$ o "^=TPtw%ݝWzFn0?P5P5P5&RMvU:|r &5cSm|a3urh":}ߞ2-/0?/іhKNLLMNRӴM@ܔ^";/Pifc^_)s=)Hbnⴶ;h0v׹_| aoY2oUdܚ}Ub\|}n;ob&HV5R!vi|d U[D~71V[2w̱Iq{b%tGcFmEXhX+ʫOS&VU69QYuT[JO$lS4MLp\xaǧ )Sܿxyee>pa~SgV{ .Ov{zz4M?xm5ׯ#koaFB􇏷0d(M~uj6)6Ŭ)"p\cTio[̉E"e%&I0Yy0X簨۷ʰɽpOK3%x1ۢ{tկW-U粯ӝbڼ\" ϫh{%/ڶmo;;+th*@ܶn}*sd dQ9;oaьYF ^;N:rJl͛JK?J:x}30\c@DPVd!эdDHݧ]MV%fD61QU@{9{J=]GW_S5ׯt_"orǎ_=o՛`d:'Vo"dVdSkx~MS,˺kcTKwiq鼩BgN=apooOOwGǒY Jw7{y"4$ P+$l޹jfgvfHŸ ?b [~ŋ)\P#ڗ/;C\('s:^6Db*ƈCxc]6q%EnWiQ=>ml?]RL pr(ѡA MIOȓK^z~cG[P{Gݮ ]pi+}G1VF'9'y_V^1<4<\XY6. 6;v\> Bqt֔Θ?ywxn[篽wrzvnϞ z(*t) e1Ie["&-W"4 ٕ5mZLo۩_]d q.$Yf)>+  Mvp4Ca5PPfMeoEbF \0p|p$xM֩=Jp-Osp/ Dj:tvg=}J6mzDž %.eh@:؝oO-ګoƫz=J$,r2q޲]Ã[)D8.@ PEIJRZ&>Ҕt(n뎁=>LVa|qi3|}NWAMKt60<7Gqgo};?M,VoD@1![dq?XɆdR/?gѯ.Rr0zɅLo$D\xd>Z$dWN&rc)5]GN'OUzK1O&>8XO]gMpκ홽cUyt!*)ttԻ 8'I. NWQ)yt']F8>Ȫ-[7XwoKNY+R^f)!?'pWE/L]ƙTZbLAI7B澨OdNd+Jʶ񯲲rWg֕>t!/Z8sDK{~R}AZP_ }]B`thRYe+?pٳ)JH  kG)(-joyV444("8&CW4b791ɨSqB3SXgѱ}fa(J9ƁI(BvөT"4X$aHd]NV?ɵN5󼧤|Ҋ_7u_"fZ;Y9sE^A2φN[3͙sW_Mzuj=۷KĦ 7sQ   HĊ'! /tH59Q/Oi1 '9bIeʴ9rJN813'nՙ6"曯V-@.' 7xNzXoř1s @eR8,>>ow՘E4W:Q3Tz4CRfi:&fEbV?Z%֔.4yj,r5Z(.,EE:h svlv۴O~Xd\JsR64w:AaBLF:i.--  t7:t[{}:Nf{yb=b5o=-gdo~\&,|*)ǣhW|shh`P8/8n$/8/%d\"ÆD/  5T&2Ήt8 hz5W] ε~sm~}@~BB 淞TL~WMs52;w#%se&/<*P#͢4cSY)Ym1~q"T=nWM]ĠhSq[xe RTŒt xs}|lu jb~,[+9RC4I?!*HaKiyB~I)L,,%Ok!IR3e+L='zs Ѭ8B<_|4XĠhR9[R_q\#nBH1%x1!$'FG޸{asyx2ZcC{hm}A鑑[7{<%3fyJ*.Soh@Фe:!3bYfK\<3T=GR92t ǯP3 BVm/6U8w7'#NLԽ{:WvzjJ< pc?8Nv=?<䚢nd***ް^5k֧~:w܊7?uZLЀ#̍}B|$DJXq8 ?6lͲIHTiE"MWSSa1o .z{uή Ű7 dv4–tf*qz gA܄W*;c$BAN!bIDNd2e}HyhS+&w<7 09u֝>ȸbΕ7\kuNvCioy`(䈐#K_826|u@wJ\瞶2_f1!+z ȇW殫C{KSjeQU F'z=duDXth־M;O&~X'%Bk\NY@S0|yr2& `=dwɧ:|/~O%.0V-hVƵ0[ou6x2!'r2!'ʩD{tRS0iZיz5B$zuJDCJ%履702FNadSNq1Ƥ\t^ɄB2ޢ.hliMsX@crLڡ}E̸%Uש]a}7cz˪33k"mK-vi.{3~4gN7'9b0.^7.j:}W~ׅf&?q1[vy4.Z5X*O=|.9a)-X^b>(sz%gTbf~ۓ ̋s2L>ǸL75mOT2I"韰F(g몫Wފȯi 2?(f&a8(n )i~Z?čIzWL]lQB!Y0IL>DܵH&)K83+2]rB JN3զe4+1?S掛wr!YIkЯsCM* Xt0?[VO佱P&Tޠs;. ;c5]R*}-L S3_i;ʝO@ujJ8(3թILafN2+JtyXٖWЂ1h;.3Lb:޺>x'v[g񊲭 kJxZPi(=`cp*L=G$R3]ꍍK˙kЫ$ɉ4[g{3]gYx: ;ɲs|irHWIMIsơftmfNCDtM^SjFY|;}e?w{U+[Oߠb16с,jqW]"3kd;Jn 2m?y{vl~tб39I_҅+t9 ;M4LTj&}:3v`RJ9a&`0hj0 Vr2!'r2!'r2!'r2!'r2!'r2!'r2o~V$)86˂x\ ~svЯ|w#Hf}ZҰxr nImW4eve/"@< LO&'ēdd2x2@l&[O7_㻹imaNdaڟn#;ی:\ɀb:(6TWMS*7EƩqP&fMsd񇢾Y;8D'7Ɯ퓷l݇۹&#v{scnY3nfmFל߷ $L>*'<@cY?o\ɰ;O>zy⻷yG581ݽ5-׏0ܘoG}II?}Ǟl}X;'$W|q[R͈ WT ܸ|z_~f-o5Xt Pafsw\ i>U5myl=g%brxL p+ɺu`.HAL͟X1'eyPk{M[5L-gv|r*x0ladFsb,|*:9Wt2UyfnDU;,d`ev=پ=&bü[7gY`ݟaJ8B'XB0t}2M&'ēdd2x2@< LO&'ēdd2x2@< LO&'ēdd2xL^6.E{='lg9/0Α\4Ij`'S}뫛KLn.ٛ'i|OF4\?1ZrS O'ɭkqdO{<oX7{uwun}ZfDiӒۛg=FcNڝcoQQaz0KFϐE<rRuyl>n=h=.42mɽVE{Fep+VLi36ǨIw칲THk\75'7vv~.\R7 ;3d+AM6 :ˏhp 7&ܽqUal3?UIWumY(zv1位񻏹))sO~};uGv7{ϟ_|;?hU\S*h߯6[YR#\gltҫpru  LO&'ēdd2xό|]qigMއPv2sD=սce=@< LO&'ēdr'ӳ]Qe?:;Z2_ί%3>>;=?ufd= `^d'08#0dd2x2@< Ld|5..F`!}sqq0썿ݽ|__˨="{&/|_?iO#֧'z.sh;1bO16lL~MB*c^פ3߿|EpcIENDB`knopflerfish-osgi-5.1.0/docs/images/desktop_info_log.gif0000644000175000017500000016360612346515440022377 0ustar felixfelixGIF89a1#%- %1!!#!6"<=3?MS@g^hZAccckgcskc Bx'Rs@Tqh hh!(jJj**Zj:k뮷j믮[kk*˫iRkmf;lj[ݦr{횻-+;// \ 7G0K_\aFZ:cJ=`*RzgƁ(ȋ m4H_K'NGPS-uX_\g^ _-ǖjvk7p6lmu덷܀}7}>ވv+޸͸]gw瞇袗N馧ꡏ,*L/r@< &rmrUMrV޼c4|K_=cg?׃}o_w_?//uW2 'x@ *d %:GZ0%`W0jKa _8C^P7amЇ<HH%nPlȔ }#Xf;\*Az yhBSB 9ڱxGя}HH@RDd iF*|##IDV)C*u2yR$R&O<&WJץd)_)Xe.Y^꒖,}KTS f/9JRR3))OFB59gz 6iMos,ytT8MwJs&>өeȡ VPpGИmq'P0 hA :*KG8"" HG:@AEG@8Ƴ)t4YJ]6$3 Tը$=zԥ6uOMjTTvҪ$*STBիR+Uˑ-%e&MmΜ6yjַUp$zjε{k\׷kaX.VcYN\;i|vU,gYίn5gGӶeml [{2 e @Ѓ-n@9៿{x(rUH1c\4A\:@ P{߻j{yv ~p|`vp`O%8=WOboVgmjƹ^q\cX7ɪc8<񎇼cUvn-jYZΞΜrlvjY\7fώr:h(C P%pUsD7Y3n׻Ux;*] Z,0݀LW!k F3ȑ$3xaD$6ëeYۺָpak?޺׮i l^_nbi;_`z6-njwXvEabiOSSp`  j7oox{w0ǻ>t:=׏=\=n X蚗eoz' Cw\ ۢ T Pbg_WMbxIh sM @6@o}kR&~}  gF'Ggfq`7D72| I8D6< m?z Bx4uDtd7A7;F=k?7_$zEt|Cug{H29X8vGRTA\HlOX 6GWSY;FsFJTmt[7tHz@fIFW'|HhDXA@$PoQtfiU6+$%XD6ЉxMޕD0Dr5RR2 7 0`s2W 0~GetA:~0 @@p ғ2׌K)X08x w@P X H0Ҁw )`ӈH hn8U#"$I!c)aeDŽHa_=4=Gvxx==G?S7yCBBx9{Ǔ? @1@{;IRzanG|l,6kmIGrqQ;+5̗\SPoV}Yq,]R&~Y_LɰH ԰i @Sh p 0ntGt)  t  k Pxh _j370/0;@W S0!YAؐfwVjǛAMoٖutyiɟ>9CO>y`g{mj _Fl'wJlx;yX'jmv*vOyG `"_r{.:ǔvàaFA5zFW`Zix><pX)KԬ)l [hPEH8)kίI2͞ L)L0 P 0㽴 W0 PV0}-1bc*9~>:=BV^0T>[]k}Rbnec~h~SnOrJvjzM-PҷD'PJ%.p۳iZˈ!ɫP>[ Pi0ٛԀ!, TkC i.m/{p mhtW i0 А9. $|ja U`!д(/x /P됫` nt ==<%v` Xxa)) ) ) /0/rS!#&_$*/0,/&?,06;0^D\܇+@i)v  |_|z O ID7Iy Vo OLj ͬ'D ޼$\spI$ c됩C~ |DOy%<'O))/o?)iԨXp@ *DpC%:Dʼnf8#GAz4ǐKJXƊS¤9S͙6;⤹߉=z#Z .N ѴA)i(HV@ @3cƊLh͂ "X!'*87u1b4~(otNTvp~0ė( A #P 0 3\B94C ! D G|A cq%Ps\EAE#$xpaɥ"HH$\r&R )/SLA-+j.3HC8X{*C@ 7X Q7 @i?1MREt:T1ClOVu7KXS5RO?TUDoeSEuMXcEvYeeYgvZiZkNXxwV)'Q[sWHrrHgH*@̴9֬< Nպ5X f1O.?)vdmK&dSFye[fecHy)svҩuU*gw~Fw*-Z.V`p7ԨLfe/.{mfm{nRyouho*bvzqƝ&橁k6۴g%5s6GsCsVE7}SG}u[gucgvs]n]ށ>x7x?ޓo^ߟwxgG$ߵᙯ~yħh~}W~?,' G,ߖҠ C d`U L +0Ք01L gh 5{;7BP)da p3!@tCPEBaxЇA$"8# FD{8"!BNLbD,J@$Q aX%(a KJy 2d*Q912[yKWe/yK_*/Kb&STf3{ KYǜ%4Kk3&6oz3⼦,irv :N[r4*3OjSg;Yf- P(!\BPR>4 eC%Jщ*4E-QnGKғt"(D]Q=DcP*Ԕ h'}IJdQ T%ɂ<rP>թST`ZjW:U|իckYzVkUk[يְ^n[zW5_*Uչʵ` ~M]l_µ*Yֽ keUJ6x%U3[ZԎVejzڦXԸBVms`TD1Eqùϥ.t[]B7nw]oy{^UosW|7/x]v7uK`W f^7̭n{1KZ̀.)\r87ɝoظ*F]l80N1WlX 8(vL#+7]r&#Sr&sE1le$XYw\8BquY\%q{f8<\xJl\l+q+9RfsqGaqp8ě>qiK+#'-iSZʈV5WSձuej\Z׵6'Nv}lc'Vv=MjrXѣ^񑋌bf@ƞ]No;[sN1srKw=uʹ{]y{X]6Ґw}~s#GlnL8Z6sCpjc)5}o{ 7S7_uY^9O>n)~wm~?Rǹ>{5a9Qozܿo0{2W{:y߻wH.^8knWǝ`> _2.^ԅqxƹkxaHWN>>xe܌7LxG{_m$GǽpxwU<oG?]~'z?t??cc89SKc@s@L.7vs{3;43K<D32r{5껷;=3;}{ök#45䪿ヮArӸK9=6& C7qc"&=1+5C@[;SC“zʹ.8ǣGk}c>Sd2WE ;9>Ds9;?#;l1C@d@;pHI,E o;qAkà;yR+T6:8"B'kżE;4"/51bB^$;:=n>sC=$-930ś=⳼KFɛ`[4M<$8EL?_qHċ54GD >h[<2O.|M :c;/G<@:zI.s;kpH)=!kó!s2'$ ; 5#ÚS,3ӹ:3{FF7$L/EvT,G; ~c1DYʀł\B |H0Jk?Yk.\E~dJ@$ƘCF&<"H EudIMAJ;2;LMD?>,1sL MNNJ<4s.)W^<3y#E}>TC4_ԷlllķVL,5:,:KE ܽ;?: @šã{Hn;$l=tO,3AKZτSG8;#"LK>ФA(,KdL`[K2CC HTĠsGMH ClHMQDKyKR o,CQ;L$Ry324/Yܳ)u:ƬKќG|1N,R+X۴(E#L(E4IC#= _;$R$+O=5=["0NνLARQ0 úTCIфQ}DADL@OQNL.tAbԽTΏKS\ԯ U_3V/EOLB$j SG3%=&z|<5S'5<=M$G'DU+j]T5Ag4PS#qS;F=GH3pUG8sIILSXJ>g-mRMJJ?Qq_eV[2!ٜnMMRpRBS˃K*.Z PVWdX. K-{]/KK[ =3+OK̿lO@SG .u=;LCE;4 {."T*CJHEE <}ٮӮ#ڴ?Uu2U$Y]uO?H]jTN"uHδqŽC_#DlZԺE˝N:c+4إZ]U$XeB#SyD3ZR~u\)̳F,> \VzӪ3Oۃ:I][ 9ItSU̷<[<^C=;ClM< >g5\UdIM[MjECOaھa\L};tTeSֽƳPshT]*0Gu8l9'fI=ȳL\`~da(R:%D$ӤTH"$L<]OLUu02ڜ|AB2QAn$ҩcC餴E5汲&;(<;vNֵ>Jm9`-F{݊Uݥ]jO]ޖ1˴׿=kiGO+ ~WS5lyVOelS|hf݁6X>7lC]F†<8viuK ,[Addip \OD}i/Zgmo ųtud%\uNF ChӁ[4`aC}OLԦPA5 5\'nѩS&ےʭuCEUpmĖVlndfm 74Z3qMPf,>Y6 AAunj-g:L ƥf,jB1GbDP[뻅mcShF%X8l3VV ^_vOu roCoIcnE5}G'S#٘|eۥ3@vOoDurX^:vuN{؝tLmw7^f>!\T[a~=u[HT~fD;ۿhvreO$'oudDjT(ҢI*mҨNBj*VZ"eFfVbfz)ֲm-ܸrҭk.޼z/.|wJ+L46'KL̘7kРG.MԨWnteײ_φYܺw7sa8{!^Fń3DM8dfy|'x`!'u˟Ǚ~u'=w}W} c^%! _6 wy 3٥ރEل(rM^55x#9#\4(? 32c*G6m'Y61xdRfeXY}YIfejYY^er& gz)egev9((Iy3x)j)0r!GjStEY8hPȠ-Y^ ] bIlJ,ў)%n n #↘'Nf+{/{r/rXK1Ԭ5飘v+jqnFqfagK|1 r"9q7l#rqeWv\ʥ!z n =4EקJX4K/= GV}aXS+bɓ+ jgsUG}/ʝ!ږY}7ّ=V~R*ks+Xx;ZN7=!^.ww~窟~vG>;gMNFJ{;Ed66w('cv(SdoQfyUWbo!_fgy2 ?5kKxnUL3je?OA2 rP0B+Ai%4XULŨ5p::E@ |ZdXc{dh1!x(&'ZxЦ;`26se&2D'Hڱ " : ;'_dh7JKf+.U sѠrHqH}(DE:(A dE-jQ9Dm:y M"Z)6d@Ч12%.h s޼0EQD|a H׸)4Ch</I+gᇌ 毜8pɏ6#w!xJvF]ϼ"íb7PZϜlzERxcsYL-u,RDv|Z@{Yf.eXj.(Di V-!GAI0&cp̝fh<@t?@ӺQnq: Ԩ|>m:jt|KZw-ә׼6Nlݎq_Zֽnc{rhArKmxk0$ԛ H_u뼔^ؗkAN)N+N 00vbl>GϦ=42/F̯V?HZϗ+~0)j 36+a|~KFy̰PTR;3UWz~Q5>cw۲]6AnAGA WŨQ[˅}CQ[%%hOd͠SA A " ֔:" >` |A1HIO@N:mQhM5\ՕyӧP!d ŏԄXS!ؕu_y՟]߭aakim%рJK[ Ev ٪ARsUl" TW udOv0B X@D h" X`:  "B>tC >4!0HڨɀIK;W|amASe$!5FqaՈW5Zᶝ߮a !#_ɣ>١;c>z bn[m s,F)da+SA2.E@FVP~=)իZ ,@ @W ɀO=@CTi\җZڢpI`ZZ(N=JW砓4>5~OPTRfel_E>U5]a;~ݭ[a\֡$a[Z~]%ՕBB:)R޺4d(Ahh"`e|@1LEܩ(&m&+mS>tC7|APn\zpe Q2Z">1 ҅FeFIe#R$#sv,&gPpUEdE{H| |G}.4&%C6"LvH PIv4ӥ!v=+ Y'w J@JAՄu耞dT6  !E A-uU#RRʓ3:U^ڴ1i<} D_(۰'~jPcVTd:zsDe)%~O>Ohu BD(>=iRtl$mm%FjvQU]+$jhčXaъ)@,ꬼ&( ڜM@[zͻuxjrVFJԒeuM܁K>V2*J:址MM " KVMW"4j,@b],rvFjX`.ImБ#IӲA괎<9LT-J ?}R#1Old|f/ $llL&%LE΄ @M"F8:`IʭsndN fL`1ѹunQTLvJ*"\uXOȨ"E?pjrL0 2fNٜnɤun+V!REOFtHʄ,k +T* 1^A0GiemUmBiH~񐞯tfP0f_& O_Yo&uMT!-Z;LID2JH2%O%W2&_&g2'o'w2(Cīʜ#au5.E+gX>qڎ: rw {Dj}ö=99 dƆMr*Œp6w388Ce88k93:7s;s993=s=ϳ=3>d\@@4AA4B'B/4C7C?4DGDO4EWE_4FgFo4GwG4HH4IFGII4KK4LǴLtA[M4NNH9,.L Q5RuR/RR35TTTW5U_uTgTkU[WsW5XWXX75ZZo[gu[#\uZu]ߵ]O90WZ`u``6bbbc'6cGc76dOdW6fSf_f[gg6ggw6hh6jjJiP_JqD=m6nn6oo6pp۶l)]2( 5mZqT"IAalޖ豟7{S;#K{c{pk{{{/C{r{ w[/blVwy| |7|:(  Nq :9(qB$k /i~ɕ0=gVۄw~^>I秹yP_|:Ǿ›==zCۍ[ǏG{B?PU Ma"C(C KA\#'G_y% >8'Ʃ紱 òǭ*0}ՌzZ}>2rǐp`Aq lHB "@!2f7.tpcP N1r0Y!D 3J.\gN;yhPC5ziR:5鳧QBjjիQvkW_ÂoiZkG#TRF>%& "M1b 2㾄' <0b?C>Fz3{ tќ!oA 1NMPd̩E8!/6{sr;?9yǧ~w&.~=zcm+Ƃ9r-ULiGM)lB0-ZpD@0+)j4J6\~h(.% ~|P lJ(K *0,0H1ۭ$/j!$ jD<ȤHcѰQ1Ú \MLi1Q4Hr=L9(冷F`sۃͺI0j Qt6 issɄC&#H '8eb-J, 8 ‰' kYڦ4էU[}Z..$^3JɾX;RJiQ$]$ QLW[1L3$v7=+a}#RuX#,KӷڽBc(#@DxW~yH5- Q{>./۞b/B#< 韴gS"X`h' #Y&`^^mjڦ.褗ƺm𡇾;L$obȊ";8-x'TQ E(h B4{ fjS- B1Dp > WXNl ܕ@=KeS#,!p VgDhLU@9iO"CEaQdЏ2LAO=|E.^n+BKZD=f=`MiY Zr]-gK[}EAl;#5-Bj;Z67mmg\ܪu-rG]w ^%r;]ݺwխv$'I"_bSJ@HvB5XJH6P X2f-p2R`Dx>vLaYRpЁ,I>q ! (@R[8ZsVc$` (L`%MZ)~x_> O p?+(L1Rovs-Jjax""!j HB,& AzpZ7@"m#J8)'ocpaʠ z bdHV 0 1z?Ri(CQq(u I .IJpڊ2@i}} &q) `aifaap ,8Vv aQmp zt*vP0$Wq iZq3(!@`-A @  A@( ! ݔ,NV-5c6 6uQv blS "h`},0O-`393A`4q =TTSx0![h0?ISs1qT"3VHw6$`$a !Pf@@:*AE!@@ aL,ll G ,C?@FDO4EUZ `TFsYO]lD()B'BKB C  mha<7~f)QNqBepB!N'"''P}BOuP@R@C4- U)NRwbR+(0u(S1 fb2w% H;tK)t :i$Qq4(Dn! P  P YX@S8 X3AWyWUXUY[ 𖖰,MU U31UWq$au dֳ =rOsQRRO uaRa5PCiU(4Y1(,(8':Y+$S|,?̇im5U%^I-h4@a*hAU'-d;P8FAg!zgVSCqr:;;i`#]U$evhip=/Meh3):5'<9ixm..U/`QDV'z'Q7MWsp6qrtXs Wp%p%swSW#q9pNxA8/؂7v@TI#w ,"*)3A3x}J`B!O5Z:* AXPqk0Z Aن`'X ~V_4MynM/N|؅yX#xFRarWrxru9؂8ra;9ׂq-QyuES/P|B1>3@o BAB Ը'F5Gѵ,+RuݤAW)z]oI 9 yn7Ϗ6(^w'XO]y#z OS5Y(!8rYGم3ZbMؑ:-27[8ڢUbFטV_۲BA3!aaMaE)]LZ*l@ZSj@9)9~tKO| Lv> ٜb7a+xCa!#qSU9ڱgOygSX 3[o=e}S@aw&~8K U7$S<{" @9UFkWQy۷!۩%"3ewxW `H]w+`Rh/!J '[ {Ct/J\bބ!_EY1p)c)F9S|( `ݙ3}@0,y,?V.ݫ87]l[Ńxc~[m./X^Ǟ~YӞ\^מU JVN֦i̪~B@" uqzș ~ Pқ>) !?ܖ=׮nBA{__-_?_@I}%"(F8ϳ,H  :|ȰgO ;zp!D"6$1ʕ,[L#F82ΝPR+Jc?>!Cv?d̉ZzŚ=6-زj۶L28ȑÔfE5(pa[܄Ō]RU*CZ03Bf&dOz63Ŕ> ,_k=gX JQI"8Q)#_="iLswVk`urí |$Ok>ݹsH-ABO~z)-TQ2POqm_ǜ":D9hG9x]_fJԈJ)hc>·fY9 ȤCyِ#G7VOm EQH)ŔSD5UUb,#GfJqfњ͹wzĕ&IWzI眊rThu":]XYap g椞~j|ON}DJi_Zڪ $) 2X)ф)[pjRrvԧMyzgb~vu~*{Z%]vfH6eH$JouZ֥Hr13\45YުNBR"Bk9]7˨K. ?*sFg3ve19yMތthjF-%դNFn5KUTT-,|'-:w2$ [Ŝ5Dž~r6f˄ )XL-f_KB)\|ovi%ybZ6eQ oS8%q&?<o<&x/=x'߼18(ˏ$`!eh.Elaz @kgzz fA!O͂.H+(4/Z| WȅE.Nff' ~7Ǒrf*cOy̆,ɧXH$ҵGk_s:Є'3yZ`MkłY3V HHg? ЊviOY΢vmkGֳmoꖵݭog+qiPe9"b\j LG#t@A^WAk%չa2-HM5uTM /3._B` x n a?8%laf0?L 1O&N1W` 4n/TH,'c ZtHCz҃--iLє3D.;uqiU3JpUUF2{%5}x]lw \^u8yZ,Pl0^:ST|u92ֶ nn{洷]nt{N7qhu˛݆ݍv{ ~|npz8sKOp"zr@dsy].вcW<тT~l1!CI хnL_Ӆb*Qzӫ_Y?t-}O';֗nﱗ}_7}rۧ.Ͻz;1*F[r[ƒnrǿۼauL! ?/ +=s؛U^!/U՚/a4z5"/Tu_1MgTm7tGtuV~mH7nI{xt+I'oViU1&#vhB'cB~+*I-, :X9؃5(>h@|7gUyPP5"WH Al;Cx(ov2HuW'~~v8GF|vǀat█Χ(8X8؏RX*ȐZVtwDH n f) C{N/w]Z?/l# (LHe;JsNYV#wG8nzwf}aw&6(Wn\WH^fYHfY}mi'|RGT Hз8G:fG r4?dL8?ScS:ʨ,!IL:^ǘzl;ɋ h\ N鉌uSvh([Pꉞth槠*oi(VZj)njZz.ʭ.qC'HδphL30ݚ9W@@ftQ֦:%xw餍Xm*k ǡO ^Y}g1˂㸰餖uv Yoz7n{oRɉ >g1eAP695˳<7 9:;>FkCB+!GSYJŇ_ٵ7ڪͺ gD g_ ډϺR\*[j J۱yr-(+OHap _s ȡgi|XWؔSɎy ̹by_Zz v fQlj˹Xq`hI`짭5٫2J `BM_Ł n  omy eԉ|fBvnc+۫ʫ 8;Xp"oG\ !mHmCx ܄{'}˫+|F}di6Dx8XjsTXmw'tָ2c-)gԽ6 φ+DTJ!HB슕HiznKKj7;Y)[ڪ)RL~؉춯=ܵX~Z\ƭNC»;MdA 觓 I tK}Yӧe XlaYH YD,۹jk٢ 4Psj6Qzɷ i[y: uɻ=iл*{n[D,ɑ}ʾlV ~kf*؅+1-9B“HR0>b˃xnꋗ*{QZ2,"zpoܯ#{ȅ | :xc#ojջἥ*|; cr9sMѱ˩fr{H<t}zo[LvԦɺR||],ιm;|ɠd=ҾԨNܙ˷7j0Tx"" N Wߌ֐G*#=0Dj6R*mI4HX-FkYɪjJ]"z֤kɲ۹c^U0)q R.| SV]Zp ڐT^NޫCA6lY)9X88\KD+جݬJxޖ!]Z}lM?^}JHMQŷ֙c*.<#J|0:)nɸ\0C_d^D~.Wl?mK!󩷜>D~|yy |*Mn6í ,z˿pѵ{ǚΥLPYjVg|hБO#) #?B~C!%+.02GZ^GPC_]PA0G`N4O&*@/{;X]$mԤɋkY% mP]*Ԧ)l$hw{|Y0?BhutN,%냡 D /p zW pz OO`?\PEpe~EEO?\ >"?.o k|x_kQm)6\]ފ귋q1d <&4B"[xCaC(Í)d&RI Y&4̃ \I2)R\HRbD:o"̝*2(͢B51=F?,*'\r|"(@$l詄0A +dn/' o)*R0B El' i)0j*)c "{a  6 `5.$2L12I%tJ)J,K0Ǥs7!DÓ!Z;5.lB6/h5D2\'+ܲ"LfPBNS:TG :=j *m(u7W)Aft?$HV[gj{mB^>#wDS)85,NZ * &R,yQ>8fC#"& o >8~'83޸c Z !(B.h;b"T".`Va!b1HdžN %QR O^\\_`5\ ֥\BVޜUƹqD@ {, Lps]"x=q\#7"Kn&̻2} FFd(+@s* (6m2bV⥈%«8q8]JYqϹ!!ڛo:)NXRwD]\SU yET\B1O3HW||#!a[8b)@B Pr#FB;FԶ6mo[ϭnv[7h #͌iih'߹ywmwwnph(* P; wc̔2)LVqI2| ie(שyUĭծ?a~^^ǜlk~Nw]^D߭h:%'*7".݂aYGO?a# L_b) :0u[U?>s| z%6_θGe>8(A",щA)X<`>p??@D?Z.) s3FB(,aΠ?ܿ\ hi)U43Zb:MӴ%5 r J1j1CQ0#bA믱#BB181v!Kص_˴ec6?9`h{@x0Ghx}@{(< ;<>C@DB2ebDȊq6+'`&ȃ|p2A0@YL J<~ǀȂm),ҬCJ&}QB?Z9||>c8SgWXSWr5WjȆaՄSMԳ'%!@D7״r=t]WBT#92LdrY]YV!QjRk_;! ќ]CvO0m<(\&n% k ‰ [[;2hh<(WR@'SSSCLXڮ`%۲5 p!XO<=< [8[=ZS|ؔNY48%/#6?l+U-Mq,!s\_\t>e4̅N;^% F>2g:cxz,*V7r&Zꌰg\ Rs$^[FC>=-'mG&0'H|I΋@ہ5"e0b~FX UV`+ǣTm4]-`jQ1R=C]"2 3ŦM]:ii12] YU ܅՗|=҇ep'[bN'.eOtHRegHST_m_XUܢ;&#ta¡Y K ,VXܦM&b>]>cBnmQW=g/3nR`R '=ٴJgZ 8H~FMnX)!hXכQK/=JSƤ|m+-p++ta16FKdh ~W2C VV]cďDXK4k>,ڔX0G~[^輈ꁞj>V vh}N]O, >ec}$`7^I[hB%RXҲҹY)JY¯brdTFlVaC?.s֠ZaK|hW]hljja=%eGtRjR Wե`X+B[]i-͵dwnezZ&j٣c `S) O.f]Q_^T9RMN!$B\:=S 6(TFch,Q4dB-gm o +%}jzdf;v$b&pA~/*Mw6df,^gQ`yA^>1쪝Bo;&hv蓛<Bdr!QeֿΜ-f99spUƕ> 7~0W'aQ!6 q\c%1tR{>k"%V=lQ0Na:Yu$-holnk3ifNv+aёVW^GGQUnNWD^ǚ%'m&ON]Y:vo$Jdފ1Z{q_~/EK{Y*nWr^2n)gxkҡk"w ϸyKa#hZ jF9#Z8|XƚsaCwEN oUEGfG&VWྏk3 ;t'vUj)ei;4N,4lw4I,z'^mR9دFN,6v5`LƟ]c4g =nzxЩ:˵]Or-\fs71ỷ_PͯF zu1s?H:tRF\{yhDi1lg&ޫ+Tls:Nu1kˑ!jnrNiMFWG&NjSܗ;eRF=zOrȘ؅)ǐx,#c.2ȑƎ> I:4ő%=|yN!sܙbN¼ycHMQ{SC'KLj̦.ȑέ= jֳZQ\ΰVɪdTVgzfڠS!c9LiVP0QÌ y3Ξ?YҦOgFzgқIf-{6ڶoέsݧKL%V4Qr0? uJDvA٭`,RuVA^-E3&DɚU|+Z2볥W]XEx%S]4'|D=UO`IRD5q98 eRdf7fhX#l8hkFcj?9oX8J9!=Y[ a]–e7@Md=(a0ID7EX28}5KUZPnM}%.eYxeX}vj`Jm_PWyNHDMjU{qc0]bHZ+&@fbɭPvfih2mr鮸Ie)@!1D^(NòZ{ #L |u*O RZ%jl}Maz"vMP%"Y*STɤJ\3S84ΨdlW9$fٛuMfc˭Avk/a=eot=[ Yx'blѪ|_BqƟZ\j;Gj,:2QъBu/MopS,G!48Ǖ-cL$74OD S8z(iP[Ņ.$ X6u!8R4pYM,U*^\!Ex9in2Y "3MnG'7kMr(mV.6lR1oӥZȬ%f& # 6P8VBB$e)QlG0<*V )qΝP(3LV=]qʓ;(QJUh(L;Ӡ֢ Pm:)IO̒(])7& s)l/#OȡHfIV)fF˙SlRT;-e(ca<9ʋpA i,YjWR׿ꆌe<#љ:u,e;V6e1͂VmhKk~6iIZjMVmmYKE(WV ].sܕNc'Ƭ.c]vwxspwE%/v uy~P3/z;^sWPo}_ⷽz.xKad#识 Loz{&FYQ[Ԇh>721kR'pArfJg"eVfC+Ed%$/r*_yVTr,"'G9H1,Y\l%ZQV7Fɵ1?5fdӲv( YQIPuhY_X9ctIOˎe4#Pq4hyiq;|湈5{ksX8_A 0OޅPTYZ,<5#:'fai,!)G -;Xn9+ wfX%H9ԶJq%{~Lwm)Y+]I=:8?#hm"L7-c<*_9[<29kn<:9qw En:n#8۰d{"RTydu~} ]w9 =aϭ^v˾alՎvnOyٮKw^h;^]k!^\I<;W` aC:!U~J9ƭ>=^Ї#FKƼ_>;W J-El>o}8XAws1\~gV|?H_8CGPP9CBbjr`z `v`n ` ` ` . fXފaLaqĔau_} }GAX*   jN`v~r!z!a*`a`f!!aڡ9`FT a#:-5KrLQT,t@ D@\+ J`b * +~ +" "*"+^a.*","c/"/bc i#Rc5:WB6jauS_@8)X1 #2c11!=b<#.cb<#>b@#<Ң>?d2"f(湟5RdEU ̀F Ϗm'4':(,f6$*$BcB$CBAd*ڤ<N$PPcOd=Ҥ b14ZTRa6fc%EG@@ |@# „ C)d;LM&ePLQP$^_.%R=`ڥ:C_UedJ&t$Gz$u_Xe@@h$@(ZmCfCf]&pgon&&_ޥ@!2b@Tf^4@d4d'q]]6rHz#E\H)@@ {f |"0@ G;f<k&g?&\rgq6_2gaf_sf&rf26ccc6XC0D82q臲Gr@s^JC.1T(hV@.iRC&m2`LN)¤RRiBPavr>(gR,.&2PXuQ5|4|AhAw"6CgB, *))zi)JK`eVIyv#Dpfa4V(G$)&l6i<p |DkiTCvlfAL@D>b>1BzjC>kNk^HhldGv-!A"A @eff**Ųj*jlƶj"lr\,隲MJC" ƱK>xA A|AvA܃l@f@ lfAx@FpF<, --*-v\?vAm).mvLb|D& ž9&#![ڡV:>n^lNnB.vmFN9*~ _9 !nȊ9~vʥnǾ,z6eLgpA)-br./4iA A@A<8,C0<,fA8&vA&mV/ɯjB0O6'CFl[)8J.j"rJłpRn{sL(2Ţv z  Ӱ  k),记ڬSXܞT>A;dv:+ȭo56T,d0f+)82(l<>ZWbhO"/ oqqQ!FHpb|Y%X+.Rp 2,r-l3)d2.+p / r2OӪ g.eJ*`G)K&hmzҶA@=P4@ùh @Dr>Z7{A83Ϣ:B+28+mCCs3h1EH:@h&(.Oh0-+3 tMr,߲Ұ433-6 #p.N73)4'PUcu0ga6Gu A$m1AKkz*p4\1î<ß4gAH4`x5Y/Yur[i\u]cdue+e\c]K5,rmr^(@vm3@6 KRn,77.wO Kr40 *0kuP_jt;NtT(UKUOp]X,M0B/Dd,w:)^=̃gd@m<ăn{{ǷZ-GqF~hK8ZS8}_}~te[%?M=0thǨipq8rr߸x>wVL4.yZw"y,OS2{wj'V5f DK>;p4|AZínAdZ>4C>?=~;0C?P2P1>9򚹳 -99+#/KB9yiIjB`PPUg.wr:Lzs.bV{s4;zSt+C9-:bV5kFesj(A"/Ҏt3glA0﹍(W@`i2CB*508A»Y3y;+<1<7Fij{i H?ݍz_t5P 0.80|:wޤ п z#ST,bkWͦ'o:u9穜QCA@ B!B! @ *29F@6?"/G'7woA Z7gn}{=w㛺%6k{e %~v[V{/|ۼ83<γxþʮ"Br5z6 )D+mS7o9A(4ß@'xB%XB#!=,G",;?K?SX??@)RG!H,Y9e#LӸcGAv$φ2MQ*B3d 1rǐD8CEdclns jmOJ5W*ԭڪn6رe56^׮hɢ=+wYvV7/Tk^;vpഄNXoalj/reɖݛYf} Ys\ gSL0)!qƝ/  "D!-C&n12?ϡGwO!un9I )#AIy$Ǘ?#!NC)Z9,98c9+( +X xaTPp (BlZʧ~)z *jǶ2筿,H:r-< 1.-K̾2L.$1$3:6ߔK#Nsimb3Çl0:M#/ A!&|ZhDRh#Q5(#"M>!*ЃmPQh4GUU>V DV\u’Np%%ZaMtQn'ie ꨣbJ*Gq[r,sGkM# ,( ~|KG{\zL4 L$߁.84K݇?S~rLC Ͷb?҇W[0ՠ,qCKyD,dZI:Ta#""YAQB"XvY7"v0enj,$h%`4sډ(EbE-x+;Gۚ77G%Ú5|G~q#?X-\L7_spjN$Nks2^>n(! \5h 2"_"-`fkix򉧟0q^S(}#pBw>+*{ZWcMJV%fɆ&Rt((sCVc--s 87 IW(/$09͡p;aD&p]3F<m!J|% ` [> L`B4Pd{RLaEĂCP"E3 Q}h76Q߅2)C! tiU )r`M ɢ؄mݾ@mo:`*(MR rt% YBRta m9*N5P5=f4?J2b("<s,V?r &s!1BxGhM  zf&jSWLp *6T%%=xLNtE(-:FRmKZ T%Q) hXIGLeG=دWc.oB4% {ҭ 4Q]1Oˆp;|&+b!胞~"gisn$U6NT-2U j}pd p*UHeD_M@Jp $ JĢdOf6o5Fqݑ^φp/}iMa{S4] !ӳP 5j 9@N2!AYO!8Ts>` #hE Fu崮 DX^VJz!0?A|0!u-ZVAjp<"p phEo4&l.ޒa2JB}#^kIղŶu1-c LjzXnGhY cQø~{|ocpF7\!녕*듧Cd QH.Β}d0CJF{<&;x]@ gDMD H@li%Vx*VWKPqA] O31N 53WiB55hBL $8@ˑ/:pvYCַ5 gcӖnon-x3hL [KDD HERY8pCiM[8E\zz7aDŽlF}pElCL6}Pq^96q 4!#X/YhdṐ+IdȃP 3HrI~!7'f".8?7\]>L;uON&^Xϼ!^!*2!O9r'O{T㑷&5dౝl ^GX0$amCFݤ┬~X{WI߳k})E|/==S cf\0t!yH 7׃V,[Y|?UgnׯNs|t[,Ѣ*lO*p*x솏[l.8p=h&Au,5D̊7@J7/?{n!6`m0oC lJ'L0 K Z2,bO*  co  *pO)0Np/Aar@5oՊ#Q:1QPj+. ),*bB ːpp۰UQ 0f*osKnNZȄj'@R˒->/%L ׭E`dmZM#b3d01ckyQqG͏IՂc 2!R>0FEE"#1$Y1ِ$0+dP%iou0&tu r'y'r$l4ܲ󘐢E.m A ٱ$*2+$o%%mP&aRɲb}--%O!ȡ/򑲥")n6"LGbs+RG+R$ ^21ǒϒ2-2NͷRMd3A34 1 Rmhf(Jt*N) 3*31S+C1-p%R /&q&ɄR] R49dRYĦZbϔNr5f2IL)-])u37q6wS73,,8D 3@t@c$JI('*[beSq1-hCq6S1MC;7_+32%s,SEǂb?9 @iFmX*T$H/L`*T=%]=DuSD7O4,8Y2ERO1vF4LC@G fl2QD B 5BI3I72mCOa>KD{JKPN4Ǥ3sk>nF'*UL˼.B r4A2"ZR)H4H[U.ړO=>,uDQJ ?$-{ KIR1U{-gS 4A)l"'*K<5 <-<w"W7q8{9y}yCԄyS˅e{_ƐFW QƑU!)mQSqLљ JaYgQRTBRYɬ0<:i%[F X!)9'QiR1:o:MӰFE BP9 O5zorez (:I x[aYmަii?uFZW$IY): [TV:٨::7$MXiT(AvBz&Tc z #8zvRnBZMu)Pn%@\ZQz5{:spTM):zQ@fi:a[GUE& 3e1}[7,9ɬ1[mZY"C5[-N3S[ {t vMFZ'{ǷmA;T%NK6>}<t 9bǨ\?"˺K)<:;d=Z l"U6H@WU}C7uQ7[tU܇+}_ƟL盶.Vn #[Y7 L}#y]zZ * 3*`v( YZWݽG"Na-|U]:c~ϋIP{^. @',]:YccXa:"`,4 `Rzp#~A>`/1vߺ;e,*((@E!I?62`2 :@6B`!  R Ҿ1#4=?@_#D'KS[iUEVéE(Q֙!)խ 63 A# <_8"T}0@ ! ~ A! 6̐bۿy2x(P>8ŋ3jȱ|xH!]R$Ȑ#_yIb3)cŊ=zsȎqǒ"c,  TU)դPKٳhӪ]˶۷C9rҬ0a%.{Q!d8O<'ɕeD8a"d)rD.]F,.Mw펆+fdʖ1E.aM9ƛ34Y=;S]*:RBĺ(&W*PЗ>&r᠃~t@d3Fˤl@w(R"u\$әT5&DQ^?va#g(,k3Th8އ;)P<  > SCNTWEAfIJT |'FP f4Dq4PD03 @DMKGĨ\JVzCg1(Rj)h*j8+j+~%QS] 8.@(U}kv^&xO>O4SB6\xXxKA8 Dy!'vDD<tp 7pW|qw\3M!(r˳,3Z%O>)фaG3KUR XQ9pǽ$y Wma? 3|<eD;IDNFpw ^/[yʪq^硏n_]vfxEyOQT)8A  U+w\ڭW*x_>M1O>=ڰ35Ps xx>kT@e&q-d! F>!g?;U$@Hd<FpvzbEkz1" |3&:{]u( 0aaFF0`EmA jCNH)=!d4-P,la A( (:H1ьhT#8αvh8=RnF# IHCfK;NC x㚏 R,ׄ'5B6C(*o`ȡF>6B0BJI2@6"h4zY'>0 4MK=e@|?9j^3&q$MyvCh`xr#)kB+#,]%0WR@ ^ dEY @A9@D%,ш" =|(YPЗ4B;GG16éNB%QT:UPmT9YZj jr6 w~r0`Le 3t5}->Lkf7˧}Y@|5"̇G>!Cp R E t"!̇KPP-ms{EjYZve.o} \ }q[:N+ R ,_qlUNz=~r ~O|KTI *A ZpB"HXAE^" E6 ~Xvp>$La cXٰkbx4$&xO}z.Z`S%W$,DFf.f sPLF":HCy  XЊ̤:$^L3 f8˙veZ6Cِu%X'pM /l"L %Nя0  q/ }unHv 7`4A>lk]nZ r%D'VtԿzѮlwG<+>ցЄ<!h!0ȸtrI1qL|hg p3E>> /9.M(X%V6ly`}]t+&&7E٧0p~A8 1s5Fx1i *x :ֵ"kϗ_Nv+WE-WRN˶&1)E?M1E$ e~w`7Q@_.dCjwb>8όχ'=/ԫvmݽ^ޟT˹{{pvsWzBYRޓL~ݍ<\` #h zШw]׽H~,~{g/GytGzWQK-E&H=7tPYT C#~-t`AZp p v0 H~ B*Ȃ.H 3H|VNp9E8iE5?n<6tՁ}"/0%Sx~ ׂNw { C @zDC ix k C{DvDŽ|xJܒsXR0TQk"Kt\8/`}ujMy Lo8Lp 8rD#vxwX؈|uiFioсRTxR%xL0pL@3OWs+gq"'yLhwY#_JPqS1[5^ =ey*~ff z'n Bci74 ئőmN=^ޒi#..TxR ND`RT(`6'7ܐhHYEyp;-dQX> 6j4難xCŃUoɣLyj/MZ Yn%˷sY8o_a,Kj3ʘcHfhlz>Hs!%th)mQTҖeAfa&9IeᨾkY JNCiшeڧ 8dnZ|6ZJ:D-֏֥R(QjZGv)gzM^ky_'4~/fZ*qz㺬5ʬ*J׭JR%UCii95ħzyt|ڄ{ q8 z؀k6 +K+k h<%P.vey $zڴJL1ˮ" Q˙µ/V Z|eʮ+w{|jxPsz%Cbhyff Q X+m{*aںZ뱈{,+(0+{"{`7;+6K@_?W{ˣ:E)H۲jm˸P{pѱI ˻a{[i1˸fqJ7K`ۜE+'tHۮϛ;ᖸ닼kv׭ھYP;+۬ 7񫬚(zoQ&EjXǙ=KbX œ8QMs9o=xK3JCe"e9q(Bʚ_饏'2,{yRR@zi\j_^KWS̛hz`za|NtH<- !u9^h|B pw܃dyt≘~ܞefrXRӷ ?)l̩Ѡ}t,k:(m0@M,\9eCi Lt)O\D00 3-ίџ5Է&"]Ԧַ2`]H0ӚѮW ya vc2-p6ʛ-Wvzٗf؎}y]=m{͞G}I|Ovx6}Х?yl\ۥ}ک-{,P MN+xX< }hy@*4B#EP R|Ñ@OcNO>1RNVZ.۔-Dڕ[v^"9'1-,*1La aMQ d ]zܲ}p7 }!HqQ!1qa a뽑~Mf0"i؜ȺSZ6Jܾ>^~>^~ -u}$O%.TR%Wr#޳##@b!!! ""$B!?B!?$EbH3-=-gF, .Sw0?// 36w19>=?<_@OGoBHINM?L_POWoRXY/ P`Z{B9+S-=(2)r))Lǒ,3bò2*e>1>hYt'_O/?_/?_ѩ&Q4$4)4/4w4!t3 01c11?0ϯ334?]bb?_b4Hp`AdB!N|XQ"3d2"è#ǍEDFQE)Q\e̙+g^})k`Ϧ][vظs뾍m~>8㯇w(8БI뾃'w}vŇ'޼ns9ӬP){:H"@R rH-!oAiy:zgj<`pD¢(, 5CE$qFkxgD+N#E 2ci"cprJ*D*R gIci,qLְ,L)K&ݜ,R:'? PBǟB u"If<qTRI!ՈI4J7ŴK94OGuRTKO-5RAU5SVQV4G*pO )!¯B0"--8P(|0`,@ cB0F4jG'8kvn T\rEWݸ}7y5qԑGI3MJ! lݎnV3zמ~ 8?X@ 0Z!FFj"@j1@aB )dA@(p/|C;G fz^W=O8N0u5AQ H`?P+@jmzs<Ҷ$y9!asHQ.!k(D#=2zu0RX98#,YGhXp @ :'*aF! $@ 5H1i\cF̱wGHFjjG3|<1UIcWm쓡d(JQcd)Ѳ+GYO9@s4-{9K5z-jE5},E7IRr:|Gb Ԭ!pq z$! =D`uD @H@KpR$࢙h?6яt%=iJWҖT3%$UKhҁ2$H|VK|0[9yi5[ITg-e\_5r+XGVb|m%55CQV65!lYDv-n;{w,e=Bpd#>`_zjY eTTP h\1JЂRFA(PCaK\jesVW5GS0=7EQPGULRDj߸ u_'p`drm0#UZ&~?Â!65{@9VB"FŐ՛bO$7;"k/qc#Wք ^`*@Wa2HC+$ ZPWkaQ\4nZ"<$\&|¤ \%#3C:1B?;۴w:CC;twx??=C@ D>><İE?CTĥ;=(? Ĺc.Jł 6vZ' TU˧YD<"2Ԣ!m`$zɆ 9Aő) Öc'`~aP4 0|FnA.ǔFx&0 9~h&`???J@L??P@X´@d<$,SDSDzx4ȌÐ\ȀȐ |HK2, %(6|4'/%?L;Hã;ȈLHw L̄Ă4I|L=HöcM՜wL@O l6mB[!X!ҼvҶ<S$"aHA&تћxJ-!J,-̤?8S8apnpQ8K)KOOjȆa($С2P,ҹĬG%$&8wz{(z0z0QxmB<=zmlsxݺ5-R{Q;uQw(Q%] ="U-QR.%R(Q<ѹRt> /'8Pw$PR5S@U'`xWXC G~* j$UVeQfeVzhgVih=і%lhuVfWkRpVgpVesmp}Vs W#kV;+Q#1 JTzm@I22'!M Ua)5^ beÉ$QQ_m&vbQ0c@b%_,'^_.^)b+e_2.c(.ņN \!bTy1ʚ@"n\|J#c Y\xryA #n!a8h0dNF Odɇ8Hb*+*m#8x&=ZvZe[e\e]e8SXe^.f_>fce`Xed~dfh@Hkflfmfk ;< E<r @CEXFaXM%k(n&VdR68#r|@]~h4h"!hhhT.i>ix2<^ihȄHDiiiiL8Y<-E6d6}`m;N'dىH#bhHZ~>&*f@~kel4 kk l1.^lq7lĎl֛Gl@llLCNvőΫ ʍ`@kU\z灚% n.n>nNn^nnn~nnnnnnnnnoo.o>on>nրܟe.?o omYN>Nr.alP'Hypgpgguܢ2 F,#2ȭcuXs*y>~Hq&{qq q! '!q#Or$_"g#oWr(r**wr+r,)./s.s/'s07sO (oxs:s;ss?:?O@?tC'D?<_BoAItJtLK_tMtNtDt\x85WTgUwVGYuVWuZu^u_u`uaaub?YO^vd_bwfghuf7vllmvmvnwowrv_5gxuWuZvYGhOvkgvvyb/yW|w]WviwuZBWuZgswxno[wswwSx5v5xu]6iytu'`nyyB廇_zOiO_?~z߁` 7`zyIx bzj!ra~%(" +b$Z W%('v {)!&X$>Id"(d?a*Jhh+pjS03&ey&i&m&q9'uy'y'}' :(z(z*Ah*Pp]vJ$:)Zz)j)z)^:9uB`j'**:+j]j+ ;,{,L(i_J;-Z{-ٲk2.z;t;붻KnZj/˯ <0.ۨحj/u6) ;IZ<2%oʭ^ - K+34 3V|<.1[/7}.'4O3}Da=6x0 Ü1uBc=4CmwI6-ˀv7ۅ׌‷<1{=9}p̲Ƅ'n[8Yu܃:gxH1ȝ,{{n9-* z.[>?v!< >Oǻ>jj7=7/Κf5}0_@10@06a {GݎiC(Wa~Yٝp7CQp.|! AAN! qr{CNF<"߄9pUI|"(LsB"-L\(1XUL[ʨ5J^9ұvS w4ޱ~g( *6</E{0MHL j! CEf+eo}ORN [Ԕ/E)L2a%@inK%=ۢAm:uEY793n)vTa5m6uLѳ&>Mv́1GcݸO鲚}%(5ӧ8ZJ4g/l83&%ȼҁ{(@ JKm4mgGӌz,箟l#Pq-tKN*ՀqsQ)F!6҃ԟ\eKIEGc5l]Z_Pluh TZ,/Ԟ&[jzh_+TF&vlyA Fv}Z2 HvmvucؤfS,[RXK1׊9dm[[-*(I>O=n["}.JhL'BֽPf.x =[#],W51sLX>Xb JWl%3VBn,eX%oC2)Z2 ec'.9i sFlu)a-ZuQm5a+<*^f>n';Fs`;MԦa%- 2]*?UgҢV}}~N}%wN[JbTX=8͙VƊP]/.@m]KCGlʔރ02z8LGn},_wux; jp;H#Moզ߾FsKzp٨ xyipneey0LldYXĢv3Ik撽J|bG{&\,y޿̬,Nk -+bt/:ʸò)Y~w;P&<'a~r//?|csȆopCOXqAշJf=EzǾ!fpm Kx}1ly*fn_.^Ώ7ԥ>ͻs?}\7_?njû+H:t{feK X % 'ߙR A 2 9ZgŚQIR 9Z 2VeQ"ҭUM =],E"uZV!9\ueR9 DY\Y!Xm\ɭ-UT *A59CaR)!mmҿa+MaR-৥"[4Q.ϩ!yU"\8Qb! q iQٍ]!:U[L! a*\,T",!''▍]18Yi_qVR#766jPA6~c4V]":VRu#8c4!hٛ #@ 8c$ `@.X1$DE$E!_Ef$CjG>QG$q$I$H$KC$LD$M2J_M$0$PO%QOvdQ&e R69T.eT^\Nb%W2ZeW崄$FYJIZ&KZe$\e$]%dN%_Qc_樈bŖB &b fb>tF'uNuV'v^vf'wnwv'x~x'yy'zz'{{'||'}Χ}'~>fG@~}((&(.6(>F(N}V R]NA6InjZ a>E&@*`ꥪ(h>(^~2&< zB2C1@!挒>iIRiW @btb%6^ )Jire W2i10N霾q'i:e6˕F栮h%)6Y%J*~F~JP(J****2 NB 99*jj+k k+k"6+>FJR+N+Vk^v+~붊++k+ʫ++kޫ+캖& ,&$2*F,NlRV,^JlrZdž,Ȏlǒǖ,ʞʊlʲʚ,l,ެlڬ-m- m2F-NmƚJAf-vjfljm٪jdm-ۺ-m-ުAڮ-.-m."*nmb..ㆮ.vz.mF.ޢ.~nB.­fjnn.n6no.../.Nm.ڮ.n^/.^-ul o/֯ޯ/ooo00.0 'GK/0o+_pc0pk070 ;0  0 sW Op0 p  0 0 0q0p p Cp /q' ?TLpwq|1qqqq q!rq /r#'2#;rP##r%2$#s$+2"[2(r({r$)2!(k*r'+o2-O%2.s-r.-r-r0'1S@@;knopflerfish-osgi-5.1.0/docs/images/desktop_setbundle_startlevel.gif0000644000175000017500000017275412346515440025041 0ustar felixfelixGIF89a1#!))1 &!)!!))!9 BB99/ 9HB=9^BJFBBVJOLJ1SfX]RJwoR{e_Xgkkk{ZgosCp%Y } sVsZ}RIskcssk{skssphsmZckhss{{IZkn{{{{Ds{6rCee홡ƌ{ƌagvy{{ƌˑΌƌΌƽLjƥΔΔΜ甲˵νɼR]+g1g<ߌ kJ9sJvVJZ{cބcވkޱ-(=:MLPRbk竉soiΈމΔ֜筜絜ޜֽ֥ﵥֽƭνֵޥޭ,1#X -*<0!Ç#6Ċ/j1cǍCH$OL˕/[œ)f̛4qsO@{)(ѣC* :J%k,^va֬^ÂXdϪM۵o+nܻtw߸] LÈ+^̸ǐ#Ko忖3c|fϜ?ە]VgɊU Ke$jԩTS[ͥ[u Nȓ+_μǫꖞU뾧}wx峓_{CϿ(v]GU,"j "kQVG- $=et"QGvT$.2H6:> BIF&J6NF RJIGWZv\edihjk馜pigxb*HavXQF'=F3 tKG OW]HKWw5^sdmhlp-jpi .xP<L1WzxSny_yoy.z褏nz騟zy.n/o'?7οCCqB ,` 4$ރA?~oǯ??_'` :{`gY3 z CH(< S0| cHڰ8?2,a 5i >~ $ )BL$"F2򑎌$$o9az&@Np =HI#܃&IO0GBxKG4‹bAQ[ Lf6|_FU3&6ynjӛ8INps,':שvII4rl'PD@DeMvr5?zEGb.{`B G\@ )M2WҖ*r&eNӦMt:*ԙTF)Rkm&5K*XRV*VծrTXJֲUvX&%(@Z@-A d[׹DF7/~ G'&no-@`(+)S7SIlh;KZЊiSպVm-#AvnmVpם|gr*׹}tδ΁?$\xă?h0J,y=:Fce?*4S0H $.x-(b`Z?F/ Xbl0+"T1Ť(e*a lIE2SS& Ip|Z(# ,sX~e1vg37 E~,:G3<{3?:}>4F3+e@?)ʠkU-(_D+ b3&v%Ab`CQ{`/\3a?S]@'8f;/@]G \I?8A ԡP?jAB4n!jM P&slY 9jV~3(79S;.rz%)GqЍteۼ8oDWJqp)]Jl kGyd|q hܾ>_9! X@԰ͽm /@<| w-~0l ` Dh@ބ@r'\8T, $^$_ԿCGYݐP6qtxL  ̔y Q p^!Pz}p:z5j¢6 hGmʘ\JpAPii~ A!Hlj`wjPp[pZǭ4):*,.02;4[{P+~Qe4<  B).!$ 0κR "XOq8#Q@8pAZT`"H$ xv m"tPU@o`QmuP#v!]&vP$r"um5 /P,h9Mh&B"!/"(d=ag]i-kGH l-nMl h}yqmu_|-x]f ׇֆ؃t׀MҌz و`Mؚ=ٛ؉}"ȋȃ,ŀ,ɣ̼Ȭmڮڲ ۴]{۩ɤۧڹ ȵܽMɿ)& G5@DE .)ts48 ۼ"d4Ff(4G̠τv pk.u}'#bv&b!GM^"fm"`"N.2w]"X2י}"!c=#!,S}+`_ ./1n32N8^<-NA:;4C^D>@F.RNK~UXٕ| -~e^c~]_ain昽k"}3=k|P'r焓ѳ>;["@T7" x2.LRa} .SLnG>cTv?28nP>NN4>쿮ZNڎ>N۽|$@&$- '823"ӞTMSM" n츾~>$"/rǞ+ (/13O7-0_4:?=AOG~>.zN/O_m b?dkdRP8 o( ڮH-s/YnOr'srOp~|_??)ۤ?/}ڨⶈ">A Ã-Q_‡=Ƒps щJb(F2MhF7gLD"ޱO#9q~ h4JGG2yTyHZ"IH=R1K~p%+KBv[D))DqDL#3i\>c|-1et&L'2?|/K5V &-fLxAsm[p&e % q|^ C`]t B"ԃ⚧Bh?x.uB}'0vR a MJAꯣ? WZ>#=3΄6_H%BT!Q7K]3P(plTSƧ:CW>8{WWHR@*(4rUMk OKs?ٖnoJS? gjrԤz/okC;[?W*c;?qr!;9eX<24D4E[3:wQ+{ :zA0X+5׋A!@:;!\Q;B"d%T;&sB)lB**t;$T<9K#;lj9@s9c/)[B%)<3*A*J#:A>-ʧkSs|BғCx+1 /&:*þh*.Q.R?qS-J/7C-dERE\|>| [$Eł$T.6_^ 7olL0K?93>[\dqEb6,Z@b,Lຨ2֬t@$?m۸xDZ!ZjF(¯<®r30">\ L,ˢR }٧r\JC+e1IBTTdO DϱO)D&3L=*4B E2AZ<9Ϥ.|C4Pܮ4"'0+/*".;P"]dL,]lk/#L GD-lM>#O7Ĕ,Kk3S .D%4j8v*c/XdDK/3GTJS_e` \-]`~` `n &aM_ NFE\ B&5".b#>b$Nb%>bsXb'~b(b)b*b+b*nb.%vH/c1c2.c3>c4Nc5^c6nc/bkcc:cmidBcC.dD>dENdF^dGndH~dIdJZibKNdOcqPɻP))H)UnWeWeVeZ[eY^e_]f^_f`Nfd^cnfc~bfbfevfifhffflmfkpfqo.gp6q>grna5&i$y6;'Ľg}Ug{z$Wgb¦d;eTfhN@m胶pchii.6l rOB)ehd釒iv镶閾iQFȭ非i )0iNj^jnjjփ%;jvj\Ӿu|FF!3c*\]dk1Nk!cY ŻFMRvY;%,$RN8hjsB)pjʮl˾llYTll϶4x ܖUmbqmɁ흁i31I3?!Sc Tߎ׃q]:3Z0.\mJnnn,8o.8@іg T !*lSDjf #rgCErJt#\6wI$e}"0B"sFT;?%M~oOq_qo6omqj!}t5BYS鈡vB\u#7U!B2iSMrՖgq+r,3l%X.r/ &yY3Kׇ QF\XPRѤs;CyENּU1@Ӭړ6󑵫}tt:'rOtPu$%sS1'm,gHͻi>O?3 ;' va)Y)%_(-&*6eWv$ܜNm9jQvmRvp/1ז8ǹ[u_vavb!6@U!=_  ؀L tAW,p{=R҉;EWT8𭲡wbJ=dL?*BזNvygjopd q\bh{\_в{=@>vU'TCfUúAYK/|C{58p\ bZ`w>zz×sM5҃ HP=ʥo8b㵚%lWJL_"RsNmI=LH~ȇOPz[6*@ŀN*""fp~,?b2{{wqVmݙgXWZ|||mizğ=|+:y B04Ã#>x ‹2&ԈF?rȔQhٲ5A!bDwޤ8Nl-WTY%)E($jujիY^+WaZ u״jײm-ܸrҭk.޼zڈǿPƿ┅JC e~TG>b>1& :0P917wFL 8|X!D@=13Ƨ[;ݨ…Bk?ɳo})'='O=;qd|oe3}$CDēw EW}Z} F"4UiUU HXX+YZ5x#9#7UyXb15BуoӏL~)8!MJ\52fQ|@BVA-N %NhtFxeiBu( MyUv}E؁!gLq_J,dV3ƈ2=++p0GaAZU? )C'  !DL8xĦpʙFu'my 'ڥPOUַE;䷂n7Nf#jI85ǚ3ͭۼ">n4;n!NUXaP'Xc.$ioeTkFf-ݦr)}7v{pepAccLv}:ǰ{72!l`քs?ާ^3l_"yA XF>9~{$Tyb@5ASJ1  VO+' Y+p<,DU4P]KWs,f3>Ag{Z&HTNz4_`Qj[$ glgpabcN TSR81q#T33Mc83.x{T΂<DDJbIWΑ*q*Ij6Qݩ`~Ao.N+ O?Z@5WGh͙rd1*~?\!).~1 mи7q Y*֛hͫs6_% jĝ#O K[颵$aMMVB@V$)L8^p(#Q* 9ӹμhq#S1r$-"xSPa=Ee*ݔp/_M$19aGo3=8_C.׃]/*ڰu|JCEαXfv5xŮ Eej=~u Ԃi7h=ery2hVax_V񫥻M,[W&an)DBeY7r'xcgIRr|;<b͛nض ȯ kW&7`QI[iD*ZiٳwiQc]K&}*m[ZOZNe&u cJ>6ҵh!Lr~)={7+o<33/G5s/=GzՋOQس^=sx2;PlR?tʡwPy?9bE"yEinr g2]?ٟ__"& B:6 V`R F`NL\Y ` ` ` `IW%Wْћ˭U}Tĉ Ԅ :! `Fa V!Z N n^!Rf>ra!!!¡!a! NFb"&"## #ƙYȋPē'VYJ"5\}JJ B#6+&" .+"-B",".-b"/b00#.b0b,22236#444^c4f#5b6j5z#$Vc8r7v9#:#89C NLL=]###@c>@AA>Nl5!vQDʗp=-S|?@=d=d@J"BdBAd?.IdAdJNOJ%M$L$B$M2O:RSJ L?XEVb%VzV|%YWveYbXCZZr[\n%[e[ZZޥ]e\e]e_ &a\a&__&[b%a&&d%\:W9" N }CRUuYfc%N*"(RI}"ɚHԄ*܃[19Uv!r&'s.s6't>tF'uNuV'v^vf'wnvք9c@ ] p5APb!xdVgF]wfo*?Pq!za.2:(BJh~ab*zr(a~v(艚芪f;<@:*)^iNb=&EMl!gzY (@AOQ}x\'z^i+C|o$QeK,NyĵZbjrz븊빚뺪kfDkkk}3_x"y)hJ(֩NhNmDDdE,1W-&X%i}' +*Ɏ(%+H LAmdXۺYgH w~ZtI,,\,9Iޏ{,%.:iHj2lӖ|D-"m2Đj̨((: (HZFN`Cߘ|t.ӈ5ĀZ)*,.?L$kEmǑɏm9˽nJn.V;ꩂ&.R׭ThiwHDl/bIA쁱Y4EԠ: kLULaLA6 rכ2mԝNudl">Ăb0DczH0K$}/LX~p!Eb= C   E +x#0"2 X %nZğ=/' EWa']3 OH\FAȱD.} 0k0l 7ȱp/=~k1292pߨhJq3pj&g" lkT˵d j憥/rz$-M*XiK@M?(BtlpkD !?a%,  6M@0 /FC=WY>ᾛ Ӟ"4D^W(+* 4DCW׀BW1b1{#ǧH^e2C4@C +Ԙ GTJD,o(RNT7G_(';=KMkhulN5,\}D8/8x~uF1SsN0'lI)y 4HCNO$B/9@P&s__&rIuP0X 0A1t5,vc2?PqqDD(_O~ בTsr"ױ-w Բu7xMJdvGGbEEַXQR7J~hm5|4|Alb{tT:-FВ: tL[j!.L&7CWHۂOCx4thhA uj1'lp}-"Sz~k k07zsAhuyf-7/f W1sQ@̦JlGDJtGQ7K-co vqp(Big >p|4tbrT , S<ļ CjUr{zƷ%VԴhĸU8z;WN> :t0zC:cMo؞ј45UK*.{A课/oxA4 hA>lRĄ1.u+x ƒa3xl  Jpg0R4cŊvTx’n|(ȉ,1erN)M$ʌ*65ʧ)j&ҐGgތSנPbY̅J"C ez@!_^{7> D9rK/Zq˗r6Vyeq;f9͝eWl՚7nz'РuƜwӕ+ʼn{y&)l0@0`H??LX``#Vv~|&bqbƎ@ /؂1#AVß|qP0:-PGXEVTQDCs#"# 28snQS-:@K5HA4MI6ԘtH.>TRuu7E[2& RFj`V L< Y3 }|<0@‹B/@- "6UQÇbval s>#}W_ X=8`޷g|8!ވ_5b c?8+M.W~ dkawJkފsR\[#IQIcҍĩjQY6j-VҺF5H99snn[i"x>>0b#$ B -IZi@@# [p؂j,oP6{=s=wv=}ځ^y'~yܛ[xoy魯z㏧貏VY's|+ta:\BІU>Mgk[ i 6YiB@XJU )ۜn޼V.WډZ}܃G?³m @@ 㡇'hǟg~|,ء2, =@ nPȠqG5UMrBh!Xьb4-5r,@2INt"PsP-9pM^&8f`sA6̘5a۠ɴJn4&VG l) <#=˼$G5hPҘ =I#@@p'E%ENu5ÅoELw)M4Z#m֚L9 fCѹ5'q+%dM*ZrmͬH7HDOG?1m!! .:,l{.6Y iҳb}XjV5`J9&/絜\׽|B47q.z0À4Xn$J,ՍӨf,9IS9X9й$J ~m0GOXSv2P >ZC 'hJ`pbX_>5B9CWWjSKxpVr`hk{^f/p,:/xV^ة8GKYs|<9OF|g7/̈ϙ4a-h`jyKp XQ2(h`R2R5i'/+[vK= MYaMA=B@t( @m٦6 md}O=H eaa@ߒӪݰ%Z3${3|oo3y >ph^(y*£g=| |{;쫦G?drd^8ܤkfeQ}Ti5(x67njQ!B@1~ Or#\U-pcLv` nw%hMi{/|ox^{{-&;s~,>,{W؂6%tz ^Q`=b_PdP'&>qc{lN.o.*e/bcNOO/PB6,OޣO o׌MHOK>nƟӐF /1 Wtnp2fc98BD5 FV:LeX:ХLkD*C-o p^0®E׎iݸ+޼(hYlHoM4= =,C%/OV#o8,01Z|JՇ LΡD8"2o@VZ@n&kN v- İl`e:F$F h1th% m@ˡ/{k36DZG 1< .:O(E -L"7R%:$G K+fΎ?L՞5R~ >k3<+D#)W HL|Pk'mG0 @`vHrfj򏦫+݀=0j˺h5PN71!OQ0M"-pn+21?R#;p2O;R3"$/ Z'iiɀ`ȍz |ϔ\c'~2('_ xU BN74@L.<Ā&/PFt232>R56 馬iX\ u6/%.R$Lլ -90(2"TS3*0,3,(%r˯`` ibԎLDFR`2psf53,G#HW fmP֔HKm H:C- !N`D;S>N5 KEwɰɺ.@3Os4:d M&Wr+r/r3s7Ws;s?sCtGWtKtOtSuWtUuYtDQL@U6OC4eavl6ljkX 9ٶUQm׆c@ eh Ew0;JN//^Y0<5>W>w׮iCa-DfcjN &7p_7 ZSʶ?x'VPsX1!q2vPHhFT-&Q 2t3`XA:4 `;&6a{`0UWIYU_S*VfCW6ALKquv>mּ49:C0Dv];s\7VAxlQf Yxn p n6WLUYʆ-r sB0 $4O!| YUZ>Xɛj]"D]iKԽR91Fq\Vj|mL8xw 8umNN!~Iy>G$1Q0O !\AٞJQ&ntzxu͓q5^7PmKbI/+aݹ#l:#S^.:S5r0;IZKrL=hRI /tWۣ%S37+i;q˧vg^݋z'lRpU$k*7Vlh)8]y] nQ;ommp[7:RCEB?#'O1պC/#)2#p1;F+1P9R*4%kf0'9]V7:{?ZR4:oe-׺"3Am035q3[3\1U6cڮ֕QazT0lb[8unaӎ|ÛxV::[cWjq\mg3ߌ?|73!/䊮W5sLҏ\2ەAY,Xܖz![ͅ9;Iow6{Ћ] z?z%}3$KY! ʟ<;="Wpԯ1}[FIМQ tV +wzO8J8ӻsM{[¶Ƌ }qr 1?K[A!-34#,}G4@/?U>ACa3^®Iikt:жsU! _tR:!mrmVsgg;ľQKT|]ڥYR4͈]xb}Ic4U 2 >]Rc܆e=|O=yǓ=YhIȬ}:5Gb156\ Yߠ{=zTF < !DBŊ3fL.QBf%=zܨsϔ=CO)+3(СB=j4)ҥJ2}4*ԩRRj5+֭Bz*5 gMR3*M %dbgȹt#6 rj36m|pgl.).ņ5~mǒg.g-ش_҇YVԔ5ݹGy{+#ĉ18rɗ[xq#i<5`#d:LGOHW ӯ_O?׫A@S(CN(lA[oy\%k6y8epgvbX`hb¸ڍZi6ltg9rhq99!$ETv]H%J-u bmvSNr7_~E9Q gvGpfYgBnB ?i! aHd>ik^!fxn!ʆimJjEOޥ'}SGWJG!vu&)K.yLd~rY~yl^+P'D k9ךv&:^3 Zl*ca-cdeX3ꎍ٪:n)jF _ \6ۓo[q y9lqxDMe7|'~J",f ? |{^7Lu;`[y.${|d\qyhW |`XQ{T6(_US ٰ0G; wCےǬ/?`RHpَ\%Bu@l2'@ 59E!L1W;ҍlWMjܐ@tsr(@Vh|_U4-=P R<ژl'Z_aLyH_2eCUazb $FQ'\K}81 ~CX8`ȼ*]fjn`66H?Nc[MCrus[g9RM~3j_ _!# @д~RnHQ0Q^U ^\L,eiLɄ&5pH$X MH_{Eʙwc5og =~}+&h¨Btdz@9P^0ۻ:Sa[|4%oCү>ocw/?o2ZbO=r^(Ї&s$EfRw*o(o7DD\6{82,?'5A"S*Sl3%8b*),x*h123h5-/ȃ1O#V.QAVu)"JhdXZv0JunMf{FÅ.Wd6!HQ(a_`tR0C(6qjqQ6AzX;Dчx66h{(de\csHxcqliQhy'6FiBv<vq5X)xjJ6׀NX\Ά*WHTSW&ZdQ=I!bd,ÍH/q/dg)/"Hv"5Ԏֈ㸏ӏChXaw䈍FX!""RPO3B˦hè'vhwAJSChQiËgXv4G5 cȌeX8~g,?ik8؇78rnS*t8C5PTCd9ns7؈dE\2\Phh>E=/g}YIqHjv*%wwiwfdׅy)(je(hd$oKo1L<NJ+&X6g"jFDC[rE21I9IʹC{YP9)Gq.IJ(\!h l'1VGC@Ɗ/.^*PT{B\r:IuM48GQ|m3/:ɉƉve]dNLi*S8i7DeC9Ȣdgd65袲Yx"Fq.q$ )@!*}!$jRVN XK=ҟޓ t^DISbk8L0iI**"/iC"xǨܓ/J> :Qĸ1*!$WAH9t N~P w|9%^ȗ֩My>ZF\` Yp!jEg,2Y?P "HVuniרHDJXЪ2H诱xIRˆ.Ջ?<~ʀt_ P )~(vM6J/6+閏㵘R0酌Edzsa _ _[k@'+{}Cye?g;G"jSX^908IvǚTd5jqQeJ ~;ت)#bCh+IVYK`W'#-~0q70yȐ8<*CiBDUÄX?[(D@]_ IK|<| ceJv OyICrZzK8{8KZMAJxNG[Iz+12#B\V+@ A  +Y؇IrcDå={VˆZKqаZ`E_^`{ ,$l +0૵a2FٙZ)AvꨪQXsk~ڪѓ_z)hٸ͹;Q0X!JsNԚ§"ZiwD|Bp5p A ` |OP d=\Ly{dvwf{XkGZ\`F^G ˲L˶˺˾,~`Cнӵ|/;y"RCV*[WqkKۤ ͖vD0˹R(C[ /8:\e4 pu @  L`vI9iM6i]cݕ=X՘titE6ekGpެE q-\Fz 8Ψ>AQİ `F`gE,S)9D#Úsۚ!bз:v/zRЄf]5d̊;ܥ騳n0xO-~!towV D#& 1Br6ZQ5FQւ /W60L}W"MnFQG@S zM P ح F-L>Ym6ޞWr)i{^i]*w?5Zmn~rc*ro=oJlZ@ G^ڀOzZ "YG^;-k>K*҃:M/n?. g)s`?H/t!ܹZ' . ./D=ciԅ?rorcmEnvnim\ir%ߒCE|_ P{gx} P ĐxR_$~k*g哖Y.LU_>ɓKn/ӏߟd6wDޜ{HFKug5k1]2@B? >Q{B>t aH| 9bDaTeL3l*ɩ2glyfMpԉsg˟s8`g~}r[N;ܿ4~3gkμnoC=CrP=[g2Ph!~(-F0@& |AB$BD7 7$9*IzJK%iҬʱzR;+i̗sɭ2":."( ,ʂ, /Ej0 nG2}R!E8A~FD=-T[fMĕvm V0#ϓиu[#/t f-7 c/嚢On,V>4<svuXq$g]iՕ>k%w-r % 2|1'>XH(L*HI)4r4yrIZy,K5s2d+w뻢Zfh:3C.<:B<> 40°+^ظO>9@b(.&JU5`6p+ޘzM[g]e7? ۅY>V9?r;80A)jzZ_.lNO^cijE rHfN$d>qO`RCM6!|[MkR8V .7AUFaguBϺ89'=˹TO|nrKbf2><+q;ǩΌG(E8kP #މ$%,Q"A̛ 1I|!X4䓛LZ[*VC1?~t,G3$ʑ?[A#uNF],`wR:$3FKjVժuG4jf, D"&a *hi?w\~ri{ݹٙ'yېoZex1}n86B<Lѡf򄌓.*q%| HympAFB!t}%lu?;@2:xx'n_<(v397b,^+,&didcvu^يZ#EdV*~ecIs=}߮A!U=(d:S@w:^kSHUY!"WY5?BNmמWF/Dς&z*&u~O|7vVں^l; Rvxvo؍+|Qs Vw'oم0;Z$)#b{`O @@ A @DTALA lAt < %ĽDk axx#>s[g,f-Zۣq:b$w{x,#09Q:b1Ҷ{=ǒٷۣGwi#eX`hm`9@ l ESR@T@V E|ERLAEP@SY[EUE\Z\E]tYF_`lE]p0S=ףi?قiL" d&I\`DL9SnbB'T2=8飨ɪ154=+C!z>ٚS= ;s,*.~\'3[烥9{?ҫFU!`> L  E ^I Eʟ@ŠL$Js-*b75br@;-6oI":hzj/ED$d'h4!NQśI[ꬁOd4NVJO@,]\ 6FA-ӆOERׯLIlW]TKmSRMނ?Ϛ*T=\͵E } EWI6`md`X`J-J8 \eeFh8]}yfsm?d^~c fP0B ލG7+9u3P:\V*^leR>;c;#/FMЏ݉C#n'UZR%k:~)*i@4N-KklHNFQ\iQϨL|OeQTaTahei  'xVRa6:Y^-#=7'ujݼ$e62ZuQM% ߑΑѴ=c7zC8F£@IF`}u6dP \i NKMXA/8]96 OФ^J͠x#Ł^cb#[|fDF8V߀}X i= SEely΀EXTA=dWv\\i`Y*4nA3 ց i%iؐmsԭa͓#?-fZܒ^()_UOH@Ӭo:)|>ci,J\S$T\@Vʀ%@NFBGpr'pBAʢ-"g9`Mx-t`^uSj{-#v=e?ee3ǻ,(b˾sF2S8T"/Gg%clm}>@N ]uv̎w`XB'pWSЍQElܪP~W\L.&&h1p~~~/oj>tQ)b7ACL"r>XLg |3 :DXBV4(1F/zTĉ8PG$%ʆ+f|1fLe4!N8d˒> \ؐ@ lj!Ir+$9rشPBF)PLv-۶n+WmjpQE޽5^ ^˷aŇ1X_}+\C2Ö1_Lyqbx5j)uش}'/̣S6w8>k8Ο_2J,YGyareh4$Պ?\ЪDYTNDY {/ EGz:XTA IuH*R~xM1 PT'S`6ؑM"USARh9愒 U (H1֒ncj AhSʶeQi}iZffvbv[kZ:֦_fYFedgڦffX8WhG(\$IBve׃< ?dPyh%h7*TRǐK*ӉGMF H"ɸ S I6zj} kAҊW,T٪፥{쬰nDM'-"%3=C xF D )IVw-6a{Nؙm^yNY[:%kjipf0eeWYmeEVeڿ¬1L훳:'uawkԴHL;HSFZ*ӪV8LRqLۆ4T{/ JbR{_IB鸞,] +Df$E9(ciZP9SnOJZ9JK~5:zϮS/. ;뼻.SPۮ.-ݻr86XO/lj9JjNz皋AO2n2{?goݼ H—9ҵM'%)#,:>O@Ps]hB Ѓ:]DPTgѨC9 }tčM&fZAlE|md&GSѡOkq_'74m)HK\ B spiI!M4/B;%/L2Zك幪7'P] c-g)[6CMC hJ0=p&ə^=,g7NM~qxEDNkZZ@FAQ͡UM52f8K.*nM\-lJN!h:z `4}wz-Bxb9 cvIVnjDR p=o SK#ʧ-HJGF[d*_DzQ8K mSs2XeT\#-NUfɑKL-P* ڵ*hukNg,,~&_+L907WJ2:ҠDH{@D $HUlS#|}^4g9 4hrH){\]!O7#/^.Mn#? ))r5JA.cOC?4a~+l]WEܿ]zگ6^w%nti}<%~6N;q16?O#C=su( 7(eԤn33ы@JoZ$.--e]Uh|9, S{'a8X:ѡO .5U[,ҋnjO6J'L! S>'_{}c?{nw]~/]Wwğ}fw<_yO^u!̛~S}xk_۾w*ry&`ei&caW)en&qTjUU[6p'XfπnGWJ/%ub'-f(dgxeB,EqFjr]͙HUB_{g"KTTZpRWDz!8I ZYPW(R舲x&n _V=]ddm$<,5)+\ujC<7C.i*):F)>Z)^ibirnijfiz)陮)零)ii))i*FnNl2,7HfRRf,vkrZƪȒ첲lʞFVǚ,ʮl,ȦUIkfXUq*-K.-$MT,Xm)Xwl(C0@sU>,b:͞,l,ެmέm nm.lnnm.n&GƋmj+z5WU$^ nbMJ`CV 01tHH(,Ħڮm.m.2n6n*o":.>BoB.N*/垨 mLNz`aM+i zĽgZm,`oumpp |@펭9V6lvmFJ/Roά_p0z0o0 ם"k5+}.f*yD8@\@1;$ 肳mNpWpJ- g ;_~o 1-G. @fnE4pv"5A4])D2h|]3X^mj-o*L('@({2 @KZă9>w1g/- q1//s17.r'>a4XC j0X 8A1PnvDk' 4LT3X /" (C>.2Bp@)Y'@+BDZ-01'-qD?421-rF+o2 > S5|4|Al5GÁn=0H@M۴iߣb͔Pz-m3JK %Wr,\roBx0r+tTdqp|(t5[s{hN`ec2[CXR[J3Wv!DNatAb/vc3ҍ. =w(R ,pRW+iDFuȢurD;)rӬX[ru5\uv5vuC2u-37a4lA(kA|{{7dg><`H@hZX7A?E<=OH)rI-Q7G?7{{{÷|ӷ}Йaw@PZ>m @ x{sow[S7YyqS-W9Jܒu]uug,jw+ ^IcAhz/b3DCg&79`Xhh@0T0tCgA@|s*~u[zXPǺۿ۽|3Vud<+CA8@T@ON8C<@ȓb*8E 1fԸcG{gϰDy2I*_$7䳚-mʌY3ʝ.O5$GQTi-^|H#]!b"Վ%K(9G5\sHq()C! 3L09n C-xY9e͐}ytФO:2kЫW 6mȲoGސw͛txg;^3c={G'zo[GHY̅bC ez@1El"*/Z/8nP Ü' &2= YlQ`R)ƟVƞpQn FI\("PJ+0Z,:k ܂K.LK/I^Iq~HH3>lNZ4= Դ?7A5C7EKG+.SJ# o:<2.TMARE)Un@rBI ҨxEr+-X*"",b_u1'GËgmIysßj5 FRi&xu1Fl$pG`I%"0ت*I#UfVڂ9j뭸M1S7GaӮzECYї[.fcsfk n(]gm6C:K}sӧNjTMUꪧƎUkS0GՅ#.a:تg ∈3G:@!j8!B8! U>j &7}u)xw_V'ǀI"][غ;~/8ˌg܋^LKzGjCǹzs6zB^{g͵_O~[c?O>'5`~E:ZN;Zfd)X³@,lYb x?7pa!!p|` X`(^ElO A1b=P@,*xgi?-iKKH&&F 6"c2r38걎|> x!x@"$"T'O~ 3>t/~j׾Pj)J=pu*eӇbaF@Ž9A)`@@OL3D%"1B P ]u/ .uYGi x.#0dLQK\ؗ<,B 7Qp s౎mG7J27 YE,#"9:8ԣ @SfmkkQ nҔK[iGFL^2s e'Cͺ޹vTV-> /-y &v%e`^*Q_Vb8 zpbX164;+Z3]tbu 9cr`BDL)^tciUGy7S&#kb7TG5pdJ6vG]ZX~ P"k+Q%  x# &!^Џ6ss`36*ቂ-O</ͮ!+KJV?۫7qܘ JF%4yJd&|čI)IgAƴjv*yF}|˾P<ǻ ?< +ҰwgYg6<#$1̻9׏W"'Pwdpy=xNtE Ҕou]Ki}zL.\,Jyfs7 ;&=idlۧq*T9yd =@:\3I*+cU6/tdKe*2B0-}0݉ΞxˣJb7? z"=ugV.hQƗ~ TdBFGXtdP1,Uf&Nni499h&njx |-XPp؈nɔ4e\ڞjmsaaȌ À@Z La޾o 7oMhCuF&FpFZ~aYpP H( B+1b*RL$ʄ$N;>9\C|+RLOf2sgznesamON02N^ d xFdn&ۂaZ@ !N`D 6O?,FOo er O.;(9m0y*R@&&d1   !/0l2t%W"clΔNp#>#tWa*/@]`VZa!힑P&Bگ(0OJg1F>%knXZ&Ip0. /!X%R:^!,ƴ2d+0reh| ^1=S0F!R#+r1]Ч4R8:퉦- *mx>v*[P(@`@"5O ܯuK)_ۥ3?vsʉ,1-QDJ8 .0JM%ܳ=rsH1"1E0!Vp"1"@k<h 0L%asPE ZAa'#nS(p y - Ob$tXVꏆ++=k$2@<<FC ;c.JJtJ=[˥RKsL??3@ "UqMskZQArpFJ^!CZ`S 6M#JT&F"Hgz.fbaD@\2ZvhG:B K򳔁T;# d<]LRkO;tJ~WTXXٓ/YUULMu@۴Z"sbl>R53nt@ Z'-]1(o* m (tN(Nx\εx:];T$P@&^`b-vb#@9T6XIcdM6XQVKrKeK4p+?Z@M+2[2+2Tܨͺ!XbT ?bQ17Eа.%haGPQGXVAmvږm!..+CWnA6o#dwuooveW/]ph6gofqZm2[Kff$"oiC!NE[)Kj5FW7SsAܸT Q/Q.dG1n-cxo7ywy?Ve wp߳eK5LKgq7rwT%T$t7BV'|uRש ^%N%`|#D:18UpBVW(<ʔLdK6e}!J(xK-y58z7=8KgZQGxM\=2Aq8'^-~)TtW|Ĵ@N@NxurorIVՁ8xŘ68Y_/SOX؍ۘ_Xa,NV4#6G0χH~_(ETTwS"yRH$bWy'O8WapiˎxY8osٖߘ}9? [ņ˾639OjOnZ&N~Y#g]B&|֊6E9Y9zXo{ykyZ* VBu؇}8:~ˆJ?xb;IK xٞagZ9_YLZ  Zڨ#7O;+~QҰ b(vQwQLw)1SSbx"˦s9:{8zڟ+=µ:D'  +`uZu9L4F--M!3xَܙ:z[:Yz7xZZs;}[NZ[!:`ֹ8.Zl9kEbzBzՑTxg۵c[yڶۯ[y{훍_[\Uw~Y8YW`<#2[R/%wy%x7q__;wc٧{;_gg3w5U^RO;`ƙ}D_O20($#H%[)jW߻heFe;ռY<̝ew׳녽߆\7D^~,-.<Lh$9. 1=ݼK\9X;eηL8#>+>/Gߎu_Mz(3?ZvptmvmVI KU߮)<=u}}+oMٽua4 {ٲgMRǰÇ#2А"/>hq"F Cd%dYDI5j" 9PS2]NJTVT6ait9]j֭\ өQϖٶiᾥ:w\t{/߿kfʕا:XqcT>0Tʗ-;L)ڕYem®A\㌳W}ZqIA]ҁ3|Z;9ܫ:5tw_> Bo s-S:yƥ 2^2X ZUBju+W Ϝ<}Gj}QTD.$zMbu1:)˲H hW0wI"|7%N<- FNbײX2I/eSA\1fmHGO`QW>YT;^r1IDmȣ|IqG~ e5;탠*?QlNX%E-v1 XFKe;\cuR`+C3ķfPojڇOMvbYX_&S:rU %4^e $p~u}v4@:.Ԛj'(n aǣ='?0O !I5͒kLcco FdPԠGFuG+aoBR:@.[D7 +S?yjZn1!0u=;ӟ?1(oʜ?%*_5-a,-K"c'*uHYp4zd{I3zjɚLʵP z$֡}nsPUs*P*Z"-4:תxU6x>bbGHDf@KvkI#*Gݭm:߼zuF І7s5M܀)mj;ƱIV9I xHͭ5SFE⚕ $AܛA a/U0ؚؼU5Ry%lXVd;UƲv)HA h]XG)kC\%h|~o;U&sxh2A#k岂Bv" *pX'Y^PaE \ @2 :FnܢRV<K#|ܮL[Xny0 8SUИ0zz'O 4V0 I;n쪶COh/L ]B!xnℽ*mOr6TåqxSk/<2NU֎7w^7q-47Hҝ}/| XB;븶5Bbk y>.\^:enRRJIb-]p+y.SX},T $m0|`4Pu/hEV#L$ՋɁ{8}iXe=~z'e.9>|\A{P&ToGMCm#@H?0` AL@0>< `,p w[]PzhGw[p^ O?,PCH1v{CKF(Xhz | q($ei5=\ve6PzpdUS:}@Dxt F`L@ +0`Vp@@cHGp]E0uw|oqjh 8؄{vVBuidqWi~dhhlvnuXr*rCE^wwIك)1jv}Љ}E;'UАV@ P L@%O]h\l#cXSLjVzwDz 8^qցVoS" hHxFz odFj}K@Ĕ)  Pf hARi&MMU~@Pp|F@pPN`Z:O&Iuz$[@ v'uW4iۈ,Q'yZؒZ (1F@ld joI*#!Qf+\"x`tڀOOO;`džwiȆF`u@1UÇE&DNH&0S7DiKzn*.UIIۧ ,n/0) @&)>W xN  P Đx#⨀G|$ȀE#y74m>i{cC`Vi9)ΨyДtnVgS yV'؛;TxFC~Y&  CX bp!0!pa wP   :؝IxIY1ICz@0YJi4RըiCK%@)D|剤J*22.W*\s +:p PF`yzdR !Ot0!  Z '` p3 ;ףhYXCD[ q98פQ]m4?Yq&:n:j@*4^t^ITbkx:!My$M*N+p  #cp P p;~pGiP J&yd7(Hz5UjvBR&jگC*[|01 :a3tE2GQ%pxrp!@ p B*I۴H=u7 ȈvzFAON#T8Ū䴓bEW(SIȵ[]`&g90e/'rC'ot/Ct3[yf(0n ! p @! euz;"s ;]]{KeFO?/"+T+1wD}˃LЛhk‰*B p p, +4A`ቒ)h*@x#iki6BdVY*;nˈX۾A'|e"egIK2ԡf N4O`Ǿ3vˤ kKTM?Yaq,\;*-]6-O-.~hTō .=#vd.f/e`Q&7D:=W,hP K-r]M3fԫbenA3U1CӗKVOM|n^urܲ^{Z#>vLñt\{3S)7;:bNMUkӞNό`YCmAQSɣS=7NYh^.޺NaYc{{ڲ$)Rԥ~BXT4J aX]NF0HdEܛ}17Q?YSJU C8ގ}HӵYJi^>${Z钼 sR6\l+NOMv?/RDϙ,meeO=8qV4焊l3Ic1^AF6t@+A%sC80G?|u'v6J\*8N ۳K<~IMR%f|d<~.OA0 Mx/sq5yW"Yɍ F%mSbӯ$ .dС@r)X"El.N$GCdœMrdˎxXf7ud%dYDI5j⇹4xQœ"_>z2 OaŎ%[Yiծ-TLrBi2?P6' ,_"6\xqNCfa#F8sfȒ GFȹ؈,5|YU.SXoĽ{Ck&.y`ъ1?fxxg>]Z7#DqRQ\5HeSNg{9rs]x[G ˸KHcnCAA =[3 LR6xc $lm#^CI`zf&Rxh87 2 '"(bʅ$:ZbmO:/rK.f2'?ëP¯ AMC Ir48(3r ]tJx)7dTOx4v'":λEts [v{ Lu'y!WO:]@SdŽM.Z/E5b<ռu\pF}Uڒ!4:PzH$cgmcküO2CSM68I=Nm۴{h=Vm'*ݬc5IDQպ]FOCf||:UY(Jծ*Ul[w)P~ /aWWkw ўgVM\#5\k$)8%KR&(}~r޸~|Ib1l|~?mwmjprԄ07 IIZ$҉K;E! k_=A^v-8APf{n#yG3iyUVMUeNKdbXE1vyًxկ7Y@EH)(Ff`& Cde+"̎L$4[NJ\nI9 1 ?R\ SrdfS!UEm=+oE5dpIle>UAetV)5qt 3 &t-DTFsk;-K'> <яpb'ǁ*$LbET,KhKt,»D!*bdT<).rLi?UtSIT a\BK܁sc.tf:Ɗ\E7\z XxQJ'9E$kc=ȫ.SB{ق0J4#QaĿ3U Ak-ְY-ϯnbVk5%/ ̉:66xnm!ؘT-ՍX[&W]{" Ja<5?mXFC-qI(zZCم-lg|FaPsYooYR֪f󷿢5Vnt-&3=;[!!~osAתpȪqB CLqiԊ)\1_- vxW3]daE&30 8-Ʋl4}x(x͋fK{*EYpK%Y)e!o&rು{[щ77p*)n~t?萾nhM32C+-FjyKA .[Boz~/Ãn 8@ ?&Ѐ`?'xb?! iR~i8hLLLL,MSH7rH]PmP}PP P P P P4(H Q-Q=QMڰD}vԿ#N@$-,( K~m8dhתb<|U$H'&hKs< >rz"IAcr]8qrրS9S;;:ӎ>}8ue`S7=S>5?ETFS:TB ?UTJTKMK7eJ>OTPUPE&0U]LcB"V}UcUZuZU[U\Y^VVY _U{}QFH|=蔿,i= @O! ?KjUH{jȇ``&,vb+'31ܣDŽ,CV(pgxr؈e؊-،؍X-rX'%@؎XEYX rْ=YYYmٕXsT4UZQU]U&2V]Zݍ ZZWZ$ڦګڬZ&/Kk|",, ,R x1 I(B 8=x!`># &"*]S Œ4Akbs7-w v0r8m׍]ׅ]s]]ڝۭ]v w(%Xe^-]=s ]]-] U^]v^U]N;ZOߡ5ZQ!(9_ _y=%eF%`V`:`fe`ޚ;(u\ǹ@#HĀ"h۷#@>qX^OLLH{ !(X WIq#Y9(;w҆ȇb@pXU]]/206c14spHu.^6.ߜ]]c/Nc]c0.>&}8c4dG>:v#uTTO&Ѻ eO-R֚i:eI=1mWZXRNm9<5"[|3@tuiK,?"x<|8u[BX!f`ogof+WJB̋חX5Z|g}gЃJ5h ]7uuUㆆއ.-ِuނd2h^fhvFދ.cinimO5KdUJZSMܼ[;xVA(e&MYAVi1i 28G=/g5^?ld.x$*d`ZM m-Zs~>SwgKLE@NlFgӕclV2̾lwll&Au.Mll^^bw`Nm^m~Fivm٠M>}ߙTPj==%I, "n0 2POcnaïLJ`@Qy4fFf,GF!dPx8I؄O8v`'-D!prg,Îg|&2p> ˦7^qVoqwfv&(lЮlwm wqw^._q#qrw(rq"W] rWNLvN3i:`V+WO j0)nf5 M~'(2(}a}=# JA9"@'|~CJ Xj Ab>|S|8lSu0 2iXvm)?l?aGvvv`)olPfd7evvm&vcv~c`rAq/uba?^uOwgn_&n<vߠfq˟#:qn` fV faǷ+j۞[D'W&|xI 8O LL͟͡wM̢Ḷwz$S2lT( z_.q8u^u)OXj7v7l{Ov{{{ww-O>{U59}i}2a *4vS7Sx.1^8. ?(|o#NMflEm`{0B`pzq eEH~U~=~ M|W%%^"0qwx'{er'/ tG^{?O{l{tO{Hgܹ` |G`C>QaDL/?:wpdH";72q=3r޼)nY͟d P3%)O7J}T(g; fQ6^5*S,њUihϮ;ə E2@B.l6 D9#D0)%K,DlRâG.mt>N35$I+<-2Ӻw&O5֯cNi;wʗ3o|6󨤇ql\P[!w;d}Ċ۷'D;'̏}zŷ^~ Q;C=a|ﵷJ҆*dPÄR$2(Ey:FF@ʐ*_z| Z+yB^* ճQG"nRiH/%N:3PTU`Rc/hTRk.OX2(FcX>EwIW)0EDQė@eQ|D8!ddTe3+"= J)pC1SʝɈY,. +H\xx",!FT߷ޫDi]r+REH$ӡS{Mi],,vOIc|DŽ08ΧQ0gӬbGKh@sU{j(w@)юΆ#-IS:Ҷr3M7ZY49-J{b85SUzy煯U וKDZquy)D Rz`a|AC爭@fr`m`ۄY2>7 fl#\im"n󾷽y^7-p2( .S|8=ύ 6Mw)e՝YNc*y-|y]f)S9}|DЍH/zӏ/]Nӳ_Vz$$f׺Ŏvl_ڷ=unw]x{.O! By.d /y%<)Vvy3<%\u¹^"ň՗H掄ۋs^mRat9~+|S_֯>s>//?ϯ·/&M?>?=! %b_9 =I9,*_Z _._6j` z  "L J_ `F_90_ 2 :aa Ja6bajZfa6`f`9!!]tΡ aaaa!"~&!e"#"!!V!abj""&b"!""a!." b($$&8[-:".ꢒ.H0"11"21#/& /*3J0Rc.NE3V661r7z#3v6#9Ɠ/j#u#..c#c8 ;^#7#;ǹcx^8#?cB#NO^:%ܐP| \! EfYDEҕH#In=G\IRJz![Hv$IbdM^$GRdJN$NҤIdN %GOj$NJd煞>T"$=.:eU^Un0$R V\F"eVƤIeVF*eQeR%;Q[P֤H-Z։w06WY`^5P@bfRfeV`9EcZfuSg:ffJ{}`VdF=&h&9H9i %ljS5j&\覎q`5}& s6ttifҜh}lw YqnxNfyXt[Цjrz'{V}fcpb'wHf'u'zfx`臙W'rJfqZQ}"M̢=xE(臂(艎舞h(h¨(樇(h ިΨhh&) &6iF)j^rV~閒r"陖)2)h(֩)(Rz **ra!!\]@NY*~*JR*vꪊꪚꤪ**媭jN*+j>:k2kF.+n+j+++f+z6kjJ*Z+ƫjrkr++뵂n*kžBCR_,n,v~,ȆȎ,ɖɞ,ʦʮ,˶˾,Ƭ,֬,,l~_-&.-6>-FN-*->Ln-v~-؆؎-ٖm aa-۶۾-ƭ-֭Ƣ-5L--֢>A,C¬Allj,lJN.Vl.*ml.ꦮ.melnʮBƮb..έ㲮/&/Ժ.֮6.>.nmp^:nnZo:/vfnJ/Zb/nlo*n//,*0pn//Fz,R/OpR0oCpZ0powpo .0 0 -S0 ðm1p 3nnpwo Kz/ _Znwo;p /;12 qW0O1 1cWq7 w0!p?2$G"'ZFoF.'c2/o*̬2 K0_0jq'o2*(2(۲$20~0l*'33733ޮ,)?"5g6o-r8399,7[e9;3< s4m<׳=3>?3@OrTs@4B'B#<_B?4DGD>7D_4FgtDSV206)oIIrH2-SoK0ҴLHϬLkOnCJ0;'5 /"lQ߮Tn#1 tTOuOVWmE#v22pWu1[#rIg/.1p(ɖUsoo, w1bog,\d~:qU2S߯kv_G[/rLQho v"w[;2^k_5{`vhpWOp-1-=Gu[˯U7\35+5o[1/2\m{1f,nug77zv7pw߆o1`qi'S#tK~/ gvKJ'b{#5s#wn0?5|W8ݢ-AswwN75~>SwJoyIS]*/410 x8p4Nf[m:ӢC8O#7S_y<{qy.3W399@cxG9@3=9OmX9繞l4{9rt :{':7;OzS:g/w4:o@/𓗺:@k:?*ǺsϺz9[4:3sq{z#;7>%[O;1Wo*{s;^I;sm;z4;ήux;Ws6L -;-6N{?s7hllSCm;#:5'[Z8]tmkqvr|^ 2ׯ۵7/6,X|wqz=y˴;gw2-wy ;-ycr{|=yS8w +R~}G7xg~_ç>}S>o=w~3+yeoy9 9=dvk0<]Yx+˸X|/z<_uwS?u3qs8tޓ&hPshѣI6}aߜm{DvlٳiGڻy8C: ~yr f 5sөWn׹wឍ7}zY~|gw~~_gZ|ŠM-멼 =؃M<E&L]|F6|+ml/}ȻV/"<1:p$bIhʇJ2Kdh&C0[ ̔lM$t34L.JS!<,Ifnwl{nmZh6%&ZlQ%I^]9\/mvʐauۭ\Ƒ v\?zlmS4C_\tiO/i7vw'Wi)_t쾪c(عj϶8/R5n<_C?!L _X@~)@/zs)"Ñi=OA ) UBp \ iXCEyHAJ'D#q)8\DЉQbK)^"QE/R_RYܢF)Pyn =Qky N*=3Y vONT$ 7E>RD$):rdM~a(hFRTQQJҕ4)r riK\%0)^D&1Yeф4YMe^әl6il~f7)Np 7YNv|:YOzst>xӞ@O%(BЂ ]TB2 eFo9$ ).G˒z)JIR+iKgҚƔ9NqS'*LzӢ?MjPT:PUTTFSjUUz_kXɺTR[M+X:ֶS+EeYW!vb&!AXfvtOa]Я(ɠc)K I2`QY~>3Ah"(c$jse  Z',B Ҷ#p&ņGK\R~} >ܩAьet8eq8d^w7ە,|!$ͭ~MIΗ|+`&,Dц2ء p) a Kΰ9< k=L(>?b8.&(d{br8qycX6rs]AZЉ&4}hG+ё~t!=iIWӔ7miOgӡtA=jQդVWmjWձ~ua=kY״wmk_u=H-i6Сώ6MgWپMmo+oV ts{ΆzN-}{򎷽[ ^mp?۽nso >x)~q~8!k[ ߸>a~7<+y m<8ysǼxu׼W:.r3L'zηnG\x/!Ǻڃsܴp^w=s[pwy7<x?G_yo3ykēAozο|}S_{ʯ~׽?^w{G=|?_O7z/ x?~7ӏ~g~?pۏO pP%5P9P7;0=p;P#0MQpE0O#c7G0I3gPi;knopflerfish-osgi-5.1.0/docs/images/osgi-fish.jpg0000644000175000017500000000551312346515440020745 0ustar felixfelixJFIFHHC  !"$"$CTx" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?͉nd?߈LY  Vh5@p9;ž"aZi2Dz9GqWg%}ƒ(d`Gma%;ҾdKk_3z(u[)5 qq*9tcaAXX6mskagZ޺i2nU m7g 䫖 }=t Gm $PrR:JLYq>7b=u#֣2 5x_M׉4_ ^j3A4vS CL xx Zf˲{Uq_ ԌƒcRr@RPDWoffzр嫜n(Kڝ{X:VIǪ'ʹ$ޡ.bǮKqN*:DH?vr8nHA4ȵKV͂jx-Z1]n4ҪHrߍnIq/Z*F RNH1`NOA_TM+;*֠1_ 쥸D0/F0θ83J_ᔶɅ/7嗯=+}9a].8I]z/CguۡIO!1FmOݤAYTbH+&xcGt;R$ [\6_I]5 unCRS:qWsx3^վ G|$%H5 KFf̬/$U8.:/8 Էz\?uciE,尳oTx>gGښs$+|Vx_\g {iv\?J]{@}ElΈ6ziz.P2jܝ>֝ϙtx/2hW*2C$S'䑈O#5v4f Rpv<:%]"*NJjd^i3 X\5!\I5%6'η'Kk8a'˕dQ(#g*zf#$=OG6)X!ZS7d)SǬ HFcmYd~8ǽt6QEbsXrHRv{c\1#+%WhpyWLcJQ[EӶ*Eϭnj=?*aK\GGsFnP5 u k*垵nu\~S29hy/ %4%qOߑB J˥+14XĚ ׵;E8Q'=_K6/^*v6=9[%qmb:⬬8#>n8S2w(\`犐8#Ƃ RxФO-mض6QZ *֢>aӮ$]mqފ+1 8 PHS%(fi$E5~ٷ9Ҋ*ډ皵 [(Z,G#zqV;*ZcՎt@4QMJ{MW({knopflerfish-osgi-5.1.0/docs/images/desktop1_small.gif0000644000175000017500000005022312346515440021762 0ustar felixfelixGIF89a+" "( (''*277+# )$3)7-33<2))(2.$85(998<6O/OQ3QFFM@WFYY[[FF'DB:YL&QKy+}0xA}B~y}'8-3+2.2736:F\EQEg|dvh}ETIUKZbezcyGVNVW~dylx=ƝEĤJƨQ˳YլIصKָYƭc{εiƴzӹnһuLTMLXZZec|i}NW_NSXhqg|fv_g}jt}Š̩شܯ൵缼ƬͲʹѷֻ̽ƂȎ—ځםèüϡ̿Ԩм͇ʝՆӚ΀هז͠ԥ۹ܪ޴,+-5H*\ȰÇ#JHŋ3jȱbfIɓ(S\ɲ˗0cʜI͛8s9sCE JѢ*]t J jڠׯ^KlhӪE۷prKݹ%N˷/_La+Vܢǐ!'LeK2kysϠCvBi'VR^:,Zb˞M;۸s»߼Nȅ'HСc@Ę@cH^ !A D#D#hzAӪVfXe%(Z ׃m%a]%Th؇E&cYg(f&ڊVŋ0ڌ3f\:o r $wZtJ]Kx1HS zDQ;#B- DP=,? .J ((xW &>8FzᆔvX&",c4zcm<㏬v%%PR !q t ']29DО;9A-[K-‹2DnJCZV(Y6h\N(ǔnh)a鈜)(/J㩴j?k1a L |M6] Hʲ3 O԰2F*p]42?K5CPC蒧4AK-cw@OBKW517p11\K!s82 %x)_rg-22Hl6󈳏&F{,"kk,Fи.! K@L WA>DCakJg+˘/mH4eP49.\Qv@"G+tъZD)3P.7insn]> ft[":ˬ3 F̎v4AXbBq! P"p]jyszĠ ~0Ev`3@ "p\ 1@ ԃ \ A|؃a(?8X? AX@}r` A@D`A`0'At! ITPE)i`&8f A e K\:`C/Հ`)Of( ̠`#9IJV-@&5 uғ %bFIR&ᔚI*Kʘ%-k9.|0P MBYІ:uD'JъZUF7юzԣLHGJR>(MJWzR(0Lg 08ͩNwa@%JԢH=Ԧ:PR@ժZXjU!z` XJְ&mHZֶp\J׺xͫ^׾ `:Mb:MlaZͬf7ζu?,/h^Hq]-hыB4"< w.۪rrЋZЅ. *Ѓ \ y;ݮ;t bWutCHo|} [+tK]1p[ aDVEq@1Bl@x*Њ`X`3 6Ad [X:.yDcFBH p"1@ -¾` \Pi.;P50L )sLJ[:[nejѢ#;!%A8oQ2 Β3[bZ+  : 9x+h( fP@aLӂ*!?;V Wclm@_WTp+xmybP7ݪni۫x4V6ъUԎ'LSٺ7ms + v(OW0gN8Ϲw4YAHOҗ;PԧN[XϺַK}D-=|ˋg-^v};ڗ!`;\]#} (Oo/^'Oioy{;?Zvؖki=W^O=7 Ww˿|Z}Z.vr=>O}n :ߵ'` j'_pfB? >=_G恿vt[Gz66VVl~0!{wW{|Gl6jUq|P6XmFzAm6xp>Fie @VWR8iawm>( v5@.1kT׃7v]mpVHHxyjoPoXrշ'{eWOV{{WNxPx|pUnxw}u舺p/Wvr`Z0 / Xw[ƃVUX{ƘXՌθ8]pؘڸ؍8Xx蘎긎؎h5Xx؏9YR0Hِ)45ّ "9$Y&y(_>Y H]*294Y$,^`>@B9DYFyHJLٔNPGVQQ\ٕ^K,m\;CГ`jlٖn9m VYvyxbnP?qy9ɔp VwP{hؗ<S`ϱmr釭瘛Y b1藋Q)R? `9ZhטZ 9bP F { z ?ٕpV |up5)О[k圗ɕR@gC0C YQ0ofQ[9gzG 5%AҠQIjef[ i( =`rY# 65 Օp PF: Zi0?Y-z sf#A9jP P P*^ bJIA4 Q 5p?Pq D`pi| a@ DСrIKI `, xI Pj?` 1ۡ]F;  \ ɠ؀ G:PV  j Pxi: ph'=8`pk0E`6 o@oP ƠI۔V"کOI  l P] n ]00Q& Dx=cDp i/9'˔Ȋ ۰ɠ3[T{˗ϹIYj அzxYapbKSk6@=p ﰩ@[xq s;^֔ ˰ U۸V{!йz0߰ n0rڰ lp,0 i6={i 1? ڰƐ OkQKByؚ\} @{p@ vk j`1K› VJH)Kɿ> xMIɼ yСk㛗Sy\ 쫔ʰKP+Z05?) gՔ,0Hy?DI*Z  R 볃Y 0d'I!zK=0D@ f <&?c-% SP> 69 tw . R=P D DD@_C P5D0DȫйP5 f Jħ=pu>Yy6 m?iHJӤ ?:5\ 5`=؃X=J̛4:r5õ+l+| P\XfpX+k R]ЊΎ% ǐ m B ˱I{NL7ѰG Ì ,Ǹ<&PlZav"j߃,Ϋ0. YLR`DS yĒ V3@ I3 ԗ,XCR kȀ d]m@.kmGƌiE)OOiFc ʪŀiؚ ʌ؍KY ŐLٜ]v {zJΠIڬv WX ј[0|L v Š ]J: K~쐞5Pݕmz@&phP 9CQ«ݞmݹ4Eo> X#> `-6̕ r9 j7]-? n<zn /F2܆m™\uYx@YݞUK`CY_X#6$. _̟ [ݔ0@^;ޕ,ϡ,-\GP$~i͆>Ւ܈۰X[Z=  fU;f˱Iк D0i.y5*~橝擋/l]cR@,z>Q[=)<,19Nj9@5] G^ZhFm]£N龝ZZ06D`=1pMn=)RÐ&6Jݝ; ߡI\<@Nw_W>Χ`_)bi1?xK|j9BY<`DP ? u§ԋԒ|5~ݴ_0ˠ]}Nf˰ʣ==̩ ¼>tOo'|/]  oo Mojm [ ْu so Dy+}k_ @[ߔa>pByAp=^o oëZh3AizDniB9#<*/~ºO kʫIհ,|D] ~ecª DzCZ?!E$9H-~~ǎȫ~5K?LjߪU@iWQIGC͘3cɐk/цfRWaŎ)?iՆU-*2fG(M`U~VDUvX?w&ՌejZ ߀U 9HxfݏHp+]V&ݛidoQU+ɕ/'+)̥m .2sGMyD,H&ȳADWH~+]5]e=6GQkWEwܑ"Jw9(i„r b #pD(o)*őں. /`Ա$Vv7*#-z|L $φZb`'Ups$tI-:ԎrrL2 ?4Nĵ!utqLrQ$u^D 0,RduQKFhԎvptRJb 92$E@œN<9KT$>SSQXyEФIuR} T`-E 2/ìtYfkXg452,mundkdF釟lM&AWziЈ%)lI]Me HkI/ .L\SH$WB:yDx` eR>decbW@XEz()PM7AyN8$G FJFvvz$~J)iM5$>zGfMguњD~&0 f@w^ħ9n[JTXIc!w!lOP1D%i5I't)J$bEsWɝ(8~|xo@^wq⊋T=䠇.P:ɄNܰ yt9|Gy۟WAB@ z@ => GwPD+7Fq=c@͠T@ 1]/衋|D SUDQFhG;zV/|%!9nn֎UCnXZcaCIk酤\ix~ҨF1}/, I=$aoA0#H! 0AQn#|x $S~ E8 !lwub f 09b&P+@F2+@! *<2 hmRk^!G5i+jD3v q{G;R@&"/ڱ= ccG4AQZ$$A)*iP,:G4JfLdl6aE18-ݨnG!FeIW9Cz&K;!U~%Aq?2ǒ0A-q +S CBPȓѽ3X ,иWV iT*nʒ]Ul$ BXklG=zLʒU~0+)] dN!x6IN3U",AL͋il+XkzHd1K. ϖqd4aKwV.YT7|+4qNO0!{jv>~w5XX:|a6DžehfDʕ& rE`jOք<$Fr1"ř=uPD^]i& =^3 ;+,B 5=u4b01ETmU1J^;^Ԡv'YNSP7j/bs0zkBR I?] =}6yV"V$O^b`{mypf6.R2(uo.c~=bDb УzRDz cxHv xF{lUx?6ЕRRk[[>[e`3;쫁#"ACd;s3i K>'x[1fe  F9G \/ IAٞ  I ԣ <向Xi$ ]$B, e3x7Xj+>; ѻ:C;C;0#ؐpz 1~=p03 ݅|h_=h>5 04`k؄;8B0y8ڮZ]4P!&^E.BAMIգH]"+e->Ŧz؃^2Hߤ`^t0^ 4~_ <>6Z1Z:!\M!H (H&/|2@4b` ,[.- 1B>, E$xch$ ` tb< 4 "vABzvӿ1cz] PL@/ 0 ;:_%M=eBLyU+1e΢e^ N 'LfJ`0.  V8 Q }K"8$^/e/t.nEb0 HhbPAX.0^@F;U@SiXSHH儀L o&=`ՈhX%Z`ԗ a j2)_L& İhetW 2(w &mdg>^[;h ~?@g(#}Q.j^?FUQ4WvP ZYg3U="@izw@ ~އ?ㅳP_yE>kE <~IN38jǟ~Q~ffNNpeiYlK6Q+z iKߒ$~ i~@x_hh`x`%_o.^^Lv玙ΧFa-9VX<R?*D`x 6= s1rFo|#@X("0a(Xq#崄-Gd JvČk>|&

[PDWA8)@e`Dًw= W e ’EE?dvus%yN/%Vv0~˜4&vbWOը Vo |+&{0yfd'K,!~֦ " Tm)FvH&׿lB^^s<^ߖm|W ȧRޏf} /1dhb"W[.I~WA@~v1};N~7| /C4~099'IB`|;~G`?wQ'!Ĉ'G nȏ`Ç),o*{hCECji&Μ:wY+"|T-2dH2^|xŏ_>&5k?~& +%"~`bV@iR]vb5UOk]˗1g*l2yZGwCMXE7W L2!_ϵ=a2/~k.E.^ݝO WDVʺUj- a  ^ ;VL>ᓏZՔN"LNoBBQ1TcL@L QHJ % RKJ"2 * EAv@̓Wd.GO=a(9=cFD !ɠ\xc=QK! jkRCD;HO/DOPEEBDzG* lJCD,; 4]LvdtÖA'RJ8G,AJˊ3&%ʢrPX X TR|"PuY;θ3jč&t9trҬu)aGvF=(h.XQ Vf"L 0Vpm2Hz34U/ GE lG9Wl3T,F8.aDvd`ht g%EZ"Q`7h>&P`EhF¬1G9*=3CrK5e T  S?M(VŠ|F/䁒3!RhGVQ/+ď,L>~)cR7%e z!>=I|*$&|LxG ?R `Q;t^EA~:"DpvXER0'Xy +-QO{A *pC ww_Wy,-,c@^vLIS&F)FI@gM`0OlQw m ډbTd5[g b~Y6;1)/Y ҐG-ER(@-t* )B(5Xc~<:Q$_ԋ^Bx]Ng\0N |,Jـ9mjSZA#0u`8q|q[8'85F2^9ʸ>Y },!GD|BjSHb"3&@n,1.EOY,S2?=1 3e!py1=HD|b˼ba>6H]y{lYOv~Ġ6xHG) X}ȓAC[3uO S [x_)-mXU K[.EyQ~qA`Eْse=d)%i$RHhϥ]aRŇrue^ ?~m.& >c[Z>ɇ;z1iěQA)iA'謎BҫNdj:|בz'IBMzqV_ei ND "C/²ʮYΗO 6`<$;nUٞF$hOH6/|k ]i ňH&%x0\٥czҋ̀ jFCHP)1 붮 &ѭC gZg D @K/e$JQ&BXBDT;0+_-fnP( cZɤ+b :ן _kCJC\>QW?|D$61U fH١b7x61ϱq߱11ϱ2! 2 {1W7#?2$;1r~N D\L#:EH_U|\lTȐp92pSn llr}p0WAQTlgui3fCfs2imvCg2O7w jj+3LC-&D\%)yw/Ђ$5+3xR8'u+87zZ/7\ g1go8w888.LN;`88Ǹ8׸8縎xc_x #Yo ua5?9GO9W_9go9w99=<98',OC94՛y998Yz}9z﹠7ӌWzKz:KS:zz'pO:{::>'/>7?>xaxB8a+dPT+XxdG8Ǿ>׾>>WY"6C-XNy;A&:?BPdb5*t=-T?=P-G8??ǿt] ?= 4xaB 6tB] NL٢!"vdH#I4yeJ#'ғ@5r\ygN;yDi93FK6ujԏ񲺌RʠRɖ5{ٖ^]Lwm .JAFp` 3\KPvQV#C^Z6lǗd̅9w.iHvՖ^6א ^Mk2hݻy;kNڡ뮾7w[tE5W~ytnc<`툧+ }Ҥsߨ yv*XfVb?T.5wxZFf4yyzA vjgZxCz4\N yHqCryCCE] wVEZqjѱ4s,3 uQ#kHwx !H(re@zzeOL e1S l+yMKz,0Z+O䩁( 3DW>̆D *#,y)c "UzxEL' W >TVt\ђ ⫝xo2ʨa( aYWla+vwbx1gzWᅈ!^"te5B]vbpVxb1r]bRT0O[eYZYew pՏa_%!zăvWj1i|e~p(Z"zѲ"b^~eb{yEax^`pkktamP!rYPZvEp+އϋ8$EZڸh.)GÁɜwtl b^ oK_M焘ןi[^siyzzھ!W0(j'7ſc<vwZ);!c|*/W,/  3b\$%*"]@!AA߁FنXyH^K0#WHh1-+M2z"B}A jd1DhG%OE dp;ك?0o 7|'5 <;,n y}QݾbgنϒEYHD$ P )[(+ygyϟ@wF2VWPAJ^ dS)Q_#1^zӢ\$2} ukI ] !*um絽yJmP rELx SPj|ZMz#C8D ]B6hz.U,D & [pl'2lNQ\F'D$9iiDEK`t! /vU OP~Vj`XKE1Zt,+!=\2Cz`KE1u/djm h!h Gj@//;P' 90< wq?oj+@BO!&QE.1AaN{+LF,+ja{E6KĄD4KeJ'A$Nv?hQyá sF*JldrdL hx&Q}geir/<&Dhb,KJD$DShdcd)K^2l HzAoEh2z10RLZŞ/UԦP6i 5]:;TahVSaV OX.0eh8RLeV6%hA~SVi^揺I#S\AXjƒƞƹ]Zjr(H(i$ p;~oQ[LHN\G&=JCG>d2%EBKAr*Dn%HbgCV84d4oMd4#K#I4F&F0s'e#1-ne89,rA;9;b"A<Ǔ:;ϳ'O="$)X =>ya %1fXS@h!6RCAIb-*A'$3B2TC7C;C?DCTDGDKDOESTEWE[E_4DfFYa:rTGu4XGHTHHHITIIIJTJJJa:P!" FKLTLǔLLEt49B04M BKBNBArn!ON$_TOuN +UQ۴P" 5R'PRN R7u@3!jrJTOUSUUWU[U_VcUVgVkVoWsUWwWy8AXXu<YUYYYZUZZZ[U[[[u#ƕ\\]U]ו]]^U^^^_U__uB`V`` `aVaaab#Vb'b+b/c3Vc';knopflerfish-osgi-5.1.0/docs/images/knopflerfish-bottom.jpg0000644000175000017500000000140112346515440023041 0ustar felixfelixJFIFHHC     C  T" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?((()=)($(E`+C~4(yQEңeQ\h(EQ\LQEa"SdE6(yQE_MEQ\+?knopflerfish-osgi-5.1.0/docs/images/desktop1.gif0000644000175000017500000006375712346515440020612 0ustar felixfelixGIF89a:!!!!)!)!1!1)1)9)91B1B9B9J9JBJJJRBRBRRRZBZJZZJcJcRcR)kRkR!kZkZ!sZ!sc!sss{c!{c)k!{k!k)s)k)s){){1{){1))1Z11911191Ɣ9Ɯ9ƜBƥJƭJΜBΥBΥR֥B֭J֭R֭ZֽkֽޭJ޵J֌JRZֵJJRRZk޵JRRZZZޜޥckRRZZcZcckcksks{,:H*\ȰÇ#JHŋ3jȱǏ CIɊ|Yɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧ<{rիXjʵׯ`ÊPJhӪ]˶۷p cx[߿  @a 'Ǐ?zS5^ˎ sN xA g` Kޠ@`!` _ABÇ/!~$߯_T8V`ZP>(Zj`j (hЁ(vb0h#5;##AP@`Ld O`TNiWfy•[viB) cif )i٦ ,)gt ' x,g2C:(2$袉 >j5P6dZ r 9ؠ~j9=뮹pуA&DBlDET[r܆HA[n+@fQuEoKaƘdQfeYgmZiVj!qn$p ̀ (wt0Gte]vWl驧{G}}_~&ȠT/8P`ZXA_[=$hl5? wAx9BH"DI#>eY6_F~䓇Y&hff)ؙgw': {^Vji癩*|j9<;kv+-F{ k"J+DO u9˽/ 8p׿0Xp1l b A%L@,3p#pDb9 8pMlvF8' N8'[NsZƀ:5Îv|ggOw hO{1iS@: D B j$t]k:DH C<ۉEkcF#uG!@&CN n} Ґ4$%%(Ty8'`VR,t)y r^vI&I4bNsJO (jݢ"(I`R.uJB'y-OUzh5٪zz,kX籆ecYB,^|;ž;WF? +Dz4(=0?r|mzЯiP-Hh1 P\OPϠ@U^U5]l Ա:B7Mdl-ɜS0G9M̨)OgdLCcgAnZXABQjGt1t#5%vIn<*)T 5NA+K\UqRRtD[IL5ĦqɬFLԝn{MDQ*%ݝSS UB;mZE/V^aX-:5TYRCnyC¶5bxet~WBrHţ.fHS l`6x)@0_* )HLcZ1& B&Xľ,b+jp7lU+pDel]"zWQkwg^Yb3FBhKSc#^P옵ѳ6H?rC5$P0zhԢLծxJ!=r$U2IRd\޲%v-L4MmrS1&dZNSy'RzNQ/8q'5~C5*zJgykp @X%(>!8KZSh zz[FML.$ *FH]5֯ LP8_S˧C* .樐i#ԧ~3S a K4,fucrֲ 8Ct\fDeL^׿jfWxgA mpz*k"=xM W1}!2ۨ[Z6l[&Kz-p6J הu tJ()q,vt]\&{Kcڴ]iG;M,XCmm7>mq'ʚ]7 _HM*ɓ'o |A#l Kg%k[EbC?Hr+(WrWPCr)q~1Rq@ HS"83cC/AFdsKUAVCT@%tDGTUU$t^&1[QgScFf6xf&dflEvV^2d&3n3TwܑE[3AEBww7|whhkhhs5r YGg 5`CH~Z"ey$[j[z#4zAr7V$J#kzJ8]F]&ו]t&m|W6^Ʒm̈́^ʇMB(֤MU;H};;N2*}OOr*<= `+?O~ , , , P->UbQKr1rрр/*3rS:RCR@&TC9sT)* ɐT6UT]Ղ]U_E\WUd^2iVq%IHblK,ɒj6#EeEځEUw%`DF~44Gk BiG[3!x!r&yEj6&jj2jE9[w3k(z$\u$\z(KDlXRK9x{c9lg2LѦ&^e'd:M|(3DM8N_ڗ)_ēo&`N p+8apr,ǍBq-Bq.Qb(bX G81/4ǏPNP`sDvC%dKs )L&UEUQNe5x1d9@EC^'V@X&UqJHf TaZv̑Uh~WXhXhw^ؓ4iTQYwFI bGYXxKMiF6T!r""啳E[IdI?•kG\k間X8H%6Kx%l#L%|Imז'߶||#}V;F)wN$oN*;P* Pg>"QCQG.%qq#h&w(RH@c RSR0 NЪ`BU*t⩐MeNU%MWUIU0$uR]f feq!YIfJWɄnf*vk1E*}v!@á}Gi hGBxnȆ,i!/*!j|Zrju: 7t[[($B#6\kȵJ\Rl8u%'$[&إ&W (ZzC''|}^f_}_r*_OŨ<<}j~y=8a~&> 5 U-awqS.x?(x:0 8?3uZqa!6/giʀarəriR;*A:BfB繐ʂ۸a7U1DV64f[VC:HxMMWQW%wu^XvlFb xn5E!*5:!BZȅ$T~83jq7I>kjI$EJ[gJL#ˉ˶lKLЖ-K|':mV^Ɗ|6kF̳>k);flDAdtKWg*Xz\4w|F>AJR#i Ri5xG#Ȏҋ#gI;k\VkG*N2q٤Wl&[&kDz[J˅Y|䕘9[hznW_nŋbKbqStS2V;|s4|@=ЈqTdstQBV6B112ݯqC4Tfe$jV&VAD*mvuKĠ13YgtWA|gF6QF ǀ!Lxd*S}Vlk|IxdlTVaGZvec~ GPf9gg޹i.yh3a #)騋jJX6i~zglVa_SCzОH[n^{o /V[o>w _;|}2YWx.od'uod0Eve-^kWva2w9V2ZcT @c0)&nK|<urab̹͊.aA ꕴsg'$BLbLkϝ^s\C ˥aU8iUP3M۹u5/f@fv|ھZլ1_ՔSƱY2H  ~;.y?Z~Fm}y >Cxthsmkg2/go\W[8mivjO.znY\9On:D {mYwp 0kXŭ.=S rn{?;罔prQ|Dw< a l*Y0>S쇖Z;/{'?A'>9q=*[+<92%CP=>#94@%P|гɻ94c!1c5sA";,8A빾+@! ע*E)  ..'8 P%l'(*993KA<Ӵ39C:|R86̲9C.*#D2!\D9@H@+/h@ȣ:p՚JLMO Qt9-[16|zC2`ZE9C,JBF\F*BD#+= hq0H; ?ٚjl8oGq-1DR\lwTG`++D=d8EdF|GT!‹Į' /h; k>-0xbHlȌ-(?E5˙zGDÔt[\IiIAcFdC+HlDg|Dh|+2$>޺\ʦ|,b=%1+zɧ9DD|˵ J|-TƱ:?pFȃKK̮lCĔI\TtbdK+̘9H& 8h HT)SITO]LPD8dְL(fVfD9MǞSU$ZMƟ5t/V>OKdyONmVdWOכ7+~k8$DUm-pmUߚnUCVBb U>bK5]] Wc=;&9V_:VabR.Y/^xc=ؗM.=;/'FY_$Ed-V c>n^&@e9C~eV %8tM .TT6k8QR>eQ=TF+?ezFfRf{-υjVamdj6N&k~X..Vދkbvj뽞`-fd~¶>]&Ŧ~ݝzȎɾ] kvllgv>mej7ՆmmM2N%-++ovvidml]3] _4NO>UW6F`m`f.&V^Ԧn*TVԎܴum[5&i/d'EgMfRD[ؔoomvEoeez ~mcV6nʦe>7Tq6oqDq7fW ,uq+pr/pak&WPVb'coo3iIn8/q~n/q-P琕c}w4 lamef&?:eq9tkKtd_ {cc%k mTW3/fu^srtj5[55g`7v*q}lc-OG*u7r;sC7wv3wwSUa[{vRr?w eYvn&N۸# 9'VvSuZ9W+RmѪ{t,[ƫ˺OC{|k?3y D1OZ-bGvmΪ[{=#=ڼ΃{ <̛ixC=xS=/,ozЃ*Fuopǧ뾖I>>Ӿ;>>O?ZôC|G{s>×>G?UխlaFzSz@@ (4A@\}ŠњAAnAA ]r_5}4'.tB 1B,B.dB'p'0y*|:DKBU:2,Xp G0DaB'Rh5^#Ȑ"G qɒ*)\%L>`93Ц@X":rE+_|(S914ЁFΜsNJB(أI6}*u -òU /8qqj9SRRu뜮_RYs ͜>"ʌ]nl璡tŵUIͮXU^m1AwJ#+EyvIt QC@G^&ų8W̓,y [];wށwp'AUC 2lmhj!m0f!Fq!vh6[(8@<PD OĀE_4atTuZ0c 9dsN2\o^v%A)DBi$I)ɤ0ʨSY !|'-۠h%fZ:(E-Y(#ZJづqc5pqGEx({EΚD~fkxbzK*++h5ٟZhN_n}.xbĥ%r8o2z^)cs4?\ 8H= /W|e|r ֗,Lc1 /, >t콈r4ڌr~! =fN_ R[g>\}A[5ë&#v^hKpjHe" R%dBZxd:ԩa8+(’-n!!#tNN@,. /A^+ֿ"hҡU %NYE"H'tRݍh-ЉX##2rΑxrb^i'v[}TnwT`vc_\YMEoa|dhCu #$GrdX3+)z<%*2E=[U*& qe$Y?A%0=FV ܼ;Q2EJ:Ne4Drk6)N\r5 &ǩN;yӹyscx3oɳ*KUņ}s<(B']AL(DE83(F)#~T294@ͩ?.mO9v1bH3Q׌ N`OY>{ iPSR :ը' Rr YhVDS6K׸jϬӝWo8M|vpuB5h\׉mj8s4XtvqOE)K $e ̲[cbOS;j6JgeawXJ@]?XBm[J鄗L5`ZfJ=[Xe1UK뮽@۴]lU3W^x=~!Jxbe v[ѱzM4cV]l{ݍ<&wU=CnxgƎ80o7w8zMjŨZUGC+=oY Yjt/iݧr'6Cl>9Y4clJ2fΐ!BNRjlIr'vf)Rbrag.vQI:Qc->K㪹 aJ-\3o_s?>Gz2-Ak q%UXsa @ŊMK#ss{NZ$&g|kic:VlC>*Qܾ2+5n{B? [to/9{wN͚v/~o]|!"iW2 e\n5bDžIxqM;Y&Y49'{H(Dq#u_{,q8ӣIR5Rlaa_S4E% =J{=;/2eˮvvb>hǸptKwM ͜2Js݊Jx 9f =cuZ=*0*?9x7sZރٟxwU =/?>oܿ=b'`[?A[ZaB;:E{[U??ӯ~߃ߜrr?.FS؏#Vm/ۤCI!da &QLR1L= TyZI]ݍ_ ߉Rރ Sa^L膡9~a]V% &1 ^`Ѕ]ff߯ 5as]49^7^aKm!a Aamu!!&O=&abD"fWC5"8_E`#a-"'*^_I"J e`]D*D+2'JG, b=Y`b 8O c1I͢\\}/ ?*Us@7QU"f陋\9#4_(FVE.Z:Ma*6nI+n{Ѕ]@F?c,N\$?fb; U#=*VaH]Ģ\$Gz$@2.$$1G$;>d.>$D5!`a^WŞy[JV%OOd%Fcf"KCFBA #AXԁiΛj&Mf߹w=d6XzRdsZskcFnF][dRu vAn!ЁtDT#Hh!Ib'?'vUIdY !" VrR{ퟫ`6(Xq6׀[Fl1grii$&Pflp&AdE0"UDE&A&{犲jUm>iyh}^V FmYyZMYYO6Z xnwxFQ%i-EfHD"`Ld}Ωx֩Ur"ʣBE`MϔX 6itZjƖ~iZj=WPbY!W>j3&Uf'*2zcGp!(`hUhT", Pe䰲9.b(DX֦ _[]ۖ)UOZi+.?zd?&1a ] Nސ"laHtA@pBb509mfc| 0m(/30[#89/ é.[0jy.[Q$b,| 9q ݯp^;[0m0j12`1)Q:611Kp%0;R#יf7oY2l%whzC⸖#7o^" iRo:rj(2bSUqFm#0e4Va*;n3,aJA R-(Ae e]u`/ӎ(3!g-}R^52J.[^IpXV7/3W3 K߇3=7kI@?c3 '/&/)K黠^rQ=܄[QeBs)BYlkcisFΫ ܽ^!mqO404BceV:)L ֓ګ)R81PPs^Q5+XK 5uRotټjmVV7[JKiMж+FwJT#٫Y)OǵI5MgVM2@{fb5cc&E 5N68nE0*svgggjR<6(3kӶ#646(tn[n?Uo4qba. w[K#>#-srsbJOdvSU-2gcysQ-[.7~eЎ~: v"kwt3 )c%q6utf(+P]K:; <]jX`Ϻh;׌<8bG{|"*yfjRVC|Hi2[ {m'fp |x[7+ox5{KQ=Yv D=G qah\o?-s/?\7#<K uC9W;=xWU}3ޢv+Q$78~mDPw~tOz>h~Ov魒 / >Q_zoސ cdY??vGɥ @P82xJW D`D)VxcF9vdH#I4yeʔ>`˘0t'N:mOCU%ziR@r6u 'B ^y3iV[v5)P`3%ژ6ql QXc5ҝ(.ٰ%~k]xEi :krdɓ)W6Ifgv^k0XjibވQW؅c[j'vx*CXw7~yr^8bWjĬmNPI# '>Qˣ+}^r͟vՃuw7B!\A*cO2h% KXMo˿4Sd1F\1 [Ѡ+*<IL.'\(&7 :PDL+D/F1DLG2B=|p1L,5H%?=IAeLJ'P!2 / KNFTSQE.쒵>3N9M5[ $+5 CGҕW_EWasQ'eN̺ *r;>KMֶDeP W OŅ[s[pVłs8h 8_? Y،w~ 66̂RJf!c +iKEYdG^BFc9#;pfit9kyPIؘ Y(΢JJҒ>9h#}*O[D:ܸ( c5b~[<в϶(~;lfmdD#^Q E5NO,*bdA yu#= )B]u[vyp_}_HXydj:6{:k^q*ڳ0#D_C :" * ???}nurg?#O1? 0~!d-OqRj\䤃IyfCZHXBlo@R.,P>֩osh_$2nH́><c8ް9!{h$1 YCs3!u%EjR˴iJ-)3p\G=!f@hG(D"EB8c :=яs%UpIx< T%$?2RCS,iIL(V/4@h  G:@A$ffV&qhLd*st&"2(|51JjMkkTsMn $kITЀ8 ir?̡@ zЄ.9E j*t}FC!*ѤAi]A`(a=ta5=OZ1t>b| vȤԧ j 6pԤf2idZU Ucۜ U@Q'vtI Y2#MUTdܸ'z@8$:ȟ<`F@!aNqAla6Vsx%|ŕ/1GףFn*ش+SiɥKMmO|5.5s@kV1(C@>7hR ]RzxaYSs;ɨY-bi{WRT|RiUi>*9!,KY?T %d`{^jyp+ji^1&A5ɷd{_KMMpK_Kij|(,[Ȩ#Z- q49-ZSJ҉Љ+pٌc8Unњa+8G8ZsW2>d?:e#4N=nvP uƢpBȢ DjH 0j#80 lW o pp0Wǖ cp M0s*/p0 IpQF&MRmh0 ?$ۤ1 s1-Ngذ /s1pR[CkCѾQ#0iAs&/$1 lLcP#+05QQ#{l2 [x Yi> p\KMREgNoq &$Q-N811H(L%g݂.'' 隆!d$A'RrPʈҞ^EQH *0:Z _p0#P,C[^(.!%gQ"S//7rMP°ϸ͟h2BA'2X-s/ƌq|q,(22Ss+Zl))1720 L R5s$R>FMr>^"U3w4-Pn995;}-/1 &q/7S=n(,82 J>'s=S$0S@#s@ ?Aϝ) ATB/4"&*S<1C?p3DMBOTD5UCepM`t@&mTdRGSC=;GqDOB+I3GpoD2HGPJ28<@cIJ=K1Fݯ9LdMKߴMO.%%B sB.nNJB$fPDP>/o'CSPNXmztqfBYSSGS}/5[RN[.rIE--VqQTF@sSeb%TpyuYTqQTjM[3NVop=|Q *KSrIuT5Y"JصiT5YbTAN[ML$\ 6*]DWy_+TbP'q&b-&c5"O[mkrUv?i&$TI=FU<8UdSigUjzaUnni$W)Q9Imզ2q:PBDXX!kb!fZinGW`V#iYoy6o okZTt8Pjk1hqTX@iqq JOʂ q5rKd/ pn]h4Q)Hn9N&ՊV^PoUϯU4tqWHL)NU73WxU y6fׂW{&pYTw{HF$H iYҩ4*y˾7}m}2G7oBWX~צP VUHф:w>|˴L.XWA7wwH'w*#!;’A77bXWgQ#{EUmYX+Tzq=XMxsWf'1"ґ5\C-݈sCmAML}A׏;Wy˜XsrPŴW$ L[8oÆ9 e߸xׇ#_vq RupϒwggxF9Ow_aQҢOR7oDekϓyظy˘XH_-3VSߦx$~NY "yNΓZLz Z&j4 vR եrN` ^ۊӨq9ΊIgOZE][ d9[12Z\Aii-l&iTPZdzo8]De[uV`-EE :ϫ3:EFJaڨZ1@ڶY:-y f>Y/+Npn²/[ 3)Yt(B/]4GA ϊxQ[KOO۵Cy_ٟs8j{Z}a; o[؋׹oy[y[Ǜۼ[כ۽;盾۾1gpA%\#\'+/_7;?==[,ݖӫ=6q9=36$<'r^䛞țCL٘CSyc)f؃~^^]^ۭI곐Vɝn~-/[TM&}婾< ^ko:Y[ݟ'8A^E^{?H^mZ[ku__@]?~0%n2ig `_w\#0 ,B9rE+_ 0ƍ;z2ȑ$K<2ʕ,[| 3f̄kڼp!:؃%СD=4ҥL:} 5ԡ>5֭fM+=&VRs͵lۺ} 7ܹtڽ7޽| 8ޜ /8Ō;~l7#D-&9͜;{ :h:/>:լQB,[ִk۾;nw ˛?>ۻwO<ۿ?`z@]A^q`.H 2 F`^8anhr!a$8b"h-".b48c2h=#>cD9dBhP|g1PUNi%Zf%^^ _fei&j&n ogui'z'~  hj(&( J hANBtFj䒛z駢J*zꨩjꫲJ몶zkW(Ah;l>{BVRmTqiuKn枋nnYAVKoދo;^ pLpp /pÀMOLq_qov(42V%tB%r`2(w3ls> tv49tM4AQ'.S2G\3ZSsbMvf+VA|ag wrMivDԹ]w~ xw7VEqȃ/x?tW[ۊCyoy~CYy馟zIuWcUnN{vʢ}|ޝ{; l/|Λyoc_}E_oe<ڏO~sz+;'nɠg}u gc?TfR[Z7Jp;G)f`s`?Hp\?z Iʐp@ oxC!0+M{~ qD 1K,_v4X疟DeTiKffVZb,|a|cl\s.{j@BxͮojęZ7NlTf:bNi>I_:"1]Pw\ ZJ6;D8sne F5Є:ֹuVKOj ]aB2/-gGOB zO9|tPEp*t' '8˔ӕ7.ԨG*YC&T$mkJٺӁюFj[u*V.S+*kHL6Юp}_Qؐ:V،^Ϩf=,_O!5Mhx^cUIMbM>cTkC ϕ֘,:sE>uqi۳ۭd ZՉ/%{&~6ߍjykoS.֒D/Gv׾KZwX+8r5dK_F~' c? Ux}O||U^xf?>CÍQX##6F})}ro{LwRk-e WwfqZ[D&So|GH\ Gq6[%p (Ņ}xujwEsbgD!x:o^+pwPDo,HISޗs6ȃ=>rAhyGqtyCOEISC]%HYvV^`1aZHÅ:H%0h{eBs"ywO7} exWoфdZ~wNznzh'i^FvGk(1}lg~8UwW6{xȇptp(цĨ%tgvcӈ6HbNHh;Rݸc(h爎TDsȎ{(x؎9?ꈅ菐KQ;8xB )8rb[zLGBAёihWJcXACnCZx5oeVK Xx4)M68xm/enFlyɑ.gG{Ph(SgViηfS$z扩h٥Kْ*ِ]8U؈]ňu9y]GexvYmWR|GGYMɔXm~G%kL`yWI&)}H)K/o(DZq6[u< eG[[ǙXБh97)hF©?3集ɹ/)iYԩ@ٛ );C,YǙ㩞ҜY/y)9.IبiietVc *Ӟi3:CAWfNwZs|{(xtD)vwe=pgßi$>hWz.~fR8(z@@Fzi؊Y9sBay Q|Ȥ\RkgdgtTplH9Z75hhT9m~٨Jz:;YhaBMp6ǁzoU ʅ[xȩ zE衎*IzG'=êƊaJ jۺzʭZH稭⊮14Q@JhA\9 xCH JitkCNլ c[:[\9tKۮ$&˖([`˲ 1+&yó=? A+CK^IK˴MO N/ZUkWY[˵ia+cKekgH;ၰ6_˶.북:`;v{Zq|{~ڷ#rxt56F۸QiD;Y1Y˸+[KѶ; +˻]kNjɫ˼oၶ+Kkh.׫˽"Kk狾髾˾ +Kk˿ ,Ll>  ,LlK=;=;<"%|+L,l- /,)4<.l9;\<|= ?,:D<>lIK\L|M O,JT}}1ߑe9_|AƓPz@CeGi|&Jihlp)tix|矀*蠄jVgœSC )QP5XJC t>P$LƒLꪬ*무j뭸++k&6F+Vk+jJ%5P 4BA.P 3K騮ʭo :/ L?z0 \kp. [13,1W1k1',r<2+pҼ68s@ALF'3K+=E7-SGMVki7C~5 M6؎me}l5mMtj7t߀.x\nO?7-P %¸қjqȢ>yª\:þǭ;[瞶;BG/p_Owoك܋_~}ooGKʿ 0  ؿ.0$3(A jp`@}(fB0\:2!0+ wC(XG8E H "@  RJHU{cՃ@GEʌf$hFo`(F:p#яycy@Gaɑ{$%HZr%+MR(9IJPz2D)GTT,aIPEЀ--K.0y9`r%Gf.S3z؃B3x U k0Et6pp?zE4(.b+P% `AP"ku( EI2}tx'ŨFҒ4,KQJRT2Nkn1 isOPȡHQT6LS թZX]Uէr^ +U:V:Ԡ.AVm[WT&.WP}_aQhi`'84a ~sdP$>T]R2Ե}RD_:[}57u_o\ǵBq66׸e.nR7םu[Tt‹֑wZ:ҫ0񲷢-|+/~^׾^ht0Mw ^ Ox75R09a wT&qCx'ncTA8fg8Ct1NB٬zm`5^\ȀCZarbmG#[po,:mγIyx׬1x64Kh.я^4%BGҸt)}iGoӍf= hsw ź֭f1lvsǘiGhg@lt"`ȸ&"0@D`h  -Q 7>XQ $.4xK!n pTn=&vO{7}f? K:7?ku3XanH h 81%HǀkfvdU3;u$S^"]rGg0g,w-)5\25'0g$N6l-Px/>h}7VCvOwDxNDvZE LpL y@  EOn`{6sW pG;ws|n 2|'o#T׀ ?@!pG]" 7:g~w7u0j6]3h[VƂn&=fWըgҘpXjH.g5u[\(o-%6[aHMU wt'Y҃kUwOQFTDNOZG ʠ L؀]m$x0zu#`7pqq W3d 77@z >f0 ] l+|$ 50*7d<~20Ff` jЊ< Rl=yr:-y٘,W(.wDŽ$FVwwgd EĐ 8UDTV.3V4 C``À' xX) !@y {{qdH=ް' } `P|2`h @5*{ZB~ٓﶝ,)b)lN!iPhhO`|`PKk)٩02:4Z6z44 NXtw.iSPC@ZwADFĐF8MT&%Px^em ^ pHc|xR!z0zM ' x : G  Q!Gv Y~cOI 0{qPʨpʩ: Јy{}ɠ]+:EzEֺڭ z*j늭窮 ʮJ*zʯ{:K ۮ++PNXlDcNX.A$dzD 7l0e L  搛 $!h` ~{h Hhֹ7{@j8{:!|~> zm ܉؈n舮ލ>N^~~雾>^.ꦮW..(9mBuDKM保ĆS0V\P   lk_o~׎ ݞܞ1~! ^^.؞^~N?_ $`r A0 . !}KD"xNn'YW P\p6 47<>@BB !ɳ>GXI@K=T_ OK0-줢$a!MC_c_hjln I?s/t$ N WO ]3%!q.Er!AB$C?"ݕOb/ #_!O~?OƟ_馞ꋮ~n?NN/ŭ>o/_hڠqCP &DxpC #6aE'^4DOIѠiݔ*MׯT2SȴPBᚏkHm:P%ԫjڵS_Z+VhǮk6WbuK6V^ݫ_mаi\@ =,D9LCE |DaFm1g1wpCs"qD%ҿ'{L? TG o(eJrF0HMJ'$s43?:N;sO=O?tPA %PCEt@%P0nRK1J9Bl0TTSUuUV[uUXcuVZkV\suW^{W`vXb5XdUv_o#ck)[lmv\r\mp5vEwxeow|yx` 6`Vxa=a ~8b睸׽oոtc|IkAY9e|_噯5qfefgc6Zsvc8fy\g64B=Ykk;l6lV;mvmߖ;n綻n;o[l|p6i G|q/kg|i<ÖfLҀV(G7m1jSucX:uφU}ve='Wt?}y]gFczqxE_'W׿r~j%eFg#\g fO\ 'BD`wVP`=Xi CP+,! ?h rZ)Q/ h*^QY"E 6P $c83!jZ _ٸEx G" IR, CQ!$I0VRed&I.ѓ_ e#G@4n {BWf{8dՁ/zƐ-g==p3|9GAyTf3Lq3!gCovfV;pRhf6{K!ӜL:N]LgJy{_&@=F/:.r%( ePY2 D+jP%;JAV+%)6)R"4-34_=PKYh֙R;M$O-tSΆK]SqjTB5U¬&U*Eh Ԝ_YÚ /]OBttҩru|V[Ƚ"SӚU+SKQ^K'fcÓ:6qJ:TUMKZQEŬYzÓn5[M]Y&:5)6YYWO+1ԭ%^33>Q+uuvR=-J]J 5Ze获3)~͇_Yw)jgZ%'f| jw{MXRwiNµZi؎X~6ӻ ~Sµ`l뺩//QrW1]{s +`7wAЬ [{D:۪'zV55fI*bԥ"h/*a-eA:϶$QFFϊ^eAsCbIӆ&l}a3hAGQ E\QU#ԭoaXȠ6 MGqpfVUTFZs$)._8X̎+$yu1IxVp4i3N,'SQ+>d01̙v[CBeM~/Ujt,f(D[]iԵlLgJ78Ik,Mte;#7y?>ٳc,exf9UЋN)?7z!w9/=y_:Џt7=Fyuao-}]snNn3:˪qn'0s.D/Iڰ6ot$7yٜP׆Ϡ4A->N[ =Z]QOk Rg6ԁuiLw}OUU(|ɟt,*}K۾UsoUw#g[3Ch  ;$WwX$([7lB%㭻B*$=%Ȓ@;6:?:(öJ꧉[ _s:q/Ӽ-˼A<#s:wji­;[Bu9B$C)c)򬄲y#/[*># Dq>s|+: =hTr4 islji>t=;bFd*q(/3HDAz 4C)8B3=97E?4B3/B+I˙:.DG[aĵ[:0J\B%CҢA+l4; 7d;5ZD;:13+. ;,5dBCC%` D/<E!Ȳ-+$h H~{R>=c\Ɯb@,𳰯#N#S2ܾ|t>oԤo\ĦtcGþ@Ɇ!` FľW+Azle{3Kl2#AM[TEz7ߪ)TIZcOK\}@6V4*-˘,)ŵ ;N\{1@uj>49¾K*Ի%En*F'+%ҫ|&$<4 M;jS7lCLUCy>44>saNPb L@g5 GkHdMJ"$*7W=4**M]mHy=O{͎Ya* mDDTZ"Mmydzt3ٌHuʌkTð4mD)E1+JKG7M6˗?E:Kӻl yKT3X@3@=i\Ʉ4GZU~dPG]CRQܶDRuL\b 6XςYߣ0P3Qhk HD ,r{l\yt$Nt] [6k>;>SVO*^M?։%} U^TUõDH>YMm-eZ[- L5tIo&$YF Zs%\ >9cTJժ1So ;ܚ[}:=F\Tչ%8F'(T8B)# TJS7S٬*LUK9 "2c8:c;c?^c-c@.dEFAN<A>GFcKdGc>dEcAdGFNeL6dQ9>RdPfPn:vL6d?cNdMd[veQ&=NX~e8dJdLV\T6be\df&e9Uvi``emfhDfiNrdm~fpCUfT6Iu,g}gg@& h~hfh~v芞hhVhhn>ii^hhi6hi.阖nivj>jN^hf~inj&,g4ijkk.k>kNk^knk~kiٚbGd3 (KkMVjkll(1c5f 2.lΞ.mі.^m>) fmVm~mmvmFm6mm6n޶m~v&N >mؖ.n.6ooVn.oNm>Fo.ono6VjŻ.Uc"`2X.+$fۭ5R4yQ-5U$"kWk,E  W;ucU>UeW\` jHts?wtOwu_wvrxwyw(j!.0QeFzMCJıg?I}T=םled v3m:x1`±}#F/ \:BmXrowyy(34zOU.`sS(mݿ[$0fMyF[+^aY%'7?Ixom^!Vișf|q22q4%}ț*-dc|ȏ|ɟLw<||<@z{//o%1j j xo*}gDϏM2}QP̉O(t T5}[8-ly{a=bycڧq||~~w)zM\n׷OXcy_@a=( xN{zcƘ dfL2 (a!'RGA5{q2TX*yLȱC5ٱ$Λ1\xXN6Q50cƆ,I4%HE=u2cB*)Pf3QXֲm-ܸrҭk.޼z/B*S3^ E? bJӂCd$SO" %iD5zd}tS XPScxX>Ԡ_[tGwZƦۉ͎fӪJI~8H CMyݟ8x>&x * : k0JbfQbCC%@u?͵A*8 %ymˈBx/x1^qseъ{#f(cv#3˄hD%2ƉRb,:EVFD'xBc  ")L)lA~x  1I:kczW EF>Qe*dĆbBN4(QiSh ̨{bFa^lX=Ӟ'>OTd<B=~NDЁQphf6D Q`KwFVfɕ FOX`@rEͪ$PQ1.53Tj|*,#B!ts ?jH86,M\~f&+saCQLe4lP=|s2){DnԌ}lPfht(EZӞeY5ԍ\DC;ōV(Hc *9q-GIء̏ LbH&0!@#bHj Z!nRFRA0+(1^ab"ooհ4!?"C'8LhJ_ .^4-7ԁi1P>T03)Ă 1+s R)dI:YV& JҌ`Jxhc|Y:5gWϸ\f(Ӷ8z*% &mMjQ2-]17D~8B1D|D9Z " pcJ2r4 zpaRLYpYX WMD" #  C !&vUC1D_m+%`Ӛzz MX~fL`NO.,IڬPSDȌݵȣ56ZŤ5-:cSe6 da%EiI`XIŐqXTCmR)q.0Rr97vY-G7hHeڤGm:rK<`CXqE'V =>n(ئ$,ð1R\lh_qu?+6U\doc7ζiiug'987'O.7t> 0+Ɏ":,),fq@ϔ@"2J0,tH/t^.Dz^qb?EQS,)הV꜅ӊWnkԁNl^c'D}s+:10!յxm!'[;%u2EMZ߱/Nhg~1';2ƽo!M dtM $41X`~Ix0TT^5* HOЍ?C7tCWu֗ HxQX: K ,a`vEd $aa>Y@BLOg|Y.AEōBR1(U}U^B,Sܞr|o<=|ИG̮4L[;9bZVb[LZuBaa!33Dc^c[ `Iu@Tƻ@[mG\qK[x!9u҅o2#??͔UwDJ5]uRv #A2!SB\Y"؉j =6T RH6$KK@ @L$M!KKB ө!pȐCd=^!NU:I=w mb>H`Z*D$5$LRE$__2@ &aLaPuaMAB'v. DuuVuj$9ƒOFZQS<R`f %VРţ4Pff%fLmJx)# ]Ql臶^րJq'od~kvK'"M;B%ߎơjX*|nڗ^Qţ hu]Tn̕) $-Q%檮Z *A8*&92lUhDY=F|0қrfpZ5*G肢;аe%aEJ#faba # &%2)&.ݕE`Erg L] Q(pQՄ^(&&+-.eV_&)ī\%[wZAh:m>F-BNV-nvm~-ׂ׆-َي-ږmڞڶ-۾ƭ--m6mՂ -~& Iz#D륬ܞ|HjQƊfJ)"BƪDހ)%nBupR˻tcYQ//&/.6/>F/NV/^f/nv/~jK]n//Ư/֯///00'/07*O0W_0gop09f@An 0 p 0 0ϰ0 1p' 10 ?'qOg#q[c_111qqCݬq{11 1!q!!!/2"3"72$?$'2%;r%G%O%o2&s&w2((2 ®2[<+2,Dz,2-ײ-2..rހT/E00)0E?(FC?LL4W35_5g36o6w37738839G '2+2,+˳+3س='4/3)+DA>B34:FktFw4HHsH{4IItHJtI4LLL4MߴMtLNtM4PPP4Qti ;/AA߲Br>rV_@#4,*?(Y 2%4CcE\52E>(C:2 ε2>tVvWraO5ba.6X6f(@?AE[`6CCt>PtR:.i)UbrnW5a'vcCa6=K’B?,$d156usXYgwZ^)J;vu?4=co7przV+wR6(FHAgH2=E6CS3};C_~g7KQ\V ;p^yS?5< x)4C>|ƿ}@At4ݤ={vC>ѓ=}?s4 ~T>Yg2};fLƈ$mlb]#C?x?(Rq=2M4̮u,Hl'1\|I(bc9F5c|X۾282 2[S{:ŻS:ݴ3O<5ЅsB=VR2">G v(D~A;H"885$8 ?"#2x mH]d.W`"֫vGdj1";ֶ#tKnbTG-T?R]W*3jzAJ~0 , | xĴ !nυa Sa!LSLsOM64D]eAKsQ>^ҾJujaJ }%$J*PHTU0Վ8pm0l#08=aBd#/fױ`"-IvV{k["h Ym&z/vmܻ-Mz'C]RםڏLÅU_<Ӱ\mK-c4}77BNK44,xrXB|zG׌8<N E}fhѓt'󭯦S6=D49 R;uPM% MU $\ M ` >SpA+`$p A`@ },P\P |&DY.V$A l`@ zG?XF3#ihF٦6kVlN`MĐiC9yH=h#%=D2c_dV6q;k(7L^R5#AD8BP$8svh:8M((X,h4 p<0?!"N@4`4kG(:8 6 dB NCh"AV.{K3]B2ɵR, 7A `Q 72b'cltKRa 0,*a GxŚ<"ch1I RC΃|['[YLBlo[f1 %vk1Ջ>°M# [v6Ax`.n/f@vt4&&@'ӍSޥ)z^?;M*MoWӝnHP0T$1᳝ۚW_ۮ^V]eAK0B]!|0JHf\!#{ S`sʈWb^: h$ 5w,)ʹ2I@B 8=kW )^ YӤv|VyTs>`ޮJw?w#iP'$Cmjҥ5qsV\ o%лž"؄`N̩,. A @`aNzI.@0)&/07?0Bp"ppp Pf` @ R%Lv@B6Nn`˽R4ϽG$k܋ QNӨj@MM}H-./;$,2nfv$lkLa0 ْ ٔ GV  b @@ aV 4@ i. Sdq,`qFj0HG0P9EqHp @ RD㲐_ol'ʺwXn谩O嚯x$r 竦dP:r 0 IxR`p-(thaU2  pXE-DLDƍLBAtaX*Y**W*`klki ֭L BR*2+r+ߒ+߂Lة-$vҗz ~2(Ɏ(EVR[ E&= #7`C6„222 27R 404/:3ӂ.0bƯ*b0010 o?d)ph hTpU < D -*t+.Lo .3!;;C`<),n̎9*:g% r PTaS#SK$(B˰ iTS54' cPSLTV$]s$ORd$C%qp jA{&j&3E.G 1z)AA:I 3L,!>"<ߥ>ͭtKS +@Ɣ>.-6I2V9q% p7f5P/EA4R93Ȏ0B%4B9*4T'TTiSS-5`37E%UED dd !T2 % {hfhhإM 誗+*J "aG;w"LCS [U5KU)4 GN+DYYYY ZZusGeuAٯA)uRT$s a6NT#sU;R/4S-TTAcKcQu 5U5V5EEgisFQgO-9j:#&lnr&YŽ* N#[)  mFAFz"]NA+Ș@n-ƶl=wv.2BvYjuij}jٶaiF&J3e efc?T$8`,vPCCsGtWe-dQu]s'SfcWccoV]R,W?Fu3rub (qiߥH%ut Ebk)!a FVԖmcrp W y{WzzF@CGybo50BsgWR=R &t/5eIv;6uG;u7e5#e7Dïvgb8WKzv#x57h#6AG@JG( /@2 @aAow%Vo FT 8w]/cyx߅PQh!X%v Q1W1xs/837uAvt5VYeWSQׄdUK!#e^Vcb4nS ?XfuO HщI$!!HF@ȗC9m1q >׋nbymYImrXa0$xYaP{U nρwc)in 2Hx ڮ6dcLNAYI@oA)ڢ1u>qࢍ): 9`}uh8}>Zw9x{Xn"( d+ `$ xm+'9}%]ZWzoxeAa&4-HhA RA} 7ܹKJXݻR/Ć])RX  6$ӘĜ;{ :h(4Y2,~0JJ eOC7;83€ 9Aen]y2=t1K3-άڲ̻?WJ \FYgb7Zq-u TrQWD_i`| VUMꉓfc2WUj)Blv[6PyP ψ3j4J"EdN2eDz9s)Α bRu_&qLj9\GΙeW~g :UwSN;ޓ.h$RUQlj\Qa)꧎vĤ-n%&Dc9]k ui@q*ꪲ̂4EH9ؓ~ n/J,{n &ې>K/Y&+nu/m{KꋧS&yM-cz̰'B k*r}UB 0n`Xd֦ej'Cqj-楐lk»R^n1P j:KgcyhNpYX94vͲxr.Pk>( ҡ-`t1:C.,uf^p65A]Tv흝˦(IyJy ;޾>. s̶Z ZmI7,:ɻQᙞ#fj&7a Y8ԷTjK-z4x,`fP-to4hw)&^s2 ~i ;@%jZe'cpHe;{`J(j^C3+ n;Lag9 9L45+rHC|.v'clcGY,v8PX^@"BS,] ABʊ $Q&J=3D4?GjreR8T&iS$ˬup; IX#qmpV- iѱ%ɥV+7G 3?&-VBQ&XyEҁ鄵$ 2,egd”ig{'C֊\!"u+-(iR13&7&h8KT\iOY"%6!j$%'$B%b)W_ΚѼNFfӢ'Ƴ?]jmjQSy  3%z@ҳZCIBϧ)] lQ- 4"Tͺ~ut]׼u|_ZP1E,jpBԏh/?<(< 8?BpgUYur)vl*"0.MCV똍}57Z0 Љ.ٜhRNw1g+FOM(yU2 R+ՙL+{IK@—s-zV &|h#*v7mWhpk ߗ=sNEi%[G\3{BGPWnvc=odkLU8e7 iR4D^\#Kڮҝ0..x/oq`]<| uR raV*QJ/^de؈)0D`{ !kWTna~Rqv哔vy@v3cW&Mbyf3 ~\H yk$}5rG8Bp;spwc}Fbzze9$-Kߵٌ%\Ȁ2&hcπ3~d$+`Bo~!ѯ~9{vIqIPG~Pv~~~4"7e"Mv\};) I iIЙ/ht𓛙wpsDx 9P @ if84Z9* qI7ʕAXyةbHL0@֧La}t}^wpt @ ʐ^ ç6{**]+*Gg).By0+4k8<+SR`V)TnsFjͩɩЙ룅{۱Xku 戃Ci\+[ `  + xs+k˺ ;pX+YN[^[NPJ۹ {;@M.8A|Q;'ÿ1-I^VqyP\z!` ,P,`\+P* L;kYD]; 8j|v!$)b]V̩O Q,SLUlWŚ[ .p yP`l LԠlp,Tk YupvD t m!ǹWLGuHJ 3g!-0.p0R'L{ i'` pȰ{l7v<&P˷˻LxcX;M[] X? ˲,̶˺ˉaw;l.̷0eZ>'@ ?osQ\P#0'ZW Ѝ@-97 NЙ ȼЬIOPuCy7 =0]="l+*(-ɗ茝|P<ϡDh^ʊT #p #p._0KMOS]&[wʌYˠGrP:O@͟@ݍ햑{` p ;`.dN 0 0,LF`KP3)|c^gr~uMڈL Aqo Fe-PCʘp X{0[0< n , NCӘ|ѼE`y9^걞mVQg 啣Z*^tmsf L=|;^^^@`ƈGw{;^{pcma-54eUuXn\3-d:S~L \b]n~H7&+DŽp S^e鏸Lp  Q N\ CȠJpL;D O_X? V.QEmT?g5XԛNwepp~\F0FplpWY֝}}p$S/HZoli6?FC]"F+@tG,GnշUӘoՏ hKֿl/ϣ(ϟ(珅|Op"Ld1BO@ DPB >QD-^ĘQ xͣ/|cYP# M %Z}TPEE!.Tb)4h⇹cġgP?-´Je׭۴rcȐ%KG2l 2PtYdʕ-_ )YVBX]jXcjlk`la[=`nkbg'\(G EW唖(LC&Ǚ^xH2E=U(VM5i^@uv<02z$RG CL1Ƣ< 7C?ܨ΢ JkrYf\ #Pi16C+y?xM8m 8!g%@'tQ#2K/+52MH/RJ%R2g,sSJ UI?T1LLUS%] U.Z1Uȉ/8k,CU Al4Pʔu6?% H{/5[<.VT\2oamVrsm\F]U-7Vv}5RoTJ%}L:<]֧뻌c8Ћ/23Cs/j[vezomYcMp9}z9]YkW\4] ~SYzx& hL2JYͅTVzӭqCʰs?Z'V<;lb5˕/~Y!7_;iBDJM>pmwt D&sXʇR'#y5bֲgMje3 w@@i{ $`2BZ(:ɶ5" eEq]IN9Y'N>׮+uxT bR(3Qz~ni*RЋ_cAQ0šZ(/|]gDlc@] Q "6ֱ$n TaH%dR(dhՐB3at) Ms6qx#=0 Pbܠ86rI[z֣EE|d0:(%8lX!b4+rDi|XGXMnv2cLX|@!N37AD͹i09GӔ/e Cy}$J'@PbZ4"CȢmSObA@BPsr221;=ԥ/A9oQ\ 9H YUf kؤW 9/?Au-r)]1F#Ϯvc#+\,ryJV6Έd2w{rnvkr46gcrYf}+Q-{^rnoɻ]I`p"AT׿Ō<=HGZV V[W ;xy+ @sѱdΙCr'^Scn߉+Q>DN];c"Vr[F"xhErd&7OrY cVkݖV_^^26`FdL闵Ls!+^5P("j9ِ :sQ\իf.%O1'i 5lϜFuDL !94j9R=Rn ZP6B*^oqPF:6O( nUk%]RXvq}k.:h@$I3]bH뮌]o+c UQ<pӶꊆ_Y] FIJxPa\`\)0^<W5\z6A |nݐj^ 7C|biz.: O@0Ax@B'ёϫGOe,Zώ̿j>hXV2;G!A7 az$w'|0'|fVq*2( dzyϥ睐$Cp'2` < ?g H}Ǐu{_77="ʶX1jNDåv8PZX8$X+ܻ=C߳808~Hmh#@#=&Ѐd>ȃ/`h4&:/J|;, dc? @ | @#H?N[3W8C  ! $P'#=3$hh@:D&  geX0Ȁ$|H!0C2\C"@5d<4Cq1,܋I5dC7D9̛#5Z+lb.0"C]<$8"H'(B;D:p#h"p&h8y&h 80A#h\E"_ a,d\fltCuE`,|6H`P:dKH3GEK ɤDl˄8Hƹ˻TUB:3TJ1c1EuE#%Ŋt'ؽJT%8'98"J>/ ylxjP/N=N,<#HlNM;4NsOdNLsM!??ڔ3Y\y5[t #Hʏ$@L%,%0s|`Ѐ p>f +j|,`Rh¶ %` C2PQ%QR F P$9 JX1Blчcc5@! {`#v{6H9Jd F'8N!P9 T9R5sj-A8C@QQxk /?E@ A-C͸DMSTT B%TWQEM1 8ȦѭDiwb77%ؒg]fm*Siť!r250D?m'@AMVu:hN%`.-C~uFXBЂ{X@H PW}S@=tUuv}xuXrUsEWu]vu9Wyݠ'GST$ PsW|<Ow'`t]pAXZ۱7|0Z`DZt]ڐ%9pZ< UTUeZX"3`^0A0YQVpYzOsMQ ͭ%ƽ\I39t3 u 2=^&PB#N$/ g`aQ句VNQhXRUUۭX]H5Uڽ]Bݽ*j1H==r |I_iMRqwR!5$TieZa]VEڋȡ #ݣ&HA[>M`H!&gx0CN@h^`UEs``[  EaUl)=s$9!}`)Ǚebq'q'Zœ˅ߝ.֠)* 0.m+@pUH%P:CǶ1.~Ax~`1zcUc:'c=FG_<-״?Eʿ*%~#bAie[,']VsY3n2&xZBȃv"UuTL9;vN"//ȇUC8AHdϽY?if8#f`fl~mvvwjfJmQ\T'N\>!Y3)pa勎h&"NFqЕ8s;;g^uHҿ5FL~Ȇl0&|؂0rtu`L_,^ϧ/zi8tj騎۩˪.-e"3} d/5kJ`#ˠm<- mĬv&@ `'XNnҶjPTLU3kٕily?fkg&(ͿÝV.Vv!.pHz] פ.g6ɖa|x}hDdx @j%HήXf>0n$mnEDb<;_+d>9tq`&p˼v#l%XL0ڃ?0S0὇Svnsoo"0bv& Y?23Mo4K8ؕ gP8L_I4\*8#9 @RX6N|2wr6lCE$KQN&SmMWBkHK-8F7 d#`%$bP lL:gav'vbg`CY!Bicuunnuk573Km0"0` Lx.X잍x0!wrwxwSBJB_mu҈oR/*wMHSc |6_DHBg()'l2"qͺ00ߒxp, +r̲`[ OA3,wZ/p. ẑg꬛_Br+07~ḱJmiy, z͚zzo.r-?{jpRn5oG|ߨ(ebmjgɧy^PCm{G2 0տKk2~gE ,7|H~2tov FU)l)g4Wn;|WCB7^ {AdޯЏ*qgǿ"Lp!ÆB(q"Ŋ/b̨q#ǂ❓7^>>R>eAA&4-6hA RVv *t(ѢF"Mt)Ӈ*S`A??3F@MϢMv-ۣC,r.~I\J 'A>v1GŌ:~,ygFe g5hz5֮I$J+󑚒W&_$r$#OcdI1Kb*V(ZEkLj˿/6HrO{wLLi&E\y/}H qh~B$*]UdQUP|TٙZa2xrBآ/B[\&նRK>fMǓO@u q#&VdF6h!  H>\rtTMWEuuCipWCB>Vq2Ζ\6sLW`pbT+R%) ge,JYhS6Tzvڝ&*^ʙy^>Rno:8jS%x]id+igZՈڥiw =".[ҘJ|Z>꫱2,>i.&RV,zaav*hjjܖ*R\h˧M8OhB(al p2X>ԗZ5^i7(:gG#MwOKU뺂їIcMfڗQז(jE-bBE2` < (ȟ3 0 ~x8!qHB?xU65Uj |հuAhmkpZxanyGFf#A]o! 2tl5pQ# 8 &d Ch<F`Ž$,aAkb#v~ W8 $#8fs"Hy&Hm{^]|/xg_$D~K1M4aڣkDL[4}_|߿{d'؇~aޮPф&#t8p_d"GH'QЁAA_ * NU[ H9[ =F_)MIP?ȃ<=4 D}X@̟7ĉA[$ԙ "lnbh!z!!n a!af"A Q٠!_!Qz.*(!EgmK|h%9x9<ë̃Ah4AXXpAAC]! _Z /ʃ>܃0v1"22c<8#4J#55Z6 A7~c8퉎(+ڠ)"2Bd"ad,"] 9qPɛ6?d0C>P2dxAퟯ_:)LM.mIJKLIMΙYNcOAPeQeRfbt\A,^$))%De!_]F![FNuO1eN$G\@?4Lf\(#5PC>0)#TO=*eHb.fc2cFfeReffvgfii&fkflΦ@j"j`q<_JvFtڹ h"2**JLj>*#*V_)+*҆`@eYz*i&S0hfT@%.pe@[6 ˋ8+5++l>lQT*#Q$@}g?}dAQ08C %p 2lt 6A&심l:l<@lB,!-M@%DkTNuOv."CKdB C Iϖa!B:ڪm? -mnxm歱m>-Tu%ׂmGWԎxYtgbI!FQG,5߾.2Ab-A:EqJ' )aMO6E?dC6C?l f0.^/o> BnG^^&r9Cnb[,8~ϧzE>4p5(`!,pfY6RQ&5d ' 0H l) H uH/גOϐ}..!C2C< ox("Dsp`Yb,qO%Zv9-B1lMqlR))G<06A UD$W25\r&ױÉ'r+LgLgL/c-'w)auFnE4`%)cS8i^^rJ3A 5,s32Gsk3T,'ghU L0BbUIE,.ʒ'Q(tAʦpʉ)&@ B+4C[ `/=GqGzVE>n6ÂqK>x/MK.L4Rtt 3RpASo 5Oq.nm x+MPk;w88eZKsb_l ?,fi* vIKRVdi;RtRIw*UҐ-e^5_q/֓ߓWb0f[q 9RurXT\pwTI/WTPCe(CB@fAgdJ]!3UyT!c1UC/zWzD{:{-9JEzEi(aEVvtŔ[8S{$7x9Sy{^5yV8!֕K.QJmsmöOƋؾ[3fWvcUy~c5YwnoC޻38$F3ɴl b&[B( mJ*!凧+ C ]|Qbƚj @)G< H2XiB4ɞ$lɄt2)Q-ӰM|HD#V<.aSNޜsN-1Ҭ?MNJDqR+Y K{>M3K*jSQMUU"(HICRII5WHqTR yUHu4D'bg-6s) *5C Wq}@Њ,Tuy^{W+D6x]r PZ0 SDJE2T)b,qd!<2$__fw|XE]Jޕ]ퟄQeS⛉.hυU(:tP&r{M_z_7뱏.[=O3qԬӉf0e]wc[uذ /ٚWop rryLn[I/ݵpAUo.\mwA-+v/'EmiƇc~ mM㑯,$^A5_^a?Zw=X/_=yl\[Ï_~Iƅ]a cj3 Q,  sËA /(Gm3`GANw.t>+dt#Z8 Ȋ7vḯxo/TNo (S  HuDn8 ʆ4H(6,F =OKN0 yӨ[ h|:JAS?2Wʠ3\$4K(D!<*0MH(E-fF~ EaꔗUbHGQ6Ѐx?X Kqp hFӝ$m>6fd{'tqU?B(Twx!t'lAL< u̶s+]0UrS?KdN:[Li4A5Gmٳp8v0-m@` ̖\x^+&Dm[6dH$.&QLX~X^"ܶٚ~8qHB?fB0A2 0 p1W}] QY#B4)dep?qm/X$,Ah+"avCZ~PlM0\``> L}l&`130"3!@ƒRpiSXͅȟ(ᜐR, 7A `g= 72UQ=,@$ ݵf|8MkPrE FB0 Ȁ3>.(c 02.cb jRYjX˚58">AlhO[Վmkgp[&ǝnsvwny{^7)\{pY.p"$ v>^ GhB\.h4 p<0?Z"0F@brm5DNQ9]sS-]MgӝuO]Uխuo]]׽v]e'R0&,eKY fW5^ B["Ixh+^'H|؆-yspѼ!q7DJ:J,ha}|_'1$W~)O(O%}}o_~_'͟~gC3A=*n`$` A!aA :0 (f!0k1P!?Da"4?WFk n>nGo>M4pHHHH.IIItIMHTKHHGHҰr[~35Lfh lssP `V@Pm Q @@ aV 4@UP5PuQ5R'R/5S^wʐO*=??k*3,mu?qVViTWs C/-!B..1tBsC/M*_*EV]W[5W\FɱZ}VWyV/  OP_O_ u_^_ `_4U S Nc67 `(=BAtaXeYeeeWe S H6LeUei6fgvfm)|kuyNQPWU?sjZjjLR-YlB.u%? ECZEkvkk?$ nTpsnXNA:9Zڣm9c v'!R U3Wc۸a۵a}[w_ۣWۖuYIn LGru Kך9v$. ucJI_yGM{Hwa‹NzN8#cU !L !` aCJF) L2A![. ɑ`(AJ#*yۗm95TR=v!|;A/gCˑ[ɍyyYzD*2[c@y61]7 f:AN`Dk]<&AdYk?Iv|ȝ~ޣ}\<ϝXpʩdw{Ǹüǩȝ>!9܉ͻKzϷZ@ 2a;Ś2ߥЭD"5 4} Q>?A;1}2F~aZmՆR쁹 P=w h<ڣg8,Qd8paB Rb1q%M[v$/ű4F.21Udi汘3WD)X̗.Ky gɠ3T*(Lp8*}LʔSq:3 M %Zŏx˷߿9I#@(Y"I"FP˘3eSt/Gzh^ͺuej?b1 SͻߖIsaJ(y7Tѝ={'^߮v_PO{~|?cxwx!HA]x$Ug;4QDR&R:uh"RJbZ'#*qcZ8bid9mA 3E]w)F (K>Nv^0Ehc2mڗlf1 fxeBP? ʜs>TEt(a1`uNZvB*)uڏ{7Gꨢ?jiNjG暫>>*+wRjODUSYY=aKA!Q7YYF%BUjkaQUOf A\rхiY>^DbK6euךGW>X̫g6 ^Kǫ 4P&Csѕ4Iz,4,45XBz͞Ҭz4ҟ LČ>ls=όu`/u^2Z+ibAŚxm;}ν7أ85 Y$ H bew1ʰhv̱ ?r.@LC +P8TmsO ԡUH-jR m6*6T7&.CJyUB^[]8X>\wUJu4V@.I|~ ,` ְ=bX:vm,d'+FְS,e5kz|rMmhUպk_K` {m@{zQP|kAi=E*rܖ,׹mItbW%`q @ 7pUko"zmuB%7SZdV<:.[3< uqi`20', S07s1G,&61Wb0~!< _X*2Ac>d"H>,3;qG"KxU~+k9`LE. MN3׬6pf3q8Yws(XK94hAטρQhs$щ ]gAsϗ7g#ZѓJ;Ѐ>)Rҧ% X#zԨ&eY;֑qYkbCzԾ5ukSتgijȮ3& Q8rNI+r܈Kmnv{nw-zmo~{7N+| VP8vxZ+>r[ ?Y qfyMj5QU*\E ^W.XHҵt/N:ԧnSOҫy_Ǡ؍;whխu}YǺo;LvCPP'N\[x.5Ϯӹ@ug}|1?pHx_n_QuԳ n0+=/O~|'RV s~G:_o94ԟ82H^}!Ϸ~|dc ~H !ɧ}8H|3U~ } t^~XI7e~1"{d~\qP0^7~|=y#AwfuqHJL؄NPR8TXVxXZ\؅^`b8dXfxhjb{ A?Rs([uWrxxt}([y|{臄(8x؈X8艡؉H(8X؊XHh苹(ĈƨĘ8؋ȋuXWhܸHv8HafxeЎ8Xx؏9Yy ِI@T ّ "9$Y&yd?.0294Y6y8moHR@B9DYFyHv9ӒJR9TYVyXLm( _9ceَPgiainpykuّs)m9{~D+I8y fُ)n)iG|Iٙ9[{Ic)eyymd}ɚyə ٗ)oy ɛ ` ĩxyڹ)LyWsiywt)iYIr橖֩ݹ ڠ ;m: )Zq ڞqoy(jꚶɖJYI:;3[h Oi幟:E`Z~Gk9X:Gj-﹛Z9J,; *i i{YjQ + Kw;:N++[z*pJy$«?ʭۢKKۼ+6_]:۹[ k ˥HzûiJ$Sʼ{nY򛳏ʿۯK]:mө;Y\ Ns˾ <Ķ ۙ)+.L[u\47:jB@BE:HJGPRzS|Xhݪ^`7d\Qfl̾1p+v|[p|mǂ<Ƅ|Ȉ<=|Ȏ,cȒ<ə %LɘӪɞI? ʤ\ʂɦʪl˩NʰGiȲ\˶\|ɷ˼L˽¬|ȼo, -ܛ+)ܽɬŋQ,"e<Ƹ  d˚zZL }k)kЗɜ< m۴Wۦ+K :\S{̷.[K$ܹk˺(-'0Z:mRO뜜Ko[ }LJ#kzKTM{ykzSڻE;>a͡D-;!Ԧ|*I-iX]{{;J̽HH;7j֊lMҊq=E m} +C} ]Z;T ڞ=mmIܨlz٘BΡlЭ̙ͪ5Aѽ Ͽ],=ݝ}\=߽}߲߫ߩ>l~ܯ ȴ>.] =!^`l&S*P.K<2^B6 >ݕBM +l⬨L^E?D^R\G.VTW.1J^{Iσе a|Wm䶍-:Mя{J=k#YkkgnӋOޱ(L._ꋝRғnՁ~Zқ>ܰ{~[bo;cm:|)BK{ׂ}=Ռ=m](9ˊx-5ꌱnשf*ؕZΆMYպՇ}0/ɳњ.N}C*Z?"ϰ=L邚[ܽ)/#9מi^9Y@0{Hߐ$R?MLSX<ʶ\<L-foUgpt q_vV~_AN?::jOɭ̕eɝŏ?o{LDR xi/Q樿WidLׯ_o쁿?ŸK?/ǿϑ Vϐ׿/Óo/,~ꯐ?ÇߏZ_n%Z2 .dC%NXE5nG!E$YI)UdsдPb((~OA%ZQI)uժWf֯][6Yhͦe֭Zm㾕[ݹyŻo_|aÉ /FXqcȏ%;rNI$H)U=ŇҤO6׮Unl۴o׎woฃ^u/m\yṡ?.ݹЩ_׎}{Ň'ϽeVfkuSoHa^XT+ƅ0(c8@X#A6hd?uM&yHyQy%C:Yzy"[\wةtҁg{n_}vr2G'{kyf`wy7u(obڥMꝢi'jR*w. |fj&jZUdwkv'>Jߴ&*쪭*m֚lrl[j &;nrj *KV[{}G*+/!kbl~K gY2{bGܰr _n5 <1gGO|-7'3:k2?j1\=:첓fI򞽴c64-tiH_M^y4BSyZ<'yS馧ȬK ׊tػ:ztMC5JmԼ3r]!~OƩ=ݲAEv~}hB >`2wß~߿ HnL1^TWܡn.x-_bEY FALbB8'#6r{ 5#P)\`UP_?ڦ3A |k)r"tYc]ޯj ?4F%0rgL|X7DG ч[ޜ884 ̰ ,`kHpJ`[ A8 CBP!`^a2..))#5Bg+=U!׍qy*4tEd2.Y<&Ml"_YD@5ItP :yA,`TpAܘ=#xHV:-%Bo (3'9젩\Px.3$E2z+B6P .7AI,V%1&, ‡nC9bV@ZwDK}@2]\y:(j8 IW,8 pPb'FM|ukivbȩcN酡 lSQ ^KT&/Dh4*}b8]\Q:wqĮ̈́yޔ< ι.;]D9\w7A*f-[@% PPJa(9u&AYIUBne?Iza.7Gfj٣eQɟ|8zʨm)v_y(ѿo0[FLÃtl#6gysY.-S{qï#H;l8{ٲfeߵfq3G& N[]ϪpvH4g6t;3S- e7u쿗:K,jKzF0h|Z@F0@47yk!n(8Qq,1o`pc(ĵoBad&!N}B ӨI.ә[K < R&' Q^> CָI=d30imD`0W5N0! Btc^ t 4 @@ 9[ȫ 9o{ۤO{|2bMvYodDe&TvLɱwSfq I$p] GEV]?c3vdo{>wkh{Wm von۰ iF`|@1n @p 7al oOhgq1[~ha3?kgG\Fx3&\A6xGm< Q~#7}\܇e:!؀(t n8 Wz yg"ijn Ű p 0 yχ8 p  ց ŀvw0g_ VLg:S?z4/6}xg4=Q~t9_5/A`$N5Jg1WpU换xp|sk pHnP Ȑp 5בr2&i6 ߰{KCWP9 Ap B@ @wG~f$w ~7 @9!bbi/sc#dk`0 i>9G tG v/f5yQiTU邥:X[9g%/%_Ehe[INvaG]vV)/֕* .3mfҩz9*9icwÇ pYqHVwdw1eYj;QHQpXpdVT*1EZcFd\hddDq'# $z١I;1 ֹkJ8kVWfxY&CxZ)p)dfIERAJEE8wQDpYdc@ j)#: 2P  gPr*K]vҞ=~é16NpydF]1vxHP:oYS_-$p @yű 0bA90X]]qOS/qúxp7qh38:K:EeWU@ ʩhm\<ƬSrS g\uG?1h( he2dvg[T/.+U&;P49]J\6T@I:f4JLFʥ&dvhv. ;|l4APӺ^{`ҥp;4&[QK}eU G>XW:}pFiX];`qj'4fEeSʸ Z>^ZklN+BXڸWX,:R9۰bkSԴOJw/K=;E'ɳZ$ 81Bk Pb+-:Ѧ!n͆:g(n3E0)/L~!m` ymP TnY?^  P ` ?P ;B_ U?`ٟ _ ?R_.HT)RJP`aC >\B]`X U2|ccgdZ_HB-U$2`' I2ҡщHN\*$]B<UfPHF,J+TN [WTՊi@+Ῡ :sN0MZC[P *iIޚ[xMg%-U`iݕ|e2!- &K(TaRMA՘*ؤLkԋ6ּ*-f3+4BAbJ[upC ;`"tR?$P-*m4) o˨ QlpGQjHJ0H  D " I08B1HtrL SO0r @ lE4Z`.aWnqWT,4&R-:=QıF$0r'GRUERHP_!D ?@ucm0\a)aM%Ѐ.=ʑ+]`ҪXvBg1%J6]ؑ"X1\Bl]?~rGFTexWJץ;;BpbK7Kێ;er4 kdeDC~7uvԂUPT1vg.1gf0-hY5ȡvav$ m][䳛;z}9SkZv1eIk5w,m#S{r(#Wm>ڂwjIAN]BYa#ux Xc] `;p(~2*`q_|s |eq9(ph3R秳|i"ӌ:EUlS&Ac ЃnAxtQH^{=D"l5ɝlvDkǿiRqjh45A} \FRTK](S*Urkȅ4@t̆P1B -`[̣ *LKΪ}Z,kd0y2$\4JtL;f5 D #DYphWCwЭѲ"*mCkⱅwTp@ RȎ` *@U gCrq\c=hIҞ4VDІ|sK8iT%:ɣ"tX.8a-&i Pp GES0;h2k?fIo*1*7%7{&է R+ Qq**PU')K=]hz-RYLaSRUluIl‘xբ~w-:KbBeOQ* ~(?ѸR9FD5m3gڗhEÖQ u/e_EH 5b`0%[5 °Y=4Uu@"^~o*o|S5&w8X;1u{PxYvJ-ӡɭ+'9Go~/!r g %m \8 6A _<,|M!9}oZ"qUߖTFue]ܣ>OhkD7)9قF+kP#4y(f 0jv.>=.r6j`0tH%#̘eg5,5zW\oqHvY> S[1.v+Ob,n6І:ZB=/Jl6+Mx!3Ss(/H!53-sɑPnT:| iMo[|d;wZǭNA.dPkx1]SNP ǐ7JQwuyC#au5U*8%A~>C{a /v.MV8ȖB-9-JEع-@U{ (6=BG/dzO6O'::9N@"P! [C}ȡR̐)Q l:X{cP{+ @LZ:Z"Ч;"Y6ҥ6js@)P! bX4 :;7^y5c#?%6 d̂0c%آ<":y&kBdpj$)G,gy77G7V%6h0r  صAJK<7#)P pTp:y-8 %pöYhjfő ޑkj%~Y?6| 1yb=>"s TBAт+)8-HȏrY+>^z@-@,قZRc̺rj<'F,p`|X>q= MPϔ#I8qM,aIJЖ.ɖ ȣ0pL# 4ͨTd pN`͘p(=\/ׄM8 MKXt<XJNNlp M \ ){2p3T XVxPsHQ I!< JyA8 zCԲCAC)BoSО?LЄ#e  Q}eHۈpP Xd HJK lMH4S ȄH&9$ X ̃hMP8/8xNM esBP 0'9瘁-3͎HXppXDUȀu0EL3r`Hˋ + DžHW`ph˅P htF4˫Ƣ"EE!^\S[L`8M)R Eep08J0sHU(UE`H0)sXs )uTŀup(] X4SIGR*K؅Mܨ0LehUXݍ/qKN]K u;ՄXuu5KpĀ8ᬍ4OlT-TȄ uVh EfiKP3RRh/ v1ͱLƙoH)hi 0]%z?HLM ؏u6ZGuW5تuX0)uX)}ԁ%ZXuق0uTpX J`X2X~eESmH XpXҁ̀]J݀콍^)mp@Oh^=>KH@ۀX 8yF=N0S5U/XxT88^ (a PUleM H։'K3t(AХ( aaab-B[s(SWXK%_Ҫ]W%uXR}^ ^E^8=Z%_ XvXBveG&d}^ `vc]^U^5d9_5]E.sv UV^H^`L}dcv H5-as(S4#==Opx60D˶`38#"Id@aPh c0CB q&gs&i0Bd( ] 膴8m0 ~^l&2Pp㄀EYu؆me]R8-G%ق8KpH΄M_SN؛ph ^H_OX2W%d]5BcȀsMZX ]M_=cހZ-ӡeZT-eOM5,M/JxM_MqFq`Kֻ;l1qYFR`XBv& ɦll.VVC ]hb膣pm$X?2/[X埍 kd 4 W;uԡj@3WM߂PO H](),\u~ vi2Ss8N_H75hJv-}(5pS^=^3i0VSNJ8Fk^H5f[>$q_q_KS٦=]* o!/Е k h,$/DžG-c%O=nԲ(T8RӁuS-Co9O8^uKMnc-~uiJU-fT=^XB6^j0p؅6նMRH^8iES>S*m.q J`0J`t>D;f{bu=bguqgG:g &"w 6l(^r 7 )rl l0Hu&[LPR؅cSMMNhH_E^ąs 4UU:fd*A^/1NpNR=t(eYUpSsXDQݍ_w^/.!~AqD rvqaip7rWV)7kl!NJl.VAOB*օ8sW%Ԟhߊm/U_XYXd& &ys]uދhkeO]XiXMdF~uTsz0=U~5S&Z~uX04ʝd]]@Um!lftCEg{ @ L(BdȄݩC;[-0CbK; + rmM`l[᷄ rmZ<}ͅGUR$J@\e4-5e渮Tɜ9KΙR%Jcð.SJ ^V \Y"5:p2d-;$/\ ` 7.%nR m,evy첂$mMס5eR oXO!Dyԙ={Jlh| -f{TS6:( 4ADP ASw, Tktvq=( {4BߌIAAX29dbiV[97d^5f[-6ft喗]5%b~%q΍Vgq9:wuoy$֗ Lv(cAhS ca`V5vх\}I%t&YadW`[A>'+1P޸c:樓; 1`%<ܰwt* n_}% YB._̲6D%<%ddg AxEA“b@ k@,[zjI ho&i"B&@b`<կ%-yAolri"[/TVqF`E0Z+W'' ALg]tӡR̵ \ u Do@&=zH#.Jn隠 ";߁Ϸ. +8pG2HxQ%w|ᬕ \Pr<vjk :0 c@L{ `qUT\ W@ 0K[ Hje@&k\(Dž[\D@  2ULQ,e|^SH hBzУl2` Tbb˰%,>) Lp3ܵ]!ֺ\)V, k@6`1! V oQ  Ǝr[bE%do (  3"-Hގ?Uo#lh7=%<% o|ʠHEBR4#%7Z"1/P.XzM(lSVUD n$Cd|[$XŋeČ %ViJPb<%<%Jc|ndp+ĩ-Nv\N2e=Ah+؂T-tҢ*)C!f[f?fl%^KURnR5!Itt%|Va G,A !('Ώ+1B" "*53&F$T[3N}95jrC=_iZ8k~cwERu֚˝EsV (9EV|!QB+emWW+^.pQY0 g*nvf~n`!5-I:5)(`BenIC=GkxZ.nHԐaWdKG; vݮT7ʡ]-E" nj\zq\V8P KqYQs5h#=mHjo Z60Q`ֶCs7#;+; |VD l5vm sxGx>wy[hw7FёIlg'ֶ9X:O3G䭿|A#.D\*i{zQ{ї>t_K.|!knghۗ7Ѐ%ηt8O6[eǚ؎MJw7.. ^39W ǁ{W qC.xÚw eNɫs9p߇/\.c?VX>? n[H >AA8] hZ^Z]ql_~!FYY^M^A=Hݸ[^]i@h@Nʡ N^Y]ܭ\Y]SC X1]Bl`C`-l8|A[D(A%k՜e]5X՜;` FZe9]%FA؀ YIVZ!"6nj"!ƽ`}U)` ڄȁ`>ypUDEF`HCDGT@>)p(ߤ") Hݖ5 ɈD'n" B4 "(rzrYb9UT@mA  HIOr(*G<%C0 TS yd8$% lF́0\B4@$}0*1bOe%&dAva#N>[iTf |--DB@A* -+ +܁ ]ŢvXA/6@HP6nEДBhyU@`6.uj AB'T+Z)-@d|&}.-ATQ&j D \A c YA8F%e^R(Ap!- .`&JabtNc(f :{'w8d@p *jliBRނ-t|l,+{&fބavXS)NeeJg=|/V@ F-t)e֝:,@@@b_ǢR-@]' ^D""\BtS| ,))jkB,~ gb7**@B'{Vg)@|܁Φ%@܂PjDtgA}DEl|t{DhlD%,2 ,ŀ @O%n@4 A pjG`)0 A) Vm ŴA4 pl) (@ -V1Ґ1^hSLCxYp\р~[\Z] ^b/ N$qkin+ (k B$>r0*@%́0Am"nt0);6'6A~2x-@ .@2sp4I/4,@o$@NOz@!)jL ).&&XAxs P|l(%0L4@Tӿ) AmRMڐKbD pg(~6nJK+VVMHGhPD/(DV}M SDSlT|@/T; ǑMM jh5 ͡}h4RhծqJut/^݂+0ndgvƱGzF:NbA4@A8@A4AA[jIMhA tWb9\Ebguޥ%¨!ڈ5\E wGWdC6X[kbq6Siim(b^Y vh~51ZW_CF56,$AnYmou݄(af[ ?A6t_\i# ֵB8vYx'`!q_|k[`cAmB6VA 4(j^ A #EtAdy #X.DEQ@pAk59^d y:7aH"1.b?y\Cz/ FA @\99#l,k Shy F#75 pP9U]Ť8yy8KEk'{N~!\ƭ[!&߮dY AEy-AA xE1sAzj72abLP |A,*#qSrnz`R#)%hO0xc8- T@$XQX#$(0;=.e;4xʄ+ %ØalIǒ4H.iԤH:zhQ%V Ǥ˲ukۨfruܠizT B0x)sj[JJvⲚ-#\שGIhˈPnq@ =rc , h*` $]ݑ+,O_[Ystk:s$~e%_W+WcW;}A/,ӧ%@,2 >Ғk1L@F"&c2p$)VP )0c,x-p7z\\#%f4_="B)Rz,&o+:68"{ԂR=:I"0#tЀLpIskϲCCLoH <( ¢(==>+/tR/䒾,,<DN5:=-X 0758Bl@t5WS4>Z%̷-MV@[/T;>5JKL--O[4qՖrե,0C }ZeveU8"dWSt~>2}6=r-͖cF=Ҁ4`8w;mm[@nW 7 ըyz^]]9YAeVSeϭc]wKR8)8dmfGL lS,Ph^:? R%И9P"*~fJoYt۞E#COLgdi7񻵫Ϸ"u̍u܏HXD(M_h# 7kHZ(! 78 mt=fإlSUvvF t1b(T*0lCɐ, abv)JM;>%8.y[ FF'@\91RfX`dz3;ܱPn;78c$JvA/uW--hقg|tŬiaD)nWHwvV_$RgJjfԀwITS(]nN16]l%Nue-V>禶}N#SeTɍތ\ BI7u`Ji9TTXfRQX9jLZ9ZmfMH8Nvū$PXGUr)YӜsmZLVa2uJeǰT{GzFliLKԏuIoEN53-R¦M >/{:dӠ VGE3S>,]:k۱厖T`a)~ʢ%HWܒ(9*ؤaxE|mkA9!!ؓx)9쥿p!KNTTbuMum]4;NwóT*dNEo)'v]=K>Y2zfFvjJ8f;1I"yQ 'K]iqߍEpa[7c++Y̚:d%XEnK;yUrC-YQ׈t)^:TX.hU2y(_Vqp?!p;-:RTIY*\ S..A*I=8yXй]dylǶik-wjp ! ib)Q~p*"o%)b(pJ:@Rx$LYb:K7Mt=~ p 1Ac)0^A@H U 8P`+nW$pzu;`Sѩnqw䍮ObUM/F!BabB a x$\ QP`)nI"2|)BϽK+ ڊmX+ajPp+f3%EMss[#!&gQ#}*L2083/"#/O1rr( ʗ̹@Jp2'N)Z g]yM,LԳC47p'5i?ml=W 6U!K,"ÕT,w5Tr6ORzLH-QyO4Kɲv\ ŚM3 R,ITuhw47rB+vRH4,ג7X 0K!ͼ\tLDS8o#H~vc8ӳ\e }3ww5n?eXU+F W|YS|6um۲/j7LWs>#^{]0׀?x2ծrdWpbV>@8D- ʃKh?sonTwtXJR|2u]wKcXTfbqeRƴLJXi Tc^F3ԈohK/-Icf/-D?WRy^uV~x{+/[TO+vYL-On'Jgyv8ݹk#؊CWl-y|ѕfPF]i3XqK/X4h{wR'Zr|˙wfr-ؐV>!w^ Oyaنwv%:}ߘ(q9Xґ9r>畃iV44(PW:TSMM:{9{Ssz2o51uCjxTSiL^Τٍk9G5Pn=J -ڢ/ʱ5O纮M5u؈J}Uɰݙ֩]{ 6stWMچ듌?wx馉%YzXk57-zOQ \]UL^˸/B.+(^Q71- -#.N!"Ԏ.2~} :z9T͚i0Ir/$QO4r$K.0{]4 |)3hQ`e%;'63oA%_NXHn !bSo!n/!zO~=L-Cz۲ ]>S#)ɕUeK$$!aDQ `(N: 3*A8gWKdȩ5::v#nTn <TfA7)X`p 8hP‚n (8- 0D(QG@^x#Hp$**@# X\0J dHRåI/Diԩ§JQLfUR}TUav*Td*=ըָXn= F `pA^D5J az-J,%k&Lsڅ0`$KxV510k"%!KD-9C LRuV-$|4!E !v̢A488ҳ"X  akx0% *NIo B%I~f ` K DrYPU\EiVd)[Q\XaV^"]Eؒ7I\T\1j8ч!R)A57i3FN rEt!6^$e\(ݗ @b4 ֗a!<_z1yE^5Nza5e|Qn,yAƅ\~rmɸaq[NbVTvcS>ٔQ*eZkWӬ͛]d)d!BO cвx:"c%'241HCW5 2L!9}"|MAPvU:jKNiZb-%ᶰ/B먯"Z2xjZ|k*E4j>sou\[%.J衋N,bH57q]vmKR4XFb'2rt$m0ki{ ڴjk{-]pjl1llt;ܕ[EZuys73ˍʕ#$;N٧όcjQV U).zv)Ϫ:gxͷ۔;/3뀃x5cq}8sq7áNyvۋ+d۝cQqwM>TU,78}nY`Dzi/K{|<.~ .F:% "DU>qe(y.CZ.~x:͆ch!B-}1x;Rȸ/+/<kW=$BQbU80f[S/jQØãT1+~.j|( wK{gI3P@ldߧ8y\;6ɴύL^H*l$yrq_/hR\%e>L"D)C^,5GhSd8Ⱦ&]K\q[ZNHM`fQ2(M~u#r~Jz$LqB|C@fpd6zFRґK:]q\#*-f0M|hGb.0#ى( eO+bDvRl<&Ѕ'*QL62-ŦQ=jAr=NgVrkcJDz:KK5d&*?T-[qUE"m!+Ssr=Vb>EF/Ykͦ6κ3,qx&+N X1+_+ƖKrIҠ&Q!3=۪rd.g,S곜nIJLA֝Eh:=5^&SF'j;ۊUtL`R~/y;O񞕜xc*Vi>RbUFؘudHG^l}oT*Q^Ӓ]lvJr~jq''2pdQn4$&5YL$^6xSf{0ufhCYMK6=dz9U/͜(\P)L&1Q<&`s ;Sv|[K7qq=uSk[+T%¼g{S,m,/lmlθBn*y_iE>Y<wCJUQxkl3U_^xО1^xmtҗtpw2 Fw:s]WM id˶=cf%*H.:1 5P¡ M]'{$P`wC8Lp P, 15aJ)or:_Jh@3/yD(SQIpҥ[h6~j;/`&VZY3[%p:4?C4 _E|0xh~RDDmvg@BJgȂ>@9%0$-*Qt2YmP#Yy)ywu%9×lNTq8S| 3| U]CDga_V?؝'dVcц8mCEi&7xX]g{jܪz)xŤkx4^GHy_HG`HAvDEHPچupH׫5['BUtT*mFm1[e7Mx ,X*IIOEa5vLM%v:fZ_ i#q5!jvZqii|k %N1j$~kj6qx!@+soWvAٙ^NAf׳+y  Vnqnarnk %r1o v} O!Ɇwթ`V۽Sa[[ $Qrrr"0tjA)-'RR&,S6[R;|IZhP`ՌŤlP+wVB98"i#I#`vI^%y(,[/lMy{9)h7i$V<SI *'`G&͖1<ŰՂGj;w@(a\xZi]ڶE֙E%bOL_S||EGS"cZT}9|1\G&ӆm +PlKŏ\`V >(6!?iki f^Ljivk%p%aV!-(q+q$LT糡Į%v̇)bd&]' K2A r˻ R0tsы z2 )] lr,-o&2r$g'QļXy|^+Umi4{ucqΈXLtl){,s ar+7nt~A['8W ,M P j}}Q` B !׼0JMXz%TGu .L=x I T#9mLZڧ9d OQ^g'C)*Q1Y/_А)1Zgҥm9& #e&a@#,Ѳm,FF$`P\WAP+T^ : ڋD^~h"Ѐ/mɩ?/b, aajb@&X\苉TP 2$@jN)X`@-Rؐ @H"ƍ dѣŐ ;,H Y^$LiLcΘ&{dY3$N5aUeQw2Q)R+WV ZqђJ-iS7*lǫ)-|2ϣhoZӯI. .Н2a]qiߣBJ._X>6ܖ$Ӭ6-;κwf-I+\9$⟑.֜M= 6ӞY.<%弢5s.m_\7IVU&FWc^ zר+"vWJ޻M~X)*۔+'/K@و ΢k0OCˌk9> o*?KS/s2 /48λ9DRK(;^ sQʸj sK3LaS@Ro†K4pRZ/JN\HZd1Nj`ka9Aq#b Y@dKV1H%U&:ߝ3zÃO*f,֫]kVMd87f! Y@mNva(@`&;r)d9ܢI[mYlBQd.fBliyVy6na]n f3%>15%mh 3ӳctyHW:zJC,c{*J-H޴(Nbc]NWT*T.p~D̡5%ދ-ka{WRv%䯸4]PH%Heʎ>oh6=?]lZV oZ5񉵽oa9_:ψ&-~al< /TTE-k.Өj6m[=ӘblywdEP0+- đ=} [7U n&zDՍR mOl'>4[F"o؋Yi,\+î\[╸%;DJ?JOj/{ 17 `uj~u\9OEmDW]4LnLVgT3kgߪK=ڟR0@swԡ;ɬ8G[jed9WѥMhzrv}g^cAֈ&f,NBmbc3Եۛk{5If8V5&7L_ E[8j[t;ah]jvSA&nt:L/i/8q1m>rZn/*s+yc{//70%bx^?3ûV5w}t3RGkдm&=pЁ Wg1Ikܾkvϔtz;`_Ox%l?k.:c'3~5 *p|`3%[OAqO}RJ_ȫ2 tp傳Ef1K21a+R 4,f4s;#7%Ѱ?\$/hA-hAVK;زhA0㵶AK=5 D3ls2}c(C(t<:L9Z9 d?. -p; >35؀p!)5, P4<;.5yA3;cClC;&4K1T4EW=+0,c3XĂPM<eT%>K?>S'2Ƭ$#L(]1NcBK58Rd |Cb4pĨ@/ Dz+p=nF˫{S<=BC/D[68;HȲB HPķ0/4Hp.DZd?<(3;^tÖ/ 49;{vOۻkCPAgzTBS ߠ~lG(Ⱦ clA)X-Ђp/̨ I;9-3CQD4(3CԘ4ÒTGm􉯼L{GiHf4C 1l8jsS4OK5@4\,S+> }C%S4/]Ôo2POcǸȒQ:LLC89MG$y={Q NC6<$\Jt+L?l 4܄+L)PS+%TF:\\8OSz]I"l5L9O mR@w[ ̴輷S2xE@4DOQA8$ʐ;knopflerfish-osgi-5.1.0/docs/images/knopflerfish_red120pxl.gif0000644000175000017500000000077112346515440023336 0ustar felixfelixGIF89ax HH89)*uvWWfg!,x @`!`hlB̋PLԥnt[HhY mqTS6M&:%x { wOSނ, 5JsRuW{Z{JZ{cވk䙃915=MBNRbkⴉƁRmԊνֽֽ֥֜ƭνޥޭ,1#Yb%F*\ȰÇ#JHŋ3jȱǏ CIɓ(S\cb3vE 7nJKYhEGhQH&])ӧNB**իVbݪ+ׯ^Â5JٳhӪ]˶۷pʝK.Yxw߾  Y~Ҋ3b0e7hrX֬^g!M4ӡQNzְ_ˎM{ڸo{wNȓ+_μУKN}c߮;w3hg1^Ͼ1,7D"f>ٿMf7kF& 6F(Vhfv (ƀ)',f"&8-b2X#?Ƙ"CBG$FP2Jy$XRdWX\Y%e襖;#mߜhA'~>4 5{I'f-J磐F*餔Vj饘f馜v駠*ꨤjꩨꪬZYSხk>@h P l~z'jVkfv+n覫+k,𻄒p Q05D B 6 lت;ŮL J$+ʺ<#r)|22s/̳.߼k:s; 0kL/]t< MP@u_-a c6fnpr׭ζmk} 8v7}8ɉǽO~WN8ܖ砇.z)n轚O?nF .B þZ(:1֔3|8'07O<;O}o ~#}˽~?۟?c@9\` (AZ_un*!GB0}r! aXB 0&`phCp0)XB\ fB(`M?G4"#"1@1"1 =9 BW|Ejs@A: dIHrxT {(G$"?XEBd$;9ɏA*CKR+KVҕ,sI]Җe0u b Ә<2i5sU4)MNӚլf4Lnrۼ7q5IALH*1 k z'=hO)s#4G8h#01]X`>HԤ%)$< z-®d2Md4ilz Ou*>!%Ր ԛ;5RUZT-UUE$G}duкVouY*H5v\JW޵| ,^ XUMa ;rrrLd$#CҲ5 YVֳmf 3fH@`O($JAmkcPGbD%1Fhe'.t:KTO>4OEUUSrfajYpq]k]ߺ=b؈le#~v) 4۵U}Pcm6?qFF̣md x"uwui1u'5HZg9*ȃ/h<,qWSIxcjZ7eSm}QiGhKWRsXweyX;W4py^Ec[Z:az`FvCg-}RRLL o Gzp` ~-Eh+ ~pwhcȉ7u|gG`  '|#T` P> ?```k(2@w À(V5xDvtVu=lxMG7F^H5Rɷ-z{jR)8R!РR921Đ gP^{| L# 0,*Ʋ;U|. H '7  D|ɒ<ɔ\ɖ|ɘɚɟĢCyW$,̜'`F9s:W+p&`Pˆ+p ~ HI N9R7Ţϼ? ;Olj2z` `̷:]|p p ɸ ^Nm P͙0ηxP m0Ȑ!wi` 7C|g 's"',.-=0M/}2]:67@B=D]Fm*L,CI 5P4\P-bdsa-P3+oļ  y]"z{ 8ω쪔9 p n;Japi 8`` 8| (mj`e`Ҙr|il9|rlĘq is`׏٬y BʢƟ kׁ :(Ѝ(=݉b)׭M޽ލ݉b"k"۝}M߳= '-]= ] >N^~N#> ">u1c-ʰ| )^kզ wHF&Fg斵ǕΒ+1ΒyF {o' n>žˎq;U1,N0ԦQ^Cձ"pnFF;>z2Q!,`;Rg )%!,"8mnИ-''" n  b b  l !'i@,.02?4O@Q:NM75YLd0a(%R]N!(?5`?d_fhj0 =[@o[qJ\O|U'e e-dp(B !'j?_@$0N p? 1Nr$/#&"K#Gb#/ϟO_$?$."$ / ?_OǮNľnnдA# A*DC N0"Ń+BqF #vdH deK/eƤ9fM7mLCPgK>sEψF&T:tgQN>Y:֬`UYic{_2eLiA 2>%߿פYU%`oe3ŏC+Œ)o|y1WVĻ7'fmzj׭a~ZeЊuݰ’UI(SB>1y ~:ϭHr Xէg=[>}Ƈ_fO֫O@* 3 /2 Jh!/j(j‡G*R1EJ]lEU<iEdFZ4}q!HD"y# 2\rH(qJ.2K -/ 3-DŽrQ d2N5d2K:ܳ-M.REAPBHFuPDrC+M3LKdSP?5TRG5TTOU5TXUVa5VZg5VY_=qDWG}B vXcAp6Zjhm[ow\q%\sEw]ue]ww^y^{wv_8`zm 7c 8b'b/6F;cCydK&dSFye[fecyfkfsygyYg:hYIAf(䖟6Zj89z뉱kNI岡Fdq^{!{n[{o400/i%><|r)}oykW~{}u/t|Ϳ/_7}W}ߗ?}ݯ拗\+ bˈ3ƌ 43 1 |+8b<@R C .$ahAV% x n;4 zp\ YXC29 "}D#)(ґ4F$"Zd#CION$@G .Dd$2_:`B `^gau;1/7dsػ41bH>͉td]8b8sjS\5P=T} +XH2PÜS5u\[YZDf5 -Z׵уrDpb/ [Wn]%_VpjS+[.έ!Tٿ*.}kcT6`?+Iyl[LȲVaT#Vvu\dlGڪ%.lQ{\VsݲNWŵn"ԹnvK] s[hsLnFk^a QX4W *|J`bc +j%\Nݜ\۶4[Bq\^'7{6q,Z-FE6&(c'۾^1c^-): DpI`UuM6#:69's7ƲL7kHf`x,g;Ω}=ٖsslh/;ʄkzeSTnT;lbKs<0w"N*6NZACkl2\Bw´ސa5 ydɊ=mcb1wCv1\[^η?GC0G׫K~ci c)d{l+ kJ1>죽q'%^qqrn5ڇ_o89@3<2|avR)OsӶ9NE_p}m} fzO8ZU7pbdSE;=9.-Lv4tY{ T댻3ιݟqJ6=_;վ28+YVyahYPЗorSEFzm[ם.̧'GarjVulUS#As:t]iňFQN_ys_ I~\#H5%nۿyϭcc k0HR[?RBYZ.ê!\?/zz+l[>z?{w?c1C?#!j@[*3hA%aK?;:ӯ9c/K$5;:#%乯"(q2=%T){'ғ(k;S3:<ɨѻA:i'0;o=7ɓЃ =qrś÷k@<Bd߱QD˙C2R

;<&è4;z<`C54EA:bicKK48<ͯ"M;=ԧ]܊M[ A=q#CWL1cȎ28<(-ҩuc;K Ț\L2"6O:r-ڢsH I#s?rIT7$(=ܮA/bw>b}#e:CY dm3P-@A\-.6O>$QTtZj?/vIK,.Fw:c'$E"r2+;A D$1 C<4SACUD̤K4mܞDEw 5%';(ɬrQ£*@ wmV}ő NFBnjt7o=83RER/*JFQVTIh|KPT@RbGԂr+sQTmLMCDɫ&;K]Nͳ<6dBˊ;Č:mcMͼò4|=#7LD3A][^]uHkJ6Ou0ԫ 0i>Q;G#FBH\ GE*^msnW \[8#9wF']QGmh?*F]u>9KuEQitҭeP ۬%`>E؀58;%R=;xQc'u "NE~{Y<3s*yT]l*CE[MLUK(Sϳ74>[ORLb8 !ҫ(L lܥFm7;<9<&iZ4dc3̗7MAA,ЂC&B^BVdGfdH6dFNdHVEJHnd-LdKN>dCFdQMeOdTdSNeNnU.eYKW[NeKe]eUeY&ebeWf^F6f[eVeMJegGnfORfXhovcVpdjfYY^ffVgvfe^frfzfsneLgNgy^gu.r~zFewu,芮 ph臞 fhhhh蓶h^f6hhFi^i鐾ihi&.jf~ꦖꝎjvjhj.jj^hUykkkkkkkkk^٥a,^7lC1ŦƦY2Y|Gb#͞y6mlr/m)mۮmmmmm^ھmmvn8nmm)mn&vmVoVNF>ofno6oo^pnon/p톘 lQAIz+}RAKudoF! ,5X֔DVw,l#Fwa+r*]{UʭF%ӂ 2r/r0s1s2/s3?s4Os5??fU?%-Ny±m!83laE"㮁c T\ܿZCB-SEM_slZ S(5uQuR/uS?uTOuhuWuW׃^je>V%bΝUīvY&HYD3P۵Z5h'kMќO}8ϯ1uSdkm䥹jmUw|w}w~0wSxxwYBb.0 cO_ҕW-lY }SbS :g2mkz*CW2XMgZ+2)_Y\ *Pw/z?zOx34pz40ud3.`O=SysYyj%\Wv-ZṈ+cq?D>-jb\,L-a`YHN]w||5߂3z<ҝj\c՚gRR .h)W$} u֒:G&řH?ն:Ud.l0Ċ3n1Ȓ'Sl2̚7sԔ)PH!]EtS. H M %ZiUsQwz̚%TS! z&Ӽ͊ Q`5%sӕ0OM,s#o5%yI֎F8quX5}mGP]-^} }Y^L5h8"%x")"}6i06jZ $0Q$ $U^ƨ@(Sa;BHyT]Aut(LA|:1qNԊH^gK d!b4Zf*Utu%},qpt55B( CtW(e2TfYT{CntP_~+x-:+z+&!EBlyE`  4GQ)@\pz,^zx ELa_X(@zKC?x3{ax N"h:NjYnGjY1*#HӉ!G"#d{ӄΙera*uV3=3.khEj>; { ,`nX'iֶކt`]KA lԅteE/ pIB NC_?L04 +jhԐ/w| bӘu$1q銎o0Hܠ]JU5mN!aďhah&?CO#|3V}oF|܇=b~I?d,f n5[,X d\Zc!J_[ pxCxY3^X8.&ߋ^wF2?Z( 4$X3G>BH\ЏRZ)Y< jA x , &Җp6,Vh*yH / ^5h(N,R_yiirI9Up?%MI㙠c_Ls>!䶒,&#5*0^eC>8b/zգ JG<j9P+G>.%R*y$A9rA@Ct0Qhk\ȯ!Ğ?`)fQk \)Y 6SآW1c[^%XYo5a iAd4 E!mՊ&?eMڒ3)eu='Kܙ(vN_@kE)D0MGטф3Ɠ&T5-GO{*Thk[節EK{+@ r0$OPL2 G6_)QMes z#]8^]bh{]SY+%,?Q"9$B{j)1K8VB fR[:Ʀv"bhXPOV"</Y%B-~%g}-hMQ>6vlqڇ23_g- :,.K3 )!8 Ũѫ+H )!`C0RscۉX h0. 4 Yu>iHC/{%ݠeTdpc18bXuTSZMd;Cin&|CZ+.#ZNmu clthl-j86({E.M[(d5ei =&3C*"@o2:)(މնy h P@.BsUJ`iU}tCl%!X 1ЃBxfZ0< tQ>0\1N>`gQ*ȭ9{V1h#JZh׎6֣lj]!)m׽^Kʅ麡ֈGlI_aNrHQ&['vy]xVus`c6X=E\edM>fKW /2'v DAuR'^egۏܦP4-$RYX?]Rb͕,c⽍B槊IZ1L&͢)I}M(}N ]MD"T,1 燶id@tN爒hN͡O5KÀ&bQ Z-RibPjU~\ PN?^)ffwIX~G &ᧂT/DTzo)'Ё axjl(檮? *6>9* X[RRF/NV/^f/nv/.@8oJhgmx///Ư/֯///00'9 GO0W_0g&w009xH 0 0 0 0p  13? qC'q/S1;10oq0[0qg9ppƿ Fϱӱ11  r q!!"'2###2$/#Kr$7r%O%S&g2'c'_2 9p¦2a<++2,Dz,2-ײ-2.߸'F/#/F0(C#F?(C3G34O4W35_5g36o6w377388sr 7z*r.dz<3=׳.3++?A?2  A/mB4B7B;4C?DG4E/ECEOtFW4FwF{4GH4IoIItJ4JJ4KLtH9:*sڳO4P.2+gR'RK31%OO5U;ش(ra3 lU(,+u+35ZZrZZ5\[\5]=r>A5`j(T{W/;/9C:#)4c?uPgfXughHh 4A@5V6k'lk3#}|K6>A8dAasa5k34Adݷr/c+}A~ h @'tNu:D+'_7[>s~?>eAA)4-6hA ?VxcFc$I1i'I#OtfL3i&'N&*[fRϘ6ujTL4`$#_ZԈ/FN5{Vcȑ%O\mލwF凹c⌡w@m♣o4S|sР Mt<ԗMS^Yhؠ?Ϟݺue̗5Ogѵmoߝ34Ω۞~lڹKwۿAs ӴPb(#M%ɒ'Og( $:[i,# IfVW-uSVuNVeMz/>(#"##8$>HgAÉ#(b"h l8ˆQA=2 Y>|\ 靝&~aB @=`Vo 8}I'Xo\p G\qS"(:/^,2Fy{r#@#I\bȊń23t?q"((Gk4fPiq6ei,(UKXFkQwSBXpY Qx6si)AdnCF8FP3""9,p"a/Gqt@x uE\G?q*cUH>O/CzܐdLyn&ᛁ;8@NsSNP(~qA Z,c [F42|h?\~; *Z5]fmS!f)[Sꤢ5%?T \!2S̸2&BHў\ՐW>tHo:t~x%,a%u9`u&^Dt#"5AZ^#a9EXl$ 'H?̠< ]nMs,@1q d*ֲՁj()5@Qa`{6˩}uKUJ_hCK+ȩku5]7bF oE723I"8pB9̡Ex%> \@'x]38WH[A jCX`0b|Q"?2[ad$3a-[  FL,X,v1Ɋ` UȂ (Y0.'9qZSߞى/+U8]e~KC3먁IZS*^d&կ^)FbH';8FE `$ ! d#cX0wK6mo, fۣ]x_8[.W/{rvA\) 4A ̬f ћJ ͽ u_BR04)X'ҌK5RM 1ڵUڙr+ HVf|a؍0‡b?Uq+H@D&.QwIZ2XP$ΐ<0!iwFwx=n0`߆3%NFbחu']c*H RM=hZ ^^=M WS*}c3tU:TNom3Ş+?`O0}f4)H9R1QT<3:S; Em;Ԫ3+pIp.FV`(nnr<F%p2N^K-ɶ`&a 40"BIFBB%PP P;"DMN͜ ONNw,7Mt﨎4Hk 94IT9T.T-oTJJc#,,RKJ:.C  r!I.&D pkO%l N*C "b>S\`$5^mR5[5[Mm\\#+]0(pozt)Vm59ydwesdYVeYvuXXX,qK+PZӓZJ;Mg`X<Ú`BrrrŞ`U^.'AN`@`Rñ#U^&3yaZAlE`u59%aq_eqijALj1jKϹZ,k+τFi\/0Jk+r/s3&|nW r Ip\o@sOaFAaRl3?+Afvq!rnUQ׉tMSQ7qru \x3Y@n)_|W|Ǘb|Lk%i1l/I6 y $uKO$`w& FTnA^yR\ V 1Sw w*S}S ~`~~rUVS_cX-==GaÒ`jk?@aۢ  _Z.umT &V@ Rc1oh*61wXQUe/ckO8cX|.ir1 $$~_L8)V@́ B؋3).<А3nE4yDR8zx1bp7V)GKW853@8 NՔ_- >T3y$ `R5S9SeF2Gcw"Lw]'Y& %y^HTDCV&6bdĝ"Ey]W77rSV55Yski!y7Bw#`5USy۹5Z(ڢSq5A A$UӉb/嘛jnRMsZ|Yl/3xoCzIV`CIaiWuC8!ib[W9-dAѨV+7cqU/"S33 A 5ۀ- Al;Z&'[煣AՍE:a7"YrE[;-ذ[c-qze;)~`I#5;_9IZQ7wcؚoyA4k;B {)۽c{{v6G-;Q8?Ua ^յu[i;c)³ھ7\#ۆA=9;[;;x;ЌҪ͛{;m'_[E;ߙɥťJ)WA\:9/ǝOܠ֚߼EM{yGe-}3AWs]gC腾!9YSuQ{ \3Z8=A\ta~>Qmi>oک>-u^S[z^E^#)&[}=E< >v ~C_{yqkaCJG{A^Gw >5vx1ُ'1\cxw6,d~ןe?W7^~7gB{a…7.<8o{QlYo!f3e+̙!.H2%6(5jp@cA3gMqc ?nӥ"yɞ%{=ѵ'4˛_XTr檶P];4w%ބFSQUYEW'")X7IeDU%QN`fa)^I_vVOIxUdXV A!̍]u/H5nG\*ʨr-q]q΁w\"Erf^{V|RjfbkYj4Yzhn|VbB6j#Zcw9y蠊.)i:)uV~+NbAk))UVaW^Ko# ;ʊ+`^jY[Â@~hZZ *qG*J yr}). {2qwȧ6R3vq(mtJ;)M JOM5M|ix\5 !my,APvn+칇|% w+pX uπw]ҩ33@'Ny喯ŴN+垇-so֤I<󟿥N{^gw}a5qU(%|ch!7ӛD‘"d"D$̠FƑ~O=vr4rF׉DC"˨XZ2l 6 E8 ϵxɛ.$/*$%vNBh#`5d$cyB=DF`?Wx-~qg\x=1%8TfH- kh0j0@dX41c8T+mF]܍~xϮBk(*m aHh4@dpBQ`+`@ $pz4 hE3)miLkz@$D q/#m_'Pn tE7ёt/M)8_)yۡlG,!h4 p=F?xnuMph6tw]o; Nj! G(B> Ik' EXo\v7|pzFjf`CfF6A 4Cr{Z@<zM2 #8!@n8nLw:ԛ[Z' D(B@' Vȝ`'8A|?=hWwa;LB>seH)Ĝe0?xE w^G<:[o9!|=m{'yϵį,%Ad?7$M}og景ηg#?*i-]^ |p? G Ѐxx呂 y7qUw#hXwJVr}D`3W %d80= zg=nLp W#!p@ Ԑ€L E5OSUWZ؅_cXgpG kNqHqJ sPEs0Veh85j(ThXrbHf~6$s?WHAgGat#ՄA  sZ#00 ` & /p78؋X醌ʨ7_|8q|B.肈g5W5Xoh(h%_bEJxL+pb[ p ) Z pprmMŐ Iɑ z3 LJMK@Xt IІy3 yy y!i$Lb's\Mg^xp @+ rt9tpy0hjɖn wuYy7P`׍N xupNPu\@a}imqyisWC˵sR4I4xu$ ` +2/IƉHFwGXGfw<9YǙ9~y[C'M>d]T 'P 0l79z FQ5c6I:+xwRv8*ji30~G[ITG \P=0)/, )7;jx@*Dj5B!W`'iwwЂE 3 <ʤ?0EzCҢ sW]iwD'2'EHLPzp00 0'C3y:zW&zz|}G vrpOPqE{L j6:8:>#xʫޖ ٠#0 PP:p 0 jȪ;2|H؇Ǔ:?F`yp zzɺz.W!!2vʫ6Օt]M\@ p X i"8ˀ {y fzH)OsP6i-6dga5O1H#4گS9CN À '0 &ѬyCn pL'A9և6I0ẂJPaS[W۴)vugU8[)j;Pz EbFɠ 0 yÐ o~ Z[9zwG;wE@e9;K ۸YH0 ;ic }+~{V̀JSA X0 z X7ǫ˼X&Z9`#q*6ܻH VK%Ƞ XPEF# \l;`G&9 ɔܦ],1\Si#pB×2@"Dz@)ȬJ,Z \P\; j;`C`Й׃, r8"c8<"B?˭"G׊.lS[<l=|?8H@aEKΡKBH +m m[ʮA'R;zmB%&(Ȩ11ccCP9,|;-Ԯ\SQB7D-͊K-=ؚ2JCSg=\-AmAl:άcq-6. R0LA[*ׂ"п̄Q=؉EmgWy;ҶIٜqa6y՜!:<&˟ >"خMDL/ذgJm¬=9rAr[.}˵m;L4-OGM9ح\D-9"؊r)m- )BuIQ?}_-RNtaۧ8ܲ(kķ\#= AN(1b1Z-* 7"nrN5$U=2q˰A#=Hޱh&OQU)ASd'LzcnƈISimQ1E",UR,N.2#vG|.1Y. l~]lsa>5-Ѹ Δ:ڦm邮.I=NQ&~萾[n뎮%땳+NYL>꭮=YH-| $^NN]$H(gn4N>!U6xMZL^ =ެf1.4_敞W~G"Z~l>r\M%-ԃֆ,z!o~63-D߲FJ1guv͐,~DO?eJw&zMEz]OJRjKjDIb*QO'ptdAOMeë]HF@INO"P=JNFMDF/!_ֳKmp?T~r/do6R<ݤOް*ӌ5tOdP7;4(SĝO@ DPB >Q@Q\LREJ)P<֘¢rnjCϘA\SL5mބ9QN=}TODz gJ  )^ŚUV]~!+Sd#H.|3).bśWޮ>%GTJ ej]?Y/fbfG(l,)FZuF*eJiūmƝ[wc*Kx]s+ZJƻ?/`L #R;vݽ:xbQ0KYiW]s<[sIZ4 J;.tQ7TuF=Uyy ;,D3ڇ#;#:XV=2` b(W 7(/` 6H wGեYx%wOܜMf߭y^R5i7~H"5"xṅ ~ m  ~g&|:ꩫ:뭻º $ZoKZ4#j44v-gsfZfxA? l|ev;n/"Zۨ(,aкjF8Y9Ёʁ;L7A$UyB!appw8Xj|'H! @!|CX@ d \}A qGBpwTc|'؍jS, [a4,[ɥlȑwD4+F p$+C$ءpsPeh;h|` 0w #`!  IHC"Rt$ )IJZ; yH'$r|"9J,gx >Cmޑ /[; 'tB08>ȁۘ yNz@ N`,dIO9/uӝ].XҸ8) 1&MXNPP:Np IPP"ƅmMDV:ZJtNY{}}?RL_Td@=O_/4=!Qz [ђ .}mѢ{G}f='D&>1c ag's_O9S}rHN?,yղ?d5mȼIy+DWd7HSG'){uT -%*3QA5Ax~`ҩ[A['hA24t1uhxJ?˿[?k={&X7E+$+;$`'(.` Ӄ{I8\ HB/FB Қ+H|6.X~853J8>df&@$ܱj,H9Il1IDlA }D},O?2`./Āk{5ɤ`PaW8cEz J$0+{>zx 1Ljrʹː+P(Hr?$yI$ x`t&8TB:Ks?XQaHJLIlKkL$  ȜL,̻u" f 9#Y/Pl>#F"#mЇj=Q3`HtYNIb$#x%h4NpdIN}KCTG, bůĕ"Ѓ}f`.& %M YP@sYPBz݋݄D L  5/07#P33.ȃ#JԱ!5Rވ[@P0E *܋dpΝ;&!eH` Fvd8dDDV8J6 Fe_;ąf"lvcVSֿVN)X `a_gr^6ӘYIH!eXO}bfjbx$ES%$eT&BlV -fq%^EMjD}fR4BhiFef儆 @NNf]%= &A- YµW}bx\eQ癦ǛhWNan ~e hpj~ m@꫾A@uƷkj0h*nhvUŐ&q_ Z.WU ]60޽Ɩ@꾜lJ=kΞхU;މ]H=m]=i0mJiFۥMY]]^휬h^]}e6TmޡnU: ᶍQF&ݗk!\ eY;2 M\XbFLv轜_Em\wڲUO[FUGF|]Zuْm}mFfeg{M-qu٧U._7ٶ%U/ynkXqrm%rf?} /$ٻYM. Xr X&mo0opMXo&1ZrG67n {T ̮leNBZ&nI Цc7 pG?vaB 8:>ѓS9g͐<ɠ嗧@_ L$lmPR: HUVJ ` $Z"&c¥de$M$O%Q"%SZww% Z*[B&]R&^j&9ϳQzTB=xTa'p  ,x0a.tp"Ŋ/b̨q#ǎ? yDZ,(ș#-@H'/z<4 (#N"`K8pՌ*"E9BDk'v k'v8A"ۦSg|> %jRN լ[tزgӮmV0FV\LE)P>ϨsnjC͍"-Pٶk{a톯+fț )#O|9s?$GNe %f"udW{I ^åΨ "ۊZVYZXr,ADOu9^A} \6fVHQg50h.@11>pm=4n[-IqPNON[rIѥ.$ܗ^PhAs? 0uQLxxrlU`IDZZ)O!GlRri'z*gՠuDF:釖aVfUxveddo[,p)yR[mEE7]]Gu(hpL?\pE*C 5iTFD rQGO1Kѯ!K.KjD }P>)%Mѯ-M5ay[WIaDfL3uGM_ӏ?Z0 L"!`(lC  pAx\ߠ(pB4*2ρΑhͶpMxͷ߀ ^yHLV78Sne1+ ?j._pa{t+YvdwDŽ+L?['x%K"Zģ (y|FM$K)r$qazճ =O|3Ǿa~&g?=N,33Q j^B"Z02! khi!5PgL/ۙ/BuG(["X+Vъ!EnUibh*`\0%惉N2j\@S lQy(g; LB_$%(jg0AS6a [xB!XFP%U[Y łVNo)MJUR#d,5'2 !g~ 9N#!2fM~PQ%Cd@ьQ'b3#äVw##̉Nuӝe%멸{V0gsf@a9z+nb4%EN>x` L04!1]#`%-B)IRs*K]*Zd\i qZ$TGmpvh6SVѯ5?˄"ڧ LЗTb ^ SJyXMF#D+VUt`eʽڔ~J`zHhv"#ydHRhZځZ,aIGηwli_&1Bw+KIV`M BeKe#-o} \:X{Tq`"PM4@& ڏ Lk7pij@~shpQJm ,u੾22`7ƃq'bY=lGE =syaw߾/笍>3GVH}a!<\Ce+ FP#˯Uw91w"y7c^ؑ3Fd_iMV4໎l >;oWZ}9e%? e'XkO!R B樳sEbt_r_2mR[d(T=,<F>Tۍ\NUa| ZK18]T`}Uzkɠ`vdA\gAW] 2GGe9ϑ 8 4ځF!}VĝmUP QYaTx]5͝8jC aҖa!63yMhT!J1ҡN&rbX9]'b3xm+Hp`4W,k%өS0 Mc3*f v+:c5ZT"(]5#U%M0jb8c: JȞ>)G4DZ)4+V> @f٢(Wu=ą>D@8a1֔ H ZGZ}$FIU >'gH(~VcT e@dT EF$CZ$#Dc%HXlW‘$ra#g7*d U EfqLMV$CTC D֤XzeD$`&Ĥ%QS\V[IvWI\%S*TSI_ e`e^fa&fJY^fDTU20FD% XJIdnjGkOH^dR29mZnF`nsXn'`ne`*&c^>b_.q% ZuWnތESht h(Khz.IH˔Xjfd GJmNg]fwhd>%IMZvQ'tBqfQ&vs%u6hog1(uCqyB]=he\ }{"KChh{gP"3Ur\^'s(_i(tJsJ&=iF9wb"7>7<͋kbWVFM}Ԭ2M(ᬥ9e*fai^g^h`RinpFϖ"^bhv^)]hzѣLR l )&H(R^e z(pNhrX!"*e>6GbjYz^d*bfN%myFеbkjiґF"S~"$z1T(5W:( xB"raF&Öa6z)£ cBƊD~9,NJ,EeɉȪF䧸˒^gr&+l%$x*]962mF^-~a)6-z,@lj- mغ@ mHB֮lc+FF(a­z4B$Q҉(1j^@*f֦n.+Unbd0nVJ|n>nL%.j/e`A}?x2``Oop 7q7rr7stcK#.pLyzwzzw{{w||w}}w~~w xx#ZGm a` WXY,JdE%NOP DQER,ESx~n}ƋC9~9CӾ>>~>9ؾ> #;hѣ '}rGr]P?Ի_: pA/9?;|y9ӽ=9@;&8:լ[~ ;ٴk$KؔDG P =23\7㜳;G!ʧo3M>4aN>N 5RWMUVSREMMUTW%UQy=mrRյs0OCVcO0E%2q T>4Oޖ' _xS>G-1eN(@$iX ~pcrl30mV[u,flk[;XϾM\8?k{Km:=_C~{\\ln ZW7eFMrO O#ؕ,>u7\ġ=mGypN)(AyB:&!=^qx敲>/=Oz٫DY In(d>f:㛺=Zssv=sZz/٭u7k*V2Gx} {XB̺WXkPBY0q^lmOhTd%H"-P`Zf$~ j $fI-cz.|`"`Fa!^O6AYe2j#Δ r N.P@W 끬  ֺP( O 7ԐN( 0  A Ѱ Zpu(=ȡ0P i" vp`dAʟrfLAꠈЅ?Bخ yG BPJ{ !2) FCL$pq1jo D.FN  |o7G, L"@BIXSX5)Y/i&ja0#_XL [[5\u\ŵ\ \ Z ȵ]]5^`^^5_u__u!5^Z ObSN%V22GwH!'cK!v݌rW !YeQefɋ 2!agy:! .ĿF?Ch6ivi6iMDvjji5aakkk6lvlv4ʬ6m.*S #=6 x1NE [u"6vNXʔSHf9~0 $wrar n bDwta n4#*([ug2aawv]v%@F@wyww}ww7xwxWv-io a!w`nm4u4'e G{RpE{s\aha|||}շ}}7~W~w~~~~777~k8xx X)x-/1x)%wt[1Ȯ_$JG?pNӉ>GvaJWx3xEz}8x{v]~)~-^1]}ב^#5/^3[;IIWM ay}>~艾>~陾>~ꩾ>~빾1f:~ >~پ>~? ?wH!?%)-w~=A?EI^(HPhZ?Ocg`k_oy?}s퇟w?%-{]_m}?_~_ٿ?~wÿcw? \L  ,Xp!‡ .tbC%05N$ǏKfJ2%ƕ!YVɳϟ@ JѣH*]ʴӧPJ)4-8hA&9F)M;;ԙ֣Ddgx.MsS7ڼC8mᑅWxǐ#KL˘3z3@xٸ5Ɨm׺Ka.̭ulA'z}jMУKNfrd'>{vr[>7u>ۯq?{?~z1uh&`e?XgEUM-Tp)YL7\#&njbG(ֈ/^ⅻb@)DRVZqXGX9 TViXvA(iFih+ޱ)tix!!y*蠄j[ffw裐F*ӹhR馜vdw߁jꩨꘉbg`*무j+fr䭼di= r)mdjtQ+]sn1mfkD%ݨ^}e$|8o! n`G{WlG0 ;,`UZ*Dq0"6p᭧XwR؆!f}Xx#/nMkRe6,t v.i"Fo+z <ލ ]Mrl~5meSz[-H[)1-pkHp|pm㻊1?ެeKbNr' N /oҕCmpݺK, W Ǐz18gNyG3JXl2;n3(wN;{O>Hc~㊨|>y/oxGn/N-PH}I㞲)1iʂ ̠3#:Rm !ҪO WBupW- gx+8̡9@]i@ < HL$BPPdKpX̢n` #UdB]QhLC8=qpcmxF9Zb>F'lI vL"AHGD.L^=JZRd d/N됞 (}UE9rLVSED)_IZi0.wyF) k1_}e %$+֤~=u3EP:NkyFnuCK)F8<찹4M>7;ρ EԱFË)GSʹ1zԾz\ZT6~uD=RT"wA]Gusrנl^[ aS5dR%ySf^ivz>SDzr|BM 98kwvӢiwY=vuǶ)\5ȅR)Cs$GυRtK3ͮ2iNz&K>MzrC)K$ͯ}ѫW{KA/>n0[7LKΒ %CLV(F|eR.q$G,+6"3a0b )+]pLgzS#LtNW򓦉lJRg4eɓI3%6k@(8XHx8 H"X(x*h,-.08/X2h4x:<>?؃@8BXAxDFLNP؄QRzGR S[8Tȅ\](a(`f8iXgHh؆kjt8vȆw(xz؇nquȇH臊hx8Hxh8H؉؊(ȊHN Ȁ╋Q؋MxŸ8,p(=+X]Әh%Q pƀWJh PpG~(!q .'݈ PXw EpF }a IA}agFWNt$)8#w^ђ.} 8%ɍy8)~!(BC9FYHIJyKLNM9PIRYXyZiK)+@c)dyfeYaٖlnp9rYtyvxzٗ|~9Yy٘9YyٙIyk@ I niiy9IYyi9IYyi͙Ϲ9IYyiݙ߹9IYyi홞﹞9Iinʟh ڠmi*:ʡ#J$'&%Z١0 1* z :<; 9BZCz>ڣJ5*(ʢOڢ4*D**jPzQJLJ`:d*E [jlKgzNR_jUmeJ|pڡ}ʦoFG-. ::Zکʩک: ڪʪZz :*:ꫫ:* ʬ JȚӺj۪⊭:j:꺭j$@Zz:˯ K ˰ [ K{۱ +!#[(+{*K'k{{,[=;< 4˲A˳;?;J۱E;0>MHSkK8[I ,;knopflerfish-osgi-5.1.0/docs/images/kf300_black.png0000644000175000017500000001534612346515440021045 0ustar felixfelixPNG  IHDR,8/RtEXtCreation Time #!4]tIME 0?cr~ pHYsoddIDATx\XWצi,KAHEQc1TKl1&j1DD(EiҥH/ [إquYqg}=sΝy9;/ACA`+(PL3P@1Հ~l;;T#IY$ I{fg'9gP(¨xoO F+2I|Y@/ 散SWQO5M:ZW좰0y;b|I dNУ,?MV_΋  Y&6qg .5Y FF BnaBw#5$izY1(>".*@ xW;0L-vQ@@>_}ZSXPΆ#ɩi򵴴,^dejŵ}+UXy[ ccafC$pRRR""bߞ0FkQiuM eCi [sS#}]]" OPaeXSnjsssfn>uS--LaB]DV}eevi36q$MHAAAA[w@u$Ċcx9ӷB锿B͌w``p€r FU=] ~~6 tIHH_EEE]do=g;n^ޖS!!)96ߥ.͓N].:zCߍ ^"'p$̾Wg'Ge]HN\r Բt ruJb"HI:&'wvޏ~\VUCPe|=\@ȿk@2`FFFDd%Tnܽ?u?NLIIKw|}_mIJIdtg%!wDM^ Vq$_lX[H(j%2icS2Ԏ%=; v^6m$\d ܪOvr3_h`p|IM^IYQIx6H\GxOE'zqH0LКνr=ص $XG'y^5L~AT,,$had' e'$4vrm}C֋ҪIΫ 'b@?͖ QmdJ}ccIeUyM dej[U[$(, Jx99Y{dյuW- lգk.f3{yVUɚhi)xN\\HXLVVRQ 5>fo}J;ȡQ`̶'i(( 9)-M;gjgkR͐ՕzZF$5UU9,F݆/mΆ梲IlJ65v` -m%9y=:r^NPuu}ĥ+P%<1%L( [=A$<>cߚf@O&RWBB/QQR<+ؿx )--=W]Y-byn.veϙ&ɷOMcYЉ6MMx,vF'C_34_s<!mmmS$"nI5K{4,P2Yf}_8P355ȲM7)*_A G\/E3<\q a>u5JwAFvl(Փ22m媪Hˑ-j]v1AgHIKvo.$NK^ᠮcR/6m`47 IIJ)(*4=`iν8hki!oIZN]Q7<Ęc p5pYPUQ9{({׋&ikG#8/nZ{+++WU1c&Nom}wvv=A@o˦ A>&>> %$%mM/\W=|ٮ}}0x\rD8ANy֖]C(󂫃 DE54xV0A===QqO*Ĕ8<BJW0 0@cc#VRV4ꥁsg,kh}Vx-Y=KHJ+GBICO:Z}p$ 1Qf ;ڸ_l_~VAPw>&)yp" ey©y4AB|-4LBB֥ȱaww=N:ٟI:PQlXR#"8}v<Wlksln@l& vȅӞKV\wD1O=d瑺ԅk7G }.{yKˑfA|QQ[|y*.}I}ۂ@N; k~0A||ojjoܹ߈?|n_"<:I {Ơn|$3PR 3@oi4sq-HpGZMS3I9{/^C0rϑO- IM$n[’ME|:fyPh]Ax}jn`@o$-kXC*i/MY0u?2E K՟>/2K='HVWU Mimmuu5s*&1sURHَn.0eMIddd`a |\a @ @PyusMHl\V_OM zLMϳ+kjG'xGym]?2uymPi MaNz$mP%ht‚<'ADPRUc>ww7G+<~?)))mƋoqR/(fIˬaIHzE7Y>^.57o}w\tz7ge;mAjUޞ<3#=u4 ͔g\lQ6!DN yCU|/^p$3gj!5GG{G`QK]M[S:,odd 0IQi* E«եWnvJ7v|낷h\dQ+^GoX$Tﱍ6=dec/L[].848N9s,Xb'tY#JʧbihqͲ@xRtTțAK7?5ag\eΐ{O(VxhVBlUR7}8 ڰ=hx1L&*z2S? w'ӗLxq]$>iIBuo=OA^yКc_ ]>y=!)mmNn:G~=`gibM}uӆ ,yn\RJV:=IN7UsgKssFދ䈘xyĽxYv675$g ,ͧbFN :R/SSm]]v~ø'GL 8YI he r gIF 4{&zO<[ ëtPH L| GJCUHJꛚ !"鈡yB1xZ!*Hz>bۻȊy897T'Kq!^,}_B* 9Rb>dc&/|{,Kͅy0U`8>.N6_#b061:GDqF"EꕾڝwnVEbiF"Ϟur70QB&}돟F  GK&͕[IB|: 5uSOT y~: МĘ.w'DD|#@/>248ܤx h9@S-^~cî="Ɔ1'RFp,9HT݌bQ"D&Rك<8*/偦' ` `D_@_^V!!j*S?H,(Ŝi.+F6D1uIJuڼc׮(XY N*[7GF#:->2u4̕ḟ{!Ii;ES6-"#ז^dUW=e=ژM[1]6GGH"ښ n9}bK+1sAX߿W6b:l4k^f+Ϩ7x5+)*7nݪES: 9M31c]mEXP'#(HK-gӢ_bon޸y'6WlS^~ ~4]}g}z&8ٴVEIo(3^;u5"b3}݂48Ç?PKIJ 8s}t\. G"–Ɔ!/GĦ:9[vJ.\ljrKXJƭ(:[#OB2$b ÿ́`_GM_>Ov pS[ ׯƮI a݋R_os`PB13x89v x?!8#p-=Wx.ƌ5_߽x-45%)IpGޛ=Z dL1{U}GϲM[pmɁ_ IŃvfpgb_{@̌x8+Nl(!.=yҍ8s 35~6`hd$H.wi^1@њp( $#)qԬ'N?@F\lÂYjj/]h8z<{z!;Qz]]5'# ͍:Nh4yBS -2X;eM+6m#dd0Zov6Sg%arŐa{V7<MYL0 G(@¡>^~>g.]I8rK#!<(m3-ۇz/I`9: F{;kqqs>yz=Q7L3 Pٕv?uϾ?k'fQ0 ,Lo߿6-&F(_L0:O8 FL8 FOKXIENDB`knopflerfish-osgi-5.1.0/docs/jars/0000755000175000017500000000000012475375714016054 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/junit_runner/0000755000175000017500000000000012475375714020576 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/junit_runner/junit_runner_all-4.0.0.html0000644000175000017500000001164012346515430025461 0ustar felixfelix junit_runner_all-4.0.0.jar

junit_runner_all-4.0.0.jar

OSGi manifest attributes
Bundle-Name JUnitRunner
Bundle-SymbolicName org.knopflerfish.bundle.junit_runner
Bundle-Version 4.0.0
Bundle-Description Grunt, the JUnit test runner. Runs JUnit tests registered in the framework and dumps results to XML files.
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL https://www.knopflerfish.org/svn/knopflerfish.org/trunk/osgi/bundles_opt/junit/junit_runner/readme.txt
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.junit_runner.Activator
Bundle-Classpath .
Export-Package
Import-Package junit.framework 0.0.0
org.knopflerfish.service.junit 0.0.0
org.osgi.framework 0.0.0
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:11
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/junit/junit_runner
Bundle-Category testing
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/junit/junit_runner/
Bundle-UUID org.knopflerfish:junit_runner:4.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

junit_all-3.8.1.kf4-001junit.framework, org.knopflerfish.service.junit
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/junit_runner/Activator.java
org/knopflerfish/bundle/junit_runner/Grunt.java
knopflerfish-osgi-5.1.0/docs/jars/style.css0000644000175000017500000000645412346515430017723 0ustar felixfelixBODY { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:11px; color:000000; text-align:left; font-weight:normal; background:#fff; } TD { font-family: Verdana, Arial, Helvetica, sans-serif; text-align:left; vertical-align:top; font-size:11px; } TD A { color:000000; text-decoration:none font-size:11px; } .mfheader { font-family: Verdana, Arial, Helvetica, sans-serif; text-align:left; vertical-align:top; font-size:11px; font-weight:bold; /* background: #805362; */ color: #fff; padding-top: 4px; padding-bottom: 4px; /* text-align: center; */ border-style: solid; border-color: #999999; background-color: #dedede; border-width: 1px; color: #444444; padding-left: 10px; } TH { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:11px; color:000000; text-align:left; vertical-align:top; font-weight:bold } TD A { color:000000; text-decoration:none font-size:11px; } PRE { font-family: Courier New, Courier; font-size:11px; color:000000; text-align:left; font-weight:normal; } H1 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:19px; font-weight:bold; /* background: #dddddd; */ } H3 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:13px; font-weight:bold; background: #805362; color: #fff; padding: 2px 0px 2px 3px; } H4 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:11px; font-weight:bold; background: #805362; color: #fff; padding: 2px 0px 2px 10px; border-style: solid; border-color: #999999; background-color: #dedede; border-width: 1px; color: #444444; } H5 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:9px; font-weight:bold; background: #805362; color: #fff; padding: 2px 0px 2px 3px; } H6 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size:7px; font-weight:bold } TD.menu { color: #ffffff; font-size:9px; font-weight:bold; text-align:left; } A.top { float: right; text-decoration: none; font-weight: bold; } A, A:visited, A:selected, A:active { color:000000; text-decoration: none; font-weight: bold; } A:hover { text-decoration: underline; } li.A:visited, li.A:selected, li.A:active { text-decoration: none; font-weight: bold; } li.A:hover { text-decoration: underline; } .small { font-size:9px; } .medium { font-size:13px; } .big { font-size:17px; } .ghosted { color: #888888; } .framed { border-type: solid; border-top: 1px solid; border-left: 1px solid; border-bottom: 1px solid; border-right: 1px solid; background:#eeeeee; border-color:#000000; padding-left: 2; padding-top: 2; padding-bottom: 2; padding-right: 2; text-decoration:none; font-size: 11px; } .boxed { border-type: solid; border-top: 1px solid; border-left: 1px solid; border-bottom: 1px solid; border-right: 1px solid; background:#E7DBAD; border-color:#000000; padding-left: 2; padding-top: 1; padding-bottom: 2; padding-right: 2; text-decoration:none; float: left; } dt { font-weight:bold; margin-bottom: 5px; } dd { margin-bottom: 5px; } knopflerfish-osgi-5.1.0/docs/jars/kf_metatype/0000755000175000017500000000000012475375714020364 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/kf_metatype/kf_metatype_all-5.0.2.html0000644000175000017500000003024112346515430025036 0ustar felixfelix kf_metatype_all-5.0.2.jar

kf_metatype_all-5.0.2.jar

download (123656 bytes)

OSGi manifest attributes
Bundle-Name KF-XML-Metatype
Bundle-SymbolicName org.knopflerfish.bundle.kf_metatype
Bundle-Version 5.0.2
Bundle-Description XML format support for CM and Metatype
Bundle-Vendor Knopflerfish,nanoxml
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.metatype.Activator
Bundle-Classpath .,nanoxml-2.2.1.jar
Export-Package net.n3.nanoxml 2.2.1
org.knopflerfish.util.metatype 0.0.0
Import-Package net.n3.nanoxml [2.2.1,3.0.0)
org.knopflerfish.service.log [1.2.0,2.0.0)
org.knopflerfish.util 0.0.0
org.knopflerfish.util.metatype 0.0.0
org.kxml2.io 0.0.0
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.metatype [1.2.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
org.xmlpull.v1 0.0.0
Dynamic-ImportPackage
Provide-Capability osgi.service; objectClass:List="org.osgi.service.metatype.MetaTypeService",osgi.service; objectClass:List="org.knopflerfish.util.metatype.SystemMetatypeProvider",osgi.service; objectClass:List="org.osgi.service.cm.ManagedService"; service.pid:String="org.knopflerfish.util.metatype.SystemMetatypeProvider",osgi.service; objectClass:List="org.osgi.service.cm.ManagedService"; service.pid:String="java.system.properties"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:32
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/metatype/kf_metatype
Bundle-APIVendor Knopflerfish
Bundle-Category utility
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/metatype/kf_metatype/
Bundle-UUID org.knopflerfish:kf_metatype:5.0.2
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.knopflerfish.util, org.osgi.service.cm
http_all-4.0.5org.knopflerfish.service.log
kf_metatype_all-5.0.2net.n3.nanoxml, org.knopflerfish.util.metatype
kxml-2.3.0.kf4-001org.kxml2.io, org.xmlpull.v1
metatype-4.0.0org.osgi.service.metatype
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
util-4.1.0org.knopflerfish.util
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

cm_desktop_all-5.0.2org.knopflerfish.util.metatype
cm_desktop-5.0.2org.knopflerfish.util.metatype
kf_metatype_all-5.0.2net.n3.nanoxml, org.knopflerfish.util.metatype

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/metatype/Activator.java
org/knopflerfish/util/metatype/AD.java
org/knopflerfish/util/metatype/AE.java
org/knopflerfish/util/metatype/BundleMetaTypeInformationSnapshot.java
org/knopflerfish/util/metatype/BundleMetaTypeResource.java
org/knopflerfish/util/metatype/KFLegacyMetaTypeParser.java
org/knopflerfish/util/metatype/Loader.java
org/knopflerfish/util/metatype/MTP.java
org/knopflerfish/util/metatype/OCD.java
org/knopflerfish/util/metatype/OsgiMetaTypeXmlParser.java
org/knopflerfish/util/metatype/SystemMetatypeProvider.java
knopflerfish-osgi-5.1.0/docs/jars/desktop_jvm/0000755000175000017500000000000012475375714020401 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/desktop_jvm/desktop_jvm-1.0.0.html0000644000175000017500000001547312346515426024251 0ustar felixfelix desktop_jvm-1.0.0.jar

desktop_jvm-1.0.0.jar

download (14486 bytes)

OSGi manifest attributes
Bundle-Name desktop_jvm-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.desktop_jvm-IMPL
Bundle-Version 1.0.0
Bundle-Description JVM info desktop plugin (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.desktop.jvminfo.Activator
Bundle-Classpath .
Export-Package
Import-Package javax.swing 0.0.0
javax.swing.border 0.0.0
org.knopflerfish.service.desktop 0.0.0
org.knopflerfish.service.log 0.0.0
org.osgi.framework 0.0.0
Dynamic-ImportPackage
Provide-Capability
Require-Capability
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:31
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/desktop_displayers/desktop_jvm
Bundle-Category service
Bundle-UUID org.knopflerfish:desktop_jvm:1.0.0:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.desktop, org.knopflerfish.service.log
desktop_api-5.0.1org.knopflerfish.service.desktop
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/desktop/jvminfo/Activator.java
org/knopflerfish/bundle/desktop/jvminfo/DefaultSwingBundleDisplayer.java
org/knopflerfish/bundle/desktop/jvminfo/JGraph.java
org/knopflerfish/bundle/desktop/jvminfo/JVMDisplayer.java
knopflerfish-osgi-5.1.0/docs/jars/desktop_jvm/desktop_jvm_all-1.0.0.html0000644000175000017500000001546112346515426025076 0ustar felixfelix desktop_jvm_all-1.0.0.jar

desktop_jvm_all-1.0.0.jar

download (14473 bytes)

OSGi manifest attributes
Bundle-Name desktop_jvm
Bundle-SymbolicName org.knopflerfish.bundle.desktop_jvm
Bundle-Version 1.0.0
Bundle-Description JVM info desktop plugin
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.desktop.jvminfo.Activator
Bundle-Classpath .
Export-Package
Import-Package javax.swing 0.0.0
javax.swing.border 0.0.0
org.knopflerfish.service.desktop 0.0.0
org.knopflerfish.service.log 0.0.0
org.osgi.framework 0.0.0
Dynamic-ImportPackage
Provide-Capability
Require-Capability
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:31
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/desktop_displayers/desktop_jvm
Bundle-Category service
Bundle-UUID org.knopflerfish:desktop_jvm:1.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.desktop, org.knopflerfish.service.log
desktop_api-5.0.1org.knopflerfish.service.desktop
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/desktop/jvminfo/Activator.java
org/knopflerfish/bundle/desktop/jvminfo/DefaultSwingBundleDisplayer.java
org/knopflerfish/bundle/desktop/jvminfo/JGraph.java
org/knopflerfish/bundle/desktop/jvminfo/JVMDisplayer.java
knopflerfish-osgi-5.1.0/docs/jars/subsystem/0000755000175000017500000000000012475375714020112 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/subsystem/subsystem_api-1.0.0.html0000644000175000017500000001345412346515430024314 0ustar felixfelix subsystem_api-1.0.0.jar

subsystem_api-1.0.0.jar

download (12485 bytes)

OSGi manifest attributes
Bundle-Name Subsystem-API
Bundle-SymbolicName org.knopflerfish.bundle.subsystem-API
Bundle-Version 1.0.0
Bundle-Description OSGi specified subsytem service (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.subsystem 1.0.0
Import-Package org.osgi.framework [1.7.0,2.0.0)
org.osgi.service.subsystem [1.0.0,1.1.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=1.5))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:07
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/subsystem
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/subsystem/
Bundle-UUID org.knopflerfish:subsystem:1.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

subsystem_api-1.0.0org.osgi.service.subsystem
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

subsystem_api-1.0.0org.osgi.service.subsystem

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/subsystem/Subsystem.java
org/osgi/service/subsystem/SubsystemConstants.java
org/osgi/service/subsystem/SubsystemException.java
org/osgi/service/subsystem/SubsystemPermission.java
org/osgi/service/subsystem/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/device/0000755000175000017500000000000012475375714017313 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/device/device-4.0.1.html0000644000175000017500000001735612346515426022103 0ustar felixfelix device-4.0.1.jar

device-4.0.1.jar

download (17731 bytes)

OSGi manifest attributes
Bundle-Name Device-Manager-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.device-IMPL
Bundle-Version 4.0.1
Bundle-Description Device manager (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.device.Activator
Bundle-Classpath .
Export-Package
Import-Package org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.device [1.1.0,1.2.0)
org.osgi.service.log [1.2.0,3.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:27
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/device/device
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/device/device/
Bundle-UUID org.knopflerfish:device:4.0.1:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.osgi.service.log
desktop_all-5.0.1org.osgi.service.log
device_all-4.0.1org.osgi.service.device
device_api-4.0.1org.osgi.service.device
frameworkorg.osgi.framework
log_all-5.0.0org.osgi.service.log
log_api-5.0.0org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/device/Activator.java
org/knopflerfish/bundle/device/DriverRef.java
org/knopflerfish/bundle/device/MatchImpl.java
org/knopflerfish/bundle/device/MatchValue.java
org/osgi/service/device/Constants.java
org/osgi/service/device/Device.java
org/osgi/service/device/Driver.java
org/osgi/service/device/DriverLocator.java
org/osgi/service/device/DriverSelector.java
org/osgi/service/device/Match.java
org/osgi/service/device/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/device/device_api-4.0.1.html0000644000175000017500000002064112346515426022723 0ustar felixfelix device_api-4.0.1.jar

device_api-4.0.1.jar

download (3450 bytes)

OSGi manifest attributes
Bundle-Name Device-Manager-API
Bundle-SymbolicName org.knopflerfish.bundle.device-API
Bundle-Version 4.0.1
Bundle-Description Device manager (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.device 1.1.0
Import-Package org.osgi.framework 0.0.0
org.osgi.service.device [1.1.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:27
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/device/device
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/device/device/
Bundle-UUID org.knopflerfish:device:4.0.1:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

device_all-4.0.1org.osgi.service.device
device_api-4.0.1org.osgi.service.device
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

basicdriverlocator_all-4.0.0org.osgi.service.device
basicdriverlocator-4.0.0org.osgi.service.device
device_all-4.0.1org.osgi.service.device
device_api-4.0.1org.osgi.service.device
device-4.0.1org.osgi.service.device
serialportdevice_all-4.0.0org.osgi.service.device
serialportdevice_api-4.0.0org.osgi.service.device

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/device/Activator.java
org/knopflerfish/bundle/device/DriverRef.java
org/knopflerfish/bundle/device/MatchImpl.java
org/knopflerfish/bundle/device/MatchValue.java
org/osgi/service/device/Constants.java
org/osgi/service/device/Device.java
org/osgi/service/device/Driver.java
org/osgi/service/device/DriverLocator.java
org/osgi/service/device/DriverSelector.java
org/osgi/service/device/Match.java
org/osgi/service/device/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/device/device_all-4.0.1.html0000644000175000017500000002263412346515426022726 0ustar felixfelix device_all-4.0.1.jar

device_all-4.0.1.jar

download (20333 bytes)

OSGi manifest attributes
Bundle-Name Device-Manager
Bundle-SymbolicName org.knopflerfish.bundle.device
Bundle-Version 4.0.1
Bundle-Description Device manager
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.device.Activator
Bundle-Classpath .
Export-Package org.osgi.service.device 1.1.0
Import-Package org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.device [1.1.0,1.2.0)
org.osgi.service.log [1.2.0,3.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:27
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/device/device
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/device/device/
Bundle-UUID org.knopflerfish:device:4.0.1
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.osgi.service.log
desktop_all-5.0.1org.osgi.service.log
device_all-4.0.1org.osgi.service.device
device_api-4.0.1org.osgi.service.device
frameworkorg.osgi.framework
log_all-5.0.0org.osgi.service.log
log_api-5.0.0org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

basicdriverlocator_all-4.0.0org.osgi.service.device
basicdriverlocator-4.0.0org.osgi.service.device
device_all-4.0.1org.osgi.service.device
device_api-4.0.1org.osgi.service.device
device-4.0.1org.osgi.service.device
serialportdevice_all-4.0.0org.osgi.service.device
serialportdevice_api-4.0.0org.osgi.service.device

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/device/Activator.java
org/knopflerfish/bundle/device/DriverRef.java
org/knopflerfish/bundle/device/MatchImpl.java
org/knopflerfish/bundle/device/MatchValue.java
org/osgi/service/device/Constants.java
org/osgi/service/device/Device.java
org/osgi/service/device/Driver.java
org/osgi/service/device/DriverLocator.java
org/osgi/service/device/DriverSelector.java
org/osgi/service/device/Match.java
org/osgi/service/device/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/package_list.html0000644000175000017500000011264312346515430021363 0ustar felixfelix Knopflerfish Bundle Packages
PackageProvider(s)
gnu.io 2.0.0comm-linux_all-3.0.0
gnu.io 2.2.0rxtxcomm_api-2.2.0.pre2
javax.comm 2.0.0comm-linux_all-3.0.0
comm-win32_all-3.0.0
javax.microedition.io 0.0.0io_all-4.0.0
io_api-4.0.0
javax.servlet 2.5.0jsdk_api-2.5.0.kf3-2
javax.servlet.http 2.5.0jsdk_api-2.5.0.kf3-2
javax.xml 1.3.0xerces-2.10.1.kf5
javax.xml.datatype 1.3.0xerces-2.10.1.kf5
javax.xml.namespace 1.3.0xerces-2.10.1.kf5
javax.xml.parsers 1.2.0crimson-2.1.0.kf4-001
javax.xml.parsers 1.3.0xerces-2.10.1.kf5
javax.xml.transform 1.3.0xerces-2.10.1.kf5
javax.xml.transform 1.3.0.selectFirstxalan-2.7.1.kf3_01
javax.xml.transform.dom 1.3.0xerces-2.10.1.kf5
javax.xml.transform.dom 1.3.0.selectFirstxalan-2.7.1.kf3_01
javax.xml.transform.sax 1.3.0xerces-2.10.1.kf5
javax.xml.transform.sax 1.3.0.selectFirstxalan-2.7.1.kf3_01
javax.xml.transform.stream 1.3.0xerces-2.10.1.kf5
javax.xml.transform.stream 1.3.0.selectFirstxalan-2.7.1.kf3_01
javax.xml.validation 1.3.0xerces-2.10.1.kf5
javax.xml.xpath 1.3.0xerces-2.10.1.kf5
junit.framework 3.8.1junit_all-3.8.1.kf4-001
net.jini.admin 0.0.0jinidriver_all-0.1.0
net.jini.core.discovery 0.0.0jinidriver_all-0.1.0
net.jini.core.entry 0.0.0jinidriver_all-0.1.0
net.jini.core.event 0.0.0jinidriver_all-0.1.0
net.jini.core.lease 0.0.0jinidriver_all-0.1.0
net.jini.core.lookup 0.0.0jinidriver_all-0.1.0
net.jini.discovery 0.0.0jinidriver_all-0.1.0
net.jini.lease 0.0.0jinidriver_all-0.1.0
net.jini.lookup 0.0.0jinidriver_all-0.1.0
net.jini.lookup.entry 0.0.0jinidriver_all-0.1.0
net.n3.nanoxml 2.2.1kf_metatype_all-5.0.2
org.apache.commons.logging 1.0.3commons-logging_all-2.0.0.kf4-001
org.apache.crimson.jaxp 0.0.0crimson-2.1.0.kf4-001
org.apache.felix.scr 1.6.0component_all-5.0.3
component_api-5.0.3
desktop_all-5.0.1
org.apache.html.dom 0.0.0xerces-2.10.1.kf5
org.apache.wml 0.0.0xerces-2.10.1.kf5
org.apache.wml.dom 0.0.0xerces-2.10.1.kf5
org.apache.xalan 0.0.0xalan-2.7.1.kf3_01
org.apache.xalan.processor 0.0.0xalan-2.7.1.kf3_01
org.apache.xerces.dom 0.0.0xerces-2.10.1.kf5
org.apache.xerces.dom.events 0.0.0xerces-2.10.1.kf5
org.apache.xerces.dom3.as 0.0.0xerces-2.10.1.kf5
org.apache.xerces.jaxp 0.0.0xerces-2.10.1.kf5
org.apache.xerces.jaxp.datatype 0.0.0xerces-2.10.1.kf5
org.apache.xerces.jaxp.validation 0.0.0xerces-2.10.1.kf5
org.apache.xerces.parsers 0.0.0xerces-2.10.1.kf5
org.apache.xerces.util 0.0.0xerces-2.10.1.kf5
org.apache.xerces.xinclude 0.0.0xerces-2.10.1.kf5
org.apache.xerces.xni 0.0.0xerces-2.10.1.kf5
org.apache.xerces.xni.grammars 0.0.0xerces-2.10.1.kf5
org.apache.xerces.xni.parser 0.0.0xerces-2.10.1.kf5
org.apache.xerces.xpointer 0.0.0xerces-2.10.1.kf5
org.apache.xerces.xs 0.0.0xerces-2.10.1.kf5
org.apache.xerces.xs.datatypes 0.0.0xerces-2.10.1.kf5
org.apache.xml.resolver 1.2.0xerces-2.10.1.kf5
org.apache.xml.resolver.apps 1.2.0xerces-2.10.1.kf5
org.apache.xml.resolver.helpers 1.2.0xerces-2.10.1.kf5
org.apache.xml.resolver.readers 1.2.0xerces-2.10.1.kf5
org.apache.xml.resolver.tools 1.2.0xerces-2.10.1.kf5
org.apache.xml.serialize 0.0.0xerces-2.10.1.kf5
org.apache.xml.serializer 1.0.0xerces-2.10.1.kf5
org.apache.xpath.jaxp 0.0.0xalan-2.7.1.kf3_01
org.knopflerfish.service.console 2.1.2console_all-4.0.1
console_api-4.0.1
desktop_all-5.0.1
org.knopflerfish.service.desktop 2.2.0desktop_all-5.0.1
desktop_api-5.0.1
org.knopflerfish.service.dirdeployer 0.0.0dirdeployer_all-4.0.1
dirdeployer_api-4.0.1
org.knopflerfish.service.junit 1.0.0junit_all-3.8.1.kf4-001
org.knopflerfish.service.log 1.2.0commons-logging_all-2.0.0.kf4-001
desktop_all-5.0.1
http_all-4.0.5
useradmin_all-4.1.1
useradmin-4.1.1
log_all-5.0.0
log_api-5.0.0
org.knopflerfish.service.remotefw 0.0.0desktop_all-5.0.1
remotefw_api-4.0.0
org.knopflerfish.service.repository 1.0.0repository_xml_all-1.0.2
repository_xml_api-1.0.2
org.knopflerfish.service.repositorymanager 1.2.0repositorymanager_all-1.2.0
repositorymanager_api-1.2.0
org.knopflerfish.service.serial 0.0.0serialportdevice_all-4.0.0
serialportdevice_api-4.0.0
org.knopflerfish.service.um.ipam 1.0.0useradmin_all-4.1.1
useradmin_api-4.1.1
org.knopflerfish.service.um.useradmin 1.0.0useradmin_all-4.1.1
useradmin_api-4.1.1
org.knopflerfish.shared.cm 1.1.0cm_all-5.0.1
cm-5.0.1
cm_desktop_all-5.0.2
dirdeployer_all-4.0.1
org.knopflerfish.util 1.1.0desktop_all-5.0.1
util-4.1.0
org.knopflerfish.util.framework 1.0.0desktop_all-5.0.1
util-4.1.0
org.knopflerfish.util.metatype 0.0.0kf_metatype_all-5.0.2
org.knopflerfish.util.sort 1.0.0desktop_all-5.0.1
util-4.1.0
org.knopflerfish.util.workerthread 1.0.0desktop_all-5.0.1
util-4.1.0
org.kxml2.io 0.0.0kxml-2.3.0.kf4-001
org.kxml2.kdom 0.0.0kxml-2.3.0.kf4-001
org.kxml2.wap 0.0.0kxml-2.3.0.kf4-001
org.kxml2.wap.syncml 0.0.0kxml-2.3.0.kf4-001
org.kxml2.wap.wml 0.0.0kxml-2.3.0.kf4-001
org.kxml2.wap.wv 0.0.0kxml-2.3.0.kf4-001
org.osgi.application 1.0.0foreignapplication_api-4.0.0
org.osgi.framework 1.7.0framework
org.osgi.framework.hooks.bundle 1.1.0framework
org.osgi.framework.hooks.resolver 1.0.0framework
org.osgi.framework.hooks.service 1.1.0framework
org.osgi.framework.hooks.weaving 1.0.0framework
org.osgi.framework.launch 1.1.0framework
org.osgi.framework.namespace 1.0.0framework
org.osgi.framework.startlevel 1.0.0framework
org.osgi.framework.wiring 1.1.0framework
org.osgi.namespace.contract 1.0.0namespace_api-1.0.0
org.osgi.namespace.extender 1.0.0namespace_api-1.0.0
org.osgi.namespace.service 1.0.0namespace_api-1.0.0
org.osgi.resource 1.0.0framework
org.osgi.service.application 1.1.0applicationadmin_api-4.0.0
org.osgi.service.blueprint.container 1.0.2blueprint_api-5.0.0
org.osgi.service.blueprint.reflect 1.0.1blueprint_api-5.0.0
org.osgi.service.cm 1.5.0cm_all-5.0.1
cm_api-5.0.1
desktop_all-5.0.1
org.osgi.service.command 1.0.0command_all-0.2
command_api-0.2
org.osgi.service.component 1.2.1component_all-5.0.3
component_api-5.0.3
desktop_all-5.0.1
org.osgi.service.component.annotations 1.2.0component_annotations_api-1.0.0
org.osgi.service.condpermadmin 1.1.1framework
org.osgi.service.coordinator 1.0.1coordinator_api-1.0.0
org.osgi.service.deploymentadmin 1.1.0deploymentadmin_api-4.0.0
org.osgi.service.deploymentadmin.spi 1.0.1deploymentadmin_api-4.0.0
org.osgi.service.device 1.1.0device_all-4.0.1
device_api-4.0.1
org.osgi.service.dmt 2.0.1dmt_api-5.0.0
org.osgi.service.dmt.notification 2.0.0dmt_api-5.0.0
org.osgi.service.dmt.notification.spi 2.0.0dmt_api-5.0.0
org.osgi.service.dmt.security 2.0.0dmt_api-5.0.0
org.osgi.service.dmt.spi 2.0.0dmt_api-5.0.0
org.osgi.service.event 1.3.0desktop_all-5.0.1
event_all-4.0.1
event_api-4.0.1
org.osgi.service.http 1.2.1http_all-4.0.5
http_api-4.0.5
org.osgi.service.indexer 1.0.2repoindex_kf_all-1.0.1
org.osgi.service.io 1.0.0io_all-4.0.0
io_api-4.0.0
org.osgi.service.jini 1.0.0jinidriver_all-0.1.0
org.osgi.service.log 1.3.0commons-logging_all-2.0.0.kf4-001
desktop_all-5.0.1
log_all-5.0.0
log_api-5.0.0
org.osgi.service.metatype 1.2.0metatype-4.0.0
org.osgi.service.monitor 1.0.0monitor_api-4.0.0
org.osgi.service.packageadmin 1.2.0framework
org.osgi.service.permissionadmin 1.2.0framework
org.osgi.service.prefs 1.1.1desktop_all-5.0.1
prefs_all-4.0.2
prefs_api-4.0.2
org.osgi.service.provisioning 1.2.0provisioning_api-4.0.0
org.osgi.service.remoteserviceadmin 1.0.1remoteserviceadmin_api-1.0.0
org.osgi.service.repository 1.0.0repository_api-1.0.0
repositorymanager_all-1.2.0
org.osgi.service.resolver 1.0.1repositorymanager_all-1.2.0
resolver_api-1.0.0
org.osgi.service.serviceloader 1.0.0serviceloader_api-1.0.0
org.osgi.service.startlevel 1.1.0framework
org.osgi.service.subsystem 1.0.0subsystem_api-1.0.0
org.osgi.service.threadio 1.0.0threadio_all-0.2.0
threadio_api-0.2.0
org.osgi.service.upnp 1.2.0upnp_api-4.0.0
org.osgi.service.url 1.0.0framework
org.osgi.service.useradmin 1.1.0useradmin_all-4.1.1
useradmin_api-4.1.1
org.osgi.service.wireadmin 1.0.1wireadmin_api-5.0.0
org.osgi.util.measurement 1.0.1measurement-4.0.0
org.osgi.util.position 1.0.1position-4.0.0
org.osgi.util.tracker 1.5.1framework
org.osgi.util.xml 1.0.1xerces-2.10.1.kf5
xml-4.0.0
org.w3c.dom 2.0.0crimson-2.1.0.kf4-001
org.w3c.dom 3.0.0xerces-2.10.1.kf5
org.w3c.dom.bootstrap 3.0.0xerces-2.10.1.kf5
org.w3c.dom.css 3.0.0xerces-2.10.1.kf5
org.w3c.dom.events 3.0.0xerces-2.10.1.kf5
org.w3c.dom.html 3.0.0xerces-2.10.1.kf5
org.w3c.dom.ls 3.0.0xerces-2.10.1.kf5
org.w3c.dom.ranges 3.0.0xerces-2.10.1.kf5
org.w3c.dom.stylesheets 3.0.0xerces-2.10.1.kf5
org.w3c.dom.traversal 3.0.0xerces-2.10.1.kf5
org.w3c.dom.views 3.0.0xerces-2.10.1.kf5
org.w3c.dom.xpath 3.0.0xerces-2.10.1.kf5
org.xml.sax 2.0.0crimson-2.1.0.kf4-001
org.xml.sax 2.0.2xerces-2.10.1.kf5
org.xml.sax.ext 1.0.0crimson-2.1.0.kf4-001
org.xml.sax.ext 2.0.2xerces-2.10.1.kf5
org.xml.sax.helpers 2.0.0crimson-2.1.0.kf4-001
org.xml.sax.helpers 2.0.2xerces-2.10.1.kf5
org.xmlpull.v1 1.1.3.1kxml-2.3.0.kf4-001
knopflerfish-osgi-5.1.0/docs/jars/sslj2sp/0000755000175000017500000000000012475375714017454 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/sslj2sp/sslj2sp-4.0.0.html0000644000175000017500000001460612346515430022372 0ustar felixfelix sslj2sp-4.0.0.jar

sslj2sp-4.0.0.jar

download (17994 bytes)

OSGi manifest attributes
Bundle-Name sslj2sp-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.sslj2sp-IMPL
Bundle-Version 4.0.0
Bundle-Description SSL Provider using the Java 2 security architecture. (IMPL)
Bundle-Vendor Knopflerfish/Oscar
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL https://www.knopflerfish.org/svn/knopflerfish.org/trunk/osgi/bundles/sslj2sp/readme.txt
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.ssl.j2sp.Activator
Bundle-Classpath .
Export-Package
Import-Package javax.net.ssl 0.0.0
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=1.4))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:51
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/sslj2sp
Bundle-Category service
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/sslj2sp/
Bundle-UUID org.knopflerfish:sslj2sp:4.0.0:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.osgi.service.log
desktop_all-5.0.1org.osgi.service.cm, org.osgi.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.osgi.service.log
log_api-5.0.0org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/ssl/j2sp/Activator.java
org/knopflerfish/bundle/ssl/j2sp/ConstsIf.java
org/knopflerfish/bundle/ssl/j2sp/SslServiceFactory.java
org/knopflerfish/bundle/ssl/j2sp/SslServiceWrapper.java
knopflerfish-osgi-5.1.0/docs/jars/repoindex_kf/0000755000175000017500000000000012475375714020531 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/repoindex_kf/repoindex_kf_all-1.0.1.html0000644000175000017500000001567312346515430025357 0ustar felixfelix repoindex_kf_all-1.0.1.jar

repoindex_kf_all-1.0.1.jar

download (19638 bytes)

OSGi manifest attributes
Bundle-Name KF Resource Analyzer Extensions
Bundle-SymbolicName org.knopflerfish.bundle.repository.index
Bundle-Version 1.0.1
Bundle-Description KF Resource Analyzer Extensions
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.repository.index.Activator
Bundle-Classpath .
Export-Package org.osgi.service.indexer 1.0.2
Import-Package org.osgi.framework 0.0.0
org.osgi.service.indexer [1.0.2,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=1.5))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:00
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/repository/repoindex_kf
Bundle-Category utility
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/repository/
Bundle-UUID org.knopflerfish:repoindex_kf:1.0.1
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

repoindex_kf_all-1.0.1org.osgi.service.indexer
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

repoindex_kf_all-1.0.1org.osgi.service.indexer

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/repository/index/Activator.java
org/knopflerfish/bundle/repository/index/KnopflerfishExtentions.java
org/knopflerfish/bundle/repository/index/Util.java
org/osgi/service/indexer/Builder.java
org/osgi/service/indexer/Capability.java
org/osgi/service/indexer/Namespaces.java
org/osgi/service/indexer/Requirement.java
org/osgi/service/indexer/Resource.java
org/osgi/service/indexer/ResourceAnalyzer.java
org/osgi/service/indexer/ResourceIndexer.java
knopflerfish-osgi-5.1.0/docs/jars/xalan/0000755000175000017500000000000012475375714017157 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/xalan/xalan-2.7.1.kf3_01.html0000644000175000017500000001501012346515430022556 0ustar felixfelix xalan-2.7.1.kf3_01.jar

xalan-2.7.1.kf3_01.jar

download (1804820 bytes)

OSGi manifest attributes
Bundle-Name Xalan
Bundle-SymbolicName org.knopflerfish.bundle.xalan
Bundle-Version 2.7.1.kf3_01
Bundle-Description The Apache Xalan-Java XML transformer
Bundle-Vendor Apache/Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=xalan/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.osgi.util.xml.XMLTransformerActivator
Bundle-Classpath .,xml-apis.jar,xalan.jar
Export-Package javax.xml.transform 1.3.0.selectFirst
javax.xml.transform.dom 1.3.0.selectFirst
javax.xml.transform.sax 1.3.0.selectFirst
javax.xml.transform.stream 1.3.0.selectFirst
org.apache.xalan 0.0.0
org.apache.xalan.processor 0.0.0
org.apache.xpath.jaxp 0.0.0
Import-Package javax.naming 0.0.0
javax.xml.namespace 1.3.0
javax.xml.parsers 1.3.0
javax.xml.transform 1.3.0
javax.xml.transform.dom 1.3.0
javax.xml.transform.sax 1.3.0
javax.xml.transform.stream 1.3.0
javax.xml.xpath 1.3.0
org.apache.xalan 0.0.0
org.apache.xalan.processor 0.0.0
org.apache.xerces.parsers 0.0.0
org.apache.xml.serialize 0.0.0
org.apache.xml.serializer 0.0.0
org.apache.xpath.jaxp 0.0.0
org.osgi.framework 0.0.0
org.w3c.dom 0.0.0
org.w3c.dom.events 0.0.0
org.w3c.dom.traversal 0.0.0
org.w3c.dom.xpath 0.0.0
org.xml.sax 0.0.0
org.xml.sax.ext 0.0.0
org.xml.sax.helpers 0.0.0
Dynamic-ImportPackage
Provide-Capability
Require-Capability
Other manifest attributes
Build-Date Fri June 13 2014, 08:27:37
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/xml/xalan
Bundle-Category lib
Bundle-Copyright http://www.apache.org/licenses/LICENSE-2.0
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/xml/xalan/
Bundle-UUID org.knopflerfish:xalan:2.7.1.kf3_01
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

crimson-2.1.0.kf4-001org.w3c.dom, org.xml.sax, org.xml.sax.ext, org.xml.sax.helpers
xalan-2.7.1.kf3_01javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax, javax.xml.transform.stream, org.apache.xalan, org.apache.xalan.processor, org.apache.xpath.jaxp
xerces-2.10.1.kf5javax.xml.namespace, javax.xml.parsers, javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax, javax.xml.transform.stream, javax.xml.xpath, org.apache.xerces.parsers, org.apache.xml.serialize, org.apache.xml.serializer, org.w3c.dom, org.w3c.dom.events, org.w3c.dom.traversal, org.w3c.dom.xpath, org.xml.sax, org.xml.sax.ext, org.xml.sax.helpers
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

xalan-2.7.1.kf3_01javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax, javax.xml.transform.stream, org.apache.xalan, org.apache.xalan.processor, org.apache.xpath.jaxp
xerces-2.10.1.kf5javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax, javax.xml.transform.stream

Bundle source

Here are links to the source files of this bundle.
org/osgi/util/xml/XMLTransformerActivator.java
knopflerfish-osgi-5.1.0/docs/jars/xerces/0000755000175000017500000000000012475375714017345 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/xerces/xerces-2.10.1.kf5.html0000644000175000017500000002745212346515430022723 0ustar felixfelix xerces-2.10.1.kf5.jar

xerces-2.10.1.kf5.jar

download (1619502 bytes)

OSGi manifest attributes
Bundle-Name Xerces-J
Bundle-SymbolicName org.knopflerfish.bundle.xerces
Bundle-Version 2.10.1.kf5
Bundle-Description The Apache Xerces2 Java XML parser
Bundle-Vendor Apache/Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=xerces/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.osgi.util.xml.XMLParserActivator
Bundle-Classpath .,xercesImpl.jar,xml-apis.jar,resolver.jar,serializer.jar
Export-Package javax.xml 1.3.0
javax.xml.datatype 1.3.0
javax.xml.namespace 1.3.0
javax.xml.parsers 1.3.0
javax.xml.transform 1.3.0
javax.xml.transform.dom 1.3.0
javax.xml.transform.sax 1.3.0
javax.xml.transform.stream 1.3.0
javax.xml.validation 1.3.0
javax.xml.xpath 1.3.0
org.apache.html.dom 0.0.0
org.apache.wml 0.0.0
org.apache.wml.dom 0.0.0
org.apache.xerces.dom 0.0.0
org.apache.xerces.dom.events 0.0.0
org.apache.xerces.dom3.as 0.0.0
org.apache.xerces.jaxp 0.0.0
org.apache.xerces.jaxp.datatype 0.0.0
org.apache.xerces.jaxp.validation 0.0.0
org.apache.xerces.parsers 0.0.0
org.apache.xerces.util 0.0.0
org.apache.xerces.xinclude 0.0.0
org.apache.xerces.xni 0.0.0
org.apache.xerces.xni.grammars 0.0.0
org.apache.xerces.xni.parser 0.0.0
org.apache.xerces.xpointer 0.0.0
org.apache.xerces.xs 0.0.0
org.apache.xerces.xs.datatypes 0.0.0
org.apache.xml.resolver 1.2.0
org.apache.xml.resolver.apps 1.2.0
org.apache.xml.resolver.helpers 1.2.0
org.apache.xml.resolver.readers 1.2.0
org.apache.xml.resolver.tools 1.2.0
org.apache.xml.serialize 0.0.0
org.apache.xml.serializer 1.0.0
org.osgi.util.xml 1.0.1
org.w3c.dom 3.0.0
org.w3c.dom.bootstrap 3.0.0
org.w3c.dom.css 3.0.0
org.w3c.dom.events 3.0.0
org.w3c.dom.html 3.0.0
org.w3c.dom.ls 3.0.0
org.w3c.dom.ranges 3.0.0
org.w3c.dom.stylesheets 3.0.0
org.w3c.dom.traversal 3.0.0
org.w3c.dom.views 3.0.0
org.w3c.dom.xpath 3.0.0
org.xml.sax 2.0.2
org.xml.sax.ext 2.0.2
org.xml.sax.helpers 2.0.2
Import-Package javax.xml 1.3.0
javax.xml.datatype 1.3.0
javax.xml.namespace 1.3.0
javax.xml.parsers 1.3.0
javax.xml.transform 1.3.0
javax.xml.transform.dom 1.3.0
javax.xml.transform.sax 1.3.0
javax.xml.transform.stream 1.3.0
javax.xml.validation 1.3.0
javax.xml.xpath 1.3.0
org.apache.html.dom 0.0.0
org.apache.wml 0.0.0
org.apache.wml.dom 0.0.0
org.apache.xerces.dom 0.0.0
org.apache.xerces.dom.events 0.0.0
org.apache.xerces.dom3.as 0.0.0
org.apache.xerces.jaxp 0.0.0
org.apache.xerces.jaxp.datatype 0.0.0
org.apache.xerces.jaxp.validation 0.0.0
org.apache.xerces.parsers 0.0.0
org.apache.xerces.util 0.0.0
org.apache.xerces.xinclude 0.0.0
org.apache.xerces.xni 0.0.0
org.apache.xerces.xni.grammars 0.0.0
org.apache.xerces.xni.parser 0.0.0
org.apache.xerces.xpointer 0.0.0
org.apache.xerces.xs 0.0.0
org.apache.xerces.xs.datatypes 0.0.0
org.apache.xml.resolver 1.2.0
org.apache.xml.resolver.apps 1.2.0
org.apache.xml.resolver.helpers 1.2.0
org.apache.xml.resolver.readers 1.2.0
org.apache.xml.resolver.tools 1.2.0
org.apache.xml.serialize [0.0.0,1.0.0)
org.apache.xml.serializer 1.0.0
org.osgi.framework 0.0.0
org.osgi.util.xml [1.0.1,2.0.0)
org.w3c.dom 3.0.0
org.w3c.dom.bootstrap 3.0.0
org.w3c.dom.css 3.0.0
org.w3c.dom.events 3.0.0
org.w3c.dom.html 3.0.0
org.w3c.dom.ls 3.0.0
org.w3c.dom.ranges 3.0.0
org.w3c.dom.stylesheets 3.0.0
org.w3c.dom.traversal 3.0.0
org.w3c.dom.views 3.0.0
org.w3c.dom.xpath 3.0.0
org.xml.sax 2.0.2
org.xml.sax.ext 2.0.2
org.xml.sax.helpers 2.0.2
sun.io 0.0.0
Dynamic-ImportPackage
Provide-Capability
Require-Capability
Other manifest attributes
Build-Date Fri June 13 2014, 08:27:10
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/xml/xerces
Bundle-Category lib
Bundle-Copyright http://www.apache.org/licenses/LICENSE-2.0
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/xml/xerces/
Bundle-UUID org.knopflerfish:xerces:2.10.1.kf5
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

xalan-2.7.1.kf3_01javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax, javax.xml.transform.stream
xerces-2.10.1.kf5javax.xml, javax.xml.datatype, javax.xml.namespace, javax.xml.parsers, javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax, javax.xml.transform.stream, javax.xml.validation, javax.xml.xpath, org.apache.html.dom, org.apache.wml, org.apache.wml.dom, org.apache.xerces.dom, org.apache.xerces.dom.events, org.apache.xerces.dom3.as, org.apache.xerces.jaxp, org.apache.xerces.jaxp.datatype, org.apache.xerces.jaxp.validation, org.apache.xerces.parsers, org.apache.xerces.util, org.apache.xerces.xinclude, org.apache.xerces.xni, org.apache.xerces.xni.grammars, org.apache.xerces.xni.parser, org.apache.xerces.xpointer, org.apache.xerces.xs, org.apache.xerces.xs.datatypes, org.apache.xml.resolver, org.apache.xml.resolver.apps, org.apache.xml.resolver.helpers, org.apache.xml.resolver.readers, org.apache.xml.resolver.tools, org.apache.xml.serialize, org.apache.xml.serializer, org.osgi.util.xml, org.w3c.dom, org.w3c.dom.bootstrap, org.w3c.dom.css, org.w3c.dom.events, org.w3c.dom.html, org.w3c.dom.ls, org.w3c.dom.ranges, org.w3c.dom.stylesheets, org.w3c.dom.traversal, org.w3c.dom.views, org.w3c.dom.xpath, org.xml.sax, org.xml.sax.ext, org.xml.sax.helpers
xml-4.0.0org.osgi.util.xml
frameworkorg.osgi.framework
Unresolved
sun.io0.0.0

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

crimson-2.1.0.kf4-001javax.xml.parsers, org.w3c.dom, org.xml.sax, org.xml.sax.ext, org.xml.sax.helpers
junit_all-3.8.1.kf4-001javax.xml.parsers, org.w3c.dom
xalan-2.7.1.kf3_01javax.xml.namespace, javax.xml.parsers, javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax, javax.xml.transform.stream, javax.xml.xpath, org.apache.xerces.parsers, org.apache.xml.serialize, org.apache.xml.serializer, org.w3c.dom, org.w3c.dom.events, org.w3c.dom.traversal, org.w3c.dom.xpath, org.xml.sax, org.xml.sax.ext, org.xml.sax.helpers
xerces-2.10.1.kf5javax.xml, javax.xml.datatype, javax.xml.namespace, javax.xml.parsers, javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax, javax.xml.transform.stream, javax.xml.validation, javax.xml.xpath, org.apache.html.dom, org.apache.wml, org.apache.wml.dom, org.apache.xerces.dom, org.apache.xerces.dom.events, org.apache.xerces.dom3.as, org.apache.xerces.jaxp, org.apache.xerces.jaxp.datatype, org.apache.xerces.jaxp.validation, org.apache.xerces.parsers, org.apache.xerces.util, org.apache.xerces.xinclude, org.apache.xerces.xni, org.apache.xerces.xni.grammars, org.apache.xerces.xni.parser, org.apache.xerces.xpointer, org.apache.xerces.xs, org.apache.xerces.xs.datatypes, org.apache.xml.resolver, org.apache.xml.resolver.apps, org.apache.xml.resolver.helpers, org.apache.xml.resolver.readers, org.apache.xml.resolver.tools, org.apache.xml.serialize, org.apache.xml.serializer, org.osgi.util.xml, org.w3c.dom, org.w3c.dom.bootstrap, org.w3c.dom.css, org.w3c.dom.events, org.w3c.dom.html, org.w3c.dom.ls, org.w3c.dom.ranges, org.w3c.dom.stylesheets, org.w3c.dom.traversal, org.w3c.dom.views, org.w3c.dom.xpath, org.xml.sax, org.xml.sax.ext, org.xml.sax.helpers
xml-4.0.0javax.xml.parsers

Bundle source

Here are links to the source files of this bundle. None found knopflerfish-osgi-5.1.0/docs/jars/jsdk/0000755000175000017500000000000012475375714017007 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/jsdk/jsdk_api-2.5.0.kf3-2.html0000644000175000017500000003173612346515430022740 0ustar felixfelix jsdk_api-2.5.0.kf3-2.jar

jsdk_api-2.5.0.kf3-2.jar

download (42999 bytes)

OSGi manifest attributes
Bundle-Name JSDK-API
Bundle-SymbolicName org.knopflerfish.bundle.jsdk-API
Bundle-Version 2.5.0.kf3-2
Bundle-Description The servlet API classes (API)
Bundle-Vendor Knopflerfish/Sun/Apache
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/Apache-2.0;link="http://www.apache.org/licenses/LICENSE-2.0";description="Apache License, Version 2.0"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package javax.servlet 2.5.0
javax.servlet.http 2.5.0
Import-Package javax.servlet [2.5.0,3.0.0)
javax.servlet.http [2.5.0,3.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:46
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/jsdk
Bundle-APIVendor Sun
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/jsdk/
Bundle-UUID org.knopflerfish:jsdk:2.5.0.kf3-2:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

jsdk_api-2.5.0.kf3-2javax.servlet, javax.servlet.http

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

http_all-4.0.5javax.servlet, javax.servlet.http
http_api-4.0.5javax.servlet, javax.servlet.http
http-4.0.5javax.servlet, javax.servlet.http
httpconsole_all-4.0.1javax.servlet, javax.servlet.http
httproot-4.0.0javax.servlet, javax.servlet.http
jinidriver_all-0.1.0javax.servlet, javax.servlet.http
jsdk_api-2.5.0.kf3-2javax.servlet, javax.servlet.http
junit_all-3.8.1.kf4-001javax.servlet, javax.servlet.http

Bundle source

Here are links to the source files of this bundle.
javax/servlet/Filter.java
javax/servlet/FilterChain.java
javax/servlet/FilterConfig.java
javax/servlet/GenericServlet.java
javax/servlet/RequestDispatcher.java
javax/servlet/Servlet.java
javax/servlet/ServletConfig.java
javax/servlet/ServletContext.java
javax/servlet/ServletContextAttributeEvent.java
javax/servlet/ServletContextAttributeListener.java
javax/servlet/ServletContextEvent.java
javax/servlet/ServletContextListener.java
javax/servlet/ServletException.java
javax/servlet/ServletInputStream.java
javax/servlet/ServletOutputStream.java
javax/servlet/ServletRequest.java
javax/servlet/ServletRequestAttributeEvent.java
javax/servlet/ServletRequestAttributeListener.java
javax/servlet/ServletRequestEvent.java
javax/servlet/ServletRequestListener.java
javax/servlet/ServletRequestWrapper.java
javax/servlet/ServletResponse.java
javax/servlet/ServletResponseWrapper.java
javax/servlet/SingleThreadModel.java
javax/servlet/UnavailableException.java
javax/servlet/http/Cookie.java
javax/servlet/http/HttpServlet.java
javax/servlet/http/HttpServletRequest.java
javax/servlet/http/HttpServletRequestWrapper.java
javax/servlet/http/HttpServletResponse.java
javax/servlet/http/HttpServletResponseWrapper.java
javax/servlet/http/HttpSession.java
javax/servlet/http/HttpSessionActivationListener.java
javax/servlet/http/HttpSessionAttributeListener.java
javax/servlet/http/HttpSessionBindingEvent.java
javax/servlet/http/HttpSessionBindingListener.java
javax/servlet/http/HttpSessionContext.java
javax/servlet/http/HttpSessionEvent.java
javax/servlet/http/HttpSessionListener.java
javax/servlet/http/HttpUtils.java
knopflerfish-osgi-5.1.0/docs/jars/command/0000755000175000017500000000000012475375714017472 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/command/command_api-0.2.html0000644000175000017500000002277712346515426023134 0ustar felixfelix command_api-0.2.jar

command_api-0.2.jar

download (3052 bytes)

OSGi manifest attributes
Bundle-Name command-API
Bundle-SymbolicName org.knopflerfish.bundle.command-API
Bundle-Version 0.2
Bundle-Description Command Service (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.command 1.0.0
Import-Package org.osgi.service.command [1.0.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:21
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/command/command
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/command/command/
Bundle-UUID org.knopflerfish:command:0.2:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

command_all-0.2org.osgi.service.command
command_api-0.2org.osgi.service.command

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

command_all-0.2org.osgi.service.command
command_api-0.2org.osgi.service.command
commandtty-4.0.1org.osgi.service.command
console2command-2.0.0org.osgi.service.command

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/command/Activator.java
org/knopflerfish/bundle/command/CommandProcessorFactory.java
org/knopflerfish/bundle/command/CommandProcessorImpl.java
org/knopflerfish/bundle/command/CommandProviders.java
org/knopflerfish/bundle/command/CommandProvidersService.java
org/knopflerfish/bundle/command/CommandProvidersTest.java
org/knopflerfish/bundle/command/CommandSessionImpl.java
org/knopflerfish/bundle/command/FrameworkConverter.java
org/knopflerfish/bundle/command/JavaLangConverter.java
org/knopflerfish/bundle/command/Program.java
org/knopflerfish/bundle/command/Tokenizer.java
org/knopflerfish/bundle/command/Util.java
org/knopflerfish/bundle/command/commands/CommandCommands.java
org/knopflerfish/bundle/command/commands/EchoCmd.java
org/knopflerfish/bundle/command/commands/FrameworkCommands.java
org/osgi/service/command/CommandProcessor.java
org/osgi/service/command/CommandSession.java
org/osgi/service/command/Converter.java
org/osgi/service/command/Function.java
knopflerfish-osgi-5.1.0/docs/jars/command/command_all-0.2.html0000644000175000017500000002525112346515426023121 0ustar felixfelix command_all-0.2.jar

command_all-0.2.jar

download (35977 bytes)

OSGi manifest attributes
Bundle-Name command
Bundle-SymbolicName org.knopflerfish.bundle.command
Bundle-Version 0.2
Bundle-Description Command Service
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.command.Activator
Bundle-Classpath .
Export-Package org.osgi.service.command 1.0.0
Import-Package org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.command [1.0.0,2.0.0)
org.osgi.service.threadio [1.0.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:21
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/command/command
Bundle-Category service
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/command/command/
Bundle-UUID org.knopflerfish:command:0.2
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

command_all-0.2org.osgi.service.command
command_api-0.2org.osgi.service.command
threadio_all-0.2.0org.osgi.service.threadio
threadio_api-0.2.0org.osgi.service.threadio
frameworkorg.osgi.framework, org.osgi.util.tracker

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

command_all-0.2org.osgi.service.command
command_api-0.2org.osgi.service.command
commandtty-4.0.1org.osgi.service.command
console2command-2.0.0org.osgi.service.command

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/command/Activator.java
org/knopflerfish/bundle/command/CommandProcessorFactory.java
org/knopflerfish/bundle/command/CommandProcessorImpl.java
org/knopflerfish/bundle/command/CommandProviders.java
org/knopflerfish/bundle/command/CommandProvidersService.java
org/knopflerfish/bundle/command/CommandProvidersTest.java
org/knopflerfish/bundle/command/CommandSessionImpl.java
org/knopflerfish/bundle/command/FrameworkConverter.java
org/knopflerfish/bundle/command/JavaLangConverter.java
org/knopflerfish/bundle/command/Program.java
org/knopflerfish/bundle/command/Tokenizer.java
org/knopflerfish/bundle/command/Util.java
org/knopflerfish/bundle/command/commands/CommandCommands.java
org/knopflerfish/bundle/command/commands/EchoCmd.java
org/knopflerfish/bundle/command/commands/FrameworkCommands.java
org/osgi/service/command/CommandProcessor.java
org/osgi/service/command/CommandSession.java
org/osgi/service/command/Converter.java
org/osgi/service/command/Function.java
knopflerfish-osgi-5.1.0/docs/jars/wireadmin/0000755000175000017500000000000012475375714020033 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/wireadmin/wireadmin_api-5.0.0.html0000644000175000017500000001603612346515430024161 0ustar felixfelix wireadmin_api-5.0.0.jar

wireadmin_api-5.0.0.jar

download (10209 bytes)

OSGi manifest attributes
Bundle-Name wireadmin-API
Bundle-SymbolicName org.knopflerfish.bundle.wireadmin-API
Bundle-Version 5.0.0
Bundle-Description WireAdmin (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/Apache-2.0;link="http://www.apache.org/licenses/LICENSE-2.0";description="Apache License, Version 2.0"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.wireadmin 1.0.1
Import-Package org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.wireadmin [1.0.1,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:24
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/wireadmin
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/wireadmin/
Bundle-UUID org.knopflerfish:wireadmin:5.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

wireadmin_api-5.0.0org.osgi.service.wireadmin
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

wireadmin_api-5.0.0org.osgi.service.wireadmin

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/wireadmin/BasicEnvelope.java
org/osgi/service/wireadmin/Consumer.java
org/osgi/service/wireadmin/Envelope.java
org/osgi/service/wireadmin/Producer.java
org/osgi/service/wireadmin/Wire.java
org/osgi/service/wireadmin/WireAdmin.java
org/osgi/service/wireadmin/WireAdminEvent.java
org/osgi/service/wireadmin/WireAdminListener.java
org/osgi/service/wireadmin/WireConstants.java
org/osgi/service/wireadmin/WirePermission.java
org/osgi/service/wireadmin/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/junit/0000755000175000017500000000000012475375714017205 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/junit/junit_all-3.8.1.kf4-001.html0000644000175000017500000002163712346515430023477 0ustar felixfelix junit_all-3.8.1.kf4-001.jar

junit_all-3.8.1.kf4-001.jar

download (146393 bytes)

OSGi manifest attributes
Bundle-Name JUnit
Bundle-SymbolicName org.knopflerfish.bundle.junit
Bundle-Version 3.8.1.kf4-001
Bundle-Description JUnit support
Bundle-Vendor JUnit/Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=junit
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.junit.Activator
Bundle-Classpath .,junit.jar
Export-Package junit.framework 3.8.1
org.knopflerfish.service.junit 1.0.0
Import-Package javax.servlet 0.0.0
javax.servlet.http 0.0.0
javax.swing 0.0.0
javax.swing.border 0.0.0
javax.swing.event 0.0.0
javax.swing.text 0.0.0
javax.swing.tree 0.0.0
javax.xml.parsers 0.0.0
junit.framework 3.8.1
org.knopflerfish.service.console 0.0.0
org.knopflerfish.service.junit 1.0.0
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.http [1.2.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
org.w3c.dom 0.0.0
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:08
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/junit/junit
Bundle-APIVendor JUnit
Bundle-Category testing
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/junit/junit/
Bundle-UUID org.knopflerfish:junit:3.8.1.kf4-001
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
crimson-2.1.0.kf4-001javax.xml.parsers, org.w3c.dom
desktop_all-5.0.1org.knopflerfish.service.console
http_all-4.0.5org.osgi.service.http
http_api-4.0.5org.osgi.service.http
jsdk_api-2.5.0.kf3-2javax.servlet, javax.servlet.http
junit_all-3.8.1.kf4-001junit.framework, org.knopflerfish.service.junit
xerces-2.10.1.kf5javax.xml.parsers, org.w3c.dom
frameworkorg.osgi.framework, org.osgi.util.tracker

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

junit_all-3.8.1.kf4-001junit.framework, org.knopflerfish.service.junit
junit_runner_all-4.0.0junit.framework, org.knopflerfish.service.junit

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/junit/Activator.java
org/knopflerfish/bundle/junit/HttpExporter.java
org/knopflerfish/bundle/junit/JUnitCommandGroup.java
org/knopflerfish/bundle/junit/JUnitServiceImpl.java
org/knopflerfish/bundle/junit/JUnitServlet.java
org/knopflerfish/service/junit/JUnitService.java
org/knopflerfish/service/junit/client/JUnitClient.java
knopflerfish-osgi-5.1.0/docs/jars/prefs/0000755000175000017500000000000012475375714017173 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/prefs/prefs_all-4.0.2.html0000644000175000017500000002353412346515430022462 0ustar felixfelix prefs_all-4.0.2.jar

prefs_all-4.0.2.jar

download (26716 bytes)

OSGi manifest attributes
Bundle-Name Prefs
Bundle-SymbolicName org.knopflerfish.bundle.prefs
Bundle-Version 4.0.2
Bundle-Description Preferences
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=prefs/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.prefs.Activator
Bundle-Classpath .
Export-Package org.osgi.service.prefs 1.1.1
Import-Package org.knopflerfish.service.log [1.2.0,2.0.0)
org.knopflerfish.util 0.0.0
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.prefs [1.1.0,1.2.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:32
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/prefs
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/prefs
Bundle-UUID org.knopflerfish:prefs:4.0.2
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.knopflerfish.util, org.osgi.service.prefs
http_all-4.0.5org.knopflerfish.service.log
prefs_all-4.0.2org.osgi.service.prefs
prefs_api-4.0.2org.osgi.service.prefs
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
util-4.1.0org.knopflerfish.util
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

desktop_all-5.0.1org.osgi.service.prefs
desktop-5.0.1org.osgi.service.prefs
prefs_all-4.0.2org.osgi.service.prefs
prefs_api-4.0.2org.osgi.service.prefs

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/prefs/Activator.java
org/knopflerfish/bundle/prefs/PreferencesImpl.java
org/knopflerfish/bundle/prefs/PreferencesServiceFactory.java
org/knopflerfish/bundle/prefs/PreferencesServiceImpl.java
org/knopflerfish/bundle/prefs/PrefsStorage.java
org/knopflerfish/bundle/prefs/PrefsStorageFile.java
org/osgi/service/prefs/BackingStoreException.java
org/osgi/service/prefs/Preferences.java
org/osgi/service/prefs/PreferencesService.java
org/osgi/service/prefs/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/prefs/prefs_api-4.0.2.html0000644000175000017500000001674212346515430022466 0ustar felixfelix prefs_api-4.0.2.jar

prefs_api-4.0.2.jar

download (3019 bytes)

OSGi manifest attributes
Bundle-Name Prefs-API
Bundle-SymbolicName org.knopflerfish.bundle.prefs-API
Bundle-Version 4.0.2
Bundle-Description Preferences (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=prefs/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.prefs 1.1.1
Import-Package org.osgi.service.prefs [1.1.1,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:32
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/prefs
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/prefs
Bundle-UUID org.knopflerfish:prefs:4.0.2:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

desktop_all-5.0.1org.osgi.service.prefs
prefs_all-4.0.2org.osgi.service.prefs
prefs_api-4.0.2org.osgi.service.prefs

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

desktop_all-5.0.1org.osgi.service.prefs
desktop-5.0.1org.osgi.service.prefs
prefs_all-4.0.2org.osgi.service.prefs
prefs_api-4.0.2org.osgi.service.prefs

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/prefs/Activator.java
org/knopflerfish/bundle/prefs/PreferencesImpl.java
org/knopflerfish/bundle/prefs/PreferencesServiceFactory.java
org/knopflerfish/bundle/prefs/PreferencesServiceImpl.java
org/knopflerfish/bundle/prefs/PrefsStorage.java
org/knopflerfish/bundle/prefs/PrefsStorageFile.java
org/osgi/service/prefs/BackingStoreException.java
org/osgi/service/prefs/Preferences.java
org/osgi/service/prefs/PreferencesService.java
org/osgi/service/prefs/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/resolver/0000755000175000017500000000000012475375714017715 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/resolver/resolver_api-1.0.0.html0000644000175000017500000001443312346515430023720 0ustar felixfelix resolver_api-1.0.0.jar

resolver_api-1.0.0.jar

download (3846 bytes)

OSGi manifest attributes
Bundle-Name resolver-API
Bundle-SymbolicName org.knopflerfish.bundle.resolver-API
Bundle-Version 1.0.0
Bundle-Description Resolver API (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.resolver 1.0.1
Import-Package org.osgi.resource 0.0.0
org.osgi.service.resolver [1.0.1,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:45
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/resolver/resolver_api
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/resolver/
Bundle-UUID org.knopflerfish:resolver:1.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

repositorymanager_all-1.2.0org.osgi.service.resolver
resolver_api-1.0.0org.osgi.service.resolver
frameworkorg.osgi.resource

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

repositorymanager_all-1.2.0org.osgi.service.resolver
resolver_api-1.0.0org.osgi.service.resolver

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/resolver/HostedCapability.java
org/osgi/service/resolver/ResolutionException.java
org/osgi/service/resolver/ResolveContext.java
org/osgi/service/resolver/Resolver.java
org/osgi/service/resolver/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/scrcommands/0000755000175000017500000000000012475375714020365 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/scrcommands/scrcommands-4.0.1.html0000644000175000017500000001444312346515430024214 0ustar felixfelix scrcommands-4.0.1.jar

scrcommands-4.0.1.jar

download (14583 bytes)

OSGi manifest attributes
Bundle-Name ScrCommands-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.scrcommands-IMPL
Bundle-Version 4.0.1
Bundle-Description Provides SCR admin commands for the Knopflerfish console (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=scrcommands/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package
Import-Package org.apache.felix.scr [1.4.0,2.0.0)
org.knopflerfish.service.console [2.1.0,3.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.component [1.2.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:37
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/scrcommands
Bundle-Category management
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/scrcommands/
Bundle-UUID org.knopflerfish:scrcommands:4.0.1:impl
Knopflerfish-Version 5.1.0
Service-Component OSGI-INF/service.xml

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

component_all-5.0.3org.apache.felix.scr, org.osgi.service.component
component_api-5.0.3org.apache.felix.scr, org.osgi.service.component
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.apache.felix.scr, org.knopflerfish.service.console, org.osgi.service.component
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/scrcommands/ScrCommandGroup.java
knopflerfish-osgi-5.1.0/docs/jars/dirdeployer/0000755000175000017500000000000012475375714020376 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/dirdeployer/dirdeployer_all-4.0.1.html0000644000175000017500000002702612346515426025074 0ustar felixfelix dirdeployer_all-4.0.1.jar

dirdeployer_all-4.0.1.jar

download (41921 bytes)

OSGi manifest attributes
Bundle-Name Directory Deployer
Bundle-SymbolicName org.knopflerfish.bundle.dirdeployer
Bundle-Version 4.0.1
Bundle-Description Monitors a set of file system directory for bundlesand configurations to deploy
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=dirdeployer/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.dirdeployer.Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.dirdeployer 0.0.0
org.knopflerfish.shared.cm 1.1.0
Import-Package org.knopflerfish.service.dirdeployer [0.0.0,1.0.0)
org.knopflerfish.shared.cm [1.1.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.framework.startlevel [1.0.0,2.0.0)
org.osgi.framework.wiring [1.0.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:27
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/dirdeployer
Bundle-APIVendor Knopflerfish
Bundle-Category example
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/dirdeployer/
Bundle-UUID org.knopflerfish:dirdeployer:4.0.1
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.knopflerfish.shared.cm, org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
cm-5.0.1org.knopflerfish.shared.cm
cm_desktop_all-5.0.2org.knopflerfish.shared.cm
commons-logging_all-2.0.0.kf4-001org.osgi.service.log
desktop_all-5.0.1org.osgi.service.cm, org.osgi.service.log
dirdeployer_all-4.0.1org.knopflerfish.service.dirdeployer, org.knopflerfish.shared.cm
dirdeployer_api-4.0.1org.knopflerfish.service.dirdeployer
frameworkorg.osgi.framework, org.osgi.framework.startlevel, org.osgi.framework.wiring, org.osgi.util.tracker
log_all-5.0.0org.osgi.service.log
log_api-5.0.0org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

cm_all-5.0.1org.knopflerfish.shared.cm
cm-5.0.1org.knopflerfish.shared.cm
cm_cmd-5.0.1org.knopflerfish.shared.cm
cm_desktop_all-5.0.2org.knopflerfish.shared.cm
cm_desktop-5.0.2org.knopflerfish.shared.cm
dirdeployer_all-4.0.1org.knopflerfish.service.dirdeployer, org.knopflerfish.shared.cm
dirdeployer_api-4.0.1org.knopflerfish.service.dirdeployer

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/dirdeployer/Activator.java
org/knopflerfish/bundle/dirdeployer/Config.java
org/knopflerfish/bundle/dirdeployer/DeployedBundle.java
org/knopflerfish/bundle/dirdeployer/DeployedCMData.java
org/knopflerfish/bundle/dirdeployer/DeployedFile.java
org/knopflerfish/bundle/dirdeployer/DirDeployerImpl.java
org/knopflerfish/service/dirdeployer/DirDeployerService.java
knopflerfish-osgi-5.1.0/docs/jars/dirdeployer/dirdeployer_api-4.0.1.html0000644000175000017500000001526212346515430025067 0ustar felixfelix dirdeployer_api-4.0.1.jar

dirdeployer_api-4.0.1.jar

download (1596 bytes)

OSGi manifest attributes
Bundle-Name Directory Deployer-API
Bundle-SymbolicName org.knopflerfish.bundle.dirdeployer-API
Bundle-Version 4.0.1
Bundle-Description Monitors a set of file system directory for bundlesand configurations to deploy (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=dirdeployer/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.dirdeployer 0.0.0
Import-Package org.knopflerfish.service.dirdeployer [0.0.0,1.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:27
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/dirdeployer
Bundle-APIVendor Knopflerfish
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/dirdeployer/
Bundle-UUID org.knopflerfish:dirdeployer:4.0.1:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

dirdeployer_all-4.0.1org.knopflerfish.service.dirdeployer
dirdeployer_api-4.0.1org.knopflerfish.service.dirdeployer

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

dirdeployer_all-4.0.1org.knopflerfish.service.dirdeployer
dirdeployer_api-4.0.1org.knopflerfish.service.dirdeployer

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/dirdeployer/Activator.java
org/knopflerfish/bundle/dirdeployer/Config.java
org/knopflerfish/bundle/dirdeployer/DeployedBundle.java
org/knopflerfish/bundle/dirdeployer/DeployedCMData.java
org/knopflerfish/bundle/dirdeployer/DeployedFile.java
org/knopflerfish/bundle/dirdeployer/DirDeployerImpl.java
org/knopflerfish/service/dirdeployer/DirDeployerService.java
knopflerfish-osgi-5.1.0/docs/jars/main.html0000644000175000017500000004265612346515430017667 0ustar felixfelix Knopflerfish - Bundle Jar Documentation

Bundle Jar Documentation

This section contains information on all bundle jar files included in this distribution of Knopflerfish.

Select the bundles from the bundle list to the left to view detailed bundle information, including manifest headers, bundle dependencies and derived javadoc links based on imported and exported packages.

Unresolved packages
xerces-2.10.1.kf5 sun.io 0.0.0 optional

Bundle Jars Listing

applicationadmin_api-4.0.0Application Admin API (API)
basicdriverlocator-4.0.0Basic device driver locator (IMPL)
basicdriverlocator_all-4.0.0Basic device driver locator
blueprint_api-5.0.0Blueprint Container API (API)
classpatcher_all-5.0.0Implements a WeavingHook to allow patching of classes at load time using ASM
cm-5.0.1Configuration Management Service (IMPL)
cm_all-5.0.1Configuration Management Service
cm_api-5.0.1Configuration Management Service (API)
cm_cmd-5.0.1Commands for the CM service (IMPL)
cm_desktop-5.0.2CM desktop plugin (IMPL)
cm_desktop_all-5.0.2CM desktop plugin
comm-linux_all-3.0.0Native driver for linux javax.comm using the RXTX library. Note that this bundle is LGPL and contains full source to rxtx
comm-win32_all-3.0.0Native driver for win32 javax.comm using Sun's COMM library
command_all-0.2Command Service
command_api-0.2Command Service (API)
commandtty-4.0.1Command line system console (IMPL)
commons-logging_all-2.0.0.kf4-001Apache Commons logging. Publishced under Apache License. See http://www.apache.org/licenses/LICENSE-2.0
component_all-5.0.3Declarative Services SCR
component_annotations_api-1.0.0OSGi specified component annotations (API)
component_api-5.0.3Declarative Services SCR (API)
connectors-3.0.0OSGi IO http, socket and datagram-receive Connectors (IMPL)
connectors_all-3.0.0OSGi IO http, socket and datagram-receive Connectors
console-4.0.1Knopflerfish Console Service (IMPL)
console2command-2.0.0Wrapper for KF console commands to RFC147 commands (IMPL)
console_all-4.0.1Knopflerfish Console Service
console_api-4.0.1Knopflerfish Console Service (API)
consoletcp-5.0.0Console Service Server accepting TCP connection. (IMPL)
consoletcp_all-5.0.0Console Service Server accepting TCP connection.
consoletelnet-4.0.1Console service server accepting telnet connections. (IMPL)
consoletty-4.0.1Console Service Command Line Console (IMPL)
coordinator_api-1.0.0OSGi specified coordinator service (API)
crimson-2.1.0.kf4-001The Crimson XML parser
deploymentadmin_api-4.0.0Deployment Admin API (API)
desktop-5.0.1Swing framework desktop (IMPL)
desktop_all-5.0.1Swing framework desktop
desktop_api-5.0.1Swing framework desktop (API)
desktop_jvm-1.0.0JVM info desktop plugin (IMPL)
desktop_jvm_all-1.0.0JVM info desktop plugin
device-4.0.1Device manager (IMPL)
device_all-4.0.1Device manager
device_api-4.0.1Device manager (API)
dirdeployer_all-4.0.1Monitors a set of file system directory for bundlesand configurations to deploy
dirdeployer_api-4.0.1Monitors a set of file system directory for bundlesand configurations to deploy (API)
dmt_api-5.0.0DMT (API)
event_all-4.0.1Event Admin
event_api-4.0.1Event Admin (API)
foreignapplication_api-4.0.0Foreign Application Access API (API)
frameworkKnopflerfish OSGi framework system bundle
frameworkcommands-4.0.1Framework commands (IMPL)
http-4.0.5HTTP/HTTPS Server (IMPL)
http_all-4.0.5HTTP/HTTPS Server
http_api-4.0.5HTTP/HTTPS Server (API)
httpconsole_all-4.0.1
httproot-4.0.0Demo HTTP Service user that publishes on the root (IMPL)
io_all-4.0.0IO
io_api-4.0.0IO (API)
jinidriver_all-0.1.0Jini driver (experimental) using Sun's jini impl. jini-core.jar and jini-ext.jar, see http://wwws.sun.com/software/jini/licensing/SCSL3_JiniTSA1.html
jsdk_api-2.5.0.kf3-2The servlet API classes (API)
junit_all-3.8.1.kf4-001JUnit support
junit_runner_all-4.0.0Grunt, the JUnit test runner. Runs JUnit tests registered in the framework and dumps results to XML files.
kf_metatype_all-5.0.2XML format support for CM and Metatype
kxml-2.3.0.kf4-001Packing of kXML 2 as a bundle (LIB)
log-5.0.0The Knopflerfish OSGi log service (IMPL)
log_all-5.0.0The Knopflerfish OSGi log service
log_api-5.0.0The Knopflerfish OSGi log service (API)
logcommands-5.0.0Provides log commands for the Knopflerfish console (IMPL)
measurement-4.0.0Measurement API (LIB)
metatype-4.0.0Metatype API (LIB)
monitor_api-4.0.0Monitor Admin API (API)
namespace_api-1.0.0OSGi Namespace (API)
position-4.0.0Position API (LIB)
prefs_all-4.0.2Preferences
prefs_api-4.0.2Preferences (API)
provisioning_api-4.0.0Initial Provisioning (API)
remotefw_api-4.0.0Remote Framework (API)
remoteserviceadmin_api-1.0.0OSGi specified remote service admin service (API)
repoindex_kf_all-1.0.1KF Resource Analyzer Extensions
repository_api-1.0.0Repository API (API)
repository_desktop_all-1.1.1Knopflerfish desktop plugin visualizing OSGi Repository contents.
repository_xml_all-1.0.2Xml Backed Repository
repository_xml_api-1.0.2Xml Backed Repository (API)
repositorycommands-1.1.1Repository commands (IMPL)
repositorymanager_all-1.2.0Repository Manager
repositorymanager_api-1.2.0Repository Manager (API)
resolver_api-1.0.0Resolver API (API)
rxtxcomm-linux-arm-2.1.7.1RXTX comm native driver for Linux/arm_le (LIB)
rxtxcomm-linux-x86-2.2.0.pre2RXTX comm native driver for Linux/x86 (LIB)
rxtxcomm_api-2.2.0.pre2RXTX comm java library, requires native driver fragment (API)
scrcommands-4.0.1Provides SCR admin commands for the Knopflerfish console (IMPL)
serialportdevice_all-4.0.0Serial port device
serialportdevice_api-4.0.0Serial port device (API)
serviceloader_api-1.0.0OSGi specified serviceloader service (API)
sslj2sp-4.0.0SSL Provider using the Java 2 security architecture. (IMPL)
subsystem_api-1.0.0OSGi specified subsytem service (API)
threadio-0.2.0ThreadIO Service (IMPL)
threadio_all-0.2.0ThreadIO Service
threadio_api-0.2.0ThreadIO Service (API)
trayicon_fw-4.0.0Framework tray icon. Allows basic control of the framework using the windows system tray.
upnp_api-4.0.0UPnP (API)
useradmin-4.1.1User Administration Service (IMPL)
useradmin_all-4.1.1User Administration Service
useradmin_api-4.1.1User Administration Service (API)
util-4.1.0Misc utilities (LIB)
wireadmin_api-5.0.0WireAdmin (API)
xalan-2.7.1.kf3_01The Apache Xalan-Java XML transformer
xerces-2.10.1.kf5The Apache Xerces2 Java XML parser
xml-4.0.0XML (LIB)

knopflerfish-osgi-5.1.0/docs/jars/repositorycommands/0000755000175000017500000000000012475375714022015 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/repositorycommands/repositorycommands-1.1.1.html0000644000175000017500000001660112346515430027270 0ustar felixfelix repositorycommands-1.1.1.jar

repositorycommands-1.1.1.jar

download (15643 bytes)

OSGi manifest attributes
Bundle-Name Repository-Commands-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.repositorycommands-IMPL
Bundle-Version 1.1.1
Bundle-Description Repository commands (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=repositorycommands/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.repositorycommands.Activator
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.console [2.0.0,3.0.0)
org.knopflerfish.service.repositorymanager [1.1.0,2.0.0)
org.osgi.framework [1.7.0,2.0.0)
org.osgi.resource [1.0.0,2.0.0)
org.osgi.service.repository [1.0.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service;objectClass:List="org.knopflerfish.service.console.CommandGroup"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:58
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/repository/repositorycommands
Bundle-Category management
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/repositorycommands/
Bundle-UUID org.knopflerfish:repositorycommands:1.1.1:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console
repository_api-1.0.0org.osgi.service.repository
repositorymanager_all-1.2.0org.knopflerfish.service.repositorymanager, org.osgi.service.repository
repositorymanager_api-1.2.0org.knopflerfish.service.repositorymanager
frameworkorg.osgi.framework, org.osgi.resource, org.osgi.util.tracker

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/repositorycommands/Activator.java
org/knopflerfish/bundle/repositorycommands/RepositoryCommandGroup.java
knopflerfish-osgi-5.1.0/docs/jars/deploymentadmin/0000755000175000017500000000000012475375714021245 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/deploymentadmin/deploymentadmin_api-4.0.0.html0000644000175000017500000002007312346515426026605 0ustar felixfelix deploymentadmin_api-4.0.0.jar

deploymentadmin_api-4.0.0.jar

download (11683 bytes)

OSGi manifest attributes
Bundle-Name deploymentadmin-API
Bundle-SymbolicName org.knopflerfish.bundle.deploymentadmin-API
Bundle-Version 4.0.0
Bundle-Description Deployment Admin API (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.deploymentadmin 1.1.0
org.osgi.service.deploymentadmin.spi 1.0.1
Import-Package org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.deploymentadmin [1.1.0,2.0.0)
org.osgi.service.deploymentadmin.spi [1.0.1,2.0.0)
Dynamic-ImportPackage *
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:49
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/deploymentadmin
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/deploymentadmin/
Bundle-UUID org.knopflerfish:deploymentadmin:4.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

deploymentadmin_api-4.0.0org.osgi.service.deploymentadmin, org.osgi.service.deploymentadmin.spi
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

deploymentadmin_api-4.0.0org.osgi.service.deploymentadmin, org.osgi.service.deploymentadmin.spi

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/deploymentadmin/BundleInfo.java
org/osgi/service/deploymentadmin/DeploymentAdmin.java
org/osgi/service/deploymentadmin/DeploymentAdminPermission.java
org/osgi/service/deploymentadmin/DeploymentException.java
org/osgi/service/deploymentadmin/DeploymentPackage.java
org/osgi/service/deploymentadmin/package-info.java
org/osgi/service/deploymentadmin/spi/DeploymentCustomizerPermission.java
org/osgi/service/deploymentadmin/spi/DeploymentSession.java
org/osgi/service/deploymentadmin/spi/ResourceProcessor.java
org/osgi/service/deploymentadmin/spi/ResourceProcessorException.java
org/osgi/service/deploymentadmin/spi/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/useradmin/0000755000175000017500000000000012475375714020043 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/useradmin/useradmin_all-4.1.1.html0000644000175000017500000006140312346515430024177 0ustar felixfelix useradmin_all-4.1.1.jar

useradmin_all-4.1.1.jar

download (50025 bytes)

OSGi manifest attributes
Bundle-Name UserAdmin
Bundle-SymbolicName org.knopflerfish.bundle.useradmin
Bundle-Version 4.1.1
Bundle-Description User Administration Service
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.service.um.useradmin.impl.Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.log 1.2.0
org.knopflerfish.service.um.ipam 1.0.0
org.knopflerfish.service.um.useradmin 1.0.0
org.osgi.service.useradmin 1.1.0
Import-Package org.knopflerfish.service.log [1.2.0,2.0.0)
org.knopflerfish.service.um.ipam [1.0.0,2.0.0)
org.knopflerfish.service.um.useradmin [1.0.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.event [1.3.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.service.useradmin [1.1.0,1.2.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:27:56
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/useradmin
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/useradmin/
Bundle-UUID org.knopflerfish:useradmin:4.1.1
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.event, org.osgi.service.log
event_all-4.0.1org.osgi.service.event
event_api-4.0.1org.osgi.service.event
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log, org.knopflerfish.service.um.ipam, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin_api-4.1.1org.knopflerfish.service.um.ipam, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

basicdriverlocator_all-4.0.0org.knopflerfish.service.log
basicdriverlocator-4.0.0org.knopflerfish.service.log
cm_all-5.0.1org.knopflerfish.service.log
cm-5.0.1org.knopflerfish.service.log
cm_desktop_all-5.0.2org.knopflerfish.service.log
cm_desktop-5.0.2org.knopflerfish.service.log
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
consoletcp_all-5.0.0org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
consoletcp-5.0.0org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
consoletelnet-4.0.1org.knopflerfish.service.log, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
desktop_all-5.0.1org.knopflerfish.service.log
desktop-5.0.1org.knopflerfish.service.log
desktop_jvm_all-1.0.0org.knopflerfish.service.log
desktop_jvm-1.0.0org.knopflerfish.service.log
event_all-4.0.1org.knopflerfish.service.log
http_all-4.0.5org.knopflerfish.service.log
http-4.0.5org.knopflerfish.service.log
httpconsole_all-4.0.1org.knopflerfish.service.log
httproot-4.0.0org.knopflerfish.service.log
kf_metatype_all-5.0.2org.knopflerfish.service.log
logcommands-5.0.0org.knopflerfish.service.log
prefs_all-4.0.2org.knopflerfish.service.log
repository_desktop_all-1.1.1org.knopflerfish.service.log
serialportdevice_all-4.0.0org.knopflerfish.service.log
trayicon_fw-4.0.0org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log, org.knopflerfish.service.um.ipam, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin_api-4.1.1org.knopflerfish.service.um.ipam, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin-4.1.1org.knopflerfish.service.log, org.knopflerfish.service.um.ipam, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log
log-5.0.0org.knopflerfish.service.log

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/service/um/ipam/IPAMValuationService.java
org/knopflerfish/service/um/ipam/Levels.java
org/knopflerfish/service/um/useradmin/BackEndControl.java
org/knopflerfish/service/um/useradmin/BackEndException.java
org/knopflerfish/service/um/useradmin/Condition.java
org/knopflerfish/service/um/useradmin/ContextualAuthorization.java
org/knopflerfish/service/um/useradmin/PasswdAuthenticator.java
org/knopflerfish/service/um/useradmin/PasswdSession.java
org/knopflerfish/service/um/useradmin/PasswdUtil.java
org/knopflerfish/service/um/useradmin/impl/Activator.java
org/knopflerfish/service/um/useradmin/impl/AuthorizationImpl.java
org/knopflerfish/service/um/useradmin/impl/ConditionImpl.java
org/knopflerfish/service/um/useradmin/impl/EventQueue.java
org/knopflerfish/service/um/useradmin/impl/GroupImpl.java
org/knopflerfish/service/um/useradmin/impl/LDAPQuery.java
org/knopflerfish/service/um/useradmin/impl/RoleImpl.java
org/knopflerfish/service/um/useradmin/impl/SendUserAdminEventJob.java
org/knopflerfish/service/um/useradmin/impl/UACredentials.java
org/knopflerfish/service/um/useradmin/impl/UAProperties.java
org/knopflerfish/service/um/useradmin/impl/UserAdminImpl.java
org/knopflerfish/service/um/useradmin/impl/UserImpl.java
org/osgi/service/useradmin/Authorization.java
org/osgi/service/useradmin/Group.java
org/osgi/service/useradmin/Role.java
org/osgi/service/useradmin/User.java
org/osgi/service/useradmin/UserAdmin.java
org/osgi/service/useradmin/UserAdminEvent.java
org/osgi/service/useradmin/UserAdminListener.java
org/osgi/service/useradmin/UserAdminPermission.java
org/osgi/service/useradmin/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/useradmin/useradmin-4.1.1.html0000644000175000017500000005374612346515430023362 0ustar felixfelix useradmin-4.1.1.jar

useradmin-4.1.1.jar

download (36390 bytes)

OSGi manifest attributes
Bundle-Name UserAdmin-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.useradmin-IMPL
Bundle-Version 4.1.1
Bundle-Description User Administration Service (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.service.um.useradmin.impl.Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.log 1.2.0
Import-Package org.knopflerfish.service.log [1.2.0,2.0.0)
org.knopflerfish.service.um.ipam [1.0.0,2.0.0)
org.knopflerfish.service.um.useradmin [1.0.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.event [1.3.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.service.useradmin [1.1.0,1.2.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:27:56
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/useradmin
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/useradmin/
Bundle-UUID org.knopflerfish:useradmin:4.1.1:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.event, org.osgi.service.log
event_all-4.0.1org.osgi.service.event
event_api-4.0.1org.osgi.service.event
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log, org.knopflerfish.service.um.ipam, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin_api-4.1.1org.knopflerfish.service.um.ipam, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

basicdriverlocator_all-4.0.0org.knopflerfish.service.log
basicdriverlocator-4.0.0org.knopflerfish.service.log
cm_all-5.0.1org.knopflerfish.service.log
cm-5.0.1org.knopflerfish.service.log
cm_desktop_all-5.0.2org.knopflerfish.service.log
cm_desktop-5.0.2org.knopflerfish.service.log
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
consoletelnet-4.0.1org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.log
desktop-5.0.1org.knopflerfish.service.log
desktop_jvm_all-1.0.0org.knopflerfish.service.log
desktop_jvm-1.0.0org.knopflerfish.service.log
event_all-4.0.1org.knopflerfish.service.log
http_all-4.0.5org.knopflerfish.service.log
http-4.0.5org.knopflerfish.service.log
httpconsole_all-4.0.1org.knopflerfish.service.log
httproot-4.0.0org.knopflerfish.service.log
kf_metatype_all-5.0.2org.knopflerfish.service.log
logcommands-5.0.0org.knopflerfish.service.log
prefs_all-4.0.2org.knopflerfish.service.log
repository_desktop_all-1.1.1org.knopflerfish.service.log
serialportdevice_all-4.0.0org.knopflerfish.service.log
trayicon_fw-4.0.0org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log
log-5.0.0org.knopflerfish.service.log

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/service/um/ipam/IPAMValuationService.java
org/knopflerfish/service/um/ipam/Levels.java
org/knopflerfish/service/um/useradmin/BackEndControl.java
org/knopflerfish/service/um/useradmin/BackEndException.java
org/knopflerfish/service/um/useradmin/Condition.java
org/knopflerfish/service/um/useradmin/ContextualAuthorization.java
org/knopflerfish/service/um/useradmin/PasswdAuthenticator.java
org/knopflerfish/service/um/useradmin/PasswdSession.java
org/knopflerfish/service/um/useradmin/PasswdUtil.java
org/knopflerfish/service/um/useradmin/impl/Activator.java
org/knopflerfish/service/um/useradmin/impl/AuthorizationImpl.java
org/knopflerfish/service/um/useradmin/impl/ConditionImpl.java
org/knopflerfish/service/um/useradmin/impl/EventQueue.java
org/knopflerfish/service/um/useradmin/impl/GroupImpl.java
org/knopflerfish/service/um/useradmin/impl/LDAPQuery.java
org/knopflerfish/service/um/useradmin/impl/RoleImpl.java
org/knopflerfish/service/um/useradmin/impl/SendUserAdminEventJob.java
org/knopflerfish/service/um/useradmin/impl/UACredentials.java
org/knopflerfish/service/um/useradmin/impl/UAProperties.java
org/knopflerfish/service/um/useradmin/impl/UserAdminImpl.java
org/knopflerfish/service/um/useradmin/impl/UserImpl.java
org/osgi/service/useradmin/Authorization.java
org/osgi/service/useradmin/Group.java
org/osgi/service/useradmin/Role.java
org/osgi/service/useradmin/User.java
org/osgi/service/useradmin/UserAdmin.java
org/osgi/service/useradmin/UserAdminEvent.java
org/osgi/service/useradmin/UserAdminListener.java
org/osgi/service/useradmin/UserAdminPermission.java
org/osgi/service/useradmin/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/useradmin/useradmin_api-4.1.1.html0000644000175000017500000003702712346515430024205 0ustar felixfelix useradmin_api-4.1.1.jar

useradmin_api-4.1.1.jar

download (15225 bytes)

OSGi manifest attributes
Bundle-Name UserAdmin-API
Bundle-SymbolicName org.knopflerfish.bundle.useradmin-API
Bundle-Version 4.1.1
Bundle-Description User Administration Service (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.um.ipam 1.0.0
org.knopflerfish.service.um.useradmin 1.0.0
org.osgi.service.useradmin 1.1.0
Import-Package org.knopflerfish.service.um.ipam [1.0.0,2.0.0)
org.knopflerfish.service.um.useradmin [1.0.0,2.0.0)
org.osgi.framework 0.0.0
org.osgi.service.useradmin [1.1.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:27:56
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/useradmin
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/useradmin/
Bundle-UUID org.knopflerfish:useradmin:4.1.1:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

useradmin_all-4.1.1org.knopflerfish.service.um.ipam, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin_api-4.1.1org.knopflerfish.service.um.ipam, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

consoletcp_all-5.0.0org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
consoletcp-5.0.0org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
consoletelnet-4.0.1org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin_all-4.1.1org.knopflerfish.service.um.ipam, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin_api-4.1.1org.knopflerfish.service.um.ipam, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin-4.1.1org.knopflerfish.service.um.ipam, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/service/um/ipam/IPAMValuationService.java
org/knopflerfish/service/um/ipam/Levels.java
org/knopflerfish/service/um/useradmin/BackEndControl.java
org/knopflerfish/service/um/useradmin/BackEndException.java
org/knopflerfish/service/um/useradmin/Condition.java
org/knopflerfish/service/um/useradmin/ContextualAuthorization.java
org/knopflerfish/service/um/useradmin/PasswdAuthenticator.java
org/knopflerfish/service/um/useradmin/PasswdSession.java
org/knopflerfish/service/um/useradmin/PasswdUtil.java
org/knopflerfish/service/um/useradmin/impl/Activator.java
org/knopflerfish/service/um/useradmin/impl/AuthorizationImpl.java
org/knopflerfish/service/um/useradmin/impl/ConditionImpl.java
org/knopflerfish/service/um/useradmin/impl/EventQueue.java
org/knopflerfish/service/um/useradmin/impl/GroupImpl.java
org/knopflerfish/service/um/useradmin/impl/LDAPQuery.java
org/knopflerfish/service/um/useradmin/impl/RoleImpl.java
org/knopflerfish/service/um/useradmin/impl/SendUserAdminEventJob.java
org/knopflerfish/service/um/useradmin/impl/UACredentials.java
org/knopflerfish/service/um/useradmin/impl/UAProperties.java
org/knopflerfish/service/um/useradmin/impl/UserAdminImpl.java
org/knopflerfish/service/um/useradmin/impl/UserImpl.java
org/osgi/service/useradmin/Authorization.java
org/osgi/service/useradmin/Group.java
org/osgi/service/useradmin/Role.java
org/osgi/service/useradmin/User.java
org/osgi/service/useradmin/UserAdmin.java
org/osgi/service/useradmin/UserAdminEvent.java
org/osgi/service/useradmin/UserAdminListener.java
org/osgi/service/useradmin/UserAdminPermission.java
org/osgi/service/useradmin/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/rxtxcomm-linux-x86/0000755000175000017500000000000012475375714021515 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/rxtxcomm-linux-x86/rxtxcomm-linux-x86-2.2.0.pre2.html0000644000175000017500000000746312346515430027346 0ustar felixfelix rxtxcomm-linux-x86-2.2.0.pre2.jar

rxtxcomm-linux-x86-2.2.0.pre2.jar

download (91325 bytes)

OSGi manifest attributes
Bundle-Name RXTXcomm-linux-x86-LIB
Bundle-SymbolicName org.knopflerfish.bundle.rxtxcomm-linux-x86-LIB
Bundle-Version 2.2.0.pre2
Bundle-Description RXTX comm native driver for Linux/x86 (LIB)
Bundle-Vendor Knopflerfish/Piayda/RXTX
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=serial
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package
Import-Package
Dynamic-ImportPackage
Provide-Capability
Require-Capability
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:22
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/serial/rxtxcomm-linux-x86
Bundle-Category utility
Bundle-NativeCode librxtxParallel.so; librxtxSerial.so ;osname = Linux ;processor = x86
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/serial/rxtxcomm-linux-arm/
Bundle-UUID org.knopflerfish:rxtxcomm-linux-x86:2.2.0.pre2:lib
Fragment-Host org.knopflerfish.bundle.rxtxcomm-API
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

None found

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle. None found knopflerfish-osgi-5.1.0/docs/jars/trayicon_fw/0000755000175000017500000000000012475375714020400 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/trayicon_fw/trayicon_fw-4.0.0.html0000644000175000017500000001474012346515430024241 0ustar felixfelix trayicon_fw-4.0.0.jar

trayicon_fw-4.0.0.jar

download (13109 bytes)

OSGi manifest attributes
Bundle-Name FW-Tray
Bundle-SymbolicName org.knopflerfish.bundle.trayicon_fw
Bundle-Version 4.0.0
Bundle-Description Framework tray icon. Allows basic control of the framework using the windows system tray.
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL https://www.knopflerfish.org/svn/knopflerfish.org/trunk/osgi/bundles/trayicon/trayicon_fw/readme.txt
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.trayicons.framework.Activator
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.log [1.2.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.framework.startlevel [1.0.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=1.6))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:39
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/trayicon/trayicon_fw
Bundle-Category management
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/trayicon/trayicon_fw/
Bundle-UUID org.knopflerfish:trayicon_fw:4.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.log
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework, org.osgi.framework.startlevel
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/trayicons/framework/Activator.java
org/knopflerfish/bundle/trayicons/framework/FrameworkTrayIcon.java
knopflerfish-osgi-5.1.0/docs/jars/log/0000755000175000017500000000000012475375714016635 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/log/log_all-5.0.0.html0000644000175000017500000005273212346515430021567 0ustar felixfelix log_all-5.0.0.jar

log_all-5.0.0.jar

download (42745 bytes)

OSGi manifest attributes
Bundle-Name Log Service
Bundle-SymbolicName org.knopflerfish.log
Bundle-Version 5.0.0
Bundle-Description The Knopflerfish OSGi log service
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=log/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.log.Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.log 1.2.0
org.osgi.service.log 1.3.0
Import-Package org.knopflerfish.service.log [1.2.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service; objectClass:List="org.osgi.service.cm.ManagedService, org.knopflerfish.service.log.LogConfig"; service.pid=org.knopflerfish.bundle.log.LogConfig,osgi.service; objectClass:List="org.osgi.service.log.LogReaderService",osgi.service; objectClass:List="org.osgi.service.log.LogService, org.knopflerfish.service.log.LogService"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:38
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/log
Bundle-APIVendor OSGi/Knopflerfish
Bundle-Category osgi
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/log/
Bundle-UUID org.knopflerfish:log:5.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.cm, org.osgi.service.log
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

basicdriverlocator_all-4.0.0org.knopflerfish.service.log
basicdriverlocator-4.0.0org.knopflerfish.service.log
cm_all-5.0.1org.knopflerfish.service.log
cm-5.0.1org.knopflerfish.service.log
cm_desktop_all-5.0.2org.knopflerfish.service.log
cm_desktop-5.0.2org.knopflerfish.service.log
commandtty-4.0.1org.osgi.service.log
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
component_all-5.0.3org.osgi.service.log
console_all-4.0.1org.osgi.service.log
console-4.0.1org.osgi.service.log
console2command-2.0.0org.osgi.service.log
consoletcp_all-5.0.0org.osgi.service.log
consoletcp-5.0.0org.osgi.service.log
consoletelnet-4.0.1org.knopflerfish.service.log
consoletty-4.0.1org.osgi.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.log
desktop-5.0.1org.knopflerfish.service.log, org.osgi.service.log
desktop_jvm_all-1.0.0org.knopflerfish.service.log
desktop_jvm-1.0.0org.knopflerfish.service.log
device_all-4.0.1org.osgi.service.log
device-4.0.1org.osgi.service.log
dirdeployer_all-4.0.1org.osgi.service.log
event_all-4.0.1org.knopflerfish.service.log, org.osgi.service.log
http_all-4.0.5org.knopflerfish.service.log, org.osgi.service.log
http-4.0.5org.knopflerfish.service.log, org.osgi.service.log
httpconsole_all-4.0.1org.knopflerfish.service.log
httproot-4.0.0org.knopflerfish.service.log
kf_metatype_all-5.0.2org.knopflerfish.service.log
logcommands-5.0.0org.knopflerfish.service.log, org.osgi.service.log
prefs_all-4.0.2org.knopflerfish.service.log
repository_desktop_all-1.1.1org.knopflerfish.service.log
serialportdevice_all-4.0.0org.knopflerfish.service.log
sslj2sp-4.0.0org.osgi.service.log
trayicon_fw-4.0.0org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log, org.osgi.service.log
useradmin-4.1.1org.knopflerfish.service.log, org.osgi.service.log
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/log/Activator.java
org/knopflerfish/bundle/log/FileLog.java
org/knopflerfish/bundle/log/LogConfigImpl.java
org/knopflerfish/bundle/log/LogEntryImpl.java
org/knopflerfish/bundle/log/LogFrameworkListener.java
org/knopflerfish/bundle/log/LogReaderServiceFactory.java
org/knopflerfish/bundle/log/LogReaderServiceImpl.java
org/knopflerfish/bundle/log/LogServiceFactory.java
org/knopflerfish/bundle/log/LogServiceImpl.java
org/knopflerfish/service/log/LogConfig.java
org/knopflerfish/service/log/LogRef.java
org/knopflerfish/service/log/LogService.java
org/knopflerfish/service/log/LogUtil.java
org/osgi/service/log/LogEntry.java
org/osgi/service/log/LogListener.java
org/osgi/service/log/LogReaderService.java
org/osgi/service/log/LogService.java
org/osgi/service/log/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/log/log-5.0.0.html0000644000175000017500000002625312346515430020736 0ustar felixfelix log-5.0.0.jar

log-5.0.0.jar

download (34626 bytes)

OSGi manifest attributes
Bundle-Name Log Service-IMPL
Bundle-SymbolicName org.knopflerfish.log-IMPL
Bundle-Version 5.0.0
Bundle-Description The Knopflerfish OSGi log service (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=log/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.log.Activator
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.log [1.2.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service; objectClass:List="org.osgi.service.cm.ManagedService, org.knopflerfish.service.log.LogConfig"; service.pid=org.knopflerfish.bundle.log.LogConfig,osgi.service; objectClass:List="org.osgi.service.log.LogReaderService",osgi.service; objectClass:List="org.osgi.service.log.LogService, org.knopflerfish.service.log.LogService"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:38
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/log
Bundle-APIVendor OSGi/Knopflerfish
Bundle-Category osgi
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/log/
Bundle-UUID org.knopflerfish:log:5.0.0:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.cm, org.osgi.service.log
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/log/Activator.java
org/knopflerfish/bundle/log/FileLog.java
org/knopflerfish/bundle/log/LogConfigImpl.java
org/knopflerfish/bundle/log/LogEntryImpl.java
org/knopflerfish/bundle/log/LogFrameworkListener.java
org/knopflerfish/bundle/log/LogReaderServiceFactory.java
org/knopflerfish/bundle/log/LogReaderServiceImpl.java
org/knopflerfish/bundle/log/LogServiceFactory.java
org/knopflerfish/bundle/log/LogServiceImpl.java
org/knopflerfish/service/log/LogConfig.java
org/knopflerfish/service/log/LogRef.java
org/knopflerfish/service/log/LogService.java
org/knopflerfish/service/log/LogUtil.java
org/osgi/service/log/LogEntry.java
org/osgi/service/log/LogListener.java
org/osgi/service/log/LogReaderService.java
org/osgi/service/log/LogService.java
org/osgi/service/log/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/log/log_api-5.0.0.html0000644000175000017500000005064212346515430021566 0ustar felixfelix log_api-5.0.0.jar

log_api-5.0.0.jar

download (9179 bytes)

OSGi manifest attributes
Bundle-Name Log Service-API
Bundle-SymbolicName org.knopflerfish.log-API
Bundle-Version 5.0.0
Bundle-Description The Knopflerfish OSGi log service (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=log/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.log 1.2.0
org.osgi.service.log 1.3.0
Import-Package org.knopflerfish.service.log [1.2.0,2.0.0)
org.osgi.framework 0.0.0
org.osgi.service.log [1.3.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:38
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/log
Bundle-APIVendor OSGi/Knopflerfish
Bundle-Category API
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/log/
Bundle-UUID org.knopflerfish:log:5.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.log
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

basicdriverlocator_all-4.0.0org.knopflerfish.service.log
basicdriverlocator-4.0.0org.knopflerfish.service.log
cm_all-5.0.1org.knopflerfish.service.log
cm-5.0.1org.knopflerfish.service.log
cm_desktop_all-5.0.2org.knopflerfish.service.log
cm_desktop-5.0.2org.knopflerfish.service.log
commandtty-4.0.1org.osgi.service.log
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
component_all-5.0.3org.osgi.service.log
console_all-4.0.1org.osgi.service.log
console-4.0.1org.osgi.service.log
console2command-2.0.0org.osgi.service.log
consoletcp_all-5.0.0org.osgi.service.log
consoletcp-5.0.0org.osgi.service.log
consoletelnet-4.0.1org.knopflerfish.service.log
consoletty-4.0.1org.osgi.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.log
desktop-5.0.1org.knopflerfish.service.log, org.osgi.service.log
desktop_jvm_all-1.0.0org.knopflerfish.service.log
desktop_jvm-1.0.0org.knopflerfish.service.log
device_all-4.0.1org.osgi.service.log
device-4.0.1org.osgi.service.log
dirdeployer_all-4.0.1org.osgi.service.log
event_all-4.0.1org.knopflerfish.service.log, org.osgi.service.log
http_all-4.0.5org.knopflerfish.service.log, org.osgi.service.log
http-4.0.5org.knopflerfish.service.log, org.osgi.service.log
httpconsole_all-4.0.1org.knopflerfish.service.log
httproot-4.0.0org.knopflerfish.service.log
kf_metatype_all-5.0.2org.knopflerfish.service.log
logcommands-5.0.0org.knopflerfish.service.log, org.osgi.service.log
prefs_all-4.0.2org.knopflerfish.service.log
repository_desktop_all-1.1.1org.knopflerfish.service.log
serialportdevice_all-4.0.0org.knopflerfish.service.log
sslj2sp-4.0.0org.osgi.service.log
trayicon_fw-4.0.0org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log, org.osgi.service.log
useradmin-4.1.1org.knopflerfish.service.log, org.osgi.service.log
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/log/Activator.java
org/knopflerfish/bundle/log/FileLog.java
org/knopflerfish/bundle/log/LogConfigImpl.java
org/knopflerfish/bundle/log/LogEntryImpl.java
org/knopflerfish/bundle/log/LogFrameworkListener.java
org/knopflerfish/bundle/log/LogReaderServiceFactory.java
org/knopflerfish/bundle/log/LogReaderServiceImpl.java
org/knopflerfish/bundle/log/LogServiceFactory.java
org/knopflerfish/bundle/log/LogServiceImpl.java
org/knopflerfish/service/log/LogConfig.java
org/knopflerfish/service/log/LogRef.java
org/knopflerfish/service/log/LogService.java
org/knopflerfish/service/log/LogUtil.java
org/osgi/service/log/LogEntry.java
org/osgi/service/log/LogListener.java
org/osgi/service/log/LogReaderService.java
org/osgi/service/log/LogService.java
org/osgi/service/log/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/position/0000755000175000017500000000000012475375714017720 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/position/position-4.0.0.html0000644000175000017500000001165712346515430023105 0ustar felixfelix position-4.0.0.jar

position-4.0.0.jar

download (4350 bytes)

OSGi manifest attributes
Bundle-Name position-LIB
Bundle-SymbolicName org.knopflerfish.bundle.position-LIB
Bundle-Version 4.0.0
Bundle-Description Position API (LIB)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.util.position 1.0.1
Import-Package org.osgi.util.measurement [1.0.0,2.0.0)
org.osgi.util.position [1.0.0,1.1.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:15
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/position
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/position/
Bundle-UUID org.knopflerfish:position:4.0.0:lib
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

measurement-4.0.0org.osgi.util.measurement
position-4.0.0org.osgi.util.position

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

position-4.0.0org.osgi.util.position

Bundle source

Here are links to the source files of this bundle.
org/osgi/util/position/Position.java
org/osgi/util/position/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/commons-logging/0000755000175000017500000000000012475375714021153 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/commons-logging/commons-logging_all-2.0.0.kf4-001.html0000644000175000017500000004714012346515426027403 0ustar felixfelix commons-logging_all-2.0.0.kf4-001.jar

commons-logging_all-2.0.0.kf4-001.jar

download (37649 bytes)

OSGi manifest attributes
Bundle-Name Commons-Logging
Bundle-SymbolicName org.knopflerfish.bundle.commons-logging
Bundle-Version 2.0.0.kf4-001
Bundle-Description Apache Commons logging. Publishced under Apache License. See http://www.apache.org/licenses/LICENSE-2.0
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL https://www.knopflerfish.org/svn/knopflerfish.org/trunk/osgi/bundles_opt/commons-logging/readme.txt
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.commons.logging.Activator
Bundle-Classpath .
Export-Package org.apache.commons.logging 1.0.3
org.knopflerfish.service.log 1.2.0
org.osgi.service.log 1.3.0
Import-Package org.apache.commons.logging [1.0.3,2.0.0)
org.knopflerfish.service.log [1.2.0,2.0.0)
org.osgi.framework 0.0.0
org.osgi.service.log [1.3.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:05
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/commons-logging
Bundle-APIVendor Knopflerfish/Apache
Bundle-Category lib
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/commons-logging/
Bundle-UUID org.knopflerfish:commons-logging:2.0.0.kf4-001
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.apache.commons.logging, org.knopflerfish.service.log, org.osgi.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.log
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

basicdriverlocator_all-4.0.0org.knopflerfish.service.log
basicdriverlocator-4.0.0org.knopflerfish.service.log
cm_all-5.0.1org.knopflerfish.service.log
cm-5.0.1org.knopflerfish.service.log
cm_desktop_all-5.0.2org.knopflerfish.service.log
cm_desktop-5.0.2org.knopflerfish.service.log
commandtty-4.0.1org.osgi.service.log
commons-logging_all-2.0.0.kf4-001org.apache.commons.logging, org.knopflerfish.service.log, org.osgi.service.log
component_all-5.0.3org.osgi.service.log
console_all-4.0.1org.osgi.service.log
console-4.0.1org.osgi.service.log
console2command-2.0.0org.osgi.service.log
consoletcp_all-5.0.0org.osgi.service.log
consoletcp-5.0.0org.osgi.service.log
consoletelnet-4.0.1org.knopflerfish.service.log
consoletty-4.0.1org.osgi.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.log
desktop-5.0.1org.knopflerfish.service.log, org.osgi.service.log
desktop_jvm_all-1.0.0org.knopflerfish.service.log
desktop_jvm-1.0.0org.knopflerfish.service.log
device_all-4.0.1org.osgi.service.log
device-4.0.1org.osgi.service.log
dirdeployer_all-4.0.1org.osgi.service.log
event_all-4.0.1org.knopflerfish.service.log, org.osgi.service.log
http_all-4.0.5org.knopflerfish.service.log, org.osgi.service.log
http-4.0.5org.knopflerfish.service.log, org.osgi.service.log
httpconsole_all-4.0.1org.knopflerfish.service.log
httproot-4.0.0org.knopflerfish.service.log
kf_metatype_all-5.0.2org.knopflerfish.service.log
logcommands-5.0.0org.knopflerfish.service.log, org.osgi.service.log
prefs_all-4.0.2org.knopflerfish.service.log
repository_desktop_all-1.1.1org.knopflerfish.service.log
serialportdevice_all-4.0.0org.knopflerfish.service.log
sslj2sp-4.0.0org.osgi.service.log
trayicon_fw-4.0.0org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log, org.osgi.service.log
useradmin-4.1.1org.knopflerfish.service.log, org.osgi.service.log
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Bundle source

Here are links to the source files of this bundle.
org/apache/commons/logging/Log.java
org/apache/commons/logging/LogConfigurationException.java
org/apache/commons/logging/LogFactory.java
org/apache/commons/logging/LogSource.java
org/apache/commons/logging/impl/LogFactoryImpl.java
org/apache/commons/logging/impl/NoOpLog.java
org/apache/commons/logging/impl/SimpleLog.java
org/knopflerfish/bundle/commons/logging/Activator.java
org/knopflerfish/bundle/commons/logging/LogFactoryOSGI.java
org/knopflerfish/bundle/commons/logging/LogOSGI.java
knopflerfish-osgi-5.1.0/docs/jars/cm_desktop/0000755000175000017500000000000012475375714020204 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/cm_desktop/cm_desktop_all-5.0.2.html0000644000175000017500000003442212346515426024510 0ustar felixfelix cm_desktop_all-5.0.2.jar

cm_desktop_all-5.0.2.jar

download (94485 bytes)

OSGi manifest attributes
Bundle-Name CM-Desktop
Bundle-SymbolicName org.knopflerfish.bundle.cm_desktop
Bundle-Version 5.0.2
Bundle-Description CM desktop plugin
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL https://www.knopflerfish.org/svn/knopflerfish.org/trunk/osgi/bundles/metatype/cm_desktop/readme.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.desktop.cm.Activator
Bundle-Classpath .
Export-Package org.knopflerfish.shared.cm 1.1.0
Import-Package javax.swing 0.0.0
javax.swing.border 0.0.0
javax.swing.event 0.0.0
javax.swing.filechooser 0.0.0
javax.swing.table 0.0.0
javax.swing.text 0.0.0
javax.swing.text.html 0.0.0
org.knopflerfish.service.desktop [2.2.0,3.0.0)
org.knopflerfish.service.log 0.0.0
org.knopflerfish.shared.cm [1.1.0,2.0.0)
org.knopflerfish.util.metatype 0.0.0
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.5.0,2.0.0)
org.osgi.service.metatype [1.2.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service; objectClass:List="org.osgi.service.cm.ConfigurationListener",osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"
Require-Capability osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=1.5))",osgi.service;objectClass:List="org.osgi.service.metatype.MetaTypeService"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:37
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/metatype/cm_desktop
Bundle-Category management
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/metatype/cm_desktop/
Bundle-UUID org.knopflerfish:cm_desktop:5.0.2
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.knopflerfish.shared.cm, org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
cm-5.0.1org.knopflerfish.shared.cm
cm_desktop_all-5.0.2org.knopflerfish.shared.cm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.desktop, org.knopflerfish.service.log, org.osgi.service.cm
desktop_api-5.0.1org.knopflerfish.service.desktop
dirdeployer_all-4.0.1org.knopflerfish.shared.cm
http_all-4.0.5org.knopflerfish.service.log
kf_metatype_all-5.0.2org.knopflerfish.util.metatype
metatype-4.0.0org.osgi.service.metatype
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

cm_all-5.0.1org.knopflerfish.shared.cm
cm-5.0.1org.knopflerfish.shared.cm
cm_cmd-5.0.1org.knopflerfish.shared.cm
cm_desktop_all-5.0.2org.knopflerfish.shared.cm
cm_desktop-5.0.2org.knopflerfish.shared.cm
dirdeployer_all-4.0.1org.knopflerfish.shared.cm

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/desktop/cm/Activator.java
org/knopflerfish/bundle/desktop/cm/CMDisplayer.java
org/knopflerfish/bundle/desktop/cm/ControlPanel.java
org/knopflerfish/bundle/desktop/cm/DefaultSwingBundleDisplayer.java
org/knopflerfish/bundle/desktop/cm/FileFilterImpl.java
org/knopflerfish/bundle/desktop/cm/JCMInfo.java
org/knopflerfish/bundle/desktop/cm/JCMProp.java
org/knopflerfish/bundle/desktop/cm/JCMService.java
org/knopflerfish/bundle/desktop/cm/JLabelled.java
org/knopflerfish/bundle/desktop/cm/JNumber.java
org/knopflerfish/bundle/desktop/cm/JVector.java
org/knopflerfish/bundle/desktop/cm/PropertiesPanel.java
org/knopflerfish/bundle/desktop/cm/SystemMetaTypeInformation.java
org/knopflerfish/bundle/desktop/cm/TargetPanel.java
org/knopflerfish/bundle/desktop/cm/Util.java
knopflerfish-osgi-5.1.0/docs/jars/cm_desktop/cm_desktop-5.0.2.html0000644000175000017500000003161212346515426023656 0ustar felixfelix cm_desktop-5.0.2.jar

cm_desktop-5.0.2.jar

download (77382 bytes)

OSGi manifest attributes
Bundle-Name CM-Desktop-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.cm_desktop-IMPL
Bundle-Version 5.0.2
Bundle-Description CM desktop plugin (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL https://www.knopflerfish.org/svn/knopflerfish.org/trunk/osgi/bundles/metatype/cm_desktop/readme.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.desktop.cm.Activator
Bundle-Classpath .
Export-Package
Import-Package javax.swing 0.0.0
javax.swing.border 0.0.0
javax.swing.event 0.0.0
javax.swing.filechooser 0.0.0
javax.swing.table 0.0.0
javax.swing.text 0.0.0
javax.swing.text.html 0.0.0
org.knopflerfish.service.desktop [2.2.0,3.0.0)
org.knopflerfish.service.log 0.0.0
org.knopflerfish.shared.cm [1.1.0,2.0.0)
org.knopflerfish.util.metatype 0.0.0
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.5.0,2.0.0)
org.osgi.service.metatype [1.2.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service; objectClass:List="org.osgi.service.cm.ConfigurationListener",osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"
Require-Capability osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=1.5))",osgi.service;objectClass:List="org.osgi.service.metatype.MetaTypeService"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:37
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/metatype/cm_desktop
Bundle-Category management
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/metatype/cm_desktop/
Bundle-UUID org.knopflerfish:cm_desktop:5.0.2:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.knopflerfish.shared.cm, org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
cm-5.0.1org.knopflerfish.shared.cm
cm_desktop_all-5.0.2org.knopflerfish.shared.cm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.desktop, org.knopflerfish.service.log, org.osgi.service.cm
desktop_api-5.0.1org.knopflerfish.service.desktop
dirdeployer_all-4.0.1org.knopflerfish.shared.cm
http_all-4.0.5org.knopflerfish.service.log
kf_metatype_all-5.0.2org.knopflerfish.util.metatype
metatype-4.0.0org.osgi.service.metatype
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/desktop/cm/Activator.java
org/knopflerfish/bundle/desktop/cm/CMDisplayer.java
org/knopflerfish/bundle/desktop/cm/ControlPanel.java
org/knopflerfish/bundle/desktop/cm/DefaultSwingBundleDisplayer.java
org/knopflerfish/bundle/desktop/cm/FileFilterImpl.java
org/knopflerfish/bundle/desktop/cm/JCMInfo.java
org/knopflerfish/bundle/desktop/cm/JCMProp.java
org/knopflerfish/bundle/desktop/cm/JCMService.java
org/knopflerfish/bundle/desktop/cm/JLabelled.java
org/knopflerfish/bundle/desktop/cm/JNumber.java
org/knopflerfish/bundle/desktop/cm/JVector.java
org/knopflerfish/bundle/desktop/cm/PropertiesPanel.java
org/knopflerfish/bundle/desktop/cm/SystemMetaTypeInformation.java
org/knopflerfish/bundle/desktop/cm/TargetPanel.java
org/knopflerfish/bundle/desktop/cm/Util.java
knopflerfish-osgi-5.1.0/docs/jars/namespace/0000755000175000017500000000000012475375714020010 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/namespace/namespace_api-1.0.0.html0000644000175000017500000001613712346515430024111 0ustar felixfelix namespace_api-1.0.0.jar

namespace_api-1.0.0.jar

download (3654 bytes)

OSGi manifest attributes
Bundle-Name Namespace-API
Bundle-SymbolicName org.knopflerfish.bundle.namespace-API
Bundle-Version 1.0.0
Bundle-Description OSGi Namespace (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.namespace.contract 1.0.0
org.osgi.namespace.extender 1.0.0
org.osgi.namespace.service 1.0.0
Import-Package org.osgi.namespace.contract [1.0.0,1.1.0)
org.osgi.namespace.extender [1.0.0,1.1.0)
org.osgi.namespace.service [1.0.0,1.1.0)
org.osgi.resource [1.0.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:25:53
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/namespace
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/namespace/
Bundle-UUID org.knopflerfish:namespace:1.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

namespace_api-1.0.0org.osgi.namespace.contract, org.osgi.namespace.extender, org.osgi.namespace.service
frameworkorg.osgi.resource

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

namespace_api-1.0.0org.osgi.namespace.contract, org.osgi.namespace.extender, org.osgi.namespace.service

Bundle source

Here are links to the source files of this bundle.
org/osgi/namespace/contract/ContractNamespace.java
org/osgi/namespace/contract/package-info.java
org/osgi/namespace/extender/ExtenderNamespace.java
org/osgi/namespace/extender/package-info.java
org/osgi/namespace/service/ServiceNamespace.java
org/osgi/namespace/service/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/repository_xml/0000755000175000017500000000000012475375714021153 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/repository_xml/repository_xml_all-1.0.2.html0000644000175000017500000002471412346515430026420 0ustar felixfelix repository_xml_all-1.0.2.jar

repository_xml_all-1.0.2.jar

download (24041 bytes)

OSGi manifest attributes
Bundle-Name repository xml
Bundle-SymbolicName org.knopflerfish.bundle.repository.xml
Bundle-Version 1.0.2
Bundle-Description Xml Backed Repository
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.repository.Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.repository 1.0.0
Import-Package org.knopflerfish.service.repository [1.0.0,2.0.0)
org.kxml2.io 0.0.0
org.osgi.framework 0.0.0
org.osgi.resource 0.0.0
org.osgi.service.cm 0.0.0
org.osgi.service.repository 0.0.0
org.osgi.util.tracker 0.0.0
org.xmlpull.v1 0.0.0
Dynamic-ImportPackage
Provide-Capability osgi.service;objectClass:List="org.osgi.service.Repository",osgi.service;objectClass:List="org.knopflerfish.service.repository.XmlBackedRepositoryFactory"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:50
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/repository/repository_xml
Bundle-Category utility
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/repository/repository_xml
Bundle-UUID org.knopflerfish:repository_xml:1.0.2
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
desktop_all-5.0.1org.osgi.service.cm
kxml-2.3.0.kf4-001org.kxml2.io, org.xmlpull.v1
repository_api-1.0.0org.osgi.service.repository
repository_xml_all-1.0.2org.knopflerfish.service.repository
repository_xml_api-1.0.2org.knopflerfish.service.repository
repositorymanager_all-1.2.0org.osgi.service.repository
frameworkorg.osgi.framework, org.osgi.resource, org.osgi.util.tracker

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

repository_xml_all-1.0.2org.knopflerfish.service.repository
repository_xml_api-1.0.2org.knopflerfish.service.repository
repositorymanager_all-1.2.0org.knopflerfish.service.repository

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/repository/Activator.java
org/knopflerfish/bundle/repository/FactoryImpl.java
org/knopflerfish/bundle/repository/RepositoryImpl.java
org/knopflerfish/bundle/repository/xml/CapabilityImpl.java
org/knopflerfish/bundle/repository/xml/Data.java
org/knopflerfish/bundle/repository/xml/RepositoryXmlParser.java
org/knopflerfish/bundle/repository/xml/RequirementImpl.java
org/knopflerfish/bundle/repository/xml/ResourceImpl.java
org/knopflerfish/service/repository/XmlBackedRepositoryFactory.java
org/knopflerfish/service/repository/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/repository_xml/repository_xml_api-1.0.2.html0000644000175000017500000002044412346515430026415 0ustar felixfelix repository_xml_api-1.0.2.jar

repository_xml_api-1.0.2.jar

download (2056 bytes)

OSGi manifest attributes
Bundle-Name repository xml-API
Bundle-SymbolicName org.knopflerfish.bundle.repository.xml-API
Bundle-Version 1.0.2
Bundle-Description Xml Backed Repository (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.repository 1.0.0
Import-Package org.knopflerfish.service.repository [1.0.0,2.0.0)
org.osgi.framework 0.0.0
Dynamic-ImportPackage
Provide-Capability osgi.service;objectClass:List="org.osgi.service.Repository",osgi.service;objectClass:List="org.knopflerfish.service.repository.XmlBackedRepositoryFactory"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:50
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/repository/repository_xml
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/repository/repository_xml
Bundle-UUID org.knopflerfish:repository_xml:1.0.2:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

repository_xml_all-1.0.2org.knopflerfish.service.repository
repository_xml_api-1.0.2org.knopflerfish.service.repository
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

repository_xml_all-1.0.2org.knopflerfish.service.repository
repository_xml_api-1.0.2org.knopflerfish.service.repository
repositorymanager_all-1.2.0org.knopflerfish.service.repository

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/repository/Activator.java
org/knopflerfish/bundle/repository/FactoryImpl.java
org/knopflerfish/bundle/repository/RepositoryImpl.java
org/knopflerfish/bundle/repository/xml/CapabilityImpl.java
org/knopflerfish/bundle/repository/xml/Data.java
org/knopflerfish/bundle/repository/xml/RepositoryXmlParser.java
org/knopflerfish/bundle/repository/xml/RequirementImpl.java
org/knopflerfish/bundle/repository/xml/ResourceImpl.java
org/knopflerfish/service/repository/XmlBackedRepositoryFactory.java
org/knopflerfish/service/repository/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/rxtxcomm/0000755000175000017500000000000012475375714017735 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/rxtxcomm/rxtxcomm_api-2.2.0.pre2.html0000644000175000017500000002522312346515430024631 0ustar felixfelix rxtxcomm_api-2.2.0.pre2.jar

rxtxcomm_api-2.2.0.pre2.jar

download (66938 bytes)

OSGi manifest attributes
Bundle-Name RXTXcomm-API
Bundle-SymbolicName org.knopflerfish.bundle.rxtxcomm-API
Bundle-Version 2.2.0.pre2
Bundle-Description RXTX comm java library, requires native driver fragment (API)
Bundle-Vendor Knopflerfish/Piayda/RXTX
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=serial
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package gnu.io 2.2.0
Import-Package gnu.io [2.2.0,3.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:17
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/serial/rxtxcomm
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/serial/rxtxcomm/
Bundle-UUID org.knopflerfish:rxtxcomm:2.2.0.pre2:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

rxtxcomm_api-2.2.0.pre2gnu.io

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

comm-linux_all-3.0.0gnu.io
rxtxcomm_api-2.2.0.pre2gnu.io

Bundle source

Here are links to the source files of this bundle.
gnu/io/CommDriver.java
gnu/io/CommPort.java
gnu/io/CommPortEnumerator.java
gnu/io/CommPortIdentifier.java
gnu/io/CommPortOwnershipListener.java
gnu/io/Configure.java
gnu/io/I2C.java
gnu/io/I2CPort.java
gnu/io/I2CPortEvent.java
gnu/io/I2CPortEventListener.java
gnu/io/LPRPort.java
gnu/io/NoSuchPortException.java
gnu/io/ParallelPort.java
gnu/io/ParallelPortEvent.java
gnu/io/ParallelPortEventListener.java
gnu/io/PortInUseException.java
gnu/io/RS485.java
gnu/io/RS485Port.java
gnu/io/RS485PortEvent.java
gnu/io/RS485PortEventListener.java
gnu/io/RXTXCommDriver.java
gnu/io/RXTXPort.java
gnu/io/RXTXVersion.java
gnu/io/Raw.java
gnu/io/RawPort.java
gnu/io/RawPortEvent.java
gnu/io/RawPortEventListener.java
gnu/io/SerialPort.java
gnu/io/SerialPortEvent.java
gnu/io/SerialPortEventListener.java
gnu/io/UnSupportedLoggerException.java
gnu/io/UnsupportedCommOperationException.java
gnu/io/Zystem.java
knopflerfish-osgi-5.1.0/docs/jars/header.html0000644000175000017500000000400712346515430020157 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/jars/repositorymanager/0000755000175000017500000000000012475375714021626 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/repositorymanager/repositorymanager_all-1.2.0.html0000644000175000017500000003023312346515430027537 0ustar felixfelix repositorymanager_all-1.2.0.jar

repositorymanager_all-1.2.0.jar

download (24908 bytes)

OSGi manifest attributes
Bundle-Name Repository-Manager
Bundle-SymbolicName org.knopflerfish.bundle.repositorymanager
Bundle-Version 1.2.0
Bundle-Description Repository Manager
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org/index.html?docpage=repositorycommands/index.html
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.repositorymanager.Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.repositorymanager 1.2.0
org.osgi.service.repository 1.0.0
org.osgi.service.resolver 1.0.1
Import-Package org.knopflerfish.service.repository [1.0.0,2.0.0)
org.knopflerfish.service.repositorymanager [1.2.0,2.0.0)
org.osgi.framework [1.7.0,2.0.0)
org.osgi.framework.wiring [1.0.0,2.0.0)
org.osgi.resource [1.0.0,2.0.0)
org.osgi.service.repository [1.0.0,2.0.0)
org.osgi.service.resolver [1.0.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service;objectClass:List="org.knopflerfish.service.repositorymanager.RepositoryManager"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:53
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/repository/repositorymanager
Bundle-Category utility
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/repositorymanager/
Bundle-UUID org.knopflerfish:repositorymanager:1.2.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

repository_api-1.0.0org.osgi.service.repository
repository_xml_all-1.0.2org.knopflerfish.service.repository
repository_xml_api-1.0.2org.knopflerfish.service.repository
repositorymanager_all-1.2.0org.knopflerfish.service.repositorymanager, org.osgi.service.repository, org.osgi.service.resolver
repositorymanager_api-1.2.0org.knopflerfish.service.repositorymanager
resolver_api-1.0.0org.osgi.service.resolver
frameworkorg.osgi.framework, org.osgi.framework.wiring, org.osgi.resource, org.osgi.util.tracker

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

repository_api-1.0.0org.osgi.service.repository
repository_xml_all-1.0.2org.osgi.service.repository
repository_desktop_all-1.1.1org.knopflerfish.service.repositorymanager, org.osgi.service.repository
repositorycommands-1.1.1org.knopflerfish.service.repositorymanager, org.osgi.service.repository
repositorymanager_all-1.2.0org.knopflerfish.service.repositorymanager, org.osgi.service.repository, org.osgi.service.resolver
repositorymanager_api-1.2.0org.knopflerfish.service.repositorymanager
resolver_api-1.0.0org.osgi.service.resolver

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/repositorymanager/Activator.java
org/knopflerfish/bundle/repositorymanager/Repositories.java
org/knopflerfish/bundle/repositorymanager/RepositoryListener.java
org/knopflerfish/bundle/repositorymanager/RepositoryManagerImpl.java
org/knopflerfish/bundle/repositorymanager/ResolveContextImpl.java
org/knopflerfish/service/repositorymanager/BasicRequirement.java
org/knopflerfish/service/repositorymanager/RepositoryInfo.java
org/knopflerfish/service/repositorymanager/RepositoryManager.java
knopflerfish-osgi-5.1.0/docs/jars/repositorymanager/repositorymanager_api-1.2.0.html0000644000175000017500000002071512346515430027544 0ustar felixfelix repositorymanager_api-1.2.0.jar

repositorymanager_api-1.2.0.jar

download (6850 bytes)

OSGi manifest attributes
Bundle-Name Repository-Manager-API
Bundle-SymbolicName org.knopflerfish.bundle.repositorymanager-API
Bundle-Version 1.2.0
Bundle-Description Repository Manager (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org/index.html?docpage=repositorycommands/index.html
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.repositorymanager 1.2.0
Import-Package org.knopflerfish.service.repositorymanager [1.2.0,2.0.0)
org.osgi.framework 0.0.0
org.osgi.resource 0.0.0
Dynamic-ImportPackage
Provide-Capability osgi.service;objectClass:List="org.knopflerfish.service.repositorymanager.RepositoryManager"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:53
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/repository/repositorymanager
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/repositorymanager/
Bundle-UUID org.knopflerfish:repositorymanager:1.2.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

repositorymanager_all-1.2.0org.knopflerfish.service.repositorymanager
repositorymanager_api-1.2.0org.knopflerfish.service.repositorymanager
frameworkorg.osgi.framework, org.osgi.resource

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

repository_desktop_all-1.1.1org.knopflerfish.service.repositorymanager
repositorycommands-1.1.1org.knopflerfish.service.repositorymanager
repositorymanager_all-1.2.0org.knopflerfish.service.repositorymanager
repositorymanager_api-1.2.0org.knopflerfish.service.repositorymanager

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/repositorymanager/Activator.java
org/knopflerfish/bundle/repositorymanager/Repositories.java
org/knopflerfish/bundle/repositorymanager/RepositoryListener.java
org/knopflerfish/bundle/repositorymanager/RepositoryManagerImpl.java
org/knopflerfish/bundle/repositorymanager/ResolveContextImpl.java
org/knopflerfish/service/repositorymanager/BasicRequirement.java
org/knopflerfish/service/repositorymanager/RepositoryInfo.java
org/knopflerfish/service/repositorymanager/RepositoryManager.java
knopflerfish-osgi-5.1.0/docs/jars/connectors/0000755000175000017500000000000012475375714020231 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/connectors/connectors_all-3.0.0.html0000644000175000017500000001613712346515426024561 0ustar felixfelix connectors_all-3.0.0.jar

connectors_all-3.0.0.jar

download (17949 bytes)

OSGi manifest attributes
Bundle-Name Connection-Factories
Bundle-SymbolicName org.knopflerfish.bundle.connectors
Bundle-Version 3.0.0
Bundle-Description OSGi IO http, socket and datagram-receive Connectors
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.connectors.Activator
Bundle-Classpath .
Export-Package
Import-Package javax.microedition.io 0.0.0
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.io [1.0.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:36
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/io/connectors
Bundle-Category service
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/io/connectors/
Bundle-UUID org.knopflerfish:connectors:3.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

io_all-4.0.0javax.microedition.io, org.osgi.service.io
io_api-4.0.0javax.microedition.io, org.osgi.service.io
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/connectors/Activator.java
org/knopflerfish/bundle/connectors/BaseConnectionFactory.java
org/knopflerfish/bundle/connectors/datagram/DatagramConnectionAdapter.java
org/knopflerfish/bundle/connectors/datagram/DatagramConnectionFactory.java
org/knopflerfish/bundle/connectors/datagram/DatagramImpl.java
org/knopflerfish/bundle/connectors/http/HttpConnectionAdapter.java
org/knopflerfish/bundle/connectors/http/HttpConnectionFactory.java
org/knopflerfish/bundle/connectors/socket/ServerSocketConnectionImpl.java
org/knopflerfish/bundle/connectors/socket/SocketConnectionFactory.java
org/knopflerfish/bundle/connectors/socket/SocketConnectionImpl.java
knopflerfish-osgi-5.1.0/docs/jars/connectors/connectors-3.0.0.html0000644000175000017500000001615112346515426023725 0ustar felixfelix connectors-3.0.0.jar

connectors-3.0.0.jar

download (17965 bytes)

OSGi manifest attributes
Bundle-Name Connection-Factories-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.connectors-IMPL
Bundle-Version 3.0.0
Bundle-Description OSGi IO http, socket and datagram-receive Connectors (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.connectors.Activator
Bundle-Classpath .
Export-Package
Import-Package javax.microedition.io 0.0.0
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.io [1.0.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:36
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/io/connectors
Bundle-Category service
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/io/connectors/
Bundle-UUID org.knopflerfish:connectors:3.0.0:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

io_all-4.0.0javax.microedition.io, org.osgi.service.io
io_api-4.0.0javax.microedition.io, org.osgi.service.io
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/connectors/Activator.java
org/knopflerfish/bundle/connectors/BaseConnectionFactory.java
org/knopflerfish/bundle/connectors/datagram/DatagramConnectionAdapter.java
org/knopflerfish/bundle/connectors/datagram/DatagramConnectionFactory.java
org/knopflerfish/bundle/connectors/datagram/DatagramImpl.java
org/knopflerfish/bundle/connectors/http/HttpConnectionAdapter.java
org/knopflerfish/bundle/connectors/http/HttpConnectionFactory.java
org/knopflerfish/bundle/connectors/socket/ServerSocketConnectionImpl.java
org/knopflerfish/bundle/connectors/socket/SocketConnectionFactory.java
org/knopflerfish/bundle/connectors/socket/SocketConnectionImpl.java
knopflerfish-osgi-5.1.0/docs/jars/remoteserviceadmin/0000755000175000017500000000000012475375714021741 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/remoteserviceadmin/remoteserviceadmin_api-1.0.0.html0000644000175000017500000001773712346515430030002 0ustar felixfelix remoteserviceadmin_api-1.0.0.jar

remoteserviceadmin_api-1.0.0.jar

download (20605 bytes)

OSGi manifest attributes
Bundle-Name Remote Service Admin-API
Bundle-SymbolicName org.knopflerfish.bundle.remoteserviceadmin-API
Bundle-Version 1.0.0
Bundle-Description OSGi specified remote service admin service (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.remoteserviceadmin 1.0.1
Import-Package org.osgi.framework [1.7.0,2.0.0)
org.osgi.service.remoteserviceadmin [1.0.1,1.1.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:02
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/remoteserviceadmin
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/remoteserviceadmin/
Bundle-UUID org.knopflerfish:remoteserviceadmin:1.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

remoteserviceadmin_api-1.0.0org.osgi.service.remoteserviceadmin
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

remoteserviceadmin_api-1.0.0org.osgi.service.remoteserviceadmin

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/remoteserviceadmin/EndpointDescription.java
org/osgi/service/remoteserviceadmin/EndpointListener.java
org/osgi/service/remoteserviceadmin/EndpointPermission.java
org/osgi/service/remoteserviceadmin/ExportReference.java
org/osgi/service/remoteserviceadmin/ExportRegistration.java
org/osgi/service/remoteserviceadmin/ImportReference.java
org/osgi/service/remoteserviceadmin/ImportRegistration.java
org/osgi/service/remoteserviceadmin/RemoteConstants.java
org/osgi/service/remoteserviceadmin/RemoteServiceAdmin.java
org/osgi/service/remoteserviceadmin/RemoteServiceAdminEvent.java
org/osgi/service/remoteserviceadmin/RemoteServiceAdminListener.java
org/osgi/service/remoteserviceadmin/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/rxtxcomm-linux-arm/0000755000175000017500000000000012475375714021647 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/rxtxcomm-linux-arm/rxtxcomm-linux-arm-2.1.7.1.html0000644000175000017500000000755612346515430027133 0ustar felixfelix rxtxcomm-linux-arm-2.1.7.1.jar

rxtxcomm-linux-arm-2.1.7.1.jar

download (167000 bytes)

OSGi manifest attributes
Bundle-Name RXTXcomm-linux-arm-LIB
Bundle-SymbolicName org.knopflerfish.bundle.rxtxcomm-linux-arm-LIB
Bundle-Version 2.1.7.1
Bundle-Description RXTX comm native driver for Linux/arm_le (LIB)
Bundle-Vendor Knopflerfish/Piayda/RXTX
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=serial
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package
Import-Package
Dynamic-ImportPackage
Provide-Capability
Require-Capability
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:21
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/serial/rxtxcomm-linux-arm
Bundle-Category utility
Bundle-NativeCode librxtxI2C.so; librxtxParallel.so; librxtxRS485.so;librxtxRaw.so; librxtxSerial.so ;osname = Linux ;processor = arm_le; processor = armv4tl
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/serial/rxtxcomm-linux-arm/
Bundle-UUID org.knopflerfish:rxtxcomm-linux-arm:2.1.7.1:lib
Fragment-Host org.knopflerfish.bundle.rxtxcomm-API
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

None found

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle. None found knopflerfish-osgi-5.1.0/docs/jars/repository/0000755000175000017500000000000012475375714020273 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/repository/repository_api-1.0.0.html0000644000175000017500000001561712346515430024661 0ustar felixfelix repository_api-1.0.0.jar

repository_api-1.0.0.jar

download (2728 bytes)

OSGi manifest attributes
Bundle-Name Repository-API
Bundle-SymbolicName org.knopflerfish.bundle.repository-API
Bundle-Version 1.0.0
Bundle-Description Repository API (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.repository 1.0.0
Import-Package org.osgi.resource 0.0.0
org.osgi.service.repository [1.0.0,1.1.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:47
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/repository/repository_api
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/repository/repository_api
Bundle-UUID org.knopflerfish:repository:1.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

repository_api-1.0.0org.osgi.service.repository
repositorymanager_all-1.2.0org.osgi.service.repository
frameworkorg.osgi.resource

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

repository_api-1.0.0org.osgi.service.repository
repository_xml_all-1.0.2org.osgi.service.repository
repository_desktop_all-1.1.1org.osgi.service.repository
repositorycommands-1.1.1org.osgi.service.repository
repositorymanager_all-1.2.0org.osgi.service.repository

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/repository/ContentNamespace.java
org/osgi/service/repository/Repository.java
org/osgi/service/repository/RepositoryContent.java
org/osgi/service/repository/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/consoletty/0000755000175000017500000000000012475375714020257 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/consoletty/consoletty-4.0.1.html0000644000175000017500000001550612346515426024006 0ustar felixfelix consoletty-4.0.1.jar

consoletty-4.0.1.jar

download (8230 bytes)

OSGi manifest attributes
Bundle-Name TTY-Console-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.consoletty-IMPL
Bundle-Version 4.0.1
Bundle-Description Console Service Command Line Console (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.consoletty.ConsoleTty
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.console [2.1.0,3.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:15
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/console/consoletty
Bundle-APIVendor Knopflerfish
Bundle-Category management
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/bundles/console/consoletty/
Bundle-UUID org.knopflerfish:consoletty:4.0.1:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.osgi.service.log
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console, org.osgi.service.cm, org.osgi.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.osgi.service.log
log_api-5.0.0org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/consoletty/ConsoleTty.java
knopflerfish-osgi-5.1.0/docs/jars/metatype/0000755000175000017500000000000012475375714017704 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/metatype/metatype-4.0.0.html0000644000175000017500000001405112346515430023044 0ustar felixfelix metatype-4.0.0.jar

metatype-4.0.0.jar

download (5291 bytes)

OSGi manifest attributes
Bundle-Name metatype-LIB
Bundle-SymbolicName org.knopflerfish.bundle.metatype-LIB
Bundle-Version 4.0.0
Bundle-Description Metatype API (LIB)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.metatype 1.2.0
Import-Package org.osgi.framework [1.6.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:17
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/metatype/metatype_api
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/metatype/metatype_api/
Bundle-UUID org.knopflerfish:metatype:4.0.0:lib
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

cm_desktop_all-5.0.2org.osgi.service.metatype
cm_desktop-5.0.2org.osgi.service.metatype
kf_metatype_all-5.0.2org.osgi.service.metatype

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/metatype/AttributeDefinition.java
org/osgi/service/metatype/MetaTypeInformation.java
org/osgi/service/metatype/MetaTypeProvider.java
org/osgi/service/metatype/MetaTypeService.java
org/osgi/service/metatype/ObjectClassDefinition.java
org/osgi/service/metatype/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/upnp/0000755000175000017500000000000012475375714017036 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/upnp/upnp_api-4.0.0.html0000644000175000017500000001371312346515430022165 0ustar felixfelix upnp_api-4.0.0.jar

upnp_api-4.0.0.jar

download (5849 bytes)

OSGi manifest attributes
Bundle-Name upnp-API
Bundle-SymbolicName org.knopflerfish.bundle.upnp-API
Bundle-Version 4.0.0
Bundle-Description UPnP (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.upnp 1.2.0
Import-Package org.osgi.service.upnp [1.2.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:40
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/upnp
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/upnp/
Bundle-UUID org.knopflerfish:upnp:4.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

upnp_api-4.0.0org.osgi.service.upnp

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

upnp_api-4.0.0org.osgi.service.upnp

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/upnp/UPnPAction.java
org/osgi/service/upnp/UPnPDevice.java
org/osgi/service/upnp/UPnPEventListener.java
org/osgi/service/upnp/UPnPException.java
org/osgi/service/upnp/UPnPIcon.java
org/osgi/service/upnp/UPnPLocalStateVariable.java
org/osgi/service/upnp/UPnPService.java
org/osgi/service/upnp/UPnPStateVariable.java
org/osgi/service/upnp/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/crimson/0000755000175000017500000000000012475375714017526 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/crimson/crimson-2.1.0.kf4-001.html0000644000175000017500000001315712346515426023503 0ustar felixfelix crimson-2.1.0.kf4-001.jar

crimson-2.1.0.kf4-001.jar

download (196914 bytes)

OSGi manifest attributes
Bundle-Name Crimson-XML
Bundle-SymbolicName org.knopflerfish.bundle.crimson
Bundle-Version 2.1.0.kf4-001
Bundle-Description The Crimson XML parser
Bundle-Vendor Apache/Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=crimson/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.osgi.util.xml.XMLParserActivator
Bundle-Classpath .,crimson.jar
Export-Package javax.xml.parsers 1.2.0
org.apache.crimson.jaxp 0.0.0
org.w3c.dom 2.0.0
org.xml.sax 2.0.0
org.xml.sax.ext 1.0.0
org.xml.sax.helpers 2.0.0
Import-Package javax.xml.parsers 0.0.0
org.apache.crimson.jaxp 0.0.0
org.osgi.framework [1.6.0,2.0.0)
org.w3c.dom 0.0.0
org.xml.sax 0.0.0
org.xml.sax.ext 0.0.0
org.xml.sax.helpers 0.0.0
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:27:06
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/xml/crimson
Bundle-Category lib
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/xml/crimson/
Bundle-UUID org.knopflerfish:crimson:2.1.0.kf4-001
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

crimson-2.1.0.kf4-001javax.xml.parsers, org.apache.crimson.jaxp, org.w3c.dom, org.xml.sax, org.xml.sax.ext, org.xml.sax.helpers
xerces-2.10.1.kf5javax.xml.parsers, org.w3c.dom, org.xml.sax, org.xml.sax.ext, org.xml.sax.helpers
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

crimson-2.1.0.kf4-001javax.xml.parsers, org.apache.crimson.jaxp, org.w3c.dom, org.xml.sax, org.xml.sax.ext, org.xml.sax.helpers
junit_all-3.8.1.kf4-001javax.xml.parsers, org.w3c.dom
xalan-2.7.1.kf3_01org.w3c.dom, org.xml.sax, org.xml.sax.ext, org.xml.sax.helpers
xml-4.0.0javax.xml.parsers

Bundle source

Here are links to the source files of this bundle.
javax/xml/parsers/FactoryFinder.java
org/osgi/util/xml/XMLParserActivator.java
knopflerfish-osgi-5.1.0/docs/jars/commandtty/0000755000175000017500000000000012475375714020233 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/commandtty/commandtty-4.0.1.html0000644000175000017500000001505412346515426023734 0ustar felixfelix commandtty-4.0.1.jar

commandtty-4.0.1.jar

download (8047 bytes)

OSGi manifest attributes
Bundle-Name TTY-Command-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.commandtty-IMPL
Bundle-Version 4.0.1
Bundle-Description Command line system console (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.commandtty.CommandTty
Bundle-Classpath .
Export-Package
Import-Package org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.command [1.0.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:25
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/command/commandtty
Bundle-APIVendor Knopflerfish
Bundle-Category management
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/command/commandtty/
Bundle-UUID org.knopflerfish:commandtty:4.0.1:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
command_all-0.2org.osgi.service.command
command_api-0.2org.osgi.service.command
commons-logging_all-2.0.0.kf4-001org.osgi.service.log
desktop_all-5.0.1org.osgi.service.cm, org.osgi.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.osgi.service.log
log_api-5.0.0org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/commandtty/CommandTty.java
knopflerfish-osgi-5.1.0/docs/jars/component_annotations/0000755000175000017500000000000012475375714022473 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/component_annotations/component_annotations_api-1.0.0.html0000644000175000017500000001640212346515426031257 0ustar felixfelix component_annotations_api-1.0.0.jar

component_annotations_api-1.0.0.jar

download (7811 bytes)

OSGi manifest attributes
Bundle-Name Component Annotations-API
Bundle-SymbolicName org.knopflerfish.bundle.component_annotations-API
Bundle-Version 1.0.0
Bundle-Description OSGi specified component annotations (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.component.annotations 1.2.0
Import-Package org.osgi.service.component.annotations [1.2.0,1.3.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=1.5))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:38
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/annotations/component_api
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/annotations/component_api/
Bundle-UUID org.knopflerfish:component_annotations:1.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

component_annotations_api-1.0.0org.osgi.service.component.annotations

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

component_annotations_api-1.0.0org.osgi.service.component.annotations

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/component/annotations/Activate.java
org/osgi/service/component/annotations/Component.java
org/osgi/service/component/annotations/ConfigurationPolicy.java
org/osgi/service/component/annotations/Deactivate.java
org/osgi/service/component/annotations/Modified.java
org/osgi/service/component/annotations/Reference.java
org/osgi/service/component/annotations/ReferenceCardinality.java
org/osgi/service/component/annotations/ReferencePolicy.java
org/osgi/service/component/annotations/ReferencePolicyOption.java
org/osgi/service/component/annotations/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/basicdriverlocator/0000755000175000017500000000000012475375714021735 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/basicdriverlocator/basicdriverlocator-4.0.0.html0000644000175000017500000001541212346515426027135 0ustar felixfelix basicdriverlocator-4.0.0.jar

basicdriverlocator-4.0.0.jar

download (7094 bytes)

OSGi manifest attributes
Bundle-Name basicdriverlocator-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.basicdriverlocator-IMPL
Bundle-Version 4.0.0
Bundle-Description Basic device driver locator (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.basicdriverlocator.Activator
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.log [1.2.0,3.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.device [1.1.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:31
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/device/basicdriverlocator
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/device/basicdriverlocator/
Bundle-UUID org.knopflerfish:basicdriverlocator:4.0.0:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.log
device_all-4.0.1org.osgi.service.device
device_api-4.0.1org.osgi.service.device
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/basicdriverlocator/Activator.java
org/knopflerfish/bundle/basicdriverlocator/BasicDriverLocator.java
knopflerfish-osgi-5.1.0/docs/jars/basicdriverlocator/basicdriverlocator_all-4.0.0.html0000644000175000017500000001540012346515426027762 0ustar felixfelix basicdriverlocator_all-4.0.0.jar

basicdriverlocator_all-4.0.0.jar

download (7077 bytes)

OSGi manifest attributes
Bundle-Name basicdriverlocator
Bundle-SymbolicName org.knopflerfish.bundle.basicdriverlocator
Bundle-Version 4.0.0
Bundle-Description Basic device driver locator
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.basicdriverlocator.Activator
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.log [1.2.0,3.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.device [1.1.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:31
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/device/basicdriverlocator
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/device/basicdriverlocator/
Bundle-UUID org.knopflerfish:basicdriverlocator:4.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.log
device_all-4.0.1org.osgi.service.device
device_api-4.0.1org.osgi.service.device
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/basicdriverlocator/Activator.java
org/knopflerfish/bundle/basicdriverlocator/BasicDriverLocator.java
knopflerfish-osgi-5.1.0/docs/jars/monitor/0000755000175000017500000000000012475375714017543 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/monitor/monitor_api-4.0.0.html0000644000175000017500000001327312346515430023400 0ustar felixfelix monitor_api-4.0.0.jar

monitor_api-4.0.0.jar

download (9454 bytes)

OSGi manifest attributes
Bundle-Name monitor-API
Bundle-SymbolicName org.knopflerfish.bundle.monitor-API
Bundle-Version 4.0.0
Bundle-Description Monitor Admin API (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.monitor 1.0.0
Import-Package org.osgi.service.monitor [1.0.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:59
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/monitor
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/monitor/
Bundle-UUID org.knopflerfish:monitor:4.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

monitor_api-4.0.0org.osgi.service.monitor

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

monitor_api-4.0.0org.osgi.service.monitor

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/monitor/MonitorAdmin.java
org/osgi/service/monitor/MonitorListener.java
org/osgi/service/monitor/MonitorPermission.java
org/osgi/service/monitor/Monitorable.java
org/osgi/service/monitor/MonitoringJob.java
org/osgi/service/monitor/StatusVariable.java
org/osgi/service/monitor/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/event/0000755000175000017500000000000012475375714017175 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/event/event_api-4.0.1.html0000644000175000017500000002273212346515430022465 0ustar felixfelix event_api-4.0.1.jar

event_api-4.0.1.jar

download (13415 bytes)

OSGi manifest attributes
Bundle-Name Event-Admin-API
Bundle-SymbolicName org.knopflerfish.bundle.event-API
Bundle-Version 4.0.1
Bundle-Description Event Admin (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=event/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.event 1.3.0
Import-Package org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.event [1.3.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum) (version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:11
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/event
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/event/
Bundle-UUID org.knopflerfish:event:4.0.1:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

desktop_all-5.0.1org.osgi.service.event
event_all-4.0.1org.osgi.service.event
event_api-4.0.1org.osgi.service.event
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

desktop_all-5.0.1org.osgi.service.event
desktop-5.0.1org.osgi.service.event
event_all-4.0.1org.osgi.service.event
event_api-4.0.1org.osgi.service.event
useradmin_all-4.1.1org.osgi.service.event
useradmin-4.1.1org.osgi.service.event

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/event/Activator.java
org/knopflerfish/bundle/event/ConfigurationListenerImpl.java
org/knopflerfish/bundle/event/EventAdminService.java
org/knopflerfish/bundle/event/EventHandlerTracker.java
org/knopflerfish/bundle/event/InternalAdminEvent.java
org/knopflerfish/bundle/event/MultiListener.java
org/knopflerfish/bundle/event/QueueHandler.java
org/knopflerfish/bundle/event/TimeoutDeliver.java
org/knopflerfish/bundle/event/TrackedEventHandler.java
org/osgi/service/event/Event.java
org/osgi/service/event/EventAdmin.java
org/osgi/service/event/EventConstants.java
org/osgi/service/event/EventHandler.java
org/osgi/service/event/EventProperties.java
org/osgi/service/event/TopicPermission.java
org/osgi/service/event/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/event/event_all-4.0.1.html0000644000175000017500000003107312346515430022462 0ustar felixfelix event_all-4.0.1.jar

event_all-4.0.1.jar

download (40706 bytes)

OSGi manifest attributes
Bundle-Name Event-Admin
Bundle-SymbolicName org.knopflerfish.bundle.event
Bundle-Version 4.0.1
Bundle-Description Event Admin
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=event/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.event.Activator
Bundle-Classpath .
Export-Package org.osgi.service.event 1.3.0
Import-Package org.knopflerfish.service.log [1.2.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.event [1.3.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum) (version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:11
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/event
Bundle-APIVendor OSGi
Bundle-Category service
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/event/
Bundle-UUID org.knopflerfish:event:4.0.1
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.cm, org.osgi.service.event, org.osgi.service.log
event_all-4.0.1org.osgi.service.event
event_api-4.0.1org.osgi.service.event
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

desktop_all-5.0.1org.osgi.service.event
desktop-5.0.1org.osgi.service.event
event_all-4.0.1org.osgi.service.event
event_api-4.0.1org.osgi.service.event
useradmin_all-4.1.1org.osgi.service.event
useradmin-4.1.1org.osgi.service.event

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/event/Activator.java
org/knopflerfish/bundle/event/ConfigurationListenerImpl.java
org/knopflerfish/bundle/event/EventAdminService.java
org/knopflerfish/bundle/event/EventHandlerTracker.java
org/knopflerfish/bundle/event/InternalAdminEvent.java
org/knopflerfish/bundle/event/MultiListener.java
org/knopflerfish/bundle/event/QueueHandler.java
org/knopflerfish/bundle/event/TimeoutDeliver.java
org/knopflerfish/bundle/event/TrackedEventHandler.java
org/osgi/service/event/Event.java
org/osgi/service/event/EventAdmin.java
org/osgi/service/event/EventConstants.java
org/osgi/service/event/EventHandler.java
org/osgi/service/event/EventProperties.java
org/osgi/service/event/TopicPermission.java
org/osgi/service/event/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/component/0000755000175000017500000000000012475375714020056 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/component/component_all-5.0.3.html0000644000175000017500000003675612346515426024251 0ustar felixfelix component_all-5.0.3.jar

component_all-5.0.3.jar

download (78173 bytes)

OSGi manifest attributes
Bundle-Name SCR
Bundle-SymbolicName org.knopflerfish.bundle.component
Bundle-Version 5.0.3
Bundle-Description Declarative Services SCR
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.component.Activator
Bundle-Classpath .
Export-Package org.apache.felix.scr 1.6.0
org.osgi.service.component 1.2.1
Import-Package org.apache.felix.scr [1.6.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.5.0,2.0.0)
org.osgi.service.component [1.2.1,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
org.xmlpull.v1 0.0.0
Dynamic-ImportPackage
Provide-Capability osgi.service;objectClass:List="org.apache.felix.scr.ScrService"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:03
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/component
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/component
Bundle-UUID org.knopflerfish:component:5.0.3
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.osgi.service.log
component_all-5.0.3org.apache.felix.scr, org.osgi.service.component
component_api-5.0.3org.apache.felix.scr, org.osgi.service.component
desktop_all-5.0.1org.apache.felix.scr, org.osgi.service.cm, org.osgi.service.component, org.osgi.service.log
kxml-2.3.0.kf4-001org.xmlpull.v1
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.osgi.service.log
log_api-5.0.0org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

component_all-5.0.3org.apache.felix.scr, org.osgi.service.component
component_api-5.0.3org.apache.felix.scr, org.osgi.service.component
desktop_all-5.0.1org.apache.felix.scr, org.osgi.service.component
desktop-5.0.1org.apache.felix.scr
scrcommands-4.0.1org.apache.felix.scr, org.osgi.service.component

Bundle source

Here are links to the source files of this bundle.
org/apache/felix/scr/Component.java
org/apache/felix/scr/Reference.java
org/apache/felix/scr/ScrService.java
org/knopflerfish/bundle/component/Activator.java
org/knopflerfish/bundle/component/Component.java
org/knopflerfish/bundle/component/ComponentConfiguration.java
org/knopflerfish/bundle/component/ComponentContextImpl.java
org/knopflerfish/bundle/component/ComponentDescription.java
org/knopflerfish/bundle/component/ComponentFactoryImpl.java
org/knopflerfish/bundle/component/ComponentInstanceImpl.java
org/knopflerfish/bundle/component/ComponentMethod.java
org/knopflerfish/bundle/component/DelayedComponent.java
org/knopflerfish/bundle/component/FactoryComponent.java
org/knopflerfish/bundle/component/IllegalXMLException.java
org/knopflerfish/bundle/component/ImmediateComponent.java
org/knopflerfish/bundle/component/PostponedBind.java
org/knopflerfish/bundle/component/PropertyDictionary.java
org/knopflerfish/bundle/component/Reference.java
org/knopflerfish/bundle/component/ReferenceDescription.java
org/knopflerfish/bundle/component/ReferenceListener.java
org/knopflerfish/bundle/component/SCR.java
org/knopflerfish/bundle/component/ScrServiceImpl.java
org/osgi/service/component/ComponentConstants.java
org/osgi/service/component/ComponentContext.java
org/osgi/service/component/ComponentException.java
org/osgi/service/component/ComponentFactory.java
org/osgi/service/component/ComponentInstance.java
org/osgi/service/component/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/component/component_api-5.0.3.html0000644000175000017500000003300612346515426024233 0ustar felixfelix component_api-5.0.3.jar

component_api-5.0.3.jar

download (6120 bytes)

OSGi manifest attributes
Bundle-Name SCR-API
Bundle-SymbolicName org.knopflerfish.bundle.component-API
Bundle-Version 5.0.3
Bundle-Description Declarative Services SCR (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.apache.felix.scr 1.6.0
org.osgi.service.component 1.2.1
Import-Package org.apache.felix.scr [1.6.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.component [1.2.1,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:03
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/component
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/component
Bundle-UUID org.knopflerfish:component:5.0.3:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

component_all-5.0.3org.apache.felix.scr, org.osgi.service.component
component_api-5.0.3org.apache.felix.scr, org.osgi.service.component
desktop_all-5.0.1org.apache.felix.scr, org.osgi.service.component
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

component_all-5.0.3org.apache.felix.scr, org.osgi.service.component
component_api-5.0.3org.apache.felix.scr, org.osgi.service.component
desktop_all-5.0.1org.apache.felix.scr, org.osgi.service.component
desktop-5.0.1org.apache.felix.scr
scrcommands-4.0.1org.apache.felix.scr, org.osgi.service.component

Bundle source

Here are links to the source files of this bundle.
org/apache/felix/scr/Component.java
org/apache/felix/scr/Reference.java
org/apache/felix/scr/ScrService.java
org/knopflerfish/bundle/component/Activator.java
org/knopflerfish/bundle/component/Component.java
org/knopflerfish/bundle/component/ComponentConfiguration.java
org/knopflerfish/bundle/component/ComponentContextImpl.java
org/knopflerfish/bundle/component/ComponentDescription.java
org/knopflerfish/bundle/component/ComponentFactoryImpl.java
org/knopflerfish/bundle/component/ComponentInstanceImpl.java
org/knopflerfish/bundle/component/ComponentMethod.java
org/knopflerfish/bundle/component/DelayedComponent.java
org/knopflerfish/bundle/component/FactoryComponent.java
org/knopflerfish/bundle/component/IllegalXMLException.java
org/knopflerfish/bundle/component/ImmediateComponent.java
org/knopflerfish/bundle/component/PostponedBind.java
org/knopflerfish/bundle/component/PropertyDictionary.java
org/knopflerfish/bundle/component/Reference.java
org/knopflerfish/bundle/component/ReferenceDescription.java
org/knopflerfish/bundle/component/ReferenceListener.java
org/knopflerfish/bundle/component/SCR.java
org/knopflerfish/bundle/component/ScrServiceImpl.java
org/osgi/service/component/ComponentConstants.java
org/osgi/service/component/ComponentContext.java
org/osgi/service/component/ComponentException.java
org/osgi/service/component/ComponentFactory.java
org/osgi/service/component/ComponentInstance.java
org/osgi/service/component/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/console/0000755000175000017500000000000012475375714017516 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/console/console-4.0.1.html0000644000175000017500000002172212346515426022501 0ustar felixfelix console-4.0.1.jar

console-4.0.1.jar

download (28126 bytes)

OSGi manifest attributes
Bundle-Name Console-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.console-IMPL
Bundle-Version 4.0.1
Bundle-Description Knopflerfish Console Service (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=console/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.console.Activator
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.console [2.0.0,3.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:10
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/console/console
Bundle-APIVendor Knopflerfish
Bundle-Category management
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/console/console/
Bundle-UUID org.knopflerfish:console:4.0.1:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.osgi.service.log
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console, org.osgi.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.osgi.service.log
log_api-5.0.0org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/console/Activator.java
org/knopflerfish/bundle/console/Alias.java
org/knopflerfish/bundle/console/Command.java
org/knopflerfish/bundle/console/ConsoleServiceImpl.java
org/knopflerfish/bundle/console/Pipe.java
org/knopflerfish/bundle/console/ReadThread.java
org/knopflerfish/bundle/console/SessionCommandGroup.java
org/knopflerfish/bundle/console/SessionImpl.java
org/knopflerfish/service/console/CommandGroup.java
org/knopflerfish/service/console/CommandGroupAdapter.java
org/knopflerfish/service/console/ConsoleService.java
org/knopflerfish/service/console/Session.java
org/knopflerfish/service/console/SessionListener.java
org/knopflerfish/service/console/Util.java
knopflerfish-osgi-5.1.0/docs/jars/console/console_all-4.0.1.html0000644000175000017500000003233212346515426023330 0ustar felixfelix console_all-4.0.1.jar

console_all-4.0.1.jar

download (41199 bytes)

OSGi manifest attributes
Bundle-Name Console
Bundle-SymbolicName org.knopflerfish.bundle.console
Bundle-Version 4.0.1
Bundle-Description Knopflerfish Console Service
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=console/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.console.Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.console 2.1.2
Import-Package org.knopflerfish.service.console [2.0.0,3.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:10
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/console/console
Bundle-APIVendor Knopflerfish
Bundle-Category management
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/console/console/
Bundle-UUID org.knopflerfish:console:4.0.1
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.osgi.service.log
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console, org.osgi.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.osgi.service.log
log_api-5.0.0org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

cm_cmd-5.0.1org.knopflerfish.service.console
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
console-4.0.1org.knopflerfish.service.console
console2command-2.0.0org.knopflerfish.service.console
consoletcp_all-5.0.0org.knopflerfish.service.console
consoletcp-5.0.0org.knopflerfish.service.console
consoletelnet-4.0.1org.knopflerfish.service.console
consoletty-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console
desktop-5.0.1org.knopflerfish.service.console
frameworkcommands-4.0.1org.knopflerfish.service.console
http_all-4.0.5org.knopflerfish.service.console
http-4.0.5org.knopflerfish.service.console
junit_all-3.8.1.kf4-001org.knopflerfish.service.console
logcommands-5.0.0org.knopflerfish.service.console
repositorycommands-1.1.1org.knopflerfish.service.console
scrcommands-4.0.1org.knopflerfish.service.console

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/console/Activator.java
org/knopflerfish/bundle/console/Alias.java
org/knopflerfish/bundle/console/Command.java
org/knopflerfish/bundle/console/ConsoleServiceImpl.java
org/knopflerfish/bundle/console/Pipe.java
org/knopflerfish/bundle/console/ReadThread.java
org/knopflerfish/bundle/console/SessionCommandGroup.java
org/knopflerfish/bundle/console/SessionImpl.java
org/knopflerfish/service/console/CommandGroup.java
org/knopflerfish/service/console/CommandGroupAdapter.java
org/knopflerfish/service/console/ConsoleService.java
org/knopflerfish/service/console/Session.java
org/knopflerfish/service/console/SessionListener.java
org/knopflerfish/service/console/Util.java
knopflerfish-osgi-5.1.0/docs/jars/console/console_api-4.0.1.html0000644000175000017500000003047412346515426023336 0ustar felixfelix console_api-4.0.1.jar

console_api-4.0.1.jar

download (14067 bytes)

OSGi manifest attributes
Bundle-Name Console-API
Bundle-SymbolicName org.knopflerfish.bundle.console-API
Bundle-Version 4.0.1
Bundle-Description Knopflerfish Console Service (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=console/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.console 2.1.2
Import-Package org.knopflerfish.service.console [2.1.2,3.0.0)
org.osgi.framework [1.6.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:10
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/console/console
Bundle-APIVendor Knopflerfish
Bundle-Category API
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/console/console/
Bundle-UUID org.knopflerfish:console:4.0.1:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

cm_cmd-5.0.1org.knopflerfish.service.console
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
console-4.0.1org.knopflerfish.service.console
console2command-2.0.0org.knopflerfish.service.console
consoletcp_all-5.0.0org.knopflerfish.service.console
consoletcp-5.0.0org.knopflerfish.service.console
consoletelnet-4.0.1org.knopflerfish.service.console
consoletty-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console
desktop-5.0.1org.knopflerfish.service.console
frameworkcommands-4.0.1org.knopflerfish.service.console
http_all-4.0.5org.knopflerfish.service.console
http-4.0.5org.knopflerfish.service.console
junit_all-3.8.1.kf4-001org.knopflerfish.service.console
logcommands-5.0.0org.knopflerfish.service.console
repositorycommands-1.1.1org.knopflerfish.service.console
scrcommands-4.0.1org.knopflerfish.service.console

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/console/Activator.java
org/knopflerfish/bundle/console/Alias.java
org/knopflerfish/bundle/console/Command.java
org/knopflerfish/bundle/console/ConsoleServiceImpl.java
org/knopflerfish/bundle/console/Pipe.java
org/knopflerfish/bundle/console/ReadThread.java
org/knopflerfish/bundle/console/SessionCommandGroup.java
org/knopflerfish/bundle/console/SessionImpl.java
org/knopflerfish/service/console/CommandGroup.java
org/knopflerfish/service/console/CommandGroupAdapter.java
org/knopflerfish/service/console/ConsoleService.java
org/knopflerfish/service/console/Session.java
org/knopflerfish/service/console/SessionListener.java
org/knopflerfish/service/console/Util.java
knopflerfish-osgi-5.1.0/docs/jars/io/0000755000175000017500000000000012475375714016463 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/io/io_api-4.0.0.html0000644000175000017500000001413012346515430021231 0ustar felixfelix io_api-4.0.0.jar

io_api-4.0.0.jar

download (2339 bytes)

OSGi manifest attributes
Bundle-Name io-API
Bundle-SymbolicName org.knopflerfish.bundle.io-API
Bundle-Version 4.0.0
Bundle-Description IO (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .,javax.microedition.io.jar
Export-Package javax.microedition.io 0.0.0
org.osgi.service.io 1.0.0
Import-Package javax.microedition.io [0.0.0,1.0.0)
org.osgi.service.io [1.0.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:32
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/io/io
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/io/io/
Bundle-UUID org.knopflerfish:io:4.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

io_all-4.0.0javax.microedition.io, org.osgi.service.io
io_api-4.0.0javax.microedition.io, org.osgi.service.io

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

connectors_all-3.0.0javax.microedition.io, org.osgi.service.io
connectors-3.0.0javax.microedition.io, org.osgi.service.io
io_all-4.0.0javax.microedition.io, org.osgi.service.io
io_api-4.0.0javax.microedition.io, org.osgi.service.io

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/io/Activator.java
org/knopflerfish/bundle/io/ConnectorServiceImpl.java
org/osgi/service/io/ConnectionFactory.java
org/osgi/service/io/ConnectorService.java
org/osgi/service/io/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/io/io_all-4.0.0.html0000644000175000017500000001465212346515430021241 0ustar felixfelix io_all-4.0.0.jar

io_all-4.0.0.jar

download (12863 bytes)

OSGi manifest attributes
Bundle-Name io
Bundle-SymbolicName org.knopflerfish.bundle.io
Bundle-Version 4.0.0
Bundle-Description IO
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.io.Activator
Bundle-Classpath .,javax.microedition.io.jar
Export-Package javax.microedition.io 0.0.0
org.osgi.service.io 1.0.0
Import-Package javax.microedition.io [0.0.0,1.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.io [1.0.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:32
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/io/io
Bundle-Category service
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/io/io/
Bundle-UUID org.knopflerfish:io:4.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

io_all-4.0.0javax.microedition.io, org.osgi.service.io
io_api-4.0.0javax.microedition.io, org.osgi.service.io
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

connectors_all-3.0.0javax.microedition.io, org.osgi.service.io
connectors-3.0.0javax.microedition.io, org.osgi.service.io
io_all-4.0.0javax.microedition.io, org.osgi.service.io
io_api-4.0.0javax.microedition.io, org.osgi.service.io

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/io/Activator.java
org/knopflerfish/bundle/io/ConnectorServiceImpl.java
org/osgi/service/io/ConnectionFactory.java
org/osgi/service/io/ConnectorService.java
org/osgi/service/io/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/coordinator/0000755000175000017500000000000012475375714020377 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/coordinator/coordinator_api-1.0.0.html0000644000175000017500000001415212346515426025067 0ustar felixfelix coordinator_api-1.0.0.jar

coordinator_api-1.0.0.jar

download (13214 bytes)

OSGi manifest attributes
Bundle-Name Coordinator-API
Bundle-SymbolicName org.knopflerfish.bundle.coordinator-API
Bundle-Version 1.0.0
Bundle-Description OSGi specified coordinator service (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.coordinator 1.0.1
Import-Package org.osgi.framework [1.7.0,2.0.0)
org.osgi.service.coordinator [1.0.1,1.1.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:47
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/coordinator
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/coordinator/
Bundle-UUID org.knopflerfish:coordinator:1.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

coordinator_api-1.0.0org.osgi.service.coordinator
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

coordinator_api-1.0.0org.osgi.service.coordinator

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/coordinator/Coordination.java
org/osgi/service/coordinator/CoordinationException.java
org/osgi/service/coordinator/CoordinationPermission.java
org/osgi/service/coordinator/Coordinator.java
org/osgi/service/coordinator/Participant.java
org/osgi/service/coordinator/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/frameworkcommands/0000755000175000017500000000000012475375714021573 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/frameworkcommands/frameworkcommands-4.0.1.html0000644000175000017500000001721512346515430026630 0ustar felixfelix frameworkcommands-4.0.1.jar

frameworkcommands-4.0.1.jar

download (43187 bytes)

OSGi manifest attributes
Bundle-Name FW-Commands-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.frameworkcommands-IMPL
Bundle-Version 4.0.1
Bundle-Description Framework commands (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=frameworkcommands/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.frameworkcommands.Activator
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.console 0.0.0
org.osgi.framework [1.6.0,2.0.0)
org.osgi.framework.startlevel [1.0.0,2.0.0)
org.osgi.framework.wiring [1.0.0,2.0.0)
org.osgi.service.condpermadmin [1.1.0,2.0.0)
org.osgi.service.packageadmin [1.2.0,2.0.0)
org.osgi.service.permissionadmin [1.2.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:44
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/frameworkcommands
Bundle-Category management
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/frameworkcommands/
Bundle-UUID org.knopflerfish:frameworkcommands:4.0.1:impl
Import-Service org.knopflerfish.service.console.ConsoleService 0.0.0
org.osgi.service.log.LogService 0.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console
frameworkorg.osgi.framework, org.osgi.framework.startlevel, org.osgi.framework.wiring, org.osgi.service.condpermadmin, org.osgi.service.packageadmin, org.osgi.service.permissionadmin

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/frameworkcommands/Activator.java
org/knopflerfish/bundle/frameworkcommands/FrameworkCommandGroup.java
org/knopflerfish/bundle/frameworkcommands/PermissionAdminHelper.java
org/knopflerfish/bundle/frameworkcommands/PermissionAdminHelperImpl.java
knopflerfish-osgi-5.1.0/docs/jars/classpatcher/0000755000175000017500000000000012475375714020530 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/classpatcher/classpatcher_all-5.0.0.html0000644000175000017500000001316612346515426025360 0ustar felixfelix classpatcher_all-5.0.0.jar

classpatcher_all-5.0.0.jar

download (63488 bytes)

OSGi manifest attributes
Bundle-Name Class Patcher
Bundle-SymbolicName org.knopflerfish.bundle.classpatcher
Bundle-Version 5.0.0
Bundle-Description Implements a WeavingHook to allow patching of classes at load time using ASM
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.classpatcher.Activator
Bundle-Classpath .,asm-3.2.jar
Export-Package
Import-Package org.osgi.framework [1.6.0,2.0.0)
org.osgi.framework.hooks.weaving [1.0.0,2.0.0)
org.osgi.framework.wiring [1.0.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service;objectClass:List="org.osgi.framework.hooks.weaving.WeavingHook"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:32
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/classpatcher
Bundle-Category framework
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/classpatcher/
Bundle-UUID org.knopflerfish:classpatcher:5.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

frameworkorg.osgi.framework, org.osgi.framework.hooks.weaving, org.osgi.framework.wiring

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/classpatcher/Activator.java
org/knopflerfish/bundle/classpatcher/ClassPatcher.java
org/knopflerfish/bundle/classpatcher/ClassPatcherWeavingHook.java
org/knopflerfish/bundle/classpatcher/ClassPatcherWrappers.java
knopflerfish-osgi-5.1.0/docs/jars/util/0000755000175000017500000000000012475375714017031 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/util/util-4.1.0.html0000644000175000017500000002523112346515430021321 0ustar felixfelix util-4.1.0.jar

util-4.1.0.jar

download (47278 bytes)

OSGi manifest attributes
Bundle-Name util-LIB
Bundle-SymbolicName org.knopflerfish.bundle.util-LIB
Bundle-Version 4.1.0
Bundle-Description Misc utilities (LIB)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.knopflerfish.util 1.1.0
org.knopflerfish.util.framework 1.0.0
org.knopflerfish.util.sort 1.0.0
org.knopflerfish.util.workerthread 1.0.0
Import-Package org.osgi.framework [1.6.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:25:56
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/util
Bundle-APIVendor Knopflerfish
Bundle-Category utility
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/util/
Bundle-UUID org.knopflerfish:util:4.1.0:lib
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

cm_cmd-5.0.1org.knopflerfish.util.sort
desktop_all-5.0.1org.knopflerfish.util, org.knopflerfish.util.framework, org.knopflerfish.util.sort, org.knopflerfish.util.workerthread
desktop-5.0.1org.knopflerfish.util, org.knopflerfish.util.framework
httpconsole_all-4.0.1org.knopflerfish.util
kf_metatype_all-5.0.2org.knopflerfish.util
prefs_all-4.0.2org.knopflerfish.util
repository_desktop_all-1.1.1org.knopflerfish.util.framework

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/util/Base64.java
org/knopflerfish/util/ByteArray.java
org/knopflerfish/util/CacheMap.java
org/knopflerfish/util/CachedObject.java
org/knopflerfish/util/ClassLoaderUtil.java
org/knopflerfish/util/Compare.java
org/knopflerfish/util/Dict.java
org/knopflerfish/util/Lists.java
org/knopflerfish/util/Queue.java
org/knopflerfish/util/Semaphore.java
org/knopflerfish/util/Text.java
org/knopflerfish/util/Timer.java
org/knopflerfish/util/framework/Alias.java
org/knopflerfish/util/framework/ExecutableBundleActivator.java
org/knopflerfish/util/framework/VersionRange.java
org/knopflerfish/util/sort/CompareFunc.java
org/knopflerfish/util/sort/QSort.java
org/knopflerfish/util/sort/Sort.java
org/knopflerfish/util/workerthread/Job.java
org/knopflerfish/util/workerthread/RepeatingJob.java
org/knopflerfish/util/workerthread/WorkerThread.java
knopflerfish-osgi-5.1.0/docs/jars/framework.html0000644000175000017500000007215612346515430020736 0ustar felixfelix framework.jar

framework.jar

download (620789 bytes)

OSGi manifest attributes
Bundle-Name frameworkbundle
Bundle-SymbolicName org.knopflerfish.framework
Bundle-Version 7.1.2
Bundle-Description Knopflerfish OSGi framework system bundle
Bundle-Vendor Knopflerfish
Bundle-ContactAddress
Bundle-License "http://www.knopflerfish.org/license.html";description=BSD;link="http://www.knopflerfish.org/license.html"
Bundle-DocURL http://www.knopflerfish.org/releases/current/docs/bundledoc/index.html?docpage=framework/index.html
Bundle-ManifestVersion
Bundle-Activator
Bundle-Classpath
Export-Package org.osgi.framework 1.7.0
org.osgi.framework.hooks.bundle 1.1.0
org.osgi.framework.hooks.resolver 1.0.0
org.osgi.framework.hooks.service 1.1.0
org.osgi.framework.hooks.weaving 1.0.0
org.osgi.framework.launch 1.1.0
org.osgi.framework.namespace 1.0.0
org.osgi.framework.startlevel 1.0.0
org.osgi.framework.wiring 1.1.0
org.osgi.resource 1.0.0
org.osgi.service.condpermadmin 1.1.1
org.osgi.service.packageadmin 1.2.0
org.osgi.service.permissionadmin 1.2.0
org.osgi.service.startlevel 1.1.0
org.osgi.service.url 1.0.0
org.osgi.util.tracker 1.5.1
Import-Package
Dynamic-ImportPackage
Provide-Capability
Require-Capability
Other manifest attributes
Build-Date Build Fri June 13 2014, 08:25:43
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/trunk/osgi/framework/
Implementation-Title Knopflerfish OSGi Framework
Implementation-Vendor Knopflerfish
Implementation-Version 7.1.2
Main-class org.knopflerfish.framework.Main
Specification-Title OSGi Framework API
Specification-Vendor Open Service Gateway initiative
Specification-Version 1.7
SplashScreen-Image kfsplash.gif

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

None found

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

applicationadmin_api-4.0.0org.osgi.framework
basicdriverlocator_all-4.0.0org.osgi.framework
basicdriverlocator-4.0.0org.osgi.framework
blueprint_api-5.0.0org.osgi.framework
classpatcher_all-5.0.0org.osgi.framework, org.osgi.framework.hooks.weaving, org.osgi.framework.wiring
cm_all-5.0.1org.osgi.framework
cm_api-5.0.1org.osgi.framework
cm-5.0.1org.osgi.framework
cm_cmd-5.0.1org.osgi.framework
cm_desktop_all-5.0.2org.osgi.framework, org.osgi.util.tracker
cm_desktop-5.0.2org.osgi.framework, org.osgi.util.tracker
comm-linux_all-3.0.0org.osgi.framework
comm-win32_all-3.0.0org.osgi.framework
command_all-0.2org.osgi.framework, org.osgi.util.tracker
commandtty-4.0.1org.osgi.framework, org.osgi.util.tracker
commons-logging_all-2.0.0.kf4-001org.osgi.framework
component_all-5.0.3org.osgi.framework, org.osgi.util.tracker
component_api-5.0.3org.osgi.framework
connectors_all-3.0.0org.osgi.framework
connectors-3.0.0org.osgi.framework
console_all-4.0.1org.osgi.framework
console_api-4.0.1org.osgi.framework
console-4.0.1org.osgi.framework
console2command-2.0.0org.osgi.framework, org.osgi.util.tracker
consoletcp_all-5.0.0org.osgi.framework
consoletcp-5.0.0org.osgi.framework
consoletelnet-4.0.1org.osgi.framework, org.osgi.util.tracker
consoletty-4.0.1org.osgi.framework, org.osgi.util.tracker
coordinator_api-1.0.0org.osgi.framework
crimson-2.1.0.kf4-001org.osgi.framework
deploymentadmin_api-4.0.0org.osgi.framework
desktop_all-5.0.1org.osgi.framework, org.osgi.framework.namespace, org.osgi.framework.startlevel, org.osgi.framework.wiring, org.osgi.service.packageadmin, org.osgi.util.tracker
desktop_api-5.0.1org.osgi.framework
desktop-5.0.1org.osgi.framework, org.osgi.framework.namespace, org.osgi.framework.startlevel, org.osgi.framework.wiring, org.osgi.service.packageadmin, org.osgi.util.tracker
desktop_jvm_all-1.0.0org.osgi.framework
desktop_jvm-1.0.0org.osgi.framework
device_all-4.0.1org.osgi.framework
device_api-4.0.1org.osgi.framework
device-4.0.1org.osgi.framework
dirdeployer_all-4.0.1org.osgi.framework, org.osgi.framework.startlevel, org.osgi.framework.wiring, org.osgi.util.tracker
event_all-4.0.1org.osgi.framework, org.osgi.util.tracker
event_api-4.0.1org.osgi.framework
foreignapplication_api-4.0.0org.osgi.framework
frameworkcommands-4.0.1org.osgi.framework, org.osgi.framework.startlevel, org.osgi.framework.wiring, org.osgi.service.condpermadmin, org.osgi.service.packageadmin, org.osgi.service.permissionadmin
http_all-4.0.5org.osgi.framework, org.osgi.util.tracker
http-4.0.5org.osgi.framework, org.osgi.util.tracker
httpconsole_all-4.0.1org.osgi.framework
httproot-4.0.0org.osgi.framework, org.osgi.util.tracker
io_all-4.0.0org.osgi.framework
jinidriver_all-0.1.0org.osgi.framework, org.osgi.service.packageadmin, org.osgi.util.tracker
junit_all-3.8.1.kf4-001org.osgi.framework, org.osgi.util.tracker
junit_runner_all-4.0.0org.osgi.framework
kf_metatype_all-5.0.2org.osgi.framework, org.osgi.util.tracker
logcommands-5.0.0org.osgi.framework, org.osgi.util.tracker
metatype-4.0.0org.osgi.framework
namespace_api-1.0.0org.osgi.resource
prefs_all-4.0.2org.osgi.framework
remotefw_api-4.0.0org.osgi.framework
remoteserviceadmin_api-1.0.0org.osgi.framework
repository_api-1.0.0org.osgi.resource
repoindex_kf_all-1.0.1org.osgi.framework
repository_xml_all-1.0.2org.osgi.framework, org.osgi.resource, org.osgi.util.tracker
repository_xml_api-1.0.2org.osgi.framework
repository_desktop_all-1.1.1org.osgi.framework, org.osgi.resource, org.osgi.util.tracker
repositorycommands-1.1.1org.osgi.framework, org.osgi.resource, org.osgi.util.tracker
repositorymanager_all-1.2.0org.osgi.framework, org.osgi.framework.wiring, org.osgi.resource, org.osgi.util.tracker
repositorymanager_api-1.2.0org.osgi.framework, org.osgi.resource
resolver_api-1.0.0org.osgi.resource
scrcommands-4.0.1org.osgi.framework
serialportdevice_all-4.0.0org.osgi.framework
serviceloader_api-1.0.0org.osgi.resource
sslj2sp-4.0.0org.osgi.framework
subsystem_api-1.0.0org.osgi.framework
threadio_all-0.2.0org.osgi.framework
threadio-0.2.0org.osgi.framework
trayicon_fw-4.0.0org.osgi.framework, org.osgi.framework.startlevel
useradmin_all-4.1.1org.osgi.framework, org.osgi.util.tracker
useradmin_api-4.1.1org.osgi.framework
useradmin-4.1.1org.osgi.framework, org.osgi.util.tracker
util-4.1.0org.osgi.framework
wireadmin_api-5.0.0org.osgi.framework
xalan-2.7.1.kf3_01org.osgi.framework
xerces-2.10.1.kf5org.osgi.framework
xml-4.0.0org.osgi.framework
log_all-5.0.0org.osgi.framework
log_api-5.0.0org.osgi.framework
log-5.0.0org.osgi.framework

Bundle source

Here are links to the source files of this bundle. None found knopflerfish-osgi-5.1.0/docs/jars/console2command/0000755000175000017500000000000012475375714021137 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/console2command/console2command-2.0.0.html0000644000175000017500000001642612346515426025545 0ustar felixfelix console2command-2.0.0.jar

console2command-2.0.0.jar

download (6842 bytes)

OSGi manifest attributes
Bundle-Name Console2Command-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.console2command-IMPL
Bundle-Version 2.0.0
Bundle-Description Wrapper for KF console commands to RFC147 commands (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.console2command.Activator
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.console [2.1.0,3.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.command [1.0.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:18
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/console/console2command
Bundle-APIVendor Knopflerfish
Bundle-Category utility
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/console/console2command/
Bundle-UUID org.knopflerfish:console2command:2.0.0:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

command_all-0.2org.osgi.service.command
command_api-0.2org.osgi.service.command
commons-logging_all-2.0.0.kf4-001org.osgi.service.log
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console, org.osgi.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.osgi.service.log
log_api-5.0.0org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/console2command/Activator.java
org/knopflerfish/bundle/console2command/ConsoleWrapper.java
org/knopflerfish/bundle/console2command/Dispatcher.java
knopflerfish-osgi-5.1.0/docs/jars/blueprint/0000755000175000017500000000000012475375714020060 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/blueprint/blueprint_api-5.0.0.html0000644000175000017500000003173512346515426024243 0ustar felixfelix blueprint_api-5.0.0.jar

blueprint_api-5.0.0.jar

download (17923 bytes)

OSGi manifest attributes
Bundle-Name blueprint-API
Bundle-SymbolicName org.knopflerfish.bundle.blueprint-API
Bundle-Version 5.0.0
Bundle-Description Blueprint Container API (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/Apache-2.0;link="http://www.apache.org/licenses/LICENSE-2.0";description="Apache License, Version 2.0"
Bundle-DocURL http://www.knopflerfish.org
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.blueprint.container 1.0.2
org.osgi.service.blueprint.reflect 1.0.1
Import-Package org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.blueprint.container [1.0.2,2.0.0)
org.osgi.service.blueprint.reflect [1.0.1,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:43
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/blueprint
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/blueprint
Bundle-UUID org.knopflerfish:blueprint:5.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

blueprint_api-5.0.0org.osgi.service.blueprint.container, org.osgi.service.blueprint.reflect
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

blueprint_api-5.0.0org.osgi.service.blueprint.container, org.osgi.service.blueprint.reflect

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/blueprint/container/BlueprintContainer.java
org/osgi/service/blueprint/container/BlueprintEvent.java
org/osgi/service/blueprint/container/BlueprintListener.java
org/osgi/service/blueprint/container/ComponentDefinitionException.java
org/osgi/service/blueprint/container/Converter.java
org/osgi/service/blueprint/container/EventConstants.java
org/osgi/service/blueprint/container/NoSuchComponentException.java
org/osgi/service/blueprint/container/ReifiedType.java
org/osgi/service/blueprint/container/ServiceUnavailableException.java
org/osgi/service/blueprint/container/package-info.java
org/osgi/service/blueprint/reflect/BeanArgument.java
org/osgi/service/blueprint/reflect/BeanMetadata.java
org/osgi/service/blueprint/reflect/BeanProperty.java
org/osgi/service/blueprint/reflect/CollectionMetadata.java
org/osgi/service/blueprint/reflect/ComponentMetadata.java
org/osgi/service/blueprint/reflect/IdRefMetadata.java
org/osgi/service/blueprint/reflect/MapEntry.java
org/osgi/service/blueprint/reflect/MapMetadata.java
org/osgi/service/blueprint/reflect/Metadata.java
org/osgi/service/blueprint/reflect/NonNullMetadata.java
org/osgi/service/blueprint/reflect/NullMetadata.java
org/osgi/service/blueprint/reflect/PropsMetadata.java
org/osgi/service/blueprint/reflect/RefMetadata.java
org/osgi/service/blueprint/reflect/ReferenceListMetadata.java
org/osgi/service/blueprint/reflect/ReferenceListener.java
org/osgi/service/blueprint/reflect/ReferenceMetadata.java
org/osgi/service/blueprint/reflect/RegistrationListener.java
org/osgi/service/blueprint/reflect/ServiceMetadata.java
org/osgi/service/blueprint/reflect/ServiceReferenceMetadata.java
org/osgi/service/blueprint/reflect/Target.java
org/osgi/service/blueprint/reflect/ValueMetadata.java
org/osgi/service/blueprint/reflect/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/consoletelnet/0000755000175000017500000000000012475375714020732 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/consoletelnet/consoletelnet-4.0.1.html0000644000175000017500000002770612346515426025141 0ustar felixfelix consoletelnet-4.0.1.jar

consoletelnet-4.0.1.jar

download (33390 bytes)

OSGi manifest attributes
Bundle-Name Telnet-Console-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.consoletelnet-IMPL
Bundle-Version 4.0.1
Bundle-Description Console service server accepting telnet connections. (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=consoletelnet/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.consoletelnet.TelnetServer
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.console [2.1.0,3.0.0)
org.knopflerfish.service.log [1.2.0,2.0.0)
org.knopflerfish.service.um.useradmin [1.0.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.useradmin [1.1.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:17
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/console/consoletelnet
Bundle-APIVendor Knopflerfish
Bundle-Category management
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/console/consoletelnet/
Bundle-UUID org.knopflerfish:consoletelnet:4.0.1:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console, org.knopflerfish.service.log, org.osgi.service.cm
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log, org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin_api-4.1.1org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/consoletelnet/TCC.java
org/knopflerfish/bundle/consoletelnet/TelnetCommand.java
org/knopflerfish/bundle/consoletelnet/TelnetCommandEcho.java
org/knopflerfish/bundle/consoletelnet/TelnetCommandStatus.java
org/knopflerfish/bundle/consoletelnet/TelnetCommandSupga.java
org/knopflerfish/bundle/consoletelnet/TelnetConfig.java
org/knopflerfish/bundle/consoletelnet/TelnetInputStream.java
org/knopflerfish/bundle/consoletelnet/TelnetLogin.java
org/knopflerfish/bundle/consoletelnet/TelnetOutputStream.java
org/knopflerfish/bundle/consoletelnet/TelnetPrintWriter.java
org/knopflerfish/bundle/consoletelnet/TelnetReader.java
org/knopflerfish/bundle/consoletelnet/TelnetServer.java
org/knopflerfish/bundle/consoletelnet/TelnetSession.java
org/knopflerfish/bundle/consoletelnet/TelnetStateMachine.java
knopflerfish-osgi-5.1.0/docs/jars/serialportdevice/0000755000175000017500000000000012475375714021420 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/serialportdevice/serialportdevice_api-4.0.0.html0000644000175000017500000001527512346515430027136 0ustar felixfelix serialportdevice_api-4.0.0.jar

serialportdevice_api-4.0.0.jar

download (1738 bytes)

OSGi manifest attributes
Bundle-Name serialportdevice-API
Bundle-SymbolicName org.knopflerfish.bundle.serialportdevice-API
Bundle-Version 4.0.0
Bundle-Description Serial port device (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=serial
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.serial 0.0.0
Import-Package javax.comm 0.0.0
org.knopflerfish.service.serial [0.0.0,1.0.0)
org.osgi.service.device 0.0.0
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:11
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/serial/serialportdevice
Bundle-APIVendor Knopflerfish
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/serial/serialportdevice/
Bundle-UUID org.knopflerfish:serialportdevice:4.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

comm-linux_all-3.0.0javax.comm
comm-win32_all-3.0.0javax.comm
device_all-4.0.1org.osgi.service.device
device_api-4.0.1org.osgi.service.device
serialportdevice_all-4.0.0org.knopflerfish.service.serial
serialportdevice_api-4.0.0org.knopflerfish.service.serial

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

serialportdevice_all-4.0.0org.knopflerfish.service.serial
serialportdevice_api-4.0.0org.knopflerfish.service.serial

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/serial/Activator.java
org/knopflerfish/bundle/serial/Config.java
org/knopflerfish/bundle/serial/SPD.java
org/knopflerfish/service/serial/SerialPortDevice.java
knopflerfish-osgi-5.1.0/docs/jars/serialportdevice/serialportdevice_all-4.0.0.html0000644000175000017500000002252112346515430027125 0ustar felixfelix serialportdevice_all-4.0.0.jar

serialportdevice_all-4.0.0.jar

download (7658 bytes)

OSGi manifest attributes
Bundle-Name serialportdevice
Bundle-SymbolicName org.knopflerfish.bundle.serialportdevice
Bundle-Version 4.0.0
Bundle-Description Serial port device
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=serial
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.serial.Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.serial 0.0.0
Import-Package javax.comm 0.0.0
org.knopflerfish.service.log [1.2.0,2.0.0)
org.knopflerfish.service.serial 0.0.0
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.device [1.1.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:11
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/serial/serialportdevice
Bundle-APIVendor Knopflerfish
Bundle-Category device
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/serial/serialportdevice/
Bundle-UUID org.knopflerfish:serialportdevice:4.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
comm-linux_all-3.0.0javax.comm
comm-win32_all-3.0.0javax.comm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.cm
device_all-4.0.1org.osgi.service.device
device_api-4.0.1org.osgi.service.device
http_all-4.0.5org.knopflerfish.service.log
serialportdevice_all-4.0.0org.knopflerfish.service.serial
serialportdevice_api-4.0.0org.knopflerfish.service.serial
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

serialportdevice_all-4.0.0org.knopflerfish.service.serial
serialportdevice_api-4.0.0org.knopflerfish.service.serial

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/serial/Activator.java
org/knopflerfish/bundle/serial/Config.java
org/knopflerfish/bundle/serial/SPD.java
org/knopflerfish/service/serial/SerialPortDevice.java
knopflerfish-osgi-5.1.0/docs/jars/httpconsole/0000755000175000017500000000000012475375714020416 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/httpconsole/httpconsole_all-4.0.1.html0000644000175000017500000003103312346515430025120 0ustar felixfelix httpconsole_all-4.0.1.jar

httpconsole_all-4.0.1.jar

download (70416 bytes)

OSGi manifest attributes
Bundle-Name httpconsole
Bundle-SymbolicName org.knopflerfish.bundle.httpconsole
Bundle-Version 4.0.1
Bundle-Description
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=httpconsole/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.httpconsole.Activator
Bundle-Classpath .
Export-Package
Import-Package javax.servlet [2.5.0,3.0.0)
javax.servlet.http [2.5.0,3.0.0)
org.knopflerfish.service.log [1.2.0,2.0.0)
org.knopflerfish.util [1.1.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.http [1.1.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum) (version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:59
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/http/httpconsole
Bundle-Category management
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/http/httpconsole/
Bundle-UUID org.knopflerfish:httpconsole:4.0.1
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.knopflerfish.util
http_all-4.0.5org.knopflerfish.service.log, org.osgi.service.http
http_api-4.0.5org.osgi.service.http
jsdk_api-2.5.0.kf3-2javax.servlet, javax.servlet.http
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
util-4.1.0org.knopflerfish.util
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/httpconsole/Activator.java
org/knopflerfish/bundle/httpconsole/BundleView.java
org/knopflerfish/bundle/httpconsole/Command.java
org/knopflerfish/bundle/httpconsole/ConsoleServlet.java
org/knopflerfish/bundle/httpconsole/HTMLable.java
org/knopflerfish/bundle/httpconsole/HelpCommand.java
org/knopflerfish/bundle/httpconsole/HttpWrapper.java
org/knopflerfish/bundle/httpconsole/IconCommand.java
org/knopflerfish/bundle/httpconsole/IconDialogCommand.java
org/knopflerfish/bundle/httpconsole/IconView.java
org/knopflerfish/bundle/httpconsole/InfoCommand.java
org/knopflerfish/bundle/httpconsole/InstallFileCommand.java
org/knopflerfish/bundle/httpconsole/InstallFileCommand2.java
org/knopflerfish/bundle/httpconsole/InstallURLCommand.java
org/knopflerfish/bundle/httpconsole/Login.java
org/knopflerfish/bundle/httpconsole/LogoutCommand.java
org/knopflerfish/bundle/httpconsole/ReloadCommand.java
org/knopflerfish/bundle/httpconsole/ServiceInfoCommand.java
org/knopflerfish/bundle/httpconsole/StartCommand.java
org/knopflerfish/bundle/httpconsole/StatusCommand.java
org/knopflerfish/bundle/httpconsole/StopCommand.java
org/knopflerfish/bundle/httpconsole/UninstallCommand.java
org/knopflerfish/bundle/httpconsole/UpdateCommand.java
org/knopflerfish/bundle/httpconsole/Util.java
knopflerfish-osgi-5.1.0/docs/jars/httproot/0000755000175000017500000000000012475375714017737 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/httproot/httproot-4.0.0.html0000644000175000017500000001563012346515430023136 0ustar felixfelix httproot-4.0.0.jar

httproot-4.0.0.jar

download (20492 bytes)

OSGi manifest attributes
Bundle-Name HTTP-root-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.httproot-IMPL
Bundle-Version 4.0.0
Bundle-Description Demo HTTP Service user that publishes on the root (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.httproot.Activator
Bundle-Classpath .
Export-Package
Import-Package javax.servlet [2.5.0,3.0.0)
javax.servlet.http [2.5.0,3.0.0)
org.knopflerfish.service.log [1.2.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.http [1.1.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:58
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/http/httproot
Bundle-Category example
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/http/httproot/
Bundle-UUID org.knopflerfish:httproot:4.0.0:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.log
http_all-4.0.5org.knopflerfish.service.log, org.osgi.service.http
http_api-4.0.5org.osgi.service.http
jsdk_api-2.5.0.kf3-2javax.servlet, javax.servlet.http
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/httproot/Activator.java
org/knopflerfish/bundle/httproot/InfoServlet.java
knopflerfish-osgi-5.1.0/docs/jars/threadio/0000755000175000017500000000000012475375714017653 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/threadio/threadio_api-0.2.0.html0000644000175000017500000001424612346515430023617 0ustar felixfelix threadio_api-0.2.0.jar

threadio_api-0.2.0.jar

download (1653 bytes)

OSGi manifest attributes
Bundle-Name threadio-API
Bundle-SymbolicName org.knopflerfish.bundle.threadio-API
Bundle-Version 0.2.0
Bundle-Description ThreadIO Service (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.threadio 1.0.0
Import-Package org.osgi.service.threadio [1.0.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:17
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/threadio
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/threadio/
Bundle-UUID org.knopflerfish:threadio:0.2.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

threadio_all-0.2.0org.osgi.service.threadio
threadio_api-0.2.0org.osgi.service.threadio

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

command_all-0.2org.osgi.service.threadio
threadio_all-0.2.0org.osgi.service.threadio
threadio_api-0.2.0org.osgi.service.threadio
threadio-0.2.0org.osgi.service.threadio

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/threadio/Activator.java
org/knopflerfish/bundle/threadio/Streams.java
org/knopflerfish/bundle/threadio/ThreadIOFactory.java
org/knopflerfish/bundle/threadio/ThreadIOImpl.java
org/osgi/service/threadio/ThreadIO.java
knopflerfish-osgi-5.1.0/docs/jars/threadio/threadio_all-0.2.0.html0000644000175000017500000001477212346515430023622 0ustar felixfelix threadio_all-0.2.0.jar

threadio_all-0.2.0.jar

download (7027 bytes)

OSGi manifest attributes
Bundle-Name threadio
Bundle-SymbolicName org.knopflerfish.bundle.threadio
Bundle-Version 0.2.0
Bundle-Description ThreadIO Service
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.threadio.Activator
Bundle-Classpath .
Export-Package org.osgi.service.threadio 1.0.0
Import-Package org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.threadio [1.0.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:17
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/threadio
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/threadio/
Bundle-UUID org.knopflerfish:threadio:0.2.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

threadio_all-0.2.0org.osgi.service.threadio
threadio_api-0.2.0org.osgi.service.threadio
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

command_all-0.2org.osgi.service.threadio
threadio_all-0.2.0org.osgi.service.threadio
threadio_api-0.2.0org.osgi.service.threadio
threadio-0.2.0org.osgi.service.threadio

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/threadio/Activator.java
org/knopflerfish/bundle/threadio/Streams.java
org/knopflerfish/bundle/threadio/ThreadIOFactory.java
org/knopflerfish/bundle/threadio/ThreadIOImpl.java
org/osgi/service/threadio/ThreadIO.java
knopflerfish-osgi-5.1.0/docs/jars/threadio/threadio-0.2.0.html0000644000175000017500000001303412346515430022760 0ustar felixfelix threadio-0.2.0.jar

threadio-0.2.0.jar

download (6211 bytes)

OSGi manifest attributes
Bundle-Name threadio-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.threadio-IMPL
Bundle-Version 0.2.0
Bundle-Description ThreadIO Service (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.threadio.Activator
Bundle-Classpath .
Export-Package
Import-Package org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.threadio [1.0.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:17
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/threadio
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/threadio/
Bundle-UUID org.knopflerfish:threadio:0.2.0:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

threadio_all-0.2.0org.osgi.service.threadio
threadio_api-0.2.0org.osgi.service.threadio
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/threadio/Activator.java
org/knopflerfish/bundle/threadio/Streams.java
org/knopflerfish/bundle/threadio/ThreadIOFactory.java
org/knopflerfish/bundle/threadio/ThreadIOImpl.java
org/osgi/service/threadio/ThreadIO.java
knopflerfish-osgi-5.1.0/docs/jars/kxml/0000755000175000017500000000000012475375714017027 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/kxml/kxml-2.3.0.kf4-001.html0000644000175000017500000001557312346515430022306 0ustar felixfelix kxml-2.3.0.kf4-001.jar

kxml-2.3.0.kf4-001.jar

download (56795 bytes)

OSGi manifest attributes
Bundle-Name kXML 2-LIB
Bundle-SymbolicName org.knopflerfish.bundle.kxml-LIB
Bundle-Version 2.3.0.kf4-001
Bundle-Description Packing of kXML 2 as a bundle (LIB)
Bundle-Vendor kXML.org http://kxml.sourceforge.net/
Bundle-ContactAddress http://kxml.sourceforge.net/
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=kmxl/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.kxml2.io 0.0.0
org.kxml2.kdom 0.0.0
org.kxml2.wap 0.0.0
org.kxml2.wap.syncml 0.0.0
org.kxml2.wap.wml 0.0.0
org.kxml2.wap.wv 0.0.0
org.xmlpull.v1 1.1.3.1
Import-Package
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:27:02
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/xml/kxml
Bundle-Category lib
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/xml/kxml/
Bundle-UUID org.knopflerfish:kxml:2.3.0.kf4-001:lib
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

None found

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

component_all-5.0.3org.xmlpull.v1
kf_metatype_all-5.0.2org.kxml2.io, org.xmlpull.v1
repository_xml_all-1.0.2org.kxml2.io, org.xmlpull.v1

Bundle source

Here are links to the source files of this bundle.
org/kxml2/io/KXmlParser.java
org/kxml2/io/KXmlSerializer.java
org/kxml2/kdom/Document.java
org/kxml2/kdom/Element.java
org/kxml2/kdom/Node.java
org/kxml2/wap/Wbxml.java
org/kxml2/wap/WbxmlParser.java
org/kxml2/wap/WbxmlSerializer.java
org/kxml2/wap/syncml/SyncML.java
org/kxml2/wap/wml/Wml.java
org/kxml2/wap/wv/WV.java
knopflerfish-osgi-5.1.0/docs/jars/index.html0000644000175000017500000000237712346515430020046 0ustar felixfelix Knopflerfish - Bundle Jar Documentation knopflerfish-osgi-5.1.0/docs/jars/consoletcp/0000755000175000017500000000000012475375714020225 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/consoletcp/consoletcp_all-5.0.0.html0000644000175000017500000001747212346515426024556 0ustar felixfelix consoletcp_all-5.0.0.jar

consoletcp_all-5.0.0.jar

download (13865 bytes)

OSGi manifest attributes
Bundle-Name TCP-Console
Bundle-SymbolicName org.knopflerfish.bundle.consoletcp
Bundle-Version 5.0.0
Bundle-Description Console Service Server accepting TCP connection.
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.consoletcp.ConsoleTcp
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.console [2.1.0,3.0.0)
org.knopflerfish.service.um.useradmin [1.0.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.service.useradmin [1.1.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service;objectClass:List="org.osgi.service.cm.ManagedService";service.pid="org.knopflerfish.bundle.consoletcp.ConsoleTcp"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:16
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/console/consoletcp
Bundle-APIVendor Knopflerfish
Bundle-Category management
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/console/consoletcp/
Bundle-UUID org.knopflerfish:consoletcp:5.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.osgi.service.log
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console, org.osgi.service.cm, org.osgi.service.log
useradmin_all-4.1.1org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin_api-4.1.1org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
frameworkorg.osgi.framework
log_all-5.0.0org.osgi.service.log
log_api-5.0.0org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/consoletcp/ConsoleTcp.java
knopflerfish-osgi-5.1.0/docs/jars/consoletcp/consoletcp-5.0.0.html0000644000175000017500000001750412346515426023722 0ustar felixfelix consoletcp-5.0.0.jar

consoletcp-5.0.0.jar

download (13882 bytes)

OSGi manifest attributes
Bundle-Name TCP-Console-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.consoletcp-IMPL
Bundle-Version 5.0.0
Bundle-Description Console Service Server accepting TCP connection. (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.consoletcp.ConsoleTcp
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.console [2.1.0,3.0.0)
org.knopflerfish.service.um.useradmin [1.0.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.service.useradmin [1.1.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service;objectClass:List="org.osgi.service.cm.ManagedService";service.pid="org.knopflerfish.bundle.consoletcp.ConsoleTcp"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:16
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/console/consoletcp
Bundle-APIVendor Knopflerfish
Bundle-Category management
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/console/consoletcp/
Bundle-UUID org.knopflerfish:consoletcp:5.0.0:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.osgi.service.log
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console, org.osgi.service.cm, org.osgi.service.log
useradmin_all-4.1.1org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
useradmin_api-4.1.1org.knopflerfish.service.um.useradmin, org.osgi.service.useradmin
frameworkorg.osgi.framework
log_all-5.0.0org.osgi.service.log
log_api-5.0.0org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/consoletcp/ConsoleTcp.java
knopflerfish-osgi-5.1.0/docs/jars/comm-win32/0000755000175000017500000000000012475375714017747 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/comm-win32/comm-win32_all-3.0.0.html0000644000175000017500000001223212346515426024005 0ustar felixfelix comm-win32_all-3.0.0.jar

comm-win32_all-3.0.0.jar

download (38820 bytes)

OSGi manifest attributes
Bundle-Name comm-win32
Bundle-SymbolicName org.knopflerfish.bundle.comm-win32
Bundle-Version 3.0.0
Bundle-Description Native driver for win32 javax.comm using Sun's COMM library
Bundle-Vendor Knopflerfish/Sun
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=serial
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.comm.w32.Activator
Bundle-Classpath .,comm.jar
Export-Package javax.comm 2.0.0
Import-Package javax.comm 2.0.0
org.osgi.framework 0.0.0
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:15
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/serial/comm-win32
Bundle-APIVendor Knopflerfish/Sun
Bundle-Category service
Bundle-NativeCode win32com.dll ; processor = x86 ;osname = Windows NT ; osname = Windows 98 ; osname = Windows 95 ; osname = Windows 2000 ; osname = Windows XP ;osname = Windows Vista
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/serial/comm-win32/
Bundle-UUID org.knopflerfish:comm-win32:3.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

comm-linux_all-3.0.0javax.comm
comm-win32_all-3.0.0javax.comm
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

comm-linux_all-3.0.0javax.comm
comm-win32_all-3.0.0javax.comm
serialportdevice_all-4.0.0javax.comm
serialportdevice_api-4.0.0javax.comm

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/comm/w32/Activator.java
knopflerfish-osgi-5.1.0/docs/jars/foreignapplication/0000755000175000017500000000000012475375714021731 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/foreignapplication/foreignapplication_api-4.0.0.html0000644000175000017500000001342512346515430027753 0ustar felixfelix foreignapplication_api-4.0.0.jar

foreignapplication_api-4.0.0.jar

download (3434 bytes)

OSGi manifest attributes
Bundle-Name Foreign application-API
Bundle-SymbolicName org.knopflerfish.bundle.foreignapplication-API
Bundle-Version 4.0.0
Bundle-Description Foreign Application Access API (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.application 1.0.0
Import-Package org.osgi.application [1.0.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:57
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/foreignapplication
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/foreignapplication/
Bundle-UUID org.knopflerfish:foreignapplication:4.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

foreignapplication_api-4.0.0org.osgi.application
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

foreignapplication_api-4.0.0org.osgi.application

Bundle source

Here are links to the source files of this bundle.
org/osgi/application/ApplicationContext.java
org/osgi/application/ApplicationServiceEvent.java
org/osgi/application/ApplicationServiceListener.java
org/osgi/application/Framework.java
org/osgi/application/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/dmt/0000755000175000017500000000000012475375714016640 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/dmt/dmt_api-5.0.0.html0000644000175000017500000003120712346515430021570 0ustar felixfelix dmt_api-5.0.0.jar

dmt_api-5.0.0.jar

download (37681 bytes)

OSGi manifest attributes
Bundle-Name dmt-API
Bundle-SymbolicName org.knopflerfish.bundle.dmt-API
Bundle-Version 5.0.0
Bundle-Description DMT (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/Apache-2.0;link="http://www.apache.org/licenses/LICENSE-2.0";description="Apache License, Version 2.0"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.dmt 2.0.1
org.osgi.service.dmt.notification 2.0.0
org.osgi.service.dmt.notification.spi 2.0.0
org.osgi.service.dmt.security 2.0.0
org.osgi.service.dmt.spi 2.0.0
Import-Package org.osgi.service.dmt [2.0.1,3.0.0)
org.osgi.service.dmt.notification [2.0.0,3.0.0)
org.osgi.service.dmt.notification.spi [2.0.0,3.0.0)
org.osgi.service.dmt.security [2.0.0,3.0.0)
org.osgi.service.dmt.spi [2.0.0,3.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:52
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/dmt
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/dmt/
Bundle-UUID org.knopflerfish:dmt:5.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

dmt_api-5.0.0org.osgi.service.dmt, org.osgi.service.dmt.notification, org.osgi.service.dmt.notification.spi, org.osgi.service.dmt.security, org.osgi.service.dmt.spi

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

dmt_api-5.0.0org.osgi.service.dmt, org.osgi.service.dmt.notification, org.osgi.service.dmt.notification.spi, org.osgi.service.dmt.security, org.osgi.service.dmt.spi

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/dmt/Acl.java
org/osgi/service/dmt/DmtAdmin.java
org/osgi/service/dmt/DmtConstants.java
org/osgi/service/dmt/DmtData.java
org/osgi/service/dmt/DmtEvent.java
org/osgi/service/dmt/DmtEventListener.java
org/osgi/service/dmt/DmtException.java
org/osgi/service/dmt/DmtIllegalStateException.java
org/osgi/service/dmt/DmtSession.java
org/osgi/service/dmt/MetaNode.java
org/osgi/service/dmt/Uri.java
org/osgi/service/dmt/notification/AlertItem.java
org/osgi/service/dmt/notification/NotificationService.java
org/osgi/service/dmt/notification/package-info.java
org/osgi/service/dmt/notification/spi/RemoteAlertSender.java
org/osgi/service/dmt/notification/spi/package-info.java
org/osgi/service/dmt/package-info.java
org/osgi/service/dmt/security/AlertPermission.java
org/osgi/service/dmt/security/DmtPermission.java
org/osgi/service/dmt/security/DmtPrincipalPermission.java
org/osgi/service/dmt/security/package-info.java
org/osgi/service/dmt/spi/DataPlugin.java
org/osgi/service/dmt/spi/ExecPlugin.java
org/osgi/service/dmt/spi/MountPlugin.java
org/osgi/service/dmt/spi/MountPoint.java
org/osgi/service/dmt/spi/ReadWriteDataSession.java
org/osgi/service/dmt/spi/ReadableDataSession.java
org/osgi/service/dmt/spi/TransactionalDataSession.java
org/osgi/service/dmt/spi/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/logcommands/0000755000175000017500000000000012475375714020357 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/logcommands/logcommands-5.0.0.html0000644000175000017500000002053612346515430024200 0ustar felixfelix logcommands-5.0.0.jar

logcommands-5.0.0.jar

download (16772 bytes)

OSGi manifest attributes
Bundle-Name LogCommands-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.logcommands-IMPL
Bundle-Version 5.0.0
Bundle-Description Provides log commands for the Knopflerfish console (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=logcommands/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.logcommands.LogCommands
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.console [2.1.0,3.0.0)
org.knopflerfish.service.log [1.2.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service; objectClass:List="org.knopflerfish.service.console.CommandGroup"; groupName=log,osgi.service; objectClass:List="org.knopflerfish.service.console.CommandGroup"; groupName=logconfig
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:46
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/logcommands
Bundle-Category management
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/logcommands/
Bundle-UUID org.knopflerfish:logcommands:5.0.0:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console, org.knopflerfish.service.log, org.osgi.service.log
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/logcommands/LogCommandGroup.java
org/knopflerfish/bundle/logcommands/LogCommands.java
org/knopflerfish/bundle/logcommands/LogConfigCommandGroup.java
knopflerfish-osgi-5.1.0/docs/jars/cm/0000755000175000017500000000000012475375714016453 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/cm/cm-5.0.1.html0000644000175000017500000003424312346515426020376 0ustar felixfelix cm-5.0.1.jar

cm-5.0.1.jar

download (72850 bytes)

OSGi manifest attributes
Bundle-Name cm-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.cm-IMPL
Bundle-Version 5.0.1
Bundle-Description Configuration Management Service (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=cm/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.cm.Activator
Bundle-Classpath .
Export-Package org.knopflerfish.shared.cm 1.1.0
Import-Package org.knopflerfish.service.log [1.2.0,3.0.0)
org.knopflerfish.shared.cm [1.1.0,1.2.0)
org.osgi.framework [1.7.0,2.0.0)
org.osgi.service.cm [1.5.0,1.6.0)
Dynamic-ImportPackage
Provide-Capability osgi.service;objectClass:List="org.osgi.service.cm.ConfigurationAdmin"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:01
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/cm/cm
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/cm/cm/
Bundle-UUID org.knopflerfish:cm:5.0.1:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.knopflerfish.shared.cm, org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
cm-5.0.1org.knopflerfish.shared.cm
cm_desktop_all-5.0.2org.knopflerfish.shared.cm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.cm
dirdeployer_all-4.0.1org.knopflerfish.shared.cm
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

cm_all-5.0.1org.knopflerfish.shared.cm
cm-5.0.1org.knopflerfish.shared.cm
cm_cmd-5.0.1org.knopflerfish.shared.cm
cm_desktop_all-5.0.2org.knopflerfish.shared.cm
cm_desktop-5.0.2org.knopflerfish.shared.cm
dirdeployer_all-4.0.1org.knopflerfish.shared.cm

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/cm/Activator.java
org/knopflerfish/bundle/cm/ConfigurationAdminFactory.java
org/knopflerfish/bundle/cm/ConfigurationDictionary.java
org/knopflerfish/bundle/cm/ConfigurationDispatcher.java
org/knopflerfish/bundle/cm/ConfigurationStore.java
org/knopflerfish/bundle/cm/ListenerEvent.java
org/knopflerfish/bundle/cm/ListenerEventQueue.java
org/knopflerfish/bundle/cm/PluginManager.java
org/knopflerfish/bundle/cm/Update.java
org/knopflerfish/bundle/cm/UpdateQueue.java
org/knopflerfish/shared/cm/CMDataReader.java
org/knopflerfish/shared/cm/CMDataWriter.java
org/knopflerfish/shared/cm/DictionaryUtils.java
org/knopflerfish/shared/cm/XmlReader.java
org/osgi/service/cm/Configuration.java
org/osgi/service/cm/ConfigurationAdmin.java
org/osgi/service/cm/ConfigurationEvent.java
org/osgi/service/cm/ConfigurationException.java
org/osgi/service/cm/ConfigurationListener.java
org/osgi/service/cm/ConfigurationPermission.java
org/osgi/service/cm/ConfigurationPlugin.java
org/osgi/service/cm/ManagedService.java
org/osgi/service/cm/ManagedServiceFactory.java
org/osgi/service/cm/SynchronousConfigurationListener.java
org/osgi/service/cm/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/cm/cm_api-5.0.1.html0000644000175000017500000003607712346515426021236 0ustar felixfelix cm_api-5.0.1.jar

cm_api-5.0.1.jar

download (12318 bytes)

OSGi manifest attributes
Bundle-Name cm-API
Bundle-SymbolicName org.knopflerfish.bundle.cm-API
Bundle-Version 5.0.1
Bundle-Description Configuration Management Service (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=cm/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.cm 1.5.0
Import-Package org.osgi.framework 0.0.0
org.osgi.service.cm [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:01
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/cm/cm
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/cm/cm/
Bundle-UUID org.knopflerfish:cm:5.0.1:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
desktop_all-5.0.1org.osgi.service.cm
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
cm-5.0.1org.osgi.service.cm
cm_cmd-5.0.1org.osgi.service.cm
cm_desktop_all-5.0.2org.osgi.service.cm
cm_desktop-5.0.2org.osgi.service.cm
commandtty-4.0.1org.osgi.service.cm
component_all-5.0.3org.osgi.service.cm
consoletcp_all-5.0.0org.osgi.service.cm
consoletcp-5.0.0org.osgi.service.cm
consoletelnet-4.0.1org.osgi.service.cm
consoletty-4.0.1org.osgi.service.cm
desktop_all-5.0.1org.osgi.service.cm
dirdeployer_all-4.0.1org.osgi.service.cm
event_all-4.0.1org.osgi.service.cm
http_all-4.0.5org.osgi.service.cm
http-4.0.5org.osgi.service.cm
jinidriver_all-0.1.0org.osgi.service.cm
kf_metatype_all-5.0.2org.osgi.service.cm
repository_xml_all-1.0.2org.osgi.service.cm
serialportdevice_all-4.0.0org.osgi.service.cm
sslj2sp-4.0.0org.osgi.service.cm
log_all-5.0.0org.osgi.service.cm
log-5.0.0org.osgi.service.cm

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/cm/Activator.java
org/knopflerfish/bundle/cm/ConfigurationAdminFactory.java
org/knopflerfish/bundle/cm/ConfigurationDictionary.java
org/knopflerfish/bundle/cm/ConfigurationDispatcher.java
org/knopflerfish/bundle/cm/ConfigurationStore.java
org/knopflerfish/bundle/cm/ListenerEvent.java
org/knopflerfish/bundle/cm/ListenerEventQueue.java
org/knopflerfish/bundle/cm/PluginManager.java
org/knopflerfish/bundle/cm/Update.java
org/knopflerfish/bundle/cm/UpdateQueue.java
org/knopflerfish/shared/cm/CMDataReader.java
org/knopflerfish/shared/cm/CMDataWriter.java
org/knopflerfish/shared/cm/DictionaryUtils.java
org/knopflerfish/shared/cm/XmlReader.java
org/osgi/service/cm/Configuration.java
org/osgi/service/cm/ConfigurationAdmin.java
org/osgi/service/cm/ConfigurationEvent.java
org/osgi/service/cm/ConfigurationException.java
org/osgi/service/cm/ConfigurationListener.java
org/osgi/service/cm/ConfigurationPermission.java
org/osgi/service/cm/ConfigurationPlugin.java
org/osgi/service/cm/ManagedService.java
org/osgi/service/cm/ManagedServiceFactory.java
org/osgi/service/cm/SynchronousConfigurationListener.java
org/osgi/service/cm/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/cm/cm_all-5.0.1.html0000644000175000017500000004512212346515426021224 0ustar felixfelix cm_all-5.0.1.jar

cm_all-5.0.1.jar

download (84205 bytes)

OSGi manifest attributes
Bundle-Name cm
Bundle-SymbolicName org.knopflerfish.bundle.cm
Bundle-Version 5.0.1
Bundle-Description Configuration Management Service
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=cm/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.cm.Activator
Bundle-Classpath .
Export-Package org.knopflerfish.shared.cm 1.1.0
org.osgi.service.cm 1.5.0
Import-Package org.knopflerfish.service.log [1.2.0,3.0.0)
org.knopflerfish.shared.cm [1.1.0,1.2.0)
org.osgi.framework [1.7.0,2.0.0)
org.osgi.service.cm [1.5.0,1.6.0)
Dynamic-ImportPackage
Provide-Capability osgi.service;objectClass:List="org.osgi.service.cm.ConfigurationAdmin"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:01
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/cm/cm
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/cm/cm/
Bundle-UUID org.knopflerfish:cm:5.0.1
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.knopflerfish.shared.cm, org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
cm-5.0.1org.knopflerfish.shared.cm
cm_desktop_all-5.0.2org.knopflerfish.shared.cm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.log, org.osgi.service.cm
dirdeployer_all-4.0.1org.knopflerfish.shared.cm
http_all-4.0.5org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

cm_all-5.0.1org.knopflerfish.shared.cm, org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
cm-5.0.1org.knopflerfish.shared.cm, org.osgi.service.cm
cm_cmd-5.0.1org.knopflerfish.shared.cm, org.osgi.service.cm
cm_desktop_all-5.0.2org.knopflerfish.shared.cm, org.osgi.service.cm
cm_desktop-5.0.2org.knopflerfish.shared.cm, org.osgi.service.cm
commandtty-4.0.1org.osgi.service.cm
component_all-5.0.3org.osgi.service.cm
consoletcp_all-5.0.0org.osgi.service.cm
consoletcp-5.0.0org.osgi.service.cm
consoletelnet-4.0.1org.osgi.service.cm
consoletty-4.0.1org.osgi.service.cm
desktop_all-5.0.1org.osgi.service.cm
dirdeployer_all-4.0.1org.knopflerfish.shared.cm, org.osgi.service.cm
event_all-4.0.1org.osgi.service.cm
http_all-4.0.5org.osgi.service.cm
http-4.0.5org.osgi.service.cm
jinidriver_all-0.1.0org.osgi.service.cm
kf_metatype_all-5.0.2org.osgi.service.cm
repository_xml_all-1.0.2org.osgi.service.cm
serialportdevice_all-4.0.0org.osgi.service.cm
sslj2sp-4.0.0org.osgi.service.cm
log_all-5.0.0org.osgi.service.cm
log-5.0.0org.osgi.service.cm

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/cm/Activator.java
org/knopflerfish/bundle/cm/ConfigurationAdminFactory.java
org/knopflerfish/bundle/cm/ConfigurationDictionary.java
org/knopflerfish/bundle/cm/ConfigurationDispatcher.java
org/knopflerfish/bundle/cm/ConfigurationStore.java
org/knopflerfish/bundle/cm/ListenerEvent.java
org/knopflerfish/bundle/cm/ListenerEventQueue.java
org/knopflerfish/bundle/cm/PluginManager.java
org/knopflerfish/bundle/cm/Update.java
org/knopflerfish/bundle/cm/UpdateQueue.java
org/knopflerfish/shared/cm/CMDataReader.java
org/knopflerfish/shared/cm/CMDataWriter.java
org/knopflerfish/shared/cm/DictionaryUtils.java
org/knopflerfish/shared/cm/XmlReader.java
org/osgi/service/cm/Configuration.java
org/osgi/service/cm/ConfigurationAdmin.java
org/osgi/service/cm/ConfigurationEvent.java
org/osgi/service/cm/ConfigurationException.java
org/osgi/service/cm/ConfigurationListener.java
org/osgi/service/cm/ConfigurationPermission.java
org/osgi/service/cm/ConfigurationPlugin.java
org/osgi/service/cm/ManagedService.java
org/osgi/service/cm/ManagedServiceFactory.java
org/osgi/service/cm/SynchronousConfigurationListener.java
org/osgi/service/cm/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/xml/0000755000175000017500000000000012475375714016654 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/xml/xml-4.0.0.html0000644000175000017500000001141212346515430020762 0ustar felixfelix xml-4.0.0.jar

xml-4.0.0.jar

download (4789 bytes)

OSGi manifest attributes
Bundle-Name xml-LIB
Bundle-SymbolicName org.knopflerfish.bundle.xml-LIB
Bundle-Version 4.0.0
Bundle-Description XML (LIB)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=xml/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.util.xml 1.0.1
Import-Package javax.xml.parsers 0.0.0
org.osgi.framework [1.6.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:27:00
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/xml/xml
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/xml/xml/
Bundle-UUID org.knopflerfish:xml:4.0.0:lib
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

crimson-2.1.0.kf4-001javax.xml.parsers
xerces-2.10.1.kf5javax.xml.parsers
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

xerces-2.10.1.kf5org.osgi.util.xml

Bundle source

Here are links to the source files of this bundle.
org/osgi/util/xml/XMLParserActivator.java
org/osgi/util/xml/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/measurement/0000755000175000017500000000000012475375714020401 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/measurement/measurement-4.0.0.html0000644000175000017500000001242412346515430024240 0ustar felixfelix measurement-4.0.0.jar

measurement-4.0.0.jar

download (9239 bytes)

OSGi manifest attributes
Bundle-Name measurement-LIB
Bundle-SymbolicName org.knopflerfish.bundle.measurement-LIB
Bundle-Version 4.0.0
Bundle-Description Measurement API (LIB)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.util.measurement 1.0.1
Import-Package org.osgi.util.measurement [1.0.0,1.1.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:11
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/measurement
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/measurement/
Bundle-UUID org.knopflerfish:measurement:4.0.0:lib
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

measurement-4.0.0org.osgi.util.measurement

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

measurement-4.0.0org.osgi.util.measurement
position-4.0.0org.osgi.util.measurement

Bundle source

Here are links to the source files of this bundle.
org/osgi/util/measurement/Measurement.java
org/osgi/util/measurement/State.java
org/osgi/util/measurement/Unit.java
org/osgi/util/measurement/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/repository_desktop/0000755000175000017500000000000012475375714022024 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/repository_desktop/repository_desktop_all-1.1.1.html0000644000175000017500000003075412346515430030143 0ustar felixfelix repository_desktop_all-1.1.1.jar

repository_desktop_all-1.1.1.jar

download (75221 bytes)

OSGi manifest attributes
Bundle-Name Repository Desktop
Bundle-SymbolicName org.knopflerfish.bundle.repository_desktop
Bundle-Version 1.1.1
Bundle-Description Knopflerfish desktop plugin visualizing OSGi Repository contents.
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.repository_desktop.Activator
Bundle-Classpath .
Export-Package
Import-Package javax.swing 0.0.0
javax.swing.event 0.0.0
javax.swing.table 0.0.0
javax.swing.tree 0.0.0
org.knopflerfish.service.desktop [2.2.0,3.0.0)
org.knopflerfish.service.log [1.2.0,2.0.0)
org.knopflerfish.service.repositorymanager [1.0.0,2.0.0)
org.knopflerfish.util.framework [1.0.0,2.0.0)
org.osgi.framework [1.7.0,2.0.0)
org.osgi.resource [1.0.0,2.0.0)
org.osgi.service.repository [1.0.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Repository
Require-Capability osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=1.5))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:59
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/repository/repository_desktop
Bundle-APIVendor Knopflerfish
Bundle-Category management
Bundle-Copyright Copyright (c) 2003-2013, KNOPFLERFISH project. All rights reserved.
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/repository/repository_desktop
Bundle-UUID org.knopflerfish:repository_desktop:1.1.1
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.desktop, org.knopflerfish.service.log, org.knopflerfish.util.framework
desktop_api-5.0.1org.knopflerfish.service.desktop
http_all-4.0.5org.knopflerfish.service.log
repository_api-1.0.0org.osgi.service.repository
repositorymanager_all-1.2.0org.knopflerfish.service.repositorymanager, org.osgi.service.repository
repositorymanager_api-1.2.0org.knopflerfish.service.repositorymanager
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
util-4.1.0org.knopflerfish.util.framework
frameworkorg.osgi.framework, org.osgi.resource, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/repository_desktop/Activator.java
org/knopflerfish/bundle/repository_desktop/DefaultSwingBundleDisplayer.java
org/knopflerfish/bundle/repository_desktop/DownloadableBundleRequirement.java
org/knopflerfish/bundle/repository_desktop/NsToHtml.java
org/knopflerfish/bundle/repository_desktop/NsToHtmlBundle.java
org/knopflerfish/bundle/repository_desktop/NsToHtmlContent.java
org/knopflerfish/bundle/repository_desktop/NsToHtmlEE.java
org/knopflerfish/bundle/repository_desktop/NsToHtmlGeneric.java
org/knopflerfish/bundle/repository_desktop/NsToHtmlHost.java
org/knopflerfish/bundle/repository_desktop/NsToHtmlPackage.java
org/knopflerfish/bundle/repository_desktop/RepositoriesTableModel.java
org/knopflerfish/bundle/repository_desktop/RepositoryDisplayer.java
org/knopflerfish/bundle/repository_desktop/Util.java
knopflerfish-osgi-5.1.0/docs/jars/serviceloader/0000755000175000017500000000000012475375714020703 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/serviceloader/serviceloader_api-1.0.0.html0000644000175000017500000001237212346515430025674 0ustar felixfelix serviceloader_api-1.0.0.jar

serviceloader_api-1.0.0.jar

download (1977 bytes)

OSGi manifest attributes
Bundle-Name Service Loader-API
Bundle-SymbolicName org.knopflerfish.bundle.serviceloader-API
Bundle-Version 1.0.0
Bundle-Description OSGi specified serviceloader service (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.serviceloader 1.0.0
Import-Package org.osgi.resource 0.0.0
org.osgi.service.serviceloader [1.0.0,1.1.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:05
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/serviceloader
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/serviceloader/
Bundle-UUID org.knopflerfish:serviceloader:1.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

serviceloader_api-1.0.0org.osgi.service.serviceloader
frameworkorg.osgi.resource

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

serviceloader_api-1.0.0org.osgi.service.serviceloader

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/serviceloader/ServiceLoaderNamespace.java
org/osgi/service/serviceloader/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/cm_cmd/0000755000175000017500000000000012475375714017276 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/cm_cmd/cm_cmd-5.0.1.html0000644000175000017500000001670212346515426022044 0ustar felixfelix cm_cmd-5.0.1.jar

cm_cmd-5.0.1.jar

download (23385 bytes)

OSGi manifest attributes
Bundle-Name CM-Commands-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.cm_cmd-IMPL
Bundle-Version 5.0.1
Bundle-Description Commands for the CM service (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=cm_cmd/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.cm.commands.impl.Activator
Bundle-Classpath .
Export-Package
Import-Package org.knopflerfish.service.console 0.0.0
org.knopflerfish.shared.cm [1.1.0,2.0.0)
org.knopflerfish.util.sort 0.0.0
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service;objectClass:List="org.knopflerfish.service.console.CommandGroup"
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:09
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/cm/cm_cmd
Bundle-Category management
Bundle-Icon icon.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/cm/cm_cmd/
Bundle-UUID org.knopflerfish:cm_cmd:5.0.1:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.knopflerfish.shared.cm, org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
cm-5.0.1org.knopflerfish.shared.cm
cm_desktop_all-5.0.2org.knopflerfish.shared.cm
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console, org.knopflerfish.util.sort, org.osgi.service.cm
dirdeployer_all-4.0.1org.knopflerfish.shared.cm
util-4.1.0org.knopflerfish.util.sort
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/cm/commands/impl/Activator.java
org/knopflerfish/bundle/cm/commands/impl/CMCommands.java
knopflerfish-osgi-5.1.0/docs/jars/http/0000755000175000017500000000000012475375714017033 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/http/http_api-4.0.5.html0000644000175000017500000004072512346515430022167 0ustar felixfelix http_api-4.0.5.jar

http_api-4.0.5.jar

download (2992 bytes)

OSGi manifest attributes
Bundle-Name HTTP-Server-API
Bundle-SymbolicName org.knopflerfish.bundle.http-API
Bundle-Version 4.0.5
Bundle-Description HTTP/HTTPS Server (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=http/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.http 1.2.1
Import-Package javax.net.ssl 0.0.0
javax.servlet 0.0.0
javax.servlet.http 0.0.0
org.osgi.service.http [1.2.1,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:52
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/http/http
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/http/http
Bundle-UUID org.knopflerfish:http:4.0.5:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

http_all-4.0.5org.osgi.service.http
http_api-4.0.5org.osgi.service.http
jsdk_api-2.5.0.kf3-2javax.servlet, javax.servlet.http

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

http_all-4.0.5org.osgi.service.http
http_api-4.0.5org.osgi.service.http
http-4.0.5org.osgi.service.http
httpconsole_all-4.0.1org.osgi.service.http
httproot-4.0.0org.osgi.service.http
jinidriver_all-0.1.0org.osgi.service.http
junit_all-3.8.1.kf4-001org.osgi.service.http

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/http/Activator.java
org/knopflerfish/bundle/http/Attributes.java
org/knopflerfish/bundle/http/BodyOutputStream.java
org/knopflerfish/bundle/http/DefaultHttpContext.java
org/knopflerfish/bundle/http/GZIPServletOutputStreamImpl.java
org/knopflerfish/bundle/http/HeaderBase.java
org/knopflerfish/bundle/http/HttpConfig.java
org/knopflerfish/bundle/http/HttpConfigWrapper.java
org/knopflerfish/bundle/http/HttpException.java
org/knopflerfish/bundle/http/HttpServer.java
org/knopflerfish/bundle/http/HttpServerFactory.java
org/knopflerfish/bundle/http/HttpServiceFactory.java
org/knopflerfish/bundle/http/HttpServiceImpl.java
org/knopflerfish/bundle/http/HttpSessionImpl.java
org/knopflerfish/bundle/http/HttpSessionManager.java
org/knopflerfish/bundle/http/HttpUtil.java
org/knopflerfish/bundle/http/LocaleToCharsetMap.java
org/knopflerfish/bundle/http/ObjectPool.java
org/knopflerfish/bundle/http/PoolableObject.java
org/knopflerfish/bundle/http/PoolableServletWrapper.java
org/knopflerfish/bundle/http/Registration.java
org/knopflerfish/bundle/http/Registrations.java
org/knopflerfish/bundle/http/Request.java
org/knopflerfish/bundle/http/RequestBase.java
org/knopflerfish/bundle/http/RequestDispatcherImpl.java
org/knopflerfish/bundle/http/RequestImpl.java
org/knopflerfish/bundle/http/RequestWrapper.java
org/knopflerfish/bundle/http/ResourceRegistration.java
org/knopflerfish/bundle/http/Response.java
org/knopflerfish/bundle/http/ResponseImpl.java
org/knopflerfish/bundle/http/ResponseWrapper.java
org/knopflerfish/bundle/http/ServletConfigImpl.java
org/knopflerfish/bundle/http/ServletContextImpl.java
org/knopflerfish/bundle/http/ServletContextManager.java
org/knopflerfish/bundle/http/ServletInputStreamImpl.java
org/knopflerfish/bundle/http/ServletOutputStreamImpl.java
org/knopflerfish/bundle/http/ServletPool.java
org/knopflerfish/bundle/http/ServletRegistration.java
org/knopflerfish/bundle/http/SimpleObjectPool.java
org/knopflerfish/bundle/http/SocketListener.java
org/knopflerfish/bundle/http/Transaction.java
org/knopflerfish/bundle/http/TransactionManager.java
org/knopflerfish/bundle/http/console/HttpCommandGroup.java
org/osgi/service/http/HttpContext.java
org/osgi/service/http/HttpService.java
org/osgi/service/http/NamespaceException.java
org/osgi/service/http/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/http/http_all-4.0.5.html0000644000175000017500000006523312346515430022167 0ustar felixfelix http_all-4.0.5.jar

http_all-4.0.5.jar

download (116642 bytes)

OSGi manifest attributes
Bundle-Name HTTP-Server
Bundle-SymbolicName org.knopflerfish.bundle.http
Bundle-Version 4.0.5
Bundle-Description HTTP/HTTPS Server
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=http/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.http.Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.log 1.2.0
org.osgi.service.http 1.2.1
Import-Package javax.net.ssl 0.0.0
javax.servlet [2.5.0,2.6.0)
javax.servlet.http [2.5.0,2.6.0)
org.knopflerfish.service.console 0.0.0
org.knopflerfish.service.log [1.2.0,3.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.http [1.2.0,1.3.0)
org.osgi.service.log [1.2.0,3.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:52
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/http/http
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/http/http
Bundle-UUID org.knopflerfish:http:4.0.5
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console, org.knopflerfish.service.log, org.osgi.service.cm, org.osgi.service.log
http_all-4.0.5org.knopflerfish.service.log, org.osgi.service.http
http_api-4.0.5org.osgi.service.http
jsdk_api-2.5.0.kf3-2javax.servlet, javax.servlet.http
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

basicdriverlocator_all-4.0.0org.knopflerfish.service.log
basicdriverlocator-4.0.0org.knopflerfish.service.log
cm_all-5.0.1org.knopflerfish.service.log
cm-5.0.1org.knopflerfish.service.log
cm_desktop_all-5.0.2org.knopflerfish.service.log
cm_desktop-5.0.2org.knopflerfish.service.log
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log
consoletelnet-4.0.1org.knopflerfish.service.log
desktop_all-5.0.1org.knopflerfish.service.log
desktop-5.0.1org.knopflerfish.service.log
desktop_jvm_all-1.0.0org.knopflerfish.service.log
desktop_jvm-1.0.0org.knopflerfish.service.log
event_all-4.0.1org.knopflerfish.service.log
http_all-4.0.5org.knopflerfish.service.log, org.osgi.service.http
http_api-4.0.5org.osgi.service.http
http-4.0.5org.knopflerfish.service.log, org.osgi.service.http
httpconsole_all-4.0.1org.knopflerfish.service.log, org.osgi.service.http
httproot-4.0.0org.knopflerfish.service.log, org.osgi.service.http
jinidriver_all-0.1.0org.osgi.service.http
junit_all-3.8.1.kf4-001org.osgi.service.http
kf_metatype_all-5.0.2org.knopflerfish.service.log
logcommands-5.0.0org.knopflerfish.service.log
prefs_all-4.0.2org.knopflerfish.service.log
repository_desktop_all-1.1.1org.knopflerfish.service.log
serialportdevice_all-4.0.0org.knopflerfish.service.log
trayicon_fw-4.0.0org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
log_all-5.0.0org.knopflerfish.service.log
log_api-5.0.0org.knopflerfish.service.log
log-5.0.0org.knopflerfish.service.log

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/http/Activator.java
org/knopflerfish/bundle/http/Attributes.java
org/knopflerfish/bundle/http/BodyOutputStream.java
org/knopflerfish/bundle/http/DefaultHttpContext.java
org/knopflerfish/bundle/http/GZIPServletOutputStreamImpl.java
org/knopflerfish/bundle/http/HeaderBase.java
org/knopflerfish/bundle/http/HttpConfig.java
org/knopflerfish/bundle/http/HttpConfigWrapper.java
org/knopflerfish/bundle/http/HttpException.java
org/knopflerfish/bundle/http/HttpServer.java
org/knopflerfish/bundle/http/HttpServerFactory.java
org/knopflerfish/bundle/http/HttpServiceFactory.java
org/knopflerfish/bundle/http/HttpServiceImpl.java
org/knopflerfish/bundle/http/HttpSessionImpl.java
org/knopflerfish/bundle/http/HttpSessionManager.java
org/knopflerfish/bundle/http/HttpUtil.java
org/knopflerfish/bundle/http/LocaleToCharsetMap.java
org/knopflerfish/bundle/http/ObjectPool.java
org/knopflerfish/bundle/http/PoolableObject.java
org/knopflerfish/bundle/http/PoolableServletWrapper.java
org/knopflerfish/bundle/http/Registration.java
org/knopflerfish/bundle/http/Registrations.java
org/knopflerfish/bundle/http/Request.java
org/knopflerfish/bundle/http/RequestBase.java
org/knopflerfish/bundle/http/RequestDispatcherImpl.java
org/knopflerfish/bundle/http/RequestImpl.java
org/knopflerfish/bundle/http/RequestWrapper.java
org/knopflerfish/bundle/http/ResourceRegistration.java
org/knopflerfish/bundle/http/Response.java
org/knopflerfish/bundle/http/ResponseImpl.java
org/knopflerfish/bundle/http/ResponseWrapper.java
org/knopflerfish/bundle/http/ServletConfigImpl.java
org/knopflerfish/bundle/http/ServletContextImpl.java
org/knopflerfish/bundle/http/ServletContextManager.java
org/knopflerfish/bundle/http/ServletInputStreamImpl.java
org/knopflerfish/bundle/http/ServletOutputStreamImpl.java
org/knopflerfish/bundle/http/ServletPool.java
org/knopflerfish/bundle/http/ServletRegistration.java
org/knopflerfish/bundle/http/SimpleObjectPool.java
org/knopflerfish/bundle/http/SocketListener.java
org/knopflerfish/bundle/http/Transaction.java
org/knopflerfish/bundle/http/TransactionManager.java
org/knopflerfish/bundle/http/console/HttpCommandGroup.java
org/osgi/service/http/HttpContext.java
org/osgi/service/http/HttpService.java
org/osgi/service/http/NamespaceException.java
org/osgi/service/http/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/http/http-4.0.5.html0000644000175000017500000004613212346515430021334 0ustar felixfelix http-4.0.5.jar

http-4.0.5.jar

download (108383 bytes)

OSGi manifest attributes
Bundle-Name HTTP-Server-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.http-IMPL
Bundle-Version 4.0.5
Bundle-Description HTTP/HTTPS Server (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=http/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.http.Activator
Bundle-Classpath .
Export-Package
Import-Package javax.net.ssl 0.0.0
javax.servlet [2.5.0,2.6.0)
javax.servlet.http [2.5.0,2.6.0)
org.knopflerfish.service.console 0.0.0
org.knopflerfish.service.log [1.2.0,3.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.cm [1.4.0,2.0.0)
org.osgi.service.http [1.2.0,1.3.0)
org.osgi.service.log [1.2.0,3.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:26:52
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/http/http
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/http/http
Bundle-UUID org.knopflerfish:http:4.0.5:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.knopflerfish.service.console, org.knopflerfish.service.log, org.osgi.service.cm, org.osgi.service.log
http_all-4.0.5org.knopflerfish.service.log, org.osgi.service.http
http_api-4.0.5org.osgi.service.http
jsdk_api-2.5.0.kf3-2javax.servlet, javax.servlet.http
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
frameworkorg.osgi.framework, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/http/Activator.java
org/knopflerfish/bundle/http/Attributes.java
org/knopflerfish/bundle/http/BodyOutputStream.java
org/knopflerfish/bundle/http/DefaultHttpContext.java
org/knopflerfish/bundle/http/GZIPServletOutputStreamImpl.java
org/knopflerfish/bundle/http/HeaderBase.java
org/knopflerfish/bundle/http/HttpConfig.java
org/knopflerfish/bundle/http/HttpConfigWrapper.java
org/knopflerfish/bundle/http/HttpException.java
org/knopflerfish/bundle/http/HttpServer.java
org/knopflerfish/bundle/http/HttpServerFactory.java
org/knopflerfish/bundle/http/HttpServiceFactory.java
org/knopflerfish/bundle/http/HttpServiceImpl.java
org/knopflerfish/bundle/http/HttpSessionImpl.java
org/knopflerfish/bundle/http/HttpSessionManager.java
org/knopflerfish/bundle/http/HttpUtil.java
org/knopflerfish/bundle/http/LocaleToCharsetMap.java
org/knopflerfish/bundle/http/ObjectPool.java
org/knopflerfish/bundle/http/PoolableObject.java
org/knopflerfish/bundle/http/PoolableServletWrapper.java
org/knopflerfish/bundle/http/Registration.java
org/knopflerfish/bundle/http/Registrations.java
org/knopflerfish/bundle/http/Request.java
org/knopflerfish/bundle/http/RequestBase.java
org/knopflerfish/bundle/http/RequestDispatcherImpl.java
org/knopflerfish/bundle/http/RequestImpl.java
org/knopflerfish/bundle/http/RequestWrapper.java
org/knopflerfish/bundle/http/ResourceRegistration.java
org/knopflerfish/bundle/http/Response.java
org/knopflerfish/bundle/http/ResponseImpl.java
org/knopflerfish/bundle/http/ResponseWrapper.java
org/knopflerfish/bundle/http/ServletConfigImpl.java
org/knopflerfish/bundle/http/ServletContextImpl.java
org/knopflerfish/bundle/http/ServletContextManager.java
org/knopflerfish/bundle/http/ServletInputStreamImpl.java
org/knopflerfish/bundle/http/ServletOutputStreamImpl.java
org/knopflerfish/bundle/http/ServletPool.java
org/knopflerfish/bundle/http/ServletRegistration.java
org/knopflerfish/bundle/http/SimpleObjectPool.java
org/knopflerfish/bundle/http/SocketListener.java
org/knopflerfish/bundle/http/Transaction.java
org/knopflerfish/bundle/http/TransactionManager.java
org/knopflerfish/bundle/http/console/HttpCommandGroup.java
org/osgi/service/http/HttpContext.java
org/osgi/service/http/HttpService.java
org/osgi/service/http/NamespaceException.java
org/osgi/service/http/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/remotefw/0000755000175000017500000000000012475375714017704 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/remotefw/remotefw_api-4.0.0.html0000644000175000017500000001276512346515430023707 0ustar felixfelix remotefw_api-4.0.0.jar

remotefw_api-4.0.0.jar

download (1696 bytes)

OSGi manifest attributes
Bundle-Name RemoteFW-API
Bundle-SymbolicName org.knopflerfish.bundle.remotefw-API
Bundle-Version 4.0.0
Bundle-Description Remote Framework (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=remotefw/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.remotefw 0.0.0
Import-Package org.knopflerfish.service.remotefw [0.0.0,1.0.0)
org.osgi.framework [1.6.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:19
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/remotefw
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/remotefw/
Bundle-UUID org.knopflerfish:remotefw:4.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

desktop_all-5.0.1org.knopflerfish.service.remotefw
remotefw_api-4.0.0org.knopflerfish.service.remotefw
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

desktop_all-5.0.1org.knopflerfish.service.remotefw
desktop-5.0.1org.knopflerfish.service.remotefw
remotefw_api-4.0.0org.knopflerfish.service.remotefw

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/service/remotefw/RemoteFramework.java
knopflerfish-osgi-5.1.0/docs/jars/desktop/0000755000175000017500000000000012475375714017525 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/desktop/desktop_api-5.0.1.html0000644000175000017500000010654512346515426023360 0ustar felixfelix desktop_api-5.0.1.jar

desktop_api-5.0.1.jar

download (5306 bytes)

OSGi manifest attributes
Bundle-Name Desktop-API
Bundle-SymbolicName org.knopflerfish.bundle.desktop-API
Bundle-Version 5.0.1
Bundle-Description Swing framework desktop (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=desktop/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.knopflerfish.service.desktop 2.2.0
Import-Package com.apple.eawt 0.0.0
javax.swing 0.0.0
javax.swing.plaf.basic 0.0.0
org.knopflerfish.service.desktop [2.2.0,3.0.0)
org.osgi.framework 0.0.0
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=1.5))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:21
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/desktop
Bundle-APIVendor Knopflerfish
Bundle-Category API
Bundle-Copyright Copyright (c) 2003-2013, KNOPFLERFISH project. All rights reserved.
Bundle-Icon app.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/desktop/
Bundle-UUID org.knopflerfish:desktop:5.0.1:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

desktop_all-5.0.1org.knopflerfish.service.desktop
desktop_api-5.0.1org.knopflerfish.service.desktop
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

cm_desktop_all-5.0.2org.knopflerfish.service.desktop
cm_desktop-5.0.2org.knopflerfish.service.desktop
desktop_all-5.0.1org.knopflerfish.service.desktop
desktop_api-5.0.1org.knopflerfish.service.desktop
desktop-5.0.1org.knopflerfish.service.desktop
desktop_jvm_all-1.0.0org.knopflerfish.service.desktop
desktop_jvm-1.0.0org.knopflerfish.service.desktop
repository_desktop_all-1.1.1org.knopflerfish.service.desktop

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/desktop/event/DateCellRenderer.java
org/knopflerfish/bundle/desktop/event/EventReaderDispatcher.java
org/knopflerfish/bundle/desktop/event/EventTableModel.java
org/knopflerfish/bundle/desktop/event/FilterEventTableModel.java
org/knopflerfish/bundle/desktop/event/JDetailFrame.java
org/knopflerfish/bundle/desktop/event/JEventEntryDetail.java
org/knopflerfish/bundle/desktop/event/JEventPanel.java
org/knopflerfish/bundle/desktop/event/JEventTable.java
org/knopflerfish/bundle/desktop/event/JSendEventPanel.java
org/knopflerfish/bundle/desktop/event/StringCellRenderer.java
org/knopflerfish/bundle/desktop/event/TableMap.java
org/knopflerfish/bundle/desktop/event/TableSorter.java
org/knopflerfish/bundle/desktop/event/Util.java
org/knopflerfish/bundle/desktop/prefs/Colors.java
org/knopflerfish/bundle/desktop/prefs/ExtPreferences.java
org/knopflerfish/bundle/desktop/prefs/JPrefsEditor.java
org/knopflerfish/bundle/desktop/prefs/JPrefsPanel.java
org/knopflerfish/bundle/desktop/prefs/JPrefsTree.java
org/knopflerfish/bundle/desktop/prefs/JValue.java
org/knopflerfish/bundle/desktop/prefs/JValueBoolean.java
org/knopflerfish/bundle/desktop/prefs/JValueColor.java
org/knopflerfish/bundle/desktop/prefs/JValueDouble.java
org/knopflerfish/bundle/desktop/prefs/JValueFactory.java
org/knopflerfish/bundle/desktop/prefs/JValueInteger.java
org/knopflerfish/bundle/desktop/prefs/JValueLong.java
org/knopflerfish/bundle/desktop/prefs/JValueString.java
org/knopflerfish/bundle/desktop/prefs/MountedPreferences.java
org/knopflerfish/bundle/desktop/prefs/OSGiBundlePreferences.java
org/knopflerfish/bundle/desktop/prefs/OSGiBundlesPreferences.java
org/knopflerfish/bundle/desktop/prefs/OSGiPreferences.java
org/knopflerfish/bundle/desktop/prefs/OSGiUsersPreferences.java
org/knopflerfish/bundle/desktop/prefs/PrefsTreeModel.java
org/knopflerfish/bundle/desktop/prefs/PrefsTreeNode.java
org/knopflerfish/bundle/desktop/prefs/TreeUtils.java
org/knopflerfish/bundle/desktop/swing/Activator.java
org/knopflerfish/bundle/desktop/swing/BundleImageIcon.java
org/knopflerfish/bundle/desktop/swing/ClosureHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/Colors.java
org/knopflerfish/bundle/desktop/swing/DefaultSwingBundleDisplayer.java
org/knopflerfish/bundle/desktop/swing/Desktop.java
org/knopflerfish/bundle/desktop/swing/ErrorMessageDialog.java
org/knopflerfish/bundle/desktop/swing/EventDisplayer.java
org/knopflerfish/bundle/desktop/swing/FileFilterImpl.java
org/knopflerfish/bundle/desktop/swing/GraphDisplayer.java
org/knopflerfish/bundle/desktop/swing/JBundleHistory.java
org/knopflerfish/bundle/desktop/swing/JCardPane.java
org/knopflerfish/bundle/desktop/swing/JFloatable.java
org/knopflerfish/bundle/desktop/swing/JHTMLBundle.java
org/knopflerfish/bundle/desktop/swing/JHTMLBundleLinkHandler.java
org/knopflerfish/bundle/desktop/swing/JPackageView.java
org/knopflerfish/bundle/desktop/swing/JServiceView.java
org/knopflerfish/bundle/desktop/swing/JSoftGraph.java
org/knopflerfish/bundle/desktop/swing/JSoftGraphBundle.java
org/knopflerfish/bundle/desktop/swing/JTips.java
org/knopflerfish/bundle/desktop/swing/JToolbarButton.java
org/knopflerfish/bundle/desktop/swing/KnopflerfishLookAndFeel.java
org/knopflerfish/bundle/desktop/swing/KnopflerfishTheme.java
org/knopflerfish/bundle/desktop/swing/LFManager.java
org/knopflerfish/bundle/desktop/swing/LargeIconsDisplayer.java
org/knopflerfish/bundle/desktop/swing/LogDisplayer.java
org/knopflerfish/bundle/desktop/swing/LookAndFeelMenu.java
org/knopflerfish/bundle/desktop/swing/ManifestHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/OSXAdapter.java
org/knopflerfish/bundle/desktop/swing/OverlayImageIcon.java
org/knopflerfish/bundle/desktop/swing/PackageHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/PackageManager.java
org/knopflerfish/bundle/desktop/swing/PrefsDisplayer.java
org/knopflerfish/bundle/desktop/swing/SCRHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/ServiceHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/SizeSaver.java
org/knopflerfish/bundle/desktop/swing/SpinDisplayer.java
org/knopflerfish/bundle/desktop/swing/StatusBar.java
org/knopflerfish/bundle/desktop/swing/StatusViewer.java
org/knopflerfish/bundle/desktop/swing/Strings.java
org/knopflerfish/bundle/desktop/swing/TableDisplayer.java
org/knopflerfish/bundle/desktop/swing/TableMap.java
org/knopflerfish/bundle/desktop/swing/TableSorter.java
org/knopflerfish/bundle/desktop/swing/Util.java
org/knopflerfish/bundle/desktop/swing/WiringHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/console/Config.java
org/knopflerfish/bundle/desktop/swing/console/ConsoleSwing.java
org/knopflerfish/bundle/desktop/swing/console/PrefixPrintStream.java
org/knopflerfish/bundle/desktop/swing/console/Queue.java
org/knopflerfish/bundle/desktop/swing/console/Strip.java
org/knopflerfish/bundle/desktop/swing/console/SwingIO.java
org/knopflerfish/bundle/desktop/swing/console/TextAreaOutputStream.java
org/knopflerfish/bundle/desktop/swing/console/TextReader.java
org/knopflerfish/bundle/desktop/swing/fwspin/Console.java
org/knopflerfish/bundle/desktop/swing/fwspin/GameFrame.java
org/knopflerfish/bundle/desktop/swing/fwspin/Spin.java
org/knopflerfish/bundle/desktop/swing/fwspin/SpinItem.java
org/knopflerfish/bundle/desktop/swing/graph/BundleNode.java
org/knopflerfish/bundle/desktop/swing/graph/BundleServiceNode.java
org/knopflerfish/bundle/desktop/swing/graph/DefaultLink.java
org/knopflerfish/bundle/desktop/swing/graph/DefaultNode.java
org/knopflerfish/bundle/desktop/swing/graph/EmptyNode.java
org/knopflerfish/bundle/desktop/swing/graph/Link.java
org/knopflerfish/bundle/desktop/swing/graph/Node.java
org/knopflerfish/bundle/desktop/swing/graph/PackageNode.java
org/knopflerfish/bundle/desktop/swing/graph/ServiceLink.java
org/knopflerfish/bundle/log/window/impl/DateCellRenderer.java
org/knopflerfish/bundle/log/window/impl/ExtLogEntry.java
org/knopflerfish/bundle/log/window/impl/FilterLogTableModel.java
org/knopflerfish/bundle/log/window/impl/JDetailFrame.java
org/knopflerfish/bundle/log/window/impl/JLogEntryDetail.java
org/knopflerfish/bundle/log/window/impl/JLogPanel.java
org/knopflerfish/bundle/log/window/impl/JLogTable.java
org/knopflerfish/bundle/log/window/impl/LogReaderDispatcher.java
org/knopflerfish/bundle/log/window/impl/LogTableModel.java
org/knopflerfish/bundle/log/window/impl/TableMap.java
org/knopflerfish/bundle/log/window/impl/TableSorter.java
org/knopflerfish/bundle/log/window/impl/Util.java
org/knopflerfish/service/desktop/BundleFilter.java
org/knopflerfish/service/desktop/BundleSelectionListener.java
org/knopflerfish/service/desktop/BundleSelectionModel.java
org/knopflerfish/service/desktop/DefaultBundleSelectionModel.java
org/knopflerfish/service/desktop/SelectionAware.java
org/knopflerfish/service/desktop/SwingBundleDisplayer.java
knopflerfish-osgi-5.1.0/docs/jars/desktop/desktop-5.0.1.html0000644000175000017500000012623012346515426022520 0ustar felixfelix desktop-5.0.1.jar

desktop-5.0.1.jar

download (782279 bytes)

OSGi manifest attributes
Bundle-Name Desktop-IMPL
Bundle-SymbolicName org.knopflerfish.bundle.desktop-IMPL
Bundle-Version 5.0.1
Bundle-Description Swing framework desktop (IMPL)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=desktop/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.desktop.swing.Activator
Bundle-Classpath .
Export-Package
Import-Package com.apple.eawt 0.0.0
javax.accessibility 0.0.0
javax.swing 0.0.0
javax.swing.border 0.0.0
javax.swing.event 0.0.0
javax.swing.filechooser 0.0.0
javax.swing.plaf 0.0.0
javax.swing.plaf.basic 0.0.0
javax.swing.plaf.metal 0.0.0
javax.swing.table 0.0.0
javax.swing.text 0.0.0
javax.swing.text.html 0.0.0
javax.swing.tree 0.0.0
org.apache.felix.scr [1.6.0,2.0.0)
org.knopflerfish.service.console [2.1.2,3.0.0)
org.knopflerfish.service.desktop 0.0.0
org.knopflerfish.service.log [1.2.0,2.0.0)
org.knopflerfish.service.remotefw 0.0.0
org.knopflerfish.util [1.1.0,2.0.0)
org.knopflerfish.util.framework [1.0.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.framework.namespace [1.0.0,2.0.0)
org.osgi.framework.startlevel [1.0.0,2.0.0)
org.osgi.framework.wiring [1.0.0,2.0.0)
org.osgi.service.event [1.3.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.service.packageadmin [1.2.0,2.0.0)
org.osgi.service.prefs [1.1.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Graph,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Closure,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Manifest,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Icons,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Prefs,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Wiring,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Log,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=SCR,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Services,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Table,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Events,osgi.service; objectClass:List="org.osgi.service.event.EventHandler"
Require-Capability osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=1.5))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:21
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/desktop
Bundle-APIVendor Knopflerfish
Bundle-Category management
Bundle-Copyright Copyright (c) 2003-2013, KNOPFLERFISH project. All rights reserved.
Bundle-Icon app.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/desktop/
Bundle-UUID org.knopflerfish:desktop:5.0.1:impl
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
component_all-5.0.3org.apache.felix.scr
component_api-5.0.3org.apache.felix.scr
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.apache.felix.scr, org.knopflerfish.service.console, org.knopflerfish.service.desktop, org.knopflerfish.service.log, org.knopflerfish.service.remotefw, org.knopflerfish.util, org.knopflerfish.util.framework, org.osgi.service.event, org.osgi.service.log, org.osgi.service.prefs
desktop_api-5.0.1org.knopflerfish.service.desktop
event_all-4.0.1org.osgi.service.event
event_api-4.0.1org.osgi.service.event
http_all-4.0.5org.knopflerfish.service.log
prefs_all-4.0.2org.osgi.service.prefs
prefs_api-4.0.2org.osgi.service.prefs
remotefw_api-4.0.0org.knopflerfish.service.remotefw
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
util-4.1.0org.knopflerfish.util, org.knopflerfish.util.framework
frameworkorg.osgi.framework, org.osgi.framework.namespace, org.osgi.framework.startlevel, org.osgi.framework.wiring, org.osgi.service.packageadmin, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

None found

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/desktop/event/DateCellRenderer.java
org/knopflerfish/bundle/desktop/event/EventReaderDispatcher.java
org/knopflerfish/bundle/desktop/event/EventTableModel.java
org/knopflerfish/bundle/desktop/event/FilterEventTableModel.java
org/knopflerfish/bundle/desktop/event/JDetailFrame.java
org/knopflerfish/bundle/desktop/event/JEventEntryDetail.java
org/knopflerfish/bundle/desktop/event/JEventPanel.java
org/knopflerfish/bundle/desktop/event/JEventTable.java
org/knopflerfish/bundle/desktop/event/JSendEventPanel.java
org/knopflerfish/bundle/desktop/event/StringCellRenderer.java
org/knopflerfish/bundle/desktop/event/TableMap.java
org/knopflerfish/bundle/desktop/event/TableSorter.java
org/knopflerfish/bundle/desktop/event/Util.java
org/knopflerfish/bundle/desktop/prefs/Colors.java
org/knopflerfish/bundle/desktop/prefs/ExtPreferences.java
org/knopflerfish/bundle/desktop/prefs/JPrefsEditor.java
org/knopflerfish/bundle/desktop/prefs/JPrefsPanel.java
org/knopflerfish/bundle/desktop/prefs/JPrefsTree.java
org/knopflerfish/bundle/desktop/prefs/JValue.java
org/knopflerfish/bundle/desktop/prefs/JValueBoolean.java
org/knopflerfish/bundle/desktop/prefs/JValueColor.java
org/knopflerfish/bundle/desktop/prefs/JValueDouble.java
org/knopflerfish/bundle/desktop/prefs/JValueFactory.java
org/knopflerfish/bundle/desktop/prefs/JValueInteger.java
org/knopflerfish/bundle/desktop/prefs/JValueLong.java
org/knopflerfish/bundle/desktop/prefs/JValueString.java
org/knopflerfish/bundle/desktop/prefs/MountedPreferences.java
org/knopflerfish/bundle/desktop/prefs/OSGiBundlePreferences.java
org/knopflerfish/bundle/desktop/prefs/OSGiBundlesPreferences.java
org/knopflerfish/bundle/desktop/prefs/OSGiPreferences.java
org/knopflerfish/bundle/desktop/prefs/OSGiUsersPreferences.java
org/knopflerfish/bundle/desktop/prefs/PrefsTreeModel.java
org/knopflerfish/bundle/desktop/prefs/PrefsTreeNode.java
org/knopflerfish/bundle/desktop/prefs/TreeUtils.java
org/knopflerfish/bundle/desktop/swing/Activator.java
org/knopflerfish/bundle/desktop/swing/BundleImageIcon.java
org/knopflerfish/bundle/desktop/swing/ClosureHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/Colors.java
org/knopflerfish/bundle/desktop/swing/DefaultSwingBundleDisplayer.java
org/knopflerfish/bundle/desktop/swing/Desktop.java
org/knopflerfish/bundle/desktop/swing/ErrorMessageDialog.java
org/knopflerfish/bundle/desktop/swing/EventDisplayer.java
org/knopflerfish/bundle/desktop/swing/FileFilterImpl.java
org/knopflerfish/bundle/desktop/swing/GraphDisplayer.java
org/knopflerfish/bundle/desktop/swing/JBundleHistory.java
org/knopflerfish/bundle/desktop/swing/JCardPane.java
org/knopflerfish/bundle/desktop/swing/JFloatable.java
org/knopflerfish/bundle/desktop/swing/JHTMLBundle.java
org/knopflerfish/bundle/desktop/swing/JHTMLBundleLinkHandler.java
org/knopflerfish/bundle/desktop/swing/JPackageView.java
org/knopflerfish/bundle/desktop/swing/JServiceView.java
org/knopflerfish/bundle/desktop/swing/JSoftGraph.java
org/knopflerfish/bundle/desktop/swing/JSoftGraphBundle.java
org/knopflerfish/bundle/desktop/swing/JTips.java
org/knopflerfish/bundle/desktop/swing/JToolbarButton.java
org/knopflerfish/bundle/desktop/swing/KnopflerfishLookAndFeel.java
org/knopflerfish/bundle/desktop/swing/KnopflerfishTheme.java
org/knopflerfish/bundle/desktop/swing/LFManager.java
org/knopflerfish/bundle/desktop/swing/LargeIconsDisplayer.java
org/knopflerfish/bundle/desktop/swing/LogDisplayer.java
org/knopflerfish/bundle/desktop/swing/LookAndFeelMenu.java
org/knopflerfish/bundle/desktop/swing/ManifestHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/OSXAdapter.java
org/knopflerfish/bundle/desktop/swing/OverlayImageIcon.java
org/knopflerfish/bundle/desktop/swing/PackageHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/PackageManager.java
org/knopflerfish/bundle/desktop/swing/PrefsDisplayer.java
org/knopflerfish/bundle/desktop/swing/SCRHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/ServiceHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/SizeSaver.java
org/knopflerfish/bundle/desktop/swing/SpinDisplayer.java
org/knopflerfish/bundle/desktop/swing/StatusBar.java
org/knopflerfish/bundle/desktop/swing/StatusViewer.java
org/knopflerfish/bundle/desktop/swing/Strings.java
org/knopflerfish/bundle/desktop/swing/TableDisplayer.java
org/knopflerfish/bundle/desktop/swing/TableMap.java
org/knopflerfish/bundle/desktop/swing/TableSorter.java
org/knopflerfish/bundle/desktop/swing/Util.java
org/knopflerfish/bundle/desktop/swing/WiringHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/console/Config.java
org/knopflerfish/bundle/desktop/swing/console/ConsoleSwing.java
org/knopflerfish/bundle/desktop/swing/console/PrefixPrintStream.java
org/knopflerfish/bundle/desktop/swing/console/Queue.java
org/knopflerfish/bundle/desktop/swing/console/Strip.java
org/knopflerfish/bundle/desktop/swing/console/SwingIO.java
org/knopflerfish/bundle/desktop/swing/console/TextAreaOutputStream.java
org/knopflerfish/bundle/desktop/swing/console/TextReader.java
org/knopflerfish/bundle/desktop/swing/fwspin/Console.java
org/knopflerfish/bundle/desktop/swing/fwspin/GameFrame.java
org/knopflerfish/bundle/desktop/swing/fwspin/Spin.java
org/knopflerfish/bundle/desktop/swing/fwspin/SpinItem.java
org/knopflerfish/bundle/desktop/swing/graph/BundleNode.java
org/knopflerfish/bundle/desktop/swing/graph/BundleServiceNode.java
org/knopflerfish/bundle/desktop/swing/graph/DefaultLink.java
org/knopflerfish/bundle/desktop/swing/graph/DefaultNode.java
org/knopflerfish/bundle/desktop/swing/graph/EmptyNode.java
org/knopflerfish/bundle/desktop/swing/graph/Link.java
org/knopflerfish/bundle/desktop/swing/graph/Node.java
org/knopflerfish/bundle/desktop/swing/graph/PackageNode.java
org/knopflerfish/bundle/desktop/swing/graph/ServiceLink.java
org/knopflerfish/bundle/log/window/impl/DateCellRenderer.java
org/knopflerfish/bundle/log/window/impl/ExtLogEntry.java
org/knopflerfish/bundle/log/window/impl/FilterLogTableModel.java
org/knopflerfish/bundle/log/window/impl/JDetailFrame.java
org/knopflerfish/bundle/log/window/impl/JLogEntryDetail.java
org/knopflerfish/bundle/log/window/impl/JLogPanel.java
org/knopflerfish/bundle/log/window/impl/JLogTable.java
org/knopflerfish/bundle/log/window/impl/LogReaderDispatcher.java
org/knopflerfish/bundle/log/window/impl/LogTableModel.java
org/knopflerfish/bundle/log/window/impl/TableMap.java
org/knopflerfish/bundle/log/window/impl/TableSorter.java
org/knopflerfish/bundle/log/window/impl/Util.java
org/knopflerfish/service/desktop/BundleFilter.java
org/knopflerfish/service/desktop/BundleSelectionListener.java
org/knopflerfish/service/desktop/BundleSelectionModel.java
org/knopflerfish/service/desktop/DefaultBundleSelectionModel.java
org/knopflerfish/service/desktop/SelectionAware.java
org/knopflerfish/service/desktop/SwingBundleDisplayer.java
knopflerfish-osgi-5.1.0/docs/jars/desktop/desktop_all-5.0.1.html0000644000175000017500000021141212346515426023345 0ustar felixfelix desktop_all-5.0.1.jar

desktop_all-5.0.1.jar

download (884818 bytes)

OSGi manifest attributes
Bundle-Name Desktop
Bundle-SymbolicName org.knopflerfish.bundle.desktop
Bundle-Version 5.0.1
Bundle-Description Swing framework desktop
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License http://opensource.org/licenses/BSD-3-Clause;description="BSD 3-clause";link="http://www.knopflerfish.org/licenses/knopflerfish-1.txt"
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=desktop/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.desktop.swing.Activator
Bundle-Classpath .
Export-Package org.apache.felix.scr 1.6.0
org.knopflerfish.service.console 2.1.2
org.knopflerfish.service.desktop 2.2.0
org.knopflerfish.service.log 1.2.0
org.knopflerfish.service.remotefw 0.0.0
org.knopflerfish.util 1.1.0
org.knopflerfish.util.framework 1.0.0
org.knopflerfish.util.sort 1.0.0
org.knopflerfish.util.workerthread 1.0.0
org.osgi.service.cm 1.5.0
org.osgi.service.component 1.2.1
org.osgi.service.event 1.3.0
org.osgi.service.log 1.3.0
org.osgi.service.prefs 1.1.1
Import-Package com.apple.eawt 0.0.0
javax.accessibility 0.0.0
javax.swing 0.0.0
javax.swing.border 0.0.0
javax.swing.event 0.0.0
javax.swing.filechooser 0.0.0
javax.swing.plaf 0.0.0
javax.swing.plaf.basic 0.0.0
javax.swing.plaf.metal 0.0.0
javax.swing.table 0.0.0
javax.swing.text 0.0.0
javax.swing.text.html 0.0.0
javax.swing.tree 0.0.0
org.apache.felix.scr [1.6.0,2.0.0)
org.knopflerfish.service.console [2.1.2,3.0.0)
org.knopflerfish.service.desktop 0.0.0
org.knopflerfish.service.log [1.2.0,2.0.0)
org.knopflerfish.service.remotefw 0.0.0
org.knopflerfish.util [1.1.0,2.0.0)
org.knopflerfish.util.framework [1.0.0,2.0.0)
org.knopflerfish.util.sort [1.0.0,2.0.0)
org.knopflerfish.util.workerthread [1.0.0,2.0.0)
org.osgi.framework [1.6.0,2.0.0)
org.osgi.framework.namespace [1.0.0,2.0.0)
org.osgi.framework.startlevel [1.0.0,2.0.0)
org.osgi.framework.wiring [1.0.0,2.0.0)
org.osgi.service.cm [1.5.0,2.0.0)
org.osgi.service.component [1.2.1,2.0.0)
org.osgi.service.event [1.3.0,2.0.0)
org.osgi.service.log [1.3.0,2.0.0)
org.osgi.service.packageadmin [1.2.0,2.0.0)
org.osgi.service.prefs [1.1.0,2.0.0)
org.osgi.util.tracker [1.5.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Graph,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Closure,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Manifest,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Icons,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Prefs,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Wiring,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Log,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=SCR,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Services,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Table,osgi.service; objectClass:List="org.knopflerfish.service.desktop.SwingBundleDisplayer"; org.knopflerfish.service.desktop.displayer.name=Events,osgi.service; objectClass:List="org.osgi.service.event.EventHandler"
Require-Capability osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=1.5))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:21
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/desktop
Bundle-APIVendor Knopflerfish
Bundle-Category management
Bundle-Copyright Copyright (c) 2003-2013, KNOPFLERFISH project. All rights reserved.
Bundle-Icon app.png;size=32
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/desktop/
Bundle-UUID org.knopflerfish:desktop:5.0.1
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
component_all-5.0.3org.apache.felix.scr, org.osgi.service.component
component_api-5.0.3org.apache.felix.scr, org.osgi.service.component
console_all-4.0.1org.knopflerfish.service.console
console_api-4.0.1org.knopflerfish.service.console
desktop_all-5.0.1org.apache.felix.scr, org.knopflerfish.service.console, org.knopflerfish.service.desktop, org.knopflerfish.service.log, org.knopflerfish.service.remotefw, org.knopflerfish.util, org.knopflerfish.util.framework, org.knopflerfish.util.sort, org.knopflerfish.util.workerthread, org.osgi.service.cm, org.osgi.service.component, org.osgi.service.event, org.osgi.service.log, org.osgi.service.prefs
desktop_api-5.0.1org.knopflerfish.service.desktop
event_all-4.0.1org.osgi.service.event
event_api-4.0.1org.osgi.service.event
http_all-4.0.5org.knopflerfish.service.log
prefs_all-4.0.2org.osgi.service.prefs
prefs_api-4.0.2org.osgi.service.prefs
remotefw_api-4.0.0org.knopflerfish.service.remotefw
useradmin_all-4.1.1org.knopflerfish.service.log
useradmin-4.1.1org.knopflerfish.service.log
util-4.1.0org.knopflerfish.util, org.knopflerfish.util.framework, org.knopflerfish.util.sort, org.knopflerfish.util.workerthread
frameworkorg.osgi.framework, org.osgi.framework.namespace, org.osgi.framework.startlevel, org.osgi.framework.wiring, org.osgi.service.packageadmin, org.osgi.util.tracker
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

basicdriverlocator_all-4.0.0org.knopflerfish.service.log
basicdriverlocator-4.0.0org.knopflerfish.service.log
cm_all-5.0.1org.knopflerfish.service.log, org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
cm-5.0.1org.knopflerfish.service.log, org.osgi.service.cm
cm_cmd-5.0.1org.knopflerfish.service.console, org.knopflerfish.util.sort, org.osgi.service.cm
cm_desktop_all-5.0.2org.knopflerfish.service.desktop, org.knopflerfish.service.log, org.osgi.service.cm
cm_desktop-5.0.2org.knopflerfish.service.desktop, org.knopflerfish.service.log, org.osgi.service.cm
commandtty-4.0.1org.osgi.service.cm, org.osgi.service.log
commons-logging_all-2.0.0.kf4-001org.knopflerfish.service.log, org.osgi.service.log
component_all-5.0.3org.apache.felix.scr, org.osgi.service.cm, org.osgi.service.component, org.osgi.service.log
component_api-5.0.3org.apache.felix.scr, org.osgi.service.component
console_all-4.0.1org.knopflerfish.service.console, org.osgi.service.log
console_api-4.0.1org.knopflerfish.service.console
console-4.0.1org.knopflerfish.service.console, org.osgi.service.log
console2command-2.0.0org.knopflerfish.service.console, org.osgi.service.log
consoletcp_all-5.0.0org.knopflerfish.service.console, org.osgi.service.cm, org.osgi.service.log
consoletcp-5.0.0org.knopflerfish.service.console, org.osgi.service.cm, org.osgi.service.log
consoletelnet-4.0.1org.knopflerfish.service.console, org.knopflerfish.service.log, org.osgi.service.cm
consoletty-4.0.1org.knopflerfish.service.console, org.osgi.service.cm, org.osgi.service.log
desktop_all-5.0.1org.apache.felix.scr, org.knopflerfish.service.console, org.knopflerfish.service.desktop, org.knopflerfish.service.log, org.knopflerfish.service.remotefw, org.knopflerfish.util, org.knopflerfish.util.framework, org.knopflerfish.util.sort, org.knopflerfish.util.workerthread, org.osgi.service.cm, org.osgi.service.component, org.osgi.service.event, org.osgi.service.log, org.osgi.service.prefs
desktop_api-5.0.1org.knopflerfish.service.desktop
desktop-5.0.1org.apache.felix.scr, org.knopflerfish.service.console, org.knopflerfish.service.desktop, org.knopflerfish.service.log, org.knopflerfish.service.remotefw, org.knopflerfish.util, org.knopflerfish.util.framework, org.osgi.service.event, org.osgi.service.log, org.osgi.service.prefs
desktop_jvm_all-1.0.0org.knopflerfish.service.desktop, org.knopflerfish.service.log
desktop_jvm-1.0.0org.knopflerfish.service.desktop, org.knopflerfish.service.log
device_all-4.0.1org.osgi.service.log
device-4.0.1org.osgi.service.log
dirdeployer_all-4.0.1org.osgi.service.cm, org.osgi.service.log
event_all-4.0.1org.knopflerfish.service.log, org.osgi.service.cm, org.osgi.service.event, org.osgi.service.log
event_api-4.0.1org.osgi.service.event
frameworkcommands-4.0.1org.knopflerfish.service.console
http_all-4.0.5org.knopflerfish.service.console, org.knopflerfish.service.log, org.osgi.service.cm, org.osgi.service.log
http-4.0.5org.knopflerfish.service.console, org.knopflerfish.service.log, org.osgi.service.cm, org.osgi.service.log
httpconsole_all-4.0.1org.knopflerfish.service.log, org.knopflerfish.util
httproot-4.0.0org.knopflerfish.service.log
jinidriver_all-0.1.0org.osgi.service.cm
junit_all-3.8.1.kf4-001org.knopflerfish.service.console
kf_metatype_all-5.0.2org.knopflerfish.service.log, org.knopflerfish.util, org.osgi.service.cm
logcommands-5.0.0org.knopflerfish.service.console, org.knopflerfish.service.log, org.osgi.service.log
prefs_all-4.0.2org.knopflerfish.service.log, org.knopflerfish.util, org.osgi.service.prefs
prefs_api-4.0.2org.osgi.service.prefs
remotefw_api-4.0.0org.knopflerfish.service.remotefw
repository_xml_all-1.0.2org.osgi.service.cm
repository_desktop_all-1.1.1org.knopflerfish.service.desktop, org.knopflerfish.service.log, org.knopflerfish.util.framework
repositorycommands-1.1.1org.knopflerfish.service.console
scrcommands-4.0.1org.apache.felix.scr, org.knopflerfish.service.console, org.osgi.service.component
serialportdevice_all-4.0.0org.knopflerfish.service.log, org.osgi.service.cm
sslj2sp-4.0.0org.osgi.service.cm, org.osgi.service.log
trayicon_fw-4.0.0org.knopflerfish.service.log
useradmin_all-4.1.1org.knopflerfish.service.log, org.osgi.service.event, org.osgi.service.log
useradmin-4.1.1org.knopflerfish.service.log, org.osgi.service.event, org.osgi.service.log
log_all-5.0.0org.knopflerfish.service.log, org.osgi.service.cm, org.osgi.service.log
log_api-5.0.0org.knopflerfish.service.log, org.osgi.service.log
log-5.0.0org.knopflerfish.service.log, org.osgi.service.cm, org.osgi.service.log

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/desktop/event/DateCellRenderer.java
org/knopflerfish/bundle/desktop/event/EventReaderDispatcher.java
org/knopflerfish/bundle/desktop/event/EventTableModel.java
org/knopflerfish/bundle/desktop/event/FilterEventTableModel.java
org/knopflerfish/bundle/desktop/event/JDetailFrame.java
org/knopflerfish/bundle/desktop/event/JEventEntryDetail.java
org/knopflerfish/bundle/desktop/event/JEventPanel.java
org/knopflerfish/bundle/desktop/event/JEventTable.java
org/knopflerfish/bundle/desktop/event/JSendEventPanel.java
org/knopflerfish/bundle/desktop/event/StringCellRenderer.java
org/knopflerfish/bundle/desktop/event/TableMap.java
org/knopflerfish/bundle/desktop/event/TableSorter.java
org/knopflerfish/bundle/desktop/event/Util.java
org/knopflerfish/bundle/desktop/prefs/Colors.java
org/knopflerfish/bundle/desktop/prefs/ExtPreferences.java
org/knopflerfish/bundle/desktop/prefs/JPrefsEditor.java
org/knopflerfish/bundle/desktop/prefs/JPrefsPanel.java
org/knopflerfish/bundle/desktop/prefs/JPrefsTree.java
org/knopflerfish/bundle/desktop/prefs/JValue.java
org/knopflerfish/bundle/desktop/prefs/JValueBoolean.java
org/knopflerfish/bundle/desktop/prefs/JValueColor.java
org/knopflerfish/bundle/desktop/prefs/JValueDouble.java
org/knopflerfish/bundle/desktop/prefs/JValueFactory.java
org/knopflerfish/bundle/desktop/prefs/JValueInteger.java
org/knopflerfish/bundle/desktop/prefs/JValueLong.java
org/knopflerfish/bundle/desktop/prefs/JValueString.java
org/knopflerfish/bundle/desktop/prefs/MountedPreferences.java
org/knopflerfish/bundle/desktop/prefs/OSGiBundlePreferences.java
org/knopflerfish/bundle/desktop/prefs/OSGiBundlesPreferences.java
org/knopflerfish/bundle/desktop/prefs/OSGiPreferences.java
org/knopflerfish/bundle/desktop/prefs/OSGiUsersPreferences.java
org/knopflerfish/bundle/desktop/prefs/PrefsTreeModel.java
org/knopflerfish/bundle/desktop/prefs/PrefsTreeNode.java
org/knopflerfish/bundle/desktop/prefs/TreeUtils.java
org/knopflerfish/bundle/desktop/swing/Activator.java
org/knopflerfish/bundle/desktop/swing/BundleImageIcon.java
org/knopflerfish/bundle/desktop/swing/ClosureHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/Colors.java
org/knopflerfish/bundle/desktop/swing/DefaultSwingBundleDisplayer.java
org/knopflerfish/bundle/desktop/swing/Desktop.java
org/knopflerfish/bundle/desktop/swing/ErrorMessageDialog.java
org/knopflerfish/bundle/desktop/swing/EventDisplayer.java
org/knopflerfish/bundle/desktop/swing/FileFilterImpl.java
org/knopflerfish/bundle/desktop/swing/GraphDisplayer.java
org/knopflerfish/bundle/desktop/swing/JBundleHistory.java
org/knopflerfish/bundle/desktop/swing/JCardPane.java
org/knopflerfish/bundle/desktop/swing/JFloatable.java
org/knopflerfish/bundle/desktop/swing/JHTMLBundle.java
org/knopflerfish/bundle/desktop/swing/JHTMLBundleLinkHandler.java
org/knopflerfish/bundle/desktop/swing/JPackageView.java
org/knopflerfish/bundle/desktop/swing/JServiceView.java
org/knopflerfish/bundle/desktop/swing/JSoftGraph.java
org/knopflerfish/bundle/desktop/swing/JSoftGraphBundle.java
org/knopflerfish/bundle/desktop/swing/JTips.java
org/knopflerfish/bundle/desktop/swing/JToolbarButton.java
org/knopflerfish/bundle/desktop/swing/KnopflerfishLookAndFeel.java
org/knopflerfish/bundle/desktop/swing/KnopflerfishTheme.java
org/knopflerfish/bundle/desktop/swing/LFManager.java
org/knopflerfish/bundle/desktop/swing/LargeIconsDisplayer.java
org/knopflerfish/bundle/desktop/swing/LogDisplayer.java
org/knopflerfish/bundle/desktop/swing/LookAndFeelMenu.java
org/knopflerfish/bundle/desktop/swing/ManifestHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/OSXAdapter.java
org/knopflerfish/bundle/desktop/swing/OverlayImageIcon.java
org/knopflerfish/bundle/desktop/swing/PackageHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/PackageManager.java
org/knopflerfish/bundle/desktop/swing/PrefsDisplayer.java
org/knopflerfish/bundle/desktop/swing/SCRHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/ServiceHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/SizeSaver.java
org/knopflerfish/bundle/desktop/swing/SpinDisplayer.java
org/knopflerfish/bundle/desktop/swing/StatusBar.java
org/knopflerfish/bundle/desktop/swing/StatusViewer.java
org/knopflerfish/bundle/desktop/swing/Strings.java
org/knopflerfish/bundle/desktop/swing/TableDisplayer.java
org/knopflerfish/bundle/desktop/swing/TableMap.java
org/knopflerfish/bundle/desktop/swing/TableSorter.java
org/knopflerfish/bundle/desktop/swing/Util.java
org/knopflerfish/bundle/desktop/swing/WiringHTMLDisplayer.java
org/knopflerfish/bundle/desktop/swing/console/Config.java
org/knopflerfish/bundle/desktop/swing/console/ConsoleSwing.java
org/knopflerfish/bundle/desktop/swing/console/PrefixPrintStream.java
org/knopflerfish/bundle/desktop/swing/console/Queue.java
org/knopflerfish/bundle/desktop/swing/console/Strip.java
org/knopflerfish/bundle/desktop/swing/console/SwingIO.java
org/knopflerfish/bundle/desktop/swing/console/TextAreaOutputStream.java
org/knopflerfish/bundle/desktop/swing/console/TextReader.java
org/knopflerfish/bundle/desktop/swing/fwspin/Console.java
org/knopflerfish/bundle/desktop/swing/fwspin/GameFrame.java
org/knopflerfish/bundle/desktop/swing/fwspin/Spin.java
org/knopflerfish/bundle/desktop/swing/fwspin/SpinItem.java
org/knopflerfish/bundle/desktop/swing/graph/BundleNode.java
org/knopflerfish/bundle/desktop/swing/graph/BundleServiceNode.java
org/knopflerfish/bundle/desktop/swing/graph/DefaultLink.java
org/knopflerfish/bundle/desktop/swing/graph/DefaultNode.java
org/knopflerfish/bundle/desktop/swing/graph/EmptyNode.java
org/knopflerfish/bundle/desktop/swing/graph/Link.java
org/knopflerfish/bundle/desktop/swing/graph/Node.java
org/knopflerfish/bundle/desktop/swing/graph/PackageNode.java
org/knopflerfish/bundle/desktop/swing/graph/ServiceLink.java
org/knopflerfish/bundle/log/window/impl/DateCellRenderer.java
org/knopflerfish/bundle/log/window/impl/ExtLogEntry.java
org/knopflerfish/bundle/log/window/impl/FilterLogTableModel.java
org/knopflerfish/bundle/log/window/impl/JDetailFrame.java
org/knopflerfish/bundle/log/window/impl/JLogEntryDetail.java
org/knopflerfish/bundle/log/window/impl/JLogPanel.java
org/knopflerfish/bundle/log/window/impl/JLogTable.java
org/knopflerfish/bundle/log/window/impl/LogReaderDispatcher.java
org/knopflerfish/bundle/log/window/impl/LogTableModel.java
org/knopflerfish/bundle/log/window/impl/TableMap.java
org/knopflerfish/bundle/log/window/impl/TableSorter.java
org/knopflerfish/bundle/log/window/impl/Util.java
org/knopflerfish/service/desktop/BundleFilter.java
org/knopflerfish/service/desktop/BundleSelectionListener.java
org/knopflerfish/service/desktop/BundleSelectionModel.java
org/knopflerfish/service/desktop/DefaultBundleSelectionModel.java
org/knopflerfish/service/desktop/SelectionAware.java
org/knopflerfish/service/desktop/SwingBundleDisplayer.java
knopflerfish-osgi-5.1.0/docs/jars/list.html0000644000175000017500000002547212346515430017713 0ustar felixfelix

Knopflerfish OSGi 5.1.0 Bundles

Knopflerfish Documentation
Bundle Jar Documentation
Bundle Packages

applicationadmin_api-4.0.0
basicdriverlocator-4.0.0
basicdriverlocator_all-4.0.0
blueprint_api-5.0.0
classpatcher_all-5.0.0
cm-5.0.1
cm_all-5.0.1
cm_api-5.0.1
cm_cmd-5.0.1
cm_desktop-5.0.2
cm_desktop_all-5.0.2
comm-linux_all-3.0.0
comm-win32_all-3.0.0
command_all-0.2
command_api-0.2
commandtty-4.0.1
commons-logging_all-2.0.0.kf4-001
component_all-5.0.3
component_annotations_api-1.0.0
component_api-5.0.3
connectors-3.0.0
connectors_all-3.0.0
console-4.0.1
console2command-2.0.0
console_all-4.0.1
console_api-4.0.1
consoletcp-5.0.0
consoletcp_all-5.0.0
consoletelnet-4.0.1
consoletty-4.0.1
coordinator_api-1.0.0
crimson-2.1.0.kf4-001
deploymentadmin_api-4.0.0
desktop-5.0.1
desktop_all-5.0.1
desktop_api-5.0.1
desktop_jvm-1.0.0
desktop_jvm_all-1.0.0
device-4.0.1
device_all-4.0.1
device_api-4.0.1
dirdeployer_all-4.0.1
dirdeployer_api-4.0.1
dmt_api-5.0.0
event_all-4.0.1
event_api-4.0.1
foreignapplication_api-4.0.0
framework
frameworkcommands-4.0.1
http-4.0.5
http_all-4.0.5
http_api-4.0.5
httpconsole_all-4.0.1
httproot-4.0.0
io_all-4.0.0
io_api-4.0.0
jinidriver_all-0.1.0
jsdk_api-2.5.0.kf3-2
junit_all-3.8.1.kf4-001
junit_runner_all-4.0.0
kf_metatype_all-5.0.2
kxml-2.3.0.kf4-001
log-5.0.0
log_all-5.0.0
log_api-5.0.0
logcommands-5.0.0
measurement-4.0.0
metatype-4.0.0
monitor_api-4.0.0
namespace_api-1.0.0
position-4.0.0
prefs_all-4.0.2
prefs_api-4.0.2
provisioning_api-4.0.0
remotefw_api-4.0.0
remoteserviceadmin_api-1.0.0
repoindex_kf_all-1.0.1
repository_api-1.0.0
repository_desktop_all-1.1.1
repository_xml_all-1.0.2
repository_xml_api-1.0.2
repositorycommands-1.1.1
repositorymanager_all-1.2.0
repositorymanager_api-1.2.0
resolver_api-1.0.0
rxtxcomm-linux-arm-2.1.7.1
rxtxcomm-linux-x86-2.2.0.pre2
rxtxcomm_api-2.2.0.pre2
scrcommands-4.0.1
serialportdevice_all-4.0.0
serialportdevice_api-4.0.0
serviceloader_api-1.0.0
sslj2sp-4.0.0
subsystem_api-1.0.0
threadio-0.2.0
threadio_all-0.2.0
threadio_api-0.2.0
trayicon_fw-4.0.0
upnp_api-4.0.0
useradmin-4.1.1
useradmin_all-4.1.1
useradmin_api-4.1.1
util-4.1.0
wireadmin_api-5.0.0
xalan-2.7.1.kf3_01
xerces-2.10.1.kf5
xml-4.0.0
knopflerfish-osgi-5.1.0/docs/jars/jinidriver/0000755000175000017500000000000012475375714020221 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/jinidriver/jinidriver_all-0.1.0.html0000644000175000017500000002466112346515430024533 0ustar felixfelix jinidriver_all-0.1.0.jar

jinidriver_all-0.1.0.jar

download (204969 bytes)

OSGi manifest attributes
Bundle-Name Jini-Driver
Bundle-SymbolicName org.knopflerfish.bundle.jinidriver
Bundle-Version 0.1.0
Bundle-Description Jini driver (experimental) using Sun's jini impl. jini-core.jar and jini-ext.jar, see http://wwws.sun.com/software/jini/licensing/SCSL3_JiniTSA1.html
Bundle-Vendor Knopflerfish/Nico Goeminne
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator org.knopflerfish.bundle.jini.Activator
Bundle-Classpath .,lib/jini-core.jar,lib/jini-ext.jar
Export-Package net.jini.admin 0.0.0
net.jini.core.discovery 0.0.0
net.jini.core.entry 0.0.0
net.jini.core.event 0.0.0
net.jini.core.lease 0.0.0
net.jini.core.lookup 0.0.0
net.jini.discovery 0.0.0
net.jini.lease 0.0.0
net.jini.lookup 0.0.0
net.jini.lookup.entry 0.0.0
org.osgi.service.jini 1.0.0
Import-Package javax.servlet 0.0.0
javax.servlet.http 0.0.0
net.jini.admin 0.0.0
net.jini.core.discovery 0.0.0
net.jini.core.entry 0.0.0
net.jini.core.event 0.0.0
net.jini.core.lease 0.0.0
net.jini.core.lookup 0.0.0
net.jini.discovery 0.0.0
net.jini.lease 0.0.0
net.jini.lookup 0.0.0
net.jini.lookup.entry 0.0.0
org.osgi.framework 0.0.0
org.osgi.service.cm 0.0.0
org.osgi.service.http 0.0.0
org.osgi.service.jini 1.0.0
org.osgi.service.packageadmin 0.0.0
org.osgi.util.tracker 0.0.0
Dynamic-ImportPackage *
Provide-Capability
Require-Capability
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:24
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/jini/jinidriver
Bundle-APIVendor OSGi
Bundle-Category osgi
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/jini/jinidriver
Bundle-UUID org.knopflerfish:jinidriver:0.1.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

cm_all-5.0.1org.osgi.service.cm
cm_api-5.0.1org.osgi.service.cm
desktop_all-5.0.1org.osgi.service.cm
http_all-4.0.5org.osgi.service.http
http_api-4.0.5org.osgi.service.http
jinidriver_all-0.1.0net.jini.admin, net.jini.core.discovery, net.jini.core.entry, net.jini.core.event, net.jini.core.lease, net.jini.core.lookup, net.jini.discovery, net.jini.lease, net.jini.lookup, net.jini.lookup.entry, org.osgi.service.jini
jsdk_api-2.5.0.kf3-2javax.servlet, javax.servlet.http
frameworkorg.osgi.framework, org.osgi.service.packageadmin, org.osgi.util.tracker

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

jinidriver_all-0.1.0net.jini.admin, net.jini.core.discovery, net.jini.core.entry, net.jini.core.event, net.jini.core.lease, net.jini.core.lookup, net.jini.discovery, net.jini.lease, net.jini.lookup, net.jini.lookup.entry, org.osgi.service.jini

Bundle source

Here are links to the source files of this bundle.
org/knopflerfish/bundle/jini/Activator.java
org/knopflerfish/bundle/jini/BundleHttpContext.java
org/knopflerfish/bundle/jini/Debug.java
org/knopflerfish/bundle/jini/JiniDriverImpl.java
org/knopflerfish/bundle/jini/JiniExportedService.java
org/knopflerfish/bundle/jini/JiniExporter.java
org/knopflerfish/bundle/jini/JiniServiceFactory.java
org/knopflerfish/bundle/jini/Listener.java
org/knopflerfish/bundle/jini/Osgi2Jini.java
org/knopflerfish/bundle/jini/RMICodeBaseService.java
org/knopflerfish/bundle/jini/Util.java
org/osgi/service/jini/JiniDriver.java
knopflerfish-osgi-5.1.0/docs/jars/comm-linux/0000755000175000017500000000000012475375714020144 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/comm-linux/comm-linux_all-3.0.0.html0000644000175000017500000001351212346515426024401 0ustar felixfelix comm-linux_all-3.0.0.jar

comm-linux_all-3.0.0.jar

download (119718 bytes)

OSGi manifest attributes
Bundle-Name comm-linux
Bundle-SymbolicName org.knopflerfish.bundle.comm-linux
Bundle-Version 3.0.0
Bundle-Description Native driver for linux javax.comm using the RXTX library. Note that this bundle is LGPL and contains full source to rxtx
Bundle-Vendor Piayda/RXTX
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html?docpage=serial
Bundle-ManifestVersion 2
Bundle-Activator info.piayda.bundle.comm.linux.Activator
Bundle-Classpath .,RXTXcomm.jar,comm.jar
Export-Package gnu.io 2.0.0
javax.comm 2.0.0
Import-Package gnu.io 2.0.0
javax.comm 2.0.0
org.osgi.framework 0.0.0
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:30:16
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles_opt/serial/comm-linux
Bundle-APIVendor Piayda/Sun
Bundle-Category service
Bundle-NativeCode librxtxParallel.so; librxtxSerial.so ; processor = i386 ; osname = Linux, librxtxParallel.so; librxtxSerial.so ; processor = x86 ; osname = Linux, librxtxParallel.so; librxtxSerial.so ; processor = i386 ; osname = NetBSD
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles_opt/serial/comm-linux/
Bundle-UUID org.knopflerfish:comm-linux:3.0.0
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

comm-linux_all-3.0.0gnu.io, javax.comm
comm-win32_all-3.0.0javax.comm
rxtxcomm_api-2.2.0.pre2gnu.io
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

comm-linux_all-3.0.0gnu.io, javax.comm
comm-win32_all-3.0.0javax.comm
serialportdevice_all-4.0.0javax.comm
serialportdevice_api-4.0.0javax.comm

Bundle source

Here are links to the source files of this bundle.
info/piayda/bundle/comm/linux/Activator.java
knopflerfish-osgi-5.1.0/docs/jars/provisioning/0000755000175000017500000000000012475375714020602 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/provisioning/provisioning_api-4.0.0.html0000644000175000017500000001142112346515430025467 0ustar felixfelix provisioning_api-4.0.0.jar

provisioning_api-4.0.0.jar

download (2190 bytes)

OSGi manifest attributes
Bundle-Name provisioning-API
Bundle-SymbolicName org.knopflerfish.bundle.provisioning-API
Bundle-Version 4.0.0
Bundle-Description Initial Provisioning (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.provisioning 1.2.0
Import-Package org.osgi.service.provisioning [1.2.0,2.0.0)
Dynamic-ImportPackage
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:29:43
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/provisioning
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/provisioning/
Bundle-UUID org.knopflerfish:provisioning:4.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

provisioning_api-4.0.0org.osgi.service.provisioning

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

provisioning_api-4.0.0org.osgi.service.provisioning

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/provisioning/ProvisioningService.java
org/osgi/service/provisioning/package-info.java
knopflerfish-osgi-5.1.0/docs/jars/applicationadmin/0000755000175000017500000000000012475375714021370 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/jars/applicationadmin/applicationadmin_api-4.0.0.html0000644000175000017500000001417512346515426027061 0ustar felixfelix applicationadmin_api-4.0.0.jar

applicationadmin_api-4.0.0.jar

download (18166 bytes)

OSGi manifest attributes
Bundle-Name applicationadmin-API
Bundle-SymbolicName org.knopflerfish.bundle.applicationadmin-API
Bundle-Version 4.0.0
Bundle-Description Application Admin API (API)
Bundle-Vendor Knopflerfish
Bundle-ContactAddress http://www.knopflerfish.org
Bundle-License
Bundle-DocURL http://www.knopflerfish.org/releases/5.1.0/docs/bundledoc/index.html
Bundle-ManifestVersion 2
Bundle-Activator
Bundle-Classpath .
Export-Package org.osgi.service.application 1.1.0
Import-Package org.osgi.framework [1.6.0,2.0.0)
org.osgi.service.application [1.1.0,2.0.0)
Dynamic-ImportPackage *
Provide-Capability
Require-Capability osgi.ee;filter:="(&(osgi.ee=OSGi/Minimum)(version>=1.2))"
Other manifest attributes
Build-Date Fri June 13 2014, 08:28:40
Built-From /Users/jan/work/release/knopflerfish.org/osgi/bundles/applicationadmin
Bundle-APIVendor OSGi
Bundle-Category API
Bundle-SubversionURL https://www.knopflerfish.org/svn/knopflerfish.org/tags/5.1.0/osgi/bundles/applicationadmin/
Bundle-UUID org.knopflerfish:applicationadmin:4.0.0:api
Knopflerfish-Version 5.1.0

Depends on (osgi.wiring.package)

This section lists bundles that can provide one or more of the capabilities that is required in the osgi.wiring.package namespace. Only one provider of each capability is required.

The first column is the providing bundle and the second column lists the sub-set of its provided packages that are required by this bundle.

applicationadmin_api-4.0.0org.osgi.service.application
frameworkorg.osgi.framework

Other bundles depending on this bundle (osgi.wiring.package)

This section lists bundles that requires one or more of the capabilities that is provided in the namespace osgi.wiring.package by the current bundle.

The first column is the requiring bundle and the second column lists the sub-set of capabilities that this bundle may provide to the requiring bundle.

applicationadmin_api-4.0.0org.osgi.service.application

Bundle source

Here are links to the source files of this bundle.
org/osgi/service/application/ApplicationAdminPermission.java
org/osgi/service/application/ApplicationDescriptor.java
org/osgi/service/application/ApplicationException.java
org/osgi/service/application/ApplicationHandle.java
org/osgi/service/application/ScheduledApplication.java
org/osgi/service/application/package-info.java
knopflerfish-osgi-5.1.0/docs/building.html0000644000175000017500000002210412346515440017564 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - Building

Building Knopflerfish

Knopflerfish includes an ant based build system for building a complete Knopflerfish distribution as well as building individual bundles. Ant 1.8 or later is required, available from ant.apache.org

Knopflerfish can be built either by checking out the entire source code , or by (re)building an installed distribution.

The top level build file is located in the osgi directory. The default target is to build the framework and all bundles in the bundles directory.

Invoking ant with the -p option will display the possible targets.

$ ant -p
Buildfile: build.xml

Main targets:

 all                  Builds the framework and all bundles including optional and test bundles
 bundle_doc           Builds bundle specific docs
 bundle_tasks         Builds and defines the Knopflerfish bundle tasks
 clean                Removes all generated files and directories.
 clean_local          Remove all bundles built by this build-file but keep all other bundles
                      in the jars sub-directory.
 default              Builds the framework and bundles in bundles-directory
 define_bundle_tasks  Defines the Knopflerfish bundle tasks
 javadoc              Create javadoc for all exported packages
 rebuild              Cleans then build build all
 run                  (Re)start the framework.
 run-init             Initial start with default set of bundles.
 run-kf-tests         Builds then executes the KF testsuite.
 run-kf-tests-secure  Builds then executes the KF testsuite with security enabled.
 run-secure           (Re)start framework with security enabled.
 run-secure-init      Initial start with security enabled and default set of bundles.
Default target: default
$ 

To add and build additional bundles see the programming section.

Building a compact Knopflerfish framework

You can build a compact version of the framework called framework_compact.jar. To build this you need to download Proguard 4.10. Install the proguard.jar file into ${KF_ROOT}/ant/lib and build the framework with the property compact set to true.

This a version with a reduced memory footprint. This version has no security and certificate support compiled into it. This is only supposed to be used for running and not to compile against. So you also need to compile the normal framework.jar to be able to build bundles.

$ ant -Dcompact=true -f framework/build.xml 
Buildfile: /Users/jan/workspace_osgi5/kf_osgi5/osgi/framework/build.xml

compile:

compile_full:

compile_compact:

chkBundleTaskSrc:

chkBundleTasksBuild:

build_bundle_tasks:

define_bundle_tasks:

bundle_tasks:

genexports:
   [delete] Deleting: /Users/jan/workspace_osgi5/kf_osgi5/osgi/framework/resources/exports

jar:
   [delete] Deleting: /Users/jan/workspace_osgi5/kf_osgi5/osgi/framework/resources/version
   [delete] Deleting: /Users/jan/workspace_osgi5/kf_osgi5/osgi/framework/resources/tstamp

writerelease:

jar_file_full:

jar_file_compact:
      [jar] Building jar: /Users/jan/workspace_osgi5/kf_osgi5/osgi/framework_compact.jar

proguard_compact:
     [move] Moving 1 file to /Users/jan/workspace_osgi5/kf_osgi5/osgi
 [proguard] ProGuard, version 4.10
 [proguard] Reading program jar [/Users/jan/workspace_osgi5/kf_osgi5/osgi/framework_compact.jar.tmp.jar]
 [proguard] Reading library jar [/Users/jan/workspace_osgi5/kf_osgi5/osgi/ee/ee.minimum.jar]
 [proguard] Preparing output jar [/Users/jan/workspace_osgi5/kf_osgi5/osgi/framework_compact.jar]
 [proguard]   Copying resources from program jar [/Users/jan/workspace_osgi5/kf_osgi5/osgi/framework_compact.jar.tmp.jar]
   [delete] Deleting: /Users/jan/workspace_osgi5/kf_osgi5/osgi/framework_compact.jar.tmp.jar

add_dex:

source.jar:

save_javadoc_data:

javadoc.jar:

all:

BUILD SUCCESSFUL
Total time: 14 seconds
$ ls -l framework*jar
-rw-r--r--  1 jan  staff  617250 16 Okt 10:44 framework.jar
-rw-r--r--  1 jan  staff  323070 16 Okt 10:44 framework_compact.jar
$ 
knopflerfish-osgi-5.1.0/docs/running.html0000644000175000017500000002736612346515440017466 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - Running Knopflerfish

Running Knopflerfish

Starting Knopflerfish

The Knopflerfish OSGi framework is distributed as an executable jar file and is started by running java on the framework.jar file in the osgi directory.
    > cd osgi
    > java -jar framework.jar

The framework can also be started by double-clicking on the framework.jar file from Finder/Explorer or similar tools, depending on operating system used.

The compact version of the framework is started the same way, but instead of framework.jar the framework_compact.jar file must be used, e.g.

    > cd osgi
    > java -jar framework_compact.jar

It is also possible to start Knopflerfish from the ant build environment. This is typically done when running the Knopflerfish test suite.

The SDK installation starts a default set of bundles, including the Knopflerfish OSGi Desktop bundle and other utilities.

The Knopflerfish framework can be further controlled by: For a complete description of all framework feature please refer to the framework bundle documentation .

Knopflerfish command line options

To control the behavior of Knopflerfish OSGi command line options can be supplied. To get help on the framework options, run the framework with the help option.
    java -jar framework.jar -help
This prints a help screen (exact contents is version dependent).
java -jar framework.jar -help
Knopflerfish OSGi framework launcher, version 6.0.0.0001
Copyright 2003-2013 Knopflerfish. All Rights Reserved.
See http://www.knopflerfish.org for more information.

 Usage:  java [properties] org.knopflerfish.framework.Main [options]
      or java [properties] -jar framework.jar [options]
      or ./kf2 [options] [-- [properties]]  [--- [extra]] (*)

 Options:
   -exit          Exit the JVM process
   -help          Print this text and exit
   -version       Print version and exit
   -jvminfo       Print system and framework properties and exit
   -sleep SEC     Sleep a while before next command.
   -xargs file    Load more command line arguments from file, exit if file
                  cannot be loaded.
   --xargs file   Load more command line arguments from file, continue 
                  if file cannot be loaded (but print error)

   -create        Create and initialize a new framework instance
                  after a shutdown. The default is to reuse the old
                  framework instance.
   -ff FF         Specify the name of the FrameworkFactory to use when
                  creating the framework instance.
   -init          Start an empty platform (i.e., clear old presistent data).
   -launch        Launch framework (i.e., start it).
   -shutdown mSEC Shutdown framework, timeout in milliseconds.

   -install URL   Install a bundle
   -istart URL    Install and start bundle according to activation policy.
   -start ID      Start bundle (according to its activation policy)
   -start_e ID    Start bundle eagerly (i.e., ignore its activation policy)
   -start_et ID   Start bundle eagerly and transiently
   -start_pt ID   Start bundle transiently according to policy
   -stop ID       Stop bundle
   -stop_t ID     Stop bundle transiently (i.e, non-persistent stop)
   -uninstall ID  Uninstall a bundle
   -update ID     Update a bundle

   -initlevel N   Set initial start level for installed bundles
   -startlevel N  Set the beginning start level of the Start Level service

 Extra: (Only applicable when using ./kf2)
   -java PATH	  Use this JVM (Default=java)


 The default directory used for storing bundle data is  "fwdir".

 (*) Fully R4 compatible, enables support for bootclasspath extension bundles.

 For extended help and list of all available system properties, see online
 documentation or visit:

 http://www.knopflerfish.org/releases/current/docs/bundledoc/framework/index.html

xargs files

The xargs file are Knopflerfish command line options specified in a text file, typically ending in .xargs. This is a convenient method for specifying which bundles to start as well as setting framework properties.

The Knopflerfish SDK includes the following .xargs files by default

init.xargs
Initial or bootstrap start. Also used as default if no other xargs argument is given. See also Initial start vs restart .

Generated from template.xargs.in (only present in a full source file installation).

headless.xargs
Initial or bootstrap start to use when running the JVM is running in headless mode. Same set of bundles as in init.xargs except that bundles requiring AWT has been commented out.

Generated from template.xargs.in (only present in a full source file installation) with "$(AWT)" set to '#'.

minimal.xargs
Starts the framework and a minimal set of bundles.
props.xargs
One common xargs file that only set properties. Is used, or sourced, by other xargs files.
remote-init.xargs
Initial and bootstrap start with bundles loaded from an HTTP URL from a release specific bundle repository, located on www.knopflerfish.org, instead of loading from a file URL from the installation.
init-tests.xargs
xargs file for the Knopflerfish test suite. Normally invoked via an ant target.
test-restart1.xargs
xargs file for the Knopflerfish test suite. Normally invoked via an ant target.
test-restart2.xargs
xargs file for the Knopflerfish test suite. Normally invoked via an ant target.

Framework and System Properties

The behavior of Knopflerfish can be further controlled by specifying framework and system properties that are either specified by OSGi or Knopflerfish specific. The framework and system properties are described in detail in the framework bundle documentation .

There is a default properties setting in the props.xargs file.

knopflerfish-osgi-5.1.0/docs/release_notes.html0000644000175000017500000003236012346515440020624 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - Release Notes

Release Notes Knopflerfish 5.1.0 (OSGi R5)

Maintenance release of Knopflerfish 5 available from http://www.knopflerfish.org/releases/5.1.0. Released 2014-06-13.

Knopflerfish 5 is an implementation of the "OSGi Service Platform Release 5". It contains all services specified in the "Core Specification" and most of the non Enterprise Edition related services specified in the "Compendium Specification".

The Release Notes include all new features & changes for Knopflerfish 5.1.0 compared to the release of Knopflerfish 5.0.0.

Knopflerfish Framework - OSGi Core Specification

Framework 7.1.2
Fixed framework restart problem introduced in 7.1.0.
Relaxed "org.knopflerfish.framework.validator.date" parsing, so that it tries short US locale pattern if default locale parsing fails.
Framework 7.1.1
Fixed exception when doing BundleWiring.listResources on root directory.
Framework 7.1.0
Added new URL protocol "fwresource" to access resources from the framework classloader.
The start class org.knopflerfish.framework.Main now tries to load xargs as a framework resource if the file is not found. This means that we together with the new fwresource protocol can create a single jar that contains the framework, all jars and xargs files that needs to start a complete application.
Added property "org.knopflerfish.framework.readonly", that puts framework in a read only mode. This means that framework will not write any files in "fwdir". This means that if we are running with the default "file" bundle storage then new bundles must be installed as a referenced file URL. This also implies that no data storage will be available to bundles.
Framework 7.0.2
Fixed bug that caused IndexOutOfBoundsException when updating large collections of ConditionalPermissionInfos using ConditionalPermissionUpdate.
Added property "org.knopflerfish.framework.validator.date" to framework for testing certification validation with different dates.

OSGi Compendium Specification

UserAdmin 4.1.1
Now contains and imports/exports org.knopflerfish.service.log in order to be self-contained.
Changed to use the OSGi defined Bundle-Icon instead of Application-Icon.
KF-XML-Metatype 5.0.1
Fixed bug in handling of designate-element that could cause configurations to be created, deleted or overwritten unintentionally. Refactored handling of standardized OSGi metatype xml and legacy proprietary meta type xml into separate classes.
CM 5.0.1
Improved the persistent storage of CM data, made it more robust and fault resilient.
HTTP-Server 4.0.5
Fixed another bug in the handling of chunked transfer encoding in the Request implementation. The last chunk (with size 0) is not followed by any chunk-data and thus there is no CRLF to consume.
HTTP-Server 4.0.4
Fixed another bug in the handling of chunked transfer encoding in the Request implementation. A chunk contianing a charter followed by a new line char was not correctly un-chunked.
HTTP-Server 4.0.3
Fixed a bug in the handling of chunked transfer encoding in the Request implementation. An extra CR-LF was incorrectly added to the end of the decoded data, causing problems when transfering binary data like a zip-file.
Prefs 4.0.2
Added bundle icon.
Repository XML 1.0.2
Fixed a bug in RequirementImpl and did some clean up.
Repository XML 1.0.1
Fixed a bug in CapabilityImpl.
SCR(component) 5.0.3
Fixed missed factory component check in previous version. This miss caused following error:

java.lang.IllegalStateException: Internal error! Factory component only created with newInstance

SCR(component) 5.0.2
Fixed a bug that caused factory components to be falsely created or missed being created when we use target filters.
SCR(component) 5.0.1
Fixed a bug that caused problems when adding a CM configuration with a target filter to an unsatisfied component.

Knopflerfish Services

CM Desktop 5.0.2
Add requirement for the Meta Type Service.
KF Resource Analyzer Extensions 1.0.1
Added proper handling of Bundle-License according to osgi.identity namepsace.
Repository Commands 1.1.1
Bug fixes and some refactorings.
Repository Commands 1.1.0
Added [-r] flag to install command that tries to automatically find and install dependencies along with the specified bundle by using new methods in Repository Manager.
Repository Desktop 1.1.1
The dialogue now gives information about exactly what will be installed when asking if a Resolver should be used.
Repository Desktop 1.1.0
Added support for new methods in Repository Manager to use a Resolver service when available.
Repository Manager 1.2.0
Added install and resolverAvailable methods to RepositoryManager interface. Embedded Resolver and Repository APIs.
Repository Manager 1.1.0
Added support for Resolver services and added RepositoryManager.findResolution method.
KF-XML-Metatype 5.0.2
Only build an "all" variant. This makes it possible to correctly install CM-Desktop using the Repository Desktop with the Felix resolver.

Misc, start scripts, build system etc

init.xargs
Added commented out line to install Resolver reference implementation.
knopflerfish-osgi-5.1.0/docs/changelog.html0000644000175000017500000007605412346515440017733 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - Changelog
2014-06-13 00:51:04 +0200 (Fri, 13 Jun 2014), revision 4320, cl
Renamed Application-Icon => Bundle-Icon to map 1:1 with manifest header name
U   knopflerfish.org/trunk/ant/bundlebuild.xml
U   knopflerfish.org/trunk/osgi/bundles_opt/desktop_displayers/boing/build.xml

2014-06-12 22:19:49 +0200 (Thu, 12 Jun 2014), revision 4319, cl
Added support to include content from ${out.dir}/resources. To be used when adding dynamically created resources in e.g. a custom.pre target
U   knopflerfish.org/trunk/ant/bundlebuild.xml

2014-06-12 17:20:29 +0200 (Thu, 12 Jun 2014), revision 4318, jan
Fixed some small problems in preparation for next KF release.
U   knopflerfish.org/trunk/osgi/framework/build.xml
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/Main.java
U   knopflerfish.org/trunk/release_notes.in.html

2014-06-12 12:17:11 +0200 (Thu, 12 Jun 2014), revision 4317, cl
Added bundle icon for Prefs. Changed to use Bundle-Icon for UserAdmin
U   knopflerfish.org/trunk/osgi/bundles/prefs/bundle.manifest
A   knopflerfish.org/trunk/osgi/bundles/prefs/resources/
A   knopflerfish.org/trunk/osgi/bundles/prefs/resources/icon.png
U   knopflerfish.org/trunk/osgi/bundles/useradmin/bundle.manifest
U   knopflerfish.org/trunk/release_notes.in.html

2014-06-12 11:50:26 +0200 (Thu, 12 Jun 2014), revision 4316, jan
Changed RSA key length to avoid restrictions in Java 7 and later. Be more flexible in validation date parsing.
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/build_keystore.xml
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/validator/JKSValidator.java

2014-06-10 19:39:20 +0200 (Tue, 10 Jun 2014), revision 4315, jan
Fixed listRescources (SF#178) and added a testcase. Detect dead-lock when doing dynamic import in permssion check (SF#179).
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/Activator.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/BadBundleListener.java
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/BundleWiringTestSuite.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/CapabilityTestSuite.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/FWTestCase.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/FragmentTestSuite.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/FrameworkTestSuite.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/NativeCodeTestSuite.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/PackageAdminTestSuite.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/PackageTestSuite.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/PermissionTest.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/PermissionTestSuite.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/RegListenThread.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/RegServThread.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/RequireBundleTestSuite.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/ServiceListenerTestSuite.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/framework_test/src/org/knopflerfish/bundle/framework_test/Util.java
U   knopflerfish.org/trunk/osgi/framework/build.xml
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/BundleClassLoader.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/Resolver.java
U   knopflerfish.org/trunk/osgi/init-tests.xargs.in
U   knopflerfish.org/trunk/release_notes.in.html

2014-06-09 14:43:48 +0200 (Mon, 09 Jun 2014), revision 4314, jan
Add framework property to put framework in read-only mode.
U   knopflerfish.org/trunk/osgi/framework/doc/index.html
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/FWProps.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/FrameworkContext.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/Main.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/StartLevelController.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/Util.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/Archive.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/BundleArchiveImpl.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/bundlestorage/file/BundleStorageImpl.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermissionInfoStorage.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/permissions/PermissionInfoStorage.java
U   knopflerfish.org/trunk/release_notes.in.html

2014-06-09 08:00:49 +0200 (Mon, 09 Jun 2014), revision 4313, jan
Added framework resource protocol
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/src/org/knopflerfish/bundle/component_test/ComponentTestSuite.java
U   knopflerfish.org/trunk/osgi/framework/build.xml
U   knopflerfish.org/trunk/osgi/framework/doc/index.html
A   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/FWResourceURLStreamHandler.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/FrameworkContext.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/Main.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/ServiceURLStreamHandlerFactory.java
U   knopflerfish.org/trunk/release_notes.in.html

2014-05-15 17:53:50 +0200 (Thu, 15 May 2014), revision 4312, ekolin
Fix buidling of the compact framework version when using Java SE 7+.
U   knopflerfish.org/trunk/osgi/framework/build.xml

2014-04-11 09:58:17 +0200 (Fri, 11 Apr 2014), revision 4311, ekolin
Make sure that CM-Desktop can be installed by the Desktop Repository when using the Felix Resolver service.
U   knopflerfish.org/trunk/KnopflerfishEclipseDictionary.txt
U   knopflerfish.org/trunk/osgi/bundles/metatype/cm_desktop/build.xml
U   knopflerfish.org/trunk/osgi/bundles/metatype/cm_desktop/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/build.xml
U   knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/bundle.manifest
U   knopflerfish.org/trunk/release_notes.in.html

2014-04-11 09:07:19 +0200 (Fri, 11 Apr 2014), revision 4310, ekolin
The eol format was mixed, change to  on all lines
U   knopflerfish.org/trunk/osgi/template.xargs.in

2014-03-19 13:25:40 +0100 (Wed, 19 Mar 2014), revision 4309, perg
Made UserAdmin self-contained wrt kf log utility
U   knopflerfish.org/trunk/osgi/bundles/useradmin/build.xml
U   knopflerfish.org/trunk/osgi/bundles/useradmin/bundle.manifest
U   knopflerfish.org/trunk/release_notes.in.html

2014-02-25 16:00:35 +0100 (Tue, 25 Feb 2014), revision 4308, perg
Changed spelling error sources to source
U   knopflerfish.org/trunk/ant/bundletasks.xml

2014-02-24 21:52:00 +0100 (Mon, 24 Feb 2014), revision 4307, perg
Fixed bug in kf_metatype bundle and refactored handling of standardized and proprietary xml formats.
U   knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/src/org/knopflerfish/bundle/metatype/Activator.java
A   knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/src/org/knopflerfish/util/metatype/KFLegacyMetaTypeParser.java
A   knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/src/org/knopflerfish/util/metatype/OsgiMetaTypeXmlParser.java
U   knopflerfish.org/trunk/osgi/bundles/metatype/kf_metatype/src/org/knopflerfish/util/metatype/SystemMetatypeProvider.java
U   knopflerfish.org/trunk/release_notes.in.html

2014-02-20 13:40:39 +0100 (Thu, 20 Feb 2014), revision 4306, jan
Fixed an IllegalStateException for factory components.
U   knopflerfish.org/trunk/osgi/bundles/component/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/ReferenceListener.java
U   knopflerfish.org/trunk/release_notes.in.html

2014-02-14 21:46:06 +0100 (Fri, 14 Feb 2014), revision 4305, jan

U   knopflerfish.org/trunk/osgi/bundles/cm/cm/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/cm/cm/src/org/knopflerfish/bundle/cm/ConfigurationAdminFactory.java
U   knopflerfish.org/trunk/osgi/bundles/cm/cm/src/org/knopflerfish/bundle/cm/ConfigurationStore.java
U   knopflerfish.org/trunk/release_notes.in.html

2014-02-05 17:24:41 +0100 (Wed, 05 Feb 2014), revision 4304, ekolin
Http 4.0.5; more fixes for handling of transfer encoding chunked.
U   knopflerfish.org/trunk/osgi/bundles/http/http/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/http/http/src/org/knopflerfish/bundle/http/RequestImpl.java
U   knopflerfish.org/trunk/release_notes.in.html

2014-01-29 13:32:42 +0100 (Wed, 29 Jan 2014), revision 4303, ekolin
Add missing ignore for generated file.
_U  knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/resources/

2014-01-29 12:04:57 +0100 (Wed, 29 Jan 2014), revision 4302, ekolin
Rewrite unchunk code to simple read the number of bytes that the shunk shall contian, ignoring any CR or LF in the data.
U   knopflerfish.org/trunk/osgi/bundles/http/http/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/http/http/src/org/knopflerfish/bundle/http/RequestImpl.java
U   knopflerfish.org/trunk/release_notes.in.html

2014-01-29 11:10:48 +0100 (Wed, 29 Jan 2014), revision 4301, perg
Improvements to Repository Desktop and some minor fixes
U   knopflerfish.org/trunk/osgi/bundles/repository/repository_desktop/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/repository/repository_desktop/src/org/knopflerfish/bundle/repository_desktop/RepositoryDisplayer.java
U   knopflerfish.org/trunk/osgi/bundles/repository/repository_xml/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/repository/repository_xml/src/org/knopflerfish/bundle/repository/xml/CapabilityImpl.java
U   knopflerfish.org/trunk/osgi/bundles/repository/repository_xml/src/org/knopflerfish/bundle/repository/xml/RequirementImpl.java
U   knopflerfish.org/trunk/osgi/bundles/repository/repository_xml/src/org/knopflerfish/bundle/repository/xml/ResourceImpl.java
U   knopflerfish.org/trunk/release_notes.in.html

2014-01-29 10:19:30 +0100 (Wed, 29 Jan 2014), revision 4300, ekolin
Fix problem with decoding of chunked tranfer encoding in the Htt-Server.
U   knopflerfish.org/trunk/osgi/bundles/http/http/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/http/http/src/org/knopflerfish/bundle/http/RequestImpl.java
U   knopflerfish.org/trunk/release_notes.in.html

2014-01-22 10:43:46 +0100 (Wed, 22 Jan 2014), revision 4298, jan
Fixed bug with ConditionalPermissionUpdate.
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/condpermadmin_test/src/org/knopflerfish/bundle/condpermadmin_test/CondPermAdminTestSuite.java
U   knopflerfish.org/trunk/osgi/framework/build.xml
U   knopflerfish.org/trunk/osgi/framework/doc/index.html
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/permissions/ConditionalPermissionInfoStorage.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/validator/JKSValidator.java
U   knopflerfish.org/trunk/osgi/framework/src/org/knopflerfish/framework/validator/SelfSignedValidator.java
U   knopflerfish.org/trunk/release_notes.in.html

2013-12-12 14:55:26 +0100 (Thu, 12 Dec 2013), revision 4296, perg
Fixed spelling error: source -> sources
U   knopflerfish.org/trunk/ant/bundletasks.xml

2013-12-12 13:44:26 +0100 (Thu, 12 Dec 2013), revision 4295, perg
Work in progress - support for repoindex
U   knopflerfish.org/trunk/tools/mvnrepo/build.xml

2013-12-12 13:42:21 +0100 (Thu, 12 Dec 2013), revision 4294, perg
Work in progress - support for repoindex
U   knopflerfish.org/trunk/tools/mvnrepo/build.xml
A   knopflerfish.org/trunk/tools/mvnrepo/mvnrepoindex2html.xsl

2013-12-12 13:20:25 +0100 (Thu, 12 Dec 2013), revision 4293, perg
Work in progress - support for repoindex
U   knopflerfish.org/trunk/ant/bundletasks.xml

2013-12-12 12:47:13 +0100 (Thu, 12 Dec 2013), revision 4292, perg
Work in progress - support for repoindex
U   knopflerfish.org/trunk/ant/bundletasks.xml

2013-12-12 12:25:07 +0100 (Thu, 12 Dec 2013), revision 4291, perg
Work in progress - support for repoindex
U   knopflerfish.org/trunk/tools/mvnrepo/build.xml

2013-12-12 12:21:20 +0100 (Thu, 12 Dec 2013), revision 4290, perg
Work in progress - support for repoindex
U   knopflerfish.org/trunk/tools/mvnrepo/build.xml

2013-12-12 12:14:02 +0100 (Thu, 12 Dec 2013), revision 4289, perg
Work in progress - support for repoindex
U   knopflerfish.org/trunk/tools/mvnrepo/build.xml

2013-12-11 10:32:25 +0100 (Wed, 11 Dec 2013), revision 4288, jan
Fixed a bug that caused factory components to be falsely created or missed being created when we use target filters. Also added test-cases for this.
U   knopflerfish.org/trunk/osgi/bundles/component/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/Component.java
U   knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/DelayedComponent.java
U   knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/FactoryComponent.java
U   knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/ImmediateComponent.java
U   knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/Reference.java
U   knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/ReferenceListener.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/build.xml
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/src/org/knopflerfish/bundle/component_test/ComponentTestSuite.java
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/build.xml
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/bundle.manifest
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/resources/
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/resources/service.xml
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/bundle/
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/bundle/componentM_test/
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/bundle/componentM_test/ComponentAImpl.java
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/bundle/componentM_test/ComponentB1Impl.java
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/bundle/componentM_test/ComponentB2Impl.java
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/bundle/componentM_test/ComponentCImpl.java
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/service/
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/service/componentM_test/
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/service/componentM_test/ComponentA.java
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/service/componentM_test/ComponentB.java
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentM_test/src/org/knopflerfish/service/componentM_test/ComponentC.java
U   knopflerfish.org/trunk/release_notes.in.html

2013-12-10 13:45:26 +0100 (Tue, 10 Dec 2013), revision 4287, perg
Corrected bundle and package versions
U   knopflerfish.org/trunk/osgi/bundles/repository/repository_desktop/src/org/knopflerfish/bundle/repository_desktop/RepositoryDisplayer.java
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorycommands/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/service/repositorymanager/packageinfo
U   knopflerfish.org/trunk/release_notes.in.html

2013-12-09 14:56:08 +0100 (Mon, 09 Dec 2013), revision 4286, perg
Improved support for Resolver in Repository Manager. Updated Repository console and desktop bundles to use the improved support. Embedded Resolver and Repository APIs in Repository Manager.
U   knopflerfish.org/trunk/osgi/bundles/repository/repository_desktop/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/repository/repository_desktop/src/org/knopflerfish/bundle/repository_desktop/RepositoryDisplayer.java
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorycommands/src/org/knopflerfish/bundle/repositorycommands/RepositoryCommandGroup.java
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/build.xml
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/bundle/repositorymanager/RepositoryManagerImpl.java
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/service/repositorymanager/RepositoryManager.java
U   knopflerfish.org/trunk/osgi/template.xargs.in
U   knopflerfish.org/trunk/release_notes.in.html

2013-11-18 11:26:55 +0100 (Mon, 18 Nov 2013), revision 4285, perg
Updated w/ Resolver related updates
U   knopflerfish.org/trunk/release_notes.in.html

2013-11-16 00:14:56 +0100 (Sat, 16 Nov 2013), revision 4284, perg
Added commented out line to install a resolver
U   knopflerfish.org/trunk/osgi/template.xargs.in

2013-11-15 23:44:51 +0100 (Fri, 15 Nov 2013), revision 4283, perg
Added support for Resolver Service 1.0
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorycommands/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorycommands/src/org/knopflerfish/bundle/repositorycommands/Activator.java
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorycommands/src/org/knopflerfish/bundle/repositorycommands/RepositoryCommandGroup.java
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/build.xml
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/bundle/repositorymanager/Activator.java
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/bundle/repositorymanager/RepositoryManagerImpl.java
A   knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/bundle/repositorymanager/ResolveContextImpl.java
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/service/repositorymanager/RepositoryManager.java
U   knopflerfish.org/trunk/osgi/bundles/repository/repositorymanager/src/org/knopflerfish/service/repositorymanager/packageinfo

2013-11-15 23:44:02 +0100 (Fri, 15 Nov 2013), revision 4282, perg
Fix in equals impl
U   knopflerfish.org/trunk/osgi/bundles/repository/repository_xml/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/repository/repository_xml/src/org/knopflerfish/bundle/repository/xml/CapabilityImpl.java

2013-10-24 14:49:23 +0200 (Thu, 24 Oct 2013), revision 4280, perg
Updated release notes and set correct bundle version
U   knopflerfish.org/trunk/osgi/bundles/repository/repoindex_kf/bundle.manifest
U   knopflerfish.org/trunk/release_notes.in.html

2013-10-24 14:34:07 +0200 (Thu, 24 Oct 2013), revision 4279, perg
Updated changelog.txt
U   knopflerfish.org/trunk/changelog.txt
U   knopflerfish.org/trunk/osgi/bundles_opt/junit/osgi_ct_adapter/src/org/knopflerfish/bundle/osgi_ct_adapter/Activator.java

2013-10-24 14:26:15 +0200 (Thu, 24 Oct 2013), revision 4278, perg
Fixed parsing of Bundle-License
U   knopflerfish.org/trunk/osgi/bundles/repository/repoindex_kf/bundle.manifest

2013-10-24 14:21:24 +0200 (Thu, 24 Oct 2013), revision 4277, perg
Fixed parsing of Bundle-License
U   knopflerfish.org/trunk/osgi/bundles/repository/repoindex_kf/src/org/knopflerfish/bundle/repository/index/KnopflerfishExtentions.java
A   knopflerfish.org/trunk/osgi/bundles/repository/repoindex_kf/src/org/knopflerfish/bundle/repository/index/Util.java

2013-10-23 18:00:48 +0200 (Wed, 23 Oct 2013), revision 4276, jan
Fixed a bug that caused problems when adding a CM configuration with a target filter to an unsatisfied component.
U   knopflerfish.org/trunk/osgi/bundles/component/bundle.manifest
U   knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/Component.java
U   knopflerfish.org/trunk/osgi/bundles/component/src/org/knopflerfish/bundle/component/ReferenceListener.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/src/org/knopflerfish/bundle/component_test/ComponentTestSuite.java
U   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentC_test/resources/service.xml
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentC_test/src/org/knopflerfish/bundle/componentC_test/ComponentUImpl.java
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentC_test/src/org/knopflerfish/bundle/componentC_test/ComponentVImpl.java
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentC_test/src/org/knopflerfish/service/componentC_test/ComponentU.java
A   knopflerfish.org/trunk/osgi/bundles_test/regression_tests/component_test/test_target_bundles/componentC_test/src/org/knopflerfish/service/componentC_test/ComponentV.java
U   knopflerfish.org/trunk/release_notes.in.html

2013-10-23 17:50:15 +0200 (Wed, 23 Oct 2013), revision 4275, jan
Update framework documentation with some 5.0.0 changes.
U   knopflerfish.org/trunk/osgi/framework/doc/index.html
U   knopflerfish.org/trunk/osgi/framework/resources/help.txt

2013-10-23 10:17:09 +0200 (Wed, 23 Oct 2013), revision 4274, ekolin
Switch to proguard 4.10
U   knopflerfish.org/trunk/ant/build.xml
U   knopflerfish.org/trunk/ant/bundletasks.xml
U   knopflerfish.org/trunk/osgi/framework/build.xml

2013-10-22 16:44:48 +0200 (Tue, 22 Oct 2013), revision 4273, ekolin
Automatically download proguard from maven central.
U   knopflerfish.org/trunk/ant/bundletasks.xml
U   knopflerfish.org/trunk/osgi/framework/build.xml

2013-10-22 15:53:19 +0200 (Tue, 22 Oct 2013), revision 4272, ekolin
Remove reference to OSGiR4v4.3
U   knopflerfish.org/trunk/osgi/framework/doc/index.html

2013-10-22 13:40:10 +0200 (Tue, 22 Oct 2013), revision 4271, ekolin
Fix another bundle repository link.
U   knopflerfish.org/trunk/htdocs/html_templates/template.html

2013-10-22 13:03:21 +0200 (Tue, 22 Oct 2013), revision 4270, ekolin
Nightly builds should say maintenance release, not major release...
U   knopflerfish.org/trunk/release_notes.in.html

2013-10-22 12:56:46 +0200 (Tue, 22 Oct 2013), revision 4269, ekolin
Remove some warnings for the ant tasks. Fix link to Makewave logo in nightlybuilds page.
U   knopflerfish.org/trunk/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleArchives.java
U   knopflerfish.org/trunk/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleInfoTask.java
U   knopflerfish.org/trunk/tools/nightlybuild/snap_index.html.pre

2013-10-21 21:06:51 +0200 (Mon, 21 Oct 2013), revision 4267, jan
Post release 5.0.0 update
U   knopflerfish.org/trunk/build.xml
U   knopflerfish.org/trunk/release_notes.in.html

2013-10-21 21:01:35 +0200 (Mon, 21 Oct 2013), revision 4266, ekolin
Fix href to the style sheet.
U   knopflerfish.org/trunk/ant/bundletasks.xml

2013-10-21 21:01:14 +0200 (Mon, 21 Oct 2013), revision 4265, jan
update version
U   knopflerfish.org/trunk/tools/mvnrepo/build.xml

2013-10-21 20:57:21 +0200 (Mon, 21 Oct 2013), revision 4264, ekolin
Bundle repository link should point to the new repository file.
U   knopflerfish.org/trunk/htdocs/html_src/release_page.html.in

2013-10-21 19:25:29 +0200 (Mon, 21 Oct 2013), revision 4261, ekolin
Also search for the repoindex bundle in the direcotry to index.
U   knopflerfish.org/trunk/ant/bundletasks.xml

2013-10-21 17:29:38 +0200 (Mon, 21 Oct 2013), revision 4260, ekolin

U   knopflerfish.org/trunk/changelog.txt

2013-10-21 17:02:56 +0200 (Mon, 21 Oct 2013), revision 4259, ekolin
Merge of the KF-5 development branch.

knopflerfish-osgi-5.1.0/docs/index.html0000644000175000017500000001555312346515440017110 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - Open Source OSGi Serivce Platform

Knopflerfish version 5.1.0

This is the documentation for version 5.1.0 of Knopflerfish - OSGi Service Platform.

Knopflerfish 5 (KF5) is the first release of Knopflerfish which is implemented according to the OSGi R5 specifications.

The Contents section provides a summary of what is included in the release.

The Release Notes has the full summary of all changes.

About Knopflerfish

Makewave is the maintainer and sponsor of the Knopflerfish project and has several developers assigned to develop and maintain the Knopflerfish OSGi distribution.

The Knopflerfish project's goal is to develop and distribute easy to use open source code, build tools and applications, related to the OSGi framework. See charter for details.

The OSGi Service Platform

The OSGi Alliance specifies the OSGi Service Platform, an industry standard Java application platform, allowing multiple applications, to securely run in a single JVM. These programs can share resources as data, functionality and threads.

Knopflerfish OSGi is an implementation of the OSGi Specifications.

Applications areas for OSGi ranges from use as a service platform on embedded devices, to plugin mechanisms for larger programs. The initial goal of OSGi was the embedded market, but other uses are certainly possible.

For more information on the OSGi Alliance, see http://www.osgi.org

knopflerfish-osgi-5.1.0/docs/tutorials/0000755000175000017500000000000012475375714017143 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/0000755000175000017500000000000012475375714022507 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/readme.txt0000644000175000017500000000040112346515440024465 0ustar felixfelix This directory contains the OSGi Tutorial (in OpenOffice Writer format) originally by Sven Haiges and updated by Erik wistrand. The example_source directory contains the source code used in the tutorial. These examples depend on ${kf.dir/framework.jar} knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/kf_osgi_tutorial.odt0000644000175000017500000130205712346515440026560 0ustar felixfelixPK:^2 ''mimetypeapplication/vnd.oasis.opendocument.textPK:Configurations2/statusbar/PK:'Configurations2/accelerator/current.xmlPKPK:Configurations2/floater/PK:Configurations2/popupmenu/PK:Configurations2/progressbar/PK:Configurations2/menubar/PK:Configurations2/toolbar/PK:Configurations2/images/Bitmaps/PK:l))-Pictures/10000000000003350000022BB09A896E.pngPNG  IHDR5+Y% )JIDATx]`֞[(cIU#MDTlbCC `AAvEEyR,O齉 (V:""!-;ݻ&|ei;9gf%.c < RV?G0?Weà*@_'v񀣇ƣnPdqyu|9.pI+B_"V8#G [RBf90Mc"Ǥw#y?x3t4!Kոg8G`o,|KlWl-OMN]lȇBÃ/0^q ϗ)SzZӗEn NFܬQd$e8Q|9)"hgQܑqS$; mit]߽7GsLL@.Yß9}o~c`fpCs7/ " ΈF L5P_0=;g`j p&J=vvB@R_oE(WXD NSw0 >dB.KLE⨖3A2k" aaR'l_nd@";[b1b,/]B/҈"Yf:LҡUB%{CTE^n,b/ 5b6DLCY,CP $!vD^Xkp)VuLU D;8Vgl 9xMGi-0":Bf*2y#-m3x'2OeCL q[!B'] 3lmpm"6V>@VĎ{ 눠A+3XizzS |3P+8}Ǩ@vKPRʲJ0= "4zR<:0!ll23:$b=}o[v> ܠlwŲ؟g=mOvNY*-,۲jU-#*2 2Ar`J+0HwgBm7Ll+$WYΞe+UZ@A[29OA(F.{arl"p2ѱc'\ }P.Xvqy߇W/tiJpfb13ye3‹6" &1B3ZFyRvke~⌛*xEəP!,2y蠄|=A#60T:QD;BE{t!583]\ 1)^ qB()Ӡ݀LcFL&|aZDH[Z 1YML(q4丼2#$LgH|ܗc:T/Ai0u/Xd5L= 9_I|Y:L P'`KP\[Ydgg ! I5FvYؒ朎 2(yk(>Eh1zaw 2}a}^1FS/9Ik eúR 2!;/ w̸xO ?hMr{'4냊 7!60. 3 eE;{-fx M2J^N CE%Y!8"H"m&BdS3dq 2gUH=)ȸrN(h656qoKƄq@΁?".DGPr "\K€7gWpʯ/ mW]_=kUB6W0f$'OJ\dž+U~_5T' 4̺0= b8lL-F4?~z7ANw1-{|'^0 RMZ*w,@D[ SP~}3{!$8 6IU ƶP7 3I 2P(H jLFX Exֈy a تg<HPrKsHHV)efDHj8'3ӤǼ[#pia$&Hg&" ,\(?cԔIy 3,*a%.iZVSG$L8FS$\ r%  Pho-I &aO`0`TRr"ڇ15" pۖ(JZh"*EsR{M6 =+Urj0FUZ9Und .J&{id7dp G $KDJZ%bPa#H:$$l'4ϑ'Rk" gBXg=*6V$*Y½&`M `!SNk H$urJG+eo~tx|b!&Ba$)N>& Xx ǜJh~Ehx{!LZDVXZ,i0bY[^fp,RVzE;|5*6:^Dr^^>{qQD`>|/lUK/kIHHGR%'O%| %@"ȎA%{ó3 w4u &6K , -`"L+u+"\3X 'sCy2k]E._Ɍ ”vFF2)?WI˖oDߛ'ޘ:hM~;s˸-2qLd9S#TQծQ3hֿ?@O''HtL,8ٽ~}XQõ,)їd2;hK4/{wm! oylƶ)7 U%<9[UX:>Y38&6m}y E.&&x7!1%)AT!#uiޙDzNƆ;{EeR`Xt2YFR}%SLsw=zǿ |IR0cXbD_1V(?##9 g}*a o=0K7.wo/h2uRc1#aCol`r>:y'>\ JL)-4>ꑞ9P0.<֛RCKL1x#IИ93da?UxdcLVvJ4E8D1qÍFd;07KYgɁDg wSxT1$qR%( !B&g = SNulofPǂq-&N2r)ܧYPh$FA$|9)3 KUhPT 1c=<9u&d}לA,T_XXd!p)l_Ro]>3fqbzaS%?߲ͼ?cKn ÞRd7ƭ;cՒ̅ :4G:/V CG2p",jԠujnԭx)K _Hb@̊;@~9 .L&`@rjZDٶWVgB4^aL"/_Nz;vW=w1g+#27XDwT]BZᡷsb۟ydƖΗz1DcangıOf]9^PpZ+n@CլD;+g ?l; &Qv|iu*Y@4s,Z6K$L'Lѐ:3$[2S {I[R+jf&PB JT5BHW]Typ9ڑRė9fMPʰ06rr\!LHyMJN,f) jΕwuKCrR7^O8a:$:UDl#,}trv"E^"6Gy1;RcZWJr!O *.4.uΠ䤓sr6ԕ}%{~‰8xJ\͎H @bedP\%%.%YhUSy=ֲuJ2H)Mhp K"p?NYcSY,cܵKhh4_M oʲJ[+:ȲO:͏,e7P(??FrsO'%,?N@E |Fr3C^Gr%~\͍7UMX]|T, Ҥq%1riapg[ WQ8pޔC{?S3[nݸ锯?c}ˆ|hoMjZP>2I8_=qVhš'06}\ɁN|z]_os:3s++=#97V>xMBv`ʼn ޻|{ol0!|™-/C|x}7i׼s5Wl葦w̐#ΕɊвӻ?i] S^ 1gh{r/}jhЪC?[6QdEb2{| ͺrX{;8w|2iϲ~G8 lۄyM$muzNtM\/yRoѢܡj? Eݼ{:KgR[{f3Ճȥ{Z9Mj*_f}ֆW&P,fu~73ɜ>)}/m]x1l<:SLvɧEe"T SMDoi붙 3A@>j#4Ҙ¬(]ɏU6վņGѬ!F 屑l,-ESmMTwF p3EP)Q wۓ&#B+" oT%Q,w4gBh2N!"Em'Q`)Ng<^mNk9T($ij;9|]gxB'*}ļ9 ㋂PadЦжB@,ţ]NYr 5{q+NbK?%V=N|`@MY],,MJNQws*X6iRuZwzyZku_^Ѿ}VMt/aXr!̗11Q} I'yŗj@A޺kCՂݏ&'&xm[QٲPHP񅳾/lSP1OuiM?~f|md,MI3v]|id{z|Xexcҏ@)ѱ0Pf׭k*A׾rCH9׻rrﴫ|DhnU_9._}gֽf8j`fmAx}YS'APjGϏ$nYhrCq׎_:merC9q4gk O]6Sיq> f9m#M6a澅u i}5JfY߬L\ڿxp&GMΗGS~Q΁iǶ-bsۧ?]wj~`/8̾U-%٣В'=R>qǾyKnYuوp p=6nvuB}3hBߦd|xkn80/4@}Jkv/ݸ B(xyJ'3eOk[Y*gR=e]7,y%׌U5Rx2nUx;q@U@<*3愉4t/( }(B qpaQ47`EGAnd͚ {! Y/`#GIsFRd=DAF:>,csHG-@h5$y^ ULPE! ΆB )|AzNv=r<R!9-Bi s.DdU]Mɹ;lɼFbR\|8ax? zF C>7_$0PM?q܊S,b% %s5Nc!x&@_6;[]8Dl [d@Ckl(x "!oUXɢC(H^JJR41"^`0d*&Q({9ıӄ̋d 1xC5Z- v]ٓ٦2ʷ34o6K"}WO'fm>2+XߧE"-߼^u F47c~Zw_I|83qYi)3moY"0X lo)D~Eʖ@[nqhϚY95\MA?M(V>պ#>. teΛ=_ {z֑Ouo̖ȈUO 9(߭Q< 1вm6eDİn];i拄̜8杠nNܿus @߬r曳6o^ O _N_le߼T.?bu}eMʆ$n=7zeV]WMN17yvvxyY/K1D|eiYY s|7 kơʥKQBԺ9(9ý3> 9lP~.R.XbS!yթs F?g#ܮm@eKCJ2IzFo2b yd0hH )AK(R$#bs PD4АIr%4\z%3g1(^-9TN r}3)4đD$55"(=KU@V)JOU4j 2ZO)F|3)99+]D~Eb՚ݖ@ϔZءXGtMJLOH4årI XZYH*'@KJHMef2&7 9$U@yH7 {'W`.hJԘqӛX%ĉ%Yވ6!?@Cb-]9w:mΔ*ǟRSRY& 22ӤU i׿Q֕s_ "<¬ r֧p,@\0"Y,}ch3[`$x8wspˋ<&6v7{ϙQ+ڌ>}i};mN]:%y'9'Z,n %#>r-D٪k\Rt}7[y̪ʨFLtie 2e9̣W@:wZU44vl6!VI&\ u< A&4%)3ž)|sW Z̩П/e =)l6rҴ6W]O훗O,syêEUX0L8BV5D r9)v}2r܀gX> "/p, (~& SGqXXک35[g?d'g?U1x ٣!MpDI:8nKP9H* ^Tk qZcQ/:@kB4ː01 R SYM+H@"$rF(e,v;P6P1Jrrzu(⧉d '/JψAld0/4bZ4LKR .Nd`Q8FC **i8\ ]\zyweZ6wNJlz?1)%%)e‡̰O}f/^2g bKjqn>}{^EfRÏl6,SI}^xi⮯wzǿ ao2=^VkzS$̛ bwlKrmߴAn,Wsf]{ۀ)/X>|TExƅl [W?f*(_ύY׎m[AXيW^u:hZ tzsVc#VԵC5}W;[40mJ6tPpcMwޑPΒfFh=K:mW,}xtf,sYO(OE'zƎ>\+)Y& nW-MiQ ,eIsng:Γ/?Sá}M޼oڢ<םS|]NMV_:%\^!d5*-~Et:#a01+А2* Pˏ&c(Z3:ltv VEbH+S;]JO β@\nր٦BxIRM!⮢Q°]ש/_aD2F{9>sޱbmVa 1#EO1eG'.@uehD(DXdZqWu%TV9زVl?Hy7HLnƟb*/T m>Mqל7 HLHY+,-8έrYGʭ6M1-_Guv}dAW,#D#|iѐբEU*]ܦUc^6-\{ {P@>Y`$L [>1ᦦ}3a0 ǵz]/K#weY~7fdMߟ߻.Yb@%;,! uMo:k$, N0H74&_K!P^Ic\;jߏ_4g^YU@ xPְ-fOꒁP~Zo 3yY3pFg;k:PE(kأ>s8\>cċ75=6>_ss׶,D :uֵm|e֤9uxKnUfM=7^2''|۽Y$FC3RY:3!NLN_~f: hRZ:KP8/6`g/ΠmF|:mMзFyӪ՚ !/mX:I.PAdFpwqh B$px\iørGy??5j ?\T\ $?դ$ &f9@wzτIl3*OK t,k(ja4AѤˏhB[kEsƺ$o k ;BJQ.]=.qCQ@bõdP2fzUj) ѮR/e !D9J7l\:=e0:sė6dP8:+RY|+Հb%EF [~n:C>U5WNBsP/a"$AV!_qXrT'Fin $|챁51cO8LfBeޱ0nCW@i{ZuWw>m7^a=!A-oObJrF:ç|mρ# J? cmνUQnsO&x^\y7kB0\\a/ 8D@A@#P 6|nQ^-P!}8RPdqnc :YT6ie|OwyY[u[G*11=LwP?)M_^ˀOlC ~Uu UxnXk:il^V#~2>e?L^^&_PWzc*+Lk_KYi\dUȇ4ˇ_G?G$i$Ȋg`H20$Ris䐲U)hæǰ愝SA{L-<ࡾI~.Ȕ NXYTTM_,u7lWnA89 J7/111^$qu)RسݹO5蚶{mt2t4&{6L%ޔ[ 9CتbZ2m> vdgc`E6jt0d C]XpCs""e:!ԩOWR,ũHZȞMbR !3Wj<` 7 ˱ ˊg ;.*B\!dx@ C/[#M-E(Vw{P Q/$hTEʩȢjS rHP>&hK"^LVB3)YG.-EyK+f&3KOt9a#> aC^.1!)NdgVlV#"RՈ*M\ݘK;aĉYWlv2v rGvdq^ѡ(ф n:[{xzg$șaY]{.COQfqaipfDcݑmw2 *{,Җƌ" Yrsb@#9ΣW,=X+2zs%䌞Eh.*R| ;Aq+ՅfƊB'!ZqZܛ-:K[8NZQLDJE'd&YTv^q;c(3 zdMwȑA3^ƐvsH1H3`+b{UUGSJm?s /*4rP_peحip.Ak"8ZĘq;r';?V)],FeQZ)_ sKlW2is$d G⇼qb0@o`Y,+KR 8S5iT `aUȥ@>V<}0b] $J^wiaćO%=VM,=kcXN(ݙCQ*3C^ddsDZ~f(pZ_~L|>T.e섻 @c)8g0Ah 4i[J4sd bOSHQ؆q5w9E,CpZl"XLBGBj,RP`u;J)oj[l[r=C̫kp_j4`cHF/BS[Ԙ;CRyc X'2m$Ct2lMK\ P2K`.)E,CZ_e-s)xjɵVKDEiܻ]yFQ5J:[?K"77ձ:pUjT(#Jټc(<~s ^Xh}RUVdgJQ$a8*0M RD:Wi2tD黅q_ΜC:fYmk=(Ƌ &ܭ_+pho_ xD: 3:mtS3Z[9xBV/|-lV#R\-d'.viG;Tg5gQr8ɳڽ $'Jđ +#O0ƓQnC!S\dJ\q:Jpн<5JCCCw,wiMv̬^7M `0.É/Ėq _R3o:/`@nHCwQm8=tERSzBSi/30_ YQ=BaM444444448Rͭ76aC(hhhhhhhhh>fzX֔>DjզXT.iZq<'?15<+E*tXo/_ws}ϯ_*zq"rkj~ȼL`oSxlEb%ЁE&eoQfݰ".KiWb8 M`7SWldg͞n};7Al)PKܥU]JBŢ5xWkQ%ЁsζY._5uyX|.z%F` sA,3b3P^~|L'>z+f$b=y7ηPj_oXxL*Nʧ_ї_ kݚlƱ0ƌpVR8C0r k>S5LG[{4FOeYY -ZR,b]%u$aޭIGfi[,6^jgY[A kt,7#.|Y NLb#w}ݱ{z)[^j =x? phd>eb¹ Wb;(5c }xLX'V\غ1~/m;7};lW}ło(;72Y[K%_ǴZe$dkabY[^ͻ2}ʩYc͔cZn`wwڱiqyNk{<|zz,Ox1J~ii>E LLCCCCC㬂Բor v]b]~k6qGT7|##Pشk>]X$DK;gC;T[?Lq-@iIF(Yknw{`|YK|@h[f d ׫L Cel^227&=\edyҊ~#ۂU8t/T,1o޺Vo tόl=U-f$0a۷L8ޡ t+nX]2 Tqф ncr0?~x BH 0sz1DߢEũK_֟ihhbk'?[?9N1϶j(ӻ;Ms瞽%*YW.~%RRU랊fm޴1Tɜ:O-SЭIʖ-9jԌ <}FKlP'N'NظqcNNg10?RJFFwCv2 *`Q@&IǎѨWÇ9r乍?xB~rgo@^ޘׯzB94444j$MGگ"arK{iuBC߯`ps׆W\~2/L?mގY8^:i 0}_fy@ fJe1=z ڳg&"^711@lޤ8|p^^^RVMo>yk…k׾K O4 g ;1b<.(`0x*][NaI~aEMG0QihhhMо}'"Q=|"SL-uo\jß ָēY;MhPhn۲es:eZnw27ʈ_ P`!ܓ B*Փ8rHAAAjjjŊt shg}D,`6uīTkUN\-fU&L%&rQeLL~%{kW~ÊGS/kɦcfߟ\BLϊa a 8qD ߸`0s%gEر㮻4iRzzkT&'''R`)[칟+2d3o޼y L˞x≮]7^{ Fth_"ũuHY< R@˸o{իA2C OQ:=E 9ASrF ),3a>Ycٹ5՞Sԁu3zz5<,ڽveԜqNM鈉uǻlsE'oE8Tl ۉS)ّZcv*XGi[hBQ~z_0ʖNSfW yS﹡s/Ӂ672"Td/條;\s@BbB9)1YAA#Eӟgk֬iӦnޫ_~wE9YRR.q\(x \瞓ݎ>pС#F\qZZ| {W^yP+9IEw"FD]|z8r& [reBRSo,MBNM3QYQw(L`;]{ EJ`v.溞=foG(MyK:ÇcgՅiJ+A[ [40g?`ȭݰaܼ}H_4aXFnJoŤqC~Y[LSМϣ/q;/Xm8l[:BcͼIנJILÎl?m/Ѩ9s][L5⌮i"z<֮=B/MH8G%%/S cJL)MWa!7ooa!\rI׮],Xp}K-[ $jLИ}36!" 1X tMGtbŊ V\jվ;}rM&NwG3,Mjs\;/>23 ٗ3R4:KU:<i̾-8uVc+B<ljp{~OlL_mċ\N u+#Qg 9D5:и]nkzI Z318;ضmcvBP?S?Q|#G+.z_n{YN\FJ+,YvСҥK{}F)nvSCMF5_99i[A&|[=pb1w}r.]ZZC˗mkxcf.HXhwJڗHԨQ#Ejժ۱"1$D Iq S0)wiJ-ڼy*n8f;Mv9 *? E",ͪީ7ۨQ^M#JHu~ը"1A#ka֞gj}^s`ָ:í8l!;urp肩TemMvLÎM3i*rk.whé:2͝KL18kزeK͚5qa]*n,&&omA] jʆ )5\|945NĖKN_v4}^X~R˖-cڵk#!L3*99a׮S޽T۶WVP4/DYVkpY$KRJ:uJ*#8|vvv8p`Μ9WZu׮]wq219{ꩧ4h~1 IrKiΤ3/]XbEӦMqΘ1#''Ǽxr֮]dɒ)0<G{8Egy~1Ybw[q& C深+\O/ew<3m2w6 xYo͸7cj!t[Ѹy혱׍1 p#jE͛JgrM.mguo8kdcc͋/.>9~?91᪌GLlxϑز[nT8]8z(n.[$&ac:ʲ5] :←qNqc?~^NCC|$g a"ӓl~j{m6ۻ[PP0uڴw6nyfg{{{z-?ݺuǼJ[7ٳ&)))`09dO(@ GK`|dSܿɮ@Br 6nْ…><29k0P_1pyaoy`̚5kƍxߵkh&MH/~ܹs}?s}`??ƈ E=ŧ4a6Gxݬ N9ONow{'N)sd}vhoWmk֨2nٲ%==]&`G⚑SL6Ii ϝ_,o^>克o0z+bAAvɢO%4999 &,`yD(9"ĤhND3$ ~?+ws 6liZdɒ$kshItNg)yx]NZZj+nŸJ\x.W#qE@"3bn _$?cHy֭[n8%,o4i:RH AQdvc* :a\`ي+>$ 4!@J>5hF 9Nۍ@' OnމMbN]s5/^tiNN/~o b$F!(n4bvnذjfgg;7t3ba2ؙM7ɟF wٳ>/9u˛Jva~X_"zG~Hl紙A>ɟ$5x+-WWó ޫEE8*+YYjkWZ+~v{,/]^(Rzt~l'q|yf&nLVVW B6,wK(&8zRx*b7^-b]DFJ* ze;j(O0]Kv O8QyB7t5I{zkC5w%1|bIJŎRe*#rʫ *t'ObB(FcokDN'j?ZQ~mCq|ýza >#цgZSwjZ1`uX;ې>>":1˼5nҕUsmD~Z>K4>ů_>?袇n`kdnzzݓXSdu 󙝕9o|T|jWn΅ Dʺ$6"Wxm>/\|Afv(["^mvV7| 7i6`0  8i1bhV1~AbtbS18Qd`ieC܊"3AY6gq@ոeUhi1pnoN݃ϭf+s.LXe?*/2 5Tx*_p))oזʆFI/T@&Aq>~٬RRۅzDM<ˊX ZPY]HmjZkP9XPfOevWaɨS*@>ք?zcMóIH,{9S]Oε.WnFZxt6ɇѣ{IUē Sn/G]* I [k&m#5`;F}41q/"tzaPJ$ZPYmK69g +U 4Re\EpL5?2 iu +I7HH.Tk,S.{TXDH#Y(eMG:>:ٱ8C^B;}Lij֊Y%1{:VۈG{s%ƨ i@$8[bŤIR@ @5YV___GǥC;l;z#6\h001q3ݜ@TΞ=ˉ3VLwwh: z._5qBvh^c%f(2~5#X6{A# : gF!:DYO&"NQ :X_?'"hP rqIPP ,&f J5>'ebv -@џbi '@Bc2f?ĮG>E 8d~`k3!ve` ލ1nLooWb0PX455@2 gcH1g L'] f0]Y{&ldϧMX00v mzuX]- 7>J/Sw#n^;( <fF,fOZ8J kF])D(x*dQ܈0f?B+5Qa}w qL9ƒ[(eTpYŔ'-(vsiɻ]K|u.x"MrFDp !;~מ x4Pc9_3΁F\ `ELTY+l9|!J=}۳\u%Vt"Zge hyOX*jEmQL=cdt%wAeÃAQU[كQEITE] I^< IOE1_'6T,bkHEBŢ55@l0QèaxE+2Ͷqʙ͋s+lE>@w '^ +q&wj$ ڋ?H1P&nf"`~׊-`~D/^/׉8}Ʀ>⼕NlJ)#MH-FhJou06r:\ mh\KٕξȐGɧ+R-Br~Gҳ(uw'K)k^qk [JEk 5sDţ5M"ʰlq|x4 ~rXD]eA$vD?Hi9]`e<'$K)c)_fӀuD)\bjXy&6Qq"̌ [X=MneUyk [5 Ϻx(2kNϒ;FbT4F*>|&r4Sq;kGY lVK^yfLj2nZ 0H 8 lXU]-<dЪs0JoC]E X[v1B>!D|3*⪛}|jw#hAVVյ4Bv$ח$pst3뒽2W0{mddmY+ۆY6GޒA7 >(“3P3#сa, c%FL&.v$3Ww~e뻼AfSu =ژ,?2hJ ܜ 5#Ka`3ytl^R{z] k˓-W(}5TQג14+0f]΢L*/ JiM!6Y}VJojFІwMH@2N8glǞmڄlbzwO5qRzZ&"OߢO>;yJEP(D cD,`y-,1>.'wEL ݎq2'?C!-n0PLoRpFm l{!s?֢Ÿ9s^AQw򜼆K.gOͫW04hz@8?'rl!nޫ(Hi[14-@&Va ƨ8Ä4fm 1R]l k_5+b)(@XzBO{mmcͭghx;=HZӗ,+NMjz'!2IQSjcuI_Sw?4kgO˞?~ 輂bSG:.M'Lj28/p`䬜Ls?X>_:`yZa;ߤ޿lƤ; ]/Ξ`CW{327߲'/̝}KRr)./fϚnaoLk_:{}cƌK=}StV <xA Lؿ3EY{+'LDO0*ZySᒥ4F_^I_AuVo.-?xEzu'X1HG#&0vdkp PVV֚5k^l|93;wM+Ld6&3s"f>sRrRrJn^^ɺgO]7wηΟ?, [ z}>X^/#"*<$:?8` Gkpg!Qd1bWO<_b(~ZobNS !ITz^eӗZ'Oa4ssswV__n6E,`g"n$q!AD'ό3~Y[̝o ʋXd`e%- 4ӟ%\YI4t_S ~e7[3O<ԙgo;{T,`B,hƝ)i~L9<\ j##="U8$^~h*Im&߸x<y R"(ʈ{X<>:!#oN\R͚|333k9!&)玽5n)FTPqttjάR nu:~!5뭽W~?{,???} 㨪]}|LܥG]u%JUv,v6Sq̱<-Ռ >뛝ni~*Jԝ[ W-M/+}17gd_F#`4pτ5ihM;o 4 ޣfWVBGm x:>n:61{+Qf}ΫL`~űn-rw/ ~K{srr_ H#ιPܬ*PQEkE̒KA6Xlȇ؛W-)F E{AY +3L11]\3wfZFd6Ҙu_QJ:kkyzSף}^gj^?yU[n]~&X~d̳TV;]nAcq&7Q 51F6b= ,fתgmv؀ox?;`CLGI~ 6LU(OJNMCB Qꌓᄡ3ӧ,`Gى/[ ci3͈*2Tz"ba`UmU",ކ"Uʆ"1Z}31@8 ŇFUE4́@ 9}beݧgL)_R ȑ#&I;`yˏ b>53ˊ`$oC_ ZO~ڟ;/$0FH'8w3̒kilBfdizy+oZ5뺻>}ikΙDf2K;9~yݻw{O>$ W,`y(lܤ(r<-;/8S,g>??L6synɴ",`yF8XCRcT|ЌFcNNNO ?p8}*2&9YIL)`r yAAݻW^x@ <@bCIgR?=,ԙ@jJJϟ2wdG]3]TuLsEQ}}G'͹k}' ͘1dǎEEExК:uط<X !^>-k{fH7 YYo&Ųu֮kn <@pB>&Y/6uԛo]/l6[XX8uڴw6Z* f͚ooٲԥX^/1w`=rĀN,J_"g4ͰӛLMp"7j׮]F뮛4iҾ#4BΝ;G=878aXjQse9EBmVcf,iD 3}6RRRÇ'9S>;z5kT{{{[[[lْU0z>8DLp감+ M0Đ(}ٙ M&7KPP [hSijWANNNCCCRR60aX"-bTleuv--l gs.58!QH*Mt*BɝxM._*7ʩByAn?qPY[j^eF/"f-ɫFZ*.pxT(+6g;` q>ژ<}rrss7l@Ӵ*}ɒ%w}7 TX^/QUkw4wM]fը]>hj_=jaxBDL3C~^H1a Hڿy@0Nո7 a0n[fM2K6mٳ_ï7c3hGϑ]\/^reVv66###3scp4$ϸݛNqMӵuovw7Uk3y|'{6>\5oo`M4 ^M_Tv^3bifzLolt"eCQ=u깬p^6&Ѥ2 M`ɱGwXнSÞd> rB[#r:wP _2?FZ"U_-;N*Hbu!_zJ⛚lH|[ {a /,QVrc-OS=: $qq^`FⲰRqDy|uMCOk֦y*/6ѻFxAu]V w~S@o2!&Qͦb ѱaM=WG.p`ziʼnhكPS+; _?Z)EXm$4CJė5őcPT_D_ #goxNl&-cIۆxv眵뒯+VEk'mُXk=P[ N[jm+Ѩ*E cW7brV<\&ӨS6u$dUʿHȗM| X8Mvʕ`%7`YAQ?ZdkƸY ]ŶJي}LiaKfOe |n mRcT6v=ohY] QbcZ7W N2d ZM 'o,6X^#~˳ ^zه,LyZܢ[`T_~9f8b$VG+d^T(O03&b[s.v EYKXyQtK+<|l}[UqE@U1f#д6]%[x2b)ޤ%(1^ ͆G}O 6K$oBՂjqJȣ/.olLvW|NgWDk ]lK,DVI ?PKwB3${I!Q,u27KS:9d|"_ n+#~7J[}V "7`"3 NA®.CGRV%_8b"074dGɖ#bˠ;kF)y,Qm4:$Lĝƹl p<ҡ2g=&^ժ0QPK6?Ug +~I?`Eۣ8RsézJÇ!qR8Su7il%\ fbdz 5rX$j!NM !j[7Ԫb^e4(dLwlxkӺHd7df4"ww0# @evWt1 %b!-#VII*s46Z]-ԃiFTV"*UUG>:, eEj?fbNѾKZ;B6¦A\N:5ąI4>&͠F-O |Ayrh̸ś2:z89 )b)Vg? W?t4ɓ@ Qhsc 3i]Gi>-@L1QqEQϤjeJY!EF`bD1?` "k-(KJ@e qR': n:\=8BE}VCJ|,Ê- ck)(eًkh[c VvU휣odzU<Đτ@ @褐bCfP22<IG׊m-g}vNWqp66/1մ6J!'a)Dg#*G lJv[AXrV;s!JG.k1~,uDEr ajg]ɝN2OiZg0 8@Wى/[ E^DciFTT / VmF9RC:Cm0 3n=`C2}舳ӵ2KjW%~xFNͲHB2).g |hcL?qaF?M`hk2LLkGY lVK^yfLj2nZ <@@nqo%}G>s;R+]];{۲]~Õlzj#\G^@Md0 +2?{?zߦMHΆ;[.wP'e (O>;yJEP(DQ`V'`y$6F̒SJ 곸mo=dN'ZTU/YYY`__8gK]P0 !w򜼆K.gOͫW04hz4 &hĿv¥FۉyL'7XUj|3ol}ŋǎ9s&.ݳM|;B{u]zw+X``62(#qfNSjf D3/+jϦϾ|λv] i)t(Nǚ[6z Q 0L0*ZySᒥ222hF,7k?+(.7|`ժա`p?ѥ7_H`y$ -D3N**Ow{^d 'B/]/^`0@ >1sֲS3r&|z/)k 9r$??? "`ygB1IŒkilB&hizy+oZ5뺻>}ikΙDf2K;9~yݻw{O>$ W,`yw6Ύ؉=ub[zsCi3NL;QZ*B*))`y(h4/ۡIY-c?e4iɔ &+ beZPP{իW{<4}:,0%'d+,{_{GzOv=CMnPծ]n_=;;[7`y$6E£s$64sBKEɞ4纯sǻ.04z͘1dǎEEExК:uط<X a!,ן,[0׶̞n4 lYS tMe֭]]]c,`yD[z&Ύc}6uԛo]/l6[XX8uڴw6Z* f͚ooٲԥX^/ B$Z3 x6n܈]v뮻nҤIڎOJJ:wG}c,`y4r୴ x$%%{9|l8q"N3%볣G{:o[Fu˖-ZC, lG?^(|eI벲 詠mxZL#B-gC-!Dz 8SSi,"_@ͻ=?bf!B4~C-`0/kE ϵJKV srrƶ X^/XXBqG5F$;ÄBK]L5ZW3<}iֶ\d R:'ZKߟo|Rvo SK(:$Ó$RdE ݆FY/ rk?XU;vV3 ֈdKI(30!--s1s&fE(,fa`Q%.^Xƌ+z0~b2o"'@W_|-WKr+k`Ϧ׷նJxE&j!U "e#ģRZT9g8:ZWkR  q-n UK[P&*U"C/9Y*6F4j9[J^! MEhCXUNwlv63:#ٳGφ9caد@kP/֭[n8, `yv; n@<"y9BF(>)͛Y)_+G4ٜbpن $ڼt$>bU)V,w9Dؠ2VUy>sIJJN_;Ka+_y|'*:n8,`pg 7% jgRoJ K6& UakqPv#A|Ve^0t-59 lv{m=a;ו SRN> $0ϨSf*gxtgKeCm[AVYsEX@Xz5#XK-QCI,Ϊ|Yvnu#ȪRɡm[LQIn*9&X6]s%I*a6QTXRy_#!!:pkvuj">hIYƒUY?YA&P (g4&(lw UsGKTTQƧ%k~uwFeJW75Bx/> zy;`v- cb71Q)AoEĄC`(d$ƽ>: {c0$2#φ=kHxl^H[k4{U%刨aHK#`,ٳѣ჏WNqj, +zݔ15@hkR[=gP(c@.RmC dw:[kؓkv.zeEux$m،l(R#_ RpL Sl&ԧbxS9`40Ae 9 W,!MsQ_Q oBvl53vtt:`YVreQ6FqJZv)9eH 8juFjD`QQU[S^/@ZA]S&U0#.ǽ (*m% P'@b  9:|MUhkcӤ{QS`v:'J Qυ{a1^!SQ>MZIAeu!F~Bqd/{pmH0nXH^cl7Ei$7y6!r\fԣIF3qngJ_I(uBL ^MĪDiluUPC22h0g$Fmk xǦ*"!Dˈ^Pigm xt{ֆdA <]"E:wJLB+:>Ev$цG #7RԊ:P`aIU$aE-!QmPBZ EL K%:>%#[Il[׌eL2S4CaiƆΧH3TȠ"q _vx-RЏ񍡊olрa'w!sT7Rv!yEs 7x2 V!q~߱oh F, ;Vu5ԧLj$v35@&@S?#!6br+#X6A{**RuA4ԫTy|c&i֒.H.8ځBNӍiDE'gs3*fTYE^56ĺ2b8i/ vKGE+e:Xވ]92bB Ů,w| 5lMY)7?2SA碫L;((Ϫ(6{ka!EG4nYߥp^BPx[__QfwM3P1Ps1dGT)£׷[bRY\4d܎1)ΈŪ~ߐZA{؝}7Xl!ԙp /g"AFIkpP  h "Q]4L-/e ]`H~Wa8( ;nFqE) 9~$?M#_1re(``> seO#;][.K!SU,գކ,=cD0UrBq2L~-vE"mE^C4!^#,fW#x " Bdmxԥ\qA1gQ; uE%`nq(3@؞2v*ne"j%5Isf-96ˉlOMZ48:*+D9"?I1 WFy 'D9S+ɊiK4b*aY<P$@]$fasemӾYcv7UӣY|sZJaм 'D2nCQ/"68bE:623g@L#Dso@"? Ca}}QC&9]ݛHpdPb8 3ݡXb8tI/l|tj'R0RX' YlGn`SL#Ox slc6Dc~M bE{lz8q&,/h~ 5@0OUҬ%bv{K 9Ups]p*kyNUziz<Abh&^=|+姸*.}H)?\$8Iw[ڮ ` .Ru[Ji 4C;bY8)hVxNyS-CVcc9^.٧~"~u>F &)z7UXTo%@W@o&@_?R`ZrL˝7cTѨw23rM?{@.Wf"' _xls;R+]];{۲]~lzj#\G uл/P|{͘f'3{:Fz70I2̛;kƌw>͟n7/so_ B^{?zߦMHΆ;[.wP'eb)N'ux((`0mCVp1fPv6ӓL+syG떉 f?zu7p>=~tGSO[c?_>};߿gK 3`@l s ~m'NMo3@ף߼gcU6OBg实ދ/;vl̙wϞ6=e=wf70N͛߉QR26syS][3>=/-̝ۋ> ?˗e S>;KOM:z h?z?XwϽ`6kӏwU;w!7,P)53o}!f^VjպM}w>wfR,P`4itl /tz@I+ReũI a_5yOf&_9315-/cɹYY F `=?rĩ@%0 C(ٌҒQf:e3'Lt9zw.)\`z{6M8M?`<_=?>o(_O>o.;J^NH$RR%{F.{-~.Jʔ?jBJPnč>9ikfri?x?}WPlBDž4(܎3/x,[?phrV &U,w /}|prrfI3{W.6#2iժSӓ.w㾿]Xlf)_?brɳ}.rYz}۞}?KѦ6<<ά` }oÖ{inN=[?冕ӧN}uS#Jꘙz0ҍ.Y/*¡yQޠQ=aGraLW05F F kCuRAh$.M]=R5/pӚₔge3&O] |qݓ-w=ya[pNq?~1;tˍ{[?xd2^s3f\雘k⃛ g9q!-%h4rtt.Z<s0z{PrJFэΞ:[037'?:}Go玷vaieopqw/q(UlcEW~?~U?^[fo.v|7?6);__)lp=Qϋ֑C:7#ِ}lb%p9ˇkU <<+*b[l:lR"E_ڿN䜯|A,Gno9^|G|fݪ[__tAG۬w?b }GIDgnoi!.+v<qjW8!4uRmmm˅jTp}`C#p+ʇ2X-]fg3(9/\5!yՈ8+hׯcJ]:+ZT隊{*H>7w%8Rw<ꥥX5(쯫!"!iy|Ql]QujOG,LT[mgJ_kۉ}"Gu֬Yb˙ٹknZa2'SUZfD.]}}ܼu+Ξ^X.}ü3hzh0)I$鑳9sc_ֽdS:ϟ?wlʝc[ӱ5wƔs]Ɂ YЖ$%rh}uk{;?M?ڒ;{׬{8/jz߻}[Y~, B50^vY#؁"lu+Jy_Nk(IItPYȿn] tוx-O^ S_es1Yl-MxGl|tY8taȔ|8/$PT!TQRXEjBHTafSeהJzQk6,ꥥC*Fҳ]Q$Ey0<6ì8ˇI賎WO<_b(~*obNS !ITz^eӗZ'Oa4ssswV__n6rHjJI>e $i)`(4%'{BzZ΄g'1I)}is.=ī8}Ad`@dtV #NJ(DǏw@o^xoIXGJ2&̊oD[Q h6gqF Hde^]E){D_T|朾)ge }i=H @]͊J$.%:_!212_Tvl$F|iDXo߱-[/]<%aC?2g;Bsqaֆ twuuwsrw|㻆Fɽ)A.n@[+AdR+s@Nǟ3rě5cB,8x3|jIwc% y빦 :LCkI}q=pSj3 #r"@T4 ќ65&K6EӚqqf%v3ًR5rPì ] Ym6sh{\RV^g)Z6b%7ĕe;046CA3SґAg%%ʇxnn:6SA n3f$! u(Ѕ͋ce+~o:|m<#gʗ%m%oU$V<<Xa]١Pz Av޹T+ wy{"rwE.K$-: p6%gL.DR)&N[P[c#Q< 볟**5gBg,U\vQqe\\:P;D~0_rzDzRd\mL3tZ44njM̓éPGŐRʂi8# _ )=cͼl|iĚƓEnǗQQ6LĹIf`fU6308 6/kO[/ HLH$7V7)o#XÅO1oY|1Yw3Y-7sgǕ6B7EK 4Y˕:YHM[i0gN˸#t0OooA[MO%(tGj+J>>~U>U{w?Xu>Cr2/((HNNamwww?O40pX|نoaPgu @&Dj):|Gn6]iuE28&Ç;::*j%gCiffm#fc,~|>5o:8CW" %A(:]<<}H1y m]ӗ>Pϖ64$xK.T]#]JA@HRсhD*MW._t•#]o khJ=`}n2TM]DaOG7DM93OFܼ w@`WC WQQQPɪPH}oJyߟSyа!X7wQ:T764\1] 5]Dݹ=80޵qJV,έCsfo~?ؑpR{UԠR)4u?*(@ r썭u+ D,0`BwPtwmDJﴵ[8w#%=>|_7>\N[yf=C7n7?\<$B*{g 6>I$:<_G8p… {55z;[;\R)$N,I,rKI1¯C4M B] !)P(8SR{@uP^ieg߻:{~QD__ M/=U$p8 "MFwTyE_@=۷~CD"wEnB $Iqqiӊ<==SgF:< D](Dw: P) W7ȰSt !R*(AvV!e'baް&yn{c}WWW3-~b¸O>S5DGw-TG[CuhlȟBI̝MTGk~p \D~rui-ջv:G Cm) κ?:qQ?NXP(lmm-,/2pҤIRE'`.?عίZtSJjT%g$5I %rS;7nq' ?G@DK &|1LA颵v29ΟӬ& ʼnِ!C&'Lݷo_hh\.?uTttOD.$a.\8vX~~>NhA {òZ3D"jBJ7%qZs_3|oy+FI#0_*pWg>=N滁ci-%JJ}r\i#9*[JO.Zc|=ߓf<wf} 4;<)XYѬݾTIXQKh/Ru69/L‰?xVX%ѣGB XZЮDS?+WpLƍ9=7 ~IR]ml:O յ?vxX裳?5%M? \+?__RtTP?3<ǻ_oh-\Dc wBli׼Ǩ$}>̴Fר-I*4:H;jԟ+a<0gYWTsWo䜸0-7)Rxq rlTKE-IJ UZ_vωZSQ g;Uj4 qF~%}K?\IMbDsz}hD~3rĕ Mn\WAggg@@ݻa-+꜔W}yG2zOgw߳C/_qkӧM bBF} c0 e c\"YJjXD'@E,ZFf@n|%+@"6&;)%7iDw_"7Oxf/> 9rL&[|y3i"AAAo1c<#Nr.xc񱯿||Xm85?j(^2YMqUQG;{,BD$i1.k2TcRSMU2 ]AGIOΙH餟2&0..Έ>WCDfDP(-Z!!!G'L`8SK24 'ŘGRB(_d9`7[[7{;Áw#qm+_L)+WC%Ŏͻ9+Аݖ<5M|^ X_ο.9;W^*T*u_QAEJKC^R VھjEN&$I|H+ב7Cc}4p4L}}}Q7niCKȠ]`*'ކɈ =VB}nAZ0xF'RVEY){u'MK¢ v/pUD\j+*zYF~A>h]p[g^i>mLusZ)@?bX!wqh_E}GT}-sB,&Myl,O8!m(p;:slaM}ϊ*0.aQAN?H缐(S7Sw.^}2()F-+"W!ATQ([5*OB1yQ&I_Md͒/޽-g9sR^UZ|TR."Ij&l@A͵=AaMH=%rD- s7a4Q'ИVqa.9@_vf_ժ_TbN#t_K=OΕqqq11&vMùq>Iinn69{3 ̬3KQ]QkMzW25@ȴ,vV' ]]]Mf8R01.e)oW݃qr"nHwjnĕqsYS@hGu+2%s`{h.K&VkVP4$shoqg9jzk$U]7vpXLJgO=Իᆱ,U-quΜ1}ԨQYoffΜ􌮮~){ɓX`g$AbTM3rh5h2r\Mrj3mM:g٧cV%4tceard-Oszy:i.U L͇~=Jd.\ϸtK(v0U\eB5|/qۙsU7P:$toPMG<5R?/#Ǝ;o<I%Z?gXx1c!~Ӆ<<ʶ)T3̲Ue,u!bRi4"̖ĥFQb69A2`ɤ/ %Lԃp2˜Nd,D\u\ mDJՊ?ydz!E//ߤ@{&P:{U>!G ^IQFd2#1IY&X 4ߟs;`#SmFAm%Fnݺ^{ %{?SI8z1R I b>ff( %INΠ6G_XwNkAѳBPp.!J}eL7WH^՚zF{d1g;vwh::%qmfUܢpmesw .$${%&&:>pT:y+<<Y?{{{sۡ_4FA3I\,F"˙}l&@yag)..61}4{6aaa>>>OOOfA{h#2KL6~xzG`A}@hF^R(hmĕrv|hC!U¼t:`X=ӚlV.34F"twܺuNVhh oWL^^dgAL_^O@  v"GZZZ8O}@NFq$I}}7iุ<6Ztqf7=Jcqc碣[5UG>οcoz3Gi{[_n{[X?._do<@8 J9\8g+***F^VVV5J?#G\  >#@$'N=ZT*嗒^}v̙qƱ-..nmm?~ aXFS(?ӧE"$XiQZZ*.hXW4&$I/Xiy{{1Xyyyi90koll,#Ѱ&iwmH 3"XUTT|7oV{`k٠A_41[{{{iiiWWW\\g8CWWW0 3g= Eeeeqq1aX8oq`gg'VZF6u^^^XDq {e剓H-Fh[RC9yDçOa84:  >Ql6g E>"u(H$_2S.HT*3}~8qFBoOk$W ݠ$P{{tWZD5Rh3g a϶3fggL&Á3k4lgL-5[`ֽzר+$ѝk7  UXK{9JD鬛_y~]6>5st=< x&݅8`T߾"I_.e邍 [S-gۿ&A61,Ѱꫯ؁Xa݆%o\~d]]]L L ~:pv'qmN@zgǍ?ѿ$ ,txuʿN9E϶_00李jQ7{ u%+$U-̊A#[>|`7=o> E f>p+"nyxvtxUJ}27 >gsܸqcǎqP}88cG(/U{@mm$Ivu)&O3@#RgX!sN:Mw?/9⾊ꚻnjWu;Dcm)afKǨZ~ڴiJF50hy`QL;co|U֎8???3fٻ?hƤ{D.nW/ >>JR4x|qtsszj[[t(/?""flyg1iK؍v-w o߾t7=W4Y1$Tϗâ.^= ;W6&.pА7n  .=rFhlޭW/oi}ڥz>򿝧ZF-_ّQ9@u4/Aj4nVT* %At)ѡz 畉a?77Wfņ֗f8$1jK'Š}omz) zg-] U-0VZ^ejo~{ # gAg%%ʇxnn:6SA n3f$! u(Ѕ͋ce+~o:|m<#gʗFV?jyoon|Ќ?MobcP<pq}FLp$(IE{{GB~A*JnTrsnQTH…DxH4̭vTpGK\`9.A>q[~[؁C$Rn˟(hE@f6W8>7z- E"k[MO%(tGj+J>>~U>U{w?Xu>Cr2/((HNNam ioo 7 'n^AggCW" %A(:]<<}H1y m]ӗ޾CРwnugB@p&}3s?4jH@5g֦ϼ/5U͌ҟ KJ cVvÇC@oqGѣ**@Hq'<\QAFRcol^ _N[\\|ĉ-[P|$ʱcœr[~bϟ^y}7<`76{)^zaMpb~1|衇nܸΝoxHpT>]?~'[ %1w7Gwo]y pCΚ5СC'NraȐ!Tt>s/Pt:iF3.*  eQr?!]N4I*>4$?km}vG!v=߫?le$*$1D ĕx&4/(2O/*翠7>\vv7s'eH_3bjMZBGG3gcȐ!۷/44T.:u*::zHpa"WFr(Ç_pرc8],wv1}GiwAtp%1/b [,}C@ 18XY%`}IJİ -(ZF$ 6nƆ(QY\_y ~0b ,ю=* 'L0pҪv%B]]]\RVVc>Ð!x`ʼn~+©S' -8>6O55׺2_w }JHDن {߭z}}j2&U5Bgrv:"_$#p 6>WS Iwoه%NΔ8@ĉ5q(w'}2DC{b$K!S6Ც$kj#Q=㠺N[sfiKT^UTBM^D>Z-$T2/Nn2dsb߱KK+_SH)qq&&b(Gsm&7#YL\{F_mV1*}Sp#K$1#G\utvv޽նYpˇj[^<|DYYR -Hko+AƯ?21~ Խ&.!l7񡏽15z<X7~Yqpgd:'g8ZٚiL*Syn|ohó9z ey+1e._J޲c$RM(cp΋ ϼ= CoP۷C"RtiQVFtJv9=(^)0&=)BvIK"rqh*YϞŒ$#2Lsk܌3z#\7,SXi 7oR䄏3G`=&OGCLbو35Ru>KBSHi/Sۓ&T5D$V7>~hekBsFS@0-ʕ7/_=e0k]ni>ೣxMXvA$}M4U4K<{JgSd:}h>5$Yn$Wek:8 5VJcuMX)4:3d [#7a'~q mB?Z/N&ПBJ2g ğ',\8dԃ(C?d8T0O͉V{XqptW%,sJyiJn*F[:Sșs'|fF J$̎˭W5ޔ*T5T-([2H˝V%s<}yeK'>Y M#Yg$l&g N)ܺVzPÙ!q)hUbZ&蒤t Y*ąՈ:SRQZvX.=cFCMk;ztעnHy~ots&ԽH GL6gek҈$"6 {z@# QP*jJQ^l3ÇmQЌnqh n_` ag}@^6XY ٘=I {BR(9;L ?$81oܸC&&xzz`F9iKKnst ܌=@~@Y 乜WsӇ&5h^85aaa'OzhX?쳎fgVq2X+, =r/5,V0cf>ηk9f%6߿^W wuueO-JIt6#Y=º:+lPB˘E6Iq ߴS$휾acKPcWM駪 cIIw찷`|3;-C}І36{XzeLx-z>|?_CϻV>^Kf'2CKS!9&m:ƿ%rTpbfU?Q 1ɮ O: 2,'p ʄrdq=: c2!Z{2AcUn/OdC٣1cAs-dîx{x_>_nv7>\n?-q@ZeP_:Bj)P!6űٳm.ܹs'A6gۉ?\Ww\=\.AyT&㛈2L C\TύKYj'2TL`Reˊp^HƱs+`%&e4*<|/YrnY\癃rRר¿SԲ?d)OU+'L> O_LG!&wLTi8z #Xpr/V~N5k b/#s6;Hb^>u+A_z}減$c *h>ewN-R\ 5H6#5V2kz̐)FNDV]Q>J8PR )ڞȞɇxT}8T g$T.Fq(dėc N7#tqA^ou(8nS 7%zs9^btat8WW] 0-3E3&gfRAd{o(cVڳJmذgm3ꞩZ?4g{ȞCg:ݪaؙ<N47\/_i*|IA7I0^|m#$}ZL]Ks2[UC=}op-J^~.`]v7QqA=z?`wի36K>=PF[\rHv=jvZ3Y{%A$58,6{Y>-γ@hO-Awnh+k[;S^=eBepPΏdI=gf jLį=vN"LVK8/mًCZEoy%;IZ*D,W>{|ݓ3bWWy$0H̉^N5ǾILN6Z<MQU~֜ѫ g 1]||r+긷w/M^D>^4kuPgzSR[ |c1aWWYFHwy? uLfǨ}$IǺ!*癉'Bꍓ^~,/%Ui U0S(9qtGCQD;ʓ>(Iy"ON-f"Q{Q!;Q?[ctLA$Z*-/oA/E.FO_z|ڳXG}+R|}/Y=tK/QhH|ߢCe6,_J޲R3h&XeHwQٚiڵ8~/Y΃w9?ʕ:gLíTUp⣺Tdmb =n7;VWg}L[Audkf`w-c 1+v#W>9jxꌉF TYr߮a>mG:q,Ę~V]3bm ;x;n:-ɀ=RQ;c:!Se;~L1R3hL<]wԋ? 6<7ej1Ug$T*pi[A;3W+_{Йz׿c>c٬_GVdi`$?_P(-Z2zhw„ 39s/O2|.9g2 f+UϚ?D%zkC?۴ͤH^/$<yYe40dWIyi@2.V2$sDyix: ͤBlb =n7MάVO6xq 8Df?lK}`_0rk.!)ǿ TYr #5"zyə.+ug z-`G>wk;622rĈXp,%"3o< ;xP?9Md-bQ,? T mD@/: ?^ۦj7F/ЯMlρ2ׄzegYzkԻ\9!}s][ [`DO5XięYYYLYZ.wcͶ*3~G(0-))y-@3ۯL铰efu[v :c>P垎oI گ0 f`+(}F G!Z$Mi92=Ñ͑m}?g|ٛ}~ Lpvsd۬D23wg˞J9`{jo{MolYpvX *l۶m62B}]}F;;'b6r^4͛7mm p,@8<_x?۸q/T7ʗ}ɗ@XqBc<1A؈ҊX1D3 hGn3w%oC3Z}N4k2VĘ-E ϖ.uY]eAZ>}$~m:xA^cfA|d85OfvZ{Φ8(7Y.,56+AH^6*-5Ic'dd&+IMKgM/3dq^Ƥ!+j[wu!i :t56GŬ+ޗ&);ub52<55b7 ЯfƓGV 1lYq`FI*wSo4+74Fe~b#`pg;f/+Ey+&: WOcQޚL{6#Oi]?/Om@8P(JRP`=_&J4gVAH3bĈ"$3ÈѣG5jر7o~)Ri<-3˃٢E͛'=<<ݏ?>i$3@Q(vV!X 2 JQ; `H]!ƞ h3G?$c }X>p,@8nY]#k!yY Z+<*$5_SđԼy &lJGSCDZ,H0*FJdN_k{j,Twӱcfݒ6gFrӔ/ή*X6bdO Yu*WGnBɦ-;FyMV50 I4Ytd>2^֝q" &;ֽo`- `3/wq,7:#=f] CRQu(s-ZI?/&6 BQ]@ዑLWy&yM2TH:ՏlVZ1E]2ZFzNVbٍˁױěv5eҁ(u|4z՜rt5SJpz[wcRSJڇsI ulLliY)sG^(eN cIƖP#뚤j C&iGRw1IRpdALޔf)%#R+kV,^Y85jgSdD?9VJj7kG&{~gZ9gY!*O&9JXBOv< !nZ#$4r)h.-pL ~*bN*5` ;y[iFѐ`kē1XTc]j^wj&lh,4fF'Iե$*'6cȏ}ٸmϒuGxLJ۟W%NŗwsyAiW5LŠ^|&IMM#K#;gf~ sVY9~gzFú/vuI4}jKQ~jH:]Lnn\h\mDKySjs7)wtj:7+ֽ!ʒuŦI,`'5o.VnEOIJ\-G48lZݗFWTeːӔFuONMH8 odnhg*[ZRI-CWuQٲ/TIu敡˛eRTNǭyϤ 5;nAll~O"{y)X>#ޯ#f2*s78v ulxT_k1tXZ@΋-k;MKp< K>9Gy1'ojoI&E!#yTJЩ '}'tgmLB &q3=\Vm;ߦK^ЇLp7p@zI߫N3>h gf'g3Gq>p,@8>3uS' .4GgZzÅ Ξ={Uv Y$ID" 5,gsXmmmJ%>V ƍl}p,˗qFK1چeRism.^ZN@X gdեP*(}vMI)SL%@X,(BRtQЃ$8I+҂>3&#( ΐHS}Pdgⵥ(56+KY)N[טE#BR>7%Дg19.7YŚԥQr':\?ɜrt5BJ֍s&Fӎ%hJN*MK48yC,20A[Z]2זRe%L]VEeP:F1U^:b#/n5&Be7]K4Xyj9FY.jZM?τj.HKS=GafZA]J;0@L욥8aCcq$Ǐ$55GtA#RQ^cZ=%E'/ήEL?OX9iv|ZX3qAaxueLpXu BArҠ=š$iP;F9a'{C3 0kh2A,ufQ o43{C2Jf Xi6DfTqx3`YhW5]"(dR/do46O@,ԬԕqYKgvL11ֽF$¶ɓYu67ܘ%PfOi܉ff h 6HYMuUfebtn{RGI`q\pJDf8M\?ɜrt5B_!s&F>97hJ=u#M4NU:+y'}yEH*kH#$zON'c֭Z6x Cv}ڣ k VkR~ ő_>_Դ1q>$K-NE>ED|ZD4(vut|δ"y7WGFՠQ5ǫPdS"_: nQ)'~wH>>]PtH;P-eT==3[Tò5.-PLnb3\h_YuV6%>\]rjOI#Is4X! I*JWP(m3ɫ,U J&k/DJTUkK DgRT6T!4氲%QPvE<{;=<26vu9>3NrUvAsKDF]yymO5iV SӧM bBF$XLr" 5-ۻиq\ҤX[ F>,}CX:/Ţn0AhURؔN;[}Yo&TFm(>$Mv]f=ܹjwh,09sՙ{s?=!ɋА),@*ڛ:EIa*S.͜j Kerϋq='+\}dpPg.眊C𯵩e7u|$wЛNSkYaH,͝ZbZLnYdvzu^D|㫓LCGZ0/OQ;m''z饗ǟ>xP|'ߟT 8Lԛ7X(o,2K) ɛg&?Zgp}[URאJ)3jDsܞE&[֍fMlo޽{/3M5E=D,Y7o?Zڿi:;9? =C|yo+ԁ}cs9pضW}B$>谪c?ܾ]٪(̈́R]wfżN.O/ |ikS- G ԥe4&6C [g~.oP<|%ɭ-ώ (2D8)@unN}}|t#dZS 1}iLlgS#-Uz<ɊH Rm '8qcO9-1nm,9>[TX{`*YAޭ0s˥?[];j]R hَdWn8Cyjzrl~>;7Ir i>+르FSkr^m[+.d;fN,n)NjnT 3neޝZj,ZgmC uT,nsyc7ɮW _^nTXq\VۺiyG%7ql2[̩ٸlV '`܍u1?BHCnY mj8hc-Lk7G׳Lc+ 6Et6.U7:>;]>0!'K 93o qMOW׮ѹe17Ν>NZ3+#RcswZ+nҸa^vXNN]Lԛ7X(o,2K) ɛg&?Zgp}[URאJ)3jDsܞE&[֍fMhXg i{)43IndM t&Og]@gЕZ;bAmő n-e4&6C|L\ *In~ydEvt6o\N˧՜R7]6L*,Ž 0 VҌ oڄSlGFk7ѡhrq5=96?$Z6/WKiˍ6fV2us]rS]w̔ Y'urxЏ 6dg.ʼ;.JNhi1eYzE-N2 j}¼>ߍ< LFq{Ji9H&x")ߏ\_#V&B5fJ茚1y#~▩ucbYxF!GծKǎ)gZl| NndVڕJ'1VE։4tR)7Ts'58 Ý;w>t<;@ptÇ\~ Ξ}iۮA|?p?X:_ܿ?\6t{t3g݆ Kx;8 ш @w!>%\ l||Ν;3s?{W_d2/{ tU#ԡf7>ଙJ:ǏD-Dԧp#3qT*6Do잺Lhq1Y@3ĜY@ǸY4Ltݻww^Il|v^;ZefߚxKW~ex?v9n7{g݅ t3B|] @wIϾxwh/w;{3|zhNvEFQ4gnpV_.ǟ` `4>..g݅ t3B|]v5>/w9G!>;hqaT ذ,}o;^U??c;9G-%?YqlZT777+斛&%\nᔲ39'eYrr___7ezz{oGEŗ7C/[@uOF`ͽ:hn]S=r[IR2Ds76w{wmݾ-ӷlv7n%=}޾G%$; ↟[טE >0r ɪT!Wg‰>ਟ2"sX ``` K\Tz_m,W(1qcKci6ٞ?N-UgRT1N[Bpbx0ӝnjjxl Ndo? e 'm{)#eBu5~KS[[rM?!{cJ'k'ݿS[*jŻP[DdE3DXؖ`(PV~pSU9x@}|uV+^8)a9=)5&P3ٌu99V/!qLNLsoz-%-k'c)#/T/wm;@\.q[VZ$z/?qEd_;ٜYhHnc8T򌜋Syx}P?މ&~c'=t˜$Ǿ-ǗҲzW6H]DCV@L 9ԦQuѬ 3zޫ;GeaUDꁚpjѰh>nh-.Km,ギ҉e5XqZZ,O1=>k=] `P8 ďn%jc-BvLo~+?z'xbrs㛯~s6pkᎩMm;UxoD vSY)kC |xK2yZht 7~'O=ug8&IENDB`PK:-Pictures/20000007000047400000235DA9D3F5EF.svm\8_7RZ!lڱGFi%f̘EԪU{U[3{}:ܟ<6RQó#s/oxϛ <`8Di{ 9EPu Է>Or>2:9#視 8-2fڥq d~_n.=\͏YDQT=+8 Np  Tk Rrtqߛi涳&͑ͰZ~!p'13wznm_~cW°)k !ХͥOоH%Mo6ͥаQC?i ȉ1_- eDm2fOo^㌳X߅+'a~Mo1B+g[m#eM|(5R+uf~7&>\pjH4ON=v 1Pyxdn|1Hx. v gq 6x&PkW!HIz#EG`MpM`mjV,"n:%G:bP6q\Ki ,01w5 eܶ04OQ(MfUo{F,/p4,,}(r/8:wA]l'[{_+ZAjۭmIQ1pu ocC3{e6 ,=ɳoRw!gg=&d#ʙ9ռ?Sx'帞zOy%lIaݺ[섽}K$%&ItHPX hdM1[rkU6ǐdil]~&t8{dt%b$E`#;021Nk?ۦ5iz_sb92W(۷wDvIסtĿB /R":Z,O⬯6?1w@Yh~w;Z>d䟉I_(Рu+n8{'tɜjMj̛Z(=ixMibZڨ~Ej^y#(h}TY[7QM0MasߢUwt3=gok1W3=|bDP#}b XhTEnKkKC2)\K3ecָe'GWC!_dk* IvсHr`SMgc֘W^^;h/ 'ѐfRg7"X ;Z£l.j Y#).I3SX] /0n撵܀Q%*NCh_SA\ 5.-*Zv{fg)Eu+^ܜoƤ& 7 q5W9hDO[6$j~w-z(qjJ`EMSٓ'/*h 9:IPZќ>P{kew#˳}9숍kD\I˓42ѝZTRda2k|c,]O|lӭncqAGP缼D cX'|1eg_M.{R=6h+sͳ.WfVm)2\k0:$4ʹhmA:A:Y*bd#BºX俻)9enE +YPYKݔjEtA}0"۽Fk LtT>pQZKڱ+ x]lpdհA2Qg~X,9=&U"+ҭ7XgE=X04ezQ#e24|X(dvܘMSJeղ/h=s;VF3{[qmE:/ĕC׳GǪ ma;NIJ1J N48ZqVxBk\FBD;7TF@\!%t'Ø䘀F7uK,$4̜gDIz0CcU"=U5 1T^H#܍94ZpǵyZ-64|%k [^྅ԐƩ$`ӵ} {ױ=κ/=%oTV\@)|&4=z73f~ 3 5?ik&K979=qHsLې̇53m(jt ۴c1cN0w(?.BLoK* 3f&-b%֙{0]g8Cbu1qgdd}xGhD *CUYEMhkl;%&ASA0X6i.ʀhm[x"eY +A9MK{w,R!J"NDً~ HC eM<ƹbKݿwāSՉ4h#5p]&".ݰp*N ac=71cB9=imez/oʏ{1ˡXdl-2`:@u}:;~+3ÂlהM!Dcju~->3V'\WIy ~&^Nvot9 ij-؟J]oH<㗬<\zҩa" m}b;UefTw8Q&\U,wۙ%n 1}B&wW ?=.${A*' @_M EW)mXM(A,,*мؿ5 ZBPX)sQ16BC'ݻw#8:^.?͚5TNԀܛ\X>ӨuPOqwYzlFK406i}{;e7[ (~=#dS lm?Рgtj.^TDy Ej['sGM4 ` &۲ǜ8j@1V5ھb1Es1*&7H3ba0d(kUq<*)ˠUo{lr)qٻ"2J|yDU~QTJ?<'?q/K֜cRݱnJ i"P_a+H8Jp"z~嚻?GJ]mwMJrHkK,뎞~$H1gLb K3%E˭s(kgSΌrݒԎx1WtNn쩑{zw7W~DR DدWׁ}FA% -Gڹih~Y)b-%Nr;e@zCVi~an/Javsr6UaUNS:R״`Fs4ɲˋ¼snofۨ<"S724ۮ|<~Xh`!8#h-9 ʀy AGsC/Ի*twkO\#=t.1jI ^ W i}Z>1 RfgAD۰<.tJ:c<ޞ2{8 w__cw F#Hkv  ՛.LU HW`'s!]zf _A VW%L# z:kn8{!N{A٬>Ჴ 砤9BoqAϘ-^QC?WXil9Fj8+r DT|g&^p3eK2()s"Y=T!' )tgq|>-mYi]ֹ=ҋr #2H?Z'jn/BhVB-Xy+-tnjb?) tq [_E7WB!^z;  V_{J~Xz]2A oWD*}X>$ t-ϘCҥqEL{qԼ<4-F\@;V8F6Bzljt@ǎ^[Q4da[9ǺI0K_ 6//*"𛸛ث9 WFZ(Xrk3> Mc {qrݠZ,y#2V9Zl4-D8kQKkx">,;Okԏv  L.]"=N{?eߗKqS^' `+r~4%.<4dnatzvɂ=7c|g֕Iul cz)/5ĸ[DxDF <-.! ׁX2G+,ְ>p,6xbxcׅ 4<}*ٓN=WsO *f*U[2$o:nR 8yFhYOť[sK^ly:EWt C"IB*M)a[ 3~A&Uy)vUލ2QkP9s XXhё2|)įfy"l}sQYEL:|-yOf [$N*bMb\j)>&6QFg$un F@䣱%Qn=>s0^ n<8HFKg>Kl+ͨ'5x1vQ>KWW&Gc 9,-ݩ)HQ#G^z#o][bl~AwߨPT&S Y(<'gJ2TQ+\*IYQxoY Y$TKgiĢ+P"sȬJ$evf߰ 5 Mj:壏ݸ ֱ77Tcu)҈cϹIob{ CZMPZը'2u^!;p7*&j4 !+pN2;?z-.jBt/%dT.Se<9{MK (ҥaQݪnpن p %Is M/AP .:^c" I;/7Q6ВA!NJwW !⒢T'H4~s%`/yh~( v 473&/~ă}x`̖3B?Cǘ4%"E?#W5wpR 0&TتzSJ/-ތRsM =?/tDH]t${ F.37#l p@װa.mibnvaGoO[+HOi^q]X=mtc j-EZVl+}W;GAS}y֤$+wɴfu%\ZBrbf[#V"ORWx[XN"Eϒqa?%]vx`dZq$;A͈!5!khl*V9\MA `CX #0_Bܺ{=~_ u t?N"+uA$]Sgq6@. zd-iA{j Ue1\(\2h)Am뾂{#r$Oµ<"맹3Roї}K-Jۓ`Ob˾&CxHQ}T[aϚЌ@VAɠ;if|.ac/Uԥ(qkҚ}yOhbr{)D#! a ɵ-(ѓ] ɾ㇙CmVZ6=c)x_7 o4R2'o_?E~yyl!Ov ?;ZūM\T!9`eB 39KC}asux5],^|MpYS*(J)$Oz$UUֳZ"f,{v.ܵ#G\Oޑ giC*}L@&hAnyʹd{vbo#dij C)fsrXv9[c|yh,vu Oy . lTiNzdBbD5xDǪUQ#EO͗}nyXn@wH\#{bu&4zق3_ 2H80'LhwJ@ @\mYf0)qnKh:0ppݣԅac(zͽWϵߤ XϮYF p JC/rIbS>r=Qm/b, rT,,#C*ƶ7aܝO_Dt1P؏y j:)[SPWJxmt"da3jfܚG LtfUFy,Ż{vlj:ѸizR] '7]+A,c>*f: xO8t9]< VoBn({j9 \MQaoOZ,0HYzjYBX)˹VQ5IK\OC.:KVˉQlUA 9Ivdw7XpPkTD$F2EgdJc9G "<Eܾ70-Qp[Ly?yrPVG+ ni+aGKCU{zt %ԁX347R"h$6̫'ݼz3 K^j"Ukro~ڑ/e2yہDL~(],<q&UNh4Ժ$R)co\ͤ4lkH©D A3ªzL|7.z<)߻SFP5y$@ {ysp v]/^YTZKq)uy@SQaPߋvEjf@T ʳ6#&cc:I,o"BLUXlSK&T`iW['7d}U˻58 QVM-}]Fi_eA7UA^^ɵ$l&mhռU8Nܕ*UȴxVdG(kbjU/\#;6AfX#?0@ާWzz*v{5wCP=1ut(''{)ݯC_:v͹nV\TK+S~ جUϧ$ P6q&ם: D]Q4J*Xoq,Z>>xߡ!@C:1AnQ5m6U~η^a7b]XF<6\00\m`..Y|{jANIf*XW_..'3\n6]*ٝgb1]Z\g6 BVh hB/q梽e%kjmMsq~ {Ҩz˝37h*!9W[4ߐ|M:se5FȻf n荓t >R4risjvՐKP|–#ET*ܪ!@r SE%<}ZphMOP!ZXT2up1mӣFUH촴{lk@U%^RX(?pB$A?l\#'ֆĠ߬Cr\1*rXE5A8'ɶ&ǂiy3Ŋ–3 h =V P_ߜ4QI&Jtjm( fX8V2*)@ZndFZBr}'d'3z-tȗF{N^ YM_:ʥ/hС\wV=+;F>:Z)~+0vő+VMi}]=A6ZxZ;_~DH0h&ڽ VzӅd"(!_u-% CFX)N֌Tt3\aW,s+X_PP(Q č!1~c(jIX+*6gQ>5 F1*g"#n CtS%V &mJ2ҭX*"t7Z6yǎbLW5tORU Hj{~90(g=' ͊\2(SEsOߒ8m=dDsH9G]),tZi(X6c/7YG#sg,6梌/aI[_ QlL>lTQN'~(pM~1 M|^yG;ic]MaLVu.zwj`9<@`Ht'frHT94/+Pt5+0J}3itU ,N]-\ܱZ0t(GEU_+;B˯<tu>U~*Ts TU#,l6UOiXzþs: AD 7d_l GzU< 5!+"8B>ͥBқW?nLr[~)@SU#!I5vШh.efpeq6u! 1p5\QR*vZ0Y%h-I !DJo=:spRwL*|^ϢZ.Of K ~xgS-mgw}Z}T릇#p񤆴Ϫ? O1&˞>/h bGQ04{255%ڥ{BBkl P6"xŊX9ݼ:jKd&IYϖ*E;Ppr.--cZmPiGʙ(<ڏ禷{ q<5 cF 9"HK8 #H/0}++E86Ȉ$r*,˞axBd}C慹UƤ(D CKpmђ0{ThmC]vKuQ5s6|7TM\n7t1>e#(q]hƧ~z_="1t;R˘KnTo[];gƳ LIߓRx?UM8;) CSs+a6~h]=85 6IzY]4(]!A^S*){cY*]Q|֎1̾YUURRMu mopwQE 0ͬ{C+̄N4-W1̄mn8S׶CM"w$'pnI.pOH`{C)>p)藦ـOhS(_a)uRig"(mvimk*(? dMEsylGD|$[^O$ G`CSْcZn1냒(A]p%מg 45{!PZZJtIaZ=581ZBp\ D*M^nUJHf5a蟴]ޱ˺1SQ|_ۦur'vٓ˪)q](U`b SFD,'`n܈ B @tEj)+m@ ` ;Fg+י!)9|cP}d%rV`e7eNӺd.I6MRMӕX>vyc[|STT2gy`߃;11ĕ늯wdߺ) -P"v 8)W6ᙛr ӛ}D.\moZ ׸,5·n 8O|F[^n Y@'N"IB +rG?gm{뼮sssF_vXx]:;DeLC'-ٛԄ| /D1 8iKJBE$K\{Y.MdDs> f*D\pY9D$yUx7N,QtQuo򿾽/w_%0^oqܞ׬V0 X!`,sݴ(b ƭQl>>wv-e[5˔v8♂0]5ڪ0>\ҟЌ<wVVcE?;\lBKEJW9Ԣ.$9;#VlJv̷h9*o'~ *v)'^T^"*j28@#ƽ*t# dn_䓴VG%~=4{9ZZ퓴k8&\#)p臲mo;SY6iPmҜuG*YgT&ę*aIk&g/2Y6~W]Hg?ݓ%KzUGӶ{A7r/pPHqw,B/X!BaZ? b;Eo;Uϝ_Z#{3TSglR.%;|Uv:IT АeNdY!4RIϙ證^!2Յ!ITLNM&U6Tjd ~PUm7,NƊr6:Me dtH!s| ߷=ʴl.ck+n# `COt(]Dۃy%{"]-~,^h>RNϲ9'=f(-" g$b1!]-"zBcln2kgCoG׾%":Y_&\9Bxl߃su<'fj'JI$X3u`aS,q,[ԕ,DD1 %ݞBZٍo KܨD/B&ޯgQ<rYCA^oF!q Gnj19|k 2'5(ȴfFQ٥?|]P1O-vw`?3wG=vwd#R-}!aPތ5 t YNv^GPkޯs1 &OoetbHpNk~jA,%f޺z֪mށ 9%r';ZlCyIQbǦΟ93j٣QFEbMYj,Iap45;%408V"ՃqP$),}D[: ܃F,:˷}u 7\ţEY{ZL$ h~u7H0(dQWB*3K[ʼr*!?υf_DOrE{P87zwK[.P:˗~w٨<}!-S\ԙ$ݫ @ S5y&[(8p/)!mD[+b0V1<L|~Da/=n%mZ:B̬GexEICSSd(Wq_.J֍ >_,;f@Z}g[̈́>wWT#8%?U4y2*BozҖ-y }0WwCww=$+/;T6o|\f<Ɉ?fT)z\ =P:p $m+rZr̕s$>dxt<9H}q{`x8~ɢ7[4=Qw50!w:|DM\ uq>stg1ڡ2UHXdܿ;lҏYs^dž E0y5q"|/,ڠ9Z+zm3&j'1 L-[sR,%qZ/­#$UR%"@ ӏ JBJH=l{ֿ${U-⏑m:Z^[VwℴBrymǏ2g:NO ǵI(df]ab4XmE񌌊|NEQK2\OBuFYEA6E,ky?:E%7F}|OYsX䪞/h[q76Vl19wR `U/+XD_Cy=0zm'/o3cQH*+AAGu$ԡIXroP8JP-ex%?pucbоFZ.LRo%غHW^_) W0:g۳Ʃ鲟E&X*T.ܓgLt`v=zͳ‚~%I-z,Ӽ3\X\t%$q [e+a?D]x}dUWĺ-ƍbй팂 ijOJ-[/ K=6I`07 Gy{\U9{rh`; 誳)缃EmrOzwЦPOnfGGL?Zc*8W^9lS~]DZI;NOτ+6Vy"hg!S'xP#' uC^]eXg @\%ਣƉVv~O,kdFyvယ:0fGMqim,!oݲv} Fe BMSTXl8yɵnyE'(+y2wH@m;+i J2L;;? s%!4}Zl5͋(x{*xpjxk@N$:鱘1yd|Q|.("l&(]uHLQhC#FbR9EFt>Ej=\Tbx6Ǽood 5ʏb(͊JCyRz07t~muJ+&%'GU G^l攞R$_z?0Ro[+p1WػG(˹@Bq*R+:6'3u5ǝOw,7D*[%9ʖLCR#niFɱT+:6E@17ކb;&12d;[wy9f!{FTUcekhbҍ3{q}t XϾ*Ɔtzk;qo NT@ O;(?Q/=zC:K% CܪJƮ@LQ}+tcU譯N"}Sx.HWh ~uF+"z;={%D bb=u>]R-4Ļi~%>1, OXd];v)PeOy9I~m7\(40cU6\`TuOC(jAvra"]a狸Am%8xmyf)[kq3dY/ρ%'F][<w02G_-ݶc ވF\SThoW!}#Á0&^\nOڰm[Tog" ? -Q3rAsn5˻y|>;|R,sng_2#'&n~|ܴC٧LAK)B ";b[b1B=ʔ^ٕ1oa0T{'~lIDZ!{DyAaRU6׍܃i' 3>Gĝf:%xU6Sok0/qb)n*`+`wrWei6'0u׋CMv<);6@="ta&HAG|G}۶Q_ƥ0KwBc2tD=;/ZōӧQ}.=llzO'ډōx0ĢxxBN 'rj;޻XsILXkC i_"}@Q=|U4wZfܐ}#.387(謂3QtYrݬ;!5 @'HJL$ <)`l>Zi TJ[ru ce)ޡi.ĕ.FʯM @T=}X7 V vnm6Y,>M6x\]"}Dg sXjn|*~iȖg-c2 s=ZRr9DS?U]aM?:_=e8s3gN8M#^W!W+Q8 X1mP'L30q y B_b>iڱH&x9Np(Q_zGQ6ɴ+g&lp8먪4QnO[Eq)4tQ/z.뛟 [V3 9ǫ~ +28l)Ҏ| |2ƯCԏYD R_}DM$ڷ^7zƍ?T6e0ǘ+sb} X+Τ5V!$aNn #\yGA<# n>nM)G •o+<֜9>Y2Q"[QtQ |h&vsPZ[ .4 U̲H|LsȌ$f+܈2SDj#UG!Ϫ[oi+?oۊ).sRijadr̫Kn\NE$ dd~(|pak_`yP zIW]PvxdUTL7tb6ީnj4 ̵yƋã#ݶꓤI0(/;%񕴶u) ;Զ 4Ԗ k5uʳ/.]" -y muǏ zN>[HBɩ=(%^ȡ" -#(N_,ؖV~+Ugoe=A@ ˮ#P ϥNmuq>lZPBB5>Q#"NI9iҚʠ-L!%ǖyP>DG 2 O0PBW.eϯBOⴓ(łurtssw^ h}H$\e"@6VLDŽ~>Qn`> !zk83J4kfDNq+)*DkhnR~+jv;Q^I^\uFY++i F&)84soE_4|.wӄ'kٜetٰBzA`iT: ?Lsiq1XQU Ŷwe);WAU|1qws{,OӠS8TP@a1-t6vI={VKh@P͏w܈ D𖏭фDI #a"Q3$J60|:~t;bT5g"/ THu'%u'8?&-T\]=dLmvƿ4L=E;>{|g^y7tg|M@ )ELE2h'?-̀A4O=keij{f}?ք1:J-`%םs׃4Wvs# Ms*rҲu)LAGq{껪]*j ]M8oAM=`3V6IIv$RY&x ^3UZ$"U"+BM_( I$!UP R|q hYjx!{tsv4~ײ8n4=ENʦ`u`s3|d.KiBE)YxℳPNa蕋NR&NZqj&d n[CArv=GW~> A NENP;8K𧅴j |*K?4ã5 n,>x ]9Zc+QYѲ">]%E&ee  *Qť?@.R>ILV(yEVf;(Du (W,u\)fНB߈T(>RժCX_vI˒cՔIs6qo!᫾9_+fQ&;oiIqFZ g]<昁.>}Z d2Xzy,k+}o&3?[T$@nm΀5tVOC7K{viekOwXiu*(v2b7̮| dXɮMړT7F%SE7&£gƓdGl/у{O.t+Dv5MLO!RzCUCqy\FA!:o&ciD͡"z1L+$ |4v1:Rm]A,Vwqιc7p޴7<(9]%#6\L{^ 'v[d@7 K?~ HP}s v(-0vՒ:D(_B(:5f5 ]-^  eE_+|* 5`V1QF[1rG+Z cĢj:)|3aD_Sȫd +o ^EviRɒ]`t:l1IbZLkR(Pީ<ۚBQҾל:/ƆM)!A:&X~6k] G^}g<|h!)ӤLktGB.3tre+mRǷxQӸ"k/ v?bO{Ó6 rw 0s+ &)asLR?=v| YمPlD_bnzn]\c÷:i#L/5ƸmO܎);ŵ^kwi\TRښwhtj/Ut{l<#}C+펽aEhZ"4}N=FWVH˼eS|X~f;oz UH Z~Pm`x{;زP=k_(0M>!iICCG +#C12:B&Em<#WSZj>YO LbH:bH ?)\+-`-ցno_Y/0W.z'⺔~q :껤u ǧH֨TR#(߈tS3[\@{0DJr$Wqy3*. #;GKw Ē8!1y)tah_5d;8+t@*# R:o} -Ly KWϤ\)V"~-WT( )'~b +h[oք16lꖖLmGORqIɗXC~ݯ b'S^?^1<@jCLIΛLΚtɹtf=RHX4kR}(@LJ:ce rX%_]rDu`IwaS=h|w6JoHWJe^v@{}.N1G$~?5hTzHzzI cp%ʀkRL<2aGԺb67Oo]Y(u }fH60$*7]沦.);<Dw>m;n]Հ{dsnƣy߮?ܳ1 .RH3cJC"OK,0vݴ9+Q!SWrƎ-M2R > Cvvz w|VE2T/V.4A"rO!:b\r _pZ&ȇK2%RYybqo_T=S h'0lno@dv"U6Jsd:Jtk5F#tA#85ع LdR$a¥E"r9jAl_1+X 0&i9^@;h7QC3x>ҭNHJQq&1T s`6F&M2?v ]b '˅Ĥ|n5ݫyU\=3%=cssG`Jq?FyI[,uԎLW N4H > yzp|i ,7\W%Gu3ws dц)߅+Qt+t P.9ʧg~0`N`yW9f7!٪Azp3l!(=qNYpIH}{r6!x2צ*$=<(Y$n6-/W%<ݬ|9 c⎥pW}朰g<@OI{,!;+F%&c4ob? [v0tGo*UwH{Bm潂5V&e>6M^.%O5čy'ծ\7EieQnc[$1`%Fי0Ԏ~&'-7cG}0(5*svT((0Uև>_(@(?:Cp:6x/jgP(/f'ԋKJ*dNGCPu}' 6 "B*YYz%_f!jWR8&^J!<7!}ekxecUe pт۪m/Ehw!#1+4h3&!ue3(Paqe˱X JSZLxݐdq]O5ucZB}'Z6mIzMV}$EVѡt'k.X0q] o ݛl 00mn,B#N`C,DX|ꍞ]򑝪UX`Q,SfbgSNQ e! VڲB[cE4U:,z| b[tK N-E혶 Uv4%>~5aԎѸgl?#S"1`,q j(NTT(wJI*VW:))t*~=P[HЍzPU8D&,b."_,H"j9~.DX'qJh" tX9|;LYsvw}Kh }RxAt h'&,fSɫ%כ4Q%21;˵w|w)(Ih,y= pF l%vUUtt ,^.\qaP=pυ^~bItqogf|.mB 4<:xL>77]2*%sdRŦ~#b9~!u2 'ݦ^qk;2?X }Q[ytrvנIkmΤ2I{;j RjtE*T 2TN j 2}A6KhO@8ǿ|;-dM_@>arǫ%x?ߒʲ;b]jM(Q 9BoTv}<.!zxwCnlwM[#Z5xlJ탰Wms-5!GJ[i)!s!GA@95DUTdmwGcI{."!7Raϙ3?gKR4+! N  5?Ar]G'1(w"q|}*<,̽p%aޚi%l?5L%i/ĖvUdže%'g`Ϟ>ܫ͚i>"Ic&\ni3hif2v6,|Ԙ)r nIp^0fv n?Vw'JP6Q&IwM)$R#=*v5p'c[SGQhTa{U %ϥ12F3FhIiKD8KN8{b.NfF8*%S%q[NA3E}R5oEP]T!w;mе BQ-!}8 hsy j N Y Ѻc$;7t:dZӺ8St|rW^%(H9 I/t#LH/dU#|@.3*GpBǭv=<ա4jW%eeݢ=5C2u]=^\w]]|*@QxBGmZ6L?x\)T?h65vl@ۛ\z ̞DN4t%kyXzRa%!G=*^MkƩ+%z'BZb݈ u4d d0k( ]8&u*^&yofGpS.`*H\<4Oj V{еSWMpz6m΁k]/>E2rO>)c'ݹoTk[W?wovĚ ĿJԟpyR__)g)\.3vLm_o4Ϭ h`.Xe;wAƊm9Q!*(4,Xv9QX1Կۍ!P b/6Qe ?'%^%cc E1\O<: p|--I{]E.F~d 6$S0I*rY o=W]Qֱ'T{uCq /{ڰ! sY9up&GR?~>R}2ϧIe ]#?<(]+4QzhoKո.;3SnU!1<]L7 'Oz_A Unͯpۗp+p7R5 551ִ8l yW ! ' +|_,e}W5 w4X5m4 b3m`L!W2Utˑoz0QyQ"WW4|*,jLfN:Yp:Ky"ްJ$5'+<>˝uSXO7 +F|ˬgR'و?IMѪog+5˷*Y=cg$|vm TMK۫CbX_yv=s$Za&B8n*Y76 ]\ode"AaAJsp9+՛hV(_6a\M Dי\DcRǬYaAWC#B^r|I`ΫYp% @]kY m_'!,`C[~[`6ADNwGeqđM{zDL;/d$yz?#>Ibm2,=&Q" q֣>ͺӬk9vŀ5'r~ز?[||!ȷozG89*ϝ㋪j'8dT ^C'b(y~*e{ Ag#[x'E^ˍPfJnTL+dY{eڎ9M/KxnTȋ*&iZ2+߷Ii_[=+RwSjb0xl_>C\q̻?}9qK6RWb]jZnU)Ou(ޜA}YKs`w$Ii”OxFLG7mxR3˹]'uo] Y9n] z98t> LQѓ }/iUBrEvv&xҹkU(7. |N &i50g zz9w⑮q5$y3X2=`3e]*8O%)Jy$m1# J%Nr`k48u߉jTnSMOHUd!_pfu9ͽ<}ՙ绘kͦ(ߖ_ =AF,[}XyxHRZQr){޷<dt=0蝱GåV1@3/q p|cL[cITIg;~js FvpSש>y^Dd;0wSe6HmDo gΎEE`m6Vu۝Gh;fWa~9Uom%LWhݡ'yE%tQU&3u3ppj& ) ѳ Ȑ@d>V{hxd>i[i`ʕ,94a45zGؓn$3e-K]7u֩6٧14u^Bc~{v{$] [=& z+Tض"pX`8fJZÑk9P 5i ɕ$1!N1cq3 J uh7C˞"=NJ$&:oc`u 5ww'hn ww=u}]kq1;'׻G0Wvpw煖Ӗwr[6fu_۠ٝNհLUT٪:[ O\^>[:;o+~ZN2MU q(B/|(ԄwlA.q /ɳ1mqjj"Y痆="=>[=xB'"C!ZKң:#w?i4)uM]3=aL ~Micd+vd(,Dy̍QߌK蘙3QΓ_ }6 At܉ lh')@#MQtx[>nhA]*a=Wף?mB2zI0Y m^OkUY!?!TOqRݞUGZ&7WQxW{ {, y+(KKq:3Nb9;-/;z-)Kg߬$ P9}b߻ݓ@Jr$7,S Wff8höbkԙoSòvf&usȖmR䡚ᵟ>f/'C5JBBΎrwQtwcXCTg^ĝ:5EkHKݝLz۶-;Nj2o>k;tDw`ϙ෎t#k2!V$tBg1{lYb(dGzȦ&l ClIȮ[爎cohoo)9uFYlvnY_ޯJKVOfnlE0 n- l(lނ]/b| @o<W=d} Wdgu- 4EJ ?e =l Ea׶䊉m5ָR50 Sr{:i M[yo%xV6;0kc|}RuFhnDj;q}{yt "desCg'ٮc=CG|x+Ve:ymd8},]q,ycՖ;t˖5@e d"es'סNo4Gn͓|+g$2k+1qQWؓL9>Mmˎ{ LLNs 'Aiľ+)4UX F%ҤeǨj̇l՝~wc19-N0s&}?%i6߇ӫr䟿keF=)lC)(;mS|zv;:jθ2A|lvjΤpT zSHݳuDrֻ⫇HpazzwsJX=3UA3+O p6BqbOld"Rt'Ͱr yJB0x0C;8SR itGBV *y~:=yRx*/YcJxxIQ~SOS :.%-Nc}|qjP"|P Ŷ#@MJXgHs 0R wgFYNɺ6嬉T24#" R6TfTeL8T=_FG `Pc+K_p7BSPa8gp$?!Vۮ/"P+5&+U3#S8F쫡`PljH,lIڇJ1rdG?Y_sv S\^166gQSڨh> 8W${6X2L+ĿC"׺" /jI*e+v"қQٕ]woZ]#`g+t=mЃ} 3ii8-M20O!@8nBɕb@򥓆e |^anRYӯϼq fuf'r,1Ki0)*-3Jo39Qš$_|!A>Y,K~K L#gi1OUgk\Ug{ *Nn'mضh︜OQ{Tu׼a*^ؗ=lcH-je-I?D񚐧2Pi{0?ttO}.?kz%yk-_qdmT9Ơv3f#VdZpfGbHps` *ւ~- Z9G ~c+iP&s0h]4ui7M?sò T&S.4BָϏb/Lŏt{hָ!+Wp*vEQn(7a 9d˿~E/G#Mچ-4r3Ksk5M‘ZWسևT/ѷfl䔱5%D3%Ё@v8cÝsY.o}Y ul+.QbiYzq5UYmxrE*x5kc† 50luix0<}g ¶i *NCVJ4?+IݤS8فG\J;˖=pRK6'TYdO+-~eo%IjbB kQ\=ٹ91(K:wM!oS'FN `g./}>B?hT? JwEW^K#81QSٟFy~Vp2MqeQV-͊#™|ߓB}j:`t=f\>u9?.Xʖ#~R$y@șh I% z a #m1ԸG>"M_0]u s0u']pKuE^Bw- R:{ ӷW$Kahs) jJ1W,Yls::*n#ը:^UըS(pR31?v `pCݱQD!KN߹Mm7$3:EB>wQ$ȔuqP6`=pP˻9r)~(s'\@/2 ~ x5m#D7%v5uM}ց9bf3 nތEN ɉ702^-Ə3(ixg~M1YaD:8mXڦص OhioDl J=;Ko q7luV:/mk4מRDZnzQ"a3 &E*#s",j9էېm!'%>zŽV (G3^ӟЧ6HlQl[)(|:lM i75[1He~ݻd[1y% vkw쓮|}hz;q R,+.:o RD[VS"jL:=iBAwBטeAfe&_h+'CᏯ0\1aP#M}ӎBbWi!NX#f 9y^%Q001n뙊d/@ Ew1qWR8JRE t bVQsofD6y ~̌Sqɠ(ڟ 11 clTCCR[7X"D1!XcsLO) &lՔhE7]?xxiT)2+o{2۴tA߰'1W:q:^jXS+o ly_/ Haygv._e. (V$?'dNl=uK!0F~%+4|)ױĄWr[Nc49s'; (e0k}ctVilhϕz<DŽkp*PYrrI0u[0K [yT/ՅjQA}${P=]f3UE|q(Q EvE?NVqTDΣ9$Sf@%- sr(4EelO&J1>giuRf~&Dh{؁ $<[w`J&\` c&;܆!~oU]qkUFe3eħh}T1cU-9O*Cgܜ0Bw_כ q^YQ1Bu,SI=m1Ccuu>ryzc\@L20=]sqL,Ck@-6=A^geFj65XKJkk׋ Dv?_Mc#-il!9R7{сqn;)1[HA.^Sb-tC WJgSګ'##dDRT}fg%`ɞ3s!e[5tNQ;40uǓ۲IUZC8bʜ*`Ł\'y ~ePde3"$Kd۞klgAűGcC ^Nf1$&wSGrCd =/Wj8 yblgҬ7%D; ? @EKqyi<R.=EgE-xLznY "=hvY:k縥P^[?.X+-1깯~(ӭg's3jA~>qtG7]5o#-5).miTtx'36  rfH璇jniν-n2D|ں~bMR#9/bޥWe(D7[](;@i\u.&j_XMN){EKON tr2)^V 3ES࢑H1`w)TNs5D]'Z~2ࢷ_|p⡮faњjhVـ"D0vg~Q8KFIA/b\ HQ%*_w(IP; @ճ.z1n9`C6gjԻjtzKDfHwίYsՠφľLtSŠiDԻb n1\p ic;]*tqx5[ËBAmq>}kUz<6t֜jk}=;_jƭ?>o>~A"ՔO-zwS[4EeI?]7 %)xh7k93;3#*xjxʣl>^3:}>JQJoJ¹.v y*<'g!^ȽU?p ' '0g+>DRV(w64 ۊ >\8Uftgb ,⚅.WU2"HAL;,X1tia?LKofB`3]--bMQQRpXI\vC.|6㹲, v,jY[n8?(8 e~k9HOb|3O2h:hX˳ 7h3 .v3{:/0Aȩ0]ͤTJ#GL*-O}#utc"dyWHϚ 9$Ѯnts. `c> _8nz9QUն[WރiN9aڈ7nb|uk1lPNCzEKN 7Qo ƣ6~M>i_2h}wFQPB]09ez޴и!~mJ\@/ȫ^oZ6ݐEۦL z>$nwBF.@#peqIGx83^6aZQbdzm~v Γ 6.>BlETA1A_%D.HGM!vlj10@rrAl>3]~ 3]KNFB-}l?|eΗn}xgv r,gZȥ6Gϑ#[#6S =' IO9+?$i+LeAf (IY"]PJtl,sQDW,ϮbgcyyvΧ2rZ/B=ʖ&StrlB2c_<="wpDxou t:?矌`G($RhE4T@L< NE\5dALAWNď6,dRUEm ubJި]\yrOY~ :e^@6'ad]|Dº$2=yu│YݬWTI J3F_lzep@5.5k0Z2!nD" oLo Rўd3Wc"Ps|#(oUQXxl[`85@Z, 3'nmnO]sX*ZkŚ[RgZY-Gp~ܘj*zid>z/%'>ugyE _tB"$5טf@îET,(c򙷊ipI ry_ɅkA9+ =L0p92 obͨZ G8"SgE5^@7H~LQa`_|G30q;\@8#Jڷ1 x$8Q\%Dr2E7K>A 't/ ?ٮh!mW?$э{7tiolyp/k7N" _*[81U,m 1N;: a 56h6k4fi6k3/f)/?479"/^NԢW-jZ1_5CfVt&zaE UuqOuuL|a $ȫ 0%~Ieش)?w.Bl@{>Thߞ1x4o8Qg{LHzAᅠ?pzuɼ,Csnܨ\[㮽X6F4x;]Y}o׉z7$Cu)lհ6;ܦI$,^x0~95; #$`Uu:`wJ;5͢|P%?C?;uBk|2/ TEIwZ011‚ҫ5ʁDn,#ֆKB+`u,:ܹSmb[sk8e/>}\jIiP~,K29 A:<6:QD%&ӥ G>a]bNLp,t %,.?vж=8r`O?aMγ3b.FD 7n奖i8~2RVq'&#W1UE-1T_ GK$(Mz 0唯G6ҷћN/۲[eWs #sOEװ[9O?БhY G.Ɨ/**OXk+/¥ 5)l=fB쵇-mw:=/sv]4-F{-Ϣ)aL4[A}c=67?<'ˋ֩MAGgNGiKY +3YwXxkC\lJ/>y[lKOfyL2@J˜` ~'I6B΅&PD>QL}V, 23^9՜9pdta_+,x}HO ]x<+*ᨸۜ(ftb\kZ RFYc.]ߞ!kd'llg6ˌp6!u?- u t Lf5þE3#I-~~g6d jl}SMK[M]Љ*%2WQǕ?1l۹Q0+1m^2dCfH/;y)7`="tD;Iݘ Ԧ*¯9- kv~^=i! Ph'YLڻ l 0t8nZN/e c~H ̪BF\s873?ˑPloO`N %4)5c{ZMVR0ϵ4  "aƃ=ˋN A[+.}w4^EJJ>V+lU0l@FONצU^13@2kMO"_C f5L϶l$ Xfl`-;?;yձfd2/ξ罗GK`U&vHǯSn4df5"EHդko`=hI}\\ Zl^kH|FG>۷ι[*jHi̧(X8ԞŘq` ߔ=`EMM u=g#_jK 3e;zWL'ն:g$p +Mt@؜7lSRY~מ|»5&yzͿ[I `9m9_FtVoOx2n_bXoyܶe,kmwV@^@ YKϱ=tzn g>>7Vƕ,d(eb[D_HSq?S,Ez@&@=*?FkXj Q}; 9/1O;k )QxgGxZ8y mQJu3)~0f3H;H3HMK/ةxR^L$h;C^E!ы};W턧|)U$88?^#`xd4{[0:*x֩xkm?!/ RmBz9CɏY p*'97>)ߗB#ӳGmSAFDbL̏ʮӂA_#iͷSxep F-geӸ`qH,\:Ⱦ!LCgXwdZ6x $5adQv : L y%: )=d&3541 \G^۳\w!D~'puR) /굂.}.T8`krbUHd fS&u5+,aׁ }b/ZǜN98kőiQn+[u+`ژ-E]CRⱘ8Cc|9+2_fzUuOF@Yʪ9H *<Nsol ^X&ivX^cu?PӬ 9=64 YI1jtVj& 7Bwt0(L .[:6V&,n1QDISf;Sn$v9`r{QSUX#ʡn«WsnMF|aPsmar~jUJؼ(v)tVX].F"T$#Epw:5b"wl)zixżeW=ȉɍЛoHAg/IR R ӊCsbhFs:m %dfKvur(a%[~u7t8Yƌ0] Z!\vw?tAKڧEyf&xk HzUyOy *Xf4.,i/ۃoyle5f9C6@ml75`s/R$JƧIo}Gx]]XF:$bFtG$6a\8ELKw俬;!~VqHct^U~DBJO]Dwx/G\#Z έʭ .h>*1ɺL/}ڿB?K^3m&҄o5`:.ԩqSF: ?o^(/Uꊧ{:ӿDխu%u4¢]uWzמ5'd+HͅWi Oq]jBo=$m ::X_kH@dahxIU~ig|  P4,z,uOb9/̅-s^LϐyGN&BNAT]]jW]OPB1s's+Ej;ȹ}~we_ ,8Xd.nqo7G5Npގ ĻK8 tfGҸI7v4 |Eu.40]I F4 ߽^0szcI੖>EGzbj7G7-}: x-tO8r|0:!' O5~";pxj::x+N|Yac95#(ȱ_03O'x⧖u*4ObGsdwSJ#pstj:G$(ɱy݂HTpj+ 8+SjChsBބ8=!~ړ^։[";% 3~#9bP0K窊]O~l)mz]?bӍXqSZƆ̚AZnT NLj.Z60; /|N~=[]vn[6w;מ{Z=:j4]7L.˒Uo64v޷;PЋ/1cf={;޴cÎ۞nkjD&}ي?1xӺMv۹[s;wܭ 9_]OB p|61.4Sa48L}.Ii~v8KI~_z^&EJ8%J҃泊˙l>}qZn=)Csj %c ` gD˚,{Ct@dfr91wгAs K{`Y=^`9鴁'-E9fnNKk-2闞(0'c|ADJ:'No ~3;,͂_/?/=#ohZzBCꖠp<;G㝄㩮9+muvD`ZRn>&YQo]LP2Xu(6qpa qvS6J~瓠OۀI9I aH?1i;50A#QS=R:'Ԟp Bҩx WF&F}ƽ41-0z_ BxXz^˟N,ǧgx"s!1sGG#MmGЃP4 -x;E57C&ʁщ@n5\)fʥvcG`HJ2b4+pJna^0zQ+9y5>r{,y6wp9=ⵅ=5D׆)곳o5 ؍g1gGCc> 0~pp|pO=tgsLgKӿ{85#ʗ~@2$-0Ӭ~_~MsWWr|$?aҥˎw}.+i>)гރS?0'/@|kո@[Rg+$`M d#'S㡫U6OCXI2=׉o#C>(5r}G@'`OV6[˭zhsP5%r\XoXEk<+Mi+."2@ (# ô :ިj"BA!7 m>r'8p. A3LB(ݥK;<|ya[PQ58f̺}1RRc@zyl/~Oy]QIJļĸİD7MV˞7ݕ47%yWH:E1I (c XgE0뻔 M!RKNe6Fc8:#[VQq9{-&4ޅʋKus\gN^N2 _ U+'R}7f a/ Y.肗M @H1«6 m%^>gs v,'4p/} ,\.=z_.d<\NKKD"/gsP5&97xB b GLĩs֙zÊS?t -!]g7agXX9∞B<8lM 5"bnMlgsrp39>-kk'{aw&0z-p_n<2>:p|ÑѦRM[M~r|W?iCG"3y>$|Ɩ?FqXV$b6&tv-ܒeNOY۰[q>}; `|֜#~NOSaT^e.Wʫծ՞վҚѓو U*YSVӲ7x4_^V {}ဉ@.̭ly bn[D'0S3ILOM~y@J*m/;[UWfqVOp" dS@=91=91E0NHs;ìq;۲.Ko>鉳|1n;mgw-kooCkwiݲ.nͿb-2vu-E-aݲׯXaMU7߱;W l\tmwݶew-`5l٣~ށ>^~WV^dŒ_oZnW.ʥbɯ~GՏ^wK-DzB+\C5{UuKmO_?S(>I@G]#PKh=<PK:-Pictures/200000070000203000000516108AAD5C.svmmXP̶{z E"+Ez) Ez E HH/?]sy;sfϖsηgg?3 (6@ -.xW$9FHuq5' ࿴I AH:,g/g։WW񆌌2:ns֒s-&~^K1~!ZsmOšDAIN~ bw}8V߬iU,PL8؄ $`Q hYX9kirUCВaGyS'4ﶞu`|p3L6аBt=b.wgxdO2Hڇ83$ĔHOkv!S؛7M"aJ@2.dZǗ\gu@EL||tyYيaޝ $s~ȗ/ W@Hш@'t{𙪥b7.)$DFy frBo"pqի lSŠf33xJZ0h\A@K<2:cH~h.ΜƦ92Z_10ɇYd( ܌p,zGE$seR$PP pqlH@nnL6 L;PPP3⩪ RϳD,gQ}\"mu=Ts{\F֋rzq~%Czũ3uy>ُʛ<}yWgd:k g?4NFnXxήthlA$'n:)\"5aDbV!`V_~qGFP\!v%YL%[oL<[(HetAp:9cʟ bWbmp#k=l{k)P[mCϟ|+V”u RP[T 5?ҮUkbk.U*)f" -'t$]ߪok疿b]\T¬8o?op*=_+V_bY**'zEkLT"=g}G4Kp=TO0,3U~Ѽ냼2$3ZdceeBQWMnkm=euώC+Wߗ,[6gAx$@ 4kw ?Ka)a]Żߤj2vAKϼƖk_ 2o+cU> yfǷ6>ʽ>59{F3tro=_JGklz:Khn[3v{{i幉DŽWm{#_lEr({y{ ߊ;̺Xjۄ$v+nkG \F >jy{8jWVbŬ]()C7]ݣ=ܡPXz=Ԟ5s ϲC} ʠ/2Q\3OB ̓;;1A [ewtR(A_{#<<<8IM;VKUrlI^PrtdSJeւϔ$e`h#UMV5V"bTmb7-a5la;m6- |*=C-'moɯAM COLF:UBWM ٜ|Ϣ T;]eQ0)L|Y/ ,%a[K@665яdL1!evv\q7+Wy~YYEb5Ne>4,&z~ў hxRѥ*"EP0rwonU {lo%׫n:&^.̺ūNb}CTG%w, =" Vf`m:]Lqzi&(yf3SSd<,b?cu=DKqv"xN-hOCך#bΙm5^潞rEŪx4mȕFG( 2E-렶FGI 7"BsiVҿ+/,,%ĝF`d| #% RUӵo>zXnbggæosCܝL︻)?{[ƸNǫKXOj^`crӕBWkd 6.8e1T,+k_<5|9U%</xAf-t#;5 ǯrHKkZk^Ht52O;;ɾFn2C%&݇k@pM9 EGq>)akǟY)nw2}{8Ew:5]&%eeӣ 믱:h_4s|Og,UB¥tXPH^wC^ܞgwqxQ@^nNnIe ]b1TX~]HCMǟekCڎq&)s9xIy^}d"BkNn.wc`{LT>=P}w22h~;Ge%z0f}`J-|#䉊c8CКyCQA+ΗV͑7R.^|zx2 (wTݟ󅘾&7k2=kO 2lZfhV$.Hg`@l^]Nc7DSt:} qiMq_ ;LJ%o;RW R˗.w@oq) fU% +3wp@ c |ٜzbqIq XB&mܧTuV3~|'6"ӣDk\\ m?Ⱦ`ɉjQjrlC;h4߉7Ùua^d;)9Sþs``BZFyɎ04ұcMAr/od$sDJ)ݥm{.҉"n# Xh?rЛh._"通* u2=9.2)^{;9vS+)J4WӀ4n3'Z̐K$[.pͻ':8`hBVѠXU:f3uhHId+٣H9ai~ >莜o&4qSU%??Z5!6 zp|I{ܤa >+ݏ1-Q~I#զ@5k.֍(}a1"l|KRc)$%̏vA1T E?3}_Zݥ^=e){ak&VW75o 蟌[K (a 8hط?}Qv$ 󵁹+Vh!{p!:ƫ _\Ӿ*jTɥ+oC" 2XzZN^Kk>5Jr=d87&iP, 2ĵI tsݤ;UkEX̦>!zQW'CK?cUAw|yVa":ܳ4ٴw/9Vq%a[ӶXT{2ψ :<{ ,Ao,rMfQɂv47!rE:v b> ᅝcGBa9SDZb&c~~"tq&Jhcj,o3Fe6%D.y26*3K of$R7+ jz7Bw90t6]I^k jRz26Q3-4lʳغ#Q֬OlY `tQ<˟#akux=e!tM{CO5Oۭ[_\!.hh \Ìm{#H_oxW}1 HAL'"˙6bj5rەN]w2q_=߫l5 }PYms$}b'DXRհ23?krӵoA_}ePJƼ}{eDJ+OjLj|sY .bAm>qPigZy`;Nk|k9JjWi;9ܘ"gn+N].}K'`˘Tԩtt `ƌs`!zK:i ֚$xOC}S( dhQ?742;D6;_a`Ag1n8\Ype"a_y> biY^6!aNh3@ځhk'd8Z-/؄$Z`]'e'z%:H wW`FPoaނp` ^ bz9YJφX8T#a6c'N"17RL@~EHӍ68IeYӲlfKZŪ )*j9ƣ@[ThiX<7qo@[~xڳlWG?!#)vΞǀ]@-Fe3 m`,ݑçԮ&rf23֜]zd]q4pjr0dVg;mi]ر Y7S/;g_8pV TV=S@U#[_|W0okD4>PSg)@=X #yWZߪ_\:X **Њ+0NÛ6?9:-P:BAug^S?KO,Ycod!`#_mD af}F(03Y ˯hگD*DUJxJ2mHOʥ12ZiMO𜪘/YToLZfAc'\WCr4e$L":PUEt!8؎ǂ ůO G/]fϑCj~g$Ɠ%E( bBMԹ ?tR8j\:Iq/S5_*6aWL>]_AaBŭyEa>F "LdAJj@T™ oG-wO;1 P>Ltͬ ;ZO^Q#*ygܕSF>;>kqSOfR8VT?y_`ÂF$la~mDaUxX %W;sj*e|0HޢIӲT7yFV|?,"BZGo Xs]u-hϭN}Zye偒 ?LC FjMaH&1I.5?'K d[¹Yi/ ^%[&p%6IhY@qEIzPCmX/O@>H?K '>EA2X[oR:ZgK1~v~]UqGΩ̒g"Č; ]≋nkv+tl +jq(.[;6_i+|ԭ4ҵcyCU@=B_W+J>rԳ$s2=ie!UtM}{V~PAiB'˂QR-ax\vG5I;܉o{aRIqGp}wBaZS·HCX rr/]G:v#H @Hm̞'^<~RՑ wHMb(_ecxL*y $uMvB#M1:'ZU:sbH$a>c@-Ԭ?3b٘i~ZuW'YS5ǒ;pN/;2tDSyp O[(HELU1)Cgl?{8( }?k%OnkBv1\Q fdȋ9ZS=WޫTS?UjS ,߷500](N"%_hO%5&5ʳ)6~%yXWxxY6ظ➊mZ$&k&]e$80l6q, ~?m8,X,$ۦtPƛU!̻heΌw2BSړײw_G XC% ь>w fhc2"Yo" ث48ĶBUHfJ굌5/Qʕh sr5qUblb4):W nr)Bu2o̮3xEJg{Q44i8y,|FST(/ި62Jg?Pг#he ?9W} HZGMCR'=@N,tƤF7#{ߌ͂~tK\B <,՚Ois]PҜQ}`i^j<1ugj6Z3{Lk3k?Ʀ/s-?z.GVUeC/:YфtӬ!di 'pf#+kMఘuIheV~Yaq~-7,N{1}[|R2~7a5`P}7m:K6 @ q5S ժu[^ y?is^F goO liRU4L 9aWADhՉpYzEѭMnU<͜sfVdn#G[gz*Evl{!G||kwK:g3!d@^E% ~M~%AG*[qu454 s_ڴg,7`V8)8^f^-}'Z3||38zMS`~e@+[$wٯy~#C̺q#2tlZtɑ$p= a)=%ݩbg̀(o+m7򟚂b^t۴K]hlA sT)3XE2[ͼUGW$T@=}ӹ?gk6t_X3qj1 1AVں3/յ)@Krsw(`(BQb h䅵wM b\^u" d)`!v)l3w-HsE''ve^KZĊ>oDC_pέ&B\F/ƑuɾeSqU=/Co cL0I~/i>GsK?ool%53m D;ԺGIVـT2pNqkgFBHێJ[<_1|i)e(t~䝝l``Iļ:d1Y(j!1[b3s&y3钾FP$EؗU>B-%{!Kj6l>w vF(G%9|\L!'2 22$BTc 5%xwׂuL}""nI'w Pfn3INÕ%&UP{FA$B0 Fִ~dLqa(@L|VgGY_2\ZJO<*[W) J;}d^YnKkuf;CH`{ d~ {ֻVOMJrXauA̅yL!cҩ5'3H5 gf6ͧFw97n4j'|/͌}|p3*$q?~8ں#sط QrdYM66GS]/),b((#ߩѭ;4Hڎr&À?4ܻVVVJJ(?<=X&\tQя󵪵NOa`m #*hh_,B5s,Xol!)L+u --r6T֕uS³ʵ7Ql=`|~./mg|z5>},.I}?6+l4ڞ]\J11NWOmB!]{ꋣ .d-,JQ1n̚4z8I@ nB%Ц;@>8_#/&dc71̝v24PpϚn6ٚEթp 4TkoϜG15782,q‚r;{>xڮB $00 'IvxUU!/˸bPTJuɽyLLy52I笿i"jE~3=aaa qq=~)XA b*bS)p=QmhDu^_^PIE'OS>I7y؁'^& k:_!βb|d\5 s+< ŀ GX9AV]R4:<ںmnʠ'%7~)J=BkXpRu-Y^TV}mݒtڒ7V`:HT0* j`Y@m&@堟e債=1IlD$#|2)6 _2Tm 4GU `ǡ<ż 1@iXf]XxQ+Z=O=G|9: +?_>*Z"}'!cH.7c.Q!ZLw/oޙ}\#wՁ%2ߎFO|Wϯ_9ub%0W[p#T]S_Ѹ`jf<~eu黻N״t2|9)> ϰsŇ@rcomCǭ?.DzaiM09 Dnyv{ٴ&Wk4OΉIyBO{2 |XheQeTl/xyϩ|]Nz.z™J0]4mq3=i|>uE]6 +x m/|84Cle~y<7ǢPͨByf(–\H]ōoAdwuZrM#vGy#wP;kyV˲3pϻ1>ChetPN` ҭ2iM=4xF`4";D,-lŸys竓p1Y,e{?SD|{GR7Έp;1}tGRMF3r(1 ?:A|Ycg[R] - hrG7tI"4)T\o #6+Fw<"TLb!16||_wK3_&U/_ 5YsDS%& 3Yc& XYUm{u tkw|+y7E5삾1B/.G8Yt pzkG6vdwPQL|||^g9"~ 8,q4ޙtLX/jO}>_?߰6\>ʅT"Ӷ8Uq5n5ۦL>NTBF_q3 LgUJO 1N*17Jz+WNϟ>?F_CuAOOjjWvi)>O&/""|M=l(e׮_ TAlbM@f]Kvv7},<4L*GgxQa,&z+a%.ɵAڛtENz"MnHu8kzP-x%7IE" MYvIX!V]?ze)Kϖ0ǯF ^%eIԒ3MVO^&OoK[ZӲQ>`s>!ǿ:S;R$0-:i\/C;-"zo:W،N=RBS&m0uWӫ-GFI1q7ߣ)EÑ? ˜ks"jhU`eGVn=T ?&lZlܱcOthB/12Ctk0C0UF;l0Z5ULIg9 YׂКvzqє'vqG Z;:Te[w~F4Mx0#ȥ'nldn^8p?*R h,zMK]}k/FQ,g.m쑄s3^MK=GJcA鈪/4rrp2ac,z6FC4~-U=;v7Cy=e&Uk@OY6~+'|+ȸ /V=*O;qd1_l.ֵ O' tl1+-gEAzIke|@4ewO38XK%еub9,"F9eE٪&*a`dm~L*gWse,y_b_(̛m))2>Uߤjq%s\wjWISvfOpNԳOAS<}.ZYnRQU +tMiX&A(jD[X?3Y;;GC_B@|,2JM"YIz>c{ C_M/b:})![3,<:>djЁYD[lְ2k5DMY/pb|`SZ ; vZ Ÿ۴}BS &*u1jS ]b}ݤ|jqN3w\^iR&m(LaJO:KJC(|sMD4w&r*>̛c6xP|'C"$=iOā$k^'Qie}‘4Uo3oS<~9KoqW!LlDu GX0H6u6ʇdݳgxǫJ ИDhO!;-0o !q QG2Q-{=xΠ1绞L{Ά&Mmsp랿=@~miϣaBû]NWMG`ΐe72rWSJӏ 53P9?K7l[fm]oL:tA9o+Gv6K7"24Yey*X#.XewB3*ޖ<T dLQқVoh=w * ]]ȽPA\@z6 k JQnsoݳ ?v9 phj?8-x{VVb\t=Sm}G7x; )}x7DѤp$$OI8<ē$=wu]ݯ_ǿմOU_BCT1|dO T 1`uuv8xI}7zc/T'VAqfV,"Z])KU9z3cD eڊsg\#d^&7E犝X D9,s4UE֋l]`ߋkݫ+7+Y96(_/_܄,搮a~ S61 GȧkoZdw(+_X(cyY( sm)^{v"WNbg<ֳ8t!8wuUܬ"eed ++u-v^?awBZZ. EAeHv%cax)}S*zz;VRmBBYYY2G j/pĢ5C E@ݏX? d2U"B1:2Bhhi~~UX?v:V7/ksت?K~gKՏ{6WXJI#ͣ8>T#hn4;F1;H\=LZYLuLT?gw6Nm?e@]1% i? S5!xy{]A믾/q(p0WHIa~+* @,9Cq_5qtj1j5v-[W\{~zUo|}n6'KޥΪ@*ZoҼ dߩaIg׬1:dh$Up"ۃ#OOj;iƔ^p:r;*zn~h@Hjť#9\aTڼ2vV5_aS\~pΙ'Tџ̜z"*c|@hb-6=J uƘZg\Ke\ukVgmX |O,8 E~LCFҒҲK'{9.,1mj{ǙI9#C>IVIU|6 _`xf]3}p(Yϖ*g`JᔆGK?,rDB$V֝z;|͝܈J= 0=Kds3Cq3h)9[ >*Ɲoȣ(xo7*Hc+*\r Y!gfH$&X7=aRy:-7H;b+?Y[E.|AK RGhHcfX {B):i$b` ECO.%)u3S_CNp( ״/t].VUG`yXte]F9\X T)fR@fzR'o6G45RRvB8]F^tڠAeUl,y9ۑ"B<=cBj; LOx0B4g5D&WT1 hsrrq61TDC= 6Ə0!b>*nT'wK9ԐpU)L[ Iׄ"_Ydu)-[ي .?F !oXrgrwY3k/?Ku {cLhMLؐyw^mu? 0DwW+/ ^`s@=n'r`bΪzLJ+?wܶ< *(G6O6Uu'ߺ>[ J>γg֢\EB9leJMCS?~4r"M @4ey̰61K1z[~)ȏ$%Y#Qy! q;pz׍ .JB#N?-e|zMMe.671C{#V8_ \AkT8Vw$m;$Jun"3 4,K"|I";i*S)0vbxFzF )'{zk~Kݰ"+2CQEj!vo#AG wLl<`BAS vIK' A8T_/Zq%  _),!J{#.N4F3' 5a]߫goC!|Z2l4R)?k)έˍ>;0 x^ݦf^R?u e>G7ok[k/{,V*D>֢!Ij"F2ܫwmjKb̡/TDH~/,h JaG"b DRHCM2>\_! 0q s9; V>(5oԙЁ6IjĀ@RBDX66$ּW7XV T(@Y~} XKbRzl"ģ-ˌҞ@7CVLĮK'lI |PTLhEf9 wCC 2 "5 #akZښgG8 E5+i1+o~epglvv6Ѳz}+ "Re)#rIu3gtÇcdAdxL8OPP([*"\T{6sm7.3ODa {#c #Bx3l !~]~aތZ*Opm%i6 @U4-GKD|#~W<"|Hv=rp~+*Ưo)Q/P-~RǩPU}VL<#F7{\sQ2g>%0~asT=J X::W_֍"/!St̥Ģm^ScVyy1&ex?BT!qΚ>+ ES3ȆQJGu DV BLhֲ/x赋(i"E<zXK,ȡQA؞R%8l̶}1(;TQle _$`-Ԡr*7SY~:}noҸPoe8P؁4^56hAwدQvHYU{5FBhpnx&­ zvwggbCdzOu["V+b@2% >e(O[+ 3)&:ȹySt NSz P`LvSc!5%CwS"soÿ?!'WpPK@>@APK:-Pictures/20000007000056EB00003AC2DA7454CB.svmdZXT)i ;Ajh%Ar@BRV 顑Vc~r?p>]{˨##=EBBB}R ﹥E O4  /;05H~_@̈ʯ!"!'BE}i@Fuv&zB%'a=Otoo~彪44!6Opk.Κ槫%*mWW64g6$o@n6oV kA׷A^n`j0$*Kqmj*/V͙?W4pqjfυR޾C)؍ne^XRLf|JVPL4H}@Nia 5HS.1k jku1s:Cl wBD%nI[?  $uY6nQ˷D-嚧ag'{c:|r$ 9ΞAɤҚf"`a4'7$=4t?mw1n p\M˄lgRVڥ Mf/`SPVD/7 ]Oh{Tv}'*8DFUr臟,y:x5s govf̵(o%j|Cc`PvOEޯ4=AdNk@QUiB(j^4(#9}&ANx0NM/{GE^I,cgc~j ^/U0E[:V{Ss$ҼRekr6'C]r$pZmI3&fJbi".L&ZJQͺ#Lb~ O__&E]v%CƗGx@671gaO&e`٠vȱX jd\(}Uc >`^3Ti(saiv'}|c*g;mHX7BͰ7AD&yCM/v62- <Ȼ,Nmi̟i`N*3^gi/92"b3U~@:*դJ4t:N&eOv(eg-(B/`WEwK)dh4(sNp*pMh;~Xȅ#2Pt7kwGNV~SU ѯu^-35,}|&v{?8řBU'j|YFwa9U|*:ލrpλ_ agpKF3d8}x9ֵXDv|U33kA44!GF\0h4U|<'&{3_,sΫkc3L<'tra0Wx ˆ@`FMYp(-gA[(Re7zPrЉ7ݏ/ޫA9ᨣ܆[Yv볠őB]8{Su@! :Q@mM$#8pga-O,[^ݏ+>^sk./fL)r9z;ODF2 ;fr41Pβԉ'MeHx~VQ1/hC 8G|;aQP'Cݣe(ވ;|,Si7U_H$v7(YiV,(>c|h az̳%Nz)^b'?qmxfBLT%HI|/6_Sl0=L7 1&KR&ȯ1~?9N鴚] s<6<@w [!> !:t/bjl 0>qkd-E){>ՇyzQ M n 7 xZn.%gtdףbm:G Wmy7pU S,pM*](3ː֞Œ{g 8L'AхAH}XAX_%#WLu2_#l7JjGG$T[ɽgZ׋̜O5,頦-%R LsPh}4njҴۑNg-ICEa^u0*N1K e--HZ/@qlz4U,oj`$7 ׸X&%shRpӤ;8Լ&>=>8Q9mͻX 0Y N>egڡnw7y#pRXIg/CLZ>5vv*ܙke4P% foa`V,h 7g56$hawL3}i;[ $Iv~W}| гibꖅ]ـle .)@XxIѓVsCzx}Y")D^/625`i(;YIJSC"Qi:,Cue}Ge}n[Đ4xGBy\78 GoA]@\@£Wx;z-GW.1Gq+/>gu)o|-Qm'Rp@A=I6~M$Wop~nf.$6R9Ʒ[^ĵׁC)Agm{Z~̶= ]¶z~i۶Q/ˆtNrjbl#8~ R(hXPWO]S>,$.4zi[N+$ bʧ/x'>C3)1Jip"K3ŀ~I"9;`M }9Hƀq<:m-B"w}W~'t7njM(>۬ )x[Br=Ѳ6 0 u0) B(oe2}"8i0|Èy\p#p7pD5ir`_.=;OWH]A7W $YOF=JDS@'9('"#˰`x$q3r?B .`ګAҭmk}1Rl2+i?ҴH21M n@ ]lG01P2!-C$ǫt%@ emDxɽ}uP"yTmMAM=.`GLe`=tvKQ`ٰI&||[Ʉ_K*pOE~f ; *7,?oxu͞d;ӊ!4|^Anti>ape ^x5f 8Vd\ay"6g/SX(P IYۄ^UXeD?b 77v"/;B3S˝QGƆz1`c8mwk`Qun˟i=9 /GE57OA@kRnkoȎ$f:%N=*pvޠMy%FSy{Ft?_]>n$)??)0Т3ڇȼS)@ffe&9!| ]1^lh"tb@p}r`J|BzzD}&Oeop x̓mO Mm Gb).oWJ~BCdk$tHHXtf`s#%`{^eD%C)FՅow(c-n#To¶C5JԷ[" KrIr%ke$ǁbn/3&! ' ۝U0U;0(ʹ;CA Oғ&?i 8૟˙>H ќd?θDM")b (ƍq*0nRg@>6D4~(D/:\VN U\zdh>x/[MEs\$QL I'FZG{̮ݞJU"ϧ'o@km*]ZukV,V#\7xH(8Pn#yxg$0O>ubpn+Z= U/l[M|O ^'⎣x_olm}l-Z% RE [<,:nP='Áj)YwE{[W} ϝI#C D?)3P3*bcDylc+cu)̋ x#M?:} )WSkљ>=>e:;]xo X? \ aN{CGIHO[j:W 7 Dv #[6Çx̋ume4;"Ԓ{N0u9L4vcC5nq?;j螣Կc#s?+Ф> h'z& &f-yDnnAAl8Zs'7o4 s6bM jןDbJZ_wIPCƤQ!n_:=N\5#/)?04KDG<`I`/@#Py2C uT順а mWCERؕⷪQj<3"k/nɔ#z rh\I%BdXzjlO3V(E- ɀ]}uh o*{zDMIRe/5.Ժ&_%%uGVֺ!2E(`>Β0 swem3t)dk\ UKq_ZxxJ>qZApG`g~8"PV f't;_]j4^Uԯ&tD= !,%{ho6Gr`1B#%Di}{ r J^H4IOQ *H:WśKk8lcNe'R&{n%9DWܣ!ڂjy- 9lBϯ~: GשdlnxW%T~lb(k&awfV ^42lG%o(?hew,&t7),l\zjHB W~2({Ka ch@!M&?NLyE\LZ-[ֈi'-AfF9mFt!WY9 Fpَ߀CW0iA`4{B馟:B,Nb ܲċ-=f^RP{Gkŧ*h.GFM/$f-کOlS%h˽_/5ݒbh?WcT'jaUQ^MR}m7Şf4`V U/~@{}ƏE( Sx3~\h2fzF~=o5: 6%x -4Z²+[Yu41y}oECkOX?̢,P._ 6h)ukXeZJ}TWR@+1yW+N-[\řF\w';*X>RULIu2aZdiZK$_%}(Bm*#IV昳XlΩ"w5_$ث"vclXjeALvBxLcT imkK 0>VsYEJЛ<} ?{`T+s]VaRޭ\[ci g,Hs>p=,kzܻB\"n3WU:mp/`_~Htݡٕߺ}NGJQRĥ%z'(:_nh1 kv~ .C?pzg/3$̈́Jn oz1HpoKMARc ( >8{oKB/ F8a!_:,y~v ) QʥK^>>.3ڦqsoӲSu^@Gޘ(Beod&io gcNpvkwGNH0qPaXOc;5h5GvdBmΐ$8ᔉO+j̀R%=_>pw\Ou(<7jŽ(i+\NdhAXd/䱹>Rx~',J?~yD'JЀ)n@}-HK,O67No^NC`Ukz g*'ty}亙G߽pХ5S|mZ܃etdʼna, ŵhj 3`r٣ps'+Z19+Q4cKM%\mUL_:dSk/GX/2#E!CX-6GY}_JL\i~tƄ t.7gS2^]dd$Z?ꞅ.`@_ot֠G{cG, \XOe=ډT‹.\Z3բѝ2uϾi16iu$~uAUיIM#$m`ZKBÉ|Y(][-1.=wbPӣ۬/ p7Ӌ.rKoYl1΁^C^ ]fOl ?}^dEg-(p#O2hjDN׃ĸpՌ./Q.rnV5ݻ }fKŀXq'|TC\/QcHљ+]+94p&jN]̳9Y=:Xli@ THCR7Vdm2dC/VϯL}m;FK?fCmL\1#G62GF ]N,BPw7!r_gP{ No_G>!d>TxbkyV6n41Α`Gڿq[nAfږ_Tx TP0#qO yo%j~/.ga k? ief“Lz6>6?gA}&KмrLbu=iq M1fq{Κ˃@ZCf@*z&MgD*X'c~NOQ'ۻm Lu2Sj: zDl( )' VKu;8tdHdP3l؟fy~?~Y@ÆR23B7y]X1{TBҐ][;-]` ƻ LcHcJKl;PFcƤ0t}~B}uB,₸9C]ԏ66Iҗw`"ϯ]\Zro;iUO-tl{Onm=Aut~MWE.NDA/;%^MO{Oޣi,kOc~0W$ij1=LI/+H~ ]7n'z|y^ w3F>!xVmuޕY[Pf F󠣃&1򐘿d)ö90)}'G D&);t4G @qʿthmNZV&؆ zc9t [N}8RQX`S5|ٚP"AgaHGš_ՔO65}#;B<#oYMk~!Rg~Νn J)̖'Sc.{P*ߛXtQkD `3zAq^K9Ub\]7 K|1RyF:?.kk CȲ i~ -٤ϗ%;~"!{ %p]FE:aG;霄I5(|BP^D~{;r: }gZ@t0!mjn껃HOS̚磌ոS 8ֿ>@znHvwJNg-Hq 6\>.ܠL$9S<ޔz*SBk?a9Cm로{Iy?{$dhr']]a;ʼn/-?R\jd&VTĿA:Bmeq.E7 l ~qΥ6Wh{G.<[LJ6mҜ%#5muUO~rO^~>.#9׸X3Q֛Gbtf>}Cyb2=5')b/') b2aZ SzMr8jEKI%?~v~0vX'T⛬" !iĮz"N--y#C aGaY~MJl-S(?oL+NTNů$z5voL刐L䞛73<9GB9{ ,_mN=hӤnSboKȨVn`CC I&BjHB\t}S*tn2n=6LDkmݰVޘ+%% ~Ca]2|? #qKve,)5R n3h+OěԶx^ov_IoBg`O{Z_r:uco9;te!؈/{&Qi4ޜ>́RG.Mڎl鳑l5ˮ_h~9 2d;o.-ۿ\}F@%M:ֈtb8(APD3`-<ʆPYz & z N!`u˳Օ²k=P{.쓟|Kq8`R62AH_wCuf c}B3刳O!CCw4JyFBwEގ˳-qaT@ӦrAZ_+8cUDM%5¹"jvs,x3-ܶE&n7C: 'ĦZ`E'Qes7S+ _MVAѩD6A$MM[,uD-I^yΒfIb\5/+`.`Z4(#) .'U)IM_av}{+khK} XAαlk5挌/R-:Q KO2c)ײ7->n+d?Ml|T.iסi{Q猭혠\;%@S1tXr?85g.jῸb |i@墲'u ?.<^Hm|bA 9XEL"$!FrVs/5HbAaNDL[#W`^oϷM@Y3*wvK3t7WNnJmUmiE ίڴ [_V73pI9`sU+ H֛VqaΘHu_clsV3=)l)Tge֭f>{oa2CNfX',Ȉ)# M b蛱' q8>u+b<;v1dZgG힣)(^؋MM(4y:Ѓth.~(q"ydf3R6Q,(A] SjzkĭVdu}k[j鼛/_ fiȺ*7{N|_=t|y8kign3Op?!qUivb̕kddqZ #£ݚv`Q~t퇊!e>O@<_ 鵄L(N p~\2$ky'a7ۘ͜Sfb]q/H*f ֊kjI׺IozztѰЙi(=46|u.[K*d!EBkb7G;vVGǤb/vxカ'x' 굖:"%%+sz[a{mbE>{hy-2F-Ƈ^{*ql5d6]~s!Tns_kn*yާ䉣Bz:~K:gF .ʇS8!r(A61`l݆^yƙTyLV=*­S9W*OS#"6)CKH2`Ibdh˲!d"z'wQ߷P[1KԺl{62_-` LH6@qJ~B]܀NRn\K-ct0c(7/\ȭ,YR4ΞĀ|}kGnd<; DFJ_M{<01d9rQMa.&0ß=ct IEvB6 Lb _h磡hd&5)Hg,Z LD67JcnU SQ 4C;W8IiT, NѠ+iG'ۉU @vWS0\\\#4?gɓW)M >'ӡZ30C׀Y=-͈SSOдߘS:r@Q2[2_XHk}AQmKO=FU ÁF G%zܣ@t%H02t<)]m6MB`ԢFA궶OT-b)O +LD|hޞnйmpS\(^r[P/bq 1l]>lFG`=rQՔ 32JgX螘1mʳ 8/9i rɗwSddUQ&Ҟ5P=d=ޛpE.A(>M̼ݬ.;9KE! v-8;'g jL3ylG3*`㯐ib#A<1U8eXoxyAq.yTh08?D鳌uXuȂiCOt ۫hbooȑފ4P,7fbd\][3o{0\qnyC6zqyyy]ѤGuwډ=kCJ J")!q=W t*t |&T)=$i׬Y^.ZAzذUedۅV o-5ROmoiSn3K%nvRwyf.+1-7E{{>ٝ/Ϡ]$>3^7Ȑa h6gK}VžR4u`_dK Zݟ-@#CO;d!,0D:'2cQ'}([l >r2{[))ĵ͵9eie;_&8.UpCKKmN@X K*=׏)CQC0e Ņƒ-fۅrカԸajj hN4r uDR4gOEU\J"cXgڝ"S9 W eSdv^6sIRZ&QYv lAc@J𓭠5[ ,S /yt[f=E Lծ}ۜ;݁\= kHit8 m99N .a/Srp4Jɩ&rW#t 󘱕64XY gTƳsz+G%nDF-"౞' P$&<Иc;1_֔)S39*k5+hn3sr7ȃܙ՘N`0/ȣ-LX6 dp;# #هrN_oaPC`*4^tq$a/"l ܮ䗇]b0{C6,^)oH+*ImhA:F ALM6@zW󎖝_&:ag[FO=8# Ì.^w cv:aN v>(Uаy[Aw+VXaeK#q~c EƑQ[h

" YaaY}j8PV5MM& $ޕ}֬P$&8 lxèiV1|d-Lv I$z0 µC#@s,R嗗IJ&%+ϨD 'z]h筳t NT,2B|9IO+gBfYxd1Y9[ls~P_]po&+)i{Ns) qPEG/"Vq^#tଡ଼g{㧟Y.dO)>Diw"Q0hYg'9XDK%t`}<Vdgܥpb-~`vqouNj:}%=c*O^=77_uiX%%o>1S6++@NBF3>QQR΄+CM6\_EX FH6Z,ެeQ{Rtxx\xG^>&(T btȊK$X^W(E*Zr+PZQzÝ8$+C%4qpFZ)*gckBRTivIx(mnA@J@iDAJ$aqHIs蒒΁{9u 3~^^.`.#w]v@LQ6o/%1g{?4lr,o p{r᪽`|% >d&APtJREp|lH'w^ڕdM6jă7b \Y̍}!P롸@jy+/s [;yl\=O[GOYKi)UJ]Z`McUud!hGHCodkGTP9i})`K a6EG{~ByiRks okt~hUNSm8d1%0Z)Y7Kmq'OunYB"3]7ܜd5X!L _C{ {] 0 O^tXZhQ'qF!d|񋋧?&rw&r*0:e=?.2X֨?O|BlٻsP5uctȜzUik+\84S Ixiq#ܮbfw/8J_Tm]5[^8LwUDkysri%wM$7/Ki K(ul*@ Bۃ#U 8N'޶@EܲrTx{hYܝxB|g˱̪Q᳒&dyۜzAmxg~-3m55g%tF jf\.i$J+|zǻ ҩrcVhXs+ }Ki0/AIۖ -)Mie.B>E֋*NGG ܿ6FE˘4}%n=iK5 3x)T0yfL|5/O_Wrh*%oM ¡OCO[Ns>{ >A]T+iML/}U5=WʶMp1@=W&K2Nihe6!`J鋑v!ab mb",4(mS+"hx %ֺo|ۿ`nP$1,MElty,llACZV[xC=wW2AHG8aabo=vʧY?nd;w? f9o70.Rև}II̡8`J/B]טEpАNϻbr㣭8DPK{6d#>?ٌZu "6D8fDۂ Av 4Ey#\S}6Go3z4F2wǹ_$Lj(ԟ[ (xmӯ -ߘ/j,b2v"ؠCb/pw>44<1-"Qw*W63eqj4?/yH7j2&ߐ ^yv|; zTM׻B϶' 53tնt{'Db f{?-6,ހ^.ڍKtJRA <1#{4̕TL=UU?6Ȥ/DQAzp 20\nv !3ZoOʐ L[k|,#ZƚeǨ# 19KL@k/>*qI7uܦrF< ZK:r.Auk 0AK.Ɖqm[B m8]hHr v9.o߲q^K:8I/C'Ng` l{we*!|nkfRȿex~c e(-(bDlO43ɇݟ4I-1>Sd=7kp2ߏվ+?iG9zx;uxwV3¢OGGHun {E)@掶ҽkH-գ-T߭U*Q̯xƗ ,3Zd?6L[]ث#f69ص2a ahK1%ϕF?j{Rv,:\YM׬~KTύ.M`__ÐGM; ߵu߳Y@&L\en@m//NR[,~]ug5yVʵ.;wϮr0^w6Q(7::$A+(oRGNr[?mjr6r*{{YKRg?tӝԷ/G)nc3$T~yv*w\uw ΅f"m.P[-W%8~cCȈk×c+5& xmQҥZRcO.ߑ!xZq_dh^{@=/A3'^E7Kk(} f2Ō,՜ϊ{̥-#/4?l,㫪u&h ts^MaSAuFܓpOn|ǘB皼X^L` RȆ9_MD%Ix;m&4n,+.iCz2P /灡orc.6!"i]_l\5[",ejlOmAS u.ެmb¥ɟ\Ei_E63ޯMѭCлg %C"nٖn1|$9=,qvw2۰w;Q~8Q m<1ƹLao OS}XsE9 8Չ9`@85+[L%ʺi/dgnn['4iId 3uP(/}bAezkTmm哇w|gvMg %)hix6&y Ǚ`#r# Q9f_׿V r߾8v42!!WHz]@❻, Itbnw8*m"f_WKjǫ{yP' hE-oSjF0/71di"7ZYHa!}̿j_3U5M3;R?W>b: ŀ/aCYa9sG:$!HbJ,YMenA sjNצ',)&?Uu\Þ 6(`b,dI߂/v,je_qLzVG%phiAnZ FX*zhòj< a4U=ܴl=|hU9_;w)w="/3UlףDFHQɇ[^.sqt]F&Ħ&ajM>7@6cȍS;nd,~ʢbX%JaM V qHΌ ln.aIԹMF~UyANk2W_DGfk>vFĦDP]B >=4H+b9$l ܀>y; !J85~ τ@9Яeu$SCROh܍Ύ~奓O0Ph02b~s5Y8ζTʠv3VϨ-'ń! /e۴;?˙\[f8+iBO>$VʘL<7z:؏Cj'Ч`@~Kz#d&6<H>l^e>󊙮.tlQ| @O1|UlLa@k%܎{o j݋ƿEJw.u?o9oiP@ta'x4Q~O;!vCK~+`b߫ZLk(%>D^V-򥞙:1d~ XΌuaL5WϚ-| |=?&{N>q/ o!t}oS53NoYl$ְav:W, -9\Pej 5[hpp)G/".6_Sn\9OBf!+zLW?7,zĬ2Mg50,/ Jz"x?O϶l#%Y;[:Lͪa(Q*t,s) {%/ R'-*9Nx 3![86 }?𛩻F%+ؼN$āaL "8 0JZ&TPe#HKH[_ޤᜫwU>P]T7zJQ8͢qEeVDM9?('ߨtLӯ`=\18k@C猇xէd=0eZ[N+Qx2ݻwA" [ԔЃ{B%~2z :?gN]bȀJz [{٧Zl/ d6F~3=J&rpUڀ7ǰC,VO8cGZIA-Hwcn@Ta&_Hv$Qh[ׁ{E, sտ9j% 9ST A!t[ Ə7OԵwI.=w^CpES3QdKXӊޱ}@nm%)}ade v:<߰bTHvUCZJXRWS—L| Izc nMfT+> %Pjo<|s{W kJUH7Ao~\# B(kT1_o<Ms~p$tVQGh񑐜 *V?bn_-"lq-VM{d=9jGM|0Ȁ'2[QʜRg̉{(ݓ g|UVMw{gH]XR_UCqq<"I 7'uB5fG QEs`ݪPu茴7zzPی V6/s4o?(YJs8F38 o(?0[粝7yqjhl:, mdWT81 ~0R`wm|ӀޕZ@ZBl&`fѴt[d_vƺvM4F=taxfmfYII$zc2"`Wvƍr~aD;Z+s,^kQa>._y>w DD?ֺ@#ŜLh@C42nARm\.k9OlhUwX6SULj={}NJɩ9g%W~3|4E9 ;xIPrwRc?zWRcz !CADD /- ΠP_.׵kعi1%9@ RsςHaʤ/32ƼeOȰE-9k2Qx3Ho:eo"kZW'CB8 vXNUKf%@c@FIjo)``ܑerEbXDa +G!(> ?Dx.6 r: >}#ǐrdnsJ wmG#~#}y0ce1ߤ/-A\Q3Z;dm +,LV XXXA48gsSD``WU@0y2)- geI`|dGf1qo>?$۽q?NhY:dzO4E BZ7˙qf ;X"jHoab1vC^aT e91ν9>_SwDEZZU,0a Qўp,@z=%Z[IT!e9B6 ^`m]&v݉uw0Uץ\{%1@UۯAB!Sw&^O/3AGY)&љK-5jݐssssH<I.Nwo[hP>=BZ7Gmw|{<"fk, n=q\rzsJ~XX777IL6sPhF;noo_rơRHa/^/9T *N<[뇵6uhWTT,0m ;ooңQ?I,ś ?߆*ReɖrK4***2&@ѣXoIUyyRxi&Y]]]n/ ?]"^l[=m c ]h*>h %w4o?wԟ'Y.AaFDq)\`қ jldq}huH {`C?ކ577DZEDF\jg*#^{dXh/(d7i.ok{PTwsDR``|1̶%U-UJB[@tV/dNY ]DH2JdE,o E]26:::6vF|'L8%@ ۨޙ?e=>֟x=Pkp3K~̚A>w@;=$-&;E:"'1 ?N0j s׾}*Mћ翯5c[TdtT޾}kdn9Ⱥ㼼i~?=͕[Y !3B,hJv#R3GWCCF?Ցff|]mePw73?iE=[K;t/%Ʉ.%so5KcWW0O[Ȉ>+ GW mg&<'jh«>˖t~E'{xqqC؈w]51- 'cjYx{ĿZg-SnF&-ucbNv"Y ^ukFޝa <RRC-G ׼ m㔵%Mbu_ zfjeȥ<Z4k|'/Pzb[;bR^:b_roR'HP$S4'Z3S"n+RVd)q϶YE۞<<& HEjdL.6!A x vx)HH]n*d*{=pS?)<<*0bՁeeWki<ǜjlf׵A V9;; 3$NN23q;v6ߚB"y<?L kfPUJOG~U,3 viu ?:bFHd .Wнݯz0aЉםdrt_WE GltWWW e*ϳgg6YKYw2AK^D!ȼܴJ@HHh޲igd=f(rKyC 5 ~S^@xrՈ |fíOδ{Sʀ^JF!y9Ϝ,r(kqЉ;}Aui C1O (|uoMjHÆcTƭPFa!!3lh#2+lgnrt`3yx)P_;rc,Iʘ$]Imfdb$ "񨜯z6k2ht>Rx~lѨC]ut/  fz9eJfs2iYjmYlBy iw+##cbⷳqM )ov}CSX"ѰTqs.sG- ゆ-^4$k<3_n (J+$4ɧleC^ʜ/i3HZfFg/_FIadA+"C4Od,199v߸ bQT(2(Ř&I\Ɔ =Ћp:RMO-{W-~X4N[%R;|T#ޮ#PMv|$1Yi8m\V@AA|6:ӭz@N )_r~QOpR-2}8xF%wß !?&3-)L|)zvTM(tqQ)9Y:OU =wtk2$,)[]0fv2 #/nTZ'F׋*I݌g0Q.얒7]wy#¤-r:{U#]Pvh7 biRqDhP@l!?{|/$cRΘ 2&$`woi2H_&f6T2䤤# gٱRI;eJX4BTק3;xx :RF8jh:0zwZ PsyMM7ѥ$Zst?u(էj wכ7u/_ VilbS}{j.[7]qN]Jٔ#AOq ߓ';VL.buϫUXT0fu 8GЉM-q*KiᆭyWEQJVrkyciBg عW|:nۧIeIũO&-b羰jsOa =~k\vgTt{ѢC:X9aE_B3s:*c X{az I#qpurg f<OۇI6 +ϧfhaSڗl~}} h=Ab|//aFK1G|tsUNUI"aI~Rf&MFcw_mM+ O7X(DE6}sVsblj"9JBOo63Siˌߦ[$ '.Q5ط?t~VQ`vc^NnvBa'9ϴwrGV 6t?ςXA?P0)fay훗#tZfVS#Oe(W׾pLH lXYś 4S;@jrI9 w3J,nT_\??a& P1DXMgD=^k@}'>.\(:0X CWԽ%9K oeB (}+,{bBF}+8lp:qlJ?BOu)%xhjiiac0c{~ ƘGi*"۝HV5 abܨ+sc JP1VOҢѻ_GT.xs&GJb\qR!UkH9;#y)0(?_19=.Aچr3M7F8&XzO0$9$!= {| B!"bip?-ʀd͂OGV3B,F_VJC戵r9268“!b,pa #ׅZ&gKڗ[z!>!ƾA)2Eې؆0X1 Mt-7zRF!X<|=@Q6;ri|yS] K|B,b7 hܐȆ?D䆤+mz^QrO֔UHo|s-˝ta<W<e^jcwjΥX`]FC$#ap3Poz (ZXe#)SKڲ֨3_,3E $:Y"׃2Uf?+RdHڠ0Av3t m1n &|ICy.CUm8=_Wute ֩Ą6H[ru_ vz GJ`ςc{YqZ? 빤Kyz-1_LXBzM}"אxKc2Tg7N$R?)Xc~0mYϱS\|zd,ȯYTx@{#>rNE>3[;@< \"[];M*7,U짫?+޵˧Շ hoR?3jF<M¼?n0kV1#S醾(AIڌkeߡ5<ʄp9|f(x ſL/Wf!*=ɧ]^{sD:H*?ՃMM5JCΡ)M>)eT19匍9.Ÿ~!!Q O~ڽ)ݩ@.HnS7~xnA:#px DKs+9>z.Gs5nU,`\v:+=sp?;B&R<5V1q <d9KC4tx )Ӝsa%eBd]3djy0B*F+ lp+T'I*96l^ l[= MvMy^ģ.b{#E^h.AMU5ѻJ4IݮhS$'=#_yE?}?06 5͙) E;M13z1.UW=&טIҺvkɗ}ܪAw$8tL-ØK,e=;2+lZS ~R6ˤMl_ ?叼B .}`0j{e l;W:Ky.@tt)V$0J I>£ DguV9ZECHcķyߎVwmo+PPܡ@Bp mb5PHZ(V\{;p̚ugZw>l}^tRGcU9;rÆM!l-,݀mSuE ^(?@ 0]7ˉCy8pAT"SC0 ӯK'ãrÙju"fWzY'OK.ƖkNTI:&k:Ц0/' [$s.}fgNI6yգk|4&=ޠ~ %"?~A0lvq̴7AEj Rﭙ" lrGw&8dƷM~;fFOAH@iEsEQm-|5pbKc}GH-  A~ˉАሙ PK[߮G\ᳬvd]m R'"D܂]Vq6X ĄG (( u] f,^iTk'Afa ,J Sͮ1@P0 ē2]<vrVQ :^om}GFCa\NH"Y-t=c`$41!a|y|ƻndal|⢘-Y5g8 ‚t|r)植&D񪂇fo(/nҴFmyipYo[;Ju ]_X:^XwM8Wq'yyy%rĔkm('Ha6SF*YPH7rBSJH4sI [}҅3GC+l,N>/}]o3RO0(`kZe,vԦ1|<ha hO,K!+?? i=ʭ\ TB/.EOca qشD7ld$)Ĥ|[ćطAG;-!GM`w8xKiibQ\{sh~iֺNt ˂Innoưm<~[-ExӠ%K44Q&hsMS|a V@ - FA2ÑmsGH="?<=Si;Gbd]dZ,K~ǻw9R=2>=eSV˧; Z$kGV+dtvcU[$u΅pg/{7ODFFɜJ,|lR墛t& ca9'pʃ#.z@qm镆mOip[OxAVeyuv'yO|AK vk&7bFɲVB@s,F#9%BT2%%P:*󤻸/hԉ8NiuԌȲ4IhaSJ.' J$NmVh/wN3oƒc'p.d@Cbm 9!9W[PeHmهbbl7?GFxNNB7JT"e*RQFc-ݛZVN*"n-z/w},-xrWͯ`o3&cRls ;sN,L;?5ſ˔ng`̅x1O-8t(6eZ7ش23oi/DOȫVy%1[.'OPQ3DW:Yf G~ =XqT $ h9ndnH& ~tw7[T<2kYچ(ZTZE ̏bUDCd ~^1c\MK5Z[=GOsi3G\.2ENEOO"&o}ÛXZ|awK$u(';K}Knυdpnfs)^݅ϼZgفi tܙ]T5@P"X KhtbeEpcm5f]P|u䤆7ijg+|O}(4XTKL+\63)SvC)1 _PU' t-lPY5 Dx9 mgBPUμ݄n>wuߦqҹ&/;2|7z&BS!Ď$2|'+!^'M'և?Kd ApIBV!HG_nxQOyx~Sҕ8 GqN?ϟ[oq]QI>EV/`N}AZfkE!ݹ],%zj|Sl&4Ϝ)h_x@TfR*y{Vp҈GQ`&\fjb(VXBTr7(flY#W"u~'~cao Mͳۖ(h }Q?HHlXJ]ԣZ~ )ie樶O2oPbCwBszw3Dr4L}z^+MUZ[v \xQbAMp)8w^ ^ɇë@t`+=¶{g`Ɛ(DvɆ74`ף_7нe]}tGhӮ^AožA_0JE0n˽C0yOYEۺۃIW_HAcEU"&<wgBQs R?B:F4GgrS?dX]IS-GZim.uơMN2jj.ӯO`XZ*AW^<Y ͧqe5g ;{W7$a\蓎 RSou4LsKG.*6^`JqOaֈoW[!K3=|ϩ΍7Vn89%Lh1"?xmkb]!5 Mh1=@RUЩ_5kc6R.赦kev5NÈ@Qљŝ5MzfjۑdbS $&tM|ޜϫx[ͤSt;boP^&dY~Yʪ(.qVI^l+i=Lվ9tv.xG+g,1Zw<!ADL 4 oc9曼ׯgyszca@4Id2G)֯dg\^ſh^g-Tz_8QKm,'E:tP3F7>ao)&j)j>IwÈOV1r'nٱ9GnF:簮 $d۳㟪9MZwaN>[ 0 $ =%6NfayilR nmY vPƖlc42봾nIrEpgRҥR nI,t ?W,,;|MA4BxEe$2~Ixz 6#UG^xŒ$O)Ӊ HIU1$o39y'-R+ĴGE(v3/&b`M+Fem^ =2mNжU|0ר4p֣AY-#Ϗ<ܬBL.-hlR pD6aOD]ph vз٣)n]_@ )/TUZP5\PrWK-=.^/*xU G;"7'TBFˊYy`14bǀNǡ٢[?; CfMft_Ғ;՝+u6bZ1<VA VNEZ/浾[=ҵ~;v~@$<qO}{D@ ^&Cb$2"{ۤg;f_ݝKqH])-G$a ̡7P˓˳aupQlh7dgxߔpdYreno\e)Pq;x:x|1%U)ugg"ƮMusPΪ%Oe ÐԷ('94HN@,pSf#n7L+b>@^qȢqrSxe\{,>rid,x:y`³or㖶1'!"+UtC!{ Wd-}+$Ar@l#15/| =O}tEe ߕ+s~K(d+eۅX.}eR&0 1 h)HLT>J;ʷfjv~4ڜӄUA ˟{g4jڢ^r Lgn4ك+g"P 6>>NMsJ MzH!vīP#vzq'eH8C~4F; k k31lKgsi{6Nrvw7k0:'QOPaMLqfm&"x%L]"Xc.o΁uCUo- _$ܬ[iX\RW̤2pʫȄ *㪗q )h!S>*8W\M'eU<B,roNXi:G*GjjZ=F8ÕKLffTQzS/χ w|%fu7ϖoN^zA .W3i=Ъqoٝ'Zܫ7>xi ,{6&Z MEoAs_\unnn)D}p$5+>@ӟ1jc%@wrӬI; ifS o}4 5+hvDh'G&3ŶL;cuaxkyb S^)`/3RSVTu-xS4z¿T*EjBLW>gΌp`0193o; v **Gőh^ ׶8_ayS>1:>jzm"çmT S'B!L_VJ6[. )lX;F8- _=*'sel !AX]Dž i'C>^ .7bO%0 J01~nR*׷?OM #^'toۊ?bPmf m*K̥;(?hg&UYx;y`#}0@u ?Nvi*mU?@TNɒ 6q>}[W&eUO$}.d߰3h̉PPl9gtșvw B]Jg2Me>[tA%c= 9~II͆!rJx'Q| Y*j 7PQ!06a}eD;P."tB׸1$ϒBYPFk @En%蹎%VJH _W%1urdAH48s{{XS-}*zy  0-@#1(ЬH< 嵦QV7G賐"H I č/֡]Upbe|Ekh{x0'&6 Pͅ>'vCft^SFKؠHvh}Xw9+%ǃq-uv>_V3/\vݟּg,,yc[\T7i_-~rɉVQ̀p.!X-9~_Ux|q|dV< AcnG Tw۪VhS#^#7? hP@(}Fts-V'Ny=Qܶi+Bu~^z)D{gRg͉g]嗊=..03u\ad[da̻]W1:/V6 6k?kS Sug5}t~3*C ƪ?21;;V><7 ? %)xpUsRᣫ ᖔDK:U!q> HͥޘDLt qV }6=澷ӷ78Ɋ'F=d1 I|"߈cxKA'.-S`wuP6|p)Vn ONNBI"!WW‚;{{WXpP}ߢtꌄ$ã&umކO&Mf~eX^X`mm͔'v_IllX»':Do4.:]usǛ\=5%8\ez¯P>a~KLJJ38Jwew! "K ZjoPKPy5NJraWB0xR4sssקllR0oKB[\=8 8=IJLd`zD\GMi;cFB*OL B Bi=u`iv}8?(奃zQ}t˧|l'kd@Vrm8u}UmɩT#3c@$_C,6K'~<&#OB_rS 1p7Z⥌^TPͶk}~{Z#20H?E<Ĭ8+@ ^s{|,FoM1Z8ڝ)z-vケ*ڠzS-o0y7=XM;mc0 $B5=*&~7^V3y;8RmWArZ̲\zOgn D98sqCe2KD"\jnI7 ;444:£!oS+$<,m,|&j|^N#=lTD=yٲJCY9|XZG_V bD?q;ܷ]oJ=eM cB^=~kv}**- tݷ~e~7WK*xL~,׈q=7A8}ɕy t6SI^glEޛG:E5R6ٰm/@[G>z7@(~L~3W_[[eڼce? bpr[^"I44؄hȘ3u:?#VKڣṿv4>ZT\|A[@BLj&Rh^qq*ϩyd>JoyN缗>?ҙGݧ.~Z2ܐ0?9 L(/jlIw|PEk)v>iܩಠd$>XTVYf;/4]ORe=lަ};Ff ʑ|_i+/\M+~< [J>^ĩ83ZԗlŤbb_h::4 /xKD*) m}^9Ta~_f T&VTWW紴q1-++ARR23]XkJWmx 6k "lm3dj+߭zG1:0%Z?OY߼47oK9ċ%d3Zj$/zvv]gzS3Df [ʘ!ýҷ9H$80(H죣Wuľgw ;KG,Lr@"5_rvGEO~mm> 4q]CכΠ92}vr=iŕ-.,*bian+m Rj1QkόI}hy2<; Eפ'_VR=BdHת_/w]s%o -( /Tn)hT 4mB^b{},C ̡Ƿ143MȽ~yѾ|Mrk0=͋c~GcAT0D"KT}5`gJlꅒIW,oJ_ӥnfxsrQd3.Rro:ZHhqLsʍ` w\ 7Kx~ :x5(ws\StzC- azd냯sYj$b><(u٣İens([v{⃊^uaQ1ؾϦӹq /cccL ` ) >͔l9m4c VٶXiF?Zh<pűTupwS>AOOuC1&i:s&"0TleQRATFag#%2ڏ'N R 8k6}?Aѓ)=R#ͽ5R _"&+ R_񯪋:3+ z< A8I]<]qe5pIGS|j[r915BtWmzxvq(/S L9?>>ڶXbo!bǠ˻T5߭-j}C0Ta+@]3 *$Ƕ):0]jK5z'c0S.ӿҘp֢^3ʋ> yZ:/L;A{EzEଯdi {7c)p x ɰ?6:|8m§oQ"$ņDLfir"_{E 0x׽(]xLL[ 9-/f/HYylzz`aꐃa ̑όƼD`@]kk&9;y!*䭿&h EyHLf6;A;Z*60 ]r*u:`Zr^:6h>MpߌoZflԙ^f7J'槺=Eި;En|E)(Ͻ} !()Q.Ω? !|xԓ;AmJ3#Pbw!`e43CgIzS`RC26!<ﰬjG{6W h!8_eX˫qM]oRMnsJ~[J.YuϪ`7^T ALj:Iz3ݚ,:bP-co6U?(+ Brw645󝨎#t}$qDT5i*ў!̗{(^9q--{g]' i=w76 Ve:Кn;נgW$?hWPЩ(+.l %N}lpT =:ZZ o+ĞTK놦,rDݎ)GqˠB=}]%K=DZo&J۩zzC"5G^׵#Ltn`x<|3@6!Ic!lv D9 Vmږ 3gAP[mZΗ%EuPbJ|c^:յ;{ߣ׵%فB0jZq@X`g>xƾ T66=/// )iO-tA}N[;%v`+N dd ZM+\*G!Db L2'% N_NȻ<{V5& LCGf@exj yo\ ۚt*. Hh 1H*jL|v㟆X%"qERɛf/Ld?А: !쿭to\dЀQoOEߪ !0l=ASm^'P55;der7(#r:[_5C),),I,N>jaK}++_@k1E$GYupIi}q&TW`<7]{K;J4L*@ 2K%ВD-7|_B¼^^|񰐐#Nr6Qgn5Sx$, r_>4wlxZJJ!Z%"!IK9>sICjO`)}i ϪÆ,[黈W4lR]r&A_] q 0^0$̑VTШNY-46 _/@3, \9֩H ^52y &—tMOO%}KWZb|s$_6eU #qMmt *-&.7l'\?=Ts/fH݃LVC;3ԩ b@ Î/\[˷J] x[~tX+8H{WůTn]Pң䋢>Eoѷxzci6{pl-{" JzANXN +GA1_llmOJh>~q)'%b} VޫBOcA@Ǽ&R:x88l.# Fv1t{[o&V<:wvvJ5Ɛx.?W4b\Is]iR}HmK86ǺhJ>$x<^Y݀9 -~OUZ]]p\TCO\qEh ͏+glj2 )\S66_pDINI9^hprr&9w|k$ηdJ+nk@J4}Waź|=h O ·|AYYdHYX* ?1QG zme\,'Y3&$sMz':+/ycq,,`gI~ԹP{umEsG1d&mU\TMEI_[UUՀf[ FNJwr#62xF 'Ӧ>F-,A7ۗkEר&>_<:r:v†ҡoқa1H ۞:tTO3a}EZ=yb99gp 6S PimOqOļT\|7զv115iV*C,2=okx>?Do*PkhU3[:am(x|-.Dzol]mS*EDNLɪ U`qvQ=%99|i( pVb8.F^MSޫ˭cNwG':KfYO4W7OJz6aJBybD6rds@mݶ;P8 .iH)P$P w{d&32PeWizli<-ٺEq?Pڅ>9meSJ\!,5ǻd|ux4M/&ti'3f!$$lC$Quaxdy_COoA<qc˛\K"A=ZZU J65ߝA GG/RΫԮ^-[ ~R-`e/o59Hٞf?Lx9'.P:1klփWsjQ'4 @dq:I J|nVGK/ӿm47CmwYlJ7B\ Y9_cbG'$8M@hx{lB**NjTct\ۺO)?EFqn]*x1T+١/nYQMтeˁ}m9*wXjٴ&-օm)͂_E#+˟v{f]w8X\5u~75#b|Ȧ|"UvW-w1_UZĚR=yyvyq54ezmH,YX|$S+9ѮFEB2)Πp|1K.v(~omU}ho`y-{G9Ajѹ)[dW/QyAClo#l&o\Syxas1ԏON[G/ QРT [W20H cGBUWTH(:phW|NJ.aE#:O!2X(y|B`d/u~6u{;V5]`fᄏ8(ԾS o[iSQD,:S8* Llvgs, ܨLİyB@oqU_ь+=ƳEg')o9h ށ EBn<fCoKv;Q8?[yJ;~Ox|'ʢaw 8 MˬkCuvC罸,HH, +B $=K&JQ w}6FbE[õ0`ƸA^55ǫֻoy~g{S+}Sc#/>PoBnn fwܓ/\UX)kM;WUYLݜGYew'WV$Z yN7{A|TwoT7|YZ5v Ŷ= [:Quq:tElWV*b8t3~:p7dH'}w|վ9 d2 `lRM/$dF5Pͬ4\Q^W])yYۿ̵ѡ~QAbnL:Owv[YVQw 8溏#g{"4Mez jB]'WQZ.d2a7B*+Oofi=Ią"OtX`Ѩe܂ffEM_Q)7c8wͫ@n ׬1UmxQϊ8I7!*)#풺A -_仔F**, >GF$VA*<ޘ5g]d-N}PFC߇З*70:,Q=2;zlWȁ [n@T%<.v?R/4 zOY0Pn݌37Bh0lsU7aI#"7D?؉{aNt#86=d(FO쳟xInUyãQR9=M~ṙvvv-= nClŁ*)=Ͼg,bSw\zCCWtnCHad<7Wۙ:F^&w+SW'̔lo]r 'v-"uu_v dA *dmҘzؤs\fK)iFFq=eN֋Hjbх1y4*I4/fݪ괏D^z[?9Tv =KK|-AdfVt#_e=[R1=ls q93#ve`+߻My~ԍY5<0D;[j&EeV)|6. X)- ֨3D'zZe6  %ĆM5<|n!ի욻H2vwpIT9&)+xr?Dn>iԧhUʵne~xh{ IRΗB2oYrq[/>c~Zƚ4[2ΐ.9?-5t Ϭ.ZAXlqԹEl59 e͗fL ]4.qM]3>R[FF޻U )ºw O u mدE_=|E裔g5Aj٬A uoBAO B9%ҝ -%qLkLλJY mqc"~ b_d)Ko~Y"~{y_7lU | 7oF9Pŕf^̥ge AG=H@VOb4W0u$76CEzp["o/$G rvAjHHY4~7Lֳzk_kim%$U?h[@z?zӸ:yDy^=wv(,|G4%[K{s*n]rMkUR.-u=A<2U9(^?gAkmXs8w1yB}T/8K M)kֶ/\ۜtOQ wcH2i?lOY9%:Bo@3OW-w@ Fh7֗tP'Z5uS__XQzF0gZX ;mX;GPcQ;tX+~ K{Ҟ>y^}?a< E_. r !AK CQOnπ9[l F}i'Tp0xa zFi鈟0+o~d( +tMX.Yme t6+Sֺ%x?)s,XV$vD\j`,hbv -fВ.˙UNM061ٮސTK6>;XM.e@L&\Tќ8%4dz/q舳м7AY)JCLN- z1Yq(HC{8e6[>("p:iM1˞q=K2%g%xC,V1kl h y)CŁyْN֜ŝAosy->8IϨǜ~?$:,n~r_yGڎ}T3V[ux9i$03`z^@vAd6`% !`TOtjy8R-\^24!xFik[VHmE{DOzjMrGss$Udb+0y馸nl.U>M v!n(=or^qcaO[%Aw?;TPs d·;ڋg9o\M!8.I wYwwPnR)mhc V3oꁠ$Ăo\ {J.;h͊yq0J%YRR2oc? 'ƹ}P__<03H.t4+eW}WB 'JUwۗTƸ8G{`t3ě~o ]_cJ:7:ozYF" 4ܼWtks ^.hkE^&^;JG\9AD4g],d2בZ2ɞ'o'>ox-a;S{ߧOr*ܕyU'\P 5Y" sp-Fˆ% 8LG}gK?·;65ڔfVYݿ=ٗNyxMGs:N&S ʰ3|]~E/-kw|ZD$Ud~}=3H[$hG lQ:B@2ֈxco_LVIeUleMa7XbUa]W־0dz-F,!qq}?[yK$ܲZ={ܬlC}>Q&uu6WF,b9ap:Z{i0 qOSR^kՆOv}ܾkEXw5 #g)˹# ETKw$ZƷG<|x{V@벩 uT>A1IJJGB!6. M^ &i WvsʅM3v޾Sv~ U^s_rֺwww,V\ 'W-1fY yvea~txsL݃G' tvsa`>_N|xo~&buYZF !E/\][E4]6}*^: ;n;94>nXIןw2y"jB|uږ\>;wt6C/ٖR;{ΜN*^N$4Мg2pCfۓt:{5'S?(W)gb'W0_6 ~NА|IO$mBđ\uN94X@}""V;3Ftz"4̑Kf=>3!;-[k{+Ks94><6ҴEgzBlJo-{3f]@pvߌ =p )Ka-߿Qp8ʴ0Txķ>yGOM.W'LTUq| ;f{> X=<<-՟_그{Nsy;Vg4y^d:1AZ_NR꫺4ݍfۤh䣪Q^wH -yismv;{}/`r"+w\nӰ=>2 5ʈ{g"d^m*3L:TE9w*,Z%R-_zs#S^^jF} ߁~Ԋ?y<BFQ (mmUYb۞' cAމ7/uֱ|RF $BJGR\uBM d/cA%BΞ.{W=?~VkJ/?טΪf3? %p&d{E! }޾d~%]NM'Et[:R}`6GFU|̧6(>,b)a8Ar)'z\zC%>`A75r7u<9Zeki}KABrǁ0gJV9quMO.@.vmwYHcwXNyDMbq FnȑWv~W>2| D')վ)y !2|&QaSK!CE*;6ψ+qN19VmDPI{+$!,쿑US?dz>NL|Cj-TF;SXKu񯭜'kb5 Μ' WќLkڴ+ޓ-m +-dk>~KQ#>f` [ų%KEUE}h"gY~{g,@! Ud'zh=N)'Mk|1lz33ه拟Y嬭^ fT:CzßZ*t6fo*e,o|w~(WEr@X}{wӁdoDհ=ty8.v~}^O4ͩ5c셐bRdR۞e &=b۽^eU _ X-ͅ qe4/n>QC1vL= x[]fǔmml^,.1䱹'#;7 }Cq|A:.Zn~hd*PѸ-ϳhr['$xL犟ab?Lp2̮ ģn2b)5ݣz1-Dښw_S^Αq?af%d/ n#92ūLk zrN!qH=du"?:=R{Jen19ǞECx=' ѸN(͕l[6Iw޻5co[eHT떅kn^="[)?yٹ6Uenpqw,0}z ?Ojzr ߥ\˽Oy ={{N轴Z L tiQF!Mؗ]>4+@5;1nlׁa|gI1)Ro|<8S%1 e\ޯ%rof ѐ~Z1Taٺ~Hx {Pɹi ]@M ґ^rvNɿYj D"'E ^ssCF>[T5,lօ<a"Q#7*h6ʢ!ݩi<@+&4udK$6s_6k?ءVwd5aTnߜ]|zpd)g /ȵoKW36tқzCCͺOpua0"}ưU>˱b#fF&ų x )q[7 ެD)T1/MQDژEP`$f?ax _xsS\J3UJ:O昍E_^?YP`ni8أ?Uh-L稳n[eJ#^4׺2RoXz?UQى|%!PQvx|\y~4AbpZ)}{k'T"qb'=<^宗*iu:OK6Gsg30y4>Wq1j7d |/s+K`㡫! $9Tp;Tu%Wlw@%MScıקц+<YZ?ϱ>XBO;L NEMx憻L2 }BוG5@;j8JR >nw{=q5."1RAagiW<ߚ* cq-YruR uXGX6VaB (G8Gr r s=)MK"fc9p6.d>Ju鲿@KP$rYJxˏoxCګ1QNk.@dR|^n!0SA<{4yJg͑])Msuz0a 58p!Z>3/YZ,( |/` I"kpd;,?-)&b0F\$!FY&isI>{:5ۿWo-4$U cIABķ%lS]۟NSCN )AI^Zm&hAQ+o#W !HQX;g,kG,lL5Xa;A;Gw&D l~b\hI2`ns-,g&ˡ|#Jg2U0550? WC+; CcZl)u8^98%s^kzBS,;'*D)0Mǻ5 <+h 2,1D6 D>,n!*kbE'$ݗ[STh< ͡~IPHH;],ahr$B8z?UH ACuCK9^ɮG3pe [1.d_mםbYH2Sf}XTCb旵!}P}5ey=Wf馼^_GӯFS)"O+ַwg4{Cm m/Os롙7s#luuBS::$Lq~5_8c0Ql0kht*ݩsH{6FXثi}AHM(O"arycɟ~h0dq_pZtZ0Eܮ|ADNWQk~kzGy!&+|2'լͭ'oؕ8yA,aᣔߠtIXQ(}u!n>~kfzDإ&ӆFNu_6|00"& k^%D2o\":CQn;p* (Djvjv4J}uMkdIܶʅ|'_ Q\ǂD4E+Lכwή U(?tpfM(cy߳:' =GΡQo6g)@@WXպ~h q\8m.(ס慆~˯QMB1 6z/l{@}WOQA |xoG8&Ya5h(K];AW΋UhHƖcW8 M`NCze]WH@a M:F選WZBbJt^1e x ,A`² .ĴBӀ EU8y2ٓѯU -T(Y!u:q <ܾqѺ S,So.q $4g$J99!yT$Lm TƬ "10mKZgft7yc$5#/!l b]_@vfQ]^V90:FbM17!vxoM!&aݼ"DcV ,mc>jA.ײadE"OG DvD4t&+oѼ} ?Y;ewV}XO6+6/L"W?쀐B㻢&;{Aqy9S{_,tP3uJEؤN&/է4irWt䦶E%rlW{+KB司m⚓&nlaC" VS[MGP0ߏ%nOK me7;ȏ5$= l3 #.oq$s0H3l˱NA`Юp8#jQY_/H;% ?[ NȖ&&P"pv^cb/0 jwɠyK۶>-KH>=?q'i*ԞE,;mfQڰ~8PM6Z`Y5 NБE:夼^@:ɲ*Z>%w\Xoըr1OU!V;x^wc]|H &|' 8_Vdrk p8l1P%.{EgȤCDLtqDK/SCHpZ32x}$@ Syiq*ҍxE5/OUT3Tz}is9kJ/LI&goTMcJ~ɿ\V6v"nD.e;v t0POXx,gJ#Iu"_C`i\y b \zvNċ"pvDPmTsVHJԣZ593w'և nFd9:َ1(^W }㤕x0 h-3~^qϋe -D^_Sͥfc?eYނBV8LTES$ B`vxxT$)6!u vIge @J:Wt~[4${jS!8q yti2q[@l4 Ò b=&af H:W@ E޽^; mUp)<^8<]wp0 k+}"zv: nb+b+vI)bk3pyD7UXN3e\oa>ʚ)&>,xz)a>=9.mz..hn>yW6*t*:6\l*P~*JϴՁL.R H&XBQ&77K%}:Y]*Quk{m8J߯a$D*ߵ4H~6SZK7 0HtݑUJl! M7?+/pHa'M1ʖ],׳gĤs{?omnD(`{,[?*-%ZT%,~ |R^c#@pU%䰐a e% h}پ9 b L2b*$!rHx1uBֿEyLW,+-d9Y:fCrQ@&faf5ˑvC_O!jwL[ó =״eZEwI_o6Hhз}67C}zmd9ёm#ծ\7įcSԩZЯ̌`:&YgZ 7;2J U4QC?D Gٱr :53 |ŊyK&ϴU T6{OR!n5pot -"k6脑|r*e-]V/mèqQ|9}L'%z+y̐뵇dLwB u $QdUPk}~IDDwlQ3G{^h) u#WA@ʂ;cGm>͗6CJa5#ʟ.q{ .Ѣ)x V% ud؍hƏ#ky{v"#5)OUѰwף_0.K_\jY C¬Σ5{:IL q3xR'X3˔ȨLn|^2*+cGz:G~h:nϝ Z`t=Z(ɗ'N uQyYT p'#Fa6i7ux%n:I&q/%qhf^x]TȄw-\9-&R?Q2q44 w2]A& FnPB  EHv\Sgc5a,%Q+8XN K&!ʾD0lkV qRq&2lGMR^=Tw.Ѯ캚y{WTU}tf-S0`1}FʩN&w:NC0D]rnmq Eϱׁ|o;Fn>pqY.^`0bc9!%2=PU[00+5MdJfF6k$RB'{*AOy!|Gby0;$x>rڷȒ\ㆄki ]`@FB86 >\E2Ifs"W#dB1.3ڤ%$Rր/a/ּݩ7/# *-৕Q)ž9RpBb9ĩc Du cSp.Fa\H9Wfk7d_(X:p7_pD,-~V|'o+"1 H|åg̉a 8CcS<@+a{3_x ;H?š; n(1%C4 3@hNU/Wnr /O楻 j]:.&7r-ct k~lѭf2pf갷evxx);uo^Kr|dozر!ˎf ϑ2r*alI#K3Jcp<-ׅM[uٙBU~a T=e+S䠒il{O)Ca'qUI36-9xOK.nFyE1X\VS 'gvNn>[>R7V;D5۞nOY?$cH,6Jg]ۄWW{nɀ`;Q-z1΁=d;ǘ(Y}IՆfHCpk$ feol~UZ[ -Y~m>Wumh|R;ڑ4Ifgg7d8gI ˬVW V.GA >w۩# _FWujGH{crĪwx`[hN^'Z)TQR $VDQTLMt"V~ N6n]7X=6,nGta#7vnU`:Ӝ93I-07)%엙6\CwE8=bś  S'GqLcwj8Y/vun/OqГ_>M'pqbNrE 6˜ c Ɨ W$=zwʢ>V'?/f@ n "\pdb&-{=콨a+ڋg"܉Nu`3zF".?M?c-C\k#uR}&i2HoJӐBc0I0jDiLd쥐N Ab"ZϘ M!9|&yє3|&:z=d>Cddwفu[cG$WEWG%D&LL<x22TdȔ3Q mMߚ ٚ|zkIIǢĪ蘼E }nXIQnZ&B|6bq:3%=ۨxl^nł ̋ N3֭.HqV“GKk?;Qu[Db2N^sƽ5GNU /~63U ʪ/Q}cPWuf>/8O.?Z ۜ[&<3p >4l/XnpҐ{XyC("$lĶicvYYkKIXŷ'UTi2>y0]|[hYw4V~ipM-Yq3M*C?UpS1}v8Dc 1`a涔BGaq#<]+';%^7zY5HrMTHZC{rռ  oXF^.0Y3L#cd`b61 Y-EB4q3oV; 0,?|NvFγ6kgr'}tVG4-kgbS3'@^fB 89@ kl./q/[)(L" 3׏s| ENLG/i$DLhl~re )3s[%3ˬi41|Ѱ O-b3LZM4c37g))eilRpyκ 7E[V;#̘y3?A3>EE,Ϙ6/$.gIb/br%_G!Yg񙘔OK`p-9)k%g8|J&ÖCBfOv@gΜҥ۷n$7y`*՜,pSfߜwi{ӿ?Ss1ݿO_]ӊE;WC+?|umu nNJWW_:K٣" Y9LfEg[tlY2f12m>;*e?V͑RgXHqƉTxf_ʄǓs8c|VgH,|\&7qOQtL0_wڰgp;5|鄠*3" |vPv/-J2%>;[rc(Իol%,'F'.y>+Y >ˆ4SCmXEݩ/EKrsZl>CK!aw0KP" mq;8:I!$^4όI~ WIi!gRRgƨeԲ:9 G^4Nf >#83D7yM 8-;圱&% \;26"~ȳ_~VRpTxv^a=G3smYR n~b,yw3=}wgF8=;E_ʛgXW3%Q ڰowJb9UKqZT~,rKs6?}6eSjt#,)sduh30e3qZB]4n :884AaDe83yy6ʅ5ƗL35Q_ CF8LӃƅ|uK mXd|o* jb5%(hlδ3d%&&<I&-Los6A`y=m-xgH;f'%ICS`Ml"<½']P.8}?+~Ix9 x/R[Xţ*۷kYuUӏ Ù |惝?ԅ3<΂x7?2m@jҪYጩ9V+8Rʩr(fʘN? þo8J|jH8õ`'z1j&a8? "z+0@ fB#ZR͉$g ,-س+:hEozx-n<7e{,h9-wsF˞x@g;y3gd@_,N_Z^&+`M~-^g b=Ypz~Fȏ>s{jo@~,7uU|@gcWf0o[X+VDSf6&_jUg釬^1*@\Pc&E6Y+ip3vIm'4@Jg\f:}>!L n]؜MqZMh:)hL>s?m$ut^:gtm)~U3"$Did=`"Z.1%QTJ|VՓӎly&nnVӠI< gRd#ET3NiDgl6u1-AE8)Linħa6[G3-_91MiQ N`bJ{I G? 2ѭ('vLm"7eዙq,oEgf3b#3M@&4%8c !p86.a&3, `f  L an;_Ҭ)gxq2#F 쟳3M޴`55N,\'C\m\m׼k L#Lc㻚te`FA tHD'=m [Q.˝eX44h^w}`j>`{ы_{tQ&d-h|q)#+,ڶ_8plD+]y0/J:,.,ݝ6ӕIѨѤ юƨDM\F,jQD"n* ("Ȯ $t;3zj&]5LUOuoop;t)К?H=.? 7+7[n^xK7jy_uƿ}׀+uˍZ@h~/:m|k-͍n7z77! F|r;XtjLGig8n&bB̑7:6jf2}ǭi8AUqG8>? ѣ;6a?:A8= p#Ty['/u89ܺ@!ZJi5h<&MfgVZG:sxiG̥F(>574dVQT4/bzm߂} crtv++ؖ+֍ ]GBJP9*n7}O]ĭf3 ً nw&w>4&m0? {N;<ygPwK31)idn1#(gS1k.6X<33 h"Yk23xMMԜIx,lS:g؜<ǻCr yJ4vU=ٶ f&!E;T.O+~ís#e^Q/UFxRc|ܰN3vdy)fі'Jr8' Yw"81;Qr`EV8J”vkĊrt_5wϡr^+:HnjbFjUHfopY1h}4Oh. ȃ >[A9. /~IX¹J~ʡp>;!?QpPaͩ1#:y~Z&$w!}5bs  (& Xƫ=\5~H3Gh,ƪNmgJWee53U6{))B4 3RTÙنW3q3*q9H)Q g\٤R[Φ4WE-Eɟl)fWTl]Q󛚊irLV\NKqS3fshNfT6&;\l ̔MQ3@m< 9(jSyjL+r⦇aFOlQAՅfjMg3"g9Mn#. LW63rf_x& K"v05E65M+9 M gj,`2d<&9BMr2ՂDTJdl!Se(g,YΈqMX0#Z[-43MT9i*rFM 3ZFa0 2QPc.!Frj8DsYݩq#_K߶|t+ϙ9%_>Md$Dư#y͟L_y:x;-56W9{{H^s`s1@AGz *1ſ=w 7׮-h؛9琢CrC==83pgi}?y7+=a)ȀvgڟŰ!^SFnW]!-f1vyt*JǺ`@]t-/5c$%1*PF67R.^'?iVcBwv g~7W>!pr8#^d-6lU`cx JA$R\GHVߛ2 {R03# .X7iqK;7 3a`OeS WFamJn+gt% B"[ݶK-,L}wCnY ˍ-;cUg.q!)t¢bB: s@5!+aٌ&r1O!>kpqL3sPN~EmRPw(gng*gXQpǖ2S,d }Wl蚑 NKRT  fv~FZH'6@]`7zgy8ԺڣMÕPװOqťVuIŃSY夜hSΡ)dd.uRΨ;̴3q54A>3sSi~:idyhQ*a<+fl?k++ `7 ֤D9Sl,8xREp`&i?q#Ow//M.;uމEfb̡=_cB4YI>Ƴ5SfFo  =z2(TP虠ڠAk7_X~imx%TV/؀WׯZ*/x˕-͌sgO3j0)7.!#GMk~&i I~QDV#n ?ԁ{x Mhnz񁬲GV;5NAc*UT 0#&$[Ijg\/+@L!)D8I+Vj,,N $e&-5pd< )<WsS~M?ʯW0.y%zAcA%B׾ 7%#NML KD-m֦l [;$Ig%!DX@:)#;81a L W n GS:(#mCpdq2P ǵfdq`kA`m,Śr<ր`!$.fzy٫40#^47,wJ4jB(gf6AΨ i6N?ZNܴh!NLvSWZ6n",jXtkXtKXtsXEFSXLCX̹agãk\|2WG^|C92g3V~y5~_T!=9iyEvYga"~4' P-;p . %$LP_3! (<]kpDW` I$9$)Y'BlAJdl#؝q)+<-'.ҳ/sIPYj.[J9f:̼8G* ]JF~5O :@\'vNQ(Q &O3sAye 8_+]C؆tK,J˖h==&9B|9-}>^F:} Kf,ekt!VQcY G XF8;`~0=<=& 솟"ڠifϙuT*JYRۙXrTDsr.JLda̒i[s}S5\[&7@9*?wpl|.hʦU<3x!% gxYmg.QL8m*Esڌl989̀@03#M[6wKw}'OZ`4ghY;n4gYγ'r'\de,MoJB8|Ӏe>@ *RfQZ1Y7l356a0V!gn9{wbc4@>f*[&glrf(g<Lh Mfä^9C1WCYLg,HƁgFNf\$ٌ2b襞4Ggk4ϹjOK"g&&49 MdruL=<7mFNΠ)r3ʙ͘Zn:dSBxHX8hYb3B` X F^j6ӺwXTr+u~-kʙ^DŽnZSSU_0g~\Kgg##7Dlop)292JdbkdU_5qC5+7W}J**jTQ-樤QIG%-(j13ԋ޸{حK.ū~7UX0 %oBh H`'XҒ#rwDeĂX3f%R3S&hvbRܜ$ }Hݤ!ɀ!KsRbFUjsR`3 9*;-J6dAp(Hנ]HciG4qs<ʂ{IF[YhDuCtD Wc7LGMǻ}ˮ[p8xiQ7օjV-XURV/ںzV;@ 1'q)?:+:b}{.~O8 .Z[FbB➱G  `u}2&pB?c\aUZHW,ϙc)4O@TNƿ2͗s6eDw_9c[_wEeJa5T(Zm]2!jR%"ڔmڂH1@,{f>0Uq#PnlrshQpD+`h{m۰]E=%l NܺVaD <HNQNފz^e2Bv҂뉴{cыLHH&EZbڕF@!oH@zPX->C kWDPGSk H z/w'f3bEYnSG5#p H3C6㚦eO gNeҰɐ?YI*_2bj,ֶV3̈?#f"& 5IIr&L(:4&5 ?TӔ&6E93J &gǐS4Vx?gE?*X4\4T,x 303j@ȅ "/L.[%9ސޘޔ~)9rrFKrFkr_%g~MbĬou=9ZJ&uJW)WS2HlA#"Ž e季7vm7g?{Y7cƌ  ?v ?~֗EG~ w?ܱ_ƭ;w}[&nݺM%n} _۷~>.9z}%G>dskj.#}=(~q;mANp8 _ttoݺQw]^s)=Ǿ=ׯN0cN:v?&D_M3X_'.>ѻ/Ͼ~/xO>헽>.vgx>]yO/|\+;,m~{vot+A{:@э;wXrrxnǵ:+M?z;yy5byz\w>4ڹ 8w%j;dsvX瓉~y^'(MLގ>Q}27Ur~7/˽RDzS=|GgWǏ뷦YN g1"V:PK쭽^EPPK:Usťť-Pictures/100000000000022C0000024DD3B1C9DE.pngPNG  IHDR,MAIDATx Gy'Z}F6,4pH xJP65ݟ-dxvX(D`Yc`Y"wc# $Xn6Fƛ!F$8A~`Ysգs̙3ӧ]ߣw=o|{^^ & 31G_)}/AU.T}N?wy1[(8*T.(M$y8( w2B4啯&]%dr^(@A 's/[[fVhV6Ev{M'D~4eoĖuhus/B=N*㎚ !O_xYgu_pw^__qU\ZvIeB[ӊSsCQBhM_N!oģڛV-~'_k4|;{o{>/OܽX+hGˣQ3CI`/+p:0I2޿R[HL(#0(kxu`Ǡi؆ 8mhaOD~OQOMYVPdm| 3+ "&QC-D*do PW_op3G 2iżYlńz8G9i JRHJe<.KD 3R?4Vr{p$dUJS 6^)<*Vrlzb\zWRUM-q{k_F0:3 3m4|f`*'Ixw!/ͼ$y fUWQi*WFxQ)Jafe+k-18^WFUm TDi,?g3%r ffm,d"?*eRx_!B^ʿqĔFiRVGR-m̳pI({K䘃 0sRiQ&`1bL=&jb3".*w-J53)M֨) -ػji3>Ѭ&NeڦrC?hԓS'5|\n|I^?%o}Ug}֢7.gjAl82uA Tn(߀|6,UE5PMMX0`Jr$Z %0XGYB ! Z.$FDF/'T4\CӋ<7reN:+gI~X5 Ocd!sN=,dh# QADp-W%?Q1UZ2250/&ө8ZADF)2+ v:LlhfJͷ<\dr LmZ!ѱpm93j/~9@h?g~/ˑ?(k"8Y%<~,i, P.s / ^߽ݻ>[|?|ɿuM-@Œ_NuI_8v7*Afٙʍ+2V'բ(Qz|Ndӣ65JJ eiXA9\h>J 9"XkCaHI=!U)$& ̡Qd NB(YudVIlNQ\Sh Ǩ+3*ƐQ`E_!e40ʩ1>^^נsj5GT'h Գ8 T `Q7j:>BksAYE05J5PA}.Ze\{Ai&zꪮ ,@:xz9XLXo 48']ȵuJuUcEV2S bVa⎽n95$$fЫYTt-7.}A]Xa3f%&Ύ|f 3Н &c@"wK/w%o.o57zt{o,L^DH@oցLt ,|||&֊~{mҷoٻq#g[<$t(7_z뷽aYs~λfɋ_W7oy|ZV|gyqnycG|Fz댧1oTU?.?Lc87c%|~1eeWlpGL(g}ni+@-Q #Fe]$zWE]S'>7iSC0i#",ehԮF}\ʟF#95ސk̤ eWnD>)G.Ʊo-27}h(-,FIBHq*{XPȑ)$VfM-YrPRv6Mp:ISIptiCvRYCrZEIY3A,R7YU~hPK\4 I[V+/S 599_k)I9TXCR,ګ.15G$6 l ;,9GG~J$ST}\ ^%+B1um oJ\jΐ ja5 }2Acfj!T=dTB, BuFfB ̪w F:I&h2>0=iO&EOlYZ.v`RxRG R`m傋Wm==J1سI``Rq]01@>NOihgEbdTR-b٢vNzyj:BAj kc01THgĩkd@FJ9$T8RP[e)J p.UǍ7+Ϻ:{hR*_]p0u!'!?_3_=]};y L8`]Ca&RCg൓` )ElɿruxW>L9j5Κ5+'9ΑD/_b-!=_.2p5w߸o-m*T'C=>{8ٯzurZ!jh+F6~499&ggZKkσ,0hcPZx94Bq_;swlW@tȚRZ $qхZ oO]{[?㯾oΟ}朳{x*'+ƒ]vX7RZ775S Mic"eRC9FY+7s tv(Àma}rŋ,3ml_jg;S krGJnFBʅeVl |AC X1NƔO" L1; -!\g S6b}jy/%rEW2,QxI#IEL 6`5)1qmĘy#hXEPHKU,Te=BA) vı4VȃT¥* V*1T*B-|maeSwKpkH@x'8L; PS+饖 \["ucSluJncNWj TMNE("===vm8jUbii#cTM+dQUeo#{o|{I_@!2QV\9lfa U:F)@^R\ξҿ?zTar=xg,~o8SBg?~w??{nW_忶AQ Mnfwe%{/oTc?{_o1m㦋q吻8Zn܁΂ʍ[I4Qt0OAQd#k/bt/p2?1;7SiiQ^o"r¶RpYn=DN# r_ vsOKUZ܉<S딀4rOUHLk 0N-!}$Uiq\bZv:eY?>DfDFwҜa ź"ڨ4cjSoÐq|qggT"atPBVF,QD %p6Vb)"؟N`Q3V51N10*m5A!t8FcW4d+F3d~H, 8P ;Z1Z$dгVhϢYɴU H%qJ==q H`JZUi h J5(KF10Ҡbm#aRkj'G?nYzA0_r["4"3\w7{4hEG ڡ N;پ_~NxWhT**w%?ڷ]{p//}g+Q}>4Ƶu˙s.~9mE5h!ȡȆwsO_saw=z?s v^Qd)ˌ`v;əX4;t'M,/4Ț` <5LiC@S.S3ܾΖrwnv ՓO6Ad:Mɾ^L+bKN\#[Sްa nx@-T##@<W*1:iq[-2d nq [J\YWxY'TpUGf1:&\3~6`Ű.٥2"hOz](X&Xc'/4`}c{yj'Gm8p(Ytk Y4X)Щ[IGꠙ.ѧ(^C<wxh\U}z LY ơ"/%ZcRv~E*T4V}f:$d)1)f$fj -c3eW=pikŗO}΅??p'YFA˵.<^mLts~nN\ǐ"y9gj?~?̟k W?g*3tOmn[dosxn=֬ܺoX{'h6_jEV^;>u.%QnՁ4U'T&ހmt mlB° f(Ém$ ꗻ˧/v5}k`ckˡ1WIw4:[ǦPラb0H].BmѦ<IU^_O/RDǭ<_sSy|u4V>BƩ=#k h/DAT:' ?k56k Q=Au[=@ }k(i "T&Ǒ} sUJ!W.p:,‰cfT ]M:WzXS56 Q]b6ZI oҬ&vOYy0D5vap2] \G9#ŀ;ZBMfP}"*9צ7f0U7\h][D/|{:Ψ-yNuK25_|R 0w9wD ?ipyVOOn tV,>͕<iVY"5kv±u5ŭZZJ-xAV chWX33/GY.Q"K`E)E?cr2N@wt\Os+c L=L:h>C)퓩0B 2\PE'Oíh8&- @+ibl)*W.󵚲B .EE2jH*17c.]+ Q6{v$^{O΅R\5TpqdpxbWӋ֜qQ)).!0k}SE>D\;fO 6opz! vרld 9ڑ@n=b}y )ToZO@I1`UZ<,q!$;.c0 dDԒ8U~<1 ="%# cp8T ,l@8lCf#>kvgc@Qk _;Vz\?r¹MAs tx5NP(u7OW┛ #)vR[ $z\ n"Dl,V*RHt])bL:WL7cb8$FqӤ4u]D8d0g)ѯ株gTkbmŚy T2ƌL]M1؆8k`giy͆LQk V:E'JHKZ.E\Wy1#(+M=[*1(9b]](TǬi0eBg@EŖũ񰥪;z'Mycf*#ivmla}@!PHfoVra2G*7E 0R"QiqKe44qd!Sv)63N+N GUT*X]RmSM2T9Jr*+xwvk\oTǰZI魞^h4Bw#JF_O <%0LE\K ,;47w{$%'!V tr\jDҁL(PrCTR^S$iu )Aq\d O]#M,0g҄cyy#ww'7UEV]Eƍ¬R02> icZ{PڋʈPXqi\+CޱJ [uZ#3pUe#4>CfKjKM=28dR3N#CjBm-1K٩ PV,ٰ$1VL1G Gi^khՃs祶LOjq,]%k0>f߽CUo!7[T8_g&o#T7h;i:T\WD wjYnD""p-kVa喁 >T+>:@0(ڝ8MUZ( 4;^mXk dU>H՜%Cr?"{%}U"+Ǐ)^<4 nt01w6Nb=Y; <vշXKۦ&ƭ6䪺EEH;塴Y\(zcםUO-T[8ov('qOXk3q㵑'b@MY^m%b뵪2+I+*lDZVjW"?K0EPB DA0Tu1ѬFְWne( ]&̓R[QqGX*c\:+&\@HvYGr9tnY2kQ~U*L8ԙ|n&4y.oB6c,R?vsbd{wA)?Ԋ\7D!4 ?bm S>w5-nj\}F6U%[ZTʸ:Uӹ>/&9pC5 +"FiU*V: Nj5E<S`GGc,# u\WT=N2FRR6Ԉt i]Jt(Pt\,?Sv<P fCBqG Rd9);(Z-K&B-YMQ}?2][uFzԅ#ʭe)U.&=v>T#:YaOHn)/9U ]_*! J ~gO:5fϞ׼fժUk!惄@ i~x+!>"L 6?^ӱ3{B~*Wb3έ߆>ym#W}zEr?qź?g^Bݲqf N _zLKs0G?w]~iͦO|aͥ]H+PgMSMrCGSg;:v=44V}8x--+vl&w݊|rba.Y$/P6޼V\74-6Jc2t*ծ`+JI㵨yj;/c [,km5WݰsKypj͟?V{+4HYA  Ƌ/2xd^I6ا?}ѧ7~k?{Wo +{|~"7CvK.om>pߋ^+Cg}~+CL2c3/aac-\&ΗϽIvj] &uWyxOknlKpR*txr'pP4VYXv :6ܓzbnYk^Td9!{b~"T|`ZKC;fǞ8QSd7!٪,u'֥ǟn1vye~0Ec4@ oEz=n8giY_#LʠгϿv2+"U+)3뫗Y^֟^w߽S_Mo/=}~sϼw#{ƲG-z'Q[Fv[Qh+!>\6犹V+_:뮘;G}G zs@z۪97}f7Jsb뮘Nv>pe)&_n]#eW̝[n_[l|&j[*c0E!3OJ!ʜ|/X% IC-œ)OPq>^wC"*tA1T@ L-ik BE%AdP' A;@ Lfh$Fε%>"@81 LxI'\;@  Ǐ⋿Nu]K.DHK}̄Y!BO >Ϯ\rS]^-bKI !@#r-'?o֐6М9sn ((1B#!D ^H e@ L*(j+ 鞥^1W-wHnw/25~{6(3ǟWnxaċuEbsʪ57'(Y(;xՊmngۆcT}M7O>w1?6}r{E75: 'j{蝷=/75׋K-ZYZ9-\vtKKj'O3~͙s(j\D4V} fK,ν/]w2eݳmbҠKd:)÷/'c.I_U'U~Ś/M0)p=pŜs'5u;]bhg'R}Պy! 4GCǼ*5(viCжoh4^|*)G{nGw`/D4.v/%_~8]7t_:p4.Ư⅕>~.Sc QH#Lj&ǗK]OE^7)8xRW.מc%9dl'cN5ikZ;_B: Jխ:as惽.ʞ.}+7cN]? (RЃnu_p떍]1w|ժUybT}׾m/M1`Ԯ Lk{, L,ϥ2ikZC+|2cp>\Kv \6G%ql\٨`Pݛ`܋Oxqs)@Ѝ&+szW{0`8RRz^FUmjt%W_7vA_ץ@0Z"3?QLr7nz?=ko/~=ͯ-K}s-U PbB{ܪWnRR1Z!d8կŻew"tפɯkUH64t]4q f[e}iZ8cbg* *>(Y˾UG{hmQ=xSUJ}>_)^wA|o DqZ#i .Le%&O1GJ獤~<4bL !B%A`LTP0}M(`={)zp6 My1)?u- %dUJ,!@wLSSN@6@0000p/Tץ5.Y[F(GXڞ,ᴑpZ .g?r Lu]Z^uv/T@ r'?ɏMq}i͙3n JB@ i:{_@ !DA @ @ g^j-!JA@5@%HyIa=y0(P+wBDB@  Ø @w\&2TO]r3۷o5]|-\6LY#v}S/| &i=\gf+-Үɓv^S9-F7M&ْQ6܉}9{X5MNl#y&fdNz. CLWHSyrb0n4/~ꩧJջVnYMLvwBiV%MAwlpHh6R}A%ZxSOm͗m[ƷaXtcdw,Z23UWU;XBʾw{c1|  kݲWUj%d÷¸{~"5 rɓڼtUVpF*Qf%,Vf ~*υ?3ToW>J]G0sãpEFt ÇUՋ^s &7kΥ#2L2\><^\G#ύЌUPvUm;\\r$\x3sjiBDuLl #*}| m9Uk4ЪSzwpC;f4k`GV.,70QKM݇*՞HW/Jݤ$śeYaf\;Cec_C@IQx9S">VlZ{M]q:`Te2^B6ڼ%pЭټd%=w\ Z--]"tKhO?hJEbGGGBsS\ gf 5&?^Oױs>cU4;]°Mkoi0g7߭f y$@dpm ^~gd9gSr8x[%qwu4Brok5kX^p *?:&G\Tz}|Cױֽ:sfj>Q D8'ıVţvU&EJ%5Zm L ๘㱓bQ%hl\U9YM)J ,G<}PE(:r0 pϗ@ ENM}@[L  q*:d@ z x (DC^YX |Y-oU9O*| \e8Lmj/^cmk9ZΔ$.yg4ZLw.}ݩf,n$vu;u亾K8;sֶbnB-\e8z,vg\Ug¤c]Fw'n׮5K3j4EW),f1 7( vtIK|ϧ{5mՐ5`ȃ Lj۶=iƯN SPY6hΚqfJ5<|Cւ ǹ_pe&:=}z7*a0.LL; [Ö\-^8nL/4aV092)o x[pEl{+>_Tb/3q8 k藞| wa˷bf7s6 %=_~U܌+)@*\U8}rj=qhֵ~vg2̈́ ̈́ pVvQATO1>qZ)n<%L-9Ckfo9t3~3 +Kw2S+tHJEwrZ,}^,U\2^͙XԔr>rf3<:ϸo&6tz ݈!VsmC[m 8[Bv[rf3To޼;!T+ϡ[beYpd/؁Һ/rKϏ >?*ygh ,M@'/ůMz9K.2ޑ-s8 y|;M嶘'43N!gcK/ɹ]ӲӶVп*jčR;K d=p~7ك]9W^bzثss9#cz,4n+%VfU oqg߫^WZ*Ly/\9({Zn1m^ٵxuƫmT5Ei5 U^ 4=[T4k2;an3\9حtVaev>;i+hW &T{FYi?>Ŵ];c^t/?&mb&ZsW1i:6[`$L6E@hi;jLB@ TӍ.@  qה7Ha2~7HM`x{H a~7"w"Bt` @ L"$ID;&:N &Oڝf,~S =ktXù)Ax34\3'ݹ؇V s|τn^7 #Ā@5`1X@,ړyPo ku*cѩ2:n171pz0{p9Ϩ>Jk>K iUHHBH~jCwM,=`.% X02.8SwK&]Pa|rTxUjX@W٦'y!8NWp0ԕq9π>,[z ݈(a[i|τ@x2NՀ:#ΈE_Yc7}`ٝvm]zz(>O3 nٖ5c/[:.A.,oǻ6=nW6اr!}[\Mu&Iz4i:{&L(6BG @bnuE//|F]e\fn*4lcZ^,uNx=;-dTp Cbw.)0qD)uA5:rM*E5LqS.Npٝ}T{&t m" 6vOMG$tdM.E5иO!=Aǵ8V6 1KxNh{0jڐ 8F҇@ =@%D BO(l@ ΍MH%8@ ">7jwܴAĢ=UA> *ZZ۟c]V4>w{q0AI/3Q@,ĢmgiN(۾ f%1M>.ÛFpRCǛ1ݴ{ p7]ZPg}XEؼChY]f߽G/wÚeFFl`.ZE}N{K53Nz}1;m.k6Cif7+!b&&pC0X˅:k֕V}_)˛-p ot` ʂ1 qBхtIfVIQ3K3cyC~O]KXE-p@΁:{ uSfT5<:^s8ϖv2 o;=hlS@} e!ڬ$h4[;O#BPYB@ (xxO@ 36>j߯J !#j%z@ &G q^^^9bў*T _PR!c 禴6Q& kԡ43zf@R-p|7 XE2*swgSxXYM415_>ئ3z$H3./:CĢM,Ыg>ؒ5Z`cO1 r[kryM2n,.5g13BI Bn6hW؞BԽFg/᭛/ nj+h{Gބqybrx1znOKs6UuO:>sg4W"sXUֶ)Eivhg׭#x]z,<;}.gvL%k]CZ=CzGCwugE5)k5O&qˢm_i_DŽE5и &L8g Wxq.|!@ T"+j@ L:m!$0RE W$0ţ}!G iY8&DD*EtڰhCeM M~*FWG3LK=yy]ޥT'  ]R96oה}WLzz[2i?Ox{۵HW;eE!5M9/Tx=+ ^g::wv9vOX%v0Msi|BʍNpnT e\΍sLaVrx' <45r 4#lL2}8]_3 DE',ڲm*sݱ0 N`nTD*s{=߬Zϱ=6m&qxa?O2x+;'^iTm..4ewhrWۍ#ힱhr 0t ӶA͹^?-瘂bw;2%8}{fPUgw*3\޻SvOXG|'_P>.MQet1[{\z>sY;޻ 1]?x {M2qHa\3:Iv$K,AWxwyILmFKr=-X)o{WX{5 }>H'3\}nB b>љ9iUNÙ9 }LkvpW ?ECGCUeFZ?hL>@l(S#wXt@ m!/r80@ 3{ M%G iɇZL=!bѮbў@Sl*or!w&%vtni͜~v3_༯AL;XE@,kݟN>ngiB͝ خ{{l"QS=xstdf[dgvo\ۿR-KUGF(vxEXIzh/_y`/"rgi|f>'tvsE};<1Iwu5_[~C(nmT~z,윞(z3:W,ZfiTxWX[%d>siT48\MZ$ Qb&g,@ֲ\VHԊ)w YgK89Nuw7I vUY[^ePwiHA+K זώ0`ClwWXؐhi\-I'O8 qYhh}-W lʝfOwo=0 =q]Wq<wʖ[ ٱ+ZW솚ҫB6Z|PHZDLD򊴄F^o0,!b&`,ڰvwl 379t;u6ދs{aB~͒|wĵZ[0(Q5l4Y6(WV`Wҝ߹5[K6x˾+` | %<1!i4~/a3F=Av$XhVE~ n&4Xtk,3Qߡ+S| !H9x Cm Ihv @۫%w+ 52SNJ|qR4?uS<4% ĢM Q߸瓀.jMD 2@ IY#9K+h jQ(JafBRDjWHTHV18gϚ}i\Q㹜5bdVR|o͝^$\Y>O3At68R&Yg$MOkBuQvh'cWdn!dK۱B!wӷ]N^ rvjwz=֌S=>'"˽/[9@bTWnҬ^s˹|WEIc{K([=9_ed;C<̈́>G on=YSNqܶEKlwΝ /wԶmCPJ ٯG{lg ؕ"{;0^U8}KXpyJ\M׿7=)ìʸg4z |~7e>O326:.8#pS{B[,ڝ+Sۤҵa6.˻wdaV]}1D+ /sCW´+EE"ԫ LR o.|IiuKpkμ< 3ʡy ){uL55eqG:cѮOKnqC: e<8Z~ǡswg{aej`A"2Zq' zU.l }jo{RJ݃%ͤ \{uwK̩)\T;eѮxK+ӽd\v>2[Uz ?m`VodA _Btrfޜj֮6 OJɸUh<̈́P=VU p(:zwg?J#ei)rG5v pLziZ46@ xNBvkd=꟎w@Xpj/="i|B_J8@ L! aX5OE LrB`B/ehO2z̢mZo`(SmWYz bv+Gl܄sĩnb>=Y 4#vZrh+do5 otn2AlM1&'D,څN[+ %AxNC͢ hy<*0[fBg}Hl܅v7"m36z~]V2&؊f\]:ظ0PBHΏE;ӘEۭ&܊~n:b/ظ pwPu)D,ĢmؔluwwG@])я0cuqtBsظظs6hl:eG01[{:CFlv7aȌ!שC QO?7TYUS֞iJG=MM }c@ \\#H&"B/A,@ "B B3E:urL-{ǙR'Bp *2d=1uĢVX w>pKӖE[tW[I't3IOg6R)ݹ 8ZnVw{c0[8΃ mb&L62 C! ߽ydz|5`[ \څSƙz5!ݎV/.s9ss%J{,.OXEX{ x]:4E B|E t8ԅSș@b۰dâ,ܰ)t\^ %=Owr"9hwb&tB"ud \־"2XJޖ*> p]l,;vr͓aQN.8U$mb&@ʠ$IGE) 5,N6 2s.qLSș}=S.w76Yd8`~#rH1%dq/ĢM,Ģ=qc򘶗h;eU!\1@Wa a ^QAr疤>uy>bѮ.b&t$M,,i -P&6' mh B萛sBӔzV@ I*rĘ@ A"I1O%D Y/ !@  o@ zBSB@'9-K,Ģ]SY%;Q]^qT:.RT}!D,ĢC7X[؊ Xw.qT\L!>aKX m5=JӶ_V҃-U%G5qT P, "& nhG0OɬsyZ3mgK҉8 mqqos) !b.hg 'ʢ]MqHՂiۛ-K'jU&TRW7L"mbўlmC,VKu\ti۩)JQMՄʈ8'h 6hO6v56%PO\:qT#xdNI6hNG58 .Ǩ8bѮiZm@4MRfzzC:MgΖX}Vf6i1c=𩏴z%ԖWwOGyuS?8qEZ,shk2w=piS.vlWdAym9Y{'/Εp*QyH[NXcO;yN!pOA㭯uzB=Lh67榭/FSr'Ɨ&frXRb/i<Ԣ̓fM<T BP*8Bء ! MwI)#R 5! NGudjHI<( {AcOuRhկZ2am$Ufׯ;)\|-Ǣz;m4&iLҐGP!_E^t T\jТ]<;95t֕+Gٛ%q{wW\q;0tyעy+rVN_8Ս Swir~7kZu=ٙ]6I4&iȡ釄t195IdҴE{r:c٣Kxg|Ws;5K?B%[ Q<\«&O_WLt8ӣ{,JIgX4&iL6sLҐi4IDžnHQ`@Ù*P:;ᶾ9q喸18rD<"ŝiKtrőQaP u痖hx>w}yϷ˙=6I$ y~n{S/`= 5lέumwfO4E%8w7g*ꝑ2gփ܋.Sv!wd4&i&67hh=Y5=\Ԣ 0; -7Iu02TQ(ά bt4h'[G E^^ɠPE"~``/z=iqT&=kkz̜i&yv^Ug= "nN2 K;,A= 5PaiKC@PqItjt{9@;hkOo=+)|(![ZEvgI^jT9vwBa L{`Ѿ}46 Sn m.)0[[0[C xv`g퀹nkg+ZIݽgdJRF{;>+zi@ N ^\mc8~2Eyot֫|>7y1[c1]r2w\`ceЪZd\E9>ۓZ =3>l*ƳO){w vjr-hkPV;lVY'vŭscX'Rz]>^mg~3{ 8ť7z8GBW=ߓ%|vL֘FL[ <WQzv2WԢ]`Ŗ.͹L2NqyU]{8&NGȽ 8G'5>4Ia6`:P'2qyN3m0Aմh67a`6`:H$SU2i~2'TjZjSXE"Q~Gu_+-0@%~'vH~ NLvF_^[@O`^%է?yCμ$M!jjT3@:"vQ-h҇qwe`ㆅ<*l: ' -EɜcJCʇ8ظ7,.(:9M\X{8s4v;XO8SOޟu][UugBqcV!u6nh+2e)A(2γAv, p8N9u{"t|`>*\'vC`N lظ vѷA "=b!=ha2M[USCܺn6; c)F޼6:7_qc 0 BπF-O=qE$qG^c/q7gǥ4h/3Uśq}vkqc $9o !Yn2!ѸEbv.qޫL&.?>Lظqc֢oAaBnZԢ/vܢ,lK 6n6n(/2u*gI57dzKubEU[&8qP:y)dZC?8Ugj0Er<; !Ag .ÂY3~]8J`bP<_|> 8qTmg B Z'oqab __G5@if B Zg'g>" caK8qTf BM['3֙=دگ j!f BZi̞l~]~ݷDQ 0uNѳ-ڹm)d_ONipT*FMfI-~]18 8a%l,h,.W^BMZ>ǥ4+=y9N~.ΗY`Ƣ |"q7\q ekWQg2ߺ;)PwE{(,Kt] *s5-͂E-`цC?'Bٳў >%AvjAH?uOH:NE-1AzrMz! ::E^n5]$h1{RaCPm-[z@=mhMe^m<[&匵o~$/Pf*1pI)U2:;Y[BmhWGXx ss3YSW[GO"Gt2־>-& qqZ@ȵԢ}~OkiP-+Wn󩏾z EΙ]-YUԚJۯ'9vc= qm[JZh]*x, m ~76m%Zj~.Rú9}ʼnm3{*1[_odo n {c=k߬K٦kjc1Օ?7@R<;(NʒMv[7OTWuFUqfwKٺy|/|Ӂ:ܫ=?7~nRiE[_N;3UgzEn2fN}pއwo9Y߳vT/4j]fuΫ LP|O\c1؊?74lA~bM4wwYĽ=[:*iroO=G`Tμ>WX\ssC#c5-^2dssC#4VZ2aUة!B`@M ZBt@\jEZ5`ўm6[ ֽڪc`цF5Ԣ]/s~W[ȣE6mXf B-h|Ns̙ys`ƢEقP-ړ}'oL.3g mz,*,r`цEÏ0T(Ļ[kvsg:cv9s綳^\hcXa Uu{n72\jE{yF}f"#EvmX"|{^$մh/#X X X|u^*񢰪GbU薐zms8v2kZIY'yY ٟNeL+O$=:{HjgkFgkL:dϖq{59@R>-M!_;vv3G-ˇwx{OXsFꁵZ7?1IVszZ<$-]Q=V.TFkkj;k:"#.3^Unۯ nL83ؼJ1[w܊ZqlbY#zsM.Ly&i\2Đ9r^/^uulTmÜlȾ*yA8 BStʭE%AŻtpό1@˓/\*V:ڹmLyL'+[97Z TeR{!{W{x.xW&hE_y-W,uEBDZws)96hYu8U v*>=E!P!@MAܿpPa6]$h IKۓR~ 5apxBhO*]8}鎛=a.ט2`nU30l°,XhpyƺU/bSΛ3kNg6VH1wBXhkho]vg;91.B6Z]g6l_*2Tw!\yfZ6~~ 33[¢mh;VϢrT7Xi_Ì41D%kDZ32e5j H0BO5 M Vb=qY6zU/ACQHPA rlKHҭF K&-!ҿ/3h EqKHaaU%% #n8"ғډN~UG j⏟S|dZQc&yOޘ\fg:ئ]96OT_U:`Z Ukmw:k~jȌPFZ%+ڂl.ssrc`N&zm>?7=sIn]ukl5Vc<])ۯ2魨E uxF}"clie^giE;;:d唊wa6`PaԱQǗ&4hW?F{e,KϒۦGR^X X6+S3B8U=Z/Ƕ~RD"&A CQ"@a \Z\v<|sUqƌGu{g+>l'hogX[u-yXN=| K B3<#DŽmSFYc=ѦCaÆɄB;PE%q{wW\qƁ"ǺM95>l|aU0 j1+j֟n9/o F{yzlyJ{%{>?R Cuo{g6lXB<c:q1 ?-"ћ,sQ!E)9ޞm8mZEwyL[hE-G6>#3.?B6lٰ$0#:vY-d Qy$XU(&vˉg5%S޶oƙ3b|?[ }t ,+kўb"g{8)ٰDH/$|{55MXM2z)pfpfe$x_wЭޡCk~o(UjVXfXbTye|͗y**u|'PNsк]8Dkq*05[DXUTZ[L2cN FFόI^  .;:0R&F0j?dU!ۂ!OoQy{ܴ,ERHP۸hx6)|Xv蔟[]_ W62SA+i6Tbo^MTTڔ^Iیxj,(CAhZ+1@Lpw۔)O&j l"E;< ЧxsǼsNE)l&^1hhǦJ l9Α"dkW6EQzl E{T b:y|/sjPwyr㲫xjkj1B٫i.LzphjxaQC TC B+S #B8{Fh @c D kFRZiNg`fO{-~*z1BBʜyߜD䅉" ,cR޽mE)ub%З7ϵl?)7t%<UH]<ʜy|`0[0FaiݯF ߳amlmk9on{+W$sw6֛Tĕ+Gfߕr7o^w] IZ mƙܫwMl8st{ydZB#ml92\Nssד6]QJ:orutyϱYL0/L\<[wY|ϣEǍ8ɬ}Ly:00IoV{i|:'U-_:sؓM;۽[GQp~Up^s,_dLȫ$3|BXK=-1S g6C#M77;=^"W/up&woBUGŮQ=n]8fǫ KgÜ\۶rٽ׸s#Y?GǑW?1 mǪ,.rfkc.#c"@]2z|G{Wg5X8GB?:f܀60&ܢ]%7[dzX00gUtZսRp@c $@=qimM!ZBXh1|yȐ; "E2!R;a[a/8!,j`nʢ]rڦܐmߌhkh7j66Æ6fN356=jƇhc^sb Yq¢XE;͂[;^~r ۃEƢ]1 & cUmt=P ԏ7~3:@aUdžf8:DۂEsXlv_wU9j[k,3eBe-;'fb5kX hvmYdΣc ,`ƢN"ΓxX҂Evsٔsvguw{X㱆%$0 x^bv¢٦*5X1ڂ {]#/¢ ,7zcmc Kdâ`Ep?跄 A^R8h'25qCh饗j.04! @H)At>R3/BP%ZA^E! ON_l_ Hu._h oBzm8h1^?]o?ԟK?"> ѧ~}Ͼ/~gO>~;} BEh-O~Š@Kn}t>ugn|So=3'~a^Kj A?6s$Sh;f쏿?҄~1u>AϾMS[OG_6}#'w?gl[k\hsvP?)I5m~酉;{Oy[qTO'@H5Z x BD h+ o}UW^}!ED_==ĵFYoz{o,)6Q 8h9Q(n0|3?7%A w-'[9w|'x*ߏ0BZNHSE֘@{ZɱAŃH?>]~z`¯|;?$>od7x{v~c曊#CKڅ @gh@wqtFyw`o8>?d_~Gp]2]Qo~o}BqH bX t=n H|[3{\̙;P7cFn:|M:E|+ƛ߷tXRTY}30hQ 0&|?JKZ>LiNt|No>z_?_H'$qZH럽ȉ9h۠xYh+ݗo=Q;a 1@׮G?~轿Ο*߿9Uw@@2>7>˟9*c:2{ X _$h @4F'D(t>t'zЄPt?ꋯvVx*2$Dir*G3g|ߗR++ԯqWɝlbq-#5V?0'q36Z 3C)IF&^ԱO|pM/wރkS˯y_>zr1ӛr<㷉Fjzo&Nˍ.0{oꫯ@ |=*6EX[< :iN^ZH*+i&q0`(M, uPG(eGOۡo)L؛ÍƱqfߔ_#~.(;W˓hlGǣ~_+椱_h]Z$rmLb6k&˥7ɑ/(_|A8\H_s+BkXU<=X]HשmoI4F\!$NX^U0Q"\E" ]0CP-h!P)'Y=v'O,׌O?8Nt8>%؛dܖO]B|zwى-QTI%%S`>S?ɥzḊX#/72\9؋a[A2DIKUۯʧ>@}l~#}zwEє2`BKY9U4;Dz{ Uۧ]Vz'u[xF١N')tL4C}j*ӑֱG#+xIzM'fҢ|${1fCa͈4:QsIB~cq2gFqá44uz\w8?84˭]&{^VDžj)RT/b#u_[M,MH163|1Ws >=#IAֽnTs~аmc _o—͕iǯr{A૪O&4TpdM?b SF׸m-[ X?䫦=6ǭ]4h/Vzp,(ܛ]n[{~[%#ji?Vz-iㅳ&n񫯾.Hh&ϛUW_إ$sw<m ˧5z'q,Y5dGNJ{D\;OR}vW̺ϪNZ%n=J;?4}iQd/L0ờcnyMڮ;Իa#t2V~t$Rs׆-|wɷ{T\u4)n}DAoϗ6׆I{}A"#?kNhd֚}j=hŬׯLH|f9!tm_&fܾC:-\|P]h=܇-Ec'*=vlw㇌Eg^՟L8e&J.8\9Xh[YQżvu9 TuTf>?&Lz5}5A PKÆ%oPK: content.xml}rF~uH"(Rw<:7[Gx(@ O/̬ (t#@UVVVV?}E/v:ł~zOo[g;_?gn؟Ya;(؋/g⋤NX ߺП7q2+No'!2>yUv#gVe|>AXOA{݋QL.lf0;mUWMOO6N;v-ĩ >L=UF8])~5U z8n=twN2Z'g#qչ 7L~ T|P{pp柵gKE^"WeH:mxL#"/tgp.?޿IV?8q3n•#6 D!fPanu,QM#EK'wEi%Y+ a"_t|9Dy`B ǢCAw s)oNq[}1[5p岾_s?#$/v^Cv!{<| bĉn^藌b[@i\26>c'([g_\ _[8 ϶,1]G&^:kڎrA w"U]ce _?=d>?9}~ܩ}~x^c{ZsTS[3iEg'0g)+_\l{/;IMI]B-o݌yh &[m OTmOWuΌn?EKp|o賀 (ߦq t0qgac=8ۃlGFd+qmks#?mA[sٙ=۞lc'|{' = %s=C0Ql#@U]˕*tB㉽88KWs--k^7c=4XZԖɇ_K*+Qј龭eZ{ĉf"{sZ=6#C`ۜalkv{> s=_R4uNlEC2J+9.8@/v0I'~ٛk:޺ n-)#J8лNz4f^KyFgWzD 6h- QM/7n]Poy Pk!v;dx\A<1үpdJS{`]K@&nlMdc"al";2;@ko7X.nROlS֣=_!hymD|I'0psIۓ=9䔪JtrJ?*UmS'n{S'o κN V) S֒qo `xU, iv!ˮӅ]҅ -N_^mEeFԁ}rx4Le8=xkEZ.Uw;69PoчbG`]Q} }hwNwOŪ:g#q>8{E?Evw=>Prݭ(嶢V{jf+mE(嶢Qݞ|1Y+I KZzR)ڕFc4%FcmA؟Zb98bo{!` mXzwp^Zb iDJKg0V37 Y{׼vqziRb*Ex&>=<ܹKN>^< q/?Y@Gԟk &ˆ]>i_v.Mޜ{$QNn%Ea|*Oʫ,^|̵p1ӨJpA5I#06*`;ml\aR*c bl3~ ^~8?'mq:p1ark7o}o €p'Ud;֗ujMY?{Ⱥa9v3Sҟ~' E;F;31ҿ;6si + B.{dʑN%V=Y1#sb^9y߭/+?X79Z+߷h؊X̢{En8WmZ~cPSy[@z狓 3+ nr ",YNrs}D?dD =/w@:蜨ҳsYE,lE0yn<%Ax6/?r& %?XXe䒿X"Q0\_Pwj'Ee%TWuTnQYeF[G[TVEe)XGUQYf_Qybʯ5eVh5\ԔuԜqQSfQsEM;#|YWR2px^X2-RH[+чKf䲨,a/;Y󥢜aTݱqΔk ݵ%(?r,d:6, B[j#Uzۓxs%kEqb3}ӊ?҈rͬPa ]9ڎN X[wCt`]jv ^; ;qވK 'T$R@ώح?+`̶K$@#'s\k3CTPݱnpȁ qS&+?K'v*O w5^~e؍r$ˉ$]ze@U6u"f!9.S.)-U,_G_R*_/ o 3vg~M@.oGЅtd`?P~7-rŕtֵq} `N<)%Cf3{.XC}?]sf;'!K7g oNpNB쬣ٮ@d|b"RpUz; .w:nl8@>-緍2Z,B&nL퀌6):#yQ#xo"abz97D'0>q< p@P^߂Ckd> |Z) $]^pۜN+bߟr 9dhѾwLjN\@rD@r sѬ%3~ɕdƚ^NEC!H߈rdu[5j%gezu.t D"beJLd!' י#'F&a 9  g}s^!2y#$'ؒ@>`11عUӈ9ulFJލv`"]CpRm$ ʓĄ]EPIܦyV88贇ߋ%؃)! -d `'cܾt'+?D$&fAHx)_3Pxړ1*tFp_Wd_e'—I4 0zw./5Yz' km,#Ae**XKyz⏽tN~zy0>/dGE,:Ū?թv{J}E㓜K(q?s.Y C)>FH^%\^ ׃vp٦Ltי0`[3܏KVR z3H;DR.O#BbOcng\<D;T )V"8n_Eu- ڀjǥL7VAakn5Bf m 0g şK q^|'owoNd _[ԙ1sJaq0_ lNQ,IT{pÏpe]p^.8oH-PMD.`YDT^YpEaǎkD}gT2k?bZEc4OKu=;DdZyĂbK[MҷbK@Rs rFPjd#cJ *g]&d 0M9&Yh3I3jbgx5L֥i*U9~;5̥?XE9 5~@I##e[3bF h#nE Rh(3@HpN-oO'KaݽufK3  񕑦M[I"D>XT"!t@Atsb|:иRP+`Et2ITȔ?ӟ-LU? WwËYciud^@5U9vX0&j]Guq샃#myht__>|{ߏwhKqM_;($%ǼEv"'&0JWx΂]yq8dK".~bv];CVձ?#LFXNB؝͝'WUu ɛիӣW/u:22BFSS3d5lOvGK<5eyW(H K oI92!Z‰xcf[R~waxJޓ-Wν%eB @@Zҭ̙buX]OXxuǺ-  QljG 7ԯKyX Pj`ԒqjA|;1MP9=ۧ_6@%浭 لZz"bRb#Ș d<!6N͜<+c7r^6oPm; ƭ nx%|w6hg}'e84a)L{>7B1RH &,/3ezN)k՛~dZ?g[2B+:h׍﫞:@G@0<H$/*dbrQP M-(#@an]=EGhU0`i${U iIOP&N2D&6bݝ $ФP qrҹ 4Zñ$ږr^';wHDU/!v۶Ŕ`m\xU,λp1vC:_1{xʓ㌟[cEX|^'} 8Dh̏y8oQ>h;i-"T=-L{Y.Al<s2*;'$ḳqRAMpqS[߼j^u!֫,`8TLX#~ђP45(%\ Jʙ,N!KŭR>DMh%Ycέ,Yw]fV:6+kLL`9E:iF 9%Uk7`yjA0(BDԲ' "iv|_2** Q+oN % Ѷ8 1p &#ne{3/C z 0l/"!&L!([m_E+jwΙ3)iAjeXZ}w(ڔ!F{Jk<*mk[WUk \O%_c$LlBH?uV꽽p"S\nIɿBxQm՚ ;WɍDb ;)E2iְ4QMhw2K{hg@Y}']\F tgc,)I\X y8)<Da\$skv(H3Q&dT ք!)@-kޕ +.මƧB.5EjgS (FnFKj荫ރ$xG7eT=#BN01r1nNAU_ L+/hm;lґzsذ*/j34?ׇs~E-M}Jr3 3%>Ny[/ÿ.ב3uƓO`*D@b w k&&W3O$\+ZvKW RM^)lD؆>u7KnTz`J}zvZ,'Vyp9<{uttp:U}Q3:)Yuwe0TH K݁S :E &`5dAku XWV!\O U]/u[F[Y&s}()ҜQ1SAԾz"sA=L!ҥq6Pj]eURx1koYBO ܙgCEA|*+w fo*o\o ZɜoEK  5a#nNj8ɴ3Z] harM +7U'I<Ƞ4`*RfM[V˜&|]ɽ ]fQU Tu]o@H-o) 1;qiyE[ceYܛEeLFYg7oBh[ZMV^cZ X˫VeyFc3K b* dM" iX4^ه5|G$>EX~s54JlYghܦԲ"誛|,ӻXik4!'B45kj"g"V$bp^plRjڀU]V:5NermieƤ\U\材3q$XĞ&o#*72U0!#ti[ (Fķ}CZ¶K nf6z穃VltƗIec S~!ƅjj32/4F!8-Ǣ։[|mwfBYz5Jn-dqM <[,f 0dü-AsS͏?;F^˹,};ʳT4hjfb+rHcgNE v\>"x]V52 ˚.Zq&uA7Tή@ 4p(a3N/"sȔ!/C#Z"GX=iȍϪXKx[C`SkW+_]- 3C@@wN" 'H&lHY/JS0#LY"(51ݡ, /XzBF@~#b0rZP<7*rT"åp|/̀uQcZ$jޢ뀫}ҁ8#-L  jÒ|MϑDTgwfy#A[\PqqAm>x;sl jL}M4f(:T^w*>̃h\h+b^")G8(„yM1VXN;yzWLkv>DXR2䆕,yphtm%bHiuʨ')6;Gq՟h P+ Uu"Ƚฯd(z&` ("$qnL52i<՝3_wS7AX >s=SgU<7j0+ 9-[51T|0*)nW*8Z׹VF_cӒ {*ݕũֆftR x$ċ؆;W !)cRԤ9"Ob Ețf*ˤ( g(X}"R҈LfTA< ><>*&JF9QVTUe U3i)XrYUSN s*gsus|ztm>,縡y[!/fEEE%3Y~" oW/zd2E !p#!wF€q1^cÁ)An!ʉ_A`09>x@U ivZ %u>;c=âC ~KR&KIXs*ȅ}##0.:Ĕ2R⿢v%+ehi+E jy$Q{I ];/Z43H D #X5j@dCQ%EM)wm{|bg}}N=7i*+2zLj͂LYWo/ηE>k2)?9:{Ôsy '?X;H B&ptm6"xR:3;>ְ3LQʧlɄ9A(?%d($]R *FC @-XR<\4{G&-I\2Z#4&D:kuJN9M{*̱j`@2~V iyc bMC;UƷ)8bNX\H`q`DSҿNat>bܮ\Yw0d9 ǻ HHJq͹o-/(¦X< r&^8Ck!thFDmdY5. xF- o#-5J+nF?Z@YFϴ,ګqrA 8@<)tp2* [2GEArץ:2&F$6i_eڳg=qTn`r2aδgY 6'2]aeqwy2m} |dTkϗjzX"G NZM3:|'RNL2yYO}g{re/PGQNq4pls|@KnGN8$:-fWgmH4JuhCBg ^&#D|efNtm4 L=Cl7?^ԕTwqTn͆|Ur n*v7sb*QQ&R UN9`p߽GeKb]N b]NIUW^=ώ6ReU]"+DuU8|hZq}=ze'8|Pi1ޥ}UikEbK=۹fb=8)K#oҘ(#2_Td+ӪbNXK(/!9ǖlMY<VZpe ]t-~kE&\ d#Ɩǁf% /Ycˣaoaf0,$l*!.H oXjI<]+*\5CC%f qJ4(508 PԔxiX<ND]P4c`T<+}ߌ>S&Fy 43z2i]* gsaI,cŃP\8#K^K>)E49:ԦRFfdud{}.}L&'B|G ni~u0ߏǨArz%AC@Œa1ܶrî)Sh]w0e N 3_gy|/I-P4 !=V[ZpyS ^Jd3L4:!A;e\=x!uGP83Y`{  _s=ۺœ-U4ޞƚ R"ZA#zІ$p(sɡd:auc B0]~ XbP5E?=pW!ښZX[hy&:)3 Żhqi|Y/ }hDsK 7ԏppBGat¢]mZ ]>=R~Z˵F3uԺ{uGX8_g'"TN[xԽ gQF+u˥5;gƬ!AlYHfaߟb;% 4sQBXdGTKpQ_`$=T?8P DŽ %>Rdb˥\U|VD慨W9-~3mC$G*LUZ](Or'K5™#Y%AziQ&=mL`g\ͱ攗Țz6 '|a!e/*A({_m.)>-F55 0yYZ tf@I3FC|1r\Ix:YKS&+*N$c MYcƒבEGJ(wH=` S`co's| y/Zp'KWmsiZΏ Qﱀ`z׸zS׉]o Ӭz"6k.xM$^wymJRz._66+X?9Te ~ "7X5}k喖HLּOvj5!FU,1,&6.ŌIAsFg|I PA.l Ӑ\Tbv{u'9[qu5;k^SW<0FceGQU*Fy'|06x':(צw8EI\0nI4آTEԵ/3{xS|R ȐQ@* #N^{MWB+h0Q?'Yh$񗼲^HQ]. +* !P Zk1%p\j֖5y`1z`n1A,XvT^nCVm1L1e;-Sv 9Z vEӷp445J=VN#@%/El[l."${Q#H0…:5R9l߸/Z%i=W~cKg㩃:R|g'vp%lD D qu(;PG,oJZA5#Z=yhW0COieX 0M`b^5 țnNwu(,mTRJc}Gd3فeG3#Pc蔋.EOcw#/hHP4H^%Ry4V擌Bt^Ia$~>oÜ2YOꗬ*ao:ڃ- Q?xq:;;>ouVo񇓭Rb2{mUVgX%ݞf3` Dv}OuS$d\< dsm۪ܶR#s)>P @2-tCrWon|WoRJO^rTkMeU-0fILҙAt`DHH4XGY>V[ȔNa  _( =JYX1֑2&q85FCIVY^z{;f2 ElM9s8rc~'&qݺyAzU@(C{1u{ 9.bd+6 W V) a vm)<ϫږԊwT:и=Ea.FWޗ,苒k*o 5GS J^r>cxɀc4!,}Ζ{[ Jggdɔ.0Ei '43"3(;NBvEkLLF5/WܓRa@{;_=AeI|Jr;'X) +/ BIMur{Z)H5c=ѡT]k9Kh18#E8څ/Pn؏w_DL;E]`ĩpuڧ-P.<~8:tϺ;)['%|KD[ fL5b@ @O[?2ZT:rGϯ*Q xj>NQx)M!ISV㨼OƫǕ LsyLPF㚡-[8d\g0nΦ[gB!8OGس¥}.LN/l' Vޞ kNH R t3ZrAEZuD_ƞX-돂s_{deAM\1Tl'|/X!$ή/ C >/% 7A; ` *o )*D>@PKvx@PK: styles.xmlk{CM$?^zI\t5J, w\%@ ]2z4Iz7]o扳&NHv*$NݍEN&=L]B7ZM8T3jlO`6Y>]pw@1\t{Z5@ kxt&"jjidoidݡba3>Zp+ iY)* xl"~؇^ L =DI5NvmJ<~dn)|BqFhY'(NgHO)8l ˤ0a0aCލG25PtM QIὈx$~3>ɞL e'O%dO'<"Q  IZg|A-saoCi ቇd: 8B:bHiZA"԰8(?P>ΨT_GDc=?C/z5Nj#Z% { wG4ܒN4E`부S>i(^}"KHEY(XNF!"'gmE98@?Džs{4>[O5 ;yB(ɜ-:JjE~dlMTXl6P[hJ$ !.(r 7̝!LCwо l 8D$js.(FP?XP3X')*^f @bCIfC,gnͶFg|ҬmH;3f8y'pY%(t,ӂW8gXQFK]H uv+?|젨MTKUB&nNslj:Ceu'!R6 ?7cW+%nm+5K}SfnYd^ωZUx`Pb@(<ܲr r5/ءP<ƙS .lʼ uFF(SMP{ >si! <!<#RlO䕡#( vMg ȈN>qU 5?=gY0Pq[1#J)N$!KZ֘H fmב Zm6ڢmZ%ɰ'ߘCI췋+1F)cwū?d_3,ILhhƛ{}+㗉 Zg^a<5jQmCau6Щ(qJP*$uBx3\:QZF =$d>Q >?~;;xS>VJglҰك@7/BH5s/5VrPT.HsW˥X 3pW]}+̙0\+fy㮼 s.\K{raywiiyֳF/jR@~N%"P]^P,[_m, ~+,?ʫ<TvX+R%acgner 3p6h>iPQUE )T%(b/-Q]\]5_sR+2PBbAje!G58w3i2IYki@rov7O}sY$/7t#?W~):guŇypJ>R\d_~ 湾y .o21jQN8`KRc;˶ WLa֪dVsU0MelQyCuy:>HP*ն|{x')O+RԷrתc_ә6?bCȲ mTbĞ;aO^6>5樆{ ؉rT?bΪoFaL,K[T4T‹C.sqt݊!gN{!w/ OE gd"Xpݶ*Ty}/v~ZDX׷ZcYKl6SWCPinOõzhՐ 1噡kg#B 妨xy˄:sqd6,6[ZiimEGm{-:orX lPy5iQ-SeՁMRՊnBkÇN< < NeoOffice/3.0$Unix OpenOffice.org_project/Patch 02009-04-28T23:32:532009-02-02T15:37:08233PT39H40M00SPK:Thumbnails/thumbnail.pngyUP@%e.ݝ$x݂<[p'2X܃3 2mܭڭz?n{T=Uߣa}Ro{oud'Y)-| ]_RKuJ:<>!D,S(,}8fnvFoy&匕j)t4[̻q9~]M~Z, vE @Vll],l_dq#P'/QGRS!c$I'qJ#K)~S)iw )N[Ȓ%{lO 1xUXW_nԗ)#bvlr4k,ӳ  9oö袓1-0 c\c[C_P}^Ӭ<&Ut`_]۷ksKSU;7ُNf=ejAi6+Q734nzVU^wxs$/p5QPd=F%Yw‹ۂ '%ͫEyJӸ.zC8$q;a|oXV/Yi$͉!H:ю?3- 2Q_! ?Q*F!9Ҫ-|p%hE[DP*zְ]`k}!|rI&'fU7uCk;]~_r~lc6VsM禀u *'d g/(sc/zZu Ʋ4lD9K㏎a݅mH"v0A5@7sx8{(B~tr{)=2|TM 6? r҅'eP$BLb#P]ǙDrDiI2Qͧ O ~ѳ}vwlqaPQJ"|7N!_Қ+}՜$^!TV10*WRtg14-m+p,ɎXݘ^^yN{Dm Nj|rܓ xܿU$.'=}pM Ӈ[<#/^;g1_^r kdͨ,@؟~i=NI8~Q4?O54Q#$:QK k''w.d~1 $C(n!4my.6lg)=O%ポ;&pHsRx"ǚMNx8-H k&0DhV]u;kY`ԫpֵy{'+ds>WSVYh׷&/,+IO5Ll+{<3^/RV>\Ю+=8P/S emrp +0CyHR E>y%'btdys7'_ro)u2]# FNU ܢ{^ =XLQA  J yp?,I48/ʐiKqcV040$ʋ ĩZ gWX5(mr]Ҩyg> Yݯk2Ðz,Er6]MaT4ƦAs(ݖ?3ƈHJQ odW?դ$ o`fe/irFw'n8z}+n5wFPѮI%/>U}g"?wk280JP`E1Z?2 )7typ]YTm&w*'ox>g9w2ÿ(nM&]4o`}au_Зr5CFȲH gT{\t=:␀w‹-SSVgg^6l]{ fqi2(*[c@Wy#i4A+u ?*EoqBS/e,P V}oSiKqJ7ǜ,!xzN f,蔰CnR0nDCjg5^g5RRlTxw.2щܜ݃Fn`AՊ:G^Φ eP sCF@k&1.bNQ3U6$~PfZYO05؛ub -kd܋Ig&:{Mi dDѝYK>&scwJkPpUJn6wไXFϑ6گā/ CO,G_{j )z%)EAm`B`I[hYUCql;m8Ηm5C[K !'sO[M;vNSCR˜>I_ɝ{/d*lփC >㥧հc. ]Dseo#؛2(Wwrm|OX3W`v@IT&p @T u7oˬGhfգ7]P௝%n Lg=ΥxfaL> ʓH~2ir]JzhP1|@Y;/~Yc;ZYyFAI HbFk]E&}Bг^Cb.-u_م=cFty"uM]YoT'2TkC]wiD]{_ 1Ϭ,s@ŵ '0.ʂ1Mb<",A3 Kg91Y Qҹv080sngyMT*qfQpS =P6ωN"Ĩwp% BB7-?LZZ边=yȗ_A(ymlU,=ElYTb]%֪T\W\\zZe7Xs߯xYG;Lj/n`nVmK1p=ڵ  ;; 8M6eӄȷZ'8mh4 Pܬb1Y"xβ~6W2]N]d\(HJ&jfa91jd<I9|Fu3?Z6k8ђu pîzb̹J\V?la',qq1,C>䌦5Q70(K2) Uk)G'?}r]Ou=pJ]7#W+BXDYճDċ23[=jyRAV$û&mF]y5P|օX% (+{HGJ|Чk驶bkL` &˴ra@bxXdNBo[ nwtLZ-[*H ژ|})tHTx`w}N ,,sV\Y.]E'D.HU5T h0%p^^ps@x.p+?a1T:zQy.n&طƭl_9RVelϽk fWl2SI24'ޖga9/%ɶp<`­ӹmG\~uG"壙QB,d(X梿$MlH~X&sVjl NE<}=HL8ɮK+܀Ks{O5B2Gүk<'x2AF *R%vi-HCUTFe #u0D\qU4)5`ԥ`s2_z:ioKeLG"IsG6r yxH<`01wKZrIjј%omimzύ Y@MZ?IdL)ۿZo_1x+V p Ywr_<HH4 [_f? G6\n׏}w‚ &o@))YN ĊZ/$)cGw&V^L#rAP,9yVVqX/6ё?7n3NyCq6"Y.޴/7h:g`}>ꢕVuG z !ҥw'xijO`$QKC>MIixB+yRrd>,e7iX g N<̤㑟E&=OgLƈJN.* t~Y 'O7=p0?KVOlVj"{u6in—¦Q8G}ZQs h*3y k[t$[>PcP4:{GN^-$$:?v |\>l_2l##=ຟE**vZd^ē&IΒ15hfu(lfX?~Mjw"^r^I(nΠ*oPC#8Y5\9,F,w|CO=m(aVV'dR!4XP;O]8.(m㫢n_qa\? @*Yk65 D~])hmpp3;yUmk`=VUV]Pug2P+bSyD?@'mkw)ο3q}XUCu,Uz'nX^#]ѧ:2vFuLw?H ~& 8[<eQ Q}xk 8=RHNb}ˉӴ _)'["N:(RzuOVRߤ[$ʹ51^) >"{. ϒE\d)|ZO ̜TB L.k"ؗd"Omś{ueq;Wsbq7M23/]$a;ILk7BձDuaHHsoslªܦϝT1fx<$ \8]~J:y8ì~)g0v|׈#|R5ErL֍њQ(W #sX rldm?P5DW8 \]:r3I5X>v\hRMX"xQi7k铎>G؉IB~*n5=7 :8l<7Jm6ؕDޤ GFǧ! ~Z/-EpXyd^wY-MYj08l'xXofWÚjy8lksj(*7T)jX+bHsM-4TNr'7@ J!lj^lx~T)A}zle9|uGszQ3l5i'k~Tmlcx;Um.IL5DDYYQ}%]ʒ0*HFM6˱HQdӴ姴Ol$DZg/qJ3wsE;J¦|Yg-W *>!zT--B韆᳂wK?KDVGi{Nuoߎp>EW'ECqR5uL*,|,끛\8D%-G" *7 4 'x|K(øJh%mFu7n}_/>,_ Ϛ+%cor[KGg?tB Q)\{8=FW_]H=gi9|*Nљx gÆ1N!ɷY~KRñWOSNVܠW`Xc_`h`K`}ACL^JE%Y#=,ˋd)Q;8Ȣu`D?NeCW6Ph}:";|퐐CMC}m >pC c]w[k, ,oBWdWgJ0.b0V y Ū3Fw rHN(De9+i$!~Uf*`5iWٗ"3ޞnTFw-|dy\Wڲp !(!$:zFuqn|utTq\qӗL[ߊ8C]ILhDӷ7ŕEf#wI]ULLCm;a\}rZkhu49sdpW_z",ē+̅;p{=T] ,'Ke*$ RW\< @RRڹ, hf{}S-;ݮj^JR,W2ZL%M%)efS?rQ^Q1;Ds!.rvc唓8Luév#Q Y@5;ﰮ8J- 0Ѝ*wVW6kom2Z>gݿnۙ$ӗE]pBŏPl)YH2nVd{[ݵY|$e;^دh3ᮗ h ѿ ͢W0Zx@\S9S>FY3{ K"2dfd6iɄ}I`29 r J3 "PH=Sb:!˫:ԔmԻ.p,)"@f^^%? hYU;+,,3bC\Mo)7y s2U\}0$OroeADf16ԛMG1搷phTaB=Ju72yWoCp6XRw%p^޼Jn`IлMglbisV*N6%:'_S*Ɨ2@ E^=UЎēx6Pj5?ԭ;4C ]ag17;pF7@1}X;V,rC-MT [-Uq-E6SdC{1.p+Ü(Y^(K^0 -MM$AqՖtZ8q8D #A25ȃic{:,x=t4.V pD[Iz%实Hdq ^ΒP {7a+ %[M~'OH,l!XnZXH!tͳ6=eGk2a(P^4Ay/uZcw[;F z [nrqI%H2K37>ŜF~tiI(^Iw2fv.nKCE'NXXXY2Dg??NmoMݛ @H:A$䘄Hwj`!+{Eړ( %m;tmyc 甫_&hc_ߝ ָtlө-*!p'YVPi}Ny$/Bhuݟ,[Z;h24=i2>H,Qb'3Nz/<3PN&Ĩctڽ߈c~'?&cx,F[ϴdŹmqNgzO5j-HG bS0er5` "=) (OI U(uCt (:㿲WCBld "ݖ~(DB($FGNR{V&d\`HIdDQŝ ܲ+f[1"SNTD#p/ kbH)wu)-}E1x(=d'8:x!1FЙ$%S-4b $qTGwjnoEnq>Q<!lפ'EC;wL>"I&G\"A1Sn.M A@W'] XEhC: /+3ak;gvJS(E5ǢLWNnL{_C錬p(Bˋ懣d{$8l7ZCpC4t# 2MSUI,_9:ק!a "%:f Vqt '";%YƖwV\Պ?G>Jp!X_}Nź,Am/b\%Hb,όy \ֳxAxAtƋu}n 'W4/T7]h S9T\+nK:Q @_DYC^lҶ; AL>?mCK&v٪G=C3Ԟ-I-#ȫD_O'H%ޞS B2e= o;R\ UXoШo<* %dn"+%,:o_;NFgVd0V0 mҵ)77ǧom4κ-Ok!-eyO)VFģiE5&?+B-ӃʖQ؄7eCOFÂ+YF' jy#US,Eظ{PI:",{%#' !vkښ9+B-\\JJV-VjrwfPb{[PU-+M]ґT7h=o_OWZ 1?lS&^k/u:z:zrjeZ#iu5fAfW0f[.g}mPPAjv+^nj}̿3 LQ*w?/lhhb(-:_Ês"Gѽ**g ѫZoZw2EV=i 6篨3²B_<*?-mH)óE&z,Pྺ'豃f+Iu;.F L+m)EϤԩkZ% #{llQ8RSNyBɿMn769 Ey9'9E#qXUzҝ_@['%z_UC[~ N5"Uאpb9Lk4KJsv(EC0HC gQM/om΅A_Lۣ߫+5px&++5'KK Z 8&V @3{8#"*T5f (rW8q*} :m1vtE~zZTE %jr灯;ڠ ?m䚗chu۾ ]s1,VQ|VbG/]L=cL^goegA%=€vmjY/8лDrtye]pP.K8HzEO ފGH3u[ľV(>](oA*gxt[ФubuAaɜ˕g܋̛ܓE˦ok* 7% TuHS>v4|m}A5P 5мߑ[~Qoۄ3q!Wzmx%Uo:oOmSǙAfkue]"&լwbeًY- $vscKv nzZƪnrZ տ߃5r2zhZWˆ @:.s6DJAA4RtaiRJZ|b'~Ak.iXV*#%,)*zIVa)ڞXk"Y~{rS'j`_Lr]'.-+1lj0AM($߉Ը*9l$6M,}7Xz9;ļdEHPѦ{u'݉V12I!BLbnH{mu5R _ ojy;d uISP "/\Qbv 65{f%NUNUbOdFN]QpD[| -X-7TbLjYQl屹S50KFso0р`-\u!lg(؃D("n U w!˴/+ji\Ս F'rX-`AM̴JFm&i$X^jV鶚#[ /{\롟M;J41ϻ/뙥 D`hx}mK-Y[]=Ɵ>A@URJ>ke`kaƇfk"ea\ZW"ǗKaiUKwV>fu֟} UW]J{c;˞O)jPE'X "V kA[H:6$0\.RtN-ˤà)L Eoe9hƲ%}3Ёk'lK:')tItlfDl3!)0[w&k>Q CDWR:&%86K:BW71|~ONL4xCٺ3nJ &;,>X%[C3 MWyZo&ᖿReG zi(B13o>WJq Zs}PvB!5GeT\y(wQzxs7I^\IɉbW\U8 o2?8؂(C4xlIR{C؟q[ ĿMt&c@bF.mǶAX-e S%3B¡ԋsˏ_4EV!.]O~2^p܈ʭ:)eq1Z"GS r!hJ'۾+4a )U-ǷifEтɴbi ,qT+e(TS;)qky!];U"eX&@cեpD(ڴ \^%PvkHeP]M.NشI}))jىL G؎F؆Nm&*]_ٻ[`Pæp,Ei6F& wAX h z԰* հo*,wU\uZ:GEī(}x~~i+stO^?Ox|$PÄoHM$=cL/$m'z+Ys[Y@AmwYI9krSkr)m~꬘6dO;I)VL!fqSӕ)G&Utv~i76k .XvTg4%,{t8~οo~Rx0 xsw:U^|k:j |C܂Z _׭ج`pyiv(w-T{"t}sOEo͞  },{D* 9=?g+Al m}32{et:b$ѹş 8}}y-eQb},rrҌRȤl1VK``ҳf)oKy}p5dVFTIjSd5(1yXz4=|quw "C&!Ӯj]K]u8t^ be{v%4tz=ƷtpGMV #R]Lw j?j+Δ?WY 06b2m `r!e6 +]ѨDy*"IPBבºz'{ b[%^+PY6IF[vlڪ>w#n;H2$*yqjuo us>i+R51 u0 hZI @\ze`](=qf𮩨B~ɆQҷV^AЉt U`9\ DŢF.J`qp5<:hΌw`)Bf=ٵУD`#3K_B]i^W=;zPWYt}\w |oX]WyDZmy^-2hq;_N,hL|B@jRqƨ׃ SrM~pEӅE$ʿ.Np@t?RLL|}o0v΁771J'/u/mz?ޝhpVQ^a l U7e8`gF0b_>4 Ĩ8vbdD)AG*ue$ iNgCPûBoNhxhADݮ-Ԉ Q+~L)ΙmxQPN_:ElOQWP1ܲ:ŒQ/ꝓxwuD H{(&6G ˠ!H˦]AJwBc\ ֟= %G`UҪ*R/Tps6xn)Ͷ_YG~{{}U`Ccs5xa(ayjsU4hޱTe/i_f5[lq"Hslp&ГcsCʩ"q&zE&~:F6A6~],'mӚO/ƭt߆+b8!n8?XCn #0V/Z5)* دdPx,פ/@Sfdi(w1Ͳ4ĜfJF~ˀ)Y] ZSΆ P]Fϵh1Oydj5m]>} -ܻ:H覦u{,W$,Ξ rkcM`Gq 7f-@3PhXLjT[qRPK-ȅNm$8?YcHC#1^286NnBob j>diř_R\st=ڠp^t}Mo0_& 9se# U|5M MY7z$iE1V-p, >0ñc.D!W~~XLzO3j*ho\ݟ0[wu>2 LncWB5BW_R{ɰmOWڎgu(TfmJ,~|3Ă#I>M py7Յ{7(pQwp&=_Dp~SkK~aQ|y=9bNu]@JtxYT  8^hΨS#WxE 7l+Pz͢4ӍdTݯJfhsԴEA(9m11U`{aqY%kg{pRZepȺ?[fz .7N䐮Je(Kp(wF2+ GmVҙ p:yu|5'U%g rtrs!Rc&svGlLٖ|ݣw&cmoǩZe+7͢Nx)~^isŤ˂ˊ)QiUItsSY2 \#Kl H,5ayϴԮ# 섢#S*_ PYǮ$N =F్ i& FU.QR

    J:8VN:0gPufΙ)]%z[ZAm =wa!Y31uZCS6̺xrZ xh)U,[Ĭ%qswcEcΥ P g]sk GDޛ9ߧ$)銲;PPQXlE sC\PH MR_=QKgf$: CH82)Sࢰ.pu].YE;fjՌ3'CGx&V,@ʬ4F/ ,fGta3nQdr{]5QnjDǛ} .~]Fm &uizЕѶCBx7/E/VñDxGXwc:ǨʊB?X$`yW Qi(Fo5O'q&]9 bC], '[) x@DAE=dBDn85CJKh.xj)薬KF ~ͻ3V5ς]@w'M1{lm(mj#ˬQ.uq4Ҷѧw/L .-g٠Fv`h{+"@sZ4e="D&u]9X&v6nHEB_#y`o IjY¥rvd>2.Aq|{k@4\D JeG  (leVᕱ>_gIRG xbrP򓒬j4I3IAWgS=GB^Fؠ#Ы*8%,o3Ԡױ=k[`9,t={_t) nA 祽mJE6ǽ*ub(+m"~Rh3_GqنuJ; կ@G3XY\WW;DLV)>P@F5G›QFOHO/0Mν/piAefb*qwi+;F``[u\mlqq4'LK.O-NvA89%<93U+t F$t0p"ڻ06s0}.OQwڽeQ@u$]v}Zo7Ռ6 p p~$:ɱsͲz.+;KmF@'.+gk2}iוm{1el,3c v28+ %sWOr6r ]b)NJZ3 x6|ya3NHh-$ ~H@B=Dz݀36jք-f m,VSF.jE|lS+;3һ աwtCƵvzyJ٤ýo۾CKj(Ӓgdx^K^l+e_nbҽʡ]U9,{5w;Mfס1\B1ݵ䮳7{";z~{dY&{{涌rr,3{3 icٛA?ױ$Y6C;':h_^yCCDo`GG<࢞%¥XEJ1L/PGv`aJ18| GG:ȟ<=j5%P:d|^<eDz}|7# 4=cP 6W\6I=bO7u #K^J'tUtٽ.|$ƅ ^AwIܖWy6Q3ٰe~㢄|(4qn:&[29^g9yS4br*4;Q-vbz`?(YS̸V H$|XNW^nf~mjigf`gflk`hp%5Ȣ{LzZZEkF-$L;<)C73WckMS# k98ּ< ڡh瑱Lgb4`4okA9}#ODYO/$/o/-b}#w>ܾRó] 0;1!|IԌ^ 7ԀO!T8dgs^J'y"5>jН, 9_0B+.Lϟc3P2`.RG过}\5w6ɮ) ,#[I6ZHtZA@o1x H8r?~4LЫ.y6+U 2ttUʻ7GHG=ttNWd]P 䊌xa"K:IK>:lbHj$DM"dM8"s*Nͺ: wƟ*ևUzWh꽦Z,xeRWzȹ%n;~K 1l.R=zJ 6cKrM ,yM~ݤ_eACpԹGn>@ wrv4uSdQ"K'ҚV#լ-XƫAL /- A_*{t> PɷГ@%TM][z#~ :ߞ-O:hLMs{ }8ZOV;m}ܺE>WQe>ԜBI .CJ!3+*D.klWHvX_(Z. Ӿtp^LBh힚=BB?xGm3><0OW) [)-?>OB;}Xi1ꯌtKq&2 n M;aQT*1 ߧ2z܋> !D閷Fxfl{EGE&nWUv*qag }{[4̋ծzٰ'AJ[]l NuÐаqX@ʅ$H|IĢK5vIoS eh$ye$а Fuɍ/?ᴮ5Jԙfղ:f_/ҏԔrFY{ԯ~=Hg\]"c2PTb,<;ִ짲7le|0y\VCyCDyqf)kO}Ucw3 Aki v/On)e3~wbT=^ {3ik_*;w͏nvu&>]VúhWeBuTW{KUnKcxbTrjCӑ` |c{5=y^ɷKyIʅ=4 J-qqZQ;wzgݔf sV]ڮ:m7.wLL'=OgGO- X̟:]BKBF1g!ǝP( +PX^P1X:˻ɪC$Cx xm+.^Gu𜟁"d*\}bk/[Ey;<*_i g #"?ɛl*չB1 5bJEc2&"@فm -<E*`]ބj;\%Y*= ~Z5h%QvW0tփ$)$o90˓<7yM[60*:-AsFs!{ i0zvo̟MMs' 䁻Wn~JuscCT(pp96$czb9M.X;_48Uxۅ"s/ 45)UoŘ&Klh[8Eϻ%:I ]L<8zq\4`U$pvQGPJЛ ɘWT6S,V *CuHiO(~)([/Cp8:ѕ(WHtr;EM2^2w8 q(gV+QE1^F#&(yrOc76Sis Ψ^Fۦu * ;3zG؜DƢ!`9va7)n4*BZ_ , l)AZY5`z?$y3#QwnF'{8!qX.I- ?%awGb̦ 4o^߁x]RsSX%/M9:QD$@3'%N8(źH\ 'ȿZ4,H2_?^E2œ :sCu!-@ ' z 15^Qc&S|#xK5D<x,bѕSrITӋ uG;59OPȪnmqNiKW(GJiOGXHi ͬOG=EGۯ@Jv=Hj@HqI@K~Lܞ1NKG;8]zY :_#nηJXmlmJnVZm5Ӌm4ǵ7_{[y7uo4Km4m*7N _0ݥqk]H `c ") lrŏ.~NGE0cQ"Ea:&`:rCW*=;[ 60b @38C` ܥL~a8N)Z 0-\/gq {;\F;My}arMp+MS^Yukx2C:ΟzCtivSXnGXW5[ci/-v~:&9Ty̶Q8mtĶm۶m';ض;ful{s޻֚cT55TE}^u{iRrc :',M@ȗlL&{J" =ϧbP6:vqM4_d&Ei&lҵڛX_EV3:8\#SgנM+ 68Xte=P2%iʐ1:]OXd"R攪C_҈YJt/U [eP Y-@IOT|F߳5l/" /mVڵ2uTɗ7?J[Z_jtQphN(`*fblL(bjnJN(j(enmiJJ74zfJ-]HXYBDDC_tc} ;[ʫ0JZ [ښ߀% _V=5\Qeֶ,$\ ׋23MuIX8&s_H888ƘI8=_?2qtmDo_e{e9#_T_c`/;_ ?wgWQ+cvffFq{SWLMU3?o_Y8ٸ83JuJJ`dJH5R[^g6{H4"%EuF/ns^m٬-i֪>kXW2Ԛ }~}^Xv[[8Iu\b~8-Cדck1b7pAD]^$XK̘k~ |(XTߊxJT4/s)]&ImΨr k~5| PJrzM}XӬ+)Հ^Y^L2LF}xIZc&$.1Zcafy:˵ߠ@Z[~WzM@.׮mO>x>y_c'.Ec\eYx' Oi>^b rGLoиԟ<VXqVdtcJ(µA'D <ĈłEyȝW8 N}8E)pW8H\,7HDBIQV"9 Iy\qi'ʾp?n6)U:(?[v"25F!S~0w{"YiOˊ}轱u0冩,[0CK #8v$,"A *wz[huGD8b}C\w.$? 9{"|hs(ʯQ~1M*s;Rr͊?a'O]1z`?,O"(?!K@DU~ iD~}ózJ>[47aqT:n#v1GPqɗhj#J(,= j5%ǐ<~ŦQwBQxnxRǚ~.w~_^/݁.c[䃱P.!w@4AP6I\3)P 93Rq u{,RR7-M%%l5o333sz Lx>XrVbp{piW, p_I䯵T2[  K9״g2;=d8?/ՉStbGv8`̼͐*ӻkЋ`۞R~j"a(k b9l;O sA=tl\v q ]P  z"Gw*+H7|8>/D0ԽB#jqJ˯d,~[:u:4ZJa[hS%_FDtӷP!ׁ[zD~SR-:{,v .vjδ;רt-PLoLZ aE*9 ~BQUee~߻Cq<&&#{z/ܕ~eaz6d FLו޻^j+VuZzOv)yRBdv6{3v[OS Tkk-NnzujOm$@E )"v98lv#oA'Ά K~߽R.OfӢ 2 .B!5U(V[߀׬܉D%'\޸cZ[J0z]"_ܓJpqRٞ #e UB.q0 KhdT.s&< PbR:_lv*y'aO0s̓ p*p׀&4c%$u킅l͑IW?<'W< =T]wΈ~9L+F{?.m`& YIu{'xqX<$¨\+)_mrB}( bʥ_/cܷ } V/m;7Tkittov1 id _g[%/ﮇ< 1xRUP]sJB<+(3uED8r M Y(H#x,2KcyW<;nD)}}kkc]jD9SϹţE.gܫtcHڮ0NF{zb VE QRĕXhk%}i#FJ/g n69 ,ęL;)¬Nq}$ VfY#KH$ GEB Fpux;IAq  ȅdx@C+[$]%/GOqtKT F]i  {,un@֤? % 'WEUu}^˭iwXȵ־sz;k< x^?4Y $⢆1AũjJ2r&9<Z<_ZGGV)4Ǘ{_cB ^whWCzJZ#`?v5 #i;lw43_X?~5,꒓I˔VMfotsP:TPˡVpEQM[np yhHJIZ Y;w(ԪD`5tJaI堭4ݦȮA}hՎb){4~Z, 2SQE aUmnVK 6h*<G U|V¦2CjI194bHQ`8`*oͬ{0&Q.(fuj\! ;"0!1OMpٱXMOiΣ.ۉ()Ml2Epއapoԗ?ʽspeR4ȿ-vX"K"]2h P(EyK!\ a&߲`"G9aKY}OTD!I5(vǶs1ȖfqoVV~(!(GN{]Euɖ7Fۇ]9ׄ/%SKUzSS%/%Ō^L<՜Pijf ?^iserYzN 8QhOwݡ#St'Z}[.Zeɛ>8|Rd|;eاmI*iMjagQblEsGM[` s Ƣn`[yOTi]ƽIWS(fHBST~Ltx5(S9s@qvgQU~.\OWSab~\4 "`kyQIėG_I.hg@,1ܬ]nOa8ߖۈjc?Ns3߮Y?'|鄛Lѷy@hи"E%٭XC'-[$ σ29b) ULވ-ܕogF Q},?vED)@L *(t/G%ȍ,+ڵMvzT xE^"ҽMf#Lhfstey7\ ؗ GIDkwDO֑rd;@#,,ZA#m8<|Zcn6wYT { j˵lR%(F}Ҟz̖7͙%-kh#De˖?/UѠM)\\xS!ޯM!e3LB :@M<`f͕&BQI@ѧI7$0[ZW#,&|]XxZN4F[1ݿvvuG$,IoEXJKV1HCfeg0:;[UpNJ:.TD*, ;R:DJ4&,DmBfεيtj'|Ψ)'15XR|YrU3 ¡՗\y褈 ޝ4 A fZfYj[Y Xu#, {,uۓ` dac\*$ )77̙շ،1na1y;5:hEo8 ɶlNEhţ̮*ƨbj\p ucvsv`YUIU HR̤6HlXˮ]d6Z9G+UAKv-Rbj0mۮ! ~5f?GʴQv?qG%!&+Ց]gXDmZc.L?:^NIq6X"^euEeldv8Ix|<|/l!{D5Ԭļh7O E#D1vn}` M-}|n\^e T>\4gԨb/!)PAH ago)8v0[bZA]cx$ q(SZh蘈Uxn2-`Nqd3rks2C2ak#}$.{-B"_neL)AA`kٯdowmdSjs'-&$P69x?mݕ{㶫(7q]/2Ō4F8;f(eꖗZ4j{ h0$Rlp'a$4mV*"ntW&ŌW!-G>_`GpᬨЫ),pFU>+"(gɖ?9:Yʕ.q9mRJÕ"{;4>.$rM{CߞQ~_a9~*DP +^gO5Ÿ|ֵHsZȤ`G2e;p/Z<QUc=@$*%K6`JDP]bS >A/ "BPY)3 Z[]KQi1SV D +)@>9S}=ZaX 7K$4%}M9cLyi T. G!,9-fj=7|8ܰ(|ς$|l  Ec =^fA&sD^XG'*>> / ܃I[2$-.Gc(}ZW_:=!L2ftc{ #fj!aκQ\봁QdZY(5 <%:(-Qh41tZ% g%JCsoc{Zkٷ=.4rrr+2Y->e7tVC:ҒAotxG苸ZUM2Zms/9_a0ho5(0xS©aN.jΜ \B' |P1+EbK|͵m T 0EiGM'ͱ.m|`ygnGKu4vnzzkר$U4KQymƕT&o}&yױWͳӮ~;C 8["<\!ijxg@ޕUBA+Q,fbNْےLWCS[ݮZuuN\_37ϴ"(3#h>&H{$:9l׶ds4lQ>S dJ%k `LRRV,p\8g#so v0XcK^U(."ldYG Z[#pRArBk(EQTF[ C`,S^Rr{ _QeC(h(lvV7TXPCCYAQbw3rLyX!ezKXoLocsgn3@ 5nr%cAo3߆[,O?hj_SY20E*/6F^ $WdUEP[YBa!&&1WZYiGMA73;qu:]8Pt6I͹Ok:yBFɲd6kɌx*Xuƃ#ɧxٟڄ\Aޣ}W8Eýcgǟ61?4K$t%+ CW+LgerNprO*^\s;IN &@ q3JN8>a Hx#bוcƗKl?3@Y) rNɒ\󸕩YhEaeU_(I|)S"O4y ?B(GCˇuo"LX "Sxo̍E"J(yd#+P [ R++qH8k}h"ĥ=:NdWHR)nbie}mؐ*N# ]NWn>JŚ5u1Uu3W qzɼjUMN]%*(*G/f;`H rH[f0 .4P&DcQ&NW轒>#=g! ~QtZwz ۋz4ZCZPm&XJ[uT8nJӚSgiIY`k&i׉}h**J#E-QLfPSƎmNd-垜λy )LCU$O%]=ɠޫe]^!g s'Vɜ0ۼ BG: @CF  SC,AڴJNS԰Li #j:Uk>?46VU `mwAa_/J'>BU.w/:B@Wmln.v죀`WB>!6"֤ K".h_i*cozJ[?U*\+c4#[Hh85ӱ JEs!R&R~~88Gg@< r;.ut>qTgmoE]}FثH0hETW&^s{[@Bd^ARňAN>q76wJ(s.> LVqG@3 4~qCG *;i{xHW0@^^e!ihqP ggM;óPI#%G1>y)b-IUc (M&]9Ě8",f~i^߭~.dCrOSw[yz`QJȲ%t5nNAWF%%sfNȄa% ʲ>RHF{eQɱ0Fಳ_ڞF.0Vi<ʯ&"AZhC(H.n| ߯a*Dl( ̕Ph*IsQMQ N'kn`X)dLcA`Gy#?a q"lg:oMϊtq7jjB&@B&/n[}L[)/){ ,i8#Œʽ IJ*33hq*0Ӆ)Ձ FsS_>BW!^ "} "3(ƙH3'ȶeq9Ɨ>ǣ8wu κ)`fD"f` |3S{xV6q!q/z@x"=[Y}l^ UKCmz =L<9#.oᡃRcn`va.q/ Sc7HOsFK1#Z{-`!Йn..eO-@8w^,Ib ?.>v cy:ZԆZejme !;vju؀LZ$gotI$ Ry %s' Uq: +]d܈˩qLmak[ BFI~hrbжY#&R鉾K .#@~IA*z&fq;5|E 5A崳6Q6Ϻ/ ۾66Xj  ."c0ƥ;X U-\ėE}/m&[ t\h,VӔO((ELVٺ࠼nA՚'*Ձ$$%GEpճ#-8{$d77ˀȖ6]:q#_Y)*@ pd?I-…(l#A l@W"f(?A==\F:qbb"D57h{l,3QO A4 V3 %G# aﭾ]{ʒ]rne1]ݞ7h=>e^.[%'Ϯ1sSt,@'!$) W!ïWhPuDbyY`\VWչWiv0GOQ yjd_{*Z ađ"Yy_|.v \:*Ew6S]Άv -uV;V5qsݔc.w12\[:iL]'B5J vx<.ƅ4(3!.I9܉2nhJ2ÈdĢPuY2q$@LK+dʓsQ_5dA24Il JSzK] ߬,-hSX >P56$\莣H8s/xo4aKhzMkr q߱ -`hY^̧Yj>A3ֳ~qYZk~7VIe4aAkOT#5 P[|M3dFij,+8ۍ,)M50EIS_]yڲ6ur{^a؋)i}!:'&k/s/24]c7͕X%K+~CzBYmHxҮϽ9zAb1h2~wSƿ¹=9VJPGrj?{Q&Npd ]Ȃ AwCwUztU M6!i5 &x&m  b o*'~OٳOZq5*eVӶ.va+&?07Y$lyzoGi1 Z[ȉRfXIRr ľimH|̂j d%  "d Ѡ*E6gDH"+l RD#g 6i`LonYӖ!~p=x3*H1QhTHڅ*]왕 8g,lbgggtYUV"ᴼq˯Γr3!WHR'o!/vWYձl w NpwƂ{ h %ww]2$ʹ̝TW*Yҫ sGqx"&]ڃ;ElnɻuU'xBQ~ePdrFA4gƶU=BnǕ3g&0 (b=]I6DuuU4MVO^j>7K ` GY1C )ֶ]!&&/G8X 0Q+m!\,>3~G3W׮Ӧ┐HVxr&ikDFh0#g][ #VpNEpnfye7is}8j$hP *),_BL"ؽ{4Dn &% 2 )^7Ah8E5crJeSO0;OV 6!QPR*xėiP*iZACr CQ8v"ӦC,>=h١Bm6:^CAtN(dPCc&~0өBM {1m48#O%AZoeWl6Ul4۽RrBJMlɁ3_wԃi-,70f·o$H ]m-"O63wSZQk!ۓ]j $7hѷ͓ϧ]BĢT6d@`eo ډ*BA %ѿ}E9{ɋ^m]UqYA?jmkhy(--I>J3?= Oci]SeF |0"p)iK}Sx]{{Y1,W=xDYx3CO6ͦv)rRm5Z[)X|v.KTg(!nßgRx0b\6\FDƧBY{$4 -TIdK6̓)&)mfpfr~K1 bFM,K4$ 1 m19N抈M8W [q;3OQi[_ &ˉ~' 4fm;cŋK 9Hxg҅IbJ]GIV^2 0 ?FHVciV82[*ͺ$76-Bj6\ԍ`KƊ`J!c`OH͂g?QH!ҡ3!Xp;jM>T>Eq`g}kYnFÒw |!Wz;lM2}8@U0{=#G5.!'0C|emݾ%=apO~մsh[+0ŌE5OyDu0 8Hn;5]nހ9Q~HT}Q7ƪl_k23~)\M3]hjnJ!QSMdJlOm7d}`A_쀕A53:e}0R}6N.KP@mcmh/o{~Ɓbs+Bg\qisMdAӏ,ef{ՠVN<{:9h MW-*;$%V++Y0i'P+jS<ı\;?LaEAkͣztOt9;&-L4 %} -nCf+6-*UQ3*- ƀwU>I! |+ON4,*P!)id?&tn^(¨% ꊺrT;'-ѴNPӾCܣ}=#Z85Ms}o(dtX樓PYBgR# X9 |~Vt/}l -/'=/"<2mFھ\גcё&7dTЮd,|e%=G;9=f\j}Qwq+]8q8Vݟ d(.YWtBc [e]pvR_#p N3׃0 G1V윔(`Z˿[t4AiZ,MH^mC` abg4p {,%@z蔓LoQRfa 3k56s6"F鸹cNj D i,QȂP5=d z2f魞R*F-xfVԅ:fsGO20fo-Ԏ +0W dKc. =B'>8vVeE_3=4Vd31Mx.CI` [J4kC ?AI(?Y0ྨM g5 @Ls\_wvՉ{F ftɥDiXܻ{.^$u M&l, Chƕ wcPر>4m-|Sjc 2UuG~ P,T Q2:_#j ^J bqgvGM S^QMXIg/2vάG=uJS:`0s{{S e6cl|9+7ŵ izD-N[ՑYKˑ<ʝ$sw> :48"xhB)b^6eQo ve jJ"<z>$ӶvIxwoIBbd0)7T@}r'u(0oHSjݐ+Oh3dmxOawL`bhjD0#19VF[`6A΀¯sS G 4S1r](TZ}qsWu,'⵮U'!X)*Dx {kBKgVFzo(#ƈu\7qKqesʜ<ֲȃ*k1xqlFYSBHw[,7'>Giz+5#Hѹ⃇V.5[Ӯnѳ/;\NggV@ K[q`>Yi`ڔ֥W*ڬ~i#Y9oӅ H: qF *VevwZ'"806%"U4;+̛6ٓ6/&=Sy:ܻLN~4z5uC3r!Kr=UZCV.sV!EܻVwseWM{%.`ܣ4a.X0yx[4*:'1\ ߭zw_>ZgaF|"BcRT4XTTʱbsN8ɓؠ)4@S6poʀ>`l.b0,7nk+{mx ]R6^2X, NyJ8I0z獟! :!ςU!JeL46,Q+zw Y[Pp!34(/g=G]6ZF^Яwej8cBr?3r1*G 6"Yg,39a5NSϗwh,>&ȥgts`TvWKs6{Ҕ~ȇq`0tV$v C&%'&yτnRު £<6{0R^ S<>S8 80BT!d.fTm>9yAY0*++UhQ,ZB̆*)0ߣ($REXSUxRNtՈ"Wݭڑ ix-Aŷ$ĸT=O -9bWO_mz?5l Էuo봖Xj-wxILiu34_ |Q8e^b؎ijP2eiaFҒӒTI!f̩w*Vhluv$Oi&Fh8vƊqaϹ΍vE{pҫsg,%*V'7meLkAnnm@( |PD5R"r/G fIGb'C2vQ?3){I}y(zcizEkci!DftrSr+?כ%*\e\=yUᤢt`x/FnvEE Ik $ eɅاpz3yڂD$s4.+؊|ge½禓|F̈&BA2Gz:&I)J|Dgmwd-Q0aFA><(t,WQm>~ùpoT-W_h`ؐ;r}m̮x߻^iptwי"-+ɗʃo:*l::\9plYIʚFR>6LE8US?u+R8Nw97QW63flu0frM|H>2_k.m"x;1PITynhTn?݄ !{%*t-FDjbءE̝U~|`ObW{%<1zJ`<Ǟo,w EXjAȎ)q \1JcxQ P\7m>'n+/YD2xO^|z,Wȁ<c,Q\@!f»\gf*qz/|٢qc .O5F?a]ͣc9I#C 2p,e!QN`J*ș> N 6lEEJ3dvK"ݿ699\&ckJj8a~(@N0]xIp΋B8l`.LmθA]ٗ!EU%2CmH ,`5"62sYBXqYC#'bםX$>Z{9WJD_O9TtzbRO.Ø`C \ SFo|K,\ߖ612v(ZBM&-8qQ<ȴ0cQq\x=mO%x[t] r뼁|dNqGս"FS|(S9y>x;[ɈECqSGr~,'iZ\oooZ{Ui+[>xN|NJ4 :q6r&yhMlsC^엸F4(5R"|L99%'``^h5y,>zd?FAV5I} d r+7Fbػ2Ha.&0M?c~󔡦( %f}*qr> $8k-  BŦG)mxNM%Y'D$N^ߩǯŎIFҧ"bb"0we@4{5d!KP*y=_C:¨dejQ B[ʊ",/l'E}5'sCKxR):P,OB}/c6Q|ơe((kž?{5SŠ<xS%aS9;%;$.Sޏ *ʳWSp,cؕ/J*ƘE[8!YEX#ͽ;p @FGEkd|J| R@!΢uٶZB`ajrѮ!Jw/{f?߯߄ n8qȁeCr-IpU5 %8G B9ǒV\ )y0Sf:%D}U_HwAhW@!#|C*rOA-b}VSξ]{zg"uC̪sw(Tc+O"d#K5U8n5,ۂ EcĂmZ[䙫ϻ+X&7Ub)P Ǫ5 ZO&_wl':?Xn$عC)5vZH܍_ p1%WL}ၯQI>L&V/#[K02P ;ճ;$d~gpáy?Qv ڢa\eFVW4ENA|}&{1;|߶[ BhgFP,6}uNHH][)J{Y+!H#71kݦ"'Q0kb[ǙoTXk: jߵ}ҋf~' Of* g6/ })dtdlJ`1Gٝ.2njdf`V0$q:"5)b8)lbb w/;pB)?r,OٝazxAqHz}Tۜ5c[5k@v'2r'ҧƂ{3AQmaE2,7+y!w  452>ѳ'ЖWv%2l ne&4H]w:Y)#jv61!I=FovVܓ̾d'Hʍ `UԱ:eB_=V>yM}qps;TgRөk = uEmr5_'7c-g00%UIEB {M<{lx_FX=nL=Cs*>47N4`d"n*p|xr{ }wΝH|П{u2=m(J5vу> lSk&jP5Gk_D_Ն ˷e@ L;Ŷ<ۋFmJ= [DYIF[,o1ٕRt6X8iLM'ºԧ6j߉5G /!}ܟA}eB]q35B]5ge]sEgH2",d wj]$!^q C QQ#uW=] F1,lZ@^"C?fQO~Tg2Z"ZSAٝH&HSR@[sgĹz.It$jD!a8/Dz1\/Isiԥ h(\sE QoB5ِY-7B-΃cdhVGd+IsuD&]fR#KqeͅX;_4Kȉ5MeD*;hؑB|ss}Ԥ ͞Z%La9i9yxtULҍ)T";6N5>`WI-Yʵ*RG̲ZqO o`L\#Cw *(`G& '몟5=!`07zeWs{]0w(, $[nNsڼv~{H`2 R3vF2#~+Iw"$"Ҥ1Bs<jb7n{ `m4(3PƑ 9ߨmKeWʆ>Rw};(sVW`+ew?p;WF/V*;^͋JO|؆%mR~"ԞKbOLD)3ϺL荨ZhԉMxq<.eҦά}E'v6jݱֽ?G1Wf۩?1iG҈z ^2`sr&G伊 gaN+u˔[31J6GWMvӸ'HϔػqIa>]E,ѭYG]29e*scesȚ2qJ?susEm͊Y #Y 8KjsXFJdQkH'qS9$"Ôj40*߼lu)>4@6e*4@յ^d ,\QdGA"k%gm&K.Y0zOR:V1e?XWXY9o#d3׻cqFvn8ET$~k}![\u%"/(pO*׌ ,pYʆr`z%$0vtڟYvOIlzQZxc<ǥ΢O `HU|.TАoϴSƬuVT*Wk"3;Th'\$Z癫zSz'A6LwXHPqy礧@,Qbcfۮ0ЮV='u[~&Bq). e*)<(]!ːy!oV|9y=JOA/CY. GUAhu{: v/qNJ"/^g-u/.6-ŬpZ:*Nǩ+X:H wɰJ8%b&n<-NtXP,sxXoAJ h(ڜ\O[aUʫ}KL@-`mp BnEqW6Ѫ.MP5q 9cU*3SY_Qsb9,$aOXƥIzVR6ZYkk`LEϜAm'qvǩERcEAr_oMw(lh0F``n}p/Xg<hpr͊}5z0Pti42\\Vc<]AV "ŴCIKǂ-gdЏ޺26W$A""OYۚ a7BgpghAmM/oףտC;?jB\_ D|᭶8?Eqq9r_s@.F6AΉA1S5˃cU'9v c`3|7?sq@{o??`s>7+?oP!Oݯ7w/7;G*?sf-F''?C{%kwgʿ7Y׽28kKѿ=]YPŬ(*ά rqi+̊&.voGA֎vW~@F;Nkq0 YYY;k!A`vy]V5V64teQyN e af)3ZҞw,d>{oHd/;dLHXiI_T䟹,kje,lmg0@U 7a1 .&׀s_:Z[z,XZ8X8VF g}'%9~(\1ID6?  -ZxǬA [Y}+ (35߉~_k_qb_ :G߯: oU;hDy^\llVjOf؁^_? 12vn cEq ;ׁ _cdu= so2_p;w_d`qbU79;o:^e5_wvG _)eelM;~݈hgc}5])*"fbaGE E> -I,9l\@ 7@]7Sw*_b  PKeۜPK: settings.xmlZs8"כB0 CBH뛰Ez$9+d()![/un?b~ RE(7UDa$wsg(FAЗ %ݾR)TŠ:h`bXc{u*ˮx$IRY.ooߠWz, P̢۪Ey 3*U*w"7r+45m 4&6ecڝG*,_zgz_cmuBw"f~/t=CNP/ZC^L_=C)Š`bjG^sƸtEKRW 1K.# `N0 \ncҒk\2@+Z\*r(RTmՈ)DPkžIn-PC[cXtY[O~\:,(~U=@Cؑt \Ɩcs:Z4J5NWp$3QgG2=sz9.Tn# x+#Lj^\,8{ݹ@ H*Mn@Pp.dD2tx>av# !N8N,i@ O-g3 ~(sv: )zW Sp &^D- :77r+U`O5f)(-H x}{Uk&w|1χ~zJi勰řxRی)TUB3, Q/ !ʹ-&|#'O~T f|Fg#hsT.F'Si!yN "&t }%Hc2@i( E@ DRkK4\ıJId4 9T{XMhN`+ߒVK,TW";C(Í{Jlٟ&, q#fL( V埰bTJOhk"N@&θq:2 0`/;#MIčO?@8㚯4$tU UJ;>ҿT/c9X4Cײlm6 έ<`tŊ6 u8.rPKj8 PK:META-INF/manifest.xml͒ V 4R=>"QƷ$֨ZݐCSkzٙ*ͤX;;3*<0q\;??vy߼,XM5d_Y7N蛹vĚL H&[* ~?I]fݏ2a.-];m9#:?Y="ZqW.P?@A-Pictures/200000070000287200001AAF1574711F.svmPK:쭽^EP-RPictures/20000007000056EB00003AC2DA7454CB.svmPK:Usťť-sPictures/100000000000022C0000024DD3B1C9DE.pngPK:gi->Pictures/20000007000003B6000003138C4400E5.svmPK:Æ%o Alayout-cachePK:vx@ Bcontent.xmlPK:$[v1 iY ȃstyles.xmlPK:'meta.xmlPK:5I_J-/Thumbnails/thumbnail.pngPK:eۜJThumbnails/thumbnail.pdfPK:j8 usettings.xmlPK:]; zMETA-INF/manifest.xmlPK.}knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/kf_osgi_tutorial.pdf0000644000175000017500000171070712346515440026550 0ustar felixfelix%PDF-1.4 %äüöß 2 0 obj <> stream xUn0+x`. D*[Z=9M)\d[Ġ@S49;;^ږ[X29u|aޘ?G}^6CC9v&sn>Ԋ G|\QY<~:gçf84טѷD[cA8;D yrfxQػwoل㉁@/"_>9292b`]Ϙb6NgqڲS0iwbIc VEsdGQߠv,+sz)2]\.,2sJQ`~m8Ϲ nPL1"v~Avf+Ɛ"yt|'Ye\]!V xgOp%{*\P5ZlQ$UvT05ZU%=Uؕ@8C*6Z<#/mŻf R A1EnT8`F=vAc.D3/l./͗F!cUW/)tdw:IP F 5@O> stream xMo6:/C  ԉ|m=[v/ʶRJI a[hͷ4ޢut=_*_6&mCsiml,6/ 1l =ck_6aY™O]8I`15sۇH=ZiՍ?׺kƧ|=a M4nTxOp{?-׎Ett+7:_56[OOyz]Uzh*_bO|Y KQ{K&<k>˃?9xjglYߘxSd D/vVO9v^V 2^S"^ +@H93B1}D@鸚SkW9@,`5p|?%^GJei 3JiC  P}BBRH@)4HcuHлO2f<>i XQv)VyM1n+QyK7 Bا_!c@m"wk4ER{<͸Tn)2׆x@(S<.99a%'y&v!z0],5u{j֣s\g0Ԧ }²# Q Ct W4Oy2/y}$X+T?ujx!WC\CĐ_}L_Ӫ]t+jc9ůpysG^J4y8JŸm3Fզ~GeΊwsq; (Ӿ9|%Q<2D0M.""X/#ˬkq*b`%`&)_H7S]P(M=m2nJ*^d¡^ ᗈ+MbP76-LVJa Pp{zEƓhYj>n=-o A6\S"i($Ky Q$4$#gLg:_c:!_k9$we&?_8{M3$1y ]/\?__=wc3FL5g;8E`u5&u9ӢKY1W~͜ #6X` {=x3 >!ۨ)0#X|jnZ8婬> stream xXMF WIJa @EOmSh 4rJ^YnjECrvv{3򕬓O?z_<\}n8{Y'o!]r tF sAo]m3`ϐpmSB1b4D7tu&H'_}zSV9\".^6Ї"-"s=8'i`=}b ÒU7;,qă4)?E3dOK'墬eيB 1ЍzxY7fH.xӕDWM9[]I p }@({ŋC 1+KjwH8Vr`Q=X ,Q @Ýn*ݣdFqຍ9R=?5+(GVеص?w9:`DF~~fPVt>5ŭa:=EAruY8 VIT"3,Z"E}ֻuyUQt{&I' %!]p1B04sFfzŅcʹV36[k8+6ja}Kpc85|8%6`o8@zb Ax\hòretLԉ KW ^nt*]KQ?e7NCzI't6A dF34j g'+Q.-n1u Q`Yc%H+HU7i҈A0 !I0aRTZVa(D_f5qPTMijyc":˸BLcЊ~t!W6M4.n(6%f/4o~,ϭƃ{[;oOuZ6Id-J=g[rO쪍(גSJpפ]Vӄa/siWJLrU{6b"lbk; }Ň9QJbw1<]d! ,v=|ZƅK]CjWU˺2 8bX 5u196^RZa&r>ctH%rYTks p[/D>KqTWIJ Bwu˪8$N`$toV0[ 4;3ʩ 4$-@wgg2MOO7=QTיtnS endstream endobj 9 0 obj 1621 endobj 11 0 obj <> stream xYˎ6+t^`c-r[`ܲ K~?U(Q%2-M:ӿ*\z-x?w}9sT:nSYs}ᨍ7c<*ը6g6mo'wA"~aΡV_}NVBr9~x`Ň|e|=\} >kkWVm:TH2';G#pXvΥnmQ qwe*hD2?J=D9 炅E%Z\؂O/Br=  oHOѭ>Xy _ ʟ]c8 ގQt.;Y{ d#CS# *#V朘ЇQqG("Vf*w:2hIدs:ę@Qw+r#ҡs&sГnf̎N,ml )t fzoaNNyeXqWR@ q3Bp3"DO3r}Mw -a2D^_VTY?U`IXrdLl7A(2 SS]WZ u>5[^8%Q grA>H$v3|3ihe\xj,I)&u|*n. p;I@ɥݚQBD|ݺ.HjTaNz5F[& P^qqA\o"3`%T6JbN*kkm?-/-BKޯ aⵔU` +08u=T~{ͭ3sF";)m0iЉDHR5\8 IY<-jrlh W-sGx]6iK{gYeAP}Tj6<٦@RXd,)eQ>v$m\t;WrHn3 z"lH`w4*!ܖuAn=[&Ot-8Y~tOqQ8g藳+sk :gSHt#}>o~tvڞP-x#S̼_jӨܓ'gg+:T;-Eд('@+c9Ldz1<(gHn9w*i=d/Z* 2Y3QV6:ly'> }.m0k}eҬ|89={`[)'uXFvAR,ͽ3+H6b4 pTӷ6B endstream endobj 12 0 obj 1580 endobj 14 0 obj <> stream xUM@ Wy!<` &0v m^44;-$G{[~7Vd,Nr|UԏRo87,EOeTc4щ-A>)5VinΥ1vb jv|sD)HHfJ|&Db0n2xSlxŹyr`SGȎ|(gioZkAa^vZ[*XiŰ V&{D߅G/8^Kt c&0þuF@7n^t"`TGñn}ڵnG ga0)YSƆ2oh"k~ɹt 2)uc2B9[E , Fe [[JtלIO`pεqS`*e5ZjI륝Peh@V͉jN{74YE]p,D@lYu#v^vssِ:T+^^)#*=?&1m ǼX_D}3|6Ӯ0mV: _+!v^U ^]6 endstream endobj 15 0 obj 610 endobj 17 0 obj <> stream xw769W}߹|{mrm~%Y " P K(dY,$2H", ,`ٜ䙝sS===3==4>=UO=UݿzZZZ>_~yʕ,Zy缥w]{q} qw,kһ-{X~ς.\qߢ_0w"{p5%5p"{=ăO<t3O hиr , -%vy"C bs" !~NFba’3GaC|Pׄ{U@7( 8C s_)Bt@[؀ $!zhzt!]6Є>Q??+tI=%NS;Sh?-r;HNщ}VxOO(uvI wIz̓BkOД)&$̙!)0A DCɾ<*1 O0Ѥ;`* K}ўh"&BBq"ɏ\I'L',-M֖&[Krrrr,r,x1n=9u#S FFFFF1c c\w$UknoO? M_~P$3;-N9>>/S# @o2Ō#Bdf dmB$}h/9gۀIeT{2*wFJORN g}BnOȲl80~ BS~9)"4F0)cx1tAc9'ć4-DV0))%lE<,=ˏ[cԈh%6|!ї"xFX(~P9 ЍZ W37m#^;+H gF%(5SS?I6FSm/A;|Qͣ1929$Dll:Bt\okw4v5467 4rg>9~t_ih:74t7t5t454677`8ǖ܎(^f ͷ߷f͚+Wm 2Oi\uE뾴я`!EH`D!1 Aպp@'a m BE+sIמFNݺ` wFN\)!tAA#@G!l1,$VQ sTl"":#A2PN0C RABbKI9jt$&ߜ[|(y><"DŽ53sc2rV_;\D((rG~x=E yZCe*wg)=Kȋ'Xo?#}qC S|!"w\X|q` aH wZK12:/F5y:9QpUǑDveLxWߥG%h7o>rt>}}}^k'?`3/R?(>RGYIpd~~~~ct쏒8n lh߲eˀә,S(w i/ 5? >f_#E0Qč178V8Y8 2~=gW?%Z NF0w#n49Bȸ$U4(] gBAa#倚V@`H,a8!0K 4r=1 h[s·K `r=Ay<7˓`ym|>P zzF/3+#,GӻţW⽧%noEx;#\څvB$S[㐦aPYNO tK):Lrװ? E:RG xN{]b M(]ӏԐp'8i:fI}pHbqT$1 '9/"ތޗ!<[+4C›>y_8nEIx! B#dpqp|H FD*"agؗ1|#,؇-O+v^={c߿DZk=/l~oܹs}#/>±V8U;Gpv`ªth}b[t/4Ν;әs)"w1nn " @V?!A—xq3Bh`>犜sGб"Wlw)TCSJ7'4 ?i1H\ uTg\(1)6@49+F2#YP|P/ՆΟ7=xG_l7#Q] R|qw}w3Q]_Y'y4Dn+#<΋k|!rLUG:|6Y]IۄGfTyƴ)hBZΨc-.'dYCKٓkBb-181[B@cӮӽAZbP/ǧI h'!Acތp"F(Nx ,PK^F? D:]t#?F>xgD+ۆ{wVݭٻ[w~nݖwx?tHRSb8*W_zuǫOw;>E,$ {w*5V;{.;aM9wIo~='1{u{G(CI{@"†'`m8B|W8 l)@b#{*J Bd@͝0xEIs' :wys)cԌJ;c`cDŽӺ:0̛m @գBh\Ox,/t9̎#}rN~zbp_ȡG [TcD[kDbJȓE;Ԟ[BLkrl4u'~ܞKTlazKYc$"4!rDO}.5帝1F;}WpI~N֝fGqA74   JLA9T5!GeyW;C 9$Vއ"}6wэO Nʎo}qce3輻m(r(VꏶCB8֟{{>nCϏvk-d F mcX T`GGn7qS??qN;u׍}w8xO8>ɻr[,ljuVm?9?F80ƾ97v}㙻~~[;nj&pMv\)>BoǍ7޻G'Jك 8r6z&4:@EtxFeE碷-y19i ^&sUݎ w1P h3bȸ¸UuUIQt1nnɁ|$ 5Ԃ[.MFVD8$_.}GLvy1fbZ9Qo1PbgyeǞ}G9lyw#ؑΔR CsXQy4~1,<Ȕ>8OF '*qPnX"`@f=k<Zτ#7:'IgJ# ĆS`=~EŨy&Ԯqc\**{x}c҃{?_wdߣkFXdAdSj}xXEC-}14>\|cD*ʁ7AaW/g{8so;1-somwKܛ̽w-2_t狏l8p>ߺn[x[ڿ֞k[2y6_gIe|~~= 1FAu?& 0/$tQ")$o1Aa(~ &֥ɟ8Pq?N9W%/@~A :0ڄ钟_&DYD3;!:X\B9YR7gwb8<H00Êb!7xp7?j­͌ UINcE,,bGޝ}CWڑ7>wgL,_ɼ+> ]GxF=z yx xbPIIwqéIӱ!Ձӂ}{?oΏ[6~e馳S>tHUhƔImJg"`ysPH<ܑ"sl\QiG^`-1h%MQ3 ǐ/m}̀31u縦}T1u @>i"؀T1%nh@@88*p=8Oc(i[ ]hMi= h}HfqPbfweN~% q;ZR*5O·Mg?eD`|8y~/ٮy~^pc"@1-}k UBUu>{ ߢl(ȻW|q{2i?q>hl_;\OTwjYpX -%07{#)材G˾u;Wx材hq柔GՒ5 vG3eo0Eʚ͚EhK[T/80xr^byxh1`ʤ3h^{{>Z;f@g|7fC4+jLl]w?D $D 1IO.F6}6;߂?2? nŞ7!`!-a{\tX (vA!x5ZD"AOyȓwv̢k/&7-{e(N=oOhz<19Pz.ʼ_1xZ95=x,(ߞG,757T?=}M=k}_6wT㙞ɮ Q`PF5˔&4EPĞ p+fy`5.0Egv˝=Rۀ9?;hL_HOC 2{/ͽYkJV`f?5hnT):T]>-)mp~U:p4=΋MApۉ)yhԸǔDRs=ҝLizئ{G$[ m>6mt[^9t#C CS[$TS`ql_x;SC ccM]#"͟o/'{кv]ܵnqŽn|pdӃc/z|אz=qjW?F|af'x0MK6,۰gÒ3K-ilX1_?Fo\ß6̹yhp>r&yPg&EѽξAo@i-p~QS<~uҏZH<^H}p*(+c@֫f׽'ȓ,cO0Q|޼[ӓP*tEN F0B0{>A>?$'}q4)eG q۳Wߨs_g ߘ.BS< 'Țy9!XoJ[Iީ/&qS<3yZw}?kw}A̻+M]!,?P:DP|vENz_=fo#]11xCÀrmkˡSַ>qOZo;vmx설gJ<(ScP[&46<(H9 WjB,LuwHrVympZJUy,^o[h;FUm#J ֡ip"7!G|╮ixRˠ GTB(^n_u]>Q<> ˃7":59g&Liw}ghpӟc:!nX TVH~s mGF4B/ g7BM}prdTdBjɛ;ܲu][voYg =f/zqkFlw ?fd_#ϯ~a؋kX+= &^X7º n}߳{]g['̿)>Qu?w B/>Q|ŋvK+éG/? 5ȣG;Ne7{!ߣ)y ČlvG_h6g(>+@Әʱ?FI&b;'%|u$>ZL9EOd=J .z*|2xN'-HEQ<œ%;E2oҜx伃Gw༫O.~%'I>}Ӊo̾o $`4"z~LDN'xA6ۊ'81eq:))O_w' V-{=p*r]ؖNd'wf) ctX]h?5i&(Xa`z_g#5}e5=rS ۆ&Ό '!rDW&9Fxk&]`=Fx[ICxLt;no2@$0Q ǰOO:5ǵ'e-AYLjGNaH;ꢟ/!Ni>ݐe4BSZ\B}^q MׄX5gBm砼}@'k퓶I[z'S'ϊNvNOH ZǀB0=! 2vV[{p R /H~zX)RZzOl+όĶg۷wlEkO+_{JikOw&0 x}-7J^*܎0}[GmցϏMrh_=Z^@?_xb!6y,Qo+CI/WP<xҋD> $xP|:FQpk荑qd^luOcBHr}8lLr:Ň )Q< 3S}{ؽ <*"zぅĝIC[xPMX>K{((^O[JhE3tQm`DZ@ p^Ӈ5~<=p"L;{DछL:w"לzA ~eDrvNh!{pd18&\v_~.RhuVbhMAeDP<NEl8G"RLnMV!\gl~=x7?udf=Bv6;M&g1&&cp$jnvnvnv`O7[:[:;m ['N?nNm<1:0z׼x^|ADh?.8S\Ҥk1@,h;9p&hл=Q<DEhq9?ذ|:w8?>ͦwFrfr_  7=/7.7U`V;_K64χY6'ƌ u1/JM+q7UuoDl h%CPc νnAM8owԌm}pԷ ̸y./8F:mGﲦ 'eQ_o@cuov5&wBֶ0.4Nf Efgz[@.\G`JGS^8 K̨\WxDa@jr,솤QB]i>EFXpKW1b2qՋ?l5EV-]Eb*>? X|_ ߋۃ%{,wW~x^xWZ~x\䆫w_Egu̻nG[\=[F S.Ӭ_R `eOW:_s!4:P%={v$!\?FaQDzg8 ?ܡ[sjy1Wp zKf?ZpxmDz3"20ǪC9Orov;.̍o>dd;&\n(ljSGwι"WJ` f_!k8Lګ䓶9r)yӟkmB|)Y|HX:j/u!}/??DM޸IqR}&<}?tGfsP -Rc/.pkËl(G_"\߼u'd]2yYOG- fWzcVkS6 -Uy[#F+t^kz__ S;'XxxˉqQ1cΩy??pvmLvV1mB25pA5"$5_#OȚ%F gX^j Lh)Cp\$~DVh̆f=wW՞)^' 8h݇yETeCQ)(Г3I`qsBWlw0$EI@A7/OP'(f!S&1"$IfVQ@1ڑ({{Q<^`v"^"Hd*N_x .A*w8s+\Q9qR6ܲ30QFgk:o$m|)7z:Sкk 8A]r+aHI;C`9en_L/{`m@-p-cS|m2({Ȏg!r -$Ń i /fܙQgU>RZV60wKߠ-&u o8! oEAMa ZNf͞X^-KjeѤ;92ƀx#@xE?@jU";;^ΎFKg9h6ܞ"N[/@dNt6ZX'+s)ZІ%pNL!%Z7J"i5т3?xm:3oAe-T Aq5WF}v%[mL sqz+x5UTETrL^L]Up9UNmѷSe%jmP-#Nu8Mjo]gٳ@=j*i>5wRM "V'ר'֚!ozrz(/D>$!<#+3K]f?Oy+܇$Q+ՓQ/e߉'֮bS|: Ͱ.6[OOnj@G4u>m|8twGG{6|:'kHCJ?i N~4hZk\dKI#/ud0c؉ӿo>;b=G;JG0ˋLa1,2Sm,!w"0|G0)%h+%IĞ5IJ*n-&GAbKAp%`23 ~M9N: "gWeç7Xɉ]nˍH?D|GD e|h? :AG >_'_OnW]O}$k,lb|0.|6afw%D-գLQg/G[͆*pʶh~kʌ5;,k=6wq~L~e5ez"ܧ|+%{t#uѓ ˆ$nm*-^v* ">D(1cB UUv Ýfjg! ?%I!{ږ%)rq7i{$y9VBr:Ux;Q\ȋKkb f')ފyYNz#߭I` _;'R9g#g2%Bvpz?0cu:i\QAC`d_~ {3-g$bb3್i(ʍǴu%Of1+# B؏ a"g<9Dx(DhB0"S&3Q. `?prS;|m$rkד<w]bWIxb Q)[M@CO;{Z7 u{=yhߚ?=5vO~b\)w^^!(x2{T=Ǧ2Kr5P؂CG\y8.(]ik`SX<6ߴ G=U`r"Ĺ|78\T;jk\a- @cH:1'NNP8-& ؊عw#ȱH=-F| J+E D]7#:xZM3>Qv=1'"͘!SߡIp (>ʔiDOK' mDj`Mn 9jᔃܪ}rk h\X1lq!ndj(@X-Ctk34ǐDqM9'e3B{J`M[910>2aD # 04bI U~%|AuB0!h|}tf'}֮,R ֮&*x@2i;9im37{:Dkzho<7|O:HUDžvѭsz zh}[#@G`p .#4 #4'2yDFbGbI^'WjJn%1FhAxVUm)ӭ^%79Ѯ0;-.1mu+@6(Q?R;j'jUV!jq5p8CZ'P'A-\'5qu(0ȲK-!9K/a{طS|aG=˓ jē95 KOj->fa] u6"YEHob#tXo"Q3Xgl)н)5:&얛= {FhMh0 f*3FG@'6١8UhAhVɦ*"}tTۼ1 Z^hK1dEkM}ib2pp&h\O=:xk=x=$"h#ZGmbӀރ1 HM# ȴ}PjOT2,wF_ Ni=r1B@dM+;Ĉ6s^ ahP&IlT Xp$.Bmw: pUOC#>Dr#|@uz}8|. AW H;pD?!|GpB# 7@@#7"/%νq8!E}8Foz׀z` \8>OxI/b+̆4B:jFI n~?0˞ܪMϭ [߲lkz`y6޻l͝W߹x Wv.^~syk7,\qMK7n^YU}5Og{b룏?'ްoXn:ϵkqqBv*a՚5<(8& ?#7L7lq.d-JPR7aPD?Ɣ&d͏l|HN! B v>)Gزfsk|aS/}l?,_5O-yt3+=jp 6~B4K#O`l^jӢ՛C/}oɣpyUp\5,~q8WGMy|Z}GJ5[Y I UoDV‹4Z >z#Ǟ|Ȩ*VeJHlO=յ#%|:/3)K8QX;I/fpKFɕ-PMŋy4c/sO0ɑY"`"iw)ZRqSg䰇C0O}2,/=K]b /̘{Od*w*OOQŁKd}s9gTR eyS=ղ [[2g˵-98_zf>ؔV1>ꇱ\r+/oYLU+I*G7%DF?8@߾z?S:Psc+=Cd}srlIٞb=v+Uy6=/ħ8 ˍaw.+ȢK5„''ҵxq{އ(n}ؘʅWsYf"#y?W1O46x>/e=TEI˭rǙįrP%i= 8/7>aJY2 IJ_)O]e5O 'B䗿c#ӎa -7zB~PU|_yg993=siˊ!J%e+;E y9mFMR@q(dy{QE^}yLWo%Ipj2U&!i=Ԟ|v#)m@|?&:1Q_I*+"Ԥ&2#w`d)k'Ѧu.7͗5IMjR|rwz?@$!zGsY\sU]=V$!|פ2#wQ~{o(Fsl1 %~u 2%Uuge&T1UY\<_b @O|$82󿦛I ¹VŤʑBmh ʙvĽ#Oy۞_ϑ/,_2~孠\v>8d?2z]\5B%% (iM* AJGo~;EIs4GsΨ@#*,a{^e'gAd3jkljVȗMhԑObLV^rk /ηdl5ӰD^@HJ+blGw͋$2:oX"q w[pXJYXvV`z_S̨a#9G=s()>/ۥZ}V/OR#τTó?rӰDw8(~(Oa $gYXv򱇭,dQrq&ZoiOkO>g1Y៶\{rdZ~mCp/YiRMLxʑS~#CyYor9C;Sn=W✭|{!$_j?_6ᶧ;+|+~>qSR񷟣CįIur/ޕP9hNdtwӄʺ-3kGY§P3#srXnm+18CUrU g˗Q ϧK%Me̷؆宄rIYRX>GI_K(Ԥ&_=52#/dxvF\4M_K5Q&5ősZLx|hNN<)-Gsդ&5IMjR){jWm雌ڕ $D{t uu=T=U)jY2LJ.a[ܝ/U_rQ?{h,CIrbEE'|xS5㜌đQrWWRŝ˅΢뿺yP.ff(<3G㓄#mu皭,ICįɕ-zi5b)5喠t݆7sUY%ULU=B.f5ۮr]4>񹓔n&)N[jrJ^|4q' (F;ILA)(1z+[i"#[.-g9\KL[%3FrtIuX2ΕT.$l SR?rS)=,<3+يƝ=ۀ ʼx4u'zw B5v:|>AdVEKޙxS=ղ [[2#嶓͌s%G)Yό9g˔\lgwQ/Gs ,)VqCYVܗʪ. ʽxxxHbJcj6=E+7qߜ=|y)/N>,*gYv,~|rTaO+IE._TͰr/qP I)jrJ^Γ@:@ll/#3>G ?tsvz mӝs&S.6᩿X(>]@mPΝл+)"jݍ(~"*Υr$Ź)3$I|VU\V'u5jP*ї6RȎzDI)P'$W֨Y*˞ !Ф*u_fh U5KXWf8ignRM&RϘi?]DϘ/VozȈi  WSg䰇C0JV&cxyw)G]3gaK̨+ftk6V4CYM&RC/]Js4xs3*)<)K؞jYЭ- C? |(.w9dFLG%|+\J/%sgHIjRJ*UTOSРzoHBP|$1(p紬XJYr6=/])΢d/]3 |\YRX>/82e ᶳ&_̋39P@)3x3$p>8%s|a+KYg^ec'r42%3>$Jy*# ?I8SPT)7R[ VD|I993=siˊ_=3s&%#)xRl?쬠> z/;˪Ԥ@* 9b/>)1N,V[O8e BN|Nz`"3Q~ESWTW~>ʹMS.>K/.w=,&/PȘo J82k򵒊xk0xD$Pq]WXl'UY³bbc8*;_>uMjRT?p\kCX}@~vxRghm>-f/l ibKR\~(agRs `CY5G;dXޯU؄nOXIũ8gFq8*RB,ʺ&5X*2{o]evgŧ [}`2d&zDc3XsN>,ʵT-=|",Z.6)+~wVJ[IũX^$ʋ \^bn'w)mRIXO}7&5L*x(>xVu֋w[Q' 0BH|u ]*뒏 +ya{ʊ 磿,Sɑo9[xI.oɬ9R˧.IrŗM2◫N#,,cKʘo 321˾-|SΐjC0ä+)KB2K~e r:;Qȇ:L `p7NO-טğ /s$~ $~ӝd;r[A9ZJF^n7[Ox#sO.sQR %G>q)+._g>{|n3]4_B'Bc[#KW@ uӽ--ϲ:˜hM D+$(Yt6yt; A <0>O/qcmv~iˎ톮=(zSlA&# y,W# in(y5' -?€-lS7|M[ш[eA0ZyouIxʸ@ WV7|P)~qb-͑K%/,ݾ;I7Nυ'" LRL?2.- ݉IY8냌 Ý{]|"pi+ $ NćQyG/ťϳ1ߺDlIX!;sB bSɕS|9+_\:59818n'K2xeUg[ع2U! )ơܺ~{h74ls+ZDhs kmA~OMvKiHDR" !3:t-|hHl^[B'U׏O/60k`B?;2u1K ]{ޑqub dP2GPލ|kq|S? B^FLw^[0`l dC)~!i;kٵxEh{PTO51/랬P@sch pӪ Qs-|ͨɆX FOoP~w^2?$1#ײ<ݝZ)A8v^4 y 0$X{sT_F#RƧv~z}@^`Vu_Ȥq=BH|k;=15[?]ۗS;Q=v;BPs "=B?ķF$ eTtwMlsOS$a-?{m+^qtr.7+Hq[M %OP^ V$+h~b0w9׸!œ@ a|%~4J/ K|FewzYgziǡ7n^H"f~|- v1s'ϭҭAumG a $|h !=.>Y5 Iohrkk2?wSߺ{FDhsKe22~! 9(Yt6nB0xN-h:ۜӷ܋ еAEJWȤ0|dP2WcqzP~) q3B8xuk0|JA x_Os#9uCLGgn۹ܲ{gSae!J ?uiȠ䌬~^0꒔TvY7L\$Oc)W/4S|npvp̶]a!wwz.D]``qkY^HNe0ߐ~$yccO2M w%Ua\2_3A w3[/mkΩʩg?$~뮇jկJҰ@ ;ꙸGT>zl뇲jAx`-+Z;@Ђ)~tE#uYVUUӟQ32}}N@ _fTWtOmٱ7@(Nl%#euǧfPXO?-{ y 9)>JuNu${? w!\k ;pgH8T?2.Nn M}/IK)KW$~54 K|PϹ__ig/JBuBH 3X.( *KLd+aU)ytY]o[K_7U;Y=~-y "&5(^o\7%O 2_*/+!m%<_|hC|?|屮oFß{Y3hKv@K)rKs zV}u0`Fj҂Vj!W~w"bV Ż%zV kU9o&8%Ee< R7-L:: ])i- cD[FR@Al#tҝjxO^o\)E-ᆮ=(zPBkc dP2׭'\g=j B׿A -J f͏8?E00QJA hH|W^7:5Y3Yw?Y>۸`J&xX\˲Xeo@V.IOdjQRrpiL@ЅSvwK9Vsc`|ӝQ/^sEȆӏ_Btw,Ҭ[6!>4ܕTqyB?@8!v0?wکSLZw}i] ǾrDl}U^_,sN )i&'N2? .bҮ퇊ZinqD w~=O}o`?H%Lgt(l9PfvSKqx@ S|)v~Xcƺ?\y@~˛Y-?B p"{ .:$[I Vyckׅ?oXk!Jτ5S^7_5$w=R}pQ;y-'n޶ w@1s-K >ky5mH9x!\|>>tGb &g}u5=cw{I|ɚٲI&8{åg?V{HIMwvPϡ@z3k$p@YRb U23݉]aFI  S|DzfKǙ U>\18qKŻܺ{%oaI 3 WMo$!oWg-+L_fۯ AkDd e%c05US;χ%~>şᲫϪʨϬ8V5!l +pJ>A]\yG/W Jz »+*k>O3ŭc)+Ϭxn[tp\%1H!oakA?lLo#!@X 0;ŏ:?_;WֱZWNꁌ*?muC?Z²~,J\[݉7Sϝ9#>_! 4Vol/#T=C(l fxGkʳ˘ijS| ~[+uØ%sild럏k^#ؿAr2(k)k2oc>@Cd m W΅pg,D: rz $Jg}czΧ};Z{HyϡҞIk@ r6FRKRыV:"0<ogy[?2>w`i]탓[vMt)34y|S45UO[S #GQځN&CO B`t%aVyE_<#=˺O'OˁP!JJB6σ{3ϡ?ܷ"ߺ-JBTޑ3**:M dZnJn ً!(udh vqFi@b`cHLPOQ%fI7(xcE&KvKw t@ $ Nwy|pbkgwoK:w7Nkޅڂd'2Y.!uiPo|PNiLP@ϡ.9&[!`pJ:ʺg+{+{%;-h3g+w,y[aJ&Hȼ0< JΘDʾGfs@Y7yK@H62*eۧ+6;UV^[9kq뮐du wwz.. LRL?2.- i2ҿH4ۘwG+Eceu@)̿ǡ0.AI! ap߶сɒ9Ė[n|#iI~݉N@ S]?14w{U;꯼nd|PiϻE{bӝ{B~ 'Cd{bG6σ{|jET ^s?m!0d_aˮtJz&lȽ^)D\8p^xn)G7 0 ɜX*_,!08ΙY^p7N.dOL<]?$go;ŏ2?Ƅj>z8)T*3]07YjsYR|tCj_V_o#s˧x¼t 31<08ųyA֬ڡ&?kW029V=th&CYVXB'BcKXk xn-@^$3$?(xc@ݔ:6$nlzd)vL=Rs@qqeW]?<1wwQ'kotr熮=(zRBk c [.OiQi@ײ qOAx '9~`<S:\PI[yL?s.%SZnKsωMwޏY>-?voJJ&fCV+`[+~KD 3բӘ*l08o[{v)yIGXwyr^lhvo,<Nυ$" LRL?2.- ݉IC^?p(a1ZGZ6'&0.AG . N)~h__r3o浳;SWj3t2 !|x}I | [?=2Vw}=P~-s/r[njƮSDvܦQ_ :xΖ~di?J?:$7Ձ ?y"~c{u!S{# H n7X5S1U9]>|]ξU$®7:w?]+D\ʭR%q'*<}Eםҭr=06XMpr@p`pW&zV=|F-L)_vag[Ė{CoGl %ѓpJxT `!!%iq2 S_>U=p:9r_m{3? :o!ՒC0ä+ #*`jx iu6,tݣb[%%LА9:4)#)~9]3^s_GsLs^m}#ivx8T:\B? fU@޸>O00~dn#_QJR »+0׺K xHO~G}+MMݣ^uVЉ3[ײ|u R7-u1'Ux Áu=LuV:myMVq)s ~j~jx%#7mеAE*JkdR>\ B(#c)eQ&7x*cҢd9V^F p[Rx@@'=Ň%u۸`?uo/S=>_̷~1`HG%`_g族3JGC*wwz.$ LRL?2.- ݩLYHIi0<1s*0$X{>4e<-2zBc8e!!ͼjVӫ/5tܼ>6`[%! Kڜ5zn #Sş [^l|9ŴgkY) zn 8#SE_;2bz^LںΑH @H<_pU=#/սVzFwI{ '|uHK$OVycU'(}/# /mTFulG^7[Y1r{ϕ $3?>yq:[Sa0*O>#ҭA@R q @df!=p\0~dneҝG-2E0EXe?>kdz/=N~un# |w"N>u%,4 HdZW+y?JJU2s]cdddu j6)fU""<ſgշ?|~슖i+uC?0[GȤ0|dP2T˿:B>8_%IL~?ctCGA Y)OW,n}߻oڿxי%̒ĴCl)IS7|M#W]ʠؿ[᷺$e<1@ WV7L.~R .̿?PO `m /v.4;1D: rWR9 )<~qo}yn}w?^9)6[/k)uDX #W}G(*Zޙ @눰)?w?w?g_q @H<ſ/S~*mK[Br '|ugIAar>'2$ Oucb<ﱞYP yIfx(mLs?/˚m:@1s +8Ji-ـbJ`3KsU[]@`aP7YenS|__pyw_ȭhہG%M(қY\QZ|b?+]9ܙ's<CbkWO)n0> $>Z5w~ǻׇb~U7 ?!Ք~![aRÌuS-篅[|Рcoq_V 8_@Z2q^dWJ>HJj=`< 댏7κ4dYȆ{LY_K|Eƻo~o;)<5dʁHȞyY>!l Pխn\^7@xb0t c' Z$O?2|y ț Aٌ̹2.S7 ~NۿyC?_57l8eϳAϩzd2pK8S[#KiGx_4%te-p^J{$=.hxl`aEF6JV]>9|w(yU)>yH=ܼ;G֖xLеAE?uJh=r~,#H1Í+"f0/Z͋ 4DŽ@ 4%9_Y7*y+p~H|$` 9e>~ꆯ y?`?M!M]aPO?N L]IU%gxOEuOR"Hr[?HLZڗßQIc#U*V4 B,k2?|)I $-btwKқY\*8y'㐷%4 0)4,p;("![2~?|tCj.pd?o`&sv=>¼naʸ!kNBI#.weXAB'BcK#(i@ naAYJI _7 Udh 'f= ?l_vw0EXuIF&{[aXN=(z+e'mP7@ &ko@U7@hdxue'Z>Cho0B(S|y5۟^sIjl\~&xX\˲LuA'{ 7'Q\O 8?I<}Fӏ_Btw,2nFAL=LexZܼ |aN[ le?b:H:к xx_X@{9jn\+ ?/oEyD6{B,avJ|Yw}#y>$b3\3#WpX@+Y΁>USO>&L ,w ` )J$yeuWM{[H|Pσ#fWkX ylR͋g<҃O%%B`|Iw|D>W-3zDa?-L0aF~)yd| _iA^>bco<\g>!DI@ɟ9Wq[Zۿvx3x䇂=ѕO(Fn)cu![/2~?|tCȖ'fvtԵ.X+s W(-KY¼t UUIO9GT-Wl=??G;Q~=+t"4(j-1Y@&IYg+%1|݀@'5>,. OD@J(8_<YC$F'|y'|?=?k[d\]'2Y.!u &kV$ݸ|~W_Y4*b*ė~v_ƿKH(-lS7|Me7ĕzVp9 ! x\~c_O߇z~Eȸ,/$Own2?J?!o_1|uo_WYRHJ{]|ݷ" sWR9(󅋠KS{g-pwn??/Դӧ` IZd@l~?=W~~'SB)>ү<|om}goH @H=Ȗm-tw_ȫjϨU4 c3ɑrhhkDŽ7Zm}l~|w~WJQxx¥ZH9fi?}RK9$(n`Q:ۧ(<ſߖos+[3} <Ɍo@+CXwx{xHrjyMB#SE$7?]*+n煿wTS oagG~)yZ| 5GY^ʸJ?@ٷ N0c:h7KW̐ 2 sKffVgCa%OZ%'<ůHC?o‘JzTZ/օyV!0_ټ]0>_Xk>\BycY}`|anJ{V,嵌?C Ȃ~OmQ`se\8I,)lߴ,~O g$/^Vp-[5@Uv NM0_]{ /2)ZGk*CXĄyɦ);RK-ZK˛3'2Y.! JnVT:b{ dIAoHWpMGԽVf4V:_]9J zo֔x[80 ?uD7#ϔaW,|rG_Od^A][+˾`c|+ ,dFKnzhE! wwz.A_<~d\ZS+_,3=!aݼd0<-/$7dd) y aq!e/W+YatY^8/< P 3IS|%$HZș d˒q?hB`Gw,Ə Ej=~$4?Փ7c?fOW0Hc0ㇷKOV$ !>yH|6% s;C%oaI 3 WMS ,^FRDp\>2`x*kU$̬B<1CxćT:Ѓu+z7bu![2~?|tCjЀڲ~ՠeuX"ߏ=S[F\TISGs;]{!t"4k-aY@{ S[LP_VnTPC< uVaQՄ Ofc W/,JZDQ}t#2b,D˧rI|Vڊbe>Ț(=Emd3p}"!8ݒ @OοPV! wwz." LRL?2.- ݉IY/ٷP_dCȆkVe<-p^xyBJ#S{KtXؚ 3Q$TZ@NO+~JO6 DXP 1:œX{w>i9Jka!JS$#$`E#p{@.udq5~0Nª)~@,s^GUH"f~|qV6Ac H OF3D, օ,j= x^?rAI|P؏l@z3k&pJ=0Uj `] !%c׊$!b__|klPSR-y?Dx S=LjQ߸nJH{ЕyV!m!tݣu:_>|VZ':~|qtօlV!&]?i$+0/[ع2.<{(@77٪t;Љڲd22?3&*n[0"dA =gJ-EMld럏kO(֏= (얬n\@ =g^H|(oas2?$1#ײ<ݝZ)GWJ8X=4e<-U=N!+ )~H.$ 8o6Ux\Z_%Y_%[*n Iu2(1V[Oz&.VYwBQϯnT,G q\`ca0UL^{>489N:'~J^A3ʧsxݷu` S^gh/A/c?%`XDvgtLÙ؇%c+l%")~`dIR πpΐj~![aRÌuSهpWHIRٯ {ae(py I8?r0;L,,.|oJ|HS=xi[-օlVpd,J@Gog=֖%4 H݀[e ?FB `/%_O-ޡV(!uavg_ԵPr9c?H]K@,2O, 4֍xAP@ϕ.9<" T+]5^}n)Z~!~nbRNT\2J Y7L\Y0I@H : _.c?wEC?x{ݝ -K6D_<~d\ZWu;LH\z~sjkYi+ E%O z4g[;f :犘,*% 8U(¸4hU}bm 6?r펰?$>>1rGQ50qWk^KLB{Y |:gY},֋@0ğnU>z]v-U8oZ|bR$Zb_B>@JB 0&͓9-"l;wC[|gH$a?-L0aF~)yC|j<|Vk^2`yfL0uKSg>!&4.;K|VAmz|(rO#R@^zbu!de~p*9/e\eyY"`0,ndbq1QBq%e[/v|#lr+TDhs陭kYR|pK~TK@J(+|?2lSvw( @|I|s;oxz5[,2cw%Q :G"b so<'J%^E TO5Elw%LZ^- LI!$3x2B|`,xG[&y퉟Nυ֖"" LRL?2.- b `_f럯sLV0.N@Hgy)~7U R5@ [!`wr͏:s/V~8 GJZ T"!)A>lI @HɈso-?Lx#pNHSqRggLFT~E?Ǯ-Os7S-ȿ,ďt&SqRA$~_ϽSܺ1K95!'n^VϨ%2P傰#'_7YjXeBK%OIpL}0[U>Zoy7',k gx)H2+ZtsCc:WC[>ZyBI :IdDsKk/uYnNƁH.[L)I~!7| ep DI )=psKlJČ-J=2_e,!Α,">yBG. 7^⟸nsz$H>dB+)_C) y"SZv@ 4⑈ETxrܒu;9^D&ÄRvMYS_Yn}p0~]NDoH<@ 8ÇOGT۞[x@  $~*$@ $$>j#'!! 'aU#B-wQOO Bb=S|{:H @HQ+E=ܶx@ C%H @H4n'nv}$@ ;M([=;x@ CWIW$@ Xg9I<@ I&/耗x֢$V&!'!أćU~-yn?Z޼-;n;{5j1m~m޲s-t7ݾoVnݶ;7߳oGfsw?=}}=ڮ}`k?Nm7f¾ݱk>fJ?nuNi~ŵ)_uX}=Ջk׻N,-K|ğsާQ_[Y6=768>4jS6(hl Z6nΑ.֎vhI j׈f<:mnî}-n'Sp: ~/>Ɯa6CS,qϔ Z6jYֺYцu]vkke'X,V߉ŁŁvr`S NW GIcr*bɾe<Ɩz{FzO,EkKډErczۭ{i_i='mt:|?9ɶpk_i#SgpM|]ɥɓSN;=+ד6u?C>r;m/7x9t͓iZ y>QWaíic@[j mɸOdsNRB^A~Yg^z&"O;1_)})ᵼwJzV DۭyۻS#ioK[E]5ٿ["2VՎ׍ZF[ÉX5M&vu=-ZFܭfh0ߎT6ķUP堬\(Xz嶿_d:-|Q[~,tZo䷿z^ky嶾fA=GY2NDi-k٬5EXvݲFh;oSVKȨmZo`FA# cy-3ŝEŝE] E]E=KE'{O.S+9UйXй>:˾ڭsk{-;mӥ ; s٬Yv6q>a>v.n.f֪fmZf0cdձ6m-f:r*|Xdzd:Z6qb"j2fҪj'XkXklϨK9n?Ç*W[fimVzYko]Neރ} f_Jodz&r':gf g { 眯ݳ5pZ^tNTN4X욉|u0{gxQȅۧ_ܻPһXwdy mbyke=ki|v3SlOμu/wL[㙬\+˟c3&[6iO[[5ews+ٺ|{ZA'k "Yةy O߸q_ٸѧ^9sSF^*/psvQ*o7fg8dӗ4(@I!BK| }@W$^bg$VrʗT~E9x J噾3g_.ȿcɏT mUJ|HD/:GNAe_VAʋ^*񮃼G(%ugyV gr/>Ga $e}j~9N%5%L9Y_/> 7cgKzN1q[-rjk歪ynseΥͦΦϦΰ^0^4Q:Q>Q6Y1Z9kSǘLMə2tu8xZ`p k[֙~Q|燁lǃIc]g;eƾeڏkMoccGhlSĴ}gtξΗuϕtN(n;^:\vu8q0xv#xNDN39v/]H&Tzs~X+~4OU[n_ɍ7m}%~ 緽$R ~]_zJlٲ1z ʧ,k*Dt=,9?dt{U^xu}A>Ž_׳dc9ۿH,InȶT%̦u'ؓ0eoӅ]+}taS5'+cENK˛K˝=;{Ě=9sv;|l}{4o:`&-&x:h:gmwN?2?m౉Ls'ҋW,?$?gj@Y;l(y?*Y%)yv/KW *Y{?G *Z_hy7k;mywndzٵf}k=Z1f!վhJkaڷF h;ֳܷ`s燑ٿ{Qy5]6Z:T2P˾5eTwZuiՃ4<Լ}%=KIʎlѱCC6v>7?2ER⽿,¿{mb[ su޽3|=Oxd}ijԨQFZje~__s'x?}b?[s.'} ;k'ם5jb6 mElѱsckgg#ggg>~\w2cg9οn .ۅv[l,9yf:"s3 /]u/=i^z:\b/9묕vs]b[2i.񌲍vγ0 /q*X./:c}>~W}by}rgwվ8O/":f9C"WX\̕.d/r.X;q;L@Y9w٨9|z݅fVO;uk;g?s7|<6;gowx~ffdf.jp .knz}1}g?>I endstream endobj 18 0 obj 45902 endobj 16 0 obj <> stream xXUWјyyfhӌ=]EEzH;H E E(`oIILLfɤL&wk]N_~v9g5kH$Ys`^y ~ ⼷շ;/o,֒W^ Ƣo.V~kKUY嫁(b p7X] ~. gPyD,! \O173ӓ[#$8OIpU,Sy{ʛKXr__շ{ko,yEWyq/&K u?΀ OS~^wxCq.Oq=zmU_R')l3| _{3+xUXGJаR8JzZ5blӵ6(M{a^>(t0pںf.&].\vRc WMMƒe hK[\D[琷.pc[_CpwȗO.~{lRrm>;2 1 l`?`x\ !0v`))9Hs9BP ʑPK0KP-5ۆsDG<([h{cǝ✃54-,=<HE4{D^V5-?O}8a1?8CY`h /їS7{8,/*+Wߪ(]Y|~e+?.qM'r<)~T|T]au%we7 7˦Xk}6Gg͒Kg .3t3Aгtd"f'c2J@7d5T6Uʯn O0nɯjɭlέh)k.k*= 4@1Pϓ^DQ"{ =)5byJSH0™a9,>,.JÓi8Q܀[2Ǟ^D a\"$_ $96 ~;IHXb~hG7{<;xv@,%X&H_ x!':ݛ :ⅦD@:^[8~r#PB\^P"=4=dj^_/ObmE9 8| ;baq@+9_\4,v oFz-Ckt1L9_E X} 7߼L8t&g(34e;͗(r3EzL3Sf,zD9#[h[Mn6zGu @>m 54yi(BgϢgLV| 4)zEl>ĞFPf3g{GVd܌~#W;!chR:]N `h@o5Z/_34Ьhhg+ҢZXc <:@u1=ӳ-|"&I^T2}|HMN8I#w ȣ1C3 M]04wGѶ`6c~krM͛L󣆶 O9ԇ֗`$?؂-z_14FCi0͔ !9l G,`VdhxEµ}5$ɕG%1/(VC=uw)/>>>~=?VAƝŒ{ 3fDz%&1C)—Ae~X(Ar(fQ换녙S 31WzWס|^ؽ{7NC0DF ͂YJaTjq f$W1k(oi=[>1uTŖֳc%t_Nuon>3Ԅ 6v'ӽ-=-է*T6"NJ9C!e %mbkV  ;&2ftq[/qOl/xN 21" {tL02Yy ~K!iV̐(r<<)eŤ"'Jb͂1RF$ '%%懠'7_N0ywf0GD dFeD:JSךbfGH.(p3 .5p]?ii^u:-V0]\ji=S֔r иkH ̖_1%%g8DzeBwS[&f\l\2mK([)bC3C[lֆ}op6d>-I㩡3fhf MKO312&|K^Ē&ИЛ=E^E&g n&tOqhyJeS֫_[o'U m1=K /;ͥ ͜8mr MYZE=M[dh{z/2M=4=ttf?snhGH;wӽ֞Sg 4u4d!mxL88 ԵPj[qS{T7R ۖqs@#F9~#{:;ORG@m1%m <9TNfb JNf\*H%1+Lʣ`u\b.  䄚YXwfSd-bN!, FFb_,kHG QI:!v! `Y~ޑiv vǬ=Xy2vFCӶVVXd7C{}T3YCC{ m^0^"#g$'Ćfƪh&T A6fۤL(3ņ6gh+'T2|=<Hk$HE4ˋ0hX-)7SlhRqSlC _ L4y=4e3u?ukuAITm6W8Ф WEh"4=CCczX$ ӝi\z^vHD3, ݌ %m6C,BnLa4#;H+!i M<)@f?Y1Cc&2y5/,i|M )KCCsbF >FJH< _78 HZ~Z&88j̜Y HZ b5ؚi2IZw1cNLpEh1OC7s'G'wroܥ7o}(ٟ]XM,'B:ۿR=;3ve:zgĨQ#QQ.'FM&F]KN}+%NJt_tXo/25} >:r/5&s=9f*%jJ̕qXJ̍S[7R=g5TϘ傀e*U;{ft_ukok'I) _:D^rO0.\yxq0r>ջ#wWn_y~×_O֝#Hv$e=/q*=snLHg> uf}<=+^qi?{RڙT{|933 iRWp4l<3\}C=i8>N&j"9n3N chm;Q%xew|p2pVv`u5zh DIT"bf8/rì޹^gm ./i-DZ ifWr\&Y< ʑƜ2.\v2VG6(m+ydRq~.U[X +FINc'սvkl6H&d儷6A`'5Ack13S1NSYx=#pYN>P( LЄ3)yC$MqCSi=cl=@X~y&1ShhLOeHa>Agb7{ָ\)ӝ'gqz4 R KRmvx>̂e6i֞!r)Ni=V8l[q~sNϘߴ!D63C= !5T1CMf' #idQC#3P8I 0 i$tR4]04JMg)DHq3?g`k#eh$鿗 UjTDp~LLMR3iXvli8q ch0oh| ?)0H0&@g j4fDϦvi9wam]._!ޙ^X^78R\=ǟԞ*??f=x6ȧ/ا?g g8|P0a^W½{M{_ rpqO]|<#|n"L>>"F".F] ??Y_mN,$+QPdVmkkT}m1p eh.zU -CgΞ286#cS_hVtx2qn?r'Wo?v'>u'=GSw]\͇Wn<~`I`ۣ~Kj _:4zuptr` r29s$.]l/MiJj'/\kݟHv?; ԺnU=CcgH4NA&:rԽύLtfyLM)xT``TA.rwj/!#uYLE?^sH\W.`[4b(ds}'OlWok>kk: $RzjŴp[} 4H]@nEDI-Lj-J[ktG EI7פIfo \33Τ"Rg'E K\]V2eq* ;Lmֆ= ` *rz&U&chVULq꾱K nfd.E)p3l8!Iǖ h:4lF7L3#QC"M,N04}x'GL fO n?2exXLz:{JM\i='f"C =cyL̆&νJ)|iCzPgOIqJUu$>ٌ̂AC!24Lq"4zF } m:54+RXszf-)B#g6=Ȧn&ډzF[;H)ub4\d~F'34"in h ƨj8)AOmԧ/odIwZӤ'*kh\$͇I&IVƥ>Q= 0ÁFdv'l 3csi $MlhN[({B]CAҒ - :'-pr R|ɏ'r~]s/WiyW_}w8 [ݽ{Y8~BJNi;ݟfI%Ek]Rnq5mxuŽ l\ػiM\ci;4<c7BmT.V]ԡMuQ˦EMoZZqie뗕zƒa.ӳ\ZoT gԵYEHTʉCvWL]{2YesWC{ߩs'ǯN{<|W{w?|r|م 9>;Oӝ;n_56yr]룽sRˑ 1<{4.OLL],K[į|څK._;?~|WfRL}%KpioNި -k%[Lם5H{ #b'_$UɳrqK" ZwKCc`\'@\ɔJY}ζF3t[y0lO=܊ t"]R: 4eJxQl ݮX3v ibOO<8묐4t'\d>+Mi2ŊH٪A%% yձ`h!6Q&NL]6_m.XwZQLVJ> N2 X|!fdRA-ch"f3)L<5@ЄfBSZUIgO`04.grY_3L6hɠ(&g(˺ٯ1iLa.rzt=|"N654g*MQb>fN m9&7S4z虲`hE4a!Фs67%M.&虨ƙ q~-a4fhĔh4i&14rqXAա9Yyzk 9P='C Ș*iq@iғu䰥ei8a?i14#4xOCC#| K,\iA?e᎞v3;13 RFq4WԳ3݌!]CCdx$[d6o:|〃_aqǏRr#Sxn߾s=3kk_>PUxJ6m*Uە붯lؾi+;vk4ݚؕ ;\"xpQfv $h(yTA=kWb\D2K+=k,jcm/JLFT걍ܹ[):^CiW\kkpKmVnZJbv).{%g5wڰZ5Nfu;Lw=K+uץ;u<5!!2*($>hCq @Vu:}d6ㅛV_J%Mn:'ܘpۛl~CIa*Ҳ\͏ iKy7NP)t3 4Фl ~ ۤ?{74> =OE)L͇߿fx73^\s/J KW?|zl$|oi",j-J/W,{ $S*8wgb%5D8U_?GY>ͣW[xգPQr#g Oeb_17[=z6@vFgV}ZfQ=E /ԙ%=y4gTPҵ[ 3=#nw=c|16R$$w^<מ["q-cz7:[2K#YڝԉgfOTc zΓ;$JE;HvǷ܉Vs|{p6^bhs|21rYw9|µ%nUҌ(EU nE6Ϝ+B=K.l uk;I$s]J:RȕHϰh8i[T-Y"ѳ| X{D:s=xYÄ臬)B >|3yq^yVipeWn]~pwKj}NUtwLnOw%]?t^rG_7???R//W_o?>$_k'~x8@qE&F4\= 9t6N(iv^1>yL;ಥg\χybNs2י-'/*W, ѳu.bٸO~(`hh8=#jF=#iAF'xK|s'ٮNlMdͨN&\q[U,Ԫ>6Ϣ⸚FZUoѝJ麤m$֊z {8=ks~ρ)%8FN1E2+?&aATj=>Pb1C|vXa/怶m<9=50A&fr Ȯ&@ L0dTQ5ڳ")=3^ ڞ7뿾V޸U͐ĔY(&|CgR<8=Ӕ3m`G.g ~UͨgUglꥼavi%jl>ճ"x={)3%|{ @CC[~N , 4 $I7δLYe3HtMJhs &7f63-:cO"fLτ)Lԥv34{Nx=j@!hgF !)[\  \lhͤ ;I/}Hgh|6lE hz+ ֛hfh"i!v|)C<>Xdh2&s3IznP7!I&r"404Rv$8QlhʴYeC{HlO ߈>TYBT4==NWXgHGP!IHtÌG,XV`kr3i3i39}ؤG>'#F.Fgw91w1jrf7-Gh9{ch:xrSJ:A`Dj mfpyH#N P٬$R:=X {N`0%J-%vlӁ3D;,VkY;tqk[}6ɬ[N .Ǻ֮S;$]]C[i%S9d3a;0}Yd+QBaDv)N,joN<3 Twk;uΘ P2T2>Y2Ƭ\KOUD#NeE$t M=f(53pj͗l0g:|_]5h;꿹aۛ m&fIO~'k9O4y=%8ydkqmNh#} =%ƭ4O>S݌6֐U͘IIJy=Ӕjk&6տfh\LXjrL2'ù=hM 3d m=C7{,)wMVzZB>,3t33&$1!F+ФzR=*M:yuS`h14 a&ҳ}qS8niF[ҥpYVFh;Eɖx$vbhbCZsPCxfnY`~ɾE &x-8"-4C7$9H:IMSн.g2F"l:9&8)N:3495mN3}_ ]9Kn`asÏE7Ή%QɻݺpRMDMٕIµJo7i(Pz~PAc{woPqZCT]TcmUEvt>}C#Dg=:dlMBYy_dͻ}""CyV/c/^7qkw?_Lݽg8W=oƧ+yAr毃A?US>}%s}mWg|#~{áINj;OV _*y^Z=< fjQ?vjwhWv պsv$tt'(J%ZwDRۏ`=b}ptY%;)I1KAC27 @E}ܲ^+0ujܗ.PYhw6p5 xi5#U4ԣH6oEw,Z(ޤҪ|R .kh@ҁd'JqH%Hp۬ڶrOUq{h׋8{GִVylRR *+nɏ﮴-29ֈD\),X2xSnEc" ]7rCipc$s]1tܘSޘUv2DQ1'#c"Ӝm̎uICgu³E[QKR(3g+  yoBlhO㚞)443Ep i$chzƭŹPX쉬Vi* O}*ѳJ~"h͛f)h+7Ut>Lg TUz >&ߜQ^!mc狏f 0L9Ou: .XGRCBlg׼XA{r]5ņƷאIq*3иn(ƦpRz&L x1vgyhYP`31U5aM]9iS5UK]eҴ*pEfzzz oٽ<^@Ӷ&M6e#idv'`TOn5 {RŴ1;@jQ=CO74bhFsךֵMqb'Q$-EhQv>cZ3Iqr𔔼NC+ 4m&lτvu9Ԑmj eo.f-yh&2Y銷[h"-[,RYz`2rU-V/3_LeW.6z] o[e&{F'NҦg!qgQϴU"VC#`_/-_`R٭VMOE][/gCWp'>~􃯮ҍF}=tst } Ozƾ.y?o>Χ<_}$tGG_W??;z?]Co^58v6"}0y"n!LkN(r2 zi/\8jT:Ͱoѥ? 5ɠFddBnpVܸ/ɘ*ף;KT*?QR^PӚ[yD"19IBz멅Բ䫒ry v@%Y8 v8pn3܀.)HK JE(N"*P)G!Y <)/4>DMii`wd[Xc`wkC\Zm?VҰzoْFl:},z_%ֳg3q R!.#Qk2&Z݉)c:[> r>-!_344#n(&iQ-Y   L.==s3 h(^mSaSQ3_3gճzTg*b=Ӓ3Q6)=G3y=S\0zF^ QC#4\k-:F3KHGLY35Y*kp}!f) O$뙰*XHW4glQ4!f,kh|)4'恶n>=4-iw͘=5YbM頹N^q+W#KznR]xaCC#FbhD0f/h4\_S3K%rGB-YύPsYE-Z :% xH~)9B8gg7g.g !-3rĖ(T|o(]5`[MڃϯjW7pˁ_\cS_6|Uu}7g9m}ߚk{쇁ɟ.y/Sr}{߈~Q_?p_='_+wpg\hi';)]4;-k/Iic`6ik!-);i_I; $MUp8Z ߍR&pVp3pJE" iV6,-[K=;O:_LJί>/M- +iÐŒpļpfm0shG\?=Dzb23Tz`OTot/YNIUJ¥ Y`=3"+&.&,t$\BqJKLm}-9p \સWt: bNp3ㅪܠ`ktHEٳ@æ*[RCCgOY!݌[I]rAN֖`n&,+CL.f,oh8)@X8Y .fht'_0t&@SggfrnE4*":8!A8_H-t7 M|G,]#N%,rg3(zFQgB sBBAX+B,'[,%&쳁/&$O۔3T2n'545 4!ũXX#ft3ghhU@3niN[iNhNlhƠge 7,8C#ncFchtQuM6| K"{X4$ pִ럆F< Ѕ9C#14kg6]ZqliMC;`LS77sD̹ 4@cuhGCcHZKNh`h0IBZ[Ӄ.1.5mn Xį,=#$e $\B\ɽ3-DtMKO O:ov'cct<2}pC( N=f9|ρ7Dzʓ k3+O4vvtvn?|ڃ/.N}={?xRqIIE_5]?4⏽^y˵~z߮?0O L6vT-m̯j.o*m*9Uz2QRQ\.vMLHq Oq%nGBPqe`8 qb})`k{瘭OwRE^1ְD_-p#qG܏EXFX 6w 5O(`bdh`pS7siamkxZLJڸoz{7L']WKFZ7d]rΆ4S%rlQ=oH뙬-ނ14c;D)7b  M_hYS)+p3A8CS|Y\c=(^/HTMЄЙЦ 097I*Uu+zƵɕQCTޗDT=S3R81hu__C mw6{W4@=3Uv%щ)IfL"8~ 48&8EC[GP[n 'PC3#)C0>C\vSC3'=7Q*njK̙=ik񤶆YNjt5vO:_ۣmӡv5СfECj[kAch:iʱHdfǂi 9h\4⤞fuhtէ qo4CZ5Ehd'x2Uʍ743QZ 1)I gF)/q3w3r e M2ӳDK В!=AώDQCG== <-HI$7`vy~ͬLJϲABNfgW96tLlW|n6v뫡/zF =9iU'͏g~YYz'̨:TtS?t_nQFNtb,RbMyHb.$gfG.=v4&$`j/|m' D^q ĹdLE0pq! yO +c`J<#<YGXEXF.Q00SPSP:8"FF#t6\͎ѷ tEz%:BG6E\%#]i~Goҷ+jMkb xkuiL0$yߠg=1`-[-FKi}ίhht7QLŒƳb ‬I-+ eh@7j4[s^uW9ҋ=ꙨNgfڔפLUq~SrgV 6(g26J[Jx=S &0q̣n zFZUA%MT{63.% }1oht{U|_g?m:QqӣOT~\QR%}_yR5}[95}菽ۿ m KO:.oR~j+11XFY$|| <t# *2w˄uF3H@rs@*(%h24p@88G.Ytv"|FNl,X"eddP|th<=4 O,#_a> 3q5t˜'_jJ HtڰMUM OMsO<ƝoB.G66lie/l W1\p>" ?hc4غ p $9a  -4@ ha= SqGPЂB蓐/Hsw$.zƭ !T8IcL8bgaɗH,Y3V{F H  ŋd9AGmRΝUv~ 9) -3kZ!.u&WG2>O3/ѣ_, }}ml'Ni' r;Y'ԗڨ{N?'JOZh?y}~# wNghW]OėFo/*kkQi mcspꕺ g2?#_3H<ތ'/ d$j :yC/JHdBcX_2OX,Xl@x\`DObO8se ]GĶiȺm«rO5ͥ|-+YJïFuW?po}_C[{(c;%)/?^~o\p}C)~ץZlþ9{Q)lS-ƔG:gJ^ⶕ\Uy]_1}XVxO2~j;̜Cb3,@ d~rF&c_'C^2@ d΃gY,ҳO B @:Ȼ3thw0@ d-)57ze_ ׳ю!@ \ygRz2g=}ÍxZ^_dó솔~|GE}˜xѵm,pJӯ%BF,.2Q@?Ȼ\EmB3>X߅8YmMӫ{Q3[@Ҝy3^ \p~߲fe Vwzƴss }&]ϚZsK((.>X߅8*^[3QZx>VBA  :KgfNhzC;sgxrh[6!Q9OWD191{ $*!%q a|b,ՖxG :.`N1EfSܗ:%> yŘK6>Ce΋3"9s;X0e) QzF&-Q^:Mгv<%nTIJ6dLk)\q >;d4_~§U,} bLRet/ uFZ  U,+C^2庉% 8T⇩塑!zw5qtƅ5zHгmexJ6Ɇ|Bݸ8Θ=$ש6:/iLl Y@^+Ȯ#{_i519I֊uF^K䌀 @ dփkRT8Y@Ay'2F<}kDL&f')m)/K]dy IL0PaRFS-WVdoVԉsSBxmRn哶D B  Bϒz>PTщCULcL% 8mCp,09 >o%ڈȲ\@hb^Vd K~XYo1gT>(ZO@f=-)S &tz֎.Z,YME'MT:;V\81ˌ3"9w&|i@ Ȭy3:ԳYLgmC=*3䣻^@sw!=T[ZYGg&RzkSVyV`BL7k@ r.=іzͮgR=,xQ15@ d9go{ _C˘鄞utWA @:ȻUzu+dhgO'{@ 2%ͻ5={ҘIlҳ4CA=cY4gk0`@zvKAg^}u T=׸ҳRCgUUUAAA|0 @ 0:_Rи3dg Xh8 @#Rb3 TCБ|Ӧi3Wmup=X0[W =S&g'ӳi{ I0! ?GKEDYWײr@Ӡa!*<=ƺPH(^R<337''+---%%911S;K<̤$333$`\]]=!...h5TrNNg3注gHqަ<lU{NJH:ISzF=*{Fӳ: ,sFuI=iw\嗛ݔQ ..sPRUgշ=ۧ!HM-45ͺx1ZR,>>%11BAUVV0=Cm,3H"##  [lٹsݻ8pС#G;v8 Y ŁYyYY333g\XB9O[z&B2CDģZ7 hD3IUI=T.]tXwz6` h2Йۚ4ԪZբ)-m"wC(4= i_Qz^{SUT %ENNfQQ^wwåqճg~~~ d"=VZ6}k׮_݋|ܹs"""btΟ?7 L2zV\\,((hhhg#ɜY9H:G<,= 7 sZnPEKv qʉ\ r⍨H{N2/p=kl!W|x YJK ]i wS K1,5H d#\6>KƇjBZ ={|k Qw gT=kx~nj%0ĤȨ斖ށѱ*3kerrm#)NQ)xi^^~qqvAANjj_e8eiYhh gdL[lGGGw]Dbbƍwu .߸q& DXXxzx9[zV^^~gϞeee9s۹sv"­,B=/gvŦg"-3 kBhBrΰ>4xELEQ]zFY 9/%ķ!NNN{"$D{AsMCXPT%㝛s_RШ'OL@\ gݚxz$ճN5XHеɝ@PLDdPZqvY0ugJKS!dE2Ud [{i9x,Y*'cC@xbu::mH(*&5``q3hD3 =cٹ'T7=CnES4bbb88|hq1KQST,s3!YXs*1 aBi  ٛ7o:izu9sʕ+wܑ1c:DGGϬLTj1N3S5N3Fױg ,zưr>Y!szXp^ =0ٙSI{LgnưܜֱgKY`7߳? 777zi8VW{(Xkݙhyi1^>^^mmmLM-SH(7==Ç 1l陣co^L}@6,22xyyGcʐ{6F";}Bz{M6EFFi4=駟vyر .HHH Bv̊VTT]YY'EDGGg{}6:=x@ZZŋ٦U rBfgK\ϊi!X0`4%˨)NQ?ӧ3A$T8ܵ2Y>|E=D={eB=[= R)MUhXNE^^^YYy^x۱73#32bccVqZe"=SVN{n kmiH;#uby/5N33O~~~oqMEEō7R(@=zٳBBB/_F,JtMI={N<Çi6G5ҚVzƾsl @3N\XCR=Գs3!!W3SEEELL~`HXzzF~~td ߼鑐PT]nbjv#/]c6ݪj1niCÜhoo6gfIsfGs1iFnIYRRR"s4 d\rݚ( g+X0Qhwtz.){&'ægӺ&N>WfvE]SSSd&#AHϐZ sg٢"~~4/\;y^RC=o[[[6xyy! -888++vg%\䢥stzS'33k']$vuNسyiOSSr7ww}}<+.1[ھCG/o{J̩sfb555322ӑ!OFG0@Xh5Weos󕩣{舎Krp}me熬 m B{{{s ht]UTBع+MssZǞ,Lp=X05fr{3 6=SF{fJ=5@ZYm{`A,Z)C5 U>=7,h][[@#R"5C_0앙UTc3V|:{n,X:@`uM g{̝eȨ0ל-[;Kq=6s}f l0/`v;P=ROꙹ, O~W``4I<3QfgX?[LENPa\ʤJ ij1 cE!Cu9u]l 3 gf bAX& [4@ EL쎂#jvGVm{Ϟȩ@ \ψ8pg3I'*({jﵸ=T3|nG=`P2ϢgW>7r~n7zB,\ՌPRV|zzXpZw 9U O sO?/~ Y< =`1iŢg_ZykZ~i@l_^O3KWucx  O =`cmE m?m_[qz3}+WEu&g,LGҢ[@X{vc C M}陁:ҳl)@  O YU#=ۀ  Lz^ 188XSSAG]]]͠g,p8ٽGNAA{aÖJ(gY3A W.!F(!oFgF64L} z]=p]?2q 3q Eгw۸?yiz=`gROLh 'SM'fg 3 gfT=3-߹ibWi9g9ҳv 2={en=lR콞j$'8YOOO__z=[t S4MLLܨǞgn{)k[h[$H irohhg}`aîgw^ 19g^*:ږI鹠gv=lʕ7np@ |2†]n+0t 6r6r >Єs3gu#yus n駟8pÇϟ? l/,l $fAeU^Z=ӱJXpzS9^֏]pJwuE{OP?015vdtZ(@pg! @A .Li 6v :L3 uY'g-=ǪǜJ1jL% S_u)lcEK{GOo/obYcx\"_j_}(ڇ~QT7 lTV,QsVs^ވ_%Xꙉ 3ڱg ={ %eYGaX>_Ҕ 0L7{=KƤBƯ5#[&Drb|r qxT|3ߟ0zDY{BXɓeѱy|Ý>s}a < C&_N=fWiͬ2g#dhXxDXxFS{[[:Q7Q׷ᣞ Ǖ<yI20tL&fA,J̪43ΙIk[z_[ִa#_IRPPD*|lXdԺeUwTzUnM274M%mMef֣KqwW̋ S8lVf!k3Ha3'v>1x&w rya`n`KᇞY_4/<$`/0̠;o\(a)G7`؋TN>:}9uKV1^gr\06>U7Q⒒̼6~ax IIݷn2<<%]}g~̍D=kwQ{ 3&$*,@Q`1R.DRay)Xچg' T%e=뙼{(=4DjW%3o'gY;Hdvoi,yvRYYŨbǵ:6`] f]`FnAƌ:gTq,u*?Tu[1:cuS! !r{ ?2O7PFfVOӯ+l'hw]̓Me37B9!`zCw3 Xڨ:ç,^3~0NU"]3=yeK˩53#{dhgQe/]wLe5Q?VC){jeFUANe!bMʀ]%f]Yb٘N2,tmGbiBkjjsMZmk{Z`JMc`KsZ[GBS@Ob7 8wxwhWg{fh,7=cp4"ieL{>BՋn_h,;q)K,f,gv=S7H- h[vڸ4GI`wnz}#ߏ7KfTꫯH %bz٘I!̢3/8,Kr萒oE1L:~}˻u)WwvuTh|\ԵJf%soTOGцwٿowĝ !~-\ÝE>g}>͈a3; ,&F gcqʒ=`[ɠg0-L5).1|nǛvy+GMcԬ, -{)QM:,id ԯ$ݿ}JTD-IR1$ECrkM(yQ0U݋NYup˱g~*? Og{hooo__uE'5tnDSco`e+vzڛzP='/<>-ʜÝE>H()3fff#77ѳ#{6M)gziMNaYW;zf`VܔVҌr1oӟv"=uxeꈒ=_%M6/.+{ŸBe|ؿ%7Ig؎ں@{5']nWyK-`K霴8|;D@?++kiÝE>Hόb䰓C,+;76.1''mq4dڷ79OXu3MC2sxtXAmN?GkPjR8Ǹǟ?%lv΢k\johmm++,**/(OJN̞}U`îgn (E E_陃gs:,>%sEQ~S+4pQI|)yFYǚ;EԢV Ym2}]$㰻&31 v';hXPj|Q@醔# 59_e6*}%VXعuRFݲJYeݿv̅D>Y\г^y ݸ55fe妥e%&R22@%Y7پ?r ҳpյpMᏞ |Lz7$֪:B9VxӪVɣEAʦTD#sMaXv3(K(b 9,m+MP఑A+DZtl {3vUge[?{sKo"%y񣸸& gH]KIMSQՋKVh,=[z$g xF`%U2rgur$.hr;[O(f5ڔܛؖBrZeQm獚ZŗEuMMmmm}M.RհVzw[tNMph@pgl1X2뙅kPQ -t=og閑7=NU{rnr܍MH̤NѭIƮ\eUؼ"5uCX4V]VDAAAWW״Jw@π)o,N @z6P00g[Ǟ9ѷv׷r-|ѳA[TܳsmQpo[}_T'g͠ B+Y檨Tؼf9:wttg?Z EZ?l>!,\hhE>gKT  #MϨg.>66yIbke\(gW+Ҥ=-*$e-WEAm U>,y4+_7\q\ \nnn+V8z(酘uttFFV+쬬D'Fv;2b9f%ˌ>>i3 zVB3(B370c{/c;Ϭ~YsKkCEuX9ׯ#nTZ/\s"Ӡd}˖-߶mۆ,c`@#IWmuU0-Eƿ{,8u=2 >g,q:xdOhkfk\.wsm}{XfA={qFC;_INQYYiIqqqkGoInrs/>>Dx,= XjM6o*ݒgo)^^R?O=sгI=0s|mSPG=ikoWu.VR)қF|!hq)))11+WZ1vm^˚j*322rss:{+J s)i,C@Y3z m)_R Xhz>wO=㽆;/Ϸ|wSddIz˚OW`Jna ݅梬ѮZMod&Xdl>շlRZZ6hhkm544̣c3PX!gy e zƝg/=# z6)$=Cz5  !gtNңFX%tIL>g:! {),eeQGjiݔMQ i8,/I7&6'#iCrx;VܬU4beH֐%qk32 ;9\piåg-C'$/|𰕫n)*a ӳÇ+))Ƕ6Kreoo6R fڇ>ss}l IDzᰱ`1a(ɶXdL%JvdMY9e=#{vSPyɧA ٞ֍B7SDz}Y;9NYsM݆K\Ϭ܂ۆPZ/74#%xNiy~)Se6{9vZϵT7krtt 524d ڇ>rj} A~_ul,6Ƃ#n9EqT`y;MY&)dyI h XrnkNNڔ3,l^2H{ SH M.@{ǟqXd\;i{sM݆K\Ϭ݃jۇkh+r+U< J*!:2`t١!Y故&g,á}p}@glrMq[m<SlҦ>&.OZ^3zȆM{ٹ/yzFDBѺ$&>j/4=w')p뙭gp]ұ, <;+h!FF?ː\Nl9m^1Zݡ}@pg!ϜG+Ķd,kOK=#:EXx)mD:& FS54a𳘲yAD%z֍ԋycɛϊس{f5GtmT= Hp~TXRl, w,,;kCς]}B]߄.=,w>g,uhs(JSlHς|Pʪ$=`gNoZz\),4&?Oր0L ճ־1I= M D)=OLgTCcYD\h蒊@g,H{FгtXZ3lls> NzƬgI~aq~qeUuBhW):Й\^[jJ,ɂ,wH Rb3Qgg+yU=f^] z6 ̠M:eXϸ3?%u9M.z"A׳>|RϦq%,N=Qk =KߒEgLWn߼鿛wXoH>>??ZZ̥^WHuѹ^ß,=xԳxJvpTJeMeOׄNtqŌ;,Bo&lziI0+Nb릂Τ4 Z !A a\+S}Gj@Xde^6`Rr]#۴<,5H CrBcQjg qEr,zfyì5\w#3ɷ mp=+b M֐`u.&im$AeXWkyR-ȷl_-ԟt9O} xŴSגSAӰK,lEϒ3")(u+>{37YjXV/?u݌_)CROe'Fm>aglʲ3niďuY_0/kgJ_r,yHs`DQ2"fgƟiN_9kILwr8aK!~|/6[i+0oss3ZlPL Ossm vn.=coqS G͹eiX&DϲPjf{FoENb>5}Nzƶo1z8j: %kdr,gU+FڿATf>5`@X"کE0ҟWMi9L`3Nʹt۹I`z/`G=`gvA}(ec_mۇ,= 69#69a lbV 98(g,=wwogbS5Zt=`gNoZ[z{^gy u-g3 zf55 JؗAz_Rl=x @X&뙡{SG_sGsW/г3v=ӵtihmlE&^:ϻe&7@X&kC[3ґ6DzSP z_=`g=PKF>W?@X&뙎K}ۤ}d44™3 d;7ݨnS:gyE(-mg3 zg=xvS@g,ֳExBRsBcbSj@ g,H{f]]Y!Z4r#U ln)z_=`gFo*C(gp=;sMaA C@ g,sTuPu`.\NI>~υ\t =/L 3Bˀ,s#)zvEs z2>vEitzv췻#C=_L ׳"stהH϶QLLvͮskv=OL{Vhn:gdV+@ϴǪǜJ1jL% S_u)lW@X&pг"S CϤzнU[O.h?,2%}{ǤSãVwDž#N,[mh@NGaX>_Ҕ 0L7{=KƤBƯ5#g@X&33t}t-'O=6 ~M~u$o u͎|lXdԺeUwTzUnM274M%uMef֣Kqw}xdpd<|iK ic2 '4SfXVbV՘e1pΤ|O%];zGM@X&뙙}D_Q\_|w>V1^gr\06>U7Q⒒̼6~ax IIݷn2<<662Sͬ*++<ӧ_W_?(zO)RuBpgJ7\ew? 8vɪXL3{1 >=Q[>kul1̺3/ 0,L=3tΨYzSK\ ei]u禮Gl+7G]Uim)Bj)5MC-MkW{o_T;?/ M9F=,w}WwO |Հ&)Pyڇ;>S"ln/ Ԋw(eyXrף(к 3lY dZIĬ0B8Iƞܴ?(\6mBhMM\T eنHh>} Y:̳!+s{k䎎kU<2KKK'$tߨ۟ ;S>'W5; i-CSڇ;>ܱFmnFYwW_+VK1Bj_E /f^pYMV!%~ Oc.$kuwk+ҝ6ƯSb#=ۊlkGY8 kMOg{(Z-uE'5tlrSco`e+vzڻ#:?@pڇ;9%HnޣuH9jґgI$O~%-S2#jN:i'a/zw햋X#flEɋAr^vʪ[梪g,.Kko)z_\GAzԵX:uj/m[ g '47detwc}UwPo|~W;l =4˴:9"ߊ^1|A)o M>"f5#;.QIfSHnv>HncILpu@X&뙱ePWCئ@ճ~v?pW=xR޽{ydzulGGFFkm]m.]ZygtNZE7@Rs33Cq w}x5>_QM:-fTtݢǛA-J Փ6YsГЃcw:.ݧp-_ϝ$Nv=;n~] eٿ6qOP PgM-/ x]xGxtXAmN?GkPjRx[[[}}+m?#G˹hV !vL-MH/ym24KeU0/I?wۭ|0`L( ]M!I%a°#-JFst_3 zfheꛩj;hzvBrw{>~B醔# 59_e6*}%VXعuRFݲJYeݿv̅h^O\u{Ԋ%+;4~R-_ʡA޵QֱEBVLbG`B18n*I&gLL݉?Դ=`g^>.Ϭhz3ҳ_7;oNS{yֳ7A!F:džӱ/hVժopQ,f&ŏ(#u-%5MEW/^je w}xa``{dKt'V1)›VJ- R6"h:t ĢɘtE)^ҵE1]pl m`3=k}o 恻N׳p=g=U|[Z\T__?";[ kz=*7EGԴ j>܁ᑃur$.hr;[O(f5ڔܛؖB!Lv%CdT+n79G=`@gVzT=zj+{vg23j%5uCX4V]VDAAAWW״J^Wh@•ntrsskno*Eb&unM2v/c?h7Ol &9zکW.QLݭ{޺w2s稒g,L]3Yyس_!={Ozcс}Cc"GOfȿk!K?bddSKc h^xatQ;E=:9՗Eur6 ک+_*RP{az'+[=޴=-ӱADݩg,8Y gV!{gnrٯLgwwwc*FƆ!A}CeykF]S$?舄?aARRvl^}3%n12YݳuiRlZmcAuHҲV1[R^wWjeߌ~~ۿi>&]dsTI3 z)M螘.KK׳_g42_gge $=Y5c10/Yftss[bѣGI/Td6>܁\)by+d[V ܲh|ѬZ0se]r)*=(N¤SG7ވ8K„\ݱD4G=`@gީαj{c?ZuBϾdO ?0 r$ɫˌpJ=[f}˖-߶mƾXJW g*}Ҷ~PQݬ;r/U(;ܵ?4#/i6憝.a70ɐmIW|Z20XEf/R=3|!r_\3~-zzxt߯$$79P{?ezyݿٳgWXqvإyŁxnpF=Y+>j*od|>}]Sޘp v- RLꍀ.8f.Je}"Qz{c_OO򴆆ڊꜜ|3;dgnzdh%t}gz'g|O=JH,kHOOͭoj(-̥EL6[rUc h)ikoWu.VR)қF|w%_F8vҸxle*&x)$2vFԳ-?,v,]%%g,vH7S#I9v|+]UDDdJJJZZz033CaySWW߲eKii)cۼBpڇǫk.z!z4IorKnn~{3v v?;FI%{7Іơ9I\bkcNxx8@AX^/S3Y%@BʍzgW^feefdf>5  ػw. ߿8vIn^}#ccciYZ|"r\;eWtN;]ڽoPX >Y`@g~YzT=_zAcoo6mmmhk`)JJJRݼBpڇw\wKU Nٯ;[ w6,?PQY5,?[ϋ¢g XWϽ7sL$3E41jQQ\eB&fQ,j$ PVETPPAvA]AqqZNymk9Tu_'=c%%%/_nhh '&miFl{uww>|89+W+GI^1=wXY=|'.USScb&Iҳ038dCCCǎcRӽ}A4{ܿ&IP歏\Gg$g 7u|q ڧI<9l_m\8 t=kz {56h+#ӳǎIMMͅmz(_CڽE k>ڠ}\8 J=9NNW+3C:mYguz6z133ߠG $zѳ z!3@ѳg{jP*gg=8 J= ڙpg~3=+Y̠gūz\Ul #k ;;g'A]ϲMo: '3rv1`l/s`K֠/msV`Jڤ+aUKs>]G;- 3gKHeS WL=8 jz1*{mg}{H(z&QY3w^9&bFXi'0M>K/m=cT4Y(-n1|GeVl,nU^wފ.Ä7gֽ7tdcʦ/*Cb1=SvMVPlaB!HCaot~PE9FTqEMZÕL8єMQ_b3K@NMϢz6Xg8={E]xE}ZyP֧ [=oX&O(*-|ֿi\5%K6nq f.؜=#T5Fi但PVB2lفkng'gMuz&bЉz>Wg}n0cqay[^\GόfvW+ktZ)R4"I!Z<"./;l*M=ZUM(3VNۗf[6>C]P,]Gi)Jf7T13ټ9`'i=4 zpzxxS={i=.\yS &F•Z; d ^SiUSF:d)B)gCH*/@t Z3@sQ3hYI6{%D( d&J$DiFb ¾g mrVS͗$;C/FT]*fˆk_Q*Sy9ZRI٧,2=8 FYD3Z!AS@NUςzC=8 Y'f@N]KsGKg3mU=; ѳGLh=IYpR)MC6zplDܡg=8 zvf}D^=‹Y35=|̆Hur77zpzrNҠg{zpg $ٖ"3iz=IY艋cr7~ 7u IY^ϲM=8 T=c?{1J1zz3gѳwFLlK `3g'AgQ]0|sճg=8 = Xw ݳ߻ z6]3m ڿ3ƨR6YYk%Fm] Z $(lc`$ѳ kYm /=+,*?=oG`dL\jVkl].;I^e_uq ?[@NE"[/m)U/[2zf;=SS[+q:?G}:q49՚O>eT7>= ,Lcg}:)|#[ѦU $(l}WZ80^mgL:| Sƌu丮#ƑI>tl񆆆Fֶܩ{1b Ƣ fYfQ:3 9 8~i-=8 J=[sߖس+w'/ b췮==zdSD;7'zvȹK}ܹ?32ϤY=c|6@S,]eGC_zT4b̪fifFlHs<~ltjl4y*[ Ѧյ $Pl\ngj@g~7uI\Ƶ UުXao?2rɜ䔞Ѳg~K_3pqq1rRI1g2JPlkق?{0~wɻO{AKߝ)Cd~~aSW y5o/dsO̎ ̶YfM:(~J@٠" unkm]-G>3@ճqyv'/ >~5ub.UݯawܩkllHINNxT꾹9rRglgˈ[}cݚk.϶Wܼy .qoȚw?.4baNeZ9:t ayIC8Ei\׉{;~1KR5uY4fYR{gEԻ3Fm+YVhEfj2׾!-fj ?ڴkD8R>2cuXʠS=9m灶3;-GPe F-;'/^z|ksb{s|󧴞.~HZWqwbNa&1l~|0Ѧ $pxSTpN/Gg][YZ}ME_nƔCm(r[΍ZsZtIC~k |tz3-k:Xmm2afĶa?9ƏHѦյ $PX@Ȍ!պ:Ԯv]ZY*nUOOg~om_{/0D4< R7sym{o>v][U;7N!Yi=yzm~/O0Kne-3B˦^jkkN§}#0Iy3o>|WXqhzpzzسQCn.ozGWg~?_7n=~ޓhtsse=suSIČbeQ5eGwݚW,X?sh/_ð1W^}@?qaoL|oIĭWK  93ڷۊ<$ĿØaQg<31.1gafd2co,0G>3@ճ]'/m?w;,zu =yѣ{G߿S2yry~199fEffϺZjyKV.[H_N|[bgz+ǷW]0%_^97|O;xfT E3%>5?ebX|fffgH;?n v `p4EjIP_HTX M+׳`kٵX[Z\TVv۷=ubtg0U;p&炅/~kͬMZyttm}ϋxM-<}{ء?eNrLjVpِpfL,3m&3,Sc6\:~'ں6fǏ6}g'g{N]_2x=ȉ{nnhJ'+ssϚ䔔7n޻=&|=s~UXXHf^&k&m85l֞{ 1oOŌ8Ǐ}njOlz yO~pB~9oژ?ڴE=umg|yNb= u;UWW?xܘcvLroLK.׫1We;}.M 1+r۝>lM^)l}'KGCw_w./=ꗇ}wӎ3<8~iE=8 t=KP5Xڲz6`sPDmg{eqÑC>p.3 aan,9^Ѡd O8QqgO쉏VLvaj+ۧ1r“ue]'G2M9MfN3!թQum mZK@N&3=7mg U9g=q}j_O}ܻ~/2,[pϞ==ܰaè?0+!%;Բ/6fǥsVv 5?ˍg^<߬N1?kT7iY ݿJ]c>3+$n'ݟkcfphZzpzY<<<ƎKw޽ZuZs_ϯ,Mjnœk/wfn |Ɍc&'1.bLfzoW5zpz/L=YLҩ ׯ\:}tNNN~~wk/ 4}/}:t(//upzڐwGv"b̊;JfNtfuu}Pf^2;3=˺Kcjē񣍝 $hY\Xu\[ltKtrXbFFFvv6w[lM:~s$#00pҥz*--uӧW^x~?lU7~ެoV5A̰]Q̴xf׿:=o>~؁?Ma=8 jzPO,gϽ׳?RW\YreXXXnnrΜq#;Fyw?`kג^ڵkg{ؘ;mtdڌOߙsɌitrw;p(#>>Nm}g'g7{/Cg]>mGx>|f}ܾ}LٺgCGICΟ?)!WO<?}؅ _ߙ[}cqAFoK8p?m@NU"*Ug[~S'5KJJ._@OLھ3`ƍH>|pr>WQW%/{LVVp}wغ\6Ǐ6>3gG.nNd/n陭/nR!:vǏSrU{ܿ]G;iIYgߗbh3zWzy~~Z8SA]dYG{hI0Qس5^ U"SYW^lgm .,;phce+ޡg\ $Y9]ϺB6zpzճ z=3 5= N,yĠg~ԩ `;g'x={U-ѡg[=8 zV ӳ^e{&hsUqP;zp,}yw 0zxJhnW+lNZv;+ P!q-65alpЖD-[ M- &/ IгM6q{>*asa7vX^^BӮ^x0ԃ5BAO,fٖFϬ/dmQ^ 3j?Bճn[B"[>݉1St|d9"ztRX#V2!Kc=VNV`h~9I֣ߊLuXf#zxLIeG`?+l]fd+R=,b;O&5|_k+-hiE%ߖR(vS;H $Qy虤O\+BcEcHOgZ{F*Or1Oaq"ȌYп m)/p3eTQ~pxHrhJ3gNJv:^_ل]=\IP&gn=^_ݽ{_s{on@zp(zv-0`[왡w~ZoC?^:1`_]=8 T=ۗ~-0`kLg;|}O]=8 t=KL?z֫1ԩSw@N/n?^z?۾3r#z:ѳ~~^zs䎰s7@NW=(a׉{1lSWѳ¢vFĥfe_v>ڠ}k{v:=7߾6wD*&f1OQzMNf6hmZE@NMػ[}\o +gL:| Sƌu丮#ƑI>tl񆆆F}AhZzpzI800vzɓMqLΗsޜ8#.!bل$׏'}&9g|YrN`-;G6}g'gQeI%A ò m3@2t߫vC#FL9UYYo{y9Wp,=k;&{U~ )iiCGK-Zs'O,]fkMkIYtTVٮG nK=zxc6Eaؤ̜O'i77>Gy;'߬t-/_^뿿~ݮgS? M\hm>ڴEgz6ڴe:QPh'zFNwo764>xcݚk.OWܼy .qoȚr>~4~]hœʴs)u@hѦ $P,*lgϾ|`[Ý#O'O<}j2[/?U{62YYŋɿeW.EJ?k[6hmZK@N77뾹)3k΃VL:uC? hx򨾾>߸$t~=:D~ș/{xy|?BWp֖nݲe<6hmZ]@NUgMmPqߨxPw#) <9<`D5$LZZ|c0&mJ]`.>\~"33g-]5ϼ%+𩪪B- G6}g'AEϮ7uY;ٵX[Z\TVv&9-?{xVn.av2L _ךYh j}AhӺzpzNHg/tie=c &9%ƍeee|KNwݏX>9n~*,,$d+i 6}g'gCtzv,7//0d9Sn]]]uuǍ;fW$ g/Ϥ~ҥKjkv GV>3@ѳҮkuݻחe G>x¹̴;77*zͧG~-5/ > ]}-gϞ{nذabr G>3Գ DN] /qDzNlpgg;54+uO3Bӕa{mP"{իW6m~Ȟu GoIP=)Ǟy? z6dM(2m JKԖǭ?l~}xxx;޽{uuY^OS}1!sz3bɋz0;{\lqMS*_t霜e^*=y0l~} 4h_|E;t@³׽}AhccF= Lzt[!iտ}A\䛛bș9`c˗oٲ53gϑKիTxW6hm}gAgkw I*rCRoֵ^w Prʕ+W_>...̙n>rбcw Xv-e<<<ȹ]u ڧ)>s@΃\Ãڰ/up\n~kzFxaPPК5kHANd=:rlN} :t_~N1ٽ2h@hc=8T=1"m~ Ĥ;6m(tÇUQWhm}gUUUղ)))ȆdO8Cӳ~ţg}G=`L]顡cǎ}1u)^e}Ahc'c=#IMM]dx"Q'O._Ȋ+I:$ƣԳĒOoL=7z >{fzp^w0Խ2h@hcci=#F܌h… d[Ǐ'WZE]jՋ-&.]Lذ},g5Ma~駻?~L ^~=1.)虏oh˖/_.LUN@3ԉkq]tz: XHN:Ek'ʕ+Ĥ$ێ;|8PgV" .$2FKf& s3jPBy=7lmopZ,gį1,XpI21((ؤ_ߍճm3[g.m]7Jug{ ouϱ sKVh!C[g&Гzrce fn{I]ٙKG]w=mrzxH0AkDIn*;[cpbڪUr=&XEr 2&%zeeeRRu8:Z0%:gQVг":FN_+$bu+.N o+ =Y>QfI. ]hiݣ&Y+(3׽{tZFKCJ*j HcӦV[(`b-3E4jD[/Xg|3zv)z6duL!nz m)݋HH)淥5{Lat48ߴMއtzf0/N +~N{3].^U'F堕5~L^RyQx ̚=ӝ) "yo%xi$HBѳa}0Y= lLψ=QSSc=yҾ{n Қ?E'yt J%^ݟt_.b' UP>0,"Z~VouS*V7H|^a1'1-^#M6QQ?ni Sz2=#&֭[?stСw^^^>>>dzVeTf,}QFe%2OM7zxچ.ϯ(Om ˲rݖ~MH٭([0Zi Y1ec$/V12bf0*~7Zgx1(9$VuY0YϺ$lulԨQƍ={vHHHbbIg훪LȬbc+M!Od7k|n:p6QU%R:3e.({an*Ӓ 5lȅ|XQtC`˜NdbV %3"bD+m XG !lׂܸ݊qBS4̋v] ` = ~ Ϟ߱o30VW´8cq&Tqqy$+/%^[:VsJ}hRh9гSlb.H6F3N0uy)I):q]G#t9n}>⤲V+Ah1;uO7&T {s$Xt]!Y[<,Jgy:!ZQ8+R31WJp,l3FY^m:sz٣'O6EĽ3y;_ysgΝ; IO1sq)sLs=gx jS,]eG#^Bh1GO/{_ɬaffĖ8wa+O]t2O9vm4׳[gA~-cгBЌc &ٳ=kqt,k. K^̌W_g4͇Y f6<|?oZSYg"Eyʕ'Ol(B9 KJS\5كΛC۬CY,VXh" i_3oef#jjmb n7+TмT#\RGAU0^v1gT7n ׯ86UO^7L͛7oݺu4WDQ.j5[ |fƖ(:2ەm!tUd"L 4>5c-WwT_lg]7Kh.9nڴ}oV7޽I"zÿI޽,͛ !k{ҳ3Q\m˘mŒs\u]Ι39f+{&/N!] _VsU ̸Z*K*ۄ>/75[&n/U:e3#yb|}ŤswÕ_JE-cvjԤlT*'Horݶ[Њ ]+$.,DnbUk֭M.Q2o5w{3YN.<ƟL_Z>N:7>=Ic݌<%?<*+M{`.W×?+0[IcݳJ/&~~uͨkl1fM.v:J+`bͻO#+H<'ꔊYvY<\%PѼ52UtO"I3FEU3rY!nāC^o5aooC,f7ӂzF[nYAϞ&G] Ї[i_Hˈ뢯lJ ՘ЀVl1f_fI}%-#9fd3[lX7Qy$   TYy*Z# t=˼гg;g+3gԳ;wx%!sHC,f7Mҳ?ohVг* PYvWzQrme"JODtRE`aZ_3jyuag#s}Ftk0l2-v?~[QAe,T6c H;Վ|`d*Y EZRf2ݬ} ھ}3.9'WfΌ=8vy`!MYY7ȫ$=7n?}{F΁qf q=ؤ mV5U6Izө_v}s366F8GFfdd6/b7KNN/0^|||͆@i_C˘==B8@*XB*ݳ׮7))8p?_BB}`!͉O˷=kgo MvYE* ؟ճ3 x=+-|I8`9{H=c=2~ ==B8@gR=3WD޽{322Ϝ>uAΩSi~wIf3A%z֯p_wt')V7PNNNDD? >|R|̮gZqQ6@EYSii zh,gϞ!ygVqYZ4=+3[0Fl8lzBӳg9={Pӳg9= =. m:oIg0RlmEf5gA3Ûe[,z`]x=Գ=۱3 ( zNu,z`v=,^g3KYpgCB_ g1e׳K   =+ճ  Ҵur=CARg  v ==|o8=! X+SY/gӳv3AADgѳz  blBH{z  b4OR]]8Jnd'ukjܦ.BW M馋J"iȮ+KBM9V^MͨY%6oFAĢг>#onrz) )"]ۭ]:S}ߴ0Q2'6l-V"5%mn kKk y_@xa UMg z&vܰ0&$ ɮ| CLƍI)^4rD0(2(ֈ&#$~:juqF ?3(Z{ƾơMխ z֬14ˌI78D5RgFy8eN&qAh;#&Կ; %]sB6z (= wRcW+3FedJSd둕͌z&n%RT3s';)a0P7Z~h"]`~WkUDzfKk8BQT_ @q,Hgjٽon;W8uC :/p]򻇒,ʀx\H*ٜ+ƬS]HڗF5FMن#FVk/]\> _w5[Lٞrr뗎7DݺpZŒ/\pFdںYY##Y-+<9/T;ATJ7'2-MZG$lAAezvD4z6bbZ}'qZ' 8I zNѳ6l~=CAA"Y8ѳDN2^mY=`  ZT-^Ϟ  ։Lz[}զ; AAZiB: %:  b@AA*b= T׳g  Vl'w77%?-y#;5V4JK+m;7ֆwv v7W0:Eە?FFVSzoPŝ,$T${% ҪӴŤ],FPey9Yo%N$h n!ɜwlFqf{RbPl lHP,DAGJzֆg!2t8dC7d_/"v,Nꐅދc{;rl]:h`Cc^.}қn(Stp#k+J]wm0rǕn)lNÊib:]"dYSВ &6=z$4qgIRwz&^@RMF!t(ui0vxˏdjY$}\I{S(O8FAQ3fmLٳrga N=T;5[x&o@Svʉ͡l]S_5RM>{&);3SjQj.klBg-? F=k LٛRbd# g{zIgZt}j]>//.W"C{. pŅ$>ڤ$نh~8G4Ѹk-ߐ5s\˯V2~I>'f}"uN;]h_wcJ>nݴk^6DI8 b|HeMas!Y҉cWq & o~>iޅB #AGgl )f7GsEm! dADل  bR zV=CAy$zvTg}X=OYZAABYCDNAAAm={Y3AAEg7vBAAl&ds AAJYN϶l AA:lѳ ==CABx='YѳzGe  5ӳ;ʼnN$~^MAAk׳AQOI3AAkFgw\gig  V g"C,g  uӳ'y=̭WwFxz  bznǾW㋶lW.:=MAADM؋  gkÃ_3AADgGKlBIg  V gkX=Hl3FAAlA.nl(UAAĠg$zg  Vg;.~ AAĺlҭ bϲz3-+tqussN’R.L4vE{I[ԪuS5NMc ZbL#C5/' b|=۞P9ܡwy=Ӿkg{Nf3n<~A&kԉf /K+GXu6m:մA P#ٶqzEM(JƎ;Ԅg!~ @~e ԉD]Nj$,hOdש__ لժtZm-ՔojzxL[{|[uRG8EMwoN7UDQM"ږ{ $oH^B~M_/e#!ͮGԈBbjGA"#E~y~pqzd0|Ns~B:\F. {j&ʶOTݴgEu4[0nC4fLcwP/G9"'W.Io E5E}JXR ]Lۉ&J#۳դֈۉIhȰ&ںZAj=roٍ9 =Aido!Dyv3i:2&Ԕ3&@z@oϹ&MTlU G_Y^XF*z&^H({jR$; 5 4@mdjRkT.}=SٺZAj zv` Q&Md&YV3h$+/h3t's'۳ ݓ[F$W =өW3=>eQ#'Jȝ]_aS~jjy ?kDօp YD 1US$C7JQf^B4rwPR$CI#4y\Zx6$K܂)eۢ5j[# S0 O=Arƞ.2kHgcj:vdc Hz֦s3o^TS-_3o  FгM1ٗ35AAzluOOZ-Y-ѡg  Va`Ui=D}3AA0zv oMDʽi$gz==CABz6"kAy=Y'w  "نgDdP,z  b,w;̕{Nlh2>{  b,Lgz6z  b,ճ  "=[z  bˈ*C'- <$ #FϺpgϞ; 'O~(3ٳXcž{u k[޿ˋdjd7ؔWISd/uB68Pi}QM}tݩ4rLFƌ D X"䋧>R$Պ~)^qe-?AL g7.ޙ$ ~Y@ SUDΈm hJ=+>l;@nE~ueFQ$SMKW"~V8CZ^NJ =..yuר>՘Hz^#:9uRNT)ph' Im)$k4KŇ" эJ IZ4$o.]tVGġȌ:cM"ZȌ[w3 Ԩ夯S_fi/w/PM Ǚ=yӪS AtT*$AQ+(Tjg{v:qsvvfZ|Wި<,"(("Z@/ {ܛ܄1\/s<|'|Y2NK-/W+&&Gh3C4φhH8gL "g;csv'Xѿc6tt]G:]_Ȅxpo}~!YN!#BcxCܣgEԿ %3_C{$}dtF/fKnҕ%#Sn|ZJ`A<ȽL/fCNc|lԐx^[:}*<۽/o_%M-[Tz쌹y mʩ{ͳ.6ςּ?~v91)c3g2YizMMq3g24lՍrgԋmq x]Yp"{T_ t 8x/֙5$^[jG#ig2,%3swko/}*plO&y!d3v3/#_{ez#OA@gty67ឋHK2y y6եo9y /c~gDy3ϙs}7+{F+īgۼlliVe,<'yfАBy6HiV$goڹ3f3+2z殶s4]3,Xy ҫg$ψ$Gg$W6غgX=<,i7=Ґg|ϒgͰz`]fMmg${Ϭf @tsy榎Jr4Uâ.!nbutwʍz뷿~g˺~qG]7&@|#'`$pcm7AUd߿>Ł]v߹'v޸]v8šc_FfZdUB'+mRqʨb tI@Ze;UaDص2R㎗\R|EEO.LFn `fݭ;g 4XY4_zneu2 0tMvÀvr'&'$3';Ds(o7DY399tB&$66lߔhgqwnuӸ \vT}RڳkwQQSwQswIKoɕ޲O[**:;V_1pCvU6?xZiYRyY޵O <=4znVw]ˏ }Kr93t@e_uG1̗eu{TSrqٵ򶁊zGȩ,(k/m+w9?G"w_. !zA!}zSŘWW7%]˖? ٺ7mK^ ᰅbt%fKh䙊f4Lgli^G! ]hNXGmQ8bÌ,A/쨭2;6.tmSh4hjhFF m>)L<A,hBgHFl1ɳx>^g\<3g\ݶ2jya"%X Фx .K EWh3I̪mXh39 meXhuFL[h> stream xUMk0W#H3쇡-z=Mҿ7G[;4ޛ[q{@xkw*}Sͮ:rSB^Udqw-yi4HuZ>tS/"IJ8ِN}ubBfIE&*H}H"7 ""A%ب͠T3H*P:0{I-Zt<cm<,dx^ҌDMR ^FjV;8<][ 벴̒ b쀘S׆#jFW%j, RoRpXzY*UL/ڻmLcb46rE%4Rqj+~V6Ǒ}w$+] vQSX *L[toХ/v3u-,w>R]uv<&#p-1ldefF@yJqpIԺPhpl5L˼Q1|S\1I E%&ciTTtcP f~~>ow\xt endstream endobj 22 0 obj 585 endobj 23 0 obj <> stream x\iPTW_e꫙IH*?JM(h%h ʢp%@D4Q֬H`" ȾHC 44ޢA }Myꩮ{=yw/ OE'sBBBEN<}2AHHwBcO';pņ5% է>:^DrJ!mL mR(eT`xfd^a;9B$8x {}֬U=sJ _|6Wپb3ǔMiAEk`t-:Y+ZN:E8om=Dߖ`ޠSj*4Ef)Δ<YvmRǦuHFN 8LƑܾ!#y~No3lP3 sM|XۇXSU۸Wܒj1yˡӍ}5HXC6Sl͙Q^Ԑ҃*6 s+Sޠ]mre>5qFfN;&gPn[>P_(@0HXkQΨ,5PjFߥž8e~4pi1AŦT3g ݔy2UF~9ê+ӬkU:H1J\O#U߫lYIgtTY6̜e= ?zk( :w`DF,6j .7rƕiVQi5"PA.a^6[XPѪBT43qclۇFwHW9S#F'ǁNav׍#,#6j8AXG0Õ˵l LBZ/)-,% ]P1KlXPoYlx,[ث}$#f)c ?8CW(R>"{HYI+Sr bvGZ25;2^۲j}PYLNǦ_.ڡmp}W}Tx.[Pg '8$o~DrvesQ{B,~8.fGe wɨ=!TCJM`}t=!TCqdtNBBBzNtBHHwB O, @iLH " ՕG̐#+! CAzi@P# Y=HH@W(q`^]-+P`vvm\\cDd*#;p֭[<f탃r%#/q:ghxoN&l4[+eZO>Zx4ܽwx Vu/*o򒒒bcccbbc$GrrrYYYQ]\\\TT *0'1)+oTTh% |q[B ѱ]l2$U֬Y~/rӦM[l*Lil|,ЉpFXx,o!-ҿC1Xe%%O77_,H6#P2w5sϸ^Mi۞__ 0*֣Kdee {_׵6%)cǜ1!!!+++{vŝ;w.??eY|w6JO>YnhiiiookVVVH5\ZZ ݿڭ֡Qpfv^pdS82IQ0MQ(coocHdxxӱGǞ={ŋKEx^zWMVDܚ*>75 55 YY%QQ9NNю5#Fxiv E7nз,^{m|`ҥW޼y޽{I ;;;?::*ݽ|( -,,|}}_}Uwrx!-p!~(֣‚ aQoбmh?y I&'4soTǺ&}q``9<,R r[1ll"RpqؑaecjagWgw/( ǒe=~oɴvuoذ曃zzz믿L>0_?U;F$iT|֣pzCJ(׻ (bZ? 9&NSٳr>?IgrDوCIrϞ=竿QT; GL|TȈOzHRGS6#((X%mW|E`zpi@kԆ ux5ƫ]GYa@ Ŵ_Դԡ~tuM|ETu]rwӦ` B#~~~?H@)=s ""/\~e[3zG^kBɶJ#G\\\4֣ǪM GJ%9[Q](NV{%zV=ˍkhlj _s'p-Z*&AN啙_<& rwwno>|**Bp5++ "X6n@?6bI駟"(CY׏"y=ޗbl%.P8[i|T~JE)p'H`R*}]:}Slm$l7/i-I%;-=1thhY߿ֶՕqcFnnocbbW_8֬/,o(@#brGTL&&&ڿ4=.[ U=kkk'''D"Չ;;;qߑ cѝr˗#=033sttDomll RF2L|T#z_ Iɪ,RMMM¦+JHu  >#УO]s/ʪ|18Ů57 Yº&}PDʐ ئH;H#\d=S?n޼Ν;111šYeF*vZSSS{ 0&|9$#zTWZQQhHvIIIRRҹy[ńGiOek[o_ZEEGqQ_w⢂S9slSWU꿄EJfqŋ(uQQQH~T*bI~yt]6ЀApJ*X0? Bc0ᘊ0r!Vz\T b=48pv>}&~=^Aa˪4|>$^dBBùvZ}}=ZK,>/ ZBmο{ Gs՘̜`-=lmsp9"ՉpݻX:?[ZZ-MCqYUBʕxdjZ2mGB@W ?``?/=) endstream endobj 24 0 obj 4332 endobj 26 0 obj <> stream xZK6 ﯘsL ؝X6z(\KR6i{blo#%u՗^g 1׋&S%I|ׅnVv5]cW-jUYEzxq:\IWwdvϗjS$ޜ5܂~ERC|oFB SBH`/Š=_?~hRO#q;S7QR+sS3;,PVȉBwUP'nzn:8`%e>J7U>T>I`@V;*%~< ٠f   hGd a㧅]]PHk}c )K9oư磰e?sr%r틺`,tShVMd3M譾VG* zj)j͘q@a gfE4&{Լ\U IțgGB=Z\A-kIQ`谋;5Elt絓TI;6PHMJhjJZ$ вuldb/C{V'ZF!XE0W`{]u,چ|кYAQ_,EA]E-WQC+b~6~Z)Č9d,1}|˱J_ؓ*Gt9 + rV&&1?F >ޝs6^ZY]MՇqjlB}W,z.4eGv3oj.{yPϊ&`ci![(R6ma5,³s?Ƹ=h8! H!f3ծ(]w;}VaT  0Z-Xn*w%. RB= =+ L+'LV ^:h ΣwHxgwK\'!U CNue0h+H(\fH20"cY< R8s7%6rb;`l }JWwvɌVK\;vSn^!}v B ,z(~e7>o]R0ODf- Ɉ62-~ƭM/<; !%DJ љF>fĪ"\*#Wh*u(K" -aowN+6iɅɀ3% O$sJV~`إj%qj7|ei@eF^Pɪ$B.WjI/LBş0eq҃׺|OjP3yLgEZP: JZ)&G,i]g]c:dMGl U} #Z*Crܝ+zsM=,ϡ{̕p';q-I+(,)I<lE:]\o: &VN9/VD}5p!Dc>0m œ oGtZ ZR\M]9@;2t";~^@>DN59hh,n52zAFb?8tuo:Yv,`dA(]71b}6+[(}=Efsc7{I}H>\IDx~ D'}``  nQagp.јOp^Yv}1GQ%)p$1&]*qǚ\QRa!FrD77rU͸v'{,--eu Ñp>'PioU4Qjx&yZU#BW ;OTLKC1=}JY5aVմx s%n>,7׬ۛ㕳7;k Oh^OW.KWgII}{yh㙿mxU_ۧ/ҧ5 endstream endobj 27 0 obj 2538 endobj 29 0 obj <> stream xZˮ6߯:@\Mؖ@Awm tQ{fHI<0DyEu^i|D~~_Rt}qS=MG8jQ#jqT48 ؜͉؜͉؜͉ج͊ج͊ج͊ج͊ج͊،͈،͈،͈،͈+6'Dxlʺ~%tJw_\Lw{<{xEO܏ޯ߰-^'o1,?UoJs.<KSу1i\-\=v%qOAc4@ جRcl,%žH ,]r$3Ir+ҙVoR =fj!Dq<=v~5VJpƽ,&8r++&Љ̷h.o[ wD„,J6ȑ B4+̆1r뚖{}Iy TaP౷T?FA{pߨDl8o =Ik$G6ZCB@L`CBiCZXT~YӵMtֱ)iEѶIR`$r;0ͽ/S*OJ}ሠQLE#)4pӥঋmnV~cb2ٜdb-NŒx3}(ɡ5mgɪ'sOJ,7 C5ÅZvˏ5OpE2,)*8XTgí쑜d`y]zzOl:(0iq-k{,hwĦUC#`' @+5=KxmL5V0+#u=e̳xC;fIJ!Y}!ZnS kXm>Luri 皯gΓ}rnZWgẒb'6gm3!i+nH!_CU)#챨jFmrٺJ~-^=QPtqy渪N<) eʹ*%]ͮgA9JsR3C #T`rެwG jlf3nf] )ױcP8eo1:vjI%K.FЈk.5H^sֱiZEI#| qAu݃|'T=m Lx ڬ*k8 KPb.D IūS-SB]Wao0ƹLfS,V}/Nk.[ySC|+gG]+_B0/ޠ/[Q'[J ѽ3j:Z%Nrӊ[֬M.7G0ךrʾ APІkJT4Ή8RS) po"QNL!*LwIi76v'S "qrҋ,KO6Դ=6|){!ҷ쳧$v7~jAGkc%f:#3 h#; +ҪܓH4[WzoA+.C>]<1kPUkYJszh9C0:V֖\)qJN+ 4Nq}KQHJ?\zcdMڧPlt OHLp̷p] $W~}>5j3\6\dzLbRX~/-u*DxT%),Ϩs޴ VZ4M2Qp7-mB(?? :5p6wO-rO7m!tSb?:ce&p ;$X?s/_ endstream endobj 30 0 obj 2120 endobj 32 0 obj <> stream xZKFﯘwF:fX!;C j=ZjIvbcՔQգ\埧/2Z珗_\z2ll<%]b OFQUUSJ*54dUکRնTۂj[Pm mIJSvcUFJ;UTiTAzUTjSmsmFmFmFmFmFmVͪY6k,{+͚ӄA?/%tM(&Kqmb 1';O!y7HRL^|_>l6w7ջӴd`!1a Ҕ H aS/c ן=\v4tv2s >ܻ91T;5Jb]beĈ\YnJ6=̀S]-=]EEX3h5>kVb߷hmEhw/NUikXYQovEp5Ǔ!;2)]/rrZTT'+bCl _%B>ڇjo.C$R,[ɚ6J8O|azRq-k/`KwUQhΩQ qZR[T;7 PD%G.>4f"Q®A+F`bjLܝ՗vj֩M"˥Zy;9{v7_TwcpM@59T>DސBgAȺz-NVpSC?&.l ;S  Q!VJelŭ^; xf-ؖG0WY5%!cz4oT Ħ\׫΅q/\ȗt'ak;5˕BCZB/g-L}F ֹZs E@uMưƎ?tԏR emx>KI"-\: J,`µf8,23+ ܯW.=vr3M4 {S(`tڹn$ ȥ4̝PeEi.$AtHz:K.7p8uYll&"n=uT4LʦDyUвU9w AKǍ2hƵg;?KF*8HR\u[P?PBˬZ P+'V1u3#0ks 5H{9$,'O%&ph|yV*7﵊!{ ?/ECLvQ+-OM;“'qM[N85nEzNis|yy=x=}5^lN=y|cNsI+ߏjYz8)G]3+IL`?K y(igiy6HW|)/lAВhXm: vβTik:d~<0CpBB"Foj&ҏHSTxpm.-F5Fߢt\zKG+eOg h}Jho&ֿp. +yV=#K%,uR O.W/MOo>\ endstream endobj 33 0 obj 1748 endobj 35 0 obj <> stream xX]6}ϯkFcCCmP-$v"RJج-K9gΌQn>|kTp[KAAiqh% _-˜.10 c\XpppppPpPKc&IМ!]ͧk, =Ff[k"3Fuq;F}hg/d/ 47lck0{ ).^\7Mˣ;z |6Fߎ'0EwzlCv΋7 cL o8Va`\횧 %YV$'gf2\%0zYX&j2HW3hե:OCc*&2j9`xl$ɘJ%_*KmLhmZd%֚Rm'W\љ?"vAj$q+?L@>K DhEy!4/)~XlVHkq$6R5i>uG:F?F̈́+Kl:E#bKR36k5ϻu&G $8cs($;W~5MlI\Q# BI]Iq #u+H1b9LLfLs# @IY!`(ddZPVlavj8!dtX>sdn\WN*'`@준5IԂhr/2n-$88+g XNKH#tԍט= Dr'ϊ) 'V.[U%(pG'{N)E "ݹZqޕn>1aؒLd}0IjK] SS$I.al~kvrwԕ:q]YYZg^2Ps$#'hCC*0Q"%3/!v1Qhnx梳P`"5e [ltJKJd-\8L\u#Y O *9"džgy8N dj9ӡ7jЕA\˹'3%76O/[PI/e|c fM?P)Cbv15_>WK endstream endobj 36 0 obj 1384 endobj 37 0 obj <> stream xŖjA}JQ} " i+,lKDD%aMCęN_ ^fgLv #ƵL&^eZ-f1L\`ފ^̾ h`D~ O-zBt\4MC?0hYz>o!DYUUǽ^p8^@Ed2t:{DeYgX^fNtQ0D"6n7zMԃ&sEQЏK"BX,bQfRp+4h\>L&Zr9U*zh@PnX,mn%#j5'Ja)SfQ&ABgK:t:baaD"OaDu@Er|HQż#h1`Bt<_4'vY783XE'\f) h\_N endstream endobj 38 0 obj 510 endobj 40 0 obj <> stream xT0+t^W3f,0M60zv ݥ{TiR29%ylO|ܹrhG7}scn0trUҨIlQ ssMOJMMyn3kUIܧ\hb/4hvWT0%clqB@}$Hl"- {=Z*Q[PBcb[^qocPp1 ]dC*}@gDR6R3 7ynݽN [wZi@Kأ9_|ל܊iJzkN3 Q' "*:aez?`&`_b˲/,[N8´J'ؕ2׃U+'.%g 1c\F8ka2j|EC!~jѢ*# P2FUk[#bI,9YKs%{|s'8ee endstream endobj 41 0 obj 494 endobj 42 0 obj <> stream xt[Wiim$Ŕaftb;ffcf&$3ʖmeіd[m罙܁wos4i;Vo;uΑy~7_ͺ~~_W~?{?=+oWmݶ߬w}i/+o~[;^ bu˲uY>d9ߞm֡t]Kk[,SǮ)m@y|b.w +_ʍ)qV>u|_{k| o~ww~nnk[߄O^mo7 /fÏ~ߞk؀ :?w?+O?Tl\ooP_%?!)W4OgA~ҏ~~Mk~s/߽W;?>Op&|n[_7oV/F??.O,,_ϟ-p,a{[ߢ^)S/oO]%0,-F}bۿXCw]ߞٹ}VaQ_˪eW$R;FDĕ%'RɴԊδ fz%3++*0昃JT> 0.$Hji4F*^I4#֞DmO*kOrP@U)3$mwJZ7657CNB O,Eip94Rhޥ!y.].ȿVt%JDe""JE\(Vx1r& _)̓>'|OxJ?z=[!$ۉ\;;8Zm{GJ_ Bw zT;rk nl]_qyu{n~͗v9n׍{nu6|>o}k{ "`˱-o/8~yoaM|6^ckX{o:=){[~]Fv/'#?0v;=Wk7ÑMίZfs{:{ =7:xm>a_ӧ}P[ۀ@ĩwN{:c>8φ}x.a;·\ |r1SRg 2Kw"bv^y-vun=7u$udž鎭SSs=fKpv|5_P)Go)>}A?Y|3e͌&ps:qy d] ̼i@,DP@D+WBrkroDߌ*t)q+sݡ% DBg"PH@H {Nj 3fYFM+]P@;:?1`bj#RcZcsnTeLSQTPuTCeXex%u:]]6C//rfi6UEWƪhzDHUF[U>XY>z?$7r97=MIpnKQ!uJ+Lyy.O˭ͨb%Wt- l*;Wɯ7p E 5I,na=fc/% @YuDzJh/'[ʩAa$EZIfa3- G QL/HȨbfɪfWPV2LdpոXn-'.WW/mPۅ4i/! F¦f8 *BDmQD%h!Xt^cN}_v]oF  NiG|I;Xtd^SxnchvUYQ^VB7R x%Wy'Wy&Uy&VBX. "xxvw*\i tϔ̆즠&32}SkRpS X* N17A E^ -.w>0|@gwI^$8t-k9q67b\u% i I}s}ڙ0$8>^~Kj<8m4ogo5)QHC[g<[g+A ^{nmgHC{ mBϖ1jh?\={ZC{R=C[{^ه u׵vn`xC`h >XҖ7m\g.3/gz mEcIг@Lf}3lfGsYC3I44LTmYCL?F764!=1ywia?fqa64_d2ZcC#% "C'Ć nF&CC,54,iWCr9F܌*" Ȁ4'ճb.-zDX^Y;GbD#fp$L@rUBMYp@_?JOP lCiLEhYpq+ΛSqZpVЊhZjZ2sҎS 78jj@lC# Ж4KC[IϰY \ڂf4܆FH!TЎ,6tdh^KZQ7ᓉr̒q¢ҁ-iA9Hplh淠04Ly,Јf4KCKoE;ǖގ.24 ìg+YJJzHȔCz&2Y%]o Pd  4쑢l}qhqXqDqN //%1ܼ>U;Y;^;VssŹ܁\EQsrgguwo/?ZƐT}fpHϐDp=wK^&*h˪agYY=ٸըL\-g9&.W;Sxm@ _lxf-&WZ>ګjU6sUBJ T3ЁlyG/R4i@f1@@I\Ti~nq |OX!Iֱd pVltJ ,+I S\W2:t8GV'AWv4 pm}pƒ'u.{--( u ;0S nk[5Ml[[! PSdc_ah7yu\ oh&^@ӫz2.3X2^ENJ1K cTfBzwj;ͭ+lKRD [Eŭ|x]xZ(JIJS+{+zXi݉P'Ÿ-j)lsB ~U^4;Tx[|R׸q%.1%ŷȁ] >q+k~ע٠N}  nk]/v|4cz}vqD hߵsi/G]0ڂ.Χl@3ڂ׆mC W]&C?@62vqltqcah -hhtq]wq`h0 h=4[dihOy-؀J4fT#HҎbC#S/Ǘ542'- -YPLz7Oif'- $iv/ԌviL ZLv10ŽN C˻Qp3)lhH`f44lρ#~%_Q2*cbaS9D&1IH<^Ӻ츯?O'Nb)L(dzfD)Yf<+I4Jd%g%벓 c).~뿄"yk[7zDLHxNxNhN>'U:椪rR@v,;}yAB"ioRͫ.ތ(7iņNK9f?¬@Z&fJOS;ZhK4#fIF8RG:–2}@Sx hd%v ԝ - wK9r)XPX3e^8uM /*B5JXa6`>%i: {JмW'WUA.!*hʚ9[Ȓ6q@(G,mсD̕{S)ЭS P*x>DD@3-LS} bGiYn0LY BB1uU)\&,PEq9 QNi"䷣|TUP+ʗ+n!RznjᏴ [5<Q _%ˉ 1hi+u6zN^-'QٕVޑT_W[]]k"4&$&8^ZT w;1Jp.|LqpzÈ6-7Xogl@#7an!C}ja^8]+7aC6n@sfg{7hh?󿥡=fړ4AhAh h|\kԳuq Ͳ }0Жv-Fڍ]YJC[I!D!B,Ӑif7[jh(&@-ThjVFk<\zKl:󏄞 U2haR()Z-K'E+b4I1C)1#1vTXW0OaHǧCGi! %N7JSS$qJgׁM}aG;2#U,UcPtG9̃ [~oxgg^}c7#*lAfXREJzB}B[ԡ OˆQ*Ȇ$ z\48G)@E1X3HI VᰚB)YCqkCdhB 68A@ #}A)P-BIW$kBkْ!lO5 4{+ɜ@:u3dMB8"TKRV{ITg*t$kJw ߮ ψC)Ȍ|dV>24UUe9nV<4-L rP.0Sn07,o~J;ܐ*FVU%[x SCЯ}}O;Q6ru=.19)EJ 3%zb*F =XjW lw @ ĽU[YR乣cx R1Wͯetg]<_H+g1RI+Ym,og ̨N,w-u /^E}~13ێyk#j@ =Og.NǗze4 zоz9׳ \rI{94z< hCefrj"^IϾqV\vY9G v}-14,i lFK& | uwюӅfjЈ, + a[ahDcj ICCބaCIK?mlCCfjF'>mhDaahdKPHBri 8 ,ӆnԳ]OJFEdΡ- xRB;J36$fQkk[ᣣ33sgԆnjcJ#6ͬ@v7ا7ا?ć# xBaaޚ0om7'_ g=|p5F JDa~0?~_?/̟⯬|wII~v7R==,a'Y{?BbGpmzƾos?ç~jl=(-3pK2s*\Sċk*0?4~ohJ'iFԆݴK A* 걻fl[M 3ՎsP|8lՌU f!99jW IB-=T]v+R&zL?GŚq(nZ䫴S;!Ռ  .ǣ?KIы@xTNK4[PnNF{6k$=|2}^(Gg,%3Hle)fQ|uW̖wKDy=KP)nֳyGH,m-lIOC?.dHj';6j@C#^2~ v9b=tq,GB[a18b2 hGڷ3lhiD+&plhгe Ԁ 4K=6]KF-ۆ%`HC[sP4dhR,;uz =-تf64,`FK#O2CLtcS5/4(5" C4 % I#g`+44B/44L EÆv#,1VTSlm4MJz҆qϸ=b\qoY^bH2۟͟i^1u))?zʟs<y5E~tjj{&Ҵ⺠WIwSớT&*X׷XرsYze^꟞qThM7| 7} ;6\cso}FofwXG?}YV]Go9rS樛.{p?|?=sqGN: OJ}s^6Oru+~-г`dL08!V@ >H_qYJXCGcs_~ W(~d~?2qNFm4jqLM=AjiP ]PF?!AwRy{:K<ԣVv4aVdlJ> 8#35ԁFgÓ>] K=̾͸|dJ}|1ĊM3܁GpL9?-:ʮLzpbiと#9G#Jt4#- P>ډ$HV3 dk3r6fPjqKXk&iͪ}yRvJ:<$nZ͛mzґ1l'EIh6pe~%X;#U7Fy60'Z[CB vjI!ڜ)kKٓ#j;} aY'qo"fczb(ь'­j3Ί3vwXeO"gS F)ˇ5ŊtLgpݞ`e:ЅC A44(̵*u ڴ\7ۙ.1}{W9+y0n,eeWL-F|P3ȱ>z@5vV+ii̍iU5SJf=H6!mdKk\v5qsԶ[QEq#f;sonw{q4b-rrcStqЎmh@l,h@{|ky=[bhVh@3d\FϞp%ˠ-X mAhO ZkŹ\3ZОlh(& lh% rf04<} IL%03 /FL% obsK3Y s3ZC9fC#%-i41hh+xZ-D/U v|1dh8Eh^%F@^_uGi7I{oe|겇гk~)d 7֟4O*l>nI'?nQǁ~sp mPeT:,6/ßv)O|ڰ>s줸O~SRϲv֬r3M@TNsC4[wZ=׼fg2^ܰ3P3!=S{=3f&=P"%Hq(R~9Nx?_z_V&izF5O>4 b_%y$DgGc̟`TUwx9j3įL=lBfq5)j>C:7^((8uR=o Հ,8deSҌͩGQrdJ1,:`l\a CgO3q*< ǜuHpԳ1ua]a/Ŏ[QL/:\9PP[}( %YVm  Qa {IpﭨnEۜBEY^a UM4R*|dhZ2$KAq?*5<#"O蛑(V{JA Zdp 6j_%YLNWE!g##$dL&R!zԏ Փ"N.C)l;jy2zB8~ƫ~\00֔nz,ݽzoK}ʖ"4897zGr mihnͭzV[Zu;rp Կy%sx3W.ҳ'\4{h@{Y0=[45[, ڞol@6 ;4l|Bۖ[sZyzfڷ#p .14iМF1YMLupEz`24 Ͳ #[ՌKsk͜I=Epz9Oxa=K;F'AT04zvLÆf>k644K64ˎN04ButhZ>]`Z 529,pEGV/K.9Dv#6f@;8f9fc :Bz(M166u'mO4i=m8cܬ%-cY8o혪- ۠af@?=<`^?&ՎI4vVBZTaÓtI=kGn=T]uZsScX-"JR5M019hIN ބn PB:x/jPb ̻eVʛC)Vt<OU =zj[iLfhڂ )oRjl @zHLgJZ;{ӄꨳ[pFߴ!lDvR4(J&.gG[잱|%ѹ9گ24"=+ibn5.&={/#oț ȸobd>қWۓJc6E5Wŕ^ ̓";{E}z!S[lvXo~D}&$J-!p3?B#{/`;mm'H/.ܺ' BbԌO|.ZÃۈ%.˳>gpH:=$Otu7juZ19nF.Qk~憇Z|?Tx kX𻧂5iqY{g!G 80FqѳO/E-fMv̮k@ nb1 а{nhf;6&Mgv..Iۤp%;4kkfhZ3aGLeT-f kES gqBj^cx /01MwnYxa4b̽Ⱦ29xf9A X6k"3Mk.X8fDͨ"瘒۱e%@# QڝR I/3S]Bb(iǎ^q|T>32ȇJ|J|bb}Fzkj~Ʃ'od:u>r||4^,3=.g F:8a9ug[omqWGNY iBsݝ}+!*SAhZzt=0 zϪ[^L+( Oβ>}˳=~>,Oi K sAg%`V/>1gg&}=uZCgl9q vc^n{fH*Ѡ,^(Y=avMitYY *B z3Mi@l#Vf|`w& `!._zo#*PhDcchnaY`|Ex5MM!CcëW TkQVM9Tg21&K]eSbXe_ޭjقz%WVҸº@ʳa1J:W_@y6ү)GӔa}i3/ou5)i6e#,GP{عVJիhU4cu;k+gWt)n!,Z(~v51 `hox$ Dk 7a<<1m'y'' tgɡ>`kbi O^xuCޛFylmvXgXYgt/œ\-Z|;&ޝ7i/o~GGkK>ϡ];hYB>DzWcv@enk4NX&IŠe9at+`)pSbauhg-~)ô8qL:fxY2=f);I_6NN٧Ŝ6r?0<}!q1и7/\ "ˠ[Hr, U{D~ Vvl6nEߎ+uy%U)UNe j/>9".<ֈel"Eu ]ph5a0=,R"HKG"nv~ݑ~z<~Ed@ ueuipCtC(pCpپ>L/?P_AanARMm=x*h=j1哜߾l~zLayڏwv\;Y ?co{$ý OT Thj@rx -_ {0>/-fw'ؿ8{PY-dMrjӔ{#"n/./5FqiH$ՠg99q>Q OrEz6G2 hFЬY'Y84l o&*8wqʆPϨ#aM jTH뻐NmeHpr{aHmK@!QJ)ZYd8ҌkX~pho܀~VŧYV։V-@Ky {ƿSk3ٞcH=VY/W9 P-NF9BEz&@MMaBBy6/IWIjU#* ;';&x}r)+џ_pՌQŵWv^{_\}:~ 1|v%џ\b$N;n+Gw+܇h}+)9H&Mv њR]fˎ=2FHzGed2q78Is?. 8Hr. \`y (ą di`CPpDBPp)Y"{/ 8C\BQzЂ+aW B ^ ixuFЯހ4RBLj"fdM",Y2QNQE$$1ŀ Alklk|{347^Q"ϫ38K+xrW21µWjL1o>$3I,`LG$REMjrR][WW4T* c抉JD bQ5\5\5\514W險u#ZZ\K΍?e3O2X!/i/m1xö#oZzptfW[?ɦ+,bݎ!aA\=sm~EFp%󔣂 xK:e+Mj8)3 0}yodAIԀzeA2߆E3eWT p ų-)=fRN9 ܿ>:Tk/ϱԞn谕Mi| 3wg |$ۙh:ҡ)E*SquZ#ʊYO.qX0Sr,hcj_ oxt]9K̲7tsVpnV/Gh#3s'/i C=o7839>u#[TxZl]Bb sH q\r3[ `x;{n,}=~uRYLOv.)pM;q3 }}r , ?3'S& N" *N:^b7!ss Mr2K둎 $[Qzrop CwC7/ӣ5Z28G22OxF84 [ ധ]SBĮ`C*fp$`+{dmg7+ LSl:E#B@V6M0BicF/4AIht)`J' A m^nY0#8{kLatw+*LySwHifG2ZMkU2fdqGh~;|=e5GZ[JZwJ@Oya&A\7S'o#iޙ;٭~9y@'h"00s~m>^͞iM u\05エqYx!fj1S If\ꞘzabMΣO%N5%FIgzOf,x2O8,Xv" :Q ++Dqw8PDDD.#`YSƎ!8fh$(_J.H4QHBռjdiKCP6!Rd i J`!idڟZsL(JAu/NQNf* `o/if^L[P *L&bpNMo&A-8 ]כ]՗/lK%e2jT('XMt˙+Ir&f|jt h !#ʈ Pj MX.2BTBSϩ.yu_5,U {3Xл,o|ė`e"CtKWQt#Cw@޴s}>,_;+ ܕI}@1@Q=ՓW_N@i((Q^ frMs@r0w%<bcɻ棆愈Yf. LT=pGA 1O9ѯC7d'!ŠQW hRxL9/f?@ЙWzwڻێ߂o\B) vAhoBz_G|}e@%ML3r y1J D+"oTP0PfVS `JM0I,vub PSj7ʡ3iF1u&A1-іwD15YAE$riju4ITјd`QBZ|A0.eeU3r@E}#|}&]4cxrMP 4@1_s0|] bߒaf5h}߇dOݲd[lW-aqw˿RuuuuխCQ mqwPТz L/ 'D`)Z՞'Ge:d]tft`dTuŢne]*ۈGz~=@hM&5 E^E+lСJ䣨G=Xȵ9rmLsVsF^NRߩRTңXt\[B-U'WoWS >&nnu,L*LtHG'=ĒEm [(k&"&(inRQQ1>\lAQ>oJثjJ"P8TN"6sDiS#%.*P4Q0.TPLudX4uXڮZglff3-X(i͜Qg5 M Sn)[ޝ%+[g̨"i0HEQ;Ԩ66U(D$SžXMKt*uʵIeR3JPtH@Q̌XtbQԉ#v ڮškkL u%(r(ԹI X%52ՌʏG *TXM*%UH((vb͘h,fQnBɈVwyd\2;b93@؅+Dk{slqdS݂Wr[ѡ+@_%j7=EF%G$syq)`P:Ri'=o"ZHqÃuMOu Ez!F":>:ٷhȨAz,jVK#-t,4iЦUiVU99VBEW i]iXTGQ"3 EEx U]ȝ92]^X\wx">i u+o41u\AQ6X77imu]ֺNkmUm h͞CG,l#C3PīdenO.0XDG 3R_UlPQߛP\](mDt@aӣMaEUBޞ-Z _xNlfwѤBE#J6貇]tDMuQ QŰJ⭁ aa ڞ33ڢ6GvQEcb\F;T# X;CeX\F ]ۇ/`G"?Mz:" X;;yFZ,#lFF Pԋ0;e~JBgHouXYGVP>Bce`8Nc}=EDj&+! ARGVkeu8}'[z`z@3z9n/Y%k>[{ޣXl^zXf|EGk?g舥o-7ƌy_ms%叡1Z%ǧjΐAVlc&>Md ݖ9s:֊@Z^~p}ՃDʇ~4dY IS  KxKvs_cXq޽!ȻE'tL6!= TwXZ4&kOlC};wUa#b)g>ڬPTWy? zm;wYf%bIcH>ܬP*Z-eM.C;>LVȻN_Yj%ӳW~^e+W4 3ں}Dtj.s? zE27(pqd/k)^c+;~qq)h#[zu{eݤxbyIe~"z&ﲕ+}`걵{hS-Wy=d7܄K 5[[.FV1vQAfiő/,[tiLx)yW k<}Ňe]Ҧޢzҳ9WiuDT#m-"7~-R/B6c9nGe'dy5/;W :R ]l鉨GόB]Ty{H?.Y2r ,2"3-Q[,t_~g/]1z';23}7Ljv8CuOAYICzf-i-1=[JWQU$"guxʤS8`.{jk!:;.;QO&lHtTV &{DmGZb T &zeWdw3 hSv>E#C@@@@@@Ȼ0=k uzF}Yj DT+=)ENq:w (DpV~aY mԁDS ׊.d&'?sEoM.|<42 Y =+7v,sS-F"jbN|s继O58 OQ8+bk7=d@O( nb=mS݊1:ǵ VwbbSyۤl{ys! x ]nSC"k2Q3-v S_y܄`)_ aNغT$ĺ[\* n(7;,}X؋E߄cD+sb=42!g}E NCK?DȚF5y # .\zRe^g*fߎ+ۚa&9w!=+jgu5"={w'nkc·Ay%mwMb".g =C6:e-gFۼlMm=~",xM &r :y1@у wqҳ)J{UF &[s{/]'/&כ gӐɻYJ[Tݶ&[KG/#gyr#nhE}I_ CS}Hre>2rPiB ::tk@:)Fa!cłrgSZZzm`T* )nsZF#L"Ig5lM'RFXgp \vp3??1z@H9* :)LC6=h{=˗/7>* )ns@7h@'%E`zY˪/pP'춴FUόpz(3=@lPTD*mf.F2zYo}L5Z _fe0"!84*tAUUUUeee%%%EJBj]B虎?@3kgUڬjl~saгz\#o:^ >\|n)eԬ1v`DUVִ"ZZfho.yu\ D%ܾ};"""$$Ν;sΥKj5g!HV+fl%҄3R*>~VANMͿl(&Jj{GXB gZ=wz<3d2r:'gLBRXYoHIMtυL]ٟWO GyPb;iz~Dԅ[4{eeU[$I̼`$`"##c(dJ'N@y***8 !L嚋/@@=C_>}G=C>>(2U &E~vGI유g &3lLKճ2gL=33$cnh5n;{sWoQ!o8vhێoOyw̭;tEEuN/^zupvvAnn6BX u|> =Cmu`@vᴴ4BJwuuM6=sK%YiiɓLk͜97_:gΜp{޷]0444 ?3cߊm^ iY &e!&00z΁^30FIgLt=+wgރ̰e/-(i6!5J+RaF+**܍qp.ĤtO?_YreIsFzvgk֜-*,G,ɪM&ΝKgT߸q#5JII,3W|oGCgz_>}: pp¬LdbǂL.ϝ;رc<o솤`Da6D8B:zC+hr%К0h}!5}ubы!>7y #s]4 gZo'QYIkЂIh4ԏy̔gSs-t0j5q&:6q9I#"M6HԄ(Ukzߖgu~ym#2s~Ziiי{,CCrEKmJJJ* M+麰1bTuu\^Q[[YTTqݳgέ\Y̍#ҳ۷o>|̙3.]rs'`-55g۷o`zlٲQٮ]L&ʕ+|Yccc@@~[^^>_SLEQH++9oY,&q3Q,RBuH)GG! pǹVNqd5H^zF|dKı+"7K\5 *zv׮gN=Sbמu3LjEw>` 1_ݻכ2 +w޽8pw#lV\[ dMq'wtйjkkO/޹3z5k,[0w-K{mFg:zY H޽YR)f4 ٌ3 9m۶]vtzFi wyU9Jjg? #*=#:YsD Cccڜ#k1e_ō߰e|{pi3=aes⥱+ )clWA}>Sψ䁞@0/fB,g#7Kx"r0 ?RdW{ɜ~lMuiDgnoy=u.,ˋv)*22 #=ۿlŋ#v8ݬ؋N͙s,hUH޽{={v>v#GRTf˖-|I${n٫[o_~֭_;C{G=y?@Kr諯Q5RFϨӚĸz3#x?x1I2q5s@C;j]{@Ai ZR)ԏEKɯ#L{jZr MHAUf#sE:xmT&0n0܌跥%=Ykد=CnVsg 6D@yVX&:9vA"?+9p #7./+-):`]geݬ).. uuA{/#G/\HJJrj_zdzĉHv!fhwAb㱱͜z+=>}:< *P.s$JFϐ,]tݺu6m"GϾ5k֌Z`{fçhzƘ$ 䦨 At1Չ>ۯLCVq 9\? _od霫SY=3z"LimRW2?rvQ N{CY%RN0ΐ'E"iP~=}ψ-p=N=s玗'ՂχVTUpfMnVCЦl~䙞3O, qdquXV/ٮ]eKf~q fݼY7<|ŋؚ%ܔ}HBbcc de͈MNDTggRDTŶmۈ!C@Jsg?)S̙hѢ dSH֯_駟gHq߱c8#EӧO;wʕ+?#u6n܈jxbl#*IW#eqYG &S&CdƵX2J<.Py)IJ%ق]gsjY>гLR*ɇ:azV=)H<3Skʦꆆ!e]Wz833ΝkwuuLg;v-[zuطF-\^Yij:Ϟ)?w@1WL*yyʈA33OHnR]ygyݻnPA3Tq߳ٳg,]tdAG԰$I[UU5HzM;!ܲe˗8_|֭[Q?zƞ=z zVˬޥLn֫z6kόzmp 0'=555>} IDDġGSJJJSSS-5}Mҥ4dʮ;'O_]9w iUQ5n9s JpBqq3BߺvK7#Jpgjl׌j.bNz71Y^^^= 0I=# ȚDz&q9@4,=sg#z&A[F}vESΞ= 9]ď,2Xz7ۻ(p; WxFkZ pGEEݺu\?Ht:*Mgn@.P(ӭ6P'C3g'gYY>zNڳqi 6QGqGr+g}._ #g㥪bKKKKJJ!OF΄JLMW @\zeZL٧,KddG^= X#Hf3]Et AT֊6gjmH=x3??1QzV 393s Y{%vc 3gWWzFMW#l=˓ ,׳j@ĐJF543Dgrǵg37퓛րUA0zqub٩<|f=$:g+A0zqubɋ&~߳gH*Hlgzxr3cv=zE'4V f=K&7f91i׳B@@@<@3^43Ӏ||̡gg,=c(ZX杯W*x?vO wqhmܽW_/te}}EFF9r$))CoLMMed>}C3cƌVqG7Q ;;;u::$&IV r\3Dxb;_m='Z=--y홴fLxmCT7){Dat.3L I=VaMV3jiݗ7+-$0~R.0#""V+Zb)-zEώ_Hȗ ɝz֠VgRMoo_^+2`$VUU2aID=@gn j#H>܈YLnBl0q['=Ox3Գazt״Y4#A BW֧n˻:ř^ zEώ9=kG@S:!7{'zxEώ\P0.aO =kM}#졇4iҢEHC=@"k"LgKfgwp-!$g|@9^8}'Eݗfٵ e{.BW2OigY|C5Jƙs)pt)r@dNg5dv"RKVϜ"+U>S8+0 | ^ń3*eR|rs凟7ke}u}:m*1=s[*7`ٵq3Zq2Q$ԏ1F٨x&L,vXŐr/ul /2RJ(rD1V8Y JrjʼnwGOW2Wdm CCN?y_Om~c 1ԑ%aefJ{. EvZ{G󻪀. & <ݨh2U4ci+}֬uֶjͶPƘܴ/w?z"~Pg/6Fᚸt"_L.R%< s^{v~Z)qY sBkE2-[°f_o&C+g+h2K)S)Qێc~#װѦ0QѳƊn ~0U)QhLs,^=`9= c聚zn J{І#[(zNzF؍;GVTy3/tspyjz^zg"* یTX`+\Jt3g'®5XRc}ҠH(4ݖw?3nDFe8c^nmd@ؓ.;)^z3;WzHLP۫~~nW'[0z}01A˜StWN=;[֨-k"#F,I]"*UԆ޷gܤId?)}x*AQt4tq++:K *mw߼b&3/zԤkTc\>.YUUlTLgLWxѳ 7fMӳzVӬP5z%`Gg?gH^b\r֢oZޣY =@gmz+rM/>9 Ym !=@gZfM_MgUܿ` )‹l#7kT{׳UUV3 gH~,fY۬Y.xHZM:3 )YRҤ27LeG =+5jYz0Gpz,Ź])ݟ:B #p|83qTk$5vul}Ϙjj[4r3c<8ӊ#>g %szfip Z2c !c[ڍXȺvC y\_<6Yf ={=o!=kӃ R3F3^MˎZ. Uۢ#r-(lnn##I&qi\w33qa"1, )Yvg\v;&ԸVO}}i_G8‰MuxGg \ӹ68+᨝^}(Ə]!3ENMn{g0zr*qMäGY&e=rЇ ֆQa!I+qg(.-pÐ8MN8Ome128\]a3U7.[Г9ۇ+qu(Ɠ!=3Xܜ]+Sjg zFKph16zY&5/km҅Ad" .'79u` PGġܶCmZp͹ds7=2cՍ1*buGCɝGG'"=kz=kHڵV׳gG(m Fϸ630}Zdb.8s Fy3zisNԭ02߼31coov=JtBHܹOzv.FYwEc1=klշ: ݽ=ɧ`'χ%$7  ]/Z^(|O/af$cIggpg.FXB,awԜBpoJ5*mqyk 1Ҹ=c /n{d t{7Ǔy?ȋ|CoiWg8 YS^Ѧk4"=O4zXPRo#|O:NV 5Ub"< 'm9ѹCF2}?G.ŷ=[гN}Ch.L_ɜ _dPӳsk?Z^Q<#W c}}hy -z:t4N9"Ġgؠ/zvBlܪi'7z֥o04wu WWmI[_M{M,MIKz6휲nKk6칕t_c%;$B1Z )‹=4EխT_nt: (g]j8]g\ƗG(YߜËohO y}}YuMj~̐).D+J켼g'{ow\lTgH^]Ɩ.g&L =Sv)U&sMzW>xo!<14p~?ů?-w>mʮV,z-?|yW_췿oI?YM>{+-/A"فSuN{r왛HZUFljb[8 Qܦ[}pit.ՠ_V9z3.G9pЛ̬l_]?ߏ=95kN('i-/A"ٞc!JUЮ[.>+HTMcTzHh_0&@g쾾~&8L $mO>?uR<_+.㌦mcU}B1qZ )‹}Uh6vl^Ez֮6*UmZ :KA5V1fS763t_u=)mٔV:uիqf3>M&Z]B1qZ p<=b9 )ҳVMCCSϺv)0co$Ml9!sO^7Z Ө;+*M&3؈^;Zn\/PL'=c)Cx;#ǖG=;CuZמkԦv]Oohk|ʕ+ߜ_)˃jkoK+bԨOxܦcʭ+>l6pP*ǎ)//Z^(&Zˏџxt=={O?> gbZ^(&Zˏ1C{6i6x(LiM~X >& ET';<Ï2*զvye}: =ӉZG|aƭ[ѧho;'}C# '0` ~cBYOҲo_o=RNlbBLn2IcysVQ|i.ĜY~75Fπ‹:sYGeR؟9zAzvf[)~oA>So(.5l+^LY=r?izu}anۻ߳:T{wb׾ثj9Q-/Os>eS˜Hޠ=z7M89zF^3`gCc }4&몆߽4Yӳ.Yk[?Re*U:Yj Ϛ*v kC{b˿7'O>@ ńjq3ZP/5i.G`>AX(km_D3`gt=A CuB:fbރYh9mus̛åyA>U hy8-?>z9L/csQ.GS wzF;20wA7gg.kVf jg*Sg2^++.^Bjt~֡[TG{8m@;[rr&j\,Jl@ iyR=;h@nf 5{gO;|3bm. FNھ,` _1V _zJl] gH^,Mcߠoh5EϺt=RѳA-NiyNT['zb0{/yt8߇esL#b۔-}ԈKi=DGGOOO=3( 곁5iGQ;svEp>M ICG}us?)[ gS`gs;ۚVvEK,2UX^?DY|fuLF&l[`)U?5,J@ Ln2|91G=:3PSo9 [37OT b5䬌rNa3's<1* =: \D<\r-Jg\r~Yb)& ;T3 ONps012քG 5^k Գ7 '_Ji2Mdz m#d)N?NZTusO ?@"97G9{g<);Ȑ\lfm;:YӤ-/w-J3 s<ԇMq_pPkɉrrkkF{`Z{~~`&{H ]lykʼnr`َF> 77MH= O?{ҝj1nXv!cv:t+w>y</[8>јgP"vYs~vq*{Vʎs}K;s}9RXwcM&hg\{ƨșz1qtEI _ TrJd?r,viiE_q zLjzv!)𔪆N) {@8y\S]B` z/k㼋qLmrǬgQ5vN),vQ+:1V&===7]8393;'YpПt_ %U J{jIN颌Rs$2/jj ]fcE˘fq:azZ@]O^] JOF!V' z6|9VDq}+9(pQ+dc#k3~99R=˱2/ݍoOcO:XSN*Z^<$3qm^ P̵q𲿯硏nE\`I|ƥ _z^' ԳЄSn gg:~;yp|e?>=og\ns%Ń3Iq5%P᝞z!.GA]MƎy@zF1thVXzD榭@M^uWa6=?Vduϊjy-+:ׇMQ0CгSWBo׷}A~lzF7zƨK.g ;P^#Wq3Lʱ49b-ϣgthj³9,$!d\^hRB1~zeH1rnIyvgǔֳaƨN4IJdLHzڊ~|+t]^j(#SgT㱹Km3ab Oj D̯YB Bz]Xz&=@ @"Alg3> RǟՁ .@"1 z==ΰqYgD?= a'=syg݁*gc~t&d f<\$Xg#@g3Ā/ /zvCQYG%߮g!= gH^l Coz{Oxڇ{ӳyg R=xwo}炯YL>l?y>,.!)m`pPz>Bc-zKv#CKG4zXPRo?6Gī3d RC_Z^(&B˃ Ev{OxKoӫӳ>jzzv_Ƿ[+^v$ cq-/A"فh? wYRf;ڭ՛ދҔ~k)붽fϞ[{OQK@'u;v|~P@-/A"xo!<14p~?ů?-w>mʮV,z-?|yW_췿oI?YM>{+-/A"ٙKׯ44_o~xSūg6꫅Ksw%vѣ~?˗O@Mu99dfeO~~oIXPv@!>IhyP-zEBJ;PtͫD!:Lf ohh0;+}; )S(sr>xۓF<0#.GK8i[gj_PL=@gaWnޮ`Q__t||QDZjh6uc;CU]]דMykΩS^g6ѹ>ߔjʫ-/A"ū鵆Zcz1+3gx;^c6~fݻ==zk n&pO,4(GGGcc#zhis=ՆB1AZ )‹E\Kɬ7e֛33C~'+W|s_/-®S>}"nq)n,",٬A P(N;z\?ghyh-zM!CԚs%,!ހupp6x/!ĉ|C}}/hOgX_YoNxg?㯳GL@ Dky3_z%M=C8MmGnܶߏć !3[ +VZ70wVpʂЧ6_ g>eKˎoyǿz'ydEJ:U gHҳk7J۬~ :Ezm|Eqa[ɰ%v`;I{Cf {p٥*,,{v߾k}^V+ΉhyP-zKϲz=RԳֶ/~8::U.tժ5Uֆ WoN|p#*<>>>U gHFbzر`Vvv{{{GGAt6v~pG:ePmm-:duUbZ^(&N˃ E3(zj$2%tF羾>^kJ;Eu俇Ӗ ĽS''l⼮i``UbPL=@gD8,A2z>qı7{-ֆ¼/`䴡ȩ1o޹cիWUhy -zKr{%gZ/(/XrO`_8pȿ_ybTTԃ>8{lΛ>!B1AZ )«,4bS0d6eKm,5"cc-{~g>%|ZO,*ѓ'O//fd,[W%Z[ )r_g3ķqyި54(rS_t ';2jƌ>Iz=uغ*1-/gH 3^KJsrTm-M%%%UUU*IQWUx8uU3gܰaÊ+z'xuRuUbZ^(|A"YSo:?VPPP\\^|:=##?U޽{ \*J@ o<R/=,Gzhiiٷo_dddyy#GJʾgH> 73bpQW(tI7obD]լYoߎ^TUhyՖ=F\Zozl! 7 144T__<88>NK?z1F6UM6mΜ9مB-Nq111$QQQ%%%cг ?]7QDץ81? bK xK!Aϼ.Kb;~n») ,f#r3ZեWV֔Vd䧦ݝhz@R]aGDDXVεUIhyG8fmmm}zqt:FT*uGGgssKYYŕ+WFgSN>66;`ć^ϼk=)3l6ʆf*3+S>*u>zO rpt/gtq|bc =1zr*UFg?a@\{&ѳzS̘^k鄞_+=@@AؿtϿs0j9@-N =c3ef&t3S1Ve:pBgŜw/zv!VcLϽ3vs&L6'1$11c㾠q"wQEYYd_tWwSMuwuW5>Z>uUWr+/,؋ mLZ< HK&kgEEg9v82p@Fãl,AZ xxZٖ=QF6K+:rc@]A: O*xvH^瞯uv<2 GgA(UlӮÇ]?]I#Djdig?o5 5 OZx~ݧ/Ox1zⰼ~^. %Y_DY.Y_Rc$C[a YO[y\yVxf e)gjϸ0ٱQ!09oH8<ghD;ee3,靫jQ/ ֒\/u q40"֡?p^w  2W:ڮz|2zI`8M_815z~T%Rg7A&2P?v(8*ҒvV˓NigE:\vkɵ[]a%ʋ]ugtM<ۺ'DV鱌{϶G%m8Z<{l=/9CցiNz 8Ɔe#jlP<+|Ge?Qs2P3a:3۩1/D xnO [f<-9"^K]qiր,m.s]>BaPICB`PYc|).L^Ǘ0Y2ϊjZZBQr虄Ox&LYGg۲#fD/ZQiU.(AWJxv`0 AϤXE0JVnCv[ףƶXc= < :z&A& i`xNrȌfZpf{SOH5LLh2ymΑ-35J/W;K5<+ng34ѳN{Ϩ=N{d(h"5ܐ7E _g^Ft ȃ&sxvxAZM-Ix)w,I~Cc[8'3A\$t0gI3Q+o S xL߯hC dR . x-n7j݊%LjmpZ3H}g%9B,uSYNnޛ}k7o;zVaKk:s~Am?Ԥ^oк9D3A,YYeU]}(1)->g~0&aui:m]G=gCtyxuo ,RLx戱>NOxjg>t!_n Yshֶ67cҷN= uVlͪs +r ˲ 3 s?b[qέpcRX~dzȥ}6l/ \-WYlٽ^5/=?ro `A;itL#O耗s'}.gonEOt~ՖS- 醅iI37cv|놐M7 Ae3GUN[Q LWRz#Md鏿jJ 3g˜~ ȅRJӣvEw݊wf$;{3C/p6>|M?ʕ OO9x#Ky&WBs}?q/`ˮfm{Y 9.j_cf'O5,2lPKWLUy_zwNܬ%k]4|bMxҘY1zHrXOm}N>7'_zNY3\9 H!)}7 ExvzxAZ}wD&ׯ~ě߽elϖd_ 9L" g{X'?ӟz?1&t_D\Xugg{WVʪ}ι3Ljwf0 ^[}]TSAp % >T׸XW^Zt+T2s:R"g%3<ψ"UnXT[g<|^744Ŏ7wƆ{/_'$9nua[;w?pjke MZų@#w9ܸ{>k|S_ʄ# 3 k/6^1,Oo!9w:4p[{>R@y9FlIDS}ظa_>W.k}H ɹvv.ݞ++ )QѧS._Mg;qJvτS5y$8ucf pf+8gW"1naIjBue˔ȱ ^U8G!5:l kI/G[Hã6{2󇟏R2[}쌙\ 7Fl&~snS8&bԉ}ӑEs3劧tA4`K5^v*(I\&ѩ:ScOu_L!362qxhoIjSvz\٬H)ps -I܌{ aOk3VRIYgw?rYss} -mmuuwZ[)̪#^J-q轇u Re'x'0~Of ]uk >iяcBELS+>s=~@ZWQS _FF>Tk9$ų_>TjF&hUV.wOv+sW<_5|`7&Ɵ3|mxo]g3V%bK+W,gwCf>q)K^')k7~?I<=zޱu}yKnu~=3x^4=ϬL虠:椨iѳv`1 {nl?pm܎p~J&1o~CCzkz+adCIW9aRa); %gkl2pc걿;tx 0 6vvc\\\qIirrrUZon5#~dXm~|~g8̶lѪ\ަ~GBR~xW ɧl Չ񬓉q ꋛdz[--*]ZZBpΝ]}j3ʷ2eÚo{-]ILti~A/~uXdߙ#nŌ=|(!0(0aLaRwy߾=Qό8|Xֽѻ,eMMMɟ|ű \/ Z"AkH`n˿!AdvsiQ4ew/?f[{{Iۮ~#!x}(ց;K>7ϣzOOycO68PR3/jfx;eeB_)jWzgygDYYB %}lhhyj銧 1CZ|>kNf^5vZKK\z;USo>/7^=O}Ҭp~hǝ:2 |yC _X<Ѯx6m7o\ʞ#\~5FTg3;'6V8yW}zx֒ }{$}gl_{38stܽ)>MDU`aZaDx3cV]R6{w_zC.ws7:&̳yA(YO3r2*7)=#s5M-kSgvi/l|İ叆}Vܽ{>د_?vҧS/>iKl6igq.C¿Xwf}³>%Ǟ21o&v*.3 k|y&rֺ7z~/ֽ.8#@QIg363<^s#g&5XonW43aS/dw H635SØ DgrxV1xF4qGd_+r|߃c_W80ꗢTէO__|{z;UVl˾_ 璂i;oMq+7ot[y.G C b *"k&FVl[5ڕeЬ뻟 ~d)xI͞{=rL(x ~0MTggBSZUi򭧐zNUoܼկO5o7~8eIkZZ{a`hۨGվѧfKf=;nF},J8bTwJ}^<~aιٳgO\58:1T%ՈT@J鎞G@]H:=TSQ۱ 5SOqۜ ށx8cD9ɩo߾3f r9iTYjnn xcnYRgSӐ5W]hko`@+ ^'x>M[x&/D*N=8_:zFUl^ٺUeD<+`g4J'P.[06*{Lˡ&C4sʕׯs/:iիVSU޽}rS'*>vY\/ψ懺:婲 f_{{%Q xV_OKvr0+..-,,yڵYYꍞQ]V!YTݐR2z&i|ɜ-]z+Wls$gxFϔ3~xb2sJ <IGzm!HuLAU۷osaa!wC/ Ev܆ *))!Gjs܍dgB >rn|ISvl=c<Y,IV$x\E%L<1qt7zfEcY0E.Ar7#MqK^@Ҩ"f|v0;B@Sϊ?W^mzŷjk&( w0s[ҨuuTRE̸4]g* H<2gs٤NL欒;,D/j9 AZPU $h3sɎ7Js\53i{h$cG]sgBHoDK`ybƁC'dd Z}"۝; * "rFȿF|&<;6am貊uQgiH"<}b +@d7#x˦͂A4MZ:D]kgՑ3g 0+gkH1LN2^x¬@yff%x" rD֭Ghdz-1/c [l^?u\7m^iIgz7.n[PzUe/!.{Ĉ`>.&FxƱٟɓ'ijʪj3zoݲEpyffgH=cgGhndz].z4z;bX7 FW7Kn\ܤ [yM\1 <7*ikIL:yo;q]F g4C ӧIbpp0s%K̙3'**O\`I<~8 dt")P.ųx`W5kH-66تU/^<.]tܹƎ=ڢE͛G#""hl R(;4L/ҜR:! :7dR]匊r&3𬬲^d#wyɸDMZ49%nޞDoAxϚD[ <,-ZիWsxC'*ׯ[n…w$]$۷ϵr::$9bǟOc4<CV'Z͍uDS v:dk#o؜D٘O 'Z=!5!M^t+YyyӧϟO#1ɓ',X@$.2y%6# ()).n0#dy޽$ѵr::kn^?Q^r#UUUqFz:乯x)=O1|WAH@FZhV}_ԜRD>?lHxJȓpW\\P.}&a\"Ohla0c'{)++S APWCZКW#269}訯~O;鍁Kn2LM9~ׯO?=x~?Θ;644GbF~̖ G#}|>.;f[})l3,9`|Oz^^^]|Ed&k'4wŘ#?p/_?#PFh }X#ԛ;ygz{&u7oXYYccRC._ߏB{-(ZEu79644Ŏ7wƆ{/_'$9nuac\\\qIirrrUZkNfKvڵgcgmD_N%k;< ў={zͪǏFml*|n {COn)Zqǎ#GY^x߯?9+#0"?now5LR `X]klil:PZ[[MJȜxMfFFcSKbԙ]ZwzNj-1lacw׏3YNHh=vx{h9jF^ U$.I( 'gMԆ ohh6\8Go,|nK;zׇgϞ^zw{)@)LOizʑ׼S3=Hu<ˀ }nݺE <ޘ6EV,]m AYCCC{|㹹e{K8޺⊼n"-!O³HS#n %}23o8p'$ψo߾tRg$e?vL@B߾}g̘Ar3gݾhɓW?^AR:y<ӃTdz+VމiN7QbZ>n6f4[.ZJ\s n  撍-SrBz)\לpz-E_xsA!&<Ϟv㓑T.(H~Gl/-Iًgfx.TZZI;w65519﨨y~3kr.577[w};wsO1Ek.Ss6>^W;{uWXS`p *Ts=v]xi!H/`ܸI{ah̔_4e̵f0:! ؕrїD~+ H4Y4g?^-xf0IQE9B0TrBB[|ݑ׼3=Hu<+׷ʒt>'̸\f’b:]"0j]:=gůktڲT*B.IÌ] 3j6<3qY$,2}ȁyt13)iFX7-w_Fn%; oeW*" b:9 V<8gVy,L:IÆO5Sɐ0S МI˥tɚ rݺu~OƳL w^@dI9:nuA!m?bijnųgW-}+iIn3px9/"D>i"&=̤,Ҏ4fVqshghS;x1"mb=Qi1phM"?јdgDx,cLjL7Ƽ!9J1q1{D93h54G$ggAݻw/SYnS::Y-'G&+nd8NAO%r8nn蠺T=ƻtّ5g'B2xLt~<_LkA1,ۓ(=c}ՖÄ=&j 翘3kYҍ+?Og)Ċ^FQy,Tƕo,4%m< PYCCCJ0{\ jNp5#+TocL!2G+W*zqsCݦ*6u}W^7# :3G$DǧLccI1c~r-P#)i9Q'| wF JdKq]Pgz8)y4(Dck(3SynYy̨cڿI1XD4.?sXN?3|{$3`wYSg.PYYterFyMb9IbL2&2Fr c'AK~f ֺ\1NMKP:;xҮmJlNdr{>,:T^Xřg3NԈr-_4u1t/txVʓtf]6Æxy +>'ܚb\iFe<+k3 VrvNI6 $ ͟T "ḉbBod.ti۔4`OfZro Ul{wB5'{)³3HsJAsl0uИg---U*2yn~0Jc0-iҺ1Ð=̦O鵌 =Fs"k*FWD{,1d[bRiH$s1NMT֦R,;ivusل{>p=>gH.KwWQ_i S̱q]ϊgi i(gM81,,,%%c3c`5D>iUwнTힸ9AަtxҜR:! YII *ۻw/fՊD״nRf.qsMTcxvxiN)֐𬬬>744flYkkk-D;!2vIqs\e 3i i(*++9:gv4綹Hv Gg:i i(Jt4#$VkA2Z$^쒞綹H3ϕi i(Ϥ$V__+mC+Q &uҺAAHЛJ -*K:Ϛ!+/(R_u]QbQQI|D)tQ|D*OnlkE|-!=%E F^^ށ!) 2=6֔nF7edm< Ir6ޮD/ToiE Go .VGԗN530 w<߻w֭[Uy޹s1<ӡMb|mIN+DZy7;p80 ÞΌgOKtSHyauΌg0 0 :4 aaXW0 0 3aa]Y޽K0 0 L<#Fجk׮4`a`)qlCuϏ'4 0 ð,3?SN 7oGh3aa7Xg 0yM6߿?***&&&22+óT 0 ð3fIx x0 0~ aa)g;E`ax x0 0]g'g0 0 < g93aa < 0 0 ;j 0 ð$q0 0 e 0 ð 'zao;|hV.vDIw am-<#G)'u2ԼUwT_ZUﲋzvj}7/ę5{_1;Ƴ47y>-  e*Yp$GN?KiFVI̊6`9?UIށ1G`:Nf2JMfN p6mnҍtbk^ZDe>Ɯ7ٙ\SM2 {XjjGm9rM^ 7ܮ0NYxVl: P?qRP9f%㲰%6{Me.3P|~7F'˷Ҕ«$d%2WfZm#ݔ٦Mg6zd^#wӒ$"'h1mM$8Bqѻ" ÝY}xVl9X6M4>dY ]20#iПv=vEox\:xtmt6R<")f@˥DdA_+К[tUݫLW6vgYbrg~\Klne- =ECZΚ. g wvE3~7I@(4^j~UL:O6j}0 0 ;oɿwݼYxͬl#~0M/󉈋ǒ@g24Ѷ"jJ&4EgKmۇ{4`{u%xƌ{# 0 B|ɜ-]z+WMX0b"?cWx c(W9}ti&1M?h.T&$ o!5f\&wQ.E$ŖQAgaaĈ[ɓIIIDhn~Vb aaɋ1k 0 ðZvf3aaͳ3aaM `aղ37 0 0 j $hŏY R0%7}L&13Xp<6i4Fߋ̓ށbE3Y J1(vij2*̣0 0 ;c-HZY5`afg,jx0 0 0 aaXWv8B0 0 ex0 0³knJXI}ֆ 4Tz!R3j3W,-= @s@Wg< ty+3]CTy?lذaÆ 6lkIo`0T6y5⮳uU\v+tJRO{jc ?jc:c*Kϖgmd3O^8y@ ?y3ƚ+.^VMWutNҩ9LgoSPxSVMyviCϔe{w/[]>y7G{kG =no=}X>j%^^]#,O"c>]mf{f%wipr& }:^EyOqkڗ;y 5뎱o: Y̢Y9-i,8FΧ+"|#t:'Lqil١R4IOnѮjd!B نaVꚧsOffonrN!^}A>5]CAԳU\'AFg~JxOmVɘ C #62aͭ OJ!ffa|ߢk[<4-ux1tO-Ҕ&zYBn3 6~)#t؅C.T m.f%g*gq mlD;]{){>,34φX=^~ILR3К&.d&ɳPM%iyzQh|)/,n{/&D6u켲<==|cٽu/xHrXAt 3@|Q_@F#,W?K ~/)αd?늜~R4$%D S*N*,2K獘bd#T: ^ڙ'tG>Ty 8j DrƦ9'$1ha'm 1ph_A#G>y撏{;woܶkݛBZ}%{myْꟳ}/J~-?ۼEܳlH:i;^yg~/;_ߚ<:'zR@_v|kϞjGT endstream endobj 43 0 obj 70972 endobj 45 0 obj <> stream xYM6W .?"`,Co!=h.}3dR"%mfmJzUg}Sg SIґ￟\s9;x'YJU_]uU[]5U]]UU"pU\51Vy5`KRYL<=ź?NbSV7}8 ]ȓƯ(@峿 cE^0ʋF?dɿs r;`<9@^8ȍn{u9w3|tZC!X 4s =Q4-hb?`7r.g@y%hWR9ш`K Vs_[X _O&(z%ח.a@59&0=pge↟Ȝg_,GdDnضoamB½"|Iv2 [$P ie{f-9nypYA;ǐ$tqz#%^[5h Ζ?Af8J{5.E j+5!+%:X‘ Ox`MO"ܮρ\+Òb;^AyDֆ2?Xje܁ k3C_  2S|aY4 E,fvELh/?`!m6;`*RsD}ړ'*ePaheqG]~4խhrMg%\$pXW/W8V^JEzNjqI 2Z |xVR ր> ڜG,T\V[^YAC 5N s:<ysr:zmo-Xr}IayJq%n0awܜ=Paop#d|Dꙑ懱h>[P ZLK^ꈭKq5M}#r<~촄W dш}~~/I=%S mNXGA4 +JAҵD+rF.ƉEI /x$P3FWADmn'.]VydQ[(dN࿫D 6W|٤"Wz3o\6~d-(!~,2c<:@idwbhAj>2sO fe^Ta9Ͱֵ7ߎ2Hb> stream xZKo6W@\q`PM t/eJ.Fly!j0O#."߿}~4uӨ&7~ip^`\,o"ՉT+RH"DDH "UfElVĦpt55T/RH"ՈT-RI*:JTDl$b#HF"6MؔMؔMؔMؔMؔMV#/hxWh߇!v҆f_<̯/wlވLI<4zl/s?s.W|Lן% HXp[Bss?Cb-xCgp+g)!-Xïb-4D%SC֛nZcPt\zlފj<#y;-t]H*ݛ#%,#lwpWh ʌ9FT ?7g޹֜ꗎ`Vla6p}{$sqQ ne޳<߶.eo/EE/` XWkky X ^QN{\PQ#IdF VC06 sBYĉN\TLSȐya|5@#jb1=|3C)60AxA7AhՒ54=OJLY]pa$ݰ(.J[0bȥ)Z.B\Fk IJp0R0V˩(>1 (GZM'g)+Da\CdCYRO wf@H䣫b0kNSV~,@u&obaXM pg3.Nb87X^3.S2*wy*ų]Dψ%4bgDJw7}UbE+lZ qj_7떐ZQB1qMu!ͧ W1%j70ѭL1{F59.%uc͞a0]i,;YE[wI!b={ 3bZh39_5N+W泝4Ms vmͻaҴZ5VL{)ir]VFKWE(ĀgZ {ߪO{4֗XȍlUAI >oe5HlX-6:g]V aF5hwSYҮK!aq˅y]t>j T2qDC #_m2+Fq[eHUV >^7?7Ӗ!m>d*Pq;erY"bic,OB#53 j LUqOɔBF|(m'37i=XgfJθA%'#JuDw#[GT;{vDuCQ j/Qzwk>y)gH;Ÿ*~T_Y?M~Le endstream endobj 49 0 obj 1732 endobj 51 0 obj <> stream xWMH WחdCtf.IUvvUXv}JOOOrךg5X j5pXк2ٖcۏcSa>7F^6@L;'L4loʑPky]q4?LDӱG@#yPsڡGwi'L:;2x7F1޹ӻ|.?2(VQpfަ`^cu#_b>!dאm#s>zF#b 2&8 UC 9r3-K<]~2 b$7R1sӳUBIňqA$0da%EHM*Nk% @P{B <9q`']xq1n,Xk,e W| W@ч@jcj$qI.UYr!΁Pa_Y1o!u]7Ғ+p*@[UNgJg$uZc]WOۆ",O Ac΅41R`愔>r~&Xմ}qlOF%«J"S-6ʂD}4qdx(S΋~f*ƷPHKF u3XiFQYA׻ k6@Xyx1K#00J ^A!r8T%ba}yuj}HJ'PHi]QH}X]{y^[^nǽg$ (l;&n9G~5u漹 Zqս@ܙ|kzQc]rT{Td`v.!> stream xYK6ϯ:p'zY0 d採.tjB!-ɦ9mٖ)m;SgYwv{QJ3D[ӻϓ:G#u~?;G}NLeMWvMZ_Y 5 g׽ڽ9 |v:O҅"=(\_(DEQ=O dcKyӨ]1U |8 X2F9G߽,%2hl54dVJCAg7M]q-ҌH{k 4 .QJ^ הj1R.35JeX{}L΁^f<*vA؆R-7L;c{PX  ?;,:44t}*ׁQQRX3X # ݵ@B7a>p`} pޏyΏdFDH=Ei;1zA:h8dke| -#v=:x>LMX!r"p1YMfFȠFģeR_ŷ6&z2ٻNB HP$U.ҏ DkTLcBmF&~ܵԽe$R<*ˤn"BcxF_x+##BwS8+ xxc8Cg7ȞSMui9].8XTbP9CQUlk~M$( N0 O2qA~jSb5ѐ5s4[!n/z*=͏ReS*KZ?i;C|}ظ}Bl)nbNv7;.E^;)WU0oGqNՓ(fSFY4v.]V RpU.#}[TWbX킱psJc8|J804 :v f.:CYL 0).?( <^Ԃ6 n ȫ(lBp_) $Evلc6x qz}[ѱ26BU|{0e5Ib&yby.)C \ tk0JKLl3®2tqT#2/{4d+2MC)(\]5em-U5%lnbme0Y6:7ӴXr2M_ǵf8D*٩D+N%6fcuqFgKx.V?;rܰ2īu2cHFdmW(xHy~I [C۬({Gox`24b-G E;k$\?D s/vת4O i$ڭ;rRR@dnr8ڀ0Gj*A {c=Bo% ]ZnrҘUmSӐ`@}/oܔ8SRL4q1%Qq2å`@Gd[CGknpZ겒bKVrF?')yt}]1ӑ`:o;*Zc6h!i=6?O"jEZ]RjUtcxmޜ5cJ&LO_*ko8w|9ዧ#Ly endstream endobj 55 0 obj 1774 endobj 56 0 obj <> stream JFIFC     C   ~" cỎC.cJ#fdkɭ[> kue8>oqCqmՂ1dG ]y\WM]ל|epP6kz΀8ݯ;վU\z7`&Y.A)<#׃[~үCaˣv$[3zO^^^^^^^^u\㽕DH+H+H+H>k}nϢ3nq#H 'Y}q_/W%z]i$ig%zViflи|{yYMiiiiiiiqq5]'ݣ 4ZAZAZA"6##qߎFLOɚTb1gdNpw;܉v[QBGݛdb1b1b1#KM[?""QZHӷi6i%!N!ZAZAZAdO9]DSZAZAZAZAZAZA^<=D~QLVs}ާfԈ9?Mdc#'2~3Ld9EIEIEIEIEIEIEIG.!01@ #P$%235B$Ce#a[7mp4zn1{5XX{lYmerv8wq06l, ß.v>u697MF{aj|*S4j_nZcRZLWU|uuXQyNS-m7SW9l{e"J~t]~n}/GItu·'mr.H /y=tS}K-:)u3ޑo-Ow~~xXlVqȰ{n~M> \Y(Pm]쩿gN:WSaW6ɭk:tӥk%V[ }:tӧN:tӧN:tibӧN:tцa̺ej&l0GY+aaaaaϪJ0 0 0 0 1%-m߅26;uXo,aaaacc^M^^ 0 0 0 0 1gϫO;+=Y.{haaaaa${=1|ro(w6k0 0 0 0 0/;|o ~Uaaaac"cfvk~-76Ss[5%1cono8#1|F;3&eLn[[2cɇU c1ddNe72!c6hro)ߓ ^o;#25<:bF1c-1c9< c1c3=2.q!c1e$d2d-w1n1cnc1-!1"02AQ a@`q? eLN)Jd9t*"ޜ|G'}QDǧV?esFVyO40>q^Wͻ 6+իe힞 bDm\Oɷ5d"~eS-qVD٧pjݎ^1ri۔EQEQE":((N\>N،uu(()Q׷5r"()D^O&^ir?,((`F8k} 8G1EQE6EՑ+ F1PPxLraMQQEQER:(QEQEQEQJ(QEQNϾ (QE((QE((QEQEQEQEQEQEC !1"2@AQa#q0BR 3CPb$S4cr?HFYWR f1>r‡%F1'ͥ[> ;-³fY4,x88?J# H |j-BG GEһ`0QS(eqJPY$ M!Lb[":8y hv2 +yZ$XAqR9Ȏ [\Epbbp߇EG1HFn:N+KO3X~gU^PO'.bsR.[+gbk[ gVgGSU 'Gĭ%Sp2q];hڼzɮ,VR%Z(8m:Y ׳D[^AՄѝkN{HV!wtRY'ՇcQ[(#v{'<}ZӡKEAv8!k~x*zN߆ZEv;u6cqϠY pҳiO[E䧬k~Y۽4n20E֟FOS[(Ydx/|lip,yV y֣aC+$?-Oq.>kOp+Wvp>=>lgLݘ%ɲfCmw MGQs='oۋiָ+>dz<59>?˺J˟4nlu^|( q(:0u>*H4$f![̫e>'8d.ws/̲NlwV :e\.Z3ji#UP J$C ~?m U1ʵ7tby_j 8kWW\eMl (dT꟏Ɠ;`ÁxgƖ:}fjr{7xϭMq6pxFdI>sw}&>$qšqPMق0qә,7?wt}JA l!۫,w"pƊDLV-Q<cPf+>DPS dS=̡1.)ΤbJLT<Ul`3ֺ:K4M=V#Iva{s& :zpƸk^tV1=JqLB@FڱMQ. @jr.-}6;jWV%u8={]:A[m[Fs֡Oɟ<6r+2#םiAY4䞱=z91DBBH%aY1Ǝsw]rgs̟*2'Iq"cRqY}+.C K2mlo|B9]v0}QR_"krW].#TYP)"e[hk+Nlj2^T,mD$nc]CaT9sӽ$\$Ї!t*B._PoNDPOcΣDVH(eVU <.ᡀ*|*@-s@\&E(cVEf^DfeV#W4ʬG#[]VλX+v{gzm]co]+!1Aq@Qa0 P?!}T,ҔpY/8d= ^MU %.&ejJkh#il% kv4T\ Hʎ6#1 dr9Ǻe0 ]%B]n𩭆d* =EL 1{EaHYeƬyX7*X:Yv Z.]e!;ʡ C5 ʧ,# -b`.KF4E|'W@M^ #PѼ+VnIxCd-M^*Ktm] 5Y]Ϊj/G>Z)W!/ b7 6ǒ?냿."Q"0#&0˟n[5} z!JG]O?$&dz<Wӡє[.O#OK@ ؙae4t޺E@ y觌QoGL9v?e}P\߱Ҁ%cB.рr2v1_g`0uΞN ♿  N8pR& Za*I@EZcX*@|t;6ΐV=Q֛L>: "7C}AF8kZSԕߔk6Z׏M׵$jU meP3n]S.Eu4+&$`ԈMuߢZh1EBSp78KƵQWy؛Ln]/%lSW#dgSX@QUC K:4'*apnI24~@TA8&_woc(?5D#lFH*!.bgw;'?v|LZ'.oBҌO(UxD0bSr)r)r)r)r)5tKDԙ9NS9NS9NSc9E)r)a9wUhZPo Zk1ncIcX:?ҁ)w*NElT\M&π]nڶتZީ|KtzF7wv/Z/o}81 =#%۷6 &AmTkռw24(2MDX X88q88>MŏXSXhucQ &彣 _G΢z(PT -L!= "cBϾ9_H`1ĭT~&B y2P%cs# J؇ypq4aZFB5¤zXMI XSGn[S 9? ߉%q%H^%On/ {'>g\JבAp!Ak]c!br?4cƎy?)!10AQaq @`?h (#֖7 `(᯵J0UΔ Cs .( _.U~ kFY|)h0 /,t^dF3~ڍ6Rl F|3Nu f =A.e!^(iQEQEPEQE%l4d p@&Пzs`nռ g&OߘUr MoCHB&eL't!./K~p@U2f jV:A)L@jK?Al@_ŋ,Xbŋ,Xbŋ,Xg+!q1QAa0@ P? /0VF\pi3ߍP0ءK,@(^qI-jRHPɂzoBk\HՄJ&p M) ꣅuE׫.~yLpov>%91TT^J"<]̌_]ȄɈ?2p]Cg2}wZ-@ES;+y_++++++++++++++++++++Cd)"T_윳s3^eVXE/Z9viz0KKJ\yv3pKKKKKKKKKKKKKKKKKKKAl),IK&A%%%%%%%%%?@=P6X9,3^Մfcx~鬜IW fAsh@hrn;yo7ͦim6Dh|وt'o!,^<ڕe (WUsUԘE!% j9gmim6Mim6Mi,3UYzS4fsC0rd9*N5 Xz m6Minm- \$x{/=s=+=# '$D1o"HUSdʊ" j{3^`E T3gC2@^DKhx65oθK UX˅ Mi-+|B9G冷=YkOa|F1m6Nv@$cC1 [>m6Mim6Mi7(#\߅ͦim6My{2=63RY>E<+`2QEyo7=@PER* {=o7yo7APYy%Ko7yi~K/_i~K/_i~KzDL d!U%K/_i~K/~y:Jy%K/_i~)4G.bS5_i?=#+W)#IQWG<~ Wnx)“C9J(axM[i15zVon!7})ձ-y oF `VšezjM@pZ)]$BquudmEim6Mim6MXihF/; ,`LZRϒRRs0_&.T[BϹlZ,~XzCؓ`OzRʰQA[^fim6Mim6#em}%ȶ)I /e gor%~se˜WZ^*J$ʬC,YU'8ǎ&yo7yo7@4 0&:q)6 Pq=ePcu]F 5xbӌq9yo7yo7\14*M*?_/@s99)H@НUs!9YD\اJMim6Mim,r zlR B=u}J<Ǔ7Ʈpl|VFNk#iO.^Ijmd6Mim6MiOtOtߞ{{{{{{{{{{{{{{{{{{{{{ endstream endobj 58 0 obj <> stream xZK6ϯv˂f`>0Ò[K~J-%˓l4CGWOUY]叧/QWC?_~pI]__y pq\-G8jQ#8Q%(hGEެțy"oV͊Y7#fDތțy3"oF͈7#fD@ D@ D@ D`P_pىuWsy8]盽{w?(?~~L8ߓa|0$q.f0݌ۯҲ`Eox`"3QT0D6~(F OE{"aM%E4cHBx) emQp߬3+~wf< ۚ~ Svzn#xFXyj &qd!wyHՈ(hC!ȿդkB^q{Rbh/`B"~Ȳij`fiMm$"ϩ aLz0*8oX MZ1juDz(/jxgm[I"7! /tt'b/P[ }(zKouڷv11A (FV5]qBtpo Liw03$ m-ʱ2$:Z,Ih~/ Wk_;ONvERw碸lw gZ&QQ}v`s@cr*B](*^؝eq1d}OjA1"GIOA:8q$Owt'k1@-r悉 ]Ҭ?X8&ojHl x`Lo6P=:~ 0(4ҷ8ztE"hY8Yw%k5M;WdP9>ʊyn4I:Q: Dђ8#yw&#c!C33Pux^$+ yJ$C$€d8F/`^77 RN(8qeL2D3 8#dlVCMIkGw*̈1 DŽUc^57rvn}*TX9c7'2ZrJM]FTOfKݪ1fϨ-'n[;tNhwOPή4. <lum-$\R˸Ʊyu*Rq%8$^pQHm_4;S~؂ ,T 1/YRAFH:2ϫ?wjjj!d&ŜhMv-9a˜6WqMYQ xD5w7Ӫ+VNj5X{ֱ(_r=7M(:l^ 7K KYL4TzM:|xt,w endstream endobj 59 0 obj 2204 endobj 61 0 obj <> stream xUM0 W0Y[BM zXzj¶t/}giܥɇ,KO:e9X#%xg~E^5ǥbԊqd>yHV<exfb(XY8Jӕ򡙖tuҦrIهIOB=,Va{`qDA4hZ[IJ=Kn*D-Qޢa9:JD0WJࢁ& g1L~g!lx> stream xyŕݹyw߻ycfl 60 Vk.B+@b1ЮnI[ݵkwȬ̪deeFFF8###Gݾ}>zV]tݿvnw5z\{ϯ]r}߿zk6>c>CM^KlmC0]Ck|15!Vmwպ{V>zϯ#z;_}}!%=~B"*\X~ ݙU>|6» "g.]„kz00I܁Ѻ|~7-_mO~yq׍oqͷp0[ɭ@o6nyQn \b_3FHf:ƎpwG畆JrQ&mMSB<5 Mvbt2 M҂ "P%=B.9)*;+$4'Ԩ55fKå%vd=•3ϩ--(HmhXЂ0-#[-s,YYK KbQv.ASxY; Xp)QEiYs (7wT.5ۛDH{S1֘lkL5A  )/,Ui,I65QM&?U)^I`bǻl͓۷o߱cB3-AXd\|OQ4 abΒT(Pd "c!f` B i9M)qSmH<)֥c*g6P  @,ƁAؠ> R"ڲ RA5-sϪ|b(y%%>!=3 %`Ȕ2&!c[!#oe*&N))mM]LeFaNɜFAHM(XH5IfG#Ԩ%5fMҚ;)Ms (it(9"%sX15+[Ys/:/jɐ絯"0y`+E:\h Zj-5SiPP]1PjTzjj`mTTTTTT& ˤnyjj^ȴbݶqF,b q{@l0)s.t@؞ѓ%b\ Wh$ \!N *)} b@pwR1挤Fa|dF32HA1A< 2H 2ԥ ҄Ac kAZd)R(/Y Ѹc 8!]'J ` T¿T}{X Ld -фde*l=͒cz1sɎX3!씦Flu͌9` B%&Ƭ4HJ )}F-ipb>AIsRꚒUf -, 9E@gABzΚ"gLEiY@1ZV. gY9T Jrq*YRnJ),q(ż8 k =,&}Gx\謫vU{}u`}u:Pk7T'S կAIvJWbUa"UW孭rVjUaʟ{43#ݸqϞ=hU `O=GYEG9e=#D!B"HIA%" rbyMiC>GM!"]acRr CAj,ffAi5 0.q 24!y!N> T*xV_$Y1`9E RFSJzHˏKt0/#) &Kj8Nj*cvh:%dPf]9XHAhe4Ɣc ؎:KAB!('Ȗ\lĕGX*Z6br@q6qda`(G"G",XJ9%R]F7dc)w\4Gz_@Y&@@ wWvTt8:qS}W} P} X} \} Z} ^} q+mϝ;7"|N7{~z~"owg;ꀵl䡛L1HxQh~ f6vWwDf`gЇ hV P\ LDy \!CR~$%& -AZ2Ts" B0J* aPbXSÆ:~Ф=@IAgAM A9M:Ub(м;+q#]r L!Sjh#nQSk3_V!q?]$)4V 7qU"HRAa$h41lLtB`b>)07uꙑeBhB$@mhĚyc_cs1\<>x r2╜1r. EL8ͷΙ(a[pY 5ZG ;DYrZv9ƃ8q|ᲤH fiQCH+}1xtBU֧[LOͯ^ˡ@C}8up~C=7_{w c{v=}p~D&M0oM> /9r2O}+?gtALD k,g42*TD`-`A, )д>,e RSJID5ho(
      ޯic=H:F{u>Cb~H3]ټ$ *\M#zD>٫=O4Jٰfg}Ucb gD?I* Cİq C0>a&GI!\9p&%N3C0DB%1$Їz$s vfApרaJũ 0R9l[4H+*xyLC)P&X)"bݥ\_y[d̸ɴ)Y³XG*Q$0t>N"!_t8b=:gif<b': Zsӏmͪh٣ݷGoa.Ӿ]}x5;y}O4ګ<`,ܞ-OԼsgߟ=3lbg]~.ۻ5vVնIet 'E/za JӮ!}zW<[^~rێV~ @ tqgΥ.HihQ4Å\alt,1/b@Z& AYq>4:0$dׄ{!\!J(&+C]p:ҭhcZ,BA'= XTbT kXa7 KBBAN8AY.٧uBp<&I@,$A4I NMvKqFDpyD,@a1Ĩ)A8i62 c: BԸ |"Ƚػ;-))+hC .f S}7"w7QFRF7܉3*ChxI!8h}Uz3:/ް:oF %` i#i18PYUHzh b>mѽ/xwp gc ZC30 Yn8nGN'OB23{xۏnQm?joY~} ;?~%w@vw}^xP(p8^TՊ`n]poж6[(~U*Gi_oxSCwlM}CpT=+?{*б⦶{1ZP=?OH-a9IMm}9 oO;q__zeo_:TuW~g;c$m#v[}zOzIZ3wV~iٲݲ~yw~yٲ-\mq+?eqIbbf% 2^0d2ȄwAV8 @4b%cF`uH5ı$Ea7bc>293韰bV 114eP:Йedb$vLibdHMzBOC!6l1P!X6nX}HqV/0 uuȏu)SRNN [N ,u@%V`9u#qwsFPE0u%OϠ+ΠbPq6G5C=Ɠ^s0ju"%VySPI=-ڭ u)pΈ]MP79&W8 i:? q3)iP *&$bsDbl J&= !+܌ΔlQ: [Lf K,a-SkDf`+DK x4eM(5B8%3LB"IVߤ7a Iʄ{:OJN"AJM_ 8QMBT䯁Se;eկZWٶΎwtwknZ\f#.}tuOmX,o>tw x%Z|trkww;V)_MMMA!AOn(]4pͷ^~[_\ W_D1(5)09 44b$e$ZD*{dž썑)A˖ŐhR =*nscs9{ Z`2TC9 3Te('FvRD eȃ!М!L!8b0HZ _CZŮ  \ D1KlԌ>mCRz6*ʠ r7ꅖq{øtF&urOY'020Rk|,_'vzk_O_+ qfg$hl!ZH>ijW5Tj&]"ypTQss$Lҭ Jݵ3OM}]{C[ծ=02TwOXĮqwØ @,*If"z cvpBƜM"*:k=g$N8•8hB[4bkΌZV]nGU(k)BCа("ÀCxĄȯЈ1 PyU^_Py~.(yASl_l+_YG}es'?n x m'Vˎ#xJ_/lc134<>woY3~xCVA~S;eI׽eF̿P-rK0+L \FoCbS _CC7s7MzekJ0[ n !m|E)OygdY)%L $2h0HF3Hh7>1֧ vJ oe,rԏaKA`:ѧ9ޭUO Cah:=l:5dHPѿ {7tuk=;8]^?޷{W3n{Z'xfhwN v3OTG{ Bgש } 94'xjĎ>&FfF6vfšVvNMz|bNS㘫a8 wV3 VhYƀ53e}FmyŰNhk5̧ ]Mv@w_[; ꅦQsQ`i5Ό9丣]쒺e.[ꖣ2DiP~N%uvI=bG#u(C!8n߉$"29$2tQwyFG1cHd I,EJfP$1$̂3Rm(`Cdj61yo(QUY=QX0~Jac2 1CREbFR[É5ıl}w[^|Lc|F+E/o}鱱lۨ}eym/oI^(/nq>O솙WkO{WBAcPa_#}G?~۫90 T74޾z}5m}x8yⶸK j/mqTOr` e! #(8K3 @Laș_R ]1DQq*VRBFЬ>uZ@t" 50䝡`\~T18pgD1v׏tq/U9։}'E U>l~Ԫ<ң?=@bݺԠR|0t](@nuSo;k ' ;d; #O$7K?nR~OwW ^/t u0 ' Թ*D͠ĀV`EB!2=q pɭ0WwjNviOuNt;'{T]^UuԠvPW}z@ 5!IhmZbW'HbG)utH W%wTW.Sl8z WXoj7vɝ} W'qI2ǀ9h|^$jĊ!4!L8>qWzFaFQ8Gl DSAИ> 7a"FB@A)0Q_GSH"[" [ e&-EְM a ' yANP $fأ?'ګ dAP)E]Dn~ 2V0hhO쮠O0_K!8 b( 2f@'mnm )I+ n7Gǭ15&%dR-`M%\!5r~h/Ni`Aҽ'21T S % 1hA = lWAv n͠q{zG{T6UbgHzpW eˑ.NEU3ZAR QP7H&u >юݟ჆?i'-6?}'-J"jpc]o}=7W;QrM}b0PF:5r~Ez]*u\AdP]瀱 $?ؤ8,? ;ܢ8"ucԏ(:ء]}Csb|U[-H` [A' 'ka# r``fqRNӰXխ=֮:u.6ű6YUXhXXK<;=nUMpz8l>3jm[ǬmV̸vCDoH*=}*o!AuCdI!lS{A_ %l4JR(jƒ3J@чFujPP #Ph<03BীCcLЁc:I=kU!d >=BOqiݣ#kR#xF ֈC3(A(&'H!!xvz/%r~-M{[lv6P`g}U+ ju5Z?m\ 6Pk󌨩o߱;Ԙro@n?h,K; uӭ[kn+ظ*ޓEt|dȠɷ:$8DŜuhQmnp[Ծ)|L3 g胃\hP""k\Lt\l^lvrc> PP*єJ -$YqЇ~,Y.ؑUA>MGE1<`2hȘF11&q4l6ӀjF0NvNeUW <#yo f{=pw|p^;ԹHG8]{ͪ޷N|DߛoUW3MȏtjF-.~Pi]ׅJaJ1hf:}?v~^;bC uhôUSթ=ޡ>$;~HpHfZ;P(0's!˩ASi'VUk{dVi\'k=ACƓ=:NhOj:ޮRȪǻ'V`AC0Dnmg!ô]l{d_?H 3~%b[Gꕻ>JO7 B!4OA x@~ RxՁm@T uQcxot6Aqr@wr@sA0҂mq=jБnUu?Cb[ߚksbͣ]zU8Uqެ/UoW}jNW;nSC Ac=ĺu2mqG ]IB>}3^h75315T_U~3=]A 5]!j-4GpUm;;:zΈ]cQk`p[ $:կ?ѭTVu*:ǻ:ՈxFd. }퐹A`m8:e [n=g@Ѕ#!.0}*0 TT^B?IT!#n£ШnKp%"SYcR{Lj!FlqMQ>sIlq<<A.!FIݰ9r07  6ʑqW8QD$限z&@:OJL]qNZ̈("PHҎRX (n AAQFHr MMR tFp2JLQ8!DSYM0 NNR[!%P:jeY }7|~0|}qrNj+ />(!}P2 AEh('EԨ5>l6(TÃ`R>b[$6z4F QS*:n$IK:,75'˃>SȠ P@ICEnFӇ8RY|y@L5ya;#g3  I5dia?0ʖviA"`7ojy%Da G#PiO`[r5PC`[n|Ht ?Ʊa? ߇u# Z/ANG4!?qf.mU~* tk0ă"9av65hH tvEMoyGGÈ~Vmn}UxhzX5`0׍9=")`XUoC&  > w+=`.|<S3li Nc#$Нσ45ӃpF,H]r_ߥU=p###ա\hc&F@B\n^҃.4]@/51%&2Ea4EĖ892GBLRnL<=K\);tQIZbm0zCzlZpç0fUS`$:> { #̆Jj\i+L(tns>'RWW^<.T3 F!:D0 zc,)"J@qJ)֘/x4\$ݱp`}RG5ǺGT0Dڪ>]UxL965\@&gHS0 :,$X 2][;%~_%BG6Blk 8 ZSFs`_PPCCDɘ1 ]?фԡ_DgfM1[BQhmۚFM0#r9:N֯૬ذ2 B>Q\hS =o{ZFHIn-b|5&BŁ8+P&!2rG½H)#tM(t$|PYf4ФO^1q If;4i(rRSrT({.:;Wf_n|_ɾc ai3&`Ѓ(LZFͬ =1Můqθv?9"A*vֺ:=/29SGzVD& {ޤ7RI<ɴ<obpdzZA> H*`P.JUm2O󸳑0U2KId9q3Ը?Ā#SC0gȔXCԧde&mN R}>iGUێ@8, iۅD@D` JEWhrPfCudԸ ca97~wϒ6g٨!D{Q#no&L8ڶ<1L#,Ḳ>-!}pM8 &q~V45UC 'HƤ i>mh@j|A2|~kS-o #d%4'YFRpTgO5."}~(Q]gQ0?k 㰍0eNz$kl|(8z2:P.20A7L#Ȍ% j9 7 oc-థ12\l.7%jSR3,`m'F2AqAY$$J5Am@ @Fs#" !p5T HyoYOo{W+򃨦焜0:]K*%;Ӈ53B+TբP2Y/W6 -GL$6 M >u L5(5Y[%M`FPF-dE &tm$h {C .g 0 3AQ1HA,Fiu ,b?c7+s` 0ġ䡆q3Sh q7l)F$U qԲhQĥZ&ҍ#P8l)8Yx7T@:~9A'P!VEʶqP> aKlE}1<ݯǑKC=dRr"du[& 8OSv@9!" nEJjxmK?9d#Fٽd:G:O>0 RBipH/-ߋ86ȓ^=Ta{DOa_077m=-2G 36QCJxBzdQemqm)p25𜉢8ӊjBܧT=)Ԩ(k&||b!o&хhEB74p!(H=jM˟}qgh2Rcbs>]x8i>Z OsĴ+:LCPLZ ?n'$ȁS\b̞;zgH 7:Biw4KL\xb.21%\E+W(YTCA"2?Gv1\2/\fF&! (=#L<*'g} Ќ':dIȚ͟Pp3  &9DH嶝tnꅅY?F>@j!<7VpR|rM`Ϡb3n':펒8Db b;_D)U 2 4#<=ԔKe;Q3ur̺SDp+gnO{Ӈ]VSpQQyp-PWY\p 2(l4?C /1/R"+(+pf:$c1 ?Ae/&@ ȒE\ gJ*]RE1,7SRV%}MHz%`\( xV,hS 8wM˟a0(5{d][_jӖW߲cs}j/<ؖ{?{ϣOߠlsw|'~xl'{t#O<fk{cwz_+ Y]i#O/^~Ǧ-;d <+D6<-;=KB.|'~fӖՏ?rsuO?i޴eo^\Զϼz? [7G6o}xӖغfl}do!!Z:5߶|q-c<@ )'ڱ-WZ\i'u eY2HNgӧ\<\p*AȕSJq9-*:<_0͆|OQ 9/th#a6Y|ouycy@ vžtL< /UoLzjjT^^\돍F֒i]F#/+ܹ{$PnI!s!c_0g#A;鯩z'5|?(8bЕ>oybe9J3(37x r xø/2ƍu_/ J 7xee#A=tzXQFԞ5kn x㍷Ƕmxbb `А!P;*j`Џ~37x걽{>ob^ J±ZʏnovUٞ={kE1 õC*'Aj7x2Q7Ls 7xߎ7~q1aWoӿO-:㋎bji7xm {o~*2H'JSgd֨"g_Spg=Wx7ޖ7}C 7H#wJNI''>K7 M=WoVζmD'>R}7tC C{FoRa)prf[7x㭜mݺ+͖0HVjUc71 _i'SH3J]x7 ϏAjfd́,ko}(#z}zs~1(FEWߵ@]F1 9l@z7߾fSbgPiV:=7W_a}漬œ7]`~ZE9_IR=ms~(rS^59͠E6C ۠ YĒr4yQ/-)pVkf, ~eceRW9Zx x^=t%[b#L_s Zq{@ mwboq|5Uꘐgc_#Ph~l[\);5쏁#36/3?޹,=)?ν6ߎW>U,X)UقMGu_I'{ɯ2 n(XRs)G Z#fRY~_/*}|_po(*heNG%dX׭oua5%k%%Q2;%{YCY=i7r.o$}Ûoȕ,5'R8g뫅Ȃ WäV;9F) I.=٢8]XLkT8Jl3ƌ_Ӧ䛃܊\:aD[:E'Y&3pΣJPfqXI",y.o]F1(ZլpRC }vD_v.q$3W;%"çe5H.18@vӳ Kp\щ}802I˘*R;~G5IQ8X=AeS RU_Pp;/;q >/g*=MϠ-y/}.U_ oWAy>==m?^öW޾0٨rnѝr֍*;6 Ǟelպ2[DfS+7>*j //( ?tQ( y₱8J.*mgrBRt^F1ڻ8jc{ITQv yrpղUzv\w2X,;38`X=&֝zґOl媬% Uq?"w~\μq ۿtIH+!RU- TqD[Wo%/q^H~:[X\864VT(Y*03cu;̞-V.˅7e++iq2hij/BSޟNX=U\>.'0TDt$d%;Ϸ9ʷϔp"ʧ蕬9_STAIXPssxjmE bPeoa$i-kF?>H~O幢.QTR1(ϧLr^" Jg .ߥ ;J@A ܺݕFg†g^G+c!UؕwBxbشC3ȖeӿK-P Ӌ=ʕ>] bAW{[8 } L&m}]Bj XA/Ou%Q陳7xbc,%A9QQuPi;oWAy>99viyo}l۶m')?R9gAo9{>o`NH^EAoS۳gx[?RoەJ)oo]Qݰ Ixov00`x7x r#^oۥ6Ny ",oۥ3dgIh jnifS +7_AޱfAdLS0^SsEXbe$lɣZZ{)'02o<ʝwjS⼢OV%WUJl\Y/WԹ`cg3+zgSԅA A)0,A>ctXhIW3̢?{Ey6'<:;?N˪*LEŌ](_[ r8Pdj/)G*.\1*7*wKբbYy$:ަ ej[/8 JdyJ\٤taq@$y03LL[. 1VJ&Aٳal+p\K o bSF)ڒH9wKFa-爙,A,~i+E1 Zt㮝 ]WbE Z*E1sYZ`{15UXJTȠ2%Gg πS15 X#.[jŷH(1"#B G]2OKJs +Z˱w:.fHr䂤:t)Ǒ/6f7˹щ ?#cX #ǹZ>+RW]۸.La;c>LXaYe~ŀQE0 My}<9kdz Ipb+UʱfС,RcPhҟV Vަ%A̽ CJ9ߢ,Us叵5ɭ*<_%{sQLc}m]gا‹GxfRW] |_ J`]ƪW a5 s~/M3豜DD o KO=\#.[Euwr'"pi,jx%+({Tꢘ>?ڱЭ#V{ց_?߰wdٽnvqXVd[$J%[Ӝ[>OXiv\nQ ).H{ޫ{L9`f ωC (GY[g۬X3ҕc=s{&D9=;Ta1v3{V}e vX#·81f 4#܋2Td ! H"!. @d{}^ad0A+]wA:lQ4`(m \ cHABݵYpB'ʠ1dsQɠRA#A Z_E0A#IF"zƑALDA{K4<+d*2yex:KdMYmg#( (AJ!eV*Q-3舅ыM2T< nur@ /P z'VI1$벹7[OOyݣ_rB|~ϔ9ulX1R40j̛𶬶5mcPz"0+:e ?*fWA3 ^9,?ldG7sG^8s{x_5<,z V̷ i¯OkXG^̎jx3(SvT^hިO΍2rK ӒO5]a&+B{R\Ѱ{r-L̍}3bԳ1N] :h|% t_߭'|+&g̨rL2:ƙ@[Ru;KwT999N{3_X]a;wvsrcr||[Wnmv{'f&WIY@wt=:h\U鸞F؟$nݗ>1|UegɠZE06ɕdSIH[,redSIH2HL?IA qj:)vgwAL̕ɕ鵽w;;K}+1A'>jCo6娡caQF\{AAAc(9 5se@8㙪(rBZ:Kox~}G~:0$=hevlvfe1rV8-W  ocג Z( =14#7PrG@@=s^ `,'ܞ뽻@ Cdm7[&`GX0=Y)P#*ۤx_0}/Mw8 *6c~ = 9әibGbMӱc'43&fPAXVFdZ`n.f~ѕ)2bۤQi똝 ȳ)Ϫ/tUmY if1y)lIv܎:q}`34It?ZX =Ͷʛ-jVX曢œ9{O=_|.el(W3AC}΁PY,h!fxghbw>}LOM-߃7;pK̍7ӽ̖5L\<c90DenM9l+qTRw-sZ>>6լv?0A 5x<cA_~[Zd fy9zdchOK\ȟO^ NtOt OX%AoY!glAfGNc#>g` 9<=BʴA "4b ,>9{{P>g˱uRAL񅡉ERv?سoO2hlN]Z>A&ܙ]ʾ{?Ask3B7p"9ݹb} $dHH_'{3Pb,͎zFk0"Եtx Wdht|f 띛gP0N r]ΧL,ܗ ɠ>]A­92(-uzF^\Mh"j2kGQ]ZƊtîڍ4;H&Y0oǸvgN(+f s o6=;L{ %Z5PAMSG֥1admPN Ǚ2e;KU5ELh#dIRd4~gxT87z"o6>3lao"yј#]SJ u9u-;Rخo)M$.DHM2(NAwHY[:gtd4f+^v7 6leKi+`BQ[4R@kw@6Ѱvxsow?i w\y3hQAcsBYX7[vK̍7N7mv7 1AǐךA)#7){&ge4kg?+Zz7|o\z"$Kŀ xAp⌳m?͠}>-~- ^o62[bmAK"ˠy,*8 )IAAR-2hzq}b^( Ƞ_-O,<4tOȠ' "?O.ei,H͐Z&E Y:K2h\H.ݟ]I왥Xń8B@o gH N`$B DL1OBJX}E٥Ec2(/8 1riZ8-WuZ!jt^Bg3g7PZh0p.9oza5A-eTXo6߬A ;_ ;sA-dv˚+v獘y8Unf2X~iN_Ξ_J\C=+ˠp› ygt3"D\0Pfyzxb{8(Ԉq֢WqˆqzƼqZvx)2éKB.O.ZHI NlNfSkˏ_:^껪?Y)j﫼 rz0ӊ;o >p\هb, RM/ e9 7[6֛X3ҕS _?؛kۿ7WoxDv=aqXoyw >AO)Ao60λma&@2hbfi|ڛA_2hiݎo60 {8 LḔA3 Z^^ZYZ_^Sp/M.$݋[TN&fL-O2G2HL/!ǩK+S#Bqf-# `*ggH^X'=:rovY( Er.[^]Z?sǟ_M:$ ~=Rtz3Z*)gk4oAqeL7*+aî`:fUMhc l6;way-v+Ϭ5N gw8yIàY)6 zT^Swy^5Z=NyQqVFxlOn&SKS7}CPuoȫ>Fmw<ޖ[53(k#R [l1 8A-w :T͠|?x/fslQ\_Jtk Vcfz( L52׳4jkZimjo[%~c:͠3k! nf7{{CfZ컏cvNmS= 6>c[fߕb{}L>mq. ㆬm߃ K7EDivlwlQ9e<'vn$c%t\Od ,6j7΁+ػа9R5dШ2gP3AU f"ϠWeT `2 jB0!ܗ 22,FתV+A=`6jLdP4޾'ϠX ل7[{;1tvCm G'fH _)ȇ9UT;ϻ!/Ly{b2I3(7~T7;+ ϙxv [jTn$if?I5Ǎ o]TRF֥˟A߃ K6ߞo6ٜ@u̹lY'e}Zn!Kkg@R;N;6l`3Z/gUtȖ$2^yPb~G?Nln#grbFg3]=mdжάݹk.ܨ0DbGCgfTCZ54!K㠌1TnG𐍢uYTrT2V9S̠o_:Y{;q|\=< 82T!FKlΠQGŨ0p CfoP+) ԡvRgiyTAdaʞ?i|/!e'؎%F3Lu,Q2wͶ3bXVߑmk1]+~i 8=[ﮱ73/yPmf):YSg!wOfoD[4@m<ځ򞥑ov=2*A~WTKۻic{v.|!ф;'㣆+4;S^PGpg'jfuZ@V,öN;1E;OrTYV ܎1N$h$C}8Z9Z5v;#il w0߱44mr.3b; l߳)s0׶ͩ~V2HdŌ3uG韭 8 0yw62H>QefYe.pcqR&w>'~Zuu_Ew͢mEñ쿍SXI=~ Ɗ(P)W0/w|ݡo=U&ŎjsӋ7o0gbj 0ϼST] ooYޯ {; SH(n,. z_6( vg.=ٿHC ɠ )v4{3κ8w~y-ۚW|(dWrbFQ$):h{Jt)3֐PAŌ)lo =02Y♖d ʠaAA |a&gdwIE$(2h 7dtڽ"l6@faoqoH8}wA*y3 7۝l\'XP$kv*e " 7̵l qVE.ka!,Ao9f]_9bt7w6@5g(?]#wY m uہ2T2^zMo6U.v73;񁻌q2sv/%1k5oS6!ffÛ !T5' "}x\ǁ="'/eOIe{C[AdP?Nrovx5Vj_]xHHIȭ%ek҃0sqfoʯ6L}d +u![;)[ l6Ѡ9fG4Al]AkTXc^ϧ5)h{67{#f2"ofxScf/Jڨnp_H/h/l e{Jx_Xo|Avb jZRS*Č뭓Ĺj-xe}'nmN]jZ@3gnt̔thY}:OoƧ<k[f77[+ pw8e_ e ~a,s8-~c,W]fCkaE!5f$f4fTC!ܞ_F wIȠ7qxf2)#3k{¢̛t <)?O\`$RY}Бqn?}h6^ ;9y)z۔T5>ErE)#k{<*cqHBY|ŀjEE0˶#j%I\W-q{ǤԖ <0o''2Ԉ Y3R޲Ž꾹R'_;p][i%[O i[c^vH =fboHU[:pűiV%s[K5.pG+w4p>gd#snGOw, j$oz?ax_YK{I!SӘhXY kҦiV4(9gᲆA7R+Ӫ zgwnm5Q_<*>0C- 2o!eP,8tm4qyd`mI_MoXl› eP?ue(Vozuw]yC[S[TD6lx7 eО7.N*kt34e6bo.Z RlGŖ vn2oAɭ\*n:}9zՌԖyn61isfoll'ɮjXp.K1`$M8~a3o6ͩ:^37Lo3l@ ҆͠3ٕʚIv8!j jNxCǩl}荖[=i]ݷv;lz#͎Evjy Im=C[vv86v<[q1}D 'ɮlO,"Kv86^VjiәiMx#mLTp:2DQɠ=n#g͠3$ʐAC^\zx/Ϊ r7\\1AN/o>_s*gŝ{#&h fGH o6|ל;n:_P\jj`S?@bHf%"i7b?f?89nCp7;]ͱf@ cwyPɠ1dQϠQdS̠Qd@ FdcovCe 9;:6DXEŤC%L]YFd=y\ݴU\Dal32iy{e_(`߀iAf 0LAÈ ŶGfa]cNTM\c*m-CmG6kn;Y:, d\$Tp'6ϱ;Lсiܡ3+ gy+jH@=̴G̈́l@]*T,3iò(nGuN)r;Ԩٲ=!^ge95Ӎʪi\kTqۣA-aeSћGk=?fV驞"eۡ[Pg"=ίK<, a/N:nfeXzÄJ: xf}K>WlZL栎R/V >| $̺0*Zx͖U^pŤ]*hap1*k-ّo6 ߵfw 8Af7,o6Oj/V15a9BlӽٿHL!Po}r"/Q%WttL/9^+˥mJZ;`/\{F7ZIie?2)ğT) z΄M mߋ` %$_,iʏk{uܵFR 2 qq?`d~鸰ZmzK\r6vVʨ|Q@!ANfGFm\of,>=tU*R AU]7 AfsO9~`ɸZ6Sg\_1ڣ*m^q xHB|b-dS C0Kڥ"=hwsnu],nI,jn۱/$8˛ͩfiBfx/MSuI4ZB S @x'$_)Kus~#2ȩlx }nYt)tQe]@zşAtG rT w򎤲ቝqxV,r56!CZ b9_W3 qDŽg~jxeHLIꖊi\=Xq/8u_dbj^v3NK;_<'/fI.jH"l!xk"d DA ZH$23I`16 z-3z%?  *.|* 2&h BŅQO=€ غ^3y0 r7[rjzq>d(뀹:?Y0`À 6pl< ))x:&QA?rM]j]dNa[nTx 6-N^LM镊!t}qNfM1*6W's*l#9*w>ίK*9< oo!=k\ԟ̫la΄dPJewJP$o޷˫\q3<~xc& ء}8R+ov_͠7U}BQ[Ď}oxǩh >JYrT'dGnv}q\a{}]pҮT fK >^-:zu`r^dS~b@(7^_$Z;WJ:|klYlN aRdl۲Zieeۆ%lsM(wkOmL/zs7[y$dPp3?刌ʮ˶ Kbpb~J^ܾNOӔʦlȈ{q j̡lm*oX9~x7򃛓oxߝ?_?Uͽ?eq XO,EbzɋUK凕SOܼsDo].r7; ϱf@  RyfGOܵ?].iݲh39~!jET6 쭯O)CbgUͽw/)U;*-K=8VQR̚WAlRN~T6K:>8{n#grj^QLQlq)"/;'_= ` )7 6LA%R2)oϨ1*ͦD]:eFnkʾ`a;&6g#9C'slрI 5Ïr0 },oygőHre8c0i}S#dе3ȩl:-_30i6чAfC٦:ynd=Уlt`H3,"å e[?gg"1=hdPµV2șlg6DTk]p%gTA$H #2@PɠZdQˠ Ϡ<1YAf+*Jՙ \־4d-(&z)TY7X= 'ɠYS3lrc* UP20Q\HYLyoGZ{F+S}Ge--FyUZ9ΔNEEyyk&X˚i_E0(I9ZYUu ?p=n:2h i5 LjweV]FaoֲvڣjV)/!\2I7F|5N1ңY˷F]?{d chր 7[e- 3G\l*b)L{FgKovз ٵ8О/gYo)# v^9u7 oO RRjO{$.k"|j fMvfSZ_6B[~?[>_T xEaQ孥owp{7bk{ AK]8uSG&_{I"8Ѓ #~9u4pTguW -t>d23(_̠BdAtx#O5/_ay-1`ǎ 0`!gY?N0`*Tw*޺ 7;4j7!ˠeWȠv&ALD#:ÃdPQL2.3hd$ F!X/ :`uɞvf_~5f]{iض7TiXAּ"!$_ّo%*BSضꀑAf o65;fFp]g2:~`I<'l(d4MgP' {ہ7lxUTAӉM7"M?ϵǚ6bmAz͚kcv7lC2c+Ik)_ւmެF`nl"W͎Ao63 쮠:Eqaͻ+amضMŬ{qaK]8uSGz8WL8$T2 4C/,cѰ͠k3+A B=/" 2@ T6]Ԇ `5oGx1lYKo9"RI1dRY |qfGüK3ـ 7OfxAo|@3ȋYJ o԰/q@?g*k`oj@ 3l_}fGj65_o\ ov53_ڵ›@ ᙕ.Lov]frdPI܍! x7x o6bu-xg7Φfk݋7[  *^,'B 7VY lx-Û A=K¥Po>x#O5/x.dҮ-kl6.ԑ7;lXdPeJERy(e١TS4AU7Zp%$Z~u2H\X_y͛A!AC¥ζ{ !et) `% cHAgHu!"ڣAf>\ ovx[zO耘"AC뻨 *1&֮ lcx'fsUM0Wv^8@`uپ 47;ؽ8cLU1E\ s5A xUւ7[72b5\X 7W6_-SkiaU Veg۽<?@ F EwLrnIϒTv? 7;4`8I]KRN2h^p'.guKekC? ` 3[fyAd:'-k :#ˠi><#V@/eI5drNzT^nAARyeǿ ` ǓrIZں q29w-_,[=$2mxS(R/=]*ۄ .2uqqu Na:N]-('mA͐C36m[I Tr5R:roA \ɤ܂RVp/!zKjGWqJN^b~I"dp9w}bz6Z(2KYYm3s[[}k@"dPS~u~u䕱|뿩~ڕ[# ڑAU|z!=aB>2!IԴX_Hvdp'r DI5GȠdp׶PBjGWq29Zޕ뽫۩ *Fw!elX_H 6N_/_+X'e{ :_w*AȠdpblDڑAUI)1t_*;H= TԎ B5=#3 ^oxmR/E|*p Jȯ=]X GN~_SňKj`) C0 Pԁ ` `. ʭ=Uws,42|a{42I|6D&23h[AwNȫ2s,sWΧ- )_$睽}b )MLҟN^?rg~|6哄Y/e}*)tRYVJ٫b!? %LRΙ+92N^:q1Ō\ %WWɯH9q1_b œNM]9C6.URr%FJU<シ3%'_oO*ͮS2YֽX5^5^=tzX( e$HWPPT qKJYOeE]*WŲt/ eKY:K:otOʩZ9pL~ƿ<̆m?~R[iuccMӹ-L6O5OLN]k.l.l.)l)l6C^@6u=$䵖求ɂ®+kC#/+Z WƔR奤5 O*T"~Y)r*%k-yB,Kg>c>}.}6VLgLe4OJ%iB*|m3sy K{W׊IQbDRȯV_h\xrZtC2hCev ABacM"e -qbG!&J ePAT͠®K7TT+fP_yߗwK2(v~DibeXC5_ ( bH+BsN8wLQǴT ۧ [ 'HW%uk:YYzퟓn~ZqjG)ug:}b:nZX/rrF&r!B23'݂ it͓4$M" D~FAbѓA$gRH%1T$P V q8B^ J!c1w{ĐՐ1A.J}BʠBҥн}$Vyċ!_y3Ceд j WCd {HLg>{9}.֍ n ]_uo|}Ww浴[VHѺܗ.tUueJjy_5 黬hY޲ye82[q6/T;­VN+&[>ߜ^f~T=-T,߸2YiukXVeY*[B,Kʎ`EjHqHɋ-kI/:~ߝeݗFFRiUm˺FʖY-LiZ}iE^ȋ[;!Fj٩+mmH/bfmK˚($4Ie%x"6&j62b%玝֮ownڴio?>ÿ? ? o}2,#W,_}{Rʓyz_~/=yyKϒc=s>ɒO}F~ 7OPrۤɫ8 J~Ͻ]8O?V0 endstream endobj 64 0 obj 46145 endobj 66 0 obj <> stream xZI,7W%A:afng`_ZJ e= Mo*-~)2]|n_!?~uOJ'㗗`n7h/.)~f+Gyg+BG0Ӗ?m&vDj/Đj.h!7QISgfTm| SYa{,KTdi$j{4/o_ĺ/E88GK,/# SR洑8qVa;&v͐0j$Hncsq;0L%^5v\s-:b#r@KX@\fnI~+ 3~@=;]h=eWb=3Nrpx-'].tGĚV1-j#[Zzk2Bu]-"2/%D:\,hEs Q.grbJ6T@P3ؕ87*iU$`:po-h}`+>n}0^SB 1 ֩o,MSJ΃ ̮37̏1/qLgnA,v-PElԵuN+iYG`\'Kn}f7|n /,Lx KtN]u +y‰ZU' ?f{2llp N N+|,+,/ͩ>*km>?q_Zڇ4(UBPB3Gx+.9zX-Z^zzBVnX'1 IXĜ0!i76bMh6IT=K^„x"F34@ xM` ܉^sW^ w\ 3敧Votf;.<ȷQQź܁qmKЃ+@A,6+ahKҗg=lH=5/LUl| ` VO_8{I25FGFhJylN}膿O}<#;^K#WTI6ؽ)1Y#NT{ZMUGt 2_ [JMDĴ'3g&gp c8ǝ>U7=ϳ={DDy Fť1u(Μ vZc@,)TZpеƦp[͹Rʯ~/Qe{ endstream endobj 67 0 obj 2438 endobj 69 0 obj <> stream xZM6 ϯyu-,`0L>v P{/IYS-$%|Lf韧Oy~I޿~鯧qHKtzOD~'F哎9 h0G9dNh4GMд Mд Mд M L L L L Lۂi[0m m-Ӷ`Lۂi[0mm޴mʋWpzMnwySp|yi=1.L)t%& #Q"v|-z?L^R4|~?yyqƪacuܪr]#ّLt- !ٸUPic;VQǑMme\tmhuk=FFGF"KqƃcC`tw-;3nbΔ'\7%b nx Izp[(<ƻ[ b;o zф[9)_+(`"̾KJ墪t#_T*`pֵ\6aJŦ ^}gXΐ@߅ -T3nR9ú%z&+lJBcuM nm%a]!cєx⣋J|T>a~)K\ $1':Q ]DY=+rRdt,fi%\$6cFe=nnnWcnMסϱdyq1XT"IB'n(/{t"JNs@ɇyFh`890Ьv""g@>X=bCXV[ZO[)+Wu!a@oULSMڰwXV9"VZ*{Shz0|hG q'p$íʧlfX8ɒQ"o+K9f[P =k{=#[sZN[IYq.p|TS7l%oۣe>ɭK9CӓQ?Du43wo9?:CTdaW~ XrН%{6٪=dɮ?di%>PCy)p]*,x=seXd;*|.}{&IJ<,@553kLIߓT^ɥChR" jjj=:ژ"pSۏ0|ݰLߒW IR) |wY$[:ҷ.~^;"v0Yh'R1*;yĜՕnR~WB`}oȹ H-R)3I/KmyګmtubG%6QJ7!i9V0טt98>\ٮU9oVhx>UTXn#)%riq?=@/Qn$iA# 2/ۚhhmv( Ʉji++~4Õ{Q|ZGfD3GwCGR#oכ_\Em`;^x_Fr1\}Tl^ş;J(?s1JeBީFYxN؃GG(ѫ0t.Ƽ&Y3GvJ%>'kMU\{0}=t>J endstream endobj 70 0 obj 1750 endobj 72 0 obj <> stream xYM6 ϯyD 0xCo!-=h.%){P7-["DmLk.6d6ZGϗ柋i96uAנbj o/21籘22      Pp(8@ PpoqpEi|>ܿ5E֡]cޙ΢G>tM !<.h#= d-^y}ϪCNqhU&Ӗwܭ]/c卿ѻGnؓnPFz7E9"2Ӝ5'H8U6.V~oU>&2 1 gsI7௻ Qݰ CbbP; N%>)zŸ#<Ӎ% sN}bQ+F 2\6Ew&fgq lJ\OBs:U|P1RZ[i6MI:T V `#aݓRr>&N Bϙhbhddd%?'s&ˋH"r#UI e+'z)[w©FXSh(cpCGS`90 #Qb{τ{O?z'#!2ɀ^'pcPD ̞RPz8#DS !:ܜZg h{ w8)TawRM 3:)OuOWgyS#<룃=ha1zI$:BZN et&}N$6s<'%9~]ɧ-cy'!(ǶyQPDDq]6DlJ2кl\ŖqO<[-ouׯ?H@v@9]5vCusUf[yT) TI 8sP897s$v8Qeعchsan I+mBLX-l$1kƱu8! MkDi=Up>oN]:m~652f*N=WqܦpbݕGkg mNU7gԆʩy/5d*DžgO Sute+GZ:r49Zߑ m-E kĪ ֦~-h:UϨC?O[ȕrl91zI$AchP9EYFٳ-ˆ( RQFHBUh)l?ztН>ȟ7^ShC endstream endobj 73 0 obj 1289 endobj 75 0 obj <> stream xZK7 9#  d8`@sGj<S#y+"?>>R {ݰ{6¿1_aӰσaOvas!"_>jRWU:uժuUTlNTlΘ}_UդFu5^]uUWI]UYHF*6RTlb#HfTlFfTlFfTlFfTlFfTlFŦBScI 7v?]>z:[J,:ULB~p`oC+H{՗oD2~.$}g "&㠡96wE&gB P61U>p >0n &~;7?L8c_x9Zxwx*lB IB,6 wűP]BF%+xj92k&ښƓ!D85-C DȈcoajAn`1'r8IGdy#n`k2qngj(ceN2 FgՍ脼wAæymp508&><˥&2+_e_Z9)e FC^Z@N[3@:mHuRr9;5Y3lJ XZ(.k7|y#ȼJD"jMa zу.4j&xj'CkXv~cq?3_Dc+1dKW#㥛[CKWtF0p}Wŀٵ2ZɱY:z$ 􁿃BR48Rs/EXxyOqp~:3Ubi}mF)\Nu%^~Iy 0').? F1}gs;PϜa2̩Ɓ \O:#%H*{̒L,2] NH]xƼ><8(X1I0rC0JH i~북>RgQ=S1¶O31b=QǍ싵o1`Fb|ˍ4r%$ IJi̽?mv\ؘ.y, q<5MMpFawPBaVaK56*P~l?60P!2uz`g2e^8B,Z3!d͇l{Շl18+YV!_* _h$iQ^kfn{6ege< 6Ihc z}H^,'βu)+KowBD}fIʿӔ !C*WC3@ ?SAiuݑ|Gҍ?Xb'yNt乳<ӧݿbb endstream endobj 76 0 obj 1903 endobj 78 0 obj <> stream xZM S4rهh`v'@dK6e)LwʒG*u׷n_ϐ~r'Ϸ`n |iE6+M mmV{<*$5ՉςjV#0*q%'>C|BߖxwWxH["$?_.|p!?c?g0_oO38l8)9̋>D29 'rO~Q] eO'}vΧP'C":6ڑ GβyP<Ш$˻ dk@-f˭< Sut{=BNI4ġ! Rel/p7G,f^]l>xJ14n #ZRπ/< ?_*njla?j_gq=f!AtڊC 0c},  !XXJԓ`v 2UF BDzT|,ݜtj23ǀHݺ_V/Tj|PwA&"*DpW5DȬm !r LQ'I# GO8&kXctKՂoA0oTrÜN:*X4 R-YtEraX@ Ly(Lm[!3Ws@Bdd9eWFǛ{gʹnVX2}bY?@0X/U.GĘЏ 1V! IFJS#5]%Y|5Dz)@( vB &dU%T} 2DH}YU^U9?zMG@&%:]Ɗf \4hY0?\aa;Sf3DC{jy9R|f=<[Vds G(j ^+],nJqhX0ppr^,$f+ yVI'4RqMưA}$Wm<]2=Gщ[BJyc8ON6-ds?דOq:Q%v ˣ% % h+6@I :3c&2Ukvn=+ n}-mEh;%ۍ&yeX2ƨZBOY_;};D3F]bE SpsLpş1FD7\gH-`4=S$>&=ɃV fty u yBZ%=sNnsyb;֖ n0 /tĐ2=A=CdhoYWY(Hn( /%+Q_C@;94໡ jEg;c%;L4<_V/8+{d/_z219f$}7[SδfKse౯/$&aXTkFh g/pYlu¯lk_5P(v%w){ֈg{9S{Ɛ*ew%/$C;d]8VNPU/9^ϗ{ H#/ V:@ҁk*CCR%35(Tz_c6rv%+`Eȵ_t%K.лH.KMЃ`Oj8K\Oy\bxk*N; WP()-[P~E endstream endobj 79 0 obj 2343 endobj 81 0 obj <> stream xXM6 W<$ $P֝=^HۉPg&&GI6m;ۘg)o/?fcsl\kSCkaϣF YѤFu4zuԩ*b#HF*6RTlb#ؼͫؼͫؼͫؼͫ36{OW<õOO]l~kLjHo׿M5 Vkߏdߺc$|r_bk:SjbpOf6a܋B$%DӕckX<l!^f{u)y =a/7<z8QA9T3ͣIX/w!9]LmX\ 0j&r1θ$=Mԁt?3qLVy4MlEC(JݥĩlStBuSkH6\Oa'F?U Eǀo ;5J}Eߵ0F]"8f_|6|zH,?BDfm`b=Π &΀'|'A\YA<> stream xXMk$7ϯ'*54;&9l d__ dmlժRWR՘L`Kv +q9Tߪ:2>5/?OHU& 7lY _ϝ8::L_n?l+8]eNqp ŌkXq.BgXoj|Ng~\#Uh:)^bu (,!O,tv + 1)Fz0"]Xv˃e} tl,͹DSݙy1Qi,\'˵|Ek߂h]whn\\;a{K%)y cѸ״4k^Wj)@g<;澟H]s/Ęժj,ULv QkJuPoUGT OѽiᥙmrL;`m%c;b_4Ä͕R; T&c/Ys endstream endobj 85 0 obj 1132 endobj 87 0 obj <> stream xVM0+|^)3XBHêv+P{B x>3ƚ+;]߿/OWGu:}-1ǷK7z3u赍ı㖹<+ث$ホϨx,2r.RkŪ„C4 L`OXתwa!~rJw ډ3?FSt. Fނڮ d{jp&q9 wIZi|;tjM'h i3pE]V&jxՒhr.8\Sv%={Wuo2AH|uD5i=]Ӯ SKCշ;86Rc~D68qnDȠς {T ֡ endstream endobj 88 0 obj 656 endobj 106 0 obj 16933 endobj 105 0 obj << /Length 106 0 R /Length1 24428 /Filter /FlateDecode >> stream x|ywUwϵ3s_;sαr.* Q+ăa75&xl|(eU,TuuUuMS]O7$y)TQ_x*w7\!m.hq^lU+2 錭yBήE=]uzK-[OM_|*d]uoٽctDI^OGaH $%Q5ѐ2ErRAGF?1 qx0bQ"a!Q"$A$EH5? R)GjH-#4&LZH+F$Oc$Eh2%x2tƿ!r.9NR&qd-=QPFn/t#}O[4V/HjO`7Fr#9B"G_"5!sőX 6$?Md'}YkQG5~R::jt{isQy,j*,UZW{^#%U+_{,1}k1`EX)Zت88>: N"y^N2tsb jh@ xhoPQY٬x(Q)9DCj!8ax͋Ξ~EϾH:ĕd2 l,k5y 0f֬1cg3,qZq.Q ~ZSjyR/*&fШE M G7Mv6[i^-4gF9mng$p.lv2g9pkyK+Jb:9o[ӔMV'&Mfy*:]I~lwuSӭ'6jt]urB4h>J>VWzSf=qsܮȬ#T뱾NlOiV؀z[j@F5gs3,@f5{ΨRϲ1t]5#,ζw]xAcMz=rE~m-uUhm}ZEU V6JmƎlk%^h\ƺJ8zJfl-Ƃ;lE+2r=9V-JQrK Out+/KVUHj)}*UvBPn٬ҫ$CY<\QEJZSP6$eN/u?)*^֨teǏkjuZj!kbE/+Og"it#|>T>vի~*n9~lq/8?\QD;6CB#':#D(ti** z w2~zq" /Xac8+c~o5"J ϊUt"|dJeY!q2I$jAv`&!lC+m_+}֛$wBT : :ѣ7 bʤjmtT#!yIzaЫUDҊz`t΀4zb[aJ.sږm60}pk1IgB5Q[: L2Hಙ/Y6k%;&/?u烷J.X޼A,,"̂LC$RhOFq cxtMvJp3& W.:E[m$V[4L92Dja\֑nӳ-U-Uth;T]18|yqivvE[[TtkUAeŻwhs_5*һX2V UjrV6a[VÇ?PZW  i)vvB -$X(;LVqj|_i5xJ=G Շ$yrL E`5%G-H,/W䠟ƵVL,vbO,S Bkb˞XbM<xא J,Gz<sjZςۤm{;;L{{T{{{ǜG"OV>:,VөL\XFT~LGb-=}lXh}=;LKA8 lY-TRYie|<4s7beHY{+g.Qљk髒Du$ݵtK7ԦQyw)<}VI0uQ/N8(HOŃ+pMq]]nHwMSTѼ\jļT~y6FM*"u:A7KI}6ŷNU T81!&H7/ Ww%־=gwչx >UZ Vu<|n~r$kBʰCj$v'gog< _Z}lp톊Tddؤ$mlOnmowl oOown m*+nNAH] ;t&U T:+$U;9< AXqjf/<$RI5tKo%K^v~7|:wKrYKnnh?Y`d6n[%o#gt-W』eFmw֭[lDJZ>=05lgA`ki*ϪZ2*W)9D T1 V`-' CL% ;fN(%qBO';{*aWN%] ]'7[@aw"w4/ L_W\}ffq9k`ޠ9*Zq.q@ 1=/seX? CD8R%yH/2~-Q7TYBW鴆U>3b8:pɢ YI? a>]}qx^/7B FS1y^zY tbsCI+iŃ\8eʅL.it>|>8,b֖Q*j@7Ia~dK3:go*VpNMѶ!4*aG2S>HECo௒sՒrE+|hJXSxt%\L8˵A+μ\YD7HH 0FP{EfLX Ѹ0 I 8[tIsgIYV kdԖ6 R,KBKq+Ѝ _͎|<'tjO تŃǞ>́19!3Is{߇MBD@OpLvJ+oEhF Ϟ袳-4R{K\Q.ysqG~}~9VFlJݶvxt0XO].|[a 2KYo:=1[FV >@2:RJB9ً@)䊤U/ml'^$=*x |Ը#XJa3E7tҒ➳ٙC8-r@z[1,K= hEk _ML:Ff 'fy䁴W_ڗyz(|x|{[ fNt4_T2ڣUUMU4d[y2ewO_QN3CVIUTO*́ 3WGZTy~'jvo%{,ȍz-868߭︠pO**FŽކXC-ZN?8 NH7knؓooK풒Ԣn~-?~Z*{Vf eye-W6?כ;wjr֗2o#Ǵ]c7EضE^HgUE"V*"'_4vY\%=Ad-{ X$Tx 3&8O5ܜN'aՠioVpd?Iӯ4t;fͪz 32jڟs+ZW. =X@kO Y4` ͑:Wzp ddД)ҙqύZf k͡t8wTEUbs0(DUz!;v,Á!r_m,5u :ѡ'May V:X4vs~UOnG"rr;LjɠX'gCYDWմ!w[&s=J`T Sk8S8 TC@87 ?J8_ND9Ӂ#&&Aqu0 &'>j7+vw¡H$EB#95YQE?joVz*I; JՎ]HwA1a=/!L`z!ڔjQkJ"yĦޢm҇/߹ЂILI~QV Tu|剱ooFbn0͘8T~vlrl&R̵ڃӃXM`8sA7܇mcU-56ZwHg\hOVulr]cEի *U=װ+;Gb%ZZԩ ҀOgPU (+ ٙ,qvBag$b~$6 -=PQ|~b"3Z ~eS(tkEڙ4sf<'c/NX?މ(d:\x+"ΊgƯ^]ÿ _|BUv{EܣA\.Y h FIV4DdC$aK u|)Z y0prN`rTK)T (t "5m6=ֶ4y"{={'i_'-)ewܠ ߭V  ZjDnl>J*^51 Ȝ6АwTgipy D={bN16x!;pB0WFlc4PXE5Z :4u'ܽӠnl9]["ה׺V:@@eapi)@03rdPʀ㔆Й1fUrG$_k24mBbyI Y[t7:7gTCgɫʘ߳O{Ͻ}كP֏|B22V\56f+,jNzPukzx&yH~&[yl VUXkMka!$݁޴]So\vc@rZ[jaDSZ(c0/c^3D4J(B`h830 ]Ե96]Ӥy5Ҫ CLs0#p Y)QsM7~sMno$ {Xu# ѝwY;jRO*W+i|ˤ$Wᒅ .$-PՖsV>܅|PdR,t~[R έGśǶltes-{A}8Q;Gh94&bQ-gV k[mO ߾sx-hZj^j_]Ui}yaa7Yff7eE=q7;-!*ݪu1*w;&`hTtjAe)Ex SZ7]< lGQk=P얎TD\,Xӆx//`ϞxI; Jp"p͔5wX{s-P S&6#i3 ̭x7<>2fYHꯚ7qb]gN8%#.-3&(1.Dt*LFe-/ӈJZDžz yM n4ϐ/*T_b_8hp(A%FCFRᜨ ϑkڭUU˝Jc*'{O:jT$a9JݾJf@'JYM T&m?C``WJ`sd.9Vt Sd(x.hƒ5S˓VGډ^_7.1L8jxO/M21SO|abX 8ׇ'}7`8P1xLz0 1XC>kVbjdo٧vǞjG%T@L5!kܧ݉%dQ% 4NMs tK]!8+In&AM Q1Z?!–>t2㫶 ֧ܨ$e(9pffKpB/:T;Kʚ#ԈJY85/ο:olhTwh4;4=9;,ɲNɪ.$M;E?ʞ``᳘sP,Fѐ F]7zZHsޯU_WЫ6#3y)Z:b0 0dQ@Fq|:u¸]pSƗHh':wyBQvw4oǙs9f5frj| fξprD+?{b`dȎiO!Ja7R?yڅhނ!G`#}T O1$c@+`:ҍK7a3ԑ3VlRdzW*X=;d,8ʳK8#>q@q;[IcIDdc]\$>'S c .,ށF\`+D$!WɬȎd/u +.p.SO{aO}~/]5y'{g"^wXIg0 wnqAH˴}OZ~}_ Zxk;@97Mn#z}*ўB>٣1#E|p7Уq@9a>0 X `8*6- {~@S:==C$1 /\=LnE$~MFL<᭐ 5<:I j^a8sƍyt2ڇTMCG qغghYx]UT?ɍ7=M][:Φ{Ǐ|qR?C_}ᦽOumx`|.޼piLW Fvc}qª[nr"݊>AԠ;z kǓӑvBppeFn@ HjYa<`Q= Sv.J((.HMjQ۾WXzi˷-XbI{톃6dZzj$_y͘ f{:Hֶ~tP%M؍Y#HmT@ 0ߔ3B ݟ4yɸzA2jd 8A|bс<%=[s @< ]̙$ HwA|xNrɸ|rJg-6fW̧T0ad…9x(W9. @>^.o(6n^xMlO.AZ5>ʇq=ۇ2;KɚCx](Ꮑ b2N$N&`ȉ=ؕCU3Kct ~ nHt_GH#c̭G__/@ćvّKEk&QY$pC**L~#46/ .lfؖOsФ.ϝXnIT?~C[DͫS&2;_=y XZ&j8 Ӂ;2=6 bcALGw( A(iv>Ĝ(;\ rMC3N5]vk&Omg~Wff_ANǒ@S9㕥3~&K>TgLb'YC\X]on;KRXt ZD ]V]Ek3Z,2 CCXE씓h;㩊u\ݖ@DDj뷠uIDcO aQΣ}Ϗ~1|^Ua 2H%C vf²OӒ29?<iݴMcDf_'c1q×4g͈G8oplf/ m| rE{[1iԇ>I> 3 MX+(fJ! S Ŗqj :(2'SL k&m1+.šyXLق6UϞ%?Zw詚Ӎ;MoSx2*24\}̋Z$,V;a4-x|9`c!1~@khZH-Zx LiDI aZ y#Ø= y( r'cÂ㋈lyIQ6gk ZI +vI \,sL2ca(CGhXSNoto['e3rq9"-hlYS1Y.KދeJ0Xl5_'7l-E]j]a;\9W'{EfITA"ѢBCHP##rЎZ;Al^*F1B Cs =qN!['%@XVt Jy|зʶ%d vi3e|wf3\iWY44Jn@T Bxf4 }t$R+YIew4oUA7uᢉ?~k!MGPc-ưƢ$~)셕u3,\Ԃ:ko9`:\E`Qꊒh鞇3џPmEIl$n~1gl0f1<>M)Őo*M,| iHD3{ c >$7!{O ㄗmV}.lN;%[ӿhWk;tjvbcc~p!!r-L3U:`УK/DX_~QxFVx/t]Sy  z1ö{H2t_t0 X´0>Fmxw "'*|]09> ;d'qUC0cㅌ AǤK‚vfeEX| ~d0Sո 7T Ym!Sv8SX!_Etal,^3l]AҊAʒ'[i't' UaR#:uޘ1T#<޻񦽌A&,%mi,ջ9Ձ3/9-H"j,",u)B`k}ܿT$L q"!L%Ht"N\.eX}}iC,9361MjsqMa˯ڟv=O݁P#x@J$l.\𕟡Ͻh W7َѾ[Ѿnc=qB j4}ڻCv@Gbl8ӈD(B1p`׆-rx6Gr`<W1?׊\Hǯ> vҨ%mLBW6}Ъߧ)@nPv`XҒ@C)O;/<. DCybDžKچyIH`|:/M7/ 8}2m fzˍ7")r5!S6yv~DN~ityVa9YtH p; EJߤ,GuݨrHMQ@>?MJf~v/_1*EB,{'TSPHIӦV(EŐ(iUF*2 #єiA$$^J$ KϹhN떳-~bܓ֞"" “;/yYG'#uxn A~܃UjcjȌƾRs`rF0KWbUJ}Uzx2ӑFl pYs#9RC2xGQC2{ XJ8?8 VԖӛ%+m(,=n3+~@(OLG>_2fߣ$>%l"QR0eȺcJ@+hx> Ha9*@J.CIܪ) .̘1=Lf@26>uQlhbp~<^wP+."Nt_8I,t fNx/@FI .\a3E/0*l2IE}UxeVz%Hau,F~7D(Hb (l_FA MǐZS;SE`8m5Lc;̢Ώ#Qk?B-ýwyOE$"iI;ȣώ}V2"6MrHA  YJա ocODbSgS~$#nnRƑ~zN< gS[25f }X}~[\U3H}Vkc}J>9.|B/&22ƁH0y#A: V $dx'`8K.K<ۖ0d!"̟؍Lc=^=fx4fW _jа\"\%웋`a17d< -!bg1650VCB\?1`WȊ@<}a5'WJ&,9s@=ȣkMT 䗎^gr?L|,e*]/)Cɠ Y5Z (3nF隻Q.q ɄafpJtcɀ;C.uz 8(c.*@m^2/e֐EY JardkFP!yPf`L!U2aA}_)zhT~ kGxY-'njꪝ*:T -53s؞\g Wa,  ܏'u&& ec[TɅJ:@9DzуVrc$Zh*go,&ac\%)),epwFiZ@ ;->&2%Yp-j.w̪NizYzΛwǫfFd#[Eݘ`tVϳ)#բ*+?#GkEd#ȒҀE`'3/Pavˤtk㜮 ~{-$^<T(qb8pA\LwqJ@aᘿ+C (wK7y8p'j,HA7N&gmOK3ϯ|14!0˫%y h,۲V"W\o'5$B^Do!*sܳ3?\:+~UzO:I|a(}iʯ Gm(4e>HGPpexjm={$ґӑ&#a<^iR)4ͩV$RbsDt܈ƚĞa}iH_"-F:T+${#>}NCbs\%/yz,\#NT|V,H itVѣlUZ:^&MYko4?/bkqj5'[ML4k~re帵º6'csqee/\:ׇzOo Y"z9Iv``8OT_u 3(览!J&Ǎ9}Jr՗_r^~k{~"y_U^"—yEt(=-oyz2.~"rL>3f,Ys>uEDv0F^[ @7|x~=0F`5"O9-$s`-"~M9wl{Kkb-"/Pcv>G~9q.^~;y>W)E|U tJ~3<' , Wŗ~\n*x.⻬e 3Z63D~o'qfpG[8UX6&o$?Go4}۬,g~1{ljS\w\DPw,Ž`qJw,[lKy QHz/yYį%CY ^Q+0"B z/p!|x1 lDVsrOs0+q,fxww2(նqAXjy\`zH+ (Bw)ֹyoCceDY\:Ca~dW2jc,W蟕EVqe| ("` T*Źl7xCǚ6t_sg?R endstream endobj 104 0 obj << /Type /FontDescriptor /Ascent 754 /CapHeight 587 /Descent -246 /Flags 33 /FontBBox [-655 -409 764 1089] /FontName /IAAAAA+Courier /ItalicAngle 0 /StemV 76 /MaxWidth 823 /StemH 67 /XHeight 457 /FontFile2 105 0 R >> endobj 107 0 obj [ 600 600 600 0 600 0 600 0 600 600 600 600 600 600 600 600 600 600 600 0 0 600 0 0 600 600 600 600 600 600 600 600 0 600 600 600 600 600 600 600 600 600 0 600 600 600 600 600 600 0 600 600 600 600 600 600 0 0 0 600 0 600 0 600 0 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 0 600 600 600 600 600 600 600 600 600 600 0 600 ] endobj 103 0 obj << /Type /Font /Subtype /TrueType /BaseFont /IAAAAA+Courier /FontDescriptor 104 0 R /Widths 107 0 R /FirstChar 32 /LastChar 125 /Encoding /MacRomanEncoding >> endobj 111 0 obj 10342 endobj 110 0 obj << /Length 111 0 R /Length1 15524 /Filter /FlateDecode >> stream x{{Tŝoթӯszzf{^=@ DD1ՄV1UCFͺ.::&qYnb z g{Ms9u~UN߫J1׮u\,u=|FB}H.]:V-!D߸qӹQ=!g]w?vD iԧ1 e7ހrgo\9?»"pŵo"$׭ ʫPZfA'ٸju~ IQ3ב" h1aDR5\TsqV(#zXN*XJJb%6qW [qj!5#? HPj&-$HB$LZQ&[ɧT+M'R!Q%h'q~HFuYG%D*Abe;C9"QGdi#ϰMg.hIel+л0=@&v&ZNng$&ˡGGw~?"w!Mm <t"YDʯJ _Ȼ~ɖ-ôn#;OaS,%{{7n!;L+kH-}r<%zZ*)).?\»9W)ȏ%/o %/OmUϥtt=9*KvV.CI$gJQ8]vrUC\uPաa`ʣҭft++y5vP= 0~?L'.`q=eZYǛysdbSTudt}QJ;e+9rtY)Գ3ϿbgXYZpkm Yo׸&(i5hJ )kȒɘ90$ DCŀ"| T*U$UJy2Qw)S%n͠׫$;t9t#oUgE2pk.tg_s~-CTBԒ^GlXM1xup0+8H$rֶNvKҔpA>W5t;p$Q/)F® hF -`B}V{a d2}=2+Ksۈ!0v!X |c˗_1k_S2NM vjEyR[:7UqG% |lk n A%VʳH4F<imNA3 Y&Qjod44I6T02Ҕ:n\QVnD01ʍOH;xK~P8vĆOFbhȣ\|R\L7iW^`Nz{fef'қmOa&/[yK'sx>[.%dZ: ٷy0aZX31NOAU\ OF吥H, , SaɰF`SYQW K;I^C?,7(sx-:7ԃVUq[v(vx0V1pit'X > $O#\Hj+wtsgEoYq2+J͉Ts/uuW/ʛf͞iˍWVkOe{vϸFGy;ޓ7/aV aM}z |oۂƠ#W*TH2km8<8h~LʈX\qW%z+@ iDgZ[ښp%lZs={w^ۘT~,}y&1Q6˃AW]tur/Ԁf"Xܾ`C'{evΡT2EݪpmSKZنb9EchDtJISس~:+jH5ȅAq?z+:JRo{(Z} h"x~4x8VLJGcA>PC_h^sBp -o,R$۬D)'L[˄уeOg;Y#kٛcĐi7JvTҢsKw6s*/L2 ߓwc˜#|@y)&vvA1& q 6y~Cu=l zj` L7>| 8vhvxӃC1-t #1僑U4_ct_ ݦD~n/ڻ2N,/tdbxc=LYcs \gMȖ No)[KK^2MU˼HڞOdzj&cS5ܥ֐WK A">Dk|~hh ˠa_%A)bLkQ:%AhOqej?g/4mT,֋5Ĺ}=l#g{Y19{S^[O?C<)*R>VR]`8\2$H[XJRf*W^%&Zr9*Qєެo j4s#<)STɱk,BD̝N[bA_sbAAWA=Ȱq _, kQy_y-QA(k<|Zak -mnT -rzkm= u= huуn_ruԢ%AzC9s׹C;?vNV=ւsAn:vppi'9V. Ю܆JP0 4݅>^x,ӹ{d_*<L¨ Cr9)%*,&آ9ۨ o6J+AJi.ը 2@:WTEX'u~;#ϳ jA@D\KM&Xl1Hz]7ot]r[GgLݸK?mzq)os /sz̈́;'uUvw%8 L{Cڤ?ՠH6yf{B nL~143U1.{jcVwKM[]0m6C7LoGBX >*WHK|ǎ"?Hw6 5֕t?rH',wX{*"ܻNrqį]TfRNlOq>&K ZD\|]kGxֺ{IgЄ[!mԴTM-FhpCMx~hv-._p/)3 19}1HdLu! 2W/2BGspdXqeKNhś)E\ 2v;L_L'g+  :kk6TOt&aN+g.XȻ6..D1F?+vBHwґ^)cx.sXڗ/mk8 kv4Α }(zY.{+}窪h&z2]''Z4N-^AdjD4 ¢8#ȠK٤r*UK>:NNUX oń\{o_-#7~ePC+\9=^וჟ(Ml44pSLKRʋ Ng_NQko؊[2ޖ&}kE$Җ{]K[1뚚bc$˽E"xfO`Y!; GzNٜNjҼYéTD>V7OŸ]ql.\VMH*R'[ϦNؔSb<m;Yf!SL$Wm4% 5ĽYa~/hXt+ko+9 #VTj驎sAZ|qಭx#6.P>qڶ\.Ջ٬}=hkܻ}{!n</HTpRͤq@(&|,GbF&&Fp"c"[\E`,S_"{Մ kK ͆s5=g;ϭX|̉ۜ;Zٯ-jZvZ.swQgs}Zz"ֺy5hD` l$Wyh!Wfpq4t1?, dbWZ7q}Ѭp=F߆w5b )v+ZDymWM&xKK5zF[|#"x*d[RwPnU!KlE肪'XJvc|{:gxKfy2Q*։ҙZc(VrneNo FÓj{s9dذP5E[q+ j|r5NEy0xNAedൺ I0a0RtH-"7@UPL{8x^|K۸կ5{asN+^Гi]ʰ%ȍ3u^=ѴNAXD/V(v}$ǩ6s:Z+ۂ5ТאVY>ēMV)<]CtJe[t 5Sb2|¦$fn@ϫҋ, qdR܉0g{s׈ #յ- Yg.Ps6W"Pܶ%or.ƦBeU$h=m_s6aCE454`6dєkͰt0ƃ @:w)vޙ^7_ӧ|L:9)6o2^Ĵ\RPGT-J}o+bׅڛ|uUG,dϾvuLR\e.WwJ_YP=-fӪ.Ŭ/Ui+lp; 1Ӻe3{'m71w_+=Ip{H$A7+" l#LA=c3jK= |Tɪ=hyQk4Vb_忈|gB39\J⚏kod|pʓpu*g/GK6gZwZ sqJ5;6;Ou ݸ8;6a*>M^jGܵ"Mds3r|\]]hvk7te7^?WlyC}C㿛6 i髴Vk-h؊ηq2KBԮD4{8.)dc3qL%` 6 Rr |'֟gDF*c"n )&vRT!""j3>7=}p}(c"*dbas(Nw=q;"=*fKaΉ@6x7-y2Fҁ~]&w ߢp9 u1yF^&2 #xQu@oW*`? ;ű=/`J s}ύq?[5ai|#;iA_5 )ɿQÐrp#\z?'|oǝG>!_Y+\xy Qs1^Pyif~/(]NHS6t->8<צ6["]i 2ou"Ykᵢ|R&,2|CDDEЕ*Xx"?_WV8%t'TO@JA^.jO<fa4*2dKqr55tHAC;CgxAs!re\,IB"-~yN.SX9^;EyβuFB3¶HagJ; 3aL^q襭gxCT<K!'͂38 K_s?ނ᫱Q!) Ik}]?|\^ IY#j<9#J<*;k)5. c> endobj 112 0 obj [ 600 0 600 0 0 0 0 0 600 600 0 0 600 0 600 600 0 0 0 0 0 0 0 0 0 0 0 600 0 600 0 0 0 600 600 600 600 600 600 600 600 600 0 0 0 600 600 600 0 0 600 600 600 600 0 0 0 0 0 0 0 0 0 0 0 600 600 600 600 600 600 600 600 600 0 600 600 600 600 600 600 0 600 600 600 600 600 600 ] endobj 108 0 obj << /Type /Font /Subtype /TrueType /BaseFont /MAAAAA+Courier-Bold /FontDescriptor 109 0 R /Widths 112 0 R /FirstChar 32 /LastChar 119 /Encoding /MacRomanEncoding >> endobj 116 0 obj 2688 endobj 115 0 obj << /Length 116 0 R /Length1 4972 /Filter /FlateDecode >> stream xW{pT}nH yG Bɲ솄 pAwlLb@3 Vh)al2*>PG[탎wn8{w~wM!FDI"yZ#mYhWc>gĖZjZ5lZyU+B?}:7$_kτ%Iw+G4ZhYSht.t[k6G4sS#ћVo:֣knPz;춵Ѷܻ l ?dCGn(M~rNʔ&Bd6QZ/3zyKgSmtKk^zM6oTE/2|o~.8xw0r-m2JhGOLdAf7KhCG ]SYbϫfyP!8u`mTtc=l4;@5hX;#35i\ǪaI?C#h} ,ngl'%x{i<+Gi z>gN1Ml5.Nԁ#qfcSaYH BS8$^]#yi,l_klgKp'Et+E6hGpjYzj t> ưL6-D[nd cNXX' $!]/LjZU:,1_\ =/)^/Ht4N/U6Uڃ^gsErS"oW7mm;lq'O*6 gP_?Si51?8,B1TW=|QJ(Nݨ=+ig ҂KG.!=4U4ؼyy9ٞIڵnU蚐͸WIOdIgu)[+//!r!0 U>/װH/"&"Y:fM_kV,BB~ΒZ< ۍ jWuVzYGc,^/H.*84/щGL34@^^ l0- b&8ikjVRmKA]t!s5>~ί!)".x"X o\ s- ZePPgAp@FnV$ͧ5ƚ ̀t3RTX{c۹q`k}|tn<% _IN]vEgPnxbfԌeOEDnǓ22¾ñY8)ħij<sD-6OyN~ЉZYdHZ#?LkEYOu5A%U2 H y5>Bݐ+T˰2^+jLU2$yh,4 -ŊPVBBg2σ)y0F4+M)ĩdWNp (߾އ U@ sq>dAb ,_SUPm鈶7ExV+Q~EŒU^> `:"5} #RB:mK12o,8S f٧|8ˠQteGQd8{Ia [^.ӝע:@mf@|T+$0'&JQqA!r2ǐ0<3wڧurЀ`"*\-ΉW~2<80ԣJknW6Cqe&˽)ne29p0E*%%e&"LER7]ک̂k+3 8;R>,PAv+f6N/ݝWɫR>^ Wmϲuq9r:`*CC6S0Jax!810u3`zP2 Y`QtثH\,GYbCnh51sg> endobj 117 0 obj [ 278 ] endobj 113 0 obj << /Type /Font /Subtype /TrueType /BaseFont /GAAAAA+Helvetica /FontDescriptor 114 0 R /Widths 117 0 R /FirstChar 32 /LastChar 32 /Encoding /MacRomanEncoding >> endobj 121 0 obj 2722 endobj 120 0 obj << /Length 121 0 R /Length1 5012 /Filter /FlateDecode >> stream xW pT{Bn !1 a1MԢ7TY`ю2r [ 8-:iʇj@>E0?uiзM%_4Qk`7쁃zT00򻡊|^89Xpn(hzA؋<lv<<r!Ohx i`T=ͭ6rsrg $l7l5=|3B1,Z>*X {a `+$$L| Op=<?/kB79:6 >7 0YX)S;ip:SUڡ\e 5 JQ ` 6lgYBTEp&\@+6gKc&Hk[R1(yΖ'v9OAI.'(0%VaAhcۣ4& 55~;n*.hU+yS5d. ]u0B-apkQKZ!X`$e>- ŧRi [)9'Nj-l:&]z0NAnW rU1{ PwI幅) P5HA wV"dkj;CU"6q_PԌRBquL<#Y(D",g_HFz j2l İ撐 e; 0Ngb0 Mঙvpubxh.HG0\L3Kn÷` %pHЖ _'+FQ1N 0Õ7#^E 6BHg:1x4 / #0W3knõ#]nYOhtKGb؟@:a38_0̀tN}n&(UCAϘ3CWJѥc6%<|zqנ+U6GpP[`:4n,3„St:sco΂k0A@XM/Stef7N/̌ bo7{ bX8MLͦlS)ǔen6e&'S$l4 f I1%I&{ 8ꛌ$fnN,M(M-t+=L}U=SYQcg@o[=ֶD-GjyX2/UϻV5sװZլV5U<*]Kh endstream endobj 119 0 obj << /Type /FontDescriptor /Ascent 770 /CapHeight 731 /Descent -230 /Flags 32 /FontBBox [-1018 -481 1436 1159] /FontName /FAAAAA+Helvetica-Bold /ItalicAngle 0 /StemV 149 /MaxWidth 1500 /StemH 124 /XHeight 540 /FontFile2 120 0 R >> endobj 122 0 obj [ 278 ] endobj 118 0 obj << /Type /Font /Subtype /TrueType /BaseFont /FAAAAA+Helvetica-Bold /FontDescriptor 119 0 R /Widths 122 0 R /FirstChar 32 /LastChar 32 /Encoding /MacRomanEncoding >> endobj 126 0 obj 2735 endobj 125 0 obj << /Length 126 0 R /Length1 5020 /Filter /FlateDecode >> stream xW pT{Bn{IHKxl塻IL 1R0 TYXT ldt2J21VHuxX0ݰa2S{@H.Ail  ,Ɵ^~Gۛ/ h]cE>͡`ӷ;>%y̐ظK;:1t&ܺ1sEۂΓ^G:z]A5?"0@FB-+I'ɆؓFꔃY lx\`}@C&jS7!AxBSY?~'`6E 0hlxCRa+ d)-eedW[uR)ʅ*XG>A30?uiӷMzhNx^ dJ{ h2{P(tkGG= .c~N3cIjl8 ڻy|dC!,>JX wý MzB{c&a.XN\ |ȉrT~n p}w~V,7 )JScC5Mu(mVr q}D ]8oOB͎p.Vc !l6w½xP A g\2.ȭ ;wt~y;?w|-҅]:!,vn2jXjh745S!ϕy*1O%IRGԣnY:mx,v r&6M[ 4(ܧAXz٭^ϭ?G.T`(\*D:SL >DZeDi~ c}EH0K`Z29*@C/zۯIQRtn()}RW)v놘rcv? G>&Y󂬒`R#!.\ ͅp\?W*G[OW jW0`{*wĒo?NG HI>GZcz`l[HqNG6[f|R.[=H''+ (X}=mG`oZT vrr3^ʥfRB.i"a>|vUŇ!Pap)wrվNSHM_Si5#ocIgdXZA)0Yj8fEܠ \=Q쪦X=dl'X~l7P\)2ި3; F8 ykM#.2%qR!%:åW0<T HG0!npcx+8ny3]3\y^48 B׎ {pm7#:W%aQ1#0K.af@A:L7P+vF?d! xKM6eȚSuh`QU٢IEPR4XəԻ?5|8*x/MٺbwD|.ʿ}>x,hߤZӫսQnA͑!6P *cVq@+bzD\2tDTbbotg:i S2QDw>]t:nK졊iَyQ<`2:&3_g6K![Eq[DHbZ~z?L{3+27QϣN>uӴd76嘲L&Siy9<ΜhN0F``>VrؾdLb(h d Q#lZ28n s~|hSӁKk@ TF޵޵'gv ]IWI9Mc`H]+I-x˦i%:_%x/;{=U#jmתD-KVjUqժbլVUjU+zOKmRp endstream endobj 124 0 obj << /Type /FontDescriptor /Ascent 770 /CapHeight 731 /Descent -230 /Flags 96 /FontBBox [-1001 -481 1589 1175] /FontName /LAAAAA+Helvetica-BoldOblique /ItalicAngle -12 /StemV 0 /MaxWidth 1500 /XHeight 540 /FontFile2 125 0 R >> endobj 127 0 obj [ 278 ] endobj 123 0 obj << /Type /Font /Subtype /TrueType /BaseFont /LAAAAA+Helvetica-BoldOblique /FontDescriptor 124 0 R /Widths 127 0 R /FirstChar 32 /LastChar 32 /Encoding /MacRomanEncoding >> endobj 131 0 obj 17843 endobj 130 0 obj << /Length 131 0 R /Length1 23816 /Filter /FlateDecode >> stream x |T?|>w̒mf2a,$$Dr-BBD HLPAPD ZT ʐP j$VTԦP 3 ~ws]νvgCH8lk8>uɮ!Qq|K'ԯ Ƿ,꘳y1'Ј8G'~6*&]lFdE={dXmv%J`fVvNn(_@ Ecq2\_w_?MI$ɒ I!Φ5ĵ䵩Xv:&.9Id !{4FG4'a*TNULS_Md:D/H/D7v 5L3Rϐ)K I#^yȔ;SĎ;o'^2u|=UrIzvX9N>4595#ukꗩ]?'1;j2nGVϑ"G3p6E+Dz1^K;}t-}>D_fb5]l;G*ʥ:ittt\I&y|\>&bzLy%IYRTn,5?u$7\<<=C^D j19~KNS/ dz5ފ^|>Bi}Eҿз{w'=8 cqf {e}\x)|gA)C M_Oe"kGΗ=yfP ە;'UR}jzz[o&)ϴѴ (Ay3kd 6Ut*5xYVjgGZcψ;j R"ir)u_6J:,DOF|7Ob>NS;:#>YX>/]l&UJ]齚TF#r9ȅr!RC' msi&)}Rb>j+v /7rr$I'$,mKq&2A齼M^.Hsat1Hi8u6qIi/%?^$,6$B[Wӗ&g*_G6w79H-,J?d:SZ^Bs!yRrO2* SRiNȥb /!/^Drl6Zb0GȐa yQ\}|(iTE͏?}?PAʡ3KGRAݜ?etyIޭ$SC!ׯ#:~ m"/룧5#/qaC*T.+-) , C9Yߗ]aY-fGem ' Ra8o6N>D["ScZ&ƥQr%s%AF o{)3ڼp؟dKƁՆ-\dޚAt2&oK bŮ{ ޢ?;_7|+#&;ژ̫Kp+ f_h26+i.cȻO̰gIh!'hxlBk6["Aӣλ'u\edɉF'?m \kc!֬mZޚǬYTA{cmFSqFFoͣlg'z.XcF77߀#ЪU03 (,'ŀw 'Ut\D>v.W?~f/Hp6/>d⬫@y/g7z,UȺcT¦i3f;0W^ۮڜ=4[,RjiZ[$KPEt%=N%Dl;ta`E`m |z&GFBYaC!+Ս}FZ3Ktugg`c`g0[ډ.Ù`_p菉-gZ>oA6fWvWuKi{MwQO*\i- xLlH2Ѥ*LV٫fe Κ$xsĠ]7)=6VWQ= JL8k-!V^&ݮ;Y7/24KĬEV^ xPS->c' (;B' _ iUmĈUH]3s6LͲ$ oiΩ=+|_HK?8LH 4}4u3*"gM؞tA)r0&MLYǤ5j+qOQ(ZMP(D#GѢp"VZP(S$rrq  Db71Q&ZjZhb7%v9E1~IB,_wʈĕ'tPVT`ؖS-vנ#`nMSeB )Hy@ha$Cz?/D+F]nWK?V rWy/[;-Ι.$;]Y=lM9-vĄVAJ\N+0.4Pݡ;%qK;^npN 4|mَQhp:s'}Ka須8ĩᒙ-)ktVg -sssr_6m*,%;0z-z ckLY!yaί(raŀt-kN>z,m/oy'-Lo{Ĵ?Z:G+?|鷉=. <_H<3@Jw{zhg!YkivDNsOl4H^ ˋaVYr%ᒒmw?=|ӜC"ܷ㺾/ZaSGNTUJ |*UudaK:H,AQBrRS)acLf.> $ܾVc;hTĮަ[@/18{AEA52ihi;li]{>;&95?r>) 0i4K5eU1 wLvLvLӧ1mzDKM̒ Qcj꧁nA+*4P4`og{`eJҋ0̬! oF[AgsFZ!!gMdU~hƓg:!0\%,vftU"h*KjZ&v!.yXT}j3@fJ\3jXȠżV~JuRVC}^S;[rVu9a1^nBӧAVwiG4r}46y N(9CU/Riܙw')^†.?'fkϴ;ϼΪ~ O"SL~UZ@ xX U_(4~(/I䧸q?D$.hc)-'0bF^"i7HÒ"e60E~n;ONZP@L CgW/8 ם\ ٯry`?H*^͒leFݜL@+zܜBC<*Ӻl#B1 ;7-;[&kI0:j 3*+,|V`XpB| ъБo`zYw'׬?'%U``M')6=r^ZzS~ڇ]Yy^13珐@_~/\jO5m>t;g' 4z(᠎`Z!VGy4/"@0Cw`>Q6B@p.F@r  5E%mVk:@#A`L6r78kiyzK y>1FV'j\i < sI766;9kG=}Y, XۄH}k֭sB ᕃ%s3BU&YcsИ>}W > HO 9(;1C>Rؔg}mR93gH$ ^=6u%)۷~U3U(jx 26-A k`0Ur@P#rӖ\r!] jδąoD V{i)Z_XX9E㢘("B]QU|3- c'ˑd{8LԘȧPGLB=fٲ6KK0fmm\F[–qKCrA+F_O2W6_\#Fp %S:ʡ_:jZ\UXP4C1^@iŲM.D\mvQw!# B% }>v٫Q?;Vm @`0&owW4w5Fi/k\?F 8|?CyH1"@4"<9UrPS/xQRb;t:#J5ӧ7ݕy[֝kdĕ0Vڬ ՙwGwd0B/HK+GKV,=Yfw7o /d~ lC8wcz]XO Ii_;JgHK ~KjDu3r$q8ozz+RUX^9n!AH-;[*b.K߾U8aR3F`j>p']^<|gW? /Y|QU2/,b>g"ˡo>7S/)O q1.@Hdhx%~1> {b:=tɫ,r׏}t3+Tk>QC/-Ib{MC}yGY4³M1`'7LkUo?4jRŭQi\\-T [oRot[U1ݦM-XT~P7}1Dwv顫B);L׆i~n#eД*G5ih`Fmpm H.WjZn~3'A4e-L2_}+o#1"$q,rjf&pw?CQ"6,8$wM9B+G[rnI(xϖ0A>w SԖZ9}dN_sG[i//=b^fx *:SFM_ ˞<Ae їGX?vs8hoetSX_+XQ.zhP 8Dh;J| {k -3ҡ3WݷʫxdMOszɂ8XxؠH~?.:l9/No_޾æ,v'b&gӠL7?2síz%m&Wp[3?cU*[*si mz2M;-OMlO9v=~*sems/KC=!_i_JL :\Xb ׶T捩]Ya1w:J5C ;~ɲV0~`|0`K^:gsV@ώU~YEW`75ƛ ͆FoH~8tMm˾-ɝǏV EcQlU9zW &M<~lU5axiވfQac$#Fޤn1*{CJJ<)O.5W)U4yҼNY><vt[` a21nSq!LLLPE suI^;4V\vqK!>*N6T`;3qrNx§Ld1tDuaC/[3&ŌO`+FpqI?3{]n9f|#C@ИRoRf+WѮe_M&yk{(=>VwVz8.s2w8{o>϶^k?I$u g\67PB'g9%j')Y?DsҕN*Epr)"zX4Mnq,Lº3 ncvA6M~C.2;F1Bgq"cn XD8Ut@?=.JK^^ryq]FgYrEӊpk&u6$0W7+=ǀmi6,{<.KL K8>uKwozz~~?ST4}'|o:e2Y 3VXdEİ$#J21~X -^YFAV4EDbNXdI jSC2]+dFf[MmoFJd8݉E\0sqHQ"`oy:9 RL+Wh@ǬakP%"*aͰF9@| CZL30jh/P*$FOc 'ezU3׿OAG1o=}Q>(ba \8TWF{>G;9T /4ƛRPpRڳ?+ch@!wFMY^A~ ;)T]U9xٱ),5Rdz=t#{C^XS[,8 Y9 CI U5:9=.k\4tUNOM'Ox2ksmnv}dm?rG>}?9;Jо"/bߓFE0X:f*Wcс)ERLm] +LpLNmRY&d9#Lί4׷7&=o{Ok2m<XI˓v?2^ H߳|zsZ٧[8Jl6'12hYhs"R*(֪U()E" +`@7_K;Y@PQY$CJv{4)'(,r1T-kjJnO~h/_zYKg˖4v@mEik̇dr7/pV]sւYd=CC'ǻ!E#GMIvg{?ث}uޫ|K:,:6 J `O  @)fT[kJXI]i@h 0]a&vmbn+@P1ގ@# 8nLw?6W3/>Q?47{.7rxYӸ;whZ5Q*\0~G3g3}ձKW)Hv&xI>[ Xey/!D߆o K]CtkkHYEC/n;G%:ATaf QGIt `!p͘5v\X٨PM)cNwUڦD}[3fxX}S`*o3G! N놀"8б!,_e뢃&><-6V ?ڱhn>W>h'"=U"4c xV>[.]nehQVtOclO}:7o0|%K%~tt V;*o>>?"a Gܓ U1+.C:jվ W\zE: W$`zMO <L]ҵ2~iiyh^XTWjʀ`4<07g(L氖*( ( F^D&Vx(Y q5aq4G% !V$4DBRD=Vכ Dʛ*JvYL f+}s@Oa%|{|<ɾ" Zoߑ9roH@X 'KNpHTLCUF,CY%LEaVǪ0wcIRYg{I[%Z'N~hMA3ג$,sE w7>cȗNȗR!j>Q z''yeee@GXg,ވ)n ɦLk&-Z0kXKS]ssW׻r"^eφ2n'WQ3<r@Rߒ@>tCr$ċJ r嶨 k &pp(vpsswf"R>BD`O`@ʰ& pEȲLƨ=Ԁ茵8' XiJ *.cN_-Uv` 1cX7OB#ZpY^:8pR{ڳKF\pȒy?|z-COɇ_|~Bbg^ӛMP`K,@ӼѸ\A'1tJ27?l~4I[b"v]BY&f O?%z& );6IG=H`ZyJk9B\ no/s;k M:ἵQiC³"=@ll7uj,p ҖƐ F "b _;4>nvP _O`ygj"sLT~G>TǤu],ؿ^pҴJnoGZ e6fD#*f~[Z 87K& e.\gq0A{>E;qqB{LXFI"0 QPĒ6ER Y9:`Vf7ŏ!1YQXL)F _ڔfH;Si=f16I؞v7}ҏ 9kTmȫQ)U _8L*&bw$yMy_'fu{?/_J*0=.>ϝ-KeULn65b_m^z46PJ>Tmj E'+Tc^Dq~5/՜nJJKr˨*eh0iQY` vFTiGѣѧU}Dz/˼w+iz!Z4o݃CŻ n}R>O(s9O(6* ( W^9+!W6ہrYeYk}"iO1!L.rimjYO1}.OҲ3>Ҏw\9fc;~qN+t-'zzn~ywdU$BH`>N|m<kyfbJ![SPW7tUW=[(Gms|Rwiw'uMH6]3ٜbVV7[Q|Yt l"$V\gn: q=h cƔ' Hq̨ԄJ ݥy46AZtI.=奣"|".M{bacH25"5 !m@JeD&v.7;VqqxTWl);QZ{GjKUީa|=bTFǸ}DtF6HHǑ0ZDڈ7p_'T׍2c2O~_6"1^ګl[e[-*۠lPYҠ2?G@Ahh+GI+=H)$ ҂@B(!$qi-H&| wb[$ʴ"@J!b84U2 L%(-a qOh> _*Y%fWdA7~vgٝ}bGh#Jq ;|I֟ؐ eb< Nge4tV"̟|,#yә'ә=ҙUdݱDӕ+MW&L4]h2teDӕ+MW&L4]h2teDӕ+MW&O X%F:{=Ogt+..R!ˑ ! ŐH^u@d#yQf~!Yi-īÑPhvuXwv[v#s܎箭*߉nt6-]β(WHo#-Ei:EHc.DD EaXEE:I' hJ_ #~?ew1|޽*>O0ZCña_ %8㥸uI"< [2J_quAМح(ZcZjkPp4m{/qx/#UdBnC*sYvB@U;sT a,&Zo\O"[D lvxfC =^/QSM[.,&\A/'N]C-Sf&4'SGlu%Sg wf{X¤4xϳ13vBF]L|Kj5걵˦8V+:o\l[ Ux80XWDI4'8P`/;nkztQqv9L$,ʑdcϤ!W+ !\(QNڭ(G|h̓⯁6>]+(mi6=ŖPPLEuA$pKN, d> endobj 132 0 obj [ 278 0 0 0 0 0 0 0 0 0 0 0 0 0 278 0 0 556 556 556 556 556 0 0 0 0 0 0 0 0 0 0 0 722 722 722 722 667 611 0 722 0 0 0 611 0 0 778 0 0 722 667 611 722 0 944 0 0 0 0 0 0 0 0 0 556 611 556 611 556 333 611 611 278 278 556 278 889 611 611 611 0 389 556 333 611 556 778 0 556 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 556 ] endobj 128 0 obj << /Type /Font /Subtype /TrueType /BaseFont /EAAAAA+Arial-BoldItalicMT /FontDescriptor 129 0 R /Widths 132 0 R /FirstChar 32 /LastChar 208 /Encoding /MacRomanEncoding >> endobj 136 0 obj 15425 endobj 135 0 obj << /Length 136 0 R /Length1 21032 /Filter /FlateDecode >> stream x |TE7\Uw}߳tw:,MLH:@$7D a5#AA\YUpTĕ# :t1ꌎȸ :Θg}ddAD%߿nԙyIέSNsn%j"+uS9Cxkm(/>eыN"]~]rOMXS٢|g!c"d8Vj]}9W,x+?HR׀+]۩+^4#]{#݋tA璫 !=Υ ;1c! Bo"L~ "r0zHQG`B0#xHV%\D <!()ul-$bdLH-N8d_`9$yߡSO 72HEfԁ=d&@Eԉkҟscno&/SEJdԟIυI[kh2L2߯я=)"}ԧ_H&%vqtTrb!ld168y}~qTi .чK/7NU^_r>m'=Y_O?$ёt}&Y:V0YKxANJKkM<%uzG/ROOc \yGDMgӋt=~Q7f hu [ :f7{ƾ$!O!t W8"|"Ĩx8\"Ә F0Z1VϦyl![ֱ;س=^eﲣz"BL.Lf s0eJa ({[xCxKTL8Yrz~q{|J>&=/KNKe&lLL%EJAy[]'ͦ%ysnWcΡ"b1t!uB b蛛E'GU1A[F*kJf$8@6 %w WI0y h ;ұYVfB?k=rz5yM"o30!ǘHt=Nr\tv1Bk#YlŌ>M>O﨔M4)s;6¥^;*G?$Y*cLjד[t5bt)VVمu10 i_ ,rYF3@6󩍌y `J Ǥߍ+K +1Ht JMCޢoj-LV %ObNTZ?CsnQ5#)+).*G¡`nNvVz.nZ&ASdI%#MD#!F#Ǘtd2(#BVO$Bo~RSEKImZR[:, %^oz쩭i %iIZ|7#![JЎPcE;JѽFøȸad7ҹzP-¼23c@1 -HLmml J%踋#$26aiU8<.ḧ́'0)wX{md~G̴ `ޅ aјnC{Gxc\f }CƍB? 7eM혩!nkkMd*3FqY(,xY&1A]Nj_zCgF‰Hۼ.qu=~5iI鰽6{{-֡B=SŴ<<,e)QdBBG]BOZ#HX8lx$&?mX Q<C  m"Ǿiμ5ᅜOβZ;Ob"8)8FKWtB im絍*a>zU2ꩭtJ,֖`)q%ϔEywB=gyF%P0S<=)MY0Etؖ{#tԽ*]?}vk IFٸmmP-A&;B>hJVzY$ASub!%z(>NN4XKcxyA U|OBb?kzM|ww$5.{\,⽾l":0^g}e=P9:ɱr\&gKλ9tq9f`K)F,8S:oRey*-^♋{ןhfiRS1 TLS+ֹ_u7e“N>ဴO~EeafKU3U͛l^TkYdNN`,[AT愩`؎ nn >)4?GlLǤcB{MYДyɮcf +HڝOeE~J,!ǰ ("@ Yibf)ەA X*ƘrOk+.IX|qA r:j4:jIělZgtiuӟLɰ-JwN픭nr߾ZxRxEߤcQ25Znuma}ERqoӄ^3w-]fߧ,u|}М @ˌutwJ;uOZv;,쇝7f4`{vĥ$o]a Atq"HY;`,@Ou?BK󏃏:yQ猩-݃7Nߩ㴍nwO7mmaH1=c8Ji/26=!lFA!AcSxu>1**:˳L;T "P!`oB-o&vLc>~m1= V{Y|J[rHٵߢҟJIo:y~kg;&[x/Ůbri~SzYP )E}W_::klLS>[ f@:[JEE8V:J~[9J +,^(ϦnZRnZ9=p &0Cp[G1!|[d1sy= Sm:zz] *R >+m}jrϵ vzKeOy:\;\xJѐ. X0X Wj5 *ip^C՞mS"69x5nN] 2mYT#xSSM+|w3m3m:XtVWV¡_^+nm0Z^][0)K W(R_=J 6C(Pyӑә:;Ga9nB8l+K嗽oKS[Hݱcۻ:ǫGX"m*~q85oKLNV??֙J]z pj oSt9 jCi7NNX'X/P.3^fڭidl<&KUveuFXFXϳ.\g{`V9қ5{,[$Klr&mz 6puEBa.R 3n9!G`aP<"aF v0-Z, J]X=M4TpCusX$b…Hd+[wVBMyw錋.;Nҁ)G} MSmc'΁z11O0zD=ޛa"6z76z/PZXLּ=ӻSaef^[dǥE[6gk5s.SF^{!"vuEnλ9ycs~^~4 y"F3_1oayW",o)y,ŗv` a &l:Y4%񔋀 P-pmwQ pvXZ}:qoR ,%lLgeCrֽD}RvN> ް 5zd= &5y r_M:xjuԘC<3bBA5a(C{a* t`ax2Ϡ\Ȥ-F#~zD4m}X'qURG7ta#i巧/R?eߵ YsFϺΗ.k残je\yx.ԇ5jL_.K-Nj"Sd]Wq-U  GP f[3ΐ ua!<6|)Ń\z05I#5Y|ԩhݐ藟lTG*:E F+gٶos?icl4L07C7,MSZ:άY,U՝՟%fQ!/mѥ'5f1Mh:l9L WOGTaϰYX$/gnZdtnq-*3oҕ#8ᑳt3Bt*um$ҟ,x , ڥ.Rl)5>{Bm#M /w`o~ee#=rͿe;el,'b}9_WėgMbC.m3V|_adfXͶׅ,@<˖='*&aWPAk5ãb}-hnbAMFT-ivg9l\/Kxzxrq.X;WT`+G,`i}9״&c,ˡ]m2>ߟ ځS@Lbq-<0_}2lsmK)t-,B̶渣 ӱ78,d0a~xփ?-KgЋF|_p~crm؟w4g6N֎U_߭pqOÍ5Ye1,yag-EGG;fs1~dJl8F+1xú@g.͵3! CX5NϩPO&ۺ 7X J%K|6x,hۉ%qVXG$_LU ׵ߺ҅kE'i[ޟ+ybJ=0A31:?oujYd]Xw>ve˾?}.iQjOOX!Z7w9vz;a7Uzr 8W®$yFτ5yżX^lXp܎۪BǬ"K}_w~Xk/&oAGY֯t:{tzݎcɦIVympP\t<;On2Le' b]Q)9ۚV!#ܪwܜ+uewPC- \sϊJ6 e'y+@_U+j7H uu8@qre ]=W̵ua'~cP\TO-r\+>.V7)6 5|@A0y.ф 0{ӉaŸDuYTP0f,6+˕~ i a="ɽeQ߈vbzuȃp˼ kg]X[K鴲}?bWRo4^qqrÇ tcU1%b}N|;s9ڭ\R%eWZtVfkg^*f3\sI<'カ-8ct;G:1۠Jjw~8/`b~ZW;ץ-bK/-."^w5m篂b`/\V.h}! YWU8+߽i>z5Utܜ_Nq-p;75/=}ޡia><0g =$Ƭ4}HX:g-+GgEvRtNŨ5GKrphj(?GOzay[|>;c_pNzSe>l!'b'R1ԫ)X:Mn\+5G̣=4%'ihMWU`~}|̓w;gW5lX;% y7ӈ}D uEV~S|*}72$AVp/`S5@ڡW LGEnh\ڨ2<5~qMOqspS(F1G}bCxj)G2UR72$tQΚZ__hag!Jp܆^HGb`-V[B\# QkBBYt}G?w*;LϙG-X,xҫBI J äAᚿ+*60+;;ZlEvuvU.yzYj dEs$v\y0zDBǪP~jZP_/TG/+|BZ,\](PayaP,5Æ*_ P _W $gҦ1evϜ@ϥp%-cΰj?9rɫ1 /Z؅+Nԧu#>w=9cs/l6>rNM[S5=8{XӚO?ks!U:ge+R̖A`&ڂ+l21m@-X1jë8 nM8dO-KWpq2DfmOLXKj`J>pd˚d*(Fzvܢ57`)`N^j:37n~ɯgmYY6}lMwWܩgfNot/ H.Qq(N`Z'jwxќ¥~袋}"mH%p D ~$m|4z˟HC[{j+˻S|Kkһٵ]x7xmPdPcqƳ Άov;TaNyN[,֨ͦ)&Qt gbiG|ڏo~1|CW=gMT|>RZ7O${d-k/t=&eAϩ{M3?zzgcRBKH%jYdt4ͦՙH/[+ 8\`mr8D}`curqqRFV9Ȩ^G3t }?)^a+'EiNx7'pAnb$& DFђ:.8}7T}}N?0r c,a/] vodc{K}WGNO{9v4oAtckmޭhdhbm 40Zm saU"$>3"J~:jӵ//Y^Sޒg󞍘W}!'&cdY%S*S7g6{7L XlbE6[4T ㏫egB{WVKd7?'7zq- 5OY\n#Uyr8dUI%Z{ua 9v t5=Nqi<ӢVAMJI?1W0!OO's] :0NQ$Q'A?dގnEDdwXv+pA!+w4MBSAkq[+H]iz(e}ӦͿlc>ٱqgU08%Y T{F޿IpAjؠdF\$0g,A W%z(dCU c\ S{K k1[*&;1wjo鉎'Q#0xbM؈FFFFtj#PuʄIlA؎8g+w/))r=z /pj|=&KEaj2az%m(p:`D]ç䰐 BpIw0QD32nN${O7J_t?;YMx\'1H/}#uG^X x M&>XR2V6  EYC^g)'y2|dϱ*ϊ _C~.zޅDR`OR$ɤZʂ3)@_$>i,tأ@n|O Hd5ɖPwj@-Uw;PA4T;!@3_|ȶ r8=*!)V'1&>.FV٭:bOǵXLA`xJUn]p7i9[Ҥ% N`tS-wSF0:ѡat0x;ѡa-h0Z`h-hFC UPCaPj(F905r`F90ʁQaF! #0Bi!`0l a 6`4 0li04` c01V(Gr(G4#@9#@9:'g~n?p~ 5ۯ&F #0Hh `$0 n`tkF705n`t[--`l`l0c 0hSn)*-*Wdo hzR$AL&zDK#AxAbo !BUyUOc5i20:,,da9@op d`sXTOI?B/2d Rd9st&tu:cNǸyzZ28 զ&da.AC(-Ɨ"agZ$Q;/uO<#Z$yZA꣭"Uc_ap Q?5>dw&8|.`CA <'xgiw&[S3:X\VQ`{ x7ImeO 0d]l ^T!N_27 N.=){Z@ߒ άvD9lQ(cJDSrťsl: >2t:Y'꘎K;Y QFcisbfeƆ>fᠭOdi<_lhCjf BPM7x5ȓ(S/ t sz9ՋZ=z{|:- ?n( V^FBZNJRP}ڋTk,QC*UgTim hUtuΐ.=×|#Ҹ#EޕygFcŋ80> endobj 137 0 obj [ 278 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 556 556 556 556 556 556 556 0 0 0 0 0 0 0 0 0 0 0 722 0 667 0 778 0 278 0 722 0 0 0 778 0 0 722 667 611 722 0 0 0 0 0 0 0 0 0 0 0 556 611 556 611 556 333 611 611 278 0 0 278 889 611 611 611 0 389 556 333 611 556 0 556 556 ] endobj 133 0 obj << /Type /Font /Subtype /TrueType /BaseFont /DAAAAA+Arial-BoldMT /FontDescriptor 134 0 R /Widths 137 0 R /FirstChar 32 /LastChar 121 /Encoding /MacRomanEncoding >> endobj 141 0 obj 15895 endobj 140 0 obj << /Length 141 0 R /Length1 22392 /Filter /FlateDecode >> stream x| |TǾw>dwMI "@HM0A"A@ > U࣊Z?R>(ZmZQg); bޝ339K(!JڈDy箤3J^Cxe޺5Goz!kV.\K+% !ʧ ]3<!2E r}rrc7!,ZfB~Dzcw!?a+$^;w#_+W~!y/G~ V&ޘxNB,2D%<%JDX_ DU ǎWb&Y&v qq!^4? 0r$D1\=DAIhK2"i^S1ڣ"\]Vs{Oe$y(mߣo6=&P~Ja.z}YN"ϐQF+"zLO zb3RHZ^c*ߪܮܩm=e2xѳ8y I7P m7⸅ESw9AF?ү|q]~bq`/%/!R$Smv/U \ܫTv+(/(gU{Fb|z{%[zm9& Nű}/(nwAZLGˁ9t ]EOųޤm,,6fq\Ulu7WAH)G*Iitt^ޑ&rDΗrJ'ϑ*WU\]T0000ln8`x|'ρ/)iT''wr9~~ zCK([ʹ(lDI%g#N'KU4jE-F~+Wj%픰*_I*y[:I #ϲh7{R*L7ɪFr(.$I)H29tlȴC(r.]4@B<> <~oI:uB";sHyU~L'5m? a'W 4z)0^"当Xi%{L%Nd|<(6(?o.RGkm_hIh5XGjN:kj#jMt' xmc1/iK.=vݢu-K^yL|lhWTW7|/#Fkҁ8NeD)SjCX43/~uG)фIcq4zC-ںS#WnLKsq3֦}7]c7_\Gy[7Gӻ6^tn(ƯԄk\۲u,n #U?=MMi ^e ^KZDӦKZ04i2X{0̜"X&o[![]/G߭XWsf@zN@9],O,E$qi #[ DqVz>Fdq4e64$xt? ( wK ퟄWr:@ji:NRbN"1S\#xC]viB eb!IԂ(gϺFkZN i0*E Mk-q9Y~H=᩾>vzwy,ľ>1㤏1 q\/[bΘ3b&*u}+k ufI~VM̬z P]%?r?on&5݃)9t1~n5JEtSn֙9t Sݤim^΃hpF2_lW5s^IⴜƥIB ߱wy?6?\j,=[f{^wם\&H E1u$2FeŢ65Vm&uqpjUբzM8ϛk2]ypn0?Z5ڙ@/w88*ǽjW1W=5ϰy;+,͋(PcTw U,:95b6g,!DfblQoPSTW:07Xv,$㐵e#,kn~E/^q؄{tU1ѶgCM\Dyᶅ{[KӜk&^b׻ aKNLDa}yDSg4n7PH231E6-CVR.O~4WOjxp4s`Nprk;߼=SC%3*?u'Z UF7uI$A0Q<SM& QIB [qZ |-[Ȏ?n+ɨ5^`$]LZ}ϧl5HS|s^+C`8TkRK$#IcfPoˍCc;j@._IhQQ)#"iRZVGfTFNLtH©L 0_K./Z.g˷ޝ?Vlzذ͔}#YhϩխUzv,᠕m6yΣ_ͭN|t#H"t~߰K+DZ^MʦEikCؗ<͍U wKg"q\46+,GGQ3F *f!l& )3X3K] KI+])EV&yeF1 ݮ[-(# ?f 19usJS2Q6Vcc asğ5e@9:YaZCf 4#X"jH4o%*P^*Իꪌ*YTq4O̩S 0]9EDȩ(/?QC{srg{>Wbdd;+z4' dY=%$?;`.|>=ب4sܳ|s3Wϴ@$,dš+d)Y!| TU2+=!ؖKsI>Ҫ Lց~ 6ORgUy[#2ٕaBTj8+<2nC_c=pxݿo}Bӟӿݵ7t8}1/l% K=^\]-w \<ŧs*!9b&/l's_nb1'`b~ g{>}w ͗ݵ{{z~&mfߚ#(P;A,G/'͓[5("UH.ϭ-.5f^Qt*0'~ $~wزg4h|^ْ@*L uTku3 e%k< [nY[[К]jöq={ucIW(4%$!.lp 4^#B m`^a&/򼒠ʓfL& 6>G& Q5'40+nEK4SYIwPvҴox $@pƲYs7 X>Ѥ fa g"fpn S@@o"W4Bytȉ?tv)BU%p2a6WAa29BW+cye+UOO2{Dﲩv٧ҏT o5p?u?ojuںqTc Vr6{㕓˗ؿn5A̡cXg CZEVsjRJhS x}:B|oS7 +W4y)O7',Kr"7WRl>?22!sF#-dT؊lCs*CË/+n5/-.nve~qFpD狎>"c5qNwrImC_ğ*)J.Ǘ461.NnleYYaVZP+ysK5]ic.٭svN`p]A|W`zA! ea2`6BiJ =>#dUS:*N sbz>jC*dWB$d49('TACL+UuU]U Δs(~E_Ÿ_ZpD=Z2. =t &? {#ăMWCSjz y9ӝ> (%)ɪ fV F%6F^,yxxRR vL^oK:~ҷ-M=qǖh&_+f-_d c4i$,Hxi*;.YM[|uoMGɥmT: !JDB숨˃f[{UpqmZ[ַ}oISL$UJAJCW.wLQQfrH(9'l NXf--6xYZblSy^GԲ:ˉ ?" \J0E!w4=KI+7z.'0* 8Pah 7[SPb 䍫\t[xo!9A¦ɼš(E@#B сOv{Uz8U4|~vϠBs~OG<ꉗ9#uCf>we}:,F+aɮXy1y ̠#!T~2 .P}J#11wAqh euuyn}I9 A!f {)m&p`˅g Fn{~+"o RN/>>ŨŨ\)8nC `v` B* Z RݫEΪR4bv5Qo.0򱓪~{;KdO`ì-O?~ے&si.5{ -]x{|1; 6菛lK*l6egH 6<3=WyZ]ו? ~y#T3l}s/%lz. _ai[h{_=ghdh$`J/$t$4턓jNls99MdY3 Z))X)0s#S_8׸ KyҐ1|&æ$'d!`?NckULךWM_ʄcnkU`!\C ggBf9M?]-lq#?vRiQXz_kGCr0fu_smVM ReiŘgBm4y\zKs>(v  rM OuL u- Wg6G9l>owW;]496!4~yn5pǏp5 7bPPҥ +6j F!>Ok dG e#/>bsjbIB3f"w/JәSX,5=sq+)_:Tz?9cn4o[lu;nz=A#VZnZtϡEGY􄐓n b&yuJz`eAClƠȖtHQ0RkIVGLsX%wz'e_Bƾ{ 8ਫ਼ G*v9tx[KH>gR`.3\SbCWq4؝}[9;1~ +հ9kETM=I3Bĩ:BaF.wƇc [99qgΝ.V6qmVؖ}s xbtTcD<+EX-uՔ-$=%*PXLCe+?sK GG^^dWahl耚3b3,6̋RVvا >v1hQ|&i#]LNv^s]~j' j>k%@9k(O6W Kwgo_F޷A$?RpqqґqGc2:3H1Ws;t51.R]cpXT7s<,nx* pU 5u)wb }fl̚t]g]oxbw?qMaDY;i;Qo|q|3RﺎK/r]c3nP{xA9>~;W9Ն<{dQ4VGR(qb&LzЊvf ^0`*3N8, o!1vǧypܚ&y9/*Vglw7xe/$,CSXK8O7'4Zb*qWY0ߜLa`W`f~nX/jb'vr]v6#pFjF]QθS9ty}ڥSZ=͏?3=wamC&]ݣ.+dmufCy߱k$=|X*Ʈ X!sosD/g ԬTg$yU2/ ] ]gf.5\ H]; & Pʲ"qPIkoK渚'TWJfM5Mjt|r%i#ÿ/9.3̸|}"뷇/?10k)LbƪC3ǥoXT5w`$K."W,hugBĈCi8cظk.T\ ^U3U)|>}f+_qVom3mNecwl*ɭ2ss/=_odo,oLW 35 v{yn&HD*>~_ r#SNjy<"½ηɟ ec!(k` d]{ DGKw{٠0M"7^VD;Fu]ܪM Φ/=P"ظ|R'#:HeҦdR̤ Wpv9w],ո5+toaS:hPq>%(j55yĺC,+$t8Ab[mxO*i鯾Q3F&(jx^XSqd0H] ldy~aY r2NN?)}:m֭Ď ˅.\.$._.$f01QڛBd g\N\KXy, Fxɷ-dz&-~Veb+Nzur'>%#\>>/e%/^tλUgjO;?cx]-굙mv/ -,B>"(K>LPEhP*?8XhB-\]/%+x<6e9[XȲ්TPrV-\LaEp!|#>|u>(më:Mfـh- ;>DfW mͫ(,fxkiydf(^:I9=u+'nv{^9 3 ҧvr!Ft 7sCQ2qxLɸP]l4Vh]ýCuZ[短6MӚ]ir|mkw:cRە eJ2ijeBSZ~H:H}a>Wg  ,f}1$/̀jmD_!P">xeKr 71s36C15a}|2MWV6|v Z%ؒ]tT]>~ǯL7Γ7޾ov Qx޿hkի1ܻXa ]uy~U]krM4ek<,,wt莨qoxhoBxuovhquܷ4;?;Dq9rõmﹽiU/\(8aY7rT bT (tt f1gaTv=m^Cܕ ?{B"9cc9#$"p Ӌ62 c8- $^aw`6/ƍBt,rbړ7~uyrM/N-sc_y𞯥Ǐ}&/a e}Dj2uFVMNh&"O̦Fj̏; yB]4 7:%Ȫ\=!1m5[w}q B'˛7ZMg;ʫF=*O|dOiY_jk < |r'i`fLwn+xL }K)!lbZ5ggfg[f[gۖXX:dAaMEkk ~`~zOяK~4qS /ڗUҋ¬~@*p@hÁ\(+j0a5h2G\@ G$P8PH`Ed@XP"N7;ytxKf.efa' C͹M_b` eRA!r&g 8uD1V15[ʺXMY[+"ɵ,hˬA8CD Q&-;a&dk5H%#SUo|r4^%y]] ̋átj.ͭIj-""C*y!Y!ZTh2)9D"Z.׳;v@8q# UܮnvW W+_,;X $RMoZ?$ٳv^3ΧYr?AbOr;im&63W3fLš|js%4c0֙Z +kmA&waZAPD8f.pഉ j|$d*:[Bt^ߺ}9Awsse7q1,/^fR*q=JQϴW/+}SEyF.xF z%A[!Nw$ܘ`)[^TܴZk 4rokP>\g-V,ܡBy8yEmh&pU8x6VwLPk %SttʄbU>/4/d3 ]$lI`bxf9l ը!얅x#&aCzQ!T`jnUM,S=㡎'iekӷoaU Ig0>fqZO1Q*v_ eJ'@41c >qe |gKxæ#l:xRdştS^!Bnx!~K%$a@LIsbOƙg]&cz [l\lZOױMי7vVO}F5=^ w;U\rn>_W(F@V%̮ !gǨ^'nۂmzX28>tS2-@/^&b"vnlw.4u$l$&^% W|YVgҜrΐg;9ornufȇ#;0ߢoM΢ssk?cD2(&وeBtBS ze5f=ӀN+E11 cKIp(FNǾ~^{{lt8vx<dh0pq9Zf-6Cu'ust0o03s'kMxls9y΢)E&>wĈW:57٬* ?u ?/I}rosvZ5>aZ0^̉2FS3R}b:|̉A(nOǰ\,7fN5Dמ :kC^h7 Wl'ء.\\\Wsb9*GoMܯͯW)Ausr%Y*g?x"EHT(=U#?upKxoBG՗<3{̒n-T6Rh-  M&wSbbu7xndsycz/=p^?3zݖpHv:njd9 a ;2{qXA ͷ\ZT¬4|$f=lnq.6u\t'u!, d4Ś27z_)+M { { zΝh(׺r$ƋI6%?hybŧy,34/P+TV 6vٟSϾH*rB2) 3 %}Τb];H꽎e 4wSZQAh#W.ƛֱ_f\ƶV}G?!# y)74;UM%#ޞFN"c4՞nвWewCɭZQf{n,G<Q7m' ܎W+ Pn6_-ۂVe< u5h_ʯ4⨠X}"ǛSV.^7\޲N/iPR>IʥHo^d틦"F b4Ó;NSZV"iC؁ !*C!D+!wg :#;юtёQ^|pBD1?naD*H_FOWKy2ʂzs4R+ \('; F" LFAeGX~ yYa#>A5}IDOFy~) D;;LO{?z3#oF;e#J9y=|GN#J'N{PT4=yt#*h“"KâbAVtGdZrVdMXk0İx!R=>v#WG;yꬴMӮzR?ctzXӐLէ SlKM(M-_u^)ĿMԹO6Du5Hg–Za+d#_S{7mJq L1u4~^7K#k;LюD( 11v$j˶{ .Ѯ'hg2h0D;v{[ j B_6m^IMx++6&=R\&F$LxIi_;.4CI>h#\v\@, ϾMfV--;-ۮFkTyx:wA)6=/^;Boճyx^2nFڦ}TT~^w\WŔp)bx3w8Uɫ{U{U{lj{AS&X",fkK(4ګ)wDKĂMYi2끣U)^e_-2":DwUi(vGԚknqmߊ֬僑S?Ф m]ﴦa1bk0 e,:x̲p8o(Ij^f25 –ocz]CZt^ Q0cЀW.'V,ͯiv~Ffmԇ5}85ER(\#KDWk` endstream endobj 139 0 obj << /Type /FontDescriptor /Ascent 905 /CapHeight 723 /Descent -212 /Flags 32 /FontBBox [-665 -325 2000 1006] /FontName /BAAAAA+ArialMT /ItalicAngle 0 /StemV 0 /Leading 33 /MaxWidth 2000 /XHeight 525 /FontFile2 140 0 R >> endobj 142 0 obj [ 278 0 0 0 0 0 0 0 0 0 0 0 0 0 278 0 0 0 556 0 0 0 0 0 0 0 0 0 0 0 0 0 0 667 667 0 0 0 611 778 0 278 0 667 0 0 0 778 667 0 0 667 611 0 0 0 0 0 0 0 0 0 0 0 0 556 556 500 556 556 278 556 556 222 0 500 222 833 556 556 556 0 333 500 278 556 500 722 0 500 ] endobj 138 0 obj << /Type /Font /Subtype /TrueType /BaseFont /BAAAAA+ArialMT /FontDescriptor 139 0 R /Widths 142 0 R /FirstChar 32 /LastChar 121 /Encoding /MacRomanEncoding >> endobj 146 0 obj 16941 endobj 145 0 obj << /Length 146 0 R /Length1 24736 /Filter /FlateDecode >> stream x|`TU9N3NK&3ɤ'0!!&NB/,X@]EE\ oUD4 b[eqW쾅Dz?sggr0BH#YAJ|yyׯ/ AHyE^ BBeݴY"/^0gyI)*Cy_C9x?g&kܳsޜuA8g-s N@h ?|'}F(\I2(߶+^ڵoR: ?Ert RfX$Y"JԠD*FkO'%z 8FdBf3V!;r 'r!7 /!?(B( ="((*@1r!B W\<}A{7!BɹClSh9z 3Hw LY+A }4%7S;x!hq& c[V&U=m%5Lf3{2= c= w,ȨMff+Vf.9!l<M$:t z:0r4s/S+:"zXvO?ECt}p>^çdxxfTfn5qhdt=݌h}> Qd plnwzNc%.CϑY80#nNh:E{ NSL|+ ߏ»sy }&AFy4 俘gJ2l`%-a'7dlaNqٛ9 /K?ye]h(i=l&ɧP mÿ1AsXjxSn+aF! +Hy l̽k" }#o~܂/.,'ujCTWU' 㱂h~^$ z.nZ&#gJX`o 6wHGG,3#CU>)^7«zٞbO507ԉ ߃Oh}6>uNʏ[Mō| wMolh,uCa05@.e؏X{)u0Ĕ+ؔrR n3?5~BkS[ )0/87S5HIR 1mǏmá193[SGS6k:榆 [&v޸q5unޡ גpsfxfX1xx5Gt$tT-6њ|J\qi,kc MIrC3oRu`ۜF~ 8n;srn`fLzMIin􍂣R"@<ޤ5cтjq^5,a*5VdIJбJa8% sA~ x5sr50NA-SXޱV*WƯ!K+8>4vNL #PHК-h X[tЖc}-)e}_KA D dM)#fnZ<4myA}̤ [93yP)N' rq9fVʙ@Ub/z~B P)`9umjAtQO}lwXWc4 iTRqTUYV \AD<ȋiy6O79?5' I J߯O jF鞧w{ҪNMNŅd]}*r9wVv'`zOc"} z_ ! xHEyUAn3Ⱥ[ΤNx߷ȧw㑿uhE5u.QȈ.YK{*T˿$nx"9(C:ոKa?8ay,;\V޸L UPETG\Taǂ^w/J/iy%2*gl7R0֫H r< /uGT'NjуwŐ3=w㜓h(;CP0<`f \ȨNFFt͐vq\+n1pT{Zf 4SBAǓ @XC 9P Cb(eA^^-Q_{n,i4©X F*/Jwmpixsxxl 1TP/„hm=#uX5tѫ6QڤD "h7XW1R\^FrxUil&l:MƀV#zV?n.WvYnhBP0¾ YY@Ea0~qh)EwqwDa\cFu'sL䠯1cda݉e4b8p@9 6vp5dE1 rqn=@Jw;0 V\M m ^T,  2ͽKNzG_G7.׶'fa2ۙfWx8V@jIi&I@<% E l0bp}>j VxJkBRl T>$"*~: UoGyp4&ȅp:Tyk "0PC EaAaU.# :}E-Quwͻ#]Ckv⒥ڝ'sHZ={%o~p=qG>z$`=*ItwF3_ z=J|ૣ78S pE3" $VQ-+D\)E"B^&ָhE>4.Q"ΓO=Txj]yLUBG xT w&)srzkjjj_yH[A*vq?(T5kF!DƾubF*G**`)nCY)0f.tdٓTK­ҧ%'cf4Wϖd/qɏ> l,u&< _L[l)y|d Z"ZxZ-> ጶj WKeO%xFV!Y+Vu#NS $4DT*%^-}+ LtQ$p5 žAI,/ ͊j|.1ghJ1[{糌N7}|¼ hX ]A[p*?qcѸ)hTX H&g`M0vԠ$0%(AO?\9Fج}(뇜(:7ߔE`8OϺҀ0N8= 5XvcGMzѲhcp }m$-Z^F(.+ xg|Kt\wgrflsy5Y8~d%k@\`1/ F 31H)R(р:l1z uTiopl:/S!W}KZr9X dYT.MMf |F+:`헇 K_1хB/l|u3``?/:XV.m&דȭqEm~҇sL/r<|a!T"=*q% 9g+Kˤu $!Qc *DC]IŠtC()F+)S,D!*9yb*K n:Y1NMֶ?5;3Ճ{'v'Ov(D⋯*9.ژQdM -]2Z_⾊ϖ?yHfIY1~c{oo _t#;^Feq ƃ FTF@Et!2)`Rka]"xTaW<[|h ]wlxEQp;Y=:Ii +϶mtEfI$6t)rnۅהqZp1mߓUΗdsQuMAW9 Hr] nc{:?| ܔ~ӣNi-R1yɏ9zFX0wKY{ m\71\=o'$_+tfGeOb[LK*}iq)*QԔ mm+ p)I ul %`Dn>EM+XN+h9/67?3ۛbk=tu>Q-sJ'oY[߾6}M5?{bE> v+TFJ*^ApV r3h 4r8+N< O礇5x<-ٞM<=JϟïhJm-`~YaT@Xȉ Jd%K# [iIWtzt @<ߐWJAAoqD̏]~s̏bY V]rAY9+9Vk*(zT y jIEU:Z5F<"R%e FQGĤfUq' 1z6|K.R٢TSmY2@> 'ds  7f0,JpG*l>nP53rkA)k}Y;&ݻ=Ȫgk{??+b:5]^yRMMID:6l a A1Sl=E"z k=YЕx8Yg"O7wzвݵGAKCJjp(̣Ƈ\梍E;)z/J!]@kG+TLVg|.J@q."ģI6'xAx^u:B" GӂRpU۷ r)R~T~ZʝUGEDc{ T0pH"퐫 1>Ft693sۤ,RfMSr _ t1gUWQ.TH`QY$[WU҇ 0H0TŴϞ={Z֯Wqv~cZAOGh -?2Gwt}Ӵpa2 ύ\Kr5HP!4گKX8l <6Z6;Vf x| k]Ӄ*^6O,`T&'۰9ej nOB=>c7 5+|17?;?#|K"dͳ5ccyK KK:*`¨:H@dXys'nm|UP;_ŇݯS/Q] "=xsw`}!+% $i.gŅ[4jӇ?.ޒGw$UwPrө~!"($mN%Y2M7~gKmե唾͛poOмvQh&h=m`ىxDma%d8^Ϳu~b8MxIoLt{6fߋ2aq-[>5a? V0j]]Y!|'wYp$# BVx9<67.,-~|+#%`Aǂ$&l6q-+]Y9n(}VOsm)~7j N+o޾q6;`-ExzٝKvibNv0Ei一¾P,.P~ۣ!,*tUJuQTWwsKXE VXso+Nk`C!Pd[geS0UHo}A K;m [>2 ZsI`BI)/aCaQ'7{i%AWrB亥ٔ6ؗ55ޚ `3aXdYa! Ά/ Bk %敭]Y9e{DI\Dd2*@/V9;m+xuL@" ef8W90bTAEE} *]T=<<<d9UemHsug)Yx`!D+s@YOzW$-9T~}ѢГODUP:B`gt `nrc̱ooȳmxK{}6yQf<<>+$TfTAC,w5bZ❧8Sf('Iq{ȈRšF刾d1K?8X)i4L? 1P9H4g`.mBr.L!e`at)l ]6iKK񗙱۾l2#N,8KsssNYǵZ@kU2Y@k8[Ae^#=OkT)(kfUNN9PX>׺zm+AZlan4ԑ7r\ wc8s MR࿡>0 ~O`qed#{dfR  !0hh04Lm+JLx*zV+V{dRO3E!+VV 0P` 8z(H}p%1ieWFʚeeʼn@eH+n u b]0!E 9VTI,/R1 p` jDEm.G>>/Bˑ{%ZjBGkO2{)k\($r9Clҿ2m Xo)tGNiQ6ϏerGd~ЂP Ǹ ZApz5RgX' |B{}2(^ ;U+@ ͱ.H%W+Q>{EP %_@ɖH,W[tvY\z#$ʊ7SRR UN+=SV5577%{8iA{Ril!%|4jAz_W].%R^A)+给rr ǿOf /Q;{dtnlIXߜLYCa.LquY4Y-LJăuXH&0.Լ;)S$Awk.tTND@aJ?@^ c쮃}$\#S*r%{drn7+RG+qB6NؚsA >AwZm-3$w,v@9Wjckk6D憻z_V >6 b,v~K>T5kKdY.Q.Q/-3.0/+cT``Wh?Y'z:kE auC6Xԩ}:~R~F~^.ϻ@<ŝm_I8)px@,g[3pygIH-M;9()@c.E|u DJ5D A>654YZ 8. VȦa  Tk@WMgM_)ڵO4}1lLI{NgnUܢqUz&ӽ叛 jo}0ycQTX.XKP~~8i`Lc=(&Wq@:AzB[mPWY!8>5ʃxW8QkK̓CoV Wѿ%@9|lL,AfsxU]hKO5iVrgΣx.ےK3CS̠]{Ҙ~]IF=9ͤ{,uzb/i|?15l~:_6_(qIcd~fu^~Ġf^zirmm{MtY'e <`Ja5?WXCP98PE=} gr0(4T J* Z|ԍ7d*TI:(<4r6jҁ 81ٽ0UAWYɺT T5_ɄS]5{氽GI?!2 G4lx+YS#KQ(# "@R iTZKBEO_.c@U &-USPF F zEʆ,4ʾސѭԥ6lH^$bnj@tWz%8gxcҪEΧwM~kNm{y[olΚ!|2_.X.^cknmD/_\lSޜ8zK ]rc&O_U>][] 4r+( aiUBEe58"sj=)KB$H=pu1"<_`!_tRlgAJr `a{)Q匼o6DMKJq)dOz}"*R,?k2rY$dg>~Yl:Mn@P}&2imsy޼Y$S_[<iΛkh]C|b7qKlH AX K= 5$4+nYZ"\h<@ޑ | %g0laNN6R퐩Tr 6z rxc;h2EƲbS62tYr;>V%j30V0Yf&꼤JN 5LJŜWrj5^.tY}ѡ3ö]K3z֔Y\T1;\ f5۬m0<:L*79,NbHP{rDw)!QIiE9 u @$(dǝR91>SUeepl<G,سŦ =l _P6w>E"8d0k- lt6#R wؘZR7WvgQ ԫ˙H^Qj(&/l uzN["zl-xdFlҠSwikbӱ&I^ϑ:wg%H(9͘$,iP \QR2H?+"Q9w08x@UcVwP!T`ϭwvW{bV(;l5\o!^G3oϠ!t:mA !{#\I1LÇ:ꂋEJhĞ \Ðt. !LZ!|a=z}7Zw V~{ ­@xG!` 1!̀P a#8^ j>7 kb {TZqr*n֘4kkC?Ѡ6pp/͓ͧYOG:;]r׻|;}…V;s8 ;a OPOI4#zr)bN6jtsuK\7n 'LC@x(_#ѯf g2vZ%|ˬѯ5f46 o]w-[{j[ 7Z43ڎa1Xה2RҭbF']s I, \ @k@`.JA8]0PsjB~xPw.e 8Z.gٹt P5lJ *(cX׈CRF 5z'cV[=owBN).:pO!U.XLicW l:U?ZL[]doR"uRSwJ:)_kR>Df|L`FKx ϴ@QR:!@0MhY*r#GB#Fq (φ6+CMa1ah jfCI3k_=SWpZD0"2 F3 b!N@a6cޅ`j T A0Bp f>slob?#|~^E.+ 'd&CѾ -fCXI (Q"jHcZH tGkjJ2zT*5_DaI r^9 C+!GtQ'!@'<&#&#IRNA؇NM 9u.6jpM>/4XQ-m[Мb?NnC U0-y}B`.c ȘC/~ O??Ko } M}12b]Ŗ'+UP!sA:D5ـښJW=GX4 [JuR,J]tԝ{snL֙q3u3u8c>tScʘ"+1]>: "åTRӺtH%@<; BaqNG Ҍl/Ex&MB,M!q[ Q1DQ(T+A_aOtNWjj6`Y%Q"%5YE6j4f<\ òM̌!c& cИ|`VOi 3y#UӣLLUƤTg6(==MnZu~<"AϝK5Y|}mv}TkOq735-UJ3oguCʦC&mIuDZ^/Pi"Cs@6&=TrMے0Ujcp8r4-iUrlWZz֪YZ-ZRf9UYz@)maDUVgUk}j?Jn  >r-~)VnuxhG1 \:W4@( endstream endobj 144 0 obj << /Type /FontDescriptor /Ascent 833 /CapHeight 578 /Descent -300 /Flags 33 /FontBBox [-122 -680 622 1021] /FontName /HAAAAA+CourierNewPSMT /ItalicAngle 0 /StemV 0 /MaxWidth 634 /XHeight 431 /FontFile2 145 0 R >> endobj 147 0 obj [ 600 0 0 0 0 0 0 0 600 600 0 0 0 600 600 0 0 0 0 0 0 0 0 0 0 0 0 0 600 0 600 0 0 600 600 600 600 600 0 0 0 600 0 0 600 0 600 0 600 0 600 600 600 600 0 0 0 0 0 0 0 0 0 600 0 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 0 600 600 600 600 600 600 600 0 600 ] endobj 143 0 obj << /Type /Font /Subtype /TrueType /BaseFont /HAAAAA+CourierNewPSMT /FontDescriptor 144 0 R /Widths 147 0 R /FirstChar 32 /LastChar 122 /Encoding /MacRomanEncoding >> endobj 151 0 obj 17617 endobj 150 0 obj << /Length 151 0 R /Length1 23804 /Filter /FlateDecode >> stream xy|T?~νw&gܙI2d$d!! a ELHA QqC+Dl>e 5[mmIWmUkԶH[%}>{~&9s{v>K(!D Oe/"5mBwr]$D?LKlY¡ ʄLK/[JH(PgiBzmÅLA (D4"#SoRըMt_)G@J+y_ F준8.s¹x  $z7K&wٓgԫ4j_Fϳ_l'QM'}gOi!*ZhCRL$2t7ɟ A12<@"dzB"2~ʤ̥= !S 04jHn!G$YLSG-vr!%]L/cג};9rJGT~RM.&b4'_LE٣C.=\ - U[K"MVHmk}$alGo|%6r^EG '[RExM:f;א8xJ:n[Uxr 4@ĸ~A~M^zu.;:~H}o(G)US=5Q *Z]MG'q=[&A>O"73#+^<Ɠʹ~/r *Y[Ǫ3j8Yg.d+z/7)O}4٨i ]AQzBGco}{{;ƍ>ª7Uk&x85[c*ͤصk;E%œ"?'WNOS ɃEDh)Fw>W0}g8™\ 7;xo?SmQW)O4'1kg3A&.=o2dpn6Vfr%h+f`#ϒ[m>V'zceZ-t96w5F>m/q')DĈ >-qss w[x"_ķ;, [U\բTV%Fީ^^]w?VT}R=GfX֠vkjo>}VvRW|BK..: c?6?IJ ށ\Bpsܷw!6tpk_ W8/R^MkMusZJG=Ec1i}{ L~<=Kd9E.!O]w( Y6kBGWɿ@o"oy4M%ªfP/d/d4SU)9gb kzՉ6&Fzkr=qcupJ~N#ҿּI';QGAn*D&'hZ'?͠eUdF/Ir:IprQ"yɽ^uΥyp/7fqZ?1@oNz;@iVԛջO\݇U#90gzJA?-E'dR/,ߞ9X܈Zn w  BC(:_ug9< x#B% gBq㳻gGЧɻJJim-#djH7=|AR?( \?p^Hļies ihV-dNףVczb&j{ [o+T>~dd_ gPnnP_7:SUYQ.K&%EXTCb0y=nQ` Vd4uZZsKl?K)"aW!$u|L6Ğ[Qr%/JR!HSv)y 67S]Jx6#P{e[(KCَ+wJAUj]nH#F.i u5Q%rDg^=(cK/v/ioý,m]&]%Ҍ5!J3YMkV4,ѐCKGv1,KK^ؓ嗢-v۲'_FQ疯B|Y_ۋ:,сJ97ָz{&4b#aʏoRWzirǪ~,wG%z#'=ca6ޥm-C9zN`OAu*`25SBJqs3KYYY,H4-Fv,%X˲B=KiVЎO 0@)KR41S2|jYl8Lf "V)ؤīS!#ݘۥiL8a\HvpAO>"rDN'{\?9Sx<0VYо>K9Js, 9  ż!o*-h}XJ._AǔUQaXPGVpxf=/F>9| _{`9ܜw0|-lǎ)Ա 8}h@;P~E'vы[8([.9"uaO\k^6_\ž*pU(oj@Ӓ8F;VV%F="N  I3xa[G*r&ďsR-r`ϔ{Bx{H{(d^,qWp \^c1C~LlG^yK&ęi^C5Ikd.K cmw+iG[G۬6*ŋՙJV3",)e\RY폴.Yں"zdCox^EKf}s/)9GJ*1Wbd[s"ӽ?{hlMK"uҧiٮn<2جn;2=汄Q]4uӨ͔8ZE awpj ǫxka(C܏<B*ObhDZʱQop.Gw26c@FN=ޮ1 Uw̝T]+EjJKTm:3}鷃Y_驳*i|OD0ڛW+['!3GG"6X+ztVpҨD%HXsa lf$N sbr-bjaG*Y8uIHsIIA4@q:(HLBOy| >CCq9ލ]l\rLz2)}ݬLRsJ)\ +\u[,eI.  qDHjD+46j3HIj .0\ ߙTUTg@ASKDu,_OX+ lU>X*y]}o31SGGK_ӾwPLN:w[m/RwENWS"K(D#"ǂ|+$XL:DNבBxeWy"+JY-ʪa Oq';9O8s e\Y}e]c1@1@y`idݺEL’ӭֺb+$g(M#Kj42OBR'҄$d2~ǖS\4Y^-w Jd 2FPmRuX5KAf:US1~ \gZ}>n?sw9sݴΞc)^%&M[}vy]53o9wɞFgP#9987d ]( ("j 7;o׭omf{L+ ':[Λ\7Q=4++5͛}7jk-6{4@s0 ?a[ԫeU.Iۨ;q{lZYo5bK=Nuɏ5><;5FSs:,pטMXZ^4imWZLŤ}IzeuM*E4l]j 5Q:cVU$Eܷ7o7o#8hw>x'֪WO$_{#'~w+\}1czHS4]_^UKiXҪR>bmTkCqU7M| f֒]eO6z]ii H|Ai0W,* ĭ0=-0~舖jp4m0F$VL|>Fcl-#l̑`0I9 K\1-6Q%Pb8 u`ƖXKB6 cBFFcJ*ʒ0g#T',ccR(UL&܁V)#NgU8%c` iXnQ\⪊oo'VZR bt"IJƇT㿮|]=te(+D+kXx۶8k#;嚋arZ(RvEPD}n "Ož/b1ulP8t_oaZ}5 xy\g o^X5:5go_7`"F_feiDχ_Yg}x;{0a>g'31 _i~.Hh#-pΝͰwQk D(Rh!6Ҁ+2YIw3]bk%* b?n%uk#73 LbŴMՔ`յ/$Y8-B/"L2H&rXk-w]]]CPج U1Rj rjf .ߟ~A+t}_"iA5 Yow7`?5:ÓB7sWŠ*6~mu$Uɓ" {5%#‘3W&ā@rFzg[Ti~{Tysb1x \&Ű΁L)j>=ox]uk.mry]"Q5!*\+  %hX)<۫٫mc~{ˁf34zE)0΀~g*́͞=Á}茋,Z2NA9='Idtʅ.9;90_+`&e*b%/H0AHB,w1uu{9la|1ZCȥAfĨgxUF)K ) YtC:N=0#nH3exAIѫ:-ό,/hZШӗ]Uz3i4={ii!pX dF@ #ߗ_qHRdt;}}S^tGF#hF\ D|K¦'*+(s_ÑFՅT-M$!$;ah Xo"L)Gpv}po*WbLoTb~CT|D@cd**ux cxqԑH"/3%xx}_yU2%-S5:S]PDLMFN&Sǟ*P^lKʅ<ϞR"7>kM5CL71jb;ST#۞zMDuSc*nnZLɵ* >QGSr+üBVmRS)kR(#d&Q䶒OdG3u_BZ#p5OTš8 .&^' KV]jZFUٺddըT]utN;|; SAؽ 2 VCbE~'I^~dE>bJda%xPIr7V.VO2^fjb5S e/뱹++PMdV*25LTLƒ0 s&aQ護b5pSG:g4oyf(O|fJJ^rO~:K8Ɵ.(_o/y`j M롳A&w|f"f 3 kg̻C!чֈ${&b `=Lr\s&!w{wnqKTGiN[(m-)J8TBH֤c6AMmŗ,w֧d5^|[z]օr/M)s296ѡ*x;el"\G>^3So_OQnJ_m.UZ~u*-lګ?@4u7-s7mp.<@h2MNWh/X+/>nUekXꩪgxUkQ`U=W2TѪ.[Bt tD{ިtî渘D%+ \җNsn$E:gn"dܜR4]\*m+iWmG0g>+ r`'77qMB]qwqVj+ղˬÕeu_R{O;=L+nbAdS?V$V|0Sl2~$l lo_L%FX y>p9Rgi~ *+p[ 1AX  5DMS5aX"+E3ݰI1?Y6 X n"*k]l/)W p{0v- ?> ibp`ņ- EaOrǞ~΋VՖB1Y\>Ǝ3{&B=uνn悚2 W8<H] [:\u{lQݏdkqѲj.\ ^{ V37yZLwh W^"t /ɖhK,bΓeî-7<+{bO vtVHBZ8+ 81c/7oٰF"~.r%-r#{nIuz}!BH!'aZ|/(8d2l}X_d1r-7T| VMHsdI**o*ފ 0^Q OQ!N' ]1V(M!rNR s .bx |A*aK4D#$ )2/ڱY-'ۗ6^<-2wxEOˏX 7O9|_sh݇$4-O9 b\EkꞒUGeD?m3՚:MChZt(їNM}R茰-^u4&Eb d{]/4A^;SDYݝiUrc2/+20M=im{<`T̠l@oC]?<9W7h9A4㛼F.)KD3"hcҏ 5X4[&sdBM~fг#5|d5fΜpdTsqyH(@9*d]t**j9`?4dt9&0o(t` =7fczG cFocҼPexkeڦlz L4ժQ.ZEf2ʅ pY>3z1D"R<%+mo2̇o  z^lWO4(qi0`Ut)u^pEbbԉmfHz饗_ V.=7,L eZr a8* NKtDE2\ P$%b$ SA VEuY͸Qk8(I15P!r ;si9؄ aY6G񪀕e\`P̟% ELhɉU']h=NKnnG89~ԩwSMPg3<]©S %MwKYYT];WÂQxCPLlfU]`PP[&PId^˄Go o\M8Hi,n4xlEȾ->_|%?|-hmx|u6Մë2:AQ@@hvFvS+{UEaC1*jQtkS“aʈ0UTP*Q AYyft'.#gZg|li칊LéM!doרS!̳D eVɯЗ$8_G\k\LltP :4xP$(EQ@"EHr  iFT$m$URUr*`PiIQ`!!y^0!;#Nj5ӫ=r2y瘇=;}?IRRϧx93ť'ZƈČ6@$rߒmiF[aܡ<ӌo5sk FA50P7xvajMWFZS+eA 5ӚJ]yU &hffplC:}[VPX #G;OtrSԔ1ɝ3G:Ӹ4*(R^R9D ͸h!)fu|2tt@%j0 4~y*L/Q4xWl"_M-SYZ?3 G]7[5}Oҍ"PzH=)e)8F^PcW/l]hqwm'_E"Rzm r sh8g°Y050J: jAINuuz M1\6;Ej&/T;8w[-I"8Q:̽%""h$T%7B(*&q +Z- 54e(3N>-/rW-^h "g%pkG4;V8řCnvuT+qE"Qxj`lzV1MqFnfcB D% D= ,-CԦQp?%xpYO4.% guY)D3qO)>`cyi$0Jb?ḟ1h&LZ1}*{Fe~S8Chb}ӭacihew.UEC+J!Rl`la; "O}s r@ɢj`Oz.(B-f.S70qyWO/Og:lI.ݯxiYfJV3d2`*9Мj̃f MϰT9 k͈4,K,8ʣF.ԫ@Tal+Y.,,2;1/uxh ̮?tuٞ%4{EkX41[$Bt챧uVMZ)HK̠l@м$M`Mmwimv4hh-B -}^{E~`6$rawhW^!WtW T*ySAl$M#Q)քj`?WL ~Z;edR("_Ti#g`͙UR _PĒ@(V.) 7UD/,NxPs QyfFb6R&6@\ٖq۱ǽ77/ȓÎDmT>]zcEd)VEeV}zU1WeBo'z.U].2uqyy˒;3X ^P?oWGo[{5ӳ8PB` '+0e_|+ɇ8h O Όca\"PND`TVb@QXX+ *r\_l R  >b8J-%ҎjOhy`QHJ.@;Oa`mR5?;ָR\pjaug'\6t`sdnoE4ܨDGH{hӛ|iIUgدX/aPB긖Nj)3)HR~xw zH"LhS2D>5+ɨAc$Jh6ʥQ. -LXB @h 2(Xh2b4O1~e̐ 3cV1EǺ*=0D@a?k QNilw 0NOs_(jiEMcQf'{~pKTl/^O^;NU^W;Dle0g~1\Uj-Bբ)8M^e% )!Y-YwB|.DC41}[ekY>+Ep1t:Fyz68?'eٚJ,MC!c+T)7[Td!8e$E #!&o^/_G!̙ 㡜`7S{Nu (d_9(WM!1%JEJ:R]ȕKܥ_]ӦMFɫl`lwhijG:3v9K<ּ:$SWʳ < OmX":=IT$%W^D T"eh&+$HV!mL O GZWG&5Ow }6`ddu5#_!5{=]oR5%57h`0ᭇL;&EG;k\kݲwo֔FqVSZ,Ix'"RA-ܙ&^v_yκ˗>75cݚK} (˃T8e_Nfl ZۏA Afa眇t+sE@%а4dT2+pUC!"d#VpKxŧDVsWU`mʃUP|6Qه\JVv`dPgq[nqܢW!VΆ)0jX-6 BIjk?5#4UJlXN; 4.I8cwPhSWem""IayV*fEӑP 9Fs|;'*[ c5Jz|CsbYaT?Y> ,?R.H]-xƴ#%** >!Af"$CPyiV {R9ҢBn;fJk*IKq?!'#>2}KzcC4"DXlamE+`&g1w -gJk7?ǿF:7E{Sʮ!=ބ:i+[Ae&Wf CD)7*Ol۰ ]'(pPgh{b>/VTz2[ˆS5?XqI JK res2ohZ}eR| [C&xm l _yZIGCz9Z臿 /i2\? ~OB;).?;Zȳ!2.m^n#6n;m6NVʫWrZLF} Ǔcq k:qx]w;8W֞ZiݚOUKu6~'4 \PF` ]Ƭq8jTg5#Q 'u_36[Z۬5OZZ0g82S2TT,%.VBrPכ(7OKYG(3^Gʣr(We?(Dz ? zd! ~9 IJQ ]Jh?LGڀ+VBr^I5. q87íSb"|/sBs<_Co+w?Uޏ*YLkfnoݛU[j!EYWpA%߬XX,B'{9C(JDE/GߍLò7bs3=ynU 0^~2 2,dI7d8;ɠGɘŌ919+?q7M0Wu0\W /u7׵ uآǎ Ѓ:M6.1u.QynE܊ ܊ P [nŷQ=j_H{ p8Ռ[H!a%9x.Q X7Vy\BD;eέ['a%J=aۘ!{}U4JuU5\I f$tinEKG {S3s]lJ:X%-f>56|feϠZ\Śr85V$+T\1s5S ")x ܊`nE;=>Lj'MJl+%!HV(]688z?org?Xk04^PS(NQ|;qR|kEDi%djL|!E.~V ѱ슋+c9qŀYYܿbx_")V(| kݔ"^6qc" _$*f +1KKJ/J\<sʈf5)+;d4 xYG˪esMuy? L: ț"mLd-:Π4:N۠ٵq?\(;hg@B'arc-psΝMNu_s;{22P05,XUK3pgpܭÔ,쉛|,MoĹlou/^WS?Ms's>VdwN}[v[@o[~K+zQA)F(>q&V ~=䶃MX +ZE[Z*ZەB7@?Р#4PQY8[`e+_f+_,{/#b\>Cth=\Ծ?{šYF(/^˳mٵR[taӥ}ayy[n<]Z;4im_5YeX[,{kk=kk=kk> endobj 152 0 obj [ 250 333 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 0 0 0 0 0 0 0 0 0 0 0 570 0 0 722 667 722 0 0 611 0 0 0 0 0 667 0 722 778 0 0 722 556 667 0 0 0 0 0 0 0 0 0 0 500 0 500 556 444 556 444 0 500 0 278 0 556 278 833 556 500 556 0 444 389 333 556 500 ] endobj 148 0 obj << /Type /Font /Subtype /TrueType /BaseFont /JAAAAA+TimesNewRomanPS-BoldMT /FontDescriptor 149 0 R /Widths 152 0 R /FirstChar 32 /LastChar 118 /Encoding /MacRomanEncoding >> endobj 156 0 obj 20141 endobj 155 0 obj << /Length 156 0 R /Length1 26944 /Filter /FlateDecode >> stream x `T7~ιw}}$3I& $a}_dQ@+*!!*j۸5Ŷhs$mgr̽s!9ڎ-X5o M#? 6w $NCߍk:ҷ8B8ByKVnZ]w!.^Dh\ L+s_jgBYzg #f٫]FPaw_3oբ'역Yn=`5.ZӶF#:!ir$Duց#eEY${D>9])E2NR"R4ZtHo<+3 +!;r 'rS!A^C~@A 0(8JAA.XZdF ,_Х0xI KÝh/E mE7FTDh :- o@q<4W>d*gfD>Cݏv 7hz z\O[ 1CVt{$b3)ԄGux]Pt6(7֡ѫ QK?[X4MGK1o xt4Y|+Ixz02-nt-N!L{C Fův̂' ݃G?A?.< _=WnE{ѯ߰OדBU< wW4[ѽvϠ ⿲; (/I)h)mC{>ч}Y,:I%TD]@57J[ף]h7|Nob7 ($7Kfs#yqx'&U^@/nԃ~B'($z"5{I;WŇ)Q>Ѓ#(xk@sg__؆sF } !wG=sLcr^yѼ=v: M="uA?vklDCmO?? Md9YM0q0>&f]a쇂͂`&H P =>sb p6pퟀFï p#|էx^'a!+Q3n%YS|xx *hAP]O41h6< x݁3]:  K>/kt Ɍ} bo?7A܁_g;Ww<|-ё" d$G&dYCȃi29I*|J (41mlM1e}OooX]̞ uL\xD% P5Ƌu )G+2oc.3%nśDlx}F0\\m ǷQ>THn7pW?/}.O3\DY\ $jQ~ZB֒?5p'7g=ŸY$6+z~6a7I~f7P ʮg:+#} zo;#<(rῠ!"{p7+ďq vF 6"ffvw#38;[0h(eaziߍ:v̙3)3o=BqJm5.E͓|fLw7`W~s[ [gg͸| Lw򜼰G$V`ܦҺU 릞W.ᶁ訉 }ϭ}M#E{':F 4pû'͘~); &kmM@O C1zbN o1o ӃGwI9nb]KöG蒛9sfgl&X q;UdSg^UH6a$=K,¡2\ OdO 5QBf}+S0aJFz w_DVFIl6$„!rYKU=LAtd$aGduX]L}ǾiLN}o2۪>hM93R&Q݇gJ4nkCk1FSUtd3AW 0 ʉ֨@ZK? ":1Q2gC_@_9P7/U '?,񂉕BYCv\L"2&bY!\rX%?C L>Z]'K2VMKo^u]΀dߗHݏ 9.Ʋ,pǓE( 'RyeUyOl_|L_kwt;N|n^z.Go޼Ώ 7QC 1$ /FhĪľϙ$^!'̯%cHAODG!cd'N'6X^O'.ޓ p^iSN{Y] v :({s`k~2F01u\ui,J7m/BW؇{}}\ڵxm[ giB f3Ѕ&'(}Ĺ_7u5'm<癥ơժ:"0cøɧ1-+[+g=?<ڭ;þr`8})`RcRȰ=#$E Rv/bAO.%# ,L3H 32BNdB$|&{[&\KrX""TJ+>x9y'  &t!Tڃu\D aj$n@+L %yN&TejI8We- p*op ofWЀĨj])/ ɘĮ bŮ] hqt*`iqZ^0FԁNK;o(܍WƬ,o5Ë~ĭz9(NEEkٵu؛;Eww ev' Dž_ qj16쿼H"/ 0S2^0JY[^Rŧc#}c -}TChKڀIWCUT9Em<"#΅ ?2Q7e͏ػՆ3аX{zC7 )l~3D0e-Rx/=bEƞ#r 8*'R\l~D[Kp^-pPnP^@x"bag3HىDh2`wJ֩d*@ 5gDIj_e]Ѻ(,Gkj#ZFhDL'o=U"0DO-krJJ?)})r8vKO^Kϲ[HuVC զZm?E*aHa{ kufUK$Dy+/x 1ۺFK.Zl_M4rJ23.dVlWK&k$^ :vY- dkۻf~x9M0֊[z{Ztq,TR' <0!s>G mI hX=ϫ[QsG n(ni!WBӆ<弡0~xq *)%ڜ^۲~&TP)sͩ~rnuCIA(0f &\Գج dFKɿ<ؖvXd1@LBh?ˆg K7ʮsުGMcrڷD¤p"f =DfY 8;nP`:C>.*E8ٜs!;/ /ZJHho8./սӂ0 %nN~Ю< M -uM+OѭŇ~`K VF]S714kvyj;?O~STo@ȔO { B3Ͷ)97*J8ԁmvSoK*ILb}2lЫ#'mHXbSISEJt5)o?`d`iUzMpZv-'~sy- gAjxwnVk+ o((лʒ=q9tXu-la=3>֚b>oDqD1yUhZ) )σ_B߫sӜ嘅b9hy~o3Wnmt}VTz( S}1,^j*Uj5ŕ9bw:LU#)l"d!4:ll1GN@qTT81%bu8W q>m>%"s6d؀_v$$`3ZC 8|^_M~zLon>&I\b%KjoAі=?jg?kx)MŨ %Xk|U+4.pJ~ 6N*}|>d$tj𗅂ݛぽao7,K[`_(Z[lA|r@dM(`2B~תW.#73 2Xp"fm~< |ּaa8pBA909Լ#41a`8;Hr:zÙJHRTh;a8yWBP0k <s(ת.Glw`pOK};zi 8myEp"fm eo/[ς),yHWDp 8Қ'v^]>x{X5a~5.8c}aP6*+`? ^XS4Gd;S Շ` ~ 6сQ+r\٨ŮMэ{\QCoY5]xFz^Y aUTL1ʅ D+MZn (j÷qjڴȢExcFmj˨}Y=hDݏS;)yNԺp[S̯sBTx6܁>?-3AQPE[Ap٫GJEsh4z>wgY#ǗN@\N*h$beaa./SkA!7ރ|]4"-*]Q)Yb ߆#||2n/(;S^ʄe tm*3ˆPxǞQ.㌁T0y@dS03p ~7'PZߪ|)APGT$H &ŧ&}gKWt_\I6g͗*EivB *9GQmp#XtT!J^TA%/C9D2L#,`hnbIi2(Pd*Nta d4 3v= tZ'eTN3d;r'yK jnJTvx9`ohK \ g:|S"=pF+Q2#ϊy'fx⼰ \L ɳ䱔WF.)_:.m m'hh:dC$zq 6 bq1'nT_ Rȯ K`ٹpga; OMQAW^o?G#x>A3iJmMpjԎ4,%ȓfdF13s32!HHRSf &zاuĬL*Eau. F5NzzN[~~Q=a]t?m9^`)r$2|-gfqm#FƨDg2t(g^ֳ p_/R\V|^J'PifCRvK3a)}>U]na`LMK^-uGvoʗqlޢ|-F'TZ<ZX\Zުئܦڢޞ؞|H!:Lbrbga=[&?|@}YSR'i)kŤӘ / y-oRVL U EcqBc`+8 Z75LI1w:&i۷@9!MlP&{{uH-j PY-uBAʗBę$Duh & \i T ALAM.frPDRv]ixIW1 i4R >/ Qt(rWtwR?]`OtukbP x=>zқ&U?Tڐc'baل}Ȅ^ae6c3h1~An=8N++@2C+`vnqb#zWeG 51 ] CϫHuZe2o![_:|6!T^O{KN0q)x<iʕO ^Z@bK4 nL`-ҧ]P*G*GSQNMJ FW.VpNulԑb˄ 1Տ /捺k]+~"Rsa+XJQTzaR `L6rUFJG;eY1=' ӕ ,* MT@lHyyDž%ff'6)xuGtu4887c8B#]yw$41SʤQ]mWzX д07}8D`*Hxt }29TZrRiB+KCda=RF労fw8]  pb)K%$t\ a .bPE33;CvwH8'D2*(U$R~_3hT uΕ|j],x0ue:2[ wUt| G9AC 5mww+2])D Dæ%fe3\2ldsrۊN{ ?g{$!( 1{64?ؓ;A|}*di'HetȽ\ g\6q9&fH9ؕsA T]e c(U 2CaBQP)mQAA!7J0IN2Ce8hP+ህe2^%=cB~3mX,"4M ;3 hHfdjT9lLZ b($ø٥P yBHkd@XP;{J/zWD\no>Ld~yMRϟQJ(zpmw@aR w::0t:ײMB+ ۪YK6~%}+)aJ8zijmdgO0y]Pge-kěC=Q,:|=>&0h-hz0{ᗊ QMי :_c )@)E^1N1G.QX^J;Nsv{BM-e<J)R-z(0j*\/0P,(ԥ=[m%z -O3M7(ϦK8("aRX.(qF-7~{lkaӞ[s-[e?ś=[k9ҳ ~qj1 DH)*`΁NjO@G]3ynJ,/LCMr6r-VUX57rFX̰(ՙF8}Tߕ{X8_^~$88ğ@6DWu?Gc~fbo(baϺ0\!=,p[+UG~!r+kL:Mep괎}er5H? 8QԽ^8;:{VyguRUdes W{y]5r|B(C&u:/yAA*WUo  \ꏓ׌lӬYuQWE0E]lhrK/)' V~i̬J|𬭉Y;\ [h)ErŢ_SLC["/SbHή3!L\aL1X L/о|5\]^޼IU?Z__?z9k0qvJUᏋfVo")VLW{>|m*ӿʔ?e8ID^[Zc?(_mF(k:ߋȉ᫤Ի z)M{6@&V$ czC'TDdi8B)P(whETÖ$`!lQln7gQ?o\vcr湉֦w].x&L4eVv.Y"sGfw.ڜXxFaߴ}㖖5X_=,V?%4K`^PqES#ODeeΕMM--!$"H&eo1qW6&gKP$M$lnʸ+'I_+Jĥf*%j}l\mNyF l0J}٥--|cG/ho9mMB',U6Sdzn `2Ʌ@jrk(M.rYxxMausG9lu{ %,%a:=K:cmɏ.IKa_|A>TC>DYZOҜ}I#Shr.i@ʷh; Qw勹`ߥ,V5lvmXUu_h赮ߏ3a!9& Ij\#υLdkhU->l4E=3tE{8\8遤&sFc*FރGv2sHrd%$'mYJ-\ҞNg̤!wiB2*nv BɜJ;9(|; !R>\oF L='`ݪS V_.W#{~Y-T)T\aVC}$cƚRoMa]J^dZ:2 T|.*$A6+p7CES2YΐrT&eDt)ʔώ0M5%hM0مLa>ࠞ -00,@gGr/+ƴq!ΆazbH1 4atNVYYZ^Q`;g_7] a\&hB8?,ai*qbH$ #a5"j5lwͽ}o4v 9_,wm7]x F,wx=3P0#AEPRҕe@a@sHDRρB#q e0X鯨c3< 2"Ŀ.^JVd[ڼb{]5Lotn۳!<.L"cC `cLӎ߄Ú$˞iZ|u ,:[8y[FK(vgNF\ߙX[/eh4g9ԕj ; .\ UW?EZ|FhN֤uJSM':TBԯ[Z.QG=pZUKi`^9北1/P{˶AkP!V%#q2)]aG}A Y2E%s_ V R$hիT׭`_x##5Gj_{5Ǜ+*V-o`&ֆ=kd6WnҰ鉜0ԔՓB3I-HQ#£*55g4e"ѤHo"iⴴU[a\F5C_SSmm42G}m(CmEH@SfF>H_]@u /[յv<kO30Ÿ9s0ƗtM)ɬuae1՚F"c=.*`]ɾPp0Pn uP5:-Ub]L 4ցƇ"PxsFD,+ύ*G}QhRCS7p+ uCvpAB5PG7P HRiڐ935L#80a\V{_"J-reی/"LگxaQ Խ̾Yv)j%̞Covse lKC~X–mJT7·};r֢Tƶ}zm>TqCE{2%ydx_,1q 8cو-NMLtNpo[{O $'YxV5̐pprgNNȮ \x7Q{1JaprY$ʘ+ajؠRtH`g\;10yq㥓|SMX:?ls:p/@;u; do/$#?R{sySD__`sK ߉B-=|cA-kyWۤd ]oя\wrgP æaٺJ":UwK.7QŜx)"׮5=/ŝg0EnHyRQ[x,inܢ|P)RWce&Ir_&bAQN+<)#>CPn\7<GA3`|vqQ$@oJXE%wP%CWS-ٔr`\u{ö;?=u?{ pd]8K#f7g ?RtF3?~ry}=xͺZ-o`fx3Y3c&N/ PLXw]/.`LG lUi%!M |>$ XR?QvӘw6hcZW%nܐU[W 8>{yvޭ&DGL>\@N,<Ů/ 'Jf}T2*M+'R0+a+yzbaY.(s:p-F [j2JD])V]y *\=#bs]Hc#-T3Agb{iA0#ak]/L`fSwp:Hŗ4CI1fPULc<] *IYsj3J90Q*9ǮK,Vbw^Sg_Nqhe#&-7n2l6`x \\4& a q9 Ήuu:4M C. IVT @1QL@"yu`XSK%s^ԁ%qfKFPK7N7G_wH'A"8p>=.3| ٍp&mlB2Db3LJIPFG _Gۣ| ՚4bR+( 1L x@Dll6e9hW0#|݇CNAͯ"F*TU1g_ )d$IUB\|[#5DG'sTxvb,?nY->ƵҴ6yG[\Y8&8WRʽWwta|x)熾q0'Em%ә6bD^ {@Rd΀E.̥MiZC/BfSI^ق 梙͜yfv(Cs)G) N=|xvGAn XPG|:n[ۤ)Hg@.Y):2 t1=~)K@|ExuΦ+w= Y[/ʩѿ0XLs薵reN!.oH}d蔰f^ pF@G\Hf]d=oD )[66+zmkYбL#x(zU坥\dX06#o{X0n-aXPbVKe -I0Uji7dO(s'sä:G@Ҷ3 JVsO6m AUh[?d`odT+$SZלNerlqţ~b c6CwjrtnM-ŭCS+c84":0&>_Z:DVHN圶‚ȯY* Y 8iڵ,eH|+6"Ÿɱ1?MBg O%)@X-PPwADQ4a.a?026<<}vȑ DSmZY9gG ɣ} kZI4븰KVWӇ\} &;}[xsj`X(V.LelRi?}&8 'HAzS:Ko=Wۜnد8`֦rcԟDQ?3< Ke<}Y^FhK5ktX3CRhry O H;-Y@A.nK Be262ݷ0hv*Tv~DUaW|yUjaC3L*zitdLOSK"Q3 ώs!)ml&uR?C+ ?A*i#sTu_-bi[-C>yOSDB#&_㥿5RfA,B[aq (XvymfX`*j]| o}`j,o>]GɮCϣ`; K%s;6-GrYT<Cqp^Kw2e0CKM8<;03"?f2إ 'IXr^6UqeJV?ԺuvGF}ӟY>`5/Z?i&a_@!?>^2:vRO  kj;uTlU֍]tի]3~Rby+-h 7лQуWnZљP5D?ADe0w8L_|ḫ܄Fܪth̜:ԝ;f@0Ҟ)(,gW˹hcI GO'Cu+,G`y]r< .>iwt6QY]&?*ezX`~@$򯆪'2°k0:NsYR 51]H aX"Br",,2vi^o%Ɯܵ&锷1d+Tl,.gu1n/5ؠ@ƭrרUscLi2k4iԾYɪS;MbSV*/af4^S' GL] n,X!U,=?TmW]q W|ӧXIL\Տ3_! @AϔGDj14 |d+ ܪ!#%ee&g!(Y'ot1f޻0fEgp\*&[ 71ٙOܾf{!9k48̐f!lG׭ kƑK(HY .ƨwK')2vNHSecɵ cxZ^D( *>AH_ a#hi?(, Gq\2x}?HxV%1" q!vFYJq+NNc[K\T3QysT+*/Kr',3J~CN7pZKA堼/(?ʃA92"䴍Fɍkˈ=uyqf*%n!XCBdi%]5ƴw#5U{Ec6u,~5"bAGoo0(G0nL^^GkxM5 aKE<^RSqBGPMW΋9~8:Ī_GfWZ^$g'zEͻ<4nd2LGqR,Y4fΚO%*tfVvӁm 9n&\1io1ڣڥ tUx^7a,SrHn]$xH V'yʳ'@,힕f,h,bIfc`0xw5|=LeN (9`p3Trrs 1* S8fNj[!0D@2ӡ0o)VⱢx)6≢x[<_ʩ}$+tgBp3/>*1+nnsWny۬n ^l$jN4'D]]nD!'K"kP~DnSڑ_`::  S:ٔ7MKًؓ{JLI!y232s=]-6;}ScE I=gtӯ5i|d a>m#v/5, endstream endobj 154 0 obj << /Type /FontDescriptor /Ascent 891 /CapHeight 670 /Descent -216 /Flags 96 /FontBBox [-498 -307 1352 1023] /FontName /KAAAAA+TimesNewRomanPS-ItalicMT /ItalicAngle -16.33299 /StemV 0 /Leading 42 /MaxWidth 1312 /XHeight 442 /FontFile2 155 0 R >> endobj 157 0 obj [ 250 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 500 500 500 500 500 500 0 0 333 0 0 0 0 0 0 0 611 667 722 611 611 722 722 0 0 667 0 0 667 722 611 0 0 500 556 0 0 833 0 0 0 0 0 0 0 0 0 500 500 444 500 444 278 500 500 278 0 444 278 722 500 500 500 0 389 389 278 500 444 667 444 ] endobj 153 0 obj << /Type /Font /Subtype /TrueType /BaseFont /KAAAAA+TimesNewRomanPS-ItalicMT /FontDescriptor 154 0 R /Widths 157 0 R /FirstChar 32 /LastChar 120 /Encoding /MacRomanEncoding >> endobj 161 0 obj 37597 endobj 160 0 obj << /Length 161 0 R /Length1 50760 /Filter /FlateDecode >> stream x `U7~}Nz_N:鮤;! K=A"a$aE踀:((3Q>qFu#R|}sOR=ҕ3|!C;BU-IoEܣ Z`?ضjƔ *V^8- [5CZ<q WYz`O^!tv °З 2!Jh2["t=^CHƊQOk .kە(5ybAN=,[ _>}aDp zA5{x&zFbQCP{AuȊehzEc4>YP:ѶIJƢ_Sx%О@p ~yg }4F=9h}( -G^|`SlOvwp=TJ֣؊d?~e1Z wmAgH+ۇxF5h>݌f\ˆHvLv}ˌC^`ي|++-8,')XO01aC$B$ O:' d,KjXI'Yz]̄bf>a~ż|MU,v){ &{Id{e/ȝ|||iye\ѨXQ" <1MFn \ؘvY7 #&'3Oɖ ?=2fEQ|ìƳsxetG"3g8ޅOX"|yP%قϐ[[FC^bFTwIM.e0e`Gmy݋>f|h7$6H#ih!A{O?~ FhXsh; Jf!uL;XY/VJмϠ ..!YpΕ=8f zedi p(xr:6%l2rNQ eFEV7ˆ&|80<5<|8+Erɿ])s|*.k||?3 w 4R{%u |mߋ[޺m=㊋azl`buq:@S^k0RXk+#:j{*܆ _8vk..c^CL~W>W! 鹣C ZcEE62^sv榱MWu2=e<7:}p^kT?"57yrO8PK.{U1@GO/wOfV;ǹ硞i"oÜ17Vwuc1 yԒ.iߏ+= LГ8 1k%̙+gg3]W|Q)NU8[OOlqs-" x/ꕇ&> ѷ,T]:D k8 ܀n;wΕѝ&-K_`k[7}a߾ԟ@%m~3VƆ*#i{H9==SzZ{gx.sibzkAcߟ=[wG3MTA;dl?y( 8])= bpR:dq_U U]]2T]U3!Xa.̙ˢ ]/ ]t.{ {i$#U*H!QI)a/K藖#,3ON4k]&Bĭf9ђR7vFS:1OJq8RRK~kyOp|l"Q^/e Փ'bbzF3txF@u`:og RҶXH>4Ͼ"aQXju<<} ơ<CԬ>իBFlǷ|-e܃?PU5hNDz^Or tf JG9v{uee̅?"rdI䧙)g?].t"nè~pXW95E5񅫝lrR\˳V,қRb2"ԏ,PZ ZKj/];^ѥ5.x=ŰEb!IW(6\RFd7ԣuFOn )>T?FOVC׏ovooj-eG^mo?.W۷w?mC?j}R=|7c-S/w'7tMqL.W TAnz5Y>xl "[pPG n|(,dihDZEGXXXъ#r؆~y~WC c^|ּPU.7_Յ' p][{z=7nn3ƭKFmسz,μ6~ۛ_?wvۨݹty}wAL3XYq~͵_Rve*CS,-PARA׼yOs^j 3z jU.݌ǨyAhufTqHcB.ʷL"7dFb>Frvwh7*@TF9w͸`PDA^ D#aRơ8yV!7޿xC{9&mɬM^ryһO<!}%!- B?nN!xR\rFޕ$=;[eŔ!EYy '݋w>yOo-*_rww2C/0>ލ^gi&-j?kgT)X֠4&Qa+ |&a춇[[ PzΔ.)3t2c֪_CPhB1Kwf*l4TydIݚyKStE4MY{QV8A څX:X* m-XAXKd%b..7!vӠB\È*L%VSUO6-լW\J6%D4 ޗɞ# &5/* v)"Gt4+2>f3/kl?^}CAƨI rKL~#\fɞBФy愬 q7:2_ L TD lH`}HS;LSHv}Fq2 i"r'#7 !Mfډ ܱeB+ة_jXI OaM攉*2ŘGc"URyF$F"X;/ܴtGZO\ *ǕMHqô_[5żym%;s~HA=}*-S@8*\C-&uSN~N9$ʀU&\[w|myQ"藎T22rW(eWZ^>yj/z8? v4^rv2Bx }u|]KXBWR >|гO>ف#ڴ:QUtV]opAAEjMH}VQm l?<<5aNT;Qs}g,3c`K?~[%R~<DO6TDM#Ѐhbm?Njɮ}Ť O>b KI931ۓT圿rQ2i81h`g` u%-TOxj+/c岐>VzI -&Uq{uno%hhD )$&PN NQRJVyGg9&|vq5T 7>N~9-9""Zٻ񨯻aszy= UC$1jaՉF4B-WŌJ&ǬVCVʵ:+hR( ar-dStXw??,dXRJղD%^"jT*ffӏmZ0n5`` rQvURQ%Ѩ Dp4ƫN'8uVF1vح5 :ic+I`C/uşfK/A`+fFGM͞e;;݊2RgV6I(s@/00r2,00,*28p̧@_}>OȉR주^`1 osdMD/r8 EZ@sASMӭd0`䔍ĝLnu]Y6-ݲfp>KX.f`l&֌U6֩k6nZ8")ݱ&?y lb7YnUʨ\Q)qܴ;lHF]>FI@b! [ ܸ)d̼Y0]}f^rsÞ.@ QF5TqK:R.ȍ!]8 O:LŠ*+Im|=۩bLIL+#s߭O<"/Y1i|]r۶gB_f'xrnv2MC㺧~4&r09{r_}$b}fhYv@Aî2P5V>o=BDCd,? c2:8LW,9O5v9E,NJl#ϐOvE!;qڭ0o*gYd'$x .PD!S̎aF-Y%gUC埁yxy$$j(MFV'74].GPW'yжDO{q"|:%tRc8TBz|Ew ҏD<𵑹h9^FGڒE7&w;e].ƛM;vZv)1gzx_&4~,YiBT4(S"#J+*yrY1:w ~hs9T&l_@[xN0 ADԂU2V{r I թ4 4V+ pQ^7e`*=1YV?x1j'w'H 9L+Px#-|압O'p6 %KJʧ7޹j[ͺ#v͒mfwWniXvT["i֛4{Bz9衩 '(brs}G6vlrF -f&, #OE )ٰx4 JVFzʏe8j"j!6@&ěS?^ @,*`Ăւ}lEQ95Qۣ?kѧ(B`'%j6GBgPiԆ+{umZQV~UjBIvJq; cBJh8.$恷 ~uK6 wG%IӘSoo+DӋ|Ȏ=O]kfMɛц}{,,CbzA'Yuf8$uKwA ("ԺȦ:+_>z T`Jx p*6_ƾa (Q3bLo. ڟ#;YZCn<,W@}\΃4da"JQKY nz"rpQ+0s`w *$8z;U#(W-M^fʹӤ1 c*A ,apjjvQ*/02YMS0m5cS١4 4ॣpnlpcww[eHǫNEH("E%@=DK`O$ Z>UU`dC)cQRj!MF*V+]%BM&%еC$4*H{=w"W\M %S f/ k_x?OaOcMB+]:~i~&A&QCyb~NQx4Y\8z̉3]- ̡yY_ղM?n9;y6ևxmCRw7b7B Υ氲f̘0dL Au6$ ; QōƣX<N1Aud|S xXӖ%%3gi 䝂St2NǬtabD2񀹒 ~g xm(L%B}/}?ljXR:9T^9~(0~B݄ |deU%U02(KFM\GLt#yu#ef-x!u'iwp!zLt#}P9v-T1ٍd1ZJ߲r[SǰPDnn ZUQ;fB ʚ$I|[q&,eMu0.NuIr`XPu5?g~O_oc>rN&y~&G/o%7zAǩ=*oOo0strGBet'4m,.ma'w*>/m9sJgӆI:nlk,7,<.[cM=ۼ4~8y[o=4}n8ϝ|kHew/0HTzSeqY%Q8nu!nsg纛b RN}gS8X{N( 23gړtϦ~݆7 6gKMBlW4HpOWC'xP U-0lG<ۓ{?r|[ӄmlL>P'?d={j|gXZ^IOѭ_TRI(ԸvɏC 6CRɗ;yK⥵Iٸ>'r1r[++*U*5u=Q{c4$TbecBi[zggmpMdSV=;]M|<]ެ4x*:-@2 Ob /(J2qLe)ZRNq12i3nkRtoly..ƼE%tx2X}˰ZgL!,-1T$7"-հ`^6pdg[ȇCʌB=iclIT6͠!v^uJMo9I ҠCihiIQ+N 8pN™$pI$q$ 'QO"O)SL5XD.Pׂs!<+K*9 x>Tg̡|`Y7Ï3CVwdJLzl}{og׼pjQڎcza&'93'gʟBvlRu:ugFzG-tU5p.<LIf8*e$Y%yJh yK}^a*Pi$ t+Brx \(/1faG>F,4g]!žAfZ:? <#;m H Z\Tzu:<.9kB#|k[POg>~.\Uv{*yՕCy3tԎZd0#lө`LˁlׯΔ5L ef-MPĬ̵3kRzM$؜ngٺ8GQ8; v[}C..{׮)Ntk[yX^~Kv2kΔ3@Mjd$+ǖ1Zf7.*Wzy&ub_@u}JA(ؕT\,;_ծR( Fe<Br ;P 9G j 2aWa̍G֚<# 5&/uoB)Y?'ꎄ.v/|Ͳgddx^1aNP`)6W7wCEk(~ hfNL9G0ɟg2AF!"Rӡ4ZtNTQ#9W6$[@}P@ y>gHQATppgp<|p6 2*j?)  Juo@%+h>j*:2MP65Iyhi5ZndzL9qdyLՐY?ǁDW6 oq{ȱ7nMUꢈɏU*/`c1ݔŽ2-Xũx10ak![6Zc1GڊqZ8 LbdeaupŠ, >QNOT,-M3鹯_vμy-Ux'v<9Tkܧѱ@o8?,K:׺nu)6NOE냠p: 9exW\2WQC%Q%UJ{ _Tm/|Q;Zh"р"|Ty'9&) Fq,{8/’C%s% zIކ+F }> W3gXZM8`4:M1+ЩໂV- X!%t*b/La^x⌍"=H d@AŠl $`^?VWr0R b0$~: 6: 3+%5emOuFlά򂍮eVVMՏWjOPoGQHF4~l-RbfbbbZK0I _\03Hp3LxB=] j:~8̗;FǏǃO?WlQ;) -W KBȲpiQ(D!F@$E`OpC'‚mQѪ`v)h1rr]4vd!QhrHS.m^P|OHd;ƕcLyJ)R(+1ߒ/Tt0_eOJyN3B1XS"O TscޙQ/?xؔvJxL7Q"(xPq %XEI |i?rEQs_8R?t2(kh^8ƥYR̈X4JQAv(@iNPiSu\&:⿿G¶֞՗G]^zo3gu[Ùͷ7i=[Ũ++]AfvӽE؀ D EXn *ce?ϖW;';6>1)dzTx]Y[_oh{vn]VCw{ ətI]JWNS2f,fy-((hR v#xaJTjT݄YܬY1g[,aah.[6|=5΂Y Tv:ۃ{3 _Pw‰VM؊9xN!o)4*>OǴz66P8w Di 6hD.a|H>}2>m@E !O3q\,(Uso|\UƟuP['%i5sK ]E:1s3&UԍT3EW"C3`ʈ-|K˃ kTIT` +bmiEՠ/( @*rJ'I ~.,-h P LMjl4+IPCی4C&Jv4{+Ƥ<h橐ܶmџ=όLyawCه-wd_Xau`c:ut~˒UL}Co}WsJyc3}ݛ ?rd)V;99xY^Q&|վnǝ PQPP~rF4C^V}f` JITt(USIJM%i:j<7S$,/`8IZ}">)Zv$ՔR01 I% QS+`^2! 1jn:7XD)?eh1wL =OGESaN69Œ`K8Vo^9qdda\H0}|Pڊ3,TT^),h`CP4P FGt4 k5 D|Wsp%LvP-\"!* !FQ:nD*5-4RT*M+aR-0ʋ1/,PP9XW] ]' +xyDN^"'7u5ԿJ 9`Sx/퉋?4ސD@^`-BPa j#_FP$ 2RP1j`E[E͔TY>H3\ WͥD4Pk:ϮQPiIo3qR~RR[(W%&&*yXSiڨ9(pF#%#%Sk&8gțMfu$(Y&_Xis9W$׳4[\u;=mm{4?3̶DZyO=哪'5O:8t?S)OG*\vOjK,J JjbbeWMN'fTiT4*h`Hj4.KU-Q5W]72t *1FiR*4XLG HFu tkdNHr)*;ّ4GΨIkt"%tϩQbTZumNj) w+V*%rL|Ut %[b6EQpѨՐtW+Ec]G2Z;%gR YD(*U4+i-ivJ.(K+?UM894!5Q{ʑdy1B8xΝqC%716DU`364P}C9|jG++a"@hHܼ(̠/k3i [،0 ސ) %%J( QR6Ɠ(`fU6v$VVQ5EyvpT1f1)r[£dCTK.5 %ɐtw^[6LJo!/F e(ߡB4u5C+|Y R}T^9"ͅ>g &]^ĹF•x'3yǙjĘXPUHGMǏs}L8^ %wLj.ԸL 7`,O$FqIG#Bl9MFObU5#,4k t|45G QVq<22s4]/=& ϼKʣ\!e_QvP9*!XVvQ`#;#r\|E~ "DHc=QDGvbp6*fslmRLHŕC=<2\ I[i.6C YI$jG+eam  }X+hM hQ$ OcEӪ2']iEr!sǘĤ0I4NrϚ?49t%`5bQi@ _\w%G5e9d`Pk3<3眜$9!pv L (cVJZJm%ZCZB@5mV*^kjRVK}muNP^kxg~K mS9EYmKϞvI{t:)r[T`A$BRg4~`jx8!g%8oc[Z^k!ď.q #lդqQ֎CAu|GlɈ+B`IaCh  C:ʻrӯrGl/%󑠲BXrLJu׌kګ w6B!ý[}*9X )6wӑZLT89qysBj3F/kdXk]S.w[Vgs;gyKkzϝl}??R^sg߇/aO}&8 s1j:r 7lBn48 M1ƛL>Ng.Elr 9+8>Sa-h{k:zI:7Vy D8)4t.)`᪘:ZQ"5bgßtK<,)Y,`h Ud7 @K2 9jCC U)(s'rm쳚g9;ҿ~_e}z s6\S^om,2⻇/6)=%[|L[yjɠ 4"P/֏۔NfW11 h ]}@{a_НY>|ױq{vy,~*i,D20u)XLb̍Gc83. /=ItT)2^{.jb&Tq &i G~5ps@w.OieTk-8,~Y,A3ן*fSpԦaExCxkXވс L9~@Hft꠳fMϙN@l3HxB+9w6?,ʀݤK7u8oVv?gW_bSŔho@܈Bз!qWT۳f5с P =eyxV, d.hT>BZrq9i^8̸S[ t It<dw9GlӄLjΘE` Njpx64fJx*1z8L^3'ɧfP,"3bE| 9' UZa~ yU^! |ژwݑM_PZ8VޝTV澮E2& wSNODYw]r||jFyB=}ޘ9ӦnG=ݡH'ӌhQ1\8#1^{Dϛ uJcd`Gd3[( 8b mC׆qDHTt2BNMFY:Q#Q@2S4RGb MhjXkJlUKvrBc_?o `y ƙSM׆⚅&^wl_=YRhg~8LS<Lgty&r`%nTFFy H}pvKj(vc0iגwB\0MG "h1& D(8<,PljKr(lg9 D@v!wzu%mZY;E{`wTSpiŭx5)p+{Ro E ]p||Ϻ{YоG׋/@ A 7(-(y{E}58/ #^⺀Q4ZTjv_jmgþG/l;-thGtx]jbӚ?/Jz)̔6"q?R\Jv9wv~O=!ݣI/N\cZh=7SMߎ&!ܮr 7L n71d0O9zIY(70<`a<;<=5F:$&Ikt?U.+)8-. EH,BOǷ,,Q/`/|2 :abmQ Qܛܠ) if7o2=jn8taAeP6@4=!*S^zg|One{ٌ¥UCCCNMU{3c6 V0,aƍu{>s+{Hmoh[q8k)׮gwo2й&ѡ|4Q H7(D]mv'ՠ O YLGs[Yq8f, 8AHFXpqrr6]9 겄Eiv4фMÈ{J8˒yfih2N[xI1X/sbi.BsӸQA$W*nvߝzNiI}v5 ݄>} Zq~8'tW؁h<2y /쉤7gv mCߝbC̦3Ym_ZYuH+;;uRMV6&x@S'Z8fVy%Z+tF-hޒy`.Hdz..m= R/ sgI9RaH9g$8ڮn(k nUuڷFF.}a w5|wRV=lc뎯;.--NOb +BdSVM\T9y\K*m"'PFň$N' ARyK)xGUu Sp?yعp<\WxJRr=7,gAlɚ=Xch7sotg^ݻu`% [f+6vn|-;;/{mGF Ԛ%c].kUZo`󆯬nnMEx[nX;϶I6&X#: 6qwmm w`уn }7p=nB2g_V({*ZJ7䊃1~X@ E].B:xK z |X7B+ $J%-bᵖ,&< *'a|N(k!=َ< e8 "229h率74:k6_kmp92!# +qP)v 9ct5iMuw&;;uH9 .:_6JkFҽule#CE)KBwktdn3} M0j0}hi14*3JA46]./wрhag.q x5dmD:e;|bkLB4p:VIs#?b:9,$Dt9c\1Sξq99"Hh ތ9UhY6;^|Fdxcb; mAr NrfN5"W$ς9Lvn&e>b|K9q5 ޮTHܵG#MNzw$|0CѨ4@oVh%yQ> 6M'$N%rb !*Ij ;AT+[gFi&8^ O0ڵLkԂUR>9~s§xpr:[}lF|q$<8SSӁe#* v VT.Qh&y09s|=`A*H 0:U_?g&vF^U _~kbdg7,bջYv'gQO hTAgBm }[Z=V4^BFkTd :@@e= ;J;ۋGo4sO{9J{ɜTrC{r;c9Ɇc9)ˤt$W :zPΚ*n>u\骯0d 9/\[.y MD2ʌ2$%YCf7 O%F:w!wD,:VJ* wrub;rMB5 Y!@X(6 31人rg[ӄHcCf.{x٬]\ej0Đqڥj E 1=-z<}:j(9:- BH DCA$*FV@mL5~IQUʀԠq#@h P )sq)?~h< @yg7ʝ3PZCm?*@Dni`N2-hdT[Ѳߩa8nz^=щ~/mնMM{EQqLY77'q*+E-mV]QI9U,C#`ӺmJYffS//L3^ G Vnu5bjVH VW:5~kW`6Vef i4nBO e25 cqS rG {q4Gq3'YN? WuQ1ݥH[yr%3Q>ld"DH`娓Ң` ~,Cp 3Mc&37ixeD# FHB1rSXaɟF:ʇا0AagB޶$Emԁ؍沟gl1-5 V vV;a˖ͤR3ńMLӆi%2Vn J#-YZiudrZZ5Dcu}5%g)."5b)vt%u `f?3Eqjz;`=C,th1$g uX"a7zcK'qZ0;\5/ NeLDkXq) AϜ@JH"GhQ'W? C N\KG؉' k9)䴒( A[ R<ܰJA+ɫɄL\Ƅ Vyl;=WRt2ycۀ)b{`֔h{X6IgUx$ 旡Z 洎؀FM=S&iJWeQqd\q e@uLRX@Zw߽#̩Iw1:i,lou;y!.Ok\*GJqc5/Fu(1{q7J2ufC QPR`.,OsIគ yiхVntv;_5FU!5bk&udؼp U╃ )M;efq/78K]@aN`Q]jG5P<I#xsk ՍZv*iC]T9Y˵wn׽ gV|J45xmo_m>_Ш 4G-ZS8nikÓ9Hl'S'H#^QϾh"7TBcCHc`>fq| ڳ&4cݲldqo=Aqˁx.)@;Y2/>^޽22أ˶/WٌN&ZM?L2o2Zx7!PBk٨<)PЖk{Kt4v0ZPJK>c]}MJ8>^D9o?Mo.+q\Fiqo-:'NH@}p"Hcj^sB&UNh{0G'a~0D8˥lYN2;`(t#4yNfK5*t}YMW" X@xIݠbMf4ɒft$N:KRXFU\6IKo<īt}wc'$ě[MV$:6cV('tT0~RAp>@nDˎg'!~zLHkUKU/yC IՁىL0Xf\?I k#ڬX&#{6]Ʀ3sJAսEM3Vu4sꨟެ?7^ c-V޿$@ hgV!,jTC M(u626TAj 5:U| i[TiJZX}hd4.@' *8 !Z@a%@M*b2E_h`57!uBǘ=9{V$;Dгڽ}Q64THb"ʞv?([}n7UmT#QոjRQEIb*il9&o2orL$E#4li\B@jKj~F#X뗡icarHcHjRvK, 3--&`O2@6qFÍlm /Sևlr ,7U-<\" >onE'>wg\,ֽ`߯w33_!Ygzki,`-;[7#>_`̍A9]4j9TML>B1)$-mC[8z h6p?D6@@G?F g?x@0 :͠0OqBkadXoi藮تrMvaZphiU  @dMݲ/= *p^fO1wmJ@/ɭ"Zd$pIlSḾͱ/iz/áGr=?ؾ{+~^nؚܚ ODA5,׊'WB4j!+ QGl/ނjSAon^xp 'nrrBqɯ/qz '$=q]dLIWUcSĊh%*a k$_/}k2n&};|n[_Tgns4I w~Kr(q~'?=<`Cw,>ʰGkXRӜtٶڜloڗ&wC<LnQߠFhfA>ݶЕhf4ȷT q%6=!ҤjKK {wq)ZSfE4|t B*BL`mV5TEX}m@~`# &*"jTLH?P~G_8j{5Ǭiqb}zO>ZT'=1r-㒈KOZ[: 5ui jf->G@E؎p/,<NVEy7\C{m_M Z8;eGZF[Z4֖CLVnז##1k%'wni=c] fA$Aф gꞍB@*6[^ #g{--~*ޖץB)"<)FX!?rS“P`$ 0[@@OBPh*kWP(755G.O>1%l$bʣ/MA}! DpUI'~-ZbrP,"npa`[.l,C,fO8ܞH"Хpj e6gC "m[mެda8VeQfhvO4Y]SQڌ:D8j'|׾k{~pTEM҄{<0]D 2/Ob{dS_gQ1E<2e(Vr]y^iCGL啿Yg02Jd ZEA眂QY| .p ƸcP_ g 8;66Ç.Nfr. S-0a aaQ5vq"ܾ4}h "u2|BS<C|.u#P O1"T*u5dcNۜi1q9zU[I,P9Al'q)p}-:;H8ͅDqh d/ؒͳc=5_nͪ~:ohh^6sɆ 1ϕKRVi)3WX+OڈXgF9S ("GhCwj! jFE47!r$fO/1&-Q2XgT%㑰e5TVk `> Lq%5# Ő$O! /R2=L%MiЇFb\p IxUmƥؐܟ s$ (B0AYiZ!&ӪVc{S^]":g?qH2ץY6둍0R/TxOaQOd1 Fc;OYI B2&O#0s 8ͤS"kKNuRx!|n\$C@q0<^ܨ[Jx8,$DN[<@$mT4myẛ.ߜ/aC5}WvFllAhuaSNy]m^"ӁToԂ _IP,+jUXS.HAF COb:Y: &'RqjHhQ+8lo(uEΈ0VW<4Dv'7K_MxF4w-z K*[<,>ө2ɨƪ!@ O5lhAa=}!(*!/~?B0G3Ѐ Q?ʬvڳ 'Xm60 R'C <I>l0}scCq8ŔbooOuc@ fbcSS3{\:ecΖn2;=fGQN')n?p 0Ak]t`Bӝ&;GdVus" m"]P-n=1(G+=@k%a%7 ܗ@ SnsNMy|o<8Y~jfaIOOUA+ MhSBa?rGy{7>?4Bףwm7VgֵhQ ܮxY3F#f{Lq~2L@+f(xbx3&ݦOQ}+Y@ ZIJ>qTͨq{HFl"$ ΣD(@+{l6|; #c9%nJdAxTF~ttr)R(v ]n;{(t&aw`h?Yq)00PT)MȉsNNFOwߒkkJ4 n?rIyf0D0vGj y}Ͷ+p|u[9tCH,^#G}i1Pןjbz4j^>f00IDΛXț"5y*KRײvzF_\>H EksW0\,!xES 7\T~a..7_=!k&$DkD~J'z 's8>Wty~PxO 6]Vb6W Hm:j Ԧ)9۰^o{kQ¹`'=g|%/-'22|FyA-?s"W]૷#7oZ[f屪sS5VXIN1fv74^=jr>3=βX9c,Nt+=_=J' Ʋ|[^.=HdlÇf~Ccsy<*gMϼ~rL:<ͬw+o_4B@=OO)x_,ri`#4S2myhNg7f^b< A3JʣBRz܃s%jH05Wν H~aJ@ϬrZAs }s^(I-Z̠7W] ɘd.-Od |k7>Ju^8/d䚖l|ggPBP}W[S8tQ`b$f=}g|#  ە ~37-ۼ_|,T֘;X$Ab26UB ??WuZQo76}-xR;ycq[j;!Ο5ՙu#zi`4<O}mXq׎sΙ#st\-Q9qYk\ C#v })p˳5yt";nx:󴱙jx^t) G >J}5‘_˂X PUX"\eM(cfX IP{pMJCE;^Uq),ԣ]cYmcyOt81>K@8(Np/R^^k=Ōg7mG{.ӎ e!;76 "7pͬǿقׅ0؈RwEҵeյԿDDg=_b1^d4]a~M?8?^h0ygKc;D/׷`*BUVzSPc`Q j.ȭKwlOX|41a# 16aݴ v\)70w +'SS.. ..Ti BN_B%Mh:ND =BaXX:BLX.N a07\-:B$1] 8,/G+n0"!LH^EQʟO(gQg߿paruL0 ]!ҫS ?kjc}Ce/(U3? Ou $GzEDEzy"<JzN{vlo)=OJ֎h~y>v|r嶓at옛c0& cnWi~[i`kCQ$|?41I<({hO1%]5._V+OHS+eP4pOo @lR4R>z^?nA4 BE%mJK !vvU=DA€ltGczr\6^I!$ʋYaIMbmg 5-=IQ=לҨeMF hF418J)88b5%ʍF8`TGlON eeEo<~Ye0>EgC9qjY1ΊqVZkE-@AEq-QQBѠqԂ^ ߂~Pzgƞ{f:&~'a+ H8Zlg5֎t c Y6Idx)]fī'367%7e6ݯ'3*JܯP)ޯ"g`4_{eO-{~jx٦e;Ipś?k u]Gvkq/^g WQ$+Q*(PT^l#}((jηbKOyUď?lF@AXl+(4'={P)x$ s`E XVӕEQIkoZ|~(M`tunh C|{ &K^Ozͷh sZ7N*c@ۜ6j^!1Жɷm^q+fkys<7F0w͢oe_^M)ƨyu5w} π\m !z `ȦC+vv;zLu-Fuf>T3cwH`IcN%ND4[eK X>K㿋w:ma?oTީ =ЫoLOΩ.T__jT𪩮h!:Hc7dYH.\ՓN!`*ބ*MOcSqa!n^BfoKM?h$ODwߘu dKa\SX`7'HbC:x*HdF#ObF/>G(~ꉮѻ؟~6cz *ϋ.z8(+]bvƷD8Ė8ڔ8D҈k<|0Z;ģ ?.ئj/ѮҞm6 jXҺt D1tt 3s|Kdc1c>7/lſ߸a#񅗢L~ɱKdyyRJ\ /tK{&7{} tx>a•kmP.홺Xxa➡X{:w;ɽvн{^}t>^}g}kdc0 F1'Lqe˘4OQh4t7t!N:dAv9!`| 9֭Rٶ- 18%.:ɮɮH'n-X؞zKԵkwD.mSTO=_'mQnno\5Q:i]t+50[ V\ۆuP y4q(jJ;Qz$;>ycJ_VW ϫ]Ͱ|o 8By(@QKR38 [!0ܶ$\5w-#!}V( (/@Zyn) ޽N=pnB endstream endobj 159 0 obj << /Type /FontDescriptor /Ascent 891 /CapHeight 670 /Descent -216 /Flags 32 /FontBBox [-568 -307 2000 1006] /FontName /CAAAAA+TimesNewRomanPSMT /ItalicAngle 0 /StemV 0 /Leading 42 /MaxWidth 2000 /XHeight 454 /FontFile2 160 0 R >> endobj 162 0 obj [ 250 333 408 0 0 0 778 180 333 333 0 0 250 333 250 278 500 500 500 500 500 500 500 500 500 500 278 0 0 564 0 444 921 722 667 667 722 611 556 722 722 333 389 722 611 889 722 722 556 0 667 556 611 722 0 944 722 722 0 0 0 0 0 500 0 444 500 444 500 444 333 500 500 278 278 500 278 778 500 500 500 500 333 389 278 500 500 722 500 500 444 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 760 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 0 444 444 ] endobj 158 0 obj << /Type /Font /Subtype /TrueType /BaseFont /CAAAAA+TimesNewRomanPSMT /FontDescriptor 159 0 R /Widths 162 0 R /FirstChar 32 /LastChar 211 /Encoding /MacRomanEncoding >> endobj 163 0 obj <> endobj 164 0 obj <> /ProcSet[/PDF/Text/ImageC/ImageI/ImageB] >> endobj 1 0 obj <>/Contents 2 0 R>> endobj 4 0 obj <>/Contents 5 0 R>> endobj 7 0 obj <>/Contents 8 0 R>> endobj 10 0 obj <>/Contents 11 0 R>> endobj 13 0 obj <>/Contents 14 0 R>> endobj 20 0 obj <>/Contents 21 0 R>> endobj 25 0 obj <>/Contents 26 0 R>> endobj 28 0 obj <>/Contents 29 0 R>> endobj 31 0 obj <>/Contents 32 0 R>> endobj 34 0 obj <>/Contents 35 0 R>> endobj 39 0 obj <>/Contents 40 0 R>> endobj 44 0 obj <>/Contents 45 0 R>> endobj 47 0 obj <>/Contents 48 0 R>> endobj 50 0 obj <>/Contents 51 0 R>> endobj 53 0 obj <>/Contents 54 0 R>> endobj 57 0 obj <>/Contents 58 0 R>> endobj 60 0 obj <>/Contents 61 0 R>> endobj 65 0 obj <>/Contents 66 0 R>> endobj 68 0 obj <>/Contents 69 0 R>> endobj 71 0 obj <>/Contents 72 0 R>> endobj 74 0 obj <>/Contents 75 0 R>> endobj 77 0 obj <>/Contents 78 0 R>> endobj 80 0 obj <>/Contents 81 0 R>> endobj 83 0 obj <>/Contents 84 0 R>> endobj 86 0 obj <>/Contents 87 0 R>> endobj 165 0 obj <> endobj 166 0 obj < /Dest[7 0 R/XYZ 72 744 0]/Parent 165 0 R/Next 169 0 R>> endobj 167 0 obj < /Dest[7 0 R/XYZ 73.9 693.7 0]/Parent 166 0 R/Next 168 0 R>> endobj 168 0 obj < /Dest[7 0 R/XYZ 73.9 466.4 0]/Parent 166 0 R/Prev 167 0 R>> endobj 169 0 obj < /Dest[10 0 R/XYZ 72 744 0]/Parent 165 0 R/Prev 166 0 R/Next 170 0 R>> endobj 170 0 obj < /Dest[25 0 R/XYZ 72 744 0]/Parent 165 0 R/Prev 169 0 R/Next 176 0 R>> endobj 171 0 obj < /Dest[25 0 R/XYZ 73.9 514.3 0]/Parent 170 0 R/Next 172 0 R>> endobj 172 0 obj < /Dest[25 0 R/XYZ 73.9 396.4 0]/Parent 170 0 R/Prev 171 0 R/Next 173 0 R>> endobj 173 0 obj < /Dest[28 0 R/XYZ 73.9 730.2 0]/Parent 170 0 R/Prev 172 0 R/Next 174 0 R>> endobj 174 0 obj < /Dest[28 0 R/XYZ 73.9 215.2 0]/Parent 170 0 R/Prev 173 0 R/Next 175 0 R>> endobj 175 0 obj < /Dest[34 0 R/XYZ 73.9 542 0]/Parent 170 0 R/Prev 174 0 R>> endobj 176 0 obj < /Dest[44 0 R/XYZ 72 744 0]/Parent 165 0 R/Prev 170 0 R/Next 182 0 R>> endobj 177 0 obj < /Dest[44 0 R/XYZ 73.9 610.4 0]/Parent 176 0 R/Next 178 0 R>> endobj 178 0 obj < /Dest[44 0 R/XYZ 73.9 383.3 0]/Parent 176 0 R/Prev 177 0 R/Next 179 0 R>> endobj 179 0 obj < /Dest[47 0 R/XYZ 73.9 730.2 0]/Parent 176 0 R/Prev 178 0 R/Next 180 0 R>> endobj 180 0 obj < /Dest[47 0 R/XYZ 73.9 498.4 0]/Parent 176 0 R/Prev 179 0 R/Next 181 0 R>> endobj 181 0 obj < /Dest[50 0 R/XYZ 73.9 646.9 0]/Parent 176 0 R/Prev 180 0 R>> endobj 182 0 obj < /Dest[53 0 R/XYZ 72 744 0]/Parent 165 0 R/Prev 176 0 R/Next 188 0 R>> endobj 183 0 obj < /Dest[53 0 R/XYZ 73.9 292.9 0]/Parent 182 0 R/Next 184 0 R>> endobj 184 0 obj < /Dest[57 0 R/XYZ 73.9 730.2 0]/Parent 182 0 R/Prev 183 0 R/Next 185 0 R>> endobj 185 0 obj < /Dest[65 0 R/XYZ 73.9 497.6 0]/Parent 182 0 R/Prev 184 0 R/Next 186 0 R>> endobj 186 0 obj < /Dest[74 0 R/XYZ 73.9 730.2 0]/Parent 182 0 R/Prev 185 0 R/Next 187 0 R>> endobj 187 0 obj < /Dest[77 0 R/XYZ 73.9 497.7 0]/Parent 182 0 R/Prev 186 0 R>> endobj 188 0 obj < /Dest[83 0 R/XYZ 72 744 0]/Parent 165 0 R/Prev 182 0 R/Next 189 0 R>> endobj 189 0 obj < /Dest[86 0 R/XYZ 72 744 0]/Parent 165 0 R/Prev 188 0 R>> endobj 102 0 obj <> endobj 89 0 obj <> >> endobj 90 0 obj <> >> endobj 91 0 obj <> >> endobj 92 0 obj <> endobj 93 0 obj <> endobj 94 0 obj <> endobj 95 0 obj <> endobj 96 0 obj <> endobj 97 0 obj <> endobj 98 0 obj <> endobj 99 0 obj <> endobj 100 0 obj <> endobj 101 0 obj <> endobj 190 0 obj <> endobj 191 0 obj < /Producer /CreationDate(D:20090428233305+02'00')>> endobj xref 0 192 0000000000 65535 f 0000479725 00000 n 0000000019 00000 n 0000000780 00000 n 0000479889 00000 n 0000000800 00000 n 0000002233 00000 n 0000480035 00000 n 0000002254 00000 n 0000003946 00000 n 0000480199 00000 n 0000003967 00000 n 0000005620 00000 n 0000480347 00000 n 0000005642 00000 n 0000006325 00000 n 0000052437 00000 n 0000006346 00000 n 0000052414 00000 n 0000126438 00000 n 0000480495 00000 n 0000126461 00000 n 0000127119 00000 n 0000127140 00000 n 0000131637 00000 n 0000480643 00000 n 0000131659 00000 n 0000134270 00000 n 0000480809 00000 n 0000134292 00000 n 0000136485 00000 n 0000480984 00000 n 0000136507 00000 n 0000138328 00000 n 0000481132 00000 n 0000138350 00000 n 0000139807 00000 n 0000139829 00000 n 0000140503 00000 n 0000481280 00000 n 0000140524 00000 n 0000141091 00000 n 0000141112 00000 n 0000212250 00000 n 0000481428 00000 n 0000212273 00000 n 0000214118 00000 n 0000481576 00000 n 0000214140 00000 n 0000215945 00000 n 0000481724 00000 n 0000215967 00000 n 0000217106 00000 n 0000481872 00000 n 0000217128 00000 n 0000218975 00000 n 0000218997 00000 n 0000482020 00000 n 0000230105 00000 n 0000232382 00000 n 0000482168 00000 n 0000232404 00000 n 0000233080 00000 n 0000233101 00000 n 0000279412 00000 n 0000482316 00000 n 0000279435 00000 n 0000281946 00000 n 0000482464 00000 n 0000281968 00000 n 0000283791 00000 n 0000482612 00000 n 0000283813 00000 n 0000285175 00000 n 0000482760 00000 n 0000285197 00000 n 0000287173 00000 n 0000482908 00000 n 0000287195 00000 n 0000289611 00000 n 0000483056 00000 n 0000289633 00000 n 0000290857 00000 n 0000483204 00000 n 0000290879 00000 n 0000292084 00000 n 0000483419 00000 n 0000292106 00000 n 0000292835 00000 n 0000489993 00000 n 0000490191 00000 n 0000490403 00000 n 0000490550 00000 n 0000490666 00000 n 0000490786 00000 n 0000490906 00000 n 0000491026 00000 n 0000491146 00000 n 0000491266 00000 n 0000491382 00000 n 0000491498 00000 n 0000491617 00000 n 0000489724 00000 n 0000310500 00000 n 0000309905 00000 n 0000292879 00000 n 0000292856 00000 n 0000310139 00000 n 0000321664 00000 n 0000321134 00000 n 0000310699 00000 n 0000310676 00000 n 0000321375 00000 n 0000324910 00000 n 0000324647 00000 n 0000321867 00000 n 0000321845 00000 n 0000324885 00000 n 0000328194 00000 n 0000327923 00000 n 0000325109 00000 n 0000325087 00000 n 0000328169 00000 n 0000331492 00000 n 0000331225 00000 n 0000328398 00000 n 0000328376 00000 n 0000331467 00000 n 0000350355 00000 n 0000349640 00000 n 0000331704 00000 n 0000331681 00000 n 0000349890 00000 n 0000366604 00000 n 0000366083 00000 n 0000350565 00000 n 0000350542 00000 n 0000366325 00000 n 0000383304 00000 n 0000382796 00000 n 0000366808 00000 n 0000366785 00000 n 0000383033 00000 n 0000401060 00000 n 0000400537 00000 n 0000383503 00000 n 0000383480 00000 n 0000400767 00000 n 0000419489 00000 n 0000418976 00000 n 0000401266 00000 n 0000401243 00000 n 0000419228 00000 n 0000440488 00000 n 0000439937 00000 n 0000419703 00000 n 0000419680 00000 n 0000440199 00000 n 0000479180 00000 n 0000478394 00000 n 0000440704 00000 n 0000440681 00000 n 0000478641 00000 n 0000479366 00000 n 0000479550 00000 n 0000483567 00000 n 0000483627 00000 n 0000483812 00000 n 0000484073 00000 n 0000484338 00000 n 0000484573 00000 n 0000484828 00000 n 0000485118 00000 n 0000485361 00000 n 0000485592 00000 n 0000485831 00000 n 0000486091 00000 n 0000486350 00000 n 0000486580 00000 n 0000486827 00000 n 0000487094 00000 n 0000487433 00000 n 0000487719 00000 n 0000487950 00000 n 0000488180 00000 n 0000488443 00000 n 0000488786 00000 n 0000489081 00000 n 0000489379 00000 n 0000489574 00000 n 0000491736 00000 n 0000491854 00000 n trailer < ] /DocChecksum /BB158D746E9C84C84A70627F97B60328 >> startxref 492022 %%EOF knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/0000755000175000017500000000000012475375714025522 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/0000755000175000017500000000000012475375714031525 5ustar felixfelix././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/manifest.mfknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/manifest.0000644000175000017500000000066712346515440033332 0ustar felixfelixManifest-Version: 2.0 Bundle-Name: dateserviceuser_bad Bundle-SymbolicName: org.knopflerfish.tutorial.dateserviceuserbad Bundle-Version: 1.0.0 Bundle-Description: Demo Date Service User Bad Bundle for the KF OSGi tutorial Bundle-Vendor: Knopflerfish Bundle-Activator: org.knopflerfish.tutorial.dateserviceuserbad.impl.Activator Bundle-Category: example Import-Package: org.osgi.framework,org.knopflerfish.tutorial.dateservice knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/build.xml0000644000175000017500000000174412346515440033341 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/src/0000755000175000017500000000000012475375714032314 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/src/org/0000755000175000017500000000000012475375714033103 5ustar felixfelix././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/src/org/knopflerfish/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/src/org/k0000755000175000017500000000000012475375714033256 5ustar felixfelix././@LongLink0000644000000000000000000000017200000000000011603 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/src/org/knopflerfish/tutorial/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/src/org/k0000755000175000017500000000000012475375714033256 5ustar felixfelix././@LongLink0000644000000000000000000000021500000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/src/org/knopflerfish/tutorial/dateserviceuserbad/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/src/org/k0000755000175000017500000000000012475375714033256 5ustar felixfelix././@LongLink0000644000000000000000000000022200000000000011577 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/src/org/knopflerfish/tutorial/dateserviceuserbad/impl/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/src/org/k0000755000175000017500000000000012475375714033256 5ustar felixfelix././@LongLink0000644000000000000000000000024000000000000011577 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/src/org/knopflerfish/tutorial/dateserviceuserbad/impl/Activator.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad/src/org/k0000644000175000017500000000226112346515440033246 0ustar felixfelixpackage org.knopflerfish.tutorial.dateserviceuserbad.impl; import java.util.Date; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.knopflerfish.tutorial.dateservice.DateService; public class Activator implements BundleActivator { public static BundleContext bc = null; public void start(BundleContext bc) throws Exception { System.out.println(bc.getBundle().getHeaders() .get(Constants.BUNDLE_NAME) + " starting..."); Activator.bc = bc; ServiceReference reference = bc.getServiceReference(DateService.class.getName()); DateService service = (DateService)bc.getService(reference); System.out.println("Using DateService: formatting date: " + service.getFormattedDate(new Date())); bc.ungetService(reference); } public void stop(BundleContext bc) throws Exception { System.out.println(bc.getBundle().getHeaders() .get(Constants.BUNDLE_NAME) + " stopping..."); Activator.bc = null; } } knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/0000755000175000017500000000000012475375714033262 5ustar felixfelix././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/manifest.mfknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/m0000644000175000017500000000065212346515440033431 0ustar felixfelixManifest-Version: 2.0 Bundle-Name: dateserviceuser_declarative Bundle-SymbolicName: org.knopflerfish.tutorial.dateserviceuserdeclarative Bundle-Version: 1.0.0 Bundle-Description: Demo Date Service User Declarative Bundle for the KF OSGi tutorial Bundle-Vendor: Knopflerfish Bundle-Category: example Import-Package: org.osgi.framework,org.knopflerfish.tutorial.dateservice Service-Component: OSGI-INF/component.xml ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/build.xmlknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/b0000644000175000017500000000200712346515440033412 0ustar felixfelix ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/src/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/s0000755000175000017500000000000012475375714033445 5ustar felixfelix././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/src/org/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/s0000755000175000017500000000000012475375714033445 5ustar felixfelix././@LongLink0000644000000000000000000000017100000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/src/org/knopflerfish/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/s0000755000175000017500000000000012475375714033445 5ustar felixfelix././@LongLink0000644000000000000000000000020200000000000011575 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/src/org/knopflerfish/tutorial/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/s0000755000175000017500000000000012475375714033445 5ustar felixfelix././@LongLink0000644000000000000000000000021100000000000011575 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/src/org/knopflerfish/tutorial/common/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/s0000755000175000017500000000000012475375714033445 5ustar felixfelix././@LongLink0000644000000000000000000000023700000000000011605 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/src/org/knopflerfish/tutorial/common/ServiceUserThread.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/s0000644000175000017500000000216712346515440033442 0ustar felixfelixpackage org.knopflerfish.tutorial.common; import java.util.Date; import org.knopflerfish.tutorial.dateservice.DateService; public class ServiceUserThread extends Thread { private DateService dateService = null; private boolean running = true; public ServiceUserThread(DateService dateService, String threadName) { super(threadName); this.dateService = dateService; } public void run() { String formattedDate = null; while (running) { Date date = new Date(); try { formattedDate = dateService.getFormattedDate(date); } catch (RuntimeException e) { System.out.println("RuntimeException occured during service usage: " + e); } System.out.println(getName() + ": converted date has value: " + formattedDate); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("ServiceUserThread ERROR: " + e); } } } public void stopThread() { System.out.println("stopping " + this); this.running = false; } } ././@LongLink0000644000000000000000000000023500000000000011603 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/src/org/knopflerfish/tutorial/dateserviceuserdeclarative/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/s0000755000175000017500000000000012475375714033445 5ustar felixfelix././@LongLink0000644000000000000000000000024200000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/src/org/knopflerfish/tutorial/dateserviceuserdeclarative/impl/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/s0000755000175000017500000000000012475375714033445 5ustar felixfelix././@LongLink0000644000000000000000000000026000000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/src/org/knopflerfish/tutorial/dateserviceuserdeclarative/impl/Component.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/s0000644000175000017500000000232612346515440033437 0ustar felixfelixpackage org.knopflerfish.tutorial.dateserviceuserdeclarative.impl; import org.knopflerfish.tutorial.dateservice.DateService; import org.knopflerfish.tutorial.common.ServiceUserThread; public class Component { DateService dateService; ServiceUserThread thread; /** * Called by the Declarative Service component finds * a registered DateService as specified in the component.xml */ protected void setDateService(DateService dateService) { log("setDateService"); this.dateService = dateService; if(thread == null) { thread = new ServiceUserThread(dateService, "declarative example"); thread.start(); } } /** * Called by the Declarative Service component notices an * unregistered DateService as specified in the component.xml */ protected void unsetDateService(DateService dateService) { log("unsetDateService"); this.dateService = null; if(thread != null) { thread.stopThread(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } thread = null; } } private void log(String message) { System.out.println("dateservice component: " + message); } } ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/resources/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/r0000755000175000017500000000000012475375714033444 5ustar felixfelix././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/resources/OSGI-INF/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/r0000755000175000017500000000000012475375714033444 5ustar felixfelix././@LongLink0000644000000000000000000000020400000000000011577 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/resources/OSGI-INF/component.xmlknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_declarative/r0000644000175000017500000000066112346515440033436 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/build.xml0000644000175000017500000000164112346515440027332 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/0000755000175000017500000000000012475375714030205 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/manifest.mf0000644000175000017500000000052012346515440032321 0ustar felixfelixManifest-Version: 2.0 Bundle-Name: simplebundle Bundle-SymbolicName: simplebundle Bundle-Version: 1.0.0 Bundle-Description: Demo Bundle for the KF OSGi tutorial Bundle-Vendor: Knopflerfish Bundle-Activator: org.knopflerfish.tutorial.simplebundle.impl.Activator Bundle-Category: example Import-Package: org.osgi.framework knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/build.xml0000644000175000017500000000151412346515440032014 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/0000755000175000017500000000000012475375714030774 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/0000755000175000017500000000000012475375714031563 5ustar felixfelix././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/knopflerfish/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/knopfler0000755000175000017500000000000012475375714033324 5ustar felixfelix././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/knopflerfish/tutorial/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/knopfler0000755000175000017500000000000012475375714033324 5ustar felixfelix././@LongLink0000644000000000000000000000020000000000000011573 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/knopflerfish/tutorial/simplebundle/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/knopfler0000755000175000017500000000000012475375714033324 5ustar felixfelix././@LongLink0000644000000000000000000000020500000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/knopflerfish/tutorial/simplebundle/impl/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/knopfler0000755000175000017500000000000012475375714033324 5ustar felixfelix././@LongLink0000644000000000000000000000023200000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/knopflerfish/tutorial/simplebundle/impl/HelloWorldThread.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/knopfler0000644000175000017500000000127512346515440033320 0ustar felixfelixpackage org.knopflerfish.tutorial.simplebundle.impl; /** * @author Sven Haiges | sven.haiges@vodafone.com * @author Erik Wistrand */ public class HelloWorldThread extends Thread { private boolean running = true; public HelloWorldThread() { super("Hello World thread"); } public void run() { while (running) { System.out.println("Hello World!"); try { Thread.sleep(5000); } catch (InterruptedException e) { System.out.println("HelloWorldThread ERROR: " + e); } } System.out.println("thread stopped"); } public void stopThread() { System.out.println("stopping thread"); this.running = false; } } ././@LongLink0000644000000000000000000000022300000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/knopflerfish/tutorial/simplebundle/impl/Activator.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/simplebundle/src/org/knopfler0000644000175000017500000000131112346515440033307 0ustar felixfelixpackage org.knopflerfish.tutorial.simplebundle.impl; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; /** * @author Sven Haiges | sven.haiges@vodafone.com */ public class Activator implements BundleActivator { public static BundleContext bc = null; private HelloWorldThread thread = null; public void start(BundleContext bc) throws Exception { System.out.println("SimpleBundle starting..."); Activator.bc = bc; thread = new HelloWorldThread(); thread.start(); } public void stop(BundleContext bc) throws Exception { System.out.println("SimpleBundle stopping..."); thread.stopThread(); thread.join(); } } knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/0000755000175000017500000000000012475375714032624 5ustar felixfelix././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/manifest.mfknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/mani0000644000175000017500000000071312346515440033461 0ustar felixfelixManifest-Version: 2.0 Bundle-Name: dateserviceuser_listener Bundle-SymbolicName: org.knopflerfish.tutorial.dateserviceuserlistener Bundle-Version: 1.0.0 Bundle-Description: Demo Date Service User Listener Bundle for the KF OSGi tutorial Bundle-Vendor: Knopflerfish Bundle-Activator: org.knopflerfish.tutorial.dateserviceuserlistener.impl.Activator Bundle-Category: example Import-Package: org.osgi.framework,org.knopflerfish.tutorial.dateservice ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/build.xmlknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/buil0000644000175000017500000000175312346515440033475 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/0000755000175000017500000000000012475375714033413 5ustar felixfelix././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/org/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/0000755000175000017500000000000012475375714033413 5ustar felixfelix././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/org/knopflerfish/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/0000755000175000017500000000000012475375714033413 5ustar felixfelix././@LongLink0000644000000000000000000000017700000000000011610 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/org/knopflerfish/tutorial/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/0000755000175000017500000000000012475375714033413 5ustar felixfelix././@LongLink0000644000000000000000000000020600000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/org/knopflerfish/tutorial/common/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/0000755000175000017500000000000012475375714033413 5ustar felixfelix././@LongLink0000644000000000000000000000023400000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/org/knopflerfish/tutorial/common/ServiceUserThread.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/0000644000175000017500000000216712346515440033410 0ustar felixfelixpackage org.knopflerfish.tutorial.common; import java.util.Date; import org.knopflerfish.tutorial.dateservice.DateService; public class ServiceUserThread extends Thread { private DateService dateService = null; private boolean running = true; public ServiceUserThread(DateService dateService, String threadName) { super(threadName); this.dateService = dateService; } public void run() { String formattedDate = null; while (running) { Date date = new Date(); try { formattedDate = dateService.getFormattedDate(date); } catch (RuntimeException e) { System.out.println("RuntimeException occured during service usage: " + e); } System.out.println(getName() + ": converted date has value: " + formattedDate); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("ServiceUserThread ERROR: " + e); } } } public void stopThread() { System.out.println("stopping " + this); this.running = false; } } ././@LongLink0000644000000000000000000000022700000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/org/knopflerfish/tutorial/dateserviceuserlistener/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/0000755000175000017500000000000012475375714033413 5ustar felixfelix././@LongLink0000644000000000000000000000023400000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/org/knopflerfish/tutorial/dateserviceuserlistener/impl/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/0000755000175000017500000000000012475375714033413 5ustar felixfelix././@LongLink0000644000000000000000000000025200000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/org/knopflerfish/tutorial/dateserviceuserlistener/impl/Activator.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_listener/src/0000644000175000017500000000536512346515440033413 0ustar felixfelixpackage org.knopflerfish.tutorial.dateserviceuserlistener.impl; import java.util.Date; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceEvent; import org.knopflerfish.tutorial.dateservice.DateService; import org.knopflerfish.tutorial.common.ServiceUserThread; public class Activator implements BundleActivator { public static BundleContext bc = null; DateService dateService; ServiceUserThread thread; public void start(BundleContext bc) throws Exception { Activator.bc = bc; log("starting"); String filter = "(objectclass=" + DateService.class.getName() + ")"; bc.addServiceListener(listener, filter); ServiceReference references[] = bc.getServiceReferences(null, filter); for (int i = 0; references != null && i < references.length; i++) { listener.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, references[i])); } } public void stop(BundleContext bc) throws Exception { log("stopping"); Activator.bc = null; } private void log(String message) { System.out.println(Activator.bc.getBundle().getHeaders() .get(Constants.BUNDLE_NAME) + ": " + message); } ServiceListener listener = new ServiceListener() { public void serviceChanged(ServiceEvent event) { switch (event.getType()) { case ServiceEvent.REGISTERED: log("ServiceEvent.REGISTERED"); dateService = (DateService) Activator.bc.getService(event .getServiceReference()); startUsingService(); break; case ServiceEvent.MODIFIED: log("ServiceEvent.MODIFIED received"); stopUsingService(); dateService = (DateService) Activator.bc.getService(event .getServiceReference()); startUsingService(); break; case ServiceEvent.UNREGISTERING: log("ServiceEvent.UNREGISTERING"); stopUsingService(); break; } } private void stopUsingService() { thread.stopThread(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } dateService = null; } private void startUsingService() { thread = new ServiceUserThread(dateService, "listener example"); thread.start(); } }; } knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/0000755000175000017500000000000012475375714031607 5ustar felixfelix././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/manifest.mfknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/manifest0000644000175000017500000000067312346515440033333 0ustar felixfelixManifest-Version: 2.0 Bundle-Name: dateserviceuser_bad2 Bundle-SymbolicName: org.knopflerfish.tutorial.dateserviceuserbad2 Bundle-Version: 1.0.0 Bundle-Description: Demo Date Service User Bad2 Bundle for the KF OSGi tutorial Bundle-Vendor: Knopflerfish Bundle-Activator: org.knopflerfish.tutorial.dateserviceuserbad2.impl.Activator Bundle-Category: example Import-Package: org.osgi.framework,org.knopflerfish.tutorial.dateservice ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/build.xmlknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/build.xm0000644000175000017500000000174312346515440033246 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/src/0000755000175000017500000000000012475375714032376 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/src/org/0000755000175000017500000000000012475375714033165 5ustar felixfelix././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/src/org/knopflerfish/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/src/org/0000755000175000017500000000000012475375714033165 5ustar felixfelix././@LongLink0000644000000000000000000000017300000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/src/org/knopflerfish/tutorial/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/src/org/0000755000175000017500000000000012475375714033165 5ustar felixfelix././@LongLink0000644000000000000000000000021700000000000011603 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/src/org/knopflerfish/tutorial/dateserviceuserbad2/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/src/org/0000755000175000017500000000000012475375714033165 5ustar felixfelix././@LongLink0000644000000000000000000000022400000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/src/org/knopflerfish/tutorial/dateserviceuserbad2/impl/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/src/org/0000755000175000017500000000000012475375714033165 5ustar felixfelix././@LongLink0000644000000000000000000000024200000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/src/org/knopflerfish/tutorial/dateserviceuserbad2/impl/Activator.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_bad2/src/org/0000644000175000017500000000243512346515440033160 0ustar felixfelixpackage org.knopflerfish.tutorial.dateserviceuserbad2.impl; import java.util.Date; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.knopflerfish.tutorial.dateservice.DateService; public class Activator implements BundleActivator { public static BundleContext bc = null; public void start(BundleContext bc) throws Exception { System.out.println(bc.getBundle().getHeaders() .get(Constants.BUNDLE_NAME) + " starting..."); Activator.bc = bc; ServiceReference reference = bc.getServiceReference(DateService.class.getName()); if(reference != null) { DateService service = (DateService)bc.getService(reference); System.out.println("Using DateService: formatting date: " + service.getFormattedDate(new Date())); bc.ungetService(reference); } else { System.out.println("No Service available!"); } } public void stop(BundleContext bc) throws Exception { System.out.println(bc.getBundle().getHeaders() .get(Constants.BUNDLE_NAME) + " stopping..."); Activator.bc = null; } } knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/0000755000175000017500000000000012475375714032432 5ustar felixfelix././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/manifest.mfknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/manif0000644000175000017500000000073512346515440033441 0ustar felixfelixManifest-Version: 2.0 Bundle-Name: dateserviceuser_tracker Bundle-SymbolicName: org.knopflerfish.tutorial.dateserviceusertracker Bundle-Version: 1.0.0 Bundle-Description: Demo Date Service User Tracker Bundle for the KF OSGi tutorial Bundle-Vendor: Knopflerfish Bundle-Activator: org.knopflerfish.tutorial.dateserviceusertracker.impl.Activator Bundle-Category: example Import-Package: org.osgi.framework,org.knopflerfish.tutorial.dateservice,org.osgi.util.tracker ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/build.xmlknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/build0000644000175000017500000000175212346515440033446 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/0000755000175000017500000000000012475375714033221 5ustar felixfelix././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/org/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/o0000755000175000017500000000000012475375714033400 5ustar felixfelix././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/org/knopflerfish/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/o0000755000175000017500000000000012475375714033400 5ustar felixfelix././@LongLink0000644000000000000000000000017600000000000011607 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/org/knopflerfish/tutorial/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/o0000755000175000017500000000000012475375714033400 5ustar felixfelix././@LongLink0000644000000000000000000000020500000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/org/knopflerfish/tutorial/common/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/o0000755000175000017500000000000012475375714033400 5ustar felixfelix././@LongLink0000644000000000000000000000023300000000000011601 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/org/knopflerfish/tutorial/common/ServiceUserThread.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/o0000644000175000017500000000216712346515440033375 0ustar felixfelixpackage org.knopflerfish.tutorial.common; import java.util.Date; import org.knopflerfish.tutorial.dateservice.DateService; public class ServiceUserThread extends Thread { private DateService dateService = null; private boolean running = true; public ServiceUserThread(DateService dateService, String threadName) { super(threadName); this.dateService = dateService; } public void run() { String formattedDate = null; while (running) { Date date = new Date(); try { formattedDate = dateService.getFormattedDate(date); } catch (RuntimeException e) { System.out.println("RuntimeException occured during service usage: " + e); } System.out.println(getName() + ": converted date has value: " + formattedDate); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("ServiceUserThread ERROR: " + e); } } } public void stopThread() { System.out.println("stopping " + this); this.running = false; } } ././@LongLink0000644000000000000000000000022500000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/org/knopflerfish/tutorial/dateserviceusertracker/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/o0000755000175000017500000000000012475375714033400 5ustar felixfelix././@LongLink0000644000000000000000000000023200000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/org/knopflerfish/tutorial/dateserviceusertracker/impl/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/o0000755000175000017500000000000012475375714033400 5ustar felixfelix././@LongLink0000644000000000000000000000025000000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/org/knopflerfish/tutorial/dateserviceusertracker/impl/Activator.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateserviceuser_tracker/src/o0000644000175000017500000000504512346515440033373 0ustar felixfelixpackage org.knopflerfish.tutorial.dateserviceusertracker.impl; import java.util.Date; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceEvent; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.knopflerfish.tutorial.dateservice.DateService; import org.knopflerfish.tutorial.common.ServiceUserThread; public class Activator implements BundleActivator { public static BundleContext bc = null; ServiceTracker tracker; ServiceUserThread thread; public void start(BundleContext bc) throws Exception { Activator.bc = bc; log("starting"); tracker = new ServiceTracker(bc, DateService.class.getName(), customizer); tracker.open(); } ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer() { public Object addingService(ServiceReference reference) { log("addingService"); DateService service = (DateService) bc.getService(reference); if (thread == null) { thread = new ServiceUserThread(service, "tracker example"); thread.start(); return service; } else { return service; } } public void modifiedService(ServiceReference reference, Object serviceObject) { thread.stopThread(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } DateService service = (DateService) bc.getService(reference); thread = new ServiceUserThread(service, "tracker example"); thread.start(); } public void removedService(ServiceReference reference, Object serviceObject) { log("removedService"); thread.stopThread(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } thread = null; } }; public void stop(BundleContext bc) throws Exception { log("stopping"); tracker.close(); Activator.bc = null; } private void log(String message) { System.out.println(Activator.bc.getBundle().getHeaders() .get(Constants.BUNDLE_NAME) + ": " + message); } } knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/0000755000175000017500000000000012475375714030020 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/manifest.mf0000644000175000017500000000064412346515440032143 0ustar felixfelixManifest-Version: 2.0 Bundle-Name: dateservice Bundle-SymbolicName: org.knopflerfish.tutorial.dateservice Bundle-Version: 1.0.0 Bundle-Description: Demo Service Bundle for the KF OSGi tutorial Bundle-Vendor: Knopflerfish Bundle-Activator: org.knopflerfish.tutorial.dateservice.impl.Activator Bundle-Category: example Import-Package: org.osgi.framework Export-Package: org.knopflerfish.tutorial.dateservice knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/build.xml0000644000175000017500000000154112346515440031627 0ustar felixfelix knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/0000755000175000017500000000000012475375714030607 5ustar felixfelixknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/0000755000175000017500000000000012475375714031376 5ustar felixfelix././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerfish/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerf0000755000175000017500000000000012475375714033305 5ustar felixfelix././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerfish/tutorial/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerf0000755000175000017500000000000012475375714033305 5ustar felixfelix././@LongLink0000644000000000000000000000017600000000000011607 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerfish/tutorial/dateservice/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerf0000755000175000017500000000000012475375714033305 5ustar felixfelix././@LongLink0000644000000000000000000000020300000000000011576 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerfish/tutorial/dateservice/impl/knopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerf0000755000175000017500000000000012475375714033305 5ustar felixfelix././@LongLink0000644000000000000000000000022700000000000011604 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerfish/tutorial/dateservice/impl/DateServiceImpl.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerf0000644000175000017500000000054412346515440033277 0ustar felixfelixpackage org.knopflerfish.tutorial.dateservice.impl; import java.text.DateFormat; import java.util.Date; import org.knopflerfish.tutorial.dateservice.DateService; public class DateServiceImpl implements DateService { public String getFormattedDate(Date date) { return DateFormat.getDateInstance(DateFormat.SHORT) .format(date); } } ././@LongLink0000644000000000000000000000022100000000000011576 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerfish/tutorial/dateservice/impl/Activator.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerf0000644000175000017500000000215712346515440033301 0ustar felixfelixpackage org.knopflerfish.tutorial.dateservice.impl; import java.util.Hashtable; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceRegistration; import org.knopflerfish.tutorial.dateservice.DateService; public class Activator implements BundleActivator { public static BundleContext bc = null; public void start(BundleContext bc) throws Exception { System.out.println(bc.getBundle().getHeaders().get (Constants.BUNDLE_NAME) + " starting..."); Activator.bc = bc; DateService service = new DateServiceImpl(); ServiceRegistration registration = bc.registerService(DateService.class.getName(), service, new Hashtable()); System.out.println("Service registered: DateService"); } public void stop(BundleContext bc) throws Exception { System.out.println(bc.getBundle().getHeaders().get (Constants.BUNDLE_NAME) + " stopping..."); Activator.bc = null; } } ././@LongLink0000644000000000000000000000021600000000000011602 Lustar rootrootknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerfish/tutorial/dateservice/DateService.javaknopflerfish-osgi-5.1.0/docs/tutorials/kf_osgi_tutorial/example_source/dateservice/src/org/knopflerf0000644000175000017500000000023112346515440033270 0ustar felixfelixpackage org.knopflerfish.tutorial.dateservice; import java.util.Date; public interface DateService { public String getFormattedDate(Date date); } knopflerfish-osgi-5.1.0/docs/components.html0000644000175000017500000005327212346515440020166 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - What is included in the Knopflerfish distribution knopflerfish-osgi-5.1.0/docs/desktop.html0000644000175000017500000002313612346515440017446 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - the famous KF Desktop bundle, visualizing the OSGi service platform

      The Knopflerfish Desktop

      The Knopflerfish OSGi Desktop displays a graphical overview of the OSGi framework. Most common operations as install, start, stop and update can be performed on bundles using the desktop. Additionally, bundle and service detail information is shown, and an experimental "Save deploy archive" is included.

      The desktop is a standard OSGi bundle, using Swing. The desktop is primarily designed to manage a locally running framework, but can be used to control a remote framework, using the optional SOAP bundles. Consult the description of how to activate the "Remote framework..." menu item.

      Additionally, the HTTP console or the Telnet console bundle can always be used for remote control. Both are available in the KF bundle repository.

      The desktop can be customized using plugin services, see SwingBundleDisplayer for details.

      The Desktop bundle can be found in

        knopflerfish/osgi/bundles/desktop
      

      When started, it creates a window with four main areas:

      Toolbar
      The top toolbar provides quick access to common operations as start/stop/update bundles.
      Bundle view
      The center bundle view area display all installed bundles and their states. By clicking on bundles in this are, detail information is displayed in the Bundle detail area Four different views a supported internally (new can be installed):
      • Icons - each bundle is displayed as an icon.
      • Details - each bundle is displayed as a table row.
      • Spin - each bundle is displayed in a really cool graphics view.
      • Time line - each bundle event is displayed in a zoomable time line view.
      Bundle detail area
      The rightmost bundle detail area shows detailed information on selected bundles such as:
      • manifest
      • bundle closure
      • imported/exported services
      • imported/exported packages
      • bundle logs.
      New detail pages can be installed run-time using plug-ins.
      Framework console
      The bottom console area allows interaction with the text console. This console acts exactly as the consoltty bundle, but does not require a shell or DOS window to run.

      Icon view

      To view the installed bundles as icons, select
      View -> Large Icons
      
      Bundle which has a BundleActivator
      Active bundle
      "Library" bundle which has no BundleActivator

      Bundles can be selected by clicking.

      Detail list view

      To view the installed bundles as a detailed list, select
      View -> Details
      

      Bundles can be selected by clicking.

      Detail spin view

      To view the installed bundles as graphics, select
      View -> Spin
      

      Dependencies between bundles and services are shown as connecting lines. Not how the console bundle depends on three other bundles in the image above.

      Bundles can be selected by clicking.

      Detail spin view

      To view the installed bundles as a time line, select
      View -> Time line
      

      Each bundle has a horizontal line, with bundle events marked for each bundle

      Bundles can be selected by clicking.

      knopflerfish-osgi-5.1.0/docs/osgi_with_security.html0000644000175000017500000005250612346515440021723 0ustar felixfelix Knopflerfish OSGi, version 5.1.0 - OSGi with Security

      Running Knopflerfish OSGi with Security

      Contents

      1. Why Security?
      2. Choose your Security
      3. Turn it On
      4. An Easy Set-up
      5. Using the Console
      6. Using Conditional Permission Admin
      7. The Tested Bundle
      8. A Calling Bundle
      9. References

      Why Security?

      For most of us, the normal way is to run our OSGi frameworks with security off. When we have absolute control of the set of installed bundles, turning on security only gives us a set-up hassle and a performance hit.

      But even if your framework is not exposed to bundles from unknown sources, you might have to run with security on in order to properly test bundles that need to do security right, in case someone else decides to run their framework with security on.

      The scenario for this tutorial is that we are developing a bundle and it is now time to test how it behaves in a framework with security on.

      Choose your Security

      To complicate things, there is more than one way to set up security.

      The OSGi core specification contains both the Permission Admin and the Conditional Permission Admin that supersedes the former one. On top of that, it is also possible to specify a Java 2 policy file that grants permissions to code from specified code sources (based on location or signature).

      It is preferred to use Conditional Permission Admin (CPA) in favor of the old Permission Admin (as it is newer, but also more powerful). The Java 2 policy file is a lot less flexible than using CPA since it is not really possible to change permissions dynamically that way. This tutorial will use CPA, the policy file will only be used to grant the framework sufficient permission.

      A few final words about the policy file. It can be useful to know that the Knopflerfish framework will by default use a Java 2 policy file that is included in the framework jar file. But if the system property java.security.policy is set, the specified policy file will be used instead. The KF default policy file grants AllPermission to everyone, which is likely to be what you want; the framework needs AllPermission and since CPA will be used to control permissions for the bundles, you want the policy file to have -- no policy at all.

      Turn it On

      Turning security on in Knopflerfish is easy, just a framework property that needs to be set.

      To set a security manager and thus turn on security, set the framework environment property org.osgi.framework.security to osgi. For Knopflerfish this will set the KFSecurityManager as security manager.

      With a security manager set (either using -Djava.security.manager or -Forg.osgi.framework.security=osgi) the KF system bundle will publish services PermissionAdmin and ConditionalPermissionAdmin. If you know that PermissionAdmin is not going to be used, you can turn it off by setting -Forg.knopflerfish.framework.service.permissionadmin=false.

      As you can see, turning security on is easy. Unfortunately, just turning it on will not do much since the default (as long as no permission has been set with CPA) is to grant everyone AllPermission. All we have accomplished so far is to slow thing down a little bit by installing a security manager.

      An Easy Set-up

      An easy set-up for permissions is to continue to grant AllPermission for bundles that you have control over/are not security testing.

      In this tutorial we are supposed to be testing a bundle under development. We do not really care about other bundles that might be installed and running, like the KF log, cm, http, event, etc bundles. To keep these working like before, we will grant them AllPermission by adding a policy that allow AllPermission under the condition that the bundle location matches the location where the KF bundles are stored in the local file system:

      ALLOW {
        [org.osgi.service.condpermadmin.BundleLocationCondition "file:jars/*"]
        (java.security.AllPermission)
      }
      

      A bundle that we do not trust/are testing should be given less permission. A good starting point is to give them permission to import any package. If we give no permissions at all, the bundle will not even be allowed to resolve and will be difficult to test. An even more restricted starting point is to only allow import of the org.osgi.framework package.

      In this tutorial the bundle that we are testing is stored in the local file system at /opt/kf/totest, and to give all bundles located here permission to import any package we need:

      ALLOW {
        [org.osgi.service.condpermadmin.BundleLocationCondition "file:/opt/kf/totest/*"]
        (org.osgi.framework.PackagePermission "*" "import")
      }
      

      A note to all Windows users out there: watch your backslashes. For example if the path to your bundles to test is c:\kf\totest, you might think that file:c:\\kf\\totest\\* will do fine as location argument. But in this argument the last backslash is not interpreted as a file separator, but as an escape character for the wildcard star, meaning that it is not going to be treated as a wildcard! file:c:\\kf\\totest* will work much better. This is documented in the javadoc for BundleLocationCondition but this little feature is easy to miss.

      Both of the policies above use a bundle location condition. It is also possible to use a bundle signer condition to grant permission to bundles that are signed by a particular signature, or to use no condition at all if a permission should be granted to all bundles.

      When we start to test our bundle, we will probably need to give it more permission. For example, if it is using the Log service, it will need a ServicePermisson for that.

      One way to add these policies is to use the setcondpermission command in the KF framework command group. Another way is to write a bundle that uses the ConditionalPermissinAdmin service to programmatically add conditional permissions.

      Using the Console

      Make sure that the bundle frameworkcommands is installed.

      In the console, type

        > framework setcondpermission \
        '[org.osgi.service.condpermadmin.BundleLocationCondition "file:jars/*"]' \
        (java.security.AllPermission)
      
      and
        > fr setcond '[org.osgi.service.condpermadmin.BundleLocationCondition \
        "file:/opt/kf/totest/*"]' \
        '(org.osgi.framework.PackagePermission "*" "import")'
      

      The policies will be part of the framework state, they will survive a restart as long as you do not use the -init flag to clear the state.

      Using the Conditional Permission Admin

      Let us write a bundle (the admin bundle) that will set up the polices for us using the CPA service that is published by the framework.

      The admin bundle will be our policy administration bundle so it will need permission to set polices using the CPA service. This means that it is in full control of the CPA and thereby able to grant itself or another bundle any kind of permission. It is easily realized that the admin bundle will have to be a trusted bundle. We could let it set the required CPA permissions for itself but to keep thing simple in this tutorial we will just treat it as trusted bundle and make sure it is loaded from the same location as the rest of the trusted KF bundles.

      Here is the source code and jar f ile for the admin bundle. We have a method, installPolicies that is called when the bundle starts:

      01: void installPolicies(ConditionalPermissionAdmin cpa, String[] pInfos) {
      02:   ConditionalPermissionUpdate cpu = cpa.newConditionalPermissionUpdate();
      03:   List piList = cpu.getConditionalPermissionInfos();
      04:
      05:   for (int i = 0; i < pInfos.length; i++) {
      06:     String pInfo = pInfos[i];
      07:     ConditionalPermissionInfo cpi = cpa.newConditionalPermissionInfo(pInfo);
      08:     piList.add(cpi);
      09:   }
      10:    
      11:   cpu.commit();
      12: }
      
      On line 02 and 03 we use the CPA to create a permission update object and get the list that our permissions will be added to. An instance of ConditionalPermissionInfo is created for each permission. The CPA service is used to create an instance from an encoded string. The string syntax is specified in the CPA chapter of the OSGi core specification. The policies that we defined in An Easy Set-up would look like this:
        private static final String[] ENCODED_PINFO = {
          "allow { [org.osgi.service.condpermadmin.BundleLocationCondition \
          	\"file:jars/*\"] (java.security.AllPermission) } \"allToTrusted\"",
          "allow { [org.osgi.service.condpermadmin.BundleLocationCondition \
          	\"file:/opt/kf/totest/*\"] (org.osgi.framework.PackagePermission \
          	\"*\" \"import\") } \"importToTested\""
        };
      

      Each ConditionalPermissionInfo instance is added to the update list and then the update is committed to the CPA service on line 11.

      Our version of the admin bundle uses hard coded policy strings to keep it simple. A more realistic version would probably read the policy data from a file or some other source.

      In a real world system, the functionality of the admin bundle could be integrated into a management agent. It would set the CPA policies and then it would take care of installing and starting the rest of the bundles that should be included in the system. We can follow this strategy without writing a complex management agent by using the xargs functionality in KF. Here is a props.xargs and an init.xargs that will:

      1. Install the admin bundle, schedule it for start.
      2. Launch the framework. This will start the admin bundle.
      3. Install and start the rest of the bundles, in this case a minimal set of KF bundles that includes the log and some console bundles for the TTY console, plus our bundle to test and a test bundle.
      This way we make sure that no bundle can 'sneak in' and do something without being subjected to the CPA policies we want to be in effect.

      Debug output for permissions is enabled in props.xargs. A lot of output is produced but it can be useful to have it enabled when you are working with a security enabled framework.

      The Tested Bundle

      This section is about the bundle that we are developing and that we want to verify is working correctly when running in a framework with security on.

      The to-test bundle is called user. It will publish a fake service (UserService) that we pretend is used to notify native components about the currently logged in OSGi user. Notification is done using the file system.

      The bundle will be using the framework and the LogService so we are going to need permission for that. We also need permission to read and write to the file system. Finally, we need permission to export a package and publish a service for other bundles to import and use. The policy for these permissions could look like:

      ALLOW {
        [org.osgi.service.condpermadmin.BundleLocationCondition "file:/opt/kf/totest/cpaexample_user*"]
        (org.osgi.framework.PackagePermission "org.osgi.framework.*" "import")
        (org.osgi.framework.PackagePermission "org.osgi.service.log" "import")
        (org.osgi.framework.ServicePermission "org.osgi.service.log.LogService" "get")
        (java.io.FilePermission "/tmp/osgiuser" "read,write,delete")
        (org.osgi.framework.PackagePermission "com.acme.resource" "exportonly")
        (org.osgi.framework.ServicePermission "com.acme.resource.ResourceService" "register")
      }
      
      While it is not mandatory, it is recommended that a bundle lists the permissions that it requires. The listed permissions are called local permissions. If defined, a bundle can never get more permissions than its local permissions. This feature makes it possible for a deployer to audit the permission requirements for a bundle. If the list of required permissions is acceptable, there is no need for the deployer to set up permissions in detail, the bundle can be given AllPermission.

      Local permissions for a bundle are defined in the resource file OSGI_INF/permissions.perm. Each permission is listed on its own line in this file, in the encoded form describes in Using Conditional Permission Admin.

      When we add local permissions to our user bundle, it is all right to use a policy in the admin bundle that grants the user bundle AllPermission. The hard coded policies in the admin bundle will now be:
        private static final String[] ENCODED_PINFO = {
          "allow { [org.osgi.service.condpermadmin.BundleLocationCondition \
          	\"file:jars/*\"] (java.security.AllPermission) } \"allToTrusted\"",
          "allow { [org.osgi.service.condpermadmin.BundleLocationCondition \
          	\"file:/opt/kf/totest/cpaexample_user*\"] \
          	(java.security.AllPermission) } \"allToUser\""
        };
      

      The source code for the user bundle is here, the jar including local permission definition is here. The interesting parts for this security tutorial can be found in the login and logout methods of UserService. Here is the login method:

      01: public void login(final String name) {
      02:   final File f = new File(fileName);
      03:
      04:   AccessController.doPrivileged(new PrivilegedAction() {
      05:     public Object run() {
      06:       if (f.exists()) {
      07:         throw new IllegalStateException("User already logged in");
      08:       }
      09:
      10:       try {
      11:         OutputStream os = new FileOutputStream(f);
      12:         os.write(name.getBytes("UTF-8"));
      13:         os.close();
      14:         log(LogService.LOG_INFO, "User " + name + " logged in");
      15:       } catch (IOException ioe) {
      16:         log(LogService.LOG_WARNING, "Problem logging user in: " + ioe);
      17:       }
      18:       return null;
      19:     }
      20:   });
      21: }
      
      When doing method calls that will lead to permission checks (lines 06, 11, 14 and 16) we need to mark us as privileged. When marked as privileged, the permission check will check that we have the required permissions but it will not continue to check that our caller (the bundle that is calling the login method in our service) also have the required permissions. Without the doPrivileged wrapper construction on line 04, it would be required for a bundle that is using our service to have the same permissions that we have.

      A Calling Bundle

      To proper test our resource bundle we also need to write a bundle that uses our UserService.

      We have to make sure that permissions required by the user bundle is not also required by any user of its registered service. A user should only be required to have permission to import the package from the user bundle and to get the UserService.

      This third bundle, called caller, is nothing special. All it does is getting the UserService and logging in a user in the start method and then logging out in the stop method. Here is the source and jar file.

      References

      Chapter 9 of OSGi Service Platform Core Specification, Conditional Permission Admin Specification, contains a lot of information about the CPA service and security in OSGi in general. The specification can be downloaded from here.

      knopflerfish-osgi-5.1.0/fish16x16.gif0000644000175000017500000000173612346513620016305 0ustar felixfelixGIF89a!)!))))1)11119!19!99!9B)9B)BB)BJ1BJ1JJ9JR9RRBRRBRZJZZJZcRccZksckscsss{{{,H*L@ "P!Ä(`` D&X4P (,` |CV €VX À QpC $` ` dxRh+JH"?1E0$\` 0@-H 4 @5;QE \@Y*@c6;

      About Knopflerfish 5 - an OSGi R5 distribution

      Knopflerfish 5 (KF5) is designed to be implemented according to the OSGi R5 specifications. The distribution includes the following components:
      • Knopflerfish OSGi framework - OSGi R5 Core Specification implementation
      • Knopflerfish OSGi bundles - OSGi R5 Service Compendium implementation
      • Knopflerfish components & extras - Knopflerfish bundles and utilities

      Knopflerfish 5 OSGi Framework - OSGi R5 Core

      The Knopflerfish 5 OSGi framework is implemented in accordance with the OSGi R5 specification.

      The numbering for the OSGi defined components refer to the OSGi specification chapter numbering. The Changes column indicates if the service / API has been updated in R5 compared to R4v4.3 of the Core specification, in which case the new specification chapter version is stated.

      Core Specification - Knopflerfish OSGi framework
      Section Changes Status R5 Description
      2. Security Layer NA Done Full The OSGi Security Layer based on the Java2 security mechanism.
      3. Module Layer NA Done Full The OSGi solution for Java modularization, a.k.a. OSGi bundles.
      4. Life Cycle Layer NA Done Full Function to control the security and life cycle operations of bundles
      5. Service Layer NA Done Full The Service Layer provides a publish, find and bind model trough the service registry.
      Core Specification - Knopflerfish Framework API:s
      6. Resource API
      New Done Full An API for the generic Requirement-Capability model.
      7. Bundle Wiring API 1.1 Done Full An API that provides access to the internal Framework package sharing mechanism. This API replaces the Package Admin Service from the OSGi R4 v4.2 and earlier.
      8. Framework Namespaces New Done Full A namespace definition for the generic Requirement-Capability model.
      9. Start Level API No Done Full An API to control the relative starting and stopping order of bundles in an OSGi Service Platform. This API replaces the Start Level Service from OSGi R4 v4.2 and earlier.
      10. Framework API 1.7 Done Full The core API for bundles to interact with the OSGi Framework.
      Core Specification - Knopflerfish Framework Services
      50. Conditional Permission Admin No Done Full Essentially a security policy and permission system for OSGi bundles. Supersedes Permission Admin
      51. Permission Admin No Done Full A permission system for bundles
      52. URL Handler No Done Full A mechanism to extend the Java run-time with new URL schemes and content handlers through bundles
      53. Resolver Hooks No Done Full A set of mechanisms for close interaction with the module layer resolving of bundle requirements and capabilities.
      54. Bundle Hooks 1.1 Done Full A set of mechanisms for controlling visibility of bundles for other bundles.
      55. Service Hooks No Done Full A set of mechanisms for close interaction with the Service Registry.
      56. Weaving Hooks No Done Full A set of mechanisms for doing byte code weaving of classes loaded by a Bundle Class Loader.
      701. Tracker Specification No Done Full Utility for Bundle and Service tracking


      Knopflerfish 5 OSGi Bundles - OSGi R5 Compendium Services

      The Knopflerfish 5 OSGi Compendium Services are implemented in accordance with the OSGi R5 specification.

      Some of the OSGi Compendium Services are only available in the commercial Knopflerfish Pro 5 version provided by Makewave. These services are clearly marked in the table below,

      The numbering for the OSGi defined components refer to the OSGi specification chapter numbering. The Changes column indicates if the service / API has been updated in R5 compared to R4v4.3 of the Compendium specification, in which case the new specification chapter version is stated.

      Knopflerfish OSGi Bundles - Service Compendium
      Specification Updates Status R5 Description
      101. Log No Stable Full A message logger for the OSGi Service Platform.
      102. HTTP No Stable Full HTTP server for the OSGi Service Platform. Supports both static HTML pages, as well as Servlets serving dynamic content
      103. Device Access No Stable Full The Device Access specification supports the coordination of automatic detection and attachment of existing devices on an OSGi Service Platform.
      104. Configuration Admin 1.5 Done Full Service for setting configuration information of OSGi bundles
      105. Meta Type No Done Full Service that allow bundle developers to describe attribute types in a computer readable form using so-called meta- data.
      106. Preferences No Stable Full Service that provides easy to use persistent storage of bundle data. typically user preference. Knopflerfish Pro includes an enhanced Preferences implementation where Ubicore serves as a remote Backing Store for the Preferences service.
      107. User Admin No Stable Full Service that a bundle can use for Authentication and Authorization.
      108. Wire Admin No Stable KF Pro Full Wiring of OSGi services inside an OSGi Service Platform. KF Pro only
      109. IO Connector No Stable Full A connector service that adopts the Java 2 ME javax.microedition.io for OSGi
      110. Initial Provisioning No Stable KF Pro Full Defines how to initially install the management agent in an OSGi Service Platform. KF Pro only
      111. UPnP Device Service No Done KF Pro Full Service for interaction with UPnP devices and Control Points. KF Pro only
      112. Declarative Services No Done Full Service that defines a declarative model for publishing, finding and binding to OSGi services
      113. Event Admin No Stable Full Provides an inter-bundle communication mechanism by sending events.
      114. Deployment Admin No Stable KF Pro Full The Deployment Admin and Device Management Tree (DMT) bundle
      115. Auto Configuration No Stable KF Pro Full The auto-configuration resource plug-in for the deployment admin service.
      116. Application Admin No Stable KF Pro Full The Application Admin Service
      117. DMT Admin No Stable KF Pro Full The Device Management Tree (DMT) Admin bundle.
      119. Monitor Admin No Stable KF Pro Full The Monitor Admin Service. KF Pro only
      120. Foreign Application Access No Stable KF Pro Full A midlet container for Application Admin
      132. Repository New In Progress New Repository is a service to search and retrieve general resources, e.g. OSGi bundles
      702. XML Parser Service No Stable Full Standardized XML Parser utility
      703. Position No Stable Full Utility for handling geographic positions
      704. Measurement and State No Stable Full A utility that provides a consistent way of handling a diverse range of measurements for bundle developers


      Knopflerfish 5 Components - Bundles and Utilities

      The Knopflerfish distribution includes a set of Knopflerfish specific bundles and Utilities. Some of the components include, or are based on other popular open source components / projects. Knopflerfish has in this case typically provided a wrapper class, bundlifying the component / project.

      Knopflerfish Components
      Component Status Includes Description
      Desktop Stable NA The desktop is a graphical tool for managing a running framework. The desktop can be extended using plug-ins. Support added for new OSGi R5 features.
      Log Utilities Stable NA Utility classes for easier logging.
      Misc utilities Stable NA Misc utility classes for text, job and IO handling.
      Console Stable NA The Console service provides means for command-based tools to publish their commands. Any bundle can provide commands.
      TTY Console Stable NA Console using stdin/stdout
      Telnet Console Stable NA Console using telnet
      Console - Framework Commands Stable NA Commands for handling the core Knopflerfish OSGi framework.
      Console - Log Commands Stable NA Commands for handling the OSGi log
      Console - CM Commands Stable NA Command for handling the Configuration Management data
      Console - SCR Commands Stable NA Command for handling and examining Declarative Services components.
      Class Patcher Stable NA This bundle contains the support for class patching using ASM that was previously implemented in the framework. It is implemented as a Weaving Hooks. The configuration properties remain the same in order to be backward compatible.
      Knopflerfish Extras & Wrapper Components
      Component Status Includes Comment
      Commons Logging Stable Commons Logging The Commons logging bundle wraps the Apache Commons Logging API over the OSGi log
      Serial port Stable RXTX Serial ports are supported via the OSGi device model and the javax.comm API. Implementations from Sun (win32) and RXTX (linux) are used for the included bundles.
      KF Test Suite Stable JUnit A JUnit based test suite for Knopflerfish bundle & framework testing.

download (12273 bytes)

Bundle: desktop
Version 5.0.1

The Knopflerfish Desktop

The Knopflerfish OSGi Desktop displays a graphical overview of the OSGi framework.

Description

The Knopflerfish OSGi Desktop displays a graphical overview of the OSGi framework. Most common operations as install, start, stop and update can be performed on bundles using the desktop. Additionally, bundle and service detail information is shown, and an experimental "Save deploy archive" is included.

The desktop is a standard OSGi bundle, using Swing. The desktop is primarily designed to manage a locally running framework, but can be used to control a remote framework, using the optional SOAP bundles. Consult the description of how to activate the "Remote framework..." menu item.

Additionally, the HTTP console or the Telnet console bundle can always be used for remote control. Both are available in the KF bundle repository.

The desktop can be customized using plug-in services, see SwingBundleDisplayer for details.

The desktop main areas

When started, it creates a window with four main areas:

Toolbar
The top toolbar provides quick access to common operations as start/stop/update bundles.
Bundle view
The center bundle view area display all installed bundles and their states. By clicking on bundles in this are, detail information is displayed in the Bundle detail area Three different views a supported internally (new can be installed):
  • Icons - each bundle is displayed as an icon.
  • Graph - each bundle is displayed in a really cool graphics view.
  • Details - each bundle is displayed as a table row.
Bundle detail area
The rightmost bundle detail area shows detailed information on various aspects of the selected bundles such as:
  • Manifest
  • Bundle closure
  • Services, i.e imported/exported services
  • Capabilities and wires, i.e. provided and required capabilites
  • SCR, i.e. declarative service components
  • Log, i.e. bundle logs
  • Events
  • Prefs, i.e. bundle preferences
New detail pages can be installed run-time using plug-ins.
Framework console
The bottom console area allows interaction with the text console. This console acts exactly as the consoltty bundle, but does not require a shell or DOS window to run.

Icon view

To view the installed bundles as icons, select

View -> Icons
Bundle which has a BundleActivator
Active bundle
"Library" bundle which has no BundleActivator
Resolved "Library" bundle
Bundle using declarative services (SCR)
Resolved declarative services bundle
Active declarative services bundle
Fragment bundle.
 

A bundle may provide its own icon by listing it in the manifest attribute Bundle-Icon:. See the OSGi Core specification R4 v4.3 for details on this.

Example of bundles providing their own icon are: "System Bundle", "Log Service", "cm" and "Console".

Bundles can be selected by clicking.

Detail list view

To view the installed bundles as a detailed list, select

  View -> Details

Bundles can be selected by clicking.

Graph View view

To view the installed bundles as graphics, select

View -> Graph

The top left corner shows the bundle id and name of the currently selected bundle.

The lower left corner shows a bundle selection history. Double-click on any of those bundles to re-select it.

The left hand side of the view shows package dependencies. Lines below the horizon are packages that the bundle imports and lines above the horizon are the packages that the bundle exports to another bundle. There is one export-line for each bundle that imports the package. Holding the mouse pointer over a package-line will pop-up a tool tip with the name and version of the package. Holding the mouse pointer over the end of a package line will pop-up a tool-tip showing the bundle that the package was imported from or exported to. Click on the end of a package line to select the bundle associated with it (that bundle will be highlighted every where it occurs in the graph), double-click to center the graph on the selected bundle. Above each export package line a mini-graph showing the exports of the bundle importing the package is drawn.

The right hand side of the view shows service dependencies. Lines below the horizon are services that the bundle uses (imports) and lines above the horizon are the services that the bundle provides (exports) to another bundle. There is one export-line for each bundle that uses a registered service. Holding the mouse pointer over a service-line will pop-up a tool tip with the service id and object-class of the service it represents. Holding the mouse pointer over the end of a service line will pop-up a tool-tip showing the bundle that the service was imported from or exported to. Click on the end of a service line to select the bundle associated with it (that bundle will be highlighted every where it occurs in the graph), double-click to center the graph on the selected bundle. Above each export service line is a mini-graph showing the services provided by the bundle using the service that the line represents.

The transparent blue half-circle below (or above) the selected bundle is a scroll-bar that scrolls the package/service lines. Drag the mouse horizontally, starting in side the half circle, to scroll.

Configuration properties

Name Description Value type Default value
org.knopflerfish.bundle.log.window.impl.LogTableModel.capacity The maximum number of log entries to keep in memory in one log view. Use a negative value (i.e., a value smaller than 1) to indicate that old entries shall never be removed. int 342
org.knopflerfish.desktop.display.large_icons.sort The sort order to use for icons in the "Large Icons" bundle displayer. Supported values are:
id
Bundle id order (default).
name
Bundle name order.
start_level
Bundle start level order.
Any unrecognized value will result sorting icons based o the bundle id.

The desktop bundles stores the sort order amongst its preferences (for each framework service id), if this property is set it will over-ride the saved preferences value.

String id
org.knopflerfish.desktop.displays A white-space separated list of built in desktop displays to instantiate on startup. Each item in the list is the full class name of a displayer. String org.knopflerfish.bundle.desktop.swing.LargeIconsDisplayer org.knopflerfish.bundle.desktop.swing.GraphDisplayer org.knopflerfish.bundle.desktop.swing.TableDisplayer org.knopflerfish.bundle.desktop.swing.ManifestHTMLDisplayer org.knopflerfish.bundle.desktop.swing.ClosureHTMLDisplayer org.knopflerfish.bundle.desktop.swing.ServiceHTMLDisplayer org.knopflerfish.bundle.desktop.swing.WiringHTMLDisplayer org.knopflerfish.bundle.desktop.swing.SCRHTMLDisplayer org.knopflerfish.bundle.desktop.swing.LogDisplayer org.knopflerfish.bundle.desktop.swing.EventDisplayer org.knopflerfish.bundle.desktop.swing.PrefsDisplayer
org.knopflerfish.desktop.displays.extra A white-space separated list of additional built in desktop displays to instantiate on startup. Each item in the list is the full class name of a displayer. Use this property when you want to start all the default built in displayers and some extra dislayer. This way you only need to specify the additional displayer and not all of them.

E.g.,

	org.knopflerfish.bundle.desktop.swing.PackageHTMLDisplayer
	org.knopflerfish.bundle.desktop.swing.SpinDisplayer

String
org.knopflerfish.desktop.display.main The name of the default bundle displayer to show in the desktop's main frame when starting. String Large Icons
org.knopflerfish.bundle.desktop.event.EventTableModel.capacity The maximum number of events to keep in memory in one event view. Use a negative value (i.e., a value smaller than 1) to indicate that old event shall never be removed. int 342

Bundle Jar docs

desktop_all-5.0.1
desktop_api-5.0.1
desktop-5.0.1

Exported Packages

PackageVersionProviders
org.apache.felix.scr1.6.0desktop_all-5.0.1
org.knopflerfish.service.console2.1.2desktop_all-5.0.1
org.knopflerfish.service.desktop2.2.0desktop_all-5.0.1, desktop_api-5.0.1
org.knopflerfish.service.log1.2.0desktop_all-5.0.1
org.knopflerfish.service.remotefw0.0.0desktop_all-5.0.1
org.knopflerfish.util1.1.0desktop_all-5.0.1
org.knopflerfish.util.framework1.0.0desktop_all-5.0.1
org.knopflerfish.util.sort1.0.0desktop_all-5.0.1
org.knopflerfish.util.workerthread1.0.0desktop_all-5.0.1
org.osgi.service.cm1.5.0desktop_all-5.0.1
org.osgi.service.component1.2.1desktop_all-5.0.1
org.osgi.service.event1.3.0desktop_all-5.0.1
org.osgi.service.log1.3.0desktop_all-5.0.1
org.osgi.service.prefs1.1.1desktop_all-5.0.1
  1. Knopflerfish framework.jar startup
  2. Initial start vs restart
  3. Starting the framework
  4. Starting the compact framework
  5. Default selection of .xargs
  6. Using a HTTP proxy
  7. Framework and System Properties
  8. OSGi Specified Framework Properties
  9. Knopflerfish Specified System Properties
  10. Knopflerfish Specified Framework Properties